@secondlayer/subgraphs 0.8.1 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/src/index.d.ts +113 -32
  2. package/dist/src/index.js +453 -99
  3. package/dist/src/index.js.map +9 -10
  4. package/dist/src/runtime/block-processor.d.ts +110 -20
  5. package/dist/src/runtime/block-processor.js +419 -90
  6. package/dist/src/runtime/block-processor.js.map +7 -8
  7. package/dist/src/runtime/catchup.d.ts +110 -20
  8. package/dist/src/runtime/catchup.js +424 -94
  9. package/dist/src/runtime/catchup.js.map +8 -9
  10. package/dist/src/runtime/clarity.js +3 -3
  11. package/dist/src/runtime/clarity.js.map +3 -3
  12. package/dist/src/runtime/context.d.ts +23 -5
  13. package/dist/src/runtime/context.js +57 -1
  14. package/dist/src/runtime/context.js.map +3 -3
  15. package/dist/src/runtime/processor.js +424 -94
  16. package/dist/src/runtime/processor.js.map +8 -9
  17. package/dist/src/runtime/reindex.d.ts +110 -20
  18. package/dist/src/runtime/reindex.js +419 -90
  19. package/dist/src/runtime/reindex.js.map +7 -8
  20. package/dist/src/runtime/reorg.d.ts +110 -20
  21. package/dist/src/runtime/reorg.js +419 -90
  22. package/dist/src/runtime/reorg.js.map +7 -8
  23. package/dist/src/runtime/runner.d.ts +150 -42
  24. package/dist/src/runtime/runner.js +193 -30
  25. package/dist/src/runtime/runner.js.map +4 -4
  26. package/dist/src/runtime/source-matcher.d.ts +86 -31
  27. package/dist/src/runtime/source-matcher.js +171 -61
  28. package/dist/src/runtime/source-matcher.js.map +4 -5
  29. package/dist/src/schema/index.d.ts +110 -20
  30. package/dist/src/schema/index.js +34 -9
  31. package/dist/src/schema/index.js.map +3 -3
  32. package/dist/src/service.js +424 -94
  33. package/dist/src/service.js.map +8 -9
  34. package/dist/src/templates.js +52 -51
  35. package/dist/src/templates.js.map +3 -3
  36. package/dist/src/types.d.ts +111 -29
  37. package/dist/src/types.js +1 -20
  38. package/dist/src/types.js.map +3 -4
  39. package/dist/src/validate.d.ts +112 -22
  40. package/dist/src/validate.js +35 -10
  41. package/dist/src/validate.js.map +3 -3
  42. package/package.json +2 -2
package/dist/src/index.js CHANGED
@@ -1,20 +1,6 @@
1
1
  import { createRequire } from "node:module";
2
2
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
3
3
 
4
- // src/types.ts
5
- function sourceKey(source) {
6
- if (source.contract) {
7
- if (source.function)
8
- return `${source.contract}::${source.function}`;
9
- if (source.event)
10
- return `${source.contract}::${source.event}`;
11
- return source.contract;
12
- }
13
- if (source.type)
14
- return source.type;
15
- return "*";
16
- }
17
-
18
4
  // src/validate.ts
19
5
  import { z } from "zod/v4";
20
6
  var SubgraphNameSchema = z.string().min(1).max(63).regex(/^[a-z][a-z0-9-]*$/, "Must start with lowercase letter, contain only lowercase alphanumeric and hyphens");
@@ -40,18 +26,43 @@ var SubgraphTableSchema = z.object({
40
26
  uniqueKeys: z.array(z.array(z.string())).optional()
41
27
  });
42
28
  var SubgraphSchemaSchema = z.record(z.string(), SubgraphTableSchema).refine((s) => Object.keys(s).length > 0, "Schema must have at least one table");
