@secondlayer/subgraphs 4.1.5 → 4.2.1
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/src/index.d.ts +87 -29
- package/dist/src/index.js +376 -128
- package/dist/src/index.js.map +9 -7
- package/dist/src/runtime/block-processor.d.ts +72 -23
- package/dist/src/runtime/block-processor.js +186 -53
- package/dist/src/runtime/block-processor.js.map +7 -5
- package/dist/src/runtime/catchup.d.ts +72 -23
- package/dist/src/runtime/catchup.js +201 -68
- package/dist/src/runtime/catchup.js.map +7 -5
- package/dist/src/runtime/emitter.js +24 -1
- package/dist/src/runtime/emitter.js.map +5 -4
- package/dist/src/runtime/processor.js +328 -166
- package/dist/src/runtime/processor.js.map +10 -7
- package/dist/src/runtime/reindex.d.ts +72 -23
- package/dist/src/runtime/reindex.js +238 -105
- package/dist/src/runtime/reindex.js.map +7 -5
- package/dist/src/runtime/reorg.d.ts +72 -23
- package/dist/src/runtime/reorg.js +215 -81
- package/dist/src/runtime/reorg.js.map +8 -6
- package/dist/src/runtime/runner.d.ts +72 -23
- package/dist/src/runtime/runner.js +156 -23
- package/dist/src/runtime/runner.js.map +8 -6
- package/dist/src/runtime/source-matcher.d.ts +72 -23
- package/dist/src/schema/index.d.ts +72 -23
- package/dist/src/schema/index.js +115 -1
- package/dist/src/schema/index.js.map +3 -3
- package/dist/src/service.js +348 -171
- package/dist/src/service.js.map +11 -8
- package/dist/src/testing/index.d.ts +195 -24
- package/dist/src/testing/index.js +448 -25
- package/dist/src/testing/index.js.map +9 -6
- package/dist/src/triggers/index.d.ts +83 -24
- package/dist/src/triggers/index.js +5 -2
- package/dist/src/triggers/index.js.map +3 -3
- package/dist/src/types.d.ts +73 -24
- package/dist/src/validate.d.ts +72 -23
- package/dist/src/validate.js +115 -1
- package/dist/src/validate.js.map +3 -3
- package/package.json +2 -2
|
@@ -46,7 +46,12 @@ type TraitScope = {
|
|
|
46
46
|
*
|
|
47
47
|
* ```ts
|
|
48
48
|
* sources: {
|
|
49
|
-
* registry: {
|
|
49
|
+
* registry: {
|
|
50
|
+
* type: "print_event",
|
|
51
|
+
* contractId: REGISTRY,
|
|
52
|
+
* topic: "pool-created",
|
|
53
|
+
* prints: { "pool-created": { pool: "principal" } },
|
|
54
|
+
* },
|
|
50
55
|
* swaps: {
|
|
51
56
|
* type: "print_event",
|
|
52
57
|
* topic: "swap",
|
|
@@ -130,6 +135,9 @@ interface ContractCallFilter extends TraitScope, FactoryScope {
|
|
|
130
135
|
* decoded function arguments. Dev-provided; serialized into the deployed
|
|
131
136
|
* definition and used at runtime to decode args by name. Omit to keep
|
|
132
137
|
* `event.args` as a positional `unknown[]`.
|
|
138
|
+
*
|
|
139
|
+
* Deploy validation requires `abi` whenever `functionName` is set
|
|
140
|
+
* (`normalizeAbi()` from `@secondlayer/stacks/clarity`).
|
|
133
141
|
*/
|
|
134
142
|
abi?: AbiContract2;
|
|
135
143
|
}
|
|
@@ -160,29 +168,70 @@ type PrintField = ColumnType | {
|
|
|
160
168
|
} | {
|
|
161
169
|
list: PrintField
|
|
162
170
|
};
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
171
|
+
/**
|
|
172
|
+
* Per-topic field schema for a print_event source. When declared, the handler's
|
|
173
|
+
* `event` is a discriminated union keyed by `topic` and `event.data` is typed
|
|
174
|
+
* per topic. Nested tuples, lists, and optional fields — see {@link PrintField}.
|
|
175
|
+
*
|
|
176
|
+
* Also opts the source into RUNTIME validation: a payload that does not match
|
|
177
|
+
* is skipped and logged rather than written as nulls.
|
|
178
|
+
*/
|
|
179
|
+
type PrintEventPrints = Record<string, Record<string, PrintField>>;
|
|
180
|
+
/**
|
|
181
|
+
* One column in a static identity map. Literals only — the bundler never
|
|
182
|
+
* executes user code, so `{ from: "tokenX" }` is valid and `from("tokenX")`
|
|
183
|
+
* is not.
|
|
184
|
+
*/
|
|
185
|
+
type MaterializeColumn = {
|
|
186
|
+
from: string
|
|
187
|
+
} | {
|
|
188
|
+
fromTx: "sender" | "txId"
|
|
189
|
+
} | {
|
|
190
|
+
fromBlock: "height" | "hash" | "timestamp"
|
|
191
|
+
};
|
|
192
|
+
/** Static insert from a source event — replaces a 1:1 handler. */
|
|
193
|
+
interface MaterializeSpec {
|
|
194
|
+
table: string;
|
|
195
|
+
/** Keys = schema column names (snake). */
|
|
196
|
+
columns: Record<string, MaterializeColumn>;
|
|
185
197
|
}
|
|
198
|
+
type PrintEventFields = FactoryScope & {
|
|
199
|
+
type: "print_event"
|
|
200
|
+
topic?: string
|
|
201
|
+
/** Identity map: insert without a handler function. XOR with handlers[name]. */
|
|
202
|
+
materialize?: MaterializeSpec
|
|
203
|
+
};
|
|
204
|
+
/**
|
|
205
|
+
* Pinned to one or more contract ids with no trait — `prints` is required so
|
|
206
|
+
* `event.data` is typed and empty-table handlers cannot typecheck.
|
|
207
|
+
*/
|
|
208
|
+
type PinnedPrintEventFilter = PrintEventFields & {
|
|
209
|
+
contractId: string | readonly string[]
|
|
210
|
+
trait?: undefined
|
|
211
|
+
prints: PrintEventPrints
|
|
212
|
+
};
|
|
213
|
+
/**
|
|
214
|
+
* Trait-scoped print source (optionally narrowed by contractId). No single
|
|
215
|
+
* schema — `prints` stays optional.
|
|
216
|
+
*/
|
|
217
|
+
type TraitPrintEventFilter = PrintEventFields & {
|
|
218
|
+
contractId?: string | readonly string[]
|
|
219
|
+
trait: string
|
|
220
|
+
prints?: PrintEventPrints
|
|
221
|
+
};
|
|
222
|
+
/**
|
|
223
|
+
* Unpinned / factory-only print source (no contractId). `prints` optional.
|
|
224
|
+
*/
|
|
225
|
+
type UnpinnedPrintEventFilter = PrintEventFields & {
|
|
226
|
+
contractId?: undefined
|
|
227
|
+
trait?: string
|
|
228
|
+
prints?: PrintEventPrints
|
|
229
|
+
};
|
|
230
|
+
/**
|
|
231
|
+
* Print-event filter. Pinned sources (contractId set, no trait) require
|
|
232
|
+
* `prints`; trait and unpinned sources may omit it.
|
|
233
|
+
*/
|
|
234
|
+
type PrintEventFilter = PinnedPrintEventFilter | TraitPrintEventFilter | UnpinnedPrintEventFilter;
|
|
186
235
|
/** All subgraph filter types — discriminated on `type` */
|
|
187
236
|
type SubgraphFilter = StxTransferFilter | StxMintFilter | StxBurnFilter | StxLockFilter | FtTransferFilter | FtMintFilter | FtBurnFilter | NftTransferFilter | NftMintFilter | NftBurnFilter | ContractCallFilter | ContractDeployFilter | PrintEventFilter;
|
|
188
237
|
interface EventTrigger {
|
|
@@ -297,7 +346,17 @@ interface TriggerHelpers {
|
|
|
297
346
|
nftBurn: (f?: Omit<NftBurnFilter, "type">) => TypedEventTrigger<NftBurnEvent>;
|
|
298
347
|
contractCall: (f?: Omit<ContractCallFilter, "type">) => TypedEventTrigger<ContractCallEvent2>;
|
|
299
348
|
contractDeploy: (f?: Omit<ContractDeployFilter, "type">) => TypedEventTrigger<ContractDeployEvent>;
|
|
300
|
-
|
|
349
|
+
/** Subscription triggers are not subgraph deploys — prints not required. */
|
|
350
|
+
printEvent: (f?: {
|
|
351
|
+
contractId?: string | readonly string[]
|
|
352
|
+
topic?: string
|
|
353
|
+
trait?: string
|
|
354
|
+
factory?: {
|
|
355
|
+
from: string
|
|
356
|
+
field: string
|
|
357
|
+
}
|
|
358
|
+
prints?: PrintEventPrints
|
|
359
|
+
}) => TypedEventTrigger<PrintEventEvent>;
|
|
301
360
|
}
|
|
302
361
|
declare const on: TriggerHelpers;
|
|
303
362
|
/** Extract the event payload type from a trigger. */
|
|
@@ -18,11 +18,14 @@ var on = {
|
|
|
18
18
|
nftBurn: (f = {}) => make({ type: "nft_burn", ...f }),
|
|
19
19
|
contractCall: (f = {}) => make({ type: "contract_call", ...f }),
|
|
20
20
|
contractDeploy: (f = {}) => make({ type: "contract_deploy", ...f }),
|
|
21
|
-
printEvent: (f = {}) => make({
|
|
21
|
+
printEvent: (f = {}) => make({
|
|
22
|
+
type: "print_event",
|
|
23
|
+
...f
|
|
24
|
+
})
|
|
22
25
|
};
|
|
23
26
|
export {
|
|
24
27
|
on
|
|
25
28
|
};
|
|
26
29
|
|
|
27
|
-
//# debugId=
|
|
30
|
+
//# debugId=E8A9BFB4916AE4AF64756E2164756E21
|
|
28
31
|
//# sourceMappingURL=index.js.map
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/triggers/index.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"/**\n * Typed event-trigger helpers. Each helper returns a standard `EventTrigger`\n * plus a phantom `__event` type used for inference at consumer sites. The\n * phantom carries no runtime value.\n */\n\nimport type {\n\tContractCallFilter,\n\tContractDeployFilter,\n\tFtBurnFilter,\n\tFtMintFilter,\n\tFtTransferFilter,\n\tNftBurnFilter,\n\tNftMintFilter,\n\tNftTransferFilter,\n\tPrintEventFilter,\n\tStxBurnFilter,\n\tStxLockFilter,\n\tStxMintFilter,\n\tStxTransferFilter,\n} from \"../types.ts\";\nimport type { EventTrigger } from \"./types.ts\";\n\n// --- Per-filter event payload shapes ---\n\n/** Metadata shared by every event. */\nexport interface TxMeta {\n\ttxId: string;\n\tsender: string;\n\tblockHeight: number;\n\tblockTime: number;\n}\n\nexport interface StxTransferEvent {\n\tsender: string;\n\trecipient: string;\n\tamount: bigint;\n\tmemo: string | null;\n\ttx: TxMeta;\n}\n\nexport interface StxMintEvent {\n\trecipient: string;\n\tamount: bigint;\n\ttx: TxMeta;\n}\n\nexport interface StxBurnEvent {\n\tsender: string;\n\tamount: bigint;\n\ttx: TxMeta;\n}\n\nexport interface StxLockEvent {\n\tlockedAddress: string;\n\tamount: bigint;\n\tunlockHeight: number;\n\ttx: TxMeta;\n}\n\nexport interface FtTransferEvent {\n\tassetIdentifier: string;\n\tsender: string;\n\trecipient: string;\n\tamount: bigint;\n\ttx: TxMeta;\n}\n\nexport interface FtMintEvent {\n\tassetIdentifier: string;\n\trecipient: string;\n\tamount: bigint;\n\ttx: TxMeta;\n}\n\nexport interface FtBurnEvent {\n\tassetIdentifier: string;\n\tsender: string;\n\tamount: bigint;\n\ttx: TxMeta;\n}\n\nexport interface NftTransferEvent {\n\tassetIdentifier: string;\n\tsender: string;\n\trecipient: string;\n\ttokenId: string;\n\ttx: TxMeta;\n}\n\nexport interface NftMintEvent {\n\tassetIdentifier: string;\n\trecipient: string;\n\ttokenId: string;\n\ttx: TxMeta;\n}\n\nexport interface NftBurnEvent {\n\tassetIdentifier: string;\n\tsender: string;\n\ttokenId: string;\n\ttx: TxMeta;\n}\n\nexport interface ContractCallEvent {\n\tcontractId: string;\n\tfunctionName: string;\n\targs: unknown[];\n\tcaller: string;\n\ttx: TxMeta;\n}\n\nexport interface ContractDeployEvent {\n\tcontractId: string;\n\tdeployer: string;\n\tcontractName: string;\n\ttx: TxMeta;\n}\n\nexport interface PrintEventEvent {\n\tcontractId: string;\n\ttopic: string | null;\n\tvalue: unknown;\n\ttx: TxMeta;\n}\n\n// --- Typed trigger wrapper ---\n\n/**\n * Phantom-typed EventTrigger. Runtime shape is identical to `EventTrigger`;\n * the `__event` field only exists at the type level, letting subscription\n * definitions infer the handler's `event` parameter from the filter.\n */\nexport type TypedEventTrigger<TEvent> = EventTrigger & {\n\treadonly __event?: TEvent;\n};\n\nfunction make<TEvent>(\n\tfilter: EventTrigger[\"filter\"],\n): TypedEventTrigger<TEvent> {\n\treturn { type: \"event\", filter };\n}\n\n// --- `on.*` helpers, 13 total ---\n\nexport interface TriggerHelpers {\n\tstxTransfer: (\n\t\tf?: Omit<StxTransferFilter, \"type\">,\n\t) => TypedEventTrigger<StxTransferEvent>;\n\tstxMint: (f?: Omit<StxMintFilter, \"type\">) => TypedEventTrigger<StxMintEvent>;\n\tstxBurn: (f?: Omit<StxBurnFilter, \"type\">) => TypedEventTrigger<StxBurnEvent>;\n\tstxLock: (f?: Omit<StxLockFilter, \"type\">) => TypedEventTrigger<StxLockEvent>;\n\tftTransfer: (\n\t\tf?: Omit<FtTransferFilter, \"type\">,\n\t) => TypedEventTrigger<FtTransferEvent>;\n\tftMint: (f?: Omit<FtMintFilter, \"type\">) => TypedEventTrigger<FtMintEvent>;\n\tftBurn: (f?: Omit<FtBurnFilter, \"type\">) => TypedEventTrigger<FtBurnEvent>;\n\tnftTransfer: (\n\t\tf?: Omit<NftTransferFilter, \"type\">,\n\t) => TypedEventTrigger<NftTransferEvent>;\n\tnftMint: (f?: Omit<NftMintFilter, \"type\">) => TypedEventTrigger<NftMintEvent>;\n\tnftBurn: (f?: Omit<NftBurnFilter, \"type\">) => TypedEventTrigger<NftBurnEvent>;\n\tcontractCall: (\n\t\tf?: Omit<ContractCallFilter, \"type\">,\n\t) => TypedEventTrigger<ContractCallEvent>;\n\tcontractDeploy: (\n\t\tf?: Omit<ContractDeployFilter, \"type\">,\n\t) => TypedEventTrigger<ContractDeployEvent>;\n\tprintEvent: (\n\t\
|
|
5
|
+
"/**\n * Typed event-trigger helpers. Each helper returns a standard `EventTrigger`\n * plus a phantom `__event` type used for inference at consumer sites. The\n * phantom carries no runtime value.\n */\n\nimport type {\n\tContractCallFilter,\n\tContractDeployFilter,\n\tFtBurnFilter,\n\tFtMintFilter,\n\tFtTransferFilter,\n\tNftBurnFilter,\n\tNftMintFilter,\n\tNftTransferFilter,\n\tPrintEventFilter,\n\tPrintEventPrints,\n\tStxBurnFilter,\n\tStxLockFilter,\n\tStxMintFilter,\n\tStxTransferFilter,\n} from \"../types.ts\";\nimport type { EventTrigger } from \"./types.ts\";\n\n// --- Per-filter event payload shapes ---\n\n/** Metadata shared by every event. */\nexport interface TxMeta {\n\ttxId: string;\n\tsender: string;\n\tblockHeight: number;\n\tblockTime: number;\n}\n\nexport interface StxTransferEvent {\n\tsender: string;\n\trecipient: string;\n\tamount: bigint;\n\tmemo: string | null;\n\ttx: TxMeta;\n}\n\nexport interface StxMintEvent {\n\trecipient: string;\n\tamount: bigint;\n\ttx: TxMeta;\n}\n\nexport interface StxBurnEvent {\n\tsender: string;\n\tamount: bigint;\n\ttx: TxMeta;\n}\n\nexport interface StxLockEvent {\n\tlockedAddress: string;\n\tamount: bigint;\n\tunlockHeight: number;\n\ttx: TxMeta;\n}\n\nexport interface FtTransferEvent {\n\tassetIdentifier: string;\n\tsender: string;\n\trecipient: string;\n\tamount: bigint;\n\ttx: TxMeta;\n}\n\nexport interface FtMintEvent {\n\tassetIdentifier: string;\n\trecipient: string;\n\tamount: bigint;\n\ttx: TxMeta;\n}\n\nexport interface FtBurnEvent {\n\tassetIdentifier: string;\n\tsender: string;\n\tamount: bigint;\n\ttx: TxMeta;\n}\n\nexport interface NftTransferEvent {\n\tassetIdentifier: string;\n\tsender: string;\n\trecipient: string;\n\ttokenId: string;\n\ttx: TxMeta;\n}\n\nexport interface NftMintEvent {\n\tassetIdentifier: string;\n\trecipient: string;\n\ttokenId: string;\n\ttx: TxMeta;\n}\n\nexport interface NftBurnEvent {\n\tassetIdentifier: string;\n\tsender: string;\n\ttokenId: string;\n\ttx: TxMeta;\n}\n\nexport interface ContractCallEvent {\n\tcontractId: string;\n\tfunctionName: string;\n\targs: unknown[];\n\tcaller: string;\n\ttx: TxMeta;\n}\n\nexport interface ContractDeployEvent {\n\tcontractId: string;\n\tdeployer: string;\n\tcontractName: string;\n\ttx: TxMeta;\n}\n\nexport interface PrintEventEvent {\n\tcontractId: string;\n\ttopic: string | null;\n\tvalue: unknown;\n\ttx: TxMeta;\n}\n\n// --- Typed trigger wrapper ---\n\n/**\n * Phantom-typed EventTrigger. Runtime shape is identical to `EventTrigger`;\n * the `__event` field only exists at the type level, letting subscription\n * definitions infer the handler's `event` parameter from the filter.\n */\nexport type TypedEventTrigger<TEvent> = EventTrigger & {\n\treadonly __event?: TEvent;\n};\n\nfunction make<TEvent>(\n\tfilter: EventTrigger[\"filter\"],\n): TypedEventTrigger<TEvent> {\n\treturn { type: \"event\", filter };\n}\n\n// --- `on.*` helpers, 13 total ---\n\nexport interface TriggerHelpers {\n\tstxTransfer: (\n\t\tf?: Omit<StxTransferFilter, \"type\">,\n\t) => TypedEventTrigger<StxTransferEvent>;\n\tstxMint: (f?: Omit<StxMintFilter, \"type\">) => TypedEventTrigger<StxMintEvent>;\n\tstxBurn: (f?: Omit<StxBurnFilter, \"type\">) => TypedEventTrigger<StxBurnEvent>;\n\tstxLock: (f?: Omit<StxLockFilter, \"type\">) => TypedEventTrigger<StxLockEvent>;\n\tftTransfer: (\n\t\tf?: Omit<FtTransferFilter, \"type\">,\n\t) => TypedEventTrigger<FtTransferEvent>;\n\tftMint: (f?: Omit<FtMintFilter, \"type\">) => TypedEventTrigger<FtMintEvent>;\n\tftBurn: (f?: Omit<FtBurnFilter, \"type\">) => TypedEventTrigger<FtBurnEvent>;\n\tnftTransfer: (\n\t\tf?: Omit<NftTransferFilter, \"type\">,\n\t) => TypedEventTrigger<NftTransferEvent>;\n\tnftMint: (f?: Omit<NftMintFilter, \"type\">) => TypedEventTrigger<NftMintEvent>;\n\tnftBurn: (f?: Omit<NftBurnFilter, \"type\">) => TypedEventTrigger<NftBurnEvent>;\n\tcontractCall: (\n\t\tf?: Omit<ContractCallFilter, \"type\">,\n\t) => TypedEventTrigger<ContractCallEvent>;\n\tcontractDeploy: (\n\t\tf?: Omit<ContractDeployFilter, \"type\">,\n\t) => TypedEventTrigger<ContractDeployEvent>;\n\t/** Subscription triggers are not subgraph deploys — prints not required. */\n\tprintEvent: (f?: {\n\t\tcontractId?: string | readonly string[];\n\t\ttopic?: string;\n\t\ttrait?: string;\n\t\tfactory?: { from: string; field: string };\n\t\tprints?: PrintEventPrints;\n\t}) => TypedEventTrigger<PrintEventEvent>;\n}\n\nexport const on: TriggerHelpers = {\n\tstxTransfer: (f = {}) =>\n\t\tmake<StxTransferEvent>({ type: \"stx_transfer\", ...f }),\n\n\tstxMint: (f = {}) => make<StxMintEvent>({ type: \"stx_mint\", ...f }),\n\n\tstxBurn: (f = {}) => make<StxBurnEvent>({ type: \"stx_burn\", ...f }),\n\n\tstxLock: (f = {}) => make<StxLockEvent>({ type: \"stx_lock\", ...f }),\n\n\tftTransfer: (f = {}) => make<FtTransferEvent>({ type: \"ft_transfer\", ...f }),\n\n\tftMint: (f = {}) => make<FtMintEvent>({ type: \"ft_mint\", ...f }),\n\n\tftBurn: (f = {}) => make<FtBurnEvent>({ type: \"ft_burn\", ...f }),\n\n\tnftTransfer: (f = {}) =>\n\t\tmake<NftTransferEvent>({ type: \"nft_transfer\", ...f }),\n\n\tnftMint: (f = {}) => make<NftMintEvent>({ type: \"nft_mint\", ...f }),\n\n\tnftBurn: (f = {}) => make<NftBurnEvent>({ type: \"nft_burn\", ...f }),\n\n\tcontractCall: (f = {}) =>\n\t\tmake<ContractCallEvent>({ type: \"contract_call\", ...f }),\n\n\tcontractDeploy: (f = {}) =>\n\t\tmake<ContractDeployEvent>({ type: \"contract_deploy\", ...f }),\n\n\tprintEvent: (f = {}) =>\n\t\tmake<PrintEventEvent>({\n\t\t\ttype: \"print_event\",\n\t\t\t...f,\n\t\t} as PrintEventFilter),\n};\n\n/** Extract the event payload type from a trigger. */\nexport type EventOf<T> = T extends TypedEventTrigger<infer E> ? E : never;\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": ";;;;
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": ";;;;AA0IA,SAAS,IAAY,CACpB,QAC4B;AAAA,EAC5B,OAAO,EAAE,MAAM,SAAS,OAAO;AAAA;AAsCzB,IAAM,KAAqB;AAAA,EACjC,aAAa,CAAC,IAAI,CAAC,MAClB,KAAuB,EAAE,MAAM,mBAAmB,EAAE,CAAC;AAAA,EAEtD,SAAS,CAAC,IAAI,CAAC,MAAM,KAAmB,EAAE,MAAM,eAAe,EAAE,CAAC;AAAA,EAElE,SAAS,CAAC,IAAI,CAAC,MAAM,KAAmB,EAAE,MAAM,eAAe,EAAE,CAAC;AAAA,EAElE,SAAS,CAAC,IAAI,CAAC,MAAM,KAAmB,EAAE,MAAM,eAAe,EAAE,CAAC;AAAA,EAElE,YAAY,CAAC,IAAI,CAAC,MAAM,KAAsB,EAAE,MAAM,kBAAkB,EAAE,CAAC;AAAA,EAE3E,QAAQ,CAAC,IAAI,CAAC,MAAM,KAAkB,EAAE,MAAM,cAAc,EAAE,CAAC;AAAA,EAE/D,QAAQ,CAAC,IAAI,CAAC,MAAM,KAAkB,EAAE,MAAM,cAAc,EAAE,CAAC;AAAA,EAE/D,aAAa,CAAC,IAAI,CAAC,MAClB,KAAuB,EAAE,MAAM,mBAAmB,EAAE,CAAC;AAAA,EAEtD,SAAS,CAAC,IAAI,CAAC,MAAM,KAAmB,EAAE,MAAM,eAAe,EAAE,CAAC;AAAA,EAElE,SAAS,CAAC,IAAI,CAAC,MAAM,KAAmB,EAAE,MAAM,eAAe,EAAE,CAAC;AAAA,EAElE,cAAc,CAAC,IAAI,CAAC,MACnB,KAAwB,EAAE,MAAM,oBAAoB,EAAE,CAAC;AAAA,EAExD,gBAAgB,CAAC,IAAI,CAAC,MACrB,KAA0B,EAAE,MAAM,sBAAsB,EAAE,CAAC;AAAA,EAE5D,YAAY,CAAC,IAAI,CAAC,MACjB,KAAsB;AAAA,IACrB,MAAM;AAAA,OACH;AAAA,EACJ,CAAqB;AACvB;",
|
|
8
|
+
"debugId": "E8A9BFB4916AE4AF64756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
package/dist/src/types.d.ts
CHANGED
|
@@ -119,7 +119,12 @@ type TraitScope = {
|
|
|
119
119
|
*
|
|
120
120
|
* ```ts
|
|
121
121
|
* sources: {
|
|
122
|
-
* registry: {
|
|
122
|
+
* registry: {
|
|
123
|
+
* type: "print_event",
|
|
124
|
+
* contractId: REGISTRY,
|
|
125
|
+
* topic: "pool-created",
|
|
126
|
+
* prints: { "pool-created": { pool: "principal" } },
|
|
127
|
+
* },
|
|
123
128
|
* swaps: {
|
|
124
129
|
* type: "print_event",
|
|
125
130
|
* topic: "swap",
|
|
@@ -244,6 +249,9 @@ interface ContractCallFilter extends TraitScope, FactoryScope {
|
|
|
244
249
|
* decoded function arguments. Dev-provided; serialized into the deployed
|
|
245
250
|
* definition and used at runtime to decode args by name. Omit to keep
|
|
246
251
|
* `event.args` as a positional `unknown[]`.
|
|
252
|
+
*
|
|
253
|
+
* Deploy validation requires `abi` whenever `functionName` is set
|
|
254
|
+
* (`normalizeAbi()` from `@secondlayer/stacks/clarity`).
|
|
247
255
|
*/
|
|
248
256
|
abi?: AbiContract2;
|
|
249
257
|
}
|
|
@@ -274,29 +282,70 @@ type PrintField = ColumnType | {
|
|
|
274
282
|
} | {
|
|
275
283
|
list: PrintField
|
|
276
284
|
};
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
285
|
+
/**
|
|
286
|
+
* Per-topic field schema for a print_event source. When declared, the handler's
|
|
287
|
+
* `event` is a discriminated union keyed by `topic` and `event.data` is typed
|
|
288
|
+
* per topic. Nested tuples, lists, and optional fields — see {@link PrintField}.
|
|
289
|
+
*
|
|
290
|
+
* Also opts the source into RUNTIME validation: a payload that does not match
|
|
291
|
+
* is skipped and logged rather than written as nulls.
|
|
292
|
+
*/
|
|
293
|
+
type PrintEventPrints = Record<string, Record<string, PrintField>>;
|
|
294
|
+
/**
|
|
295
|
+
* One column in a static identity map. Literals only — the bundler never
|
|
296
|
+
* executes user code, so `{ from: "tokenX" }` is valid and `from("tokenX")`
|
|
297
|
+
* is not.
|
|
298
|
+
*/
|
|
299
|
+
type MaterializeColumn = {
|
|
300
|
+
from: string
|
|
301
|
+
} | {
|
|
302
|
+
fromTx: "sender" | "txId"
|
|
303
|
+
} | {
|
|
304
|
+
fromBlock: "height" | "hash" | "timestamp"
|
|
305
|
+
};
|
|
306
|
+
/** Static insert from a source event — replaces a 1:1 handler. */
|
|
307
|
+
interface MaterializeSpec {
|
|
308
|
+
table: string;
|
|
309
|
+
/** Keys = schema column names (snake). */
|
|
310
|
+
columns: Record<string, MaterializeColumn>;
|
|
299
311
|
}
|
|
312
|
+
type PrintEventFields = FactoryScope & {
|
|
313
|
+
type: "print_event"
|
|
314
|
+
topic?: string
|
|
315
|
+
/** Identity map: insert without a handler function. XOR with handlers[name]. */
|
|
316
|
+
materialize?: MaterializeSpec
|
|
317
|
+
};
|
|
318
|
+
/**
|
|
319
|
+
* Pinned to one or more contract ids with no trait — `prints` is required so
|
|
320
|
+
* `event.data` is typed and empty-table handlers cannot typecheck.
|
|
321
|
+
*/
|
|
322
|
+
type PinnedPrintEventFilter = PrintEventFields & {
|
|
323
|
+
contractId: string | readonly string[]
|
|
324
|
+
trait?: undefined
|
|
325
|
+
prints: PrintEventPrints
|
|
326
|
+
};
|
|
327
|
+
/**
|
|
328
|
+
* Trait-scoped print source (optionally narrowed by contractId). No single
|
|
329
|
+
* schema — `prints` stays optional.
|
|
330
|
+
*/
|
|
331
|
+
type TraitPrintEventFilter = PrintEventFields & {
|
|
332
|
+
contractId?: string | readonly string[]
|
|
333
|
+
trait: string
|
|
334
|
+
prints?: PrintEventPrints
|
|
335
|
+
};
|
|
336
|
+
/**
|
|
337
|
+
* Unpinned / factory-only print source (no contractId). `prints` optional.
|
|
338
|
+
*/
|
|
339
|
+
type UnpinnedPrintEventFilter = PrintEventFields & {
|
|
340
|
+
contractId?: undefined
|
|
341
|
+
trait?: string
|
|
342
|
+
prints?: PrintEventPrints
|
|
343
|
+
};
|
|
344
|
+
/**
|
|
345
|
+
* Print-event filter. Pinned sources (contractId set, no trait) require
|
|
346
|
+
* `prints`; trait and unpinned sources may omit it.
|
|
347
|
+
*/
|
|
348
|
+
type PrintEventFilter = PinnedPrintEventFilter | TraitPrintEventFilter | UnpinnedPrintEventFilter;
|
|
300
349
|
/** All subgraph filter types — discriminated on `type` */
|
|
301
350
|
type SubgraphFilter = StxTransferFilter | StxMintFilter | StxBurnFilter | StxLockFilter | FtTransferFilter | FtMintFilter | FtBurnFilter | NftTransferFilter | NftMintFilter | NftBurnFilter | ContractCallFilter | ContractDeployFilter | PrintEventFilter;
|
|
302
351
|
/** Transaction metadata available in handlers */
|
|
@@ -386,4 +435,4 @@ interface SubgraphDefinition {
|
|
|
386
435
|
/** Handler functions — keys must match source names (or "*" for catch-all) */
|
|
387
436
|
handlers: Record<string, SubgraphHandler>;
|
|
388
437
|
}
|
|
389
|
-
export { TxMeta, SubgraphTable, SubgraphSchema, SubgraphRelation, SubgraphHandler, SubgraphFilter, SubgraphDefinition, SubgraphContext, SubgraphColumn, StxTransferFilter, StxMintFilter, StxLockFilter, StxBurnFilter, RowValue, PrintField, PrintEventFilter, NftTransferFilter, NftMintFilter, NftBurnFilter, FtTransferFilter, FtMintFilter, FtBurnFilter, FactoryScope, ContractDeployFilter, ContractCallFilter, ContractCallEvent, ComputedValue, ColumnType };
|
|
438
|
+
export { UnpinnedPrintEventFilter, TxMeta, TraitPrintEventFilter, SubgraphTable, SubgraphSchema, SubgraphRelation, SubgraphHandler, SubgraphFilter, SubgraphDefinition, SubgraphContext, SubgraphColumn, StxTransferFilter, StxMintFilter, StxLockFilter, StxBurnFilter, RowValue, PrintField, PrintEventPrints, PrintEventFilter, PinnedPrintEventFilter, NftTransferFilter, NftMintFilter, NftBurnFilter, MaterializeSpec, MaterializeColumn, FtTransferFilter, FtMintFilter, FtBurnFilter, FactoryScope, ContractDeployFilter, ContractCallFilter, ContractCallEvent, ComputedValue, ColumnType };
|
package/dist/src/validate.d.ts
CHANGED
|
@@ -119,7 +119,12 @@ type TraitScope = {
|
|
|
119
119
|
*
|
|
120
120
|
* ```ts
|
|
121
121
|
* sources: {
|
|
122
|
-
* registry: {
|
|
122
|
+
* registry: {
|
|
123
|
+
* type: "print_event",
|
|
124
|
+
* contractId: REGISTRY,
|
|
125
|
+
* topic: "pool-created",
|
|
126
|
+
* prints: { "pool-created": { pool: "principal" } },
|
|
127
|
+
* },
|
|
123
128
|
* swaps: {
|
|
124
129
|
* type: "print_event",
|
|
125
130
|
* topic: "swap",
|
|
@@ -203,6 +208,9 @@ interface ContractCallFilter extends TraitScope, FactoryScope {
|
|
|
203
208
|
* decoded function arguments. Dev-provided; serialized into the deployed
|
|
204
209
|
* definition and used at runtime to decode args by name. Omit to keep
|
|
205
210
|
* `event.args` as a positional `unknown[]`.
|
|
211
|
+
*
|
|
212
|
+
* Deploy validation requires `abi` whenever `functionName` is set
|
|
213
|
+
* (`normalizeAbi()` from `@secondlayer/stacks/clarity`).
|
|
206
214
|
*/
|
|
207
215
|
abi?: AbiContract2;
|
|
208
216
|
}
|
|
@@ -233,29 +241,70 @@ type PrintField = ColumnType | {
|
|
|
233
241
|
} | {
|
|
234
242
|
list: PrintField
|
|
235
243
|
};
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
244
|
+
/**
|
|
245
|
+
* Per-topic field schema for a print_event source. When declared, the handler's
|
|
246
|
+
* `event` is a discriminated union keyed by `topic` and `event.data` is typed
|
|
247
|
+
* per topic. Nested tuples, lists, and optional fields — see {@link PrintField}.
|
|
248
|
+
*
|
|
249
|
+
* Also opts the source into RUNTIME validation: a payload that does not match
|
|
250
|
+
* is skipped and logged rather than written as nulls.
|
|
251
|
+
*/
|
|
252
|
+
type PrintEventPrints = Record<string, Record<string, PrintField>>;
|
|
253
|
+
/**
|
|
254
|
+
* One column in a static identity map. Literals only — the bundler never
|
|
255
|
+
* executes user code, so `{ from: "tokenX" }` is valid and `from("tokenX")`
|
|
256
|
+
* is not.
|
|
257
|
+
*/
|
|
258
|
+
type MaterializeColumn = {
|
|
259
|
+
from: string
|
|
260
|
+
} | {
|
|
261
|
+
fromTx: "sender" | "txId"
|
|
262
|
+
} | {
|
|
263
|
+
fromBlock: "height" | "hash" | "timestamp"
|
|
264
|
+
};
|
|
265
|
+
/** Static insert from a source event — replaces a 1:1 handler. */
|
|
266
|
+
interface MaterializeSpec {
|
|
267
|
+
table: string;
|
|
268
|
+
/** Keys = schema column names (snake). */
|
|
269
|
+
columns: Record<string, MaterializeColumn>;
|
|
258
270
|
}
|
|
271
|
+
type PrintEventFields = FactoryScope & {
|
|
272
|
+
type: "print_event"
|
|
273
|
+
topic?: string
|
|
274
|
+
/** Identity map: insert without a handler function. XOR with handlers[name]. */
|
|
275
|
+
materialize?: MaterializeSpec
|
|
276
|
+
};
|
|
277
|
+
/**
|
|
278
|
+
* Pinned to one or more contract ids with no trait — `prints` is required so
|
|
279
|
+
* `event.data` is typed and empty-table handlers cannot typecheck.
|
|
280
|
+
*/
|
|
281
|
+
type PinnedPrintEventFilter = PrintEventFields & {
|
|
282
|
+
contractId: string | readonly string[]
|
|
283
|
+
trait?: undefined
|
|
284
|
+
prints: PrintEventPrints
|
|
285
|
+
};
|
|
286
|
+
/**
|
|
287
|
+
* Trait-scoped print source (optionally narrowed by contractId). No single
|
|
288
|
+
* schema — `prints` stays optional.
|
|
289
|
+
*/
|
|
290
|
+
type TraitPrintEventFilter = PrintEventFields & {
|
|
291
|
+
contractId?: string | readonly string[]
|
|
292
|
+
trait: string
|
|
293
|
+
prints?: PrintEventPrints
|
|
294
|
+
};
|
|
295
|
+
/**
|
|
296
|
+
* Unpinned / factory-only print source (no contractId). `prints` optional.
|
|
297
|
+
*/
|
|
298
|
+
type UnpinnedPrintEventFilter = PrintEventFields & {
|
|
299
|
+
contractId?: undefined
|
|
300
|
+
trait?: string
|
|
301
|
+
prints?: PrintEventPrints
|
|
302
|
+
};
|
|
303
|
+
/**
|
|
304
|
+
* Print-event filter. Pinned sources (contractId set, no trait) require
|
|
305
|
+
* `prints`; trait and unpinned sources may omit it.
|
|
306
|
+
*/
|
|
307
|
+
type PrintEventFilter = PinnedPrintEventFilter | TraitPrintEventFilter | UnpinnedPrintEventFilter;
|
|
259
308
|
/** All subgraph filter types — discriminated on `type` */
|
|
260
309
|
type SubgraphFilter = StxTransferFilter | StxMintFilter | StxBurnFilter | StxLockFilter | FtTransferFilter | FtMintFilter | FtBurnFilter | NftTransferFilter | NftMintFilter | NftBurnFilter | ContractCallFilter | ContractDeployFilter | PrintEventFilter;
|
|
261
310
|
/** Transaction metadata available in handlers */
|
package/dist/src/validate.js
CHANGED
|
@@ -98,6 +98,15 @@ var amountRange = {
|
|
|
98
98
|
minAmount: z.bigint().optional(),
|
|
99
99
|
maxAmount: z.bigint().optional()
|
|
100
100
|
};
|
|
101
|
+
var MaterializeColumnSchema = z.union([
|
|
102
|
+
z.object({ from: z.string().min(1) }).strict(),
|
|
103
|
+
z.object({ fromTx: z.enum(["sender", "txId"]) }).strict(),
|
|
104
|
+
z.object({ fromBlock: z.enum(["height", "hash", "timestamp"]) }).strict()
|
|
105
|
+
]);
|
|
106
|
+
var MaterializeSpecSchema = z.object({
|
|
107
|
+
table: z.string().min(1),
|
|
108
|
+
columns: z.record(z.string(), MaterializeColumnSchema)
|
|
109
|
+
}).strict();
|
|
101
110
|
var SubgraphFilterUnion = z.discriminatedUnion("type", [
|
|
102
111
|
z.object({
|
|
103
112
|
type: z.literal("stx_transfer"),
|
|
@@ -180,11 +189,114 @@ var SubgraphFilterUnion = z.discriminatedUnion("type", [
|
|
|
180
189
|
contractId: contractIdField.optional(),
|
|
181
190
|
topic: z.string().optional(),
|
|
182
191
|
prints: z.record(z.string(), z.record(z.string(), PrintFieldSchema)).optional(),
|
|
192
|
+
materialize: MaterializeSpecSchema.optional(),
|
|
183
193
|
...traitScope,
|
|
184
194
|
...factoryScope
|
|
185
195
|
}).strict()
|
|
186
196
|
]);
|
|
187
197
|
var SubgraphFilterSchema = SubgraphFilterUnion;
|
|
198
|
+
function hasPinnedContractId(contractId) {
|
|
199
|
+
if (typeof contractId === "string")
|
|
200
|
+
return contractId.length > 0;
|
|
201
|
+
if (Array.isArray(contractId))
|
|
202
|
+
return contractId.length > 0;
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
205
|
+
function printMaterializeFromKeys(prints) {
|
|
206
|
+
const keys = new Set(["topic"]);
|
|
207
|
+
if (prints) {
|
|
208
|
+
for (const fields of Object.values(prints)) {
|
|
209
|
+
for (const k of Object.keys(fields))
|
|
210
|
+
keys.add(k);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return [...keys].sort();
|
|
214
|
+
}
|
|
215
|
+
function refineMaterialize(name, filter, schema, ctx) {
|
|
216
|
+
if (!("materialize" in filter) || filter.materialize === undefined)
|
|
217
|
+
return;
|
|
218
|
+
const spec = filter.materialize;
|
|
219
|
+
const table = schema[spec.table];
|
|
220
|
+
if (!table) {
|
|
221
|
+
ctx.addIssue({
|
|
222
|
+
code: "custom",
|
|
223
|
+
path: ["sources", name, "materialize", "table"],
|
|
224
|
+
message: `materialize table "${spec.table}" is not in schema`
|
|
225
|
+
});
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
for (const col of Object.keys(spec.columns)) {
|
|
229
|
+
if (!(col in table.columns)) {
|
|
230
|
+
ctx.addIssue({
|
|
231
|
+
code: "custom",
|
|
232
|
+
path: ["sources", name, "materialize", "columns", col],
|
|
233
|
+
message: `materialize column "${col}" is not on schema table "${spec.table}"`
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
if (filter.type === "print_event") {
|
|
238
|
+
const known = printMaterializeFromKeys(filter.prints);
|
|
239
|
+
const knownSet = new Set(known);
|
|
240
|
+
for (const [col, mapping] of Object.entries(spec.columns)) {
|
|
241
|
+
if (!("from" in mapping))
|
|
242
|
+
continue;
|
|
243
|
+
if (!knownSet.has(mapping.from)) {
|
|
244
|
+
ctx.addIssue({
|
|
245
|
+
code: "custom",
|
|
246
|
+
path: ["sources", name, "materialize", "columns", col, "from"],
|
|
247
|
+
message: `materialize from "${mapping.from}" is not a known print field — known: ${known.join(", ")}`
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
function refineDeployGates(def, ctx) {
|
|
254
|
+
for (const [name, filter] of Object.entries(def.sources)) {
|
|
255
|
+
if (filter.type === "print_event") {
|
|
256
|
+
const pinned = hasPinnedContractId(filter.contractId) && !filter.trait;
|
|
257
|
+
if (pinned) {
|
|
258
|
+
const prints = filter.prints;
|
|
259
|
+
if (prints === undefined || typeof prints !== "object" || Object.keys(prints).length === 0) {
|
|
260
|
+
ctx.addIssue({
|
|
261
|
+
code: "custom",
|
|
262
|
+
path: ["sources", name, "prints"],
|
|
263
|
+
message: `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.`
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
if (filter.type === "contract_call" && filter.functionName !== undefined) {
|
|
269
|
+
if (filter.abi === undefined) {
|
|
270
|
+
ctx.addIssue({
|
|
271
|
+
code: "custom",
|
|
272
|
+
path: ["sources", name, "abi"],
|
|
273
|
+
message: `contract_call source "${name}" has functionName but no abi — pass a canonical ABI (normalizeAbi() from @secondlayer/stacks/clarity).`
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
refineMaterialize(name, filter, def.schema, ctx);
|
|
278
|
+
}
|
|
279
|
+
const hasCatchAll = def.handlers["*"] != null;
|
|
280
|
+
for (const [name, filter] of Object.entries(def.sources)) {
|
|
281
|
+
const hasMaterialize = "materialize" in filter && filter.materialize !== undefined;
|
|
282
|
+
const hasHandler = def.handlers[name] != null;
|
|
283
|
+
if (hasMaterialize && hasHandler) {
|
|
284
|
+
ctx.addIssue({
|
|
285
|
+
code: "custom",
|
|
286
|
+
path: ["handlers", name],
|
|
287
|
+
message: `source "${name}" has both materialize and a handler — use one or the other`
|
|
288
|
+
});
|
|
289
|
+
continue;
|
|
290
|
+
}
|
|
291
|
+
if (!hasHandler && !hasMaterialize && !hasCatchAll) {
|
|
292
|
+
ctx.addIssue({
|
|
293
|
+
code: "custom",
|
|
294
|
+
path: ["handlers", name],
|
|
295
|
+
message: `source "${name}" has no handler (and no "*") — events will be skipped and the table stay empty.`
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
188
300
|
var SubgraphDefinitionSchema = z.object({
|
|
189
301
|
name: SubgraphNameSchema,
|
|
190
302
|
version: z.string().optional(),
|
|
@@ -194,6 +306,8 @@ var SubgraphDefinitionSchema = z.object({
|
|
|
194
306
|
sources: z.record(z.string(), SubgraphFilterSchema).refine((s) => Object.keys(s).length > 0, "Must have at least one source"),
|
|
195
307
|
schema: SubgraphSchemaSchema,
|
|
196
308
|
handlers: z.record(z.string(), z.any())
|
|
309
|
+
}).superRefine((def, ctx) => {
|
|
310
|
+
refineDeployGates(def, ctx);
|
|
197
311
|
});
|
|
198
312
|
function validateSubgraphDefinition(def) {
|
|
199
313
|
return SubgraphDefinitionSchema.parse(def);
|
|
@@ -231,5 +345,5 @@ export {
|
|
|
231
345
|
AbiContractSchema
|
|
232
346
|
};
|
|
233
347
|
|
|
234
|
-
//# debugId=
|
|
348
|
+
//# debugId=F1208BA1BE21EB0E64756E2164756E21
|
|
235
349
|
//# sourceMappingURL=validate.js.map
|