@secondlayer/subgraphs 0.8.1 → 0.9.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 (42) hide show
  1. package/dist/src/index.d.ts +113 -32
  2. package/dist/src/index.js +453 -99
  3. package/dist/src/index.js.map +9 -10
  4. package/dist/src/runtime/block-processor.d.ts +110 -20
  5. package/dist/src/runtime/block-processor.js +419 -90
  6. package/dist/src/runtime/block-processor.js.map +7 -8
  7. package/dist/src/runtime/catchup.d.ts +110 -20
  8. package/dist/src/runtime/catchup.js +424 -94
  9. package/dist/src/runtime/catchup.js.map +8 -9
  10. package/dist/src/runtime/clarity.js +3 -3
  11. package/dist/src/runtime/clarity.js.map +3 -3
  12. package/dist/src/runtime/context.d.ts +23 -5
  13. package/dist/src/runtime/context.js +57 -1
  14. package/dist/src/runtime/context.js.map +3 -3
  15. package/dist/src/runtime/processor.js +424 -94
  16. package/dist/src/runtime/processor.js.map +8 -9
  17. package/dist/src/runtime/reindex.d.ts +110 -20
  18. package/dist/src/runtime/reindex.js +419 -90
  19. package/dist/src/runtime/reindex.js.map +7 -8
  20. package/dist/src/runtime/reorg.d.ts +110 -20
  21. package/dist/src/runtime/reorg.js +419 -90
  22. package/dist/src/runtime/reorg.js.map +7 -8
  23. package/dist/src/runtime/runner.d.ts +150 -42
  24. package/dist/src/runtime/runner.js +193 -30
  25. package/dist/src/runtime/runner.js.map +4 -4
  26. package/dist/src/runtime/source-matcher.d.ts +86 -31
  27. package/dist/src/runtime/source-matcher.js +171 -61
  28. package/dist/src/runtime/source-matcher.js.map +4 -5
  29. package/dist/src/schema/index.d.ts +110 -20
  30. package/dist/src/schema/index.js +34 -9
  31. package/dist/src/schema/index.js.map +3 -3
  32. package/dist/src/service.js +424 -94
  33. package/dist/src/service.js.map +8 -9
  34. package/dist/src/templates.js +52 -51
  35. package/dist/src/templates.js.map +3 -3
  36. package/dist/src/types.d.ts +111 -29
  37. package/dist/src/types.js +1 -20
  38. package/dist/src/types.js.map +3 -4
  39. package/dist/src/validate.d.ts +112 -22
  40. package/dist/src/validate.js +35 -10
  41. package/dist/src/validate.js.map +3 -3
  42. package/package.json +2 -2
@@ -2,12 +2,12 @@ import { createRequire } from "node:module";
2
2
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
3
3
 
4
4
  // src/runtime/clarity.ts
