@constructive-io/graphql-codegen 4.41.0 → 4.41.2

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/docs-generator.js +28 -0
  2. package/core/codegen/cli/executor-generator.d.ts +2 -6
  3. package/core/codegen/cli/executor-generator.js +12 -48
  4. package/core/codegen/cli/index.d.ts +0 -2
  5. package/core/codegen/cli/index.js +2 -16
  6. package/core/codegen/cli/utils-generator.d.ts +0 -8
  7. package/core/codegen/cli/utils-generator.js +0 -14
  8. package/core/codegen/hooks-docs-generator.js +26 -0
  9. package/core/codegen/orm/client-generator.d.ts +1 -3
  10. package/core/codegen/orm/client-generator.js +1 -1
  11. package/core/codegen/orm/docs-generator.js +55 -1
  12. package/core/codegen/orm/index.js +1 -1
  13. package/core/codegen/templates/select-types.ts +1 -1
  14. package/core/generate.js +2 -19
  15. package/esm/core/codegen/cli/docs-generator.js +28 -0
  16. package/esm/core/codegen/cli/executor-generator.d.ts +2 -6
  17. package/esm/core/codegen/cli/executor-generator.js +12 -48
  18. package/esm/core/codegen/cli/index.d.ts +0 -2
  19. package/esm/core/codegen/cli/index.js +3 -17
  20. package/esm/core/codegen/cli/utils-generator.d.ts +0 -8
  21. package/esm/core/codegen/cli/utils-generator.js +0 -13
  22. package/esm/core/codegen/hooks-docs-generator.js +27 -1
  23. package/esm/core/codegen/orm/client-generator.d.ts +1 -3
  24. package/esm/core/codegen/orm/client-generator.js +1 -1
  25. package/esm/core/codegen/orm/docs-generator.js +55 -1
  26. package/esm/core/codegen/orm/index.js +1 -1
  27. package/esm/core/generate.js +2 -19
  28. package/esm/types/config.d.ts +0 -18
  29. package/package.json +4 -4
  30. package/types/config.d.ts +0 -18
  31. package/core/codegen/templates/node-fetch.ts +0 -198
@@ -111,6 +111,18 @@ function generateReadme(tables, customOperations, toolName, registry) {
111
111
  lines.push(`| \`create\` | Create a new ${singularName} |`);
112
112
  lines.push(`| \`update\` | Update an existing ${singularName} |`);
113
113
  lines.push(`| \`delete\` | Delete a ${singularName} |`);
114
+ if (table.query?.bulkInsert) {
115
+ lines.push(`| \`bulk-create\` | Bulk create ${singularName} records |`);
116
+ }
117
+ if (table.query?.bulkUpsert) {
118
+ lines.push(`| \`bulk-upsert\` | Bulk upsert ${singularName} records |`);
119
+ }
120
+ if (table.query?.bulkUpdate) {
121
+ lines.push(`| \`bulk-update\` | Bulk update ${singularName} records |`);
122
+ }
123
+ if (table.query?.bulkDelete) {
124
+ lines.push(`| \`bulk-delete\` | Bulk delete ${singularName} records |`);
125
+ }
114
126
  lines.push('');
115
127
  lines.push('**Fields:**');
116
128
  lines.push('');
@@ -403,6 +415,10 @@ function generateSkills(tables, customOperations, toolName, targetName, registry
403
415
  `${toolName} ${kebab} create ${createFlags}`,
404
416
  `${toolName} ${kebab} update --${pk.name} <${(0, docs_utils_1.cleanTypeName)(pk.gqlType)}> ${editableFields.map((f) => `[--${f.name} <${(0, docs_utils_1.cleanTypeName)(f.type.gqlType)}>]`).join(' ')}`,
405
417
  `${toolName} ${kebab} delete --${pk.name} <${(0, docs_utils_1.cleanTypeName)(pk.gqlType)}>`,
418
+ ...(table.query?.bulkInsert ? [`${toolName} ${kebab} bulk-create --data '<JSON array>'`] : []),
419
+ ...(table.query?.bulkUpsert ? [`${toolName} ${kebab} bulk-upsert --data '<JSON array>'`] : []),
420
+ ...(table.query?.bulkUpdate ? [`${toolName} ${kebab} bulk-update --where '<JSON>' --data '<JSON>'`] : []),
421
+ ...(table.query?.bulkDelete ? [`${toolName} ${kebab} bulk-delete --where '<JSON>'`] : []),
406
422
  ],
407
423
  examples: [
408
424
  {
@@ -694,6 +710,18 @@ function generateMultiTargetReadme(input) {
694
710
  lines.push(`| \`create\` | Create a new ${singularName} |`);
695
711
  lines.push(`| \`update\` | Update an existing ${singularName} |`);
696
712
  lines.push(`| \`delete\` | Delete a ${singularName} |`);
713
+ if (table.query?.bulkInsert) {
714
+ lines.push(`| \`bulk-create\` | Bulk create ${singularName} records |`);
715
+ }
716
+ if (table.query?.bulkUpsert) {
717
+ lines.push(`| \`bulk-upsert\` | Bulk upsert ${singularName} records |`);
718
+ }
719
+ if (table.query?.bulkUpdate) {
720
+ lines.push(`| \`bulk-update\` | Bulk update ${singularName} records |`);
721
+ }
722
+ if (table.query?.bulkDelete) {
723
+ lines.push(`| \`bulk-delete\` | Bulk delete ${singularName} records |`);
724
+ }
697
725
  lines.push('');
698
726
  lines.push('**Fields:**');
699
727
  lines.push('');
@@ -7,9 +7,5 @@ export interface MultiTargetExecutorInput {
7
7
  endpoint: string;
8
8
  ormImportPath: string;
9
9
  }
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;
10
+ export declare function generateExecutorFile(toolName: string): GeneratedFile;
11
+ export declare function generateMultiTargetExecutorFile(toolName: string, targets: MultiTargetExecutorInput[]): GeneratedFile;
@@ -44,12 +44,8 @@ function createImportDeclaration(moduleSpecifier, namedImports, typeOnly = false
44
44
  decl.importKind = typeOnly ? 'type' : 'value';
45
45
  return decl;
46
46
  }
47
- function generateExecutorFile(toolName, options) {
47
+ function generateExecutorFile(toolName) {
48
48
  const statements = [];
49
- // Import NodeHttpAdapter for *.localhost subdomain routing
50
- if (options?.nodeHttpAdapter) {
51
- statements.push(createImportDeclaration('./node-fetch', ['NodeHttpAdapter']));
52
- }
53
49
  statements.push(createImportDeclaration('appstash', ['createConfigStore']));
54
50
  statements.push(createImportDeclaration('../orm', ['createClient']));
55
51
  statements.push(t.variableDeclaration('const', [
@@ -109,26 +105,12 @@ function generateExecutorFile(toolName, options) {
109
105
  ]))),
110
106
  ])),
111
107
  ])),
