@secondlayer/subgraphs 4.4.1 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/README.md +13 -21
  2. package/dist/{src/index.d.ts → index.d.ts} +59 -189
  3. package/dist/index.js +2151 -0
  4. package/dist/index.js.map +24 -0
  5. package/dist/{src/runtime → runtime}/emitter.d.ts +1 -1
  6. package/dist/{src/runtime → runtime}/emitter.js +8 -12
  7. package/dist/{src/runtime → runtime}/emitter.js.map +3 -3
  8. package/dist/{src/runtime → runtime}/replay.d.ts +1 -1
  9. package/dist/{src/runtime → runtime}/replay.js +342 -683
  10. package/dist/{src/runtime → runtime}/replay.js.map +5 -5
  11. package/dist/{src/schema → schema}/index.d.ts +10 -69
  12. package/dist/{src/schema → schema}/index.js +188 -281
  13. package/dist/schema/index.js.map +13 -0
  14. package/dist/{src/testing → testing}/index.d.ts +65 -115
  15. package/dist/{src/testing → testing}/index.js +554 -968
  16. package/dist/testing/index.js.map +21 -0
  17. package/dist/{src/types.d.ts → types.d.ts} +10 -66
  18. package/dist/{src/validate.d.ts → validate.d.ts} +11 -69
  19. package/dist/{src/validate.js → validate.js} +18 -98
  20. package/dist/validate.js.map +10 -0
  21. package/package.json +18 -26
  22. package/dist/src/index.js +0 -6081
  23. package/dist/src/index.js.map +0 -44
  24. package/dist/src/runtime/block-processor.d.ts +0 -559
  25. package/dist/src/runtime/block-processor.js +0 -3810
  26. package/dist/src/runtime/block-processor.js.map +0 -31
  27. package/dist/src/runtime/catchup.d.ts +0 -473
  28. package/dist/src/runtime/catchup.js +0 -4228
  29. package/dist/src/runtime/catchup.js.map +0 -35
  30. package/dist/src/runtime/clarity.d.ts +0 -15
  31. package/dist/src/runtime/clarity.js +0 -41
  32. package/dist/src/runtime/clarity.js.map +0 -10
  33. package/dist/src/runtime/context.d.ts +0 -325
  34. package/dist/src/runtime/context.js +0 -936
  35. package/dist/src/runtime/context.js.map +0 -13
  36. package/dist/src/runtime/processor.d.ts +0 -11
  37. package/dist/src/runtime/processor.js +0 -5372
  38. package/dist/src/runtime/processor.js.map +0 -40
  39. package/dist/src/runtime/reindex.d.ts +0 -539
  40. package/dist/src/runtime/reindex.js +0 -4802
  41. package/dist/src/runtime/reindex.js.map +0 -37
  42. package/dist/src/runtime/reorg.d.ts +0 -432
  43. package/dist/src/runtime/reorg.js +0 -4355
  44. package/dist/src/runtime/reorg.js.map +0 -36
  45. package/dist/src/runtime/runner.d.ts +0 -719
  46. package/dist/src/runtime/runner.js +0 -1332
  47. package/dist/src/runtime/runner.js.map +0 -16
  48. package/dist/src/runtime/source-matcher.d.ts +0 -304
  49. package/dist/src/runtime/source-matcher.js +0 -335
  50. package/dist/src/runtime/source-matcher.js.map +0 -10
  51. package/dist/src/runtime/stats.d.ts +0 -23
  52. package/dist/src/runtime/stats.js +0 -71
  53. package/dist/src/runtime/stats.js.map +0 -10
  54. package/dist/src/schema/index.js.map +0 -13
  55. package/dist/src/service.d.ts +0 -0
  56. package/dist/src/service.js +0 -5398
  57. package/dist/src/service.js.map +0 -41
  58. package/dist/src/testing/index.js.map +0 -22
  59. package/dist/src/triggers/index.d.ts +0 -381
  60. package/dist/src/triggers/index.js +0 -31
  61. package/dist/src/triggers/index.js.map +0 -10
  62. package/dist/src/validate.js.map +0 -10
  63. /package/dist/{src/types.js → types.js} +0 -0
  64. /package/dist/{src/types.js.map → types.js.map} +0 -0
