@secondlayer/subgraphs 6.4.0 → 6.5.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.
package/dist/types.d.ts CHANGED
@@ -16,7 +16,7 @@ import { AssetIdentifier } from "@secondlayer/stacks/filters";
16
16
  */
17
17
  type ChainReadCacheMode = "per-block" | "contract-constant";
18
18
  type ChainReadOptions = {
19
- cache?: ChainReadCacheMode
19
+ cache?: ChainReadCacheMode;
20
20
  };
21
21
  /**
22
22
  * `ChainReadClient` with the ABI generic erased. Structurally cheap, so the
@@ -25,7 +25,7 @@ type ChainReadOptions = {
25
25
  */
26
26
  interface ErasedChainReadClient {
27
27
  contract(contractId: string, abi: unknown, options?: ChainReadOptions): {
28
- read: Record<string, (args?: Record<string, unknown>) => Promise<unknown>>
28
+ read: Record<string, (args?: Record<string, unknown>) => Promise<unknown>>;
29
29
  };
30
30
  }
31
31
  /** Supported column types for subgraph schemas */
@@ -86,7 +86,7 @@ interface StxLockFilter {
86
86
  * as-of each processed block. Lets a source index "all SIP-010 tokens" etc.
87
87
  */
88
88
  type TraitScope = {
89
- trait?: string
89
+ trait?: string;
90
90
  };
91
91
  /**
92
92
  * Scope a source to a DYNAMIC address set discovered from another source's
@@ -126,10 +126,10 @@ type TraitScope = {
126
126
  interface FactoryScope {
127
127
  factory?: {
128
128
  /** Source name whose events reveal the addresses. */
129
- from: string
129
+ from: string;
130
130
  /** Dotted path to the address on that source's payload
131
131
  * (e.g. `"data.pool"`, `"contractId"`, `"data.token.id"`). */
132
- field: string
132
+ field: string;
133
133
  };
134
134
  }
135
135
  /** FT event filters */
@@ -202,12 +202,12 @@ interface ContractCallEvent {
202
202
  resultHex: string | null;
203
203
  /** Transaction metadata. */
204
204
  tx: {
205
- txId: string
206
- sender: string
207
- type: string
208
- status: string
209
- contractId: string | null
210
- functionName: string | null
205
+ txId: string;
206
+ sender: string;
207
+ type: string;
208
+ status: string;
209
+ contractId: string | null;
210
+ functionName: string | null;
211
211
  };
212
212
  }
213
213
  /** Contract event filters */