112
- // Build createClient config — use NodeHttpAdapter for *.localhost endpoints
113
- ...(options?.nodeHttpAdapter
114
- ? [
115
- t.returnStatement(t.callExpression(t.identifier('createClient'), [
116
- t.objectExpression([
117
- t.objectProperty(t.identifier('adapter'), t.newExpression(t.identifier('NodeHttpAdapter'), [
118
- t.memberExpression(t.identifier('ctx'), t.identifier('endpoint')),
119
- t.identifier('headers'),
120
- ])),
121
- ]),
122
- ])),
123
- ]
124
- : [
125
- t.returnStatement(t.callExpression(t.identifier('createClient'), [
126
- t.objectExpression([
127
- t.objectProperty(t.identifier('endpoint'), t.memberExpression(t.identifier('ctx'), t.identifier('endpoint'))),
128
- t.objectProperty(t.identifier('headers'), t.identifier('headers')),
129
- ]),
130
- ])),
108
+ t.returnStatement(t.callExpression(t.identifier('createClient'), [
109
+ t.objectExpression([
110
+ t.objectProperty(t.identifier('endpoint'), t.memberExpression(t.identifier('ctx'), t.identifier('endpoint'))),
111
+ t.objectProperty(t.identifier('headers'), t.identifier('headers')),
131
112
  ]),
113
+ ])),
132
114
  ]);
133
115
  const getClientFunc = t.functionDeclaration(t.identifier('getClient'), [contextNameParam], getClientBody);
134
116
  statements.push(t.exportNamedDeclaration(getClientFunc));
@@ -139,12 +121,8 @@ function generateExecutorFile(toolName, options) {
139
121
  content: header + '\n' + code,
140
122
  };
141
123
  }