@@ -1,5 +1,171 @@
1
- import { createRequire } from "node:module";
2
- var __require = /* @__PURE__ */ createRequire(import.meta.url);
1
+ // src/schema/generator.ts
2
+ import { createHash } from "node:crypto";
3
+
4
+ // src/schema/utils.ts
5
+ import { pgSchemaName } from "@secondlayer/shared/db/queries/subgraphs";
6
+ function quotePgIdent(name) {
7
+ if (/^[a-z_][a-z0-9_]*$/i.test(name))
8
+ return name;
9
+ return `"${name.replace(/"/g, '""')}"`;
10
+ }
11
+ function snakeToCamel(name) {
12
+ return name.replace(/_([a-z0-9])/g, (_, c) => c.toUpperCase());
13
+ }
14
+ function pascalCase(name) {
15
+ const camel = snakeToCamel(name);
16
+ return camel.charAt(0).toUpperCase() + camel.slice(1);
17
+ }
18
+
19
+ // src/schema/generator.ts
20
+ var TYPE_MAP = {
21
+ text: "TEXT",
22
+ uint: "NUMERIC",
23
+ int: "NUMERIC",
24
+ principal: "TEXT",
25
+ boolean: "BOOLEAN",
26
+ timestamp: "TIMESTAMPTZ",
27
+ jsonb: "JSONB"
28
+ };
29
+ var MAX_IDENT_BYTES = 63;
30
+ function safeIndexName(name) {
31
+ if (name.length <= MAX_IDENT_BYTES)
32
+ return name;
33
+ const hash = createHash("sha256").update(name).digest("hex").slice(0, 8);
34
+ return `${name.slice(0, MAX_IDENT_BYTES - hash.length - 1)}_${hash}`;
35
+ }
36
+ function emitIndexedColumnIndexDDL(schemaName, tableName, colName, opts) {
37
+ const concurrently = opts?.concurrently ? " CONCURRENTLY" : "";
38
+ const qualified = `${quotePgIdent(schemaName)}.${quotePgIdent(tableName)}`;
39
+ const plain = `idx_${schemaName}_${tableName}_${colName}`;
40
+ const composite = safeIndexName(`idx_${schemaName}_${tableName}_${colName}_id`);
41
+ const col = quotePgIdent(colName);
42
+ const id = quotePgIdent("_id");
43
+ return {
44
+ create: [
45
+ `CREATE INDEX${concurrently} IF NOT EXISTS ${quotePgIdent(plain)} ON ${qualified} (${col})`,
46
+ `CREATE INDEX${concurrently} IF NOT EXISTS ${quotePgIdent(composite)} ON ${qualified} (${col}, ${id})`
47
+ ],
48
+ drop: [
49
+ `DROP INDEX${concurrently} IF EXISTS ${quotePgIdent(schemaName)}.${quotePgIdent(plain)}`,
50
+ `DROP INDEX${concurrently} IF EXISTS ${quotePgIdent(schemaName)}.${quotePgIdent(composite)}`
51
+ ]
52
+ };
53
+ }
54
+ function escapeLiteralDefault(value) {
55
+ if (value === null || value === undefined)
56
+ return "NULL";
57
+ if (typeof value === "number" || typeof value === "bigint")
58
+ return String(value);
59
+ if (typeof value === "boolean")
60
+ return value ? "TRUE" : "FALSE";
61
+ return `'${String(value).replace(/'/g, "''")}'`;
62
+ }
63
+ function tableNeedsTrgm(tableDef) {
64
+ return Object.values(tableDef.columns).some((col) => col.search);
65
+ }
66
+ function emitTableDDL(schemaName, tableName, tableDef) {
67
+ const qualifiedName = `${quotePgIdent(schemaName)}.${quotePgIdent(tableName)}`;
68
+ const statements = [];
69
+ const columnDefs = [
70
+ "_id BIGSERIAL PRIMARY KEY",
71
+ "_block_height BIGINT NOT NULL",
72
+ "_tx_id TEXT NOT NULL",
73
+ "_created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()"
74
+ ];
75
+ for (const [colName, col] of Object.entries(tableDef.columns)) {
76
+ const sqlType = TYPE_MAP[col.type];
77
+ const nullable = col.nullable ? "" : " NOT NULL";
78
+ let colDef = `${quotePgIdent(colName)} ${sqlType}${nullable}`;
79
+ if (col.default !== undefined) {
80
+ colDef += ` DEFAULT ${escapeLiteralDefault(col.default)}`;
81
+ }
82
+ if (col.type === "uint") {
83
+ colDef += ` CHECK (${quotePgIdent(colName)} >= 0)`;
84
+ }
85
+ columnDefs.push(colDef);
86
+ }
87
+ statements.push(`CREATE TABLE IF NOT EXISTS ${qualifiedName} (
88
+ ${columnDefs.join(`,
89
+ `)}
90
+ )`);
91
+ statements.push(`CREATE INDEX IF NOT EXISTS ${quotePgIdent(`idx_${schemaName}_${tableName}_block_height`)} ON ${qualifiedName} (_block_height)`);
92
+ statements.push(`CREATE INDEX IF NOT EXISTS ${quotePgIdent(`idx_${schemaName}_${tableName}_tx_id`)} ON ${qualifiedName} (_tx_id)`);
93
+ for (const [colName, col] of Object.entries(tableDef.columns)) {
94
+ if (col.indexed) {
95
+ statements.push(...emitIndexedColumnIndexDDL(schemaName, tableName, colName).create);
96
+ }
97
+ }
98
+ for (const [colName, col] of Object.entries(tableDef.columns)) {
99
+ if (col.search) {
100
+ statements.push(`CREATE INDEX IF NOT EXISTS ${quotePgIdent(`idx_${schemaName}_${tableName}_${colName}_trgm`)} ON ${qualifiedName} USING gin (${quotePgIdent(colName)} gin_trgm_ops)`);
101
+ }
102
+ }
103
+ if (tableDef.indexes) {
104
+ for (let i = 0;i < tableDef.indexes.length; i++) {
105
+ const cols = tableDef.indexes[i];
106
+ const idxName = quotePgIdent(`idx_${schemaName}_${tableName}_composite_${i}`);
107
+ statements.push(`CREATE INDEX IF NOT EXISTS ${idxName} ON ${qualifiedName} (${cols.map(quotePgIdent).join(", ")})`);
108
+ }
109
+ }
110
+ if (tableDef.uniqueKeys) {
111
+ for (let i = 0;i < tableDef.uniqueKeys.length; i++) {
112
+ const cols = tableDef.uniqueKeys[i];
113
+ const constraintName = quotePgIdent(`uq_${schemaName}_${tableName}_${cols.join("_")}`);
114
+ statements.push(`ALTER TABLE ${qualifiedName} ADD CONSTRAINT ${constraintName} UNIQUE (${cols.map(quotePgIdent).join(", ")})`);
115
+ }
116
+ }
117
+ return statements;
118
+ }
119
+ function emitJournalDDL(schemaName) {
120
+ return [
121
+ `CREATE TABLE IF NOT EXISTS ${schemaName}._journal (
122
+ _jid BIGSERIAL PRIMARY KEY,
123
+ block_height BIGINT NOT NULL,
124
+ table_name TEXT NOT NULL,
125
+ row_key JSONB NOT NULL,
126
+ prev_row JSONB,
127
+ _created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
128
+ )`,
129
+ `CREATE INDEX IF NOT EXISTS idx_${schemaName}_journal_height ON ${schemaName}._journal (block_height)`
130
+ ];
131
+ }
132
+ function emitFactoryDDL(schemaName) {
133
+ return [
134
+ `CREATE TABLE IF NOT EXISTS ${schemaName}._factory_addresses (
135
+ source_name TEXT NOT NULL,
136
+ address TEXT NOT NULL,
137
+ block_height BIGINT NOT NULL,
138
+ _created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
139
+ PRIMARY KEY (source_name, address)
140
+ )`,
141
+ `CREATE INDEX IF NOT EXISTS idx_${schemaName}_factory_height ON ${schemaName}._factory_addresses (block_height)`
142
+ ];
143
+ }
144
+ function generateSubgraphSQL(def, schemaNameOverride) {
145
+ const schemaName = schemaNameOverride ?? pgSchemaName(def.name);
146
+ const statements = [];
147
+ const needsTrgm = Object.values(def.schema).some((table) => Object.values(table.columns).some((col) => col.search));
148
+ if (needsTrgm) {
149
+ statements.push("CREATE EXTENSION IF NOT EXISTS pg_trgm");
150
+ }
151
+ statements.push(`CREATE SCHEMA IF NOT EXISTS ${schemaName}`);
152
+ for (const [tableName, tableDef] of Object.entries(def.schema)) {
153
+ statements.push(...emitTableDDL(schemaName, tableName, tableDef));
154
+ }
155
+ statements.push(...emitJournalDDL(schemaName));
156
+ if (Object.values(def.sources ?? {}).some((src) => src.factory !== undefined)) {
157
+ statements.push(...emitFactoryDDL(schemaName));
158
+ }
159
+ const hashInput = JSON.stringify({
160
+ name: def.name,
161
+ schema: def.schema,
162
+ sources: def.sources
163
+ }, (_key, value) => typeof value === "bigint" ? value.toString() : value);
164
+ const hash = createHash("sha256").update(hashInput).digest("hex");
165
+ return { statements, hash };
166
+ }
167
+ // src/schema/deployer.ts
168
+ import { sql } from "kysely";
3
169
 
