@enc-protocol/services
v0.9.0
Published
Platform-agnostic generic protocol services that sit between per-app SDKs (@enc-protocol/<app>-sdk) and platform adapters: Registry, Profiles, PeerMessaging, Subscriber, EnclaveProvisioner, plus a legacy-shim + composeSdk one-liner that wires everything t
Maintainers
Readme
@enc-protocol/services
Platform-agnostic generic protocol services that sit between per-app SDKs and platform adapters. Provides identity & enclave registration, cross-enclave profiles, peer messaging, event subscription with decryption, and dynamic enclave provisioning.
Install
npm install @enc-protocol/servicesAPI
Registry
Class for managing three independent registration sub-apps (identities, enclaves, nodes) that share one registry enclave. Delegates lookups to a RegistryStrategyFn plugin or falls back to HTTP dataview + event log traversal.
Registry constructor
new Registry(opts?: {
adapter?: Adapter,
identitiesAdapter?: Adapter,
enclavesAdapter?: Adapter,
nodesAdapter?: Adapter,
plugins?: ClientPluginRegistry
})registry.identities — Sub-app for identity records (pubkey → app enclaves map).
lookup(id_pub)→ Promise resolves record or null; caches resultspublish(record)→ Promise submits identity eventlist(opts?: {limit?})→ Promise resolves array of all identitiesresolveEnclave(pubKey, appName)→ Promise resolves{ok, enclave?, error?}
registry.enclaves — Sub-app for enclave directory.
lookup(enclave_id)→ Promise resolves record or nullpublish(record)→ Promise submits enclave eventlist(opts?: {limit?})→ Promise resolves array of all enclaves
registry.nodes — Sub-app for node directory.
lookup(seq_pub)→ Promise resolves record or nullpublish(record)→ Promise submits node eventlist(opts?: {limit?})→ Promise resolves array of all nodes
registry.setAdapter(adapter) — Point all three sub-apps at the same adapter.
registry.setPlugins(plugins) — Wire all three sub-apps to the RegistryStrategyFn plugin.
Profiles
Class for cross-enclave profile resolution. Profiles live in each user's Personal enclave under a Shared(profile) slot. Delegates to ProfileResolverFn plugin or falls back to synchronous cache lookup + HTTP dataview fetch.
Profiles constructor
new Profiles(opts?: {
personalAdapter?: Adapter,
dataviewUrl?: string,
plugins?: ClientPluginRegistry
})profiles.get(pubKey) — Promise resolves profile object for the given pubkey, or null if not found. Caches results.
profiles.set(profile) — Promise submits profile to the personal adapter's Shared(profile) slot.
profiles.nameFor(pubKey) — Synchronous lookup of profile name from cache. Returns first of name or display_name fields, or first 8 chars of pubkey as fallback.
profiles.setPersonalAdapter(adapter) — Point at a personal enclave adapter.
profiles.setDataviewUrl(url) — Set HTTP dataview base URL for profile queries.
PeerMessaging
Class for submitting events into a peer's enclave rather than the user's own. Routes via PeerRoutingFn plugin or falls back to registry lookup + optional encryption + adapter.toEnclave.
PeerMessaging constructor
new PeerMessaging(opts?: {
adapter?: Adapter,
registry?: Registry,
encrypted?: string[],
eventToDataType?: {[event: string]: string},
sdk?: any,
plugins?: ClientPluginRegistry
})peer.submit(peerPub, targetAppName, event, content, cryptoOpts?) — Promise<{ok, error?, receipt?, target?}> submits an event to peer's enclave. Resolves peer's enclave_id via registry, optionally encrypts content, and routes through adapter.toEnclave.
Subscriber
Class wrapping adapter.subscribe with optional per-event decryption. Decrypts content for events in encrypted set using sdk._decrypt, sdk.crypto.decrypt, or EnvelopeDecryptFn plugin.
Subscriber constructor
new Subscriber(opts?: {
adapter?: Adapter,
encrypted?: string[],
eventToDataType?: {[event: string]: string},
sdk?: any,
plugins?: ClientPluginRegistry
})subscriber.subscribe(callback) — Returns unsubscribe function. Calls callback with each event from adapter, auto-decrypting encrypted event types. Callback receives {type, content, from, _encrypted?, ...}.
EnclaveProvisioner
Class for minting enclaves on demand with timeout. Delegates to ProvisionerFn plugin or falls back to adapter.createEnclave with configurable timeout.
EnclaveProvisioner constructor
new EnclaveProvisioner(opts?: {
adapter?: Adapter,
timeoutMs?: number,
plugins?: ClientPluginRegistry
})provisioner.mint(rbacManifest) — Promise resolves enclave creation result. Throws on timeout (default 5000ms) or if adapter has no createEnclave method.
Schema
flattenEnclaveManifest(raw, opts?) — Transforms authored enclave JSON manifest into normalized {schema, states, traits, initEntries, ...} shape expected by adapters. Delegates to ManifestNormalizerFn plugin (default from @enc-protocol/plugin-client-base/normalizer).
setManifestNormalizer(fn) — Swap the active normalizer implementation. Pass null to restore the default.
Legacy Shim
createLegacyShim(opts) — Bridges typed SDK + protocol services to legacy impl-web renderer surface. Returns an object with:
- Dynamic
submit_<event>(content, cryptoOpts?)methods for each write event - Dynamic
query_<table>(queryOpts?)methods for each read table submit_to_peer(peerPub, targetAppName, event, content, cryptoOpts?)— delegates to peer.submitcreate_enclave(rbac)— delegates to provisioner.mintsubscribe(cb)— delegates to subscriber.subscribeidentities,enclaves,nodes— direct sub-app accessprofiles— direct profiles accessquery_events(eventType, opts?)— raw event query_events,_queries,_encrypted— metadata arrays for renderers
Composition
composeSdk(opts) — Construct typed SDK + all protocol services + legacy shim in one call.
composeSdk({
SdkClass: HelloSdk,
adapter: myAdapter,
crypto?: {encrypt, decrypt},
infra?: manifestWithEndpoints,
identity?: overrideFromAddress,
plugins?: ClientPluginRegistry
})Returns the legacy-shim wrapper. All SDK + services share one plugin registry, so plugin overrides apply consistently across encryption, routing, provisioning, etc. Throws if adapter is missing; returns null if SdkClass is null.
Example
import { composeSdk, Registry, Profiles, PeerMessaging } from '@enc-protocol/services'
import { HelloSdk } from '@enc-protocol/hello-sdk'
import { MemoryAdapter } from '@enc-protocol/adapters'
const adapter = new MemoryAdapter()
const registryAdapter = new MemoryAdapter()
// Option 1: Compose everything at once
const sdk = composeSdk({
SdkClass: HelloSdk,
adapter,
crypto: { encrypt, decrypt }
})
// Option 2: Assemble services separately
const registry = new Registry({ adapter: registryAdapter })
const profiles = new Profiles({ personalAdapter: adapter })
const peer = new PeerMessaging({ adapter, registry })
// Use the registry
const identity = await registry.identities.lookup('0x1234...')
await registry.identities.publish({ id_pub: '0x1234...', enclaves: { hello: 'encl_xyz' } })
// Cross-enclave profiles
const profile = await profiles.get('0x5678...')
await profiles.set({ name: 'Alice', display_name: 'alice.eth' })
// Send to peer's enclave
const result = await peer.submit('0x9abc...', 'hello', 'message', {body: 'hi'})
// Subscribe to events
const unsubscribe = sdk.subscribe(event => console.log(event))