@xyo-network/xl1-rest-block-viewer 2.0.14 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/dist/neutral/RestBlockViewer.d.ts +14 -6
- package/dist/neutral/RestBlockViewer.d.ts.map +1 -1
- package/dist/neutral/index.mjs +10 -6
- package/dist/neutral/index.mjs.map +2 -2
- package/dist/neutral/paths.d.ts +5 -0
- package/dist/neutral/paths.d.ts.map +1 -1
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -19,13 +19,14 @@ Finalized XL1 blocks and completed steps never change, so the whole chain can be
|
|
|
19
19
|
/payload/<hash>.json ← payload by hash
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
The path builders in `paths.ts` are the shared contract between the
|
|
22
|
+
The path builders in `paths.ts` are the shared contract between the writers of these files and this viewer that reads them. The finalized (immutable) files and the mutable chain state (the head pointer) may live in separate buckets behind separate domains — the publisher writes the finalized files, the chain's finalizer writes the head pointer. Every file except the head pointer is immutable, so responses are cached aggressively (in-memory LRU here, CDN/edge in front). `blocksByStep` serves completed steps only — the in-flight tail step has no file and returns `[]`.
|
|
23
23
|
|
|
24
24
|
```ts
|
|
25
25
|
import { RestBlockViewer } from '@xyo-network/xl1-rest-block-viewer'
|
|
26
26
|
|
|
27
27
|
const viewer = await RestBlockViewer.create({
|
|
28
|
-
|
|
28
|
+
finalizedBaseUrl: 'https://chain.example.com', // finalized (immutable) files
|
|
29
|
+
chainStateBaseUrl: 'https://head.example.com', // optional: chain state / head pointer domain (defaults to finalizedBaseUrl)
|
|
29
30
|
headPollIntervalMs: 10_000, // optional: emit headUpdated as the head advances
|
|
30
31
|
})
|
|
31
32
|
await viewer.start()
|
|
@@ -6,18 +6,24 @@ import type { CreatableProviderParams } from '@xyo-network/xl1-protocol-sdk';
|
|
|
6
6
|
import { AbstractCreatableProvider } from '@xyo-network/xl1-protocol-sdk';
|
|
7
7
|
/** Parameters for RestBlockViewer. */
|
|
8
8
|
export interface RestBlockViewerParams extends CreatableProviderParams {
|
|
9
|
-
/**
|
|
10
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Base URL serving the mutable chain state (the head pointer, `chain/head.json`) when it
|
|
11
|
+
* lives in a separate bucket/domain from the finalized files. Defaults to `finalizedBaseUrl`.
|
|
12
|
+
*/
|
|
13
|
+
chainStateBaseUrl?: string;
|
|
11
14
|
/** Optional fetch override (custom agents, auth headers, tests). Defaults to the global fetch. */
|
|
12
15
|
fetchFn?: typeof globalThis.fetch;
|
|
16
|
+
/** Base URL of the finalized (immutable) static chain files (e.g. a public R2 bucket or CDN domain). */
|
|
17
|
+
finalizedBaseUrl: string;
|
|
13
18
|
headPollIntervalMs?: number;
|
|
14
19
|
}
|
|
15
20
|
/**
|
|
16
21
|
* A BlockViewer over a statically generated REST file layout (see `paths.ts`).
|
|
17
22
|
*
|
|
18
23
|
* Reads are anonymous HTTP GETs against immutable files, so everything except the head
|
|
19
|
-
* pointer is cached aggressively.
|
|
20
|
-
*
|
|
24
|
+
* pointer is cached aggressively. The head pointer is read from `chainStateBaseUrl` when
|
|
25
|
+
* the chain state and finalized files live in separate buckets/domains. `blocksByStep`
|
|
26
|
+
* serves only completed steps — the in-flight tail step has no static file and returns [].
|
|
21
27
|
*/
|
|
22
28
|
export declare class RestBlockViewer extends AbstractCreatableProvider<RestBlockViewerParams, BlockViewer['eventData']> implements BlockViewer {
|
|
23
29
|
static readonly defaultMoniker: "BlockViewer";
|
|
@@ -127,12 +133,14 @@ export declare class RestBlockViewer extends AbstractCreatableProvider<RestBlock
|
|
|
127
133
|
private _headPollHash?;
|
|
128
134
|
private _headPollInProgress;
|
|
129
135
|
private _headPollTimer;
|
|
130
|
-
get
|
|
136
|
+
get chainStateBaseUrl(): string;
|
|
137
|
+
get finalizedBaseUrl(): string;
|
|
131
138
|
protected get fetchFn(): typeof globalThis.fetch;
|
|
132
139
|
protected get headPollIntervalMs(): number | undefined;
|
|
133
140
|
static paramsHandler(params: Partial<RestBlockViewerParams>): Promise<{
|
|
134
|
-
|
|
141
|
+
chainStateBaseUrl: string | undefined;
|
|
135
142
|
fetchFn: typeof fetch | undefined;
|
|
143
|
+
finalizedBaseUrl: string;
|
|
136
144
|
headPollIntervalMs: number | undefined;
|
|
137
145
|
context: import("@xyo-network/xl1-protocol-sdk").CreatableProviderContextType;
|
|
138
146
|
name?: import("@xylabs/sdk-js").CreatableName;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RestBlockViewer.d.ts","sourceRoot":"","sources":["../../src/RestBlockViewer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAA;AAE1C,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAEhE,OAAO,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAA;AAC5D,OAAO,KAAK,EACV,SAAS,EAAE,WAAW,EAAE,OAAO,EAC/B,+BAA+B,EAAE,gBAAgB,EAAE,aAAa,EAAE,cAAc,EAAE,aAAa,EAChG,MAAM,+BAA+B,CAAA;AAItC,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAA;AAC5E,OAAO,EACL,yBAAyB,EAC1B,MAAM,+BAA+B,CAAA;AAMtC,sCAAsC;AACtC,MAAM,WAAW,qBAAsB,SAAQ,uBAAuB;IACpE
|
|
1
|
+
{"version":3,"file":"RestBlockViewer.d.ts","sourceRoot":"","sources":["../../src/RestBlockViewer.ts"],"names":[],"mappings":"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"}
|
package/dist/neutral/index.mjs
CHANGED
|
@@ -48,8 +48,11 @@ var RestBlockViewer = class extends AbstractCreatableProvider {
|
|
|
48
48
|
_headPollHash;
|
|
49
49
|
_headPollInProgress = false;
|
|
50
50
|
_headPollTimer = null;
|
|
51
|
-
get
|
|
52
|
-
return this.params.
|
|
51
|
+
get chainStateBaseUrl() {
|
|
52
|
+
return this.params.chainStateBaseUrl ?? this.params.finalizedBaseUrl;
|
|
53
|
+
}
|
|
54
|
+
get finalizedBaseUrl() {
|
|
55
|
+
return this.params.finalizedBaseUrl;
|
|
53
56
|
}
|
|
54
57
|
get fetchFn() {
|
|
55
58
|
return this.params.fetchFn ?? globalThis.fetch.bind(globalThis);
|
|
@@ -64,8 +67,9 @@ var RestBlockViewer = class extends AbstractCreatableProvider {
|
|
|
64
67
|
}
|
|
65
68
|
return {
|
|
66
69
|
...await super.paramsHandler(params),
|
|
67
|
-
|
|
70
|
+
chainStateBaseUrl: params.chainStateBaseUrl?.replace(/\/+$/, ""),
|
|
68
71
|
fetchFn: params.fetchFn,
|
|
72
|
+
finalizedBaseUrl: assertEx(params.finalizedBaseUrl, () => "finalizedBaseUrl is required").replace(/\/+$/, ""),
|
|
69
73
|
headPollIntervalMs
|
|
70
74
|
};
|
|
71
75
|
}
|
|
@@ -140,7 +144,7 @@ var RestBlockViewer = class extends AbstractCreatableProvider {
|
|
|
140
144
|
}
|
|
141
145
|
async currentBlock() {
|
|
142
146
|
return await this.spanAsync("currentBlock", async () => {
|
|
143
|
-
const parsed = assertEx(await this.fetchJson(headPath()), () => "Head not found");
|
|
147
|
+
const parsed = assertEx(await this.fetchJson(headPath(), this.chainStateBaseUrl), () => "Head not found");
|
|
144
148
|
return this.cacheBlock(parsed);
|
|
145
149
|
}, this.context);
|
|
146
150
|
}
|
|
@@ -195,8 +199,8 @@ var RestBlockViewer = class extends AbstractCreatableProvider {
|
|
|
195
199
|
this.blockByNumberCache.set(block[0].block, block);
|
|
196
200
|
return block;
|
|
197
201
|
}
|
|
198
|
-
async fetchJson(path) {
|
|
199
|
-
const response = await this.fetchFn(`${
|
|
202
|
+
async fetchJson(path, baseUrl = this.finalizedBaseUrl) {
|
|
203
|
+
const response = await this.fetchFn(`${baseUrl}/${path}`);
|
|
200
204
|
if (response.status === 404) return void 0;
|
|
201
205
|
assertEx(response.ok, () => `Request failed [${response.status}] for ${path}`);
|
|
202
206
|
return await response.json();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/paths.ts", "../../src/RestBlockViewer.ts"],
|
|
4
|
-
"sourcesContent": ["import type { Hash } from '@xylabs/sdk-js'\n\n/**\n * Path contract for the static REST chain layout.\n *\n * These builders are the single source of truth for where files live, shared by the\n * publisher (which writes the static files) and `RestBlockViewer` (which reads them),\n * so the layout cannot drift between the two. Paths are relative \u2014 no leading slash \u2014\n * and joined to a base URL by the consumer.\n *\n * Every file except the head pointer is immutable once written:\n * - block and payload files never change after finalization\n * - step files are only written for completed steps\n * - the head pointer is rewritten as the chain advances and must not be cached long-term\n */\n\n/** The mutable head pointer: the current head SignedHydratedBlockWithHashMeta. */\nexport const headPath = (): string => 'chain/head.json'\n\n/** A block by number: SignedHydratedBlockWithHashMeta. */\nexport const blockNumberPath = (block: number): string => `block/number/${block}.json`\n\n/** A block by hash: the same content as its by-number twin. */\nexport const blockHashPath = (hash: Hash): string => `block/hash/${hash}.json`\n\n/**\n * A completed step's blocks: a BlocksStepSummary payload whose `blocks` array is ordered\n * oldest-first. Only complete steps are published; the in-flight tail step has no file.\n */\nexport const blocksStepPath = (stepLevel: number, stepIndex: number): string => `blocks/step/${stepLevel}/${stepIndex}.json`\n\n/** A payload by hash: WithHashMeta<Payload>. */\nexport const payloadPath = (hash: Hash): string => `payload/${hash}.json`\n", "import type { Hash } from '@xylabs/sdk-js'\nimport { assertEx, exists } from '@xylabs/sdk-js'\nimport type { Payload, WithHashMeta } from '@xyo-network/sdk-js'\nimport { PayloadZodLoose, WithHashMetaZod } from '@xyo-network/sdk-js'\nimport { LruCacheMap } from '@xyo-network/xl1-driver-memory'\nimport type {\n BlockRate, BlockViewer, ChainId,\n SignedHydratedBlockWithHashMeta, SingleTimeConfig, TimeDurations, XL1BlockNumber, XL1BlockRange,\n} from '@xyo-network/xl1-protocol-lib'\nimport {\n asSignedHydratedBlockWithHashMeta, asXL1BlockNumber, BlockViewerMoniker, stepSize,\n} from '@xyo-network/xl1-protocol-lib'\nimport type { CreatableProviderParams } from '@xyo-network/xl1-protocol-sdk'\nimport {\n AbstractCreatableProvider, asBlocksStepSummary, blocksMaxStep, calculateBlockRate, calculateStepSizeRate, calculateTimeRate, creatableProvider,\n} from '@xyo-network/xl1-protocol-sdk'\n\nimport {\n blockHashPath, blockNumberPath, blocksStepPath, headPath, payloadPath,\n} from './paths.ts'\n\n/** Parameters for RestBlockViewer. */\nexport interface RestBlockViewerParams extends CreatableProviderParams {\n /** Base URL of the static chain layout (e.g. a public R2 bucket or CDN domain). */\n baseUrl: string\n /** Optional fetch override (custom agents, auth headers, tests). Defaults to the global fetch. */\n fetchFn?: typeof globalThis.fetch\n headPollIntervalMs?: number\n}\n\nconst MIN_HEAD_POLL_INTERVAL_MS = 5000\n\nconst PayloadFileZod = WithHashMetaZod(PayloadZodLoose)\n\n/**\n * A BlockViewer over a statically generated REST file layout (see `paths.ts`).\n *\n * Reads are anonymous HTTP GETs against immutable files, so everything except the head\n * pointer is cached aggressively. `blocksByStep` serves only completed steps \u2014 the\n * in-flight tail step has no static file and returns [].\n */\n@creatableProvider()\nexport class RestBlockViewer extends AbstractCreatableProvider<RestBlockViewerParams, BlockViewer['eventData']> implements BlockViewer {\n static readonly defaultMoniker = BlockViewerMoniker\n static readonly dependencies = []\n static readonly monikers = [BlockViewerMoniker]\n moniker = RestBlockViewer.defaultMoniker\n\n protected blockByHashCache = new LruCacheMap<Hash, SignedHydratedBlockWithHashMeta>({ max: 2000 })\n protected blockByNumberCache = new LruCacheMap<XL1BlockNumber, SignedHydratedBlockWithHashMeta>({ max: 2000 })\n protected payloadCache = new LruCacheMap<Hash, WithHashMeta<Payload>>({ max: 10_000 })\n protected stepCache = new LruCacheMap<string, SignedHydratedBlockWithHashMeta[]>({ max: 4 })\n\n private _headPollHash?: Hash\n private _headPollInProgress = false\n private _headPollTimer: ReturnType<typeof setInterval> | null = null\n\n get baseUrl(): string {\n return this.params.baseUrl\n }\n\n protected get fetchFn(): typeof globalThis.fetch {\n return this.params.fetchFn ?? globalThis.fetch.bind(globalThis)\n }\n\n protected get headPollIntervalMs() {\n return this.params.headPollIntervalMs\n }\n\n static override async paramsHandler(params: Partial<RestBlockViewerParams>) {\n const headPollIntervalMs = params.headPollIntervalMs\n if (headPollIntervalMs !== undefined) {\n assertEx(headPollIntervalMs >= MIN_HEAD_POLL_INTERVAL_MS, () => `headPollIntervalMs must be at least ${MIN_HEAD_POLL_INTERVAL_MS}ms`)\n }\n return {\n ...await super.paramsHandler(params),\n baseUrl: assertEx(params.baseUrl, () => 'baseUrl is required').replace(/\\/+$/, ''),\n fetchFn: params.fetchFn,\n headPollIntervalMs,\n } satisfies RestBlockViewerParams\n }\n\n async blockByHash(hash: Hash): Promise<SignedHydratedBlockWithHashMeta | null> {\n return await this.spanAsync('blockByHash', async () => {\n const cached = this.blockByHashCache.get(hash)\n if (cached) return cached\n const parsed = await this.fetchJson(blockHashPath(hash))\n return parsed === undefined ? null : this.cacheBlock(parsed)\n }, { ...this.context, timeBudgetLimit: 100 })\n }\n\n async blockByNumber(blockNumber: XL1BlockNumber): Promise<SignedHydratedBlockWithHashMeta | null> {\n return await this.spanAsync('blockByNumber', async () => {\n const cached = this.blockByNumberCache.get(blockNumber)\n if (cached) return cached\n const parsed = await this.fetchJson(blockNumberPath(blockNumber))\n return parsed === undefined ? null : this.cacheBlock(parsed)\n }, { ...this.context, timeBudgetLimit: 100 })\n }\n\n async blocksByHash(hash: Hash, limit = 50): Promise<SignedHydratedBlockWithHashMeta[]> {\n return await this.spanAsync('blocksByHash', async () => {\n assertEx(limit > 0, () => 'limit must be greater than 0')\n assertEx(limit <= 100, () => 'limit must be less than 100')\n const blocks: SignedHydratedBlockWithHashMeta[] = []\n let current = await this.blockByHash(hash)\n while (current && blocks.length < limit) {\n blocks.push(current)\n const previousHash = current[0].previous\n if (previousHash === null) break\n current = await this.blockByHash(previousHash)\n }\n return blocks\n }, { ...this.context, timeBudgetLimit: 300 })\n }\n\n async blocksByNumber(blockNumber: XL1BlockNumber, limit = 50): Promise<SignedHydratedBlockWithHashMeta[]> {\n return await this.spanAsync('blocksByNumber', async () => {\n assertEx(limit > 0, () => 'limit must be greater than 0')\n assertEx(limit <= 100, () => 'limit must be less than 100')\n const blocks: SignedHydratedBlockWithHashMeta[] = []\n let current = await this.blockByNumber(blockNumber)\n while (current && blocks.length < limit) {\n blocks.push(current)\n if (current[0].block === 0) break\n current = await this.blockByNumber(asXL1BlockNumber(current[0].block - 1, true))\n }\n return blocks\n }, this.context)\n }\n\n async blocksByStep(stepLevel: number, stepIndex: number): Promise<SignedHydratedBlockWithHashMeta[]> {\n return await this.spanAsync('blocksByStep', async () => {\n assertEx(Number.isInteger(stepIndex) && stepIndex >= 0, () => 'stepIndex must be a non-negative integer')\n stepSize(stepLevel) // validates the level against StepSizes\n assertEx(\n stepLevel <= blocksMaxStep,\n () => `blocksByStep does not support step levels above ${blocksMaxStep} (requested ${stepLevel})`,\n )\n const cacheKey = `${stepLevel}|${stepIndex}`\n const cached = this.stepCache.get(cacheKey)\n if (cached) return cached\n const parsed = await this.fetchJson(blocksStepPath(stepLevel, stepIndex))\n // Only completed steps are published; the in-flight tail step has no file\n if (parsed === undefined) return []\n const summary = asBlocksStepSummary(parsed, { required: true })\n // Step files store blocks oldest-first; the viewer interface returns newest-first\n const blocks = summary.blocks.map(b => asSignedHydratedBlockWithHashMeta(b, true)).toReversed()\n this.stepCache.set(cacheKey, blocks)\n return blocks\n }, this.context)\n }\n\n chainId(): Promise<ChainId>\n chainId(blockNumber: XL1BlockNumber): Promise<ChainId>\n chainId(blockNumber: 'latest'): Promise<ChainId>\n async chainId(blockNumber: XL1BlockNumber | 'latest' = 'latest'): Promise<ChainId> {\n return await this.spanAsync('chainId', async () => {\n return blockNumber === 'latest'\n ? (await this.currentBlock())[0].chain\n : assertEx(await this.blockByNumber(blockNumber), () => `Block not found [${blockNumber}]`)[0].chain\n }, this.context)\n }\n\n async currentBlock(): Promise<SignedHydratedBlockWithHashMeta> {\n return await this.spanAsync('currentBlock', async () => {\n const parsed = assertEx(await this.fetchJson(headPath()), () => 'Head not found')\n return this.cacheBlock(parsed)\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 async payloadByHash(hash: Hash): Promise<WithHashMeta<Payload> | null> {\n const [payload] = await this.payloadsByHash([hash])\n return payload ?? null\n }\n\n async payloadsByHash(hashes: Hash[]): Promise<WithHashMeta<Payload>[]> {\n return await this.spanAsync('payloadsByHash', async () => {\n const results = await Promise.all(hashes.map(async (hash) => {\n const cached = this.payloadCache.get(hash)\n if (cached) return cached\n const parsed = await this.fetchJson(payloadPath(hash))\n if (parsed === undefined) return\n const payload = PayloadFileZod.parse(parsed)\n this.payloadCache.set(hash, payload)\n return payload\n }))\n return results.filter(exists)\n }, this.context)\n }\n\n async rate(range: XL1BlockRange, timeUnit?: keyof TimeDurations): Promise<BlockRate> {\n return await calculateBlockRate(this, range, timeUnit)\n }\n\n async stepSizeRate(start: XL1BlockNumber, stepIndex: number, count = 1, timeUnit?: keyof TimeDurations): Promise<BlockRate> {\n return await calculateStepSizeRate(this, start, stepIndex, count, timeUnit)\n }\n\n async timeDurationRate(\n timeConfig: SingleTimeConfig,\n startBlockNumber?: XL1BlockNumber,\n timeUnit?: keyof TimeDurations,\n toleranceMs?: number,\n maxAttempts?: number,\n ): Promise<BlockRate> {\n return await calculateTimeRate(this, timeConfig, startBlockNumber, timeUnit, toleranceMs, maxAttempts)\n }\n\n protected override async startHandler(): Promise<void> {\n await super.startHandler()\n if (this.headPollIntervalMs === undefined) return\n await this.pollHead(false)\n this.startHeadPolling()\n }\n\n protected override async stopHandler(): Promise<void> {\n this.stopHeadPolling()\n this._headPollHash = undefined\n await super.stopHandler()\n }\n\n /** Validates a parsed block file and populates both block caches. */\n private cacheBlock(parsed: unknown): SignedHydratedBlockWithHashMeta {\n const block = asSignedHydratedBlockWithHashMeta(parsed, true)\n this.blockByHashCache.set(block[0]._hash, block)\n this.blockByNumberCache.set(block[0].block, block)\n return block\n }\n\n private async fetchJson(path: string): Promise<unknown> {\n const response = await this.fetchFn(`${this.baseUrl}/${path}`)\n if (response.status === 404) return undefined\n assertEx(response.ok, () => `Request failed [${response.status}] for ${path}`)\n return await response.json()\n }\n\n private async pollHead(emitOnChange: boolean): Promise<void> {\n if (this._headPollInProgress) return\n this._headPollInProgress = true\n try {\n const block = await this.currentBlock()\n const hash = block[0]._hash\n if (this._headPollHash === undefined) {\n this._headPollHash = hash\n return\n }\n if (hash !== this._headPollHash) {\n this._headPollHash = hash\n if (emitOnChange) {\n await this.emit('headUpdated', { block })\n }\n }\n } catch (ex) {\n this.logger?.error('Error polling block head', ex)\n } finally {\n this._headPollInProgress = false\n }\n }\n\n private startHeadPolling() {\n if (this.headPollIntervalMs === undefined) return\n this.stopHeadPolling()\n this._headPollTimer = setInterval(() => {\n void this.pollHead(true)\n }, this.headPollIntervalMs)\n }\n\n private stopHeadPolling() {\n if (this._headPollTimer) {\n clearInterval(this._headPollTimer)\n this._headPollTimer = null\n }\n }\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;
|
|
4
|
+
"sourcesContent": ["import type { Hash } from '@xylabs/sdk-js'\n\n/**\n * Path contract for the static REST chain layout.\n *\n * These builders are the single source of truth for where files live, shared by the\n * publisher (which writes the static files) and `RestBlockViewer` (which reads them),\n * so the layout cannot drift between the two. Paths are relative \u2014 no leading slash \u2014\n * and joined to a base URL by the consumer.\n *\n * Every file except the head pointer is immutable once written:\n * - block and payload files never change after finalization\n * - step files are only written for completed steps\n * - the head pointer is rewritten as the chain advances and must not be cached long-term\n *\n * The finalized (immutable) files and the mutable chain state (the head pointer) may live\n * in separate buckets behind separate domains: the publisher writes only the finalized\n * files, the chain's finalizer writes the head pointer, and the viewer joins `headPath` to\n * its chain-state base URL and everything else to its finalized base URL.\n */\n\n/** The mutable head pointer: the current head SignedHydratedBlockWithHashMeta. */\nexport const headPath = (): string => 'chain/head.json'\n\n/** A block by number: SignedHydratedBlockWithHashMeta. */\nexport const blockNumberPath = (block: number): string => `block/number/${block}.json`\n\n/** A block by hash: the same content as its by-number twin. */\nexport const blockHashPath = (hash: Hash): string => `block/hash/${hash}.json`\n\n/**\n * A completed step's blocks: a BlocksStepSummary payload whose `blocks` array is ordered\n * oldest-first. Only complete steps are published; the in-flight tail step has no file.\n */\nexport const blocksStepPath = (stepLevel: number, stepIndex: number): string => `blocks/step/${stepLevel}/${stepIndex}.json`\n\n/** A payload by hash: WithHashMeta<Payload>. */\nexport const payloadPath = (hash: Hash): string => `payload/${hash}.json`\n", "import type { Hash } from '@xylabs/sdk-js'\nimport { assertEx, exists } from '@xylabs/sdk-js'\nimport type { Payload, WithHashMeta } from '@xyo-network/sdk-js'\nimport { PayloadZodLoose, WithHashMetaZod } from '@xyo-network/sdk-js'\nimport { LruCacheMap } from '@xyo-network/xl1-driver-memory'\nimport type {\n BlockRate, BlockViewer, ChainId,\n SignedHydratedBlockWithHashMeta, SingleTimeConfig, TimeDurations, XL1BlockNumber, XL1BlockRange,\n} from '@xyo-network/xl1-protocol-lib'\nimport {\n asSignedHydratedBlockWithHashMeta, asXL1BlockNumber, BlockViewerMoniker, stepSize,\n} from '@xyo-network/xl1-protocol-lib'\nimport type { CreatableProviderParams } from '@xyo-network/xl1-protocol-sdk'\nimport {\n AbstractCreatableProvider, asBlocksStepSummary, blocksMaxStep, calculateBlockRate, calculateStepSizeRate, calculateTimeRate, creatableProvider,\n} from '@xyo-network/xl1-protocol-sdk'\n\nimport {\n blockHashPath, blockNumberPath, blocksStepPath, headPath, payloadPath,\n} from './paths.ts'\n\n/** Parameters for RestBlockViewer. */\nexport interface RestBlockViewerParams extends CreatableProviderParams {\n /**\n * Base URL serving the mutable chain state (the head pointer, `chain/head.json`) when it\n * lives in a separate bucket/domain from the finalized files. Defaults to `finalizedBaseUrl`.\n */\n chainStateBaseUrl?: string\n /** Optional fetch override (custom agents, auth headers, tests). Defaults to the global fetch. */\n fetchFn?: typeof globalThis.fetch\n /** Base URL of the finalized (immutable) static chain files (e.g. a public R2 bucket or CDN domain). */\n finalizedBaseUrl: string\n headPollIntervalMs?: number\n}\n\nconst MIN_HEAD_POLL_INTERVAL_MS = 5000\n\nconst PayloadFileZod = WithHashMetaZod(PayloadZodLoose)\n\n/**\n * A BlockViewer over a statically generated REST file layout (see `paths.ts`).\n *\n * Reads are anonymous HTTP GETs against immutable files, so everything except the head\n * pointer is cached aggressively. The head pointer is read from `chainStateBaseUrl` when\n * the chain state and finalized files live in separate buckets/domains. `blocksByStep`\n * serves only completed steps \u2014 the in-flight tail step has no static file and returns [].\n */\n@creatableProvider()\nexport class RestBlockViewer extends AbstractCreatableProvider<RestBlockViewerParams, BlockViewer['eventData']> implements BlockViewer {\n static readonly defaultMoniker = BlockViewerMoniker\n static readonly dependencies = []\n static readonly monikers = [BlockViewerMoniker]\n moniker = RestBlockViewer.defaultMoniker\n\n protected blockByHashCache = new LruCacheMap<Hash, SignedHydratedBlockWithHashMeta>({ max: 2000 })\n protected blockByNumberCache = new LruCacheMap<XL1BlockNumber, SignedHydratedBlockWithHashMeta>({ max: 2000 })\n protected payloadCache = new LruCacheMap<Hash, WithHashMeta<Payload>>({ max: 10_000 })\n protected stepCache = new LruCacheMap<string, SignedHydratedBlockWithHashMeta[]>({ max: 4 })\n\n private _headPollHash?: Hash\n private _headPollInProgress = false\n private _headPollTimer: ReturnType<typeof setInterval> | null = null\n\n get chainStateBaseUrl(): string {\n return this.params.chainStateBaseUrl ?? this.params.finalizedBaseUrl\n }\n\n get finalizedBaseUrl(): string {\n return this.params.finalizedBaseUrl\n }\n\n protected get fetchFn(): typeof globalThis.fetch {\n return this.params.fetchFn ?? globalThis.fetch.bind(globalThis)\n }\n\n protected get headPollIntervalMs() {\n return this.params.headPollIntervalMs\n }\n\n static override async paramsHandler(params: Partial<RestBlockViewerParams>) {\n const headPollIntervalMs = params.headPollIntervalMs\n if (headPollIntervalMs !== undefined) {\n assertEx(headPollIntervalMs >= MIN_HEAD_POLL_INTERVAL_MS, () => `headPollIntervalMs must be at least ${MIN_HEAD_POLL_INTERVAL_MS}ms`)\n }\n return {\n ...await super.paramsHandler(params),\n chainStateBaseUrl: params.chainStateBaseUrl?.replace(/\\/+$/, ''),\n fetchFn: params.fetchFn,\n finalizedBaseUrl: assertEx(params.finalizedBaseUrl, () => 'finalizedBaseUrl is required').replace(/\\/+$/, ''),\n headPollIntervalMs,\n } satisfies RestBlockViewerParams\n }\n\n async blockByHash(hash: Hash): Promise<SignedHydratedBlockWithHashMeta | null> {\n return await this.spanAsync('blockByHash', async () => {\n const cached = this.blockByHashCache.get(hash)\n if (cached) return cached\n const parsed = await this.fetchJson(blockHashPath(hash))\n return parsed === undefined ? null : this.cacheBlock(parsed)\n }, { ...this.context, timeBudgetLimit: 100 })\n }\n\n async blockByNumber(blockNumber: XL1BlockNumber): Promise<SignedHydratedBlockWithHashMeta | null> {\n return await this.spanAsync('blockByNumber', async () => {\n const cached = this.blockByNumberCache.get(blockNumber)\n if (cached) return cached\n const parsed = await this.fetchJson(blockNumberPath(blockNumber))\n return parsed === undefined ? null : this.cacheBlock(parsed)\n }, { ...this.context, timeBudgetLimit: 100 })\n }\n\n async blocksByHash(hash: Hash, limit = 50): Promise<SignedHydratedBlockWithHashMeta[]> {\n return await this.spanAsync('blocksByHash', async () => {\n assertEx(limit > 0, () => 'limit must be greater than 0')\n assertEx(limit <= 100, () => 'limit must be less than 100')\n const blocks: SignedHydratedBlockWithHashMeta[] = []\n let current = await this.blockByHash(hash)\n while (current && blocks.length < limit) {\n blocks.push(current)\n const previousHash = current[0].previous\n if (previousHash === null) break\n current = await this.blockByHash(previousHash)\n }\n return blocks\n }, { ...this.context, timeBudgetLimit: 300 })\n }\n\n async blocksByNumber(blockNumber: XL1BlockNumber, limit = 50): Promise<SignedHydratedBlockWithHashMeta[]> {\n return await this.spanAsync('blocksByNumber', async () => {\n assertEx(limit > 0, () => 'limit must be greater than 0')\n assertEx(limit <= 100, () => 'limit must be less than 100')\n const blocks: SignedHydratedBlockWithHashMeta[] = []\n let current = await this.blockByNumber(blockNumber)\n while (current && blocks.length < limit) {\n blocks.push(current)\n if (current[0].block === 0) break\n current = await this.blockByNumber(asXL1BlockNumber(current[0].block - 1, true))\n }\n return blocks\n }, this.context)\n }\n\n async blocksByStep(stepLevel: number, stepIndex: number): Promise<SignedHydratedBlockWithHashMeta[]> {\n return await this.spanAsync('blocksByStep', async () => {\n assertEx(Number.isInteger(stepIndex) && stepIndex >= 0, () => 'stepIndex must be a non-negative integer')\n stepSize(stepLevel) // validates the level against StepSizes\n assertEx(\n stepLevel <= blocksMaxStep,\n () => `blocksByStep does not support step levels above ${blocksMaxStep} (requested ${stepLevel})`,\n )\n const cacheKey = `${stepLevel}|${stepIndex}`\n const cached = this.stepCache.get(cacheKey)\n if (cached) return cached\n const parsed = await this.fetchJson(blocksStepPath(stepLevel, stepIndex))\n // Only completed steps are published; the in-flight tail step has no file\n if (parsed === undefined) return []\n const summary = asBlocksStepSummary(parsed, { required: true })\n // Step files store blocks oldest-first; the viewer interface returns newest-first\n const blocks = summary.blocks.map(b => asSignedHydratedBlockWithHashMeta(b, true)).toReversed()\n this.stepCache.set(cacheKey, blocks)\n return blocks\n }, this.context)\n }\n\n chainId(): Promise<ChainId>\n chainId(blockNumber: XL1BlockNumber): Promise<ChainId>\n chainId(blockNumber: 'latest'): Promise<ChainId>\n async chainId(blockNumber: XL1BlockNumber | 'latest' = 'latest'): Promise<ChainId> {\n return await this.spanAsync('chainId', async () => {\n return blockNumber === 'latest'\n ? (await this.currentBlock())[0].chain\n : assertEx(await this.blockByNumber(blockNumber), () => `Block not found [${blockNumber}]`)[0].chain\n }, this.context)\n }\n\n async currentBlock(): Promise<SignedHydratedBlockWithHashMeta> {\n return await this.spanAsync('currentBlock', async () => {\n const parsed = assertEx(await this.fetchJson(headPath(), this.chainStateBaseUrl), () => 'Head not found')\n return this.cacheBlock(parsed)\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 async payloadByHash(hash: Hash): Promise<WithHashMeta<Payload> | null> {\n const [payload] = await this.payloadsByHash([hash])\n return payload ?? null\n }\n\n async payloadsByHash(hashes: Hash[]): Promise<WithHashMeta<Payload>[]> {\n return await this.spanAsync('payloadsByHash', async () => {\n const results = await Promise.all(hashes.map(async (hash) => {\n const cached = this.payloadCache.get(hash)\n if (cached) return cached\n const parsed = await this.fetchJson(payloadPath(hash))\n if (parsed === undefined) return\n const payload = PayloadFileZod.parse(parsed)\n this.payloadCache.set(hash, payload)\n return payload\n }))\n return results.filter(exists)\n }, this.context)\n }\n\n async rate(range: XL1BlockRange, timeUnit?: keyof TimeDurations): Promise<BlockRate> {\n return await calculateBlockRate(this, range, timeUnit)\n }\n\n async stepSizeRate(start: XL1BlockNumber, stepIndex: number, count = 1, timeUnit?: keyof TimeDurations): Promise<BlockRate> {\n return await calculateStepSizeRate(this, start, stepIndex, count, timeUnit)\n }\n\n async timeDurationRate(\n timeConfig: SingleTimeConfig,\n startBlockNumber?: XL1BlockNumber,\n timeUnit?: keyof TimeDurations,\n toleranceMs?: number,\n maxAttempts?: number,\n ): Promise<BlockRate> {\n return await calculateTimeRate(this, timeConfig, startBlockNumber, timeUnit, toleranceMs, maxAttempts)\n }\n\n protected override async startHandler(): Promise<void> {\n await super.startHandler()\n if (this.headPollIntervalMs === undefined) return\n await this.pollHead(false)\n this.startHeadPolling()\n }\n\n protected override async stopHandler(): Promise<void> {\n this.stopHeadPolling()\n this._headPollHash = undefined\n await super.stopHandler()\n }\n\n /** Validates a parsed block file and populates both block caches. */\n private cacheBlock(parsed: unknown): SignedHydratedBlockWithHashMeta {\n const block = asSignedHydratedBlockWithHashMeta(parsed, true)\n this.blockByHashCache.set(block[0]._hash, block)\n this.blockByNumberCache.set(block[0].block, block)\n return block\n }\n\n private async fetchJson(path: string, baseUrl = this.finalizedBaseUrl): Promise<unknown> {\n const response = await this.fetchFn(`${baseUrl}/${path}`)\n if (response.status === 404) return undefined\n assertEx(response.ok, () => `Request failed [${response.status}] for ${path}`)\n return await response.json()\n }\n\n private async pollHead(emitOnChange: boolean): Promise<void> {\n if (this._headPollInProgress) return\n this._headPollInProgress = true\n try {\n const block = await this.currentBlock()\n const hash = block[0]._hash\n if (this._headPollHash === undefined) {\n this._headPollHash = hash\n return\n }\n if (hash !== this._headPollHash) {\n this._headPollHash = hash\n if (emitOnChange) {\n await this.emit('headUpdated', { block })\n }\n }\n } catch (ex) {\n this.logger?.error('Error polling block head', ex)\n } finally {\n this._headPollInProgress = false\n }\n }\n\n private startHeadPolling() {\n if (this.headPollIntervalMs === undefined) return\n this.stopHeadPolling()\n this._headPollTimer = setInterval(() => {\n void this.pollHead(true)\n }, this.headPollIntervalMs)\n }\n\n private stopHeadPolling() {\n if (this._headPollTimer) {\n clearInterval(this._headPollTimer)\n this._headPollTimer = null\n }\n }\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;AAsBO,IAAM,WAAW,MAAc;AAG/B,IAAM,kBAAkB,CAAC,UAA0B,gBAAgB,KAAK;AAGxE,IAAM,gBAAgB,CAAC,SAAuB,cAAc,IAAI;AAMhE,IAAM,iBAAiB,CAAC,WAAmB,cAA8B,eAAe,SAAS,IAAI,SAAS;AAG9G,IAAM,cAAc,CAAC,SAAuB,WAAW,IAAI;;;ACpClE,SAAS,UAAU,cAAc;AAEjC,SAAS,iBAAiB,uBAAuB;AACjD,SAAS,mBAAmB;AAK5B;AAAA,EACE;AAAA,EAAmC;AAAA,EAAkB;AAAA,EAAoB;AAAA,OACpE;AAEP;AAAA,EACE;AAAA,EAA2B;AAAA,EAAqB;AAAA,EAAe;AAAA,EAAoB;AAAA,EAAuB;AAAA,EAAmB;AAAA,OACxH;AAoBP,IAAM,4BAA4B;AAElC,IAAM,iBAAiB,gBAAgB,eAAe;AAW/C,IAAM,kBAAN,cAA8B,0BAAkG;AAAA,EAIrI,UAAU,gBAAgB;AAAA,EAEhB,mBAAmB,IAAI,YAAmD,EAAE,KAAK,IAAK,CAAC;AAAA,EACvF,qBAAqB,IAAI,YAA6D,EAAE,KAAK,IAAK,CAAC;AAAA,EACnG,eAAe,IAAI,YAAyC,EAAE,KAAK,IAAO,CAAC;AAAA,EAC3E,YAAY,IAAI,YAAuD,EAAE,KAAK,EAAE,CAAC;AAAA,EAEnF;AAAA,EACA,sBAAsB;AAAA,EACtB,iBAAwD;AAAA,EAEhE,IAAI,oBAA4B;AAC9B,WAAO,KAAK,OAAO,qBAAqB,KAAK,OAAO;AAAA,EACtD;AAAA,EAEA,IAAI,mBAA2B;AAC7B,WAAO,KAAK,OAAO;AAAA,EACrB;AAAA,EAEA,IAAc,UAAmC;AAC/C,WAAO,KAAK,OAAO,WAAW,WAAW,MAAM,KAAK,UAAU;AAAA,EAChE;AAAA,EAEA,IAAc,qBAAqB;AACjC,WAAO,KAAK,OAAO;AAAA,EACrB;AAAA,EAEA,aAAsB,cAAc,QAAwC;AAC1E,UAAM,qBAAqB,OAAO;AAClC,QAAI,uBAAuB,QAAW;AACpC,eAAS,sBAAsB,2BAA2B,MAAM,uCAAuC,yBAAyB,IAAI;AAAA,IACtI;AACA,WAAO;AAAA,MACL,GAAG,MAAM,MAAM,cAAc,MAAM;AAAA,MACnC,mBAAmB,OAAO,mBAAmB,QAAQ,QAAQ,EAAE;AAAA,MAC/D,SAAS,OAAO;AAAA,MAChB,kBAAkB,SAAS,OAAO,kBAAkB,MAAM,8BAA8B,EAAE,QAAQ,QAAQ,EAAE;AAAA,MAC5G;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,YAAY,MAA6D;AAC7E,WAAO,MAAM,KAAK,UAAU,eAAe,YAAY;AACrD,YAAM,SAAS,KAAK,iBAAiB,IAAI,IAAI;AAC7C,UAAI,OAAQ,QAAO;AACnB,YAAM,SAAS,MAAM,KAAK,UAAU,cAAc,IAAI,CAAC;AACvD,aAAO,WAAW,SAAY,OAAO,KAAK,WAAW,MAAM;AAAA,IAC7D,GAAG,EAAE,GAAG,KAAK,SAAS,iBAAiB,IAAI,CAAC;AAAA,EAC9C;AAAA,EAEA,MAAM,cAAc,aAA8E;AAChG,WAAO,MAAM,KAAK,UAAU,iBAAiB,YAAY;AACvD,YAAM,SAAS,KAAK,mBAAmB,IAAI,WAAW;AACtD,UAAI,OAAQ,QAAO;AACnB,YAAM,SAAS,MAAM,KAAK,UAAU,gBAAgB,WAAW,CAAC;AAChE,aAAO,WAAW,SAAY,OAAO,KAAK,WAAW,MAAM;AAAA,IAC7D,GAAG,EAAE,GAAG,KAAK,SAAS,iBAAiB,IAAI,CAAC;AAAA,EAC9C;AAAA,EAEA,MAAM,aAAa,MAAY,QAAQ,IAAgD;AACrF,WAAO,MAAM,KAAK,UAAU,gBAAgB,YAAY;AACtD,eAAS,QAAQ,GAAG,MAAM,8BAA8B;AACxD,eAAS,SAAS,KAAK,MAAM,6BAA6B;AAC1D,YAAM,SAA4C,CAAC;AACnD,UAAI,UAAU,MAAM,KAAK,YAAY,IAAI;AACzC,aAAO,WAAW,OAAO,SAAS,OAAO;AACvC,eAAO,KAAK,OAAO;AACnB,cAAM,eAAe,QAAQ,CAAC,EAAE;AAChC,YAAI,iBAAiB,KAAM;AAC3B,kBAAU,MAAM,KAAK,YAAY,YAAY;AAAA,MAC/C;AACA,aAAO;AAAA,IACT,GAAG,EAAE,GAAG,KAAK,SAAS,iBAAiB,IAAI,CAAC;AAAA,EAC9C;AAAA,EAEA,MAAM,eAAe,aAA6B,QAAQ,IAAgD;AACxG,WAAO,MAAM,KAAK,UAAU,kBAAkB,YAAY;AACxD,eAAS,QAAQ,GAAG,MAAM,8BAA8B;AACxD,eAAS,SAAS,KAAK,MAAM,6BAA6B;AAC1D,YAAM,SAA4C,CAAC;AACnD,UAAI,UAAU,MAAM,KAAK,cAAc,WAAW;AAClD,aAAO,WAAW,OAAO,SAAS,OAAO;AACvC,eAAO,KAAK,OAAO;AACnB,YAAI,QAAQ,CAAC,EAAE,UAAU,EAAG;AAC5B,kBAAU,MAAM,KAAK,cAAc,iBAAiB,QAAQ,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;AAAA,MACjF;AACA,aAAO;AAAA,IACT,GAAG,KAAK,OAAO;AAAA,EACjB;AAAA,EAEA,MAAM,aAAa,WAAmB,WAA+D;AACnG,WAAO,MAAM,KAAK,UAAU,gBAAgB,YAAY;AACtD,eAAS,OAAO,UAAU,SAAS,KAAK,aAAa,GAAG,MAAM,0CAA0C;AACxG,eAAS,SAAS;AAClB;AAAA,QACE,aAAa;AAAA,QACb,MAAM,mDAAmD,aAAa,eAAe,SAAS;AAAA,MAChG;AACA,YAAM,WAAW,GAAG,SAAS,IAAI,SAAS;AAC1C,YAAM,SAAS,KAAK,UAAU,IAAI,QAAQ;AAC1C,UAAI,OAAQ,QAAO;AACnB,YAAM,SAAS,MAAM,KAAK,UAAU,eAAe,WAAW,SAAS,CAAC;AAExE,UAAI,WAAW,OAAW,QAAO,CAAC;AAClC,YAAM,UAAU,oBAAoB,QAAQ,EAAE,UAAU,KAAK,CAAC;AAE9D,YAAM,SAAS,QAAQ,OAAO,IAAI,OAAK,kCAAkC,GAAG,IAAI,CAAC,EAAE,WAAW;AAC9F,WAAK,UAAU,IAAI,UAAU,MAAM;AACnC,aAAO;AAAA,IACT,GAAG,KAAK,OAAO;AAAA,EACjB;AAAA,EAKA,MAAM,QAAQ,cAAyC,UAA4B;AACjF,WAAO,MAAM,KAAK,UAAU,WAAW,YAAY;AACjD,aAAO,gBAAgB,YAClB,MAAM,KAAK,aAAa,GAAG,CAAC,EAAE,QAC/B,SAAS,MAAM,KAAK,cAAc,WAAW,GAAG,MAAM,oBAAoB,WAAW,GAAG,EAAE,CAAC,EAAE;AAAA,IACnG,GAAG,KAAK,OAAO;AAAA,EACjB;AAAA,EAEA,MAAM,eAAyD;AAC7D,WAAO,MAAM,KAAK,UAAU,gBAAgB,YAAY;AACtD,YAAM,SAAS,SAAS,MAAM,KAAK,UAAU,SAAS,GAAG,KAAK,iBAAiB,GAAG,MAAM,gBAAgB;AACxG,aAAO,KAAK,WAAW,MAAM;AAAA,IAC/B,GAAG,KAAK,OAAO;AAAA,EACjB;AAAA,EAEA,MAAM,mBAAkC;AACtC,YAAQ,MAAM,KAAK,aAAa,GAAG,CAAC,EAAE;AAAA,EACxC;AAAA,EAEA,MAAM,qBAA8C;AAClD,YAAQ,MAAM,KAAK,aAAa,GAAG,CAAC,EAAE;AAAA,EACxC;AAAA,EAEA,MAAM,cAAc,MAAmD;AACrE,UAAM,CAAC,OAAO,IAAI,MAAM,KAAK,eAAe,CAAC,IAAI,CAAC;AAClD,WAAO,WAAW;AAAA,EACpB;AAAA,EAEA,MAAM,eAAe,QAAkD;AACrE,WAAO,MAAM,KAAK,UAAU,kBAAkB,YAAY;AACxD,YAAM,UAAU,MAAM,QAAQ,IAAI,OAAO,IAAI,OAAO,SAAS;AAC3D,cAAM,SAAS,KAAK,aAAa,IAAI,IAAI;AACzC,YAAI,OAAQ,QAAO;AACnB,cAAM,SAAS,MAAM,KAAK,UAAU,YAAY,IAAI,CAAC;AACrD,YAAI,WAAW,OAAW;AAC1B,cAAM,UAAU,eAAe,MAAM,MAAM;AAC3C,aAAK,aAAa,IAAI,MAAM,OAAO;AACnC,eAAO;AAAA,MACT,CAAC,CAAC;AACF,aAAO,QAAQ,OAAO,MAAM;AAAA,IAC9B,GAAG,KAAK,OAAO;AAAA,EACjB;AAAA,EAEA,MAAM,KAAK,OAAsB,UAAoD;AACnF,WAAO,MAAM,mBAAmB,MAAM,OAAO,QAAQ;AAAA,EACvD;AAAA,EAEA,MAAM,aAAa,OAAuB,WAAmB,QAAQ,GAAG,UAAoD;AAC1H,WAAO,MAAM,sBAAsB,MAAM,OAAO,WAAW,OAAO,QAAQ;AAAA,EAC5E;AAAA,EAEA,MAAM,iBACJ,YACA,kBACA,UACA,aACA,aACoB;AACpB,WAAO,MAAM,kBAAkB,MAAM,YAAY,kBAAkB,UAAU,aAAa,WAAW;AAAA,EACvG;AAAA,EAEA,MAAyB,eAA8B;AACrD,UAAM,MAAM,aAAa;AACzB,QAAI,KAAK,uBAAuB,OAAW;AAC3C,UAAM,KAAK,SAAS,KAAK;AACzB,SAAK,iBAAiB;AAAA,EACxB;AAAA,EAEA,MAAyB,cAA6B;AACpD,SAAK,gBAAgB;AACrB,SAAK,gBAAgB;AACrB,UAAM,MAAM,YAAY;AAAA,EAC1B;AAAA;AAAA,EAGQ,WAAW,QAAkD;AACnE,UAAM,QAAQ,kCAAkC,QAAQ,IAAI;AAC5D,SAAK,iBAAiB,IAAI,MAAM,CAAC,EAAE,OAAO,KAAK;AAC/C,SAAK,mBAAmB,IAAI,MAAM,CAAC,EAAE,OAAO,KAAK;AACjD,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,UAAU,MAAc,UAAU,KAAK,kBAAoC;AACvF,UAAM,WAAW,MAAM,KAAK,QAAQ,GAAG,OAAO,IAAI,IAAI,EAAE;AACxD,QAAI,SAAS,WAAW,IAAK,QAAO;AACpC,aAAS,SAAS,IAAI,MAAM,mBAAmB,SAAS,MAAM,SAAS,IAAI,EAAE;AAC7E,WAAO,MAAM,SAAS,KAAK;AAAA,EAC7B;AAAA,EAEA,MAAc,SAAS,cAAsC;AAC3D,QAAI,KAAK,oBAAqB;AAC9B,SAAK,sBAAsB;AAC3B,QAAI;AACF,YAAM,QAAQ,MAAM,KAAK,aAAa;AACtC,YAAM,OAAO,MAAM,CAAC,EAAE;AACtB,UAAI,KAAK,kBAAkB,QAAW;AACpC,aAAK,gBAAgB;AACrB;AAAA,MACF;AACA,UAAI,SAAS,KAAK,eAAe;AAC/B,aAAK,gBAAgB;AACrB,YAAI,cAAc;AAChB,gBAAM,KAAK,KAAK,eAAe,EAAE,MAAM,CAAC;AAAA,QAC1C;AAAA,MACF;AAAA,IACF,SAAS,IAAI;AACX,WAAK,QAAQ,MAAM,4BAA4B,EAAE;AAAA,IACnD,UAAE;AACA,WAAK,sBAAsB;AAAA,IAC7B;AAAA,EACF;AAAA,EAEQ,mBAAmB;AACzB,QAAI,KAAK,uBAAuB,OAAW;AAC3C,SAAK,gBAAgB;AACrB,SAAK,iBAAiB,YAAY,MAAM;AACtC,WAAK,KAAK,SAAS,IAAI;AAAA,IACzB,GAAG,KAAK,kBAAkB;AAAA,EAC5B;AAAA,EAEQ,kBAAkB;AACxB,QAAI,KAAK,gBAAgB;AACvB,oBAAc,KAAK,cAAc;AACjC,WAAK,iBAAiB;AAAA,IACxB;AAAA,EACF;AACF;AApPE,cADW,iBACK,kBAAiB;AACjC,cAFW,iBAEK,gBAAe,CAAC;AAChC,cAHW,iBAGK,YAAW,CAAC,kBAAkB;AAHnC,kBAAN;AAAA,EADN,kBAAkB;AAAA,GACN;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/neutral/paths.d.ts
CHANGED
|
@@ -11,6 +11,11 @@ import type { Hash } from '@xylabs/sdk-js';
|
|
|
11
11
|
* - block and payload files never change after finalization
|
|
12
12
|
* - step files are only written for completed steps
|
|
13
13
|
* - the head pointer is rewritten as the chain advances and must not be cached long-term
|
|
14
|
+
*
|
|
15
|
+
* The finalized (immutable) files and the mutable chain state (the head pointer) may live
|
|
16
|
+
* in separate buckets behind separate domains: the publisher writes only the finalized
|
|
17
|
+
* files, the chain's finalizer writes the head pointer, and the viewer joins `headPath` to
|
|
18
|
+
* its chain-state base URL and everything else to its finalized base URL.
|
|
14
19
|
*/
|
|
15
20
|
/** The mutable head pointer: the current head SignedHydratedBlockWithHashMeta. */
|
|
16
21
|
export declare const headPath: () => string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/paths.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAA;AAE1C
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/paths.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAA;AAE1C;;;;;;;;;;;;;;;;;GAiBG;AAEH,kFAAkF;AAClF,eAAO,MAAM,QAAQ,QAAO,MAA2B,CAAA;AAEvD,0DAA0D;AAC1D,eAAO,MAAM,eAAe,GAAI,OAAO,MAAM,KAAG,MAAsC,CAAA;AAEtF,+DAA+D;AAC/D,eAAO,MAAM,aAAa,GAAI,MAAM,IAAI,KAAG,MAAmC,CAAA;AAE9E;;;GAGG;AACH,eAAO,MAAM,cAAc,GAAI,WAAW,MAAM,EAAE,WAAW,MAAM,KAAG,MAAsD,CAAA;AAE5H,gDAAgD;AAChD,eAAO,MAAM,WAAW,GAAI,MAAM,IAAI,KAAG,MAAgC,CAAA"}
|
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-viewer",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.1.1",
|
|
5
5
|
"description": "XYO Layer One BlockViewer over a statically generated REST file layout",
|
|
6
6
|
"homepage": "https://xylabs.com",
|
|
7
7
|
"bugs": {
|
|
@@ -35,9 +35,9 @@
|
|
|
35
35
|
"README.md"
|
|
36
36
|
],
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@xyo-network/xl1-driver-memory": "~2.
|
|
39
|
-
"@xyo-network/xl1-protocol-sdk": "~2.
|
|
40
|
-
"@xyo-network/xl1-protocol-lib": "~2.
|
|
38
|
+
"@xyo-network/xl1-driver-memory": "~2.1.1",
|
|
39
|
+
"@xyo-network/xl1-protocol-sdk": "~2.1.1",
|
|
40
|
+
"@xyo-network/xl1-protocol-lib": "~2.1.1"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@bitauth/libauth": "~3.0.0",
|
|
@@ -47,9 +47,9 @@
|
|
|
47
47
|
"@opentelemetry/sdk-trace-base": "^2.7.1",
|
|
48
48
|
"@scure/base": "~2.2.0",
|
|
49
49
|
"@scure/bip39": "~2.2.0",
|
|
50
|
-
"@xylabs/geo": "^6.0
|
|
51
|
-
"@xylabs/sdk-js": "^6.0
|
|
52
|
-
"@xylabs/threads": "~6.
|
|
50
|
+
"@xylabs/geo": "^6.1.0",
|
|
51
|
+
"@xylabs/sdk-js": "^6.1.0",
|
|
52
|
+
"@xylabs/threads": "~6.1",
|
|
53
53
|
"@xylabs/toolchain": "~8.1.20",
|
|
54
54
|
"@xylabs/tsconfig": "~8.1.20",
|
|
55
55
|
"@xyo-network/address": "^6.0.9",
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
"@scure/bip39": "~2.2",
|
|
84
84
|
"@xylabs/geo": "^6.0",
|
|
85
85
|
"@xylabs/sdk-js": "^6.0",
|
|
86
|
-
"@xylabs/threads": "
|
|
86
|
+
"@xylabs/threads": "^6.1",
|
|
87
87
|
"@xyo-network/address": "^6.0",
|
|
88
88
|
"@xyo-network/sdk-js": "^6.0",
|
|
89
89
|
"@xyo-network/sdk-protocol-js": "~6.0",
|