@secondlayer/shared 7.6.0 → 7.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/dist/src/archive/copy-loader.d.ts +49 -0
  2. package/dist/src/archive/copy-loader.js +111 -0
  3. package/dist/src/archive/copy-loader.js.map +10 -0
  4. package/dist/src/archive/key-registry.d.ts +52 -0
  5. package/dist/src/archive/key-registry.js +168 -0
  6. package/dist/src/archive/key-registry.js.map +11 -0
  7. package/dist/src/archive/progress.d.ts +36 -0
  8. package/dist/src/archive/progress.js +75 -0
  9. package/dist/src/archive/progress.js.map +10 -0
  10. package/dist/src/archive/range-digest.d.ts +1062 -0
  11. package/dist/src/archive/range-digest.js +142 -0
  12. package/dist/src/archive/range-digest.js.map +10 -0
  13. package/dist/src/archive/status.d.ts +92 -0
  14. package/dist/src/archive/status.js +106 -0
  15. package/dist/src/archive/status.js.map +10 -0
  16. package/dist/src/db/index.d.ts +27 -1
  17. package/dist/src/db/index.js +2 -1
  18. package/dist/src/db/index.js.map +3 -3
  19. package/dist/src/db/queries/chain-reorgs.d.ts +25 -0
  20. package/dist/src/db/queries/chain-reorgs.js +2 -1
  21. package/dist/src/db/queries/chain-reorgs.js.map +3 -3
  22. package/dist/src/db/queries/contracts.d.ts +25 -0
  23. package/dist/src/db/queries/integrity.d.ts +25 -0
  24. package/dist/src/db/queries/subgraph-gaps.d.ts +25 -0
  25. package/dist/src/db/queries/subgraph-operations.d.ts +25 -0
  26. package/dist/src/db/queries/subgraphs.d.ts +25 -0
  27. package/dist/src/db/queries/subgraphs.js +2 -1
  28. package/dist/src/db/queries/subgraphs.js.map +3 -3
  29. package/dist/src/db/queries/subscriptions.d.ts +25 -0
  30. package/dist/src/db/schema.d.ts +26 -1
  31. package/dist/src/index.d.ts +27 -1
  32. package/dist/src/index.js +2 -1
  33. package/dist/src/index.js.map +3 -3
  34. package/dist/src/node/local-client.d.ts +25 -0
  35. package/migrations/0114_observer_journal.ts +54 -0
  36. package/package.json +22 -2
