nitro-graphql 2.0.0-beta.3 → 2.0.0-beta.30

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 (72) hide show
  1. package/README.md +476 -19
  2. package/dist/define.d.mts +296 -0
  3. package/dist/define.mjs +323 -0
  4. package/dist/ecosystem/nuxt.mjs +109 -0
  5. package/dist/index.d.mts +43 -0
  6. package/dist/index.mjs +63 -0
  7. package/dist/rollup.d.mts +12 -0
  8. package/dist/rollup.mjs +282 -0
  9. package/dist/routes/apollo-server.d.mts +6 -0
  10. package/dist/routes/{apollo-server.js → apollo-server.mjs} +7 -7
  11. package/dist/routes/debug.d.mts +61 -0
  12. package/dist/routes/debug.mjs +445 -0
  13. package/dist/routes/graphql-yoga.d.mts +6 -0
  14. package/dist/routes/{graphql-yoga.js → graphql-yoga.mjs} +11 -7
  15. package/dist/routes/health.d.mts +10 -0
  16. package/dist/routes/{health.js → health.mjs} +3 -2
  17. package/dist/setup.d.mts +11 -0
  18. package/dist/setup.mjs +392 -0
  19. package/dist/{utils/define.d.ts → types/define.d.mts} +4 -27
  20. package/dist/types/define.mjs +1 -0
  21. package/dist/types/index.d.mts +246 -0
  22. package/dist/types/index.mjs +1 -0
  23. package/dist/types/standard-schema.mjs +1 -0
  24. package/dist/utils/{apollo.d.ts → apollo.d.mts} +2 -2
  25. package/dist/utils/apollo.mjs +59 -0
  26. package/dist/utils/{client-codegen.d.ts → client-codegen.d.mts} +6 -3
  27. package/dist/utils/{client-codegen.js → client-codegen.mjs} +6 -6
  28. package/dist/utils/errors.d.mts +73 -0
  29. package/dist/utils/errors.mjs +89 -0
  30. package/dist/utils/file-generator.d.mts +37 -0
  31. package/dist/utils/file-generator.mjs +72 -0
  32. package/dist/utils/{index.d.ts → index.d.mts} +4 -3
  33. package/dist/utils/{index.js → index.mjs} +76 -37
  34. package/dist/utils/path-resolver.d.mts +70 -0
  35. package/dist/utils/path-resolver.mjs +127 -0
  36. package/dist/utils/{server-codegen.d.ts → server-codegen.d.mts} +1 -1
  37. package/dist/utils/{server-codegen.js → server-codegen.mjs} +3 -3
  38. package/dist/utils/type-generation.d.mts +12 -0
  39. package/dist/utils/type-generation.mjs +420 -0
  40. package/dist/virtual/debug-info.d.mts +9 -0
  41. package/dist/virtual/debug-info.mjs +26 -0
  42. package/dist/virtual/graphql-config.d.mts +9 -0
  43. package/dist/virtual/graphql-config.mjs +10 -0
  44. package/dist/virtual/module-config.d.mts +9 -0
  45. package/dist/virtual/module-config.mjs +10 -0
  46. package/dist/virtual/server-directives.d.mts +11 -0
  47. package/dist/virtual/server-directives.mjs +10 -0
  48. package/dist/virtual/server-resolvers.d.mts +11 -0
  49. package/dist/virtual/server-resolvers.mjs +10 -0
  50. package/dist/virtual/server-schemas.d.mts +11 -0
  51. package/dist/virtual/server-schemas.mjs +10 -0
  52. package/package.json +79 -70
  53. package/dist/ecosystem/nuxt.js +0 -67
  54. package/dist/index.d.ts +0 -8
  55. package/dist/index.js +0 -264
  56. package/dist/rollup.js +0 -114
  57. package/dist/routes/apollo-server.d.ts +0 -6
  58. package/dist/routes/graphql-yoga.d.ts +0 -6
  59. package/dist/routes/health.d.ts +0 -6
  60. package/dist/types/index.d.ts +0 -128
  61. package/dist/utils/apollo.js +0 -61
  62. package/dist/utils/define.js +0 -57
  63. package/dist/utils/type-generation.d.ts +0 -7
  64. package/dist/utils/type-generation.js +0 -287
  65. /package/dist/ecosystem/{nuxt.d.ts → nuxt.d.mts} +0 -0
  66. /package/dist/graphql/{index.d.ts → index.d.mts} +0 -0
  67. /package/dist/graphql/{index.js → index.mjs} +0 -0
  68. /package/dist/graphql/{server.d.ts → server.d.mts} +0 -0
  69. /package/dist/graphql/{server.js → server.mjs} +0 -0
  70. /package/dist/types/{standard-schema.d.ts → standard-schema.d.mts} +0 -0
  71. /package/dist/utils/{directive-parser.d.ts → directive-parser.d.mts} +0 -0
  72. /package/dist/utils/{directive-parser.js → directive-parser.mjs} +0 -0
