@secondlayer/subgraphs 3.20.0 → 3.22.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 +188 -16
  2. package/dist/src/index.js +369 -41
  3. package/dist/src/index.js.map +12 -11
  4. package/dist/src/runtime/block-processor.d.ts +100 -13
  5. package/dist/src/runtime/block-processor.js +208 -22
  6. package/dist/src/runtime/block-processor.js.map +9 -8
  7. package/dist/src/runtime/catchup.d.ts +100 -13
  8. package/dist/src/runtime/catchup.js +208 -22
  9. package/dist/src/runtime/catchup.js.map +9 -8
  10. package/dist/src/runtime/context.d.ts +34 -8
  11. package/dist/src/runtime/context.js +25 -12
  12. package/dist/src/runtime/context.js.map +4 -4
  13. package/dist/src/runtime/processor.js +213 -22
  14. package/dist/src/runtime/processor.js.map +10 -9
  15. package/dist/src/runtime/reindex.d.ts +100 -13
  16. package/dist/src/runtime/reindex.js +208 -22
  17. package/dist/src/runtime/reindex.js.map +9 -8
  18. package/dist/src/runtime/reorg.d.ts +100 -13
  19. package/dist/src/runtime/reorg.js +213 -22
  20. package/dist/src/runtime/reorg.js.map +10 -9
  21. package/dist/src/runtime/replay.js +29 -6
  22. package/dist/src/runtime/replay.js.map +3 -3
  23. package/dist/src/runtime/runner.d.ts +125 -17
  24. package/dist/src/runtime/runner.js +100 -3
  25. package/dist/src/runtime/runner.js.map +5 -4
  26. package/dist/src/runtime/source-matcher.d.ts +98 -11
  27. package/dist/src/runtime/source-matcher.js +30 -6
  28. package/dist/src/runtime/source-matcher.js.map +3 -3
  29. package/dist/src/schema/index.d.ts +100 -13
  30. package/dist/src/schema/index.js +171 -20
  31. package/dist/src/schema/index.js.map +5 -5
  32. package/dist/src/service.js +213 -22
  33. package/dist/src/service.js.map +10 -9
  34. package/dist/src/testing/index.d.ts +620 -0
  35. package/dist/src/testing/index.js +1297 -0
  36. package/dist/src/testing/index.js.map +16 -0
  37. package/dist/src/triggers/index.d.ts +87 -9
  38. package/dist/src/types.d.ts +101 -14
  39. package/dist/src/validate.d.ts +136 -14
  40. package/dist/src/validate.js +158 -19
  41. package/dist/src/validate.js.map +3 -3
  42. package/package.json +7 -5
@@ -25,15 +25,24 @@ interface SubgraphRelation {
25
25
  /** Target column(s) the fields point at (a uniqueKeys entry on the target). */
26
26
  referencedColumns: string[];
27
27
  }
28
- /** Table definition within a subgraph schema */
28
+ /**
29
+ * Table definition within a subgraph schema.
30
+ *
31
+ * The array fields are `readonly` so a schema literal can be hoisted out of
32
+ * the `defineSubgraph()` call with `as const` (or {@link defineSchema}) and
33
+ * still typecheck — `as const` produces `readonly [readonly ["holder"]]`,
34
+ * which a mutable `string[][]` rejects. Without that, extracting a helper
35
+ * that takes `ctx` meant losing the entire typed surface, which is why the
36
+ * shipped starter reached for `ctx: any`.
37
+ */
29
38
  interface SubgraphTable {
30
39
  columns: Record<string, SubgraphColumn>;
31
40
  /** Composite indexes (each entry is an array of column names) */
32
- indexes?: string[][];
41
+ indexes?: readonly (readonly string[])[];
33
42
  /** Unique key constraints (each entry is an array of column names). Required for upsert. */
34
- uniqueKeys?: string[][];
43
+ uniqueKeys?: readonly (readonly string[])[];
35
44
  /** Foreign-key relations to other tables (for typed ORM joins). */
36
- relations?: SubgraphRelation[];
45
+ relations?: readonly SubgraphRelation[];
37
46
  }
38
47
  /** Subgraph schema — maps table names to table definitions */
