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

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 (71) hide show
  1. package/dist/codegen/client-types.mjs +9 -54
  2. package/dist/codegen/external-types.mjs +7 -48
  3. package/dist/codegen/index.d.mts +4 -11
  4. package/dist/codegen/index.mjs +1 -15
  5. package/dist/codegen/server-types.mjs +2 -14
  6. package/dist/constants/scalars.mjs +27 -0
  7. package/dist/constants.mjs +16 -1
  8. package/dist/rollup.d.mts +1 -7
  9. package/dist/rollup.mjs +12 -187
  10. package/dist/routes/apollo-server.d.mts +2 -2
  11. package/dist/routes/apollo-server.mjs +7 -51
  12. package/dist/routes/debug-template.d.mts +15 -0
  13. package/dist/routes/debug-template.mjs +385 -0
  14. package/dist/routes/debug.d.mts +2 -2
  15. package/dist/routes/debug.mjs +1 -344
  16. package/dist/routes/graphql-yoga.d.mts +2 -2
  17. package/dist/routes/graphql-yoga.mjs +7 -51
  18. package/dist/routes/health.d.mts +2 -2
  19. package/dist/setup/file-watcher.mjs +9 -5
  20. package/dist/setup/graphql-scanner.mjs +25 -0
  21. package/dist/setup/scaffold-generator.mjs +1 -1
  22. package/dist/setup/ts-config.mjs +1 -1
  23. package/dist/setup.mjs +38 -47
  24. package/dist/types/index.d.mts +1 -1
  25. package/dist/utils/client-codegen.mjs +4 -30
  26. package/dist/utils/codegen-plugin.d.mts +20 -0
  27. package/dist/utils/codegen-plugin.mjs +30 -0
  28. package/dist/utils/federation.d.mts +29 -0
  29. package/dist/utils/federation.mjs +40 -0
  30. package/dist/utils/file-writer.d.mts +35 -0
  31. package/dist/utils/file-writer.mjs +32 -0
  32. package/dist/utils/imports.d.mts +15 -0
  33. package/dist/utils/imports.mjs +25 -0
  34. package/dist/utils/index.d.mts +11 -38
  35. package/dist/utils/index.mjs +10 -287
  36. package/dist/utils/layers.d.mts +22 -0
  37. package/dist/utils/layers.mjs +28 -0
  38. package/dist/utils/ofetch-templates.d.mts +30 -0
  39. package/dist/utils/ofetch-templates.mjs +135 -0
  40. package/dist/utils/scanning/common.d.mts +23 -0
  41. package/dist/utils/scanning/common.mjs +39 -0
  42. package/dist/utils/scanning/directives.d.mts +11 -0
  43. package/dist/utils/scanning/directives.mjs +43 -0
  44. package/dist/utils/scanning/documents.d.mts +15 -0
  45. package/dist/utils/scanning/documents.mjs +46 -0
  46. package/dist/utils/scanning/index.d.mts +6 -0
  47. package/dist/utils/scanning/index.mjs +7 -0
  48. package/dist/utils/scanning/resolvers.d.mts +11 -0
  49. package/dist/utils/scanning/resolvers.mjs +100 -0
  50. package/dist/utils/scanning/schemas.d.mts +15 -0
  51. package/dist/utils/scanning/schemas.mjs +29 -0
  52. package/dist/utils/schema-builder.d.mts +48 -0
  53. package/dist/utils/schema-builder.mjs +51 -0
  54. package/dist/utils/server-codegen.mjs +3 -29
  55. package/dist/utils/type-generation.d.mts +2 -2
  56. package/dist/utils/type-generation.mjs +2 -2
  57. package/dist/utils/validation.d.mts +11 -0
  58. package/dist/utils/validation.mjs +34 -0
  59. package/dist/virtual/generators/config.d.mts +22 -0
  60. package/dist/virtual/generators/config.mjs +36 -0
  61. package/dist/virtual/generators/debug.d.mts +14 -0
  62. package/dist/virtual/generators/debug.mjs +53 -0
  63. package/dist/virtual/generators/directives.d.mts +14 -0
  64. package/dist/virtual/generators/directives.mjs +52 -0
  65. package/dist/virtual/generators/index.d.mts +6 -0
  66. package/dist/virtual/generators/index.mjs +7 -0
  67. package/dist/virtual/generators/resolvers.d.mts +14 -0
  68. package/dist/virtual/generators/resolvers.mjs +55 -0
  69. package/dist/virtual/generators/schemas.d.mts +14 -0
  70. package/dist/virtual/generators/schemas.mjs +43 -0
  71. package/package.json +22 -18