@@ -0,0 +1,127 @@
1
+ import { isAbsolute, resolve } from "pathe";
2
+
3
+ //#region src/utils/path-resolver.ts
4
+ /**
5
+ * Replace placeholders in a path string
6
+ * Supports: {serviceName}, {buildDir}, {rootDir}, {framework}, {typesDir}, {serverGraphql}, {clientGraphql}
7
+ */
8
+ function replacePlaceholders(path, placeholders) {
9
+ return path.replace(/\{serviceName\}/g, placeholders.serviceName || "default").replace(/\{buildDir\}/g, placeholders.buildDir).replace(/\{rootDir\}/g, placeholders.rootDir).replace(/\{framework\}/g, placeholders.framework).replace(/\{typesDir\}/g, placeholders.typesDir).replace(/\{serverGraphql\}/g, placeholders.serverGraphql).replace(/\{clientGraphql\}/g, placeholders.clientGraphql);
10
+ }
11
+ /**
12
+ * Get default paths based on framework and user configuration
13
+ */
14
+ function getDefaultPaths(nitro) {
15
+ const isNuxt = nitro.options.framework?.name === "nuxt";
16
+ const rootDir = nitro.options.rootDir;
17
+ const buildDir = nitro.options.buildDir;
18
+ const pathsConfig = nitro.options.graphql?.paths || {};
19
+ const defaultServerGraphql = pathsConfig.serverGraphql || resolve(rootDir, "server", "graphql");
20
+ const defaultClientGraphql = pathsConfig.clientGraphql || resolve(rootDir, isNuxt ? "app/graphql" : "graphql");
21
+ const defaultBuildDir = pathsConfig.buildDir || buildDir;
22
+ const defaultTypesDir = pathsConfig.typesDir || resolve(defaultBuildDir, "types");
23
+ return {
24
+ serviceName: "default",
25
+ buildDir: defaultBuildDir,
26
+ rootDir,
27
+ framework: isNuxt ? "nuxt" : "nitro",
28
+ typesDir: defaultTypesDir,
29
+ serverGraphql: defaultServerGraphql,
30
+ clientGraphql: defaultClientGraphql
31
+ };
32
+ }
33
+ /**
34
+ * Check if a file should be generated based on config
35
+ * Returns: true if should generate, false if should skip
36
+ */
37
+ function shouldGenerateFile(config, categoryEnabled, topLevelEnabled) {
38
+ if (config === false) return false;
39
+ if (config === true || typeof config === "string") return true;
40
+ if (categoryEnabled === false) return false;
41
+ if (categoryEnabled === true) return true;
42
+ return topLevelEnabled;
43
+ }
44
+ /**
45
+ * Resolve the file path based on configuration
46
+ * Returns: resolved absolute path or null if file should not be generated
47
+ */
48
+ function resolveFilePath(config, categoryEnabled, topLevelEnabled, defaultPath, placeholders) {
49
+ if (!shouldGenerateFile(config, categoryEnabled, topLevelEnabled)) return null;
50
+ if (typeof config === "string") {
51
+ const customPath = replacePlaceholders(config, placeholders);
52
+ return isAbsolute(customPath) ? customPath : resolve(placeholders.rootDir, customPath);
53
+ }
54
+ const resolvedDefault = replacePlaceholders(defaultPath, placeholders);
55
+ return resolve(placeholders.rootDir, resolvedDefault);
56
+ }
57
+ /**
58
+ * Check if scaffold files should be generated (category-level check)
59
+ */
60
+ function shouldGenerateScaffold(nitro) {
61
+ const scaffoldConfig = nitro.options.graphql?.scaffold;
62
+ if (scaffoldConfig === false) return false;
63
+ if (scaffoldConfig && scaffoldConfig.enabled === false) return false;
64
+ return true;
65
+ }
66
+ /**
67
+ * Get scaffold configuration (handles false case)
68
+ */
69
+ function getScaffoldConfig(nitro) {
70
+ const scaffoldConfig = nitro.options.graphql?.scaffold;
71
+ if (scaffoldConfig === false) return { enabled: false };
72
+ return scaffoldConfig || {};
73
+ }
74
+ /**
75
+ * Check if client utilities should be generated (category-level check)
76
+ */
77
+ function shouldGenerateClientUtils(nitro) {
78
+ const clientUtilsConfig = nitro.options.graphql?.clientUtils;
79
+ if (clientUtilsConfig === false) return false;
80
+ if (clientUtilsConfig && clientUtilsConfig.enabled === false) return false;
81
+ return true;
82
+ }
83
+ /**
84
+ * Get client utilities configuration (handles false case)
85
+ */
86
+ function getClientUtilsConfig(nitro) {
87
+ const clientUtilsConfig = nitro.options.graphql?.clientUtils;
88
+ if (clientUtilsConfig === false) return { enabled: false };
89
+ return clientUtilsConfig || {};
90
+ }
91
+ /**
92
+ * Check if SDK files should be generated (category-level check)
93
+ */
94
+ function shouldGenerateSDK(nitro) {
95
+ const sdkConfig = nitro.options.graphql?.sdk;
96
+ if (sdkConfig === false) return false;
97
+ if (sdkConfig && sdkConfig.enabled === false) return false;
98
+ return true;
99
+ }
100
+ /**
101
+ * Get SDK configuration (handles false case)
102
+ */
103
+ function getSdkConfig(nitro) {
104
+ const sdkConfig = nitro.options.graphql?.sdk;
105
+ if (sdkConfig === false) return { enabled: false };
106
+ return sdkConfig || {};
107
+ }
108
+ /**
109
+ * Check if type files should be generated (category-level check)
110
+ */
111
+ function shouldGenerateTypes(nitro) {
112
+ const typesConfig = nitro.options.graphql?.types;
113
+ if (typesConfig === false) return false;
114
+ if (typesConfig && typesConfig.enabled === false) return false;
115
+ return true;
116
+ }
117
+ /**
118
+ * Get types configuration (handles false case)
119
+ */
120
+ function getTypesConfig(nitro) {
121
+ const typesConfig = nitro.options.graphql?.types;
122
+ if (typesConfig === false) return { enabled: false };
123
+ return typesConfig || {};
124
+ }
125
+
126
+ //#endregion
127
+ export { getClientUtilsConfig, getDefaultPaths, getScaffoldConfig, getSdkConfig, getTypesConfig, replacePlaceholders, resolveFilePath, shouldGenerateClientUtils, shouldGenerateFile, shouldGenerateSDK, shouldGenerateScaffold, shouldGenerateTypes };
@@ -1,4 +1,4 @@
1
- import { NitroGraphQLOptions } from "../types/index.js";
1
+ import { NitroGraphQLOptions } from "../types/index.mjs";
2
2
  import { GraphQLSchema } from "graphql";