39
48
  type SubgraphSchema = Record<string, SubgraphTable>;
@@ -68,6 +77,45 @@ interface StxLockFilter {
68
77
  type TraitScope = {
69
78
  trait?: string
70
79
  };
80
+ /**
81
+ * Scope a source to a DYNAMIC address set discovered from another source's
82
+ * events, instead of a fixed contract list.
83
+ *
84
+ * The standard shape it unlocks: a router plus pools created after you
85
+ * deploy. `contractId` arrays cover a set you know at authoring time; a
86
+ * factory covers the set that grows. It is deliberately NOT tied to contract
87
+ * deployment — the address can come from any field of any event, so it also
88
+ * covers launchpad-minted tokens, DAO extension allowlists, and registry
89
+ * entries.
90
+ *
91
+ * ```ts
92
+ * sources: {
93
+ * registry: { type: "print_event", contractId: REGISTRY, topic: "pool-created" },
94
+ * swaps: {
95
+ * type: "print_event",
96
+ * topic: "swap",
97
+ * // every pool the registry has ever announced, including new ones
98
+ * factory: { from: "registry", field: "data.pool" },
99
+ * },
100
+ * }
101
+ * ```
102
+ *
103
+ * Two guarantees the runtime provides:
104
+ * - **Same-block ordering** — a contract discovered in block N receives its
105
+ * own block-N events. Discovery runs before matching, within the block.
106
+ * - **Reorg-scoped** — the discovered set is stamped with the block that
107
+ * revealed it and rolled back with everything else on a fork, so an address
108
+ * announced on an orphaned chain does not linger forever.
109
+ */
110
+ interface FactoryScope {
111
+ factory?: {
112
+ /** Source name whose events reveal the addresses. */
113
+ from: string
114
+ /** Dotted path to the address on that source's payload
115
+ * (e.g. `"data.pool"`, `"contractId"`, `"data.token.id"`). */
116
+ field: string
117
+ };
118
+ }
71
119
  /** FT event filters */
72
120
  interface FtTransferFilter extends TraitScope {
73
121
  type: "ft_transfer";
@@ -147,9 +195,19 @@ interface ContractCallEvent {
147
195
  };
148
196
  }
149
197
  /** Contract event filters */
150
- interface ContractCallFilter extends TraitScope {
198
+ interface ContractCallFilter extends TraitScope, FactoryScope {
151
199
  type: "contract_call";
152
- contractId?: string;
200
+ /**
201
+ * One contract id, or a SET of them (max 20) — the standard DeFi shape is
202
+ * a router plus N pools, which used to cost N near-identical sources and
203
+ * handlers, or the `"*"` catch-all that erases per-source typing. Payload
204
+ * types are identical per `type`, so one handler serves the set and
205
+ * `event.contractId` disambiguates.
206
+ *
207
+ * Supports `*` wildcards (e.g. `"SP1ABC….pool-*"`). Mutually exclusive
208
+ * with `trait`, which resolves its own set per block.
209
+ */
210
+ contractId?: string | readonly string[];
153
211
  functionName?: string;
154
212
  caller?: string;
155
213
  /**
@@ -165,18 +223,47 @@ interface ContractDeployFilter {
165
223
  deployer?: string;
166
224
  contractName?: string;
167
225
  }
168
- interface PrintEventFilter extends TraitScope {
226
+ /**
227
+ * One declared field of a print payload.
228
+ *
229
+ * A bare {@link ColumnType} is a required scalar (`amount: "uint"`). The
230
+ * composite forms exist because real print payloads are not flat: BNS-V2
231
+ * emits `name` as a NESTED tuple, and a `prints` vocabulary that could only
232
+ * say `"jsonb"` is why a handler reading flat `data.name` type-checked,
233
+ * deployed, and then decoded to null on every event.
234
+ *
235
+ * - `{ type: F, optional: true }` — the KEY becomes optional on `event.data`
236
+ * (mirrors `always_present: false` in the inferred schema).
237
+ * - `{ tuple: { … } }` — a nested tuple, typed all the way down.
238
+ * - `{ list: F }` — a list of `F`.
239
+ */
240
+ type PrintField = ColumnType | {
241
+ type: PrintField
242
+ optional: true
243
+ } | {
244
+ tuple: Record<string, PrintField>
245
+ } | {
246
+ list: PrintField
247
+ };
248
+ interface PrintEventFilter extends TraitScope, FactoryScope {
169
249
  type: "print_event";
170
- contractId?: string;
250
+ /** One contract id, or a set of them (max 20). Supports `*` wildcards.
251
+ * Mutually exclusive with `trait`. */
252
+ contractId?: string | readonly string[];
171
253
  topic?: string;
172
254
  /**
173
- * Optional per-topic field schema. When declared, the handler's `event` is
174
- * a discriminated union keyed by `topic` and `event.data` is typed per topic
255
+ * Per-topic field schema. When declared, the handler's `event` is a
256
+ * discriminated union keyed by `topic` and `event.data` is typed per topic
175
257
  * (e.g. `{ "completed-deposit": { amount: "uint", sender: "principal" } }`).
176
- * Uses the same `ColumnType` vocab as `schema`; nested fields use `"jsonb"`.
177
- * Type-level only — not validated at runtime.
258
+ * Nested tuples, lists, and optional fields are expressible — see
259
+ * {@link PrintField}.
260
+ *
261
+ * Declaring `prints` also opts the source into RUNTIME validation: an
262
+ * event whose decoded payload does not match is skipped and logged rather
263
+ * than written as nulls (and the deploy-time field lint is promoted from
264
+ * a warning to an error).
178
265
  */
179
- prints?: Record<string, Record<string, ColumnType>>;
266
+ prints?: Record<string, Record<string, PrintField>>;
180
267
  }
181
268
  /** All subgraph filter types — discriminated on `type` */
182
269
  type SubgraphFilter = StxTransferFilter | StxMintFilter | StxBurnFilter | StxLockFilter | FtTransferFilter | FtMintFilter | FtBurnFilter | NftTransferFilter | NftMintFilter | NftBurnFilter | ContractCallFilter | ContractDeployFilter | PrintEventFilter;
@@ -258,6 +345,16 @@ interface SubgraphDefinition {
258
345
  * Validates a subgraph definition, returning the parsed result or throwing on failure.
259
346
  */
260
347
  declare function validateSubgraphDefinition(def: unknown): SubgraphDefinition;
348
+ /**
349
+ * Per-source-type field vocabulary, DERIVED from
350
+ * {@link SubgraphFilterSchema}. Agent-facing surfaces (the MCP filters
351
+ * reference) used to hand-maintain a parallel copy of this list; deriving it
352
+ * means adding a field to a filter can never leave the documentation behind.
353
+ */
354
+ declare function filterFieldsByType(): Array<{
355
+ type: string
356
+ fields: string[]
357
+ }>;
261
358
  interface ReindexOptions {
262
359
  fromBlock?: number;
263
360
  toBlock?: number;
@@ -604,13 +701,34 @@ type ContractCallPayload<F> = F extends {
604
701
  * per topic; otherwise it falls back to the untyped {@link PrintEventPayload}.
605
702
  */
606
703
  type PrintEventFor<F> = F extends {
607
- prints: infer P extends Record<string, Record<string, ColumnType>>
704
+ prints: infer P extends Record<string, Record<string, PrintField>>
608
705
  } ? { [K in keyof P] : {
609
706
  contractId: string
610
707
  topic: K
611
- data: { [Field in keyof P[K]] : ColumnToTS<P[K][Field]> }
708
+ data: PrintDataOf<P[K]>
612
709
  tx: TxMeta
613
710
  } }[keyof P] : PrintEventPayload;
711
+ /** TS type of one declared print field (nested tuples and lists included). */
712
+ type PrintFieldToTS<F> = F extends ColumnType ? ColumnToTS<F> : F extends {
713
+ type: infer Inner
714
+ optional: true
715
+ } ? PrintFieldToTS<Inner> : F extends {
716
+ tuple: infer T extends Record<string, PrintField>
717
+ } ? PrintDataOf<T> : F extends {
718
+ list: infer Item
719
+ } ? PrintFieldToTS<Item>[] : unknown;
720
+ type OptionalFieldKeys<T> = { [K in keyof T] : T[K] extends {
721
+ optional: true
722
+ } ? K : never }[keyof T];
723
+ /** Collapse an intersection into one object literal, so hovering `event.data`
724
+ * shows the fields rather than `A & B`. */
725
+ type Flatten<T> = { [K in keyof T] : T[K] } & {};
726
+ /**
727
+ * `event.data` for one topic: declared fields typed, with
728
+ * `{ optional: true }` fields made optional KEYS (a field observed on only
729
+ * some events must not be typed as always present).
730
+ */
731
+ type PrintDataOf<T extends Record<string, PrintField>> = Flatten<{ [K in Exclude<keyof T, OptionalFieldKeys<T>>] : PrintFieldToTS<T[K]> } & { [K in OptionalFieldKeys<T>]? : PrintFieldToTS<T[K]> }>;
614
732
  /** The event payload a handler receives for a given source filter. */
615
733
  type EventForFilter<F extends SubgraphFilter> = F extends {
616
734
  type: "print_event"
@@ -690,6 +808,60 @@ declare function defineSubgraph<
690
808
  const S extends SubgraphSchema
691
809
  >(def: TypedSubgraphDefinition<Sources, S>): TypedSubgraphDefinition<Sources, S>;
692
810
  /**
811
+ * Identity helper that preserves a schema literal's exact types so it can be
812
+ * HOISTED out of the `defineSubgraph()` call and reused:
813
+ *
814
+ * ```ts
815
+ * const schema = defineSchema({
816
+ * balances: {
817
+ * columns: { holder: { type: "principal" }, amount: { type: "uint" } },
818
+ * uniqueKeys: [["holder"]],
819
+ * },
820
+ * });
821
+ *
822
+ * // An extracted helper keeps the full typed surface — table names and row
823
+ * // columns are still checked:
824
+ * function credit(ctx: TypedSubgraphContext<typeof schema>, holder: string) {
825
+ * ctx.increment("balances", { holder }, { amount: 1n });
826
+ * }
827
+ *
828
+ * defineSubgraph({ name: "balances", schema, sources, handlers });
829
+ * ```
830
+ *
831
+ * `as const` alone does not work here (it produces `readonly` arrays that a
832
+ * mutable `uniqueKeys` rejected) and a bare literal widens `type` to `string`.
833
+ * That gap is why the shipped starter typed its helper `ctx: any` — and in
834
+ * doing so modelled a non-commutative read-modify-write the docs warn against.
835
+ */
836
+ declare function defineSchema<const S extends SubgraphSchema>(schema: S): S;
837
+ /**
838
+ * The typed handler context for a subgraph definition — for annotating
839
+ * helpers extracted out of a handler:
840
+ *
841
+ * ```ts
842
+ * const def = defineSubgraph({ … });
843
+ * function credit(ctx: InferContext<typeof def>) { … }
844
+ * ```
845
+ *
846
+ * Prefer `TypedSubgraphContext<typeof schema>` when the schema is hoisted;
847
+ * this is the form for when only the definition is in scope.
848
+ */
849
+ type InferContext<D> = D extends {
850
+ schema: infer S extends SubgraphSchema
851
+ } ? TypedSubgraphContext<S> : never;
852
+ type PrintValidationResult = {
853
+ ok: true
854
+ } | {
855
+ ok: false
856
+ reason: string
857
+ };
858
+ /**
859
+ * Validate one decoded print event against a source's `prints` declaration.
860
+ * Returns `{ ok: true }` when no declaration covers this topic (undeclared
861
+ * topics are not the developer's stated contract, so they pass through).
862
+ */
863
+ declare function validatePrintPayload(prints: Record<string, Record<string, PrintField>> | undefined, topic: string, data: Record<string, unknown>): PrintValidationResult;
864
+ /**
693
865
  * Empirical print-payload schema inference. Callers (the index print-schema
694
866
  * endpoint) extract topic + raw Clarity hex per row; this module deserializes
695
867
  * a bounded sample per topic, unifies the observed value shapes into a single
@@ -928,4 +1100,4 @@ type SparseProbeTarget = {
928
1100
  declare function canSparseScan(subgraph: SubgraphDefinition): boolean;
929
1101
  /** Probe targets for a subgraph's filters: decoded type + contract scope when\\n* the filter pins one (assetIdentifier "SP….contract::asset" or contractId). */
930
1102
  declare function sparseProbeTargets(subgraph: SubgraphDefinition): SparseProbeTarget[];
931
- export { validateSubgraphDefinition, sparseProbeTargets, resumeReindex, renderDeployPlan, reindexSubgraph, pgSchemaName, inferPrintTopics, hasBreakingChanges, generateSubgraphSQL, generatePrismaSchema, generateKyselySchema, generateIndexSchema, generateDrizzleSchema, diffSchema, deploySchema, defineSubgraph, canSparseScan, camelizeDataKey, backfillSubgraph, WriteRow, WhereInput, TypedSubgraphDefinition, TypedSubgraphContext, TypedHandlers, TxMeta, TableDiff, SystemRow, SubscribeOptions, SubgraphTableClient, SubgraphTable, SubgraphSchema, SubgraphHandler, SubgraphFilter, SubgraphDefinition, SubgraphContext, SubgraphColumn, StxTransferPayload, StxTransferFilter, StxMintPayload, StxMintFilter, StxLockPayload, StxLockFilter, StxBurnPayload, StxBurnFilter, SparseProbeTarget, RowValue, ReindexOptions, PrismaGenOptions, PrintSample, PrintEventPayload, PrintEventFor, PrintEventFilter, NftTransferPayload, NftTransferFilter, NftMintPayload, NftMintFilter, NftBurnPayload, NftBurnFilter, KyselyGenOptions, InferredTopicSchema, InferredPrintField, InferTableRow, InferSubgraphClient, InferColumnType, IndexCodegenTarget, IndexCodegenOptions, INDEX_CODEGEN_TABLES, GeneratedSQL, FtTransferPayload, FtTransferFilter, FtMintPayload, FtMintFilter, FtBurnPayload, FtBurnFilter, FindManyOptions, EventForFilter, DrizzleGenOptions, DeployPlan, DeployDiff, ContractDeployPayload, ContractDeployFilter, ContractCallPayload, ContractCallFilter, ContractCallEvent, ComputedValue, ComparisonFilter, ColumnType, ColumnToTS, ColumnDiff, ByoMigrationPlan, ByoBreakingChangeError, AnyEvent, AggregateSpec, AggregateResult };
1103
+ export { validateSubgraphDefinition, validatePrintPayload, sparseProbeTargets, resumeReindex, renderDeployPlan, reindexSubgraph, pgSchemaName, inferPrintTopics, hasBreakingChanges, generateSubgraphSQL, generatePrismaSchema, generateKyselySchema, generateIndexSchema, generateDrizzleSchema, filterFieldsByType, diffSchema, deploySchema, defineSubgraph, defineSchema, canSparseScan, camelizeDataKey, backfillSubgraph, WriteRow, WhereInput, TypedSubgraphDefinition, TypedSubgraphContext, TypedHandlers, TxMeta, 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, PrintEventPayload, PrintEventFor, PrintEventFilter, PrintDataOf, NftTransferPayload, NftTransferFilter, NftMintPayload, NftMintFilter, NftBurnPayload, NftBurnFilter, KyselyGenOptions, InferredTopicSchema, InferredPrintField, InferTableRow, InferSubgraphClient, InferContext, InferColumnType, IndexCodegenTarget, IndexCodegenOptions, INDEX_CODEGEN_TABLES, GeneratedSQL, FtTransferPayload, FtTransferFilter, FtMintPayload, FtMintFilter, FtBurnPayload, FtBurnFilter, FindManyOptions, FactoryScope, EventForFilter, DrizzleGenOptions, DeployPlan, DeployDiff, ContractDeployPayload, ContractDeployFilter, ContractCallPayload, ContractCallFilter, ContractCallEvent, ComputedValue, ComparisonFilter, ColumnType, ColumnToTS, ColumnDiff, ByoMigrationPlan, ByoBreakingChangeError, AnyEvent, AggregateSpec, AggregateResult };