@soda-gql/typegen 0.10.1 → 0.10.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.
package/dist/index.d.mts CHANGED
@@ -4,6 +4,71 @@ import { DocumentNode } from "graphql";
4
4
  import { Result } from "neverthrow";
5
5
  import { ResolvedSodaGqlConfig } from "@soda-gql/config";
6
6
 
7
+ //#region packages/typegen/src/errors.d.ts
8
+
9
+ /**
10
+ * Error codes specific to typegen operations.
11
+ */
12
+ type TypegenErrorCode = "TYPEGEN_CODEGEN_REQUIRED" | "TYPEGEN_SCHEMA_LOAD_FAILED" | "TYPEGEN_BUILD_FAILED" | "TYPEGEN_EMIT_FAILED" | "TYPEGEN_BUNDLE_FAILED" | "TYPEGEN_FRAGMENT_MISSING_KEY";
13
+ /**
14
+ * Typegen-specific error type.
15
+ */
16
+ type TypegenSpecificError = {
17
+ readonly code: "TYPEGEN_CODEGEN_REQUIRED";
18
+ readonly message: string;
19
+ readonly outdir: string;
20
+ } | {
21
+ readonly code: "TYPEGEN_SCHEMA_LOAD_FAILED";
22
+ readonly message: string;
23
+ readonly schemaNames: readonly string[];
24
+ readonly cause?: unknown;
25
+ } | {
26
+ readonly code: "TYPEGEN_BUILD_FAILED";
27
+ readonly message: string;
28
+ readonly cause?: unknown;
29
+ } | {
30
+ readonly code: "TYPEGEN_EMIT_FAILED";
31
+ readonly message: string;
32
+ readonly path: string;
33
+ readonly cause?: unknown;
34
+ } | {
35
+ readonly code: "TYPEGEN_BUNDLE_FAILED";
36
+ readonly message: string;
37
+ readonly path: string;
38
+ readonly cause?: unknown;
39
+ } | {
40
+ readonly code: "TYPEGEN_FRAGMENT_MISSING_KEY";
41
+ readonly message: string;
42
+ readonly fragments: readonly {
43
+ readonly canonicalId: string;
44
+ readonly typename: string;
45
+ readonly schemaLabel: string;
46
+ }[];
47
+ };
48
+ /**
49
+ * Union of all typegen errors (specific + builder errors).
50
+ */
51
+ type TypegenError = TypegenSpecificError | BuilderError;
52
+ /**
53
+ * Error constructor helpers for concise error creation.
54
+ */
55
+ declare const typegenErrors: {
56
+ readonly codegenRequired: (outdir: string) => TypegenSpecificError;
57
+ readonly schemaLoadFailed: (schemaNames: readonly string[], cause?: unknown) => TypegenSpecificError;
58
+ readonly buildFailed: (message: string, cause?: unknown) => TypegenSpecificError;
59
+ readonly emitFailed: (path: string, message: string, cause?: unknown) => TypegenSpecificError;
60
+ readonly bundleFailed: (path: string, message: string, cause?: unknown) => TypegenSpecificError;
61
+ readonly fragmentMissingKey: (fragments: readonly {
62
+ canonicalId: string;
63
+ typename: string;
64
+ schemaLabel: string;
65
+ }[]) => TypegenSpecificError;
66
+ };
67
+ /**
68
+ * Format TypegenError for console output (human-readable).
69
+ */
70
+ declare const formatTypegenError: (error: TypegenError) => string;
71
+ //#endregion
7
72
  //#region packages/typegen/src/emitter.d.ts
8
73
 
9
74
  /**
@@ -25,12 +90,10 @@ type PrebuiltTypesEmitterOptions = {
25
90
  */
26
91
  readonly outdir: string;
27
92
  /**
28
- * Inject configuration per schema.
29
- * Maps schema name to inject file paths (absolute paths).
93
+ * Relative import path to _internal-injects.ts from types.prebuilt.ts.
94
+ * Example: "./_internal-injects"
30
95
  */
31
- readonly injects: Record<string, {
32
- readonly scalars: string;
33
- }>;
96
+ readonly injectsModulePath: string;
34
97
  };