3
3
 
4
4
  //#region src/utils/server-codegen.d.ts
@@ -1,5 +1,5 @@
1
- import consola from "consola";
2
1
  import { defu as defu$1 } from "defu";
2
+ import consola from "consola";
3
3
  import { parse } from "graphql";
4
4
  import { printSchemaWithDirectives } from "@graphql-tools/utils";
5
5
  import { codegen } from "@graphql-codegen/core";
@@ -37,7 +37,7 @@ async function generateTypes(selectFremework, schema, config = {}, outputPath) {
37
37
  },
38
38
  defaultScalarType: "unknown",
39
39
  defaultMapper: `ResolverReturnType<{T}>`,
40
- contextType: "h3#H3Event",
40
+ contextType: "nitro/h3#H3Event",
41
41
  maybeValue: "T | null | undefined",
42
42
  inputMaybeValue: "T | undefined",
43
43
  declarationKind: "interface",
@@ -61,7 +61,7 @@ async function generateTypes(selectFremework, schema, config = {}, outputPath) {
61
61
  return {
62
62
  prepend: [
63
63
  `import schemas from '#graphql/schema'`,
64
- `import type { StandardSchemaV1 } from 'nitro-graphql'`,
64
+ `import type { StandardSchemaV1 } from 'nitro-graphql/types'`,
65
65
  `
66
66
  export interface NPMConfig {
67
67
  framework: '${selectFremework || "graphql-yoga"}';
@@ -0,0 +1,12 @@
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 };
@@ -0,0 +1,420 @@
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";
12
+
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 };
@@ -0,0 +1,9 @@
1
+ //#region src/virtual/debug-info.d.ts
2
+ /**
3
+ * Virtual module stub for #nitro-graphql/debug-info
4
+ * This file is only used during build/bundling to prevent import resolution errors.
5
+ * At runtime, Nitro will override this with the actual virtual module.
6
+ */
7
+ declare const debugInfo: Record<string, any>;
8
+ //#endregion
9
+ export { debugInfo };
@@ -0,0 +1,26 @@
1
+ //#region src/virtual/debug-info.ts
2
+ /**
3
+ * Virtual module stub for #nitro-graphql/debug-info
4
+ * This file is only used during build/bundling to prevent import resolution errors.
5
+ * At runtime, Nitro will override this with the actual virtual module.
6
+ */
7
+ const debugInfo = {
8
+ isDev: false,
9
+ framework: "",
10
+ graphqlFramework: "",
11
+ federation: {},
12
+ scanned: {
13
+ schemas: 0,
14
+ schemaFiles: [],
15
+ resolvers: 0,
16
+ resolverFiles: [],
17
+ directives: 0,
18
+ directiveFiles: [],
19
+ documents: 0,
20
+ documentFiles: []
21
+ },
22
+ virtualModules: {}
23
+ };
24
+
25
+ //#endregion
26
+ export { debugInfo };
@@ -0,0 +1,9 @@
1
+ //#region src/virtual/graphql-config.d.ts
2
+ /**
3
+ * Virtual module stub for #nitro-graphql/graphql-config
4
+ * This file is only used during build/bundling to prevent import resolution errors.
5
+ * At runtime, Nitro will override this with the actual virtual module.
6
+ */
7
+ declare const importedConfig: {};
8
+ //#endregion
9
+ export { importedConfig };
@@ -0,0 +1,10 @@
1
+ //#region src/virtual/graphql-config.ts
2
+ /**
3
+ * Virtual module stub for #nitro-graphql/graphql-config
4
+ * This file is only used during build/bundling to prevent import resolution errors.
5
+ * At runtime, Nitro will override this with the actual virtual module.
6
+ */
7
+ const importedConfig = {};
8
+
9
+ //#endregion
10
+ export { importedConfig };
@@ -0,0 +1,9 @@
1
+ //#region src/virtual/module-config.d.ts
2
+ /**
3
+ * Virtual module stub for #nitro-graphql/module-config
4
+ * This file is only used during build/bundling to prevent import resolution errors.
5
+ * At runtime, Nitro will override this with the actual virtual module.
6
+ */
7
+ declare const moduleConfig: Record<string, any>;
8
+ //#endregion
9
+ export { moduleConfig };
@@ -0,0 +1,10 @@
1
+ //#region src/virtual/module-config.ts
2
+ /**
3
+ * Virtual module stub for #nitro-graphql/module-config
4
+ * This file is only used during build/bundling to prevent import resolution errors.
5
+ * At runtime, Nitro will override this with the actual virtual module.
6
+ */
7
+ const moduleConfig = {};
8
+
9
+ //#endregion
10
+ export { moduleConfig };