@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
package/README.md CHANGED
@@ -12,16 +12,11 @@ bun add @secondlayer/subgraphs
12
12
 
13
13
  ## Quick Start
14
14
 
15
- For the full hosted beta loop, including project setup, fast deploys with
16
- `--start-block`, querying, and webhooks, start with
17
- [QUICKSTART.md](QUICKSTART.md).
18
-
19
15
  ```typescript
20
16
  import { defineSubgraph } from "@secondlayer/subgraphs";
21
17
 
22
18
  export default defineSubgraph({
23
19
  name: "token-transfers",
24
- version: "1.0.0",
25
20
  sources: {
26
21
  // Named event sources — the key becomes the handler name.
27
22
  transfer: {
@@ -51,28 +46,25 @@ export default defineSubgraph({
51
46
  });
52
47
  ```
53
48
 
54
- Deploy via CLI (`secondlayer subgraphs deploy path/to/definition.ts`), SDK (`sl.subgraphs.deploy({...})`), or MCP (`subgraphs_deploy`). The CLI can also scaffold from a deployed contract with `secondlayer subgraphs scaffold <contract> -o subgraphs/name.ts`; scaffold writes or amends `package.json` and runs `bun install` unless `--no-install` is passed. The dashboard is read-only — creation always happens through an API surface.
49
+ Deploy via CLI (`secondlayer subgraphs deploy path/to/definition.ts`), SDK (`sl.subgraphs.deploy({...})`), or MCP (`subgraphs_deploy`). The CLI can also scaffold from a deployed contract with `secondlayer subgraphs scaffold <contract> -o subgraphs/name.ts`; scaffold writes or amends `package.json` and runs `bun install` unless `--no-install` is passed. `secondlayer subgraphs create <name> --from-contract <id>` writes a definition with one `ctx.insert` handler per print topic.
50
+
51
+ Every source needs a handler of the same name. Handlers write with `ctx.insert`, `update`, `upsert`, `delete` and `increment`, and read with `ctx.findOne` / `findMany`. A `contract_call` source with `functionName` gets its `abi` fetched at deploy by the CLI; pass it yourself for wildcard, multi-contract or trait sources, or a local deploy.
55
52
 
56
53
  ## Exports
57
54
 
58
55
  | Subpath | Description |
59
56
  | --- | --- |
60
- | `.` | `defineSubgraph`, `validateSubgraphDefinition`, `deploySchema`, `diffSchema`, `reindexSubgraph`, `backfillSubgraph`, `generateSubgraphSQL`, `pgSchemaName` |
57
+ | `.` | `defineSubgraph`, `defineSchema`, `InferContext` / `TypedSubgraphContext`, `readContractAt`, `validateSubgraphDefinition`, ORM generators (`generatePrismaSchema`, `generateDrizzleSchema`, `generateKyselySchema`), `deploySchema`, `diffSchema`, `generateSubgraphSQL`, `pgSchemaName` |
61
58
  | `./types` | All schema + filter + handler types (`SubgraphDefinition`, `SubgraphFilter`, `StxTransferFilter`, etc.) |
62
59
  | `./schema` | Generator + deployer internals |
63
60
  | `./validate` | Shape + filter validation for deploys |
64
- | `./triggers` | Typed `on.*` helpers for all `SubgraphFilter` variants |
65
- | `./runtime/source-matcher` | Pure fn: match txs+events against a `SubgraphFilter` — used by the processor hot path |
66
- | `./runtime/replay` | `replayWebhook({ accountId, webhookId, fromBlock, toBlock })` — re-enqueue historical rows as outbox entries |
67
-
68
- ## Runtime components
61
+ | `./testing` | `runSubgraphTest`, `createTestContext`, `buildEvent`: run handlers against real or built events before deploying |
62
+ | `./runtime/replay` | `replayWebhook({ accountId, webhookId, fromBlock, toBlock })`: re-enqueue historical rows as outbox entries |
63
+ | `./runtime/emitter` | Webhook egress checks used by the API (`checkEgressAllowed`) |
69
64
 
70
- The runtime ships behind these entrypoints (import from the package root):
65
+ ## Runtime
71
66
 
72
- - `startSubgraphProcessor(opts?)` — boots the block processor. LISTENs on `indexer:new_block`, matches sources, runs handlers, flushes writes inside a transaction, and emits outbox rows for matching webhooks. Also boots the emitter worker.
73
- - `processBlock(subgraph, name, height, opts?)` — single-block entry point used by catch-up, reindex, and tests.
74
- - `catchUpSubgraph(def, name)` — drains pending blocks up to chain tip.
75
- - `reindexSubgraph(def, opts)` — drop + rebuild schema tables from a start block. Breaking schema changes trigger this automatically on deploy.
67
+ The processor runs as a service, not a library import: `bun run packages/subgraphs/src/service.ts` (the `subgraph-processor` container in `docker/`). It LISTENs on `indexer:new_block`, matches sources, runs handlers, flushes writes inside a transaction, and emits outbox rows for matching webhooks. Breaking schema changes trigger a reindex on deploy.
76
68
 
