@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.
Files changed (73) hide show
  1. package/dist/src/crypto/hmac.js +2 -2
  2. package/dist/src/crypto/hmac.js.map +3 -3
  3. package/dist/src/db/index.d.ts +18 -3
  4. package/dist/src/db/index.js +6 -2
  5. package/dist/src/db/index.js.map +4 -4
  6. package/dist/src/db/jsonb.js.map +2 -2
  7. package/dist/src/db/queries/accounts.d.ts +16 -3
  8. package/dist/src/db/queries/accounts.js +6 -3
  9. package/dist/src/db/queries/accounts.js.map +3 -3
  10. package/dist/src/db/queries/integrity.d.ts +15 -2
  11. package/dist/src/db/queries/integrity.js.map +2 -2
  12. package/dist/src/db/queries/metrics.d.ts +15 -2
  13. package/dist/src/db/queries/metrics.js.map +2 -2
  14. package/dist/src/db/queries/subgraph-gaps.d.ts +305 -0
  15. package/dist/src/db/queries/subgraph-gaps.js +103 -0
  16. package/dist/src/db/queries/subgraph-gaps.js.map +10 -0
  17. package/dist/src/db/queries/subgraphs.d.ts +15 -2
  18. package/dist/src/db/queries/subgraphs.js +2 -2
  19. package/dist/src/db/queries/subgraphs.js.map +4 -4
  20. package/dist/src/db/queries/usage.d.ts +23 -3
  21. package/dist/src/db/queries/usage.js +35 -3
  22. package/dist/src/db/queries/usage.js.map +4 -4
  23. package/dist/src/db/schema.d.ts +18 -3
  24. package/dist/src/env.js.map +2 -2
  25. package/dist/src/errors.d.ts +17 -4
  26. package/dist/src/errors.js +14 -2
  27. package/dist/src/errors.js.map +3 -3
  28. package/dist/src/index.d.ts +78 -6
  29. package/dist/src/index.js +26 -8
  30. package/dist/src/index.js.map +12 -12
  31. package/dist/src/lib/plans.js.map +2 -2
  32. package/dist/src/logger.js.map +3 -3
  33. package/dist/src/node/archive-client.js +22 -6
  34. package/dist/src/node/archive-client.js.map +5 -5
  35. package/dist/src/node/client.js.map +2 -2
  36. package/dist/src/node/hiro-client.js +47 -11
  37. package/dist/src/node/hiro-client.js.map +5 -5
  38. package/dist/src/node/hiro-pg-client.js +131 -26
  39. package/dist/src/node/hiro-pg-client.js.map +3 -3
  40. package/dist/src/node/local-client.d.ts +15 -2
  41. package/dist/src/node/local-client.js.map +2 -2
  42. package/dist/src/queue/index.js +8 -4
  43. package/dist/src/queue/index.js.map +5 -5
  44. package/dist/src/queue/listener.js.map +2 -2
  45. package/dist/src/queue/recovery.js +6 -2
  46. package/dist/src/queue/recovery.js.map +5 -5
  47. package/dist/src/schemas/filters.js +2 -2
  48. package/dist/src/schemas/filters.js.map +3 -3
  49. package/dist/src/schemas/index.d.ts +45 -1
  50. package/dist/src/schemas/index.js +5 -3
  51. package/dist/src/schemas/index.js.map +5 -5
  52. package/dist/src/schemas/subgraphs.d.ts +45 -1
  53. package/dist/src/schemas/subgraphs.js.map +2 -2
  54. package/dist/src/types.d.ts +1 -1
  55. package/migrations/0001_initial.ts +295 -159
  56. package/migrations/0002_api_keys.ts +44 -28
  57. package/migrations/0003_tenant_isolation.ts +116 -107
  58. package/migrations/0004_accounts_and_usage.ts +81 -75
  59. package/migrations/0005_sessions.ts +33 -33
  60. package/migrations/0006_tx_index.ts +6 -2
  61. package/migrations/0007_contracts.ts +38 -24
  62. package/migrations/0008_drop_contracts.ts +33 -19
  63. package/migrations/0009_waitlist.ts +12 -12
  64. package/migrations/0010_waitlist_status.ts +5 -5
  65. package/migrations/0011_account_insights.ts +52 -52
  66. package/migrations/0012_view_health_snapshots.ts +21 -21
  67. package/migrations/0013_view_processing_stats.ts +32 -32
  68. package/migrations/0014_view_table_snapshots.ts +24 -24
  69. package/migrations/0015_rename_views_to_subgraphs.ts +137 -75
  70. package/migrations/0016_rename_webhook_to_endpoint.ts +12 -4
  71. package/migrations/0017_security_hardening.ts +32 -0
  72. package/migrations/0018_subgraph_gaps.ts +39 -0
  73. package/package.json +147 -143
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../src/node/client.ts"],
4
4
  "sourcesContent": [
5
- "\nexport interface NodeInfo {\n peer_version: number;\n pox_consensus: string;\n burn_block_height: number;\n stable_pox_consensus: string;\n stable_burn_block_height: number;\n server_version: string;\n network_id: number;\n parent_network_id: number;\n stacks_tip_height: number;\n stacks_tip: string;\n stacks_tip_consensus_hash: string;\n genesis_chainstate_hash: string;\n}\n\nexport interface BlockResponse {\n hash: string;\n height: number;\n parent_block_hash: string;\n burn_block_height: number;\n burn_block_hash: string;\n burn_block_time: number;\n index_block_hash: string;\n parent_index_block_hash: string;\n miner_txid: string;\n txs: string[];\n // Full block data varies by endpoint — kept minimal for fetch use case\n}\n\nexport class StacksNodeClient {\n private rpcUrl: string;\n\n constructor(rpcUrl?: string) {\n this.rpcUrl = rpcUrl || process.env.STACKS_NODE_RPC_URL || \"http://localhost:20443\";\n }\n\n async getInfo(): Promise<NodeInfo> {\n const res = await fetch(`${this.rpcUrl}/v2/info`, {\n signal: AbortSignal.timeout(10_000),\n });\n if (!res.ok) {\n throw new Error(`Node RPC /v2/info returned ${res.status}`);\n }\n return res.json() as Promise<NodeInfo>;\n }\n\n async getBlock(height: number): Promise<BlockResponse | null> {\n // Stacks API v2 block-by-height endpoint\n const res = await fetch(`${this.rpcUrl}/v2/blocks/${height}`, {\n signal: AbortSignal.timeout(30_000),\n });\n if (res.status === 404) return null;\n if (!res.ok) {\n throw new Error(`Node RPC /v2/blocks/${height} returned ${res.status}`);\n }\n return res.json() as Promise<BlockResponse>;\n }\n\n async isHealthy(): Promise<boolean> {\n try {\n const info = await this.getInfo();\n return info.stacks_tip_height > 0;\n } catch {\n return false;\n }\n }\n\n async getContractAbi(contractId: string): Promise<unknown> {\n const dotIdx = contractId.indexOf(\".\");\n const address = contractId.slice(0, dotIdx);\n const name = contractId.slice(dotIdx + 1);\n const res = await fetch(`${this.rpcUrl}/v2/contracts/interface/${address}/${name}`, {\n signal: AbortSignal.timeout(30_000),\n });\n if (!res.ok) {\n throw new Error(`Node RPC /v2/contracts/interface/${address}/${name} returned ${res.status}`);\n }\n return res.json();\n }\n\n getRpcUrl(): string {\n return this.rpcUrl;\n }\n}\n"
5
+ "export interface NodeInfo {\n\tpeer_version: number;\n\tpox_consensus: string;\n\tburn_block_height: number;\n\tstable_pox_consensus: string;\n\tstable_burn_block_height: number;\n\tserver_version: string;\n\tnetwork_id: number;\n\tparent_network_id: number;\n\tstacks_tip_height: number;\n\tstacks_tip: string;\n\tstacks_tip_consensus_hash: string;\n\tgenesis_chainstate_hash: string;\n}\n\nexport interface BlockResponse {\n\thash: string;\n\theight: number;\n\tparent_block_hash: string;\n\tburn_block_height: number;\n\tburn_block_hash: string;\n\tburn_block_time: number;\n\tindex_block_hash: string;\n\tparent_index_block_hash: string;\n\tminer_txid: string;\n\ttxs: string[];\n\t// Full block data varies by endpoint — kept minimal for fetch use case\n}\n\nexport class StacksNodeClient {\n\tprivate rpcUrl: string;\n\n\tconstructor(rpcUrl?: string) {\n\t\tthis.rpcUrl =\n\t\t\trpcUrl || process.env.STACKS_NODE_RPC_URL || \"http://localhost:20443\";\n\t}\n\n\tasync getInfo(): Promise<NodeInfo> {\n\t\tconst res = await fetch(`${this.rpcUrl}/v2/info`, {\n\t\t\tsignal: AbortSignal.timeout(10_000),\n\t\t});\n\t\tif (!res.ok) {\n\t\t\tthrow new Error(`Node RPC /v2/info returned ${res.status}`);\n\t\t}\n\t\treturn res.json() as Promise<NodeInfo>;\n\t}\n\n\tasync getBlock(height: number): Promise<BlockResponse | null> {\n\t\t// Stacks API v2 block-by-height endpoint\n\t\tconst res = await fetch(`${this.rpcUrl}/v2/blocks/${height}`, {\n\t\t\tsignal: AbortSignal.timeout(30_000),\n\t\t});\n\t\tif (res.status === 404) return null;\n\t\tif (!res.ok) {\n\t\t\tthrow new Error(`Node RPC /v2/blocks/${height} returned ${res.status}`);\n\t\t}\n\t\treturn res.json() as Promise<BlockResponse>;\n\t}\n\n\tasync isHealthy(): Promise<boolean> {\n\t\ttry {\n\t\t\tconst info = await this.getInfo();\n\t\t\treturn info.stacks_tip_height > 0;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tasync getContractAbi(contractId: string): Promise<unknown> {\n\t\tconst dotIdx = contractId.indexOf(\".\");\n\t\tconst address = contractId.slice(0, dotIdx);\n\t\tconst name = contractId.slice(dotIdx + 1);\n\t\tconst res = await fetch(\n\t\t\t`${this.rpcUrl}/v2/contracts/interface/${address}/${name}`,\n\t\t\t{\n\t\t\t\tsignal: AbortSignal.timeout(30_000),\n\t\t\t},\n\t\t);\n\t\tif (!res.ok) {\n\t\t\tthrow new Error(\n\t\t\t\t`Node RPC /v2/contracts/interface/${address}/${name} returned ${res.status}`,\n\t\t\t);\n\t\t}\n\t\treturn res.json();\n\t}\n\n\tgetRpcUrl(): string {\n\t\treturn this.rpcUrl;\n\t}\n}\n"
6
6
  ],
