@muhkoo/connect 0.9.0-alpha.0 → 0.10.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/blockEngine.worker.js.map +1 -1
- package/dist/browser/index.js +441 -71
- package/dist/browser/index.js.map +1 -1
- package/dist/connect.d.ts +103 -2
- package/dist/server/index.js +441 -71
- package/dist/server/index.js.map +1 -1
- package/package.json +1 -1
package/dist/connect.d.ts
CHANGED
|
@@ -1494,6 +1494,9 @@ declare class ShardClient {
|
|
|
1494
1494
|
* `null` for 404 so callers can distinguish "missing" from "errored".
|
|
1495
1495
|
*/
|
|
1496
1496
|
getShard(hash: string): Promise<Uint8Array | null>;
|
|
1497
|
+
/** Fetch a shard from origin. Returns `null` for 404 (or offline when a
|
|
1498
|
+
* cache is present, so RS recovery can proceed); throws otherwise. */
|
|
1499
|
+
private fetchFromOrigin;
|
|
1497
1500
|
/**
|
|
1498
1501
|
* Check whether a shard exists. Lets the caller skip a PUT they'd otherwise
|
|
1499
1502
|
* dedup-rewrite. The server can implement this as a HEAD or return a small
|
|
@@ -2511,6 +2514,21 @@ declare class ZkAuth {
|
|
|
2511
2514
|
* to re-enable encryption/messaging without a full re-login.
|
|
2512
2515
|
*/
|
|
2513
2516
|
restore(): Promise<AuthUser | null>;
|
|
2517
|
+
/**
|
|
2518
|
+
* Boot helper — call this once on app start. Restores the session AND, when a
|
|
2519
|
+
* passkey is enrolled, silently unlocks the identity via WebAuthn (recovering
|
|
2520
|
+
* the master seed so the ratchet keypair rehydrates and `client.kv` works).
|
|
2521
|
+
* The seed is never persisted, so a passkey (or password) is the only way to
|
|
2522
|
+
* unlock after a reload — this keeps that off the app's plate.
|
|
2523
|
+
*
|
|
2524
|
+
* Returns `{ user, unlocked }`. When `unlocked` is false (no passkey, the
|
|
2525
|
+
* user cancelled, or the browser required a gesture), prompt for a password
|
|
2526
|
+
* and call {@link unlock}. Apps need no key-management scaffolding beyond this.
|
|
2527
|
+
*/
|
|
2528
|
+
resume(): Promise<{
|
|
2529
|
+
user: AuthUser | null;
|
|
2530
|
+
unlocked: boolean;
|
|
2531
|
+
}>;
|
|
2514
2532
|
/**
|
|
2515
2533
|
* Re-derive identity material for an already-authenticated (restored)
|
|
2516
2534
|
* session, so the client can decrypt storage and run the ratchet. Verifies
|
|
@@ -3723,11 +3741,29 @@ declare class SpaceKeyring implements EpochKeyProvider {
|
|
|
3723
3741
|
private readonly policy;
|
|
3724
3742
|
/** Cached member directory: memberId → imported ECDSA verify key. */
|
|
3725
3743
|
private readonly memberEcdsa;
|
|
3744
|
+
/** Coalesce concurrent roster refreshes (the parallel history/backlog decode
|
|
3745
|
+
* would otherwise fire one `roster` fetch PER message — a thundering herd). */
|
|
3746
|
+
private dirInFlight;
|
|
3747
|
+
private dirRefreshedAt;
|
|
3748
|
+
/** Min gap between non-forced roster refreshes. A miss that persists within
|
|
3749
|
+
* this window won't re-fetch (the roster hasn't changed that fast); genuine
|
|
3750
|
+
* membership changes use `{ force: true }` (join requests / history loads). */
|
|
3751
|
+
private static readonly DIR_COOLDOWN_MS;
|
|
3726
3752
|
constructor(deps: SpaceKeyringDeps);
|
|
3727
3753
|
/** The cached ECDSA verify key for a member, if known. */
|
|
3728
3754
|
ecdsaKeyFor(memberId: string): CryptoKey | undefined;
|
|
3729
|
-
/**
|
|
3730
|
-
|
|
3755
|
+
/**
|
|
3756
|
+
* Refresh the member directory (memberId → ECDSA key) from the roster.
|
|
3757
|
+
* Coalesces concurrent callers into ONE fetch, and skips a fetch when one
|
|
3758
|
+
* completed within {@link DIR_COOLDOWN_MS} (unless `force`). Without this, a
|
|
3759
|
+
* page of N messages decoded in parallel — each missing the cold directory —
|
|
3760
|
+
* fires N simultaneous `roster` requests that queue behind the browser's
|
|
3761
|
+
* connection limit and take many seconds.
|
|
3762
|
+
*/
|
|
3763
|
+
refreshDirectory(opts?: {
|
|
3764
|
+
force?: boolean;
|
|
3765
|
+
}): Promise<void>;
|
|
3766
|
+
private doRefreshDirectory;
|
|
3731
3767
|
currentEpoch(): number;
|
|
3732
3768
|
keyForEpoch(epoch: number): Uint8Array | undefined;
|
|
3733
3769
|
hasAnyKey(): boolean;
|
|
@@ -3748,6 +3784,13 @@ declare class SpaceKeyring implements EpochKeyProvider {
|
|
|
3748
3784
|
* epoch keys obtained. Safe to call repeatedly (idempotent).
|
|
3749
3785
|
*/
|
|
3750
3786
|
pullKeys(): Promise<number>;
|
|
3787
|
+
/**
|
|
3788
|
+
* Background freshness check for the cache-hit fast path: confirm we hold the
|
|
3789
|
+
* current epoch (picks up a rotation / our removal) WITHOUT the full newcomer
|
|
3790
|
+
* admit handshake. Cheap + idempotent; never blocks first paint. Returns the
|
|
3791
|
+
* number of newly-obtained epoch keys (0 = already current).
|
|
3792
|
+
*/
|
|
3793
|
+
reconcile(): Promise<number>;
|
|
3751
3794
|
/**
|
|
3752
3795
|
* Wrap our group key(s) for a newcomer and post the blobs. In a `static`
|
|
3753
3796
|
* space the newcomer receives every epoch we hold (full history); in a
|
|
@@ -4207,6 +4250,53 @@ declare class MessageNamespace {
|
|
|
4207
4250
|
private myId;
|
|
4208
4251
|
}
|
|
4209
4252
|
|
|
4253
|
+
/**
|
|
4254
|
+
* `ChatKeyVault` — SDK-owned lifecycle for a member's long-lived ratchet/space
|
|
4255
|
+
* keypair (the connect `KeyStore` entry keyed by the member id / username).
|
|
4256
|
+
*
|
|
4257
|
+
* Historically each app hand-rolled this (see the web app's old
|
|
4258
|
+
* `personal/spaceLoader.ts`): generate a keypair at register, seed-wrap it, and
|
|
4259
|
+
* PUT it to the personal space; on login GET + unwrap + hydrate the `KeyStore`.
|
|
4260
|
+
* That scaffolding now lives here so ANY app gets a **stable** member keypair
|
|
4261
|
+
* across reloads for free — without which the member re-admits to every space on
|
|
4262
|
+
* every load and the group-key cache can never round-trip.
|
|
4263
|
+
*
|
|
4264
|
+
* Security invariant: the wrapping secret is the **master seed** (not the
|
|
4265
|
+
* password), so the blob survives password changes and unlocks under a passkey.
|
|
4266
|
+
* The seed is only ever held in memory (never persisted), so this vault can only
|
|
4267
|
+
* provision/rehydrate while the client is unlocked.
|
|
4268
|
+
*/
|
|
4269
|
+
|
|
4270
|
+
/** Opaque personal-space blob store (a `PersonalSpaceClient` or a kv-backed shim). */
|
|
4271
|
+
interface ChatKeyStore {
|
|
4272
|
+
get(key: string): Promise<WrappedPayload | null>;
|
|
4273
|
+
put(key: string, value: WrappedPayload): Promise<void>;
|
|
4274
|
+
}
|
|
4275
|
+
declare class ChatKeyVault {
|
|
4276
|
+
private readonly store;
|
|
4277
|
+
constructor(store: ChatKeyStore);
|
|
4278
|
+
/**
|
|
4279
|
+
* Register-time: ensure a keypair exists for `memberId`, seed-wrap the
|
|
4280
|
+
* dehydrated form, and persist it to the personal space. Idempotent — reuses
|
|
4281
|
+
* an existing in-tab keypair rather than minting a second one.
|
|
4282
|
+
*/
|
|
4283
|
+
provision(memberId: string, seedSecret: string): Promise<void>;
|
|
4284
|
+
/**
|
|
4285
|
+
* Sign-in / unlock time: fetch the wrapped blob, unwrap with the seed, and
|
|
4286
|
+
* hydrate the `KeyStore` — restoring the SAME keypair the member had before.
|
|
4287
|
+
* Returns `true` when a keypair is now in hand (already present or hydrated),
|
|
4288
|
+
* `false` when there's no blob yet (a brand-new member → caller provisions).
|
|
4289
|
+
* Throws only on a genuine unwrap failure (wrong secret / tampered blob).
|
|
4290
|
+
*/
|
|
4291
|
+
rehydrate(memberId: string, seedSecret: string): Promise<boolean>;
|
|
4292
|
+
/**
|
|
4293
|
+
* Ensure a stable keypair is in hand: rehydrate from the vault if a blob
|
|
4294
|
+
* exists, otherwise mint one and persist it (so it's stable next session).
|
|
4295
|
+
* Used at register and lazily when a space is first opened.
|
|
4296
|
+
*/
|
|
4297
|
+
ensure(memberId: string, seedSecret: string): Promise<void>;
|
|
4298
|
+
}
|
|
4299
|
+
|
|
4210
4300
|
/**
|
|
4211
4301
|
* `client.space` — the fan-out group-encryption surface.
|
|
4212
4302
|
*
|
|
@@ -4242,6 +4332,9 @@ interface SpaceNamespaceDeps {
|
|
|
4242
4332
|
cache?: SpaceKeyCache;
|
|
4243
4333
|
/** Offline manager — enables message caching + offline send replay. */
|
|
4244
4334
|
offline?: OfflineManager;
|
|
4335
|
+
/** SDK-owned ratchet-keypair vault — gives a STABLE member keypair across
|
|
4336
|
+
* reloads (rehydrate-or-provision) instead of a fresh one each session. */
|
|
4337
|
+
chatKeys?: ChatKeyVault;
|
|
4245
4338
|
/** P2P swarm config — enables peer block exchange among Space members. */
|
|
4246
4339
|
p2p?: {
|
|
4247
4340
|
enabled?: boolean;
|
|
@@ -4249,6 +4342,7 @@ interface SpaceNamespaceDeps {
|
|
|
4249
4342
|
workerFactory?: () => Worker;
|
|
4250
4343
|
iceServers?: RTCIceServer[];
|
|
4251
4344
|
maxPeers?: number;
|
|
4345
|
+
debug?: boolean;
|
|
4252
4346
|
};
|
|
4253
4347
|
}
|
|
4254
4348
|
declare class SpaceNamespace {
|
|
@@ -4727,6 +4821,8 @@ interface ClientOptions {
|
|
|
4727
4821
|
workerFactory?: () => Worker;
|
|
4728
4822
|
iceServers?: RTCIceServer[];
|
|
4729
4823
|
maxPeers?: number;
|
|
4824
|
+
/** Log P2P mesh + block-exchange activity to the console (staging/dev). */
|
|
4825
|
+
debug?: boolean;
|
|
4730
4826
|
};
|
|
4731
4827
|
}
|
|
4732
4828
|
declare class Client {
|
|
@@ -5245,10 +5341,13 @@ interface EngineHandle {
|
|
|
5245
5341
|
interface PeerExchangeOptions {
|
|
5246
5342
|
/** How long to wait for a peer before giving up to origin. Default 2500ms. */
|
|
5247
5343
|
timeoutMs?: number;
|
|
5344
|
+
/** Log peer-served vs origin-fallback per block to the console. */
|
|
5345
|
+
debug?: boolean;
|
|
5248
5346
|
}
|
|
5249
5347
|
declare class PeerExchange implements PeerBlockSource {
|
|
5250
5348
|
private readonly engine;
|
|
5251
5349
|
private readonly timeoutMs;
|
|
5350
|
+
private readonly debug;
|
|
5252
5351
|
constructor(engine: EngineHandle, opts?: PeerExchangeOptions);
|
|
5253
5352
|
getBlock(hash: string, opts?: {
|
|
5254
5353
|
timeoutMs?: number;
|
|
@@ -5404,6 +5503,8 @@ interface PeerNetworkOptions {
|
|
|
5404
5503
|
timeoutMs?: number;
|
|
5405
5504
|
/** Inject a transport (tests / a future libp2p transport). Default WebRTC. */
|
|
5406
5505
|
transport?: PeerTransport;
|
|
5506
|
+
/** Log mesh + block-exchange activity to the console (use on staging/dev). */
|
|
5507
|
+
debug?: boolean;
|
|
5407
5508
|
}
|
|
5408
5509
|
declare class PeerNetwork {
|
|
5409
5510
|
/** Pass this to a `ShardClient` as `peers`. */
|