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

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 (38) hide show
  1. package/dist/codegen/client-types.d.mts +13 -0
  2. package/dist/codegen/client-types.mjs +176 -0
  3. package/dist/codegen/external-types.d.mts +12 -0
  4. package/dist/codegen/external-types.mjs +129 -0
  5. package/dist/codegen/index.d.mts +25 -0
  6. package/dist/codegen/index.mjs +38 -0
  7. package/dist/codegen/server-types.d.mts +13 -0
  8. package/dist/codegen/server-types.mjs +76 -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.mjs +91 -0
  13. package/dist/ecosystem/nuxt.mjs +3 -3
  14. package/dist/rollup.d.mts +7 -7
  15. package/dist/rollup.mjs +73 -73
  16. package/dist/routes/apollo-server.d.mts +2 -2
  17. package/dist/routes/debug.d.mts +2 -2
  18. package/dist/routes/health.d.mts +2 -2
  19. package/dist/setup/file-watcher.mjs +80 -0
  20. package/dist/setup/rollup-integration.mjs +90 -0
  21. package/dist/setup/scaffold-generator.mjs +109 -0
  22. package/dist/setup/ts-config.mjs +69 -0
  23. package/dist/setup.d.mts +2 -2
  24. package/dist/setup.mjs +127 -274
  25. package/dist/types/index.d.mts +1 -1
  26. package/dist/utils/client-codegen.d.mts +1 -1
  27. package/dist/utils/client-codegen.mjs +5 -2
  28. package/dist/utils/directive-parser.d.mts +2 -1
  29. package/dist/utils/directive-parser.mjs +4 -2
  30. package/dist/utils/file-generator.mjs +1 -1
  31. package/dist/utils/index.d.mts +2 -2
  32. package/dist/utils/index.mjs +2 -2
  33. package/dist/utils/path-resolver.d.mts +2 -2
  34. package/dist/utils/path-resolver.mjs +2 -2
  35. package/dist/utils/server-codegen.mjs +4 -1
  36. package/dist/utils/type-generation.d.mts +6 -12
  37. package/dist/utils/type-generation.mjs +6 -419
  38. package/package.json +8 -2
