houdini 2.0.0-next.28 → 2.0.0-next.29

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 (50) hide show
  1. package/build/cmd/init.js +14 -13
  2. package/build/lib/ast.d.ts +1 -1
  3. package/build/lib/codegen.d.ts +4 -4
  4. package/build/lib/codegen.js +136 -77
  5. package/build/lib/config.d.ts +2 -2
  6. package/build/lib/config.js +2 -1
  7. package/build/lib/constants.js +4 -0
  8. package/build/lib/database.d.ts +3 -3
  9. package/build/lib/database.js +60 -92
  10. package/build/lib/db.d.ts +13 -0
  11. package/build/lib/db.js +134 -0
  12. package/build/lib/fs.d.ts +6 -6
  13. package/build/lib/fs.js +4 -4
  14. package/build/lib/index.d.ts +1 -0
  15. package/build/lib/index.js +1 -0
  16. package/build/lib/logger.js +2 -2
  17. package/build/lib/parse.js +2 -0
  18. package/build/lib/plugins.d.ts +1 -1
  19. package/build/lib/plugins.js +13 -2
  20. package/build/lib/project.js +6 -2
  21. package/build/lib/walk.d.ts +7 -3
  22. package/build/node/index.js +28 -38
  23. package/build/package.json +28 -31
  24. package/build/router/conventions.d.ts +4 -4
  25. package/build/router/jwt.js +16 -31
  26. package/build/router/match.d.ts +1 -1
  27. package/build/router/match.js +2 -4
  28. package/build/router/session.js +1 -1
  29. package/build/runtime/cache/gc.js +1 -0
  30. package/build/runtime/cache/index.d.ts +2 -2
  31. package/build/runtime/cache/index.js +22 -1
  32. package/build/runtime/cache/lists.d.ts +5 -5
  33. package/build/runtime/cache/lists.js +9 -0
  34. package/build/runtime/cache/staleManager.js +25 -0
  35. package/build/runtime/cache/storage.js +4 -0
  36. package/build/runtime/cache/subscription.js +1 -0
  37. package/build/runtime/client.js +2 -0
  38. package/build/runtime/config.d.ts +1 -1
  39. package/build/runtime/deepEquals.js +2 -4
  40. package/build/runtime/documentStore.js +30 -4
  41. package/build/runtime/pagination.js +2 -1
  42. package/build/runtime/types.d.ts +1 -0
  43. package/build/runtime/types.js +10 -1
  44. package/build/vite/hmr.js +112 -89
  45. package/build/vite/houdini.js +1 -0
  46. package/build/vite/index.d.ts +2 -2
  47. package/build/vite/index.js +13 -5
  48. package/build/vite/schema.d.ts +1 -1
  49. package/build/vite/schema.js +70 -31
  50. package/package.json +32 -33
