@secondlayer/shared 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/crypto/hmac.js +2 -2
- package/dist/src/crypto/hmac.js.map +3 -3
- package/dist/src/db/index.d.ts +18 -3
- package/dist/src/db/index.js +6 -2
- package/dist/src/db/index.js.map +4 -4
- package/dist/src/db/jsonb.js.map +2 -2
- package/dist/src/db/queries/accounts.d.ts +16 -3
- package/dist/src/db/queries/accounts.js +6 -3
- package/dist/src/db/queries/accounts.js.map +3 -3
- package/dist/src/db/queries/integrity.d.ts +15 -2
- package/dist/src/db/queries/integrity.js.map +2 -2
- package/dist/src/db/queries/metrics.d.ts +15 -2
- package/dist/src/db/queries/metrics.js.map +2 -2
- package/dist/src/db/queries/subgraph-gaps.d.ts +305 -0
- package/dist/src/db/queries/subgraph-gaps.js +103 -0
- package/dist/src/db/queries/subgraph-gaps.js.map +10 -0
- package/dist/src/db/queries/subgraphs.d.ts +15 -2
- package/dist/src/db/queries/subgraphs.js +2 -2
- package/dist/src/db/queries/subgraphs.js.map +4 -4
- package/dist/src/db/queries/usage.d.ts +23 -3
- package/dist/src/db/queries/usage.js +35 -3
- package/dist/src/db/queries/usage.js.map +4 -4
- package/dist/src/db/schema.d.ts +18 -3
- package/dist/src/env.js.map +2 -2
- package/dist/src/errors.d.ts +17 -4
- package/dist/src/errors.js +14 -2
- package/dist/src/errors.js.map +3 -3
- package/dist/src/index.d.ts +78 -6
- package/dist/src/index.js +26 -8
- package/dist/src/index.js.map +12 -12
- package/dist/src/lib/plans.js.map +2 -2
- package/dist/src/logger.js.map +3 -3
- package/dist/src/node/archive-client.js +22 -6
- package/dist/src/node/archive-client.js.map +5 -5
- package/dist/src/node/client.js.map +2 -2
- package/dist/src/node/hiro-client.js +47 -11
- package/dist/src/node/hiro-client.js.map +5 -5
- package/dist/src/node/hiro-pg-client.js +131 -26
- package/dist/src/node/hiro-pg-client.js.map +3 -3
- package/dist/src/node/local-client.d.ts +15 -2
- package/dist/src/node/local-client.js.map +2 -2
- package/dist/src/queue/index.js +8 -4
- package/dist/src/queue/index.js.map +5 -5
- package/dist/src/queue/listener.js.map +2 -2
- package/dist/src/queue/recovery.js +6 -2
- package/dist/src/queue/recovery.js.map +5 -5
- package/dist/src/schemas/filters.js +2 -2
- package/dist/src/schemas/filters.js.map +3 -3
- package/dist/src/schemas/index.d.ts +45 -1
- package/dist/src/schemas/index.js +5 -3
- package/dist/src/schemas/index.js.map +5 -5
- package/dist/src/schemas/subgraphs.d.ts +45 -1
- package/dist/src/schemas/subgraphs.js.map +2 -2
- package/dist/src/types.d.ts +1 -1
- package/migrations/0001_initial.ts +295 -159
- package/migrations/0002_api_keys.ts +44 -28
- package/migrations/0003_tenant_isolation.ts +116 -107
- package/migrations/0004_accounts_and_usage.ts +81 -75
- package/migrations/0005_sessions.ts +33 -33
- package/migrations/0006_tx_index.ts +6 -2
- package/migrations/0007_contracts.ts +38 -24
- package/migrations/0008_drop_contracts.ts +33 -19
- package/migrations/0009_waitlist.ts +12 -12
- package/migrations/0010_waitlist_status.ts +5 -5
- package/migrations/0011_account_insights.ts +52 -52
- package/migrations/0012_view_health_snapshots.ts +21 -21
- package/migrations/0013_view_processing_stats.ts +32 -32
- package/migrations/0014_view_table_snapshots.ts +24 -24
- package/migrations/0015_rename_views_to_subgraphs.ts +137 -75
- package/migrations/0016_rename_webhook_to_endpoint.ts +12 -4
- package/migrations/0017_security_hardening.ts +32 -0
- package/migrations/0018_subgraph_gaps.ts +39 -0
- package/package.json +147 -143
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/node/hiro-pg-client.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"/**\n * Direct Postgres client for reading from a local Hiro API database.\n *\n * Bypasses the Hiro HTTP API entirely — queries the stacks_blockchain_api\n * schema directly. Orders of magnitude faster for bulk backfill since we\n * avoid per-tx HTTP round-trips and the API's slow UNION event queries.\n *\n * Expects HIRO_PG_URL env var pointing to the Hiro API database, e.g.:\n * postgres://secondlayer:pass@localhost:5432/stacks_blockchain_api\n */\n\nimport postgres from \"postgres\";\n\nconst SCHEMA = \"stacks_blockchain_api\";\n\n// Hiro DB stores bytea; we need 0x-prefixed hex strings\nfunction toHex(buf: Buffer | Uint8Array | null): string {\n if (!buf) return \"0x\";\n return \"0x\" + Buffer.from(buf).toString(\"hex\");\n}\n\n// asset_event_type_id mapping: 1=transfer, 2=mint, 3=burn\nfunction stxEventType(assetTypeId: number): string {\n switch (assetTypeId) {\n case 1: return \"stx_transfer_event\";\n case 2: return \"stx_mint_event\";\n case 3: return \"stx_burn_event\";\n default: return \"stx_transfer_event\";\n }\n}\n\nfunction ftEventType(assetTypeId: number): string {\n switch (assetTypeId) {\n case 1: return \"ft_transfer_event\";\n case 2: return \"ft_mint_event\";\n case 3: return \"ft_burn_event\";\n default: return \"ft_transfer_event\";\n }\n}\n\nfunction nftEventType(assetTypeId: number): string {\n switch (assetTypeId) {\n case 1: return \"nft_transfer_event\";\n case 2: return \"nft_mint_event\";\n case 3: return \"nft_burn_event\";\n default: return \"nft_transfer_event\";\n }\n}\n\n// Hiro tx type_id mapping\nfunction mapTxTypeId(typeId: number): string {\n switch (typeId) {\n case 0: return \"token_transfer\";\n case 1: return \"smart_contract\";\n case 2: return \"contract_call\";\n case 3: return \"poison_microblock\";\n case 4: return \"coinbase\";\n case 5: return \"coinbase\"; // coinbase-pay-to-alt\n case 6: return \"smart_contract\"; // versioned\n case 7: return \"tenure_change\";\n case 8: return \"coinbase\"; // nakamoto coinbase\n default: return \"token_transfer\";\n }\n}\n\n// Hiro tx status mapping\nfunction mapTxStatus(status: number): string {\n switch (status) {\n case 1: return \"success\";\n case 0: return \"abort_by_response\";\n default: return \"abort_by_post_condition\";\n }\n}\n\ninterface BlockRow {\n block_hash: Buffer;\n block_height: number;\n index_block_hash: Buffer;\n parent_block_hash: Buffer;\n parent_index_block_hash: Buffer;\n burn_block_hash: Buffer;\n burn_block_height: number;\n burn_block_time: number;\n block_time: number;\n miner_txid: Buffer;\n}\n\ninterface TxRow {\n tx_id: Buffer;\n tx_index: number;\n type_id: number;\n status: number;\n sender_address: string;\n raw_tx: Buffer;\n event_count: number;\n contract_call_contract_id: string | null;\n contract_call_function_name: string | null;\n smart_contract_contract_id: string | null;\n}\n\nexport class HiroPgClient {\n private sql: ReturnType<typeof postgres>;\n\n constructor(connectionUrl?: string) {\n const url = connectionUrl || process.env.HIRO_PG_URL;\n if (!url) throw new Error(\"HIRO_PG_URL is required for HiroPgClient\");\n this.sql = postgres(url, {\n max: 10,\n idle_timeout: 30,\n });\n }\n\n async getChainTip(): Promise<number> {\n const rows = await this.sql`\n SELECT MAX(block_height) as tip FROM ${this.sql(SCHEMA)}.blocks WHERE canonical = true\n `;\n return Number(rows[0]?.tip ?? 0);\n }\n\n /**\n * Fetch a complete block by height directly from PG.\n * Returns data in the same NewBlockPayload shape the backfill expects.\n */\n async getBlockForIndexer(height: number, options?: { includeRawTx?: boolean }): Promise<any | null> {\n // 1. Block metadata\n const blocks = await this.sql<BlockRow[]>`\n SELECT block_hash, block_height, index_block_hash, parent_block_hash,\n parent_index_block_hash, burn_block_hash, burn_block_height,\n burn_block_time, block_time, miner_txid\n FROM ${this.sql(SCHEMA)}.blocks\n WHERE block_height = ${height} AND canonical = true\n LIMIT 1\n `;\n if (blocks.length === 0) return null;\n const block = blocks[0];\n\n // 2. Transactions\n const txs = await this.sql<TxRow[]>`\n SELECT tx_id, tx_index, type_id, status, sender_address, raw_tx, event_count,\n contract_call_contract_id, contract_call_function_name, smart_contract_contract_id\n FROM ${this.sql(SCHEMA)}.txs\n WHERE block_height = ${height} AND canonical = true AND microblock_canonical = true\n ORDER BY tx_index\n `;\n\n const transactions = txs.map((tx) => {\n const txType = mapTxTypeId(tx.type_id);\n const entry: any = {\n txid: toHex(tx.tx_id),\n raw_tx: options?.includeRawTx ? toHex(tx.raw_tx) : \"0x00\",\n status: mapTxStatus(tx.status),\n tx_index: tx.tx_index,\n tx_type: txType,\n sender_address: tx.sender_address,\n };\n if (txType === \"contract_call\" && tx.contract_call_contract_id) {\n entry.contract_call = {\n contract_id: tx.contract_call_contract_id,\n function_name: tx.contract_call_function_name || \"\",\n };\n } else if (txType === \"smart_contract\" && tx.smart_contract_contract_id) {\n entry.smart_contract = {\n contract_id: tx.smart_contract_contract_id,\n };\n }\n return entry;\n });\n\n // 3. Events — query all event tables by block_height (fast, indexed)\n const events: any[] = [];\n\n // STX events\n const stxEvents = await this.sql`\n SELECT tx_id, event_index, asset_event_type_id, amount, sender, recipient, memo\n FROM ${this.sql(SCHEMA)}.stx_events\n WHERE block_height = ${height} AND canonical = true AND microblock_canonical = true\n ORDER BY event_index\n `;\n for (const e of stxEvents) {\n const type = stxEventType(e.asset_event_type_id);\n const evt: any = { txid: toHex(e.tx_id), event_index: e.event_index, committed: true, type };\n if (type === \"stx_transfer_event\") {\n evt.stx_transfer_event = {\n sender: e.sender || \"\",\n recipient: e.recipient || \"\",\n amount: String(e.amount),\n ...(e.memo ? { memo: toHex(e.memo) } : {}),\n };\n } else if (type === \"stx_mint_event\") {\n evt.stx_mint_event = { recipient: e.recipient || \"\", amount: String(e.amount) };\n } else if (type === \"stx_burn_event\") {\n evt.stx_burn_event = { sender: e.sender || \"\", amount: String(e.amount) };\n }\n events.push(evt);\n }\n\n // STX lock events\n const lockEvents = await this.sql`\n SELECT tx_id, event_index, locked_amount, unlock_height, locked_address\n FROM ${this.sql(SCHEMA)}.stx_lock_events\n WHERE block_height = ${height} AND canonical = true AND microblock_canonical = true\n ORDER BY event_index\n `;\n for (const e of lockEvents) {\n events.push({\n txid: toHex(e.tx_id),\n event_index: e.event_index,\n committed: true,\n type: \"stx_lock_event\",\n stx_lock_event: {\n locked_amount: String(e.locked_amount),\n unlock_height: String(e.unlock_height),\n locked_address: e.locked_address,\n },\n });\n }\n\n // FT events\n const ftEvents = await this.sql`\n SELECT tx_id, event_index, asset_event_type_id, asset_identifier, amount, sender, recipient\n FROM ${this.sql(SCHEMA)}.ft_events\n WHERE block_height = ${height} AND canonical = true AND microblock_canonical = true\n ORDER BY event_index\n `;\n for (const e of ftEvents) {\n const type = ftEventType(e.asset_event_type_id);\n const evt: any = { txid: toHex(e.tx_id), event_index: e.event_index, committed: true, type };\n if (type === \"ft_transfer_event\") {\n evt.ft_transfer_event = {\n asset_identifier: e.asset_identifier,\n sender: e.sender || \"\",\n recipient: e.recipient || \"\",\n amount: String(e.amount),\n };\n } else if (type === \"ft_mint_event\") {\n evt.ft_mint_event = { asset_identifier: e.asset_identifier, recipient: e.recipient || \"\", amount: String(e.amount) };\n } else if (type === \"ft_burn_event\") {\n evt.ft_burn_event = { asset_identifier: e.asset_identifier, sender: e.sender || \"\", amount: String(e.amount) };\n }\n events.push(evt);\n }\n\n // NFT events\n const nftEvents = await this.sql`\n SELECT tx_id, event_index, asset_event_type_id, asset_identifier, value, sender, recipient\n FROM ${this.sql(SCHEMA)}.nft_events\n WHERE block_height = ${height} AND canonical = true AND microblock_canonical = true\n ORDER BY event_index\n `;\n for (const e of nftEvents) {\n const type = nftEventType(e.asset_event_type_id);\n const evt: any = { txid: toHex(e.tx_id), event_index: e.event_index, committed: true, type };\n const val = toHex(e.value);\n if (type === \"nft_transfer_event\") {\n evt.nft_transfer_event = { asset_identifier: e.asset_identifier, sender: e.sender || \"\", recipient: e.recipient || \"\", value: val };\n } else if (type === \"nft_mint_event\") {\n evt.nft_mint_event = { asset_identifier: e.asset_identifier, recipient: e.recipient || \"\", value: val };\n } else if (type === \"nft_burn_event\") {\n evt.nft_burn_event = { asset_identifier: e.asset_identifier, sender: e.sender || \"\", value: val };\n }\n events.push(evt);\n }\n\n // Contract log events\n const logEvents = await this.sql`\n SELECT tx_id, event_index, contract_identifier, topic, value\n FROM ${this.sql(SCHEMA)}.contract_logs\n WHERE block_height = ${height} AND canonical = true AND microblock_canonical = true\n ORDER BY event_index\n `;\n for (const e of logEvents) {\n events.push({\n txid: toHex(e.tx_id),\n event_index: e.event_index,\n committed: true,\n type: \"smart_contract_event\",\n smart_contract_event: {\n contract_identifier: e.contract_identifier,\n topic: e.topic,\n value: toHex(e.value),\n },\n });\n }\n\n return {\n block_hash: toHex(block.block_hash),\n block_height: block.block_height,\n index_block_hash: toHex(block.index_block_hash),\n parent_block_hash: toHex(block.parent_block_hash),\n parent_index_block_hash: toHex(block.parent_index_block_hash),\n burn_block_hash: toHex(block.burn_block_hash),\n burn_block_height: block.burn_block_height,\n burn_block_timestamp: block.burn_block_time,\n miner_txid: toHex(block.miner_txid),\n timestamp: block.block_time,\n transactions,\n events,\n };\n }\n\n /**\n * Fetch multiple blocks in bulk — 6 queries total instead of 6 per block.\n * Returns array of NewBlockPayload in height order.\n */\n async getBlockBatch(heights: number[], options?: { includeRawTx?: boolean }): Promise<any[]> {\n if (heights.length === 0) return [];\n\n // 1. All blocks in range\n const blocks = await this.sql`\n SELECT block_hash, block_height, index_block_hash, parent_block_hash,\n parent_index_block_hash, burn_block_hash, burn_block_height,\n burn_block_time, block_time, miner_txid\n FROM ${this.sql(SCHEMA)}.blocks\n WHERE block_height = ANY(${heights}) AND canonical = true\n `;\n\n if (blocks.length === 0) return [];\n const blockMap = new Map<number, any>();\n for (const b of blocks) {\n blockMap.set(b.block_height, { ...b, transactions: [], events: [] });\n }\n\n // 2. All transactions\n const txs = await this.sql`\n SELECT tx_id, tx_index, type_id, status, sender_address, raw_tx, event_count, block_height,\n contract_call_contract_id, contract_call_function_name, smart_contract_contract_id\n FROM ${this.sql(SCHEMA)}.txs\n WHERE block_height = ANY(${heights}) AND canonical = true AND microblock_canonical = true\n ORDER BY block_height, tx_index\n `;\n for (const tx of txs) {\n const block = blockMap.get(tx.block_height);\n if (!block) continue;\n const txType = mapTxTypeId(tx.type_id);\n const entry: any = {\n txid: toHex(tx.tx_id),\n raw_tx: options?.includeRawTx ? toHex(tx.raw_tx) : \"0x00\",\n status: mapTxStatus(tx.status),\n tx_index: tx.tx_index,\n tx_type: txType,\n sender_address: tx.sender_address,\n };\n if (txType === \"contract_call\" && tx.contract_call_contract_id) {\n entry.contract_call = { contract_id: tx.contract_call_contract_id, function_name: tx.contract_call_function_name || \"\" };\n } else if (txType === \"smart_contract\" && tx.smart_contract_contract_id) {\n entry.smart_contract = { contract_id: tx.smart_contract_contract_id };\n }\n block.transactions.push(entry);\n }\n\n // 3. STX events\n const stxEvents = await this.sql`\n SELECT tx_id, event_index, asset_event_type_id, amount, sender, recipient, memo, block_height\n FROM ${this.sql(SCHEMA)}.stx_events\n WHERE block_height = ANY(${heights}) AND canonical = true AND microblock_canonical = true\n `;\n for (const e of stxEvents) {\n const block = blockMap.get(e.block_height);\n if (!block) continue;\n const type = stxEventType(e.asset_event_type_id);\n const evt: any = { txid: toHex(e.tx_id), event_index: e.event_index, committed: true, type };\n if (type === \"stx_transfer_event\") {\n evt.stx_transfer_event = { sender: e.sender || \"\", recipient: e.recipient || \"\", amount: String(e.amount), ...(e.memo ? { memo: toHex(e.memo) } : {}) };\n } else if (type === \"stx_mint_event\") {\n evt.stx_mint_event = { recipient: e.recipient || \"\", amount: String(e.amount) };\n } else if (type === \"stx_burn_event\") {\n evt.stx_burn_event = { sender: e.sender || \"\", amount: String(e.amount) };\n }\n block.events.push(evt);\n }\n\n // 4. STX lock events\n const lockEvents = await this.sql`\n SELECT tx_id, event_index, locked_amount, unlock_height, locked_address, block_height\n FROM ${this.sql(SCHEMA)}.stx_lock_events\n WHERE block_height = ANY(${heights}) AND canonical = true AND microblock_canonical = true\n `;\n for (const e of lockEvents) {\n const block = blockMap.get(e.block_height);\n if (!block) continue;\n block.events.push({\n txid: toHex(e.tx_id), event_index: e.event_index, committed: true, type: \"stx_lock_event\",\n stx_lock_event: { locked_amount: String(e.locked_amount), unlock_height: String(e.unlock_height), locked_address: e.locked_address },\n });\n }\n\n // 5. FT events\n const ftEvents = await this.sql`\n SELECT tx_id, event_index, asset_event_type_id, asset_identifier, amount, sender, recipient, block_height\n FROM ${this.sql(SCHEMA)}.ft_events\n WHERE block_height = ANY(${heights}) AND canonical = true AND microblock_canonical = true\n `;\n for (const e of ftEvents) {\n const block = blockMap.get(e.block_height);\n if (!block) continue;\n const type = ftEventType(e.asset_event_type_id);\n const evt: any = { txid: toHex(e.tx_id), event_index: e.event_index, committed: true, type };\n if (type === \"ft_transfer_event\") {\n evt.ft_transfer_event = { asset_identifier: e.asset_identifier, sender: e.sender || \"\", recipient: e.recipient || \"\", amount: String(e.amount) };\n } else if (type === \"ft_mint_event\") {\n evt.ft_mint_event = { asset_identifier: e.asset_identifier, recipient: e.recipient || \"\", amount: String(e.amount) };\n } else if (type === \"ft_burn_event\") {\n evt.ft_burn_event = { asset_identifier: e.asset_identifier, sender: e.sender || \"\", amount: String(e.amount) };\n }\n block.events.push(evt);\n }\n\n // 6. NFT events\n const nftEvents = await this.sql`\n SELECT tx_id, event_index, asset_event_type_id, asset_identifier, value, sender, recipient, block_height\n FROM ${this.sql(SCHEMA)}.nft_events\n WHERE block_height = ANY(${heights}) AND canonical = true AND microblock_canonical = true\n `;\n for (const e of nftEvents) {\n const block = blockMap.get(e.block_height);\n if (!block) continue;\n const type = nftEventType(e.asset_event_type_id);\n const evt: any = { txid: toHex(e.tx_id), event_index: e.event_index, committed: true, type };\n const val = toHex(e.value);\n if (type === \"nft_transfer_event\") {\n evt.nft_transfer_event = { asset_identifier: e.asset_identifier, sender: e.sender || \"\", recipient: e.recipient || \"\", value: val };\n } else if (type === \"nft_mint_event\") {\n evt.nft_mint_event = { asset_identifier: e.asset_identifier, recipient: e.recipient || \"\", value: val };\n } else if (type === \"nft_burn_event\") {\n evt.nft_burn_event = { asset_identifier: e.asset_identifier, sender: e.sender || \"\", value: val };\n }\n block.events.push(evt);\n }\n\n // 7. Contract log events\n const logEvents = await this.sql`\n SELECT tx_id, event_index, contract_identifier, topic, value, block_height\n FROM ${this.sql(SCHEMA)}.contract_logs\n WHERE block_height = ANY(${heights}) AND canonical = true AND microblock_canonical = true\n `;\n for (const e of logEvents) {\n const block = blockMap.get(e.block_height);\n if (!block) continue;\n block.events.push({\n txid: toHex(e.tx_id), event_index: e.event_index, committed: true, type: \"smart_contract_event\",\n smart_contract_event: { contract_identifier: e.contract_identifier, topic: e.topic, value: toHex(e.value) },\n });\n }\n\n // Build results in height order\n return heights\n .filter((h) => blockMap.has(h))\n .map((h) => {\n const b = blockMap.get(h)!;\n return {\n block_hash: toHex(b.block_hash),\n block_height: b.block_height,\n index_block_hash: toHex(b.index_block_hash),\n parent_block_hash: toHex(b.parent_block_hash),\n parent_index_block_hash: toHex(b.parent_index_block_hash),\n burn_block_hash: toHex(b.burn_block_hash),\n burn_block_height: b.burn_block_height,\n burn_block_timestamp: b.burn_block_time,\n miner_txid: toHex(b.miner_txid),\n timestamp: b.block_time,\n transactions: b.transactions,\n events: b.events,\n };\n });\n }\n\n async close(): Promise<void> {\n await this.sql.end();\n }\n}\n"
|
|
5
|
+
"/**\n * Direct Postgres client for reading from a local Hiro API database.\n *\n * Bypasses the Hiro HTTP API entirely — queries the stacks_blockchain_api\n * schema directly. Orders of magnitude faster for bulk backfill since we\n * avoid per-tx HTTP round-trips and the API's slow UNION event queries.\n *\n * Expects HIRO_PG_URL env var pointing to the Hiro API database, e.g.:\n * postgres://secondlayer:pass@localhost:5432/stacks_blockchain_api\n */\n\nimport postgres from \"postgres\";\n\nconst SCHEMA = \"stacks_blockchain_api\";\n\n// Hiro DB stores bytea; we need 0x-prefixed hex strings\nfunction toHex(buf: Buffer | Uint8Array | null): string {\n\tif (!buf) return \"0x\";\n\treturn \"0x\" + Buffer.from(buf).toString(\"hex\");\n}\n\n// asset_event_type_id mapping: 1=transfer, 2=mint, 3=burn\nfunction stxEventType(assetTypeId: number): string {\n\tswitch (assetTypeId) {\n\t\tcase 1:\n\t\t\treturn \"stx_transfer_event\";\n\t\tcase 2:\n\t\t\treturn \"stx_mint_event\";\n\t\tcase 3:\n\t\t\treturn \"stx_burn_event\";\n\t\tdefault:\n\t\t\treturn \"stx_transfer_event\";\n\t}\n}\n\nfunction ftEventType(assetTypeId: number): string {\n\tswitch (assetTypeId) {\n\t\tcase 1:\n\t\t\treturn \"ft_transfer_event\";\n\t\tcase 2:\n\t\t\treturn \"ft_mint_event\";\n\t\tcase 3:\n\t\t\treturn \"ft_burn_event\";\n\t\tdefault:\n\t\t\treturn \"ft_transfer_event\";\n\t}\n}\n\nfunction nftEventType(assetTypeId: number): string {\n\tswitch (assetTypeId) {\n\t\tcase 1:\n\t\t\treturn \"nft_transfer_event\";\n\t\tcase 2:\n\t\t\treturn \"nft_mint_event\";\n\t\tcase 3:\n\t\t\treturn \"nft_burn_event\";\n\t\tdefault:\n\t\t\treturn \"nft_transfer_event\";\n\t}\n}\n\n// Hiro tx type_id mapping\nfunction mapTxTypeId(typeId: number): string {\n\tswitch (typeId) {\n\t\tcase 0:\n\t\t\treturn \"token_transfer\";\n\t\tcase 1:\n\t\t\treturn \"smart_contract\";\n\t\tcase 2:\n\t\t\treturn \"contract_call\";\n\t\tcase 3:\n\t\t\treturn \"poison_microblock\";\n\t\tcase 4:\n\t\t\treturn \"coinbase\";\n\t\tcase 5:\n\t\t\treturn \"coinbase\"; // coinbase-pay-to-alt\n\t\tcase 6:\n\t\t\treturn \"smart_contract\"; // versioned\n\t\tcase 7:\n\t\t\treturn \"tenure_change\";\n\t\tcase 8:\n\t\t\treturn \"coinbase\"; // nakamoto coinbase\n\t\tdefault:\n\t\t\treturn \"token_transfer\";\n\t}\n}\n\n// Hiro tx status mapping\nfunction mapTxStatus(status: number): string {\n\tswitch (status) {\n\t\tcase 1:\n\t\t\treturn \"success\";\n\t\tcase 0:\n\t\t\treturn \"abort_by_response\";\n\t\tdefault:\n\t\t\treturn \"abort_by_post_condition\";\n\t}\n}\n\ninterface BlockRow {\n\tblock_hash: Buffer;\n\tblock_height: number;\n\tindex_block_hash: Buffer;\n\tparent_block_hash: Buffer;\n\tparent_index_block_hash: Buffer;\n\tburn_block_hash: Buffer;\n\tburn_block_height: number;\n\tburn_block_time: number;\n\tblock_time: number;\n\tminer_txid: Buffer;\n}\n\ninterface TxRow {\n\ttx_id: Buffer;\n\ttx_index: number;\n\ttype_id: number;\n\tstatus: number;\n\tsender_address: string;\n\traw_tx: Buffer;\n\tevent_count: number;\n\tcontract_call_contract_id: string | null;\n\tcontract_call_function_name: string | null;\n\tsmart_contract_contract_id: string | null;\n}\n\nexport class HiroPgClient {\n\tprivate sql: ReturnType<typeof postgres>;\n\n\tconstructor(connectionUrl?: string) {\n\t\tconst url = connectionUrl || process.env.HIRO_PG_URL;\n\t\tif (!url) throw new Error(\"HIRO_PG_URL is required for HiroPgClient\");\n\t\tthis.sql = postgres(url, {\n\t\t\tmax: 10,\n\t\t\tidle_timeout: 30,\n\t\t});\n\t}\n\n\tasync getChainTip(): Promise<number> {\n\t\tconst rows = await this.sql`\n SELECT MAX(block_height) as tip FROM ${this.sql(SCHEMA)}.blocks WHERE canonical = true\n `;\n\t\treturn Number(rows[0]?.tip ?? 0);\n\t}\n\n\t/**\n\t * Fetch a complete block by height directly from PG.\n\t * Returns data in the same NewBlockPayload shape the backfill expects.\n\t */\n\tasync getBlockForIndexer(\n\t\theight: number,\n\t\toptions?: { includeRawTx?: boolean },\n\t): Promise<any | null> {\n\t\t// 1. Block metadata\n\t\tconst blocks = await this.sql<BlockRow[]>`\n SELECT block_hash, block_height, index_block_hash, parent_block_hash,\n parent_index_block_hash, burn_block_hash, burn_block_height,\n burn_block_time, block_time, miner_txid\n FROM ${this.sql(SCHEMA)}.blocks\n WHERE block_height = ${height} AND canonical = true\n LIMIT 1\n `;\n\t\tif (blocks.length === 0) return null;\n\t\tconst block = blocks[0];\n\n\t\t// 2. Transactions\n\t\tconst txs = await this.sql<TxRow[]>`\n SELECT tx_id, tx_index, type_id, status, sender_address, raw_tx, event_count,\n contract_call_contract_id, contract_call_function_name, smart_contract_contract_id\n FROM ${this.sql(SCHEMA)}.txs\n WHERE block_height = ${height} AND canonical = true AND microblock_canonical = true\n ORDER BY tx_index\n `;\n\n\t\tconst transactions = txs.map((tx) => {\n\t\t\tconst txType = mapTxTypeId(tx.type_id);\n\t\t\tconst entry: any = {\n\t\t\t\ttxid: toHex(tx.tx_id),\n\t\t\t\traw_tx: options?.includeRawTx ? toHex(tx.raw_tx) : \"0x00\",\n\t\t\t\tstatus: mapTxStatus(tx.status),\n\t\t\t\ttx_index: tx.tx_index,\n\t\t\t\ttx_type: txType,\n\t\t\t\tsender_address: tx.sender_address,\n\t\t\t};\n\t\t\tif (txType === \"contract_call\" && tx.contract_call_contract_id) {\n\t\t\t\tentry.contract_call = {\n\t\t\t\t\tcontract_id: tx.contract_call_contract_id,\n\t\t\t\t\tfunction_name: tx.contract_call_function_name || \"\",\n\t\t\t\t};\n\t\t\t} else if (txType === \"smart_contract\" && tx.smart_contract_contract_id) {\n\t\t\t\tentry.smart_contract = {\n\t\t\t\t\tcontract_id: tx.smart_contract_contract_id,\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn entry;\n\t\t});\n\n\t\t// 3. Events — query all event tables by block_height (fast, indexed)\n\t\tconst events: any[] = [];\n\n\t\t// STX events\n\t\tconst stxEvents = await this.sql`\n SELECT tx_id, event_index, asset_event_type_id, amount, sender, recipient, memo\n FROM ${this.sql(SCHEMA)}.stx_events\n WHERE block_height = ${height} AND canonical = true AND microblock_canonical = true\n ORDER BY event_index\n `;\n\t\tfor (const e of stxEvents) {\n\t\t\tconst type = stxEventType(e.asset_event_type_id);\n\t\t\tconst evt: any = {\n\t\t\t\ttxid: toHex(e.tx_id),\n\t\t\t\tevent_index: e.event_index,\n\t\t\t\tcommitted: true,\n\t\t\t\ttype,\n\t\t\t};\n\t\t\tif (type === \"stx_transfer_event\") {\n\t\t\t\tevt.stx_transfer_event = {\n\t\t\t\t\tsender: e.sender || \"\",\n\t\t\t\t\trecipient: e.recipient || \"\",\n\t\t\t\t\tamount: String(e.amount),\n\t\t\t\t\t...(e.memo ? { memo: toHex(e.memo) } : {}),\n\t\t\t\t};\n\t\t\t} else if (type === \"stx_mint_event\") {\n\t\t\t\tevt.stx_mint_event = {\n\t\t\t\t\trecipient: e.recipient || \"\",\n\t\t\t\t\tamount: String(e.amount),\n\t\t\t\t};\n\t\t\t} else if (type === \"stx_burn_event\") {\n\t\t\t\tevt.stx_burn_event = {\n\t\t\t\t\tsender: e.sender || \"\",\n\t\t\t\t\tamount: String(e.amount),\n\t\t\t\t};\n\t\t\t}\n\t\t\tevents.push(evt);\n\t\t}\n\n\t\t// STX lock events\n\t\tconst lockEvents = await this.sql`\n SELECT tx_id, event_index, locked_amount, unlock_height, locked_address\n FROM ${this.sql(SCHEMA)}.stx_lock_events\n WHERE block_height = ${height} AND canonical = true AND microblock_canonical = true\n ORDER BY event_index\n `;\n\t\tfor (const e of lockEvents) {\n\t\t\tevents.push({\n\t\t\t\ttxid: toHex(e.tx_id),\n\t\t\t\tevent_index: e.event_index,\n\t\t\t\tcommitted: true,\n\t\t\t\ttype: \"stx_lock_event\",\n\t\t\t\tstx_lock_event: {\n\t\t\t\t\tlocked_amount: String(e.locked_amount),\n\t\t\t\t\tunlock_height: String(e.unlock_height),\n\t\t\t\t\tlocked_address: e.locked_address,\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\n\t\t// FT events\n\t\tconst ftEvents = await this.sql`\n SELECT tx_id, event_index, asset_event_type_id, asset_identifier, amount, sender, recipient\n FROM ${this.sql(SCHEMA)}.ft_events\n WHERE block_height = ${height} AND canonical = true AND microblock_canonical = true\n ORDER BY event_index\n `;\n\t\tfor (const e of ftEvents) {\n\t\t\tconst type = ftEventType(e.asset_event_type_id);\n\t\t\tconst evt: any = {\n\t\t\t\ttxid: toHex(e.tx_id),\n\t\t\t\tevent_index: e.event_index,\n\t\t\t\tcommitted: true,\n\t\t\t\ttype,\n\t\t\t};\n\t\t\tif (type === \"ft_transfer_event\") {\n\t\t\t\tevt.ft_transfer_event = {\n\t\t\t\t\tasset_identifier: e.asset_identifier,\n\t\t\t\t\tsender: e.sender || \"\",\n\t\t\t\t\trecipient: e.recipient || \"\",\n\t\t\t\t\tamount: String(e.amount),\n\t\t\t\t};\n\t\t\t} else if (type === \"ft_mint_event\") {\n\t\t\t\tevt.ft_mint_event = {\n\t\t\t\t\tasset_identifier: e.asset_identifier,\n\t\t\t\t\trecipient: e.recipient || \"\",\n\t\t\t\t\tamount: String(e.amount),\n\t\t\t\t};\n\t\t\t} else if (type === \"ft_burn_event\") {\n\t\t\t\tevt.ft_burn_event = {\n\t\t\t\t\tasset_identifier: e.asset_identifier,\n\t\t\t\t\tsender: e.sender || \"\",\n\t\t\t\t\tamount: String(e.amount),\n\t\t\t\t};\n\t\t\t}\n\t\t\tevents.push(evt);\n\t\t}\n\n\t\t// NFT events\n\t\tconst nftEvents = await this.sql`\n SELECT tx_id, event_index, asset_event_type_id, asset_identifier, value, sender, recipient\n FROM ${this.sql(SCHEMA)}.nft_events\n WHERE block_height = ${height} AND canonical = true AND microblock_canonical = true\n ORDER BY event_index\n `;\n\t\tfor (const e of nftEvents) {\n\t\t\tconst type = nftEventType(e.asset_event_type_id);\n\t\t\tconst evt: any = {\n\t\t\t\ttxid: toHex(e.tx_id),\n\t\t\t\tevent_index: e.event_index,\n\t\t\t\tcommitted: true,\n\t\t\t\ttype,\n\t\t\t};\n\t\t\tconst val = toHex(e.value);\n\t\t\tif (type === \"nft_transfer_event\") {\n\t\t\t\tevt.nft_transfer_event = {\n\t\t\t\t\tasset_identifier: e.asset_identifier,\n\t\t\t\t\tsender: e.sender || \"\",\n\t\t\t\t\trecipient: e.recipient || \"\",\n\t\t\t\t\tvalue: val,\n\t\t\t\t};\n\t\t\t} else if (type === \"nft_mint_event\") {\n\t\t\t\tevt.nft_mint_event = {\n\t\t\t\t\tasset_identifier: e.asset_identifier,\n\t\t\t\t\trecipient: e.recipient || \"\",\n\t\t\t\t\tvalue: val,\n\t\t\t\t};\n\t\t\t} else if (type === \"nft_burn_event\") {\n\t\t\t\tevt.nft_burn_event = {\n\t\t\t\t\tasset_identifier: e.asset_identifier,\n\t\t\t\t\tsender: e.sender || \"\",\n\t\t\t\t\tvalue: val,\n\t\t\t\t};\n\t\t\t}\n\t\t\tevents.push(evt);\n\t\t}\n\n\t\t// Contract log events\n\t\tconst logEvents = await this.sql`\n SELECT tx_id, event_index, contract_identifier, topic, value\n FROM ${this.sql(SCHEMA)}.contract_logs\n WHERE block_height = ${height} AND canonical = true AND microblock_canonical = true\n ORDER BY event_index\n `;\n\t\tfor (const e of logEvents) {\n\t\t\tevents.push({\n\t\t\t\ttxid: toHex(e.tx_id),\n\t\t\t\tevent_index: e.event_index,\n\t\t\t\tcommitted: true,\n\t\t\t\ttype: \"smart_contract_event\",\n\t\t\t\tsmart_contract_event: {\n\t\t\t\t\tcontract_identifier: e.contract_identifier,\n\t\t\t\t\ttopic: e.topic,\n\t\t\t\t\tvalue: toHex(e.value),\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\n\t\treturn {\n\t\t\tblock_hash: toHex(block.block_hash),\n\t\t\tblock_height: block.block_height,\n\t\t\tindex_block_hash: toHex(block.index_block_hash),\n\t\t\tparent_block_hash: toHex(block.parent_block_hash),\n\t\t\tparent_index_block_hash: toHex(block.parent_index_block_hash),\n\t\t\tburn_block_hash: toHex(block.burn_block_hash),\n\t\t\tburn_block_height: block.burn_block_height,\n\t\t\tburn_block_timestamp: block.burn_block_time,\n\t\t\tminer_txid: toHex(block.miner_txid),\n\t\t\ttimestamp: block.block_time,\n\t\t\ttransactions,\n\t\t\tevents,\n\t\t};\n\t}\n\n\t/**\n\t * Fetch multiple blocks in bulk — 6 queries total instead of 6 per block.\n\t * Returns array of NewBlockPayload in height order.\n\t */\n\tasync getBlockBatch(\n\t\theights: number[],\n\t\toptions?: { includeRawTx?: boolean },\n\t): Promise<any[]> {\n\t\tif (heights.length === 0) return [];\n\n\t\t// 1. All blocks in range\n\t\tconst blocks = await this.sql`\n SELECT block_hash, block_height, index_block_hash, parent_block_hash,\n parent_index_block_hash, burn_block_hash, burn_block_height,\n burn_block_time, block_time, miner_txid\n FROM ${this.sql(SCHEMA)}.blocks\n WHERE block_height = ANY(${heights}) AND canonical = true\n `;\n\n\t\tif (blocks.length === 0) return [];\n\t\tconst blockMap = new Map<number, any>();\n\t\tfor (const b of blocks) {\n\t\t\tblockMap.set(b.block_height, { ...b, transactions: [], events: [] });\n\t\t}\n\n\t\t// 2. All transactions\n\t\tconst txs = await this.sql`\n SELECT tx_id, tx_index, type_id, status, sender_address, raw_tx, event_count, block_height,\n contract_call_contract_id, contract_call_function_name, smart_contract_contract_id\n FROM ${this.sql(SCHEMA)}.txs\n WHERE block_height = ANY(${heights}) AND canonical = true AND microblock_canonical = true\n ORDER BY block_height, tx_index\n `;\n\t\tfor (const tx of txs) {\n\t\t\tconst block = blockMap.get(tx.block_height);\n\t\t\tif (!block) continue;\n\t\t\tconst txType = mapTxTypeId(tx.type_id);\n\t\t\tconst entry: any = {\n\t\t\t\ttxid: toHex(tx.tx_id),\n\t\t\t\traw_tx: options?.includeRawTx ? toHex(tx.raw_tx) : \"0x00\",\n\t\t\t\tstatus: mapTxStatus(tx.status),\n\t\t\t\ttx_index: tx.tx_index,\n\t\t\t\ttx_type: txType,\n\t\t\t\tsender_address: tx.sender_address,\n\t\t\t};\n\t\t\tif (txType === \"contract_call\" && tx.contract_call_contract_id) {\n\t\t\t\tentry.contract_call = {\n\t\t\t\t\tcontract_id: tx.contract_call_contract_id,\n\t\t\t\t\tfunction_name: tx.contract_call_function_name || \"\",\n\t\t\t\t};\n\t\t\t} else if (txType === \"smart_contract\" && tx.smart_contract_contract_id) {\n\t\t\t\tentry.smart_contract = { contract_id: tx.smart_contract_contract_id };\n\t\t\t}\n\t\t\tblock.transactions.push(entry);\n\t\t}\n\n\t\t// 3. STX events\n\t\tconst stxEvents = await this.sql`\n SELECT tx_id, event_index, asset_event_type_id, amount, sender, recipient, memo, block_height\n FROM ${this.sql(SCHEMA)}.stx_events\n WHERE block_height = ANY(${heights}) AND canonical = true AND microblock_canonical = true\n `;\n\t\tfor (const e of stxEvents) {\n\t\t\tconst block = blockMap.get(e.block_height);\n\t\t\tif (!block) continue;\n\t\t\tconst type = stxEventType(e.asset_event_type_id);\n\t\t\tconst evt: any = {\n\t\t\t\ttxid: toHex(e.tx_id),\n\t\t\t\tevent_index: e.event_index,\n\t\t\t\tcommitted: true,\n\t\t\t\ttype,\n\t\t\t};\n\t\t\tif (type === \"stx_transfer_event\") {\n\t\t\t\tevt.stx_transfer_event = {\n\t\t\t\t\tsender: e.sender || \"\",\n\t\t\t\t\trecipient: e.recipient || \"\",\n\t\t\t\t\tamount: String(e.amount),\n\t\t\t\t\t...(e.memo ? { memo: toHex(e.memo) } : {}),\n\t\t\t\t};\n\t\t\t} else if (type === \"stx_mint_event\") {\n\t\t\t\tevt.stx_mint_event = {\n\t\t\t\t\trecipient: e.recipient || \"\",\n\t\t\t\t\tamount: String(e.amount),\n\t\t\t\t};\n\t\t\t} else if (type === \"stx_burn_event\") {\n\t\t\t\tevt.stx_burn_event = {\n\t\t\t\t\tsender: e.sender || \"\",\n\t\t\t\t\tamount: String(e.amount),\n\t\t\t\t};\n\t\t\t}\n\t\t\tblock.events.push(evt);\n\t\t}\n\n\t\t// 4. STX lock events\n\t\tconst lockEvents = await this.sql`\n SELECT tx_id, event_index, locked_amount, unlock_height, locked_address, block_height\n FROM ${this.sql(SCHEMA)}.stx_lock_events\n WHERE block_height = ANY(${heights}) AND canonical = true AND microblock_canonical = true\n `;\n\t\tfor (const e of lockEvents) {\n\t\t\tconst block = blockMap.get(e.block_height);\n\t\t\tif (!block) continue;\n\t\t\tblock.events.push({\n\t\t\t\ttxid: toHex(e.tx_id),\n\t\t\t\tevent_index: e.event_index,\n\t\t\t\tcommitted: true,\n\t\t\t\ttype: \"stx_lock_event\",\n\t\t\t\tstx_lock_event: {\n\t\t\t\t\tlocked_amount: String(e.locked_amount),\n\t\t\t\t\tunlock_height: String(e.unlock_height),\n\t\t\t\t\tlocked_address: e.locked_address,\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\n\t\t// 5. FT events\n\t\tconst ftEvents = await this.sql`\n SELECT tx_id, event_index, asset_event_type_id, asset_identifier, amount, sender, recipient, block_height\n FROM ${this.sql(SCHEMA)}.ft_events\n WHERE block_height = ANY(${heights}) AND canonical = true AND microblock_canonical = true\n `;\n\t\tfor (const e of ftEvents) {\n\t\t\tconst block = blockMap.get(e.block_height);\n\t\t\tif (!block) continue;\n\t\t\tconst type = ftEventType(e.asset_event_type_id);\n\t\t\tconst evt: any = {\n\t\t\t\ttxid: toHex(e.tx_id),\n\t\t\t\tevent_index: e.event_index,\n\t\t\t\tcommitted: true,\n\t\t\t\ttype,\n\t\t\t};\n\t\t\tif (type === \"ft_transfer_event\") {\n\t\t\t\tevt.ft_transfer_event = {\n\t\t\t\t\tasset_identifier: e.asset_identifier,\n\t\t\t\t\tsender: e.sender || \"\",\n\t\t\t\t\trecipient: e.recipient || \"\",\n\t\t\t\t\tamount: String(e.amount),\n\t\t\t\t};\n\t\t\t} else if (type === \"ft_mint_event\") {\n\t\t\t\tevt.ft_mint_event = {\n\t\t\t\t\tasset_identifier: e.asset_identifier,\n\t\t\t\t\trecipient: e.recipient || \"\",\n\t\t\t\t\tamount: String(e.amount),\n\t\t\t\t};\n\t\t\t} else if (type === \"ft_burn_event\") {\n\t\t\t\tevt.ft_burn_event = {\n\t\t\t\t\tasset_identifier: e.asset_identifier,\n\t\t\t\t\tsender: e.sender || \"\",\n\t\t\t\t\tamount: String(e.amount),\n\t\t\t\t};\n\t\t\t}\n\t\t\tblock.events.push(evt);\n\t\t}\n\n\t\t// 6. NFT events\n\t\tconst nftEvents = await this.sql`\n SELECT tx_id, event_index, asset_event_type_id, asset_identifier, value, sender, recipient, block_height\n FROM ${this.sql(SCHEMA)}.nft_events\n WHERE block_height = ANY(${heights}) AND canonical = true AND microblock_canonical = true\n `;\n\t\tfor (const e of nftEvents) {\n\t\t\tconst block = blockMap.get(e.block_height);\n\t\t\tif (!block) continue;\n\t\t\tconst type = nftEventType(e.asset_event_type_id);\n\t\t\tconst evt: any = {\n\t\t\t\ttxid: toHex(e.tx_id),\n\t\t\t\tevent_index: e.event_index,\n\t\t\t\tcommitted: true,\n\t\t\t\ttype,\n\t\t\t};\n\t\t\tconst val = toHex(e.value);\n\t\t\tif (type === \"nft_transfer_event\") {\n\t\t\t\tevt.nft_transfer_event = {\n\t\t\t\t\tasset_identifier: e.asset_identifier,\n\t\t\t\t\tsender: e.sender || \"\",\n\t\t\t\t\trecipient: e.recipient || \"\",\n\t\t\t\t\tvalue: val,\n\t\t\t\t};\n\t\t\t} else if (type === \"nft_mint_event\") {\n\t\t\t\tevt.nft_mint_event = {\n\t\t\t\t\tasset_identifier: e.asset_identifier,\n\t\t\t\t\trecipient: e.recipient || \"\",\n\t\t\t\t\tvalue: val,\n\t\t\t\t};\n\t\t\t} else if (type === \"nft_burn_event\") {\n\t\t\t\tevt.nft_burn_event = {\n\t\t\t\t\tasset_identifier: e.asset_identifier,\n\t\t\t\t\tsender: e.sender || \"\",\n\t\t\t\t\tvalue: val,\n\t\t\t\t};\n\t\t\t}\n\t\t\tblock.events.push(evt);\n\t\t}\n\n\t\t// 7. Contract log events\n\t\tconst logEvents = await this.sql`\n SELECT tx_id, event_index, contract_identifier, topic, value, block_height\n FROM ${this.sql(SCHEMA)}.contract_logs\n WHERE block_height = ANY(${heights}) AND canonical = true AND microblock_canonical = true\n `;\n\t\tfor (const e of logEvents) {\n\t\t\tconst block = blockMap.get(e.block_height);\n\t\t\tif (!block) continue;\n\t\t\tblock.events.push({\n\t\t\t\ttxid: toHex(e.tx_id),\n\t\t\t\tevent_index: e.event_index,\n\t\t\t\tcommitted: true,\n\t\t\t\ttype: \"smart_contract_event\",\n\t\t\t\tsmart_contract_event: {\n\t\t\t\t\tcontract_identifier: e.contract_identifier,\n\t\t\t\t\ttopic: e.topic,\n\t\t\t\t\tvalue: toHex(e.value),\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\n\t\t// Build results in height order\n\t\treturn heights\n\t\t\t.filter((h) => blockMap.has(h))\n\t\t\t.map((h) => {\n\t\t\t\tconst b = blockMap.get(h)!;\n\t\t\t\treturn {\n\t\t\t\t\tblock_hash: toHex(b.block_hash),\n\t\t\t\t\tblock_height: b.block_height,\n\t\t\t\t\tindex_block_hash: toHex(b.index_block_hash),\n\t\t\t\t\tparent_block_hash: toHex(b.parent_block_hash),\n\t\t\t\t\tparent_index_block_hash: toHex(b.parent_index_block_hash),\n\t\t\t\t\tburn_block_hash: toHex(b.burn_block_hash),\n\t\t\t\t\tburn_block_height: b.burn_block_height,\n\t\t\t\t\tburn_block_timestamp: b.burn_block_time,\n\t\t\t\t\tminer_txid: toHex(b.miner_txid),\n\t\t\t\t\ttimestamp: b.block_time,\n\t\t\t\t\ttransactions: b.transactions,\n\t\t\t\t\tevents: b.events,\n\t\t\t\t};\n\t\t\t});\n\t}\n\n\tasync close(): Promise<void> {\n\t\tawait this.sql.end();\n\t}\n}\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": "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",
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "FA22CF35B56E552564756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
|
@@ -38,7 +38,7 @@ interface StreamsTable {
|
|
|
38
38
|
options: Generated<unknown>;
|
|
39
39
|
endpoint_url: string;
|
|
40
40
|
signing_secret: string | null;
|
|
41
|
-
api_key_id: string
|
|
41
|
+
api_key_id: string;
|
|
42
42
|
created_at: Generated<Date>;
|
|
43
43
|
updated_at: Generated<Date>;
|
|
44
44
|
}
|
|
@@ -92,15 +92,26 @@ interface SubgraphsTable {
|
|
|
92
92
|
schema_hash: string;
|
|
93
93
|
handler_path: string;
|
|
94
94
|
schema_name: string | null;
|
|
95
|
+
start_block: Generated<number>;
|
|
95
96
|
last_processed_block: Generated<number>;
|
|
96
97
|
last_error: string | null;
|
|
97
98
|
last_error_at: Date | null;
|
|
98
99
|
total_processed: Generated<number>;
|
|
99
100
|
total_errors: Generated<number>;
|
|
100
|
-
api_key_id: string
|
|
101
|
+
api_key_id: string;
|
|
101
102
|
created_at: Generated<Date>;
|
|
102
103
|
updated_at: Generated<Date>;
|
|
103
104
|
}
|
|
105
|
+
interface SubgraphGapsTable {
|
|
106
|
+
id: Generated<string>;
|
|
107
|
+
subgraph_id: string;
|
|
108
|
+
subgraph_name: string;
|
|
109
|
+
gap_start: number;
|
|
110
|
+
gap_end: number;
|
|
111
|
+
reason: string;
|
|
112
|
+
detected_at: Generated<Date>;
|
|
113
|
+
resolved_at: Date | null;
|
|
114
|
+
}
|
|
104
115
|
interface ApiKeysTable {
|
|
105
116
|
id: Generated<string>;
|
|
106
117
|
key_hash: string;
|
|
@@ -137,6 +148,7 @@ interface MagicLinksTable {
|
|
|
137
148
|
token: string;
|
|
138
149
|
expires_at: Date;
|
|
139
150
|
used_at: Date | null;
|
|
151
|
+
failed_attempts: Generated<number>;
|
|
140
152
|
created_at: Generated<Date>;
|
|
141
153
|
}
|
|
142
154
|
interface UsageDailyTable {
|
|
@@ -238,6 +250,7 @@ interface Database {
|
|
|
238
250
|
subgraph_health_snapshots: SubgraphHealthSnapshotsTable;
|
|
239
251
|
subgraph_processing_stats: SubgraphProcessingStatsTable;
|
|
240
252
|
subgraph_table_snapshots: SubgraphTableSnapshotsTable;
|
|
253
|
+
subgraph_gaps: SubgraphGapsTable;
|
|
241
254
|
}
|
|
242
255
|
/** Matches the NewBlockPayload shape expected by the indexer's /new_block endpoint */
|
|
243
256
|
interface ReplayBlockPayload {
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/node/local-client.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"/**\n * Local replay client — reconstructs NewBlockPayload from our own Postgres.\n *\n * Used for re-orgs, reprocessing, and self-serve replay after genesis sync.\n * Eliminates need for self-hosted Hiro API for blocks already in our DB.\n */\n\nimport type { Kysely } from \"kysely\";\nimport type { Database } from \"../db/types.ts\";\n\n/** Matches the NewBlockPayload shape expected by the indexer's /new_block endpoint */\nexport interface ReplayBlockPayload {\n
|
|
5
|
+
"/**\n * Local replay client — reconstructs NewBlockPayload from our own Postgres.\n *\n * Used for re-orgs, reprocessing, and self-serve replay after genesis sync.\n * Eliminates need for self-hosted Hiro API for blocks already in our DB.\n */\n\nimport type { Kysely } from \"kysely\";\nimport type { Database } from \"../db/types.ts\";\n\n/** Matches the NewBlockPayload shape expected by the indexer's /new_block endpoint */\nexport interface ReplayBlockPayload {\n\tblock_hash: string;\n\tblock_height: number;\n\tindex_block_hash: string;\n\tparent_block_hash: string;\n\tparent_index_block_hash: string;\n\tburn_block_hash: string;\n\tburn_block_height: number;\n\tburn_block_timestamp: number;\n\tminer_txid: string;\n\ttimestamp: number;\n\ttransactions: ReplayTransactionPayload[];\n\tevents: ReplayEventPayload[];\n}\n\ninterface ReplayTransactionPayload {\n\ttxid: string;\n\traw_tx: string;\n\tstatus: string;\n\ttx_index: number;\n\ttx_type?: string;\n\tsender_address?: string;\n}\n\ninterface ReplayEventPayload {\n\ttxid: string;\n\tevent_index: number;\n\tcommitted: boolean;\n\ttype: string;\n\t[key: string]: unknown;\n}\n\nexport class LocalClient {\n\t/**\n\t * Reconstruct a NewBlockPayload from local DB for replay.\n\t * Returns null if block not found.\n\t */\n\tasync getBlockForReplay(\n\t\tdb: Kysely<Database>,\n\t\theight: number,\n\t): Promise<ReplayBlockPayload | null> {\n\t\tconst block = await db\n\t\t\t.selectFrom(\"blocks\")\n\t\t\t.selectAll()\n\t\t\t.where(\"height\", \"=\", height)\n\t\t\t.where(\"canonical\", \"=\", true)\n\t\t\t.executeTakeFirst();\n\n\t\tif (!block) return null;\n\n\t\tconst transactions = await db\n\t\t\t.selectFrom(\"transactions\")\n\t\t\t.selectAll()\n\t\t\t.where(\"block_height\", \"=\", height)\n\t\t\t.orderBy(\"tx_index\", \"asc\")\n\t\t\t.execute();\n\n\t\tconst events = await db\n\t\t\t.selectFrom(\"events\")\n\t\t\t.selectAll()\n\t\t\t.where(\"block_height\", \"=\", height)\n\t\t\t.orderBy(\"event_index\", \"asc\")\n\t\t\t.execute();\n\n\t\treturn {\n\t\t\tblock_hash: block.hash,\n\t\t\tblock_height: block.height,\n\t\t\t// Not stored in our DB — not needed by parser/deliveries\n\t\t\tindex_block_hash: \"\",\n\t\t\tparent_block_hash: block.parent_hash,\n\t\t\tparent_index_block_hash: \"\",\n\t\t\tburn_block_hash: \"\",\n\t\t\tburn_block_height: block.burn_block_height,\n\t\t\tburn_block_timestamp: block.timestamp,\n\t\t\tminer_txid: \"\",\n\t\t\ttimestamp: block.timestamp,\n\t\t\ttransactions: transactions.map((tx) => ({\n\t\t\t\ttxid: tx.tx_id,\n\t\t\t\traw_tx: tx.raw_tx,\n\t\t\t\tstatus: tx.status,\n\t\t\t\ttx_index: tx.tx_index,\n\t\t\t\ttx_type: tx.type,\n\t\t\t\tsender_address: tx.sender,\n\t\t\t})),\n\t\t\tevents: events.map((evt) => {\n\t\t\t\tconst data = (evt.data ?? {}) as Record<string, unknown>;\n\t\t\t\tconst eventType = evt.type;\n\n\t\t\t\t// Reconstruct the flat event structure the indexer expects:\n\t\t\t\t// { txid, event_index, committed, type, [type_key]: data }\n\t\t\t\tconst payload: ReplayEventPayload = {\n\t\t\t\t\ttxid: evt.tx_id,\n\t\t\t\t\tevent_index: evt.event_index,\n\t\t\t\t\tcommitted: true,\n\t\t\t\t\ttype: eventType,\n\t\t\t\t};\n\n\t\t\t\t// Attach event-specific data under the correct key\n\t\t\t\tif (eventType && data) {\n\t\t\t\t\tpayload[eventType] = data;\n\t\t\t\t}\n\n\t\t\t\treturn payload;\n\t\t\t}),\n\t\t};\n\t}\n\n\t/** Get highest block height in local DB */\n\tasync getChainTip(db: Kysely<Database>): Promise<number> {\n\t\tconst row = await db\n\t\t\t.selectFrom(\"blocks\")\n\t\t\t.select((eb) => eb.fn.max(\"height\").as(\"max_height\"))\n\t\t\t.where(\"canonical\", \"=\", true)\n\t\t\t.executeTakeFirst();\n\t\treturn Number(row?.max_height ?? 0);\n\t}\n\n\t/** Check if a specific block height exists in local DB */\n\tasync hasBlock(db: Kysely<Database>, height: number): Promise<boolean> {\n\t\tconst row = await db\n\t\t\t.selectFrom(\"blocks\")\n\t\t\t.select(\"height\")\n\t\t\t.where(\"height\", \"=\", height)\n\t\t\t.where(\"canonical\", \"=\", true)\n\t\t\t.executeTakeFirst();\n\t\treturn !!row;\n\t}\n}\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": ";;;;;;;;;;;;;;;;;AA2CO,MAAM,YAAY;AAAA,
|
|
7
|
+
"mappings": ";;;;;;;;;;;;;;;;;AA2CO,MAAM,YAAY;AAAA,OAKlB,kBAAiB,CACtB,IACA,QACqC;AAAA,IACrC,MAAM,QAAQ,MAAM,GAClB,WAAW,QAAQ,EACnB,UAAU,EACV,MAAM,UAAU,KAAK,MAAM,EAC3B,MAAM,aAAa,KAAK,IAAI,EAC5B,iBAAiB;AAAA,IAEnB,IAAI,CAAC;AAAA,MAAO,OAAO;AAAA,IAEnB,MAAM,eAAe,MAAM,GACzB,WAAW,cAAc,EACzB,UAAU,EACV,MAAM,gBAAgB,KAAK,MAAM,EACjC,QAAQ,YAAY,KAAK,EACzB,QAAQ;AAAA,IAEV,MAAM,SAAS,MAAM,GACnB,WAAW,QAAQ,EACnB,UAAU,EACV,MAAM,gBAAgB,KAAK,MAAM,EACjC,QAAQ,eAAe,KAAK,EAC5B,QAAQ;AAAA,IAEV,OAAO;AAAA,MACN,YAAY,MAAM;AAAA,MAClB,cAAc,MAAM;AAAA,MAEpB,kBAAkB;AAAA,MAClB,mBAAmB,MAAM;AAAA,MACzB,yBAAyB;AAAA,MACzB,iBAAiB;AAAA,MACjB,mBAAmB,MAAM;AAAA,MACzB,sBAAsB,MAAM;AAAA,MAC5B,YAAY;AAAA,MACZ,WAAW,MAAM;AAAA,MACjB,cAAc,aAAa,IAAI,CAAC,QAAQ;AAAA,QACvC,MAAM,GAAG;AAAA,QACT,QAAQ,GAAG;AAAA,QACX,QAAQ,GAAG;AAAA,QACX,UAAU,GAAG;AAAA,QACb,SAAS,GAAG;AAAA,QACZ,gBAAgB,GAAG;AAAA,MACpB,EAAE;AAAA,MACF,QAAQ,OAAO,IAAI,CAAC,QAAQ;AAAA,QAC3B,MAAM,OAAQ,IAAI,QAAQ,CAAC;AAAA,QAC3B,MAAM,YAAY,IAAI;AAAA,QAItB,MAAM,UAA8B;AAAA,UACnC,MAAM,IAAI;AAAA,UACV,aAAa,IAAI;AAAA,UACjB,WAAW;AAAA,UACX,MAAM;AAAA,QACP;AAAA,QAGA,IAAI,aAAa,MAAM;AAAA,UACtB,QAAQ,aAAa;AAAA,QACtB;AAAA,QAEA,OAAO;AAAA,OACP;AAAA,IACF;AAAA;AAAA,OAIK,YAAW,CAAC,IAAuC;AAAA,IACxD,MAAM,MAAM,MAAM,GAChB,WAAW,QAAQ,EACnB,OAAO,CAAC,OAAO,GAAG,GAAG,IAAI,QAAQ,EAAE,GAAG,YAAY,CAAC,EACnD,MAAM,aAAa,KAAK,IAAI,EAC5B,iBAAiB;AAAA,IACnB,OAAO,OAAO,KAAK,cAAc,CAAC;AAAA;AAAA,OAI7B,SAAQ,CAAC,IAAsB,QAAkC;AAAA,IACtE,MAAM,MAAM,MAAM,GAChB,WAAW,QAAQ,EACnB,OAAO,QAAQ,EACf,MAAM,UAAU,KAAK,MAAM,EAC3B,MAAM,aAAa,KAAK,IAAI,EAC5B,iBAAiB;AAAA,IACnB,OAAO,CAAC,CAAC;AAAA;AAEX;",
|
|
8
8
|
"debugId": "DE87E3DF563DF80464756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
package/dist/src/queue/index.js
CHANGED
|
@@ -42,8 +42,12 @@ function getDb(connectionString) {
|
|
|
42
42
|
if (!db) {
|
|
43
43
|
const url = connectionString || process.env.DATABASE_URL || "postgres://postgres:postgres@localhost:5432/streams_dev";
|
|
44
44
|
const isLocal = url.includes("localhost") || url.includes("127.0.0.1") || url.includes("@postgres:");
|
|
45
|
+
const poolMax = Number.parseInt(process.env.DATABASE_POOL_MAX ?? "20", 10);
|
|
45
46
|
rawClient = postgres(url, {
|
|
46
|
-
|
|
47
|
+
max: poolMax,
|
|
48
|
+
ssl: isLocal ? undefined : {
|
|
49
|
+
rejectUnauthorized: process.env.NODE_TLS_REJECT_UNAUTHORIZED !== "0"
|
|
50
|
+
}
|
|
47
51
|
});
|
|
48
52
|
db = new Kysely({
|
|
49
53
|
dialect: new PostgresJSDialect({ postgres: rawClient })
|
|
@@ -77,8 +81,8 @@ __export(exports_queue, {
|
|
|
77
81
|
claim: () => claim,
|
|
78
82
|
WORKER_ID: () => WORKER_ID
|
|
79
83
|
});
|
|
80
|
-
import { sql as sql3 } from "kysely";
|
|
81
84
|
import { randomUUID } from "crypto";
|
|
85
|
+
import { sql as sql3 } from "kysely";
|
|
82
86
|
var WORKER_ID = `worker-${randomUUID().slice(0, 8)}`;
|
|
83
87
|
async function enqueue(streamId, blockHeight, backfill = false) {
|
|
84
88
|
const db2 = getDb();
|
|
@@ -153,7 +157,7 @@ async function stats() {
|
|
|
153
157
|
`.execute(getDb());
|
|
154
158
|
const counts = {};
|
|
155
159
|
for (const row of rows) {
|
|
156
|
-
counts[row.status] = parseInt(row.count, 10);
|
|
160
|
+
counts[row.status] = Number.parseInt(row.count, 10);
|
|
157
161
|
}
|
|
158
162
|
return {
|
|
159
163
|
pending: counts["pending"] || 0,
|
|
@@ -176,5 +180,5 @@ export {
|
|
|
176
180
|
WORKER_ID
|
|
177
181
|
};
|
|
178
182
|
|
|
179
|
-
//# debugId=
|
|
183
|
+
//# debugId=D0A7A5EB2FBB9F6664756E2164756E21
|
|
180
184
|
//# sourceMappingURL=index.js.map
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/db/jsonb.ts", "../src/db/index.ts", "../src/queue/index.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import {
|
|
6
|
-
"import { Kysely } from \"kysely\";\nimport { PostgresJSDialect } from \"kysely-postgres-js\";\nimport postgres from \"postgres\";\nimport type { Database } from \"./types.ts\";\n\nlet db: Kysely<Database> | null = null;\nlet rawClient: ReturnType<typeof postgres> | null = null;\n\nexport function getDb(connectionString?: string): Kysely<Database> {\n
|
|
7
|
-
"import {
|
|
5
|
+
"import { type RawBuilder, sql } from \"kysely\";\n\n/**\n * Safely encode a JS value as a JSONB literal for Kysely inserts/updates.\n * Kysely + postgres.js double-encodes JSON when using parameterized queries\n * with ::jsonb casts. This uses sql.raw to inline a properly escaped literal.\n */\nexport function jsonb(value: unknown): RawBuilder<unknown> {\n\tconst escaped = JSON.stringify(value).replace(/'/g, \"''\");\n\treturn sql`${sql.raw(`'${escaped}'::jsonb`)}`;\n}\n\n/**\n * Safely parse a JSONB value from the database.\n * Handles double-encoded strings where postgres.js returns a JSON string\n * instead of a parsed object.\n */\nexport function parseJsonb<T = unknown>(value: unknown): T {\n\tif (typeof value === \"string\") {\n\t\ttry {\n\t\t\treturn JSON.parse(value) as T;\n\t\t} catch {\n\t\t\treturn value as T;\n\t\t}\n\t}\n\treturn (value ?? {}) as T;\n}\n",
|
|
6
|
+
"import { Kysely } from \"kysely\";\nimport { PostgresJSDialect } from \"kysely-postgres-js\";\nimport postgres from \"postgres\";\nimport type { Database } from \"./types.ts\";\n\nlet db: Kysely<Database> | null = null;\nlet rawClient: ReturnType<typeof postgres> | null = null;\n\nexport function getDb(connectionString?: string): Kysely<Database> {\n\tif (!db) {\n\t\tconst url =\n\t\t\tconnectionString ||\n\t\t\tprocess.env.DATABASE_URL ||\n\t\t\t\"postgres://postgres:postgres@localhost:5432/streams_dev\";\n\n\t\t// Always use SSL for remote databases, just disable cert verification if needed\n\t\tconst isLocal =\n\t\t\turl.includes(\"localhost\") ||\n\t\t\turl.includes(\"127.0.0.1\") ||\n\t\t\turl.includes(\"@postgres:\");\n\t\tconst poolMax = Number.parseInt(process.env.DATABASE_POOL_MAX ?? \"20\", 10);\n\t\trawClient = postgres(url, {\n\t\t\tmax: poolMax,\n\t\t\tssl: isLocal\n\t\t\t\t? undefined\n\t\t\t\t: {\n\t\t\t\t\t\trejectUnauthorized:\n\t\t\t\t\t\t\tprocess.env.NODE_TLS_REJECT_UNAUTHORIZED !== \"0\",\n\t\t\t\t\t},\n\t\t});\n\t\tdb = new Kysely<Database>({\n\t\t\tdialect: new PostgresJSDialect({ postgres: rawClient }),\n\t\t});\n\t}\n\treturn db;\n}\n\n/** Raw postgres.js client for dynamic schema DDL (CREATE SCHEMA, DROP, etc.) */\nexport function getRawClient(): ReturnType<typeof postgres> {\n\tif (!rawClient) getDb();\n\treturn rawClient!;\n}\n\n/** Close the DB connection pool. Call in CLI commands to allow process exit. */\nexport async function closeDb(): Promise<void> {\n\tif (db) {\n\t\tawait db.destroy();\n\t\tdb = null;\n\t}\n\tif (rawClient) {\n\t\tawait rawClient.end();\n\t\trawClient = null;\n\t}\n}\n\nimport { sql } from \"kysely\";\nexport { sql };\nexport * from \"./types.ts\";\nexport { jsonb, parseJsonb } from \"./jsonb.ts\";\n",
|
|
7
|
+
"import { randomUUID } from \"crypto\";\nimport { sql } from \"kysely\";\nimport { getDb } from \"../db/index.ts\";\nimport type { Job } from \"../db/types.ts\";\n\nexport interface QueueStats {\n\tpending: number;\n\tprocessing: number;\n\tcompleted: number;\n\tfailed: number;\n\ttotal: number;\n}\n\n// Worker identifier for this process\nconst WORKER_ID: string = `worker-${randomUUID().slice(0, 8)}`;\n\n/**\n * Enqueue a new job for stream evaluation\n */\nexport async function enqueue(\n\tstreamId: string,\n\tblockHeight: number,\n\tbackfill = false,\n): Promise<string> {\n\tconst db = getDb();\n\n\tconst row = await db\n\t\t.insertInto(\"jobs\")\n\t\t.values({\n\t\t\tstream_id: streamId,\n\t\t\tblock_height: blockHeight,\n\t\t\tbackfill,\n\t\t\tstatus: \"pending\",\n\t\t\tattempts: 0,\n\t\t})\n\t\t.returning([\"id\"])\n\t\t.executeTakeFirstOrThrow();\n\n\treturn row.id;\n}\n\n/**\n * Claim a pending job using SKIP LOCKED to prevent concurrent access\n * Returns null if no jobs available\n */\nexport async function claim(): Promise<Job | null> {\n\tconst db = getDb();\n\n\tconst { rows } = await sql<Job>`\n UPDATE jobs\n SET\n status = 'processing',\n locked_at = NOW(),\n locked_by = ${WORKER_ID},\n attempts = attempts + 1\n WHERE id = (\n SELECT id FROM jobs\n WHERE status = 'pending'\n ORDER BY\n backfill ASC,\n block_height ASC,\n created_at ASC\n FOR UPDATE SKIP LOCKED\n LIMIT 1\n )\n RETURNING *\n `.execute(db);\n\n\treturn rows[0] ?? null;\n}\n\n/**\n * Mark a job as completed\n */\nexport async function complete(jobId: string): Promise<void> {\n\tconst db = getDb();\n\n\tawait db\n\t\t.updateTable(\"jobs\")\n\t\t.set({\n\t\t\tstatus: \"completed\",\n\t\t\tcompleted_at: new Date(),\n\t\t\tlocked_at: null,\n\t\t\tlocked_by: null,\n\t\t})\n\t\t.where(\"id\", \"=\", jobId)\n\t\t.execute();\n}\n\n/**\n * Mark a job as failed\n * Re-queues if under max attempts, otherwise marks as permanently failed\n */\nexport async function fail(\n\tjobId: string,\n\terror: string,\n\tmaxAttempts = 3,\n): Promise<void> {\n\tconst db = getDb();\n\n\tconst job = await db\n\t\t.selectFrom(\"jobs\")\n\t\t.select(\"attempts\")\n\t\t.where(\"id\", \"=\", jobId)\n\t\t.executeTakeFirst();\n\n\tif (!job) return;\n\n\tif (job.attempts < maxAttempts) {\n\t\tawait db\n\t\t\t.updateTable(\"jobs\")\n\t\t\t.set({\n\t\t\t\tstatus: \"pending\",\n\t\t\t\terror,\n\t\t\t\tlocked_at: null,\n\t\t\t\tlocked_by: null,\n\t\t\t})\n\t\t\t.where(\"id\", \"=\", jobId)\n\t\t\t.execute();\n\t} else {\n\t\tawait db\n\t\t\t.updateTable(\"jobs\")\n\t\t\t.set({\n\t\t\t\tstatus: \"failed\",\n\t\t\t\terror,\n\t\t\t\tcompleted_at: new Date(),\n\t\t\t\tlocked_at: null,\n\t\t\t\tlocked_by: null,\n\t\t\t})\n\t\t\t.where(\"id\", \"=\", jobId)\n\t\t\t.execute();\n\t}\n}\n\n/**\n * Get queue statistics\n */\nexport async function stats(): Promise<QueueStats> {\n\tconst { rows } = await sql<{ status: string; count: string }>`\n SELECT status, COUNT(*) as count\n FROM jobs\n GROUP BY status\n `.execute(getDb());\n\n\tconst counts: Record<string, number> = {};\n\tfor (const row of rows) {\n\t\tcounts[row.status] = Number.parseInt(row.count, 10);\n\t}\n\n\treturn {\n\t\tpending: counts[\"pending\"] || 0,\n\t\tprocessing: counts[\"processing\"] || 0,\n\t\tcompleted: counts[\"completed\"] || 0,\n\t\tfailed: counts[\"failed\"] || 0,\n\t\ttotal: Object.values(counts).reduce((a, b) => a + b, 0),\n\t};\n}\n\n/**\n * Get worker ID for this process\n */\nexport function getWorkerId(): string {\n\treturn WORKER_ID;\n}\n\nexport { WORKER_ID };\n"
|
|
8
8
|
],
|
|
9
|
-
"mappings": ";;;;;;;;;;;;;;;;;AAAA;AAOO,SAAS,KAAK,CAAC,OAAqC;AAAA,
|
|
10
|
-
"debugId": "
|
|
9
|
+
"mappings": ";;;;;;;;;;;;;;;;;AAAA;AAOO,SAAS,KAAK,CAAC,OAAqC;AAAA,EAC1D,MAAM,UAAU,KAAK,UAAU,KAAK,EAAE,QAAQ,MAAM,IAAI;AAAA,EACxD,OAAO,MAAM,IAAI,IAAI,IAAI,iBAAiB;AAAA;AAQpC,SAAS,UAAuB,CAAC,OAAmB;AAAA,EAC1D,IAAI,OAAO,UAAU,UAAU;AAAA,IAC9B,IAAI;AAAA,MACH,OAAO,KAAK,MAAM,KAAK;AAAA,MACtB,MAAM;AAAA,MACP,OAAO;AAAA;AAAA,EAET;AAAA,EACA,OAAQ,SAAS,CAAC;AAAA;;;ACzBnB;AACA;AACA;AAqDA,gBAAS;AAlDT,IAAI,KAA8B;AAClC,IAAI,YAAgD;AAE7C,SAAS,KAAK,CAAC,kBAA6C;AAAA,EAClE,IAAI,CAAC,IAAI;AAAA,IACR,MAAM,MACL,oBACA,QAAQ,IAAI,gBACZ;AAAA,IAGD,MAAM,UACL,IAAI,SAAS,WAAW,KACxB,IAAI,SAAS,WAAW,KACxB,IAAI,SAAS,YAAY;AAAA,IAC1B,MAAM,UAAU,OAAO,SAAS,QAAQ,IAAI,qBAAqB,MAAM,EAAE;AAAA,IACzE,YAAY,SAAS,KAAK;AAAA,MACzB,KAAK;AAAA,MACL,KAAK,UACF,YACA;AAAA,QACA,oBACC,QAAQ,IAAI,iCAAiC;AAAA,MAC/C;AAAA,IACH,CAAC;AAAA,IACD,KAAK,IAAI,OAAiB;AAAA,MACzB,SAAS,IAAI,kBAAkB,EAAE,UAAU,UAAU,CAAC;AAAA,IACvD,CAAC;AAAA,EACF;AAAA,EACA,OAAO;AAAA;AAID,SAAS,YAAY,GAAgC;AAAA,EAC3D,IAAI,CAAC;AAAA,IAAW,MAAM;AAAA,EACtB,OAAO;AAAA;AAIR,eAAsB,OAAO,GAAkB;AAAA,EAC9C,IAAI,IAAI;AAAA,IACP,MAAM,GAAG,QAAQ;AAAA,IACjB,KAAK;AAAA,EACN;AAAA,EACA,IAAI,WAAW;AAAA,IACd,MAAM,UAAU,IAAI;AAAA,IACpB,YAAY;AAAA,EACb;AAAA;;;;;;;;;;;;ACpDD;AACA,gBAAS;AAaT,IAAM,YAAoB,UAAU,WAAW,EAAE,MAAM,GAAG,CAAC;AAK3D,eAAsB,OAAO,CAC5B,UACA,aACA,WAAW,OACO;AAAA,EAClB,MAAM,MAAK,MAAM;AAAA,EAEjB,MAAM,MAAM,MAAM,IAChB,WAAW,MAAM,EACjB,OAAO;AAAA,IACP,WAAW;AAAA,IACX,cAAc;AAAA,IACd;AAAA,IACA,QAAQ;AAAA,IACR,UAAU;AAAA,EACX,CAAC,EACA,UAAU,CAAC,IAAI,CAAC,EAChB,wBAAwB;AAAA,EAE1B,OAAO,IAAI;AAAA;AAOZ,eAAsB,KAAK,GAAwB;AAAA,EAClD,MAAM,MAAK,MAAM;AAAA,EAEjB,QAAQ,SAAS,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA,oBAKJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAahB,QAAQ,GAAE;AAAA,EAEb,OAAO,KAAK,MAAM;AAAA;AAMnB,eAAsB,QAAQ,CAAC,OAA8B;AAAA,EAC5D,MAAM,MAAK,MAAM;AAAA,EAEjB,MAAM,IACJ,YAAY,MAAM,EAClB,IAAI;AAAA,IACJ,QAAQ;AAAA,IACR,cAAc,IAAI;AAAA,IAClB,WAAW;AAAA,IACX,WAAW;AAAA,EACZ,CAAC,EACA,MAAM,MAAM,KAAK,KAAK,EACtB,QAAQ;AAAA;AAOX,eAAsB,IAAI,CACzB,OACA,OACA,cAAc,GACE;AAAA,EAChB,MAAM,MAAK,MAAM;AAAA,EAEjB,MAAM,MAAM,MAAM,IAChB,WAAW,MAAM,EACjB,OAAO,UAAU,EACjB,MAAM,MAAM,KAAK,KAAK,EACtB,iBAAiB;AAAA,EAEnB,IAAI,CAAC;AAAA,IAAK;AAAA,EAEV,IAAI,IAAI,WAAW,aAAa;AAAA,IAC/B,MAAM,IACJ,YAAY,MAAM,EAClB,IAAI;AAAA,MACJ,QAAQ;AAAA,MACR;AAAA,MACA,WAAW;AAAA,MACX,WAAW;AAAA,IACZ,CAAC,EACA,MAAM,MAAM,KAAK,KAAK,EACtB,QAAQ;AAAA,EACX,EAAO;AAAA,IACN,MAAM,IACJ,YAAY,MAAM,EAClB,IAAI;AAAA,MACJ,QAAQ;AAAA,MACR;AAAA,MACA,cAAc,IAAI;AAAA,MAClB,WAAW;AAAA,MACX,WAAW;AAAA,IACZ,CAAC,EACA,MAAM,MAAM,KAAK,KAAK,EACtB,QAAQ;AAAA;AAAA;AAOZ,eAAsB,KAAK,GAAwB;AAAA,EAClD,QAAQ,SAAS,MAAM;AAAA;AAAA;AAAA;AAAA,IAIpB,QAAQ,MAAM,CAAC;AAAA,EAElB,MAAM,SAAiC,CAAC;AAAA,EACxC,WAAW,OAAO,MAAM;AAAA,IACvB,OAAO,IAAI,UAAU,OAAO,SAAS,IAAI,OAAO,EAAE;AAAA,EACnD;AAAA,EAEA,OAAO;AAAA,IACN,SAAS,OAAO,cAAc;AAAA,IAC9B,YAAY,OAAO,iBAAiB;AAAA,IACpC,WAAW,OAAO,gBAAgB;AAAA,IAClC,QAAQ,OAAO,aAAa;AAAA,IAC5B,OAAO,OAAO,OAAO,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,IAAI,GAAG,CAAC;AAAA,EACvD;AAAA;AAMM,SAAS,WAAW,GAAW;AAAA,EACrC,OAAO;AAAA;",
|
|
10
|
+
"debugId": "D0A7A5EB2FBB9F6664756E2164756E21",
|
|
11
11
|
"names": []
|
|
12
12
|
}
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/queue/listener.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import postgres from \"postgres\";\n\nconst CHANNEL_NEW_JOB = \"streams:new_job\";\n\n/**\n * Listen for notifications on a channel\n * Uses a dedicated connection for LISTEN\n */\nexport async function listen(\n
|
|
5
|
+
"import postgres from \"postgres\";\n\nconst CHANNEL_NEW_JOB = \"streams:new_job\";\n\n/**\n * Listen for notifications on a channel\n * Uses a dedicated connection for LISTEN\n */\nexport async function listen(\n\tchannel: string,\n\tcallback: (payload?: string) => void,\n): Promise<() => Promise<void>> {\n\tconst connectionString = process.env.DATABASE_URL;\n\tif (!connectionString) {\n\t\tthrow new Error(\"DATABASE_URL is required\");\n\t}\n\n\t// Each listener gets its own connection\n\tconst client = postgres(connectionString, {\n\t\tmax: 1,\n\t\tonnotice: () => {}, // Ignore notices\n\t});\n\n\tawait client.listen(channel, (payload) => {\n\t\tcallback(payload);\n\t});\n\n\t// Return cleanup function\n\treturn async () => {\n\t\tawait client.end();\n\t};\n}\n\n/**\n * Send a notification on a channel\n */\nexport async function notify(channel: string, payload?: string): Promise<void> {\n\tconst connectionString = process.env.DATABASE_URL;\n\tif (!connectionString) {\n\t\tthrow new Error(\"DATABASE_URL is required\");\n\t}\n\n\tconst client = postgres(connectionString, { max: 1 });\n\n\ttry {\n\t\tif (payload) {\n\t\t\tawait client`SELECT pg_notify(${channel}, ${payload})`;\n\t\t} else {\n\t\t\tawait client`SELECT pg_notify(${channel}, '')`;\n\t\t}\n\t} finally {\n\t\tawait client.end();\n\t}\n}\n\n/**\n * Listen for new job notifications\n * Convenience wrapper for the common use case\n */\nexport async function listenForJobs(\n\tcallback: (payload?: string) => void,\n): Promise<() => Promise<void>> {\n\treturn listen(CHANNEL_NEW_JOB, callback);\n}\n\n/**\n * Notify workers about new jobs\n */\nexport async function notifyNewJob(streamId?: string): Promise<void> {\n\treturn notify(CHANNEL_NEW_JOB, streamId);\n}\n\nexport { CHANNEL_NEW_JOB };\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": ";;;;;;;;;;;;;;;;;AAAA;AAEA,IAAM,kBAAkB;AAMxB,eAAsB,MAAM,
|
|
7
|
+
"mappings": ";;;;;;;;;;;;;;;;;AAAA;AAEA,IAAM,kBAAkB;AAMxB,eAAsB,MAAM,CAC3B,SACA,UAC+B;AAAA,EAC/B,MAAM,mBAAmB,QAAQ,IAAI;AAAA,EACrC,IAAI,CAAC,kBAAkB;AAAA,IACtB,MAAM,IAAI,MAAM,0BAA0B;AAAA,EAC3C;AAAA,EAGA,MAAM,SAAS,SAAS,kBAAkB;AAAA,IACzC,KAAK;AAAA,IACL,UAAU,MAAM;AAAA,EACjB,CAAC;AAAA,EAED,MAAM,OAAO,OAAO,SAAS,CAAC,YAAY;AAAA,IACzC,SAAS,OAAO;AAAA,GAChB;AAAA,EAGD,OAAO,YAAY;AAAA,IAClB,MAAM,OAAO,IAAI;AAAA;AAAA;AAOnB,eAAsB,MAAM,CAAC,SAAiB,SAAiC;AAAA,EAC9E,MAAM,mBAAmB,QAAQ,IAAI;AAAA,EACrC,IAAI,CAAC,kBAAkB;AAAA,IACtB,MAAM,IAAI,MAAM,0BAA0B;AAAA,EAC3C;AAAA,EAEA,MAAM,SAAS,SAAS,kBAAkB,EAAE,KAAK,EAAE,CAAC;AAAA,EAEpD,IAAI;AAAA,IACH,IAAI,SAAS;AAAA,MACZ,MAAM,0BAA0B,YAAY;AAAA,IAC7C,EAAO;AAAA,MACN,MAAM,0BAA0B;AAAA;AAAA,YAEhC;AAAA,IACD,MAAM,OAAO,IAAI;AAAA;AAAA;AAQnB,eAAsB,aAAa,CAClC,UAC+B;AAAA,EAC/B,OAAO,OAAO,iBAAiB,QAAQ;AAAA;AAMxC,eAAsB,YAAY,CAAC,UAAkC;AAAA,EACpE,OAAO,OAAO,iBAAiB,QAAQ;AAAA;",
|
|
8
8
|
"debugId": "694EC70CE737295164756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
|
@@ -42,8 +42,12 @@ function getDb(connectionString) {
|
|
|
42
42
|
if (!db) {
|
|
43
43
|
const url = connectionString || process.env.DATABASE_URL || "postgres://postgres:postgres@localhost:5432/streams_dev";
|
|
44
44
|
const isLocal = url.includes("localhost") || url.includes("127.0.0.1") || url.includes("@postgres:");
|
|
45
|
+
const poolMax = Number.parseInt(process.env.DATABASE_POOL_MAX ?? "20", 10);
|
|
45
46
|
rawClient = postgres(url, {
|
|
46
|
-
|
|
47
|
+
max: poolMax,
|
|
48
|
+
ssl: isLocal ? undefined : {
|
|
49
|
+
rejectUnauthorized: process.env.NODE_TLS_REJECT_UNAUTHORIZED !== "0"
|
|
50
|
+
}
|
|
47
51
|
});
|
|
48
52
|
db = new Kysely({
|
|
49
53
|
dialect: new PostgresJSDialect({ postgres: rawClient })
|
|
@@ -100,5 +104,5 @@ export {
|
|
|
100
104
|
recoverStaleJobs
|
|
101
105
|
};
|
|
102
106
|
|
|
103
|
-
//# debugId=
|
|
107
|
+
//# debugId=1F195B570B55546D64756E2164756E21
|
|
104
108
|
//# sourceMappingURL=recovery.js.map
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/db/jsonb.ts", "../src/db/index.ts", "../src/queue/recovery.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import {
|
|
6
|
-
"import { Kysely } from \"kysely\";\nimport { PostgresJSDialect } from \"kysely-postgres-js\";\nimport postgres from \"postgres\";\nimport type { Database } from \"./types.ts\";\n\nlet db: Kysely<Database> | null = null;\nlet rawClient: ReturnType<typeof postgres> | null = null;\n\nexport function getDb(connectionString?: string): Kysely<Database> {\n
|
|
7
|
-
"import { sql } from \"kysely\";\nimport { getDb } from \"../db/index.ts\";\n\n/**\n * Recover jobs that have been locked for longer than the threshold\n * These are likely from crashed workers\n *\n * @param staleThresholdMinutes - Minutes after which a locked job is considered stale\n * @returns Number of recovered jobs\n */\nexport async function recoverStaleJobs(\n
|
|
5
|
+
"import { type RawBuilder, sql } from \"kysely\";\n\n/**\n * Safely encode a JS value as a JSONB literal for Kysely inserts/updates.\n * Kysely + postgres.js double-encodes JSON when using parameterized queries\n * with ::jsonb casts. This uses sql.raw to inline a properly escaped literal.\n */\nexport function jsonb(value: unknown): RawBuilder<unknown> {\n\tconst escaped = JSON.stringify(value).replace(/'/g, \"''\");\n\treturn sql`${sql.raw(`'${escaped}'::jsonb`)}`;\n}\n\n/**\n * Safely parse a JSONB value from the database.\n * Handles double-encoded strings where postgres.js returns a JSON string\n * instead of a parsed object.\n */\nexport function parseJsonb<T = unknown>(value: unknown): T {\n\tif (typeof value === \"string\") {\n\t\ttry {\n\t\t\treturn JSON.parse(value) as T;\n\t\t} catch {\n\t\t\treturn value as T;\n\t\t}\n\t}\n\treturn (value ?? {}) as T;\n}\n",
|
|
6
|
+
"import { Kysely } from \"kysely\";\nimport { PostgresJSDialect } from \"kysely-postgres-js\";\nimport postgres from \"postgres\";\nimport type { Database } from \"./types.ts\";\n\nlet db: Kysely<Database> | null = null;\nlet rawClient: ReturnType<typeof postgres> | null = null;\n\nexport function getDb(connectionString?: string): Kysely<Database> {\n\tif (!db) {\n\t\tconst url =\n\t\t\tconnectionString ||\n\t\t\tprocess.env.DATABASE_URL ||\n\t\t\t\"postgres://postgres:postgres@localhost:5432/streams_dev\";\n\n\t\t// Always use SSL for remote databases, just disable cert verification if needed\n\t\tconst isLocal =\n\t\t\turl.includes(\"localhost\") ||\n\t\t\turl.includes(\"127.0.0.1\") ||\n\t\t\turl.includes(\"@postgres:\");\n\t\tconst poolMax = Number.parseInt(process.env.DATABASE_POOL_MAX ?? \"20\", 10);\n\t\trawClient = postgres(url, {\n\t\t\tmax: poolMax,\n\t\t\tssl: isLocal\n\t\t\t\t? undefined\n\t\t\t\t: {\n\t\t\t\t\t\trejectUnauthorized:\n\t\t\t\t\t\t\tprocess.env.NODE_TLS_REJECT_UNAUTHORIZED !== \"0\",\n\t\t\t\t\t},\n\t\t});\n\t\tdb = new Kysely<Database>({\n\t\t\tdialect: new PostgresJSDialect({ postgres: rawClient }),\n\t\t});\n\t}\n\treturn db;\n}\n\n/** Raw postgres.js client for dynamic schema DDL (CREATE SCHEMA, DROP, etc.) */\nexport function getRawClient(): ReturnType<typeof postgres> {\n\tif (!rawClient) getDb();\n\treturn rawClient!;\n}\n\n/** Close the DB connection pool. Call in CLI commands to allow process exit. */\nexport async function closeDb(): Promise<void> {\n\tif (db) {\n\t\tawait db.destroy();\n\t\tdb = null;\n\t}\n\tif (rawClient) {\n\t\tawait rawClient.end();\n\t\trawClient = null;\n\t}\n}\n\nimport { sql } from \"kysely\";\nexport { sql };\nexport * from \"./types.ts\";\nexport { jsonb, parseJsonb } from \"./jsonb.ts\";\n",
|
|
7
|
+
"import { sql } from \"kysely\";\nimport { getDb } from \"../db/index.ts\";\n\n/**\n * Recover jobs that have been locked for longer than the threshold\n * These are likely from crashed workers\n *\n * @param staleThresholdMinutes - Minutes after which a locked job is considered stale\n * @returns Number of recovered jobs\n */\nexport async function recoverStaleJobs(\n\tstaleThresholdMinutes = 5,\n): Promise<number> {\n\tconst { rows } = await sql`\n UPDATE jobs\n SET\n status = 'pending',\n locked_at = NULL,\n locked_by = NULL\n WHERE\n status = 'processing'\n AND locked_at < NOW() - INTERVAL '${sql.raw(staleThresholdMinutes.toString())} minutes'\n RETURNING id\n `.execute(getDb());\n\n\treturn rows.length;\n}\n\n/**\n * Run periodic stale job recovery\n * Returns a cleanup function to stop the interval\n */\nexport function startRecoveryLoop(\n\tintervalMs = 60000, // 1 minute\n\tstaleThresholdMinutes = 5,\n): () => void {\n\tconst intervalId = setInterval(async () => {\n\t\ttry {\n\t\t\tconst recovered = await recoverStaleJobs(staleThresholdMinutes);\n\t\t\tif (recovered > 0) {\n\t\t\t\tconsole.log(`Recovered ${recovered} stale jobs`);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconsole.error(\"Error recovering stale jobs:\", error);\n\t\t}\n\t}, intervalMs);\n\n\treturn () => clearInterval(intervalId);\n}\n"
|
|
8
8
|
],
|
|
9
|
-
"mappings": ";;;;;;;;;;;;;;;;;AAAA;AAOO,SAAS,KAAK,CAAC,OAAqC;AAAA,
|
|
10
|
-
"debugId": "
|
|
9
|
+
"mappings": ";;;;;;;;;;;;;;;;;AAAA;AAOO,SAAS,KAAK,CAAC,OAAqC;AAAA,EAC1D,MAAM,UAAU,KAAK,UAAU,KAAK,EAAE,QAAQ,MAAM,IAAI;AAAA,EACxD,OAAO,MAAM,IAAI,IAAI,IAAI,iBAAiB;AAAA;AAQpC,SAAS,UAAuB,CAAC,OAAmB;AAAA,EAC1D,IAAI,OAAO,UAAU,UAAU;AAAA,IAC9B,IAAI;AAAA,MACH,OAAO,KAAK,MAAM,KAAK;AAAA,MACtB,MAAM;AAAA,MACP,OAAO;AAAA;AAAA,EAET;AAAA,EACA,OAAQ,SAAS,CAAC;AAAA;;;ACzBnB;AACA;AACA;AAqDA,gBAAS;AAlDT,IAAI,KAA8B;AAClC,IAAI,YAAgD;AAE7C,SAAS,KAAK,CAAC,kBAA6C;AAAA,EAClE,IAAI,CAAC,IAAI;AAAA,IACR,MAAM,MACL,oBACA,QAAQ,IAAI,gBACZ;AAAA,IAGD,MAAM,UACL,IAAI,SAAS,WAAW,KACxB,IAAI,SAAS,WAAW,KACxB,IAAI,SAAS,YAAY;AAAA,IAC1B,MAAM,UAAU,OAAO,SAAS,QAAQ,IAAI,qBAAqB,MAAM,EAAE;AAAA,IACzE,YAAY,SAAS,KAAK;AAAA,MACzB,KAAK;AAAA,MACL,KAAK,UACF,YACA;AAAA,QACA,oBACC,QAAQ,IAAI,iCAAiC;AAAA,MAC/C;AAAA,IACH,CAAC;AAAA,IACD,KAAK,IAAI,OAAiB;AAAA,MACzB,SAAS,IAAI,kBAAkB,EAAE,UAAU,UAAU,CAAC;AAAA,IACvD,CAAC;AAAA,EACF;AAAA,EACA,OAAO;AAAA;AAID,SAAS,YAAY,GAAgC;AAAA,EAC3D,IAAI,CAAC;AAAA,IAAW,MAAM;AAAA,EACtB,OAAO;AAAA;AAIR,eAAsB,OAAO,GAAkB;AAAA,EAC9C,IAAI,IAAI;AAAA,IACP,MAAM,GAAG,QAAQ;AAAA,IACjB,KAAK;AAAA,EACN;AAAA,EACA,IAAI,WAAW;AAAA,IACd,MAAM,UAAU,IAAI;AAAA,IACpB,YAAY;AAAA,EACb;AAAA;;ACpDD,gBAAS;AAUT,eAAsB,gBAAgB,CACrC,wBAAwB,GACN;AAAA,EAClB,QAAQ,SAAS,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0CAQkB,KAAI,IAAI,sBAAsB,SAAS,CAAC;AAAA;AAAA,IAE9E,QAAQ,MAAM,CAAC;AAAA,EAElB,OAAO,KAAK;AAAA;AAON,SAAS,iBAAiB,CAChC,aAAa,OACb,wBAAwB,GACX;AAAA,EACb,MAAM,aAAa,YAAY,YAAY;AAAA,IAC1C,IAAI;AAAA,MACH,MAAM,YAAY,MAAM,iBAAiB,qBAAqB;AAAA,MAC9D,IAAI,YAAY,GAAG;AAAA,QAClB,QAAQ,IAAI,aAAa,sBAAsB;AAAA,MAChD;AAAA,MACC,OAAO,OAAO;AAAA,MACf,QAAQ,MAAM,gCAAgC,KAAK;AAAA;AAAA,KAElD,UAAU;AAAA,EAEb,OAAO,MAAM,cAAc,UAAU;AAAA;",
|
|
10
|
+
"debugId": "1F195B570B55546D64756E2164756E21",
|
|
11
11
|
"names": []
|
|
12
12
|
}
|
|
@@ -15,8 +15,8 @@ var __export = (target, all) => {
|
|
|
15
15
|
};
|
|
16
16
|
|
|
17
17
|
// src/schemas/filters.ts
|
|
18
|
-
import { z } from "zod/v4";
|
|
19
18
|
import { isValidAddress as _isValidAddress } from "@secondlayer/stacks";
|
|
19
|
+
import { z } from "zod/v4";
|
|
20
20
|
var isValidAddress = _isValidAddress;
|
|
21
21
|
var stacksPrincipal = z.string().refine((val) => {
|
|
22
22
|
const parts = val.split(".");
|
|
@@ -134,5 +134,5 @@ export {
|
|
|
134
134
|
ContractCallFilterSchema
|
|
135
135
|
};
|
|
136
136
|
|
|
137
|
-
//# debugId=
|
|
137
|
+
//# debugId=A8EC768F22E32CBD64756E2164756E21
|
|
138
138
|
//# sourceMappingURL=filters.js.map
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/schemas/filters.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import {
|
|
5
|
+
"import { isValidAddress as _isValidAddress } from \"@secondlayer/stacks\";\nimport { z } from \"zod/v4\";\n\nconst isValidAddress = _isValidAddress as (addr: string) => boolean;\n\n/** Validate a Stacks principal (standard or contract, e.g. SP2J...ABC or SP2J...ABC.contract-name) */\nconst stacksPrincipal = z.string().refine((val) => {\n\tconst parts = val.split(\".\");\n\tif (parts.length > 2) return false;\n\treturn isValidAddress(parts[0]!);\n}, \"Invalid Stacks principal address\");\n\n// Base filter with common fields\nconst baseFilter = {\n\t// Optional: filter by sender\n\tsender: stacksPrincipal.optional(),\n\t// Optional: filter by recipient\n\trecipient: stacksPrincipal.optional(),\n};\n\n// Type exports — defined first so they can annotate schemas\nexport interface StxTransferFilter {\n\ttype: \"stx_transfer\";\n\tsender?: string;\n\trecipient?: string;\n\tminAmount?: number;\n\tmaxAmount?: number;\n}\n\nexport interface StxMintFilter {\n\ttype: \"stx_mint\";\n\trecipient?: string;\n\tminAmount?: number;\n}\n\nexport interface StxBurnFilter {\n\ttype: \"stx_burn\";\n\tsender?: string;\n\tminAmount?: number;\n}\n\nexport interface StxLockFilter {\n\ttype: \"stx_lock\";\n\tlockedAddress?: string;\n\tminAmount?: number;\n}\n\nexport interface FtTransferFilter {\n\ttype: \"ft_transfer\";\n\tsender?: string;\n\trecipient?: string;\n\tassetIdentifier?: string;\n\tminAmount?: number;\n}\n\nexport interface FtMintFilter {\n\ttype: \"ft_mint\";\n\trecipient?: string;\n\tassetIdentifier?: string;\n\tminAmount?: number;\n}\n\nexport interface FtBurnFilter {\n\ttype: \"ft_burn\";\n\tsender?: string;\n\tassetIdentifier?: string;\n\tminAmount?: number;\n}\n\nexport interface NftTransferFilter {\n\ttype: \"nft_transfer\";\n\tsender?: string;\n\trecipient?: string;\n\tassetIdentifier?: string;\n\ttokenId?: string;\n}\n\nexport interface NftMintFilter {\n\ttype: \"nft_mint\";\n\trecipient?: string;\n\tassetIdentifier?: string;\n\ttokenId?: string;\n}\n\nexport interface NftBurnFilter {\n\ttype: \"nft_burn\";\n\tsender?: string;\n\tassetIdentifier?: string;\n\ttokenId?: string;\n}\n\nexport interface ContractCallFilter {\n\ttype: \"contract_call\";\n\tcontractId?: string;\n\tfunctionName?: string;\n\tcaller?: string;\n}\n\nexport interface ContractDeployFilter {\n\ttype: \"contract_deploy\";\n\tdeployer?: string;\n\tcontractName?: string;\n}\n\nexport interface PrintEventFilter {\n\ttype: \"print_event\";\n\tcontractId?: string;\n\ttopic?: string;\n\tcontains?: string;\n}\n\nexport type StreamFilter =\n\t| StxTransferFilter\n\t| StxMintFilter\n\t| StxBurnFilter\n\t| StxLockFilter\n\t| FtTransferFilter\n\t| FtMintFilter\n\t| FtBurnFilter\n\t| NftTransferFilter\n\t| NftMintFilter\n\t| NftBurnFilter\n\t| ContractCallFilter\n\t| ContractDeployFilter\n\t| PrintEventFilter;\n\n// STX Transfer Filter\nexport const StxTransferFilterSchema: z.ZodType<StxTransferFilter> = z.object({\n\ttype: z.literal(\"stx_transfer\"),\n\t...baseFilter,\n\t// Optional: minimum amount in microSTX\n\tminAmount: z.coerce.number().int().positive().optional(),\n\t// Optional: maximum amount in microSTX\n\tmaxAmount: z.coerce.number().int().positive().optional(),\n});\n\n// STX Mint Filter\nexport const StxMintFilterSchema: z.ZodType<StxMintFilter> = z.object({\n\ttype: z.literal(\"stx_mint\"),\n\trecipient: stacksPrincipal.optional(),\n\tminAmount: z.coerce.number().int().positive().optional(),\n});\n\n// STX Burn Filter\nexport const StxBurnFilterSchema: z.ZodType<StxBurnFilter> = z.object({\n\ttype: z.literal(\"stx_burn\"),\n\tsender: stacksPrincipal.optional(),\n\tminAmount: z.coerce.number().int().positive().optional(),\n});\n\n// STX Lock Filter\nexport const StxLockFilterSchema: z.ZodType<StxLockFilter> = z.object({\n\ttype: z.literal(\"stx_lock\"),\n\tlockedAddress: stacksPrincipal.optional(),\n\tminAmount: z.coerce.number().int().positive().optional(),\n});\n\n// FT Transfer Filter\nexport const FtTransferFilterSchema: z.ZodType<FtTransferFilter> = z.object({\n\ttype: z.literal(\"ft_transfer\"),\n\t...baseFilter,\n\t// Contract that defines the token (e.g., SP3K8BC0PPEVCV7NZ6QSRWPQ2JE9E5B6N3PA0KBR9.token-wstx)\n\tassetIdentifier: z.string().optional(),\n\tminAmount: z.coerce.number().int().positive().optional(),\n});\n\n// FT Mint Filter\nexport const FtMintFilterSchema: z.ZodType<FtMintFilter> = z.object({\n\ttype: z.literal(\"ft_mint\"),\n\trecipient: stacksPrincipal.optional(),\n\tassetIdentifier: z.string().optional(),\n\tminAmount: z.coerce.number().int().positive().optional(),\n});\n\n// FT Burn Filter\nexport const FtBurnFilterSchema: z.ZodType<FtBurnFilter> = z.object({\n\ttype: z.literal(\"ft_burn\"),\n\tsender: stacksPrincipal.optional(),\n\tassetIdentifier: z.string().optional(),\n\tminAmount: z.coerce.number().int().positive().optional(),\n});\n\n// NFT Transfer Filter\nexport const NftTransferFilterSchema: z.ZodType<NftTransferFilter> = z.object({\n\ttype: z.literal(\"nft_transfer\"),\n\t...baseFilter,\n\tassetIdentifier: z.string().optional(),\n\t// Optional: filter by specific token ID (Clarity value as hex)\n\ttokenId: z.string().optional(),\n});\n\n// NFT Mint Filter\nexport const NftMintFilterSchema: z.ZodType<NftMintFilter> = z.object({\n\ttype: z.literal(\"nft_mint\"),\n\trecipient: stacksPrincipal.optional(),\n\tassetIdentifier: z.string().optional(),\n\ttokenId: z.string().optional(),\n});\n\n// NFT Burn Filter\nexport const NftBurnFilterSchema: z.ZodType<NftBurnFilter> = z.object({\n\ttype: z.literal(\"nft_burn\"),\n\tsender: stacksPrincipal.optional(),\n\tassetIdentifier: z.string().optional(),\n\ttokenId: z.string().optional(),\n});\n\n// Contract Call Filter\nexport const ContractCallFilterSchema: z.ZodType<ContractCallFilter> = z.object(\n\t{\n\t\ttype: z.literal(\"contract_call\"),\n\t\t// Contract being called\n\t\tcontractId: stacksPrincipal.optional(),\n\t\t// Function name (supports wildcards with *)\n\t\tfunctionName: z.string().optional(),\n\t\t// Caller address\n\t\tcaller: stacksPrincipal.optional(),\n\t},\n);\n\n// Contract Deploy Filter\nexport const ContractDeployFilterSchema: z.ZodType<ContractDeployFilter> =\n\tz.object({\n\t\ttype: z.literal(\"contract_deploy\"),\n\t\t// Deployer address\n\t\tdeployer: stacksPrincipal.optional(),\n\t\t// Contract name pattern (supports wildcards)\n\t\tcontractName: z.string().optional(),\n\t});\n\n// Print Event Filter (smart contract events)\nexport const PrintEventFilterSchema: z.ZodType<PrintEventFilter> = z.object({\n\ttype: z.literal(\"print_event\"),\n\t// Contract emitting the event\n\tcontractId: stacksPrincipal.optional(),\n\t// Topic/name of the event\n\ttopic: z.string().optional(),\n\t// Search for substring in event data\n\tcontains: z.string().optional(),\n});\n\n// Union of all filter types\nexport const StreamFilterSchema: z.ZodType<StreamFilter> = z.discriminatedUnion(\n\t\"type\",\n\t[\n\t\tStxTransferFilterSchema as any,\n\t\tStxMintFilterSchema as any,\n\t\tStxBurnFilterSchema as any,\n\t\tStxLockFilterSchema as any,\n\t\tFtTransferFilterSchema as any,\n\t\tFtMintFilterSchema as any,\n\t\tFtBurnFilterSchema as any,\n\t\tNftTransferFilterSchema as any,\n\t\tNftMintFilterSchema as any,\n\t\tNftBurnFilterSchema as any,\n\t\tContractCallFilterSchema as any,\n\t\tContractDeployFilterSchema as any,\n\t\tPrintEventFilterSchema as any,\n\t],\n);\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": ";;;;;;;;;;;;;;;;;AAAA
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "A8EC768F22E32CBD64756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|