7
- "mappings": ";;;;;;;;;;;;;;;;;AA8BO,MAAM,iBAAiB;AAAA,EACpB;AAAA,EAER,WAAW,CAAC,QAAiB;AAAA,IAC3B,KAAK,SAAS,UAAU,QAAQ,IAAI,uBAAuB;AAAA;AAAA,OAGvD,QAAO,GAAsB;AAAA,IACjC,MAAM,MAAM,MAAM,MAAM,GAAG,KAAK,kBAAkB;AAAA,MAChD,QAAQ,YAAY,QAAQ,GAAM;AAAA,IACpC,CAAC;AAAA,IACD,IAAI,CAAC,IAAI,IAAI;AAAA,MACX,MAAM,IAAI,MAAM,8BAA8B,IAAI,QAAQ;AAAA,IAC5D;AAAA,IACA,OAAO,IAAI,KAAK;AAAA;AAAA,OAGZ,SAAQ,CAAC,QAA+C;AAAA,IAE5D,MAAM,MAAM,MAAM,MAAM,GAAG,KAAK,oBAAoB,UAAU;AAAA,MAC5D,QAAQ,YAAY,QAAQ,KAAM;AAAA,IACpC,CAAC;AAAA,IACD,IAAI,IAAI,WAAW;AAAA,MAAK,OAAO;AAAA,IAC/B,IAAI,CAAC,IAAI,IAAI;AAAA,MACX,MAAM,IAAI,MAAM,uBAAuB,mBAAmB,IAAI,QAAQ;AAAA,IACxE;AAAA,IACA,OAAO,IAAI,KAAK;AAAA;AAAA,OAGZ,UAAS,GAAqB;AAAA,IAClC,IAAI;AAAA,MACF,MAAM,OAAO,MAAM,KAAK,QAAQ;AAAA,MAChC,OAAO,KAAK,oBAAoB;AAAA,MAChC,MAAM;AAAA,MACN,OAAO;AAAA;AAAA;AAAA,OAIL,eAAc,CAAC,YAAsC;AAAA,IACzD,MAAM,SAAS,WAAW,QAAQ,GAAG;AAAA,IACrC,MAAM,UAAU,WAAW,MAAM,GAAG,MAAM;AAAA,IAC1C,MAAM,OAAO,WAAW,MAAM,SAAS,CAAC;AAAA,IACxC,MAAM,MAAM,MAAM,MAAM,GAAG,KAAK,iCAAiC,WAAW,QAAQ;AAAA,MAClF,QAAQ,YAAY,QAAQ,KAAM;AAAA,IACpC,CAAC;AAAA,IACD,IAAI,CAAC,IAAI,IAAI;AAAA,MACX,MAAM,IAAI,MAAM,oCAAoC,WAAW,iBAAiB,IAAI,QAAQ;AAAA,IAC9F;AAAA,IACA,OAAO,IAAI,KAAK;AAAA;AAAA,EAGlB,SAAS,GAAW;AAAA,IAClB,OAAO,KAAK;AAAA;AAEhB;",
7
+ "mappings": ";;;;;;;;;;;;;;;;;AA6BO,MAAM,iBAAiB;AAAA,EACrB;AAAA,EAER,WAAW,CAAC,QAAiB;AAAA,IAC5B,KAAK,SACJ,UAAU,QAAQ,IAAI,uBAAuB;AAAA;AAAA,OAGzC,QAAO,GAAsB;AAAA,IAClC,MAAM,MAAM,MAAM,MAAM,GAAG,KAAK,kBAAkB;AAAA,MACjD,QAAQ,YAAY,QAAQ,GAAM;AAAA,IACnC,CAAC;AAAA,IACD,IAAI,CAAC,IAAI,IAAI;AAAA,MACZ,MAAM,IAAI,MAAM,8BAA8B,IAAI,QAAQ;AAAA,IAC3D;AAAA,IACA,OAAO,IAAI,KAAK;AAAA;AAAA,OAGX,SAAQ,CAAC,QAA+C;AAAA,IAE7D,MAAM,MAAM,MAAM,MAAM,GAAG,KAAK,oBAAoB,UAAU;AAAA,MAC7D,QAAQ,YAAY,QAAQ,KAAM;AAAA,IACnC,CAAC;AAAA,IACD,IAAI,IAAI,WAAW;AAAA,MAAK,OAAO;AAAA,IAC/B,IAAI,CAAC,IAAI,IAAI;AAAA,MACZ,MAAM,IAAI,MAAM,uBAAuB,mBAAmB,IAAI,QAAQ;AAAA,IACvE;AAAA,IACA,OAAO,IAAI,KAAK;AAAA;AAAA,OAGX,UAAS,GAAqB;AAAA,IACnC,IAAI;AAAA,MACH,MAAM,OAAO,MAAM,KAAK,QAAQ;AAAA,MAChC,OAAO,KAAK,oBAAoB;AAAA,MAC/B,MAAM;AAAA,MACP,OAAO;AAAA;AAAA;AAAA,OAIH,eAAc,CAAC,YAAsC;AAAA,IAC1D,MAAM,SAAS,WAAW,QAAQ,GAAG;AAAA,IACrC,MAAM,UAAU,WAAW,MAAM,GAAG,MAAM;AAAA,IAC1C,MAAM,OAAO,WAAW,MAAM,SAAS,CAAC;AAAA,IACxC,MAAM,MAAM,MAAM,MACjB,GAAG,KAAK,iCAAiC,WAAW,QACpD;AAAA,MACC,QAAQ,YAAY,QAAQ,KAAM;AAAA,IACnC,CACD;AAAA,IACA,IAAI,CAAC,IAAI,IAAI;AAAA,MACZ,MAAM,IAAI,MACT,oCAAoC,WAAW,iBAAiB,IAAI,QACrE;AAAA,IACD;AAAA,IACA,OAAO,IAAI,KAAK;AAAA;AAAA,EAGjB,SAAS,GAAW;AAAA,IACnB,OAAO,KAAK;AAAA;AAEd;",
8
8
  "debugId": "76864EA72C96976464756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -146,18 +146,28 @@ class HiroClient {
146
146
  }
147
147
  async fetchWithRetry(url, timeoutMs = 120000) {
148
148
  for (let attempt = 0;attempt < this.maxRetries; attempt++) {
149
- const res = await fetch(url, { headers: this.headers, signal: AbortSignal.timeout(timeoutMs) });
149
+ const res = await fetch(url, {
150
+ headers: this.headers,
151
+ signal: AbortSignal.timeout(timeoutMs)
152
+ });
150
153
  if (res.ok || res.status === 404)
151
154
  return res;
152
155
  if (res.status === 429 || res.status >= 500) {
153
156
  const delay = Math.min(1000 * Math.pow(2, attempt), 1e4);
154
- logger.info("Rate limited, retrying", { url: url.split("/").slice(-2).join("/"), attempt, delay });
157
+ logger.info("Rate limited, retrying", {
158
+ url: url.split("/").slice(-2).join("/"),
159
+ attempt,
160
+ delay
161
+ });
155
162
  await new Promise((r) => setTimeout(r, delay));
156
163
  continue;
157
164
  }
158
165
  return res;
159
166
  }
160
- return fetch(url, { headers: this.headers, signal: AbortSignal.timeout(timeoutMs) });
167
+ return fetch(url, {
168
+ headers: this.headers,
169
+ signal: AbortSignal.timeout(timeoutMs)
170
+ });
161
171
  }
162
172
  async getBlockForIndexer(height, options) {
163
173
  let block = await this.fetchBlock(height);
@@ -184,13 +194,20 @@ class HiroClient {
184
194
  });
185
195
  if (hiroTx.event_count > 0) {
186
196
  if (hiroTx.event_count > 1000) {
187
- logger.info("Fetching large event set", { txId: hiroTx.tx_id, eventCount: hiroTx.event_count, height });
197
+ logger.info("Fetching large event set", {
198
+ txId: hiroTx.tx_id,
199
+ eventCount: hiroTx.event_count,
200
+ height
201
+ });
188
202
  }
189
203
  try {
190
204
  const events = await this.fetchAllEvents(hiroTx.tx_id, baseUrl);
191
205
  eventPayloads.push(...events);
192
206
  } catch (err) {
193
- logger.warn("Failed to fetch events for backfill", { txId: hiroTx.tx_id, error: String(err) });
207
+ logger.warn("Failed to fetch events for backfill", {
208
+ txId: hiroTx.tx_id,
209
+ error: String(err)
210
+ });
194
211
  }
195
212
  }
196
213
  }
@@ -252,7 +269,10 @@ class HiroClient {
252
269
  while (true) {
253
270
  const res = await this.fetchWithRetry(`${url}/extended/v1/tx/events?tx_id=${txId}&limit=${limit}&offset=${offset}`);
254
271
  if (!res.ok) {
255
- logger.warn("Failed to fetch events from Hiro", { txId, status: res.status });
272
+ logger.warn("Failed to fetch events from Hiro", {
273
+ txId,
274
+ status: res.status
275
+ });
256
276
  break;
257
277
  }
258
278
  const data = await res.json();
@@ -408,13 +428,21 @@ function convertHiroEvent(hEvent) {
408
428
  return {
409
429
  ...base,
410
430
  type: "ft_mint_event",
411
- ft_mint_event: { asset_identifier: assetId, recipient: a.recipient, amount: a.amount }
431
+ ft_mint_event: {
432
+ asset_identifier: assetId,
433
+ recipient: a.recipient,
434
+ amount: a.amount
435
+ }
412
436
  };
413
437
  case "burn":
414
438
  return {
415
439
  ...base,
416
440
  type: "ft_burn_event",
417
- ft_burn_event: { asset_identifier: assetId, sender: a.sender, amount: a.amount }
441
+ ft_burn_event: {
442
+ asset_identifier: assetId,
443
+ sender: a.sender,
444
+ amount: a.amount
445
+ }
418
446
  };
419
447
  }
420
448
  }
@@ -437,13 +465,21 @@ function convertHiroEvent(hEvent) {
437
465
  return {
438
466
  ...base,
439
467
  type: "nft_mint_event",
440
- nft_mint_event: { asset_identifier: assetId, recipient: a.recipient, value: a.value }
468
+ nft_mint_event: {
469
+ asset_identifier: assetId,
470
+ recipient: a.recipient,
471
+ value: a.value
472
+ }
441
473
  };
442
474
  case "burn":
443
475
  return {
444
476
  ...base,
445
477
  type: "nft_burn_event",
446
- nft_burn_event: { asset_identifier: assetId, sender: a.sender, value: a.value }
478
+ nft_burn_event: {
479
+ asset_identifier: assetId,
480
+ sender: a.sender,
481
+ value: a.value
482
+ }
447
483
  };
448
484
  }
449
485
  }
@@ -468,5 +504,5 @@ export {
468
504
  HiroClient
469
505
  };
470
506
 
