@constructive-io/graphql-codegen 4.2.0 → 4.4.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 (31) hide show
  1. package/core/codegen/cli/custom-command-generator.js +15 -4
  2. package/core/codegen/cli/executor-generator.d.ts +6 -2
  3. package/core/codegen/cli/executor-generator.js +48 -12
  4. package/core/codegen/cli/index.d.ts +10 -2
  5. package/core/codegen/cli/index.js +31 -4
  6. package/core/codegen/cli/table-command-generator.d.ts +3 -1
  7. package/core/codegen/cli/table-command-generator.js +50 -5
  8. package/core/codegen/cli/utils-generator.d.ts +17 -0
  9. package/core/codegen/cli/utils-generator.js +29 -0
  10. package/core/codegen/orm/client-generator.d.ts +3 -1
  11. package/core/codegen/orm/client-generator.js +7 -1
  12. package/core/codegen/orm/index.js +1 -1
  13. package/core/codegen/templates/cli-entry.ts +33 -0
  14. package/core/codegen/templates/node-fetch.ts +162 -0
  15. package/core/generate.js +21 -2
  16. package/esm/core/codegen/cli/custom-command-generator.js +15 -4
  17. package/esm/core/codegen/cli/executor-generator.d.ts +6 -2
  18. package/esm/core/codegen/cli/executor-generator.js +48 -12
  19. package/esm/core/codegen/cli/index.d.ts +10 -2
  20. package/esm/core/codegen/cli/index.js +31 -5
  21. package/esm/core/codegen/cli/table-command-generator.d.ts +3 -1
  22. package/esm/core/codegen/cli/table-command-generator.js +50 -5
  23. package/esm/core/codegen/cli/utils-generator.d.ts +17 -0
  24. package/esm/core/codegen/cli/utils-generator.js +27 -0
  25. package/esm/core/codegen/orm/client-generator.d.ts +3 -1
  26. package/esm/core/codegen/orm/client-generator.js +7 -1
  27. package/esm/core/codegen/orm/index.js +1 -1
  28. package/esm/core/generate.js +21 -2
  29. package/esm/types/config.d.ts +26 -0
  30. package/package.json +10 -10
  31. package/types/config.d.ts +26 -0
@@ -101,9 +101,19 @@ function buildDefaultSelectString(returnType, isMutation) {
101
101
  }
102
102
  return '';
103
103
  }
