nitro-graphql 2.0.0-beta.4 → 2.0.0-beta.41
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 +438 -27
- package/dist/cli/commands/generate.d.mts +26 -0
- package/dist/cli/commands/generate.mjs +196 -0
- package/dist/cli/commands/index.d.mts +4 -0
- package/dist/cli/commands/index.mjs +5 -0
- package/dist/cli/commands/init.d.mts +46 -0
- package/dist/cli/commands/init.mjs +195 -0
- package/dist/cli/commands/validate.d.mts +10 -0
- package/dist/cli/commands/validate.mjs +69 -0
- package/dist/cli/completions.d.mts +7 -0
- package/dist/cli/completions.mjs +34 -0
- package/dist/cli/config.d.mts +75 -0
- package/dist/cli/config.mjs +20 -0
- package/dist/cli/index.d.mts +24 -0
- package/dist/cli/index.mjs +253 -0
- package/dist/config.d.mts +2 -0
- package/dist/config.mjs +3 -0
- package/dist/core/codegen/client.d.mts +23 -0
- package/dist/core/codegen/client.mjs +150 -0
- package/dist/core/codegen/document-loader.d.mts +10 -0
- package/dist/core/codegen/document-loader.mjs +18 -0
- package/dist/core/codegen/index.d.mts +8 -0
- package/dist/core/codegen/index.mjs +9 -0
- package/dist/core/codegen/plugin.d.mts +20 -0
- package/dist/core/codegen/plugin.mjs +30 -0
- package/dist/core/codegen/runtime.d.mts +20 -0
- package/dist/core/codegen/runtime.mjs +60 -0
- package/dist/core/codegen/schema-loader.d.mts +28 -0
- package/dist/core/codegen/schema-loader.mjs +128 -0
- package/dist/core/codegen/server.d.mts +28 -0
- package/dist/core/codegen/server.mjs +143 -0
- package/dist/core/codegen/validation.d.mts +13 -0
- package/dist/core/codegen/validation.mjs +96 -0
- package/dist/core/config.d.mts +50 -0
- package/dist/core/config.mjs +82 -0
- package/dist/core/constants.d.mts +188 -0
- package/dist/core/constants.mjs +210 -0
- package/dist/core/index.d.mts +33 -0
- package/dist/core/index.mjs +27 -0
- package/dist/core/manifest.d.mts +46 -0
- package/dist/core/manifest.mjs +76 -0
- package/dist/core/scanning/ast-scanner.d.mts +28 -0
- package/dist/core/scanning/ast-scanner.mjs +122 -0
- package/dist/core/scanning/common.d.mts +37 -0
- package/dist/core/scanning/common.mjs +60 -0
- package/dist/core/scanning/directives.d.mts +10 -0
- package/dist/core/scanning/directives.mjs +29 -0
- package/dist/core/scanning/documents.d.mts +21 -0
- package/dist/core/scanning/documents.mjs +43 -0
- package/dist/core/scanning/index.d.mts +7 -0
- package/dist/core/scanning/index.mjs +8 -0
- package/dist/core/scanning/resolvers.d.mts +15 -0
- package/dist/core/scanning/resolvers.mjs +59 -0
- package/dist/core/scanning/schemas.d.mts +14 -0
- package/dist/core/scanning/schemas.mjs +64 -0
- package/dist/core/schema/builder.d.mts +53 -0
- package/dist/core/schema/builder.mjs +70 -0
- package/dist/core/schema/federation.d.mts +34 -0
- package/dist/core/schema/federation.mjs +40 -0
- package/dist/core/schema/index.d.mts +3 -0
- package/dist/core/schema/index.mjs +4 -0
- package/dist/core/types/adapter.d.mts +58 -0
- package/dist/core/types/codegen.d.mts +133 -0
- package/dist/core/types/config.d.mts +210 -0
- package/dist/core/types/config.mjs +1 -0
- package/dist/{utils/define.d.ts → core/types/define.d.mts} +3 -30
- package/dist/core/types/define.mjs +1 -0
- package/dist/core/types/index.d.mts +5 -0
- package/dist/core/types/index.mjs +1 -0
- package/dist/core/types/scanning.d.mts +69 -0
- package/dist/core/types/scanning.mjs +1 -0
- package/dist/{utils/directive-parser.d.ts → core/utils/directive-parser.d.mts} +21 -4
- package/dist/{utils/directive-parser.js → core/utils/directive-parser.mjs} +25 -34
- package/dist/core/utils/errors.d.mts +77 -0
- package/dist/core/utils/errors.mjs +93 -0
- package/dist/core/utils/file-io.d.mts +24 -0
- package/dist/core/utils/file-io.mjs +47 -0
- package/dist/core/utils/imports.d.mts +15 -0
- package/dist/core/utils/imports.mjs +25 -0
- package/dist/core/utils/index.d.mts +7 -0
- package/dist/core/utils/index.mjs +8 -0
- package/dist/core/utils/logger.d.mts +19 -0
- package/dist/core/utils/logger.mjs +38 -0
- package/dist/core/utils/ofetch-templates.d.mts +30 -0
- package/dist/core/utils/ofetch-templates.mjs +135 -0
- package/dist/core/validation/external-services.d.mts +11 -0
- package/dist/core/validation/external-services.mjs +34 -0
- package/dist/core/validation/index.d.mts +2 -0
- package/dist/core/validation/index.mjs +3 -0
- package/dist/define.d.mts +294 -0
- package/dist/define.mjs +323 -0
- package/dist/index.d.mts +6 -0
- package/dist/index.mjs +6 -0
- package/dist/nitro/adapter.d.mts +30 -0
- package/dist/nitro/adapter.mjs +97 -0
- package/dist/{utils/apollo.d.ts → nitro/apollo.d.mts} +3 -3
- package/dist/nitro/apollo.mjs +59 -0
- package/dist/nitro/codegen.d.mts +19 -0
- package/dist/nitro/codegen.mjs +141 -0
- package/dist/nitro/config.d.mts +51 -0
- package/dist/nitro/config.mjs +57 -0
- package/dist/nitro/index.d.mts +46 -0
- package/dist/nitro/index.mjs +65 -0
- package/dist/nitro/paths.d.mts +54 -0
- package/dist/nitro/paths.mjs +92 -0
- package/dist/nitro/rollup.d.mts +6 -0
- package/dist/nitro/rollup.mjs +95 -0
- package/dist/nitro/routes/apollo-server.d.mts +6 -0
- package/dist/nitro/routes/apollo-server.mjs +71 -0
- package/dist/nitro/routes/debug-template.d.mts +15 -0
- package/dist/nitro/routes/debug-template.mjs +385 -0
- package/dist/nitro/routes/debug.d.mts +55 -0
- package/dist/nitro/routes/debug.mjs +102 -0
- package/dist/nitro/routes/graphql-yoga.d.mts +6 -0
- package/dist/nitro/routes/graphql-yoga.mjs +62 -0
- package/dist/nitro/routes/health.d.mts +10 -0
- package/dist/{routes/health.js → nitro/routes/health.mjs} +4 -3
- package/dist/nitro/setup/extend-loader.d.mts +19 -0
- package/dist/nitro/setup/extend-loader.mjs +129 -0
- package/dist/nitro/setup/file-watcher.d.mts +16 -0
- package/dist/nitro/setup/file-watcher.mjs +98 -0
- package/dist/nitro/setup/logging.d.mts +17 -0
- package/dist/nitro/setup/logging.mjs +66 -0
- package/dist/nitro/setup/rollup-integration.d.mts +16 -0
- package/dist/nitro/setup/rollup-integration.mjs +90 -0
- package/dist/nitro/setup/routes.d.mts +10 -0
- package/dist/nitro/setup/routes.mjs +35 -0
- package/dist/nitro/setup/ts-config.d.mts +11 -0
- package/dist/nitro/setup/ts-config.mjs +69 -0
- package/dist/nitro/setup.d.mts +12 -0
- package/dist/nitro/setup.mjs +234 -0
- package/dist/nitro/types.d.mts +374 -0
- package/dist/nitro/types.mjs +1 -0
- package/dist/nitro/virtual/generators.d.mts +31 -0
- package/dist/nitro/virtual/generators.mjs +113 -0
- package/dist/nitro/virtual/stubs.d.mts +20 -0
- package/dist/nitro/virtual/stubs.mjs +31 -0
- package/dist/{ecosystem/nuxt.d.ts → nuxt.d.mts} +1 -1
- package/dist/nuxt.mjs +109 -0
- package/dist/{graphql/server.d.ts → stubs/index.d.mts} +5 -1
- package/dist/stubs/index.mjs +1 -0
- package/package.json +102 -77
- package/dist/ecosystem/nuxt.js +0 -67
- package/dist/graphql/index.d.ts +0 -5
- package/dist/index.d.ts +0 -8
- package/dist/index.js +0 -264
- package/dist/rollup.js +0 -119
- package/dist/routes/apollo-server.d.ts +0 -6
- package/dist/routes/apollo-server.js +0 -89
- package/dist/routes/graphql-yoga.d.ts +0 -6
- package/dist/routes/graphql-yoga.js +0 -91
- package/dist/routes/health.d.ts +0 -6
- package/dist/types/index.d.ts +0 -128
- package/dist/types/standard-schema.d.ts +0 -59
- package/dist/utils/apollo.js +0 -61
- package/dist/utils/client-codegen.d.ts +0 -38
- package/dist/utils/client-codegen.js +0 -290
- package/dist/utils/define.js +0 -57
- package/dist/utils/index.d.ts +0 -39
- package/dist/utils/index.js +0 -250
- package/dist/utils/server-codegen.d.ts +0 -7
- package/dist/utils/server-codegen.js +0 -136
- package/dist/utils/type-generation.d.ts +0 -7
- package/dist/utils/type-generation.js +0 -287
- package/dist/vite.d.ts +0 -25
- package/dist/vite.js +0 -40
- /package/dist/{graphql/index.js → core/types/adapter.mjs} +0 -0
- /package/dist/{graphql/server.js → core/types/codegen.mjs} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//#region src/utils/directive-parser.ts
|
|
1
|
+
//#region src/core/utils/directive-parser.ts
|
|
2
2
|
/**
|
|
3
3
|
* Clean AST-based directive parser using oxc-parser
|
|
4
4
|
*/
|
|
@@ -180,45 +180,36 @@ function generateDirectiveSchema(directive) {
|
|
|
180
180
|
return `directive @${directive.name}${args} on ${locations}`;
|
|
181
181
|
}
|
|
182
182
|
/**
|
|
183
|
-
*
|
|
183
|
+
* Get the file path from a directive reference
|
|
184
184
|
*/
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
const { existsSync, readFileSync, writeFileSync, mkdirSync } = await import("node:fs");
|
|
188
|
-
const { readFile } = await import("node:fs/promises");
|
|
189
|
-
const { resolve, dirname } = await import("pathe");
|
|
190
|
-
const directiveSchemas = [];
|
|
191
|
-
const seenDirectives = /* @__PURE__ */ new Set();
|
|
192
|
-
const parser = new DirectiveParser();
|
|
193
|
-
for (const dir of directives) for (const _imp of dir.imports) {
|
|
194
|
-
const fileContent = await readFile(dir.specifier, "utf-8");
|
|
195
|
-
const directiveDefs = await parser.parseDirectives(fileContent, dir.specifier);
|
|
196
|
-
for (const def of directiveDefs) {
|
|
197
|
-
if (seenDirectives.has(def.name)) continue;
|
|
198
|
-
seenDirectives.add(def.name);
|
|
199
|
-
const schema = generateDirectiveSchema(def);
|
|
200
|
-
directiveSchemas.push(schema);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
if (directiveSchemas.length > 0) {
|
|
204
|
-
const directivesPath = resolve(nitro.graphql.buildDir, "_directives.graphql");
|
|
205
|
-
const content = `# WARNING: This file is auto-generated by nitro-graphql
|
|
206
|
-
# Do not modify this file directly. It will be overwritten.
|
|
207
|
-
# To define custom directives, create .directive.ts files using defineDirective()
|
|
208
|
-
|
|
209
|
-
${directiveSchemas.join("\n\n")}`;
|
|
210
|
-
const targetDir = dirname(directivesPath);
|
|
211
|
-
if (!existsSync(targetDir)) mkdirSync(targetDir, { recursive: true });
|
|
212
|
-
let shouldWrite = true;
|
|
213
|
-
if (existsSync(directivesPath)) shouldWrite = readFileSync(directivesPath, "utf-8") !== content;
|
|
214
|
-
if (shouldWrite) writeFileSync(directivesPath, content, "utf-8");
|
|
215
|
-
if (!nitro.scanSchemas.includes(directivesPath)) nitro.scanSchemas.push(directivesPath);
|
|
216
|
-
}
|
|
185
|
+
function getFilePath(ref) {
|
|
186
|
+
return "fullPath" in ref ? ref.fullPath : ref.specifier;
|
|
217
187
|
}
|
|
218
188
|
/**
|
|
219
189
|
* Singleton instance for reuse
|
|
220
190
|
*/
|
|
221
191
|
const directiveParser = new DirectiveParser();
|
|
192
|
+
/**
|
|
193
|
+
* Generate GraphQL schemas from an array of parsed directives
|
|
194
|
+
*/
|
|
195
|
+
async function generateDirectiveSchemas(nitro, directives) {
|
|
196
|
+
if (directives.length === 0) return null;
|
|
197
|
+
const fs = await import("node:fs");
|
|
198
|
+
const path = await import("pathe");
|
|
199
|
+
const allParsedDirectives = [];
|
|
200
|
+
for (const directive of directives) try {
|
|
201
|
+
const filePath = getFilePath(directive);
|
|
202
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
203
|
+
const parsed = await directiveParser.parseDirectives(content, filePath);
|
|
204
|
+
allParsedDirectives.push(...parsed);
|
|
205
|
+
} catch {}
|
|
206
|
+
if (allParsedDirectives.length === 0) return null;
|
|
207
|
+
const schemaContent = allParsedDirectives.map((d) => generateDirectiveSchema(d)).join("\n\n");
|
|
208
|
+
const directivesPath = path.join(nitro.graphql.buildDir, "_directives.graphql");
|
|
209
|
+
fs.mkdirSync(path.dirname(directivesPath), { recursive: true });
|
|
210
|
+
fs.writeFileSync(directivesPath, schemaContent, "utf-8");
|
|
211
|
+
return directivesPath;
|
|
212
|
+
}
|
|
222
213
|
|
|
223
214
|
//#endregion
|
|
224
215
|
export { DirectiveParser, directiveParser, generateDirectiveSchema, generateDirectiveSchemas };
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
//#region src/core/utils/errors.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Error handling utilities for GraphQL
|
|
4
|
+
* Framework-agnostic error masking and handling
|
|
5
|
+
*/
|
|
6
|
+
interface MaskErrorOptions {
|
|
7
|
+
/**
|
|
8
|
+
* Default HTTP status code for validation errors (ZodError)
|
|
9
|
+
* @default 400
|
|
10
|
+
*/
|
|
11
|
+
validationStatusCode?: number;
|
|
12
|
+
/**
|
|
13
|
+
* Default HTTP status code for HTTP errors when status is not provided
|
|
14
|
+
* @default 500
|
|
15
|
+
*/
|
|
16
|
+
defaultHttpStatusCode?: number;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Default error masking function for GraphQL Yoga
|
|
20
|
+
* Handles common error types like ZodError and HTTPError
|
|
21
|
+
*
|
|
22
|
+
* @param options - Configuration options for error handling
|
|
23
|
+
*
|
|
24
|
+
* @example Basic usage
|
|
25
|
+
* ```ts
|
|
26
|
+
* import { defineGraphQLConfig } from 'nitro-graphql/define'
|
|
27
|
+
* import { createDefaultMaskError } from 'nitro-graphql/core'
|
|
28
|
+
*
|
|
29
|
+
* export default defineGraphQLConfig({
|
|
30
|
+
* maskedErrors: {
|
|
31
|
+
* maskError: createDefaultMaskError()
|
|
32
|
+
* }
|
|
33
|
+
* })
|
|
34
|
+
* ```
|
|
35
|
+
*
|
|
36
|
+
* @example Custom status codes
|
|
37
|
+
* ```ts
|
|
38
|
+
* import { defineGraphQLConfig } from 'nitro-graphql/define'
|
|
39
|
+
* import { createDefaultMaskError } from 'nitro-graphql/core'
|
|
40
|
+
*
|
|
41
|
+
* export default defineGraphQLConfig({
|
|
42
|
+
* maskedErrors: {
|
|
43
|
+
* maskError: createDefaultMaskError({
|
|
44
|
+
* validationStatusCode: 422, // Use 422 for validation errors
|
|
45
|
+
* defaultHttpStatusCode: 500 // Use 500 for unknown HTTP errors
|
|
46
|
+
* })
|
|
47
|
+
* }
|
|
48
|
+
* })
|
|
49
|
+
* ```
|
|
50
|
+
*
|
|
51
|
+
* @example Custom error handling with fallback to default
|
|
52
|
+
* ```ts
|
|
53
|
+
* import { defineGraphQLConfig } from 'nitro-graphql/define'
|
|
54
|
+
* import { createDefaultMaskError } from 'nitro-graphql/core'
|
|
55
|
+
*
|
|
56
|
+
* const defaultMaskError = createDefaultMaskError()
|
|
57
|
+
*
|
|
58
|
+
* export default defineGraphQLConfig({
|
|
59
|
+
* maskedErrors: {
|
|
60
|
+
* maskError: (error: unknown) => {
|
|
61
|
+
* // Handle custom errors first
|
|
62
|
+
* if (error instanceof MyCustomError) {
|
|
63
|
+
* return new GraphQLError(error.message, {
|
|
64
|
+
* extensions: { code: 'CUSTOM_ERROR' }
|
|
65
|
+
* })
|
|
66
|
+
* }
|
|
67
|
+
*
|
|
68
|
+
* // Fall back to default handling
|
|
69
|
+
* return defaultMaskError(error)
|
|
70
|
+
* }
|
|
71
|
+
* }
|
|
72
|
+
* })
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
declare function createDefaultMaskError(options?: MaskErrorOptions): (error: unknown) => Error;
|
|
76
|
+
//#endregion
|
|
77
|
+
export { MaskErrorOptions, createDefaultMaskError };
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { GraphQLError } from "graphql";
|
|
2
|
+
|
|
3
|
+
//#region src/core/utils/errors.ts
|
|
4
|
+
/**
|
|
5
|
+
* Error handling utilities for GraphQL
|
|
6
|
+
* Framework-agnostic error masking and handling
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Default error masking function for GraphQL Yoga
|
|
10
|
+
* Handles common error types like ZodError and HTTPError
|
|
11
|
+
*
|
|
12
|
+
* @param options - Configuration options for error handling
|
|
13
|
+
*
|
|
14
|
+
* @example Basic usage
|
|
15
|
+
* ```ts
|
|
16
|
+
* import { defineGraphQLConfig } from 'nitro-graphql/define'
|
|
17
|
+
* import { createDefaultMaskError } from 'nitro-graphql/core'
|
|
18
|
+
*
|
|
19
|
+
* export default defineGraphQLConfig({
|
|
20
|
+
* maskedErrors: {
|
|
21
|
+
* maskError: createDefaultMaskError()
|
|
22
|
+
* }
|
|
23
|
+
* })
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* @example Custom status codes
|
|
27
|
+
* ```ts
|
|
28
|
+
* import { defineGraphQLConfig } from 'nitro-graphql/define'
|
|
29
|
+
* import { createDefaultMaskError } from 'nitro-graphql/core'
|
|
30
|
+
*
|
|
31
|
+
* export default defineGraphQLConfig({
|
|
32
|
+
* maskedErrors: {
|
|
33
|
+
* maskError: createDefaultMaskError({
|
|
34
|
+
* validationStatusCode: 422, // Use 422 for validation errors
|
|
35
|
+
* defaultHttpStatusCode: 500 // Use 500 for unknown HTTP errors
|
|
36
|
+
* })
|
|
37
|
+
* }
|
|
38
|
+
* })
|
|
39
|
+
* ```
|
|
40
|
+
*
|
|
41
|
+
* @example Custom error handling with fallback to default
|
|
42
|
+
* ```ts
|
|
43
|
+
* import { defineGraphQLConfig } from 'nitro-graphql/define'
|
|
44
|
+
* import { createDefaultMaskError } from 'nitro-graphql/core'
|
|
45
|
+
*
|
|
46
|
+
* const defaultMaskError = createDefaultMaskError()
|
|
47
|
+
*
|
|
48
|
+
* export default defineGraphQLConfig({
|
|
49
|
+
* maskedErrors: {
|
|
50
|
+
* maskError: (error: unknown) => {
|
|
51
|
+
* // Handle custom errors first
|
|
52
|
+
* if (error instanceof MyCustomError) {
|
|
53
|
+
* return new GraphQLError(error.message, {
|
|
54
|
+
* extensions: { code: 'CUSTOM_ERROR' }
|
|
55
|
+
* })
|
|
56
|
+
* }
|
|
57
|
+
*
|
|
58
|
+
* // Fall back to default handling
|
|
59
|
+
* return defaultMaskError(error)
|
|
60
|
+
* }
|
|
61
|
+
* }
|
|
62
|
+
* })
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
function createDefaultMaskError(options) {
|
|
66
|
+
const validationStatusCode = options?.validationStatusCode ?? 400;
|
|
67
|
+
const defaultHttpStatusCode = options?.defaultHttpStatusCode ?? 500;
|
|
68
|
+
return (error) => {
|
|
69
|
+
if (error && typeof error === "object" && "originalError" in error) {
|
|
70
|
+
const graphqlError = error;
|
|
71
|
+
if (graphqlError.originalError && typeof graphqlError.originalError === "object" && "issues" in graphqlError.originalError && Array.isArray(graphqlError.originalError.issues)) return new GraphQLError("Validation failed", { extensions: {
|
|
72
|
+
code: "BAD_USER_INPUT",
|
|
73
|
+
validationErrors: graphqlError.originalError.issues.map((issue) => ({
|
|
74
|
+
field: issue.path.join("."),
|
|
75
|
+
message: issue.message
|
|
76
|
+
})),
|
|
77
|
+
http: { status: validationStatusCode }
|
|
78
|
+
} });
|
|
79
|
+
if (graphqlError.originalError && typeof graphqlError.originalError === "object" && "statusCode" in graphqlError.originalError && "statusMessage" in graphqlError.originalError) {
|
|
80
|
+
const httpError = graphqlError.originalError;
|
|
81
|
+
const statusCode = httpError.statusCode ?? defaultHttpStatusCode;
|
|
82
|
+
return new GraphQLError(httpError.statusMessage || httpError.message || "Internal Server Error", { extensions: {
|
|
83
|
+
code: statusCode,
|
|
84
|
+
http: { status: statusCode }
|
|
85
|
+
} });
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
//#endregion
|
|
93
|
+
export { createDefaultMaskError };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
//#region src/core/utils/file-io.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Unified file I/O utilities
|
|
4
|
+
* Centralizes file writing patterns used across the codebase
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Write file with automatic directory creation
|
|
8
|
+
*/
|
|
9
|
+
declare function writeFile(path: string, content: string): void;
|
|
10
|
+
/**
|
|
11
|
+
* Write file only if content changed (for dev mode optimization)
|
|
12
|
+
* Returns true if file was written, false if unchanged
|
|
13
|
+
*/
|
|
14
|
+
declare function writeFileIfChanged(path: string, content: string): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Ensure directory exists
|
|
17
|
+
*/
|
|
18
|
+
declare function ensureDir(path: string): void;
|
|
19
|
+
/**
|
|
20
|
+
* Read file safely, returns undefined if file doesn't exist
|
|
21
|
+
*/
|
|
22
|
+
declare function readFileSafe(path: string): string | undefined;
|
|
23
|
+
//#endregion
|
|
24
|
+
export { ensureDir, readFileSafe, writeFile, writeFileIfChanged };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { dirname } from "pathe";
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
|
+
|
|
4
|
+
//#region src/core/utils/file-io.ts
|
|
5
|
+
/**
|
|
6
|
+
* Unified file I/O utilities
|
|
7
|
+
* Centralizes file writing patterns used across the codebase
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Write file with automatic directory creation
|
|
11
|
+
*/
|
|
12
|
+
function writeFile(path, content) {
|
|
13
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
14
|
+
writeFileSync(path, content, "utf-8");
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Write file only if content changed (for dev mode optimization)
|
|
18
|
+
* Returns true if file was written, false if unchanged
|
|
19
|
+
*/
|
|
20
|
+
function writeFileIfChanged(path, content) {
|
|
21
|
+
try {
|
|
22
|
+
if (existsSync(path)) {
|
|
23
|
+
if (readFileSync(path, "utf-8") === content) return false;
|
|
24
|
+
}
|
|
25
|
+
} catch {}
|
|
26
|
+
writeFile(path, content);
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Ensure directory exists
|
|
31
|
+
*/
|
|
32
|
+
function ensureDir(path) {
|
|
33
|
+
mkdirSync(path, { recursive: true });
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Read file safely, returns undefined if file doesn't exist
|
|
37
|
+
*/
|
|
38
|
+
function readFileSafe(path) {
|
|
39
|
+
try {
|
|
40
|
+
return readFileSync(path, "utf-8");
|
|
41
|
+
} catch {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
//#endregion
|
|
47
|
+
export { ensureDir, readFileSafe, writeFile, writeFileIfChanged };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/core/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/core/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 };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { DirectiveFileRef, DirectiveParser, ParsedDirective, directiveParser, generateDirectiveSchema, generateDirectiveSchemas } from "./directive-parser.mjs";
|
|
2
|
+
import { MaskErrorOptions, createDefaultMaskError } from "./errors.mjs";
|
|
3
|
+
import { ensureDir, readFileSafe, writeFile, writeFileIfChanged } from "./file-io.mjs";
|
|
4
|
+
import { getImportId, relativeWithDot } from "./imports.mjs";
|
|
5
|
+
import { createLogger, createSilentLogger, defaultLogger } from "./logger.mjs";
|
|
6
|
+
import { OfetchTemplateOptions, generateOfetchTemplate } from "./ofetch-templates.mjs";
|
|
7
|
+
export { DirectiveFileRef, DirectiveParser, MaskErrorOptions, OfetchTemplateOptions, ParsedDirective, createDefaultMaskError, createLogger, createSilentLogger, defaultLogger, directiveParser, ensureDir, generateDirectiveSchema, generateDirectiveSchemas, generateOfetchTemplate, getImportId, readFileSafe, relativeWithDot, writeFile, writeFileIfChanged };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ensureDir, readFileSafe, writeFile, writeFileIfChanged } from "./file-io.mjs";
|
|
2
|
+
import { createLogger, createSilentLogger, defaultLogger } from "./logger.mjs";
|
|
3
|
+
import { DirectiveParser, directiveParser, generateDirectiveSchema, generateDirectiveSchemas } from "./directive-parser.mjs";
|
|
4
|
+
import { createDefaultMaskError } from "./errors.mjs";
|
|
5
|
+
import { getImportId, relativeWithDot } from "./imports.mjs";
|
|
6
|
+
import { generateOfetchTemplate } from "./ofetch-templates.mjs";
|
|
7
|
+
|
|
8
|
+
export { DirectiveParser, createDefaultMaskError, createLogger, createSilentLogger, defaultLogger, directiveParser, ensureDir, generateDirectiveSchema, generateDirectiveSchemas, generateOfetchTemplate, getImportId, readFileSafe, relativeWithDot, writeFile, writeFileIfChanged };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { CoreLogger } from "../types/config.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/core/utils/logger.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Create a logger instance with the nitro-graphql tag
|
|
7
|
+
*/
|
|
8
|
+
declare function createLogger(tag?: string): CoreLogger;
|
|
9
|
+
/**
|
|
10
|
+
* Default logger instance
|
|
11
|
+
*/
|
|
12
|
+
declare const defaultLogger: CoreLogger;
|
|
13
|
+
/**
|
|
14
|
+
* Create a silent logger (no output)
|
|
15
|
+
* Useful for testing or when logging should be suppressed
|
|
16
|
+
*/
|
|
17
|
+
declare function createSilentLogger(): CoreLogger;
|
|
18
|
+
//#endregion
|
|
19
|
+
export { createLogger, createSilentLogger, defaultLogger };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { LOG_TAG } from "../constants.mjs";
|
|
2
|
+
import { consola as consola$1 } from "consola";
|
|
3
|
+
|
|
4
|
+
//#region src/core/utils/logger.ts
|
|
5
|
+
/**
|
|
6
|
+
* Create a logger instance with the nitro-graphql tag
|
|
7
|
+
*/
|
|
8
|
+
function createLogger(tag = LOG_TAG) {
|
|
9
|
+
const logger = consola$1.withTag(tag);
|
|
10
|
+
return {
|
|
11
|
+
info: (message, ...args) => logger.info(message, ...args),
|
|
12
|
+
warn: (message, ...args) => logger.warn(message, ...args),
|
|
13
|
+
error: (message, ...args) => logger.error(message, ...args),
|
|
14
|
+
success: (message, ...args) => logger.success(message, ...args),
|
|
15
|
+
debug: (message, ...args) => logger.debug(message, ...args)
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Default logger instance
|
|
20
|
+
*/
|
|
21
|
+
const defaultLogger = createLogger();
|
|
22
|
+
/**
|
|
23
|
+
* Create a silent logger (no output)
|
|
24
|
+
* Useful for testing or when logging should be suppressed
|
|
25
|
+
*/
|
|
26
|
+
function createSilentLogger() {
|
|
27
|
+
const noop = () => {};
|
|
28
|
+
return {
|
|
29
|
+
info: noop,
|
|
30
|
+
warn: noop,
|
|
31
|
+
error: noop,
|
|
32
|
+
success: noop,
|
|
33
|
+
debug: noop
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
//#endregion
|
|
38
|
+
export { createLogger, createSilentLogger, defaultLogger };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
//#region src/core/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/core/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,11 @@
|
|
|
1
|
+
//#region src/core/validation/external-services.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* External services validation utilities
|
|
4
|
+
* Framework-agnostic validation helpers
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Validate external GraphQL service configuration
|
|
8
|
+
*/
|
|
9
|
+
declare function validateExternalServices(services: unknown[]): string[];
|
|
10
|
+
//#endregion
|
|
11
|
+
export { validateExternalServices };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
//#region src/core/validation/external-services.ts
|
|
2
|
+
/**
|
|
3
|
+
* External services validation utilities
|
|
4
|
+
* Framework-agnostic validation helpers
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Validate external GraphQL service configuration
|
|
8
|
+
*/
|
|
9
|
+
function validateExternalServices(services) {
|
|
10
|
+
const errors = [];
|
|
11
|
+
const serviceNames = /* @__PURE__ */ new Set();
|
|
12
|
+
for (const [index, service] of services.entries()) {
|
|
13
|
+
const prefix = `externalServices[${index}]`;
|
|
14
|
+
if (!service || typeof service !== "object") {
|
|
15
|
+
errors.push(`${prefix} must be an object`);
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
if (!("name" in service) || typeof service.name !== "string") errors.push(`${prefix}.name is required and must be a string`);
|
|
19
|
+
else if (serviceNames.has(service.name)) errors.push(`${prefix}.name "${service.name}" must be unique`);
|
|
20
|
+
else serviceNames.add(service.name);
|
|
21
|
+
if (!("schema" in service) || !service.schema) errors.push(`${prefix}.schema is required`);
|
|
22
|
+
if (!("endpoint" in service) || typeof service.endpoint !== "string") errors.push(`${prefix}.endpoint is required and must be a string`);
|
|
23
|
+
else try {
|
|
24
|
+
new URL(service.endpoint);
|
|
25
|
+
} catch {
|
|
26
|
+
errors.push(`${prefix}.endpoint "${service.endpoint}" must be a valid URL`);
|
|
27
|
+
}
|
|
28
|
+
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)`);
|
|
29
|
+
}
|
|
30
|
+
return errors;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
//#endregion
|
|
34
|
+
export { validateExternalServices };
|