471
- //# debugId=84E732ABB4DEC21A64756E2164756E21
507
+ //# debugId=FEEE8A495BF3115D64756E2164756E21
472
508
  //# sourceMappingURL=hiro-client.js.map
@@ -2,11 +2,11 @@
2
2
  "version": 3,
3
3
  "sources": ["../src/env.ts", "../src/logger.ts", "../src/node/hiro-client.ts"],
4
4
  "sourcesContent": [
5
- "import { z } from \"zod/v4\";\n\n// Parse comma-separated networks\nconst networksSchema = z.string().transform((val) => {\n const networks = val.split(\",\").map((n) => n.trim()).filter(Boolean);\n const valid = [\"mainnet\", \"testnet\"];\n for (const n of networks) {\n if (!valid.includes(n)) {\n throw new Error(`Invalid network: ${n}. Must be one of: ${valid.join(\", \")}`);\n }\n }\n return networks as (\"mainnet\" | \"testnet\")[];\n});\n\ninterface EnvSchemaOutput {\n DATABASE_URL?: string;\n NETWORK?: \"mainnet\" | \"testnet\";\n NETWORKS?: (\"mainnet\" | \"testnet\")[];\n LOG_LEVEL: \"debug\" | \"info\" | \"warn\" | \"error\";\n NODE_ENV: \"development\" | \"production\" | \"test\";\n}\n\n// Cast needed: z.preprocess / z.default create different _input vs _output types\n// that z.ZodType<T> can't represent without explicit input type param\nconst envSchema: z.ZodType<EnvSchemaOutput> = z.object({\n DATABASE_URL: z.preprocess(\n (val) => (typeof val === \"string\" && val.length === 0) ? undefined : val,\n z.string().url().optional(),\n ),\n NETWORK: z.enum([\"mainnet\", \"testnet\"]).optional(),\n NETWORKS: networksSchema.optional(),\n LOG_LEVEL: z.enum([\"debug\", \"info\", \"warn\", \"error\"]).default(\"info\"),\n NODE_ENV: z.enum([\"development\", \"production\", \"test\"]).default(\"development\"),\n}) as unknown as z.ZodType<EnvSchemaOutput>;\n\nexport type Env = EnvSchemaOutput & {\n enabledNetworks: (\"mainnet\" | \"testnet\")[];\n};\n\nlet cachedEnv: Env | null = null;\n\nexport function getEnv(): Env {\n if (cachedEnv) {\n return cachedEnv;\n }\n\n const result = envSchema.safeParse(process.env);\n\n if (!result.success) {\n console.error(\"❌ Invalid environment configuration:\");\n console.error(z.treeifyError(result.error));\n throw new Error(\"Invalid environment configuration\");\n }\n\n // Compute enabled networks from NETWORKS or NETWORK\n let enabledNetworks: (\"mainnet\" | \"testnet\")[];\n if (result.data.NETWORKS && result.data.NETWORKS.length > 0) {\n enabledNetworks = result.data.NETWORKS;\n } else if (result.data.NETWORK) {\n enabledNetworks = [result.data.NETWORK];\n } else {\n enabledNetworks = [\"mainnet\"]; // Default\n }\n\n cachedEnv = { ...result.data, enabledNetworks };\n return cachedEnv;\n}\n\n// Export for testing\nexport { envSchema };\n",
6
- "import { getEnv } from \"./env.ts\";\n\ntype LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\";\n\nconst LOG_LEVELS: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n};\n\nclass Logger {\n private _level?: LogLevel;\n private _isProduction?: boolean;\n private _initialized = false;\n\n private init() {\n if (this._initialized) return;\n this._initialized = true;\n try {\n const env = getEnv();\n this._level = env.LOG_LEVEL;\n this._isProduction = env.NODE_ENV === \"production\";\n } catch {\n // Fallback when env is unavailable (e.g. tests without DATABASE_URL)\n this._level = \"info\";\n this._isProduction = false;\n }\n }\n\n private get level(): LogLevel {\n this.init();\n return this._level!;\n }\n\n private get isProduction(): boolean {\n this.init();\n return this._isProduction!;\n }\n\n private shouldLog(level: LogLevel): boolean {\n return LOG_LEVELS[level] >= LOG_LEVELS[this.level];\n }\n\n private formatMessage(level: LogLevel, message: string, meta?: Record<string, any>) {\n const timestamp = new Date().toISOString();\n\n if (this.isProduction) {\n // JSON output for production\n return JSON.stringify({\n timestamp,\n level,\n message,\n ...meta,\n });\n }\n\n // Human-readable output for development\n const metaStr = meta ? ` ${JSON.stringify(meta)}` : \"\";\n return `[${timestamp}] ${level.toUpperCase()}: ${message}${metaStr}`;\n }\n\n debug(message: string, meta?: Record<string, any>): void {\n if (this.shouldLog(\"debug\")) {\n console.debug(this.formatMessage(\"debug\", message, meta));\n }\n }\n\n info(message: string, meta?: Record<string, any>): void {\n if (this.shouldLog(\"info\")) {\n console.info(this.formatMessage(\"info\", message, meta));\n }\n }\n\n warn(message: string, meta?: Record<string, any>): void {\n if (this.shouldLog(\"warn\")) {\n console.warn(this.formatMessage(\"warn\", message, meta));\n }\n }\n\n error(message: string, meta?: Record<string, any>): void {\n if (this.shouldLog(\"error\")) {\n console.error(this.formatMessage(\"error\", message, meta));\n }\n }\n}\n\n// Export singleton instance\nexport const logger: Logger = new Logger();\n",
7
- "/**\n * Hiro public API client for backfilling historical block data.\n *\n * The stacks-node RPC `/v2/blocks/{height}` only returns block headers + tx IDs,\n * not full transaction data or events. The Hiro API serves complete block data\n * that we can transform into the NewBlockPayload format our indexer expects.\n */\n\nimport { logger } from \"../logger.ts\";\n\nconst DEFAULT_HIRO_API_URL = \"https://api.mainnet.hiro.so\";\n\n/** v2 /extended/v2/blocks/{height} response */\nexport interface HiroBlockResponse {\n canonical: boolean;\n height: number;\n hash: string;\n block_time: number;\n block_time_iso: string;\n index_block_hash: string;\n parent_block_hash: string;\n parent_index_block_hash: string;\n burn_block_hash: string;\n burn_block_height: number;\n burn_block_time: number;\n miner_txid: string;\n tx_count: number;\n}\n\n/** v2 /extended/v2/blocks/{height}/transactions response */\nexport interface HiroBlockTxsResponse {\n limit: number;\n offset: number;\n total: number;\n results: HiroTxResponse[];\n}\n\nexport interface HiroTxResponse {\n tx_id: string;\n tx_type: string;\n tx_status: string;\n sender_address: string;\n fee_rate: string;\n nonce: number;\n block_hash: string;\n block_height: number;\n burn_block_height: number;\n tx_index: number;\n event_count: number;\n token_transfer?: {\n recipient_address: string;\n amount: string;\n memo: string;\n };\n contract_call?: {\n contract_id: string;\n function_name: string;\n function_args: unknown[];\n };\n smart_contract?: {\n contract_id: string;\n source_code: string;\n };\n}\n\nexport interface HiroEvent {\n event_index: number;\n event_type: string; // \"stx_asset\" | \"fungible_token_asset\" | \"non_fungible_token_asset\" | \"smart_contract_log\"\n tx_id: string;\n asset?: {\n asset_event_type: string; // \"transfer\" | \"mint\" | \"burn\"\n sender?: string;\n recipient?: string;\n amount?: string;\n memo?: string;\n asset_id?: string;\n value?: unknown;\n };\n contract_log?: {\n contract_id: string;\n topic: string;\n value: unknown;\n };\n}\n\nexport interface HiroEventsResponse {\n limit: number;\n offset: number;\n events: HiroEvent[];\n}\n\n/** Shape our indexer expects at POST /new_block */\nexport interface NewBlockPayload {\n block_hash: string;\n block_height: number;\n index_block_hash: string;\n parent_block_hash: string;\n parent_index_block_hash: string;\n burn_block_hash: string;\n burn_block_height: number;\n burn_block_timestamp: number;\n miner_txid: string;\n timestamp: number;\n transactions: TransactionPayload[];\n events: TransactionEventPayload[];\n}\n\ninterface TransactionPayload {\n txid: string;\n raw_tx: string;\n status: string;\n tx_index: number;\n tx_type?: string;\n sender_address?: string;\n}\n\ninterface TransactionEventPayload {\n txid: string;\n event_index: number;\n committed: boolean;\n type: string;\n stx_transfer_event?: { sender: string; recipient: string; amount: string; memo?: string };\n stx_mint_event?: { recipient: string; amount: string };\n stx_burn_event?: { sender: string; amount: string };\n stx_lock_event?: { locked_amount: string; unlock_height: string; locked_address: string };\n ft_transfer_event?: { asset_identifier: string; sender: string; recipient: string; amount: string };\n ft_mint_event?: { asset_identifier: string; recipient: string; amount: string };\n ft_burn_event?: { asset_identifier: string; sender: string; amount: string };\n nft_transfer_event?: { asset_identifier: string; sender: string; recipient: string; value: unknown };\n nft_mint_event?: { asset_identifier: string; recipient: string; value: unknown };\n nft_burn_event?: { asset_identifier: string; sender: string; value: unknown };\n smart_contract_event?: { contract_identifier: string; topic: string; value: unknown };\n}\n\nexport interface GetBlockOptions {\n /** Fetch actual raw_tx hex for each transaction (instead of \"0x00\" placeholder) */\n includeRawTx?: boolean;\n /** Max concurrent raw_tx fetches per block (default: 10) */\n rawTxConcurrency?: number;\n}\n\nexport class HiroClient {\n private apiUrl: string;\n private fallbackUrl: string | undefined;\n private apiKey: string | undefined;\n private maxRetries: number;\n\n constructor(apiUrl?: string, maxRetries = 5) {\n this.apiUrl = apiUrl || process.env.HIRO_API_URL || DEFAULT_HIRO_API_URL;\n this.fallbackUrl = process.env.HIRO_FALLBACK_URL;\n this.apiKey = process.env.HIRO_API_KEY;\n this.maxRetries = maxRetries;\n }\n\n private get headers(): Record<string, string> {\n return this.apiKey ? { \"x-hiro-api-key\": this.apiKey } : {};\n }\n\n /** Fetch with retry on 429/5xx using exponential backoff */\n private async fetchWithRetry(url: string, timeoutMs = 120_000): Promise<Response> {\n for (let attempt = 0; attempt < this.maxRetries; attempt++) {\n const res = await fetch(url, { headers: this.headers, signal: AbortSignal.timeout(timeoutMs) });\n\n if (res.ok || res.status === 404) return res;\n\n if (res.status === 429 || res.status >= 500) {\n const delay = Math.min(1000 * Math.pow(2, attempt), 10_000);\n logger.info(\"Rate limited, retrying\", { url: url.split(\"/\").slice(-2).join(\"/\"), attempt, delay });\n await new Promise((r) => setTimeout(r, delay));\n continue;\n }\n\n // 4xx (not 404/429) — don't retry\n return res;\n }\n\n // Final attempt\n return fetch(url, { headers: this.headers, signal: AbortSignal.timeout(timeoutMs) });\n }\n\n /**\n * Fetch a complete block by height, including all transactions and events,\n * transformed into the NewBlockPayload format our indexer expects.\n *\n * Uses 3-step approach:\n * 1. GET /extended/v2/blocks/{height} — block metadata\n * 2. GET /extended/v2/blocks/{height}/transactions — all txs (paginated)\n * 3. GET /extended/v1/tx/events?tx_id={txId} — events per tx (only for txs with events)\n */\n async getBlockForIndexer(height: number, options?: GetBlockOptions): Promise<NewBlockPayload | null> {\n // 1. Fetch block metadata (try primary, fallback on 404)\n let block = await this.fetchBlock(height);\n let usingFallback = false;\n if (!block && this.fallbackUrl) {\n block = await this.fetchBlock(height, this.fallbackUrl);\n if (block) usingFallback = true;\n }\n if (!block) return null;\n\n // 2. Fetch all transactions via v2 block/transactions endpoint\n const baseUrl = usingFallback ? this.fallbackUrl! : this.apiUrl;\n const hiroTxs = await this.fetchBlockTransactions(height, baseUrl);\n\n const txPayloads: TransactionPayload[] = [];\n const eventPayloads: TransactionEventPayload[] = [];\n\n for (const hiroTx of hiroTxs) {\n txPayloads.push({\n txid: hiroTx.tx_id,\n raw_tx: \"0x00\",\n status: mapTxStatus(hiroTx.tx_status),\n tx_index: hiroTx.tx_index ?? 0,\n tx_type: mapTxType(hiroTx.tx_type),\n sender_address: hiroTx.sender_address,\n });\n\n // 3. Fetch events only for txs that have them\n if (hiroTx.event_count > 0) {\n if (hiroTx.event_count > 1000) {\n logger.info(\"Fetching large event set\", { txId: hiroTx.tx_id, eventCount: hiroTx.event_count, height });\n }\n try {\n const events = await this.fetchAllEvents(hiroTx.tx_id, baseUrl);\n eventPayloads.push(...events);\n } catch (err) {\n logger.warn(\"Failed to fetch events for backfill\", { txId: hiroTx.tx_id, error: String(err) });\n }\n }\n }\n\n // 4. Optionally fetch raw_tx for all transactions\n if (options?.includeRawTx && txPayloads.length > 0) {\n const txIds = txPayloads.map((t) => t.txid);\n const rawTxMap = await this.fetchRawTxBatch(txIds, options.rawTxConcurrency);\n for (const txPayload of txPayloads) {\n const raw = rawTxMap.get(txPayload.txid);\n if (raw) txPayload.raw_tx = raw;\n }\n }\n\n return {\n block_hash: block.hash,\n block_height: block.height,\n index_block_hash: block.index_block_hash,\n parent_block_hash: block.parent_block_hash,\n parent_index_block_hash: block.parent_index_block_hash,\n burn_block_hash: block.burn_block_hash,\n burn_block_height: block.burn_block_height,\n burn_block_timestamp: block.burn_block_time,\n miner_txid: block.miner_txid,\n timestamp: block.block_time,\n transactions: txPayloads,\n events: eventPayloads,\n };\n }\n\n /** v2 block metadata */\n private async fetchBlock(height: number, baseUrl?: string): Promise<HiroBlockResponse | null> {\n const url = baseUrl || this.apiUrl;\n const res = await this.fetchWithRetry(`${url}/extended/v2/blocks/${height}`);\n if (res.status === 404) return null;\n if (!res.ok) throw new Error(`Hiro API block/${height} returned ${res.status}`);\n return res.json() as Promise<HiroBlockResponse>;\n }\n\n /** v2 block transactions (paginated) */\n private async fetchBlockTransactions(height: number, baseUrl?: string): Promise<HiroTxResponse[]> {\n const url = baseUrl || this.apiUrl;\n const txs: HiroTxResponse[] = [];\n let offset = 0;\n const limit = 50;\n\n while (true) {\n const res = await this.fetchWithRetry(\n `${url}/extended/v2/blocks/${height}/transactions?limit=${limit}&offset=${offset}`\n );\n if (!res.ok) throw new Error(`Hiro API block/${height}/transactions returned ${res.status}`);\n\n const data = (await res.json()) as HiroBlockTxsResponse;\n txs.push(...data.results);\n\n if (txs.length >= data.total || data.results.length < limit) break;\n offset += limit;\n }\n\n return txs;\n }\n\n private async fetchAllEvents(txId: string, baseUrl?: string, _maxEvents?: number): Promise<TransactionEventPayload[]> {\n const url = baseUrl || this.apiUrl;\n const events: TransactionEventPayload[] = [];\n let offset = 0;\n const limit = 100;\n\n while (true) {\n const res = await this.fetchWithRetry(\n `${url}/extended/v1/tx/events?tx_id=${txId}&limit=${limit}&offset=${offset}`\n );\n if (!res.ok) {\n logger.warn(\"Failed to fetch events from Hiro\", { txId, status: res.status });\n break;\n }\n\n const data = (await res.json()) as HiroEventsResponse;\n for (const hEvent of data.events) {\n const converted = convertHiroEvent(hEvent);\n if (converted) events.push(converted);\n }\n\n if (data.events.length < limit) break;\n offset += limit;\n }\n\n return events;\n }\n\n /** Fetch raw_tx hex for a single transaction */\n async fetchRawTx(txId: string): Promise<string | null> {\n try {\n const res = await this.fetchWithRetry(`${this.apiUrl}/extended/v1/tx/${txId}/raw`, 10_000);\n if (!res.ok) return null;\n const data = (await res.json()) as { raw_tx: string };\n return data.raw_tx || null;\n } catch {\n return null;\n }\n }\n\n /** Fetch raw_tx for multiple transactions with bounded concurrency */\n async fetchRawTxBatch(txIds: string[], concurrency = 10): Promise<Map<string, string>> {\n const results = new Map<string, string>();\n for (let i = 0; i < txIds.length; i += concurrency) {\n const chunk = txIds.slice(i, i + concurrency);\n const settled = await Promise.allSettled(\n chunk.map(async (txId) => {\n const raw = await this.fetchRawTx(txId);\n return { txId, raw };\n })\n );\n for (const result of settled) {\n if (result.status === \"fulfilled\" && result.value.raw) {\n results.set(result.value.txId, result.value.raw);\n }\n }\n }\n return results;\n }\n\n /** Fetch current chain tip height from Hiro API status endpoint */\n async fetchChainTip(): Promise<number> {\n const res = await this.fetchWithRetry(`${this.apiUrl}/extended/v1/status`);\n if (!res.ok) throw new Error(`Hiro API /status returned ${res.status}`);\n const data = (await res.json()) as { chain_tip?: { block_height: number }; stacks_tip_height?: number };\n return data.chain_tip?.block_height ?? data.stacks_tip_height ?? 0;\n }\n\n async isHealthy(): Promise<boolean> {\n try {\n const res = await fetch(`${this.apiUrl}/extended/v1/status`, {\n headers: this.headers,\n signal: AbortSignal.timeout(10_000),\n });\n // 429 = rate limited but reachable\n return res.ok || res.status === 429;\n } catch {\n return false;\n }\n }\n\n getApiUrl(): string {\n return this.apiUrl;\n }\n}\n\n/** Map Hiro tx_status to our indexer's expected format */\nfunction mapTxStatus(status: string): string {\n switch (status) {\n case \"success\":\n return \"success\";\n case \"abort_by_response\":\n case \"abort_by_post_condition\":\n return status;\n default:\n return \"success\";\n }\n}\n\n/** Map Hiro tx_type to node event tx_type */\nfunction mapTxType(type: string): string {\n switch (type) {\n case \"token_transfer\":\n return \"token_transfer\";\n case \"contract_call\":\n return \"contract_call\";\n case \"smart_contract\":\n return \"smart_contract\";\n case \"coinbase\":\n return \"coinbase\";\n case \"tenure_change\":\n return \"tenure_change\";\n case \"poison_microblock\":\n return \"poison_microblock\";\n default:\n return type;\n }\n}\n\n/**\n * Convert a Hiro API event to our indexer's TransactionEvent format.\n *\n * Hiro uses:\n * event_type: \"stx_asset\" | \"fungible_token_asset\" | \"non_fungible_token_asset\" | \"smart_contract_log\"\n * asset.asset_event_type: \"transfer\" | \"mint\" | \"burn\" | \"lock\"\n *\n * Our indexer expects:\n * type: \"stx_transfer_event\" | \"stx_mint_event\" | \"ft_transfer_event\" | \"smart_contract_event\" | ...\n */\nfunction convertHiroEvent(hEvent: HiroEvent): TransactionEventPayload | null {\n const base = {\n txid: hEvent.tx_id,\n event_index: hEvent.event_index,\n committed: true,\n };\n\n if (hEvent.event_type === \"stx_asset\" && hEvent.asset) {\n const a = hEvent.asset;\n switch (a.asset_event_type) {\n case \"transfer\":\n return {\n ...base,\n type: \"stx_transfer_event\",\n stx_transfer_event: {\n sender: a.sender!,\n recipient: a.recipient!,\n amount: a.amount!,\n memo: a.memo,\n },\n };\n case \"mint\":\n return {\n ...base,\n type: \"stx_mint_event\",\n stx_mint_event: { recipient: a.recipient!, amount: a.amount! },\n };\n case \"burn\":\n return {\n ...base,\n type: \"stx_burn_event\",\n stx_burn_event: { sender: a.sender!, amount: a.amount! },\n };\n case \"lock\":\n return {\n ...base,\n type: \"stx_lock_event\",\n stx_lock_event: {\n locked_amount: a.amount!,\n unlock_height: \"0\",\n locked_address: a.sender!,\n },\n };\n }\n }\n\n if (hEvent.event_type === \"fungible_token_asset\" && hEvent.asset) {\n const a = hEvent.asset;\n const assetId = a.asset_id || \"\";\n switch (a.asset_event_type) {\n case \"transfer\":\n return {\n ...base,\n type: \"ft_transfer_event\",\n ft_transfer_event: {\n asset_identifier: assetId,\n sender: a.sender!,\n recipient: a.recipient!,\n amount: a.amount!,\n },\n };\n case \"mint\":\n return {\n ...base,\n type: \"ft_mint_event\",\n ft_mint_event: { asset_identifier: assetId, recipient: a.recipient!, amount: a.amount! },\n };\n case \"burn\":\n return {\n ...base,\n type: \"ft_burn_event\",\n ft_burn_event: { asset_identifier: assetId, sender: a.sender!, amount: a.amount! },\n };\n }\n }\n\n if (hEvent.event_type === \"non_fungible_token_asset\" && hEvent.asset) {\n const a = hEvent.asset;\n const assetId = a.asset_id || \"\";\n switch (a.asset_event_type) {\n case \"transfer\":\n return {\n ...base,\n type: \"nft_transfer_event\",\n nft_transfer_event: {\n asset_identifier: assetId,\n sender: a.sender!,\n recipient: a.recipient!,\n value: a.value,\n },\n };\n case \"mint\":\n return {\n ...base,\n type: \"nft_mint_event\",\n nft_mint_event: { asset_identifier: assetId, recipient: a.recipient!, value: a.value },\n };\n case \"burn\":\n return {\n ...base,\n type: \"nft_burn_event\",\n nft_burn_event: { asset_identifier: assetId, sender: a.sender!, value: a.value },\n };\n }\n }\n\n if (hEvent.event_type === \"smart_contract_log\" && hEvent.contract_log) {\n return {\n ...base,\n type: \"smart_contract_event\",\n smart_contract_event: {\n contract_identifier: hEvent.contract_log.contract_id,\n topic: hEvent.contract_log.topic,\n value: hEvent.contract_log.value,\n },\n };\n }\n\n logger.debug(\"Unknown Hiro event type, skipping\", {\n eventType: hEvent.event_type,\n txId: hEvent.tx_id,\n });\n return null;\n}\n"
5
+ "import { z } from \"zod/v4\";\n\n// Parse comma-separated networks\nconst networksSchema = z.string().transform((val) => {\n\tconst networks = val\n\t\t.split(\",\")\n\t\t.map((n) => n.trim())\n\t\t.filter(Boolean);\n\tconst valid = [\"mainnet\", \"testnet\"];\n\tfor (const n of networks) {\n\t\tif (!valid.includes(n)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Invalid network: ${n}. Must be one of: ${valid.join(\", \")}`,\n\t\t\t);\n\t\t}\n\t}\n\treturn networks as (\"mainnet\" | \"testnet\")[];\n});\n\ninterface EnvSchemaOutput {\n\tDATABASE_URL?: string;\n\tNETWORK?: \"mainnet\" | \"testnet\";\n\tNETWORKS?: (\"mainnet\" | \"testnet\")[];\n\tLOG_LEVEL: \"debug\" | \"info\" | \"warn\" | \"error\";\n\tNODE_ENV: \"development\" | \"production\" | \"test\";\n}\n\n// Cast needed: z.preprocess / z.default create different _input vs _output types\n// that z.ZodType<T> can't represent without explicit input type param\nconst envSchema: z.ZodType<EnvSchemaOutput> = z.object({\n\tDATABASE_URL: z.preprocess(\n\t\t(val) => (typeof val === \"string\" && val.length === 0 ? undefined : val),\n\t\tz.string().url().optional(),\n\t),\n\tNETWORK: z.enum([\"mainnet\", \"testnet\"]).optional(),\n\tNETWORKS: networksSchema.optional(),\n\tLOG_LEVEL: z.enum([\"debug\", \"info\", \"warn\", \"error\"]).default(\"info\"),\n\tNODE_ENV: z\n\t\t.enum([\"development\", \"production\", \"test\"])\n\t\t.default(\"development\"),\n}) as unknown as z.ZodType<EnvSchemaOutput>;\n\nexport type Env = EnvSchemaOutput & {\n\tenabledNetworks: (\"mainnet\" | \"testnet\")[];\n};\n\nlet cachedEnv: Env | null = null;\n\nexport function getEnv(): Env {\n\tif (cachedEnv) {\n\t\treturn cachedEnv;\n\t}\n\n\tconst result = envSchema.safeParse(process.env);\n\n\tif (!result.success) {\n\t\tconsole.error(\"❌ Invalid environment configuration:\");\n\t\tconsole.error(z.treeifyError(result.error));\n\t\tthrow new Error(\"Invalid environment configuration\");\n\t}\n\n\t// Compute enabled networks from NETWORKS or NETWORK\n\tlet enabledNetworks: (\"mainnet\" | \"testnet\")[];\n\tif (result.data.NETWORKS && result.data.NETWORKS.length > 0) {\n\t\tenabledNetworks = result.data.NETWORKS;\n\t} else if (result.data.NETWORK) {\n\t\tenabledNetworks = [result.data.NETWORK];\n\t} else {\n\t\tenabledNetworks = [\"mainnet\"]; // Default\n\t}\n\n\tcachedEnv = { ...result.data, enabledNetworks };\n\treturn cachedEnv;\n}\n\n// Export for testing\nexport { envSchema };\n",
6
+ "import { getEnv } from \"./env.ts\";\n\ntype LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\";\n\nconst LOG_LEVELS: Record<LogLevel, number> = {\n\tdebug: 0,\n\tinfo: 1,\n\twarn: 2,\n\terror: 3,\n};\n\nclass Logger {\n\tprivate _level?: LogLevel;\n\tprivate _isProduction?: boolean;\n\tprivate _initialized = false;\n\n\tprivate init() {\n\t\tif (this._initialized) return;\n\t\tthis._initialized = true;\n\t\ttry {\n\t\t\tconst env = getEnv();\n\t\t\tthis._level = env.LOG_LEVEL;\n\t\t\tthis._isProduction = env.NODE_ENV === \"production\";\n\t\t} catch {\n\t\t\t// Fallback when env is unavailable (e.g. tests without DATABASE_URL)\n\t\t\tthis._level = \"info\";\n\t\t\tthis._isProduction = false;\n\t\t}\n\t}\n\n\tprivate get level(): LogLevel {\n\t\tthis.init();\n\t\treturn this._level!;\n\t}\n\n\tprivate get isProduction(): boolean {\n\t\tthis.init();\n\t\treturn this._isProduction!;\n\t}\n\n\tprivate shouldLog(level: LogLevel): boolean {\n\t\treturn LOG_LEVELS[level] >= LOG_LEVELS[this.level];\n\t}\n\n\tprivate formatMessage(\n\t\tlevel: LogLevel,\n\t\tmessage: string,\n\t\tmeta?: Record<string, any>,\n\t) {\n\t\tconst timestamp = new Date().toISOString();\n\n\t\tif (this.isProduction) {\n\t\t\t// JSON output for production\n\t\t\treturn JSON.stringify({\n\t\t\t\ttimestamp,\n\t\t\t\tlevel,\n\t\t\t\tmessage,\n\t\t\t\t...meta,\n\t\t\t});\n\t\t}\n\n\t\t// Human-readable output for development\n\t\tconst metaStr = meta ? ` ${JSON.stringify(meta)}` : \"\";\n\t\treturn `[${timestamp}] ${level.toUpperCase()}: ${message}${metaStr}`;\n\t}\n\n\tdebug(message: string, meta?: Record<string, any>): void {\n\t\tif (this.shouldLog(\"debug\")) {\n\t\t\tconsole.debug(this.formatMessage(\"debug\", message, meta));\n\t\t}\n\t}\n\n\tinfo(message: string, meta?: Record<string, any>): void {\n\t\tif (this.shouldLog(\"info\")) {\n\t\t\tconsole.info(this.formatMessage(\"info\", message, meta));\n\t\t}\n\t}\n\n\twarn(message: string, meta?: Record<string, any>): void {\n\t\tif (this.shouldLog(\"warn\")) {\n\t\t\tconsole.warn(this.formatMessage(\"warn\", message, meta));\n\t\t}\n\t}\n\n\terror(message: string, meta?: Record<string, any>): void {\n\t\tif (this.shouldLog(\"error\")) {\n\t\t\tconsole.error(this.formatMessage(\"error\", message, meta));\n\t\t}\n\t}\n}\n\n// Export singleton instance\nexport const logger: Logger = new Logger();\n",
7
+ "/**\n * Hiro public API client for backfilling historical block data.\n *\n * The stacks-node RPC `/v2/blocks/{height}` only returns block headers + tx IDs,\n * not full transaction data or events. The Hiro API serves complete block data\n * that we can transform into the NewBlockPayload format our indexer expects.\n */\n\nimport { logger } from \"../logger.ts\";\n\nconst DEFAULT_HIRO_API_URL = \"https://api.mainnet.hiro.so\";\n\n/** v2 /extended/v2/blocks/{height} response */\nexport interface HiroBlockResponse {\n\tcanonical: boolean;\n\theight: number;\n\thash: string;\n\tblock_time: number;\n\tblock_time_iso: string;\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_time: number;\n\tminer_txid: string;\n\ttx_count: number;\n}\n\n/** v2 /extended/v2/blocks/{height}/transactions response */\nexport interface HiroBlockTxsResponse {\n\tlimit: number;\n\toffset: number;\n\ttotal: number;\n\tresults: HiroTxResponse[];\n}\n\nexport interface HiroTxResponse {\n\ttx_id: string;\n\ttx_type: string;\n\ttx_status: string;\n\tsender_address: string;\n\tfee_rate: string;\n\tnonce: number;\n\tblock_hash: string;\n\tblock_height: number;\n\tburn_block_height: number;\n\ttx_index: number;\n\tevent_count: number;\n\ttoken_transfer?: {\n\t\trecipient_address: string;\n\t\tamount: string;\n\t\tmemo: string;\n\t};\n\tcontract_call?: {\n\t\tcontract_id: string;\n\t\tfunction_name: string;\n\t\tfunction_args: unknown[];\n\t};\n\tsmart_contract?: {\n\t\tcontract_id: string;\n\t\tsource_code: string;\n\t};\n}\n\nexport interface HiroEvent {\n\tevent_index: number;\n\tevent_type: string; // \"stx_asset\" | \"fungible_token_asset\" | \"non_fungible_token_asset\" | \"smart_contract_log\"\n\ttx_id: string;\n\tasset?: {\n\t\tasset_event_type: string; // \"transfer\" | \"mint\" | \"burn\"\n\t\tsender?: string;\n\t\trecipient?: string;\n\t\tamount?: string;\n\t\tmemo?: string;\n\t\tasset_id?: string;\n\t\tvalue?: unknown;\n\t};\n\tcontract_log?: {\n\t\tcontract_id: string;\n\t\ttopic: string;\n\t\tvalue: unknown;\n\t};\n}\n\nexport interface HiroEventsResponse {\n\tlimit: number;\n\toffset: number;\n\tevents: HiroEvent[];\n}\n\n/** Shape our indexer expects at POST /new_block */\nexport interface NewBlockPayload {\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: TransactionPayload[];\n\tevents: TransactionEventPayload[];\n}\n\ninterface TransactionPayload {\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 TransactionEventPayload {\n\ttxid: string;\n\tevent_index: number;\n\tcommitted: boolean;\n\ttype: string;\n\tstx_transfer_event?: {\n\t\tsender: string;\n\t\trecipient: string;\n\t\tamount: string;\n\t\tmemo?: string;\n\t};\n\tstx_mint_event?: { recipient: string; amount: string };\n\tstx_burn_event?: { sender: string; amount: string };\n\tstx_lock_event?: {\n\t\tlocked_amount: string;\n\t\tunlock_height: string;\n\t\tlocked_address: string;\n\t};\n\tft_transfer_event?: {\n\t\tasset_identifier: string;\n\t\tsender: string;\n\t\trecipient: string;\n\t\tamount: string;\n\t};\n\tft_mint_event?: {\n\t\tasset_identifier: string;\n\t\trecipient: string;\n\t\tamount: string;\n\t};\n\tft_burn_event?: { asset_identifier: string; sender: string; amount: string };\n\tnft_transfer_event?: {\n\t\tasset_identifier: string;\n\t\tsender: string;\n\t\trecipient: string;\n\t\tvalue: unknown;\n\t};\n\tnft_mint_event?: {\n\t\tasset_identifier: string;\n\t\trecipient: string;\n\t\tvalue: unknown;\n\t};\n\tnft_burn_event?: { asset_identifier: string; sender: string; value: unknown };\n\tsmart_contract_event?: {\n\t\tcontract_identifier: string;\n\t\ttopic: string;\n\t\tvalue: unknown;\n\t};\n}\n\nexport interface GetBlockOptions {\n\t/** Fetch actual raw_tx hex for each transaction (instead of \"0x00\" placeholder) */\n\tincludeRawTx?: boolean;\n\t/** Max concurrent raw_tx fetches per block (default: 10) */\n\trawTxConcurrency?: number;\n}\n\nexport class HiroClient {\n\tprivate apiUrl: string;\n\tprivate fallbackUrl: string | undefined;\n\tprivate apiKey: string | undefined;\n\tprivate maxRetries: number;\n\n\tconstructor(apiUrl?: string, maxRetries = 5) {\n\t\tthis.apiUrl = apiUrl || process.env.HIRO_API_URL || DEFAULT_HIRO_API_URL;\n\t\tthis.fallbackUrl = process.env.HIRO_FALLBACK_URL;\n\t\tthis.apiKey = process.env.HIRO_API_KEY;\n\t\tthis.maxRetries = maxRetries;\n\t}\n\n\tprivate get headers(): Record<string, string> {\n\t\treturn this.apiKey ? { \"x-hiro-api-key\": this.apiKey } : {};\n\t}\n\n\t/** Fetch with retry on 429/5xx using exponential backoff */\n\tprivate async fetchWithRetry(\n\t\turl: string,\n\t\ttimeoutMs = 120_000,\n\t): Promise<Response> {\n\t\tfor (let attempt = 0; attempt < this.maxRetries; attempt++) {\n\t\t\tconst res = await fetch(url, {\n\t\t\t\theaders: this.headers,\n\t\t\t\tsignal: AbortSignal.timeout(timeoutMs),\n\t\t\t});\n\n\t\t\tif (res.ok || res.status === 404) return res;\n\n\t\t\tif (res.status === 429 || res.status >= 500) {\n\t\t\t\tconst delay = Math.min(1000 * Math.pow(2, attempt), 10_000);\n\t\t\t\tlogger.info(\"Rate limited, retrying\", {\n\t\t\t\t\turl: url.split(\"/\").slice(-2).join(\"/\"),\n\t\t\t\t\tattempt,\n\t\t\t\t\tdelay,\n\t\t\t\t});\n\t\t\t\tawait new Promise((r) => setTimeout(r, delay));\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// 4xx (not 404/429) — don't retry\n\t\t\treturn res;\n\t\t}\n\n\t\t// Final attempt\n\t\treturn fetch(url, {\n\t\t\theaders: this.headers,\n\t\t\tsignal: AbortSignal.timeout(timeoutMs),\n\t\t});\n\t}\n\n\t/**\n\t * Fetch a complete block by height, including all transactions and events,\n\t * transformed into the NewBlockPayload format our indexer expects.\n\t *\n\t * Uses 3-step approach:\n\t * 1. GET /extended/v2/blocks/{height} — block metadata\n\t * 2. GET /extended/v2/blocks/{height}/transactions — all txs (paginated)\n\t * 3. GET /extended/v1/tx/events?tx_id={txId} — events per tx (only for txs with events)\n\t */\n\tasync getBlockForIndexer(\n\t\theight: number,\n\t\toptions?: GetBlockOptions,\n\t): Promise<NewBlockPayload | null> {\n\t\t// 1. Fetch block metadata (try primary, fallback on 404)\n\t\tlet block = await this.fetchBlock(height);\n\t\tlet usingFallback = false;\n\t\tif (!block && this.fallbackUrl) {\n\t\t\tblock = await this.fetchBlock(height, this.fallbackUrl);\n\t\t\tif (block) usingFallback = true;\n\t\t}\n\t\tif (!block) return null;\n\n\t\t// 2. Fetch all transactions via v2 block/transactions endpoint\n\t\tconst baseUrl = usingFallback ? this.fallbackUrl! : this.apiUrl;\n\t\tconst hiroTxs = await this.fetchBlockTransactions(height, baseUrl);\n\n\t\tconst txPayloads: TransactionPayload[] = [];\n\t\tconst eventPayloads: TransactionEventPayload[] = [];\n\n\t\tfor (const hiroTx of hiroTxs) {\n\t\t\ttxPayloads.push({\n\t\t\t\ttxid: hiroTx.tx_id,\n\t\t\t\traw_tx: \"0x00\",\n\t\t\t\tstatus: mapTxStatus(hiroTx.tx_status),\n\t\t\t\ttx_index: hiroTx.tx_index ?? 0,\n\t\t\t\ttx_type: mapTxType(hiroTx.tx_type),\n\t\t\t\tsender_address: hiroTx.sender_address,\n\t\t\t});\n\n\t\t\t// 3. Fetch events only for txs that have them\n\t\t\tif (hiroTx.event_count > 0) {\n\t\t\t\tif (hiroTx.event_count > 1000) {\n\t\t\t\t\tlogger.info(\"Fetching large event set\", {\n\t\t\t\t\t\ttxId: hiroTx.tx_id,\n\t\t\t\t\t\teventCount: hiroTx.event_count,\n\t\t\t\t\t\theight,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tconst events = await this.fetchAllEvents(hiroTx.tx_id, baseUrl);\n\t\t\t\t\teventPayloads.push(...events);\n\t\t\t\t} catch (err) {\n\t\t\t\t\tlogger.warn(\"Failed to fetch events for backfill\", {\n\t\t\t\t\t\ttxId: hiroTx.tx_id,\n\t\t\t\t\t\terror: String(err),\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// 4. Optionally fetch raw_tx for all transactions\n\t\tif (options?.includeRawTx && txPayloads.length > 0) {\n\t\t\tconst txIds = txPayloads.map((t) => t.txid);\n\t\t\tconst rawTxMap = await this.fetchRawTxBatch(\n\t\t\t\ttxIds,\n\t\t\t\toptions.rawTxConcurrency,\n\t\t\t);\n\t\t\tfor (const txPayload of txPayloads) {\n\t\t\t\tconst raw = rawTxMap.get(txPayload.txid);\n\t\t\t\tif (raw) txPayload.raw_tx = raw;\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tblock_hash: block.hash,\n\t\t\tblock_height: block.height,\n\t\t\tindex_block_hash: block.index_block_hash,\n\t\t\tparent_block_hash: block.parent_block_hash,\n\t\t\tparent_index_block_hash: block.parent_index_block_hash,\n\t\t\tburn_block_hash: 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: block.miner_txid,\n\t\t\ttimestamp: block.block_time,\n\t\t\ttransactions: txPayloads,\n\t\t\tevents: eventPayloads,\n\t\t};\n\t}\n\n\t/** v2 block metadata */\n\tprivate async fetchBlock(\n\t\theight: number,\n\t\tbaseUrl?: string,\n\t): Promise<HiroBlockResponse | null> {\n\t\tconst url = baseUrl || this.apiUrl;\n\t\tconst res = await this.fetchWithRetry(\n\t\t\t`${url}/extended/v2/blocks/${height}`,\n\t\t);\n\t\tif (res.status === 404) return null;\n\t\tif (!res.ok)\n\t\t\tthrow new Error(`Hiro API block/${height} returned ${res.status}`);\n\t\treturn res.json() as Promise<HiroBlockResponse>;\n\t}\n\n\t/** v2 block transactions (paginated) */\n\tprivate async fetchBlockTransactions(\n\t\theight: number,\n\t\tbaseUrl?: string,\n\t): Promise<HiroTxResponse[]> {\n\t\tconst url = baseUrl || this.apiUrl;\n\t\tconst txs: HiroTxResponse[] = [];\n\t\tlet offset = 0;\n\t\tconst limit = 50;\n\n\t\twhile (true) {\n\t\t\tconst res = await this.fetchWithRetry(\n\t\t\t\t`${url}/extended/v2/blocks/${height}/transactions?limit=${limit}&offset=${offset}`,\n\t\t\t);\n\t\t\tif (!res.ok)\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Hiro API block/${height}/transactions returned ${res.status}`,\n\t\t\t\t);\n\n\t\t\tconst data = (await res.json()) as HiroBlockTxsResponse;\n\t\t\ttxs.push(...data.results);\n\n\t\t\tif (txs.length >= data.total || data.results.length < limit) break;\n\t\t\toffset += limit;\n\t\t}\n\n\t\treturn txs;\n\t}\n\n\tprivate async fetchAllEvents(\n\t\ttxId: string,\n\t\tbaseUrl?: string,\n\t\t_maxEvents?: number,\n\t): Promise<TransactionEventPayload[]> {\n\t\tconst url = baseUrl || this.apiUrl;\n\t\tconst events: TransactionEventPayload[] = [];\n\t\tlet offset = 0;\n\t\tconst limit = 100;\n\n\t\twhile (true) {\n\t\t\tconst res = await this.fetchWithRetry(\n\t\t\t\t`${url}/extended/v1/tx/events?tx_id=${txId}&limit=${limit}&offset=${offset}`,\n\t\t\t);\n\t\t\tif (!res.ok) {\n\t\t\t\tlogger.warn(\"Failed to fetch events from Hiro\", {\n\t\t\t\t\ttxId,\n\t\t\t\t\tstatus: res.status,\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tconst data = (await res.json()) as HiroEventsResponse;\n\t\t\tfor (const hEvent of data.events) {\n\t\t\t\tconst converted = convertHiroEvent(hEvent);\n\t\t\t\tif (converted) events.push(converted);\n\t\t\t}\n\n\t\t\tif (data.events.length < limit) break;\n\t\t\toffset += limit;\n\t\t}\n\n\t\treturn events;\n\t}\n\n\t/** Fetch raw_tx hex for a single transaction */\n\tasync fetchRawTx(txId: string): Promise<string | null> {\n\t\ttry {\n\t\t\tconst res = await this.fetchWithRetry(\n\t\t\t\t`${this.apiUrl}/extended/v1/tx/${txId}/raw`,\n\t\t\t\t10_000,\n\t\t\t);\n\t\t\tif (!res.ok) return null;\n\t\t\tconst data = (await res.json()) as { raw_tx: string };\n\t\t\treturn data.raw_tx || null;\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/** Fetch raw_tx for multiple transactions with bounded concurrency */\n\tasync fetchRawTxBatch(\n\t\ttxIds: string[],\n\t\tconcurrency = 10,\n\t): Promise<Map<string, string>> {\n\t\tconst results = new Map<string, string>();\n\t\tfor (let i = 0; i < txIds.length; i += concurrency) {\n\t\t\tconst chunk = txIds.slice(i, i + concurrency);\n\t\t\tconst settled = await Promise.allSettled(\n\t\t\t\tchunk.map(async (txId) => {\n\t\t\t\t\tconst raw = await this.fetchRawTx(txId);\n\t\t\t\t\treturn { txId, raw };\n\t\t\t\t}),\n\t\t\t);\n\t\t\tfor (const result of settled) {\n\t\t\t\tif (result.status === \"fulfilled\" && result.value.raw) {\n\t\t\t\t\tresults.set(result.value.txId, result.value.raw);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn results;\n\t}\n\n\t/** Fetch current chain tip height from Hiro API status endpoint */\n\tasync fetchChainTip(): Promise<number> {\n\t\tconst res = await this.fetchWithRetry(`${this.apiUrl}/extended/v1/status`);\n\t\tif (!res.ok) throw new Error(`Hiro API /status returned ${res.status}`);\n\t\tconst data = (await res.json()) as {\n\t\t\tchain_tip?: { block_height: number };\n\t\t\tstacks_tip_height?: number;\n\t\t};\n\t\treturn data.chain_tip?.block_height ?? data.stacks_tip_height ?? 0;\n\t}\n\n\tasync isHealthy(): Promise<boolean> {\n\t\ttry {\n\t\t\tconst res = await fetch(`${this.apiUrl}/extended/v1/status`, {\n\t\t\t\theaders: this.headers,\n\t\t\t\tsignal: AbortSignal.timeout(10_000),\n\t\t\t});\n\t\t\t// 429 = rate limited but reachable\n\t\t\treturn res.ok || res.status === 429;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tgetApiUrl(): string {\n\t\treturn this.apiUrl;\n\t}\n}\n\n/** Map Hiro tx_status to our indexer's expected format */\nfunction mapTxStatus(status: string): string {\n\tswitch (status) {\n\t\tcase \"success\":\n\t\t\treturn \"success\";\n\t\tcase \"abort_by_response\":\n\t\tcase \"abort_by_post_condition\":\n\t\t\treturn status;\n\t\tdefault:\n\t\t\treturn \"success\";\n\t}\n}\n\n/** Map Hiro tx_type to node event tx_type */\nfunction mapTxType(type: string): string {\n\tswitch (type) {\n\t\tcase \"token_transfer\":\n\t\t\treturn \"token_transfer\";\n\t\tcase \"contract_call\":\n\t\t\treturn \"contract_call\";\n\t\tcase \"smart_contract\":\n\t\t\treturn \"smart_contract\";\n\t\tcase \"coinbase\":\n\t\t\treturn \"coinbase\";\n\t\tcase \"tenure_change\":\n\t\t\treturn \"tenure_change\";\n\t\tcase \"poison_microblock\":\n\t\t\treturn \"poison_microblock\";\n\t\tdefault:\n\t\t\treturn type;\n\t}\n}\n\n/**\n * Convert a Hiro API event to our indexer's TransactionEvent format.\n *\n * Hiro uses:\n * event_type: \"stx_asset\" | \"fungible_token_asset\" | \"non_fungible_token_asset\" | \"smart_contract_log\"\n * asset.asset_event_type: \"transfer\" | \"mint\" | \"burn\" | \"lock\"\n *\n * Our indexer expects:\n * type: \"stx_transfer_event\" | \"stx_mint_event\" | \"ft_transfer_event\" | \"smart_contract_event\" | ...\n */\nfunction convertHiroEvent(hEvent: HiroEvent): TransactionEventPayload | null {\n\tconst base = {\n\t\ttxid: hEvent.tx_id,\n\t\tevent_index: hEvent.event_index,\n\t\tcommitted: true,\n\t};\n\n\tif (hEvent.event_type === \"stx_asset\" && hEvent.asset) {\n\t\tconst a = hEvent.asset;\n\t\tswitch (a.asset_event_type) {\n\t\t\tcase \"transfer\":\n\t\t\t\treturn {\n\t\t\t\t\t...base,\n\t\t\t\t\ttype: \"stx_transfer_event\",\n\t\t\t\t\tstx_transfer_event: {\n\t\t\t\t\t\tsender: a.sender!,\n\t\t\t\t\t\trecipient: a.recipient!,\n\t\t\t\t\t\tamount: a.amount!,\n\t\t\t\t\t\tmemo: a.memo,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\tcase \"mint\":\n\t\t\t\treturn {\n\t\t\t\t\t...base,\n\t\t\t\t\ttype: \"stx_mint_event\",\n\t\t\t\t\tstx_mint_event: { recipient: a.recipient!, amount: a.amount! },\n\t\t\t\t};\n\t\t\tcase \"burn\":\n\t\t\t\treturn {\n\t\t\t\t\t...base,\n\t\t\t\t\ttype: \"stx_burn_event\",\n\t\t\t\t\tstx_burn_event: { sender: a.sender!, amount: a.amount! },\n\t\t\t\t};\n\t\t\tcase \"lock\":\n\t\t\t\treturn {\n\t\t\t\t\t...base,\n\t\t\t\t\ttype: \"stx_lock_event\",\n\t\t\t\t\tstx_lock_event: {\n\t\t\t\t\t\tlocked_amount: a.amount!,\n\t\t\t\t\t\tunlock_height: \"0\",\n\t\t\t\t\t\tlocked_address: a.sender!,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t}\n\t}\n\n\tif (hEvent.event_type === \"fungible_token_asset\" && hEvent.asset) {\n\t\tconst a = hEvent.asset;\n\t\tconst assetId = a.asset_id || \"\";\n\t\tswitch (a.asset_event_type) {\n\t\t\tcase \"transfer\":\n\t\t\t\treturn {\n\t\t\t\t\t...base,\n\t\t\t\t\ttype: \"ft_transfer_event\",\n\t\t\t\t\tft_transfer_event: {\n\t\t\t\t\t\tasset_identifier: assetId,\n\t\t\t\t\t\tsender: a.sender!,\n\t\t\t\t\t\trecipient: a.recipient!,\n\t\t\t\t\t\tamount: a.amount!,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\tcase \"mint\":\n\t\t\t\treturn {\n\t\t\t\t\t...base,\n\t\t\t\t\ttype: \"ft_mint_event\",\n\t\t\t\t\tft_mint_event: {\n\t\t\t\t\t\tasset_identifier: assetId,\n\t\t\t\t\t\trecipient: a.recipient!,\n\t\t\t\t\t\tamount: a.amount!,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\tcase \"burn\":\n\t\t\t\treturn {\n\t\t\t\t\t...base,\n\t\t\t\t\ttype: \"ft_burn_event\",\n\t\t\t\t\tft_burn_event: {\n\t\t\t\t\t\tasset_identifier: assetId,\n\t\t\t\t\t\tsender: a.sender!,\n\t\t\t\t\t\tamount: a.amount!,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t}\n\t}\n\n\tif (hEvent.event_type === \"non_fungible_token_asset\" && hEvent.asset) {\n\t\tconst a = hEvent.asset;\n\t\tconst assetId = a.asset_id || \"\";\n\t\tswitch (a.asset_event_type) {\n\t\t\tcase \"transfer\":\n\t\t\t\treturn {\n\t\t\t\t\t...base,\n\t\t\t\t\ttype: \"nft_transfer_event\",\n\t\t\t\t\tnft_transfer_event: {\n\t\t\t\t\t\tasset_identifier: assetId,\n\t\t\t\t\t\tsender: a.sender!,\n\t\t\t\t\t\trecipient: a.recipient!,\n\t\t\t\t\t\tvalue: a.value,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\tcase \"mint\":\n\t\t\t\treturn {\n\t\t\t\t\t...base,\n\t\t\t\t\ttype: \"nft_mint_event\",\n\t\t\t\t\tnft_mint_event: {\n\t\t\t\t\t\tasset_identifier: assetId,\n\t\t\t\t\t\trecipient: a.recipient!,\n\t\t\t\t\t\tvalue: a.value,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\tcase \"burn\":\n\t\t\t\treturn {\n\t\t\t\t\t...base,\n\t\t\t\t\ttype: \"nft_burn_event\",\n\t\t\t\t\tnft_burn_event: {\n\t\t\t\t\t\tasset_identifier: assetId,\n\t\t\t\t\t\tsender: a.sender!,\n\t\t\t\t\t\tvalue: a.value,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t}\n\t}\n\n\tif (hEvent.event_type === \"smart_contract_log\" && hEvent.contract_log) {\n\t\treturn {\n\t\t\t...base,\n\t\t\ttype: \"smart_contract_event\",\n\t\t\tsmart_contract_event: {\n\t\t\t\tcontract_identifier: hEvent.contract_log.contract_id,\n\t\t\t\ttopic: hEvent.contract_log.topic,\n\t\t\t\tvalue: hEvent.contract_log.value,\n\t\t\t},\n\t\t};\n\t}\n\n\tlogger.debug(\"Unknown Hiro event type, skipping\", {\n\t\teventType: hEvent.event_type,\n\t\ttxId: hEvent.tx_id,\n\t});\n\treturn null;\n}\n"
8
8
  ],