@@ -0,0 +1,109 @@
1
+ import { FILE_CONFIG_TS, FILE_CONTEXT_DTS, FILE_CONTEXT_TS, FILE_GRAPHQL_CONFIG, FILE_SCHEMA_TS, LOG_TAG } from "../constants.mjs";
2
+ import { relativeWithDot } from "../utils/index.mjs";
3
+ import { writeFileIfNotExists } from "../utils/file-generator.mjs";
4
+ import { getDefaultPaths, getScaffoldConfig, resolveFilePath, shouldGenerateScaffold } from "../utils/path-resolver.mjs";
5
+ import consola from "consola";
6
+ import { join, resolve } from "pathe";
7
+ import { existsSync, mkdirSync } from "node:fs";
8
+
9
+ //#region src/setup/scaffold-generator.ts
10
+ const logger = consola.withTag(LOG_TAG);
11
+ /**
12
+ * Generate all scaffold files based on configuration
13
+ * Can be disabled via: scaffold: false or scaffold.enabled: false
14
+ */
15
+ function generateScaffoldFiles(nitro) {
16
+ if (!shouldGenerateScaffold(nitro)) {
17
+ logger.info("Scaffold file generation is disabled (library mode)");
18
+ return;
19
+ }
20
+ const placeholders = getDefaultPaths(nitro);
21
+ const scaffoldConfig = getScaffoldConfig(nitro);
22
+ generateGraphQLConfig(nitro, scaffoldConfig, placeholders);
23
+ generateServerScaffoldFiles(nitro, scaffoldConfig, placeholders);
24
+ checkOldContextFile(nitro);
25
+ }
26
+ /**
27
+ * Generate graphql.config.ts for IDE tooling support
28
+ */
29
+ function generateGraphQLConfig(nitro, scaffoldConfig, placeholders) {
30
+ const graphqlConfigPath = resolveFilePath(scaffoldConfig.graphqlConfig, scaffoldConfig.enabled, true, FILE_GRAPHQL_CONFIG, placeholders);
31
+ if (!graphqlConfigPath) return;
32
+ writeFileIfNotExists(graphqlConfigPath, `import type { IGraphQLConfig } from 'graphql-config'
33
+
34
+ export default <IGraphQLConfig> {
35
+ projects: {
36
+ default: {
37
+ schema: [
38
+ '${relativeWithDot(nitro.options.rootDir, resolve(nitro.graphql.buildDir, "schema.graphql"))}',
39
+ ],
40
+ documents: [
41
+ '${relativeWithDot(nitro.options.rootDir, resolve(nitro.graphql.clientDir, "**/*.{graphql,js,ts,jsx,tsx}"))}',
42
+ ],
43
+ },
44
+ },
45
+ }`, FILE_GRAPHQL_CONFIG);
46
+ }
47
+ /**
48
+ * Generate server-side scaffold files (schema.ts, config.ts, context.d.ts)
49
+ */
50
+ function generateServerScaffoldFiles(nitro, scaffoldConfig, placeholders) {
51
+ const serverSchemaPath = resolveFilePath(scaffoldConfig.serverSchema, scaffoldConfig.enabled, true, "{serverGraphql}/schema.ts", placeholders);
52
+ const serverConfigPath = resolveFilePath(scaffoldConfig.serverConfig, scaffoldConfig.enabled, true, "{serverGraphql}/config.ts", placeholders);
53
+ const serverContextPath = resolveFilePath(scaffoldConfig.serverContext, scaffoldConfig.enabled, true, "{serverGraphql}/context.d.ts", placeholders);
54
+ if (serverSchemaPath || serverConfigPath || serverContextPath) {
55
+ if (!existsSync(nitro.graphql.serverDir)) mkdirSync(nitro.graphql.serverDir, { recursive: true });
56
+ }
57
+ if (serverSchemaPath) writeFileIfNotExists(serverSchemaPath, `export default defineSchema({
58
+
59
+ })
60
+ `, `server ${FILE_SCHEMA_TS}`);
61
+ if (serverConfigPath) writeFileIfNotExists(serverConfigPath, `// Example GraphQL config file please change it to your needs
62
+ // import * as tables from '../drizzle/schema/index'
63
+ // import { useDatabase } from '../utils/useDb'
64
+ import { defineGraphQLConfig } from 'nitro-graphql/define'
65
+
66
+ export default defineGraphQLConfig({
67
+ // graphql-yoga example config
68
+ // context: () => {
69
+ // return {
70
+ // context: {
71
+ // useDatabase,
72
+ // tables,
73
+ // },
74
+ // }
75
+ // },
76
+ })
77
+ `, `server ${FILE_CONFIG_TS}`);
78
+ if (serverContextPath) writeFileIfNotExists(serverContextPath, `// Example context definition - please change it to your needs
79
+ // import type { Database } from '../utils/useDb'
80
+
81
+ declare module 'nitro/h3' {
82
+ interface H3EventContext {
83
+ // Add your custom context properties here
84
+ // useDatabase: () => Database
85
+ // tables: typeof import('../drizzle/schema')
86
+ // auth?: {
87
+ // user?: {
88
+ // id: string
89
+ // role: 'admin' | 'user'
90
+ // }
91
+ // }
92
+ }
93
+ }
94
+
95
+ export {}
96
+ `, `server ${FILE_CONTEXT_DTS}`);
97
+ }
98
+ /**
99
+ * Check for old context.ts file and warn users to migrate to context.d.ts
100
+ */
101
+ function checkOldContextFile(nitro) {
102
+ if (existsSync(join(nitro.graphql.serverDir, FILE_CONTEXT_TS))) {
103
+ logger.warn(`Found ${FILE_CONTEXT_TS} file. Please rename it to ${FILE_CONTEXT_DTS} for type-only definitions.`);
104
+ logger.info(`The context file should now be ${FILE_CONTEXT_DTS} instead of ${FILE_CONTEXT_TS}`);
105
+ }
106
+ }
107
+
108
+ //#endregion
109
+ export { generateScaffoldFiles };
@@ -0,0 +1,69 @@
1
+ import { relativeWithDot } from "../utils/index.mjs";
2
+ import { getDefaultPaths, getTypesConfig, resolveFilePath } from "../utils/path-resolver.mjs";
3
+ import { dirname, join, resolve } from "pathe";
4
+
5
+ //#region src/setup/ts-config.ts
6
+ /**
7
+ * Setup TypeScript path aliases for GraphQL types
8
+ * Called via nitro:config hook to extend tsconfig.json
9
+ */
10
+ function setupTypeScriptPaths(nitro, types) {
11
+ const tsconfigDir = dirname(resolve(nitro.options.buildDir, nitro.options.typescript.tsconfigPath));
12
+ types.tsConfig ||= {};
13
+ types.tsConfig.compilerOptions ??= {};
14
+ types.tsConfig.compilerOptions.paths ??= {};
15
+ types.tsConfig.include = types.tsConfig.include || [];
16
+ const placeholders = getDefaultPaths(nitro);
17
+ const typesConfig = getTypesConfig(nitro);
18
+ setupServerTypesPath(nitro, types, tsconfigDir, placeholders, typesConfig);
19
+ setupClientTypesPath(nitro, types, tsconfigDir, placeholders, typesConfig);
20
+ setupSchemaPath(nitro, types, tsconfigDir);
21
+ setupExternalServicePaths(nitro, types, tsconfigDir, placeholders, typesConfig);
22
+ types.tsConfig.include.push(relativeWithDot(tsconfigDir, join(placeholders.typesDir, "graphql.d.ts")));
23
+ }
24
+ /**
25
+ * Setup #graphql/server path alias
26
+ */
27
+ function setupServerTypesPath(nitro, types, tsconfigDir, placeholders, typesConfig) {
28
+ const serverTypesPath = resolveFilePath(typesConfig.server, typesConfig.enabled, true, "{typesDir}/nitro-graphql-server.d.ts", placeholders);
29
+ if (serverTypesPath) {
30
+ types.tsConfig.compilerOptions.paths["#graphql/server"] = [relativeWithDot(tsconfigDir, serverTypesPath)];
31
+ types.tsConfig.include.push(relativeWithDot(tsconfigDir, serverTypesPath));
32
+ }
33
+ }
34
+ /**
35
+ * Setup #graphql/client path alias
36
+ */
37
+ function setupClientTypesPath(nitro, types, tsconfigDir, placeholders, typesConfig) {
38
+ const clientTypesPath = resolveFilePath(typesConfig.client, typesConfig.enabled, true, "{typesDir}/nitro-graphql-client.d.ts", placeholders);
39
+ if (clientTypesPath) {
40
+ types.tsConfig.compilerOptions.paths["#graphql/client"] = [relativeWithDot(tsconfigDir, clientTypesPath)];
41
+ types.tsConfig.include.push(relativeWithDot(tsconfigDir, clientTypesPath));
42
+ }
43
+ }
44
+ /**
45
+ * Setup #graphql/schema path alias
46
+ */
47
+ function setupSchemaPath(nitro, types, tsconfigDir) {
48
+ types.tsConfig.compilerOptions.paths["#graphql/schema"] = [relativeWithDot(tsconfigDir, join(nitro.graphql.serverDir, "schema.ts"))];
49
+ }
50
+ /**
51
+ * Setup #graphql/client/{serviceName} path aliases for external services
52
+ */
53
+ function setupExternalServicePaths(nitro, types, tsconfigDir, placeholders, typesConfig) {
54
+ if (!nitro.options.graphql?.externalServices?.length) return;
55
+ for (const service of nitro.options.graphql.externalServices) {
56
+ const servicePlaceholders = {
57
+ ...placeholders,
58
+ serviceName: service.name
59
+ };
60
+ const externalTypesPath = resolveFilePath(service.paths?.types ?? typesConfig.external, typesConfig.enabled, true, "{typesDir}/nitro-graphql-client-{serviceName}.d.ts", servicePlaceholders);
61
+ if (externalTypesPath) {
62
+ types.tsConfig.compilerOptions.paths[`#graphql/client/${service.name}`] = [relativeWithDot(tsconfigDir, externalTypesPath)];
63
+ types.tsConfig.include.push(relativeWithDot(tsconfigDir, externalTypesPath));
64
+ }
65
+ }
66
+ }
67
+
68
+ //#endregion
69
+ export { setupTypeScriptPaths };
package/dist/setup.d.mts CHANGED
@@ -3,8 +3,8 @@ import { Nitro } from "nitro/types";
3
3
  //#region src/setup.d.ts
