Skip to main content

Developer Setup

This SDK follows the MystenLabs TS SDK building guidelines. It uses the client extension pattern: you extend a base Sui client with messaging, groups, and Seal extensions.

Quick setup with createMessagingGroupsClient()

This helper 'factory' function handles all three extensions automatically:

import { SuiGrpcClient } from '@mysten/sui/grpc';
import { createMessagingGroupsClient } from '@mysten/sui-stack-messaging';

const client = createMessagingGroupsClient(
new SuiGrpcClient({
baseUrl: 'https://fullnode.testnet.sui.io:443',
network: 'testnet',
}),
{
seal: {
serverConfigs: [
{ objectId: '0x...', weight: 1 },
{ objectId: '0x...', weight: 1 },
],
},
encryption: {
sessionKey: { signer: keypair },
},
relayer: {
relayerUrl: 'https://your-relayer.example.com',
},
},
);

After creation, the client exposes four namespaces:

NamespacePurpose
client.messagingE2EE messaging, group creation, key rotation
client.groupsPermission management (Sui Groups docs)
client.sealSeal encryption/decryption (utilized by messaging)
client.coreBase Sui RPC methods

Manual extension chain (advanced)

For full control over each extension, use $extend() directly:

import { SuiGrpcClient } from '@mysten/sui/grpc';
import { SealClient } from '@mysten/seal';
import { suiGroups } from '@mysten/sui-groups';
import { suiStackMessaging } from '@mysten/sui-stack-messaging';

const base = new SuiGrpcClient({
baseUrl: 'https://fullnode.testnet.sui.io:443',
network: 'testnet',
});

// Step 1: extend with groups + seal (independent of each other)
const withGroupsAndSeal = base.$extend(
suiGroups({
witnessType: `${MESSAGING_PACKAGE_ID}::messaging::Messaging`,
}),
{
name: 'seal' as const,
register: (c) =>
new SealClient({
suiClient: c,
serverConfigs: [
{ objectId: '0x...', weight: 1 },
{ objectId: '0x...', weight: 1 },
],
}),
},
);

// Step 2: extend with messaging (depends on both groups and seal)
const client = withGroupsAndSeal.$extend(
suiStackMessaging({
encryption: { sessionKey: { signer: keypair } },
relayer: { relayerUrl: 'https://your-relayer.example.com' },
}),
);

Configuration reference

encryption (required)

Controls how the SDK obtains Seal session keys and encrypts/decrypts messages.

Session key tiers

encryption: {
sessionKey: { signer: keypair },
}

The SDK derives the address through signer.toSuiAddress(), creates a SessionKey, and handles certification automatically.

Tier 2: Callback-based (for current dapp-kit without Signer abstraction):
encryption: {
sessionKey: {
address: '0x...',
onSign: async (message: Uint8Array) => {
// Sign with your wallet adapter and return the signature string
return signPersonalMessage(message);
},
},
}

The SDK creates the session key, then calls onSign() with the personal message bytes.

Tier 3: Manual (full control over session key lifecycle):
encryption: {
sessionKey: {
getSessionKey: () => myManagedSessionKey,
},
}

Session key options (Tier 1 and 2)

OptionDefaultDescription
ttlMin10Session key TTL in minutes
refreshBufferMs60000Refresh this many ms before expiry
mvrName(none)MVR name for Seal policy resolution

Encryption options

OptionDefaultDescription
sealThreshold2Number of key servers needed for decryption
cryptoPrimitivesWeb CryptoCustom AES-GCM implementation
sealPolicyDefaultSealPolicyCustom Seal access control policy (see Extending)

relayer (required)

Either provide a URL for the built-in HTTP transport or a custom transport instance:

// Built-in HTTP transport
relayer: {
relayerUrl: 'https://your-relayer.example.com',
pollingIntervalMs: 3000, // default
timeout: 30000, // default
onError: (err) => console.error(err),
}

// Custom transport
relayer: {
transport: myCustomTransport, // implements RelayerTransport
}

See Relayer for the RelayerTransport interface.

attachments (optional)

Enable file attachment support by providing a storage adapter:

import { WalrusHttpStorageAdapter } from '@mysten/sui-stack-messaging';

attachments: {
storageAdapter: new WalrusHttpStorageAdapter({
publisherUrl: 'https://publisher.walrus-testnet.walrus.space',
aggregatorUrl: 'https://aggregator.walrus-testnet.walrus.space',
epochs: 5,
}),
maxAttachments: 10, // default
maxFileSizeBytes: 10_485_760, // 10 MB default
maxTotalFileSizeBytes: 52_428_800, // 50 MB default
}

When omitted, sendMessage cannot include files and received attachment metadata is not resolvable. See Attachments.

packageConfig (optional)

Auto-detected for Testnet and Mainnet. Required for localnet or custom deployments:

packageConfig: {
messaging: {
originalPackageId: '0x...', // First published package ID (type names, BCS, Seal)
latestPackageId: '0x...', // Current package ID (moveCall targets)
namespaceId: '0x...', // MessagingNamespace shared object
versionId: '0x...', // Version shared object
},
permissionedGroups: { // optional, also auto-detected
originalPackageId: '0x...',
latestPackageId: '0x...',
},
}

suinsConfig (optional)

Auto-detected for Testnet and Mainnet. Only needed for SuiNS reverse lookup operations (setSuinsReverseLookup, unsetSuinsReverseLookup).

seal (factory only)

When using createMessagingGroupsClient, pass either a pre-built SealClient or Seal config options:

// Config options (SealClient created internally)
seal: {
serverConfigs: [
{ objectId: '0x...', weight: 1 },
{ objectId: '0x...', weight: 1 },
],
}

// Pre-built SealClient
seal: existingSealClient,

Sub-modules

The client.messaging object exposes several sub-modules:

Sub-modulePurposeExample
callPTB thunks: composable transaction stepstx.add(client.messaging.call.createAndShareGroup(opts))
txFull transactions: ready to signclient.messaging.tx.createAndShareGroup(opts)
viewRead-only queries (no gas)client.messaging.view.groupsMetadata(opts)
bcsBCS type definitions for parsingclient.messaging.bcs.EncryptionHistory
deriveDeterministic address derivationclient.messaging.derive.groupId({ uuid })
encryptionLow-level encrypt/decryptclient.messaging.encryption.encrypt(opts)
transportDirect relayer accessclient.messaging.transport.fetchMessages(opts)

When to use which

  • Top-level imperative methods (for example, client.messaging.sendMessage()): simplest path, sign, encrypt, and send in one call.
  • tx.*: when you need a Transaction object to inspect or modify before signing (for example, with dapp-kit's signAndExecuteTransaction).
  • call.*: when composing multiple operations into a single PTB.
  • view.*: for read-only queries that don't require a signer.

The GroupRef pattern

Most messaging methods accept a GroupRef, either a UUID or explicit object IDs:

// By UUID (simpler: derives both IDs internally)
await client.messaging.sendMessage({
signer: keypair,
groupRef: { uuid: 'my-group-uuid' },
text: 'Hello!',
});

// By explicit IDs
await client.messaging.sendMessage({
signer: keypair,
groupRef: {
groupId: '0x...',
encryptionHistoryId: '0x...',
},
text: 'Hello!',
});

Using UUIDs is recommended. See Group Discovery for details on UUID derivation and tracking.