@secondlayer/subgraphs 0.5.7 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/src/index.d.ts +17 -5
  2. package/dist/src/index.js +467 -191
  3. package/dist/src/index.js.map +16 -15
  4. package/dist/src/runtime/block-processor.d.ts +9 -1
  5. package/dist/src/runtime/block-processor.js +216 -144
  6. package/dist/src/runtime/block-processor.js.map +9 -9
  7. package/dist/src/runtime/catchup.d.ts +2 -2
  8. package/dist/src/runtime/catchup.js +366 -160
  9. package/dist/src/runtime/catchup.js.map +12 -11
  10. package/dist/src/runtime/clarity.js.map +2 -2
  11. package/dist/src/runtime/context.d.ts +4 -2
  12. package/dist/src/runtime/context.js +79 -36
  13. package/dist/src/runtime/context.js.map +3 -3
  14. package/dist/src/runtime/processor.js +384 -166
  15. package/dist/src/runtime/processor.js.map +14 -13
  16. package/dist/src/runtime/reindex.d.ts +13 -1
  17. package/dist/src/runtime/reindex.js +459 -189
  18. package/dist/src/runtime/reindex.js.map +13 -12
  19. package/dist/src/runtime/reorg.js +229 -148
  20. package/dist/src/runtime/reorg.js.map +10 -10
  21. package/dist/src/runtime/runner.d.ts +4 -2
  22. package/dist/src/runtime/runner.js +7 -3
  23. package/dist/src/runtime/runner.js.map +4 -4
  24. package/dist/src/runtime/source-matcher.js.map +3 -3
  25. package/dist/src/runtime/stats.d.ts +1 -1
  26. package/dist/src/runtime/stats.js +2 -2
  27. package/dist/src/runtime/stats.js.map +3 -3
  28. package/dist/src/schema/index.d.ts +1 -1
  29. package/dist/src/schema/index.js +9 -3
  30. package/dist/src/schema/index.js.map +5 -5
  31. package/dist/src/service.js +385 -167
  32. package/dist/src/service.js.map +15 -14
  33. package/dist/src/templates.js.map +2 -2
  34. package/dist/src/types.js.map +2 -2
  35. package/dist/src/validate.js +2 -2
  36. package/dist/src/validate.js.map +3 -3
  37. package/package.json +51 -51