4
4
 
5
5
  /**
6
- * Shared setup logic for nitro-graphql module
7
- * Used by both the direct Nitro module export and the Vite plugin's nitro: hook
6
+ * Main setup function for nitro-graphql
7
+ * Coordinates all initialization steps for the module
8
8
  */
9
9
  declare function setupNitroGraphQL(nitro: Nitro): Promise<void>;
10
10
  //#endregion
package/dist/setup.mjs CHANGED
@@ -1,40 +1,50 @@
1
+ import { ENDPOINT_DEBUG, FRAMEWORK_NITRO, FRAMEWORK_NUXT, GRAPHQL_HTTP_METHODS, LOG_TAG } from "./constants.mjs";
2
+ import { DEFAULT_RUNTIME_CONFIG, DEFAULT_TYPESCRIPT_STRICT, DEFAULT_TYPES_CONFIG } from "./config/defaults.mjs";
1
3
  import { generateDirectiveSchemas } from "./utils/directive-parser.mjs";
2
- import { generateLayerIgnorePatterns, getLayerAppDirectories, getLayerServerDirectories, relativeWithDot, scanDirectives, scanDocs, scanResolvers, scanSchemas, validateExternalServices } from "./utils/index.mjs";
3
- import { writeFileIfNotExists } from "./utils/file-generator.mjs";
4
- import { getScaffoldConfig, getTypesConfig, resolveFilePath, shouldGenerateScaffold } from "./utils/path-resolver.mjs";
5
- import { clientTypeGeneration, serverTypeGeneration } from "./utils/type-generation.mjs";
4
+ import { scanDirectives, scanDocuments, scanResolvers, scanSchemas, validateExternalServices } from "./utils/index.mjs";
5
+ import { getDefaultPaths } from "./utils/path-resolver.mjs";
6
+ import { clientTypeGeneration, serverTypeGeneration } from "./codegen/index.mjs";
6
7
  import { rollupConfig } from "./rollup.mjs";
8
+ import { getWatchDirectories, setupFileWatcher } from "./setup/file-watcher.mjs";
9
+ import { setupRollupChunking, setupRollupExternals } from "./setup/rollup-integration.mjs";
10
+ import { generateScaffoldFiles } from "./setup/scaffold-generator.mjs";
11
+ import { setupTypeScriptPaths } from "./setup/ts-config.mjs";
7
12
  import defu from "defu";
8
- import { existsSync, mkdirSync } from "node:fs";
9
13
  import { fileURLToPath } from "node:url";