142
- function generateMultiTargetExecutorFile(toolName, targets, options) {
124
+ function generateMultiTargetExecutorFile(toolName, targets) {
143
125
  const statements = [];
144
- // Import NodeHttpAdapter for *.localhost subdomain routing
145
- if (options?.nodeHttpAdapter) {
146
- statements.push(createImportDeclaration('./node-fetch', ['NodeHttpAdapter']));
147
- }
148
126
  statements.push(createImportDeclaration('appstash', ['createConfigStore']));
149
127
  for (const target of targets) {
150
128
  const aliasName = `create${target.name[0].toUpperCase()}${target.name.slice(1)}Client`;
@@ -235,26 +213,12 @@ function generateMultiTargetExecutorFile(toolName, targets, options) {
235
213
  ]), t.blockStatement([
236
214
  t.expressionStatement(t.assignmentExpression('=', t.identifier('endpoint'), t.logicalExpression('||', t.memberExpression(t.identifier('defaultEndpoints'), t.identifier('targetName'), true), t.stringLiteral('')))),
237
215
  ])),
238
- // Build createClient config — use NodeHttpAdapter for *.localhost endpoints
239
- ...(options?.nodeHttpAdapter
240
- ? [
241
- t.returnStatement(t.callExpression(t.identifier('createFn'), [
242
- t.objectExpression([
243
- t.objectProperty(t.identifier('adapter'), t.newExpression(t.identifier('NodeHttpAdapter'), [
244
- t.identifier('endpoint'),
245
- t.identifier('headers'),
246
- ])),
247
- ]),
248
- ])),
249
- ]
250
- : [
251
- t.returnStatement(t.callExpression(t.identifier('createFn'), [
252
- t.objectExpression([
253
- t.objectProperty(t.identifier('endpoint'), t.identifier('endpoint')),
254
- t.objectProperty(t.identifier('headers'), t.identifier('headers')),
255
- ]),
256
- ])),
216
+ t.returnStatement(t.callExpression(t.identifier('createFn'), [
217
+ t.objectExpression([
218
+ t.objectProperty(t.identifier('endpoint'), t.identifier('endpoint')),
219
+ t.objectProperty(t.identifier('headers'), t.identifier('headers')),
257
220
  ]),
221
+ ])),
258
222
  ]);
259
223
  const getClientFunc = t.functionDeclaration(t.identifier('getClient'), [targetNameParam, contextNameParam], getClientBody);
260
224
  statements.push(t.exportNamedDeclaration(getClientFunc));
@@ -39,8 +39,6 @@ export interface GenerateMultiTargetCliOptions {
39
39
  toolName: string;
40
40
  builtinNames?: BuiltinNames;
41
41
  targets: MultiTargetCliTarget[];
42
- /** Enable NodeHttpAdapter for *.localhost subdomain routing */
43
- nodeHttpAdapter?: boolean;
44
42
  /** Generate a runnable index.ts entry point */
45
43
  entryPoint?: boolean;
46
44
  }
@@ -19,11 +19,7 @@ function generateCli(options) {
19
19
  const toolName = typeof cliConfig === 'object' && cliConfig.toolName
20
20
  ? cliConfig.toolName
21
21
  : 'app';
22
- // Use top-level nodeHttpAdapter from config (auto-enabled for CLI by generate.ts)
23
- const useNodeHttpAdapter = !!config.nodeHttpAdapter;
24
- const executorFile = (0, executor_generator_1.generateExecutorFile)(toolName, {
25
- nodeHttpAdapter: useNodeHttpAdapter,
26
- });
22
+ const executorFile = (0, executor_generator_1.generateExecutorFile)(toolName);
27
23
  files.push(executorFile);
28
24
  const utilsFile = (0, utils_generator_1.generateUtilsFile)();
29
25
  files.push(utilsFile);
@@ -32,10 +28,6 @@ function generateCli(options) {
32
28
  if (hasAnyEmbeddings) {
33
29
  files.push((0, utils_generator_1.generateEmbedderFile)());
34
30
  }
35
- // Generate node HTTP adapter if configured (for *.localhost subdomain routing)
36
- if (useNodeHttpAdapter) {
37
- files.push((0, utils_generator_1.generateNodeFetchFile)());
38
- }
39
31
  const contextFile = (0, infra_generator_1.generateContextCommand)(toolName);
40
32
  files.push(contextFile);
41
33
  const authFile = (0, infra_generator_1.generateAuthCommand)(toolName);
@@ -97,9 +89,7 @@ function generateMultiTargetCli(options) {
97
89
  endpoint: t.endpoint,
98
90
  ormImportPath: t.ormImportPath,
99
91
  }));
100
- const executorFile = (0, executor_generator_1.generateMultiTargetExecutorFile)(toolName, executorInputs, {
101
- nodeHttpAdapter: !!options.nodeHttpAdapter,
102
- });
92
+ const executorFile = (0, executor_generator_1.generateMultiTargetExecutorFile)(toolName, executorInputs);
103
93
  files.push(executorFile);
104
94
  const utilsFile = (0, utils_generator_1.generateUtilsFile)();
105
95
  files.push(utilsFile);
@@ -108,10 +98,6 @@ function generateMultiTargetCli(options) {
108
98
  if (hasAnyMtEmbeddings) {
109
99
  files.push((0, utils_generator_1.generateEmbedderFile)());
110
100
  }
111
- // Generate node HTTP adapter if configured (for *.localhost subdomain routing)
112
- if (options.nodeHttpAdapter) {
113
- files.push((0, utils_generator_1.generateNodeFetchFile)());
114
- }
115
101
  const contextFile = (0, infra_generator_1.generateMultiTargetContextCommand)(toolName, builtinNames.context, targets.map((t) => ({ name: t.name, endpoint: t.endpoint })));
116
102
  files.push(contextFile);
117
103
  const authFile = (0, infra_generator_1.generateAuthCommandWithName)(toolName, builtinNames.auth);
@@ -8,14 +8,6 @@ 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
11
  /**
20
12
  * Generate an index.ts entry point file for the CLI.
21
13
  *
@@ -34,7 +34,6 @@ 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
37
  exports.generateEntryPointFile = generateEntryPointFile;
39
38
  exports.generateEmbedderFile = generateEmbedderFile;
40
39
  const fs = __importStar(require("fs"));
@@ -79,19 +78,6 @@ function generateUtilsFile() {
79
78
  content: readTemplateFile('cli-utils.ts', 'CLI utility functions for type coercion and input handling'),
80
79
  };
81
80
  }
82
- /**
83
- * Generate a node-fetch.ts file with NodeHttpAdapter for CLI.
84
- *
85
- * Provides a GraphQLAdapter implementation using node:http/node:https
86
- * instead of the Fetch API. This cleanly handles *.localhost subdomain
87
- * routing (DNS resolution + Host header) without any global patching.
88
- */
89
- function generateNodeFetchFile() {
90
- return {
91
- fileName: 'node-fetch.ts',
92
- content: readTemplateFile('node-fetch.ts', 'Node HTTP adapter for localhost subdomain routing'),
93
- };
94
- }
95
81
  /**
96
82
  * Generate an index.ts entry point file for the CLI.
97
83
  *
@@ -52,6 +52,18 @@ function generateHooksReadme(tables, customOperations, registry) {
52
52
  lines.push(`| \`${(0, utils_1.getUpdateMutationHookName)(table)}\` | Mutation | ${table.description || `Update a ${singularName}`} |`);
53
53
  lines.push(`| \`${(0, utils_1.getDeleteMutationHookName)(table)}\` | Mutation | ${table.description || `Delete a ${singularName}`} |`);
54
54
  }
55
+ if (table.query?.bulkInsert) {
56
+ lines.push(`| \`${(0, utils_1.getBulkCreateMutationHookName)(table)}\` | Mutation | Bulk create ${pluralName} |`);
57
+ }
58
+ if (table.query?.bulkUpsert) {
59
+ lines.push(`| \`${(0, utils_1.getBulkUpsertMutationHookName)(table)}\` | Mutation | Bulk upsert ${pluralName} |`);
60
+ }
61
+ if (table.query?.bulkUpdate) {
62
+ lines.push(`| \`${(0, utils_1.getBulkUpdateMutationHookName)(table)}\` | Mutation | Bulk update ${pluralName} |`);
63
+ }
64
+ if (table.query?.bulkDelete) {
65
+ lines.push(`| \`${(0, utils_1.getBulkDeleteMutationHookName)(table)}\` | Mutation | Bulk delete ${pluralName} |`);
66
+ }
55
67
  }
56
68
  for (const op of customOperations) {
57
69
  lines.push(`| \`${getCustomHookName(op)}\` | ${(0, utils_1.ucFirst)(op.kind)} | ${op.description || op.name} |`);
@@ -85,6 +97,14 @@ function generateHooksReadme(tables, customOperations, registry) {
85
97
  lines.push(` selection: { fields: { ${pk.name}: true } },`);
86
98
  lines.push('});');
87
99
  lines.push(`create({ ${scalarFields.filter((f) => f.name !== pk.name && f.name !== 'nodeId' && f.name !== 'createdAt' && f.name !== 'updatedAt').map((f) => `${f.name}: ${(0, docs_utils_1.fieldPlaceholder)(f)}`).join(', ')} });`);
100
+ if (table.query?.bulkInsert) {
101
+ lines.push('');
102
+ lines.push(`// Bulk create ${pluralName}`);
103
+ lines.push(`const { mutate: bulkCreate } = ${(0, utils_1.getBulkCreateMutationHookName)(table)}({`);
104
+ lines.push(` selection: { fields: { ${pk.name}: true } },`);
105
+ lines.push('});');
106
+ lines.push(`bulkCreate({ data: [{ ${scalarFields.filter((f) => f.name !== pk.name && f.name !== 'nodeId' && f.name !== 'createdAt' && f.name !== 'updatedAt').map((f) => `${f.name}: ${(0, docs_utils_1.fieldPlaceholder)(f)}`).join(', ')} }] });`);
107
+ }
88
108
  lines.push('```');
89
109
  lines.push('');
90
110
  }
@@ -155,6 +175,7 @@ function generateHooksAgentsDocs(tables, customOperations) {
155
175
  lines.push('');
156
176
  lines.push('- Query hooks: `use<PluralName>Query`, `use<SingularName>Query`');
157
177
  lines.push('- Mutation hooks: `useCreate<Name>Mutation`, `useUpdate<Name>Mutation`, `useDelete<Name>Mutation`');
178
+ lines.push('- Bulk mutation hooks (when enabled): `useBulkCreate<Name>Mutation`, `useBulkUpsert<Name>Mutation`, `useBulkUpdate<Name>Mutation`, `useBulkDelete<Name>Mutation`');
158
179
  lines.push('- All hooks accept a `selection` parameter to pick fields');
159
180
  lines.push('');
160
181
  lines.push('## Boundaries');
@@ -200,6 +221,10 @@ function generateHooksSkills(tables, customOperations, targetName, registry) {
200
221
  `${(0, utils_1.getDeleteMutationHookName)(table)}({})`,
201
222
  ]
202
223
  : []),
224
+ ...(table.query?.bulkInsert ? [`${(0, utils_1.getBulkCreateMutationHookName)(table)}() — bulk create with data array`] : []),
225
+ ...(table.query?.bulkUpsert ? [`${(0, utils_1.getBulkUpsertMutationHookName)(table)}() — bulk upsert with onConflict`] : []),
226
+ ...(table.query?.bulkUpdate ? [`${(0, utils_1.getBulkUpdateMutationHookName)(table)}() — bulk update with where + data`] : []),
227
+ ...(table.query?.bulkDelete ? [`${(0, utils_1.getBulkDeleteMutationHookName)(table)}() — bulk delete with where`] : []),
203
228
  ],
204
229
  examples: [
205
230
  {
@@ -275,6 +300,7 @@ function generateHooksSkills(tables, customOperations, targetName, registry) {
275
300
  '',
276
301
  `// Query hooks: use<Model>Query, use<Model>sQuery`,
277
302
  `// Mutation hooks: useCreate<Model>Mutation, useUpdate<Model>Mutation, useDelete<Model>Mutation`,
303
+ `// Bulk mutation hooks (when enabled): useBulkCreate<Model>Mutation, useBulkUpsert<Model>Mutation, etc.`,
278
304
  '',
279
305
  `const { data, isLoading } = ${hookExamples[0] || 'useModelQuery'}({`,
280
306
  ` selection: { fields: { id: true } },`,
@@ -31,6 +31,4 @@ export declare function generateSelectTypesFile(): GeneratedClientFile;
31
31
  /**
32
32
  * Generate the main index.ts with createClient factory
33
33
  */
34
- export declare function generateCreateClientFile(tables: Table[], hasCustomQueries: boolean, hasCustomMutations: boolean, options?: {
35
- nodeHttpAdapter?: boolean;
36
- }): GeneratedClientFile;
34
+ export declare function generateCreateClientFile(tables: Table[], hasCustomQueries: boolean, hasCustomMutations: boolean): GeneratedClientFile;
@@ -126,7 +126,7 @@ function createImportDeclaration(moduleSpecifier, namedImports, typeOnly = false
126
126
  /**
127
127
  * Generate the main index.ts with createClient factory
128
128
  */
129
- function generateCreateClientFile(tables, hasCustomQueries, hasCustomMutations, options) {
129
+ function generateCreateClientFile(tables, hasCustomQueries, hasCustomMutations) {
130
130
  const statements = [];
131
131
  // Add imports
132
132
  // Import OrmClient (value) and OrmClientConfig (type) separately
@@ -26,7 +26,17 @@ function generateOrmReadme(tables, customOperations, registry) {
26
26
  lines.push('|-------|------------|');
27
27
  for (const table of tables) {
28
28
  const { singularName } = (0, utils_1.getTableNames)(table);
29
- lines.push(`| \`${singularName}\` | findMany, findOne, create, update, delete |`);
29
+ const bulkOps = [];
30
+ if (table.query?.bulkInsert)
31
+ bulkOps.push('bulkCreate');
32
+ if (table.query?.bulkUpsert)
33
+ bulkOps.push('bulkUpsert');
34
+ if (table.query?.bulkUpdate)
35
+ bulkOps.push('bulkUpdate');
36
+ if (table.query?.bulkDelete)
37
+ bulkOps.push('bulkDelete');
38
+ const ops = ['findMany', 'findOne', 'create', 'update', 'delete', ...bulkOps].join(', ');
39
+ lines.push(`| \`${singularName}\` | ${ops} |`);
30
40
  }
31
41
  lines.push('');
32
42
  if (tables.length > 0) {
@@ -67,6 +77,26 @@ function generateOrmReadme(tables, customOperations, registry) {
67
77
  lines.push('');
68
78
  lines.push(`// Delete`);
69
79
  lines.push(`const deleted = await db.${singularName}.delete({ where: { ${pk.name}: ${(0, docs_utils_1.pkPlaceholder)(pk)} } }).execute();`);
80
+ if (table.query?.bulkInsert) {
81
+ lines.push('');
82
+ lines.push(`// Bulk Create`);
83
+ lines.push(`const bulkCreated = await db.${singularName}.bulkCreate({ data: [{ ${editableFields.map((f) => `${f.name}: ${(0, docs_utils_1.fieldPlaceholder)(f)}`).join(', ')} }], select: { ${pk.name}: true } }).execute();`);
84
+ }
85
+ if (table.query?.bulkUpsert) {
86
+ lines.push('');
87
+ lines.push(`// Bulk Upsert`);
88
+ lines.push(`const bulkUpserted = await db.${singularName}.bulkUpsert({ data: [{ ${editableFields.map((f) => `${f.name}: ${(0, docs_utils_1.fieldPlaceholder)(f)}`).join(', ')} }], onConflict: { constraint: 'PRIMARY_KEY', action: 'UPDATE' }, select: { ${pk.name}: true } }).execute();`);
89
+ }
90
+ if (table.query?.bulkUpdate) {
91
+ lines.push('');
92
+ lines.push(`// Bulk Update`);
93
+ lines.push(`const bulkUpdated = await db.${singularName}.bulkUpdate({ where: { ${editableFields[0]?.name || 'field'}: { equalTo: ${editableFields[0] ? (0, docs_utils_1.fieldPlaceholder)(editableFields[0]) : "'<String>'"} } }, data: { ${editableFields[0]?.name || 'field'}: ${editableFields[0] ? (0, docs_utils_1.fieldPlaceholder)(editableFields[0]) : "'<String>'"} }, select: { ${pk.name}: true } }).execute();`);
94
+ }
95
+ if (table.query?.bulkDelete) {
96
+ lines.push('');
97
+ lines.push(`// Bulk Delete`);
98
+ lines.push(`const bulkDeleted = await db.${singularName}.bulkDelete({ where: { ${pk.name}: { equalTo: ${(0, docs_utils_1.pkPlaceholder)(pk)} } } }).execute();`);
99
+ }
70
100
  lines.push('```');
71
101
  lines.push('');
72
102
  const ormSpecialGroups = (0, docs_utils_1.categorizeSpecialFields)(table);
@@ -170,6 +200,7 @@ function generateOrmAgentsDocs(tables, customOperations) {
170
200
  lines.push('');
171
201
  lines.push('- Access models via `db.<ModelName>` (e.g. `db.User`)');
172
202
  lines.push('- CRUD methods: `findMany`, `findOne`, `create`, `update`, `delete`');
203
+ lines.push('- Bulk methods (when enabled via smart tags): `bulkCreate`, `bulkUpsert`, `bulkUpdate`, `bulkDelete`');
173
204
  lines.push('- Chain `.execute().unwrap()` to run and throw on error, or `.execute()` alone for discriminated union result');
174
205
  lines.push('- Custom operations via `db.query.<name>` or `db.mutation.<name>`');
175
206
  lines.push('');
@@ -200,6 +231,19 @@ function generateOrmSkills(tables, customOperations, targetName, registry) {
200
231
  ? ormSkillBaseDesc + '\n\n' +
201
232
  ormSkillSpecialGroups.map((g) => `**${g.label}:** ${g.fields.map((f) => `\`${f.name}\``).join(', ')}\n${g.description}`).join('\n\n')
202
233
  : ormSkillBaseDesc;
234
+ const bulkUsageLines = [];
235
+ if (table.query?.bulkInsert) {
236
+ bulkUsageLines.push(`db.${modelName}.bulkCreate({ data: [...], select: { id: true } }).execute()`);
237
+ }
238
+ if (table.query?.bulkUpsert) {
239
+ bulkUsageLines.push(`db.${modelName}.bulkUpsert({ data: [...], onConflict: { constraint: '...', action: 'UPDATE' }, select: { id: true } }).execute()`);
240
+ }
241
+ if (table.query?.bulkUpdate) {
242
+ bulkUsageLines.push(`db.${modelName}.bulkUpdate({ where: {...}, data: {...}, select: { id: true } }).execute()`);
243
+ }
244
+ if (table.query?.bulkDelete) {
245
+ bulkUsageLines.push(`db.${modelName}.bulkDelete({ where: {...} }).execute()`);
246
+ }
203
247
  files.push({
204
248
  fileName: `${skillName}/references/${refName}.md`,
205
249
  content: (0, docs_utils_1.buildSkillReference)({
@@ -212,6 +256,7 @@ function generateOrmSkills(tables, customOperations, targetName, registry) {
212
256
  `db.${modelName}.create({ data: { ${editableFields.map((f) => `${f.name}: ${(0, docs_utils_1.fieldPlaceholder)(f)}`).join(', ')} }, select: { id: true } }).execute()`,
213
257
  `db.${modelName}.update({ where: { ${pk.name}: ${(0, docs_utils_1.pkPlaceholder)(pk)} }, data: { ${editableFields[0]?.name || 'field'}: ${editableFields[0] ? (0, docs_utils_1.fieldPlaceholder)(editableFields[0]) : "'<String>'"} }, select: { id: true } }).execute()`,
214
258
  `db.${modelName}.delete({ where: { ${pk.name}: ${(0, docs_utils_1.pkPlaceholder)(pk)} } }).execute()`,
259
+ ...bulkUsageLines,
215
260
  ],
216
261
  examples: [
217
262
  {
@@ -261,6 +306,7 @@ function generateOrmSkills(tables, customOperations, targetName, registry) {
261
306
  }
262
307
  // Generate the overview SKILL.md
263
308
  const tableNames = tables.map((t) => (0, utils_1.lcFirst)((0, utils_1.getTableNames)(t).singularName));
309
+ const hasBulkTables = tables.some((t) => t.query?.bulkInsert || t.query?.bulkUpsert || t.query?.bulkUpdate || t.query?.bulkDelete);
264
310
  files.push({
265
311
  fileName: `${skillName}/SKILL.md`,
266
312
  content: (0, docs_utils_1.buildSkillFile)({
@@ -277,6 +323,14 @@ function generateOrmSkills(tables, customOperations, targetName, registry) {
277
323
  `db.<model>.create({ data: { ... }, select: { id: true } }).execute()`,
278
324
  `db.<model>.update({ where: { id: '<UUID>' }, data: { ... }, select: { id: true } }).execute()`,
279
325
  `db.<model>.delete({ where: { id: '<UUID>' } }).execute()`,
326
+ ...(hasBulkTables ? [
327
+ '',
328
+ `// Bulk operations (on tables with @behavior +bulkInsert/+bulkUpsert/+bulkUpdate/+bulkDelete)`,
329
+ `db.<model>.bulkCreate({ data: [...], select: { id: true } }).execute()`,
330
+ `db.<model>.bulkUpsert({ data: [...], onConflict: { constraint: '...', action: 'UPDATE' }, select: { id: true } }).execute()`,
331
+ `db.<model>.bulkUpdate({ where: {...}, data: {...}, select: { id: true } }).execute()`,
332
+ `db.<model>.bulkDelete({ where: {...} }).execute()`,
333
+ ] : []),
280
334
  ],
281
335
  examples: [
282
336
  {
@@ -94,7 +94,7 @@ function generateOrm(options) {
94
94
  const typesBarrel = (0, barrel_1.generateTypesBarrel)(useSharedTypes);
95
95
  files.push({ path: typesBarrel.fileName, content: typesBarrel.content });
96
96
  // 7. Generate main index.ts with createClient
97
- const indexFile = (0, client_generator_1.generateCreateClientFile)(tables, hasCustomQueries, hasCustomMutations, { nodeHttpAdapter: !!options.config.nodeHttpAdapter });
97
+ const indexFile = (0, client_generator_1.generateCreateClientFile)(tables, hasCustomQueries, hasCustomMutations);
98
98
  files.push({ path: indexFile.fileName, content: indexFile.content });
99
99
  return {
100
100
  files,
@@ -21,7 +21,7 @@ export interface PageInfo {
21
21
  endCursor?: string | null;
22
22
  }
23
23
 
24
- export interface FindManyArgs<TSelect, TWhere, TOrderBy = never> {
24
+ export interface FindManyArgs<TSelect, TWhere, TOrderBy> {
25
25
  select?: TSelect;
26
26
  where?: TWhere;
27
27
  orderBy?: TOrderBy[];
package/core/generate.js CHANGED
@@ -89,9 +89,6 @@ async function generate(options = {}, internalOptions) {
89
89
  const runReactQuery = config.reactQuery ?? false;
90
90
  const runCli = internalOptions?.skipCli ? false : !!config.cli;
91
91
  const runOrm = runReactQuery || !!config.cli || (options.orm !== undefined ? !!options.orm : false);
92
- // Auto-enable nodeHttpAdapter when CLI is enabled, unless explicitly set to false
93
- const useNodeHttpAdapter = options.nodeHttpAdapter === true ||
94
- (runCli && options.nodeHttpAdapter !== false);
95
92
  const schemaEnabled = !!options.schema?.enabled;
96
93
  if (!schemaEnabled && !runReactQuery && !runOrm && !runCli) {
97
94
  return {
@@ -226,22 +223,13 @@ async function generate(options = {}, internalOptions) {
226
223
  mutations: customOperations.mutations,
227
224
  typeRegistry: customOperations.typeRegistry,
228
225
  },
229
- config: { ...config, nodeHttpAdapter: useNodeHttpAdapter },
226
+ config,
230
227
  sharedTypesPath: bothEnabled ? '..' : undefined,
231
228
  });
232
229
  filesToWrite.push(...files.map((file) => ({
233
230
  ...file,
234
231
  path: node_path_1.default.posix.join('orm', file.path),
235
232
  })));
236
- // Generate NodeHttpAdapter in ORM output when enabled
237
- if (useNodeHttpAdapter) {
238
- const { generateNodeFetchFile } = await Promise.resolve().then(() => __importStar(require('./codegen/cli/utils-generator')));
239
- const nodeFetchFile = generateNodeFetchFile();
240
- filesToWrite.push({
241
- path: node_path_1.default.posix.join('orm', nodeFetchFile.fileName),
242
- content: nodeFetchFile.content,
243
- });
244
- }
245
233
  }
246
234
  // Generate CLI commands
247
235
  if (runCli) {
@@ -252,7 +240,7 @@ async function generate(options = {}, internalOptions) {
252
240
  queries: customOperations.queries,
253
241
  mutations: customOperations.mutations,
254
242
  },
255
- config: { ...config, nodeHttpAdapter: useNodeHttpAdapter },
243
+ config,
256
244
  typeRegistry: customOperations.typeRegistry,
257
245
  });
258
246
  filesToWrite.push(...files.map((file) => ({
@@ -582,16 +570,11 @@ async function generateMulti(options) {
582
570
  if (useUnifiedCli && cliTargets.length > 0 && !dryRun) {
583
571
  const cliConfig = typeof unifiedCli === 'object' ? unifiedCli : {};
584
572
  const toolName = cliConfig.toolName ?? 'app';
585
- // Auto-enable nodeHttpAdapter for unified CLI unless explicitly disabled
586
- // Check first target config for explicit nodeHttpAdapter setting
587
573
  const firstTargetConfig = configs[names[0]];
588
- const multiNodeHttpAdapter = firstTargetConfig?.nodeHttpAdapter === true ||
589
- (firstTargetConfig?.nodeHttpAdapter !== false);
590
574
  const { files } = (0, cli_1.generateMultiTargetCli)({
591
575
  toolName,
592
576
  builtinNames: cliConfig.builtinNames,
593
577
  targets: cliTargets,
594
- nodeHttpAdapter: multiNodeHttpAdapter,
595
578
  entryPoint: cliConfig.entryPoint,
596
579
  });
597
580
  const cliFilesToWrite = files.map((file) => ({
@@ -101,6 +101,18 @@ export function generateReadme(tables, customOperations, toolName, registry) {
101
101
  lines.push(`| \`create\` | Create a new ${singularName} |`);
102
102
  lines.push(`| \`update\` | Update an existing ${singularName} |`);
103
103
  lines.push(`| \`delete\` | Delete a ${singularName} |`);
104
+ if (table.query?.bulkInsert) {
105
+ lines.push(`| \`bulk-create\` | Bulk create ${singularName} records |`);
106
+ }
107
+ if (table.query?.bulkUpsert) {
108
+ lines.push(`| \`bulk-upsert\` | Bulk upsert ${singularName} records |`);
109
+ }
110
+ if (table.query?.bulkUpdate) {
111
+ lines.push(`| \`bulk-update\` | Bulk update ${singularName} records |`);
112
+ }
113
+ if (table.query?.bulkDelete) {
114
+ lines.push(`| \`bulk-delete\` | Bulk delete ${singularName} records |`);
115
+ }
104
116
  lines.push('');
105
117
  lines.push('**Fields:**');
106
118
  lines.push('');
@@ -393,6 +405,10 @@ export function generateSkills(tables, customOperations, toolName, targetName, r
393
405
  `${toolName} ${kebab} create ${createFlags}`,
394
406
  `${toolName} ${kebab} update --${pk.name} <${cleanTypeName(pk.gqlType)}> ${editableFields.map((f) => `[--${f.name} <${cleanTypeName(f.type.gqlType)}>]`).join(' ')}`,
395
407
  `${toolName} ${kebab} delete --${pk.name} <${cleanTypeName(pk.gqlType)}>`,
408
+ ...(table.query?.bulkInsert ? [`${toolName} ${kebab} bulk-create --data '<JSON array>'`] : []),
409
+ ...(table.query?.bulkUpsert ? [`${toolName} ${kebab} bulk-upsert --data '<JSON array>'`] : []),
410
+ ...(table.query?.bulkUpdate ? [`${toolName} ${kebab} bulk-update --where '<JSON>' --data '<JSON>'`] : []),
411
+ ...(table.query?.bulkDelete ? [`${toolName} ${kebab} bulk-delete --where '<JSON>'`] : []),
396
412
  ],
397
413
  examples: [
398
414
  {
@@ -684,6 +700,18 @@ export function generateMultiTargetReadme(input) {
684
700
  lines.push(`| \`create\` | Create a new ${singularName} |`);
685
701
  lines.push(`| \`update\` | Update an existing ${singularName} |`);
686
702
  lines.push(`| \`delete\` | Delete a ${singularName} |`);
703
+ if (table.query?.bulkInsert) {
704
+ lines.push(`| \`bulk-create\` | Bulk create ${singularName} records |`);
705
+ }
706
+ if (table.query?.bulkUpsert) {
707
+ lines.push(`| \`bulk-upsert\` | Bulk upsert ${singularName} records |`);
708
+ }
709
+ if (table.query?.bulkUpdate) {
710
+ lines.push(`| \`bulk-update\` | Bulk update ${singularName} records |`);
711
+ }
712
+ if (table.query?.bulkDelete) {
713
+ lines.push(`| \`bulk-delete\` | Bulk delete ${singularName} records |`);
714
+ }
687
715
  lines.push('');
688
716
  lines.push('**Fields:**');
689
717
  lines.push('');
@@ -7,9 +7,5 @@ export interface MultiTargetExecutorInput {
7
7
  endpoint: string;
8
8
  ormImportPath: string;
9
9
  }
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;
10
+ export declare function generateExecutorFile(toolName: string): GeneratedFile;
11
+ export declare function generateMultiTargetExecutorFile(toolName: string, targets: MultiTargetExecutorInput[]): GeneratedFile;