@@ -1,22 +1,23 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/types.ts", "../src/validate.ts", "../src/runtime/context.ts", "../src/runtime/source-matcher.ts", "../src/runtime/clarity.ts", "../src/runtime/runner.ts", "../src/runtime/block-processor.ts", "../src/schema/utils.ts", "../src/runtime/stats.ts", "../src/runtime/reindex.ts", "../src/schema/generator.ts", "../src/define.ts", "../src/schema/deployer.ts"],
3
+ "sources": ["../src/types.ts", "../src/validate.ts", "../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/stats.ts", "../src/runtime/reindex.ts", "../src/schema/generator.ts", "../src/runtime/batch-loader.ts", "../src/define.ts", "../src/schema/deployer.ts"],
4
4
  "sourcesContent": [
5
- "/** Supported column types for subgraph schemas */\nexport type ColumnType =\n | \"text\"\n | \"uint\"\n | \"int\"\n | \"principal\"\n | \"boolean\"\n | \"timestamp\"\n | \"jsonb\";\n\n/** Column definition in a subgraph table */\nexport interface SubgraphColumn {\n type: ColumnType;\n nullable?: boolean;\n indexed?: boolean;\n search?: boolean;\n default?: string | number | boolean;\n}\n\n/** Table definition within a subgraph schema */\nexport interface SubgraphTable {\n columns: Record<string, SubgraphColumn>;\n /** Composite indexes (each entry is an array of column names) */\n indexes?: string[][];\n /** Unique key constraints (each entry is an array of column names). Required for upsert. */\n uniqueKeys?: string[][];\n}\n\n/** Subgraph schema — maps table names to table definitions */\nexport type SubgraphSchema = Record<string, SubgraphTable>;\n\n/** Source filter for what blockchain data this subgraph processes */\nexport interface SubgraphSource {\n /** Contract principal (e.g., SP000...::contract-name). Supports * wildcards. */\n contract?: string;\n /** Event name/topic to filter on */\n event?: string;\n /** Function name to filter on */\n function?: string;\n /** Transaction type filter (e.g., \"stx_transfer\", \"contract_call\") */\n type?: string;\n /** Minimum amount filter (for stx_transfer sources) */\n minAmount?: bigint;\n}\n\n/** Context passed to subgraph handlers during event processing */\nexport interface SubgraphContext {\n block: { height: number; hash: string; timestamp: number; burnBlockHeight: number };\n tx: { txId: string; sender: string; type: string; status: string };\n insert(table: string, row: Record<string, unknown>): void;\n update(table: string, where: Record<string, unknown>, set: Record<string, unknown>): void;\n upsert(table: string, key: Record<string, unknown>, row: Record<string, unknown>): void;\n delete(table: string, where: Record<string, unknown>): void;\n findOne(table: string, where: Record<string, unknown>): Promise<Record<string, unknown> | null>;\n findMany(table: string, where: Record<string, unknown>): Promise<Record<string, unknown>[]>;\n}\n\n/** Handler function that processes events and writes to the subgraph */\nexport type SubgraphHandler = (\n event: Record<string, unknown>,\n ctx: SubgraphContext,\n) => Promise<void> | void;\n\n/**\n * Derive the source key used to look up handlers.\n * - { contract: \"SP123.market\", function: \"list\" } → \"SP123.market::list\"\n * - { contract: \"SP123.market\", event: \"sale\" } → \"SP123.market::sale\"\n * - { contract: \"SP123.market\" } → \"SP123.market\"\n * - { type: \"stx_transfer\" } → \"stx_transfer\"\n */\nexport function sourceKey(source: SubgraphSource): string {\n if (source.contract) {\n if (source.function) return `${source.contract}::${source.function}`;\n if (source.event) return `${source.contract}::${source.event}`;\n return source.contract;\n }\n if (source.type) return source.type;\n return \"*\";\n}\n\n/** Complete subgraph definition */\nexport interface SubgraphDefinition {\n /** Unique subgraph name (lowercase, alphanumeric + hyphens) */\n name: string;\n /** Semantic version */\n version?: string;\n /** Human description */\n description?: string;\n /** What blockchain data to process — one or more source filters */\n sources: SubgraphSource[];\n /** Tables in this subgraph */\n schema: SubgraphSchema;\n /** Keyed handler functions — keys match sourceKey() output, \"*\" is catch-all */\n handlers: Record<string, SubgraphHandler>;\n}\n",
6
- "import { z } from \"zod/v4\";\nimport type { ColumnType, SubgraphColumn, SubgraphTable, SubgraphSource, SubgraphDefinition } from \"./types.ts\";\n\nexport const SubgraphNameSchema: z.ZodType<string> = z\n .string()\n .min(1)\n .max(63)\n .regex(\n /^[a-z][a-z0-9-]*$/,\n \"Must start with lowercase letter, contain only lowercase alphanumeric and hyphens\",\n );\n\nexport const ColumnTypeSchema: z.ZodType<ColumnType> = z.enum([\n \"text\",\n \"uint\",\n \"int\",\n \"principal\",\n \"boolean\",\n \"timestamp\",\n \"jsonb\",\n]);\n\nexport const SubgraphColumnSchema: z.ZodType<SubgraphColumn> = z.object({\n type: ColumnTypeSchema,\n nullable: z.boolean().optional(),\n indexed: z.boolean().optional(),\n search: z.boolean().optional(),\n default: z.union([z.string(), z.number(), z.boolean()]).optional(),\n}) as z.ZodType<SubgraphColumn>;\n\nexport const SubgraphTableSchema: z.ZodType<SubgraphTable> = z.object({\n columns: z\n .record(z.string(), SubgraphColumnSchema)\n .refine((c) => Object.keys(c).length > 0, \"Table must have at least one column\"),\n indexes: z.array(z.array(z.string())).optional(),\n uniqueKeys: z.array(z.array(z.string())).optional(),\n}) as z.ZodType<SubgraphTable>;\n\nexport const SubgraphSchemaSchema: z.ZodType<Record<string, SubgraphTable>> = z\n .record(z.string(), SubgraphTableSchema)\n .refine((s) => Object.keys(s).length > 0, \"Schema must have at least one table\") as z.ZodType<Record<string, SubgraphTable>>;\n\nexport const SubgraphSourceSchema: z.ZodType<SubgraphSource> = z\n .object({\n contract: z.string().optional(),\n event: z.string().optional(),\n function: z.string().optional(),\n type: z.string().optional(),\n minAmount: z.bigint().optional(),\n })\n .refine(\n (s) => s.contract || s.type,\n \"Source must specify at least 'contract' or 'type'\",\n ) as z.ZodType<SubgraphSource>;\n\nexport const SubgraphDefinitionSchema: z.ZodType<SubgraphDefinition> = z.object({\n name: SubgraphNameSchema,\n version: z.string().optional(),\n description: z.string().optional(),\n sources: z.array(SubgraphSourceSchema).min(1, \"Must have at least one source\"),\n schema: SubgraphSchemaSchema,\n handlers: z.record(z.string(), z.function() as unknown as z.ZodType<Function>),\n}) as unknown as z.ZodType<SubgraphDefinition>;\n\n/**\n * Validates a subgraph definition, returning the parsed result or throwing on failure.\n */\nexport function validateSubgraphDefinition(def: unknown): SubgraphDefinition {\n return SubgraphDefinitionSchema.parse(def);\n}\n",
7
- "import { sql, type Kysely, type Transaction } from \"kysely\";\nimport type { Database } from \"@secondlayer/shared/db\";\nimport { logger } from \"@secondlayer/shared/logger\";\nimport type { SubgraphSchema } from \"../types.ts\";\n\ntype AnyDb = Kysely<Database> | Transaction<Database>;\n\ninterface WriteOp {\n kind: \"insert\" | \"update\" | \"delete\";\n table: string;\n data: Record<string, unknown>;\n /** For update: SET clause */\n set?: Record<string, unknown>;\n}\n\nexport interface BlockMeta {\n height: number;\n hash: string;\n timestamp: number;\n burnBlockHeight: number;\n}\n\nexport interface TxMeta {\n txId: string;\n sender: string;\n type: string;\n status: string;\n}\n\n/** Validate that a column name is safe for SQL identifiers */\nfunction validateColumnName(name: string): void {\n if (!/^[a-z_][a-z0-9_]*$/i.test(name)) {\n throw new Error(`Invalid column name: ${name}`);\n }\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 readonly block: BlockMeta;\n private _tx: TxMeta;\n private readonly db: AnyDb;\n private readonly pgSchemaName: string;\n private readonly subgraphSchema: SubgraphSchema;\n private readonly ops: WriteOp[] = [];\n\n constructor(\n db: AnyDb,\n pgSchemaName: string,\n subgraphSchema: SubgraphSchema,\n block: BlockMeta,\n tx: TxMeta,\n ) {\n this.db = db;\n this.pgSchemaName = pgSchemaName;\n this.subgraphSchema = subgraphSchema;\n this.block = block;\n this._tx = tx;\n }\n\n get tx(): TxMeta {\n return this._tx;\n }\n\n /** Update the current transaction context (used by runner between events) */\n setTx(tx: TxMeta): void {\n this._tx = tx;\n }\n\n // --- Write operations (batched) ---\n\n insert(table: string, row: Record<string, unknown>): void {\n this.validateTable(table);\n this.ops.push({ kind: \"insert\", table, data: row });\n }\n\n update(\n table: string,\n where: Record<string, unknown>,\n set: Record<string, unknown>,\n ): void {\n this.validateTable(table);\n this.ops.push({ kind: \"update\", table, data: where, set });\n }\n\n upsert(\n table: string,\n key: Record<string, unknown>,\n row: Record<string, unknown>,\n ): void {\n this.validateTable(table);\n const tableDef = this.subgraphSchema[table]!;\n const keyColumns = Object.keys(key);\n\n // Check if there's a matching uniqueKeys constraint\n const hasUniqueConstraint = tableDef.uniqueKeys?.some(\n (uk) => uk.length === keyColumns.length && uk.every((c) => keyColumns.includes(c)),\n );\n\n if (hasUniqueConstraint) {\n // Use ON CONFLICT for proper upsert\n this.ops.push({ kind: \"insert\", table, data: { ...key, ...row, _upsert_keys: keyColumns } });\n } else {\n // Fallback: log warning, use findOne + conditional insert/update\n logger.warn(\"upsert called without matching uniqueKeys constraint, using fallback\", {\n table,\n keys: keyColumns,\n });\n this.ops.push({ kind: \"insert\", table, data: { ...key, ...row, _upsert_fallback_keys: keyColumns, _upsert_fallback_set: row } });\n }\n }\n\n delete(table: string, where: Record<string, unknown>): void {\n this.validateTable(table);\n this.ops.push({ kind: \"delete\", table, data: where });\n }\n\n // --- Read operations (immediate) ---\n\n async findOne(\n table: string,\n where: Record<string, unknown>,\n ): Promise<Record<string, unknown> | null> {\n this.validateTable(table);\n const qualifiedTable = `\"${this.pgSchemaName}\".\"${table}\"`;\n const { clause } = buildWhereClause(where);\n const query = `SELECT * FROM ${qualifiedTable} WHERE ${clause} LIMIT 1`;\n const { rows } = await sql.raw(query).execute(this.db);\n const row = (rows as Record<string, unknown>[])[0] ?? null;\n return row ? this.coerceRow(table, row) : null;\n }\n\n async findMany(\n table: string,\n where: Record<string, unknown>,\n ): Promise<Record<string, unknown>[]> {\n this.validateTable(table);\n const qualifiedTable = `\"${this.pgSchemaName}\".\"${table}\"`;\n const { clause } = buildWhereClause(where);\n const query = `SELECT * FROM ${qualifiedTable} WHERE ${clause}`;\n const { rows } = await sql.raw(query).execute(this.db);\n return (rows as Record<string, unknown>[]).map((r) => this.coerceRow(table, r));\n }\n\n /** Coerce string values from Postgres back to BigInt for uint/int columns */\n private coerceRow(table: string, row: Record<string, unknown>): Record<string, unknown> {\n const tableDef = this.subgraphSchema[table];\n if (!tableDef) return row;\n const result = { ...row };\n for (const [col, def] of Object.entries(tableDef.columns)) {\n if ((def.type === \"uint\" || def.type === \"int\") && typeof result[col] === \"string\") {\n result[col] = BigInt(result[col] as string);\n }\n }\n return result;\n }\n\n // --- Flush ---\n\n /** Number of pending write operations */\n get pendingOps(): number {\n return this.ops.length;\n }\n\n /**\n * Execute all batched writes in a single transaction.\n * Auto-populates _block_height, _tx_id, _created_at on inserts.\n */\n async flush(): Promise<number> {\n if (this.ops.length === 0) return 0;\n\n const opsToFlush = [...this.ops];\n this.ops.length = 0;\n\n const statements = this.buildStatements(opsToFlush);\n\n // If db is already a transaction, execute directly\n if (\"isTransaction\" in this.db) {\n for (const stmt of statements) {\n await sql.raw(stmt).execute(this.db);\n }\n } else {\n await (this.db as Kysely<Database>).transaction().execute(async (tx) => {\n for (const stmt of statements) {\n await sql.raw(stmt).execute(tx);\n }\n });\n }\n\n return opsToFlush.length;\n }\n\n /** Build SQL statements from write ops */\n private buildStatements(ops: WriteOp[]): string[] {\n const statements: string[] = [];\n\n for (const op of ops) {\n const qualifiedTable = `\"${this.pgSchemaName}\".\"${op.table}\"`;\n\n switch (op.kind) {\n case \"insert\": {\n const upsertKeys = op.data._upsert_keys as string[] | undefined;\n const fallbackKeys = op.data._upsert_fallback_keys as string[] | undefined;\n const fallbackSet = op.data._upsert_fallback_set as Record<string, unknown> | undefined;\n const data = { ...op.data };\n delete data._upsert_keys;\n delete data._upsert_fallback_keys;\n delete data._upsert_fallback_set;\n\n // Auto-populate meta columns\n data._block_height = this.block.height;\n data._tx_id = this._tx.txId;\n data._created_at = \"NOW()\";\n\n const cols = Object.keys(data);\n cols.forEach(validateColumnName);\n const vals = cols.map((c) =>\n data[c] === \"NOW()\" ? \"NOW()\" : escapeLiteral(data[c]),\n );\n let stmt = `INSERT INTO ${qualifiedTable} (${cols.map((c) => `\"${c}\"`).join(\", \")}) VALUES (${vals.join(\", \")})`;\n\n if (upsertKeys && upsertKeys.length > 0) {\n const updateCols = cols.filter((c) => !upsertKeys.includes(c) && !c.startsWith(\"_\"));\n if (updateCols.length > 0) {\n const setClauses = updateCols.map((c) => `\"${c}\" = EXCLUDED.\"${c}\"`);\n stmt += ` ON CONFLICT (${upsertKeys.map((k) => `\"${k}\"`).join(\", \")}) DO UPDATE SET ${setClauses.join(\", \")}`;\n } else {\n stmt += ` ON CONFLICT (${upsertKeys.map((k) => `\"${k}\"`).join(\", \")}) DO NOTHING`;\n }\n } else if (fallbackKeys && fallbackSet) {\n // Fallback upsert: use ON CONFLICT DO UPDATE but without a declared constraint\n // This will just be a plain INSERT — if it conflicts, PG will raise an error.\n // The caller was already warned. This is the best we can do without a unique constraint.\n }\n\n statements.push(stmt);\n break;\n }\n case \"update\": {\n const setEntries = Object.entries(op.set!);\n setEntries.forEach(([k]) => validateColumnName(k));\n const setClauses = setEntries.map(\n ([k, v]) => `\"${k}\" = ${escapeLiteral(v)}`,\n );\n const { clause } = buildWhereClause(op.data);\n statements.push(\n `UPDATE ${qualifiedTable} SET ${setClauses.join(\", \")} WHERE ${clause}`,\n );\n break;\n }\n case \"delete\": {\n const { clause } = buildWhereClause(op.data);\n statements.push(`DELETE FROM ${qualifiedTable} WHERE ${clause}`);\n break;\n }\n }\n }\n\n return statements;\n }\n\n private validateTable(table: string): void {\n if (!this.subgraphSchema[table]) {\n throw new Error(\n `Table \"${table}\" not found in subgraph schema. Available: [${Object.keys(this.subgraphSchema).join(\", \")}]`,\n );\n }\n }\n}\n\n// --- Helpers ---\n\nfunction escapeLiteral(value: unknown): string {\n if (value === null || value === undefined) return \"NULL\";\n if (typeof value === \"number\" || typeof value === \"bigint\") return String(value);\n if (typeof value === \"boolean\") return value ? \"TRUE\" : \"FALSE\";\n if (typeof value === \"object\") return `'${JSON.stringify(value).replace(/'/g, \"''\")}'::jsonb`;\n // String — escape single quotes\n return `'${String(value).replace(/'/g, \"''\")}'`;\n}\n\nfunction buildWhereClause(where: Record<string, unknown>): {\n clause: string;\n values: unknown[];\n} {\n const entries = Object.entries(where);\n if (entries.length === 0) return { clause: \"TRUE\", values: [] };\n\n entries.forEach(([k]) => validateColumnName(k));\n const parts = entries.map(([k, v]) => `\"${k}\" = ${escapeLiteral(v)}`);\n return { clause: parts.join(\" AND \"), values: [] };\n}\n",
8
- "import { type SubgraphSource, sourceKey } from \"../types.ts\";\n\nexport interface MatchedTx {\n tx: { tx_id: string; type: string; sender: string; status: string; contract_id?: string | null; function_name?: string | null };\n events: { id: string; tx_id: string; type: string; event_index: number; data: unknown }[];\n /** Which source produced this match — used for handler dispatch */\n sourceKey: string;\n}\n\n/**\n * Check if a string matches a pattern with `*` wildcard support.\n */\nfunction matchPattern(value: string, pattern: string): boolean {\n if (!pattern.includes(\"*\")) return value === pattern;\n const regex = pattern\n .replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\")\n .replace(/\\*/g, \".*\");\n return new RegExp(`^${regex}$`).test(value);\n}\n\ntype TxRecord = { tx_id: string; type: string; sender: string; status: string; contract_id?: string | null; function_name?: string | null };\ntype EventRecord = { id: string; tx_id: string; type: string; event_index: number; data: unknown };\n\n/**\n * Match a single source against transactions and events.\n */\nfunction matchSource(\n source: SubgraphSource,\n transactions: TxRecord[],\n eventsByTx: Map<string, EventRecord[]>,\n): MatchedTx[] {\n const results: MatchedTx[] = [];\n const key = sourceKey(source);\n\n for (const tx of transactions) {\n // Type-based matching (e.g., token_transfer → matches tx.type)\n if (source.type) {\n if (!matchPattern(tx.type, source.type)) continue;\n\n const txEvents = eventsByTx.get(tx.tx_id) ?? [];\n\n // Collect all events for this tx (type-based sources match the whole tx)\n let matchedEvents = txEvents;\n\n // minAmount filter check events with an amount field\n if (source.minAmount !== undefined) {\n const amountEvents = matchedEvents.filter((e) => {\n const data = e.data as Record<string, unknown> | null;\n const rawAmount = data?.amount as string | number | undefined;\n if (rawAmount === undefined) return false;\n const amount = BigInt(rawAmount);\n return amount >= source.minAmount!;\n });\n if (amountEvents.length === 0) continue;\n matchedEvents = amountEvents;\n }\n\n results.push({ tx, events: matchedEvents, sourceKey: key });\n continue;\n }\n\n // Contract-based matching\n if (source.contract) {\n const txContractMatch = tx.contract_id && matchPattern(tx.contract_id, source.contract);\n\n // Function filter\n if (source.function && tx.function_name) {\n if (!matchPattern(tx.function_name, source.function)) continue;\n } else if (source.function && !tx.function_name) {\n continue;\n }\n\n const txEvents = eventsByTx.get(tx.tx_id) ?? [];\n let matchedEvents = txEvents;\n\n if (!txContractMatch) {\n // Check if any events match the contract\n matchedEvents = txEvents.filter((e) => {\n const data = e.data as Record<string, unknown> | null;\n const contractIdentifier = data?.contract_identifier as string | undefined;\n return contractIdentifier && matchPattern(contractIdentifier, source.contract!);\n });\n if (matchedEvents.length === 0) continue;\n }\n\n // Event type / topic filter\n if (source.event) {\n matchedEvents = matchedEvents.filter((e) => {\n if (matchPattern(e.type, source.event!)) return true;\n const data = e.data as Record<string, unknown> | null;\n const topic = data?.topic as string | undefined;\n return topic ? matchPattern(topic, source.event!) : false;\n });\n }\n\n if (txContractMatch || matchedEvents.length > 0) {\n results.push({ tx, events: matchedEvents, sourceKey: key });\n }\n }\n }\n\n return results;\n}\n\n/**\n * Match all sources against a block's transactions and events.\n * Deduplicates by (txId, sourceKey) — each handler key fires at most once per tx.\n */\nexport function matchSources(\n sources: SubgraphSource[],\n transactions: TxRecord[],\n events: EventRecord[],\n): MatchedTx[] {\n // Index events by txId\n const eventsByTx = new Map<string, EventRecord[]>();\n for (const event of events) {\n const list = eventsByTx.get(event.tx_id) ?? [];\n list.push(event);\n eventsByTx.set(event.tx_id, list);\n }\n\n const seen = new Set<string>();\n const results: MatchedTx[] = [];\n\n for (const source of sources) {\n const matches = matchSource(source, transactions, eventsByTx);\n for (const match of matches) {\n const dedupeKey = `${match.tx.tx_id}:${match.sourceKey}`;\n if (!seen.has(dedupeKey)) {\n seen.add(dedupeKey);\n results.push(match);\n }\n }\n }\n\n return results;\n}\n",
9
- "import { cvToJSON, 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 try {\n const cleanHex = hex.startsWith(\"0x\") ? hex.slice(2) : hex;\n const cv = deserializeCV(cleanHex);\n return cvToJSON(cv);\n } catch {\n return hex;\n }\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 if (typeof data === \"string\" && data.startsWith(\"0x\") && data.length > 10) {\n return decodeClarityValue(data);\n }\n\n if (Array.isArray(data)) {\n return data.map(decodeEventData);\n }\n\n if (typeof data === \"object\" && data !== null) {\n const decoded: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(data)) {\n decoded[key] = decodeEventData(value);\n }\n return decoded;\n }\n\n return data;\n}\n\n/**\n * Decode function args array (hex-encoded Clarity values).\n */\nexport function decodeFunctionArgs(args: string[]): unknown[] {\n return args.map(decodeClarityValue);\n}\n",
10
- "import { logger } from \"@secondlayer/shared/logger\";\nimport { getErrorMessage } from \"@secondlayer/shared\";\nimport type { SubgraphDefinition } from \"../types.ts\";\nimport type { SubgraphContext } from \"./context.ts\";\nimport type { MatchedTx } from \"./source-matcher.ts\";\nimport { decodeEventData } from \"./clarity.ts\";\n\n/** Max consecutive handler errors before marking subgraph as error */\nconst DEFAULT_ERROR_THRESHOLD = 50;\n\nexport interface RunResult {\n processed: number;\n errors: number;\n}\n\n/**\n * Resolve the handler for a matched tx.\n * Looks up by sourceKey first, then falls back to \"*\" catch-all.\n */\nfunction resolveHandler(handlers: SubgraphDefinition[\"handlers\"], key: string) {\n return handlers[key] ?? handlers[\"*\"] ?? null;\n}\n\n/**\n * Run a subgraph's keyed handlers against all matched transactions/events.\n *\n * Each MatchedTx carries a sourceKey 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 subgraph: SubgraphDefinition,\n matched: MatchedTx[],\n ctx: SubgraphContext,\n opts?: { errorThreshold?: number },\n): Promise<RunResult> {\n let processed = 0;\n let errors = 0;\n const threshold = opts?.errorThreshold ?? DEFAULT_ERROR_THRESHOLD;\n\n for (const { tx, events, sourceKey } of matched) {\n const handler = resolveHandler(subgraph.handlers, sourceKey);\n if (!handler) {\n logger.warn(\"No handler found for source key\", { subgraph: subgraph.name, sourceKey, txId: tx.tx_id });\n continue;\n }\n\n ctx.setTx({\n txId: tx.tx_id,\n sender: tx.sender,\n type: tx.type,\n status: tx.status,\n });\n\n // If no events but tx matched, call handler with tx-level data\n if (events.length === 0) {\n try {\n const txPayload: Record<string, unknown> = {\n tx: {\n txId: tx.tx_id,\n sender: tx.sender,\n type: tx.type,\n status: tx.status,\n contractId: tx.contract_id,\n functionName: tx.function_name,\n },\n };\n await handler(txPayload, ctx);\n processed++;\n } catch (err) {\n errors++;\n logger.error(\"Subgraph handler error\", {\n subgraph: subgraph.name,\n sourceKey,\n txId: tx.tx_id,\n error: getErrorMessage(err),\n });\n }\n continue;\n }\n\n for (const event of events) {\n if (errors >= threshold) {\n logger.error(\"Subgraph error threshold reached, skipping remaining events\", {\n subgraph: subgraph.name,\n errors,\n threshold,\n });\n return { processed, errors };\n }\n\n try {\n const decoded = decodeEventData(event.data) as Record<string, unknown>;\n const eventPayload: Record<string, unknown> = {\n ...decoded,\n _eventId: event.id,\n _eventType: event.type,\n _eventIndex: event.event_index,\n tx: {\n txId: tx.tx_id,\n sender: tx.sender,\n type: tx.type,\n status: tx.status,\n contractId: tx.contract_id,\n functionName: tx.function_name,\n },\n };\n\n await handler(eventPayload, ctx);\n processed++;\n } catch (err) {\n errors++;\n logger.error(\"Subgraph handler error\", {\n subgraph: subgraph.name,\n sourceKey,\n txId: tx.tx_id,\n eventId: event.id,\n eventType: event.type,\n error: getErrorMessage(err),\n });\n }\n }\n }\n\n return { processed, errors };\n}\n",
11
- "import { sql, type Transaction } from \"kysely\";\nimport { getDb, type Database } from \"@secondlayer/shared/db\";\nimport { logger } from \"@secondlayer/shared/logger\";\nimport { updateSubgraphStatus, recordSubgraphProcessed } from \"@secondlayer/shared/db/queries/subgraphs\";\nimport type { SubgraphDefinition } from \"../types.ts\";\nimport { pgSchemaName } from \"../schema/utils.ts\";\nimport { SubgraphContext, type BlockMeta, type TxMeta } from \"./context.ts\";\nimport { matchSources } from \"./source-matcher.ts\";\nimport { runHandlers } from \"./runner.ts\";\n\nexport interface ProcessBlockTiming {\n totalMs: number;\n handlerMs: number;\n flushMs: number;\n}\n\nexport interface ProcessBlockResult {\n blockHeight: number;\n matched: number;\n processed: number;\n errors: number;\n skipped: boolean;\n timing?: 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 ProcessBlockOptions {\n /** Skip updating last_processed_block in DB (reindex batches this externally). */\n skipProgressUpdate?: boolean;\n}\n\nexport async function processBlock(\n subgraph: SubgraphDefinition,\n subgraphName: string,\n blockHeight: number,\n opts?: ProcessBlockOptions,\n): Promise<ProcessBlockResult> {\n const db = getDb();\n const blockStart = performance.now();\n const result: ProcessBlockResult = {\n blockHeight,\n matched: 0,\n processed: 0,\n errors: 0,\n skipped: false,\n };\n\n // 1. Load block\n const block = await db\n .selectFrom(\"blocks\")\n .selectAll()\n .where(\"height\", \"=\", blockHeight)\n .executeTakeFirst();\n\n if (!block) {\n logger.warn(\"Block not found for subgraph processing\", { subgraph: subgraphName, blockHeight });\n result.skipped = true;\n return result;\n }\n\n if (!block.canonical) {\n logger.debug(\"Skipping non-canonical block\", { subgraph: subgraphName, blockHeight });\n result.skipped = true;\n return result;\n }\n\n // 2. Load txs + events\n const txs = await db\n .selectFrom(\"transactions\")\n .selectAll()\n .where(\"block_height\", \"=\", blockHeight)\n .execute();\n\n const evts = await db\n .selectFrom(\"events\")\n .selectAll()\n .where(\"block_height\", \"=\", blockHeight)\n .execute();\n\n // 3. Match source\n const matched = matchSources(subgraph.sources, txs, evts);\n result.matched = matched.length;\n\n if (matched.length === 0) {\n if (!opts?.skipProgressUpdate) {\n await updateSubgraphStatus(db, subgraphName, \"active\", blockHeight);\n }\n return result;\n }\n\n // 4. Create context and run handlers\n // Use stored schema_name from DB if available, otherwise compute\n const subgraphRecord = await db\n .selectFrom(\"subgraphs\")\n .select(\"schema_name\")\n .where(\"name\", \"=\", subgraphName)\n .executeTakeFirst();\n const schemaName = subgraphRecord?.schema_name ?? pgSchemaName(subgraphName);\n const blockMeta: BlockMeta = {\n height: block.height,\n hash: block.hash,\n timestamp: block.timestamp,\n burnBlockHeight: block.burn_block_height,\n };\n const initialTx: TxMeta = {\n txId: \"\",\n sender: \"\",\n type: \"\",\n status: \"\",\n };\n\n // Wrap entire block processing in a single transaction\n let handlerMs = 0;\n let flushMs = 0;\n\n await db.transaction().execute(async (tx: Transaction<Database>) => {\n const ctx = new SubgraphContext(tx, schemaName, subgraph.schema, blockMeta, initialTx);\n\n const handlerStart = performance.now();\n const runResult = await runHandlers(subgraph, matched, ctx);\n handlerMs = performance.now() - handlerStart;\n\n result.processed = runResult.processed;\n result.errors = runResult.errors;\n\n // 5. Flush writes\n if (ctx.pendingOps > 0) {\n const flushStart = performance.now();\n await ctx.flush();\n flushMs = performance.now() - flushStart;\n }\n\n // 6. Update progress + health metrics (same transaction)\n if (!opts?.skipProgressUpdate) {\n const status = runResult.errors > 0 && runResult.processed === 0 ? \"error\" : \"active\";\n await updateSubgraphStatus(tx, subgraphName, status, blockHeight);\n }\n\n if (!opts?.skipProgressUpdate && (runResult.processed > 0 || runResult.errors > 0)) {\n const lastError = runResult.errors > 0\n ? `${runResult.errors} error(s) at block ${blockHeight}`\n : undefined;\n await recordSubgraphProcessed(tx, subgraphName, runResult.processed, runResult.errors, lastError);\n }\n });\n\n const totalMs = performance.now() - blockStart;\n result.timing = {\n totalMs: Math.round(totalMs),\n handlerMs: Math.round(handlerMs),\n flushMs: Math.round(flushMs),\n };\n\n // 7. Row count warning — sample every 1000 blocks\n if (blockHeight % 1000 === 0) {\n try {\n const tables = Object.keys(subgraph.schema);\n for (const table of tables) {\n const { rows } = await sql.raw(\n `SELECT COUNT(*) as count FROM \"${schemaName}\".\"${table}\"`,\n ).execute(db);\n const count = Number((rows[0] as Record<string, unknown>).count);\n if (count >= 10_000_000) {\n logger.warn(\"Subgraph table exceeds 10M rows\", { subgraph: subgraphName, table, count });\n }\n }\n } catch {\n // Table may not exist yet\n }\n }\n\n return result;\n}\n",
5
+ "/** Supported column types for subgraph schemas */\nexport type ColumnType =\n\t| \"text\"\n\t| \"uint\"\n\t| \"int\"\n\t| \"principal\"\n\t| \"boolean\"\n\t| \"timestamp\"\n\t| \"jsonb\";\n\n/** Column definition in a subgraph table */\nexport interface SubgraphColumn {\n\ttype: ColumnType;\n\tnullable?: boolean;\n\tindexed?: boolean;\n\tsearch?: boolean;\n\tdefault?: string | number | boolean;\n}\n\n/** Table definition within a subgraph schema */\nexport interface SubgraphTable {\n\tcolumns: Record<string, SubgraphColumn>;\n\t/** Composite indexes (each entry is an array of column names) */\n\tindexes?: string[][];\n\t/** Unique key constraints (each entry is an array of column names). Required for upsert. */\n\tuniqueKeys?: string[][];\n}\n\n/** Subgraph schema — maps table names to table definitions */\nexport type SubgraphSchema = Record<string, SubgraphTable>;\n\n/** Source filter for what blockchain data this subgraph processes */\nexport interface SubgraphSource {\n\t/** Contract principal (e.g., SP000...::contract-name). Supports * wildcards. */\n\tcontract?: string;\n\t/** Event name/topic to filter on */\n\tevent?: string;\n\t/** Function name to filter on */\n\tfunction?: string;\n\t/** Transaction type filter (e.g., \"stx_transfer\", \"contract_call\") */\n\ttype?: string;\n\t/** Minimum amount filter (for stx_transfer sources) */\n\tminAmount?: bigint;\n}\n\n/** Context passed to subgraph handlers during event processing */\nexport interface SubgraphContext {\n\tblock: {\n\t\theight: number;\n\t\thash: string;\n\t\ttimestamp: number;\n\t\tburnBlockHeight: number;\n\t};\n\ttx: { txId: string; sender: string; type: string; status: string };\n\tinsert(table: string, row: Record<string, unknown>): void;\n\tupdate(\n\t\ttable: string,\n\t\twhere: Record<string, unknown>,\n\t\tset: Record<string, unknown>,\n\t): void;\n\tupsert(\n\t\ttable: string,\n\t\tkey: Record<string, unknown>,\n\t\trow: Record<string, unknown>,\n\t): void;\n\tdelete(table: string, where: Record<string, unknown>): void;\n\tfindOne(\n\t\ttable: string,\n\t\twhere: Record<string, unknown>,\n\t): Promise<Record<string, unknown> | null>;\n\tfindMany(\n\t\ttable: string,\n\t\twhere: Record<string, unknown>,\n\t): Promise<Record<string, unknown>[]>;\n}\n\n/** Handler function that processes events and writes to the subgraph */\nexport type SubgraphHandler = (\n\tevent: Record<string, unknown>,\n\tctx: SubgraphContext,\n) => Promise<void> | void;\n\n/**\n * Derive the source key used to look up handlers.\n * - { contract: \"SP123.market\", function: \"list\" } → \"SP123.market::list\"\n * - { contract: \"SP123.market\", event: \"sale\" } → \"SP123.market::sale\"\n * - { contract: \"SP123.market\" } → \"SP123.market\"\n * - { type: \"stx_transfer\" } → \"stx_transfer\"\n */\nexport function sourceKey(source: SubgraphSource): string {\n\tif (source.contract) {\n\t\tif (source.function) return `${source.contract}::${source.function}`;\n\t\tif (source.event) return `${source.contract}::${source.event}`;\n\t\treturn source.contract;\n\t}\n\tif (source.type) return source.type;\n\treturn \"*\";\n}\n\n/** Complete subgraph definition */\nexport interface SubgraphDefinition {\n\t/** Unique subgraph name (lowercase, alphanumeric + hyphens) */\n\tname: string;\n\t/** Semantic version */\n\tversion?: string;\n\t/** Human description */\n\tdescription?: string;\n\t/** What blockchain data to process — one or more source filters */\n\tsources: SubgraphSource[];\n\t/** Tables in this subgraph */\n\tschema: SubgraphSchema;\n\t/** Keyed handler functions — keys match sourceKey() output, \"*\" is catch-all */\n\thandlers: Record<string, SubgraphHandler>;\n}\n",
6
+ "import { z } from \"zod/v4\";\nimport type {\n\tColumnType,\n\tSubgraphColumn,\n\tSubgraphDefinition,\n\tSubgraphSource,\n\tSubgraphTable,\n} from \"./types.ts\";\n\nexport const SubgraphNameSchema: z.ZodType<string> = z\n\t.string()\n\t.min(1)\n\t.max(63)\n\t.regex(\n\t\t/^[a-z][a-z0-9-]*$/,\n\t\t\"Must start with lowercase letter, contain only lowercase alphanumeric and hyphens\",\n\t);\n\nexport const ColumnTypeSchema: z.ZodType<ColumnType> = z.enum([\n\t\"text\",\n\t\"uint\",\n\t\"int\",\n\t\"principal\",\n\t\"boolean\",\n\t\"timestamp\",\n\t\"jsonb\",\n]);\n\nexport const SubgraphColumnSchema: z.ZodType<SubgraphColumn> = z.object({\n\ttype: ColumnTypeSchema,\n\tnullable: z.boolean().optional(),\n\tindexed: z.boolean().optional(),\n\tsearch: z.boolean().optional(),\n\tdefault: z.union([z.string(), z.number(), z.boolean()]).optional(),\n}) as z.ZodType<SubgraphColumn>;\n\nexport const SubgraphTableSchema: z.ZodType<SubgraphTable> = z.object({\n\tcolumns: z\n\t\t.record(z.string(), SubgraphColumnSchema)\n\t\t.refine(\n\t\t\t(c) => Object.keys(c).length > 0,\n\t\t\t\"Table must have at least one column\",\n\t\t),\n\tindexes: z.array(z.array(z.string())).optional(),\n\tuniqueKeys: z.array(z.array(z.string())).optional(),\n}) as z.ZodType<SubgraphTable>;\n\nexport const SubgraphSchemaSchema: z.ZodType<Record<string, SubgraphTable>> = z\n\t.record(z.string(), SubgraphTableSchema)\n\t.refine(\n\t\t(s) => Object.keys(s).length > 0,\n\t\t\"Schema must have at least one table\",\n\t) as z.ZodType<Record<string, SubgraphTable>>;\n\nexport const SubgraphSourceSchema: z.ZodType<SubgraphSource> = z\n\t.object({\n\t\tcontract: z.string().optional(),\n\t\tevent: z.string().optional(),\n\t\tfunction: z.string().optional(),\n\t\ttype: z.string().optional(),\n\t\tminAmount: z.bigint().optional(),\n\t})\n\t.refine(\n\t\t(s) => s.contract || s.type,\n\t\t\"Source must specify at least 'contract' or 'type'\",\n\t) as z.ZodType<SubgraphSource>;\n\nexport const SubgraphDefinitionSchema: z.ZodType<SubgraphDefinition> = z.object(\n\t{\n\t\tname: SubgraphNameSchema,\n\t\tversion: z.string().optional(),\n\t\tdescription: z.string().optional(),\n\t\tsources: z\n\t\t\t.array(SubgraphSourceSchema)\n\t\t\t.min(1, \"Must have at least one source\"),\n\t\tschema: SubgraphSchemaSchema,\n\t\thandlers: z.record(z.string(), z.any()),\n\t},\n) as unknown as z.ZodType<SubgraphDefinition>;\n\n/**\n * Validates a subgraph definition, returning the parsed result or throwing on failure.\n */\nexport function validateSubgraphDefinition(def: unknown): SubgraphDefinition {\n\treturn SubgraphDefinitionSchema.parse(def);\n}\n",
7
+ "import type { Database } from \"@secondlayer/shared/db\";\nimport { logger } from \"@secondlayer/shared/logger\";\nimport { type Kysely, type Transaction, sql } from \"kysely\";\nimport type { 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 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}\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({ kind: \"insert\", table, data: row });\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\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\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, _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_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// --- 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/** 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\tasync flush(): Promise<number> {\n\t\tif (this.ops.length === 0) return 0;\n\n\t\tconst opsToFlush = [...this.ops];\n\t\tthis.ops.length = 0;\n\n\t\tconst statements = this.buildStatements(opsToFlush);\n\n\t\t// If db is already a transaction, execute directly\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\treturn opsToFlush.length;\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\tdelete data._upsert_keys;\n\t\tdelete data._upsert_fallback_keys;\n\t\tdelete data._upsert_fallback_set;\n\n\t\tdata._block_height = this.block.height;\n\t\tdata._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 qualifiedTable = `\"${this.pgSchemaName}\".\"${currentBatch.table}\"`;\n\t\t\tconst colList = currentBatch.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 = currentBatch.rows;\n\t\t\tif (currentBatch.upsertKeys && currentBatch.upsertKeys.length > 0) {\n\t\t\t\tconst keyIndices = currentBatch.upsertKeys.map((k) =>\n\t\t\t\t\tcurrentBatch!.cols.indexOf(k),\n\t\t\t\t);\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 (currentBatch.upsertKeys && currentBatch.upsertKeys.length > 0) {\n\t\t\t\tconst updateCols = currentBatch.cols.filter(\n\t\t\t\t\t(c) => !currentBatch!.upsertKeys!.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 (${currentBatch.upsertKeys.map((k) => `\"${k}\"`).join(\", \")}) DO UPDATE SET ${setClauses.join(\", \")}`;\n\t\t\t\t} else {\n\t\t\t\t\tstmt += ` ON CONFLICT (${currentBatch.upsertKeys.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\tsetEntries.forEach(([k]) => 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\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).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\tentries.forEach(([k]) => validateColumnName(k));\n\tconst parts = entries.map(([k, v]) => `\"${k}\" = ${escapeLiteral(v)}`);\n\treturn { clause: parts.join(\" AND \"), values: [] };\n}\n",
8
+ "import { cvToJSON, 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 cvToJSON(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",
9
+ "import { getErrorMessage } from \"@secondlayer/shared\";\nimport { logger } from \"@secondlayer/shared/logger\";\nimport type { SubgraphDefinition } from \"../types.ts\";\nimport { 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/**\n * Resolve the handler for a matched tx.\n * Looks up by sourceKey first, then falls back to \"*\" catch-all.\n */\nfunction resolveHandler(handlers: SubgraphDefinition[\"handlers\"], key: string) {\n\treturn handlers[key] ?? handlers[\"*\"] ?? null;\n}\n\n/**\n * Run a subgraph's keyed handlers against all matched transactions/events.\n *\n * Each MatchedTx carries a sourceKey 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\tfor (const { tx, events, sourceKey } of matched) {\n\t\tconst handler = resolveHandler(subgraph.handlers, sourceKey);\n\t\tif (!handler) {\n\t\t\tlogger.warn(\"No handler found for source key\", {\n\t\t\t\tsubgraph: subgraph.name,\n\t\t\t\tsourceKey,\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});\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 txPayload: Record<string, unknown> = {\n\t\t\t\t\ttx: {\n\t\t\t\t\t\ttxId: tx.tx_id,\n\t\t\t\t\t\tsender: tx.sender,\n\t\t\t\t\t\ttype: tx.type,\n\t\t\t\t\t\tstatus: tx.status,\n\t\t\t\t\t\tcontractId: tx.contract_id,\n\t\t\t\t\t\tfunctionName: tx.function_name,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t\tawait handler(txPayload, 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\tsourceKey,\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 decoded = decodeEventData(event.data) as Record<string, unknown>;\n\t\t\t\tconst eventPayload: Record<string, unknown> = {\n\t\t\t\t\t...decoded,\n\t\t\t\t\t_eventId: event.id,\n\t\t\t\t\t_eventType: event.type,\n\t\t\t\t\t_eventIndex: event.event_index,\n\t\t\t\t\ttx: {\n\t\t\t\t\t\ttxId: tx.tx_id,\n\t\t\t\t\t\tsender: tx.sender,\n\t\t\t\t\t\ttype: tx.type,\n\t\t\t\t\t\tstatus: tx.status,\n\t\t\t\t\t\tcontractId: tx.contract_id,\n\t\t\t\t\t\tfunctionName: tx.function_name,\n\t\t\t\t\t},\n\t\t\t\t};\n\n\t\t\t\tawait handler(eventPayload, 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\tsourceKey,\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",
10
+ "import { type SubgraphSource, sourceKey } from \"../types.ts\";\n\nexport interface MatchedTx {\n\ttx: {\n\t\ttx_id: string;\n\t\ttype: string;\n\t\tsender: string;\n\t\tstatus: string;\n\t\tcontract_id?: string | null;\n\t\tfunction_name?: string | null;\n\t};\n\tevents: {\n\t\tid: string;\n\t\ttx_id: string;\n\t\ttype: string;\n\t\tevent_index: number;\n\t\tdata: unknown;\n\t}[];\n\t/** Which source produced this match used for handler dispatch */\n\tsourceKey: string;\n}\n\n/**\n * Check if a string matches a pattern with `*` wildcard support.\n */\nfunction matchPattern(value: string, pattern: string): boolean {\n\tif (!pattern.includes(\"*\")) return value === pattern;\n\tconst regex = pattern\n\t\t.replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\")\n\t\t.replace(/\\*/g, \".*\");\n\treturn new RegExp(`^${regex}$`).test(value);\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};\ntype EventRecord = {\n\tid: string;\n\ttx_id: string;\n\ttype: string;\n\tevent_index: number;\n\tdata: unknown;\n};\n\n/**\n * Match a single source against transactions and events.\n */\nfunction matchSource(\n\tsource: SubgraphSource,\n\ttransactions: TxRecord[],\n\teventsByTx: Map<string, EventRecord[]>,\n): MatchedTx[] {\n\tconst results: MatchedTx[] = [];\n\tconst key = sourceKey(source);\n\n\tfor (const tx of transactions) {\n\t\t// Type-based matching (e.g., token_transfer → matches tx.type)\n\t\tif (source.type) {\n\t\t\tif (!matchPattern(tx.type, source.type)) continue;\n\n\t\t\tconst txEvents = eventsByTx.get(tx.tx_id) ?? [];\n\n\t\t\t// Collect all events for this tx (type-based sources match the whole tx)\n\t\t\tlet matchedEvents = txEvents;\n\n\t\t\t// minAmount filter check events with an amount field\n\t\t\tif (source.minAmount !== undefined) {\n\t\t\t\tconst amountEvents = matchedEvents.filter((e) => {\n\t\t\t\t\tconst data = e.data as Record<string, unknown> | null;\n\t\t\t\t\tconst rawAmount = data?.amount as string | number | undefined;\n\t\t\t\t\tif (rawAmount === undefined) return false;\n\t\t\t\t\tconst amount = BigInt(rawAmount);\n\t\t\t\t\treturn amount >= source.minAmount!;\n\t\t\t\t});\n\t\t\t\tif (amountEvents.length === 0) continue;\n\t\t\t\tmatchedEvents = amountEvents;\n\t\t\t}\n\n\t\t\tresults.push({ tx, events: matchedEvents, sourceKey: key });\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Contract-based matching\n\t\tif (source.contract) {\n\t\t\tconst txContractMatch =\n\t\t\t\ttx.contract_id && matchPattern(tx.contract_id, source.contract);\n\n\t\t\t// Function filter\n\t\t\tif (source.function && tx.function_name) {\n\t\t\t\tif (!matchPattern(tx.function_name, source.function)) continue;\n\t\t\t} else if (source.function && !tx.function_name) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst txEvents = eventsByTx.get(tx.tx_id) ?? [];\n\t\t\tlet matchedEvents = txEvents;\n\n\t\t\tif (!txContractMatch) {\n\t\t\t\t// Check if any events match the contract\n\t\t\t\tmatchedEvents = txEvents.filter((e) => {\n\t\t\t\t\tconst data = e.data as Record<string, unknown> | null;\n\t\t\t\t\tconst contractIdentifier = data?.contract_identifier as\n\t\t\t\t\t\t| string\n\t\t\t\t\t\t| undefined;\n\t\t\t\t\treturn (\n\t\t\t\t\t\tcontractIdentifier &&\n\t\t\t\t\t\tmatchPattern(contractIdentifier, source.contract!)\n\t\t\t\t\t);\n\t\t\t\t});\n\t\t\t\tif (matchedEvents.length === 0) continue;\n\t\t\t}\n\n\t\t\t// Event type / topic filter\n\t\t\tif (source.event) {\n\t\t\t\tmatchedEvents = matchedEvents.filter((e) => {\n\t\t\t\t\tif (matchPattern(e.type, source.event!)) return true;\n\t\t\t\t\tconst data = e.data as Record<string, unknown> | null;\n\t\t\t\t\tconst topic = data?.topic as string | undefined;\n\t\t\t\t\treturn topic ? matchPattern(topic, source.event!) : false;\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (txContractMatch || matchedEvents.length > 0) {\n\t\t\t\tresults.push({ tx, events: matchedEvents, sourceKey: key });\n\t\t\t}\n\t\t}\n\t}\n\n\treturn results;\n}\n\n/**\n * Match all sources against a block's transactions and events.\n * Deduplicates by (txId, sourceKey) — each handler key fires at most once per tx.\n */\nexport function matchSources(\n\tsources: SubgraphSource[],\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 source of sources) {\n\t\tconst matches = matchSource(source, transactions, eventsByTx);\n\t\tfor (const match of matches) {\n\t\t\tconst dedupeKey = `${match.tx.tx_id}:${match.sourceKey}`;\n\t\t\tif (!seen.has(dedupeKey)) {\n\t\t\t\tseen.add(dedupeKey);\n\t\t\t\tresults.push(match);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn results;\n}\n",
11
+ "import { type Database, getDb } 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 { runHandlers } from \"./runner.ts\";\nimport { matchSources } from \"./source-matcher.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 db = getDb();\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 (use pre-loaded data if available, otherwise fetch from DB)\n\tlet block, txs, evts;\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 db\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\n\t\ttxs = await db\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 db\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(db, subgraphName, \"active\", blockHeight);\n\t\t}\n\t\treturn result;\n\t}\n\n\t// 4. Create context and run handlers\n\t// Use cached schema_name (fetched once per subgraph, not per block)\n\tlet schemaName = schemaNameCache.get(subgraphName);\n\tif (!schemaName) {\n\t\tconst subgraphRecord = await db\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\n\tlet handlerMs = 0;\n\tlet flushMs = 0;\n\n\tawait db.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\n\t\tif (ctx.pendingOps > 0) {\n\t\t\tconst flushStart = performance.now();\n\t\t\tawait ctx.flush();\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\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(`SELECT COUNT(*) as count FROM \"${schemaName}\".\"${table}\"`)\n\t\t\t\t\t.execute(db);\n\t\t\t\tconst count = Number((rows[0] as Record<string, unknown>).count);\n\t\t\t\tif (count >= 10_000_000) {\n\t\t\t\t\tlogger.warn(\"Subgraph table exceeds 10M rows\", {\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 {\n\t\t\t// Table may not exist yet\n\t\t}\n\t}\n\n\treturn result;\n}\n",
12
12
  "// Re-export canonical pgSchemaName from shared\nexport { pgSchemaName } from \"@secondlayer/shared/db/queries/subgraphs\";\n",
13
- "import type { Kysely } from \"kysely\";\nimport type { Database } from \"@secondlayer/shared/db\";\nimport type { ProcessBlockTiming } from \"./block-processor.ts\";\n\ninterface StatsEntry {\n subgraphName: string;\n apiKeyId: string | null;\n bucketStart: Date;\n blocksProcessed: number;\n totalTimeMs: number;\n handlerTimeMs: number;\n flushTimeMs: number;\n maxBlockTimeMs: number;\n maxHandlerTimeMs: number;\n totalOps: number;\n isCatchup: boolean;\n}\n\nconst FLUSH_INTERVAL_BLOCKS = 100;\nconst FLUSH_INTERVAL_MS = 60_000;\n\n/**\n * Accumulates per-block timing stats and flushes to DB periodically.\n * One instance per subgraph during catchup/reindex/live processing.\n */\nexport class StatsAccumulator {\n private current: StatsEntry;\n private lastFlush = Date.now();\n\n constructor(\n private subgraphName: string,\n private apiKeyId: string | null,\n private isCatchup: boolean,\n ) {\n this.current = this.newEntry();\n }\n\n record(timing: ProcessBlockTiming, opsCount: number): void {\n this.current.blocksProcessed++;\n this.current.totalTimeMs += timing.totalMs;\n this.current.handlerTimeMs += timing.handlerMs;\n this.current.flushTimeMs += timing.flushMs;\n this.current.maxBlockTimeMs = Math.max(this.current.maxBlockTimeMs, timing.totalMs);\n this.current.maxHandlerTimeMs = Math.max(this.current.maxHandlerTimeMs, timing.handlerMs);\n this.current.totalOps += opsCount;\n }\n\n shouldFlush(): boolean {\n return (\n this.current.blocksProcessed >= FLUSH_INTERVAL_BLOCKS ||\n Date.now() - this.lastFlush >= FLUSH_INTERVAL_MS\n );\n }\n\n async flush(db: Kysely<Database>): Promise<void> {\n if (this.current.blocksProcessed === 0) return;\n\n const entry = this.current;\n this.current = this.newEntry();\n this.lastFlush = Date.now();\n\n const avgOpsPerBlock = entry.blocksProcessed > 0\n ? entry.totalOps / entry.blocksProcessed\n : 0;\n\n await db\n .insertInto(\"subgraph_processing_stats\")\n .values({\n subgraph_name: entry.subgraphName,\n api_key_id: entry.apiKeyId,\n bucket_start: entry.bucketStart,\n bucket_end: new Date(),\n blocks_processed: entry.blocksProcessed,\n total_time_ms: Math.round(entry.totalTimeMs),\n handler_time_ms: Math.round(entry.handlerTimeMs),\n flush_time_ms: Math.round(entry.flushTimeMs),\n max_block_time_ms: Math.round(entry.maxBlockTimeMs),\n max_handler_time_ms: Math.round(entry.maxHandlerTimeMs),\n avg_ops_per_block: parseFloat(avgOpsPerBlock.toFixed(2)),\n is_catchup: entry.isCatchup,\n })\n .execute();\n }\n\n private newEntry(): StatsEntry {\n return {\n subgraphName: this.subgraphName,\n apiKeyId: this.apiKeyId,\n bucketStart: new Date(),\n blocksProcessed: 0,\n totalTimeMs: 0,\n handlerTimeMs: 0,\n flushTimeMs: 0,\n maxBlockTimeMs: 0,\n maxHandlerTimeMs: 0,\n totalOps: 0,\n isCatchup: this.isCatchup,\n };\n }\n}\n",
14
- "import { getDb, getRawClient } from \"@secondlayer/shared/db\";\nimport { updateSubgraphStatus } from \"@secondlayer/shared/db/queries/subgraphs\";\nimport { logger } from \"@secondlayer/shared/logger\";\nimport { getErrorMessage } from \"@secondlayer/shared\";\nimport { generateSubgraphSQL } from \"../schema/generator.ts\";\nimport { pgSchemaName } from \"../schema/utils.ts\";\nimport type { SubgraphDefinition } from \"../types.ts\";\nimport { processBlock } from \"./block-processor.ts\";\nimport { StatsAccumulator } from \"./stats.ts\";\n\nconst LOG_INTERVAL = 1000;\n\nexport interface ReindexOptions {\n fromBlock?: number;\n toBlock?: number;\n schemaName?: string;\n}\n\n/**\n * Reindex a subgraph by dropping its tables, recreating them, and reprocessing\n * all historical blocks through the handler pipeline.\n */\nexport async function reindexSubgraph(\n def: SubgraphDefinition,\n opts?: ReindexOptions,\n): Promise<{ processed: number }> {\n const db = getDb();\n const client = getRawClient();\n const subgraphName = def.name;\n const schemaName = opts?.schemaName ?? pgSchemaName(subgraphName);\n\n // Set status to reindexing\n await updateSubgraphStatus(db, subgraphName, \"reindexing\");\n\n logger.info(\"Reindex starting\", { subgraph: subgraphName });\n\n try {\n // Drop and recreate schema + tables\n await client.unsafe(`DROP SCHEMA IF EXISTS \"${schemaName}\" CASCADE`);\n\n const { statements } = generateSubgraphSQL(def, schemaName);\n for (const stmt of statements) {\n await client.unsafe(stmt);\n }\n\n logger.info(\"Schema recreated for reindex\", { subgraph: subgraphName });\n\n // Determine block range\n const fromBlock = opts?.fromBlock ?? 1;\n let toBlock: number;\n\n if (opts?.toBlock != null) {\n toBlock = opts.toBlock;\n } else {\n const progress = await db\n .selectFrom(\"index_progress\")\n .selectAll()\n .where(\"network\", \"=\", process.env.NETWORK ?? \"mainnet\")\n .executeTakeFirst();\n toBlock = progress?.last_indexed_block ?? progress?.last_contiguous_block ?? 0;\n }\n\n if (fromBlock > toBlock) {\n logger.info(\"No blocks to reindex\", { subgraph: subgraphName, fromBlock, toBlock });\n await updateSubgraphStatus(db, subgraphName, \"active\", 0);\n return { processed: 0 };\n }\n\n const totalBlocks = toBlock - fromBlock + 1;\n logger.info(\"Reindexing blocks\", { subgraph: subgraphName, fromBlock, toBlock, totalBlocks });\n\n // Look up api_key_id for stats\n const subgraphRow = await db\n .selectFrom(\"subgraphs\")\n .select(\"api_key_id\")\n .where(\"name\", \"=\", subgraphName)\n .executeTakeFirst();\n\n const stats = new StatsAccumulator(subgraphName, subgraphRow?.api_key_id ?? null, false);\n let blocksProcessed = 0;\n let totalEventsProcessed = 0;\n let totalErrors = 0;\n const PROGRESS_INTERVAL = 100; // update DB progress every N blocks\n\n for (let height = fromBlock; height <= toBlock; height++) {\n const result = await processBlock(def, subgraphName, height, { skipProgressUpdate: true });\n blocksProcessed++;\n totalEventsProcessed += result.processed;\n totalErrors += result.errors;\n\n if (result.timing) {\n stats.record(result.timing, result.processed);\n if (stats.shouldFlush()) {\n await stats.flush(db);\n }\n }\n\n // Batch progress updates to avoid NOTIFY storm\n if (blocksProcessed % PROGRESS_INTERVAL === 0) {\n await updateSubgraphStatus(db, subgraphName, \"reindexing\", height);\n }\n\n if (blocksProcessed % LOG_INTERVAL === 0) {\n logger.info(\"Reindex progress\", {\n subgraph: subgraphName,\n processed: blocksProcessed,\n total: totalBlocks,\n currentBlock: height,\n pct: Math.round((blocksProcessed / totalBlocks) * 100),\n });\n }\n }\n\n // Flush remaining stats\n await stats.flush(db);\n\n // Write final health metrics in one update\n const { recordSubgraphProcessed } = await import(\"@secondlayer/shared/db/queries/subgraphs\");\n if (totalEventsProcessed > 0 || totalErrors > 0) {\n await recordSubgraphProcessed(db, subgraphName, totalEventsProcessed, totalErrors,\n totalErrors > 0 ? `${totalErrors} error(s) during reindex` : undefined);\n }\n\n // Done — set back to active\n await updateSubgraphStatus(db, subgraphName, \"active\", toBlock);\n\n logger.info(\"Reindex complete\", { subgraph: subgraphName, blocks: blocksProcessed, events: totalEventsProcessed, errors: totalErrors });\n return { processed: blocksProcessed };\n } catch (err) {\n logger.error(\"Reindex failed\", {\n subgraph: subgraphName,\n error: getErrorMessage(err),\n });\n await updateSubgraphStatus(db, subgraphName, \"error\");\n throw err;\n }\n}\n",
15
- "import type { ColumnType, SubgraphDefinition } from \"../types.ts\";\nimport { pgSchemaName } from \"./utils.ts\";\n\nexport const TYPE_MAP: Record<ColumnType, string> = {\n text: \"TEXT\",\n uint: \"NUMERIC\",\n int: \"NUMERIC\",\n principal: \"TEXT\",\n boolean: \"BOOLEAN\",\n timestamp: \"TIMESTAMPTZ\",\n jsonb: \"JSONB\",\n};\n\nexport interface GeneratedSQL {\n statements: string[];\n hash: string;\n}\n\nfunction escapeLiteralDefault(value: unknown): string {\n if (value === null || value === undefined) return \"NULL\";\n if (typeof value === \"number\" || typeof value === \"bigint\") return String(value);\n if (typeof value === \"boolean\") return value ? \"TRUE\" : \"FALSE\";\n return `'${String(value).replace(/'/g, \"''\")}'`;\n}\n\n/**\n * Generates PostgreSQL DDL statements for a subgraph definition.\n * Creates a dedicated schema `subgraph_<name>` with one table per schema entry,\n * each with auto-columns and indexes.\n */\nexport function generateSubgraphSQL(def: SubgraphDefinition, schemaNameOverride?: string): GeneratedSQL {\n const schemaName = schemaNameOverride ?? pgSchemaName(def.name);\n const statements: string[] = [];\n\n // Check if any column uses search (trigram)\n const needsTrgm = Object.values(def.schema).some((table) =>\n Object.values(table.columns).some((col) => col.search),\n );\n\n if (needsTrgm) {\n statements.push(`CREATE EXTENSION IF NOT EXISTS pg_trgm`);\n }\n\n // Schema namespace\n statements.push(`CREATE SCHEMA IF NOT EXISTS ${schemaName}`);\n\n // One table per schema entry\n for (const [tableName, tableDef] of Object.entries(def.schema)) {\n const qualifiedName = `${schemaName}.${tableName}`;\n\n // Auto-columns + user columns\n const columnDefs: string[] = [\n `_id BIGSERIAL PRIMARY KEY`,\n `_block_height BIGINT NOT NULL`,\n `_tx_id TEXT NOT NULL`,\n `_created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()`,\n ];\n\n for (const [colName, col] of Object.entries(tableDef.columns)) {\n const sqlType = TYPE_MAP[col.type];\n const nullable = col.nullable ? \"\" : \" NOT NULL\";\n let colDef = `${colName} ${sqlType}${nullable}`;\n if (col.default !== undefined) {\n colDef += ` DEFAULT ${escapeLiteralDefault(col.default)}`;\n }\n columnDefs.push(colDef);\n }\n\n statements.push(\n `CREATE TABLE IF NOT EXISTS ${qualifiedName} (\\n ${columnDefs.join(\",\\n \")}\\n)`,\n );\n\n // Auto-indexes on meta columns\n statements.push(\n `CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_block_height ON ${qualifiedName} (_block_height)`,\n );\n statements.push(\n `CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_tx_id ON ${qualifiedName} (_tx_id)`,\n );\n\n // Single-column indexes\n for (const [colName, col] of Object.entries(tableDef.columns)) {\n if (col.indexed) {\n statements.push(\n `CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_${colName} ON ${qualifiedName} (${colName})`,\n );\n }\n }\n\n // Trigram GIN indexes for search columns\n for (const [colName, col] of Object.entries(tableDef.columns)) {\n if (col.search) {\n statements.push(\n `CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_${colName}_trgm ON ${qualifiedName} USING gin (${colName} gin_trgm_ops)`,\n );\n }\n }\n\n // Composite indexes\n if (tableDef.indexes) {\n for (let i = 0; i < tableDef.indexes.length; i++) {\n const cols = tableDef.indexes[i]!;\n const idxName = `idx_${schemaName}_${tableName}_composite_${i}`;\n statements.push(\n `CREATE INDEX IF NOT EXISTS ${idxName} ON ${qualifiedName} (${cols.join(\", \")})`,\n );\n }\n }\n\n // Unique constraints (required for upsert ON CONFLICT)\n if (tableDef.uniqueKeys) {\n for (let i = 0; i < tableDef.uniqueKeys.length; i++) {\n const cols = tableDef.uniqueKeys[i]!;\n const constraintName = `uq_${schemaName}_${tableName}_${cols.join(\"_\")}`;\n statements.push(\n `ALTER TABLE ${qualifiedName} ADD CONSTRAINT ${constraintName} UNIQUE (${cols.join(\", \")})`,\n );\n }\n }\n }\n\n // Hash based on schema structure (excludes handler)\n const hashInput = JSON.stringify({\n name: def.name,\n version: def.version,\n schema: def.schema,\n sources: def.sources,\n }, (_key, value) => typeof value === \"bigint\" ? value.toString() : value);\n const hash = String(Bun.hash(hashInput));\n\n return { statements, hash };\n}\n",
16
- "import type { SubgraphDefinition, SubgraphSchema } from \"./types.ts\";\n\n/**\n * Identity function that preserves schema literal types for type inference.\n *\n * The generic `S` is narrowed to the exact schema shape so that column type\n * literals (e.g. `\"uint\"`) are preserved rather than widened to `string`.\n *\n * @example\n * ```ts\n * export default defineSubgraph({\n * name: \"my-subgraph\",\n * sources: [{ contract: \"SP000...::my-contract\" }],\n * schema: { transfers: { columns: { amount: { type: \"uint\" } } } },\n * handlers: { \"*\": (event, ctx) => { ... } }\n * })\n * // typeof result.schema.transfers.columns.amount.type \"uint\" (not string)\n * ```\n */\nexport function defineSubgraph<S extends SubgraphSchema>(\n def: Omit<SubgraphDefinition, \"schema\"> & { schema: S },\n): Omit<SubgraphDefinition, \"schema\"> & { schema: S } {\n return def;\n}\n",
17
- "import { sql, type Kysely } from \"kysely\";\nimport type { Database } from \"@secondlayer/shared/db\";\nimport { validateSubgraphDefinition } from \"../validate.ts\";\nimport { generateSubgraphSQL, TYPE_MAP } from \"./generator.ts\";\nimport { pgSchemaName } from \"./utils.ts\";\nimport type { SubgraphDefinition, SubgraphSchema } from \"../types.ts\";\n\ntype AnyDb = Kysely<Database>;\n\n/** Deep-clone an object, converting BigInts to strings for JSON serialization. */\nfunction toJsonSafe(obj: unknown): unknown {\n return JSON.parse(JSON.stringify(obj, (_key, value) =>\n typeof value === \"bigint\" ? value.toString() : value\n ));\n}\n\nexport interface TableDiff {\n /** Tables added to the schema */\n addedTables: string[];\n /** Tables removed from the schema */\n removedTables: string[];\n /** Per-table column diffs (only for tables present in both) */\n tables: Record<string, ColumnDiff>;\n}\n\nexport interface ColumnDiff {\n added: string[];\n removed: string[];\n changed: string[];\n}\n\n/**\n * Compare two multi-table subgraph schemas and return differences.\n */\nexport function diffSchema(existing: SubgraphSchema, incoming: SubgraphSchema): TableDiff {\n const existingTables = new Set(Object.keys(existing));\n const incomingTables = new Set(Object.keys(incoming));\n\n const addedTables = [...incomingTables].filter((t) => !existingTables.has(t));\n const removedTables = [...existingTables].filter((t) => !incomingTables.has(t));\n\n const tables: Record<string, ColumnDiff> = {};\n for (const tableName of incomingTables) {\n if (!existingTables.has(tableName)) continue;\n const existingCols = existing[tableName]!.columns;\n const incomingCols = incoming[tableName]!.columns;\n\n const existingKeys = new Set(Object.keys(existingCols));\n const incomingKeys = new Set(Object.keys(incomingCols));\n\n tables[tableName] = {\n added: [...incomingKeys].filter((k) => !existingKeys.has(k)),\n removed: [...existingKeys].filter((k) => !incomingKeys.has(k)),\n changed: [...incomingKeys].filter((k) => {\n if (!existingKeys.has(k)) return false;\n return JSON.stringify(existingCols[k]) !== JSON.stringify(incomingCols[k]);\n }),\n };\n }\n\n return { addedTables, removedTables, tables };\n}\n\n/**\n * Returns true if the diff contains any breaking changes\n * (removed tables, removed columns, or changed column types).\n */\nfunction hasBreakingChanges(diff: TableDiff): { breaking: boolean; reasons: string[] } {\n const reasons: string[] = [];\n if (diff.removedTables.length > 0) {\n reasons.push(`removed tables: [${diff.removedTables.join(\", \")}]`);\n }\n for (const [table, colDiff] of Object.entries(diff.tables)) {\n if (colDiff.removed.length > 0) {\n reasons.push(`${table}: removed columns [${colDiff.removed.join(\", \")}]`);\n }\n if (colDiff.changed.length > 0) {\n reasons.push(`${table}: changed columns [${colDiff.changed.join(\", \")}]`);\n }\n }\n return { breaking: reasons.length > 0, reasons };\n}\n\n/**\n * Deploy a subgraph schema to the database.\n * - New subgraph → CREATE SCHEMA + tables + register\n * - Same hash → no-op\n * - Additive change → ALTER TABLE ADD COLUMN / CREATE TABLE for new tables\n * - Breaking change → throws error\n */\nexport async function deploySchema(\n db: AnyDb,\n def: SubgraphDefinition,\n handlerPath: string,\n opts?: { forceReindex?: boolean; apiKeyId?: string; schemaName?: string },\n): Promise<{ action: \"created\" | \"unchanged\" | \"updated\" | \"reindexed\"; subgraphId: string }> {\n validateSubgraphDefinition(def);\n\n const { statements, hash } = generateSubgraphSQL(def, opts?.schemaName);\n const { getSubgraph, registerSubgraph } = await import(\"@secondlayer/shared/db/queries/subgraphs\");\n\n const existing = await getSubgraph(db, def.name, opts?.apiKeyId);\n\n const schemaName = opts?.schemaName ?? pgSchemaName(def.name);\n const regData = {\n name: def.name,\n version: def.version || \"1.0.0\",\n definition: toJsonSafe({ name: def.name, version: def.version, description: def.description, sources: def.sources, schema: def.schema }) as Record<string, unknown>,\n schemaHash: hash,\n handlerPath,\n apiKeyId: opts?.apiKeyId,\n schemaName,\n };\n\n if (existing) {\n if (existing.schema_hash === hash && !opts?.forceReindex) {\n // Update handler path in case file moved\n const { updateSubgraphHandlerPath } = await import(\"@secondlayer/shared/db/queries/subgraphs\");\n await updateSubgraphHandlerPath(db, def.name, handlerPath);\n return { action: \"unchanged\", subgraphId: existing.id };\n }\n\n if (existing.schema_hash === hash && opts?.forceReindex) {\n // Same schema but force reindex requested — drop and recreate\n await sql.raw(`DROP SCHEMA IF EXISTS \"${schemaName}\" CASCADE`).execute(db);\n for (const stmt of statements) {\n await sql.raw(stmt).execute(db);\n }\n const sg = await registerSubgraph(db, regData);\n return { action: \"reindexed\", subgraphId: sg.id };\n }\n\n if (existing.definition.schema) {\n const diff = diffSchema(existing.definition.schema as SubgraphSchema, def.schema);\n const { breaking, reasons } = hasBreakingChanges(diff);\n\n if (breaking) {\n if (!opts?.forceReindex) {\n throw new Error(\n `Breaking schema change detected (${reasons.join(\"; \")}). ` +\n `Use --reindex to force rebuild, or delete the subgraph first.`,\n );\n }\n\n // Force reindex: drop schema, recreate, register, caller triggers reindex\n await sql.raw(`DROP SCHEMA IF EXISTS \"${schemaName}\" CASCADE`).execute(db);\n for (const stmt of statements) {\n await sql.raw(stmt).execute(db);\n }\n const sg = await registerSubgraph(db, regData);\n return { action: \"reindexed\", subgraphId: sg.id };\n }\n\n // Create new tables\n for (const tableName of diff.addedTables) {\n const tableDef = def.schema[tableName]!;\n const qualifiedName = `${schemaName}.${tableName}`;\n const colDefs = [\n `_id BIGSERIAL PRIMARY KEY`,\n `_block_height BIGINT NOT NULL`,\n `_tx_id TEXT NOT NULL`,\n `_created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()`,\n ];\n for (const [colName, col] of Object.entries(tableDef.columns)) {\n const nullable = col.nullable ? \"\" : \" NOT NULL\";\n colDefs.push(`${colName} ${TYPE_MAP[col.type]!}${nullable}`);\n }\n await sql.raw(\n `CREATE TABLE IF NOT EXISTS ${qualifiedName} (\\n ${colDefs.join(\",\\n \")}\\n)`,\n ).execute(db);\n await sql.raw(\n `CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_block_height ON ${qualifiedName} (_block_height)`,\n ).execute(db);\n await sql.raw(\n `CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_tx_id ON ${qualifiedName} (_tx_id)`,\n ).execute(db);\n for (const [colName, col] of Object.entries(tableDef.columns)) {\n if (col.indexed) {\n await sql.raw(\n `CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_${colName} ON ${qualifiedName} (${colName})`,\n ).execute(db);\n }\n if (col.search) {\n await sql.raw(\n `CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_${colName}_trgm ON ${qualifiedName} USING gin (${colName} gin_trgm_ops)`,\n ).execute(db);\n }\n }\n }\n\n // Add columns to existing tables\n for (const [tableName, colDiff] of Object.entries(diff.tables)) {\n if (colDiff.added.length === 0) continue;\n const qualifiedName = `${schemaName}.${tableName}`;\n const tableDef = def.schema[tableName]!;\n for (const colName of colDiff.added) {\n const col = tableDef.columns[colName]!;\n const sqlType = TYPE_MAP[col.type]!;\n const nullable = col.nullable ? \"\" : \" NOT NULL DEFAULT \" + getDefault(col.type);\n await sql.raw(\n `ALTER TABLE ${qualifiedName} ADD COLUMN ${colName} ${sqlType}${nullable}`,\n ).execute(db);\n if (col.indexed) {\n await sql.raw(\n `CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_${colName} ON ${qualifiedName} (${colName})`,\n ).execute(db);\n }\n if (col.search) {\n await sql.raw(\n `CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_${colName}_trgm ON ${qualifiedName} USING gin (${colName} gin_trgm_ops)`,\n ).execute(db);\n }\n }\n }\n }\n\n const sg = await registerSubgraph(db, regData);\n return { action: \"updated\", subgraphId: sg.id };\n }\n\n // New subgraph — execute all DDL\n for (const stmt of statements) {\n await sql.raw(stmt).execute(db);\n }\n\n const sg = await registerSubgraph(db, regData);\n return { action: \"created\", subgraphId: sg.id };\n}\n\nfunction getDefault(type: string): string {\n switch (type) {\n case \"text\":\n case \"principal\":\n return \"''\";\n case \"uint\":\n case \"int\":\n return \"0\";\n case \"boolean\":\n return \"false\";\n case \"timestamp\":\n return \"NOW()\";\n case \"jsonb\":\n return \"'{}'\";\n default:\n return \"''\";\n }\n}\n"
13
+ "import type { Database } from \"@secondlayer/shared/db\";\nimport type { Kysely } from \"kysely\";\nimport type { ProcessBlockTiming } from \"./block-processor.ts\";\n\ninterface StatsEntry {\n\tsubgraphName: string;\n\tapiKeyId: string | null;\n\tbucketStart: Date;\n\tblocksProcessed: number;\n\ttotalTimeMs: number;\n\thandlerTimeMs: number;\n\tflushTimeMs: number;\n\tmaxBlockTimeMs: number;\n\tmaxHandlerTimeMs: number;\n\ttotalOps: number;\n\tisCatchup: boolean;\n}\n\nconst FLUSH_INTERVAL_BLOCKS = 100;\nconst FLUSH_INTERVAL_MS = 60_000;\n\n/**\n * Accumulates per-block timing stats and flushes to DB periodically.\n * One instance per subgraph during catchup/reindex/live processing.\n */\nexport class StatsAccumulator {\n\tprivate current: StatsEntry;\n\tprivate lastFlush = Date.now();\n\n\tconstructor(\n\t\tprivate subgraphName: string,\n\t\tprivate apiKeyId: string | null,\n\t\tprivate isCatchup: boolean,\n\t) {\n\t\tthis.current = this.newEntry();\n\t}\n\n\trecord(timing: ProcessBlockTiming, opsCount: number): void {\n\t\tthis.current.blocksProcessed++;\n\t\tthis.current.totalTimeMs += timing.totalMs;\n\t\tthis.current.handlerTimeMs += timing.handlerMs;\n\t\tthis.current.flushTimeMs += timing.flushMs;\n\t\tthis.current.maxBlockTimeMs = Math.max(\n\t\t\tthis.current.maxBlockTimeMs,\n\t\t\ttiming.totalMs,\n\t\t);\n\t\tthis.current.maxHandlerTimeMs = Math.max(\n\t\t\tthis.current.maxHandlerTimeMs,\n\t\t\ttiming.handlerMs,\n\t\t);\n\t\tthis.current.totalOps += opsCount;\n\t}\n\n\tshouldFlush(): boolean {\n\t\treturn (\n\t\t\tthis.current.blocksProcessed >= FLUSH_INTERVAL_BLOCKS ||\n\t\t\tDate.now() - this.lastFlush >= FLUSH_INTERVAL_MS\n\t\t);\n\t}\n\n\tasync flush(db: Kysely<Database>): Promise<void> {\n\t\tif (this.current.blocksProcessed === 0) return;\n\n\t\tconst entry = this.current;\n\t\tthis.current = this.newEntry();\n\t\tthis.lastFlush = Date.now();\n\n\t\tconst avgOpsPerBlock =\n\t\t\tentry.blocksProcessed > 0 ? entry.totalOps / entry.blocksProcessed : 0;\n\n\t\tawait db\n\t\t\t.insertInto(\"subgraph_processing_stats\")\n\t\t\t.values({\n\t\t\t\tsubgraph_name: entry.subgraphName,\n\t\t\t\tapi_key_id: entry.apiKeyId,\n\t\t\t\tbucket_start: entry.bucketStart,\n\t\t\t\tbucket_end: new Date(),\n\t\t\t\tblocks_processed: entry.blocksProcessed,\n\t\t\t\ttotal_time_ms: Math.round(entry.totalTimeMs),\n\t\t\t\thandler_time_ms: Math.round(entry.handlerTimeMs),\n\t\t\t\tflush_time_ms: Math.round(entry.flushTimeMs),\n\t\t\t\tmax_block_time_ms: Math.round(entry.maxBlockTimeMs),\n\t\t\t\tmax_handler_time_ms: Math.round(entry.maxHandlerTimeMs),\n\t\t\t\tavg_ops_per_block: Number.parseFloat(avgOpsPerBlock.toFixed(2)),\n\t\t\t\tis_catchup: entry.isCatchup,\n\t\t\t})\n\t\t\t.execute();\n\t}\n\n\tprivate newEntry(): StatsEntry {\n\t\treturn {\n\t\t\tsubgraphName: this.subgraphName,\n\t\t\tapiKeyId: this.apiKeyId,\n\t\t\tbucketStart: new Date(),\n\t\t\tblocksProcessed: 0,\n\t\t\ttotalTimeMs: 0,\n\t\t\thandlerTimeMs: 0,\n\t\t\tflushTimeMs: 0,\n\t\t\tmaxBlockTimeMs: 0,\n\t\t\tmaxHandlerTimeMs: 0,\n\t\t\ttotalOps: 0,\n\t\t\tisCatchup: this.isCatchup,\n\t\t};\n\t}\n}\n",
14
+ "import { getErrorMessage } from \"@secondlayer/shared\";\nimport { getDb, getRawClient } from \"@secondlayer/shared/db\";\nimport {\n\ttype GapRange,\n\trecordGapBatch,\n\tresolveGaps,\n} from \"@secondlayer/shared/db/queries/subgraph-gaps\";\nimport { updateSubgraphStatus } from \"@secondlayer/shared/db/queries/subgraphs\";\nimport { logger } from \"@secondlayer/shared/logger\";\nimport { generateSubgraphSQL } from \"../schema/generator.ts\";\nimport { pgSchemaName } from \"../schema/utils.ts\";\nimport type { SubgraphDefinition } from \"../types.ts\";\nimport { avgEventsPerBlock, loadBlockRange } from \"./batch-loader.ts\";\nimport { type ProcessBlockResult, processBlock } from \"./block-processor.ts\";\nimport { StatsAccumulator } from \"./stats.ts\";\n\nconst LOG_INTERVAL = 1000;\nconst DEFAULT_BATCH_SIZE = 500;\nconst MIN_BATCH_SIZE = 100;\nconst MAX_BATCH_SIZE = 1000;\n\n/**\n * Coalesce individual block heights + reasons into contiguous gap ranges.\n */\nfunction coalesceFailedBlocks(\n\tblocks: { height: number; reason: string }[],\n): GapRange[] {\n\tif (blocks.length === 0) return [];\n\tblocks.sort((a, b) => a.height - b.height);\n\n\tconst ranges: GapRange[] = [];\n\tlet start = blocks[0].height;\n\tlet end = blocks[0].height;\n\tlet reason = blocks[0].reason;\n\n\tfor (let i = 1; i < blocks.length; i++) {\n\t\tconst b = blocks[i];\n\t\tif (b.height === end + 1 && b.reason === reason) {\n\t\t\tend = b.height;\n\t\t} else {\n\t\t\tranges.push({ start, end, reason });\n\t\t\tstart = b.height;\n\t\t\tend = b.height;\n\t\t\treason = b.reason;\n\t\t}\n\t}\n\tranges.push({ start, end, reason });\n\treturn ranges;\n}\n\nexport interface ReindexOptions {\n\tfromBlock?: number;\n\ttoBlock?: number;\n\tschemaName?: string;\n}\n\n/**\n * Shared block range processor used by both reindex and backfill.\n * Processes blocks in batches with prefetch pipeline.\n */\nasync function processBlockRange(\n\tdef: SubgraphDefinition,\n\topts: {\n\t\tfromBlock: number;\n\t\ttoBlock: number;\n\t\tstatus: string;\n\t\tisCatchup: boolean;\n\t\tapiKeyId: string | null;\n\t\tsubgraphId?: string;\n\t},\n): Promise<{\n\tblocksProcessed: number;\n\ttotalEventsProcessed: number;\n\ttotalErrors: number;\n}> {\n\tconst db = getDb();\n\tconst subgraphName = def.name;\n\tconst { fromBlock, toBlock, status } = opts;\n\tconst totalBlocks = toBlock - fromBlock + 1;\n\n\tconst stats = new StatsAccumulator(\n\t\tsubgraphName,\n\t\topts.apiKeyId,\n\t\topts.isCatchup,\n\t);\n\tlet blocksProcessed = 0;\n\tlet totalEventsProcessed = 0;\n\tlet totalErrors = 0;\n\tlet batchSize = DEFAULT_BATCH_SIZE;\n\tlet currentHeight = fromBlock;\n\n\t// Pipeline: start loading first batch\n\tlet nextBatchPromise = loadBlockRange(\n\t\tdb,\n\t\tcurrentHeight,\n\t\tMath.min(currentHeight + batchSize - 1, toBlock),\n\t);\n\n\twhile (currentHeight <= toBlock) {\n\t\tconst batch = await nextBatchPromise;\n\t\tconst batchEnd = Math.min(currentHeight + batchSize - 1, toBlock);\n\n\t\t// Prefetch next batch\n\t\tconst nextStart = batchEnd + 1;\n\t\tif (nextStart <= toBlock) {\n\t\t\tconst nextEnd = Math.min(nextStart + batchSize - 1, toBlock);\n\t\t\tnextBatchPromise = loadBlockRange(db, nextStart, nextEnd);\n\t\t}\n\n\t\tconst batchFailedBlocks: { height: number; reason: string }[] = [];\n\n\t\tfor (let height = currentHeight; height <= batchEnd; height++) {\n\t\t\tconst blockData = batch.get(height);\n\t\t\tif (!blockData) {\n\t\t\t\tbatchFailedBlocks.push({ height, reason: \"block_missing\" });\n\t\t\t\tblocksProcessed++;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tlet result: ProcessBlockResult;\n\t\t\ttry {\n\t\t\t\tresult = await processBlock(def, subgraphName, height, {\n\t\t\t\t\tskipProgressUpdate: true,\n\t\t\t\t\tpreloaded: blockData,\n\t\t\t\t});\n\t\t\t} catch (err) {\n\t\t\t\tlogger.error(\"Block processing error\", {\n\t\t\t\t\tsubgraph: subgraphName,\n\t\t\t\t\tblockHeight: height,\n\t\t\t\t\terror: err instanceof Error ? err.message : String(err),\n\t\t\t\t});\n\t\t\t\tbatchFailedBlocks.push({ height, reason: \"processing_error\" });\n\t\t\t\tawait updateSubgraphStatus(db, subgraphName, status, height).catch(\n\t\t\t\t\t() => {},\n\t\t\t\t);\n\t\t\t\tblocksProcessed++;\n\t\t\t\ttotalErrors++;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tblocksProcessed++;\n\t\t\ttotalEventsProcessed += result.processed;\n\t\t\ttotalErrors += result.errors;\n\n\t\t\tif (result.timing) {\n\t\t\t\tstats.record(result.timing, result.processed);\n\t\t\t\tif (stats.shouldFlush()) {\n\t\t\t\t\tawait stats.flush(db);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Batch progress updates\n\t\t\tif (blocksProcessed % 100 === 0) {\n\t\t\t\tawait updateSubgraphStatus(db, subgraphName, status, height);\n\t\t\t}\n\n\t\t\tif (blocksProcessed % LOG_INTERVAL === 0) {\n\t\t\t\tlogger.info(\n\t\t\t\t\t`${status === \"reindexing\" ? \"Reindex\" : \"Backfill\"} progress`,\n\t\t\t\t\t{\n\t\t\t\t\t\tsubgraph: subgraphName,\n\t\t\t\t\t\tprocessed: blocksProcessed,\n\t\t\t\t\t\ttotal: totalBlocks,\n\t\t\t\t\t\tcurrentBlock: height,\n\t\t\t\t\t\tpct: Math.round((blocksProcessed / totalBlocks) * 100),\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// Record any gaps from this batch\n\t\tif (batchFailedBlocks.length > 0 && opts.subgraphId) {\n\t\t\tconst gaps = coalesceFailedBlocks(batchFailedBlocks);\n\t\t\tawait recordGapBatch(db, opts.subgraphId, subgraphName, gaps).catch(\n\t\t\t\t(err: unknown) => {\n\t\t\t\t\tlogger.warn(\"Failed to record subgraph gaps\", {\n\t\t\t\t\t\tsubgraph: subgraphName,\n\t\t\t\t\t\terror: err instanceof Error ? err.message : String(err),\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\n\t\t// Adaptive batch sizing\n\t\tconst avg = avgEventsPerBlock(batch);\n\t\tif (avg > 50)\n\t\t\tbatchSize = Math.max(Math.round(batchSize * 0.5), MIN_BATCH_SIZE);\n\t\telse if (avg < 10)\n\t\t\tbatchSize = Math.min(Math.round(batchSize * 1.5), MAX_BATCH_SIZE);\n\n\t\tcurrentHeight = batchEnd + 1;\n\t}\n\n\tawait stats.flush(db);\n\treturn { blocksProcessed, totalEventsProcessed, totalErrors };\n}\n\n/**\n * Resolve block range from options, defaulting to 1..chain_tip.\n */\nasync function resolveBlockRange(\n\tdb: ReturnType<typeof getDb>,\n\topts?: ReindexOptions,\n): Promise<{ fromBlock: number; toBlock: number }> {\n\tconst fromBlock = opts?.fromBlock ?? 1;\n\tlet toBlock: number;\n\n\tif (opts?.toBlock != null) {\n\t\ttoBlock = opts.toBlock;\n\t} else {\n\t\tconst progress = await db\n\t\t\t.selectFrom(\"index_progress\")\n\t\t\t.selectAll()\n\t\t\t.where(\"network\", \"=\", process.env.NETWORK ?? \"mainnet\")\n\t\t\t.executeTakeFirst();\n\t\ttoBlock =\n\t\t\tprogress?.last_indexed_block ?? progress?.last_contiguous_block ?? 0;\n\t}\n\n\treturn { fromBlock, toBlock };\n}\n\n/**\n * Reindex a subgraph by dropping its tables, recreating them, and reprocessing\n * all historical blocks through the handler pipeline.\n */\nexport async function reindexSubgraph(\n\tdef: SubgraphDefinition,\n\topts?: ReindexOptions,\n): Promise<{ processed: number }> {\n\tconst db = getDb();\n\tconst client = getRawClient();\n\tconst subgraphName = def.name;\n\tconst schemaName = opts?.schemaName ?? pgSchemaName(subgraphName);\n\n\tawait updateSubgraphStatus(db, subgraphName, \"reindexing\");\n\tlogger.info(\"Reindex starting\", { subgraph: subgraphName });\n\n\ttry {\n\t\t// Drop and recreate schema + tables\n\t\tawait client.unsafe(`DROP SCHEMA IF EXISTS \"${schemaName}\" CASCADE`);\n\t\tconst { statements } = generateSubgraphSQL(def, schemaName);\n\t\tfor (const stmt of statements) {\n\t\t\tawait client.unsafe(stmt);\n\t\t}\n\t\tlogger.info(\"Schema recreated for reindex\", { subgraph: subgraphName });\n\n\t\tconst { fromBlock, toBlock } = await resolveBlockRange(db, opts);\n\n\t\tif (fromBlock > toBlock) {\n\t\t\tlogger.info(\"No blocks to reindex\", {\n\t\t\t\tsubgraph: subgraphName,\n\t\t\t\tfromBlock,\n\t\t\t\ttoBlock,\n\t\t\t});\n\t\t\tawait updateSubgraphStatus(db, subgraphName, \"active\", 0);\n\t\t\treturn { processed: 0 };\n\t\t}\n\n\t\tlogger.info(\"Reindexing blocks\", {\n\t\t\tsubgraph: subgraphName,\n\t\t\tfromBlock,\n\t\t\ttoBlock,\n\t\t\ttotalBlocks: toBlock - fromBlock + 1,\n\t\t});\n\n\t\tconst subgraphRow = await db\n\t\t\t.selectFrom(\"subgraphs\")\n\t\t\t.select([\"id\", \"api_key_id\"])\n\t\t\t.where(\"name\", \"=\", subgraphName)\n\t\t\t.executeTakeFirst();\n\n\t\tconst result = await processBlockRange(def, {\n\t\t\tfromBlock,\n\t\t\ttoBlock,\n\t\t\tstatus: \"reindexing\",\n\t\t\tisCatchup: false,\n\t\t\tapiKeyId: subgraphRow?.api_key_id ?? null,\n\t\t\tsubgraphId: subgraphRow?.id,\n\t\t});\n\n\t\t// Write final health metrics\n\t\tconst { recordSubgraphProcessed } = await import(\n\t\t\t\"@secondlayer/shared/db/queries/subgraphs\"\n\t\t);\n\t\tif (result.totalEventsProcessed > 0 || result.totalErrors > 0) {\n\t\t\tawait recordSubgraphProcessed(\n\t\t\t\tdb,\n\t\t\t\tsubgraphName,\n\t\t\t\tresult.totalEventsProcessed,\n\t\t\t\tresult.totalErrors,\n\t\t\t\tresult.totalErrors > 0\n\t\t\t\t\t? `${result.totalErrors} error(s) during reindex`\n\t\t\t\t\t: undefined,\n\t\t\t);\n\t\t}\n\n\t\tawait updateSubgraphStatus(db, subgraphName, \"active\", toBlock);\n\t\tlogger.info(\"Reindex complete\", {\n\t\t\tsubgraph: subgraphName,\n\t\t\tblocks: result.blocksProcessed,\n\t\t\tevents: result.totalEventsProcessed,\n\t\t\terrors: result.totalErrors,\n\t\t});\n\t\treturn { processed: result.blocksProcessed };\n\t} catch (err) {\n\t\tlogger.error(\"Reindex failed\", {\n\t\t\tsubgraph: subgraphName,\n\t\t\terror: getErrorMessage(err),\n\t\t});\n\t\tawait updateSubgraphStatus(db, subgraphName, \"error\");\n\t\tthrow err;\n\t}\n}\n\n/**\n * Backfill a subgraph by re-processing a block range WITHOUT dropping the schema.\n * Uses upserts so existing data is updated, not duplicated. Safe to run while\n * the subgraph is actively syncing.\n */\nexport async function backfillSubgraph(\n\tdef: SubgraphDefinition,\n\topts: { fromBlock: number; toBlock: number; schemaName?: string },\n): Promise<{ processed: number }> {\n\tconst db = getDb();\n\tconst subgraphName = def.name;\n\n\tlogger.info(\"Backfill starting\", {\n\t\tsubgraph: subgraphName,\n\t\tfrom: opts.fromBlock,\n\t\tto: opts.toBlock,\n\t});\n\n\ttry {\n\t\tconst subgraphRow = await db\n\t\t\t.selectFrom(\"subgraphs\")\n\t\t\t.select([\"id\", \"api_key_id\"])\n\t\t\t.where(\"name\", \"=\", subgraphName)\n\t\t\t.executeTakeFirst();\n\n\t\tconst result = await processBlockRange(def, {\n\t\t\tfromBlock: opts.fromBlock,\n\t\t\ttoBlock: opts.toBlock,\n\t\t\tstatus: \"active\",\n\t\t\tisCatchup: false,\n\t\t\tapiKeyId: subgraphRow?.api_key_id ?? null,\n\t\t\tsubgraphId: subgraphRow?.id,\n\t\t});\n\n\t\t// Resolve any gaps within the backfilled range\n\t\tconst resolved = await resolveGaps(\n\t\t\tdb,\n\t\t\tsubgraphName,\n\t\t\topts.fromBlock,\n\t\t\topts.toBlock,\n\t\t).catch(() => 0);\n\t\tif (resolved > 0) {\n\t\t\tlogger.info(\"Resolved subgraph gaps via backfill\", {\n\t\t\t\tsubgraph: subgraphName,\n\t\t\t\tresolved,\n\t\t\t});\n\t\t}\n\n\t\t// Write final health metrics\n\t\tconst { recordSubgraphProcessed } = await import(\n\t\t\t\"@secondlayer/shared/db/queries/subgraphs\"\n\t\t);\n\t\tif (result.totalEventsProcessed > 0 || result.totalErrors > 0) {\n\t\t\tawait recordSubgraphProcessed(\n\t\t\t\tdb,\n\t\t\t\tsubgraphName,\n\t\t\t\tresult.totalEventsProcessed,\n\t\t\t\tresult.totalErrors,\n\t\t\t\tresult.totalErrors > 0\n\t\t\t\t\t? `${result.totalErrors} error(s) during backfill`\n\t\t\t\t\t: undefined,\n\t\t\t);\n\t\t}\n\n\t\tlogger.info(\"Backfill complete\", {\n\t\t\tsubgraph: subgraphName,\n\t\t\tblocks: result.blocksProcessed,\n\t\t\tevents: result.totalEventsProcessed,\n\t\t\terrors: result.totalErrors,\n\t\t});\n\t\treturn { processed: result.blocksProcessed };\n\t} catch (err) {\n\t\tlogger.error(\"Backfill failed\", {\n\t\t\tsubgraph: subgraphName,\n\t\t\terror: getErrorMessage(err),\n\t\t});\n\t\tthrow err;\n\t}\n}\n",
15
+ "import type { ColumnType, SubgraphDefinition } from \"../types.ts\";\nimport { pgSchemaName } from \"./utils.ts\";\n\nexport const TYPE_MAP: Record<ColumnType, string> = {\n\ttext: \"TEXT\",\n\tuint: \"NUMERIC\",\n\tint: \"NUMERIC\",\n\tprincipal: \"TEXT\",\n\tboolean: \"BOOLEAN\",\n\ttimestamp: \"TIMESTAMPTZ\",\n\tjsonb: \"JSONB\",\n};\n\nexport interface GeneratedSQL {\n\tstatements: string[];\n\thash: string;\n}\n\nfunction escapeLiteralDefault(value: unknown): string {\n\tif (value === null || value === undefined) return \"NULL\";\n\tif (typeof value === \"number\" || typeof value === \"bigint\")\n\t\treturn String(value);\n\tif (typeof value === \"boolean\") return value ? \"TRUE\" : \"FALSE\";\n\treturn `'${String(value).replace(/'/g, \"''\")}'`;\n}\n\n/**\n * Generates PostgreSQL DDL statements for a subgraph definition.\n * Creates a dedicated schema `subgraph_<name>` with one table per schema entry,\n * each with auto-columns and indexes.\n */\nexport function generateSubgraphSQL(\n\tdef: SubgraphDefinition,\n\tschemaNameOverride?: string,\n): GeneratedSQL {\n\tconst schemaName = schemaNameOverride ?? pgSchemaName(def.name);\n\tconst statements: string[] = [];\n\n\t// Check if any column uses search (trigram)\n\tconst needsTrgm = Object.values(def.schema).some((table) =>\n\t\tObject.values(table.columns).some((col) => col.search),\n\t);\n\n\tif (needsTrgm) {\n\t\tstatements.push(`CREATE EXTENSION IF NOT EXISTS pg_trgm`);\n\t}\n\n\t// Schema namespace\n\tstatements.push(`CREATE SCHEMA IF NOT EXISTS ${schemaName}`);\n\n\t// One table per schema entry\n\tfor (const [tableName, tableDef] of Object.entries(def.schema)) {\n\t\tconst qualifiedName = `${schemaName}.${tableName}`;\n\n\t\t// Auto-columns + user columns\n\t\tconst columnDefs: string[] = [\n\t\t\t`_id BIGSERIAL PRIMARY KEY`,\n\t\t\t`_block_height BIGINT NOT NULL`,\n\t\t\t`_tx_id TEXT NOT NULL`,\n\t\t\t`_created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()`,\n\t\t];\n\n\t\tfor (const [colName, col] of Object.entries(tableDef.columns)) {\n\t\t\tconst sqlType = TYPE_MAP[col.type];\n\t\t\tconst nullable = col.nullable ? \"\" : \" NOT NULL\";\n\t\t\tlet colDef = `${colName} ${sqlType}${nullable}`;\n\t\t\tif (col.default !== undefined) {\n\t\t\t\tcolDef += ` DEFAULT ${escapeLiteralDefault(col.default)}`;\n\t\t\t}\n\t\t\tcolumnDefs.push(colDef);\n\t\t}\n\n\t\tstatements.push(\n\t\t\t`CREATE TABLE IF NOT EXISTS ${qualifiedName} (\\n ${columnDefs.join(\",\\n \")}\\n)`,\n\t\t);\n\n\t\t// Auto-indexes on meta columns\n\t\tstatements.push(\n\t\t\t`CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_block_height ON ${qualifiedName} (_block_height)`,\n\t\t);\n\t\tstatements.push(\n\t\t\t`CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_tx_id ON ${qualifiedName} (_tx_id)`,\n\t\t);\n\n\t\t// Single-column indexes\n\t\tfor (const [colName, col] of Object.entries(tableDef.columns)) {\n\t\t\tif (col.indexed) {\n\t\t\t\tstatements.push(\n\t\t\t\t\t`CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_${colName} ON ${qualifiedName} (${colName})`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// Trigram GIN indexes for search columns\n\t\tfor (const [colName, col] of Object.entries(tableDef.columns)) {\n\t\t\tif (col.search) {\n\t\t\t\tstatements.push(\n\t\t\t\t\t`CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_${colName}_trgm ON ${qualifiedName} USING gin (${colName} gin_trgm_ops)`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// Composite indexes\n\t\tif (tableDef.indexes) {\n\t\t\tfor (let i = 0; i < tableDef.indexes.length; i++) {\n\t\t\t\tconst cols = tableDef.indexes[i]!;\n\t\t\t\tconst idxName = `idx_${schemaName}_${tableName}_composite_${i}`;\n\t\t\t\tstatements.push(\n\t\t\t\t\t`CREATE INDEX IF NOT EXISTS ${idxName} ON ${qualifiedName} (${cols.join(\", \")})`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// Unique constraints (required for upsert ON CONFLICT)\n\t\tif (tableDef.uniqueKeys) {\n\t\t\tfor (let i = 0; i < tableDef.uniqueKeys.length; i++) {\n\t\t\t\tconst cols = tableDef.uniqueKeys[i]!;\n\t\t\t\tconst constraintName = `uq_${schemaName}_${tableName}_${cols.join(\"_\")}`;\n\t\t\t\tstatements.push(\n\t\t\t\t\t`ALTER TABLE ${qualifiedName} ADD CONSTRAINT ${constraintName} UNIQUE (${cols.join(\", \")})`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Hash based on schema structure (excludes handler)\n\tconst hashInput = JSON.stringify(\n\t\t{\n\t\t\tname: def.name,\n\t\t\tversion: def.version,\n\t\t\tschema: def.schema,\n\t\t\tsources: def.sources,\n\t\t},\n\t\t(_key, value) => (typeof value === \"bigint\" ? value.toString() : value),\n\t);\n\tconst hash = String(Bun.hash(hashInput));\n\n\treturn { statements, hash };\n}\n",
16
+ "import type {\n\tBlock,\n\tDatabase,\n\tEvent,\n\tTransaction,\n} from \"@secondlayer/shared/db\";\nimport type { Kysely } from \"kysely\";\n\nexport interface BlockData {\n\tblock: Block;\n\ttxs: Transaction[];\n\tevents: Event[];\n}\n\n/**\n * Load a range of blocks with their transactions and events in 3 parallel queries.\n * Returns a Map keyed by block height. Non-canonical blocks are excluded.\n */\nexport async function loadBlockRange(\n\tdb: Kysely<Database>,\n\tfromHeight: number,\n\ttoHeight: number,\n): Promise<Map<number, BlockData>> {\n\tconst [blocks, txs, events] = await Promise.all([\n\t\tdb\n\t\t\t.selectFrom(\"blocks\")\n\t\t\t.selectAll()\n\t\t\t.where(\"height\", \">=\", fromHeight)\n\t\t\t.where(\"height\", \"<=\", toHeight)\n\t\t\t.where(\"canonical\", \"=\", true)\n\t\t\t.execute(),\n\t\tdb\n\t\t\t.selectFrom(\"transactions\")\n\t\t\t.selectAll()\n\t\t\t.where(\"block_height\", \">=\", fromHeight)\n\t\t\t.where(\"block_height\", \"<=\", toHeight)\n\t\t\t.execute(),\n\t\tdb\n\t\t\t.selectFrom(\"events\")\n\t\t\t.selectAll()\n\t\t\t.where(\"block_height\", \">=\", fromHeight)\n\t\t\t.where(\"block_height\", \"<=\", toHeight)\n\t\t\t.execute(),\n\t]);\n\n\t// Index by block height (coerce to number — bigint columns may return as string or number)\n\tconst txsByHeight = new Map<number, Transaction[]>();\n\tfor (const tx of txs) {\n\t\tconst h = Number(tx.block_height);\n\t\tconst list = txsByHeight.get(h) ?? [];\n\t\tlist.push(tx);\n\t\ttxsByHeight.set(h, list);\n\t}\n\n\tconst eventsByHeight = new Map<number, Event[]>();\n\tfor (const evt of events) {\n\t\tconst h = Number(evt.block_height);\n\t\tconst list = eventsByHeight.get(h) ?? [];\n\t\tlist.push(evt);\n\t\teventsByHeight.set(h, list);\n\t}\n\n\tconst result = new Map<number, BlockData>();\n\tfor (const block of blocks) {\n\t\tconst h = Number(block.height);\n\t\tresult.set(h, {\n\t\t\tblock,\n\t\t\ttxs: txsByHeight.get(h) ?? [],\n\t\t\tevents: eventsByHeight.get(h) ?? [],\n\t\t});\n\t}\n\n\treturn result;\n}\n\n/**\n * Compute average events per block from a loaded batch.\n * Used for adaptive batch sizing.\n */\nexport function avgEventsPerBlock(batch: Map<number, BlockData>): number {\n\tif (batch.size === 0) return 0;\n\tlet totalEvents = 0;\n\tfor (const data of batch.values()) {\n\t\ttotalEvents += data.events.length;\n\t}\n\treturn totalEvents / batch.size;\n}\n",
17
+ "import type { SubgraphDefinition, SubgraphSchema } from \"./types.ts\";\n\n/**\n * Identity function that preserves schema literal types for type inference.\n *\n * The generic `S` is narrowed to the exact schema shape so that column type\n * literals (e.g. `\"uint\"`) are preserved rather than widened to `string`.\n *\n * @example\n * ```ts\n * export default defineSubgraph({\n * name: \"my-subgraph\",\n * sources: [{ contract: \"SP000...::my-contract\" }],\n * schema: { transfers: { columns: { amount: { type: \"uint\" } } } },\n * handlers: { \"*\": (event, ctx) => { ... } }\n * })\n * // typeof result.schema.transfers.columns.amount.type \"uint\" (not string)\n * ```\n */\nexport function defineSubgraph<S extends SubgraphSchema>(\n\tdef: Omit<SubgraphDefinition, \"schema\"> & { schema: S },\n): Omit<SubgraphDefinition, \"schema\"> & { schema: S } {\n\treturn def;\n}\n",
18
+ "import type { Database } from \"@secondlayer/shared/db\";\nimport { type Kysely, sql } from \"kysely\";\nimport type { SubgraphDefinition, SubgraphSchema } from \"../types.ts\";\nimport { validateSubgraphDefinition } from \"../validate.ts\";\nimport { TYPE_MAP, generateSubgraphSQL } from \"./generator.ts\";\nimport { pgSchemaName } from \"./utils.ts\";\n\ntype AnyDb = Kysely<Database>;\n\n/** Deep-clone an object, converting BigInts to strings for JSON serialization. */\nfunction toJsonSafe(obj: unknown): unknown {\n\treturn JSON.parse(\n\t\tJSON.stringify(obj, (_key, value) =>\n\t\t\ttypeof value === \"bigint\" ? value.toString() : value,\n\t\t),\n\t);\n}\n\nexport interface TableDiff {\n\t/** Tables added to the schema */\n\taddedTables: string[];\n\t/** Tables removed from the schema */\n\tremovedTables: string[];\n\t/** Per-table column diffs (only for tables present in both) */\n\ttables: Record<string, ColumnDiff>;\n}\n\nexport interface ColumnDiff {\n\tadded: string[];\n\tremoved: string[];\n\tchanged: string[];\n}\n\n/**\n * Compare two multi-table subgraph schemas and return differences.\n */\nexport function diffSchema(\n\texisting: SubgraphSchema,\n\tincoming: SubgraphSchema,\n): TableDiff {\n\tconst existingTables = new Set(Object.keys(existing));\n\tconst incomingTables = new Set(Object.keys(incoming));\n\n\tconst addedTables = [...incomingTables].filter((t) => !existingTables.has(t));\n\tconst removedTables = [...existingTables].filter(\n\t\t(t) => !incomingTables.has(t),\n\t);\n\n\tconst tables: Record<string, ColumnDiff> = {};\n\tfor (const tableName of incomingTables) {\n\t\tif (!existingTables.has(tableName)) continue;\n\t\tconst existingCols = existing[tableName]!.columns;\n\t\tconst incomingCols = incoming[tableName]!.columns;\n\n\t\tconst existingKeys = new Set(Object.keys(existingCols));\n\t\tconst incomingKeys = new Set(Object.keys(incomingCols));\n\n\t\ttables[tableName] = {\n\t\t\tadded: [...incomingKeys].filter((k) => !existingKeys.has(k)),\n\t\t\tremoved: [...existingKeys].filter((k) => !incomingKeys.has(k)),\n\t\t\tchanged: [...incomingKeys].filter((k) => {\n\t\t\t\tif (!existingKeys.has(k)) return false;\n\t\t\t\treturn (\n\t\t\t\t\tJSON.stringify(existingCols[k]) !== JSON.stringify(incomingCols[k])\n\t\t\t\t);\n\t\t\t}),\n\t\t};\n\t}\n\n\treturn { addedTables, removedTables, tables };\n}\n\n/**\n * Returns true if the diff contains any breaking changes\n * (removed tables, removed columns, or changed column types).\n */\nfunction hasBreakingChanges(diff: TableDiff): {\n\tbreaking: boolean;\n\treasons: string[];\n} {\n\tconst reasons: string[] = [];\n\tif (diff.removedTables.length > 0) {\n\t\treasons.push(`removed tables: [${diff.removedTables.join(\", \")}]`);\n\t}\n\tfor (const [table, colDiff] of Object.entries(diff.tables)) {\n\t\tif (colDiff.removed.length > 0) {\n\t\t\treasons.push(`${table}: removed columns [${colDiff.removed.join(\", \")}]`);\n\t\t}\n\t\tif (colDiff.changed.length > 0) {\n\t\t\treasons.push(`${table}: changed columns [${colDiff.changed.join(\", \")}]`);\n\t\t}\n\t}\n\treturn { breaking: reasons.length > 0, reasons };\n}\n\n/**\n * Deploy a subgraph schema to the database.\n * - New subgraph → CREATE SCHEMA + tables + register\n * - Same hash → no-op\n * - Additive change → ALTER TABLE ADD COLUMN / CREATE TABLE for new tables\n * - Breaking change → throws error\n */\nexport async function deploySchema(\n\tdb: AnyDb,\n\tdef: SubgraphDefinition,\n\thandlerPath: string,\n\topts?: { forceReindex?: boolean; apiKeyId?: string; schemaName?: string },\n): Promise<{\n\taction: \"created\" | \"unchanged\" | \"updated\" | \"reindexed\";\n\tsubgraphId: string;\n}> {\n\tvalidateSubgraphDefinition(def);\n\n\tconst { statements, hash } = generateSubgraphSQL(def, opts?.schemaName);\n\tconst { getSubgraph, registerSubgraph } = await import(\n\t\t\"@secondlayer/shared/db/queries/subgraphs\"\n\t);\n\n\tconst existing = await getSubgraph(db, def.name, opts?.apiKeyId);\n\n\tconst schemaName = opts?.schemaName ?? pgSchemaName(def.name);\n\tconst regData = {\n\t\tname: def.name,\n\t\tversion: def.version || \"1.0.0\",\n\t\tdefinition: toJsonSafe({\n\t\t\tname: def.name,\n\t\t\tversion: def.version,\n\t\t\tdescription: def.description,\n\t\t\tsources: def.sources,\n\t\t\tschema: def.schema,\n\t\t}) as Record<string, unknown>,\n\t\tschemaHash: hash,\n\t\thandlerPath,\n\t\tapiKeyId: opts?.apiKeyId,\n\t\tschemaName,\n\t};\n\n\tif (existing) {\n\t\tif (existing.schema_hash === hash && !opts?.forceReindex) {\n\t\t\t// Update handler path in case file moved\n\t\t\tconst { updateSubgraphHandlerPath } = await import(\n\t\t\t\t\"@secondlayer/shared/db/queries/subgraphs\"\n\t\t\t);\n\t\t\tawait updateSubgraphHandlerPath(db, def.name, handlerPath);\n\t\t\treturn { action: \"unchanged\", subgraphId: existing.id };\n\t\t}\n\n\t\tif (existing.schema_hash === hash && opts?.forceReindex) {\n\t\t\t// Same schema but force reindex requested — drop and recreate\n\t\t\tawait sql\n\t\t\t\t.raw(`DROP SCHEMA IF EXISTS \"${schemaName}\" CASCADE`)\n\t\t\t\t.execute(db);\n\t\t\tfor (const stmt of statements) {\n\t\t\t\tawait sql.raw(stmt).execute(db);\n\t\t\t}\n\t\t\tconst sg = await registerSubgraph(db, regData);\n\t\t\treturn { action: \"reindexed\", subgraphId: sg.id };\n\t\t}\n\n\t\tif (existing.definition.schema) {\n\t\t\tconst diff = diffSchema(\n\t\t\t\texisting.definition.schema as SubgraphSchema,\n\t\t\t\tdef.schema,\n\t\t\t);\n\t\t\tconst { breaking, reasons } = hasBreakingChanges(diff);\n\n\t\t\tif (breaking) {\n\t\t\t\tif (!opts?.forceReindex) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Breaking schema change detected (${reasons.join(\"; \")}). ` +\n\t\t\t\t\t\t\t`Use --reindex to force rebuild, or delete the subgraph first.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\t// Force reindex: drop schema, recreate, register, caller triggers reindex\n\t\t\t\tawait sql\n\t\t\t\t\t.raw(`DROP SCHEMA IF EXISTS \"${schemaName}\" CASCADE`)\n\t\t\t\t\t.execute(db);\n\t\t\t\tfor (const stmt of statements) {\n\t\t\t\t\tawait sql.raw(stmt).execute(db);\n\t\t\t\t}\n\t\t\t\tconst sg = await registerSubgraph(db, regData);\n\t\t\t\treturn { action: \"reindexed\", subgraphId: sg.id };\n\t\t\t}\n\n\t\t\t// Create new tables\n\t\t\tfor (const tableName of diff.addedTables) {\n\t\t\t\tconst tableDef = def.schema[tableName]!;\n\t\t\t\tconst qualifiedName = `${schemaName}.${tableName}`;\n\t\t\t\tconst colDefs = [\n\t\t\t\t\t`_id BIGSERIAL PRIMARY KEY`,\n\t\t\t\t\t`_block_height BIGINT NOT NULL`,\n\t\t\t\t\t`_tx_id TEXT NOT NULL`,\n\t\t\t\t\t`_created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()`,\n\t\t\t\t];\n\t\t\t\tfor (const [colName, col] of Object.entries(tableDef.columns)) {\n\t\t\t\t\tconst nullable = col.nullable ? \"\" : \" NOT NULL\";\n\t\t\t\t\tcolDefs.push(`${colName} ${TYPE_MAP[col.type]!}${nullable}`);\n\t\t\t\t}\n\t\t\t\tawait sql\n\t\t\t\t\t.raw(\n\t\t\t\t\t\t`CREATE TABLE IF NOT EXISTS ${qualifiedName} (\\n ${colDefs.join(\",\\n \")}\\n)`,\n\t\t\t\t\t)\n\t\t\t\t\t.execute(db);\n\t\t\t\tawait sql\n\t\t\t\t\t.raw(\n\t\t\t\t\t\t`CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_block_height ON ${qualifiedName} (_block_height)`,\n\t\t\t\t\t)\n\t\t\t\t\t.execute(db);\n\t\t\t\tawait sql\n\t\t\t\t\t.raw(\n\t\t\t\t\t\t`CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_tx_id ON ${qualifiedName} (_tx_id)`,\n\t\t\t\t\t)\n\t\t\t\t\t.execute(db);\n\t\t\t\tfor (const [colName, col] of Object.entries(tableDef.columns)) {\n\t\t\t\t\tif (col.indexed) {\n\t\t\t\t\t\tawait sql\n\t\t\t\t\t\t\t.raw(\n\t\t\t\t\t\t\t\t`CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_${colName} ON ${qualifiedName} (${colName})`,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.execute(db);\n\t\t\t\t\t}\n\t\t\t\t\tif (col.search) {\n\t\t\t\t\t\tawait sql\n\t\t\t\t\t\t\t.raw(\n\t\t\t\t\t\t\t\t`CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_${colName}_trgm ON ${qualifiedName} USING gin (${colName} gin_trgm_ops)`,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.execute(db);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Add columns to existing tables\n\t\t\tfor (const [tableName, colDiff] of Object.entries(diff.tables)) {\n\t\t\t\tif (colDiff.added.length === 0) continue;\n\t\t\t\tconst qualifiedName = `${schemaName}.${tableName}`;\n\t\t\t\tconst tableDef = def.schema[tableName]!;\n\t\t\t\tfor (const colName of colDiff.added) {\n\t\t\t\t\tconst col = tableDef.columns[colName]!;\n\t\t\t\t\tconst sqlType = TYPE_MAP[col.type]!;\n\t\t\t\t\tconst nullable = col.nullable\n\t\t\t\t\t\t? \"\"\n\t\t\t\t\t\t: \" NOT NULL DEFAULT \" + getDefault(col.type);\n\t\t\t\t\tawait sql\n\t\t\t\t\t\t.raw(\n\t\t\t\t\t\t\t`ALTER TABLE ${qualifiedName} ADD COLUMN ${colName} ${sqlType}${nullable}`,\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.execute(db);\n\t\t\t\t\tif (col.indexed) {\n\t\t\t\t\t\tawait sql\n\t\t\t\t\t\t\t.raw(\n\t\t\t\t\t\t\t\t`CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_${colName} ON ${qualifiedName} (${colName})`,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.execute(db);\n\t\t\t\t\t}\n\t\t\t\t\tif (col.search) {\n\t\t\t\t\t\tawait sql\n\t\t\t\t\t\t\t.raw(\n\t\t\t\t\t\t\t\t`CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_${colName}_trgm ON ${qualifiedName} USING gin (${colName} gin_trgm_ops)`,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.execute(db);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst sg = await registerSubgraph(db, regData);\n\t\treturn { action: \"updated\", subgraphId: sg.id };\n\t}\n\n\t// New subgraph — execute all DDL\n\tfor (const stmt of statements) {\n\t\tawait sql.raw(stmt).execute(db);\n\t}\n\n\tconst sg = await registerSubgraph(db, regData);\n\treturn { action: \"created\", subgraphId: sg.id };\n}\n\nfunction getDefault(type: string): string {\n\tswitch (type) {\n\t\tcase \"text\":\n\t\tcase \"principal\":\n\t\t\treturn \"''\";\n\t\tcase \"uint\":\n\t\tcase \"int\":\n\t\t\treturn \"0\";\n\t\tcase \"boolean\":\n\t\t\treturn \"false\";\n\t\tcase \"timestamp\":\n\t\t\treturn \"NOW()\";\n\t\tcase \"jsonb\":\n\t\t\treturn \"'{}'\";\n\t\tdefault:\n\t\t\treturn \"''\";\n\t}\n}\n"
18
19
  ],
