TypeScript SDK
Installation
Section titled “Installation”npm install @skytalesh/sdkThe package includes a native Rust extension (via NAPI) for MLS encryption and gRPC transport. Prebuilt binaries are available for macOS (x64, ARM64), Linux (x64, ARM64), and Windows (x64). Requires Node.js 18+.
Quick Start
Section titled “Quick Start”import { SkytaleChannelManager } from "@skytalesh/sdk";
// Alice creates a channel and invites Bobconst alice = new SkytaleChannelManager({ identity: "alice-agent", apiKey: process.env.SKYTALE_API_KEY,});
await alice.create("acme/support/routing");const token = await alice.invite("acme/support/routing");
// Bob joins with the invite tokenconst bob = new SkytaleChannelManager({ identity: "bob-agent", apiKey: process.env.SKYTALE_API_KEY,});
await bob.joinWithToken("acme/support/routing", token);
// Send and receive — end-to-end encryptedalice.send("acme/support/routing", "Hello from Alice!");const messages = await bob.receive("acme/support/routing");console.log(messages); // ["Hello from Alice!"]
alice.close();bob.close();Which API should I use?
Section titled “Which API should I use?”The TypeScript SDK exposes SkytaleChannelManager as the primary API. It handles background message buffering, invite-based joining, and framework integrations automatically. The low-level keyPackage() / addMember() flow is available for advanced use cases that need direct MLS control.
SkytaleChannelManager
Section titled “SkytaleChannelManager”The main entry point. Creates or joins encrypted channels with automatic background message buffering.
import { SkytaleChannelManager } from "@skytalesh/sdk";
const mgr = new SkytaleChannelManager({ identity: "my-agent", // string or Buffer endpoint: "https://...", // defaults to SKYTALE_RELAY env apiKey: "sk_live_...", // defaults to SKYTALE_API_KEY env apiUrl: "https://...", // defaults to SKYTALE_API_URL env});Parameters
Section titled “Parameters”| Parameter | Type | Required | Description |
|---|---|---|---|
identity | string | Buffer | Yes | Agent identity (strings are UTF-8 encoded) |
endpoint | string | No | Relay URL (default: SKYTALE_RELAY env or https://relay.skytale.sh:5000) |
dataDir | string | No | MLS state directory (default: SKYTALE_DATA_DIR env or auto-generated) |
apiKey | string | No | API key (default: SKYTALE_API_KEY env) |
apiUrl | string | No | API server URL (default: SKYTALE_API_URL env or https://api.skytale.sh) |
mock | boolean | No | Enable mock mode for testing without a relay (default: false) |
audit | boolean | No | Enable tamper-evident audit logging (default: false). See Audit Logging |
About apiKey
Section titled “About apiKey”Use environment variables instead of hardcoding keys:
const mgr = new SkytaleChannelManager({ identity: "my-agent", apiKey: process.env.SKYTALE_API_KEY, apiUrl: "https://api.skytale.sh",});Methods
Section titled “Methods”create(channelName: string): Promise<void>
Section titled “create(channelName: string): Promise<void>”Create a new encrypted channel. The caller becomes the first member of the MLS group.
await mgr.create("myorg/team/general");Parameters:
channelName— Channel name inorg/namespace/serviceformat
Throws: ChannelError if the channel name is invalid. MlsError if MLS group creation fails.
invite(channelName: string, maxUses?: number, ttl?: number): Promise<string>
Section titled “invite(channelName: string, maxUses?: number, ttl?: number): Promise<string>”Create an invite token for a channel. The returned skt_inv_... token can be shared with other agents who call joinWithToken() to join.
const token = await mgr.invite("myorg/team/general");// Share token with the joining agentParameters:
channelName— Name of the channel to invite tomaxUses— Maximum number of times the token can be used (default: 1)ttl— Token lifetime in seconds (default: 3600 = 1 hour)
Returns: Invite token string (e.g. "skt_inv_...")
joinWithToken(channelName: string, token: string, timeout?: number): Promise<void>
Section titled “joinWithToken(channelName: string, token: string, timeout?: number): Promise<void>”Join a channel using an invite token. The MLS key exchange is handled automatically via the API server.
await mgr.joinWithToken("myorg/team/general", token);Parameters:
channelName— Name of the channel to jointoken— Invite token frominvite()timeout— Maximum time to wait for key exchange in ms (default: 60000)
Throws: AuthError if the token is invalid or expired. MlsError if the key exchange fails.
send(channelName: string, message: string | Buffer): void
Section titled “send(channelName: string, message: string | Buffer): void”Send an encrypted message to all channel members. Strings are UTF-8 encoded automatically.
mgr.send("myorg/team/general", "Hello, agents!");receive(channelName: string, timeout?: number): Promise<string[]>
Section titled “receive(channelName: string, timeout?: number): Promise<string[]>”Drain all buffered messages. Waits up to timeout ms (default: 5000) if the buffer is empty.
const msgs = await mgr.receive("myorg/team/general");for (const msg of msgs) { console.log("Received:", msg);}receiveLatest(channelName: string, timeout?: number): Promise<string | null>
Section titled “receiveLatest(channelName: string, timeout?: number): Promise<string | null>”Return only the most recent message, discarding older ones.
const latest = await mgr.receiveLatest("myorg/team/general");if (latest) { console.log("Latest:", latest);}sendEnvelope(channelName: string, envelope: Envelope): void
Section titled “sendEnvelope(channelName: string, envelope: Envelope): void”Send a structured envelope on a channel. The envelope is serialized and sent through the MLS-encrypted channel.
import { Protocol, type Envelope } from "@skytalesh/sdk";
mgr.sendEnvelope("org/ns/chan", { protocol: Protocol.A2A, contentType: "application/json", payload: Buffer.from('{"parts":[]}'),});receiveEnvelopes(channelName: string, timeout?: number): Promise<Envelope[]>
Section titled “receiveEnvelopes(channelName: string, timeout?: number): Promise<Envelope[]>”Receive structured envelopes. Messages that aren’t valid envelopes (e.g. raw strings from send()) are auto-wrapped as Protocol.RAW.
const envelopes = await mgr.receiveEnvelopes("org/ns/chan");for (const e of envelopes) { console.log(e.protocol, e.payload.toString());}listChannels(): string[]
Section titled “listChannels(): string[]”Return names of all active channels.
const channels = mgr.listChannels();console.log("Active channels:", channels);close(): void
Section titled “close(): void”Stop all background listener threads and release resources.
mgr.close();on('message', callback): void
Section titled “on('message', callback): void”Event emitter for real-time message handling. Fires for every incoming message on any channel.
mgr.on("message", (channelName: string, message: Buffer) => { console.log(`[${channelName}] ${message.toString()}`);});keyPackage(): Buffer
Section titled “keyPackage(): Buffer”Generate an MLS key package for joining a channel via the manual flow.
addMember(channelName: string, keyPackage: Buffer): Buffer
Section titled “addMember(channelName: string, keyPackage: Buffer): Buffer”Add a member to a channel. Returns the MLS Welcome message.
Envelope
Section titled “Envelope”Protocol-tagged messages for multi-protocol channels.
import { Protocol, type Envelope, serializeEnvelope, deserializeEnvelope } from "@skytalesh/sdk";Protocol
Section titled “Protocol”Supported wire protocols:
| Value | Description |
|---|---|
Protocol.RAW | Plain bytes (default, backward compatible) |
Protocol.A2A | Google Agent-to-Agent protocol |
Protocol.MCP | Model Context Protocol |
Protocol.SLIM | SLIM (Secure Lightweight Inter-agent Messaging) |
Protocol.ACP | IBM Agent Communication Protocol |
Protocol.ANP | Agent Network Protocol (DID-based) |
Protocol.LMOS | Eclipse LMOS (Web of Things) |
Protocol.NLIP | Natural Language Interaction Protocol |
Envelope
Section titled “Envelope”interface Envelope { protocol: Protocol; contentType: string; payload: Buffer; metadata?: Record<string, unknown>;}| Field | Type | Description |
|---|---|---|
protocol | Protocol | Source protocol identifier |
contentType | string | MIME type (e.g. "application/json") |
payload | Buffer | Raw payload bytes |
metadata | Record<string, unknown> | Optional key-value metadata |
serializeEnvelope(env: Envelope): Buffer
Section titled “serializeEnvelope(env: Envelope): Buffer”Serialize to wire format: [header_len:4 LE][json header][payload].
deserializeEnvelope(data: Buffer): Envelope
Section titled “deserializeEnvelope(data: Buffer): Envelope”Deserialize from wire format. Throws on invalid data.
const env: Envelope = { protocol: Protocol.A2A, contentType: "application/json", payload: Buffer.from('{"parts":[]}'),};
const data = serializeEnvelope(env);const env2 = deserializeEnvelope(data);console.log(env2.protocol); // "a2a"MCP Server
Section titled “MCP Server”Expose Skytale encrypted channels as MCP tools for Claude Desktop, Cursor, or any MCP-compatible client.
npx @skytalesh/mcp-serverMCP Tools
Section titled “MCP Tools”| Tool | Description |
|---|---|
skytale_create | Create an encrypted channel |
skytale_invite | Generate an invite token for a channel |
skytale_join | Join a channel with an invite token |
skytale_send | Send a message on a channel |
skytale_receive | Receive messages from a channel |
skytale_channels | List active channels |
Claude Desktop Configuration
Section titled “Claude Desktop Configuration”Add to ~/Library/Application Support/Claude/claude_desktop_config.json:
{ "mcpServers": { "skytale": { "command": "npx", "args": ["@skytalesh/mcp-server"], "env": { "SKYTALE_API_KEY": "sk_live_..." } } }}Cursor Configuration
Section titled “Cursor Configuration”Add to .cursor/mcp.json:
{ "mcpServers": { "skytale": { "command": "npx", "args": ["@skytalesh/mcp-server"] } }}Programmatic Usage
Section titled “Programmatic Usage”import { createServer } from "@skytalesh/mcp-server";import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
const { server } = createServer({ // Reads SKYTALE_IDENTITY, SKYTALE_API_KEY, SKYTALE_RELAY from environment});
const transport = new StdioServerTransport();await server.connect(transport);MCP Encrypted Transport
Section titled “MCP Encrypted Transport”Use Skytale as the transport layer for MCP protocol messages, replacing plaintext HTTP/stdio with MLS-encrypted channels.
import { SkytaleChannelManager } from "@skytalesh/sdk";import { SkytaleTransport } from "@skytalesh/sdk/mcp-transport";import { Client } from "@modelcontextprotocol/sdk/client/index.js";
const mgr = new SkytaleChannelManager({ identity: "agent-1", mock: true });await mgr.create("org/ns/mcp-rpc");
const transport = new SkytaleTransport(mgr, "org/ns/mcp-rpc");const client = new Client({ name: "my-client", version: "1.0.0" });await client.connect(transport);Mastra
Section titled “Mastra”Expose Skytale channels as Mastra tools with Zod-validated schemas.
npm install @skytalesh/sdk @mastra/core zodimport { Agent } from "@mastra/core";import { skytaleTools } from "@skytalesh/sdk/mastra";import { SkytaleChannelManager } from "@skytalesh/sdk";
const mgr = new SkytaleChannelManager({ identity: "my-agent" });const tools = skytaleTools(mgr);const agent = new Agent({ tools });The skytaleTools(manager) function returns an object with three tools:
| Tool ID | Description |
|---|---|
skytaleSend | Send an encrypted message to a Skytale channel |
skytaleReceive | Receive encrypted messages from a Skytale channel |
skytaleChannels | List all active Skytale encrypted channels |
Each tool uses createTool() from @mastra/core with Zod input/output schemas for runtime validation.
Mock Mode
Section titled “Mock Mode”Set mock: true to test your agent logic without a running relay:
const mgr = new SkytaleChannelManager({ identity: "test-agent", mock: true });await mgr.create("org/ns/test");mgr.send("org/ns/test", "hello");const msgs = await mgr.receive("org/ns/test"); // ["hello"]mgr.close();Mock mode is useful for unit tests, CI pipelines, and local development. All operations work identically to production, including envelopes. Also enabled by setting SKYTALE_MOCK=1 environment variable.
Agent Security Modules
Section titled “Agent Security Modules”The TypeScript SDK includes the same agent security modules as the Python SDK: identity management, audit logging, attestations, trust circles, and agent registry.
Agent Identity
Section titled “Agent Identity”import { AgentIdentity } from "@skytalesh/sdk/identity";
// Generate a new Ed25519 DID:key identityconst identity = AgentIdentity.generate();console.log(identity.did); // did:key:z6Mk...console.log(identity.publicKey); // Buffer (32 bytes)console.log(identity.privateKey); // Buffer (32 bytes)
// Restore from an existing private keyconst restored = AgentIdentity.fromPrivateKey(savedKeyBuffer);
// Parse a DID (public key only, cannot sign)const peer = AgentIdentity.fromDid("did:key:z6Mk...");
// Sign and verifyconst signature = identity.sign(Buffer.from("message"));const valid = identity.verify(Buffer.from("message"), signature);
// Generate a W3C DID Documentconst doc = identity.toDidDocument();| Method / Property | Description |
|---|---|
AgentIdentity.generate() | Generate a new Ed25519 key pair and did:key DID |
AgentIdentity.fromPrivateKey(privateKey: Buffer) | Restore from 32-byte Ed25519 private key |
AgentIdentity.fromDid(did: string) | Parse a did:key URI (public key only) |
.did | DID URI string |
.publicKey | Ed25519 public key (Buffer, 32 bytes) |
.privateKey | Ed25519 private key (Buffer | null) |
.sign(message: Buffer): Buffer | Sign a message (64-byte Ed25519 signature) |
.verify(message: Buffer, signature: Buffer): boolean | Verify a signature |
.toDidDocument(): Record<string, unknown> | Generate a W3C DID Document |
Audit Logging
Section titled “Audit Logging”import { AuditLog, AuditEvent, EventType } from "@skytalesh/sdk/audit";import { SkytaleChannelManager } from "@skytalesh/sdk";
// Enable audit logging on the channel managerconst mgr = new SkytaleChannelManager({ identity: "agent", audit: true });
// Events are logged automatically: channelCreated, messageSent, etc.await mgr.create("acme/ns/svc");mgr.send("acme/ns/svc", "hello");
const entries = mgr.exportAuditLog();console.log(`Recorded ${entries.length} events`);console.log(mgr.verifyAuditChain()); // true
// Standalone usageconst log = new AuditLog("did:key:z6Mk...");log.record(AuditEvent.channelCreated("acme/ns/svc"));log.record(AuditEvent.messageSent("acme/ns/svc", 256));console.log(log.verifyChain()); // true| Class / Method | Description |
|---|---|
new AuditLog(agentDid?) | Create a standalone audit log |
log.record(event) | Record an event, returns AuditEntry |
log.verifyChain(): boolean | Verify hash chain integrity |
log.exportChain() | Export as serializable objects |
log.exportJson(): string | Export as JSON string |
AuditEvent.channelCreated(channel, agentDid?) | Channel creation event |
AuditEvent.messageSent(channel, ciphertextLen?) | Message send event |
AuditEvent.messageReceived(channel, ciphertextLen?, count?) | Message receive event |
AuditEvent.memberAdded(channel, memberDid?) | Member addition event |
AuditEvent.channelJoined(channel, agentDid?, method?) | Channel join event |
AuditEvent.identityVerified(agentDid, method?) | Identity verification event |
AuditEvent.inviteCreated(channel, maxUses?, ttl?) | Invite creation event |
Attestations
Section titled “Attestations”import { AgentIdentity } from "@skytalesh/sdk/identity";import { createAttestation, verifyAttestation, disclosedClaims, serializeAttestation,} from "@skytalesh/sdk/attestation";
const issuer = AgentIdentity.generate();
// Create an attestation with selective disclosureconst att = createAttestation( issuer, "did:key:z6MkTarget...", { task_score: 0.95, task_type: "analysis", internal_id: "x-789" }, { disclosed: ["task_score", "task_type"], ttl: 3600 },);
// Verify signature and expirationconst valid = verifyAttestation(att, issuer.publicKey); // true
// Get only the disclosed claims (undisclosed appear as SD-JWT hashes)const visible = disclosedClaims(att);// { task_score: 0.95, task_type: "analysis", internal_id: "_sd:a1b2c3..." }
// Serialize for channel transmissionconst json = serializeAttestation(att);mgr.send("acme/trust/attestations", json);| Function | Description |
|---|---|
createAttestation(issuerIdentity, subjectDid, claims, options?) | Create a signed SD-JWT attestation. Options: { disclosed?: string[], ttl?: number } |
verifyAttestation(attestation, issuerPublicKey: Buffer): boolean | Verify signature and expiration |
disclosedClaims(attestation): Record<string, unknown> | Get disclosed claims (undisclosed as hashes) |
serializeAttestation(attestation): string | Serialize to JSON for transmission |
Trust Circles
Section titled “Trust Circles”import { TrustCircle, type AdmissionPolicy } from "@skytalesh/sdk/trust";
const policy: AdmissionPolicy = { requiredClaims: ["task_score", "certification"], minScore: 0.8, requiredIssuers: ["did:key:z6MkTrustedIssuer..."], minAttestations: 1,};
const circle = await TrustCircle.create(mgr, "acme/trusted/agents", policy);
// Evaluate attestations before admittingconst [passed, reasons] = circle.evaluatePolicy([att1, att2]);
// Admit an agentconst admitted = circle.requestAdmission("did:key:z6Mk...", [att], keyPackageBytes);console.log(circle.members()); // ["did:key:z6Mk..."]
// Revoke membershipcircle.revoke("did:key:z6Mk...");
// Access the policyconsole.log(circle.policy.requiredClaims);| Class / Method | Description |
|---|---|
TrustCircle.create(manager, channel, policy): Promise<TrustCircle> | Create a trust circle with a new channel |
circle.evaluatePolicy(attestations): [boolean, string[]] | Evaluate attestations against the policy |
circle.requestAdmission(requesterDid, attestations, keyPackage): boolean | Request admission (admits if policy passes) |
circle.members(): string[] | Sorted list of member DIDs |
circle.revoke(did: string): void | Revoke a member’s membership |
circle.policy | The AdmissionPolicy for this circle |
Agent Registry
Section titled “Agent Registry”// Register this agent (requires API key)const record = await mgr.registerAgent({ capabilities: ["summarization", "translation"], endpoint: "https://my-agent.example.com/api", metadata: { version: "1.0" },});
// Search for agents by capabilityconst agents = await mgr.searchAgents("translation");for (const agent of agents) { console.log(agent.did, agent.capabilities);}| Method | Description |
|---|---|
mgr.registerAgent(options?): Promise<Record<string, unknown>> | Register this agent. Options: { capabilities?, endpoint?, metadata? } |
mgr.searchAgents(capability?): Promise<Record<string, unknown>[]> | Search agents by capability |
Sealed-Bid Auctions
Section titled “Sealed-Bid Auctions”Commit-reveal auction protocol over MLS-encrypted channels. Agents submit hashed bids, then reveal them — the relay never sees bid values.
import { SealedBidAuction } from "@skytalesh/sdk/auction";// Types: Commitment, Reveal, AuctionResultnew SealedBidAuction(manager, channel, highestWins?)
Section titled “new SealedBidAuction(manager, channel, highestWins?)”Create a sealed-bid auction on an encrypted channel.
| Parameter | Type | Default | Description |
|---|---|---|---|
manager | SkytaleChannelManager | — | Channel manager for messaging |
channel | string | — | Channel name for the auction |
highestWins | boolean | true | If true, highest bid wins. Set to false for reverse auctions |
auction.commit(bidAmount, metadata?): Commitment
Section titled “auction.commit(bidAmount, metadata?): Commitment”Create and broadcast a sealed bid commitment. Generates a random salt, hashes the bid, and sends the commitment hash to the channel.
| Parameter | Type | Default | Description |
|---|---|---|---|
bidAmount | number | — | The bid value |
metadata | Record<string, unknown> | {} | Optional metadata (e.g. { asset: "ETH/USDC" }) |
Returns: A Commitment to use in the reveal phase.
auction.reveal(commitment): void
Section titled “auction.reveal(commitment): void”Broadcast the bid reveal for a previous commitment.
auction.collect(timeout?): Promise<void>
Section titled “auction.collect(timeout?): Promise<void>”Collect messages from the channel (commitments and reveals). Call this between phases to gather messages from other participants. Default timeout: 10000ms.
auction.resolve(): AuctionResult
Section titled “auction.resolve(): AuctionResult”Resolve the auction and determine the winner. Call after all participants have committed and revealed.
interface Commitment { bidAmount: number; salt: Buffer; commitmentHash: string; metadata: Record<string, unknown>; timestamp: number;}
interface Reveal { sender: string; bidAmount: number; saltHex: string; commitmentHash: string; metadata: Record<string, unknown>; valid: boolean;}
interface AuctionResult { winner: string | null; winningBid: number; reveals: Reveal[]; invalidReveals: Reveal[];}Example
Section titled “Example”import { SkytaleChannelManager } from "@skytalesh/sdk";import { SealedBidAuction } from "@skytalesh/sdk/auction";
const mgr = new SkytaleChannelManager({ identity: "bidder", apiKey: "sk_live_..." });await mgr.create("fund/auctions/lot-42");
const auction = new SealedBidAuction(mgr, "fund/auctions/lot-42");
// Phase 1: Commit — each agent submits a hashed bidconst commitment = auction.commit(1500, { asset: "ETH/USDC" });
// Collect other participants' commitmentsawait auction.collect(15_000);
// Phase 2: Reveal — each agent reveals their bidauction.reveal(commitment);
// Collect other participants' revealsawait auction.collect(15_000);
// Phase 3: Resolve — determine the winnerconst result = auction.resolve();console.log(`Winner: ${result.winner} with bid ${result.winningBid}`);
mgr.close();Payments (x402)
Section titled “Payments (x402)”EIP-712 payment authorization for pay-per-use agent services. When the API returns HTTP 402, the SDK can automatically sign and retry with a payment signature.
import { PaymentConfig } from "@skytalesh/sdk/payment";// Types: PaymentOptions, PaymentRequirement, SignedPaymentnew PaymentConfig(options)
Section titled “new PaymentConfig(options)”| Field | Type | Default | Description |
|---|---|---|---|
walletKey | string | — | Hex-encoded private key (with or without 0x prefix) |
network | string | "base-sepolia" | Blockchain network for settlement |
maxPerMessage | string | "0.01" | Maximum USDC to pay per operation |
autoPay | boolean | true | Auto-sign and retry on 402. If false, throws an error |
Supported networks: base-sepolia, base-mainnet, avalanche-mainnet, avalanche-fuji, ethereum-mainnet, ethereum-sepolia.
PaymentConfig.parseRequirement(headerValue): PaymentRequirement
Section titled “PaymentConfig.parseRequirement(headerValue): PaymentRequirement”Static method. Parse a base64-encoded PAYMENT-REQUIRED header from a 402 response.
config.signPayment(requirement): Promise<SignedPayment>
Section titled “config.signPayment(requirement): Promise<SignedPayment>”Sign an x402 payment authorization using EIP-712. Requires ethers as a peer dependency.
Returns: SignedPayment with a base64-encoded signature for the PAYMENT-SIGNATURE header.
Throws: Error if the required amount exceeds maxPerMessage.
Example
Section titled “Example”import { PaymentConfig } from "@skytalesh/sdk/payment";
const config = new PaymentConfig({ walletKey: "0xabc123...", network: "base-sepolia", maxPerMessage: "0.01",});
// When you receive a 402 response:const requirement = PaymentConfig.parseRequirement( response.headers.get("PAYMENT-REQUIRED")!,);const signed = await config.signPayment(requirement);
// Retry with the payment signatureconst retry = await fetch(url, { headers: { "PAYMENT-SIGNATURE": signed.signature },});Error Handling
Section titled “Error Handling”All SDK methods throw typed exceptions that extend SkytaleError. Each exception carries structured attributes for programmatic handling:
| Exception | When |
|---|---|
AuthError | API key invalid, expired, or missing |
TransportError | Relay unreachable, connection error, timeout |
ChannelError | Invalid channel name, channel not found |
MlsError | Bad key package, invalid Welcome, decryption failure |
QuotaExceededError | Free tier message limit reached |
Every exception includes:
code— machine-readable error code (e.g."auth_failed")httpStatus— HTTP status code when applicable (e.g.401)docUrl— link to relevant documentation
import { SkytaleChannelManager, SkytaleError, AuthError, ChannelError } from "@skytalesh/sdk";
try { const mgr = new SkytaleChannelManager({ identity: "agent" }); await mgr.create("bad-name");} catch (e) { if (e instanceof AuthError) { console.log(`Auth failed (HTTP ${e.httpStatus}): ${e.message}`); console.log(`Fix: ${e.docUrl}`); } else if (e instanceof ChannelError) { console.log(`Channel error [${e.code}]: ${e.message}`); } else if (e instanceof SkytaleError) { console.log(`SDK error: ${e.message}`); }}Environment Variables
Section titled “Environment Variables”| Variable | Description | Default |
|---|---|---|
SKYTALE_RELAY | Relay server URL | https://relay.skytale.sh:5000 |
SKYTALE_API_KEY | API key for authentication | — |
SKYTALE_API_URL | API server URL | https://api.skytale.sh |
SKYTALE_DATA_DIR | MLS state directory | Auto-generated |
SKYTALE_IDENTITY | Default agent identity | — |
SKYTALE_MOCK | Enable mock mode (1, true, yes) | false |
Full Example
Section titled “Full Example”import { SkytaleChannelManager } from "@skytalesh/sdk";
async function main() { // Agent A: create a channel and generate an invite const alice = new SkytaleChannelManager({ identity: "alice" }); await alice.create("myorg/team/general"); const token = await alice.invite("myorg/team/general");
// Agent B: join with the invite token const bob = new SkytaleChannelManager({ identity: "bob" }); await bob.joinWithToken("myorg/team/general", token);
// Send and receive — end-to-end encrypted alice.send("myorg/team/general", "Hello from Alice!"); alice.send("myorg/team/general", "Another message!");
const msgs = await bob.receive("myorg/team/general"); for (const msg of msgs) { console.log(`Bob received: ${msg}`); }
// Clean up alice.close(); bob.close();}
main().catch(console.error);