Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Per-app SDKs

Each ENC Protocol app ships as a typed JavaScript SDK at @enc-protocol/<app>-cli. Each exports a class extending AppSdk (from @enc-protocol/cli-sdk-base) with method-per-action / method-per-read:

import { HelloSdk } from '@enc-protocol/hello-cli'
 
const sdk = new HelloSdk({ mode: 'cf', nodeUrl: process.env.NODE_URL })
await sdk.init()
await sdk.submitMessages({ draft: 'hi' })   // → Hello.post (via tableMap)
const events = await sdk.queryMessages()

Install

echo "@enc-protocol:registry=https://npm-registry.ocrybit.workers.dev/" >> .npmrc
npm install @enc-protocol/<app>-cli

Constructor

new <App>Sdk(opts: {
  mode: 'mem' | 'cf'
  identity?: Identity          // required for cf mode
  nodeUrl?: string             // cf mode (or set NODE_URL env)
  repoRoot?: string            // path to find apps/<id>/ + enclaves/
  encHome?: string             // state directory (defaults to ~/.enc)
  forceReadable?: boolean      // test-only Public-R escape (cf)
})

Then:

await sdk.init()   // loads app definition, registers all enclaves, wires dataview

Encryption hook

Apps with schema.encrypt (DM, Wallet) have _encrypt(dataType, args) called before each submit. Default is pass-through; subclass to add real encryption:

class EncryptedDm extends DmSdk {
  async _encrypt(dataType, args) {
    return { ciphertext: await mlsEncrypt(args) }
  }
}

Per-app reference

hello

@enc-protocol/hello-cli — enclaves: Hello.

import { HelloSdk } from '@enc-protocol/hello-cli'
 
await sdk.submitMessages({ draft: 'hello' })   // → Hello.post
const events = await sdk.queryMessages()

dm

@enc-protocol/dm-cli — enclaves: DM, Personal, Registry. Encrypted: messages, invites.

import { DmSdk } from '@enc-protocol/dm-cli'
 
await sdk.submitMessages({ message_draft: 'hi' })   // → DM.message (encrypted)
await sdk.deleteInvites({})                         // → DM.invite
const profiles = await sdk.queryProfiles()          // → cross_enclave dataview
const invites  = await sdk.queryInvites()
const messages = await sdk.queryMessages()

group

@enc-protocol/group-cli — enclaves: Group, Personal. Encrypted: messages.

personal

@enc-protocol/personal-cli — enclaves: Personal, Group. Encrypted: private.

await sdk.submitPublic({ draft: '...' })    // → Personal.public
await sdk.submitPrivate({ draft: '...' })   // → Personal.private (encrypted)
const notices = await sdk.queryNotices()    // → cross_enclave (Group.notice)

registry

@enc-protocol/registry-cli — enclaves: Registry. Pure read-only at the app level (writes happen at the enclave level via the registry's customs).

timeline

@enc-protocol/timeline-cli — enclaves: Timeline, Personal. Encrypted: none.

super

@enc-protocol/super-cli — multi-enclave composition. Enclaves: DM, Group, Personal.

import { SuperSdk } from '@enc-protocol/super-cli'
 
await sdk.submitMessages({ message_draft: 'hi' })   // → DM.message
await sdk.submitMoments({ moment_draft: 'wow' })    // → Personal.public
const profiles = await sdk.queryProfiles()          // → cross_enclave dataview

wallet

@enc-protocol/wallet-cli — multi-enclave + external chain. Enclaves: DM, Personal, Registry. Encrypted: messages.

appstore

@enc-protocol/appstore-clihost app. Bundles all 6 enclaves; no own write commands. Use bundled-enclave SDKs directly.

node

@enc-protocol/node-clihost app. Same shape as appstore.

Multi-enclave routing

For apps like super (3 enclaves), each submit<DataType>(args) resolves to the correct enclave via the schema's tableMap:

super.submitMessages({...})
  → tableMap.messages = "message"
  → "message" is declared in DM's customs
  → routes to DM.message

Resolution happens at runtime in AppSdk._resolve(name). Both data_types AND raw enclave event names are accepted — useful for backward-compat with enclave-shaped workflows.

Dataview (cross_enclave reads)

cross_enclave: true reads (e.g. super.profiles, dm.profiles) are served by DataView. It captures matching submits on the source enclave (per apps/<id>/infra.json's cross_enclave_reads) and serves rows on query — in-memory, Map-based UPSERT for Shared(<key>) slots and registry snapshots.

Production dataview (CF Durable Object + SQLite) lives in impl-emulator/dataview-workers/. The mem-mode dataview in @enc-protocol/cli-sdk-base mirrors its semantics without SQLite — sufficient for local development, testing, and most CLI use.

See also