@xyo-network/xl1-rest-block-publisher 2.1.9 → 2.2.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 +14 -6
- package/dist/node/S3BlockPublishRunner.d.ts +1 -1
- package/dist/node/S3BlockPublishRunner.d.ts.map +1 -1
- package/dist/node/S3ChainStatePublishRunner.d.ts.map +1 -1
- package/dist/node/S3ChainStateViewer.d.ts.map +1 -1
- package/dist/node/S3IndexPublishRunner.d.ts.map +1 -1
- package/dist/node/encoding.d.ts +1 -1
- package/dist/node/encoding.d.ts.map +1 -1
- package/dist/node/index.mjs +40 -58
- package/dist/node/index.mjs.map +3 -3
- package/package.json +9 -10
package/README.md
CHANGED
|
@@ -16,11 +16,19 @@ Finalized blocks and completed steps never change, so the chain can be materiali
|
|
|
16
16
|
- **`S3ChainStatePublishRunner`** — the mutable chain state (the head pointer), targeting the chain-state bucket
|
|
17
17
|
|
|
18
18
|
```text
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
/
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
Finalized bucket (S3BlockPublishRunner):
|
|
20
|
+
block/number/<n>.json
|
|
21
|
+
block/hash/<hash>.json
|
|
22
|
+
payload/<hash>.json
|
|
23
|
+
manifest.json
|
|
24
|
+
|
|
25
|
+
Index bucket (S3IndexPublishRunner):
|
|
26
|
+
<family>/<level>/<index>.json ← completed frames only
|
|
27
|
+
manifest.json
|
|
28
|
+
head.json
|
|
29
|
+
|
|
30
|
+
Chain-state bucket (S3ChainStatePublishRunner):
|
|
31
|
+
chain/head.json
|
|
24
32
|
```
|
|
25
33
|
|
|
26
34
|
Bodies are pre-compressed at write time (brotli by default, gzip or none configurable) and stored with the matching `Content-Encoding` plus `application/json`, so HTTP clients decompress transparently — keys keep their `.json` extension. Finalized files get `Cache-Control: public, max-age=31536000, immutable`; the head pointer gets `must-revalidate`.
|
|
@@ -48,7 +56,7 @@ if (range) {
|
|
|
48
56
|
}
|
|
49
57
|
```
|
|
50
58
|
|
|
51
|
-
`sync(from)` resumes from a caller-supplied cursor — typically the block after the last published head pointer. Omitting `from` republishes from genesis, which is safe (idempotent — deterministic keys, immutable content) but slow, so re-running after a crash is always safe.
|
|
59
|
+
`sync(from)` resumes from a caller-supplied cursor — typically the block after the last published head pointer. Omitting `from` republishes from genesis, which is safe (idempotent — deterministic keys, immutable content) but slow, so re-running after a crash is always safe. Path builders and manifest schemas come from [`@xyo-network/xl1-network-model`](https://www.npmjs.com/package/@xyo-network/xl1-network-model); see [`STATIC_REST_LAYOUT.md`](../../../protocol/STATIC_REST_LAYOUT.md).
|
|
52
60
|
|
|
53
61
|
## Install
|
|
54
62
|
|
|
@@ -26,7 +26,7 @@ export interface S3BlockPublishRunnerParams extends S3ProviderParams {
|
|
|
26
26
|
}
|
|
27
27
|
/**
|
|
28
28
|
* Publishes finalized blocks (and their payloads) as the static REST file layout that
|
|
29
|
-
* `RestBlockViewer` reads (see
|
|
29
|
+
* `RestBlockViewer` reads (see `@xyo-network/xl1-network-model` static REST layout).
|
|
30
30
|
*
|
|
31
31
|
* Publishing is idempotent: keys are deterministic and contents immutable, so re-publishing
|
|
32
32
|
* any range is safe. `sync(from)` resumes from a caller-supplied cursor (typically the block
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"S3BlockPublishRunner.d.ts","sourceRoot":"","sources":["../../src/S3BlockPublishRunner.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"S3BlockPublishRunner.d.ts","sourceRoot":"","sources":["../../src/S3BlockPublishRunner.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,kBAAkB,EAAE,WAAW,EAAE,+BAA+B,EAAE,cAAc,EAAE,aAAa,EAChG,MAAM,+BAA+B,CAAA;AAOtC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC/D,OAAO,EACL,kBAAkB,EACnB,MAAM,yBAAyB,CAAA;AAEhC,wDAAwD;AACxD,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,cAAc,CAAA;IAC3B,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;CACd;AAED,2CAA2C;AAC3C,MAAM,WAAW,0BAA2B,SAAQ,gBAAgB;IAClE,sDAAsD;IACtD,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;OAGG;IACH,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,IAAI,CAAA;IAClD,qEAAqE;IACrE,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB;;;OAGG;IACH,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB;AAED;;;;;;;GAOG;AACH,qBACa,oBAAqB,SAAQ,kBAAkB,CAAC,0BAA0B,CAAE,YAAW,kBAAkB;IACpH,MAAM,CAAC,QAAQ,CAAC,cAAc,uBAA4B;IAC1D,MAAM,CAAC,QAAQ,CAAC,YAAY,kBAAuB;IACnD,MAAM,CAAC,QAAQ,CAAC,QAAQ,yBAA8B;IACtD,OAAO,uBAAsC;IAE7C,SAAS,CAAC,OAAO,CAAC,EAAE,WAAW,CAAA;IAE/B,IAAI,WAAW,IAAI,MAAM,CAExB;IAED,IAAI,gBAAgB,IAAI,MAAM,CAE7B;IAED,IAAI,MAAM,IAAI,WAAW,CAExB;IAEc,aAAa;IAK5B;;;;;;;;;;;;;;OAcG;IACG,gBAAgB,CAAC,KAAK,GAAE,cAA0C,GAAG,OAAO,CAAC,cAAc,CAAC;IAkBlG,sEAAsE;IAChE,QAAQ,CAAC,WAAW,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC;IAI7D,sFAAsF;IAChF,YAAY,CAAC,WAAW,EAAE,cAAc,GAAG,OAAO,CAAC,+BAA+B,GAAG,IAAI,CAAC;IAYhG,sFAAsF;IAChF,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAKtC;;;OAGG;IACG,IAAI,CAAC,IAAI,GAAE,cAA0C,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAsB3F,6FAA6F;IAC7F,OAAO,CAAC,MAAM;CAQf"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"S3ChainStatePublishRunner.d.ts","sourceRoot":"","sources":["../../src/S3ChainStatePublishRunner.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"S3ChainStatePublishRunner.d.ts","sourceRoot":"","sources":["../../src/S3ChainStatePublishRunner.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAEV,uBAAuB,EAAE,uBAAuB,EAAE,+BAA+B,EAClF,MAAM,+BAA+B,CAAA;AAItC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC/D,OAAO,EAAE,kBAAkB,EAAyB,MAAM,yBAAyB,CAAA;AAEnF,gDAAgD;AAChD,MAAM,WAAW,+BAAgC,SAAQ,gBAAgB;IACvE;;;OAGG;IACH,MAAM,CAAC,EAAE,uBAAuB,CAAA;CACjC;AAED;;;;;;;GAOG;AACH,qBACa,yBAA0B,SAAQ,kBAAkB,CAAC,+BAA+B,CAAE,YAAW,uBAAuB;IACnI,MAAM,CAAC,QAAQ,CAAC,cAAc,4BAAiC;IAC/D,MAAM,CAAC,QAAQ,CAAC,YAAY,kBAAuB;IACnD,MAAM,CAAC,QAAQ,CAAC,QAAQ,8BAAmC;IAC3D,OAAO,4BAA2C;IAElD,SAAS,CAAC,OAAO,CAAC,EAAE,uBAAuB,CAAA;IAE3C,IAAI,MAAM,IAAI,uBAAuB,CAEpC;IAEc,aAAa;IAK5B,8EAA8E;IACxE,WAAW,IAAI,OAAO,CAAC,+BAA+B,CAAC;CAM9D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"S3ChainStateViewer.d.ts","sourceRoot":"","sources":["../../src/S3ChainStateViewer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAA;
|
|
1
|
+
{"version":3,"file":"S3ChainStateViewer.d.ts","sourceRoot":"","sources":["../../src/S3ChainStateViewer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAA;AAG1C,OAAO,KAAK,EACV,gBAAgB,EAAE,+BAA+B,EAAE,cAAc,EAClE,MAAM,+BAA+B,CAAA;AAItC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAE5D,yCAAyC;AACzC,MAAM,WAAW,wBAAyB,SAAQ,gBAAgB;CAAG;AAErE;;;;;GAKG;AACH,qBACa,kBAAmB,SAAQ,kBAAkB,CAAC,wBAAwB,EAAE,gBAAgB,CAAC,WAAW,CAAC,CAChH,YAAW,gBAAgB;IAC3B,MAAM,CAAC,QAAQ,CAAC,cAAc,qBAA0B;IACxD,MAAM,CAAC,QAAQ,CAAC,YAAY,UAAK;IACjC,MAAM,CAAC,QAAQ,CAAC,QAAQ,uBAA4B;IACpD,OAAO,qBAAoC;IAE3C,8EAA8E;IACxE,YAAY,IAAI,OAAO,CAAC,+BAA+B,CAAC;IAOxD,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IAKjC,kBAAkB,IAAI,OAAO,CAAC,cAAc,CAAC;IAKnD,oFAAoF;IAC9E,eAAe,IAAI,OAAO,CAAC,+BAA+B,GAAG,SAAS,CAAC;CAI9E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"S3IndexPublishRunner.d.ts","sourceRoot":"","sources":["../../src/S3IndexPublishRunner.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"S3IndexPublishRunner.d.ts","sourceRoot":"","sources":["../../src/S3IndexPublishRunner.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EACA,WAAW,EAAkB,kBAAkB,EAAE,kBAAkB,EAAE,cAAc,EAC7F,cAAc,EACf,MAAM,+BAA+B,CAAA;AAatC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAC/D,OAAO,EACL,kBAAkB,EACnB,MAAM,yBAAyB,CAAA;AAsGhC,2CAA2C;AAC3C,MAAM,WAAW,0BAA2B,SAAQ,gBAAgB;IAClE,kHAAkH;IAClH,OAAO,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAA;IACjC;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;OAGG;IACH,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB;AAED;;;;;;;;;;;GAWG;AACH,qBACa,oBAAqB,SAAQ,kBAAkB,CAAC,0BAA0B,CAAE,YAAW,kBAAkB;IACpH,MAAM,CAAC,QAAQ,CAAC,cAAc,uBAA4B;IAC1D,MAAM,CAAC,QAAQ,CAAC,YAAY,kBAAuB;IACnD,MAAM,CAAC,QAAQ,CAAC,QAAQ,yBAA8B;IACtD,OAAO,uBAAsC;IAE7C,SAAS,CAAC,OAAO,CAAC,EAAE,WAAW,CAAA;IAE/B,IAAI,MAAM,IAAI,WAAW,CAExB;IAED,SAAS,KAAK,OAAO,IAAI,OAAO,UAAU,CAAC,KAAK,CAE/C;IAEc,aAAa;IAK5B,wGAAwG;IAClG,0BAA0B,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC;IAqBlF,6FAA6F;IACvF,YAAY,CAAC,MAAM,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUnG,0GAA0G;YAC5F,gBAAgB;IAsB9B,0GAA0G;YAC5F,aAAa;IAwB3B;;;;OAIG;YACW,SAAS;YAaT,aAAa;IAK3B,OAAO,CAAC,UAAU;YASJ,SAAS;YAKT,aAAa;CAS5B"}
|
package/dist/node/encoding.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export interface EncodedBody {
|
|
|
8
8
|
/**
|
|
9
9
|
* Encodes a JSON string for storage. Bodies are pre-compressed at write time and stored
|
|
10
10
|
* with the matching Content-Encoding so HTTP clients decompress transparently — keys keep
|
|
11
|
-
* their .
|
|
11
|
+
* their .JSON extension and Content-Type stays application/json.
|
|
12
12
|
*/
|
|
13
13
|
export declare function encodeBody(json: string, encoding: RestContentEncoding): EncodedBody;
|
|
14
14
|
/** Decodes a stored body back to its JSON string using the object's Content-Encoding. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"encoding.d.ts","sourceRoot":"","sources":["../../src/encoding.ts"],"names":[],"mappings":"AAEA,iDAAiD;AACjD,MAAM,MAAM,mBAAmB,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,CAAA;AAExD,oFAAoF;AACpF,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,UAAU,CAAA;IAChB,eAAe,CAAC,EAAE,IAAI,GAAG,MAAM,CAAA;CAChC;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,mBAAmB,GAAG,WAAW,
|
|
1
|
+
{"version":3,"file":"encoding.d.ts","sourceRoot":"","sources":["../../src/encoding.ts"],"names":[],"mappings":"AAEA,iDAAiD;AACjD,MAAM,MAAM,mBAAmB,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,CAAA;AAExD,oFAAoF;AACpF,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,UAAU,CAAA;IAChB,eAAe,CAAC,EAAE,IAAI,GAAG,MAAM,CAAA;CAChC;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,mBAAmB,GAAG,WAAW,CAanF;AAED,yFAAyF;AACzF,wBAAgB,UAAU,CAAC,IAAI,EAAE,UAAU,EAAE,eAAe,CAAC,EAAE,MAAM,GAAG,MAAM,CAa7E"}
|
package/dist/node/index.mjs
CHANGED
|
@@ -31,7 +31,8 @@ function encodeBody(json, encoding) {
|
|
|
31
31
|
return { body: ZLIB.gzipSync(json), contentEncoding: "gzip" };
|
|
32
32
|
}
|
|
33
33
|
case "none": {
|
|
34
|
-
|
|
34
|
+
const encoder = new TextEncoder();
|
|
35
|
+
return { body: encoder.encode(json) };
|
|
35
36
|
}
|
|
36
37
|
}
|
|
37
38
|
}
|
|
@@ -44,7 +45,8 @@ function decodeBody(body, contentEncoding) {
|
|
|
44
45
|
return ZLIB.gunzipSync(body).toString("utf8");
|
|
45
46
|
}
|
|
46
47
|
default: {
|
|
47
|
-
|
|
48
|
+
const decoder = new TextDecoder();
|
|
49
|
+
return decoder.decode(body);
|
|
48
50
|
}
|
|
49
51
|
}
|
|
50
52
|
}
|
|
@@ -108,20 +110,19 @@ var isNotFoundError = (error) => {
|
|
|
108
110
|
|
|
109
111
|
// src/S3BlockPublishRunner.ts
|
|
110
112
|
import { assertEx as assertEx2, isNull } from "@xylabs/sdk-js";
|
|
113
|
+
import {
|
|
114
|
+
blockHashPath,
|
|
115
|
+
blockNumberPath,
|
|
116
|
+
createChainManifest,
|
|
117
|
+
manifestPath,
|
|
118
|
+
payloadPath
|
|
119
|
+
} from "@xyo-network/xl1-network-model";
|
|
111
120
|
import {
|
|
112
121
|
asXL1BlockNumber,
|
|
113
122
|
BlockPublishRunnerMoniker,
|
|
114
123
|
BlockViewerMoniker
|
|
115
124
|
} from "@xyo-network/xl1-protocol-lib";
|
|
116
125
|
import { creatableProvider } from "@xyo-network/xl1-protocol-sdk";
|
|
117
|
-
import {
|
|
118
|
-
blockHashPath,
|
|
119
|
-
blockNumberPath,
|
|
120
|
-
CHAIN_LAYOUT_VERSION,
|
|
121
|
-
ChainManifestSchema,
|
|
122
|
-
manifestPath,
|
|
123
|
-
payloadPath
|
|
124
|
-
} from "@xyo-network/xl1-rest-block-viewer";
|
|
125
126
|
import { Semaphore } from "async-mutex";
|
|
126
127
|
var S3BlockPublishRunner = class extends AbstractS3Provider {
|
|
127
128
|
moniker = S3BlockPublishRunner.defaultMoniker;
|
|
@@ -165,7 +166,8 @@ var S3BlockPublishRunner = class extends AbstractS3Provider {
|
|
|
165
166
|
Array.from({ length: high - low + 1 }, (_, i) => this.hasBlock(asXL1BlockNumber(low + i, true)))
|
|
166
167
|
);
|
|
167
168
|
for (let blockNumber = high; blockNumber >= low; blockNumber--) {
|
|
168
|
-
|
|
169
|
+
const index = blockNumber - low;
|
|
170
|
+
if (present.at(index) === true) return asXL1BlockNumber(blockNumber + 1, true);
|
|
169
171
|
}
|
|
170
172
|
}
|
|
171
173
|
return floor;
|
|
@@ -188,19 +190,7 @@ var S3BlockPublishRunner = class extends AbstractS3Provider {
|
|
|
188
190
|
}
|
|
189
191
|
/** Publishes the finalized layout descriptor (idempotent; refreshed on each sync). */
|
|
190
192
|
async publishManifest() {
|
|
191
|
-
const manifest =
|
|
192
|
-
earliestBlock: 0,
|
|
193
|
-
encoding: this.contentEncoding,
|
|
194
|
-
// literal templates: a self-describing mirror of the path builders in xl1-rest-block-viewer
|
|
195
|
-
paths: {
|
|
196
|
-
blockByHash: "block/hash/{hash}.json",
|
|
197
|
-
blockByNumber: "block/number/{block}.json",
|
|
198
|
-
head: "chain/head.json",
|
|
199
|
-
payload: "payload/{hash}.json"
|
|
200
|
-
},
|
|
201
|
-
schema: ChainManifestSchema,
|
|
202
|
-
version: CHAIN_LAYOUT_VERSION
|
|
203
|
-
};
|
|
193
|
+
const manifest = createChainManifest(this.contentEncoding);
|
|
204
194
|
await this.putJson(manifestPath(), JSON.stringify(manifest), MANIFEST_CACHE_CONTROL);
|
|
205
195
|
}
|
|
206
196
|
/**
|
|
@@ -248,9 +238,9 @@ S3BlockPublishRunner = __decorateClass([
|
|
|
248
238
|
|
|
249
239
|
// src/S3ChainStatePublishRunner.ts
|
|
250
240
|
import { assertEx as assertEx3 } from "@xylabs/sdk-js";
|
|
241
|
+
import { headPath } from "@xyo-network/xl1-network-model";
|
|
251
242
|
import { BlockViewerMoniker as BlockViewerMoniker2, ChainStatePublishRunnerMoniker } from "@xyo-network/xl1-protocol-lib";
|
|
252
243
|
import { creatableProvider as creatableProvider2 } from "@xyo-network/xl1-protocol-sdk";
|
|
253
|
-
import { headPath } from "@xyo-network/xl1-rest-block-viewer";
|
|
254
244
|
var S3ChainStatePublishRunner = class extends AbstractS3Provider {
|
|
255
245
|
moniker = S3ChainStatePublishRunner.defaultMoniker;
|
|
256
246
|
_source;
|
|
@@ -278,9 +268,9 @@ S3ChainStatePublishRunner = __decorateClass([
|
|
|
278
268
|
|
|
279
269
|
// src/S3ChainStateViewer.ts
|
|
280
270
|
import { assertEx as assertEx4 } from "@xylabs/sdk-js";
|
|
271
|
+
import { headPath as headPath2 } from "@xyo-network/xl1-network-model";
|
|
281
272
|
import { asSignedHydratedBlockWithHashMeta, ChainStateViewerMoniker } from "@xyo-network/xl1-protocol-lib";
|
|
282
273
|
import { creatableProvider as creatableProvider3 } from "@xyo-network/xl1-protocol-sdk";
|
|
283
|
-
import { headPath as headPath2 } from "@xyo-network/xl1-rest-block-viewer";
|
|
284
274
|
var S3ChainStateViewer = class extends AbstractS3Provider {
|
|
285
275
|
moniker = S3ChainStateViewer.defaultMoniker;
|
|
286
276
|
/** The published head; throws when no head pointer has been published yet. */
|
|
@@ -291,10 +281,12 @@ var S3ChainStateViewer = class extends AbstractS3Provider {
|
|
|
291
281
|
}, this.context);
|
|
292
282
|
}
|
|
293
283
|
async currentBlockHash() {
|
|
294
|
-
|
|
284
|
+
const block = await this.currentBlock();
|
|
285
|
+
return block[0]._hash;
|
|
295
286
|
}
|
|
296
287
|
async currentBlockNumber() {
|
|
297
|
-
|
|
288
|
+
const block = await this.currentBlock();
|
|
289
|
+
return block[0].block;
|
|
298
290
|
}
|
|
299
291
|
/** The published head, or undefined when no head pointer has been published yet. */
|
|
300
292
|
async tryCurrentBlock() {
|
|
@@ -311,6 +303,14 @@ S3ChainStateViewer = __decorateClass([
|
|
|
311
303
|
|
|
312
304
|
// src/S3IndexPublishRunner.ts
|
|
313
305
|
import { assertEx as assertEx5 } from "@xylabs/sdk-js";
|
|
306
|
+
import {
|
|
307
|
+
asIndexHead,
|
|
308
|
+
createIndexHead,
|
|
309
|
+
createIndexManifest,
|
|
310
|
+
indexHeadPath,
|
|
311
|
+
indexManifestPath,
|
|
312
|
+
indexSummaryPath
|
|
313
|
+
} from "@xyo-network/xl1-network-model";
|
|
314
314
|
import {
|
|
315
315
|
asXL1BlockNumber as asXL1BlockNumber2,
|
|
316
316
|
asXL1BlockRange,
|
|
@@ -329,14 +329,6 @@ import {
|
|
|
329
329
|
transfersMaxStep,
|
|
330
330
|
transfersStepSummaryFromRange
|
|
331
331
|
} from "@xyo-network/xl1-protocol-sdk";
|
|
332
|
-
import {
|
|
333
|
-
INDEX_LAYOUT_VERSION,
|
|
334
|
-
indexHeadPath,
|
|
335
|
-
IndexHeadSchema,
|
|
336
|
-
indexManifestPath,
|
|
337
|
-
IndexManifestSchema,
|
|
338
|
-
indexSummaryPath
|
|
339
|
-
} from "@xyo-network/xl1-rest-block-viewer";
|
|
340
332
|
import { Semaphore as Semaphore2 } from "async-mutex";
|
|
341
333
|
var S3IndexSummaryMap = class {
|
|
342
334
|
family;
|
|
@@ -383,7 +375,7 @@ var S3IndexSummaryMap = class {
|
|
|
383
375
|
const blockNumber = await this.resolveBlockNumber(hash);
|
|
384
376
|
if (blockNumber === void 0) return void 0;
|
|
385
377
|
const stepIndex = (blockNumber + 1) / stepSize - 1;
|
|
386
|
-
return Number.
|
|
378
|
+
return Number.isSafeInteger(stepIndex) && stepIndex >= 0 ? indexSummaryPath(this.family, stepLevel, stepIndex) : void 0;
|
|
387
379
|
}
|
|
388
380
|
async pathForKey(key) {
|
|
389
381
|
const [hash, sizeText] = key.split("|");
|
|
@@ -406,7 +398,7 @@ var S3IndexPublishRunner = class extends AbstractS3Provider {
|
|
|
406
398
|
return assertEx5(this._source, () => "No source specified");
|
|
407
399
|
}
|
|
408
400
|
get fetchFn() {
|
|
409
|
-
return this.params.fetchFn ??
|
|
401
|
+
return this.params.fetchFn ?? fetch.bind(globalThis);
|
|
410
402
|
}
|
|
411
403
|
async createHandler() {
|
|
412
404
|
await super.createHandler();
|
|
@@ -416,7 +408,8 @@ var S3IndexPublishRunner = class extends AbstractS3Provider {
|
|
|
416
408
|
async publishCompletedFramesUpTo(ceiling) {
|
|
417
409
|
const head = await this.source.currentBlockNumber();
|
|
418
410
|
assertEx5(ceiling <= head, () => `Ceiling ${ceiling} exceeds source head ${head}`);
|
|
419
|
-
const
|
|
411
|
+
const existingWatermark = await this.readWatermark();
|
|
412
|
+
const previous = existingWatermark?.block ?? -1;
|
|
420
413
|
const families = {
|
|
421
414
|
balances: await this.publishFamily("balances", balancesMaxStep, balancesStepSummaryFromRange, previous, ceiling),
|
|
422
415
|
blocks: await this.publishFamily("blocks", blocksMaxStep, blocksStepSummaryFromRange, previous, ceiling),
|
|
@@ -502,7 +495,7 @@ var S3IndexPublishRunner = class extends AbstractS3Provider {
|
|
|
502
495
|
}
|
|
503
496
|
async readWatermark() {
|
|
504
497
|
const found = await this.getJson(indexHeadPath());
|
|
505
|
-
return found === void 0 ? void 0 : found;
|
|
498
|
+
return found === void 0 ? void 0 : asIndexHead(found, true);
|
|
506
499
|
}
|
|
507
500
|
summaryMap(family) {
|
|
508
501
|
return new S3IndexSummaryMap(
|
|
@@ -513,27 +506,16 @@ var S3IndexPublishRunner = class extends AbstractS3Provider {
|
|
|
513
506
|
);
|
|
514
507
|
}
|
|
515
508
|
async writeHead(watermark) {
|
|
516
|
-
const head =
|
|
517
|
-
schema: IndexHeadSchema,
|
|
518
|
-
version: INDEX_LAYOUT_VERSION,
|
|
519
|
-
block: watermark.block,
|
|
520
|
-
hash: watermark.hash,
|
|
521
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
522
|
-
families: watermark.families
|
|
523
|
-
};
|
|
509
|
+
const head = createIndexHead(watermark);
|
|
524
510
|
await this.putJson(indexHeadPath(), JSON.stringify(head), MUTABLE_CACHE_CONTROL);
|
|
525
511
|
}
|
|
526
512
|
async writeManifest() {
|
|
527
|
-
const manifest = {
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
schemas: { maxStep: schemasMaxStep, path: "schemas/{level}/{index}.json" },
|
|
534
|
-
transfers: { maxStep: transfersMaxStep, path: "transfers/{level}/{index}.json" }
|
|
535
|
-
}
|
|
536
|
-
};
|
|
513
|
+
const manifest = createIndexManifest({
|
|
514
|
+
balances: balancesMaxStep,
|
|
515
|
+
blocks: blocksMaxStep,
|
|
516
|
+
schemas: schemasMaxStep,
|
|
517
|
+
transfers: transfersMaxStep
|
|
518
|
+
});
|
|
537
519
|
await this.putJson(indexManifestPath(), JSON.stringify(manifest), MANIFEST_CACHE_CONTROL);
|
|
538
520
|
}
|
|
539
521
|
};
|
package/dist/node/index.mjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/AbstractS3Provider.ts", "../../src/encoding.ts", "../../src/S3BlockPublishRunner.ts", "../../src/S3ChainStatePublishRunner.ts", "../../src/S3ChainStateViewer.ts", "../../src/S3IndexPublishRunner.ts"],
|
|
4
|
-
"sourcesContent": ["import type { S3Client } from '@aws-sdk/client-s3'\nimport {\n GetObjectCommand, HeadObjectCommand, PutObjectCommand,\n} from '@aws-sdk/client-s3'\nimport { assertEx } from '@xylabs/sdk-js'\nimport type { CreatableProviderEventData, CreatableProviderParams } from '@xyo-network/xl1-protocol-sdk'\nimport { AbstractCreatableProvider } from '@xyo-network/xl1-protocol-sdk'\n\nimport type { RestContentEncoding } from './encoding.ts'\nimport { decodeBody, encodeBody } from './encoding.ts'\n\n/** Shared parameters for S3-backed providers: where and how files are stored. */\nexport interface S3ProviderParams extends CreatableProviderParams {\n bucket: string\n /** S3-compatible client pointed at the target endpoint (e.g. Cloudflare R2). */\n client: S3Client\n /** Storage/wire encoding for published files. Defaults to 'br' (brotli). */\n contentEncoding?: RestContentEncoding\n /** Optional key prefix, allowing the layout to live in a shared bucket. */\n prefix?: string\n}\n\n/** Finalized files never change once written. */\nexport const IMMUTABLE_CACHE_CONTROL = 'public, max-age=31536000, immutable'\n/**\n * The head pointer is rewritten as the chain advances. A small positive TTL plus\n * stale-while-revalidate keeps origin load low at high RPS while staying fresh \u2014 better\n * than `max-age=0` for a hot, frequently-read object. Used for the chain-state head and\n * the index watermark.\n */\nexport const MUTABLE_CACHE_CONTROL = 'public, max-age=5, stale-while-revalidate=30'\n/**\n * Manifests are mostly-static layout descriptors that change only when the layout evolves;\n * a short TTL lets a new layout propagate within minutes without per-request revalidation.\n */\nexport const MANIFEST_CACHE_CONTROL = 'public, max-age=300'\n\n/**\n * Base for providers targeting S3-compatible storage. Bodies are pre-compressed at write\n * time and stored with the matching Content-Encoding plus application/json, so HTTP clients\n * decompress transparently \u2014 keys keep their `.json` extension. Reads decode the stored\n * Content-Encoding back to JSON.\n */\nexport abstract class AbstractS3Provider<\n TParams extends S3ProviderParams = S3ProviderParams,\n TEventData extends CreatableProviderEventData = CreatableProviderEventData,\n> extends AbstractCreatableProvider<TParams, TEventData> {\n get bucket(): string {\n return assertEx(this.params.bucket, () => 'No bucket specified')\n }\n\n get client(): S3Client {\n return assertEx(this.params.client, () => 'No client specified')\n }\n\n get contentEncoding(): RestContentEncoding {\n return this.params.contentEncoding ?? 'br'\n }\n\n get prefix(): string {\n return this.params.prefix ?? ''\n }\n\n /** Reads and decodes a stored JSON file, or undefined when the key does not exist. */\n protected async getJson(path: string): Promise<unknown> {\n try {\n const response = await this.client.send(new GetObjectCommand({ Bucket: this.bucket, Key: `${this.prefix}${path}` }))\n const body = await response.Body?.transformToByteArray()\n if (body === undefined) return undefined\n return JSON.parse(decodeBody(body, response.ContentEncoding)) as unknown\n } catch (error) {\n if (isNotFoundError(error)) return undefined\n throw error\n }\n }\n\n /** True when the key exists, checked without fetching the body. */\n protected async hasJson(path: string): Promise<boolean> {\n try {\n await this.client.send(new HeadObjectCommand({ Bucket: this.bucket, Key: `${this.prefix}${path}` }))\n return true\n } catch (error) {\n if (isNotFoundError(error)) return false\n throw error\n }\n }\n\n protected async putJson(path: string, json: string, cacheControl: string): Promise<void> {\n const { body, contentEncoding } = encodeBody(json, this.contentEncoding)\n await this.client.send(new PutObjectCommand({\n Bucket: this.bucket,\n Key: `${this.prefix}${path}`,\n Body: body,\n CacheControl: cacheControl,\n ContentEncoding: contentEncoding,\n ContentType: 'application/json',\n }))\n }\n}\n\nconst isNotFoundError = (error: unknown): boolean => {\n if (typeof error !== 'object' || error === null) return false\n const { name, $metadata } = error as { $metadata?: { httpStatusCode?: number }; name?: string }\n return name === 'NoSuchKey' || name === 'NotFound' || $metadata?.httpStatusCode === 404\n}\n", "import ZLIB from 'node:zlib'\n\n/** Wire/storage encoding for published files. */\nexport type RestContentEncoding = 'br' | 'gzip' | 'none'\n\n/** An encoded file body plus the HTTP Content-Encoding it should be served with. */\nexport interface EncodedBody {\n body: Uint8Array\n contentEncoding?: 'br' | 'gzip'\n}\n\n/**\n * Encodes a JSON string for storage. Bodies are pre-compressed at write time and stored\n * with the matching Content-Encoding so HTTP clients decompress transparently \u2014 keys keep\n * their .json extension and Content-Type stays application/json.\n */\nexport function encodeBody(json: string, encoding: RestContentEncoding): EncodedBody {\n switch (encoding) {\n case 'br': {\n return { body: ZLIB.brotliCompressSync(json), contentEncoding: 'br' }\n }\n case 'gzip': {\n return { body: ZLIB.gzipSync(json), contentEncoding: 'gzip' }\n }\n case 'none': {\n return { body: new TextEncoder().encode(json) }\n }\n }\n}\n\n/** Decodes a stored body back to its JSON string using the object's Content-Encoding. */\nexport function decodeBody(body: Uint8Array, contentEncoding?: string): string {\n switch (contentEncoding) {\n case 'br': {\n return ZLIB.brotliDecompressSync(body).toString('utf8')\n }\n case 'gzip': {\n return ZLIB.gunzipSync(body).toString('utf8')\n }\n default: {\n return new TextDecoder().decode(body)\n }\n }\n}\n", "import { assertEx, isNull } from '@xylabs/sdk-js'\nimport type {\n BlockPublishRunner, BlockViewer, SignedHydratedBlockWithHashMeta, XL1BlockNumber, XL1BlockRange,\n} from '@xyo-network/xl1-protocol-lib'\nimport {\n asXL1BlockNumber, BlockPublishRunnerMoniker, BlockViewerMoniker,\n} from '@xyo-network/xl1-protocol-lib'\nimport { creatableProvider } from '@xyo-network/xl1-protocol-sdk'\nimport type { ChainManifest } from '@xyo-network/xl1-rest-block-viewer'\nimport {\n blockHashPath, blockNumberPath, CHAIN_LAYOUT_VERSION, ChainManifestSchema, manifestPath, payloadPath,\n} from '@xyo-network/xl1-rest-block-viewer'\nimport { Semaphore } from 'async-mutex'\n\nimport type { S3ProviderParams } from './AbstractS3Provider.ts'\nimport {\n AbstractS3Provider, IMMUTABLE_CACHE_CONTROL, MANIFEST_CACHE_CONTROL,\n} from './AbstractS3Provider.ts'\n\n/** A progress event emitted while publishing blocks. */\nexport interface BlockPublishProgress {\n blockNumber: XL1BlockNumber\n published: number\n total: number\n}\n\n/** Parameters for S3BlockPublishRunner. */\nexport interface S3BlockPublishRunnerParams extends S3ProviderParams {\n /** Maximum concurrent block publishes during sync. */\n concurrency?: number\n /**\n * Called every `progressInterval` blocks (and at pass completion). When omitted, the same\n * events are logged via the params logger so long backfills are observable out of the box.\n */\n onProgress?: (event: BlockPublishProgress) => void\n /** How many block publishes between progress reports during sync. */\n progressInterval?: number\n /**\n * The viewer to publish from (only finalized chains should be published). When omitted,\n * resolved from the locator via BlockViewerMoniker.\n */\n source?: BlockViewer\n}\n\n/**\n * Publishes finalized blocks (and their payloads) as the static REST file layout that\n * `RestBlockViewer` reads (see `paths.ts` in @xyo-network/xl1-rest-block-viewer).\n *\n * Publishing is idempotent: keys are deterministic and contents immutable, so re-publishing\n * any range is safe. `sync(from)` resumes from a caller-supplied cursor (typically the block\n * after the last published head); omitting it republishes from genesis, which is safe.\n */\n@creatableProvider()\nexport class S3BlockPublishRunner extends AbstractS3Provider<S3BlockPublishRunnerParams> implements BlockPublishRunner {\n static readonly defaultMoniker = BlockPublishRunnerMoniker\n static readonly dependencies = [BlockViewerMoniker]\n static readonly monikers = [BlockPublishRunnerMoniker]\n moniker = S3BlockPublishRunner.defaultMoniker\n\n protected _source?: BlockViewer\n\n get concurrency(): number {\n return this.params.concurrency ?? 8\n }\n\n get progressInterval(): number {\n return this.params.progressInterval ?? 100\n }\n\n get source(): BlockViewer {\n return assertEx(this._source, () => 'No source specified')\n }\n\n override async createHandler() {\n await super.createHandler()\n this._source = this.params.source ?? await this.locator.getInstance(BlockViewerMoniker)\n }\n\n /**\n * Finds where a catch-up sync should start: walks backwards from the source head probing\n * by-number paths (in batches of `concurrency`) until it finds an already published block,\n * never probing below `floor`, and returns the block after it.\n *\n * This is what makes resuming cheap after a bucket was primed externally (an importer\n * CLI) or after publishing was toggled off and on: already published blocks above a\n * stale or missing head pointer are skipped instead of republished.\n *\n * Scope: only the topmost contiguous gap is healed. The walk stops at the first published\n * block, so holes below it are not probed \u2014 deep verification belongs to an importer or\n * audit tool. The walk also trusts that whoever published a block also published its\n * payloads and step files. As a fast path, a missing genesis block with `floor` at\n * genesis is treated as an empty bucket (full backfill) without walking the whole range.\n */\n async findCatchUpStart(floor: XL1BlockNumber = asXL1BlockNumber(0, true)): Promise<XL1BlockNumber> {\n const sourceHead = await this.source.currentBlock()\n const end = sourceHead[0].block\n if (floor > end) return floor\n if (floor === 0 && !(await this.hasBlock(asXL1BlockNumber(0, true)))) return floor\n for (let high: number = end; high >= floor; high -= this.concurrency) {\n const low = Math.max(floor, high - this.concurrency + 1)\n const present = await Promise.all(\n Array.from({ length: high - low + 1 }, (_, i) => this.hasBlock(asXL1BlockNumber(low + i, true))),\n )\n for (let blockNumber = high; blockNumber >= low; blockNumber--) {\n if (present[blockNumber - low]) return asXL1BlockNumber(blockNumber + 1, true)\n }\n }\n return floor\n }\n\n /** True when the block is already published at its by-number path. */\n async hasBlock(blockNumber: XL1BlockNumber): Promise<boolean> {\n return await this.hasJson(blockNumberPath(blockNumber))\n }\n\n /** Publishes one block at its by-number and by-hash paths, plus its payload files. */\n async publishBlock(blockNumber: XL1BlockNumber): Promise<SignedHydratedBlockWithHashMeta | null> {\n const block = await this.source.blockByNumber(blockNumber)\n if (isNull(block)) return null\n const json = JSON.stringify(block)\n await this.putJson(blockNumberPath(block[0].block), json, IMMUTABLE_CACHE_CONTROL)\n await this.putJson(blockHashPath(block[0]._hash), json, IMMUTABLE_CACHE_CONTROL)\n for (const payload of block[1]) {\n await this.putJson(payloadPath(payload._hash), JSON.stringify(payload), IMMUTABLE_CACHE_CONTROL)\n }\n return block\n }\n\n /** Publishes the finalized layout descriptor (idempotent; refreshed on each sync). */\n async publishManifest(): Promise<void> {\n const manifest: ChainManifest = {\n earliestBlock: 0,\n encoding: this.contentEncoding,\n // literal templates: a self-describing mirror of the path builders in xl1-rest-block-viewer\n paths: {\n blockByHash: 'block/hash/{hash}.json',\n blockByNumber: 'block/number/{block}.json',\n head: 'chain/head.json',\n payload: 'payload/{hash}.json',\n },\n schema: ChainManifestSchema,\n version: CHAIN_LAYOUT_VERSION,\n }\n await this.putJson(manifestPath(), JSON.stringify(manifest), MANIFEST_CACHE_CONTROL)\n }\n\n /**\n * Publishes every block from `from` (inclusive, default genesis) through the source head.\n * Returns the published range, or null when already up to date.\n */\n async sync(from: XL1BlockNumber = asXL1BlockNumber(0, true)): Promise<XL1BlockRange | null> {\n const sourceHead = await this.source.currentBlock()\n const end = sourceHead[0].block\n if (from > end) return null\n await this.publishManifest()\n\n const semaphore = new Semaphore(this.concurrency)\n const numbers = Array.from({ length: end - from + 1 }, (_, i) => asXL1BlockNumber(from + i, true))\n const total = numbers.length\n let publishedCount = 0\n await Promise.all(numbers.map(blockNumber => semaphore.runExclusive(async () => {\n assertEx(await this.publishBlock(blockNumber), () => `Block not found in source [${blockNumber}]`)\n publishedCount += 1\n if (publishedCount % this.progressInterval === 0 || publishedCount === total) {\n this.report({\n blockNumber, published: publishedCount, total,\n })\n }\n })))\n return [from, end]\n }\n\n /** Emits a progress event to the onProgress callback, or logs it when no callback is set. */\n private report(event: BlockPublishProgress): void {\n const onProgress = this.params.onProgress\n if (onProgress) {\n onProgress(event)\n return\n }\n this.logger?.info(`S3BlockPublishRunner: published block ${event.blockNumber} (${event.published}/${event.total})`)\n }\n}\n", "import { assertEx } from '@xylabs/sdk-js'\nimport type {\n BlockViewer,\n ChainStatePublishRunner, ChainStateViewerMethods, SignedHydratedBlockWithHashMeta,\n} from '@xyo-network/xl1-protocol-lib'\nimport { BlockViewerMoniker, ChainStatePublishRunnerMoniker } from '@xyo-network/xl1-protocol-lib'\nimport { creatableProvider } from '@xyo-network/xl1-protocol-sdk'\nimport { headPath } from '@xyo-network/xl1-rest-block-viewer'\n\nimport type { S3ProviderParams } from './AbstractS3Provider.ts'\nimport { AbstractS3Provider, MUTABLE_CACHE_CONTROL } from './AbstractS3Provider.ts'\n\n/** Parameters for S3ChainStatePublishRunner. */\nexport interface S3ChainStatePublishRunnerParams extends S3ProviderParams {\n /**\n * Where the current head is read from (any BlockViewer satisfies this). When omitted,\n * resolved from the locator via BlockViewerMoniker.\n */\n source?: ChainStateViewerMethods\n}\n\n/**\n * Publishes the mutable chain state \u2014 the head pointer (`chain/head.json`) \u2014 that\n * `RestChainStateViewer` reads. This is the one mutable file in the REST layout, so it is\n * stored with must-revalidate caching and should target the chain-state bucket.\n *\n * Callers must publish the finalized files for a head before publishing the head itself,\n * so readers never see a head that references missing files.\n */\n@creatableProvider()\nexport class S3ChainStatePublishRunner extends AbstractS3Provider<S3ChainStatePublishRunnerParams> implements ChainStatePublishRunner {\n static readonly defaultMoniker = ChainStatePublishRunnerMoniker\n static readonly dependencies = [BlockViewerMoniker]\n static readonly monikers = [ChainStatePublishRunnerMoniker]\n moniker = S3ChainStatePublishRunner.defaultMoniker\n\n protected _source?: ChainStateViewerMethods\n\n get source(): ChainStateViewerMethods {\n return assertEx(this._source, () => 'No source specified')\n }\n\n override async createHandler() {\n await super.createHandler()\n this._source = this.params.source ?? await this.locator.getInstance<BlockViewer>(BlockViewerMoniker)\n }\n\n /** Publishes the source's current head to the mutable chain state pointer. */\n async publishHead(): Promise<SignedHydratedBlockWithHashMeta> {\n const head = await this.source.currentBlock()\n await this.putJson(headPath(), JSON.stringify(head), MUTABLE_CACHE_CONTROL)\n this.logger?.info(`S3ChainStatePublishRunner: published head ${head[0].block}`)\n return head\n }\n}\n", "import type { Hash } from '@xylabs/sdk-js'\nimport { assertEx } from '@xylabs/sdk-js'\nimport type {\n ChainStateViewer, SignedHydratedBlockWithHashMeta, XL1BlockNumber,\n} from '@xyo-network/xl1-protocol-lib'\nimport { asSignedHydratedBlockWithHashMeta, ChainStateViewerMoniker } from '@xyo-network/xl1-protocol-lib'\nimport { creatableProvider } from '@xyo-network/xl1-protocol-sdk'\nimport { headPath } from '@xyo-network/xl1-rest-block-viewer'\n\nimport type { S3ProviderParams } from './AbstractS3Provider.ts'\nimport { AbstractS3Provider } from './AbstractS3Provider.ts'\n\n/** Parameters for S3ChainStateViewer. */\nexport interface S3ChainStateViewerParams extends S3ProviderParams {}\n\n/**\n * A ChainStateViewer over the chain-state bucket, reading the published head pointer back\n * through the S3 API (authenticated, not the public HTTP layout \u2014 see RestChainStateViewer\n * for anonymous reads). This is how publishers learn their resume cursor: the head pointer\n * is only written after the finalized files it references exist.\n */\n@creatableProvider()\nexport class S3ChainStateViewer extends AbstractS3Provider<S3ChainStateViewerParams, ChainStateViewer['eventData']>\n implements ChainStateViewer {\n static readonly defaultMoniker = ChainStateViewerMoniker\n static readonly dependencies = []\n static readonly monikers = [ChainStateViewerMoniker]\n moniker = S3ChainStateViewer.defaultMoniker\n\n /** The published head; throws when no head pointer has been published yet. */\n async currentBlock(): Promise<SignedHydratedBlockWithHashMeta> {\n return await this.spanAsync('currentBlock', async () => {\n const parsed = assertEx(await this.getJson(headPath()), () => 'Head not found')\n return asSignedHydratedBlockWithHashMeta(parsed, true)\n }, this.context)\n }\n\n async currentBlockHash(): Promise<Hash> {\n return (await this.currentBlock())[0]._hash\n }\n\n async currentBlockNumber(): Promise<XL1BlockNumber> {\n return (await this.currentBlock())[0].block\n }\n\n /** The published head, or undefined when no head pointer has been published yet. */\n async tryCurrentBlock(): Promise<SignedHydratedBlockWithHashMeta | undefined> {\n const parsed = await this.getJson(headPath())\n return parsed === undefined ? undefined : asSignedHydratedBlockWithHashMeta(parsed, true)\n }\n}\n", "import type { Hash } from '@xylabs/sdk-js'\nimport { assertEx } from '@xylabs/sdk-js'\nimport type {\n AsyncMap, BlockViewer, CachingContext, IndexPublishRunner, IndexSummaryFamily, IndexWatermark, MapType,\n XL1BlockNumber, XL1BlockRange,\n} from '@xyo-network/xl1-protocol-lib'\nimport {\n asXL1BlockNumber, asXL1BlockRange, BlockViewerMoniker, IndexPublishRunnerMoniker, StepSizes,\n} from '@xyo-network/xl1-protocol-lib'\nimport {\n balancesMaxStep, balancesStepSummaryFromRange,\n blocksMaxStep, blocksStepSummaryFromRange,\n creatableProvider,\n schemasMaxStep, schemasStepSummaryFromRange,\n transfersMaxStep, transfersStepSummaryFromRange,\n} from '@xyo-network/xl1-protocol-sdk'\nimport type { IndexHead, IndexManifest } from '@xyo-network/xl1-rest-block-viewer'\nimport {\n INDEX_LAYOUT_VERSION,\n indexHeadPath, IndexHeadSchema, indexManifestPath, IndexManifestSchema, indexSummaryPath,\n} from '@xyo-network/xl1-rest-block-viewer'\nimport { Semaphore } from 'async-mutex'\n\nimport type { S3ProviderParams } from './AbstractS3Provider.ts'\nimport {\n AbstractS3Provider, IMMUTABLE_CACHE_CONTROL, MANIFEST_CACHE_CONTROL, MUTABLE_CACHE_CONTROL,\n} from './AbstractS3Provider.ts'\n\n/** The minimum shape the summary map needs to place a frame: its head hash and frame size. */\ninterface FramePlacement {\n hash: Hash\n stepSize: number\n}\n\n/** The signature shared by every `*StepSummaryFromRange` builder. */\ntype SummaryBuilder<T extends FramePlacement> = (\n context: CachingContext,\n semaphores: Semaphore[],\n blockViewer: BlockViewer,\n summaryMap: MapType<string, T>,\n range: XL1BlockRange,\n) => Promise<T>\n\n/**\n * A summary map backed by the index bucket. The builders cache completed frames here keyed by\n * `${frameHeadHash}|${frameSize}`; this map turns that key into the frame's `indexSummaryPath`\n * (resolving the head hash to a block number via the source viewer) so `get` reads the published\n * frame and `set` writes it \u2014 making the bucket itself the builders' frame cache, which gives\n * skip-if-present resume and cascading sub-frame writes for free.\n */\nclass S3IndexSummaryMap<T extends FramePlacement> implements AsyncMap<string, T> {\n private readonly family: IndexSummaryFamily\n private readonly numberCache = new Map<Hash, number>()\n private readonly read: (path: string) => Promise<unknown>\n private readonly source: BlockViewer\n private readonly write: (path: string, json: string) => Promise<void>\n\n constructor(\n family: IndexSummaryFamily,\n source: BlockViewer,\n read: (path: string) => Promise<unknown>,\n write: (path: string, json: string) => Promise<void>,\n ) {\n this.family = family\n this.source = source\n this.read = read\n this.write = write\n }\n\n clear(): void {\n this.numberCache.clear()\n }\n\n delete(_id: string): boolean {\n return false\n }\n\n async get(id: string): Promise<T | undefined> {\n const path = await this.pathForKey(id)\n if (path === undefined) return undefined\n const found = await this.read(path)\n return found === undefined ? undefined : (found as T)\n }\n\n async getMany(ids: string[]): Promise<T[]> {\n const found = await Promise.all(ids.map(id => this.get(id)))\n return found.flatMap(value => (value === undefined ? [] : [value]))\n }\n\n async has(id: string): Promise<boolean> {\n return (await this.get(id)) !== undefined\n }\n\n async set(id: string, data: T): Promise<void> {\n const path = (await this.pathForFrame(data.hash, data.stepSize)) ?? (await this.pathForKey(id))\n if (path === undefined) return\n await this.write(path, JSON.stringify(data))\n }\n\n async setMany(entries: [string, T][]): Promise<void> {\n await Promise.all(entries.map(([id, data]) => this.set(id, data)))\n }\n\n private async pathForFrame(hash: Hash, stepSize: number): Promise<string | undefined> {\n const stepLevel = StepSizes.indexOf(asXL1BlockNumber(stepSize, true))\n if (stepLevel === -1) return undefined\n const blockNumber = await this.resolveBlockNumber(hash)\n if (blockNumber === undefined) return undefined\n const stepIndex = (blockNumber + 1) / stepSize - 1\n return Number.isInteger(stepIndex) && stepIndex >= 0 ? indexSummaryPath(this.family, stepLevel, stepIndex) : undefined\n }\n\n private async pathForKey(key: string): Promise<string | undefined> {\n const [hash, sizeText] = key.split('|')\n return await this.pathForFrame(hash as Hash, Number(sizeText))\n }\n\n private async resolveBlockNumber(hash: Hash): Promise<number | undefined> {\n const cached = this.numberCache.get(hash)\n if (cached !== undefined) return cached\n const block = await this.source.blockByHash(hash)\n if (!block) return undefined\n const blockNumber = block[0].block\n this.numberCache.set(hash, blockNumber)\n return blockNumber\n }\n}\n\n/** Parameters for S3IndexPublishRunner. */\nexport interface S3IndexPublishRunnerParams extends S3ProviderParams {\n /** Optional fetch override for CDN frame reads (custom agents, auth headers, tests). Defaults to global fetch. */\n fetchFn?: typeof globalThis.fetch\n /**\n * Base URL of the index files served over HTTP (a CDN / public R2 domain). When set, the runner\n * READS already-published frames through it \u2014 cheap, cached, immutable \u2014 instead of the S3 API,\n * falling back to the S3 API only on a read error. A miss (404) is treated as not-yet-published,\n * so the caller rebuilds it. Writes and the head watermark always go through the S3 API.\n */\n readBaseUrl?: string\n /**\n * The viewer to build the index from (only finalized chains should be indexed). When omitted,\n * resolved from the locator via BlockViewerMoniker.\n */\n source?: BlockViewer\n}\n\n/**\n * Publishes the multi-family chain index (blocks, balances, schemas, transfers) as the static\n * REST file layout that `RestIndexViewer` reads. Frames are immutable: only complete frames are\n * ever published, and a completed frame never changes. The runner reads blocks from its source\n * viewer (MongoDB, or the finalized/chain-state buckets via CDN) and writes summaries to the\n * index bucket; the head watermark and manifest are written last so a reader never sees a\n * watermark pointing past the frames that back it.\n *\n * When `readBaseUrl` is set, already-published frames are read back through the CDN (immutable,\n * cached) instead of the S3 API, so resume / skip-if-present and cross-pass sub-frame reuse are\n * cheap cache hits rather than per-object S3 GETs \u2014 the bulk of the read cost during catch-up.\n */\n@creatableProvider()\nexport class S3IndexPublishRunner extends AbstractS3Provider<S3IndexPublishRunnerParams> implements IndexPublishRunner {\n static readonly defaultMoniker = IndexPublishRunnerMoniker\n static readonly dependencies = [BlockViewerMoniker]\n static readonly monikers = [IndexPublishRunnerMoniker]\n moniker = S3IndexPublishRunner.defaultMoniker\n\n protected _source?: BlockViewer\n\n get source(): BlockViewer {\n return assertEx(this._source, () => 'No source specified')\n }\n\n protected get fetchFn(): typeof globalThis.fetch {\n return this.params.fetchFn ?? globalThis.fetch.bind(globalThis)\n }\n\n override async createHandler() {\n await super.createHandler()\n this._source = this.params.source ?? await this.locator.getInstance(BlockViewerMoniker)\n }\n\n /** Builds every family's frames completed up to the ceiling, then writes the manifest and watermark. */\n async publishCompletedFramesUpTo(ceiling: XL1BlockNumber): Promise<IndexWatermark> {\n const head = await this.source.currentBlockNumber()\n assertEx(ceiling <= head, () => `Ceiling ${ceiling} exceeds source head ${head}`)\n const previous = (await this.readWatermark())?.block ?? -1\n const families: Record<IndexSummaryFamily, number> = {\n balances: await this.publishFamily('balances', balancesMaxStep, balancesStepSummaryFromRange, previous, ceiling),\n blocks: await this.publishFamily('blocks', blocksMaxStep, blocksStepSummaryFromRange, previous, ceiling),\n schemas: await this.publishFamily('schemas', schemasMaxStep, schemasStepSummaryFromRange, previous, ceiling),\n transfers: await this.publishFamily('transfers', transfersMaxStep, transfersStepSummaryFromRange, previous, ceiling),\n }\n const ceilingBlock = assertEx(await this.source.blockByNumber(ceiling), () => `Block not found for ceiling ${ceiling}`)\n const watermark: IndexWatermark = {\n block: ceiling, hash: ceilingBlock[0]._hash, families,\n }\n await this.writeManifest()\n await this.writeHead(watermark)\n this.logger?.info(`S3IndexPublishRunner: index complete through block ${ceiling}`)\n return watermark\n }\n\n /** Publishes one completed frame for a family (and any missing sub-frames it depends on). */\n async publishFrame(family: IndexSummaryFamily, stepLevel: number, stepIndex: number): Promise<void> {\n const size = StepSizes[stepLevel]\n const lastBlock = (stepIndex + 1) * size - 1\n const head = await this.source.currentBlockNumber()\n assertEx(lastBlock <= head, () => `Frame ${family} ${stepLevel}/${stepIndex} is not complete (head ${head})`)\n const range = asXL1BlockRange([stepIndex * size, lastBlock], true)\n await this.buildFamilyFrame(family, range)\n this.logger?.info(`S3IndexPublishRunner: published frame ${family} ${stepLevel}/${stepIndex}`)\n }\n\n /** Dispatches a single frame to its family builder, writing it (and missing sub-frames) to the bucket. */\n private async buildFamilyFrame(family: IndexSummaryFamily, range: XL1BlockRange): Promise<void> {\n const semaphores = StepSizes.map(() => new Semaphore(20))\n switch (family) {\n case 'balances': {\n await balancesStepSummaryFromRange(this.context, semaphores, this.source, this.summaryMap('balances'), range)\n break\n }\n case 'blocks': {\n await blocksStepSummaryFromRange(this.context, semaphores, this.source, this.summaryMap('blocks'), range)\n break\n }\n case 'schemas': {\n await schemasStepSummaryFromRange(this.context, semaphores, this.source, this.summaryMap('schemas'), range)\n break\n }\n case 'transfers': {\n await transfersStepSummaryFromRange(this.context, semaphores, this.source, this.summaryMap('transfers'), range)\n break\n }\n }\n }\n\n /** Builds a family's frames in (previous, ceiling] across every level; returns total completed frames. */\n private async publishFamily<T extends FramePlacement>(\n family: IndexSummaryFamily,\n maxStep: number,\n build: SummaryBuilder<T>,\n previous: number,\n ceiling: number,\n ): Promise<number> {\n const map = this.summaryMap<T>(family)\n const semaphores = StepSizes.map(() => new Semaphore(20))\n let completed = 0\n // Bottom-up so a level's sub-frames exist (in the bucket) before the level above is built.\n for (let stepLevel = 0; stepLevel <= maxStep; stepLevel++) {\n const size = StepSizes[stepLevel]\n const fromIndex = Math.floor((previous + 1) / size)\n const toIndex = Math.floor((ceiling + 1) / size)\n completed += toIndex\n for (let stepIndex = fromIndex; stepIndex < toIndex; stepIndex++) {\n const start = stepIndex * size\n await build(this.context, semaphores, this.source, map, asXL1BlockRange([start, start + size - 1], true))\n }\n }\n return completed\n }\n\n /**\n * Reads an already-published frame. Through the CDN (`readBaseUrl`) when configured \u2014 cheap and\n * cache-friendly for immutable frames \u2014 falling back to the S3 API only on a read error; a CDN\n * miss (404) is treated as not-yet-published so the caller rebuilds it. Otherwise reads via S3.\n */\n private async readFrame(path: string): Promise<unknown> {\n const base = this.params.readBaseUrl\n if (base === undefined) return await this.getJson(path)\n try {\n const response = await this.fetchFn(`${base}/${path}`)\n if (response.status === 404) return undefined\n if (response.ok) return await response.json()\n return await this.getJson(path)\n } catch {\n return await this.getJson(path)\n }\n }\n\n private async readWatermark(): Promise<IndexHead | undefined> {\n const found = await this.getJson(indexHeadPath())\n return found === undefined ? undefined : (found as IndexHead)\n }\n\n private summaryMap<T extends FramePlacement>(family: IndexSummaryFamily): S3IndexSummaryMap<T> {\n return new S3IndexSummaryMap<T>(\n family,\n this.source,\n path => this.readFrame(path),\n (path, json) => this.putJson(path, json, IMMUTABLE_CACHE_CONTROL),\n )\n }\n\n private async writeHead(watermark: IndexWatermark): Promise<void> {\n const head: IndexHead = {\n schema: IndexHeadSchema,\n version: INDEX_LAYOUT_VERSION,\n block: watermark.block,\n hash: watermark.hash,\n updatedAt: new Date().toISOString(),\n families: watermark.families,\n }\n await this.putJson(indexHeadPath(), JSON.stringify(head), MUTABLE_CACHE_CONTROL)\n }\n\n private async writeManifest(): Promise<void> {\n const manifest: IndexManifest = {\n schema: IndexManifestSchema,\n version: INDEX_LAYOUT_VERSION,\n families: {\n balances: { maxStep: balancesMaxStep, path: 'balances/{level}/{index}.json' },\n blocks: { maxStep: blocksMaxStep, path: 'blocks/{level}/{index}.json' },\n schemas: { maxStep: schemasMaxStep, path: 'schemas/{level}/{index}.json' },\n transfers: { maxStep: transfersMaxStep, path: 'transfers/{level}/{index}.json' },\n },\n }\n await this.putJson(indexManifestPath(), JSON.stringify(manifest), MANIFEST_CACHE_CONTROL)\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["assertEx", "assertEx", "assertEx", "BlockViewerMoniker", "creatableProvider", "assertEx", "BlockViewerMoniker", "creatableProvider", "assertEx", "
|
|
4
|
+
"sourcesContent": ["import type { S3Client } from '@aws-sdk/client-s3'\nimport {\n GetObjectCommand, HeadObjectCommand, PutObjectCommand,\n} from '@aws-sdk/client-s3'\nimport { assertEx } from '@xylabs/sdk-js'\nimport type { CreatableProviderEventData, CreatableProviderParams } from '@xyo-network/xl1-protocol-sdk'\nimport { AbstractCreatableProvider } from '@xyo-network/xl1-protocol-sdk'\n\nimport type { RestContentEncoding } from './encoding.ts'\nimport { decodeBody, encodeBody } from './encoding.ts'\n\n/** Shared parameters for S3-backed providers: where and how files are stored. */\nexport interface S3ProviderParams extends CreatableProviderParams {\n bucket: string\n /** S3-compatible client pointed at the target endpoint (e.g. Cloudflare R2). */\n client: S3Client\n /** Storage/wire encoding for published files. Defaults to 'br' (brotli). */\n contentEncoding?: RestContentEncoding\n /** Optional key prefix, allowing the layout to live in a shared bucket. */\n prefix?: string\n}\n\n/** Finalized files never change once written. */\nexport const IMMUTABLE_CACHE_CONTROL = 'public, max-age=31536000, immutable'\n/**\n * The head pointer is rewritten as the chain advances. A small positive TTL plus\n * stale-while-revalidate keeps origin load low at high RPS while staying fresh \u2014 better\n * than `max-age=0` for a hot, frequently-read object. Used for the chain-state head and\n * the index watermark.\n */\nexport const MUTABLE_CACHE_CONTROL = 'public, max-age=5, stale-while-revalidate=30'\n/**\n * Manifests are mostly-static layout descriptors that change only when the layout evolves;\n * a short TTL lets a new layout propagate within minutes without per-request revalidation.\n */\nexport const MANIFEST_CACHE_CONTROL = 'public, max-age=300'\n\n/**\n * Base for providers targeting S3-compatible storage. Bodies are pre-compressed at write\n * time and stored with the matching Content-Encoding plus application/json, so HTTP clients\n * decompress transparently \u2014 keys keep their `.json` extension. Reads decode the stored\n * Content-Encoding back to JSON.\n */\nexport abstract class AbstractS3Provider<\n TParams extends S3ProviderParams = S3ProviderParams,\n TEventData extends CreatableProviderEventData = CreatableProviderEventData,\n> extends AbstractCreatableProvider<TParams, TEventData> {\n get bucket(): string {\n return assertEx(this.params.bucket, () => 'No bucket specified')\n }\n\n get client(): S3Client {\n return assertEx(this.params.client, () => 'No client specified')\n }\n\n get contentEncoding(): RestContentEncoding {\n return this.params.contentEncoding ?? 'br'\n }\n\n get prefix(): string {\n return this.params.prefix ?? ''\n }\n\n /** Reads and decodes a stored JSON file, or undefined when the key does not exist. */\n protected async getJson(path: string): Promise<unknown> {\n try {\n const response = await this.client.send(new GetObjectCommand({ Bucket: this.bucket, Key: `${this.prefix}${path}` }))\n const body = await response.Body?.transformToByteArray()\n if (body === undefined) return undefined\n return JSON.parse(decodeBody(body, response.ContentEncoding)) as unknown\n } catch (error) {\n if (isNotFoundError(error)) return undefined\n throw error\n }\n }\n\n /** True when the key exists, checked without fetching the body. */\n protected async hasJson(path: string): Promise<boolean> {\n try {\n await this.client.send(new HeadObjectCommand({ Bucket: this.bucket, Key: `${this.prefix}${path}` }))\n return true\n } catch (error) {\n if (isNotFoundError(error)) return false\n throw error\n }\n }\n\n protected async putJson(path: string, json: string, cacheControl: string): Promise<void> {\n const { body, contentEncoding } = encodeBody(json, this.contentEncoding)\n await this.client.send(new PutObjectCommand({\n Bucket: this.bucket,\n Key: `${this.prefix}${path}`,\n Body: body,\n CacheControl: cacheControl,\n ContentEncoding: contentEncoding,\n ContentType: 'application/json',\n }))\n }\n}\n\nconst isNotFoundError = (error: unknown): boolean => {\n if (typeof error !== 'object' || error === null) return false\n const { name, $metadata } = error as { $metadata?: { httpStatusCode?: number }; name?: string }\n return name === 'NoSuchKey' || name === 'NotFound' || $metadata?.httpStatusCode === 404\n}\n", "import ZLIB from 'node:zlib'\n\n/** Wire/storage encoding for published files. */\nexport type RestContentEncoding = 'br' | 'gzip' | 'none'\n\n/** An encoded file body plus the HTTP Content-Encoding it should be served with. */\nexport interface EncodedBody {\n body: Uint8Array\n contentEncoding?: 'br' | 'gzip'\n}\n\n/**\n * Encodes a JSON string for storage. Bodies are pre-compressed at write time and stored\n * with the matching Content-Encoding so HTTP clients decompress transparently \u2014 keys keep\n * their .JSON extension and Content-Type stays application/json.\n */\nexport function encodeBody(json: string, encoding: RestContentEncoding): EncodedBody {\n switch (encoding) {\n case 'br': {\n return { body: ZLIB.brotliCompressSync(json), contentEncoding: 'br' }\n }\n case 'gzip': {\n return { body: ZLIB.gzipSync(json), contentEncoding: 'gzip' }\n }\n case 'none': {\n const encoder = new TextEncoder()\n return { body: encoder.encode(json) }\n }\n }\n}\n\n/** Decodes a stored body back to its JSON string using the object's Content-Encoding. */\nexport function decodeBody(body: Uint8Array, contentEncoding?: string): string {\n switch (contentEncoding) {\n case 'br': {\n return ZLIB.brotliDecompressSync(body).toString('utf8')\n }\n case 'gzip': {\n return ZLIB.gunzipSync(body).toString('utf8')\n }\n default: {\n const decoder = new TextDecoder()\n return decoder.decode(body)\n }\n }\n}\n", "import { assertEx, isNull } from '@xylabs/sdk-js'\nimport {\n blockHashPath, blockNumberPath, createChainManifest, manifestPath, payloadPath,\n} from '@xyo-network/xl1-network-model'\nimport type {\n BlockPublishRunner, BlockViewer, SignedHydratedBlockWithHashMeta, XL1BlockNumber, XL1BlockRange,\n} from '@xyo-network/xl1-protocol-lib'\nimport {\n asXL1BlockNumber, BlockPublishRunnerMoniker, BlockViewerMoniker,\n} from '@xyo-network/xl1-protocol-lib'\nimport { creatableProvider } from '@xyo-network/xl1-protocol-sdk'\nimport { Semaphore } from 'async-mutex'\n\nimport type { S3ProviderParams } from './AbstractS3Provider.ts'\nimport {\n AbstractS3Provider, IMMUTABLE_CACHE_CONTROL, MANIFEST_CACHE_CONTROL,\n} from './AbstractS3Provider.ts'\n\n/** A progress event emitted while publishing blocks. */\nexport interface BlockPublishProgress {\n blockNumber: XL1BlockNumber\n published: number\n total: number\n}\n\n/** Parameters for S3BlockPublishRunner. */\nexport interface S3BlockPublishRunnerParams extends S3ProviderParams {\n /** Maximum concurrent block publishes during sync. */\n concurrency?: number\n /**\n * Called every `progressInterval` blocks (and at pass completion). When omitted, the same\n * events are logged via the params logger so long backfills are observable out of the box.\n */\n onProgress?: (event: BlockPublishProgress) => void\n /** How many block publishes between progress reports during sync. */\n progressInterval?: number\n /**\n * The viewer to publish from (only finalized chains should be published). When omitted,\n * resolved from the locator via BlockViewerMoniker.\n */\n source?: BlockViewer\n}\n\n/**\n * Publishes finalized blocks (and their payloads) as the static REST file layout that\n * `RestBlockViewer` reads (see `@xyo-network/xl1-network-model` static REST layout).\n *\n * Publishing is idempotent: keys are deterministic and contents immutable, so re-publishing\n * any range is safe. `sync(from)` resumes from a caller-supplied cursor (typically the block\n * after the last published head); omitting it republishes from genesis, which is safe.\n */\n@creatableProvider()\nexport class S3BlockPublishRunner extends AbstractS3Provider<S3BlockPublishRunnerParams> implements BlockPublishRunner {\n static readonly defaultMoniker = BlockPublishRunnerMoniker\n static readonly dependencies = [BlockViewerMoniker]\n static readonly monikers = [BlockPublishRunnerMoniker]\n moniker = S3BlockPublishRunner.defaultMoniker\n\n protected _source?: BlockViewer\n\n get concurrency(): number {\n return this.params.concurrency ?? 8\n }\n\n get progressInterval(): number {\n return this.params.progressInterval ?? 100\n }\n\n get source(): BlockViewer {\n return assertEx(this._source, () => 'No source specified')\n }\n\n override async createHandler() {\n await super.createHandler()\n this._source = this.params.source ?? await this.locator.getInstance(BlockViewerMoniker)\n }\n\n /**\n * Finds where a catch-up sync should start: walks backwards from the source head probing\n * by-number paths (in batches of `concurrency`) until it finds an already published block,\n * never probing below `floor`, and returns the block after it.\n *\n * This is what makes resuming cheap after a bucket was primed externally (an importer\n * CLI) or after publishing was toggled off and on: already published blocks above a\n * stale or missing head pointer are skipped instead of republished.\n *\n * Scope: only the topmost contiguous gap is healed. The walk stops at the first published\n * block, so holes below it are not probed \u2014 deep verification belongs to an importer or\n * audit tool. The walk also trusts that whoever published a block also published its\n * payloads and step files. As a fast path, a missing genesis block with `floor` at\n * genesis is treated as an empty bucket (full backfill) without walking the whole range.\n */\n async findCatchUpStart(floor: XL1BlockNumber = asXL1BlockNumber(0, true)): Promise<XL1BlockNumber> {\n const sourceHead = await this.source.currentBlock()\n const end = sourceHead[0].block\n if (floor > end) return floor\n if (floor === 0 && !(await this.hasBlock(asXL1BlockNumber(0, true)))) return floor\n for (let high: number = end; high >= floor; high -= this.concurrency) {\n const low = Math.max(floor, high - this.concurrency + 1)\n const present = await Promise.all(\n Array.from({ length: high - low + 1 }, (_, i) => this.hasBlock(asXL1BlockNumber(low + i, true))),\n )\n for (let blockNumber = high; blockNumber >= low; blockNumber--) {\n const index = blockNumber - low\n if (present.at(index) === true) return asXL1BlockNumber(blockNumber + 1, true)\n }\n }\n return floor\n }\n\n /** True when the block is already published at its by-number path. */\n async hasBlock(blockNumber: XL1BlockNumber): Promise<boolean> {\n return await this.hasJson(blockNumberPath(blockNumber))\n }\n\n /** Publishes one block at its by-number and by-hash paths, plus its payload files. */\n async publishBlock(blockNumber: XL1BlockNumber): Promise<SignedHydratedBlockWithHashMeta | null> {\n const block = await this.source.blockByNumber(blockNumber)\n if (isNull(block)) return null\n const json = JSON.stringify(block)\n await this.putJson(blockNumberPath(block[0].block), json, IMMUTABLE_CACHE_CONTROL)\n await this.putJson(blockHashPath(block[0]._hash), json, IMMUTABLE_CACHE_CONTROL)\n for (const payload of block[1]) {\n await this.putJson(payloadPath(payload._hash), JSON.stringify(payload), IMMUTABLE_CACHE_CONTROL)\n }\n return block\n }\n\n /** Publishes the finalized layout descriptor (idempotent; refreshed on each sync). */\n async publishManifest(): Promise<void> {\n const manifest = createChainManifest(this.contentEncoding)\n await this.putJson(manifestPath(), JSON.stringify(manifest), MANIFEST_CACHE_CONTROL)\n }\n\n /**\n * Publishes every block from `from` (inclusive, default genesis) through the source head.\n * Returns the published range, or null when already up to date.\n */\n async sync(from: XL1BlockNumber = asXL1BlockNumber(0, true)): Promise<XL1BlockRange | null> {\n const sourceHead = await this.source.currentBlock()\n const end = sourceHead[0].block\n if (from > end) return null\n await this.publishManifest()\n\n const semaphore = new Semaphore(this.concurrency)\n const numbers = Array.from({ length: end - from + 1 }, (_, i) => asXL1BlockNumber(from + i, true))\n const total = numbers.length\n let publishedCount = 0\n await Promise.all(numbers.map(blockNumber => semaphore.runExclusive(async () => {\n assertEx(await this.publishBlock(blockNumber), () => `Block not found in source [${blockNumber}]`)\n publishedCount += 1\n if (publishedCount % this.progressInterval === 0 || publishedCount === total) {\n this.report({\n blockNumber, published: publishedCount, total,\n })\n }\n })))\n return [from, end]\n }\n\n /** Emits a progress event to the onProgress callback, or logs it when no callback is set. */\n private report(event: BlockPublishProgress): void {\n const onProgress = this.params.onProgress\n if (onProgress) {\n onProgress(event)\n return\n }\n this.logger?.info(`S3BlockPublishRunner: published block ${event.blockNumber} (${event.published}/${event.total})`)\n }\n}\n", "import { assertEx } from '@xylabs/sdk-js'\nimport { headPath } from '@xyo-network/xl1-network-model'\nimport type {\n BlockViewer,\n ChainStatePublishRunner, ChainStateViewerMethods, SignedHydratedBlockWithHashMeta,\n} from '@xyo-network/xl1-protocol-lib'\nimport { BlockViewerMoniker, ChainStatePublishRunnerMoniker } from '@xyo-network/xl1-protocol-lib'\nimport { creatableProvider } from '@xyo-network/xl1-protocol-sdk'\n\nimport type { S3ProviderParams } from './AbstractS3Provider.ts'\nimport { AbstractS3Provider, MUTABLE_CACHE_CONTROL } from './AbstractS3Provider.ts'\n\n/** Parameters for S3ChainStatePublishRunner. */\nexport interface S3ChainStatePublishRunnerParams extends S3ProviderParams {\n /**\n * Where the current head is read from (any BlockViewer satisfies this). When omitted,\n * resolved from the locator via BlockViewerMoniker.\n */\n source?: ChainStateViewerMethods\n}\n\n/**\n * Publishes the mutable chain state \u2014 the head pointer (`chain/head.json`) \u2014 that\n * `RestChainStateViewer` reads. This is the one mutable file in the REST layout, so it is\n * stored with must-revalidate caching and should target the chain-state bucket.\n *\n * Callers must publish the finalized files for a head before publishing the head itself,\n * so readers never see a head that references missing files.\n */\n@creatableProvider()\nexport class S3ChainStatePublishRunner extends AbstractS3Provider<S3ChainStatePublishRunnerParams> implements ChainStatePublishRunner {\n static readonly defaultMoniker = ChainStatePublishRunnerMoniker\n static readonly dependencies = [BlockViewerMoniker]\n static readonly monikers = [ChainStatePublishRunnerMoniker]\n moniker = S3ChainStatePublishRunner.defaultMoniker\n\n protected _source?: ChainStateViewerMethods\n\n get source(): ChainStateViewerMethods {\n return assertEx(this._source, () => 'No source specified')\n }\n\n override async createHandler() {\n await super.createHandler()\n this._source = this.params.source ?? await this.locator.getInstance<BlockViewer>(BlockViewerMoniker)\n }\n\n /** Publishes the source's current head to the mutable chain state pointer. */\n async publishHead(): Promise<SignedHydratedBlockWithHashMeta> {\n const head = await this.source.currentBlock()\n await this.putJson(headPath(), JSON.stringify(head), MUTABLE_CACHE_CONTROL)\n this.logger?.info(`S3ChainStatePublishRunner: published head ${head[0].block}`)\n return head\n }\n}\n", "import type { Hash } from '@xylabs/sdk-js'\nimport { assertEx } from '@xylabs/sdk-js'\nimport { headPath } from '@xyo-network/xl1-network-model'\nimport type {\n ChainStateViewer, SignedHydratedBlockWithHashMeta, XL1BlockNumber,\n} from '@xyo-network/xl1-protocol-lib'\nimport { asSignedHydratedBlockWithHashMeta, ChainStateViewerMoniker } from '@xyo-network/xl1-protocol-lib'\nimport { creatableProvider } from '@xyo-network/xl1-protocol-sdk'\n\nimport type { S3ProviderParams } from './AbstractS3Provider.ts'\nimport { AbstractS3Provider } from './AbstractS3Provider.ts'\n\n/** Parameters for S3ChainStateViewer. */\nexport interface S3ChainStateViewerParams extends S3ProviderParams {}\n\n/**\n * A ChainStateViewer over the chain-state bucket, reading the published head pointer back\n * through the S3 API (authenticated, not the public HTTP layout \u2014 see RestChainStateViewer\n * for anonymous reads). This is how publishers learn their resume cursor: the head pointer\n * is only written after the finalized files it references exist.\n */\n@creatableProvider()\nexport class S3ChainStateViewer extends AbstractS3Provider<S3ChainStateViewerParams, ChainStateViewer['eventData']>\n implements ChainStateViewer {\n static readonly defaultMoniker = ChainStateViewerMoniker\n static readonly dependencies = []\n static readonly monikers = [ChainStateViewerMoniker]\n moniker = S3ChainStateViewer.defaultMoniker\n\n /** The published head; throws when no head pointer has been published yet. */\n async currentBlock(): Promise<SignedHydratedBlockWithHashMeta> {\n return await this.spanAsync('currentBlock', async () => {\n const parsed = assertEx(await this.getJson(headPath()), () => 'Head not found')\n return asSignedHydratedBlockWithHashMeta(parsed, true)\n }, this.context)\n }\n\n async currentBlockHash(): Promise<Hash> {\n const block = await this.currentBlock()\n return block[0]._hash\n }\n\n async currentBlockNumber(): Promise<XL1BlockNumber> {\n const block = await this.currentBlock()\n return block[0].block\n }\n\n /** The published head, or undefined when no head pointer has been published yet. */\n async tryCurrentBlock(): Promise<SignedHydratedBlockWithHashMeta | undefined> {\n const parsed = await this.getJson(headPath())\n return parsed === undefined ? undefined : asSignedHydratedBlockWithHashMeta(parsed, true)\n }\n}\n", "import type { Hash } from '@xylabs/sdk-js'\nimport { assertEx } from '@xylabs/sdk-js'\nimport type { IndexHead } from '@xyo-network/xl1-network-model'\nimport {\n asIndexHead,\n createIndexHead,\n createIndexManifest,\n indexHeadPath,\n indexManifestPath,\n indexSummaryPath,\n} from '@xyo-network/xl1-network-model'\nimport type {\n AsyncMap, BlockViewer, CachingContext, IndexPublishRunner, IndexSummaryFamily, IndexWatermark, MapType,\n XL1BlockNumber, XL1BlockRange,\n} from '@xyo-network/xl1-protocol-lib'\nimport {\n asXL1BlockNumber, asXL1BlockRange, BlockViewerMoniker, IndexPublishRunnerMoniker, StepSizes,\n} from '@xyo-network/xl1-protocol-lib'\nimport {\n balancesMaxStep, balancesStepSummaryFromRange,\n blocksMaxStep, blocksStepSummaryFromRange,\n creatableProvider,\n schemasMaxStep, schemasStepSummaryFromRange,\n transfersMaxStep, transfersStepSummaryFromRange,\n} from '@xyo-network/xl1-protocol-sdk'\nimport { Semaphore } from 'async-mutex'\n\nimport type { S3ProviderParams } from './AbstractS3Provider.ts'\nimport {\n AbstractS3Provider, IMMUTABLE_CACHE_CONTROL, MANIFEST_CACHE_CONTROL, MUTABLE_CACHE_CONTROL,\n} from './AbstractS3Provider.ts'\n\n/** The minimum shape the summary map needs to place a frame: its head hash and frame size. */\ninterface FramePlacement {\n hash: Hash\n stepSize: number\n}\n\n/** The signature shared by every `*StepSummaryFromRange` builder. */\ntype SummaryBuilder<T extends FramePlacement> = (\n context: CachingContext,\n semaphores: Semaphore[],\n blockViewer: BlockViewer,\n summaryMap: MapType<string, T>,\n range: XL1BlockRange,\n) => Promise<T>\n\n/**\n * A summary map backed by the index bucket. The builders cache completed frames here keyed by\n * `${frameHeadHash}|${frameSize}`; this map turns that key into the frame's `indexSummaryPath`\n * (resolving the head hash to a block number via the source viewer) so `get` reads the published\n * frame and `set` writes it \u2014 making the bucket itself the builders' frame cache, which gives\n * skip-if-present resume and cascading sub-frame writes for free.\n */\nclass S3IndexSummaryMap<T extends FramePlacement> implements AsyncMap<string, T> {\n private readonly family: IndexSummaryFamily\n private readonly numberCache = new Map<Hash, number>()\n private readonly read: (path: string) => Promise<unknown>\n private readonly source: BlockViewer\n private readonly write: (path: string, json: string) => Promise<void>\n\n constructor(\n family: IndexSummaryFamily,\n source: BlockViewer,\n read: (path: string) => Promise<unknown>,\n write: (path: string, json: string) => Promise<void>,\n ) {\n this.family = family\n this.source = source\n this.read = read\n this.write = write\n }\n\n clear(): void {\n this.numberCache.clear()\n }\n\n delete(_id: string): boolean {\n return false\n }\n\n async get(id: string): Promise<T | undefined> {\n const path = await this.pathForKey(id)\n if (path === undefined) return undefined\n const found = await this.read(path)\n return found === undefined ? undefined : (found as T)\n }\n\n async getMany(ids: string[]): Promise<T[]> {\n const found = await Promise.all(ids.map(id => this.get(id)))\n return found.flatMap(value => (value === undefined ? [] : [value]))\n }\n\n async has(id: string): Promise<boolean> {\n return (await this.get(id)) !== undefined\n }\n\n async set(id: string, data: T): Promise<void> {\n const path = (await this.pathForFrame(data.hash, data.stepSize)) ?? (await this.pathForKey(id))\n if (path === undefined) return\n await this.write(path, JSON.stringify(data))\n }\n\n async setMany(entries: [string, T][]): Promise<void> {\n await Promise.all(entries.map(([id, data]) => this.set(id, data)))\n }\n\n private async pathForFrame(hash: Hash, stepSize: number): Promise<string | undefined> {\n const stepLevel = StepSizes.indexOf(asXL1BlockNumber(stepSize, true))\n if (stepLevel === -1) return undefined\n const blockNumber = await this.resolveBlockNumber(hash)\n if (blockNumber === undefined) return undefined\n const stepIndex = (blockNumber + 1) / stepSize - 1\n return Number.isSafeInteger(stepIndex) && stepIndex >= 0 ? indexSummaryPath(this.family, stepLevel, stepIndex) : undefined\n }\n\n private async pathForKey(key: string): Promise<string | undefined> {\n const [hash, sizeText] = key.split('|')\n return await this.pathForFrame(hash as Hash, Number(sizeText))\n }\n\n private async resolveBlockNumber(hash: Hash): Promise<number | undefined> {\n const cached = this.numberCache.get(hash)\n if (cached !== undefined) return cached\n const block = await this.source.blockByHash(hash)\n if (!block) return undefined\n const blockNumber = block[0].block\n this.numberCache.set(hash, blockNumber)\n return blockNumber\n }\n}\n\n/** Parameters for S3IndexPublishRunner. */\nexport interface S3IndexPublishRunnerParams extends S3ProviderParams {\n /** Optional fetch override for CDN frame reads (custom agents, auth headers, tests). Defaults to global fetch. */\n fetchFn?: typeof globalThis.fetch\n /**\n * Base URL of the index files served over HTTP (a CDN / public R2 domain). When set, the runner\n * READS already-published frames through it \u2014 cheap, cached, immutable \u2014 instead of the S3 API,\n * falling back to the S3 API only on a read error. A miss (404) is treated as not-yet-published,\n * so the caller rebuilds it. Writes and the head watermark always go through the S3 API.\n */\n readBaseUrl?: string\n /**\n * The viewer to build the index from (only finalized chains should be indexed). When omitted,\n * resolved from the locator via BlockViewerMoniker.\n */\n source?: BlockViewer\n}\n\n/**\n * Publishes the multi-family chain index (blocks, balances, schemas, transfers) as the static\n * REST file layout that `RestIndexViewer` reads. Frames are immutable: only complete frames are\n * ever published, and a completed frame never changes. The runner reads blocks from its source\n * viewer (MongoDB, or the finalized/chain-state buckets via CDN) and writes summaries to the\n * index bucket; the head watermark and manifest are written last so a reader never sees a\n * watermark pointing past the frames that back it.\n *\n * When `readBaseUrl` is set, already-published frames are read back through the CDN (immutable,\n * cached) instead of the S3 API, so resume / skip-if-present and cross-pass sub-frame reuse are\n * cheap cache hits rather than per-object S3 GETs \u2014 the bulk of the read cost during catch-up.\n */\n@creatableProvider()\nexport class S3IndexPublishRunner extends AbstractS3Provider<S3IndexPublishRunnerParams> implements IndexPublishRunner {\n static readonly defaultMoniker = IndexPublishRunnerMoniker\n static readonly dependencies = [BlockViewerMoniker]\n static readonly monikers = [IndexPublishRunnerMoniker]\n moniker = S3IndexPublishRunner.defaultMoniker\n\n protected _source?: BlockViewer\n\n get source(): BlockViewer {\n return assertEx(this._source, () => 'No source specified')\n }\n\n protected get fetchFn(): typeof globalThis.fetch {\n return this.params.fetchFn ?? fetch.bind(globalThis)\n }\n\n override async createHandler() {\n await super.createHandler()\n this._source = this.params.source ?? await this.locator.getInstance(BlockViewerMoniker)\n }\n\n /** Builds every family's frames completed up to the ceiling, then writes the manifest and watermark. */\n async publishCompletedFramesUpTo(ceiling: XL1BlockNumber): Promise<IndexWatermark> {\n const head = await this.source.currentBlockNumber()\n assertEx(ceiling <= head, () => `Ceiling ${ceiling} exceeds source head ${head}`)\n const existingWatermark = await this.readWatermark()\n const previous = existingWatermark?.block ?? -1\n const families: Record<IndexSummaryFamily, number> = {\n balances: await this.publishFamily('balances', balancesMaxStep, balancesStepSummaryFromRange, previous, ceiling),\n blocks: await this.publishFamily('blocks', blocksMaxStep, blocksStepSummaryFromRange, previous, ceiling),\n schemas: await this.publishFamily('schemas', schemasMaxStep, schemasStepSummaryFromRange, previous, ceiling),\n transfers: await this.publishFamily('transfers', transfersMaxStep, transfersStepSummaryFromRange, previous, ceiling),\n }\n const ceilingBlock = assertEx(await this.source.blockByNumber(ceiling), () => `Block not found for ceiling ${ceiling}`)\n const watermark: IndexWatermark = {\n block: ceiling, hash: ceilingBlock[0]._hash, families,\n }\n await this.writeManifest()\n await this.writeHead(watermark)\n this.logger?.info(`S3IndexPublishRunner: index complete through block ${ceiling}`)\n return watermark\n }\n\n /** Publishes one completed frame for a family (and any missing sub-frames it depends on). */\n async publishFrame(family: IndexSummaryFamily, stepLevel: number, stepIndex: number): Promise<void> {\n const size = StepSizes[stepLevel]\n const lastBlock = (stepIndex + 1) * size - 1\n const head = await this.source.currentBlockNumber()\n assertEx(lastBlock <= head, () => `Frame ${family} ${stepLevel}/${stepIndex} is not complete (head ${head})`)\n const range = asXL1BlockRange([stepIndex * size, lastBlock], true)\n await this.buildFamilyFrame(family, range)\n this.logger?.info(`S3IndexPublishRunner: published frame ${family} ${stepLevel}/${stepIndex}`)\n }\n\n /** Dispatches a single frame to its family builder, writing it (and missing sub-frames) to the bucket. */\n private async buildFamilyFrame(family: IndexSummaryFamily, range: XL1BlockRange): Promise<void> {\n const semaphores = StepSizes.map(() => new Semaphore(20))\n switch (family) {\n case 'balances': {\n await balancesStepSummaryFromRange(this.context, semaphores, this.source, this.summaryMap('balances'), range)\n break\n }\n case 'blocks': {\n await blocksStepSummaryFromRange(this.context, semaphores, this.source, this.summaryMap('blocks'), range)\n break\n }\n case 'schemas': {\n await schemasStepSummaryFromRange(this.context, semaphores, this.source, this.summaryMap('schemas'), range)\n break\n }\n case 'transfers': {\n await transfersStepSummaryFromRange(this.context, semaphores, this.source, this.summaryMap('transfers'), range)\n break\n }\n }\n }\n\n /** Builds a family's frames in (previous, ceiling] across every level; returns total completed frames. */\n private async publishFamily<T extends FramePlacement>(\n family: IndexSummaryFamily,\n maxStep: number,\n build: SummaryBuilder<T>,\n previous: number,\n ceiling: number,\n ): Promise<number> {\n const map = this.summaryMap<T>(family)\n const semaphores = StepSizes.map(() => new Semaphore(20))\n let completed = 0\n // Bottom-up so a level's sub-frames exist (in the bucket) before the level above is built.\n for (let stepLevel = 0; stepLevel <= maxStep; stepLevel++) {\n const size = StepSizes[stepLevel]\n const fromIndex = Math.floor((previous + 1) / size)\n const toIndex = Math.floor((ceiling + 1) / size)\n completed += toIndex\n for (let stepIndex = fromIndex; stepIndex < toIndex; stepIndex++) {\n const start = stepIndex * size\n await build(this.context, semaphores, this.source, map, asXL1BlockRange([start, start + size - 1], true))\n }\n }\n return completed\n }\n\n /**\n * Reads an already-published frame. Through the CDN (`readBaseUrl`) when configured \u2014 cheap and\n * cache-friendly for immutable frames \u2014 falling back to the S3 API only on a read error; a CDN\n * miss (404) is treated as not-yet-published so the caller rebuilds it. Otherwise reads via S3.\n */\n private async readFrame(path: string): Promise<unknown> {\n const base = this.params.readBaseUrl\n if (base === undefined) return await this.getJson(path)\n try {\n const response = await this.fetchFn(`${base}/${path}`)\n if (response.status === 404) return undefined\n if (response.ok) return await response.json()\n return await this.getJson(path)\n } catch {\n return await this.getJson(path)\n }\n }\n\n private async readWatermark(): Promise<IndexHead | undefined> {\n const found = await this.getJson(indexHeadPath())\n return found === undefined ? undefined : asIndexHead(found, true)\n }\n\n private summaryMap<T extends FramePlacement>(family: IndexSummaryFamily): S3IndexSummaryMap<T> {\n return new S3IndexSummaryMap<T>(\n family,\n this.source,\n path => this.readFrame(path),\n (path, json) => this.putJson(path, json, IMMUTABLE_CACHE_CONTROL),\n )\n }\n\n private async writeHead(watermark: IndexWatermark): Promise<void> {\n const head = createIndexHead(watermark)\n await this.putJson(indexHeadPath(), JSON.stringify(head), MUTABLE_CACHE_CONTROL)\n }\n\n private async writeManifest(): Promise<void> {\n const manifest = createIndexManifest({\n balances: balancesMaxStep,\n blocks: blocksMaxStep,\n schemas: schemasMaxStep,\n transfers: transfersMaxStep,\n })\n await this.putJson(indexManifestPath(), JSON.stringify(manifest), MANIFEST_CACHE_CONTROL)\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["assertEx", "assertEx", "assertEx", "BlockViewerMoniker", "creatableProvider", "assertEx", "BlockViewerMoniker", "creatableProvider", "assertEx", "headPath", "creatableProvider", "assertEx", "headPath", "creatableProvider", "assertEx", "asXL1BlockNumber", "BlockViewerMoniker", "creatableProvider", "Semaphore", "asXL1BlockNumber", "assertEx", "BlockViewerMoniker", "Semaphore", "creatableProvider"]
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "http://json.schemastore.org/package.json",
|
|
3
3
|
"name": "@xyo-network/xl1-rest-block-publisher",
|
|
4
|
-
"version": "2.1
|
|
4
|
+
"version": "2.2.1",
|
|
5
5
|
"description": "XYO Layer One static REST chain layout publisher",
|
|
6
6
|
"homepage": "https://xylabs.com",
|
|
7
7
|
"bugs": {
|
|
@@ -35,12 +35,12 @@
|
|
|
35
35
|
"README.md"
|
|
36
36
|
],
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@xyo-network/xl1-protocol-
|
|
39
|
-
"@xyo-network/xl1-protocol-
|
|
40
|
-
"@xyo-network/xl1-
|
|
38
|
+
"@xyo-network/xl1-protocol-lib": "~2.2.1",
|
|
39
|
+
"@xyo-network/xl1-protocol-sdk": "~2.2.1",
|
|
40
|
+
"@xyo-network/xl1-network-model": "~2.2.1"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
|
-
"@aws-sdk/client-s3": "^3.
|
|
43
|
+
"@aws-sdk/client-s3": "^3.1070.0",
|
|
44
44
|
"@bitauth/libauth": "~3.0.0",
|
|
45
45
|
"@metamask/providers": "^22.1.1",
|
|
46
46
|
"@noble/post-quantum": "~0.6.1",
|
|
@@ -51,9 +51,8 @@
|
|
|
51
51
|
"@xylabs/geo": "^6.1.3",
|
|
52
52
|
"@xylabs/sdk-js": "^6.1.3",
|
|
53
53
|
"@xylabs/threads": "^6.1.3",
|
|
54
|
-
"@xylabs/toolchain": "~8.
|
|
55
|
-
"@xylabs/tsconfig": "~8.
|
|
56
|
-
"@xyo-network/address": "^6.1.1",
|
|
54
|
+
"@xylabs/toolchain": "~8.2.5",
|
|
55
|
+
"@xylabs/tsconfig": "~8.2.5",
|
|
57
56
|
"@xyo-network/sdk-js": "^6.1.0",
|
|
58
57
|
"@xyo-network/sdk-protocol-js": "~6.1.1",
|
|
59
58
|
"ajv": "^8.20.0",
|
|
@@ -70,7 +69,8 @@
|
|
|
70
69
|
"vite": "^8.0.16",
|
|
71
70
|
"vitest": "~4.1.9",
|
|
72
71
|
"webextension-polyfill": "^0.12.0",
|
|
73
|
-
"zod": "~4.4.3"
|
|
72
|
+
"zod": "~4.4.3",
|
|
73
|
+
"@xyo-network/xl1-rest-block-viewer": "~2.2.1"
|
|
74
74
|
},
|
|
75
75
|
"peerDependencies": {
|
|
76
76
|
"@aws-sdk/client-s3": "^3.700",
|
|
@@ -84,7 +84,6 @@
|
|
|
84
84
|
"@xylabs/geo": "^6.0",
|
|
85
85
|
"@xylabs/sdk-js": "^6.0",
|
|
86
86
|
"@xylabs/threads": "^6.1",
|
|
87
|
-
"@xyo-network/address": "^6.0",
|
|
88
87
|
"@xyo-network/sdk-js": "^6.0",
|
|
89
88
|
"@xyo-network/sdk-protocol-js": "~6.1",
|
|
90
89
|
"ajv": "^8.20",
|