this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Expose opake.did on the SDK, reframe the WASM accessor

The `getDid` WASM export had a stale docstring — it justified the
binding with "self-event filtering in the SSE consumer," a mechanism
removed when tree idempotency took over. Meanwhile every consumer
that renders a "signed in as..." UI, keys a local cache by account,
or discriminates between identities had no ergonomic way to ask the
SDK who this Opake represents: `listAccounts().find(a => a.isDefault)`
is clumsy and wrong when the caller passed an explicit DID to init;
reaching into `storage.loadConfig()` leaks the abstraction.

The capability is legitimate — the DID of an Opake instance is
invariant for its lifetime, the WASM side already has a cheap sync
accessor, and exposing it is universally useful. The dead
justification was the smell, not the method.

- WASM: rewrite `getDid`'s docstring around its actual purpose (cheap
sync identity accessor, called once by the SDK during init).
- SDK: add a `readonly did: string` field on `Opake`, populated in
`init()` via a single `ctx.getDid()` call (guaranteed lock-free
since no other code holds the mutex at that point). Surfaces on
`opake.did` — invariant, no round-trip, ergonomic for UI and
account-keyed caches.
- Update the class-level JSDoc with a `console.log("signed in as...")`
example so the property is discoverable.

+32 -5
+11 -3
crates/opake-wasm/src/opake_wasm.rs
··· 862 862 } 863 863 } 864 864 865 - /// Get the authenticated DID without exposing the full session. 865 + /// Return the DID this Opake was constructed for. 866 866 /// 867 - /// Returns the DID string, or an error if the context is busy or has 868 - /// no session. Used for self-event filtering in the SSE consumer. 867 + /// The DID is invariant for the lifetime of an OpakeContext — it's set 868 + /// once at `create()` time (either passed explicitly or resolved from 869 + /// the storage's default account) and never changes. Sync + cheap: 870 + /// the SDK calls this once during `Opake.init()` to populate a 871 + /// `readonly did: string` property, so JS consumers never have to 872 + /// round-trip into WASM to answer "who am I signed in as." 873 + /// 874 + /// Errors only on mutex contention via `try_lock`, which can't happen 875 + /// during the init window when the SDK calls it (no other code holds 876 + /// the lock before `Opake.init()` returns). 869 877 #[wasm_bindgen(js_name = getDid)] 870 878 pub fn get_did(&self) -> Result<String, JsError> { 871 879 let guard = self
+21 -2
packages/opake-sdk/src/opake.ts
··· 117 117 * All async methods proactively refresh the OAuth token before expiry — 118 118 * no manual token management needed. 119 119 * 120 + * The signed-in DID is available on the instance as `opake.did` — 121 + * invariant for the instance's lifetime, populated at init time. 122 + * 120 123 * @example 121 124 * ```typescript 122 125 * import { Opake } from "@opake/sdk"; 123 126 * import { IndexedDbStorage } from "@opake/sdk/storage/indexeddb"; 124 127 * 125 128 * const opake = await Opake.init({ storage: new IndexedDbStorage() }); 129 + * console.log(`signed in as ${opake.did}`); 126 130 * 127 131 * const cabinet = await opake.cabinet(); 128 132 * const tree = await cabinet.loadTree(); ··· 136 140 private readonly storage: Storage; 137 141 private refreshPromise: Promise<void> | null = null; 138 142 139 - private constructor(ctx: WasmOpakeContext, storage: Storage) { 143 + /** 144 + * The DID this Opake was constructed for. 145 + * 146 + * Populated once in `Opake.init()` from the underlying WASM context. 147 + * Invariant for the lifetime of the instance — if you need to switch 148 + * accounts, destroy this Opake and `init()` a new one with the target 149 + * DID. Useful for rendering "signed in as..." UI and for keying 150 + * consumer-side caches by account. 151 + */ 152 + readonly did: string; 153 + 154 + private constructor(ctx: WasmOpakeContext, storage: Storage, did: string) { 140 155 this.ctx = ctx; 141 156 this.storage = storage; 157 + this.did = did; 142 158 registerCleanup(this, ctx, this); 143 159 } 144 160 ··· 396 412 397 413 try { 398 414 const ctx = await wasm.OpakeContext.create(options?.did ?? null, adapter); 399 - return new Opake(ctx, storage); 415 + // Cache the resolved DID — sync read, no lock contention possible 416 + // this early in the lifecycle (nothing else holds the WASM mutex yet). 417 + const did = ctx.getDid(); 418 + return new Opake(ctx, storage, did); 400 419 } catch (e) { 401 420 throw parseWasmError(e); 402 421 }