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.
- package/dist/codegen/client-types.mjs +9 -54
- package/dist/codegen/external-types.mjs +7 -48
- package/dist/codegen/index.d.mts +4 -11
- package/dist/codegen/index.mjs +1 -15
- package/dist/codegen/server-types.mjs +2 -14
- package/dist/constants/scalars.mjs +27 -0
- package/dist/constants.mjs +16 -1
- package/dist/rollup.d.mts +1 -7
- package/dist/rollup.mjs +12 -187
- package/dist/routes/apollo-server.d.mts +2 -2
- package/dist/routes/apollo-server.mjs +7 -51
- package/dist/routes/debug-template.d.mts +15 -0
- package/dist/routes/debug-template.mjs +385 -0
- package/dist/routes/debug.d.mts +2 -2
- package/dist/routes/debug.mjs +1 -344
- package/dist/routes/graphql-yoga.d.mts +2 -2
- package/dist/routes/graphql-yoga.mjs +7 -51
- package/dist/routes/health.d.mts +2 -2
- package/dist/setup/file-watcher.mjs +9 -5
- package/dist/setup/graphql-scanner.mjs +25 -0
- package/dist/setup/scaffold-generator.mjs +1 -1
- package/dist/setup/ts-config.mjs +1 -1
- package/dist/setup.mjs +38 -47
- package/dist/types/index.d.mts +1 -1
- package/dist/utils/client-codegen.mjs +4 -30
- package/dist/utils/codegen-plugin.d.mts +20 -0
- package/dist/utils/codegen-plugin.mjs +30 -0
- package/dist/utils/federation.d.mts +29 -0
- package/dist/utils/federation.mjs +40 -0
- package/dist/utils/file-writer.d.mts +35 -0
- package/dist/utils/file-writer.mjs +32 -0
- package/dist/utils/imports.d.mts +15 -0
- package/dist/utils/imports.mjs +25 -0
- package/dist/utils/index.d.mts +11 -38
- package/dist/utils/index.mjs +10 -287
- package/dist/utils/layers.d.mts +22 -0
- package/dist/utils/layers.mjs +28 -0
- package/dist/utils/ofetch-templates.d.mts +30 -0
- package/dist/utils/ofetch-templates.mjs +135 -0
- package/dist/utils/scanning/common.d.mts +23 -0
- package/dist/utils/scanning/common.mjs +39 -0
- package/dist/utils/scanning/directives.d.mts +11 -0
- package/dist/utils/scanning/directives.mjs +43 -0
- package/dist/utils/scanning/documents.d.mts +15 -0
- package/dist/utils/scanning/documents.mjs +46 -0
- package/dist/utils/scanning/index.d.mts +6 -0
- package/dist/utils/scanning/index.mjs +7 -0
- package/dist/utils/scanning/resolvers.d.mts +11 -0
- package/dist/utils/scanning/resolvers.mjs +100 -0
- package/dist/utils/scanning/schemas.d.mts +15 -0
- package/dist/utils/scanning/schemas.mjs +29 -0
- package/dist/utils/schema-builder.d.mts +48 -0
- package/dist/utils/schema-builder.mjs +51 -0
- package/dist/utils/server-codegen.mjs +3 -29
- package/dist/utils/type-generation.d.mts +2 -2
- package/dist/utils/type-generation.mjs +2 -2
- package/dist/utils/validation.d.mts +11 -0
- package/dist/utils/validation.mjs +34 -0
- package/dist/virtual/generators/config.d.mts +22 -0
- package/dist/virtual/generators/config.mjs +36 -0
- package/dist/virtual/generators/debug.d.mts +14 -0
- package/dist/virtual/generators/debug.mjs +53 -0
- package/dist/virtual/generators/directives.d.mts +14 -0
- package/dist/virtual/generators/directives.mjs +52 -0
- package/dist/virtual/generators/index.d.mts +6 -0
- package/dist/virtual/generators/index.mjs +7 -0
- package/dist/virtual/generators/resolvers.d.mts +14 -0
- package/dist/virtual/generators/resolvers.mjs +55 -0
- package/dist/virtual/generators/schemas.d.mts +14 -0
- package/dist/virtual/generators/schemas.mjs +43 -0
- package/package.json +22 -18
package/dist/types/index.d.mts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { StandardSchemaV1 } from "./standard-schema.mjs";
|
|
2
|
-
import { ESMCodeGenOptions } from "knitwork";
|
|
3
2
|
import { TypeScriptPluginConfig } from "@graphql-codegen/typescript";
|
|
4
3
|
import { plugin as plugin$1 } from "@graphql-codegen/typescript-generic-sdk";
|
|
5
4
|
import { TypeScriptDocumentsPluginConfig } from "@graphql-codegen/typescript-operations";
|
|
6
5
|
import { IResolvers } from "@graphql-tools/utils";
|
|
7
6
|
import { TypeScriptResolversPluginConfig } from "@graphql-codegen/typescript-resolvers";
|
|
7
|
+
import { ESMCodeGenOptions } from "knitwork";
|
|
8
8
|
|
|
9
9
|
//#region src/types/index.d.ts
|
|
10
10
|
type CodegenServerConfig = TypeScriptPluginConfig & TypeScriptResolversPluginConfig;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { DEFAULT_GRAPHQL_SCALARS } from "../constants/scalars.mjs";
|
|
2
|
+
import { pluginContent } from "./codegen-plugin.mjs";
|
|
1
3
|
import { defu as defu$1 } from "defu";
|
|
2
4
|
import { consola as consola$1 } from "consola";
|
|
3
5
|
import { dirname, resolve } from "pathe";
|
|
4
|
-
import { parse } from "graphql";
|
|
5
6
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
7
|
+
import { parse } from "graphql";
|
|
6
8
|
import { createHash } from "node:crypto";
|
|
7
9
|
import { codegen } from "@graphql-codegen/core";
|
|
8
10
|
import { preset } from "@graphql-codegen/import-types-preset";
|
|
@@ -13,24 +15,8 @@ import { GraphQLFileLoader } from "@graphql-tools/graphql-file-loader";
|
|
|
13
15
|
import { loadDocuments, loadSchemaSync } from "@graphql-tools/load";
|
|
14
16
|
import { UrlLoader } from "@graphql-tools/url-loader";
|
|
15
17
|
import { printSchemaWithDirectives } from "@graphql-tools/utils";
|
|
16
|
-
import { CurrencyResolver, DateTimeISOResolver, DateTimeResolver, JSONObjectResolver, JSONResolver, NonEmptyStringResolver, UUIDResolver } from "graphql-scalars";
|
|
17
18
|
|
|
18
19
|
//#region src/utils/client-codegen.ts
|
|
19
|
-
/**
|
|
20
|
-
* Plugin to add prepend comments to generated files
|
|
21
|
-
*/
|
|
22
|
-
function pluginContent(_schema, _documents, _config, _info) {
|
|
23
|
-
return {
|
|
24
|
-
prepend: [
|
|
25
|
-
"// THIS FILE IS GENERATED, DO NOT EDIT!",
|
|
26
|
-
"/* eslint-disable eslint-comments/no-unlimited-disable */",
|
|
27
|
-
"/* tslint:disable */",
|
|
28
|
-
"/* eslint-disable */",
|
|
29
|
-
"/* prettier-ignore */"
|
|
30
|
-
],
|
|
31
|
-
content: ""
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
20
|
async function graphQLLoadSchemaSync(schemaPointers, data = {}) {
|
|
35
21
|
const filteredPointers = [...Array.isArray(schemaPointers) ? schemaPointers : [schemaPointers], "!**/vfs/**"];
|
|
36
22
|
let result;
|
|
@@ -185,19 +171,7 @@ async function generateClientTypes(schema, docs, config = {}, sdkConfig = {}, ou
|
|
|
185
171
|
pureMagicComment: true,
|
|
186
172
|
dedupeOperationSuffix: true,
|
|
187
173
|
rawRequest: true,
|
|
188
|
-
scalars:
|
|
189
|
-
DateTime: DateTimeResolver.extensions.codegenScalarType,
|
|
190
|
-
DateTimeISO: DateTimeISOResolver.extensions.codegenScalarType,
|
|
191
|
-
UUID: UUIDResolver.extensions.codegenScalarType,
|
|
192
|
-
JSON: JSONResolver.extensions.codegenScalarType,
|
|
193
|
-
JSONObject: JSONObjectResolver.extensions.codegenScalarType,
|
|
194
|
-
NonEmptyString: NonEmptyStringResolver.extensions.codegenScalarType,
|
|
195
|
-
Currency: CurrencyResolver.extensions.codegenScalarType,
|
|
196
|
-
File: {
|
|
197
|
-
input: "File",
|
|
198
|
-
output: "File"
|
|
199
|
-
}
|
|
200
|
-
}
|
|
174
|
+
scalars: DEFAULT_GRAPHQL_SCALARS
|
|
201
175
|
}, config);
|
|
202
176
|
const mergedSdkConfig = defu$1(mergedConfig, sdkConfig);
|
|
203
177
|
try {
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { GraphQLSchema } from "graphql";
|
|
2
|
+
import { Source } from "@graphql-tools/utils";
|
|
3
|
+
|
|
4
|
+
//#region src/utils/codegen-plugin.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Plugin to add prepend comments to generated files
|
|
8
|
+
* Used by both server and client codegen
|
|
9
|
+
*/
|
|
10
|
+
declare function pluginContent(_schema: GraphQLSchema, _documents: Source[], _config: Record<string, unknown> | undefined, _info: Record<string, unknown> | undefined): {
|
|
11
|
+
prepend: string[];
|
|
12
|
+
content: string;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Generate the prepend header for generated files
|
|
16
|
+
* Can be used when creating files manually without codegen
|
|
17
|
+
*/
|
|
18
|
+
declare const GENERATED_FILE_HEADER = "// THIS FILE IS GENERATED, DO NOT EDIT!\n/* eslint-disable eslint-comments/no-unlimited-disable */\n/* tslint:disable */\n/* eslint-disable */\n/* prettier-ignore */\n";
|
|
19
|
+
//#endregion
|
|
20
|
+
export { GENERATED_FILE_HEADER, pluginContent };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
//#region src/utils/codegen-plugin.ts
|
|
2
|
+
/**
|
|
3
|
+
* Plugin to add prepend comments to generated files
|
|
4
|
+
* Used by both server and client codegen
|
|
5
|
+
*/
|
|
6
|
+
function pluginContent(_schema, _documents, _config, _info) {
|
|
7
|
+
return {
|
|
8
|
+
prepend: [
|
|
9
|
+
"// THIS FILE IS GENERATED, DO NOT EDIT!",
|
|
10
|
+
"/* eslint-disable eslint-comments/no-unlimited-disable */",
|
|
11
|
+
"/* tslint:disable */",
|
|
12
|
+
"/* eslint-disable */",
|
|
13
|
+
"/* prettier-ignore */"
|
|
14
|
+
],
|
|
15
|
+
content: ""
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Generate the prepend header for generated files
|
|
20
|
+
* Can be used when creating files manually without codegen
|
|
21
|
+
*/
|
|
22
|
+
const GENERATED_FILE_HEADER = `// THIS FILE IS GENERATED, DO NOT EDIT!
|
|
23
|
+
/* eslint-disable eslint-comments/no-unlimited-disable */
|
|
24
|
+
/* tslint:disable */
|
|
25
|
+
/* eslint-disable */
|
|
26
|
+
/* prettier-ignore */
|
|
27
|
+
`;
|
|
28
|
+
|
|
29
|
+
//#endregion
|
|
30
|
+
export { GENERATED_FILE_HEADER, pluginContent };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { DocumentNode, GraphQLSchema } from "graphql";
|
|
2
|
+
|
|
3
|
+
//#region src/utils/federation.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Type for buildSubgraphSchema function from @apollo/subgraph
|
|
7
|
+
*/
|
|
8
|
+
type BuildSubgraphSchemaFn = (options: {
|
|
9
|
+
typeDefs: DocumentNode;
|
|
10
|
+
resolvers: Record<string, unknown>;
|
|
11
|
+
}) => GraphQLSchema;
|
|
12
|
+
/**
|
|
13
|
+
* Dynamically load @apollo/subgraph for federation support.
|
|
14
|
+
* Returns the buildSubgraphSchema function if available, or false if the package is not installed.
|
|
15
|
+
* Result is cached for subsequent calls.
|
|
16
|
+
*/
|
|
17
|
+
declare function loadFederationSupport(): Promise<BuildSubgraphSchemaFn | false>;
|
|
18
|
+
/**
|
|
19
|
+
* Log a warning when federation is enabled but @apollo/subgraph is not available.
|
|
20
|
+
* Uses consola logger instead of console.warn for consistent logging.
|
|
21
|
+
*/
|
|
22
|
+
declare function warnFederationUnavailable(): void;
|
|
23
|
+
/**
|
|
24
|
+
* Reset the federation support cache.
|
|
25
|
+
* Useful for testing or when the module needs to be reloaded.
|
|
26
|
+
*/
|
|
27
|
+
declare function resetFederationCache(): void;
|
|
28
|
+
//#endregion
|
|
29
|
+
export { loadFederationSupport, resetFederationCache, warnFederationUnavailable };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { LOG_TAG } from "../constants.mjs";
|
|
2
|
+
import { consola as consola$1 } from "consola";
|
|
3
|
+
|
|
4
|
+
//#region src/utils/federation.ts
|
|
5
|
+
const logger = consola$1.withTag(LOG_TAG);
|
|
6
|
+
/**
|
|
7
|
+
* Cached result: function if available, false if not available, null if not checked yet
|
|
8
|
+
*/
|
|
9
|
+
let buildSubgraphSchemaCache = null;
|
|
10
|
+
/**
|
|
11
|
+
* Dynamically load @apollo/subgraph for federation support.
|
|
12
|
+
* Returns the buildSubgraphSchema function if available, or false if the package is not installed.
|
|
13
|
+
* Result is cached for subsequent calls.
|
|
14
|
+
*/
|
|
15
|
+
async function loadFederationSupport() {
|
|
16
|
+
if (buildSubgraphSchemaCache !== null) return buildSubgraphSchemaCache;
|
|
17
|
+
try {
|
|
18
|
+
buildSubgraphSchemaCache = (await import("@apollo/subgraph")).buildSubgraphSchema;
|
|
19
|
+
} catch {
|
|
20
|
+
buildSubgraphSchemaCache = false;
|
|
21
|
+
}
|
|
22
|
+
return buildSubgraphSchemaCache;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Log a warning when federation is enabled but @apollo/subgraph is not available.
|
|
26
|
+
* Uses consola logger instead of console.warn for consistent logging.
|
|
27
|
+
*/
|
|
28
|
+
function warnFederationUnavailable() {
|
|
29
|
+
logger.warn("Federation enabled but @apollo/subgraph not available, falling back to regular schema");
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Reset the federation support cache.
|
|
33
|
+
* Useful for testing or when the module needs to be reloaded.
|
|
34
|
+
*/
|
|
35
|
+
function resetFederationCache() {
|
|
36
|
+
buildSubgraphSchemaCache = null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
//#endregion
|
|
40
|
+
export { loadFederationSupport, resetFederationCache, warnFederationUnavailable };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { PathPlaceholders } from "./path-resolver.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/utils/file-writer.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Options for writing generated files
|
|
7
|
+
*/
|
|
8
|
+
interface WriteGeneratedFileOptions {
|
|
9
|
+
/** Path configuration (string path, boolean, or undefined) */
|
|
10
|
+
pathConfig: string | boolean | undefined;
|
|
11
|
+
/** Whether the category is enabled */
|
|
12
|
+
categoryEnabled: boolean | undefined;
|
|
13
|
+
/** Default path template with placeholders */
|
|
14
|
+
defaultPath: string;
|
|
15
|
+
/** Content to write */
|
|
16
|
+
content: string;
|
|
17
|
+
/** Path placeholders for resolution */
|
|
18
|
+
placeholders: PathPlaceholders;
|
|
19
|
+
/** Description for logging (e.g., "client types", "SDK") */
|
|
20
|
+
description: string;
|
|
21
|
+
/** Whether to suppress success logs */
|
|
22
|
+
silent?: boolean;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Write a generated file with path resolution and directory creation
|
|
26
|
+
* Returns the resolved path if file was written, undefined otherwise
|
|
27
|
+
*/
|
|
28
|
+
declare function writeGeneratedFile(options: WriteGeneratedFileOptions): string | undefined;
|
|
29
|
+
/**
|
|
30
|
+
* Write multiple generated files
|
|
31
|
+
* Returns array of resolved paths for files that were written
|
|
32
|
+
*/
|
|
33
|
+
declare function writeGeneratedFiles(files: WriteGeneratedFileOptions[]): (string | undefined)[];
|
|
34
|
+
//#endregion
|
|
35
|
+
export { WriteGeneratedFileOptions, writeGeneratedFile, writeGeneratedFiles };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { LOG_TAG } from "../constants.mjs";
|
|
2
|
+
import { resolveFilePath } from "./path-resolver.mjs";
|
|
3
|
+
import consola from "consola";
|
|
4
|
+
import { dirname } from "pathe";
|
|
5
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
6
|
+
|
|
7
|
+
//#region src/utils/file-writer.ts
|
|
8
|
+
const logger = consola.withTag(LOG_TAG);
|
|
9
|
+
/**
|
|
10
|
+
* Write a generated file with path resolution and directory creation
|
|
11
|
+
* Returns the resolved path if file was written, undefined otherwise
|
|
12
|
+
*/
|
|
13
|
+
function writeGeneratedFile(options) {
|
|
14
|
+
const { pathConfig, categoryEnabled, defaultPath, content, placeholders, description, silent = false } = options;
|
|
15
|
+
const resolvedPath = resolveFilePath(pathConfig, categoryEnabled, true, defaultPath, placeholders);
|
|
16
|
+
if (resolvedPath) {
|
|
17
|
+
mkdirSync(dirname(resolvedPath), { recursive: true });
|
|
18
|
+
writeFileSync(resolvedPath, content, "utf-8");
|
|
19
|
+
if (!silent) logger.success(`Generated ${description} at: ${resolvedPath}`);
|
|
20
|
+
return resolvedPath;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Write multiple generated files
|
|
25
|
+
* Returns array of resolved paths for files that were written
|
|
26
|
+
*/
|
|
27
|
+
function writeGeneratedFiles(files) {
|
|
28
|
+
return files.map((file) => writeGeneratedFile(file));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
//#endregion
|
|
32
|
+
export { writeGeneratedFile, writeGeneratedFiles };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/utils/imports.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Import utilities
|
|
4
|
+
* Helpers for generating import IDs and relative paths
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Generate a unique import ID for a file path
|
|
8
|
+
*/
|
|
9
|
+
declare function getImportId(p: string, lazy?: boolean): string;
|
|
10
|
+
/**
|
|
11
|
+
* Get relative path with a leading dot for module resolution
|
|
12
|
+
*/
|
|
13
|
+
declare function relativeWithDot(from: string, to: string): string;
|
|
14
|
+
//#endregion
|
|
15
|
+
export { getImportId, relativeWithDot };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { relative } from "pathe";
|
|
2
|
+
import { hash } from "ohash";
|
|
3
|
+
|
|
4
|
+
//#region src/utils/imports.ts
|
|
5
|
+
/**
|
|
6
|
+
* Import utilities
|
|
7
|
+
* Helpers for generating import IDs and relative paths
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Generate a unique import ID for a file path
|
|
11
|
+
*/
|
|
12
|
+
function getImportId(p, lazy) {
|
|
13
|
+
return (lazy ? "_lazy_" : "_") + hash(p).replace(/-/g, "").slice(0, 6);
|
|
14
|
+
}
|
|
15
|
+
const RELATIVE_RE = /^\.{1,2}\//;
|
|
16
|
+
/**
|
|
17
|
+
* Get relative path with a leading dot for module resolution
|
|
18
|
+
*/
|
|
19
|
+
function relativeWithDot(from, to) {
|
|
20
|
+
const rel = relative(from, to);
|
|
21
|
+
return RELATIVE_RE.test(rel) ? rel : `./${rel}`;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
//#endregion
|
|
25
|
+
export { getImportId, relativeWithDot };
|
package/dist/utils/index.d.mts
CHANGED
|
@@ -1,40 +1,13 @@
|
|
|
1
|
-
import { GenImport } from "../types/index.mjs";
|
|
2
1
|
import { directiveParser, generateDirectiveSchema, generateDirectiveSchemas } from "./directive-parser.mjs";
|
|
3
2
|
import { createDefaultMaskError } from "./errors.mjs";
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
declare function getLayerServerDirectories(nitro: Nitro): string[];
|
|
16
|
-
/**
|
|
17
|
-
* Get all Nuxt layer app directories from Nitro config
|
|
18
|
-
*/
|
|
19
|
-
declare function getLayerAppDirectories(nitro: Nitro): string[];
|
|
20
|
-
/**
|
|
21
|
-
* Generate layer-aware ignore patterns for auto-generated files
|
|
22
|
-
*/
|
|
23
|
-
declare function generateLayerIgnorePatterns(): string[];
|
|
24
|
-
declare function getImportId(p: string, lazy?: boolean): string;
|
|
25
|
-
declare function relativeWithDot(from: string, to: string): string;
|
|
26
|
-
declare function scanGraphql(nitro: Nitro): Promise<string[]>;
|
|
27
|
-
declare function scanResolvers(nitro: Nitro): Promise<GenImport[]>;
|
|
28
|
-
declare function scanDirectives(nitro: Nitro): Promise<GenImport[]>;
|
|
29
|
-
declare function scanSchemas(nitro: Nitro): Promise<string[]>;
|
|
30
|
-
declare function scanDocuments(nitro: Nitro): Promise<string[]>;
|
|
31
|
-
/**
|
|
32
|
-
* Scan documents for a specific external service
|
|
33
|
-
*/
|
|
34
|
-
declare function scanExternalServiceDocs(nitro: Nitro, serviceName: string, patterns: string[]): Promise<string[]>;
|
|
35
|
-
/**
|
|
36
|
-
* Validate external GraphQL service configuration
|
|
37
|
-
*/
|
|
38
|
-
declare function validateExternalServices(services: unknown[]): string[];
|
|
39
|
-
//#endregion
|
|
40
|
-
export { GLOB_SCAN_PATTERN, createDefaultMaskError, directiveParser, generateDirectiveSchema, generateDirectiveSchemas, generateLayerIgnorePatterns, getImportId, getLayerAppDirectories, getLayerDirectories, getLayerServerDirectories, relativeWithDot, scanDirectives, scanDocuments, scanExternalServiceDocs, scanGraphql, scanResolvers, scanSchemas, validateExternalServices };
|
|
3
|
+
import { loadFederationSupport, resetFederationCache, warnFederationUnavailable } from "./federation.mjs";
|
|
4
|
+
import { getImportId, relativeWithDot } from "./imports.mjs";
|
|
5
|
+
import { generateLayerIgnorePatterns, getLayerAppDirectories, getLayerDirectories, getLayerServerDirectories } from "./layers.mjs";
|
|
6
|
+
import { FileInfo, deduplicateFiles, scanDir } from "./scanning/common.mjs";
|
|
7
|
+
import { scanDirectives } from "./scanning/directives.mjs";
|
|
8
|
+
import { scanDocuments, scanExternalServiceDocs } from "./scanning/documents.mjs";
|
|
9
|
+
import { scanResolvers } from "./scanning/resolvers.mjs";
|
|
10
|
+
import { scanGraphql, scanSchemas } from "./scanning/schemas.mjs";
|
|
11
|
+
import "./scanning/index.mjs";
|
|
12
|
+
import { validateExternalServices } from "./validation.mjs";
|
|
13
|
+
export { type FileInfo, createDefaultMaskError, deduplicateFiles, directiveParser, generateDirectiveSchema, generateDirectiveSchemas, generateLayerIgnorePatterns, getImportId, getLayerAppDirectories, getLayerDirectories, getLayerServerDirectories, loadFederationSupport, relativeWithDot, resetFederationCache, scanDir, scanDirectives, scanDocuments, scanExternalServiceDocs, scanGraphql, scanResolvers, scanSchemas, validateExternalServices, warnFederationUnavailable };
|
package/dist/utils/index.mjs
CHANGED
|
@@ -1,290 +1,13 @@
|
|
|
1
|
+
import { loadFederationSupport, resetFederationCache, warnFederationUnavailable } from "./federation.mjs";
|
|
1
2
|
import { directiveParser, generateDirectiveSchema, generateDirectiveSchemas } from "./directive-parser.mjs";
|
|
2
3
|
import { createDefaultMaskError } from "./errors.mjs";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
4
|
+
import { getImportId, relativeWithDot } from "./imports.mjs";
|
|
5
|
+
import { generateLayerIgnorePatterns, getLayerAppDirectories, getLayerDirectories, getLayerServerDirectories } from "./layers.mjs";
|
|
6
|
+
import { deduplicateFiles, scanDir } from "./scanning/common.mjs";
|
|
7
|
+
import { scanDirectives } from "./scanning/directives.mjs";
|
|
8
|
+
import { scanDocuments, scanExternalServiceDocs } from "./scanning/documents.mjs";
|
|
9
|
+
import { scanResolvers } from "./scanning/resolvers.mjs";
|
|
10
|
+
import { scanGraphql, scanSchemas } from "./scanning/schemas.mjs";
|
|
11
|
+
import { validateExternalServices } from "./validation.mjs";
|
|
8
12
|
|
|
9
|
-
|
|
10
|
-
const GLOB_SCAN_PATTERN = "**/*.{graphql,gql,js,mjs,cjs,ts,mts,cts,tsx,jsx}";
|
|
11
|
-
/**
|
|
12
|
-
* Get all Nuxt layer directories from Nitro config
|
|
13
|
-
*/
|
|
14
|
-
function getLayerDirectories(nitro) {
|
|
15
|
-
return nitro.options.graphql?.layerDirectories || [];
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Get all Nuxt layer server directories from Nitro config
|
|
19
|
-
*/
|
|
20
|
-
function getLayerServerDirectories(nitro) {
|
|
21
|
-
return nitro.options.graphql?.layerServerDirs || [];
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Get all Nuxt layer app directories from Nitro config
|
|
25
|
-
*/
|
|
26
|
-
function getLayerAppDirectories(nitro) {
|
|
27
|
-
return nitro.options.graphql?.layerAppDirs || [];
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Generate layer-aware ignore patterns for auto-generated files
|
|
31
|
-
*/
|
|
32
|
-
function generateLayerIgnorePatterns() {
|
|
33
|
-
return [];
|
|
34
|
-
}
|
|
35
|
-
function getImportId(p, lazy) {
|
|
36
|
-
return (lazy ? "_lazy_" : "_") + hash(p).replace(/-/g, "").slice(0, 6);
|
|
37
|
-
}
|
|
38
|
-
const RELATIVE_RE = /^\.{1,2}\//;
|
|
39
|
-
function relativeWithDot(from, to) {
|
|
40
|
-
const rel = relative(from, to);
|
|
41
|
-
return RELATIVE_RE.test(rel) ? rel : `./${rel}`;
|
|
42
|
-
}
|
|
43
|
-
async function scanGraphql(nitro) {
|
|
44
|
-
const serverDirRelative = relative(nitro.options.rootDir, nitro.graphql.serverDir);
|
|
45
|
-
const files = await scanDir(nitro, nitro.options.rootDir, serverDirRelative, "**/*.{graphql,gql}");
|
|
46
|
-
const layerServerDirs = getLayerServerDirectories(nitro);
|
|
47
|
-
const layerFiles = await Promise.all(layerServerDirs.map((layerServerDir) => scanDir(nitro, layerServerDir, "graphql", "**/*.{graphql,gql}"))).then((r) => r.flat());
|
|
48
|
-
const allFiles = [...files, ...layerFiles];
|
|
49
|
-
const seenPaths = /* @__PURE__ */ new Set();
|
|
50
|
-
return allFiles.filter((file) => {
|
|
51
|
-
if (seenPaths.has(file.fullPath)) return false;
|
|
52
|
-
seenPaths.add(file.fullPath);
|
|
53
|
-
return true;
|
|
54
|
-
}).map((f) => f.fullPath);
|
|
55
|
-
}
|
|
56
|
-
async function scanResolvers(nitro) {
|
|
57
|
-
const serverDirRelative = relative(nitro.options.rootDir, nitro.graphql.serverDir);
|
|
58
|
-
const regularFiles = await scanDir(nitro, nitro.options.rootDir, serverDirRelative, "**/*.resolver.{ts,js}");
|
|
59
|
-
const layerServerDirs = getLayerServerDirectories(nitro);
|
|
60
|
-
const layerFiles = await Promise.all(layerServerDirs.map((layerServerDir) => scanDir(nitro, layerServerDir, "graphql", "**/*.resolver.{ts,js}"))).then((r) => r.flat());
|
|
61
|
-
const allFiles = [...regularFiles, ...layerFiles];
|
|
62
|
-
const seenPaths = /* @__PURE__ */ new Set();
|
|
63
|
-
const files = allFiles.filter((file) => {
|
|
64
|
-
if (seenPaths.has(file.fullPath)) return false;
|
|
65
|
-
seenPaths.add(file.fullPath);
|
|
66
|
-
return true;
|
|
67
|
-
});
|
|
68
|
-
const exportName = [];
|
|
69
|
-
const VALID_DEFINE_FUNCTIONS = [
|
|
70
|
-
"defineResolver",
|
|
71
|
-
"defineQuery",
|
|
72
|
-
"defineMutation",
|
|
73
|
-
"defineField",
|
|
74
|
-
"defineSubscription",
|
|
75
|
-
"defineDirective"
|
|
76
|
-
];
|
|
77
|
-
for (const file of files) try {
|
|
78
|
-
const fileContent = await readFile(file.fullPath, "utf-8");
|
|
79
|
-
const parsed = parseSync(file.fullPath, fileContent);
|
|
80
|
-
if (parsed.errors && parsed.errors.length > 0) {
|
|
81
|
-
if (nitro.options.dev) {
|
|
82
|
-
const fileName = basename(file.fullPath);
|
|
83
|
-
const firstError = parsed.errors[0];
|
|
84
|
-
const location = firstError?.labels?.[0];
|
|
85
|
-
const lineInfo = location ? `:${location.start}` : "";
|
|
86
|
-
const message = firstError?.message.split(",")[0] || "Syntax error";
|
|
87
|
-
console.error(`✖ ${fileName}${lineInfo} - ${message}`);
|
|
88
|
-
}
|
|
89
|
-
continue;
|
|
90
|
-
}
|
|
91
|
-
const exports = {
|
|
92
|
-
imports: [],
|
|
93
|
-
specifier: file.fullPath
|
|
94
|
-
};
|
|
95
|
-
let hasDefaultExport = false;
|
|
96
|
-
let hasNamedExport = false;
|
|
97
|
-
const namedExports = [];
|
|
98
|
-
for (const node of parsed.program.body) {
|
|
99
|
-
if (node.type === "ExportDefaultDeclaration") hasDefaultExport = true;
|
|
100
|
-
if (node.type === "ExportNamedDeclaration" && node.declaration && node.declaration.type === "VariableDeclaration") {
|
|
101
|
-
for (const decl of node.declaration.declarations) if (decl.type === "VariableDeclarator" && decl.init && decl.id.type === "Identifier") {
|
|
102
|
-
hasNamedExport = true;
|
|
103
|
-
namedExports.push(decl.id.name);
|
|
104
|
-
if (decl.init && decl.init.type === "CallExpression") {
|
|
105
|
-
if (decl.init.callee.type === "Identifier" && decl.init.callee.name === "defineResolver") exports.imports.push({
|
|
106
|
-
name: decl.id.name,
|
|
107
|
-
type: "resolver",
|
|
108
|
-
as: `_${hash(decl.id.name + file.fullPath).replace(/-/g, "").slice(0, 6)}`
|
|
109
|
-
});
|
|
110
|
-
if (decl.init.callee.type === "Identifier" && decl.init.callee.name === "defineQuery") exports.imports.push({
|
|
111
|
-
name: decl.id.name,
|
|
112
|
-
type: "query",
|
|
113
|
-
as: `_${hash(decl.id.name + file.fullPath).replace(/-/g, "").slice(0, 6)}`
|
|
114
|
-
});
|
|
115
|
-
if (decl.init.callee.type === "Identifier" && decl.init.callee.name === "defineMutation") exports.imports.push({
|
|
116
|
-
name: decl.id.name,
|
|
117
|
-
type: "mutation",
|
|
118
|
-
as: `_${hash(decl.id.name + file.fullPath).replace(/-/g, "").slice(0, 6)}`
|
|
119
|
-
});
|
|
120
|
-
if (decl.init.callee.type === "Identifier" && decl.init.callee.name === "defineField") exports.imports.push({
|
|
121
|
-
name: decl.id.name,
|
|
122
|
-
type: "type",
|
|
123
|
-
as: `_${hash(decl.id.name + file.fullPath).replace(/-/g, "").slice(0, 6)}`
|
|
124
|
-
});
|
|
125
|
-
if (decl.init.callee.type === "Identifier" && decl.init.callee.name === "defineSubscription") exports.imports.push({
|
|
126
|
-
name: decl.id.name,
|
|
127
|
-
type: "subscription",
|
|
128
|
-
as: `_${hash(decl.id.name + file.fullPath).replace(/-/g, "").slice(0, 6)}`
|
|
129
|
-
});
|
|
130
|
-
if (decl.init.callee.type === "Identifier" && decl.init.callee.name === "defineDirective") exports.imports.push({
|
|
131
|
-
name: decl.id.name,
|
|
132
|
-
type: "directive",
|
|
133
|
-
as: `_${hash(decl.id.name + file.fullPath).replace(/-/g, "").slice(0, 6)}`
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
if (nitro.options.dev) {
|
|
140
|
-
const relPath = relative(nitro.options.rootDir, file.fullPath);
|
|
141
|
-
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.`);
|
|
142
|
-
if (exports.imports.length === 0 && hasNamedExport) {
|
|
143
|
-
const validFunctions = VALID_DEFINE_FUNCTIONS.join(", ");
|
|
144
|
-
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.`);
|
|
145
|
-
}
|
|
146
|
-
if (!hasDefaultExport && !hasNamedExport) nitro.logger.warn(`[nitro-graphql] ${relPath}: No exports found. Resolver files must export resolvers using defineResolver, defineQuery, defineMutation, etc.`);
|
|
147
|
-
}
|
|
148
|
-
if (exports.imports.length > 0) exportName.push(exports);
|
|
149
|
-
} catch (error) {
|
|
150
|
-
const relPath = relative(nitro.options.rootDir, file.fullPath);
|
|
151
|
-
nitro.logger.error(`[nitro-graphql] Failed to parse resolver file ${relPath}:`, error);
|
|
152
|
-
}
|
|
153
|
-
return exportName;
|
|
154
|
-
}
|
|
155
|
-
async function scanDirectives(nitro) {
|
|
156
|
-
const serverDirRelative = relative(nitro.options.rootDir, nitro.graphql.serverDir);
|
|
157
|
-
const regularFiles = await scanDir(nitro, nitro.options.rootDir, serverDirRelative, "**/*.directive.{ts,js}");
|
|
158
|
-
const layerServerDirs = getLayerServerDirectories(nitro);
|
|
159
|
-
const layerFiles = await Promise.all(layerServerDirs.map((layerServerDir) => scanDir(nitro, layerServerDir, "graphql", "**/*.directive.{ts,js}"))).then((r) => r.flat());
|
|
160
|
-
const allFiles = [...regularFiles, ...layerFiles];
|
|
161
|
-
const seenPaths = /* @__PURE__ */ new Set();
|
|
162
|
-
const files = allFiles.filter((file) => {
|
|
163
|
-
if (seenPaths.has(file.fullPath)) return false;
|
|
164
|
-
seenPaths.add(file.fullPath);
|
|
165
|
-
return true;
|
|
166
|
-
});
|
|
167
|
-
const exportName = [];
|
|
168
|
-
for (const file of files) {
|
|
169
|
-
const fileContent = await readFile(file.fullPath, "utf-8");
|
|
170
|
-
const parsed = parseSync(file.fullPath, fileContent);
|
|
171
|
-
const exports = {
|
|
172
|
-
imports: [],
|
|
173
|
-
specifier: file.fullPath
|
|
174
|
-
};
|
|
175
|
-
for (const node of parsed.program.body) if (node.type === "ExportNamedDeclaration" && node.declaration && node.declaration.type === "VariableDeclaration") {
|
|
176
|
-
for (const decl of node.declaration.declarations) if (decl.type === "VariableDeclarator" && decl.init && decl.id.type === "Identifier") {
|
|
177
|
-
if (decl.init && decl.init.type === "CallExpression") {
|
|
178
|
-
if (decl.init.callee.type === "Identifier" && decl.init.callee.name === "defineDirective") exports.imports.push({
|
|
179
|
-
name: decl.id.name,
|
|
180
|
-
type: "directive",
|
|
181
|
-
as: `_${hash(decl.id.name + file.fullPath).replace(/-/g, "").slice(0, 6)}`
|
|
182
|
-
});
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
if (exports.imports.length > 0) exportName.push(exports);
|
|
187
|
-
}
|
|
188
|
-
return exportName;
|
|
189
|
-
}
|
|
190
|
-
async function scanSchemas(nitro) {
|
|
191
|
-
const serverDirRelative = relative(nitro.options.rootDir, nitro.graphql.serverDir);
|
|
192
|
-
const files = await scanDir(nitro, nitro.options.rootDir, serverDirRelative, "**/*.graphql");
|
|
193
|
-
const layerServerDirs = getLayerServerDirectories(nitro);
|
|
194
|
-
const layerFiles = await Promise.all(layerServerDirs.map((layerServerDir) => scanDir(nitro, layerServerDir, "graphql", "**/*.graphql"))).then((r) => r.flat());
|
|
195
|
-
const allFiles = [...files, ...layerFiles];
|
|
196
|
-
const seenPaths = /* @__PURE__ */ new Set();
|
|
197
|
-
return allFiles.filter((file) => {
|
|
198
|
-
if (seenPaths.has(file.fullPath)) return false;
|
|
199
|
-
seenPaths.add(file.fullPath);
|
|
200
|
-
return true;
|
|
201
|
-
}).map((f) => f.fullPath);
|
|
202
|
-
}
|
|
203
|
-
async function scanDocuments(nitro) {
|
|
204
|
-
const files = await scanDir(nitro, nitro.options.rootDir, nitro.graphql.dir.client, "**/*.graphql");
|
|
205
|
-
const layerAppDirs = getLayerAppDirectories(nitro);
|
|
206
|
-
const layerFiles = await Promise.all(layerAppDirs.map((layerAppDir) => scanDir(nitro, layerAppDir, "graphql", "**/*.graphql"))).then((r) => r.flat());
|
|
207
|
-
const combinedFiles = [...files, ...layerFiles];
|
|
208
|
-
const seenPaths = /* @__PURE__ */ new Set();
|
|
209
|
-
const allFiles = combinedFiles.filter((file) => {
|
|
210
|
-
if (seenPaths.has(file.fullPath)) return false;
|
|
211
|
-
seenPaths.add(file.fullPath);
|
|
212
|
-
return true;
|
|
213
|
-
});
|
|
214
|
-
const externalPatterns = (nitro.options.graphql?.externalServices || []).flatMap((service) => service.documents || []);
|
|
215
|
-
return allFiles.filter((f) => !f.path.startsWith("external/")).filter((f) => {
|
|
216
|
-
const relativePath = f.path;
|
|
217
|
-
for (const pattern of externalPatterns) {
|
|
218
|
-
const clientDirPattern = `${nitro.graphql.dir.client}/`;
|
|
219
|
-
if (pattern.replace(/* @__PURE__ */ new RegExp(`^${clientDirPattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}`), "").split("/")[0] === relativePath.split("/")[0]) return false;
|
|
220
|
-
}
|
|
221
|
-
return true;
|
|
222
|
-
}).map((f) => f.fullPath);
|
|
223
|
-
}
|
|
224
|
-
/**
|
|
225
|
-
* Scan documents for a specific external service
|
|
226
|
-
*/
|
|
227
|
-
async function scanExternalServiceDocs(nitro, serviceName, patterns) {
|
|
228
|
-
if (!patterns.length) return [];
|
|
229
|
-
const files = [];
|
|
230
|
-
for (const pattern of patterns) try {
|
|
231
|
-
const serviceFiles = await glob(pattern, {
|
|
232
|
-
cwd: nitro.options.rootDir,
|
|
233
|
-
dot: true,
|
|
234
|
-
ignore: nitro.options.ignore,
|
|
235
|
-
absolute: true
|
|
236
|
-
});
|
|
237
|
-
files.push(...serviceFiles);
|
|
238
|
-
} catch (error) {
|
|
239
|
-
nitro.logger.warn(`[graphql:${serviceName}] Error scanning documents with pattern "${pattern}":`, error);
|
|
240
|
-
}
|
|
241
|
-
return files.filter((file, index, self) => self.indexOf(file) === index);
|
|
242
|
-
}
|
|
243
|
-
/**
|
|
244
|
-
* Validate external GraphQL service configuration
|
|
245
|
-
*/
|
|
246
|
-
function validateExternalServices(services) {
|
|
247
|
-
const errors = [];
|
|
248
|
-
const serviceNames = /* @__PURE__ */ new Set();
|
|
249
|
-
for (const [index, service] of services.entries()) {
|
|
250
|
-
const prefix = `externalServices[${index}]`;
|
|
251
|
-
if (!service || typeof service !== "object") {
|
|
252
|
-
errors.push(`${prefix} must be an object`);
|
|
253
|
-
continue;
|
|
254
|
-
}
|
|
255
|
-
if (!("name" in service) || typeof service.name !== "string") errors.push(`${prefix}.name is required and must be a string`);
|
|
256
|
-
else if (serviceNames.has(service.name)) errors.push(`${prefix}.name "${service.name}" must be unique`);
|
|
257
|
-
else serviceNames.add(service.name);
|
|
258
|
-
if (!("schema" in service) || !service.schema) errors.push(`${prefix}.schema is required`);
|
|
259
|
-
if (!("endpoint" in service) || typeof service.endpoint !== "string") errors.push(`${prefix}.endpoint is required and must be a string`);
|
|
260
|
-
else try {
|
|
261
|
-
new URL(service.endpoint);
|
|
262
|
-
} catch {
|
|
263
|
-
errors.push(`${prefix}.endpoint "${service.endpoint}" must be a valid URL`);
|
|
264
|
-
}
|
|
265
|
-
if ("name" in service && service.name && typeof service.name === "string" && !/^[a-z]\w*$/i.test(service.name)) errors.push(`${prefix}.name "${service.name}" must be a valid identifier (letters, numbers, underscore, starting with letter)`);
|
|
266
|
-
}
|
|
267
|
-
return errors;
|
|
268
|
-
}
|
|
269
|
-
async function scanDir(nitro, dir, name, globPattern = GLOB_SCAN_PATTERN) {
|
|
270
|
-
return (await glob(join(name, globPattern), {
|
|
271
|
-
cwd: dir,
|
|
272
|
-
dot: true,
|
|
273
|
-
ignore: nitro.options.ignore,
|
|
274
|
-
absolute: true
|
|
275
|
-
}).catch((error) => {
|
|
276
|
-
if (error?.code === "ENOTDIR") {
|
|
277
|
-
nitro.logger.warn(`Ignoring \`${join(dir, name)}\`. It must be a directory.`);
|
|
278
|
-
return [];
|
|
279
|
-
}
|
|
280
|
-
throw error;
|
|
281
|
-
})).map((fullPath) => {
|
|
282
|
-
return {
|
|
283
|
-
fullPath,
|
|
284
|
-
path: relative(join(dir, name), fullPath)
|
|
285
|
-
};
|
|
286
|
-
}).sort((a, b) => a.path.localeCompare(b.path));
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
//#endregion
|
|
290
|
-
export { GLOB_SCAN_PATTERN, createDefaultMaskError, directiveParser, generateDirectiveSchema, generateDirectiveSchemas, generateLayerIgnorePatterns, getImportId, getLayerAppDirectories, getLayerDirectories, getLayerServerDirectories, relativeWithDot, scanDirectives, scanDocuments, scanExternalServiceDocs, scanGraphql, scanResolvers, scanSchemas, validateExternalServices };
|
|
13
|
+
export { createDefaultMaskError, deduplicateFiles, directiveParser, generateDirectiveSchema, generateDirectiveSchemas, generateLayerIgnorePatterns, getImportId, getLayerAppDirectories, getLayerDirectories, getLayerServerDirectories, loadFederationSupport, relativeWithDot, resetFederationCache, scanDir, scanDirectives, scanDocuments, scanExternalServiceDocs, scanGraphql, scanResolvers, scanSchemas, validateExternalServices, warnFederationUnavailable };
|