@secondlayer/subgraphs 2.0.8 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -246,11 +246,249 @@ declare function backfillSubgraph(def: SubgraphDefinition, opts: {
246
246
  }): Promise<{
247
247
  processed: number
248
248
  }>;
249
+ interface FtTransferPayload {
250
+ sender: string;
251
+ recipient: string;
252
+ amount: bigint;
253
+ assetIdentifier: string;
254
+ tx: TxMeta;
255
+ }
256
+ interface FtMintPayload {
257
+ recipient: string;
258
+ amount: bigint;
259
+ assetIdentifier: string;
260
+ tx: TxMeta;
261
+ }
262
+ interface FtBurnPayload {
263
+ sender: string;
264
+ amount: bigint;
265
+ assetIdentifier: string;
266
+ tx: TxMeta;
267
+ }
268
+ interface NftTransferPayload {
269
+ sender: string;
270
+ recipient: string;
271
+ tokenId: unknown;
272
+ assetIdentifier: string;
273
+ tx: TxMeta;
274
+ }
275
+ interface NftMintPayload {
276
+ recipient: string;
277
+ tokenId: unknown;
278
+ assetIdentifier: string;
279
+ tx: TxMeta;
280
+ }
281
+ interface NftBurnPayload {
282
+ sender: string;
283
+ tokenId: unknown;
284
+ assetIdentifier: string;
285
+ tx: TxMeta;
286
+ }
287
+ interface StxTransferPayload {
288
+ sender: string;
289
+ recipient: string;
290
+ amount: bigint;
291
+ /** Memo string, or "" when none was attached. */
292
+ memo: string;
293
+ tx: TxMeta;
294
+ }
295
+ interface StxMintPayload {
296
+ recipient: string;
297
+ amount: bigint;
298
+ tx: TxMeta;
299
+ }
300
+ interface StxBurnPayload {
301
+ sender: string;
302
+ amount: bigint;
303
+ tx: TxMeta;
304
+ }
305
+ interface StxLockPayload {
306
+ lockedAddress: string;
307
+ lockedAmount: bigint;
308
+ unlockHeight: bigint;
309
+ tx: TxMeta;
310
+ }
311
+ interface PrintEventPayload {
312
+ contractId: string;
313
+ /** Decoded print topic (the Clarity tuple's `topic` field), or "". */
314
+ topic: string;
315
+ /**
316
+ * Remaining decoded tuple fields, camelCased. Empty object when the print
317
+ * value isn't a tuple. Narrow per `topic` to access typed fields.
318
+ */
319
+ data: Record<string, unknown>;
320
+ tx: TxMeta;
321
+ }
322
+ interface ContractDeployPayload {
323
+ contractId: string;
324
+ deployer: string;
325
+ tx: TxMeta;
326
+ }
327
+ /** The event payload a handler receives for a given source filter. */
328
+ type EventForFilter<F extends SubgraphFilter> = F extends {
329
+ type: "print_event"
330
+ } ? PrintEventPayload : F extends {
331
+ type: "ft_transfer"
332
+ } ? FtTransferPayload : F extends {
333
+ type: "ft_mint"
334
+ } ? FtMintPayload : F extends {
335
+ type: "ft_burn"
336
+ } ? FtBurnPayload : F extends {
337
+ type: "nft_transfer"
338
+ } ? NftTransferPayload : F extends {
339
+ type: "nft_mint"
340
+ } ? NftMintPayload : F extends {
341
+ type: "nft_burn"
342
+ } ? NftBurnPayload : F extends {
343
+ type: "stx_transfer"
344
+ } ? StxTransferPayload : F extends {
345
+ type: "stx_mint"
346
+ } ? StxMintPayload : F extends {
347
+ type: "stx_burn"
348
+ } ? StxBurnPayload : F extends {
349
+ type: "stx_lock"
350
+ } ? StxLockPayload : F extends {
351
+ type: "contract_call"
352
+ } ? ContractCallEvent : F extends {
353
+ type: "contract_deploy"
354
+ } ? ContractDeployPayload : never;
355
+ /** Union of every event payload — the `"*"` catch-all handler receives this. */
356
+ type AnyEvent = FtTransferPayload | FtMintPayload | FtBurnPayload | NftTransferPayload | NftMintPayload | NftBurnPayload | StxTransferPayload | StxMintPayload | StxBurnPayload | StxLockPayload | PrintEventPayload | ContractCallEvent | ContractDeployPayload;
357
+ /** Maps a ColumnType string literal to its TypeScript equivalent */
358
+ type ColumnToTS<T extends string> = T extends "uint" | "int" ? bigint : T extends "text" | "principal" | "timestamp" ? string : T extends "boolean" ? boolean : T extends "jsonb" ? Record<string, unknown> : unknown;
359
+ /** Infer TS type for a single column definition, respecting nullable */
360
+ type InferColumnType<C extends SubgraphColumn> = C["type"] extends ColumnType ? C["nullable"] extends true ? ColumnToTS<C["type"]> | null : ColumnToTS<C["type"]> : unknown;
361
+ /** Shape of system columns on every returned row (camelCase, underscore-prefixed) */
362
+ interface SystemRow {
363
+ _id: string;
364
+ _blockHeight: bigint;
365
+ _txId: string;
366
+ _createdAt: string;
367
+ }
368
+ /** Infer the row shape for a single table definition */
369
+ type InferTableRow<T extends SubgraphTable> = SystemRow & { [K in keyof T["columns"]] : InferColumnType<T["columns"][K]> };
370
+ /** Comparison operators for a scalar value */
371
+ type ComparisonFilter<T> = {
372
+ eq?: T
373
+ neq?: T
374
+ gt?: T
375
+ gte?: T
376
+ lt?: T
377
+ lte?: T
378
+ };
379
+ /** Where clause — each column accepts a scalar (eq) or comparison object */
380
+ type WhereInput<TRow> = { [K in keyof TRow]? : TRow[K] | ComparisonFilter<TRow[K]> };
249
381
  /**
250
- * Identity function that preserves schema literal types for type inference.
382
+ * No-prefix aliases for system columns accepted in where/orderBy inputs.
383
+ * Both `_blockHeight` and `blockHeight` are valid — serializer handles mapping.
384
+ */
385
+ type SystemWhereAliases = {
386
+ blockHeight?: bigint | ComparisonFilter<bigint>
387
+ txId?: string | ComparisonFilter<string>
388
+ createdAt?: string | ComparisonFilter<string>
389
+ id?: string | ComparisonFilter<string>
390
+ };
391
+ type SystemOrderByAliases = {
392
+ blockHeight?: "asc" | "desc"
393
+ txId?: "asc" | "desc"
394
+ createdAt?: "asc" | "desc"
395
+ id?: "asc" | "desc"
396
+ };
397
+ interface FindManyOptions<TRow> {
398
+ where?: WhereInput<TRow> & SystemWhereAliases;
399
+ orderBy?: { [K in keyof TRow]? : "asc" | "desc" } & SystemOrderByAliases;
400
+ limit?: number;
401
+ offset?: number;
402
+ fields?: (keyof TRow & string)[];
403
+ }
404
+ interface SubgraphTableClient<TRow> {
405
+ findMany(options?: FindManyOptions<TRow>): Promise<TRow[]>;
406
+ count(where?: WhereInput<TRow> & SystemWhereAliases): Promise<number>;
407
+ }
408
+ /** A column is optional on insert when it's nullable or has a SQL default. */
409
+ type IsOptionalColumn<C> = C extends {
410
+ nullable: true
411
+ } ? true : C extends {
412
+ default: string | number | boolean
413
+ } ? true : false;
414
+ /**
415
+ * Row shape accepted by `ctx.insert`. System columns (`_id`, `_blockHeight`,
416
+ * `_txId`, `_createdAt`) are omitted — the runtime adds them. Nullable and
417
+ * defaulted columns are optional; all others required.
418
+ */
419
+ type WriteRow<T extends SubgraphTable> = { [K in keyof T["columns"] as IsOptionalColumn<T["columns"][K]> extends true ? never : K] : InferColumnType<T["columns"][K]> } & { [K in keyof T["columns"] as IsOptionalColumn<T["columns"][K]> extends true ? K : never]? : InferColumnType<T["columns"][K]> };
420
+ /** Computed-or-value row for `patchOrInsert` — each field may be a function of the existing row. */
421
+ type PatchRow<T extends SubgraphTable> = { [K in keyof WriteRow<T>]? : WriteRow<T>[K] | ((existing: InferTableRow<T> | null) => unknown) };
422
+ type TableName<S extends SubgraphSchema> = keyof S & string;
423
+ type ColumnName<
424
+ S extends SubgraphSchema,
425
+ T extends TableName<S>
426
+ > = keyof S[T]["columns"] & string;
427
+ type RowWhere<
428
+ S extends SubgraphSchema,
429
+ T extends TableName<S>
430
+ > = WhereInput<InferTableRow<S[T]>>;
431
+ /**
432
+ * Schema-typed handler context. Mirrors the runtime `SubgraphContext` but
433
+ * checks table names against `S` and row/where shapes against each table's
434
+ * columns. The runtime passes the concrete (untyped) context — this facade is
435
+ * type-level only.
436
+ */
437
+ interface TypedSubgraphContext<S extends SubgraphSchema> {
438
+ block: {
439
+ height: number
440
+ hash: string
441
+ timestamp: number
442
+ burnBlockHeight: number
443
+ };
444
+ tx: TxMeta;
445
+ insert<T extends TableName<S>>(table: T, row: WriteRow<S[T]>): void;
446
+ update<T extends TableName<S>>(table: T, where: RowWhere<S, T>, set: Partial<WriteRow<S[T]>>): void;
447
+ upsert<T extends TableName<S>>(table: T, key: Partial<WriteRow<S[T]>>, row: WriteRow<S[T]>): void;
448
+ delete<T extends TableName<S>>(table: T, where: RowWhere<S, T>): void;
449
+ patch<T extends TableName<S>>(table: T, where: RowWhere<S, T>, set: Partial<WriteRow<S[T]>>): void;
450
+ patchOrInsert<T extends TableName<S>>(table: T, key: Partial<WriteRow<S[T]>>, row: PatchRow<S[T]> & Record<string, ComputedValue>): Promise<void>;
451
+ findOne<T extends TableName<S>>(table: T, where: RowWhere<S, T>): Promise<InferTableRow<S[T]> | null>;
452
+ findMany<T extends TableName<S>>(table: T, where: RowWhere<S, T>): Promise<InferTableRow<S[T]>[]>;
453
+ formatUnits(value: bigint, decimals: number): string;
454
+ count<T extends TableName<S>>(table: T, where?: RowWhere<S, T>): Promise<number>;
455
+ sum<T extends TableName<S>>(table: T, column: ColumnName<S, T>, where?: RowWhere<S, T>): Promise<bigint>;
456
+ min<T extends TableName<S>>(table: T, column: ColumnName<S, T>, where?: RowWhere<S, T>): Promise<bigint | null>;
457
+ max<T extends TableName<S>>(table: T, column: ColumnName<S, T>, where?: RowWhere<S, T>): Promise<bigint | null>;
458
+ countDistinct<T extends TableName<S>>(table: T, column: ColumnName<S, T>, where?: RowWhere<S, T>): Promise<number>;
459
+ }
460
+ /** Infer a typed client object from a subgraph definition shape */
461
+ type InferSubgraphClient<T> = T extends {
462
+ schema: infer S
463
+ } ? { [K in keyof S] : S[K] extends SubgraphTable ? SubgraphTableClient<InferTableRow<S[K]>> : never } : never;
464
+ /**
465
+ * Handlers keyed by source name. Each handler's `event` is typed from the
466
+ * matching source's filter `type` (e.g. a `print_event` source → `event.topic`
467
+ * is a `string`), and `ctx` is typed against the subgraph `schema` (table
468
+ * names + row columns checked). The optional `"*"` catch-all receives any event.
251
469
  *
252
- * The generic `S` is narrowed to the exact schema shape so that column type
253
- * literals (e.g. `"uint"`) are preserved rather than widened to `string`.
470
+ * Handlers are optional per source (a source with no handler is skipped at
471
+ * runtime), matching `handlers[name] ?? handlers["*"]` resolution.
472
+ */
473
+ type TypedHandlers<
474
+ Sources extends Record<string, SubgraphFilter>,
475
+ S extends SubgraphSchema
476
+ > = { [K in keyof Sources]? : (event: EventForFilter<Sources[K]>, ctx: TypedSubgraphContext<S>) => void | Promise<void> } & {
477
+ "*"?: (event: AnyEvent, ctx: TypedSubgraphContext<S>) => void | Promise<void>
478
+ };
479
+ /** Subgraph definition with `sources`/`schema` literals preserved for typed
480
+ * handlers and downstream query-client inference (`getSubgraph`). */
481
+ type TypedSubgraphDefinition<
482
+ Sources extends Record<string, SubgraphFilter>,
483
+ S extends SubgraphSchema
484
+ > = Omit<SubgraphDefinition, "sources" | "schema" | "handlers"> & {
485
+ sources: Sources
486
+ schema: S
487
+ handlers: TypedHandlers<Sources, S>
488
+ };
489
+ /**
490
+ * Identity function that preserves `sources` and `schema` literal types so
491
+ * handlers are typed per source and the schema drives query-client inference.
254
492
  *
255
493
  * @example
256
494
  * ```ts
@@ -258,15 +496,19 @@ declare function backfillSubgraph(def: SubgraphDefinition, opts: {
258
496
  * name: "my-subgraph",
259
497
  * sources: { transfer: { type: "ft_transfer", assetIdentifier: "SP...::token" } },
260
498
  * schema: { transfers: { columns: { amount: { type: "uint" } } } },
261
- * handlers: { transfer: (event, ctx) => { ... } }
262
- * })
499
+ * handlers: {
500
+ * transfer: (event, ctx) => {
501
+ * // event: FtTransferPayload → event.amount is bigint, no cast
502
+ * ctx.insert("transfers", { amount: event.amount });
503
+ * },
504
+ * },
505
+ * });
263
506
  * ```
264
507
  */
