@secondlayer/subgraphs 3.21.0 → 3.23.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 +238 -17
  2. package/dist/src/index.js +389 -52
  3. package/dist/src/index.js.map +12 -11
  4. package/dist/src/runtime/block-processor.d.ts +111 -10
  5. package/dist/src/runtime/block-processor.js +263 -31
  6. package/dist/src/runtime/block-processor.js.map +9 -8
  7. package/dist/src/runtime/catchup.d.ts +111 -10
  8. package/dist/src/runtime/catchup.js +263 -31
  9. package/dist/src/runtime/catchup.js.map +9 -8
  10. package/dist/src/runtime/context.d.ts +111 -11
  11. package/dist/src/runtime/context.js +166 -12
  12. package/dist/src/runtime/context.js.map +7 -6
  13. package/dist/src/runtime/processor.js +272 -35
  14. package/dist/src/runtime/processor.js.map +10 -9
  15. package/dist/src/runtime/reindex.d.ts +111 -10
  16. package/dist/src/runtime/reindex.js +263 -31
  17. package/dist/src/runtime/reindex.js.map +9 -8
  18. package/dist/src/runtime/reorg.d.ts +111 -10
  19. package/dist/src/runtime/reorg.js +268 -31
  20. package/dist/src/runtime/reorg.js.map +10 -9
  21. package/dist/src/runtime/replay.d.ts +3 -3
  22. package/dist/src/runtime/replay.js +30 -6
  23. package/dist/src/runtime/replay.js.map +4 -4
  24. package/dist/src/runtime/runner.d.ts +191 -17
  25. package/dist/src/runtime/source-matcher.d.ts +68 -8
  26. package/dist/src/runtime/source-matcher.js +30 -6
  27. package/dist/src/runtime/source-matcher.js.map +3 -3
  28. package/dist/src/runtime/stats.d.ts +3 -3
  29. package/dist/src/schema/index.d.ts +114 -13
  30. package/dist/src/schema/index.js +133 -20
  31. package/dist/src/schema/index.js.map +5 -5
  32. package/dist/src/service.js +272 -35
  33. package/dist/src/service.js.map +10 -9
  34. package/dist/src/testing/index.d.ts +667 -0
  35. package/dist/src/testing/index.js +1463 -0
  36. package/dist/src/testing/index.js.map +17 -0
  37. package/dist/src/triggers/index.d.ts +57 -6
  38. package/dist/src/types.d.ts +112 -11
  39. package/dist/src/validate.d.ts +129 -11
  40. package/dist/src/validate.js +117 -18
  41. package/dist/src/validate.js.map +3 -3
  42. package/package.json +9 -3