35
98
  /**
36
99
  * Result of emitting prebuilt types.
@@ -68,85 +131,41 @@ type PrebuiltTypesEmitResult = {
68
131
  * }
69
132
  * ```
70
133
  */
71
- declare const emitPrebuiltTypes: (options: PrebuiltTypesEmitterOptions) => Promise<Result<PrebuiltTypesEmitResult, BuilderError>>;
72
- //#endregion
73
- //#region packages/typegen/src/errors.d.ts
74
- /**
75
- * Error codes specific to typegen operations.
76
- */
77
- type TypegenErrorCode = "TYPEGEN_CODEGEN_REQUIRED" | "TYPEGEN_SCHEMA_LOAD_FAILED" | "TYPEGEN_BUILD_FAILED" | "TYPEGEN_EMIT_FAILED" | "TYPEGEN_BUNDLE_FAILED";
78
- /**
79
- * Typegen-specific error type.
80
- */
81
- type TypegenSpecificError = {
82
- readonly code: "TYPEGEN_CODEGEN_REQUIRED";
83
- readonly message: string;
84
- readonly outdir: string;
85
- } | {
86
- readonly code: "TYPEGEN_SCHEMA_LOAD_FAILED";
87
- readonly message: string;
88
- readonly schemaNames: readonly string[];
89
- readonly cause?: unknown;
90
- } | {
91
- readonly code: "TYPEGEN_BUILD_FAILED";
92
- readonly message: string;
93
- readonly cause?: unknown;
94
- } | {
95
- readonly code: "TYPEGEN_EMIT_FAILED";
96
- readonly message: string;
97
- readonly path: string;
98
- readonly cause?: unknown;
99
- } | {
100
- readonly code: "TYPEGEN_BUNDLE_FAILED";
101
- readonly message: string;
102
- readonly path: string;
103
- readonly cause?: unknown;
104
- };
105
- /**
106
- * Union of all typegen errors (specific + builder errors).
107
- */
108
- type TypegenError = TypegenSpecificError | BuilderError;
109
- /**
110
- * Error constructor helpers for concise error creation.
111
- */
112
- declare const typegenErrors: {
113
- readonly codegenRequired: (outdir: string) => TypegenSpecificError;
114
- readonly schemaLoadFailed: (schemaNames: readonly string[], cause?: unknown) => TypegenSpecificError;
115
- readonly buildFailed: (message: string, cause?: unknown) => TypegenSpecificError;
116
- readonly emitFailed: (path: string, message: string, cause?: unknown) => TypegenSpecificError;
117
- readonly bundleFailed: (path: string, message: string, cause?: unknown) => TypegenSpecificError;
118
- };
119
- /**
120
- * Format TypegenError for console output (human-readable).
121
- */
122
- declare const formatTypegenError: (error: TypegenError) => string;
134
+ declare const emitPrebuiltTypes: (options: PrebuiltTypesEmitterOptions) => Promise<Result<PrebuiltTypesEmitResult, BuilderError | TypegenError>>;
123
135
  //#endregion
124
136
  //#region packages/typegen/src/prebuilt-generator.d.ts
125
137
  type PrebuiltGeneratorOptions = {
126
138
  /**
127
- * Relative import path to the main gql module.
128
- * Example: "../index" (from prebuilt/index.ts to index.ts)
139
+ * Relative import path to the internal module.
140
+ * Example: "./_internal" (from index.prebuilt.ts to _internal.ts)
141
+ */
142
+ readonly internalModulePath: string;
143
+ /**
144
+ * Relative import path to the injects module.
145
+ * Example: "./_internal-injects" (from index.prebuilt.ts to _internal-injects.ts)
129
146
  */
130
- readonly mainModulePath: string;
147
+ readonly injectsModulePath: string;
131
148
  /**
132
- * Per-schema injection config (adapter import paths).
149
+ * Per-schema injection config.
150
+ * Maps schema name to whether it has an adapter.
133
151
  */
134
152
  readonly injection?: Map<string, {
135
- readonly adapterImportPath?: string;
153
+ readonly hasAdapter?: boolean;
136
154
  }>;
137
155
  };