19
- "mappings": "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",
20
- "debugId": "B83B1361C4912AAD64756E2164756E21",
20
+ "mappings": ";;;;AAyFO,SAAS,SAAS,CAAC,QAAgC;AAAA,EACzD,IAAI,OAAO,UAAU;AAAA,IACpB,IAAI,OAAO;AAAA,MAAU,OAAO,GAAG,OAAO,aAAa,OAAO;AAAA,IAC1D,IAAI,OAAO;AAAA,MAAO,OAAO,GAAG,OAAO,aAAa,OAAO;AAAA,IACvD,OAAO,OAAO;AAAA,EACf;AAAA,EACA,IAAI,OAAO;AAAA,IAAM,OAAO,OAAO;AAAA,EAC/B,OAAO;AAAA;;;AChGR;AASO,IAAM,qBAAwC,EACnD,OAAO,EACP,IAAI,CAAC,EACL,IAAI,EAAE,EACN,MACA,qBACA,mFACD;AAEM,IAAM,mBAA0C,EAAE,KAAK;AAAA,EAC7D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,CAAC;AAEM,IAAM,uBAAkD,EAAE,OAAO;AAAA,EACvE,MAAM;AAAA,EACN,UAAU,EAAE,QAAQ,EAAE,SAAS;AAAA,EAC/B,SAAS,EAAE,QAAQ,EAAE,SAAS;AAAA,EAC9B,QAAQ,EAAE,QAAQ,EAAE,SAAS;AAAA,EAC7B,SAAS,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC,CAAC,EAAE,SAAS;AAClE,CAAC;AAEM,IAAM,sBAAgD,EAAE,OAAO;AAAA,EACrE,SAAS,EACP,OAAO,EAAE,OAAO,GAAG,oBAAoB,EACvC,OACA,CAAC,MAAM,OAAO,KAAK,CAAC,EAAE,SAAS,GAC/B,qCACD;AAAA,EACD,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,SAAS;AAAA,EAC/C,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,SAAS;AACnD,CAAC;AAEM,IAAM,uBAAiE,EAC5E,OAAO,EAAE,OAAO,GAAG,mBAAmB,EACtC,OACA,CAAC,MAAM,OAAO,KAAK,CAAC,EAAE,SAAS,GAC/B,qCACD;AAEM,IAAM,uBAAkD,EAC7D,OAAO;AAAA,EACP,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,EAC9B,OAAO,EAAE,OAAO,EAAE,SAAS;AAAA,EAC3B,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,EAC9B,MAAM,EAAE,OAAO,EAAE,SAAS;AAAA,EAC1B,WAAW,EAAE,OAAO,EAAE,SAAS;AAChC,CAAC,EACA,OACA,CAAC,MAAM,EAAE,YAAY,EAAE,MACvB,mDACD;AAEM,IAAM,2BAA0D,EAAE,OACxE;AAAA,EACC,MAAM;AAAA,EACN,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,EAC7B,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,EACjC,SAAS,EACP,MAAM,oBAAoB,EAC1B,IAAI,GAAG,+BAA+B;AAAA,EACxC,QAAQ;AAAA,EACR,UAAU,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,IAAI,CAAC;AACvC,CACD;AAKO,SAAS,0BAA0B,CAAC,KAAkC;AAAA,EAC5E,OAAO,yBAAyB,MAAM,GAAG;AAAA;;;ACnF1C;AACA;AA4BA,SAAS,kBAAkB,CAAC,MAAoB;AAAA,EAC/C,IAAI,CAAC,sBAAsB,KAAK,IAAI,GAAG;AAAA,IACtC,MAAM,IAAI,MAAM,wBAAwB,MAAM;AAAA,EAC/C;AAAA;AAAA;AAQM,MAAM,gBAAgB;AAAA,EACnB;AAAA,EACD;AAAA,EACS;AAAA,EACA;AAAA,EACA;AAAA,EACA,MAAiB,CAAC;AAAA,EAEnC,WAAW,CACV,IACA,cACA,gBACA,OACA,IACC;AAAA,IACD,KAAK,KAAK;AAAA,IACV,KAAK,eAAe;AAAA,IACpB,KAAK,iBAAiB;AAAA,IACtB,KAAK,QAAQ;AAAA,IACb,KAAK,MAAM;AAAA;AAAA,MAGR,EAAE,GAAW;AAAA,IAChB,OAAO,KAAK;AAAA;AAAA,EAIb,KAAK,CAAC,IAAkB;AAAA,IACvB,KAAK,MAAM;AAAA;AAAA,EAKZ,MAAM,CAAC,OAAe,KAAoC;AAAA,IACzD,KAAK,cAAc,KAAK;AAAA,IACxB,KAAK,IAAI,KAAK,EAAE,MAAM,UAAU,OAAO,MAAM,IAAI,CAAC;AAAA;AAAA,EAGnD,MAAM,CACL,OACA,OACA,KACO;AAAA,IACP,KAAK,cAAc,KAAK;AAAA,IACxB,KAAK,IAAI,KAAK,EAAE,MAAM,UAAU,OAAO,MAAM,OAAO,IAAI,CAAC;AAAA;AAAA,EAG1D,MAAM,CACL,OACA,KACA,KACO;AAAA,IACP,KAAK,cAAc,KAAK;AAAA,IACxB,MAAM,WAAW,KAAK,eAAe;AAAA,IACrC,MAAM,aAAa,OAAO,KAAK,GAAG;AAAA,IAGlC,MAAM,sBAAsB,SAAS,YAAY,KAChD,CAAC,OACA,GAAG,WAAW,WAAW,UACzB,GAAG,MAAM,CAAC,MAAM,WAAW,SAAS,CAAC,CAAC,CACxC;AAAA,IAEA,IAAI,qBAAqB;AAAA,MAExB,KAAK,IAAI,KAAK;AAAA,QACb,MAAM;AAAA,QACN;AAAA,QACA,MAAM,KAAK,QAAQ,KAAK,cAAc,WAAW;AAAA,MAClD,CAAC;AAAA,IACF,EAAO;AAAA,MAEN,OAAO,KACN,wEACA;AAAA,QACC;AAAA,QACA,MAAM;AAAA,MACP,CACD;AAAA,MACA,KAAK,IAAI,KAAK;AAAA,QACb,MAAM;AAAA,QACN;AAAA,QACA,MAAM;AAAA,aACF;AAAA,aACA;AAAA,UACH,uBAAuB;AAAA,UACvB,sBAAsB;AAAA,QACvB;AAAA,MACD,CAAC;AAAA;AAAA;AAAA,EAIH,MAAM,CAAC,OAAe,OAAsC;AAAA,IAC3D,KAAK,cAAc,KAAK;AAAA,IACxB,KAAK,IAAI,KAAK,EAAE,MAAM,UAAU,OAAO,MAAM,MAAM,CAAC;AAAA;AAAA,OAK/C,QAAO,CACZ,OACA,OAC0C;AAAA,IAC1C,KAAK,cAAc,KAAK;AAAA,IACxB,MAAM,iBAAiB,IAAI,KAAK,kBAAkB;AAAA,IAClD,QAAQ,WAAW,iBAAiB,KAAK;AAAA,IACzC,MAAM,QAAQ,iBAAiB,wBAAwB;AAAA,IACvD,QAAQ,SAAS,MAAM,IAAI,IAAI,KAAK,EAAE,QAAQ,KAAK,EAAE;AAAA,IACrD,MAAM,MAAO,KAAmC,MAAM;AAAA,IACtD,OAAO,MAAM,KAAK,UAAU,OAAO,GAAG,IAAI;AAAA;AAAA,OAGrC,SAAQ,CACb,OACA,OACqC;AAAA,IACrC,KAAK,cAAc,KAAK;AAAA,IACxB,MAAM,iBAAiB,IAAI,KAAK,kBAAkB;AAAA,IAClD,QAAQ,WAAW,iBAAiB,KAAK;AAAA,IACzC,MAAM,QAAQ,iBAAiB,wBAAwB;AAAA,IACvD,QAAQ,SAAS,MAAM,IAAI,IAAI,KAAK,EAAE,QAAQ,KAAK,EAAE;AAAA,IACrD,OAAQ,KAAmC,IAAI,CAAC,MAC/C,KAAK,UAAU,OAAO,CAAC,CACxB;AAAA;AAAA,EAIO,SAAS,CAChB,OACA,KAC0B;AAAA,IAC1B,MAAM,WAAW,KAAK,eAAe;AAAA,IACrC,IAAI,CAAC;AAAA,MAAU,OAAO;AAAA,IACtB,MAAM,SAAS,KAAK,IAAI;AAAA,IACxB,YAAY,KAAK,QAAQ,OAAO,QAAQ,SAAS,OAAO,GAAG;AAAA,MAC1D,KACE,IAAI,SAAS,UAAU,IAAI,SAAS,UACrC,OAAO,OAAO,SAAS,UACtB;AAAA,QACD,OAAO,OAAO,OAAO,OAAO,IAAc;AAAA,MAC3C;AAAA,IACD;AAAA,IACA,OAAO;AAAA;AAAA,MAMJ,UAAU,GAAW;AAAA,IACxB,OAAO,KAAK,IAAI;AAAA;AAAA,OAOX,MAAK,GAAoB;AAAA,IAC9B,IAAI,KAAK,IAAI,WAAW;AAAA,MAAG,OAAO;AAAA,IAElC,MAAM,aAAa,CAAC,GAAG,KAAK,GAAG;AAAA,IAC/B,KAAK,IAAI,SAAS;AAAA,IAElB,MAAM,aAAa,KAAK,gBAAgB,UAAU;AAAA,IAGlD,IAAI,mBAAmB,KAAK,IAAI;AAAA,MAC/B,WAAW,QAAQ,YAAY;AAAA,QAC9B,MAAM,IAAI,IAAI,IAAI,EAAE,QAAQ,KAAK,EAAE;AAAA,MACpC;AAAA,IACD,EAAO;AAAA,MACN,MAAO,KAAK,GAAwB,YAAY,EAAE,QAAQ,OAAO,OAAO;AAAA,QACvE,WAAW,QAAQ,YAAY;AAAA,UAC9B,MAAM,IAAI,IAAI,IAAI,EAAE,QAAQ,EAAE;AAAA,QAC/B;AAAA,OACA;AAAA;AAAA,IAGF,OAAO,WAAW;AAAA;AAAA,EAIX,aAAa,CAAC,IAMpB;AAAA,IACD,MAAM,aAAa,GAAG,KAAK;AAAA,IAC3B,MAAM,OAAO,KAAK,GAAG,KAAK;AAAA,IAC1B,OAAO,KAAK;AAAA,IACZ,OAAO,KAAK;AAAA,IACZ,OAAO,KAAK;AAAA,IAEZ,KAAK,gBAAgB,KAAK,MAAM;AAAA,IAChC,KAAK,SAAS,KAAK,IAAI;AAAA,IACvB,KAAK,cAAc;AAAA,IAEnB,MAAM,OAAO,OAAO,KAAK,IAAI;AAAA,IAC7B,KAAK,QAAQ,kBAAkB;AAAA,IAC/B,MAAM,OAAO,KAAK,IAAI,CAAC,MACtB,KAAK,OAAO,UAAU,UAAU,cAAc,KAAK,EAAE,CACtD;AAAA,IAGA,MAAM,WAAW,GAAG,GAAG,SAAS,CAAC,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,GAAG,KAAK,aAAa,CAAC,GAAG,UAAU,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI;AAAA,IAE9G,OAAO,EAAE,MAAM,MAAM,MAAM,YAAY,SAAS;AAAA;AAAA,EAIzC,eAAe,CAAC,KAA0B;AAAA,IACjD,MAAM,aAAuB,CAAC;AAAA,IAU9B,IAAI,eAAmC;AAAA,IACvC,IAAI,kBAAkB;AAAA,IAEtB,MAAM,mBAAmB,MAAM;AAAA,MAC9B,IAAI,CAAC;AAAA,QAAc;AAAA,MACnB,MAAM,iBAAiB,IAAI,KAAK,kBAAkB,aAAa;AAAA,MAC/D,MAAM,UAAU,aAAa,KAAK,IAAI,CAAC,MAAM,IAAI,IAAI,EAAE,KAAK,IAAI;AAAA,MAGhE,IAAI,OAAO,aAAa;AAAA,MACxB,IAAI,aAAa,cAAc,aAAa,WAAW,SAAS,GAAG;AAAA,QAClE,MAAM,aAAa,aAAa,WAAW,IAAI,CAAC,MAC/C,aAAc,KAAK,QAAQ,CAAC,CAC7B;AAAA,QACA,MAAM,OAAO,IAAI;AAAA,QACjB,SAAS,IAAI,EAAG,IAAI,KAAK,QAAQ,KAAK;AAAA,UACrC,MAAM,MAAM,WAAW,IAAI,CAAC,OAAO,KAAK,GAAG,GAAG,EAAE,KAAK,MAAI;AAAA,UACzD,KAAK,IAAI,KAAK,CAAC;AAAA,QAChB;AAAA,QACA,IAAI,KAAK,OAAO,KAAK,QAAQ;AAAA,UAC5B,OAAO,MAAM,KAAK,KAAK,OAAO,CAAC,EAAE,IAAI,CAAC,MAAM,KAAK,EAAE;AAAA,QACpD;AAAA,MACD;AAAA,MAEA,MAAM,aAAa,KAAK,IAAI,CAAC,MAAM,IAAI,EAAE,KAAK,IAAI,IAAI,EAAE,KAAK,IAAI;AAAA,MACjE,IAAI,OAAO,eAAe,mBAAmB,mBAAmB;AAAA,MAEhE,IAAI,aAAa,cAAc,aAAa,WAAW,SAAS,GAAG;AAAA,QAClE,MAAM,aAAa,aAAa,KAAK,OACpC,CAAC,MAAM,CAAC,aAAc,WAAY,SAAS,CAAC,KAAK,CAAC,EAAE,WAAW,GAAG,CACnE;AAAA,QACA,IAAI,WAAW,SAAS,GAAG;AAAA,UAC1B,MAAM,aAAa,WAAW,IAAI,CAAC,MAAM,IAAI,kBAAkB,IAAI;AAAA,UACnE,QAAQ,iBAAiB,aAAa,WAAW,IAAI,CAAC,MAAM,IAAI,IAAI,EAAE,KAAK,IAAI,oBAAoB,WAAW,KAAK,IAAI;AAAA,QACxH,EAAO;AAAA,UACN,QAAQ,iBAAiB,aAAa,WAAW,IAAI,CAAC,MAAM,IAAI,IAAI,EAAE,KAAK,IAAI;AAAA;AAAA,MAEjF;AAAA,MAEA,WAAW,KAAK,IAAI;AAAA,MACpB,eAAe;AAAA,MACf,kBAAkB;AAAA;AAAA,IAGnB,WAAW,MAAM,KAAK;AAAA,MACrB,MAAM,iBAAiB,IAAI,KAAK,kBAAkB,GAAG;AAAA,MAErD,IAAI,GAAG,SAAS,UAAU;AAAA,QACzB,QAAQ,MAAM,MAAM,YAAY,aAAa,KAAK,cAAc,EAAE;AAAA,QAElE,IAAI,aAAa,mBAAmB,cAAc;AAAA,UAEjD,aAAa,KAAK,KAAK,IAAI;AAAA,QAC5B,EAAO;AAAA,UAEN,iBAAiB;AAAA,UACjB,eAAe,EAAE,OAAO,GAAG,OAAO,MAAM,MAAM,CAAC,IAAI,GAAG,WAAW;AAAA,UACjE,kBAAkB;AAAA;AAAA,MAEpB,EAAO;AAAA,QAEN,iBAAiB;AAAA,QAEjB,IAAI,GAAG,SAAS,UAAU;AAAA,UACzB,MAAM,aAAa,OAAO,QAAQ,GAAG,GAAI;AAAA,UACzC,WAAW,QAAQ,EAAE,OAAO,mBAAmB,CAAC,CAAC;AAAA,UACjD,MAAM,aAAa,WAAW,IAC7B,EAAE,GAAG,OAAO,IAAI,QAAQ,cAAc,CAAC,GACxC;AAAA,UACA,QAAQ,WAAW,iBAAiB,GAAG,IAAI;AAAA,UAC3C,WAAW,KACV,UAAU,sBAAsB,WAAW,KAAK,IAAI,WAAW,QAChE;AAAA,QACD,EAAO,SAAI,GAAG,SAAS,UAAU;AAAA,UAChC,QAAQ,WAAW,iBAAiB,GAAG,IAAI;AAAA,UAC3C,WAAW,KAAK,eAAe,wBAAwB,QAAQ;AAAA,QAChE;AAAA;AAAA,IAEF;AAAA,IAGA,iBAAiB;AAAA,IAEjB,OAAO;AAAA;AAAA,EAGA,aAAa,CAAC,OAAqB;AAAA,IAC1C,IAAI,CAAC,KAAK,eAAe,QAAQ;AAAA,MAChC,MAAM,IAAI,MACT,UAAU,oDAAoD,OAAO,KAAK,KAAK,cAAc,EAAE,KAAK,IAAI,IACzG;AAAA,IACD;AAAA;AAEF;AAIA,SAAS,aAAa,CAAC,OAAwB;AAAA,EAC9C,IAAI,UAAU,QAAQ,UAAU;AAAA,IAAW,OAAO;AAAA,EAClD,IAAI,OAAO,UAAU,YAAY,OAAO,UAAU;AAAA,IACjD,OAAO,OAAO,KAAK;AAAA,EACpB,IAAI,OAAO,UAAU;AAAA,IAAW,OAAO,QAAQ,SAAS;AAAA,EACxD,IAAI,OAAO,UAAU;AAAA,IACpB,OAAO,IAAI,KAAK,UAAU,KAAK,EAAE,QAAQ,MAAM,IAAI;AAAA,EAEpD,OAAO,IAAI,OAAO,KAAK,EAAE,QAAQ,MAAM,IAAI;AAAA;AAG5C,SAAS,gBAAgB,CAAC,OAGxB;AAAA,EACD,MAAM,UAAU,OAAO,QAAQ,KAAK;AAAA,EACpC,IAAI,QAAQ,WAAW;AAAA,IAAG,OAAO,EAAE,QAAQ,QAAQ,QAAQ,CAAC,EAAE;AAAA,EAE9D,QAAQ,QAAQ,EAAE,OAAO,mBAAmB,CAAC,CAAC;AAAA,EAC9C,MAAM,QAAQ,QAAQ,IAAI,EAAE,GAAG,OAAO,IAAI,QAAQ,cAAc,CAAC,GAAG;AAAA,EACpE,OAAO,EAAE,QAAQ,MAAM,KAAK,OAAO,GAAG,QAAQ,CAAC,EAAE;AAAA;;;AC5XlD;AAMO,SAAS,kBAAkB,CAAC,KAAsB;AAAA,EACxD,IAAI;AAAA,IACH,MAAM,WAAW,IAAI,WAAW,IAAI,IAAI,IAAI,MAAM,CAAC,IAAI;AAAA,IACvD,MAAM,KAAK,cAAc,QAAQ;AAAA,IACjC,OAAO,SAAS,EAAE;AAAA,IACjB,MAAM;AAAA,IACP,OAAO;AAAA;AAAA;AAQF,SAAS,eAAe,CAAC,MAAwB;AAAA,EACvD,IAAI,OAAO,SAAS,YAAY,KAAK,WAAW,IAAI,KAAK,KAAK,SAAS,IAAI;AAAA,IAC1E,OAAO,mBAAmB,IAAI;AAAA,EAC/B;AAAA,EAEA,IAAI,MAAM,QAAQ,IAAI,GAAG;AAAA,IACxB,OAAO,KAAK,IAAI,eAAe;AAAA,EAChC;AAAA,EAEA,IAAI,OAAO,SAAS,YAAY,SAAS,MAAM;AAAA,IAC9C,MAAM,UAAmC,CAAC;AAAA,IAC1C,YAAY,KAAK,UAAU,OAAO,QAAQ,IAAI,GAAG;AAAA,MAChD,QAAQ,OAAO,gBAAgB,KAAK;AAAA,IACrC;AAAA,IACA,OAAO;AAAA,EACR;AAAA,EAEA,OAAO;AAAA;AAMD,SAAS,kBAAkB,CAAC,MAA2B;AAAA,EAC7D,OAAO,KAAK,IAAI,kBAAkB;AAAA;;;AC5CnC;AACA,mBAAS;AAOT,IAAM,0BAA0B;AAWhC,SAAS,cAAc,CAAC,UAA0C,KAAa;AAAA,EAC9E,OAAO,SAAS,QAAQ,SAAS,QAAQ;AAAA;AAW1C,eAAsB,WAAW,CAChC,UACA,SACA,KACA,MACqB;AAAA,EACrB,IAAI,YAAY;AAAA,EAChB,IAAI,SAAS;AAAA,EACb,MAAM,YAAY,MAAM,kBAAkB;AAAA,EAE1C,aAAa,IAAI,QAAQ,2BAAe,SAAS;AAAA,IAChD,MAAM,UAAU,eAAe,SAAS,UAAU,UAAS;AAAA,IAC3D,IAAI,CAAC,SAAS;AAAA,MACb,QAAO,KAAK,mCAAmC;AAAA,QAC9C,UAAU,SAAS;AAAA,QACnB;AAAA,QACA,MAAM,GAAG;AAAA,MACV,CAAC;AAAA,MACD;AAAA,IACD;AAAA,IAEA,IAAI,MAAM;AAAA,MACT,MAAM,GAAG;AAAA,MACT,QAAQ,GAAG;AAAA,MACX,MAAM,GAAG;AAAA,MACT,QAAQ,GAAG;AAAA,IACZ,CAAC;AAAA,IAGD,IAAI,OAAO,WAAW,GAAG;AAAA,MACxB,IAAI;AAAA,QACH,MAAM,YAAqC;AAAA,UAC1C,IAAI;AAAA,YACH,MAAM,GAAG;AAAA,YACT,QAAQ,GAAG;AAAA,YACX,MAAM,GAAG;AAAA,YACT,QAAQ,GAAG;AAAA,YACX,YAAY,GAAG;AAAA,YACf,cAAc,GAAG;AAAA,UAClB;AAAA,QACD;AAAA,QACA,MAAM,QAAQ,WAAW,GAAG;AAAA,QAC5B;AAAA,QACC,OAAO,KAAK;AAAA,QACb;AAAA,QACA,QAAO,MAAM,0BAA0B;AAAA,UACtC,UAAU,SAAS;AAAA,UACnB;AAAA,UACA,MAAM,GAAG;AAAA,UACT,OAAO,gBAAgB,GAAG;AAAA,QAC3B,CAAC;AAAA;AAAA,MAEF;AAAA,IACD;AAAA,IAEA,WAAW,SAAS,QAAQ;AAAA,MAC3B,IAAI,UAAU,WAAW;AAAA,QACxB,QAAO,MACN,+DACA;AAAA,UACC,UAAU,SAAS;AAAA,UACnB;AAAA,UACA;AAAA,QACD,CACD;AAAA,QACA,OAAO,EAAE,WAAW,OAAO;AAAA,MAC5B;AAAA,MAEA,IAAI;AAAA,QACH,MAAM,UAAU,gBAAgB,MAAM,IAAI;AAAA,QAC1C,MAAM,eAAwC;AAAA,aAC1C;AAAA,UACH,UAAU,MAAM;AAAA,UAChB,YAAY,MAAM;AAAA,UAClB,aAAa,MAAM;AAAA,UACnB,IAAI;AAAA,YACH,MAAM,GAAG;AAAA,YACT,QAAQ,GAAG;AAAA,YACX,MAAM,GAAG;AAAA,YACT,QAAQ,GAAG;AAAA,YACX,YAAY,GAAG;AAAA,YACf,cAAc,GAAG;AAAA,UAClB;AAAA,QACD;AAAA,QAEA,MAAM,QAAQ,cAAc,GAAG;AAAA,QAC/B;AAAA,QACC,OAAO,KAAK;AAAA,QACb;AAAA,QACA,QAAO,MAAM,0BAA0B;AAAA,UACtC,UAAU,SAAS;AAAA,UACnB;AAAA,UACA,MAAM,GAAG;AAAA,UACT,SAAS,MAAM;AAAA,UACf,WAAW,MAAM;AAAA,UACjB,OAAO,gBAAgB,GAAG;AAAA,QAC3B,CAAC;AAAA;AAAA,IAEH;AAAA,EACD;AAAA,EAEA,OAAO,EAAE,WAAW,OAAO;AAAA;;;AC3G5B,SAAS,YAAY,CAAC,OAAe,SAA0B;AAAA,EAC9D,IAAI,CAAC,QAAQ,SAAS,GAAG;AAAA,IAAG,OAAO,UAAU;AAAA,EAC7C,MAAM,QAAQ,QACZ,QAAQ,qBAAqB,MAAM,EACnC,QAAQ,OAAO,IAAI;AAAA,EACrB,OAAO,IAAI,OAAO,IAAI,QAAQ,EAAE,KAAK,KAAK;AAAA;AAsB3C,SAAS,WAAW,CACnB,QACA,cACA,YACc;AAAA,EACd,MAAM,UAAuB,CAAC;AAAA,EAC9B,MAAM,MAAM,UAAU,MAAM;AAAA,EAE5B,WAAW,MAAM,cAAc;AAAA,IAE9B,IAAI,OAAO,MAAM;AAAA,MAChB,IAAI,CAAC,aAAa,GAAG,MAAM,OAAO,IAAI;AAAA,QAAG;AAAA,MAEzC,MAAM,WAAW,WAAW,IAAI,GAAG,KAAK,KAAK,CAAC;AAAA,MAG9C,IAAI,gBAAgB;AAAA,MAGpB,IAAI,OAAO,cAAc,WAAW;AAAA,QACnC,MAAM,eAAe,cAAc,OAAO,CAAC,MAAM;AAAA,UAChD,MAAM,OAAO,EAAE;AAAA,UACf,MAAM,YAAY,MAAM;AAAA,UACxB,IAAI,cAAc;AAAA,YAAW,OAAO;AAAA,UACpC,MAAM,SAAS,OAAO,SAAS;AAAA,UAC/B,OAAO,UAAU,OAAO;AAAA,SACxB;AAAA,QACD,IAAI,aAAa,WAAW;AAAA,UAAG;AAAA,QAC/B,gBAAgB;AAAA,MACjB;AAAA,MAEA,QAAQ,KAAK,EAAE,IAAI,QAAQ,eAAe,WAAW,IAAI,CAAC;AAAA,MAC1D;AAAA,IACD;AAAA,IAGA,IAAI,OAAO,UAAU;AAAA,MACpB,MAAM,kBACL,GAAG,eAAe,aAAa,GAAG,aAAa,OAAO,QAAQ;AAAA,MAG/D,IAAI,OAAO,YAAY,GAAG,eAAe;AAAA,QACxC,IAAI,CAAC,aAAa,GAAG,eAAe,OAAO,QAAQ;AAAA,UAAG;AAAA,MACvD,EAAO,SAAI,OAAO,YAAY,CAAC,GAAG,eAAe;AAAA,QAChD;AAAA,MACD;AAAA,MAEA,MAAM,WAAW,WAAW,IAAI,GAAG,KAAK,KAAK,CAAC;AAAA,MAC9C,IAAI,gBAAgB;AAAA,MAEpB,IAAI,CAAC,iBAAiB;AAAA,QAErB,gBAAgB,SAAS,OAAO,CAAC,MAAM;AAAA,UACtC,MAAM,OAAO,EAAE;AAAA,UACf,MAAM,qBAAqB,MAAM;AAAA,UAGjC,OACC,sBACA,aAAa,oBAAoB,OAAO,QAAS;AAAA,SAElD;AAAA,QACD,IAAI,cAAc,WAAW;AAAA,UAAG;AAAA,MACjC;AAAA,MAGA,IAAI,OAAO,OAAO;AAAA,QACjB,gBAAgB,cAAc,OAAO,CAAC,MAAM;AAAA,UAC3C,IAAI,aAAa,EAAE,MAAM,OAAO,KAAM;AAAA,YAAG,OAAO;AAAA,UAChD,MAAM,OAAO,EAAE;AAAA,UACf,MAAM,QAAQ,MAAM;AAAA,UACpB,OAAO,QAAQ,aAAa,OAAO,OAAO,KAAM,IAAI;AAAA,SACpD;AAAA,MACF;AAAA,MAEA,IAAI,mBAAmB,cAAc,SAAS,GAAG;AAAA,QAChD,QAAQ,KAAK,EAAE,IAAI,QAAQ,eAAe,WAAW,IAAI,CAAC;AAAA,MAC3D;AAAA,IACD;AAAA,EACD;AAAA,EAEA,OAAO;AAAA;AAOD,SAAS,YAAY,CAC3B,SACA,cACA,QACc;AAAA,EAEd,MAAM,aAAa,IAAI;AAAA,EACvB,WAAW,SAAS,QAAQ;AAAA,IAC3B,MAAM,OAAO,WAAW,IAAI,MAAM,KAAK,KAAK,CAAC;AAAA,IAC7C,KAAK,KAAK,KAAK;AAAA,IACf,WAAW,IAAI,MAAM,OAAO,IAAI;AAAA,EACjC;AAAA,EAEA,MAAM,OAAO,IAAI;AAAA,EACjB,MAAM,UAAuB,CAAC;AAAA,EAE9B,WAAW,UAAU,SAAS;AAAA,IAC7B,MAAM,UAAU,YAAY,QAAQ,cAAc,UAAU;AAAA,IAC5D,WAAW,SAAS,SAAS;AAAA,MAC5B,MAAM,YAAY,GAAG,MAAM,GAAG,SAAS,MAAM;AAAA,MAC7C,IAAI,CAAC,KAAK,IAAI,SAAS,GAAG;AAAA,QACzB,KAAK,IAAI,SAAS;AAAA,QAClB,QAAQ,KAAK,KAAK;AAAA,MACnB;AAAA,IACD;AAAA,EACD;AAAA,EAEA,OAAO;AAAA;;;ACvKR;AACA;AAAA;AAAA;AAAA;AAIA,mBAAS;AACT,gBAA2B;;;ACL3B;;;ADaA,IAAM,kBAAkB,IAAI;AAwC5B,eAAsB,YAAY,CACjC,UACA,cACA,aACA,MAC8B;AAAA,EAC9B,MAAM,KAAK,MAAM;AAAA,EACjB,MAAM,aAAa,YAAY,IAAI;AAAA,EACnC,MAAM,SAA6B;AAAA,IAClC;AAAA,IACA,SAAS;AAAA,IACT,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,SAAS;AAAA,EACV;AAAA,EAGA,IAAI,OAAO,KAAK;AAAA,EAChB,IAAI,MAAM,WAAW;AAAA,IACpB,QAAQ,KAAK,UAAU;AAAA,IACvB,MAAM,KAAK,UAAU;AAAA,IACrB,OAAO,KAAK,UAAU;AAAA,EACvB,EAAO;AAAA,IACN,QAAQ,MAAM,GACZ,WAAW,QAAQ,EACnB,UAAU,EACV,MAAM,UAAU,KAAK,WAAW,EAChC,iBAAiB;AAAA,IAEnB,IAAI,CAAC,OAAO;AAAA,MACX,QAAO,KAAK,2CAA2C;AAAA,QACtD,UAAU;AAAA,QACV;AAAA,MACD,CAAC;AAAA,MACD,OAAO,UAAU;AAAA,MACjB,OAAO;AAAA,IACR;AAAA,IAEA,IAAI,CAAC,MAAM,WAAW;AAAA,MACrB,QAAO,MAAM,gCAAgC;AAAA,QAC5C,UAAU;AAAA,QACV;AAAA,MACD,CAAC;AAAA,MACD,OAAO,UAAU;AAAA,MACjB,OAAO;AAAA,IACR;AAAA,IAGA,MAAM,MAAM,GACV,WAAW,cAAc,EACzB,UAAU,EACV,MAAM,gBAAgB,KAAK,WAAW,EACtC,QAAQ;AAAA,IAEV,OAAO,MAAM,GACX,WAAW,QAAQ,EACnB,UAAU,EACV,MAAM,gBAAgB,KAAK,WAAW,EACtC,QAAQ;AAAA;AAAA,EAIX,MAAM,UAAU,aAAa,SAAS,SAAS,KAAK,IAAI;AAAA,EACxD,OAAO,UAAU,QAAQ;AAAA,EAEzB,IAAI,QAAQ,WAAW,GAAG;AAAA,IACzB,IAAI,CAAC,MAAM,oBAAoB;AAAA,MAC9B,MAAM,qBAAqB,IAAI,cAAc,UAAU,WAAW;AAAA,IACnE;AAAA,IACA,OAAO;AAAA,EACR;AAAA,EAIA,IAAI,aAAa,gBAAgB,IAAI,YAAY;AAAA,EACjD,IAAI,CAAC,YAAY;AAAA,IAChB,MAAM,iBAAiB,MAAM,GAC3B,WAAW,WAAW,EACtB,OAAO,aAAa,EACpB,MAAM,QAAQ,KAAK,YAAY,EAC/B,iBAAiB;AAAA,IACnB,aAAa,gBAAgB,eAAe,aAAa,YAAY;AAAA,IACrE,gBAAgB,IAAI,cAAc,UAAU;AAAA,EAC7C;AAAA,EACA,MAAM,YAAuB;AAAA,IAC5B,QAAQ,MAAM;AAAA,IACd,MAAM,MAAM;AAAA,IACZ,WAAW,MAAM;AAAA,IACjB,iBAAiB,MAAM;AAAA,EACxB;AAAA,EACA,MAAM,YAAoB;AAAA,IACzB,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,QAAQ;AAAA,EACT;AAAA,EAGA,IAAI,YAAY;AAAA,EAChB,IAAI,UAAU;AAAA,EAEd,MAAM,GAAG,YAAY,EAAE,QAAQ,OAAO,OAA8B;AAAA,IACnE,MAAM,MAAM,IAAI,gBACf,IACA,YACA,SAAS,QACT,WACA,SACD;AAAA,IAEA,MAAM,eAAe,YAAY,IAAI;AAAA,IACrC,MAAM,YAAY,MAAM,YAAY,UAAU,SAAS,GAAG;AAAA,IAC1D,YAAY,YAAY,IAAI,IAAI;AAAA,IAEhC,OAAO,YAAY,UAAU;AAAA,IAC7B,OAAO,SAAS,UAAU;AAAA,IAG1B,IAAI,IAAI,aAAa,GAAG;AAAA,MACvB,MAAM,aAAa,YAAY,IAAI;AAAA,MACnC,MAAM,IAAI,MAAM;AAAA,MAChB,UAAU,YAAY,IAAI,IAAI;AAAA,IAC/B;AAAA,IAGA,IAAI,CAAC,MAAM,oBAAoB;AAAA,MAC9B,MAAM,SACL,UAAU,SAAS,KAAK,UAAU,cAAc,IAAI,UAAU;AAAA,MAC/D,MAAM,qBAAqB,IAAI,cAAc,QAAQ,WAAW;AAAA,IACjE;AAAA,IAEA,IACC,CAAC,MAAM,uBACN,UAAU,YAAY,KAAK,UAAU,SAAS,IAC9C;AAAA,MACD,MAAM,YACL,UAAU,SAAS,IAChB,GAAG,UAAU,4BAA4B,gBACzC;AAAA,MACJ,MAAM,wBACL,IACA,cACA,UAAU,WACV,UAAU,QACV,SACD;AAAA,IACD;AAAA,GACA;AAAA,EAED,MAAM,UAAU,YAAY,IAAI,IAAI;AAAA,EACpC,OAAO,SAAS;AAAA,IACf,SAAS,KAAK,MAAM,OAAO;AAAA,IAC3B,WAAW,KAAK,MAAM,SAAS;AAAA,IAC/B,SAAS,KAAK,MAAM,OAAO;AAAA,EAC5B;AAAA,EAGA,IAAI,cAAc,SAAS,GAAG;AAAA,IAC7B,IAAI;AAAA,MACH,MAAM,SAAS,OAAO,KAAK,SAAS,MAAM;AAAA,MAC1C,WAAW,SAAS,QAAQ;AAAA,QAC3B,QAAQ,SAAS,MAAM,KACrB,IAAI,kCAAkC,gBAAgB,QAAQ,EAC9D,QAAQ,EAAE;AAAA,QACZ,MAAM,QAAQ,OAAQ,KAAK,GAA+B,KAAK;AAAA,QAC/D,IAAI,SAAS,KAAY;AAAA,UACxB,QAAO,KAAK,mCAAmC;AAAA,YAC9C,UAAU;AAAA,YACV;AAAA,YACA;AAAA,UACD,CAAC;AAAA,QACF;AAAA,MACD;AAAA,MACC,MAAM;AAAA,EAGT;AAAA,EAEA,OAAO;AAAA;;;AEtNR,IAAM,wBAAwB;AAC9B,IAAM,oBAAoB;AAAA;AAMnB,MAAM,iBAAiB;AAAA,EAKpB;AAAA,EACA;AAAA,EACA;AAAA,EAND;AAAA,EACA,YAAY,KAAK,IAAI;AAAA,EAE7B,WAAW,CACF,cACA,UACA,WACP;AAAA,IAHO;AAAA,IACA;AAAA,IACA;AAAA,IAER,KAAK,UAAU,KAAK,SAAS;AAAA;AAAA,EAG9B,MAAM,CAAC,QAA4B,UAAwB;AAAA,IAC1D,KAAK,QAAQ;AAAA,IACb,KAAK,QAAQ,eAAe,OAAO;AAAA,IACnC,KAAK,QAAQ,iBAAiB,OAAO;AAAA,IACrC,KAAK,QAAQ,eAAe,OAAO;AAAA,IACnC,KAAK,QAAQ,iBAAiB,KAAK,IAClC,KAAK,QAAQ,gBACb,OAAO,OACR;AAAA,IACA,KAAK,QAAQ,mBAAmB,KAAK,IACpC,KAAK,QAAQ,kBACb,OAAO,SACR;AAAA,IACA,KAAK,QAAQ,YAAY;AAAA;AAAA,EAG1B,WAAW,GAAY;AAAA,IACtB,OACC,KAAK,QAAQ,mBAAmB,yBAChC,KAAK,IAAI,IAAI,KAAK,aAAa;AAAA;AAAA,OAI3B,MAAK,CAAC,IAAqC;AAAA,IAChD,IAAI,KAAK,QAAQ,oBAAoB;AAAA,MAAG;AAAA,IAExC,MAAM,QAAQ,KAAK;AAAA,IACnB,KAAK,UAAU,KAAK,SAAS;AAAA,IAC7B,KAAK,YAAY,KAAK,IAAI;AAAA,IAE1B,MAAM,iBACL,MAAM,kBAAkB,IAAI,MAAM,WAAW,MAAM,kBAAkB;AAAA,IAEtE,MAAM,GACJ,WAAW,2BAA2B,EACtC,OAAO;AAAA,MACP,eAAe,MAAM;AAAA,MACrB,YAAY,MAAM;AAAA,MAClB,cAAc,MAAM;AAAA,MACpB,YAAY,IAAI;AAAA,MAChB,kBAAkB,MAAM;AAAA,MACxB,eAAe,KAAK,MAAM,MAAM,WAAW;AAAA,MAC3C,iBAAiB,KAAK,MAAM,MAAM,aAAa;AAAA,MAC/C,eAAe,KAAK,MAAM,MAAM,WAAW;AAAA,MAC3C,mBAAmB,KAAK,MAAM,MAAM,cAAc;AAAA,MAClD,qBAAqB,KAAK,MAAM,MAAM,gBAAgB;AAAA,MACtD,mBAAmB,OAAO,WAAW,eAAe,QAAQ,CAAC,CAAC;AAAA,MAC9D,YAAY,MAAM;AAAA,IACnB,CAAC,EACA,QAAQ;AAAA;AAAA,EAGH,QAAQ,GAAe;AAAA,IAC9B,OAAO;AAAA,MACN,cAAc,KAAK;AAAA,MACnB,UAAU,KAAK;AAAA,MACf,aAAa,IAAI;AAAA,MACjB,iBAAiB;AAAA,MACjB,aAAa;AAAA,MACb,eAAe;AAAA,MACf,aAAa;AAAA,MACb,gBAAgB;AAAA,MAChB,kBAAkB;AAAA,MAClB,UAAU;AAAA,MACV,WAAW,KAAK;AAAA,IACjB;AAAA;AAEF;;;ACxGA,4BAAS;AACT,kBAAS;AACT;AAAA;AAAA;AAAA;AAKA,iCAAS;AACT,mBAAS;;;ACLF,IAAM,WAAuC;AAAA,EACnD,MAAM;AAAA,EACN,MAAM;AAAA,EACN,KAAK;AAAA,EACL,WAAW;AAAA,EACX,SAAS;AAAA,EACT,WAAW;AAAA,EACX,OAAO;AACR;AAOA,SAAS,oBAAoB,CAAC,OAAwB;AAAA,EACrD,IAAI,UAAU,QAAQ,UAAU;AAAA,IAAW,OAAO;AAAA,EAClD,IAAI,OAAO,UAAU,YAAY,OAAO,UAAU;AAAA,IACjD,OAAO,OAAO,KAAK;AAAA,EACpB,IAAI,OAAO,UAAU;AAAA,IAAW,OAAO,QAAQ,SAAS;AAAA,EACxD,OAAO,IAAI,OAAO,KAAK,EAAE,QAAQ,MAAM,IAAI;AAAA;AAQrC,SAAS,mBAAmB,CAClC,KACA,oBACe;AAAA,EACf,MAAM,aAAa,sBAAsB,aAAa,IAAI,IAAI;AAAA,EAC9D,MAAM,aAAuB,CAAC;AAAA,EAG9B,MAAM,YAAY,OAAO,OAAO,IAAI,MAAM,EAAE,KAAK,CAAC,UACjD,OAAO,OAAO,MAAM,OAAO,EAAE,KAAK,CAAC,QAAQ,IAAI,MAAM,CACtD;AAAA,EAEA,IAAI,WAAW;AAAA,IACd,WAAW,KAAK,wCAAwC;AAAA,EACzD;AAAA,EAGA,WAAW,KAAK,+BAA+B,YAAY;AAAA,EAG3D,YAAY,WAAW,aAAa,OAAO,QAAQ,IAAI,MAAM,GAAG;AAAA,IAC/D,MAAM,gBAAgB,GAAG,cAAc;AAAA,IAGvC,MAAM,aAAuB;AAAA,MAC5B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACD;AAAA,IAEA,YAAY,SAAS,QAAQ,OAAO,QAAQ,SAAS,OAAO,GAAG;AAAA,MAC9D,MAAM,UAAU,SAAS,IAAI;AAAA,MAC7B,MAAM,WAAW,IAAI,WAAW,KAAK;AAAA,MACrC,IAAI,SAAS,GAAG,WAAW,UAAU;AAAA,MACrC,IAAI,IAAI,YAAY,WAAW;AAAA,QAC9B,UAAU,YAAY,qBAAqB,IAAI,OAAO;AAAA,MACvD;AAAA,MACA,WAAW,KAAK,MAAM;AAAA,IACvB;AAAA,IAEA,WAAW,KACV,8BAA8B;AAAA,IAAsB,WAAW,KAAK;AAAA,GAAO;AAAA,EAC5E;AAAA,IAGA,WAAW,KACV,kCAAkC,cAAc,6BAA6B,+BAC9E;AAAA,IACA,WAAW,KACV,kCAAkC,cAAc,sBAAsB,wBACvE;AAAA,IAGA,YAAY,SAAS,QAAQ,OAAO,QAAQ,SAAS,OAAO,GAAG;AAAA,MAC9D,IAAI,IAAI,SAAS;AAAA,QAChB,WAAW,KACV,kCAAkC,cAAc,aAAa,cAAc,kBAAkB,UAC9F;AAAA,MACD;AAAA,IACD;AAAA,IAGA,YAAY,SAAS,QAAQ,OAAO,QAAQ,SAAS,OAAO,GAAG;AAAA,MAC9D,IAAI,IAAI,QAAQ;AAAA,QACf,WAAW,KACV,kCAAkC,cAAc,aAAa,mBAAmB,4BAA4B,uBAC7G;AAAA,MACD;AAAA,IACD;AAAA,IAGA,IAAI,SAAS,SAAS;AAAA,MACrB,SAAS,IAAI,EAAG,IAAI,SAAS,QAAQ,QAAQ,KAAK;AAAA,QACjD,MAAM,OAAO,SAAS,QAAQ;AAAA,QAC9B,MAAM,UAAU,OAAO,cAAc,uBAAuB;AAAA,QAC5D,WAAW,KACV,8BAA8B,cAAc,kBAAkB,KAAK,KAAK,IAAI,IAC7E;AAAA,MACD;AAAA,IACD;AAAA,IAGA,IAAI,SAAS,YAAY;AAAA,MACxB,SAAS,IAAI,EAAG,IAAI,SAAS,WAAW,QAAQ,KAAK;AAAA,QACpD,MAAM,OAAO,SAAS,WAAW;AAAA,QACjC,MAAM,iBAAiB,MAAM,cAAc,aAAa,KAAK,KAAK,GAAG;AAAA,QACrE,WAAW,KACV,eAAe,gCAAgC,0BAA0B,KAAK,KAAK,IAAI,IACxF;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA,EAGA,MAAM,YAAY,KAAK,UACtB;AAAA,IACC,MAAM,IAAI;AAAA,IACV,SAAS,IAAI;AAAA,IACb,QAAQ,IAAI;AAAA,IACZ,SAAS,IAAI;AAAA,EACd,GACA,CAAC,MAAM,UAAW,OAAO,UAAU,WAAW,MAAM,SAAS,IAAI,KAClE;AAAA,EACA,MAAM,OAAO,OAAO,IAAI,KAAK,SAAS,CAAC;AAAA,EAEvC,OAAO,EAAE,YAAY,KAAK;AAAA;;;ACvH3B,eAAsB,cAAc,CACnC,IACA,YACA,UACkC;AAAA,EAClC,OAAO,QAAQ,KAAK,UAAU,MAAM,QAAQ,IAAI;AAAA,IAC/C,GACE,WAAW,QAAQ,EACnB,UAAU,EACV,MAAM,UAAU,MAAM,UAAU,EAChC,MAAM,UAAU,MAAM,QAAQ,EAC9B,MAAM,aAAa,KAAK,IAAI,EAC5B,QAAQ;AAAA,IACV,GACE,WAAW,cAAc,EACzB,UAAU,EACV,MAAM,gBAAgB,MAAM,UAAU,EACtC,MAAM,gBAAgB,MAAM,QAAQ,EACpC,QAAQ;AAAA,IACV,GACE,WAAW,QAAQ,EACnB,UAAU,EACV,MAAM,gBAAgB,MAAM,UAAU,EACtC,MAAM,gBAAgB,MAAM,QAAQ,EACpC,QAAQ;AAAA,EACX,CAAC;AAAA,EAGD,MAAM,cAAc,IAAI;AAAA,EACxB,WAAW,MAAM,KAAK;AAAA,IACrB,MAAM,IAAI,OAAO,GAAG,YAAY;AAAA,IAChC,MAAM,OAAO,YAAY,IAAI,CAAC,KAAK,CAAC;AAAA,IACpC,KAAK,KAAK,EAAE;AAAA,IACZ,YAAY,IAAI,GAAG,IAAI;AAAA,EACxB;AAAA,EAEA,MAAM,iBAAiB,IAAI;AAAA,EAC3B,WAAW,OAAO,QAAQ;AAAA,IACzB,MAAM,IAAI,OAAO,IAAI,YAAY;AAAA,IACjC,MAAM,OAAO,eAAe,IAAI,CAAC,KAAK,CAAC;AAAA,IACvC,KAAK,KAAK,GAAG;AAAA,IACb,eAAe,IAAI,GAAG,IAAI;AAAA,EAC3B;AAAA,EAEA,MAAM,SAAS,IAAI;AAAA,EACnB,WAAW,SAAS,QAAQ;AAAA,IAC3B,MAAM,IAAI,OAAO,MAAM,MAAM;AAAA,IAC7B,OAAO,IAAI,GAAG;AAAA,MACb;AAAA,MACA,KAAK,YAAY,IAAI,CAAC,KAAK,CAAC;AAAA,MAC5B,QAAQ,eAAe,IAAI,CAAC,KAAK,CAAC;AAAA,IACnC,CAAC;AAAA,EACF;AAAA,EAEA,OAAO;AAAA;AAOD,SAAS,iBAAiB,CAAC,OAAuC;AAAA,EACxE,IAAI,MAAM,SAAS;AAAA,IAAG,OAAO;AAAA,EAC7B,IAAI,cAAc;AAAA,EAClB,WAAW,QAAQ,MAAM,OAAO,GAAG;AAAA,IAClC,eAAe,KAAK,OAAO;AAAA,EAC5B;AAAA,EACA,OAAO,cAAc,MAAM;AAAA;;;AFrE5B,IAAM,eAAe;AACrB,IAAM,qBAAqB;AAC3B,IAAM,iBAAiB;AACvB,IAAM,iBAAiB;AAKvB,SAAS,oBAAoB,CAC5B,QACa;AAAA,EACb,IAAI,OAAO,WAAW;AAAA,IAAG,OAAO,CAAC;AAAA,EACjC,OAAO,KAAK,CAAC,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM;AAAA,EAEzC,MAAM,SAAqB,CAAC;AAAA,EAC5B,IAAI,QAAQ,OAAO,GAAG;AAAA,EACtB,IAAI,MAAM,OAAO,GAAG;AAAA,EACpB,IAAI,SAAS,OAAO,GAAG;AAAA,EAEvB,SAAS,IAAI,EAAG,IAAI,OAAO,QAAQ,KAAK;AAAA,IACvC,MAAM,IAAI,OAAO;AAAA,IACjB,IAAI,EAAE,WAAW,MAAM,KAAK,EAAE,WAAW,QAAQ;AAAA,MAChD,MAAM,EAAE;AAAA,IACT,EAAO;AAAA,MACN,OAAO,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;AAAA,MAClC,QAAQ,EAAE;AAAA,MACV,MAAM,EAAE;AAAA,MACR,SAAS,EAAE;AAAA;AAAA,EAEb;AAAA,EACA,OAAO,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;AAAA,EAClC,OAAO;AAAA;AAaR,eAAe,iBAAiB,CAC/B,KACA,MAYE;AAAA,EACF,MAAM,KAAK,OAAM;AAAA,EACjB,MAAM,eAAe,IAAI;AAAA,EACzB,QAAQ,WAAW,SAAS,WAAW;AAAA,EACvC,MAAM,cAAc,UAAU,YAAY;AAAA,EAE1C,MAAM,QAAQ,IAAI,iBACjB,cACA,KAAK,UACL,KAAK,SACN;AAAA,EACA,IAAI,kBAAkB;AAAA,EACtB,IAAI,uBAAuB;AAAA,EAC3B,IAAI,cAAc;AAAA,EAClB,IAAI,YAAY;AAAA,EAChB,IAAI,gBAAgB;AAAA,EAGpB,IAAI,mBAAmB,eACtB,IACA,eACA,KAAK,IAAI,gBAAgB,YAAY,GAAG,OAAO,CAChD;AAAA,EAEA,OAAO,iBAAiB,SAAS;AAAA,IAChC,MAAM,QAAQ,MAAM;AAAA,IACpB,MAAM,WAAW,KAAK,IAAI,gBAAgB,YAAY,GAAG,OAAO;AAAA,IAGhE,MAAM,YAAY,WAAW;AAAA,IAC7B,IAAI,aAAa,SAAS;AAAA,MACzB,MAAM,UAAU,KAAK,IAAI,YAAY,YAAY,GAAG,OAAO;AAAA,MAC3D,mBAAmB,eAAe,IAAI,WAAW,OAAO;AAAA,IACzD;AAAA,IAEA,MAAM,oBAA0D,CAAC;AAAA,IAEjE,SAAS,SAAS,cAAe,UAAU,UAAU,UAAU;AAAA,MAC9D,MAAM,YAAY,MAAM,IAAI,MAAM;AAAA,MAClC,IAAI,CAAC,WAAW;AAAA,QACf,kBAAkB,KAAK,EAAE,QAAQ,QAAQ,gBAAgB,CAAC;AAAA,QAC1D;AAAA,QACA;AAAA,MACD;AAAA,MAEA,IAAI;AAAA,MACJ,IAAI;AAAA,QACH,SAAS,MAAM,aAAa,KAAK,cAAc,QAAQ;AAAA,UACtD,oBAAoB;AAAA,UACpB,WAAW;AAAA,QACZ,CAAC;AAAA,QACA,OAAO,KAAK;AAAA,QACb,QAAO,MAAM,0BAA0B;AAAA,UACtC,UAAU;AAAA,UACV,aAAa;AAAA,UACb,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,QACvD,CAAC;AAAA,QACD,kBAAkB,KAAK,EAAE,QAAQ,QAAQ,mBAAmB,CAAC;AAAA,QAC7D,MAAM,sBAAqB,IAAI,cAAc,QAAQ,MAAM,EAAE,MAC5D,MAAM,EACP;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA;AAAA,MAGD;AAAA,MACA,wBAAwB,OAAO;AAAA,MAC/B,eAAe,OAAO;AAAA,MAEtB,IAAI,OAAO,QAAQ;AAAA,QAClB,MAAM,OAAO,OAAO,QAAQ,OAAO,SAAS;AAAA,QAC5C,IAAI,MAAM,YAAY,GAAG;AAAA,UACxB,MAAM,MAAM,MAAM,EAAE;AAAA,QACrB;AAAA,MACD;AAAA,MAGA,IAAI,kBAAkB,QAAQ,GAAG;AAAA,QAChC,MAAM,sBAAqB,IAAI,cAAc,QAAQ,MAAM;AAAA,MAC5D;AAAA,MAEA,IAAI,kBAAkB,iBAAiB,GAAG;AAAA,QACzC,QAAO,KACN,GAAG,WAAW,eAAe,YAAY,uBACzC;AAAA,UACC,UAAU;AAAA,UACV,WAAW;AAAA,UACX,OAAO;AAAA,UACP,cAAc;AAAA,UACd,KAAK,KAAK,MAAO,kBAAkB,cAAe,GAAG;AAAA,QACtD,CACD;AAAA,MACD;AAAA,IACD;AAAA,IAGA,IAAI,kBAAkB,SAAS,KAAK,KAAK,YAAY;AAAA,MACpD,MAAM,OAAO,qBAAqB,iBAAiB;AAAA,MACnD,MAAM,eAAe,IAAI,KAAK,YAAY,cAAc,IAAI,EAAE,MAC7D,CAAC,QAAiB;AAAA,QACjB,QAAO,KAAK,kCAAkC;AAAA,UAC7C,UAAU;AAAA,UACV,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,QACvD,CAAC;AAAA,OAEH;AAAA,IACD;AAAA,IAGA,MAAM,MAAM,kBAAkB,KAAK;AAAA,IACnC,IAAI,MAAM;AAAA,MACT,YAAY,KAAK,IAAI,KAAK,MAAM,YAAY,GAAG,GAAG,cAAc;AAAA,IAC5D,SAAI,MAAM;AAAA,MACd,YAAY,KAAK,IAAI,KAAK,MAAM,YAAY,GAAG,GAAG,cAAc;AAAA,IAEjE,gBAAgB,WAAW;AAAA,EAC5B;AAAA,EAEA,MAAM,MAAM,MAAM,EAAE;AAAA,EACpB,OAAO,EAAE,iBAAiB,sBAAsB,YAAY;AAAA;AAM7D,eAAe,iBAAiB,CAC/B,IACA,MACkD;AAAA,EAClD,MAAM,YAAY,MAAM,aAAa;AAAA,EACrC,IAAI;AAAA,EAEJ,IAAI,MAAM,WAAW,MAAM;AAAA,IAC1B,UAAU,KAAK;AAAA,EAChB,EAAO;AAAA,IACN,MAAM,WAAW,MAAM,GACrB,WAAW,gBAAgB,EAC3B,UAAU,EACV,MAAM,WAAW,KAAK,QAAQ,IAAI,WAAW,SAAS,EACtD,iBAAiB;AAAA,IACnB,UACC,UAAU,sBAAsB,UAAU,yBAAyB;AAAA;AAAA,EAGrE,OAAO,EAAE,WAAW,QAAQ;AAAA;AAO7B,eAAsB,eAAe,CACpC,KACA,MACiC;AAAA,EACjC,MAAM,KAAK,OAAM;AAAA,EACjB,MAAM,SAAS,aAAa;AAAA,EAC5B,MAAM,eAAe,IAAI;AAAA,EACzB,MAAM,aAAa,MAAM,cAAc,aAAa,YAAY;AAAA,EAEhE,MAAM,sBAAqB,IAAI,cAAc,YAAY;AAAA,EACzD,QAAO,KAAK,oBAAoB,EAAE,UAAU,aAAa,CAAC;AAAA,EAE1D,IAAI;AAAA,IAEH,MAAM,OAAO,OAAO,0BAA0B,qBAAqB;AAAA,IACnE,QAAQ,eAAe,oBAAoB,KAAK,UAAU;AAAA,IAC1D,WAAW,QAAQ,YAAY;AAAA,MAC9B,MAAM,OAAO,OAAO,IAAI;AAAA,IACzB;AAAA,IACA,QAAO,KAAK,gCAAgC,EAAE,UAAU,aAAa,CAAC;AAAA,IAEtE,QAAQ,WAAW,YAAY,MAAM,kBAAkB,IAAI,IAAI;AAAA,IAE/D,IAAI,YAAY,SAAS;AAAA,MACxB,QAAO,KAAK,wBAAwB;AAAA,QACnC,UAAU;AAAA,QACV;AAAA,QACA;AAAA,MACD,CAAC;AAAA,MACD,MAAM,sBAAqB,IAAI,cAAc,UAAU,CAAC;AAAA,MACxD,OAAO,EAAE,WAAW,EAAE;AAAA,IACvB;AAAA,IAEA,QAAO,KAAK,qBAAqB;AAAA,MAChC,UAAU;AAAA,MACV;AAAA,MACA;AAAA,MACA,aAAa,UAAU,YAAY;AAAA,IACpC,CAAC;AAAA,IAED,MAAM,cAAc,MAAM,GACxB,WAAW,WAAW,EACtB,OAAO,CAAC,MAAM,YAAY,CAAC,EAC3B,MAAM,QAAQ,KAAK,YAAY,EAC/B,iBAAiB;AAAA,IAEnB,MAAM,SAAS,MAAM,kBAAkB,KAAK;AAAA,MAC3C;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,UAAU,aAAa,cAAc;AAAA,MACrC,YAAY,aAAa;AAAA,IAC1B,CAAC;AAAA,IAGD,QAAQ,sDAA4B,MACnC;AAAA,IAED,IAAI,OAAO,uBAAuB,KAAK,OAAO,cAAc,GAAG;AAAA,MAC9D,MAAM,yBACL,IACA,cACA,OAAO,sBACP,OAAO,aACP,OAAO,cAAc,IAClB,GAAG,OAAO,wCACV,SACJ;AAAA,IACD;AAAA,IAEA,MAAM,sBAAqB,IAAI,cAAc,UAAU,OAAO;AAAA,IAC9D,QAAO,KAAK,oBAAoB;AAAA,MAC/B,UAAU;AAAA,MACV,QAAQ,OAAO;AAAA,MACf,QAAQ,OAAO;AAAA,MACf,QAAQ,OAAO;AAAA,IAChB,CAAC;AAAA,IACD,OAAO,EAAE,WAAW,OAAO,gBAAgB;AAAA,IAC1C,OAAO,KAAK;AAAA,IACb,QAAO,MAAM,kBAAkB;AAAA,MAC9B,UAAU;AAAA,MACV,OAAO,iBAAgB,GAAG;AAAA,IAC3B,CAAC;AAAA,IACD,MAAM,sBAAqB,IAAI,cAAc,OAAO;AAAA,IACpD,MAAM;AAAA;AAAA;AASR,eAAsB,gBAAgB,CACrC,KACA,MACiC;AAAA,EACjC,MAAM,KAAK,OAAM;AAAA,EACjB,MAAM,eAAe,IAAI;AAAA,EAEzB,QAAO,KAAK,qBAAqB;AAAA,IAChC,UAAU;AAAA,IACV,MAAM,KAAK;AAAA,IACX,IAAI,KAAK;AAAA,EACV,CAAC;AAAA,EAED,IAAI;AAAA,IACH,MAAM,cAAc,MAAM,GACxB,WAAW,WAAW,EACtB,OAAO,CAAC,MAAM,YAAY,CAAC,EAC3B,MAAM,QAAQ,KAAK,YAAY,EAC/B,iBAAiB;AAAA,IAEnB,MAAM,SAAS,MAAM,kBAAkB,KAAK;AAAA,MAC3C,WAAW,KAAK;AAAA,MAChB,SAAS,KAAK;AAAA,MACd,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,UAAU,aAAa,cAAc;AAAA,MACrC,YAAY,aAAa;AAAA,IAC1B,CAAC;AAAA,IAGD,MAAM,WAAW,MAAM,YACtB,IACA,cACA,KAAK,WACL,KAAK,OACN,EAAE,MAAM,MAAM,CAAC;AAAA,IACf,IAAI,WAAW,GAAG;AAAA,MACjB,QAAO,KAAK,uCAAuC;AAAA,QAClD,UAAU;AAAA,QACV;AAAA,MACD,CAAC;AAAA,IACF;AAAA,IAGA,QAAQ,sDAA4B,MACnC;AAAA,IAED,IAAI,OAAO,uBAAuB,KAAK,OAAO,cAAc,GAAG;AAAA,MAC9D,MAAM,yBACL,IACA,cACA,OAAO,sBACP,OAAO,aACP,OAAO,cAAc,IAClB,GAAG,OAAO,yCACV,SACJ;AAAA,IACD;AAAA,IAEA,QAAO,KAAK,qBAAqB;AAAA,MAChC,UAAU;AAAA,MACV,QAAQ,OAAO;AAAA,MACf,QAAQ,OAAO;AAAA,MACf,QAAQ,OAAO;AAAA,IAChB,CAAC;AAAA,IACD,OAAO,EAAE,WAAW,OAAO,gBAAgB;AAAA,IAC1C,OAAO,KAAK;AAAA,IACb,QAAO,MAAM,mBAAmB;AAAA,MAC/B,UAAU;AAAA,MACV,OAAO,iBAAgB,GAAG;AAAA,IAC3B,CAAC;AAAA,IACD,MAAM;AAAA;AAAA;;AGpXD,SAAS,cAAwC,CACvD,KACqD;AAAA,EACrD,OAAO;AAAA;;ACrBR,gBAAsB;AAStB,SAAS,UAAU,CAAC,KAAuB;AAAA,EAC1C,OAAO,KAAK,MACX,KAAK,UAAU,KAAK,CAAC,MAAM,UAC1B,OAAO,UAAU,WAAW,MAAM,SAAS,IAAI,KAChD,CACD;AAAA;AAqBM,SAAS,UAAU,CACzB,UACA,UACY;AAAA,EACZ,MAAM,iBAAiB,IAAI,IAAI,OAAO,KAAK,QAAQ,CAAC;AAAA,EACpD,MAAM,iBAAiB,IAAI,IAAI,OAAO,KAAK,QAAQ,CAAC;AAAA,EAEpD,MAAM,cAAc,CAAC,GAAG,cAAc,EAAE,OAAO,CAAC,MAAM,CAAC,eAAe,IAAI,CAAC,CAAC;AAAA,EAC5E,MAAM,gBAAgB,CAAC,GAAG,cAAc,EAAE,OACzC,CAAC,MAAM,CAAC,eAAe,IAAI,CAAC,CAC7B;AAAA,EAEA,MAAM,SAAqC,CAAC;AAAA,EAC5C,WAAW,aAAa,gBAAgB;AAAA,IACvC,IAAI,CAAC,eAAe,IAAI,SAAS;AAAA,MAAG;AAAA,IACpC,MAAM,eAAe,SAAS,WAAY;AAAA,IAC1C,MAAM,eAAe,SAAS,WAAY;AAAA,IAE1C,MAAM,eAAe,IAAI,IAAI,OAAO,KAAK,YAAY,CAAC;AAAA,IACtD,MAAM,eAAe,IAAI,IAAI,OAAO,KAAK,YAAY,CAAC;AAAA,IAEtD,OAAO,aAAa;AAAA,MACnB,OAAO,CAAC,GAAG,YAAY,EAAE,OAAO,CAAC,MAAM,CAAC,aAAa,IAAI,CAAC,CAAC;AAAA,MAC3D,SAAS,CAAC,GAAG,YAAY,EAAE,OAAO,CAAC,MAAM,CAAC,aAAa,IAAI,CAAC,CAAC;AAAA,MAC7D,SAAS,CAAC,GAAG,YAAY,EAAE,OAAO,CAAC,MAAM;AAAA,QACxC,IAAI,CAAC,aAAa,IAAI,CAAC;AAAA,UAAG,OAAO;AAAA,QACjC,OACC,KAAK,UAAU,aAAa,EAAE,MAAM,KAAK,UAAU,aAAa,EAAE;AAAA,OAEnE;AAAA,IACF;AAAA,EACD;AAAA,EAEA,OAAO,EAAE,aAAa,eAAe,OAAO;AAAA;AAO7C,SAAS,kBAAkB,CAAC,MAG1B;AAAA,EACD,MAAM,UAAoB,CAAC;AAAA,EAC3B,IAAI,KAAK,cAAc,SAAS,GAAG;AAAA,IAClC,QAAQ,KAAK,oBAAoB,KAAK,cAAc,KAAK,IAAI,IAAI;AAAA,EAClE;AAAA,EACA,YAAY,OAAO,YAAY,OAAO,QAAQ,KAAK,MAAM,GAAG;AAAA,IAC3D,IAAI,QAAQ,QAAQ,SAAS,GAAG;AAAA,MAC/B,QAAQ,KAAK,GAAG,2BAA2B,QAAQ,QAAQ,KAAK,IAAI,IAAI;AAAA,IACzE;AAAA,IACA,IAAI,QAAQ,QAAQ,SAAS,GAAG;AAAA,MAC/B,QAAQ,KAAK,GAAG,2BAA2B,QAAQ,QAAQ,KAAK,IAAI,IAAI;AAAA,IACzE;AAAA,EACD;AAAA,EACA,OAAO,EAAE,UAAU,QAAQ,SAAS,GAAG,QAAQ;AAAA;AAUhD,eAAsB,YAAY,CACjC,IACA,KACA,aACA,MAIE;AAAA,EACF,2BAA2B,GAAG;AAAA,EAE9B,QAAQ,YAAY,SAAS,oBAAoB,KAAK,MAAM,UAAU;AAAA,EACtE,QAAQ,aAAa,qBAAqB,MACzC;AAAA,EAGD,MAAM,WAAW,MAAM,YAAY,IAAI,IAAI,MAAM,MAAM,QAAQ;AAAA,EAE/D,MAAM,aAAa,MAAM,cAAc,aAAa,IAAI,IAAI;AAAA,EAC5D,MAAM,UAAU;AAAA,IACf,MAAM,IAAI;AAAA,IACV,SAAS,IAAI,WAAW;AAAA,IACxB,YAAY,WAAW;AAAA,MACtB,MAAM,IAAI;AAAA,MACV,SAAS,IAAI;AAAA,MACb,aAAa,IAAI;AAAA,MACjB,SAAS,IAAI;AAAA,MACb,QAAQ,IAAI;AAAA,IACb,CAAC;AAAA,IACD,YAAY;AAAA,IACZ;AAAA,IACA,UAAU,MAAM;AAAA,IAChB;AAAA,EACD;AAAA,EAEA,IAAI,UAAU;AAAA,IACb,IAAI,SAAS,gBAAgB,QAAQ,CAAC,MAAM,cAAc;AAAA,MAEzD,QAAQ,8BAA8B,MACrC;AAAA,MAED,MAAM,0BAA0B,IAAI,IAAI,MAAM,WAAW;AAAA,MACzD,OAAO,EAAE,QAAQ,aAAa,YAAY,SAAS,GAAG;AAAA,IACvD;AAAA,IAEA,IAAI,SAAS,gBAAgB,QAAQ,MAAM,cAAc;AAAA,MAExD,MAAM,KACJ,IAAI,0BAA0B,qBAAqB,EACnD,QAAQ,EAAE;AAAA,MACZ,WAAW,QAAQ,YAAY;AAAA,QAC9B,MAAM,KAAI,IAAI,IAAI,EAAE,QAAQ,EAAE;AAAA,MAC/B;AAAA,MACA,MAAM,MAAK,MAAM,iBAAiB,IAAI,OAAO;AAAA,MAC7C,OAAO,EAAE,QAAQ,aAAa,YAAY,IAAG,GAAG;AAAA,IACjD;AAAA,IAEA,IAAI,SAAS,WAAW,QAAQ;AAAA,MAC/B,MAAM,OAAO,WACZ,SAAS,WAAW,QACpB,IAAI,MACL;AAAA,MACA,QAAQ,UAAU,YAAY,mBAAmB,IAAI;AAAA,MAErD,IAAI,UAAU;AAAA,QACb,IAAI,CAAC,MAAM,cAAc;AAAA,UACxB,MAAM,IAAI,MACT,oCAAoC,QAAQ,KAAK,IAAI,mEAEtD;AAAA,QACD;AAAA,QAGA,MAAM,KACJ,IAAI,0BAA0B,qBAAqB,EACnD,QAAQ,EAAE;AAAA,QACZ,WAAW,QAAQ,YAAY;AAAA,UAC9B,MAAM,KAAI,IAAI,IAAI,EAAE,QAAQ,EAAE;AAAA,QAC/B;AAAA,QACA,MAAM,MAAK,MAAM,iBAAiB,IAAI,OAAO;AAAA,QAC7C,OAAO,EAAE,QAAQ,aAAa,YAAY,IAAG,GAAG;AAAA,MACjD;AAAA,MAGA,WAAW,aAAa,KAAK,aAAa;AAAA,QACzC,MAAM,WAAW,IAAI,OAAO;AAAA,QAC5B,MAAM,gBAAgB,GAAG,cAAc;AAAA,QACvC,MAAM,UAAU;AAAA,UACf;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACD;AAAA,QACA,YAAY,SAAS,QAAQ,OAAO,QAAQ,SAAS,OAAO,GAAG;AAAA,UAC9D,MAAM,WAAW,IAAI,WAAW,KAAK;AAAA,UACrC,QAAQ,KAAK,GAAG,WAAW,SAAS,IAAI,QAAS,UAAU;AAAA,QAC5D;AAAA,QACA,MAAM,KACJ,IACA,8BAA8B;AAAA,IAAsB,QAAQ,KAAK;AAAA,GAAO;AAAA,EACzE,EACC,QAAQ,EAAE;AAAA,QACZ,MAAM,KACJ,IACA,kCAAkC,cAAc,6BAA6B,+BAC9E,EACC,QAAQ,EAAE;AAAA,QACZ,MAAM,KACJ,IACA,kCAAkC,cAAc,sBAAsB,wBACvE,EACC,QAAQ,EAAE;AAAA,QACZ,YAAY,SAAS,QAAQ,OAAO,QAAQ,SAAS,OAAO,GAAG;AAAA,UAC9D,IAAI,IAAI,SAAS;AAAA,YAChB,MAAM,KACJ,IACA,kCAAkC,cAAc,aAAa,cAAc,kBAAkB,UAC9F,EACC,QAAQ,EAAE;AAAA,UACb;AAAA,UACA,IAAI,IAAI,QAAQ;AAAA,YACf,MAAM,KACJ,IACA,kCAAkC,cAAc,aAAa,mBAAmB,4BAA4B,uBAC7G,EACC,QAAQ,EAAE;AAAA,UACb;AAAA,QACD;AAAA,MACD;AAAA,MAGA,YAAY,WAAW,YAAY,OAAO,QAAQ,KAAK,MAAM,GAAG;AAAA,QAC/D,IAAI,QAAQ,MAAM,WAAW;AAAA,UAAG;AAAA,QAChC,MAAM,gBAAgB,GAAG,cAAc;AAAA,QACvC,MAAM,WAAW,IAAI,OAAO;AAAA,QAC5B,WAAW,WAAW,QAAQ,OAAO;AAAA,UACpC,MAAM,MAAM,SAAS,QAAQ;AAAA,UAC7B,MAAM,UAAU,SAAS,IAAI;AAAA,UAC7B,MAAM,WAAW,IAAI,WAClB,KACA,uBAAuB,WAAW,IAAI,IAAI;AAAA,UAC7C,MAAM,KACJ,IACA,eAAe,4BAA4B,WAAW,UAAU,UACjE,EACC,QAAQ,EAAE;AAAA,UACZ,IAAI,IAAI,SAAS;AAAA,YAChB,MAAM,KACJ,IACA,kCAAkC,cAAc,aAAa,cAAc,kBAAkB,UAC9F,EACC,QAAQ,EAAE;AAAA,UACb;AAAA,UACA,IAAI,IAAI,QAAQ;AAAA,YACf,MAAM,KACJ,IACA,kCAAkC,cAAc,aAAa,mBAAmB,4BAA4B,uBAC7G,EACC,QAAQ,EAAE;AAAA,UACb;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAAA,IAEA,MAAM,MAAK,MAAM,iBAAiB,IAAI,OAAO;AAAA,IAC7C,OAAO,EAAE,QAAQ,WAAW,YAAY,IAAG,GAAG;AAAA,EAC/C;AAAA,EAGA,WAAW,QAAQ,YAAY;AAAA,IAC9B,MAAM,KAAI,IAAI,IAAI,EAAE,QAAQ,EAAE;AAAA,EAC/B;AAAA,EAEA,MAAM,KAAK,MAAM,iBAAiB,IAAI,OAAO;AAAA,EAC7C,OAAO,EAAE,QAAQ,WAAW,YAAY,GAAG,GAAG;AAAA;AAG/C,SAAS,UAAU,CAAC,MAAsB;AAAA,EACzC,QAAQ;AAAA,SACF;AAAA,SACA;AAAA,MACJ,OAAO;AAAA,SACH;AAAA,SACA;AAAA,MACJ,OAAO;AAAA,SACH;AAAA,MACJ,OAAO;AAAA,SACH;AAAA,MACJ,OAAO;AAAA,SACH;AAAA,MACJ,OAAO;AAAA;AAAA,MAEP,OAAO;AAAA;AAAA;",
21
+ "debugId": "5A0D359BE0D619B264756E2164756E21",
21
22
  "names": []
