nitro-graphql 2.0.0-beta.31 → 2.0.0-beta.33

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 (86) hide show
  1. package/dist/codegen/client-types.d.mts +13 -0
  2. package/dist/codegen/client-types.mjs +131 -0
  3. package/dist/codegen/external-types.d.mts +12 -0
  4. package/dist/codegen/external-types.mjs +88 -0
  5. package/dist/codegen/index.d.mts +18 -0
  6. package/dist/codegen/index.mjs +24 -0
  7. package/dist/codegen/server-types.d.mts +13 -0
  8. package/dist/codegen/server-types.mjs +64 -0
  9. package/dist/codegen/validation.d.mts +13 -0
  10. package/dist/codegen/validation.mjs +96 -0
  11. package/dist/config/defaults.mjs +36 -0
  12. package/dist/constants/scalars.mjs +27 -0
  13. package/dist/constants.mjs +106 -0
  14. package/dist/ecosystem/nuxt.mjs +3 -3
  15. package/dist/rollup.d.mts +2 -8
  16. package/dist/rollup.mjs +24 -199
  17. package/dist/routes/apollo-server.d.mts +2 -2
  18. package/dist/routes/apollo-server.mjs +7 -51
  19. package/dist/routes/debug-template.d.mts +15 -0
  20. package/dist/routes/debug-template.mjs +385 -0
  21. package/dist/routes/debug.d.mts +2 -2
  22. package/dist/routes/debug.mjs +1 -344
  23. package/dist/routes/graphql-yoga.d.mts +2 -2
  24. package/dist/routes/graphql-yoga.mjs +7 -51
  25. package/dist/routes/health.d.mts +2 -2
  26. package/dist/setup/file-watcher.mjs +84 -0
  27. package/dist/setup/graphql-scanner.mjs +25 -0
  28. package/dist/setup/rollup-integration.mjs +90 -0
  29. package/dist/setup/scaffold-generator.mjs +109 -0
  30. package/dist/setup/ts-config.mjs +69 -0
  31. package/dist/setup.d.mts +2 -2
  32. package/dist/setup.mjs +147 -303
  33. package/dist/types/index.d.mts +2 -2
  34. package/dist/utils/client-codegen.d.mts +1 -1
  35. package/dist/utils/client-codegen.mjs +5 -28
  36. package/dist/utils/codegen-plugin.d.mts +20 -0
  37. package/dist/utils/codegen-plugin.mjs +30 -0
  38. package/dist/utils/directive-parser.d.mts +2 -1
  39. package/dist/utils/directive-parser.mjs +4 -2
  40. package/dist/utils/federation.d.mts +29 -0
  41. package/dist/utils/federation.mjs +40 -0
  42. package/dist/utils/file-generator.mjs +1 -1
  43. package/dist/utils/file-writer.d.mts +35 -0
  44. package/dist/utils/file-writer.mjs +32 -0
  45. package/dist/utils/imports.d.mts +15 -0
  46. package/dist/utils/imports.mjs +25 -0
  47. package/dist/utils/index.d.mts +11 -38
  48. package/dist/utils/index.mjs +10 -287
  49. package/dist/utils/layers.d.mts +22 -0
  50. package/dist/utils/layers.mjs +28 -0
  51. package/dist/utils/ofetch-templates.d.mts +30 -0
  52. package/dist/utils/ofetch-templates.mjs +135 -0
  53. package/dist/utils/path-resolver.d.mts +2 -2
  54. package/dist/utils/path-resolver.mjs +2 -2
  55. package/dist/utils/scanning/common.d.mts +23 -0
  56. package/dist/utils/scanning/common.mjs +39 -0
  57. package/dist/utils/scanning/directives.d.mts +11 -0
  58. package/dist/utils/scanning/directives.mjs +43 -0
  59. package/dist/utils/scanning/documents.d.mts +15 -0
  60. package/dist/utils/scanning/documents.mjs +46 -0
  61. package/dist/utils/scanning/index.d.mts +6 -0
  62. package/dist/utils/scanning/index.mjs +7 -0
  63. package/dist/utils/scanning/resolvers.d.mts +11 -0
  64. package/dist/utils/scanning/resolvers.mjs +100 -0
  65. package/dist/utils/scanning/schemas.d.mts +15 -0
  66. package/dist/utils/scanning/schemas.mjs +29 -0
  67. package/dist/utils/schema-builder.d.mts +48 -0
  68. package/dist/utils/schema-builder.mjs +51 -0
  69. package/dist/utils/server-codegen.mjs +4 -27
  70. package/dist/utils/type-generation.d.mts +6 -12
  71. package/dist/utils/type-generation.mjs +6 -419
  72. package/dist/utils/validation.d.mts +11 -0
  73. package/dist/utils/validation.mjs +34 -0
  74. package/dist/virtual/generators/config.d.mts +22 -0
  75. package/dist/virtual/generators/config.mjs +36 -0
  76. package/dist/virtual/generators/debug.d.mts +14 -0
  77. package/dist/virtual/generators/debug.mjs +53 -0
  78. package/dist/virtual/generators/directives.d.mts +14 -0
  79. package/dist/virtual/generators/directives.mjs +52 -0
  80. package/dist/virtual/generators/index.d.mts +6 -0
  81. package/dist/virtual/generators/index.mjs +7 -0
  82. package/dist/virtual/generators/resolvers.d.mts +14 -0
  83. package/dist/virtual/generators/resolvers.mjs +55 -0
  84. package/dist/virtual/generators/schemas.d.mts +14 -0
  85. package/dist/virtual/generators/schemas.mjs +43 -0
  86. package/package.json +75 -57