9
- "mappings": "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",
10
- "debugId": "84E732ABB4DEC21A64756E2164756E21",
9
+ "mappings": "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",
10
+ "debugId": "FEEE8A495BF3115D64756E2164756E21",
11
11
  "names": []
12
12
  }
@@ -160,7 +160,12 @@ class HiroPgClient {
160
160
  `;
161
161
  for (const e of stxEvents) {
162
162
  const type = stxEventType(e.asset_event_type_id);
163
- const evt = { txid: toHex(e.tx_id), event_index: e.event_index, committed: true, type };
163
+ const evt = {
164
+ txid: toHex(e.tx_id),
165
+ event_index: e.event_index,
166
+ committed: true,
167
+ type
168
+ };
164
169
  if (type === "stx_transfer_event") {
165
170
  evt.stx_transfer_event = {
166
171
  sender: e.sender || "",
@@ -169,9 +174,15 @@ class HiroPgClient {
169
174
  ...e.memo ? { memo: toHex(e.memo) } : {}
170
175
  };
171
176
  } else if (type === "stx_mint_event") {
172
- evt.stx_mint_event = { recipient: e.recipient || "", amount: String(e.amount) };
177
+ evt.stx_mint_event = {
178
+ recipient: e.recipient || "",
179
+ amount: String(e.amount)
180
+ };
173
181
  } else if (type === "stx_burn_event") {
174
- evt.stx_burn_event = { sender: e.sender || "", amount: String(e.amount) };
182
+ evt.stx_burn_event = {
183
+ sender: e.sender || "",
184
+ amount: String(e.amount)
185
+ };
175
186
  }
176
187
  events.push(evt);
177
188
  }
@@ -202,7 +213,12 @@ class HiroPgClient {
202
213
  `;
203
214
  for (const e of ftEvents) {
204
215
  const type = ftEventType(e.asset_event_type_id);
205
- const evt = { txid: toHex(e.tx_id), event_index: e.event_index, committed: true, type };
216
+ const evt = {
217
+ txid: toHex(e.tx_id),
218
+ event_index: e.event_index,
219
+ committed: true,
220
+ type
221
+ };
206
222
  if (type === "ft_transfer_event") {
207
223
  evt.ft_transfer_event = {
208
224
  asset_identifier: e.asset_identifier,
@@ -211,9 +227,17 @@ class HiroPgClient {
211
227
  amount: String(e.amount)
212
228
  };
213
229
  } else if (type === "ft_mint_event") {
214
- evt.ft_mint_event = { asset_identifier: e.asset_identifier, recipient: e.recipient || "", amount: String(e.amount) };
230
+ evt.ft_mint_event = {
231
+ asset_identifier: e.asset_identifier,
232
+ recipient: e.recipient || "",
233
+ amount: String(e.amount)
234
+ };
215
235
  } else if (type === "ft_burn_event") {
216
- evt.ft_burn_event = { asset_identifier: e.asset_identifier, sender: e.sender || "", amount: String(e.amount) };
236
+ evt.ft_burn_event = {
237
+ asset_identifier: e.asset_identifier,
238
+ sender: e.sender || "",
239
+ amount: String(e.amount)
240
+ };
217
241
  }
218
242
  events.push(evt);
219
243
  }
@@ -225,14 +249,32 @@ class HiroPgClient {
225
249
  `;
226
250
  for (const e of nftEvents) {
227
251
  const type = nftEventType(e.asset_event_type_id);
228
- const evt = { txid: toHex(e.tx_id), event_index: e.event_index, committed: true, type };
252
+ const evt = {
253
+ txid: toHex(e.tx_id),
254
+ event_index: e.event_index,
255
+ committed: true,
256
+ type
257
+ };
229
258
  const val = toHex(e.value);
230
259
  if (type === "nft_transfer_event") {
231
- evt.nft_transfer_event = { asset_identifier: e.asset_identifier, sender: e.sender || "", recipient: e.recipient || "", value: val };
260
+ evt.nft_transfer_event = {
261
+ asset_identifier: e.asset_identifier,
262
+ sender: e.sender || "",
263
+ recipient: e.recipient || "",
264
+ value: val
265
+ };
232
266
  } else if (type === "nft_mint_event") {
233
- evt.nft_mint_event = { asset_identifier: e.asset_identifier, recipient: e.recipient || "", value: val };
267
+ evt.nft_mint_event = {
268
+ asset_identifier: e.asset_identifier,
269
+ recipient: e.recipient || "",
270
+ value: val
271
+ };
234
272
  } else if (type === "nft_burn_event") {
235
- evt.nft_burn_event = { asset_identifier: e.asset_identifier, sender: e.sender || "", value: val };
273
+ evt.nft_burn_event = {
274
+ asset_identifier: e.asset_identifier,
275
+ sender: e.sender || "",
276
+ value: val
277
+ };
236
278
  }
237
279
  events.push(evt);
238
280
  }
@@ -307,7 +349,10 @@ class HiroPgClient {
307
349
  sender_address: tx.sender_address
308
350
  };
309
351
  if (txType === "contract_call" && tx.contract_call_contract_id) {
310
- entry.contract_call = { contract_id: tx.contract_call_contract_id, function_name: tx.contract_call_function_name || "" };
352
+ entry.contract_call = {
353
+ contract_id: tx.contract_call_contract_id,
354
+ function_name: tx.contract_call_function_name || ""
355
+ };
311
356
  } else if (txType === "smart_contract" && tx.smart_contract_contract_id) {
312
357
  entry.smart_contract = { contract_id: tx.smart_contract_contract_id };
313
358
  }
@@ -323,13 +368,29 @@ class HiroPgClient {
323
368
  if (!block)
324
369
  continue;
325
370
  const type = stxEventType(e.asset_event_type_id);
326
- const evt = { txid: toHex(e.tx_id), event_index: e.event_index, committed: true, type };
371
+ const evt = {
372
+ txid: toHex(e.tx_id),
373
+ event_index: e.event_index,
374
+ committed: true,
375
+ type
376
+ };
327
377
  if (type === "stx_transfer_event") {
328
- evt.stx_transfer_event = { sender: e.sender || "", recipient: e.recipient || "", amount: String(e.amount), ...e.memo ? { memo: toHex(e.memo) } : {} };
378
+ evt.stx_transfer_event = {
379
+ sender: e.sender || "",
380
+ recipient: e.recipient || "",
381
+ amount: String(e.amount),
382
+ ...e.memo ? { memo: toHex(e.memo) } : {}
383
+ };
329
384
  } else if (type === "stx_mint_event") {
330
- evt.stx_mint_event = { recipient: e.recipient || "", amount: String(e.amount) };
385
+ evt.stx_mint_event = {
386
+ recipient: e.recipient || "",
387
+ amount: String(e.amount)
388
+ };
331
389
  } else if (type === "stx_burn_event") {
332
- evt.stx_burn_event = { sender: e.sender || "", amount: String(e.amount) };
390
+ evt.stx_burn_event = {
391
+ sender: e.sender || "",
392
+ amount: String(e.amount)
393
+ };
333
394
  }
334
395
  block.events.push(evt);
335
396
  }
@@ -347,7 +408,11 @@ class HiroPgClient {
347
408
  event_index: e.event_index,
348
409
  committed: true,
349
410
  type: "stx_lock_event",
350
- stx_lock_event: { locked_amount: String(e.locked_amount), unlock_height: String(e.unlock_height), locked_address: e.locked_address }
411
+ stx_lock_event: {
412
+ locked_amount: String(e.locked_amount),
413
+ unlock_height: String(e.unlock_height),
414
+ locked_address: e.locked_address
415
+ }
351
416
  });
352
417
  }
353
418
  const ftEvents = await this.sql`
@@ -360,13 +425,31 @@ class HiroPgClient {
360
425
  if (!block)
361
426
  continue;
362
427
  const type = ftEventType(e.asset_event_type_id);
363
- const evt = { txid: toHex(e.tx_id), event_index: e.event_index, committed: true, type };
428
+ const evt = {
429
+ txid: toHex(e.tx_id),
430
+ event_index: e.event_index,
431
+ committed: true,
432
+ type
433
+ };
364
434
  if (type === "ft_transfer_event") {
365
- evt.ft_transfer_event = { asset_identifier: e.asset_identifier, sender: e.sender || "", recipient: e.recipient || "", amount: String(e.amount) };
435
+ evt.ft_transfer_event = {
436
+ asset_identifier: e.asset_identifier,
437
+ sender: e.sender || "",
438
+ recipient: e.recipient || "",
439
+ amount: String(e.amount)
440
+ };
366
441
  } else if (type === "ft_mint_event") {
367
- evt.ft_mint_event = { asset_identifier: e.asset_identifier, recipient: e.recipient || "", amount: String(e.amount) };
442
+ evt.ft_mint_event = {
443
+ asset_identifier: e.asset_identifier,
444
+ recipient: e.recipient || "",
445
+ amount: String(e.amount)
446
+ };
368
447
  } else if (type === "ft_burn_event") {
369
- evt.ft_burn_event = { asset_identifier: e.asset_identifier, sender: e.sender || "", amount: String(e.amount) };
448
+ evt.ft_burn_event = {
449
+ asset_identifier: e.asset_identifier,
450
+ sender: e.sender || "",
451
+ amount: String(e.amount)
452
+ };
370
453
  }
371
454
  block.events.push(evt);
372
455
  }
@@ -380,14 +463,32 @@ class HiroPgClient {
380
463
  if (!block)
381
464
  continue;
382
465
  const type = nftEventType(e.asset_event_type_id);
383
- const evt = { txid: toHex(e.tx_id), event_index: e.event_index, committed: true, type };
466
+ const evt = {
467
+ txid: toHex(e.tx_id),
468
+ event_index: e.event_index,
469
+ committed: true,
470
+ type
471
+ };
384
472
  const val = toHex(e.value);
385
473
  if (type === "nft_transfer_event") {
386
- evt.nft_transfer_event = { asset_identifier: e.asset_identifier, sender: e.sender || "", recipient: e.recipient || "", value: val };
474
+ evt.nft_transfer_event = {
475
+ asset_identifier: e.asset_identifier,
476
+ sender: e.sender || "",
477
+ recipient: e.recipient || "",
478
+ value: val
479
+ };
387
480
  } else if (type === "nft_mint_event") {
388
- evt.nft_mint_event = { asset_identifier: e.asset_identifier, recipient: e.recipient || "", value: val };
481
+ evt.nft_mint_event = {
482
+ asset_identifier: e.asset_identifier,
483
+ recipient: e.recipient || "",
484
+ value: val
485
+ };
389
486
  } else if (type === "nft_burn_event") {
390
- evt.nft_burn_event = { asset_identifier: e.asset_identifier, sender: e.sender || "", value: val };
487
+ evt.nft_burn_event = {
488
+ asset_identifier: e.asset_identifier,
489
+ sender: e.sender || "",
490
+ value: val
491
+ };
391
492
  }
392
493
  block.events.push(evt);
393
494
  }
@@ -405,7 +506,11 @@ class HiroPgClient {
405
506
  event_index: e.event_index,
406
507
  committed: true,
407
508
  type: "smart_contract_event",
408
- smart_contract_event: { contract_identifier: e.contract_identifier, topic: e.topic, value: toHex(e.value) }
509
+ smart_contract_event: {
510
+ contract_identifier: e.contract_identifier,
511
+ topic: e.topic,
512
+ value: toHex(e.value)
513
+ }
409
514
  });
410
515
  }
411
516
  return heights.filter((h) => blockMap.has(h)).map((h) => {
@@ -434,5 +539,5 @@ export {
434
539
  HiroPgClient
435
540
  };
436
541
 
437
- //# debugId=E1188F876C00BE8364756E2164756E21
542
+ //# debugId=FA22CF35B56E552564756E2164756E21
438
543
  //# sourceMappingURL=hiro-pg-client.js.map