nitro-graphql 2.0.0-beta.4 → 2.0.0-beta.6

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.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { StandardSchemaV1 } from "./types/standard-schema.js";
2
- import { CodegenClientConfig, CodegenServerConfig, ExternalGraphQLService, FederationConfig, GenImport, GenericSdkConfig, NitroGraphQLOptions } from "./types/index.js";
3
- import * as nitro_types0 from "nitro/types";
2
+ import { ClientUtilsConfig, CodegenClientConfig, CodegenServerConfig, ExternalGraphQLService, ExternalServicePaths, FederationConfig, FileGenerationConfig, GenImport, GenericSdkConfig, NitroGraphQLOptions, PathsConfig, ScaffoldConfig, SdkConfig, TypesConfig } from "./types/index.js";
3
+ import * as nitropack0 from "nitropack";
4
4
 
5
5
  //#region src/index.d.ts
6
- declare const _default: nitro_types0.NitroModule;
6
+ declare const _default: nitropack0.NitroModule;
7
7
  //#endregion
8
- export { CodegenClientConfig, CodegenServerConfig, ExternalGraphQLService, FederationConfig, GenImport, GenericSdkConfig, NitroGraphQLOptions, StandardSchemaV1, _default as default };
8
+ export { ClientUtilsConfig, CodegenClientConfig, CodegenServerConfig, ExternalGraphQLService, ExternalServicePaths, FederationConfig, FileGenerationConfig, GenImport, GenericSdkConfig, NitroGraphQLOptions, PathsConfig, ScaffoldConfig, SdkConfig, StandardSchemaV1, TypesConfig, _default as default };
package/dist/index.js CHANGED
@@ -1,8 +1,10 @@
1
1
  import { generateDirectiveSchemas } from "./utils/directive-parser.js";
2
2
  import { generateLayerIgnorePatterns, getLayerAppDirectories, getLayerServerDirectories, relativeWithDot, scanDirectives, scanDocs, scanResolvers, scanSchemas, validateExternalServices } from "./utils/index.js";
3
+ import { writeFileIfNotExists } from "./utils/file-generator.js";
4
+ import { getDefaultPaths, getScaffoldConfig, resolveFilePath, shouldGenerateScaffold } from "./utils/path-resolver.js";
3
5
  import { clientTypeGeneration, serverTypeGeneration } from "./utils/type-generation.js";
4
6
  import { rollupConfig } from "./rollup.js";
5
- import { existsSync, mkdirSync, writeFileSync } from "node:fs";
7
+ import { existsSync, mkdirSync } from "node:fs";
6
8
  import { fileURLToPath } from "node:url";
7
9
  import { watch } from "chokidar";
8
10
  import consola from "consola";
