@secondlayer/subgraphs 0.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.
Files changed (46) hide show
  1. package/dist/src/index.d.ts +219 -0
  2. package/dist/src/index.js +956 -0
  3. package/dist/src/index.js.map +22 -0
  4. package/dist/src/runtime/block-processor.d.ts +100 -0
  5. package/dist/src/runtime/block-processor.js +501 -0
  6. package/dist/src/runtime/block-processor.js.map +16 -0
  7. package/dist/src/runtime/catchup.d.ts +78 -0
  8. package/dist/src/runtime/catchup.js +630 -0
  9. package/dist/src/runtime/catchup.js.map +18 -0
  10. package/dist/src/runtime/clarity.d.ts +15 -0
  11. package/dist/src/runtime/clarity.js +41 -0
  12. package/dist/src/runtime/clarity.js.map +10 -0
  13. package/dist/src/runtime/context.d.ts +69 -0
  14. package/dist/src/runtime/context.js +177 -0
  15. package/dist/src/runtime/context.js.map +10 -0
  16. package/dist/src/runtime/processor.d.ts +8 -0
  17. package/dist/src/runtime/processor.js +770 -0
  18. package/dist/src/runtime/processor.js.map +20 -0
  19. package/dist/src/runtime/reindex.d.ts +84 -0
  20. package/dist/src/runtime/reindex.js +738 -0
  21. package/dist/src/runtime/reindex.js.map +19 -0
  22. package/dist/src/runtime/reorg.d.ts +78 -0
  23. package/dist/src/runtime/reorg.js +536 -0
  24. package/dist/src/runtime/reorg.js.map +17 -0
  25. package/dist/src/runtime/runner.d.ts +147 -0
  26. package/dist/src/runtime/runner.js +130 -0
  27. package/dist/src/runtime/runner.js.map +11 -0
  28. package/dist/src/runtime/source-matcher.d.ts +53 -0
  29. package/dist/src/runtime/source-matcher.js +111 -0
  30. package/dist/src/runtime/source-matcher.js.map +11 -0
  31. package/dist/src/runtime/stats.d.ts +24 -0
  32. package/dist/src/runtime/stats.js +75 -0
  33. package/dist/src/runtime/stats.js.map +10 -0
  34. package/dist/src/schema/index.d.ts +117 -0
  35. package/dist/src/schema/index.js +305 -0
  36. package/dist/src/schema/index.js.map +13 -0
  37. package/dist/src/service.d.ts +0 -0
  38. package/dist/src/service.js +780 -0
  39. package/dist/src/service.js.map +21 -0
  40. package/dist/src/types.d.ts +80 -0
  41. package/dist/src/types.js +22 -0
  42. package/dist/src/types.js.map +10 -0
  43. package/dist/src/validate.d.ts +84 -0
  44. package/dist/src/validate.js +59 -0
  45. package/dist/src/validate.js.map +10 -0
  46. package/package.json +49 -0