77
69
  ## Webhook emitter
78
70
 
@@ -80,7 +72,7 @@ Every row written through `ctx.insert()` / `ctx.upsert()` is atomically enqueued
80
72
 
81
73
  The emitter drains the outbox via `LISTEN webhooks:new_outbox` and `FOR UPDATE SKIP LOCKED` batch claims. Live deliveries win a 90/10 split over replays. Each row dispatches through the format builder matching the webhook's `format` column (`standard-webhooks`, `inngest`, `trigger`, `cloudflare`, `cloudevents`, `raw`). Retries follow `30s → 2m → 10m → 1h → 6h → 24h → 72h`. Twenty consecutive failures trips the per-sub circuit breaker and pauses the webhook.
82
74
 
83
- Delivery bodies and response previews land in `webhook_deliveries`. Rows whose retries exhaust mark `status = 'dead'` in the outbox and surface in the dashboard's dead-letter queue for one-click requeue.
75
+ Delivery bodies and response previews land in `webhook_deliveries`. Rows whose retries exhaust mark `status = 'dead'` in the outbox; list them with `secondlayer webhooks dead <id>` and send one again with `secondlayer webhooks requeue`.
84
76
 
85
77
  ## Environment
86
78
 
@@ -100,13 +92,13 @@ Delivery bodies and response previews land in `webhook_deliveries`. Rows whose r
100
92
  Once rows land in your DB, generate a typed schema for your ORM:
101
93
 
102
94
  ```bash
95
+ secondlayer codegen subgraph subgraphs/my.ts # Kysely (default)
103
96
  secondlayer codegen subgraph subgraphs/my.ts --target prisma -o prisma/schema.prisma
104
97
  secondlayer codegen subgraph subgraphs/my.ts --target drizzle -o db/schema.ts
105
98
  ```
106
99
 
107
- Prisma and Drizzle have first-class generators (`generatePrismaSchema` /
108
- `generateDrizzleSchema` are exported); both emit relations/`@relation` from the
109
- schema's `relations` metadata. For Kysely, run `kysely-codegen` against the DB.
100
+ The generators are exported too (`generateKyselySchema`, `generatePrismaSchema`,
101
+ `generateDrizzleSchema`). No foreign keys or relation fields are generated.
110
102
  Output mirrors the deployed DDL — `prisma db pull` should be a no-op; treat the
111
103
  tables as read-only (the processor owns them) and never `migrate`/`push`.
112
104
  `uint`→`Decimal`/`numeric` and the `BigInt` id need `.toString()` for JSON.
@@ -110,22 +110,6 @@ interface SubgraphColumn {
110
110
  default?: string | number | boolean;
111
111
  }
112
112
  /**
113
- * A foreign-key relation to another table in the same subgraph. Drives DDL FK
114
- * constraints and ORM codegen (`@relation` in Prisma, `relations()` in Drizzle)
115
- * so generated clients get typed joins. The referenced columns must form a
116
- * `uniqueKeys` entry on the target table.
117
- */
118
- interface SubgraphRelation {
119
- /** Relation field name on this table's generated model (e.g. "pool"). */
120
- name: string;
121
- /** Target table name in this subgraph. */
122
- references: string;
123
- /** Local column(s) holding the foreign key. */
124
- fields: string[];
125
- /** Target column(s) the fields point at (a uniqueKeys entry on the target). */
126
- referencedColumns: string[];
127
- }
128
- /**
129
113
  * Table definition within a subgraph schema.
130
114
  *
131
115
  * The array fields are `readonly` so a schema literal can be hoisted out of
@@ -141,8 +125,6 @@ interface SubgraphTable {
141
125
  indexes?: readonly (readonly string[])[];
142
126
  /** Unique key constraints (each entry is an array of column names). Required for upsert. */
143
127
  uniqueKeys?: readonly (readonly string[])[];
144
- /** Foreign-key relations to other tables (for typed ORM joins). */
145
- relations?: readonly SubgraphRelation[];
146
128
  }
147
129
  /** Subgraph schema — maps table names to table definitions */
148
130
  type SubgraphSchema = Record<string, SubgraphTable>;
