@secondlayer/subgraphs 3.7.2 → 3.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/index.js +7 -4
- package/dist/src/index.js.map +3 -3
- package/dist/src/runtime/block-processor.js +7 -4
- package/dist/src/runtime/block-processor.js.map +3 -3
- package/dist/src/runtime/catchup.js +7 -4
- package/dist/src/runtime/catchup.js.map +3 -3
- package/dist/src/runtime/processor.js +203 -117
- package/dist/src/runtime/processor.js.map +14 -11
- package/dist/src/runtime/reindex.js +7 -4
- package/dist/src/runtime/reindex.js.map +3 -3
- package/dist/src/runtime/reorg.js +7 -4
- package/dist/src/runtime/reorg.js.map +3 -3
- package/dist/src/runtime/replay.js +686 -4
- package/dist/src/runtime/replay.js.map +10 -5
- package/dist/src/service.js +206 -120
- package/dist/src/service.js.map +14 -11
- package/package.json +2 -2
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/runtime/replay.ts", "../src/schema/utils.ts"],
|
|
3
|
+
"sources": ["../src/runtime/source-matcher.ts", "../src/runtime/replay.ts", "../src/schema/utils.ts", "../src/runtime/block-source.ts", "../src/runtime/batch-loader.ts", "../src/runtime/reconstruct.ts", "../src/runtime/trigger-evaluator.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import { createHash } from \"node:crypto\";\nimport { type Database, getTargetDb } from \"@secondlayer/shared/db\";\nimport { getSubscription } from \"@secondlayer/shared/db/queries/subscriptions\";\nimport { logger } from \"@secondlayer/shared/logger\";\nimport { type Kysely, sql } from \"kysely\";\nimport { pgSchemaName as defaultSchemaName } from \"../schema/utils.ts\";\n\n/**\n * Replay historical subgraph rows as new outbox entries for a single\n * subscription. Rows are marked `is_replay=TRUE` so the emitter can\n * prioritize live deliveries (90/10 split) and the delivery log can\n * tag replays distinctly.\n *\n * Idempotency: `replayId` is deterministic over `(subscription_id,\n * fromBlock, toBlock)`, so re-running the same replay range is a no-op\n * thanks to the unique `(subscription_id, dedup_key)` constraint. A\n * user who actually wants to re-deliver the same range passes a\n * distinct `replayIdSuffix` (e.g. a timestamp) to get a fresh key.\n */\n\nconst BATCH_SIZE = 500;\n\nfunction replayDedupKey(\n\tsubgraphName: string,\n\ttableName: string,\n\trow: Record<string, unknown>,\n\treplayId: string,\n): string {\n\tconst canonical = `replay:${replayId}:${subgraphName}:${tableName}:${stableStringify(row)}`;\n\treturn createHash(\"sha256\").update(canonical).digest(\"hex\").slice(0, 32);\n}\n\nfunction stableStringify(obj: Record<string, unknown>): string {\n\tconst keys = Object.keys(obj).sort();\n\treturn JSON.stringify(\n\t\tkeys.reduce<Record<string, unknown>>((acc, k) => {\n\t\t\tacc[k] = obj[k];\n\t\t\treturn acc;\n\t\t}, {}),\n\t);\n}\n\nexport interface ReplayInput {\n\taccountId: string;\n\tsubscriptionId: string;\n\tfromBlock: number;\n\ttoBlock: number;\n\t/** Force re-delivery by appending a unique suffix to the replay id. */\n\treplayIdSuffix?: string;\n}\n\nfunction deterministicReplayId(\n\tsubscriptionId: string,\n\tfromBlock: number,\n\ttoBlock: number,\n\tsuffix?: string,\n): string {\n\tconst canonical = `${subscriptionId}:${fromBlock}:${toBlock}${suffix ? `:${suffix}` : \"\"}`;\n\treturn createHash(\"sha256\").update(canonical).digest(\"hex\").slice(0, 16);\n}\n\nexport interface ReplayResult {\n\treplayId: string;\n\tenqueuedCount: number;\n\tscannedCount: number;\n}\n\nasync function resolveSchemaName(\n\tdb: Kysely<Database>,\n\tsubgraphName: string,\n): Promise<string> {\n\tconst row = await db\n\t\t.selectFrom(\"subgraphs\")\n\t\t.select(\"schema_name\")\n\t\t.where(\"name\", \"=\", subgraphName)\n\t\t.executeTakeFirst();\n\tif (!row) {\n\t\tthrow new Error(\n\t\t\t`Subgraph \"${subgraphName}\" not registered — cannot replay its rows. Deploy the subgraph first.`,\n\t\t);\n\t}\n\treturn row.schema_name ?? defaultSchemaName(subgraphName);\n}\n\nexport async function replaySubscription(\n\tinput: ReplayInput,\n): Promise<ReplayResult> {\n\tif (input.fromBlock > input.toBlock) {\n\t\tthrow new Error(\"fromBlock must be <= toBlock\");\n\t}\n\tif (input.toBlock - input.fromBlock > 100_000) {\n\t\tthrow new Error(\"replay range exceeds 100k blocks\");\n\t}\n\n\tconst db = getTargetDb();\n\tconst sub = await getSubscription(db, input.accountId, input.subscriptionId);\n\tif (!sub) throw new Error(\"Subscription not found\");\n\n\t// Replay scans the subgraph's processed table — chain subscriptions have no\n\t// such table (they react to raw chain events), so replay is subgraph-only.\n\tconst subgraphName = sub.subgraph_name;\n\tconst tableName = sub.table_name;\n\tif (sub.kind !== \"subgraph\" || !subgraphName || !tableName) {\n\t\tthrow new Error(\"replay is only supported for subgraph subscriptions\");\n\t}\n\n\tconst schema = await resolveSchemaName(db, subgraphName);\n\tconst replayId = deterministicReplayId(\n\t\tsub.id,\n\t\tinput.fromBlock,\n\t\tinput.toBlock,\n\t\tinput.replayIdSuffix,\n\t);\n\n\tlet scanned = 0;\n\tlet enqueued = 0;\n\tlet offset = 0;\n\n\twhile (true) {\n\t\tconst { rows } = await sql<\n\t\t\tRecord<string, unknown>\n\t\t>`SELECT * FROM ${sql.raw(`\"${schema}\".\"${tableName}\"`)}\n\t\t\tWHERE _block_height >= ${sql.lit(input.fromBlock)}\n\t\t\t\tAND _block_height <= ${sql.lit(input.toBlock)}\n\t\t\tORDER BY _block_height, _created_at\n\t\t\tLIMIT ${sql.lit(BATCH_SIZE)} OFFSET ${sql.lit(offset)}`.execute(db);\n\n\t\tif (rows.length === 0) break;\n\t\tscanned += rows.length;\n\n\t\tconst inserts = rows.map((row) => ({\n\t\t\tsubscription_id: sub.id,\n\t\t\tsubgraph_name: subgraphName,\n\t\t\ttable_name: tableName,\n\t\t\tblock_height: Number(row._block_height),\n\t\t\ttx_id: (row._tx_id as string | undefined) ?? null,\n\t\t\trow_pk: {\n\t\t\t\tblockHeight: Number(row._block_height),\n\t\t\t\ttxId: row._tx_id ?? \"\",\n\t\t\t\treplayId,\n\t\t\t},\n\t\t\tevent_type: `${subgraphName}.${tableName}.replay`,\n\t\t\tpayload: row,\n\t\t\tdedup_key: replayDedupKey(subgraphName, tableName, row, replayId),\n\t\t\tis_replay: true,\n\t\t}));\n\n\t\tconst result = await db\n\t\t\t.insertInto(\"subscription_outbox\")\n\t\t\t.values(inserts)\n\t\t\t.onConflict((oc) =>\n\t\t\t\toc.columns([\"subscription_id\", \"dedup_key\"]).doNothing(),\n\t\t\t)\n\t\t\t.executeTakeFirst();\n\t\tenqueued += Number(result.numInsertedOrUpdatedRows ?? 0);\n\n\t\tif (rows.length < BATCH_SIZE) break;\n\t\toffset += BATCH_SIZE;\n\t}\n\n\tlogger.info(\"Replay enqueued\", {\n\t\tsubscription: sub.name,\n\t\treplayId,\n\t\tscanned,\n\t\tenqueued,\n\t\tfromBlock: input.fromBlock,\n\t\ttoBlock: input.toBlock,\n\t});\n\n\treturn { replayId, enqueuedCount: enqueued, scannedCount: scanned };\n}\n",
|
|
6
|
-
"
|
|
5
|
+
"import type { SubgraphFilter } from \"../types.ts\";\n\nexport interface MatchedTx {\n\ttx: TxRecord;\n\tevents: EventRecord[];\n\t/** Source object key — used for handler dispatch */\n\tsourceName: string;\n}\n\ntype TxRecord = {\n\ttx_id: string;\n\ttype: string;\n\tsender: string;\n\tstatus: string;\n\tcontract_id?: string | null;\n\tfunction_name?: string | null;\n\tfunction_args?: unknown | null;\n\traw_result?: string | null;\n};\n\ntype EventRecord = {\n\tid: string;\n\ttx_id: string;\n\ttype: string;\n\tevent_index: number;\n\tdata: unknown;\n};\n\n// ── Wildcard matching (shared with v1) ──────────────────────────────\n\nconst patternCache = new Map<string, RegExp>();\n\nfunction matchPattern(value: string, pattern: string): boolean {\n\tif (!pattern.includes(\"*\")) return value === pattern;\n\tlet re = patternCache.get(pattern);\n\tif (!re) {\n\t\tconst regex = pattern\n\t\t\t.replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\")\n\t\t\t.replace(/\\*/g, \".*\");\n\t\tre = new RegExp(`^${regex}$`);\n\t\tpatternCache.set(pattern, re);\n\t}\n\treturn re.test(value);\n}\n\n// Trait → set of conforming contract IDs, resolved per block by the caller\n// (block-processor) from the contract registry. Kept as injected data so this\n// module stays pure/sync/DB-less.\nexport type TraitContracts = Map<string, ReadonlySet<string>>;\nconst EMPTY_SET: ReadonlySet<string> = new Set();\n\n/**\n * True when a filter's optional `trait` admits this contract: no trait → always\n * allowed; trait set → the contract must be in the resolved conforming set.\n */\nfunction traitAllows(\n\tfilter: SubgraphFilter,\n\tcontractId: string | undefined | null,\n\ttraitContracts: TraitContracts,\n): boolean {\n\tconst trait = (filter as { trait?: string }).trait;\n\tif (!trait) return true;\n\tif (!contractId) return false;\n\treturn (traitContracts.get(trait) ?? EMPTY_SET).has(contractId);\n}\n\n/** Extract the contract id from an asset identifier (`<contract>::<token>`). */\nfunction assetContract(assetId: string | undefined): string | undefined {\n\treturn assetId?.split(\"::\")[0];\n}\n\n// ── Per-filter-type matchers ────────────────────────────────────────\n\nfunction matchFilter(\n\tfilter: SubgraphFilter,\n\ttransactions: TxRecord[],\n\teventsByTx: Map<string, EventRecord[]>,\n\ttraitContracts: TraitContracts,\n): { tx: TxRecord; events: EventRecord[] }[] {\n\tconst results: { tx: TxRecord; events: EventRecord[] }[] = [];\n\n\tswitch (filter.type) {\n\t\t// ── STX events ──\n\t\tcase \"stx_transfer\":\n\t\tcase \"stx_mint\":\n\t\tcase \"stx_burn\":\n\t\tcase \"stx_lock\": {\n\t\t\tconst eventType = `${filter.type}_event`;\n\t\t\tfor (const tx of transactions) {\n\t\t\t\tconst txEvents = eventsByTx.get(tx.tx_id) ?? [];\n\t\t\t\tconst matched = txEvents.filter((e) => e.type === eventType);\n\t\t\t\tif (matched.length === 0) continue;\n\n\t\t\t\t// Apply address filters\n\t\t\t\tconst filtered = matched.filter((e) => {\n\t\t\t\t\tconst data = e.data as Record<string, unknown> | null;\n\t\t\t\t\tif (!data) return false;\n\t\t\t\t\tif (\"sender\" in filter && filter.sender) {\n\t\t\t\t\t\tif (!matchPattern(data.sender as string, filter.sender))\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tif (\"recipient\" in filter && filter.recipient) {\n\t\t\t\t\t\tif (!matchPattern(data.recipient as string, filter.recipient))\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tif (\"lockedAddress\" in filter && filter.lockedAddress) {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t!matchPattern(data.locked_address as string, filter.lockedAddress)\n\t\t\t\t\t\t)\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\t// Amount filters\n\t\t\t\t\tif (\"minAmount\" in filter && filter.minAmount !== undefined) {\n\t\t\t\t\t\tconst amount = BigInt(\n\t\t\t\t\t\t\t(data.amount ?? data.locked_amount ?? \"0\") as string,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tif (amount < filter.minAmount) return false;\n\t\t\t\t\t}\n\t\t\t\t\tif (\n\t\t\t\t\t\t\"maxAmount\" in filter &&\n\t\t\t\t\t\t(filter as { maxAmount?: bigint }).maxAmount !== undefined\n\t\t\t\t\t) {\n\t\t\t\t\t\tconst amount = BigInt((data.amount ?? \"0\") as string);\n\t\t\t\t\t\tif (amount > (filter as { maxAmount: bigint }).maxAmount)\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\treturn true;\n\t\t\t\t});\n\n\t\t\t\tif (filtered.length > 0) {\n\t\t\t\t\tresults.push({ tx, events: filtered });\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\t// ── FT events ──\n\t\tcase \"ft_transfer\":\n\t\tcase \"ft_mint\":\n\t\tcase \"ft_burn\": {\n\t\t\tconst eventType = `${filter.type}_event`;\n\t\t\tfor (const tx of transactions) {\n\t\t\t\tconst txEvents = eventsByTx.get(tx.tx_id) ?? [];\n\t\t\t\tconst matched = txEvents.filter((e) => {\n\t\t\t\t\tif (e.type !== eventType) return false;\n\t\t\t\t\tconst data = e.data as Record<string, unknown> | null;\n\t\t\t\t\tif (!data) return false;\n\n\t\t\t\t\t// Asset identifier filter\n\t\t\t\t\tif (filter.assetIdentifier) {\n\t\t\t\t\t\tconst assetId = data.asset_identifier as string | undefined;\n\t\t\t\t\t\tif (!assetId || !matchPattern(assetId, filter.assetIdentifier))\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\t// Trait scope — the asset's contract must conform.\n\t\t\t\t\tif (\n\t\t\t\t\t\t!traitAllows(\n\t\t\t\t\t\t\tfilter,\n\t\t\t\t\t\t\tassetContract(data.asset_identifier as string | undefined),\n\t\t\t\t\t\t\ttraitContracts,\n\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t// Address filters\n\t\t\t\t\tif (\"sender\" in filter && filter.sender) {\n\t\t\t\t\t\tif (!matchPattern(data.sender as string, filter.sender))\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tif (\"recipient\" in filter && filter.recipient) {\n\t\t\t\t\t\tif (!matchPattern(data.recipient as string, filter.recipient))\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\t// Amount filter\n\t\t\t\t\tif (filter.minAmount !== undefined) {\n\t\t\t\t\t\tconst amount = BigInt((data.amount ?? \"0\") as string);\n\t\t\t\t\t\tif (amount < filter.minAmount) return false;\n\t\t\t\t\t}\n\t\t\t\t\treturn true;\n\t\t\t\t});\n\n\t\t\t\tif (matched.length > 0) {\n\t\t\t\t\tresults.push({ tx, events: matched });\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\t// ── NFT events ──\n\t\tcase \"nft_transfer\":\n\t\tcase \"nft_mint\":\n\t\tcase \"nft_burn\": {\n\t\t\tconst eventType = `${filter.type}_event`;\n\t\t\tfor (const tx of transactions) {\n\t\t\t\tconst txEvents = eventsByTx.get(tx.tx_id) ?? [];\n\t\t\t\tconst matched = txEvents.filter((e) => {\n\t\t\t\t\tif (e.type !== eventType) return false;\n\t\t\t\t\tconst data = e.data as Record<string, unknown> | null;\n\t\t\t\t\tif (!data) return false;\n\n\t\t\t\t\tif (filter.assetIdentifier) {\n\t\t\t\t\t\tconst assetId = data.asset_identifier as string | undefined;\n\t\t\t\t\t\tif (!assetId || !matchPattern(assetId, filter.assetIdentifier))\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tif (\n\t\t\t\t\t\t!traitAllows(\n\t\t\t\t\t\t\tfilter,\n\t\t\t\t\t\t\tassetContract(data.asset_identifier as string | undefined),\n\t\t\t\t\t\t\ttraitContracts,\n\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t\t\t\treturn false;\n\t\t\t\t\tif (\"sender\" in filter && filter.sender) {\n\t\t\t\t\t\tif (!matchPattern(data.sender as string, filter.sender))\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tif (\"recipient\" in filter && filter.recipient) {\n\t\t\t\t\t\tif (!matchPattern(data.recipient as string, filter.recipient))\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\treturn true;\n\t\t\t\t});\n\n\t\t\t\tif (matched.length > 0) {\n\t\t\t\t\tresults.push({ tx, events: matched });\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\t// ── Contract call ──\n\t\tcase \"contract_call\": {\n\t\t\tfor (const tx of transactions) {\n\t\t\t\tif (tx.type !== \"contract_call\") continue;\n\n\t\t\t\t// Contract filter\n\t\t\t\tif (filter.contractId) {\n\t\t\t\t\tif (\n\t\t\t\t\t\t!tx.contract_id ||\n\t\t\t\t\t\t!matchPattern(tx.contract_id, filter.contractId)\n\t\t\t\t\t)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t// Function filter\n\t\t\t\tif (filter.functionName) {\n\t\t\t\t\tif (\n\t\t\t\t\t\t!tx.function_name ||\n\t\t\t\t\t\t!matchPattern(tx.function_name, filter.functionName)\n\t\t\t\t\t)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t// Caller filter\n\t\t\t\tif (filter.caller) {\n\t\t\t\t\tif (!matchPattern(tx.sender, filter.caller)) continue;\n\t\t\t\t}\n\t\t\t\t// Trait scope — the called contract must conform.\n\t\t\t\tif (!traitAllows(filter, tx.contract_id, traitContracts)) continue;\n\n\t\t\t\tconst txEvents = eventsByTx.get(tx.tx_id) ?? [];\n\t\t\t\tresults.push({ tx, events: txEvents });\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\t// ── Contract deploy ──\n\t\tcase \"contract_deploy\": {\n\t\t\tfor (const tx of transactions) {\n\t\t\t\tif (tx.type !== \"smart_contract\") continue;\n\n\t\t\t\tif (filter.deployer) {\n\t\t\t\t\tif (!matchPattern(tx.sender, filter.deployer)) continue;\n\t\t\t\t}\n\t\t\t\tif (filter.contractName) {\n\t\t\t\t\tconst name = tx.contract_id?.split(\".\")[1] ?? \"\";\n\t\t\t\t\tif (!matchPattern(name, filter.contractName)) continue;\n\t\t\t\t}\n\n\t\t\t\tconst txEvents = eventsByTx.get(tx.tx_id) ?? [];\n\t\t\t\tresults.push({ tx, events: txEvents });\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\t// ── Print event ──\n\t\tcase \"print_event\": {\n\t\t\tfor (const tx of transactions) {\n\t\t\t\tconst txEvents = eventsByTx.get(tx.tx_id) ?? [];\n\t\t\t\tconst matched = txEvents.filter((e) => {\n\t\t\t\t\tif (e.type !== \"smart_contract_event\" && e.type !== \"contract_event\")\n\t\t\t\t\t\treturn false;\n\t\t\t\t\tconst data = e.data as Record<string, unknown> | null;\n\t\t\t\t\tif (!data) return false;\n\t\t\t\t\tif (data.topic !== \"print\") return false;\n\n\t\t\t\t\t// Contract filter — events store the contract under either\n\t\t\t\t\t// `contract_identifier` (legacy smart_contract_event payload)\n\t\t\t\t\t// or `contract_id` (current contract_event payload). Mirror\n\t\t\t\t\t// the streams query which checks both shapes.\n\t\t\t\t\tconst printContractId =\n\t\t\t\t\t\t(data.contract_identifier as string | undefined) ??\n\t\t\t\t\t\t(data.contract_id as string | undefined);\n\t\t\t\t\tif (filter.contractId) {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t!printContractId ||\n\t\t\t\t\t\t\t!matchPattern(printContractId, filter.contractId)\n\t\t\t\t\t\t)\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tif (!traitAllows(filter, printContractId, traitContracts))\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t// Topic filter — check the decoded Clarity value's topic field\n\t\t\t\t\t// At this stage data.value is still raw hex; topic filtering happens\n\t\t\t\t\t// after decode in the runner. For now, skip topic filtering here.\n\t\t\t\t\t// The runner will filter by topic after decoding.\n\t\t\t\t\treturn true;\n\t\t\t\t});\n\n\t\t\t\tif (matched.length > 0) {\n\t\t\t\t\tresults.push({ tx, events: matched });\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn results;\n}\n\n/**\n * Match named filters against a block's transactions and events.\n * Returns matches with sourceName = the object key from sources.\n */\nexport function matchSources(\n\tsources: Record<string, SubgraphFilter>,\n\ttransactions: TxRecord[],\n\tevents: EventRecord[],\n\ttraitContracts: TraitContracts = new Map(),\n): MatchedTx[] {\n\t// Index events by txId\n\tconst eventsByTx = new Map<string, EventRecord[]>();\n\tfor (const event of events) {\n\t\tconst list = eventsByTx.get(event.tx_id) ?? [];\n\t\tlist.push(event);\n\t\teventsByTx.set(event.tx_id, list);\n\t}\n\n\tconst seen = new Set<string>();\n\tconst results: MatchedTx[] = [];\n\n\tfor (const [sourceName, filter] of Object.entries(sources)) {\n\t\tconst matches = matchFilter(\n\t\t\tfilter,\n\t\t\ttransactions,\n\t\t\teventsByTx,\n\t\t\ttraitContracts,\n\t\t);\n\t\tfor (const match of matches) {\n\t\t\tconst dedupeKey = `${match.tx.tx_id}:${sourceName}`;\n\t\t\tif (!seen.has(dedupeKey)) {\n\t\t\t\tseen.add(dedupeKey);\n\t\t\t\tresults.push({ ...match, sourceName });\n\t\t\t}\n\t\t}\n\t}\n\n\treturn results;\n}\n",
|
|
6
|
+
"import { createHash } from \"node:crypto\";\nimport { type Database, getTargetDb } from \"@secondlayer/shared/db\";\nimport type { Subscription } from \"@secondlayer/shared/db\";\nimport { getSubscription } from \"@secondlayer/shared/db/queries/subscriptions\";\nimport { logger } from \"@secondlayer/shared/logger\";\nimport { type Kysely, sql } from \"kysely\";\nimport { pgSchemaName as defaultSchemaName } from \"../schema/utils.ts\";\nimport { PublicApiBlockSource, buildHttpClient } from \"./block-source.ts\";\nimport {\n\tbuildSourcesMap,\n\tbuildTraitContracts,\n\temitChainOutbox,\n\tevaluateBlock,\n\treferencedEventTypes,\n} from \"./trigger-evaluator.ts\";\n\n/**\n * Replay historical subgraph rows as new outbox entries for a single\n * subscription. Rows are marked `is_replay=TRUE` so the emitter can\n * prioritize live deliveries (90/10 split) and the delivery log can\n * tag replays distinctly.\n *\n * Idempotency: `replayId` is deterministic over `(subscription_id,\n * fromBlock, toBlock)`, so re-running the same replay range is a no-op\n * thanks to the unique `(subscription_id, dedup_key)` constraint. A\n * user who actually wants to re-deliver the same range passes a\n * distinct `replayIdSuffix` (e.g. a timestamp) to get a fresh key.\n */\n\nconst BATCH_SIZE = 500;\n\nfunction replayDedupKey(\n\tsubgraphName: string,\n\ttableName: string,\n\trow: Record<string, unknown>,\n\treplayId: string,\n): string {\n\tconst canonical = `replay:${replayId}:${subgraphName}:${tableName}:${stableStringify(row)}`;\n\treturn createHash(\"sha256\").update(canonical).digest(\"hex\").slice(0, 32);\n}\n\nfunction stableStringify(obj: Record<string, unknown>): string {\n\tconst keys = Object.keys(obj).sort();\n\treturn JSON.stringify(\n\t\tkeys.reduce<Record<string, unknown>>((acc, k) => {\n\t\t\tacc[k] = obj[k];\n\t\t\treturn acc;\n\t\t}, {}),\n\t);\n}\n\nexport interface ReplayInput {\n\taccountId: string;\n\tsubscriptionId: string;\n\tfromBlock: number;\n\ttoBlock: number;\n\t/** Force re-delivery by appending a unique suffix to the replay id. */\n\treplayIdSuffix?: string;\n}\n\nfunction deterministicReplayId(\n\tsubscriptionId: string,\n\tfromBlock: number,\n\ttoBlock: number,\n\tsuffix?: string,\n): string {\n\tconst canonical = `${subscriptionId}:${fromBlock}:${toBlock}${suffix ? `:${suffix}` : \"\"}`;\n\treturn createHash(\"sha256\").update(canonical).digest(\"hex\").slice(0, 16);\n}\n\nexport interface ReplayResult {\n\treplayId: string;\n\tenqueuedCount: number;\n\tscannedCount: number;\n}\n\nasync function resolveSchemaName(\n\tdb: Kysely<Database>,\n\tsubgraphName: string,\n): Promise<string> {\n\tconst row = await db\n\t\t.selectFrom(\"subgraphs\")\n\t\t.select(\"schema_name\")\n\t\t.where(\"name\", \"=\", subgraphName)\n\t\t.executeTakeFirst();\n\tif (!row) {\n\t\tthrow new Error(\n\t\t\t`Subgraph \"${subgraphName}\" not registered — cannot replay its rows. Deploy the subgraph first.`,\n\t\t);\n\t}\n\treturn row.schema_name ?? defaultSchemaName(subgraphName);\n}\n\nexport async function replaySubscription(\n\tinput: ReplayInput,\n): Promise<ReplayResult> {\n\tif (input.fromBlock > input.toBlock) {\n\t\tthrow new Error(\"fromBlock must be <= toBlock\");\n\t}\n\tif (input.toBlock - input.fromBlock > 100_000) {\n\t\tthrow new Error(\"replay range exceeds 100k blocks\");\n\t}\n\n\tconst db = getTargetDb();\n\tconst sub = await getSubscription(db, input.accountId, input.subscriptionId);\n\tif (!sub) throw new Error(\"Subscription not found\");\n\n\t// Chain subs have no processed table — they react to raw chain events. Replay\n\t// re-runs the pure matcher over the canonical block range instead of scanning\n\t// rows.\n\tif (sub.kind === \"chain\") {\n\t\treturn replayChainSubscription(db, sub, input);\n\t}\n\n\tconst subgraphName = sub.subgraph_name;\n\tconst tableName = sub.table_name;\n\tif (sub.kind !== \"subgraph\" || !subgraphName || !tableName) {\n\t\tthrow new Error(\n\t\t\t\"replay is only supported for subgraph or chain subscriptions\",\n\t\t);\n\t}\n\n\tconst schema = await resolveSchemaName(db, subgraphName);\n\tconst replayId = deterministicReplayId(\n\t\tsub.id,\n\t\tinput.fromBlock,\n\t\tinput.toBlock,\n\t\tinput.replayIdSuffix,\n\t);\n\n\tlet scanned = 0;\n\tlet enqueued = 0;\n\tlet offset = 0;\n\n\twhile (true) {\n\t\tconst { rows } = await sql<\n\t\t\tRecord<string, unknown>\n\t\t>`SELECT * FROM ${sql.raw(`\"${schema}\".\"${tableName}\"`)}\n\t\t\tWHERE _block_height >= ${sql.lit(input.fromBlock)}\n\t\t\t\tAND _block_height <= ${sql.lit(input.toBlock)}\n\t\t\tORDER BY _block_height, _created_at\n\t\t\tLIMIT ${sql.lit(BATCH_SIZE)} OFFSET ${sql.lit(offset)}`.execute(db);\n\n\t\tif (rows.length === 0) break;\n\t\tscanned += rows.length;\n\n\t\tconst inserts = rows.map((row) => ({\n\t\t\tsubscription_id: sub.id,\n\t\t\tsubgraph_name: subgraphName,\n\t\t\ttable_name: tableName,\n\t\t\tblock_height: Number(row._block_height),\n\t\t\ttx_id: (row._tx_id as string | undefined) ?? null,\n\t\t\trow_pk: {\n\t\t\t\tblockHeight: Number(row._block_height),\n\t\t\t\ttxId: row._tx_id ?? \"\",\n\t\t\t\treplayId,\n\t\t\t},\n\t\t\tevent_type: `${subgraphName}.${tableName}.replay`,\n\t\t\tpayload: row,\n\t\t\tdedup_key: replayDedupKey(subgraphName, tableName, row, replayId),\n\t\t\tis_replay: true,\n\t\t}));\n\n\t\tconst result = await db\n\t\t\t.insertInto(\"subscription_outbox\")\n\t\t\t.values(inserts)\n\t\t\t.onConflict((oc) =>\n\t\t\t\toc.columns([\"subscription_id\", \"dedup_key\"]).doNothing(),\n\t\t\t)\n\t\t\t.executeTakeFirst();\n\t\tenqueued += Number(result.numInsertedOrUpdatedRows ?? 0);\n\n\t\tif (rows.length < BATCH_SIZE) break;\n\t\toffset += BATCH_SIZE;\n\t}\n\n\tlogger.info(\"Replay enqueued\", {\n\t\tsubscription: sub.name,\n\t\treplayId,\n\t\tscanned,\n\t\tenqueued,\n\t\tfromBlock: input.fromBlock,\n\t\ttoBlock: input.toBlock,\n\t});\n\n\treturn { replayId, enqueuedCount: enqueued, scannedCount: scanned };\n}\n\nconst CHAIN_REPLAY_BATCH = 200;\n\n/**\n * Replay a chain subscription by re-running the pure matcher over a historical\n * canonical block range and emitting fresh apply rows. Unlike subgraph replay\n * there is no processed table to scan — the matcher is range-driven, so we\n * reload canonical blocks off the public Index/Streams clock and re-match.\n *\n * Rows are emitted with `is_replay=TRUE` and replay-namespaced dedup keys, and —\n * critically — this never advances `trigger_evaluator_state`: replay is\n * historical and must not move the live forward cursor.\n */\nasync function replayChainSubscription(\n\tdb: Kysely<Database>,\n\tsub: Subscription,\n\tinput: ReplayInput,\n): Promise<ReplayResult> {\n\tconst replayId = deterministicReplayId(\n\t\tsub.id,\n\t\tinput.fromBlock,\n\t\tinput.toBlock,\n\t\tinput.replayIdSuffix,\n\t);\n\n\tconst { sources, keyMeta } = buildSourcesMap([sub]);\n\tconst source = new PublicApiBlockSource(\n\t\tbuildHttpClient(),\n\t\treferencedEventTypes([sub]),\n\t);\n\n\tlet scanned = 0;\n\tlet enqueued = 0;\n\tfor (\n\t\tlet from = input.fromBlock;\n\t\tfrom <= input.toBlock;\n\t\tfrom += CHAIN_REPLAY_BATCH\n\t) {\n\t\tconst to = Math.min(from + CHAIN_REPLAY_BATCH - 1, input.toBlock);\n\t\tconst blocks = await source.loadBlockRange(from, to);\n\t\t// Trait membership only grows; resolve once per batch as of its top height.\n\t\tconst traitContracts = await buildTraitContracts(db, [sub], to);\n\t\tfor (let h = from; h <= to; h++) {\n\t\t\tconst bd = blocks.get(h);\n\t\t\tif (!bd) continue;\n\t\t\tscanned++;\n\t\t\tconst matches = evaluateBlock(bd, sources, traitContracts);\n\t\t\tif (matches.length === 0) continue;\n\t\t\tenqueued += await emitChainOutbox(\n\t\t\t\tdb,\n\t\t\t\tmatches,\n\t\t\t\tkeyMeta,\n\t\t\t\th,\n\t\t\t\tbd.block.hash,\n\t\t\t\t{\n\t\t\t\t\treplayId,\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t}\n\n\tlogger.info(\"Chain replay enqueued\", {\n\t\tsubscription: sub.name,\n\t\treplayId,\n\t\tscanned,\n\t\tenqueued,\n\t\tfromBlock: input.fromBlock,\n\t\ttoBlock: input.toBlock,\n\t});\n\n\treturn { replayId, enqueuedCount: enqueued, scannedCount: scanned };\n}\n",
|
|
7
|
+
"// Re-export canonical pgSchemaName from shared\nexport { pgSchemaName } from \"@secondlayer/shared/db/queries/subgraphs\";\n",
|
|
8
|
+
"import { getSourceDb } from \"@secondlayer/shared/db\";\nimport { IndexHttpClient } from \"@secondlayer/shared/index-http\";\nimport { logger } from \"@secondlayer/shared/logger\";\nimport type { SubgraphDefinition, SubgraphFilter } from \"../types.ts\";\nimport { type BlockData, loadBlockRange } from \"./batch-loader.ts\";\nimport {\n\treconstructBlock,\n\treconstructEvent,\n\treconstructTransaction,\n} from \"./reconstruct.ts\";\n\n/**\n * Where the subgraph runtime reads canonical chain data. Today it taps the\n * indexer Postgres directly (`PostgresBlockSource`); the re-point adds a\n * `PublicApiBlockSource` that consumes the Streams clock + Index data over\n * HTTP. `matchSources` / handlers / flush / outbox are unchanged — only the\n * loader + tip swap behind this seam.\n */\nexport interface BlockSource {\n\t/** Highest canonical block height available to process. */\n\tgetTip(): Promise<number>;\n\t/** Canonical block data for [fromHeight, toHeight], keyed by height. */\n\tloadBlockRange(\n\t\tfromHeight: number,\n\t\ttoHeight: number,\n\t): Promise<Map<number, BlockData>>;\n}\n\n/** Reads directly from the shared indexer Postgres (the original behavior). */\nexport class PostgresBlockSource implements BlockSource {\n\tasync getTip(): Promise<number> {\n\t\tconst progress = await getSourceDb()\n\t\t\t.selectFrom(\"index_progress\")\n\t\t\t.selectAll()\n\t\t\t.where(\"network\", \"=\", process.env.NETWORK ?? \"mainnet\")\n\t\t\t.executeTakeFirst();\n\t\treturn progress ? Number(progress.highest_seen_block) : 0;\n\t}\n\n\tloadBlockRange(\n\t\tfromHeight: number,\n\t\ttoHeight: number,\n\t): Promise<Map<number, BlockData>> {\n\t\treturn loadBlockRange(getSourceDb(), fromHeight, toHeight);\n\t}\n}\n\n// Subgraph source filter types that map to a decoded Index event_type. The\n// `_event` suffix is the runtime's raw form; print is keyed `print_event`.\nconst EVENT_FILTER_TO_INDEX_TYPE: Record<string, string> = {\n\tstx_transfer: \"stx_transfer\",\n\tstx_mint: \"stx_mint\",\n\tstx_burn: \"stx_burn\",\n\tstx_lock: \"stx_lock\",\n\tft_transfer: \"ft_transfer\",\n\tft_mint: \"ft_mint\",\n\tft_burn: \"ft_burn\",\n\tnft_transfer: \"nft_transfer\",\n\tnft_mint: \"nft_mint\",\n\tnft_burn: \"nft_burn\",\n\tprint_event: \"print\",\n};\n\n// Tx-level source types — matched against /v1/index/transactions, not events.\nconst TX_SOURCE_TYPES = new Set([\"contract_call\", \"contract_deploy\"]);\nconst ALL_INDEX_EVENT_TYPES = [\n\t...new Set(Object.values(EVENT_FILTER_TO_INDEX_TYPE)),\n];\n\nfunction sourceFilters(subgraph: SubgraphDefinition): SubgraphFilter[] {\n\tconst sources = subgraph.sources;\n\treturn Array.isArray(sources)\n\t\t? (sources as SubgraphFilter[])\n\t\t: Object.values(sources as Record<string, SubgraphFilter>);\n}\n\n/**\n * The Index event_types the loader must fetch for a set of source filter types.\n * A contract_call/contract_deploy source matches a tx and hands its FULL event\n * set to the handler, so when one is present we fetch every event type (the\n * matched tx's events must be complete); otherwise just the referenced types.\n * Shared by the subgraph loader and the chain-trigger evaluator.\n */\nexport function indexEventTypesForFilterTypes(filterTypes: string[]): string[] {\n\tif (filterTypes.some((t) => TX_SOURCE_TYPES.has(t))) {\n\t\treturn ALL_INDEX_EVENT_TYPES;\n\t}\n\tconst types = new Set<string>();\n\tfor (const t of filterTypes) {\n\t\tconst indexType = EVENT_FILTER_TO_INDEX_TYPE[t];\n\t\tif (indexType) types.add(indexType);\n\t}\n\treturn [...types];\n}\n\nfunction referencedIndexEventTypes(subgraph: SubgraphDefinition): string[] {\n\treturn indexEventTypesForFilterTypes(\n\t\tsourceFilters(subgraph).map((f) => f.type),\n\t);\n}\n\n/**\n * streams-index eligibility: every source must be a known event-type or\n * contract_call/contract_deploy filter (no array-style sources, which leak the\n * unreconstructable `_eventId`). Trait scope IS allowed — trait resolution\n * reads the contract registry on the platform DB (`targetDb`), which the\n * processor always holds, so it's source-independent. Everything else stays on\n * the DB tap.\n */\nexport function isStreamsIndexEligible(subgraph: SubgraphDefinition): boolean {\n\tif (Array.isArray(subgraph.sources)) return false;\n\tconst filters = sourceFilters(subgraph);\n\tif (filters.length === 0) return false;\n\tfor (const f of filters) {\n\t\tconst known =\n\t\t\tEVENT_FILTER_TO_INDEX_TYPE[f.type] || TX_SOURCE_TYPES.has(f.type);\n\t\tif (!known) return false;\n\t}\n\treturn true;\n}\n\n/** Streams clock + Index data plane, reconstructed into raw BlockData rows. */\nexport class PublicApiBlockSource implements BlockSource {\n\tconstructor(\n\t\tprivate readonly http: IndexHttpClient,\n\t\tprivate readonly eventTypes: string[],\n\t) {}\n\n\tgetTip(): Promise<number> {\n\t\t// Bound advancement to what the Index data plane can serve — never\n\t\t// process past it even if the Streams clock is ahead.\n\t\treturn this.http.getIndexTip();\n\t}\n\n\tasync loadBlockRange(\n\t\tfromHeight: number,\n\t\ttoHeight: number,\n\t): Promise<Map<number, BlockData>> {\n\t\tconst [blocks, txs, eventLists] = await Promise.all([\n\t\t\tthis.http.walkBlocks(fromHeight, toHeight),\n\t\t\tthis.http.walkTransactions(fromHeight, toHeight),\n\t\t\tPromise.all(\n\t\t\t\tthis.eventTypes.map((t) =>\n\t\t\t\t\tthis.http.walkEvents(t, fromHeight, toHeight),\n\t\t\t\t),\n\t\t\t),\n\t\t]);\n\n\t\tconst map = new Map<number, BlockData>();\n\t\t// Seed every canonical height (incl. empty blocks) so catch-up doesn't\n\t\t// file them as gaps.\n\t\tfor (const b of blocks) {\n\t\t\tmap.set(b.block_height, {\n\t\t\t\tblock: reconstructBlock(b),\n\t\t\t\ttxs: [],\n\t\t\t\tevents: [],\n\t\t\t});\n\t\t}\n\t\tfor (const t of txs) {\n\t\t\tmap.get(t.block_height)?.txs.push(reconstructTransaction(t));\n\t\t}\n\t\tfor (const list of eventLists) {\n\t\t\tfor (const e of list) {\n\t\t\t\tmap.get(e.block_height)?.events.push(reconstructEvent(e));\n\t\t\t}\n\t\t}\n\t\t// Canonical ordering — multi-type event walks merge here.\n\t\tfor (const bd of map.values()) {\n\t\t\tbd.txs.sort((a, b) => a.tx_index - b.tx_index);\n\t\t\tbd.events.sort((a, b) => a.event_index - b.event_index);\n\t\t}\n\t\treturn map;\n\t}\n}\n\nconst postgresBlockSource = new PostgresBlockSource();\n\nexport function buildHttpClient(): IndexHttpClient {\n\tconst baseUrl =\n\t\tprocess.env.SUBGRAPH_INDEX_API_URL ??\n\t\tprocess.env.STREAMS_API_URL ??\n\t\t\"http://api:3800\";\n\treturn new IndexHttpClient({\n\t\tindexBaseUrl: baseUrl,\n\t\tstreamsBaseUrl: baseUrl,\n\t\tstreamsApiKey:\n\t\t\tprocess.env.STREAMS_INTERNAL_API_KEY ?? \"sk-sl_streams_l2_internal\",\n\t});\n}\n\n/**\n * Resolve the block source for a subgraph. `SUBGRAPH_SOURCE=streams-index`\n * opts eligible subgraphs onto the public Streams clock + Index data; everything\n * else (and the default) stays on the Postgres tap.\n */\nexport function resolveBlockSource(subgraph?: SubgraphDefinition): BlockSource {\n\tif (\n\t\tprocess.env.SUBGRAPH_SOURCE === \"streams-index\" &&\n\t\tsubgraph &&\n\t\tisStreamsIndexEligible(subgraph)\n\t) {\n\t\treturn new PublicApiBlockSource(\n\t\t\tbuildHttpClient(),\n\t\t\treferencedIndexEventTypes(subgraph),\n\t\t);\n\t}\n\tif (process.env.SUBGRAPH_SOURCE === \"streams-index\" && subgraph) {\n\t\tlogger.debug(\"Subgraph not streams-index eligible, using DB tap\", {\n\t\t\tsubgraph: subgraph.name,\n\t\t});\n\t}\n\treturn postgresBlockSource;\n}\n",
|
|
9
|
+
"import type {\n\tBlock,\n\tDatabase,\n\tEvent,\n\tTransaction,\n} from \"@secondlayer/shared/db\";\nimport type { Kysely } from \"kysely\";\n\nexport interface BlockData {\n\tblock: Block;\n\ttxs: Transaction[];\n\tevents: Event[];\n}\n\n/**\n * Load a range of blocks with their transactions and events in 3 parallel queries.\n * Returns a Map keyed by block height. Non-canonical blocks are excluded.\n */\nexport async function loadBlockRange(\n\tdb: Kysely<Database>,\n\tfromHeight: number,\n\ttoHeight: number,\n): Promise<Map<number, BlockData>> {\n\tconst [blocks, txs, events] = await Promise.all([\n\t\tdb\n\t\t\t.selectFrom(\"blocks\")\n\t\t\t.selectAll()\n\t\t\t.where(\"height\", \">=\", fromHeight)\n\t\t\t.where(\"height\", \"<=\", toHeight)\n\t\t\t.where(\"canonical\", \"=\", true)\n\t\t\t.execute(),\n\t\tdb\n\t\t\t.selectFrom(\"transactions\")\n\t\t\t.selectAll()\n\t\t\t.where(\"block_height\", \">=\", fromHeight)\n\t\t\t.where(\"block_height\", \"<=\", toHeight)\n\t\t\t.execute(),\n\t\tdb\n\t\t\t.selectFrom(\"events\")\n\t\t\t.selectAll()\n\t\t\t.where(\"block_height\", \">=\", fromHeight)\n\t\t\t.where(\"block_height\", \"<=\", toHeight)\n\t\t\t.execute(),\n\t]);\n\n\t// Index by block height (coerce to number — bigint columns may return as string or number)\n\tconst txsByHeight = new Map<number, Transaction[]>();\n\tfor (const tx of txs) {\n\t\tconst h = Number(tx.block_height);\n\t\tconst list = txsByHeight.get(h) ?? [];\n\t\tlist.push(tx);\n\t\ttxsByHeight.set(h, list);\n\t}\n\n\tconst eventsByHeight = new Map<number, Event[]>();\n\tfor (const evt of events) {\n\t\tconst h = Number(evt.block_height);\n\t\tconst list = eventsByHeight.get(h) ?? [];\n\t\tlist.push(evt);\n\t\teventsByHeight.set(h, list);\n\t}\n\n\tconst result = new Map<number, BlockData>();\n\tfor (const block of blocks) {\n\t\tconst h = Number(block.height);\n\t\tresult.set(h, {\n\t\t\tblock,\n\t\t\ttxs: txsByHeight.get(h) ?? [],\n\t\t\tevents: eventsByHeight.get(h) ?? [],\n\t\t});\n\t}\n\n\treturn result;\n}\n\n/**\n * Compute average events per block from a loaded batch.\n * Used for adaptive batch sizing.\n */\nexport function avgEventsPerBlock(batch: Map<number, BlockData>): number {\n\tif (batch.size === 0) return 0;\n\tlet totalEvents = 0;\n\tfor (const data of batch.values()) {\n\t\ttotalEvents += data.events.length;\n\t}\n\treturn totalEvents / batch.size;\n}\n",
|
|
10
|
+
"import type { Block, Event, Transaction } from \"@secondlayer/shared/db\";\nimport type {\n\tIndexBlockRow,\n\tIndexEventRow,\n\tIndexTransactionRow,\n} from \"@secondlayer/shared/index-http\";\n\nexport type {\n\tIndexBlockRow,\n\tIndexEventRow,\n\tIndexTransactionRow,\n} from \"@secondlayer/shared/index-http\";\n\n/**\n * Reconstruct the raw `blocks`/`events` row shapes the subgraph runtime expects\n * (the shapes `matchSources` + the handler runner read) from the decoded,\n * flattened rows the public Index API serves. This is what lets\n * `PublicApiBlockSource` feed the EXISTING pipeline byte-identically to the\n * Postgres tap.\n *\n * Two shape gaps the Index API can't avoid, handled here:\n * - Index event rows are flat (`event_type: \"ft_transfer\"`, columns\n * `sender`/`amount`/…); the runtime expects the node's nested `data` keyed by\n * a suffixed `type` (`ft_transfer_event`), with print under `contract_event`.\n * - nft/print Clarity values: the runtime decodes from the canonical hex\n * (`raw_value`), so we place the Index hex there. (The node's verbose\n * serde-tagged `value`, e.g. `{UInt:223}`, is not reproducible from hex and\n * is no longer read — see the nft tokenId normalization in runner.ts.)\n */\n\n/** ISO `block_time` (or null) → unix-seconds integer the runtime expects. */\nfunction isoToUnixSeconds(iso: string | null): number {\n\tif (!iso) return 0;\n\treturn Math.floor(new Date(iso).getTime() / 1000);\n}\n\nexport function reconstructBlock(b: IndexBlockRow): Block {\n\treturn {\n\t\theight: b.block_height,\n\t\thash: b.block_hash,\n\t\tparent_hash: b.parent_hash,\n\t\tburn_block_height: b.burn_block_height,\n\t\tburn_block_hash: b.burn_block_hash,\n\t\ttimestamp: isoToUnixSeconds(b.block_time),\n\t\t// Index serves canonical rows only.\n\t\tcanonical: true,\n\t\tcreated_at: new Date(0),\n\t} as Block;\n}\n\nexport function reconstructTransaction(t: IndexTransactionRow): Transaction {\n\treturn {\n\t\ttx_id: t.tx_id,\n\t\tblock_height: t.block_height,\n\t\ttx_index: t.tx_index,\n\t\ttype: t.tx_type,\n\t\tsender: t.sender,\n\t\tstatus: t.status,\n\t\tcontract_id:\n\t\t\tt.contract_call?.contract_id ?? t.smart_contract?.contract_id ?? null,\n\t\tfunction_name: t.contract_call?.function_name ?? null,\n\t\t// Raw hex ClarityValues — the runner decodes them via its own deserializeCV\n\t\t// path, identical to the DB tap.\n\t\tfunction_args: t.contract_call?.function_args_hex ?? [],\n\t\traw_result: t.contract_call?.result_hex ?? null,\n\t\traw_tx: \"\",\n\t\tcreated_at: new Date(0),\n\t} as Transaction;\n}\n\nexport function reconstructEvent(e: IndexEventRow): Event {\n\tconst base = {\n\t\t// Synthetic, deterministic id. The runtime only reads `id` for error logs\n\t\t// and the `*`-wildcard payload (which is streams-index-ineligible).\n\t\tid: `${e.tx_id}#${e.event_index}`,\n\t\ttx_id: e.tx_id,\n\t\tblock_height: e.block_height,\n\t\tevent_index: e.event_index,\n\t\tcreated_at: new Date(0),\n\t};\n\n\tswitch (e.event_type) {\n\t\tcase \"ft_transfer\":\n\t\tcase \"ft_mint\":\n\t\tcase \"ft_burn\":\n\t\t\treturn {\n\t\t\t\t...base,\n\t\t\t\ttype: `${e.event_type}_event`,\n\t\t\t\tdata: {\n\t\t\t\t\tasset_identifier: e.asset_identifier,\n\t\t\t\t\tsender: e.sender,\n\t\t\t\t\trecipient: e.recipient,\n\t\t\t\t\tamount: e.amount,\n\t\t\t\t},\n\t\t\t} as Event;\n\n\t\tcase \"nft_transfer\":\n\t\tcase \"nft_mint\":\n\t\tcase \"nft_burn\":\n\t\t\treturn {\n\t\t\t\t...base,\n\t\t\t\ttype: `${e.event_type}_event`,\n\t\t\t\tdata: {\n\t\t\t\t\tasset_identifier: e.asset_identifier,\n\t\t\t\t\tsender: e.sender,\n\t\t\t\t\trecipient: e.recipient,\n\t\t\t\t\t// Canonical hex → runner decodes tokenId from raw_value.\n\t\t\t\t\traw_value: e.value,\n\t\t\t\t},\n\t\t\t} as Event;\n\n\t\tcase \"stx_transfer\":\n\t\tcase \"stx_mint\":\n\t\tcase \"stx_burn\":\n\t\t\treturn {\n\t\t\t\t...base,\n\t\t\t\ttype: `${e.event_type}_event`,\n\t\t\t\tdata: {\n\t\t\t\t\tsender: e.sender,\n\t\t\t\t\trecipient: e.recipient,\n\t\t\t\t\tamount: e.amount,\n\t\t\t\t\t// Raw stx_transfer always carries memo (\"\" when empty); Index\n\t\t\t\t\t// returns null for empty — default to \"\" to match the DB tap.\n\t\t\t\t\t...(e.event_type === \"stx_transfer\" ? { memo: e.memo ?? \"\" } : {}),\n\t\t\t\t},\n\t\t\t} as Event;\n\n\t\tcase \"stx_lock\":\n\t\t\treturn {\n\t\t\t\t...base,\n\t\t\t\ttype: \"stx_lock_event\",\n\t\t\t\tdata: {\n\t\t\t\t\tlocked_address: e.sender,\n\t\t\t\t\tlocked_amount: e.amount,\n\t\t\t\t\tunlock_height: e.payload.unlock_height,\n\t\t\t\t},\n\t\t\t} as Event;\n\n\t\tcase \"print\":\n\t\t\treturn {\n\t\t\t\t...base,\n\t\t\t\ttype: \"contract_event\",\n\t\t\t\tdata: {\n\t\t\t\t\ttopic: e.payload.topic,\n\t\t\t\t\t// Matcher + runner read `contract_identifier` (the raw node field).\n\t\t\t\t\tcontract_identifier: e.contract_id,\n\t\t\t\t\tvalue: e.payload.value,\n\t\t\t\t\traw_value: e.payload.raw_value,\n\t\t\t\t},\n\t\t\t} as Event;\n\t}\n}\n",
|
|
11
|
+
"import type {\n\tDatabase,\n\tInsertSubscriptionOutbox,\n\tSubscription,\n} from \"@secondlayer/shared/db\";\nimport { resolveTraitContractIds } from \"@secondlayer/shared/db/queries/contracts\";\nimport type { ChainTrigger } from \"@secondlayer/shared/schemas/subscriptions\";\nimport type { Kysely } from \"kysely\";\nimport type { SubgraphFilter } from \"../types.ts\";\nimport type { BlockData } from \"./batch-loader.ts\";\nimport { indexEventTypesForFilterTypes } from \"./block-source.ts\";\nimport {\n\ttype MatchedTx,\n\ttype TraitContracts,\n\tmatchSources,\n} from \"./source-matcher.ts\";\n\n/** Trigger types that match a whole transaction (not an individual event). */\nconst TX_LEVEL_TRIGGER_TYPES = new Set([\"contract_call\", \"contract_deploy\"]);\n\n/**\n * Pure matching core for direct chain-level subscriptions. A single evaluator\n * loop serves ALL chain subscriptions: it reads canonical blocks off the public\n * Index/Streams clock (via `PublicApiBlockSource`), runs the same\n * `matchSources` engine the subgraph runtime uses, and routes matches back to\n * the originating subscription. Everything here is pure/sync (DB only for trait\n * resolution) so it's trivially testable.\n *\n * Source keys are `\"{subscriptionId}#{triggerIndex}\"` — `matchSources` echoes\n * the key as `MatchedTx.sourceName`, letting the emitter recover which\n * subscription (and which trigger) matched. `keyMeta` carries the readable\n * trigger type for the outbox `event_type` / payload.\n */\n\nexport interface TriggerKeyMeta {\n\tsubscriptionId: string;\n\ttriggerIndex: number;\n\ttriggerType: ChainTrigger[\"type\"];\n}\n\nexport interface ChainSourcesMap {\n\tsources: Record<string, SubgraphFilter>;\n\tkeyMeta: Map<string, TriggerKeyMeta>;\n}\n\nfunction sourceKey(subscriptionId: string, triggerIndex: number): string {\n\treturn `${subscriptionId}#${triggerIndex}`;\n}\n\nfunction toAmount(v: string | number | undefined): bigint | undefined {\n\treturn v === undefined ? undefined : BigInt(v);\n}\n\n/**\n * Convert a stored `ChainTrigger` (JSON; amounts as string/number) to the\n * runtime `SubgraphFilter` the matcher expects (amounts as bigint). Field names\n * are identical across the two shapes, so this is a copy plus amount coercion.\n */\nexport function chainTriggerToFilter(trigger: ChainTrigger): SubgraphFilter {\n\tconst t = trigger as ChainTrigger & {\n\t\tminAmount?: string | number;\n\t\tmaxAmount?: string | number;\n\t};\n\t// Spread copies all set keys; amounts (string|number) are then overwritten\n\t// with bigint where present. An absent optional amount isn't in the spread,\n\t// so there's nothing to strip.\n\tconst filter = { ...trigger } as Record<string, unknown>;\n\tconst minAmount = toAmount(t.minAmount);\n\tconst maxAmount = toAmount(t.maxAmount);\n\tif (minAmount !== undefined) filter.minAmount = minAmount;\n\tif (maxAmount !== undefined) filter.maxAmount = maxAmount;\n\treturn filter as unknown as SubgraphFilter;\n}\n\nfunction triggersOf(sub: Subscription): ChainTrigger[] {\n\treturn (sub.triggers ?? []) as ChainTrigger[];\n}\n\n/** Build the `matchSources` input from every active chain subscription. */\nexport function buildSourcesMap(chainSubs: Subscription[]): ChainSourcesMap {\n\tconst sources: Record<string, SubgraphFilter> = {};\n\tconst keyMeta = new Map<string, TriggerKeyMeta>();\n\tfor (const sub of chainSubs) {\n\t\ttriggersOf(sub).forEach((trigger, triggerIndex) => {\n\t\t\tconst key = sourceKey(sub.id, triggerIndex);\n\t\t\tsources[key] = chainTriggerToFilter(trigger);\n\t\t\tkeyMeta.set(key, {\n\t\t\t\tsubscriptionId: sub.id,\n\t\t\t\ttriggerIndex,\n\t\t\t\ttriggerType: trigger.type,\n\t\t\t});\n\t\t});\n\t}\n\treturn { sources, keyMeta };\n}\n\n/** The Index event types the loader must fetch to satisfy all chain triggers. */\nexport function referencedEventTypes(chainSubs: Subscription[]): string[] {\n\tconst filterTypes = new Set<string>();\n\tfor (const sub of chainSubs) {\n\t\tfor (const trigger of triggersOf(sub)) filterTypes.add(trigger.type);\n\t}\n\treturn indexEventTypesForFilterTypes([...filterTypes]);\n}\n\n/** Distinct traits referenced across all chain triggers. */\nexport function referencedTraits(chainSubs: Subscription[]): string[] {\n\tconst traits = new Set<string>();\n\tfor (const sub of chainSubs) {\n\t\tfor (const trigger of triggersOf(sub)) {\n\t\t\tconst trait = (trigger as { trait?: string }).trait;\n\t\t\tif (trait) traits.add(trait);\n\t\t}\n\t}\n\treturn [...traits];\n}\n\n/**\n * Resolve each referenced trait to its conforming contract-id set as of\n * `asOfBlock`, from the contract registry (`CONTRACT_REGISTRY_ENABLED` populates\n * it). Empty map when no trigger is trait-scoped → no DB work. Membership only\n * grows, so the evaluator resolves this once per batch, not per block.\n */\nexport async function buildTraitContracts(\n\tdb: Kysely<Database>,\n\tchainSubs: Subscription[],\n\tasOfBlock: number,\n): Promise<TraitContracts> {\n\tconst resolved: TraitContracts = new Map();\n\tfor (const trait of referencedTraits(chainSubs)) {\n\t\tconst ids = await resolveTraitContractIds(db, trait, asOfBlock);\n\t\tresolved.set(trait, new Set(ids));\n\t}\n\treturn resolved;\n}\n\n/** Run the matcher for one block. Thin wrapper for symmetry/testability. */\nexport function evaluateBlock(\n\tblock: BlockData,\n\tsources: Record<string, SubgraphFilter>,\n\ttraitContracts: TraitContracts,\n): MatchedTx[] {\n\treturn matchSources(sources, block.txs, block.events, traitContracts);\n}\n\n// ── Outbox emission ─────────────────────────────────────────────────────────\n\n/** Apply-envelope delivery payload (`action:'apply'`). Reorg emits a matching\n * `rollback` envelope; see `handleChainReorg`. */\ninterface ApplyEnvelope {\n\taction: \"apply\";\n\tblock_hash: string;\n\tblock_height: number;\n\ttx_id: string;\n\tcanonical: true;\n\ttrigger: ChainTrigger[\"type\"];\n\tevent: Record<string, unknown>;\n}\n\n/**\n * Stable dedup identity for a chain delivery — (subscription, tx, event,\n * block_hash). A tx-level match (contract_call/deploy) has no event, so\n * `eventIndex = -1`. `block_hash` is included so a tx that survives a reorg\n * (same tx_id, NEW canonical block) re-delivers an `apply` after its rollback,\n * instead of being suppressed forever; re-processing the SAME canonical block is\n * still idempotent (same hash → same key).\n */\nfunction chainDedupKey(\n\tsubscriptionId: string,\n\ttxId: string,\n\teventIndex: number,\n\tblockHash: string,\n\treplayId?: string,\n): string {\n\tconst base = `chain:${subscriptionId}:${txId}:${eventIndex}:${blockHash}`;\n\t// Replay keys are namespaced so a re-delivery doesn't collide with the\n\t// already-emitted live apply row (whose outbox entry may be long gone), while\n\t// re-running the SAME replay range stays idempotent (same replayId → same key).\n\treturn replayId ? `replay:${replayId}:${base}` : base;\n}\n\nfunction applyRow(\n\tmeta: TriggerKeyMeta,\n\tblockHeight: number,\n\tblockHash: string,\n\ttxId: string,\n\teventIndex: number,\n\tevent: Record<string, unknown>,\n\treplayId?: string,\n): InsertSubscriptionOutbox {\n\tconst payload: ApplyEnvelope = {\n\t\taction: \"apply\",\n\t\tblock_hash: blockHash,\n\t\tblock_height: blockHeight,\n\t\ttx_id: txId,\n\t\tcanonical: true,\n\t\ttrigger: meta.triggerType,\n\t\tevent,\n\t};\n\treturn {\n\t\tsubscription_id: meta.subscriptionId,\n\t\tkind: \"chain\",\n\t\tsubgraph_name: null,\n\t\ttable_name: null,\n\t\tblock_height: blockHeight,\n\t\ttx_id: txId,\n\t\trow_pk: { tx_id: txId, event_index: eventIndex },\n\t\tevent_type: `chain.${meta.triggerType}.apply`,\n\t\tpayload,\n\t\tdedup_key: chainDedupKey(\n\t\t\tmeta.subscriptionId,\n\t\t\ttxId,\n\t\t\teventIndex,\n\t\t\tblockHash,\n\t\t\treplayId,\n\t\t),\n\t\t...(replayId ? { is_replay: true } : {}),\n\t};\n}\n\n/**\n * Turn one block's matches into `subscription_outbox` rows (apply envelope). For\n * tx-level triggers (contract_call/deploy) we emit ONE row per matched tx\n * (`event_index = -1`); for event-level triggers, one row per matched event.\n * The `(subscription_id, dedup_key)` unique constraint makes re-processing a\n * block idempotent, so the emitter never double-delivers. Returns rows written.\n */\nexport async function emitChainOutbox(\n\tdb: Kysely<Database>,\n\tmatches: MatchedTx[],\n\tkeyMeta: Map<string, TriggerKeyMeta>,\n\tblockHeight: number,\n\tblockHash: string,\n\topts?: { replayId?: string },\n): Promise<number> {\n\tconst replayId = opts?.replayId;\n\tconst rows: InsertSubscriptionOutbox[] = [];\n\tfor (const match of matches) {\n\t\tconst meta = keyMeta.get(match.sourceName);\n\t\tif (!meta) continue;\n\t\tconst txId = match.tx.tx_id;\n\t\tif (TX_LEVEL_TRIGGER_TYPES.has(meta.triggerType)) {\n\t\t\trows.push(\n\t\t\t\tapplyRow(\n\t\t\t\t\tmeta,\n\t\t\t\t\tblockHeight,\n\t\t\t\t\tblockHash,\n\t\t\t\t\ttxId,\n\t\t\t\t\t-1,\n\t\t\t\t\t{\n\t\t\t\t\t\ttx_id: txId,\n\t\t\t\t\t\ttype: match.tx.type,\n\t\t\t\t\t\tsender: match.tx.sender,\n\t\t\t\t\t\tstatus: match.tx.status,\n\t\t\t\t\t\tcontract_id: match.tx.contract_id ?? null,\n\t\t\t\t\t\tfunction_name: match.tx.function_name ?? null,\n\t\t\t\t\t\tfunction_args: match.tx.function_args ?? null,\n\t\t\t\t\t\tresult_hex: match.tx.raw_result ?? null,\n\t\t\t\t\t},\n\t\t\t\t\treplayId,\n\t\t\t\t),\n\t\t\t);\n\t\t} else {\n\t\t\tfor (const event of match.events) {\n\t\t\t\trows.push(\n\t\t\t\t\tapplyRow(\n\t\t\t\t\t\tmeta,\n\t\t\t\t\t\tblockHeight,\n\t\t\t\t\t\tblockHash,\n\t\t\t\t\t\ttxId,\n\t\t\t\t\t\tevent.event_index,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttx_id: txId,\n\t\t\t\t\t\t\ttype: event.type,\n\t\t\t\t\t\t\tevent_index: event.event_index,\n\t\t\t\t\t\t\tdata: event.data,\n\t\t\t\t\t\t},\n\t\t\t\t\t\treplayId,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\tif (rows.length === 0) return 0;\n\t// Net-inserted (not built) so callers count genuinely new deliveries — a\n\t// re-processed block or a re-run replay returns 0.\n\tconst result = await db\n\t\t.insertInto(\"subscription_outbox\")\n\t\t.values(rows)\n\t\t.onConflict((oc) =>\n\t\t\toc.columns([\"subscription_id\", \"dedup_key\"]).doNothing(),\n\t\t)\n\t\t.executeTakeFirst();\n\treturn Number(result.numInsertedOrUpdatedRows ?? 0);\n}\n"
|
|
7
12
|
],
|
|
8
|
-
"mappings": "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",
|
|
9
|
-
"debugId": "
|
|
13
|
+
"mappings": "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",
|
|
14
|
+
"debugId": "5038D6E43C1A22BA64756E2164756E21",
|
|
10
15
|
"names": []
|
|
11
16
|
}
|