@saga-sync/client 0.0.0 → 0.1.2

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/cli.d.ts ADDED
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env node
2
+ import { Client } from "./client.js";
3
+ type Range = {
4
+ fromBlock?: bigint;
5
+ toBlock?: bigint;
6
+ };
7
+ export declare function cmdProtocols(client: Client, opts: {
8
+ json: boolean;
9
+ }): Promise<string>;
10
+ export declare function cmdInfo(client: Client, id: string, opts: {
11
+ json: boolean;
12
+ } & Range): Promise<string>;
13
+ export declare function cmdHead(client: Client, id: string, opts: {
14
+ json: boolean;
15
+ sinceBlock?: bigint;
16
+ }): Promise<{
17
+ text: string;
18
+ stale: boolean;
19
+ }>;
20
+ export declare function cmdChunks(client: Client, id: string, opts: {
21
+ json: boolean;
22
+ hot: boolean;
23
+ } & Range): Promise<string>;
24
+ export {};
25
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAQA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAyDrC,KAAK,KAAK,GAAG;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAKtD,wBAAsB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA0B3F;AAED,wBAAsB,OAAO,CAC3B,MAAM,EAAE,MAAM,EACd,EAAE,EAAE,MAAM,EACV,IAAI,EAAE;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GAAG,KAAK,GAC9B,OAAO,CAAC,MAAM,CAAC,CA2CjB;AAED,wBAAsB,OAAO,CAC3B,MAAM,EAAE,MAAM,EACd,EAAE,EAAE,MAAM,EACV,IAAI,EAAE;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GAC3C,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC,CA6B3C;AAED,wBAAsB,SAAS,CAC7B,MAAM,EAAE,MAAM,EACd,EAAE,EAAE,MAAM,EACV,IAAI,EAAE;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,OAAO,CAAA;CAAE,GAAG,KAAK,GAC5C,OAAO,CAAC,MAAM,CAAC,CAoBjB"}
package/dist/cli.js ADDED
@@ -0,0 +1,280 @@
1
+ #!/usr/bin/env node
2
+ import { parseArgs } from "node:util";
3
+ import { realpathSync } from "node:fs";
4
+ import { resolve } from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+ import { HttpStore } from "@saga-sync/core";
7
+ import { DiskStore } from "@saga-sync/core/node";
8
+ import { Client } from "./client.js";
9
+ import { selectSealedChunks, selectHotHead } from "./manifest.js";
10
+ import { humanBytes, table } from "./format.js";
11
+ const DEFAULT_CONCURRENCY = 4;
12
+ // Minimal 0x-hex of a non-negative bigint/number — replaces viem's numberToHex so
13
+ // the client carries no viem dependency. Block numbers and sizes are non-negative.
14
+ function numberToHex(value) {
15
+ return `0x${value.toString(16)}`;
16
+ }
17
+ const USAGE = `state-client — inspect + download a protocol's published state
18
+
19
+ Usage:
20
+ state-client <command> <manifest-url> [<protocol-id>] [options]
21
+
22
+ Commands:
23
+ protocols <manifest-url> list every protocol + summary (alias: ls)
24
+ info <manifest-url> <protocol-id> detailed summary for one protocol
25
+ head <manifest-url> <protocol-id> latest covered block / freshness (alias: latest)
26
+ chunks <manifest-url> <protocol-id> list this protocol's chunks
27
+ stream <manifest-url> <protocol-id> download + verify + emit NDJSON
28
+
29
+ The manifest is read from <manifest-url>/index.json. The query commands
30
+ (protocols/info/head/chunks) fetch only the manifest — no chunk downloads.
31
+
32
+ Options:
33
+ --json machine-readable output instead of human tables
34
+ --from-block <hex> info/chunks/stream: lower bound of the block range
35
+ --to-block <hex> info/chunks/stream: upper bound (exclusive)
36
+ --since-block <hex> head: exit 3 if no block beyond this is covered
37
+ --hot chunks: include the mutable hot head
38
+ --cache-dir <path> stream: local cache of verified sealed chunks
39
+ --concurrency <n> stream: parallel chunk fetches, default ${DEFAULT_CONCURRENCY}
40
+ --public-key <hex> require + verify the manifest's Ed25519 signature
41
+ --help show this message
42
+
43
+ Exit codes: 0 ok · 1 usage/fetch/not-found · 3 head --since-block found nothing newer
44
+ `;
45
+ function fail(msg) {
46
+ process.stderr.write(`state-client: ${msg}\n`);
47
+ process.exit(1);
48
+ }
49
+ function hexOrNull(b) {
50
+ return b === null ? null : numberToHex(b);
51
+ }
52
+ // Sum the compressed `size` of a chunk list plus an optional hot head.
53
+ function sumSize(chunks, hot) {
54
+ let total = chunks.reduce((s, c) => s + BigInt(c.size), 0n);
55
+ if (hot)
56
+ total += BigInt(hot.size);
57
+ return total;
58
+ }
59
+ // --- command handlers: each fetches the manifest and returns rendered output,
60
+ // so they are unit-testable against an in-memory Store without a process. ---
61
+ export async function cmdProtocols(client, opts) {
62
+ const manifest = await client.fetchManifest();
63
+ const rows = manifest.protocolIds().map((id) => {
64
+ const sealed = manifest.sealedChunks(id);
65
+ const hot = manifest.hotHead(id);
66
+ return {
67
+ protocolId: id,
68
+ sealedChunks: sealed.length,
69
+ fromBlock: hexOrNull(manifest.firstCoveredBlock(id)),
70
+ lastCoveredBlock: hexOrNull(manifest.lastCoveredBlock(id)),
71
+ hotHead: hot !== undefined,
72
+ totalSize: numberToHex(sumSize(sealed, hot)),
73
+ };
74
+ });
75
+ if (opts.json)
76
+ return JSON.stringify(rows, null, 2);
77
+ if (rows.length === 0)
78
+ return "(no protocols in manifest)";
79
+ return table(["PROTOCOL", "CHUNKS", "RANGE", "HOT", "SIZE"], rows.map((r) => [
80
+ r.protocolId,
81
+ String(r.sealedChunks),
82
+ `${r.fromBlock ?? "-"} → ${r.lastCoveredBlock ?? "-"}`,
83
+ r.hotHead ? "yes" : "no",
84
+ humanBytes(BigInt(r.totalSize)),
85
+ ]));
86
+ }
87
+ export async function cmdInfo(client, id, opts) {
88
+ const manifest = await client.fetchManifest();
89
+ if (!manifest.protocolIds().includes(id))
90
+ throw new Error(`unknown protocol "${id}"`);
91
+ const sealed = manifest.sealedChunks(id);
92
+ const hot = manifest.hotHead(id);
93
+ const range = { fromBlock: opts.fromBlock, toBlock: opts.toBlock };
94
+ const scopedSize = sumSize(selectSealedChunks(sealed, range), selectHotHead(hot, range));
95
+ const gaps = manifest.gaps(id);
96
+ const first = manifest.firstCoveredBlock(id);
97
+ const last = manifest.lastCoveredBlock(id);
98
+ if (opts.json) {
99
+ return JSON.stringify({
100
+ protocolId: id,
101
+ manifestVersion: manifest.version(),
102
+ updatedAt: manifest.updatedAt() ?? null,
103
+ fromBlock: hexOrNull(first),
104
+ lastCoveredBlock: hexOrNull(last),
105
+ sealedChunks: sealed.length,
106
+ hotHead: hot ? { fromBlock: hot.fromBlock, toBlock: hot.toBlock, size: hot.size } : null,
107
+ totalCompressedSize: numberToHex(scopedSize),
108
+ gaps,
109
+ }, null, 2);
110
+ }
111
+ const ranged = opts.fromBlock !== undefined || opts.toBlock !== undefined;
112
+ return [
113
+ `protocol: ${id}`,
114
+ `manifest: v${manifest.version()}${manifest.updatedAt() ? `, updated ${manifest.updatedAt()}` : ""}`,
115
+ `block range: ${hexOrNull(first) ?? "-"} → ${hexOrNull(last) ?? "-"}`,
116
+ `sealed chunks: ${sealed.length}`,
117
+ `hot head: ${hot ? `${hot.fromBlock} → ${hot.toBlock} (${humanBytes(BigInt(hot.size))})` : "none"}`,
118
+ `download size: ${humanBytes(scopedSize)}${ranged ? " (for requested range)" : ""}`,
119
+ `contiguity: ${gaps.length === 0
120
+ ? "gapless"
121
+ : `${gaps.length} gap(s): ${gaps.map((g) => `[${g.from},${g.to})`).join(", ")}`}`,
122
+ ].join("\n");
123
+ }
124
+ export async function cmdHead(client, id, opts) {
125
+ const manifest = await client.fetchManifest();
126
+ if (!manifest.protocolIds().includes(id))
127
+ throw new Error(`unknown protocol "${id}"`);
128
+ const last = manifest.lastCoveredBlock(id);
129
+ const hot = manifest.hotHead(id);
130
+ const stale = opts.sinceBlock !== undefined && (last === null || last <= opts.sinceBlock);
131
+ if (opts.json) {
132
+ const text = JSON.stringify({
133
+ lastCoveredBlock: hexOrNull(last),
134
+ hotHead: hot ? { fromBlock: hot.fromBlock, toBlock: hot.toBlock } : null,
135
+ }, null, 2);
136
+ return { text, stale };
137
+ }
138
+ const lines = [`last covered block: ${hexOrNull(last) ?? "-"}`];
139
+ if (hot)
140
+ lines.push(`hot head: ${hot.fromBlock} → ${hot.toBlock}`);
141
+ if (opts.sinceBlock !== undefined) {
142
+ lines.push(stale
143
+ ? `no new data since ${numberToHex(opts.sinceBlock)}`
144
+ : `new data beyond ${numberToHex(opts.sinceBlock)}`);
145
+ }
146
+ return { text: lines.join("\n"), stale };
147
+ }
148
+ export async function cmdChunks(client, id, opts) {
149
+ const manifest = await client.fetchManifest();
150
+ if (!manifest.protocolIds().includes(id))
151
+ throw new Error(`unknown protocol "${id}"`);
152
+ const range = { fromBlock: opts.fromBlock, toBlock: opts.toBlock };
153
+ const list = [...selectSealedChunks(manifest.sealedChunks(id), range)];
154
+ if (opts.hot) {
155
+ const h = selectHotHead(manifest.hotHead(id), range);
156
+ if (h)
157
+ list.push(h);
158
+ }
159
+ if (opts.json)
160
+ return JSON.stringify(list, null, 2);
161
+ if (list.length === 0)
162
+ return "(no chunks in range)";
163
+ return table(["RANGE", "SIZE", "FILE", "DIGEST"], list.map((c) => [
164
+ `[${c.fromBlock},${c.toBlock})`,
165
+ humanBytes(BigInt(c.size)),
166
+ c.file,
167
+ c.digest.data,
168
+ ]));
169
+ }
170
+ async function runStream(manifestUrl, id, opts) {
171
+ const source = new HttpStore(manifestUrl);
172
+ const cache = opts.cacheDir ? new DiskStore(opts.cacheDir) : undefined;
173
+ const client = new Client({
174
+ source,
175
+ cache,
176
+ concurrency: opts.concurrency,
177
+ publicKey: opts.publicKey,
178
+ });
179
+ let count = 0;
180
+ for await (const event of client.streamEvents(id, {
181
+ fromBlock: opts.fromBlock,
182
+ toBlock: opts.toBlock,
183
+ })) {
184
+ process.stdout.write(JSON.stringify(event) + "\n");
185
+ count++;
186
+ }
187
+ const range = opts.fromBlock !== undefined || opts.toBlock !== undefined
188
+ ? ` in [${opts.fromBlock !== undefined ? numberToHex(opts.fromBlock) : "*"},` +
189
+ `${opts.toBlock !== undefined ? numberToHex(opts.toBlock) : "*"})`
190
+ : "";
191
+ process.stderr.write(`state-client: ${count} event(s) for ${id}${range}` +
192
+ (opts.cacheDir ? ` (cache=${opts.cacheDir})` : "") +
193
+ `\n`);
194
+ }
195
+ async function main() {
196
+ const { values, positionals } = parseArgs({
197
+ allowPositionals: true,
198
+ options: {
199
+ json: { type: "boolean", default: false },
200
+ help: { type: "boolean", default: false },
201
+ "cache-dir": { type: "string" },
202
+ "from-block": { type: "string" },
203
+ "to-block": { type: "string" },
204
+ "since-block": { type: "string" },
205
+ hot: { type: "boolean", default: false },
206
+ concurrency: { type: "string" },
207
+ "public-key": { type: "string" },
208
+ },
209
+ });
210
+ if (values.help || positionals.length === 0) {
211
+ process.stdout.write(USAGE);
212
+ return;
213
+ }
214
+ const [command, manifestUrl] = positionals;
215
+ if (!manifestUrl)
216
+ fail(`missing <manifest-url>\n\n${USAGE}`);
217
+ const json = values.json;
218
+ const range = {
219
+ fromBlock: values["from-block"] ? BigInt(values["from-block"]) : undefined,
220
+ toBlock: values["to-block"] ? BigInt(values["to-block"]) : undefined,
221
+ };
222
+ const needId = () => {
223
+ const id = positionals[2];
224
+ if (!id)
225
+ fail(`missing <protocol-id> for "${command}"\n\n${USAGE}`);
226
+ return id;
227
+ };
228
+ const publicKey = values["public-key"];
229
+ const queryClient = () => new Client({ source: new HttpStore(manifestUrl), publicKey });
230
+ switch (command) {
231
+ case "protocols":
232
+ case "ls":
233
+ process.stdout.write((await cmdProtocols(queryClient(), { json })) + "\n");
234
+ return;
235
+ case "info":
236
+ process.stdout.write((await cmdInfo(queryClient(), needId(), { json, ...range })) + "\n");
237
+ return;
238
+ case "head":
239
+ case "latest": {
240
+ const sinceBlock = values["since-block"] ? BigInt(values["since-block"]) : undefined;
241
+ const res = await cmdHead(queryClient(), needId(), { json, sinceBlock });
242
+ process.stdout.write(res.text + "\n");
243
+ if (res.stale)
244
+ process.exit(3);
245
+ return;
246
+ }
247
+ case "chunks":
248
+ process.stdout.write((await cmdChunks(queryClient(), needId(), { json, hot: values.hot, ...range })) + "\n");
249
+ return;
250
+ case "stream": {
251
+ const concurrency = values.concurrency ? Number(values.concurrency) : DEFAULT_CONCURRENCY;
252
+ if (!Number.isInteger(concurrency) || concurrency < 1) {
253
+ fail(`--concurrency must be a positive integer; got ${values.concurrency}`);
254
+ }
255
+ await runStream(manifestUrl, needId(), {
256
+ cacheDir: values["cache-dir"] ? resolve(values["cache-dir"]) : undefined,
257
+ concurrency,
258
+ publicKey,
259
+ ...range,
260
+ });
261
+ return;
262
+ }
263
+ default:
264
+ fail(`unknown command "${command}"\n\n${USAGE}`);
265
+ }
266
+ }
267
+ function isMainModule() {
268
+ try {
269
+ return realpathSync(process.argv[1] ?? "") === realpathSync(fileURLToPath(import.meta.url));
270
+ }
271
+ catch {
272
+ return false;
273
+ }
274
+ }
275
+ if (isMainModule()) {
276
+ main().catch((err) => {
277
+ fail(err instanceof Error ? err.message : String(err));
278
+ });
279
+ }
280
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import type { CanonicalEvent } from "@saga-sync/core";
2
+ import type { Store } from "@saga-sync/core";
3
+ import type { ChunkMeta } from "@saga-sync/core";
4
+ import { Manifest } from "@saga-sync/core";
5
+ export type ClientOptions = {
6
+ source: Store;
7
+ cache?: Store;
8
+ concurrency?: number;
9
+ publicKey?: string;
10
+ };
11
+ export type StreamOptions = {
12
+ fromBlock?: bigint;
13
+ toBlock?: bigint;
14
+ };
15
+ export declare class Client {
16
+ private readonly source;
17
+ private readonly cache;
18
+ private readonly concurrency;
19
+ private readonly publicKey;
20
+ constructor(opts: ClientOptions);
21
+ fetchManifest(key?: string): Promise<Manifest>;
22
+ fetchChunk(meta: ChunkMeta, opts?: {
23
+ hot?: boolean;
24
+ }): Promise<CanonicalEvent[]>;
25
+ listProtocols(prefix?: string): Promise<string[]>;
26
+ streamEvents(protocolId: string, opts?: StreamOptions): AsyncGenerator<CanonicalEvent, void, void>;
27
+ private fetchSealed;
28
+ private fetchSealedOrdered;
29
+ }
30
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAI3C,MAAM,MAAM,aAAa,GAAG;IAG1B,MAAM,EAAE,KAAK,CAAC;IAKd,KAAK,CAAC,EAAE,KAAK,CAAC;IAGd,WAAW,CAAC,EAAE,MAAM,CAAC;IAGrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAOF,qBAAa,MAAM;IACjB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAQ;IAC/B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAoB;IAC1C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAqB;gBAEnC,IAAI,EAAE,aAAa;IAY/B,aAAa,CAAC,GAAG,GAAE,MAAqB,GAAG,OAAO,CAAC,QAAQ,CAAC;IAO5D,UAAU,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,GAAE;QAAE,GAAG,CAAC,EAAE,OAAO,CAAA;KAAO,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAS9E,aAAa,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAQhD,YAAY,CACjB,UAAU,EAAE,MAAM,EAClB,IAAI,GAAE,aAAkB,GACvB,cAAc,CAAC,cAAc,EAAE,IAAI,EAAE,IAAI,CAAC;YAkB/B,WAAW;YAiBV,kBAAkB;CAclC"}
package/dist/client.js ADDED
@@ -0,0 +1,100 @@
1
+ import { decodeAndVerify, fetchChunkFrom, ChunkNotFoundError } from "./fetch.js";
2
+ import { loadManifest, selectSealedChunks, selectHotHead } from "./manifest.js";
3
+ const DEFAULT_CONCURRENCY = 4;
4
+ // The consumer's entry point. Holds a (source, optional cache) pair and offers
5
+ // three layers: raw manifest, single chunk, and a merged streamEvents iterator
6
+ // across sealed chunks + the hot head.
7
+ export class Client {
8
+ source;
9
+ cache;
10
+ concurrency;
11
+ publicKey;
12
+ constructor(opts) {
13
+ this.source = opts.source;
14
+ this.cache = opts.cache;
15
+ this.concurrency = opts.concurrency ?? DEFAULT_CONCURRENCY;
16
+ this.publicKey = opts.publicKey;
17
+ if (!Number.isInteger(this.concurrency) || this.concurrency < 1) {
18
+ throw new Error(`concurrency must be a positive integer; got ${opts.concurrency}`);
19
+ }
20
+ }
21
+ // Layer 1: fetch and parse the manifest (verifying its signature when a public
22
+ // key was configured).
23
+ fetchManifest(key = "index.json") {
24
+ return loadManifest(this.source, key, { publicKey: this.publicKey });
25
+ }
26
+ // Layer 2: fetch one chunk by its manifest entry. Goes through the cache
27
+ // path (for sealed chunks) so callers get the same efficiency as
28
+ // streamEvents.
29
+ fetchChunk(meta, opts = {}) {
30
+ return opts.hot ? fetchChunkFrom(this.source, meta) : this.fetchSealed(meta);
31
+ }
32
+ // Layer 1.5: discover the protocol streams a manifest publishes. Streams are
33
+ // granular per-pool (e.g. "tornado-cash-1-eth-0.1", "tornado-cash-1-dai-100"),
34
+ // so passing the family prefix "tornado-cash-1" returns every denomination's
35
+ // id — the enumeration a consumer needs before it can pick or fan out over
36
+ // streamEvents. Omit `prefix` to list everything; result is sorted.
37
+ async listProtocols(prefix) {
38
+ const ids = (await this.fetchManifest()).protocolIds();
39
+ return (prefix === undefined ? ids : ids.filter((id) => matchesFamily(id, prefix))).sort();
40
+ }
41
+ // Layer 3: merged event stream for a protocol. Yields events in block order
42
+ // across all sealed chunks in the optional [fromBlock, toBlock) window,
43
+ // then the hot head (re-fetched every call, never cached).
44
+ async *streamEvents(protocolId, opts = {}) {
45
+ const manifest = await this.fetchManifest();
46
+ const sealed = selectSealedChunks(manifest.sealedChunks(protocolId), opts);
47
+ const hot = selectHotHead(manifest.hotHead(protocolId), opts);
48
+ for await (const events of this.fetchSealedOrdered(sealed)) {
49
+ for (const event of events)
50
+ yield event;
51
+ }
52
+ if (hot) {
53
+ const events = await fetchChunkFrom(this.source, hot);
54
+ for (const event of events)
55
+ yield event;
56
+ }
57
+ }
58
+ // Cache-aware sealed fetch: check cache → on miss, fetch from source, verify,
59
+ // populate cache. Verification runs on both paths so every byte the
60
+ // application sees was just verified.
61
+ async fetchSealed(meta) {
62
+ if (this.cache) {
63
+ const cached = await this.cache.get(meta.file);
64
+ if (cached)
65
+ return await decodeAndVerify(cached, meta);
66
+ }
67
+ const compressed = await this.source.get(meta.file);
68
+ if (!compressed)
69
+ throw new ChunkNotFoundError(meta);
70
+ const events = await decodeAndVerify(compressed, meta);
71
+ if (this.cache)
72
+ await this.cache.put(meta.file, compressed);
73
+ return events;
74
+ }
75
+ // Sliding window — keep up to `concurrency` sealed-chunk fetches in flight;
76
+ // yield them strictly in submission order so consumers see events in
77
+ // block-range order regardless of which fetch finished first. Per-chunk
78
+ // peak memory is one decompressed chunk (~10 MiB); across chunks it is
79
+ // bounded by `concurrency`.
80
+ async *fetchSealedOrdered(metas) {
81
+ const queue = [];
82
+ let next = 0;
83
+ while (next < metas.length && queue.length < this.concurrency) {
84
+ queue.push(this.fetchSealed(metas[next++]));
85
+ }
86
+ while (queue.length > 0) {
87
+ const events = await queue.shift();
88
+ if (next < metas.length)
89
+ queue.push(this.fetchSealed(metas[next++]));
90
+ yield events;
91
+ }
92
+ }
93
+ }
94
+ // A protocol id belongs to a family if it equals the prefix or extends it by a
95
+ // "-" segment, so "tornado-cash-1" matches "tornado-cash-1-eth-0.1" but not an
96
+ // unrelated id that merely starts with the same characters.
97
+ function matchesFamily(id, prefix) {
98
+ return id === prefix || id.startsWith(`${prefix}-`);
99
+ }
100
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { CanonicalEvent } from "@saga-sync/core";
2
+ import type { Store } from "@saga-sync/core";
3
+ import type { ChunkMeta } from "@saga-sync/core";
4
+ export declare class ChunkNotFoundError extends Error {
5
+ readonly meta: ChunkMeta;
6
+ constructor(meta: ChunkMeta);
7
+ }
8
+ export declare function decodeAndVerify(compressed: Uint8Array, meta: ChunkMeta): Promise<CanonicalEvent[]>;
9
+ export declare function fetchChunkFrom(store: Store, meta: ChunkMeta): Promise<CanonicalEvent[]>;
10
+ //# sourceMappingURL=fetch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../src/fetch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAMjD,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;gBACb,IAAI,EAAE,SAAS;CAK5B;AAiBD,wBAAsB,eAAe,CACnC,UAAU,EAAE,UAAU,EACtB,IAAI,EAAE,SAAS,GACd,OAAO,CAAC,cAAc,EAAE,CAAC,CAc3B;AAKD,wBAAsB,cAAc,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAI7F"}
package/dist/fetch.js ADDED
@@ -0,0 +1,51 @@
1
+ import { verifyDigest, verifyChunkEvents } from "./verify.js";
2
+ // Thrown when a chunk file referenced by the manifest is absent from the
3
+ // store. Distinct from DigestMismatchError so callers can tell "missing"
4
+ // from "wrong" — typically actionable differently (publisher gap vs. tampering).
5
+ export class ChunkNotFoundError extends Error {
6
+ meta;
7
+ constructor(meta) {
8
+ super(`chunk file not found: ${meta.file}`);
9
+ this.name = "ChunkNotFoundError";
10
+ this.meta = meta;
11
+ }
12
+ }
13
+ // Gzip decompression via the web-standard DecompressionStream, so the consumer
14
+ // read path runs in a browser as well as Node (both ship it). Async, unlike
15
+ // node:zlib's gunzipSync — the only behavioral change of the browser refactor.
16
+ async function gunzip(data) {
17
+ const stream = new Blob([data]).stream().pipeThrough(new DecompressionStream("gzip"));
18
+ return new Uint8Array(await new Response(stream).arrayBuffer());
19
+ }
20
+ const utf8 = new TextDecoder();
21
+ // Decode a chunk file's compressed bytes: gunzip → verify digest → parse JSONL →
22
+ // verify canonical form. Digest verification happens before parsing so a tampered
23
+ // chunk never reaches the caller; the canonical-form check (range + ordering, SPEC
24
+ // §3.3) then catches a correctly-digested chunk the producer built non-canonically.
25
+ // Async because gzip decompression is a streaming Web API.
26
+ export async function decodeAndVerify(compressed, meta) {
27
+ // Defensive: a zero-byte file is not produced by the pipeline (an empty
28
+ // events list still gzips to ~20 bytes), but if encountered, hand empty
29
+ // bytes to verify rather than letting gunzip throw.
30
+ const uncompressed = compressed.length === 0 ? new Uint8Array(0) : await gunzip(compressed);
31
+ verifyDigest(meta, uncompressed);
32
+ if (uncompressed.length === 0)
33
+ return [];
34
+ const events = utf8
35
+ .decode(uncompressed)
36
+ .split("\n")
37
+ .filter((line) => line.length > 0)
38
+ .map((line) => JSON.parse(line));
39
+ verifyChunkEvents(meta, events);
40
+ return events;
41
+ }
42
+ // Fetch a chunk from `store`, verify, return its events. Throws
43
+ // ChunkNotFoundError if the store has no such object, DigestMismatchError if
44
+ // the bytes do not match the manifest.
45
+ export async function fetchChunkFrom(store, meta) {
46
+ const compressed = await store.get(meta.file);
47
+ if (!compressed)
48
+ throw new ChunkNotFoundError(meta);
49
+ return decodeAndVerify(compressed, meta);
50
+ }
51
+ //# sourceMappingURL=fetch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch.js","sourceRoot":"","sources":["../src/fetch.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAE9D,yEAAyE;AACzE,yEAAyE;AACzE,iFAAiF;AACjF,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAClC,IAAI,CAAY;IACzB,YAAY,IAAe;QACzB,KAAK,CAAC,yBAAyB,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QAC5C,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;QACjC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAED,+EAA+E;AAC/E,4EAA4E;AAC5E,+EAA+E;AAC/E,KAAK,UAAU,MAAM,CAAC,IAAgB;IACpC,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,WAAW,CAAC,IAAI,mBAAmB,CAAC,MAAM,CAAC,CAAC,CAAC;IACtF,OAAO,IAAI,UAAU,CAAC,MAAM,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;AAClE,CAAC;AAED,MAAM,IAAI,GAAG,IAAI,WAAW,EAAE,CAAC;AAE/B,iFAAiF;AACjF,kFAAkF;AAClF,mFAAmF;AACnF,oFAAoF;AACpF,2DAA2D;AAC3D,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,UAAsB,EACtB,IAAe;IAEf,wEAAwE;IACxE,wEAAwE;IACxE,oDAAoD;IACpD,MAAM,YAAY,GAAG,UAAU,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC;IAC5F,YAAY,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IACjC,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACzC,MAAM,MAAM,GAAG,IAAI;SAChB,MAAM,CAAC,YAAY,CAAC;SACpB,KAAK,CAAC,IAAI,CAAC;SACX,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;SACjC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAmB,CAAC,CAAC;IACrD,iBAAiB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAChC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,gEAAgE;AAChE,6EAA6E;AAC7E,uCAAuC;AACvC,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,KAAY,EAAE,IAAe;IAChE,MAAM,UAAU,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC9C,IAAI,CAAC,UAAU;QAAE,MAAM,IAAI,kBAAkB,CAAC,IAAI,CAAC,CAAC;IACpD,OAAO,eAAe,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;AAC3C,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare function humanBytes(n: bigint): string;
2
+ export declare function table(headers: string[], rows: string[][]): string;
3
+ //# sourceMappingURL=format.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AAEA,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAS5C;AAKD,wBAAgB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,MAAM,CAQjE"}
package/dist/format.js ADDED
@@ -0,0 +1,22 @@
1
+ // Human-readable byte size from a raw count. Binary units (KiB/MiB) to match how
2
+ // chunk sizes are reasoned about elsewhere. Exact byte counts stay in --json.
3
+ export function humanBytes(n) {
4
+ const units = ["B", "KiB", "MiB", "GiB", "TiB"];
5
+ let v = Number(n);
6
+ let u = 0;
7
+ while (v >= 1024 && u < units.length - 1) {
8
+ v /= 1024;
9
+ u++;
10
+ }
11
+ return u === 0 ? `${v} B` : `${v.toFixed(1)} ${units[u]}`;
12
+ }
13
+ // Minimal fixed-width text table: a header row, a dashed rule, then the rows.
14
+ // Columns are sized to their widest cell. No dependency, no alignment beyond
15
+ // left-pad. `rows` may be empty (header + rule only).
16
+ export function table(headers, rows) {
17
+ const widths = headers.map((h, i) => Math.max(h.length, ...rows.map((r) => (r[i] ?? "").length)));
18
+ const fmt = (cells) => cells.map((c, i) => c.padEnd(widths[i])).join(" ");
19
+ const rule = widths.map((w) => "-".repeat(w)).join(" ");
20
+ return [fmt(headers), rule, ...rows.map(fmt)].join("\n");
21
+ }
22
+ //# sourceMappingURL=format.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,8EAA8E;AAC9E,MAAM,UAAU,UAAU,CAAC,CAAS;IAClC,MAAM,KAAK,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;IAChD,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IAClB,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,OAAO,CAAC,IAAI,IAAI,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzC,CAAC,IAAI,IAAI,CAAC;QACV,CAAC,EAAE,CAAC;IACN,CAAC;IACD,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AAC5D,CAAC;AAED,8EAA8E;AAC9E,6EAA6E;AAC7E,sDAAsD;AACtD,MAAM,UAAU,KAAK,CAAC,OAAiB,EAAE,IAAgB;IACvD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAClC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAC5D,CAAC;IACF,MAAM,GAAG,GAAG,CAAC,KAAe,EAAU,EAAE,CACtC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvD,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzD,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC3D,CAAC"}
@@ -0,0 +1,11 @@
1
+ export { Client } from "./client.js";
2
+ export type { ClientOptions, StreamOptions } from "./client.js";
3
+ export { HttpStore } from "@saga-sync/core";
4
+ export type { Store } from "@saga-sync/core";
5
+ export { decodeAndVerify, fetchChunkFrom, ChunkNotFoundError } from "./fetch.js";
6
+ export { verifyDigest, DigestMismatchError } from "./verify.js";
7
+ export { loadManifest } from "./manifest.js";
8
+ export type { ChunkMeta, ManifestData, LoadManifestOptions } from "./manifest.js";
9
+ export { verifyManifestSignature, ManifestSignatureError } from "@saga-sync/core";
10
+ export type { CanonicalEvent } from "@saga-sync/core";
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,YAAY,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAG7C,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAGlF,OAAO,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAElF,YAAY,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,16 @@
1
+ // @saga-sync/client — browser-safe library entry point. Everything reachable
2
+ // from here uses only web-standard APIs (fetch, DecompressionStream,
3
+ // TextDecoder, Uint8Array, @noble) and no node: built-ins — so a bundler can
4
+ // pull it into a browser app with no polyfills. The CLI and DiskStore are
5
+ // intentionally NOT re-exported here (Node-only); import them from their own
6
+ // modules. HttpStore, the manifest schema, and signature verification come from
7
+ // @saga-sync/core.
8
+ export { Client } from "./client.js";
9
+ export { HttpStore } from "@saga-sync/core";
10
+ // Read helpers and the errors a consumer handles.
11
+ export { decodeAndVerify, fetchChunkFrom, ChunkNotFoundError } from "./fetch.js";
12
+ export { verifyDigest, DigestMismatchError } from "./verify.js";
13
+ export { loadManifest } from "./manifest.js";
14
+ // Manifest signature verification (Ed25519) — consumers pin a public key.
15
+ export { verifyManifestSignature, ManifestSignatureError } from "@saga-sync/core";
16
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,qEAAqE;AACrE,6EAA6E;AAC7E,0EAA0E;AAC1E,6EAA6E;AAC7E,gFAAgF;AAChF,mBAAmB;AAEnB,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAG5C,kDAAkD;AAClD,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAG7C,0EAA0E;AAC1E,OAAO,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,17 @@
1
+ import type { Store } from "@saga-sync/core";
2
+ import { Manifest as PublisherManifest } from "@saga-sync/core";
3
+ import type { ChunkMeta } from "@saga-sync/core";
4
+ export type { ChunkMeta, ManifestData } from "@saga-sync/core";
5
+ export type LoadManifestOptions = {
6
+ publicKey?: string;
7
+ };
8
+ export declare function loadManifest(store: Store, key?: string, opts?: LoadManifestOptions): Promise<PublisherManifest>;
9
+ export declare function selectSealedChunks(chunks: ChunkMeta[], filter?: {
10
+ fromBlock?: bigint;
11
+ toBlock?: bigint;
12
+ }): ChunkMeta[];
13
+ export declare function selectHotHead(hot: ChunkMeta | undefined, filter?: {
14
+ fromBlock?: bigint;
15
+ toBlock?: bigint;
16
+ }): ChunkMeta | undefined;
17
+ //# sourceMappingURL=manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,QAAQ,IAAI,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAChE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAMjD,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/D,MAAM,MAAM,mBAAmB,GAAG;IAIhC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAMF,wBAAsB,YAAY,CAChC,KAAK,EAAE,KAAK,EACZ,GAAG,GAAE,MAAqB,EAC1B,IAAI,GAAE,mBAAwB,GAC7B,OAAO,CAAC,iBAAiB,CAAC,CAa5B;AAMD,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,SAAS,EAAE,EACnB,MAAM,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GACpD,SAAS,EAAE,CAUb;AAGD,wBAAgB,aAAa,CAC3B,GAAG,EAAE,SAAS,GAAG,SAAS,EAC1B,MAAM,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GACpD,SAAS,GAAG,SAAS,CASvB"}
@@ -0,0 +1,51 @@
1
+ import { Manifest as PublisherManifest } from "@saga-sync/core";
2
+ import { ManifestSignatureError, verifyManifestSignature } from "@saga-sync/core";
3
+ // Load and parse the manifest from a store. Throws if the manifest is absent
4
+ // (the publisher has not run yet, or the URL is wrong) or malformed. If a
5
+ // publicKey is supplied, the signature is verified first — over the raw bytes,
6
+ // before any of them are trusted.
7
+ export async function loadManifest(store, key = "index.json", opts = {}) {
8
+ const raw = await store.get(key);
9
+ if (!raw)
10
+ throw new Error(`manifest not found at key "${key}"`);
11
+ if (opts.publicKey) {
12
+ const sig = await store.get(`${key}.sig`);
13
+ if (!sig) {
14
+ throw new ManifestSignatureError(`manifest signature "${key}.sig" not found, but a public key was configured`);
15
+ }
16
+ verifyManifestSignature(raw, new TextDecoder().decode(sig).trim(), opts.publicKey);
17
+ }
18
+ return PublisherManifest.fromRaw(store, key, raw);
19
+ }
20
+ // Pure helper: filter a protocol's sealed chunks down to those overlapping
21
+ // the requested half-open [fromBlock, toBlock) window. Skip is by chunk range
22
+ // only — straddling chunks yield all their events (the caller does any per-
23
+ // event filtering).
24
+ export function selectSealedChunks(chunks, filter = {}) {
25
+ const from = filter.fromBlock;
26
+ const to = filter.toBlock;
27
+ return chunks.filter((c) => {
28
+ const cFrom = BigInt(c.fromBlock);
29
+ const cTo = BigInt(c.toBlock);
30
+ if (from !== undefined && cTo <= from)
31
+ return false; // chunk ends at or before window
32
+ if (to !== undefined && cFrom >= to)
33
+ return false; // chunk starts at or after window
34
+ return true;
35
+ });
36
+ }
37
+ // Pure helper: include the hot head only if it overlaps the window.
38
+ export function selectHotHead(hot, filter = {}) {
39
+ if (!hot)
40
+ return undefined;
41
+ const from = filter.fromBlock;
42
+ const to = filter.toBlock;
43
+ const hFrom = BigInt(hot.fromBlock);
44
+ const hTo = BigInt(hot.toBlock);
45
+ if (from !== undefined && hTo <= from)
46
+ return undefined;
47
+ if (to !== undefined && hFrom >= to)
48
+ return undefined;
49
+ return hot;
50
+ }
51
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,IAAI,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEhE,OAAO,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAclF,6EAA6E;AAC7E,0EAA0E;AAC1E,+EAA+E;AAC/E,kCAAkC;AAClC,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,KAAY,EACZ,MAAc,YAAY,EAC1B,OAA4B,EAAE;IAE9B,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACjC,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,GAAG,GAAG,CAAC,CAAC;IAChE,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QACnB,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,GAAG,MAAM,CAAC,CAAC;QAC1C,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,sBAAsB,CAC9B,uBAAuB,GAAG,kDAAkD,CAC7E,CAAC;QACJ,CAAC;QACD,uBAAuB,CAAC,GAAG,EAAE,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;IACrF,CAAC;IACD,OAAO,iBAAiB,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AACpD,CAAC;AAED,2EAA2E;AAC3E,8EAA8E;AAC9E,4EAA4E;AAC5E,oBAAoB;AACpB,MAAM,UAAU,kBAAkB,CAChC,MAAmB,EACnB,SAAmD,EAAE;IAErD,MAAM,IAAI,GAAG,MAAM,CAAC,SAAS,CAAC;IAC9B,MAAM,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC;IAC1B,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;QACzB,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QAClC,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;QAC9B,IAAI,IAAI,KAAK,SAAS,IAAI,GAAG,IAAI,IAAI;YAAE,OAAO,KAAK,CAAC,CAAC,iCAAiC;QACtF,IAAI,EAAE,KAAK,SAAS,IAAI,KAAK,IAAI,EAAE;YAAE,OAAO,KAAK,CAAC,CAAC,kCAAkC;QACrF,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;AACL,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,aAAa,CAC3B,GAA0B,EAC1B,SAAmD,EAAE;IAErD,IAAI,CAAC,GAAG;QAAE,OAAO,SAAS,CAAC;IAC3B,MAAM,IAAI,GAAG,MAAM,CAAC,SAAS,CAAC;IAC9B,MAAM,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC;IAC1B,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACpC,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAChC,IAAI,IAAI,KAAK,SAAS,IAAI,GAAG,IAAI,IAAI;QAAE,OAAO,SAAS,CAAC;IACxD,IAAI,EAAE,KAAK,SAAS,IAAI,KAAK,IAAI,EAAE;QAAE,OAAO,SAAS,CAAC;IACtD,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { ChunkMeta } from "@saga-sync/core";
2
+ import type { CanonicalEvent } from "@saga-sync/core";
3
+ export declare class DigestMismatchError extends Error {
4
+ readonly meta: ChunkMeta;
5
+ readonly expected: string;
6
+ readonly actual: string;
7
+ constructor(meta: ChunkMeta, expected: string, actual: string);
8
+ }
9
+ export declare function verifyDigest(meta: ChunkMeta, uncompressed: Uint8Array): void;
10
+ export declare class CanonicalFormError extends Error {
11
+ readonly meta: ChunkMeta;
12
+ constructor(meta: ChunkMeta, detail: string);
13
+ }
14
+ export declare function verifyChunkEvents(meta: ChunkMeta, events: CanonicalEvent[]): void;
15
+ //# sourceMappingURL=verify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAItD,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBACZ,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAS9D;AAKD,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,GAAG,IAAI,CAS5E;AAYD,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;gBACb,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM;CAK5C;AAMD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,cAAc,EAAE,GAAG,IAAI,CAyBjF"}
package/dist/verify.js ADDED
@@ -0,0 +1,70 @@
1
+ import { sha256Hex } from "@saga-sync/core";
2
+ // Thrown when a chunk's recomputed digest does not match the manifest. Carries
3
+ // both digests so the caller can log them; both are lower-case 0x-prefixed.
4
+ export class DigestMismatchError extends Error {
5
+ meta;
6
+ expected;
7
+ actual;
8
+ constructor(meta, expected, actual) {
9
+ super(`digest mismatch for ${meta.file}: expected ${expected}, got ${actual}`);
10
+ this.name = "DigestMismatchError";
11
+ this.meta = meta;
12
+ this.expected = expected;
13
+ this.actual = actual;
14
+ }
15
+ }
16
+ // Recompute the sha256 of the chunk's uncompressed JSONL bytes and compare to
17
+ // the manifest entry. Mandatory on every fetched chunk (cache hits included) —
18
+ // the whole point of the system is verifiable distribution.
19
+ export function verifyDigest(meta, uncompressed) {
20
+ if (meta.digest.type !== "sha256") {
21
+ throw new Error(`unsupported digest type ${meta.digest.type} for ${meta.file}`);
22
+ }
23
+ const expected = normalize(meta.digest.data);
24
+ const actual = sha256Hex(uncompressed);
25
+ if (expected !== actual) {
26
+ throw new DigestMismatchError(meta, expected, actual);
27
+ }
28
+ }
29
+ function normalize(hex) {
30
+ const s = hex.toLowerCase();
31
+ return s.startsWith("0x") ? s : `0x${s}`;
32
+ }
33
+ // Thrown when a chunk's events violate the canonical form (SPEC §3.3) the digest
34
+ // cannot catch on its own: out-of-range blocks, or a non-ascending order. The
35
+ // digest proves the bytes match the manifest; this proves the manifest author
36
+ // honored the ordering + range contract (defense against a buggy, even if
37
+ // trusted, producer).
38
+ export class CanonicalFormError extends Error {
39
+ meta;
40
+ constructor(meta, detail) {
41
+ super(`chunk ${meta.file} violates canonical form: ${detail}`);
42
+ this.name = "CanonicalFormError";
43
+ this.meta = meta;
44
+ }
45
+ }
46
+ // Validate the two §3.3 properties the digest does not *semantically* enforce:
47
+ // 1. every event's blockNumber is within the chunk's [fromBlock, toBlock) range
48
+ // 2. events are strictly ascending by (blockNumber, logIndex)
49
+ // Empty chunks pass trivially. Mandatory on every chunk, like the digest.
50
+ export function verifyChunkEvents(meta, events) {
51
+ const from = BigInt(meta.fromBlock);
52
+ const to = BigInt(meta.toBlock);
53
+ let prevBlock = -1n;
54
+ let prevLog = -1n;
55
+ let first = true;
56
+ for (const e of events) {
57
+ const block = BigInt(e.blockNumber);
58
+ const log = BigInt(e.logIndex);
59
+ if (block < from || block >= to) {
60
+ throw new CanonicalFormError(meta, `event at block ${e.blockNumber} is outside [${meta.fromBlock},${meta.toBlock})`);
61
+ }
62
+ if (!first && (block < prevBlock || (block === prevBlock && log <= prevLog))) {
63
+ throw new CanonicalFormError(meta, `events not strictly ascending by (blockNumber, logIndex) at block ${e.blockNumber}, logIndex ${e.logIndex}`);
64
+ }
65
+ prevBlock = block;
66
+ prevLog = log;
67
+ first = false;
68
+ }
69
+ }
70
+ //# sourceMappingURL=verify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.js","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,24 +1,38 @@
1
1
  {
2
2
  "name": "@saga-sync/client",
3
- "version": "0.0.0",
4
- "description": "",
5
- "main": "index.js",
6
- "keywords": [],
7
- "author": "",
8
- "license": "ISC",
9
- "devEngines": {
10
- "packageManager": {
11
- "name": "pnpm",
12
- "version": "^11.3.0",
13
- "onFail": "download"
14
- }
3
+ "version": "0.1.2",
4
+ "description": "Consumer library + CLI for saga-sync: fetch, verify, and stream published privacy-protocol state",
5
+ "license": "UNLICENSED",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/fatlabsxyz/saga-sync.git",
9
+ "directory": "packages/client"
15
10
  },
16
- "type": "module",
11
+ "homepage": "https://github.com/fatlabsxyz/saga-sync/tree/master/packages/client#readme",
12
+ "bugs": "https://github.com/fatlabsxyz/saga-sync/issues",
17
13
  "publishConfig": {
18
- "access": "public",
19
- "registry": "https://registry.npmjs.org"
14
+ "access": "public"
15
+ },
16
+ "type": "module",
17
+ "exports": {
18
+ ".": {
19
+ "types": "./dist/index.d.ts",
20
+ "default": "./dist/index.js"
21
+ }
22
+ },
23
+ "bin": {
24
+ "state-client": "dist/cli.js"
25
+ },
26
+ "files": [
27
+ "dist"
28
+ ],
29
+ "dependencies": {
30
+ "@saga-sync/core": "0.1.2"
31
+ },
32
+ "devDependencies": {
33
+ "@saga-sync/producer": "0.1.2"
20
34
  },
21
35
  "scripts": {
22
- "test": "echo \"Error: no test specified\" && exit 1"
36
+ "build": "tsc -b"
23
37
  }
24
38
  }