4
170
  // src/validate.ts
5
171
  import { z } from "zod";
@@ -62,13 +228,7 @@ var SubgraphColumnSchema = z.object({
62
228
  var SubgraphTableSchema = z.object({
63
229
  columns: z.record(SqlIdentifierSchema, SubgraphColumnSchema).refine((c) => Object.keys(c).length > 0, "Table must have at least one column"),
64
230
  indexes: z.array(z.array(SqlIdentifierSchema)).optional(),
65
- uniqueKeys: z.array(z.array(SqlIdentifierSchema)).optional(),
66
- relations: z.array(z.object({
67
- name: SqlIdentifierSchema,
68
- references: SqlIdentifierSchema,
69
- fields: z.array(SqlIdentifierSchema).min(1),
70
- referencedColumns: z.array(SqlIdentifierSchema).min(1)
71
- })).optional()
231
+ uniqueKeys: z.array(z.array(SqlIdentifierSchema)).optional()
72
232
  });
73
233
  var SubgraphSchemaSchema = z.record(SqlIdentifierSchema, SubgraphTableSchema).refine((s) => Object.keys(s).length > 0, "Schema must have at least one table");
74
234
  var VALID_FILTER_TYPES = [
@@ -103,15 +263,6 @@ var amountRange = {
103
263
  minAmount: z.bigint().optional(),
104
264
  maxAmount: z.bigint().optional()
105
265
  };
106
- var MaterializeColumnSchema = z.union([
107
- z.object({ from: z.string().min(1) }).strict(),
108
- z.object({ fromTx: z.enum(["sender", "txId"]) }).strict(),
109
- z.object({ fromBlock: z.enum(["height", "hash", "timestamp"]) }).strict()
110
- ]);
111
- var MaterializeSpecSchema = z.object({
112
- table: z.string().min(1),
113
- columns: z.record(z.string(), MaterializeColumnSchema)
114
- }).strict();
115
266
  var SubgraphFilterUnion = z.discriminatedUnion("type", [
116
267
  z.object({
117
268
  type: z.literal("stx_transfer"),
@@ -194,7 +345,6 @@ var SubgraphFilterUnion = z.discriminatedUnion("type", [
194
345
  contractId: contractIdField.optional(),
195
346
  topic: z.string().optional(),
196
347
  prints: z.record(z.string(), z.record(z.string(), PrintFieldSchema)).optional(),
197
- materialize: MaterializeSpecSchema.optional(),
198
348
  ...traitScope,
199
349
  ...factoryScope
200
350
  }).strict(),
@@ -244,54 +394,6 @@ function hasPinnedContractId(contractId) {
244
394
  return contractId.length > 0;
245
395
  return false;
246
396
  }
247
- function printMaterializeFromKeys(prints) {
248
- const keys = new Set(["topic"]);
249
- if (prints) {
250
- for (const fields of Object.values(prints)) {
251
- for (const k of Object.keys(fields))
252
- keys.add(k);
253
- }
254
- }
255
- return [...keys].sort();
256
- }
257
- function refineMaterialize(name, filter, schema, ctx) {
258
- if (!("materialize" in filter) || filter.materialize === undefined)
259
- return;
260
- const spec = filter.materialize;
261
- const table = schema[spec.table];
262
- if (!table) {
263
- ctx.addIssue({
264
- code: "custom",
265
- path: ["sources", name, "materialize", "table"],
266
- message: `materialize table "${spec.table}" is not in schema`
267
- });
268
- return;
269
- }
270
- for (const col of Object.keys(spec.columns)) {
271
- if (!(col in table.columns)) {
272
- ctx.addIssue({
273
- code: "custom",
274
- path: ["sources", name, "materialize", "columns", col],
275
- message: `materialize column "${col}" is not on schema table "${spec.table}"`
276
- });
277
- }
278
- }
279
- if (filter.type === "print_event") {
280
- const known = printMaterializeFromKeys(filter.prints);
281
- const knownSet = new Set(known);
282
- for (const [col, mapping] of Object.entries(spec.columns)) {
283
- if (!("from" in mapping))
284
- continue;
285
- if (!knownSet.has(mapping.from)) {
286
- ctx.addIssue({
287
- code: "custom",
288
- path: ["sources", name, "materialize", "columns", col, "from"],
289
- message: `materialize from "${mapping.from}" is not a known print field — known: ${known.join(", ")}`
290
- });
291
- }
292
- }
293
- }
294
- }
295
397
  function refineDeployGates(def, ctx) {
296
398
  for (const [name, filter] of Object.entries(def.sources)) {
297
399
  if (filter.type === "print_event") {
@@ -312,36 +414,23 @@ function refineDeployGates(def, ctx) {
312
414
  ctx.addIssue({
313
415
  code: "custom",
314
416
  path: ["sources", name, "abi"],
315
- message: `contract_call source "${name}" has functionName but no abi — pass a canonical ABI (normalizeAbi() from @secondlayer/stacks/clarity).`
417
+ message: `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).`
316
418
  });
317
419
  }
318
420
  }
319
- refineMaterialize(name, filter, def.schema, ctx);
320
421
  }
321
- const hasCatchAll = def.handlers["*"] != null;
322
- for (const [name, filter] of Object.entries(def.sources)) {
323
- const hasMaterialize = "materialize" in filter && filter.materialize !== undefined;
324
- const hasHandler = def.handlers[name] != null;
325
- if (hasMaterialize && hasHandler) {
326
- ctx.addIssue({
327
- code: "custom",
328
- path: ["handlers", name],
329
- message: `source "${name}" has both materialize and a handler — use one or the other`
330
- });
331
- continue;
332
- }
333
- if (!hasHandler && !hasMaterialize && !hasCatchAll) {
422
+ for (const name of Object.keys(def.sources)) {
423
+ if (def.handlers[name] == null) {
334
424
  ctx.addIssue({
335
425
  code: "custom",
336
426
  path: ["handlers", name],
337
- message: `source "${name}" has no handler (and no "*") — events will be skipped and the table stay empty.`
427
+ message: `source "${name}" has no handler. Add handlers.${name}, or its events are skipped and the table stays empty.`
338
428
  });
339
429
  }
340
430
  }
341
431
  }
342
432
  var SubgraphDefinitionSchema = z.object({
343
433
  name: SubgraphNameSchema,
344
- version: z.string().optional(),
345
434
  description: z.string().optional(),
346
435
  startBlock: z.number().int().nonnegative().optional(),
347
436
  backfillMode: z.enum(["blocking", "concurrent"]).optional(),
@@ -372,183 +461,7 @@ function filterFieldsByType() {
372
461
  return out;
373
462
  }
374
463
 
375
- // src/schema/generator.ts
376
- import { createHash } from "node:crypto";
377
-
378
- // src/schema/utils.ts
379
- import { pgSchemaName } from "@secondlayer/shared/db/queries/subgraphs";
380
- function quotePgIdent(name) {
381
- if (/^[a-z_][a-z0-9_]*$/i.test(name))
382
- return name;
383
- return `"${name.replace(/"/g, '""')}"`;
384
- }
385
- function snakeToCamel(name) {
386
- return name.replace(/_([a-z0-9])/g, (_, c) => c.toUpperCase());
387
- }
388
- function pascalCase(name) {
389
- const camel = snakeToCamel(name);
390
- return camel.charAt(0).toUpperCase() + camel.slice(1);
391
- }
392
-
393
- // src/schema/generator.ts
394
- var TYPE_MAP = {
395
- text: "TEXT",
396
- uint: "NUMERIC",
397
- int: "NUMERIC",
398
- principal: "TEXT",
399
- boolean: "BOOLEAN",
400
- timestamp: "TIMESTAMPTZ",
401
- jsonb: "JSONB"
402
- };
403
- var MAX_IDENT_BYTES = 63;
404
- function safeIndexName(name) {
405
- if (name.length <= MAX_IDENT_BYTES)
406
- return name;
407
- const hash = createHash("sha256").update(name).digest("hex").slice(0, 8);
408
- return `${name.slice(0, MAX_IDENT_BYTES - hash.length - 1)}_${hash}`;
409
- }
410
- function emitIndexedColumnIndexDDL(schemaName, tableName, colName, opts) {
411
- const concurrently = opts?.concurrently ? " CONCURRENTLY" : "";
412
- const qualified = `${quotePgIdent(schemaName)}.${quotePgIdent(tableName)}`;
413
- const plain = `idx_${schemaName}_${tableName}_${colName}`;
414
- const composite = safeIndexName(`idx_${schemaName}_${tableName}_${colName}_id`);
415
- const col = quotePgIdent(colName);
416
- const id = quotePgIdent("_id");
417
- return {
418
- create: [
419
- `CREATE INDEX${concurrently} IF NOT EXISTS ${quotePgIdent(plain)} ON ${qualified} (${col})`,
420
- `CREATE INDEX${concurrently} IF NOT EXISTS ${quotePgIdent(composite)} ON ${qualified} (${col}, ${id})`
421
- ],
422
- drop: [
423
- `DROP INDEX${concurrently} IF EXISTS ${quotePgIdent(schemaName)}.${quotePgIdent(plain)}`,
424
- `DROP INDEX${concurrently} IF EXISTS ${quotePgIdent(schemaName)}.${quotePgIdent(composite)}`
425
- ]
426
- };
427
- }
428
- function escapeLiteralDefault(value) {
429
- if (value === null || value === undefined)
430
- return "NULL";
431
- if (typeof value === "number" || typeof value === "bigint")
432
- return String(value);
433
- if (typeof value === "boolean")
434
- return value ? "TRUE" : "FALSE";
435
- return `'${String(value).replace(/'/g, "''")}'`;
436
- }
437
- function tableNeedsTrgm(tableDef) {
438
- return Object.values(tableDef.columns).some((col) => col.search);
439
- }
440
- function emitTableDDL(schemaName, tableName, tableDef) {
441
- const qualifiedName = `${quotePgIdent(schemaName)}.${quotePgIdent(tableName)}`;
442
- const statements = [];
443
- const columnDefs = [
444
- "_id BIGSERIAL PRIMARY KEY",
445
- "_block_height BIGINT NOT NULL",
446
- "_tx_id TEXT NOT NULL",
447
- "_created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()"
448
- ];
449
- for (const [colName, col] of Object.entries(tableDef.columns)) {
450
- const sqlType = TYPE_MAP[col.type];
451
- const nullable = col.nullable ? "" : " NOT NULL";
452
- let colDef = `${quotePgIdent(colName)} ${sqlType}${nullable}`;
453
- if (col.default !== undefined) {
454
- colDef += ` DEFAULT ${escapeLiteralDefault(col.default)}`;
455
- }
456
- if (col.type === "uint") {
457
- colDef += ` CHECK (${quotePgIdent(colName)} >= 0)`;
458
- }
459
- columnDefs.push(colDef);
460
- }
461
- statements.push(`CREATE TABLE IF NOT EXISTS ${qualifiedName} (
462
- ${columnDefs.join(`,
463
- `)}
464
- )`);
465
- statements.push(`CREATE INDEX IF NOT EXISTS ${quotePgIdent(`idx_${schemaName}_${tableName}_block_height`)} ON ${qualifiedName} (_block_height)`);
466
- statements.push(`CREATE INDEX IF NOT EXISTS ${quotePgIdent(`idx_${schemaName}_${tableName}_tx_id`)} ON ${qualifiedName} (_tx_id)`);
467
- for (const [colName, col] of Object.entries(tableDef.columns)) {
468
- if (col.indexed) {
469
- statements.push(...emitIndexedColumnIndexDDL(schemaName, tableName, colName).create);
470
- }
471
- }
472
- for (const [colName, col] of Object.entries(tableDef.columns)) {
473
- if (col.search) {
474
- statements.push(`CREATE INDEX IF NOT EXISTS ${quotePgIdent(`idx_${schemaName}_${tableName}_${colName}_trgm`)} ON ${qualifiedName} USING gin (${quotePgIdent(colName)} gin_trgm_ops)`);
475
- }
476
- }
477
- if (tableDef.indexes) {
478
- for (let i = 0;i < tableDef.indexes.length; i++) {
479
- const cols = tableDef.indexes[i];
480
- const idxName = quotePgIdent(`idx_${schemaName}_${tableName}_composite_${i}`);
481
- statements.push(`CREATE INDEX IF NOT EXISTS ${idxName} ON ${qualifiedName} (${cols.map(quotePgIdent).join(", ")})`);
482
- }
483
- }
484
- if (tableDef.uniqueKeys) {
485
- for (let i = 0;i < tableDef.uniqueKeys.length; i++) {
486
- const cols = tableDef.uniqueKeys[i];
487
- const constraintName = quotePgIdent(`uq_${schemaName}_${tableName}_${cols.join("_")}`);
488
- statements.push(`ALTER TABLE ${qualifiedName} ADD CONSTRAINT ${constraintName} UNIQUE (${cols.map(quotePgIdent).join(", ")})`);
489
- }
490
- }
491
- return statements;
492
- }
493
- function emitJournalDDL(schemaName) {
494
- return [
495
- `CREATE TABLE IF NOT EXISTS ${schemaName}._journal (
496
- _jid BIGSERIAL PRIMARY KEY,
497
- block_height BIGINT NOT NULL,
498
- table_name TEXT NOT NULL,
499
- row_key JSONB NOT NULL,
500
- prev_row JSONB,
501
- _created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
502
- )`,
503
- `CREATE INDEX IF NOT EXISTS idx_${schemaName}_journal_height ON ${schemaName}._journal (block_height)`
504
- ];
505
- }
506
- function emitFactoryDDL(schemaName) {
507
- return [
508
- `CREATE TABLE IF NOT EXISTS ${schemaName}._factory_addresses (
509
- source_name TEXT NOT NULL,
510
- address TEXT NOT NULL,
511
- block_height BIGINT NOT NULL,
512
- _created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
513
- PRIMARY KEY (source_name, address)
514
- )`,
515
- `CREATE INDEX IF NOT EXISTS idx_${schemaName}_factory_height ON ${schemaName}._factory_addresses (block_height)`
516
- ];
517
- }
518
- function emitForeignKeyDDL(schemaName, tableName, tableDef) {
519
- return (tableDef.relations ?? []).map((rel) => {
520
- const constraintName = quotePgIdent(`fk_${schemaName}_${tableName}_${rel.name}`);
521
- return `ALTER TABLE ${quotePgIdent(schemaName)}.${quotePgIdent(tableName)} ADD CONSTRAINT ${constraintName} ` + `FOREIGN KEY (${rel.fields.map(quotePgIdent).join(", ")}) ` + `REFERENCES ${quotePgIdent(schemaName)}.${quotePgIdent(rel.references)} (${rel.referencedColumns.map(quotePgIdent).join(", ")})`;
522
- });
523
- }
524
- function generateSubgraphSQL(def, schemaNameOverride) {
525
- const schemaName = schemaNameOverride ?? pgSchemaName(def.name);
526
- const statements = [];
527
- const needsTrgm = Object.values(def.schema).some((table) => Object.values(table.columns).some((col) => col.search));
528
- if (needsTrgm) {
529
- statements.push("CREATE EXTENSION IF NOT EXISTS pg_trgm");
530
- }
531
- statements.push(`CREATE SCHEMA IF NOT EXISTS ${schemaName}`);
532
- for (const [tableName, tableDef] of Object.entries(def.schema)) {
533
- statements.push(...emitTableDDL(schemaName, tableName, tableDef));
534
- }
535
- statements.push(...emitJournalDDL(schemaName));
536
- if (Object.values(def.sources ?? {}).some((src) => src.factory !== undefined)) {
537
- statements.push(...emitFactoryDDL(schemaName));
538
- }
539
- for (const [tableName, tableDef] of Object.entries(def.schema)) {
540
- statements.push(...emitForeignKeyDDL(schemaName, tableName, tableDef));
541
- }
542
- const hashInput = JSON.stringify({
543
- name: def.name,
544
- schema: def.schema,
545
- sources: def.sources
546
- }, (_key, value) => typeof value === "bigint" ? value.toString() : value);
547
- const hash = createHash("sha256").update(hashInput).digest("hex");
548
- return { statements, hash };
549
- }
550
464
  // src/schema/deployer.ts
551
- import { sql } from "kysely";
552
465
  function toJsonSafe(obj) {
553
466
  return JSON.parse(JSON.stringify(obj, (_key, value) => typeof value === "bigint" ? value.toString() : value));
554
467
  }
@@ -649,13 +562,12 @@ async function deploySchema(db, def, handlerPath, opts) {
649
562
  const ddlDb = db;
650
563
  const existing = await getSubgraph(db, def.name, opts?.accountId);
651
564
  const schemaName = opts?.schemaName ?? pgSchemaName(def.name);
652
- const newVersion = opts?.version ?? (existing ? bumpPatch(existing.version) : "1.0.0");
565
+ const newVersion = existing ? bumpPatch(existing.version) : "1.0.0";
653
566
  const regData = {
654
567
  name: def.name,
655
568
  version: newVersion,
656
569
  definition: toJsonSafe({
657
570
  name: def.name,
658
- version: def.version,
659
571
  description: def.description,
660
572
  startBlock: def.startBlock,
661
573
  sources: def.sources,
@@ -681,8 +593,8 @@ async function deploySchema(db, def, handlerPath, opts) {
681
593
  for (const stmt of statements) {
682
594
  await sql.raw(stmt).execute(ddlDb);
683
595
  }
684
- const sg2 = await registerSubgraph(db, regData);
685
- return { action: "reindexed", subgraphId: sg2.id, version: newVersion };
596
+ const sg = await registerSubgraph(db, regData);
597
+ return { action: "reindexed", subgraphId: sg.id, version: newVersion };
686
598
  }
687
599
  if (existing.schema_hash === hash && !opts?.forceReindex) {
688
600
  const handlerChanged = opts?.handlerCode != null && opts.handlerCode !== existing.handler_code;
@@ -707,8 +619,8 @@ async function deploySchema(db, def, handlerPath, opts) {
707
619
  for (const stmt of statements) {
708
620
  await sql.raw(stmt).execute(ddlDb);
709
621
  }
710
- const sg2 = await registerSubgraph(db, regData);
711
- return { action: "reindexed", subgraphId: sg2.id, version: newVersion };
622
+ const sg = await registerSubgraph(db, regData);
623
+ return { action: "reindexed", subgraphId: sg.id, version: newVersion };
712
624
  }
713
625
  if (existing.definition.schema) {
714
626
  const diff = diffSchema(existing.definition.schema, def.schema);
@@ -718,13 +630,13 @@ async function deploySchema(db, def, handlerPath, opts) {
718
630
  for (const stmt of statements) {
719
631
  await sql.raw(stmt).execute(ddlDb);
720
632
  }
721
- const sg3 = await registerSubgraph(db, regData);
722
- const deployDiff2 = toDeployDiff(diff, reasons);
633
+ const sg = await registerSubgraph(db, regData);
634
+ const deployDiff = toDeployDiff(diff, reasons);
723
635
  return {
724
636
  action: "reindexed",
725
- subgraphId: sg3.id,
637
+ subgraphId: sg.id,
726
638
  version: newVersion,
727
- diff: deployDiff2
639
+ diff: deployDiff
728
640
  };
729
641
  }
730
642
  const addedDefs = diff.addedTables.map((tableName) => ({ tableName, tableDef: def.schema[tableName] })).filter((t) => t.tableDef !== undefined);
@@ -736,11 +648,6 @@ async function deploySchema(db, def, handlerPath, opts) {
736
648
  await sql.raw(stmt).execute(ddlDb);
737
649
  }
738
650
  }
739
- for (const { tableName, tableDef } of addedDefs) {
740
- for (const stmt of emitForeignKeyDDL(schemaName, tableName, tableDef)) {
741
- await sql.raw(stmt).execute(ddlDb);
742
- }
743
- }
744
651
  for (const [tableName, colDiff] of Object.entries(diff.tables)) {
745
652
  if (colDiff.added.length === 0)
746
653
  continue;
@@ -830,7 +737,7 @@ async function deploySchema(db, def, handlerPath, opts) {
830
737
  await sql.raw(`DROP INDEX CONCURRENTLY IF EXISTS ${schemaName}.${idxName}`).execute(ddlDb);
831
738
  }
832
739
  }
833
- const sg2 = await registerSubgraph(db, regData);
740
+ const sg = await registerSubgraph(db, regData);
834
741
  const addedCols = {};
835
742
  for (const [t, colDiff] of Object.entries(diff.tables)) {
836
743
  if (colDiff.added.length > 0)
@@ -846,7 +753,7 @@ async function deploySchema(db, def, handlerPath, opts) {
846
753
  };
847
754
  return {
848
755
  action: "updated",
849
- subgraphId: sg2.id,
756
+ subgraphId: sg.id,
850
757
  version: newVersion,
851
758
  diff: deployDiff
852
759
  };
@@ -877,11 +784,11 @@ function getDefault(type) {
877
784
  }
878
785
  }
879
786
  export {
880
- generateSubgraphSQL,
881
- diffSchema,
787
+ TYPE_MAP,
882
788
  deploySchema,
883
- TYPE_MAP
789
+ diffSchema,
790
+ generateSubgraphSQL
884
791
  };
885
792
 
886
- //# debugId=796006DC2864C80064756E2164756E21
793
+ //# debugId=054E6A0FD91586DA64756E2164756E21
887
794
  //# sourceMappingURL=index.js.map