@secondlayer/subgraphs 3.2.1 → 3.3.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 +81 -0
- package/dist/src/index.d.ts +71 -9
- package/dist/src/index.js +461 -54
- package/dist/src/index.js.map +11 -9
- package/dist/src/runtime/block-processor.d.ts +37 -9
- package/dist/src/runtime/block-processor.js +127 -37
- package/dist/src/runtime/block-processor.js.map +5 -5
- package/dist/src/runtime/catchup.d.ts +34 -8
- package/dist/src/runtime/catchup.js +125 -36
- package/dist/src/runtime/catchup.js.map +5 -5
- package/dist/src/runtime/context.d.ts +27 -1
- package/dist/src/runtime/context.js +13 -2
- package/dist/src/runtime/context.js.map +3 -3
- package/dist/src/runtime/processor.js +143 -39
- package/dist/src/runtime/processor.js.map +8 -8
- package/dist/src/runtime/reindex.d.ts +34 -8
- package/dist/src/runtime/reindex.js +131 -36
- package/dist/src/runtime/reindex.js.map +6 -6
- package/dist/src/runtime/reorg.d.ts +34 -8
- package/dist/src/runtime/reorg.js +131 -39
- package/dist/src/runtime/reorg.js.map +6 -6
- package/dist/src/runtime/runner.d.ts +43 -9
- package/dist/src/runtime/source-matcher.d.ts +19 -10
- package/dist/src/runtime/source-matcher.js +26 -6
- package/dist/src/runtime/source-matcher.js.map +3 -3
- package/dist/src/schema/index.d.ts +42 -8
- package/dist/src/schema/index.js +57 -19
- package/dist/src/schema/index.js.map +5 -5
- package/dist/src/service.js +143 -39
- package/dist/src/service.js.map +8 -8
- package/dist/src/triggers/index.d.ts +16 -8
- package/dist/src/types.d.ts +35 -9
- package/dist/src/validate.d.ts +34 -8
- package/dist/src/validate.js +10 -3
- package/dist/src/validate.js.map +3 -3
- package/package.json +3 -3
|
@@ -2,18 +2,18 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/runtime/context.ts", "../src/runtime/clarity.ts", "../src/runtime/runner.ts", "../src/runtime/source-matcher.ts", "../src/runtime/block-processor.ts", "../src/schema/utils.ts", "../src/runtime/outbox-emit.ts", "../src/runtime/subscription-state.ts", "../src/runtime/emitter-matcher.ts", "../src/runtime/reorg.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 { ComputedValue, SubgraphSchema } from \"../types.ts\";\n\ntype AnyDb = Kysely<Database> | Transaction<Database>;\n\ninterface WriteOp {\n\tkind: \"insert\" | \"update\" | \"delete\";\n\ttable: string;\n\tdata: Record<string, unknown>;\n\t/** For update: SET clause */\n\tset?: Record<string, unknown>;\n}\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\nexport interface BlockMeta {\n\theight: number;\n\thash: string;\n\ttimestamp: number;\n\tburnBlockHeight: number;\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 * Reads execute immediately against the DB (pre-flush 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\tprivate readonly ops: WriteOp[] = [];\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) {\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}\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/** 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\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 qualifiedTable = `\"${this.pgSchemaName}\".\"${table}\"`;\n\t\tconst { clause } = buildWhereClause(where);\n\t\tconst query = `SELECT * FROM ${qualifiedTable} WHERE ${clause} LIMIT 1`;\n\t\tconst { rows } = await sql.raw(query).execute(this.db);\n\t\tconst row = (rows as Record<string, unknown>[])[0] ?? null;\n\t\treturn row ? this.coerceRow(table, row) : null;\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\tconst qualifiedTable = `\"${this.pgSchemaName}\".\"${table}\"`;\n\t\tconst { clause } = buildWhereClause(where);\n\t\tconst query = `SELECT * FROM ${qualifiedTable} WHERE ${clause}`;\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\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\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\tfor (const stmt of statements) {\n\t\t\t\tawait sql.raw(stmt).execute(this.db);\n\t\t\t}\n\t\t} else {\n\t\t\tawait (this.db as Kysely<Database>).transaction().execute(async (tx) => {\n\t\t\t\tfor (const stmt of statements) {\n\t\t\t\t\tawait sql.raw(stmt).execute(tx);\n\t\t\t\t}\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\"\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\top: 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/** 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/** Build SQL statements from write ops, batching compatible INSERTs. */\n\tprivate buildStatements(ops: WriteOp[]): string[] {\n\t\tconst statements: string[] = [];\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\tlet currentBatch: InsertBatch | null = null;\n\t\tlet currentBatchKey = \"\";\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\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\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 {\n\t\t\t\t// Non-insert — flush any pending insert batch first\n\t\t\t\tflushInsertBatch();\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\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\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 insert batch\n\t\tflushInsertBatch();\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/** 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 { ComputedValue, SubgraphSchema } from \"../types.ts\";\n\ntype AnyDb = Kysely<Database> | Transaction<Database>;\n\ninterface WriteOp {\n\tkind: \"insert\" | \"update\" | \"delete\";\n\ttable: string;\n\tdata: Record<string, unknown>;\n\t/** For update: SET clause */\n\tset?: Record<string, unknown>;\n}\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\nexport interface BlockMeta {\n\theight: number;\n\thash: string;\n\ttimestamp: number;\n\tburnBlockHeight: number;\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 * Reads execute immediately against the DB (pre-flush 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\tprivate 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\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) {\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}\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/** 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\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 qualifiedTable = `\"${this.pgSchemaName}\".\"${table}\"`;\n\t\tconst { clause } = buildWhereClause(where);\n\t\tconst query = `SELECT * FROM ${qualifiedTable} WHERE ${clause} LIMIT 1`;\n\t\tconst { rows } = await sql.raw(query).execute(this.db);\n\t\tconst row = (rows as Record<string, unknown>[])[0] ?? null;\n\t\treturn row ? this.coerceRow(table, row) : null;\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\tconst qualifiedTable = `\"${this.pgSchemaName}\".\"${table}\"`;\n\t\tconst { clause } = buildWhereClause(where);\n\t\tconst query = `SELECT * FROM ${qualifiedTable} WHERE ${clause}`;\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\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\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\tfor (const stmt of statements) {\n\t\t\t\tawait sql.raw(stmt).execute(this.db);\n\t\t\t}\n\t\t} else {\n\t\t\tawait (this.db as Kysely<Database>).transaction().execute(async (tx) => {\n\t\t\t\tfor (const stmt of statements) {\n\t\t\t\t\tawait sql.raw(stmt).execute(tx);\n\t\t\t\t}\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\"\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\top: 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/** 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/** Build SQL statements from write ops, batching compatible INSERTs. */\n\tprivate buildStatements(ops: WriteOp[]): string[] {\n\t\tconst statements: string[] = [];\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\tlet currentBatch: InsertBatch | null = null;\n\t\tlet currentBatchKey = \"\";\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\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\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 {\n\t\t\t\t// Non-insert — flush any pending insert batch first\n\t\t\t\tflushInsertBatch();\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\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\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 insert batch\n\t\tflushInsertBatch();\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/** 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 { 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",
|
|
7
7
|
"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 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}\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 */\nfunction 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\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.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.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.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\tconst decodedRawValue = decoded.raw_value;\n\t\t\tconst rawValue =\n\t\t\t\tdecodedRawValue &&\n\t\t\t\ttypeof decodedRawValue === \"object\" &&\n\t\t\t\t!Array.isArray(decodedRawValue)\n\t\t\t\t\t? decodedRawValue\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\tconst input = buildContractCallInput(filter, tx);\n\t\t\treturn {\n\t\t\t\t...decoded,\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\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\tfor (const { tx, events, sourceName } of matched) {\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// If no events but tx matched, call handler with tx-level data\n\t\tif (events.length === 0) {\n\t\t\ttry {\n\t\t\t\tconst payload = 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\tawait handler(payload, ctx);\n\t\t\t\tprocessed++;\n\t\t\t} catch (err) {\n\t\t\t\terrors++;\n\t\t\t\tlogger.error(\"Subgraph handler error\", {\n\t\t\t\t\tsubgraph: subgraph.name,\n\t\t\t\t\tsourceName,\n\t\t\t\t\ttxId: tx.tx_id,\n\t\t\t\t\terror: getErrorMessage(err),\n\t\t\t\t});\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tfor (const event of events) {\n\t\t\tif (errors >= threshold) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t\"Subgraph error threshold reached, skipping remaining events\",\n\t\t\t\t\t{\n\t\t\t\t\t\tsubgraph: subgraph.name,\n\t\t\t\t\t\terrors,\n\t\t\t\t\t\tthreshold,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\treturn { processed, errors };\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst payload = filter\n\t\t\t\t\t? buildEventPayload(filter, tx, event)\n\t\t\t\t\t: (() => {\n\t\t\t\t\t\t\tconst decoded = decodeEventData(event.data) as Record<\n\t\t\t\t\t\t\t\tstring,\n\t\t\t\t\t\t\t\tunknown\n\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t...decoded,\n\t\t\t\t\t\t\t\t_eventId: event.id,\n\t\t\t\t\t\t\t\t_eventType: event.type,\n\t\t\t\t\t\t\t\t_eventIndex: event.event_index,\n\t\t\t\t\t\t\t\ttx: {\n\t\t\t\t\t\t\t\t\ttxId: tx.tx_id,\n\t\t\t\t\t\t\t\t\tsender: tx.sender,\n\t\t\t\t\t\t\t\t\ttype: tx.type,\n\t\t\t\t\t\t\t\t\tstatus: tx.status,\n\t\t\t\t\t\t\t\t\tcontractId: tx.contract_id,\n\t\t\t\t\t\t\t\t\tfunctionName: tx.function_name,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t})();\n\n\t\t\t\t// Post-decode topic filter for print_event — source-matcher defers this\n\t\t\t\t// because data.value is raw hex at match time; apply it now after decode.\n\t\t\t\tif (\n\t\t\t\t\tfilter?.type === \"print_event\" &&\n\t\t\t\t\tfilter.topic &&\n\t\t\t\t\t(payload as Record<string, unknown>).topic !== filter.topic\n\t\t\t\t) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tawait handler(payload, ctx);\n\t\t\t\tprocessed++;\n\t\t\t} catch (err) {\n\t\t\t\terrors++;\n\t\t\t\tlogger.error(\"Subgraph handler error\", {\n\t\t\t\t\tsubgraph: subgraph.name,\n\t\t\t\t\tsourceName,\n\t\t\t\t\ttxId: tx.tx_id,\n\t\t\t\t\teventId: event.id,\n\t\t\t\t\teventType: event.type,\n\t\t\t\t\terror: getErrorMessage(err),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { processed, errors };\n}\n",
|
|
8
|
-
"import type { SubgraphFilter } from \"../types.ts\";\n\nexport interface MatchedTx {\n\ttx: TxRecord;\n\tevents: EventRecord[];\n\t/** Source object key — used for handler dispatch */\n\tsourceName: string;\n}\n\ntype TxRecord = {\n\ttx_id: string;\n\ttype: string;\n\tsender: string;\n\tstatus: string;\n\tcontract_id?: string | null;\n\tfunction_name?: string | null;\n\tfunction_args?: unknown | null;\n\traw_result?: string | null;\n};\n\ntype EventRecord = {\n\tid: string;\n\ttx_id: string;\n\ttype: string;\n\tevent_index: number;\n\tdata: unknown;\n};\n\n// ── Wildcard matching (shared with v1) ──────────────────────────────\n\nconst patternCache = new Map<string, RegExp>();\n\nfunction matchPattern(value: string, pattern: string): boolean {\n\tif (!pattern.includes(\"*\")) return value === pattern;\n\tlet re = patternCache.get(pattern);\n\tif (!re) {\n\t\tconst regex = pattern\n\t\t\t.replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\")\n\t\t\t.replace(/\\*/g, \".*\");\n\t\tre = new RegExp(`^${regex}$`);\n\t\tpatternCache.set(pattern, re);\n\t}\n\treturn re.test(value);\n}\n\n// ── Per-filter-type matchers ────────────────────────────────────────\n\nfunction matchFilter(\n\tfilter: SubgraphFilter,\n\ttransactions: TxRecord[],\n\teventsByTx: Map<string, EventRecord[]>,\n): { tx: TxRecord; events: EventRecord[] }[] {\n\tconst results: { tx: TxRecord; events: EventRecord[] }[] = [];\n\n\tswitch (filter.type) {\n\t\t// ── STX events ──\n\t\tcase \"stx_transfer\":\n\t\tcase \"stx_mint\":\n\t\tcase \"stx_burn\":\n\t\tcase \"stx_lock\": {\n\t\t\tconst eventType = `${filter.type}_event`;\n\t\t\tfor (const tx of transactions) {\n\t\t\t\tconst txEvents = eventsByTx.get(tx.tx_id) ?? [];\n\t\t\t\tconst matched = txEvents.filter((e) => e.type === eventType);\n\t\t\t\tif (matched.length === 0) continue;\n\n\t\t\t\t// Apply address filters\n\t\t\t\tconst filtered = matched.filter((e) => {\n\t\t\t\t\tconst data = e.data as Record<string, unknown> | null;\n\t\t\t\t\tif (!data) return false;\n\t\t\t\t\tif (\"sender\" in filter && filter.sender) {\n\t\t\t\t\t\tif (!matchPattern(data.sender as string, filter.sender))\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tif (\"recipient\" in filter && filter.recipient) {\n\t\t\t\t\t\tif (!matchPattern(data.recipient as string, filter.recipient))\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tif (\"lockedAddress\" in filter && filter.lockedAddress) {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t!matchPattern(data.locked_address as string, filter.lockedAddress)\n\t\t\t\t\t\t)\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\t// Amount filters\n\t\t\t\t\tif (\"minAmount\" in filter && filter.minAmount !== undefined) {\n\t\t\t\t\t\tconst amount = BigInt(\n\t\t\t\t\t\t\t(data.amount ?? data.locked_amount ?? \"0\") as string,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tif (amount < filter.minAmount) return false;\n\t\t\t\t\t}\n\t\t\t\t\tif (\n\t\t\t\t\t\t\"maxAmount\" in filter &&\n\t\t\t\t\t\t(filter as { maxAmount?: bigint }).maxAmount !== undefined\n\t\t\t\t\t) {\n\t\t\t\t\t\tconst amount = BigInt((data.amount ?? \"0\") as string);\n\t\t\t\t\t\tif (amount > (filter as { maxAmount: bigint }).maxAmount)\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\treturn true;\n\t\t\t\t});\n\n\t\t\t\tif (filtered.length > 0) {\n\t\t\t\t\tresults.push({ tx, events: filtered });\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\t// ── FT events ──\n\t\tcase \"ft_transfer\":\n\t\tcase \"ft_mint\":\n\t\tcase \"ft_burn\": {\n\t\t\tconst eventType = `${filter.type}_event`;\n\t\t\tfor (const tx of transactions) {\n\t\t\t\tconst txEvents = eventsByTx.get(tx.tx_id) ?? [];\n\t\t\t\tconst matched = txEvents.filter((e) => {\n\t\t\t\t\tif (e.type !== eventType) return false;\n\t\t\t\t\tconst data = e.data as Record<string, unknown> | null;\n\t\t\t\t\tif (!data) return false;\n\n\t\t\t\t\t// Asset identifier filter\n\t\t\t\t\tif (filter.assetIdentifier) {\n\t\t\t\t\t\tconst assetId = data.asset_identifier as string | undefined;\n\t\t\t\t\t\tif (!assetId || !matchPattern(assetId, filter.assetIdentifier))\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\t// Address filters\n\t\t\t\t\tif (\"sender\" in filter && filter.sender) {\n\t\t\t\t\t\tif (!matchPattern(data.sender as string, filter.sender))\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tif (\"recipient\" in filter && filter.recipient) {\n\t\t\t\t\t\tif (!matchPattern(data.recipient as string, filter.recipient))\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\t// Amount filter\n\t\t\t\t\tif (filter.minAmount !== undefined) {\n\t\t\t\t\t\tconst amount = BigInt((data.amount ?? \"0\") as string);\n\t\t\t\t\t\tif (amount < filter.minAmount) return false;\n\t\t\t\t\t}\n\t\t\t\t\treturn true;\n\t\t\t\t});\n\n\t\t\t\tif (matched.length > 0) {\n\t\t\t\t\tresults.push({ tx, events: matched });\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\t// ── NFT events ──\n\t\tcase \"nft_transfer\":\n\t\tcase \"nft_mint\":\n\t\tcase \"nft_burn\": {\n\t\t\tconst eventType = `${filter.type}_event`;\n\t\t\tfor (const tx of transactions) {\n\t\t\t\tconst txEvents = eventsByTx.get(tx.tx_id) ?? [];\n\t\t\t\tconst matched = txEvents.filter((e) => {\n\t\t\t\t\tif (e.type !== eventType) return false;\n\t\t\t\t\tconst data = e.data as Record<string, unknown> | null;\n\t\t\t\t\tif (!data) return false;\n\n\t\t\t\t\tif (filter.assetIdentifier) {\n\t\t\t\t\t\tconst assetId = data.asset_identifier as string | undefined;\n\t\t\t\t\t\tif (!assetId || !matchPattern(assetId, filter.assetIdentifier))\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tif (\"sender\" in filter && filter.sender) {\n\t\t\t\t\t\tif (!matchPattern(data.sender as string, filter.sender))\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tif (\"recipient\" in filter && filter.recipient) {\n\t\t\t\t\t\tif (!matchPattern(data.recipient as string, filter.recipient))\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\treturn true;\n\t\t\t\t});\n\n\t\t\t\tif (matched.length > 0) {\n\t\t\t\t\tresults.push({ tx, events: matched });\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\t// ── Contract call ──\n\t\tcase \"contract_call\": {\n\t\t\tfor (const tx of transactions) {\n\t\t\t\tif (tx.type !== \"contract_call\") continue;\n\n\t\t\t\t// Contract filter\n\t\t\t\tif (filter.contractId) {\n\t\t\t\t\tif (\n\t\t\t\t\t\t!tx.contract_id ||\n\t\t\t\t\t\t!matchPattern(tx.contract_id, filter.contractId)\n\t\t\t\t\t)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t// Function filter\n\t\t\t\tif (filter.functionName) {\n\t\t\t\t\tif (\n\t\t\t\t\t\t!tx.function_name ||\n\t\t\t\t\t\t!matchPattern(tx.function_name, filter.functionName)\n\t\t\t\t\t)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t// Caller filter\n\t\t\t\tif (filter.caller) {\n\t\t\t\t\tif (!matchPattern(tx.sender, filter.caller)) continue;\n\t\t\t\t}\n\n\t\t\t\tconst txEvents = eventsByTx.get(tx.tx_id) ?? [];\n\t\t\t\tresults.push({ tx, events: txEvents });\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\t// ── Contract deploy ──\n\t\tcase \"contract_deploy\": {\n\t\t\tfor (const tx of transactions) {\n\t\t\t\tif (tx.type !== \"smart_contract\") continue;\n\n\t\t\t\tif (filter.deployer) {\n\t\t\t\t\tif (!matchPattern(tx.sender, filter.deployer)) continue;\n\t\t\t\t}\n\t\t\t\tif (filter.contractName) {\n\t\t\t\t\tconst name = tx.contract_id?.split(\".\")[1] ?? \"\";\n\t\t\t\t\tif (!matchPattern(name, filter.contractName)) continue;\n\t\t\t\t}\n\n\t\t\t\tconst txEvents = eventsByTx.get(tx.tx_id) ?? [];\n\t\t\t\tresults.push({ tx, events: txEvents });\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\t// ── Print event ──\n\t\tcase \"print_event\": {\n\t\t\tfor (const tx of transactions) {\n\t\t\t\tconst txEvents = eventsByTx.get(tx.tx_id) ?? [];\n\t\t\t\tconst matched = txEvents.filter((e) => {\n\t\t\t\t\tif (e.type !== \"smart_contract_event\" && e.type !== \"contract_event\")\n\t\t\t\t\t\treturn false;\n\t\t\t\t\tconst data = e.data as Record<string, unknown> | null;\n\t\t\t\t\tif (!data) return false;\n\t\t\t\t\tif (data.topic !== \"print\") return false;\n\n\t\t\t\t\t// Contract filter — events store the contract under either\n\t\t\t\t\t// `contract_identifier` (legacy smart_contract_event payload)\n\t\t\t\t\t// or `contract_id` (current contract_event payload). Mirror\n\t\t\t\t\t// the streams query which checks both shapes.\n\t\t\t\t\tif (filter.contractId) {\n\t\t\t\t\t\tconst contractId =\n\t\t\t\t\t\t\t(data.contract_identifier as string | undefined) ??\n\t\t\t\t\t\t\t(data.contract_id as string | undefined);\n\t\t\t\t\t\tif (!contractId || !matchPattern(contractId, filter.contractId))\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\t// Topic filter — check the decoded Clarity value's topic field\n\t\t\t\t\t// At this stage data.value is still raw hex; topic filtering happens\n\t\t\t\t\t// after decode in the runner. For now, skip topic filtering here.\n\t\t\t\t\t// The runner will filter by topic after decoding.\n\t\t\t\t\treturn true;\n\t\t\t\t});\n\n\t\t\t\tif (matched.length > 0) {\n\t\t\t\t\tresults.push({ tx, events: matched });\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn results;\n}\n\n/**\n * Match named filters against a block's transactions and events.\n * Returns matches with sourceName = the object key from sources.\n */\nexport function matchSources(\n\tsources: Record<string, SubgraphFilter>,\n\ttransactions: TxRecord[],\n\tevents: EventRecord[],\n): MatchedTx[] {\n\t// Index events by txId\n\tconst eventsByTx = new Map<string, EventRecord[]>();\n\tfor (const event of events) {\n\t\tconst list = eventsByTx.get(event.tx_id) ?? [];\n\t\tlist.push(event);\n\t\teventsByTx.set(event.tx_id, list);\n\t}\n\n\tconst seen = new Set<string>();\n\tconst results: MatchedTx[] = [];\n\n\tfor (const [sourceName, filter] of Object.entries(sources)) {\n\t\tconst matches = matchFilter(filter, transactions, eventsByTx);\n\t\tfor (const match of matches) {\n\t\t\tconst dedupeKey = `${match.tx.tx_id}:${sourceName}`;\n\t\t\tif (!seen.has(dedupeKey)) {\n\t\t\t\tseen.add(dedupeKey);\n\t\t\t\tresults.push({ ...match, sourceName });\n\t\t\t}\n\t\t}\n\t}\n\n\treturn results;\n}\n",
|
|
9
|
-
"import {\n\ttype Database,\n\tgetSourceDb,\n\tgetTargetDb,\n} from \"@secondlayer/shared/db\";\nimport {\n\trecordSubgraphProcessed,\n\tupdateSubgraphStatus,\n} from \"@secondlayer/shared/db/queries/subgraphs\";\nimport { logger } from \"@secondlayer/shared/logger\";\nimport { type Transaction, sql } from \"kysely\";\nimport { pgSchemaName } from \"../schema/utils.ts\";\nimport type { SubgraphDefinition } from \"../types.ts\";\nimport { type BlockMeta, SubgraphContext, type TxMeta } from \"./context.ts\";\nimport { emitSubscriptionOutbox } from \"./outbox-emit.ts\";\nimport { runHandlers } from \"./runner.ts\";\nimport { matchSources } from \"./source-matcher.ts\";\nimport { matcher } from \"./subscription-state.ts\";\n\n// Cache schema_name per subgraph to avoid per-block DB lookups\nconst schemaNameCache = new Map<string, string>();\n\nexport interface ProcessBlockTiming {\n\ttotalMs: number;\n\thandlerMs: number;\n\tflushMs: number;\n}\n\nexport interface ProcessBlockResult {\n\tblockHeight: number;\n\tmatched: number;\n\tprocessed: number;\n\terrors: number;\n\tskipped: boolean;\n\ttiming?: ProcessBlockTiming;\n}\n\n/**\n * Process a single block through a single subgraph's pipeline.\n *\n * Flow:\n * 1. Load block + txs + events from DB\n * 2. Run source matcher\n * 3. Run handlers with SubgraphContext\n * 4. Flush context (commit writes atomically)\n * 5. Update subgraph.last_processed_block\n */\nexport interface PreloadedBlockData {\n\tblock: import(\"@secondlayer/shared/db\").Block;\n\ttxs: import(\"@secondlayer/shared/db\").Transaction[];\n\tevents: import(\"@secondlayer/shared/db\").Event[];\n}\n\nexport interface ProcessBlockOptions {\n\t/** Skip updating last_processed_block in DB (reindex batches this externally). */\n\tskipProgressUpdate?: boolean;\n\t/** Pre-loaded block data — skips DB reads when provided (used by batch catch-up). */\n\tpreloaded?: PreloadedBlockData;\n}\n\nexport async function processBlock(\n\tsubgraph: SubgraphDefinition,\n\tsubgraphName: string,\n\tblockHeight: number,\n\topts?: ProcessBlockOptions,\n): Promise<ProcessBlockResult> {\n\tconst sourceDb = getSourceDb();\n\tconst targetDb = getTargetDb();\n\tconst blockStart = performance.now();\n\tconst result: ProcessBlockResult = {\n\t\tblockHeight,\n\t\tmatched: 0,\n\t\tprocessed: 0,\n\t\terrors: 0,\n\t\tskipped: false,\n\t};\n\n\t// 1. Load block from source DB (shared indexer) — use pre-loaded data if available\n\tlet block: PreloadedBlockData[\"block\"] | undefined;\n\tlet txs: PreloadedBlockData[\"txs\"];\n\tlet evts: PreloadedBlockData[\"events\"];\n\tif (opts?.preloaded) {\n\t\tblock = opts.preloaded.block;\n\t\ttxs = opts.preloaded.txs;\n\t\tevts = opts.preloaded.events;\n\t} else {\n\t\tblock = await sourceDb\n\t\t\t.selectFrom(\"blocks\")\n\t\t\t.selectAll()\n\t\t\t.where(\"height\", \"=\", blockHeight)\n\t\t\t.executeTakeFirst();\n\n\t\tif (!block) {\n\t\t\tlogger.warn(\"Block not found for subgraph processing\", {\n\t\t\t\tsubgraph: subgraphName,\n\t\t\t\tblockHeight,\n\t\t\t});\n\t\t\tresult.skipped = true;\n\t\t\treturn result;\n\t\t}\n\n\t\tif (!block.canonical) {\n\t\t\tlogger.debug(\"Skipping non-canonical block\", {\n\t\t\t\tsubgraph: subgraphName,\n\t\t\t\tblockHeight,\n\t\t\t});\n\t\t\tresult.skipped = true;\n\t\t\treturn result;\n\t\t}\n\n\t\t// 2. Load txs + events (source DB)\n\t\ttxs = await sourceDb\n\t\t\t.selectFrom(\"transactions\")\n\t\t\t.selectAll()\n\t\t\t.where(\"block_height\", \"=\", blockHeight)\n\t\t\t.execute();\n\n\t\tevts = await sourceDb\n\t\t\t.selectFrom(\"events\")\n\t\t\t.selectAll()\n\t\t\t.where(\"block_height\", \"=\", blockHeight)\n\t\t\t.execute();\n\t}\n\n\t// 3. Match source\n\tconst matched = matchSources(subgraph.sources, txs, evts);\n\tresult.matched = matched.length;\n\n\tif (matched.length === 0) {\n\t\tif (!opts?.skipProgressUpdate) {\n\t\t\tawait updateSubgraphStatus(targetDb, subgraphName, \"active\", blockHeight);\n\t\t}\n\t\treturn result;\n\t}\n\n\t// 4. Create context and run handlers\n\t// Schema name cache lookup reads the subgraphs table (tenant-side / target DB)\n\tlet schemaName = schemaNameCache.get(subgraphName);\n\tif (!schemaName) {\n\t\tconst subgraphRecord = await targetDb\n\t\t\t.selectFrom(\"subgraphs\")\n\t\t\t.select(\"schema_name\")\n\t\t\t.where(\"name\", \"=\", subgraphName)\n\t\t\t.executeTakeFirst();\n\t\tschemaName = subgraphRecord?.schema_name ?? pgSchemaName(subgraphName);\n\t\tschemaNameCache.set(subgraphName, schemaName);\n\t}\n\tconst blockMeta: BlockMeta = {\n\t\theight: block.height,\n\t\thash: block.hash,\n\t\ttimestamp: block.timestamp,\n\t\tburnBlockHeight: block.burn_block_height,\n\t};\n\tconst initialTx: TxMeta = {\n\t\ttxId: \"\",\n\t\tsender: \"\",\n\t\ttype: \"\",\n\t\tstatus: \"\",\n\t};\n\n\t// Wrap entire block processing in a single transaction on the target DB\n\t// (tenant schemas + subgraph progress rows live in target)\n\tlet handlerMs = 0;\n\tlet flushMs = 0;\n\n\tawait targetDb.transaction().execute(async (tx: Transaction<Database>) => {\n\t\tconst ctx = new SubgraphContext(\n\t\t\ttx,\n\t\t\tschemaName,\n\t\t\tsubgraph.schema,\n\t\t\tblockMeta,\n\t\t\tinitialTx,\n\t\t);\n\n\t\tconst handlerStart = performance.now();\n\t\tconst runResult = await runHandlers(subgraph, matched, ctx);\n\t\thandlerMs = performance.now() - handlerStart;\n\n\t\tresult.processed = runResult.processed;\n\t\tresult.errors = runResult.errors;\n\n\t\t// 5. Flush writes + emit subscription outbox atomically in-tx.\n\t\tif (ctx.pendingOps > 0) {\n\t\t\tconst flushStart = performance.now();\n\t\t\tconst manifest = await ctx.flush();\n\t\t\tif (manifest.count > 0) {\n\t\t\t\tawait emitSubscriptionOutbox(\n\t\t\t\t\ttx,\n\t\t\t\t\tsubgraphName,\n\t\t\t\t\tmanifest,\n\t\t\t\t\tmatcher,\n\t\t\t\t\tblock.height,\n\t\t\t\t);\n\t\t\t}\n\t\t\tflushMs = performance.now() - flushStart;\n\t\t}\n\n\t\t// 6. Update progress + health metrics (same transaction)\n\t\tif (!opts?.skipProgressUpdate) {\n\t\t\tconst status =\n\t\t\t\trunResult.errors > 0 && runResult.processed === 0 ? \"error\" : \"active\";\n\t\t\tawait updateSubgraphStatus(tx, subgraphName, status, blockHeight);\n\t\t}\n\n\t\tif (\n\t\t\t!opts?.skipProgressUpdate &&\n\t\t\t(runResult.processed > 0 || runResult.errors > 0)\n\t\t) {\n\t\t\tconst lastError =\n\t\t\t\trunResult.errors > 0\n\t\t\t\t\t? `${runResult.errors} error(s) at block ${blockHeight}`\n\t\t\t\t\t: undefined;\n\t\t\tawait recordSubgraphProcessed(\n\t\t\t\ttx,\n\t\t\t\tsubgraphName,\n\t\t\t\trunResult.processed,\n\t\t\t\trunResult.errors,\n\t\t\t\tlastError,\n\t\t\t);\n\t\t}\n\t});\n\n\tconst totalMs = performance.now() - blockStart;\n\tresult.timing = {\n\t\ttotalMs: Math.round(totalMs),\n\t\thandlerMs: Math.round(handlerMs),\n\t\tflushMs: Math.round(flushMs),\n\t};\n\n\t// 7. Row count warning — sample every 1000 blocks (uses pg_stat estimate, not COUNT(*))\n\tif (blockHeight % 1000 === 0) {\n\t\ttry {\n\t\t\tconst tables = Object.keys(subgraph.schema);\n\t\t\tfor (const table of tables) {\n\t\t\t\tconst { rows } = await sql\n\t\t\t\t\t.raw(\n\t\t\t\t\t\t`SELECT n_live_tup AS count FROM pg_stat_user_tables WHERE schemaname = '${schemaName}' AND relname = '${table}'`,\n\t\t\t\t\t)\n\t\t\t\t\t.execute(targetDb);\n\t\t\t\tconst count = Number((rows[0] as Record<string, unknown>)?.count ?? 0);\n\t\t\t\tif (count >= 10_000_000) {\n\t\t\t\t\tlogger.warn(\"Subgraph table exceeds 10M rows (estimate)\", {\n\t\t\t\t\t\tsubgraph: subgraphName,\n\t\t\t\t\t\ttable,\n\t\t\t\t\t\tcount,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (err) {\n\t\t\t// Expected: table may not exist yet (fresh subgraph, first few\n\t\t\t// blocks before DDL runs). Log at debug so real errors —\n\t\t\t// connection, permissions, query plan — aren't invisible.\n\t\t\tlogger.debug(\"Row count sample failed\", {\n\t\t\t\tsubgraph: subgraphName,\n\t\t\t\terror: err instanceof Error ? err.message : String(err),\n\t\t\t});\n\t\t}\n\t}\n\n\treturn result;\n}\n",
|
|
8
|
+
"import type { SubgraphFilter } from \"../types.ts\";\n\nexport interface MatchedTx {\n\ttx: TxRecord;\n\tevents: EventRecord[];\n\t/** Source object key — used for handler dispatch */\n\tsourceName: string;\n}\n\ntype TxRecord = {\n\ttx_id: string;\n\ttype: string;\n\tsender: string;\n\tstatus: string;\n\tcontract_id?: string | null;\n\tfunction_name?: string | null;\n\tfunction_args?: unknown | null;\n\traw_result?: string | null;\n};\n\ntype EventRecord = {\n\tid: string;\n\ttx_id: string;\n\ttype: string;\n\tevent_index: number;\n\tdata: unknown;\n};\n\n// ── Wildcard matching (shared with v1) ──────────────────────────────\n\nconst patternCache = new Map<string, RegExp>();\n\nfunction matchPattern(value: string, pattern: string): boolean {\n\tif (!pattern.includes(\"*\")) return value === pattern;\n\tlet re = patternCache.get(pattern);\n\tif (!re) {\n\t\tconst regex = pattern\n\t\t\t.replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\")\n\t\t\t.replace(/\\*/g, \".*\");\n\t\tre = new RegExp(`^${regex}$`);\n\t\tpatternCache.set(pattern, re);\n\t}\n\treturn re.test(value);\n}\n\n// Trait → set of conforming contract IDs, resolved per block by the caller\n// (block-processor) from the contract registry. Kept as injected data so this\n// module stays pure/sync/DB-less.\nexport type TraitContracts = Map<string, ReadonlySet<string>>;\nconst EMPTY_SET: ReadonlySet<string> = new Set();\n\n/**\n * True when a filter's optional `trait` admits this contract: no trait → always\n * allowed; trait set → the contract must be in the resolved conforming set.\n */\nfunction traitAllows(\n\tfilter: SubgraphFilter,\n\tcontractId: string | undefined | null,\n\ttraitContracts: TraitContracts,\n): boolean {\n\tconst trait = (filter as { trait?: string }).trait;\n\tif (!trait) return true;\n\tif (!contractId) return false;\n\treturn (traitContracts.get(trait) ?? EMPTY_SET).has(contractId);\n}\n\n/** Extract the contract id from an asset identifier (`<contract>::<token>`). */\nfunction assetContract(assetId: string | undefined): string | undefined {\n\treturn assetId?.split(\"::\")[0];\n}\n\n// ── Per-filter-type matchers ────────────────────────────────────────\n\nfunction matchFilter(\n\tfilter: SubgraphFilter,\n\ttransactions: TxRecord[],\n\teventsByTx: Map<string, EventRecord[]>,\n\ttraitContracts: TraitContracts,\n): { tx: TxRecord; events: EventRecord[] }[] {\n\tconst results: { tx: TxRecord; events: EventRecord[] }[] = [];\n\n\tswitch (filter.type) {\n\t\t// ── STX events ──\n\t\tcase \"stx_transfer\":\n\t\tcase \"stx_mint\":\n\t\tcase \"stx_burn\":\n\t\tcase \"stx_lock\": {\n\t\t\tconst eventType = `${filter.type}_event`;\n\t\t\tfor (const tx of transactions) {\n\t\t\t\tconst txEvents = eventsByTx.get(tx.tx_id) ?? [];\n\t\t\t\tconst matched = txEvents.filter((e) => e.type === eventType);\n\t\t\t\tif (matched.length === 0) continue;\n\n\t\t\t\t// Apply address filters\n\t\t\t\tconst filtered = matched.filter((e) => {\n\t\t\t\t\tconst data = e.data as Record<string, unknown> | null;\n\t\t\t\t\tif (!data) return false;\n\t\t\t\t\tif (\"sender\" in filter && filter.sender) {\n\t\t\t\t\t\tif (!matchPattern(data.sender as string, filter.sender))\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tif (\"recipient\" in filter && filter.recipient) {\n\t\t\t\t\t\tif (!matchPattern(data.recipient as string, filter.recipient))\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tif (\"lockedAddress\" in filter && filter.lockedAddress) {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t!matchPattern(data.locked_address as string, filter.lockedAddress)\n\t\t\t\t\t\t)\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\t// Amount filters\n\t\t\t\t\tif (\"minAmount\" in filter && filter.minAmount !== undefined) {\n\t\t\t\t\t\tconst amount = BigInt(\n\t\t\t\t\t\t\t(data.amount ?? data.locked_amount ?? \"0\") as string,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tif (amount < filter.minAmount) return false;\n\t\t\t\t\t}\n\t\t\t\t\tif (\n\t\t\t\t\t\t\"maxAmount\" in filter &&\n\t\t\t\t\t\t(filter as { maxAmount?: bigint }).maxAmount !== undefined\n\t\t\t\t\t) {\n\t\t\t\t\t\tconst amount = BigInt((data.amount ?? \"0\") as string);\n\t\t\t\t\t\tif (amount > (filter as { maxAmount: bigint }).maxAmount)\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\treturn true;\n\t\t\t\t});\n\n\t\t\t\tif (filtered.length > 0) {\n\t\t\t\t\tresults.push({ tx, events: filtered });\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\t// ── FT events ──\n\t\tcase \"ft_transfer\":\n\t\tcase \"ft_mint\":\n\t\tcase \"ft_burn\": {\n\t\t\tconst eventType = `${filter.type}_event`;\n\t\t\tfor (const tx of transactions) {\n\t\t\t\tconst txEvents = eventsByTx.get(tx.tx_id) ?? [];\n\t\t\t\tconst matched = txEvents.filter((e) => {\n\t\t\t\t\tif (e.type !== eventType) return false;\n\t\t\t\t\tconst data = e.data as Record<string, unknown> | null;\n\t\t\t\t\tif (!data) return false;\n\n\t\t\t\t\t// Asset identifier filter\n\t\t\t\t\tif (filter.assetIdentifier) {\n\t\t\t\t\t\tconst assetId = data.asset_identifier as string | undefined;\n\t\t\t\t\t\tif (!assetId || !matchPattern(assetId, filter.assetIdentifier))\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\t// Trait scope — the asset's contract must conform.\n\t\t\t\t\tif (\n\t\t\t\t\t\t!traitAllows(\n\t\t\t\t\t\t\tfilter,\n\t\t\t\t\t\t\tassetContract(data.asset_identifier as string | undefined),\n\t\t\t\t\t\t\ttraitContracts,\n\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t// Address filters\n\t\t\t\t\tif (\"sender\" in filter && filter.sender) {\n\t\t\t\t\t\tif (!matchPattern(data.sender as string, filter.sender))\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tif (\"recipient\" in filter && filter.recipient) {\n\t\t\t\t\t\tif (!matchPattern(data.recipient as string, filter.recipient))\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\t// Amount filter\n\t\t\t\t\tif (filter.minAmount !== undefined) {\n\t\t\t\t\t\tconst amount = BigInt((data.amount ?? \"0\") as string);\n\t\t\t\t\t\tif (amount < filter.minAmount) return false;\n\t\t\t\t\t}\n\t\t\t\t\treturn true;\n\t\t\t\t});\n\n\t\t\t\tif (matched.length > 0) {\n\t\t\t\t\tresults.push({ tx, events: matched });\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\t// ── NFT events ──\n\t\tcase \"nft_transfer\":\n\t\tcase \"nft_mint\":\n\t\tcase \"nft_burn\": {\n\t\t\tconst eventType = `${filter.type}_event`;\n\t\t\tfor (const tx of transactions) {\n\t\t\t\tconst txEvents = eventsByTx.get(tx.tx_id) ?? [];\n\t\t\t\tconst matched = txEvents.filter((e) => {\n\t\t\t\t\tif (e.type !== eventType) return false;\n\t\t\t\t\tconst data = e.data as Record<string, unknown> | null;\n\t\t\t\t\tif (!data) return false;\n\n\t\t\t\t\tif (filter.assetIdentifier) {\n\t\t\t\t\t\tconst assetId = data.asset_identifier as string | undefined;\n\t\t\t\t\t\tif (!assetId || !matchPattern(assetId, filter.assetIdentifier))\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tif (\n\t\t\t\t\t\t!traitAllows(\n\t\t\t\t\t\t\tfilter,\n\t\t\t\t\t\t\tassetContract(data.asset_identifier as string | undefined),\n\t\t\t\t\t\t\ttraitContracts,\n\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t\t\t\treturn false;\n\t\t\t\t\tif (\"sender\" in filter && filter.sender) {\n\t\t\t\t\t\tif (!matchPattern(data.sender as string, filter.sender))\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tif (\"recipient\" in filter && filter.recipient) {\n\t\t\t\t\t\tif (!matchPattern(data.recipient as string, filter.recipient))\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\treturn true;\n\t\t\t\t});\n\n\t\t\t\tif (matched.length > 0) {\n\t\t\t\t\tresults.push({ tx, events: matched });\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\t// ── Contract call ──\n\t\tcase \"contract_call\": {\n\t\t\tfor (const tx of transactions) {\n\t\t\t\tif (tx.type !== \"contract_call\") continue;\n\n\t\t\t\t// Contract filter\n\t\t\t\tif (filter.contractId) {\n\t\t\t\t\tif (\n\t\t\t\t\t\t!tx.contract_id ||\n\t\t\t\t\t\t!matchPattern(tx.contract_id, filter.contractId)\n\t\t\t\t\t)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t// Function filter\n\t\t\t\tif (filter.functionName) {\n\t\t\t\t\tif (\n\t\t\t\t\t\t!tx.function_name ||\n\t\t\t\t\t\t!matchPattern(tx.function_name, filter.functionName)\n\t\t\t\t\t)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t// Caller filter\n\t\t\t\tif (filter.caller) {\n\t\t\t\t\tif (!matchPattern(tx.sender, filter.caller)) continue;\n\t\t\t\t}\n\t\t\t\t// Trait scope — the called contract must conform.\n\t\t\t\tif (!traitAllows(filter, tx.contract_id, traitContracts)) continue;\n\n\t\t\t\tconst txEvents = eventsByTx.get(tx.tx_id) ?? [];\n\t\t\t\tresults.push({ tx, events: txEvents });\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\t// ── Contract deploy ──\n\t\tcase \"contract_deploy\": {\n\t\t\tfor (const tx of transactions) {\n\t\t\t\tif (tx.type !== \"smart_contract\") continue;\n\n\t\t\t\tif (filter.deployer) {\n\t\t\t\t\tif (!matchPattern(tx.sender, filter.deployer)) continue;\n\t\t\t\t}\n\t\t\t\tif (filter.contractName) {\n\t\t\t\t\tconst name = tx.contract_id?.split(\".\")[1] ?? \"\";\n\t\t\t\t\tif (!matchPattern(name, filter.contractName)) continue;\n\t\t\t\t}\n\n\t\t\t\tconst txEvents = eventsByTx.get(tx.tx_id) ?? [];\n\t\t\t\tresults.push({ tx, events: txEvents });\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\t// ── Print event ──\n\t\tcase \"print_event\": {\n\t\t\tfor (const tx of transactions) {\n\t\t\t\tconst txEvents = eventsByTx.get(tx.tx_id) ?? [];\n\t\t\t\tconst matched = txEvents.filter((e) => {\n\t\t\t\t\tif (e.type !== \"smart_contract_event\" && e.type !== \"contract_event\")\n\t\t\t\t\t\treturn false;\n\t\t\t\t\tconst data = e.data as Record<string, unknown> | null;\n\t\t\t\t\tif (!data) return false;\n\t\t\t\t\tif (data.topic !== \"print\") return false;\n\n\t\t\t\t\t// Contract filter — events store the contract under either\n\t\t\t\t\t// `contract_identifier` (legacy smart_contract_event payload)\n\t\t\t\t\t// or `contract_id` (current contract_event payload). Mirror\n\t\t\t\t\t// the streams query which checks both shapes.\n\t\t\t\t\tconst printContractId =\n\t\t\t\t\t\t(data.contract_identifier as string | undefined) ??\n\t\t\t\t\t\t(data.contract_id as string | undefined);\n\t\t\t\t\tif (filter.contractId) {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t!printContractId ||\n\t\t\t\t\t\t\t!matchPattern(printContractId, filter.contractId)\n\t\t\t\t\t\t)\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tif (!traitAllows(filter, printContractId, traitContracts))\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t// Topic filter — check the decoded Clarity value's topic field\n\t\t\t\t\t// At this stage data.value is still raw hex; topic filtering happens\n\t\t\t\t\t// after decode in the runner. For now, skip topic filtering here.\n\t\t\t\t\t// The runner will filter by topic after decoding.\n\t\t\t\t\treturn true;\n\t\t\t\t});\n\n\t\t\t\tif (matched.length > 0) {\n\t\t\t\t\tresults.push({ tx, events: matched });\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn results;\n}\n\n/**\n * Match named filters against a block's transactions and events.\n * Returns matches with sourceName = the object key from sources.\n */\nexport function matchSources(\n\tsources: Record<string, SubgraphFilter>,\n\ttransactions: TxRecord[],\n\tevents: EventRecord[],\n\ttraitContracts: TraitContracts = new Map(),\n): MatchedTx[] {\n\t// Index events by txId\n\tconst eventsByTx = new Map<string, EventRecord[]>();\n\tfor (const event of events) {\n\t\tconst list = eventsByTx.get(event.tx_id) ?? [];\n\t\tlist.push(event);\n\t\teventsByTx.set(event.tx_id, list);\n\t}\n\n\tconst seen = new Set<string>();\n\tconst results: MatchedTx[] = [];\n\n\tfor (const [sourceName, filter] of Object.entries(sources)) {\n\t\tconst matches = matchFilter(\n\t\t\tfilter,\n\t\t\ttransactions,\n\t\t\teventsByTx,\n\t\t\ttraitContracts,\n\t\t);\n\t\tfor (const match of matches) {\n\t\t\tconst dedupeKey = `${match.tx.tx_id}:${sourceName}`;\n\t\t\tif (!seen.has(dedupeKey)) {\n\t\t\t\tseen.add(dedupeKey);\n\t\t\t\tresults.push({ ...match, sourceName });\n\t\t\t}\n\t\t}\n\t}\n\n\treturn results;\n}\n",
|
|
9
|
+
"import {\n\ttype Database,\n\tgetSourceDb,\n\tgetTargetDb,\n} from \"@secondlayer/shared/db\";\nimport { resolveTraitContractIds } from \"@secondlayer/shared/db/queries/contracts\";\nimport {\n\tisByoSubgraph,\n\trecordSubgraphProcessed,\n\tresolveSubgraphDb,\n\tupdateSubgraphStatus,\n} from \"@secondlayer/shared/db/queries/subgraphs\";\nimport { logger } from \"@secondlayer/shared/logger\";\nimport { type Kysely, type Transaction, sql } from \"kysely\";\nimport { pgSchemaName } from \"../schema/utils.ts\";\nimport type { SubgraphDefinition } from \"../types.ts\";\nimport { type BlockMeta, SubgraphContext, type TxMeta } from \"./context.ts\";\nimport { emitSubscriptionOutbox } from \"./outbox-emit.ts\";\nimport { runHandlers } from \"./runner.ts\";\nimport { matchSources } from \"./source-matcher.ts\";\nimport { matcher } from \"./subscription-state.ts\";\n\n/**\n * The data-plane route for a subgraph: which schema its tables live in, the DB\n * those writes/reads land on (the user's DB when BYO, else the managed target),\n * and whether it's BYO. Cached per subgraph to avoid a per-block lookup +\n * decrypt; invalidated on redeploy (the connection can change) via\n * {@link invalidateSubgraphRoute}.\n */\ninterface SubgraphRoute {\n\tschemaName: string;\n\tdataDb: Kysely<Database>;\n\tbyo: boolean;\n}\nconst routeCache = new Map<string, SubgraphRoute>();\n\nasync function resolveRoute(\n\tsubgraphName: string,\n\ttargetDb: Kysely<Database>,\n): Promise<SubgraphRoute> {\n\tconst cached = routeCache.get(subgraphName);\n\tif (cached) return cached;\n\tconst row = await targetDb\n\t\t.selectFrom(\"subgraphs\")\n\t\t.selectAll()\n\t\t.where(\"name\", \"=\", subgraphName)\n\t\t.executeTakeFirst();\n\tconst byo = row ? isByoSubgraph(row) : false;\n\tconst route: SubgraphRoute = {\n\t\tschemaName: row?.schema_name ?? pgSchemaName(subgraphName),\n\t\tdataDb: row && byo ? resolveSubgraphDb(row) : targetDb,\n\t\tbyo,\n\t};\n\trouteCache.set(subgraphName, route);\n\treturn route;\n}\n\n/** Drop a subgraph's cached route — call on redeploy/delete (conn may change). */\nexport function invalidateSubgraphRoute(subgraphName: string): void {\n\trouteCache.delete(subgraphName);\n}\n\n/**\n * Resolve each distinct trait used by a subgraph's sources to its conforming\n * contract-id set, as of `blockHeight`, from the contract registry. Empty map\n * when no source is trait-scoped (the common case → no DB work).\n */\nasync function resolveTraitContracts(\n\tsubgraph: SubgraphDefinition,\n\tblockHeight: number,\n\tdb: Kysely<Database>,\n): Promise<Map<string, ReadonlySet<string>>> {\n\tconst traits = new Set<string>();\n\tfor (const source of Object.values(subgraph.sources)) {\n\t\tconst trait = (source as { trait?: string }).trait;\n\t\tif (trait) traits.add(trait);\n\t}\n\tconst resolved = new Map<string, ReadonlySet<string>>();\n\tfor (const trait of traits) {\n\t\tconst ids = await resolveTraitContractIds(db, trait, blockHeight);\n\t\tresolved.set(trait, new Set(ids));\n\t}\n\treturn resolved;\n}\n\nexport interface ProcessBlockTiming {\n\ttotalMs: number;\n\thandlerMs: number;\n\tflushMs: number;\n}\n\nexport interface ProcessBlockResult {\n\tblockHeight: number;\n\tmatched: number;\n\tprocessed: number;\n\terrors: number;\n\tskipped: boolean;\n\ttiming?: ProcessBlockTiming;\n}\n\n/**\n * Process a single block through a single subgraph's pipeline.\n *\n * Flow:\n * 1. Load block + txs + events from DB\n * 2. Run source matcher\n * 3. Run handlers with SubgraphContext\n * 4. Flush context (commit writes atomically)\n * 5. Update subgraph.last_processed_block\n */\nexport interface PreloadedBlockData {\n\tblock: import(\"@secondlayer/shared/db\").Block;\n\ttxs: import(\"@secondlayer/shared/db\").Transaction[];\n\tevents: import(\"@secondlayer/shared/db\").Event[];\n}\n\nexport interface ProcessBlockOptions {\n\t/** Skip updating last_processed_block in DB (reindex batches this externally). */\n\tskipProgressUpdate?: boolean;\n\t/** Pre-loaded block data — skips DB reads when provided (used by batch catch-up). */\n\tpreloaded?: PreloadedBlockData;\n}\n\nexport async function processBlock(\n\tsubgraph: SubgraphDefinition,\n\tsubgraphName: string,\n\tblockHeight: number,\n\topts?: ProcessBlockOptions,\n): Promise<ProcessBlockResult> {\n\tconst sourceDb = getSourceDb();\n\tconst targetDb = getTargetDb();\n\tconst blockStart = performance.now();\n\tconst result: ProcessBlockResult = {\n\t\tblockHeight,\n\t\tmatched: 0,\n\t\tprocessed: 0,\n\t\terrors: 0,\n\t\tskipped: false,\n\t};\n\n\t// 1. Load block from source DB (shared indexer) — use pre-loaded data if available\n\tlet block: PreloadedBlockData[\"block\"] | undefined;\n\tlet txs: PreloadedBlockData[\"txs\"];\n\tlet evts: PreloadedBlockData[\"events\"];\n\tif (opts?.preloaded) {\n\t\tblock = opts.preloaded.block;\n\t\ttxs = opts.preloaded.txs;\n\t\tevts = opts.preloaded.events;\n\t} else {\n\t\tblock = await sourceDb\n\t\t\t.selectFrom(\"blocks\")\n\t\t\t.selectAll()\n\t\t\t.where(\"height\", \"=\", blockHeight)\n\t\t\t.executeTakeFirst();\n\n\t\tif (!block) {\n\t\t\tlogger.warn(\"Block not found for subgraph processing\", {\n\t\t\t\tsubgraph: subgraphName,\n\t\t\t\tblockHeight,\n\t\t\t});\n\t\t\tresult.skipped = true;\n\t\t\treturn result;\n\t\t}\n\n\t\tif (!block.canonical) {\n\t\t\tlogger.debug(\"Skipping non-canonical block\", {\n\t\t\t\tsubgraph: subgraphName,\n\t\t\t\tblockHeight,\n\t\t\t});\n\t\t\tresult.skipped = true;\n\t\t\treturn result;\n\t\t}\n\n\t\t// 2. Load txs + events (source DB)\n\t\ttxs = await sourceDb\n\t\t\t.selectFrom(\"transactions\")\n\t\t\t.selectAll()\n\t\t\t.where(\"block_height\", \"=\", blockHeight)\n\t\t\t.execute();\n\n\t\tevts = await sourceDb\n\t\t\t.selectFrom(\"events\")\n\t\t\t.selectAll()\n\t\t\t.where(\"block_height\", \"=\", blockHeight)\n\t\t\t.execute();\n\t}\n\n\t// 3. Match source. Trait-scoped sources ({ trait: \"sip-010\" }) resolve to the\n\t// set of conforming contracts AS OF this block (deploy_height ≤ blockHeight),\n\t// so a reindex backfills a token's full history even if it was classified\n\t// after deploy. Resolution is done here (DB access) so the matcher stays pure.\n\tconst traitContracts = await resolveTraitContracts(\n\t\tsubgraph,\n\t\tblockHeight,\n\t\ttargetDb,\n\t);\n\tconst matched = matchSources(subgraph.sources, txs, evts, traitContracts);\n\tresult.matched = matched.length;\n\n\tif (matched.length === 0) {\n\t\tif (!opts?.skipProgressUpdate) {\n\t\t\tawait updateSubgraphStatus(targetDb, subgraphName, \"active\", blockHeight);\n\t\t}\n\t\treturn result;\n\t}\n\n\t// 4. Resolve where this subgraph's data plane lives (managed target DB, or\n\t// the user's DB when BYO). Cached per subgraph.\n\tconst route = await resolveRoute(subgraphName, targetDb);\n\tconst schemaName = route.schemaName;\n\tconst blockMeta: BlockMeta = {\n\t\theight: block.height,\n\t\thash: block.hash,\n\t\ttimestamp: block.timestamp,\n\t\tburnBlockHeight: block.burn_block_height,\n\t};\n\tconst initialTx: TxMeta = {\n\t\ttxId: \"\",\n\t\tsender: \"\",\n\t\ttype: \"\",\n\t\tstatus: \"\",\n\t};\n\n\tlet handlerMs = 0;\n\tlet flushMs = 0;\n\n\t// Progress + health writes — always on the managed DB, identical in both\n\t// modes (the subgraphs control-plane table lives in target).\n\tconst applyProgress = async (\n\t\ttx: Transaction<Database>,\n\t\trr: { processed: number; errors: number },\n\t) => {\n\t\tif (opts?.skipProgressUpdate) return;\n\t\tconst status = rr.errors > 0 && rr.processed === 0 ? \"error\" : \"active\";\n\t\tawait updateSubgraphStatus(tx, subgraphName, status, blockHeight);\n\t\tif (rr.processed > 0 || rr.errors > 0) {\n\t\t\tconst lastError =\n\t\t\t\trr.errors > 0\n\t\t\t\t\t? `${rr.errors} error(s) at block ${blockHeight}`\n\t\t\t\t\t: undefined;\n\t\t\tawait recordSubgraphProcessed(\n\t\t\t\ttx,\n\t\t\t\tsubgraphName,\n\t\t\t\trr.processed,\n\t\t\t\trr.errors,\n\t\t\t\tlastError,\n\t\t\t);\n\t\t}\n\t};\n\n\tif (route.byo) {\n\t\t// BYO: no cross-DB transaction possible. Phase A commits handler writes to\n\t\t// the user DB first (replace-per-height makes a replay idempotent); phase\n\t\t// B then records outbox + progress on the managed DB. If phase A throws,\n\t\t// progress never advances and the block replays — safe by construction.\n\t\tlet runResult = { processed: 0, errors: 0 };\n\t\tlet manifest: Awaited<ReturnType<SubgraphContext[\"flush\"]>> | undefined;\n\t\tawait route.dataDb\n\t\t\t.transaction()\n\t\t\t.execute(async (tx: Transaction<Database>) => {\n\t\t\t\tconst ctx = new SubgraphContext(\n\t\t\t\t\ttx,\n\t\t\t\t\tschemaName,\n\t\t\t\t\tsubgraph.schema,\n\t\t\t\t\tblockMeta,\n\t\t\t\t\tinitialTx,\n\t\t\t\t\ttrue,\n\t\t\t\t);\n\t\t\t\tconst handlerStart = performance.now();\n\t\t\t\trunResult = await runHandlers(subgraph, matched, ctx);\n\t\t\t\thandlerMs = performance.now() - handlerStart;\n\t\t\t\tif (ctx.pendingOps > 0) {\n\t\t\t\t\tconst flushStart = performance.now();\n\t\t\t\t\tmanifest = await ctx.flush();\n\t\t\t\t\tflushMs = performance.now() - flushStart;\n\t\t\t\t}\n\t\t\t});\n\t\tresult.processed = runResult.processed;\n\t\tresult.errors = runResult.errors;\n\n\t\t// Phase B (managed) — only reached after phase A commits.\n\t\tawait targetDb.transaction().execute(async (tx: Transaction<Database>) => {\n\t\t\tif (manifest && manifest.count > 0) {\n\t\t\t\tawait emitSubscriptionOutbox(\n\t\t\t\t\ttx,\n\t\t\t\t\tsubgraphName,\n\t\t\t\t\tmanifest,\n\t\t\t\t\tmatcher,\n\t\t\t\t\tblock.height,\n\t\t\t\t);\n\t\t\t}\n\t\t\tawait applyProgress(tx, runResult);\n\t\t});\n\t} else {\n\t\t// Managed: a single atomic transaction on the target DB — unchanged.\n\t\tawait targetDb.transaction().execute(async (tx: Transaction<Database>) => {\n\t\t\tconst ctx = new SubgraphContext(\n\t\t\t\ttx,\n\t\t\t\tschemaName,\n\t\t\t\tsubgraph.schema,\n\t\t\t\tblockMeta,\n\t\t\t\tinitialTx,\n\t\t\t);\n\n\t\t\tconst handlerStart = performance.now();\n\t\t\tconst runResult = await runHandlers(subgraph, matched, ctx);\n\t\t\thandlerMs = performance.now() - handlerStart;\n\n\t\t\tresult.processed = runResult.processed;\n\t\t\tresult.errors = runResult.errors;\n\n\t\t\tif (ctx.pendingOps > 0) {\n\t\t\t\tconst flushStart = performance.now();\n\t\t\t\tconst manifest = await ctx.flush();\n\t\t\t\tif (manifest.count > 0) {\n\t\t\t\t\tawait emitSubscriptionOutbox(\n\t\t\t\t\t\ttx,\n\t\t\t\t\t\tsubgraphName,\n\t\t\t\t\t\tmanifest,\n\t\t\t\t\t\tmatcher,\n\t\t\t\t\t\tblock.height,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tflushMs = performance.now() - flushStart;\n\t\t\t}\n\n\t\t\tawait applyProgress(tx, runResult);\n\t\t});\n\t}\n\n\tconst totalMs = performance.now() - blockStart;\n\tresult.timing = {\n\t\ttotalMs: Math.round(totalMs),\n\t\thandlerMs: Math.round(handlerMs),\n\t\tflushMs: Math.round(flushMs),\n\t};\n\n\t// 7. Row count warning — sample every 1000 blocks (uses pg_stat estimate, not COUNT(*))\n\tif (blockHeight % 1000 === 0) {\n\t\ttry {\n\t\t\tconst tables = Object.keys(subgraph.schema);\n\t\t\tfor (const table of tables) {\n\t\t\t\tconst { rows } = await sql\n\t\t\t\t\t.raw(\n\t\t\t\t\t\t`SELECT n_live_tup AS count FROM pg_stat_user_tables WHERE schemaname = '${schemaName}' AND relname = '${table}'`,\n\t\t\t\t\t)\n\t\t\t\t\t.execute(route.dataDb);\n\t\t\t\tconst count = Number((rows[0] as Record<string, unknown>)?.count ?? 0);\n\t\t\t\tif (count >= 10_000_000) {\n\t\t\t\t\tlogger.warn(\"Subgraph table exceeds 10M rows (estimate)\", {\n\t\t\t\t\t\tsubgraph: subgraphName,\n\t\t\t\t\t\ttable,\n\t\t\t\t\t\tcount,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (err) {\n\t\t\t// Expected: table may not exist yet (fresh subgraph, first few\n\t\t\t// blocks before DDL runs). Log at debug so real errors —\n\t\t\t// connection, permissions, query plan — aren't invisible.\n\t\t\tlogger.debug(\"Row count sample failed\", {\n\t\t\t\tsubgraph: subgraphName,\n\t\t\t\terror: err instanceof Error ? err.message : String(err),\n\t\t\t});\n\t\t}\n\t}\n\n\treturn result;\n}\n",
|
|
10
10
|
"// Re-export canonical pgSchemaName from shared\nexport { pgSchemaName } from \"@secondlayer/shared/db/queries/subgraphs\";\n",
|
|
11
11
|
"import { createHash } from \"node:crypto\";\nimport type { Database } from \"@secondlayer/shared/db\";\nimport { logger } from \"@secondlayer/shared/logger\";\nimport type { Transaction } from \"kysely\";\nimport type { FlushManifest } from \"./context.ts\";\nimport type { SubscriptionMatcher } from \"./emitter-matcher.ts\";\n\n/**\n * Emit subscription outbox rows for every flushed write that matches an\n * active subscription. Inserted inside the caller's transaction — the\n * outbox write commits (or rolls back) atomically with the subgraph row\n * writes. Zero outbox inserts if no subs match or the kill-switch is set.\n *\n * Set `SECONDLAYER_EMIT_OUTBOX=false` to bypass entirely — useful during\n * backfills or when a receiver is known-down and operators want to drain\n * tenant writes without producing dead outbox.\n */\n\nlet loggedKillSwitch = false;\n\nexport function isEmitOutboxEnabled(): boolean {\n\treturn process.env.SECONDLAYER_EMIT_OUTBOX !== \"false\";\n}\n\nfunction dedupKey(\n\tsubgraphName: string,\n\ttableName: string,\n\tblockHeight: number,\n\ttxId: string,\n\trowIndex: number,\n\trow: Record<string, unknown>,\n): string {\n\t// Hash of row content + position → stable across replays of the same\n\t// block (unique constraint on (subscription_id, dedup_key) catches\n\t// duplicate emits if the block is reprocessed).\n\tconst canonical = `${subgraphName}:${tableName}:${blockHeight}:${txId}:${rowIndex}:${stableStringify(row)}`;\n\treturn createHash(\"sha256\").update(canonical).digest(\"hex\").slice(0, 32);\n}\n\nfunction stableStringify(obj: Record<string, unknown>): string {\n\tconst keys = Object.keys(obj).sort();\n\treturn JSON.stringify(\n\t\tkeys.reduce<Record<string, unknown>>((acc, k) => {\n\t\t\tacc[k] = obj[k];\n\t\t\treturn acc;\n\t\t}, {}),\n\t);\n}\n\nexport async function emitSubscriptionOutbox(\n\ttx: Transaction<Database>,\n\tsubgraphName: string,\n\tmanifest: FlushManifest,\n\tmatcher: SubscriptionMatcher,\n\tblockHeight: number,\n): Promise<number> {\n\tif (!isEmitOutboxEnabled()) {\n\t\tif (!loggedKillSwitch) {\n\t\t\tlogger.warn(\"SECONDLAYER_EMIT_OUTBOX=false — outbox emission bypassed\");\n\t\t\tloggedKillSwitch = true;\n\t\t}\n\t\treturn 0;\n\t}\n\tloggedKillSwitch = false;\n\n\tif (manifest.count === 0 || matcher.size() === 0) return 0;\n\n\ttype OutboxInsert = {\n\t\tsubscription_id: string;\n\t\tsubgraph_name: string;\n\t\ttable_name: string;\n\t\tblock_height: number;\n\t\ttx_id: string | null;\n\t\trow_pk: Record<string, unknown>;\n\t\tevent_type: string;\n\t\tpayload: Record<string, unknown>;\n\t\tdedup_key: string;\n\t};\n\n\tconst rows: OutboxInsert[] = [];\n\tfor (const write of manifest.writes) {\n\t\t// v1: emit on inserts only. Updates + deletes can land in a follow-up.\n\t\tif (write.op !== \"insert\") continue;\n\t\tconst subs = matcher.match(subgraphName, write.table, write.row);\n\t\tif (subs.length === 0) continue;\n\n\t\tconst eventType = `${subgraphName}.${write.table}.created`;\n\t\tfor (const s of subs) {\n\t\t\trows.push({\n\t\t\t\tsubscription_id: s.id,\n\t\t\t\tsubgraph_name: subgraphName,\n\t\t\t\ttable_name: write.table,\n\t\t\t\tblock_height: blockHeight,\n\t\t\t\t// Nullish-only — an empty-string txId is still a value (block-level\n\t\t\t\t// write with no specific tx), not \"no tx\".\n\t\t\t\ttx_id: write.pk.txId ?? null,\n\t\t\t\trow_pk: write.pk,\n\t\t\t\tevent_type: eventType,\n\t\t\t\tpayload: write.row,\n\t\t\t\tdedup_key: dedupKey(\n\t\t\t\t\tsubgraphName,\n\t\t\t\t\twrite.table,\n\t\t\t\t\twrite.pk.blockHeight,\n\t\t\t\t\twrite.pk.txId,\n\t\t\t\t\twrite.pk.rowIndex,\n\t\t\t\t\twrite.row,\n\t\t\t\t),\n\t\t\t});\n\t\t}\n\t}\n\n\tif (rows.length === 0) return 0;\n\n\t// Bulk INSERT with ON CONFLICT DO NOTHING on (subscription_id, dedup_key)\n\t// so a replayed block is a no-op instead of an error.\n\tawait tx\n\t\t.insertInto(\"subscription_outbox\")\n\t\t.values(rows)\n\t\t.onConflict((oc) =>\n\t\t\toc.columns([\"subscription_id\", \"dedup_key\"]).doNothing(),\n\t\t)\n\t\t.execute();\n\n\treturn rows.length;\n}\n",
|
|
12
12
|
"import type { Database, Subscription } from \"@secondlayer/shared/db\";\nimport { listSubscriptions } from \"@secondlayer/shared/db/queries/subscriptions\";\nimport type { Kysely } from \"kysely\";\nimport { sql } from \"kysely\";\nimport { SubscriptionMatcher } from \"./emitter-matcher.ts\";\n\n/**\n * Singleton matcher populated at processor startup and hot-reloaded via\n * `pg_notify('subscriptions:changed')`. The block-processor reads from it\n * to decide which outbox rows to emit for each flushed write.\n *\n * Per-account listing: in oss/dedicated mode the tenant DB holds all subs\n * for the single account; the matcher loads every row. In platform mode\n * the emitter doesn't run at all (control plane only), so this module is\n * dedicated/oss-only.\n */\n\nexport const matcher = new SubscriptionMatcher();\n\nexport async function refreshMatcher(db: Kysely<Database>): Promise<number> {\n\t// listSubscriptions is account-scoped; the emitter wants every active\n\t// sub so we do a raw query.\n\tconst rows = await sql<Subscription>`\n\t\tSELECT * FROM subscriptions WHERE status = 'active'\n\t`.execute(db);\n\tmatcher.setAll(rows.rows);\n\treturn matcher.size();\n}\n\n// Per-account helper used by tests so the DATABASE_URL-based code path is\n// exercised through listSubscriptions (keeps the query helper in the\n// integration surface).\nexport async function refreshMatcherForAccount(\n\tdb: Kysely<Database>,\n\taccountId: string,\n): Promise<number> {\n\tconst rows = await listSubscriptions(db, accountId);\n\tmatcher.setAll(rows.filter((r: Subscription) => r.status === \"active\"));\n\treturn matcher.size();\n}\n",
|
|
13
13
|
"import type { Subscription } from \"@secondlayer/shared/db\";\n\n/**\n * Subscription matcher — holds the active-subscriptions cache keyed by\n * `(subgraph_name, table_name)` and evaluates each sub's scalar-only\n * JSONB filter against a row.\n *\n * Filter DSL (v1): scalar operators over string/number/boolean columns.\n * { column: value } → column === value\n * { column: { eq: value } } → column === value\n * { column: { neq: value } } → column !== value\n * { column: { gt|gte|lt|lte: N } } → numeric compare\n * { column: { in: [a, b, c] } } → column ∈ set\n * { } → match all\n *\n * Nested objects, arrays, and non-scalar values are rejected with `false`\n * (never match) — subscribers get logged warnings at sub create time.\n *\n * Multiple conditions AND together. OR is deliberately absent in v1.\n */\n\nexport type FilterPrimitive = string | number | boolean;\nexport type FilterOperator =\n\t| { eq: FilterPrimitive }\n\t| { neq: FilterPrimitive }\n\t| { gt: number | string }\n\t| { gte: number | string }\n\t| { lt: number | string }\n\t| { lte: number | string }\n\t| { in: FilterPrimitive[] };\n\nexport type FilterClause = FilterPrimitive | FilterOperator;\nexport type SubscriptionFilter = Record<string, FilterClause>;\n\nfunction isPrimitive(v: unknown): v is FilterPrimitive {\n\tconst t = typeof v;\n\treturn t === \"string\" || t === \"number\" || t === \"boolean\";\n}\n\n/**\n * Coerce a value to BigInt for arbitrary-precision compare — avoids the\n * silent precision loss of `Number()` on integers past 2^53. Returns\n * `null` for non-integer numerics, which is fine because the filter DSL\n * is documented as scalar-only + integer-amount-aware (Stacks uses\n * uint128 bigint columns everywhere).\n */\nfunction coerceBigInt(v: unknown): bigint | null {\n\tif (typeof v === \"bigint\") return v;\n\tif (typeof v === \"number\") {\n\t\tif (!Number.isFinite(v)) return null;\n\t\tif (!Number.isInteger(v)) return null;\n\t\treturn BigInt(v);\n\t}\n\tif (typeof v === \"string\" && /^-?\\d+$/.test(v)) {\n\t\ttry {\n\t\t\treturn BigInt(v);\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\treturn null;\n}\n\n/**\n * Float compare fallback — used when a value isn't a clean integer\n * (rare in subgraph columns but defensible for user-supplied filters).\n */\nfunction coerceFloat(v: unknown): number | null {\n\tif (typeof v === \"number\" && Number.isFinite(v)) return v;\n\tif (typeof v === \"bigint\") return Number(v);\n\tif (typeof v === \"string\" && v !== \"\" && !Number.isNaN(Number(v))) {\n\t\treturn Number(v);\n\t}\n\treturn null;\n}\n\nfunction compareNumeric(a: unknown, b: unknown): 0 | 1 | -1 | null {\n\tconst ba = coerceBigInt(a);\n\tconst bb = coerceBigInt(b);\n\tif (ba !== null && bb !== null) {\n\t\tif (ba === bb) return 0;\n\t\treturn ba > bb ? 1 : -1;\n\t}\n\tconst fa = coerceFloat(a);\n\tconst fb = coerceFloat(b);\n\tif (fa === null || fb === null) return null;\n\tif (fa === fb) return 0;\n\treturn fa > fb ? 1 : -1;\n}\n\nfunction matchClause(rowValue: unknown, clause: FilterClause): boolean {\n\t// Reject non-primitive row values — `{ value: {...} }` should not\n\t// match `filter: { value: \"[object Object]\" }` via loose stringify.\n\t// Bigints are not primitives in the JSON sense but are supported\n\t// scalar inputs from subgraph rows.\n\tconst rowIsPrimitive = isPrimitive(rowValue) || typeof rowValue === \"bigint\";\n\n\tif (isPrimitive(clause)) {\n\t\tif (!rowIsPrimitive) return false;\n\t\tif (\n\t\t\ttypeof clause === \"number\" ||\n\t\t\ttypeof rowValue === \"number\" ||\n\t\t\ttypeof rowValue === \"bigint\"\n\t\t) {\n\t\t\tconst cmp = compareNumeric(rowValue, clause);\n\t\t\tif (cmp !== null) return cmp === 0;\n\t\t}\n\t\treturn rowValue === clause || String(rowValue) === String(clause);\n\t}\n\n\tif (clause === null || typeof clause !== \"object\" || Array.isArray(clause)) {\n\t\treturn false;\n\t}\n\n\tconst keys = Object.keys(clause);\n\tif (keys.length !== 1) return false;\n\tconst op = keys[0];\n\n\tconst c = clause as Record<string, unknown>;\n\tswitch (op) {\n\t\tcase \"eq\":\n\t\t\treturn matchClause(rowValue, c.eq as FilterPrimitive);\n\t\tcase \"neq\":\n\t\t\treturn !matchClause(rowValue, c.neq as FilterPrimitive);\n\t\tcase \"gt\":\n\t\tcase \"gte\":\n\t\tcase \"lt\":\n\t\tcase \"lte\": {\n\t\t\tif (!rowIsPrimitive) return false;\n\t\t\tconst cmp = compareNumeric(rowValue, c[op]);\n\t\t\tif (cmp === null) return false;\n\t\t\tif (op === \"gt\") return cmp > 0;\n\t\t\tif (op === \"gte\") return cmp >= 0;\n\t\t\tif (op === \"lt\") return cmp < 0;\n\t\t\treturn cmp <= 0;\n\t\t}\n\t\tcase \"in\": {\n\t\t\tconst list = c.in;\n\t\t\tif (!Array.isArray(list)) return false;\n\t\t\tif (!rowIsPrimitive) return false;\n\t\t\treturn list.some(\n\t\t\t\t(item) => isPrimitive(item) && matchClause(rowValue, item),\n\t\t\t);\n\t\t}\n\t\tdefault:\n\t\t\treturn false;\n\t}\n}\n\nexport function matchesFilter(\n\tfilter: SubscriptionFilter | null | undefined,\n\trow: Record<string, unknown>,\n): boolean {\n\tif (!filter || Object.keys(filter).length === 0) return true;\n\tfor (const [col, clause] of Object.entries(filter)) {\n\t\tif (!matchClause(row[col], clause)) return false;\n\t}\n\treturn true;\n}\n\n// ── Cache keyed by (subgraph_name, table_name) ──────────────────────────\n\ntype MatcherKey = string;\n\nfunction key(subgraphName: string, tableName: string): MatcherKey {\n\treturn `${subgraphName}\u0000${tableName}`;\n}\n\nexport class SubscriptionMatcher {\n\tprivate readonly byKey = new Map<MatcherKey, Subscription[]>();\n\tprivate readonly byId = new Map<string, Subscription>();\n\n\t/** Replace the entire cache with a fresh snapshot. */\n\tsetAll(subs: Subscription[]): void {\n\t\tthis.byKey.clear();\n\t\tthis.byId.clear();\n\t\tfor (const sub of subs) {\n\t\t\tif (sub.status !== \"active\") continue;\n\t\t\tthis.byId.set(sub.id, sub);\n\t\t\tconst k = key(sub.subgraph_name, sub.table_name);\n\t\t\tconst arr = this.byKey.get(k);\n\t\t\tif (arr) arr.push(sub);\n\t\t\telse this.byKey.set(k, [sub]);\n\t\t}\n\t}\n\n\t/** Returns active subs for a (subgraph, table) whose filter matches the row. */\n\tmatch(\n\t\tsubgraphName: string,\n\t\ttableName: string,\n\t\trow: Record<string, unknown>,\n\t): Subscription[] {\n\t\tconst bucket = this.byKey.get(key(subgraphName, tableName));\n\t\tif (!bucket) return [];\n\t\tconst hits: Subscription[] = [];\n\t\tfor (const sub of bucket) {\n\t\t\tif (matchesFilter(sub.filter as SubscriptionFilter, row)) hits.push(sub);\n\t\t}\n\t\treturn hits;\n\t}\n\n\thas(subgraphName: string, tableName: string): boolean {\n\t\treturn this.byKey.has(key(subgraphName, tableName));\n\t}\n\n\tsize(): number {\n\t\treturn this.byId.size;\n\t}\n\n\tget(id: string): Subscription | undefined {\n\t\treturn this.byId.get(id);\n\t}\n}\n",
|
|
14
|
-
"import { getErrorMessage } from \"@secondlayer/shared\";\nimport {
|
|
14
|
+
"import { getErrorMessage } from \"@secondlayer/shared\";\nimport { getTargetDb } from \"@secondlayer/shared/db\";\nimport type { Subgraph } from \"@secondlayer/shared/db\";\nimport {\n\tlistSubgraphs,\n\tresolveSubgraphRawClient,\n} from \"@secondlayer/shared/db/queries/subgraphs\";\nimport { logger } from \"@secondlayer/shared/logger\";\nimport { pgSchemaName } from \"../schema/utils.ts\";\nimport type { SubgraphDefinition, SubgraphSchema } from \"../types.ts\";\nimport { processBlock } from \"./block-processor.ts\";\n\n/**\n * Handle a chain reorg for all active subgraphs.\n *\n * `blockHeight` is the **shallowest** height where the chain diverged. The\n * indexer's `handleReorg` has already marked every block ≥ `blockHeight`\n * as non-canonical (a Stacks reorg can span many blocks). We mirror that\n * here: delete rows where `_block_height >= blockHeight` from every\n * subgraph table, then reprocess `blockHeight` (subsequent heights will\n * be reprocessed as the indexer ingests new-chain blocks).\n *\n * Subscription receivers that already consumed the now-reverted events\n * need to know about the rollback. We emit one `<table>.reverted` event\n * per affected table per subscription. The receiver is expected to\n * reverse any side-effects keyed on the rolled-back rows; if they ignore\n * revert events, at least we provided the signal.\n */\nexport async function handleSubgraphReorg(\n\tblockHeight: number,\n\tloadSubgraphDef: (sg: Subgraph) => Promise<SubgraphDefinition>,\n): Promise<void> {\n\t// The subgraphs registry + revert-event outbox live on the managed target\n\t// DB; the row SELECT/DELETE target each subgraph's data plane (the user's DB\n\t// for BYO), resolved per subgraph inside the loop.\n\tconst targetDb = getTargetDb();\n\tconst activeSubgraphs = (await listSubgraphs(targetDb)).filter(\n\t\t(v: Subgraph) => v.status === \"active\",\n\t);\n\n\tif (activeSubgraphs.length === 0) return;\n\n\tlogger.info(\"Propagating reorg to subgraphs\", {\n\t\tblockHeight,\n\t\tsubgraphCount: activeSubgraphs.length,\n\t});\n\n\tfor (const sg of activeSubgraphs) {\n\t\ttry {\n\t\t\tconst schema = sg.definition.schema as SubgraphSchema | undefined;\n\t\t\tif (!schema) continue;\n\n\t\t\tconst schemaName = sg.schema_name ?? pgSchemaName(sg.name);\n\t\t\t// Rows live on the subgraph's data plane — user DB for BYO, else target.\n\t\t\tconst client = resolveSubgraphRawClient(sg);\n\n\t\t\t// Snapshot affected rows BEFORE deletion so we can surface them\n\t\t\t// to subscription receivers as revert events. Cap at 1k rows\n\t\t\t// per (table, reorg) to bound memory; deeper reverts are rare\n\t\t\t// and at-volume the receiver should be reading from the table\n\t\t\t// directly anyway.\n\t\t\tconst tableNames = Object.keys(schema);\n\t\t\tconst revertedByTable: Record<string, unknown[]> = {};\n\t\t\tfor (const tableName of tableNames) {\n\t\t\t\tconst rows = await client.unsafe<unknown[]>(\n\t\t\t\t\t`SELECT * FROM \"${schemaName}\".\"${tableName}\" WHERE \"_block_height\" >= $1 LIMIT 1000`,\n\t\t\t\t\t[blockHeight],\n\t\t\t\t);\n\t\t\t\tif (rows.length > 0) revertedByTable[tableName] = rows;\n\t\t\t}\n\n\t\t\t// Delete rows at-or-above the reorg root from all tables.\n\t\t\tfor (const tableName of tableNames) {\n\t\t\t\tawait client.unsafe(\n\t\t\t\t\t`DELETE FROM \"${schemaName}\".\"${tableName}\" WHERE \"_block_height\" >= $1`,\n\t\t\t\t\t[blockHeight],\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Emit revert events to dependent subscriptions so receivers\n\t\t\t// know to roll back. Insert into subscription_outbox with a\n\t\t\t// stable dedup_key keyed on (subscription, table, height,\n\t\t\t// \"revert\") so a duplicate reorg notification is a no-op.\n\t\t\tfor (const [tableName, rows] of Object.entries(revertedByTable)) {\n\t\t\t\tif (rows.length === 0) continue;\n\t\t\t\tawait targetDb\n\t\t\t\t\t.insertInto(\"subscription_outbox\")\n\t\t\t\t\t.columns([\n\t\t\t\t\t\t\"subscription_id\",\n\t\t\t\t\t\t\"event_type\",\n\t\t\t\t\t\t\"payload\",\n\t\t\t\t\t\t\"dedup_key\",\n\t\t\t\t\t\t\"row_pk\",\n\t\t\t\t\t\t\"status\",\n\t\t\t\t\t])\n\t\t\t\t\t.expression((eb) =>\n\t\t\t\t\t\teb\n\t\t\t\t\t\t\t.selectFrom(\"subscriptions\")\n\t\t\t\t\t\t\t.select((eb2) => [\n\t\t\t\t\t\t\t\t\"id as subscription_id\",\n\t\t\t\t\t\t\t\teb2.val(`${sg.name}.${tableName}.reverted`).as(\"event_type\"),\n\t\t\t\t\t\t\t\teb2\n\t\t\t\t\t\t\t\t\t.val(\n\t\t\t\t\t\t\t\t\t\tJSON.stringify({\n\t\t\t\t\t\t\t\t\t\t\tsubgraph: sg.name,\n\t\t\t\t\t\t\t\t\t\t\ttable: tableName,\n\t\t\t\t\t\t\t\t\t\t\treorgFromHeight: blockHeight,\n\t\t\t\t\t\t\t\t\t\t\trows,\n\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t.as(\"payload\"),\n\t\t\t\t\t\t\t\teb2\n\t\t\t\t\t\t\t\t\t.val(`reorg:${sg.name}:${tableName}:${blockHeight}`)\n\t\t\t\t\t\t\t\t\t.as(\"dedup_key\"),\n\t\t\t\t\t\t\t\teb2\n\t\t\t\t\t\t\t\t\t.val({\n\t\t\t\t\t\t\t\t\t\tsubgraph: sg.name,\n\t\t\t\t\t\t\t\t\t\ttable: tableName,\n\t\t\t\t\t\t\t\t\t\treorgRoot: blockHeight,\n\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t\t.as(\"row_pk\"),\n\t\t\t\t\t\t\t\teb2.val(\"pending\").as(\"status\"),\n\t\t\t\t\t\t\t])\n\t\t\t\t\t\t\t.where(\"subgraph_name\", \"=\", sg.name)\n\t\t\t\t\t\t\t.where(\"table_name\", \"=\", tableName)\n\t\t\t\t\t\t\t.where(\"status\", \"=\", \"active\"),\n\t\t\t\t\t)\n\t\t\t\t\t.onConflict((oc) => oc.column(\"dedup_key\").doNothing())\n\t\t\t\t\t.execute()\n\t\t\t\t\t.catch((err) => {\n\t\t\t\t\t\t// Don't fail the reorg cleanup if the revert event\n\t\t\t\t\t\t// emission errors — subscriptions can't be more\n\t\t\t\t\t\t// broken than they were pre-reorg.\n\t\t\t\t\t\tlogger.warn(\"Failed to emit revert event for subscriptions\", {\n\t\t\t\t\t\t\tsubgraph: sg.name,\n\t\t\t\t\t\t\ttable: tableName,\n\t\t\t\t\t\t\tblockHeight,\n\t\t\t\t\t\t\terror: getErrorMessage(err),\n\t\t\t\t\t\t});\n\t\t\t\t\t});\n\t\t\t}\n\n\t\t\tlogger.info(\"Subgraph reorg cleanup done\", {\n\t\t\t\tsubgraph: sg.name,\n\t\t\t\tblockHeight,\n\t\t\t\ttablesAffected: Object.keys(revertedByTable).length,\n\t\t\t});\n\n\t\t\t// Reprocess the new canonical block. Subsequent blocks above\n\t\t\t// `blockHeight` will be reprocessed as the indexer ingests\n\t\t\t// them — they're already marked non-canonical by handleReorg.\n\t\t\tconst def = await loadSubgraphDef(sg);\n\t\t\tawait processBlock(def, sg.name, blockHeight);\n\n\t\t\tlogger.info(\"Subgraph reorg reprocessed\", {\n\t\t\t\tsubgraph: sg.name,\n\t\t\t\tblockHeight,\n\t\t\t});\n\t\t} catch (err) {\n\t\t\tlogger.error(\"Subgraph reorg handling failed\", {\n\t\t\t\tsubgraph: sg.name,\n\t\t\t\tblockHeight,\n\t\t\t\terror: getErrorMessage(err),\n\t\t\t});\n\t\t}\n\t}\n}\n"
|
|
15
15
|
],
|
|
16
|
-
"mappings": "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",
|
|
17
|
-
"debugId": "
|
|
16
|
+
"mappings": "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",
|
|
17
|
+
"debugId": "39C8DEB104D91A4564756E2164756E21",
|
|
18
18
|
"names": []
|
|
19
19
|
}
|
|
@@ -9,6 +9,22 @@ interface SubgraphColumn {
|
|
|
9
9
|
search?: boolean;
|
|
10
10
|
default?: string | number | boolean;
|
|
11
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* A foreign-key relation to another table in the same subgraph. Drives DDL FK
|
|
14
|
+
* constraints and ORM codegen (`@relation` in Prisma, `relations()` in Drizzle)
|
|
15
|
+
* so generated clients get typed joins. The referenced columns must form a
|
|
16
|
+
* `uniqueKeys` entry on the target table.
|
|
17
|
+
*/
|
|
18
|
+
interface SubgraphRelation {
|
|
19
|
+
/** Relation field name on this table's generated model (e.g. "pool"). */
|
|
20
|
+
name: string;
|
|
21
|
+
/** Target table name in this subgraph. */
|
|
22
|
+
references: string;
|
|
23
|
+
/** Local column(s) holding the foreign key. */
|
|
24
|
+
fields: string[];
|
|
25
|
+
/** Target column(s) the fields point at (a uniqueKeys entry on the target). */
|
|
26
|
+
referencedColumns: string[];
|
|
27
|
+
}
|
|
12
28
|
/** Table definition within a subgraph schema */
|
|
13
29
|
interface SubgraphTable {
|
|
14
30
|
columns: Record<string, SubgraphColumn>;
|
|
@@ -16,6 +32,8 @@ interface SubgraphTable {
|
|
|
16
32
|
indexes?: string[][];
|
|
17
33
|
/** Unique key constraints (each entry is an array of column names). Required for upsert. */
|
|
18
34
|
uniqueKeys?: string[][];
|
|
35
|
+
/** Foreign-key relations to other tables (for typed ORM joins). */
|
|
36
|
+
relations?: SubgraphRelation[];
|
|
19
37
|
}
|
|
20
38
|
/** Subgraph schema — maps table names to table definitions */
|
|
21
39
|
type SubgraphSchema = Record<string, SubgraphTable>;
|
|
@@ -42,45 +60,53 @@ interface StxLockFilter {
|
|
|
42
60
|
lockedAddress?: string;
|
|
43
61
|
minAmount?: bigint;
|
|
44
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* Restrict a source to contracts conforming to a trait/standard (e.g. "sip-010")
|
|
65
|
+
* instead of a fixed contract — resolved from the contract registry at match time,
|
|
66
|
+
* as-of each processed block. Lets a source index "all SIP-010 tokens" etc.
|
|
67
|
+
*/
|
|
68
|
+
type TraitScope = {
|
|
69
|
+
trait?: string
|
|
70
|
+
};
|
|
45
71
|
/** FT event filters */
|
|
46
|
-
interface FtTransferFilter {
|
|
72
|
+
interface FtTransferFilter extends TraitScope {
|
|
47
73
|
type: "ft_transfer";
|
|
48
74
|
assetIdentifier?: string;
|
|
49
75
|
sender?: string;
|
|
50
76
|
recipient?: string;
|
|
51
77
|
minAmount?: bigint;
|
|
52
78
|
}
|
|
53
|
-
interface FtMintFilter {
|
|
79
|
+
interface FtMintFilter extends TraitScope {
|
|
54
80
|
type: "ft_mint";
|
|
55
81
|
assetIdentifier?: string;
|
|
56
82
|
recipient?: string;
|
|
57
83
|
minAmount?: bigint;
|
|
58
84
|
}
|
|
59
|
-
interface FtBurnFilter {
|
|
85
|
+
interface FtBurnFilter extends TraitScope {
|
|
60
86
|
type: "ft_burn";
|
|
61
87
|
assetIdentifier?: string;
|
|
62
88
|
sender?: string;
|
|
63
89
|
minAmount?: bigint;
|
|
64
90
|
}
|
|
65
91
|
/** NFT event filters */
|
|
66
|
-
interface NftTransferFilter {
|
|
92
|
+
interface NftTransferFilter extends TraitScope {
|
|
67
93
|
type: "nft_transfer";
|
|
68
94
|
assetIdentifier?: string;
|
|
69
95
|
sender?: string;
|
|
70
96
|
recipient?: string;
|
|
71
97
|
}
|
|
72
|
-
interface NftMintFilter {
|
|
98
|
+
interface NftMintFilter extends TraitScope {
|
|
73
99
|
type: "nft_mint";
|
|
74
100
|
assetIdentifier?: string;
|
|
75
101
|
recipient?: string;
|
|
76
102
|
}
|
|
77
|
-
interface NftBurnFilter {
|
|
103
|
+
interface NftBurnFilter extends TraitScope {
|
|
78
104
|
type: "nft_burn";
|
|
79
105
|
assetIdentifier?: string;
|
|
80
106
|
sender?: string;
|
|
81
107
|
}
|
|
82
108
|
/** Contract event filters */
|
|
83
|
-
interface ContractCallFilter {
|
|
109
|
+
interface ContractCallFilter extends TraitScope {
|
|
84
110
|
type: "contract_call";
|
|
85
111
|
contractId?: string;
|
|
86
112
|
functionName?: string;
|
|
@@ -98,7 +124,7 @@ interface ContractDeployFilter {
|
|
|
98
124
|
deployer?: string;
|
|
99
125
|
contractName?: string;
|
|
100
126
|
}
|
|
101
|
-
interface PrintEventFilter {
|
|
127
|
+
interface PrintEventFilter extends TraitScope {
|
|
102
128
|
type: "print_event";
|
|
103
129
|
contractId?: string;
|
|
104
130
|
topic?: string;
|
|
@@ -222,7 +248,15 @@ declare class SubgraphContext2 {
|
|
|
222
248
|
private readonly pgSchemaName;
|
|
223
249
|
private readonly subgraphSchema;
|
|
224
250
|
private readonly ops;
|
|
225
|
-
|
|
251
|
+
/**
|
|
252
|
+
* BYO data plane: handler writes land in a user-owned DB whose flush can't
|
|
253
|
+
* share the managed block transaction, so a crash replays the block. When
|
|
254
|
+
* set, flush() prepends a replace-per-height DELETE for every inserted table
|
|
255
|
+
* (`_block_height = N` → re-INSERT), making block reprocessing idempotent.
|
|
256
|
+
* Non-idempotent `update` handlers are rejected at deploy, not here.
|
|
257
|
+
*/
|
|
258
|
+
private readonly byo;
|
|
259
|
+
constructor(db: AnyDb, pgSchemaName: string, subgraphSchema: SubgraphSchema, block: BlockMeta, tx: TxMeta2, byo?: boolean);
|
|
226
260
|
get tx(): TxMeta2;
|
|
227
261
|
/** Update the current transaction context (used by runner between events) */
|
|
228
262
|
setTx(tx: TxMeta2): void;
|