@@ -305,9 +287,8 @@ interface ContractCallFilter extends TraitScope, FactoryScope {
305
287
  /**
306
288
  * One contract id, or a SET of them (max 20) — the standard DeFi shape is
307
289
  * a router plus N pools, which used to cost N near-identical sources and
308
- * handlers, or the `"*"` catch-all that erases per-source typing. Payload
309
- * types are identical per `type`, so one handler serves the set and
310
- * `event.contractId` disambiguates.
290
+ * handlers. Payload types are identical per `type`, so one handler serves
291
+ * the set and `event.contractId` disambiguates.
311
292
  *
312
293
  * Supports `*` wildcards (e.g. `"SP1ABC….pool-*"`). Mutually exclusive
313
294
  * with `trait`, which resolves its own set per block.
@@ -321,8 +302,11 @@ interface ContractCallFilter extends TraitScope, FactoryScope {
321
302
  * definition and used at runtime to decode args by name. Omit to keep
322
303
  * `event.args` as a positional `unknown[]`.
323
304
  *
324
- * Deploy validation requires `abi` whenever `functionName` is set
325
- * (`normalizeAbi()` from `@secondlayer/stacks/clarity`).
305
+ * Required whenever `functionName` is set. `secondlayer subgraphs deploy`
306
+ * fills it in from the deployed contract for a single concrete
307
+ * `contractId`; pass it yourself for wildcard, multi-contract or trait
308
+ * sources, or a local deploy (`normalizeAbi()` from
309
+ * `@secondlayer/stacks/clarity`).
326
310
  */
327
311
  abi?: AbiContract2;
328
312
  }