104
- function buildOrmCustomCall(opKind, opName, argsExpr, selectExpr) {
105
- const callArgs = [argsExpr];
106
- if (selectExpr) {
104
+ function buildOrmCustomCall(opKind, opName, argsExpr, selectExpr, hasArgs = true) {
105
+ const callArgs = [];
106
+ if (hasArgs) {
107
+ // Operation has arguments: pass args as first param, select as second
108
+ callArgs.push(argsExpr);
109
+ if (selectExpr) {
110
+ callArgs.push(t.objectExpression([
111
+ t.objectProperty(t.identifier('select'), selectExpr),
112
+ ]));
113
+ }
114
+ }
115
+ else if (selectExpr) {
116
+ // No arguments: pass { select } as the only param (ORM signature)
107
117
  callArgs.push(t.objectExpression([
108
118
  t.objectProperty(t.identifier('select'), selectExpr),
109
119
  ]));
@@ -197,8 +207,9 @@ function generateCustomCommand(op, options) {
197
207
  ]));
198
208
  selectExpr = t.identifier('selectFields');
199
209
  }
210
+ const hasArgs = op.args.length > 0;
200
211
  bodyStatements.push(t.variableDeclaration('const', [
201
- t.variableDeclarator(t.identifier('result'), t.awaitExpression(buildOrmCustomCall(opKind, op.name, argsExpr, selectExpr))),
212
+ t.variableDeclarator(t.identifier('result'), t.awaitExpression(buildOrmCustomCall(opKind, op.name, argsExpr, selectExpr, hasArgs))),
202
213
  ]));
203
214
  if (options?.saveToken) {
204
215
  bodyStatements.push(t.ifStatement(t.logicalExpression('&&', t.memberExpression(t.identifier('argv'), t.identifier('saveToken')), t.identifier('result')), t.blockStatement([
@@ -7,5 +7,9 @@ export interface MultiTargetExecutorInput {
7
7
  endpoint: string;
8
8
  ormImportPath: string;
9
9
  }
10
- export declare function generateExecutorFile(toolName: string): GeneratedFile;
11
- export declare function generateMultiTargetExecutorFile(toolName: string, targets: MultiTargetExecutorInput[]): GeneratedFile;
10
+ export interface ExecutorOptions {
11
+ /** Enable NodeHttpAdapter for *.localhost subdomain routing */
12
+ nodeHttpAdapter?: boolean;
13
+ }
14
+ export declare function generateExecutorFile(toolName: string, options?: ExecutorOptions): GeneratedFile;
15
+ export declare function generateMultiTargetExecutorFile(toolName: string, targets: MultiTargetExecutorInput[], options?: ExecutorOptions): GeneratedFile;
@@ -44,8 +44,12 @@ function createImportDeclaration(moduleSpecifier, namedImports, typeOnly = false
44
44
  decl.importKind = typeOnly ? 'type' : 'value';
45
45
  return decl;
46
46
  }
47
- function generateExecutorFile(toolName) {
47
+ function generateExecutorFile(toolName, options) {
48
48
  const statements = [];
49
+ // Import NodeHttpAdapter for *.localhost subdomain routing
50
+ if (options?.nodeHttpAdapter) {
51
+ statements.push(createImportDeclaration('./node-fetch', ['NodeHttpAdapter']));
52
+ }
49
53
  statements.push(createImportDeclaration('appstash', ['createConfigStore']));
50
54
  statements.push(createImportDeclaration('../orm', ['createClient']));
51
55
  statements.push(t.variableDeclaration('const', [
@@ -98,12 +102,26 @@ function generateExecutorFile(toolName) {
98
102
  ]))),
99
103
  ])),
100
104
  ])),
101
- t.returnStatement(t.callExpression(t.identifier('createClient'), [
102
- t.objectExpression([
103
- t.objectProperty(t.identifier('endpoint'), t.memberExpression(t.identifier('ctx'), t.identifier('endpoint'))),
104
- t.objectProperty(t.identifier('headers'), t.identifier('headers')),
105
+ // Build createClient config — use NodeHttpAdapter for *.localhost endpoints
106
+ ...(options?.nodeHttpAdapter
107
+ ? [
108
+ t.returnStatement(t.callExpression(t.identifier('createClient'), [
109
+ t.objectExpression([
110
+ t.objectProperty(t.identifier('adapter'), t.newExpression(t.identifier('NodeHttpAdapter'), [
111
+ t.memberExpression(t.identifier('ctx'), t.identifier('endpoint')),
112
+ t.identifier('headers'),
113
+ ])),
114
+ ]),
115
+ ])),
116
+ ]
117
+ : [
118
+ t.returnStatement(t.callExpression(t.identifier('createClient'), [
119
+ t.objectExpression([
120
+ t.objectProperty(t.identifier('endpoint'), t.memberExpression(t.identifier('ctx'), t.identifier('endpoint'))),
121
+ t.objectProperty(t.identifier('headers'), t.identifier('headers')),
122
+ ]),
123
+ ])),
105
124
  ]),
106
- ])),
107
125
  ]);
108
126
  const getClientFunc = t.functionDeclaration(t.identifier('getClient'), [contextNameParam], getClientBody);
109
127
  statements.push(t.exportNamedDeclaration(getClientFunc));
@@ -114,8 +132,12 @@ function generateExecutorFile(toolName) {
114
132
  content: header + '\n' + code,
115
133
  };
116
134
  }
117
- function generateMultiTargetExecutorFile(toolName, targets) {
135
+ function generateMultiTargetExecutorFile(toolName, targets, options) {
118
136
  const statements = [];
137
+ // Import NodeHttpAdapter for *.localhost subdomain routing
138
+ if (options?.nodeHttpAdapter) {
139
+ statements.push(createImportDeclaration('./node-fetch', ['NodeHttpAdapter']));
140
+ }
119
141
  statements.push(createImportDeclaration('appstash', ['createConfigStore']));
120
142
  for (const target of targets) {
121
143
  const aliasName = `create${target.name[0].toUpperCase()}${target.name.slice(1)}Client`;
@@ -199,12 +221,26 @@ function generateMultiTargetExecutorFile(toolName, targets) {
199
221
  ]), t.blockStatement([
200
222
  t.expressionStatement(t.assignmentExpression('=', t.identifier('endpoint'), t.logicalExpression('||', t.memberExpression(t.identifier('defaultEndpoints'), t.identifier('targetName'), true), t.stringLiteral('')))),
201
223
  ])),
202
- t.returnStatement(t.callExpression(t.identifier('createFn'), [
203
- t.objectExpression([
204
- t.objectProperty(t.identifier('endpoint'), t.identifier('endpoint')),
205
- t.objectProperty(t.identifier('headers'), t.identifier('headers')),
224
+ // Build createClient config — use NodeHttpAdapter for *.localhost endpoints
225
+ ...(options?.nodeHttpAdapter
226
+ ? [
227
+ t.returnStatement(t.callExpression(t.identifier('createFn'), [
228
+ t.objectExpression([
229
+ t.objectProperty(t.identifier('adapter'), t.newExpression(t.identifier('NodeHttpAdapter'), [
230
+ t.identifier('endpoint'),
231
+ t.identifier('headers'),
232
+ ])),
233
+ ]),
234
+ ])),
235
+ ]
236
+ : [
237
+ t.returnStatement(t.callExpression(t.identifier('createFn'), [
238
+ t.objectExpression([
239
+ t.objectProperty(t.identifier('endpoint'), t.identifier('endpoint')),
240
+ t.objectProperty(t.identifier('headers'), t.identifier('headers')),
241
+ ]),
242
+ ])),
206
243
  ]),
207
- ])),
208
244
  ]);
209
245
  const getClientFunc = t.functionDeclaration(t.identifier('getClient'), [targetNameParam, contextNameParam], getClientBody);
210
246
  statements.push(t.exportNamedDeclaration(getClientFunc));
@@ -1,5 +1,5 @@
1
1
  import type { BuiltinNames, GraphQLSDKConfigTarget } from '../../../types/config';
2
- import type { CleanOperation, CleanTable } from '../../../types/schema';
2
+ import type { CleanOperation, CleanTable, TypeRegistry } from '../../../types/schema';
3
3
  import type { GeneratedFile } from './executor-generator';
4
4
  export interface GenerateCliOptions {
5
5
  tables: CleanTable[];
@@ -8,6 +8,8 @@ export interface GenerateCliOptions {
8
8
  mutations: CleanOperation[];
9
9
  };
10
10
  config: GraphQLSDKConfigTarget;
11
+ /** TypeRegistry from introspection, used to check field defaults */
12
+ typeRegistry?: TypeRegistry;
11
13
  }
12
14
  export interface GenerateCliResult {
13
15
  files: GeneratedFile[];
@@ -30,11 +32,17 @@ export interface MultiTargetCliTarget {
30
32
  mutations: CleanOperation[];
31
33
  };
32
34
  isAuthTarget?: boolean;
35
+ /** TypeRegistry from introspection, used to check field defaults */
36
+ typeRegistry?: TypeRegistry;
33
37
  }
34
38
  export interface GenerateMultiTargetCliOptions {
35
39
  toolName: string;
36
40
  builtinNames?: BuiltinNames;
37
41
  targets: MultiTargetCliTarget[];
42
+ /** Enable NodeHttpAdapter for *.localhost subdomain routing */
43
+ nodeHttpAdapter?: boolean;
44
+ /** Generate a runnable index.ts entry point */
45
+ entryPoint?: boolean;
38
46
  }
39
47
  export declare function resolveBuiltinNames(targetNames: string[], userOverrides?: BuiltinNames): {
40
48
  auth: string;
@@ -50,5 +58,5 @@ export { generateReadme, generateAgentsDocs, getCliMcpTools, generateSkills, gen
50
58
  export type { MultiTargetDocsInput } from './docs-generator';
51
59
  export { resolveDocsConfig } from '../docs-utils';
52
60
  export type { GeneratedDocFile, McpTool } from '../docs-utils';
53
- export { generateUtilsFile } from './utils-generator';
61
+ export { generateUtilsFile, generateEntryPointFile } from './utils-generator';
54
62
  export type { GeneratedFile, MultiTargetExecutorInput } from './executor-generator';
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.generateUtilsFile = exports.resolveDocsConfig = exports.generateMultiTargetSkills = exports.getMultiTargetCliMcpTools = exports.generateMultiTargetAgentsDocs = exports.generateMultiTargetReadme = exports.generateSkills = exports.getCliMcpTools = exports.generateAgentsDocs = exports.generateReadme = exports.generateAuthCommandWithName = exports.generateMultiTargetContextCommand = exports.generateAuthCommand = exports.generateContextCommand = exports.generateMultiTargetCommandMap = exports.generateCommandMap = exports.generateCustomCommand = exports.generateTableCommand = exports.generateMultiTargetExecutorFile = exports.generateExecutorFile = void 0;
3
+ exports.generateEntryPointFile = exports.generateUtilsFile = exports.resolveDocsConfig = exports.generateMultiTargetSkills = exports.getMultiTargetCliMcpTools = exports.generateMultiTargetAgentsDocs = exports.generateMultiTargetReadme = exports.generateSkills = exports.getCliMcpTools = exports.generateAgentsDocs = exports.generateReadme = exports.generateAuthCommandWithName = exports.generateMultiTargetContextCommand = exports.generateAuthCommand = exports.generateContextCommand = exports.generateMultiTargetCommandMap = exports.generateCommandMap = exports.generateCustomCommand = exports.generateTableCommand = exports.generateMultiTargetExecutorFile = exports.generateExecutorFile = void 0;
4
4
  exports.generateCli = generateCli;
5
5
  exports.resolveBuiltinNames = resolveBuiltinNames;
6
6
  exports.generateMultiTargetCli = generateMultiTargetCli;
@@ -17,16 +17,26 @@ function generateCli(options) {
17
17
  const toolName = typeof cliConfig === 'object' && cliConfig.toolName
18
18
  ? cliConfig.toolName
19
19
  : 'app';
20
- const executorFile = (0, executor_generator_1.generateExecutorFile)(toolName);
20
+ // Use top-level nodeHttpAdapter from config (auto-enabled for CLI by generate.ts)
21
+ const useNodeHttpAdapter = !!config.nodeHttpAdapter;
22
+ const executorFile = (0, executor_generator_1.generateExecutorFile)(toolName, {
23
+ nodeHttpAdapter: useNodeHttpAdapter,
24
+ });
21
25
  files.push(executorFile);
22
26
  const utilsFile = (0, utils_generator_1.generateUtilsFile)();
23
27
  files.push(utilsFile);
28
+ // Generate node HTTP adapter if configured (for *.localhost subdomain routing)
29
+ if (useNodeHttpAdapter) {
30
+ files.push((0, utils_generator_1.generateNodeFetchFile)());
31
+ }
24
32
  const contextFile = (0, infra_generator_1.generateContextCommand)(toolName);
25
33
  files.push(contextFile);
26
34
  const authFile = (0, infra_generator_1.generateAuthCommand)(toolName);
27
35
  files.push(authFile);
28
36
  for (const table of tables) {
29
- const tableFile = (0, table_command_generator_1.generateTableCommand)(table);
37
+ const tableFile = (0, table_command_generator_1.generateTableCommand)(table, {
38
+ typeRegistry: options.typeRegistry,
39
+ });
30
40
  files.push(tableFile);
31
41
  }
32
42
  const allCustomOps = [
@@ -39,6 +49,11 @@ function generateCli(options) {
39
49
  }
40
50
  const commandMapFile = (0, command_map_generator_1.generateCommandMap)(tables, allCustomOps, toolName);
41
51
  files.push(commandMapFile);
52
+ // Generate entry point if configured
53
+ const generateEntryPoint = typeof cliConfig === 'object' && !!cliConfig.entryPoint;
54
+ if (generateEntryPoint) {
55
+ files.push((0, utils_generator_1.generateEntryPointFile)());
56
+ }
42
57
  return {
43
58
  files,
44
59
  stats: {
@@ -71,10 +86,16 @@ function generateMultiTargetCli(options) {
71
86
  endpoint: t.endpoint,
72
87
  ormImportPath: t.ormImportPath,
73
88
  }));
74
- const executorFile = (0, executor_generator_1.generateMultiTargetExecutorFile)(toolName, executorInputs);
89
+ const executorFile = (0, executor_generator_1.generateMultiTargetExecutorFile)(toolName, executorInputs, {
90
+ nodeHttpAdapter: !!options.nodeHttpAdapter,
91
+ });
75
92
  files.push(executorFile);
76
93
  const utilsFile = (0, utils_generator_1.generateUtilsFile)();
77
94
  files.push(utilsFile);
95
+ // Generate node HTTP adapter if configured (for *.localhost subdomain routing)
96
+ if (options.nodeHttpAdapter) {
97
+ files.push((0, utils_generator_1.generateNodeFetchFile)());
98
+ }
78
99
  const contextFile = (0, infra_generator_1.generateMultiTargetContextCommand)(toolName, builtinNames.context, targets.map((t) => ({ name: t.name, endpoint: t.endpoint })));
79
100
  files.push(contextFile);
80
101
  const authFile = (0, infra_generator_1.generateAuthCommandWithName)(toolName, builtinNames.auth);
@@ -92,6 +113,7 @@ function generateMultiTargetCli(options) {
92
113
  const tableFile = (0, table_command_generator_1.generateTableCommand)(table, {
93
114
  targetName: target.name,
94
115
  executorImportPath: '../../executor',
116
+ typeRegistry: target.typeRegistry,
95
117
  });
96
118
  files.push(tableFile);
97
119
  }
@@ -119,6 +141,10 @@ function generateMultiTargetCli(options) {
119
141
  targets: commandMapTargets,
120
142
  });
121
143
  files.push(commandMapFile);
144
+ // Generate entry point if configured
145
+ if (options.entryPoint) {
146
+ files.push((0, utils_generator_1.generateEntryPointFile)());
147
+ }
122
148
  return {
123
149
  files,
124
150
  stats: {
@@ -158,3 +184,4 @@ var docs_utils_1 = require("../docs-utils");
158
184
  Object.defineProperty(exports, "resolveDocsConfig", { enumerable: true, get: function () { return docs_utils_1.resolveDocsConfig; } });
159
185
  var utils_generator_2 = require("./utils-generator");
160
186
  Object.defineProperty(exports, "generateUtilsFile", { enumerable: true, get: function () { return utils_generator_2.generateUtilsFile; } });
187
+ Object.defineProperty(exports, "generateEntryPointFile", { enumerable: true, get: function () { return utils_generator_2.generateEntryPointFile; } });
@@ -1,7 +1,9 @@
1
- import type { CleanTable } from '../../../types/schema';
1
+ import type { CleanTable, TypeRegistry } from '../../../types/schema';
2
2
  import type { GeneratedFile } from './executor-generator';
3
3
  export interface TableCommandOptions {
4
4
  targetName?: string;
5
5
  executorImportPath?: string;
6
+ /** TypeRegistry from introspection, used to check field defaults */
7
+ typeRegistry?: TypeRegistry;
6
8
  }
7
9
  export declare function generateTableCommand(table: CleanTable, options?: TableCommandOptions): GeneratedFile;
@@ -38,6 +38,7 @@ const t = __importStar(require("@babel/types"));
38
38
  const komoji_1 = require("komoji");
39
39
  const babel_ast_1 = require("../babel-ast");
40
40
  const utils_1 = require("../utils");
41
+ const utils_2 = require("../utils");
41
42
  function createImportDeclaration(moduleSpecifier, namedImports, typeOnly = false) {
42
43
  const specifiers = namedImports.map((name) => t.importSpecifier(t.identifier(name), t.identifier(name)));
43
44
  const decl = t.importDeclaration(specifiers, t.stringLiteral(moduleSpecifier));
@@ -183,7 +184,46 @@ function buildGetHandler(table, targetName) {
183
184
  t.tryStatement(t.blockStatement(tryBody), buildErrorCatch('Record not found.')),
184
185
  ]), false, true);
185
186
  }
186
- function buildMutationHandler(table, operation, targetName) {
187
+ /**
188
+ * Get the set of field names that have defaults in the create input type.
189
+ * Looks up the CreateXInput -> inner input type (e.g. DatabaseInput) in the
190
+ * TypeRegistry and checks each field's defaultValue from introspection.
191
+ */
192
+ function getFieldsWithDefaults(table, typeRegistry) {
193
+ const fieldsWithDefaults = new Set();
194
+ if (!typeRegistry)
195
+ return fieldsWithDefaults;
196
+ // Look up the CreateXInput type (e.g. CreateDatabaseInput)
197
+ const createInputTypeName = (0, utils_2.getCreateInputTypeName)(table);
198
+ const createInputType = typeRegistry.get(createInputTypeName);
199
+ if (!createInputType?.inputFields)
200
+ return fieldsWithDefaults;
201
+ // The CreateXInput has an inner field (e.g. "database" of type DatabaseInput)
202
+ // Find the inner input type that contains the actual field definitions
203
+ for (const inputField of createInputType.inputFields) {
204
+ // The inner field's type name is the actual input type (e.g. DatabaseInput)
205
+ const innerTypeName = inputField.type.name
206
+ || inputField.type.ofType?.name
207
+ || inputField.type.ofType?.ofType?.name;
208
+ if (!innerTypeName)
209
+ continue;
210
+ const innerType = typeRegistry.get(innerTypeName);
211
+ if (!innerType?.inputFields)
212
+ continue;
213
+ // Check each field in the inner input type for defaultValue
214
+ for (const field of innerType.inputFields) {
215
+ if (field.defaultValue !== undefined) {
216
+ fieldsWithDefaults.add(field.name);
217
+ }
218
+ // Also check if the field is NOT wrapped in NON_NULL (nullable = has default or is optional)
219
+ if (field.type.kind !== 'NON_NULL') {
220
+ fieldsWithDefaults.add(field.name);
221
+ }
222
+ }
223
+ }
224
+ return fieldsWithDefaults;
225
+ }
226
+ function buildMutationHandler(table, operation, targetName, typeRegistry) {
187
227
  const { singularName } = (0, utils_1.getTableNames)(table);
188
228
  const pkFields = (0, utils_1.getPrimaryKeyInfo)(table);
189
229
  const pk = pkFields[0];
@@ -191,6 +231,8 @@ function buildMutationHandler(table, operation, targetName) {
191
231
  f.name !== 'nodeId' &&
192
232
  f.name !== 'createdAt' &&
193
233
  f.name !== 'updatedAt');
234
+ // Get fields that have defaults from introspection (for create operations)
235
+ const fieldsWithDefaults = getFieldsWithDefaults(table, typeRegistry);
194
236
  const questions = [];
195
237
  if (operation === 'update' || operation === 'delete') {
196
238
  questions.push(t.objectExpression([
@@ -202,11 +244,14 @@ function buildMutationHandler(table, operation, targetName) {
202
244
  }
203
245
  if (operation !== 'delete') {
204
246
  for (const field of editableFields) {
247
+ // For create: field is required only if it has no default value
248
+ // For update: all fields are optional (user only updates what they want)
249
+ const isRequired = operation === 'create' && !fieldsWithDefaults.has(field.name);
205
250
  questions.push(t.objectExpression([
206
251
  t.objectProperty(t.identifier('type'), t.stringLiteral('text')),
207
252
  t.objectProperty(t.identifier('name'), t.stringLiteral(field.name)),
208
253
  t.objectProperty(t.identifier('message'), t.stringLiteral(field.name)),
209
- t.objectProperty(t.identifier('required'), t.booleanLiteral(operation === 'create')),
254
+ t.objectProperty(t.identifier('required'), t.booleanLiteral(isRequired)),
210
255
  ]));
211
256
  }
212
257
  }
@@ -365,9 +410,9 @@ function generateTableCommand(table, options) {
365
410
  const tn = options?.targetName;
366
411
  statements.push(buildListHandler(table, tn));
367
412
  statements.push(buildGetHandler(table, tn));
368
- statements.push(buildMutationHandler(table, 'create', tn));
369
- statements.push(buildMutationHandler(table, 'update', tn));
370
- statements.push(buildMutationHandler(table, 'delete', tn));
413
+ statements.push(buildMutationHandler(table, 'create', tn, options?.typeRegistry));
414
+ statements.push(buildMutationHandler(table, 'update', tn, options?.typeRegistry));
415
+ statements.push(buildMutationHandler(table, 'delete', tn, options?.typeRegistry));
371
416
  const header = (0, utils_1.getGeneratedFileHeader)(`CLI commands for ${table.name}`);
372
417
  const code = (0, babel_ast_1.generateCode)(statements);
373
418
  return {
@@ -8,3 +8,20 @@ import type { GeneratedFile } from './executor-generator';
8
8
  * and mutation input parsing.
9
9
  */
10
10
  export declare function generateUtilsFile(): GeneratedFile;
11
+ /**
12
+ * Generate a node-fetch.ts file with NodeHttpAdapter for CLI.
13
+ *
14
+ * Provides a GraphQLAdapter implementation using node:http/node:https
15
+ * instead of the Fetch API. This cleanly handles *.localhost subdomain
16
+ * routing (DNS resolution + Host header) without any global patching.
17
+ */
18
+ export declare function generateNodeFetchFile(): GeneratedFile;
19
+ /**
20
+ * Generate an index.ts entry point file for the CLI.
21
+ *
22
+ * Creates a runnable entry point that imports the command map,
23
+ * handles --version and --tty flags, and starts the CLI.
24
+ * This is off by default (cliEntryPoint: false) since many projects
25
+ * provide their own entry point with custom configuration.
26
+ */
27
+ export declare function generateEntryPointFile(): GeneratedFile;
@@ -34,6 +34,8 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.generateUtilsFile = generateUtilsFile;
37
+ exports.generateNodeFetchFile = generateNodeFetchFile;
38
+ exports.generateEntryPointFile = generateEntryPointFile;
37
39
  const fs = __importStar(require("fs"));
38
40
  const path = __importStar(require("path"));
39
41
  const utils_1 = require("../utils");
@@ -76,3 +78,30 @@ function generateUtilsFile() {
76
78
  content: readTemplateFile('cli-utils.ts', 'CLI utility functions for type coercion and input handling'),
77
79
  };
78
80
  }
81
+ /**
82
+ * Generate a node-fetch.ts file with NodeHttpAdapter for CLI.
83
+ *
84
+ * Provides a GraphQLAdapter implementation using node:http/node:https
85
+ * instead of the Fetch API. This cleanly handles *.localhost subdomain
86
+ * routing (DNS resolution + Host header) without any global patching.
87
+ */
88
+ function generateNodeFetchFile() {
89
+ return {
90
+ fileName: 'node-fetch.ts',
91
+ content: readTemplateFile('node-fetch.ts', 'Node HTTP adapter for localhost subdomain routing'),
92
+ };
93
+ }
94
+ /**
95
+ * Generate an index.ts entry point file for the CLI.
96
+ *
97
+ * Creates a runnable entry point that imports the command map,
98
+ * handles --version and --tty flags, and starts the CLI.
99
+ * This is off by default (cliEntryPoint: false) since many projects
100
+ * provide their own entry point with custom configuration.
101
+ */
102
+ function generateEntryPointFile() {
103
+ return {
104
+ fileName: 'index.ts',
105
+ content: readTemplateFile('cli-entry.ts', 'CLI entry point'),
106
+ };
107
+ }
@@ -25,4 +25,6 @@ export declare function generateSelectTypesFile(): GeneratedClientFile;
25
25
  /**
26
26
  * Generate the main index.ts with createClient factory
27
27
  */
28
- export declare function generateCreateClientFile(tables: CleanTable[], hasCustomQueries: boolean, hasCustomMutations: boolean): GeneratedClientFile;
28
+ export declare function generateCreateClientFile(tables: CleanTable[], hasCustomQueries: boolean, hasCustomMutations: boolean, options?: {
29
+ nodeHttpAdapter?: boolean;
30
+ }): GeneratedClientFile;
@@ -114,7 +114,7 @@ function createImportDeclaration(moduleSpecifier, namedImports, typeOnly = false
114
114
  /**
115
115
  * Generate the main index.ts with createClient factory
116
116
  */
117
- function generateCreateClientFile(tables, hasCustomQueries, hasCustomMutations) {
117
+ function generateCreateClientFile(tables, hasCustomQueries, hasCustomMutations, options) {
118
118
  const statements = [];
119
119
  // Add imports
120
120
  // Import OrmClient (value) and OrmClientConfig (type) separately
@@ -156,6 +156,12 @@ function generateCreateClientFile(tables, hasCustomQueries, hasCustomMutations)
156
156
  statements.push(t.exportAllDeclaration(t.stringLiteral('./select-types')));
157
157
  // Re-export all models
158
158
  statements.push(t.exportAllDeclaration(t.stringLiteral('./models')));
159
+ // Re-export NodeHttpAdapter when enabled (for use in any Node.js application)
160
+ if (options?.nodeHttpAdapter) {
161
+ statements.push(t.exportNamedDeclaration(null, [
162
+ t.exportSpecifier(t.identifier('NodeHttpAdapter'), t.identifier('NodeHttpAdapter')),
163
+ ], t.stringLiteral('./node-fetch')));
164
+ }
159
165
  // Re-export custom operations
160
166
  if (hasCustomQueries) {
161
167
  statements.push(t.exportNamedDeclaration(null, [
@@ -91,7 +91,7 @@ function generateOrm(options) {
91
91
  const typesBarrel = (0, barrel_1.generateTypesBarrel)(useSharedTypes);
92
92
  files.push({ path: typesBarrel.fileName, content: typesBarrel.content });
93
93
  // 7. Generate main index.ts with createClient
94
- const indexFile = (0, client_generator_1.generateCreateClientFile)(tables, hasCustomQueries, hasCustomMutations);
94
+ const indexFile = (0, client_generator_1.generateCreateClientFile)(tables, hasCustomQueries, hasCustomMutations, { nodeHttpAdapter: !!options.config.nodeHttpAdapter });
95
95
  files.push({ path: indexFile.fileName, content: indexFile.content });
96
96
  return {
97
97
  files,
@@ -0,0 +1,33 @@
1
+ /**
2
+ * CLI entry point for running the generated CLI application.
3
+ *
4
+ * Creates an inquirerer CLI instance with the generated command map,
5
+ * handles --version and --tty flags, and runs the CLI.
6
+ *
7
+ * NOTE: This file is read at codegen time and written to output.
8
+ * Any changes here will affect all generated CLI entry points.
9
+ */
10
+
11
+ import { CLI, CLIOptions, getPackageJson } from 'inquirerer';
12
+ import { commands } from './commands';
13
+
14
+ if (process.argv.includes('--version') || process.argv.includes('-v')) {
15
+ const pkg = getPackageJson(__dirname);
16
+ console.log(pkg.version);
17
+ process.exit(0);
18
+ }
19
+
20
+ // Check for --tty false to enable non-interactive mode (noTty)
21
+ const ttyIdx = process.argv.indexOf('--tty');
22
+ const noTty = ttyIdx !== -1 && process.argv[ttyIdx + 1] === 'false';
23
+
24
+ const options: Partial<CLIOptions> = {
25
+ noTty,
26
+ minimistOpts: { alias: { v: 'version', h: 'help' } },
27
+ };
28
+
29
+ const app = new CLI(commands, options);
30
+ app.run().catch((e) => {
31
+ console.error('Unexpected error:', e);
32
+ process.exit(1);
33
+ });