nitro-graphql 2.0.0-beta.3 → 2.0.0-beta.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +476 -19
- package/dist/define.d.mts +296 -0
- package/dist/define.mjs +323 -0
- package/dist/ecosystem/nuxt.mjs +109 -0
- package/dist/index.d.mts +43 -0
- package/dist/index.mjs +63 -0
- package/dist/rollup.d.mts +12 -0
- package/dist/rollup.mjs +282 -0
- package/dist/routes/apollo-server.d.mts +6 -0
- package/dist/routes/{apollo-server.js → apollo-server.mjs} +7 -7
- package/dist/routes/debug.d.mts +61 -0
- package/dist/routes/debug.mjs +445 -0
- package/dist/routes/graphql-yoga.d.mts +6 -0
- package/dist/routes/{graphql-yoga.js → graphql-yoga.mjs} +11 -7
- package/dist/routes/health.d.mts +10 -0
- package/dist/routes/{health.js → health.mjs} +3 -2
- package/dist/setup.d.mts +11 -0
- package/dist/setup.mjs +392 -0
- package/dist/{utils/define.d.ts → types/define.d.mts} +4 -27
- package/dist/types/define.mjs +1 -0
- package/dist/types/index.d.mts +246 -0
- package/dist/types/index.mjs +1 -0
- package/dist/types/standard-schema.mjs +1 -0
- package/dist/utils/{apollo.d.ts → apollo.d.mts} +2 -2
- package/dist/utils/apollo.mjs +59 -0
- package/dist/utils/{client-codegen.d.ts → client-codegen.d.mts} +6 -3
- package/dist/utils/{client-codegen.js → client-codegen.mjs} +6 -6
- package/dist/utils/errors.d.mts +73 -0
- package/dist/utils/errors.mjs +89 -0
- package/dist/utils/file-generator.d.mts +37 -0
- package/dist/utils/file-generator.mjs +72 -0
- package/dist/utils/{index.d.ts → index.d.mts} +4 -3
- package/dist/utils/{index.js → index.mjs} +76 -37
- package/dist/utils/path-resolver.d.mts +70 -0
- package/dist/utils/path-resolver.mjs +127 -0
- package/dist/utils/{server-codegen.d.ts → server-codegen.d.mts} +1 -1
- package/dist/utils/{server-codegen.js → server-codegen.mjs} +3 -3
- package/dist/utils/type-generation.d.mts +12 -0
- package/dist/utils/type-generation.mjs +420 -0
- package/dist/virtual/debug-info.d.mts +9 -0
- package/dist/virtual/debug-info.mjs +26 -0
- package/dist/virtual/graphql-config.d.mts +9 -0
- package/dist/virtual/graphql-config.mjs +10 -0
- package/dist/virtual/module-config.d.mts +9 -0
- package/dist/virtual/module-config.mjs +10 -0
- package/dist/virtual/server-directives.d.mts +11 -0
- package/dist/virtual/server-directives.mjs +10 -0
- package/dist/virtual/server-resolvers.d.mts +11 -0
- package/dist/virtual/server-resolvers.mjs +10 -0
- package/dist/virtual/server-schemas.d.mts +11 -0
- package/dist/virtual/server-schemas.mjs +10 -0
- package/package.json +79 -70
- package/dist/ecosystem/nuxt.js +0 -67
- package/dist/index.d.ts +0 -8
- package/dist/index.js +0 -264
- package/dist/rollup.js +0 -114
- package/dist/routes/apollo-server.d.ts +0 -6
- package/dist/routes/graphql-yoga.d.ts +0 -6
- package/dist/routes/health.d.ts +0 -6
- package/dist/types/index.d.ts +0 -128
- package/dist/utils/apollo.js +0 -61
- package/dist/utils/define.js +0 -57
- package/dist/utils/type-generation.d.ts +0 -7
- package/dist/utils/type-generation.js +0 -287
- /package/dist/ecosystem/{nuxt.d.ts → nuxt.d.mts} +0 -0
- /package/dist/graphql/{index.d.ts → index.d.mts} +0 -0
- /package/dist/graphql/{index.js → index.mjs} +0 -0
- /package/dist/graphql/{server.d.ts → server.d.mts} +0 -0
- /package/dist/graphql/{server.js → server.mjs} +0 -0
- /package/dist/types/{standard-schema.d.ts → standard-schema.d.mts} +0 -0
- /package/dist/utils/{directive-parser.d.ts → directive-parser.d.mts} +0 -0
- /package/dist/utils/{directive-parser.js → directive-parser.mjs} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { ApolloServer, BaseContext, ContextFunction } from "@apollo/server";
|
|
2
|
-
import { EventHandler, H3Event } from "h3";
|
|
3
|
-
import { WithRequired } from "@apollo/utils.withrequired";
|
|
2
|
+
import { EventHandler, H3Event } from "nitro/h3";
|
|
4
3
|
import { Hooks } from "crossws";
|
|
5
4
|
|
|
6
5
|
//#region src/utils/apollo.d.ts
|
|
6
|
+
type WithRequired<T, K extends keyof T> = T & { [P in K]-?: T[P] };
|
|
7
7
|
interface H3ContextFunctionArgument {
|
|
8
8
|
event: H3Event;
|
|
9
9
|
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { HeaderMap } from "@apollo/server";
|
|
2
|
+
import { eventHandler, getRequestURL, readBody } from "nitro/h3";
|
|
3
|
+
|
|
4
|
+
//#region src/utils/apollo.ts
|
|
5
|
+
function startServerAndCreateH3Handler(server, options) {
|
|
6
|
+
const defaultContext = () => Promise.resolve({});
|
|
7
|
+
const contextFunction = options?.context ?? defaultContext;
|
|
8
|
+
return eventHandler(async (event) => {
|
|
9
|
+
const apolloServer = typeof server === "function" ? server() : server;
|
|
10
|
+
if (!options?.serverAlreadyStarted) apolloServer.startInBackgroundHandlingStartupErrorsByLoggingAndFailingAllRequests();
|
|
11
|
+
if (event.req.method === "OPTIONS") {
|
|
12
|
+
event.res.status = 204;
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
try {
|
|
16
|
+
const graphqlRequest = await toGraphqlRequest(event);
|
|
17
|
+
const { body, headers, status } = await apolloServer.executeHTTPGraphQLRequest({
|
|
18
|
+
httpGraphQLRequest: graphqlRequest,
|
|
19
|
+
context: () => contextFunction({ event })
|
|
20
|
+
});
|
|
21
|
+
if (body.kind === "chunked") throw new Error("Incremental delivery not implemented");
|
|
22
|
+
for (const [key, value] of headers) event.res.headers.set(key, value);
|
|
23
|
+
event.res.status = status || 200;
|
|
24
|
+
return body.string;
|
|
25
|
+
} catch (error) {
|
|
26
|
+
if (error instanceof SyntaxError) {
|
|
27
|
+
event.res.status = 400;
|
|
28
|
+
return error.message;
|
|
29
|
+
} else throw error;
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
async function toGraphqlRequest(event) {
|
|
34
|
+
const url = getRequestURL(event);
|
|
35
|
+
return {
|
|
36
|
+
method: event.req.method || "POST",
|
|
37
|
+
headers: normalizeHeaders(Object.fromEntries(event.req.headers.entries())),
|
|
38
|
+
search: url.search.slice(1),
|
|
39
|
+
body: await normalizeBody(event)
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function normalizeHeaders(headers) {
|
|
43
|
+
const headerMap = new HeaderMap();
|
|
44
|
+
for (const [key, value] of Object.entries(headers)) if (value !== void 0) headerMap.set(key, value);
|
|
45
|
+
return headerMap;
|
|
46
|
+
}
|
|
47
|
+
async function normalizeBody(event) {
|
|
48
|
+
const PayloadMethods = [
|
|
49
|
+
"PATCH",
|
|
50
|
+
"POST",
|
|
51
|
+
"PUT",
|
|
52
|
+
"DELETE"
|
|
53
|
+
];
|
|
54
|
+
const method = event.req.method;
|
|
55
|
+
if (method && PayloadMethods.includes(method)) return await readBody(event);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
//#endregion
|
|
59
|
+
export { startServerAndCreateH3Handler };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CodegenClientConfig, ExternalGraphQLService, GenericSdkConfig } from "../types/index.
|
|
1
|
+
import { CodegenClientConfig, ExternalGraphQLService, GenericSdkConfig } from "../types/index.mjs";
|
|
2
2
|
import { GraphQLSchema } from "graphql";
|
|
3
3
|
import { Source } from "@graphql-tools/utils";
|
|
4
4
|
import { LoadSchemaOptions, UnnormalizedTypeDefPointer } from "@graphql-tools/load";
|
|
@@ -23,14 +23,17 @@ declare function loadExternalSchema(service: ExternalGraphQLService, buildDir?:
|
|
|
23
23
|
*/
|
|
24
24
|
declare function downloadAndSaveSchema(service: ExternalGraphQLService, buildDir: string): Promise<string | undefined>;
|
|
25
25
|
declare function loadGraphQLDocuments(patterns: string | string[]): Promise<Source[]>;
|
|
26
|
-
declare function generateClientTypes(schema: GraphQLSchema, docs: Source[], config?: CodegenClientConfig, sdkConfig?: GenericSdkConfig, outputPath?: string, serviceName?: string
|
|
26
|
+
declare function generateClientTypes(schema: GraphQLSchema, docs: Source[], config?: CodegenClientConfig, sdkConfig?: GenericSdkConfig, outputPath?: string, serviceName?: string, virtualTypesPath?: string, options?: {
|
|
27
|
+
silent?: boolean;
|
|
28
|
+
isInitial?: boolean;
|
|
29
|
+
}): Promise<false | {
|
|
27
30
|
types: string;
|
|
28
31
|
sdk: string;
|
|
29
32
|
}>;
|
|
30
33
|
/**
|
|
31
34
|
* Generate client types for external GraphQL service
|
|
32
35
|
*/
|
|
33
|
-
declare function generateExternalClientTypes(service: ExternalGraphQLService, schema: GraphQLSchema, docs: Source[]): Promise<{
|
|
36
|
+
declare function generateExternalClientTypes(service: ExternalGraphQLService, schema: GraphQLSchema, docs: Source[], virtualTypesPath?: string): Promise<{
|
|
34
37
|
types: string;
|
|
35
38
|
sdk: string;
|
|
36
39
|
} | false>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { defu as defu$1 } from "defu";
|
|
1
2
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
3
|
import { consola as consola$1 } from "consola";
|
|
3
|
-
import { defu as defu$1 } from "defu";
|
|
4
4
|
import { dirname, resolve } from "pathe";
|
|
5
5
|
import { parse } from "graphql";
|
|
6
6
|
import { printSchemaWithDirectives } from "@graphql-tools/utils";
|
|
@@ -165,9 +165,9 @@ async function loadGraphQLDocuments(patterns) {
|
|
|
165
165
|
else throw e;
|
|
166
166
|
}
|
|
167
167
|
}
|
|
168
|
-
async function generateClientTypes(schema, docs, config = {}, sdkConfig = {}, outputPath, serviceName) {
|
|
168
|
+
async function generateClientTypes(schema, docs, config = {}, sdkConfig = {}, outputPath, serviceName, virtualTypesPath, options = {}) {
|
|
169
169
|
if (docs.length === 0 && !serviceName) {
|
|
170
|
-
consola$1.info("No client GraphQL files found. Skipping client type generation.");
|
|
170
|
+
if (!options.silent && options.isInitial) consola$1.info("No client GraphQL files found. Skipping client type generation.");
|
|
171
171
|
return false;
|
|
172
172
|
}
|
|
173
173
|
const serviceLabel = serviceName ? `:${serviceName}` : "";
|
|
@@ -252,7 +252,7 @@ export function getSdk(requester: Requester): Sdk {
|
|
|
252
252
|
typescriptOperations: { plugin: plugin$2 }
|
|
253
253
|
}
|
|
254
254
|
});
|
|
255
|
-
const typesPath = serviceName ? `#graphql/client/${serviceName}` : "#graphql/client";
|
|
255
|
+
const typesPath = virtualTypesPath || (serviceName ? `#graphql/client/${serviceName}` : "#graphql/client");
|
|
256
256
|
const sdkOutput = await preset.buildGeneratesSection({
|
|
257
257
|
baseOutputDir: outputPath || "client-types.generated.ts",
|
|
258
258
|
schema: parse(printSchemaWithDirectives(schema)),
|
|
@@ -282,8 +282,8 @@ export function getSdk(requester: Requester): Sdk {
|
|
|
282
282
|
/**
|
|
283
283
|
* Generate client types for external GraphQL service
|
|
284
284
|
*/
|
|
285
|
-
async function generateExternalClientTypes(service, schema, docs) {
|
|
286
|
-
return generateClientTypes(schema, docs, service.codegen?.client || {}, service.codegen?.clientSDK || {}, void 0, service.name);
|
|
285
|
+
async function generateExternalClientTypes(service, schema, docs, virtualTypesPath) {
|
|
286
|
+
return generateClientTypes(schema, docs, service.codegen?.client || {}, service.codegen?.clientSDK || {}, void 0, service.name, virtualTypesPath);
|
|
287
287
|
}
|
|
288
288
|
|
|
289
289
|
//#endregion
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
//#region src/utils/errors.d.ts
|
|
2
|
+
interface MaskErrorOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Default HTTP status code for validation errors (ZodError)
|
|
5
|
+
* @default 400
|
|
6
|
+
*/
|
|
7
|
+
validationStatusCode?: number;
|
|
8
|
+
/**
|
|
9
|
+
* Default HTTP status code for HTTP errors when status is not provided
|
|
10
|
+
* @default 500
|
|
11
|
+
*/
|
|
12
|
+
defaultHttpStatusCode?: number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Default error masking function for GraphQL Yoga
|
|
16
|
+
* Handles common error types like ZodError and HTTPError
|
|
17
|
+
*
|
|
18
|
+
* @param options - Configuration options for error handling
|
|
19
|
+
*
|
|
20
|
+
* @example Basic usage
|
|
21
|
+
* ```ts
|
|
22
|
+
* import { defineGraphQLConfig } from 'nitro-graphql/define'
|
|
23
|
+
* import { createDefaultMaskError } from 'nitro-graphql/utils'
|
|
24
|
+
*
|
|
25
|
+
* export default defineGraphQLConfig({
|
|
26
|
+
* maskedErrors: {
|
|
27
|
+
* maskError: createDefaultMaskError()
|
|
28
|
+
* }
|
|
29
|
+
* })
|
|
30
|
+
* ```
|
|
31
|
+
*
|
|
32
|
+
* @example Custom status codes
|
|
33
|
+
* ```ts
|
|
34
|
+
* import { defineGraphQLConfig } from 'nitro-graphql/define'
|
|
35
|
+
* import { createDefaultMaskError } from 'nitro-graphql/utils'
|
|
36
|
+
*
|
|
37
|
+
* export default defineGraphQLConfig({
|
|
38
|
+
* maskedErrors: {
|
|
39
|
+
* maskError: createDefaultMaskError({
|
|
40
|
+
* validationStatusCode: 422, // Use 422 for validation errors
|
|
41
|
+
* defaultHttpStatusCode: 500 // Use 500 for unknown HTTP errors
|
|
42
|
+
* })
|
|
43
|
+
* }
|
|
44
|
+
* })
|
|
45
|
+
* ```
|
|
46
|
+
*
|
|
47
|
+
* @example Custom error handling with fallback to default
|
|
48
|
+
* ```ts
|
|
49
|
+
* import { defineGraphQLConfig } from 'nitro-graphql/define'
|
|
50
|
+
* import { createDefaultMaskError } from 'nitro-graphql/utils'
|
|
51
|
+
*
|
|
52
|
+
* const defaultMaskError = createDefaultMaskError()
|
|
53
|
+
*
|
|
54
|
+
* export default defineGraphQLConfig({
|
|
55
|
+
* maskedErrors: {
|
|
56
|
+
* maskError: (error: unknown) => {
|
|
57
|
+
* // Handle custom errors first
|
|
58
|
+
* if (error instanceof MyCustomError) {
|
|
59
|
+
* return new GraphQLError(error.message, {
|
|
60
|
+
* extensions: { code: 'CUSTOM_ERROR' }
|
|
61
|
+
* })
|
|
62
|
+
* }
|
|
63
|
+
*
|
|
64
|
+
* // Fall back to default handling
|
|
65
|
+
* return defaultMaskError(error)
|
|
66
|
+
* }
|
|
67
|
+
* }
|
|
68
|
+
* })
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
declare function createDefaultMaskError(options?: MaskErrorOptions): (error: unknown) => Error;
|
|
72
|
+
//#endregion
|
|
73
|
+
export { MaskErrorOptions, createDefaultMaskError };
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { GraphQLError } from "graphql";
|
|
2
|
+
|
|
3
|
+
//#region src/utils/errors.ts
|
|
4
|
+
/**
|
|
5
|
+
* Default error masking function for GraphQL Yoga
|
|
6
|
+
* Handles common error types like ZodError and HTTPError
|
|
7
|
+
*
|
|
8
|
+
* @param options - Configuration options for error handling
|
|
9
|
+
*
|
|
10
|
+
* @example Basic usage
|
|
11
|
+
* ```ts
|
|
12
|
+
* import { defineGraphQLConfig } from 'nitro-graphql/define'
|
|
13
|
+
* import { createDefaultMaskError } from 'nitro-graphql/utils'
|
|
14
|
+
*
|
|
15
|
+
* export default defineGraphQLConfig({
|
|
16
|
+
* maskedErrors: {
|
|
17
|
+
* maskError: createDefaultMaskError()
|
|
18
|
+
* }
|
|
19
|
+
* })
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* @example Custom status codes
|
|
23
|
+
* ```ts
|
|
24
|
+
* import { defineGraphQLConfig } from 'nitro-graphql/define'
|
|
25
|
+
* import { createDefaultMaskError } from 'nitro-graphql/utils'
|
|
26
|
+
*
|
|
27
|
+
* export default defineGraphQLConfig({
|
|
28
|
+
* maskedErrors: {
|
|
29
|
+
* maskError: createDefaultMaskError({
|
|
30
|
+
* validationStatusCode: 422, // Use 422 for validation errors
|
|
31
|
+
* defaultHttpStatusCode: 500 // Use 500 for unknown HTTP errors
|
|
32
|
+
* })
|
|
33
|
+
* }
|
|
34
|
+
* })
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* @example Custom error handling with fallback to default
|
|
38
|
+
* ```ts
|
|
39
|
+
* import { defineGraphQLConfig } from 'nitro-graphql/define'
|
|
40
|
+
* import { createDefaultMaskError } from 'nitro-graphql/utils'
|
|
41
|
+
*
|
|
42
|
+
* const defaultMaskError = createDefaultMaskError()
|
|
43
|
+
*
|
|
44
|
+
* export default defineGraphQLConfig({
|
|
45
|
+
* maskedErrors: {
|
|
46
|
+
* maskError: (error: unknown) => {
|
|
47
|
+
* // Handle custom errors first
|
|
48
|
+
* if (error instanceof MyCustomError) {
|
|
49
|
+
* return new GraphQLError(error.message, {
|
|
50
|
+
* extensions: { code: 'CUSTOM_ERROR' }
|
|
51
|
+
* })
|
|
52
|
+
* }
|
|
53
|
+
*
|
|
54
|
+
* // Fall back to default handling
|
|
55
|
+
* return defaultMaskError(error)
|
|
56
|
+
* }
|
|
57
|
+
* }
|
|
58
|
+
* })
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
function createDefaultMaskError(options) {
|
|
62
|
+
const validationStatusCode = options?.validationStatusCode ?? 400;
|
|
63
|
+
const defaultHttpStatusCode = options?.defaultHttpStatusCode ?? 500;
|
|
64
|
+
return (error) => {
|
|
65
|
+
if (error && typeof error === "object" && "originalError" in error) {
|
|
66
|
+
const graphqlError = error;
|
|
67
|
+
if (graphqlError.originalError && typeof graphqlError.originalError === "object" && "issues" in graphqlError.originalError && Array.isArray(graphqlError.originalError.issues)) return new GraphQLError("Validation failed", { extensions: {
|
|
68
|
+
code: "BAD_USER_INPUT",
|
|
69
|
+
validationErrors: graphqlError.originalError.issues.map((issue) => ({
|
|
70
|
+
field: issue.path.join("."),
|
|
71
|
+
message: issue.message
|
|
72
|
+
})),
|
|
73
|
+
http: { status: validationStatusCode }
|
|
74
|
+
} });
|
|
75
|
+
if (graphqlError.originalError && typeof graphqlError.originalError === "object" && "statusCode" in graphqlError.originalError && "statusMessage" in graphqlError.originalError) {
|
|
76
|
+
const httpError = graphqlError.originalError;
|
|
77
|
+
const statusCode = httpError.statusCode ?? defaultHttpStatusCode;
|
|
78
|
+
return new GraphQLError(httpError.statusMessage || httpError.message || "Internal Server Error", { extensions: {
|
|
79
|
+
code: statusCode,
|
|
80
|
+
http: { status: statusCode }
|
|
81
|
+
} });
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
//#endregion
|
|
89
|
+
export { createDefaultMaskError };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Nitro } from "nitro/types";
|
|
2
|
+
|
|
3
|
+
//#region src/utils/file-generator.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Safely write a file to disk, creating parent directories if needed
|
|
7
|
+
*/
|
|
8
|
+
declare function writeFile(filePath: string, content: string, description?: string): void;
|
|
9
|
+
/**
|
|
10
|
+
* Write a file only if it doesn't already exist
|
|
11
|
+
* Returns true if file was created, false if it already existed
|
|
12
|
+
*/
|
|
13
|
+
declare function writeFileIfNotExists(filePath: string, content: string, description?: string): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Write a file and always overwrite (used for generated files like SDK)
|
|
16
|
+
* This is for files that are auto-generated and should be updated on every build
|
|
17
|
+
*/
|
|
18
|
+
declare function writeGeneratedFile(filePath: string, content: string, description?: string): void;
|
|
19
|
+
/**
|
|
20
|
+
* Check if a path is configured and should be generated
|
|
21
|
+
* Returns the resolved path if should generate, null otherwise
|
|
22
|
+
*/
|
|
23
|
+
declare function getGenerationPath(resolvedPath: string | null, description?: string): string | null;
|
|
24
|
+
/**
|
|
25
|
+
* Log skipped file generation (helpful for debugging library mode)
|
|
26
|
+
*/
|
|
27
|
+
declare function logSkipped(fileName: string, reason?: string): void;
|
|
28
|
+
/**
|
|
29
|
+
* Log generated file path
|
|
30
|
+
*/
|
|
31
|
+
declare function logGenerated(fileName: string, path: string): void;
|
|
32
|
+
/**
|
|
33
|
+
* Validate that a Nitro instance has the required GraphQL configuration
|
|
34
|
+
*/
|
|
35
|
+
declare function validateGraphQLConfig(nitro: Nitro): boolean;
|
|
36
|
+
//#endregion
|
|
37
|
+
export { getGenerationPath, logGenerated, logSkipped, validateGraphQLConfig, writeFile, writeFileIfNotExists, writeGeneratedFile };
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
+
import consola from "consola";
|
|
3
|
+
import { dirname } from "pathe";
|
|
4
|
+
|
|
5
|
+
//#region src/utils/file-generator.ts
|
|
6
|
+
/**
|
|
7
|
+
* Safely write a file to disk, creating parent directories if needed
|
|
8
|
+
*/
|
|
9
|
+
function writeFile(filePath, content, description) {
|
|
10
|
+
try {
|
|
11
|
+
const dir = dirname(filePath);
|
|
12
|
+
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
13
|
+
writeFileSync(filePath, content, "utf-8");
|
|
14
|
+
if (description) consola.success(`[nitro-graphql] Generated: ${description}`);
|
|
15
|
+
} catch (error) {
|
|
16
|
+
consola.error(`[nitro-graphql] Failed to write file: ${filePath}`, error);
|
|
17
|
+
throw error;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Write a file only if it doesn't already exist
|
|
22
|
+
* Returns true if file was created, false if it already existed
|
|
23
|
+
*/
|
|
24
|
+
function writeFileIfNotExists(filePath, content, description) {
|
|
25
|
+
if (existsSync(filePath)) return false;
|
|
26
|
+
writeFile(filePath, content, description);
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Write a file and always overwrite (used for generated files like SDK)
|
|
31
|
+
* This is for files that are auto-generated and should be updated on every build
|
|
32
|
+
*/
|
|
33
|
+
function writeGeneratedFile(filePath, content, description) {
|
|
34
|
+
writeFile(filePath, content, description);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Check if a path is configured and should be generated
|
|
38
|
+
* Returns the resolved path if should generate, null otherwise
|
|
39
|
+
*/
|
|
40
|
+
function getGenerationPath(resolvedPath, description) {
|
|
41
|
+
if (!resolvedPath) {
|
|
42
|
+
if (description) consola.debug(`[nitro-graphql] Skipping generation: ${description} (disabled in config)`);
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
return resolvedPath;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Log skipped file generation (helpful for debugging library mode)
|
|
49
|
+
*/
|
|
50
|
+
function logSkipped(fileName, reason) {
|
|
51
|
+
const message = reason ? `Skipped ${fileName}: ${reason}` : `Skipped ${fileName}`;
|
|
52
|
+
consola.debug(`[nitro-graphql] ${message}`);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Log generated file path
|
|
56
|
+
*/
|
|
57
|
+
function logGenerated(fileName, path) {
|
|
58
|
+
consola.info(`[nitro-graphql] Generated ${fileName} at: ${path}`);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Validate that a Nitro instance has the required GraphQL configuration
|
|
62
|
+
*/
|
|
63
|
+
function validateGraphQLConfig(nitro) {
|
|
64
|
+
if (!nitro.options.graphql?.framework) {
|
|
65
|
+
consola.warn("[nitro-graphql] No GraphQL framework specified. Some features may not work correctly.");
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
//#endregion
|
|
72
|
+
export { getGenerationPath, logGenerated, logSkipped, validateGraphQLConfig, writeFile, writeFileIfNotExists, writeGeneratedFile };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { GenImport } from "../types/index.
|
|
2
|
-
import { directiveParser, generateDirectiveSchema, generateDirectiveSchemas } from "./directive-parser.
|
|
1
|
+
import { GenImport } from "../types/index.mjs";
|
|
2
|
+
import { directiveParser, generateDirectiveSchema, generateDirectiveSchemas } from "./directive-parser.mjs";
|
|
3
|
+
import { createDefaultMaskError } from "./errors.mjs";
|
|
3
4
|
import { Nitro } from "nitro/types";
|
|
4
5
|
|
|
5
6
|
//#region src/utils/index.d.ts
|
|
@@ -36,4 +37,4 @@ declare function scanExternalServiceDocs(nitro: Nitro, serviceName: string, patt
|
|
|
36
37
|
*/
|
|
37
38
|
declare function validateExternalServices(services: unknown[]): string[];
|
|
38
39
|
//#endregion
|
|
39
|
-
export { GLOB_SCAN_PATTERN, directiveParser, generateDirectiveSchema, generateDirectiveSchemas, generateLayerIgnorePatterns, getImportId, getLayerAppDirectories, getLayerDirectories, getLayerServerDirectories, relativeWithDot, scanDirectives, scanDocs, scanExternalServiceDocs, scanGraphql, scanResolvers, scanSchemas, validateExternalServices };
|
|
40
|
+
export { GLOB_SCAN_PATTERN, createDefaultMaskError, directiveParser, generateDirectiveSchema, generateDirectiveSchemas, generateLayerIgnorePatterns, getImportId, getLayerAppDirectories, getLayerDirectories, getLayerServerDirectories, relativeWithDot, scanDirectives, scanDocs, scanExternalServiceDocs, scanGraphql, scanResolvers, scanSchemas, validateExternalServices };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { directiveParser, generateDirectiveSchema, generateDirectiveSchemas } from "./directive-parser.
|
|
2
|
-
import {
|
|
1
|
+
import { directiveParser, generateDirectiveSchema, generateDirectiveSchemas } from "./directive-parser.mjs";
|
|
2
|
+
import { createDefaultMaskError } from "./errors.mjs";
|
|
3
3
|
import { readFile } from "node:fs/promises";
|
|
4
|
+
import { basename, join, relative } from "pathe";
|
|
4
5
|
import { hash } from "ohash";
|
|
5
6
|
import { parseAsync } from "oxc-parser";
|
|
6
7
|
import { glob } from "tinyglobby";
|
|
@@ -65,50 +66,88 @@ async function scanResolvers(nitro) {
|
|
|
65
66
|
return true;
|
|
66
67
|
});
|
|
67
68
|
const exportName = [];
|
|
68
|
-
|
|
69
|
+
const VALID_DEFINE_FUNCTIONS = [
|
|
70
|
+
"defineResolver",
|
|
71
|
+
"defineQuery",
|
|
72
|
+
"defineMutation",
|
|
73
|
+
"defineType",
|
|
74
|
+
"defineSubscription",
|
|
75
|
+
"defineDirective"
|
|
76
|
+
];
|
|
77
|
+
for (const file of files) try {
|
|
69
78
|
const fileContent = await readFile(file.fullPath, "utf-8");
|
|
70
79
|
const parsed = await parseAsync(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];
|
|
87
|
+
console.error(`✖ ${fileName}${lineInfo} - ${message}`);
|
|
88
|
+
}
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
71
91
|
const exports = {
|
|
72
92
|
imports: [],
|
|
73
93
|
specifier: file.fullPath
|
|
74
94
|
};
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
type
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
type
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
type
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
type
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
type
|
|
106
|
-
|
|
107
|
-
|
|
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 === "defineType") 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
|
+
}
|
|
108
136
|
}
|
|
109
137
|
}
|
|
110
138
|
}
|
|
139
|
+
if (nitro.options.dev) {
|
|
140
|
+
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.`);
|
|
141
|
+
if (exports.imports.length === 0 && hasNamedExport) {
|
|
142
|
+
const validFunctions = VALID_DEFINE_FUNCTIONS.join(", ");
|
|
143
|
+
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.`);
|
|
144
|
+
}
|
|
145
|
+
if (!hasDefaultExport && !hasNamedExport) nitro.logger.warn(`[nitro-graphql] ${relPath}: No exports found. Resolver files must export resolvers using defineResolver, defineQuery, defineMutation, etc.`);
|
|
146
|
+
}
|
|
111
147
|
if (exports.imports.length > 0) exportName.push(exports);
|
|
148
|
+
} catch (error) {
|
|
149
|
+
const relPath$1 = relative(nitro.options.rootDir, file.fullPath);
|
|
150
|
+
nitro.logger.error(`[nitro-graphql] Failed to parse resolver file ${relPath$1}:`, error);
|
|
112
151
|
}
|
|
113
152
|
return exportName;
|
|
114
153
|
}
|
|
@@ -247,4 +286,4 @@ async function scanDir(nitro, dir, name, globPattern = GLOB_SCAN_PATTERN) {
|
|
|
247
286
|
}
|
|
248
287
|
|
|
249
288
|
//#endregion
|
|
250
|
-
export { GLOB_SCAN_PATTERN, directiveParser, generateDirectiveSchema, generateDirectiveSchemas, generateLayerIgnorePatterns, getImportId, getLayerAppDirectories, getLayerDirectories, getLayerServerDirectories, relativeWithDot, scanDirectives, scanDocs, scanExternalServiceDocs, scanGraphql, scanResolvers, scanSchemas, validateExternalServices };
|
|
289
|
+
export { GLOB_SCAN_PATTERN, createDefaultMaskError, directiveParser, generateDirectiveSchema, generateDirectiveSchemas, generateLayerIgnorePatterns, getImportId, getLayerAppDirectories, getLayerDirectories, getLayerServerDirectories, relativeWithDot, scanDirectives, scanDocs, scanExternalServiceDocs, scanGraphql, scanResolvers, scanSchemas, validateExternalServices };
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { ClientUtilsConfig, FileGenerationConfig, ScaffoldConfig, SdkConfig, TypesConfig } from "../types/index.mjs";
|
|
2
|
+
import { Nitro } from "nitro/types";
|
|
3
|
+
|
|
4
|
+
//#region src/utils/path-resolver.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Placeholder values for path resolution
|
|
8
|
+
*/
|
|
9
|
+
interface PathPlaceholders {
|
|
10
|
+
serviceName?: string;
|
|
11
|
+
buildDir: string;
|
|
12
|
+
rootDir: string;
|
|
13
|
+
framework: 'nuxt' | 'nitro';
|
|
14
|
+
typesDir: string;
|
|
15
|
+
serverGraphql: string;
|
|
16
|
+
clientGraphql: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Replace placeholders in a path string
|
|
20
|
+
* Supports: {serviceName}, {buildDir}, {rootDir}, {framework}, {typesDir}, {serverGraphql}, {clientGraphql}
|
|
21
|
+
*/
|
|
22
|
+
declare function replacePlaceholders(path: string, placeholders: PathPlaceholders): string;
|
|
23
|
+
/**
|
|
24
|
+
* Get default paths based on framework and user configuration
|
|
25
|
+
*/
|
|
26
|
+
declare function getDefaultPaths(nitro: Nitro): Required<PathPlaceholders>;
|
|
27
|
+
/**
|
|
28
|
+
* Check if a file should be generated based on config
|
|
29
|
+
* Returns: true if should generate, false if should skip
|
|
30
|
+
*/
|
|
31
|
+
declare function shouldGenerateFile(config: FileGenerationConfig | undefined, categoryEnabled: boolean | undefined, topLevelEnabled: boolean): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Resolve the file path based on configuration
|
|
34
|
+
* Returns: resolved absolute path or null if file should not be generated
|
|
35
|
+
*/
|
|
36
|
+
declare function resolveFilePath(config: FileGenerationConfig | undefined, categoryEnabled: boolean | undefined, topLevelEnabled: boolean, defaultPath: string, placeholders: PathPlaceholders): string | null;
|
|
37
|
+
/**
|
|
38
|
+
* Check if scaffold files should be generated (category-level check)
|
|
39
|
+
*/
|
|
40
|
+
declare function shouldGenerateScaffold(nitro: Nitro): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Get scaffold configuration (handles false case)
|
|
43
|
+
*/
|
|
44
|
+
declare function getScaffoldConfig(nitro: Nitro): ScaffoldConfig;
|
|
45
|
+
/**
|
|
46
|
+
* Check if client utilities should be generated (category-level check)
|
|
47
|
+
*/
|
|
48
|
+
declare function shouldGenerateClientUtils(nitro: Nitro): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Get client utilities configuration (handles false case)
|
|
51
|
+
*/
|
|
52
|
+
declare function getClientUtilsConfig(nitro: Nitro): ClientUtilsConfig;
|
|
53
|
+
/**
|
|
54
|
+
* Check if SDK files should be generated (category-level check)
|
|
55
|
+
*/
|
|
56
|
+
declare function shouldGenerateSDK(nitro: Nitro): boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Get SDK configuration (handles false case)
|
|
59
|
+
*/
|
|
60
|
+
declare function getSdkConfig(nitro: Nitro): SdkConfig;
|
|
61
|
+
/**
|
|
62
|
+
* Check if type files should be generated (category-level check)
|
|
63
|
+
*/
|
|
64
|
+
declare function shouldGenerateTypes(nitro: Nitro): boolean;
|
|
65
|
+
/**
|
|
66
|
+
* Get types configuration (handles false case)
|
|
67
|
+
*/
|
|
68
|
+
declare function getTypesConfig(nitro: Nitro): TypesConfig;
|
|
69
|
+
//#endregion
|
|
70
|
+
export { PathPlaceholders, getClientUtilsConfig, getDefaultPaths, getScaffoldConfig, getSdkConfig, getTypesConfig, replacePlaceholders, resolveFilePath, shouldGenerateClientUtils, shouldGenerateFile, shouldGenerateSDK, shouldGenerateScaffold, shouldGenerateTypes };
|