@secondlayer/subgraphs 0.8.1 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/index.d.ts +113 -32
- package/dist/src/index.js +486 -99
- package/dist/src/index.js.map +9 -10
- package/dist/src/runtime/block-processor.d.ts +110 -20
- package/dist/src/runtime/block-processor.js +452 -90
- package/dist/src/runtime/block-processor.js.map +7 -8
- package/dist/src/runtime/catchup.d.ts +110 -20
- package/dist/src/runtime/catchup.js +457 -94
- package/dist/src/runtime/catchup.js.map +8 -9
- package/dist/src/runtime/clarity.js +3 -3
- package/dist/src/runtime/clarity.js.map +3 -3
- package/dist/src/runtime/context.d.ts +23 -5
- package/dist/src/runtime/context.js +57 -1
- package/dist/src/runtime/context.js.map +3 -3
- package/dist/src/runtime/processor.js +457 -94
- package/dist/src/runtime/processor.js.map +8 -9
- package/dist/src/runtime/reindex.d.ts +110 -20
- package/dist/src/runtime/reindex.js +452 -90
- package/dist/src/runtime/reindex.js.map +7 -8
- package/dist/src/runtime/reorg.d.ts +110 -20
- package/dist/src/runtime/reorg.js +452 -90
- package/dist/src/runtime/reorg.js.map +7 -8
- package/dist/src/runtime/runner.d.ts +152 -42
- package/dist/src/runtime/runner.js +226 -30
- package/dist/src/runtime/runner.js.map +4 -4
- package/dist/src/runtime/source-matcher.d.ts +88 -31
- package/dist/src/runtime/source-matcher.js +171 -61
- package/dist/src/runtime/source-matcher.js.map +4 -5
- package/dist/src/schema/index.d.ts +110 -20
- package/dist/src/schema/index.js +34 -9
- package/dist/src/schema/index.js.map +3 -3
- package/dist/src/service.js +457 -94
- package/dist/src/service.js.map +8 -9
- package/dist/src/templates.js +52 -51
- package/dist/src/templates.js.map +3 -3
- package/dist/src/types.d.ts +111 -29
- package/dist/src/types.js +1 -20
- package/dist/src/types.js.map +3 -4
- package/dist/src/validate.d.ts +112 -22
- package/dist/src/validate.js +35 -10
- package/dist/src/validate.js.map +3 -3
- 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 {
|
|
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
|
|
10
|
+
return cvToValue(cv);
|
|
11
11
|
} catch {
|
|
12
12
|
return hex;
|
|
13
13
|
}
|
|
@@ -36,19 +36,210 @@ 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
|
|
40
|
-
return
|
|
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 decodeFunctionArgs2(args) {
|
|
56
|
+
if (!Array.isArray(args))
|
|
57
|
+
return [];
|
|
58
|
+
return args.map((arg) => {
|
|
59
|
+
if (typeof arg === "string")
|
|
60
|
+
return decodeClarityValue(arg);
|
|
61
|
+
return arg;
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
function decodeRawResult(raw) {
|
|
65
|
+
if (typeof raw === "string" && raw.length > 2) {
|
|
66
|
+
return decodeClarityValue(raw);
|
|
67
|
+
}
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
function safeBigInt(val) {
|
|
71
|
+
if (typeof val === "bigint")
|
|
72
|
+
return val;
|
|
73
|
+
if (typeof val === "number")
|
|
74
|
+
return BigInt(val);
|
|
75
|
+
if (typeof val === "string") {
|
|
76
|
+
try {
|
|
77
|
+
return BigInt(val);
|
|
78
|
+
} catch {
|
|
79
|
+
return 0n;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return 0n;
|
|
83
|
+
}
|
|
84
|
+
function buildEventPayload(filter, tx, event) {
|
|
85
|
+
const txMeta = {
|
|
86
|
+
txId: tx.tx_id,
|
|
87
|
+
sender: tx.sender,
|
|
88
|
+
type: tx.type,
|
|
89
|
+
status: tx.status,
|
|
90
|
+
contractId: tx.contract_id ?? null,
|
|
91
|
+
functionName: tx.function_name ?? null
|
|
92
|
+
};
|
|
93
|
+
const decodedArgs = decodeFunctionArgs2(tx.function_args);
|
|
94
|
+
const decodedResult = decodeRawResult(tx.raw_result);
|
|
95
|
+
if (!event) {
|
|
96
|
+
switch (filter.type) {
|
|
97
|
+
case "contract_call":
|
|
98
|
+
return {
|
|
99
|
+
contractId: tx.contract_id ?? "",
|
|
100
|
+
functionName: tx.function_name ?? "",
|
|
101
|
+
caller: tx.sender,
|
|
102
|
+
args: decodedArgs,
|
|
103
|
+
result: decodedResult,
|
|
104
|
+
tx: txMeta
|
|
105
|
+
};
|
|
106
|
+
case "contract_deploy":
|
|
107
|
+
return {
|
|
108
|
+
contractId: tx.contract_id ?? "",
|
|
109
|
+
deployer: tx.sender,
|
|
110
|
+
tx: txMeta
|
|
111
|
+
};
|
|
112
|
+
default:
|
|
113
|
+
return { tx: txMeta };
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
const decoded = decodeEventData(event.data);
|
|
117
|
+
switch (filter.type) {
|
|
118
|
+
case "ft_transfer":
|
|
119
|
+
return {
|
|
120
|
+
sender: decoded.sender,
|
|
121
|
+
recipient: decoded.recipient,
|
|
122
|
+
amount: safeBigInt(decoded.amount),
|
|
123
|
+
assetIdentifier: decoded.asset_identifier,
|
|
124
|
+
tx: txMeta
|
|
125
|
+
};
|
|
126
|
+
case "ft_mint":
|
|
127
|
+
return {
|
|
128
|
+
recipient: decoded.recipient,
|
|
129
|
+
amount: safeBigInt(decoded.amount),
|
|
130
|
+
assetIdentifier: decoded.asset_identifier,
|
|
131
|
+
tx: txMeta
|
|
132
|
+
};
|
|
133
|
+
case "ft_burn":
|
|
134
|
+
return {
|
|
135
|
+
sender: decoded.sender,
|
|
136
|
+
amount: safeBigInt(decoded.amount),
|
|
137
|
+
assetIdentifier: decoded.asset_identifier,
|
|
138
|
+
tx: txMeta
|
|
139
|
+
};
|
|
140
|
+
case "nft_transfer":
|
|
141
|
+
return {
|
|
142
|
+
sender: decoded.sender,
|
|
143
|
+
recipient: decoded.recipient,
|
|
144
|
+
tokenId: decoded.value,
|
|
145
|
+
assetIdentifier: decoded.asset_identifier,
|
|
146
|
+
tx: txMeta
|
|
147
|
+
};
|
|
148
|
+
case "nft_mint":
|
|
149
|
+
return {
|
|
150
|
+
recipient: decoded.recipient,
|
|
151
|
+
tokenId: decoded.value,
|
|
152
|
+
assetIdentifier: decoded.asset_identifier,
|
|
153
|
+
tx: txMeta
|
|
154
|
+
};
|
|
155
|
+
case "nft_burn":
|
|
156
|
+
return {
|
|
157
|
+
sender: decoded.sender,
|
|
158
|
+
tokenId: decoded.value,
|
|
159
|
+
assetIdentifier: decoded.asset_identifier,
|
|
160
|
+
tx: txMeta
|
|
161
|
+
};
|
|
162
|
+
case "stx_transfer":
|
|
163
|
+
return {
|
|
164
|
+
sender: decoded.sender,
|
|
165
|
+
recipient: decoded.recipient,
|
|
166
|
+
amount: safeBigInt(decoded.amount),
|
|
167
|
+
memo: decoded.memo ?? "",
|
|
168
|
+
tx: txMeta
|
|
169
|
+
};
|
|
170
|
+
case "stx_mint":
|
|
171
|
+
return {
|
|
172
|
+
recipient: decoded.recipient,
|
|
173
|
+
amount: safeBigInt(decoded.amount),
|
|
174
|
+
tx: txMeta
|
|
175
|
+
};
|
|
176
|
+
case "stx_burn":
|
|
177
|
+
return {
|
|
178
|
+
sender: decoded.sender,
|
|
179
|
+
amount: safeBigInt(decoded.amount),
|
|
180
|
+
tx: txMeta
|
|
181
|
+
};
|
|
182
|
+
case "stx_lock":
|
|
183
|
+
return {
|
|
184
|
+
lockedAddress: decoded.locked_address,
|
|
185
|
+
lockedAmount: safeBigInt(decoded.locked_amount),
|
|
186
|
+
unlockHeight: safeBigInt(decoded.unlock_height),
|
|
187
|
+
tx: txMeta
|
|
188
|
+
};
|
|
189
|
+
case "print_event": {
|
|
190
|
+
const rawValue = decoded.value;
|
|
191
|
+
const clarityObj = rawValue && typeof rawValue === "object" && !Array.isArray(rawValue) ? rawValue : null;
|
|
192
|
+
const topic = clarityObj?.topic ? String(clarityObj.topic) : decoded.topic ?? "";
|
|
193
|
+
const { topic: _, ...rest } = clarityObj ?? {};
|
|
194
|
+
const data = Object.keys(rest).length > 0 ? camelizeKeys(rest) : rawValue && typeof rawValue !== "object" ? rawValue : {};
|
|
195
|
+
return {
|
|
196
|
+
contractId: decoded.contract_identifier ?? tx.contract_id ?? "",
|
|
197
|
+
topic,
|
|
198
|
+
data: data ?? {},
|
|
199
|
+
tx: txMeta
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
case "contract_call":
|
|
203
|
+
return {
|
|
204
|
+
...decoded,
|
|
205
|
+
_eventType: event.type,
|
|
206
|
+
contractId: tx.contract_id ?? "",
|
|
207
|
+
functionName: tx.function_name ?? "",
|
|
208
|
+
caller: tx.sender,
|
|
209
|
+
args: decodedArgs,
|
|
210
|
+
result: decodedResult,
|
|
211
|
+
tx: txMeta
|
|
212
|
+
};
|
|
213
|
+
case "contract_deploy":
|
|
214
|
+
return {
|
|
215
|
+
contractId: tx.contract_id ?? "",
|
|
216
|
+
deployer: tx.sender,
|
|
217
|
+
tx: txMeta
|
|
218
|
+
};
|
|
219
|
+
default:
|
|
220
|
+
return {
|
|
221
|
+
...decoded,
|
|
222
|
+
_eventType: event.type,
|
|
223
|
+
tx: txMeta
|
|
224
|
+
};
|
|
225
|
+
}
|
|
41
226
|
}
|
|
42
227
|
async function runHandlers(subgraph, matched, ctx, opts) {
|
|
43
228
|
let processed = 0;
|
|
44
229
|
let errors = 0;
|
|
45
230
|
const threshold = opts?.errorThreshold ?? DEFAULT_ERROR_THRESHOLD;
|
|
46
|
-
|
|
47
|
-
|
|
231
|
+
const filterLookup = new Map;
|
|
232
|
+
if (!Array.isArray(subgraph.sources)) {
|
|
233
|
+
for (const [name, filter] of Object.entries(subgraph.sources)) {
|
|
234
|
+
filterLookup.set(name, filter);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
for (const { tx, events, sourceName } of matched) {
|
|
238
|
+
const handler = subgraph.handlers[sourceName] ?? subgraph.handlers["*"] ?? null;
|
|
48
239
|
if (!handler) {
|
|
49
|
-
logger.warn("No handler found for source
|
|
240
|
+
logger.warn("No handler found for source", {
|
|
50
241
|
subgraph: subgraph.name,
|
|
51
|
-
|
|
242
|
+
sourceName,
|
|
52
243
|
txId: tx.tx_id
|
|
53
244
|
});
|
|
54
245
|
continue;
|
|
@@ -57,11 +248,14 @@ async function runHandlers(subgraph, matched, ctx, opts) {
|
|
|
57
248
|
txId: tx.tx_id,
|
|
58
249
|
sender: tx.sender,
|
|
59
250
|
type: tx.type,
|
|
60
|
-
status: tx.status
|
|
251
|
+
status: tx.status,
|
|
252
|
+
contractId: tx.contract_id ?? null,
|
|
253
|
+
functionName: tx.function_name ?? null
|
|
61
254
|
});
|
|
255
|
+
const filter = filterLookup.get(sourceName);
|
|
62
256
|
if (events.length === 0) {
|
|
63
257
|
try {
|
|
64
|
-
const
|
|
258
|
+
const payload = filter ? buildEventPayload(filter, tx, null) : {
|
|
65
259
|
tx: {
|
|
66
260
|
txId: tx.tx_id,
|
|
67
261
|
sender: tx.sender,
|
|
@@ -71,13 +265,13 @@ async function runHandlers(subgraph, matched, ctx, opts) {
|
|
|
71
265
|
functionName: tx.function_name
|
|
72
266
|
}
|
|
73
267
|
};
|
|
74
|
-
await handler(
|
|
268
|
+
await handler(payload, ctx);
|
|
75
269
|
processed++;
|
|
76
270
|
} catch (err) {
|
|
77
271
|
errors++;
|
|
78
272
|
logger.error("Subgraph handler error", {
|
|
79
273
|
subgraph: subgraph.name,
|
|
80
|
-
|
|
274
|
+
sourceName,
|
|
81
275
|
txId: tx.tx_id,
|
|
82
276
|
error: getErrorMessage(err)
|
|
83
277
|
});
|
|
@@ -94,28 +288,30 @@ async function runHandlers(subgraph, matched, ctx, opts) {
|
|
|
94
288
|
return { processed, errors };
|
|
95
289
|
}
|
|
96
290
|
try {
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
291
|
+
const payload = filter ? buildEventPayload(filter, tx, event) : (() => {
|
|
292
|
+
const decoded = decodeEventData(event.data);
|
|
293
|
+
return {
|
|
294
|
+
...decoded,
|
|
295
|
+
_eventId: event.id,
|
|
296
|
+
_eventType: event.type,
|
|
297
|
+
_eventIndex: event.event_index,
|
|
298
|
+
tx: {
|
|
299
|
+
txId: tx.tx_id,
|
|
300
|
+
sender: tx.sender,
|
|
301
|
+
type: tx.type,
|
|
302
|
+
status: tx.status,
|
|
303
|
+
contractId: tx.contract_id,
|
|
304
|
+
functionName: tx.function_name
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
})();
|
|
308
|
+
await handler(payload, ctx);
|
|
113
309
|
processed++;
|
|
114
310
|
} catch (err) {
|
|
115
311
|
errors++;
|
|
116
312
|
logger.error("Subgraph handler error", {
|
|
117
313
|
subgraph: subgraph.name,
|
|
118
|
-
|
|
314
|
+
sourceName,
|
|
119
315
|
txId: tx.tx_id,
|
|
120
316
|
eventId: event.id,
|
|
121
317
|
eventType: event.type,
|
|
@@ -130,5 +326,5 @@ export {
|
|
|
130
326
|
runHandlers
|
|
131
327
|
};
|
|
132
328
|
|
|
133
|
-
//# debugId=
|
|
329
|
+
//# debugId=01230613471884DF64756E2164756E21
|
|
134
330
|
//# 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 {
|
|
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 { decodeClarityValue, decodeEventData } from \"./clarity.ts\";\nimport type { SubgraphContext } from \"./context.ts\";\nimport type { MatchedTx } from \"./source-matcher.ts\";\n\n/** Max consecutive handler errors before marking subgraph as error */\nconst DEFAULT_ERROR_THRESHOLD = 50;\n\nexport interface RunResult {\n\tprocessed: number;\n\terrors: number;\n}\n\n/** Convert kebab-case to camelCase: \"bitcoin-txid\" → \"bitcoinTxid\" */\nfunction camelCase(str: string): string {\n\treturn str.replace(/-([a-z0-9])/g, (_, c) => c.toUpperCase());\n}\n\n/** Recursively camelize all object keys */\nfunction camelizeKeys(obj: unknown): unknown {\n\tif (obj === null || obj === undefined) return obj;\n\tif (typeof obj !== \"object\") return obj;\n\tif (Array.isArray(obj)) return obj.map(camelizeKeys);\n\tconst result: Record<string, unknown> = {};\n\tfor (const [k, v] of Object.entries(obj as Record<string, unknown>)) {\n\t\tresult[camelCase(k)] = camelizeKeys(v);\n\t}\n\treturn result;\n}\n\n/**\n * Decode function_args (hex-encoded ClarityValues) to an array of JS values.\n * Returns decoded values via cvToValue.\n */\nfunction decodeFunctionArgs(args: unknown): unknown[] {\n\tif (!Array.isArray(args)) return [];\n\treturn args.map((arg) => {\n\t\tif (typeof arg === \"string\") return decodeClarityValue(arg);\n\t\treturn arg;\n\t});\n}\n\n/**\n * Decode raw_result (hex-encoded Clarity return value) to JS value.\n */\nfunction decodeRawResult(raw: unknown): unknown {\n\tif (typeof raw === \"string\" && raw.length > 2) {\n\t\treturn decodeClarityValue(raw);\n\t}\n\treturn null;\n}\n\n/** Safely convert a value to BigInt. Handles string, number, bigint. Returns 0n on failure. */\nfunction safeBigInt(val: unknown): bigint {\n\tif (typeof val === \"bigint\") return val;\n\tif (typeof val === \"number\") return BigInt(val);\n\tif (typeof val === \"string\") {\n\t\ttry {\n\t\t\treturn BigInt(val);\n\t\t} catch {\n\t\t\treturn 0n;\n\t\t}\n\t}\n\treturn 0n;\n}\n\n/**\n * Build a typed event payload based on the source filter type.\n * Returns the payload the handler will receive.\n */\nfunction buildEventPayload(\n\tfilter: SubgraphFilter,\n\ttx: MatchedTx[\"tx\"],\n\tevent: MatchedTx[\"events\"][0] | null,\n): Record<string, unknown> {\n\tconst txMeta = {\n\t\ttxId: tx.tx_id,\n\t\tsender: tx.sender,\n\t\ttype: tx.type,\n\t\tstatus: tx.status,\n\t\tcontractId: tx.contract_id ?? null,\n\t\tfunctionName: tx.function_name ?? null,\n\t};\n\n\t// Decoded function args + result for contract_call payloads\n\tconst decodedArgs = decodeFunctionArgs(tx.function_args);\n\tconst decodedResult = decodeRawResult(tx.raw_result);\n\n\t// No event — tx-level match (contract_call or contract_deploy)\n\tif (!event) {\n\t\tswitch (filter.type) {\n\t\t\tcase \"contract_call\":\n\t\t\t\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: decodedArgs,\n\t\t\t\t\tresult: decodedResult,\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: safeBigInt(decoded.amount),\n\t\t\t\tassetIdentifier: decoded.asset_identifier as string,\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\t\tcase \"ft_mint\":\n\t\t\treturn {\n\t\t\t\trecipient: decoded.recipient as string,\n\t\t\t\tamount: safeBigInt(decoded.amount),\n\t\t\t\tassetIdentifier: decoded.asset_identifier as string,\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\t\tcase \"ft_burn\":\n\t\t\treturn {\n\t\t\t\tsender: decoded.sender as string,\n\t\t\t\tamount: safeBigInt(decoded.amount),\n\t\t\t\tassetIdentifier: decoded.asset_identifier as string,\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\n\t\t// ── NFT events ──\n\t\tcase \"nft_transfer\":\n\t\t\treturn {\n\t\t\t\tsender: decoded.sender as string,\n\t\t\t\trecipient: decoded.recipient as string,\n\t\t\t\ttokenId: decoded.value,\n\t\t\t\tassetIdentifier: decoded.asset_identifier as string,\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\t\tcase \"nft_mint\":\n\t\t\treturn {\n\t\t\t\trecipient: decoded.recipient as string,\n\t\t\t\ttokenId: decoded.value,\n\t\t\t\tassetIdentifier: decoded.asset_identifier as string,\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\t\tcase \"nft_burn\":\n\t\t\treturn {\n\t\t\t\tsender: decoded.sender as string,\n\t\t\t\ttokenId: decoded.value,\n\t\t\t\tassetIdentifier: decoded.asset_identifier as string,\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\n\t\t// ── STX events ──\n\t\tcase \"stx_transfer\":\n\t\t\treturn {\n\t\t\t\tsender: decoded.sender as string,\n\t\t\t\trecipient: decoded.recipient as string,\n\t\t\t\tamount: safeBigInt(decoded.amount),\n\t\t\t\tmemo: decoded.memo ?? \"\",\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\t\tcase \"stx_mint\":\n\t\t\treturn {\n\t\t\t\trecipient: decoded.recipient as string,\n\t\t\t\tamount: safeBigInt(decoded.amount),\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\t\tcase \"stx_burn\":\n\t\t\treturn {\n\t\t\t\tsender: decoded.sender as string,\n\t\t\t\tamount: safeBigInt(decoded.amount),\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\t\tcase \"stx_lock\":\n\t\t\treturn {\n\t\t\t\tlockedAddress: decoded.locked_address as string,\n\t\t\t\tlockedAmount: safeBigInt(decoded.locked_amount),\n\t\t\t\tunlockHeight: safeBigInt(decoded.unlock_height),\n\t\t\t\ttx: txMeta,\n\t\t\t};\n\n\t\t// ── Print event ──\n\t\tcase \"print_event\": {\n\t\t\tconst rawValue = decoded.value;\n\t\t\t// Extract topic from decoded Clarity value (not raw event topic which is always \"print\")\n\t\t\tconst clarityObj =\n\t\t\t\trawValue && typeof rawValue === \"object\" && !Array.isArray(rawValue)\n\t\t\t\t\t? (rawValue as Record<string, unknown>)\n\t\t\t\t\t: null;\n\t\t\tconst topic = clarityObj?.topic\n\t\t\t\t? String(clarityObj.topic)\n\t\t\t\t: ((decoded.topic as string) ?? \"\");\n\t\t\t// Camelize remaining keys for developer convenience\n\t\t\tconst { topic: _, ...rest } = clarityObj ?? {};\n\t\t\tconst data = Object.keys(rest).length > 0\n\t\t\t\t? (camelizeKeys(rest) as Record<string, unknown>)\n\t\t\t\t: rawValue && typeof rawValue !== \"object\"\n\t\t\t\t\t? rawValue\n\t\t\t\t\t: {};\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: decodedArgs,\n\t\t\t\tresult: decodedResult,\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": ";;;;AAAA;AAMO,SAAS,kBAAkB,CAAC,KAAsB;AAAA,EACxD,IAAI;AAAA,IACH,MAAM,WAAW,IAAI,WAAW,IAAI,IAAI,IAAI,MAAM,CAAC,IAAI;AAAA,IACvD,MAAM,KAAK,cAAc,QAAQ;AAAA,IACjC,OAAO,
|
|
9
|
-
"debugId": "
|
|
8
|
+
"mappings": "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",
|
|
9
|
+
"debugId": "01230613471884DF64756E2164756E21",
|
|
10
10
|
"names": []
|
|
11
11
|
}
|
|
@@ -1,34 +1,89 @@
|
|
|
1
|
-
/**
|
|
2
|
-
interface
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
|
@@ -37,6 +92,8 @@ type TxRecord = {
|
|
|
37
92
|
status: string
|
|
38
93
|
contract_id?: string | null
|
|
39
94
|
function_name?: string | null
|
|
95
|
+
function_args?: unknown | null
|
|
96
|
+
raw_result?: string | null
|
|
40
97
|
};
|
|
41
98
|
type EventRecord = {
|
|
42
99
|
id: string
|
|
@@ -46,8 +103,8 @@ type EventRecord = {
|
|
|
46
103
|
data: unknown
|
|
47
104
|
};
|
|
48
105
|
/**
|
|
49
|
-
* Match
|
|
50
|
-
*
|
|
106
|
+
* Match named filters against a block's transactions and events.
|
|
107
|
+
* Returns matches with sourceName = the object key from sources.
|
|
51
108
|
*/
|
|
52
|
-
declare function matchSources(sources:
|
|
109
|
+
declare function matchSources(sources: Record<string, SubgraphFilter>, transactions: TxRecord[], events: EventRecord[]): MatchedTx[];
|
|
53
110
|
export { matchSources, MatchedTx };
|