265
- declare function defineSubgraph<S extends SubgraphSchema>(def: Omit<SubgraphDefinition, "schema"> & {
266
- schema: S
267
- }): Omit<SubgraphDefinition, "schema"> & {
268
- schema: S
269
- };
508
+ declare function defineSubgraph<
509
+ const Sources extends Record<string, SubgraphFilter>,
510
+ const S extends SubgraphSchema
511
+ >(def: TypedSubgraphDefinition<Sources, S>): TypedSubgraphDefinition<Sources, S>;
270
512
  interface GeneratedSQL {
271
513
  statements: string[];
272
514
  hash: string;
@@ -325,59 +567,4 @@ declare function deploySchema(db: AnyDb, def: SubgraphDefinition, handlerPath: s
325
567
  version: string
326
568
  diff?: DeployDiff
327
569
  }>;
328
- /** Maps a ColumnType string literal to its TypeScript equivalent */
329
- type ColumnToTS<T extends string> = T extends "uint" | "int" ? bigint : T extends "text" | "principal" | "timestamp" ? string : T extends "boolean" ? boolean : T extends "jsonb" ? Record<string, unknown> : unknown;
330
- /** Infer TS type for a single column definition, respecting nullable */
331
- type InferColumnType<C extends SubgraphColumn> = C["type"] extends ColumnType ? C["nullable"] extends true ? ColumnToTS<C["type"]> | null : ColumnToTS<C["type"]> : unknown;
332
- /** Shape of system columns on every returned row (camelCase, underscore-prefixed) */
333
- interface SystemRow {
334
- _id: string;
335
- _blockHeight: bigint;
336
- _txId: string;
337
- _createdAt: string;
338
- }
339
- /** Infer the row shape for a single table definition */
340
- type InferTableRow<T extends SubgraphTable> = SystemRow & { [K in keyof T["columns"]] : InferColumnType<T["columns"][K]> };
341
- /** Comparison operators for a scalar value */
342
- type ComparisonFilter<T> = {
343
- eq?: T
344
- neq?: T
345
- gt?: T
346
- gte?: T
347
- lt?: T
348
- lte?: T
349
- };
350
- /** Where clause — each column accepts a scalar (eq) or comparison object */
351
- type WhereInput<TRow> = { [K in keyof TRow]? : TRow[K] | ComparisonFilter<TRow[K]> };
352
- /**
353
- * No-prefix aliases for system columns accepted in where/orderBy inputs.
354
- * Both `_blockHeight` and `blockHeight` are valid — serializer handles mapping.
355
- */
356
- type SystemWhereAliases = {
357
- blockHeight?: bigint | ComparisonFilter<bigint>
358
- txId?: string | ComparisonFilter<string>
359
- createdAt?: string | ComparisonFilter<string>
360
- id?: string | ComparisonFilter<string>
361
- };
362
- type SystemOrderByAliases = {
363
- blockHeight?: "asc" | "desc"
364
- txId?: "asc" | "desc"
365
- createdAt?: "asc" | "desc"
366
- id?: "asc" | "desc"
367
- };
368
- interface FindManyOptions<TRow> {
369
- where?: WhereInput<TRow> & SystemWhereAliases;
370
- orderBy?: { [K in keyof TRow]? : "asc" | "desc" } & SystemOrderByAliases;
371
- limit?: number;
372
- offset?: number;
373
- fields?: (keyof TRow & string)[];
374
- }
375
- interface SubgraphTableClient<TRow> {
376
- findMany(options?: FindManyOptions<TRow>): Promise<TRow[]>;
377
- count(where?: WhereInput<TRow> & SystemWhereAliases): Promise<number>;
378
- }
379
- /** Infer a typed client object from a subgraph definition shape */
380
- type InferSubgraphClient<T> = T extends {
381
- schema: infer S
382
- } ? { [K in keyof S] : S[K] extends SubgraphTable ? SubgraphTableClient<InferTableRow<S[K]>> : never } : never;
383
- export { validateSubgraphDefinition, resumeReindex, reindexSubgraph, pgSchemaName, generateSubgraphSQL, diffSchema, deploySchema, defineSubgraph, backfillSubgraph, WhereInput, TxMeta, TableDiff, SystemRow, SubgraphTableClient, SubgraphTable, SubgraphSchema, SubgraphHandler, SubgraphFilter, SubgraphDefinition, SubgraphContext, SubgraphColumn, StxTransferFilter, StxMintFilter, StxLockFilter, StxBurnFilter, RowValue, ReindexOptions, PrintEventFilter, NftTransferFilter, NftMintFilter, NftBurnFilter, InferTableRow, InferSubgraphClient, InferColumnType, GeneratedSQL, FtTransferFilter, FtMintFilter, FtBurnFilter, FindManyOptions, ContractDeployFilter, ContractCallFilter, ContractCallEvent, ComputedValue, ComparisonFilter, ColumnType, ColumnToTS, ColumnDiff };
570
+ export { validateSubgraphDefinition, resumeReindex, reindexSubgraph, pgSchemaName, generateSubgraphSQL, diffSchema, deploySchema, defineSubgraph, backfillSubgraph, WriteRow, WhereInput, TypedSubgraphDefinition, TypedSubgraphContext, TypedHandlers, TxMeta, TableDiff, SystemRow, SubgraphTableClient, SubgraphTable, SubgraphSchema, SubgraphHandler, SubgraphFilter, SubgraphDefinition, SubgraphContext, SubgraphColumn, StxTransferPayload, StxTransferFilter, StxMintPayload, StxMintFilter, StxLockPayload, StxLockFilter, StxBurnPayload, StxBurnFilter, RowValue, ReindexOptions, PrintEventPayload, PrintEventFilter, NftTransferPayload, NftTransferFilter, NftMintPayload, NftMintFilter, NftBurnPayload, NftBurnFilter, InferTableRow, InferSubgraphClient, InferColumnType, GeneratedSQL, FtTransferPayload, FtTransferFilter, FtMintPayload, FtMintFilter, FtBurnPayload, FtBurnFilter, FindManyOptions, EventForFilter, ContractDeployPayload, ContractDeployFilter, ContractCallFilter, ContractCallEvent, ComputedValue, ComparisonFilter, ColumnType, ColumnToTS, ColumnDiff, AnyEvent };
package/dist/src/index.js CHANGED
@@ -1387,6 +1387,7 @@ import {
1387
1387
  import { logger as logger5 } from "@secondlayer/shared/logger";
1388
1388
 
1389
1389
  // src/schema/generator.ts
1390
+ import { createHash as createHash2 } from "node:crypto";
1390
1391
  var TYPE_MAP = {
1391
1392
  text: "TEXT",
1392
1393
  uint: "NUMERIC",
@@ -1466,7 +1467,7 @@ function generateSubgraphSQL(def, schemaNameOverride) {
1466
1467
  schema: def.schema,
1467
1468
  sources: def.sources
1468
1469
  }, (_key, value) => typeof value === "bigint" ? value.toString() : value);
1469
- const hash = String(Bun.hash(hashInput));
1470
+ const hash = createHash2("sha256").update(hashInput).digest("hex");
1470
1471
  return { statements, hash };
1471
1472
  }
1472
1473
 
@@ -2175,5 +2176,5 @@ export {
2175
2176
  backfillSubgraph
2176
2177
  };
2177
2178
 
2178
- //# debugId=76698A606CE0E66264756E2164756E21
2179
+ //# debugId=E831E58EC98F118E64756E2164756E21
2179
2180
  //# sourceMappingURL=index.js.map