138
156
  type PrebuiltGeneratedModule = {
139
- /** The generated code for prebuilt/index.ts */
157
+ /** The generated code for index.prebuilt.ts */
140
158
  readonly indexCode: string;
141
- /** The generated code for prebuilt/types.ts (placeholder) */
142
- readonly typesCode: string;
143
159
  };
144
160
  /**
145
- * Generate the prebuilt module code.
161
+ * Generate the prebuilt index module code.
146
162
  *
147
- * This generates:
148
- * - prebuilt/index.ts: Uses createPrebuiltGqlElementComposer with types from PrebuiltTypes
149
- * - prebuilt/types.ts: Placeholder types that typegen will populate
163
+ * Generates index.prebuilt.ts with prebuilt gql composers using
164
+ * createPrebuiltGqlElementComposer. The generated module uses
165
+ * lightweight imports for type serialization compatibility:
166
+ * - Adapters from _internal-injects.ts
167
+ * - Runtime values from _internal.ts
168
+ * - AnyGqlContext instead of heavy Context type inference
150
169
  */
151
170
  declare const generatePrebuiltModule: (schemas: Map<string, DocumentNode>, options: PrebuiltGeneratorOptions) => PrebuiltGeneratedModule;
152
171
  //#endregion
@@ -221,10 +240,10 @@ type RunTypegenOptions = {
221
240
  *
222
241
  * This function:
223
242
  * 1. Loads schemas from the generated CJS bundle
224
- * 2. Generates prebuilt/index.ts using generatePrebuiltModule
243
+ * 2. Generates index.prebuilt.ts using generatePrebuiltModule
225
244
  * 3. Creates a BuilderService and builds the artifact
226
245
  * 4. Extracts field selections from the artifact
227
- * 5. Emits prebuilt/types.ts using emitPrebuiltTypes
246
+ * 5. Emits types.prebuilt.ts using emitPrebuiltTypes
228
247
  * 6. Bundles the prebuilt module
229
248
  *
230
249
  * @param options - Typegen options including config
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/emitter.ts","../src/errors.ts","../src/prebuilt-generator.ts","../src/types.ts","../src/runner.ts"],"sourcesContent":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/errors.ts","../src/emitter.ts","../src/prebuilt-generator.ts","../src/types.ts","../src/runner.ts"],"sourcesContent":[],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -7,6 +7,78 @@ import { err, ok } from "neverthrow";
7
7
  import { existsSync, readFileSync } from "node:fs";
8
8
  import { build } from "esbuild";
9
9
 
10
+ //#region packages/typegen/src/errors.ts
11
+ /**
12
+ * Error constructor helpers for concise error creation.
13
+ */
14
+ const typegenErrors = {
15
+ codegenRequired: (outdir) => ({
16
+ code: "TYPEGEN_CODEGEN_REQUIRED",
17
+ message: `Generated graphql-system module not found at '${outdir}'. Run 'soda-gql codegen' first.`,
18
+ outdir
19
+ }),
20
+ schemaLoadFailed: (schemaNames, cause) => ({
21
+ code: "TYPEGEN_SCHEMA_LOAD_FAILED",
22
+ message: `Failed to load schemas: ${schemaNames.join(", ")}`,
23
+ schemaNames,
24
+ cause
25
+ }),
26
+ buildFailed: (message, cause) => ({
27
+ code: "TYPEGEN_BUILD_FAILED",
28
+ message,
29
+ cause
30
+ }),
31
+ emitFailed: (path, message, cause) => ({
32
+ code: "TYPEGEN_EMIT_FAILED",
33
+ message,
34
+ path,
35
+ cause
36
+ }),
37
+ bundleFailed: (path, message, cause) => ({
38
+ code: "TYPEGEN_BUNDLE_FAILED",
39
+ message,
40
+ path,
41
+ cause
42
+ }),
43
+ fragmentMissingKey: (fragments) => ({
44
+ code: "TYPEGEN_FRAGMENT_MISSING_KEY",
45
+ message: `${fragments.length} fragment(s) missing required 'key' property for prebuilt types`,
46
+ fragments
47
+ })
48
+ };
49
+ /**
50
+ * Format TypegenError for console output (human-readable).
51
+ */
52
+ const formatTypegenError = (error) => {
53
+ const lines = [];
54
+ lines.push(`Error [${error.code}]: ${error.message}`);
55
+ switch (error.code) {
56
+ case "TYPEGEN_CODEGEN_REQUIRED":
57
+ lines.push(` Output directory: ${error.outdir}`);
58
+ lines.push(" Hint: Run 'soda-gql codegen' to generate the graphql-system module first.");
59
+ break;
60
+ case "TYPEGEN_SCHEMA_LOAD_FAILED":
61
+ lines.push(` Schemas: ${error.schemaNames.join(", ")}`);
62
+ break;
63
+ case "TYPEGEN_EMIT_FAILED":
64
+ case "TYPEGEN_BUNDLE_FAILED":
65
+ lines.push(` Path: ${error.path}`);
66
+ break;
67
+ case "TYPEGEN_FRAGMENT_MISSING_KEY":
68
+ lines.push(" Fragments missing 'key' property:");
69
+ for (const fragment of error.fragments) {
70
+ lines.push(` - ${fragment.canonicalId} (${fragment.typename} on ${fragment.schemaLabel})`);
71
+ }
72
+ lines.push(" Hint: Add a 'key' property to each fragment for prebuilt type resolution.");
73
+ break;
74
+ }
75
+ if ("cause" in error && error.cause) {
76
+ lines.push(` Caused by: ${error.cause}`);
77
+ }
78
+ return lines.join("\n");
79
+ };
80
+
81
+ //#endregion
10
82
  //#region packages/typegen/src/emitter.ts