@@ -276,12 +276,12 @@ interface MapWriteFilter extends TraitScope, FactoryScope {
276
276
  * - `{ list: F }` — a list of `F`.
277
277
  */
278
278
  type PrintField = ColumnType | {
279
- type: PrintField
280
- optional: true
279
+ type: PrintField;
280
+ optional: true;
281
281
  } | {
282
- tuple: Record<string, PrintField>
282
+ tuple: Record<string, PrintField>;
283
283
  } | {
284
- list: PrintField
284
+ list: PrintField;
285
285
  };
286
286
  /**
287
287
  * Per-topic field schema for a print_event source. When declared, the handler's
@@ -293,34 +293,34 @@ type PrintField = ColumnType | {
293
293
  */
294
294
  type PrintEventPrints = Record<string, Record<string, PrintField>>;
295
295
  type PrintEventFields = FactoryScope & {
296
- type: "print_event"
297
- topic?: string
296
+ type: "print_event";
297
+ topic?: string;
298
298
  };
299
299
  /**
300
300
  * Pinned to one or more contract ids with no trait — `prints` is required so
301
301
  * `event.data` is typed and empty-table handlers cannot typecheck.
302
302
  */
303
303
  type PinnedPrintEventFilter = PrintEventFields & {
304
- contractId: string | readonly string[]
305
- trait?: undefined
306
- prints: PrintEventPrints
304
+ contractId: string | readonly string[];
305
+ trait?: undefined;
306
+ prints: PrintEventPrints;
307
307
  };
308
308
  /**
309
309
  * Trait-scoped print source (optionally narrowed by contractId). No single
310
310
  * schema — `prints` stays optional.
311
311
  */
312
312
  type TraitPrintEventFilter = PrintEventFields & {
313
- contractId?: string | readonly string[]
314
- trait: string
315
- prints?: PrintEventPrints
313
+ contractId?: string | readonly string[];
314
+ trait: string;
315
+ prints?: PrintEventPrints;
316
316
  };
317
317
  /**
318
318
  * Unpinned / factory-only print source (no contractId). `prints` optional.
319
319
  */
320
320
  type UnpinnedPrintEventFilter = PrintEventFields & {
321
- contractId?: undefined
322
- trait?: string
323
- prints?: PrintEventPrints
321
+ contractId?: undefined;
322
+ trait?: string;
323
+ prints?: PrintEventPrints;
324
324
  };
325
325
  /**
326
326
  * Print-event filter. Pinned sources (contractId set, no trait) require
@@ -343,12 +343,12 @@ type RowValue = string | number | bigint | boolean | null | undefined | Record<s
343
343
  /** Context passed to subgraph handlers during event processing */
344
344
  interface SubgraphContext {
345
345
  block: {
346
- height: number
347
- hash: string
348
- timestamp: number
349
- burnBlockHeight: number
346
+ height: number;
347
+ hash: string;
348
+ timestamp: number;
349
+ burnBlockHeight: number;
350
350
  /** Nakamoto StacksBlockId, when the block row carries one. */
351
- indexBlockHash?: string | null
351
+ indexBlockHash?: string | null;
352
352
  };
353
353
  tx: TxMeta;
354
354
  /**
package/dist/types.js CHANGED
@@ -1,3 +1,3 @@
1
1
 
2
- //# debugId=F2B76011AEAE140064756E2164756E21
2
+ //# debugId=9FCB033A2878230664756E2164756E21
3
3
  //# sourceMappingURL=types.js.map
package/dist/types.js.map CHANGED
@@ -4,6 +4,6 @@
4
4
  "sourcesContent": [
5
5
  ],
6
6
  "mappings": "",
7
- "debugId": "F2B76011AEAE140064756E2164756E21",
7
+ "debugId": "9FCB033A2878230664756E2164756E21",
8
8
  "names": []
9
9
  }
@@ -17,7 +17,7 @@ import { AssetIdentifier } from "@secondlayer/stacks/filters";
17
17
  */
18
18
  type ChainReadCacheMode = "per-block" | "contract-constant";
19
19
  type ChainReadOptions = {
20
- cache?: ChainReadCacheMode
20
+ cache?: ChainReadCacheMode;
21
21
  };
22
22
  /**
23
23
  * `ChainReadClient` with the ABI generic erased. Structurally cheap, so the
@@ -26,7 +26,7 @@ type ChainReadOptions = {
26
26
  */
27
27
  interface ErasedChainReadClient {
28
28
  contract(contractId: string, abi: unknown, options?: ChainReadOptions): {
29
- read: Record<string, (args?: Record<string, unknown>) => Promise<unknown>>
29
+ read: Record<string, (args?: Record<string, unknown>) => Promise<unknown>>;
30
30
  };
31
31
  }
32
32
  /** Supported column types for subgraph schemas */
@@ -87,7 +87,7 @@ interface StxLockFilter {
87
87
  * as-of each processed block. Lets a source index "all SIP-010 tokens" etc.
88
88
  */
89
89
  type TraitScope = {
90
- trait?: string
90
+ trait?: string;
91
91
  };
92
92
  /**
93
93
  * Scope a source to a DYNAMIC address set discovered from another source's
@@ -127,10 +127,10 @@ type TraitScope = {
127
127
  interface FactoryScope {
128
128
  factory?: {
129
129
  /** Source name whose events reveal the addresses. */
130
- from: string
130
+ from: string;
131
131
  /** Dotted path to the address on that source's payload
132
132
  * (e.g. `"data.pool"`, `"contractId"`, `"data.token.id"`). */
133
- field: string
133
+ field: string;
134
134
  };
135
135
  }
136
136
  /** FT event filters */
@@ -236,12 +236,12 @@ interface MapWriteFilter extends TraitScope, FactoryScope {
236
236
  * - `{ list: F }` — a list of `F`.
237
237
  */
238
238
  type PrintField = ColumnType | {
239
- type: PrintField
240
- optional: true
239
+ type: PrintField;
240
+ optional: true;
241
241
  } | {
242
- tuple: Record<string, PrintField>
242
+ tuple: Record<string, PrintField>;
243
243
  } | {
244
- list: PrintField
244
+ list: PrintField;
245
245
  };
246
246
  /**
247
247
  * Per-topic field schema for a print_event source. When declared, the handler's
@@ -253,34 +253,34 @@ type PrintField = ColumnType | {
253
253
  */
254
254
  type PrintEventPrints = Record<string, Record<string, PrintField>>;
255
255
  type PrintEventFields = FactoryScope & {
256
- type: "print_event"
257
- topic?: string
256
+ type: "print_event";
257
+ topic?: string;
258
258
  };
259
259
  /**
260
260
  * Pinned to one or more contract ids with no trait — `prints` is required so
261
261
  * `event.data` is typed and empty-table handlers cannot typecheck.
262
262
  */
263
263
  type PinnedPrintEventFilter = PrintEventFields & {
264
- contractId: string | readonly string[]
265
- trait?: undefined
266
- prints: PrintEventPrints
264
+ contractId: string | readonly string[];
265
+ trait?: undefined;
266
+ prints: PrintEventPrints;
267
267
  };
268
268
  /**
269
269
  * Trait-scoped print source (optionally narrowed by contractId). No single
270
270
  * schema — `prints` stays optional.
271
271
  */
272
272
  type TraitPrintEventFilter = PrintEventFields & {
273
- contractId?: string | readonly string[]
274
- trait: string
275
- prints?: PrintEventPrints
273
+ contractId?: string | readonly string[];
274
+ trait: string;
275
+ prints?: PrintEventPrints;
276
276
  };
277
277
  /**
278
278
  * Unpinned / factory-only print source (no contractId). `prints` optional.
279
279
  */
280
280
  type UnpinnedPrintEventFilter = PrintEventFields & {
281
- contractId?: undefined
282
- trait?: string
283
- prints?: PrintEventPrints
281
+ contractId?: undefined;
282
+ trait?: string;
283
+ prints?: PrintEventPrints;
284
284
  };
285
285
  /**
286
286
  * Print-event filter. Pinned sources (contractId set, no trait) require
@@ -301,12 +301,12 @@ interface TxMeta {
301
301
  /** Context passed to subgraph handlers during event processing */
302
302
  interface SubgraphContext {
303
303
  block: {
304
- height: number
305
- hash: string
306
- timestamp: number
307
- burnBlockHeight: number
304
+ height: number;
305
+ hash: string;
306
+ timestamp: number;
307
+ burnBlockHeight: number;
308
308
  /** Nakamoto StacksBlockId, when the block row carries one. */
309
- indexBlockHash?: string | null
309
+ indexBlockHash?: string | null;
310
310
  };
311
311
  tx: TxMeta;
312
312
  /**
@@ -405,7 +405,7 @@ declare function validateSubgraphDefinition(def: unknown): SubgraphDefinition;
405
405
  * means adding a field to a filter can never leave the documentation behind.
406
406
  */
407
407
  declare function filterFieldsByType(): Array<{
408
- type: string
409
- fields: string[]
408
+ type: string;
409
+ fields: string[];
410
410
  }>;
411
411
  export { AbiContractSchema, ColumnTypeSchema, PrintFieldSchema, SqlIdentifierSchema, SubgraphColumnSchema, SubgraphDefinitionSchema, SubgraphFilterSchema, SubgraphNameSchema, SubgraphSchemaSchema, SubgraphTableSchema, VALID_FILTER_TYPES, filterFieldsByType, validateSubgraphDefinition };
package/dist/validate.js CHANGED
@@ -307,5 +307,5 @@ export {
307
307
  validateSubgraphDefinition
308
308
  };
309
309
 
310
- //# debugId=BFED63A6F6DDAA5F64756E2164756E21
310
+ //# debugId=3596CDEC5E862E6064756E2164756E21
311
311
  //# sourceMappingURL=validate.js.map
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/validate.ts"],
3
+ "sources": ["src/validate.ts"],
4
4
  "sourcesContent": [
5
5
  "import { z } from \"zod\";\nimport type {\n\tColumnType,\n\tSubgraphColumn,\n\tSubgraphDefinition,\n\tSubgraphFilter,\n\tSubgraphSchema,\n\tSubgraphTable,\n} from \"./types.ts\";\n\nexport const SubgraphNameSchema: z.ZodType<string> = z\n\t.string()\n\t.min(1)\n\t.max(63)\n\t.regex(\n\t\t/^[a-z][a-z0-9-]*$/,\n\t\t\"Must start with lowercase letter, contain only lowercase alphanumeric and hyphens\",\n\t);\n\n/**\n * A safe SQL identifier (table or column name). Mirrors the runtime guard in\n * runtime/context.ts (validateColumnName) so the schema validator can never\n * accept a name the runtime would reject — and closes the deploy-time DDL\n * injection path in schema/generator.ts, which interpolates these names raw.\n */\nexport const SqlIdentifierSchema: z.ZodType<string> = z\n\t.string()\n\t.min(1)\n\t.max(63) // Postgres truncates identifiers > 63 bytes; reject rather than collide.\n\t.regex(\n\t\t/^[a-z_][a-z0-9_]*$/i,\n\t\t\"Must be a valid SQL identifier: start with a letter or underscore, then letters/digits/underscores only\",\n\t);\n\nexport const ColumnTypeSchema: z.ZodType<ColumnType> = z.enum([\n\t\"text\",\n\t\"uint\",\n\t\"int\",\n\t\"principal\",\n\t\"boolean\",\n\t\"timestamp\",\n\t\"jsonb\",\n]);\n\n/**\n * One declared print field: a bare column type, or a composite (optional,\n * nested tuple, list). Recursive — real print payloads nest, and a vocabulary\n * that could only say `\"jsonb\"` is what let a flat-field declaration pass\n * while every event decoded to null.\n */\nexport const PrintFieldSchema: z.ZodType<unknown> = z.lazy(() =>\n\tz.union([\n\t\tColumnTypeSchema,\n\t\tz.object({ type: PrintFieldSchema, optional: z.literal(true) }),\n\t\tz.object({ tuple: z.record(z.string(), PrintFieldSchema) }),\n\t\tz.object({ list: PrintFieldSchema }),\n\t]),\n);\n\n/**\n * A Clarity ABI type: a primitive name, or one of the composite shapes.\n * Recursive, so nested tuples/lists/optionals are checked all the way down.\n */\nconst AbiTypeSchema: z.ZodType<unknown> = z.lazy(() =>\n\tz.union([\n\t\tz.string(),\n\t\tz.object({ buff: z.object({ length: z.number() }) }),\n\t\tz.object({ \"string-ascii\": z.object({ length: z.number() }) }),\n\t\tz.object({ \"string-utf8\": z.object({ length: z.number() }) }),\n\t\tz.object({ optional: AbiTypeSchema }),\n\t\tz.object({\n\t\t\tlist: z.object({ type: AbiTypeSchema, length: z.number() }),\n\t\t}),\n\t\tz.object({\n\t\t\ttuple: z.array(z.object({ name: z.string(), type: AbiTypeSchema })),\n\t\t}),\n\t\tz.object({\n\t\t\tresponse: z.object({ ok: AbiTypeSchema, error: AbiTypeSchema }),\n\t\t}),\n\t]),\n);\n\n/**\n * The canonical `AbiContract` shape, validated at deploy time.\n *\n * This used to be `z.record(z.string(), z.any())`, which accepted a raw\n * Hiro/Clarinet ABI (`read_only` access, `buffer` types, outputs wrapped as\n * `{ type: … }`) and let it through — the deploy succeeded and `event.input`\n * then mis-decoded at RUNTIME, per event, forever. Reject it here instead,\n * and name the fix: run it through `normalizeAbi` from\n * `@secondlayer/stacks/clarity`.\n */\nexport const AbiContractSchema: z.ZodType<unknown> = z.object({\n\tfunctions: z.array(\n\t\tz.object({\n\t\t\tname: z.string(),\n\t\t\taccess: z.enum([\"public\", \"read-only\", \"private\"], {\n\t\t\t\tmessage:\n\t\t\t\t\t\"ABI access must be public | read-only | private — a raw Hiro/Clarinet ABI uses `read_only`. Normalize it first: normalizeAbi() from @secondlayer/stacks/clarity.\",\n\t\t\t}),\n\t\t\targs: z.array(z.object({ name: z.string(), type: AbiTypeSchema })),\n\t\t\t// Canonical shape is a bare AbiType; raw ABIs wrap it as `{ type: … }`.\n\t\t\toutputs: AbiTypeSchema,\n\t\t}),\n\t),\n\tmaps: z.array(z.unknown()).optional(),\n\tvariables: z.array(z.unknown()).optional(),\n\tfungible_tokens: z.array(z.unknown()).optional(),\n\tnon_fungible_tokens: z.array(z.unknown()).optional(),\n\timplemented_traits: z.array(z.unknown()).optional(),\n\tdefined_traits: z.array(z.unknown()).optional(),\n});\n\nexport const SubgraphColumnSchema: z.ZodType<SubgraphColumn> = z.object({\n\ttype: ColumnTypeSchema,\n\tnullable: z.boolean().optional(),\n\tindexed: z.boolean().optional(),\n\tsearch: z.boolean().optional(),\n\tdefault: z.union([z.string(), z.number(), z.boolean()]).optional(),\n}) as z.ZodType<SubgraphColumn>;\n\nexport const SubgraphTableSchema: z.ZodType<SubgraphTable> = z.object({\n\tcolumns: z\n\t\t.record(SqlIdentifierSchema, SubgraphColumnSchema)\n\t\t.refine(\n\t\t\t(c) => Object.keys(c).length > 0,\n\t\t\t\"Table must have at least one column\",\n\t\t),\n\tindexes: z.array(z.array(SqlIdentifierSchema)).optional(),\n\tuniqueKeys: z.array(z.array(SqlIdentifierSchema)).optional(),\n}) as z.ZodType<SubgraphTable>;\n\nexport const SubgraphSchemaSchema: z.ZodType<Record<string, SubgraphTable>> = z\n\t.record(SqlIdentifierSchema, SubgraphTableSchema)\n\t.refine(\n\t\t(s) => Object.keys(s).length > 0,\n\t\t\"Schema must have at least one table\",\n\t) as z.ZodType<Record<string, SubgraphTable>>;\n\nexport const VALID_FILTER_TYPES = [\n\t\"stx_transfer\",\n\t\"stx_mint\",\n\t\"stx_burn\",\n\t\"stx_lock\",\n\t\"ft_transfer\",\n\t\"ft_mint\",\n\t\"ft_burn\",\n\t\"nft_transfer\",\n\t\"nft_mint\",\n\t\"nft_burn\",\n\t\"contract_call\",\n\t\"contract_deploy\",\n\t\"print_event\",\n\t\"nested_contract_call\",\n\t\"var_set\",\n\t\"map_set\",\n\t\"map_insert\",\n\t\"map_delete\",\n] as const;\n\n/** A contract id, or a set of them (max 20, matching the Index API cap). */\nconst contractIdField = z.union([\n\tz.string(),\n\tz.array(z.string()).min(1).max(20),\n]);\n\n/** Fields shared by the trait-scopable filters. */\nconst traitScope = { trait: z.string().optional() };\n/** Dynamic address set discovered from another source's events. */\nconst factoryScope = {\n\tfactory: z\n\t\t.object({ from: z.string().min(1), field: z.string().min(1) })\n\t\t.strict()\n\t\t.optional(),\n};\nconst amountRange = {\n\tminAmount: z.bigint().optional(),\n\tmaxAmount: z.bigint().optional(),\n};\n\n/**\n * A REAL discriminated union — one member per source type, each `.strict()`\n * with only the fields that type actually supports.\n *\n * It used to be one flat object with every field optional, so\n * `{ type: \"contract_deploy\", assetIdentifier: \"SP…\", minAmount: 1n }`\n * validated clean at deploy and then matched nothing, forever. The runtime\n * union already knew better; only the validator didn't.\n */\nconst SubgraphFilterUnion = z.discriminatedUnion(\"type\", [\n\tz\n\t\t.object({\n\t\t\ttype: z.literal(\"stx_transfer\"),\n\t\t\tsender: z.string().optional(),\n\t\t\trecipient: z.string().optional(),\n\t\t\t...amountRange,\n\t\t})\n\t\t.strict(),\n\tz\n\t\t.object({\n\t\t\ttype: z.literal(\"stx_mint\"),\n\t\t\trecipient: z.string().optional(),\n\t\t\tminAmount: z.bigint().optional(),\n\t\t})\n\t\t.strict(),\n\tz\n\t\t.object({\n\t\t\ttype: z.literal(\"stx_burn\"),\n\t\t\tsender: z.string().optional(),\n\t\t\tminAmount: z.bigint().optional(),\n\t\t})\n\t\t.strict(),\n\tz\n\t\t.object({\n\t\t\ttype: z.literal(\"stx_lock\"),\n\t\t\tlockedAddress: z.string().optional(),\n\t\t\tminAmount: z.bigint().optional(),\n\t\t})\n\t\t.strict(),\n\tz\n\t\t.object({\n\t\t\ttype: z.literal(\"ft_transfer\"),\n\t\t\tassetIdentifier: z.string().optional(),\n\t\t\tsender: z.string().optional(),\n\t\t\trecipient: z.string().optional(),\n\t\t\tminAmount: z.bigint().optional(),\n\t\t\t...traitScope,\n\t\t})\n\t\t.strict(),\n\tz\n\t\t.object({\n\t\t\ttype: z.literal(\"ft_mint\"),\n\t\t\tassetIdentifier: z.string().optional(),\n\t\t\trecipient: z.string().optional(),\n\t\t\tminAmount: z.bigint().optional(),\n\t\t\t...traitScope,\n\t\t})\n\t\t.strict(),\n\tz\n\t\t.object({\n\t\t\ttype: z.literal(\"ft_burn\"),\n\t\t\tassetIdentifier: z.string().optional(),\n\t\t\tsender: z.string().optional(),\n\t\t\tminAmount: z.bigint().optional(),\n\t\t\t...traitScope,\n\t\t})\n\t\t.strict(),\n\tz\n\t\t.object({\n\t\t\ttype: z.literal(\"nft_transfer\"),\n\t\t\tassetIdentifier: z.string().optional(),\n\t\t\tsender: z.string().optional(),\n\t\t\trecipient: z.string().optional(),\n\t\t\t...traitScope,\n\t\t})\n\t\t.strict(),\n\tz\n\t\t.object({\n\t\t\ttype: z.literal(\"nft_mint\"),\n\t\t\tassetIdentifier: z.string().optional(),\n\t\t\trecipient: z.string().optional(),\n\t\t\t...traitScope,\n\t\t})\n\t\t.strict(),\n\tz\n\t\t.object({\n\t\t\ttype: z.literal(\"nft_burn\"),\n\t\t\tassetIdentifier: z.string().optional(),\n\t\t\tsender: z.string().optional(),\n\t\t\t...traitScope,\n\t\t})\n\t\t.strict(),\n\tz\n\t\t.object({\n\t\t\ttype: z.literal(\"contract_call\"),\n\t\t\tcontractId: contractIdField.optional(),\n\t\t\tfunctionName: z.string().optional(),\n\t\t\tcaller: z.string().optional(),\n\t\t\tabi: AbiContractSchema.optional(),\n\t\t\t...traitScope,\n\t\t\t...factoryScope,\n\t\t})\n\t\t.strict(),\n\tz\n\t\t.object({\n\t\t\ttype: z.literal(\"contract_deploy\"),\n\t\t\tdeployer: z.string().optional(),\n\t\t\tcontractName: z.string().optional(),\n\t\t})\n\t\t.strict(),\n\tz\n\t\t.object({\n\t\t\ttype: z.literal(\"print_event\"),\n\t\t\tcontractId: contractIdField.optional(),\n\t\t\ttopic: z.string().optional(),\n\t\t\tprints: z\n\t\t\t\t.record(z.string(), z.record(z.string(), PrintFieldSchema))\n\t\t\t\t.optional(),\n\t\t\t...traitScope,\n\t\t\t...factoryScope,\n\t\t})\n\t\t.strict(),\n\tz\n\t\t.object({\n\t\t\ttype: z.literal(\"nested_contract_call\"),\n\t\t\tcontractId: contractIdField.optional(),\n\t\t\tfunctionName: z.string().optional(),\n\t\t\tcaller: z.string().optional(),\n\t\t\tsender: z.string().optional(),\n\t\t\t...traitScope,\n\t\t\t...factoryScope,\n\t\t})\n\t\t.strict(),\n\tz\n\t\t.object({\n\t\t\ttype: z.literal(\"var_set\"),\n\t\t\tcontractId: contractIdField.optional(),\n\t\t\tvarName: z.string().optional(),\n\t\t\t...traitScope,\n\t\t\t...factoryScope,\n\t\t})\n\t\t.strict(),\n\tz\n\t\t.object({\n\t\t\ttype: z.literal(\"map_set\"),\n\t\t\tcontractId: contractIdField.optional(),\n\t\t\tmap: z.string().optional(),\n\t\t\t...traitScope,\n\t\t\t...factoryScope,\n\t\t})\n\t\t.strict(),\n\tz\n\t\t.object({\n\t\t\ttype: z.literal(\"map_insert\"),\n\t\t\tcontractId: contractIdField.optional(),\n\t\t\tmap: z.string().optional(),\n\t\t\t...traitScope,\n\t\t\t...factoryScope,\n\t\t})\n\t\t.strict(),\n\tz\n\t\t.object({\n\t\t\ttype: z.literal(\"map_delete\"),\n\t\t\tcontractId: contractIdField.optional(),\n\t\t\tmap: z.string().optional(),\n\t\t\t...traitScope,\n\t\t\t...factoryScope,\n\t\t})\n\t\t.strict(),\n]);\n\n/**\n * `trait` and `contractId` compose rather than conflict: the matcher ANDs\n * them, so the pair means \"contracts conforming to this trait, narrowed to\n * these ids\". (The Index READ API refuses the combination because its query\n * planner picks one index path — that's an API constraint, not a semantic\n * one, and subgraph sources are not bound by it.)\n */\nexport const SubgraphFilterSchema: z.ZodType<SubgraphFilter> =\n\tSubgraphFilterUnion as unknown as z.ZodType<SubgraphFilter>;\n\n/** Pinned contractId: a non-empty string or a non-empty array of ids. */\nfunction hasPinnedContractId(\n\tcontractId: string | readonly string[] | undefined,\n): boolean {\n\tif (typeof contractId === \"string\") return contractId.length > 0;\n\tif (Array.isArray(contractId)) return contractId.length > 0;\n\treturn false;\n}\n\n/**\n * Deploy gates beyond the per-filter union: pinned print_event needs a\n * non-empty `prints` map, contract_call+functionName needs `abi`, and every\n * source needs a handler of the same name.\n */\nfunction refineDeployGates(\n\tdef: {\n\t\tsources: Record<string, SubgraphFilter>;\n\t\thandlers: Record<string, unknown>;\n\t\tschema: SubgraphSchema;\n\t},\n\tctx: z.RefinementCtx,\n): void {\n\tfor (const [name, filter] of Object.entries(def.sources)) {\n\t\tif (filter.type === \"print_event\") {\n\t\t\t// Trait / unpinned (no contractId) may omit prints — no single schema.\n\t\t\tconst pinned = hasPinnedContractId(filter.contractId) && !filter.trait;\n\t\t\tif (pinned) {\n\t\t\t\tconst prints = filter.prints;\n\t\t\t\tif (\n\t\t\t\t\tprints === undefined ||\n\t\t\t\t\ttypeof prints !== \"object\" ||\n\t\t\t\t\tObject.keys(prints).length === 0\n\t\t\t\t) {\n\t\t\t\t\tctx.addIssue({\n\t\t\t\t\t\tcode: \"custom\",\n\t\t\t\t\t\tpath: [\"sources\", name, \"prints\"],\n\t\t\t\t\t\tmessage: `print_event source \"${name}\" has no prints map — field names would be untyped and empty tables would typecheck. Declare prints from index_print_schema / create --from-contract.`,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (filter.type === \"contract_call\" && filter.functionName !== undefined) {\n\t\t\tif (filter.abi === undefined) {\n\t\t\t\tctx.addIssue({\n\t\t\t\t\tcode: \"custom\",\n\t\t\t\t\tpath: [\"sources\", name, \"abi\"],\n\t\t\t\t\tmessage: `contract_call source \"${name}\" has functionName but no abi. \\`secondlayer subgraphs deploy\\` fills it in from the deployed contract; otherwise pass abi (normalizeAbi() from @secondlayer/stacks/clarity).`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\tfor (const name of Object.keys(def.sources)) {\n\t\tif (def.handlers[name] == null) {\n\t\t\tctx.addIssue({\n\t\t\t\tcode: \"custom\",\n\t\t\t\tpath: [\"handlers\", name],\n\t\t\t\tmessage: `source \"${name}\" has no handler. Add handlers.${name}, or its events are skipped and the table stays empty.`,\n\t\t\t});\n\t\t}\n\t}\n}\n\nexport const SubgraphDefinitionSchema: z.ZodType<SubgraphDefinition> = z\n\t.object({\n\t\tname: SubgraphNameSchema,\n\t\tdescription: z.string().optional(),\n\t\tstartBlock: z.number().int().nonnegative().optional(),\n\t\t// 'concurrent' = tip-first deploy: go live at tip immediately, fill\n\t\t// history via a background backfill. Only safe for order-tolerant\n\t\t// handlers (commutative or insert-only writes).\n\t\tbackfillMode: z.enum([\"blocking\", \"concurrent\"]).optional(),\n\t\tsources: z\n\t\t\t.record(z.string(), SubgraphFilterSchema)\n\t\t\t.refine(\n\t\t\t\t(s) => Object.keys(s).length > 0,\n\t\t\t\t\"Must have at least one source\",\n\t\t\t),\n\t\tschema: SubgraphSchemaSchema,\n\t\thandlers: z.record(z.string(), z.any()),\n\t})\n\t.superRefine((def, ctx) => {\n\t\trefineDeployGates(\n\t\t\tdef as {\n\t\t\t\tsources: Record<string, SubgraphFilter>;\n\t\t\t\thandlers: Record<string, unknown>;\n\t\t\t\tschema: SubgraphSchema;\n\t\t\t},\n\t\t\tctx,\n\t\t);\n\t}) as unknown as z.ZodType<SubgraphDefinition>;\n\n/**\n * Validates a subgraph definition, returning the parsed result or throwing on failure.\n */\nexport function validateSubgraphDefinition(def: unknown): SubgraphDefinition {\n\treturn SubgraphDefinitionSchema.parse(def);\n}\n\n/**\n * Per-source-type field vocabulary, DERIVED from\n * {@link SubgraphFilterSchema}. Agent-facing surfaces (the MCP filters\n * reference) used to hand-maintain a parallel copy of this list; deriving it\n * means adding a field to a filter can never leave the documentation behind.\n */\nexport function filterFieldsByType(): Array<{\n\ttype: string;\n\tfields: string[];\n}> {\n\t// Read the UNION directly (SubgraphFilterSchema wraps it in superRefine).\n\t// biome-ignore lint/suspicious/noExplicitAny: reading zod's internal option shapes\n\tconst options = (SubgraphFilterUnion as any)?._def?.options ?? [];\n\tconst out: Array<{ type: string; fields: string[] }> = [];\n\tfor (const option of options) {\n\t\t// `.superRefine()` wraps the union, so unwrap one level when present.\n\t\tconst shape = option?.shape ?? option?._def?.shape;\n\t\tif (!shape) continue;\n\t\tconst literal =\n\t\t\tshape.type?._def?.values?.[0] ?? shape.type?._def?.value ?? undefined;\n\t\tif (typeof literal !== \"string\") continue;\n\t\tout.push({\n\t\t\ttype: literal,\n\t\t\tfields: Object.keys(shape).filter((k) => k !== \"type\"),\n\t\t});\n\t}\n\treturn out;\n}\n"
6
6
  ],
7
7
  "mappings": "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",
8
- "debugId": "BFED63A6F6DDAA5F64756E2164756E21",
8
+ "debugId": "3596CDEC5E862E6064756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -17,7 +17,7 @@ import { AssetIdentifier } from "@secondlayer/stacks/filters";
17
17
  */
18
18
  type ChainReadCacheMode = "per-block" | "contract-constant";
19
19
  type ChainReadOptions = {
20
- cache?: ChainReadCacheMode
20
+ cache?: ChainReadCacheMode;
21
21
  };
22
22
  /**
23
23
  * `ChainReadClient` with the ABI generic erased. Structurally cheap, so the
@@ -26,7 +26,7 @@ type ChainReadOptions = {
26
26
  */
27
27
  interface ErasedChainReadClient {
28
28
  contract(contractId: string, abi: unknown, options?: ChainReadOptions): {
29
- read: Record<string, (args?: Record<string, unknown>) => Promise<unknown>>
29
+ read: Record<string, (args?: Record<string, unknown>) => Promise<unknown>>;
30
30
  };
31
31
  }
32
32
  /** Supported column types for subgraph schemas */
@@ -87,7 +87,7 @@ interface StxLockFilter {
87
87
  * as-of each processed block. Lets a source index "all SIP-010 tokens" etc.
88
88
  */
89
89
  type TraitScope = {
90
- trait?: string
90
+ trait?: string;
91
91
  };
92
92
  /**
93
93
  * Scope a source to a DYNAMIC address set discovered from another source's
@@ -127,10 +127,10 @@ type TraitScope = {
127
127
  interface FactoryScope {
128
128
  factory?: {
129
129
  /** Source name whose events reveal the addresses. */
130
- from: string
130
+ from: string;
131
131
  /** Dotted path to the address on that source's payload
132
132
  * (e.g. `"data.pool"`, `"contractId"`, `"data.token.id"`). */
133
- field: string
133
+ field: string;
134
134
  };
135
135
  }
136
136
  /** FT event filters */
@@ -236,12 +236,12 @@ interface MapWriteFilter extends TraitScope, FactoryScope {
236
236
  * - `{ list: F }` — a list of `F`.
237
237
  */
238
238
  type PrintField = ColumnType | {
239
- type: PrintField
240
- optional: true
239
+ type: PrintField;
240
+ optional: true;
241
241
  } | {
242
- tuple: Record<string, PrintField>
242
+ tuple: Record<string, PrintField>;
243
243
  } | {
244
- list: PrintField
244
+ list: PrintField;
245
245
  };
246
246
  /**
247
247
  * Per-topic field schema for a print_event source. When declared, the handler's
@@ -253,34 +253,34 @@ type PrintField = ColumnType | {
253
253
  */
254
254
  type PrintEventPrints = Record<string, Record<string, PrintField>>;
255
255
  type PrintEventFields = FactoryScope & {
256
- type: "print_event"
257
- topic?: string
256
+ type: "print_event";
257
+ topic?: string;
258
258
  };
259
259
  /**
260
260
  * Pinned to one or more contract ids with no trait — `prints` is required so
261
261
  * `event.data` is typed and empty-table handlers cannot typecheck.
262
262
  */
263
263
  type PinnedPrintEventFilter = PrintEventFields & {
264
- contractId: string | readonly string[]
265
- trait?: undefined
266
- prints: PrintEventPrints
264
+ contractId: string | readonly string[];
265
+ trait?: undefined;
266
+ prints: PrintEventPrints;
267
267
  };
268
268
  /**
269
269
  * Trait-scoped print source (optionally narrowed by contractId). No single
270
270
  * schema — `prints` stays optional.
271
271
  */
272
272
  type TraitPrintEventFilter = PrintEventFields & {
273
- contractId?: string | readonly string[]
274
- trait: string
275
- prints?: PrintEventPrints
273
+ contractId?: string | readonly string[];
274
+ trait: string;
275
+ prints?: PrintEventPrints;
276
276
  };
277
277
  /**
278
278
  * Unpinned / factory-only print source (no contractId). `prints` optional.
279
279
  */
280
280
  type UnpinnedPrintEventFilter = PrintEventFields & {
281
- contractId?: undefined
282
- trait?: string
283
- prints?: PrintEventPrints
281
+ contractId?: undefined;
282
+ trait?: string;
283
+ prints?: PrintEventPrints;
284
284
  };
285
285
  /**
286
286
  * Print-event filter. Pinned sources (contractId set, no trait) require
@@ -301,12 +301,12 @@ interface TxMeta {
301
301
  /** Context passed to subgraph handlers during event processing */
302
302
  interface SubgraphContext {
303
303
  block: {
304
- height: number
305
- hash: string
306
- timestamp: number
307
- burnBlockHeight: number
304
+ height: number;
305
+ hash: string;
306
+ timestamp: number;
307
+ burnBlockHeight: number;
308
308
  /** Nakamoto StacksBlockId, when the block row carries one. */
309
- indexBlockHash?: string | null
309
+ indexBlockHash?: string | null;
310
310
  };
311
311
  tx: TxMeta;
312
312
  /**
@@ -417,10 +417,25 @@ interface PinInput {
417
417
  /** Defaults to {@link SUBGRAPHS_RUNTIME}. */
418
418
  runtime?: string;
419
419
  }
420
+ /** What a pin commits to, as stored in `pin_preimage`. */
421
+ interface PinFields {
422
+ /** sha256 of the bundled handler, hex. */
423
+ handlerHash: string;
424
+ network: string;
425
+ runtime: string;
426
+ schemaHash: string;
427
+ startBlock: number | null;
428
+ }
429
+ /**
430
+ * The canonical JSON a pin is the sha256 of: fixed key order, primitives
431
+ * only. Stored beside the pin so anyone can recompute it from the served
432
+ * handler code.
433
+ */
434
+ declare function pinPreimage(input: PinInput): string;
420
435
  /**
421
436
  * Content hash over everything that shapes a subgraph's rows. Unlike
422
437
  * `schema_hash`, it changes with the handler, `startBlock` and runtime, so
423
438
  * two deploys with the same pin produce the same rows from the same chain.
424
439
  */
425
440
  declare function computePin(input: PinInput): string;
426
- export { ALLOWED_GLOBALS, ALLOWED_MATH, FORBIDDEN_GLOBALS, HandlerFinding, LOCALE_METHODS, PinInput, SUBGRAPHS_RUNTIME, SubgraphVerification, computePin, deriveVerification, formatFinding, isDeterminismViolation };
441
+ export { ALLOWED_GLOBALS, ALLOWED_MATH, FORBIDDEN_GLOBALS, HandlerFinding, LOCALE_METHODS, PinFields, PinInput, SUBGRAPHS_RUNTIME, SubgraphVerification, computePin, deriveVerification, formatFinding, isDeterminismViolation, pinPreimage };
@@ -3,7 +3,7 @@ import { createHash } from "node:crypto";
3
3
  // package.json
4
4
  var package_default = {
5
5
  name: "@secondlayer/subgraphs",
6
- version: "6.4.0",
6
+ version: "6.5.0",
7
7
  description: "Describe the Stacks data you want as one TypeScript file; it fills itself and survives reorgs.",
8
8
  license: "MIT",
9
9
  repository: {
@@ -47,6 +47,10 @@ var package_default = {
47
47
  "./testing": {
48
48
  types: "./dist/testing/index.d.ts",
49
49
  import: "./dist/testing/index.js"
50
+ },
51
+ "./verify": {
52
+ types: "./dist/verify/index.d.ts",
53
+ import: "./dist/verify/index.js"
50
54
  }
51
55
  },
52
56
  files: ["dist"],
@@ -58,14 +62,16 @@ var package_default = {
58
62
  prepublishOnly: "bun run build"
59
63
  },
60
64
  dependencies: {
61
- "@secondlayer/shared": "^11.22.0",
62
- "@secondlayer/stacks": "^6.1.0",
65
+ "@secondlayer/shared": "^11.23.0",
66
+ "@secondlayer/stacks": "^6.2.0",
67
+ "@secondlayer/verify": "^0.3.0",
63
68
  esbuild: "^0.28.2",
64
69
  kysely: "0.28.17",
65
70
  zod: "^4.3.6"
66
71
  },
67
72
  devDependencies: {
68
73
  "@types/bun": "latest",
74
+ bunup: "0.16.32",
69
75
  typescript: "^5"
70
76
  },
71
77
  publishConfig: {
@@ -195,7 +201,6 @@ function formatFinding(f) {
195
201
  var STATE_SOURCE_TYPES = new Set([
196
202
  "var_set",
197
203
  "map_set",
198
- "map_insert",
199
204
  "map_delete"
200
205
  ]);
201
206
  var LEVEL_RANK = { state: 0, events: 1, none: 2 };
@@ -212,6 +217,9 @@ function deriveVerification(def, findings = []) {
212
217
  if (filter.trait) {
213
218
  raise("none");
214
219
  reasons.push(`source "${name}": trait scope needs a proven contract registry`);
220
+ } else if (filter.type === "map_insert") {
221
+ raise("events");
222
+ reasons.push(`map_insert source "${name}": map_insert vs map_set needs event proofs`);
215
223
  } else if (!STATE_SOURCE_TYPES.has(filter.type)) {
216
224
  raise("events");
217
225
  reasons.push(`${filter.type} source "${name}" needs event proofs`);
@@ -229,14 +237,12 @@ function deriveVerification(def, findings = []) {
229
237
  if (findings.length > MAX_LISTED_FINDINGS) {
230
238
  reasons.push(`…and ${findings.length - MAX_LISTED_FINDINGS} more handler findings`);
231
239
  }
232
- const writesMapInsert = Object.values(def.sources ?? {}).some((s) => s.type === "map_insert");
233
240
  return {
234
241
  level,
235
242
  reasons,
236
243
  unproven: reasons.length === 0 ? [
237
244
  "tx attribution of writes: event.tx, _tx_id (needs event proofs)",
238
- "intermediate writes within a block (needs event proofs)",
239
- ...writesMapInsert ? ["map_insert vs map_set (needs event proofs)"] : []
245
+ "intermediate writes within a block (needs event proofs)"
240
246
  ] : []
241
247
  };
242
248
  }
@@ -246,15 +252,18 @@ function isDeterminismViolation(v) {
246
252
  function sha256(input) {
247
253
  return createHash("sha256").update(input).digest("hex");
248
254
  }
249
- function computePin(input) {
250
- const canonical = JSON.stringify({
255
+ function pinPreimage(input) {
256
+ const fields = {
251
257
  handlerHash: sha256(input.handlerCode),
252
258
  network: input.network,
253
259
  runtime: input.runtime ?? SUBGRAPHS_RUNTIME,
254
260
  schemaHash: input.schemaHash,
255
261
  startBlock: input.startBlock ?? null
256
- });
257
- return sha256(canonical);
262
+ };
263
+ return JSON.stringify(fields);
264
+ }
265
+ function computePin(input) {
266
+ return sha256(pinPreimage(input));
258
267
  }
259
268
  export {
260
269
  ALLOWED_GLOBALS,
@@ -265,8 +274,9 @@ export {
265
274
  computePin,
266
275
  deriveVerification,
267
276
  formatFinding,
268
- isDeterminismViolation
277
+ isDeterminismViolation,
278
+ pinPreimage
269
279
  };
270
280
 
271
- //# debugId=72124B475AB027A564756E2164756E21
281
+ //# debugId=FE2C72378A236A9764756E2164756E21
272
282
  //# sourceMappingURL=verification.js.map