@@ -0,0 +1,142 @@
1
+ import { createRequire } from "node:module";
2
+ var __defProp = Object.defineProperty;
3
+ var __returnValue = (v) => v;
4
+ function __exportSetter(name, newValue) {
5
+ this[name] = __returnValue.bind(null, newValue);
6
+ }
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, {
10
+ get: all[name],
11
+ enumerable: true,
12
+ configurable: true,
13
+ set: __exportSetter.bind(all, name)
14
+ });
15
+ };
16
+
17
+ // src/archive/range-digest.ts
18
+ import { sql } from "kysely";
19
+ var RANGE_DIGEST_SPEC = "md5:sql-identity-v1";
20
+ function identityExpression(dataset) {
21
+ if (dataset === "blocks") {
22
+ return sql`md5(
23
+ height::text || '|' ||
24
+ hash || '|' ||
25
+ parent_hash || '|' ||
26
+ burn_block_height::text || '|' ||
27
+ coalesce(burn_block_hash, '~') || '|' ||
28
+ coalesce(index_block_hash, '~')
29
+ )`;
30
+ }
31
+ if (dataset === "transactions") {
32
+ return sql`md5(
33
+ tx_id || '|' ||
34
+ block_height::text || '|' ||
35
+ tx_index::text || '|' ||
36
+ type || '|' ||
37
+ sender || '|' ||
38
+ status || '|' ||
39
+ coalesce(contract_id, '~') || '|' ||
40
+ coalesce(function_name, '~')
41
+ )`;
42
+ }
43
+ return sql`md5(
44
+ tx_id || '|' ||
45
+ block_height::text || '|' ||
46
+ event_index::text || '|' ||
47
+ type
48
+ )`;
49
+ }
50
+ function orderExpression(dataset) {
51
+ if (dataset === "blocks")
52
+ return sql`height`;
53
+ if (dataset === "transactions")
54
+ return sql`block_height, tx_index, tx_id`;
55
+ return sql`block_height, event_index, tx_id`;
56
+ }
57
+ function fromExpression(dataset) {
58
+ if (dataset === "blocks") {
59
+ return sql`FROM blocks WHERE canonical = true`;
60
+ }
61
+ const table = dataset === "transactions" ? sql`transactions` : sql`events`;
62
+ return sql`FROM ${table} AS child
63
+ JOIN blocks AS b ON b.height = child.block_height AND b.canonical = true
64
+ WHERE true`;
65
+ }
66
+ function heightColumn(dataset) {
67
+ return dataset === "blocks" ? sql`height` : sql`child.block_height`;
68
+ }
69
+ async function computeRangeDigest(db, dataset, fromBlock, toBlock) {
70
+ const { rows } = await sql`
71
+ SELECT
72
+ md5(string_agg(row_digest, '' ORDER BY ord)) AS digest,
73
+ COUNT(*)::text AS row_count
74
+ FROM (
75
+ SELECT
76
+ ${identityExpression(dataset)} AS row_digest,
77
+ row_number() OVER (ORDER BY ${orderExpression(dataset)}) AS ord
78
+ ${fromExpression(dataset)}
79
+ AND ${heightColumn(dataset)} >= ${fromBlock}
80
+ AND ${heightColumn(dataset)} <= ${toBlock}
81
+ ) AS identity_rows
82
+ `.execute(db);
83
+ const row = rows[0];
84
+ const rowCount = Number(row?.row_count ?? 0);
85
+ return {
86
+ dataset,
87
+ from_block: fromBlock,
88
+ to_block: toBlock,
89
+ row_count: rowCount,
90
+ digest: rowCount === 0 ? null : row?.digest ?? null,
91
+ digest_spec: RANGE_DIGEST_SPEC
92
+ };
93
+ }
94
+ async function computeRangeDigests(db, fromBlock, toBlock, datasets = [
95
+ "blocks",
96
+ "transactions",
97
+ "events"
98
+ ]) {
99
+ const digests = [];
100
+ for (const dataset of datasets) {
101
+ digests.push(await computeRangeDigest(db, dataset, fromBlock, toBlock));
102
+ }
103
+ return digests;
104
+ }
105
+ function compareRangeDigests(local, reference) {
106
+ const localByKey = new Map(local.map((d) => [`${d.dataset}:${d.from_block}-${d.to_block}`, d]));
107
+ return reference.map((expected) => {
108
+ const key = `${expected.dataset}:${expected.from_block}-${expected.to_block}`;
109
+ const actual = localByKey.get(key);
110
+ const base = {
111
+ dataset: expected.dataset,
112
+ from_block: expected.from_block,
113
+ to_block: expected.to_block,
114
+ expected_digest: expected.digest,
115
+ expected_rows: expected.row_count
116
+ };
117
+ if (!actual) {
118
+ return {
119
+ ...base,
120
+ status: "missing-locally",
121
+ actual_digest: null,
122
+ actual_rows: 0
123
+ };
124
+ }
125
+ const status = actual.row_count !== expected.row_count ? "count-mismatch" : actual.digest === expected.digest ? "match" : "digest-mismatch";
126
+ return {
127
+ ...base,
128
+ status,
129
+ actual_digest: actual.digest,
130
+ actual_rows: actual.row_count
131
+ };
132
+ });
133
+ }
134
+ export {
135
+ computeRangeDigests,
136
+ computeRangeDigest,
137
+ compareRangeDigests,
138
+ RANGE_DIGEST_SPEC
139
+ };
140
+
141
+ //# debugId=D76FA402AE6DA40A64756E2164756E21
142
+ //# sourceMappingURL=range-digest.js.map
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/archive/range-digest.ts"],
4
+ "sourcesContent": [
5
+ "import { sql } from \"kysely\";\nimport type { Kysely } from \"kysely\";\nimport type { Database } from \"../db/schema.ts\";\n\n/**\n * Cheap, SQL-computed digests over a height range — the basis of a verify that\n * runs in seconds instead of hours.\n *\n * The archive's per-object `sha256:parquet-object` digests can only be checked\n * by regenerating the Parquet locally, which costs a full export. That is a\n * reasonable paranoid check and a terrible first-run experience: nobody will\n * spend two hours to discover whether they are broken. These digests are\n * computed by the database itself, over the columns that actually carry chain\n * identity, so an operator gets an answer before they lose interest.\n *\n * What this catches is not a subset chosen for convenience — it is precisely\n * the defect class seen in production: missing heights, a canonical child whose\n * `parent_hash` names a block we no longer hold, duplicate canonical rows at one\n * height, and any altered block/transaction identity. What it deliberately does\n * NOT catch is a difference in bulky payload columns (`raw_tx`, event `data`)\n * that leaves identity intact; `--deep` re-export exists for that.\n *\n * Determinism rules, so two independent databases agree:\n * - Aggregate over an explicit ORDER BY, never table order.\n * - Hash each row to a fixed-width digest FIRST, then aggregate those, so the\n * intermediate string is 32 bytes/row rather than the whole row.\n * - Normalize NULL to a sentinel that cannot collide with a real value.\n * - Never include a column whose representation is environment-dependent\n * (timestamps with timezone rendering, generated ids, `created_at`).\n */\n\nexport const RANGE_DIGEST_SPEC = \"md5:sql-identity-v1\" as const;\n\nexport type RangeDigestDataset = \"blocks\" | \"transactions\" | \"events\";\n\nexport type RangeDigest = {\n\tdataset: RangeDigestDataset;\n\tfrom_block: number;\n\tto_block: number;\n\trow_count: number;\n\t/** null when the range holds no rows — an empty range has no digest, and\n\t * that is materially different from \"a digest that happens to be of zero\n\t * rows\", which would compare equal across datasets. */\n\tdigest: string | null;\n\tdigest_spec: typeof RANGE_DIGEST_SPEC;\n};\n\n/**\n * Identity columns per dataset. `blocks` carries the whole corruption surface\n * we care about, which is why quick mode leans on it.\n */\nfunction identityExpression(dataset: RangeDigestDataset) {\n\tif (dataset === \"blocks\") {\n\t\treturn sql`md5(\n\t\t\theight::text || '|' ||\n\t\t\thash || '|' ||\n\t\t\tparent_hash || '|' ||\n\t\t\tburn_block_height::text || '|' ||\n\t\t\tcoalesce(burn_block_hash, '~') || '|' ||\n\t\t\tcoalesce(index_block_hash, '~')\n\t\t)`;\n\t}\n\tif (dataset === \"transactions\") {\n\t\treturn sql`md5(\n\t\t\ttx_id || '|' ||\n\t\t\tblock_height::text || '|' ||\n\t\t\ttx_index::text || '|' ||\n\t\t\ttype || '|' ||\n\t\t\tsender || '|' ||\n\t\t\tstatus || '|' ||\n\t\t\tcoalesce(contract_id, '~') || '|' ||\n\t\t\tcoalesce(function_name, '~')\n\t\t)`;\n\t}\n\treturn sql`md5(\n\t\ttx_id || '|' ||\n\t\tblock_height::text || '|' ||\n\t\tevent_index::text || '|' ||\n\t\ttype\n\t)`;\n}\n\nfunction orderExpression(dataset: RangeDigestDataset) {\n\tif (dataset === \"blocks\") return sql`height`;\n\tif (dataset === \"transactions\") return sql`block_height, tx_index, tx_id`;\n\treturn sql`block_height, event_index, tx_id`;\n}\n\n/**\n * Rows are restricted to CANONICAL blocks in every dataset — a non-canonical\n * row at a height must not change the digest, or a database that merely retains\n * more reorg history than another would report as diverging.\n */\nfunction fromExpression(dataset: RangeDigestDataset) {\n\tif (dataset === \"blocks\") {\n\t\treturn sql`FROM blocks WHERE canonical = true`;\n\t}\n\tconst table = dataset === \"transactions\" ? sql`transactions` : sql`events`;\n\treturn sql`FROM ${table} AS child\n\t\tJOIN blocks AS b ON b.height = child.block_height AND b.canonical = true\n\t\tWHERE true`;\n}\n\nfunction heightColumn(dataset: RangeDigestDataset) {\n\treturn dataset === \"blocks\" ? sql`height` : sql`child.block_height`;\n}\n\nexport async function computeRangeDigest(\n\tdb: Kysely<Database>,\n\tdataset: RangeDigestDataset,\n\tfromBlock: number,\n\ttoBlock: number,\n): Promise<RangeDigest> {\n\tconst { rows } = await sql<{ digest: string | null; row_count: string }>`\n\t\tSELECT\n\t\t\tmd5(string_agg(row_digest, '' ORDER BY ord)) AS digest,\n\t\t\tCOUNT(*)::text AS row_count\n\t\tFROM (\n\t\t\tSELECT\n\t\t\t\t${identityExpression(dataset)} AS row_digest,\n\t\t\t\trow_number() OVER (ORDER BY ${orderExpression(dataset)}) AS ord\n\t\t\t${fromExpression(dataset)}\n\t\t\t\tAND ${heightColumn(dataset)} >= ${fromBlock}\n\t\t\t\tAND ${heightColumn(dataset)} <= ${toBlock}\n\t\t) AS identity_rows\n\t`.execute(db);\n\n\tconst row = rows[0];\n\tconst rowCount = Number(row?.row_count ?? 0);\n\treturn {\n\t\tdataset,\n\t\tfrom_block: fromBlock,\n\t\tto_block: toBlock,\n\t\trow_count: rowCount,\n\t\tdigest: rowCount === 0 ? null : (row?.digest ?? null),\n\t\tdigest_spec: RANGE_DIGEST_SPEC,\n\t};\n}\n\nexport async function computeRangeDigests(\n\tdb: Kysely<Database>,\n\tfromBlock: number,\n\ttoBlock: number,\n\tdatasets: readonly RangeDigestDataset[] = [\n\t\t\"blocks\",\n\t\t\"transactions\",\n\t\t\"events\",\n\t],\n): Promise<RangeDigest[]> {\n\tconst digests: RangeDigest[] = [];\n\tfor (const dataset of datasets) {\n\t\tdigests.push(await computeRangeDigest(db, dataset, fromBlock, toBlock));\n\t}\n\treturn digests;\n}\n\nexport type RangeComparison = {\n\tdataset: RangeDigestDataset;\n\tfrom_block: number;\n\tto_block: number;\n\tstatus: \"match\" | \"digest-mismatch\" | \"count-mismatch\" | \"missing-locally\";\n\texpected_digest: string | null;\n\tactual_digest: string | null;\n\texpected_rows: number;\n\tactual_rows: number;\n};\n\n/**\n * Compare locally computed digests against a reference set.\n *\n * Row count is reported separately from digest because the two failures mean\n * different things to an operator: a count difference is missing or extra data\n * (usually a gap or an un-swept reorg), while an equal count with a different\n * digest means the same number of rows carry different identities — the\n * fork-point corruption signature.\n */\nexport function compareRangeDigests(\n\tlocal: readonly RangeDigest[],\n\treference: readonly RangeDigest[],\n): RangeComparison[] {\n\tconst localByKey = new Map(\n\t\tlocal.map((d) => [`${d.dataset}:${d.from_block}-${d.to_block}`, d]),\n\t);\n\n\treturn reference.map((expected) => {\n\t\tconst key = `${expected.dataset}:${expected.from_block}-${expected.to_block}`;\n\t\tconst actual = localByKey.get(key);\n\t\tconst base = {\n\t\t\tdataset: expected.dataset,\n\t\t\tfrom_block: expected.from_block,\n\t\t\tto_block: expected.to_block,\n\t\t\texpected_digest: expected.digest,\n\t\t\texpected_rows: expected.row_count,\n\t\t};\n\t\tif (!actual) {\n\t\t\treturn {\n\t\t\t\t...base,\n\t\t\t\tstatus: \"missing-locally\" as const,\n\t\t\t\tactual_digest: null,\n\t\t\t\tactual_rows: 0,\n\t\t\t};\n\t\t}\n\t\tconst status =\n\t\t\tactual.row_count !== expected.row_count\n\t\t\t\t? (\"count-mismatch\" as const)\n\t\t\t\t: actual.digest === expected.digest\n\t\t\t\t\t? (\"match\" as const)\n\t\t\t\t\t: (\"digest-mismatch\" as const);\n\t\treturn {\n\t\t\t...base,\n\t\t\tstatus,\n\t\t\tactual_digest: actual.digest,\n\t\t\tactual_rows: actual.row_count,\n\t\t};\n\t});\n}\n"
6
+ ],
7
+ "mappings": "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",
8
+ "debugId": "D76FA402AE6DA40A64756E2164756E21",
9
+ "names": []
10
+ }
@@ -0,0 +1,92 @@
1
+ /**
2
+ * `status.json` — the archive's operational truth, published short-cache from
3
+ * verified state only.
4
+ *
5
+ * Everything else in the tree is immutable and signed, which makes it durable
6
+ * but silent: a consumer holding a valid manifest cannot tell whether it is
7
+ * current, three days behind, or the last thing published before an incident.
8
+ * This object answers that, and it is the only object allowed to say something
9
+ * unflattering.
10
+ *
11
+ * The distinction this file exists to protect:
12
+ *
13
+ * lagging → the archive trails the chain tip because it only publishes below
14
+ * the finality boundary. This is CORRECT and permanent. An archive
15
+ * that reported `stale` for its own finality lag would be crying
16
+ * wolf forever, and consumers would learn to ignore it.
17
+ * stale → publishing stopped. The lag exceeds what the finality rule can
18
+ * explain, so something is broken.
19
+ *
20
+ * `state` is derived from measurements, never asserted by the publisher, and
21
+ * every unhealthy state is reachable — an archive that can only report health
22
+ * is decoration.
23
+ */
24
+ declare const ARCHIVE_STATUS_SCHEMA_VERSION = 1;
25
+ type ArchiveState = "fresh" | "lagging" | "stale" | "gap" | "failed-audit" | "source-unavailable";
26
+ type ArchiveStatus = {
27
+ schema_version: typeof ARCHIVE_STATUS_SCHEMA_VERSION
28
+ network: string
29
+ state: ArchiveState
30
+ /** Human-facing one-liner explaining the state, including WHY. */
31
+ detail: string
32
+ generated_at: string
33
+ archive: {
34
+ snapshot_digest: string | null
35
+ coverage_to_block: number | null
36
+ promoted_at: string | null
37
+ signing_key_id: string | null
38
+ }
39
+ source: {
40
+ /** Chain tip as the publisher last observed it. Null when unreachable. */
41
+ tip_height: number | null
42
+ /** Highest height eligible to publish under the finality rule. */
43
+ finalized_height: number | null
44
+ }
45
+ lag: {
46
+ /** Behind the FINALIZED height — the number that indicates a problem. */
47
+ blocks_behind_finalized: number | null
48
+ /** Behind the raw chain tip — expected to be non-zero forever. */
49
+ blocks_behind_tip: number | null
50
+ seconds_since_promotion: number | null
51
+ }
52
+ audit: {
53
+ complete: boolean
54
+ checked_at: string
55
+ } | null
56
+ signature?: string
57
+ key_id?: string
58
+ };
59
+ type StatusInputs = {
60
+ network: string
61
+ snapshotDigest: string | null
62
+ coverageToBlock: number | null
63
+ promotedAt: string | null
64
+ signingKeyId: string | null
65
+ /** Null when the source could not be reached. */
66
+ sourceTipHeight: number | null
67
+ finalizedHeight: number | null
68
+ audit: {
69
+ complete: boolean
70
+ checkedAt: string
71
+ } | null
72
+ now: Date
73
+ /**
74
+ * How far behind the FINALIZED height the archive may fall before it is
75
+ * stale rather than merely lagging. Publishing one partition covers 50k
76
+ * blocks, so a healthy archive sits well inside this.
77
+ */
78
+ maxBlocksBehindFinalized?: number
79
+ /** How long since the last promotion before staleness, regardless of height. */
80
+ maxSecondsSincePromotion?: number
81
+ };
82
+ /**
83
+ * Derive status from measurements. Pure, so every state below is reachable in
84
+ * a test rather than only in production at 3am.
85
+ *
86
+ * Order matters: a failing audit outranks freshness, because an archive that
87
+ * is current and wrong is worse than one that is behind and correct.
88
+ */
89
+ declare function deriveArchiveStatus(inputs: StatusInputs): ArchiveStatus;
90
+ /** States a consumer should refuse to restore from. */
91
+ declare function isRestorable(state: ArchiveState): boolean;
92
+ export { isRestorable, deriveArchiveStatus, StatusInputs, ArchiveStatus, ArchiveState, ARCHIVE_STATUS_SCHEMA_VERSION };
@@ -0,0 +1,106 @@
1
+ import { createRequire } from "node:module";
2
+ var __defProp = Object.defineProperty;
3
+ var __returnValue = (v) => v;
4
+ function __exportSetter(name, newValue) {
5
+ this[name] = __returnValue.bind(null, newValue);
6
+ }
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, {
10
+ get: all[name],
11
+ enumerable: true,
12
+ configurable: true,
13
+ set: __exportSetter.bind(all, name)
14
+ });
15
+ };
16
+
17
+ // src/archive/status.ts
18
+ var ARCHIVE_STATUS_SCHEMA_VERSION = 1;
19
+ var DEFAULT_MAX_BLOCKS_BEHIND_FINALIZED = 60000;
20
+ var DEFAULT_MAX_SECONDS_SINCE_PROMOTION = 48 * 3600;
21
+ function deriveArchiveStatus(inputs) {
22
+ const maxBehind = inputs.maxBlocksBehindFinalized ?? DEFAULT_MAX_BLOCKS_BEHIND_FINALIZED;
23
+ const maxAge = inputs.maxSecondsSincePromotion ?? DEFAULT_MAX_SECONDS_SINCE_PROMOTION;
24
+ const secondsSincePromotion = inputs.promotedAt ? Math.max(0, Math.round((inputs.now.getTime() - Date.parse(inputs.promotedAt)) / 1000)) : null;
25
+ const behindFinalized = inputs.finalizedHeight !== null && inputs.coverageToBlock !== null ? Math.max(0, inputs.finalizedHeight - inputs.coverageToBlock) : null;
26
+ const behindTip = inputs.sourceTipHeight !== null && inputs.coverageToBlock !== null ? Math.max(0, inputs.sourceTipHeight - inputs.coverageToBlock) : null;
27
+ const base = {
28
+ schema_version: ARCHIVE_STATUS_SCHEMA_VERSION,
29
+ network: inputs.network,
30
+ generated_at: inputs.now.toISOString(),
31
+ archive: {
32
+ snapshot_digest: inputs.snapshotDigest,
33
+ coverage_to_block: inputs.coverageToBlock,
34
+ promoted_at: inputs.promotedAt,
35
+ signing_key_id: inputs.signingKeyId
36
+ },
37
+ source: {
38
+ tip_height: inputs.sourceTipHeight,
39
+ finalized_height: inputs.finalizedHeight
40
+ },
41
+ lag: {
42
+ blocks_behind_finalized: behindFinalized,
43
+ blocks_behind_tip: behindTip,
44
+ seconds_since_promotion: secondsSincePromotion
45
+ },
46
+ audit: inputs.audit ? { complete: inputs.audit.complete, checked_at: inputs.audit.checkedAt } : null
47
+ };
48
+ if (inputs.audit && !inputs.audit.complete) {
49
+ return {
50
+ ...base,
51
+ state: "failed-audit",
52
+ detail: `the canonical audit did not pass at ${inputs.audit.checkedAt}; this archive is not safe to restore from`
53
+ };
54
+ }
55
+ if (!inputs.snapshotDigest || inputs.coverageToBlock === null) {
56
+ return {
57
+ ...base,
58
+ state: "gap",
59
+ detail: "no snapshot is currently promoted"
60
+ };
61
+ }
62
+ if (inputs.sourceTipHeight === null || inputs.finalizedHeight === null) {
63
+ return {
64
+ ...base,
65
+ state: "source-unavailable",
66
+ detail: "the chain source could not be reached, so freshness cannot be determined"
67
+ };
68
+ }
69
+ if (secondsSincePromotion !== null && secondsSincePromotion > maxAge) {
70
+ return {
71
+ ...base,
72
+ state: "stale",
73
+ detail: `last promotion was ${Math.round(secondsSincePromotion / 3600)}h ago, beyond the ${Math.round(maxAge / 3600)}h freshness objective`
74
+ };
75
+ }
76
+ if (behindFinalized !== null && behindFinalized > maxBehind) {
77
+ return {
78
+ ...base,
79
+ state: "stale",
80
+ detail: `${behindFinalized} blocks behind the finalized height, beyond the ${maxBehind} threshold`
81
+ };
82
+ }
83
+ if (behindTip !== null && behindTip > 0) {
84
+ return {
85
+ ...base,
86
+ state: "lagging",
87
+ detail: `${behindTip} blocks behind the chain tip, which is expected: only heights below the finality boundary are published`
88
+ };
89
+ }
90
+ return {
91
+ ...base,
92
+ state: "fresh",
93
+ detail: "published through the finalized height"
94
+ };
95
+ }
96
+ function isRestorable(state) {
97
+ return state === "fresh" || state === "lagging";
98
+ }
99
+ export {
100
+ isRestorable,
101
+ deriveArchiveStatus,
102
+ ARCHIVE_STATUS_SCHEMA_VERSION
103
+ };
104
+
105
+ //# debugId=D9102A12541A66EA64756E2164756E21
106
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/archive/status.ts"],
4
+ "sourcesContent": [
5
+ "/**\n * `status.json` — the archive's operational truth, published short-cache from\n * verified state only.\n *\n * Everything else in the tree is immutable and signed, which makes it durable\n * but silent: a consumer holding a valid manifest cannot tell whether it is\n * current, three days behind, or the last thing published before an incident.\n * This object answers that, and it is the only object allowed to say something\n * unflattering.\n *\n * The distinction this file exists to protect:\n *\n * lagging → the archive trails the chain tip because it only publishes below\n * the finality boundary. This is CORRECT and permanent. An archive\n * that reported `stale` for its own finality lag would be crying\n * wolf forever, and consumers would learn to ignore it.\n * stale → publishing stopped. The lag exceeds what the finality rule can\n * explain, so something is broken.\n *\n * `state` is derived from measurements, never asserted by the publisher, and\n * every unhealthy state is reachable — an archive that can only report health\n * is decoration.\n */\n\nexport const ARCHIVE_STATUS_SCHEMA_VERSION = 1;\n\nexport type ArchiveState =\n\t| \"fresh\"\n\t| \"lagging\"\n\t| \"stale\"\n\t| \"gap\"\n\t| \"failed-audit\"\n\t| \"source-unavailable\";\n\nexport type ArchiveStatus = {\n\tschema_version: typeof ARCHIVE_STATUS_SCHEMA_VERSION;\n\tnetwork: string;\n\tstate: ArchiveState;\n\t/** Human-facing one-liner explaining the state, including WHY. */\n\tdetail: string;\n\tgenerated_at: string;\n\tarchive: {\n\t\tsnapshot_digest: string | null;\n\t\tcoverage_to_block: number | null;\n\t\tpromoted_at: string | null;\n\t\tsigning_key_id: string | null;\n\t};\n\tsource: {\n\t\t/** Chain tip as the publisher last observed it. Null when unreachable. */\n\t\ttip_height: number | null;\n\t\t/** Highest height eligible to publish under the finality rule. */\n\t\tfinalized_height: number | null;\n\t};\n\tlag: {\n\t\t/** Behind the FINALIZED height — the number that indicates a problem. */\n\t\tblocks_behind_finalized: number | null;\n\t\t/** Behind the raw chain tip — expected to be non-zero forever. */\n\t\tblocks_behind_tip: number | null;\n\t\tseconds_since_promotion: number | null;\n\t};\n\taudit: {\n\t\tcomplete: boolean;\n\t\tchecked_at: string;\n\t} | null;\n\tsignature?: string;\n\tkey_id?: string;\n};\n\nexport type StatusInputs = {\n\tnetwork: string;\n\tsnapshotDigest: string | null;\n\tcoverageToBlock: number | null;\n\tpromotedAt: string | null;\n\tsigningKeyId: string | null;\n\t/** Null when the source could not be reached. */\n\tsourceTipHeight: number | null;\n\tfinalizedHeight: number | null;\n\taudit: { complete: boolean; checkedAt: string } | null;\n\tnow: Date;\n\t/**\n\t * How far behind the FINALIZED height the archive may fall before it is\n\t * stale rather than merely lagging. Publishing one partition covers 50k\n\t * blocks, so a healthy archive sits well inside this.\n\t */\n\tmaxBlocksBehindFinalized?: number;\n\t/** How long since the last promotion before staleness, regardless of height. */\n\tmaxSecondsSincePromotion?: number;\n};\n\nconst DEFAULT_MAX_BLOCKS_BEHIND_FINALIZED = 60_000;\nconst DEFAULT_MAX_SECONDS_SINCE_PROMOTION = 48 * 3_600;\n\n/**\n * Derive status from measurements. Pure, so every state below is reachable in\n * a test rather than only in production at 3am.\n *\n * Order matters: a failing audit outranks freshness, because an archive that\n * is current and wrong is worse than one that is behind and correct.\n */\nexport function deriveArchiveStatus(inputs: StatusInputs): ArchiveStatus {\n\tconst maxBehind =\n\t\tinputs.maxBlocksBehindFinalized ?? DEFAULT_MAX_BLOCKS_BEHIND_FINALIZED;\n\tconst maxAge =\n\t\tinputs.maxSecondsSincePromotion ?? DEFAULT_MAX_SECONDS_SINCE_PROMOTION;\n\n\tconst secondsSincePromotion = inputs.promotedAt\n\t\t? Math.max(\n\t\t\t\t0,\n\t\t\t\tMath.round(\n\t\t\t\t\t(inputs.now.getTime() - Date.parse(inputs.promotedAt)) / 1000,\n\t\t\t\t),\n\t\t\t)\n\t\t: null;\n\n\tconst behindFinalized =\n\t\tinputs.finalizedHeight !== null && inputs.coverageToBlock !== null\n\t\t\t? Math.max(0, inputs.finalizedHeight - inputs.coverageToBlock)\n\t\t\t: null;\n\tconst behindTip =\n\t\tinputs.sourceTipHeight !== null && inputs.coverageToBlock !== null\n\t\t\t? Math.max(0, inputs.sourceTipHeight - inputs.coverageToBlock)\n\t\t\t: null;\n\n\tconst base = {\n\t\tschema_version:\n\t\t\tARCHIVE_STATUS_SCHEMA_VERSION as typeof ARCHIVE_STATUS_SCHEMA_VERSION,\n\t\tnetwork: inputs.network,\n\t\tgenerated_at: inputs.now.toISOString(),\n\t\tarchive: {\n\t\t\tsnapshot_digest: inputs.snapshotDigest,\n\t\t\tcoverage_to_block: inputs.coverageToBlock,\n\t\t\tpromoted_at: inputs.promotedAt,\n\t\t\tsigning_key_id: inputs.signingKeyId,\n\t\t},\n\t\tsource: {\n\t\t\ttip_height: inputs.sourceTipHeight,\n\t\t\tfinalized_height: inputs.finalizedHeight,\n\t\t},\n\t\tlag: {\n\t\t\tblocks_behind_finalized: behindFinalized,\n\t\t\tblocks_behind_tip: behindTip,\n\t\t\tseconds_since_promotion: secondsSincePromotion,\n\t\t},\n\t\taudit: inputs.audit\n\t\t\t? { complete: inputs.audit.complete, checked_at: inputs.audit.checkedAt }\n\t\t\t: null,\n\t};\n\n\t// A failed audit is the loudest signal: current-and-wrong beats behind-and-right.\n\tif (inputs.audit && !inputs.audit.complete) {\n\t\treturn {\n\t\t\t...base,\n\t\t\tstate: \"failed-audit\",\n\t\t\tdetail: `the canonical audit did not pass at ${inputs.audit.checkedAt}; this archive is not safe to restore from`,\n\t\t};\n\t}\n\n\tif (!inputs.snapshotDigest || inputs.coverageToBlock === null) {\n\t\treturn {\n\t\t\t...base,\n\t\t\tstate: \"gap\",\n\t\t\tdetail: \"no snapshot is currently promoted\",\n\t\t};\n\t}\n\n\t// Source unreachable: report the gap in KNOWLEDGE rather than guessing. The\n\t// archive may be perfectly healthy; we cannot currently say so.\n\tif (inputs.sourceTipHeight === null || inputs.finalizedHeight === null) {\n\t\treturn {\n\t\t\t...base,\n\t\t\tstate: \"source-unavailable\",\n\t\t\tdetail:\n\t\t\t\t\"the chain source could not be reached, so freshness cannot be determined\",\n\t\t};\n\t}\n\n\tif (secondsSincePromotion !== null && secondsSincePromotion > maxAge) {\n\t\treturn {\n\t\t\t...base,\n\t\t\tstate: \"stale\",\n\t\t\tdetail: `last promotion was ${Math.round(secondsSincePromotion / 3_600)}h ago, beyond the ${Math.round(maxAge / 3_600)}h freshness objective`,\n\t\t};\n\t}\n\n\tif (behindFinalized !== null && behindFinalized > maxBehind) {\n\t\treturn {\n\t\t\t...base,\n\t\t\tstate: \"stale\",\n\t\t\tdetail: `${behindFinalized} blocks behind the finalized height, beyond the ${maxBehind} threshold`,\n\t\t};\n\t}\n\n\t// Behind the tip but within the finality boundary — correct, permanent, and\n\t// explicitly NOT staleness.\n\tif (behindTip !== null && behindTip > 0) {\n\t\treturn {\n\t\t\t...base,\n\t\t\tstate: \"lagging\",\n\t\t\tdetail: `${behindTip} blocks behind the chain tip, which is expected: only heights below the finality boundary are published`,\n\t\t};\n\t}\n\n\treturn {\n\t\t...base,\n\t\tstate: \"fresh\",\n\t\tdetail: \"published through the finalized height\",\n\t};\n}\n\n/** States a consumer should refuse to restore from. */\nexport function isRestorable(state: ArchiveState): boolean {\n\treturn state === \"fresh\" || state === \"lagging\";\n}\n"
6
+ ],
7
+ "mappings": ";;;;;;;;;;;;;;;;;AAwBO,IAAM,gCAAgC;AAiE7C,IAAM,sCAAsC;AAC5C,IAAM,sCAAsC,KAAK;AAS1C,SAAS,mBAAmB,CAAC,QAAqC;AAAA,EACxE,MAAM,YACL,OAAO,4BAA4B;AAAA,EACpC,MAAM,SACL,OAAO,4BAA4B;AAAA,EAEpC,MAAM,wBAAwB,OAAO,aAClC,KAAK,IACL,GACA,KAAK,OACH,OAAO,IAAI,QAAQ,IAAI,KAAK,MAAM,OAAO,UAAU,KAAK,IAC1D,CACD,IACC;AAAA,EAEH,MAAM,kBACL,OAAO,oBAAoB,QAAQ,OAAO,oBAAoB,OAC3D,KAAK,IAAI,GAAG,OAAO,kBAAkB,OAAO,eAAe,IAC3D;AAAA,EACJ,MAAM,YACL,OAAO,oBAAoB,QAAQ,OAAO,oBAAoB,OAC3D,KAAK,IAAI,GAAG,OAAO,kBAAkB,OAAO,eAAe,IAC3D;AAAA,EAEJ,MAAM,OAAO;AAAA,IACZ,gBACC;AAAA,IACD,SAAS,OAAO;AAAA,IAChB,cAAc,OAAO,IAAI,YAAY;AAAA,IACrC,SAAS;AAAA,MACR,iBAAiB,OAAO;AAAA,MACxB,mBAAmB,OAAO;AAAA,MAC1B,aAAa,OAAO;AAAA,MACpB,gBAAgB,OAAO;AAAA,IACxB;AAAA,IACA,QAAQ;AAAA,MACP,YAAY,OAAO;AAAA,MACnB,kBAAkB,OAAO;AAAA,IAC1B;AAAA,IACA,KAAK;AAAA,MACJ,yBAAyB;AAAA,MACzB,mBAAmB;AAAA,MACnB,yBAAyB;AAAA,IAC1B;AAAA,IACA,OAAO,OAAO,QACX,EAAE,UAAU,OAAO,MAAM,UAAU,YAAY,OAAO,MAAM,UAAU,IACtE;AAAA,EACJ;AAAA,EAGA,IAAI,OAAO,SAAS,CAAC,OAAO,MAAM,UAAU;AAAA,IAC3C,OAAO;AAAA,SACH;AAAA,MACH,OAAO;AAAA,MACP,QAAQ,uCAAuC,OAAO,MAAM;AAAA,IAC7D;AAAA,EACD;AAAA,EAEA,IAAI,CAAC,OAAO,kBAAkB,OAAO,oBAAoB,MAAM;AAAA,IAC9D,OAAO;AAAA,SACH;AAAA,MACH,OAAO;AAAA,MACP,QAAQ;AAAA,IACT;AAAA,EACD;AAAA,EAIA,IAAI,OAAO,oBAAoB,QAAQ,OAAO,oBAAoB,MAAM;AAAA,IACvE,OAAO;AAAA,SACH;AAAA,MACH,OAAO;AAAA,MACP,QACC;AAAA,IACF;AAAA,EACD;AAAA,EAEA,IAAI,0BAA0B,QAAQ,wBAAwB,QAAQ;AAAA,IACrE,OAAO;AAAA,SACH;AAAA,MACH,OAAO;AAAA,MACP,QAAQ,sBAAsB,KAAK,MAAM,wBAAwB,IAAK,sBAAsB,KAAK,MAAM,SAAS,IAAK;AAAA,IACtH;AAAA,EACD;AAAA,EAEA,IAAI,oBAAoB,QAAQ,kBAAkB,WAAW;AAAA,IAC5D,OAAO;AAAA,SACH;AAAA,MACH,OAAO;AAAA,MACP,QAAQ,GAAG,kEAAkE;AAAA,IAC9E;AAAA,EACD;AAAA,EAIA,IAAI,cAAc,QAAQ,YAAY,GAAG;AAAA,IACxC,OAAO;AAAA,SACH;AAAA,MACH,OAAO;AAAA,MACP,QAAQ,GAAG;AAAA,IACZ;AAAA,EACD;AAAA,EAEA,OAAO;AAAA,OACH;AAAA,IACH,OAAO;AAAA,IACP,QAAQ;AAAA,EACT;AAAA;AAIM,SAAS,YAAY,CAAC,OAA8B;AAAA,EAC1D,OAAO,UAAU,WAAW,UAAU;AAAA;",
8
+ "debugId": "D9102A12541A66EA64756E2164756E21",
9
+ "names": []
10
+ }
@@ -715,6 +715,30 @@ interface PendingForkBlocksTable {
715
715
  payload: ColumnType<unknown, unknown, unknown>;
716
716
  received_at: Generated<Date>;
717
717
  }
