@xyo-network/xl1-rest-block-publisher 2.1.3 → 2.1.5

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.
@@ -0,0 +1,46 @@
1
+ import type { S3Client } from '@aws-sdk/client-s3';
2
+ import type { CreatableProviderEventData, CreatableProviderParams } from '@xyo-network/xl1-protocol-sdk';
3
+ import { AbstractCreatableProvider } from '@xyo-network/xl1-protocol-sdk';
4
+ import type { RestContentEncoding } from './encoding.ts';
5
+ /** Shared parameters for S3-backed providers: where and how files are stored. */
6
+ export interface S3ProviderParams extends CreatableProviderParams {
7
+ bucket: string;
8
+ /** S3-compatible client pointed at the target endpoint (e.g. Cloudflare R2). */
9
+ client: S3Client;
10
+ /** Storage/wire encoding for published files. Defaults to 'br' (brotli). */
11
+ contentEncoding?: RestContentEncoding;
12
+ /** Optional key prefix, allowing the layout to live in a shared bucket. */
13
+ prefix?: string;
14
+ }
15
+ /** Finalized files never change once written. */
16
+ export declare const IMMUTABLE_CACHE_CONTROL = "public, max-age=31536000, immutable";
17
+ /**
18
+ * The head pointer is rewritten as the chain advances. A small positive TTL plus
19
+ * stale-while-revalidate keeps origin load low at high RPS while staying fresh — better
20
+ * than `max-age=0` for a hot, frequently-read object. Used for the chain-state head and
21
+ * the index watermark.
22
+ */
23
+ export declare const MUTABLE_CACHE_CONTROL = "public, max-age=5, stale-while-revalidate=30";
24
+ /**
25
+ * Manifests are mostly-static layout descriptors that change only when the layout evolves;
26
+ * a short TTL lets a new layout propagate within minutes without per-request revalidation.
27
+ */
28
+ export declare const MANIFEST_CACHE_CONTROL = "public, max-age=300";
29
+ /**
30
+ * Base for providers targeting S3-compatible storage. Bodies are pre-compressed at write
31
+ * time and stored with the matching Content-Encoding plus application/json, so HTTP clients
32
+ * decompress transparently — keys keep their `.json` extension. Reads decode the stored
33
+ * Content-Encoding back to JSON.
34
+ */
35
+ export declare abstract class AbstractS3Provider<TParams extends S3ProviderParams = S3ProviderParams, TEventData extends CreatableProviderEventData = CreatableProviderEventData> extends AbstractCreatableProvider<TParams, TEventData> {
36
+ get bucket(): string;
37
+ get client(): S3Client;
38
+ get contentEncoding(): RestContentEncoding;
39
+ get prefix(): string;
40
+ /** Reads and decodes a stored JSON file, or undefined when the key does not exist. */
41
+ protected getJson(path: string): Promise<unknown>;
42
+ /** True when the key exists, checked without fetching the body. */
43
+ protected hasJson(path: string): Promise<boolean>;
44
+ protected putJson(path: string, json: string, cacheControl: string): Promise<void>;
45
+ }
46
+ //# sourceMappingURL=AbstractS3Provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AbstractS3Provider.d.ts","sourceRoot":"","sources":["../../src/AbstractS3Provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAKlD,OAAO,KAAK,EAAE,0BAA0B,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAA;AACxG,OAAO,EAAE,yBAAyB,EAAE,MAAM,+BAA+B,CAAA;AAEzE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAA;AAGxD,iFAAiF;AACjF,MAAM,WAAW,gBAAiB,SAAQ,uBAAuB;IAC/D,MAAM,EAAE,MAAM,CAAA;IACd,gFAAgF;IAChF,MAAM,EAAE,QAAQ,CAAA;IAChB,4EAA4E;IAC5E,eAAe,CAAC,EAAE,mBAAmB,CAAA;IACrC,2EAA2E;IAC3E,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,iDAAiD;AACjD,eAAO,MAAM,uBAAuB,wCAAwC,CAAA;AAC5E;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,iDAAiD,CAAA;AACnF;;;GAGG;AACH,eAAO,MAAM,sBAAsB,wBAAwB,CAAA;AAE3D;;;;;GAKG;AACH,8BAAsB,kBAAkB,CACtC,OAAO,SAAS,gBAAgB,GAAG,gBAAgB,EACnD,UAAU,SAAS,0BAA0B,GAAG,0BAA0B,CAC1E,SAAQ,yBAAyB,CAAC,OAAO,EAAE,UAAU,CAAC;IACtD,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,IAAI,MAAM,IAAI,QAAQ,CAErB;IAED,IAAI,eAAe,IAAI,mBAAmB,CAEzC;IAED,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,sFAAsF;cACtE,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAYvD,mEAAmE;cACnD,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;cAUvC,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAWzF"}
@@ -1,6 +1,6 @@
1
1
  import type { BlockPublishRunner, BlockViewer, SignedHydratedBlockWithHashMeta, XL1BlockNumber, XL1BlockRange } from '@xyo-network/xl1-protocol-lib';
2
- import type { S3PublishRunnerParams } from './AbstractS3PublishRunner.ts';
3
- import { AbstractS3PublishRunner } from './AbstractS3PublishRunner.ts';
2
+ import type { S3ProviderParams } from './AbstractS3Provider.ts';
3
+ import { AbstractS3Provider } from './AbstractS3Provider.ts';
4
4
  /** A progress event emitted while publishing blocks. */