package/build/cmd/init.js CHANGED
@@ -92,10 +92,7 @@ async function init(_path, args) {
92
92
  message: `What's the URL for your api? ${number_of_round === 1 ? "" : `(attempt ${number_of_round})`}`,
93
93
  placeholder: `http://localhost:4000/graphql ${number_of_round === 1 ? "" : "Authorization=Bearer MyToken"}`,
94
94
  validate: (value) => {
95
- if (value === "") {
96
- return;
97
- }
98
- if (!value.startsWith("http")) {
95
+ if (value && !value.startsWith("http")) {
99
96
  return "Please enter a valid URL";
100
97
  }
101
98
  }
@@ -145,8 +142,7 @@ async function init(_path, args) {
145
142
  message: "Where is the schema file?",
146
143
  initialValue: "./schema.graphql",
147
144
  validate: (value) => {
148
- if (!value)
149
- return "Please enter a valid path";
145
+ if (!value) return "Please enter a valid path";
150
146
  try {
151
147
  fs.statSync(path.resolve(value));
152
148
  } catch {
@@ -168,8 +164,7 @@ async function init(_path, args) {
168
164
  message: "Where is your schema located?",
169
165
  initialValue: schemaPath,
170
166
  validate: (value) => {
171
- if (!value)
172
- return "Please enter a valid schemaPath";
167
+ if (!value) return "Please enter a valid schemaPath";
173
168
  }
174
169
  })
175
170
  },
@@ -285,13 +280,19 @@ async function houdiniConfig(configPath, schemaPath, module, frameworkInfo, url,
285
280
 
286
281
  /** @type {import('houdini').ConfigFile} */
287
282
  const config = ${configObj}`;
288
- const content = module === "esm" ? `${content_base}
283
+ const content = module === "esm" ? (
284
+ // ESM default config
285
+ `${content_base}
289
286
 
290
287
  export default config
291
- ` : `${content_base}
288
+ `
289
+ ) : (
290
+ // CommonJS default config
291
+ `${content_base}
292
292
 
293
293
  module.exports = config
294
- `;
294
+ `
295
+ );
295
296
  await fs.writeFile(configPath, content);
296
297
  return false;
297
298
  }
@@ -471,12 +472,12 @@ async function packageJSON(targetPath, frameworkInfo) {
471
472
  }
472
473
  packageJSON2.devDependencies = {
473
474
  ...packageJSON2.devDependencies,
474
- houdini: "^2.0.0-next.28"
475
+ houdini: "^2.0.0-next.29"
475
476
  };
476
477
  if (frameworkInfo.framework === "svelte" || frameworkInfo.framework === "kit") {
477
478
  packageJSON2.devDependencies = {
478
479
  ...packageJSON2.devDependencies,
479
- "houdini-svelte": "^3.0.0-next.29"
480
+ "houdini-svelte": "^3.0.0-next.30"
480
481
  };
481
482
  } else {
482
483
  throw new Error(`Unmanaged framework: "${JSON.stringify(frameworkInfo)}"`);
@@ -12,5 +12,5 @@ export declare function find_exported_fn(body: Statement[], name: string): {
12
12
  declaration: FunctionDeclaration | FunctionExpression | ArrowFunctionExpression | null | Identifier | CallExpression;
13
13
  export: ExportNamedDeclaration;
14
14
  } | null;
15
- export declare function find_exported_id(program: Program, name: string): recast.types.namedTypes.ExportNamedDeclaration;
15
+ export declare function find_exported_id(program: Program, name: string): recast.types.namedTypes.ExportNamedDeclaration | undefined;
16
16
  export {};
@@ -1,6 +1,6 @@
1
- import { type DatabaseSync } from 'node:sqlite';
2
1
  import * as conventions from '../router/conventions.js';
3
2
  import type { Config } from './config.js';
3
+ import { type Db } from './db.js';
4
4
  import type { ProjectManifest } from './types.js';
5
5
  export type PluginSpec = {
6
6
  name: string;
@@ -30,8 +30,8 @@ export type Adapter = ((args: {
30
30
  outDir: string;
31
31
  }) => Promise<void> | void;
32
32
  };
33
- export declare function connect_db(config: Config): [DatabaseSync, string];
34
- export declare function init_db(config: Config, preserve: boolean): Promise<[DatabaseSync, string]>;
33
+ export declare function connect_db(config: Config): Promise<[Db, string]>;
34
+ export declare function init_db(config: Config, preserve: boolean): Promise<[Db, string]>;
35
35
  export type CompilerProxy = {
36
36
  close: () => Promise<void>;
37
37
  trigger_hook: (name: PipelineHook, opts?: {
@@ -43,7 +43,7 @@ export type CompilerProxy = {
43
43
  run_pipeline: (options: RunPipelineOptions) => Promise<Record<PipelineHook, Record<string, any>>>;
44
44
  };
45
45
  export declare function plugin_db_key(name: string): string;
46
- export declare function codegen_setup(config: Config, mode: string, db: DatabaseSync, db_file: string): Promise<CompilerProxy>;
46
+ export declare function codegen_setup(config: Config, mode: string, db: Db, db_file: string): Promise<CompilerProxy>;
47
47
  export declare const PIPELINE_HOOKS: readonly ["Config", "AfterLoad", "Schema", "ExtractDocuments", "AfterExtract", "BeforeValidate", "Validate", "AfterValidate", "BeforeGenerate", "GenerateDocuments", "GenerateRuntime", "AfterGenerate"];
48
48
  export type PipelineHook = (typeof PIPELINE_HOOKS)[number];
49
49
  export type RunPipelineOptions = {
@@ -1,25 +1,66 @@
1
1
  import { spawn } from "node:child_process";
2
+ import { writeFileSync } from "node:fs";
3
+ import { tmpdir } from "node:os";
2
4
  import path from "node:path";
3
5
  import { createInterface } from "node:readline";
4
- import sqlite from "node:sqlite";
5
6
  import { WebSocket } from "ws";
7
+ const wasiRunnerPath = path.join(tmpdir(), "houdini-wasi-runner.mjs");
8
+ writeFileSync(
9
+ wasiRunnerPath,
10
+ `import{WASI}from'node:wasi';
11
+ import{readFileSync}from'node:fs';
12
+ import{Worker,isMainThread,workerData,MessageChannel,receiveMessageOnPort}from'worker_threads';
13
+ const[,,w,...r]=process.argv;
14
+ if(isMainThread){
15
+ const{port1:p1,port2:p2}=new MessageChannel();
16
+ const sb=new Int32Array(new SharedArrayBuffer(4));
17
+ process.stdin.on('error',()=>{});
18
+ process.stdin.on('data',d=>{p1.postMessage(d);Atomics.add(sb,0,1);Atomics.notify(sb,0);});
19
+ process.stdin.on('end',()=>{p1.postMessage(null);Atomics.add(sb,0,1);Atomics.notify(sb,0);});
20
+ const wk=new Worker(new URL(import.meta.url),{workerData:{w,r,p:p2,sb},transferList:[p2]});
21
+ wk.on('exit',c=>process.exit(c??0));
22
+ }else{
23
+ const{w:wb,r:args,p:port,sb}=workerData;
24
+ const wasi=new WASI({version:'preview1',args:[wb,...args],env:process.env,preopens:{'/':'/'}});
25
+ let mem=null;
26
+ const io=wasi.getImportObject();
27
+ const rfr=io.wasi_snapshot_preview1.fd_read;
28
+ io.wasi_snapshot_preview1.fd_read=(fd,iovs,il,nr)=>{
29
+ if(fd!==0||!mem)return rfr(fd,iovs,il,nr);
30
+ while(Atomics.load(sb,0)===0)Atomics.wait(sb,0,0);
31
+ const m=receiveMessageOnPort(port);
32
+ Atomics.sub(sb,0,1);
33
+ const v=new DataView(mem.buffer);
34
+ if(!m||m.message===null){v.setUint32(nr,0,true);return 0;}
35
+ const b=Buffer.isBuffer(m.message)?m.message:Buffer.from(m.message);
36
+ let wn=0;
37
+ for(let i=0;i<il;i++){
38
+ const p=v.getUint32(iovs+i*8,true),l=v.getUint32(iovs+i*8+4,true);
39
+ const n=Math.min(l,b.length-wn);
40
+ if(n<=0)break;
41
+ new Uint8Array(mem.buffer,p,n).set(b.subarray(wn,wn+n));
42
+ wn+=n;}
43
+ v.setUint32(nr,wn,true);
44
+ return 0;};
45
+ const mod=new WebAssembly.Module(readFileSync(wb));
46
+ const inst=new WebAssembly.Instance(mod,io);
47
+ mem=inst.exports.memory;
48
+ wasi.start(inst);
49
+ process.exit(0);}
50
+ `
51
+ );
6
52
  import * as conventions from "../router/conventions.js";
53
+ import { openDb } from "./db.js";
7
54
  import { create_schema, write_config } from "./database.js";
8
55
  import { format_hook_error } from "./error.js";
9
56
  import * as fs from "./fs.js";
10
57
  import { Logger } from "./logger.js";
11
58
  import { LogLevel } from "./types.js";
12
- function connect_db(config) {
59
+ async function connect_db(config) {
13
60
  const filepath = conventions.db_path(config);
14
- const db = new sqlite.DatabaseSync(filepath);
15
- db.exec("PRAGMA journal_mode = WAL");
16
- db.exec("PRAGMA synchronous = off");
17
- db.exec("PRAGMA cache_size = 10000");
18
- db.exec("PRAGMA temp_store = memory");
19
- db.exec("PRAGMA busy_timeout = 5000");
20
- db.exec("PRAGMA foreign_key = ON");
21
- db.exec("PRAGMA defer_foreign_keys = ON");
61
+ const db = await openDb(filepath);
22
62
  db.exec(create_schema);
63
+ db.flush();
23
64
  return [db, filepath];
24
65
  }
25
66
  async function init_db(config, preserve) {
@@ -38,7 +79,7 @@ async function init_db(config, preserve) {
38
79
  } catch (_e) {
39
80
  }
40
81
  }
41
- return [connect_db(config)[0], db_file];
82
+ return connect_db(config);
42
83
  }
43
84
  function plugin_db_key(name) {
44
85
  if (!name.startsWith("./") && !name.startsWith("../") && !path.isAbsolute(name)) {
@@ -47,6 +88,7 @@ function plugin_db_key(name) {
47
88
  return name.replace(/\./g, "_").replace(/\//g, "__");
48
89
  }
49
90
  async function codegen_setup(config, mode, db, db_file) {
91
+ let _db = db;
50
92
  const logger = new Logger(config.config_file.logLevel ?? LogLevel.Summary);
51
93
  await fs.mkdirpSync(conventions.houdini_root(config));
52
94
  const rawTransport = config.config_file.pluginTransport ?? "websocket";
@@ -57,47 +99,51 @@ async function codegen_setup(config, mode, db, db_file) {
57
99
  const spec_results = {};
58
100
  const stdioStdin = /* @__PURE__ */ new Map();
59
101
  const triggerHookRef = { fn: null };
60
- const wait_for_plugin_db = (configKey, dbKey) => new Promise((resolve, reject) => {
61
- const find_plugin = db.prepare("SELECT * FROM plugins WHERE name = ?");
62
- const interval = setInterval(() => {
63
- const row = find_plugin.get(dbKey);
64
- if (row) {
65
- clearInterval(interval);
66
- db.prepare("UPDATE plugins set config = ? where name = ?").run(
67
- JSON.stringify(
68
- config.plugins.find((p) => p.name === configKey)?.config ?? {}
69
- ),
70
- dbKey
71
- );
72
- const spec = {
73
- name: row.name,
74
- port: row.port,
75
- hooks: new Set(JSON.parse(row.hooks)),
76
- order: row.plugin_order,
77
- directory: config.plugins.find((p) => p.name === configKey)?.directory || ""
78
- };
79
- spec_results[configKey] = spec;
80
- if (row.config_module) {
81
- import(row.config_module).then((module) => {
82
- if (module && typeof module.default === "function") {
83
- config.config_file = module.default(config.config_file);
84
- }
85
- resolver(spec);
86
- });
87
- } else {
88
- resolver(spec);
102
+ const pendingRequests = /* @__PURE__ */ new Map();
103
+ const wait_for_plugin_db = async (configKey, dbKey) => {
104
+ const pollDb = await openDb(db_file);
105
+ return new Promise((resolve, reject) => {
106
+ const interval = setInterval(() => {
107
+ pollDb.reload();
108
+ const row = pollDb.get("SELECT * FROM plugins WHERE name = ?", [dbKey]);
109
+ if (row) {
110
+ clearInterval(interval);
111
+ clearTimeout(timeout);
112
+ pollDb.run("UPDATE plugins SET config = ? WHERE name = ?", [
113
+ JSON.stringify(
114
+ config.plugins.find((p) => p.name === configKey)?.config ?? {}
115
+ ),
116
+ dbKey
117
+ ]);
118
+ pollDb.flush();
119
+ pollDb.close();
120
+ const spec = {
121
+ name: row.name,
122
+ port: row.port,
123
+ hooks: new Set(JSON.parse(row.hooks)),
124
+ order: row.plugin_order,
125
+ directory: config.plugins.find((p) => p.name === configKey)?.directory || ""
126
+ };
127
+ spec_results[configKey] = spec;
128
+ if (row.config_module) {
129
+ import(row.config_module).then((module) => {
130
+ if (module && typeof module.default === "function") {
131
+ config.config_file = module.default(config.config_file);
132
+ }
133
+ resolve(spec);
134
+ });
135
+ } else {
136
+ resolve(spec);
137
+ }
89
138
  }
90
- }
91
- }, 10);
92
- const timeout = setTimeout(() => {
93
- clearInterval(interval);
94
- reject(new Error(`Timeout waiting for plugin ${configKey} to register`));
95
- }, 1e4);
96
- const resolver = (spec) => {
97
- clearTimeout(timeout);
98
- resolve(spec);
99
- };
100
- });
139
+ }, 10);
140
+ const timeout = setTimeout(() => {
141
+ clearInterval(interval);
142
+ pollDb.close();
143
+ reject(new Error(`Timeout waiting for plugin ${configKey} to register`));
144
+ }, 1e4);
145
+ });
146
+ };
101
147
  const wait_for_plugin_stdio = (name, child) => new Promise((resolve, reject) => {
102
148
  const timeout = setTimeout(() => {
103
149
  reject(new Error(`Timeout waiting for plugin ${name} to register`));
@@ -123,24 +169,26 @@ async function codegen_setup(config, mode, db, db_file) {
123
169
  directory: config.plugins.find((p) => p.name === name)?.directory || ""
124
170
  };
125
171
  spec_results[name] = spec;
126
- db.prepare(
172
+ _db.run(
127
173
  `INSERT OR IGNORE INTO plugins (name, hooks, port, plugin_order, include_runtime, config_module, client_plugins)
128
- VALUES (?, ?, ?, ?, ?, ?, ?)`
129
- ).run(
130
- spec.name,
131
- JSON.stringify([...spec.hooks]),
132
- spec.port,
133
- spec.order,
134
- msg.includeRuntime ?? null,
135
- msg.configModule ?? null,
136
- msg.clientPlugins ?? null
174
+ VALUES (?, ?, ?, ?, ?, ?, ?)`,
175
+ [
176
+ spec.name,
177
+ JSON.stringify([...spec.hooks]),
178
+ spec.port,
179
+ spec.order,
180
+ msg.includeRuntime ?? null,
181
+ msg.configModule ?? null,
182
+ msg.clientPlugins ?? null
183
+ ]
137
184
  );
138
- db.prepare("UPDATE plugins SET config = ? WHERE name = ?").run(
185
+ _db.run("UPDATE plugins SET config = ? WHERE name = ?", [
139
186
  JSON.stringify(
140
187
  config.plugins.find((p) => p.name === name)?.config ?? {}
141
188
  ),
142
189
  spec.name
143
- );
190
+ ]);
191
+ _db.flush();
144
192
  if (msg.configModule) {
145
193
  import(msg.configModule).then((module) => {
146
194
  if (module && typeof module.default === "function") {
@@ -161,8 +209,7 @@ async function codegen_setup(config, mode, db, db_file) {
161
209
  }
162
210
  if (msg.type === "response") {
163
211
  const pending = pendingRequests.get(msg.id);
164
- if (!pending)
165
- return;
212
+ if (!pending) return;
166
213
  clearTimeout(pending.timeout);
167
214
  pendingRequests.delete(msg.id);
168
215
  if (msg.error) {
@@ -214,8 +261,7 @@ async function codegen_setup(config, mode, db, db_file) {
214
261
  reject(new Error(`Plugin ${name} stdout closed before registering`));
215
262
  } else {
216
263
  for (const [id, pending] of pendingRequests.entries()) {
217
- if (pending.plugin !== name)
218
- continue;
264
+ if (pending.plugin !== name) continue;
219
265
  clearTimeout(pending.timeout);
220
266
  pendingRequests.delete(id);
221
267
  pending.reject(new Error(`Plugin ${name} closed unexpectedly`));
@@ -223,7 +269,8 @@ async function codegen_setup(config, mode, db, db_file) {
223
269
  }
224
270
  });
225
271
  });
226
- db.prepare("DELETE FROM plugins").run();
272
+ _db.run("DELETE FROM plugins");
273
+ _db.flush();
227
274
  logger.time("Start Plugins");
228
275
  await Promise.all(
229
276
  config.plugins.map(async (plugin) => {
@@ -233,18 +280,24 @@ async function codegen_setup(config, mode, db, db_file) {
233
280
  if (jsExtensions.includes(path.extname(plugin.executable))) {
234
281
  executable = "node";
235
282
  args.unshift(plugin.executable);
283
+ } else if (path.extname(plugin.executable) === ".wasm") {
284
+ executable = "node";
285
+ args.unshift(wasiRunnerPath, plugin.executable);
236
286
  }
237
287
  const dbKey = plugin_db_key(plugin.name);
238
288
  args.push("--plugin-key", dbKey);
239
- if (useStdio) {
289
+ const pluginUsesStdio = useStdio || path.extname(plugin.executable) === ".wasm";
290
+ if (pluginUsesStdio) {
240
291
  args.push("--transport", "stdio");
241
292
  }
242
293
  logger.time(`Spawn ${plugin.name}`);
243
294
  const child = spawn(executable, args, {
244
- stdio: useStdio ? ["pipe", "pipe", "inherit"] : ["inherit", "inherit", "inherit"],
295
+ // [stdin, stdout, stderr]: stdio plugins need piped stdin/stdout for the
296
+ // message protocol; stderr is always inherited so plugin logs reach the terminal.
297
+ stdio: pluginUsesStdio ? ["pipe", "pipe", "inherit"] : ["inherit", "inherit", "inherit"],
245
298
  detached: process.platform !== "win32"
246
299
  });
247
- if (useStdio) {
300
+ if (pluginUsesStdio) {
248
301
  stdioStdin.set(dbKey, child.stdin);
249
302
  child.stdin.on("error", (err) => {
250
303
  if (err.code !== "EPIPE") {
@@ -254,7 +307,7 @@ async function codegen_setup(config, mode, db, db_file) {
254
307
  }
255
308
  plugins[plugin.name] = {
256
309
  process: child,
257
- ...await (useStdio ? wait_for_plugin_stdio(plugin.name, child) : wait_for_plugin_db(plugin.name, dbKey))
310
+ ...await (pluginUsesStdio ? wait_for_plugin_stdio(plugin.name, child) : wait_for_plugin_db(plugin.name, dbKey))
258
311
  };
259
312
  logger.timeEnd(`Spawn ${plugin.name}`, LogLevel.Verbose);
260
313
  })
@@ -265,7 +318,6 @@ async function codegen_setup(config, mode, db, db_file) {
265
318
  logger.timeEnd("Start Plugins", LogLevel.Summary);
266
319
  const wsConnections = /* @__PURE__ */ new Map();
267
320
  let messageCounter = 0;
268
- const pendingRequests = /* @__PURE__ */ new Map();
269
321
  async function getOrCreateWS(name, port) {
270
322
  const existing = wsConnections.get(name);
271
323
  if (existing && existing.readyState === WebSocket.OPEN) {
@@ -282,8 +334,7 @@ async function codegen_setup(config, mode, db, db_file) {
282
334
  try {
283
335
  const response = JSON.parse(data.toString());
284
336
  const pending = pendingRequests.get(response.id);
285
- if (!pending)
286
- return;
337
+ if (!pending) return;
287
338
  clearTimeout(pending.timeout);
288
339
  pendingRequests.delete(response.id);
289
340
  switch (response.type) {
@@ -361,7 +412,8 @@ async function codegen_setup(config, mode, db, db_file) {
361
412
  });
362
413
  }
363
414
  };
364
- const trigger_hook = async (hook, {
415
+ _db.reload();
416
+ const _fireHook = async (hook, {
365
417
  parallel_safe,
366
418
  payload,
367
419
  task_id
@@ -387,8 +439,15 @@ async function codegen_setup(config, mode, db, db_file) {
387
439
  }
388
440
  return result;
389
441
  };
442
+ const trigger_hook = async (hook, opts) => {
443
+ _db.flush();
444
+ const result = await _fireHook(hook, opts);
445
+ _db.reload();
446
+ return result;
447
+ };
390
448
  triggerHookRef.fn = trigger_hook;
391
- await write_config(db, config, invoke_hook, plugin_specs, mode, logger);
449
+ await write_config(_db, config, invoke_hook, plugin_specs, mode, logger);
450
+ _db.flush();
392
451
  await trigger_hook("Config");
393
452
  await trigger_hook("AfterLoad");
394
453
  await trigger_hook("Schema");
@@ -214,7 +214,7 @@ export declare class Config {
214
214
  });
215
215
  schema_path(): string;
216
216
  get localApiDir(): string;
217
- api_url(): Promise<string>;
217
+ api_url(): Promise<string | undefined>;
218
218
  get include(): Array<string>;
219
219
  includeFile(filepath: string, { root }?: {
220
220
  root?: string;
@@ -225,7 +225,7 @@ export declare class Config {
225
225
  root?: string;
226
226
  }): boolean;
227
227
  schema_pull_headers(): Promise<any>;
228
- process_env_values(env: Record<string, string | undefined>, value: string | ((env: any) => string)): string;
228
+ process_env_values(env: Record<string, string | undefined>, value: string | ((env: any) => string)): string | undefined;
229
229
  get artifact_dir(): string;
230
230
  get routes_dir(): string;
231
231
  artifactPath(document: graphql.DocumentNode): string;
@@ -1,5 +1,5 @@
1
1
  import * as graphql from "graphql";
2
- import minimatch from "minimatch";
2
+ import { minimatch } from "minimatch";
3
3
  import { plugin_dir } from "../router/conventions.js";
4
4
  import * as path from "./path.js";
5
5
  class Config {
@@ -104,6 +104,7 @@ class Config {
104
104
  get routes_dir() {
105
105
  return path.join(this.root_dir, "src", "routes");
106
106
  }
107
+ // the location of the artifact generated corresponding to the provided documents
107
108
  artifactPath(document) {
108
109
  return path.join(this.artifact_dir, `${documentName(document)}.js`);
109
110
  }
@@ -1,5 +1,9 @@
1
1
  const siteURL = "https://houdinigraphql.com";
2
2
  const houdini_mode = {
3
+ /**
4
+ * to set the testing mode do like this:
5
+ * `process.env.HOUDINI_TEST = 'true'`
6
+ */
3
7
  get is_testing() {
4
8
  return process.env.HOUDINI_TEST === "true";
5
9
  }
@@ -1,6 +1,6 @@
1
- import type sqlite from 'node:sqlite';
2
1
  import type { PluginSpec } from './codegen.js';
2
+ import type { Db } from './db.js';
3
3
  import type { Config } from './config.js';
4
4
  import { Logger } from './logger.js';
5
- export declare const create_schema = "\nCREATE TABLE IF NOT EXISTS plugins (\n name TEXT NOT NULL PRIMARY KEY UNIQUE,\n port INTEGER NOT NULL,\n hooks JSON NOT NULL,\n plugin_order TEXT NOT NULL CHECK (plugin_order IN ('before', 'after', 'core')),\n include_runtime TEXT,\n include_static_runtime TEXT,\n config JSON,\n\t config_module TEXT,\n\t\tclient_plugins JSON\n);\n\n-- Watch Schema Config\nCREATE TABLE IF NOT EXISTS watch_schema_config (\n url TEXT NOT NULL,\n headers JSON,\n interval INTEGER,\n timeout INTEGER\n);\n\n-- Router Config\nCREATE TABLE IF NOT EXISTS router_config (\n api_endpoint TEXT,\n redirect TEXT UNIQUE,\n session_keys TEXT NOT NULL UNIQUE,\n url TEXT,\n mutation TEXT UNIQUE\n);\n\n-- Runtime Scalar Definition\nCREATE TABLE IF NOT EXISTS runtime_scalar_definitions (\n name TEXT NOT NULL PRIMARY KEY UNIQUE,\n type TEXT NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS component_fields (\n\tid INTEGER PRIMARY KEY AUTOINCREMENT,\n\tdocument INTEGER NOT NULL,\n type TEXT,\n\tprop TEXT,\n field TEXT,\n\tinline BOOLEAN default false,\n type_field TEXT,\n fragment TEXT,\n\tUNIQUE (document),\n\tFOREIGN KEY (document) REFERENCES raw_documents(id) ON DELETE CASCADE\n);\n\n-- Static Config (main config table)\nCREATE TABLE IF NOT EXISTS config (\n include JSON NOT NULL,\n exclude JSON NOT NULL,\n schema_path TEXT NOT NULL,\n definitions_path TEXT,\n cache_buffer_size INTEGER,\n default_cache_policy TEXT,\n default_partial BOOLEAN,\n default_lifetime INTEGER,\n default_list_position TEXT CHECK (default_list_position IN ('APPEND', 'PREPEND')),\n default_list_target TEXT CHECK (default_list_target IN ('ALL', 'NULL')),\n default_paginate_mode TEXT CHECK (default_paginate_mode IN ('Infinite', 'SinglePage')),\n suppress_pagination_deduplication BOOLEAN,\n log_level TEXT CHECK (log_level IN ('QUIET', 'FULL', 'SUMMARY', 'SHORT_SUMMARY')),\n default_fragment_masking BOOLEAN,\n default_keys JSON,\n persisted_queries_path TEXT NOT NULL,\n project_root TEXT,\n runtime_dir TEXT,\n\t\tpath TEXT\n);\n\nCREATE TABLE IF NOT EXISTS scalar_config (\n name TEXT NOT NULL PRIMARY KEY UNIQUE,\n type TEXT NOT NULL,\n\tinput_types JSON,\n\tmodule TEXT,\n\tdefault_import BOOLEAN\n);\n\n-- Types configuration\nCREATE TABLE IF NOT EXISTS type_configs (\n name TEXT NOT NULL,\n keys JSON NOT NULL,\n\tresolve_query TEXT\n);\n\n-- A table of original document contents (to be populated by plugins)\nCREATE TABLE IF NOT EXISTS raw_documents (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n offset_line INTEGER,\n offset_column INTEGER,\n filepath TEXT NOT NULL,\n content TEXT NOT NULL,\n current_task TEXT,\n loaded_with TEXT\n);\n\n-----------------------------------------------------------\n-- Schema Definition Tables\n-----------------------------------------------------------\n\nCREATE TABLE IF NOT EXISTS types (\n name TEXT NOT NULL PRIMARY KEY UNIQUE,\n kind TEXT NOT NULL CHECK (kind IN ('OBJECT', 'INTERFACE', 'UNION', 'ENUM', 'SCALAR', 'INPUT')),\n operation TEXT,\n\tdescription TEXT,\n\tinternal BOOLEAN default false,\n\tbuilt_in BOOLEAN default false\n);\n\nCREATE TABLE IF NOT EXISTS type_fields (\n id TEXT PRIMARY KEY, -- will be something like User.name so we don't have to look up the generated id\n parent TEXT NOT NULL, -- will be User\n name TEXT NOT NULL,\n type TEXT NOT NULL,\n\t type_modifiers TEXT,\n default_value TEXT,\n description TEXT,\n\t internal BOOLEAN default false,\n document INT,\n\n FOREIGN KEY (document) REFERENCES raw_documents(id) ON DELETE CASCADE,\n FOREIGN KEY (parent) REFERENCES types(name) ON DELETE CASCADE,\n FOREIGN KEY (type) REFERENCES types(name) ON DELETE CASCADE,\n UNIQUE (parent, name)\n);\n\nCREATE TABLE IF NOT EXISTS type_field_arguments (\n id TEXT PRIMARY KEY,\n field TEXT NOT NULL,\n name TEXT NOT NULL,\n type TEXT NOT NULL,\n type_modifiers TEXT,\n default_value TEXT,\n FOREIGN KEY (field) REFERENCES type_fields(id) ON DELETE CASCADE,\n UNIQUE (field, name)\n);\n\n\nCREATE TABLE IF NOT EXISTS enum_values (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n parent TEXT NOT NULL,\n value TEXT NOT NULL,\n description TEXT,\n FOREIGN KEY (parent) REFERENCES types(name) ON DELETE CASCADE,\n UNIQUE (parent, value)\n);\n\nCREATE TABLE IF NOT EXISTS possible_types (\n type TEXT NOT NULL,\n member TEXT NOT NULL,\n FOREIGN KEY (type) REFERENCES types(name) ON DELETE CASCADE,\n FOREIGN KEY (member) REFERENCES types(name) ON DELETE CASCADE,\n PRIMARY KEY (type, member)\n);\n\nCREATE TABLE IF NOT EXISTS directives (\n name TEXT NOT NULL UNIQUE PRIMARY KEY,\n\tinternal BOOLEAN default false,\n visible BOOLEAN default true,\n repeatable BOOLEAN default false,\n\tdescription TEXT\n);\n\nCREATE TABLE IF NOT EXISTS directive_arguments (\n parent TEXT NOT NULL,\n name TEXT NOT NULL,\n type TEXT NOT NULL,\n\ttype_modifiers TEXT,\n default_value TEXT,\n FOREIGN KEY (parent) REFERENCES directives(name),\n PRIMARY KEY (parent, name),\n UNIQUE (parent, name)\n);\n\nCREATE TABLE IF NOT EXISTS directive_locations (\n directive TEXT NOT NULL,\n location TEXT NOT NULL CHECK (location IN ('QUERY', 'MUTATION', 'SUBSCRIPTION', 'FIELD', 'FRAGMENT_DEFINITION', 'FRAGMENT_SPREAD', 'INLINE_FRAGMENT', 'SCHEMA', 'SCALAR', 'OBJECT', 'FIELD_DEFINITION', 'ARGUMENT_DEFINITION', 'INTERFACE', 'UNION', 'ENUM', 'ENUM_VALUE', 'INPUT_OBJECT', 'INPUT_FIELD_DEFINITION')),\n FOREIGN KEY (directive) REFERENCES directives(name),\n PRIMARY KEY (directive, location)\n);\n\nCREATE TABLE IF NOT EXISTS document_variable_directives (\n\tid INTEGER PRIMARY KEY AUTOINCREMENT,\n\tparent INTEGER NOT NULL,\n\tdirective TEXT NOT NULL,\n row INTEGER NOT NULL,\n column INTEGER NOT NULL,\n\tFOREIGN KEY (parent) REFERENCES document_variables(id) ON DELETE CASCADE,\n\tFOREIGN KEY (directive) REFERENCES directives(name) ON DELETE CASCADE\n);\n\nCREATE TABLE IF NOT EXISTS document_variable_directive_arguments (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n parent INTEGER NOT NULL,\n name TEXT NOT NULL,\n value INTEGER NOT NULL,\n\n FOREIGN KEY (value) REFERENCES argument_values(id) ON DELETE CASCADE,\n FOREIGN KEY (parent) REFERENCES document_variable_directives(id) ON DELETE CASCADE\n);\n\n-----------------------------------------------------------\n-- Document Tables\n-----------------------------------------------------------\n\nCREATE TABLE IF NOT EXISTS document_variables (\n \tid INTEGER PRIMARY KEY AUTOINCREMENT,\n document TEXT NOT NULL,\n name TEXT NOT NULL,\n type TEXT NOT NULL,\n type_modifiers TEXT,\n default_value INT,\n row INTEGER NOT NULL,\n column INTEGER NOT NULL,\n\n FOREIGN KEY (default_value) REFERENCES argument_values(id) ON DELETE CASCADE,\n FOREIGN KEY (document) REFERENCES documents(id) ON DELETE CASCADE,\n UNIQUE (document, name)\n);\n\n-- this is pulled out separately from operations and fragments so foreign keys can be used\nCREATE TABLE IF NOT EXISTS documents (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n name TEXT NOT NULL,\n kind TEXT NOT NULL CHECK (kind IN ('query', 'mutation', 'subscription', 'fragment')),\n raw_document INTEGER,\n type_condition TEXT,\n hash TEXT,\n printed TEXT,\n\t\tinternal boolean default false,\n\t\tvisible boolean default true,\n\t\tprocessed boolean default false,\n FOREIGN KEY (type_condition) REFERENCES types(name) ON DELETE CASCADE,\n FOREIGN KEY (raw_document) REFERENCES raw_documents(id) ON DELETE CASCADE\n);\n\nCREATE TABLE IF NOT EXISTS selections (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n field_name TEXT NOT NULL,\n\tkind TEXT NOT NULL CHECK (kind IN ('field', 'fragment', 'inline_fragment')),\n alias TEXT,\n type TEXT, -- should be something like User.Avatar\n fragment_ref TEXT, -- used when fragment arguments cause a hash to be inlined (removing the ability to track what the original fragment is)\n\t\tfragment_args JSON -- used to store the arguments that are used when fragment variables are expanded\n);\n\nCREATE TABLE IF NOT EXISTS selection_directives (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n selection_id INTEGER NOT NULL,\n directive TEXT NOT NULL,\n row INTEGER NOT NULL,\n column INTEGER NOT NULL,\n FOREIGN KEY (selection_id) REFERENCES selections(id) ON DELETE CASCADE,\n FOREIGN KEY (directive) REFERENCES directives(name) ON DELETE CASCADE\n);\n\nCREATE TABLE IF NOT EXISTS selection_directive_arguments (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n parent INTEGER NOT NULL,\n name TEXT NOT NULL,\n value INTEGER NOT NULL,\n document INTEGER NOT NULL,\n\n FOREIGN KEY (value) REFERENCES argument_values(id) ON DELETE CASCADE,\n FOREIGN KEY (parent) REFERENCES selection_directives(id) ON DELETE CASCADE,\n FOREIGN KEY (document) REFERENCES documents(id) ON DELETE CASCADE\n);\n\nCREATE TABLE IF NOT EXISTS document_directives (\n\tid INTEGER PRIMARY KEY AUTOINCREMENT,\n\tdocument int NOT NULL,\n\tdirective TEXT NOT NULL,\n\trow INTEGER NOT NULL,\n\tcolumn INTEGER NOT NULL,\n\tFOREIGN KEY (document) REFERENCES documents(id) ON DELETE CASCADE,\n\tFOREIGN KEY (directive) REFERENCES directives(name) ON DELETE CASCADE\n);\n\nCREATE TABLE IF NOT EXISTS document_directive_arguments (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n parent INTEGER NOT NULL,\n name TEXT NOT NULL,\n value INTEGER NOT NULL,\n\n FOREIGN KEY (value) REFERENCES argument_values(id) ON DELETE CASCADE,\n FOREIGN KEY (parent) REFERENCES document_directives(id) ON DELETE CASCADE\n);\n\nCREATE TABLE IF NOT EXISTS selection_refs (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n parent_id INTEGER,\n child_id INTEGER NOT NULL,\n path_index INTEGER NOT NULL,\n document INTEGER NOT NULL,\n\trow INTEGER NOT NULL,\n\tcolumn INTEGER NOT NULL,\n\tinternal BOOLEAN NOT NULL DEFAULT false,\n FOREIGN KEY (parent_id) REFERENCES selections(id) ON DELETE CASCADE,\n FOREIGN KEY (child_id) REFERENCES selections(id) ON DELETE CASCADE,\n FOREIGN KEY (document) REFERENCES documents(id) ON DELETE CASCADE\n);\n\nCREATE TABLE IF NOT EXISTS selection_arguments (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n selection_id INTEGER NOT NULL,\n document INTEGER NOT NULL,\n name TEXT NOT NULL,\n value INTEGER NOT NULL,\n row INTEGER NOT NULL,\n column INTEGER NOT NULL,\n field_argument TEXT NOT NULL,\n\n FOREIGN KEY (value) REFERENCES argument_values(id) ON DELETE CASCADE,\n FOREIGN KEY (selection_id) REFERENCES selections(id) ON DELETE CASCADE,\n FOREIGN KEY (document) REFERENCES documents(id) ON DELETE CASCADE\n);\n\n\nCREATE TABLE IF NOT EXISTS argument_values (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n kind TEXT NOT NULL CHECK (kind IN ('Variable', 'Int', 'Float', 'String', 'Block', 'Boolean', 'Null', 'Enum', 'List', 'Object')),\n raw TEXT NOT NULL,\n row INTEGER NOT NULL,\n column INTEGER NOT NULL,\n expected_type TEXT NOT NULL,\n expected_type_modifiers TEXT,\n document INTEGER NOT NULL,\n\n FOREIGN KEY (document) REFERENCES documents(id) ON DELETE CASCADE\n);\n\nCREATE TABLE IF NOT EXISTS argument_value_children (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n name TEXT,\n parent INTEGER NOT NULL,\n value INTEGER NOT NULL,\n row INTEGER NOT NULL,\n column INTEGER NOT NULL,\n document INTEGER NOT NULL,\n\n FOREIGN KEY (document) REFERENCES documents(id) ON DELETE CASCADE,\n FOREIGN KEY (parent) REFERENCES argument_values(id) ON DELETE CASCADE,\n FOREIGN KEY (value) REFERENCES argument_values(id) ON DELETE CASCADE\n);\n\nCREATE TABLE IF NOT EXISTS discovered_lists (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n name TEXT,\n node_type TEXT NOT NULL,\n edge_type TEXT,\n connection_type TEXT NOT NULL,\n node INTEGER NOT NULL,\n page_size INTEGER NOT NULL,\n document INTEGER NOT NULL,\n mode TEXT NOT NULL,\n embedded BOOLEAN NOT NULL,\n target_type TEXT NOT NULL,\n connection BOOLEAN default false,\n list_field INTEGER NOT NULL,\n paginate TEXT,\n supports_forward BOOLEAN default false,\n supports_backward BOOLEAN default false,\n cursor_type TEXT,\n\n FOREIGN KEY (list_field) REFERENCES selections(id) ON DELETE CASCADE,\n\t FOREIGN KEY (node) REFERENCES selections(id) ON DELETE CASCADE,\n FOREIGN KEY (node_type) REFERENCES types(name) ON DELETE CASCADE,\n FOREIGN KEY (document) REFERENCES documents(id) ON DELETE CASCADE\n);\n\nCREATE TABLE IF NOT EXISTS document_dependencies (\n document INTEGER NOT NULL,\n depends_on TEXT NOT NULL,\n\n FOREIGN KEY (document) REFERENCES documents(id) ON DELETE CASCADE,\n UNIQUE (document, depends_on)\n);\n\n-----------------------------------------------------------\n-- Indices\n-----------------------------------------------------------\n\n-- component_fields\nCREATE INDEX IF NOT EXISTS idx_component_fields_type_fields ON component_fields(type_field);\n\n-- discovered_lists\nCREATE INDEX IF NOT EXISTS idx_discovered_lists_document ON discovered_lists(document);\nCREATE INDEX IF NOT EXISTS idx_discovered_lists_node ON discovered_lists(node);\nCREATE INDEX IF NOT EXISTS idx_discovered_lists_list_field ON discovered_lists(list_field);\n-- note: no index on discovered_lists(connection) \u2014 boolean column, ~2 distinct values\n\n-- types\nCREATE INDEX IF NOT EXISTS idx_types_kind_operation ON types(kind, operation);\n-- note: no index on types(name) \u2014 covered by PRIMARY KEY UNIQUE\n\n-- documents\nCREATE INDEX IF NOT EXISTS idx_documents_kind ON documents(kind);\nCREATE INDEX IF NOT EXISTS idx_documents_type_condition ON documents(type_condition);\nCREATE INDEX IF NOT EXISTS idx_documents_raw_document ON documents(raw_document);\nCREATE INDEX IF NOT EXISTS idx_documents_name_kind ON documents(name, kind);\n\n-- raw_documents\nCREATE INDEX IF NOT EXISTS idx_raw_documents_current_task ON raw_documents(current_task);\n\n-- selections\nCREATE INDEX IF NOT EXISTS idx_selections_type ON selections(type);\nCREATE INDEX IF NOT EXISTS idx_selections_alias ON selections(alias);\nCREATE INDEX IF NOT EXISTS idx_selections_field_name_kind ON selections(field_name, kind);\n\n-- selection_refs: composite covers document-only lookups, so no separate single-column index needed\nCREATE INDEX IF NOT EXISTS idx_selection_refs_parent_id ON selection_refs(parent_id);\n\nCREATE INDEX IF NOT EXISTS idx_selection_refs_child_id ON selection_refs(child_id);\nCREATE INDEX IF NOT EXISTS idx_selection_refs_document_parent_id ON selection_refs(document, parent_id);\n\n-- selection_directives / selection_directive_arguments / selection_arguments\nCREATE INDEX IF NOT EXISTS idx_selection_directives_selection ON selection_directives(selection_id);\nCREATE INDEX IF NOT EXISTS idx_selection_directives_directive ON selection_directives(directive);\nCREATE INDEX IF NOT EXISTS idx_selection_directive_arguments_parent_name ON selection_directive_arguments(parent, name);\n-- note: no index on selection_directive_arguments(parent) alone \u2014 covered by (parent,name) composite\nCREATE INDEX IF NOT EXISTS idx_selection_directive_arguments_value ON selection_directive_arguments(value);\n-- document FK on selection_directive_arguments and selection_arguments: used in WHERE/JOIN in CollectDocuments\nCREATE INDEX IF NOT EXISTS idx_selection_directive_arguments_document ON selection_directive_arguments(document);\nCREATE INDEX IF NOT EXISTS idx_selection_arguments_document ON selection_arguments(document);\nCREATE INDEX IF NOT EXISTS idx_selection_arguments_selection ON selection_arguments(selection_id);\nCREATE INDEX IF NOT EXISTS idx_selection_arguments_value ON selection_arguments(value);\n\n-- type_fields / type_field_arguments\n-- note: no index on type_fields(id) or type_field_arguments(id) \u2014 covered by their TEXT PRIMARY KEYs\nCREATE INDEX IF NOT EXISTS idx_type_fields_parent ON type_fields(parent);\nCREATE INDEX IF NOT EXISTS idx_type_fields_name ON type_fields(name);\nCREATE INDEX IF NOT EXISTS idx_type_configs_name ON type_configs(name);\n\n-- possible_types\n-- note: no index on possible_types(type) \u2014 covered by PRIMARY KEY(type,member) leading column\nCREATE INDEX IF NOT EXISTS idx_possible_types_member ON possible_types(member);\n\n-- type_fields: type and document FK columns have no implicit index\nCREATE INDEX IF NOT EXISTS idx_type_fields_type ON type_fields(type);\nCREATE INDEX IF NOT EXISTS idx_type_fields_document ON type_fields(document);\n\n-- enum_values\n-- note: no index on enum_values(parent) or (parent,value) \u2014 both covered by UNIQUE(parent,value)\n\n-- document_directives / document_directive_arguments\nCREATE INDEX IF NOT EXISTS idx_document_directives_document ON document_directives(document);\nCREATE INDEX IF NOT EXISTS idx_document_directives_directive ON document_directives(directive);\nCREATE INDEX IF NOT EXISTS idx_document_directive_arguments_parent_name ON document_directive_arguments(parent, name);\n-- note: no index on document_directive_arguments(parent) alone \u2014 covered by (parent,name) composite\nCREATE INDEX IF NOT EXISTS idx_document_directive_arguments_value on document_directive_arguments(value);\n\n-- document_variables\n-- note: no index on document_variables(document,name) \u2014 covered by UNIQUE(document,name)\n-- default_value FK is used as a JOIN column in validate and fragmentArguments transforms\nCREATE INDEX IF NOT EXISTS idx_document_variables_default_value ON document_variables(default_value);\nCREATE INDEX IF NOT EXISTS idx_document_variables_document_id ON document_variables(document, id);\nCREATE INDEX IF NOT EXISTS idx_document_variables_document_type_modifiers_default ON document_variables(document, type_modifiers, default_value);\n\n-- document_variable_directives / document_variable_directive_arguments\nCREATE INDEX IF NOT EXISTS idx_document_variable_directives_parent ON document_variable_directives(parent);\nCREATE INDEX IF NOT EXISTS idx_document_variable_directives_directive ON document_variable_directives(directive);\nCREATE INDEX IF NOT EXISTS idx_document_variable_directive_arguments_parent ON document_variable_directive_arguments(parent);\n\n-- document_dependencies\n-- note: no index on document_dependencies(document) \u2014 covered by UNIQUE(document,depends_on) leading column\nCREATE INDEX IF NOT EXISTS idx_document_dependency_depends_on on document_dependencies(depends_on);\n\n-- argument_values: composite (document,id) covers document-only lookups\n-- note: no separate index on argument_values(document) alone\nCREATE INDEX IF NOT EXISTS idx_argument_values_kind_raw ON argument_values(kind, raw);\nCREATE INDEX IF NOT EXISTS idx_argument_values_document_id ON argument_values(document, id);\nCREATE INDEX IF NOT EXISTS idx_argument_values_expected_type_document ON argument_values(expected_type, document);\n\n-- argument_value_children: composite (parent,value) covers parent-only lookups\n-- note: no separate index on argument_value_children(parent) alone\nCREATE INDEX IF NOT EXISTS idx_argument_value_children_parent_value ON argument_value_children(parent, value);\nCREATE INDEX IF NOT EXISTS idx_argument_value_children_value ON argument_value_children(value);\n-- document FK: large table; index needed for efficient CASCADE DELETE from documents\nCREATE INDEX IF NOT EXISTS idx_argument_value_children_document ON argument_value_children(document);\n";
6
- export declare function write_config(db: sqlite.DatabaseSync, config: Config, invoke_hook: (plugin: string, hook: string, args: Record<string, any>) => Promise<Record<string, any>>, plugins: Array<PluginSpec>, mode: string, logger?: Logger): Promise<void>;
5
+ export declare const create_schema = "\nCREATE TABLE IF NOT EXISTS plugins (\n name TEXT NOT NULL PRIMARY KEY UNIQUE,\n port INTEGER NOT NULL,\n hooks JSON NOT NULL,\n plugin_order TEXT CHECK (plugin_order IS NULL OR plugin_order IN ('before', 'after', 'core')),\n include_runtime TEXT,\n include_static_runtime TEXT,\n config JSON,\n\t config_module TEXT,\n\t\tclient_plugins JSON\n);\n\n-- Watch Schema Config\nCREATE TABLE IF NOT EXISTS watch_schema_config (\n url TEXT NOT NULL,\n headers JSON,\n interval INTEGER,\n timeout INTEGER\n);\n\n-- Router Config\nCREATE TABLE IF NOT EXISTS router_config (\n api_endpoint TEXT,\n redirect TEXT UNIQUE,\n session_keys TEXT NOT NULL UNIQUE,\n url TEXT,\n mutation TEXT UNIQUE\n);\n\n-- Runtime Scalar Definition\nCREATE TABLE IF NOT EXISTS runtime_scalar_definitions (\n name TEXT NOT NULL PRIMARY KEY UNIQUE,\n type TEXT NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS component_fields (\n\tid INTEGER PRIMARY KEY AUTOINCREMENT,\n\tdocument INTEGER NOT NULL,\n type TEXT,\n\tprop TEXT,\n field TEXT,\n\tinline BOOLEAN default false,\n type_field TEXT,\n fragment TEXT,\n\tUNIQUE (document),\n\tFOREIGN KEY (document) REFERENCES raw_documents(id) ON DELETE CASCADE\n);\n\n-- Static Config (main config table)\nCREATE TABLE IF NOT EXISTS config (\n include JSON NOT NULL,\n exclude JSON NOT NULL,\n schema_path TEXT NOT NULL,\n definitions_path TEXT,\n cache_buffer_size INTEGER,\n default_cache_policy TEXT,\n default_partial BOOLEAN,\n default_lifetime INTEGER,\n default_list_position TEXT CHECK (default_list_position IN ('APPEND', 'PREPEND')),\n default_list_target TEXT CHECK (default_list_target IN ('ALL', 'NULL')),\n default_paginate_mode TEXT CHECK (default_paginate_mode IN ('Infinite', 'SinglePage')),\n suppress_pagination_deduplication BOOLEAN,\n log_level TEXT CHECK (log_level IN ('QUIET', 'FULL', 'SUMMARY', 'SHORT_SUMMARY')),\n default_fragment_masking BOOLEAN,\n default_keys JSON,\n persisted_queries_path TEXT NOT NULL,\n project_root TEXT,\n runtime_dir TEXT,\n\t\tpath TEXT\n);\n\nCREATE TABLE IF NOT EXISTS scalar_config (\n name TEXT NOT NULL PRIMARY KEY UNIQUE,\n type TEXT NOT NULL,\n\tinput_types JSON,\n\tmodule TEXT,\n\tdefault_import BOOLEAN\n);\n\n-- Types configuration\nCREATE TABLE IF NOT EXISTS type_configs (\n name TEXT NOT NULL,\n keys JSON NOT NULL,\n\tresolve_query TEXT\n);\n\n-- A table of original document contents (to be populated by plugins)\nCREATE TABLE IF NOT EXISTS raw_documents (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n offset_line INTEGER,\n offset_column INTEGER,\n filepath TEXT NOT NULL,\n content TEXT NOT NULL,\n current_task TEXT,\n loaded_with TEXT\n);\n\n-----------------------------------------------------------\n-- Schema Definition Tables\n-----------------------------------------------------------\n\nCREATE TABLE IF NOT EXISTS types (\n name TEXT NOT NULL PRIMARY KEY UNIQUE,\n kind TEXT NOT NULL CHECK (kind IN ('OBJECT', 'INTERFACE', 'UNION', 'ENUM', 'SCALAR', 'INPUT')),\n operation TEXT,\n\tdescription TEXT,\n\tinternal BOOLEAN default false,\n\tbuilt_in BOOLEAN default false\n);\n\nCREATE TABLE IF NOT EXISTS type_fields (\n id TEXT PRIMARY KEY, -- will be something like User.name so we don't have to look up the generated id\n parent TEXT NOT NULL, -- will be User\n name TEXT NOT NULL,\n type TEXT NOT NULL,\n\t type_modifiers TEXT,\n default_value TEXT,\n description TEXT,\n\t internal BOOLEAN default false,\n document INT,\n\n FOREIGN KEY (document) REFERENCES raw_documents(id) ON DELETE CASCADE,\n FOREIGN KEY (parent) REFERENCES types(name) ON DELETE CASCADE,\n FOREIGN KEY (type) REFERENCES types(name) ON DELETE CASCADE,\n UNIQUE (parent, name)\n);\n\nCREATE TABLE IF NOT EXISTS type_field_arguments (\n id TEXT PRIMARY KEY,\n field TEXT NOT NULL,\n name TEXT NOT NULL,\n type TEXT NOT NULL,\n type_modifiers TEXT,\n default_value TEXT,\n FOREIGN KEY (field) REFERENCES type_fields(id) ON DELETE CASCADE,\n UNIQUE (field, name)\n);\n\n\nCREATE TABLE IF NOT EXISTS enum_values (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n parent TEXT NOT NULL,\n value TEXT NOT NULL,\n description TEXT,\n FOREIGN KEY (parent) REFERENCES types(name) ON DELETE CASCADE,\n UNIQUE (parent, value)\n);\n\nCREATE TABLE IF NOT EXISTS possible_types (\n type TEXT NOT NULL,\n member TEXT NOT NULL,\n FOREIGN KEY (type) REFERENCES types(name) ON DELETE CASCADE,\n FOREIGN KEY (member) REFERENCES types(name) ON DELETE CASCADE,\n PRIMARY KEY (type, member)\n);\n\nCREATE TABLE IF NOT EXISTS directives (\n name TEXT NOT NULL UNIQUE PRIMARY KEY,\n\tinternal BOOLEAN default false,\n visible BOOLEAN default true,\n repeatable BOOLEAN default false,\n\tdescription TEXT\n);\n\nCREATE TABLE IF NOT EXISTS directive_arguments (\n parent TEXT NOT NULL,\n name TEXT NOT NULL,\n type TEXT NOT NULL,\n\ttype_modifiers TEXT,\n default_value TEXT,\n FOREIGN KEY (parent) REFERENCES directives(name),\n PRIMARY KEY (parent, name),\n UNIQUE (parent, name)\n);\n\nCREATE TABLE IF NOT EXISTS directive_locations (\n directive TEXT NOT NULL,\n location TEXT NOT NULL CHECK (location IN ('QUERY', 'MUTATION', 'SUBSCRIPTION', 'FIELD', 'FRAGMENT_DEFINITION', 'FRAGMENT_SPREAD', 'INLINE_FRAGMENT', 'SCHEMA', 'SCALAR', 'OBJECT', 'FIELD_DEFINITION', 'ARGUMENT_DEFINITION', 'INTERFACE', 'UNION', 'ENUM', 'ENUM_VALUE', 'INPUT_OBJECT', 'INPUT_FIELD_DEFINITION')),\n FOREIGN KEY (directive) REFERENCES directives(name),\n PRIMARY KEY (directive, location)\n);\n\nCREATE TABLE IF NOT EXISTS document_variable_directives (\n\tid INTEGER PRIMARY KEY AUTOINCREMENT,\n\tparent INTEGER NOT NULL,\n\tdirective TEXT NOT NULL,\n row INTEGER NOT NULL,\n column INTEGER NOT NULL,\n\tFOREIGN KEY (parent) REFERENCES document_variables(id) ON DELETE CASCADE,\n\tFOREIGN KEY (directive) REFERENCES directives(name) ON DELETE CASCADE\n);\n\nCREATE TABLE IF NOT EXISTS document_variable_directive_arguments (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n parent INTEGER NOT NULL,\n name TEXT NOT NULL,\n value INTEGER NOT NULL,\n\n FOREIGN KEY (value) REFERENCES argument_values(id) ON DELETE CASCADE,\n FOREIGN KEY (parent) REFERENCES document_variable_directives(id) ON DELETE CASCADE\n);\n\n-----------------------------------------------------------\n-- Document Tables\n-----------------------------------------------------------\n\nCREATE TABLE IF NOT EXISTS document_variables (\n \tid INTEGER PRIMARY KEY AUTOINCREMENT,\n document TEXT NOT NULL,\n name TEXT NOT NULL,\n type TEXT NOT NULL,\n type_modifiers TEXT,\n default_value INT,\n row INTEGER NOT NULL,\n column INTEGER NOT NULL,\n\n FOREIGN KEY (default_value) REFERENCES argument_values(id) ON DELETE CASCADE,\n FOREIGN KEY (document) REFERENCES documents(id) ON DELETE CASCADE,\n UNIQUE (document, name)\n);\n\n-- this is pulled out separately from operations and fragments so foreign keys can be used\nCREATE TABLE IF NOT EXISTS documents (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n name TEXT NOT NULL,\n kind TEXT NOT NULL CHECK (kind IN ('query', 'mutation', 'subscription', 'fragment')),\n raw_document INTEGER,\n type_condition TEXT,\n hash TEXT,\n printed TEXT,\n\t\tinternal boolean default false,\n\t\tvisible boolean default true,\n\t\tprocessed boolean default false,\n FOREIGN KEY (type_condition) REFERENCES types(name) ON DELETE CASCADE,\n FOREIGN KEY (raw_document) REFERENCES raw_documents(id) ON DELETE CASCADE\n);\n\nCREATE TABLE IF NOT EXISTS selections (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n field_name TEXT NOT NULL,\n\tkind TEXT NOT NULL CHECK (kind IN ('field', 'fragment', 'inline_fragment')),\n alias TEXT,\n type TEXT, -- should be something like User.Avatar\n fragment_ref TEXT, -- used when fragment arguments cause a hash to be inlined (removing the ability to track what the original fragment is)\n\t\tfragment_args JSON -- used to store the arguments that are used when fragment variables are expanded\n);\n\nCREATE TABLE IF NOT EXISTS selection_directives (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n selection_id INTEGER NOT NULL,\n directive TEXT NOT NULL,\n row INTEGER NOT NULL,\n column INTEGER NOT NULL,\n FOREIGN KEY (selection_id) REFERENCES selections(id) ON DELETE CASCADE,\n FOREIGN KEY (directive) REFERENCES directives(name) ON DELETE CASCADE\n);\n\nCREATE TABLE IF NOT EXISTS selection_directive_arguments (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n parent INTEGER NOT NULL,\n name TEXT NOT NULL,\n value INTEGER NOT NULL,\n document INTEGER NOT NULL,\n\n FOREIGN KEY (value) REFERENCES argument_values(id) ON DELETE CASCADE,\n FOREIGN KEY (parent) REFERENCES selection_directives(id) ON DELETE CASCADE,\n FOREIGN KEY (document) REFERENCES documents(id) ON DELETE CASCADE\n);\n\nCREATE TABLE IF NOT EXISTS document_directives (\n\tid INTEGER PRIMARY KEY AUTOINCREMENT,\n\tdocument int NOT NULL,\n\tdirective TEXT NOT NULL,\n\trow INTEGER NOT NULL,\n\tcolumn INTEGER NOT NULL,\n\tFOREIGN KEY (document) REFERENCES documents(id) ON DELETE CASCADE,\n\tFOREIGN KEY (directive) REFERENCES directives(name) ON DELETE CASCADE\n);\n\nCREATE TABLE IF NOT EXISTS document_directive_arguments (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n parent INTEGER NOT NULL,\n name TEXT NOT NULL,\n value INTEGER NOT NULL,\n\n FOREIGN KEY (value) REFERENCES argument_values(id) ON DELETE CASCADE,\n FOREIGN KEY (parent) REFERENCES document_directives(id) ON DELETE CASCADE\n);\n\nCREATE TABLE IF NOT EXISTS selection_refs (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n parent_id INTEGER,\n child_id INTEGER NOT NULL,\n path_index INTEGER NOT NULL,\n document INTEGER NOT NULL,\n\trow INTEGER NOT NULL,\n\tcolumn INTEGER NOT NULL,\n\tinternal BOOLEAN NOT NULL DEFAULT false,\n FOREIGN KEY (parent_id) REFERENCES selections(id) ON DELETE CASCADE,\n FOREIGN KEY (child_id) REFERENCES selections(id) ON DELETE CASCADE,\n FOREIGN KEY (document) REFERENCES documents(id) ON DELETE CASCADE\n);\n\nCREATE TABLE IF NOT EXISTS selection_arguments (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n selection_id INTEGER NOT NULL,\n document INTEGER NOT NULL,\n name TEXT NOT NULL,\n value INTEGER NOT NULL,\n row INTEGER NOT NULL,\n column INTEGER NOT NULL,\n field_argument TEXT NOT NULL,\n\n FOREIGN KEY (value) REFERENCES argument_values(id) ON DELETE CASCADE,\n FOREIGN KEY (selection_id) REFERENCES selections(id) ON DELETE CASCADE,\n FOREIGN KEY (document) REFERENCES documents(id) ON DELETE CASCADE\n);\n\n\nCREATE TABLE IF NOT EXISTS argument_values (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n kind TEXT NOT NULL CHECK (kind IN ('Variable', 'Int', 'Float', 'String', 'Block', 'Boolean', 'Null', 'Enum', 'List', 'Object')),\n raw TEXT NOT NULL,\n row INTEGER NOT NULL,\n column INTEGER NOT NULL,\n expected_type TEXT NOT NULL,\n expected_type_modifiers TEXT,\n document INTEGER NOT NULL,\n\n FOREIGN KEY (document) REFERENCES documents(id) ON DELETE CASCADE\n);\n\nCREATE TABLE IF NOT EXISTS argument_value_children (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n name TEXT,\n parent INTEGER NOT NULL,\n value INTEGER NOT NULL,\n row INTEGER NOT NULL,\n column INTEGER NOT NULL,\n document INTEGER NOT NULL,\n\n FOREIGN KEY (document) REFERENCES documents(id) ON DELETE CASCADE,\n FOREIGN KEY (parent) REFERENCES argument_values(id) ON DELETE CASCADE,\n FOREIGN KEY (value) REFERENCES argument_values(id) ON DELETE CASCADE\n);\n\nCREATE TABLE IF NOT EXISTS discovered_lists (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n name TEXT,\n node_type TEXT NOT NULL,\n edge_type TEXT,\n connection_type TEXT NOT NULL,\n node INTEGER NOT NULL,\n page_size INTEGER NOT NULL,\n document INTEGER NOT NULL,\n mode TEXT NOT NULL,\n embedded BOOLEAN NOT NULL,\n target_type TEXT NOT NULL,\n connection BOOLEAN default false,\n list_field INTEGER NOT NULL,\n paginate TEXT,\n supports_forward BOOLEAN default false,\n supports_backward BOOLEAN default false,\n cursor_type TEXT,\n\n FOREIGN KEY (list_field) REFERENCES selections(id) ON DELETE CASCADE,\n\t FOREIGN KEY (node) REFERENCES selections(id) ON DELETE CASCADE,\n FOREIGN KEY (node_type) REFERENCES types(name) ON DELETE CASCADE,\n FOREIGN KEY (document) REFERENCES documents(id) ON DELETE CASCADE\n);\n\nCREATE TABLE IF NOT EXISTS document_dependencies (\n document INTEGER NOT NULL,\n depends_on TEXT NOT NULL,\n\n FOREIGN KEY (document) REFERENCES documents(id) ON DELETE CASCADE,\n UNIQUE (document, depends_on)\n);\n\n-----------------------------------------------------------\n-- Indices\n-----------------------------------------------------------\n\n-- component_fields\nCREATE INDEX IF NOT EXISTS idx_component_fields_type_fields ON component_fields(type_field);\n\n-- discovered_lists\nCREATE INDEX IF NOT EXISTS idx_discovered_lists_document ON discovered_lists(document);\nCREATE INDEX IF NOT EXISTS idx_discovered_lists_node ON discovered_lists(node);\nCREATE INDEX IF NOT EXISTS idx_discovered_lists_list_field ON discovered_lists(list_field);\n-- note: no index on discovered_lists(connection) \u2014 boolean column, ~2 distinct values\n\n-- types\nCREATE INDEX IF NOT EXISTS idx_types_kind_operation ON types(kind, operation);\n-- note: no index on types(name) \u2014 covered by PRIMARY KEY UNIQUE\n\n-- documents\nCREATE INDEX IF NOT EXISTS idx_documents_kind ON documents(kind);\nCREATE INDEX IF NOT EXISTS idx_documents_type_condition ON documents(type_condition);\nCREATE INDEX IF NOT EXISTS idx_documents_raw_document ON documents(raw_document);\nCREATE INDEX IF NOT EXISTS idx_documents_name_kind ON documents(name, kind);\n\n-- raw_documents\nCREATE INDEX IF NOT EXISTS idx_raw_documents_current_task ON raw_documents(current_task);\n\n-- selections\nCREATE INDEX IF NOT EXISTS idx_selections_type ON selections(type);\nCREATE INDEX IF NOT EXISTS idx_selections_alias ON selections(alias);\nCREATE INDEX IF NOT EXISTS idx_selections_field_name_kind ON selections(field_name, kind);\n\n-- selection_refs: composite covers document-only lookups, so no separate single-column index needed\nCREATE INDEX IF NOT EXISTS idx_selection_refs_parent_id ON selection_refs(parent_id);\n\nCREATE INDEX IF NOT EXISTS idx_selection_refs_child_id ON selection_refs(child_id);\nCREATE INDEX IF NOT EXISTS idx_selection_refs_document_parent_id ON selection_refs(document, parent_id);\n\n-- selection_directives / selection_directive_arguments / selection_arguments\nCREATE INDEX IF NOT EXISTS idx_selection_directives_selection ON selection_directives(selection_id);\nCREATE INDEX IF NOT EXISTS idx_selection_directives_directive ON selection_directives(directive);\nCREATE INDEX IF NOT EXISTS idx_selection_directive_arguments_parent_name ON selection_directive_arguments(parent, name);\n-- note: no index on selection_directive_arguments(parent) alone \u2014 covered by (parent,name) composite\nCREATE INDEX IF NOT EXISTS idx_selection_directive_arguments_value ON selection_directive_arguments(value);\n-- document FK on selection_directive_arguments and selection_arguments: used in WHERE/JOIN in CollectDocuments\nCREATE INDEX IF NOT EXISTS idx_selection_directive_arguments_document ON selection_directive_arguments(document);\nCREATE INDEX IF NOT EXISTS idx_selection_arguments_document ON selection_arguments(document);\nCREATE INDEX IF NOT EXISTS idx_selection_arguments_selection ON selection_arguments(selection_id);\nCREATE INDEX IF NOT EXISTS idx_selection_arguments_value ON selection_arguments(value);\n\n-- type_fields / type_field_arguments\n-- note: no index on type_fields(id) or type_field_arguments(id) \u2014 covered by their TEXT PRIMARY KEYs\nCREATE INDEX IF NOT EXISTS idx_type_fields_parent ON type_fields(parent);\nCREATE INDEX IF NOT EXISTS idx_type_fields_name ON type_fields(name);\nCREATE INDEX IF NOT EXISTS idx_type_configs_name ON type_configs(name);\n\n-- possible_types\n-- note: no index on possible_types(type) \u2014 covered by PRIMARY KEY(type,member) leading column\nCREATE INDEX IF NOT EXISTS idx_possible_types_member ON possible_types(member);\n\n-- type_fields: type and document FK columns have no implicit index\nCREATE INDEX IF NOT EXISTS idx_type_fields_type ON type_fields(type);\nCREATE INDEX IF NOT EXISTS idx_type_fields_document ON type_fields(document);\n\n-- enum_values\n-- note: no index on enum_values(parent) or (parent,value) \u2014 both covered by UNIQUE(parent,value)\n\n-- document_directives / document_directive_arguments\nCREATE INDEX IF NOT EXISTS idx_document_directives_document ON document_directives(document);\nCREATE INDEX IF NOT EXISTS idx_document_directives_directive ON document_directives(directive);\nCREATE INDEX IF NOT EXISTS idx_document_directive_arguments_parent_name ON document_directive_arguments(parent, name);\n-- note: no index on document_directive_arguments(parent) alone \u2014 covered by (parent,name) composite\nCREATE INDEX IF NOT EXISTS idx_document_directive_arguments_value on document_directive_arguments(value);\n\n-- document_variables\n-- note: no index on document_variables(document,name) \u2014 covered by UNIQUE(document,name)\n-- default_value FK is used as a JOIN column in validate and fragmentArguments transforms\nCREATE INDEX IF NOT EXISTS idx_document_variables_default_value ON document_variables(default_value);\nCREATE INDEX IF NOT EXISTS idx_document_variables_document_id ON document_variables(document, id);\nCREATE INDEX IF NOT EXISTS idx_document_variables_document_type_modifiers_default ON document_variables(document, type_modifiers, default_value);\n\n-- document_variable_directives / document_variable_directive_arguments\nCREATE INDEX IF NOT EXISTS idx_document_variable_directives_parent ON document_variable_directives(parent);\nCREATE INDEX IF NOT EXISTS idx_document_variable_directives_directive ON document_variable_directives(directive);\nCREATE INDEX IF NOT EXISTS idx_document_variable_directive_arguments_parent ON document_variable_directive_arguments(parent);\n\n-- document_dependencies\n-- note: no index on document_dependencies(document) \u2014 covered by UNIQUE(document,depends_on) leading column\nCREATE INDEX IF NOT EXISTS idx_document_dependency_depends_on on document_dependencies(depends_on);\n\n-- argument_values: composite (document,id) covers document-only lookups\n-- note: no separate index on argument_values(document) alone\nCREATE INDEX IF NOT EXISTS idx_argument_values_kind_raw ON argument_values(kind, raw);\nCREATE INDEX IF NOT EXISTS idx_argument_values_document_id ON argument_values(document, id);\nCREATE INDEX IF NOT EXISTS idx_argument_values_expected_type_document ON argument_values(expected_type, document);\n\n-- argument_value_children: composite (parent,value) covers parent-only lookups\n-- note: no separate index on argument_value_children(parent) alone\nCREATE INDEX IF NOT EXISTS idx_argument_value_children_parent_value ON argument_value_children(parent, value);\nCREATE INDEX IF NOT EXISTS idx_argument_value_children_value ON argument_value_children(value);\n-- document FK: large table; index needed for efficient CASCADE DELETE from documents\nCREATE INDEX IF NOT EXISTS idx_argument_value_children_document ON argument_value_children(document);\n";
6
+ export declare function write_config(db: Db, config: Config, invoke_hook: (plugin: string, hook: string, args: Record<string, any>) => Promise<Record<string, any>>, plugins: Array<PluginSpec>, mode: string, logger?: Logger): Promise<void>;