@@ -1,4 +1,73 @@
1
- import { AbiContract } from "@secondlayer/stacks/clarity";
1
+ import { AbiContract as AbiContract2 } from "@secondlayer/stacks/clarity";
2
+ import { UnwrapResponse } from "@secondlayer/stacks/actions";
3
+ import { AbiContract, ExtractFunctionArgs, ExtractFunctionOutput, ExtractReadOnlyFunctions, ToCamelCase } from "@secondlayer/stacks/clarity";
4
+ /**
5
+ * How long a read stays valid.
6
+ *
7
+ * - `per-block` (default): pinned to the block being processed, cached under
8
+ * its `index_block_hash`. Sound for any read-only function — reindexing the
9
+ * same block always returns the same value, and a reorg-replaced block has a
10
+ * different id so it can't inherit the orphaned answer.
11
+ * - `contract-constant`: the caller asserts the value cannot change for this
12
+ * contract and these args (SIP-010 `get-decimals`/`get-symbol`), so it is
13
+ * resolved ONCE instead of once per block. This is the mode that makes a
14
+ * backfill affordable — under `per-block` every block is a distinct key and
15
+ * therefore a distinct RPC. Declaring it on a value that does change pins the
16
+ * first answer forever, so it is opt-in and never inferred.
17
+ */
18
+ type ChainReadCacheMode = "per-block" | "contract-constant";
19
+ type ChainReadOptions = {
20
+ cache?: ChainReadCacheMode
21
+ };
22
+ /**
23
+ * The chain-read surface, fully typed by an ABI.
24
+ *
25
+ * Shaped like `getContract` from `@secondlayer/stacks` — the same ABI in, the
26
+ * same camelCased read methods out — minus `call`/`buildCall`: a handler
27
+ * indexes the chain, it never writes to it.
28
+ *
29
+ * Reached through {@link readContractAt} rather than off `ctx.client`
30
+ * directly: an ABI-generic method living on the context interface makes every
31
+ * structural comparison of a subgraph definition instantiate it, which exceeds
32
+ * TS's depth budget. At a call site the ABI is already concrete and it costs
33
+ * nothing.
34
+ */
35
+ interface ChainReadClient {
36
+ /**
37
+ * Read-only methods of a contract, evaluated against the exact block being
38
+ * processed.
39
+ *
40
+ * Every call is pinned to the block's `index_block_hash`, so a handler is a
41
+ * pure function of its block: reindexing a range produces byte-identical
42
+ * rows. Reading at the node's tip instead would make the same reindex
43
+ * return different values — that is the corruption this refuses to allow,
44
+ * so a block whose id was never persisted throws rather than falling back.
45
+ *
46
+ * Results are memoized in Postgres, so a value is fetched once per block
47
+ * rather than once per event (or once per contract with
48
+ * `cache: "contract-constant"`).
49
+ */
50
+ contract<const C extends AbiContract>(contractId: string, abi: C, options?: ChainReadOptions): {
51
+ read: ChainReadMethods<C>
52
+ };
53
+ }
54
+ /**
55
+ * The camelCased read methods of an ABI. Spelled out rather than reused from
56
+ * `ContractInstance<C>["read"]`: that type is a conditional over the codegen
57
+ * brand, and evaluating it wherever a subgraph definition is structurally
58
+ * compared pushes TS past its instantiation depth.
59
+ */
60
+ type ChainReadMethods<C extends AbiContract> = { [N in ExtractReadOnlyFunctions<C> as ToCamelCase<N>] : (args: ExtractFunctionArgs<C, N>) => Promise<UnwrapResponse<ExtractFunctionOutput<C, N>>> };
61
+ /**
62
+ * `ChainReadClient` with the ABI generic erased. Structurally cheap, so the
63
+ * base `SubgraphContext` can carry it; `TypedSubgraphContext` uses the real
64
+ * one and handlers get full inference.
65
+ */
66
+ interface ErasedChainReadClient {
67
+ contract(contractId: string, abi: unknown, options?: ChainReadOptions): {
68
+ read: Record<string, (args?: Record<string, unknown>) => Promise<unknown>>
69
+ };
70
+ }
2
71
  /** Supported column types for subgraph schemas */
3
72
  type ColumnType = "text" | "uint" | "int" | "principal" | "boolean" | "timestamp" | "jsonb";
4
73
  /** Column definition in a subgraph table */
@@ -25,15 +94,24 @@ interface SubgraphRelation {
25
94
  /** Target column(s) the fields point at (a uniqueKeys entry on the target). */
26
95
  referencedColumns: string[];
27
96
  }
28
- /** Table definition within a subgraph schema */
97
+ /**
98
+ * Table definition within a subgraph schema.
99
+ *
100
+ * The array fields are `readonly` so a schema literal can be hoisted out of
101
+ * the `defineSubgraph()` call with `as const` (or {@link defineSchema}) and
102
+ * still typecheck — `as const` produces `readonly [readonly ["holder"]]`,
103
+ * which a mutable `string[][]` rejects. Without that, extracting a helper
104
+ * that takes `ctx` meant losing the entire typed surface, which is why the
105
+ * shipped starter reached for `ctx: any`.
106
+ */
29
107
  interface SubgraphTable {
30
108
  columns: Record<string, SubgraphColumn>;
31
109
  /** Composite indexes (each entry is an array of column names) */
32
- indexes?: string[][];
110
+ indexes?: readonly (readonly string[])[];
33
111
  /** Unique key constraints (each entry is an array of column names). Required for upsert. */
34
- uniqueKeys?: string[][];
112
+ uniqueKeys?: readonly (readonly string[])[];
35
113
  /** Foreign-key relations to other tables (for typed ORM joins). */
36
- relations?: SubgraphRelation[];
114
+ relations?: readonly SubgraphRelation[];
37
115
  }