5
5
  export interface BlockPublishProgress {
6
6
  blockNumber: XL1BlockNumber;
@@ -8,7 +8,7 @@ export interface BlockPublishProgress {
8
8
  total: number;
9
9
  }
10
10
  /** Parameters for S3BlockPublishRunner. */
11
- export interface S3BlockPublishRunnerParams extends S3PublishRunnerParams {
11
+ export interface S3BlockPublishRunnerParams extends S3ProviderParams {
12
12
  /** Maximum concurrent block publishes during sync. */
13
13
  concurrency?: number;
14
14
  /**
@@ -18,8 +18,11 @@ export interface S3BlockPublishRunnerParams extends S3PublishRunnerParams {
18
18
  onProgress?: (event: BlockPublishProgress) => void;
19
19
  /** How many block publishes between progress reports during sync. */
20
20
  progressInterval?: number;
21
- /** The viewer to publish from (only finalized chains should be published). */
22
- source: BlockViewer;
21
+ /**
22
+ * The viewer to publish from (only finalized chains should be published). When omitted,
23
+ * resolved from the locator via BlockViewerMoniker.
24
+ */
25
+ source?: BlockViewer;
23
26
  }
24
27
  /**
25
28
  * Publishes finalized blocks (and their payloads) as the static REST file layout that
@@ -29,16 +32,38 @@ export interface S3BlockPublishRunnerParams extends S3PublishRunnerParams {
29
32
  * any range is safe. `sync(from)` resumes from a caller-supplied cursor (typically the block
30
33
  * after the last published head); omitting it republishes from genesis, which is safe.
31
34
  */
32
- export declare class S3BlockPublishRunner extends AbstractS3PublishRunner<S3BlockPublishRunnerParams> implements BlockPublishRunner {
35
+ export declare class S3BlockPublishRunner extends AbstractS3Provider<S3BlockPublishRunnerParams> implements BlockPublishRunner {
33
36
  static readonly defaultMoniker: "BlockPublishRunner";
34
- static readonly dependencies: never[];
37
+ static readonly dependencies: "BlockViewer"[];
35
38
  static readonly monikers: "BlockPublishRunner"[];
36
39
  moniker: "BlockPublishRunner";
40
+ protected _source?: BlockViewer;
37
41
  get concurrency(): number;
38
42
  get progressInterval(): number;
39
43
  get source(): BlockViewer;
44
+ createHandler(): Promise<void>;
45
+ /**
46
+ * Finds where a catch-up sync should start: walks backwards from the source head probing
47
+ * by-number paths (in batches of `concurrency`) until it finds an already published block,
48
+ * never probing below `floor`, and returns the block after it.
49
+ *
50
+ * This is what makes resuming cheap after a bucket was primed externally (an importer
51
+ * CLI) or after publishing was toggled off and on: already published blocks above a
52
+ * stale or missing head pointer are skipped instead of republished.
53
+ *
54
+ * Scope: only the topmost contiguous gap is healed. The walk stops at the first published
55
+ * block, so holes below it are not probed — deep verification belongs to an importer or
56
+ * audit tool. The walk also trusts that whoever published a block also published its
57
+ * payloads and step files. As a fast path, a missing genesis block with `floor` at
58
+ * genesis is treated as an empty bucket (full backfill) without walking the whole range.
59
+ */
60
+ findCatchUpStart(floor?: XL1BlockNumber): Promise<XL1BlockNumber>;
61
+ /** True when the block is already published at its by-number path. */
62
+ hasBlock(blockNumber: XL1BlockNumber): Promise<boolean>;
40
63
  /** Publishes one block at its by-number and by-hash paths, plus its payload files. */
41
64
  publishBlock(blockNumber: XL1BlockNumber): Promise<SignedHydratedBlockWithHashMeta | null>;
65
+ /** Publishes the finalized layout descriptor (idempotent; refreshed on each sync). */
66
+ publishManifest(): Promise<void>;
42
67
  /**
43
68
  * Publishes every block from `from` (inclusive, default genesis) through the source head.
44
69
  * Returns the published range, or null when already up to date.
@@ -1 +1 @@
1
- {"version":3,"file":"S3BlockPublishRunner.d.ts","sourceRoot":"","sources":["../../src/S3BlockPublishRunner.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,kBAAkB,EAAE,WAAW,EAAE,+BAA+B,EAAE,cAAc,EAAE,aAAa,EAChG,MAAM,+BAA+B,CAAA;AAQtC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAA;AACzE,OAAO,EAAE,uBAAuB,EAA2B,MAAM,8BAA8B,CAAA;AAE/F,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,qBAAqB;IACvE,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,8EAA8E;IAC9E,MAAM,EAAE,WAAW,CAAA;CACpB;AAED;;;;;;;GAOG;AACH,qBACa,oBAAqB,SAAQ,uBAAuB,CAAC,0BAA0B,CAAE,YAAW,kBAAkB;IACzH,MAAM,CAAC,QAAQ,CAAC,cAAc,uBAA4B;IAC1D,MAAM,CAAC,QAAQ,CAAC,YAAY,UAAK;IACjC,MAAM,CAAC,QAAQ,CAAC,QAAQ,yBAA8B;IACtD,OAAO,uBAAsC;IAE7C,IAAI,WAAW,IAAI,MAAM,CAExB;IAED,IAAI,gBAAgB,IAAI,MAAM,CAE7B;IAED,IAAI,MAAM,IAAI,WAAW,CAExB;IAED,sFAAsF;IAChF,YAAY,CAAC,WAAW,EAAE,cAAc,GAAG,OAAO,CAAC,+BAA+B,GAAG,IAAI,CAAC;IAYhG;;;OAGG;IACG,IAAI,CAAC,IAAI,GAAE,cAA0C,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAqB3F,6FAA6F;IAC7F,OAAO,CAAC,MAAM;CAQf"}
1
+ {"version":3,"file":"S3BlockPublishRunner.d.ts","sourceRoot":"","sources":["../../src/S3BlockPublishRunner.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,kBAAkB,EAAE,WAAW,EAAE,+BAA+B,EAAE,cAAc,EAAE,aAAa,EAChG,MAAM,+BAA+B,CAAA;AAWtC,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;IAiBlG,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;IAiBtC;;;OAGG;IACG,IAAI,CAAC,IAAI,GAAE,cAA0C,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAsB3F,6FAA6F;IAC7F,OAAO,CAAC,MAAM;CAQf"}
@@ -1,10 +1,13 @@
1
1
  import type { ChainStatePublishRunner, ChainStateViewerMethods, SignedHydratedBlockWithHashMeta } from '@xyo-network/xl1-protocol-lib';
2
- import type { S3PublishRunnerParams } from './AbstractS3PublishRunner.ts';
3
- import { AbstractS3PublishRunner } from './AbstractS3PublishRunner.ts';
2
+ import type { S3ProviderParams } from './AbstractS3Provider.ts';
3
+ import { AbstractS3Provider } from './AbstractS3Provider.ts';
4
4
  /** Parameters for S3ChainStatePublishRunner. */
5
- export interface S3ChainStatePublishRunnerParams extends S3PublishRunnerParams {
6
- /** Where the current head is read from (any BlockViewer satisfies this). */
7
- source: ChainStateViewerMethods;
5
+ export interface S3ChainStatePublishRunnerParams extends S3ProviderParams {
6
+ /**
7
+ * Where the current head is read from (any BlockViewer satisfies this). When omitted,
8
+ * resolved from the locator via BlockViewerMoniker.
9
+ */
10
+ source?: ChainStateViewerMethods;
8
11
  }
9
12
  /**
10
13
  * Publishes the mutable chain state — the head pointer (`chain/head.json`) — that
@@ -14,12 +17,14 @@ export interface S3ChainStatePublishRunnerParams extends S3PublishRunnerParams {
14
17
  * Callers must publish the finalized files for a head before publishing the head itself,
15
18
  * so readers never see a head that references missing files.
16
19
  */
17
- export declare class S3ChainStatePublishRunner extends AbstractS3PublishRunner<S3ChainStatePublishRunnerParams> implements ChainStatePublishRunner {
20
+ export declare class S3ChainStatePublishRunner extends AbstractS3Provider<S3ChainStatePublishRunnerParams> implements ChainStatePublishRunner {
18
21
  static readonly defaultMoniker: "ChainStatePublishRunner";
19
- static readonly dependencies: never[];
22
+ static readonly dependencies: "BlockViewer"[];
20
23
  static readonly monikers: "ChainStatePublishRunner"[];
21
24
  moniker: "ChainStatePublishRunner";
25
+ protected _source?: ChainStateViewerMethods;
22
26
  get source(): ChainStateViewerMethods;
27
+ createHandler(): Promise<void>;
23
28
  /** Publishes the source's current head to the mutable chain state pointer. */
24
29
  publishHead(): Promise<SignedHydratedBlockWithHashMeta>;
25
30
  }
@@ -1 +1 @@
1
- {"version":3,"file":"S3ChainStatePublishRunner.d.ts","sourceRoot":"","sources":["../../src/S3ChainStatePublishRunner.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,uBAAuB,EAAE,uBAAuB,EAAE,+BAA+B,EAClF,MAAM,+BAA+B,CAAA;AAKtC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAA;AACzE,OAAO,EAAE,uBAAuB,EAAyB,MAAM,8BAA8B,CAAA;AAE7F,gDAAgD;AAChD,MAAM,WAAW,+BAAgC,SAAQ,qBAAqB;IAC5E,4EAA4E;IAC5E,MAAM,EAAE,uBAAuB,CAAA;CAChC;AAED;;;;;;;GAOG;AACH,qBACa,yBAA0B,SAAQ,uBAAuB,CAAC,+BAA+B,CAAE,YAAW,uBAAuB;IACxI,MAAM,CAAC,QAAQ,CAAC,cAAc,4BAAiC;IAC/D,MAAM,CAAC,QAAQ,CAAC,YAAY,UAAK;IACjC,MAAM,CAAC,QAAQ,CAAC,QAAQ,8BAAmC;IAC3D,OAAO,4BAA2C;IAElD,IAAI,MAAM,IAAI,uBAAuB,CAEpC;IAED,8EAA8E;IACxE,WAAW,IAAI,OAAO,CAAC,+BAA+B,CAAC;CAM9D"}
1
+ {"version":3,"file":"S3ChainStatePublishRunner.d.ts","sourceRoot":"","sources":["../../src/S3ChainStatePublishRunner.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,uBAAuB,EAAE,uBAAuB,EAAE,+BAA+B,EAClF,MAAM,+BAA+B,CAAA;AAKtC,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"}
@@ -0,0 +1,26 @@
1
+ import type { Hash } from '@xylabs/sdk-js';
2
+ import type { ChainStateViewer, SignedHydratedBlockWithHashMeta, XL1BlockNumber } from '@xyo-network/xl1-protocol-lib';
3
+ import type { S3ProviderParams } from './AbstractS3Provider.ts';
4
+ import { AbstractS3Provider } from './AbstractS3Provider.ts';
5
+ /** Parameters for S3ChainStateViewer. */
6
+ export interface S3ChainStateViewerParams extends S3ProviderParams {
7
+ }
8
+ /**
9
+ * A ChainStateViewer over the chain-state bucket, reading the published head pointer back
10
+ * through the S3 API (authenticated, not the public HTTP layout — see RestChainStateViewer
11
+ * for anonymous reads). This is how publishers learn their resume cursor: the head pointer
12
+ * is only written after the finalized files it references exist.
13
+ */
14
+ export declare class S3ChainStateViewer extends AbstractS3Provider<S3ChainStateViewerParams, ChainStateViewer['eventData']> implements ChainStateViewer {
15
+ static readonly defaultMoniker: "ChainStateViewer";
16
+ static readonly dependencies: never[];
17
+ static readonly monikers: "ChainStateViewer"[];
18
+ moniker: "ChainStateViewer";
19
+ /** The published head; throws when no head pointer has been published yet. */
20
+ currentBlock(): Promise<SignedHydratedBlockWithHashMeta>;
21
+ currentBlockHash(): Promise<Hash>;
22
+ currentBlockNumber(): Promise<XL1BlockNumber>;
23
+ /** The published head, or undefined when no head pointer has been published yet. */
24
+ tryCurrentBlock(): Promise<SignedHydratedBlockWithHashMeta | undefined>;
25
+ }
26
+ //# sourceMappingURL=S3ChainStateViewer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"S3ChainStateViewer.d.ts","sourceRoot":"","sources":["../../src/S3ChainStateViewer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAA;AAE1C,OAAO,KAAK,EACV,gBAAgB,EAAE,+BAA+B,EAAE,cAAc,EAClE,MAAM,+BAA+B,CAAA;AAKtC,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;IAIjC,kBAAkB,IAAI,OAAO,CAAC,cAAc,CAAC;IAInD,oFAAoF;IAC9E,eAAe,IAAI,OAAO,CAAC,+BAA+B,GAAG,SAAS,CAAC;CAI9E"}
@@ -1,28 +1,41 @@
1
- import type { BlockViewer, IndexPublishRunner, XL1BlockNumber } from '@xyo-network/xl1-protocol-lib';
2
- import type { S3PublishRunnerParams } from './AbstractS3PublishRunner.ts';
3
- import { AbstractS3PublishRunner } from './AbstractS3PublishRunner.ts';
1
+ import type { BlockViewer, IndexPublishRunner, IndexSummaryFamily, IndexWatermark, XL1BlockNumber } from '@xyo-network/xl1-protocol-lib';
2
+ import type { S3ProviderParams } from './AbstractS3Provider.ts';
3
+ import { AbstractS3Provider } from './AbstractS3Provider.ts';
4
4
  /** Parameters for S3IndexPublishRunner. */
5
- export interface S3IndexPublishRunnerParams extends S3PublishRunnerParams {
6
- /** The viewer to publish from (only finalized chains should be published). */
7
- source: BlockViewer;
5
+ export interface S3IndexPublishRunnerParams extends S3ProviderParams {
6
+ /**
7
+ * The viewer to build the index from (only finalized chains should be indexed). When omitted,
8
+ * resolved from the locator via BlockViewerMoniker.
9
+ */
10
+ source?: BlockViewer;
8
11
  }
9
12
  /**
10
- * Publishes completed steps' block summaries (the chain index) as the static REST file
11
- * layout that `RestIndexViewer` reads. Step files are immutable: only complete steps are
12
- * ever published, and a completed step's blocks never change.
13
+ * Publishes the multi-family chain index (blocks, balances, schemas, transfers) as the static
14
+ * REST file layout that `RestIndexViewer` reads. Frames are immutable: only complete frames are
15
+ * ever published, and a completed frame never changes. The runner reads blocks from its source
16
+ * viewer (MongoDB, or the finalized/chain-state buckets via CDN) and writes summaries to the
17
+ * index bucket; the head watermark and manifest are written last so a reader never sees a
18
+ * watermark pointing past the frames that back it.
13
19
  */
14
- export declare class S3IndexPublishRunner extends AbstractS3PublishRunner<S3IndexPublishRunnerParams> implements IndexPublishRunner {
20
+ export declare class S3IndexPublishRunner extends AbstractS3Provider<S3IndexPublishRunnerParams> implements IndexPublishRunner {
15
21
  static readonly defaultMoniker: "IndexPublishRunner";
16
- static readonly dependencies: never[];
22
+ static readonly dependencies: "BlockViewer"[];
17
23
  static readonly monikers: "IndexPublishRunner"[];
18
24
  moniker: "IndexPublishRunner";
25
+ protected _source?: BlockViewer;
19
26
  get source(): BlockViewer;
20
- /**
21
- * Publishes one completed step's blocks as a BlocksStepSummary file (blocks oldest-first).
22
- * Asserts the step is complete — partial tail steps are never published.
23
- */
24
- publishStep(stepLevel: number, stepIndex: number): Promise<void>;
25
- /** Publishes every step (at every level) completed by the given block. */
26
- publishStepsCompletedBy(blockNumber: XL1BlockNumber): Promise<void>;
27
+ createHandler(): Promise<void>;
28
+ /** Builds every family's frames completed up to the ceiling, then writes the manifest and watermark. */
29
+ publishCompletedFramesUpTo(ceiling: XL1BlockNumber): Promise<IndexWatermark>;
30
+ /** Publishes one completed frame for a family (and any missing sub-frames it depends on). */
31
+ publishFrame(family: IndexSummaryFamily, stepLevel: number, stepIndex: number): Promise<void>;
32
+ /** Dispatches a single frame to its family builder, writing it (and missing sub-frames) to the bucket. */
33
+ private buildFamilyFrame;
34
+ /** Builds a family's frames in (previous, ceiling] across every level; returns total completed frames. */
35
+ private publishFamily;
36
+ private readWatermark;
37
+ private summaryMap;
38
+ private writeHead;
39
+ private writeManifest;
27
40
  }
28
41
  //# sourceMappingURL=S3IndexPublishRunner.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"S3IndexPublishRunner.d.ts","sourceRoot":"","sources":["../../src/S3IndexPublishRunner.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACS,WAAW,EAAE,kBAAkB,EAAE,cAAc,EACnE,MAAM,+BAA+B,CAAA;AAOtC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAA;AACzE,OAAO,EAAE,uBAAuB,EAA2B,MAAM,8BAA8B,CAAA;AAE/F,2CAA2C;AAC3C,MAAM,WAAW,0BAA2B,SAAQ,qBAAqB;IACvE,8EAA8E;IAC9E,MAAM,EAAE,WAAW,CAAA;CACpB;AAED;;;;GAIG;AACH,qBACa,oBAAqB,SAAQ,uBAAuB,CAAC,0BAA0B,CAAE,YAAW,kBAAkB;IACzH,MAAM,CAAC,QAAQ,CAAC,cAAc,uBAA4B;IAC1D,MAAM,CAAC,QAAQ,CAAC,YAAY,UAAK;IACjC,MAAM,CAAC,QAAQ,CAAC,QAAQ,yBAA8B;IACtD,OAAO,uBAAsC;IAE7C,IAAI,MAAM,IAAI,WAAW,CAExB;IAED;;;OAGG;IACG,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBtE,0EAA0E;IACpE,uBAAuB,CAAC,WAAW,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;CAQ1E"}
1
+ {"version":3,"file":"S3IndexPublishRunner.d.ts","sourceRoot":"","sources":["../../src/S3IndexPublishRunner.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACA,WAAW,EAAkB,kBAAkB,EAAE,kBAAkB,EAAE,cAAc,EAC7F,cAAc,EACf,MAAM,+BAA+B,CAAA;AAkBtC,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;;;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,MAAM,IAAI,WAAW,CAExB;IAEc,aAAa;IAK5B,wGAAwG;IAClG,0BAA0B,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC;IAoBlF,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;YAwBb,aAAa;IAK3B,OAAO,CAAC,UAAU;YASJ,SAAS;YAYT,aAAa;CAa5B"}
@@ -1,6 +1,7 @@
1
- export * from './AbstractS3PublishRunner.ts';
1
+ export * from './AbstractS3Provider.ts';
2
2
  export * from './encoding.ts';
3
3
  export * from './S3BlockPublishRunner.ts';
4
4
  export * from './S3ChainStatePublishRunner.ts';
5
+ export * from './S3ChainStateViewer.ts';
5
6
  export * from './S3IndexPublishRunner.ts';
6
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,8BAA8B,CAAA;AAC5C,cAAc,eAAe,CAAA;AAC7B,cAAc,2BAA2B,CAAA;AACzC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,2BAA2B,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAA;AACvC,cAAc,eAAe,CAAA;AAC7B,cAAc,2BAA2B,CAAA;AACzC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,yBAAyB,CAAA;AACvC,cAAc,2BAA2B,CAAA"}
@@ -11,8 +11,12 @@ var __decorateClass = (decorators, target, key, kind) => {
11
11
  };
12
12
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
13
13
 
14
- // src/AbstractS3PublishRunner.ts
15
- import { PutObjectCommand } from "@aws-sdk/client-s3";
14
+ // src/AbstractS3Provider.ts
15
+ import {
16
+ GetObjectCommand,
17
+ HeadObjectCommand,
18
+ PutObjectCommand
19
+ } from "@aws-sdk/client-s3";
16
20
  import { assertEx } from "@xylabs/sdk-js";
17
21
  import { AbstractCreatableProvider } from "@xyo-network/xl1-protocol-sdk";
18
22
 
@@ -45,10 +49,11 @@ function decodeBody(body, contentEncoding) {
45
49
  }
46
50
  }
47
51
 
48
- // src/AbstractS3PublishRunner.ts
52
+ // src/AbstractS3Provider.ts
49
53
  var IMMUTABLE_CACHE_CONTROL = "public, max-age=31536000, immutable";
50
- var MUTABLE_CACHE_CONTROL = "public, max-age=0, must-revalidate";
51
- var AbstractS3PublishRunner = class extends AbstractCreatableProvider {
54
+ var MUTABLE_CACHE_CONTROL = "public, max-age=5, stale-while-revalidate=30";
55
+ var MANIFEST_CACHE_CONTROL = "public, max-age=300";
56
+ var AbstractS3Provider = class extends AbstractCreatableProvider {
52
57
  get bucket() {
53
58
  return assertEx(this.params.bucket, () => "No bucket specified");
54
59
  }
@@ -61,6 +66,28 @@ var AbstractS3PublishRunner = class extends AbstractCreatableProvider {
61
66
  get prefix() {
62
67
  return this.params.prefix ?? "";
63
68
  }
69
+ /** Reads and decodes a stored JSON file, or undefined when the key does not exist. */
70
+ async getJson(path) {
71
+ try {
72
+ const response = await this.client.send(new GetObjectCommand({ Bucket: this.bucket, Key: `${this.prefix}${path}` }));
73
+ const body = await response.Body?.transformToByteArray();
74
+ if (body === void 0) return void 0;
75
+ return JSON.parse(decodeBody(body, response.ContentEncoding));
76
+ } catch (error) {
77
+ if (isNotFoundError(error)) return void 0;
78
+ throw error;
79
+ }
80
+ }
81
+ /** True when the key exists, checked without fetching the body. */
82
+ async hasJson(path) {
83
+ try {
84
+ await this.client.send(new HeadObjectCommand({ Bucket: this.bucket, Key: `${this.prefix}${path}` }));
85
+ return true;
86
+ } catch (error) {
87
+ if (isNotFoundError(error)) return false;
88
+ throw error;
89
+ }
90
+ }
64
91
  async putJson(path, json, cacheControl) {
65
92
  const { body, contentEncoding } = encodeBody(json, this.contentEncoding);
66
93
  await this.client.send(new PutObjectCommand({
@@ -73,19 +100,32 @@ var AbstractS3PublishRunner = class extends AbstractCreatableProvider {
73
100
  }));
74
101
  }
75
102
  };
103
+ var isNotFoundError = (error) => {
104
+ if (typeof error !== "object" || error === null) return false;
105
+ const { name, $metadata } = error;
106
+ return name === "NoSuchKey" || name === "NotFound" || $metadata?.httpStatusCode === 404;
107
+ };
76
108
 
77
109
  // src/S3BlockPublishRunner.ts
78
110
  import { assertEx as assertEx2, isNull } from "@xylabs/sdk-js";
79
- import { asXL1BlockNumber, BlockPublishRunnerMoniker } from "@xyo-network/xl1-protocol-lib";
111
+ import {
112
+ asXL1BlockNumber,
113
+ BlockPublishRunnerMoniker,
114
+ BlockViewerMoniker
115
+ } from "@xyo-network/xl1-protocol-lib";
80
116
  import { creatableProvider } from "@xyo-network/xl1-protocol-sdk";
81
117
  import {
82
118
  blockHashPath,
83
119
  blockNumberPath,
120
+ CHAIN_LAYOUT_VERSION,
121
+ ChainManifestSchema,
122
+ manifestPath,
84
123
  payloadPath
85
124
  } from "@xyo-network/xl1-rest-block-viewer";
86
125
  import { Semaphore } from "async-mutex";
87
- var S3BlockPublishRunner = class extends AbstractS3PublishRunner {
126
+ var S3BlockPublishRunner = class extends AbstractS3Provider {
88
127
  moniker = S3BlockPublishRunner.defaultMoniker;
128
+ _source;
89
129
  get concurrency() {
90
130
  return this.params.concurrency ?? 8;
91
131
  }
@@ -93,7 +133,46 @@ var S3BlockPublishRunner = class extends AbstractS3PublishRunner {
93
133
  return this.params.progressInterval ?? 100;
94
134
  }
95
135
  get source() {
96
- return assertEx2(this.params.source, () => "No source specified");
136
+ return assertEx2(this._source, () => "No source specified");
137
+ }
138
+ async createHandler() {
139
+ await super.createHandler();
140
+ this._source = this.params.source ?? await this.locator.getInstance(BlockViewerMoniker);
141
+ }
142
+ /**
143
+ * Finds where a catch-up sync should start: walks backwards from the source head probing
144
+ * by-number paths (in batches of `concurrency`) until it finds an already published block,
145
+ * never probing below `floor`, and returns the block after it.
146
+ *
147
+ * This is what makes resuming cheap after a bucket was primed externally (an importer
148
+ * CLI) or after publishing was toggled off and on: already published blocks above a
149
+ * stale or missing head pointer are skipped instead of republished.
150
+ *
151
+ * Scope: only the topmost contiguous gap is healed. The walk stops at the first published
152
+ * block, so holes below it are not probed — deep verification belongs to an importer or
153
+ * audit tool. The walk also trusts that whoever published a block also published its
154
+ * payloads and step files. As a fast path, a missing genesis block with `floor` at
155
+ * genesis is treated as an empty bucket (full backfill) without walking the whole range.
156
+ */
157
+ async findCatchUpStart(floor = asXL1BlockNumber(0, true)) {
158
+ const sourceHead = await this.source.currentBlock();
159
+ const end = sourceHead[0].block;
160
+ if (floor > end) return floor;
161
+ if (floor === 0 && !await this.hasBlock(asXL1BlockNumber(0, true))) return floor;
162
+ for (let high = end; high >= floor; high -= this.concurrency) {
163
+ const low = Math.max(floor, high - this.concurrency + 1);
164
+ const present = await Promise.all(
165
+ Array.from({ length: high - low + 1 }, (_, i) => this.hasBlock(asXL1BlockNumber(low + i, true)))
166
+ );
167
+ for (let blockNumber = high; blockNumber >= low; blockNumber--) {
168
+ if (present[blockNumber - low]) return asXL1BlockNumber(blockNumber + 1, true);
169
+ }
170
+ }
171
+ return floor;
172
+ }
173
+ /** True when the block is already published at its by-number path. */
174
+ async hasBlock(blockNumber) {
175
+ return await this.hasJson(blockNumberPath(blockNumber));
97
176
  }
98
177
  /** Publishes one block at its by-number and by-hash paths, plus its payload files. */
99
178
  async publishBlock(blockNumber) {
@@ -107,6 +186,23 @@ var S3BlockPublishRunner = class extends AbstractS3PublishRunner {
107
186
  }
108
187
  return block;
109
188
  }
189
+ /** Publishes the finalized layout descriptor (idempotent; refreshed on each sync). */
190
+ 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
+ };
204
+ await this.putJson(manifestPath(), JSON.stringify(manifest), MANIFEST_CACHE_CONTROL);
205
+ }
110
206
  /**
111
207
  * Publishes every block from `from` (inclusive, default genesis) through the source head.
112
208
  * Returns the published range, or null when already up to date.
@@ -115,6 +211,7 @@ var S3BlockPublishRunner = class extends AbstractS3PublishRunner {
115
211
  const sourceHead = await this.source.currentBlock();
116
212
  const end = sourceHead[0].block;
117
213
  if (from > end) return null;
214
+ await this.publishManifest();
118
215
  const semaphore = new Semaphore(this.concurrency);
119
216
  const numbers = Array.from({ length: end - from + 1 }, (_, i) => asXL1BlockNumber(from + i, true));
120
217
  const total = numbers.length;
@@ -143,7 +240,7 @@ var S3BlockPublishRunner = class extends AbstractS3PublishRunner {
143
240
  }
144
241
  };
145
242
  __publicField(S3BlockPublishRunner, "defaultMoniker", BlockPublishRunnerMoniker);
146
- __publicField(S3BlockPublishRunner, "dependencies", []);
243
+ __publicField(S3BlockPublishRunner, "dependencies", [BlockViewerMoniker]);
147
244
  __publicField(S3BlockPublishRunner, "monikers", [BlockPublishRunnerMoniker]);
148
245
  S3BlockPublishRunner = __decorateClass([
149
246
  creatableProvider()
@@ -151,13 +248,18 @@ S3BlockPublishRunner = __decorateClass([
151
248
 
152
249
  // src/S3ChainStatePublishRunner.ts
153
250
  import { assertEx as assertEx3 } from "@xylabs/sdk-js";
154
- import { ChainStatePublishRunnerMoniker } from "@xyo-network/xl1-protocol-lib";
251
+ import { BlockViewerMoniker as BlockViewerMoniker2, ChainStatePublishRunnerMoniker } from "@xyo-network/xl1-protocol-lib";
155
252
  import { creatableProvider as creatableProvider2 } from "@xyo-network/xl1-protocol-sdk";
156
253
  import { headPath } from "@xyo-network/xl1-rest-block-viewer";
157
- var S3ChainStatePublishRunner = class extends AbstractS3PublishRunner {
254
+ var S3ChainStatePublishRunner = class extends AbstractS3Provider {
158
255
  moniker = S3ChainStatePublishRunner.defaultMoniker;
256
+ _source;
159
257
  get source() {
160
- return assertEx3(this.params.source, () => "No source specified");
258
+ return assertEx3(this._source, () => "No source specified");
259
+ }
260
+ async createHandler() {
261
+ await super.createHandler();
262
+ this._source = this.params.source ?? await this.locator.getInstance(BlockViewerMoniker2);
161
263
  }
162
264
  /** Publishes the source's current head to the mutable chain state pointer. */
163
265
  async publishHead() {
@@ -168,69 +270,267 @@ var S3ChainStatePublishRunner = class extends AbstractS3PublishRunner {
168
270
  }
169
271
  };
170
272
  __publicField(S3ChainStatePublishRunner, "defaultMoniker", ChainStatePublishRunnerMoniker);
171
- __publicField(S3ChainStatePublishRunner, "dependencies", []);
273
+ __publicField(S3ChainStatePublishRunner, "dependencies", [BlockViewerMoniker2]);
172
274
  __publicField(S3ChainStatePublishRunner, "monikers", [ChainStatePublishRunnerMoniker]);
173
275
  S3ChainStatePublishRunner = __decorateClass([
174
276
  creatableProvider2()
175
277
  ], S3ChainStatePublishRunner);
176
278
 
177
- // src/S3IndexPublishRunner.ts
279
+ // src/S3ChainStateViewer.ts
178
280
  import { assertEx as assertEx4 } from "@xylabs/sdk-js";
281
+ import { asSignedHydratedBlockWithHashMeta, ChainStateViewerMoniker } from "@xyo-network/xl1-protocol-lib";
282
+ import { creatableProvider as creatableProvider3 } from "@xyo-network/xl1-protocol-sdk";
283
+ import { headPath as headPath2 } from "@xyo-network/xl1-rest-block-viewer";
284
+ var S3ChainStateViewer = class extends AbstractS3Provider {
285
+ moniker = S3ChainStateViewer.defaultMoniker;
286
+ /** The published head; throws when no head pointer has been published yet. */
287
+ async currentBlock() {
288
+ return await this.spanAsync("currentBlock", async () => {
289
+ const parsed = assertEx4(await this.getJson(headPath2()), () => "Head not found");
290
+ return asSignedHydratedBlockWithHashMeta(parsed, true);
291
+ }, this.context);
292
+ }
293
+ async currentBlockHash() {
294
+ return (await this.currentBlock())[0]._hash;
295
+ }
296
+ async currentBlockNumber() {
297
+ return (await this.currentBlock())[0].block;
298
+ }
299
+ /** The published head, or undefined when no head pointer has been published yet. */
300
+ async tryCurrentBlock() {
301
+ const parsed = await this.getJson(headPath2());
302
+ return parsed === void 0 ? void 0 : asSignedHydratedBlockWithHashMeta(parsed, true);
303
+ }
304
+ };
305
+ __publicField(S3ChainStateViewer, "defaultMoniker", ChainStateViewerMoniker);
306
+ __publicField(S3ChainStateViewer, "dependencies", []);
307
+ __publicField(S3ChainStateViewer, "monikers", [ChainStateViewerMoniker]);
308
+ S3ChainStateViewer = __decorateClass([
309
+ creatableProvider3()
310
+ ], S3ChainStateViewer);
311
+
312
+ // src/S3IndexPublishRunner.ts
313
+ import { assertEx as assertEx5 } from "@xylabs/sdk-js";
179
314
  import {
180
- BlocksStepSummarySchema,
315
+ asXL1BlockNumber as asXL1BlockNumber2,
316
+ asXL1BlockRange,
317
+ BlockViewerMoniker as BlockViewerMoniker3,
181
318
  IndexPublishRunnerMoniker,
182
319
  StepSizes
183
320
  } from "@xyo-network/xl1-protocol-lib";
184
- import { blocksMaxStep, creatableProvider as creatableProvider3 } from "@xyo-network/xl1-protocol-sdk";
185
- import { blocksStepPath } from "@xyo-network/xl1-rest-block-viewer";
186
- var S3IndexPublishRunner = class extends AbstractS3PublishRunner {
321
+ import {
322
+ balancesMaxStep,
323
+ balancesStepSummaryFromRange,
324
+ blocksMaxStep,
325
+ blocksStepSummaryFromRange,
326
+ creatableProvider as creatableProvider4,
327
+ schemasMaxStep,
328
+ schemasStepSummaryFromRange,
329
+ transfersMaxStep,
330
+ transfersStepSummaryFromRange
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
+ import { Semaphore as Semaphore2 } from "async-mutex";
341
+ var S3IndexSummaryMap = class {
342
+ family;
343
+ numberCache = /* @__PURE__ */ new Map();
344
+ read;
345
+ source;
346
+ write;
347
+ constructor(family, source, read, write) {
348
+ this.family = family;
349
+ this.source = source;
350
+ this.read = read;
351
+ this.write = write;
352
+ }
353
+ clear() {
354
+ this.numberCache.clear();
355
+ }
356
+ delete(_id) {
357
+ return false;
358
+ }
359
+ async get(id) {
360
+ const path = await this.pathForKey(id);
361
+ if (path === void 0) return void 0;
362
+ const found = await this.read(path);
363
+ return found === void 0 ? void 0 : found;
364
+ }
365
+ async getMany(ids) {
366
+ const found = await Promise.all(ids.map((id) => this.get(id)));
367
+ return found.flatMap((value) => value === void 0 ? [] : [value]);
368
+ }
369
+ async has(id) {
370
+ return await this.get(id) !== void 0;
371
+ }
372
+ async set(id, data) {
373
+ const path = await this.pathForFrame(data.hash, data.stepSize) ?? await this.pathForKey(id);
374
+ if (path === void 0) return;
375
+ await this.write(path, JSON.stringify(data));
376
+ }
377
+ async setMany(entries) {
378
+ await Promise.all(entries.map(([id, data]) => this.set(id, data)));
379
+ }
380
+ async pathForFrame(hash, stepSize) {
381
+ const stepLevel = StepSizes.indexOf(asXL1BlockNumber2(stepSize, true));
382
+ if (stepLevel === -1) return void 0;
383
+ const blockNumber = await this.resolveBlockNumber(hash);
384
+ if (blockNumber === void 0) return void 0;
385
+ const stepIndex = (blockNumber + 1) / stepSize - 1;
386
+ return Number.isInteger(stepIndex) && stepIndex >= 0 ? indexSummaryPath(this.family, stepLevel, stepIndex) : void 0;
387
+ }
388
+ async pathForKey(key) {
389
+ const [hash, sizeText] = key.split("|");
390
+ return await this.pathForFrame(hash, Number(sizeText));
391
+ }
392
+ async resolveBlockNumber(hash) {
393
+ const cached = this.numberCache.get(hash);
394
+ if (cached !== void 0) return cached;
395
+ const block = await this.source.blockByHash(hash);
396
+ if (!block) return void 0;
397
+ const blockNumber = block[0].block;
398
+ this.numberCache.set(hash, blockNumber);
399
+ return blockNumber;
400
+ }
401
+ };
402
+ var S3IndexPublishRunner = class extends AbstractS3Provider {
187
403
  moniker = S3IndexPublishRunner.defaultMoniker;
404
+ _source;
188
405
  get source() {
189
- return assertEx4(this.params.source, () => "No source specified");
406
+ return assertEx5(this._source, () => "No source specified");
190
407
  }
191
- /**
192
- * Publishes one completed step's blocks as a BlocksStepSummary file (blocks oldest-first).
193
- * Asserts the step is complete — partial tail steps are never published.
194
- */
195
- async publishStep(stepLevel, stepIndex) {
196
- const size = StepSizes[stepLevel];
197
- assertEx4(stepLevel <= blocksMaxStep, () => `publishStep does not support step levels above ${blocksMaxStep} (requested ${stepLevel})`);
198
- const lastBlockNumber = (stepIndex + 1) * size - 1;
199
- const headNumber = await this.source.currentBlockNumber();
200
- assertEx4(lastBlockNumber <= headNumber, () => `Step ${stepLevel}/${stepIndex} is not complete (head ${headNumber})`);
201
- const newestFirst = await this.source.blocksByStep(stepLevel, stepIndex);
202
- const blocks = newestFirst.toReversed();
203
- const summary = {
204
- schema: BlocksStepSummarySchema,
205
- hash: assertEx4(blocks.at(-1), () => `No blocks for step ${stepLevel}/${stepIndex}`)[0]._hash,
206
- stepSize: size,
207
- blocks
408
+ async createHandler() {
409
+ await super.createHandler();
410
+ this._source = this.params.source ?? await this.locator.getInstance(BlockViewerMoniker3);
411
+ }
412
+ /** Builds every family's frames completed up to the ceiling, then writes the manifest and watermark. */
413
+ async publishCompletedFramesUpTo(ceiling) {
414
+ const head = await this.source.currentBlockNumber();
415
+ assertEx5(ceiling <= head, () => `Ceiling ${ceiling} exceeds source head ${head}`);
416
+ const previous = (await this.readWatermark())?.block ?? -1;
417
+ const families = {
418
+ balances: await this.publishFamily("balances", balancesMaxStep, balancesStepSummaryFromRange, previous, ceiling),
419
+ blocks: await this.publishFamily("blocks", blocksMaxStep, blocksStepSummaryFromRange, previous, ceiling),
420
+ schemas: await this.publishFamily("schemas", schemasMaxStep, schemasStepSummaryFromRange, previous, ceiling),
421
+ transfers: await this.publishFamily("transfers", transfersMaxStep, transfersStepSummaryFromRange, previous, ceiling)
422
+ };
423
+ const ceilingBlock = assertEx5(await this.source.blockByNumber(ceiling), () => `Block not found for ceiling ${ceiling}`);
424
+ const watermark = {
425
+ block: ceiling,
426
+ hash: ceilingBlock[0]._hash,
427
+ families
208
428
  };
209
- await this.putJson(blocksStepPath(stepLevel, stepIndex), JSON.stringify(summary), IMMUTABLE_CACHE_CONTROL);
210
- this.logger?.info(`S3IndexPublishRunner: published step ${stepLevel}/${stepIndex}`);
429
+ await this.writeManifest();
430
+ await this.writeHead(watermark);
431
+ this.logger?.info(`S3IndexPublishRunner: index complete through block ${ceiling}`);
432
+ return watermark;
211
433
  }
212
- /** Publishes every step (at every level) completed by the given block. */
213
- async publishStepsCompletedBy(blockNumber) {
214
- for (let stepLevel = 0; stepLevel <= blocksMaxStep; stepLevel++) {
434
+ /** Publishes one completed frame for a family (and any missing sub-frames it depends on). */
435
+ async publishFrame(family, stepLevel, stepIndex) {
436
+ const size = StepSizes[stepLevel];
437
+ const lastBlock = (stepIndex + 1) * size - 1;
438
+ const head = await this.source.currentBlockNumber();
439
+ assertEx5(lastBlock <= head, () => `Frame ${family} ${stepLevel}/${stepIndex} is not complete (head ${head})`);
440
+ const range = asXL1BlockRange([stepIndex * size, lastBlock], true);
441
+ await this.buildFamilyFrame(family, range);
442
+ this.logger?.info(`S3IndexPublishRunner: published frame ${family} ${stepLevel}/${stepIndex}`);
443
+ }
444
+ /** Dispatches a single frame to its family builder, writing it (and missing sub-frames) to the bucket. */
445
+ async buildFamilyFrame(family, range) {
446
+ const semaphores = StepSizes.map(() => new Semaphore2(20));
447
+ switch (family) {
448
+ case "balances": {
449
+ await balancesStepSummaryFromRange(this.context, semaphores, this.source, this.summaryMap("balances"), range);
450
+ break;
451
+ }
452
+ case "blocks": {
453
+ await blocksStepSummaryFromRange(this.context, semaphores, this.source, this.summaryMap("blocks"), range);
454
+ break;
455
+ }
456
+ case "schemas": {
457
+ await schemasStepSummaryFromRange(this.context, semaphores, this.source, this.summaryMap("schemas"), range);
458
+ break;
459
+ }
460
+ case "transfers": {
461
+ await transfersStepSummaryFromRange(this.context, semaphores, this.source, this.summaryMap("transfers"), range);
462
+ break;
463
+ }
464
+ }
465
+ }
466
+ /** Builds a family's frames in (previous, ceiling] across every level; returns total completed frames. */
467
+ async publishFamily(family, maxStep, build, previous, ceiling) {
468
+ const map = this.summaryMap(family);
469
+ const semaphores = StepSizes.map(() => new Semaphore2(20));
470
+ let completed = 0;
471
+ for (let stepLevel = 0; stepLevel <= maxStep; stepLevel++) {
215
472
  const size = StepSizes[stepLevel];
216
- if ((blockNumber + 1) % size === 0) {
217
- await this.publishStep(stepLevel, (blockNumber + 1) / size - 1);
473
+ const fromIndex = Math.floor((previous + 1) / size);
474
+ const toIndex = Math.floor((ceiling + 1) / size);
475
+ completed += toIndex;
476
+ for (let stepIndex = fromIndex; stepIndex < toIndex; stepIndex++) {
477
+ const start = stepIndex * size;
478
+ await build(this.context, semaphores, this.source, map, asXL1BlockRange([start, start + size - 1], true));
218
479
  }
219
480
  }
481
+ return completed;
482
+ }
483
+ async readWatermark() {
484
+ const found = await this.getJson(indexHeadPath());
485
+ return found === void 0 ? void 0 : found;
486
+ }
487
+ summaryMap(family) {
488
+ return new S3IndexSummaryMap(
489
+ family,
490
+ this.source,
491
+ (path) => this.getJson(path),
492
+ (path, json) => this.putJson(path, json, IMMUTABLE_CACHE_CONTROL)
493
+ );
494
+ }
495
+ async writeHead(watermark) {
496
+ const head = {
497
+ schema: IndexHeadSchema,
498
+ version: INDEX_LAYOUT_VERSION,
499
+ block: watermark.block,
500
+ hash: watermark.hash,
501
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
502
+ families: watermark.families
503
+ };
504
+ await this.putJson(indexHeadPath(), JSON.stringify(head), MUTABLE_CACHE_CONTROL);
505
+ }
506
+ async writeManifest() {
507
+ const manifest = {
508
+ schema: IndexManifestSchema,
509
+ version: INDEX_LAYOUT_VERSION,
510
+ families: {
511
+ balances: { maxStep: balancesMaxStep, path: "balances/{level}/{index}.json" },
512
+ blocks: { maxStep: blocksMaxStep, path: "blocks/{level}/{index}.json" },
513
+ schemas: { maxStep: schemasMaxStep, path: "schemas/{level}/{index}.json" },
514
+ transfers: { maxStep: transfersMaxStep, path: "transfers/{level}/{index}.json" }
515
+ }
516
+ };
517
+ await this.putJson(indexManifestPath(), JSON.stringify(manifest), MANIFEST_CACHE_CONTROL);
220
518
  }
221
519
  };
222
520
  __publicField(S3IndexPublishRunner, "defaultMoniker", IndexPublishRunnerMoniker);
223
- __publicField(S3IndexPublishRunner, "dependencies", []);
521
+ __publicField(S3IndexPublishRunner, "dependencies", [BlockViewerMoniker3]);
224
522
  __publicField(S3IndexPublishRunner, "monikers", [IndexPublishRunnerMoniker]);
225
523
  S3IndexPublishRunner = __decorateClass([
226
- creatableProvider3()
524
+ creatableProvider4()
227
525
  ], S3IndexPublishRunner);
228
526
  export {
229
- AbstractS3PublishRunner,
527
+ AbstractS3Provider,
230
528
  IMMUTABLE_CACHE_CONTROL,
529
+ MANIFEST_CACHE_CONTROL,
231
530
  MUTABLE_CACHE_CONTROL,
232
531
  S3BlockPublishRunner,
233
532
  S3ChainStatePublishRunner,
533
+ S3ChainStateViewer,
234
534
  S3IndexPublishRunner,
235
535
  decodeBody,
236
536
  encodeBody
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../../src/AbstractS3PublishRunner.ts", "../../src/encoding.ts", "../../src/S3BlockPublishRunner.ts", "../../src/S3ChainStatePublishRunner.ts", "../../src/S3IndexPublishRunner.ts"],
4
- "sourcesContent": ["import type { S3Client } from '@aws-sdk/client-s3'\nimport { PutObjectCommand } from '@aws-sdk/client-s3'\nimport { assertEx } from '@xylabs/sdk-js'\nimport type { CreatableProviderParams } from '@xyo-network/xl1-protocol-sdk'\nimport { AbstractCreatableProvider } from '@xyo-network/xl1-protocol-sdk'\n\nimport type { RestContentEncoding } from './encoding.ts'\nimport { encodeBody } from './encoding.ts'\n\n/** Shared parameters for S3 publish runners: where and how published files are written. */\nexport interface S3PublishRunnerParams 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/** Chain state is rewritten as the chain advances. */\nexport const MUTABLE_CACHE_CONTROL = 'public, max-age=0, must-revalidate'\n\n/**\n * Base for publish runners targeting S3-compatible storage. Bodies are pre-compressed at\n * write time and stored with the matching Content-Encoding plus application/json, so HTTP\n * clients decompress transparently \u2014 keys keep their `.json` extension.\n */\nexport abstract class AbstractS3PublishRunner<TParams extends S3PublishRunnerParams = S3PublishRunnerParams>\n extends AbstractCreatableProvider<TParams> {\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 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", "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 { asXL1BlockNumber, BlockPublishRunnerMoniker } from '@xyo-network/xl1-protocol-lib'\nimport { creatableProvider } from '@xyo-network/xl1-protocol-sdk'\nimport {\n blockHashPath, blockNumberPath, payloadPath,\n} from '@xyo-network/xl1-rest-block-viewer'\nimport { Semaphore } from 'async-mutex'\n\nimport type { S3PublishRunnerParams } from './AbstractS3PublishRunner.ts'\nimport { AbstractS3PublishRunner, IMMUTABLE_CACHE_CONTROL } from './AbstractS3PublishRunner.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 S3PublishRunnerParams {\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 /** The viewer to publish from (only finalized chains should be published). */\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 AbstractS3PublishRunner<S3BlockPublishRunnerParams> implements BlockPublishRunner {\n static readonly defaultMoniker = BlockPublishRunnerMoniker\n static readonly dependencies = []\n static readonly monikers = [BlockPublishRunnerMoniker]\n moniker = S3BlockPublishRunner.defaultMoniker\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.params.source, () => 'No source specified')\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 /**\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\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 ChainStatePublishRunner, ChainStateViewerMethods, SignedHydratedBlockWithHashMeta,\n} from '@xyo-network/xl1-protocol-lib'\nimport { 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 { S3PublishRunnerParams } from './AbstractS3PublishRunner.ts'\nimport { AbstractS3PublishRunner, MUTABLE_CACHE_CONTROL } from './AbstractS3PublishRunner.ts'\n\n/** Parameters for S3ChainStatePublishRunner. */\nexport interface S3ChainStatePublishRunnerParams extends S3PublishRunnerParams {\n /** Where the current head is read from (any BlockViewer satisfies this). */\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 AbstractS3PublishRunner<S3ChainStatePublishRunnerParams> implements ChainStatePublishRunner {\n static readonly defaultMoniker = ChainStatePublishRunnerMoniker\n static readonly dependencies = []\n static readonly monikers = [ChainStatePublishRunnerMoniker]\n moniker = S3ChainStatePublishRunner.defaultMoniker\n\n get source(): ChainStateViewerMethods {\n return assertEx(this.params.source, () => 'No source specified')\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 { assertEx } from '@xylabs/sdk-js'\nimport type {\n BlocksStepSummary, BlockViewer, IndexPublishRunner, XL1BlockNumber,\n} from '@xyo-network/xl1-protocol-lib'\nimport {\n BlocksStepSummarySchema, IndexPublishRunnerMoniker, StepSizes,\n} from '@xyo-network/xl1-protocol-lib'\nimport { blocksMaxStep, creatableProvider } from '@xyo-network/xl1-protocol-sdk'\nimport { blocksStepPath } from '@xyo-network/xl1-rest-block-viewer'\n\nimport type { S3PublishRunnerParams } from './AbstractS3PublishRunner.ts'\nimport { AbstractS3PublishRunner, IMMUTABLE_CACHE_CONTROL } from './AbstractS3PublishRunner.ts'\n\n/** Parameters for S3IndexPublishRunner. */\nexport interface S3IndexPublishRunnerParams extends S3PublishRunnerParams {\n /** The viewer to publish from (only finalized chains should be published). */\n source: BlockViewer\n}\n\n/**\n * Publishes completed steps' block summaries (the chain index) as the static REST file\n * layout that `RestIndexViewer` reads. Step files are immutable: only complete steps are\n * ever published, and a completed step's blocks never change.\n */\n@creatableProvider()\nexport class S3IndexPublishRunner extends AbstractS3PublishRunner<S3IndexPublishRunnerParams> implements IndexPublishRunner {\n static readonly defaultMoniker = IndexPublishRunnerMoniker\n static readonly dependencies = []\n static readonly monikers = [IndexPublishRunnerMoniker]\n moniker = S3IndexPublishRunner.defaultMoniker\n\n get source(): BlockViewer {\n return assertEx(this.params.source, () => 'No source specified')\n }\n\n /**\n * Publishes one completed step's blocks as a BlocksStepSummary file (blocks oldest-first).\n * Asserts the step is complete \u2014 partial tail steps are never published.\n */\n async publishStep(stepLevel: number, stepIndex: number): Promise<void> {\n const size = StepSizes[stepLevel]\n assertEx(stepLevel <= blocksMaxStep, () => `publishStep does not support step levels above ${blocksMaxStep} (requested ${stepLevel})`)\n const lastBlockNumber = (stepIndex + 1) * size - 1\n const headNumber = await this.source.currentBlockNumber()\n assertEx(lastBlockNumber <= headNumber, () => `Step ${stepLevel}/${stepIndex} is not complete (head ${headNumber})`)\n const newestFirst = await this.source.blocksByStep(stepLevel, stepIndex)\n const blocks = newestFirst.toReversed()\n const summary: BlocksStepSummary = {\n schema: BlocksStepSummarySchema,\n hash: assertEx(blocks.at(-1), () => `No blocks for step ${stepLevel}/${stepIndex}`)[0]._hash,\n stepSize: size,\n blocks,\n }\n await this.putJson(blocksStepPath(stepLevel, stepIndex), JSON.stringify(summary), IMMUTABLE_CACHE_CONTROL)\n this.logger?.info(`S3IndexPublishRunner: published step ${stepLevel}/${stepIndex}`)\n }\n\n /** Publishes every step (at every level) completed by the given block. */\n async publishStepsCompletedBy(blockNumber: XL1BlockNumber): Promise<void> {\n for (let stepLevel = 0; stepLevel <= blocksMaxStep; stepLevel++) {\n const size = StepSizes[stepLevel]\n if ((blockNumber + 1) % size === 0) {\n await this.publishStep(stepLevel, (blockNumber + 1) / size - 1)\n }\n }\n }\n}\n"],
5
- "mappings": "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",
6
- "names": ["assertEx", "assertEx", "assertEx", "creatableProvider", "assertEx", "creatableProvider", "assertEx", "creatableProvider", "assertEx", "creatableProvider"]
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 /**\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@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 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 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.getJson(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", "creatableProvider", "headPath", "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.3",
4
+ "version": "2.1.5",
5
5
  "description": "XYO Layer One static REST chain layout publisher",
6
6
  "homepage": "https://xylabs.com",
7
7
  "bugs": {
@@ -35,31 +35,29 @@
35
35
  "README.md"
36
36
  ],
37
37
  "dependencies": {
38
- "@xyo-network/xl1-protocol-lib": "~2.1.3",
39
- "@xyo-network/xl1-protocol-sdk": "~2.1.3",
40
- "@xyo-network/xl1-rest-block-viewer": "~2.1.3"
38
+ "@xyo-network/xl1-protocol-lib": "~2.1.5",
39
+ "@xyo-network/xl1-protocol-sdk": "~2.1.5",
40
+ "@xyo-network/xl1-rest-block-viewer": "~2.1.5"
41
41
  },
42
42
  "devDependencies": {
43
- "@aws-sdk/client-s3": "^3.1065.0",
43
+ "@aws-sdk/client-s3": "^3.1067.0",
44
44
  "@bitauth/libauth": "~3.0.0",
45
45
  "@metamask/providers": "^22.1.1",
46
46
  "@noble/post-quantum": "~0.6.1",
47
47
  "@opentelemetry/api": "^1.9.1",
48
- "@opentelemetry/sdk-trace-base": "^2.7.1",
48
+ "@opentelemetry/sdk-trace-base": "^2.8.0",
49
49
  "@scure/base": "~2.2.0",
50
50
  "@scure/bip39": "~2.2.0",
51
- "@xylabs/geo": "^6.1.0",
52
- "@xylabs/sdk-js": "^6.1.0",
53
- "@xylabs/threads": "~6.1",
51
+ "@xylabs/geo": "^6.1.1",
52
+ "@xylabs/sdk-js": "^6.1.1",
53
+ "@xylabs/threads": "^6.1.1",
54
54
  "@xylabs/toolchain": "~8.1.20",
55
55
  "@xylabs/tsconfig": "~8.1.20",
56
- "@xyo-network/address": "^6.0.9",
57
- "@xyo-network/sdk-js": "^6.0.4",
58
- "@xyo-network/sdk-protocol-js": "~6.0.9",
56
+ "@xyo-network/address": "^6.1.1",
57
+ "@xyo-network/sdk-js": "^6.1.0",
58
+ "@xyo-network/sdk-protocol-js": "~6.1.1",
59
59
  "ajv": "^8.20.0",
60
60
  "async-mutex": "^0.5.0",
61
- "bn.js": "^5.2.3",
62
- "buffer": "^6.0.3",
63
61
  "cosmiconfig": "^9.0.2",
64
62
  "debug": "~4.4.3",
65
63
  "eslint": "^10.4.1",
@@ -88,11 +86,9 @@
88
86
  "@xylabs/threads": "^6.1",
89
87
  "@xyo-network/address": "^6.0",
90
88
  "@xyo-network/sdk-js": "^6.0",
91
- "@xyo-network/sdk-protocol-js": "~6.0",
89
+ "@xyo-network/sdk-protocol-js": "~6.1",
92
90
  "ajv": "^8.20",
93
91
  "async-mutex": "^0.5",
94
- "bn.js": "^5.2",
95
- "buffer": "^6.0",
96
92
  "cosmiconfig": "^9.0",
97
93
  "debug": "~4.4",
98
94
  "ethers": "^6.16",
@@ -1,31 +0,0 @@
1
- import type { S3Client } from '@aws-sdk/client-s3';
2
- import type { CreatableProviderParams } from '@xyo-network/xl1-protocol-sdk';
3
- import { AbstractCreatableProvider } from '@xyo-network/xl1-protocol-sdk';
4
- import type { RestContentEncoding } from './encoding.ts';
5
- /** Shared parameters for S3 publish runners: where and how published files are written. */
6
- export interface S3PublishRunnerParams extends CreatableProviderParams {
7
- bucket: string;
8
- /** S3-compatible client pointed at the target endpoint (e.g. Cloudflare R2). */
9
- client: S3Client;
10
- /** Storage/wire encoding for published files. Defaults to 'br' (brotli). */
11
- contentEncoding?: RestContentEncoding;
12
- /** Optional key prefix, allowing the layout to live in a shared bucket. */
13
- prefix?: string;
14
- }
15
- /** Finalized files never change once written. */
16
- export declare const IMMUTABLE_CACHE_CONTROL = "public, max-age=31536000, immutable";
17
- /** Chain state is rewritten as the chain advances. */
18
- export declare const MUTABLE_CACHE_CONTROL = "public, max-age=0, must-revalidate";
19
- /**
20
- * Base for publish runners targeting S3-compatible storage. Bodies are pre-compressed at
21
- * write time and stored with the matching Content-Encoding plus application/json, so HTTP
22
- * clients decompress transparently — keys keep their `.json` extension.
23
- */
24
- export declare abstract class AbstractS3PublishRunner<TParams extends S3PublishRunnerParams = S3PublishRunnerParams> extends AbstractCreatableProvider<TParams> {
25
- get bucket(): string;
26
- get client(): S3Client;
27
- get contentEncoding(): RestContentEncoding;
28
- get prefix(): string;
29
- protected putJson(path: string, json: string, cacheControl: string): Promise<void>;
30
- }
31
- //# sourceMappingURL=AbstractS3PublishRunner.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"AbstractS3PublishRunner.d.ts","sourceRoot":"","sources":["../../src/AbstractS3PublishRunner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAGlD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAA;AAC5E,OAAO,EAAE,yBAAyB,EAAE,MAAM,+BAA+B,CAAA;AAEzE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAA;AAGxD,2FAA2F;AAC3F,MAAM,WAAW,qBAAsB,SAAQ,uBAAuB;IACpE,MAAM,EAAE,MAAM,CAAA;IACd,gFAAgF;IAChF,MAAM,EAAE,QAAQ,CAAA;IAChB,4EAA4E;IAC5E,eAAe,CAAC,EAAE,mBAAmB,CAAA;IACrC,2EAA2E;IAC3E,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,iDAAiD;AACjD,eAAO,MAAM,uBAAuB,wCAAwC,CAAA;AAC5E,sDAAsD;AACtD,eAAO,MAAM,qBAAqB,uCAAuC,CAAA;AAEzE;;;;GAIG;AACH,8BAAsB,uBAAuB,CAAC,OAAO,SAAS,qBAAqB,GAAG,qBAAqB,CACzG,SAAQ,yBAAyB,CAAC,OAAO,CAAC;IAC1C,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,IAAI,MAAM,IAAI,QAAQ,CAErB;IAED,IAAI,eAAe,IAAI,mBAAmB,CAEzC;IAED,IAAI,MAAM,IAAI,MAAM,CAEnB;cAEe,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAWzF"}