@@ -111,12 +113,53 @@ var src_default = defineNitroModule({
111
113
  nitro.scanDirectives = directives;
112
114
  await generateDirectiveSchemas(nitro, directives);
113
115
  nitro.hooks.hook("dev:start", async () => {
114
- nitro.scanSchemas = await scanSchemas(nitro);
115
- nitro.scanResolvers = await scanResolvers(nitro);
116
+ const schemas = await scanSchemas(nitro);
117
+ nitro.scanSchemas = schemas;
118
+ const resolvers = await scanResolvers(nitro);
119
+ nitro.scanResolvers = resolvers;
116
120
  const directives$1 = await scanDirectives(nitro);
117
121
  nitro.scanDirectives = directives$1;
118
122
  await generateDirectiveSchemas(nitro, directives$1);
119
- nitro.scanDocuments = await scanDocs(nitro);
123
+ const docs = await scanDocs(nitro);
124
+ nitro.scanDocuments = docs;
125
+ if (nitro.options.dev) {
126
+ consola.box({
127
+ title: "Nitro GraphQL",
128
+ message: [
129
+ `Framework: ${nitro.options.graphql?.framework || "Not configured"}`,
130
+ `Schemas: ${schemas.length}`,
131
+ `Resolvers: ${resolvers.length}`,
132
+ `Directives: ${directives$1.length}`,
133
+ `Documents: ${docs.length}`,
134
+ "",
135
+ "Debug Dashboard: /_nitro/graphql/debug"
136
+ ].join("\n"),
137
+ style: {
138
+ borderColor: "cyan",
139
+ borderStyle: "rounded"
140
+ }
141
+ });
142
+ if (resolvers.length > 0) {
143
+ const totalExports = resolvers.reduce((sum, r) => sum + r.imports.length, 0);
144
+ const typeCount = {
145
+ query: 0,
146
+ mutation: 0,
147
+ resolver: 0,
148
+ type: 0,
149
+ subscription: 0,
150
+ directive: 0
151
+ };
152
+ for (const resolver of resolvers) for (const imp of resolver.imports) if (imp.type in typeCount) typeCount[imp.type]++;
153
+ const breakdown = [];
154
+ if (typeCount.query > 0) breakdown.push(`${typeCount.query} query`);
155
+ if (typeCount.mutation > 0) breakdown.push(`${typeCount.mutation} mutation`);
156
+ if (typeCount.resolver > 0) breakdown.push(`${typeCount.resolver} resolver`);
157
+ if (typeCount.type > 0) breakdown.push(`${typeCount.type} type`);
158
+ if (typeCount.subscription > 0) breakdown.push(`${typeCount.subscription} subscription`);
159
+ if (typeCount.directive > 0) breakdown.push(`${typeCount.directive} directive`);
160
+ if (breakdown.length > 0) consola.success(`[nitro-graphql] ${totalExports} resolver export(s): ${breakdown.join(", ")}`);
161
+ } else consola.warn("[nitro-graphql] No resolvers found. Check /_nitro/graphql/debug for details.");
162
+ }
120
163
  });
121
164
  await rollupConfig(nitro);
122
165
  await serverTypeGeneration(nitro);
@@ -146,6 +189,14 @@ var src_default = defineNitroModule({
146
189
  handler: join(runtime, "health"),
147
190
  method: "GET"
148
191
  });
192
+ if (nitro.options.dev) {
193
+ nitro.options.handlers.push({
194
+ route: "/_nitro/graphql/debug",
195
+ handler: join(runtime, "debug"),
196
+ method: "get"
197
+ });
198
+ consola.info("[nitro-graphql] Debug dashboard available at: /_nitro/graphql/debug");
199
+ }
149
200
  if (nitro.options.imports) {
150
201
  nitro.options.imports.presets ??= [];
151
202
  nitro.options.imports.presets.push({
@@ -193,34 +244,36 @@ var src_default = defineNitroModule({
193
244
  const nuxtOptions = nitro._nuxt?.options;
194
245
  if (nuxtOptions) nuxtOptions.nitroGraphqlExternalServices = nitro.options.graphql?.externalServices || [];
195
246
  });
196
- if (!existsSync(join(nitro.options.rootDir, "graphql.config.ts"))) {
197
- const schemaPath = relativeWithDot(nitro.options.rootDir, resolve(nitro.graphql.buildDir, "schema.graphql"));
198
- const documentsPath = relativeWithDot(nitro.options.rootDir, resolve(nitro.graphql.clientDir, "**/*.{graphql,js,ts,jsx,tsx}"));
199
- writeFileSync(join(nitro.options.rootDir, "graphql.config.ts"), `
247
+ if (shouldGenerateScaffold(nitro)) {
248
+ const placeholders = getDefaultPaths(nitro);
249
+ const scaffoldConfig = getScaffoldConfig(nitro);
250
+ const graphqlConfigPath = resolveFilePath(scaffoldConfig.graphqlConfig, scaffoldConfig.enabled, true, "graphql.config.ts", placeholders);
251
+ if (graphqlConfigPath) writeFileIfNotExists(graphqlConfigPath, `
200
252
  import type { IGraphQLConfig } from 'graphql-config'
201
253
 
202
254
  export default <IGraphQLConfig> {
203
255
  projects: {
204
256
  default: {
205
257
  schema: [
206
- '${schemaPath}',
258
+ '${relativeWithDot(nitro.options.rootDir, resolve(nitro.graphql.buildDir, "schema.graphql"))}',
207
259
  ],
208
260
  documents: [
209
- '${documentsPath}',
261
+ '${relativeWithDot(nitro.options.rootDir, resolve(nitro.graphql.clientDir, "**/*.{graphql,js,ts,jsx,tsx}"))}',
210
262
  ],
211
263
  },
212
264
  },
213
- }`, "utf-8");
214
- }
215
- if (!existsSync(nitro.graphql.serverDir)) mkdirSync(nitro.graphql.serverDir, { recursive: true });
216
- if (!existsSync(join(nitro.graphql.serverDir, "schema.ts"))) writeFileSync(join(nitro.graphql.serverDir, "schema.ts"), `
217
- import { defineSchema } from 'nitro-graphql/utils/define'
218
-
219
- export default defineSchema({
265
+ }`, "graphql.config.ts");
266
+ const serverSchemaPath = resolveFilePath(scaffoldConfig.serverSchema, scaffoldConfig.enabled, true, "{serverGraphql}/schema.ts", placeholders);
267
+ const serverConfigPath = resolveFilePath(scaffoldConfig.serverConfig, scaffoldConfig.enabled, true, "{serverGraphql}/config.ts", placeholders);
268
+ const serverContextPath = resolveFilePath(scaffoldConfig.serverContext, scaffoldConfig.enabled, true, "{serverGraphql}/context.ts", placeholders);
269
+ if (serverSchemaPath || serverConfigPath || serverContextPath) {
270
+ if (!existsSync(nitro.graphql.serverDir)) mkdirSync(nitro.graphql.serverDir, { recursive: true });
271
+ }
272
+ if (serverSchemaPath) writeFileIfNotExists(serverSchemaPath, `export default defineSchema({
220
273
 
221
274
  })
222
- `, "utf-8");
223
- if (!existsSync(join(nitro.graphql.serverDir, "config.ts"))) writeFileSync(join(nitro.graphql.serverDir, "config.ts"), `// Example GraphQL config file please change it to your needs
275
+ `, "server schema.ts");
276
+ if (serverConfigPath) writeFileIfNotExists(serverConfigPath, `// Example GraphQL config file please change it to your needs
224
277
  // import * as tables from '../drizzle/schema/index'
225
278
  // import { useDatabase } from '../utils/useDb'
226
279
  import { defineGraphQLConfig } from 'nitro-graphql/utils/define'
@@ -236,8 +289,8 @@ export default defineGraphQLConfig({
236
289
  // }
237
290
  // },
238
291
  })
239
- `, "utf-8");
240
- if (!existsSync(join(nitro.graphql.serverDir, "context.ts"))) writeFileSync(join(nitro.graphql.serverDir, "context.ts"), `// Example context definition - please change it to your needs
292
+ `, "server config.ts");
293
+ if (serverContextPath) writeFileIfNotExists(serverContextPath, `// Example context definition - please change it to your needs
241
294
  // import type { Database } from '../utils/useDb'
242
295
 
243
296
  declare module 'h3' {
@@ -252,11 +305,12 @@ declare module 'h3' {
252
305
  // }
253
306
  // }
254
307
  }
255
- }`, "utf-8");
256
- if (existsSync(join(nitro.graphql.serverDir, "context.d.ts"))) {
257
- consola.warn("nitro-graphql: Found context.d.ts file. Please rename it to context.ts for the new structure.");
258
- consola.info("The context file should now be context.ts instead of context.d.ts");
259
- }
308
+ }`, "server context.ts");
309
+ if (existsSync(join(nitro.graphql.serverDir, "context.d.ts"))) {
310
+ consola.warn("nitro-graphql: Found context.d.ts file. Please rename it to context.ts for the new structure.");
311
+ consola.info("The context file should now be context.ts instead of context.d.ts");
312
+ }
313
+ } else consola.info("[nitro-graphql] Scaffold file generation is disabled (library mode)");
260
314
  }
261
315
  });
262
316
 
package/dist/rollup.js CHANGED
@@ -12,15 +12,15 @@ async function rollupConfig(app) {
12
12
  virtualDirectives(app);
13
13
  getGraphQLConfig(app);
14
14
  virtualModuleConfig(app);
15
+ virtualDebugInfo(app);
15
16
  app.hooks.hook("rollup:before", (nitro, rollupConfig$1) => {
16
17
  rollupConfig$1.plugins = rollupConfig$1.plugins || [];
17
- const { include = /\.(graphql|gql)$/i, exclude, validate = false } = app.options.graphql?.loader || {};
18
+ const { include = /\.(?:graphql|gql)$/i, exclude, validate = false } = app.options.graphql?.loader || {};
18
19
  if (Array.isArray(rollupConfig$1.plugins)) {
19
20
  rollupConfig$1.plugins.push({
20
21
  name: "nitro-graphql",
21
- enforce: "pre",
22
22
  resolveId(id) {
23
- if (/\.(graphql|gql)$/i.test(id)) return null;
23
+ if (/\.(?:graphql|gql)$/i.test(id)) return null;
24
24
  },
25
25
  async load(id) {
26
26
  if (exclude?.test?.(id)) return null;
@@ -38,7 +38,6 @@ async function rollupConfig(app) {
38
38
  });
39
39
  rollupConfig$1.plugins.push({
40
40
  name: "nitro-graphql-watcher",
41
- enforce: "pre",
42
41
  async buildStart() {
43
42
  const graphqlFiles = await scanGraphql(nitro);
44
43
  for (const file of graphqlFiles) this.addWatchFile(file);
@@ -55,46 +54,120 @@ function virtualSchemas(app) {
55
54
  const getSchemas = () => [...app.scanSchemas, ...app.options.graphql?.typedefs ?? []];
56
55
  app.options.virtual ??= {};
57
56
  app.options.virtual["#nitro-internal-virtual/server-schemas"] = () => {
58
- const imports = getSchemas();
59
- return `
60
- ${imports.map((handler) => `import ${getImportId(handler)} from '${handler}';`).join("\n")}
57
+ try {
58
+ const imports = getSchemas();
59
+ if (imports.length === 0) {
60
+ if (app.options.dev) app.logger.warn("[nitro-graphql] No schemas found. Virtual module will export empty array.");
61
+ return "export const schemas = []";
62
+ }
63
+ const importStatements = imports.map((handler) => `import ${getImportId(handler)} from '${handler}';`);
64
+ const schemaArray = imports.map((h) => `{ def: ${getImportId(h)} }`);
65
+ const code = `
66
+ ${importStatements.join("\n")}
61
67
 
62
68
  export const schemas = [
63
- ${imports.map((h) => `{ def: ${getImportId(h)} }`).join(",\n")}
69
+ ${schemaArray.join(",\n")}
64
70
  ];
65
71
  `;
72
+ if (app.options.dev) app.logger.success(`[nitro-graphql] Generated virtual schema module: ${imports.length} schema(s)`);
73
+ return code;
74
+ } catch (error) {
75
+ app.logger.error("[nitro-graphql] Failed to generate virtual schema module:", error);
76
+ return "export const schemas = []";
77
+ }
66
78
  };
67
79
  }
68
80
  function virtualResolvers(app) {
69
81
  const getResolvers = () => [...app.scanResolvers];
70
82
  app.options.virtual ??= {};
71
83
  app.options.virtual["#nitro-internal-virtual/server-resolvers"] = () => {
72
- const imports = getResolvers();
73
- const importsContent = imports.map(({ specifier, imports: imports$1, options }) => genImport(specifier, imports$1, options));
74
- const data = imports.map(({ imports: imports$1 }) => imports$1.map((i) => `{ resolver: ${i.as} }`).join(",\n")).filter(Boolean).join(",\n");
75
- return [
76
- ...importsContent,
77
- "export const resolvers = [",
78
- data,
79
- "]",
80
- ""
81
- ].join("\n");
84
+ try {
85
+ const imports = getResolvers();
86
+ if (imports.length === 0) {
87
+ if (app.options.dev) app.logger.warn("[nitro-graphql] No resolvers found. Virtual module will export empty array.");
88
+ return "export const resolvers = []";
89
+ }
90
+ const importsContent = [];
91
+ const invalidImports = [];
92
+ for (const { specifier, imports: importList, options } of imports) try {
93
+ if (!importList || importList.length === 0) {
94
+ invalidImports.push(`${specifier}: No exports found`);
95
+ continue;
96
+ }
97
+ const importCode = genImport(specifier, importList, options);
98
+ importsContent.push(importCode);
99
+ } catch (error) {
100
+ const message = error instanceof Error ? error.message : String(error);
101
+ invalidImports.push(`${specifier}: ${message}`);
102
+ if (app.options.dev) app.logger.error(`[nitro-graphql] Failed to generate import for ${specifier}:`, error);
103
+ }
104
+ if (invalidImports.length > 0 && app.options.dev) {
105
+ app.logger.warn("[nitro-graphql] Some resolver imports could not be generated:");
106
+ for (const msg of invalidImports) app.logger.warn(` - ${msg}`);
107
+ }
108
+ const data = imports.map(({ imports: importList }) => importList.map((i) => `{ resolver: ${i.as} }`).join(",\n")).filter(Boolean).join(",\n");
109
+ const code = [
110
+ ...importsContent,
111
+ "",
112
+ "export const resolvers = [",
113
+ data,
114
+ "]",
115
+ ""
116
+ ].join("\n");
117
+ if (app.options.dev) {
118
+ const totalExports = imports.reduce((sum, r) => sum + r.imports.length, 0);
119
+ app.logger.success(`[nitro-graphql] Generated virtual resolver module: ${totalExports} export(s) from ${imports.length} file(s)`);
120
+ }
121
+ return code;
122
+ } catch (error) {
123
+ app.logger.error("[nitro-graphql] Failed to generate virtual resolver module:", error);
124
+ return "export const resolvers = []";
125
+ }
82
126
  };
83
127
  }
84
128
  function virtualDirectives(app) {
85
129
  const getDirectives = () => app.scanDirectives || [];
86
130
  app.options.virtual ??= {};
87
131
  app.options.virtual["#nitro-internal-virtual/server-directives"] = () => {
88
- const imports = getDirectives();
89
- const importsContent = imports.map(({ specifier, imports: imports$1, options }) => genImport(specifier, imports$1, options));
90
- const data = imports.map(({ imports: imports$1 }) => imports$1.map((i) => `{ directive: ${i.as} }`).join(",\n")).filter(Boolean).join(",\n");
91
- return [
92
- ...importsContent,
93
- "export const directives = [",
94
- data,
95
- "]",
96
- ""
97
- ].join("\n");
132
+ try {
133
+ const imports = getDirectives();
134
+ if (imports.length === 0) return "export const directives = []";
135
+ const importsContent = [];
136
+ const invalidImports = [];
137
+ for (const { specifier, imports: importList, options } of imports) try {
138
+ if (!importList || importList.length === 0) {
139
+ invalidImports.push(`${specifier}: No exports found`);
140
+ continue;
141
+ }
142
+ const importCode = genImport(specifier, importList, options);
143
+ importsContent.push(importCode);
144
+ } catch (error) {
145
+ const message = error instanceof Error ? error.message : String(error);
146
+ invalidImports.push(`${specifier}: ${message}`);
147
+ if (app.options.dev) app.logger.error(`[nitro-graphql] Failed to generate import for directive ${specifier}:`, error);
148
+ }
149
+ if (invalidImports.length > 0 && app.options.dev) {
150
+ app.logger.warn("[nitro-graphql] Some directive imports could not be generated:");
151
+ for (const msg of invalidImports) app.logger.warn(` - ${msg}`);
152
+ }
153
+ const data = imports.map(({ imports: importList }) => importList.map((i) => `{ directive: ${i.as} }`).join(",\n")).filter(Boolean).join(",\n");
154
+ const code = [
155
+ ...importsContent,
156
+ "",
157
+ "export const directives = [",
158
+ data,
159
+ "]",
160
+ ""
161
+ ].join("\n");
162
+ if (app.options.dev) {
163
+ const totalExports = imports.reduce((sum, d) => sum + d.imports.length, 0);
164
+ app.logger.success(`[nitro-graphql] Generated virtual directive module: ${totalExports} directive(s) from ${imports.length} file(s)`);
165
+ }
166
+ return code;
167
+ } catch (error) {
168
+ app.logger.error("[nitro-graphql] Failed to generate virtual directive module:", error);
169
+ return "export const directives = []";
170
+ }
98
171
  };
99
172
  }
100
173
  function getGraphQLConfig(app) {
@@ -114,6 +187,60 @@ function virtualModuleConfig(app) {
114
187
  return `export const moduleConfig = ${JSON.stringify(moduleConfig, null, 2)};`;
115
188
  };
116
189
  }
190
+ function virtualDebugInfo(app) {
191
+ app.options.virtual ??= {};
192
+ app.options.virtual["#nitro-internal-virtual/debug-info"] = () => {
193
+ const virtualModuleCodes = {};
194
+ try {
195
+ const schemasGenerator = app.options.virtual["#nitro-internal-virtual/server-schemas"];
196
+ if (schemasGenerator && typeof schemasGenerator === "function") virtualModuleCodes["server-schemas"] = schemasGenerator();
197
+ } catch (error) {
198
+ virtualModuleCodes["server-schemas"] = `// Error generating: ${error instanceof Error ? error.message : String(error)}`;
199
+ }
200
+ try {
201
+ const resolversGenerator = app.options.virtual["#nitro-internal-virtual/server-resolvers"];
202
+ if (resolversGenerator && typeof resolversGenerator === "function") virtualModuleCodes["server-resolvers"] = resolversGenerator();
203
+ } catch (error) {
204
+ virtualModuleCodes["server-resolvers"] = `// Error generating: ${error instanceof Error ? error.message : String(error)}`;
205
+ }
206
+ try {
207
+ const directivesGenerator = app.options.virtual["#nitro-internal-virtual/server-directives"];
208
+ if (directivesGenerator && typeof directivesGenerator === "function") virtualModuleCodes["server-directives"] = directivesGenerator();
209
+ } catch (error) {
210
+ virtualModuleCodes["server-directives"] = `// Error generating: ${error instanceof Error ? error.message : String(error)}`;
211
+ }
212
+ try {
213
+ const moduleConfigGenerator = app.options.virtual["#nitro-internal-virtual/module-config"];
214
+ if (moduleConfigGenerator && typeof moduleConfigGenerator === "function") virtualModuleCodes["module-config"] = moduleConfigGenerator();
215
+ } catch (error) {
216
+ virtualModuleCodes["module-config"] = `// Error generating: ${error instanceof Error ? error.message : String(error)}`;
217
+ }
218
+ try {
219
+ const graphqlConfigGenerator = app.options.virtual["#nitro-internal-virtual/graphql-config"];
220
+ if (graphqlConfigGenerator && typeof graphqlConfigGenerator === "function") virtualModuleCodes["graphql-config"] = graphqlConfigGenerator();
221
+ } catch (error) {
222
+ virtualModuleCodes["graphql-config"] = `// Error generating: ${error instanceof Error ? error.message : String(error)}`;
223
+ }
224
+ const debugInfo = {
225
+ isDev: app.options.dev,
226
+ framework: app.options.framework.name,
227
+ graphqlFramework: app.options.graphql?.framework,
228
+ federation: app.options.graphql?.federation,
229
+ scanned: {
230
+ schemas: app.scanSchemas?.length || 0,
231
+ schemaFiles: app.scanSchemas || [],
232
+ resolvers: app.scanResolvers?.length || 0,
233
+ resolverFiles: app.scanResolvers || [],
234
+ directives: app.scanDirectives?.length || 0,
235
+ directiveFiles: app.scanDirectives || [],
236
+ documents: app.scanDocuments?.length || 0,
237
+ documentFiles: app.scanDocuments || []
238
+ },
239
+ virtualModules: virtualModuleCodes
240
+ };
241
+ return `export const debugInfo = ${JSON.stringify(debugInfo, null, 2)};`;
242
+ };
243
+ }
117
244
 
118
245
  //#endregion
119
246
  export { rollupConfig };
@@ -0,0 +1,15 @@
1
+ import * as h35 from "h3";
2
+
3
+ //#region src/routes/debug.d.ts
4
+
5
+ /**
6
+ * Debug endpoint for inspecting virtual modules and GraphQL setup
7
+ * Only available in development mode
8
+ *
9
+ * Routes:
10
+ * - /_nitro/graphql/debug - HTML dashboard
11
+ * - /_nitro/graphql/debug?format=json - JSON API
12
+ */
13
+ declare const _default: h35.EventHandler<h35.EventHandlerRequest, unknown>;
14
+ //#endregion
15
+ export { _default as default };