@@ -0,0 +1,117 @@
1
+ /** Supported column types for subgraph schemas */
2
+ type ColumnType = "text" | "uint" | "int" | "principal" | "boolean" | "timestamp" | "jsonb";
3
+ /** Column definition in a subgraph table */
4
+ interface SubgraphColumn {
5
+ type: ColumnType;
6
+ nullable?: boolean;
7
+ indexed?: boolean;
8
+ search?: boolean;
9
+ default?: string | number | boolean;
10
+ }
11
+ /** Table definition within a subgraph schema */
12
+ interface SubgraphTable {
13
+ columns: Record<string, SubgraphColumn>;
14
+ /** Composite indexes (each entry is an array of column names) */
15
+ indexes?: string[][];
16
+ /** Unique key constraints (each entry is an array of column names). Required for upsert. */
17
+ uniqueKeys?: string[][];
18
+ }
19
+ /** Subgraph schema — maps table names to table definitions */
20
+ type SubgraphSchema = Record<string, SubgraphTable>;
21
+ /** Source filter for what blockchain data this subgraph processes */
22
+ interface SubgraphSource {
23
+ /** Contract principal (e.g., SP000...::contract-name). Supports * wildcards. */
24
+ contract?: string;
25
+ /** Event name/topic to filter on */
26
+ event?: string;
27
+ /** Function name to filter on */
28
+ function?: string;
29
+ /** Transaction type filter (e.g., "stx_transfer", "contract_call") */
30
+ type?: string;
31
+ /** Minimum amount filter (for stx_transfer sources) */
32
+ minAmount?: bigint;
33
+ }
34
+ /** Context passed to subgraph handlers during event processing */
35
+ interface SubgraphContext {
36
+ block: {
37
+ height: number
38
+ hash: string
39
+ timestamp: number
40
+ burnBlockHeight: number
41
+ };
42
+ tx: {
43
+ txId: string
44
+ sender: string
45
+ type: string
46
+ status: string
47
+ };
48
+ insert(table: string, row: Record<string, unknown>): void;
49
+ update(table: string, where: Record<string, unknown>, set: Record<string, unknown>): void;
50
+ upsert(table: string, key: Record<string, unknown>, row: Record<string, unknown>): void;
51
+ delete(table: string, where: Record<string, unknown>): void;
52
+ findOne(table: string, where: Record<string, unknown>): Promise<Record<string, unknown> | null>;
53
+ findMany(table: string, where: Record<string, unknown>): Promise<Record<string, unknown>[]>;
54
+ }
55
+ /** Handler function that processes events and writes to the subgraph */
56
+ type SubgraphHandler = (event: Record<string, unknown>, ctx: SubgraphContext) => Promise<void> | void;
57
+ /** Complete subgraph definition */
58
+ interface SubgraphDefinition {
59
+ /** Unique subgraph name (lowercase, alphanumeric + hyphens) */
60
+ name: string;
61
+ /** Semantic version */
62
+ version?: string;
63
+ /** Human description */
64
+ description?: string;
65
+ /** What blockchain data to process — one or more source filters */
66
+ sources: SubgraphSource[];
67
+ /** Tables in this subgraph */
68
+ schema: SubgraphSchema;
69
+ /** Keyed handler functions — keys match sourceKey() output, "*" is catch-all */
70
+ handlers: Record<string, SubgraphHandler>;
71
+ }
72
+ interface GeneratedSQL {
73
+ statements: string[];
74
+ hash: string;
75
+ }
76
+ /**
77
+ * Generates PostgreSQL DDL statements for a subgraph definition.
78
+ * Creates a dedicated schema `subgraph_<name>` with one table per schema entry,
79
+ * each with auto-columns and indexes.
80
+ */
81
+ declare function generateSubgraphSQL(def: SubgraphDefinition, schemaNameOverride?: string): GeneratedSQL;
82
+ import { Kysely } from "kysely";
83
+ import { Database } from "@secondlayer/shared/db";
84
+ type AnyDb = Kysely<Database>;
85
+ interface TableDiff {
86
+ /** Tables added to the schema */
87
+ addedTables: string[];
88
+ /** Tables removed from the schema */
89
+ removedTables: string[];
90
+ /** Per-table column diffs (only for tables present in both) */
91
+ tables: Record<string, ColumnDiff>;
92
+ }
93
+ interface ColumnDiff {
94
+ added: string[];
95
+ removed: string[];
96
+ changed: string[];
97
+ }
98
+ /**
99
+ * Compare two multi-table subgraph schemas and return differences.
100
+ */
101
+ declare function diffSchema(existing: SubgraphSchema, incoming: SubgraphSchema): TableDiff;
102
+ /**
103
+ * Deploy a subgraph schema to the database.
104
+ * - New subgraph → CREATE SCHEMA + tables + register
105
+ * - Same hash → no-op
106
+ * - Additive change → ALTER TABLE ADD COLUMN / CREATE TABLE for new tables
107
+ * - Breaking change → throws error
108
+ */
109
+ declare function deploySchema(db: AnyDb, def: SubgraphDefinition, handlerPath: string, opts?: {
110
+ forceReindex?: boolean
111
+ apiKeyId?: string
112
+ schemaName?: string
113
+ }): Promise<{
114
+ action: "created" | "unchanged" | "updated" | "reindexed"
115
+ subgraphId: string
116
+ }>;
117
+ export { generateSubgraphSQL, diffSchema, deploySchema, TableDiff, GeneratedSQL, ColumnDiff };
@@ -0,0 +1,305 @@
1
+ import { createRequire } from "node:module";
2
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
3
+
4
+ // src/validate.ts
5
+ import { z } from "zod";
6
+ var SubgraphNameSchema = z.string().min(1).max(63).regex(/^[a-z][a-z0-9-]*$/, "Must start with lowercase letter, contain only lowercase alphanumeric and hyphens");
7
+ var ColumnTypeSchema = z.enum([
8
+ "text",
9
+ "uint",
10
+ "int",
11
+ "principal",
12
+ "boolean",
13
+ "timestamp",
14
+ "jsonb"
15
+ ]);
16
+ var SubgraphColumnSchema = z.object({
17
+ type: ColumnTypeSchema,
18
+ nullable: z.boolean().optional(),
19
+ indexed: z.boolean().optional(),
20
+ search: z.boolean().optional(),
21
+ default: z.union([z.string(), z.number(), z.boolean()]).optional()
22
+ });
23
+ var SubgraphTableSchema = z.object({
24
+ columns: z.record(z.string(), SubgraphColumnSchema).refine((c) => Object.keys(c).length > 0, "Table must have at least one column"),
25
+ indexes: z.array(z.array(z.string())).optional(),
26
+ uniqueKeys: z.array(z.array(z.string())).optional()
27
+ });
28
+ var SubgraphSchemaSchema = z.record(z.string(), SubgraphTableSchema).refine((s) => Object.keys(s).length > 0, "Schema must have at least one table");
29
+ var SubgraphSourceSchema = z.object({
30
+ contract: z.string().optional(),
31
+ event: z.string().optional(),
32
+ function: z.string().optional(),
33
+ type: z.string().optional(),
34
+ minAmount: z.bigint().optional()
35
+ }).refine((s) => s.contract || s.type, "Source must specify at least 'contract' or 'type'");
36
+ var SubgraphDefinitionSchema = z.object({
37
+ name: SubgraphNameSchema,
38
+ version: z.string().optional(),
39
+ description: z.string().optional(),
40
+ sources: z.array(SubgraphSourceSchema).min(1, "Must have at least one source"),
41
+ schema: SubgraphSchemaSchema,
42
+ handlers: z.record(z.string(), z.function())
43
+ });
44
+ function validateSubgraphDefinition(def) {
45
+ return SubgraphDefinitionSchema.parse(def);
46
+ }
47
+
48
+ // src/schema/utils.ts
49
+ import { pgSchemaName } from "@secondlayer/shared/db/queries/subgraphs";
50
+
51
+ // src/schema/generator.ts
52
+ var TYPE_MAP = {
53
+ text: "TEXT",
54
+ uint: "BIGINT",
55
+ int: "INTEGER",
56
+ principal: "TEXT",
57
+ boolean: "BOOLEAN",
58
+ timestamp: "TIMESTAMPTZ",
59
+ jsonb: "JSONB"
60
+ };
61
+ function escapeLiteralDefault(value) {
62
+ if (value === null || value === undefined)
63
+ return "NULL";
64
+ if (typeof value === "number" || typeof value === "bigint")
65
+ return String(value);
66
+ if (typeof value === "boolean")
67
+ return value ? "TRUE" : "FALSE";
68
+ return `'${String(value).replace(/'/g, "''")}'`;
69
+ }
70
+ function generateSubgraphSQL(def, schemaNameOverride) {
71
+ const schemaName = schemaNameOverride ?? pgSchemaName(def.name);
72
+ const statements = [];
73
+ const needsTrgm = Object.values(def.schema).some((table) => Object.values(table.columns).some((col) => col.search));
74
+ if (needsTrgm) {
75
+ statements.push(`CREATE EXTENSION IF NOT EXISTS pg_trgm`);
76
+ }
77
+ statements.push(`CREATE SCHEMA IF NOT EXISTS ${schemaName}`);
78
+ for (const [tableName, tableDef] of Object.entries(def.schema)) {
79
+ const qualifiedName = `${schemaName}.${tableName}`;
80
+ const columnDefs = [
81
+ `_id BIGSERIAL PRIMARY KEY`,
82
+ `_block_height BIGINT NOT NULL`,
83
+ `_tx_id TEXT NOT NULL`,
84
+ `_created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()`
85
+ ];
86
+ for (const [colName, col] of Object.entries(tableDef.columns)) {
87
+ const sqlType = TYPE_MAP[col.type];
88
+ const nullable = col.nullable ? "" : " NOT NULL";
89
+ let colDef = `${colName} ${sqlType}${nullable}`;
90
+ if (col.default !== undefined) {
91
+ colDef += ` DEFAULT ${escapeLiteralDefault(col.default)}`;
92
+ }
93
+ columnDefs.push(colDef);
94
+ }
95
+ statements.push(`CREATE TABLE IF NOT EXISTS ${qualifiedName} (
96
+ ${columnDefs.join(`,
97
+ `)}
98
+ )`);
99
+ statements.push(`CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_block_height ON ${qualifiedName} (_block_height)`);
100
+ statements.push(`CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_tx_id ON ${qualifiedName} (_tx_id)`);
101
+ for (const [colName, col] of Object.entries(tableDef.columns)) {
102
+ if (col.indexed) {
103
+ statements.push(`CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_${colName} ON ${qualifiedName} (${colName})`);
104
+ }
105
+ }
106
+ for (const [colName, col] of Object.entries(tableDef.columns)) {
107
+ if (col.search) {
108
+ statements.push(`CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_${colName}_trgm ON ${qualifiedName} USING gin (${colName} gin_trgm_ops)`);
109
+ }
110
+ }
111
+ if (tableDef.indexes) {
112
+ for (let i = 0;i < tableDef.indexes.length; i++) {
113
+ const cols = tableDef.indexes[i];
114
+ const idxName = `idx_${schemaName}_${tableName}_composite_${i}`;
115
+ statements.push(`CREATE INDEX IF NOT EXISTS ${idxName} ON ${qualifiedName} (${cols.join(", ")})`);
116
+ }
117
+ }
118
+ if (tableDef.uniqueKeys) {
119
+ for (let i = 0;i < tableDef.uniqueKeys.length; i++) {
120
+ const cols = tableDef.uniqueKeys[i];
121
+ const constraintName = `uq_${schemaName}_${tableName}_${cols.join("_")}`;
122
+ statements.push(`ALTER TABLE ${qualifiedName} ADD CONSTRAINT ${constraintName} UNIQUE (${cols.join(", ")})`);
123
+ }
124
+ }
125
+ }
126
+ const hashInput = JSON.stringify({
127
+ name: def.name,
128
+ version: def.version,
129
+ schema: def.schema,
130
+ sources: def.sources
131
+ }, (_key, value) => typeof value === "bigint" ? value.toString() : value);
132
+ const hash = String(Bun.hash(hashInput));
133
+ return { statements, hash };
134
+ }
135
+ // src/schema/deployer.ts
136
+ import { sql } from "kysely";
137
+ function toJsonSafe(obj) {
138
+ return JSON.parse(JSON.stringify(obj, (_key, value) => typeof value === "bigint" ? value.toString() : value));
139
+ }
140
+ function diffSchema(existing, incoming) {
141
+ const existingTables = new Set(Object.keys(existing));
142
+ const incomingTables = new Set(Object.keys(incoming));
143
+ const addedTables = [...incomingTables].filter((t) => !existingTables.has(t));
144
+ const removedTables = [...existingTables].filter((t) => !incomingTables.has(t));
145
+ const tables = {};
146
+ for (const tableName of incomingTables) {
147
+ if (!existingTables.has(tableName))
148
+ continue;
149
+ const existingCols = existing[tableName].columns;
150
+ const incomingCols = incoming[tableName].columns;
151
+ const existingKeys = new Set(Object.keys(existingCols));
152
+ const incomingKeys = new Set(Object.keys(incomingCols));
153
+ tables[tableName] = {
154
+ added: [...incomingKeys].filter((k) => !existingKeys.has(k)),
155
+ removed: [...existingKeys].filter((k) => !incomingKeys.has(k)),
156
+ changed: [...incomingKeys].filter((k) => {
157
+ if (!existingKeys.has(k))
158
+ return false;
159
+ return JSON.stringify(existingCols[k]) !== JSON.stringify(incomingCols[k]);
160
+ })
161
+ };
162
+ }
163
+ return { addedTables, removedTables, tables };
164
+ }
165
+ function hasBreakingChanges(diff) {
166
+ const reasons = [];
167
+ if (diff.removedTables.length > 0) {
168
+ reasons.push(`removed tables: [${diff.removedTables.join(", ")}]`);
169
+ }
170
+ for (const [table, colDiff] of Object.entries(diff.tables)) {
171
+ if (colDiff.removed.length > 0) {
172
+ reasons.push(`${table}: removed columns [${colDiff.removed.join(", ")}]`);
173
+ }
174
+ if (colDiff.changed.length > 0) {
175
+ reasons.push(`${table}: changed columns [${colDiff.changed.join(", ")}]`);
176
+ }
177
+ }
178
+ return { breaking: reasons.length > 0, reasons };
179
+ }
180
+ async function deploySchema(db, def, handlerPath, opts) {
181
+ validateSubgraphDefinition(def);
182
+ const { statements, hash } = generateSubgraphSQL(def, opts?.schemaName);
183
+ const { getSubgraph, registerSubgraph } = await import("@secondlayer/shared/db/queries/subgraphs");
184
+ const existing = await getSubgraph(db, def.name, opts?.apiKeyId);
185
+ const schemaName = opts?.schemaName ?? pgSchemaName(def.name);
186
+ const regData = {
187
+ name: def.name,
188
+ version: def.version || "1.0.0",
189
+ definition: toJsonSafe({ name: def.name, version: def.version, description: def.description, sources: def.sources, schema: def.schema }),
190
+ schemaHash: hash,
191
+ handlerPath,
192
+ apiKeyId: opts?.apiKeyId,
193
+ schemaName
194
+ };
195
+ if (existing) {
196
+ if (existing.schema_hash === hash && !opts?.forceReindex) {
197
+ const { updateSubgraphHandlerPath } = await import("@secondlayer/shared/db/queries/subgraphs");
198
+ await updateSubgraphHandlerPath(db, def.name, handlerPath);
199
+ return { action: "unchanged", subgraphId: existing.id };
200
+ }
201
+ if (existing.schema_hash === hash && opts?.forceReindex) {
202
+ await sql.raw(`DROP SCHEMA IF EXISTS "${schemaName}" CASCADE`).execute(db);
203
+ for (const stmt of statements) {
204
+ await sql.raw(stmt).execute(db);
205
+ }
206
+ const sg3 = await registerSubgraph(db, regData);
207
+ return { action: "reindexed", subgraphId: sg3.id };
208
+ }
209
+ const existingDef = existing.definition;
210
+ if (existingDef.schema) {
211
+ const diff = diffSchema(existingDef.schema, def.schema);
212
+ const { breaking, reasons } = hasBreakingChanges(diff);
213
+ if (breaking) {
214
+ if (!opts?.forceReindex) {
215
+ throw new Error(`Breaking schema change detected (${reasons.join("; ")}). Use --reindex to force rebuild, or delete the subgraph first.`);
216
+ }
217
+ await sql.raw(`DROP SCHEMA IF EXISTS "${schemaName}" CASCADE`).execute(db);
218
+ for (const stmt of statements) {
219
+ await sql.raw(stmt).execute(db);
220
+ }
221
+ const sg3 = await registerSubgraph(db, regData);
222
+ return { action: "reindexed", subgraphId: sg3.id };
223
+ }
224
+ for (const tableName of diff.addedTables) {
225
+ const tableDef = def.schema[tableName];
226
+ const qualifiedName = `${schemaName}.${tableName}`;
227
+ const colDefs = [
228
+ `_id BIGSERIAL PRIMARY KEY`,
229
+ `_block_height BIGINT NOT NULL`,
230
+ `_tx_id TEXT NOT NULL`,
231
+ `_created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()`
232
+ ];
233
+ for (const [colName, col] of Object.entries(tableDef.columns)) {
234
+ const nullable = col.nullable ? "" : " NOT NULL";
235
+ colDefs.push(`${colName} ${TYPE_MAP[col.type]}${nullable}`);
236
+ }
237
+ await sql.raw(`CREATE TABLE IF NOT EXISTS ${qualifiedName} (
238
+ ${colDefs.join(`,
239
+ `)}
240
+ )`).execute(db);
241
+ await sql.raw(`CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_block_height ON ${qualifiedName} (_block_height)`).execute(db);
242
+ await sql.raw(`CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_tx_id ON ${qualifiedName} (_tx_id)`).execute(db);
243
+ for (const [colName, col] of Object.entries(tableDef.columns)) {
244
+ if (col.indexed) {
245
+ await sql.raw(`CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_${colName} ON ${qualifiedName} (${colName})`).execute(db);
246
+ }
247
+ if (col.search) {
248
+ await sql.raw(`CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_${colName}_trgm ON ${qualifiedName} USING gin (${colName} gin_trgm_ops)`).execute(db);
249
+ }
250
+ }
251
+ }
252
+ for (const [tableName, colDiff] of Object.entries(diff.tables)) {
253
+ if (colDiff.added.length === 0)
254
+ continue;
255
+ const qualifiedName = `${schemaName}.${tableName}`;
256
+ const tableDef = def.schema[tableName];
257
+ for (const colName of colDiff.added) {
258
+ const col = tableDef.columns[colName];
259
+ const sqlType = TYPE_MAP[col.type];
260
+ const nullable = col.nullable ? "" : " NOT NULL DEFAULT " + getDefault(col.type);
261
+ await sql.raw(`ALTER TABLE ${qualifiedName} ADD COLUMN ${colName} ${sqlType}${nullable}`).execute(db);
262
+ if (col.indexed) {
263
+ await sql.raw(`CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_${colName} ON ${qualifiedName} (${colName})`).execute(db);
264
+ }
265
+ if (col.search) {
266
+ await sql.raw(`CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_${colName}_trgm ON ${qualifiedName} USING gin (${colName} gin_trgm_ops)`).execute(db);
267
+ }
268
+ }
269
+ }
270
+ }
271
+ const sg2 = await registerSubgraph(db, regData);
272
+ return { action: "updated", subgraphId: sg2.id };
273
+ }
274
+ for (const stmt of statements) {
275
+ await sql.raw(stmt).execute(db);
276
+ }
277
+ const sg = await registerSubgraph(db, regData);
278
+ return { action: "created", subgraphId: sg.id };
279
+ }
280
+ function getDefault(type) {
281
+ switch (type) {
282
+ case "text":
283
+ case "principal":
284
+ return "''";
285
+ case "uint":
286
+ case "int":
287
+ return "0";
288
+ case "boolean":
289
+ return "false";
290
+ case "timestamp":
291
+ return "NOW()";
292
+ case "jsonb":
293
+ return "'{}'";
294
+ default:
295
+ return "''";
296
+ }
297
+ }
298
+ export {
299
+ generateSubgraphSQL,
300
+ diffSchema,
301
+ deploySchema
302
+ };
303
+
304
+ //# debugId=7C395A847CABC5D164756E2164756E21
305
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,13 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/validate.ts", "../src/schema/utils.ts", "../src/schema/generator.ts", "../src/schema/deployer.ts"],
4
+ "sourcesContent": [
5
+ "import { z } from \"zod\";\nimport type { ColumnType, SubgraphColumn, SubgraphTable, SubgraphSource, SubgraphDefinition } from \"./types.ts\";\n\nexport const SubgraphNameSchema: z.ZodType<string> = z\n .string()\n .min(1)\n .max(63)\n .regex(\n /^[a-z][a-z0-9-]*$/,\n \"Must start with lowercase letter, contain only lowercase alphanumeric and hyphens\",\n );\n\nexport const ColumnTypeSchema: z.ZodType<ColumnType> = z.enum([\n \"text\",\n \"uint\",\n \"int\",\n \"principal\",\n \"boolean\",\n \"timestamp\",\n \"jsonb\",\n]);\n\nexport const SubgraphColumnSchema: z.ZodType<SubgraphColumn> = z.object({\n type: ColumnTypeSchema,\n nullable: z.boolean().optional(),\n indexed: z.boolean().optional(),\n search: z.boolean().optional(),\n default: z.union([z.string(), z.number(), z.boolean()]).optional(),\n}) as z.ZodType<SubgraphColumn>;\n\nexport const SubgraphTableSchema: z.ZodType<SubgraphTable> = z.object({\n columns: z\n .record(z.string(), SubgraphColumnSchema)\n .refine((c) => Object.keys(c).length > 0, \"Table must have at least one column\"),\n indexes: z.array(z.array(z.string())).optional(),\n uniqueKeys: z.array(z.array(z.string())).optional(),\n}) as z.ZodType<SubgraphTable>;\n\nexport const SubgraphSchemaSchema: z.ZodType<Record<string, SubgraphTable>> = z\n .record(z.string(), SubgraphTableSchema)\n .refine((s) => Object.keys(s).length > 0, \"Schema must have at least one table\") as z.ZodType<Record<string, SubgraphTable>>;\n\nexport const SubgraphSourceSchema: z.ZodType<SubgraphSource> = z\n .object({\n contract: z.string().optional(),\n event: z.string().optional(),\n function: z.string().optional(),\n type: z.string().optional(),\n minAmount: z.bigint().optional(),\n })\n .refine(\n (s) => s.contract || s.type,\n \"Source must specify at least 'contract' or 'type'\",\n ) as z.ZodType<SubgraphSource>;\n\nexport const SubgraphDefinitionSchema: z.ZodType<SubgraphDefinition> = z.object({\n name: SubgraphNameSchema,\n version: z.string().optional(),\n description: z.string().optional(),\n sources: z.array(SubgraphSourceSchema).min(1, \"Must have at least one source\"),\n schema: SubgraphSchemaSchema,\n handlers: z.record(z.string(), z.function()),\n}) 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 return SubgraphDefinitionSchema.parse(def);\n}\n",
6
+ "// Re-export canonical pgSchemaName from shared\nexport { pgSchemaName } from \"@secondlayer/shared/db/queries/subgraphs\";\n",
7
+ "import type { ColumnType, SubgraphDefinition } from \"../types.ts\";\nimport { pgSchemaName } from \"./utils.ts\";\n\nexport const TYPE_MAP: Record<ColumnType, string> = {\n text: \"TEXT\",\n uint: \"BIGINT\",\n int: \"INTEGER\",\n principal: \"TEXT\",\n boolean: \"BOOLEAN\",\n timestamp: \"TIMESTAMPTZ\",\n jsonb: \"JSONB\",\n};\n\nexport interface GeneratedSQL {\n statements: string[];\n hash: string;\n}\n\nfunction escapeLiteralDefault(value: unknown): string {\n if (value === null || value === undefined) return \"NULL\";\n if (typeof value === \"number\" || typeof value === \"bigint\") return String(value);\n if (typeof value === \"boolean\") return value ? \"TRUE\" : \"FALSE\";\n return `'${String(value).replace(/'/g, \"''\")}'`;\n}\n\n/**\n * Generates PostgreSQL DDL statements for a subgraph definition.\n * Creates a dedicated schema `subgraph_<name>` with one table per schema entry,\n * each with auto-columns and indexes.\n */\nexport function generateSubgraphSQL(def: SubgraphDefinition, schemaNameOverride?: string): GeneratedSQL {\n const schemaName = schemaNameOverride ?? pgSchemaName(def.name);\n const statements: string[] = [];\n\n // Check if any column uses search (trigram)\n const needsTrgm = Object.values(def.schema).some((table) =>\n Object.values(table.columns).some((col) => col.search),\n );\n\n if (needsTrgm) {\n statements.push(`CREATE EXTENSION IF NOT EXISTS pg_trgm`);\n }\n\n // Schema namespace\n statements.push(`CREATE SCHEMA IF NOT EXISTS ${schemaName}`);\n\n // One table per schema entry\n for (const [tableName, tableDef] of Object.entries(def.schema)) {\n const qualifiedName = `${schemaName}.${tableName}`;\n\n // Auto-columns + user columns\n const columnDefs: string[] = [\n `_id BIGSERIAL PRIMARY KEY`,\n `_block_height BIGINT NOT NULL`,\n `_tx_id TEXT NOT NULL`,\n `_created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()`,\n ];\n\n for (const [colName, col] of Object.entries(tableDef.columns)) {\n const sqlType = TYPE_MAP[col.type];\n const nullable = col.nullable ? \"\" : \" NOT NULL\";\n let colDef = `${colName} ${sqlType}${nullable}`;\n if (col.default !== undefined) {\n colDef += ` DEFAULT ${escapeLiteralDefault(col.default)}`;\n }\n columnDefs.push(colDef);\n }\n\n statements.push(\n `CREATE TABLE IF NOT EXISTS ${qualifiedName} (\\n ${columnDefs.join(\",\\n \")}\\n)`,\n );\n\n // Auto-indexes on meta columns\n statements.push(\n `CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_block_height ON ${qualifiedName} (_block_height)`,\n );\n statements.push(\n `CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_tx_id ON ${qualifiedName} (_tx_id)`,\n );\n\n // Single-column indexes\n for (const [colName, col] of Object.entries(tableDef.columns)) {\n if (col.indexed) {\n statements.push(\n `CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_${colName} ON ${qualifiedName} (${colName})`,\n );\n }\n }\n\n // Trigram GIN indexes for search columns\n for (const [colName, col] of Object.entries(tableDef.columns)) {\n if (col.search) {\n statements.push(\n `CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_${colName}_trgm ON ${qualifiedName} USING gin (${colName} gin_trgm_ops)`,\n );\n }\n }\n\n // Composite indexes\n if (tableDef.indexes) {\n for (let i = 0; i < tableDef.indexes.length; i++) {\n const cols = tableDef.indexes[i]!;\n const idxName = `idx_${schemaName}_${tableName}_composite_${i}`;\n statements.push(\n `CREATE INDEX IF NOT EXISTS ${idxName} ON ${qualifiedName} (${cols.join(\", \")})`,\n );\n }\n }\n\n // Unique constraints (required for upsert ON CONFLICT)\n if (tableDef.uniqueKeys) {\n for (let i = 0; i < tableDef.uniqueKeys.length; i++) {\n const cols = tableDef.uniqueKeys[i]!;\n const constraintName = `uq_${schemaName}_${tableName}_${cols.join(\"_\")}`;\n statements.push(\n `ALTER TABLE ${qualifiedName} ADD CONSTRAINT ${constraintName} UNIQUE (${cols.join(\", \")})`,\n );\n }\n }\n }\n\n // Hash based on schema structure (excludes handler)\n const hashInput = JSON.stringify({\n name: def.name,\n version: def.version,\n schema: def.schema,\n sources: def.sources,\n }, (_key, value) => typeof value === \"bigint\" ? value.toString() : value);\n const hash = String(Bun.hash(hashInput));\n\n return { statements, hash };\n}\n",
8
+ "import { sql, type Kysely } from \"kysely\";\nimport type { Database } from \"@secondlayer/shared/db\";\nimport { validateSubgraphDefinition } from \"../validate.ts\";\nimport { generateSubgraphSQL, TYPE_MAP } from \"./generator.ts\";\nimport { pgSchemaName } from \"./utils.ts\";\nimport type { SubgraphDefinition, SubgraphSchema } from \"../types.ts\";\n\ntype AnyDb = Kysely<Database>;\n\n/** Deep-clone an object, converting BigInts to strings for JSON serialization. */\nfunction toJsonSafe(obj: unknown): unknown {\n return JSON.parse(JSON.stringify(obj, (_key, value) =>\n typeof value === \"bigint\" ? value.toString() : value\n ));\n}\n\nexport interface TableDiff {\n /** Tables added to the schema */\n addedTables: string[];\n /** Tables removed from the schema */\n removedTables: string[];\n /** Per-table column diffs (only for tables present in both) */\n tables: Record<string, ColumnDiff>;\n}\n\nexport interface ColumnDiff {\n added: string[];\n removed: string[];\n changed: string[];\n}\n\n/**\n * Compare two multi-table subgraph schemas and return differences.\n */\nexport function diffSchema(existing: SubgraphSchema, incoming: SubgraphSchema): TableDiff {\n const existingTables = new Set(Object.keys(existing));\n const incomingTables = new Set(Object.keys(incoming));\n\n const addedTables = [...incomingTables].filter((t) => !existingTables.has(t));\n const removedTables = [...existingTables].filter((t) => !incomingTables.has(t));\n\n const tables: Record<string, ColumnDiff> = {};\n for (const tableName of incomingTables) {\n if (!existingTables.has(tableName)) continue;\n const existingCols = existing[tableName]!.columns;\n const incomingCols = incoming[tableName]!.columns;\n\n const existingKeys = new Set(Object.keys(existingCols));\n const incomingKeys = new Set(Object.keys(incomingCols));\n\n tables[tableName] = {\n added: [...incomingKeys].filter((k) => !existingKeys.has(k)),\n removed: [...existingKeys].filter((k) => !incomingKeys.has(k)),\n changed: [...incomingKeys].filter((k) => {\n if (!existingKeys.has(k)) return false;\n return JSON.stringify(existingCols[k]) !== JSON.stringify(incomingCols[k]);\n }),\n };\n }\n\n return { addedTables, removedTables, tables };\n}\n\n/**\n * Returns true if the diff contains any breaking changes\n * (removed tables, removed columns, or changed column types).\n */\nfunction hasBreakingChanges(diff: TableDiff): { breaking: boolean; reasons: string[] } {\n const reasons: string[] = [];\n if (diff.removedTables.length > 0) {\n reasons.push(`removed tables: [${diff.removedTables.join(\", \")}]`);\n }\n for (const [table, colDiff] of Object.entries(diff.tables)) {\n if (colDiff.removed.length > 0) {\n reasons.push(`${table}: removed columns [${colDiff.removed.join(\", \")}]`);\n }\n if (colDiff.changed.length > 0) {\n reasons.push(`${table}: changed columns [${colDiff.changed.join(\", \")}]`);\n }\n }\n return { breaking: reasons.length > 0, reasons };\n}\n\n/**\n * Deploy a subgraph schema to the database.\n * - New subgraph → CREATE SCHEMA + tables + register\n * - Same hash → no-op\n * - Additive change → ALTER TABLE ADD COLUMN / CREATE TABLE for new tables\n * - Breaking change → throws error\n */\nexport async function deploySchema(\n db: AnyDb,\n def: SubgraphDefinition,\n handlerPath: string,\n opts?: { forceReindex?: boolean; apiKeyId?: string; schemaName?: string },\n): Promise<{ action: \"created\" | \"unchanged\" | \"updated\" | \"reindexed\"; subgraphId: string }> {\n validateSubgraphDefinition(def);\n\n const { statements, hash } = generateSubgraphSQL(def, opts?.schemaName);\n const { getSubgraph, registerSubgraph } = await import(\"@secondlayer/shared/db/queries/subgraphs\");\n\n const existing = await getSubgraph(db, def.name, opts?.apiKeyId);\n\n const schemaName = opts?.schemaName ?? pgSchemaName(def.name);\n const regData = {\n name: def.name,\n version: def.version || \"1.0.0\",\n definition: toJsonSafe({ name: def.name, version: def.version, description: def.description, sources: def.sources, schema: def.schema }) as Record<string, unknown>,\n schemaHash: hash,\n handlerPath,\n apiKeyId: opts?.apiKeyId,\n schemaName,\n };\n\n if (existing) {\n if (existing.schema_hash === hash && !opts?.forceReindex) {\n // Update handler path in case file moved\n const { updateSubgraphHandlerPath } = await import(\"@secondlayer/shared/db/queries/subgraphs\");\n await updateSubgraphHandlerPath(db, def.name, handlerPath);\n return { action: \"unchanged\", subgraphId: existing.id };\n }\n\n if (existing.schema_hash === hash && opts?.forceReindex) {\n // Same schema but force reindex requested — drop and recreate\n await sql.raw(`DROP SCHEMA IF EXISTS \"${schemaName}\" CASCADE`).execute(db);\n for (const stmt of statements) {\n await sql.raw(stmt).execute(db);\n }\n const sg = await registerSubgraph(db, regData);\n return { action: \"reindexed\", subgraphId: sg.id };\n }\n\n const existingDef = existing.definition as { schema?: SubgraphSchema };\n if (existingDef.schema) {\n const diff = diffSchema(existingDef.schema, def.schema);\n const { breaking, reasons } = hasBreakingChanges(diff);\n\n if (breaking) {\n if (!opts?.forceReindex) {\n throw new Error(\n `Breaking schema change detected (${reasons.join(\"; \")}). ` +\n `Use --reindex to force rebuild, or delete the subgraph first.`,\n );\n }\n\n // Force reindex: drop schema, recreate, register, caller triggers reindex\n await sql.raw(`DROP SCHEMA IF EXISTS \"${schemaName}\" CASCADE`).execute(db);\n for (const stmt of statements) {\n await sql.raw(stmt).execute(db);\n }\n const sg = await registerSubgraph(db, regData);\n return { action: \"reindexed\", subgraphId: sg.id };\n }\n\n // Create new tables\n for (const tableName of diff.addedTables) {\n const tableDef = def.schema[tableName]!;\n const qualifiedName = `${schemaName}.${tableName}`;\n const colDefs = [\n `_id BIGSERIAL PRIMARY KEY`,\n `_block_height BIGINT NOT NULL`,\n `_tx_id TEXT NOT NULL`,\n `_created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()`,\n ];\n for (const [colName, col] of Object.entries(tableDef.columns)) {\n const nullable = col.nullable ? \"\" : \" NOT NULL\";\n colDefs.push(`${colName} ${TYPE_MAP[col.type]!}${nullable}`);\n }\n await sql.raw(\n `CREATE TABLE IF NOT EXISTS ${qualifiedName} (\\n ${colDefs.join(\",\\n \")}\\n)`,\n ).execute(db);\n await sql.raw(\n `CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_block_height ON ${qualifiedName} (_block_height)`,\n ).execute(db);\n await sql.raw(\n `CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_tx_id ON ${qualifiedName} (_tx_id)`,\n ).execute(db);\n for (const [colName, col] of Object.entries(tableDef.columns)) {\n if (col.indexed) {\n await sql.raw(\n `CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_${colName} ON ${qualifiedName} (${colName})`,\n ).execute(db);\n }\n if (col.search) {\n await sql.raw(\n `CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_${colName}_trgm ON ${qualifiedName} USING gin (${colName} gin_trgm_ops)`,\n ).execute(db);\n }\n }\n }\n\n // Add columns to existing tables\n for (const [tableName, colDiff] of Object.entries(diff.tables)) {\n if (colDiff.added.length === 0) continue;\n const qualifiedName = `${schemaName}.${tableName}`;\n const tableDef = def.schema[tableName]!;\n for (const colName of colDiff.added) {\n const col = tableDef.columns[colName]!;\n const sqlType = TYPE_MAP[col.type]!;\n const nullable = col.nullable ? \"\" : \" NOT NULL DEFAULT \" + getDefault(col.type);\n await sql.raw(\n `ALTER TABLE ${qualifiedName} ADD COLUMN ${colName} ${sqlType}${nullable}`,\n ).execute(db);\n if (col.indexed) {\n await sql.raw(\n `CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_${colName} ON ${qualifiedName} (${colName})`,\n ).execute(db);\n }\n if (col.search) {\n await sql.raw(\n `CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_${colName}_trgm ON ${qualifiedName} USING gin (${colName} gin_trgm_ops)`,\n ).execute(db);\n }\n }\n }\n }\n\n const sg = await registerSubgraph(db, regData);\n return { action: \"updated\", subgraphId: sg.id };\n }\n\n // New subgraph — execute all DDL\n for (const stmt of statements) {\n await sql.raw(stmt).execute(db);\n }\n\n const sg = await registerSubgraph(db, regData);\n return { action: \"created\", subgraphId: sg.id };\n}\n\nfunction getDefault(type: string): string {\n switch (type) {\n case \"text\":\n case \"principal\":\n return \"''\";\n case \"uint\":\n case \"int\":\n return \"0\";\n case \"boolean\":\n return \"false\";\n case \"timestamp\":\n return \"NOW()\";\n case \"jsonb\":\n return \"'{}'\";\n default:\n return \"''\";\n }\n}\n"
9
+ ],
10
+ "mappings": "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",
11
+ "debugId": "7C395A847CABC5D164756E2164756E21",
12
+ "names": []
13
+ }
File without changes