@@ -0,0 +1,22 @@
1
+ import { Nitro } from "nitro/types";
2
+
3
+ //#region src/utils/layers.d.ts
4
+
5
+ /**
6
+ * Get all Nuxt layer directories from Nitro config
7
+ */
8
+ declare function getLayerDirectories(nitro: Nitro): string[];
9
+ /**
10
+ * Get all Nuxt layer server directories from Nitro config
11
+ */
12
+ declare function getLayerServerDirectories(nitro: Nitro): string[];
13
+ /**
14
+ * Get all Nuxt layer app directories from Nitro config
15
+ */
16
+ declare function getLayerAppDirectories(nitro: Nitro): string[];
17
+ /**
18
+ * Generate layer-aware ignore patterns for auto-generated files
19
+ */
20
+ declare function generateLayerIgnorePatterns(): string[];
21
+ //#endregion
22
+ export { generateLayerIgnorePatterns, getLayerAppDirectories, getLayerDirectories, getLayerServerDirectories };
@@ -0,0 +1,28 @@
1
+ //#region src/utils/layers.ts
2
+ /**
3
+ * Get all Nuxt layer directories from Nitro config
4
+ */
5
+ function getLayerDirectories(nitro) {
6
+ return nitro.options.graphql?.layerDirectories || [];
7
+ }
8
+ /**
9
+ * Get all Nuxt layer server directories from Nitro config
10
+ */
11
+ function getLayerServerDirectories(nitro) {
12
+ return nitro.options.graphql?.layerServerDirs || [];
13
+ }
14
+ /**
15
+ * Get all Nuxt layer app directories from Nitro config
16
+ */
17
+ function getLayerAppDirectories(nitro) {
18
+ return nitro.options.graphql?.layerAppDirs || [];
19
+ }
20
+ /**
21
+ * Generate layer-aware ignore patterns for auto-generated files
22
+ */
23
+ function generateLayerIgnorePatterns() {
24
+ return [];
25
+ }
26
+
27
+ //#endregion
28
+ export { generateLayerIgnorePatterns, getLayerAppDirectories, getLayerDirectories, getLayerServerDirectories };
@@ -0,0 +1,30 @@
1
+ //#region src/utils/ofetch-templates.d.ts
2
+ /**
3
+ * Shared ofetch template generation utilities
4
+ * Used by both main client and external service code generation
5
+ */
6
+ interface OfetchTemplateOptions {
7
+ /** Service name (e.g., 'default', 'github') */
8
+ serviceName: string;
9
+ /** Whether to use Nuxt composables ($fetch, useRequestHeaders) */
10
+ isNuxt: boolean;
11
+ /** Endpoint URL for the GraphQL service */
12
+ endpoint: string;
13
+ /** Whether this is an external service (affects naming convention) */
14
+ isExternal?: boolean;
15
+ }
16
+ /**
17
+ * Generate ofetch client template content
18
+ *
19
+ * For main (default) service:
20
+ * - SDK exported as `$sdk`
21
+ * - Client function is `createGraphQLClient`
22
+ *
23
+ * For external services:
24
+ * - SDK exported as `$${serviceName}Sdk`
25
+ * - Client function is `create${ServiceName}GraphQLClient`
26
+ * - Endpoint has default value
27
+ */
28
+ declare function generateOfetchTemplate(options: OfetchTemplateOptions): string;
29
+ //#endregion
30
+ export { OfetchTemplateOptions, generateOfetchTemplate };
@@ -0,0 +1,135 @@
1
+ //#region src/utils/ofetch-templates.ts
2
+ /**
3
+ * Capitalize first letter of a string
4
+ */
5
+ function capitalize(str) {
6
+ return str.charAt(0).toUpperCase() + str.slice(1);
7
+ }
8
+ /**
9
+ * Generate ofetch client template content
10
+ *
11
+ * For main (default) service:
12
+ * - SDK exported as `$sdk`
13
+ * - Client function is `createGraphQLClient`
14
+ *
15
+ * For external services:
16
+ * - SDK exported as `$${serviceName}Sdk`
17
+ * - Client function is `create${ServiceName}GraphQLClient`
18
+ * - Endpoint has default value
19
+ */
20
+ function generateOfetchTemplate(options) {
21
+ const { serviceName, isNuxt, endpoint, isExternal = false } = options;
22
+ if (isExternal) return generateExternalOfetchTemplate({
23
+ serviceName,
24
+ isNuxt,
25
+ endpoint
26
+ });
27
+ return generateMainOfetchTemplate({
28
+ isNuxt,
29
+ endpoint
30
+ });
31
+ }
32
+ /**
33
+ * Generate ofetch template for main (default) GraphQL service
34
+ */
35
+ function generateMainOfetchTemplate(options) {
36
+ const { isNuxt, endpoint } = options;
37
+ if (isNuxt) return `// This file is auto-generated once by nitro-graphql for quick start
38
+ // You can modify this file according to your needs
39
+ import type { Requester } from './sdk'
40
+ import { getSdk } from './sdk'
41
+
42
+ export function createGraphQLClient(endpoint: string): Requester {
43
+ return async <R>(doc: string, vars?: any): Promise<R> => {
44
+ const headers = import.meta.server ? useRequestHeaders() : undefined
45
+
46
+ const result = await $fetch(endpoint, {
47
+ method: 'POST',
48
+ body: { query: doc, variables: vars },
49
+ headers: {
50
+ 'Content-Type': 'application/json',
51
+ ...headers,
52
+ },
53
+ })
54
+
55
+ return result as R
56
+ }
57
+ }
58
+
59
+ export const $sdk = getSdk(createGraphQLClient('${endpoint}'))`;
60
+ return `// This file is auto-generated once by nitro-graphql for quick start
61
+ // You can modify this file according to your needs
62
+ import type { Requester } from './sdk'
63
+ import { ofetch } from 'ofetch'
64
+ import { getSdk } from './sdk'
65
+
66
+ export function createGraphQLClient(endpoint: string): Requester {
67
+ return async <R>(doc: string, vars?: any): Promise<R> => {
68
+ const result = await ofetch(endpoint, {
69
+ method: 'POST',
70
+ body: { query: doc, variables: vars },
71
+ headers: {
72
+ 'Content-Type': 'application/json',
73
+ },
74
+ })
75
+
76
+ return result as R
77
+ }
78
+ }
79
+
80
+ export const $sdk = getSdk(createGraphQLClient('${endpoint}'))`;
81
+ }
82
+ /**
83
+ * Generate ofetch template for external GraphQL service
84
+ */
85
+ function generateExternalOfetchTemplate(options) {
86
+ const { serviceName, isNuxt, endpoint } = options;
87
+ const capitalizedName = capitalize(serviceName);
88
+ if (isNuxt) return `// This file is auto-generated once by nitro-graphql for quick start
89
+ // You can modify this file according to your needs
90
+ import type { Sdk, Requester } from './sdk'
91
+ import { getSdk } from './sdk'
92
+
93
+ export function create${capitalizedName}GraphQLClient(endpoint: string = '${endpoint}'): Requester {
94
+ return async <R>(doc: string, vars?: any): Promise<R> => {
95
+ const headers = import.meta.server ? useRequestHeaders() : undefined
96
+
97
+ const result = await $fetch(endpoint, {
98
+ method: 'POST',
99
+ body: { query: doc, variables: vars },
100
+ headers: {
101
+ 'Content-Type': 'application/json',
102
+ ...headers,
103
+ },
104
+ })
105
+
106
+ return result as R
107
+ }
108
+ }
109
+
110
+ export const $${serviceName}Sdk: Sdk = getSdk(create${capitalizedName}GraphQLClient())`;
111
+ return `// This file is auto-generated once by nitro-graphql for quick start
112
+ // You can modify this file according to your needs
113
+ import type { Sdk, Requester } from './sdk'
114
+ import { ofetch } from 'ofetch'
115
+ import { getSdk } from './sdk'
116
+
117
+ export function create${capitalizedName}GraphQLClient(endpoint: string = '${endpoint}'): Requester {
118
+ return async <R>(doc: string, vars?: any): Promise<R> => {
119
+ const result = await ofetch(endpoint, {
120
+ method: 'POST',
121
+ body: { query: doc, variables: vars },
122
+ headers: {
123
+ 'Content-Type': 'application/json',
124
+ },
125
+ })
126
+
127
+ return result as R
128
+ }
129
+ }
130
+
131
+ export const $${serviceName}Sdk: Sdk = getSdk(create${capitalizedName}GraphQLClient())`;
132
+ }
133
+
134
+ //#endregion
135
+ export { generateOfetchTemplate };
@@ -0,0 +1,23 @@
1
+ import { Nitro } from "nitro/types";
2
+
3
+ //#region src/utils/scanning/common.d.ts
4
+
5
+ /**
6
+ * File information returned from scanning operations
7
+ */
8
+ interface FileInfo {
9
+ path: string;
10
+ fullPath: string;
11
+ }
12
+ /**
13
+ * Scan a directory for files matching a glob pattern
14
+ */
15
+ declare function scanDir(nitro: Nitro, dir: string, name: string, globPattern?: string): Promise<FileInfo[]>;
16
+ /**
17
+ * Deduplicate files by fullPath
18
+ */
19
+ declare function deduplicateFiles<T extends {
20
+ fullPath: string;
21
+ }>(files: T[]): T[];
22
+ //#endregion
23
+ export { FileInfo, deduplicateFiles, scanDir };
@@ -0,0 +1,39 @@
1
+ import { GLOB_SCAN_PATTERN } from "../../constants.mjs";
2
+ import { join, relative } from "pathe";
3
+ import { glob } from "tinyglobby";
4
+
5
+ //#region src/utils/scanning/common.ts
6
+ /**
7
+ * Scan a directory for files matching a glob pattern
8
+ */
9
+ async function scanDir(nitro, dir, name, globPattern = GLOB_SCAN_PATTERN) {
10
+ return (await glob(join(name, globPattern), {
11
+ cwd: dir,
12
+ dot: true,
13
+ ignore: nitro.options.ignore,
14
+ absolute: true
15
+ }).catch((error) => {
16
+ if (error?.code === "ENOTDIR") {
17
+ nitro.logger.warn(`Ignoring \`${join(dir, name)}\`. It must be a directory.`);
18
+ return [];
19
+ }
20
+ throw error;
21
+ })).map((fullPath) => ({
22
+ fullPath,
23
+ path: relative(join(dir, name), fullPath)
24
+ })).sort((a, b) => a.path.localeCompare(b.path));
25
+ }
26
+ /**
27
+ * Deduplicate files by fullPath
28
+ */
29
+ function deduplicateFiles(files) {
30
+ const seenPaths = /* @__PURE__ */ new Set();
31
+ return files.filter((file) => {
32
+ if (seenPaths.has(file.fullPath)) return false;
33
+ seenPaths.add(file.fullPath);
34
+ return true;
35
+ });
36
+ }
37
+
38
+ //#endregion
39
+ export { deduplicateFiles, scanDir };
@@ -0,0 +1,11 @@
1
+ import { GenImport } from "../../types/index.mjs";
2
+ import { Nitro } from "nitro/types";
3
+
4
+ //#region src/utils/scanning/directives.d.ts
5
+
6
+ /**
7
+ * Scan for directive files and parse their exports
8
+ */
9
+ declare function scanDirectives(nitro: Nitro): Promise<GenImport[]>;
10
+ //#endregion
11
+ export { scanDirectives };
@@ -0,0 +1,43 @@
1
+ import { getLayerServerDirectories } from "../layers.mjs";
2
+ import { deduplicateFiles, scanDir } from "./common.mjs";
3
+ import { readFile } from "node:fs/promises";
4
+ import { relative } from "pathe";
5
+ import { hash } from "ohash";
6
+ import { parseSync } from "oxc-parser";
7
+
8
+ //#region src/utils/scanning/directives.ts
9
+ /**
10
+ * Scan for directive files and parse their exports
11
+ */
12
+ async function scanDirectives(nitro) {
13
+ const serverDirRelative = relative(nitro.options.rootDir, nitro.graphql.serverDir);
14
+ const regularFiles = await scanDir(nitro, nitro.options.rootDir, serverDirRelative, "**/*.directive.{ts,js}");
15
+ const layerServerDirs = getLayerServerDirectories(nitro);
16
+ const layerFiles = await Promise.all(layerServerDirs.map((layerServerDir) => scanDir(nitro, layerServerDir, "graphql", "**/*.directive.{ts,js}"))).then((r) => r.flat());
17
+ const files = deduplicateFiles([...regularFiles, ...layerFiles]);
18
+ const exportName = [];
19
+ for (const file of files) {
20
+ const fileContent = await readFile(file.fullPath, "utf-8");
21
+ const parsed = parseSync(file.fullPath, fileContent);
22
+ const exports = {
23
+ imports: [],
24
+ specifier: file.fullPath
25
+ };
26
+ for (const node of parsed.program.body) if (node.type === "ExportNamedDeclaration" && node.declaration && node.declaration.type === "VariableDeclaration") {
27
+ for (const decl of node.declaration.declarations) if (decl.type === "VariableDeclarator" && decl.init && decl.id.type === "Identifier") {
28
+ if (decl.init && decl.init.type === "CallExpression") {
29
+ if (decl.init.callee.type === "Identifier" && decl.init.callee.name === "defineDirective") exports.imports.push({
30
+ name: decl.id.name,
31
+ type: "directive",
32
+ as: `_${hash(decl.id.name + file.fullPath).replace(/-/g, "").slice(0, 6)}`
33
+ });
34
+ }
35
+ }
36
+ }
37
+ if (exports.imports.length > 0) exportName.push(exports);
38
+ }
39
+ return exportName;
40
+ }
41
+
42
+ //#endregion
43
+ export { scanDirectives };
@@ -0,0 +1,15 @@
1
+ import { Nitro } from "nitro/types";
2
+
3
+ //#region src/utils/scanning/documents.d.ts
4
+
5
+ /**
6
+ * Scan for GraphQL client documents (.graphql) in client directory
7
+ * Excludes files from external service directories
8
+ */
9
+ declare function scanDocuments(nitro: Nitro): Promise<string[]>;
10
+ /**
11
+ * Scan documents for a specific external service
12
+ */
13
+ declare function scanExternalServiceDocs(nitro: Nitro, serviceName: string, patterns: string[]): Promise<string[]>;
14
+ //#endregion
15
+ export { scanDocuments, scanExternalServiceDocs };
@@ -0,0 +1,46 @@
1
+ import { getLayerAppDirectories } from "../layers.mjs";
2
+ import { deduplicateFiles, scanDir } from "./common.mjs";
3
+ import { glob } from "tinyglobby";
4
+
5
+ //#region src/utils/scanning/documents.ts
6
+ /**
7
+ * Scan for GraphQL client documents (.graphql) in client directory
8
+ * Excludes files from external service directories
9
+ */
10
+ async function scanDocuments(nitro) {
11
+ const files = await scanDir(nitro, nitro.options.rootDir, nitro.graphql.dir.client, "**/*.graphql");
12
+ const layerAppDirs = getLayerAppDirectories(nitro);
13
+ const layerFiles = await Promise.all(layerAppDirs.map((layerAppDir) => scanDir(nitro, layerAppDir, "graphql", "**/*.graphql"))).then((r) => r.flat());
14
+ const allFiles = deduplicateFiles([...files, ...layerFiles]);
15
+ const externalPatterns = (nitro.options.graphql?.externalServices || []).flatMap((service) => service.documents || []);
16
+ return allFiles.filter((f) => !f.path.startsWith("external/")).filter((f) => {
17
+ const relativePath = f.path;
18
+ for (const pattern of externalPatterns) {
19
+ const clientDirPattern = `${nitro.graphql.dir.client}/`;
20
+ if (pattern.replace(/* @__PURE__ */ new RegExp(`^${clientDirPattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}`), "").split("/")[0] === relativePath.split("/")[0]) return false;
21
+ }
22
+ return true;
23
+ }).map((f) => f.fullPath);
24
+ }
25
+ /**
26
+ * Scan documents for a specific external service
27
+ */
28
+ async function scanExternalServiceDocs(nitro, serviceName, patterns) {
29
+ if (!patterns.length) return [];
30
+ const files = [];
31
+ for (const pattern of patterns) try {
32
+ const serviceFiles = await glob(pattern, {
33
+ cwd: nitro.options.rootDir,
34
+ dot: true,
35
+ ignore: nitro.options.ignore,
36
+ absolute: true
37
+ });
38
+ files.push(...serviceFiles);
39
+ } catch (error) {
40
+ nitro.logger.warn(`[graphql:${serviceName}] Error scanning documents with pattern "${pattern}":`, error);
41
+ }
42
+ return files.filter((file, index, self) => self.indexOf(file) === index);
43
+ }
44
+
45
+ //#endregion
46
+ export { scanDocuments, scanExternalServiceDocs };
@@ -0,0 +1,6 @@
1
+ import { FileInfo, deduplicateFiles, scanDir } from "./common.mjs";
2
+ import { scanDirectives } from "./directives.mjs";
3
+ import { scanDocuments, scanExternalServiceDocs } from "./documents.mjs";
4
+ import { scanResolvers } from "./resolvers.mjs";
5
+ import { scanGraphql, scanSchemas } from "./schemas.mjs";
6
+ export { type FileInfo, deduplicateFiles, scanDir, scanDirectives, scanDocuments, scanExternalServiceDocs, scanGraphql, scanResolvers, scanSchemas };
@@ -0,0 +1,7 @@
1
+ import { deduplicateFiles, scanDir } from "./common.mjs";
2
+ import { scanDirectives } from "./directives.mjs";
3
+ import { scanDocuments, scanExternalServiceDocs } from "./documents.mjs";
4
+ import { scanResolvers } from "./resolvers.mjs";
5
+ import { scanGraphql, scanSchemas } from "./schemas.mjs";
6
+
7
+ export { deduplicateFiles, scanDir, scanDirectives, scanDocuments, scanExternalServiceDocs, scanGraphql, scanResolvers, scanSchemas };
@@ -0,0 +1,11 @@
1
+ import { GenImport } from "../../types/index.mjs";
2
+ import { Nitro } from "nitro/types";
3
+
4
+ //#region src/utils/scanning/resolvers.d.ts
5
+
6
+ /**
7
+ * Scan for resolver files and parse their exports
8
+ */
9
+ declare function scanResolvers(nitro: Nitro): Promise<GenImport[]>;
10
+ //#endregion
11
+ export { scanResolvers };
@@ -0,0 +1,100 @@
1
+ import { DEFINE_FUNCTIONS } from "../../constants.mjs";
2
+ import { getLayerServerDirectories } from "../layers.mjs";
3
+ import { deduplicateFiles, scanDir } from "./common.mjs";
4
+ import { readFile } from "node:fs/promises";
5
+ import { basename, relative } from "pathe";
6
+ import { hash } from "ohash";
7
+ import { parseSync } from "oxc-parser";
8
+
9
+ //#region src/utils/scanning/resolvers.ts
10
+ /**
11
+ * Scan for resolver files and parse their exports
12
+ */
13
+ async function scanResolvers(nitro) {
14
+ const serverDirRelative = relative(nitro.options.rootDir, nitro.graphql.serverDir);
15
+ const regularFiles = await scanDir(nitro, nitro.options.rootDir, serverDirRelative, "**/*.resolver.{ts,js}");
16
+ const layerServerDirs = getLayerServerDirectories(nitro);
17
+ const layerFiles = await Promise.all(layerServerDirs.map((layerServerDir) => scanDir(nitro, layerServerDir, "graphql", "**/*.resolver.{ts,js}"))).then((r) => r.flat());
18
+ const files = deduplicateFiles([...regularFiles, ...layerFiles]);
19
+ const exportName = [];
20
+ for (const file of files) try {
21
+ const fileContent = await readFile(file.fullPath, "utf-8");
22
+ const parsed = parseSync(file.fullPath, fileContent);
23
+ if (parsed.errors && parsed.errors.length > 0) {
24
+ if (nitro.options.dev) {
25
+ const fileName = basename(file.fullPath);
26
+ const firstError = parsed.errors[0];
27
+ const location = firstError?.labels?.[0];
28
+ const lineInfo = location ? `:${location.start}` : "";
29
+ const message = firstError?.message.split(",")[0] || "Syntax error";
30
+ console.error(`✖ ${fileName}${lineInfo} - ${message}`);
31
+ }
32
+ continue;
33
+ }
34
+ const exports = {
35
+ imports: [],
36
+ specifier: file.fullPath
37
+ };
38
+ let hasDefaultExport = false;
39
+ let hasNamedExport = false;
40
+ const namedExports = [];
41
+ for (const node of parsed.program.body) {
42
+ if (node.type === "ExportDefaultDeclaration") hasDefaultExport = true;
43
+ if (node.type === "ExportNamedDeclaration" && node.declaration && node.declaration.type === "VariableDeclaration") {
44
+ for (const decl of node.declaration.declarations) if (decl.type === "VariableDeclarator" && decl.init && decl.id.type === "Identifier") {
45
+ hasNamedExport = true;
46
+ namedExports.push(decl.id.name);
47
+ if (decl.init && decl.init.type === "CallExpression") {
48
+ if (decl.init.callee.type === "Identifier" && decl.init.callee.name === "defineResolver") exports.imports.push({
49
+ name: decl.id.name,
50
+ type: "resolver",
51
+ as: `_${hash(decl.id.name + file.fullPath).replace(/-/g, "").slice(0, 6)}`
52
+ });
53
+ if (decl.init.callee.type === "Identifier" && decl.init.callee.name === "defineQuery") exports.imports.push({
54
+ name: decl.id.name,
55
+ type: "query",
56
+ as: `_${hash(decl.id.name + file.fullPath).replace(/-/g, "").slice(0, 6)}`
57
+ });
58
+ if (decl.init.callee.type === "Identifier" && decl.init.callee.name === "defineMutation") exports.imports.push({
59
+ name: decl.id.name,
60
+ type: "mutation",
61
+ as: `_${hash(decl.id.name + file.fullPath).replace(/-/g, "").slice(0, 6)}`
62
+ });
63
+ if (decl.init.callee.type === "Identifier" && decl.init.callee.name === "defineField") exports.imports.push({
64
+ name: decl.id.name,
65
+ type: "type",
66
+ as: `_${hash(decl.id.name + file.fullPath).replace(/-/g, "").slice(0, 6)}`
67
+ });
68
+ if (decl.init.callee.type === "Identifier" && decl.init.callee.name === "defineSubscription") exports.imports.push({
69
+ name: decl.id.name,
70
+ type: "subscription",
71
+ as: `_${hash(decl.id.name + file.fullPath).replace(/-/g, "").slice(0, 6)}`
72
+ });
73
+ if (decl.init.callee.type === "Identifier" && decl.init.callee.name === "defineDirective") exports.imports.push({
74
+ name: decl.id.name,
75
+ type: "directive",
76
+ as: `_${hash(decl.id.name + file.fullPath).replace(/-/g, "").slice(0, 6)}`
77
+ });
78
+ }
79
+ }
80
+ }
81
+ }
82
+ if (nitro.options.dev) {
83
+ const relPath = relative(nitro.options.rootDir, file.fullPath);
84
+ if (hasDefaultExport && !hasNamedExport) nitro.logger.warn(`[nitro-graphql] ${relPath}: Using default export instead of named export. Resolvers must use named exports like "export const myResolver = defineQuery(...)". Default exports are not detected.`);
85
+ if (exports.imports.length === 0 && hasNamedExport) {
86
+ const validFunctions = DEFINE_FUNCTIONS.join(", ");
87
+ nitro.logger.warn(`[nitro-graphql] ${relPath}: File has named exports [${namedExports.join(", ")}] but none use the required define functions (${validFunctions}). Exports will not be registered.`);
88
+ }
89
+ if (!hasDefaultExport && !hasNamedExport) nitro.logger.warn(`[nitro-graphql] ${relPath}: No exports found. Resolver files must export resolvers using defineResolver, defineQuery, defineMutation, etc.`);
90
+ }
91
+ if (exports.imports.length > 0) exportName.push(exports);
92
+ } catch (error) {
93
+ const relPath = relative(nitro.options.rootDir, file.fullPath);
94
+ nitro.logger.error(`[nitro-graphql] Failed to parse resolver file ${relPath}:`, error);
95
+ }
96
+ return exportName;
97
+ }
98
+
99
+ //#endregion
100
+ export { scanResolvers };
@@ -0,0 +1,15 @@
1
+ import { Nitro } from "nitro/types";
2
+
3
+ //#region src/utils/scanning/schemas.d.ts
4
+
5
+ /**
6
+ * Scan for GraphQL schema files (.graphql) in server directory
7
+ */
8
+ declare function scanSchemas(nitro: Nitro): Promise<string[]>;
9
+ /**
10
+ * Scan for GraphQL files (.graphql, .gql) in server directory
11
+ * Similar to scanSchemas but includes .gql extension
12
+ */
13
+ declare function scanGraphql(nitro: Nitro): Promise<string[]>;
14
+ //#endregion
15
+ export { scanGraphql, scanSchemas };
@@ -0,0 +1,29 @@
1
+ import { getLayerServerDirectories } from "../layers.mjs";
2
+ import { deduplicateFiles, scanDir } from "./common.mjs";
3
+ import { relative } from "pathe";
4
+
5
+ //#region src/utils/scanning/schemas.ts
6
+ /**
7
+ * Scan for GraphQL schema files (.graphql) in server directory
8
+ */
9
+ async function scanSchemas(nitro) {
10
+ const serverDirRelative = relative(nitro.options.rootDir, nitro.graphql.serverDir);
11
+ const files = await scanDir(nitro, nitro.options.rootDir, serverDirRelative, "**/*.graphql");
12
+ const layerServerDirs = getLayerServerDirectories(nitro);
13
+ const layerFiles = await Promise.all(layerServerDirs.map((layerServerDir) => scanDir(nitro, layerServerDir, "graphql", "**/*.graphql"))).then((r) => r.flat());
14
+ return deduplicateFiles([...files, ...layerFiles]).map((f) => f.fullPath);
15
+ }
16
+ /**
17
+ * Scan for GraphQL files (.graphql, .gql) in server directory
18
+ * Similar to scanSchemas but includes .gql extension
19
+ */
20
+ async function scanGraphql(nitro) {
21
+ const serverDirRelative = relative(nitro.options.rootDir, nitro.graphql.serverDir);
22
+ const files = await scanDir(nitro, nitro.options.rootDir, serverDirRelative, "**/*.{graphql,gql}");
23
+ const layerServerDirs = getLayerServerDirectories(nitro);
24
+ const layerFiles = await Promise.all(layerServerDirs.map((layerServerDir) => scanDir(nitro, layerServerDir, "graphql", "**/*.{graphql,gql}"))).then((r) => r.flat());
25
+ return deduplicateFiles([...files, ...layerFiles]).map((f) => f.fullPath);
26
+ }
27
+
28
+ //#endregion
29
+ export { scanGraphql, scanSchemas };
@@ -0,0 +1,48 @@
1
+ import { DirectiveDefinition } from "../types/define.mjs";
2
+ import { GraphQLSchema } from "graphql";
3
+
4
+ //#region src/utils/schema-builder.d.ts
5
+
6
+ /**
7
+ * Schema definition from virtual module
8
+ */
9
+ interface SchemaDefinition {
10
+ def: string;
11
+ }
12
+ /**
13
+ * Resolver definition from virtual module
14
+ */
15
+ interface ResolverDefinition {
16
+ resolver: Record<string, unknown>;
17
+ }
18
+ /**
19
+ * Directive wrapper from virtual module
20
+ */
21
+ interface DirectiveWrapper {
22
+ directive: DirectiveDefinition;
23
+ }
24
+ /**
25
+ * Module configuration for federation
26
+ */
27
+ interface ModuleConfig {
28
+ federation?: {
29
+ enabled?: boolean;
30
+ serviceName?: string;
31
+ };
32
+ }
33
+ /**
34
+ * Options for creating a merged schema
35
+ */
36
+ interface CreateMergedSchemaOptions {
37
+ schemas: SchemaDefinition[];
38
+ resolvers: ResolverDefinition[];
39
+ directives?: DirectiveWrapper[];
40
+ moduleConfig: ModuleConfig;
41
+ }
42
+ /**
43
+ * Create a merged GraphQL schema from schemas, resolvers, and directives
44
+ * Supports Apollo Federation when enabled
45
+ */
46
+ declare function createMergedSchema(options: CreateMergedSchemaOptions): Promise<GraphQLSchema>;
47
+ //#endregion
48
+ export { CreateMergedSchemaOptions, DirectiveWrapper, ModuleConfig, ResolverDefinition, SchemaDefinition, createMergedSchema };