10
- import { watch } from "chokidar";
11
14
  import consola from "consola";
12
- import { dirname, join, relative, resolve } from "pathe";
15
+ import { join, relative, resolve } from "pathe";
13
16
 
14
17
  //#region src/setup.ts
15
- const logger = consola.withTag("nitro-graphql");
18
+ const logger = consola.withTag(LOG_TAG);
16
19
  /**
17
- * Shared setup logic for nitro-graphql module
18
- * Used by both the direct Nitro module export and the Vite plugin's nitro: hook
20
+ * Main setup function for nitro-graphql
21
+ * Coordinates all initialization steps for the module
19
22
  */
20
23
  async function setupNitroGraphQL(nitro) {
24
+ initializeConfiguration(nitro);
25
+ validateConfiguration(nitro);
26
+ setupBuildDirectories(nitro);
27
+ setupRollupExternals(nitro);
28
+ setupRollupChunking(nitro);
29
+ initializeRuntimeConfig(nitro);
30
+ setupFileWatching(nitro);
31
+ await scanGraphQLFiles(nitro);
32
+ setupDevHooks(nitro);
33
+ await rollupConfig(nitro);
34
+ await generateTypes(nitro);
35
+ setupCloseHooks(nitro);
36
+ registerRouteHandlers(nitro);
37
+ setupTypeScriptConfiguration(nitro);
38
+ setupNuxtIntegration(nitro);
39
+ generateScaffoldFiles(nitro);
40
+ }
41
+ /**
42
+ * Initialize default configuration values
43
+ */
44
+ function initializeConfiguration(nitro) {
21
45
  nitro.options.graphql ||= {};
22
- nitro.options.graphql.types = defu(nitro.options.graphql.types, {
23
- server: ".graphql/nitro-graphql-server.d.ts",
24
- client: ".graphql/nitro-graphql-client.d.ts",
25
- enabled: true
26
- });
46
+ nitro.options.graphql.types = defu(nitro.options.graphql.types, DEFAULT_TYPES_CONFIG);
27
47
  if (!nitro.options.graphql?.framework) logger.warn("No GraphQL framework specified. Please set graphql.framework to \"graphql-yoga\" or \"apollo-server\".");
28
- if (nitro.options.graphql?.externalServices?.length) {
29
- const validationErrors = validateExternalServices(nitro.options.graphql.externalServices);
30
- if (validationErrors.length > 0) {
31
- logger.error("External services configuration errors:");
32
- for (const error of validationErrors) logger.error(` - ${error}`);
33
- throw new Error("Invalid external services configuration");
34
- }
35
- logger.info(`Configured ${nitro.options.graphql.externalServices.length} external GraphQL services`);
36
- }
37
- const { getDefaultPaths } = await import("./utils/path-resolver.mjs");
38
48
  const defaultPaths = getDefaultPaths(nitro);
39
49
  nitro.graphql ||= {
40
50
  buildDir: "",
@@ -47,100 +57,87 @@ async function setupNitroGraphQL(nitro) {
47
57
  server: "server"
48
58
  }
49
59
  };
50
- nitro.hooks.hook("rollup:before", (_, rollupConfig$1) => {
51
- rollupConfig$1.external = rollupConfig$1.external || [];
52
- const allExternals = [...["oxc-parser", "@oxc-parser"]];
53
- if (!nitro.options.graphql?.federation?.enabled) allExternals.push(...[
54
- "@apollo/subgraph",
55
- "@apollo/federation-internals",
56
- "@apollo/cache-control-types"
57
- ]);
58
- if (Array.isArray(rollupConfig$1.external)) rollupConfig$1.external.push(...allExternals);
59
- else if (typeof rollupConfig$1.external === "function") {
60
- const originalExternal = rollupConfig$1.external;
61
- rollupConfig$1.external = (id, parent, isResolved) => {
62
- if (allExternals.some((external) => id.includes(external))) return true;
63
- return originalExternal(id, parent, isResolved);
64
- };
60
+ }
61
+ /**
62
+ * Validate external services configuration
63
+ */
64
+ function validateConfiguration(nitro) {
65
+ if (nitro.options.graphql?.externalServices?.length) {
66
+ const validationErrors = validateExternalServices(nitro.options.graphql.externalServices);
67
+ if (validationErrors.length > 0) {
68
+ logger.error("External services configuration errors:");
69
+ for (const error of validationErrors) logger.error(` - ${error}`);
70
+ throw new Error("Invalid external services configuration");
65
71
  }
66
- });
67
- nitro.options.runtimeConfig.graphql = defu(nitro.options.runtimeConfig.graphql || {}, {
68
- endpoint: {
69
- graphql: "/api/graphql",
70
- healthCheck: "/api/graphql/health"
71
- },
72
- playground: true
73
- });
72
+ logger.info(`Configured ${nitro.options.graphql.externalServices.length} external GraphQL services`);
73
+ }
74
74
  if (nitro.options.graphql?.federation?.enabled) logger.info(`Apollo Federation enabled for service: ${nitro.options.graphql.federation.serviceName || "unnamed"}`);
75
+ }
76
+ /**
77
+ * Setup build directories
78
+ */
79
+ function setupBuildDirectories(nitro) {
75
80
  const graphqlBuildDir = resolve(nitro.options.buildDir, "graphql");
76
81
  nitro.graphql.buildDir = graphqlBuildDir;
77
- const watchDirs = [];
78
82
  switch (nitro.options.framework.name) {
79
- case "nuxt": {
83
+ case FRAMEWORK_NUXT:
80
84
  nitro.graphql.dir.client = relative(nitro.options.rootDir, nitro.graphql.clientDir);
81
85
  nitro.graphql.dir.server = relative(nitro.options.rootDir, nitro.graphql.serverDir);
82
- watchDirs.push(nitro.graphql.clientDir);
83
- const layerServerDirs = getLayerServerDirectories(nitro);
84
- const layerAppDirs = getLayerAppDirectories(nitro);
85
- for (const layerServerDir of layerServerDirs) watchDirs.push(join(layerServerDir, "graphql"));
86
- for (const layerAppDir of layerAppDirs) watchDirs.push(join(layerAppDir, "graphql"));
87
86
  break;
88
- }
89
- case "nitro":
87
+ case FRAMEWORK_NITRO:
90
88
  nitro.graphql.dir.client = relative(nitro.options.rootDir, nitro.graphql.clientDir);
91
89
  nitro.graphql.dir.server = relative(nitro.options.rootDir, nitro.graphql.serverDir);
92
- watchDirs.push(nitro.graphql.clientDir);
93
- watchDirs.push(nitro.graphql.serverDir);
94
90
  break;
95
- default:
91
+ default: break;
96
92
  }
97
- if (nitro.options.graphql?.externalServices?.length) {
98
- for (const service of nitro.options.graphql.externalServices) if (service.documents?.length) for (const pattern of service.documents) {
99
- if (!pattern) continue;
100
- const baseDir = pattern.split("**")[0]?.replace(/\/$/, "") || ".";
101
- const resolvedDir = resolve(nitro.options.rootDir, baseDir);
102
- if (!watchDirs.includes(resolvedDir)) watchDirs.push(resolvedDir);
103
- }
104
- }
105
- const watcher = watch(watchDirs, {
106
- persistent: true,
107
- ignoreInitial: true,
108
- ignored: [...nitro.options.ignore, ...generateLayerIgnorePatterns()]
109
- }).on("all", async (_, path) => {
110
- const isGraphQLFile = path.endsWith(".graphql") || path.endsWith(".gql");
111
- const isResolverFile = path.endsWith(".resolver.ts") || path.endsWith(".resolver.js");
112
- const isDirectiveFile = path.endsWith(".directive.ts") || path.endsWith(".directive.js");
113
- if (isGraphQLFile || isResolverFile || isDirectiveFile) if (path.includes(nitro.graphql.serverDir) || path.includes("server/graphql") || path.includes("server\\graphql") || isResolverFile || isDirectiveFile) {
114
- await scanResolvers(nitro).then((r) => nitro.scanResolvers = r);
115
- await scanDirectives(nitro).then((d) => nitro.scanDirectives = d);
116
- logger.success("Types regenerated");
117
- await serverTypeGeneration(nitro, { silent: true });
118
- await clientTypeGeneration(nitro, { silent: true });
119
- await nitro.hooks.callHook("dev:reload");
120
- } else {
121
- logger.success("Types regenerated");
122
- await clientTypeGeneration(nitro, { silent: true });
123
- }
124
- });
93
+ }
94
+ /**
95
+ * Initialize runtime configuration
96
+ */
97
+ function initializeRuntimeConfig(nitro) {
98
+ nitro.options.runtimeConfig.graphql = defu(nitro.options.runtimeConfig.graphql || {}, DEFAULT_RUNTIME_CONFIG);
99
+ }
100
+ /**
101
+ * Setup file watching for development mode
102
+ */
103
+ function setupFileWatching(nitro) {
104
+ const watchDirs = getWatchDirectories(nitro);
105
+ nitro.graphql.watchDirs = watchDirs;
106
+ const watcher = setupFileWatcher(nitro, watchDirs);
125
107
  nitro.hooks.hook("close", () => {
126
108
  watcher.close();
127
109
  });
128
- const tsconfigDir = dirname(resolve(nitro.options.buildDir, nitro.options.typescript.tsconfigPath));
129
- nitro.scanSchemas = await scanSchemas(nitro);
130
- nitro.scanDocuments = await scanDocs(nitro);
131
- nitro.scanResolvers = await scanResolvers(nitro);
110
+ }
111
+ /**
112
+ * Scan all GraphQL files (schemas, resolvers, directives, documents)
113
+ */
114
+ async function scanGraphQLFiles(nitro) {
132
115
  const directives = await scanDirectives(nitro);
133
116
  nitro.scanDirectives = directives;
134
- await generateDirectiveSchemas(nitro, directives);
117
+ nitro.scanSchemas = [];
118
+ const directivesPath = await generateDirectiveSchemas(nitro, directives);
119
+ const schemas = await scanSchemas(nitro);
120
+ if (directivesPath && !schemas.includes(directivesPath)) schemas.push(directivesPath);
121
+ nitro.scanSchemas = schemas;
122
+ nitro.scanDocuments = await scanDocuments(nitro);
123
+ nitro.scanResolvers = await scanResolvers(nitro);
124
+ }
125
+ /**
126
+ * Setup dev mode hooks for rescanning files
127
+ */
128
+ function setupDevHooks(nitro) {
135
129
  let hasShownInitialLogs = false;
136
130
  nitro.hooks.hook("dev:start", async () => {
137
- nitro.scanSchemas = await scanSchemas(nitro);
131
+ const directives = await scanDirectives(nitro);
132
+ nitro.scanDirectives = directives;
133
+ if (!nitro.scanSchemas) nitro.scanSchemas = [];
134
+ const directivesPath = await generateDirectiveSchemas(nitro, directives);
135
+ const schemas = await scanSchemas(nitro);
136
+ if (directivesPath && !schemas.includes(directivesPath)) schemas.push(directivesPath);
137
+ nitro.scanSchemas = schemas;
138
+ nitro.scanDocuments = await scanDocuments(nitro);
138
139
  const resolvers = await scanResolvers(nitro);
139
140
  nitro.scanResolvers = resolvers;
140
- const directives$1 = await scanDirectives(nitro);
141
- nitro.scanDirectives = directives$1;
142
- await generateDirectiveSchemas(nitro, directives$1);
143
- nitro.scanDocuments = await scanDocs(nitro);
144
141
  if (nitro.options.dev && !hasShownInitialLogs) {
145
142
  hasShownInitialLogs = true;
146
143
  if (resolvers.length > 0) {
@@ -165,25 +162,35 @@ async function setupNitroGraphQL(nitro) {
165
162
  } else logger.warn("No resolvers found. Check /_nitro/graphql/debug for details.");
166
163
  }
167
164
  });
168
- await rollupConfig(nitro);
165
+ }
166
+ /**
167
+ * Generate server and client types
168
+ */
169
+ async function generateTypes(nitro) {
169
170
  await serverTypeGeneration(nitro);
170
171
  await clientTypeGeneration(nitro, { isInitial: true });
172
+ }
173
+ /**
174
+ * Setup close hooks for final type generation
175
+ */
176
+ function setupCloseHooks(nitro) {
171
177
  nitro.hooks.hook("close", async () => {
172
178
  await serverTypeGeneration(nitro, { silent: true });
173
179
  await clientTypeGeneration(nitro, { silent: true });
174
180
  });
181
+ }
182
+ /**
183
+ * Register GraphQL route handlers
184
+ */
185
+ function registerRouteHandlers(nitro) {
175
186
  const runtime = fileURLToPath(new URL("routes", import.meta.url));
176
- const methods = [
177
- "GET",
178
- "POST",
179
- "OPTIONS"
180
- ];
181
- if (nitro.options.graphql?.framework === "graphql-yoga") for (const method of methods) nitro.options.handlers.push({
187
+ const framework = nitro.options.graphql?.framework;
188
+ if (framework === "graphql-yoga") for (const method of GRAPHQL_HTTP_METHODS) nitro.options.handlers.push({
182
189
  route: nitro.options.runtimeConfig.graphql?.endpoint?.graphql || "/api/graphql",
183
190
  handler: join(runtime, "graphql-yoga"),
184
191
  method
185
192
  });
186
- if (nitro.options.graphql?.framework === "apollo-server") for (const method of methods) nitro.options.handlers.push({
193
+ if (framework === "apollo-server") for (const method of GRAPHQL_HTTP_METHODS) nitro.options.handlers.push({
187
194
  route: nitro.options.runtimeConfig.graphql?.endpoint?.graphql || "/api/graphql",
188
195
  handler: join(runtime, "apollo-server"),
189
196
  method
@@ -194,182 +201,28 @@ async function setupNitroGraphQL(nitro) {
194
201
  method: "GET"
195
202
  });
196
203
  if (nitro.options.dev) nitro.options.handlers.push({
197
- route: "/_nitro/graphql/debug",
204
+ route: ENDPOINT_DEBUG,
198
205
  handler: join(runtime, "debug"),
199
206
  method: "GET"
200
207
  });
201
- nitro.hooks.hook("rollup:before", (_, rollupConfig$1) => {
202
- const manualChunks = rollupConfig$1.output?.manualChunks;
203
- const chunkFiles = rollupConfig$1.output?.chunkFileNames;
204
- if (!rollupConfig$1.output.inlineDynamicImports) {
205
- rollupConfig$1.output.manualChunks = (id, meta) => {
206
- if (id.endsWith(".graphql") || id.endsWith(".gql")) {
207
- let graphqlIndex = id.indexOf("server/graphql/");
208
- let baseLength = 15;
209
- if (graphqlIndex === -1) {
210
- graphqlIndex = id.indexOf("routes/graphql/");
211
- baseLength = 15;
212
- }
213
- if (graphqlIndex !== -1) return id.slice(graphqlIndex + baseLength).replace(/\.(?:graphql|gql)$/, "-schema");
214
- return "schemas";
215
- }
216
- if (id.endsWith(".resolver.ts")) {
217
- let graphqlIndex = id.indexOf("server/graphql/");
218
- let baseLength = 15;
219
- if (graphqlIndex === -1) {
220
- graphqlIndex = id.indexOf("routes/graphql/");
221
- baseLength = 15;
222
- }
223
- if (graphqlIndex !== -1) return id.slice(graphqlIndex + baseLength).replace(/\.resolver\.ts$/, "");
224
- return "resolvers";
225
- }
226
- if (typeof manualChunks === "function") return manualChunks(id, meta);
227
- };
228
- rollupConfig$1.output.advancedChunks = {
229
- groups: [{
230
- name: (moduleId) => {
231
- if (!moduleId.endsWith(".graphql") && !moduleId.endsWith(".gql")) return;
232
- let graphqlIndex = moduleId.indexOf("server/graphql/");
233
- let baseLength = 15;
234
- if (graphqlIndex === -1) {
235
- graphqlIndex = moduleId.indexOf("routes/graphql/");
236
- baseLength = 15;
237
- }
238
- if (graphqlIndex !== -1) return moduleId.slice(graphqlIndex + baseLength).replace(/\.(?:graphql|gql)$/, "-schema");
239
- return "schemas";
240
- },
241
- test: /\.(?:graphql|gql)$/
242
- }, {
243
- name: (moduleId) => {
244
- if (!moduleId.endsWith(".resolver.ts")) return;
245
- let graphqlIndex = moduleId.indexOf("server/graphql/");
246
- let baseLength = 15;
247
- if (graphqlIndex === -1) {
248
- graphqlIndex = moduleId.indexOf("routes/graphql/");
249
- baseLength = 15;
250
- }
251
- if (graphqlIndex !== -1) return moduleId.slice(graphqlIndex + baseLength).replace(/\.resolver\.ts$/, "");
252
- return "resolvers";
253
- },
254
- test: /\.resolver\.(?:ts|js)$/
255
- }],
256
- minSize: 0,
257
- minShareCount: 1
258
- };
259
- }
260
- rollupConfig$1.output.chunkFileNames = (chunkInfo) => {
261
- if (chunkInfo.moduleIds && chunkInfo.moduleIds.some((id) => id.endsWith(".graphql") || id.endsWith(".resolver.ts") || id.endsWith(".gql"))) return `chunks/graphql/[name].mjs`;
262
- if (typeof chunkFiles === "function") return chunkFiles(chunkInfo);
263
- return `chunks/_/[name].mjs`;
264
- };
265
- });
266
- nitro.options.typescript.strict = true;
208
+ }
209
+ /**
210
+ * Setup TypeScript configuration and path aliases
211
+ */
212
+ function setupTypeScriptConfiguration(nitro) {
213
+ nitro.options.typescript.strict = DEFAULT_TYPESCRIPT_STRICT;
267
214
  nitro.hooks.hook("types:extend", (types) => {
268
- types.tsConfig ||= {};
269
- types.tsConfig.compilerOptions ??= {};
270
- types.tsConfig.compilerOptions.paths ??= {};
271
- const placeholders = getDefaultPaths(nitro);
272
- const typesConfig = getTypesConfig(nitro);
273
- const serverTypesPath = resolveFilePath(typesConfig.server, typesConfig.enabled, true, "{typesDir}/nitro-graphql-server.d.ts", placeholders);
274
- if (serverTypesPath) types.tsConfig.compilerOptions.paths["#graphql/server"] = [relativeWithDot(tsconfigDir, serverTypesPath)];
275
- const clientTypesPath = resolveFilePath(typesConfig.client, typesConfig.enabled, true, "{typesDir}/nitro-graphql-client.d.ts", placeholders);
276
- if (clientTypesPath) types.tsConfig.compilerOptions.paths["#graphql/client"] = [relativeWithDot(tsconfigDir, clientTypesPath)];
277
- types.tsConfig.compilerOptions.paths["#graphql/schema"] = [relativeWithDot(tsconfigDir, join(nitro.graphql.serverDir, "schema.ts"))];
278
- if (nitro.options.graphql?.externalServices?.length) for (const service of nitro.options.graphql.externalServices) {
279
- const servicePlaceholders = {
280
- ...placeholders,
281
- serviceName: service.name
282
- };
283
- const externalTypesPath = resolveFilePath(service.paths?.types ?? typesConfig.external, typesConfig.enabled, true, "{typesDir}/nitro-graphql-client-{serviceName}.d.ts", servicePlaceholders);
284
- if (externalTypesPath) types.tsConfig.compilerOptions.paths[`#graphql/client/${service.name}`] = [relativeWithDot(tsconfigDir, externalTypesPath)];
285
- }
286
- types.tsConfig.include = types.tsConfig.include || [];
287
- if (serverTypesPath) types.tsConfig.include.push(relativeWithDot(tsconfigDir, serverTypesPath));
288
- if (clientTypesPath) types.tsConfig.include.push(relativeWithDot(tsconfigDir, clientTypesPath));
289
- types.tsConfig.include.push(relativeWithDot(tsconfigDir, join(placeholders.typesDir, "graphql.d.ts")));
290
- if (nitro.options.graphql?.externalServices?.length) for (const service of nitro.options.graphql.externalServices) {
291
- const servicePlaceholders = {
292
- ...placeholders,
293
- serviceName: service.name
294
- };
295
- const externalTypesPath = resolveFilePath(service.paths?.types ?? typesConfig.external, typesConfig.enabled, true, "{typesDir}/nitro-graphql-client-{serviceName}.d.ts", servicePlaceholders);
296
- if (externalTypesPath) types.tsConfig.include.push(relativeWithDot(tsconfigDir, externalTypesPath));
297
- }
215
+ setupTypeScriptPaths(nitro, types);
298
216
  });
299
- if (nitro.options.framework?.name === "nuxt" && nitro.options.graphql?.externalServices?.length) nitro.hooks.hook("build:before", () => {
217
+ }
218
+ /**
219
+ * Setup Nuxt-specific integration
220
+ */
221
+ function setupNuxtIntegration(nitro) {
222
+ if (nitro.options.framework?.name === FRAMEWORK_NUXT && nitro.options.graphql?.externalServices?.length) nitro.hooks.hook("build:before", () => {
300
223
  const nuxtOptions = nitro._nuxt?.options;
301
224
  if (nuxtOptions) nuxtOptions.nitroGraphqlExternalServices = nitro.options.graphql?.externalServices || [];
302
225
  });
303
- if (shouldGenerateScaffold(nitro)) {
304
- const placeholders = getDefaultPaths(nitro);
305
- const scaffoldConfig = getScaffoldConfig(nitro);
306
- const graphqlConfigPath = resolveFilePath(scaffoldConfig.graphqlConfig, scaffoldConfig.enabled, true, "graphql.config.ts", placeholders);
307
- if (graphqlConfigPath) writeFileIfNotExists(graphqlConfigPath, `
308
- import type { IGraphQLConfig } from 'graphql-config'
309
-
310
- export default <IGraphQLConfig> {
311
- projects: {
312
- default: {
313
- schema: [
314
- '${relativeWithDot(nitro.options.rootDir, resolve(nitro.graphql.buildDir, "schema.graphql"))}',
315
- ],
316
- documents: [
317
- '${relativeWithDot(nitro.options.rootDir, resolve(nitro.graphql.clientDir, "**/*.{graphql,js,ts,jsx,tsx}"))}',
318
- ],
319
- },
320
- },
321
- }`, "graphql.config.ts");
322
- const serverSchemaPath = resolveFilePath(scaffoldConfig.serverSchema, scaffoldConfig.enabled, true, "{serverGraphql}/schema.ts", placeholders);
323
- const serverConfigPath = resolveFilePath(scaffoldConfig.serverConfig, scaffoldConfig.enabled, true, "{serverGraphql}/config.ts", placeholders);
324
- const serverContextPath = resolveFilePath(scaffoldConfig.serverContext, scaffoldConfig.enabled, true, "{serverGraphql}/context.d.ts", placeholders);
325
- if (serverSchemaPath || serverConfigPath || serverContextPath) {
326
- if (!existsSync(nitro.graphql.serverDir)) mkdirSync(nitro.graphql.serverDir, { recursive: true });
327
- }
328
- if (serverSchemaPath) writeFileIfNotExists(serverSchemaPath, `export default defineSchema({
329
-
330
- })
331
- `, "server schema.ts");
332
- if (serverConfigPath) writeFileIfNotExists(serverConfigPath, `// Example GraphQL config file please change it to your needs
333
- // import * as tables from '../drizzle/schema/index'
334
- // import { useDatabase } from '../utils/useDb'
335
- import { defineGraphQLConfig } from 'nitro-graphql/define'
336
-
337
- export default defineGraphQLConfig({
338
- // graphql-yoga example config
339
- // context: () => {
340
- // return {
341
- // context: {
342
- // useDatabase,
343
- // tables,
344
- // },
345
- // }
346
- // },
347
- })
348
- `, "server config.ts");
349
- if (serverContextPath) writeFileIfNotExists(serverContextPath, `// Example context definition - please change it to your needs
350
- // import type { Database } from '../utils/useDb'
351
-
352
- declare module 'nitro/h3' {
353
- interface H3EventContext {
354
- // Add your custom context properties here
355
- // useDatabase: () => Database
356
- // tables: typeof import('../drizzle/schema')
357
- // auth?: {
358
- // user?: {
359
- // id: string
360
- // role: 'admin' | 'user'
361
- // }
362
- // }
363
- }
364
- }
365
-
366
- export {}
367
- `, "server context.d.ts");
368
- if (existsSync(join(nitro.graphql.serverDir, "context.ts"))) {
369
- logger.warn("Found context.ts file. Please rename it to context.d.ts for type-only definitions.");
370
- logger.info("The context file should now be context.d.ts instead of context.ts");
371
- }
372
- } else logger.info("Scaffold file generation is disabled (library mode)");
373
226
  }
374
227
 
375
228
  //#endregion