@@ -379,29 +363,9 @@ type PrintField = ColumnType | {
379
363
  * is skipped and logged rather than written as nulls.
380
364
  */
381
365
  type PrintEventPrints = Record<string, Record<string, PrintField>>;
382
- /**
383
- * One column in a static identity map. Literals only — the bundler never
384
- * executes user code, so `{ from: "tokenX" }` is valid and `from("tokenX")`
385
- * is not.
386
- */
387
- type MaterializeColumn = {
388
- from: string
389
- } | {
390
- fromTx: "sender" | "txId"
391
- } | {
392
- fromBlock: "height" | "hash" | "timestamp"
393
- };
394
- /** Static insert from a source event — replaces a 1:1 handler. */
395
- interface MaterializeSpec {
396
- table: string;
397
- /** Keys = schema column names (snake). */
398
- columns: Record<string, MaterializeColumn>;
399
- }
400
366
  type PrintEventFields = FactoryScope & {
401
367
  type: "print_event"
402
368
  topic?: string
403
- /** Identity map: insert without a handler function. XOR with handlers[name]. */
404
- materialize?: MaterializeSpec
405
369
  };
406
370
  /**
407
371
  * Pinned to one or more contract ids with no trait — `prints` is required so
@@ -447,8 +411,6 @@ interface TxMeta {
447
411
  }
448
412
  /** Scalar types that can appear as row values */
449
413
  type RowValue = string | number | bigint | boolean | null | undefined | Record<string, unknown> | unknown[];
450
- /** Value or computed function that receives existing row */
451
- type ComputedValue = RowValue | ((existing: Record<string, unknown> | null) => unknown);
452
414
  /** Context passed to subgraph handlers during event processing */
453
415
  interface SubgraphContext {
454
416
  block: {
@@ -479,27 +441,11 @@ interface SubgraphContext {
479
441
  * Atomic counter update — the blessed accumulator primitive. Applies
480
442
  * `col = COALESCE(col, 0) + delta` per column (insert-or-add); deltas may
481
443
  * be negative. Requires a uniqueKeys constraint matching `key`. Prefer
482
- * this over patchOrInsert with functional updaters for running totals.
444
+ * this over read-modify-write handlers for running totals.
483
445
  */
484
446
  increment(table: string, key: Record<string, unknown>, deltas: Record<string, bigint | number>): void;
485
- /** Partial update — sets only specified fields, preserves others */
486
- patch(table: string, where: Record<string, unknown>, set: Record<string, unknown>): void;
487
- /** Find-then-merge-or-insert. Values can be functions: (existing) => newValue */
488
- patchOrInsert(table: string, key: Record<string, unknown>, row: Record<string, ComputedValue>): Promise<void>;
489
447
  findOne(table: string, where: Record<string, unknown>): Promise<Record<string, unknown> | null>;
490
448
  findMany(table: string, where: Record<string, unknown>): Promise<Record<string, unknown>[]>;
491
- /** Format a bigint amount with decimal places */
492
- formatUnits(value: bigint, decimals: number): string;
493
- /** Count rows matching filter */
494
- count(table: string, where?: Record<string, unknown>): Promise<number>;
495
- /** Sum a numeric column */
496
- sum(table: string, column: string, where?: Record<string, unknown>): Promise<bigint>;
497
- /** Min of a numeric column */
498
- min(table: string, column: string, where?: Record<string, unknown>): Promise<bigint | null>;
499
- /** Max of a numeric column */
500
- max(table: string, column: string, where?: Record<string, unknown>): Promise<bigint | null>;
501
- /** Count distinct values in a column */
502
- countDistinct(table: string, column: string, where?: Record<string, unknown>): Promise<number>;
503
449
  }
504
450
  /** Handler function that processes events and writes to the subgraph */
505
451
  type SubgraphHandler = (event: Record<string, unknown>, ctx: SubgraphContext) => Promise<void> | void;
@@ -507,8 +453,6 @@ type SubgraphHandler = (event: Record<string, unknown>, ctx: SubgraphContext) =>
507
453
  interface SubgraphDefinition {
508
454
  /** Unique subgraph name (lowercase, alphanumeric + hyphens) */
509
455
  name: string;
510
- /** Semantic version */
511
- version?: string;
512
456
  /** Human description */
513
457
  description?: string;
514
458
  /** Block height to start indexing from (default: 1) */
@@ -520,90 +464,9 @@ interface SubgraphDefinition {
520
464
  sources: Record<string, SubgraphFilter>;
521
465
  /** Tables in this subgraph */
522
466
  schema: SubgraphSchema;
523
- /** Handler functions — keys must match source names (or "*" for catch-all) */
467
+ /** Handler functions, one per source, keyed by source name */
524
468
  handlers: Record<string, SubgraphHandler>;
525
469
  }
526
- /**
527
- * Validates a subgraph definition, returning the parsed result or throwing on failure.
528
- */
529
- declare function validateSubgraphDefinition(def: unknown): SubgraphDefinition;
530
- /**
531
- * Per-source-type field vocabulary, DERIVED from
532
- * {@link SubgraphFilterSchema}. Agent-facing surfaces (the MCP filters
533
- * reference) used to hand-maintain a parallel copy of this list; deriving it
534
- * means adding a field to a filter can never leave the documentation behind.
535
- */
536
- declare function filterFieldsByType(): Array<{
537
- type: string
538
- fields: string[]
539
- }>;
540
- /** A (decoded event type, optional contract scope) pair the sparse probe
541
- * checks. Contract scoping is what makes token-subgraph reindexes leap over
542
- * everything that isn't their token. */
543
- type SparseProbeTarget = {
544
- eventType: string
545
- contractId?: string
546
- };
547
- /** Sparse scanning is sound only when EVERY source is an event-type filter —
548
- * a contract_call/contract_deploy source matches transactions, which the
549
- * event probe can't see. */
550
- declare function canSparseScan(subgraph: SubgraphDefinition): boolean;
551
- /** Probe targets for a subgraph's filters: decoded type + contract scope when\\n* the filter pins one (assetIdentifier "SP….contract::asset" or contractId). */
552
- declare function sparseProbeTargets(subgraph: SubgraphDefinition): SparseProbeTarget[];
553
- interface ReindexOptions {
554
- /**
555
- * Floor on the walk's first block — NOT a caller-supplied range. When set
556
- * (e.g. an op row carrying a `from_block`), it raises the walk start and
557
- * can never lower it. There is deliberately no `toBlock` counterpart:
558
- * a reindex always runs to chain tip. See {@link resolveBlockRange}.
559
- */
560
- startBlockFloor?: number;
561
- schemaName?: string;
562
- /** Op row to receive processed_events on each progress flush. */
563
- operationId?: string;
564
- signal?: AbortSignal;
565
- }
566
- /**
567
- * Reindex a subgraph by dropping its tables, recreating them, and reprocessing
568
- * all historical blocks through the handler pipeline.
569
- *
570
- * Always whole-subgraph: `[start_block, chain tip]`. There is no ranged
571
- * reindex — the drop cannot be scoped to a range without re-running delta
572
- * handlers (`ctx.increment` / `ctx.update` / `ctx.patchOrInsert`) over rows
573
- * that were never removed, which is the exact double-count hazard `backfill`
574
- * already refuses. Use `backfillSubgraph` for ranged, additive work.
575
- *
576
- * Supports cancellation via AbortSignal — on shutdown abort, status stays
577
- * "reindexing" for auto-resume; on user cancel, status resets to "active".
578
- */
579
- declare function reindexSubgraph(def: SubgraphDefinition, opts?: ReindexOptions): Promise<{
580
- processed: number
581
- }>;
582
- /**
583
- * Resume a previously interrupted reindex. Skips schema drop (already done)
584
- * and continues from last_processed_block + 1.
585
- */
586
- declare function resumeReindex(def: SubgraphDefinition, opts: {
587
- schemaName: string
588
- operationId?: string
589
- signal?: AbortSignal
590
- }): Promise<{
591
- processed: number
592
- }>;
593
- /**
594
- * Backfill a subgraph by re-processing a block range WITHOUT dropping the schema.
595
- * Uses upserts so existing data is updated, not duplicated. Safe to run while
596
- * the subgraph is actively syncing.
597
- */
598
- declare function backfillSubgraph(def: SubgraphDefinition, opts: {
599
- fromBlock: number
600
- toBlock: number
601
- schemaName?: string
602
- operationId?: string
603
- signal?: AbortSignal
604
- }): Promise<{
605
- processed: number
606
- }>;
607
470
  import { AbiContract as AbiContract3, ExtractFunctionArgs as ExtractFunctionArgs2, ExtractFunctionNames } from "@secondlayer/stacks/clarity";
608
471
  /** Maps a ColumnType string literal to its TypeScript equivalent */
609
472
  type ColumnToTS<T extends string> = T extends "uint" | "int" ? bigint : T extends "text" | "principal" | "timestamp" ? string : T extends "boolean" ? boolean : T extends "jsonb" ? Record<string, unknown> : unknown;
@@ -758,8 +621,6 @@ type WriteColumnType<C extends SubgraphColumn> = C["type"] extends "uint" | "int
758
621
  * defaulted columns are optional; all others required.
759
622
  */
760
623
  type WriteRow<T extends SubgraphTable> = { [K in keyof T["columns"] as IsOptionalColumn<T["columns"][K]> extends true ? never : K] : WriteColumnType<T["columns"][K]> } & { [K in keyof T["columns"] as IsOptionalColumn<T["columns"][K]> extends true ? K : never]? : WriteColumnType<T["columns"][K]> };
761
- /** Computed-or-value row for `patchOrInsert` — each field may be a function of the existing row. */
762
- type PatchRow<T extends SubgraphTable> = { [K in keyof WriteRow<T>]? : WriteRow<T>[K] | ((existing: InferTableRow<T> | null) => unknown) };
763
624
  type TableName<S extends SubgraphSchema> = keyof S & string;
764
625
  type ColumnName<
765
626
  S extends SubgraphSchema,
@@ -799,8 +660,6 @@ interface TypedSubgraphContext<S extends SubgraphSchema> {
799
660
  K extends Partial<WriteRow<S[T]>>
800
661
  >(table: T, key: K, row: Omit<WriteRow<S[T]>, keyof K> & Partial<WriteRow<S[T]>>): void;
801
662
  delete<T extends TableName<S>>(table: T, where: RowWhere<S, T>): void;
802
- patch<T extends TableName<S>>(table: T, where: RowWhere<S, T>, set: Partial<WriteRow<S[T]>>): void;
803
- patchOrInsert<T extends TableName<S>>(table: T, key: Partial<WriteRow<S[T]>>, row: PatchRow<S[T]> & Record<string, ComputedValue>): Promise<void>;
804
663
  /**
805
664
  * Atomic accumulator — `INSERT … ON CONFLICT (key) DO UPDATE SET col =
806
665
  * COALESCE(col,0) + delta`. Deltas commute, so it's the reorg-safe primitive
@@ -810,12 +669,6 @@ interface TypedSubgraphContext<S extends SubgraphSchema> {
810
669
  increment<T extends TableName<S>>(table: T, key: Partial<WriteRow<S[T]>>, deltas: Partial<Record<ColumnName<S, T>, bigint | number>>): void;
811
670
  findOne<T extends TableName<S>>(table: T, where: RowWhere<S, T>): Promise<InferTableRow<S[T]> | null>;
812
671
  findMany<T extends TableName<S>>(table: T, where: RowWhere<S, T>): Promise<InferTableRow<S[T]>[]>;
813
- formatUnits(value: bigint, decimals: number): string;
814
- count<T extends TableName<S>>(table: T, where?: RowWhere<S, T>): Promise<number>;
815
- sum<T extends TableName<S>>(table: T, column: ColumnName<S, T>, where?: RowWhere<S, T>): Promise<bigint>;
816
- min<T extends TableName<S>>(table: T, column: ColumnName<S, T>, where?: RowWhere<S, T>): Promise<bigint | null>;
817
- max<T extends TableName<S>>(table: T, column: ColumnName<S, T>, where?: RowWhere<S, T>): Promise<bigint | null>;
818
- countDistinct<T extends TableName<S>>(table: T, column: ColumnName<S, T>, where?: RowWhere<S, T>): Promise<number>;
819
672
  }
820
673
  /** Infer a typed client object from a subgraph definition shape */
821
674
  type InferSubgraphClient<T> = T extends {
@@ -1015,29 +868,22 @@ type EventForFilter<F extends SubgraphFilter> = F extends {
1015
868
  } ? VarSetPayload : F extends {
1016
869
  type: infer T extends "map_set" | "map_insert" | "map_delete"
1017
870
  } ? T extends "map_delete" ? MapDeletePayload : MapWritePayload : never;
1018
- /** Union of every event payload — the `"*"` catch-all handler receives this. */
871
+ /** Union of every event payload. */
1019
872
  type AnyEvent = FtTransferPayload | FtMintPayload | FtBurnPayload | NftTransferPayload | NftMintPayload | NftBurnPayload | StxTransferPayload | StxMintPayload | StxBurnPayload | StxLockPayload | PrintEventPayload | ContractCallEvent | ContractDeployPayload | NestedContractCallPayload | VarSetPayload | MapWritePayload | MapDeletePayload;
1020
873
  type HandlerFn<
1021
874
  F extends SubgraphFilter,
1022
875
  S extends SubgraphSchema
1023
876
  > = (event: EventForFilter<F>, ctx: TypedSubgraphContext<S>) => void | Promise<void>;
1024
- type SourceHasMaterialize<F> = F extends {
1025
- materialize: MaterializeSpec
1026
- } ? true : false;
1027
877
  /**
1028
- * Handlers keyed by source name. Each handler's `event` is typed from the
1029
- * matching source's filter `type` (e.g. a `print_event` source → `event.topic`
1030
- * is a `string`), and `ctx` is typed against the subgraph `schema` (table
1031
- * names + row columns checked). Sources with `materialize` may omit a
1032
- * handler; every other source key is required. Optional `"*"` catch-all
1033
- * receives any event (validate also accepts `*` alone).
878
+ * Handlers keyed by source name, one per source. Each handler's `event` is
879
+ * typed from the matching source's filter `type` (e.g. a `print_event` source
880
+ * gives `event.topic: string`), and `ctx` is typed against the subgraph
881
+ * `schema` (table names + row columns checked).
1034
882
  */
1035
883
  type TypedHandlers<
1036
884
  Sources extends Record<string, SubgraphFilter>,
1037
885
  S extends SubgraphSchema
1038
- > = { [K in keyof Sources as SourceHasMaterialize<Sources[K]> extends true ? never : K]-? : HandlerFn<Sources[K], S> } & { [K in keyof Sources as SourceHasMaterialize<Sources[K]> extends true ? K : never]? : HandlerFn<Sources[K], S> } & {
1039
- "*"?: (event: AnyEvent, ctx: TypedSubgraphContext<S>) => void | Promise<void>
1040
- };
886
+ > = { [K in keyof Sources]-? : HandlerFn<Sources[K], S> };
1041
887
  /** Subgraph definition with `sources`/`schema` literals preserved for typed
1042
888
  * handlers and downstream query-client inference (`getSubgraph`). */
1043
889
  type TypedSubgraphDefinition<
@@ -1113,6 +959,20 @@ declare function defineSchema<const S extends SubgraphSchema>(schema: S): S;
1113
959
  type InferContext<D> = D extends {
1114
960
  schema: infer S extends SubgraphSchema
1115
961
  } ? TypedSubgraphContext<S> : never;
962
+ /**
963
+ * Validates a subgraph definition, returning the parsed result or throwing on failure.
964
+ */
965
+ declare function validateSubgraphDefinition(def: unknown): SubgraphDefinition;
966
+ /**
967
+ * Per-source-type field vocabulary, DERIVED from
968
+ * {@link SubgraphFilterSchema}. Agent-facing surfaces (the MCP filters
969
+ * reference) used to hand-maintain a parallel copy of this list; deriving it
970
+ * means adding a field to a filter can never leave the documentation behind.
971
+ */
972
+ declare function filterFieldsByType(): Array<{
973
+ type: string
974
+ fields: string[]
975
+ }>;
1116
976
  type PrintValidationResult = {
1117
977
  ok: true
1118
978
  } | {
@@ -1120,12 +980,6 @@ type PrintValidationResult = {
1120
980
  reason: string
1121
981
  };
1122
982
  /**
1123
- * Validate one decoded print event against a source's `prints` declaration.
1124
- * Returns `{ ok: true }` when no declaration covers this topic (undeclared
1125
- * topics are not the developer's stated contract, so they pass through).
1126
- */
1127
- declare function validatePrintPayload(prints: Record<string, Record<string, PrintField>> | undefined, topic: string, data: Record<string, unknown>): PrintValidationResult;
1128
- /**
1129
983
  * Empirical print-payload schema inference. Callers (the index print-schema
1130
984
  * endpoint) extract topic + raw Clarity hex per row; this module deserializes
1131
985
  * a bounded sample per topic, unifies the observed value shapes into a single
@@ -1159,13 +1013,6 @@ interface InferredTopicSchema {
1159
1013
  non_tuple: boolean;
1160
1014
  fields: InferredPrintField[];
1161
1015
  }
1162
- /**
1163
- * Kebab-case → camelCase for print tuple keys. Canonical: the runner uses
1164
- * this on `event.data`, and `camel_name` in inferred print schema is the
1165
- * same function. Distinct from ABI `toCamelCase` (`transfer-STX` stays
1166
- * `transfer-STX` here, becomes `transferSTX` there).
1167
- */
1168
- declare function camelizeDataKey(str: string): string;
1169
1016
  /** Recursively camelize object keys with the print-payload helper (not ABI
1170
1017
  * `toCamelCase` — that one strips `-STX` and prefixes leading digits). */
1171
1018
  declare function camelizeKeys(obj: unknown): unknown;
@@ -1229,12 +1076,10 @@ interface IndexCodegenOptions {
1229
1076
  datasourceEnv?: string;
1230
1077
  }
1231
1078
  declare function generateIndexSchema(target: IndexCodegenTarget, opts?: IndexCodegenOptions): string;
1232
- /** Index tables available to codegen, for help text and validation. */
1233
- declare const INDEX_CODEGEN_TABLES: readonly string[];
1234
1079
  import { pgSchemaName } from "@secondlayer/shared/db/queries/subgraphs";
1235
- import { Database as Database3 } from "@secondlayer/shared/db";
1236
- import { Kysely as Kysely3 } from "kysely";
1237
- type AnyDb = Kysely3<Database3>;
1080
+ import { Database as Database2 } from "@secondlayer/shared/db";
1081
+ import { Kysely as Kysely2 } from "kysely";
1082
+ type AnyDb = Kysely2<Database2>;
1238
1083
  interface TableDiff {
1239
1084
  /** Tables added to the schema */
1240
1085
  addedTables: string[];
@@ -1316,7 +1161,6 @@ declare function deploySchema(db: AnyDb, def: SubgraphDefinition, handlerPath: s
1316
1161
  apiKeyId?: string
1317
1162
  accountId?: string
1318
1163
  schemaName?: string
1319
- version?: string
1320
1164
  handlerCode?: string
1321
1165
  sourceCode?: string
1322
1166
  }): Promise<{
@@ -1327,4 +1171,30 @@ declare function deploySchema(db: AnyDb, def: SubgraphDefinition, handlerPath: s
1327
1171
  /** Non-fatal caveats the caller should surface (e.g. handler grafts at tip). */
1328
1172
  warnings?: string[]
1329
1173
  }>;
1330
- export { validateSubgraphDefinition, validatePrintPayload, sparseProbeTargets, resumeReindex, renderDeployPlan, reindexSubgraph, readContractAt, pgSchemaName, inferPrintTopics, hasBreakingChanges, generateSubgraphSQL, generatePrismaSchema, generateKyselySchema, generateIndexSchema, generateDrizzleSchema, filterFieldsByType, diffSchema, deploySchema, defineSubgraph, defineSchema, canSparseScan, camelizeKeys, camelizeDataKey, backfillSubgraph, WriteRow, WhereInput, VarSetPayload, UnpinnedPrintEventFilter, TypedSubgraphDefinition, TypedSubgraphContext, TypedHandlers, TxMeta, TraitPrintEventFilter, TableDiff, SystemRow, SubscribeOptions, SubgraphTableClient, SubgraphTable, SubgraphSchema, SubgraphHandler, SubgraphFilter, SubgraphDefinition, SubgraphContext, SubgraphColumn, StxTransferPayload, StxTransferFilter, StxMintPayload, StxMintFilter, StxLockPayload, StxLockFilter, StxBurnPayload, StxBurnFilter, SparseProbeTarget, RowValue, ReindexOptions, PrismaGenOptions, PrintValidationResult, PrintSample, PrintFieldToTS, PrintField, PrintEventPrints, PrintEventPayload, PrintEventFor, PrintEventFilter, PrintDataOf, PinnedPrintEventFilter, NftTransferPayload, NftTransferFilter, NftMintPayload, NftMintFilter, NftBurnPayload, NftBurnFilter, NestedContractCallPayload, MaterializeSpec, MaterializeColumn, MapWritePayload, MapDeletePayload, KyselyGenOptions, InferredTopicSchema, InferredPrintField, InferTableRow, InferSubgraphClient, InferContext, InferColumnType, IndexCodegenTarget, IndexCodegenOptions, INDEX_CODEGEN_TABLES, GeneratedSQL, FtTransferPayload, FtTransferFilter, FtMintPayload, FtMintFilter, FtBurnPayload, FtBurnFilter, FindManyOptions, FactoryScope, EventForFilter, ErasedChainReadClient, DrizzleGenOptions, DeployPlan, DeployDiff, ContractDeployPayload, ContractDeployFilter, ContractCallPayload, ContractCallFilter, ContractCallEvent, ComputedValue, ComparisonFilter, ColumnType, ColumnToTS, ColumnDiff, ChainReadOptions, ChainReadMethods, ChainReadError, ChainReadClient, ChainReadCacheMode, AnyEvent, AggregateSpec, AggregateResult };
1174
+ /** A (decoded event type, optional contract scope) pair the sparse probe
1175
+ * checks. Contract scoping is what makes token-subgraph reindexes leap over
1176
+ * everything that isn't their token. */
1177
+ type SparseProbeTarget = {
1178
+ eventType: string
1179
+ contractId?: string
1180
+ };
1181
+ /** Sparse scanning is sound only when EVERY source is an event-type filter —
1182
+ * a contract_call/contract_deploy source matches transactions, which the
1183
+ * event probe can't see. */
1184
+ declare function canSparseScan(subgraph: SubgraphDefinition): boolean;
1185
+ /** Probe targets for a subgraph's filters: decoded type + contract scope when\\n* the filter pins one (assetIdentifier "SP….contract::asset" or contractId). */
1186
+ declare function sparseProbeTargets(subgraph: SubgraphDefinition): SparseProbeTarget[];
1187
+ interface ReindexOptions {
1188
+ /**
1189
+ * Floor on the walk's first block — NOT a caller-supplied range. When set
1190
+ * (e.g. an op row carrying a `from_block`), it raises the walk start and
1191
+ * can never lower it. There is deliberately no `toBlock` counterpart:
1192
+ * a reindex always runs to chain tip. See {@link resolveBlockRange}.
1193
+ */
1194
+ startBlockFloor?: number;
1195
+ schemaName?: string;
1196
+ /** Op row to receive processed_events on each progress flush. */
1197
+ operationId?: string;
1198
+ signal?: AbortSignal;
1199
+ }
1200
+ export { AggregateResult, AggregateSpec, AnyEvent, ChainReadCacheMode, ChainReadClient, ChainReadError, ChainReadMethods, ChainReadOptions, ColumnDiff, ColumnToTS, ColumnType, ComparisonFilter, ContractCallEvent, ContractCallFilter, ContractCallPayload, ContractDeployFilter, ContractDeployPayload, DeployDiff, DeployPlan, DrizzleGenOptions, ErasedChainReadClient, EventForFilter, FactoryScope, FindManyOptions, FtBurnFilter, FtBurnPayload, FtMintFilter, FtMintPayload, FtTransferFilter, FtTransferPayload, GeneratedSQL, IndexCodegenOptions, IndexCodegenTarget, InferColumnType, InferContext, InferSubgraphClient, InferTableRow, InferredPrintField, InferredTopicSchema, KyselyGenOptions, MapDeletePayload, MapWritePayload, NestedContractCallPayload, NftBurnFilter, NftBurnPayload, NftMintFilter, NftMintPayload, NftTransferFilter, NftTransferPayload, PinnedPrintEventFilter, PrintDataOf, PrintEventFilter, PrintEventFor, PrintEventPayload, PrintEventPrints, PrintField, PrintFieldToTS, PrintSample, PrintValidationResult, PrismaGenOptions, ReindexOptions, RowValue, SparseProbeTarget, StxBurnFilter, StxBurnPayload, StxLockFilter, StxLockPayload, StxMintFilter, StxMintPayload, StxTransferFilter, StxTransferPayload, SubgraphColumn, SubgraphContext, SubgraphDefinition, SubgraphFilter, SubgraphHandler, SubgraphSchema, SubgraphTable, SubgraphTableClient, SubscribeOptions, SystemRow, TableDiff, TraitPrintEventFilter, TxMeta, TypedHandlers, TypedSubgraphContext, TypedSubgraphDefinition, UnpinnedPrintEventFilter, VarSetPayload, WhereInput, WriteRow, camelizeKeys, canSparseScan, defineSchema, defineSubgraph, deploySchema, diffSchema, filterFieldsByType, generateDrizzleSchema, generateIndexSchema, generateKyselySchema, generatePrismaSchema, generateSubgraphSQL, hasBreakingChanges, inferPrintTopics, pgSchemaName, readContractAt, renderDeployPlan, sparseProbeTargets, validateSubgraphDefinition };