@secondlayer/subgraphs 4.4.1 → 5.0.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 (64) hide show
  1. package/README.md +13 -21
  2. package/dist/{src/index.d.ts → index.d.ts} +59 -189
  3. package/dist/index.js +2151 -0
  4. package/dist/index.js.map +24 -0
  5. package/dist/{src/runtime → runtime}/emitter.d.ts +1 -1
  6. package/dist/{src/runtime → runtime}/emitter.js +8 -12
  7. package/dist/{src/runtime → runtime}/emitter.js.map +3 -3
  8. package/dist/{src/runtime → runtime}/replay.d.ts +1 -1
  9. package/dist/{src/runtime → runtime}/replay.js +342 -683
  10. package/dist/{src/runtime → runtime}/replay.js.map +5 -5
  11. package/dist/{src/schema → schema}/index.d.ts +10 -69
  12. package/dist/{src/schema → schema}/index.js +188 -281
  13. package/dist/schema/index.js.map +13 -0
  14. package/dist/{src/testing → testing}/index.d.ts +65 -115
  15. package/dist/{src/testing → testing}/index.js +554 -968
  16. package/dist/testing/index.js.map +21 -0
  17. package/dist/{src/types.d.ts → types.d.ts} +10 -66
  18. package/dist/{src/validate.d.ts → validate.d.ts} +11 -69
  19. package/dist/{src/validate.js → validate.js} +18 -98
  20. package/dist/validate.js.map +10 -0
  21. package/package.json +18 -26
  22. package/dist/src/index.js +0 -6081
  23. package/dist/src/index.js.map +0 -44
  24. package/dist/src/runtime/block-processor.d.ts +0 -559
  25. package/dist/src/runtime/block-processor.js +0 -3810
  26. package/dist/src/runtime/block-processor.js.map +0 -31
  27. package/dist/src/runtime/catchup.d.ts +0 -473
  28. package/dist/src/runtime/catchup.js +0 -4228
  29. package/dist/src/runtime/catchup.js.map +0 -35
  30. package/dist/src/runtime/clarity.d.ts +0 -15
  31. package/dist/src/runtime/clarity.js +0 -41
  32. package/dist/src/runtime/clarity.js.map +0 -10
  33. package/dist/src/runtime/context.d.ts +0 -325
  34. package/dist/src/runtime/context.js +0 -936
  35. package/dist/src/runtime/context.js.map +0 -13
  36. package/dist/src/runtime/processor.d.ts +0 -11
  37. package/dist/src/runtime/processor.js +0 -5372
  38. package/dist/src/runtime/processor.js.map +0 -40
  39. package/dist/src/runtime/reindex.d.ts +0 -539
  40. package/dist/src/runtime/reindex.js +0 -4802
  41. package/dist/src/runtime/reindex.js.map +0 -37
  42. package/dist/src/runtime/reorg.d.ts +0 -432
  43. package/dist/src/runtime/reorg.js +0 -4355
  44. package/dist/src/runtime/reorg.js.map +0 -36
  45. package/dist/src/runtime/runner.d.ts +0 -719
  46. package/dist/src/runtime/runner.js +0 -1332
  47. package/dist/src/runtime/runner.js.map +0 -16
  48. package/dist/src/runtime/source-matcher.d.ts +0 -304
  49. package/dist/src/runtime/source-matcher.js +0 -335
  50. package/dist/src/runtime/source-matcher.js.map +0 -10
  51. package/dist/src/runtime/stats.d.ts +0 -23
  52. package/dist/src/runtime/stats.js +0 -71
  53. package/dist/src/runtime/stats.js.map +0 -10
  54. package/dist/src/schema/index.js.map +0 -13
  55. package/dist/src/service.d.ts +0 -0
  56. package/dist/src/service.js +0 -5398
  57. package/dist/src/service.js.map +0 -41
  58. package/dist/src/testing/index.js.map +0 -22
  59. package/dist/src/triggers/index.d.ts +0 -381
  60. package/dist/src/triggers/index.js +0 -31
  61. package/dist/src/triggers/index.js.map +0 -10
  62. package/dist/src/validate.js.map +0 -10
  63. /package/dist/{src/types.js → types.js} +0 -0
  64. /package/dist/{src/types.js.map → types.js.map} +0 -0
