@muhkoo/connect 0.14.0-alpha.9 → 0.15.0-alpha.1
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/README.md +2 -2
- package/dist/browser/index.js +2422 -538
- package/dist/browser/index.js.map +1 -1
- package/dist/connect.d.ts +813 -43
- package/dist/connect.workers.d.ts +38 -1
- package/dist/server/index.js +2422 -538
- package/dist/server/index.js.map +1 -1
- package/dist/workers/index.js +111 -22
- package/dist/workers/index.js.map +1 -1
- package/package.json +1 -1
package/dist/connect.d.ts
CHANGED
|
@@ -160,14 +160,14 @@ type Permission = 'read' | 'write' | 'delete' | 'admin' | 'share' | 'invite';
|
|
|
160
160
|
/**
|
|
161
161
|
* Role types
|
|
162
162
|
*/
|
|
163
|
-
type Role = 'owner' | 'admin' | 'editor' | 'viewer' | 'member';
|
|
163
|
+
type Role$1 = 'owner' | 'admin' | 'editor' | 'viewer' | 'member';
|
|
164
164
|
/**
|
|
165
165
|
* ACL Entry - grants permissions to a user (identified by public key)
|
|
166
166
|
*/
|
|
167
167
|
interface ACLEntry {
|
|
168
168
|
subject: string;
|
|
169
169
|
permissions: Permission[];
|
|
170
|
-
role?: Role;
|
|
170
|
+
role?: Role$1;
|
|
171
171
|
expiresAt?: number;
|
|
172
172
|
conditions?: {
|
|
173
173
|
ipAllowlist?: string[];
|
|
@@ -194,7 +194,7 @@ interface ACL {
|
|
|
194
194
|
*/
|
|
195
195
|
interface Participant {
|
|
196
196
|
publicKey: string;
|
|
197
|
-
role: Role;
|
|
197
|
+
role: Role$1;
|
|
198
198
|
addedAt: number;
|
|
199
199
|
addedBy: string;
|
|
200
200
|
customPermissions?: Permission[];
|
|
@@ -434,20 +434,51 @@ interface DehydratedKeys {
|
|
|
434
434
|
ecdsaPub: string;
|
|
435
435
|
ecdsaPriv: string;
|
|
436
436
|
}
|
|
437
|
+
/** A member's own ECDH and ECDSA pairs, held outside the store until {@link KeyStore.replaceOwnKeyPair}. */
|
|
438
|
+
interface OwnKeyPair {
|
|
439
|
+
ecdh: KeyPair;
|
|
440
|
+
ecdsa: AuthKeyPair;
|
|
441
|
+
}
|
|
437
442
|
declare class KeyStore {
|
|
438
443
|
private static instance;
|
|
439
444
|
private _keys;
|
|
440
445
|
private _authKeys;
|
|
446
|
+
/** The exact pairs marked vault-backed, so a pair written over them later is never taken for them. */
|
|
447
|
+
private _vaultBacked;
|
|
441
448
|
private constructor();
|
|
442
449
|
static getInstance(): KeyStore;
|
|
443
450
|
get keys(): Map<string, KeyPair>;
|
|
444
451
|
get authKeys(): Map<string, AuthKeyPair>;
|
|
445
452
|
generateOwnKeyPair(id: string): Promise<KeyPair>;
|
|
446
453
|
storeRemotePublicKeys(id: string, ecdhPublicKey: CryptoKey, ecdsaPublicKey: CryptoKey): Promise<void>;
|
|
454
|
+
/** Generate an own pair without touching the store; {@link replaceOwnKeyPair} puts it in place. */
|
|
455
|
+
generateKeyPair(): Promise<OwnKeyPair>;
|
|
447
456
|
hydrateKeyPair(id: string, dehydrated: DehydratedKeys): Promise<void>;
|
|
457
|
+
/** Import a dehydrated pair without touching the store; {@link replaceOwnKeyPair} puts it in place. */
|
|
458
|
+
importKeyPair(dehydrated: DehydratedKeys): Promise<OwnKeyPair>;
|
|
448
459
|
getKeyPair(id: string): KeyPair | null;
|
|
449
460
|
getAuthKeyPair(id: string): AuthKeyPair | null;
|
|
461
|
+
/** Record that the pair `id` holds now came from the seed-wrapped vault (ChatKeyVault). */
|
|
462
|
+
markVaultBacked(id: string): void;
|
|
463
|
+
/**
|
|
464
|
+
* Put `pair` in place as `id`'s own pair and mark it vault-backed, in one
|
|
465
|
+
* synchronous step: whatever `id` held before is dropped, so a pair minted
|
|
466
|
+
* while the vault pair was being fetched or generated is never kept and
|
|
467
|
+
* marked in its place (design §3.3).
|
|
468
|
+
*/
|
|
469
|
+
replaceOwnKeyPair(id: string, pair: OwnKeyPair): void;
|
|
470
|
+
/**
|
|
471
|
+
* Whether `id`'s own pair was loaded from, or persisted to, the vault in this
|
|
472
|
+
* tab, and is still the very pair that was marked. A Space identity must be
|
|
473
|
+
* vault-backed (design §3.3): any other pair, such as one minted by a locked
|
|
474
|
+
* DM subscription, never takes part, even one that lands over the marked pair.
|
|
475
|
+
*/
|
|
476
|
+
isVaultBacked(id: string): boolean;
|
|
477
|
+
/** Drop every key held for `id` (SpecA §6.4 `KeyStore.forget`). */
|
|
478
|
+
forget(id: string): void;
|
|
450
479
|
dehydrateKeyPair(id: string): Promise<DehydratedKeys>;
|
|
480
|
+
/** Dehydrate a pair that is not (yet) in the store, in the same format as {@link dehydrateKeyPair}. */
|
|
481
|
+
exportKeyPair(pair: OwnKeyPair): Promise<DehydratedKeys>;
|
|
451
482
|
getRawEcdsaPublicKey(id: string): Promise<Uint8Array | null>;
|
|
452
483
|
packDehydratedKeys(id: string): Promise<string>;
|
|
453
484
|
hydrateFromPacked(id: string, masterKey: string): Promise<void>;
|
|
@@ -522,7 +553,6 @@ declare class DoubleRatchet {
|
|
|
522
553
|
private sessionType;
|
|
523
554
|
private maxSkip;
|
|
524
555
|
private overlapPeriod;
|
|
525
|
-
private windowSize;
|
|
526
556
|
constructor(senderId: string, recipientId: string, sessionType: 'global' | 'specific', isClient?: boolean);
|
|
527
557
|
private hkdf;
|
|
528
558
|
initializeSession(isClient?: boolean): Promise<void>;
|
|
@@ -885,6 +915,8 @@ interface WSTransportOptions {
|
|
|
885
915
|
* auto-response. Default `"pong"`.
|
|
886
916
|
*/
|
|
887
917
|
pongFrame?: string;
|
|
918
|
+
/** A close with one of these codes is terminal: no reconnect, `DISCONNECTED` carries `{code, reason}`; `resume()` restarts. */
|
|
919
|
+
terminalCloseCodes?: number[];
|
|
888
920
|
}
|
|
889
921
|
declare class WSTransport extends EventCore {
|
|
890
922
|
/**
|
|
@@ -917,11 +949,14 @@ declare class WSTransport extends EventCore {
|
|
|
917
949
|
private pongFrame;
|
|
918
950
|
private heartbeatTimer;
|
|
919
951
|
private pongTimer;
|
|
952
|
+
private readonly terminalCloseCodes;
|
|
920
953
|
constructor(opts: WSTransportOptions);
|
|
921
954
|
/** Open the socket. Resolves when CONNECTED fires. Rejects on first error. */
|
|
922
955
|
connect(): Promise<void>;
|
|
923
956
|
/** Close the socket and stop reconnecting. */
|
|
924
957
|
disconnect(): void;
|
|
958
|
+
/** Restart reconnecting after a terminal close or `disconnect()`; the next URL comes from `urlProvider`. */
|
|
959
|
+
resume(): void;
|
|
925
960
|
/**
|
|
926
961
|
* Send a raw frame. If currently disconnected, the frame is queued and sent
|
|
927
962
|
* after the next successful reconnect (up to `maxQueueSize`).
|
|
@@ -1035,6 +1070,8 @@ declare class BroadcastChannel {
|
|
|
1035
1070
|
connect(): Promise<void>;
|
|
1036
1071
|
/** Close the WebSocket and stop reconnecting. */
|
|
1037
1072
|
disconnect(): void;
|
|
1073
|
+
/** Reconnect after a terminal close (see `terminalCloseCodes`) or `disconnect()`, on a fresh `urlProvider` URL. */
|
|
1074
|
+
resume(): void;
|
|
1038
1075
|
/**
|
|
1039
1076
|
* Send our `keyExchange` frame to the room. Idempotent — only sends on the
|
|
1040
1077
|
* first call. Call this once your higher-level handshake (e.g. sending a
|
|
@@ -1214,6 +1251,68 @@ declare class DoubleRatchetManager {
|
|
|
1214
1251
|
private loadState;
|
|
1215
1252
|
}
|
|
1216
1253
|
|
|
1254
|
+
/**
|
|
1255
|
+
* OPRF (Oblivious PRF) — RFC 9497, ristretto255-SHA512, mode 0x00.
|
|
1256
|
+
*
|
|
1257
|
+
* Used to gate the password/recovery factors of the identity vault
|
|
1258
|
+
* ({@link ./vault}). The wrap key for a password factor is
|
|
1259
|
+
* `HKDF(OPRF(serverKey, scrypt(password)))`, so:
|
|
1260
|
+
* - the client cannot derive the wrap key offline (it needs the server's
|
|
1261
|
+
* secret-keyed evaluation), and
|
|
1262
|
+
* - the server learns nothing — it only ever sees a *blinded* group element,
|
|
1263
|
+
* never the password or the resulting key.
|
|
1264
|
+
*
|
|
1265
|
+
* Net effect: a stolen vault blob is NOT offline-crackable; every guess costs a
|
|
1266
|
+
* round-trip to a rate-limited server endpoint. The same OPRF backs the M2
|
|
1267
|
+
* Google/email factors.
|
|
1268
|
+
*
|
|
1269
|
+
* Thin wrapper over `@noble/curves`' vetted `ristretto255_oprf` so the protocol
|
|
1270
|
+
* (blind / blindEvaluate / finalize) lives in one named place. CLIENT uses
|
|
1271
|
+
* {@link oprfBlind} + {@link oprfFinalize}.
|
|
1272
|
+
*
|
|
1273
|
+
* The `oprfDeriveKey` / `oprfBlindEvaluate` helpers here are the SERVER half,
|
|
1274
|
+
* but note they are used only by this repo's tests. The accelerator does NOT
|
|
1275
|
+
* import them: it has an independent implementation in its own
|
|
1276
|
+
* `src/services/oprf.ts`, also built directly on `@noble/curves`. (An earlier
|
|
1277
|
+
* version of this comment claimed the accelerator's VaultDO imported them; it
|
|
1278
|
+
* does not — it imports `@muhkoo/connect` in exactly two files, both for
|
|
1279
|
+
* Groth16 verification.) Any protocol change therefore has to land in BOTH
|
|
1280
|
+
* repos in lockstep.
|
|
1281
|
+
*
|
|
1282
|
+
* KNOWN WEAKNESS — mode 0x00, tracked as audit finding C4 and NOT fixed here.
|
|
1283
|
+
* This uses RFC 9497 base mode: the server returns a bare evaluation with no
|
|
1284
|
+
* DLEQ proof, and {@link oprfFinalize} verifies nothing. A hostile server can
|
|
1285
|
+
* answer `{evaluated: blinded}` (i.e. k=1); the unblinded point is then just
|
|
1286
|
+
* `H(input)` and the wrap key collapses to a pure function of public strings,
|
|
1287
|
+
* destroying the offline-uncrackability guarantee stated above.
|
|
1288
|
+
*
|
|
1289
|
+
* The fix is `ristretto255_oprf.voprf` (mode 0x01) with the server's public key
|
|
1290
|
+
* pinned as a build-time constant and the proof verified on every finalize.
|
|
1291
|
+
* noble's `voprf` variant is already present and unused. It cannot be done
|
|
1292
|
+
* client-side alone: the wire response (`{evaluated}` / `{evaluated, evaluated2}`)
|
|
1293
|
+
* carries no proof field, and the pinned public keys must correspond to the
|
|
1294
|
+
* accelerator's actual K1/K2 secrets. Changing only this file would break login
|
|
1295
|
+
* against the live server.
|
|
1296
|
+
*/
|
|
1297
|
+
/**
|
|
1298
|
+
* The RFC 9497 mode this client speaks, declared on every evaluation request.
|
|
1299
|
+
*
|
|
1300
|
+
* Declaring it is what lets the server refuse loudly instead of answering in a
|
|
1301
|
+
* mode we did not ask for — the silent substitution that IS audit finding C4.
|
|
1302
|
+
* A server too old to know the field drops it and answers in base mode, which is
|
|
1303
|
+
* what we asked for anyway, so sending it is safe in both directions and imposes
|
|
1304
|
+
* no deploy ordering.
|
|
1305
|
+
*
|
|
1306
|
+
* NOT to be confused with the vault's KEY VERSION, a different axis that also
|
|
1307
|
+
* uses small integers: there, `2` means "per-account key". Here `2` means POPRF.
|
|
1308
|
+
* The server half of these constants is `accelerator/src/services/oprf.ts` and
|
|
1309
|
+
* MUST hold the same numbers.
|
|
1310
|
+
*/
|
|
1311
|
+
declare const OPRF_PROTOCOL_BASE = 0;
|
|
1312
|
+
/** RFC 9497 mode 0x02 — the fix for C4. Reserved; no deployment serves it yet. */
|
|
1313
|
+
declare const OPRF_PROTOCOL_POPRF = 2;
|
|
1314
|
+
type OprfProtocol = typeof OPRF_PROTOCOL_BASE | typeof OPRF_PROTOCOL_POPRF;
|
|
1315
|
+
|
|
1217
1316
|
/**
|
|
1218
1317
|
* HTTP client for the accelerator's `/api/auth/*` endpoints.
|
|
1219
1318
|
*
|
|
@@ -1227,6 +1326,21 @@ declare class DoubleRatchetManager {
|
|
|
1227
1326
|
* (with the worker's message inlined where available).
|
|
1228
1327
|
*/
|
|
1229
1328
|
|
|
1329
|
+
/**
|
|
1330
|
+
* A non-2xx response from `/api/auth/*`, carrying the HTTP status and the
|
|
1331
|
+
* worker's machine-readable `code` alongside its human `error` string.
|
|
1332
|
+
*
|
|
1333
|
+
* Exists because the status used to be discarded: every failure arrived as a
|
|
1334
|
+
* bare `Error` whose only distinguishing feature was its message, so classifying
|
|
1335
|
+
* one meant regex-matching a sentence the server is free to reword. See
|
|
1336
|
+
* `VaultUnavailableError`, which still does exactly that for rate limits.
|
|
1337
|
+
*/
|
|
1338
|
+
declare class AuthHttpError extends Error {
|
|
1339
|
+
readonly label: string;
|
|
1340
|
+
readonly status: number;
|
|
1341
|
+
readonly code: string | undefined;
|
|
1342
|
+
constructor(label: string, status: number, code: string | undefined, detail: string);
|
|
1343
|
+
}
|
|
1230
1344
|
interface ZkRegisterRequest {
|
|
1231
1345
|
username: string;
|
|
1232
1346
|
/** Decimal-string Poseidon commitment. */
|
|
@@ -1306,16 +1420,24 @@ declare class AuthClient {
|
|
|
1306
1420
|
verify(token: string): Promise<{
|
|
1307
1421
|
username: string;
|
|
1308
1422
|
}>;
|
|
1309
|
-
/**
|
|
1310
|
-
|
|
1423
|
+
/**
|
|
1424
|
+
* Blinded OPRF evaluation — the server-gated half of a password/recovery wrap key.
|
|
1425
|
+
*
|
|
1426
|
+
* `oprfProtocol` declares the RFC 9497 mode this client speaks so the server
|
|
1427
|
+
* can refuse rather than answer in a different one. A server too old to know
|
|
1428
|
+
* the field drops it and answers in base mode, so this is safe against any
|
|
1429
|
+
* deployment.
|
|
1430
|
+
*/
|
|
1431
|
+
oprfEvaluate(username: string, blinded: string, oprfProtocol?: OprfProtocol): Promise<{
|
|
1311
1432
|
evaluated: string;
|
|
1312
1433
|
}>;
|
|
1313
1434
|
/**
|
|
1314
|
-
* Gated
|
|
1315
|
-
*
|
|
1316
|
-
*
|
|
1435
|
+
* Gated OPRF evaluation (M2 — email/google factors). Requires a live
|
|
1436
|
+
* `verifyToken` from {@link emailOtpVerify}; returns BOTH keys'
|
|
1437
|
+
* evaluations (K1 and K2, both operated by Muhkoo). The recover token is
|
|
1438
|
+
* consumed by this call.
|
|
1317
1439
|
*/
|
|
1318
|
-
oprfEvaluateGated(username: string, blinded: string, factorType: "email" | "google", purpose: "enroll" | "recover", verifyToken: string): Promise<{
|
|
1440
|
+
oprfEvaluateGated(username: string, blinded: string, factorType: "email" | "google", purpose: "enroll" | "recover", verifyToken: string, oprfProtocol?: OprfProtocol): Promise<{
|
|
1319
1441
|
evaluated: string;
|
|
1320
1442
|
evaluated2: string;
|
|
1321
1443
|
}>;
|
|
@@ -2896,6 +3018,11 @@ interface HostedAuthDeps {
|
|
|
2896
3018
|
/** Sleep used by the poll loop. Injectable so tests don't burn wall-clock. */
|
|
2897
3019
|
sleep?: (ms: number, signal?: AbortSignal) => Promise<void>;
|
|
2898
3020
|
}
|
|
3021
|
+
/**
|
|
3022
|
+
* A same-origin path the app may be sent back to after sign-in. It starts with
|
|
3023
|
+
* "/", not "//", and has no backslash or control characters (design §4.4.9).
|
|
3024
|
+
*/
|
|
3025
|
+
declare function isSameOriginPath(p: unknown): p is string;
|
|
2899
3026
|
/** One in-flight pairing attempt. Hold it; pass it back into poll/wait/cancel. */
|
|
2900
3027
|
interface DevicePairingSession {
|
|
2901
3028
|
/** Opaque; carry it back into poll/wait/cancel. Never render it. */
|
|
@@ -3048,13 +3175,15 @@ declare class HostedAuth {
|
|
|
3048
3175
|
* (App side) Begin hosted login: stash a PKCE verifier + state, then send
|
|
3049
3176
|
* the browser to the hosted authorize page. Returns the URL it redirects to
|
|
3050
3177
|
* (also useful for popup mode / tests). `redirectUri` must be registered for
|
|
3051
|
-
* the app in the portal.
|
|
3178
|
+
* the app in the portal. `returnTo`, a same-origin path, rides the stash and
|
|
3179
|
+
* comes back from {@link handleCallback}; anything else is refused here.
|
|
3052
3180
|
*/
|
|
3053
3181
|
login(opts: {
|
|
3054
3182
|
appId: string;
|
|
3055
3183
|
redirectUri: string;
|
|
3056
3184
|
redirect?: boolean;
|
|
3057
3185
|
prompt?: "login";
|
|
3186
|
+
returnTo?: string;
|
|
3058
3187
|
}): Promise<string>;
|
|
3059
3188
|
/**
|
|
3060
3189
|
* (App side) Send the user to centralized account & security management on
|
|
@@ -3071,9 +3200,12 @@ declare class HostedAuth {
|
|
|
3071
3200
|
/**
|
|
3072
3201
|
* (App side) Complete login on the callback URL: verify state, exchange the
|
|
3073
3202
|
* code (+ PKCE verifier) for the session, unseal the seed from the fragment,
|
|
3074
|
-
* establish the session, and scrub the URL. Returns the signed-in user
|
|
3203
|
+
* establish the session, and scrub the URL. Returns the signed-in user, with
|
|
3204
|
+
* the `returnTo` passed to {@link login} when it is still a same-origin path.
|
|
3075
3205
|
*/
|
|
3076
|
-
handleCallback(): Promise<AuthUser
|
|
3206
|
+
handleCallback(): Promise<AuthUser & {
|
|
3207
|
+
returnTo?: string;
|
|
3208
|
+
}>;
|
|
3077
3209
|
/**
|
|
3078
3210
|
* (Hosted-page side) Finish an /authorize request after the user has
|
|
3079
3211
|
* authenticated here: seal the in-memory seed, mint the grant, and return
|
|
@@ -3299,6 +3431,24 @@ declare function formatUserCode(canonical: string): string;
|
|
|
3299
3431
|
declare class VaultUnavailableError extends Error {
|
|
3300
3432
|
constructor(cause?: unknown);
|
|
3301
3433
|
}
|
|
3434
|
+
/**
|
|
3435
|
+
* The vault refused the OPRF protocol this client speaks.
|
|
3436
|
+
*
|
|
3437
|
+
* Distinct from {@link VaultUnavailableError} because the remedy is different and
|
|
3438
|
+
* the two used to be conflated: "unavailable" means retry, and a version mismatch
|
|
3439
|
+
* never resolves by retrying — it resolves by updating the app (or the server).
|
|
3440
|
+
*
|
|
3441
|
+
* Critically, this must NOT be caught into the
|
|
3442
|
+
* `vaultSeed ?? deriveMasterSeedFromPassword(...)` fallback in `login`/`unlock`.
|
|
3443
|
+
* That fallback is correct for an account with no password factor, and wrong for
|
|
3444
|
+
* a refusal: it derives a different seed, and on a legacy-migrated account —
|
|
3445
|
+
* where the fallback seed happens to be the right one — it would let
|
|
3446
|
+
* `migrateLegacyPasswordFactor` rewrite the factor as a side effect of a failure
|
|
3447
|
+
* the user was never shown.
|
|
3448
|
+
*/
|
|
3449
|
+
declare class VaultProtocolMismatchError extends Error {
|
|
3450
|
+
constructor(cause?: unknown);
|
|
3451
|
+
}
|
|
3302
3452
|
/**
|
|
3303
3453
|
* A stored device pairing that the account has since revoked.
|
|
3304
3454
|
*
|
|
@@ -3428,15 +3578,16 @@ declare class ZkAuth {
|
|
|
3428
3578
|
recoverWithPhrase(username: string, mnemonic: string, opts?: LoginOptions): Promise<AuthUser>;
|
|
3429
3579
|
/**
|
|
3430
3580
|
* Add an **email** as a recovery + login factor (M2 verification-gated:
|
|
3431
|
-
* the server only releases the
|
|
3581
|
+
* the server only releases the gated OPRF eval after the address is
|
|
3432
3582
|
* OTP-verified). Sends the code, then returns a `confirm` continuation:
|
|
3433
3583
|
*
|
|
3434
3584
|
* const { confirm } = await client.auth.zk.enrollEmailFactor("me@x.com");
|
|
3435
3585
|
* await confirm(codeFromInbox);
|
|
3436
3586
|
*
|
|
3437
3587
|
* Requires being signed in with the seed held (like the other enrolls).
|
|
3438
|
-
* Custody note:
|
|
3439
|
-
*
|
|
3588
|
+
* Custody note: Muhkoo holds the keys behind gated factors, so it can
|
|
3589
|
+
* recover the seed of any account with an email or Google factor. The
|
|
3590
|
+
* hosted sign-in UI discloses this; a custom enroll UI must too.
|
|
3440
3591
|
*/
|
|
3441
3592
|
enrollEmailFactor(email: string): Promise<{
|
|
3442
3593
|
email: string;
|
|
@@ -3445,7 +3596,7 @@ declare class ZkAuth {
|
|
|
3445
3596
|
/**
|
|
3446
3597
|
* Recover an account via its enrolled **email** factor. Sends a code to the
|
|
3447
3598
|
* enrolled address (the response never reveals whether one exists), then
|
|
3448
|
-
* `confirm(code)` completes: gated read +
|
|
3599
|
+
* `confirm(code)` completes: gated read + gated OPRF eval → unwrap seed →
|
|
3449
3600
|
* normal ZK login. After this, call {@link changePassword} to set a new
|
|
3450
3601
|
* password.
|
|
3451
3602
|
*
|
|
@@ -3458,11 +3609,14 @@ declare class ZkAuth {
|
|
|
3458
3609
|
/**
|
|
3459
3610
|
* Link a Google account as a recovery + login factor. Requires being signed
|
|
3460
3611
|
* in with the seed held. `idToken` is a fresh Google ID token (GIS).
|
|
3612
|
+
* Custody note: as with {@link enrollEmailFactor}, Muhkoo holds the keys
|
|
3613
|
+
* behind this factor and can recover the seed of an account that has it.
|
|
3614
|
+
* The hosted sign-in UI discloses this; a custom enroll UI must too.
|
|
3461
3615
|
*/
|
|
3462
3616
|
enrollGoogleFactor(idToken: string): Promise<void>;
|
|
3463
3617
|
/**
|
|
3464
3618
|
* Sign in with Google — verify the ID token, unlock the seed via the gated
|
|
3465
|
-
*
|
|
3619
|
+
* OPRF eval, and establish a session. Same machinery serves "Sign in
|
|
3466
3620
|
* with Google" and "recover with Google"; the account must have linked the
|
|
3467
3621
|
* factor first.
|
|
3468
3622
|
*/
|
|
@@ -3471,7 +3625,8 @@ declare class ZkAuth {
|
|
|
3471
3625
|
* Register a brand-new, **passwordless** account whose only factor is Google.
|
|
3472
3626
|
* A random master seed is generated and wrapped under the Google-gated key;
|
|
3473
3627
|
* the user can add a password / passkey / phrase later. The ZK registration
|
|
3474
|
-
* is identical to a password signup.
|
|
3628
|
+
* is identical to a password signup. Custody note: see
|
|
3629
|
+
* {@link enrollGoogleFactor} — Muhkoo can recover this account's seed.
|
|
3475
3630
|
*/
|
|
3476
3631
|
registerWithGoogle(username: string, idToken: string): Promise<AuthUser>;
|
|
3477
3632
|
/**
|
|
@@ -3726,9 +3881,10 @@ interface HttpClientOptions {
|
|
|
3726
3881
|
* token) or `false` if it couldn't (the `401` propagates as an
|
|
3727
3882
|
* {@link HttpError}). Wired by {@link Client} to `auth.zk.recover()`.
|
|
3728
3883
|
*
|
|
3729
|
-
* Only consulted by the JSON helpers (`get`/`post`/`del`)
|
|
3730
|
-
* {@link
|
|
3731
|
-
* power recovery itself
|
|
3884
|
+
* Only consulted by the JSON helpers (`get`/`post`/`del`) and
|
|
3885
|
+
* {@link HttpClient.fetchWithRecovery}; the raw {@link fetch} passes 401s
|
|
3886
|
+
* straight through so the auth wire calls that power recovery itself
|
|
3887
|
+
* can't recurse.
|
|
3732
3888
|
*/
|
|
3733
3889
|
onUnauthorized?: () => Promise<boolean>;
|
|
3734
3890
|
}
|
|
@@ -3755,6 +3911,15 @@ declare class HttpClient {
|
|
|
3755
3911
|
* up credentials without knowing about them.
|
|
3756
3912
|
*/
|
|
3757
3913
|
readonly fetch: typeof fetch;
|
|
3914
|
+
/**
|
|
3915
|
+
* {@link fetch} with the JSON helpers' stale-session recovery: a 401 on a
|
|
3916
|
+
* request made while a session token is held runs `onUnauthorized` once
|
|
3917
|
+
* and, if that recovered, replays the request once with the fresh token.
|
|
3918
|
+
* The final response is returned whatever its status, never thrown. The
|
|
3919
|
+
* replay re-sends `init` as given, so its body must be re-sendable (a
|
|
3920
|
+
* string or bytes, not a stream).
|
|
3921
|
+
*/
|
|
3922
|
+
readonly fetchWithRecovery: typeof fetch;
|
|
3758
3923
|
/** True when `input` resolves to {@link baseOrigin} (relative URLs always do). */
|
|
3759
3924
|
private isSameOrigin;
|
|
3760
3925
|
get<T = unknown>(path: string): Promise<T>;
|
|
@@ -3919,8 +4084,9 @@ interface OfflineStore {
|
|
|
3919
4084
|
* mutation by re-invoking the real namespace method (with an `isReplay` flag so
|
|
3920
4085
|
* it doesn't re-enqueue). `drain()` replays entries in HLC order:
|
|
3921
4086
|
* - success → remove the entry;
|
|
3922
|
-
* - permanent failure (4xx
|
|
3923
|
-
*
|
|
4087
|
+
* - permanent failure (4xx, or a Space whose member list refuses this user)
|
|
4088
|
+
* → drop it and surface a `SYNC_ERROR` (a write the server will never
|
|
4089
|
+
* accept must not wedge the queue forever);
|
|
3924
4090
|
* - transient/network failure → stop draining and leave the rest for the next
|
|
3925
4091
|
* reconnect.
|
|
3926
4092
|
*
|
|
@@ -4500,6 +4666,140 @@ declare class StorageNamespace {
|
|
|
4500
4666
|
private space;
|
|
4501
4667
|
}
|
|
4502
4668
|
|
|
4669
|
+
/**
|
|
4670
|
+
* Wire types of the e2e-channels trust layer (spec 2026-09-27 §3.2, §3.5,
|
|
4671
|
+
* §4.2.4, §5.3.1). These shapes are signed and stored: never rename a field.
|
|
4672
|
+
*
|
|
4673
|
+
* Every string field holds the exact string that was transmitted; the
|
|
4674
|
+
* canonical encoders in `canonical.ts` sign those strings as they are.
|
|
4675
|
+
*
|
|
4676
|
+
* Ported from the accelerator's `src/trust/types.ts` (the server-only app
|
|
4677
|
+
* roster types are left out); the shared shapes must stay identical.
|
|
4678
|
+
*/
|
|
4679
|
+
type Visibility = "private" | "public";
|
|
4680
|
+
type HistoryPolicy$1 = "static" | "rotate";
|
|
4681
|
+
type MemberRole = "viewer" | "editor";
|
|
4682
|
+
type SvcMode = "addressed" | "all";
|
|
4683
|
+
type MlogOp = "genesis" | "add" | "role" | "remove" | "leave" | "join" | "link" | "unlink" | "redeem" | "svc" | "retire";
|
|
4684
|
+
/** `legacyCommits` is `{}` for a new Space; values are b64url of 32 bytes, keys canonical decimal epochs. */
|
|
4685
|
+
interface GenesisBody {
|
|
4686
|
+
visibility: Visibility;
|
|
4687
|
+
policy: HistoryPolicy$1;
|
|
4688
|
+
appId: string;
|
|
4689
|
+
baseEpoch: number;
|
|
4690
|
+
legacyCommits: Record<string, string>;
|
|
4691
|
+
}
|
|
4692
|
+
interface AddBody {
|
|
4693
|
+
member: string;
|
|
4694
|
+
memberIk: string;
|
|
4695
|
+
role: MemberRole;
|
|
4696
|
+
}
|
|
4697
|
+
interface RoleBody {
|
|
4698
|
+
member: string;
|
|
4699
|
+
role: MemberRole;
|
|
4700
|
+
}
|
|
4701
|
+
interface RemoveBody {
|
|
4702
|
+
member: string;
|
|
4703
|
+
}
|
|
4704
|
+
type LeaveBody = Record<string, never>;
|
|
4705
|
+
/** `via` is a linkId, or "" for no link. */
|
|
4706
|
+
interface JoinBody {
|
|
4707
|
+
via: string;
|
|
4708
|
+
}
|
|
4709
|
+
interface LinkBody {
|
|
4710
|
+
linkId: string;
|
|
4711
|
+
role: MemberRole;
|
|
4712
|
+
standing: boolean;
|
|
4713
|
+
expiresAt: number;
|
|
4714
|
+
maxUses: number;
|
|
4715
|
+
linkEcdhPub: string;
|
|
4716
|
+
linkSignPub: string;
|
|
4717
|
+
keyCommits: Record<string, string>;
|
|
4718
|
+
}
|
|
4719
|
+
interface UnlinkBody {
|
|
4720
|
+
linkId: string;
|
|
4721
|
+
}
|
|
4722
|
+
interface RedeemBody {
|
|
4723
|
+
linkId: string;
|
|
4724
|
+
}
|
|
4725
|
+
interface SvcBody {
|
|
4726
|
+
member: string;
|
|
4727
|
+
action: "add" | "remove";
|
|
4728
|
+
ecdhPub: string;
|
|
4729
|
+
ecdsaPub: string;
|
|
4730
|
+
mode: SvcMode;
|
|
4731
|
+
rosterSeq: number;
|
|
4732
|
+
}
|
|
4733
|
+
interface RetireBody {
|
|
4734
|
+
member: string;
|
|
4735
|
+
reason: string;
|
|
4736
|
+
}
|
|
4737
|
+
interface MlogBodies {
|
|
4738
|
+
genesis: GenesisBody;
|
|
4739
|
+
add: AddBody;
|
|
4740
|
+
role: RoleBody;
|
|
4741
|
+
remove: RemoveBody;
|
|
4742
|
+
leave: LeaveBody;
|
|
4743
|
+
join: JoinBody;
|
|
4744
|
+
link: LinkBody;
|
|
4745
|
+
unlink: UnlinkBody;
|
|
4746
|
+
redeem: RedeemBody;
|
|
4747
|
+
svc: SvcBody;
|
|
4748
|
+
retire: RetireBody;
|
|
4749
|
+
}
|
|
4750
|
+
interface EntryBase {
|
|
4751
|
+
v: 1;
|
|
4752
|
+
spaceId: string;
|
|
4753
|
+
/** 0 = genesis; −1 only in an enable intent (§5.3.3), never stored. */
|
|
4754
|
+
seq: number;
|
|
4755
|
+
/** hash of entry seq−1; "" at genesis and in an intent. */
|
|
4756
|
+
prev: string;
|
|
4757
|
+
/** Signer member id; "" in a server-written `retire`. */
|
|
4758
|
+
by: string;
|
|
4759
|
+
/** Signer IK (b64 or hex raw P-256), exactly as sent; "" in a `retire`. */
|
|
4760
|
+
ik: string;
|
|
4761
|
+
/** Signer clock, informational. */
|
|
4762
|
+
at: number;
|
|
4763
|
+
/** b64 P1363 ECDSA-P256-SHA256 by `ik` over entryBytes; "" only in a `retire`. */
|
|
4764
|
+
sig: string;
|
|
4765
|
+
/** Link-sign signature over entryBytes (`link`, `redeem`, `join` with `via`). */
|
|
4766
|
+
lsig?: string;
|
|
4767
|
+
}
|
|
4768
|
+
type MembershipEntry<O extends MlogOp = MlogOp> = {
|
|
4769
|
+
[K in O]: EntryBase & {
|
|
4770
|
+
op: K;
|
|
4771
|
+
body: MlogBodies[K];
|
|
4772
|
+
};
|
|
4773
|
+
}[O];
|
|
4774
|
+
type UnsignedEntry<O extends MlogOp = MlogOp> = {
|
|
4775
|
+
[K in O]: Omit<MembershipEntry<K>, "sig" | "lsig">;
|
|
4776
|
+
}[O];
|
|
4777
|
+
interface ChatKeyCert {
|
|
4778
|
+
v: 1;
|
|
4779
|
+
ik: string;
|
|
4780
|
+
ecdh: string;
|
|
4781
|
+
ecdsa: string;
|
|
4782
|
+
sig: string;
|
|
4783
|
+
}
|
|
4784
|
+
interface EpochCommit {
|
|
4785
|
+
v: 1;
|
|
4786
|
+
spaceId: string;
|
|
4787
|
+
epoch: number;
|
|
4788
|
+
prevKeyed: number;
|
|
4789
|
+
keyCommit: string;
|
|
4790
|
+
headSeq: number;
|
|
4791
|
+
headHash: string;
|
|
4792
|
+
sole: boolean;
|
|
4793
|
+
by: string;
|
|
4794
|
+
ik: string;
|
|
4795
|
+
at: number;
|
|
4796
|
+
sig: string;
|
|
4797
|
+
}
|
|
4798
|
+
interface MlogHead {
|
|
4799
|
+
seq: number;
|
|
4800
|
+
hash: string;
|
|
4801
|
+
}
|
|
4802
|
+
|
|
4503
4803
|
/**
|
|
4504
4804
|
* Shared types for the Space fan-out group-encryption layer.
|
|
4505
4805
|
*
|
|
@@ -4509,6 +4809,7 @@ declare class StorageNamespace {
|
|
|
4509
4809
|
* which is what lets the server persist + replay messages as history while
|
|
4510
4810
|
* staying blind to their contents.
|
|
4511
4811
|
*/
|
|
4812
|
+
|
|
4512
4813
|
/**
|
|
4513
4814
|
* How a space treats history across membership changes.
|
|
4514
4815
|
* - `static`: one group key for all time (epoch 0). New members can read the
|
|
@@ -4556,6 +4857,8 @@ interface JoinRequest {
|
|
|
4556
4857
|
/** Epoch the newcomer wants a key for (defaults to current). */
|
|
4557
4858
|
desiredEpoch?: number;
|
|
4558
4859
|
ts?: number;
|
|
4860
|
+
/** The account IK's certificate over the two identity strings above (design §3.2). Optional: a join never requires one. */
|
|
4861
|
+
keyCert?: ChatKeyCert;
|
|
4559
4862
|
}
|
|
4560
4863
|
/** A space member's published identity keys (the keyring directory). */
|
|
4561
4864
|
interface RosterMember {
|
|
@@ -4710,6 +5013,18 @@ interface KeyringTransport {
|
|
|
4710
5013
|
/** Add `username` to a private channel's membership allowlist. */
|
|
4711
5014
|
invite(username: string): Promise<void>;
|
|
4712
5015
|
fetchMetadata(): Promise<SpaceMetadata | null>;
|
|
5016
|
+
/** GET /keyring/log (design §3.6): entries with seq > since, ascending, ≤ limit; head null = no log. */
|
|
5017
|
+
fetchLog?(since?: number, limit?: number): Promise<{
|
|
5018
|
+
entries: MembershipEntry[];
|
|
5019
|
+
head: MlogHead | null;
|
|
5020
|
+
}>;
|
|
5021
|
+
/** POST /keyring/log {entry, ec?}. */
|
|
5022
|
+
postLogEntry?(entry: MembershipEntry, ec?: EpochCommit): Promise<{
|
|
5023
|
+
ok: true;
|
|
5024
|
+
head: MlogHead;
|
|
5025
|
+
}>;
|
|
5026
|
+
/** Status of GET /keyring/state, or "network" when the request fails. */
|
|
5027
|
+
probeState?(): Promise<number | "network">;
|
|
4713
5028
|
}
|
|
4714
5029
|
/** PersonalSpace-backed cache of this member's group keys (epoch → base64 key). */
|
|
4715
5030
|
interface SpaceKeyCache {
|
|
@@ -4729,6 +5044,10 @@ interface SpaceKeyringDeps {
|
|
|
4729
5044
|
transport: KeyringTransport;
|
|
4730
5045
|
cache?: SpaceKeyCache;
|
|
4731
5046
|
historyPolicy?: HistoryPolicy;
|
|
5047
|
+
/** Mints the IK certificate for this member's chat keys (design §3.2). Absent, or resolving undefined, means none. */
|
|
5048
|
+
keyCert?: () => Promise<ChatKeyCert | undefined>;
|
|
5049
|
+
/** Whether a key may be wrapped to `memberId`; absent means anyone. On a signed Space: log members and the keeper only. */
|
|
5050
|
+
canWrapTo?: (memberId: string) => boolean;
|
|
4732
5051
|
}
|
|
4733
5052
|
declare class SpaceKeyring implements EpochKeyProvider {
|
|
4734
5053
|
private readonly deps;
|
|
@@ -4745,7 +5064,11 @@ declare class SpaceKeyring implements EpochKeyProvider {
|
|
|
4745
5064
|
* this window won't re-fetch (the roster hasn't changed that fast); genuine
|
|
4746
5065
|
* membership changes use `{ force: true }` (join requests / history loads). */
|
|
4747
5066
|
private static readonly DIR_COOLDOWN_MS;
|
|
5067
|
+
private readonly keyListeners;
|
|
4748
5068
|
constructor(deps: SpaceKeyringDeps);
|
|
5069
|
+
/** Notified whenever this keyring gains a key (bootstrap, cache hit, pull). Returns an unsubscribe. */
|
|
5070
|
+
onKeysChanged(h: () => void): () => void;
|
|
5071
|
+
private notifyKeys;
|
|
4749
5072
|
/** The cached ECDSA verify key for a member, if known. */
|
|
4750
5073
|
ecdsaKeyFor(memberId: string): CryptoKey | undefined;
|
|
4751
5074
|
/**
|
|
@@ -4763,6 +5086,10 @@ declare class SpaceKeyring implements EpochKeyProvider {
|
|
|
4763
5086
|
currentEpoch(): number;
|
|
4764
5087
|
keyForEpoch(epoch: number): Uint8Array | undefined;
|
|
4765
5088
|
hasAnyKey(): boolean;
|
|
5089
|
+
/** The raw 32-byte group key for `epoch`, for its key commitment (design §4.2.4). */
|
|
5090
|
+
rawKey(epoch: number): Uint8Array | undefined;
|
|
5091
|
+
/** Whether a key may be wrapped to `memberId` (design §4.5.1: on a signed Space, log members and the keeper only). */
|
|
5092
|
+
canWrapTo(memberId: string): boolean;
|
|
4766
5093
|
/** Hydrate keys from the PersonalSpace cache, if available. Best-effort —
|
|
4767
5094
|
* a cache miss/failure (e.g. not unlocked) must not block joining. */
|
|
4768
5095
|
loadFromCache(): Promise<boolean>;
|
|
@@ -4772,7 +5099,8 @@ declare class SpaceKeyring implements EpochKeyProvider {
|
|
|
4772
5099
|
/**
|
|
4773
5100
|
* Post a join request so an online key-holder can wrap a key for us. Also
|
|
4774
5101
|
* publishes our identity keys in the member directory (so others can verify
|
|
4775
|
-
* our message signatures, and the keeper can wrap to us).
|
|
5102
|
+
* our message signatures, and the keeper can wrap to us). With a `keyCert`
|
|
5103
|
+
* dep it also carries the IK certificate over exactly those two strings.
|
|
4776
5104
|
*/
|
|
4777
5105
|
requestKey(desiredEpoch?: number): Promise<void>;
|
|
4778
5106
|
/**
|
|
@@ -4810,6 +5138,124 @@ declare class SpaceKeyring implements EpochKeyProvider {
|
|
|
4810
5138
|
invite(username: string): Promise<void>;
|
|
4811
5139
|
}
|
|
4812
5140
|
|
|
5141
|
+
type Role = "owner" | "editor" | "viewer";
|
|
5142
|
+
interface LogMember {
|
|
5143
|
+
id: string;
|
|
5144
|
+
ik: string;
|
|
5145
|
+
role: Role;
|
|
5146
|
+
since: number;
|
|
5147
|
+
}
|
|
5148
|
+
|
|
5149
|
+
/** What LogSync needs from core (kept structural so spaces/ never imports core/). */
|
|
5150
|
+
interface LogSyncDeps {
|
|
5151
|
+
spaceId: string;
|
|
5152
|
+
me: () => string;
|
|
5153
|
+
appId: () => Promise<string>;
|
|
5154
|
+
commitment: () => string | null;
|
|
5155
|
+
transport: {
|
|
5156
|
+
fetchLog(since?: number, limit?: number): Promise<{
|
|
5157
|
+
entries: MembershipEntry[];
|
|
5158
|
+
head: MlogHead | null;
|
|
5159
|
+
}>;
|
|
5160
|
+
postLogEntry(entry: MembershipEntry, ec?: EpochCommit): Promise<{
|
|
5161
|
+
head: MlogHead;
|
|
5162
|
+
}>;
|
|
5163
|
+
};
|
|
5164
|
+
signer: {
|
|
5165
|
+
sign(b: Uint8Array): Promise<string>;
|
|
5166
|
+
identityKeyRaw(): Promise<string>;
|
|
5167
|
+
};
|
|
5168
|
+
directory: {
|
|
5169
|
+
lookup(username: string): Promise<string>;
|
|
5170
|
+
};
|
|
5171
|
+
pins: {
|
|
5172
|
+
get(doc: "identity" | "spaces", key: string): Promise<string | undefined>;
|
|
5173
|
+
pin(doc: "identity" | "spaces", entries: Record<string, string>): Promise<{
|
|
5174
|
+
conflicts: string[];
|
|
5175
|
+
}>;
|
|
5176
|
+
};
|
|
5177
|
+
store: () => Promise<{
|
|
5178
|
+
get<T>(k: string): Promise<T | undefined>;
|
|
5179
|
+
put(k: string, v: unknown): Promise<void>;
|
|
5180
|
+
}>;
|
|
5181
|
+
}
|
|
5182
|
+
interface MemberView {
|
|
5183
|
+
id: string;
|
|
5184
|
+
role: Role;
|
|
5185
|
+
ik: string;
|
|
5186
|
+
fingerprint: string;
|
|
5187
|
+
identityChanged: boolean;
|
|
5188
|
+
}
|
|
5189
|
+
type IntegrityState = {
|
|
5190
|
+
broken: false;
|
|
5191
|
+
} | {
|
|
5192
|
+
broken: true;
|
|
5193
|
+
reason: string;
|
|
5194
|
+
};
|
|
5195
|
+
/**
|
|
5196
|
+
* One Space's membership log, as this client has verified it (design §3.6–§3.7).
|
|
5197
|
+
* Syncs the whole log from −1 on each call (slice logs are tiny, so no entry
|
|
5198
|
+
* cache), checks the head against the high-water mark kept in `muhkoo.trust`,
|
|
5199
|
+
* checks the genesis against the pins (TOFU against the directory the first
|
|
5200
|
+
* time), and pins every IK a verified `add` names (design §3.4).
|
|
5201
|
+
*/
|
|
5202
|
+
declare class LogSync {
|
|
5203
|
+
private readonly deps;
|
|
5204
|
+
private log;
|
|
5205
|
+
private enabled;
|
|
5206
|
+
private integrityState;
|
|
5207
|
+
private changed;
|
|
5208
|
+
private fps;
|
|
5209
|
+
private listeners;
|
|
5210
|
+
private timer;
|
|
5211
|
+
private running;
|
|
5212
|
+
private followUp;
|
|
5213
|
+
constructor(deps: LogSyncDeps);
|
|
5214
|
+
get logEnabled(): boolean;
|
|
5215
|
+
get integrity(): IntegrityState;
|
|
5216
|
+
get signer(): LogSyncDeps["signer"];
|
|
5217
|
+
get directory(): LogSyncDeps["directory"];
|
|
5218
|
+
member(id: string): LogMember | undefined;
|
|
5219
|
+
isMember(id: string): boolean;
|
|
5220
|
+
members(): MemberView[];
|
|
5221
|
+
onChange(h: () => void): () => void;
|
|
5222
|
+
/**
|
|
5223
|
+
* An `mlog` frame marks the log stale; sync once a burst of frames settles.
|
|
5224
|
+
* A failure is logged with its code and reported through `onChange`, never
|
|
5225
|
+
* thrown; integrity is left as it was, and the next frame or open retries.
|
|
5226
|
+
*/
|
|
5227
|
+
scheduleSync(): void;
|
|
5228
|
+
private hwKey;
|
|
5229
|
+
/** Whether this client holds a high-water mark for this Space, i.e. has verified its log before (design §3.7 item 3). */
|
|
5230
|
+
hasHighWater(): Promise<boolean>;
|
|
5231
|
+
/**
|
|
5232
|
+
* Fetch and verify the whole log. Single-flight: a call made while a sync
|
|
5233
|
+
* runs does not start a second one alongside it. It waits for exactly one
|
|
5234
|
+
* follow-up run, which starts once the running one ends, so it sees whatever
|
|
5235
|
+
* prompted the call; every call made in the meantime shares that follow-up.
|
|
5236
|
+
*/
|
|
5237
|
+
sync(): Promise<void>;
|
|
5238
|
+
private startSync;
|
|
5239
|
+
private runSync;
|
|
5240
|
+
/** Genesis trust (design §3.7 item 2): the pinned genesis hash, else TOFU with the owner's IK checked against the directory. */
|
|
5241
|
+
private checkGenesis;
|
|
5242
|
+
/** "s:" + b64url(SHA-256(utf8(spaceId))), the spaces-v1 key; computed exactly as PinStore.spacePinKey, which this layer may not import. */
|
|
5243
|
+
private spacePinKey;
|
|
5244
|
+
/** Pin every IK a verified add names (design §3.4 row 2); a different pinned IK flags the member (identity-changed). */
|
|
5245
|
+
private pinMembers;
|
|
5246
|
+
/**
|
|
5247
|
+
* Sign and append one entry. On `409 Log moved`: re-sync, re-sign against the
|
|
5248
|
+
* new head and retry, at most 3 times with jitter (design §9.2 I9). Nothing is
|
|
5249
|
+
* signed while integrity is broken, including after a re-sync that breaks it.
|
|
5250
|
+
* Any other refusal → SpaceTrustError("log-refused") carrying the server's code and reason.
|
|
5251
|
+
* Once the server has stored the entry, its `{seq}` is returned even if the sync confirming it fails.
|
|
5252
|
+
*/
|
|
5253
|
+
append(op: MembershipEntry["op"], body: Record<string, unknown>, ec?: (hash: string, entry: UnsignedEntry) => Promise<EpochCommit>): Promise<{
|
|
5254
|
+
seq: number;
|
|
5255
|
+
}>;
|
|
5256
|
+
private emit;
|
|
5257
|
+
}
|
|
5258
|
+
|
|
4813
5259
|
/**
|
|
4814
5260
|
* `Space` — a client handle for one shared space.
|
|
4815
5261
|
*
|
|
@@ -4927,6 +5373,11 @@ interface EphemeralEvent {
|
|
|
4927
5373
|
interface MessageDeletedEvent {
|
|
4928
5374
|
handle: number;
|
|
4929
5375
|
}
|
|
5376
|
+
type AdmissionState = "locked" | "requesting" | "keyed" | "not-member" | "identity-mismatch" | "integrity";
|
|
5377
|
+
/** WebSocket close code for a refused private-Space socket (design §3.6; accelerator NOT_MEMBER_CLOSE_CODE). */
|
|
5378
|
+
declare const NOT_MEMBER_CLOSE_CODE = 4403;
|
|
5379
|
+
/** At most one resume after a 4403 per Space per this interval (design §6.7). */
|
|
5380
|
+
declare const NOT_MEMBER_RECHECK_MS = 60000;
|
|
4930
5381
|
interface SpaceDeps {
|
|
4931
5382
|
/** Transport room id. For fan-out spaces this is the encoded space pubkey. */
|
|
4932
5383
|
name: string;
|
|
@@ -4961,6 +5412,21 @@ interface SpaceDeps {
|
|
|
4961
5412
|
deferShardUpload?: (hash: string) => Promise<void>;
|
|
4962
5413
|
/** Offline message cache + send queue. Undefined ⇒ no offline behavior. */
|
|
4963
5414
|
offline?: SpaceOfflineAdapter;
|
|
5415
|
+
/** Locked session (design §3.3): no keyring, never connects; the app re-opens after sign-in. */
|
|
5416
|
+
locked?: boolean;
|
|
5417
|
+
/** The Space's membership log (a signed private Space), when this client has trust wired. */
|
|
5418
|
+
logSync?: LogSync;
|
|
5419
|
+
/** Visibility the Space was created with; only a private Space gets a genesis (design §3.8). */
|
|
5420
|
+
visibility?: "private" | "public";
|
|
5421
|
+
/** This app's id, which a genesis names (design §3.5). */
|
|
5422
|
+
appId?: () => Promise<string>;
|
|
5423
|
+
/**
|
|
5424
|
+
* Status of GET /keyring/state after the client's silent 401 recovery, or "network": asked after a
|
|
5425
|
+
* 4403 close before believing it (design §6.9).
|
|
5426
|
+
*/
|
|
5427
|
+
probeState?: () => Promise<number | "network">;
|
|
5428
|
+
/** True while the session holds a token, so a reconnect must never go ticketless. */
|
|
5429
|
+
hasSession?: () => boolean;
|
|
4964
5430
|
}
|
|
4965
5431
|
/** The subset of {@link BroadcastChannel} a {@link Space} drives. */
|
|
4966
5432
|
interface SpaceChannelLike {
|
|
@@ -4973,13 +5439,22 @@ interface SpaceChannelLike {
|
|
|
4973
5439
|
sendRaw(frame: unknown): void;
|
|
4974
5440
|
peers?(): string[];
|
|
4975
5441
|
isConnected?(): boolean;
|
|
5442
|
+
/** Reconnect after a terminal close, on a fresh URL. */
|
|
5443
|
+
resume?(): void;
|
|
4976
5444
|
}
|
|
4977
5445
|
declare class Space {
|
|
4978
5446
|
private readonly deps;
|
|
4979
5447
|
readonly name: string;
|
|
4980
5448
|
readonly historyPolicy: HistoryPolicy;
|
|
4981
5449
|
private channel;
|
|
4982
|
-
|
|
5450
|
+
/**
|
|
5451
|
+
* The log turned this user away and closed `channel` (design §3.7). Its
|
|
5452
|
+
* single-use ticket is spent, so it is never dialled again: the next
|
|
5453
|
+
* `connect()` checks the log and opens a new channel on a fresh ticket.
|
|
5454
|
+
*/
|
|
5455
|
+
private channelSpent;
|
|
5456
|
+
/** Every raw channel listener (`on`), attached to each channel this Space opens. */
|
|
5457
|
+
private readonly listeners;
|
|
4983
5458
|
private readonly cipher;
|
|
4984
5459
|
/** Per-instance event bus for fan-out events (isolated across spaces). */
|
|
4985
5460
|
private readonly events;
|
|
@@ -4987,12 +5462,52 @@ declare class Space {
|
|
|
4987
5462
|
private catchUpUnsub;
|
|
4988
5463
|
/** Optional P2P swarm for this Space (block exchange among members). */
|
|
4989
5464
|
private peerNet;
|
|
5465
|
+
private _admission;
|
|
5466
|
+
/** Whether admission follows the log's changes yet (subscribed once, on the first open the log admits). */
|
|
5467
|
+
private admissionWired;
|
|
5468
|
+
/** When the last resume after a 4403 ran (design §6.7: at most one per {@link NOT_MEMBER_RECHECK_MS}). */
|
|
5469
|
+
private lastResumeAt;
|
|
5470
|
+
private resumeTimer;
|
|
5471
|
+
/** Bumped by `disconnect()`: a /keyring/state answer that arrives after it is dropped. */
|
|
5472
|
+
private teardowns;
|
|
4990
5473
|
constructor(deps: SpaceDeps);
|
|
4991
5474
|
/** The encoded space id (same as the transport name for fan-out spaces). */
|
|
4992
5475
|
get id(): string;
|
|
4993
5476
|
/** The keyring backing this space's group keys, if any. */
|
|
4994
5477
|
get keyring(): SpaceKeyring | undefined;
|
|
4995
|
-
/**
|
|
5478
|
+
/** Where this member stands in this Space (design §4.5.12, as the slice ships it). */
|
|
5479
|
+
get admission(): AdmissionState;
|
|
5480
|
+
/** Subscribe to admission changes. Returns an unsubscribe. */
|
|
5481
|
+
onAdmission(h: (s: AdmissionState) => void): () => void;
|
|
5482
|
+
protected setAdmission(s: AdmissionState): void;
|
|
5483
|
+
/** The log turned this user away; nothing reconnects until it admits them again. */
|
|
5484
|
+
private denied;
|
|
5485
|
+
/**
|
|
5486
|
+
* Sync the membership log and derive admission from it, before any ticket
|
|
5487
|
+
* (design §3.4, §3.7, §4.5.12). A 403 from the log route is not-member and a
|
|
5488
|
+
* 401 is locked. Any other failure is fatal only where this client has
|
|
5489
|
+
* verified the log before (it holds a high-water mark). Otherwise the Space
|
|
5490
|
+
* opens as unlogged this time, and the next open or `mlog` frame syncs again.
|
|
5491
|
+
*/
|
|
5492
|
+
private admitByLog;
|
|
5493
|
+
/** Re-derive admission from the verified log (design §3.4 rows, §3.7, §4.5.12). */
|
|
5494
|
+
private evaluateAdmission;
|
|
5495
|
+
/**
|
|
5496
|
+
* A 4403 alone never shows not-member: ask /keyring/state first (design §6.9, AV12).
|
|
5497
|
+
* 403 is not-member and 401, which `probeState` returns only once a silent re-auth has failed, is
|
|
5498
|
+
* locked; either closes the channel for good, like a log refusal. Any
|
|
5499
|
+
* other answer (404 while step I has no state route, 2xx, 5xx, a network error) resumes, at most
|
|
5500
|
+
* once per {@link NOT_MEMBER_RECHECK_MS}.
|
|
5501
|
+
*/
|
|
5502
|
+
private onNotMemberClose;
|
|
5503
|
+
/** Close the socket of a user the log turned away, and never dial that channel again (design §3.7). */
|
|
5504
|
+
private dropChannel;
|
|
5505
|
+
/**
|
|
5506
|
+
* Open the space websocket (resolves the ticket + identity lazily). On a
|
|
5507
|
+
* Space with a membership log, the log is checked first: a user it does not
|
|
5508
|
+
* list, or lists under another identity key, is refused with
|
|
5509
|
+
* {@link AdmissionDeniedError} before any ticket is fetched (design §4.5.12).
|
|
5510
|
+
*/
|
|
4996
5511
|
connect(): Promise<void>;
|
|
4997
5512
|
disconnect(): void;
|
|
4998
5513
|
/** Attach a P2P swarm so this Space's file reads/writes can use peers. */
|
|
@@ -5008,7 +5523,7 @@ declare class Space {
|
|
|
5008
5523
|
gossipToPeers(data: Uint8Array): void;
|
|
5009
5524
|
/** Subscribe to peer gossip ({@link gossipToPeers}). Returns an unsubscribe fn. */
|
|
5010
5525
|
onPeerGossip(handler: (from: string, data: Uint8Array) => void): () => void;
|
|
5011
|
-
/** Subscribe to a raw channel event. Buffered until `connect()` if early. */
|
|
5526
|
+
/** Subscribe to a raw channel event. Buffered until `connect()` if early, and kept across a new channel. */
|
|
5012
5527
|
on(event: string, handler: Listener): void;
|
|
5013
5528
|
off(event: string, handler: Listener): void;
|
|
5014
5529
|
/** Advertise our keyExchange to the room (idempotent per connection). */
|
|
@@ -5092,7 +5607,7 @@ declare class Space {
|
|
|
5092
5607
|
timeoutMs?: number;
|
|
5093
5608
|
pollMs?: number;
|
|
5094
5609
|
}): Promise<boolean>;
|
|
5095
|
-
/** Creator path: mint
|
|
5610
|
+
/** Creator path: mint epoch 0; for a private Space, sign the genesis + ec(0) BEFORE connecting (design §4.5.10). */
|
|
5096
5611
|
create(): Promise<void>;
|
|
5097
5612
|
/** Wrap the group key for a newcomer and post it (key-holder action). */
|
|
5098
5613
|
admit(memberId: string, identityEcdhPub: string): Promise<void>;
|
|
@@ -5103,6 +5618,29 @@ declare class Space {
|
|
|
5103
5618
|
memberId: string;
|
|
5104
5619
|
identityEcdhPub: string;
|
|
5105
5620
|
}>): Promise<number>;
|
|
5621
|
+
/** Whether this Space has a verified membership log. */
|
|
5622
|
+
get logEnabled(): boolean;
|
|
5623
|
+
/** The verified member list, or null when this Space has no log. */
|
|
5624
|
+
membership(): MemberView[] | null;
|
|
5625
|
+
/** Called with the member list (null when unlogged) each time the log is re-synced. Returns an unsubscribe. */
|
|
5626
|
+
onMembership(h: (m: MemberView[] | null) => void): () => void;
|
|
5627
|
+
private requireLog;
|
|
5628
|
+
/** Add by exact username (design §3.8; the owner, or an editor for viewers). Looks the IK up in the directory. */
|
|
5629
|
+
add(username: string, opts?: {
|
|
5630
|
+
role?: "viewer" | "editor";
|
|
5631
|
+
}): Promise<{
|
|
5632
|
+
seq: number;
|
|
5633
|
+
}>;
|
|
5634
|
+
/** Remove a member. In this build it cuts them off at the relay; it does not rotate the key. */
|
|
5635
|
+
remove(memberId: string): Promise<{
|
|
5636
|
+
seq: number;
|
|
5637
|
+
}>;
|
|
5638
|
+
setRole(memberId: string, role: "viewer" | "editor"): Promise<{
|
|
5639
|
+
seq: number;
|
|
5640
|
+
}>;
|
|
5641
|
+
leave(): Promise<{
|
|
5642
|
+
seq: number;
|
|
5643
|
+
}>;
|
|
5106
5644
|
putFile(file: File | Blob | Uint8Array, metadata: SpaceFileMetadata, opts?: {
|
|
5107
5645
|
onProgress?: (completed: number, total: number) => void;
|
|
5108
5646
|
/**
|
|
@@ -5295,19 +5833,27 @@ declare class ChatKeyVault {
|
|
|
5295
5833
|
private readonly store;
|
|
5296
5834
|
constructor(store: ChatKeyStore);
|
|
5297
5835
|
/**
|
|
5298
|
-
* Register-time: ensure a keypair exists for `memberId`,
|
|
5299
|
-
*
|
|
5300
|
-
*
|
|
5836
|
+
* Register-time: ensure a vault-backed keypair exists for `memberId`,
|
|
5837
|
+
* seed-wrap it and persist it. Idempotent for a pair that is already
|
|
5838
|
+
* vault-backed. Otherwise a fresh pair is generated, persisted, and only
|
|
5839
|
+
* then swapped in, replacing whatever the tab held: a throwaway key is never
|
|
5840
|
+
* persisted as the stable one, and a failed persist leaves the tab's keys
|
|
5841
|
+
* as they were, with nothing marked.
|
|
5301
5842
|
*/
|
|
5302
5843
|
provision(memberId: string, seedSecret: string): Promise<void>;
|
|
5303
5844
|
/**
|
|
5304
|
-
* Sign-in / unlock time: fetch the wrapped blob, unwrap with the seed, and
|
|
5305
|
-
* hydrate the `KeyStore
|
|
5306
|
-
* Returns `true` when a keypair is now in hand
|
|
5307
|
-
*
|
|
5308
|
-
*
|
|
5845
|
+
* Sign-in / unlock time: fetch the wrapped blob, unwrap it with the seed, and
|
|
5846
|
+
* hydrate the `KeyStore`, restoring the SAME keypair the member had before.
|
|
5847
|
+
* Returns `true` when a vault-backed keypair is now in hand, and `false` when
|
|
5848
|
+
* there is no blob yet (a brand-new member; the caller provisions). A store
|
|
5849
|
+
* failure propagates as thrown; a blob that does not unwrap, parse or import
|
|
5850
|
+
* throws `ChatKeysUnreadableError`. Nothing in the `KeyStore` changes until
|
|
5851
|
+
* the saved pair is imported; it then replaces whatever pair the tab held,
|
|
5852
|
+
* in one step, so a pair minted meanwhile is never kept in its place.
|
|
5309
5853
|
*/
|
|
5310
5854
|
rehydrate(memberId: string, seedSecret: string): Promise<boolean>;
|
|
5855
|
+
/** Unwrap, parse and import a saved pair, outside the `KeyStore`. */
|
|
5856
|
+
private unwrapPair;
|
|
5311
5857
|
/**
|
|
5312
5858
|
* Ensure a stable keypair is in hand: rehydrate from the vault if a blob
|
|
5313
5859
|
* exists, otherwise mint one and persist it (so it's stable next session).
|
|
@@ -5316,6 +5862,101 @@ declare class ChatKeyVault {
|
|
|
5316
5862
|
ensure(memberId: string, seedSecret: string): Promise<void>;
|
|
5317
5863
|
}
|
|
5318
5864
|
|
|
5865
|
+
/**
|
|
5866
|
+
* POST /api/auth/identity (SpecA §4.1 as amended by CS-7). An unknown name
|
|
5867
|
+
* answers a deterministic decoy, so a lookup never says whether an account
|
|
5868
|
+
* exists. Responses are cached for the life of the Client. Any failure,
|
|
5869
|
+
* including a 429, fails closed (SpecA §4.3).
|
|
5870
|
+
*/
|
|
5871
|
+
declare class IdentityDirectory {
|
|
5872
|
+
private readonly http;
|
|
5873
|
+
private readonly cache;
|
|
5874
|
+
constructor(http: Pick<HttpClient, "post">);
|
|
5875
|
+
lookup(username: string): Promise<string>;
|
|
5876
|
+
lookupMany(usernames: string[]): Promise<Record<string, string>>;
|
|
5877
|
+
}
|
|
5878
|
+
|
|
5879
|
+
/** Signs with the account identity key (IK). Never exposes the seed (SpecA §6.1). */
|
|
5880
|
+
interface IdentitySigner {
|
|
5881
|
+
/** b64 IEEE-P1363 ECDSA-P256-SHA256 over `bytes`. */
|
|
5882
|
+
sign(bytes: Uint8Array): Promise<string>;
|
|
5883
|
+
/** The IK as standard padded base64 of the raw 65-byte point. */
|
|
5884
|
+
identityKeyRaw(): Promise<string>;
|
|
5885
|
+
}
|
|
5886
|
+
|
|
5887
|
+
/**
|
|
5888
|
+
* IndexedDB `muhkoo.trust` (design §6.6): pin high-water marks and per-Space log
|
|
5889
|
+
* heads. When IndexedDB is absent, throws on open, or has not opened within 2 s,
|
|
5890
|
+
* it is an in-memory store for the life of the Client, and `persistent` is
|
|
5891
|
+
* false (KI1).
|
|
5892
|
+
*/
|
|
5893
|
+
interface TrustStore {
|
|
5894
|
+
readonly persistent: boolean;
|
|
5895
|
+
get<T>(key: string): Promise<T | undefined>;
|
|
5896
|
+
put(key: string, value: unknown): Promise<void>;
|
|
5897
|
+
del(key: string): Promise<void>;
|
|
5898
|
+
}
|
|
5899
|
+
|
|
5900
|
+
type PinDocName = "identity" | "spaces";
|
|
5901
|
+
interface PinDoc {
|
|
5902
|
+
v: 1;
|
|
5903
|
+
ownerCommitment: string;
|
|
5904
|
+
counter: number;
|
|
5905
|
+
entries: Record<string, string>;
|
|
5906
|
+
sig: string;
|
|
5907
|
+
}
|
|
5908
|
+
interface PinStoreDeps {
|
|
5909
|
+
http: Pick<HttpClient, "post">;
|
|
5910
|
+
commitment: () => string | null;
|
|
5911
|
+
signer: IdentitySigner;
|
|
5912
|
+
store: () => Promise<TrustStore>;
|
|
5913
|
+
}
|
|
5914
|
+
declare class PinStore {
|
|
5915
|
+
private readonly deps;
|
|
5916
|
+
constructor(deps: PinStoreDeps);
|
|
5917
|
+
private commitment;
|
|
5918
|
+
private markKey;
|
|
5919
|
+
private kvPath;
|
|
5920
|
+
private fetchDoc;
|
|
5921
|
+
private verify;
|
|
5922
|
+
/** The current verified document; an empty bootstrap at counter 0 when none exists and no mark does either. */
|
|
5923
|
+
read(doc: PinDocName): Promise<PinDoc>;
|
|
5924
|
+
get(doc: PinDocName, key: string): Promise<string | undefined>;
|
|
5925
|
+
/** Pin new keys. A key already pinned to a different value is reported, never overwritten (design §3.4). */
|
|
5926
|
+
pin(doc: PinDocName, entries: Record<string, string>): Promise<{
|
|
5927
|
+
conflicts: string[];
|
|
5928
|
+
}>;
|
|
5929
|
+
unpin(doc: PinDocName, keys: string[]): Promise<void>;
|
|
5930
|
+
/** User-confirmed recovery (design §9.1 "Your saved trust records are missing."): forget the high-water mark. */
|
|
5931
|
+
resetMark(doc: PinDocName): Promise<void>;
|
|
5932
|
+
private mutate;
|
|
5933
|
+
}
|
|
5934
|
+
|
|
5935
|
+
/** One per Client: shared by every Space (and, in sub-project 4, DMs). */
|
|
5936
|
+
declare class TrustContext {
|
|
5937
|
+
private readonly deps;
|
|
5938
|
+
readonly directory: IdentityDirectory;
|
|
5939
|
+
readonly signer: IdentitySigner;
|
|
5940
|
+
readonly pins: PinStore;
|
|
5941
|
+
private storeP;
|
|
5942
|
+
private opened;
|
|
5943
|
+
private appIdP;
|
|
5944
|
+
constructor(deps: {
|
|
5945
|
+
http: HttpClient;
|
|
5946
|
+
session: SessionState;
|
|
5947
|
+
openStore?: () => Promise<TrustStore>;
|
|
5948
|
+
});
|
|
5949
|
+
/** Whether muhkoo.trust survives a restart (KI1): false until the open settles, and false for an in-memory store. */
|
|
5950
|
+
get persistent(): boolean;
|
|
5951
|
+
store(): Promise<TrustStore>;
|
|
5952
|
+
/** This app's id, from GET /api/app/trust (a genesis must name it, D4). Cached; a failure is retried next call. */
|
|
5953
|
+
appId(): Promise<string>;
|
|
5954
|
+
/** User-confirmed "Reset trust for this space" (design §9.1): drop its genesis pin and log high-water. */
|
|
5955
|
+
resetSpacePins(spaceId: string): Promise<void>;
|
|
5956
|
+
/** `client.trust.unpin(username)`: forget a member's pinned identity after comparing safety numbers (design §3.4). */
|
|
5957
|
+
unpinUser(username: string): Promise<void>;
|
|
5958
|
+
}
|
|
5959
|
+
|
|
5319
5960
|
/**
|
|
5320
5961
|
* `client.space` — the fan-out group-encryption surface.
|
|
5321
5962
|
*
|
|
@@ -5354,6 +5995,9 @@ interface SpaceNamespaceDeps {
|
|
|
5354
5995
|
/** SDK-owned ratchet-keypair vault — gives a STABLE member keypair across
|
|
5355
5996
|
* reloads (rehydrate-or-provision) instead of a fresh one each session. */
|
|
5356
5997
|
chatKeys?: ChatKeyVault;
|
|
5998
|
+
/** The Client's trust context. Present, every join request carries the IK
|
|
5999
|
+
* certificate over this member's chat keys (design §3.2). */
|
|
6000
|
+
trust?: TrustContext;
|
|
5357
6001
|
/** P2P swarm config — enables peer block exchange among Space members. */
|
|
5358
6002
|
p2p?: {
|
|
5359
6003
|
enabled?: boolean;
|
|
@@ -5369,6 +6013,10 @@ declare class SpaceNamespace {
|
|
|
5369
6013
|
private spaceCache?;
|
|
5370
6014
|
/** Spaces built this session, by id — used to route offline send replays. */
|
|
5371
6015
|
private readonly openSpaces;
|
|
6016
|
+
/** In-flight identity loads, by member id; each entry is deleted once it settles. */
|
|
6017
|
+
private readonly identityInFlight;
|
|
6018
|
+
/** Chat-key certificates, by member and the exact key strings; a failed mint is dropped so the next join retries. */
|
|
6019
|
+
private readonly certs;
|
|
5372
6020
|
/** Unique id for THIS device/session — the P2P peer identity. A user's own
|
|
5373
6021
|
* devices share a member id, so the mesh MUST distinguish them by this or a
|
|
5374
6022
|
* device treats its siblings' signals as its own echo and never connects. */
|
|
@@ -5397,8 +6045,14 @@ declare class SpaceNamespace {
|
|
|
5397
6045
|
joinSpace(spaceId: string, opts?: {
|
|
5398
6046
|
timeoutMs?: number;
|
|
5399
6047
|
}): Promise<Space>;
|
|
5400
|
-
/**
|
|
5401
|
-
|
|
6048
|
+
/**
|
|
6049
|
+
* A handle to a space without auto-connecting (uses cached keys on demand).
|
|
6050
|
+
* `messaging: false` opens a files-only space, as {@link createSpace} makes:
|
|
6051
|
+
* no keyring and no identity, so it opens whether or not the session is locked.
|
|
6052
|
+
*/
|
|
6053
|
+
get(spaceId: string, historyPolicy?: HistoryPolicy, opts?: {
|
|
6054
|
+
messaging?: boolean;
|
|
6055
|
+
}): Promise<Space>;
|
|
5402
6056
|
/** List this app's channels (name → space-id) for the key's environment. */
|
|
5403
6057
|
listChannels(): Promise<Array<{
|
|
5404
6058
|
name: string;
|
|
@@ -5457,8 +6111,22 @@ declare class SpaceNamespace {
|
|
|
5457
6111
|
}>>;
|
|
5458
6112
|
private keyringFor;
|
|
5459
6113
|
private build;
|
|
5460
|
-
/**
|
|
6114
|
+
/**
|
|
6115
|
+
* The member's stable chat identity (design §3.3). A locked session (no
|
|
6116
|
+
* seed) throws `IdentityLockedError`. A vault failure throws
|
|
6117
|
+
* `IdentityUnavailableError`: `retryable` when the vault could not be
|
|
6118
|
+
* reached (§9.2 I8), and not when the saved keys do not unwrap under this
|
|
6119
|
+
* seed. A throwaway pair is never minted: doing so is what hid a reloaded
|
|
6120
|
+
* member's earlier messages from everyone else.
|
|
6121
|
+
*
|
|
6122
|
+
* Concurrent calls for one member share a single load, so two first opens
|
|
6123
|
+
* can never interleave their forget/generate steps and persist a second or
|
|
6124
|
+
* mixed pair.
|
|
6125
|
+
*/
|
|
5461
6126
|
private ensureIdentity;
|
|
6127
|
+
private loadIdentity;
|
|
6128
|
+
/** One certificate per (member, chat keys) for the life of the Client (design §3.2: global, not per Space). */
|
|
6129
|
+
private certFor;
|
|
5462
6130
|
private fetchPolicy;
|
|
5463
6131
|
private fetchTicket;
|
|
5464
6132
|
private myId;
|
|
@@ -6089,6 +6757,8 @@ interface VfsContentStore {
|
|
|
6089
6757
|
write(data: Uint8Array | Blob, meta: {
|
|
6090
6758
|
name: string;
|
|
6091
6759
|
type: string;
|
|
6760
|
+
}, opts?: {
|
|
6761
|
+
onProgress?: (done: number, total: number) => void;
|
|
6092
6762
|
}): Promise<{
|
|
6093
6763
|
manifest: FileManifest;
|
|
6094
6764
|
size: number;
|
|
@@ -6149,6 +6819,18 @@ declare class VfsNamespace {
|
|
|
6149
6819
|
* than by TTL — a stale directory listing shows files that are not there.
|
|
6150
6820
|
*/
|
|
6151
6821
|
private cache;
|
|
6822
|
+
/**
|
|
6823
|
+
* The write of each directory record still in flight, by id.
|
|
6824
|
+
*
|
|
6825
|
+
* Two writes of one record must land in the order they were made. The
|
|
6826
|
+
* personal space has no compare-and-swap: of two writes of one key that
|
|
6827
|
+
* are in flight together it keeps whichever request finishes last, and
|
|
6828
|
+
* that is often the one sent first. Then the earlier write, sealed before
|
|
6829
|
+
* the later edit was made, undoes it. That is how a file deleted forever
|
|
6830
|
+
* from the Trash, while the move that put it there was still being
|
|
6831
|
+
* written, came back. So each write waits for the one before it.
|
|
6832
|
+
*/
|
|
6833
|
+
private readonly writing;
|
|
6152
6834
|
private readonly historyLimit;
|
|
6153
6835
|
private readonly maxEntries;
|
|
6154
6836
|
private readonly maxPathChars;
|
|
@@ -6307,6 +6989,7 @@ declare class VfsNamespace {
|
|
|
6307
6989
|
*/
|
|
6308
6990
|
writeFile(path: string, data: Uint8Array | string | Blob, opts?: {
|
|
6309
6991
|
type?: string;
|
|
6992
|
+
onProgress?: (done: number, total: number) => void;
|
|
6310
6993
|
}): Promise<VfsStat>;
|
|
6311
6994
|
/**
|
|
6312
6995
|
* Delete a file, or a directory when `recursive`.
|
|
@@ -6420,6 +7103,14 @@ declare class VfsNamespace {
|
|
|
6420
7103
|
private readRecord;
|
|
6421
7104
|
/** Apply an edit to a directory record and persist it. */
|
|
6422
7105
|
private mutate;
|
|
7106
|
+
/**
|
|
7107
|
+
* Seal a directory record as it stands NOW and put it in the store.
|
|
7108
|
+
*
|
|
7109
|
+
* Read at the moment of sending, not when the edit was made, so a write
|
|
7110
|
+
* that waited behind another carries every edit made to the record by
|
|
7111
|
+
* then, its own included.
|
|
7112
|
+
*/
|
|
7113
|
+
private writeRecord;
|
|
6423
7114
|
private createDir;
|
|
6424
7115
|
/**
|
|
6425
7116
|
* Every directory record in a subtree, each once, opened - and nothing
|
|
@@ -7009,6 +7700,12 @@ declare class Client {
|
|
|
7009
7700
|
readonly message: MessageNamespace;
|
|
7010
7701
|
/** Fan-out group spaces — `client.space.createSpace(...)`, etc. */
|
|
7011
7702
|
readonly space: SpaceNamespace;
|
|
7703
|
+
/** Trust records shared by every Space: pins and per-Space log heads (design §3.4, §6.9). */
|
|
7704
|
+
readonly trust: {
|
|
7705
|
+
readonly persistent: boolean;
|
|
7706
|
+
unpin(username: string): Promise<void>;
|
|
7707
|
+
resetSpacePins(spaceId: string): Promise<void>;
|
|
7708
|
+
};
|
|
7012
7709
|
/** Programmable Agents — `client.agents.create(appId, …)`, etc. */
|
|
7013
7710
|
readonly agents: AgentsNamespace;
|
|
7014
7711
|
/** Serverless functions — `client.functions.deploy(appId, …)`, etc. */
|
|
@@ -7945,14 +8642,29 @@ declare namespace protocol {
|
|
|
7945
8642
|
* GET /api/spaces/:id/keyring/pending -> JoinRequest[]
|
|
7946
8643
|
* GET /api/spaces/:id/keyring/roster -> { memberId, identityEcdhPub }[]
|
|
7947
8644
|
* POST /api/spaces/:id/keyring/rotate { nextEpoch } -> { epoch }
|
|
8645
|
+
* GET /api/spaces/:id/keyring/log ?since&limit -> { entries, head }
|
|
8646
|
+
* POST /api/spaces/:id/keyring/log { entry, ec? } -> { ok, head }
|
|
8647
|
+
* GET /api/spaces/:id/keyring/state (status only)
|
|
7948
8648
|
* GET /api/spaces/:id/metadata -> SpaceMetadata
|
|
7949
8649
|
*/
|
|
7950
8650
|
|
|
8651
|
+
/** A keyring route answered non-2xx; status and JSON body preserved (the existing methods keep their plain Errors). */
|
|
8652
|
+
declare class KeyringHttpError extends Error {
|
|
8653
|
+
readonly status: number;
|
|
8654
|
+
readonly body: Record<string, unknown> | null;
|
|
8655
|
+
constructor(status: number, body: Record<string, unknown> | null, route: string);
|
|
8656
|
+
}
|
|
7951
8657
|
interface KeyringClientDeps {
|
|
7952
8658
|
spaceId: string;
|
|
7953
8659
|
httpBaseUrl: string;
|
|
7954
8660
|
/** Header-injecting fetch from the client's HttpClient. */
|
|
7955
8661
|
fetch: typeof fetch;
|
|
8662
|
+
/**
|
|
8663
|
+
* The same fetch with the HttpClient's silent 401 recovery (`HttpClient.fetchWithRecovery`).
|
|
8664
|
+
* `probeState` and the log routes use it, so a 401 reads as locked only once a re-auth has failed (design §6.9).
|
|
8665
|
+
* Defaults to {@link fetch}.
|
|
8666
|
+
*/
|
|
8667
|
+
fetchWithRecovery?: typeof fetch;
|
|
7956
8668
|
}
|
|
7957
8669
|
declare class KeyringClient implements KeyringTransport {
|
|
7958
8670
|
private readonly deps;
|
|
@@ -7960,6 +8672,27 @@ declare class KeyringClient implements KeyringTransport {
|
|
|
7960
8672
|
private url;
|
|
7961
8673
|
private post;
|
|
7962
8674
|
private get;
|
|
8675
|
+
/**
|
|
8676
|
+
* The log routes. Sent through `fetchWithRecovery` when given, as `probeState` is, so a stale session is
|
|
8677
|
+
* re-established before a 401 reads as locked (design §6.9): a GET replays safely, and a POST body is a string.
|
|
8678
|
+
*/
|
|
8679
|
+
private request;
|
|
8680
|
+
/** GET /keyring/log (design §3.6): entries with seq > since, ascending, ≤ limit; head null = no log. */
|
|
8681
|
+
fetchLog(since?: number, limit?: number): Promise<{
|
|
8682
|
+
entries: MembershipEntry[];
|
|
8683
|
+
head: MlogHead | null;
|
|
8684
|
+
}>;
|
|
8685
|
+
/** POST /keyring/log {entry, ec?} → {ok, head}; `409 {error:"Log moved", head}` (no code) on a compare-and-set miss. */
|
|
8686
|
+
postLogEntry(entry: MembershipEntry, ec?: EpochCommit): Promise<{
|
|
8687
|
+
ok: true;
|
|
8688
|
+
head: MlogHead;
|
|
8689
|
+
}>;
|
|
8690
|
+
/**
|
|
8691
|
+
* Status of GET /keyring/state, or "network" when the request fails: 403 is not-member, 401 is locked,
|
|
8692
|
+
* anything else resumes (design §6.9). Sent through `fetchWithRecovery` when given, so a stale session
|
|
8693
|
+
* is re-established before a 401 is believed.
|
|
8694
|
+
*/
|
|
8695
|
+
probeState(): Promise<number | "network">;
|
|
7963
8696
|
postJoinRequest(req: JoinRequest): Promise<void>;
|
|
7964
8697
|
fetchBlobs(memberId: string): Promise<WrappedKey[]>;
|
|
7965
8698
|
postWrappedKey(targetMemberId: string, wrapped: WrappedKey, fromMemberId: string): Promise<void>;
|
|
@@ -7994,6 +8727,43 @@ declare class KeyringClient implements KeyringTransport {
|
|
|
7994
8727
|
fetchMetadata(): Promise<SpaceMetadata | null>;
|
|
7995
8728
|
}
|
|
7996
8729
|
|
|
8730
|
+
/**
|
|
8731
|
+
* Trust-layer errors shared by Spaces and, later, DMs (design §3.3, §6.9;
|
|
8732
|
+
* SpecA §6.6). Class names are public API and are frozen at their first
|
|
8733
|
+
* release (design Q16).
|
|
8734
|
+
*/
|
|
8735
|
+
/** The session holds no seed, so it has no stable identity and may not take part (design §3.3, T7). */
|
|
8736
|
+
declare class IdentityLockedError extends Error {
|
|
8737
|
+
readonly code: "identity-locked";
|
|
8738
|
+
constructor(message?: string);
|
|
8739
|
+
}
|
|
8740
|
+
/**
|
|
8741
|
+
* The stable chat keys could not be loaded (design §3.3). `retryable` says
|
|
8742
|
+
* whether the same call can succeed later. It is true when the vault could not
|
|
8743
|
+
* be reached or written (a 5xx or a network error on `chat-keys`), which the
|
|
8744
|
+
* next open retries (§9.2 I8). It is false when the saved keys were read but do
|
|
8745
|
+
* not unwrap under this session's seed, because they are damaged or were saved
|
|
8746
|
+
* under another seed, and when the client has no vault: retrying fails the same way.
|
|
8747
|
+
*/
|
|
8748
|
+
declare class IdentityUnavailableError extends Error {
|
|
8749
|
+
readonly reason?: unknown | undefined;
|
|
8750
|
+
readonly retryable: boolean;
|
|
8751
|
+
readonly code: "identity-unavailable";
|
|
8752
|
+
constructor(message?: string, reason?: unknown | undefined, retryable?: boolean);
|
|
8753
|
+
}
|
|
8754
|
+
type SpaceTrustCode = "integrity" | "log-conflict" | "log-refused" | "lookup-failed" | "pins-missing" | "pins-rollback" | "pins-stale" | "pins-invalid" | "pins-write-failed";
|
|
8755
|
+
/** A membership-log or pin failure. `detail` carries server fields (`reason`, `head`, ...). */
|
|
8756
|
+
declare class SpaceTrustError extends Error {
|
|
8757
|
+
readonly code: SpaceTrustCode;
|
|
8758
|
+
readonly detail?: Record<string, unknown> | undefined;
|
|
8759
|
+
constructor(code: SpaceTrustCode, message?: string, detail?: Record<string, unknown> | undefined);
|
|
8760
|
+
}
|
|
8761
|
+
/** This user may not open this Space (design §4.5.12, V25). */
|
|
8762
|
+
declare class AdmissionDeniedError extends Error {
|
|
8763
|
+
readonly code: "not-member" | "identity-mismatch";
|
|
8764
|
+
constructor(code: "not-member" | "identity-mismatch", message?: string);
|
|
8765
|
+
}
|
|
8766
|
+
|
|
7997
8767
|
declare class Logger {
|
|
7998
8768
|
private prefix;
|
|
7999
8769
|
private logLevel;
|
|
@@ -8228,7 +8998,7 @@ declare function getId(row: {
|
|
|
8228
8998
|
* expect (and isn't serving a stale cached bundle). Keep this in sync with
|
|
8229
8999
|
* `package.json` `version`.
|
|
8230
9000
|
*/
|
|
8231
|
-
declare const VERSION = "0.
|
|
9001
|
+
declare const VERSION = "0.15.0-alpha.1";
|
|
8232
9002
|
|
|
8233
9003
|
/**
|
|
8234
9004
|
* The SDK's process-global logger.
|
|
@@ -8260,5 +9030,5 @@ declare global {
|
|
|
8260
9030
|
}
|
|
8261
9031
|
declare const appLogger: InstanceType<typeof Logger>;
|
|
8262
9032
|
|
|
8263
|
-
export { ACCESS_TOKEN_SCOPES, AES_GCM_IV_BYTES, AES_GCM_KEY_BYTES, AES_GCM_TAG_BYTES, AccessTokensNamespace, AgentsNamespace, AuthClient, AuthNamespace, AuthPublicInput, Authenticator, BlockEngine, BroadcastChannel, BroadcastChannelEvents, ChannelExistsError, ChannelNotFoundError, ChunkCipher, CircuitIntegrityError, Client, ConnectivityManager, DEFAULT_AUTH_BASE_URL, DEFAULT_BASE_URL, DEFAULT_BRANCH, DEFAULT_FN_HOST_SUFFIX, DEVICE_IDENTITY_STORAGE_KEY, DEVICE_KEY_DB_NAME, DbCache, DbNamespace, DbTable, DevicePairingError, DeviceRevokedError, DeviceStoreUnavailableError, DoubleRatchet, DoubleRatchetCipher, DoubleRatchetManager, EncryptedSession, EventCore, EventCoreEvents, Field, Field as FieldElement, FileStorage, FunctionsNamespace, HLC, HashKnowledge, HostedAuth, HttpClient, HttpError, IndexedDbStore, KEEPER_MEMBER_ID, KeyStore, KeyringClient, KvCache, KvNamespace, LocalEngineHost, LocalStorageSessionStore, Logger, MemorySessionStore, Message, Message as MessageDefault, MessageNamespace, MuhkooAgent, MuhkooDB, MuhkooFunction, MuhkooSpace, NoopStore, OfflineLockedError, OfflineManager, OutboundQueue, P2P_SUBJECT, PAIRING_CODE_ALPHABET, PAIRING_CODE_LENGTH, PBKDF2_DEFAULT_ITERATIONS, PINNED_CIRCUIT_DIGESTS, PREIMAGE_POK_VERIFICATION_KEY, Packet, PasskeyOriginError, PeerExchange, PeerNetwork, PersonalSpaceClient, Poseidon, PreimagePoK, ROOT_ID, Ready, ReauthRequiredError, ReedSolomonCodec, Repo, Retry, Space as Room, SerializeMessage, SessionState, ShardCache, ShardClient, SharedSpaceClient, SnapshotNamespace, Space, SpaceCache, SpaceKeyring, SpaceNamespace, SpacePacketCipher, SpaceSignaler, StorageNamespace, SyncEngine, VERSION, VFS_ROOT_INFO, VaultUnavailableError, VcsError, VcsNamespace, VfsConflictError, VfsCorruptRecordError, VfsLimitError, VfsLockedError, VfsNamespace, VfsNotFoundError, WSTransport, WebRtcTransport, WorkerEngineHost, ZERO_HLC, ZkAuth, _accountId, _formatBytes, _messageId, _objectId, _packetId, _socketId, _userId, appLogger, assertType, base58Decode, base58Encode, buildCommitment, canonicalUserCode, clearDeviceIdentity, compareHlc, compilePrograms, concatBytes, configureDeviceStore, createPasskeyWithPrf, decodeFromHex, decorators, decryptAesGcm, defaultCircuitUrls, defaultRpId, defaultSessionStore, deleteBeatsWrite, deleteRegister, deriveAesKeyFromPassphrase, deriveBitsHkdf, deriveIdentity, deriveIdentityFromSeed, deriveMasterSeedFromPassword, deserialize, deviceFingerprint, deviceIdentityIsEphemeral, deviceIdentityKey, dirKey, ejectAgentPrompt, ejectAgentTools, emptyMap, emptyRegister, encodeToHex, encryptAesGcm, evaluatePasskeyPrf, exportPublicKeyBase64, exportPublicKeyHex, formatUserCode, fromBase64, fromBase64Url, fromHex, generateAuthProof, generateChecksum, generateDevicePairingKeypair, generateId, generatePkce, getIPAddress, getId, getMuhkooAppDescriptor, getSubtle, hasDeviceIdentity, headKey, historyKey, initBn128Wasm, initRsWasm, initializeCircuits, isNewer, isNumber, isOfflineCapable, isP2pCapable, isProvisional, loadDeviceIdentity, log, manifestToStat, materializeRow, merge3, merge3Text, mergeKey, mergeMap, mergeMessage, mergeRegister, messageKey, objectKey, pack, padHandle, pairingVerificationCode, passkeyPrfCapable, passkeySupported, passkeyUsableFromOrigin, persistDeviceIdentity, poseidonHash, protocol, provisionalHandle, quickVerify, randomBytes, randomState, refKey, refsIndexKey, rpIdUsableForOrigin, sealSeed, sealSeedToDevice, serialize, shardHash, signMessage, stableStringify, toBase64, toBase64Url, toField, toHex, tombstoneRow, unpack, unsealSeed, unsealSeedFromDevice, unwrapWithPassphrase, utf8Decode, utf8Encode, verify, verifyChecksum, verifyGroth16, verifyHashKnowledge, verifyPreimagePoK, wrapWithPassphrase, writeBeatsTombstone, writeColumns, writeRegister };
|
|
8264
|
-
export type { ACL, ACLEntry, AccessTokenInfo, AccessTokensNamespaceDeps, AgentConfig, AgentCreateInput, AgentDbToolMode, AgentProvisioned, AgentScopeOpts, AgentSkill, AgentToolsConfig, AgentTrigger, AgentTriggerType, AgentUpdateInput, AgentsNamespaceDeps, AttachedPeerNetwork, AuthClientOptions, AuthKeyPair, AuthSuccess, AuthToken, AuthType, AuthUser, BlockStore, Bn128WasmInstance, BroadcastChannelEvent, BroadcastChannelOptions, CachedSpaceMessage, Change, ChannelLike, ChunkKeyMaterial, ChunkManifest, CipherFrame, CipherMessage, CipherMessageHeader, CircuitBufferConfig, CircuitIntegrity, CircuitUrls, ClientOptions, Commit, Conflict, ConnectivityOptions, ConnectivityState, CreateAccessTokenInput, CreatedAccessToken, DbFilterOp, DbNamespaceDeps, DbQuery, DbQueryPage, DbQueryResult, DbWhereCondition, DehydratedKeypair, DehydratedKeys, DeviceBlobStore, DeviceKeyVault, DevicePairingErrorReason, DevicePairingKeypair, DevicePairingPoll, DevicePairingRequest, DevicePairingSession, DirEntry, DirNode, DoubleRatchetCipherDeps, ECDHCurve, EncodeResult, EngineHandle, EngineHost, Entry, EphemeralEvent, EpochKeyProvider, FileEntry, FileManifest, FileNamespaceDeps, FileStat, FileStorageOptions, FunctionCaps, FunctionConfig, FunctionDeployInput, FunctionInvokeOptions, FunctionScopeOpts, FunctionTrigger, FunctionTriggerType, FunctionTriggers, FunctionUpdateInput, FunctionsNamespaceDeps, Groth16Proof, Hasher, Head, HistoryRecord, HlcParts, HlcState, HostedAuthDeps, HttpClientOptions, IncomingFrame, KeyExchangeFrame, KeyPair, Keypair, KeyringClientDeps, KeyringTransport, KvEntry, KvNamespaceDeps, LogEntry, LoginOptions, LwwMap, LwwRegister, Merge3Result, MergeRegionConflict, MergeResult, MessageBody, MessageDeletedEvent, MessageEntry, MessageEvent, MessageHeaders, MessageNamespaceDeps, MessageOp, MessageOptions, MessageSubscription, MuhkooAgentMeta, MuhkooAgentToolsConfig, MuhkooAppDescriptor, MuhkooDBAccess, MuhkooDBMeta, MuhkooFunctionMeta, MuhkooKeystoreBridge, MuhkooMessageEvent, MuhkooSpaceMeta, OAuthProvider, OfflineEntry, OfflineManagerDeps, OfflineStore, OutSink, PacketCipher, PacketHeaders, PacketOptions, PairedDevice, Participant, PasskeyEnrollment, PeerBlockSource, PeerExchangeOptions, PeerId, PeerNetworkOptions, PeerTransport, Permission, PermissionCheckRequest, PermissionCheckResult, PersistedDeviceIdentity, PersonalSpaceClientOptions, Pkce, PublicKeyJWK, QueueEntry, RatchetState, ReceiveResult, RegisterParams, Replayer, Role, SpaceDeps as RoomDeps, SpaceFileMetadata as RoomFileMetadata, Scope, SealedHandoff, SealedHeaders, SealedRecord, Session, SessionOptions, SessionStore, SetOptions, ShardByteCache, ShardClientOptions, SharedSpaceClientOptions, SignalEnvelope, SignalKind, SignalingSpace, SnapshotNamespaceDeps, SnarkProof, SpaceChannelLike, SpaceCursor, SpaceDeps, SpaceFileMetadata, SpaceKeyCache, SpaceKeyringDeps, SpaceMessageEvent, SpaceNamespaceDeps, SpaceOfflineAdapter, StartDevicePairingOptions, StorageChangeEvent, StoreName, StoredSession, Subscription, Tree, TreeDir, TreeEntry, TreeFile, UserIdentity, VaultFactor, VcsNamespaceDeps, VcsNamespaceOptions, VerificationKey, VfsContentStore, VfsNamespaceDeps, VfsStat, VfsStore, WSMessage, WSMessageType, WSTransportOptions, WaitForDevicePairingOptions, WebRtcTransportOptions, WrappedPayload, WriteFileInput, WriteFileOptions, WriteToShardsInput, ZkAuthDeps, ZkAuthenticateRequest, ZkChallengeResponse, ZkCompiled, ZkIdentity, ZkRegisterRequest, ZkRegisterResponse };
|
|
9033
|
+
export { ACCESS_TOKEN_SCOPES, AES_GCM_IV_BYTES, AES_GCM_KEY_BYTES, AES_GCM_TAG_BYTES, AccessTokensNamespace, AdmissionDeniedError, AgentsNamespace, AuthClient, AuthHttpError, AuthNamespace, AuthPublicInput, Authenticator, BlockEngine, BroadcastChannel, BroadcastChannelEvents, ChannelExistsError, ChannelNotFoundError, ChunkCipher, CircuitIntegrityError, Client, ConnectivityManager, DEFAULT_AUTH_BASE_URL, DEFAULT_BASE_URL, DEFAULT_BRANCH, DEFAULT_FN_HOST_SUFFIX, DEVICE_IDENTITY_STORAGE_KEY, DEVICE_KEY_DB_NAME, DbCache, DbNamespace, DbTable, DevicePairingError, DeviceRevokedError, DeviceStoreUnavailableError, DoubleRatchet, DoubleRatchetCipher, DoubleRatchetManager, EncryptedSession, EventCore, EventCoreEvents, Field, Field as FieldElement, FileStorage, FunctionsNamespace, HLC, HashKnowledge, HostedAuth, HttpClient, HttpError, IdentityLockedError, IdentityUnavailableError, IndexedDbStore, KEEPER_MEMBER_ID, KeyStore, KeyringClient, KeyringHttpError, KvCache, KvNamespace, LocalEngineHost, LocalStorageSessionStore, Logger, MemorySessionStore, Message, Message as MessageDefault, MessageNamespace, MuhkooAgent, MuhkooDB, MuhkooFunction, MuhkooSpace, NOT_MEMBER_CLOSE_CODE, NOT_MEMBER_RECHECK_MS, NoopStore, OfflineLockedError, OfflineManager, OutboundQueue, P2P_SUBJECT, PAIRING_CODE_ALPHABET, PAIRING_CODE_LENGTH, PBKDF2_DEFAULT_ITERATIONS, PINNED_CIRCUIT_DIGESTS, PREIMAGE_POK_VERIFICATION_KEY, Packet, PasskeyOriginError, PeerExchange, PeerNetwork, PersonalSpaceClient, Poseidon, PreimagePoK, ROOT_ID, Ready, ReauthRequiredError, ReedSolomonCodec, Repo, Retry, Space as Room, SerializeMessage, SessionState, ShardCache, ShardClient, SharedSpaceClient, SnapshotNamespace, Space, SpaceCache, SpaceKeyring, SpaceNamespace, SpacePacketCipher, SpaceSignaler, SpaceTrustError, StorageNamespace, SyncEngine, VERSION, VFS_ROOT_INFO, VaultProtocolMismatchError, VaultUnavailableError, VcsError, VcsNamespace, VfsConflictError, VfsCorruptRecordError, VfsLimitError, VfsLockedError, VfsNamespace, VfsNotFoundError, WSTransport, WebRtcTransport, WorkerEngineHost, ZERO_HLC, ZkAuth, _accountId, _formatBytes, _messageId, _objectId, _packetId, _socketId, _userId, appLogger, assertType, base58Decode, base58Encode, buildCommitment, canonicalUserCode, clearDeviceIdentity, compareHlc, compilePrograms, concatBytes, configureDeviceStore, createPasskeyWithPrf, decodeFromHex, decorators, decryptAesGcm, defaultCircuitUrls, defaultRpId, defaultSessionStore, deleteBeatsWrite, deleteRegister, deriveAesKeyFromPassphrase, deriveBitsHkdf, deriveIdentity, deriveIdentityFromSeed, deriveMasterSeedFromPassword, deserialize, deviceFingerprint, deviceIdentityIsEphemeral, deviceIdentityKey, dirKey, ejectAgentPrompt, ejectAgentTools, emptyMap, emptyRegister, encodeToHex, encryptAesGcm, evaluatePasskeyPrf, exportPublicKeyBase64, exportPublicKeyHex, formatUserCode, fromBase64, fromBase64Url, fromHex, generateAuthProof, generateChecksum, generateDevicePairingKeypair, generateId, generatePkce, getIPAddress, getId, getMuhkooAppDescriptor, getSubtle, hasDeviceIdentity, headKey, historyKey, initBn128Wasm, initRsWasm, initializeCircuits, isNewer, isNumber, isOfflineCapable, isP2pCapable, isProvisional, isSameOriginPath, loadDeviceIdentity, log, manifestToStat, materializeRow, merge3, merge3Text, mergeKey, mergeMap, mergeMessage, mergeRegister, messageKey, objectKey, pack, padHandle, pairingVerificationCode, passkeyPrfCapable, passkeySupported, passkeyUsableFromOrigin, persistDeviceIdentity, poseidonHash, protocol, provisionalHandle, quickVerify, randomBytes, randomState, refKey, refsIndexKey, rpIdUsableForOrigin, sealSeed, sealSeedToDevice, serialize, shardHash, signMessage, stableStringify, toBase64, toBase64Url, toField, toHex, tombstoneRow, unpack, unsealSeed, unsealSeedFromDevice, unwrapWithPassphrase, utf8Decode, utf8Encode, verify, verifyChecksum, verifyGroth16, verifyHashKnowledge, verifyPreimagePoK, wrapWithPassphrase, writeBeatsTombstone, writeColumns, writeRegister };
|
|
9034
|
+
export type { ACL, ACLEntry, AccessTokenInfo, AccessTokensNamespaceDeps, AdmissionState, AgentConfig, AgentCreateInput, AgentDbToolMode, AgentProvisioned, AgentScopeOpts, AgentSkill, AgentToolsConfig, AgentTrigger, AgentTriggerType, AgentUpdateInput, AgentsNamespaceDeps, AttachedPeerNetwork, AuthClientOptions, AuthKeyPair, AuthSuccess, AuthToken, AuthType, AuthUser, BlockStore, Bn128WasmInstance, BroadcastChannelEvent, BroadcastChannelOptions, CachedSpaceMessage, Change, ChannelLike, ChatKeyCert, ChunkKeyMaterial, ChunkManifest, CipherFrame, CipherMessage, CipherMessageHeader, CircuitBufferConfig, CircuitIntegrity, CircuitUrls, ClientOptions, Commit, Conflict, ConnectivityOptions, ConnectivityState, CreateAccessTokenInput, CreatedAccessToken, DbFilterOp, DbNamespaceDeps, DbQuery, DbQueryPage, DbQueryResult, DbWhereCondition, DehydratedKeypair, DehydratedKeys, DeviceBlobStore, DeviceKeyVault, DevicePairingErrorReason, DevicePairingKeypair, DevicePairingPoll, DevicePairingRequest, DevicePairingSession, DirEntry, DirNode, DoubleRatchetCipherDeps, ECDHCurve, EncodeResult, EngineHandle, EngineHost, Entry, EphemeralEvent, EpochKeyProvider, FileEntry, FileManifest, FileNamespaceDeps, FileStat, FileStorageOptions, FunctionCaps, FunctionConfig, FunctionDeployInput, FunctionInvokeOptions, FunctionScopeOpts, FunctionTrigger, FunctionTriggerType, FunctionTriggers, FunctionUpdateInput, FunctionsNamespaceDeps, Groth16Proof, Hasher, Head, HistoryRecord, HlcParts, HlcState, HostedAuthDeps, HttpClientOptions, IncomingFrame, KeyExchangeFrame, KeyPair, Keypair, KeyringClientDeps, KeyringTransport, KvEntry, KvNamespaceDeps, LogEntry, LoginOptions, LwwMap, LwwRegister, MemberView, MembershipEntry, Merge3Result, MergeRegionConflict, MergeResult, MessageBody, MessageDeletedEvent, MessageEntry, MessageEvent, MessageHeaders, MessageNamespaceDeps, MessageOp, MessageOptions, MessageSubscription, MuhkooAgentMeta, MuhkooAgentToolsConfig, MuhkooAppDescriptor, MuhkooDBAccess, MuhkooDBMeta, MuhkooFunctionMeta, MuhkooKeystoreBridge, MuhkooMessageEvent, MuhkooSpaceMeta, OAuthProvider, OfflineEntry, OfflineManagerDeps, OfflineStore, OutSink, PacketCipher, PacketHeaders, PacketOptions, PairedDevice, Participant, PasskeyEnrollment, PeerBlockSource, PeerExchangeOptions, PeerId, PeerNetworkOptions, PeerTransport, Permission, PermissionCheckRequest, PermissionCheckResult, PersistedDeviceIdentity, PersonalSpaceClientOptions, Pkce, PublicKeyJWK, QueueEntry, RatchetState, ReceiveResult, RegisterParams, Replayer, Role$1 as Role, SpaceDeps as RoomDeps, SpaceFileMetadata as RoomFileMetadata, Scope, SealedHandoff, SealedHeaders, SealedRecord, Session, SessionOptions, SessionStore, SetOptions, ShardByteCache, ShardClientOptions, SharedSpaceClientOptions, SignalEnvelope, SignalKind, SignalingSpace, SnapshotNamespaceDeps, SnarkProof, SpaceChannelLike, SpaceCursor, SpaceDeps, SpaceFileMetadata, SpaceKeyCache, SpaceKeyringDeps, SpaceMessageEvent, SpaceNamespaceDeps, SpaceOfflineAdapter, SpaceTrustCode, StartDevicePairingOptions, StorageChangeEvent, StoreName, StoredSession, Subscription, Tree, TreeDir, TreeEntry, TreeFile, UserIdentity, VaultFactor, VcsNamespaceDeps, VcsNamespaceOptions, VerificationKey, VfsContentStore, VfsNamespaceDeps, VfsStat, VfsStore, WSMessage, WSMessageType, WSTransportOptions, WaitForDevicePairingOptions, WebRtcTransportOptions, WrappedPayload, WriteFileInput, WriteFileOptions, WriteToShardsInput, ZkAuthDeps, ZkAuthenticateRequest, ZkChallengeResponse, ZkCompiled, ZkIdentity, ZkRegisterRequest, ZkRegisterResponse };
|