/** * Presence handle — real-time awareness of who is viewing/editing a collection. * encrypted ephemeral channel keyed by collection DEK via HKDF. * * The presence key is derived from the collection DEK so: * - The adapter never learns user identities from presence payloads. * - Presence rotates automatically when the DEK rotates (revoked users * can no longer participate after a DEK rotation). * * Two transport strategies: * 1. **Pub/sub** (real-time): used when the adapter implements * `presencePublish` and `presenceSubscribe`. * 2. **Storage-poll** (fallback): presence records are written to a * reserved `_presence_` collection on the sync adapter * (if available) or local adapter, and polled periodically. */ import type { NoydbStore, PresencePeer } from '../../kernel/types.js'; import { type EnclaveKey } from '../../kernel/enclave/index.js'; /** Options for constructing a PresenceHandle. @internal */ export interface PresenceHandleOpts { /** Local adapter for storage-poll fallback. */ adapter: NoydbStore; /** Remote (sync) adapter — preferred for broadcasting presence if available. */ syncAdapter?: NoydbStore; /** Vault name — used as part of the channel and storage key. */ vault: string; /** Collection name — used as HKDF `info` and channel suffix. */ collectionName: string; /** Calling user's ID, embedded unencrypted in storage records. */ userId: string; /** Whether encryption is active. When false, presence payloads are stored as JSON. */ encrypted: boolean; /** Callback that resolves the collection DEK (used to derive the presence key). */ getDEK: (collectionName: string) => Promise; /** How long (ms) before a peer's presence is considered stale. Default: 30_000. */ staleMs?: number; /** Poll interval (ms) for the storage-poll fallback. Default: 5_000. */ pollIntervalMs?: number; } /** Presence handle for a single collection. */ export declare class PresenceHandle

{ private readonly adapter; private readonly syncAdapter; private readonly vault; private readonly collectionName; private readonly userId; private readonly encrypted; private readonly getDEK; private readonly staleMs; private readonly pollIntervalMs; private readonly channel; private readonly storageCollection; private presenceKey; private subscribers; private unsubscribePubSub; private pollTimer; private stopped; constructor(opts: PresenceHandleOpts); /** * Announce yourself (or update your cursor/status). * Encrypts `payload` with the presence key and publishes it. */ update(payload: P): Promise; /** * Subscribe to presence updates. The callback receives a filtered, decrypted * list of all currently-active peers (excluding yourself, excluding stale). * * Returns an unsubscribe function. Also call `stop()` to release all resources. */ subscribe(cb: (peers: PresencePeer

[]) => void): () => void; /** Stop all listening and clear resources. */ stop(): void; private getPresenceKey; private getPubSubAdapter; private startListening; private stopListening; private handlePubSubMessage; private decryptPresencePayload; private writeStorageRecord; private pollStoragePresence; }