@muhkoo/connect 0.2.0-alpha.2 → 0.4.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 +73 -6
- package/dist/browser/index.js +844 -282
- package/dist/browser/index.js.map +1 -1
- package/dist/connect.d.ts +661 -121
- package/dist/server/index.js +1456 -894
- package/dist/server/index.js.map +1 -1
- package/dist/workers/index.js +138 -4
- package/dist/workers/index.js.map +1 -1
- package/package.json +1 -1
package/dist/connect.d.ts
CHANGED
|
@@ -936,6 +936,22 @@ declare class EncryptedSession {
|
|
|
936
936
|
interface WSTransportOptions {
|
|
937
937
|
/** WebSocket URL, e.g. `ws://localhost:8787/foo`. */
|
|
938
938
|
url: string;
|
|
939
|
+
/**
|
|
940
|
+
* Optional async provider for a FRESH connection URL, called before each
|
|
941
|
+
* RECONNECT. Use it when the URL carries a single-use/expiring credential
|
|
942
|
+
* (e.g. a one-time WS upgrade ticket): on reconnect the baked-in ticket is
|
|
943
|
+
* already consumed/expired, so without this the reconnect is rejected and the
|
|
944
|
+
* transport burns through its attempts. The initial connect uses `url` as-is.
|
|
945
|
+
*/
|
|
946
|
+
urlProvider?: () => string | Promise<string>;
|
|
947
|
+
/**
|
|
948
|
+
* Stable identifier for this connection (a channel / space / personal-space
|
|
949
|
+
* id). Lifecycle + MESSAGE events are namespaced by it on the shared
|
|
950
|
+
* `EventCore` bus so concurrent transports (chat room A, room B, the storage
|
|
951
|
+
* feed, …) never receive each other's frames. Optional — a unique id is
|
|
952
|
+
* generated when omitted; pass a semantic one for clearer debugging.
|
|
953
|
+
*/
|
|
954
|
+
id?: string;
|
|
939
955
|
/** Reconnect automatically after unexpected disconnect (default `true`). */
|
|
940
956
|
autoReconnect?: boolean;
|
|
941
957
|
/** Delay between reconnect attempts in ms (default `3000`). */
|
|
@@ -947,12 +963,43 @@ interface WSTransportOptions {
|
|
|
947
963
|
* throws synchronously. Default `100`.
|
|
948
964
|
*/
|
|
949
965
|
maxQueueSize?: number;
|
|
966
|
+
/**
|
|
967
|
+
* Heartbeat interval in ms. While connected, a `pingFrame` is sent every
|
|
968
|
+
* interval to keep the socket warm (long-lived WebSockets get dropped by CF
|
|
969
|
+
* / intermediaries when idle) and to detect a silently-dead connection.
|
|
970
|
+
* Default `30000`. Set `0` to disable the heartbeat entirely.
|
|
971
|
+
*/
|
|
972
|
+
heartbeatInterval?: number;
|
|
973
|
+
/**
|
|
974
|
+
* How long (ms) to wait for a `pongFrame` after sending a ping before
|
|
975
|
+
* treating the connection as dead and forcing a reconnect. Should be well
|
|
976
|
+
* under `heartbeatInterval`. Default `10000`.
|
|
977
|
+
*/
|
|
978
|
+
heartbeatTimeout?: number;
|
|
979
|
+
/** Outbound keep-alive frame. Default `"ping"`. */
|
|
980
|
+
pingFrame?: string;
|
|
981
|
+
/**
|
|
982
|
+
* Inbound keep-alive ack. Matching frames are swallowed (never surfaced as a
|
|
983
|
+
* `MESSAGE`) and reset the liveness timer. Must match the server's
|
|
984
|
+
* auto-response. Default `"pong"`.
|
|
985
|
+
*/
|
|
986
|
+
pongFrame?: string;
|
|
950
987
|
}
|
|
951
988
|
declare class WSTransport extends EventCore {
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
989
|
+
/**
|
|
990
|
+
* Per-instance event scope. `EventCore` is a process-global static emitter,
|
|
991
|
+
* so without namespacing every WSTransport would hear every other one's
|
|
992
|
+
* frames. We prefix each event with this transport's `id` and expose
|
|
993
|
+
* `on`/`off`/`emit` that scope transparently — callers still use the plain
|
|
994
|
+
* `EventCoreEvents` enum and only ever see their own connection's events.
|
|
995
|
+
*/
|
|
996
|
+
readonly id: string;
|
|
997
|
+
readonly emit: (event: EventCoreEvents, data: unknown) => void;
|
|
998
|
+
readonly on: (event: EventCoreEvents, handler: EventListener | CallableFunction) => void;
|
|
999
|
+
readonly off: (event: EventCoreEvents, handler: EventListener | CallableFunction) => void;
|
|
1000
|
+
private scopedEvent;
|
|
955
1001
|
private url;
|
|
1002
|
+
private urlProvider?;
|
|
956
1003
|
private socket;
|
|
957
1004
|
private _isConnected;
|
|
958
1005
|
private _isConnecting;
|
|
@@ -963,6 +1010,12 @@ declare class WSTransport extends EventCore {
|
|
|
963
1010
|
private reconnectTimeout;
|
|
964
1011
|
private outboundQueue;
|
|
965
1012
|
private maxQueueSize;
|
|
1013
|
+
private heartbeatInterval;
|
|
1014
|
+
private heartbeatTimeout;
|
|
1015
|
+
private pingFrame;
|
|
1016
|
+
private pongFrame;
|
|
1017
|
+
private heartbeatTimer;
|
|
1018
|
+
private pongTimer;
|
|
966
1019
|
constructor(opts: WSTransportOptions);
|
|
967
1020
|
/** Open the socket. Resolves when CONNECTED fires. Rejects on first error. */
|
|
968
1021
|
connect(): Promise<void>;
|
|
@@ -977,6 +1030,25 @@ declare class WSTransport extends EventCore {
|
|
|
977
1030
|
isConnecting(): boolean;
|
|
978
1031
|
queuedFrames(): number;
|
|
979
1032
|
reconnectAttemptCount(): number;
|
|
1033
|
+
/** Begin the keep-alive loop (no-op when disabled). */
|
|
1034
|
+
private startHeartbeat;
|
|
1035
|
+
/** Stop the keep-alive loop and clear any pending liveness deadline. */
|
|
1036
|
+
private stopHeartbeat;
|
|
1037
|
+
/**
|
|
1038
|
+
* Send one ping and arm a liveness deadline. If no `pongFrame` arrives before
|
|
1039
|
+
* `heartbeatTimeout`, the connection is considered dead and we force a
|
|
1040
|
+
* reconnect — this is what catches a silently-dropped TCP connection that
|
|
1041
|
+
* never fired `onclose` (the failure mode that "loses connection with the
|
|
1042
|
+
* Accelerator" on long sessions).
|
|
1043
|
+
*/
|
|
1044
|
+
private sendHeartbeat;
|
|
1045
|
+
/**
|
|
1046
|
+
* Tear down a connection we believe is dead and kick off reconnect, without
|
|
1047
|
+
* waiting on the OS/browser to eventually fire `onclose` (which a half-open
|
|
1048
|
+
* socket may never do). We detach the handlers first so the normal close path
|
|
1049
|
+
* can't double-fire the reconnect.
|
|
1050
|
+
*/
|
|
1051
|
+
private forceReconnect;
|
|
980
1052
|
private scheduleReconnect;
|
|
981
1053
|
private flushQueue;
|
|
982
1054
|
}
|
|
@@ -1382,123 +1454,50 @@ declare class ShardClient {
|
|
|
1382
1454
|
}
|
|
1383
1455
|
|
|
1384
1456
|
/**
|
|
1385
|
-
* HTTP client for the
|
|
1386
|
-
*
|
|
1387
|
-
* Mirrors the proven shape of `PersonalSpaceClient` — every gated call:
|
|
1388
|
-
* 1. POSTs `/challenge` to get a fresh nonce keyed to the caller's commitment
|
|
1389
|
-
* 2. Generates a Groth16 proof for the `preimagePoK` circuit with the nonce
|
|
1390
|
-
* reduced into a BN254 field element as the public signal
|
|
1391
|
-
* 3. POSTs the operation with `{ challengeId, proof, publicSignals, ... }`
|
|
1392
|
-
*
|
|
1393
|
-
* What's different from `PersonalSpaceClient`:
|
|
1394
|
-
* - Addressed by space ID, not user commitment. Multiple users can be
|
|
1395
|
-
* members of the same space.
|
|
1396
|
-
* - The space carries a participants list + ACL (shared types from
|
|
1397
|
-
* `src/types/permissions.ts`). The server checks that the proving
|
|
1398
|
-
* commitment is a participant with the requested permission before each
|
|
1399
|
-
* mutation.
|
|
1400
|
-
* - Stores file manifests (not generic KV blobs). The shape is constrained
|
|
1401
|
-
* by `FileManifest` from `../types`.
|
|
1402
|
-
*
|
|
1403
|
-
* Wire protocol (this client implements the client side; the server side is
|
|
1404
|
-
* the next slice of work in accelerator):
|
|
1405
|
-
*
|
|
1406
|
-
* POST /api/spaces create a new space (gated by caller proof)
|
|
1407
|
-
* body: { challengeId, proof, publicSignals, initialAcl? }
|
|
1408
|
-
* returns: { spaceId }
|
|
1409
|
-
*
|
|
1410
|
-
* POST /api/spaces/:spaceId/challenge issue a nonce for the caller
|
|
1411
|
-
* body: { commitment }
|
|
1412
|
-
* returns: { challengeId, nonce }
|
|
1413
|
-
*
|
|
1414
|
-
* POST /api/spaces/:spaceId/files write a file manifest
|
|
1415
|
-
* body: { challengeId, proof, publicSignals, manifest }
|
|
1416
|
-
* returns: { ok: true, fileId }
|
|
1417
|
-
*
|
|
1418
|
-
* POST /api/spaces/:spaceId/files/:fileId/get read a file manifest
|
|
1419
|
-
* body: { challengeId, proof, publicSignals }
|
|
1420
|
-
* returns: { manifest }
|
|
1421
|
-
*
|
|
1422
|
-
* DELETE /api/spaces/:spaceId/files/:fileId delete a file manifest
|
|
1423
|
-
* body: { challengeId, proof, publicSignals }
|
|
1424
|
-
* returns: { ok: true, existed: boolean }
|
|
1425
|
-
*
|
|
1426
|
-
* POST /api/spaces/:spaceId/files/list list manifests in space
|
|
1427
|
-
* body: { challengeId, proof, publicSignals }
|
|
1428
|
-
* returns: { files: FileStat[] }
|
|
1457
|
+
* HTTP client for the gated file-manifest store on a SharedSpace
|
|
1458
|
+
* (`/api/spaces/:spaceId/files`).
|
|
1429
1459
|
*
|
|
1430
|
-
*
|
|
1431
|
-
*
|
|
1432
|
-
*
|
|
1460
|
+
* A "file" in a space is its **manifest** (per-chunk keys + the SHA-256 of each
|
|
1461
|
+
* global shard). The shard bytes live in the open `/api/shards` store; the
|
|
1462
|
+
* manifest is the capability. This client only moves manifests in/out of the
|
|
1463
|
+
* space's gated store.
|
|
1433
1464
|
*
|
|
1434
|
-
*
|
|
1435
|
-
*
|
|
1436
|
-
*
|
|
1465
|
+
* Authorization is **session-based**, consistent with the rest of the
|
|
1466
|
+
* SharedSpace (keyring, websocket): the SDK's credential-stamping `fetch`
|
|
1467
|
+
* (from {@link HttpClient}) attaches the app key + session token, the platform
|
|
1468
|
+
* validates the session and injects a trusted `X-Muhkoo-User-Context`, and the
|
|
1469
|
+
* DO authorizes on that + channel membership. There is no per-op Groth16 proof.
|
|
1437
1470
|
*
|
|
1438
|
-
*
|
|
1439
|
-
*
|
|
1440
|
-
*
|
|
1471
|
+
* Wire protocol (server: `SharedSpaceDO`):
|
|
1472
|
+
* POST /api/spaces/:spaceId/files body: { manifest } → { ok, fileId }
|
|
1473
|
+
* GET /api/spaces/:spaceId/files → { files: FileStat[] }
|
|
1474
|
+
* GET /api/spaces/:spaceId/files/:fileId → { manifest }
|
|
1475
|
+
* DELETE /api/spaces/:spaceId/files/:fileId → { ok, existed }
|
|
1441
1476
|
*/
|
|
1442
1477
|
|
|
1443
1478
|
interface SharedSpaceClientOptions {
|
|
1444
|
-
/** Base URL of the accelerator. */
|
|
1479
|
+
/** Base URL of the accelerator (e.g. `https://api.muhkoo.dev`). */
|
|
1445
1480
|
baseUrl: string;
|
|
1446
|
-
/**
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
ecdsaPub: string;
|
|
1452
|
-
/** Public signal: Poseidon hash of `ecdsaPub`. */
|
|
1453
|
-
ecdsaPubHash: string;
|
|
1454
|
-
/** Compiled circuit assets — same files PersonalSpaceClient uses. */
|
|
1455
|
-
circuits: {
|
|
1456
|
-
wasmUrl: string;
|
|
1457
|
-
zkeyUrl: string;
|
|
1458
|
-
};
|
|
1459
|
-
/** Optional custom fetch (defaults to `globalThis.fetch`). */
|
|
1481
|
+
/**
|
|
1482
|
+
* Credential-stamping fetch — pass {@link HttpClient.fetch} so requests
|
|
1483
|
+
* carry the app key + session token. Defaults to `globalThis.fetch`
|
|
1484
|
+
* (unauthenticated; only useful in tests).
|
|
1485
|
+
*/
|
|
1460
1486
|
fetch?: typeof fetch;
|
|
1461
1487
|
}
|
|
1462
1488
|
declare class SharedSpaceClient {
|
|
1463
1489
|
private readonly baseUrl;
|
|
1464
|
-
private readonly commitment;
|
|
1465
|
-
private readonly secret;
|
|
1466
|
-
private readonly salt;
|
|
1467
|
-
private readonly ecdsaPub;
|
|
1468
|
-
private readonly ecdsaPubHash;
|
|
1469
|
-
private readonly wasmUrl;
|
|
1470
|
-
private readonly zkeyUrl;
|
|
1471
1490
|
private readonly fetchFn;
|
|
1472
1491
|
constructor(opts: SharedSpaceClientOptions);
|
|
1473
|
-
/**
|
|
1474
|
-
* Create a brand new space. The caller becomes the owner; `initialAcl`
|
|
1475
|
-
* adds any additional ACL entries up front (e.g. inviting a co-owner at
|
|
1476
|
-
* creation time).
|
|
1477
|
-
*/
|
|
1478
|
-
createSpace(initialAcl?: ACLEntry[]): Promise<{
|
|
1479
|
-
spaceId: string;
|
|
1480
|
-
}>;
|
|
1481
|
-
/** Write a file manifest into the space. Requires `write` permission. */
|
|
1492
|
+
/** Write a file manifest into the space. Requires space membership. */
|
|
1482
1493
|
writeFileManifest(spaceId: string, manifest: FileManifest): Promise<void>;
|
|
1483
|
-
/** Read a file manifest by id. Requires
|
|
1494
|
+
/** Read a file manifest by id. Requires space membership. */
|
|
1484
1495
|
readFileManifest(spaceId: string, fileId: string): Promise<FileManifest>;
|
|
1485
|
-
/** Delete a file manifest by id. Requires
|
|
1496
|
+
/** Delete a file manifest by id. Requires space membership. */
|
|
1486
1497
|
deleteFileManifest(spaceId: string, fileId: string): Promise<boolean>;
|
|
1487
|
-
/** List file summaries in the space. Requires
|
|
1498
|
+
/** List file summaries in the space. Requires space membership. */
|
|
1488
1499
|
listFiles(spaceId: string): Promise<FileStat[]>;
|
|
1489
|
-
|
|
1490
|
-
addParticipant(spaceId: string, participant: Participant): Promise<void>;
|
|
1491
|
-
/** Remove a participant by their public-key identity. Requires `admin`. */
|
|
1492
|
-
removeParticipant(spaceId: string, participantCommitment: string): Promise<boolean>;
|
|
1493
|
-
/** Set / replace an ACL entry. Requires `admin`. */
|
|
1494
|
-
setACLEntry(spaceId: string, entry: ACLEntry): Promise<void>;
|
|
1495
|
-
/** Request a challenge for `spaceId` and generate the matching proof. */
|
|
1496
|
-
private proveFreshChallenge;
|
|
1497
|
-
/**
|
|
1498
|
-
* Hit `/challenge`. The body includes the caller's commitment so the
|
|
1499
|
-
* server can scope the issued nonce to this principal.
|
|
1500
|
-
*/
|
|
1501
|
-
private requestChallenge;
|
|
1500
|
+
private filesBase;
|
|
1502
1501
|
private jsonRequest;
|
|
1503
1502
|
}
|
|
1504
1503
|
|
|
@@ -1596,6 +1595,12 @@ interface WriteToShardsInput {
|
|
|
1596
1595
|
* resumable uploads: the same id always maps to the same manifest slot.
|
|
1597
1596
|
*/
|
|
1598
1597
|
fileId?: string;
|
|
1598
|
+
/**
|
|
1599
|
+
* Optional upload-progress callback, invoked after each chunk finishes
|
|
1600
|
+
* (`completed` of `total` chunks). Lets a UI show a progress bar. Called once
|
|
1601
|
+
* with `(0, total)` before the first chunk so a bar can render immediately.
|
|
1602
|
+
*/
|
|
1603
|
+
onProgress?: (completed: number, total: number) => void;
|
|
1599
1604
|
}
|
|
1600
1605
|
declare class FileStorage {
|
|
1601
1606
|
private readonly space;
|
|
@@ -2158,6 +2163,30 @@ declare class ZkAuth {
|
|
|
2158
2163
|
* both the session and the identity are stored on the client.
|
|
2159
2164
|
*/
|
|
2160
2165
|
login(username: string, password: string, opts?: LoginOptions): Promise<AuthUser>;
|
|
2166
|
+
/**
|
|
2167
|
+
* Silently re-authenticate the current user without prompting for a
|
|
2168
|
+
* password. Only possible while the client is **unlocked** — i.e. the
|
|
2169
|
+
* derived {@link ZkIdentity} (secret + keypairs) is still in memory from a
|
|
2170
|
+
* prior `login()`/`unlock()`. Re-runs the full challenge→proof→authenticate
|
|
2171
|
+
* dance with that in-memory identity and swaps in the fresh token.
|
|
2172
|
+
*
|
|
2173
|
+
* Returns `true` if a new session was minted, `false` if recovery isn't
|
|
2174
|
+
* possible (no active user, or locked — the identity was never derived or
|
|
2175
|
+
* was lost on reload). A `false` result is the app's cue to send the user
|
|
2176
|
+
* back to the login screen.
|
|
2177
|
+
*
|
|
2178
|
+
* Used automatically by the {@link Client} when a token-gated request comes
|
|
2179
|
+
* back `401` (stale/expired token), so transient session expiry self-heals
|
|
2180
|
+
* instead of surfacing errors mid-session.
|
|
2181
|
+
*/
|
|
2182
|
+
recover(): Promise<boolean>;
|
|
2183
|
+
/**
|
|
2184
|
+
* Shared sign-in core: prove knowledge of `identity` against a fresh
|
|
2185
|
+
* challenge and persist the resulting session + identity. Used by both
|
|
2186
|
+
* `login()` (identity derived from a password) and `recover()` (identity
|
|
2187
|
+
* already in memory).
|
|
2188
|
+
*/
|
|
2189
|
+
private proveAndStore;
|
|
2161
2190
|
/**
|
|
2162
2191
|
* Restore a persisted session on boot. Validates the stored token with the
|
|
2163
2192
|
* accelerator; returns the user when valid, or `null` (and clears the
|
|
@@ -2231,6 +2260,18 @@ interface HttpClientOptions {
|
|
|
2231
2260
|
getSessionToken?: () => string | null;
|
|
2232
2261
|
/** Custom fetch — defaults to `globalThis.fetch`. */
|
|
2233
2262
|
fetch?: typeof fetch;
|
|
2263
|
+
/**
|
|
2264
|
+
* Called when a token-gated request comes back `401` (stale/expired
|
|
2265
|
+
* session). Should attempt to silently re-establish a session and resolve
|
|
2266
|
+
* `true` if it succeeded (the request is then retried once with the fresh
|
|
2267
|
+
* token) or `false` if it couldn't (the `401` propagates as an
|
|
2268
|
+
* {@link HttpError}). Wired by {@link Client} to `auth.zk.recover()`.
|
|
2269
|
+
*
|
|
2270
|
+
* Only consulted by the JSON helpers (`get`/`post`/`del`); the raw
|
|
2271
|
+
* {@link fetch} passes 401s straight through so the auth wire calls that
|
|
2272
|
+
* power recovery itself can't recurse.
|
|
2273
|
+
*/
|
|
2274
|
+
onUnauthorized?: () => Promise<boolean>;
|
|
2234
2275
|
}
|
|
2235
2276
|
/** Thrown for any non-2xx accelerator response. Carries the HTTP status. */
|
|
2236
2277
|
declare class HttpError extends Error {
|
|
@@ -2242,6 +2283,7 @@ declare class HttpClient {
|
|
|
2242
2283
|
readonly baseUrl: string;
|
|
2243
2284
|
private readonly apiKey;
|
|
2244
2285
|
private readonly getSessionToken;
|
|
2286
|
+
private readonly onUnauthorized;
|
|
2245
2287
|
private readonly fetchFn;
|
|
2246
2288
|
constructor(opts: HttpClientOptions);
|
|
2247
2289
|
/**
|
|
@@ -2252,19 +2294,20 @@ declare class HttpClient {
|
|
|
2252
2294
|
readonly fetch: typeof fetch;
|
|
2253
2295
|
get<T = unknown>(path: string): Promise<T>;
|
|
2254
2296
|
post<T = unknown>(path: string, body?: unknown): Promise<T>;
|
|
2297
|
+
patch<T = unknown>(path: string, body?: unknown): Promise<T>;
|
|
2255
2298
|
del<T = unknown>(path: string, body?: unknown): Promise<T>;
|
|
2256
2299
|
private request;
|
|
2257
2300
|
}
|
|
2258
2301
|
|
|
2259
2302
|
/**
|
|
2260
|
-
* `client.
|
|
2261
|
-
*
|
|
2303
|
+
* `client.kv` — per-user key/value storage backed by the accelerator's personal
|
|
2304
|
+
* space.
|
|
2262
2305
|
*
|
|
2263
|
-
* await client.
|
|
2264
|
-
* const todo = await client.
|
|
2265
|
-
* const ids = await client.
|
|
2266
|
-
* await client.
|
|
2267
|
-
* const off = client.
|
|
2306
|
+
* await client.kv.set('todos', id, { title, completed })
|
|
2307
|
+
* const todo = await client.kv.get('todos', id)
|
|
2308
|
+
* const ids = await client.kv.list('todos')
|
|
2309
|
+
* await client.kv.delete('todos', id)
|
|
2310
|
+
* const off = client.kv.on('change', e => …) // realtime, cross-device
|
|
2268
2311
|
*
|
|
2269
2312
|
* A *collection* is a key namespace within the user's space; the stored key is
|
|
2270
2313
|
* `${collection}/${id}`. Operations are authorized by the user's session token
|
|
@@ -2272,13 +2315,15 @@ declare class HttpClient {
|
|
|
2272
2315
|
*
|
|
2273
2316
|
* Values are encrypted at rest by default ({@link StorageCipher}, an AES-GCM
|
|
2274
2317
|
* key derived from the ZK identity); pass `{ encrypt: false }` to store
|
|
2275
|
-
* plaintext. The realtime feed rides the personal space's
|
|
2276
|
-
*
|
|
2318
|
+
* plaintext. The realtime feed rides the personal space's websocket over a
|
|
2319
|
+
* {@link WSTransport} (heartbeat keep-alive + auto-reconnect, event-namespaced
|
|
2320
|
+
* so it doesn't cross wires with chat/space transports).
|
|
2277
2321
|
*
|
|
2278
|
-
*
|
|
2322
|
+
* For **files** (blobs), use `client.storage` instead — `client.kv` is for
|
|
2323
|
+
* small structured values. `query()` is intentionally deferred.
|
|
2279
2324
|
*/
|
|
2280
2325
|
|
|
2281
|
-
interface
|
|
2326
|
+
interface KvNamespaceDeps {
|
|
2282
2327
|
http: HttpClient;
|
|
2283
2328
|
session: SessionState;
|
|
2284
2329
|
/** WebSocket base (ws/wss) for the change feed; derived from baseUrl. */
|
|
@@ -2295,11 +2340,11 @@ interface StorageChangeEvent<T = unknown> {
|
|
|
2295
2340
|
/** The decrypted value for `set`; `null` for `delete`. */
|
|
2296
2341
|
data: T | null;
|
|
2297
2342
|
}
|
|
2298
|
-
declare class
|
|
2343
|
+
declare class KvNamespace {
|
|
2299
2344
|
private readonly deps;
|
|
2300
2345
|
private cipher;
|
|
2301
2346
|
private cipherIdentity;
|
|
2302
|
-
constructor(deps:
|
|
2347
|
+
constructor(deps: KvNamespaceDeps);
|
|
2303
2348
|
/** Store `value` under `collection`/`id` (encrypted at rest by default). */
|
|
2304
2349
|
set<T = unknown>(collection: string, id: string, value: T, opts?: SetOptions): Promise<void>;
|
|
2305
2350
|
/** Fetch the value at `collection`/`id`, or `null` if absent. */
|
|
@@ -2328,6 +2373,100 @@ declare class StorageNamespace {
|
|
|
2328
2373
|
private getCipher;
|
|
2329
2374
|
}
|
|
2330
2375
|
|
|
2376
|
+
/**
|
|
2377
|
+
* `client.storage` — file storage. Hides the `FileStorage` / `ShardClient` /
|
|
2378
|
+
* `SharedSpaceClient` primitives behind the unified client.
|
|
2379
|
+
*
|
|
2380
|
+
* const { stat, manifest } = await client.storage.writeFile({ spaceId, data, metadata })
|
|
2381
|
+
* const { data } = await client.storage.readFile(spaceId, fileId)
|
|
2382
|
+
* const files = await client.storage.listFiles() // my shared files
|
|
2383
|
+
* const files = await client.storage.listFiles({ spaceId }) // a space's files
|
|
2384
|
+
* await client.storage.deleteFile(spaceId, fileId)
|
|
2385
|
+
*
|
|
2386
|
+
* Model:
|
|
2387
|
+
* - **Files are written to a SharedSpace** (never the personal space). A file
|
|
2388
|
+
* is its manifest (per-chunk keys + global shard hashes); the manifest lives
|
|
2389
|
+
* in the space's gated, metered `/files` store, the shard ciphertext in the
|
|
2390
|
+
* global open `/api/shards` store.
|
|
2391
|
+
* - **The manifest is the capability** — anyone holding it reads the file from
|
|
2392
|
+
* the global shards, anywhere ({@link readByManifest}). Share a file by
|
|
2393
|
+
* sharing its manifest.
|
|
2394
|
+
* - **Personal discovery mirror** — on a successful write the SDK also records
|
|
2395
|
+
* the manifest in the user's `client.kv` under a reserved collection, so
|
|
2396
|
+
* {@link listFiles} (no `spaceId`) can show "files I've shared" without
|
|
2397
|
+
* enumerating spaces. The mirror is unmetered and is NOT a write path.
|
|
2398
|
+
*
|
|
2399
|
+
* For small structured values use `client.kv` instead.
|
|
2400
|
+
*/
|
|
2401
|
+
|
|
2402
|
+
interface FileNamespaceDeps {
|
|
2403
|
+
http: HttpClient;
|
|
2404
|
+
baseUrl: string;
|
|
2405
|
+
/** Used for the unmetered personal discovery mirror. */
|
|
2406
|
+
kv: KvNamespace;
|
|
2407
|
+
/**
|
|
2408
|
+
* Optional pre-compiled Reed–Solomon WASM module. Defaults to the bundled
|
|
2409
|
+
* loader; pass one where the bundled loader path isn't available (vitest,
|
|
2410
|
+
* deploy-time-precompiled environments). Forwarded to {@link FileStorage}.
|
|
2411
|
+
*/
|
|
2412
|
+
rsWasmModule?: WebAssembly.Module;
|
|
2413
|
+
}
|
|
2414
|
+
interface WriteFileOptions {
|
|
2415
|
+
/** SharedSpace the file is written to (obtain via `client.space`). */
|
|
2416
|
+
spaceId: string;
|
|
2417
|
+
data: Uint8Array | Blob | File;
|
|
2418
|
+
metadata: {
|
|
2419
|
+
name: string;
|
|
2420
|
+
type: string;
|
|
2421
|
+
path?: string;
|
|
2422
|
+
lastModified?: number;
|
|
2423
|
+
};
|
|
2424
|
+
}
|
|
2425
|
+
declare class StorageNamespace {
|
|
2426
|
+
private readonly deps;
|
|
2427
|
+
private fileStorage;
|
|
2428
|
+
constructor(deps: FileNamespaceDeps);
|
|
2429
|
+
/**
|
|
2430
|
+
* Write a file to a SharedSpace: shard ciphertext → the global store, the
|
|
2431
|
+
* manifest → the space's gated store, and a mirror copy → the caller's
|
|
2432
|
+
* personal index. Returns the `stat` and the `manifest` (share the manifest
|
|
2433
|
+
* to let others read the file).
|
|
2434
|
+
*/
|
|
2435
|
+
writeFile(input: WriteFileOptions): Promise<{
|
|
2436
|
+
stat: FileStat;
|
|
2437
|
+
manifest: FileManifest;
|
|
2438
|
+
}>;
|
|
2439
|
+
/** Read a file from its space (resolves the manifest, then the shards). */
|
|
2440
|
+
readFile(spaceId: string, fileId: string): Promise<{
|
|
2441
|
+
data: Uint8Array;
|
|
2442
|
+
stat: FileStat;
|
|
2443
|
+
}>;
|
|
2444
|
+
/**
|
|
2445
|
+
* Read a file straight from a manifest — the capability path. No space
|
|
2446
|
+
* membership needed; this is how a shared file is opened.
|
|
2447
|
+
*/
|
|
2448
|
+
readByManifest(manifest: FileManifest): Promise<{
|
|
2449
|
+
data: Uint8Array;
|
|
2450
|
+
stat: FileStat;
|
|
2451
|
+
}>;
|
|
2452
|
+
/**
|
|
2453
|
+
* List files. With no argument, returns the caller's own shared files from
|
|
2454
|
+
* the personal mirror; with `{ spaceId }`, lists that space's files.
|
|
2455
|
+
*/
|
|
2456
|
+
listFiles(opts?: {
|
|
2457
|
+
spaceId?: string;
|
|
2458
|
+
}): Promise<FileStat[]>;
|
|
2459
|
+
/** Delete a file from its space and remove the personal mirror entry. */
|
|
2460
|
+
deleteFile(spaceId: string, fileId: string): Promise<boolean>;
|
|
2461
|
+
/** Read a manifest verbatim (e.g. to share a file). */
|
|
2462
|
+
getManifest(spaceId: string, fileId: string): Promise<FileManifest>;
|
|
2463
|
+
private fs;
|
|
2464
|
+
private _shards;
|
|
2465
|
+
private shards;
|
|
2466
|
+
private _space;
|
|
2467
|
+
private space;
|
|
2468
|
+
}
|
|
2469
|
+
|
|
2331
2470
|
/**
|
|
2332
2471
|
* Shared types for the Space fan-out group-encryption layer.
|
|
2333
2472
|
*
|
|
@@ -2393,6 +2532,23 @@ interface RosterMember {
|
|
|
2393
2532
|
/** Base64url-encoded JWK of the member's identity ECDSA public key. */
|
|
2394
2533
|
identityEcdsaPub?: string;
|
|
2395
2534
|
}
|
|
2535
|
+
/** A shareable invite link to a space. Redeeming it allowlists the holder so
|
|
2536
|
+
* the keeper admits them. */
|
|
2537
|
+
interface InviteLink {
|
|
2538
|
+
/** The capability token; embed in a URL to share. */
|
|
2539
|
+
token: string;
|
|
2540
|
+
/** Member id (username) that created the link. */
|
|
2541
|
+
createdBy?: string;
|
|
2542
|
+
createdAt?: number;
|
|
2543
|
+
/** Epoch ms when the link stops working; 0 = never. */
|
|
2544
|
+
expiresAt?: number;
|
|
2545
|
+
/** Max redemptions; 0 = unlimited. */
|
|
2546
|
+
maxUses?: number;
|
|
2547
|
+
/** Redemptions so far. */
|
|
2548
|
+
uses?: number;
|
|
2549
|
+
/** Access level granted to redeemers ("viewer" | "editor"). */
|
|
2550
|
+
role?: string;
|
|
2551
|
+
}
|
|
2396
2552
|
|
|
2397
2553
|
/**
|
|
2398
2554
|
* PacketCipher — the strategy `Network` uses to seal/open a packet's payload.
|
|
@@ -2631,8 +2787,35 @@ interface SpaceMessageEvent {
|
|
|
2631
2787
|
channel: string;
|
|
2632
2788
|
epoch: number;
|
|
2633
2789
|
contentType?: string;
|
|
2790
|
+
/**
|
|
2791
|
+
* Server storage handle — the monotonic server timestamp this message is
|
|
2792
|
+
* persisted under (`msg:<handle>`). Stable across history replay; pass it to
|
|
2793
|
+
* {@link Space.editMessage} / {@link Space.deleteMessage} to mutate the
|
|
2794
|
+
* persisted entry. Carried on edit events too (same handle as the original).
|
|
2795
|
+
*/
|
|
2796
|
+
handle: number;
|
|
2634
2797
|
message: Message;
|
|
2635
2798
|
}
|
|
2799
|
+
/**
|
|
2800
|
+
* An inbound ephemeral signal — an application broadcast the server relays to
|
|
2801
|
+
* the room but never persists (no history). Rides the generic `pub` relay:
|
|
2802
|
+
* `subject` is an app-defined routing key, `data` is opaque app JSON, and
|
|
2803
|
+
* `from` is the server-authenticated sender. Typing indicators, presence pings,
|
|
2804
|
+
* live cursors, etc. are built on top of this in the app layer — the SDK and
|
|
2805
|
+
* server stay domain-agnostic.
|
|
2806
|
+
*/
|
|
2807
|
+
interface EphemeralEvent {
|
|
2808
|
+
/** Server-stamped authenticated sender. */
|
|
2809
|
+
from: string;
|
|
2810
|
+
/** Application-defined routing key (e.g. "typing"). */
|
|
2811
|
+
subject: string;
|
|
2812
|
+
/** Opaque application payload. */
|
|
2813
|
+
data: unknown;
|
|
2814
|
+
}
|
|
2815
|
+
/** A server-authoritative deletion of the persisted message at `handle`. */
|
|
2816
|
+
interface MessageDeletedEvent {
|
|
2817
|
+
handle: number;
|
|
2818
|
+
}
|
|
2636
2819
|
interface SpaceDeps {
|
|
2637
2820
|
/** Transport room id. For fan-out spaces this is the encoded space pubkey. */
|
|
2638
2821
|
name: string;
|
|
@@ -2715,6 +2898,38 @@ declare class Space {
|
|
|
2715
2898
|
}): Promise<void>;
|
|
2716
2899
|
/** Subscribe to decrypted fan-out messages. Returns an unsubscribe fn. */
|
|
2717
2900
|
onMessage(handler: (e: SpaceMessageEvent) => void): () => void;
|
|
2901
|
+
/**
|
|
2902
|
+
* Edit a persisted message IN PLACE, addressed by its server
|
|
2903
|
+
* {@link SpaceMessageEvent.handle}. Re-seals `payload` and asks the server
|
|
2904
|
+
* to replace the stored entry; the server authorizes against the original
|
|
2905
|
+
* author. Receivers get an {@link onMessageEdited} event carrying the new
|
|
2906
|
+
* content at the same handle. This is a generic persisted-item edit — the
|
|
2907
|
+
* server has no notion of what the payload means.
|
|
2908
|
+
*/
|
|
2909
|
+
editMessage(handle: number, payload: unknown, opts?: {
|
|
2910
|
+
channel?: string;
|
|
2911
|
+
contentType?: string;
|
|
2912
|
+
}): Promise<void>;
|
|
2913
|
+
/**
|
|
2914
|
+
* Hard-delete a persisted message by its server {@link SpaceMessageEvent.handle}
|
|
2915
|
+
* — the ciphertext is removed from storage. Server authorizes against the
|
|
2916
|
+
* original author. Receivers get an {@link onMessageDeleted} event.
|
|
2917
|
+
*/
|
|
2918
|
+
deleteMessage(handle: number): Promise<void>;
|
|
2919
|
+
/** Subscribe to in-place edits of persisted messages (new content at the same handle). */
|
|
2920
|
+
onMessageEdited(handler: (e: SpaceMessageEvent) => void): () => void;
|
|
2921
|
+
/** Subscribe to deletions of persisted messages. */
|
|
2922
|
+
onMessageDeleted(handler: (e: MessageDeletedEvent) => void): () => void;
|
|
2923
|
+
/**
|
|
2924
|
+
* Broadcast an ephemeral, never-persisted signal to the room over the
|
|
2925
|
+
* generic `pub` relay. `subject` is an app-defined routing key; `data` is
|
|
2926
|
+
* opaque. The transport stays domain-agnostic — app concepts like typing
|
|
2927
|
+
* indicators, presence, or live cursors are built on top of this. No-op if
|
|
2928
|
+
* the space isn't connected (ephemeral signals aren't worth queuing).
|
|
2929
|
+
*/
|
|
2930
|
+
sendEphemeral(subject: string, data: unknown): void;
|
|
2931
|
+
/** Subscribe to inbound ephemeral signals. `from` is the authenticated sender. */
|
|
2932
|
+
onEphemeral(handler: (e: EphemeralEvent) => void): () => void;
|
|
2718
2933
|
/** Subscribe to inbound join requests (for a key-holder to admit). */
|
|
2719
2934
|
onJoinRequest(handler: (req: JoinRequest) => void): () => void;
|
|
2720
2935
|
/**
|
|
@@ -2747,7 +2962,9 @@ declare class Space {
|
|
|
2747
2962
|
memberId: string;
|
|
2748
2963
|
identityEcdhPub: string;
|
|
2749
2964
|
}>): Promise<number>;
|
|
2750
|
-
putFile(file: File | Blob | Uint8Array, metadata: SpaceFileMetadata
|
|
2965
|
+
putFile(file: File | Blob | Uint8Array, metadata: SpaceFileMetadata, opts?: {
|
|
2966
|
+
onProgress?: (completed: number, total: number) => void;
|
|
2967
|
+
}): Promise<{
|
|
2751
2968
|
manifest: FileManifest;
|
|
2752
2969
|
stat: FileStat;
|
|
2753
2970
|
}>;
|
|
@@ -2759,10 +2976,18 @@ declare class Space {
|
|
|
2759
2976
|
/** Wire the RAW_FRAME handler that drives fan-out events. */
|
|
2760
2977
|
private wireFanout;
|
|
2761
2978
|
private onRawFrame;
|
|
2979
|
+
/**
|
|
2980
|
+
* Seal `payload` once with the current group key + sign it, returning the
|
|
2981
|
+
* serialized `Packet` string. Shared by send (a new message) and edit
|
|
2982
|
+
* (replacement content for an existing handle). Requires a keyring.
|
|
2983
|
+
*/
|
|
2984
|
+
private sealMessage;
|
|
2762
2985
|
/**
|
|
2763
2986
|
* Decode one persisted/broadcast frame into a SpaceMessageEvent.
|
|
2764
2987
|
* `isRawFrame` true means `input` is the already-extracted `spaceMessage`
|
|
2765
|
-
* packet string
|
|
2988
|
+
* packet string (and `serverTs` carries the message's storage handle from
|
|
2989
|
+
* the enclosing frame); false means `input` is the full
|
|
2990
|
+
* `{spaceMessage, name, timestamp}` frame and the handle is read from it.
|
|
2766
2991
|
*/
|
|
2767
2992
|
private decodeFrame;
|
|
2768
2993
|
/**
|
|
@@ -2945,6 +3170,40 @@ declare class SpaceNamespace {
|
|
|
2945
3170
|
joinChannel(name: string, opts?: {
|
|
2946
3171
|
timeoutMs?: number;
|
|
2947
3172
|
}): Promise<Space>;
|
|
3173
|
+
/** Mint a shareable invite link for a space. `opts.expiresInSec` / `maxUses`
|
|
3174
|
+
* bound it (0/undefined = unlimited); `opts.role` ("viewer"|"editor") is the
|
|
3175
|
+
* access granted to redeemers (default viewer). Returns the link. */
|
|
3176
|
+
createInviteLink(spaceId: string, opts?: {
|
|
3177
|
+
expiresInSec?: number;
|
|
3178
|
+
maxUses?: number;
|
|
3179
|
+
role?: string;
|
|
3180
|
+
}): Promise<InviteLink>;
|
|
3181
|
+
/** Set a member's role on a space ("viewer" | "editor"). Owner-only. */
|
|
3182
|
+
setMemberRole(spaceId: string, username: string, role: string): Promise<void>;
|
|
3183
|
+
/** Roster with roles (owner/members only). */
|
|
3184
|
+
members(spaceId: string): Promise<Array<{
|
|
3185
|
+
memberId: string;
|
|
3186
|
+
role: string;
|
|
3187
|
+
}>>;
|
|
3188
|
+
/** List a space's active invite links (creator/members only). */
|
|
3189
|
+
listInviteLinks(spaceId: string): Promise<InviteLink[]>;
|
|
3190
|
+
/** Revoke an invite link by token. */
|
|
3191
|
+
revokeInviteLink(spaceId: string, token: string): Promise<void>;
|
|
3192
|
+
/**
|
|
3193
|
+
* Join a space using an invite link: redeem the token (the keeper admits
|
|
3194
|
+
* this member), then connect and resolve once the group key arrives.
|
|
3195
|
+
* Returns the open {@link Space}.
|
|
3196
|
+
*/
|
|
3197
|
+
joinByInvite(spaceId: string, token: string, opts?: {
|
|
3198
|
+
timeoutMs?: number;
|
|
3199
|
+
}): Promise<Space>;
|
|
3200
|
+
/** The current member roster of a space (member id → identity public keys). */
|
|
3201
|
+
roster(spaceId: string): Promise<Array<{
|
|
3202
|
+
memberId: string;
|
|
3203
|
+
identityEcdhPub: string;
|
|
3204
|
+
identityEcdsaPub?: string;
|
|
3205
|
+
}>>;
|
|
3206
|
+
private keyringFor;
|
|
2948
3207
|
private build;
|
|
2949
3208
|
/** Ensure the member has an identity keypair; return its public ECDH + ECDSA keys. */
|
|
2950
3209
|
private ensureIdentity;
|
|
@@ -2953,6 +3212,236 @@ declare class SpaceNamespace {
|
|
|
2953
3212
|
private myId;
|
|
2954
3213
|
}
|
|
2955
3214
|
|
|
3215
|
+
/**
|
|
3216
|
+
* `client.agents` — manage an app's **Programmable Agents** (server-side
|
|
3217
|
+
* "virtual users" backed by Workers AI).
|
|
3218
|
+
*
|
|
3219
|
+
* const { config } = await client.agents.create(appId, {
|
|
3220
|
+
* handle: '@assistant', displayName: 'Assistant',
|
|
3221
|
+
* systemPrompt: 'You are a helpful teammate in this Space.',
|
|
3222
|
+
* triggers: [{ type: 'mention' }],
|
|
3223
|
+
* });
|
|
3224
|
+
* await client.agents.enable(appId, config.agentId, spaceId); // per-Space opt-in
|
|
3225
|
+
*
|
|
3226
|
+
* These are MANAGEMENT calls — the agent itself runs on the accelerator. Only an
|
|
3227
|
+
* app's owner or an editor of its shared Space may create/update/enable an agent
|
|
3228
|
+
* (viewers can read). Authorization rides the user session token; non-owner
|
|
3229
|
+
* editors pass their management Space via `opts.space`.
|
|
3230
|
+
*
|
|
3231
|
+
* v1 is "prompts + persona": a system prompt, a model, named prompt `skills`,
|
|
3232
|
+
* and `triggers` that decide when the agent speaks. No tools, no code.
|
|
3233
|
+
*/
|
|
3234
|
+
|
|
3235
|
+
type AgentTriggerType = "mention" | "keyword" | "regex" | "always";
|
|
3236
|
+
interface AgentTrigger {
|
|
3237
|
+
type: AgentTriggerType;
|
|
3238
|
+
/** Required for `keyword` (case-insensitive substring) and `regex`. */
|
|
3239
|
+
pattern?: string;
|
|
3240
|
+
/** Name of a {@link AgentSkill} to run on match. */
|
|
3241
|
+
skill?: string;
|
|
3242
|
+
}
|
|
3243
|
+
interface AgentSkill {
|
|
3244
|
+
name: string;
|
|
3245
|
+
prompt: string;
|
|
3246
|
+
}
|
|
3247
|
+
interface AgentConfig {
|
|
3248
|
+
agentId: string;
|
|
3249
|
+
/** @-mention target, e.g. "@assistant". */
|
|
3250
|
+
handle: string;
|
|
3251
|
+
displayName: string;
|
|
3252
|
+
model: string;
|
|
3253
|
+
systemPrompt: string;
|
|
3254
|
+
skills: AgentSkill[];
|
|
3255
|
+
triggers: AgentTrigger[];
|
|
3256
|
+
/** Space ids this agent is enabled on (per-Space opt-in). */
|
|
3257
|
+
enabledSpaces: string[];
|
|
3258
|
+
caps: {
|
|
3259
|
+
dailyTokenBudget: number;
|
|
3260
|
+
};
|
|
3261
|
+
createdAt: number;
|
|
3262
|
+
updatedAt: number;
|
|
3263
|
+
}
|
|
3264
|
+
/** The editor-settable fields when creating an agent. */
|
|
3265
|
+
interface AgentCreateInput {
|
|
3266
|
+
handle: string;
|
|
3267
|
+
displayName: string;
|
|
3268
|
+
systemPrompt: string;
|
|
3269
|
+
model?: string;
|
|
3270
|
+
skills?: AgentSkill[];
|
|
3271
|
+
triggers?: AgentTrigger[];
|
|
3272
|
+
caps?: {
|
|
3273
|
+
dailyTokenBudget: number;
|
|
3274
|
+
};
|
|
3275
|
+
}
|
|
3276
|
+
type AgentUpdateInput = Partial<AgentCreateInput>;
|
|
3277
|
+
/** Create/get response — the config plus the agent's published identity keys. */
|
|
3278
|
+
interface AgentProvisioned {
|
|
3279
|
+
config: AgentConfig;
|
|
3280
|
+
/** The agent's Space member id (`__agent__:<agentId>`). */
|
|
3281
|
+
memberId: string;
|
|
3282
|
+
/** base64url-JWK identity ECDH public key (null until provisioned). */
|
|
3283
|
+
ecdhPub: string | null;
|
|
3284
|
+
/** base64url-JWK identity ECDSA public key — verifies the agent's messages. */
|
|
3285
|
+
ecdsaPub: string | null;
|
|
3286
|
+
}
|
|
3287
|
+
interface AgentsNamespaceDeps {
|
|
3288
|
+
http: HttpClient;
|
|
3289
|
+
}
|
|
3290
|
+
/** Common option: a management Space for delegated (non-owner) access. */
|
|
3291
|
+
interface AgentScopeOpts {
|
|
3292
|
+
space?: string;
|
|
3293
|
+
}
|
|
3294
|
+
declare class AgentsNamespace {
|
|
3295
|
+
private readonly deps;
|
|
3296
|
+
constructor(deps: AgentsNamespaceDeps);
|
|
3297
|
+
/** List the app's agents. */
|
|
3298
|
+
list(appId: string, opts?: AgentScopeOpts): Promise<AgentConfig[]>;
|
|
3299
|
+
/** Read one agent (config + identity keys). */
|
|
3300
|
+
get(appId: string, agentId: string, opts?: AgentScopeOpts): Promise<AgentProvisioned>;
|
|
3301
|
+
/** Create an agent (owner/editor only). */
|
|
3302
|
+
create(appId: string, input: AgentCreateInput, opts?: AgentScopeOpts): Promise<AgentProvisioned>;
|
|
3303
|
+
/** Update an agent's editor-settable fields (owner/editor only). */
|
|
3304
|
+
update(appId: string, agentId: string, patch: AgentUpdateInput, opts?: AgentScopeOpts): Promise<{
|
|
3305
|
+
config: AgentConfig;
|
|
3306
|
+
}>;
|
|
3307
|
+
/** Delete an agent (owner/editor only). */
|
|
3308
|
+
delete(appId: string, agentId: string, opts?: AgentScopeOpts): Promise<{
|
|
3309
|
+
deleted: boolean;
|
|
3310
|
+
}>;
|
|
3311
|
+
/** Enable the agent on a Space (per-Space opt-in). */
|
|
3312
|
+
enable(appId: string, agentId: string, spaceId: string, opts?: AgentScopeOpts): Promise<{
|
|
3313
|
+
config: AgentConfig;
|
|
3314
|
+
}>;
|
|
3315
|
+
/** Disable the agent on a Space. */
|
|
3316
|
+
disable(appId: string, agentId: string, spaceId: string, opts?: AgentScopeOpts): Promise<{
|
|
3317
|
+
config: AgentConfig;
|
|
3318
|
+
}>;
|
|
3319
|
+
private path;
|
|
3320
|
+
}
|
|
3321
|
+
|
|
3322
|
+
/**
|
|
3323
|
+
* `client.functions` — manage an app's **serverless functions** (developer-
|
|
3324
|
+
* authored code that runs on the accelerator).
|
|
3325
|
+
*
|
|
3326
|
+
* const { config } = await client.functions.deploy(appId, {
|
|
3327
|
+
* name: 'hello', displayName: 'Hello',
|
|
3328
|
+
* code: `export default { fetch: () => new Response('hi') }`,
|
|
3329
|
+
* triggers: { http: { enabled: true } },
|
|
3330
|
+
* });
|
|
3331
|
+
* // HTTP-reachable at hello--<slug>.fns.muhkoo.dev
|
|
3332
|
+
* await client.functions.enable(appId, config.functionId, spaceId); // Space-bound
|
|
3333
|
+
*
|
|
3334
|
+
* These are MANAGEMENT calls — the function itself runs on the accelerator
|
|
3335
|
+
* (uploaded just-in-time, decrypted only at invocation). Only an app's owner or
|
|
3336
|
+
* an editor of its shared Space may deploy/update/enable (viewers read).
|
|
3337
|
+
* Authorization rides the user session token; non-owner editors pass their
|
|
3338
|
+
* management Space via `opts.space`.
|
|
3339
|
+
*
|
|
3340
|
+
* v1 is "compute-only": a function is an untrusted single-module ES worker
|
|
3341
|
+
* (`export default { fetch }`) with NO platform bindings — it reaches the
|
|
3342
|
+
* platform as an external client (the end-user session is passed through). Two
|
|
3343
|
+
* triggers: `http` (its own subdomain) and `space` (invoked on Space messages,
|
|
3344
|
+
* like a Programmable Agent).
|
|
3345
|
+
*/
|
|
3346
|
+
|
|
3347
|
+
type FunctionTriggerType = "keyword" | "regex" | "always";
|
|
3348
|
+
interface FunctionTrigger {
|
|
3349
|
+
type: FunctionTriggerType;
|
|
3350
|
+
/** Required for `keyword` (case-insensitive substring) and `regex`. */
|
|
3351
|
+
pattern?: string;
|
|
3352
|
+
}
|
|
3353
|
+
interface FunctionTriggers {
|
|
3354
|
+
/** HTTP-invocable at `<name>--<slug>.fns.<zone>`. */
|
|
3355
|
+
http?: {
|
|
3356
|
+
enabled: boolean;
|
|
3357
|
+
methods?: string[];
|
|
3358
|
+
};
|
|
3359
|
+
/** Invoked on matching Space messages (per-Space opt-in via enable). */
|
|
3360
|
+
space?: {
|
|
3361
|
+
match: FunctionTrigger[];
|
|
3362
|
+
};
|
|
3363
|
+
}
|
|
3364
|
+
interface FunctionCaps {
|
|
3365
|
+
/** Per-invocation CPU ceiling (ms). */
|
|
3366
|
+
cpuMs: number;
|
|
3367
|
+
/** Per-invocation subrequest ceiling. */
|
|
3368
|
+
subRequests: number;
|
|
3369
|
+
/** Hard daily invocation cap (0 = unlimited). */
|
|
3370
|
+
dailyInvocationBudget: number;
|
|
3371
|
+
}
|
|
3372
|
+
interface FunctionConfig {
|
|
3373
|
+
functionId: string;
|
|
3374
|
+
/** DNS-safe slug — the function's subdomain label + WfP script name part. */
|
|
3375
|
+
name: string;
|
|
3376
|
+
displayName: string;
|
|
3377
|
+
triggers: FunctionTriggers;
|
|
3378
|
+
/** Space ids this function is enabled on (per-Space opt-in for `space`). */
|
|
3379
|
+
enabledSpaces: string[];
|
|
3380
|
+
caps: FunctionCaps;
|
|
3381
|
+
scriptName: string;
|
|
3382
|
+
/** sha-256 of the last-deployed source. */
|
|
3383
|
+
codeHash?: string;
|
|
3384
|
+
/** When the source was last (re)deployed. */
|
|
3385
|
+
deployedAt?: number;
|
|
3386
|
+
createdAt: number;
|
|
3387
|
+
updatedAt: number;
|
|
3388
|
+
}
|
|
3389
|
+
/** The editor-settable fields when deploying a function. */
|
|
3390
|
+
interface FunctionDeployInput {
|
|
3391
|
+
name: string;
|
|
3392
|
+
displayName: string;
|
|
3393
|
+
/** Raw single-module ES worker source (`export default { fetch }`). */
|
|
3394
|
+
code: string;
|
|
3395
|
+
triggers?: FunctionTriggers;
|
|
3396
|
+
caps?: Partial<FunctionCaps>;
|
|
3397
|
+
}
|
|
3398
|
+
/** Update input — any subset, including new `code` to redeploy. */
|
|
3399
|
+
type FunctionUpdateInput = Partial<FunctionDeployInput>;
|
|
3400
|
+
interface FunctionsNamespaceDeps {
|
|
3401
|
+
http: HttpClient;
|
|
3402
|
+
}
|
|
3403
|
+
/** Common option: a management Space for delegated (non-owner) access. */
|
|
3404
|
+
interface FunctionScopeOpts {
|
|
3405
|
+
space?: string;
|
|
3406
|
+
}
|
|
3407
|
+
declare class FunctionsNamespace {
|
|
3408
|
+
private readonly deps;
|
|
3409
|
+
constructor(deps: FunctionsNamespaceDeps);
|
|
3410
|
+
/** List the app's functions. */
|
|
3411
|
+
list(appId: string, opts?: FunctionScopeOpts): Promise<FunctionConfig[]>;
|
|
3412
|
+
/** Read one function's config. */
|
|
3413
|
+
get(appId: string, functionId: string, opts?: FunctionScopeOpts): Promise<{
|
|
3414
|
+
config: FunctionConfig;
|
|
3415
|
+
}>;
|
|
3416
|
+
/** Read a function's decrypted source (owner/editor; for the editor UI). */
|
|
3417
|
+
code(appId: string, functionId: string, opts?: FunctionScopeOpts): Promise<{
|
|
3418
|
+
functionId: string;
|
|
3419
|
+
code: string;
|
|
3420
|
+
codeHash: string | null;
|
|
3421
|
+
}>;
|
|
3422
|
+
/** Deploy (create) a function (owner/editor only). */
|
|
3423
|
+
deploy(appId: string, input: FunctionDeployInput, opts?: FunctionScopeOpts): Promise<{
|
|
3424
|
+
config: FunctionConfig;
|
|
3425
|
+
}>;
|
|
3426
|
+
/** Update a function's editor-settable fields and/or redeploy its `code`. */
|
|
3427
|
+
update(appId: string, functionId: string, patch: FunctionUpdateInput, opts?: FunctionScopeOpts): Promise<{
|
|
3428
|
+
config: FunctionConfig;
|
|
3429
|
+
}>;
|
|
3430
|
+
/** Delete a function (owner/editor only). */
|
|
3431
|
+
delete(appId: string, functionId: string, opts?: FunctionScopeOpts): Promise<{
|
|
3432
|
+
deleted: boolean;
|
|
3433
|
+
}>;
|
|
3434
|
+
/** Enable the function on a Space (per-Space opt-in for the `space` trigger). */
|
|
3435
|
+
enable(appId: string, functionId: string, spaceId: string, opts?: FunctionScopeOpts): Promise<{
|
|
3436
|
+
config: FunctionConfig;
|
|
3437
|
+
}>;
|
|
3438
|
+
/** Disable the function on a Space. */
|
|
3439
|
+
disable(appId: string, functionId: string, spaceId: string, opts?: FunctionScopeOpts): Promise<{
|
|
3440
|
+
config: FunctionConfig;
|
|
3441
|
+
}>;
|
|
3442
|
+
private path;
|
|
3443
|
+
}
|
|
3444
|
+
|
|
2956
3445
|
/** The hosted Muhkoo Accelerator — the default {@link ClientOptions.baseUrl}. */
|
|
2957
3446
|
declare const DEFAULT_BASE_URL = "https://api.muhkoo.dev";
|
|
2958
3447
|
interface ClientOptions {
|
|
@@ -2990,19 +3479,48 @@ declare class Client {
|
|
|
2990
3479
|
readonly baseUrl: string;
|
|
2991
3480
|
/** Authentication — `client.auth.zk.login(...)`, etc. */
|
|
2992
3481
|
readonly auth: AuthNamespace;
|
|
2993
|
-
/** Per-user
|
|
3482
|
+
/** Per-user key/value storage — `client.kv.set(...)`, etc. */
|
|
3483
|
+
readonly kv: KvNamespace;
|
|
3484
|
+
/** File storage — `client.storage.writeFile(...)`, etc. */
|
|
2994
3485
|
readonly storage: StorageNamespace;
|
|
2995
3486
|
/** Realtime messaging — `client.message.subscribe(...)`, etc. */
|
|
2996
3487
|
readonly message: MessageNamespace;
|
|
2997
3488
|
/** Fan-out group spaces — `client.space.createSpace(...)`, etc. */
|
|
2998
3489
|
readonly space: SpaceNamespace;
|
|
3490
|
+
/** Programmable Agents — `client.agents.create(appId, …)`, etc. */
|
|
3491
|
+
readonly agents: AgentsNamespace;
|
|
3492
|
+
/** Serverless functions — `client.functions.deploy(appId, …)`, etc. */
|
|
3493
|
+
readonly functions: FunctionsNamespace;
|
|
2999
3494
|
private readonly session;
|
|
3000
3495
|
private readonly http;
|
|
3496
|
+
/** Subscribers notified when a session expires and can't be recovered. */
|
|
3497
|
+
private readonly sessionExpiredHandlers;
|
|
3498
|
+
/** Shared in-flight recovery so a burst of 401s triggers one re-auth. */
|
|
3499
|
+
private recoverInFlight;
|
|
3001
3500
|
constructor(options?: ClientOptions);
|
|
3002
3501
|
/** The currently signed-in user, or `null`. */
|
|
3003
3502
|
get user(): AuthUser | null;
|
|
3004
3503
|
/** Whether a token-bearing session is active. */
|
|
3005
3504
|
get isAuthenticated(): boolean;
|
|
3505
|
+
/**
|
|
3506
|
+
* Subscribe to session expiry that couldn't be silently recovered (the
|
|
3507
|
+
* user's identity wasn't in memory to re-prove — typically after a reload
|
|
3508
|
+
* where only the token was persisted, and that token has since gone stale).
|
|
3509
|
+
* This is the signal to send the user back to the login screen.
|
|
3510
|
+
*
|
|
3511
|
+
* Returns an unsubscribe function.
|
|
3512
|
+
*
|
|
3513
|
+
* const off = client.onSessionExpired(() => router.push('/login'));
|
|
3514
|
+
*/
|
|
3515
|
+
onSessionExpired(handler: () => void): () => void;
|
|
3516
|
+
/**
|
|
3517
|
+
* Attempt a silent re-auth of the current user. Concurrent callers share a
|
|
3518
|
+
* single in-flight attempt (a stale token usually 401s several requests at
|
|
3519
|
+
* once — we re-auth once, not once per request). On failure the
|
|
3520
|
+
* session-expired event fires so the app can react. Exposed so apps can
|
|
3521
|
+
* also drive recovery proactively (e.g. on `visibilitychange`).
|
|
3522
|
+
*/
|
|
3523
|
+
recoverSession(): Promise<boolean>;
|
|
3006
3524
|
}
|
|
3007
3525
|
|
|
3008
3526
|
/**
|
|
@@ -3040,8 +3558,30 @@ declare class KeyringClient implements KeyringTransport {
|
|
|
3040
3558
|
epoch: number;
|
|
3041
3559
|
}>;
|
|
3042
3560
|
invite(username: string): Promise<void>;
|
|
3561
|
+
createInviteLink(opts?: {
|
|
3562
|
+
expiresInSec?: number;
|
|
3563
|
+
maxUses?: number;
|
|
3564
|
+
role?: string;
|
|
3565
|
+
}): Promise<InviteLink>;
|
|
3566
|
+
listInviteLinks(): Promise<InviteLink[]>;
|
|
3567
|
+
/** Set a member's role ("viewer" | "editor"). Owner-only on the server. */
|
|
3568
|
+
setMemberRole(username: string, role: string): Promise<void>;
|
|
3569
|
+
/** Roster with roles (owner/members only). */
|
|
3570
|
+
members(): Promise<Array<{
|
|
3571
|
+
memberId: string;
|
|
3572
|
+
role: string;
|
|
3573
|
+
}>>;
|
|
3574
|
+
revokeInviteLink(token: string): Promise<void>;
|
|
3575
|
+
/** Redeem a link: the server allowlists this member and asks the keeper to
|
|
3576
|
+
* wrap the group key for their identity. Caller must be authenticated. */
|
|
3577
|
+
redeemInvite(req: {
|
|
3578
|
+
token: string;
|
|
3579
|
+
identityEcdhPub: string;
|
|
3580
|
+
identityEcdsaPub?: string;
|
|
3581
|
+
desiredEpoch?: number;
|
|
3582
|
+
}): Promise<void>;
|
|
3043
3583
|
fetchMetadata(): Promise<SpaceMetadata | null>;
|
|
3044
3584
|
}
|
|
3045
3585
|
|
|
3046
|
-
export { AES_GCM_IV_BYTES, AES_GCM_KEY_BYTES, AES_GCM_TAG_BYTES, AuthClient, AuthNamespace, AuthPublicInput, Authenticator, BroadcastChannel, BroadcastChannelEvents, ChannelExistsError, ChannelNotFoundError, ChunkCipher, Client, DEFAULT_BASE_URL, DoubleRatchet, DoubleRatchetCipher, DoubleRatchetManager, EncryptedSession, EventCore, EventCoreEvents, Field, Field as FieldElement, FileStorage, HashKnowledge, HttpClient, HttpError, KEEPER_MEMBER_ID, KeyStore, KeyringClient, LocalStorageSessionStore, MemorySessionStore, Message, Message as MessageDefault, MessageNamespace, PBKDF2_DEFAULT_ITERATIONS, PREIMAGE_POK_VERIFICATION_KEY, Packet, PersonalSpaceClient, Poseidon, PreimagePoK, ReedSolomonCodec, Space as Room, SerializeMessage, SessionState, ShardClient, SharedSpaceClient, Space, SpaceKeyring, SpaceNamespace, SpacePacketCipher, StorageNamespace, WSTransport, ZkAuth, buildCommitment, compilePrograms, decodeFromHex, decorators, decryptAesGcm, defaultCircuitUrls, defaultSessionStore, deriveAesKeyFromPassphrase, deriveBitsHkdf, deriveIdentity, encodeToHex, encryptAesGcm, exportPublicKeyBase64, exportPublicKeyHex, generateAuthProof, getSubtle, initBn128Wasm, initRsWasm, initializeCircuits, manifestToStat, poseidonHash, quickVerify, randomBytes, shardHash, signMessage, toField, unwrapWithPassphrase, verify, verifyGroth16, verifyHashKnowledge, verifyPreimagePoK, wrapWithPassphrase };
|
|
3047
|
-
export type { ACL, ACLEntry, AuthClientOptions, AuthKeyPair, AuthSuccess, AuthToken, AuthType, AuthUser, Bn128WasmInstance, BroadcastChannelEvent, BroadcastChannelOptions, ChannelLike, ChunkKeyMaterial, ChunkManifest, CipherFrame, CipherMessage, CipherMessageHeader, CircuitBufferConfig, CircuitUrls, ClientOptions, DehydratedKeypair, DehydratedKeys, DoubleRatchetCipherDeps, ECDHCurve, EncodeResult, EpochKeyProvider, FileManifest, FileStat, FileStorageOptions, Groth16Proof, HttpClientOptions, IncomingFrame, KeyExchangeFrame, KeyPair, Keypair, KeyringClientDeps, KeyringTransport, LoginOptions, MessageBody, MessageEvent, MessageHeaders, MessageNamespaceDeps, MessageOptions, MessageSubscription, MuhkooMessageEvent, OAuthProvider, PacketCipher, PacketHeaders, PacketOptions, Participant, Permission, PermissionCheckRequest, PermissionCheckResult, PersonalSpaceClientOptions, PublicKeyJWK, RatchetState, ReceiveResult, RegisterParams, Role, SpaceDeps as RoomDeps, SpaceFileMetadata as RoomFileMetadata, SealedHeaders, Session, SessionOptions, SessionStore, SetOptions, ShardClientOptions, SharedSpaceClientOptions, SnarkProof, SpaceChannelLike, SpaceDeps, SpaceFileMetadata, SpaceKeyCache, SpaceKeyringDeps, SpaceMessageEvent, SpaceNamespaceDeps, StorageChangeEvent,
|
|
3586
|
+
export { AES_GCM_IV_BYTES, AES_GCM_KEY_BYTES, AES_GCM_TAG_BYTES, AgentsNamespace, AuthClient, AuthNamespace, AuthPublicInput, Authenticator, BroadcastChannel, BroadcastChannelEvents, ChannelExistsError, ChannelNotFoundError, ChunkCipher, Client, DEFAULT_BASE_URL, DoubleRatchet, DoubleRatchetCipher, DoubleRatchetManager, EncryptedSession, EventCore, EventCoreEvents, Field, Field as FieldElement, FileStorage, FunctionsNamespace, HashKnowledge, HttpClient, HttpError, KEEPER_MEMBER_ID, KeyStore, KeyringClient, KvNamespace, LocalStorageSessionStore, MemorySessionStore, Message, Message as MessageDefault, MessageNamespace, PBKDF2_DEFAULT_ITERATIONS, PREIMAGE_POK_VERIFICATION_KEY, Packet, PersonalSpaceClient, Poseidon, PreimagePoK, ReedSolomonCodec, Space as Room, SerializeMessage, SessionState, ShardClient, SharedSpaceClient, Space, SpaceKeyring, SpaceNamespace, SpacePacketCipher, StorageNamespace, WSTransport, ZkAuth, buildCommitment, compilePrograms, decodeFromHex, decorators, decryptAesGcm, defaultCircuitUrls, defaultSessionStore, deriveAesKeyFromPassphrase, deriveBitsHkdf, deriveIdentity, encodeToHex, encryptAesGcm, exportPublicKeyBase64, exportPublicKeyHex, generateAuthProof, getSubtle, initBn128Wasm, initRsWasm, initializeCircuits, manifestToStat, poseidonHash, quickVerify, randomBytes, shardHash, signMessage, toField, unwrapWithPassphrase, verify, verifyGroth16, verifyHashKnowledge, verifyPreimagePoK, wrapWithPassphrase };
|
|
3587
|
+
export type { ACL, ACLEntry, AgentConfig, AgentCreateInput, AgentProvisioned, AgentScopeOpts, AgentSkill, AgentTrigger, AgentTriggerType, AgentUpdateInput, AgentsNamespaceDeps, AuthClientOptions, AuthKeyPair, AuthSuccess, AuthToken, AuthType, AuthUser, Bn128WasmInstance, BroadcastChannelEvent, BroadcastChannelOptions, ChannelLike, ChunkKeyMaterial, ChunkManifest, CipherFrame, CipherMessage, CipherMessageHeader, CircuitBufferConfig, CircuitUrls, ClientOptions, DehydratedKeypair, DehydratedKeys, DoubleRatchetCipherDeps, ECDHCurve, EncodeResult, EphemeralEvent, EpochKeyProvider, FileManifest, FileNamespaceDeps, FileStat, FileStorageOptions, FunctionCaps, FunctionConfig, FunctionDeployInput, FunctionScopeOpts, FunctionTrigger, FunctionTriggerType, FunctionTriggers, FunctionUpdateInput, FunctionsNamespaceDeps, Groth16Proof, HttpClientOptions, IncomingFrame, KeyExchangeFrame, KeyPair, Keypair, KeyringClientDeps, KeyringTransport, KvNamespaceDeps, LoginOptions, MessageBody, MessageDeletedEvent, MessageEvent, MessageHeaders, MessageNamespaceDeps, MessageOptions, MessageSubscription, MuhkooMessageEvent, OAuthProvider, PacketCipher, PacketHeaders, PacketOptions, Participant, Permission, PermissionCheckRequest, PermissionCheckResult, PersonalSpaceClientOptions, PublicKeyJWK, RatchetState, ReceiveResult, RegisterParams, Role, SpaceDeps as RoomDeps, SpaceFileMetadata as RoomFileMetadata, SealedHeaders, Session, SessionOptions, SessionStore, SetOptions, ShardClientOptions, SharedSpaceClientOptions, SnarkProof, SpaceChannelLike, SpaceDeps, SpaceFileMetadata, SpaceKeyCache, SpaceKeyringDeps, SpaceMessageEvent, SpaceNamespaceDeps, StorageChangeEvent, StoredSession, Subscription, UserIdentity, VerificationKey, WSMessage, WSMessageType, WSTransportOptions, WrappedPayload, WriteFileInput, WriteFileOptions, WriteToShardsInput, ZkAuthDeps, ZkAuthenticateRequest, ZkChallengeResponse, ZkCompiled, ZkIdentity, ZkRegisterRequest, ZkRegisterResponse };
|