11
83
  /**
12
84
  * Prebuilt types emitter.
@@ -36,11 +108,16 @@ import { build } from "esbuild";
36
108
  * Group field selections by schema.
37
109
  * Uses the schemaLabel from each selection to group them correctly.
38
110
  *
111
+ * In strict mode, all fragments must have a 'key' property. Fragments
112
+ * without keys will cause an error.
113
+ *
39
114
  * @returns Result containing grouped selections and warnings, or error if schema not found
115
+ * or fragments are missing keys
40
116
  */
41
117
  const groupBySchema = (fieldSelections, schemas) => {
42
118
  const grouped = new Map();
43
119
  const warnings = [];
120
+ const missingKeyFragments = [];
44
121
  for (const schemaName of Object.keys(schemas)) {
45
122
  grouped.set(schemaName, {
46
123
  fragments: [],
@@ -62,6 +139,11 @@ const groupBySchema = (fieldSelections, schemas) => {
62
139
  };
63
140
  if (selection.type === "fragment") {
64
141
  if (!selection.key) {
142
+ missingKeyFragments.push({
143
+ canonicalId,
144
+ typename: selection.typename,
145
+ schemaLabel: selection.schemaLabel
146
+ });
65
147
  continue;
66
148
  }
67
149
  try {
@@ -98,23 +180,15 @@ const groupBySchema = (fieldSelections, schemas) => {
98
180
  }
99
181
  }
100
182
  }
183
+ if (missingKeyFragments.length > 0) {
184
+ return err(typegenErrors.fragmentMissingKey(missingKeyFragments));
185
+ }
101
186
  return ok({
102
187
  grouped,
103
188
  warnings
104
189
  });
105
190
  };
106
191
  /**
107
- * Calculate relative import path from one file to another.
108
- */
109
- const toImportSpecifier$1 = (from, to) => {
110
- const fromDir = dirname(from);
111
- let relativePath = relative(fromDir, to);
112
- if (!relativePath.startsWith(".")) {
113
- relativePath = `./${relativePath}`;
114
- }
115
- return relativePath.replace(/\.ts$/, "");
116
- };
117
- /**
118
192
  * Extract input object names from a GraphQL TypeNode.
119
193
  */
120
194
  const extractInputObjectsFromType = (schema, typeNode, inputObjects) => {
@@ -210,8 +284,8 @@ const generateInputObjectTypeDefinitions = (schema, schemaName, inputNames) => {
210
284
  /**
211
285
  * Generate the TypeScript code for prebuilt types.
212
286
  */
213
- const generateTypesCode = (grouped, schemas, injects, outdir) => {
214
- const typesFilePath = join(outdir, "prebuilt", "types.ts");
287
+ const generateTypesCode = (grouped, schemas, injectsModulePath) => {
288
+ const schemaNames = Object.keys(schemas);
215
289
  const lines = [
216
290
  "/**",
217
291
  " * Prebuilt type registry.",
@@ -225,12 +299,10 @@ const generateTypesCode = (grouped, schemas, injects, outdir) => {
225
299
  "",
226
300
  "import type { PrebuiltTypeRegistry } from \"@soda-gql/core\";"
227
301
  ];
228
- for (const [schemaName, inject] of Object.entries(injects)) {
229
- const relativePath = toImportSpecifier$1(typesFilePath, inject.scalars);
230
- lines.push(`import type { scalar as scalar_${schemaName} } from "${relativePath}";`);
231
- }
302
+ const scalarImports = schemaNames.map((name) => `scalar_${name}`).join(", ");
303
+ lines.push(`import type { ${scalarImports} } from "${injectsModulePath}";`);
232
304
  lines.push("");
233
- for (const schemaName of Object.keys(injects)) {
305
+ for (const schemaName of schemaNames) {
234
306
  lines.push(`type ScalarInput_${schemaName}<T extends keyof typeof scalar_${schemaName}> = ` + `typeof scalar_${schemaName}[T]["$type"]["input"];`);
235
307
  lines.push(`type ScalarOutput_${schemaName}<T extends keyof typeof scalar_${schemaName}> = ` + `typeof scalar_${schemaName}[T]["$type"]["output"];`);
236
308
  }
@@ -291,14 +363,14 @@ const generateTypesCode = (grouped, schemas, injects, outdir) => {
291
363
  * ```
292
364
  */
293
365
  const emitPrebuiltTypes = async (options) => {
294
- const { schemas, fieldSelections, outdir, injects } = options;
366
+ const { schemas, fieldSelections, outdir, injectsModulePath } = options;
295
367
  const groupResult = groupBySchema(fieldSelections, schemas);
296
368
  if (groupResult.isErr()) {
297
369
  return err(groupResult.error);
298
370
  }
299
371
  const { grouped, warnings } = groupResult.value;
300
- const code = generateTypesCode(grouped, schemas, injects, outdir);
301
- const typesPath = join(outdir, "prebuilt", "types.ts");
372
+ const code = generateTypesCode(grouped, schemas, injectsModulePath);
373
+ const typesPath = join(outdir, "types.prebuilt.ts");
302
374
  try {
303
375
  await writeFile(typesPath, code, "utf-8");
304
376
  return ok({
@@ -310,143 +382,91 @@ const emitPrebuiltTypes = async (options) => {
310
382
  }
311
383
  };
312
384
 
313
- //#endregion
314
- //#region packages/typegen/src/errors.ts
315
- /**
316
- * Error constructor helpers for concise error creation.
317
- */
318
- const typegenErrors = {
319
- codegenRequired: (outdir) => ({
320
- code: "TYPEGEN_CODEGEN_REQUIRED",
321
- message: `Generated graphql-system module not found at '${outdir}'. Run 'soda-gql codegen' first.`,
322
- outdir
323
- }),
324
- schemaLoadFailed: (schemaNames, cause) => ({
325
- code: "TYPEGEN_SCHEMA_LOAD_FAILED",
326
- message: `Failed to load schemas: ${schemaNames.join(", ")}`,
327
- schemaNames,
328
- cause
329
- }),
330
- buildFailed: (message, cause) => ({
331
- code: "TYPEGEN_BUILD_FAILED",
332
- message,
333
- cause
334
- }),
335
- emitFailed: (path, message, cause) => ({
336
- code: "TYPEGEN_EMIT_FAILED",
337
- message,
338
- path,
339
- cause
340
- }),
341
- bundleFailed: (path, message, cause) => ({
342
- code: "TYPEGEN_BUNDLE_FAILED",
343
- message,
344
- path,
345
- cause
346
- })
347
- };
348
- /**
349
- * Format TypegenError for console output (human-readable).
350
- */
351
- const formatTypegenError = (error) => {
352
- const lines = [];
353
- lines.push(`Error [${error.code}]: ${error.message}`);
354
- switch (error.code) {
355
- case "TYPEGEN_CODEGEN_REQUIRED":
356
- lines.push(` Output directory: ${error.outdir}`);
357
- lines.push(" Hint: Run 'soda-gql codegen' to generate the graphql-system module first.");
358
- break;
359
- case "TYPEGEN_SCHEMA_LOAD_FAILED":
360
- lines.push(` Schemas: ${error.schemaNames.join(", ")}`);
361
- break;
362
- case "TYPEGEN_EMIT_FAILED":
363
- case "TYPEGEN_BUNDLE_FAILED":
364
- lines.push(` Path: ${error.path}`);
365
- break;
366
- }
367
- if ("cause" in error && error.cause) {
368
- lines.push(` Caused by: ${error.cause}`);
369
- }
370
- return lines.join("\n");
371
- };
372
-
373
385
  //#endregion
374
386
  //#region packages/typegen/src/prebuilt-generator.ts
375
387
  /**
376
- * Generate the prebuilt module code.
388
+ * Generate the prebuilt index module code.
377
389
  *
378
- * This generates:
379
- * - prebuilt/index.ts: Uses createPrebuiltGqlElementComposer with types from PrebuiltTypes
380
- * - prebuilt/types.ts: Placeholder types that typegen will populate
390
+ * Generates index.prebuilt.ts with prebuilt gql composers using
391
+ * createPrebuiltGqlElementComposer. The generated module uses
392
+ * lightweight imports for type serialization compatibility:
393
+ * - Adapters from _internal-injects.ts
394
+ * - Runtime values from _internal.ts
395
+ * - AnyGqlContext instead of heavy Context type inference
381
396
  */
382
397
  const generatePrebuiltModule = (schemas, options) => {
383
398
  const schemaNames = Array.from(schemas.keys());
384
- const typeImports = [];
385
- const runtimeImports = [];
386
- for (const name of schemaNames) {
387
- typeImports.push(`Schema_${name}`, `FragmentBuilders_${name}`, `Context_${name}`);
388
- runtimeImports.push(`__schema_${name}`, `__inputTypeMethods_${name}`, `__directiveMethods_${name}`);
389
- const hasAdapter = options.injection?.get(name)?.adapterImportPath !== undefined;
390
- if (hasAdapter) {
391
- typeImports.push(`Adapter_${name}`);
392
- runtimeImports.push(`__adapter_${name}`);
393
- }
394
- }
395
- const gqlEntries = [];
399
+ const injection = options.injection ?? new Map();
400
+ const adapterImports = [];
396
401
  for (const name of schemaNames) {
397
- const document = schemas.get(name);
398
- if (!document) continue;
399
- const hasAdapter = options.injection?.get(name)?.adapterImportPath !== undefined;
400
- if (hasAdapter) {
401
- gqlEntries.push(` ${name}: createPrebuiltGqlElementComposer<Schema_${name}, PrebuiltTypes_${name}, FragmentBuilders_${name}, typeof __directiveMethods_${name}, Context_${name}, Adapter_${name}>(__schema_${name}, { adapter: __adapter_${name}, inputTypeMethods: __inputTypeMethods_${name}, directiveMethods: __directiveMethods_${name} })`);
402
- } else {
403
- gqlEntries.push(` ${name}: createPrebuiltGqlElementComposer<Schema_${name}, PrebuiltTypes_${name}, FragmentBuilders_${name}, typeof __directiveMethods_${name}, Context_${name}>(__schema_${name}, { inputTypeMethods: __inputTypeMethods_${name}, directiveMethods: __directiveMethods_${name} })`);
402
+ const config = injection.get(name);
403
+ if (config?.hasAdapter) {
404
+ adapterImports.push(`adapter_${name}`);
404
405
  }
405
406
  }
407
+ const internalImports = schemaNames.flatMap((name) => [
408
+ `__schema_${name}`,
409
+ `__inputTypeMethods_${name}`,
410
+ `__directiveMethods_${name}`
411
+ ]);
412
+ const gqlEntries = schemaNames.map((name) => {
413
+ const config = injection.get(name);
414
+ const adapterArg = config?.hasAdapter ? `adapter: adapter_${name},` : "";
415
+ return ` ${name}: createPrebuiltGqlElementComposer<
416
+ AnyGraphqlSchema,
417
+ PrebuiltTypes_${name},
418
+ Record<string, unknown>,
419
+ StandardDirectives,
420
+ AnyGqlContext
421
+ >(
422
+ __schema_${name} as AnyGraphqlSchema,
423
+ {
424
+ inputTypeMethods: __inputTypeMethods_${name},
425
+ directiveMethods: __directiveMethods_${name},
426
+ ${adapterArg}
427
+ }
428
+ )`;
429
+ });
430
+ const injectsImportSpecifiers = adapterImports.length > 0 ? adapterImports.join(", ") : "";
431
+ const injectsImportLine = injectsImportSpecifiers ? `import { ${injectsImportSpecifiers} } from "${options.injectsModulePath}";` : "";
406
432
  const indexCode = `\
407
433
  /**
408
434
  * Prebuilt GQL module for bundler-compatible type resolution.
409
435
  *
410
- * This module uses createPrebuiltGqlElementComposer which looks up types
411
- * from PrebuiltTypes instead of using complex type inference.
436
+ * This module creates prebuilt composers using createPrebuiltGqlElementComposer
437
+ * that look up types from PrebuiltTypes instead of complex inference.
438
+ *
439
+ * Uses lightweight imports:
440
+ * - Adapters from _internal-injects.ts
441
+ * - Runtime values from _internal.ts
442
+ * - AnyGqlContext instead of heavy Context type inference
412
443
  *
413
444
  * @module
414
445
  * @generated by @soda-gql/typegen
415
446
  */
416
447
 
417
- import { createPrebuiltGqlElementComposer } from "@soda-gql/core";
418
448
  import {
419
- ${runtimeImports.join(",\n ")},
420
- type ${typeImports.join(",\n type ")},
421
- } from "${options.mainModulePath}";
422
- import type { ${schemaNames.map((name) => `PrebuiltTypes_${name}`).join(", ")} } from "./types";
423
-
424
- export const gql = {
425
- ${gqlEntries.join(",\n")}
426
- };
449
+ createPrebuiltGqlElementComposer,
450
+ type AnyGqlContext,
451
+ type AnyGraphqlSchema,
452
+ type StandardDirectives,
453
+ } from "@soda-gql/core";
454
+ ${injectsImportLine}
455
+ import { ${internalImports.join(", ")} } from "${options.internalModulePath}";
456
+ import type { ${schemaNames.map((name) => `PrebuiltTypes_${name}`).join(", ")} } from "./types.prebuilt";
427
457
 
428
- // Re-export types from main module
429
- export type { ${typeImports.join(", ")} };
430
- `;
431
- const typesCode = `\
432
458
  /**
433
- * Prebuilt type registry.
434
- *
435
- * This file contains placeholder types that will be populated by typegen
436
- * when running \`soda-gql typegen\` command.
459
+ * Prebuilt GQL composers with strict type resolution from PrebuiltTypeRegistry.
437
460
  *
438
- * @module
439
- * @generated by @soda-gql/typegen
461
+ * These composers have the same runtime behavior as the base composers,
462
+ * but their return types are resolved from the prebuilt type registry
463
+ * instead of using complex type inference.
440
464
  */
441
-
442
- import type { EmptyPrebuiltTypeRegistry } from "@soda-gql/core";
443
-
444
- ${schemaNames.map((name) => `// Placeholder for ${name} schema - populated by typegen\nexport type PrebuiltTypes_${name} = EmptyPrebuiltTypeRegistry;`).join("\n\n")}
465
+ export const gql = {
466
+ ${gqlEntries.join(",\n")}
467
+ };
445
468
  `;
446
- return {
447
- indexCode,
448
- typesCode
449
- };
469
+ return { indexCode };
450
470
  };
451
471
 
452
472
  //#endregion
@@ -456,10 +476,10 @@ ${schemaNames.map((name) => `// Placeholder for ${name} schema - populated by ty
456
476
  *
457
477
  * Orchestrates the prebuilt type generation process:
458
478
  * 1. Load schemas from generated CJS bundle
459
- * 2. Generate prebuilt/index.ts
479
+ * 2. Generate index.prebuilt.ts
460
480
  * 3. Build artifact to evaluate elements
461
481
  * 4. Extract field selections
462
- * 5. Emit prebuilt/types.ts
482
+ * 5. Emit types.prebuilt.ts
463
483
  * 6. Bundle prebuilt module
464
484
  *
465
485
  * @module
@@ -549,10 +569,10 @@ const loadSchemaDocuments = (schemasConfig) => {
549
569
  *
550
570
  * This function:
551
571
  * 1. Loads schemas from the generated CJS bundle
552
- * 2. Generates prebuilt/index.ts using generatePrebuiltModule
572
+ * 2. Generates index.prebuilt.ts using generatePrebuiltModule
553
573
  * 3. Creates a BuilderService and builds the artifact
554
574
  * 4. Extracts field selections from the artifact
555
- * 5. Emits prebuilt/types.ts using emitPrebuiltTypes
575
+ * 5. Emits types.prebuilt.ts using emitPrebuiltTypes
556
576
  * 6. Bundles the prebuilt module
557
577
  *
558
578
  * @param options - Typegen options including config
@@ -572,23 +592,19 @@ const runTypegen = async (options) => {
572
592
  return err(typegenErrors.schemaLoadFailed(schemaNames, schemasResult.error));
573
593
  }
574
594
  const schemas = schemasResult.value;
575
- const prebuiltDir = join(outdir, "prebuilt");
576
- await mkdir(prebuiltDir, { recursive: true });
577
595
  const schemaDocuments = loadSchemaDocuments(config.schemas);
578
- const mainModulePath = toImportSpecifier(join(prebuiltDir, "index.ts"), join(outdir, "index.ts"), importSpecifierOptions);
596
+ const prebuiltIndexPath = join(outdir, "index.prebuilt.ts");
597
+ const internalModulePath = toImportSpecifier(prebuiltIndexPath, join(outdir, "_internal.ts"), importSpecifierOptions);
598
+ const injectsModulePath = toImportSpecifier(prebuiltIndexPath, join(outdir, "_internal-injects.ts"), importSpecifierOptions);
579
599
  const injection = new Map();
580
600
  for (const [schemaName, schemaConfig] of Object.entries(config.schemas)) {
581
- if (schemaConfig.inject.adapter) {
582
- injection.set(schemaName, { adapterImportPath: toImportSpecifier(join(outdir, "index.ts"), schemaConfig.inject.adapter, importSpecifierOptions) });
583
- } else {
584
- injection.set(schemaName, {});
585
- }
601
+ injection.set(schemaName, { hasAdapter: !!schemaConfig.inject.adapter });
586
602
  }
587
603
  const prebuilt = generatePrebuiltModule(schemaDocuments, {
588
- mainModulePath,
604
+ internalModulePath,
605
+ injectsModulePath,
589
606
  injection
590
607
  });
591
- const prebuiltIndexPath = join(prebuiltDir, "index.ts");
592
608
  try {
593
609
  await writeModule(prebuiltIndexPath, prebuilt.indexCode);
594
610
  } catch (error) {
@@ -605,15 +621,11 @@ const runTypegen = async (options) => {
605
621
  }
606
622
  const fieldSelectionsResult = extractFieldSelections(intermediateElements);
607
623
  const { selections: fieldSelections, warnings: extractWarnings } = fieldSelectionsResult;
608
- const injects = {};
609
- for (const [schemaName, schemaConfig] of Object.entries(config.schemas)) {
610
- injects[schemaName] = { scalars: schemaConfig.inject.scalars };
611
- }
612
624
  const emitResult = await emitPrebuiltTypes({
613
625
  schemas,
614
626
  fieldSelections,
615
627
  outdir,
616
- injects
628
+ injectsModulePath
617
629
  });
618
630
  if (emitResult.isErr()) {
619
631
  return err(emitResult.error);