@@ -1,335 +0,0 @@
1
- import { createRequire } from "node:module";
2
- var __require = /* @__PURE__ */ createRequire(import.meta.url);
3
-
4
- // src/runtime/source-matcher.ts
5
- var patternCache = new Map;
6
- function matchAny(value, pattern) {
7
- return Array.isArray(pattern) ? pattern.some((p) => matchPattern(value, p)) : matchPattern(value, pattern);
8
- }
9
- function matchPattern(value, pattern) {
10
- if (!pattern.includes("*"))
11
- return value === pattern;
12
- let re = patternCache.get(pattern);
13
- if (!re) {
14
- const regex = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
15
- re = new RegExp(`^${regex}$`);
16
- patternCache.set(pattern, re);
17
- }
18
- return re.test(value);
19
- }
20
- var EMPTY_SET = new Set;
21
- function factoryAllows(filter, contractId, factoryContracts) {
22
- if (!filter.factory)
23
- return true;
24
- if (!contractId)
25
- return false;
26
- return (factoryContracts.get(filter.factory.from) ?? EMPTY_SET).has(contractId);
27
- }
28
- function readPath(payload, path) {
29
- let cur = payload;
30
- for (const key of path.split(".")) {
31
- if (cur === null || typeof cur !== "object")
32
- return;
33
- cur = cur[key];
34
- }
35
- return cur;
36
- }
37
- function traitAllows(filter, contractId, traitContracts) {
38
- const trait = filter.trait;
39
- if (!trait)
40
- return true;
41
- if (!contractId)
42
- return false;
43
- return (traitContracts.get(trait) ?? EMPTY_SET).has(contractId);
44
- }
45
- function assetContract(assetId) {
46
- return assetId?.split("::")[0];
47
- }
48
- function printContractId(data) {
49
- if (!data)
50
- return;
51
- const id = (typeof data.contract_identifier === "string" ? data.contract_identifier : undefined) ?? (typeof data.contract_id === "string" ? data.contract_id : undefined);
52
- return id || undefined;
53
- }
54
- function matchFilter(filter, transactions, eventsByTx, traitContracts, factoryContracts = new Map, vmEventsByTx = new Map) {
55
- const results = [];
56
- switch (filter.type) {
57
- case "stx_transfer":
58
- case "stx_mint":
59
- case "stx_burn":
60
- case "stx_lock": {
61
- const eventType = `${filter.type}_event`;
62
- for (const tx of transactions) {
63
- const txEvents = eventsByTx.get(tx.tx_id) ?? [];
64
- const matched = txEvents.filter((e) => e.type === eventType);
65
- if (matched.length === 0)
66
- continue;
67
- const filtered = matched.filter((e) => {
68
- const data = e.data;
69
- if (!data)
70
- return false;
71
- if ("sender" in filter && filter.sender) {
72
- if (!matchPattern(data.sender, filter.sender))
73
- return false;
74
- }
75
- if ("recipient" in filter && filter.recipient) {
76
- if (!matchPattern(data.recipient, filter.recipient))
77
- return false;
78
- }
79
- if ("lockedAddress" in filter && filter.lockedAddress) {
80
- if (!matchPattern(data.locked_address, filter.lockedAddress))
81
- return false;
82
- }
83
- if ("minAmount" in filter && filter.minAmount !== undefined) {
84
- const amount = BigInt(data.amount ?? data.locked_amount ?? "0");
85
- if (amount < filter.minAmount)
86
- return false;
87
- }
88
- if ("maxAmount" in filter && filter.maxAmount !== undefined) {
89
- const amount = BigInt(data.amount ?? "0");
90
- if (amount > filter.maxAmount)
91
- return false;
92
- }
93
- return true;
94
- });
95
- if (filtered.length > 0) {
96
- results.push({ tx, events: filtered });
97
- }
98
- }
99
- break;
100
- }
101
- case "ft_transfer":
102
- case "ft_mint":
103
- case "ft_burn": {
104
- const eventType = `${filter.type}_event`;
105
- for (const tx of transactions) {
106
- const txEvents = eventsByTx.get(tx.tx_id) ?? [];
107
- const matched = txEvents.filter((e) => {
108
- if (e.type !== eventType)
109
- return false;
110
- const data = e.data;
111
- if (!data)
112
- return false;
113
- if (filter.assetIdentifier) {
114
- const assetId = data.asset_identifier;
115
- if (!assetId || !matchPattern(assetId, filter.assetIdentifier))
116
- return false;
117
- }
118
- if (!traitAllows(filter, assetContract(data.asset_identifier), traitContracts))
119
- return false;
120
- if ("sender" in filter && filter.sender) {
121
- if (!matchPattern(data.sender, filter.sender))
122
- return false;
123
- }
124
- if ("recipient" in filter && filter.recipient) {
125
- if (!matchPattern(data.recipient, filter.recipient))
126
- return false;
127
- }
128
- if (filter.minAmount !== undefined) {
129
- const amount = BigInt(data.amount ?? "0");
130
- if (amount < filter.minAmount)
131
- return false;
132
- }
133
- return true;
134
- });
135
- if (matched.length > 0) {
136
- results.push({ tx, events: matched });
137
- }
138
- }
139
- break;
140
- }
141
- case "nft_transfer":
142
- case "nft_mint":
143
- case "nft_burn": {
144
- const eventType = `${filter.type}_event`;
145
- for (const tx of transactions) {
146
- const txEvents = eventsByTx.get(tx.tx_id) ?? [];
147
- const matched = txEvents.filter((e) => {
148
- if (e.type !== eventType)
149
- return false;
150
- const data = e.data;
151
- if (!data)
152
- return false;
153
- if (filter.assetIdentifier) {
154
- const assetId = data.asset_identifier;
155
- if (!assetId || !matchPattern(assetId, filter.assetIdentifier))
156
- return false;
157
- }
158
- if (!traitAllows(filter, assetContract(data.asset_identifier), traitContracts))
159
- return false;
160
- if ("sender" in filter && filter.sender) {
161
- if (!matchPattern(data.sender, filter.sender))
162
- return false;
163
- }
164
- if ("recipient" in filter && filter.recipient) {
165
- if (!matchPattern(data.recipient, filter.recipient))
166
- return false;
167
- }
168
- return true;
169
- });
170
- if (matched.length > 0) {
171
- results.push({ tx, events: matched });
172
- }
173
- }
174
- break;
175
- }
176
- case "contract_call": {
177
- for (const tx of transactions) {
178
- if (tx.type !== "contract_call")
179
- continue;
180
- if (filter.contractId) {
181
- if (!tx.contract_id || !matchAny(tx.contract_id, filter.contractId))
182
- continue;
183
- }
184
- if (!factoryAllows(filter, tx.contract_id, factoryContracts))
185
- continue;
186
- if (filter.functionName) {
187
- if (!tx.function_name || !matchPattern(tx.function_name, filter.functionName))
188
- continue;
189
- }
190
- if (filter.caller) {
191
- if (!matchPattern(tx.sender, filter.caller))
192
- continue;
193
- }
194
- if (!traitAllows(filter, tx.contract_id, traitContracts))
195
- continue;
196
- const txEvents = eventsByTx.get(tx.tx_id) ?? [];
197
- results.push({ tx, events: txEvents });
198
- }
199
- break;
200
- }
201
- case "contract_deploy": {
202
- for (const tx of transactions) {
203
- if (tx.type !== "smart_contract")
204
- continue;
205
- if (filter.deployer) {
206
- if (!matchPattern(tx.sender, filter.deployer))
207
- continue;
208
- }
209
- if (filter.contractName) {
210
- const name = tx.contract_id?.split(".")[1] ?? "";
211
- if (!matchPattern(name, filter.contractName))
212
- continue;
213
- }
214
- const txEvents = eventsByTx.get(tx.tx_id) ?? [];
215
- results.push({ tx, events: txEvents });
216
- }
217
- break;
218
- }
219
- case "nested_contract_call":
220
- case "var_set":
221
- case "map_set":
222
- case "map_insert":
223
- case "map_delete": {
224
- for (const tx of transactions) {
225
- const txEvents = vmEventsByTx.get(tx.tx_id) ?? [];
226
- const matched = txEvents.filter((e) => {
227
- if (e.type !== filter.type)
228
- return false;
229
- const data = e.data;
230
- if (!data)
231
- return false;
232
- const contractId = printContractId(data);
233
- if ("contractId" in filter && filter.contractId) {
234
- if (!contractId || !matchAny(contractId, filter.contractId))
235
- return false;
236
- }
237
- if (!traitAllows(filter, contractId, traitContracts))
238
- return false;
239
- if (!factoryAllows(filter, contractId, factoryContracts))
240
- return false;
241
- if (filter.type === "nested_contract_call") {
242
- if (filter.functionName) {
243
- if (typeof data.function_name !== "string" || !matchPattern(data.function_name, filter.functionName))
244
- return false;
245
- }
246
- if (filter.caller) {
247
- if (typeof data.caller !== "string" || !matchPattern(data.caller, filter.caller))
248
- return false;
249
- }
250
- if (filter.sender) {
251
- if (typeof data.sender !== "string" || !matchPattern(data.sender, filter.sender))
252
- return false;
253
- }
254
- }
255
- if (filter.type === "var_set" && filter.varName) {
256
- if (typeof data.var_name !== "string" || !matchPattern(data.var_name, filter.varName))
257
- return false;
258
- }
259
- if ((filter.type === "map_set" || filter.type === "map_insert" || filter.type === "map_delete") && filter.map) {
260
- if (typeof data.map_name !== "string" || !matchPattern(data.map_name, filter.map))
261
- return false;
262
- }
263
- return true;
264
- });
265
- if (matched.length > 0)
266
- results.push({ tx, events: matched });
267
- }
268
- break;
269
- }
270
- case "print_event": {
271
- for (const tx of transactions) {
272
- const txEvents = eventsByTx.get(tx.tx_id) ?? [];
273
- const matched = txEvents.filter((e) => {
274
- if (e.type !== "smart_contract_event" && e.type !== "contract_event")
275
- return false;
276
- const data = e.data;
277
- if (!data)
278
- return false;
279
- if (data.topic !== "print")
280
- return false;
281
- const contractId = printContractId(data);
282
- if (filter.contractId) {
283
- if (!contractId || !matchAny(contractId, filter.contractId))
284
- return false;
285
- }
286
- if (!traitAllows(filter, contractId, traitContracts))
287
- return false;
288
- if (!factoryAllows(filter, contractId, factoryContracts))
289
- return false;
290
- return true;
291
- });
292
- if (matched.length > 0) {
293
- results.push({ tx, events: matched });
294
- }
295
- }
296
- break;
297
- }
298
- }
299
- return results;
300
- }
301
- function matchSources(sources, transactions, events, traitContracts = new Map, factoryContracts = new Map, vmEvents = []) {
302
- const eventsByTx = new Map;
303
- for (const event of events) {
304
- const list = eventsByTx.get(event.tx_id) ?? [];
305
- list.push(event);
306
- eventsByTx.set(event.tx_id, list);
307
- }
308
- const vmEventsByTx = new Map;
309
- for (const event of vmEvents) {
310
- const list = vmEventsByTx.get(event.tx_id) ?? [];
311
- list.push(event);
312
- vmEventsByTx.set(event.tx_id, list);
313
- }
314
- const seen = new Set;
315
- const results = [];
316
- for (const [sourceName, filter] of Object.entries(sources)) {
317
- const matches = matchFilter(filter, transactions, eventsByTx, traitContracts, factoryContracts, vmEventsByTx);
318
- for (const match of matches) {
319
- const dedupeKey = `${match.tx.tx_id}:${sourceName}`;
320
- if (!seen.has(dedupeKey)) {
321
- seen.add(dedupeKey);
322
- results.push({ ...match, sourceName });
323
- }
324
- }
325
- }
326
- return results;
327
- }
328
- export {
329
- readPath,
330
- printContractId,
331
- matchSources
332
- };
333
-
334
- //# debugId=A32A408B404000D764756E2164756E21
335
- //# sourceMappingURL=source-matcher.js.map
@@ -1,10 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/runtime/source-matcher.ts"],
4
- "sourcesContent": [
5
- "import type { SubgraphFilter } from \"../types.ts\";\n\nexport interface MatchedTx {\n\ttx: TxRecord;\n\tevents: EventRecord[];\n\t/** Source object key — used for handler dispatch */\n\tsourceName: string;\n}\n\nexport type TxRecord = {\n\ttx_id: string;\n\ttype: string;\n\tsender: string;\n\tstatus: string;\n\t/** Position within the block — the runner sorts dispatch into chain order. */\n\ttx_index?: number;\n\tcontract_id?: string | null;\n\tfunction_name?: string | null;\n\tfunction_args?: unknown | null;\n\traw_result?: string | null;\n};\n\nexport type EventRecord = {\n\tid: string;\n\ttx_id: string;\n\ttype: string;\n\t/** Classic `event_index`, or `ordinal` when `clock === \"vm\"`. */\n\tevent_index: number;\n\tdata: unknown;\n\t/** Set on opt-in `vm_events` rows. Two clocks never sort or dedupe together. */\n\tclock?: \"vm\";\n};\n\n// ── Wildcard matching (shared with v1) ──────────────────────────────\n\nconst patternCache = new Map<string, RegExp>();\n\n/** Match a value against one pattern, or ANY pattern in a set. */\nfunction matchAny(value: string, pattern: string | readonly string[]): boolean {\n\treturn Array.isArray(pattern)\n\t\t? pattern.some((p) => matchPattern(value, p))\n\t\t: matchPattern(value, pattern as string);\n}\n\nfunction matchPattern(value: string, pattern: string): boolean {\n\tif (!pattern.includes(\"*\")) return value === pattern;\n\tlet re = patternCache.get(pattern);\n\tif (!re) {\n\t\tconst regex = pattern\n\t\t\t.replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\")\n\t\t\t.replace(/\\*/g, \".*\");\n\t\tre = new RegExp(`^${regex}$`);\n\t\tpatternCache.set(pattern, re);\n\t}\n\treturn re.test(value);\n}\n\n// Trait → set of conforming contract IDs, resolved per block by the caller\n// (block-processor) from the contract registry. Kept as injected data so this\n// module stays pure/sync/DB-less.\nexport type TraitContracts = Map<string, ReadonlySet<string>>;\nconst EMPTY_SET: ReadonlySet<string> = new Set();\n\n/**\n * True when a filter's optional `trait` admits this contract: no trait → always\n * allowed; trait set → the contract must be in the resolved conforming set.\n */\n/** Addresses discovered per source name (factory sets), resolved by the\n * caller as-of the block being processed. */\nexport type FactoryContracts = ReadonlyMap<string, ReadonlySet<string>>;\n\n/**\n * A factory-scoped source matches only contracts its factory has revealed.\n * Same shape as {@link traitAllows}: the set is injected, so this module\n * stays pure and sync.\n */\nfunction factoryAllows(\n\tfilter: { factory?: { from: string; field: string } },\n\tcontractId: string | undefined | null,\n\tfactoryContracts: FactoryContracts,\n): boolean {\n\tif (!filter.factory) return true;\n\tif (!contractId) return false;\n\treturn (factoryContracts.get(filter.factory.from) ?? EMPTY_SET).has(\n\t\tcontractId,\n\t);\n}\n\n/** Read a dotted path off a decoded payload (`\"data.pool\"`). */\nexport function readPath(payload: unknown, path: string): unknown {\n\tlet cur: unknown = payload;\n\tfor (const key of path.split(\".\")) {\n\t\tif (cur === null || typeof cur !== \"object\") return undefined;\n\t\tcur = (cur as Record<string, unknown>)[key];\n\t}\n\treturn cur;\n}\n\nfunction traitAllows(\n\tfilter: SubgraphFilter,\n\tcontractId: string | undefined | null,\n\ttraitContracts: TraitContracts,\n): boolean {\n\tconst trait = (filter as { trait?: string }).trait;\n\tif (!trait) return true;\n\tif (!contractId) return false;\n\treturn (traitContracts.get(trait) ?? EMPTY_SET).has(contractId);\n}\n\n/** Extract the contract id from an asset identifier (`<contract>::<token>`). */\nfunction assetContract(assetId: string | undefined): string | undefined {\n\treturn assetId?.split(\"::\")[0];\n}\n\n/**\n * Contract on a print payload. Legacy `smart_contract_event` rows use\n * `contract_identifier`; current `contract_event` rows use `contract_id`.\n * Matcher and runner must share this — a print that matches on `contract_id`\n * otherwise reaches the handler with `event.contractId === \"\"`.\n */\nexport function printContractId(\n\tdata: Record<string, unknown> | null | undefined,\n): string | undefined {\n\tif (!data) return undefined;\n\tconst id =\n\t\t(typeof data.contract_identifier === \"string\"\n\t\t\t? data.contract_identifier\n\t\t\t: undefined) ??\n\t\t(typeof data.contract_id === \"string\" ? data.contract_id : undefined);\n\treturn id || undefined;\n}\n\n// ── Per-filter-type matchers ────────────────────────────────────────\n\nfunction matchFilter(\n\tfilter: SubgraphFilter,\n\ttransactions: TxRecord[],\n\teventsByTx: Map<string, EventRecord[]>,\n\ttraitContracts: TraitContracts,\n\tfactoryContracts: FactoryContracts = new Map(),\n\tvmEventsByTx: Map<string, EventRecord[]> = new Map(),\n): { tx: TxRecord; events: EventRecord[] }[] {\n\tconst results: { tx: TxRecord; events: EventRecord[] }[] = [];\n\n\tswitch (filter.type) {\n\t\t// ── STX events ──\n\t\tcase \"stx_transfer\":\n\t\tcase \"stx_mint\":\n\t\tcase \"stx_burn\":\n\t\tcase \"stx_lock\": {\n\t\t\tconst eventType = `${filter.type}_event`;\n\t\t\tfor (const tx of transactions) {\n\t\t\t\tconst txEvents = eventsByTx.get(tx.tx_id) ?? [];\n\t\t\t\tconst matched = txEvents.filter((e) => e.type === eventType);\n\t\t\t\tif (matched.length === 0) continue;\n\n\t\t\t\t// Apply address filters\n\t\t\t\tconst filtered = matched.filter((e) => {\n\t\t\t\t\tconst data = e.data as Record<string, unknown> | null;\n\t\t\t\t\tif (!data) return false;\n\t\t\t\t\tif (\"sender\" in filter && filter.sender) {\n\t\t\t\t\t\tif (!matchPattern(data.sender as string, filter.sender))\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tif (\"recipient\" in filter && filter.recipient) {\n\t\t\t\t\t\tif (!matchPattern(data.recipient as string, filter.recipient))\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tif (\"lockedAddress\" in filter && filter.lockedAddress) {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t!matchPattern(data.locked_address as string, filter.lockedAddress)\n\t\t\t\t\t\t)\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\t// Amount filters\n\t\t\t\t\tif (\"minAmount\" in filter && filter.minAmount !== undefined) {\n\t\t\t\t\t\tconst amount = BigInt(\n\t\t\t\t\t\t\t(data.amount ?? data.locked_amount ?? \"0\") as string,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tif (amount < filter.minAmount) return false;\n\t\t\t\t\t}\n\t\t\t\t\tif (\n\t\t\t\t\t\t\"maxAmount\" in filter &&\n\t\t\t\t\t\t(filter as { maxAmount?: bigint }).maxAmount !== undefined\n\t\t\t\t\t) {\n\t\t\t\t\t\tconst amount = BigInt((data.amount ?? \"0\") as string);\n\t\t\t\t\t\tif (amount > (filter as { maxAmount: bigint }).maxAmount)\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\treturn true;\n\t\t\t\t});\n\n\t\t\t\tif (filtered.length > 0) {\n\t\t\t\t\tresults.push({ tx, events: filtered });\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\t// ── FT events ──\n\t\tcase \"ft_transfer\":\n\t\tcase \"ft_mint\":\n\t\tcase \"ft_burn\": {\n\t\t\tconst eventType = `${filter.type}_event`;\n\t\t\tfor (const tx of transactions) {\n\t\t\t\tconst txEvents = eventsByTx.get(tx.tx_id) ?? [];\n\t\t\t\tconst matched = txEvents.filter((e) => {\n\t\t\t\t\tif (e.type !== eventType) return false;\n\t\t\t\t\tconst data = e.data as Record<string, unknown> | null;\n\t\t\t\t\tif (!data) return false;\n\n\t\t\t\t\t// Asset identifier filter\n\t\t\t\t\tif (filter.assetIdentifier) {\n\t\t\t\t\t\tconst assetId = data.asset_identifier as string | undefined;\n\t\t\t\t\t\tif (!assetId || !matchPattern(assetId, filter.assetIdentifier))\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\t// Trait scope — the asset's contract must conform.\n\t\t\t\t\tif (\n\t\t\t\t\t\t!traitAllows(\n\t\t\t\t\t\t\tfilter,\n\t\t\t\t\t\t\tassetContract(data.asset_identifier as string | undefined),\n\t\t\t\t\t\t\ttraitContracts,\n\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t// Address filters\n\t\t\t\t\tif (\"sender\" in filter && filter.sender) {\n\t\t\t\t\t\tif (!matchPattern(data.sender as string, filter.sender))\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tif (\"recipient\" in filter && filter.recipient) {\n\t\t\t\t\t\tif (!matchPattern(data.recipient as string, filter.recipient))\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\t// Amount filter\n\t\t\t\t\tif (filter.minAmount !== undefined) {\n\t\t\t\t\t\tconst amount = BigInt((data.amount ?? \"0\") as string);\n\t\t\t\t\t\tif (amount < filter.minAmount) return false;\n\t\t\t\t\t}\n\t\t\t\t\treturn true;\n\t\t\t\t});\n\n\t\t\t\tif (matched.length > 0) {\n\t\t\t\t\tresults.push({ tx, events: matched });\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\t// ── NFT events ──\n\t\tcase \"nft_transfer\":\n\t\tcase \"nft_mint\":\n\t\tcase \"nft_burn\": {\n\t\t\tconst eventType = `${filter.type}_event`;\n\t\t\tfor (const tx of transactions) {\n\t\t\t\tconst txEvents = eventsByTx.get(tx.tx_id) ?? [];\n\t\t\t\tconst matched = txEvents.filter((e) => {\n\t\t\t\t\tif (e.type !== eventType) return false;\n\t\t\t\t\tconst data = e.data as Record<string, unknown> | null;\n\t\t\t\t\tif (!data) return false;\n\n\t\t\t\t\tif (filter.assetIdentifier) {\n\t\t\t\t\t\tconst assetId = data.asset_identifier as string | undefined;\n\t\t\t\t\t\tif (!assetId || !matchPattern(assetId, filter.assetIdentifier))\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tif (\n\t\t\t\t\t\t!traitAllows(\n\t\t\t\t\t\t\tfilter,\n\t\t\t\t\t\t\tassetContract(data.asset_identifier as string | undefined),\n\t\t\t\t\t\t\ttraitContracts,\n\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t\t\t\treturn false;\n\t\t\t\t\tif (\"sender\" in filter && filter.sender) {\n\t\t\t\t\t\tif (!matchPattern(data.sender as string, filter.sender))\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tif (\"recipient\" in filter && filter.recipient) {\n\t\t\t\t\t\tif (!matchPattern(data.recipient as string, filter.recipient))\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\treturn true;\n\t\t\t\t});\n\n\t\t\t\tif (matched.length > 0) {\n\t\t\t\t\tresults.push({ tx, events: matched });\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\t// ── Contract call ──\n\t\tcase \"contract_call\": {\n\t\t\tfor (const tx of transactions) {\n\t\t\t\tif (tx.type !== \"contract_call\") continue;\n\n\t\t\t\t// Contract filter\n\t\t\t\tif (filter.contractId) {\n\t\t\t\t\tif (!tx.contract_id || !matchAny(tx.contract_id, filter.contractId))\n\t\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t// Factory scope: only contracts this source's factory revealed.\n\t\t\t\tif (!factoryAllows(filter, tx.contract_id, factoryContracts)) continue;\n\t\t\t\t// Function filter\n\t\t\t\tif (filter.functionName) {\n\t\t\t\t\tif (\n\t\t\t\t\t\t!tx.function_name ||\n\t\t\t\t\t\t!matchPattern(tx.function_name, filter.functionName)\n\t\t\t\t\t)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t// Caller filter\n\t\t\t\tif (filter.caller) {\n\t\t\t\t\tif (!matchPattern(tx.sender, filter.caller)) continue;\n\t\t\t\t}\n\t\t\t\t// Trait scope — the called contract must conform.\n\t\t\t\tif (!traitAllows(filter, tx.contract_id, traitContracts)) continue;\n\n\t\t\t\tconst txEvents = eventsByTx.get(tx.tx_id) ?? [];\n\t\t\t\tresults.push({ tx, events: txEvents });\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\t// ── Contract deploy ──\n\t\tcase \"contract_deploy\": {\n\t\t\tfor (const tx of transactions) {\n\t\t\t\tif (tx.type !== \"smart_contract\") continue;\n\n\t\t\t\tif (filter.deployer) {\n\t\t\t\t\tif (!matchPattern(tx.sender, filter.deployer)) continue;\n\t\t\t\t}\n\t\t\t\tif (filter.contractName) {\n\t\t\t\t\tconst name = tx.contract_id?.split(\".\")[1] ?? \"\";\n\t\t\t\t\tif (!matchPattern(name, filter.contractName)) continue;\n\t\t\t\t}\n\n\t\t\t\tconst txEvents = eventsByTx.get(tx.tx_id) ?? [];\n\t\t\t\tresults.push({ tx, events: txEvents });\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"nested_contract_call\":\n\t\tcase \"var_set\":\n\t\tcase \"map_set\":\n\t\tcase \"map_insert\":\n\t\tcase \"map_delete\": {\n\t\t\t// vm sources read the vm clock only. A classic tx-level source never\n\t\t\t// sees these rows, and a vm source never sees `events[]`.\n\t\t\tfor (const tx of transactions) {\n\t\t\t\tconst txEvents = vmEventsByTx.get(tx.tx_id) ?? [];\n\t\t\t\tconst matched = txEvents.filter((e) => {\n\t\t\t\t\tif (e.type !== filter.type) return false;\n\t\t\t\t\tconst data = e.data as Record<string, unknown> | null;\n\t\t\t\t\tif (!data) return false;\n\t\t\t\t\tconst contractId = printContractId(data);\n\t\t\t\t\tif (\"contractId\" in filter && filter.contractId) {\n\t\t\t\t\t\tif (!contractId || !matchAny(contractId, filter.contractId))\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tif (!traitAllows(filter, contractId, traitContracts)) return false;\n\t\t\t\t\tif (!factoryAllows(filter, contractId, factoryContracts))\n\t\t\t\t\t\treturn false;\n\t\t\t\t\tif (filter.type === \"nested_contract_call\") {\n\t\t\t\t\t\tif (filter.functionName) {\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\ttypeof data.function_name !== \"string\" ||\n\t\t\t\t\t\t\t\t!matchPattern(data.function_name, filter.functionName)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (filter.caller) {\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\ttypeof data.caller !== \"string\" ||\n\t\t\t\t\t\t\t\t!matchPattern(data.caller, filter.caller)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (filter.sender) {\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\ttypeof data.sender !== \"string\" ||\n\t\t\t\t\t\t\t\t!matchPattern(data.sender, filter.sender)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (filter.type === \"var_set\" && filter.varName) {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\ttypeof data.var_name !== \"string\" ||\n\t\t\t\t\t\t\t!matchPattern(data.var_name, filter.varName)\n\t\t\t\t\t\t)\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tif (\n\t\t\t\t\t\t(filter.type === \"map_set\" ||\n\t\t\t\t\t\t\tfilter.type === \"map_insert\" ||\n\t\t\t\t\t\t\tfilter.type === \"map_delete\") &&\n\t\t\t\t\t\tfilter.map\n\t\t\t\t\t) {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\ttypeof data.map_name !== \"string\" ||\n\t\t\t\t\t\t\t!matchPattern(data.map_name, filter.map)\n\t\t\t\t\t\t)\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\treturn true;\n\t\t\t\t});\n\t\t\t\tif (matched.length > 0) results.push({ tx, events: matched });\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\t// ── Print event ──\n\t\tcase \"print_event\": {\n\t\t\tfor (const tx of transactions) {\n\t\t\t\tconst txEvents = eventsByTx.get(tx.tx_id) ?? [];\n\t\t\t\tconst matched = txEvents.filter((e) => {\n\t\t\t\t\tif (e.type !== \"smart_contract_event\" && e.type !== \"contract_event\")\n\t\t\t\t\t\treturn false;\n\t\t\t\t\tconst data = e.data as Record<string, unknown> | null;\n\t\t\t\t\tif (!data) return false;\n\t\t\t\t\tif (data.topic !== \"print\") return false;\n\n\t\t\t\t\tconst contractId = printContractId(data);\n\t\t\t\t\tif (filter.contractId) {\n\t\t\t\t\t\tif (!contractId || !matchAny(contractId, filter.contractId))\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tif (!traitAllows(filter, contractId, traitContracts)) return false;\n\t\t\t\t\tif (!factoryAllows(filter, contractId, factoryContracts))\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t// Topic filter — check the decoded Clarity value's topic field\n\t\t\t\t\t// At this stage data.value is still raw hex; topic filtering happens\n\t\t\t\t\t// after decode in the runner. For now, skip topic filtering here.\n\t\t\t\t\t// The runner will filter by topic after decoding.\n\t\t\t\t\treturn true;\n\t\t\t\t});\n\n\t\t\t\tif (matched.length > 0) {\n\t\t\t\t\tresults.push({ tx, events: matched });\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn results;\n}\n\n/**\n * Match named filters against a block's transactions and events.\n * Returns matches with sourceName = the object key from sources.\n */\nexport function matchSources(\n\tsources: Record<string, SubgraphFilter>,\n\ttransactions: TxRecord[],\n\tevents: EventRecord[],\n\ttraitContracts: TraitContracts = new Map(),\n\tfactoryContracts: FactoryContracts = new Map(),\n\t/** Opt-in `vm_events` rows (second clock). Only vm-typed sources read them. */\n\tvmEvents: EventRecord[] = [],\n): MatchedTx[] {\n\t// Index events by txId — one map per clock.\n\tconst eventsByTx = new Map<string, EventRecord[]>();\n\tfor (const event of events) {\n\t\tconst list = eventsByTx.get(event.tx_id) ?? [];\n\t\tlist.push(event);\n\t\teventsByTx.set(event.tx_id, list);\n\t}\n\tconst vmEventsByTx = new Map<string, EventRecord[]>();\n\tfor (const event of vmEvents) {\n\t\tconst list = vmEventsByTx.get(event.tx_id) ?? [];\n\t\tlist.push(event);\n\t\tvmEventsByTx.set(event.tx_id, list);\n\t}\n\n\tconst seen = new Set<string>();\n\tconst results: MatchedTx[] = [];\n\n\tfor (const [sourceName, filter] of Object.entries(sources)) {\n\t\tconst matches = matchFilter(\n\t\t\tfilter,\n\t\t\ttransactions,\n\t\t\teventsByTx,\n\t\t\ttraitContracts,\n\t\t\tfactoryContracts,\n\t\t\tvmEventsByTx,\n\t\t);\n\t\tfor (const match of matches) {\n\t\t\tconst dedupeKey = `${match.tx.tx_id}:${sourceName}`;\n\t\t\tif (!seen.has(dedupeKey)) {\n\t\t\t\tseen.add(dedupeKey);\n\t\t\t\tresults.push({ ...match, sourceName });\n\t\t\t}\n\t\t}\n\t}\n\n\treturn results;\n}\n"
6
- ],
7
- "mappings": "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",
8
- "debugId": "A32A408B404000D764756E2164756E21",
9
- "names": []
10
- }
@@ -1,23 +0,0 @@
1
- interface ProcessBlockTiming {
2
- totalMs: number;
3
- handlerMs: number;
4
- flushMs: number;
5
- }
6
- import { Database as Database3 } from "@secondlayer/shared/db";
7
- import { Kysely as Kysely3 } from "kysely";
8
- /**
9
- * Accumulates per-block timing stats and flushes to DB periodically.
10
- * One instance per subgraph during catchup/reindex/live processing.
11
- */
12
- declare class StatsAccumulator {
13
- private subgraphName;
14
- private isCatchup;
15
- private current;
16
- private lastFlush;
17
- constructor(subgraphName: string, isCatchup: boolean);
18
- record(timing: ProcessBlockTiming, opsCount: number): void;
19
- shouldFlush(): boolean;
20
- flush(db: Kysely3<Database3>): Promise<void>;
21
- private newEntry;
22
- }
23
- export { StatsAccumulator };
@@ -1,71 +0,0 @@
1
- import { createRequire } from "node:module";
2
- var __require = /* @__PURE__ */ createRequire(import.meta.url);
3
-
4
- // src/runtime/stats.ts
5
- var FLUSH_INTERVAL_BLOCKS = 100;
6
- var FLUSH_INTERVAL_MS = 60000;
7
-
8
- class StatsAccumulator {
9
- subgraphName;
10
- isCatchup;
11
- current;
12
- lastFlush = Date.now();
13
- constructor(subgraphName, isCatchup) {
14
- this.subgraphName = subgraphName;
15
- this.isCatchup = isCatchup;
16
- this.current = this.newEntry();
17
- }
18
- record(timing, opsCount) {
19
- this.current.blocksProcessed++;
20
- this.current.totalTimeMs += timing.totalMs;
21
- this.current.handlerTimeMs += timing.handlerMs;
22
- this.current.flushTimeMs += timing.flushMs;
23
- this.current.maxBlockTimeMs = Math.max(this.current.maxBlockTimeMs, timing.totalMs);
24
- this.current.maxHandlerTimeMs = Math.max(this.current.maxHandlerTimeMs, timing.handlerMs);
25
- this.current.totalOps += opsCount;
26
- }
27
- shouldFlush() {
28
- return this.current.blocksProcessed >= FLUSH_INTERVAL_BLOCKS || Date.now() - this.lastFlush >= FLUSH_INTERVAL_MS;
29
- }
30
- async flush(db) {
31
- if (this.current.blocksProcessed === 0)
32
- return;
33
- const entry = this.current;
34
- this.current = this.newEntry();
35
- this.lastFlush = Date.now();
36
- const avgOpsPerBlock = entry.blocksProcessed > 0 ? entry.totalOps / entry.blocksProcessed : 0;
37
- await db.insertInto("subgraph_processing_stats").values({
38
- subgraph_name: entry.subgraphName,
39
- bucket_start: entry.bucketStart,
40
- bucket_end: new Date,
41
- blocks_processed: entry.blocksProcessed,
42
- total_time_ms: Math.round(entry.totalTimeMs),
43
- handler_time_ms: Math.round(entry.handlerTimeMs),
44
- flush_time_ms: Math.round(entry.flushTimeMs),
45
- max_block_time_ms: Math.round(entry.maxBlockTimeMs),
46
- max_handler_time_ms: Math.round(entry.maxHandlerTimeMs),
47
- avg_ops_per_block: Number.parseFloat(avgOpsPerBlock.toFixed(2)),
48
- is_catchup: entry.isCatchup
49
- }).execute();
50
- }
51
- newEntry() {
52
- return {
53
- subgraphName: this.subgraphName,
54
- bucketStart: new Date,
55
- blocksProcessed: 0,
56
- totalTimeMs: 0,
57
- handlerTimeMs: 0,
58
- flushTimeMs: 0,
59
- maxBlockTimeMs: 0,
60
- maxHandlerTimeMs: 0,
61
- totalOps: 0,
62
- isCatchup: this.isCatchup
63
- };
64
- }
65
- }
66
- export {
67
- StatsAccumulator
68
- };
69
-
70
- //# debugId=ABEF009DEA3A0EDE64756E2164756E21
71
- //# sourceMappingURL=stats.js.map
@@ -1,10 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/runtime/stats.ts"],
4
- "sourcesContent": [
5
- "import type { Database } from \"@secondlayer/shared/db\";\nimport type { Kysely } from \"kysely\";\nimport type { ProcessBlockTiming } from \"./block-processor.ts\";\n\ninterface StatsEntry {\n\tsubgraphName: string;\n\tbucketStart: Date;\n\tblocksProcessed: number;\n\ttotalTimeMs: number;\n\thandlerTimeMs: number;\n\tflushTimeMs: number;\n\tmaxBlockTimeMs: number;\n\tmaxHandlerTimeMs: number;\n\ttotalOps: number;\n\tisCatchup: boolean;\n}\n\nconst FLUSH_INTERVAL_BLOCKS = 100;\nconst FLUSH_INTERVAL_MS = 60_000;\n\n/**\n * Accumulates per-block timing stats and flushes to DB periodically.\n * One instance per subgraph during catchup/reindex/live processing.\n */\nexport class StatsAccumulator {\n\tprivate current: StatsEntry;\n\tprivate lastFlush = Date.now();\n\n\tconstructor(\n\t\tprivate subgraphName: string,\n\t\tprivate isCatchup: boolean,\n\t) {\n\t\tthis.current = this.newEntry();\n\t}\n\n\trecord(timing: ProcessBlockTiming, opsCount: number): void {\n\t\tthis.current.blocksProcessed++;\n\t\tthis.current.totalTimeMs += timing.totalMs;\n\t\tthis.current.handlerTimeMs += timing.handlerMs;\n\t\tthis.current.flushTimeMs += timing.flushMs;\n\t\tthis.current.maxBlockTimeMs = Math.max(\n\t\t\tthis.current.maxBlockTimeMs,\n\t\t\ttiming.totalMs,\n\t\t);\n\t\tthis.current.maxHandlerTimeMs = Math.max(\n\t\t\tthis.current.maxHandlerTimeMs,\n\t\t\ttiming.handlerMs,\n\t\t);\n\t\tthis.current.totalOps += opsCount;\n\t}\n\n\tshouldFlush(): boolean {\n\t\treturn (\n\t\t\tthis.current.blocksProcessed >= FLUSH_INTERVAL_BLOCKS ||\n\t\t\tDate.now() - this.lastFlush >= FLUSH_INTERVAL_MS\n\t\t);\n\t}\n\n\tasync flush(db: Kysely<Database>): Promise<void> {\n\t\tif (this.current.blocksProcessed === 0) return;\n\n\t\tconst entry = this.current;\n\t\tthis.current = this.newEntry();\n\t\tthis.lastFlush = Date.now();\n\n\t\tconst avgOpsPerBlock =\n\t\t\tentry.blocksProcessed > 0 ? entry.totalOps / entry.blocksProcessed : 0;\n\n\t\tawait db\n\t\t\t.insertInto(\"subgraph_processing_stats\")\n\t\t\t.values({\n\t\t\t\tsubgraph_name: entry.subgraphName,\n\t\t\t\tbucket_start: entry.bucketStart,\n\t\t\t\tbucket_end: new Date(),\n\t\t\t\tblocks_processed: entry.blocksProcessed,\n\t\t\t\ttotal_time_ms: Math.round(entry.totalTimeMs),\n\t\t\t\thandler_time_ms: Math.round(entry.handlerTimeMs),\n\t\t\t\tflush_time_ms: Math.round(entry.flushTimeMs),\n\t\t\t\tmax_block_time_ms: Math.round(entry.maxBlockTimeMs),\n\t\t\t\tmax_handler_time_ms: Math.round(entry.maxHandlerTimeMs),\n\t\t\t\tavg_ops_per_block: Number.parseFloat(avgOpsPerBlock.toFixed(2)),\n\t\t\t\tis_catchup: entry.isCatchup,\n\t\t\t})\n\t\t\t.execute();\n\t}\n\n\tprivate newEntry(): StatsEntry {\n\t\treturn {\n\t\t\tsubgraphName: this.subgraphName,\n\t\t\tbucketStart: new Date(),\n\t\t\tblocksProcessed: 0,\n\t\t\ttotalTimeMs: 0,\n\t\t\thandlerTimeMs: 0,\n\t\t\tflushTimeMs: 0,\n\t\t\tmaxBlockTimeMs: 0,\n\t\t\tmaxHandlerTimeMs: 0,\n\t\t\ttotalOps: 0,\n\t\t\tisCatchup: this.isCatchup,\n\t\t};\n\t}\n}\n"
6
- ],
7
- "mappings": ";;;;AAiBA,IAAM,wBAAwB;AAC9B,IAAM,oBAAoB;AAAA;AAMnB,MAAM,iBAAiB;AAAA,EAKpB;AAAA,EACA;AAAA,EALD;AAAA,EACA,YAAY,KAAK,IAAI;AAAA,EAE7B,WAAW,CACF,cACA,WACP;AAAA,IAFO;AAAA,IACA;AAAA,IAER,KAAK,UAAU,KAAK,SAAS;AAAA;AAAA,EAG9B,MAAM,CAAC,QAA4B,UAAwB;AAAA,IAC1D,KAAK,QAAQ;AAAA,IACb,KAAK,QAAQ,eAAe,OAAO;AAAA,IACnC,KAAK,QAAQ,iBAAiB,OAAO;AAAA,IACrC,KAAK,QAAQ,eAAe,OAAO;AAAA,IACnC,KAAK,QAAQ,iBAAiB,KAAK,IAClC,KAAK,QAAQ,gBACb,OAAO,OACR;AAAA,IACA,KAAK,QAAQ,mBAAmB,KAAK,IACpC,KAAK,QAAQ,kBACb,OAAO,SACR;AAAA,IACA,KAAK,QAAQ,YAAY;AAAA;AAAA,EAG1B,WAAW,GAAY;AAAA,IACtB,OACC,KAAK,QAAQ,mBAAmB,yBAChC,KAAK,IAAI,IAAI,KAAK,aAAa;AAAA;AAAA,OAI3B,MAAK,CAAC,IAAqC;AAAA,IAChD,IAAI,KAAK,QAAQ,oBAAoB;AAAA,MAAG;AAAA,IAExC,MAAM,QAAQ,KAAK;AAAA,IACnB,KAAK,UAAU,KAAK,SAAS;AAAA,IAC7B,KAAK,YAAY,KAAK,IAAI;AAAA,IAE1B,MAAM,iBACL,MAAM,kBAAkB,IAAI,MAAM,WAAW,MAAM,kBAAkB;AAAA,IAEtE,MAAM,GACJ,WAAW,2BAA2B,EACtC,OAAO;AAAA,MACP,eAAe,MAAM;AAAA,MACrB,cAAc,MAAM;AAAA,MACpB,YAAY,IAAI;AAAA,MAChB,kBAAkB,MAAM;AAAA,MACxB,eAAe,KAAK,MAAM,MAAM,WAAW;AAAA,MAC3C,iBAAiB,KAAK,MAAM,MAAM,aAAa;AAAA,MAC/C,eAAe,KAAK,MAAM,MAAM,WAAW;AAAA,MAC3C,mBAAmB,KAAK,MAAM,MAAM,cAAc;AAAA,MAClD,qBAAqB,KAAK,MAAM,MAAM,gBAAgB;AAAA,MACtD,mBAAmB,OAAO,WAAW,eAAe,QAAQ,CAAC,CAAC;AAAA,MAC9D,YAAY,MAAM;AAAA,IACnB,CAAC,EACA,QAAQ;AAAA;AAAA,EAGH,QAAQ,GAAe;AAAA,IAC9B,OAAO;AAAA,MACN,cAAc,KAAK;AAAA,MACnB,aAAa,IAAI;AAAA,MACjB,iBAAiB;AAAA,MACjB,aAAa;AAAA,MACb,eAAe;AAAA,MACf,aAAa;AAAA,MACb,gBAAgB;AAAA,MAChB,kBAAkB;AAAA,MAClB,UAAU;AAAA,MACV,WAAW,KAAK;AAAA,IACjB;AAAA;AAEF;",
8
- "debugId": "ABEF009DEA3A0EDE64756E2164756E21",
9
- "names": []
10
- }