22
23
  }
@@ -69,6 +69,7 @@ interface SubgraphDefinition {
69
69
  /** Keyed handler functions — keys match sourceKey() output, "*" is catch-all */
70
70
  handlers: Record<string, SubgraphHandler>;
71
71
  }
72
+ import { Transaction } from "kysely";
72
73
  interface ProcessBlockTiming {
73
74
  totalMs: number;
74
75
  handlerMs: number;
@@ -92,9 +93,16 @@ interface ProcessBlockResult {
92
93
  * 4. Flush context (commit writes atomically)
93
94
  * 5. Update subgraph.last_processed_block
94
95
  */
96
+ interface PreloadedBlockData {
97
+ block: import("@secondlayer/shared/db").Block;
98
+ txs: import("@secondlayer/shared/db").Transaction[];
99
+ events: import("@secondlayer/shared/db").Event[];
100
+ }
95
101
  interface ProcessBlockOptions {
96
102
  /** Skip updating last_processed_block in DB (reindex batches this externally). */
97
103
  skipProgressUpdate?: boolean;
104
+ /** Pre-loaded block data — skips DB reads when provided (used by batch catch-up). */
105
+ preloaded?: PreloadedBlockData;
98
106
  }
99
107
  declare function processBlock(subgraph: SubgraphDefinition, subgraphName: string, blockHeight: number, opts?: ProcessBlockOptions): Promise<ProcessBlockResult>;
100
- export { processBlock, ProcessBlockTiming, ProcessBlockResult, ProcessBlockOptions };
108
+ export { processBlock, ProcessBlockTiming, ProcessBlockResult, ProcessBlockOptions, PreloadedBlockData };