@@ -1,12 +1,6 @@
1
- import { Nitro } from "nitro/types";
2
-
3
- //#region src/utils/type-generation.d.ts
4
- declare function serverTypeGeneration(app: Nitro, options?: {
5
- silent?: boolean;
6
- }): Promise<void>;
7
- declare function clientTypeGeneration(nitro: Nitro, options?: {
8
- silent?: boolean;
9
- isInitial?: boolean;
10
- }): Promise<void>;
11
- //#endregion
12
- export { clientTypeGeneration, serverTypeGeneration };
1
+ import { generateMainClientTypes } from "../codegen/client-types.mjs";
2
+ import { generateExternalServicesTypes } from "../codegen/external-types.mjs";
3
+ import { generateServerTypes } from "../codegen/server-types.mjs";
4
+ import { validateNoDuplicateTypes } from "../codegen/validation.mjs";
5
+ import { generateClientTypes } from "../codegen/index.mjs";
6
+ export { generateClientTypes, generateExternalServicesTypes, generateMainClientTypes, generateServerTypes, validateNoDuplicateTypes };
@@ -1,420 +1,7 @@
1
- import { downloadAndSaveSchema, generateClientTypes, generateExternalClientTypes, loadExternalSchema, loadGraphQLDocuments } from "./client-codegen.mjs";
2
- import { writeFileIfNotExists } from "./file-generator.mjs";
3
- import { getClientUtilsConfig, getDefaultPaths, getSdkConfig, getTypesConfig, resolveFilePath, shouldGenerateClientUtils, shouldGenerateTypes } from "./path-resolver.mjs";
4
- import { generateTypes } from "./server-codegen.mjs";
5
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
6
- import consola from "consola";
7
- import { basename, dirname, join, resolve } from "pathe";
8
- import { buildSchema, parse } from "graphql";
9
- import { loadFilesSync } from "@graphql-tools/load-files";
10
- import { mergeTypeDefs } from "@graphql-tools/merge";
11
- import { printSchemaWithDirectives } from "@graphql-tools/utils";
1
+ import { generateMainClientTypes } from "../codegen/client-types.mjs";
2
+ import { generateExternalServicesTypes } from "../codegen/external-types.mjs";
3
+ import { validateNoDuplicateTypes } from "../codegen/validation.mjs";
4
+ import { generateServerTypes } from "../codegen/server-types.mjs";
5
+ import { generateClientTypes } from "../codegen/index.mjs";
12
6
 