38
116
  /** Subgraph schema — maps table names to table definitions */
39
117
  type SubgraphSchema = Record<string, SubgraphTable>;
@@ -68,6 +146,45 @@ interface StxLockFilter {
68
146
  type TraitScope = {
69
147
  trait?: string
70
148
  };
149
+ /**
150
+ * Scope a source to a DYNAMIC address set discovered from another source's
151
+ * events, instead of a fixed contract list.
152
+ *
153
+ * The standard shape it unlocks: a router plus pools created after you
154
+ * deploy. `contractId` arrays cover a set you know at authoring time; a
155
+ * factory covers the set that grows. It is deliberately NOT tied to contract
156
+ * deployment — the address can come from any field of any event, so it also
157
+ * covers launchpad-minted tokens, DAO extension allowlists, and registry
158
+ * entries.
159
+ *
160
+ * ```ts
161
+ * sources: {
162
+ * registry: { type: "print_event", contractId: REGISTRY, topic: "pool-created" },
163
+ * swaps: {
164
+ * type: "print_event",
165
+ * topic: "swap",
166
+ * // every pool the registry has ever announced, including new ones
167
+ * factory: { from: "registry", field: "data.pool" },
168
+ * },
169
+ * }
170
+ * ```
171
+ *
172
+ * Two guarantees the runtime provides:
173
+ * - **Same-block ordering** — a contract discovered in block N receives its
174
+ * own block-N events. Discovery runs before matching, within the block.
175
+ * - **Reorg-scoped** — the discovered set is stamped with the block that
176
+ * revealed it and rolled back with everything else on a fork, so an address
177
+ * announced on an orphaned chain does not linger forever.
178
+ */
179
+ interface FactoryScope {
180
+ factory?: {
181
+ /** Source name whose events reveal the addresses. */
182
+ from: string
183
+ /** Dotted path to the address on that source's payload
184
+ * (e.g. `"data.pool"`, `"contractId"`, `"data.token.id"`). */
185
+ field: string
186
+ };
187
+ }
71
188
  /** FT event filters */
72
189
  interface FtTransferFilter extends TraitScope {
73
190
  type: "ft_transfer";
@@ -106,9 +223,19 @@ interface NftBurnFilter extends TraitScope {
106
223
  sender?: string;
107
224
  }
108
225
  /** Contract event filters */
109
- interface ContractCallFilter extends TraitScope {
226
+ interface ContractCallFilter extends TraitScope, FactoryScope {
110
227
  type: "contract_call";
111
- contractId?: string;
228
+ /**
229
+ * One contract id, or a SET of them (max 20) — the standard DeFi shape is
230
+ * a router plus N pools, which used to cost N near-identical sources and
231
+ * handlers, or the `"*"` catch-all that erases per-source typing. Payload
232
+ * types are identical per `type`, so one handler serves the set and
233
+ * `event.contractId` disambiguates.
234
+ *
235
+ * Supports `*` wildcards (e.g. `"SP1ABC….pool-*"`). Mutually exclusive
236
+ * with `trait`, which resolves its own set per block.
237
+ */
238
+ contractId?: string | readonly string[];
112
239
  functionName?: string;
113
240
  caller?: string;
114
241
  /**
@@ -117,7 +244,7 @@ interface ContractCallFilter extends TraitScope {
117
244
  * definition and used at runtime to decode args by name. Omit to keep
118
245
  * `event.args` as a positional `unknown[]`.
119
246
  */
120
- abi?: AbiContract;
247
+ abi?: AbiContract2;
121
248
  }
122
249
  interface ContractDeployFilter {
123
250
  type: "contract_deploy";
@@ -146,9 +273,11 @@ type PrintField = ColumnType | {
146
273
  } | {
147
274
  list: PrintField
148
275
  };
149
- interface PrintEventFilter extends TraitScope {
276
+ interface PrintEventFilter extends TraitScope, FactoryScope {
150
277
  type: "print_event";
151
- contractId?: string;
278
+ /** One contract id, or a set of them (max 20). Supports `*` wildcards.
279
+ * Mutually exclusive with `trait`. */
280
+ contractId?: string | readonly string[];
152
281
  topic?: string;
153
282
  /**
154
283
  * Per-topic field schema. When declared, the handler's `event` is a
@@ -186,8 +315,21 @@ interface SubgraphContext {
186
315
  hash: string
187
316
  timestamp: number
188
317
  burnBlockHeight: number
318
+ /** Nakamoto StacksBlockId, when the block row carries one. */
319
+ indexBlockHash?: string | null
189
320
  };
190
321
  tx: TxMeta;
322
+ /**
323
+ * Read-only contract calls pinned to this block. Cached, so the same
324
+ * (contract, function, args) is fetched once per block rather than once
325
+ * per event.
326
+ *
327
+ * Erased here on purpose: this interface is compared structurally wherever
328
+ * a subgraph definition is passed around, and carrying an ABI-generic
329
+ * method pushes those comparisons past TS's instantiation depth. Handlers
330
+ * receive `TypedSubgraphContext`, which exposes the fully typed version.
331
+ */
332
+ client: ErasedChainReadClient;
191
333
  insert(table: string, row: Record<string, unknown>): void;
192
334
  update(table: string, where: Record<string, unknown>, set: Record<string, unknown>): void;
193
335
  upsert(table: string, key: Record<string, unknown>, row: Record<string, unknown>): void;
@@ -240,9 +382,16 @@ interface SubgraphDefinition {
240
382
  /** Handler functions — keys must match source names (or "*" for catch-all) */
241
383
  handlers: Record<string, SubgraphHandler>;
242
384
  }
243
- import { Database } from "@secondlayer/shared/db";
244
- import { Kysely, Transaction } from "kysely";
245
- type AnyDb = Kysely<Database> | Transaction<Database>;
385
+ import { Database as Database2 } from "@secondlayer/shared/db";
386
+ import { Kysely as Kysely2, Transaction } from "kysely";
387
+ type AnyDb = Kysely2<Database2> | Transaction<Database2>;
388
+ interface WriteOp {
389
+ kind: "insert" | "update" | "delete" | "increment";
390
+ table: string;
391
+ data: Record<string, unknown>;
392
+ /** For update: SET clause. For increment: column → signed delta. */
393
+ set?: Record<string, unknown>;
394
+ }
246
395
  interface FlushWrite {
247
396
  op: "insert" | "update" | "delete";
248
397
  table: string;
@@ -264,6 +413,13 @@ interface BlockMeta {
264
413
  hash: string;
265
414
  timestamp: number;
266
415
  burnBlockHeight: number;
416
+ /**
417
+ * Nakamoto StacksBlockId — the identifier `?tip=` accepts, and the only way
418
+ * to pin a read-only call to THIS block. Null on rows ingested before it
419
+ * was persisted; `ctx.client.readOnly` refuses to run rather than silently
420
+ * reading at the node's tip.
421
+ */
422
+ indexBlockHash?: string | null;
267
423
  }
268
424
  interface TxMeta2 {
269
425
  txId: string;
@@ -289,7 +445,10 @@ declare class SubgraphContext2 {
289
445
  private readonly db;
290
446
  private readonly pgSchemaName;
291
447
  private readonly subgraphSchema;
292
- private readonly ops;
448
+ /** Pending writes for this block. `protected` so the in-memory test
449
+ * context (`@secondlayer/subgraphs/testing`) can materialize them through
450
+ * the SAME overlay this class uses — never a second implementation. */
451
+ protected readonly ops: WriteOp[];
293
452
  /**
294
453
  * BYO data plane: handler writes land in a user-owned DB whose flush can't
295
454
  * share the managed block transaction, so a crash replays the block. When
@@ -305,7 +464,15 @@ declare class SubgraphContext2 {
305
464
  * journal would just be churn the pruner deletes.
306
465
  */
307
466
  private readonly journal;
467
+ /** Memoized per block; see the `client` getter. */
468
+ protected _client?: ChainReadClient;
308
469
  constructor(db: AnyDb, pgSchemaName: string, subgraphSchema: SubgraphSchema, block: BlockMeta, tx: TxMeta2, byo?: boolean, journal?: boolean);
470
+ /**
471
+ * Chain reads pinned to THIS block. Lazily built so a handler that never
472
+ * reads never touches the node config, and so the in-memory test context
473
+ * can override it without a node.
474
+ */
475
+ get client(): ChainReadClient;
309
476
  get tx(): TxMeta2;
310
477
  /** Update the current transaction context (used by runner between events) */
311
478
  setTx(tx: TxMeta2): void;
@@ -340,6 +507,13 @@ declare class SubgraphContext2 {
340
507
  patchOrInsert(table: string, key: Record<string, unknown>, row: Record<string, ComputedValue>): Promise<void>;
341
508
  /** Format a bigint amount with decimal places */
342
509
  formatUnits(value: bigint, decimals: number): string;
510
+ /**
511
+ * Committed rows matching `where`, BEFORE the pending-ops overlay. The one
512
+ * seam a different backing store replaces (the in-memory test context);
513
+ * everything above it — validation, overlay, op queueing, flush semantics
514
+ * — stays here so the two can't diverge.
515
+ */
516
+ protected readRows(table: string, where: Record<string, unknown>, limit?: number): Promise<Record<string, unknown>[]>;
343
517
  findOne(table: string, where: Record<string, unknown>): Promise<Record<string, unknown> | null>;
344
518
  findMany(table: string, where: Record<string, unknown>): Promise<Record<string, unknown>[]>;
345
519
  /**
@@ -349,10 +523,10 @@ declare class SubgraphContext2 {
349
523
  * apply by where-match. Overlaid rows synthesized from pending inserts
350
524
  * lack DB-generated columns (_id, _created_at).
351
525
  */
352
- private overlayOne;
353
- private overlayMany;
526
+ protected overlayOne(table: string, where: Record<string, unknown>, dbRow: Record<string, unknown> | null): Record<string, unknown> | null;
527
+ protected overlayMany(table: string, where: Record<string, unknown>, dbRows: Record<string, unknown>[]): Record<string, unknown>[];
354
528
  /** Apply one pending op to a candidate row state (null = row absent). */
355
- private applyOpToRow;
529
+ protected applyOpToRow(op: WriteOp, row: Record<string, unknown> | null, where: Record<string, unknown>): Record<string, unknown> | null;
356
530
  count(table: string, where?: Record<string, unknown>): Promise<number>;
357
531
  sum(table: string, column: string, where?: Record<string, unknown>): Promise<bigint>;
358
532
  min(table: string, column: string, where?: Record<string, unknown>): Promise<bigint | null>;
@@ -1,4 +1,4 @@
1
- import { AbiContract } from "@secondlayer/stacks/clarity";
1
+ import { AbiContract as AbiContract2 } from "@secondlayer/stacks/clarity";
2
2
  /** Supported column types for subgraph schemas */
3
3
  type ColumnType = "text" | "uint" | "int" | "principal" | "boolean" | "timestamp" | "jsonb";
4
4
  /** STX event filters */
@@ -32,6 +32,45 @@ interface StxLockFilter {
32
32
  type TraitScope = {
33
33
  trait?: string
34
34
  };
35
+ /**
36
+ * Scope a source to a DYNAMIC address set discovered from another source's
37
+ * events, instead of a fixed contract list.
38
+ *
39
+ * The standard shape it unlocks: a router plus pools created after you
40
+ * deploy. `contractId` arrays cover a set you know at authoring time; a
41
+ * factory covers the set that grows. It is deliberately NOT tied to contract
42
+ * deployment — the address can come from any field of any event, so it also
43
+ * covers launchpad-minted tokens, DAO extension allowlists, and registry
44
+ * entries.
45
+ *
46
+ * ```ts
47
+ * sources: {
48
+ * registry: { type: "print_event", contractId: REGISTRY, topic: "pool-created" },
49
+ * swaps: {
50
+ * type: "print_event",
51
+ * topic: "swap",
52
+ * // every pool the registry has ever announced, including new ones
53
+ * factory: { from: "registry", field: "data.pool" },
54
+ * },
55
+ * }
56
+ * ```
57
+ *
58
+ * Two guarantees the runtime provides:
59
+ * - **Same-block ordering** — a contract discovered in block N receives its
60
+ * own block-N events. Discovery runs before matching, within the block.
61
+ * - **Reorg-scoped** — the discovered set is stamped with the block that
62
+ * revealed it and rolled back with everything else on a fork, so an address
63
+ * announced on an orphaned chain does not linger forever.
64
+ */
65
+ interface FactoryScope {
66
+ factory?: {
67
+ /** Source name whose events reveal the addresses. */
68
+ from: string
69
+ /** Dotted path to the address on that source's payload
70
+ * (e.g. `"data.pool"`, `"contractId"`, `"data.token.id"`). */
71
+ field: string
72
+ };
73
+ }
35
74
  /** FT event filters */
36
75
  interface FtTransferFilter extends TraitScope {
37
76
  type: "ft_transfer";
@@ -70,9 +109,19 @@ interface NftBurnFilter extends TraitScope {
70
109
  sender?: string;
71
110
  }
72
111
  /** Contract event filters */
73
- interface ContractCallFilter extends TraitScope {
112
+ interface ContractCallFilter extends TraitScope, FactoryScope {
74
113
  type: "contract_call";
75
- contractId?: string;
114
+ /**
115
+ * One contract id, or a SET of them (max 20) — the standard DeFi shape is
116
+ * a router plus N pools, which used to cost N near-identical sources and
117
+ * handlers, or the `"*"` catch-all that erases per-source typing. Payload
118
+ * types are identical per `type`, so one handler serves the set and
119
+ * `event.contractId` disambiguates.
120
+ *
121
+ * Supports `*` wildcards (e.g. `"SP1ABC….pool-*"`). Mutually exclusive
122
+ * with `trait`, which resolves its own set per block.
123
+ */
124
+ contractId?: string | readonly string[];
76
125
  functionName?: string;
77
126
  caller?: string;
78
127
  /**
@@ -81,7 +130,7 @@ interface ContractCallFilter extends TraitScope {
81
130
  * definition and used at runtime to decode args by name. Omit to keep
82
131
  * `event.args` as a positional `unknown[]`.
83
132
  */
84
- abi?: AbiContract;
133
+ abi?: AbiContract2;
85
134
  }
86
135
  interface ContractDeployFilter {
87
136
  type: "contract_deploy";
@@ -110,9 +159,11 @@ type PrintField = ColumnType | {
110
159
  } | {
111
160
  list: PrintField
112
161
  };
113
- interface PrintEventFilter extends TraitScope {
162
+ interface PrintEventFilter extends TraitScope, FactoryScope {
114
163
  type: "print_event";
115
- contractId?: string;
164
+ /** One contract id, or a set of them (max 20). Supports `*` wildcards.
165
+ * Mutually exclusive with `trait`. */
166
+ contractId?: string | readonly string[];
116
167
  topic?: string;
117
168
  /**
118
169
  * Per-topic field schema. When declared, the handler's `event` is a
@@ -157,8 +208,17 @@ type EventRecord = {
157
208
  };
158
209
  type TraitContracts = Map<string, ReadonlySet<string>>;
159
210
  /**
211
+ * True when a filter's optional `trait` admits this contract: no trait → always
212
+ * allowed; trait set → the contract must be in the resolved conforming set.
213
+ */
214
+ /** Addresses discovered per source name (factory sets), resolved by the
215
+ * caller as-of the block being processed. */
216
+ type FactoryContracts = ReadonlyMap<string, ReadonlySet<string>>;
217
+ /** Read a dotted path off a decoded payload (`"data.pool"`). */
218
+ declare function readPath(payload: unknown, path: string): unknown;
219
+ /**
160
220
  * Match named filters against a block's transactions and events.
161
221
  * Returns matches with sourceName = the object key from sources.
162
222
  */
163
- declare function matchSources(sources: Record<string, SubgraphFilter>, transactions: TxRecord[], events: EventRecord[], traitContracts?: TraitContracts): MatchedTx[];
164
- export { matchSources, TraitContracts, MatchedTx };
223
+ declare function matchSources(sources: Record<string, SubgraphFilter>, transactions: TxRecord[], events: EventRecord[], traitContracts?: TraitContracts, factoryContracts?: FactoryContracts): MatchedTx[];
224
+ export { readPath, matchSources, TxRecord, TraitContracts, MatchedTx, FactoryContracts, EventRecord };
@@ -3,6 +3,9 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
3
3
 
4
4
  // src/runtime/source-matcher.ts
5
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
+ }
6
9
  function matchPattern(value, pattern) {
7
10
  if (!pattern.includes("*"))
8
11
  return value === pattern;
@@ -15,6 +18,22 @@ function matchPattern(value, pattern) {
15
18
  return re.test(value);
16
19
  }
17
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
+ }
18
37
  function traitAllows(filter, contractId, traitContracts) {
19
38
  const trait = filter.trait;
20
39
  if (!trait)
@@ -26,7 +45,7 @@ function traitAllows(filter, contractId, traitContracts) {
26
45
  function assetContract(assetId) {
27
46
  return assetId?.split("::")[0];
28
47
  }
29
- function matchFilter(filter, transactions, eventsByTx, traitContracts) {
48
+ function matchFilter(filter, transactions, eventsByTx, traitContracts, factoryContracts = new Map) {
30
49
  const results = [];
31
50
  switch (filter.type) {
32
51
  case "stx_transfer":
@@ -153,9 +172,11 @@ function matchFilter(filter, transactions, eventsByTx, traitContracts) {
153
172
  if (tx.type !== "contract_call")
154
173
  continue;
155
174
  if (filter.contractId) {
156
- if (!tx.contract_id || !matchPattern(tx.contract_id, filter.contractId))
175
+ if (!tx.contract_id || !matchAny(tx.contract_id, filter.contractId))
157
176
  continue;
158
177
  }
178
+ if (!factoryAllows(filter, tx.contract_id, factoryContracts))
179
+ continue;
159
180
  if (filter.functionName) {
160
181
  if (!tx.function_name || !matchPattern(tx.function_name, filter.functionName))
161
182
  continue;
@@ -202,11 +223,13 @@ function matchFilter(filter, transactions, eventsByTx, traitContracts) {
202
223
  return false;
203
224
  const printContractId = data.contract_identifier ?? data.contract_id;
204
225
  if (filter.contractId) {
205
- if (!printContractId || !matchPattern(printContractId, filter.contractId))
226
+ if (!printContractId || !matchAny(printContractId, filter.contractId))
206
227
  return false;
207
228
  }
208
229
  if (!traitAllows(filter, printContractId, traitContracts))
209
230
  return false;
231
+ if (!factoryAllows(filter, printContractId, factoryContracts))
232
+ return false;
210
233
  return true;
211
234
  });
212
235
  if (matched.length > 0) {
@@ -218,7 +241,7 @@ function matchFilter(filter, transactions, eventsByTx, traitContracts) {
218
241
  }
219
242
  return results;
220
243
  }
221
- function matchSources(sources, transactions, events, traitContracts = new Map) {
244
+ function matchSources(sources, transactions, events, traitContracts = new Map, factoryContracts = new Map) {
222
245
  const eventsByTx = new Map;
223
246
  for (const event of events) {
224
247
  const list = eventsByTx.get(event.tx_id) ?? [];
@@ -228,7 +251,7 @@ function matchSources(sources, transactions, events, traitContracts = new Map) {
228
251
  const seen = new Set;
229
252
  const results = [];
230
253
  for (const [sourceName, filter] of Object.entries(sources)) {
231
- const matches = matchFilter(filter, transactions, eventsByTx, traitContracts);
254
+ const matches = matchFilter(filter, transactions, eventsByTx, traitContracts, factoryContracts);
232
255
  for (const match of matches) {
233
256
  const dedupeKey = `${match.tx.tx_id}:${sourceName}`;
234
257
  if (!seen.has(dedupeKey)) {
@@ -240,8 +263,9 @@ function matchSources(sources, transactions, events, traitContracts = new Map) {
240
263
  return results;
241
264
  }
242
265
  export {
266
+ readPath,
243
267
  matchSources
244
268
  };
245
269
 
246
- //# debugId=4C4140B5CFEF4A9764756E2164756E21
270
+ //# debugId=3A7F11E035AAF9A264756E2164756E21
247
271
  //# sourceMappingURL=source-matcher.js.map
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../src/runtime/source-matcher.ts"],
4
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\ntype 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\ntype EventRecord = {\n\tid: string;\n\ttx_id: string;\n\ttype: string;\n\tevent_index: number;\n\tdata: unknown;\n};\n\n// ── Wildcard matching (shared with v1) ──────────────────────────────\n\nconst patternCache = new Map<string, RegExp>();\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 */\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// ── Per-filter-type matchers ────────────────────────────────────────\n\nfunction matchFilter(\n\tfilter: SubgraphFilter,\n\ttransactions: TxRecord[],\n\teventsByTx: Map<string, EventRecord[]>,\n\ttraitContracts: TraitContracts,\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 (\n\t\t\t\t\t\t!tx.contract_id ||\n\t\t\t\t\t\t!matchPattern(tx.contract_id, filter.contractId)\n\t\t\t\t\t)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t}\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\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\t// Contract filter — events store the contract under either\n\t\t\t\t\t// `contract_identifier` (legacy smart_contract_event payload)\n\t\t\t\t\t// or `contract_id` (current contract_event payload). Mirror\n\t\t\t\t\t// the streams query which checks both shapes.\n\t\t\t\t\tconst printContractId =\n\t\t\t\t\t\t(data.contract_identifier as string | undefined) ??\n\t\t\t\t\t\t(data.contract_id as string | undefined);\n\t\t\t\t\tif (filter.contractId) {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t!printContractId ||\n\t\t\t\t\t\t\t!matchPattern(printContractId, filter.contractId)\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 (!traitAllows(filter, printContractId, traitContracts))\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): MatchedTx[] {\n\t// Index events by txId\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\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);\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"
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\tevent_index: number;\n\tdata: unknown;\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// ── 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): { 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\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\t// Contract filter — events store the contract under either\n\t\t\t\t\t// `contract_identifier` (legacy smart_contract_event payload)\n\t\t\t\t\t// or `contract_id` (current contract_event payload). Mirror\n\t\t\t\t\t// the streams query which checks both shapes.\n\t\t\t\t\tconst printContractId =\n\t\t\t\t\t\t(data.contract_identifier as string | undefined) ??\n\t\t\t\t\t\t(data.contract_id as string | undefined);\n\t\t\t\t\tif (filter.contractId) {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t!printContractId ||\n\t\t\t\t\t\t\t!matchAny(printContractId, filter.contractId)\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 (!traitAllows(filter, printContractId, traitContracts))\n\t\t\t\t\t\treturn false;\n\t\t\t\t\tif (!factoryAllows(filter, printContractId, 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): MatchedTx[] {\n\t// Index events by txId\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\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);\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
6
  ],
7
- "mappings": "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",
8
- "debugId": "4C4140B5CFEF4A9764756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "3A7F11E035AAF9A264756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -3,8 +3,8 @@ interface ProcessBlockTiming {
3
3
  handlerMs: number;
4
4
  flushMs: number;
5
5
  }
6
- import { Database } from "@secondlayer/shared/db";
7
- import { Kysely } from "kysely";
6
+ import { Database as Database2 } from "@secondlayer/shared/db";
7
+ import { Kysely as Kysely2 } from "kysely";
8
8
  /**
9
9
  * Accumulates per-block timing stats and flushes to DB periodically.
10
10
  * One instance per subgraph during catchup/reindex/live processing.
@@ -17,7 +17,7 @@ declare class StatsAccumulator {
17
17
  constructor(subgraphName: string, isCatchup: boolean);
18
18
  record(timing: ProcessBlockTiming, opsCount: number): void;
19
19
  shouldFlush(): boolean;
20
- flush(db: Kysely<Database>): Promise<void>;
20
+ flush(db: Kysely2<Database2>): Promise<void>;
21
21
  private newEntry;
22
22
  }
23
23
  export { StatsAccumulator };