@secondlayer/subgraphs 3.26.3 → 4.0.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.
- package/README.md +10 -63
- package/dist/src/index.d.ts +8 -38
- package/dist/src/index.js +70 -174
- package/dist/src/index.js.map +8 -8
- package/dist/src/runtime/block-processor.d.ts +2 -13
- package/dist/src/runtime/block-processor.js +66 -136
- package/dist/src/runtime/block-processor.js.map +5 -5
- package/dist/src/runtime/catchup.d.ts +4 -4
- package/dist/src/runtime/catchup.js +66 -135
- package/dist/src/runtime/catchup.js.map +6 -6
- package/dist/src/runtime/context.d.ts +1 -9
- package/dist/src/runtime/context.js +2 -13
- package/dist/src/runtime/context.js.map +3 -3
- package/dist/src/runtime/processor.js +69 -145
- package/dist/src/runtime/processor.js.map +9 -9
- package/dist/src/runtime/reindex.d.ts +3 -4
- package/dist/src/runtime/reindex.js +66 -135
- package/dist/src/runtime/reindex.js.map +7 -7
- package/dist/src/runtime/reorg.js +69 -141
- package/dist/src/runtime/reorg.js.map +7 -7
- package/dist/src/runtime/runner.d.ts +1 -9
- package/dist/src/runtime/runner.js.map +2 -2
- package/dist/src/schema/index.d.ts +0 -8
- package/dist/src/schema/index.js +4 -38
- package/dist/src/schema/index.js.map +3 -3
- package/dist/src/service.js +69 -145
- package/dist/src/service.js.map +9 -9
- package/dist/src/testing/index.js +3 -14
- package/dist/src/testing/index.js.map +5 -5
- package/package.json +2 -2
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/runtime/context.ts", "../src/schema/generator.ts", "../src/schema/utils.ts", "../src/runtime/chain-read.ts", "../src/runtime/clarity.ts", "../src/runtime/runner.ts", "../src/runtime/print-validate.ts", "../src/testing/index.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import type { Database } from \"@secondlayer/shared/db\";\nimport { logger } from \"@secondlayer/shared/logger\";\nimport { formatUnits } from \"@secondlayer/stacks/utils\";\nimport { type Kysely, type Transaction, sql } from \"kysely\";\nimport { TYPE_MAP, emitJournalDDL } from \"../schema/generator.ts\";\nimport type { ComputedValue, SubgraphSchema } from \"../types.ts\";\n\ntype AnyDb = Kysely<Database> | Transaction<Database>;\n\n/** Reorg journal entries older than this many blocks are prunable — far past\n * Stacks finality (observed reorg depth is single digits). */\nexport const JOURNAL_RETENTION_BLOCKS = 300;\n\n/** Schemas whose `_journal` table existence has been ensured this process.\n * Populated only after a successful flush (a rolled-back CREATE must retry). */\nconst journalEnsured = new Set<string>();\n\ninterface WriteOp {\n\tkind: \"insert\" | \"update\" | \"delete\" | \"increment\";\n\ttable: string;\n\tdata: Record<string, unknown>;\n\t/** For update: SET clause. For increment: column → signed delta. */\n\tset?: Record<string, unknown>;\n}\n\n/**\n * One step of a flush. Most writes are a plain SQL string executed in order.\n * An increment is a PAIR the executor branches on, because closing its\n * lost-update race needs a per-statement rowcount — see\n * {@link SubgraphContext.execStatements} and the rationale on the increment\n * batch in `buildStatements`.\n */\ntype FlushStatement =\n\t| string\n\t| {\n\t\t\tkind: \"increment\";\n\t\t\t/** `UPDATE … SET c = COALESCE(c,0) + δ WHERE <key>` */\n\t\t\tupdate: string;\n\t\t\t/** `INSERT … SELECT … WHERE NOT EXISTS (<key>)` */\n\t\t\tinsert: string;\n\t\t\t/** Key predicate, for the (unreachable-by-design) error message. */\n\t\t\tkeyPred: string;\n\t\t\ttable: string;\n\t };\n\nexport interface FlushWrite {\n\top: \"insert\" | \"update\" | \"delete\";\n\ttable: string;\n\t/** Full row data (for inserts) or where+set merged (for updates). Bigints stringified. */\n\trow: Record<string, unknown>;\n\t/** Stable identifier for dedup — `{blockHeight, txId, rowIndex}` */\n\tpk: { blockHeight: number; txId: string; rowIndex: number };\n}\n\nexport interface FlushManifest {\n\tcount: number;\n\twrites: FlushWrite[];\n}\n\nimport { type ChainReadClient, createChainReadClient } from \"./chain-read.ts\";\n\nexport interface BlockMeta {\n\theight: number;\n\thash: string;\n\ttimestamp: number;\n\tburnBlockHeight: number;\n\t/**\n\t * Nakamoto StacksBlockId — the identifier `?tip=` accepts, and the only way\n\t * to pin a read-only call to THIS block. Null on rows ingested before it\n\t * was persisted; `ctx.client.readOnly` refuses to run rather than silently\n\t * reading at the node's tip.\n\t */\n\tindexBlockHash?: string | null;\n}\n\nexport interface TxMeta {\n\ttxId: string;\n\tsender: string;\n\ttype: string;\n\tstatus: string;\n\tcontractId?: string | null;\n\tfunctionName?: string | null;\n}\n\n/** Validate that a column name is safe for SQL identifiers */\nfunction validateColumnName(name: string): void {\n\tif (!/^[a-z_][a-z0-9_]*$/i.test(name)) {\n\t\tthrow new Error(`Invalid column name: ${name}`);\n\t}\n}\n\n/**\n * Runtime context passed to subgraph handlers.\n * Batches writes and flushes them atomically at the end of a block.\n *\n * Row reads (findOne/findMany) are read-your-writes: they overlay the pending\n * ops queue on the DB state, so a handler observes every write queued earlier\n * in the same block. Without this, accumulator patterns (balance = f(existing))\n * silently lose all but the last same-block delta per row (fix-f040 B1).\n * Aggregate reads (count/sum/min/max) remain pre-flush DB state.\n */\nexport class SubgraphContext {\n\treadonly block: BlockMeta;\n\tprivate _tx: TxMeta;\n\tprivate readonly db: AnyDb;\n\tprivate readonly pgSchemaName: string;\n\tprivate readonly subgraphSchema: SubgraphSchema;\n\t/** Pending writes for this block. `protected` so the in-memory test\n\t * context (`@secondlayer/subgraphs/testing`) can materialize them through\n\t * the SAME overlay this class uses — never a second implementation. */\n\tprotected readonly ops: WriteOp[] = [];\n\t/**\n\t * BYO data plane: handler writes land in a user-owned DB whose flush can't\n\t * share the managed block transaction, so a crash replays the block. When\n\t * set, flush() prepends a replace-per-height DELETE for every inserted table\n\t * (`_block_height = N` → re-INSERT), making block reprocessing idempotent.\n\t * Non-idempotent `update` handlers are rejected at deploy, not here.\n\t */\n\tprivate readonly byo: boolean;\n\t/**\n\t * Record pre-images of keyed mutations into the schema's `_journal` so a\n\t * reorg can restore prior row states (fix-f040 B2). Enabled on the live\n\t * path only — deep reindex/backfill heights are past finality, and the\n\t * journal would just be churn the pruner deletes.\n\t */\n\tprivate readonly journal: boolean;\n\n\t/** Memoized per block; see the `client` getter. */\n\tprotected _client?: ChainReadClient;\n\n\tconstructor(\n\t\tdb: AnyDb,\n\t\tpgSchemaName: string,\n\t\tsubgraphSchema: SubgraphSchema,\n\t\tblock: BlockMeta,\n\t\ttx: TxMeta,\n\t\tbyo = false,\n\t\tjournal = false,\n\t) {\n\t\tthis.db = db;\n\t\tthis.pgSchemaName = pgSchemaName;\n\t\tthis.subgraphSchema = subgraphSchema;\n\t\tthis.block = block;\n\t\tthis._tx = tx;\n\t\tthis.byo = byo;\n\t\tthis.journal = journal;\n\t}\n\n\t/**\n\t * Chain reads pinned to THIS block. Lazily built so a handler that never\n\t * reads never touches the node config, and so the in-memory test context\n\t * can override it without a node.\n\t */\n\tget client(): ChainReadClient {\n\t\tthis._client ??= createChainReadClient({\n\t\t\tblockHeight: this.block.height,\n\t\t\tindexBlockHash: this.block.indexBlockHash,\n\t\t});\n\t\treturn this._client;\n\t}\n\n\tget tx(): TxMeta {\n\t\treturn this._tx;\n\t}\n\n\t/** Update the current transaction context (used by runner between events) */\n\tsetTx(tx: TxMeta): void {\n\t\tthis._tx = tx;\n\t}\n\n\t// --- Write operations (batched) ---\n\n\tinsert(table: string, row: Record<string, unknown>): void {\n\t\tthis.validateTable(table);\n\t\tthis.ops.push({\n\t\t\tkind: \"insert\",\n\t\t\ttable,\n\t\t\tdata: { ...row, _block_height: this.block.height, _tx_id: this._tx.txId },\n\t\t});\n\t}\n\n\tupdate(\n\t\ttable: string,\n\t\twhere: Record<string, unknown>,\n\t\tset: Record<string, unknown>,\n\t): void {\n\t\tthis.validateTable(table);\n\t\tthis.ops.push({ kind: \"update\", table, data: where, set });\n\t}\n\n\tupsert(\n\t\ttable: string,\n\t\tkey: Record<string, unknown>,\n\t\trow: Record<string, unknown>,\n\t): void {\n\t\tthis.validateTable(table);\n\t\tconst tableDef = this.subgraphSchema[table];\n\t\tif (!tableDef) return;\n\t\tconst keyColumns = Object.keys(key);\n\n\t\t// Check if there's a matching uniqueKeys constraint\n\t\tconst hasUniqueConstraint = tableDef.uniqueKeys?.some(\n\t\t\t(uk) =>\n\t\t\t\tuk.length === keyColumns.length &&\n\t\t\t\tuk.every((c) => keyColumns.includes(c)),\n\t\t);\n\n\t\tconst meta = { _block_height: this.block.height, _tx_id: this._tx.txId };\n\n\t\tif (hasUniqueConstraint) {\n\t\t\t// Use ON CONFLICT for proper upsert\n\t\t\tthis.ops.push({\n\t\t\t\tkind: \"insert\",\n\t\t\t\ttable,\n\t\t\t\tdata: { ...key, ...row, ...meta, _upsert_keys: keyColumns },\n\t\t\t});\n\t\t} else {\n\t\t\t// Fallback: log warning, use findOne + conditional insert/update\n\t\t\tlogger.warn(\n\t\t\t\t\"upsert called without matching uniqueKeys constraint, using fallback\",\n\t\t\t\t{\n\t\t\t\t\ttable,\n\t\t\t\t\tkeys: keyColumns,\n\t\t\t\t},\n\t\t\t);\n\t\t\tthis.ops.push({\n\t\t\t\tkind: \"insert\",\n\t\t\t\ttable,\n\t\t\t\tdata: {\n\t\t\t\t\t...key,\n\t\t\t\t\t...row,\n\t\t\t\t\t...meta,\n\t\t\t\t\t_upsert_fallback_keys: keyColumns,\n\t\t\t\t\t_upsert_fallback_set: row,\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t}\n\n\tdelete(table: string, where: Record<string, unknown>): void {\n\t\tthis.validateTable(table);\n\t\tthis.ops.push({ kind: \"delete\", table, data: where });\n\t}\n\n\t/**\n\t * Atomic counter update — the blessed accumulator primitive. Compiles to\n\t * `INSERT ... ON CONFLICT (key) DO UPDATE SET col = COALESCE(t.col,0) + delta`,\n\t * so deltas commute: same-block, replayed-in-order, and concurrent updates\n\t * all land correctly without read-modify-write. Missing row inserts the\n\t * delta as the initial value. Requires a uniqueKeys constraint matching\n\t * `key`; deltas may be negative.\n\t */\n\tincrement(\n\t\ttable: string,\n\t\tkey: Record<string, unknown>,\n\t\tdeltas: Record<string, bigint | number>,\n\t): void {\n\t\tthis.validateTable(table);\n\t\tconst tableDef = this.subgraphSchema[table];\n\t\tconst keyColumns = Object.keys(key);\n\t\tconst hasUniqueConstraint = tableDef?.uniqueKeys?.some(\n\t\t\t(uk) =>\n\t\t\t\tuk.length === keyColumns.length &&\n\t\t\t\tuk.every((c) => keyColumns.includes(c)),\n\t\t);\n\t\tif (!hasUniqueConstraint) {\n\t\t\tthrow new Error(\n\t\t\t\t`increment(\"${table}\") requires a uniqueKeys constraint on [${keyColumns.join(\", \")}]`,\n\t\t\t);\n\t\t}\n\t\tfor (const [col, v] of Object.entries(deltas)) {\n\t\t\tvalidateColumnName(col);\n\t\t\tif (keyColumns.includes(col)) {\n\t\t\t\tthrow new Error(`increment(\"${table}\"): \"${col}\" is a key column`);\n\t\t\t}\n\t\t\tif (typeof v !== \"bigint\" && typeof v !== \"number\") {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`increment(\"${table}\"): delta for \"${col}\" must be bigint or number`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tthis.ops.push({\n\t\t\tkind: \"increment\",\n\t\t\ttable,\n\t\t\tdata: {\n\t\t\t\t...key,\n\t\t\t\t_block_height: this.block.height,\n\t\t\t\t_tx_id: this._tx.txId,\n\t\t\t\t_upsert_keys: keyColumns,\n\t\t\t},\n\t\t\tset: { ...deltas },\n\t\t});\n\t}\n\n\t// --- Ops checkpoint (per-event atomicity) ---\n\n\t/** Current length of the pending-ops queue. Pair with {@link rollbackTo}. */\n\topsCheckpoint(): number {\n\t\treturn this.ops.length;\n\t}\n\n\t/**\n\t * Discard ops queued after a checkpoint. The runner wraps each handler\n\t * invocation so a thrown handler contributes nothing — without this, a\n\t * transfer handler that debited then threw flushes a one-sided debit\n\t * (fix-f040 B6).\n\t */\n\trollbackTo(checkpoint: number): void {\n\t\tif (checkpoint < 0 || checkpoint > this.ops.length) return;\n\t\tthis.ops.length = checkpoint;\n\t}\n\n\t/** Partial update — sets only specified fields, preserves everything else */\n\tpatch(\n\t\ttable: string,\n\t\twhere: Record<string, unknown>,\n\t\tset: Record<string, unknown>,\n\t): void {\n\t\tthis.update(table, where, set);\n\t}\n\n\t/**\n\t * Find-then-merge-or-insert. Values can be functions: (existing) => newValue.\n\t * Async because it reads existing row first.\n\t */\n\tasync patchOrInsert(\n\t\ttable: string,\n\t\tkey: Record<string, unknown>,\n\t\trow: Record<string, ComputedValue>,\n\t): Promise<void> {\n\t\tconst existing = await this.findOne(table, key);\n\t\tconst resolved: Record<string, unknown> = {};\n\t\tfor (const [k, v] of Object.entries(row)) {\n\t\t\tresolved[k] = typeof v === \"function\" ? v(existing) : v;\n\t\t}\n\t\tthis.upsert(table, key, resolved);\n\t}\n\n\t/** Format a bigint amount with decimal places */\n\tformatUnits(value: bigint, decimals: number): string {\n\t\treturn formatUnits(value, decimals);\n\t}\n\n\t// --- Read operations (immediate) ---\n\n\t/**\n\t * Committed rows matching `where`, BEFORE the pending-ops overlay. The one\n\t * seam a different backing store replaces (the in-memory test context);\n\t * everything above it — validation, overlay, op queueing, flush semantics\n\t * — stays here so the two can't diverge.\n\t */\n\tprotected async readRows(\n\t\ttable: string,\n\t\twhere: Record<string, unknown>,\n\t\tlimit?: number,\n\t): Promise<Record<string, unknown>[]> {\n\t\tconst qualifiedTable = `\"${this.pgSchemaName}\".\"${table}\"`;\n\t\tconst { clause } = buildWhereClause(where);\n\t\tconst query = `SELECT * FROM ${qualifiedTable} WHERE ${clause}${\n\t\t\tlimit !== undefined ? ` LIMIT ${limit}` : \"\"\n\t\t}`;\n\t\tconst { rows } = await sql.raw(query).execute(this.db);\n\t\treturn (rows as Record<string, unknown>[]).map((r) =>\n\t\t\tthis.coerceRow(table, r),\n\t\t);\n\t}\n\n\tasync findOne(\n\t\ttable: string,\n\t\twhere: Record<string, unknown>,\n\t): Promise<Record<string, unknown> | null> {\n\t\tthis.validateTable(table);\n\t\tconst row = (await this.readRows(table, where, 1))[0] ?? null;\n\t\treturn this.overlayOne(table, where, row);\n\t}\n\n\tasync findMany(\n\t\ttable: string,\n\t\twhere: Record<string, unknown>,\n\t): Promise<Record<string, unknown>[]> {\n\t\tthis.validateTable(table);\n\t\treturn this.overlayMany(table, where, await this.readRows(table, where));\n\t}\n\n\t// --- Pending-ops overlay (read-your-writes) ---\n\n\t/**\n\t * Replay pending ops for `table` over a single DB-read result so reads\n\t * observe earlier same-block writes. Mirrors flush semantics: upserts\n\t * merge non-key/non-meta columns, increments add deltas, updates/deletes\n\t * apply by where-match. Overlaid rows synthesized from pending inserts\n\t * lack DB-generated columns (_id, _created_at).\n\t */\n\tprotected overlayOne(\n\t\ttable: string,\n\t\twhere: Record<string, unknown>,\n\t\tdbRow: Record<string, unknown> | null,\n\t): Record<string, unknown> | null {\n\t\tif (this.ops.length === 0) return dbRow;\n\t\tlet row = dbRow;\n\t\tfor (const op of this.ops) {\n\t\t\tif (op.table !== table) continue;\n\t\t\trow = this.applyOpToRow(op, row, where);\n\t\t}\n\t\treturn row;\n\t}\n\n\tprotected overlayMany(\n\t\ttable: string,\n\t\twhere: Record<string, unknown>,\n\t\tdbRows: Record<string, unknown>[],\n\t): Record<string, unknown>[] {\n\t\tif (this.ops.length === 0) return [...dbRows];\n\t\tlet result = [...dbRows];\n\t\tfor (const op of this.ops) {\n\t\t\tif (op.table !== table) continue;\n\t\t\tif (op.kind === \"update\") {\n\t\t\t\tfor (let i = 0; i < result.length; i++) {\n\t\t\t\t\t// biome-ignore lint/style/noNonNullAssertion: idx bounds-checked by loop condition\n\t\t\t\t\tif (rowMatches(result[i]!, op.data))\n\t\t\t\t\t\tresult[i] = { ...result[i], ...(op.set ?? {}) };\n\t\t\t\t}\n\t\t\t} else if (op.kind === \"delete\") {\n\t\t\t\tresult = result.filter((r) => !rowMatches(r, op.data));\n\t\t\t} else {\n\t\t\t\t// insert / increment — merge into the keyed row, or append if the\n\t\t\t\t// new row satisfies the filter.\n\t\t\t\tconst upsertKeys = op.data._upsert_keys as string[] | undefined;\n\t\t\t\tconst clean = stripControlKeys(op.data);\n\t\t\t\tconst idx = upsertKeys\n\t\t\t\t\t? result.findIndex((r) =>\n\t\t\t\t\t\t\tupsertKeys.every((k) => valEq(r[k], clean[k])),\n\t\t\t\t\t\t)\n\t\t\t\t\t: -1;\n\t\t\t\tif (idx >= 0) {\n\t\t\t\t\t// biome-ignore lint/style/noNonNullAssertion: idx bounds-checked above\n\t\t\t\t\tconst existing = result[idx]!;\n\t\t\t\t\tresult[idx] = this.applyOpToRow(op, existing, where) ?? existing;\n\t\t\t\t} else {\n\t\t\t\t\tconst created = this.applyOpToRow(op, null, where);\n\t\t\t\t\tif (created) result.push(created);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\t/** Apply one pending op to a candidate row state (null = row absent). */\n\tprotected applyOpToRow(\n\t\top: WriteOp,\n\t\trow: Record<string, unknown> | null,\n\t\twhere: Record<string, unknown>,\n\t): Record<string, unknown> | null {\n\t\tconst upsertKeys = op.data._upsert_keys as string[] | undefined;\n\t\tconst clean = stripControlKeys(op.data);\n\n\t\tswitch (op.kind) {\n\t\t\tcase \"insert\": {\n\t\t\t\tif (row) {\n\t\t\t\t\t// Same entity? Compare on the upsert key — a plain insert (no\n\t\t\t\t\t// key) can never target an existing row.\n\t\t\t\t\tif (upsertKeys?.every((k) => valEq(row[k], clean[k]))) {\n\t\t\t\t\t\t// Mirror ON CONFLICT DO UPDATE: non-key, non-meta cols only.\n\t\t\t\t\t\tconst merged = { ...row };\n\t\t\t\t\t\tfor (const [k, v] of Object.entries(clean)) {\n\t\t\t\t\t\t\tif (!upsertKeys.includes(k) && !k.startsWith(\"_\")) merged[k] = v;\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn merged;\n\t\t\t\t\t}\n\t\t\t\t\treturn row;\n\t\t\t\t}\n\t\t\t\treturn rowMatches(clean, where) ? { ...clean } : null;\n\t\t\t}\n\t\t\tcase \"increment\": {\n\t\t\t\tconst deltas = op.set ?? {};\n\t\t\t\tif (row) {\n\t\t\t\t\t// biome-ignore lint/style/noNonNullAssertion: increment always carries _upsert_keys\n\t\t\t\t\tif (upsertKeys!.every((k) => valEq(row[k], clean[k]))) {\n\t\t\t\t\t\tconst merged = { ...row };\n\t\t\t\t\t\tfor (const [col, d] of Object.entries(deltas)) {\n\t\t\t\t\t\t\tmerged[col] = toBigIntOr0(merged[col]) + toBigIntOr0(d);\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn merged;\n\t\t\t\t\t}\n\t\t\t\t\treturn row;\n\t\t\t\t}\n\t\t\t\tif (!rowMatches(clean, where)) return null;\n\t\t\t\tconst created: Record<string, unknown> = { ...clean };\n\t\t\t\tfor (const [col, d] of Object.entries(deltas)) {\n\t\t\t\t\tcreated[col] = toBigIntOr0(d);\n\t\t\t\t}\n\t\t\t\treturn created;\n\t\t\t}\n\t\t\tcase \"update\":\n\t\t\t\treturn row && rowMatches(row, op.data)\n\t\t\t\t\t? { ...row, ...(op.set ?? {}) }\n\t\t\t\t\t: row;\n\t\t\tcase \"delete\":\n\t\t\t\treturn row && rowMatches(row, op.data) ? null : row;\n\t\t}\n\t}\n\n\t// --- Aggregate reads ---\n\n\tasync count(table: string, where?: Record<string, unknown>): Promise<number> {\n\t\tthis.validateTable(table);\n\t\tconst qualifiedTable = `\"${this.pgSchemaName}\".\"${table}\"`;\n\t\tconst whereClause = where ? `WHERE ${buildWhereClause(where).clause}` : \"\";\n\t\tconst { rows } = await sql\n\t\t\t.raw(\n\t\t\t\t`SELECT COUNT(*)::int AS count FROM ${qualifiedTable} ${whereClause}`,\n\t\t\t)\n\t\t\t.execute(this.db);\n\t\treturn Number((rows as Record<string, unknown>[])[0]?.count ?? 0);\n\t}\n\n\tasync sum(\n\t\ttable: string,\n\t\tcolumn: string,\n\t\twhere?: Record<string, unknown>,\n\t): Promise<bigint> {\n\t\tthis.validateTable(table);\n\t\tvalidateColumnName(column);\n\t\tconst qualifiedTable = `\"${this.pgSchemaName}\".\"${table}\"`;\n\t\tconst whereClause = where ? `WHERE ${buildWhereClause(where).clause}` : \"\";\n\t\tconst { rows } = await sql\n\t\t\t.raw(\n\t\t\t\t`SELECT COALESCE(SUM(\"${column}\"), 0) AS total FROM ${qualifiedTable} ${whereClause}`,\n\t\t\t)\n\t\t\t.execute(this.db);\n\t\treturn BigInt(\n\t\t\t(rows as Record<string, unknown>[])[0]?.total?.toString() ?? \"0\",\n\t\t);\n\t}\n\n\tasync min(\n\t\ttable: string,\n\t\tcolumn: string,\n\t\twhere?: Record<string, unknown>,\n\t): Promise<bigint | null> {\n\t\tthis.validateTable(table);\n\t\tvalidateColumnName(column);\n\t\tconst qualifiedTable = `\"${this.pgSchemaName}\".\"${table}\"`;\n\t\tconst whereClause = where ? `WHERE ${buildWhereClause(where).clause}` : \"\";\n\t\tconst { rows } = await sql\n\t\t\t.raw(\n\t\t\t\t`SELECT MIN(\"${column}\") AS val FROM ${qualifiedTable} ${whereClause}`,\n\t\t\t)\n\t\t\t.execute(this.db);\n\t\tconst val = (rows as Record<string, unknown>[])[0]?.val;\n\t\treturn val != null ? BigInt(val.toString()) : null;\n\t}\n\n\tasync max(\n\t\ttable: string,\n\t\tcolumn: string,\n\t\twhere?: Record<string, unknown>,\n\t): Promise<bigint | null> {\n\t\tthis.validateTable(table);\n\t\tvalidateColumnName(column);\n\t\tconst qualifiedTable = `\"${this.pgSchemaName}\".\"${table}\"`;\n\t\tconst whereClause = where ? `WHERE ${buildWhereClause(where).clause}` : \"\";\n\t\tconst { rows } = await sql\n\t\t\t.raw(\n\t\t\t\t`SELECT MAX(\"${column}\") AS val FROM ${qualifiedTable} ${whereClause}`,\n\t\t\t)\n\t\t\t.execute(this.db);\n\t\tconst val = (rows as Record<string, unknown>[])[0]?.val;\n\t\treturn val != null ? BigInt(val.toString()) : null;\n\t}\n\n\tasync countDistinct(\n\t\ttable: string,\n\t\tcolumn: string,\n\t\twhere?: Record<string, unknown>,\n\t): Promise<number> {\n\t\tthis.validateTable(table);\n\t\tvalidateColumnName(column);\n\t\tconst qualifiedTable = `\"${this.pgSchemaName}\".\"${table}\"`;\n\t\tconst whereClause = where ? `WHERE ${buildWhereClause(where).clause}` : \"\";\n\t\tconst { rows } = await sql\n\t\t\t.raw(\n\t\t\t\t`SELECT COUNT(DISTINCT \"${column}\")::int AS count FROM ${qualifiedTable} ${whereClause}`,\n\t\t\t)\n\t\t\t.execute(this.db);\n\t\treturn Number((rows as Record<string, unknown>[])[0]?.count ?? 0);\n\t}\n\n\t/** Coerce string values from Postgres back to BigInt for uint/int columns */\n\tprivate coerceRow(\n\t\ttable: string,\n\t\trow: Record<string, unknown>,\n\t): Record<string, unknown> {\n\t\tconst tableDef = this.subgraphSchema[table];\n\t\tif (!tableDef) return row;\n\t\tconst result = { ...row };\n\t\tfor (const [col, def] of Object.entries(tableDef.columns)) {\n\t\t\tif (\n\t\t\t\t(def.type === \"uint\" || def.type === \"int\") &&\n\t\t\t\ttypeof result[col] === \"string\"\n\t\t\t) {\n\t\t\t\tresult[col] = BigInt(result[col] as string);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\t// --- Flush ---\n\n\t/** Number of pending write operations */\n\tget pendingOps(): number {\n\t\treturn this.ops.length;\n\t}\n\n\t/**\n\t * Execute all batched writes in a single transaction.\n\t * Auto-populates _block_height, _tx_id, _created_at on inserts.\n\t *\n\t * Returns a {@link FlushManifest} describing every write so downstream\n\t * consumers (subscription emitter) can fan out outbox rows atomically\n\t * with the flush itself.\n\t */\n\tasync flush(): Promise<FlushManifest> {\n\t\tif (this.ops.length === 0) return { count: 0, writes: [] };\n\n\t\tawait this.ensureJournalTable();\n\n\t\tconst opsToFlush = [...this.ops];\n\t\tthis.ops.length = 0;\n\n\t\tconst statements = this.buildStatements(opsToFlush);\n\n\t\tif (\"isTransaction\" in this.db) {\n\t\t\tawait this.execStatements(this.db, statements);\n\t\t} else {\n\t\t\tawait (this.db as Kysely<Database>).transaction().execute(async (tx) => {\n\t\t\t\tawait this.execStatements(tx, statements);\n\t\t\t});\n\t\t}\n\n\t\tconst writes: FlushWrite[] = opsToFlush.map((op, rowIndex) => {\n\t\t\tconst blockHeight =\n\t\t\t\t(op.data._block_height as number | undefined) ?? this.block.height;\n\t\t\tconst txId = (op.data._tx_id as string | undefined) ?? this._tx.txId;\n\t\t\tconst baseRow =\n\t\t\t\top.kind === \"update\" || op.kind === \"increment\"\n\t\t\t\t\t? { ...op.data, ...(op.set ?? {}) }\n\t\t\t\t\t: { ...op.data };\n\t\t\t// Strip upsert control keys — not part of the row shape\n\t\t\t(baseRow as Record<string, unknown>)._upsert_keys = undefined;\n\t\t\t(baseRow as Record<string, unknown>)._upsert_fallback_keys = undefined;\n\t\t\t(baseRow as Record<string, unknown>)._upsert_fallback_set = undefined;\n\t\t\treturn {\n\t\t\t\t// Increments surface as \"updated\" to subscribers — the row payload\n\t\t\t\t// carries the key + the applied delta, not the absolute value.\n\t\t\t\top: op.kind === \"increment\" ? \"update\" : op.kind,\n\t\t\t\ttable: op.table,\n\t\t\t\trow: jsonSafe(baseRow),\n\t\t\t\tpk: { blockHeight, txId, rowIndex },\n\t\t\t};\n\t\t});\n\n\t\treturn { count: opsToFlush.length, writes };\n\t}\n\n\t/**\n\t * Run a built statement list on an open transaction.\n\t *\n\t * Plain statements run in order. An increment runs UPDATE-first and then,\n\t * ONLY if that matched nothing, the guarded INSERT — and if the INSERT also\n\t * wrote nothing, the UPDATE again.\n\t *\n\t * That last step is the whole point. Under READ COMMITTED, two block\n\t * transactions flushing the same key while the row is absent both see\n\t * `UPDATE → 0 rows`; the first commits its INSERT, and the second's\n\t * `WHERE NOT EXISTS` then sees that committed row and inserts nothing. No\n\t * error, no constraint violation — the second delta was simply dropped.\n\t * Re-running the UPDATE takes a fresh snapshot that DOES see the winner's\n\t * row and applies the delta onto it.\n\t *\n\t * It cannot double-apply: the retry is reached only when the first UPDATE\n\t * matched no row AND the INSERT wrote no row, so the delta has not been\n\t * applied by either.\n\t */\n\tprivate async execStatements(\n\t\texecutor: AnyDb,\n\t\tstatements: FlushStatement[],\n\t): Promise<void> {\n\t\tconst affected = (r: { numAffectedRows?: bigint }): bigint =>\n\t\t\tr.numAffectedRows ?? 0n;\n\n\t\tfor (const stmt of statements) {\n\t\t\tif (typeof stmt === \"string\") {\n\t\t\t\tawait sql.raw(stmt).execute(executor);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst updated = await sql.raw(stmt.update).execute(executor);\n\t\t\tif (affected(updated) > 0n) continue;\n\n\t\t\tconst inserted = await sql.raw(stmt.insert).execute(executor);\n\t\t\tif (affected(inserted) > 0n) continue;\n\n\t\t\tconst retried = await sql.raw(stmt.update).execute(executor);\n\t\t\tif (affected(retried) === 0n) {\n\t\t\t\t// Neither wrote: the row a concurrent writer created was gone again\n\t\t\t\t// by the retry (a delete raced in). Fail loudly — silently dropping\n\t\t\t\t// the delta is the bug this whole path exists to prevent. The block\n\t\t\t\t// transaction rolls back and the walk re-processes it.\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`increment could not be applied to ${this.pgSchemaName}.${stmt.table} where ${stmt.keyPred}: row neither updated nor inserted`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Prepare a single insert row, returning its data, columns, upsert key for batching. */\n\tprivate prepareInsert(op: WriteOp): {\n\t\tdata: Record<string, unknown>;\n\t\tcols: string[];\n\t\tvals: string[];\n\t\tupsertKeys: string[] | undefined;\n\t\tbatchKey: string;\n\t} {\n\t\tconst upsertKeys = op.data._upsert_keys as string[] | undefined;\n\t\tconst data = { ...op.data };\n\t\t// biome-ignore lint/performance/noDelete: must remove key, not set undefined — Object.keys must not include these\n\t\tdelete data._upsert_keys;\n\t\t// biome-ignore lint/performance/noDelete: same as above\n\t\tdelete data._upsert_fallback_keys;\n\t\t// biome-ignore lint/performance/noDelete: same as above\n\t\tdelete data._upsert_fallback_set;\n\n\t\t// _block_height and _tx_id are captured at insert/upsert time (not flush time)\n\t\t// to ensure correct tx attribution when multiple txs are batched per block\n\t\tif (!data._block_height) data._block_height = this.block.height;\n\t\tif (!data._tx_id) data._tx_id = this._tx.txId;\n\t\tdata._created_at = \"NOW()\";\n\n\t\tconst cols = Object.keys(data);\n\t\tcols.forEach(validateColumnName);\n\t\tconst vals = cols.map((c) =>\n\t\t\tdata[c] === \"NOW()\" ? \"NOW()\" : escapeLiteral(data[c]),\n\t\t);\n\n\t\t// Batch key: table + sorted columns + upsert key signature (spread to avoid mutating cols)\n\t\tconst batchKey = `${op.table}:${[...cols].sort().join(\",\")}:${upsertKeys ? [...upsertKeys].sort().join(\",\") : \"\"}`;\n\n\t\treturn { data, cols, vals, upsertKeys, batchKey };\n\t}\n\n\t/**\n\t * Lazily create `_journal` for schemas deployed before it existed. Cached\n\t * per process only once CONFIRMED present (to_regclass) — a CREATE issued\n\t * inside a block tx could roll back with it, so self-created tables are\n\t * re-verified on the next flush instead of trusted.\n\t */\n\tprivate async ensureJournalTable(): Promise<void> {\n\t\tif (!this.journal || journalEnsured.has(this.pgSchemaName)) return;\n\t\tconst { rows } = await sql\n\t\t\t.raw(`SELECT to_regclass('\"${this.pgSchemaName}\".\"_journal\"') AS r`)\n\t\t\t.execute(this.db);\n\t\tif ((rows as { r: unknown }[])[0]?.r) {\n\t\t\tjournalEnsured.add(this.pgSchemaName);\n\t\t\treturn;\n\t\t}\n\t\t// Schema names are generator-produced lowercase identifiers, so the\n\t\t// unquoted form emitJournalDDL emits is safe.\n\t\tfor (const stmt of emitJournalDDL(this.pgSchemaName)) {\n\t\t\tawait sql.raw(stmt).execute(this.db);\n\t\t}\n\t}\n\n\t/** SQL type of a user column (for casting journal key VALUES), if known. */\n\tprivate columnSqlType(table: string, col: string): string | undefined {\n\t\tconst def = this.subgraphSchema[table]?.columns?.[col];\n\t\treturn def ? TYPE_MAP[def.type] : undefined;\n\t}\n\n\t/**\n\t * Journal pre-images for a keyed batch: one `_journal` row per key with the\n\t * row's current state (`prev_row`), or NULL when the key doesn't exist yet\n\t * (the mutation will create it — a revert deletes it). Emitted BEFORE the\n\t * mutation statement, same transaction.\n\t */\n\tprivate journalCaptureSQL(\n\t\ttable: string,\n\t\tkeyCols: string[],\n\t\t/** One escaped-literal tuple per key, ordered like keyCols. */\n\t\tkeyLiteralRows: string[][],\n\t): string {\n\t\tconst cast = (col: string, expr: string) => {\n\t\t\tconst t = this.columnSqlType(table, col);\n\t\t\treturn t ? `CAST(${expr} AS ${t})` : expr;\n\t\t};\n\t\tconst keyObj = keyCols\n\t\t\t.map((k) => `'${k}', ${cast(k, `v.\"${k}\"`)}`)\n\t\t\t.join(\", \");\n\t\tconst joinCond = keyCols\n\t\t\t.map((k) => `t.\"${k}\" = ${cast(k, `v.\"${k}\"`)}`)\n\t\t\t.join(\" AND \");\n\t\tconst valuesList = keyLiteralRows\n\t\t\t.map((r) => `(${r.join(\", \")})`)\n\t\t\t.join(\", \");\n\t\treturn (\n\t\t\t`INSERT INTO \"${this.pgSchemaName}\".\"_journal\" (\"block_height\", \"table_name\", \"row_key\", \"prev_row\") ` +\n\t\t\t`SELECT ${this.block.height}, '${table}', jsonb_build_object(${keyObj}), to_jsonb(t.*) ` +\n\t\t\t`FROM (VALUES ${valuesList}) AS v(${keyCols.map((k) => `\"${k}\"`).join(\", \")}) ` +\n\t\t\t`LEFT JOIN \"${this.pgSchemaName}\".\"${table}\" t ON ${joinCond}`\n\t\t);\n\t}\n\n\t/** Journal pre-images of rows a where-clause mutation will touch, keyed by `_id`. */\n\tprivate journalCaptureByWhereSQL(table: string, clause: string): string {\n\t\treturn (\n\t\t\t`INSERT INTO \"${this.pgSchemaName}\".\"_journal\" (\"block_height\", \"table_name\", \"row_key\", \"prev_row\") ` +\n\t\t\t`SELECT ${this.block.height}, '${table}', jsonb_build_object('_id', t.\"_id\"), to_jsonb(t.*) ` +\n\t\t\t`FROM \"${this.pgSchemaName}\".\"${table}\" t WHERE ${clause}`\n\t\t);\n\t}\n\n\t/** Build SQL statements from write ops, batching compatible INSERTs. */\n\tprivate buildStatements(ops: WriteOp[]): FlushStatement[] {\n\t\tconst statements: FlushStatement[] = [];\n\n\t\t// BYO replace-per-height: clear this block's prior inserts before\n\t\t// re-inserting so a replayed block (no cross-DB tx) stays idempotent.\n\t\t// One DELETE per distinct inserted table; upserts/updates self-heal.\n\t\tif (this.byo) {\n\t\t\tconst insertTables = new Set<string>();\n\t\t\tfor (const op of ops)\n\t\t\t\tif (op.kind === \"insert\") insertTables.add(op.table);\n\t\t\tfor (const table of insertTables) {\n\t\t\t\tstatements.push(\n\t\t\t\t\t`DELETE FROM \"${this.pgSchemaName}\".\"${table}\" WHERE \"_block_height\" = ${this.block.height}`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// Group consecutive inserts by batch key\n\t\ttype InsertBatch = {\n\t\t\ttable: string;\n\t\t\tcols: string[];\n\t\t\trows: string[][];\n\t\t\tupsertKeys: string[] | undefined;\n\t\t};\n\n\t\t// Consecutive increments on the same (table, key cols, delta cols)\n\t\t// coalesce: same-key deltas SUM (they commute), then compile to one\n\t\t// multi-row INSERT ... ON CONFLICT DO UPDATE SET c = COALESCE(c,0)+EXCLUDED.c.\n\t\ttype IncrementBatch = {\n\t\t\ttable: string;\n\t\t\tkeyCols: string[];\n\t\t\tdeltaCols: string[];\n\t\t\t/** key signature → { key values, summed deltas, insert-time meta } */\n\t\t\trows: Map<\n\t\t\t\tstring,\n\t\t\t\t{\n\t\t\t\t\tkeys: Record<string, unknown>;\n\t\t\t\t\tdeltas: Record<string, bigint>;\n\t\t\t\t\tmeta: { blockHeight: unknown; txId: unknown };\n\t\t\t\t}\n\t\t\t>;\n\t\t};\n\n\t\tlet currentBatch: InsertBatch | null = null;\n\t\tlet currentBatchKey = \"\";\n\t\tlet incBatch: IncrementBatch | null = null;\n\t\tlet incBatchKey = \"\";\n\n\t\tconst flushIncrementBatch = () => {\n\t\t\tif (!incBatch) return;\n\t\t\tconst batch = incBatch;\n\t\t\tconst qualifiedTable = `\"${this.pgSchemaName}\".\"${batch.table}\"`;\n\t\t\tconst cols = [\n\t\t\t\t...batch.keyCols,\n\t\t\t\t...batch.deltaCols,\n\t\t\t\t\"_block_height\",\n\t\t\t\t\"_tx_id\",\n\t\t\t\t\"_created_at\",\n\t\t\t];\n\t\t\tif (this.journal) {\n\t\t\t\tstatements.push(\n\t\t\t\t\tthis.journalCaptureSQL(\n\t\t\t\t\t\tbatch.table,\n\t\t\t\t\t\tbatch.keyCols,\n\t\t\t\t\t\tArray.from(batch.rows.values()).map((r) =>\n\t\t\t\t\t\t\tbatch.keyCols.map((k) => escapeLiteral(r.keys[k])),\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t\t// NOT insert-on-conflict: Postgres validates the PROPOSED insert\n\t\t\t// tuple against CHECK constraints BEFORE conflict arbitration, so a\n\t\t\t// negative delta against an EXISTING row (every debit on a uint\n\t\t\t// balance) errors even though DO UPDATE would produce a legal value\n\t\t\t// (prod halts at sbtc 341445 / usdcx 5269728; empirically verified).\n\t\t\t// UPDATE-first lets the CHECK see the FINAL value; the guarded\n\t\t\t// INSERT covers missing rows — where a negative delta is a GENUINE\n\t\t\t// violation and must still fail loudly.\n\t\t\t//\n\t\t\t// The pair is emitted as ONE step rather than two statements because\n\t\t\t// the executor must branch on their rowcounts: an INSERT that wrote\n\t\t\t// nothing means a concurrent transaction created the row after our\n\t\t\t// UPDATE missed it, and the delta has to be re-applied instead of\n\t\t\t// silently dropped. See `execStatements`.\n\t\t\tfor (const r of batch.rows.values()) {\n\t\t\t\tconst keyPred = batch.keyCols\n\t\t\t\t\t.map((k) => `\"${k}\" = ${escapeLiteral(r.keys[k])}`)\n\t\t\t\t\t.join(\" AND \");\n\t\t\t\tconst updSet = batch.deltaCols\n\t\t\t\t\t.map(\n\t\t\t\t\t\t(c) =>\n\t\t\t\t\t\t\t`\"${c}\" = COALESCE(\"${c}\", 0) + (${String(r.deltas[c] ?? 0n)})`,\n\t\t\t\t\t)\n\t\t\t\t\t.join(\", \");\n\t\t\t\tconst insertVals = [\n\t\t\t\t\t...batch.keyCols.map((k) => escapeLiteral(r.keys[k])),\n\t\t\t\t\t...batch.deltaCols.map((c) => String(r.deltas[c] ?? 0n)),\n\t\t\t\t\tescapeLiteral(r.meta.blockHeight),\n\t\t\t\t\tescapeLiteral(r.meta.txId),\n\t\t\t\t\t\"NOW()\",\n\t\t\t\t];\n\t\t\t\tstatements.push({\n\t\t\t\t\tkind: \"increment\",\n\t\t\t\t\ttable: batch.table,\n\t\t\t\t\tkeyPred,\n\t\t\t\t\tupdate: `UPDATE ${qualifiedTable} SET ${updSet} WHERE ${keyPred}`,\n\t\t\t\t\tinsert:\n\t\t\t\t\t\t`INSERT INTO ${qualifiedTable} (${cols.map((c) => `\"${c}\"`).join(\", \")}) ` +\n\t\t\t\t\t\t`SELECT ${insertVals.join(\", \")} ` +\n\t\t\t\t\t\t`WHERE NOT EXISTS (SELECT 1 FROM ${qualifiedTable} WHERE ${keyPred})`,\n\t\t\t\t});\n\t\t\t}\n\t\t\tincBatch = null;\n\t\t\tincBatchKey = \"\";\n\t\t};\n\n\t\tconst flushInsertBatch = () => {\n\t\t\tif (!currentBatch) return;\n\t\t\tconst batch = currentBatch;\n\t\t\tconst qualifiedTable = `\"${this.pgSchemaName}\".\"${batch.table}\"`;\n\t\t\tconst colList = batch.cols.map((c) => `\"${c}\"`).join(\", \");\n\n\t\t\t// Deduplicate by upsert key — last row wins (Postgres rejects duplicate keys in one INSERT)\n\t\t\tlet rows = batch.rows;\n\t\t\tif (batch.upsertKeys && batch.upsertKeys.length > 0) {\n\t\t\t\tconst uKeys = batch.upsertKeys;\n\t\t\t\tconst keyIndices = uKeys.map((k) => batch.cols.indexOf(k));\n\t\t\t\tconst seen = new Map<string, number>();\n\t\t\t\tfor (let i = 0; i < rows.length; i++) {\n\t\t\t\t\tconst key = keyIndices.map((ki) => rows[i][ki]).join(\"\\0\");\n\t\t\t\t\tseen.set(key, i);\n\t\t\t\t}\n\t\t\t\tif (seen.size < rows.length) {\n\t\t\t\t\trows = Array.from(seen.values()).map((i) => rows[i]);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst valuesList = rows.map((r) => `(${r.join(\", \")})`).join(\", \");\n\t\t\tlet stmt = `INSERT INTO ${qualifiedTable} (${colList}) VALUES ${valuesList}`;\n\n\t\t\t// Plain inserts are append-only (revert = delete by _block_height);\n\t\t\t// only keyed upserts can overwrite state worth journaling.\n\t\t\tif (this.journal && batch.upsertKeys && batch.upsertKeys.length > 0) {\n\t\t\t\tconst uKeys = batch.upsertKeys;\n\t\t\t\tconst keyIndices = uKeys.map((k) => batch.cols.indexOf(k));\n\t\t\t\tstatements.push(\n\t\t\t\t\tthis.journalCaptureSQL(\n\t\t\t\t\t\tbatch.table,\n\t\t\t\t\t\tuKeys,\n\t\t\t\t\t\trows.map((r) => keyIndices.map((ki) => r[ki])),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (batch.upsertKeys && batch.upsertKeys.length > 0) {\n\t\t\t\tconst batchKeys = batch.upsertKeys;\n\t\t\t\tconst updateCols = batch.cols.filter(\n\t\t\t\t\t(c) => !batchKeys.includes(c) && !c.startsWith(\"_\"),\n\t\t\t\t);\n\t\t\t\tif (updateCols.length > 0) {\n\t\t\t\t\tconst setClauses = updateCols.map((c) => `\"${c}\" = EXCLUDED.\"${c}\"`);\n\t\t\t\t\tstmt += ` ON CONFLICT (${batchKeys.map((k) => `\"${k}\"`).join(\", \")}) DO UPDATE SET ${setClauses.join(\", \")}`;\n\t\t\t\t} else {\n\t\t\t\t\tstmt += ` ON CONFLICT (${batchKeys.map((k) => `\"${k}\"`).join(\", \")}) DO NOTHING`;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tstatements.push(stmt);\n\t\t\tcurrentBatch = null;\n\t\t\tcurrentBatchKey = \"\";\n\t\t};\n\n\t\tfor (const op of ops) {\n\t\t\tconst qualifiedTable = `\"${this.pgSchemaName}\".\"${op.table}\"`;\n\n\t\t\tif (op.kind === \"insert\") {\n\t\t\t\tflushIncrementBatch();\n\t\t\t\tconst { cols, vals, upsertKeys, batchKey } = this.prepareInsert(op);\n\n\t\t\t\tif (batchKey === currentBatchKey && currentBatch) {\n\t\t\t\t\t// Same table + columns + upsert key — append to batch\n\t\t\t\t\tcurrentBatch.rows.push(vals);\n\t\t\t\t} else {\n\t\t\t\t\t// Different batch — flush previous and start new\n\t\t\t\t\tflushInsertBatch();\n\t\t\t\t\tcurrentBatch = { table: op.table, cols, rows: [vals], upsertKeys };\n\t\t\t\t\tcurrentBatchKey = batchKey;\n\t\t\t\t}\n\t\t\t} else if (op.kind === \"increment\") {\n\t\t\t\tflushInsertBatch();\n\t\t\t\tconst keyCols = [...(op.data._upsert_keys as string[])].sort();\n\t\t\t\tconst deltaCols = Object.keys(op.set ?? {}).sort();\n\t\t\t\tconst batchKey = `inc:${op.table}:${keyCols.join(\",\")}:${deltaCols.join(\",\")}`;\n\t\t\t\tif (batchKey !== incBatchKey || !incBatch) {\n\t\t\t\t\tflushIncrementBatch();\n\t\t\t\t\tincBatch = { table: op.table, keyCols, deltaCols, rows: new Map() };\n\t\t\t\t\tincBatchKey = batchKey;\n\t\t\t\t}\n\t\t\t\tconst clean = stripControlKeys(op.data);\n\t\t\t\tconst keySig = keyCols.map((k) => escapeLiteral(clean[k])).join(\"\\0\");\n\t\t\t\tconst existing = incBatch.rows.get(keySig);\n\t\t\t\tif (existing) {\n\t\t\t\t\tfor (const c of deltaCols) {\n\t\t\t\t\t\texisting.deltas[c] =\n\t\t\t\t\t\t\t(existing.deltas[c] ?? 0n) + toBigIntOr0(op.set?.[c]);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tconst deltas: Record<string, bigint> = {};\n\t\t\t\t\tfor (const c of deltaCols) deltas[c] = toBigIntOr0(op.set?.[c]);\n\t\t\t\t\tincBatch.rows.set(keySig, {\n\t\t\t\t\t\tkeys: clean,\n\t\t\t\t\t\tdeltas,\n\t\t\t\t\t\tmeta: {\n\t\t\t\t\t\t\tblockHeight: op.data._block_height ?? this.block.height,\n\t\t\t\t\t\t\ttxId: op.data._tx_id ?? this._tx.txId,\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Non-insert — flush any pending batches first\n\t\t\t\tflushInsertBatch();\n\t\t\t\tflushIncrementBatch();\n\n\t\t\t\tif (op.kind === \"update\") {\n\t\t\t\t\tconst setEntries = Object.entries(op.set ?? {});\n\t\t\t\t\tfor (const [k] of setEntries) validateColumnName(k);\n\t\t\t\t\tconst setClauses = setEntries.map(\n\t\t\t\t\t\t([k, v]) => `\"${k}\" = ${escapeLiteral(v)}`,\n\t\t\t\t\t);\n\t\t\t\t\tconst { clause } = buildWhereClause(op.data);\n\t\t\t\t\tif (this.journal) {\n\t\t\t\t\t\tstatements.push(this.journalCaptureByWhereSQL(op.table, clause));\n\t\t\t\t\t}\n\t\t\t\t\tstatements.push(\n\t\t\t\t\t\t`UPDATE ${qualifiedTable} SET ${setClauses.join(\", \")} WHERE ${clause}`,\n\t\t\t\t\t);\n\t\t\t\t} else if (op.kind === \"delete\") {\n\t\t\t\t\tconst { clause } = buildWhereClause(op.data);\n\t\t\t\t\tif (this.journal) {\n\t\t\t\t\t\tstatements.push(this.journalCaptureByWhereSQL(op.table, clause));\n\t\t\t\t\t}\n\t\t\t\t\tstatements.push(`DELETE FROM ${qualifiedTable} WHERE ${clause}`);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Flush any remaining batches\n\t\tflushInsertBatch();\n\t\tflushIncrementBatch();\n\n\t\treturn statements;\n\t}\n\n\tprivate validateTable(table: string): void {\n\t\tif (!this.subgraphSchema[table]) {\n\t\t\tthrow new Error(\n\t\t\t\t`Table \"${table}\" not found in subgraph schema. Available: [${Object.keys(this.subgraphSchema).join(\", \")}]`,\n\t\t\t);\n\t\t}\n\t}\n}\n\n// --- Helpers ---\n\n/** Drop internal upsert control keys from an op's data. */\nfunction stripControlKeys(\n\tdata: Record<string, unknown>,\n): Record<string, unknown> {\n\tconst {\n\t\t_upsert_keys: _a,\n\t\t_upsert_fallback_keys: _b,\n\t\t_upsert_fallback_set: _c,\n\t\t...clean\n\t} = data;\n\treturn clean;\n}\n\n/** Loose value equality across bigint/number/string representations. */\nfunction valEq(a: unknown, b: unknown): boolean {\n\tif (a === b) return true;\n\tif (a == null || b == null) return false;\n\treturn String(a) === String(b);\n}\n\n/** Does `row` satisfy every column constraint in `where`? */\nfunction rowMatches(\n\trow: Record<string, unknown>,\n\twhere: Record<string, unknown>,\n): boolean {\n\treturn Object.entries(where).every(([k, v]) => valEq(row[k], v));\n}\n\nfunction toBigIntOr0(v: unknown): bigint {\n\tif (typeof v === \"bigint\") return v;\n\tif (v == null) return 0n;\n\ttry {\n\t\treturn BigInt(String(v));\n\t} catch {\n\t\treturn 0n;\n\t}\n}\n\n/** Coerce a row for JSON serialization — bigints become strings. */\nfunction jsonSafe(row: Record<string, unknown>): Record<string, unknown> {\n\tconst out: Record<string, unknown> = {};\n\tfor (const [k, v] of Object.entries(row)) {\n\t\tout[k] = typeof v === \"bigint\" ? v.toString() : v;\n\t}\n\treturn out;\n}\n\nfunction escapeLiteral(value: unknown): string {\n\tif (value === null || value === undefined) return \"NULL\";\n\tif (typeof value === \"number\" || typeof value === \"bigint\")\n\t\treturn String(value);\n\tif (typeof value === \"boolean\") return value ? \"TRUE\" : \"FALSE\";\n\tif (typeof value === \"object\")\n\t\treturn `'${JSON.stringify(value, (_k, v) => (typeof v === \"bigint\" ? v.toString() : v)).replace(/'/g, \"''\")}'::jsonb`;\n\t// String — escape single quotes\n\treturn `'${String(value).replace(/'/g, \"''\")}'`;\n}\n\nfunction buildWhereClause(where: Record<string, unknown>): {\n\tclause: string;\n\tvalues: unknown[];\n} {\n\tconst entries = Object.entries(where);\n\tif (entries.length === 0) return { clause: \"TRUE\", values: [] };\n\n\tfor (const [k] of entries) validateColumnName(k);\n\tconst parts = entries.map(([k, v]) => `\"${k}\" = ${escapeLiteral(v)}`);\n\treturn { clause: parts.join(\" AND \"), values: [] };\n}\n",
|
|
5
|
+
"import type { Database } from \"@secondlayer/shared/db\";\nimport { logger } from \"@secondlayer/shared/logger\";\nimport { formatUnits } from \"@secondlayer/stacks/utils\";\nimport { type Kysely, type Transaction, sql } from \"kysely\";\nimport { TYPE_MAP, emitJournalDDL } from \"../schema/generator.ts\";\nimport type { ComputedValue, SubgraphSchema } from \"../types.ts\";\n\ntype AnyDb = Kysely<Database> | Transaction<Database>;\n\n/** Reorg journal entries older than this many blocks are prunable — far past\n * Stacks finality (observed reorg depth is single digits). */\nexport const JOURNAL_RETENTION_BLOCKS = 300;\n\n/** Schemas whose `_journal` table existence has been ensured this process.\n * Populated only after a successful flush (a rolled-back CREATE must retry). */\nconst journalEnsured = new Set<string>();\n\ninterface WriteOp {\n\tkind: \"insert\" | \"update\" | \"delete\" | \"increment\";\n\ttable: string;\n\tdata: Record<string, unknown>;\n\t/** For update: SET clause. For increment: column → signed delta. */\n\tset?: Record<string, unknown>;\n}\n\n/**\n * One step of a flush. Most writes are a plain SQL string executed in order.\n * An increment is a PAIR the executor branches on, because closing its\n * lost-update race needs a per-statement rowcount — see\n * {@link SubgraphContext.execStatements} and the rationale on the increment\n * batch in `buildStatements`.\n */\ntype FlushStatement =\n\t| string\n\t| {\n\t\t\tkind: \"increment\";\n\t\t\t/** `UPDATE … SET c = COALESCE(c,0) + δ WHERE <key>` */\n\t\t\tupdate: string;\n\t\t\t/** `INSERT … SELECT … WHERE NOT EXISTS (<key>)` */\n\t\t\tinsert: string;\n\t\t\t/** Key predicate, for the (unreachable-by-design) error message. */\n\t\t\tkeyPred: string;\n\t\t\ttable: string;\n\t };\n\nexport interface FlushWrite {\n\top: \"insert\" | \"update\" | \"delete\";\n\ttable: string;\n\t/** Full row data (for inserts) or where+set merged (for updates). Bigints stringified. */\n\trow: Record<string, unknown>;\n\t/** Stable identifier for dedup — `{blockHeight, txId, rowIndex}` */\n\tpk: { blockHeight: number; txId: string; rowIndex: number };\n}\n\nexport interface FlushManifest {\n\tcount: number;\n\twrites: FlushWrite[];\n}\n\nimport { type ChainReadClient, createChainReadClient } from \"./chain-read.ts\";\n\nexport interface BlockMeta {\n\theight: number;\n\thash: string;\n\ttimestamp: number;\n\tburnBlockHeight: number;\n\t/**\n\t * Nakamoto StacksBlockId — the identifier `?tip=` accepts, and the only way\n\t * to pin a read-only call to THIS block. Null on rows ingested before it\n\t * was persisted; `ctx.client.readOnly` refuses to run rather than silently\n\t * reading at the node's tip.\n\t */\n\tindexBlockHash?: string | null;\n}\n\nexport interface TxMeta {\n\ttxId: string;\n\tsender: string;\n\ttype: string;\n\tstatus: string;\n\tcontractId?: string | null;\n\tfunctionName?: string | null;\n}\n\n/** Validate that a column name is safe for SQL identifiers */\nfunction validateColumnName(name: string): void {\n\tif (!/^[a-z_][a-z0-9_]*$/i.test(name)) {\n\t\tthrow new Error(`Invalid column name: ${name}`);\n\t}\n}\n\n/**\n * Runtime context passed to subgraph handlers.\n * Batches writes and flushes them atomically at the end of a block.\n *\n * Row reads (findOne/findMany) are read-your-writes: they overlay the pending\n * ops queue on the DB state, so a handler observes every write queued earlier\n * in the same block. Without this, accumulator patterns (balance = f(existing))\n * silently lose all but the last same-block delta per row (fix-f040 B1).\n * Aggregate reads (count/sum/min/max) remain pre-flush DB state.\n */\nexport class SubgraphContext {\n\treadonly block: BlockMeta;\n\tprivate _tx: TxMeta;\n\tprivate readonly db: AnyDb;\n\tprivate readonly pgSchemaName: string;\n\tprivate readonly subgraphSchema: SubgraphSchema;\n\t/** Pending writes for this block. `protected` so the in-memory test\n\t * context (`@secondlayer/subgraphs/testing`) can materialize them through\n\t * the SAME overlay this class uses — never a second implementation. */\n\tprotected readonly ops: WriteOp[] = [];\n\t/**\n\t * Record pre-images of keyed mutations into the schema's `_journal` so a\n\t * reorg can restore prior row states (fix-f040 B2). Enabled on the live\n\t * path only — deep reindex/backfill heights are past finality, and the\n\t * journal would just be churn the pruner deletes.\n\t */\n\tprivate readonly journal: boolean;\n\n\t/** Memoized per block; see the `client` getter. */\n\tprotected _client?: ChainReadClient;\n\n\tconstructor(\n\t\tdb: AnyDb,\n\t\tpgSchemaName: string,\n\t\tsubgraphSchema: SubgraphSchema,\n\t\tblock: BlockMeta,\n\t\ttx: TxMeta,\n\t\tjournal = false,\n\t) {\n\t\tthis.db = db;\n\t\tthis.pgSchemaName = pgSchemaName;\n\t\tthis.subgraphSchema = subgraphSchema;\n\t\tthis.block = block;\n\t\tthis._tx = tx;\n\t\tthis.journal = journal;\n\t}\n\n\t/**\n\t * Chain reads pinned to THIS block. Lazily built so a handler that never\n\t * reads never touches the node config, and so the in-memory test context\n\t * can override it without a node.\n\t */\n\tget client(): ChainReadClient {\n\t\tthis._client ??= createChainReadClient({\n\t\t\tblockHeight: this.block.height,\n\t\t\tindexBlockHash: this.block.indexBlockHash,\n\t\t});\n\t\treturn this._client;\n\t}\n\n\tget tx(): TxMeta {\n\t\treturn this._tx;\n\t}\n\n\t/** Update the current transaction context (used by runner between events) */\n\tsetTx(tx: TxMeta): void {\n\t\tthis._tx = tx;\n\t}\n\n\t// --- Write operations (batched) ---\n\n\tinsert(table: string, row: Record<string, unknown>): void {\n\t\tthis.validateTable(table);\n\t\tthis.ops.push({\n\t\t\tkind: \"insert\",\n\t\t\ttable,\n\t\t\tdata: { ...row, _block_height: this.block.height, _tx_id: this._tx.txId },\n\t\t});\n\t}\n\n\tupdate(\n\t\ttable: string,\n\t\twhere: Record<string, unknown>,\n\t\tset: Record<string, unknown>,\n\t): void {\n\t\tthis.validateTable(table);\n\t\tthis.ops.push({ kind: \"update\", table, data: where, set });\n\t}\n\n\tupsert(\n\t\ttable: string,\n\t\tkey: Record<string, unknown>,\n\t\trow: Record<string, unknown>,\n\t): void {\n\t\tthis.validateTable(table);\n\t\tconst tableDef = this.subgraphSchema[table];\n\t\tif (!tableDef) return;\n\t\tconst keyColumns = Object.keys(key);\n\n\t\t// Check if there's a matching uniqueKeys constraint\n\t\tconst hasUniqueConstraint = tableDef.uniqueKeys?.some(\n\t\t\t(uk) =>\n\t\t\t\tuk.length === keyColumns.length &&\n\t\t\t\tuk.every((c) => keyColumns.includes(c)),\n\t\t);\n\n\t\tconst meta = { _block_height: this.block.height, _tx_id: this._tx.txId };\n\n\t\tif (hasUniqueConstraint) {\n\t\t\t// Use ON CONFLICT for proper upsert\n\t\t\tthis.ops.push({\n\t\t\t\tkind: \"insert\",\n\t\t\t\ttable,\n\t\t\t\tdata: { ...key, ...row, ...meta, _upsert_keys: keyColumns },\n\t\t\t});\n\t\t} else {\n\t\t\t// Fallback: log warning, use findOne + conditional insert/update\n\t\t\tlogger.warn(\n\t\t\t\t\"upsert called without matching uniqueKeys constraint, using fallback\",\n\t\t\t\t{\n\t\t\t\t\ttable,\n\t\t\t\t\tkeys: keyColumns,\n\t\t\t\t},\n\t\t\t);\n\t\t\tthis.ops.push({\n\t\t\t\tkind: \"insert\",\n\t\t\t\ttable,\n\t\t\t\tdata: {\n\t\t\t\t\t...key,\n\t\t\t\t\t...row,\n\t\t\t\t\t...meta,\n\t\t\t\t\t_upsert_fallback_keys: keyColumns,\n\t\t\t\t\t_upsert_fallback_set: row,\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t}\n\n\tdelete(table: string, where: Record<string, unknown>): void {\n\t\tthis.validateTable(table);\n\t\tthis.ops.push({ kind: \"delete\", table, data: where });\n\t}\n\n\t/**\n\t * Atomic counter update — the blessed accumulator primitive. Compiles to\n\t * `INSERT ... ON CONFLICT (key) DO UPDATE SET col = COALESCE(t.col,0) + delta`,\n\t * so deltas commute: same-block, replayed-in-order, and concurrent updates\n\t * all land correctly without read-modify-write. Missing row inserts the\n\t * delta as the initial value. Requires a uniqueKeys constraint matching\n\t * `key`; deltas may be negative.\n\t */\n\tincrement(\n\t\ttable: string,\n\t\tkey: Record<string, unknown>,\n\t\tdeltas: Record<string, bigint | number>,\n\t): void {\n\t\tthis.validateTable(table);\n\t\tconst tableDef = this.subgraphSchema[table];\n\t\tconst keyColumns = Object.keys(key);\n\t\tconst hasUniqueConstraint = tableDef?.uniqueKeys?.some(\n\t\t\t(uk) =>\n\t\t\t\tuk.length === keyColumns.length &&\n\t\t\t\tuk.every((c) => keyColumns.includes(c)),\n\t\t);\n\t\tif (!hasUniqueConstraint) {\n\t\t\tthrow new Error(\n\t\t\t\t`increment(\"${table}\") requires a uniqueKeys constraint on [${keyColumns.join(\", \")}]`,\n\t\t\t);\n\t\t}\n\t\tfor (const [col, v] of Object.entries(deltas)) {\n\t\t\tvalidateColumnName(col);\n\t\t\tif (keyColumns.includes(col)) {\n\t\t\t\tthrow new Error(`increment(\"${table}\"): \"${col}\" is a key column`);\n\t\t\t}\n\t\t\tif (typeof v !== \"bigint\" && typeof v !== \"number\") {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`increment(\"${table}\"): delta for \"${col}\" must be bigint or number`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tthis.ops.push({\n\t\t\tkind: \"increment\",\n\t\t\ttable,\n\t\t\tdata: {\n\t\t\t\t...key,\n\t\t\t\t_block_height: this.block.height,\n\t\t\t\t_tx_id: this._tx.txId,\n\t\t\t\t_upsert_keys: keyColumns,\n\t\t\t},\n\t\t\tset: { ...deltas },\n\t\t});\n\t}\n\n\t// --- Ops checkpoint (per-event atomicity) ---\n\n\t/** Current length of the pending-ops queue. Pair with {@link rollbackTo}. */\n\topsCheckpoint(): number {\n\t\treturn this.ops.length;\n\t}\n\n\t/**\n\t * Discard ops queued after a checkpoint. The runner wraps each handler\n\t * invocation so a thrown handler contributes nothing — without this, a\n\t * transfer handler that debited then threw flushes a one-sided debit\n\t * (fix-f040 B6).\n\t */\n\trollbackTo(checkpoint: number): void {\n\t\tif (checkpoint < 0 || checkpoint > this.ops.length) return;\n\t\tthis.ops.length = checkpoint;\n\t}\n\n\t/** Partial update — sets only specified fields, preserves everything else */\n\tpatch(\n\t\ttable: string,\n\t\twhere: Record<string, unknown>,\n\t\tset: Record<string, unknown>,\n\t): void {\n\t\tthis.update(table, where, set);\n\t}\n\n\t/**\n\t * Find-then-merge-or-insert. Values can be functions: (existing) => newValue.\n\t * Async because it reads existing row first.\n\t */\n\tasync patchOrInsert(\n\t\ttable: string,\n\t\tkey: Record<string, unknown>,\n\t\trow: Record<string, ComputedValue>,\n\t): Promise<void> {\n\t\tconst existing = await this.findOne(table, key);\n\t\tconst resolved: Record<string, unknown> = {};\n\t\tfor (const [k, v] of Object.entries(row)) {\n\t\t\tresolved[k] = typeof v === \"function\" ? v(existing) : v;\n\t\t}\n\t\tthis.upsert(table, key, resolved);\n\t}\n\n\t/** Format a bigint amount with decimal places */\n\tformatUnits(value: bigint, decimals: number): string {\n\t\treturn formatUnits(value, decimals);\n\t}\n\n\t// --- Read operations (immediate) ---\n\n\t/**\n\t * Committed rows matching `where`, BEFORE the pending-ops overlay. The one\n\t * seam a different backing store replaces (the in-memory test context);\n\t * everything above it — validation, overlay, op queueing, flush semantics\n\t * — stays here so the two can't diverge.\n\t */\n\tprotected async readRows(\n\t\ttable: string,\n\t\twhere: Record<string, unknown>,\n\t\tlimit?: number,\n\t): Promise<Record<string, unknown>[]> {\n\t\tconst qualifiedTable = `\"${this.pgSchemaName}\".\"${table}\"`;\n\t\tconst { clause } = buildWhereClause(where);\n\t\tconst query = `SELECT * FROM ${qualifiedTable} WHERE ${clause}${\n\t\t\tlimit !== undefined ? ` LIMIT ${limit}` : \"\"\n\t\t}`;\n\t\tconst { rows } = await sql.raw(query).execute(this.db);\n\t\treturn (rows as Record<string, unknown>[]).map((r) =>\n\t\t\tthis.coerceRow(table, r),\n\t\t);\n\t}\n\n\tasync findOne(\n\t\ttable: string,\n\t\twhere: Record<string, unknown>,\n\t): Promise<Record<string, unknown> | null> {\n\t\tthis.validateTable(table);\n\t\tconst row = (await this.readRows(table, where, 1))[0] ?? null;\n\t\treturn this.overlayOne(table, where, row);\n\t}\n\n\tasync findMany(\n\t\ttable: string,\n\t\twhere: Record<string, unknown>,\n\t): Promise<Record<string, unknown>[]> {\n\t\tthis.validateTable(table);\n\t\treturn this.overlayMany(table, where, await this.readRows(table, where));\n\t}\n\n\t// --- Pending-ops overlay (read-your-writes) ---\n\n\t/**\n\t * Replay pending ops for `table` over a single DB-read result so reads\n\t * observe earlier same-block writes. Mirrors flush semantics: upserts\n\t * merge non-key/non-meta columns, increments add deltas, updates/deletes\n\t * apply by where-match. Overlaid rows synthesized from pending inserts\n\t * lack DB-generated columns (_id, _created_at).\n\t */\n\tprotected overlayOne(\n\t\ttable: string,\n\t\twhere: Record<string, unknown>,\n\t\tdbRow: Record<string, unknown> | null,\n\t): Record<string, unknown> | null {\n\t\tif (this.ops.length === 0) return dbRow;\n\t\tlet row = dbRow;\n\t\tfor (const op of this.ops) {\n\t\t\tif (op.table !== table) continue;\n\t\t\trow = this.applyOpToRow(op, row, where);\n\t\t}\n\t\treturn row;\n\t}\n\n\tprotected overlayMany(\n\t\ttable: string,\n\t\twhere: Record<string, unknown>,\n\t\tdbRows: Record<string, unknown>[],\n\t): Record<string, unknown>[] {\n\t\tif (this.ops.length === 0) return [...dbRows];\n\t\tlet result = [...dbRows];\n\t\tfor (const op of this.ops) {\n\t\t\tif (op.table !== table) continue;\n\t\t\tif (op.kind === \"update\") {\n\t\t\t\tfor (let i = 0; i < result.length; i++) {\n\t\t\t\t\t// biome-ignore lint/style/noNonNullAssertion: idx bounds-checked by loop condition\n\t\t\t\t\tif (rowMatches(result[i]!, op.data))\n\t\t\t\t\t\tresult[i] = { ...result[i], ...(op.set ?? {}) };\n\t\t\t\t}\n\t\t\t} else if (op.kind === \"delete\") {\n\t\t\t\tresult = result.filter((r) => !rowMatches(r, op.data));\n\t\t\t} else {\n\t\t\t\t// insert / increment — merge into the keyed row, or append if the\n\t\t\t\t// new row satisfies the filter.\n\t\t\t\tconst upsertKeys = op.data._upsert_keys as string[] | undefined;\n\t\t\t\tconst clean = stripControlKeys(op.data);\n\t\t\t\tconst idx = upsertKeys\n\t\t\t\t\t? result.findIndex((r) =>\n\t\t\t\t\t\t\tupsertKeys.every((k) => valEq(r[k], clean[k])),\n\t\t\t\t\t\t)\n\t\t\t\t\t: -1;\n\t\t\t\tif (idx >= 0) {\n\t\t\t\t\t// biome-ignore lint/style/noNonNullAssertion: idx bounds-checked above\n\t\t\t\t\tconst existing = result[idx]!;\n\t\t\t\t\tresult[idx] = this.applyOpToRow(op, existing, where) ?? existing;\n\t\t\t\t} else {\n\t\t\t\t\tconst created = this.applyOpToRow(op, null, where);\n\t\t\t\t\tif (created) result.push(created);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\t/** Apply one pending op to a candidate row state (null = row absent). */\n\tprotected applyOpToRow(\n\t\top: WriteOp,\n\t\trow: Record<string, unknown> | null,\n\t\twhere: Record<string, unknown>,\n\t): Record<string, unknown> | null {\n\t\tconst upsertKeys = op.data._upsert_keys as string[] | undefined;\n\t\tconst clean = stripControlKeys(op.data);\n\n\t\tswitch (op.kind) {\n\t\t\tcase \"insert\": {\n\t\t\t\tif (row) {\n\t\t\t\t\t// Same entity? Compare on the upsert key — a plain insert (no\n\t\t\t\t\t// key) can never target an existing row.\n\t\t\t\t\tif (upsertKeys?.every((k) => valEq(row[k], clean[k]))) {\n\t\t\t\t\t\t// Mirror ON CONFLICT DO UPDATE: non-key, non-meta cols only.\n\t\t\t\t\t\tconst merged = { ...row };\n\t\t\t\t\t\tfor (const [k, v] of Object.entries(clean)) {\n\t\t\t\t\t\t\tif (!upsertKeys.includes(k) && !k.startsWith(\"_\")) merged[k] = v;\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn merged;\n\t\t\t\t\t}\n\t\t\t\t\treturn row;\n\t\t\t\t}\n\t\t\t\treturn rowMatches(clean, where) ? { ...clean } : null;\n\t\t\t}\n\t\t\tcase \"increment\": {\n\t\t\t\tconst deltas = op.set ?? {};\n\t\t\t\tif (row) {\n\t\t\t\t\t// biome-ignore lint/style/noNonNullAssertion: increment always carries _upsert_keys\n\t\t\t\t\tif (upsertKeys!.every((k) => valEq(row[k], clean[k]))) {\n\t\t\t\t\t\tconst merged = { ...row };\n\t\t\t\t\t\tfor (const [col, d] of Object.entries(deltas)) {\n\t\t\t\t\t\t\tmerged[col] = toBigIntOr0(merged[col]) + toBigIntOr0(d);\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn merged;\n\t\t\t\t\t}\n\t\t\t\t\treturn row;\n\t\t\t\t}\n\t\t\t\tif (!rowMatches(clean, where)) return null;\n\t\t\t\tconst created: Record<string, unknown> = { ...clean };\n\t\t\t\tfor (const [col, d] of Object.entries(deltas)) {\n\t\t\t\t\tcreated[col] = toBigIntOr0(d);\n\t\t\t\t}\n\t\t\t\treturn created;\n\t\t\t}\n\t\t\tcase \"update\":\n\t\t\t\treturn row && rowMatches(row, op.data)\n\t\t\t\t\t? { ...row, ...(op.set ?? {}) }\n\t\t\t\t\t: row;\n\t\t\tcase \"delete\":\n\t\t\t\treturn row && rowMatches(row, op.data) ? null : row;\n\t\t}\n\t}\n\n\t// --- Aggregate reads ---\n\n\tasync count(table: string, where?: Record<string, unknown>): Promise<number> {\n\t\tthis.validateTable(table);\n\t\tconst qualifiedTable = `\"${this.pgSchemaName}\".\"${table}\"`;\n\t\tconst whereClause = where ? `WHERE ${buildWhereClause(where).clause}` : \"\";\n\t\tconst { rows } = await sql\n\t\t\t.raw(\n\t\t\t\t`SELECT COUNT(*)::int AS count FROM ${qualifiedTable} ${whereClause}`,\n\t\t\t)\n\t\t\t.execute(this.db);\n\t\treturn Number((rows as Record<string, unknown>[])[0]?.count ?? 0);\n\t}\n\n\tasync sum(\n\t\ttable: string,\n\t\tcolumn: string,\n\t\twhere?: Record<string, unknown>,\n\t): Promise<bigint> {\n\t\tthis.validateTable(table);\n\t\tvalidateColumnName(column);\n\t\tconst qualifiedTable = `\"${this.pgSchemaName}\".\"${table}\"`;\n\t\tconst whereClause = where ? `WHERE ${buildWhereClause(where).clause}` : \"\";\n\t\tconst { rows } = await sql\n\t\t\t.raw(\n\t\t\t\t`SELECT COALESCE(SUM(\"${column}\"), 0) AS total FROM ${qualifiedTable} ${whereClause}`,\n\t\t\t)\n\t\t\t.execute(this.db);\n\t\treturn BigInt(\n\t\t\t(rows as Record<string, unknown>[])[0]?.total?.toString() ?? \"0\",\n\t\t);\n\t}\n\n\tasync min(\n\t\ttable: string,\n\t\tcolumn: string,\n\t\twhere?: Record<string, unknown>,\n\t): Promise<bigint | null> {\n\t\tthis.validateTable(table);\n\t\tvalidateColumnName(column);\n\t\tconst qualifiedTable = `\"${this.pgSchemaName}\".\"${table}\"`;\n\t\tconst whereClause = where ? `WHERE ${buildWhereClause(where).clause}` : \"\";\n\t\tconst { rows } = await sql\n\t\t\t.raw(\n\t\t\t\t`SELECT MIN(\"${column}\") AS val FROM ${qualifiedTable} ${whereClause}`,\n\t\t\t)\n\t\t\t.execute(this.db);\n\t\tconst val = (rows as Record<string, unknown>[])[0]?.val;\n\t\treturn val != null ? BigInt(val.toString()) : null;\n\t}\n\n\tasync max(\n\t\ttable: string,\n\t\tcolumn: string,\n\t\twhere?: Record<string, unknown>,\n\t): Promise<bigint | null> {\n\t\tthis.validateTable(table);\n\t\tvalidateColumnName(column);\n\t\tconst qualifiedTable = `\"${this.pgSchemaName}\".\"${table}\"`;\n\t\tconst whereClause = where ? `WHERE ${buildWhereClause(where).clause}` : \"\";\n\t\tconst { rows } = await sql\n\t\t\t.raw(\n\t\t\t\t`SELECT MAX(\"${column}\") AS val FROM ${qualifiedTable} ${whereClause}`,\n\t\t\t)\n\t\t\t.execute(this.db);\n\t\tconst val = (rows as Record<string, unknown>[])[0]?.val;\n\t\treturn val != null ? BigInt(val.toString()) : null;\n\t}\n\n\tasync countDistinct(\n\t\ttable: string,\n\t\tcolumn: string,\n\t\twhere?: Record<string, unknown>,\n\t): Promise<number> {\n\t\tthis.validateTable(table);\n\t\tvalidateColumnName(column);\n\t\tconst qualifiedTable = `\"${this.pgSchemaName}\".\"${table}\"`;\n\t\tconst whereClause = where ? `WHERE ${buildWhereClause(where).clause}` : \"\";\n\t\tconst { rows } = await sql\n\t\t\t.raw(\n\t\t\t\t`SELECT COUNT(DISTINCT \"${column}\")::int AS count FROM ${qualifiedTable} ${whereClause}`,\n\t\t\t)\n\t\t\t.execute(this.db);\n\t\treturn Number((rows as Record<string, unknown>[])[0]?.count ?? 0);\n\t}\n\n\t/** Coerce string values from Postgres back to BigInt for uint/int columns */\n\tprivate coerceRow(\n\t\ttable: string,\n\t\trow: Record<string, unknown>,\n\t): Record<string, unknown> {\n\t\tconst tableDef = this.subgraphSchema[table];\n\t\tif (!tableDef) return row;\n\t\tconst result = { ...row };\n\t\tfor (const [col, def] of Object.entries(tableDef.columns)) {\n\t\t\tif (\n\t\t\t\t(def.type === \"uint\" || def.type === \"int\") &&\n\t\t\t\ttypeof result[col] === \"string\"\n\t\t\t) {\n\t\t\t\tresult[col] = BigInt(result[col] as string);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\t// --- Flush ---\n\n\t/** Number of pending write operations */\n\tget pendingOps(): number {\n\t\treturn this.ops.length;\n\t}\n\n\t/**\n\t * Execute all batched writes in a single transaction.\n\t * Auto-populates _block_height, _tx_id, _created_at on inserts.\n\t *\n\t * Returns a {@link FlushManifest} describing every write so downstream\n\t * consumers (subscription emitter) can fan out outbox rows atomically\n\t * with the flush itself.\n\t */\n\tasync flush(): Promise<FlushManifest> {\n\t\tif (this.ops.length === 0) return { count: 0, writes: [] };\n\n\t\tawait this.ensureJournalTable();\n\n\t\tconst opsToFlush = [...this.ops];\n\t\tthis.ops.length = 0;\n\n\t\tconst statements = this.buildStatements(opsToFlush);\n\n\t\tif (\"isTransaction\" in this.db) {\n\t\t\tawait this.execStatements(this.db, statements);\n\t\t} else {\n\t\t\tawait (this.db as Kysely<Database>).transaction().execute(async (tx) => {\n\t\t\t\tawait this.execStatements(tx, statements);\n\t\t\t});\n\t\t}\n\n\t\tconst writes: FlushWrite[] = opsToFlush.map((op, rowIndex) => {\n\t\t\tconst blockHeight =\n\t\t\t\t(op.data._block_height as number | undefined) ?? this.block.height;\n\t\t\tconst txId = (op.data._tx_id as string | undefined) ?? this._tx.txId;\n\t\t\tconst baseRow =\n\t\t\t\top.kind === \"update\" || op.kind === \"increment\"\n\t\t\t\t\t? { ...op.data, ...(op.set ?? {}) }\n\t\t\t\t\t: { ...op.data };\n\t\t\t// Strip upsert control keys — not part of the row shape\n\t\t\t(baseRow as Record<string, unknown>)._upsert_keys = undefined;\n\t\t\t(baseRow as Record<string, unknown>)._upsert_fallback_keys = undefined;\n\t\t\t(baseRow as Record<string, unknown>)._upsert_fallback_set = undefined;\n\t\t\treturn {\n\t\t\t\t// Increments surface as \"updated\" to subscribers — the row payload\n\t\t\t\t// carries the key + the applied delta, not the absolute value.\n\t\t\t\top: op.kind === \"increment\" ? \"update\" : op.kind,\n\t\t\t\ttable: op.table,\n\t\t\t\trow: jsonSafe(baseRow),\n\t\t\t\tpk: { blockHeight, txId, rowIndex },\n\t\t\t};\n\t\t});\n\n\t\treturn { count: opsToFlush.length, writes };\n\t}\n\n\t/**\n\t * Run a built statement list on an open transaction.\n\t *\n\t * Plain statements run in order. An increment runs UPDATE-first and then,\n\t * ONLY if that matched nothing, the guarded INSERT — and if the INSERT also\n\t * wrote nothing, the UPDATE again.\n\t *\n\t * That last step is the whole point. Under READ COMMITTED, two block\n\t * transactions flushing the same key while the row is absent both see\n\t * `UPDATE → 0 rows`; the first commits its INSERT, and the second's\n\t * `WHERE NOT EXISTS` then sees that committed row and inserts nothing. No\n\t * error, no constraint violation — the second delta was simply dropped.\n\t * Re-running the UPDATE takes a fresh snapshot that DOES see the winner's\n\t * row and applies the delta onto it.\n\t *\n\t * It cannot double-apply: the retry is reached only when the first UPDATE\n\t * matched no row AND the INSERT wrote no row, so the delta has not been\n\t * applied by either.\n\t */\n\tprivate async execStatements(\n\t\texecutor: AnyDb,\n\t\tstatements: FlushStatement[],\n\t): Promise<void> {\n\t\tconst affected = (r: { numAffectedRows?: bigint }): bigint =>\n\t\t\tr.numAffectedRows ?? 0n;\n\n\t\tfor (const stmt of statements) {\n\t\t\tif (typeof stmt === \"string\") {\n\t\t\t\tawait sql.raw(stmt).execute(executor);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst updated = await sql.raw(stmt.update).execute(executor);\n\t\t\tif (affected(updated) > 0n) continue;\n\n\t\t\tconst inserted = await sql.raw(stmt.insert).execute(executor);\n\t\t\tif (affected(inserted) > 0n) continue;\n\n\t\t\tconst retried = await sql.raw(stmt.update).execute(executor);\n\t\t\tif (affected(retried) === 0n) {\n\t\t\t\t// Neither wrote: the row a concurrent writer created was gone again\n\t\t\t\t// by the retry (a delete raced in). Fail loudly — silently dropping\n\t\t\t\t// the delta is the bug this whole path exists to prevent. The block\n\t\t\t\t// transaction rolls back and the walk re-processes it.\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`increment could not be applied to ${this.pgSchemaName}.${stmt.table} where ${stmt.keyPred}: row neither updated nor inserted`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Prepare a single insert row, returning its data, columns, upsert key for batching. */\n\tprivate prepareInsert(op: WriteOp): {\n\t\tdata: Record<string, unknown>;\n\t\tcols: string[];\n\t\tvals: string[];\n\t\tupsertKeys: string[] | undefined;\n\t\tbatchKey: string;\n\t} {\n\t\tconst upsertKeys = op.data._upsert_keys as string[] | undefined;\n\t\tconst data = { ...op.data };\n\t\t// biome-ignore lint/performance/noDelete: must remove key, not set undefined — Object.keys must not include these\n\t\tdelete data._upsert_keys;\n\t\t// biome-ignore lint/performance/noDelete: same as above\n\t\tdelete data._upsert_fallback_keys;\n\t\t// biome-ignore lint/performance/noDelete: same as above\n\t\tdelete data._upsert_fallback_set;\n\n\t\t// _block_height and _tx_id are captured at insert/upsert time (not flush time)\n\t\t// to ensure correct tx attribution when multiple txs are batched per block\n\t\tif (!data._block_height) data._block_height = this.block.height;\n\t\tif (!data._tx_id) data._tx_id = this._tx.txId;\n\t\tdata._created_at = \"NOW()\";\n\n\t\tconst cols = Object.keys(data);\n\t\tcols.forEach(validateColumnName);\n\t\tconst vals = cols.map((c) =>\n\t\t\tdata[c] === \"NOW()\" ? \"NOW()\" : escapeLiteral(data[c]),\n\t\t);\n\n\t\t// Batch key: table + sorted columns + upsert key signature (spread to avoid mutating cols)\n\t\tconst batchKey = `${op.table}:${[...cols].sort().join(\",\")}:${upsertKeys ? [...upsertKeys].sort().join(\",\") : \"\"}`;\n\n\t\treturn { data, cols, vals, upsertKeys, batchKey };\n\t}\n\n\t/**\n\t * Lazily create `_journal` for schemas deployed before it existed. Cached\n\t * per process only once CONFIRMED present (to_regclass) — a CREATE issued\n\t * inside a block tx could roll back with it, so self-created tables are\n\t * re-verified on the next flush instead of trusted.\n\t */\n\tprivate async ensureJournalTable(): Promise<void> {\n\t\tif (!this.journal || journalEnsured.has(this.pgSchemaName)) return;\n\t\tconst { rows } = await sql\n\t\t\t.raw(`SELECT to_regclass('\"${this.pgSchemaName}\".\"_journal\"') AS r`)\n\t\t\t.execute(this.db);\n\t\tif ((rows as { r: unknown }[])[0]?.r) {\n\t\t\tjournalEnsured.add(this.pgSchemaName);\n\t\t\treturn;\n\t\t}\n\t\t// Schema names are generator-produced lowercase identifiers, so the\n\t\t// unquoted form emitJournalDDL emits is safe.\n\t\tfor (const stmt of emitJournalDDL(this.pgSchemaName)) {\n\t\t\tawait sql.raw(stmt).execute(this.db);\n\t\t}\n\t}\n\n\t/** SQL type of a user column (for casting journal key VALUES), if known. */\n\tprivate columnSqlType(table: string, col: string): string | undefined {\n\t\tconst def = this.subgraphSchema[table]?.columns?.[col];\n\t\treturn def ? TYPE_MAP[def.type] : undefined;\n\t}\n\n\t/**\n\t * Journal pre-images for a keyed batch: one `_journal` row per key with the\n\t * row's current state (`prev_row`), or NULL when the key doesn't exist yet\n\t * (the mutation will create it — a revert deletes it). Emitted BEFORE the\n\t * mutation statement, same transaction.\n\t */\n\tprivate journalCaptureSQL(\n\t\ttable: string,\n\t\tkeyCols: string[],\n\t\t/** One escaped-literal tuple per key, ordered like keyCols. */\n\t\tkeyLiteralRows: string[][],\n\t): string {\n\t\tconst cast = (col: string, expr: string) => {\n\t\t\tconst t = this.columnSqlType(table, col);\n\t\t\treturn t ? `CAST(${expr} AS ${t})` : expr;\n\t\t};\n\t\tconst keyObj = keyCols\n\t\t\t.map((k) => `'${k}', ${cast(k, `v.\"${k}\"`)}`)\n\t\t\t.join(\", \");\n\t\tconst joinCond = keyCols\n\t\t\t.map((k) => `t.\"${k}\" = ${cast(k, `v.\"${k}\"`)}`)\n\t\t\t.join(\" AND \");\n\t\tconst valuesList = keyLiteralRows\n\t\t\t.map((r) => `(${r.join(\", \")})`)\n\t\t\t.join(\", \");\n\t\treturn (\n\t\t\t`INSERT INTO \"${this.pgSchemaName}\".\"_journal\" (\"block_height\", \"table_name\", \"row_key\", \"prev_row\") ` +\n\t\t\t`SELECT ${this.block.height}, '${table}', jsonb_build_object(${keyObj}), to_jsonb(t.*) ` +\n\t\t\t`FROM (VALUES ${valuesList}) AS v(${keyCols.map((k) => `\"${k}\"`).join(\", \")}) ` +\n\t\t\t`LEFT JOIN \"${this.pgSchemaName}\".\"${table}\" t ON ${joinCond}`\n\t\t);\n\t}\n\n\t/** Journal pre-images of rows a where-clause mutation will touch, keyed by `_id`. */\n\tprivate journalCaptureByWhereSQL(table: string, clause: string): string {\n\t\treturn (\n\t\t\t`INSERT INTO \"${this.pgSchemaName}\".\"_journal\" (\"block_height\", \"table_name\", \"row_key\", \"prev_row\") ` +\n\t\t\t`SELECT ${this.block.height}, '${table}', jsonb_build_object('_id', t.\"_id\"), to_jsonb(t.*) ` +\n\t\t\t`FROM \"${this.pgSchemaName}\".\"${table}\" t WHERE ${clause}`\n\t\t);\n\t}\n\n\t/** Build SQL statements from write ops, batching compatible INSERTs. */\n\tprivate buildStatements(ops: WriteOp[]): FlushStatement[] {\n\t\tconst statements: FlushStatement[] = [];\n\n\t\t// Group consecutive inserts by batch key\n\t\ttype InsertBatch = {\n\t\t\ttable: string;\n\t\t\tcols: string[];\n\t\t\trows: string[][];\n\t\t\tupsertKeys: string[] | undefined;\n\t\t};\n\n\t\t// Consecutive increments on the same (table, key cols, delta cols)\n\t\t// coalesce: same-key deltas SUM (they commute), then compile to one\n\t\t// multi-row INSERT ... ON CONFLICT DO UPDATE SET c = COALESCE(c,0)+EXCLUDED.c.\n\t\ttype IncrementBatch = {\n\t\t\ttable: string;\n\t\t\tkeyCols: string[];\n\t\t\tdeltaCols: string[];\n\t\t\t/** key signature → { key values, summed deltas, insert-time meta } */\n\t\t\trows: Map<\n\t\t\t\tstring,\n\t\t\t\t{\n\t\t\t\t\tkeys: Record<string, unknown>;\n\t\t\t\t\tdeltas: Record<string, bigint>;\n\t\t\t\t\tmeta: { blockHeight: unknown; txId: unknown };\n\t\t\t\t}\n\t\t\t>;\n\t\t};\n\n\t\tlet currentBatch: InsertBatch | null = null;\n\t\tlet currentBatchKey = \"\";\n\t\tlet incBatch: IncrementBatch | null = null;\n\t\tlet incBatchKey = \"\";\n\n\t\tconst flushIncrementBatch = () => {\n\t\t\tif (!incBatch) return;\n\t\t\tconst batch = incBatch;\n\t\t\tconst qualifiedTable = `\"${this.pgSchemaName}\".\"${batch.table}\"`;\n\t\t\tconst cols = [\n\t\t\t\t...batch.keyCols,\n\t\t\t\t...batch.deltaCols,\n\t\t\t\t\"_block_height\",\n\t\t\t\t\"_tx_id\",\n\t\t\t\t\"_created_at\",\n\t\t\t];\n\t\t\tif (this.journal) {\n\t\t\t\tstatements.push(\n\t\t\t\t\tthis.journalCaptureSQL(\n\t\t\t\t\t\tbatch.table,\n\t\t\t\t\t\tbatch.keyCols,\n\t\t\t\t\t\tArray.from(batch.rows.values()).map((r) =>\n\t\t\t\t\t\t\tbatch.keyCols.map((k) => escapeLiteral(r.keys[k])),\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t\t// NOT insert-on-conflict: Postgres validates the PROPOSED insert\n\t\t\t// tuple against CHECK constraints BEFORE conflict arbitration, so a\n\t\t\t// negative delta against an EXISTING row (every debit on a uint\n\t\t\t// balance) errors even though DO UPDATE would produce a legal value\n\t\t\t// (prod halts at sbtc 341445 / usdcx 5269728; empirically verified).\n\t\t\t// UPDATE-first lets the CHECK see the FINAL value; the guarded\n\t\t\t// INSERT covers missing rows — where a negative delta is a GENUINE\n\t\t\t// violation and must still fail loudly.\n\t\t\t//\n\t\t\t// The pair is emitted as ONE step rather than two statements because\n\t\t\t// the executor must branch on their rowcounts: an INSERT that wrote\n\t\t\t// nothing means a concurrent transaction created the row after our\n\t\t\t// UPDATE missed it, and the delta has to be re-applied instead of\n\t\t\t// silently dropped. See `execStatements`.\n\t\t\tfor (const r of batch.rows.values()) {\n\t\t\t\tconst keyPred = batch.keyCols\n\t\t\t\t\t.map((k) => `\"${k}\" = ${escapeLiteral(r.keys[k])}`)\n\t\t\t\t\t.join(\" AND \");\n\t\t\t\tconst updSet = batch.deltaCols\n\t\t\t\t\t.map(\n\t\t\t\t\t\t(c) =>\n\t\t\t\t\t\t\t`\"${c}\" = COALESCE(\"${c}\", 0) + (${String(r.deltas[c] ?? 0n)})`,\n\t\t\t\t\t)\n\t\t\t\t\t.join(\", \");\n\t\t\t\tconst insertVals = [\n\t\t\t\t\t...batch.keyCols.map((k) => escapeLiteral(r.keys[k])),\n\t\t\t\t\t...batch.deltaCols.map((c) => String(r.deltas[c] ?? 0n)),\n\t\t\t\t\tescapeLiteral(r.meta.blockHeight),\n\t\t\t\t\tescapeLiteral(r.meta.txId),\n\t\t\t\t\t\"NOW()\",\n\t\t\t\t];\n\t\t\t\tstatements.push({\n\t\t\t\t\tkind: \"increment\",\n\t\t\t\t\ttable: batch.table,\n\t\t\t\t\tkeyPred,\n\t\t\t\t\tupdate: `UPDATE ${qualifiedTable} SET ${updSet} WHERE ${keyPred}`,\n\t\t\t\t\tinsert:\n\t\t\t\t\t\t`INSERT INTO ${qualifiedTable} (${cols.map((c) => `\"${c}\"`).join(\", \")}) ` +\n\t\t\t\t\t\t`SELECT ${insertVals.join(\", \")} ` +\n\t\t\t\t\t\t`WHERE NOT EXISTS (SELECT 1 FROM ${qualifiedTable} WHERE ${keyPred})`,\n\t\t\t\t});\n\t\t\t}\n\t\t\tincBatch = null;\n\t\t\tincBatchKey = \"\";\n\t\t};\n\n\t\tconst flushInsertBatch = () => {\n\t\t\tif (!currentBatch) return;\n\t\t\tconst batch = currentBatch;\n\t\t\tconst qualifiedTable = `\"${this.pgSchemaName}\".\"${batch.table}\"`;\n\t\t\tconst colList = batch.cols.map((c) => `\"${c}\"`).join(\", \");\n\n\t\t\t// Deduplicate by upsert key — last row wins (Postgres rejects duplicate keys in one INSERT)\n\t\t\tlet rows = batch.rows;\n\t\t\tif (batch.upsertKeys && batch.upsertKeys.length > 0) {\n\t\t\t\tconst uKeys = batch.upsertKeys;\n\t\t\t\tconst keyIndices = uKeys.map((k) => batch.cols.indexOf(k));\n\t\t\t\tconst seen = new Map<string, number>();\n\t\t\t\tfor (let i = 0; i < rows.length; i++) {\n\t\t\t\t\tconst key = keyIndices.map((ki) => rows[i][ki]).join(\"\\0\");\n\t\t\t\t\tseen.set(key, i);\n\t\t\t\t}\n\t\t\t\tif (seen.size < rows.length) {\n\t\t\t\t\trows = Array.from(seen.values()).map((i) => rows[i]);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst valuesList = rows.map((r) => `(${r.join(\", \")})`).join(\", \");\n\t\t\tlet stmt = `INSERT INTO ${qualifiedTable} (${colList}) VALUES ${valuesList}`;\n\n\t\t\t// Plain inserts are append-only (revert = delete by _block_height);\n\t\t\t// only keyed upserts can overwrite state worth journaling.\n\t\t\tif (this.journal && batch.upsertKeys && batch.upsertKeys.length > 0) {\n\t\t\t\tconst uKeys = batch.upsertKeys;\n\t\t\t\tconst keyIndices = uKeys.map((k) => batch.cols.indexOf(k));\n\t\t\t\tstatements.push(\n\t\t\t\t\tthis.journalCaptureSQL(\n\t\t\t\t\t\tbatch.table,\n\t\t\t\t\t\tuKeys,\n\t\t\t\t\t\trows.map((r) => keyIndices.map((ki) => r[ki])),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (batch.upsertKeys && batch.upsertKeys.length > 0) {\n\t\t\t\tconst batchKeys = batch.upsertKeys;\n\t\t\t\tconst updateCols = batch.cols.filter(\n\t\t\t\t\t(c) => !batchKeys.includes(c) && !c.startsWith(\"_\"),\n\t\t\t\t);\n\t\t\t\tif (updateCols.length > 0) {\n\t\t\t\t\tconst setClauses = updateCols.map((c) => `\"${c}\" = EXCLUDED.\"${c}\"`);\n\t\t\t\t\tstmt += ` ON CONFLICT (${batchKeys.map((k) => `\"${k}\"`).join(\", \")}) DO UPDATE SET ${setClauses.join(\", \")}`;\n\t\t\t\t} else {\n\t\t\t\t\tstmt += ` ON CONFLICT (${batchKeys.map((k) => `\"${k}\"`).join(\", \")}) DO NOTHING`;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tstatements.push(stmt);\n\t\t\tcurrentBatch = null;\n\t\t\tcurrentBatchKey = \"\";\n\t\t};\n\n\t\tfor (const op of ops) {\n\t\t\tconst qualifiedTable = `\"${this.pgSchemaName}\".\"${op.table}\"`;\n\n\t\t\tif (op.kind === \"insert\") {\n\t\t\t\tflushIncrementBatch();\n\t\t\t\tconst { cols, vals, upsertKeys, batchKey } = this.prepareInsert(op);\n\n\t\t\t\tif (batchKey === currentBatchKey && currentBatch) {\n\t\t\t\t\t// Same table + columns + upsert key — append to batch\n\t\t\t\t\tcurrentBatch.rows.push(vals);\n\t\t\t\t} else {\n\t\t\t\t\t// Different batch — flush previous and start new\n\t\t\t\t\tflushInsertBatch();\n\t\t\t\t\tcurrentBatch = { table: op.table, cols, rows: [vals], upsertKeys };\n\t\t\t\t\tcurrentBatchKey = batchKey;\n\t\t\t\t}\n\t\t\t} else if (op.kind === \"increment\") {\n\t\t\t\tflushInsertBatch();\n\t\t\t\tconst keyCols = [...(op.data._upsert_keys as string[])].sort();\n\t\t\t\tconst deltaCols = Object.keys(op.set ?? {}).sort();\n\t\t\t\tconst batchKey = `inc:${op.table}:${keyCols.join(\",\")}:${deltaCols.join(\",\")}`;\n\t\t\t\tif (batchKey !== incBatchKey || !incBatch) {\n\t\t\t\t\tflushIncrementBatch();\n\t\t\t\t\tincBatch = { table: op.table, keyCols, deltaCols, rows: new Map() };\n\t\t\t\t\tincBatchKey = batchKey;\n\t\t\t\t}\n\t\t\t\tconst clean = stripControlKeys(op.data);\n\t\t\t\tconst keySig = keyCols.map((k) => escapeLiteral(clean[k])).join(\"\\0\");\n\t\t\t\tconst existing = incBatch.rows.get(keySig);\n\t\t\t\tif (existing) {\n\t\t\t\t\tfor (const c of deltaCols) {\n\t\t\t\t\t\texisting.deltas[c] =\n\t\t\t\t\t\t\t(existing.deltas[c] ?? 0n) + toBigIntOr0(op.set?.[c]);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tconst deltas: Record<string, bigint> = {};\n\t\t\t\t\tfor (const c of deltaCols) deltas[c] = toBigIntOr0(op.set?.[c]);\n\t\t\t\t\tincBatch.rows.set(keySig, {\n\t\t\t\t\t\tkeys: clean,\n\t\t\t\t\t\tdeltas,\n\t\t\t\t\t\tmeta: {\n\t\t\t\t\t\t\tblockHeight: op.data._block_height ?? this.block.height,\n\t\t\t\t\t\t\ttxId: op.data._tx_id ?? this._tx.txId,\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// Non-insert — flush any pending batches first\n\t\t\t\tflushInsertBatch();\n\t\t\t\tflushIncrementBatch();\n\n\t\t\t\tif (op.kind === \"update\") {\n\t\t\t\t\tconst setEntries = Object.entries(op.set ?? {});\n\t\t\t\t\tfor (const [k] of setEntries) validateColumnName(k);\n\t\t\t\t\tconst setClauses = setEntries.map(\n\t\t\t\t\t\t([k, v]) => `\"${k}\" = ${escapeLiteral(v)}`,\n\t\t\t\t\t);\n\t\t\t\t\tconst { clause } = buildWhereClause(op.data);\n\t\t\t\t\tif (this.journal) {\n\t\t\t\t\t\tstatements.push(this.journalCaptureByWhereSQL(op.table, clause));\n\t\t\t\t\t}\n\t\t\t\t\tstatements.push(\n\t\t\t\t\t\t`UPDATE ${qualifiedTable} SET ${setClauses.join(\", \")} WHERE ${clause}`,\n\t\t\t\t\t);\n\t\t\t\t} else if (op.kind === \"delete\") {\n\t\t\t\t\tconst { clause } = buildWhereClause(op.data);\n\t\t\t\t\tif (this.journal) {\n\t\t\t\t\t\tstatements.push(this.journalCaptureByWhereSQL(op.table, clause));\n\t\t\t\t\t}\n\t\t\t\t\tstatements.push(`DELETE FROM ${qualifiedTable} WHERE ${clause}`);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Flush any remaining batches\n\t\tflushInsertBatch();\n\t\tflushIncrementBatch();\n\n\t\treturn statements;\n\t}\n\n\tprivate validateTable(table: string): void {\n\t\tif (!this.subgraphSchema[table]) {\n\t\t\tthrow new Error(\n\t\t\t\t`Table \"${table}\" not found in subgraph schema. Available: [${Object.keys(this.subgraphSchema).join(\", \")}]`,\n\t\t\t);\n\t\t}\n\t}\n}\n\n// --- Helpers ---\n\n/** Drop internal upsert control keys from an op's data. */\nfunction stripControlKeys(\n\tdata: Record<string, unknown>,\n): Record<string, unknown> {\n\tconst {\n\t\t_upsert_keys: _a,\n\t\t_upsert_fallback_keys: _b,\n\t\t_upsert_fallback_set: _c,\n\t\t...clean\n\t} = data;\n\treturn clean;\n}\n\n/** Loose value equality across bigint/number/string representations. */\nfunction valEq(a: unknown, b: unknown): boolean {\n\tif (a === b) return true;\n\tif (a == null || b == null) return false;\n\treturn String(a) === String(b);\n}\n\n/** Does `row` satisfy every column constraint in `where`? */\nfunction rowMatches(\n\trow: Record<string, unknown>,\n\twhere: Record<string, unknown>,\n): boolean {\n\treturn Object.entries(where).every(([k, v]) => valEq(row[k], v));\n}\n\nfunction toBigIntOr0(v: unknown): bigint {\n\tif (typeof v === \"bigint\") return v;\n\tif (v == null) return 0n;\n\ttry {\n\t\treturn BigInt(String(v));\n\t} catch {\n\t\treturn 0n;\n\t}\n}\n\n/** Coerce a row for JSON serialization — bigints become strings. */\nfunction jsonSafe(row: Record<string, unknown>): Record<string, unknown> {\n\tconst out: Record<string, unknown> = {};\n\tfor (const [k, v] of Object.entries(row)) {\n\t\tout[k] = typeof v === \"bigint\" ? v.toString() : v;\n\t}\n\treturn out;\n}\n\nfunction escapeLiteral(value: unknown): string {\n\tif (value === null || value === undefined) return \"NULL\";\n\tif (typeof value === \"number\" || typeof value === \"bigint\")\n\t\treturn String(value);\n\tif (typeof value === \"boolean\") return value ? \"TRUE\" : \"FALSE\";\n\tif (typeof value === \"object\")\n\t\treturn `'${JSON.stringify(value, (_k, v) => (typeof v === \"bigint\" ? v.toString() : v)).replace(/'/g, \"''\")}'::jsonb`;\n\t// String — escape single quotes\n\treturn `'${String(value).replace(/'/g, \"''\")}'`;\n}\n\nfunction buildWhereClause(where: Record<string, unknown>): {\n\tclause: string;\n\tvalues: unknown[];\n} {\n\tconst entries = Object.entries(where);\n\tif (entries.length === 0) return { clause: \"TRUE\", values: [] };\n\n\tfor (const [k] of entries) validateColumnName(k);\n\tconst parts = entries.map(([k, v]) => `\"${k}\" = ${escapeLiteral(v)}`);\n\treturn { clause: parts.join(\" AND \"), values: [] };\n}\n",
|
|
6
6
|
"import { createHash } from \"node:crypto\";\nimport type {\n\tColumnType,\n\tSubgraphDefinition,\n\tSubgraphTable,\n} from \"../types.ts\";\nimport { pgSchemaName, quotePgIdent } from \"./utils.ts\";\n\nexport const TYPE_MAP: Record<ColumnType, string> = {\n\ttext: \"TEXT\",\n\tuint: \"NUMERIC\",\n\tint: \"NUMERIC\",\n\tprincipal: \"TEXT\",\n\tboolean: \"BOOLEAN\",\n\ttimestamp: \"TIMESTAMPTZ\",\n\tjsonb: \"JSONB\",\n};\n\nexport interface GeneratedSQL {\n\tstatements: string[];\n\thash: string;\n}\n\n// Postgres truncates identifiers over 63 bytes. schema/table/column names are\n// each individually capped at 63 (SqlIdentifierSchema / SubgraphNameSchema),\n// but concatenated (`idx_<schema>_<table>_<col>_id`, plus an optional\n// account-scoped schema prefix) they can exceed that — two different columns\n// could then truncate to the same name and silently collide on CREATE INDEX.\n// Route the sort-composite name through here: short names pass through\n// unchanged (human-readable, matches the single-column naming style); an\n// oversized name is truncated and given a content hash suffix so it can't\n// collide with a different oversized name that happens to share a prefix.\nconst MAX_IDENT_BYTES = 63;\nfunction safeIndexName(name: string): string {\n\tif (name.length <= MAX_IDENT_BYTES) return name;\n\tconst hash = createHash(\"sha256\").update(name).digest(\"hex\").slice(0, 8);\n\treturn `${name.slice(0, MAX_IDENT_BYTES - hash.length - 1)}_${hash}`;\n}\n\nfunction escapeLiteralDefault(value: unknown): string {\n\tif (value === null || value === undefined) return \"NULL\";\n\tif (typeof value === \"number\" || typeof value === \"bigint\")\n\t\treturn String(value);\n\tif (typeof value === \"boolean\") return value ? \"TRUE\" : \"FALSE\";\n\treturn `'${String(value).replace(/'/g, \"''\")}'`;\n}\n\n/** True if any column on the table uses full-text `search` (needs the pg_trgm\n * extension before its GIN index can be created). */\nexport function tableNeedsTrgm(tableDef: SubgraphTable): boolean {\n\treturn Object.values(tableDef.columns).some((col) => col.search);\n}\n\n/**\n * All per-table DDL for ONE table — create + meta/user/composite indexes + UNIQUE\n * constraints (NOT foreign keys; see {@link emitForeignKeyDDL}, emitted in a\n * second pass once every referenced table exists). Single-sourced so the full\n * generator and the deployer's additive-create path can't drift — a missing\n * UNIQUE or DEFAULT here would make a handler `upsert ON CONFLICT` fail at runtime.\n */\nexport function emitTableDDL(\n\tschemaName: string,\n\ttableName: string,\n\ttableDef: SubgraphTable,\n): string[] {\n\tconst qualifiedName = `${quotePgIdent(schemaName)}.${quotePgIdent(tableName)}`;\n\tconst statements: string[] = [];\n\n\tconst columnDefs: string[] = [\n\t\t\"_id BIGSERIAL PRIMARY KEY\",\n\t\t\"_block_height BIGINT NOT NULL\",\n\t\t\"_tx_id TEXT NOT NULL\",\n\t\t\"_created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()\",\n\t];\n\tfor (const [colName, col] of Object.entries(tableDef.columns)) {\n\t\tconst sqlType = TYPE_MAP[col.type];\n\t\tconst nullable = col.nullable ? \"\" : \" NOT NULL\";\n\t\tlet colDef = `${quotePgIdent(colName)} ${sqlType}${nullable}`;\n\t\tif (col.default !== undefined) {\n\t\t\tcolDef += ` DEFAULT ${escapeLiteralDefault(col.default)}`;\n\t\t}\n\t\t// uint is unsigned by definition — fail loudly instead of silently\n\t\t// storing a negative (fix-f040 B4). Handlers run in chain order, so a\n\t\t// legitimate same-block receive-then-spend never trips this.\n\t\tif (col.type === \"uint\") {\n\t\t\tcolDef += ` CHECK (${quotePgIdent(colName)} >= 0)`;\n\t\t}\n\t\tcolumnDefs.push(colDef);\n\t}\n\tstatements.push(\n\t\t`CREATE TABLE IF NOT EXISTS ${qualifiedName} (\\n ${columnDefs.join(\",\\n \")}\\n)`,\n\t);\n\n\t// Auto-indexes on meta columns.\n\tstatements.push(\n\t\t`CREATE INDEX IF NOT EXISTS ${quotePgIdent(`idx_${schemaName}_${tableName}_block_height`)} ON ${qualifiedName} (_block_height)`,\n\t);\n\tstatements.push(\n\t\t`CREATE INDEX IF NOT EXISTS ${quotePgIdent(`idx_${schemaName}_${tableName}_tx_id`)} ON ${qualifiedName} (_tx_id)`,\n\t);\n\n\t// Single-column indexes, plus a composite `(col, \"_id\")` sort index.\n\t// `/v1`'s `?_sort=<col>&_order=` keyset predicate compares `(col, \"_id\")`\n\t// and orders by `col, \"_id\"` — a composite index matches that exactly, so\n\t// deep pages on a low-cardinality column become an index-only scan instead\n\t// of a Filter/re-sort within each value group. The single-column index\n\t// stays too: it still serves plain equality filters (`?col=value`).\n\tfor (const [colName, col] of Object.entries(tableDef.columns)) {\n\t\tif (col.indexed) {\n\t\t\tstatements.push(\n\t\t\t\t`CREATE INDEX IF NOT EXISTS ${quotePgIdent(`idx_${schemaName}_${tableName}_${colName}`)} ON ${qualifiedName} (${quotePgIdent(colName)})`,\n\t\t\t);\n\t\t\tstatements.push(\n\t\t\t\t`CREATE INDEX IF NOT EXISTS ${quotePgIdent(safeIndexName(`idx_${schemaName}_${tableName}_${colName}_id`))} ON ${qualifiedName} (${quotePgIdent(colName)}, ${quotePgIdent(\"_id\")})`,\n\t\t\t);\n\t\t}\n\t}\n\n\t// Trigram GIN indexes for search columns.\n\tfor (const [colName, col] of Object.entries(tableDef.columns)) {\n\t\tif (col.search) {\n\t\t\tstatements.push(\n\t\t\t\t`CREATE INDEX IF NOT EXISTS ${quotePgIdent(`idx_${schemaName}_${tableName}_${colName}_trgm`)} ON ${qualifiedName} USING gin (${quotePgIdent(colName)} gin_trgm_ops)`,\n\t\t\t);\n\t\t}\n\t}\n\n\t// Composite indexes.\n\tif (tableDef.indexes) {\n\t\tfor (let i = 0; i < tableDef.indexes.length; i++) {\n\t\t\t// biome-ignore lint/style/noNonNullAssertion: value is non-null after preceding check or by construction; TS narrowing limitation\n\t\t\tconst cols = tableDef.indexes[i]!;\n\t\t\tconst idxName = quotePgIdent(\n\t\t\t\t`idx_${schemaName}_${tableName}_composite_${i}`,\n\t\t\t);\n\t\t\tstatements.push(\n\t\t\t\t`CREATE INDEX IF NOT EXISTS ${idxName} ON ${qualifiedName} (${cols.map(quotePgIdent).join(\", \")})`,\n\t\t\t);\n\t\t}\n\t}\n\n\t// Unique constraints (required for upsert ON CONFLICT).\n\tif (tableDef.uniqueKeys) {\n\t\tfor (let i = 0; i < tableDef.uniqueKeys.length; i++) {\n\t\t\t// biome-ignore lint/style/noNonNullAssertion: value is non-null after preceding check or by construction; TS narrowing limitation\n\t\t\tconst cols = tableDef.uniqueKeys[i]!;\n\t\t\tconst constraintName = quotePgIdent(\n\t\t\t\t`uq_${schemaName}_${tableName}_${cols.join(\"_\")}`,\n\t\t\t);\n\t\t\tstatements.push(\n\t\t\t\t`ALTER TABLE ${qualifiedName} ADD CONSTRAINT ${constraintName} UNIQUE (${cols.map(quotePgIdent).join(\", \")})`,\n\t\t\t);\n\t\t}\n\t}\n\n\treturn statements;\n}\n\n/**\n * Per-schema revert journal. Before every keyed mutation (upsert / increment /\n * update / delete) the flush records the row's prior state; a reorg restores\n * those states instead of deleting whole rows by `_block_height` — which is\n * only correct for append-only tables, not accumulators (fix-f040 B2).\n * `prev_row IS NULL` marks a row first created by the journaled op.\n */\nexport function emitJournalDDL(schemaName: string): string[] {\n\treturn [\n\t\t`CREATE TABLE IF NOT EXISTS ${schemaName}._journal (\n _jid BIGSERIAL PRIMARY KEY,\n block_height BIGINT NOT NULL,\n table_name TEXT NOT NULL,\n row_key JSONB NOT NULL,\n prev_row JSONB,\n _created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()\n)`,\n\t\t`CREATE INDEX IF NOT EXISTS idx_${schemaName}_journal_height ON ${schemaName}._journal (block_height)`,\n\t];\n}\n\n/**\n * Storage for factory-discovered addresses.\n *\n * `block_height` is what makes the set reorg-scoped: the reorg handler\n * deletes rows at or above the fork alongside the data tables, so an address\n * revealed on an orphaned chain does not linger in the matcher forever\n * (the failure mode a set kept outside the rollback model would have).\n */\nexport function emitFactoryDDL(schemaName: string): string[] {\n\treturn [\n\t\t`CREATE TABLE IF NOT EXISTS ${schemaName}._factory_addresses (\n source_name TEXT NOT NULL,\n address TEXT NOT NULL,\n block_height BIGINT NOT NULL,\n _created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n PRIMARY KEY (source_name, address)\n)`,\n\t\t`CREATE INDEX IF NOT EXISTS idx_${schemaName}_factory_height ON ${schemaName}._factory_addresses (block_height)`,\n\t];\n}\n\n/** Foreign-key DDL for one table's relations. Emit AFTER every referenced table\n * exists; references require the target columns to be a UNIQUE key. */\nexport function emitForeignKeyDDL(\n\tschemaName: string,\n\ttableName: string,\n\ttableDef: SubgraphTable,\n): string[] {\n\treturn (tableDef.relations ?? []).map((rel) => {\n\t\tconst constraintName = quotePgIdent(\n\t\t\t`fk_${schemaName}_${tableName}_${rel.name}`,\n\t\t);\n\t\treturn (\n\t\t\t`ALTER TABLE ${quotePgIdent(schemaName)}.${quotePgIdent(tableName)} ADD CONSTRAINT ${constraintName} ` +\n\t\t\t`FOREIGN KEY (${rel.fields.map(quotePgIdent).join(\", \")}) ` +\n\t\t\t`REFERENCES ${quotePgIdent(schemaName)}.${quotePgIdent(rel.references)} (${rel.referencedColumns.map(quotePgIdent).join(\", \")})`\n\t\t);\n\t});\n}\n\n/**\n * Generates PostgreSQL DDL statements for a subgraph definition.\n * Creates a dedicated schema `subgraph_<name>` with one table per schema entry,\n * each with auto-columns and indexes.\n */\nexport function generateSubgraphSQL(\n\tdef: SubgraphDefinition,\n\tschemaNameOverride?: string,\n): GeneratedSQL {\n\tconst schemaName = schemaNameOverride ?? pgSchemaName(def.name);\n\tconst statements: string[] = [];\n\n\t// Check if any column uses search (trigram)\n\tconst needsTrgm = Object.values(def.schema).some((table) =>\n\t\tObject.values(table.columns).some((col) => col.search),\n\t);\n\n\tif (needsTrgm) {\n\t\tstatements.push(\"CREATE EXTENSION IF NOT EXISTS pg_trgm\");\n\t}\n\n\t// Schema namespace\n\tstatements.push(`CREATE SCHEMA IF NOT EXISTS ${schemaName}`);\n\n\t// One table per schema entry (single-sourced per-table DDL).\n\tfor (const [tableName, tableDef] of Object.entries(def.schema)) {\n\t\tstatements.push(...emitTableDDL(schemaName, tableName, tableDef));\n\t}\n\n\t// Revert journal (one per schema) — see emitJournalDDL.\n\tstatements.push(...emitJournalDDL(schemaName));\n\t// Only when a source actually uses a factory — no dead table otherwise.\n\tif (\n\t\tObject.values(def.sources ?? {}).some(\n\t\t\t(src) => (src as { factory?: unknown }).factory !== undefined,\n\t\t)\n\t) {\n\t\tstatements.push(...emitFactoryDDL(schemaName));\n\t}\n\n\t// Foreign keys are added in a second pass so every referenced table exists.\n\t// These mirror the ORM relations emitted by the codegen (no drift) and require\n\t// the referenced columns to be a UNIQUE key on the target table.\n\tfor (const [tableName, tableDef] of Object.entries(def.schema)) {\n\t\tstatements.push(...emitForeignKeyDDL(schemaName, tableName, tableDef));\n\t}\n\n\t// Hash based on schema structure only — version intentionally excluded\n\t// so server-managed version bumps don't look like schema changes\n\tconst hashInput = JSON.stringify(\n\t\t{\n\t\t\tname: def.name,\n\t\t\tschema: def.schema,\n\t\t\tsources: def.sources,\n\t\t},\n\t\t(_key, value) => (typeof value === \"bigint\" ? value.toString() : value),\n\t);\n\t// node crypto (not Bun.hash) so the published node-runtime `sl` CLI can\n\t// compute schema hashes too (e.g. `sl subgraphs spec`).\n\tconst hash = createHash(\"sha256\").update(hashInput).digest(\"hex\");\n\n\treturn { statements, hash };\n}\n",
|
|
7
7
|
"// Re-export canonical pgSchemaName from shared\nexport { pgSchemaName } from \"@secondlayer/shared/db/queries/subgraphs\";\n\n/**\n * Double-quotes a Postgres identifier unless it's already a safe bare\n * identifier, escaping any embedded double quotes. Defense-in-depth for the\n * DDL emitters: every name reaching them (schema/table/column names, and the\n * composite names generator.ts builds from them) is validated upstream\n * (`SqlIdentifierSchema` / `SubgraphNameSchema`), so this is a no-op for every\n * currently-valid name — output stays byte-identical. It only changes\n * anything if a hostile name (embedded quote, semicolon, whitespace, ...)\n * somehow reached this far, turning it into an inert quoted identifier\n * instead of raw SQL.\n */\nexport function quotePgIdent(name: string): string {\n\tif (/^[a-z_][a-z0-9_]*$/i.test(name)) return name;\n\treturn `\"${name.replace(/\"/g, '\"\"')}\"`;\n}\n\n/** `user_account` → `userAccount`. Column and variable names in every emitted\n * ORM surface go through this. */\nexport function snakeToCamel(name: string): string {\n\treturn name.replace(/_([a-z0-9])/g, (_, c: string) => c.toUpperCase());\n}\n\n/** `user_account` → `UserAccount`. Type/model names for one table must agree\n * across the Prisma, Drizzle, Kysely, and index-codegen emitters — a user can\n * import from more than one, so this lives here rather than per-generator. */\nexport function pascalCase(name: string): string {\n\tconst camel = snakeToCamel(name);\n\treturn camel.charAt(0).toUpperCase() + camel.slice(1);\n}\n",
|
|
8
8
|
"import { getSourceDb } from \"@secondlayer/shared/db\";\nimport type { Database } from \"@secondlayer/shared/db/schema\";\nimport { logger } from \"@secondlayer/shared/logger\";\nimport { http, createPublicClient } from \"@secondlayer/stacks\";\nimport {\n\tContractResponseError,\n\ttype UnwrapResponse,\n\tbuildFunctionArgs,\n\tisResponseOutput,\n\treadContract,\n} from \"@secondlayer/stacks/actions\";\nimport type { ClarityValue } from \"@secondlayer/stacks/clarity\";\nimport type {\n\tAbiContract,\n\tAbiFunction,\n\tAbiType,\n\tExtractFunctionArgs,\n\tExtractFunctionOutput,\n\tExtractReadOnlyFunctions,\n\tToCamelCase,\n} from \"@secondlayer/stacks/clarity\";\nimport {\n\tclarityValueToJSUntyped,\n\tdeserializeCV,\n\tnormalizeAbi,\n\tserializeCV,\n\ttoCamelCase,\n} from \"@secondlayer/stacks/clarity\";\nimport type { Kysely } from \"kysely\";\n\n/**\n * How long a read stays valid.\n *\n * - `per-block` (default): pinned to the block being processed, cached under\n * its `index_block_hash`. Sound for any read-only function — reindexing the\n * same block always returns the same value, and a reorg-replaced block has a\n * different id so it can't inherit the orphaned answer.\n * - `contract-constant`: the caller asserts the value cannot change for this\n * contract and these args (SIP-010 `get-decimals`/`get-symbol`), so it is\n * resolved ONCE instead of once per block. This is the mode that makes a\n * backfill affordable — under `per-block` every block is a distinct key and\n * therefore a distinct RPC. Declaring it on a value that does change pins the\n * first answer forever, so it is opt-in and never inferred.\n */\nexport type ChainReadCacheMode = \"per-block\" | \"contract-constant\";\n\nexport type ChainReadOptions = { cache?: ChainReadCacheMode };\n\n/**\n * The chain-read surface, fully typed by an ABI.\n *\n * Shaped like `getContract` from `@secondlayer/stacks` — the same ABI in, the\n * same camelCased read methods out — minus `call`/`buildCall`: a handler\n * indexes the chain, it never writes to it.\n *\n * Reached through {@link readContractAt} rather than off `ctx.client`\n * directly: an ABI-generic method living on the context interface makes every\n * structural comparison of a subgraph definition instantiate it, which exceeds\n * TS's depth budget. At a call site the ABI is already concrete and it costs\n * nothing.\n */\nexport interface ChainReadClient {\n\t/**\n\t * Read-only methods of a contract, evaluated against the exact block being\n\t * processed.\n\t *\n\t * Every call is pinned to the block's `index_block_hash`, so a handler is a\n\t * pure function of its block: reindexing a range produces byte-identical\n\t * rows. Reading at the node's tip instead would make the same reindex\n\t * return different values — that is the corruption this refuses to allow,\n\t * so a block whose id was never persisted throws rather than falling back.\n\t *\n\t * Results are memoized in Postgres, so a value is fetched once per block\n\t * rather than once per event (or once per contract with\n\t * `cache: \"contract-constant\"`).\n\t */\n\tcontract<const C extends AbiContract>(\n\t\tcontractId: string,\n\t\tabi: C,\n\t\toptions?: ChainReadOptions,\n\t): { read: ChainReadMethods<C> };\n}\n\n/**\n * The camelCased read methods of an ABI. Spelled out rather than reused from\n * `ContractInstance<C>[\"read\"]`: that type is a conditional over the codegen\n * brand, and evaluating it wherever a subgraph definition is structurally\n * compared pushes TS past its instantiation depth.\n */\nexport type ChainReadMethods<C extends AbiContract> = {\n\t[N in ExtractReadOnlyFunctions<C> as ToCamelCase<N>]: (\n\t\targs: ExtractFunctionArgs<C, N>,\n\t) => Promise<UnwrapResponse<ExtractFunctionOutput<C, N>>>;\n};\n\n/**\n * `ChainReadClient` with the ABI generic erased. Structurally cheap, so the\n * base `SubgraphContext` can carry it; `TypedSubgraphContext` uses the real\n * one and handlers get full inference.\n */\nexport interface ErasedChainReadClient {\n\t// `abi: unknown`, not `AbiContract`: naming the ABI type here drags its\n\t// (deeply recursive) definition into every structural comparison of a\n\t// subgraph definition. `readContractAt` constrains it properly.\n\tcontract(\n\t\tcontractId: string,\n\t\tabi: unknown,\n\t\toptions?: ChainReadOptions,\n\t): {\n\t\tread: Record<string, (args?: Record<string, unknown>) => Promise<unknown>>;\n\t};\n}\n\n/**\n * Typed read methods for one contract, from a handler.\n *\n * ```ts\n * const token = readContractAt(ctx, contractId, SIP010_ABI, {\n * cache: \"contract-constant\",\n * });\n * const decimals = await token.read.getDecimals({}); // bigint\n * ```\n */\nexport function readContractAt<const C extends AbiContract>(\n\tctx: { client: ErasedChainReadClient },\n\tcontractId: string,\n\tabi: C,\n\toptions?: ChainReadOptions,\n): { read: ChainReadMethods<C> } {\n\treturn ctx.client.contract(contractId, abi, options) as unknown as {\n\t\tread: ChainReadMethods<C>;\n\t};\n}\n\nexport class ChainReadError extends Error {\n\toverride name = \"ChainReadError\";\n}\n\n/**\n * Node transport for handler reads. Deliberately its own client rather than a\n * shared singleton: `retryCount: 0` keeps a slow node from multiplying into the\n * block's retry budget (`processBlockWithRetry` already owns retries), and the\n * concurrency gate below bounds how much of a backfill can hit the node at once.\n */\nfunction nodeClient(rpcUrl: string) {\n\treturn createPublicClient({\n\t\ttransport: http(rpcUrl, { retryCount: 0, timeout: 10_000 }),\n\t});\n}\n\n/**\n * Cap concurrent node reads across all handlers in this process. A handler that\n * reads on every event turns a 100-block batch into thousands of in-flight\n * requests otherwise — enough to knock over the node the indexer depends on.\n */\nclass ConcurrencyGate {\n\tprivate active = 0;\n\tprivate queue: Array<() => void> = [];\n\n\tconstructor(private readonly limit: number) {}\n\n\tasync run<T>(fn: () => Promise<T>): Promise<T> {\n\t\tif (this.active >= this.limit) {\n\t\t\tawait new Promise<void>((resolve) => this.queue.push(resolve));\n\t\t}\n\t\tthis.active++;\n\t\ttry {\n\t\t\treturn await fn();\n\t\t} finally {\n\t\t\tthis.active--;\n\t\t\tthis.queue.shift()?.();\n\t\t}\n\t}\n}\n\nconst DEFAULT_MAX_CONCURRENT_READS = 4;\n\nfunction maxConcurrentReads(): number {\n\tconst raw = process.env.SUBGRAPH_CHAIN_READ_CONCURRENCY;\n\tconst parsed = raw ? Number.parseInt(raw, 10) : Number.NaN;\n\treturn Number.isFinite(parsed) && parsed > 0\n\t\t? parsed\n\t\t: DEFAULT_MAX_CONCURRENT_READS;\n}\n\nconst gate = new ConcurrencyGate(maxConcurrentReads());\n\n/** Stable key for an arg set — property order must not fork a cache entry. */\nfunction hashArgs(args: readonly ClarityValue[]): string {\n\tconst serialized = args.map((arg) => serializeCV(arg)).join(\",\");\n\treturn Bun.hash(serialized).toString(16);\n}\n\nfunction findFunction(abi: AbiContract, name: string): AbiFunction {\n\tconst fn = abi.functions.find((f) => f.name === name) as\n\t\t| AbiFunction\n\t\t| undefined;\n\tif (!fn) {\n\t\tthrow new ChainReadError(`No function \"${name}\" in the supplied ABI.`);\n\t}\n\tif (fn.access !== \"read-only\") {\n\t\tthrow new ChainReadError(\n\t\t\t`\"${name}\" is ${fn.access}, not read-only — a handler cannot call it.`,\n\t\t);\n\t}\n\treturn fn;\n}\n\nexport type ChainReadContext = {\n\tblockHeight: number;\n\tindexBlockHash: string | null | undefined;\n\trpcUrl?: string;\n\tdb?: Kysely<Database>;\n};\n\n/**\n * Build the `ctx.client` surface for one block. Generic lives on the METHOD,\n * not here, so a handler's ABI narrows per call without infecting\n * `SubgraphContext` with a type parameter.\n */\n/**\n * Build the `ctx.client` surface for one block. The ABI generic lives on\n * `contract()`, not here, so a handler's types narrow per contract without\n * `SubgraphContext` carrying a type parameter.\n */\nexport function createChainReadClient(ctx: ChainReadContext): ChainReadClient {\n\t// The ABI generic is erased inside the implementation on purpose:\n\t// re-resolving `ExtractFunctionArgs` against an unfixed type parameter is\n\t// what pushes TS past its instantiation depth on a real-sized ABI.\n\tconst readValue = async (\n\t\tcontractId: string,\n\t\tabi: AbiContract,\n\t\tfunctionName: string,\n\t\targs: Record<string, unknown>,\n\t\toptions: ChainReadOptions,\n\t): Promise<unknown> => {\n\t\tconst rpcUrl = ctx.rpcUrl ?? process.env.STACKS_NODE_RPC_URL;\n\t\tif (!rpcUrl) {\n\t\t\tthrow new ChainReadError(\n\t\t\t\t\"ctx.client needs a Stacks node: set STACKS_NODE_RPC_URL on the subgraph processor.\",\n\t\t\t);\n\t\t}\n\n\t\tconst constant = options.cache === \"contract-constant\";\n\t\tif (!constant && !ctx.indexBlockHash) {\n\t\t\tthrow new ChainReadError(\n\t\t\t\t`Block ${ctx.blockHeight} has no index_block_hash, so a read cannot be pinned to it. Reading at the node's tip would make this handler non-deterministic (the same reindex would produce different rows). Re-ingest the block, or pass cache: \"contract-constant\" if the value genuinely cannot change.`,\n\t\t\t);\n\t\t}\n\n\t\tconst fn = findFunction(abi, functionName);\n\t\tconst clarityArgs = buildFunctionArgs(fn, args);\n\t\tconst db = ctx.db ?? getSourceDb();\n\t\tconst argsHash = hashArgs(clarityArgs);\n\t\tconst pinnedTo = constant ? null : (ctx.indexBlockHash as string);\n\n\t\tconst cached = await db\n\t\t\t.selectFrom(\"chain_read_cache\")\n\t\t\t.select(\"result_hex\")\n\t\t\t.where(\"contract_id\", \"=\", contractId)\n\t\t\t.where(\"function_name\", \"=\", fn.name)\n\t\t\t.where(\"args_hash\", \"=\", argsHash)\n\t\t\t.where((eb) =>\n\t\t\t\tpinnedTo === null\n\t\t\t\t\t? eb(\"index_block_hash\", \"is\", null)\n\t\t\t\t\t: eb(\"index_block_hash\", \"=\", pinnedTo),\n\t\t\t)\n\t\t\t.executeTakeFirst();\n\n\t\tconst resultHex =\n\t\t\tcached?.result_hex ??\n\t\t\t(await gate.run(async () => {\n\t\t\t\t// A constant read still pins to this block where it can: \"cannot\n\t\t\t\t// change\" is a claim about future blocks, not a license to read\n\t\t\t\t// a tip that may be ahead of the one being processed.\n\t\t\t\tif (!ctx.indexBlockHash) {\n\t\t\t\t\t// The one path where an UNPINNED read happens. Reachable only\n\t\t\t\t\t// in constant mode on a block with no persisted id — which is\n\t\t\t\t\t// exactly what the pinning error tells you to do — so it is\n\t\t\t\t\t// allowed, but never silently.\n\t\t\t\t\tlogger.warn(\n\t\t\t\t\t\t\"Chain read is not pinned to a block (no index_block_hash)\",\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcontractId,\n\t\t\t\t\t\t\tfunctionName: fn.name,\n\t\t\t\t\t\t\tblockHeight: ctx.blockHeight,\n\t\t\t\t\t\t\tnote: 'cache: \"contract-constant\" asserts this value cannot change; the node answered at its own tip',\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst value = await readContract(nodeClient(rpcUrl), {\n\t\t\t\t\tcontract: contractId,\n\t\t\t\t\tfunctionName: fn.name,\n\t\t\t\t\targs: clarityArgs,\n\t\t\t\t\ttip: ctx.indexBlockHash ?? undefined,\n\t\t\t\t});\n\t\t\t\treturn serializeCV(value);\n\t\t\t}));\n\n\t\tif (!cached) {\n\t\t\tawait db\n\t\t\t\t.insertInto(\"chain_read_cache\")\n\t\t\t\t.values({\n\t\t\t\t\tcontract_id: contractId,\n\t\t\t\t\tfunction_name: fn.name,\n\t\t\t\t\targs_hash: argsHash,\n\t\t\t\t\tindex_block_hash: pinnedTo,\n\t\t\t\t\tblock_height: constant ? null : ctx.blockHeight,\n\t\t\t\t\tresult_hex: resultHex,\n\t\t\t\t})\n\t\t\t\t// Two handlers in the same batch can race to the same key; the\n\t\t\t\t// value is identical either way, so the loser keeps its own.\n\t\t\t\t.onConflict((oc) => oc.doNothing())\n\t\t\t\t.execute();\n\t\t}\n\n\t\tconst value = deserializeCV(resultHex);\n\t\tconst js = clarityValueToJSUntyped(fn.outputs as AbiType, value);\n\n\t\tif (isResponseOutput(fn.outputs as AbiType)) {\n\t\t\tconst response = js as { ok?: unknown; err?: unknown };\n\t\t\tif (\"ok\" in response) return response.ok;\n\t\t\tthrow new ContractResponseError(\n\t\t\t\t`${contractId}::${fn.name} returned an err response.`,\n\t\t\t\tresponse.err,\n\t\t\t);\n\t\t}\n\t\treturn js;\n\t};\n\n\treturn {\n\t\tcontract(contractId: string, rawAbi: AbiContract, options = {}) {\n\t\t\t// Accept a raw Hiro/Clarinet ABI as well as a normalized one — raw\n\t\t\t// ABIs wrap `outputs` as `{ type: … }`, which the JS bridge can't read.\n\t\t\tconst abi = normalizeAbi(rawAbi);\n\t\t\tconst camelToKebab = new Map<string, string>();\n\t\t\tfor (const fn of abi.functions) {\n\t\t\t\tcamelToKebab.set(toCamelCase(fn.name), fn.name);\n\t\t\t}\n\n\t\t\tconst read = new Proxy(\n\t\t\t\t{},\n\t\t\t\t{\n\t\t\t\t\tget(_target, prop: string) {\n\t\t\t\t\t\tconst fnName = camelToKebab.get(prop) ?? prop;\n\t\t\t\t\t\treturn (args: Record<string, unknown> = {}) =>\n\t\t\t\t\t\t\treadValue(contractId, abi, fnName, args, options);\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t);\n\n\t\t\treturn { read } as never;\n\t\t},\n\t};\n}\n",
|
|
9
9
|
"import { cvToValue, deserializeCV } from \"@secondlayer/stacks/clarity\";\n\n/**\n * Decode a hex-encoded Clarity value to a JS object.\n * Returns original value on failure.\n */\nexport function decodeClarityValue(hex: string): unknown {\n\ttry {\n\t\tconst cleanHex = hex.startsWith(\"0x\") ? hex.slice(2) : hex;\n\t\tconst cv = deserializeCV(cleanHex);\n\t\treturn cvToValue(cv);\n\t} catch {\n\t\treturn hex;\n\t}\n}\n\n/**\n * Recursively decode all hex-encoded Clarity values in an object.\n * Any string starting with \"0x\" and longer than 10 chars is attempted.\n */\nexport function decodeEventData(data: unknown): unknown {\n\tif (typeof data === \"string\" && data.startsWith(\"0x\") && data.length > 10) {\n\t\treturn decodeClarityValue(data);\n\t}\n\n\tif (Array.isArray(data)) {\n\t\treturn data.map(decodeEventData);\n\t}\n\n\tif (typeof data === \"object\" && data !== null) {\n\t\tconst decoded: Record<string, unknown> = {};\n\t\tfor (const [key, value] of Object.entries(data)) {\n\t\t\tdecoded[key] = decodeEventData(value);\n\t\t}\n\t\treturn decoded;\n\t}\n\n\treturn data;\n}\n\n/**\n * Decode function args array (hex-encoded Clarity values).\n */\nexport function decodeFunctionArgs(args: string[]): unknown[] {\n\treturn args.map(decodeClarityValue);\n}\n",
|
|
10
|
-
"import { getErrorMessage } from \"@secondlayer/shared\";\nimport { logger } from \"@secondlayer/shared/logger\";\nimport {\n\tclarityValueToJS,\n\tdeserializeCV,\n\ttoCamelCase,\n} from \"@secondlayer/stacks/clarity\";\nimport type {\n\tContractCallFilter,\n\tSubgraphDefinition,\n\tSubgraphFilter,\n} from \"../types.ts\";\nimport { decodeClarityValue, decodeEventData } from \"./clarity.ts\";\nimport type { SubgraphContext } from \"./context.ts\";\nimport { validatePrintPayload } from \"./print-validate.ts\";\nimport type { MatchedTx } from \"./source-matcher.ts\";\n\n/** Max consecutive handler errors before marking subgraph as error */\nconst DEFAULT_ERROR_THRESHOLD = 50;\n\nexport interface RunResult {\n\tprocessed: number;\n\terrors: number;\n\t/** Print events skipped because their decoded payload did not match the\n\t * source's declared `prints` schema. Never an error: skipping keeps the\n\t * block committable, which the checkpoint model requires. */\n\tskipped?: number;\n}\n\n/** Convert kebab-case to camelCase: \"bitcoin-txid\" → \"bitcoinTxid\" */\nfunction camelCase(str: string): string {\n\treturn str.replace(/-([a-z0-9])/g, (_, c) => c.toUpperCase());\n}\n\n/** Recursively camelize all object keys */\nfunction camelizeKeys(obj: unknown): unknown {\n\tif (obj === null || obj === undefined) return obj;\n\tif (typeof obj !== \"object\") return obj;\n\tif (Array.isArray(obj)) return obj.map(camelizeKeys);\n\tconst result: Record<string, unknown> = {};\n\tfor (const [k, v] of Object.entries(obj as Record<string, unknown>)) {\n\t\tresult[camelCase(k)] = camelizeKeys(v);\n\t}\n\treturn result;\n}\n\n/**\n * Decode function_args (hex-encoded ClarityValues) to an array of JS values.\n * Returns decoded values via cvToValue.\n *\n * postgres.js returns JSONB columns as JSON strings rather than parsed objects —\n * parse the string first before checking Array.isArray.\n */\nfunction decodeFunctionArgs(args: unknown): unknown[] {\n\tlet parsed = args;\n\tif (typeof parsed === \"string\") {\n\t\ttry {\n\t\t\tparsed = JSON.parse(parsed);\n\t\t} catch {\n\t\t\treturn [];\n\t\t}\n\t}\n\tif (!Array.isArray(parsed)) return [];\n\treturn parsed.map((arg) => {\n\t\tif (typeof arg === \"string\") return decodeClarityValue(arg);\n\t\treturn arg;\n\t});\n}\n\n/**\n * Decode raw_result (hex-encoded Clarity return value) to JS value.\n */\nfunction decodeRawResult(raw: unknown): unknown {\n\tif (typeof raw === \"string\" && raw.length > 2) {\n\t\treturn decodeClarityValue(raw);\n\t}\n\treturn null;\n}\n\n/** Safely convert a value to BigInt. Handles string, number, bigint. Returns 0n on failure. */\nfunction safeBigInt(val: unknown): bigint {\n\tif (typeof val === \"bigint\") return val;\n\tif (typeof val === \"number\") return BigInt(val);\n\tif (typeof val === \"string\") {\n\t\ttry {\n\t\t\treturn BigInt(val);\n\t\t} catch {\n\t\t\treturn 0n;\n\t\t}\n\t}\n\treturn 0n;\n}\n\n/**\n * Build the named, ABI-decoded `event.input` for a contract_call source that\n * declares an `abi`. Each function arg is decoded via `clarityValueToJS` so the\n * values match the types `ExtractFunctionArgs` promises (Uint8Array buffers,\n * camelCase tuple keys, wrapped responses). Returns undefined when no abi /\n * function match, leaving handlers with the positional `args` only.\n */\nexport function buildContractCallInput(\n\tfilter: ContractCallFilter,\n\ttx: MatchedTx[\"tx\"],\n): Record<string, unknown> | undefined {\n\tconst abi = filter.abi;\n\tconst fnName = tx.function_name;\n\tif (!abi || !fnName) return undefined;\n\tconst fn = abi.functions?.find((f) => f.name === fnName);\n\tif (!fn || !Array.isArray(fn.args)) return undefined;\n\n\tlet rawArgs: unknown = tx.function_args;\n\tif (typeof rawArgs === \"string\") {\n\t\ttry {\n\t\t\trawArgs = JSON.parse(rawArgs);\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\tif (!Array.isArray(rawArgs)) return undefined;\n\n\t// Call through a non-generic cast: clarityValueToJS<T> instantiates the deep\n\t// AbiToTS<T> conditional (TS2589) at runtime call sites. The static types\n\t// come from ContractCallPayload; here we only need its runtime reshaping.\n\tconst decodeArg = clarityValueToJS as unknown as (\n\t\ttype: unknown,\n\t\tcv: unknown,\n\t) => unknown;\n\tconst input: Record<string, unknown> = {};\n\tfn.args.forEach((arg, i) => {\n\t\tconst hex = rawArgs[i];\n\t\tif (typeof hex !== \"string\") return;\n\t\ttry {\n\t\t\tconst clean = hex.startsWith(\"0x\") ? hex.slice(2) : hex;\n\t\t\tinput[toCamelCase(arg.name)] = decodeArg(arg.type, deserializeCV(clean));\n\t\t} catch {\n\t\t\t// Skip args that fail to decode rather than dropping the whole event.\n\t\t}\n\t});\n\treturn input;\n}\n\n/**\n * Build a typed event payload based on the source filter type.\n * Returns the payload the handler will receive.\n */\nexport function buildEventPayload(\n\tfilter: SubgraphFilter,\n\ttx: MatchedTx[\"tx\"],\n\tevent: MatchedTx[\"events\"][0] | null,\n): Record<string, unknown> {\n\tconst txMeta = {\n\t\ttxId: tx.tx_id,\n\t\tsender: tx.sender,\n\t\ttype: tx.type,\n\t\tstatus: tx.status,\n\t\tcontractId: tx.contract_id ?? null,\n\t\tfunctionName: tx.function_name ?? null,\n\t};\n\n\t// Decoded function args + result for contract_call payloads\n\tconst decodedArgs = decodeFunctionArgs(tx.function_args);\n\tconst decodedResult = decodeRawResult(tx.raw_result);\n\n\t// No event — tx-level match (contract_call or contract_deploy)\n\tif (!event) {\n\t\tswitch (filter.type) {\n\t\t\tcase \"contract_call\": {\n\t\t\t\tconst input = buildContractCallInput(filter, tx);\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"contract_call\",\n\t\t\t\t\tcontractId: tx.contract_id ?? \"\",\n\t\t\t\t\tfunctionName: tx.function_name ?? \"\",\n\t\t\t\t\tsender: tx.sender,\n\t\t\t\t\targs: decodedArgs,\n\t\t\t\t\t...(input !== undefined ? { input } : {}),\n\t\t\t\t\tresult: decodedResult,\n\t\t\t\t\tresultHex: tx.raw_result ?? null,\n\t\t\t\t\ttx: txMeta,\n\t\t\t\t};\n\t\t\t}\n\t\t\tcase \"contract_deploy\":\n\t\t\t\treturn {\n\t\t\t\t\tcontractId: tx.contract_id ?? \"\",\n\t\t\t\t\tdeployer: tx.sender,\n\t\t\t\t\ttx: txMeta,\n\t\t\t\t};\n\t\t\tdefault:\n\t\t\t\treturn { tx: txMeta };\n\t\t}\n\t}\n\n\t// Decode event data (Clarity values auto-unwrapped via cvToValue)\n\tconst decoded = decodeEventData(event.data) as Record<string, unknown>;\n\n\tswitch (filter.type) {\n\t\t// ── FT events ──\n\t\tcase \"ft_transfer\":\n\t\t\treturn {\n\t\t\t\tsender: decoded.sender as string,\n\t\t\t\trecipient: decoded.recipient as string,\n\t\t\t\tamount: safeBigInt(decoded.amount),\n\t\t\t\tassetIdentifier: decoded.asset_identifier as string,\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\t\tcase \"ft_mint\":\n\t\t\treturn {\n\t\t\t\trecipient: decoded.recipient as string,\n\t\t\t\tamount: safeBigInt(decoded.amount),\n\t\t\t\tassetIdentifier: decoded.asset_identifier as string,\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\t\tcase \"ft_burn\":\n\t\t\treturn {\n\t\t\t\tsender: decoded.sender as string,\n\t\t\t\tamount: safeBigInt(decoded.amount),\n\t\t\t\tassetIdentifier: decoded.asset_identifier as string,\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\n\t\t// ── NFT events ──\n\t\t// tokenId decodes from the canonical hex (`raw_value`), not the node's\n\t\t// verbose serde-tagged `value` (`{UInt:223}`). The hex is source-\n\t\t// independent — present in both the DB tap and the Index API — so a\n\t\t// subgraph yields the same clean tokenId (e.g. 223n) on either source.\n\t\tcase \"nft_transfer\":\n\t\t\treturn {\n\t\t\t\tsender: decoded.sender as string,\n\t\t\t\trecipient: decoded.recipient as string,\n\t\t\t\ttokenId: decoded.raw_value ?? decoded.value,\n\t\t\t\tassetIdentifier: decoded.asset_identifier as string,\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\t\tcase \"nft_mint\":\n\t\t\treturn {\n\t\t\t\trecipient: decoded.recipient as string,\n\t\t\t\ttokenId: decoded.raw_value ?? decoded.value,\n\t\t\t\tassetIdentifier: decoded.asset_identifier as string,\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\t\tcase \"nft_burn\":\n\t\t\treturn {\n\t\t\t\tsender: decoded.sender as string,\n\t\t\t\ttokenId: decoded.raw_value ?? decoded.value,\n\t\t\t\tassetIdentifier: decoded.asset_identifier as string,\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\n\t\t// ── STX events ──\n\t\tcase \"stx_transfer\":\n\t\t\treturn {\n\t\t\t\tsender: decoded.sender as string,\n\t\t\t\trecipient: decoded.recipient as string,\n\t\t\t\tamount: safeBigInt(decoded.amount),\n\t\t\t\tmemo: decoded.memo ?? \"\",\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\t\tcase \"stx_mint\":\n\t\t\treturn {\n\t\t\t\trecipient: decoded.recipient as string,\n\t\t\t\tamount: safeBigInt(decoded.amount),\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\t\tcase \"stx_burn\":\n\t\t\treturn {\n\t\t\t\tsender: decoded.sender as string,\n\t\t\t\tamount: safeBigInt(decoded.amount),\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\t\tcase \"stx_lock\":\n\t\t\treturn {\n\t\t\t\tlockedAddress: decoded.locked_address as string,\n\t\t\t\tlockedAmount: safeBigInt(decoded.locked_amount),\n\t\t\t\tunlockHeight: safeBigInt(decoded.unlock_height),\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\n\t\t// ── Print event ──\n\t\tcase \"print_event\": {\n\t\t\t// Decode the print value from the canonical hex (`raw_value`) so it's\n\t\t\t// source-independent and clean — the node's verbose serde-tagged\n\t\t\t// `value` (e.g. `{Optional:{data:null}}`) is not reproducible from the\n\t\t\t// Index API and is no longer used (same rationale as nft tokenId).\n\t\t\t// decodeEventData skips hex ≤10 chars, so decode `raw_value` directly.\n\t\t\tconst rawHex = (event.data as Record<string, unknown> | null)?.raw_value;\n\t\t\tconst rawValue =\n\t\t\t\ttypeof rawHex === \"string\" && rawHex.startsWith(\"0x\")\n\t\t\t\t\t? decodeClarityValue(rawHex)\n\t\t\t\t\t: decoded.value;\n\t\t\t// Extract topic from decoded Clarity value (not raw event topic which is always \"print\")\n\t\t\tconst clarityObj =\n\t\t\t\trawValue && typeof rawValue === \"object\" && !Array.isArray(rawValue)\n\t\t\t\t\t? (rawValue as Record<string, unknown>)\n\t\t\t\t\t: null;\n\t\t\tconst topic = clarityObj?.topic\n\t\t\t\t? String(clarityObj.topic)\n\t\t\t\t: ((decoded.topic as string) ?? \"\");\n\t\t\t// Camelize remaining keys for developer convenience\n\t\t\tconst { topic: _, ...rest } = clarityObj ?? {};\n\t\t\tconst data =\n\t\t\t\tObject.keys(rest).length > 0\n\t\t\t\t\t? (camelizeKeys(rest) as Record<string, unknown>)\n\t\t\t\t\t: rawValue && typeof rawValue !== \"object\"\n\t\t\t\t\t\t? rawValue\n\t\t\t\t\t\t: {};\n\t\t\treturn {\n\t\t\t\tcontractId:\n\t\t\t\t\t(decoded.contract_identifier as string) ?? tx.contract_id ?? \"\",\n\t\t\t\ttopic,\n\t\t\t\tdata: data ?? {},\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\t\t}\n\n\t\t// ── Contract call (with events) ──\n\t\tcase \"contract_call\": {\n\t\t\t// Normalize the spread event Clarity `value` to the decoded canonical\n\t\t\t// (from `raw_value`), so it's identical whether the event came from the\n\t\t\t// DB tap or the Index API — the node's serde-tagged `value` is not\n\t\t\t// reproducible from Index (same rationale as nft tokenId / print).\n\t\t\tconst ccRawHex = (event.data as Record<string, unknown> | null)\n\t\t\t\t?.raw_value;\n\t\t\tconst normalized =\n\t\t\t\ttypeof ccRawHex === \"string\" && ccRawHex.startsWith(\"0x\")\n\t\t\t\t\t? { ...decoded, value: decodeClarityValue(ccRawHex) }\n\t\t\t\t\t: decoded;\n\t\t\tconst input = buildContractCallInput(filter, tx);\n\t\t\treturn {\n\t\t\t\t...normalized,\n\t\t\t\ttype: \"contract_call\",\n\t\t\t\t_eventType: event.type,\n\t\t\t\tcontractId: tx.contract_id ?? \"\",\n\t\t\t\tfunctionName: tx.function_name ?? \"\",\n\t\t\t\tsender: tx.sender,\n\t\t\t\targs: decodedArgs,\n\t\t\t\t...(input !== undefined ? { input } : {}),\n\t\t\t\tresult: decodedResult,\n\t\t\t\tresultHex: tx.raw_result ?? null,\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\t\t}\n\n\t\t// ── Contract deploy ──\n\t\tcase \"contract_deploy\":\n\t\t\treturn {\n\t\t\t\tcontractId: tx.contract_id ?? \"\",\n\t\t\t\tdeployer: tx.sender,\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\n\t\tdefault:\n\t\t\t// Fallback: spread decoded data with tx metadata\n\t\t\treturn {\n\t\t\t\t...decoded,\n\t\t\t\t_eventType: event.type,\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\t}\n}\n\n/**\n * Run a subgraph's keyed handlers against all matched transactions/events.\n *\n * Each MatchedTx carries a sourceName from the matcher. The runner looks up\n * the corresponding handler in subgraph.handlers, falling back to \"*\".\n *\n * Does NOT flush — caller is responsible for flushing ctx after run.\n */\nexport async function runHandlers(\n\tsubgraph: SubgraphDefinition,\n\tmatched: MatchedTx[],\n\tctx: SubgraphContext,\n\topts?: { errorThreshold?: number },\n): Promise<RunResult> {\n\tlet processed = 0;\n\tlet errors = 0;\n\tlet skipped = 0;\n\tconst threshold = opts?.errorThreshold ?? DEFAULT_ERROR_THRESHOLD;\n\n\t// Build filter lookup from sources (supports both array and named object)\n\tconst filterLookup = new Map<string, SubgraphFilter>();\n\tif (!Array.isArray(subgraph.sources)) {\n\t\tfor (const [name, filter] of Object.entries(\n\t\t\tsubgraph.sources as Record<string, SubgraphFilter>,\n\t\t)) {\n\t\t\tfilterLookup.set(name, filter);\n\t\t}\n\t}\n\n\t// Flatten matches to per-event dispatch units and sort into CHAIN order\n\t// (tx_index, then event_index; tx-level matches first within their tx).\n\t// The matcher groups results by source, so without this a block's mints\n\t// all run before (or after) its transfers — a debit could apply before\n\t// the same block's funding credit, which on-chain ordering forbids. Chain\n\t// order makes per-statement invariants (e.g. uint CHECK >= 0) sound.\n\ttype DispatchUnit = {\n\t\ttx: MatchedTx[\"tx\"];\n\t\tsourceName: string;\n\t\tevent: MatchedTx[\"events\"][0] | null;\n\t};\n\tconst units: DispatchUnit[] = [];\n\tfor (const { tx, events, sourceName } of matched) {\n\t\tif (events.length === 0) {\n\t\t\tunits.push({ tx, sourceName, event: null });\n\t\t} else {\n\t\t\tfor (const event of events) units.push({ tx, sourceName, event });\n\t\t}\n\t}\n\tunits.sort(\n\t\t(a, b) =>\n\t\t\t(a.tx.tx_index ?? 0) - (b.tx.tx_index ?? 0) ||\n\t\t\t(a.event?.event_index ?? -1) - (b.event?.event_index ?? -1),\n\t);\n\n\tfor (const { tx, event, sourceName } of units) {\n\t\tif (errors >= threshold) {\n\t\t\tlogger.error(\n\t\t\t\t\"Subgraph error threshold reached, skipping remaining events\",\n\t\t\t\t{\n\t\t\t\t\tsubgraph: subgraph.name,\n\t\t\t\t\terrors,\n\t\t\t\t\tthreshold,\n\t\t\t\t},\n\t\t\t);\n\t\t\treturn { processed, errors, ...(skipped > 0 ? { skipped } : {}) };\n\t\t}\n\n\t\tconst handler =\n\t\t\tsubgraph.handlers[sourceName] ?? subgraph.handlers[\"*\"] ?? null;\n\t\tif (!handler) {\n\t\t\tlogger.warn(\"No handler found for source\", {\n\t\t\t\tsubgraph: subgraph.name,\n\t\t\t\tsourceName,\n\t\t\t\ttxId: tx.tx_id,\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\n\t\tctx.setTx({\n\t\t\ttxId: tx.tx_id,\n\t\t\tsender: tx.sender,\n\t\t\ttype: tx.type,\n\t\t\tstatus: tx.status,\n\t\t\tcontractId: tx.contract_id ?? null,\n\t\t\tfunctionName: tx.function_name ?? null,\n\t\t});\n\n\t\tconst filter = filterLookup.get(sourceName);\n\n\t\t// Checkpoint the ops queue: a handler that throws mid-way must\n\t\t// contribute nothing — a partial flush (e.g. a debit without its\n\t\t// credit) silently corrupts accumulator tables (fix-f040 B6).\n\t\tconst checkpoint = ctx.opsCheckpoint();\n\t\ttry {\n\t\t\tlet payload: Record<string, unknown>;\n\t\t\tif (event === null) {\n\t\t\t\t// Tx-level match (contract_call / contract_deploy)\n\t\t\t\tpayload = filter\n\t\t\t\t\t? buildEventPayload(filter, tx, null)\n\t\t\t\t\t: {\n\t\t\t\t\t\t\ttx: {\n\t\t\t\t\t\t\t\ttxId: tx.tx_id,\n\t\t\t\t\t\t\t\tsender: tx.sender,\n\t\t\t\t\t\t\t\ttype: tx.type,\n\t\t\t\t\t\t\t\tstatus: tx.status,\n\t\t\t\t\t\t\t\tcontractId: tx.contract_id,\n\t\t\t\t\t\t\t\tfunctionName: tx.function_name,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t};\n\t\t\t} else if (filter) {\n\t\t\t\tpayload = buildEventPayload(filter, tx, event);\n\t\t\t} else {\n\t\t\t\tconst decoded = decodeEventData(event.data) as Record<string, unknown>;\n\t\t\t\tpayload = {\n\t\t\t\t\t...decoded,\n\t\t\t\t\t_eventId: event.id,\n\t\t\t\t\t_eventType: event.type,\n\t\t\t\t\t_eventIndex: event.event_index,\n\t\t\t\t\ttx: {\n\t\t\t\t\t\ttxId: tx.tx_id,\n\t\t\t\t\t\tsender: tx.sender,\n\t\t\t\t\t\ttype: tx.type,\n\t\t\t\t\t\tstatus: tx.status,\n\t\t\t\t\t\tcontractId: tx.contract_id,\n\t\t\t\t\t\tfunctionName: tx.function_name,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// Post-decode topic filter for print_event — source-matcher defers this\n\t\t\t// because data.value is raw hex at match time; apply it now after decode.\n\t\t\tif (\n\t\t\t\tevent !== null &&\n\t\t\t\tfilter?.type === \"print_event\" &&\n\t\t\t\tfilter.topic &&\n\t\t\t\tpayload.topic !== filter.topic\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Declared `prints` is the developer's stated payload shape, so a\n\t\t\t// mismatch is a real defect (a contract upgrade, or a declaration\n\t\t\t// that never matched — the bns-names class, where every event\n\t\t\t// decoded to null for an entire deploy). Skip + log rather than\n\t\t\t// write nulls; never throw, which would wedge the block.\n\t\t\tif (event !== null && filter?.type === \"print_event\" && filter.prints) {\n\t\t\t\tconst printPayload = payload as {\n\t\t\t\t\ttopic?: string;\n\t\t\t\t\tdata?: Record<string, unknown>;\n\t\t\t\t};\n\t\t\t\tconst verdict = validatePrintPayload(\n\t\t\t\t\tfilter.prints,\n\t\t\t\t\tprintPayload.topic ?? \"\",\n\t\t\t\t\tprintPayload.data ?? {},\n\t\t\t\t);\n\t\t\t\tif (!verdict.ok) {\n\t\t\t\t\tskipped++;\n\t\t\t\t\tlogger.warn(\"Print payload does not match declared prints schema\", {\n\t\t\t\t\t\tsubgraph: subgraph.name,\n\t\t\t\t\t\tsourceName,\n\t\t\t\t\t\ttopic: printPayload.topic,\n\t\t\t\t\t\ttxId: tx.tx_id,\n\t\t\t\t\t\treason: verdict.reason,\n\t\t\t\t\t});\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tawait handler(payload, ctx);\n\t\t\tprocessed++;\n\t\t} catch (err) {\n\t\t\tctx.rollbackTo(checkpoint);\n\t\t\terrors++;\n\t\t\tlogger.error(\"Subgraph handler error\", {\n\t\t\t\tsubgraph: subgraph.name,\n\t\t\t\tsourceName,\n\t\t\t\ttxId: tx.tx_id,\n\t\t\t\t...(event !== null ? { eventId: event.id, eventType: event.type } : {}),\n\t\t\t\terror: getErrorMessage(err),\n\t\t\t});\n\t\t}\n\t}\n\n\treturn { processed, errors, ...(skipped > 0 ? { skipped } : {}) };\n}\n",
|
|
10
|
+
"import { getErrorMessage } from \"@secondlayer/shared\";\nimport { logger } from \"@secondlayer/shared/logger\";\nimport {\n\tclarityValueToJS,\n\tdeserializeCV,\n\ttoCamelCase,\n} from \"@secondlayer/stacks/clarity\";\nimport type {\n\tContractCallFilter,\n\tSubgraphDefinition,\n\tSubgraphFilter,\n} from \"../types.ts\";\nimport { decodeClarityValue, decodeEventData } from \"./clarity.ts\";\nimport type { SubgraphContext } from \"./context.ts\";\nimport { validatePrintPayload } from \"./print-validate.ts\";\nimport type { MatchedTx } from \"./source-matcher.ts\";\n\n/** Max consecutive handler errors before marking subgraph as error */\nconst DEFAULT_ERROR_THRESHOLD = 50;\n\nexport interface RunResult {\n\tprocessed: number;\n\terrors: number;\n\t/** Print events skipped because their decoded payload did not match the\n\t * source's declared `prints` schema. Never an error: skipping keeps the\n\t * block committable, which the checkpoint model requires. */\n\tskipped?: number;\n}\n\n/** Convert kebab-case to camelCase: \"bitcoin-txid\" → \"bitcoinTxid\" */\nfunction camelCase(str: string): string {\n\treturn str.replace(/-([a-z0-9])/g, (_, c) => c.toUpperCase());\n}\n\n/** Recursively camelize all object keys */\nfunction camelizeKeys(obj: unknown): unknown {\n\tif (obj === null || obj === undefined) return obj;\n\tif (typeof obj !== \"object\") return obj;\n\tif (Array.isArray(obj)) return obj.map(camelizeKeys);\n\tconst result: Record<string, unknown> = {};\n\tfor (const [k, v] of Object.entries(obj as Record<string, unknown>)) {\n\t\tresult[camelCase(k)] = camelizeKeys(v);\n\t}\n\treturn result;\n}\n\n/**\n * Decode function_args (hex-encoded ClarityValues) to an array of JS values.\n * Returns decoded values via cvToValue.\n *\n * The string branch is legacy tolerance, not driver behaviour: rows written\n * before 2026-08-12 hold a jsonb *string* containing JSON because the writer\n * pre-serialized the array (see backfill-function-args.ts). Correct rows arrive\n * as arrays. Keep both paths until every environment has been backfilled.\n */\nfunction decodeFunctionArgs(args: unknown): unknown[] {\n\tlet parsed = args;\n\tif (typeof parsed === \"string\") {\n\t\ttry {\n\t\t\tparsed = JSON.parse(parsed);\n\t\t} catch {\n\t\t\treturn [];\n\t\t}\n\t}\n\tif (!Array.isArray(parsed)) return [];\n\treturn parsed.map((arg) => {\n\t\tif (typeof arg === \"string\") return decodeClarityValue(arg);\n\t\treturn arg;\n\t});\n}\n\n/**\n * Decode raw_result (hex-encoded Clarity return value) to JS value.\n */\nfunction decodeRawResult(raw: unknown): unknown {\n\tif (typeof raw === \"string\" && raw.length > 2) {\n\t\treturn decodeClarityValue(raw);\n\t}\n\treturn null;\n}\n\n/** Safely convert a value to BigInt. Handles string, number, bigint. Returns 0n on failure. */\nfunction safeBigInt(val: unknown): bigint {\n\tif (typeof val === \"bigint\") return val;\n\tif (typeof val === \"number\") return BigInt(val);\n\tif (typeof val === \"string\") {\n\t\ttry {\n\t\t\treturn BigInt(val);\n\t\t} catch {\n\t\t\treturn 0n;\n\t\t}\n\t}\n\treturn 0n;\n}\n\n/**\n * Build the named, ABI-decoded `event.input` for a contract_call source that\n * declares an `abi`. Each function arg is decoded via `clarityValueToJS` so the\n * values match the types `ExtractFunctionArgs` promises (Uint8Array buffers,\n * camelCase tuple keys, wrapped responses). Returns undefined when no abi /\n * function match, leaving handlers with the positional `args` only.\n */\nexport function buildContractCallInput(\n\tfilter: ContractCallFilter,\n\ttx: MatchedTx[\"tx\"],\n): Record<string, unknown> | undefined {\n\tconst abi = filter.abi;\n\tconst fnName = tx.function_name;\n\tif (!abi || !fnName) return undefined;\n\tconst fn = abi.functions?.find((f) => f.name === fnName);\n\tif (!fn || !Array.isArray(fn.args)) return undefined;\n\n\tlet rawArgs: unknown = tx.function_args;\n\tif (typeof rawArgs === \"string\") {\n\t\ttry {\n\t\t\trawArgs = JSON.parse(rawArgs);\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\tif (!Array.isArray(rawArgs)) return undefined;\n\n\t// Call through a non-generic cast: clarityValueToJS<T> instantiates the deep\n\t// AbiToTS<T> conditional (TS2589) at runtime call sites. The static types\n\t// come from ContractCallPayload; here we only need its runtime reshaping.\n\tconst decodeArg = clarityValueToJS as unknown as (\n\t\ttype: unknown,\n\t\tcv: unknown,\n\t) => unknown;\n\tconst input: Record<string, unknown> = {};\n\tfn.args.forEach((arg, i) => {\n\t\tconst hex = rawArgs[i];\n\t\tif (typeof hex !== \"string\") return;\n\t\ttry {\n\t\t\tconst clean = hex.startsWith(\"0x\") ? hex.slice(2) : hex;\n\t\t\tinput[toCamelCase(arg.name)] = decodeArg(arg.type, deserializeCV(clean));\n\t\t} catch {\n\t\t\t// Skip args that fail to decode rather than dropping the whole event.\n\t\t}\n\t});\n\treturn input;\n}\n\n/**\n * Build a typed event payload based on the source filter type.\n * Returns the payload the handler will receive.\n */\nexport function buildEventPayload(\n\tfilter: SubgraphFilter,\n\ttx: MatchedTx[\"tx\"],\n\tevent: MatchedTx[\"events\"][0] | null,\n): Record<string, unknown> {\n\tconst txMeta = {\n\t\ttxId: tx.tx_id,\n\t\tsender: tx.sender,\n\t\ttype: tx.type,\n\t\tstatus: tx.status,\n\t\tcontractId: tx.contract_id ?? null,\n\t\tfunctionName: tx.function_name ?? null,\n\t};\n\n\t// Decoded function args + result for contract_call payloads\n\tconst decodedArgs = decodeFunctionArgs(tx.function_args);\n\tconst decodedResult = decodeRawResult(tx.raw_result);\n\n\t// No event — tx-level match (contract_call or contract_deploy)\n\tif (!event) {\n\t\tswitch (filter.type) {\n\t\t\tcase \"contract_call\": {\n\t\t\t\tconst input = buildContractCallInput(filter, tx);\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"contract_call\",\n\t\t\t\t\tcontractId: tx.contract_id ?? \"\",\n\t\t\t\t\tfunctionName: tx.function_name ?? \"\",\n\t\t\t\t\tsender: tx.sender,\n\t\t\t\t\targs: decodedArgs,\n\t\t\t\t\t...(input !== undefined ? { input } : {}),\n\t\t\t\t\tresult: decodedResult,\n\t\t\t\t\tresultHex: tx.raw_result ?? null,\n\t\t\t\t\ttx: txMeta,\n\t\t\t\t};\n\t\t\t}\n\t\t\tcase \"contract_deploy\":\n\t\t\t\treturn {\n\t\t\t\t\tcontractId: tx.contract_id ?? \"\",\n\t\t\t\t\tdeployer: tx.sender,\n\t\t\t\t\ttx: txMeta,\n\t\t\t\t};\n\t\t\tdefault:\n\t\t\t\treturn { tx: txMeta };\n\t\t}\n\t}\n\n\t// Decode event data (Clarity values auto-unwrapped via cvToValue)\n\tconst decoded = decodeEventData(event.data) as Record<string, unknown>;\n\n\tswitch (filter.type) {\n\t\t// ── FT events ──\n\t\tcase \"ft_transfer\":\n\t\t\treturn {\n\t\t\t\tsender: decoded.sender as string,\n\t\t\t\trecipient: decoded.recipient as string,\n\t\t\t\tamount: safeBigInt(decoded.amount),\n\t\t\t\tassetIdentifier: decoded.asset_identifier as string,\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\t\tcase \"ft_mint\":\n\t\t\treturn {\n\t\t\t\trecipient: decoded.recipient as string,\n\t\t\t\tamount: safeBigInt(decoded.amount),\n\t\t\t\tassetIdentifier: decoded.asset_identifier as string,\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\t\tcase \"ft_burn\":\n\t\t\treturn {\n\t\t\t\tsender: decoded.sender as string,\n\t\t\t\tamount: safeBigInt(decoded.amount),\n\t\t\t\tassetIdentifier: decoded.asset_identifier as string,\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\n\t\t// ── NFT events ──\n\t\t// tokenId decodes from the canonical hex (`raw_value`), not the node's\n\t\t// verbose serde-tagged `value` (`{UInt:223}`). The hex is source-\n\t\t// independent — present in both the DB tap and the Index API — so a\n\t\t// subgraph yields the same clean tokenId (e.g. 223n) on either source.\n\t\tcase \"nft_transfer\":\n\t\t\treturn {\n\t\t\t\tsender: decoded.sender as string,\n\t\t\t\trecipient: decoded.recipient as string,\n\t\t\t\ttokenId: decoded.raw_value ?? decoded.value,\n\t\t\t\tassetIdentifier: decoded.asset_identifier as string,\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\t\tcase \"nft_mint\":\n\t\t\treturn {\n\t\t\t\trecipient: decoded.recipient as string,\n\t\t\t\ttokenId: decoded.raw_value ?? decoded.value,\n\t\t\t\tassetIdentifier: decoded.asset_identifier as string,\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\t\tcase \"nft_burn\":\n\t\t\treturn {\n\t\t\t\tsender: decoded.sender as string,\n\t\t\t\ttokenId: decoded.raw_value ?? decoded.value,\n\t\t\t\tassetIdentifier: decoded.asset_identifier as string,\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\n\t\t// ── STX events ──\n\t\tcase \"stx_transfer\":\n\t\t\treturn {\n\t\t\t\tsender: decoded.sender as string,\n\t\t\t\trecipient: decoded.recipient as string,\n\t\t\t\tamount: safeBigInt(decoded.amount),\n\t\t\t\tmemo: decoded.memo ?? \"\",\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\t\tcase \"stx_mint\":\n\t\t\treturn {\n\t\t\t\trecipient: decoded.recipient as string,\n\t\t\t\tamount: safeBigInt(decoded.amount),\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\t\tcase \"stx_burn\":\n\t\t\treturn {\n\t\t\t\tsender: decoded.sender as string,\n\t\t\t\tamount: safeBigInt(decoded.amount),\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\t\tcase \"stx_lock\":\n\t\t\treturn {\n\t\t\t\tlockedAddress: decoded.locked_address as string,\n\t\t\t\tlockedAmount: safeBigInt(decoded.locked_amount),\n\t\t\t\tunlockHeight: safeBigInt(decoded.unlock_height),\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\n\t\t// ── Print event ──\n\t\tcase \"print_event\": {\n\t\t\t// Decode the print value from the canonical hex (`raw_value`) so it's\n\t\t\t// source-independent and clean — the node's verbose serde-tagged\n\t\t\t// `value` (e.g. `{Optional:{data:null}}`) is not reproducible from the\n\t\t\t// Index API and is no longer used (same rationale as nft tokenId).\n\t\t\t// decodeEventData skips hex ≤10 chars, so decode `raw_value` directly.\n\t\t\tconst rawHex = (event.data as Record<string, unknown> | null)?.raw_value;\n\t\t\tconst rawValue =\n\t\t\t\ttypeof rawHex === \"string\" && rawHex.startsWith(\"0x\")\n\t\t\t\t\t? decodeClarityValue(rawHex)\n\t\t\t\t\t: decoded.value;\n\t\t\t// Extract topic from decoded Clarity value (not raw event topic which is always \"print\")\n\t\t\tconst clarityObj =\n\t\t\t\trawValue && typeof rawValue === \"object\" && !Array.isArray(rawValue)\n\t\t\t\t\t? (rawValue as Record<string, unknown>)\n\t\t\t\t\t: null;\n\t\t\tconst topic = clarityObj?.topic\n\t\t\t\t? String(clarityObj.topic)\n\t\t\t\t: ((decoded.topic as string) ?? \"\");\n\t\t\t// Camelize remaining keys for developer convenience\n\t\t\tconst { topic: _, ...rest } = clarityObj ?? {};\n\t\t\tconst data =\n\t\t\t\tObject.keys(rest).length > 0\n\t\t\t\t\t? (camelizeKeys(rest) as Record<string, unknown>)\n\t\t\t\t\t: rawValue && typeof rawValue !== \"object\"\n\t\t\t\t\t\t? rawValue\n\t\t\t\t\t\t: {};\n\t\t\treturn {\n\t\t\t\tcontractId:\n\t\t\t\t\t(decoded.contract_identifier as string) ?? tx.contract_id ?? \"\",\n\t\t\t\ttopic,\n\t\t\t\tdata: data ?? {},\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\t\t}\n\n\t\t// ── Contract call (with events) ──\n\t\tcase \"contract_call\": {\n\t\t\t// Normalize the spread event Clarity `value` to the decoded canonical\n\t\t\t// (from `raw_value`), so it's identical whether the event came from the\n\t\t\t// DB tap or the Index API — the node's serde-tagged `value` is not\n\t\t\t// reproducible from Index (same rationale as nft tokenId / print).\n\t\t\tconst ccRawHex = (event.data as Record<string, unknown> | null)\n\t\t\t\t?.raw_value;\n\t\t\tconst normalized =\n\t\t\t\ttypeof ccRawHex === \"string\" && ccRawHex.startsWith(\"0x\")\n\t\t\t\t\t? { ...decoded, value: decodeClarityValue(ccRawHex) }\n\t\t\t\t\t: decoded;\n\t\t\tconst input = buildContractCallInput(filter, tx);\n\t\t\treturn {\n\t\t\t\t...normalized,\n\t\t\t\ttype: \"contract_call\",\n\t\t\t\t_eventType: event.type,\n\t\t\t\tcontractId: tx.contract_id ?? \"\",\n\t\t\t\tfunctionName: tx.function_name ?? \"\",\n\t\t\t\tsender: tx.sender,\n\t\t\t\targs: decodedArgs,\n\t\t\t\t...(input !== undefined ? { input } : {}),\n\t\t\t\tresult: decodedResult,\n\t\t\t\tresultHex: tx.raw_result ?? null,\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\t\t}\n\n\t\t// ── Contract deploy ──\n\t\tcase \"contract_deploy\":\n\t\t\treturn {\n\t\t\t\tcontractId: tx.contract_id ?? \"\",\n\t\t\t\tdeployer: tx.sender,\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\n\t\tdefault:\n\t\t\t// Fallback: spread decoded data with tx metadata\n\t\t\treturn {\n\t\t\t\t...decoded,\n\t\t\t\t_eventType: event.type,\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\t}\n}\n\n/**\n * Run a subgraph's keyed handlers against all matched transactions/events.\n *\n * Each MatchedTx carries a sourceName from the matcher. The runner looks up\n * the corresponding handler in subgraph.handlers, falling back to \"*\".\n *\n * Does NOT flush — caller is responsible for flushing ctx after run.\n */\nexport async function runHandlers(\n\tsubgraph: SubgraphDefinition,\n\tmatched: MatchedTx[],\n\tctx: SubgraphContext,\n\topts?: { errorThreshold?: number },\n): Promise<RunResult> {\n\tlet processed = 0;\n\tlet errors = 0;\n\tlet skipped = 0;\n\tconst threshold = opts?.errorThreshold ?? DEFAULT_ERROR_THRESHOLD;\n\n\t// Build filter lookup from sources (supports both array and named object)\n\tconst filterLookup = new Map<string, SubgraphFilter>();\n\tif (!Array.isArray(subgraph.sources)) {\n\t\tfor (const [name, filter] of Object.entries(\n\t\t\tsubgraph.sources as Record<string, SubgraphFilter>,\n\t\t)) {\n\t\t\tfilterLookup.set(name, filter);\n\t\t}\n\t}\n\n\t// Flatten matches to per-event dispatch units and sort into CHAIN order\n\t// (tx_index, then event_index; tx-level matches first within their tx).\n\t// The matcher groups results by source, so without this a block's mints\n\t// all run before (or after) its transfers — a debit could apply before\n\t// the same block's funding credit, which on-chain ordering forbids. Chain\n\t// order makes per-statement invariants (e.g. uint CHECK >= 0) sound.\n\ttype DispatchUnit = {\n\t\ttx: MatchedTx[\"tx\"];\n\t\tsourceName: string;\n\t\tevent: MatchedTx[\"events\"][0] | null;\n\t};\n\tconst units: DispatchUnit[] = [];\n\tfor (const { tx, events, sourceName } of matched) {\n\t\tif (events.length === 0) {\n\t\t\tunits.push({ tx, sourceName, event: null });\n\t\t} else {\n\t\t\tfor (const event of events) units.push({ tx, sourceName, event });\n\t\t}\n\t}\n\tunits.sort(\n\t\t(a, b) =>\n\t\t\t(a.tx.tx_index ?? 0) - (b.tx.tx_index ?? 0) ||\n\t\t\t(a.event?.event_index ?? -1) - (b.event?.event_index ?? -1),\n\t);\n\n\tfor (const { tx, event, sourceName } of units) {\n\t\tif (errors >= threshold) {\n\t\t\tlogger.error(\n\t\t\t\t\"Subgraph error threshold reached, skipping remaining events\",\n\t\t\t\t{\n\t\t\t\t\tsubgraph: subgraph.name,\n\t\t\t\t\terrors,\n\t\t\t\t\tthreshold,\n\t\t\t\t},\n\t\t\t);\n\t\t\treturn { processed, errors, ...(skipped > 0 ? { skipped } : {}) };\n\t\t}\n\n\t\tconst handler =\n\t\t\tsubgraph.handlers[sourceName] ?? subgraph.handlers[\"*\"] ?? null;\n\t\tif (!handler) {\n\t\t\tlogger.warn(\"No handler found for source\", {\n\t\t\t\tsubgraph: subgraph.name,\n\t\t\t\tsourceName,\n\t\t\t\ttxId: tx.tx_id,\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\n\t\tctx.setTx({\n\t\t\ttxId: tx.tx_id,\n\t\t\tsender: tx.sender,\n\t\t\ttype: tx.type,\n\t\t\tstatus: tx.status,\n\t\t\tcontractId: tx.contract_id ?? null,\n\t\t\tfunctionName: tx.function_name ?? null,\n\t\t});\n\n\t\tconst filter = filterLookup.get(sourceName);\n\n\t\t// Checkpoint the ops queue: a handler that throws mid-way must\n\t\t// contribute nothing — a partial flush (e.g. a debit without its\n\t\t// credit) silently corrupts accumulator tables (fix-f040 B6).\n\t\tconst checkpoint = ctx.opsCheckpoint();\n\t\ttry {\n\t\t\tlet payload: Record<string, unknown>;\n\t\t\tif (event === null) {\n\t\t\t\t// Tx-level match (contract_call / contract_deploy)\n\t\t\t\tpayload = filter\n\t\t\t\t\t? buildEventPayload(filter, tx, null)\n\t\t\t\t\t: {\n\t\t\t\t\t\t\ttx: {\n\t\t\t\t\t\t\t\ttxId: tx.tx_id,\n\t\t\t\t\t\t\t\tsender: tx.sender,\n\t\t\t\t\t\t\t\ttype: tx.type,\n\t\t\t\t\t\t\t\tstatus: tx.status,\n\t\t\t\t\t\t\t\tcontractId: tx.contract_id,\n\t\t\t\t\t\t\t\tfunctionName: tx.function_name,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t};\n\t\t\t} else if (filter) {\n\t\t\t\tpayload = buildEventPayload(filter, tx, event);\n\t\t\t} else {\n\t\t\t\tconst decoded = decodeEventData(event.data) as Record<string, unknown>;\n\t\t\t\tpayload = {\n\t\t\t\t\t...decoded,\n\t\t\t\t\t_eventId: event.id,\n\t\t\t\t\t_eventType: event.type,\n\t\t\t\t\t_eventIndex: event.event_index,\n\t\t\t\t\ttx: {\n\t\t\t\t\t\ttxId: tx.tx_id,\n\t\t\t\t\t\tsender: tx.sender,\n\t\t\t\t\t\ttype: tx.type,\n\t\t\t\t\t\tstatus: tx.status,\n\t\t\t\t\t\tcontractId: tx.contract_id,\n\t\t\t\t\t\tfunctionName: tx.function_name,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// Post-decode topic filter for print_event — source-matcher defers this\n\t\t\t// because data.value is raw hex at match time; apply it now after decode.\n\t\t\tif (\n\t\t\t\tevent !== null &&\n\t\t\t\tfilter?.type === \"print_event\" &&\n\t\t\t\tfilter.topic &&\n\t\t\t\tpayload.topic !== filter.topic\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Declared `prints` is the developer's stated payload shape, so a\n\t\t\t// mismatch is a real defect (a contract upgrade, or a declaration\n\t\t\t// that never matched — the bns-names class, where every event\n\t\t\t// decoded to null for an entire deploy). Skip + log rather than\n\t\t\t// write nulls; never throw, which would wedge the block.\n\t\t\tif (event !== null && filter?.type === \"print_event\" && filter.prints) {\n\t\t\t\tconst printPayload = payload as {\n\t\t\t\t\ttopic?: string;\n\t\t\t\t\tdata?: Record<string, unknown>;\n\t\t\t\t};\n\t\t\t\tconst verdict = validatePrintPayload(\n\t\t\t\t\tfilter.prints,\n\t\t\t\t\tprintPayload.topic ?? \"\",\n\t\t\t\t\tprintPayload.data ?? {},\n\t\t\t\t);\n\t\t\t\tif (!verdict.ok) {\n\t\t\t\t\tskipped++;\n\t\t\t\t\tlogger.warn(\"Print payload does not match declared prints schema\", {\n\t\t\t\t\t\tsubgraph: subgraph.name,\n\t\t\t\t\t\tsourceName,\n\t\t\t\t\t\ttopic: printPayload.topic,\n\t\t\t\t\t\ttxId: tx.tx_id,\n\t\t\t\t\t\treason: verdict.reason,\n\t\t\t\t\t});\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tawait handler(payload, ctx);\n\t\t\tprocessed++;\n\t\t} catch (err) {\n\t\t\tctx.rollbackTo(checkpoint);\n\t\t\terrors++;\n\t\t\tlogger.error(\"Subgraph handler error\", {\n\t\t\t\tsubgraph: subgraph.name,\n\t\t\t\tsourceName,\n\t\t\t\ttxId: tx.tx_id,\n\t\t\t\t...(event !== null ? { eventId: event.id, eventType: event.type } : {}),\n\t\t\t\terror: getErrorMessage(err),\n\t\t\t});\n\t\t}\n\t}\n\n\treturn { processed, errors, ...(skipped > 0 ? { skipped } : {}) };\n}\n",
|
|
11
11
|
"import type { ColumnType, PrintField } from \"../types.ts\";\n\n/**\n * Runtime validation of a decoded print payload against a source's declared\n * `prints` schema.\n *\n * Declaring `prints` is the opt-in that makes strictness safe: the developer\n * has stated the shape, so a mismatch is a real defect (a contract upgrade,\n * or a hand-written declaration that never matched — the bns-names class of\n * bug, where a handler read flat `data.name` while BNS-V2 emitted a nested\n * tuple, and every event silently decoded to null for a whole deploy).\n *\n * Failure mode is SKIP + LOG, never throw: throwing would fail the block, and\n * a poisoned block that can never advance is incompatible with the\n * checkpoint model. One bad event is dropped and counted; the rest of the\n * block commits.\n */\n\nconst COLUMN_TYPES = new Set<string>([\n\t\"text\",\n\t\"uint\",\n\t\"int\",\n\t\"principal\",\n\t\"boolean\",\n\t\"timestamp\",\n\t\"jsonb\",\n]);\n\nfunction isColumnType(field: PrintField): field is ColumnType {\n\treturn typeof field === \"string\" && COLUMN_TYPES.has(field);\n}\n\n/** Does a decoded value match one declared field? */\nfunction matchesField(field: PrintField, value: unknown): boolean {\n\tif (isColumnType(field)) {\n\t\tswitch (field) {\n\t\t\tcase \"uint\":\n\t\t\tcase \"int\":\n\t\t\t\treturn typeof value === \"bigint\" || typeof value === \"number\";\n\t\t\tcase \"boolean\":\n\t\t\t\treturn typeof value === \"boolean\";\n\t\t\tcase \"text\":\n\t\t\tcase \"principal\":\n\t\t\tcase \"timestamp\":\n\t\t\t\t// Buffers decode to strings; principals too. Accept any scalar the\n\t\t\t\t// decoder can render, but reject objects/arrays.\n\t\t\t\treturn (\n\t\t\t\t\ttypeof value === \"string\" ||\n\t\t\t\t\ttypeof value === \"number\" ||\n\t\t\t\t\ttypeof value === \"bigint\"\n\t\t\t\t);\n\t\t\tcase \"jsonb\":\n\t\t\t\t// Deliberately permissive: `jsonb` is the \"shape unknown\" escape.\n\t\t\t\treturn value !== undefined;\n\t\t}\n\t}\n\tif (typeof field !== \"object\" || field === null) return false;\n\tif (\"optional\" in field) {\n\t\treturn (\n\t\t\tvalue === undefined || value === null || matchesField(field.type, value)\n\t\t);\n\t}\n\tif (\"tuple\" in field) {\n\t\tif (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n\t\t\treturn false;\n\t\t}\n\t\treturn matchesTopic(field.tuple, value as Record<string, unknown>).ok;\n\t}\n\tif (\"list\" in field) {\n\t\treturn (\n\t\t\tArray.isArray(value) &&\n\t\t\tvalue.every((item) => matchesField(field.list, item))\n\t\t);\n\t}\n\treturn false;\n}\n\nexport type PrintValidationResult =\n\t| { ok: true }\n\t| { ok: false; reason: string };\n\n/** Validate a decoded payload object against one topic's declared fields. */\nexport function matchesTopic(\n\tdeclared: Record<string, PrintField>,\n\tdata: Record<string, unknown>,\n): PrintValidationResult {\n\tfor (const [name, field] of Object.entries(declared)) {\n\t\tconst present = name in data;\n\t\tconst optional =\n\t\t\ttypeof field === \"object\" && field !== null && \"optional\" in field;\n\t\tif (!present) {\n\t\t\tif (optional) continue;\n\t\t\treturn { ok: false, reason: `missing declared field \"${name}\"` };\n\t\t}\n\t\tif (!matchesField(field, data[name])) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\treason: `field \"${name}\" does not match its declared type (got ${describe(data[name])})`,\n\t\t\t};\n\t\t}\n\t}\n\treturn { ok: true };\n}\n\nfunction describe(value: unknown): string {\n\tif (value === null) return \"null\";\n\tif (Array.isArray(value)) return \"array\";\n\treturn typeof value;\n}\n\n/**\n * Validate one decoded print event against a source's `prints` declaration.\n * Returns `{ ok: true }` when no declaration covers this topic (undeclared\n * topics are not the developer's stated contract, so they pass through).\n */\nexport function validatePrintPayload(\n\tprints: Record<string, Record<string, PrintField>> | undefined,\n\ttopic: string,\n\tdata: Record<string, unknown>,\n): PrintValidationResult {\n\tif (!prints) return { ok: true };\n\tconst declared = prints[topic];\n\tif (!declared) return { ok: true };\n\treturn matchesTopic(declared, data);\n}\n",
|
|
12
|
-
"import type { AbiContract } from \"@secondlayer/stacks/clarity\";\nimport { normalizeAbi, toCamelCase } from \"@secondlayer/stacks/clarity\";\nimport type { EventForFilter } from \"../events.ts\";\nimport type { TypedSubgraphContext } from \"../infer.ts\";\nimport type { ChainReadClient } from \"../runtime/chain-read.ts\";\nimport { SubgraphContext } from \"../runtime/context.ts\";\nimport type { BlockMeta, TxMeta } from \"../runtime/context.ts\";\nimport { buildEventPayload } from \"../runtime/runner.ts\";\nimport type { SubgraphFilter, SubgraphSchema } from \"../types.ts\";\n\n/**\n * `@secondlayer/subgraphs/testing` — run a handler without deploying.\n *\n * There was no way to execute a handler outside production: seventeen `sl\n * subgraphs` subcommands and none ran one, `dev` deployed DDL and printed\n * handler keys, `--dry-run` validated schema only. The cost was measurable —\n * three of four production subgraphs shipped broken, including one that held\n * 0 rows chain-wide for a whole release because of a 3-line field-mapping bug\n * that a single fixture event would have caught.\n *\n * The context here is the REAL {@link SubgraphContext} with its row store\n * swapped for memory. Read-your-writes, upsert merging, increment deltas,\n * where-matching, and control-key handling all come from the one\n * implementation — a second copy of that logic already drifted once (see\n * `runtime/sandbox/overlay-parity.test.ts`), and this surface will not be the\n * third.\n */\n\nconst TEST_SCHEMA_NAME = \"subgraph_test\";\n\nfunction defaultBlock(overrides: Partial<BlockMeta> = {}): BlockMeta {\n\treturn {\n\t\theight: 1,\n\t\thash: \"0xtest\",\n\t\ttimestamp: 0,\n\t\tburnBlockHeight: 1,\n\t\t...overrides,\n\t};\n}\n\nfunction defaultTx(overrides: Partial<TxMeta> = {}): TxMeta {\n\treturn {\n\t\ttxId: \"0xtest-tx\",\n\t\tsender: \"SP000000000000000000002Q6VF78\",\n\t\ttype: \"contract_call\",\n\t\tstatus: \"success\",\n\t\tcontractId: null,\n\t\tfunctionName: null,\n\t\t...overrides,\n\t};\n}\n\n/** An in-memory subgraph context for tests. */\nexport interface TestSubgraphContext<S extends SubgraphSchema>\n\textends Omit<TypedSubgraphContext<S>, never> {\n\t/**\n\t * Current rows of `table`, INCLUDING writes queued by the handler you just\n\t * ran (the same read-your-writes overlay the runtime uses). Drop straight\n\t * into `toMatchInlineSnapshot()`.\n\t */\n\trows(table: keyof S & string): Promise<Record<string, unknown>[]>;\n\t/** Commit pending writes into the in-memory store, as an end-of-block flush\n\t * would — call between blocks when a test spans several. */\n\tcommit(): Promise<void>;\n\t/** Swap the transaction metadata handlers see (`ctx.tx`). */\n\tsetTx(tx: Partial<TxMeta>): void;\n}\n\n/** The real context, backed by an in-memory row store instead of Postgres. */\nclass InMemorySubgraphContext extends SubgraphContext {\n\t/** Committed rows per table (what a flush would have persisted). */\n\tprivate readonly store = new Map<string, Record<string, unknown>[]>();\n\n\tconstructor(schema: SubgraphSchema, block: BlockMeta, tx: TxMeta) {\n\t\t// `db` is never touched: `readRows` is overridden below, and the test\n\t\t// context never flushes SQL.\n\t\tsuper(
|
|
12
|
+
"import type { AbiContract } from \"@secondlayer/stacks/clarity\";\nimport { normalizeAbi, toCamelCase } from \"@secondlayer/stacks/clarity\";\nimport type { EventForFilter } from \"../events.ts\";\nimport type { TypedSubgraphContext } from \"../infer.ts\";\nimport type { ChainReadClient } from \"../runtime/chain-read.ts\";\nimport { SubgraphContext } from \"../runtime/context.ts\";\nimport type { BlockMeta, TxMeta } from \"../runtime/context.ts\";\nimport { buildEventPayload } from \"../runtime/runner.ts\";\nimport type { SubgraphFilter, SubgraphSchema } from \"../types.ts\";\n\n/**\n * `@secondlayer/subgraphs/testing` — run a handler without deploying.\n *\n * There was no way to execute a handler outside production: seventeen `sl\n * subgraphs` subcommands and none ran one, `dev` deployed DDL and printed\n * handler keys, `--dry-run` validated schema only. The cost was measurable —\n * three of four production subgraphs shipped broken, including one that held\n * 0 rows chain-wide for a whole release because of a 3-line field-mapping bug\n * that a single fixture event would have caught.\n *\n * The context here is the REAL {@link SubgraphContext} with its row store\n * swapped for memory. Read-your-writes, upsert merging, increment deltas,\n * where-matching, and control-key handling all come from the one\n * implementation — a second copy of that logic already drifted once (see\n * `runtime/sandbox/overlay-parity.test.ts`), and this surface will not be the\n * third.\n */\n\nconst TEST_SCHEMA_NAME = \"subgraph_test\";\n\nfunction defaultBlock(overrides: Partial<BlockMeta> = {}): BlockMeta {\n\treturn {\n\t\theight: 1,\n\t\thash: \"0xtest\",\n\t\ttimestamp: 0,\n\t\tburnBlockHeight: 1,\n\t\t...overrides,\n\t};\n}\n\nfunction defaultTx(overrides: Partial<TxMeta> = {}): TxMeta {\n\treturn {\n\t\ttxId: \"0xtest-tx\",\n\t\tsender: \"SP000000000000000000002Q6VF78\",\n\t\ttype: \"contract_call\",\n\t\tstatus: \"success\",\n\t\tcontractId: null,\n\t\tfunctionName: null,\n\t\t...overrides,\n\t};\n}\n\n/** An in-memory subgraph context for tests. */\nexport interface TestSubgraphContext<S extends SubgraphSchema>\n\textends Omit<TypedSubgraphContext<S>, never> {\n\t/**\n\t * Current rows of `table`, INCLUDING writes queued by the handler you just\n\t * ran (the same read-your-writes overlay the runtime uses). Drop straight\n\t * into `toMatchInlineSnapshot()`.\n\t */\n\trows(table: keyof S & string): Promise<Record<string, unknown>[]>;\n\t/** Commit pending writes into the in-memory store, as an end-of-block flush\n\t * would — call between blocks when a test spans several. */\n\tcommit(): Promise<void>;\n\t/** Swap the transaction metadata handlers see (`ctx.tx`). */\n\tsetTx(tx: Partial<TxMeta>): void;\n}\n\n/** The real context, backed by an in-memory row store instead of Postgres. */\nclass InMemorySubgraphContext extends SubgraphContext {\n\t/** Committed rows per table (what a flush would have persisted). */\n\tprivate readonly store = new Map<string, Record<string, unknown>[]>();\n\n\tconstructor(schema: SubgraphSchema, block: BlockMeta, tx: TxMeta) {\n\t\t// `db` is never touched: `readRows` is overridden below, and the test\n\t\t// context never flushes SQL.\n\t\tsuper(undefined as never, TEST_SCHEMA_NAME, schema, block, tx, false);\n\t}\n\n\t/** The one seam: committed rows come from memory, not Postgres. */\n\tprotected override async readRows(\n\t\ttable: string,\n\t\twhere: Record<string, unknown>,\n\t\tlimit?: number,\n\t): Promise<Record<string, unknown>[]> {\n\t\tconst rows = (this.store.get(table) ?? []).filter((row) =>\n\t\t\tObject.entries(where).every(([k, v]) => sameValue(row[k], v)),\n\t\t);\n\t\treturn limit === undefined ? rows : rows.slice(0, limit);\n\t}\n\n\tasync rowsOf(table: string): Promise<Record<string, unknown>[]> {\n\t\t// Overlay the pending ops exactly as a read would — so the assertion\n\t\t// sees what the handler actually did, before any flush.\n\t\treturn this.overlayMany(table, {}, await this.readRows(table, {}));\n\t}\n\n\t/**\n\t * Offline `ctx.client`. A handler unit test has no node, so reads are\n\t * stubbed by `<contractId>.<function-name>`; an unstubbed read throws\n\t * naming the key, rather than silently returning undefined and failing the\n\t * assertion somewhere else.\n\t */\n\tsetReads(reads: Record<string, unknown>): void {\n\t\tthis._client = {\n\t\t\tcontract(contractId: string, abi: AbiContract) {\n\t\t\t\tconst camelToKebab = new Map<string, string>();\n\t\t\t\tfor (const fn of normalizeAbi(abi).functions) {\n\t\t\t\t\tcamelToKebab.set(toCamelCase(fn.name), fn.name);\n\t\t\t\t}\n\t\t\t\tconst read = new Proxy(\n\t\t\t\t\t{},\n\t\t\t\t\t{\n\t\t\t\t\t\tget(_target, prop: string) {\n\t\t\t\t\t\t\tconst fnName = camelToKebab.get(prop) ?? prop;\n\t\t\t\t\t\t\tconst key = `${contractId}.${fnName}`;\n\t\t\t\t\t\t\treturn async () => {\n\t\t\t\t\t\t\t\tif (!(key in reads)) {\n\t\t\t\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t\t\t`No stubbed chain read for \"${key}\" — pass it via createTestContext(schema, { reads: { \"${key}\": … } }).`,\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\treturn reads[key];\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\treturn { read } as never;\n\t\t\t},\n\t\t} as ChainReadClient;\n\t}\n\n\t/** Materialize pending ops into the store (an end-of-block flush). */\n\tasync commitOps(): Promise<void> {\n\t\tconst tables = new Set<string>();\n\t\tfor (const op of this.ops) tables.add(op.table);\n\t\tfor (const table of tables) {\n\t\t\tthis.store.set(table, await this.rowsOf(table));\n\t\t}\n\t\tthis.ops.length = 0;\n\t}\n}\n\n/** Loose value equality across the bigint/number/string boundary decoded\n * Clarity values straddle. */\nfunction sameValue(a: unknown, b: unknown): boolean {\n\tif (a === b) return true;\n\tif (\n\t\t(typeof a === \"bigint\" || typeof a === \"number\") &&\n\t\t(typeof b === \"bigint\" || typeof b === \"number\")\n\t) {\n\t\treturn BigInt(a) === BigInt(b);\n\t}\n\treturn String(a) === String(b);\n}\n\n/**\n * Build an in-memory context for a subgraph's schema.\n *\n * ```ts\n * const ctx = createTestContext(bns.schema, { block: { height: 167_484 } });\n * await bns.handlers.bns!(buildEvent(bns.sources.bns, { … }), ctx);\n * expect(await ctx.rows(\"names\")).toMatchInlineSnapshot();\n * ```\n */\nexport function createTestContext<const S extends SubgraphSchema>(\n\tschema: S,\n\toptions: {\n\t\tblock?: Partial<BlockMeta>;\n\t\ttx?: Partial<TxMeta>;\n\t\t/** Stubbed `ctx.client.readOnly` results, keyed\n\t\t * `\"<contractId>.<function-name>\"`. */\n\t\treads?: Record<string, unknown>;\n\t} = {},\n): TestSubgraphContext<S> {\n\tconst impl = new InMemorySubgraphContext(\n\t\tschema,\n\t\tdefaultBlock(options.block),\n\t\tdefaultTx(options.tx),\n\t);\n\timpl.setReads(options.reads ?? {});\n\tconst ctx = impl as unknown as TestSubgraphContext<S>;\n\tctx.rows = (table) => impl.rowsOf(table);\n\tctx.commit = () => impl.commitOps();\n\tctx.setTx = (tx) => impl.setTx(defaultTx(tx));\n\treturn ctx;\n}\n\n/**\n * Build a handler-shaped event payload for a source, typed by that source's\n * filter. `data` supplies the decoded, camelCased fields the runtime would\n * have produced; block/tx metadata is filled in.\n *\n * ```ts\n * buildEvent(bns.sources.bns, {\n * topic: \"name-register\",\n * data: { name: { name: \"0x616c696365\", namespace: \"0x627463\" } },\n * })\n * ```\n */\nexport function buildEvent<const F extends SubgraphFilter>(\n\tsource: F,\n\t// Loose on the way IN, exact on the way OUT. `Partial<EventForFilter<F>>`\n\t// would be nicer, but for a contract_call source carrying an `abi` it\n\t// instantiates the deep `ExtractFunctionArgs`/`AbiToTS` conditional and\n\t// TS gives up (TS2589) — the same hazard `runtime/runner.ts` documents at\n\t// its `clarityValueToJS` call. The RETURN type is exact, which is what\n\t// makes the event assignable to the handler.\n\tpayload: Record<string, unknown>,\n\toptions: { tx?: Partial<TxMeta> } = {},\n): EventForFilter<F> {\n\tconst tx = defaultTx(options.tx);\n\tconst base: Record<string, unknown> = { type: source.type, tx };\n\tif (source.type === \"print_event\") {\n\t\tbase.contractId = source.contractId ?? \"\";\n\t\tbase.topic = \"\";\n\t\tbase.data = {};\n\t} else if (source.type === \"contract_call\") {\n\t\tbase.contractId = source.contractId ?? \"\";\n\t\tbase.functionName = source.functionName ?? \"\";\n\t\tbase.sender = tx.sender;\n\t\tbase.args = [];\n\t\tbase.result = null;\n\t\tbase.resultHex = null;\n\t}\n\t// Double cast: the exact return type is the point, but TS cannot check\n\t// the assignment through the deep ABI conditional (see above).\n\treturn { ...base, ...payload } as unknown as EventForFilter<F>;\n}\n\nexport { buildEventPayload };\nexport type { BlockMeta, TxMeta };\n"
|
|
13
13
|
],
|
|
14
|
-
"mappings": "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",
|
|
15
|
-
"debugId": "
|
|
14
|
+
"mappings": "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",
|
|
15
|
+
"debugId": "F28CFCCFD7CC80FA64756E2164756E21",
|
|
16
16
|
"names": []
|
|
17
17
|
}
|