718
+ type ObserverJournalStatus = "received" | "processed" | "failed";
719
+ /**
720
+ * Exact observer callback receipt. `raw_body` is immutable evidence; the
721
+ * processing columns are updated only after the current derived-state write
722
+ * succeeds or fails.
723
+ */
724
+ interface ObserverJournalTable {
725
+ sequence: Generated<string>;
726
+ network: string;
727
+ path: string;
728
+ source: string | null;
729
+ received_at: Generated<Date>;
730
+ raw_body: ColumnType<Buffer, Buffer, Buffer>;
731
+ raw_body_sha256: string;
732
+ status: ColumnType<ObserverJournalStatus, ObserverJournalStatus | undefined, ObserverJournalStatus>;
733
+ semantic_sha256: string | null;
734
+ block_height: number | null;
735
+ block_hash: string | null;
736
+ burn_block_height: number | null;
737
+ burn_block_hash: string | null;
738
+ result: unknown | null;
739
+ error: string | null;
740
+ processed_at: Date | null;
741
+ }
718
742
  interface Database {
719
743
  blocks: BlocksTable;
720
744
  transactions: TransactionsTable;
@@ -778,6 +802,7 @@ interface Database {
778
802
  x402_balances: X402BalancesTable;
779
803
  chain_read_cache: ChainReadCacheTable;
780
804
  pending_fork_blocks: PendingForkBlocksTable;
805
+ observer_journal: ObserverJournalTable;
781
806
  }
782
807
  /** Prepaid x402 credit — one running USD-micros balance per payer principal. */
783
808
  interface X402BalancesTable {
@@ -1965,6 +1990,7 @@ declare const TABLE_TO_DB: {
1965
1990
  chain_reorgs: string
1966
1991
  chain_read_cache: string
1967
1992
  pending_fork_blocks: string
1993
+ observer_journal: string
1968
1994
  decoded_events: string
1969
1995
  decoder_checkpoints: string
1970
1996
  pox4_calls: string
@@ -2083,4 +2109,4 @@ declare function getRawClient(role?: "source" | "target"): ReturnType<typeof pos
2083
2109
  declare function getRawClientFor(url: string): ReturnType<typeof postgres>;
2084
2110
  /** Close all DB connection pools. Call in CLI commands to allow process exit. */
2085
2111
  declare function closeDb(): Promise<void>;
2086
- export { sql, setMigrationRole, parseJsonb, onControlPlane, onChainPlane, jsonb, getTargetDb, getSourceDb, getRawClientFor, getRawClient, getMigrationRole, getDbSplitStatus, getDb, closeDb, assertDbSplit, X402PaymentsTable, X402BalancesTable, UsageSnapshotsTable, UsageSnapshot, UsageDailyTable, UsageDaily, UpdateTransaction, UpdateTenantUsageMonthly, UpdateTenantComputeAddon, UpdateTenant, UpdateSubscriptionOutbox, UpdateSubscription, UpdateSubgraphOperation, UpdateSubgraph, UpdateProject, UpdateIndexProgress, UpdateEvent, UpdateContract, UpdateBlock, UpdateApiKey, UpdateAccountSpendCap, UpdateAccountCredits, TriggerEvaluatorStateTable, TriggerEvaluatorState, TransactionsTable, TransactionsArchiveTable, Transaction, TenantsTable, TenantUsageMonthlyTable, TenantUsageMonthly, TenantStatus, TenantComputeAddonsTable, TenantComputeAddon, Tenant, TeamMembersTable, TeamMember, TeamInvitationsTable, TeamInvitation, TABLE_TO_DB, SubscriptionsTable, SubscriptionStatus, SubscriptionRuntime, SubscriptionOutboxTable, SubscriptionOutbox, SubscriptionKind, SubscriptionFormat, SubscriptionDelivery, SubscriptionDeliveriesTable, Subscription, SubgraphsTable, SubgraphUsageDailyTable, SubgraphUsageDaily, SubgraphTableSnapshotsTable, SubgraphProcessingStatsTable, SubgraphOperationsTable, SubgraphOperationStatus, SubgraphOperationKind, SubgraphOperation, SubgraphHealthSnapshotsTable, SubgraphHealthSnapshot, SubgraphGapsTable, SubgraphGap, Subgraph, SessionsTable, Session, ServiceHeartbeatsTable, SbtcTokenEventsTable, SbtcTokenEventType, SbtcSupplySnapshotsTable, SbtcSettlementsTable, SbtcEventsTable, SbtcEventTopic, SOURCE_READ_TYPES, SOURCE_READ_PKS, SOURCE_READ_COLUMNS, ProvisioningAuditStatus, ProvisioningAuditLogTable, ProvisioningAuditLog, ProvisioningAuditEvent, ProjectsTable, Project, ProcessedStripeEventsTable, Pox5EventsTable, Pox5EventTopic, Pox4SignersDailyTable, Pox4FunctionName, Pox4CyclesDailyTable, Pox4CallsTable, PendingForkBlocksTable, OutboxStatus, NumericAsText, MigrationRole, MempoolTransactionsTable, MempoolTransaction, MagicLinksTable, MagicLink, InsertTransaction, InsertTenantUsageMonthly, InsertTenantComputeAddon, InsertTenant, InsertTeamMember, InsertTeamInvitation, InsertSubscriptionOutbox, InsertSubscriptionDelivery, InsertSubscription, InsertSubgraphUsageDaily, InsertSubgraphOperation, InsertSubgraphHealthSnapshot, InsertSubgraphGap, InsertSubgraph, InsertSession, InsertProvisioningAuditLog, InsertProject, InsertMempoolTransaction, InsertMagicLink, InsertIndexProgress, InsertEvent, InsertContract, InsertClaimToken, InsertBlock, InsertApiKey, InsertAccountSpendCap, InsertAccountInsight, InsertAccountCredits, InsertAccountAgentRun, InsertAccount, IndexProgressTable, IndexProgress, IndexPrimaryKey, IndexColumnType, IndexColumn, EventsTable, EventsArchiveTable, Event, DecoderCheckpointsTable, DecodedEventsTable, DeadLetterEventsTable, DbSplitStatus, DbReadRow, DbPlane, Database, ContractsTable, Contract, ClaimTokensTable, ClaimToken, ChainReorgsTable, ChainReadCacheTable, BurnBlockRewardsTable, BurnBlockRewardSlotsTable, BnsNamespacesTable, BnsNamespaceEventsTable, BnsNamespaceEventStatus, BnsNamesTable, BnsNameEventsTable, BnsNameEventTopic, BnsMarketplaceEventsTable, BnsMarketplaceAction, BlocksTable, Block, ApiKeysTable, ApiKey, AccountsTable, AccountSpendCapsTable, AccountSpendCap, AccountInsightsTable, AccountInsight, AccountCreditsTable, AccountCredits, AccountAgentRunsTable, AccountAgentRun, Account };
2112
+ export { sql, setMigrationRole, parseJsonb, onControlPlane, onChainPlane, jsonb, getTargetDb, getSourceDb, getRawClientFor, getRawClient, getMigrationRole, getDbSplitStatus, getDb, closeDb, assertDbSplit, X402PaymentsTable, X402BalancesTable, UsageSnapshotsTable, UsageSnapshot, UsageDailyTable, UsageDaily, UpdateTransaction, UpdateTenantUsageMonthly, UpdateTenantComputeAddon, UpdateTenant, UpdateSubscriptionOutbox, UpdateSubscription, UpdateSubgraphOperation, UpdateSubgraph, UpdateProject, UpdateIndexProgress, UpdateEvent, UpdateContract, UpdateBlock, UpdateApiKey, UpdateAccountSpendCap, UpdateAccountCredits, TriggerEvaluatorStateTable, TriggerEvaluatorState, TransactionsTable, TransactionsArchiveTable, Transaction, TenantsTable, TenantUsageMonthlyTable, TenantUsageMonthly, TenantStatus, TenantComputeAddonsTable, TenantComputeAddon, Tenant, TeamMembersTable, TeamMember, TeamInvitationsTable, TeamInvitation, TABLE_TO_DB, SubscriptionsTable, SubscriptionStatus, SubscriptionRuntime, SubscriptionOutboxTable, SubscriptionOutbox, SubscriptionKind, SubscriptionFormat, SubscriptionDelivery, SubscriptionDeliveriesTable, Subscription, SubgraphsTable, SubgraphUsageDailyTable, SubgraphUsageDaily, SubgraphTableSnapshotsTable, SubgraphProcessingStatsTable, SubgraphOperationsTable, SubgraphOperationStatus, SubgraphOperationKind, SubgraphOperation, SubgraphHealthSnapshotsTable, SubgraphHealthSnapshot, SubgraphGapsTable, SubgraphGap, Subgraph, SessionsTable, Session, ServiceHeartbeatsTable, SbtcTokenEventsTable, SbtcTokenEventType, SbtcSupplySnapshotsTable, SbtcSettlementsTable, SbtcEventsTable, SbtcEventTopic, SOURCE_READ_TYPES, SOURCE_READ_PKS, SOURCE_READ_COLUMNS, ProvisioningAuditStatus, ProvisioningAuditLogTable, ProvisioningAuditLog, ProvisioningAuditEvent, ProjectsTable, Project, ProcessedStripeEventsTable, Pox5EventsTable, Pox5EventTopic, Pox4SignersDailyTable, Pox4FunctionName, Pox4CyclesDailyTable, Pox4CallsTable, PendingForkBlocksTable, OutboxStatus, ObserverJournalTable, ObserverJournalStatus, NumericAsText, MigrationRole, MempoolTransactionsTable, MempoolTransaction, MagicLinksTable, MagicLink, InsertTransaction, InsertTenantUsageMonthly, InsertTenantComputeAddon, InsertTenant, InsertTeamMember, InsertTeamInvitation, InsertSubscriptionOutbox, InsertSubscriptionDelivery, InsertSubscription, InsertSubgraphUsageDaily, InsertSubgraphOperation, InsertSubgraphHealthSnapshot, InsertSubgraphGap, InsertSubgraph, InsertSession, InsertProvisioningAuditLog, InsertProject, InsertMempoolTransaction, InsertMagicLink, InsertIndexProgress, InsertEvent, InsertContract, InsertClaimToken, InsertBlock, InsertApiKey, InsertAccountSpendCap, InsertAccountInsight, InsertAccountCredits, InsertAccountAgentRun, InsertAccount, IndexProgressTable, IndexProgress, IndexPrimaryKey, IndexColumnType, IndexColumn, EventsTable, EventsArchiveTable, Event, DecoderCheckpointsTable, DecodedEventsTable, DeadLetterEventsTable, DbSplitStatus, DbReadRow, DbPlane, Database, ContractsTable, Contract, ClaimTokensTable, ClaimToken, ChainReorgsTable, ChainReadCacheTable, BurnBlockRewardsTable, BurnBlockRewardSlotsTable, BnsNamespacesTable, BnsNamespaceEventsTable, BnsNamespaceEventStatus, BnsNamesTable, BnsNameEventsTable, BnsNameEventTopic, BnsMarketplaceEventsTable, BnsMarketplaceAction, BlocksTable, Block, ApiKeysTable, ApiKey, AccountsTable, AccountSpendCapsTable, AccountSpendCap, AccountInsightsTable, AccountInsight, AccountCreditsTable, AccountCredits, AccountAgentRunsTable, AccountAgentRun, Account };
@@ -705,6 +705,7 @@ var TABLE_TO_DB = {
705
705
  chain_reorgs: "source",
706
706
  chain_read_cache: "source",
707
707
  pending_fork_blocks: "source",
708
+ observer_journal: "source",
708
709
  decoded_events: "source",
709
710
  decoder_checkpoints: "source",
710
711
  pox4_calls: "source",
@@ -948,5 +949,5 @@ export {
948
949
  SOURCE_READ_COLUMNS
949
950
  };
950
951
 
951
- //# debugId=FCB4393A94934B0064756E2164756E21
952
+ //# debugId=37AABDB3C4D0230C64756E2164756E21
952
953
  //# sourceMappingURL=index.js.map