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

4. Write the frontend app

Now the app, using the personal SDK. PersonalSdk is platform-agnostic — it takes one adapter per enclave it declares (Personal + Group). We use the formalized NetworkAdapter from @enc-protocol/client (codegen'd from the Lean spec): it does plaintext signed writes and the ECDH session-authenticated reads the node requires.

npm config set @enc-protocol:registry https://npm-registry.ocrybit.workers.dev/
npm install @enc-protocol/personal-cli @enc-protocol/client @enc-protocol/protocol-runtime

enc-personal.mjs — wire the SDK to a node

// enc-personal.mjs
import { PersonalSdk } from '@enc-protocol/personal-cli'
import { flattenEnclaveManifest } from '@enc-protocol/protocol-runtime'
import { createIdentity } from '@enc-protocol/client'
import { NetworkAdapter } from '@enc-protocol/client/network-adapter.js'
 
export { createIdentity }
 
/** Build a PersonalSdk wired to a real node (mints the owner's enclaves). */
export async function createPersonalSdk({ nodeUrl, identity = createIdentity() }) {
  const M = PersonalSdk.MANIFESTS
  const adapters = {}
 
  for (const name of M.app.enclaves) {            // ['Personal', 'Group']
    // the bundled enclave manifest → the wire RBAC manifest for this owner
    const wire = flattenEnclaveManifest(M.enclaves[name]).enclaveManifest(identity.publicKeyHex)
    const adapter = new NetworkAdapter(nodeUrl, '', identity)
    await adapter.createEnclave(wire)             // mint + wire the ECDH reader
    adapters[name] = adapter
  }
 
  const sdk = new PersonalSdk({ adapters, identity: { pubHex: identity.publicKeyHex } })
  await sdk.init()
  return sdk
}

app.mjs — the app

// app.mjs — NODE_URL=http://localhost:8787 node app.mjs
import { createPersonalSdk } from './enc-personal.mjs'
 
const sdk = await createPersonalSdk({ nodeUrl: process.env.NODE_URL || 'http://localhost:8787' })
 
await sdk.submitPublic({ draft: 'hello from my Personal app' })
await sdk.submitPrivate({ draft: 'a note only I can read' })
 
const posts = await sdk.queryPublic()
const notes = await sdk.queryPrivate()
 
console.log('public feed:')
for (const p of posts) console.log('  •', JSON.parse(p.content).draft)
console.log('private notes:')
for (const n of notes) console.log('  •', JSON.parse(n.content).draft)

Run it (with the node from step 1 running):

$ NODE_URL=http://localhost:8787 node app.mjs
public feed:
 hello from my Personal app
private notes:
 a note only I can read

The NetworkAdapter mints the enclave, signs writes, and runs the ECDH session-authenticated reads the node enforces — all from the formalized client SDK. Each query returns event objects whose content is the JSON you wrote, so JSON.parse(p.content).draft reads the field back.

Next: Write a test →