5
- import { cvToJSON, deserializeCV } from "@secondlayer/stacks/clarity";
5
+ import { cvToValue, deserializeCV } from "@secondlayer/stacks/clarity";
6
6
  function decodeClarityValue(hex) {
7
7
  try {
8
8
  const cleanHex = hex.startsWith("0x") ? hex.slice(2) : hex;
9
9
  const cv = deserializeCV(cleanHex);
10
- return cvToJSON(cv);
10
+ return cvToValue(cv);
11
11
  } catch {
12
12
  return hex;
13
13
  }
@@ -36,19 +36,177 @@ function decodeFunctionArgs(args) {
36
36
  import { getErrorMessage } from "@secondlayer/shared";
37
37
  import { logger } from "@secondlayer/shared/logger";
38
38
  var DEFAULT_ERROR_THRESHOLD = 50;
39
- function resolveHandler(handlers, key) {
40
- return handlers[key] ?? handlers["*"] ?? null;
39
+ function camelCase(str) {
40
+ return str.replace(/-([a-z0-9])/g, (_, c) => c.toUpperCase());
41
+ }
42
+ function camelizeKeys(obj) {
43
+ if (obj === null || obj === undefined)
44
+ return obj;
45
+ if (typeof obj !== "object")
46
+ return obj;
47
+ if (Array.isArray(obj))
48
+ return obj.map(camelizeKeys);
49
+ const result = {};
50
+ for (const [k, v] of Object.entries(obj)) {
51
+ result[camelCase(k)] = camelizeKeys(v);
52
+ }
53
+ return result;
54
+ }
55
+ function buildEventPayload(filter, tx, event) {
56
+ const txMeta = {
57
+ txId: tx.tx_id,
58
+ sender: tx.sender,
59
+ type: tx.type,
60
+ status: tx.status,
61
+ contractId: tx.contract_id ?? null,
62
+ functionName: tx.function_name ?? null
63
+ };
64
+ if (!event) {
65
+ switch (filter.type) {
66
+ case "contract_call":
67
+ return {
68
+ contractId: tx.contract_id ?? "",
69
+ functionName: tx.function_name ?? "",
70
+ caller: tx.sender,
71
+ args: {},
72
+ result: null,
73
+ tx: txMeta
74
+ };
75
+ case "contract_deploy":
76
+ return {
77
+ contractId: tx.contract_id ?? "",
78
+ deployer: tx.sender,
79
+ tx: txMeta
80
+ };
81
+ default:
82
+ return { tx: txMeta };
83
+ }
84
+ }
85
+ const decoded = decodeEventData(event.data);
86
+ switch (filter.type) {
87
+ case "ft_transfer":
88
+ return {
89
+ sender: decoded.sender,
90
+ recipient: decoded.recipient,
91
+ amount: decoded.amount,
92
+ assetIdentifier: decoded.asset_identifier,
93
+ tx: txMeta
94
+ };
95
+ case "ft_mint":
96
+ return {
97
+ recipient: decoded.recipient,
98
+ amount: decoded.amount,
99
+ assetIdentifier: decoded.asset_identifier,
100
+ tx: txMeta
101
+ };
102
+ case "ft_burn":
103
+ return {
104
+ sender: decoded.sender,
105
+ amount: decoded.amount,
106
+ assetIdentifier: decoded.asset_identifier,
107
+ tx: txMeta
108
+ };
109
+ case "nft_transfer":
110
+ return {
111
+ sender: decoded.sender,
112
+ recipient: decoded.recipient,
113
+ tokenId: decoded.value,
114
+ assetIdentifier: decoded.asset_identifier,
115
+ tx: txMeta
116
+ };
117
+ case "nft_mint":
118
+ return {
119
+ recipient: decoded.recipient,
120
+ tokenId: decoded.value,
121
+ assetIdentifier: decoded.asset_identifier,
122
+ tx: txMeta
123
+ };
124
+ case "nft_burn":
125
+ return {
126
+ sender: decoded.sender,
127
+ tokenId: decoded.value,
128
+ assetIdentifier: decoded.asset_identifier,
129
+ tx: txMeta
130
+ };
131
+ case "stx_transfer":
132
+ return {
133
+ sender: decoded.sender,
134
+ recipient: decoded.recipient,
135
+ amount: decoded.amount,
136
+ memo: decoded.memo ?? "",
137
+ tx: txMeta
138
+ };
139
+ case "stx_mint":
140
+ return {
141
+ recipient: decoded.recipient,
142
+ amount: decoded.amount,
143
+ tx: txMeta
144
+ };
145
+ case "stx_burn":
146
+ return {
147
+ sender: decoded.sender,
148
+ amount: decoded.amount,
149
+ tx: txMeta
150
+ };
151
+ case "stx_lock":
152
+ return {
153
+ lockedAddress: decoded.locked_address,
154
+ lockedAmount: decoded.locked_amount,
155
+ unlockHeight: decoded.unlock_height,
156
+ tx: txMeta
157
+ };
158
+ case "print_event": {
159
+ const topic = decoded.topic ?? "";
160
+ const rawValue = decoded.value;
161
+ const data = rawValue && typeof rawValue === "object" ? camelizeKeys(rawValue) : rawValue;
162
+ return {
163
+ contractId: decoded.contract_identifier ?? tx.contract_id ?? "",
164
+ topic,
165
+ data: data ?? {},
166
+ tx: txMeta
167
+ };
168
+ }
169
+ case "contract_call":
170
+ return {
171
+ ...decoded,
172
+ _eventType: event.type,
173
+ contractId: tx.contract_id ?? "",
174
+ functionName: tx.function_name ?? "",
175
+ caller: tx.sender,
176
+ args: {},
177
+ result: null,
178
+ tx: txMeta
179
+ };
180
+ case "contract_deploy":
181
+ return {
182
+ contractId: tx.contract_id ?? "",
183
+ deployer: tx.sender,
184
+ tx: txMeta
185
+ };
186
+ default:
187
+ return {
188
+ ...decoded,
189
+ _eventType: event.type,
190
+ tx: txMeta
191
+ };
192
+ }
41
193
  }
42
194
  async function runHandlers(subgraph, matched, ctx, opts) {
43
195
  let processed = 0;
44
196
  let errors = 0;
45
197
  const threshold = opts?.errorThreshold ?? DEFAULT_ERROR_THRESHOLD;
46
- for (const { tx, events, sourceKey } of matched) {
47
- const handler = resolveHandler(subgraph.handlers, sourceKey);
198
+ const filterLookup = new Map;
199
+ if (!Array.isArray(subgraph.sources)) {
200
+ for (const [name, filter] of Object.entries(subgraph.sources)) {
201
+ filterLookup.set(name, filter);
202
+ }
203
+ }
204
+ for (const { tx, events, sourceName } of matched) {
205
+ const handler = subgraph.handlers[sourceName] ?? subgraph.handlers["*"] ?? null;
48
206
  if (!handler) {
49
- logger.warn("No handler found for source key", {
207
+ logger.warn("No handler found for source", {
50
208
  subgraph: subgraph.name,
51
- sourceKey,
209
+ sourceName,
52
210
  txId: tx.tx_id
53
211
  });
54
212
  continue;
@@ -57,11 +215,14 @@ async function runHandlers(subgraph, matched, ctx, opts) {
57
215
  txId: tx.tx_id,
58
216
  sender: tx.sender,
59
217
  type: tx.type,
60
- status: tx.status
218
+ status: tx.status,
219
+ contractId: tx.contract_id ?? null,
220
+ functionName: tx.function_name ?? null
61
221
  });
222
+ const filter = filterLookup.get(sourceName);
62
223
  if (events.length === 0) {
63
224
  try {
64
- const txPayload = {
225
+ const payload = filter ? buildEventPayload(filter, tx, null) : {
65
226
  tx: {
66
227
  txId: tx.tx_id,
67
228
  sender: tx.sender,
@@ -71,13 +232,13 @@ async function runHandlers(subgraph, matched, ctx, opts) {
71
232
  functionName: tx.function_name
72
233
  }
73
234
  };
74
- await handler(txPayload, ctx);
235
+ await handler(payload, ctx);
75
236
  processed++;
76
237
  } catch (err) {
77
238
  errors++;
78
239
  logger.error("Subgraph handler error", {
79
240
  subgraph: subgraph.name,
80
- sourceKey,
241
+ sourceName,
81
242
  txId: tx.tx_id,
82
243
  error: getErrorMessage(err)
83
244
  });
@@ -94,28 +255,30 @@ async function runHandlers(subgraph, matched, ctx, opts) {
94
255
  return { processed, errors };
95
256
  }
96
257
  try {
97
- const decoded = decodeEventData(event.data);
98
- const eventPayload = {
99
- ...decoded,
100
- _eventId: event.id,
101
- _eventType: event.type,
102
- _eventIndex: event.event_index,
103
- tx: {
104
- txId: tx.tx_id,
105
- sender: tx.sender,
106
- type: tx.type,
107
- status: tx.status,
108
- contractId: tx.contract_id,
109
- functionName: tx.function_name
110
- }
111
- };
112
- await handler(eventPayload, ctx);
258
+ const payload = filter ? buildEventPayload(filter, tx, event) : (() => {
259
+ const decoded = decodeEventData(event.data);
260
+ return {
261
+ ...decoded,
262
+ _eventId: event.id,
263
+ _eventType: event.type,
264
+ _eventIndex: event.event_index,
265
+ tx: {
266
+ txId: tx.tx_id,
267
+ sender: tx.sender,
268
+ type: tx.type,
269
+ status: tx.status,
270
+ contractId: tx.contract_id,
271
+ functionName: tx.function_name
272
+ }
273
+ };
274
+ })();
275
+ await handler(payload, ctx);
113
276
  processed++;
114
277
  } catch (err) {
115
278
  errors++;
116
279
  logger.error("Subgraph handler error", {
117
280
  subgraph: subgraph.name,
118
- sourceKey,
281
+ sourceName,
119
282
  txId: tx.tx_id,
120
283
  eventId: event.id,
121
284
  eventType: event.type,
@@ -130,5 +293,5 @@ export {
130
293
  runHandlers
131
294
  };
132
295
 
133
- //# debugId=611E9DD629D6006D64756E2164756E21
296
+ //# debugId=7008E1755DAEF1C564756E2164756E21
134
297
  //# sourceMappingURL=runner.js.map
@@ -2,10 +2,10 @@
2
2
  "version": 3,
3
3
  "sources": ["../src/runtime/clarity.ts", "../src/runtime/runner.ts"],
4
4
  "sourcesContent": [
5
- "import { cvToJSON, deserializeCV } from \"@secondlayer/stacks/clarity\";\n\n/**\n * Decode a hex-encoded Clarity value to a JS object.\n * Returns original value on failure.\n */\nexport function decodeClarityValue(hex: string): unknown {\n\ttry {\n\t\tconst cleanHex = hex.startsWith(\"0x\") ? hex.slice(2) : hex;\n\t\tconst cv = deserializeCV(cleanHex);\n\t\treturn cvToJSON(cv);\n\t} catch {\n\t\treturn hex;\n\t}\n}\n\n/**\n * Recursively decode all hex-encoded Clarity values in an object.\n * Any string starting with \"0x\" and longer than 10 chars is attempted.\n */\nexport function decodeEventData(data: unknown): unknown {\n\tif (typeof data === \"string\" && data.startsWith(\"0x\") && data.length > 10) {\n\t\treturn decodeClarityValue(data);\n\t}\n\n\tif (Array.isArray(data)) {\n\t\treturn data.map(decodeEventData);\n\t}\n\n\tif (typeof data === \"object\" && data !== null) {\n\t\tconst decoded: Record<string, unknown> = {};\n\t\tfor (const [key, value] of Object.entries(data)) {\n\t\t\tdecoded[key] = decodeEventData(value);\n\t\t}\n\t\treturn decoded;\n\t}\n\n\treturn data;\n}\n\n/**\n * Decode function args array (hex-encoded Clarity values).\n */\nexport function decodeFunctionArgs(args: string[]): unknown[] {\n\treturn args.map(decodeClarityValue);\n}\n",
6
- "import { getErrorMessage } from \"@secondlayer/shared\";\nimport { logger } from \"@secondlayer/shared/logger\";\nimport type { SubgraphDefinition } from \"../types.ts\";\nimport { decodeEventData } from \"./clarity.ts\";\nimport type { SubgraphContext } from \"./context.ts\";\nimport type { MatchedTx } from \"./source-matcher.ts\";\n\n/** Max consecutive handler errors before marking subgraph as error */\nconst DEFAULT_ERROR_THRESHOLD = 50;\n\nexport interface RunResult {\n\tprocessed: number;\n\terrors: number;\n}\n\n/**\n * Resolve the handler for a matched tx.\n * Looks up by sourceKey first, then falls back to \"*\" catch-all.\n */\nfunction resolveHandler(handlers: SubgraphDefinition[\"handlers\"], key: string) {\n\treturn handlers[key] ?? handlers[\"*\"] ?? null;\n}\n\n/**\n * Run a subgraph's keyed handlers against all matched transactions/events.\n *\n * Each MatchedTx carries a sourceKey from the matcher. The runner looks up\n * the corresponding handler in subgraph.handlers, falling back to \"*\".\n *\n * Does NOT flush — caller is responsible for flushing ctx after run.\n */\nexport async function runHandlers(\n\tsubgraph: SubgraphDefinition,\n\tmatched: MatchedTx[],\n\tctx: SubgraphContext,\n\topts?: { errorThreshold?: number },\n): Promise<RunResult> {\n\tlet processed = 0;\n\tlet errors = 0;\n\tconst threshold = opts?.errorThreshold ?? DEFAULT_ERROR_THRESHOLD;\n\n\tfor (const { tx, events, sourceKey } of matched) {\n\t\tconst handler = resolveHandler(subgraph.handlers, sourceKey);\n\t\tif (!handler) {\n\t\t\tlogger.warn(\"No handler found for source key\", {\n\t\t\t\tsubgraph: subgraph.name,\n\t\t\t\tsourceKey,\n\t\t\t\ttxId: tx.tx_id,\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\n\t\tctx.setTx({\n\t\t\ttxId: tx.tx_id,\n\t\t\tsender: tx.sender,\n\t\t\ttype: tx.type,\n\t\t\tstatus: tx.status,\n\t\t});\n\n\t\t// If no events but tx matched, call handler with tx-level data\n\t\tif (events.length === 0) {\n\t\t\ttry {\n\t\t\t\tconst txPayload: Record<string, unknown> = {\n\t\t\t\t\ttx: {\n\t\t\t\t\t\ttxId: tx.tx_id,\n\t\t\t\t\t\tsender: tx.sender,\n\t\t\t\t\t\ttype: tx.type,\n\t\t\t\t\t\tstatus: tx.status,\n\t\t\t\t\t\tcontractId: tx.contract_id,\n\t\t\t\t\t\tfunctionName: tx.function_name,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t\tawait handler(txPayload, ctx);\n\t\t\t\tprocessed++;\n\t\t\t} catch (err) {\n\t\t\t\terrors++;\n\t\t\t\tlogger.error(\"Subgraph handler error\", {\n\t\t\t\t\tsubgraph: subgraph.name,\n\t\t\t\t\tsourceKey,\n\t\t\t\t\ttxId: tx.tx_id,\n\t\t\t\t\terror: getErrorMessage(err),\n\t\t\t\t});\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tfor (const event of events) {\n\t\t\tif (errors >= threshold) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t\"Subgraph error threshold reached, skipping remaining events\",\n\t\t\t\t\t{\n\t\t\t\t\t\tsubgraph: subgraph.name,\n\t\t\t\t\t\terrors,\n\t\t\t\t\t\tthreshold,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\treturn { processed, errors };\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst decoded = decodeEventData(event.data) as Record<string, unknown>;\n\t\t\t\tconst eventPayload: Record<string, unknown> = {\n\t\t\t\t\t...decoded,\n\t\t\t\t\t_eventId: event.id,\n\t\t\t\t\t_eventType: event.type,\n\t\t\t\t\t_eventIndex: event.event_index,\n\t\t\t\t\ttx: {\n\t\t\t\t\t\ttxId: tx.tx_id,\n\t\t\t\t\t\tsender: tx.sender,\n\t\t\t\t\t\ttype: tx.type,\n\t\t\t\t\t\tstatus: tx.status,\n\t\t\t\t\t\tcontractId: tx.contract_id,\n\t\t\t\t\t\tfunctionName: tx.function_name,\n\t\t\t\t\t},\n\t\t\t\t};\n\n\t\t\t\tawait handler(eventPayload, ctx);\n\t\t\t\tprocessed++;\n\t\t\t} catch (err) {\n\t\t\t\terrors++;\n\t\t\t\tlogger.error(\"Subgraph handler error\", {\n\t\t\t\t\tsubgraph: subgraph.name,\n\t\t\t\t\tsourceKey,\n\t\t\t\t\ttxId: tx.tx_id,\n\t\t\t\t\teventId: event.id,\n\t\t\t\t\teventType: event.type,\n\t\t\t\t\terror: getErrorMessage(err),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { processed, errors };\n}\n"
5
+ "import { cvToValue, deserializeCV } from \"@secondlayer/stacks/clarity\";\n\n/**\n * Decode a hex-encoded Clarity value to a JS object.\n * Returns original value on failure.\n */\nexport function decodeClarityValue(hex: string): unknown {\n\ttry {\n\t\tconst cleanHex = hex.startsWith(\"0x\") ? hex.slice(2) : hex;\n\t\tconst cv = deserializeCV(cleanHex);\n\t\treturn cvToValue(cv);\n\t} catch {\n\t\treturn hex;\n\t}\n}\n\n/**\n * Recursively decode all hex-encoded Clarity values in an object.\n * Any string starting with \"0x\" and longer than 10 chars is attempted.\n */\nexport function decodeEventData(data: unknown): unknown {\n\tif (typeof data === \"string\" && data.startsWith(\"0x\") && data.length > 10) {\n\t\treturn decodeClarityValue(data);\n\t}\n\n\tif (Array.isArray(data)) {\n\t\treturn data.map(decodeEventData);\n\t}\n\n\tif (typeof data === \"object\" && data !== null) {\n\t\tconst decoded: Record<string, unknown> = {};\n\t\tfor (const [key, value] of Object.entries(data)) {\n\t\t\tdecoded[key] = decodeEventData(value);\n\t\t}\n\t\treturn decoded;\n\t}\n\n\treturn data;\n}\n\n/**\n * Decode function args array (hex-encoded Clarity values).\n */\nexport function decodeFunctionArgs(args: string[]): unknown[] {\n\treturn args.map(decodeClarityValue);\n}\n",
6
+ "import { getErrorMessage } from \"@secondlayer/shared\";\nimport { logger } from \"@secondlayer/shared/logger\";\nimport type { SubgraphDefinition, SubgraphFilter } from \"../types.ts\";\nimport { decodeEventData } from \"./clarity.ts\";\nimport type { SubgraphContext } from \"./context.ts\";\nimport type { MatchedTx } from \"./source-matcher.ts\";\n\n/** Max consecutive handler errors before marking subgraph as error */\nconst DEFAULT_ERROR_THRESHOLD = 50;\n\nexport interface RunResult {\n\tprocessed: number;\n\terrors: number;\n}\n\n/** Convert kebab-case to camelCase: \"bitcoin-txid\" → \"bitcoinTxid\" */\nfunction camelCase(str: string): string {\n\treturn str.replace(/-([a-z0-9])/g, (_, c) => c.toUpperCase());\n}\n\n/** Recursively camelize all object keys */\nfunction camelizeKeys(obj: unknown): unknown {\n\tif (obj === null || obj === undefined) return obj;\n\tif (typeof obj !== \"object\") return obj;\n\tif (Array.isArray(obj)) return obj.map(camelizeKeys);\n\tconst result: Record<string, unknown> = {};\n\tfor (const [k, v] of Object.entries(obj as Record<string, unknown>)) {\n\t\tresult[camelCase(k)] = camelizeKeys(v);\n\t}\n\treturn result;\n}\n\n/**\n * Build a typed event payload based on the source filter type.\n * Returns the payload the handler will receive.\n */\nfunction buildEventPayload(\n\tfilter: SubgraphFilter,\n\ttx: MatchedTx[\"tx\"],\n\tevent: MatchedTx[\"events\"][0] | null,\n): Record<string, unknown> {\n\tconst txMeta = {\n\t\ttxId: tx.tx_id,\n\t\tsender: tx.sender,\n\t\ttype: tx.type,\n\t\tstatus: tx.status,\n\t\tcontractId: tx.contract_id ?? null,\n\t\tfunctionName: tx.function_name ?? null,\n\t};\n\n\t// No event — tx-level match (contract_call or contract_deploy)\n\tif (!event) {\n\t\tswitch (filter.type) {\n\t\t\tcase \"contract_call\":\n\t\t\t\treturn {\n\t\t\t\t\tcontractId: tx.contract_id ?? \"\",\n\t\t\t\t\tfunctionName: tx.function_name ?? \"\",\n\t\t\t\t\tcaller: tx.sender,\n\t\t\t\t\targs: {}, // TODO: decode from ABI when available\n\t\t\t\t\tresult: null,\n\t\t\t\t\ttx: txMeta,\n\t\t\t\t};\n\t\t\tcase \"contract_deploy\":\n\t\t\t\treturn {\n\t\t\t\t\tcontractId: tx.contract_id ?? \"\",\n\t\t\t\t\tdeployer: tx.sender,\n\t\t\t\t\ttx: txMeta,\n\t\t\t\t};\n\t\t\tdefault:\n\t\t\t\treturn { tx: txMeta };\n\t\t}\n\t}\n\n\t// Decode event data (Clarity values auto-unwrapped via cvToValue)\n\tconst decoded = decodeEventData(event.data) as Record<string, unknown>;\n\n\tswitch (filter.type) {\n\t\t// ── FT events ──\n\t\tcase \"ft_transfer\":\n\t\t\treturn {\n\t\t\t\tsender: decoded.sender as string,\n\t\t\t\trecipient: decoded.recipient as string,\n\t\t\t\tamount: decoded.amount,\n\t\t\t\tassetIdentifier: decoded.asset_identifier as string,\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\t\tcase \"ft_mint\":\n\t\t\treturn {\n\t\t\t\trecipient: decoded.recipient as string,\n\t\t\t\tamount: decoded.amount,\n\t\t\t\tassetIdentifier: decoded.asset_identifier as string,\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\t\tcase \"ft_burn\":\n\t\t\treturn {\n\t\t\t\tsender: decoded.sender as string,\n\t\t\t\tamount: decoded.amount,\n\t\t\t\tassetIdentifier: decoded.asset_identifier as string,\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\n\t\t// ── NFT events ──\n\t\tcase \"nft_transfer\":\n\t\t\treturn {\n\t\t\t\tsender: decoded.sender as string,\n\t\t\t\trecipient: decoded.recipient as string,\n\t\t\t\ttokenId: decoded.value,\n\t\t\t\tassetIdentifier: decoded.asset_identifier as string,\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\t\tcase \"nft_mint\":\n\t\t\treturn {\n\t\t\t\trecipient: decoded.recipient as string,\n\t\t\t\ttokenId: decoded.value,\n\t\t\t\tassetIdentifier: decoded.asset_identifier as string,\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\t\tcase \"nft_burn\":\n\t\t\treturn {\n\t\t\t\tsender: decoded.sender as string,\n\t\t\t\ttokenId: decoded.value,\n\t\t\t\tassetIdentifier: decoded.asset_identifier as string,\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\n\t\t// ── STX events ──\n\t\tcase \"stx_transfer\":\n\t\t\treturn {\n\t\t\t\tsender: decoded.sender as string,\n\t\t\t\trecipient: decoded.recipient as string,\n\t\t\t\tamount: decoded.amount,\n\t\t\t\tmemo: decoded.memo ?? \"\",\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\t\tcase \"stx_mint\":\n\t\t\treturn {\n\t\t\t\trecipient: decoded.recipient as string,\n\t\t\t\tamount: decoded.amount,\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\t\tcase \"stx_burn\":\n\t\t\treturn {\n\t\t\t\tsender: decoded.sender as string,\n\t\t\t\tamount: decoded.amount,\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\t\tcase \"stx_lock\":\n\t\t\treturn {\n\t\t\t\tlockedAddress: decoded.locked_address as string,\n\t\t\t\tlockedAmount: decoded.locked_amount,\n\t\t\t\tunlockHeight: decoded.unlock_height,\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\n\t\t// ── Print event ──\n\t\tcase \"print_event\": {\n\t\t\tconst topic = decoded.topic as string ?? \"\";\n\t\t\tconst rawValue = decoded.value;\n\t\t\t// Camelize keys for developer convenience\n\t\t\tconst data =\n\t\t\t\trawValue && typeof rawValue === \"object\"\n\t\t\t\t\t? (camelizeKeys(rawValue) as Record<string, unknown>)\n\t\t\t\t\t: rawValue;\n\t\t\treturn {\n\t\t\t\tcontractId: decoded.contract_identifier as string ?? tx.contract_id ?? \"\",\n\t\t\t\ttopic,\n\t\t\t\tdata: data ?? {},\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\t\t}\n\n\t\t// ── Contract call (with events) ──\n\t\tcase \"contract_call\":\n\t\t\treturn {\n\t\t\t\t...decoded,\n\t\t\t\t_eventType: event.type,\n\t\t\t\tcontractId: tx.contract_id ?? \"\",\n\t\t\t\tfunctionName: tx.function_name ?? \"\",\n\t\t\t\tcaller: tx.sender,\n\t\t\t\targs: {}, // TODO: decode from ABI\n\t\t\t\tresult: null,\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\n\t\t// ── Contract deploy ──\n\t\tcase \"contract_deploy\":\n\t\t\treturn {\n\t\t\t\tcontractId: tx.contract_id ?? \"\",\n\t\t\t\tdeployer: tx.sender,\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\n\t\tdefault:\n\t\t\t// Fallback: spread decoded data with tx metadata\n\t\t\treturn {\n\t\t\t\t...decoded,\n\t\t\t\t_eventType: event.type,\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\t}\n}\n\n/**\n * Run a subgraph's keyed handlers against all matched transactions/events.\n *\n * Each MatchedTx carries a sourceName from the matcher. The runner looks up\n * the corresponding handler in subgraph.handlers, falling back to \"*\".\n *\n * Does NOT flush — caller is responsible for flushing ctx after run.\n */\nexport async function runHandlers(\n\tsubgraph: SubgraphDefinition,\n\tmatched: MatchedTx[],\n\tctx: SubgraphContext,\n\topts?: { errorThreshold?: number },\n): Promise<RunResult> {\n\tlet processed = 0;\n\tlet errors = 0;\n\tconst threshold = opts?.errorThreshold ?? DEFAULT_ERROR_THRESHOLD;\n\n\t// Build filter lookup from sources (supports both array and named object)\n\tconst filterLookup = new Map<string, SubgraphFilter>();\n\tif (!Array.isArray(subgraph.sources)) {\n\t\tfor (const [name, filter] of Object.entries(\n\t\t\tsubgraph.sources as Record<string, SubgraphFilter>,\n\t\t)) {\n\t\t\tfilterLookup.set(name, filter);\n\t\t}\n\t}\n\n\tfor (const { tx, events, sourceName } of matched) {\n\t\tconst handler =\n\t\t\tsubgraph.handlers[sourceName] ?? subgraph.handlers[\"*\"] ?? null;\n\t\tif (!handler) {\n\t\t\tlogger.warn(\"No handler found for source\", {\n\t\t\t\tsubgraph: subgraph.name,\n\t\t\t\tsourceName,\n\t\t\t\ttxId: tx.tx_id,\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\n\t\tctx.setTx({\n\t\t\ttxId: tx.tx_id,\n\t\t\tsender: tx.sender,\n\t\t\ttype: tx.type,\n\t\t\tstatus: tx.status,\n\t\t\tcontractId: tx.contract_id ?? null,\n\t\t\tfunctionName: tx.function_name ?? null,\n\t\t});\n\n\t\tconst filter = filterLookup.get(sourceName);\n\n\t\t// If no events but tx matched, call handler with tx-level data\n\t\tif (events.length === 0) {\n\t\t\ttry {\n\t\t\t\tconst payload = filter\n\t\t\t\t\t? buildEventPayload(filter, tx, null)\n\t\t\t\t\t: {\n\t\t\t\t\t\t\ttx: {\n\t\t\t\t\t\t\t\ttxId: tx.tx_id,\n\t\t\t\t\t\t\t\tsender: tx.sender,\n\t\t\t\t\t\t\t\ttype: tx.type,\n\t\t\t\t\t\t\t\tstatus: tx.status,\n\t\t\t\t\t\t\t\tcontractId: tx.contract_id,\n\t\t\t\t\t\t\t\tfunctionName: tx.function_name,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t};\n\t\t\t\tawait handler(payload, ctx);\n\t\t\t\tprocessed++;\n\t\t\t} catch (err) {\n\t\t\t\terrors++;\n\t\t\t\tlogger.error(\"Subgraph handler error\", {\n\t\t\t\t\tsubgraph: subgraph.name,\n\t\t\t\t\tsourceName,\n\t\t\t\t\ttxId: tx.tx_id,\n\t\t\t\t\terror: getErrorMessage(err),\n\t\t\t\t});\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tfor (const event of events) {\n\t\t\tif (errors >= threshold) {\n\t\t\t\tlogger.error(\n\t\t\t\t\t\"Subgraph error threshold reached, skipping remaining events\",\n\t\t\t\t\t{\n\t\t\t\t\t\tsubgraph: subgraph.name,\n\t\t\t\t\t\terrors,\n\t\t\t\t\t\tthreshold,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t\treturn { processed, errors };\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst payload = filter\n\t\t\t\t\t? buildEventPayload(filter, tx, event)\n\t\t\t\t\t: (() => {\n\t\t\t\t\t\t\tconst decoded = decodeEventData(event.data) as Record<\n\t\t\t\t\t\t\t\tstring,\n\t\t\t\t\t\t\t\tunknown\n\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t...decoded,\n\t\t\t\t\t\t\t\t_eventId: event.id,\n\t\t\t\t\t\t\t\t_eventType: event.type,\n\t\t\t\t\t\t\t\t_eventIndex: event.event_index,\n\t\t\t\t\t\t\t\ttx: {\n\t\t\t\t\t\t\t\t\ttxId: tx.tx_id,\n\t\t\t\t\t\t\t\t\tsender: tx.sender,\n\t\t\t\t\t\t\t\t\ttype: tx.type,\n\t\t\t\t\t\t\t\t\tstatus: tx.status,\n\t\t\t\t\t\t\t\t\tcontractId: tx.contract_id,\n\t\t\t\t\t\t\t\t\tfunctionName: tx.function_name,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t})();\n\n\t\t\t\tawait handler(payload, ctx);\n\t\t\t\tprocessed++;\n\t\t\t} catch (err) {\n\t\t\t\terrors++;\n\t\t\t\tlogger.error(\"Subgraph handler error\", {\n\t\t\t\t\tsubgraph: subgraph.name,\n\t\t\t\t\tsourceName,\n\t\t\t\t\ttxId: tx.tx_id,\n\t\t\t\t\teventId: event.id,\n\t\t\t\t\teventType: event.type,\n\t\t\t\t\terror: getErrorMessage(err),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { processed, errors };\n}\n"
7
7
  ],
8
- "mappings": "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",
9
- "debugId": "611E9DD629D6006D64756E2164756E21",
8
+ "mappings": "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",
9
+ "debugId": "7008E1755DAEF1C564756E2164756E21",
10
10
  "names": []
11
11
  }
@@ -1,34 +1,89 @@
1
- /** Source filter for what blockchain data this subgraph processes */
2
- interface SubgraphSource {
3
- /** Contract principal (e.g., SP000...::contract-name). Supports * wildcards. */
4
- contract?: string;
5
- /** Event name/topic to filter on */
6
- event?: string;
7
- /** Function name to filter on */
8
- function?: string;
9
- /** Transaction type filter (e.g., "stx_transfer", "contract_call") */
10
- type?: string;
11
- /** Minimum amount filter (for stx_transfer sources) */
1
+ /** STX event filters */
2
+ interface StxTransferFilter {
3
+ type: "stx_transfer";
4
+ sender?: string;
5
+ recipient?: string;
12
6
  minAmount?: bigint;
7
+ maxAmount?: bigint;
13
8
  }
9
+ interface StxMintFilter {
10
+ type: "stx_mint";
11
+ recipient?: string;
12
+ minAmount?: bigint;
13
+ }
14
+ interface StxBurnFilter {
15
+ type: "stx_burn";
16
+ sender?: string;
17
+ minAmount?: bigint;
18
+ }
19
+ interface StxLockFilter {
20
+ type: "stx_lock";
21
+ lockedAddress?: string;
22
+ minAmount?: bigint;
23
+ }
24
+ /** FT event filters */
25
+ interface FtTransferFilter {
26
+ type: "ft_transfer";
27
+ assetIdentifier?: string;
28
+ sender?: string;
29
+ recipient?: string;
30
+ minAmount?: bigint;
31
+ }
32
+ interface FtMintFilter {
33
+ type: "ft_mint";
34
+ assetIdentifier?: string;
35
+ recipient?: string;
36
+ minAmount?: bigint;
37
+ }
38
+ interface FtBurnFilter {
39
+ type: "ft_burn";
40
+ assetIdentifier?: string;
41
+ sender?: string;
42
+ minAmount?: bigint;
43
+ }
44
+ /** NFT event filters */
45
+ interface NftTransferFilter {
46
+ type: "nft_transfer";
47
+ assetIdentifier?: string;
48
+ sender?: string;
49
+ recipient?: string;
50
+ }
51
+ interface NftMintFilter {
52
+ type: "nft_mint";
53
+ assetIdentifier?: string;
54
+ recipient?: string;
55
+ }
56
+ interface NftBurnFilter {
57
+ type: "nft_burn";
58
+ assetIdentifier?: string;
59
+ sender?: string;
60
+ }
61
+ /** Contract event filters */
62
+ interface ContractCallFilter {
63
+ type: "contract_call";
64
+ contractId?: string;
65
+ functionName?: string;
66
+ caller?: string;
67
+ /** ABI for typed event.args. If omitted, auto-fetched at deploy time. */
68
+ abi?: Record<string, unknown>;
69
+ }
70
+ interface ContractDeployFilter {
71
+ type: "contract_deploy";
72
+ deployer?: string;
73
+ contractName?: string;
74
+ }
75
+ interface PrintEventFilter {
76
+ type: "print_event";
77
+ contractId?: string;
78
+ topic?: string;
79
+ }
80
+ /** All subgraph filter types — discriminated on `type` */
81
+ type SubgraphFilter = StxTransferFilter | StxMintFilter | StxBurnFilter | StxLockFilter | FtTransferFilter | FtMintFilter | FtBurnFilter | NftTransferFilter | NftMintFilter | NftBurnFilter | ContractCallFilter | ContractDeployFilter | PrintEventFilter;
14
82
  interface MatchedTx {
15
- tx: {
16
- tx_id: string
17
- type: string
18
- sender: string
19
- status: string
20
- contract_id?: string | null
21
- function_name?: string | null
22
- };
23
- events: {
24
- id: string
25
- tx_id: string
26
- type: string
27
- event_index: number
28
- data: unknown
29
- }[];
30
- /** Which source produced this match — used for handler dispatch */
31
- sourceKey: string;
83
+ tx: TxRecord;
84
+ events: EventRecord[];
85
+ /** Source object key — used for handler dispatch */
86
+ sourceName: string;
32
87
  }
33
88
  type TxRecord = {
34
89
  tx_id: string
@@ -46,8 +101,8 @@ type EventRecord = {
46
101
  data: unknown
47
102
  };
48
103
  /**
49
- * Match all sources against a block's transactions and events.
50
- * Deduplicates by (txId, sourceKey) each handler key fires at most once per tx.
104
+ * Match named filters against a block's transactions and events.
105
+ * Returns matches with sourceName = the object key from sources.
51
106
  */
52
- declare function matchSources(sources: SubgraphSource[], transactions: TxRecord[], events: EventRecord[]): MatchedTx[];
107
+ declare function matchSources(sources: Record<string, SubgraphFilter>, transactions: TxRecord[], events: EventRecord[]): MatchedTx[];
53
108
  export { matchSources, MatchedTx };