@muhkoo/connect 0.8.0-alpha.0 → 0.9.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/blockEngine.worker.js +349 -0
- package/dist/browser/blockEngine.worker.js.map +1 -0
- package/dist/browser/index.js +909 -80
- package/dist/browser/index.js.map +1 -1
- package/dist/connect.d.ts +445 -3
- package/dist/server/index.js +909 -80
- package/dist/server/index.js.map +1 -1
- package/package.json +5 -2
package/dist/connect.d.ts
CHANGED
|
@@ -1415,6 +1415,18 @@ interface ShardByteCache {
|
|
|
1415
1415
|
get(hash: string): Promise<Uint8Array | null>;
|
|
1416
1416
|
put(hash: string, bytes: Uint8Array): Promise<void>;
|
|
1417
1417
|
}
|
|
1418
|
+
/**
|
|
1419
|
+
* A peer block source (the p2p layer's `PeerExchange` satisfies this
|
|
1420
|
+
* structurally). Consulted between the local cache and origin: a block fetched
|
|
1421
|
+
* from a peer is verified by hash before use. Declared here so the storage layer
|
|
1422
|
+
* doesn't import the p2p module (dependency arrow stays p2p → storage).
|
|
1423
|
+
*/
|
|
1424
|
+
interface PeerBlockSource {
|
|
1425
|
+
getBlock(hash: string, opts?: {
|
|
1426
|
+
timeoutMs?: number;
|
|
1427
|
+
}): Promise<Uint8Array | null>;
|
|
1428
|
+
announce(hash: string): void;
|
|
1429
|
+
}
|
|
1418
1430
|
interface ShardClientOptions {
|
|
1419
1431
|
/** Base URL of the accelerator (e.g. `https://muhkoo-accelerator.workers.dev`). */
|
|
1420
1432
|
baseUrl: string;
|
|
@@ -1446,6 +1458,12 @@ interface ShardClientOptions {
|
|
|
1446
1458
|
* keyed by `hash`, so only the hash needs recording.
|
|
1447
1459
|
*/
|
|
1448
1460
|
deferUpload?: (hash: string) => Promise<void>;
|
|
1461
|
+
/**
|
|
1462
|
+
* Optional peer block source. When present, GETs try peers between the local
|
|
1463
|
+
* cache and origin (peer blocks are verified by hash); PUTs announce the new
|
|
1464
|
+
* block to peers. Best-effort — any failure falls through to origin.
|
|
1465
|
+
*/
|
|
1466
|
+
peers?: PeerBlockSource;
|
|
1449
1467
|
}
|
|
1450
1468
|
/**
|
|
1451
1469
|
* Compute the lowercase hex SHA-256 of `bytes`. Available via WebCrypto in
|
|
@@ -1458,6 +1476,7 @@ declare class ShardClient {
|
|
|
1458
1476
|
private readonly fetchFn;
|
|
1459
1477
|
private readonly cache?;
|
|
1460
1478
|
private readonly deferUpload?;
|
|
1479
|
+
private readonly peers?;
|
|
1461
1480
|
constructor(opts: ShardClientOptions);
|
|
1462
1481
|
/** Build the URL for a given shard hash — exposed for callers that want to log or pre-resolve. */
|
|
1463
1482
|
urlForHash(hash: string): string;
|
|
@@ -3775,6 +3794,19 @@ declare class SpaceKeyring implements EpochKeyProvider {
|
|
|
3775
3794
|
*/
|
|
3776
3795
|
|
|
3777
3796
|
type Listener = (e: CustomEvent) => void;
|
|
3797
|
+
/**
|
|
3798
|
+
* A P2P swarm attached to a Space (the p2p layer's `PeerNetwork` satisfies this
|
|
3799
|
+
* structurally — Space never imports the p2p module). `exchange` is consulted by
|
|
3800
|
+
* the Space's file `ShardClient`; `start` runs peer discovery on connect; `close`
|
|
3801
|
+
* tears the mesh down.
|
|
3802
|
+
*/
|
|
3803
|
+
interface AttachedPeerNetwork {
|
|
3804
|
+
readonly exchange: PeerBlockSource;
|
|
3805
|
+
start(): void;
|
|
3806
|
+
close(): void;
|
|
3807
|
+
gossip(data: Uint8Array): void;
|
|
3808
|
+
onGossip(cb: (from: string, data: Uint8Array) => void): () => void;
|
|
3809
|
+
}
|
|
3778
3810
|
interface SpaceFileMetadata {
|
|
3779
3811
|
name: string;
|
|
3780
3812
|
type: string;
|
|
@@ -3914,6 +3946,8 @@ declare class Space {
|
|
|
3914
3946
|
private readonly events;
|
|
3915
3947
|
private rawWired;
|
|
3916
3948
|
private catchUpUnsub;
|
|
3949
|
+
/** Optional P2P swarm for this Space (block exchange among members). */
|
|
3950
|
+
private peerNet;
|
|
3917
3951
|
constructor(deps: SpaceDeps);
|
|
3918
3952
|
/** The encoded space id (same as the transport name for fan-out spaces). */
|
|
3919
3953
|
get id(): string;
|
|
@@ -3922,6 +3956,19 @@ declare class Space {
|
|
|
3922
3956
|
/** Open the space websocket (resolves the ticket + identity lazily). */
|
|
3923
3957
|
connect(): Promise<void>;
|
|
3924
3958
|
disconnect(): void;
|
|
3959
|
+
/** Attach a P2P swarm so this Space's file reads/writes can use peers. */
|
|
3960
|
+
attachPeerNetwork(net: AttachedPeerNetwork): void;
|
|
3961
|
+
/**
|
|
3962
|
+
* Broadcast an app payload directly to connected Space peers over P2P,
|
|
3963
|
+
* **bypassing the server** — for CRDT ops / high-frequency state (live
|
|
3964
|
+
* cursors, presence, collaborative edits) you don't want to push through the
|
|
3965
|
+
* relay. No-op when no P2P mesh is active (requires `client` `p2p`).
|
|
3966
|
+
* Unlike {@link sendEphemeral} (server-relayed, metered, size-limited), this
|
|
3967
|
+
* is peer-direct and fragments large payloads.
|
|
3968
|
+
*/
|
|
3969
|
+
gossipToPeers(data: Uint8Array): void;
|
|
3970
|
+
/** Subscribe to peer gossip ({@link gossipToPeers}). Returns an unsubscribe fn. */
|
|
3971
|
+
onPeerGossip(handler: (from: string, data: Uint8Array) => void): () => void;
|
|
3925
3972
|
/** Subscribe to a raw channel event. Buffered until `connect()` if early. */
|
|
3926
3973
|
on(event: string, handler: Listener): void;
|
|
3927
3974
|
off(event: string, handler: Listener): void;
|
|
@@ -3982,7 +4029,7 @@ declare class Space {
|
|
|
3982
4029
|
* indicators, presence, or live cursors are built on top of this. No-op if
|
|
3983
4030
|
* the space isn't connected (ephemeral signals aren't worth queuing).
|
|
3984
4031
|
*/
|
|
3985
|
-
sendEphemeral(subject: string, data: unknown): void;
|
|
4032
|
+
sendEphemeral(subject: string, data: unknown, to?: string): void;
|
|
3986
4033
|
/** Subscribe to inbound ephemeral signals. `from` is the authenticated sender. */
|
|
3987
4034
|
onEphemeral(handler: (e: EphemeralEvent) => void): () => void;
|
|
3988
4035
|
/** Subscribe to inbound join requests (for a key-holder to admit). */
|
|
@@ -4195,6 +4242,14 @@ interface SpaceNamespaceDeps {
|
|
|
4195
4242
|
cache?: SpaceKeyCache;
|
|
4196
4243
|
/** Offline manager — enables message caching + offline send replay. */
|
|
4197
4244
|
offline?: OfflineManager;
|
|
4245
|
+
/** P2P swarm config — enables peer block exchange among Space members. */
|
|
4246
|
+
p2p?: {
|
|
4247
|
+
enabled?: boolean;
|
|
4248
|
+
/** `() => new Worker(new URL(...))` to run the block engine off-thread. */
|
|
4249
|
+
workerFactory?: () => Worker;
|
|
4250
|
+
iceServers?: RTCIceServer[];
|
|
4251
|
+
maxPeers?: number;
|
|
4252
|
+
};
|
|
4198
4253
|
}
|
|
4199
4254
|
declare class SpaceNamespace {
|
|
4200
4255
|
private readonly deps;
|
|
@@ -4661,6 +4716,18 @@ interface ClientOptions {
|
|
|
4661
4716
|
/** Soft cap on durable-queue bytes before degrading to online-only. */
|
|
4662
4717
|
maxQueueBytes?: number;
|
|
4663
4718
|
};
|
|
4719
|
+
/**
|
|
4720
|
+
* Peer-to-peer block exchange (`client.space` files) among Space members,
|
|
4721
|
+
* over WebRTC signaled on the Space relay. Best-effort — falls back to
|
|
4722
|
+
* origin. **Opt-in** (browser only). Pass `workerFactory` to run the block
|
|
4723
|
+
* engine off the main thread.
|
|
4724
|
+
*/
|
|
4725
|
+
p2p?: {
|
|
4726
|
+
enabled?: boolean;
|
|
4727
|
+
workerFactory?: () => Worker;
|
|
4728
|
+
iceServers?: RTCIceServer[];
|
|
4729
|
+
maxPeers?: number;
|
|
4730
|
+
};
|
|
4664
4731
|
}
|
|
4665
4732
|
declare class Client {
|
|
4666
4733
|
readonly baseUrl: string;
|
|
@@ -5158,6 +5225,381 @@ declare function writeBeatsTombstone(writeHlc: string, tombstoneHlc: string | nu
|
|
|
5158
5225
|
*/
|
|
5159
5226
|
declare function deleteBeatsWrite(deleteHlc: string, writeHlc: string | null): boolean;
|
|
5160
5227
|
|
|
5228
|
+
/**
|
|
5229
|
+
* `PeerExchange` — the thin façade the storage layer consults to try fetching a
|
|
5230
|
+
* block from peers before falling back to origin. It satisfies the structural
|
|
5231
|
+
* `PeerBlockSource` interface that {@link ../storage/transport/ShardClient}
|
|
5232
|
+
* declares (so storage never imports the p2p module — the dependency arrow stays
|
|
5233
|
+
* one-way, p2p → storage).
|
|
5234
|
+
*
|
|
5235
|
+
* It delegates to an {@link EngineHandle} — either an in-process {@link
|
|
5236
|
+
* ./worker/blockEngine.BlockEngine} or the Web Worker proxy — so the same façade
|
|
5237
|
+
* works whether the block engine runs on the main thread or off it.
|
|
5238
|
+
*/
|
|
5239
|
+
|
|
5240
|
+
/** The subset of a block engine (in-process or worker-proxied) PeerExchange drives. */
|
|
5241
|
+
interface EngineHandle {
|
|
5242
|
+
want(hash: string, timeoutMs: number): Promise<Uint8Array | null>;
|
|
5243
|
+
announce(hash: string): void;
|
|
5244
|
+
}
|
|
5245
|
+
interface PeerExchangeOptions {
|
|
5246
|
+
/** How long to wait for a peer before giving up to origin. Default 2500ms. */
|
|
5247
|
+
timeoutMs?: number;
|
|
5248
|
+
}
|
|
5249
|
+
declare class PeerExchange implements PeerBlockSource {
|
|
5250
|
+
private readonly engine;
|
|
5251
|
+
private readonly timeoutMs;
|
|
5252
|
+
constructor(engine: EngineHandle, opts?: PeerExchangeOptions);
|
|
5253
|
+
getBlock(hash: string, opts?: {
|
|
5254
|
+
timeoutMs?: number;
|
|
5255
|
+
}): Promise<Uint8Array | null>;
|
|
5256
|
+
announce(hash: string): void;
|
|
5257
|
+
}
|
|
5258
|
+
|
|
5259
|
+
/**
|
|
5260
|
+
* `SpaceSignaler` — WebRTC signaling carried over the Space's existing ephemeral
|
|
5261
|
+
* relay. No new server channel: `Space.sendEphemeral`/`onEphemeral` already
|
|
5262
|
+
* blind-relay `pub` frames stamped with the authenticated sender, so SDP
|
|
5263
|
+
* offers/answers and ICE candidates ride a reserved subject (`__p2p__`) scoped
|
|
5264
|
+
* to Space membership. The sender (`from`) is server-stamped and can't be
|
|
5265
|
+
* spoofed; the payload is opaque to the server.
|
|
5266
|
+
*
|
|
5267
|
+
* Envelopes carry a `to` (a member id, or `"*"` for discovery) so the
|
|
5268
|
+
* accelerator can optionally unicast peer-pair signaling instead of broadcasting
|
|
5269
|
+
* (a small, backward-compatible `pub` enhancement); the client filters by `to`
|
|
5270
|
+
* regardless.
|
|
5271
|
+
*/
|
|
5272
|
+
declare const P2P_SUBJECT = "__p2p__";
|
|
5273
|
+
type SignalKind = "hello" | "bye" | "offer" | "answer" | "ice";
|
|
5274
|
+
interface SignalEnvelope {
|
|
5275
|
+
/** Target member id, or `"*"` to broadcast (discovery / departure). */
|
|
5276
|
+
to: string;
|
|
5277
|
+
kind: SignalKind;
|
|
5278
|
+
data?: unknown;
|
|
5279
|
+
}
|
|
5280
|
+
/** The slice of {@link ../../spaces/Space.Space} the signaler needs. */
|
|
5281
|
+
interface SignalingSpace {
|
|
5282
|
+
sendEphemeral(subject: string, data: unknown, to?: string): void;
|
|
5283
|
+
onEphemeral(handler: (e: {
|
|
5284
|
+
from: string;
|
|
5285
|
+
subject: string;
|
|
5286
|
+
data: unknown;
|
|
5287
|
+
}) => void): () => void;
|
|
5288
|
+
}
|
|
5289
|
+
declare class SpaceSignaler {
|
|
5290
|
+
private readonly space;
|
|
5291
|
+
private readonly myId;
|
|
5292
|
+
constructor(space: SignalingSpace, myId: string);
|
|
5293
|
+
/** Send a signal to one peer (or `"*"`). */
|
|
5294
|
+
send(to: string, kind: SignalKind, data?: unknown): void;
|
|
5295
|
+
/** Announce/withdraw P2P availability to all Space members. */
|
|
5296
|
+
broadcast(kind: SignalKind, data?: unknown): void;
|
|
5297
|
+
/**
|
|
5298
|
+
* Subscribe to inbound signals addressed to us (or broadcast). Skips our own
|
|
5299
|
+
* echoes. Returns an unsubscribe function.
|
|
5300
|
+
*/
|
|
5301
|
+
onSignal(cb: (from: string, kind: SignalKind, data: unknown) => void): () => void;
|
|
5302
|
+
}
|
|
5303
|
+
|
|
5304
|
+
/**
|
|
5305
|
+
* `PeerTransport` — the pluggable wire under the block engine. It moves opaque
|
|
5306
|
+
* frames between Space peers; it knows nothing about blocks, hashes, or the
|
|
5307
|
+
* protocol. {@link ./WebRtcTransport} implements it over RTCDataChannels today;
|
|
5308
|
+
* a future libp2p/Helia transport can implement the same interface without the
|
|
5309
|
+
* block engine or `ShardClient` changing.
|
|
5310
|
+
*
|
|
5311
|
+
* Implementations are responsible for fragmenting/ reassembling frames larger
|
|
5312
|
+
* than the underlying channel's max message size (a 4 MiB shard won't fit in one
|
|
5313
|
+
* `RTCDataChannel.send`); the engine always deals in whole frames.
|
|
5314
|
+
*/
|
|
5315
|
+
type PeerId = string;
|
|
5316
|
+
interface PeerTransport {
|
|
5317
|
+
/** Currently connected peer ids. */
|
|
5318
|
+
peers(): PeerId[];
|
|
5319
|
+
/** Dial a discovered peer (optional — some transports connect implicitly). */
|
|
5320
|
+
connectTo?(peer: PeerId): void;
|
|
5321
|
+
/** Send a whole frame to one peer on `channel` (fragmented internally if needed). */
|
|
5322
|
+
send(peer: PeerId, data: Uint8Array, channel?: number): void;
|
|
5323
|
+
/** Send a whole frame to every connected peer on `channel`. */
|
|
5324
|
+
broadcast(data: Uint8Array, channel?: number): void;
|
|
5325
|
+
/** Subscribe to inbound (reassembled) frames. Returns an unsubscribe fn. */
|
|
5326
|
+
onMessage(cb: (peer: PeerId, data: Uint8Array, channel: number) => void): () => void;
|
|
5327
|
+
/** Subscribe to the connected-peer set changing. Returns an unsubscribe fn. */
|
|
5328
|
+
onPeerChange(cb: (peers: PeerId[]) => void): () => void;
|
|
5329
|
+
/** Tear down all connections. */
|
|
5330
|
+
close(): void;
|
|
5331
|
+
}
|
|
5332
|
+
|
|
5333
|
+
/**
|
|
5334
|
+
* `BlockEngine` — the bitswap-lite want/have ledger. Host-agnostic: it speaks
|
|
5335
|
+
* only to a {@link BlockStore} (get/put/has) and an `out` sink that ships
|
|
5336
|
+
* encoded frames to a peer (or `"*"` to broadcast). The host wires `out` and
|
|
5337
|
+
* `handleFrame` to a real transport — on the main thread or inside the Web
|
|
5338
|
+
* Worker (see {@link ./engineClient}) — so this class is pure and unit-testable.
|
|
5339
|
+
*
|
|
5340
|
+
* It never sees keys: blocks are AES-GCM ciphertext, addressed by SHA-256. The
|
|
5341
|
+
* one trust check is integrity — an inbound BLOCK is re-hashed and dropped on
|
|
5342
|
+
* mismatch, so a malicious peer can't poison the store (the requester just
|
|
5343
|
+
* falls back to origin).
|
|
5344
|
+
*/
|
|
5345
|
+
interface BlockStore {
|
|
5346
|
+
get(hash: string): Promise<Uint8Array | null>;
|
|
5347
|
+
put(hash: string, bytes: Uint8Array): Promise<void>;
|
|
5348
|
+
has(hash: string): Promise<boolean>;
|
|
5349
|
+
}
|
|
5350
|
+
/** Ship an encoded frame to one peer, or `"*"` for every connected peer. */
|
|
5351
|
+
type OutSink = (target: string | "*", frame: Uint8Array) => void;
|
|
5352
|
+
/** Lowercase hex SHA-256 of `bytes` — injected so tests can stub it. */
|
|
5353
|
+
type Hasher = (bytes: Uint8Array) => Promise<string>;
|
|
5354
|
+
declare class BlockEngine {
|
|
5355
|
+
private readonly store;
|
|
5356
|
+
private readonly out;
|
|
5357
|
+
private readonly hash;
|
|
5358
|
+
private readonly wants;
|
|
5359
|
+
constructor(store: BlockStore, out: OutSink, hash: Hasher);
|
|
5360
|
+
/**
|
|
5361
|
+
* Ask the swarm for a block. Resolves with the verified bytes, or `null` on
|
|
5362
|
+
* timeout (caller then falls back to origin). Returns immediately if we
|
|
5363
|
+
* already hold it; concurrent wants for the same hash share one request.
|
|
5364
|
+
*/
|
|
5365
|
+
want(hash: string, timeoutMs: number): Promise<Uint8Array | null>;
|
|
5366
|
+
/** Tell the swarm we now hold `hash` (so peers wanting it can pull from us). */
|
|
5367
|
+
announce(hash: string): void;
|
|
5368
|
+
/** Handle one inbound frame from `peer`. */
|
|
5369
|
+
handleFrame(peer: string, frame: Uint8Array): Promise<void>;
|
|
5370
|
+
/** Drop all pending waits (resolve null) — on teardown. */
|
|
5371
|
+
close(): void;
|
|
5372
|
+
}
|
|
5373
|
+
|
|
5374
|
+
/**
|
|
5375
|
+
* `PeerNetwork` — the per-Space orchestrator that ties the pieces together on
|
|
5376
|
+
* the main thread:
|
|
5377
|
+
*
|
|
5378
|
+
* transport (WebRTC) ⇄ engine host (Worker or in-process) → PeerExchange
|
|
5379
|
+
* ▲ │
|
|
5380
|
+
* └────────────── signaling over the Space relay ─────────────┘
|
|
5381
|
+
*
|
|
5382
|
+
* It owns one {@link ./transport/WebRtcTransport} + one {@link
|
|
5383
|
+
* ./worker/engineHost.EngineHost}, wires inbound frames to the engine and the
|
|
5384
|
+
* engine's outbound frames back to the transport, runs peer discovery over the
|
|
5385
|
+
* Space's ephemeral channel, and exposes a {@link ./PeerExchange.PeerExchange}
|
|
5386
|
+
* for `ShardClient` to consult. Scope is one Space (private swarm).
|
|
5387
|
+
*
|
|
5388
|
+
* `engineHost` defaults to in-process; pass `workerFactory` to run the block
|
|
5389
|
+
* engine off the main thread (the consumer's bundler resolves the worker URL).
|
|
5390
|
+
*/
|
|
5391
|
+
|
|
5392
|
+
interface PeerNetworkOptions {
|
|
5393
|
+
/** The Space (used for signaling over its ephemeral relay). */
|
|
5394
|
+
space: SignalingSpace;
|
|
5395
|
+
/** Our authenticated member id (the Space's `myId`). */
|
|
5396
|
+
myId: string;
|
|
5397
|
+
/** Blockstore for the in-process engine. Defaults to a `ShardCache`. */
|
|
5398
|
+
store?: BlockStore;
|
|
5399
|
+
/** Run the block engine in a Worker — `() => new Worker(new URL(...))`. */
|
|
5400
|
+
workerFactory?: () => Worker;
|
|
5401
|
+
iceServers?: RTCIceServer[];
|
|
5402
|
+
maxPeers?: number;
|
|
5403
|
+
/** Peer fetch timeout passed to PeerExchange. */
|
|
5404
|
+
timeoutMs?: number;
|
|
5405
|
+
/** Inject a transport (tests / a future libp2p transport). Default WebRTC. */
|
|
5406
|
+
transport?: PeerTransport;
|
|
5407
|
+
}
|
|
5408
|
+
declare class PeerNetwork {
|
|
5409
|
+
/** Pass this to a `ShardClient` as `peers`. */
|
|
5410
|
+
readonly exchange: PeerExchange;
|
|
5411
|
+
private readonly transport;
|
|
5412
|
+
private readonly host;
|
|
5413
|
+
private readonly signaler;
|
|
5414
|
+
private readonly offs;
|
|
5415
|
+
private readonly gossipCbs;
|
|
5416
|
+
private closed;
|
|
5417
|
+
constructor(opts: PeerNetworkOptions);
|
|
5418
|
+
/**
|
|
5419
|
+
* Begin peer discovery — broadcast a hello so existing members dial us and
|
|
5420
|
+
* we learn them. Call once the signaling channel is live (the Space fires
|
|
5421
|
+
* this on CONNECTED); safe to call again on reconnect.
|
|
5422
|
+
*/
|
|
5423
|
+
start(): void;
|
|
5424
|
+
/**
|
|
5425
|
+
* Broadcast an app payload to all connected peers over the gossip channel —
|
|
5426
|
+
* a direct, server-bypassing data path for CRDT ops / high-frequency state
|
|
5427
|
+
* (cursors, presence, collaborative edits). Single-hop (no re-forwarding).
|
|
5428
|
+
*/
|
|
5429
|
+
gossip(data: Uint8Array): void;
|
|
5430
|
+
/** Subscribe to gossip from peers. Returns an unsubscribe function. */
|
|
5431
|
+
onGossip(cb: (from: string, data: Uint8Array) => void): () => void;
|
|
5432
|
+
/** Connected peer count (open data channels). */
|
|
5433
|
+
peerCount(): number;
|
|
5434
|
+
close(): void;
|
|
5435
|
+
}
|
|
5436
|
+
|
|
5437
|
+
/**
|
|
5438
|
+
* Whether this environment can do WebRTC peering. `RTCPeerConnection` is
|
|
5439
|
+
* Window-only (absent in Node/Workers/SSR), so this gates whether a
|
|
5440
|
+
* {@link ./PeerNetwork} can be built at all.
|
|
5441
|
+
*/
|
|
5442
|
+
declare function isP2pCapable(): boolean;
|
|
5443
|
+
|
|
5444
|
+
/**
|
|
5445
|
+
* `WebRtcTransport` — a {@link ./PeerTransport.PeerTransport} over RTCDataChannels,
|
|
5446
|
+
* signaled by {@link ../signaling/SpaceSignaler}. Runs on the **main thread**
|
|
5447
|
+
* (`RTCPeerConnection` is Window-only — not available in Workers), so the block
|
|
5448
|
+
* engine lives in a Worker and this only shuttles bytes.
|
|
5449
|
+
*
|
|
5450
|
+
* Connection setup uses a deterministic initiator (the peer with the smaller id
|
|
5451
|
+
* dials) to avoid offer/answer glare. STUN handles NAT traversal; there is no
|
|
5452
|
+
* TURN — an unreachable peer simply never connects and the caller falls back to
|
|
5453
|
+
* origin (P2P is best-effort).
|
|
5454
|
+
*
|
|
5455
|
+
* Frames (up to a 4 MiB shard) exceed an RTCDataChannel's max message size, so
|
|
5456
|
+
* each frame is fragmented into `CHUNK`-sized pieces with a 12-byte header
|
|
5457
|
+
* `[msgId u32][index u32][total u32]` and reassembled per peer.
|
|
5458
|
+
*/
|
|
5459
|
+
|
|
5460
|
+
interface WebRtcTransportOptions {
|
|
5461
|
+
iceServers?: RTCIceServer[];
|
|
5462
|
+
/** Cap on simultaneous peer connections (mesh size). Default 8. */
|
|
5463
|
+
maxPeers?: number;
|
|
5464
|
+
}
|
|
5465
|
+
declare class WebRtcTransport implements PeerTransport {
|
|
5466
|
+
private readonly signaler;
|
|
5467
|
+
private readonly myId;
|
|
5468
|
+
private readonly conns;
|
|
5469
|
+
private readonly msgCbs;
|
|
5470
|
+
private readonly peerCbs;
|
|
5471
|
+
private readonly offSignal;
|
|
5472
|
+
private readonly iceServers;
|
|
5473
|
+
private readonly maxPeers;
|
|
5474
|
+
private nextMsgId;
|
|
5475
|
+
constructor(signaler: SpaceSignaler, myId: PeerId, opts?: WebRtcTransportOptions);
|
|
5476
|
+
peers(): PeerId[];
|
|
5477
|
+
/** Dial a peer (no-op unless we're the deterministic initiator for the pair). */
|
|
5478
|
+
connectTo(peerId: PeerId): void;
|
|
5479
|
+
send(peer: PeerId, data: Uint8Array, channel?: number): void;
|
|
5480
|
+
broadcast(data: Uint8Array, channel?: number): void;
|
|
5481
|
+
onMessage(cb: (peer: PeerId, data: Uint8Array, channel: number) => void): () => void;
|
|
5482
|
+
onPeerChange(cb: (peers: PeerId[]) => void): () => void;
|
|
5483
|
+
close(): void;
|
|
5484
|
+
private newPc;
|
|
5485
|
+
private initiate;
|
|
5486
|
+
private bindChannel;
|
|
5487
|
+
private onSignal;
|
|
5488
|
+
private drop;
|
|
5489
|
+
private firePeerChange;
|
|
5490
|
+
private sendFragmented;
|
|
5491
|
+
private drain;
|
|
5492
|
+
private onChunk;
|
|
5493
|
+
}
|
|
5494
|
+
|
|
5495
|
+
/**
|
|
5496
|
+
* `EngineHost` — the boundary {@link ../PeerNetwork} wires a transport to. It
|
|
5497
|
+
* abstracts *where* the {@link ./blockEngine.BlockEngine} runs:
|
|
5498
|
+
* - {@link LocalEngineHost} runs it on the calling thread (tests, or a
|
|
5499
|
+
* fallback when the Web Worker can't be built by a consumer's bundler);
|
|
5500
|
+
* - the Worker proxy ({@link ./engineClient}) runs it off-thread.
|
|
5501
|
+
*
|
|
5502
|
+
* Either way the host exposes the same surface: drive `want`/`announce`, feed it
|
|
5503
|
+
* inbound frames via `handleFrame`, and receive its outbound frames via
|
|
5504
|
+
* `onOutbound` (which the network forwards to the transport).
|
|
5505
|
+
*/
|
|
5506
|
+
|
|
5507
|
+
interface EngineHost {
|
|
5508
|
+
want(hash: string, timeoutMs: number): Promise<Uint8Array | null>;
|
|
5509
|
+
announce(hash: string): void;
|
|
5510
|
+
/** Feed an inbound frame received from `peer` on the transport. */
|
|
5511
|
+
handleFrame(peer: string, frame: Uint8Array): void;
|
|
5512
|
+
/** Receive frames the engine wants to send (`"*"` = broadcast). */
|
|
5513
|
+
onOutbound(cb: (target: string, frame: Uint8Array) => void): () => void;
|
|
5514
|
+
close(): void;
|
|
5515
|
+
}
|
|
5516
|
+
/** Runs the engine in-process (main thread or test). */
|
|
5517
|
+
declare class LocalEngineHost implements EngineHost {
|
|
5518
|
+
private readonly engine;
|
|
5519
|
+
private readonly cbs;
|
|
5520
|
+
constructor(store: BlockStore, hasher: Hasher);
|
|
5521
|
+
want(hash: string, timeoutMs: number): Promise<Uint8Array | null>;
|
|
5522
|
+
announce(hash: string): void;
|
|
5523
|
+
handleFrame(peer: string, frame: Uint8Array): void;
|
|
5524
|
+
onOutbound(cb: (target: string, frame: Uint8Array) => void): () => void;
|
|
5525
|
+
close(): void;
|
|
5526
|
+
}
|
|
5527
|
+
|
|
5528
|
+
/**
|
|
5529
|
+
* `WorkerEngineHost` — the main-thread proxy to a {@link ./blockEngine.BlockEngine}
|
|
5530
|
+
* running inside a dedicated Web Worker (so hashing, blockstore I/O, and the
|
|
5531
|
+
* protocol codec stay off the main thread). It speaks the small message protocol
|
|
5532
|
+
* in {@link ./blockEngine.worker} and satisfies {@link ./engineHost.EngineHost},
|
|
5533
|
+
* so {@link ../PeerNetwork} treats it identically to the in-process host.
|
|
5534
|
+
*
|
|
5535
|
+
* Block bytes cross the worker boundary as **transferable** ArrayBuffers
|
|
5536
|
+
* (zero-copy). Only encrypted blocks ever cross — keys never enter the worker.
|
|
5537
|
+
*/
|
|
5538
|
+
|
|
5539
|
+
declare class WorkerEngineHost implements EngineHost {
|
|
5540
|
+
private readonly worker;
|
|
5541
|
+
private readonly wants;
|
|
5542
|
+
private readonly cbs;
|
|
5543
|
+
private nextId;
|
|
5544
|
+
constructor(worker: Worker);
|
|
5545
|
+
want(hash: string, timeoutMs: number): Promise<Uint8Array | null>;
|
|
5546
|
+
announce(hash: string): void;
|
|
5547
|
+
handleFrame(peer: string, frame: Uint8Array): void;
|
|
5548
|
+
onOutbound(cb: (target: string, frame: Uint8Array) => void): () => void;
|
|
5549
|
+
close(): void;
|
|
5550
|
+
}
|
|
5551
|
+
|
|
5552
|
+
/**
|
|
5553
|
+
* Bitswap-lite wire protocol for peer block exchange. Four frame types over a
|
|
5554
|
+
* {@link ../transport/PeerTransport} data channel:
|
|
5555
|
+
*
|
|
5556
|
+
* WANT(hash) — "does anyone have this block?" / "send it to me"
|
|
5557
|
+
* HAVE(hash) — "I hold this block" (announce / reply to a WANT)
|
|
5558
|
+
* BLOCK(hash, bytes) — the block itself (verified by hash on receipt)
|
|
5559
|
+
* CANCEL(hash) — "stop, I got it elsewhere"
|
|
5560
|
+
*
|
|
5561
|
+
* Frames are compact binary so a 4 MiB shard isn't base64-bloated through JSON:
|
|
5562
|
+
*
|
|
5563
|
+
* byte 0 : type (0 WANT | 1 HAVE | 2 BLOCK | 3 CANCEL)
|
|
5564
|
+
* bytes 1..33 : 32-byte raw SHA-256 of the block (our shard hash, hex-decoded)
|
|
5565
|
+
* bytes 33.. : payload (BLOCK only)
|
|
5566
|
+
*
|
|
5567
|
+
* Blocks are AES-GCM ciphertext, so a frame carries nothing readable; the hash
|
|
5568
|
+
* is the capability check (the receiver re-hashes the payload and drops a
|
|
5569
|
+
* mismatch). See {@link ./blockEngine}.
|
|
5570
|
+
*/
|
|
5571
|
+
declare enum FrameType {
|
|
5572
|
+
WANT = 0,
|
|
5573
|
+
HAVE = 1,
|
|
5574
|
+
BLOCK = 2,
|
|
5575
|
+
CANCEL = 3
|
|
5576
|
+
}
|
|
5577
|
+
interface DecodedFrame {
|
|
5578
|
+
type: FrameType;
|
|
5579
|
+
/** Lowercase hex SHA-256 (matches `shardHash`). */
|
|
5580
|
+
hash: string;
|
|
5581
|
+
/** Present only for {@link FrameType.BLOCK}. */
|
|
5582
|
+
payload?: Uint8Array;
|
|
5583
|
+
}
|
|
5584
|
+
declare function encodeWant(hash: string): Uint8Array;
|
|
5585
|
+
declare function encodeHave(hash: string): Uint8Array;
|
|
5586
|
+
declare function encodeCancel(hash: string): Uint8Array;
|
|
5587
|
+
declare function encodeBlock(hash: string, payload: Uint8Array): Uint8Array;
|
|
5588
|
+
declare function decode(frame: Uint8Array): DecodedFrame;
|
|
5589
|
+
|
|
5590
|
+
type protocol_DecodedFrame = DecodedFrame;
|
|
5591
|
+
type protocol_FrameType = FrameType;
|
|
5592
|
+
declare const protocol_FrameType: typeof FrameType;
|
|
5593
|
+
declare const protocol_decode: typeof decode;
|
|
5594
|
+
declare const protocol_encodeBlock: typeof encodeBlock;
|
|
5595
|
+
declare const protocol_encodeCancel: typeof encodeCancel;
|
|
5596
|
+
declare const protocol_encodeHave: typeof encodeHave;
|
|
5597
|
+
declare const protocol_encodeWant: typeof encodeWant;
|
|
5598
|
+
declare namespace protocol {
|
|
5599
|
+
export { protocol_FrameType as FrameType, protocol_decode as decode, protocol_encodeBlock as encodeBlock, protocol_encodeCancel as encodeCancel, protocol_encodeHave as encodeHave, protocol_encodeWant as encodeWant };
|
|
5600
|
+
export type { protocol_DecodedFrame as DecodedFrame };
|
|
5601
|
+
}
|
|
5602
|
+
|
|
5161
5603
|
/**
|
|
5162
5604
|
* KeyringClient — HTTP implementation of {@link KeyringTransport} against the
|
|
5163
5605
|
* accelerator's per-space keyring endpoints. All blobs are opaque to the
|
|
@@ -5218,5 +5660,5 @@ declare class KeyringClient implements KeyringTransport {
|
|
|
5218
5660
|
fetchMetadata(): Promise<SpaceMetadata | null>;
|
|
5219
5661
|
}
|
|
5220
5662
|
|
|
5221
|
-
export { AES_GCM_IV_BYTES, AES_GCM_KEY_BYTES, AES_GCM_TAG_BYTES, AgentsNamespace, AuthClient, AuthNamespace, AuthPublicInput, Authenticator, BroadcastChannel, BroadcastChannelEvents, ChannelExistsError, ChannelNotFoundError, ChunkCipher, Client, ConnectivityManager, DEFAULT_AUTH_BASE_URL, DEFAULT_BASE_URL, DEFAULT_FN_HOST_SUFFIX, DbCache, DoubleRatchet, DoubleRatchetCipher, DoubleRatchetManager, EncryptedSession, EventCore, EventCoreEvents, Field, Field as FieldElement, FileStorage, FunctionsNamespace, HLC, HashKnowledge, HttpClient, HttpError, IndexedDbStore, KEEPER_MEMBER_ID, KeyStore, KeyringClient, KvCache, KvNamespace, LocalStorageSessionStore, MemorySessionStore, Message, Message as MessageDefault, MessageNamespace, MuhkooAgent, MuhkooDB, MuhkooFunction, MuhkooSpace, NoopStore, OfflineLockedError, OfflineManager, OutboundQueue, PBKDF2_DEFAULT_ITERATIONS, PREIMAGE_POK_VERIFICATION_KEY, Packet, PersonalSpaceClient, Poseidon, PreimagePoK, ReedSolomonCodec, Space as Room, SerializeMessage, SessionState, ShardCache, ShardClient, SharedSpaceClient, SnapshotNamespace, Space, SpaceCache, SpaceKeyring, SpaceNamespace, SpacePacketCipher, StorageNamespace, SyncEngine, VaultUnavailableError, WSTransport, ZERO_HLC, ZkAuth, buildCommitment, compareHlc, compilePrograms, decodeFromHex, decorators, decryptAesGcm, defaultCircuitUrls, defaultSessionStore, deleteBeatsWrite, deleteRegister, deriveAesKeyFromPassphrase, deriveBitsHkdf, deriveIdentity, deriveIdentityFromSeed, deriveMasterSeedFromPassword, ejectAgentPrompt, ejectAgentTools, emptyMap, emptyRegister, encodeToHex, encryptAesGcm, exportPublicKeyBase64, exportPublicKeyHex, generateAuthProof, generatePkce, getMuhkooAppDescriptor, getSubtle, initBn128Wasm, initRsWasm, initializeCircuits, isNewer, isOfflineCapable, isProvisional, manifestToStat, materializeRow, mergeMap, mergeMessage, mergeRegister, messageKey, pack, padHandle, poseidonHash, provisionalHandle, quickVerify, randomBytes, randomState, sealSeed, shardHash, signMessage, stableStringify, toField, tombstoneRow, unpack, unsealSeed, unwrapWithPassphrase, verify, verifyGroth16, verifyHashKnowledge, verifyPreimagePoK, wrapWithPassphrase, writeBeatsTombstone, writeColumns, writeRegister };
|
|
5222
|
-
export type { ACL, ACLEntry, AgentConfig, AgentCreateInput, AgentDbToolMode, AgentProvisioned, AgentScopeOpts, AgentSkill, AgentToolsConfig, AgentTrigger, AgentTriggerType, AgentUpdateInput, AgentsNamespaceDeps, AuthClientOptions, AuthKeyPair, AuthSuccess, AuthToken, AuthType, AuthUser, Bn128WasmInstance, BroadcastChannelEvent, BroadcastChannelOptions, CachedSpaceMessage, ChannelLike, ChunkKeyMaterial, ChunkManifest, CipherFrame, CipherMessage, CipherMessageHeader, CircuitBufferConfig, CircuitUrls, ClientOptions, ConnectivityOptions, ConnectivityState, DbQueryPage, DehydratedKeypair, DehydratedKeys, DoubleRatchetCipherDeps, ECDHCurve, EncodeResult, EphemeralEvent, EpochKeyProvider, FileManifest, FileNamespaceDeps, FileStat, FileStorageOptions, FunctionCaps, FunctionConfig, FunctionDeployInput, FunctionInvokeOptions, FunctionScopeOpts, FunctionTrigger, FunctionTriggerType, FunctionTriggers, FunctionUpdateInput, FunctionsNamespaceDeps, Groth16Proof, HlcParts, HlcState, HttpClientOptions, IncomingFrame, KeyExchangeFrame, KeyPair, Keypair, KeyringClientDeps, KeyringTransport, KvEntry, KvNamespaceDeps, LoginOptions, LwwMap, LwwRegister, MessageBody, MessageDeletedEvent, MessageEntry, MessageEvent, MessageHeaders, MessageNamespaceDeps, MessageOp, MessageOptions, MessageSubscription, MuhkooAgentMeta, MuhkooAgentToolsConfig, MuhkooAppDescriptor, MuhkooDBAccess, MuhkooDBMeta, MuhkooFunctionMeta, MuhkooMessageEvent, MuhkooSpaceMeta, OAuthProvider, OfflineEntry, OfflineManagerDeps, OfflineStore, PacketCipher, PacketHeaders, PacketOptions, Participant, Permission, PermissionCheckRequest, PermissionCheckResult, PersonalSpaceClientOptions, Pkce, PublicKeyJWK, QueueEntry, RatchetState, ReceiveResult, RegisterParams, Replayer, Role, SpaceDeps as RoomDeps, SpaceFileMetadata as RoomFileMetadata, SealedHandoff, SealedHeaders, Session, SessionOptions, SessionStore, SetOptions, ShardByteCache, ShardClientOptions, SharedSpaceClientOptions, SnapshotNamespaceDeps, SnarkProof, SpaceChannelLike, SpaceCursor, SpaceDeps, SpaceFileMetadata, SpaceKeyCache, SpaceKeyringDeps, SpaceMessageEvent, SpaceNamespaceDeps, SpaceOfflineAdapter, StorageChangeEvent, StoreName, StoredSession, Subscription, UserIdentity, VaultFactor, VerificationKey, WSMessage, WSMessageType, WSTransportOptions, WrappedPayload, WriteFileInput, WriteFileOptions, WriteToShardsInput, ZkAuthDeps, ZkAuthenticateRequest, ZkChallengeResponse, ZkCompiled, ZkIdentity, ZkRegisterRequest, ZkRegisterResponse };
|
|
5663
|
+
export { AES_GCM_IV_BYTES, AES_GCM_KEY_BYTES, AES_GCM_TAG_BYTES, AgentsNamespace, AuthClient, AuthNamespace, AuthPublicInput, Authenticator, BlockEngine, BroadcastChannel, BroadcastChannelEvents, ChannelExistsError, ChannelNotFoundError, ChunkCipher, Client, ConnectivityManager, DEFAULT_AUTH_BASE_URL, DEFAULT_BASE_URL, DEFAULT_FN_HOST_SUFFIX, DbCache, DoubleRatchet, DoubleRatchetCipher, DoubleRatchetManager, EncryptedSession, EventCore, EventCoreEvents, Field, Field as FieldElement, FileStorage, FunctionsNamespace, HLC, HashKnowledge, HttpClient, HttpError, IndexedDbStore, KEEPER_MEMBER_ID, KeyStore, KeyringClient, KvCache, KvNamespace, LocalEngineHost, LocalStorageSessionStore, MemorySessionStore, Message, Message as MessageDefault, MessageNamespace, MuhkooAgent, MuhkooDB, MuhkooFunction, MuhkooSpace, NoopStore, OfflineLockedError, OfflineManager, OutboundQueue, P2P_SUBJECT, PBKDF2_DEFAULT_ITERATIONS, PREIMAGE_POK_VERIFICATION_KEY, Packet, PeerExchange, PeerNetwork, PersonalSpaceClient, Poseidon, PreimagePoK, ReedSolomonCodec, Space as Room, SerializeMessage, SessionState, ShardCache, ShardClient, SharedSpaceClient, SnapshotNamespace, Space, SpaceCache, SpaceKeyring, SpaceNamespace, SpacePacketCipher, SpaceSignaler, StorageNamespace, SyncEngine, VaultUnavailableError, WSTransport, WebRtcTransport, WorkerEngineHost, ZERO_HLC, ZkAuth, buildCommitment, compareHlc, compilePrograms, decodeFromHex, decorators, decryptAesGcm, defaultCircuitUrls, defaultSessionStore, deleteBeatsWrite, deleteRegister, deriveAesKeyFromPassphrase, deriveBitsHkdf, deriveIdentity, deriveIdentityFromSeed, deriveMasterSeedFromPassword, ejectAgentPrompt, ejectAgentTools, emptyMap, emptyRegister, encodeToHex, encryptAesGcm, exportPublicKeyBase64, exportPublicKeyHex, generateAuthProof, generatePkce, getMuhkooAppDescriptor, getSubtle, initBn128Wasm, initRsWasm, initializeCircuits, isNewer, isOfflineCapable, isP2pCapable, isProvisional, manifestToStat, materializeRow, mergeMap, mergeMessage, mergeRegister, messageKey, pack, padHandle, poseidonHash, protocol, provisionalHandle, quickVerify, randomBytes, randomState, sealSeed, shardHash, signMessage, stableStringify, toField, tombstoneRow, unpack, unsealSeed, unwrapWithPassphrase, verify, verifyGroth16, verifyHashKnowledge, verifyPreimagePoK, wrapWithPassphrase, writeBeatsTombstone, writeColumns, writeRegister };
|
|
5664
|
+
export type { ACL, ACLEntry, AgentConfig, AgentCreateInput, AgentDbToolMode, AgentProvisioned, AgentScopeOpts, AgentSkill, AgentToolsConfig, AgentTrigger, AgentTriggerType, AgentUpdateInput, AgentsNamespaceDeps, AttachedPeerNetwork, AuthClientOptions, AuthKeyPair, AuthSuccess, AuthToken, AuthType, AuthUser, BlockStore, Bn128WasmInstance, BroadcastChannelEvent, BroadcastChannelOptions, CachedSpaceMessage, ChannelLike, ChunkKeyMaterial, ChunkManifest, CipherFrame, CipherMessage, CipherMessageHeader, CircuitBufferConfig, CircuitUrls, ClientOptions, ConnectivityOptions, ConnectivityState, DbQueryPage, DehydratedKeypair, DehydratedKeys, DoubleRatchetCipherDeps, ECDHCurve, EncodeResult, EngineHandle, EngineHost, EphemeralEvent, EpochKeyProvider, FileManifest, FileNamespaceDeps, FileStat, FileStorageOptions, FunctionCaps, FunctionConfig, FunctionDeployInput, FunctionInvokeOptions, FunctionScopeOpts, FunctionTrigger, FunctionTriggerType, FunctionTriggers, FunctionUpdateInput, FunctionsNamespaceDeps, Groth16Proof, Hasher, HlcParts, HlcState, HttpClientOptions, IncomingFrame, KeyExchangeFrame, KeyPair, Keypair, KeyringClientDeps, KeyringTransport, KvEntry, KvNamespaceDeps, LoginOptions, LwwMap, LwwRegister, MessageBody, MessageDeletedEvent, MessageEntry, MessageEvent, MessageHeaders, MessageNamespaceDeps, MessageOp, MessageOptions, MessageSubscription, MuhkooAgentMeta, MuhkooAgentToolsConfig, MuhkooAppDescriptor, MuhkooDBAccess, MuhkooDBMeta, MuhkooFunctionMeta, MuhkooMessageEvent, MuhkooSpaceMeta, OAuthProvider, OfflineEntry, OfflineManagerDeps, OfflineStore, OutSink, PacketCipher, PacketHeaders, PacketOptions, Participant, PeerBlockSource, PeerExchangeOptions, PeerId, PeerNetworkOptions, PeerTransport, Permission, PermissionCheckRequest, PermissionCheckResult, PersonalSpaceClientOptions, Pkce, PublicKeyJWK, QueueEntry, RatchetState, ReceiveResult, RegisterParams, Replayer, Role, SpaceDeps as RoomDeps, SpaceFileMetadata as RoomFileMetadata, SealedHandoff, SealedHeaders, Session, SessionOptions, SessionStore, SetOptions, ShardByteCache, ShardClientOptions, SharedSpaceClientOptions, SignalEnvelope, SignalKind, SignalingSpace, SnapshotNamespaceDeps, SnarkProof, SpaceChannelLike, SpaceCursor, SpaceDeps, SpaceFileMetadata, SpaceKeyCache, SpaceKeyringDeps, SpaceMessageEvent, SpaceNamespaceDeps, SpaceOfflineAdapter, StorageChangeEvent, StoreName, StoredSession, Subscription, UserIdentity, VaultFactor, VerificationKey, WSMessage, WSMessageType, WSTransportOptions, WebRtcTransportOptions, WrappedPayload, WriteFileInput, WriteFileOptions, WriteToShardsInput, ZkAuthDeps, ZkAuthenticateRequest, ZkChallengeResponse, ZkCompiled, ZkIdentity, ZkRegisterRequest, ZkRegisterResponse };
|