13
- //#region src/utils/type-generation.ts
14
- const logger = consola.withTag("nitro-graphql");
15
- let buildSubgraphSchema = null;
16
- async function loadFederationSupport() {
17
- if (buildSubgraphSchema !== null) return buildSubgraphSchema;
18
- try {
19
- buildSubgraphSchema = (await import("@apollo/subgraph")).buildSubgraphSchema;
20
- } catch {
21
- buildSubgraphSchema = false;
22
- }
23
- return buildSubgraphSchema;
24
- }
25
- function generateGraphQLIndexFile(nitro, clientDir, externalServices = []) {
26
- if (!shouldGenerateClientUtils(nitro)) return;
27
- const placeholders = getDefaultPaths(nitro);
28
- const clientUtilsConfig = getClientUtilsConfig(nitro);
29
- const indexPath = resolveFilePath(clientUtilsConfig.index, clientUtilsConfig.enabled, true, "{clientGraphql}/index.ts", placeholders);
30
- if (!indexPath) return;
31
- if (!existsSync(indexPath)) {
32
- let indexContent = `// This file is auto-generated once by nitro-graphql for quick start
33
- // You can modify this file according to your needs
34
- //
35
- // Export your main GraphQL service (auto-generated)
36
- export * from './default/ofetch'
37
-
38
- // Export external GraphQL services (auto-generated for existing services)
39
- // When you add new external services, don't forget to add their exports here:
40
- // export * from './yourServiceName/ofetch'
41
- `;
42
- for (const service of externalServices) indexContent += `export * from './${service.name}/ofetch'\n`;
43
- writeFileIfNotExists(indexPath, indexContent, "client index.ts");
44
- }
45
- }
46
- function generateNuxtOfetchClient(nitro, clientDir, serviceName = "default") {
47
- if (!shouldGenerateClientUtils(nitro)) return;
48
- const placeholders = {
49
- ...getDefaultPaths(nitro),
50
- serviceName
51
- };
52
- const clientUtilsConfig = getClientUtilsConfig(nitro);
53
- const ofetchPath = resolveFilePath(clientUtilsConfig.ofetch, clientUtilsConfig.enabled, true, "{clientGraphql}/{serviceName}/ofetch.ts", placeholders);
54
- if (!ofetchPath) return;
55
- const serviceDir = dirname(ofetchPath);
56
- if (!existsSync(serviceDir)) mkdirSync(serviceDir, { recursive: true });
57
- if (existsSync(ofetchPath)) return;
58
- writeFileIfNotExists(ofetchPath, nitro.options.framework?.name === "nuxt" ? `// This file is auto-generated once by nitro-graphql for quick start
59
- // You can modify this file according to your needs
60
- import type { Requester } from './sdk'
61
- import { getSdk } from './sdk'
62
-
63
- export function createGraphQLClient(endpoint: string): Requester {
64
- return async <R>(doc: string, vars?: any): Promise<R> => {
65
- const headers = import.meta.server ? useRequestHeaders() : undefined
66
-
67
- const result = await $fetch(endpoint, {
68
- method: 'POST',
69
- body: { query: doc, variables: vars },
70
- headers: {
71
- 'Content-Type': 'application/json',
72
- ...headers,
73
- },
74
- })
75
-
76
- return result as R
77
- }
78
- }
79
-
80
- export const $sdk = getSdk(createGraphQLClient('/api/graphql'))` : `// This file is auto-generated once by nitro-graphql for quick start
81
- // You can modify this file according to your needs
82
- import type { Requester } from './sdk'
83
- import { ofetch } from 'ofetch'
84
- import { getSdk } from './sdk'
85
-
86
- export function createGraphQLClient(endpoint: string): Requester {
87
- return async <R>(doc: string, vars?: any): Promise<R> => {
88
- const result = await ofetch(endpoint, {
89
- method: 'POST',
90
- body: { query: doc, variables: vars },
91
- headers: {
92
- 'Content-Type': 'application/json',
93
- },
94
- })
95
-
96
- return result as R
97
- }
98
- }
99
-
100
- export const $sdk = getSdk(createGraphQLClient('/api/graphql'))`, `${serviceName} ofetch.ts`);
101
- }
102
- function generateExternalOfetchClient(nitro, service, endpoint) {
103
- if (!shouldGenerateClientUtils(nitro)) return;
104
- const serviceName = service.name;
105
- const placeholders = {
106
- ...getDefaultPaths(nitro),
107
- serviceName
108
- };
109
- const clientUtilsConfig = getClientUtilsConfig(nitro);
110
- const ofetchPath = resolveFilePath(service.paths?.ofetch ?? clientUtilsConfig.ofetch, clientUtilsConfig.enabled, true, "{clientGraphql}/{serviceName}/ofetch.ts", placeholders);
111
- if (!ofetchPath) return;
112
- const serviceDir = dirname(ofetchPath);
113
- if (!existsSync(serviceDir)) mkdirSync(serviceDir, { recursive: true });
114
- if (!existsSync(ofetchPath)) {
115
- const capitalizedServiceName = serviceName.charAt(0).toUpperCase() + serviceName.slice(1);
116
- writeFileIfNotExists(ofetchPath, nitro.options.framework?.name === "nuxt" ? `// This file is auto-generated once by nitro-graphql for quick start
117
- // You can modify this file according to your needs
118
- import type { Sdk, Requester } from './sdk'
119
- import { getSdk } from './sdk'
120
-
121
- export function create${capitalizedServiceName}GraphQLClient(endpoint: string = '${endpoint}'): Requester {
122
- return async <R>(doc: string, vars?: any): Promise<R> => {
123
- const headers = import.meta.server ? useRequestHeaders() : undefined
124
-
125
- const result = await $fetch(endpoint, {
126
- method: 'POST',
127
- body: { query: doc, variables: vars },
128
- headers: {
129
- 'Content-Type': 'application/json',
130
- ...headers,
131
- },
132
- })
133
-
134
- return result as R
135
- }
136
- }
137
-
138
- export const $${serviceName}Sdk: Sdk = getSdk(create${capitalizedServiceName}GraphQLClient())` : `// This file is auto-generated once by nitro-graphql for quick start
139
- // You can modify this file according to your needs
140
- import type { Sdk, Requester } from './sdk'
141
- import { ofetch } from 'ofetch'
142
- import { getSdk } from './sdk'
143
-
144
- export function create${capitalizedServiceName}GraphQLClient(endpoint: string = '${endpoint}'): Requester {
145
- return async <R>(doc: string, vars?: any): Promise<R> => {
146
- const result = await ofetch(endpoint, {
147
- method: 'POST',
148
- body: { query: doc, variables: vars },
149
- headers: {
150
- 'Content-Type': 'application/json',
151
- },
152
- })
153
-
154
- return result as R
155
- }
156
- }
157
-
158
- export const $${serviceName}Sdk: Sdk = getSdk(create${capitalizedServiceName}GraphQLClient())`, `${serviceName} external ofetch.ts`);
159
- }
160
- }
161
- /**
162
- * Check for duplicate type definitions using a simpler approach
163
- * Try to build each schema individually - if that succeeds but merging fails, we have duplicates
164
- * @returns true if validation passes, false if duplicates found
165
- */
166
- function validateNoDuplicateTypes(schemas, schemaStrings) {
167
- const individualSchemasByFile = /* @__PURE__ */ new Map();
168
- schemaStrings.forEach((schemaContent, index) => {
169
- const schemaPath = schemas[index];
170
- const fileName = basename(schemaPath);
171
- try {
172
- parse(schemaContent);
173
- individualSchemasByFile.set(fileName, schemaContent);
174
- } catch (error) {
175
- consola.warn(`Invalid GraphQL syntax in ${fileName}:`, error);
176
- throw error;
177
- }
178
- });
179
- try {
180
- mergeTypeDefs([schemaStrings.join("\n\n")], {
181
- throwOnConflict: false,
182
- commentDescriptions: true,
183
- sort: true
184
- });
185
- mergeTypeDefs([schemaStrings.join("\n\n")], {
186
- throwOnConflict: true,
187
- commentDescriptions: true,
188
- sort: true
189
- });
190
- } catch (conflictError) {
191
- if (conflictError?.message?.includes("already defined with a different type")) throw conflictError;
192
- }
193
- const typeNames = /* @__PURE__ */ new Set();
194
- const duplicateTypes = [];
195
- schemaStrings.forEach((schemaContent, index) => {
196
- const fileName = basename(schemas[index]);
197
- try {
198
- parse(schemaContent).definitions.forEach((def) => {
199
- if (def.kind === "ObjectTypeDefinition" || def.kind === "InterfaceTypeDefinition" || def.kind === "UnionTypeDefinition" || def.kind === "EnumTypeDefinition" || def.kind === "InputObjectTypeDefinition" || def.kind === "ScalarTypeDefinition") {
200
- const typeName = def.name.value;
201
- if ([
202
- "String",
203
- "Int",
204
- "Float",
205
- "Boolean",
206
- "ID",
207
- "DateTime",
208
- "JSON"
209
- ].includes(typeName)) return;
210
- if (typeNames.has(typeName)) {
211
- const existing = duplicateTypes.find((d) => d.type === typeName);
212
- if (existing) existing.files.push(fileName);
213
- else {
214
- const firstFile = schemas.find((_, i) => {
215
- const content = schemaStrings[i];
216
- if (!content) return false;
217
- try {
218
- return parse(content).definitions.some((d) => (d.kind === "ObjectTypeDefinition" || d.kind === "InterfaceTypeDefinition" || d.kind === "UnionTypeDefinition" || d.kind === "EnumTypeDefinition" || d.kind === "InputObjectTypeDefinition" || d.kind === "ScalarTypeDefinition") && d.name.value === typeName);
219
- } catch {
220
- return false;
221
- }
222
- });
223
- duplicateTypes.push({
224
- type: typeName,
225
- files: [basename(firstFile || ""), fileName]
226
- });
227
- }
228
- } else typeNames.add(typeName);
229
- }
230
- });
231
- } catch {}
232
- });
233
- if (duplicateTypes.length > 0) {
234
- let errorMessage = "⚠️ DUPLICATE TYPE DEFINITIONS DETECTED!\n\n";
235
- duplicateTypes.forEach(({ type, files }) => {
236
- errorMessage += `❌ Type "${type}" is defined in multiple files:\n`;
237
- files.forEach((fileName) => {
238
- const fullPath = schemas.find((path) => basename(path) === fileName) || fileName;
239
- errorMessage += ` • ${fullPath}\n`;
240
- });
241
- errorMessage += "\n";
242
- });
243
- errorMessage += "💡 Each GraphQL type should only be defined once.\n";
244
- errorMessage += " Consider using \"extend type\" syntax instead of duplicate definitions.\n";
245
- errorMessage += `\n🔍 Found ${duplicateTypes.length} duplicate type(s): ${duplicateTypes.map((d) => d.type).join(", ")}`;
246
- consola.error(errorMessage);
247
- return false;
248
- }
249
- return true;
250
- }
251
- async function serverTypeGeneration(app, options = {}) {
252
- try {
253
- if (!shouldGenerateTypes(app)) {
254
- logger.debug("Server type generation is disabled");
255
- return;
256
- }
257
- const schemas = app.scanSchemas || [];
258
- if (!schemas.length) {
259
- if (!options.silent) consola.info("No GraphQL definitions found for server type generation.");
260
- return;
261
- }
262
- const schemaStrings = loadFilesSync(schemas).map((schema$1) => typeof schema$1 === "string" ? schema$1 : schema$1.loc?.source?.body || "").filter(Boolean);
263
- if (!validateNoDuplicateTypes(schemas, schemaStrings)) return;
264
- const federationEnabled = app.options.graphql?.federation?.enabled === true;
265
- const mergedSchemas = mergeTypeDefs([schemaStrings.join("\n\n")], {
266
- throwOnConflict: true,
267
- commentDescriptions: true,
268
- sort: true
269
- });
270
- let schema;
271
- if (federationEnabled) {
272
- const buildSubgraph = await loadFederationSupport();
273
- if (!buildSubgraph) throw new Error("Federation is enabled but @apollo/subgraph is not installed. Run: pnpm add @apollo/subgraph");
274
- schema = buildSubgraph([{ typeDefs: parse(mergedSchemas) }]);
275
- } else schema = buildSchema(mergedSchemas);
276
- const data = await generateTypes(app.options.graphql?.framework || "graphql-yoga", schema, app.options.graphql ?? {});
277
- const printSchema = printSchemaWithDirectives(schema);
278
- const schemaPath = resolve(app.graphql.buildDir, "schema.graphql");
279
- mkdirSync(dirname(schemaPath), { recursive: true });
280
- writeFileSync(schemaPath, printSchema, "utf-8");
281
- const placeholders = getDefaultPaths(app);
282
- const typesConfig = getTypesConfig(app);
283
- const serverTypesPath = resolveFilePath(typesConfig.server, typesConfig.enabled, true, "{typesDir}/nitro-graphql-server.d.ts", placeholders);
284
- if (serverTypesPath) {
285
- mkdirSync(dirname(serverTypesPath), { recursive: true });
286
- writeFileSync(serverTypesPath, data, "utf-8");
287
- if (!options.silent) logger.success(`Generated server types at: ${serverTypesPath}`);
288
- }
289
- } catch (error) {
290
- logger.error("Server schema generation error:", error);
291
- }
292
- }
293
- async function clientTypeGeneration(nitro, options = {}) {
294
- try {
295
- if (nitro.scanSchemas && nitro.scanSchemas.length > 0) await generateMainClientTypes(nitro, options);
296
- if (nitro.options.graphql?.externalServices?.length) await generateExternalServicesTypes(nitro, options);
297
- } catch (error) {
298
- logger.error("Client schema generation error:", error);
299
- }
300
- }
301
- /**
302
- * Check for old structure files and warn user about manual migration
303
- */
304
- function checkOldStructure(clientDir) {
305
- const oldOfetchPath = resolve(clientDir, "ofetch.ts");
306
- const oldSdkPath = resolve(clientDir, "sdk.ts");
307
- if (existsSync(oldOfetchPath) || existsSync(oldSdkPath)) {
308
- const foundFiles = [];
309
- if (existsSync(oldOfetchPath)) foundFiles.push("app/graphql/ofetch.ts");
310
- if (existsSync(oldSdkPath)) foundFiles.push("app/graphql/sdk.ts");
311
- consola.error(`⚠️ OLD GRAPHQL STRUCTURE DETECTED!
312
-
313
- 📁 Found old files in app/graphql/ directory that need to be moved:
314
- • ${foundFiles.join("\n • ")}
315
-
316
- 🔄 Please manually move these files to the new structure:
317
- • app/graphql/ofetch.ts → app/graphql/default/ofetch.ts
318
- • app/graphql/sdk.ts → app/graphql/default/sdk.ts
319
-
320
- 📝 Also update your app/graphql/index.ts to include:
321
- export * from './default/ofetch'
322
-
323
- 💡 After moving, update your imports to use:
324
- import { $sdk } from "#graphql/client"
325
-
326
- 🚫 The old files will cause import conflicts until moved!`);
327
- }
328
- }
329
- async function generateMainClientTypes(nitro, options = {}) {
330
- checkOldStructure(nitro.graphql.clientDir);
331
- const docs = nitro.scanDocuments;
332
- const loadDocs = await loadGraphQLDocuments(docs);
333
- const schemaFilePath = join(nitro.graphql.buildDir, "schema.graphql");
334
- if (!existsSync(schemaFilePath)) {
335
- if (!options.silent) consola.info("Schema file not ready yet for client type generation. Server types need to be generated first.");
336
- return;
337
- }
338
- const graphqlString = readFileSync(schemaFilePath, "utf-8");
339
- const federationEnabled = nitro.options.graphql?.federation?.enabled === true;
340
- let schema;
341
- if (federationEnabled) {
342
- const buildSubgraph = await loadFederationSupport();
343
- if (!buildSubgraph) throw new Error("Federation is enabled but @apollo/subgraph is not installed. Run: pnpm add @apollo/subgraph");
344
- schema = buildSubgraph([{ typeDefs: parse(graphqlString) }]);
345
- } else schema = buildSchema(graphqlString);
346
- const types = await generateClientTypes(schema, loadDocs, nitro.options.graphql?.codegen?.client ?? {}, nitro.options.graphql?.codegen?.clientSDK ?? {}, void 0, void 0, void 0, options);
347
- if (types === false) return;
348
- const placeholders = getDefaultPaths(nitro);
349
- const typesConfig = getTypesConfig(nitro);
350
- const sdkConfig = getSdkConfig(nitro);
351
- const clientTypesPath = resolveFilePath(typesConfig.client, typesConfig.enabled, true, "{typesDir}/nitro-graphql-client.d.ts", placeholders);
352
- if (clientTypesPath) {
353
- mkdirSync(dirname(clientTypesPath), { recursive: true });
354
- writeFileSync(clientTypesPath, types.types, "utf-8");
355
- if (!options.silent) logger.success(`Generated client types at: ${clientTypesPath}`);
356
- }
357
- const sdkPath = resolveFilePath(sdkConfig.main, sdkConfig.enabled, true, "{clientGraphql}/default/sdk.ts", placeholders);
358
- if (sdkPath) {
359
- mkdirSync(dirname(sdkPath), { recursive: true });
360
- writeFileSync(sdkPath, types.sdk, "utf-8");
361
- if (!options.silent) logger.success(`Generated SDK at: ${sdkPath}`);
362
- }
363
- generateNuxtOfetchClient(nitro, nitro.graphql.clientDir, "default");
364
- const externalServices = nitro.options.graphql?.externalServices || [];
365
- if (externalServices.length > 0) generateGraphQLIndexFile(nitro, nitro.graphql.clientDir, externalServices);
366
- }
367
- async function generateExternalServicesTypes(nitro, options = {}) {
368
- const externalServices = nitro.options.graphql?.externalServices || [];
369
- for (const service of externalServices) try {
370
- if (!options.silent) consola.info(`[graphql:${service.name}] Processing external service`);
371
- await downloadAndSaveSchema(service, nitro.options.buildDir);
372
- const schema = await loadExternalSchema(service, nitro.options.buildDir);
373
- if (!schema) {
374
- consola.warn(`[graphql:${service.name}] Failed to load schema, skipping`);
375
- continue;
376
- }
377
- const documentPatterns = service.documents || [];
378
- let loadDocs = [];
379
- if (documentPatterns.length > 0) try {
380
- loadDocs = await loadGraphQLDocuments(documentPatterns);
381
- if (!loadDocs || loadDocs.length === 0) {
382
- consola.warn(`[graphql:${service.name}] No GraphQL documents found, skipping service generation`);
383
- continue;
384
- }
385
- } catch (error) {
386
- consola.warn(`[graphql:${service.name}] No documents found, skipping service generation:`, error);
387
- continue;
388
- }
389
- const types = await generateExternalClientTypes(service, schema, loadDocs);
390
- if (types === false) {
391
- consola.warn(`[graphql:${service.name}] Type generation failed`);
392
- continue;
393
- }
394
- const placeholders = {
395
- ...getDefaultPaths(nitro),
396
- serviceName: service.name
397
- };
398
- const typesConfig = getTypesConfig(nitro);
399
- const sdkConfig = getSdkConfig(nitro);
400
- const serviceTypesPath = resolveFilePath(service.paths?.types ?? typesConfig.external, typesConfig.enabled, true, "{typesDir}/nitro-graphql-client-{serviceName}.d.ts", placeholders);
401
- if (serviceTypesPath) {
402
- mkdirSync(dirname(serviceTypesPath), { recursive: true });
403
- writeFileSync(serviceTypesPath, types.types, "utf-8");
404
- if (!options.silent) consola.success(`[graphql:${service.name}] Generated types at: ${serviceTypesPath}`);
405
- }
406
- const serviceSdkPath = resolveFilePath(service.paths?.sdk ?? sdkConfig.external, sdkConfig.enabled, true, "{clientGraphql}/{serviceName}/sdk.ts", placeholders);
407
- if (serviceSdkPath) {
408
- mkdirSync(dirname(serviceSdkPath), { recursive: true });
409
- writeFileSync(serviceSdkPath, types.sdk, "utf-8");
410
- if (!options.silent) consola.success(`[graphql:${service.name}] Generated SDK at: ${serviceSdkPath}`);
411
- }
412
- generateExternalOfetchClient(nitro, service, service.endpoint);
413
- if (!options.silent) consola.success(`[graphql:${service.name}] External service types generated successfully`);
414
- } catch (error) {
415
- consola.error(`[graphql:${service.name}] External service generation failed:`, error);
416
- }
417
- }
418
-
419
- //#endregion
420
- export { clientTypeGeneration, serverTypeGeneration };
7
+ export { generateClientTypes, generateExternalServicesTypes, generateMainClientTypes, generateServerTypes, validateNoDuplicateTypes };
@@ -0,0 +1,11 @@
1
+ //#region src/utils/validation.d.ts
2
+ /**
3
+ * Validation utilities
4
+ * Configuration validation helpers
5
+ */
6
+ /**
7
+ * Validate external GraphQL service configuration
8
+ */
9
+ declare function validateExternalServices(services: unknown[]): string[];
10
+ //#endregion
11
+ export { validateExternalServices };
@@ -0,0 +1,34 @@
1
+ //#region src/utils/validation.ts
2
+ /**
3
+ * Validation utilities
4
+ * Configuration validation helpers
5
+ */
6
+ /**
7
+ * Validate external GraphQL service configuration
8
+ */
9
+ function validateExternalServices(services) {
10
+ const errors = [];
11
+ const serviceNames = /* @__PURE__ */ new Set();
12
+ for (const [index, service] of services.entries()) {
13
+ const prefix = `externalServices[${index}]`;
14
+ if (!service || typeof service !== "object") {
15
+ errors.push(`${prefix} must be an object`);
16
+ continue;
17
+ }
18
+ if (!("name" in service) || typeof service.name !== "string") errors.push(`${prefix}.name is required and must be a string`);
19
+ else if (serviceNames.has(service.name)) errors.push(`${prefix}.name "${service.name}" must be unique`);
20
+ else serviceNames.add(service.name);
21
+ if (!("schema" in service) || !service.schema) errors.push(`${prefix}.schema is required`);
22
+ if (!("endpoint" in service) || typeof service.endpoint !== "string") errors.push(`${prefix}.endpoint is required and must be a string`);
23
+ else try {
24
+ new URL(service.endpoint);
25
+ } catch {
26
+ errors.push(`${prefix}.endpoint "${service.endpoint}" must be a valid URL`);
27
+ }
28
+ if ("name" in service && service.name && typeof service.name === "string" && !/^[a-z]\w*$/i.test(service.name)) errors.push(`${prefix}.name "${service.name}" must be a valid identifier (letters, numbers, underscore, starting with letter)`);
29
+ }
30
+ return errors;
31
+ }
32
+
33
+ //#endregion
34
+ export { validateExternalServices };
@@ -0,0 +1,22 @@
1
+ import { Nitro } from "nitro/types";
2
+
3
+ //#region src/virtual/generators/config.d.ts
4
+
5
+ /**
6
+ * Generate virtual module code for GraphQL config (from server/graphql/config.ts)
7
+ */
8
+ declare function generateGraphQLConfigModule(nitro: Nitro): string;
9
+ /**
10
+ * Register the GraphQL config virtual module with Nitro
11
+ */
12
+ declare function virtualGraphQLConfig(nitro: Nitro): void;
13
+ /**
14
+ * Generate virtual module code for module config (serialized graphql options)
15
+ */
16
+ declare function generateModuleConfigModule(nitro: Nitro): string;
17
+ /**
18
+ * Register the module config virtual module with Nitro
19
+ */
20
+ declare function virtualModuleConfig(nitro: Nitro): void;
21
+ //#endregion
22
+ export { generateGraphQLConfigModule, generateModuleConfigModule, virtualGraphQLConfig, virtualModuleConfig };
@@ -0,0 +1,36 @@
1
+ import { resolve } from "pathe";
2
+
3
+ //#region src/virtual/generators/config.ts
4
+ /**
5
+ * Generate virtual module code for GraphQL config (from server/graphql/config.ts)
6
+ */
7
+ function generateGraphQLConfigModule(nitro) {
8
+ return `import config from '${resolve(nitro.graphql.serverDir, "config.ts")}'
9
+ const importedConfig = config
10
+ export { importedConfig }
11
+ `;
12
+ }
13
+ /**
14
+ * Register the GraphQL config virtual module with Nitro
15
+ */
16
+ function virtualGraphQLConfig(nitro) {
17
+ nitro.options.virtual ??= {};
18
+ nitro.options.virtual["#nitro-graphql/graphql-config"] = () => generateGraphQLConfigModule(nitro);
19
+ }
20
+ /**
21
+ * Generate virtual module code for module config (serialized graphql options)
22
+ */
23
+ function generateModuleConfigModule(nitro) {
24
+ const moduleConfig = nitro.options.graphql || {};
25
+ return `export const moduleConfig = ${JSON.stringify(moduleConfig, null, 2)};`;
26
+ }
27
+ /**
28
+ * Register the module config virtual module with Nitro
29
+ */
30
+ function virtualModuleConfig(nitro) {
31
+ nitro.options.virtual ??= {};
32
+ nitro.options.virtual["#nitro-graphql/module-config"] = () => generateModuleConfigModule(nitro);
33
+ }
34
+
35
+ //#endregion
36
+ export { generateGraphQLConfigModule, generateModuleConfigModule, virtualGraphQLConfig, virtualModuleConfig };
@@ -0,0 +1,14 @@
1
+ import { Nitro } from "nitro/types";
2
+
3
+ //#region src/virtual/generators/debug.d.ts
4
+
5
+ /**
6
+ * Generate virtual module code for debug info
7
+ */
8
+ declare function generateDebugInfoModule(nitro: Nitro): string;
9
+ /**
10
+ * Register the debug info virtual module with Nitro
11
+ */
12
+ declare function virtualDebugInfo(nitro: Nitro): void;
13
+ //#endregion
14
+ export { generateDebugInfoModule, virtualDebugInfo };
@@ -0,0 +1,53 @@
1
+ //#region src/virtual/generators/debug.ts
2
+ /**
3
+ * Safely call a virtual module generator and capture its output
4
+ */
5
+ function safeGenerateModuleCode(nitro, moduleName) {
6
+ try {
7
+ const generator = nitro.options.virtual?.[moduleName];
8
+ if (generator && typeof generator === "function") return generator();
9
+ return "// Module not found";
10
+ } catch (error) {
11
+ return `// Error generating: ${error instanceof Error ? error.message : String(error)}`;
12
+ }
13
+ }
14
+ /**
15
+ * Generate virtual module code for debug info
16
+ */
17
+ function generateDebugInfoModule(nitro) {
18
+ const virtualModuleCodes = {
19
+ "server-schemas": safeGenerateModuleCode(nitro, "#nitro-graphql/server-schemas"),
20
+ "server-resolvers": safeGenerateModuleCode(nitro, "#nitro-graphql/server-resolvers"),
21
+ "server-directives": safeGenerateModuleCode(nitro, "#nitro-graphql/server-directives"),
22
+ "module-config": safeGenerateModuleCode(nitro, "#nitro-graphql/module-config"),
23
+ "graphql-config": safeGenerateModuleCode(nitro, "#nitro-graphql/graphql-config")
24
+ };
25
+ const debugInfo = {
26
+ isDev: nitro.options.dev,
27
+ framework: nitro.options.framework.name,
28
+ graphqlFramework: nitro.options.graphql?.framework,
29
+ federation: nitro.options.graphql?.federation,
30
+ scanned: {
31
+ schemas: nitro.scanSchemas?.length || 0,
32
+ schemaFiles: nitro.scanSchemas || [],
33
+ resolvers: nitro.scanResolvers?.length || 0,
34
+ resolverFiles: nitro.scanResolvers || [],
35
+ directives: nitro.scanDirectives?.length || 0,
36
+ directiveFiles: nitro.scanDirectives || [],
37
+ documents: nitro.scanDocuments?.length || 0,
38
+ documentFiles: nitro.scanDocuments || []
39
+ },
40
+ virtualModules: virtualModuleCodes
41
+ };
42
+ return `export const debugInfo = ${JSON.stringify(debugInfo, null, 2)};`;
43
+ }
44
+ /**
45
+ * Register the debug info virtual module with Nitro
46
+ */
47
+ function virtualDebugInfo(nitro) {
48
+ nitro.options.virtual ??= {};
49
+ nitro.options.virtual["#nitro-graphql/debug-info"] = () => generateDebugInfoModule(nitro);
50
+ }
51
+
52
+ //#endregion
53
+ export { generateDebugInfoModule, virtualDebugInfo };
@@ -0,0 +1,14 @@
1
+ import { Nitro } from "nitro/types";
2
+
3
+ //#region src/virtual/generators/directives.d.ts
4
+
5
+ /**
6
+ * Generate virtual module code for server directives
7
+ */
8
+ declare function generateDirectivesModule(nitro: Nitro): string;
9
+ /**
10
+ * Register the directives virtual module with Nitro
11
+ */
12
+ declare function virtualDirectives(nitro: Nitro): void;
13
+ //#endregion
14
+ export { generateDirectivesModule, virtualDirectives };