43
- var SubgraphSourceSchema = z.object({
44
- contract: z.string().optional(),
45
- event: z.string().optional(),
46
- function: z.string().optional(),
47
- type: z.string().optional(),
48
- minAmount: z.bigint().optional()
49
- }).refine((s) => s.contract || s.type, "Source must specify at least 'contract' or 'type'");
29
+ var VALID_FILTER_TYPES = [
30
+ "stx_transfer",
31
+ "stx_mint",
32
+ "stx_burn",
33
+ "stx_lock",
34
+ "ft_transfer",
35
+ "ft_mint",
36
+ "ft_burn",
37
+ "nft_transfer",
38
+ "nft_mint",
39
+ "nft_burn",
40
+ "contract_call",
41
+ "contract_deploy",
42
+ "print_event"
43
+ ];
44
+ var SubgraphFilterSchema = z.object({
45
+ type: z.enum(VALID_FILTER_TYPES),
46
+ sender: z.string().optional(),
47
+ recipient: z.string().optional(),
48
+ minAmount: z.bigint().optional(),
49
+ maxAmount: z.bigint().optional(),
50
+ assetIdentifier: z.string().optional(),
51
+ contractId: z.string().optional(),
52
+ functionName: z.string().optional(),
53
+ caller: z.string().optional(),
54
+ deployer: z.string().optional(),
55
+ contractName: z.string().optional(),
56
+ topic: z.string().optional(),
57
+ lockedAddress: z.string().optional(),
58
+ abi: z.record(z.string(), z.any()).optional()
59
+ }).passthrough();
50
60
  var SubgraphDefinitionSchema = z.object({
51
61
  name: SubgraphNameSchema,
52
62
  version: z.string().optional(),
53
63
  description: z.string().optional(),
54
- sources: z.array(SubgraphSourceSchema).min(1, "Must have at least one source"),
64
+ startBlock: z.number().int().nonnegative().optional(),
65
+ sources: z.record(z.string(), SubgraphFilterSchema).refine((s) => Object.keys(s).length > 0, "Must have at least one source"),
55
66
  schema: SubgraphSchemaSchema,
56
67
  handlers: z.record(z.string(), z.any())
57
68
  });
@@ -61,6 +72,7 @@ function validateSubgraphDefinition(def) {
61
72
 
62
73
  // src/runtime/context.ts
63
74
  import { logger } from "@secondlayer/shared/logger";
75
+ import { formatUnits } from "@secondlayer/stacks/utils";
64
76
  import { sql } from "kysely";
65
77
  function validateColumnName(name) {
66
78
  if (!/^[a-z_][a-z0-9_]*$/i.test(name)) {
@@ -128,6 +140,20 @@ class SubgraphContext {
128
140
  this.validateTable(table);
129
141
  this.ops.push({ kind: "delete", table, data: where });
130
142
  }
143
+ patch(table, where, set) {
144
+ this.update(table, where, set);
145
+ }
146
+ async patchOrInsert(table, key, row) {
147
+ const existing = await this.findOne(table, key);
148
+ const resolved = {};
149
+ for (const [k, v] of Object.entries(row)) {
150
+ resolved[k] = typeof v === "function" ? v(existing) : v;
151
+ }
152
+ this.upsert(table, key, resolved);
153
+ }
154
+ formatUnits(value, decimals) {
155
+ return formatUnits(value, decimals);
156
+ }
131
157
  async findOne(table, where) {
132
158
  this.validateTable(table);
133
159
  const qualifiedTable = `"${this.pgSchemaName}"."${table}"`;
@@ -145,6 +171,47 @@ class SubgraphContext {
145
171
  const { rows } = await sql.raw(query).execute(this.db);
146
172
  return rows.map((r) => this.coerceRow(table, r));
147
173
  }
174
+ async count(table, where) {
175
+ this.validateTable(table);
176
+ const qualifiedTable = `"${this.pgSchemaName}"."${table}"`;
177
+ const whereClause = where ? `WHERE ${buildWhereClause(where).clause}` : "";
178
+ const { rows } = await sql.raw(`SELECT COUNT(*)::int AS count FROM ${qualifiedTable} ${whereClause}`).execute(this.db);
179
+ return Number(rows[0]?.count ?? 0);
180
+ }
181
+ async sum(table, column, where) {
182
+ this.validateTable(table);
183
+ validateColumnName(column);
184
+ const qualifiedTable = `"${this.pgSchemaName}"."${table}"`;
185
+ const whereClause = where ? `WHERE ${buildWhereClause(where).clause}` : "";
186
+ const { rows } = await sql.raw(`SELECT COALESCE(SUM("${column}"), 0) AS total FROM ${qualifiedTable} ${whereClause}`).execute(this.db);
187
+ return BigInt(rows[0]?.total?.toString() ?? "0");
188
+ }
189
+ async min(table, column, where) {
190
+ this.validateTable(table);
191
+ validateColumnName(column);
192
+ const qualifiedTable = `"${this.pgSchemaName}"."${table}"`;
193
+ const whereClause = where ? `WHERE ${buildWhereClause(where).clause}` : "";
194
+ const { rows } = await sql.raw(`SELECT MIN("${column}") AS val FROM ${qualifiedTable} ${whereClause}`).execute(this.db);
195
+ const val = rows[0]?.val;
196
+ return val != null ? BigInt(val.toString()) : null;
197
+ }
198
+ async max(table, column, where) {
199
+ this.validateTable(table);
200
+ validateColumnName(column);
201
+ const qualifiedTable = `"${this.pgSchemaName}"."${table}"`;
202
+ const whereClause = where ? `WHERE ${buildWhereClause(where).clause}` : "";
203
+ const { rows } = await sql.raw(`SELECT MAX("${column}") AS val FROM ${qualifiedTable} ${whereClause}`).execute(this.db);
204
+ const val = rows[0]?.val;
205
+ return val != null ? BigInt(val.toString()) : null;
206
+ }
207
+ async countDistinct(table, column, where) {
208
+ this.validateTable(table);
209
+ validateColumnName(column);
210
+ const qualifiedTable = `"${this.pgSchemaName}"."${table}"`;
211
+ const whereClause = where ? `WHERE ${buildWhereClause(where).clause}` : "";
212
+ const { rows } = await sql.raw(`SELECT COUNT(DISTINCT "${column}")::int AS count FROM ${qualifiedTable} ${whereClause}`).execute(this.db);
213
+ return Number(rows[0]?.count ?? 0);
214
+ }
148
215
  coerceRow(table, row) {
149
216
  const tableDef = this.subgraphSchema[table];
150
217
  if (!tableDef)
@@ -285,12 +352,12 @@ function buildWhereClause(where) {
285
352
  }
286
353
 
287
354
  // src/runtime/clarity.ts
288
- import { cvToJSON, deserializeCV } from "@secondlayer/stacks/clarity";
355
+ import { cvToValue, deserializeCV } from "@secondlayer/stacks/clarity";
289
356
  function decodeClarityValue(hex) {
290
357
  try {
291
358
  const cleanHex = hex.startsWith("0x") ? hex.slice(2) : hex;
292
359
  const cv = deserializeCV(cleanHex);
293
- return cvToJSON(cv);
360
+ return cvToValue(cv);
294
361
  } catch {
295
362
  return hex;
296
363
  }
@@ -319,19 +386,177 @@ function decodeFunctionArgs(args) {
319
386
  import { getErrorMessage } from "@secondlayer/shared";
320
387
  import { logger as logger2 } from "@secondlayer/shared/logger";
321
388
  var DEFAULT_ERROR_THRESHOLD = 50;
322
- function resolveHandler(handlers, key) {
323
- return handlers[key] ?? handlers["*"] ?? null;
389
+ function camelCase(str) {
390
+ return str.replace(/-([a-z0-9])/g, (_, c) => c.toUpperCase());
391
+ }
392
+ function camelizeKeys(obj) {
393
+ if (obj === null || obj === undefined)
394
+ return obj;
395
+ if (typeof obj !== "object")
396
+ return obj;
397
+ if (Array.isArray(obj))
398
+ return obj.map(camelizeKeys);
399
+ const result = {};
400
+ for (const [k, v] of Object.entries(obj)) {
401
+ result[camelCase(k)] = camelizeKeys(v);
402
+ }
403
+ return result;
404
+ }
405
+ function buildEventPayload(filter, tx, event) {
406
+ const txMeta = {
407
+ txId: tx.tx_id,
408
+ sender: tx.sender,
409
+ type: tx.type,
410
+ status: tx.status,
411
+ contractId: tx.contract_id ?? null,
412
+ functionName: tx.function_name ?? null
413
+ };
414
+ if (!event) {
415
+ switch (filter.type) {
416
+ case "contract_call":
417
+ return {
418
+ contractId: tx.contract_id ?? "",
419
+ functionName: tx.function_name ?? "",
420
+ caller: tx.sender,
421
+ args: {},
422
+ result: null,
423
+ tx: txMeta
424
+ };
425
+ case "contract_deploy":
426
+ return {
427
+ contractId: tx.contract_id ?? "",
428
+ deployer: tx.sender,
429
+ tx: txMeta
430
+ };
431
+ default:
432
+ return { tx: txMeta };
433
+ }
434
+ }
435
+ const decoded = decodeEventData(event.data);
436
+ switch (filter.type) {
437
+ case "ft_transfer":
438
+ return {
439
+ sender: decoded.sender,
440
+ recipient: decoded.recipient,
441
+ amount: decoded.amount,
442
+ assetIdentifier: decoded.asset_identifier,
443
+ tx: txMeta
444
+ };
445
+ case "ft_mint":
446
+ return {
447
+ recipient: decoded.recipient,
448
+ amount: decoded.amount,
449
+ assetIdentifier: decoded.asset_identifier,
450
+ tx: txMeta
451
+ };
452
+ case "ft_burn":
453
+ return {
454
+ sender: decoded.sender,
455
+ amount: decoded.amount,
456
+ assetIdentifier: decoded.asset_identifier,
457
+ tx: txMeta
458
+ };
459
+ case "nft_transfer":
460
+ return {
461
+ sender: decoded.sender,
462
+ recipient: decoded.recipient,
463
+ tokenId: decoded.value,
464
+ assetIdentifier: decoded.asset_identifier,
465
+ tx: txMeta
466
+ };
467
+ case "nft_mint":
468
+ return {
469
+ recipient: decoded.recipient,
470
+ tokenId: decoded.value,
471
+ assetIdentifier: decoded.asset_identifier,
472
+ tx: txMeta
473
+ };
474
+ case "nft_burn":
475
+ return {
476
+ sender: decoded.sender,
477
+ tokenId: decoded.value,
478
+ assetIdentifier: decoded.asset_identifier,
479
+ tx: txMeta
480
+ };
481
+ case "stx_transfer":
482
+ return {
483
+ sender: decoded.sender,
484
+ recipient: decoded.recipient,
485
+ amount: decoded.amount,
486
+ memo: decoded.memo ?? "",
487
+ tx: txMeta
488
+ };
489
+ case "stx_mint":
490
+ return {
491
+ recipient: decoded.recipient,
492
+ amount: decoded.amount,
493
+ tx: txMeta
494
+ };
495
+ case "stx_burn":
496
+ return {
497
+ sender: decoded.sender,
498
+ amount: decoded.amount,
499
+ tx: txMeta
500
+ };
501
+ case "stx_lock":
502
+ return {
503
+ lockedAddress: decoded.locked_address,
504
+ lockedAmount: decoded.locked_amount,
505
+ unlockHeight: decoded.unlock_height,
506
+ tx: txMeta
507
+ };
508
+ case "print_event": {
509
+ const topic = decoded.topic ?? "";
510
+ const rawValue = decoded.value;
511
+ const data = rawValue && typeof rawValue === "object" ? camelizeKeys(rawValue) : rawValue;
512
+ return {
513
+ contractId: decoded.contract_identifier ?? tx.contract_id ?? "",
514
+ topic,
515
+ data: data ?? {},
516
+ tx: txMeta
517
+ };
518
+ }
519
+ case "contract_call":
520
+ return {
521
+ ...decoded,
522
+ _eventType: event.type,
523
+ contractId: tx.contract_id ?? "",
524
+ functionName: tx.function_name ?? "",
525
+ caller: tx.sender,
526
+ args: {},
527
+ result: null,
528
+ tx: txMeta
529
+ };
530
+ case "contract_deploy":
531
+ return {
532
+ contractId: tx.contract_id ?? "",
533
+ deployer: tx.sender,
534
+ tx: txMeta
535
+ };
536
+ default:
537
+ return {
538
+ ...decoded,
539
+ _eventType: event.type,
540
+ tx: txMeta
541
+ };
542
+ }
324
543
  }
325
544
  async function runHandlers(subgraph, matched, ctx, opts) {
326
545
  let processed = 0;
327
546
  let errors = 0;
328
547
  const threshold = opts?.errorThreshold ?? DEFAULT_ERROR_THRESHOLD;
329
- for (const { tx, events, sourceKey: sourceKey2 } of matched) {
330
- const handler = resolveHandler(subgraph.handlers, sourceKey2);
548
+ const filterLookup = new Map;
549
+ if (!Array.isArray(subgraph.sources)) {
550
+ for (const [name, filter] of Object.entries(subgraph.sources)) {
551
+ filterLookup.set(name, filter);
552
+ }
553
+ }
554
+ for (const { tx, events, sourceName } of matched) {
555
+ const handler = subgraph.handlers[sourceName] ?? subgraph.handlers["*"] ?? null;
331
556
  if (!handler) {
332
- logger2.warn("No handler found for source key", {
557
+ logger2.warn("No handler found for source", {
333
558
  subgraph: subgraph.name,
334
- sourceKey: sourceKey2,
559
+ sourceName,
335
560
  txId: tx.tx_id
336
561
  });
337
562
  continue;
@@ -340,11 +565,14 @@ async function runHandlers(subgraph, matched, ctx, opts) {
340
565
  txId: tx.tx_id,
341
566
  sender: tx.sender,
342
567
  type: tx.type,
343
- status: tx.status
568
+ status: tx.status,
569
+ contractId: tx.contract_id ?? null,
570
+ functionName: tx.function_name ?? null
344
571
  });
572
+ const filter = filterLookup.get(sourceName);
345
573
  if (events.length === 0) {
346
574
  try {
347
- const txPayload = {
575
+ const payload = filter ? buildEventPayload(filter, tx, null) : {
348
576
  tx: {
349
577
  txId: tx.tx_id,
350
578
  sender: tx.sender,
@@ -354,13 +582,13 @@ async function runHandlers(subgraph, matched, ctx, opts) {
354
582
  functionName: tx.function_name
355
583
  }
356
584
  };
357
- await handler(txPayload, ctx);
585
+ await handler(payload, ctx);
358
586
  processed++;
359
587
  } catch (err) {
360
588
  errors++;
361
589
  logger2.error("Subgraph handler error", {
362
590
  subgraph: subgraph.name,
363
- sourceKey: sourceKey2,
591
+ sourceName,
364
592
  txId: tx.tx_id,
365
593
  error: getErrorMessage(err)
366
594
  });
@@ -377,28 +605,30 @@ async function runHandlers(subgraph, matched, ctx, opts) {
377
605
  return { processed, errors };
378
606
  }
379
607
  try {
380
- const decoded = decodeEventData(event.data);
381
- const eventPayload = {
382
- ...decoded,
383
- _eventId: event.id,
384
- _eventType: event.type,
385
- _eventIndex: event.event_index,
386
- tx: {
387
- txId: tx.tx_id,
388
- sender: tx.sender,
389
- type: tx.type,
390
- status: tx.status,
391
- contractId: tx.contract_id,
392
- functionName: tx.function_name
393
- }
394
- };
395
- await handler(eventPayload, ctx);
608
+ const payload = filter ? buildEventPayload(filter, tx, event) : (() => {
609
+ const decoded = decodeEventData(event.data);
610
+ return {
611
+ ...decoded,
612
+ _eventId: event.id,
613
+ _eventType: event.type,
614
+ _eventIndex: event.event_index,
615
+ tx: {
616
+ txId: tx.tx_id,
617
+ sender: tx.sender,
618
+ type: tx.type,
619
+ status: tx.status,
620
+ contractId: tx.contract_id,
621
+ functionName: tx.function_name
622
+ }
623
+ };
624
+ })();
625
+ await handler(payload, ctx);
396
626
  processed++;
397
627
  } catch (err) {
398
628
  errors++;
399
629
  logger2.error("Subgraph handler error", {
400
630
  subgraph: subgraph.name,
401
- sourceKey: sourceKey2,
631
+ sourceName,
402
632
  txId: tx.tx_id,
403
633
  eventId: event.id,
404
634
  eventType: event.type,
@@ -423,62 +653,186 @@ function matchPattern(value, pattern) {
423
653
  }
424
654
  return re.test(value);
425
655
  }
426
- function matchSource(source, transactions, eventsByTx) {
656
+ function matchFilter(filter, transactions, eventsByTx) {
427
657
  const results = [];
428
- const key = sourceKey(source);
429
- for (const tx of transactions) {
430
- if (source.type) {
431
- if (!matchPattern(tx.type, source.type))
432
- continue;
433
- const txEvents = eventsByTx.get(tx.tx_id) ?? [];
434
- let matchedEvents = txEvents;
435
- if (source.minAmount !== undefined) {
436
- const amountEvents = matchedEvents.filter((e) => {
658
+ switch (filter.type) {
659
+ case "stx_transfer":
660
+ case "stx_mint":
661
+ case "stx_burn":
662
+ case "stx_lock": {
663
+ const eventType = `${filter.type}_event`;
664
+ for (const tx of transactions) {
665
+ const txEvents = eventsByTx.get(tx.tx_id) ?? [];
666
+ const matched = txEvents.filter((e) => e.type === eventType);
667
+ if (matched.length === 0)
668
+ continue;
669
+ const filtered = matched.filter((e) => {
437
670
  const data = e.data;
438
- const rawAmount = data?.amount;
439
- if (rawAmount === undefined)
671
+ if (!data)
440
672
  return false;
441
- const amount = BigInt(rawAmount);
442
- return amount >= source.minAmount;
673
+ if ("sender" in filter && filter.sender) {
674
+ if (!matchPattern(data.sender, filter.sender))
675
+ return false;
676
+ }
677
+ if ("recipient" in filter && filter.recipient) {
678
+ if (!matchPattern(data.recipient, filter.recipient))
679
+ return false;
680
+ }
681
+ if ("lockedAddress" in filter && filter.lockedAddress) {
682
+ if (!matchPattern(data.locked_address, filter.lockedAddress))
683
+ return false;
684
+ }
685
+ if ("minAmount" in filter && filter.minAmount !== undefined) {
686
+ const amount = BigInt(data.amount ?? data.locked_amount ?? "0");
687
+ if (amount < filter.minAmount)
688
+ return false;
689
+ }
690
+ if ("maxAmount" in filter && filter.maxAmount !== undefined) {
691
+ const amount = BigInt(data.amount ?? "0");
692
+ if (amount > filter.maxAmount)
693
+ return false;
694
+ }
695
+ return true;
443
696
  });
444
- if (amountEvents.length === 0)
445
- continue;
446
- matchedEvents = amountEvents;
697
+ if (filtered.length > 0) {
698
+ results.push({ tx, events: filtered });
699
+ }
447
700
  }
448
- results.push({ tx, events: matchedEvents, sourceKey: key });
449
- continue;
701
+ break;
450
702
  }
451
- if (source.contract) {
452
- const txContractMatch = tx.contract_id && matchPattern(tx.contract_id, source.contract);
453
- if (source.function && tx.function_name) {
454
- if (!matchPattern(tx.function_name, source.function))
455
- continue;
456
- } else if (source.function && !tx.function_name) {
457
- continue;
703
+ case "ft_transfer":
704
+ case "ft_mint":
705
+ case "ft_burn": {
706
+ const eventType = `${filter.type}_event`;
707
+ for (const tx of transactions) {
708
+ const txEvents = eventsByTx.get(tx.tx_id) ?? [];
709
+ const matched = txEvents.filter((e) => {
710
+ if (e.type !== eventType)
711
+ return false;
712
+ const data = e.data;
713
+ if (!data)
714
+ return false;
715
+ if (filter.assetIdentifier) {
716
+ const assetId = data.asset_identifier;
717
+ if (!assetId || !matchPattern(assetId, filter.assetIdentifier))
718
+ return false;
719
+ }
720
+ if ("sender" in filter && filter.sender) {
721
+ if (!matchPattern(data.sender, filter.sender))
722
+ return false;
723
+ }
724
+ if ("recipient" in filter && filter.recipient) {
725
+ if (!matchPattern(data.recipient, filter.recipient))
726
+ return false;
727
+ }
728
+ if (filter.minAmount !== undefined) {
729
+ const amount = BigInt(data.amount ?? "0");
730
+ if (amount < filter.minAmount)
731
+ return false;
732
+ }
733
+ return true;
734
+ });
735
+ if (matched.length > 0) {
736
+ results.push({ tx, events: matched });
737
+ }
458
738
  }
459
- const txEvents = eventsByTx.get(tx.tx_id) ?? [];
460
- let matchedEvents = txEvents;
461
- if (!txContractMatch) {
462
- matchedEvents = txEvents.filter((e) => {
739
+ break;
740
+ }
741
+ case "nft_transfer":
742
+ case "nft_mint":
743
+ case "nft_burn": {
744
+ const eventType = `${filter.type}_event`;
745
+ for (const tx of transactions) {
746
+ const txEvents = eventsByTx.get(tx.tx_id) ?? [];
747
+ const matched = txEvents.filter((e) => {
748
+ if (e.type !== eventType)
749
+ return false;
463
750
  const data = e.data;
464
- const contractIdentifier = data?.contract_identifier;
465
- return contractIdentifier && matchPattern(contractIdentifier, source.contract);
751
+ if (!data)
752
+ return false;
753
+ if (filter.assetIdentifier) {
754
+ const assetId = data.asset_identifier;
755
+ if (!assetId || !matchPattern(assetId, filter.assetIdentifier))
756
+ return false;
757
+ }
758
+ if ("sender" in filter && filter.sender) {
759
+ if (!matchPattern(data.sender, filter.sender))
760
+ return false;
761
+ }
762
+ if ("recipient" in filter && filter.recipient) {
763
+ if (!matchPattern(data.recipient, filter.recipient))
764
+ return false;
765
+ }
766
+ return true;
466
767
  });
467
- if (matchedEvents.length === 0)
768
+ if (matched.length > 0) {
769
+ results.push({ tx, events: matched });
770
+ }
771
+ }
772
+ break;
773
+ }
774
+ case "contract_call": {
775
+ for (const tx of transactions) {
776
+ if (tx.type !== "contract_call")
777
+ continue;
778
+ if (filter.contractId) {
779
+ if (!tx.contract_id || !matchPattern(tx.contract_id, filter.contractId))
780
+ continue;
781
+ }
782
+ if (filter.functionName) {
783
+ if (!tx.function_name || !matchPattern(tx.function_name, filter.functionName))
784
+ continue;
785
+ }
786
+ if (filter.caller) {
787
+ if (!matchPattern(tx.sender, filter.caller))
788
+ continue;
789
+ }
790
+ const txEvents = eventsByTx.get(tx.tx_id) ?? [];
791
+ results.push({ tx, events: txEvents });
792
+ }
793
+ break;
794
+ }
795
+ case "contract_deploy": {
796
+ for (const tx of transactions) {
797
+ if (tx.type !== "smart_contract")
468
798
  continue;
799
+ if (filter.deployer) {
800
+ if (!matchPattern(tx.sender, filter.deployer))
801
+ continue;
802
+ }
803
+ if (filter.contractName) {
804
+ const name = tx.contract_id?.split(".")[1] ?? "";
805
+ if (!matchPattern(name, filter.contractName))
806
+ continue;
807
+ }
808
+ const txEvents = eventsByTx.get(tx.tx_id) ?? [];
809
+ results.push({ tx, events: txEvents });
469
810
  }
470
- if (source.event) {
471
- matchedEvents = matchedEvents.filter((e) => {
472
- if (matchPattern(e.type, source.event))
473
- return true;
811
+ break;
812
+ }
813
+ case "print_event": {
814
+ for (const tx of transactions) {
815
+ const txEvents = eventsByTx.get(tx.tx_id) ?? [];
816
+ const matched = txEvents.filter((e) => {
817
+ if (e.type !== "smart_contract_event")
818
+ return false;
474
819
  const data = e.data;
475
- const topic = data?.topic;
476
- return topic ? matchPattern(topic, source.event) : false;
820
+ if (!data)
821
+ return false;
822
+ if (data.topic !== "print")
823
+ return false;
824
+ if (filter.contractId) {
825
+ const contractId = data.contract_identifier;
826
+ if (!contractId || !matchPattern(contractId, filter.contractId))
827
+ return false;
828
+ }
829
+ return true;
477
830
  });
831
+ if (matched.length > 0) {
832
+ results.push({ tx, events: matched });
833
+ }
478
834
  }
479
- if (txContractMatch || matchedEvents.length > 0) {
480
- results.push({ tx, events: matchedEvents, sourceKey: key });
481
- }
835
+ break;
482
836
  }
483
837
  }
484
838
  return results;
@@ -492,13 +846,13 @@ function matchSources(sources, transactions, events) {
492
846
  }
493
847
  const seen = new Set;
494
848
  const results = [];
495
- for (const source of sources) {
496
- const matches = matchSource(source, transactions, eventsByTx);
849
+ for (const [sourceName, filter] of Object.entries(sources)) {
850
+ const matches = matchFilter(filter, transactions, eventsByTx);
497
851
  for (const match of matches) {
498
- const dedupeKey = `${match.tx.tx_id}:${match.sourceKey}`;
852
+ const dedupeKey = `${match.tx.tx_id}:${sourceName}`;
499
853
  if (!seen.has(dedupeKey)) {
500
854
  seen.add(dedupeKey);
501
- results.push(match);
855
+ results.push({ ...match, sourceName });
502
856
  }
503
857
  }
504
858
  }
@@ -1175,6 +1529,7 @@ async function backfillSubgraph(def, opts) {
1175
1529
  throw err;
1176
1530
  }
1177
1531
  }
1532
+
1178
1533
  // src/define.ts
1179
1534
  function defineSubgraph(def) {
1180
1535
  return def;
@@ -1351,7 +1706,6 @@ function getDefault(type) {
1351
1706
  }
1352
1707
  export {
1353
1708
  validateSubgraphDefinition,
1354
- sourceKey,
1355
1709
  resumeReindex,
1356
1710
  reindexSubgraph,
1357
1711
  pgSchemaName,
@@ -1362,5 +1716,5 @@ export {
1362
1716
  backfillSubgraph
1363
1717
  };
1364
1718
 
1365
- //# debugId=4B7B76347D5AD39564756E2164756E21
1719
+ //# debugId=9F5F23B13281C9C864756E2164756E21
1366
1720
  //# sourceMappingURL=index.js.map