nitro-graphql 2.0.0-beta.34 → 2.0.0-beta.37
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/index.d.mts +2 -1
- package/dist/index.mjs +2 -2
- package/dist/routes/apollo-server.d.mts +2 -2
- package/dist/routes/apollo-server.mjs +34 -8
- package/dist/routes/debug.d.mts +2 -2
- package/dist/routes/graphql-yoga.d.mts +2 -2
- package/dist/routes/graphql-yoga.mjs +18 -7
- package/dist/setup.d.mts +8 -1
- package/dist/setup.mjs +102 -24
- package/dist/types/index.d.mts +54 -4
- package/dist/utils/client-codegen.mjs +27 -17
- package/package.json +12 -11
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { NitroGraphQLOptions } from "./types/index.mjs";
|
|
2
|
+
import { resolveSecurityConfig } from "./setup.mjs";
|
|
2
3
|
import { NitroModule } from "nitro/types";
|
|
3
4
|
import { Plugin } from "vite";
|
|
4
5
|
|
|
@@ -40,4 +41,4 @@ declare function graphqlModule(options?: NitroGraphQLOptions): Plugin & {
|
|
|
40
41
|
nitro?: NitroModule;
|
|
41
42
|
};
|
|
42
43
|
//#endregion
|
|
43
|
-
export { graphqlModule as default };
|
|
44
|
+
export { graphqlModule as default, resolveSecurityConfig };
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { setupNitroGraphQL } from "./setup.mjs";
|
|
1
|
+
import { resolveSecurityConfig, setupNitroGraphQL } from "./setup.mjs";
|
|
2
2
|
import { readFile } from "node:fs/promises";
|
|
3
3
|
import defu from "defu";
|
|
4
4
|
|
|
@@ -60,4 +60,4 @@ function graphqlModule(options) {
|
|
|
60
60
|
var src_default = graphqlModule;
|
|
61
61
|
|
|
62
62
|
//#endregion
|
|
63
|
-
export { src_default as default };
|
|
63
|
+
export { src_default as default, resolveSecurityConfig };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as nitro_deps_h30 from "nitro/deps/h3";
|
|
2
2
|
|
|
3
3
|
//#region src/routes/apollo-server.d.ts
|
|
4
|
-
declare const _default:
|
|
4
|
+
declare const _default: nitro_deps_h30.EventHandlerWithFetch<nitro_deps_h30.EventHandlerRequest, Promise<any>>;
|
|
5
5
|
//#endregion
|
|
6
6
|
export { _default as default };
|
|
@@ -6,6 +6,7 @@ import { directives } from "#nitro-graphql/server-directives";
|
|
|
6
6
|
import { resolvers } from "#nitro-graphql/server-resolvers";
|
|
7
7
|
import { schemas } from "#nitro-graphql/server-schemas";
|
|
8
8
|
import { ApolloServer } from "@apollo/server";
|
|
9
|
+
import { ApolloServerPluginLandingPageDisabled } from "@apollo/server/plugin/disabled";
|
|
9
10
|
import { ApolloServerPluginLandingPageLocalDefault } from "@apollo/server/plugin/landingPage/default";
|
|
10
11
|
import { startServerAndCreateH3Handler } from "nitro-graphql/utils/apollo";
|
|
11
12
|
import { defineEventHandler } from "nitro/h3";
|
|
@@ -15,15 +16,40 @@ let apolloServer = null;
|
|
|
15
16
|
let serverStarted = false;
|
|
16
17
|
async function createApolloServer() {
|
|
17
18
|
if (!apolloServer) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
19
|
+
const schema = await createMergedSchema({
|
|
20
|
+
schemas,
|
|
21
|
+
resolvers,
|
|
22
|
+
directives,
|
|
23
|
+
moduleConfig
|
|
24
|
+
});
|
|
25
|
+
const securityConfig = moduleConfig.security || {
|
|
25
26
|
introspection: true,
|
|
26
|
-
|
|
27
|
+
playground: true,
|
|
28
|
+
maskErrors: false,
|
|
29
|
+
disableSuggestions: false
|
|
30
|
+
};
|
|
31
|
+
const plugins = [];
|
|
32
|
+
if (securityConfig.playground) plugins.push(ApolloServerPluginLandingPageLocalDefault({ embed: true }));
|
|
33
|
+
else plugins.push(ApolloServerPluginLandingPageDisabled());
|
|
34
|
+
const userFacingCodes = [
|
|
35
|
+
"BAD_USER_INPUT",
|
|
36
|
+
"GRAPHQL_VALIDATION_FAILED",
|
|
37
|
+
"UNAUTHENTICATED",
|
|
38
|
+
"FORBIDDEN",
|
|
39
|
+
"BAD_REQUEST"
|
|
40
|
+
];
|
|
41
|
+
apolloServer = new ApolloServer(defu({
|
|
42
|
+
schema,
|
|
43
|
+
introspection: securityConfig.introspection,
|
|
44
|
+
plugins,
|
|
45
|
+
formatError: securityConfig.maskErrors ? (formattedError, _error) => {
|
|
46
|
+
const code = formattedError?.extensions?.code;
|
|
47
|
+
if (code && userFacingCodes.includes(code)) return formattedError;
|
|
48
|
+
return {
|
|
49
|
+
message: "Internal server error",
|
|
50
|
+
extensions: { code: "INTERNAL_SERVER_ERROR" }
|
|
51
|
+
};
|
|
52
|
+
} : void 0
|
|
27
53
|
}, importedConfig));
|
|
28
54
|
if (!serverStarted) {
|
|
29
55
|
await apolloServer.start();
|
package/dist/routes/debug.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as nitro_deps_h31 from "nitro/deps/h3";
|
|
2
2
|
|
|
3
3
|
//#region src/routes/debug.d.ts
|
|
4
4
|
|
|
@@ -10,7 +10,7 @@ import * as nitro_deps_h33 from "nitro/deps/h3";
|
|
|
10
10
|
* - /_nitro/graphql/debug - HTML dashboard
|
|
11
11
|
* - /_nitro/graphql/debug?format=json - JSON API
|
|
12
12
|
*/
|
|
13
|
-
declare const _default:
|
|
13
|
+
declare const _default: nitro_deps_h31.EventHandlerWithFetch<nitro_deps_h31.EventHandlerRequest, Promise<string | {
|
|
14
14
|
timestamp: string;
|
|
15
15
|
environment: {
|
|
16
16
|
dev: any;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as nitro_deps_h33 from "nitro/deps/h3";
|
|
2
2
|
|
|
3
3
|
//#region src/routes/graphql-yoga.d.ts
|
|
4
|
-
declare const _default:
|
|
4
|
+
declare const _default: nitro_deps_h33.EventHandlerWithFetch<nitro_deps_h33.EventHandlerRequest, Promise<Response>>;
|
|
5
5
|
//#endregion
|
|
6
6
|
export { _default as default };
|
|
@@ -28,17 +28,28 @@ new window.EmbeddedSandbox({
|
|
|
28
28
|
</html>`;
|
|
29
29
|
let yoga;
|
|
30
30
|
var graphql_yoga_default = defineEventHandler(async (event) => {
|
|
31
|
-
if (!yoga)
|
|
32
|
-
schema
|
|
31
|
+
if (!yoga) {
|
|
32
|
+
const schema = await createMergedSchema({
|
|
33
33
|
schemas,
|
|
34
34
|
resolvers,
|
|
35
35
|
directives,
|
|
36
36
|
moduleConfig
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
37
|
+
});
|
|
38
|
+
const securityConfig = moduleConfig.security || {
|
|
39
|
+
introspection: true,
|
|
40
|
+
playground: true,
|
|
41
|
+
maskErrors: false,
|
|
42
|
+
disableSuggestions: false
|
|
43
|
+
};
|
|
44
|
+
yoga = createYoga(defu({
|
|
45
|
+
schema,
|
|
46
|
+
graphqlEndpoint: "/api/graphql",
|
|
47
|
+
landingPage: securityConfig.playground,
|
|
48
|
+
graphiql: securityConfig.playground ? { defaultQuery: "# Welcome to GraphQL\n#\n# Try running a query!\n" } : false,
|
|
49
|
+
renderGraphiQL: securityConfig.playground ? () => apolloSandboxHtml : void 0,
|
|
50
|
+
maskedErrors: securityConfig.maskErrors
|
|
51
|
+
}, importedConfig));
|
|
52
|
+
}
|
|
42
53
|
const response = await yoga.handleRequest(event.req, event);
|
|
43
54
|
if (event.res.status && event.res.status !== 200) return new Response(response.body, {
|
|
44
55
|
...response,
|
package/dist/setup.d.mts
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
|
+
import { SecurityConfig } from "./types/index.mjs";
|
|
1
2
|
import { Nitro } from "nitro/types";
|
|
2
3
|
|
|
3
4
|
//#region src/setup.d.ts
|
|
4
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Resolves security configuration with environment-aware defaults
|
|
8
|
+
* In production: introspection off, playground off, errors masked, suggestions disabled
|
|
9
|
+
* In development: introspection on, playground on, errors shown, suggestions enabled
|
|
10
|
+
*/
|
|
11
|
+
declare function resolveSecurityConfig(config?: SecurityConfig): Required<SecurityConfig>;
|
|
5
12
|
/**
|
|
6
13
|
* Main setup function for nitro-graphql
|
|
7
14
|
* Coordinates all initialization steps for the module
|
|
8
15
|
*/
|
|
9
16
|
declare function setupNitroGraphQL(nitro: Nitro): Promise<void>;
|
|
10
17
|
//#endregion
|
|
11
|
-
export { setupNitroGraphQL };
|
|
18
|
+
export { resolveSecurityConfig, setupNitroGraphQL };
|
package/dist/setup.mjs
CHANGED
|
@@ -18,34 +18,52 @@ import { join, relative, resolve } from "pathe";
|
|
|
18
18
|
//#region src/setup.ts
|
|
19
19
|
const logger = consola.withTag(LOG_TAG);
|
|
20
20
|
/**
|
|
21
|
+
* Resolves security configuration with environment-aware defaults
|
|
22
|
+
* In production: introspection off, playground off, errors masked, suggestions disabled
|
|
23
|
+
* In development: introspection on, playground on, errors shown, suggestions enabled
|
|
24
|
+
*/
|
|
25
|
+
function resolveSecurityConfig(config) {
|
|
26
|
+
const isProd = process.env.NODE_ENV === "production";
|
|
27
|
+
return {
|
|
28
|
+
introspection: config?.introspection ?? !isProd,
|
|
29
|
+
playground: config?.playground ?? !isProd,
|
|
30
|
+
maskErrors: config?.maskErrors ?? isProd,
|
|
31
|
+
disableSuggestions: config?.disableSuggestions ?? isProd
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
21
35
|
* Main setup function for nitro-graphql
|
|
22
36
|
* Coordinates all initialization steps for the module
|
|
23
37
|
*/
|
|
24
38
|
async function setupNitroGraphQL(nitro) {
|
|
25
|
-
|
|
39
|
+
const serverEnabled = nitro.options.graphql?.server !== false;
|
|
40
|
+
initializeConfiguration(nitro, serverEnabled);
|
|
26
41
|
validateConfiguration(nitro);
|
|
27
42
|
setupBuildDirectories(nitro);
|
|
28
|
-
|
|
29
|
-
|
|
43
|
+
if (serverEnabled) {
|
|
44
|
+
setupRollupExternals(nitro);
|
|
45
|
+
setupRollupChunking(nitro);
|
|
46
|
+
}
|
|
30
47
|
initializeRuntimeConfig(nitro);
|
|
31
|
-
setupFileWatching(nitro);
|
|
32
|
-
await scanGraphQLFiles(nitro);
|
|
33
|
-
setupDevHooks(nitro);
|
|
34
|
-
await rollupConfig(nitro);
|
|
35
|
-
await generateTypes(nitro);
|
|
36
|
-
setupCloseHooks(nitro);
|
|
37
|
-
registerRouteHandlers(nitro);
|
|
48
|
+
setupFileWatching(nitro, serverEnabled);
|
|
49
|
+
await scanGraphQLFiles(nitro, serverEnabled);
|
|
50
|
+
if (serverEnabled) setupDevHooks(nitro);
|
|
51
|
+
if (serverEnabled) await rollupConfig(nitro);
|
|
52
|
+
await generateTypes(nitro, serverEnabled);
|
|
53
|
+
setupCloseHooks(nitro, serverEnabled);
|
|
54
|
+
if (serverEnabled) registerRouteHandlers(nitro);
|
|
38
55
|
setupTypeScriptConfiguration(nitro);
|
|
39
56
|
setupNuxtIntegration(nitro);
|
|
40
|
-
generateScaffoldFiles(nitro);
|
|
57
|
+
if (serverEnabled) generateScaffoldFiles(nitro);
|
|
58
|
+
logStartupInfo(nitro, serverEnabled);
|
|
41
59
|
}
|
|
42
60
|
/**
|
|
43
61
|
* Initialize default configuration values
|
|
44
62
|
*/
|
|
45
|
-
function initializeConfiguration(nitro) {
|
|
63
|
+
function initializeConfiguration(nitro, serverEnabled) {
|
|
46
64
|
nitro.options.graphql ||= {};
|
|
47
65
|
nitro.options.graphql.types = defu(nitro.options.graphql.types, DEFAULT_TYPES_CONFIG);
|
|
48
|
-
if (!nitro.options.graphql?.framework) logger.warn("No GraphQL framework specified. Please set graphql.framework to \"graphql-yoga\" or \"apollo-server\".");
|
|
66
|
+
if (serverEnabled && !nitro.options.graphql?.framework) logger.warn("No GraphQL framework specified. Please set graphql.framework to \"graphql-yoga\" or \"apollo-server\".");
|
|
49
67
|
const defaultPaths = getDefaultPaths(nitro);
|
|
50
68
|
nitro.graphql ||= {
|
|
51
69
|
buildDir: "",
|
|
@@ -58,6 +76,10 @@ function initializeConfiguration(nitro) {
|
|
|
58
76
|
server: "server"
|
|
59
77
|
}
|
|
60
78
|
};
|
|
79
|
+
nitro.scanSchemas ||= [];
|
|
80
|
+
nitro.scanResolvers ||= [];
|
|
81
|
+
nitro.scanDirectives ||= [];
|
|
82
|
+
nitro.scanDocuments ||= [];
|
|
61
83
|
}
|
|
62
84
|
/**
|
|
63
85
|
* Validate external services configuration
|
|
@@ -96,13 +118,17 @@ function setupBuildDirectories(nitro) {
|
|
|
96
118
|
* Initialize runtime configuration
|
|
97
119
|
*/
|
|
98
120
|
function initializeRuntimeConfig(nitro) {
|
|
99
|
-
|
|
121
|
+
const securityConfig = resolveSecurityConfig(nitro.options.graphql?.security);
|
|
122
|
+
nitro.options.runtimeConfig.graphql = defu(nitro.options.runtimeConfig.graphql || {}, {
|
|
123
|
+
...DEFAULT_RUNTIME_CONFIG,
|
|
124
|
+
security: securityConfig
|
|
125
|
+
});
|
|
100
126
|
}
|
|
101
127
|
/**
|
|
102
128
|
* Setup file watching for development mode
|
|
103
129
|
*/
|
|
104
|
-
function setupFileWatching(nitro) {
|
|
105
|
-
const watchDirs = getWatchDirectories(nitro);
|
|
130
|
+
function setupFileWatching(nitro, serverEnabled) {
|
|
131
|
+
const watchDirs = serverEnabled ? getWatchDirectories(nitro) : [nitro.graphql.clientDir].filter(Boolean);
|
|
106
132
|
nitro.graphql.watchDirs = watchDirs;
|
|
107
133
|
const watcher = setupFileWatcher(nitro, watchDirs);
|
|
108
134
|
nitro.hooks.hook("close", () => {
|
|
@@ -112,8 +138,12 @@ function setupFileWatching(nitro) {
|
|
|
112
138
|
/**
|
|
113
139
|
* Scan all GraphQL files (schemas, resolvers, directives, documents)
|
|
114
140
|
*/
|
|
115
|
-
async function scanGraphQLFiles(nitro) {
|
|
116
|
-
await scanAllGraphQLFiles(nitro);
|
|
141
|
+
async function scanGraphQLFiles(nitro, serverEnabled) {
|
|
142
|
+
if (serverEnabled) await scanAllGraphQLFiles(nitro);
|
|
143
|
+
else {
|
|
144
|
+
const { scanDocuments } = await import("./utils/index.mjs");
|
|
145
|
+
nitro.scanDocuments = await scanDocuments(nitro);
|
|
146
|
+
}
|
|
117
147
|
}
|
|
118
148
|
/**
|
|
119
149
|
* Setup dev mode hooks for rescanning files
|
|
@@ -157,16 +187,18 @@ function logResolverDiagnostics(nitro) {
|
|
|
157
187
|
/**
|
|
158
188
|
* Generate server and client types
|
|
159
189
|
*/
|
|
160
|
-
async function generateTypes(nitro) {
|
|
161
|
-
|
|
162
|
-
|
|
190
|
+
async function generateTypes(nitro, serverEnabled) {
|
|
191
|
+
if (serverEnabled) {
|
|
192
|
+
await generateServerTypes(nitro);
|
|
193
|
+
await generateClientTypes(nitro, { isInitial: true });
|
|
194
|
+
} else await generateClientTypes(nitro, { isInitial: true });
|
|
163
195
|
}
|
|
164
196
|
/**
|
|
165
197
|
* Setup close hooks for final type generation
|
|
166
198
|
*/
|
|
167
|
-
function setupCloseHooks(nitro) {
|
|
199
|
+
function setupCloseHooks(nitro, serverEnabled) {
|
|
168
200
|
nitro.hooks.hook("close", async () => {
|
|
169
|
-
await generateServerTypes(nitro, { silent: true });
|
|
201
|
+
if (serverEnabled) await generateServerTypes(nitro, { silent: true });
|
|
170
202
|
await generateClientTypes(nitro, { silent: true });
|
|
171
203
|
});
|
|
172
204
|
}
|
|
@@ -215,6 +247,52 @@ function setupNuxtIntegration(nitro) {
|
|
|
215
247
|
if (nuxtOptions) nuxtOptions.nitroGraphqlExternalServices = nitro.options.graphql?.externalServices || [];
|
|
216
248
|
});
|
|
217
249
|
}
|
|
250
|
+
/**
|
|
251
|
+
* Log startup information
|
|
252
|
+
*/
|
|
253
|
+
function logStartupInfo(nitro, serverEnabled) {
|
|
254
|
+
const externalServicesCount = nitro.options.graphql?.externalServices?.length || 0;
|
|
255
|
+
const docs = nitro.scanDocuments || [];
|
|
256
|
+
const isProd = process.env.NODE_ENV === "production";
|
|
257
|
+
if (serverEnabled) {
|
|
258
|
+
const securityConfig = resolveSecurityConfig(nitro.options.graphql?.security);
|
|
259
|
+
const framework = nitro.options.graphql?.framework || "unknown";
|
|
260
|
+
const schemas = nitro.scanSchemas?.length || 0;
|
|
261
|
+
const resolvers = nitro.scanResolvers?.length || 0;
|
|
262
|
+
consola.box({
|
|
263
|
+
title: "Nitro GraphQL",
|
|
264
|
+
message: [
|
|
265
|
+
`Framework: ${framework}`,
|
|
266
|
+
`Environment: ${isProd ? "production" : "development"}`,
|
|
267
|
+
`Schemas: ${schemas}`,
|
|
268
|
+
`Resolvers: ${resolvers}`,
|
|
269
|
+
externalServicesCount > 0 ? `External Services: ${externalServicesCount}` : "",
|
|
270
|
+
docs.length > 0 ? `Documents: ${docs.length}` : "",
|
|
271
|
+
"",
|
|
272
|
+
"Security:",
|
|
273
|
+
`├─ Introspection: ${securityConfig.introspection ? "enabled" : "disabled"}`,
|
|
274
|
+
`├─ Playground: ${securityConfig.playground ? "enabled" : "disabled"}`,
|
|
275
|
+
`├─ Error Masking: ${securityConfig.maskErrors ? "enabled" : "disabled"}`,
|
|
276
|
+
`└─ Field Suggestions: ${securityConfig.disableSuggestions ? "disabled" : "enabled"}`
|
|
277
|
+
].filter(Boolean).join("\n"),
|
|
278
|
+
style: {
|
|
279
|
+
borderColor: isProd ? "yellow" : "cyan",
|
|
280
|
+
borderStyle: "rounded"
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
} else consola.box({
|
|
284
|
+
title: "Nitro GraphQL (Client Only)",
|
|
285
|
+
message: [
|
|
286
|
+
"Server mode: disabled",
|
|
287
|
+
`External Services: ${externalServicesCount}`,
|
|
288
|
+
`Documents: ${docs.length}`
|
|
289
|
+
].join("\n"),
|
|
290
|
+
style: {
|
|
291
|
+
borderColor: "blue",
|
|
292
|
+
borderStyle: "rounded"
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
}
|
|
218
296
|
|
|
219
297
|
//#endregion
|
|
220
|
-
export { setupNitroGraphQL };
|
|
298
|
+
export { resolveSecurityConfig, setupNitroGraphQL };
|
package/dist/types/index.d.mts
CHANGED
|
@@ -16,6 +16,13 @@ type GenericSdkConfig = Omit<Parameters<typeof plugin$1>[2], 'documentMode'> & {
|
|
|
16
16
|
};
|
|
17
17
|
type CodegenClientConfig = TypeScriptPluginConfig & TypeScriptDocumentsPluginConfig & {
|
|
18
18
|
endpoint?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Generate TypedDocumentNode exports for urql/Apollo Client compatibility.
|
|
21
|
+
* When enabled, generates typed document constants that can be used with
|
|
22
|
+
* any GraphQL client that supports TypedDocumentNode.
|
|
23
|
+
* @default false
|
|
24
|
+
*/
|
|
25
|
+
typedDocumentNode?: boolean;
|
|
19
26
|
};
|
|
20
27
|
interface IESMImport {
|
|
21
28
|
name: string;
|
|
@@ -72,10 +79,13 @@ interface ExternalServicePaths {
|
|
|
72
79
|
interface ExternalGraphQLService {
|
|
73
80
|
/** Unique name for this service (used for file naming and type generation) */
|
|
74
81
|
name: string;
|
|
75
|
-
/**
|
|
76
|
-
schema: string | string[];
|
|
77
|
-
/** GraphQL endpoint for this service */
|
|
82
|
+
/** GraphQL endpoint for this service (also used as schema source if `schema` is not specified) */
|
|
78
83
|
endpoint: string;
|
|
84
|
+
/**
|
|
85
|
+
* Schema source - can be URL(s) for remote schemas or file path(s) for local schemas
|
|
86
|
+
* @default Uses `endpoint` for introspection if not specified
|
|
87
|
+
*/
|
|
88
|
+
schema?: string | string[];
|
|
79
89
|
/** Optional headers for schema introspection and client requests */
|
|
80
90
|
headers?: Record<string, string> | (() => Record<string, string>);
|
|
81
91
|
/** Optional: specific document patterns for this service */
|
|
@@ -187,8 +197,43 @@ interface PathsConfig {
|
|
|
187
197
|
/** Types directory (default: '{buildDir}/types') */
|
|
188
198
|
typesDir?: string;
|
|
189
199
|
}
|
|
200
|
+
/**
|
|
201
|
+
* Security configuration for production environments
|
|
202
|
+
* All options auto-detect based on NODE_ENV when not explicitly set
|
|
203
|
+
*/
|
|
204
|
+
interface SecurityConfig {
|
|
205
|
+
/**
|
|
206
|
+
* Enable GraphQL introspection queries
|
|
207
|
+
* @default true in development, false in production
|
|
208
|
+
*/
|
|
209
|
+
introspection?: boolean;
|
|
210
|
+
/**
|
|
211
|
+
* Enable GraphQL playground/sandbox UI
|
|
212
|
+
* @default true in development, false in production
|
|
213
|
+
*/
|
|
214
|
+
playground?: boolean;
|
|
215
|
+
/**
|
|
216
|
+
* Mask internal error details in responses
|
|
217
|
+
* When enabled, internal errors show "Internal server error" instead of actual message
|
|
218
|
+
* @default false in development, true in production
|
|
219
|
+
*/
|
|
220
|
+
maskErrors?: boolean;
|
|
221
|
+
/**
|
|
222
|
+
* Disable "Did you mean X?" field suggestions in error messages
|
|
223
|
+
* Prevents attackers from discovering field names via brute force
|
|
224
|
+
* @default false in development, true in production
|
|
225
|
+
*/
|
|
226
|
+
disableSuggestions?: boolean;
|
|
227
|
+
}
|
|
190
228
|
interface NitroGraphQLOptions {
|
|
191
229
|
framework?: 'graphql-yoga' | 'apollo-server';
|
|
230
|
+
/**
|
|
231
|
+
* Enable/disable GraphQL server functionality
|
|
232
|
+
* When set to false, only external services client types will be generated
|
|
233
|
+
* Server routes, resolvers, schemas, and directives will not be processed
|
|
234
|
+
* @default true
|
|
235
|
+
*/
|
|
236
|
+
server?: boolean;
|
|
192
237
|
endpoint?: {
|
|
193
238
|
graphql?: string;
|
|
194
239
|
healthCheck?: string;
|
|
@@ -241,6 +286,11 @@ interface NitroGraphQLOptions {
|
|
|
241
286
|
* Customize base directories for file generation
|
|
242
287
|
*/
|
|
243
288
|
paths?: PathsConfig;
|
|
289
|
+
/**
|
|
290
|
+
* Security configuration for production environments
|
|
291
|
+
* Auto-detects NODE_ENV and applies secure defaults in production
|
|
292
|
+
*/
|
|
293
|
+
security?: SecurityConfig;
|
|
244
294
|
}
|
|
245
295
|
//#endregion
|
|
246
|
-
export { ClientUtilsConfig, CodegenClientConfig, CodegenServerConfig, ExternalGraphQLService, ExternalServicePaths, FederationConfig, FileGenerationConfig, GenImport, GenericSdkConfig, NitroGraphQLOptions, PathsConfig, ScaffoldConfig, SdkConfig, StandardSchemaV1, TypesConfig };
|
|
296
|
+
export { ClientUtilsConfig, CodegenClientConfig, CodegenServerConfig, ExternalGraphQLService, ExternalServicePaths, FederationConfig, FileGenerationConfig, GenImport, GenericSdkConfig, NitroGraphQLOptions, PathsConfig, ScaffoldConfig, SdkConfig, SecurityConfig, StandardSchemaV1, TypesConfig };
|
|
@@ -8,9 +8,10 @@ import { parse } from "graphql";
|
|
|
8
8
|
import { createHash } from "node:crypto";
|
|
9
9
|
import { codegen } from "@graphql-codegen/core";
|
|
10
10
|
import { preset } from "@graphql-codegen/import-types-preset";
|
|
11
|
-
import { plugin } from "@graphql-codegen/
|
|
12
|
-
import { plugin as plugin$1 } from "@graphql-codegen/typescript
|
|
13
|
-
import { plugin as plugin$2 } from "@graphql-codegen/typescript-
|
|
11
|
+
import { plugin } from "@graphql-codegen/typed-document-node";
|
|
12
|
+
import { plugin as plugin$1 } from "@graphql-codegen/typescript";
|
|
13
|
+
import { plugin as plugin$2 } from "@graphql-codegen/typescript-generic-sdk";
|
|
14
|
+
import { plugin as plugin$3 } from "@graphql-codegen/typescript-operations";
|
|
14
15
|
import { GraphQLFileLoader } from "@graphql-tools/graphql-file-loader";
|
|
15
16
|
import { loadDocuments, loadSchemaSync } from "@graphql-tools/load";
|
|
16
17
|
import { UrlLoader } from "@graphql-tools/url-loader";
|
|
@@ -41,7 +42,8 @@ async function graphQLLoadSchemaSync(schemaPointers, data = {}) {
|
|
|
41
42
|
async function loadExternalSchema(service, buildDir) {
|
|
42
43
|
try {
|
|
43
44
|
const headers = typeof service.headers === "function" ? service.headers() : service.headers || {};
|
|
44
|
-
const
|
|
45
|
+
const schemaSource = service.schema ?? service.endpoint;
|
|
46
|
+
const schemas = Array.isArray(schemaSource) ? schemaSource : [schemaSource];
|
|
45
47
|
if (service.downloadSchema && buildDir) {
|
|
46
48
|
const defaultPath = resolve(buildDir, "graphql", "schemas", `${service.name}.graphql`);
|
|
47
49
|
const schemaFilePath = service.downloadPath ? resolve(service.downloadPath) : defaultPath;
|
|
@@ -82,7 +84,8 @@ async function downloadAndSaveSchema(service, buildDir) {
|
|
|
82
84
|
const schemaFilePath = service.downloadPath ? resolve(service.downloadPath) : defaultPath;
|
|
83
85
|
try {
|
|
84
86
|
const headers = typeof service.headers === "function" ? service.headers() : service.headers || {};
|
|
85
|
-
const
|
|
87
|
+
const schemaSource = service.schema ?? service.endpoint;
|
|
88
|
+
const schemas = Array.isArray(schemaSource) ? schemaSource : [schemaSource];
|
|
86
89
|
const hasUrlSchemas = schemas.some((schema) => isUrl(schema));
|
|
87
90
|
const hasLocalSchemas = schemas.some((schema) => !isUrl(schema));
|
|
88
91
|
let shouldDownload = false;
|
|
@@ -184,7 +187,7 @@ async function generateClientTypes(schema, docs, config = {}, sdkConfig = {}, ou
|
|
|
184
187
|
plugins: [{ pluginContent: {} }, { typescript: {} }],
|
|
185
188
|
pluginMap: {
|
|
186
189
|
pluginContent: { plugin: pluginContent },
|
|
187
|
-
typescript: { plugin }
|
|
190
|
+
typescript: { plugin: plugin$1 }
|
|
188
191
|
}
|
|
189
192
|
}),
|
|
190
193
|
sdk: `// THIS FILE IS GENERATED, DO NOT EDIT!
|
|
@@ -213,21 +216,28 @@ export function getSdk(requester: Requester): Sdk {
|
|
|
213
216
|
}
|
|
214
217
|
`
|
|
215
218
|
};
|
|
219
|
+
const enableTypedDocumentNode = config.typedDocumentNode === true;
|
|
220
|
+
const plugins = [
|
|
221
|
+
{ pluginContent: {} },
|
|
222
|
+
{ typescript: {} },
|
|
223
|
+
{ typescriptOperations: {} }
|
|
224
|
+
];
|
|
225
|
+
const pluginMap = {
|
|
226
|
+
pluginContent: { plugin: pluginContent },
|
|
227
|
+
typescript: { plugin: plugin$1 },
|
|
228
|
+
typescriptOperations: { plugin: plugin$3 }
|
|
229
|
+
};
|
|
230
|
+
if (enableTypedDocumentNode) {
|
|
231
|
+
plugins.push({ typedDocumentNode: {} });
|
|
232
|
+
pluginMap.typedDocumentNode = { plugin };
|
|
233
|
+
}
|
|
216
234
|
const output = await codegen({
|
|
217
235
|
filename: outputPath || "client-types.generated.ts",
|
|
218
236
|
schema: parse(printSchemaWithDirectives(schema)),
|
|
219
237
|
documents: [...docs],
|
|
220
238
|
config: mergedConfig,
|
|
221
|
-
plugins
|
|
222
|
-
|
|
223
|
-
{ typescript: {} },
|
|
224
|
-
{ typescriptOperations: {} }
|
|
225
|
-
],
|
|
226
|
-
pluginMap: {
|
|
227
|
-
pluginContent: { plugin: pluginContent },
|
|
228
|
-
typescript: { plugin },
|
|
229
|
-
typescriptOperations: { plugin: plugin$2 }
|
|
230
|
-
}
|
|
239
|
+
plugins,
|
|
240
|
+
pluginMap
|
|
231
241
|
});
|
|
232
242
|
const typesPath = virtualTypesPath || (serviceName ? `#graphql/client/${serviceName}` : "#graphql/client");
|
|
233
243
|
const sdkOutput = await preset.buildGeneratesSection({
|
|
@@ -239,7 +249,7 @@ export function getSdk(requester: Requester): Sdk {
|
|
|
239
249
|
plugins: [{ pluginContent: {} }, { typescriptGenericSdk: {} }],
|
|
240
250
|
pluginMap: {
|
|
241
251
|
pluginContent: { plugin: pluginContent },
|
|
242
|
-
typescriptGenericSdk: { plugin: plugin$
|
|
252
|
+
typescriptGenericSdk: { plugin: plugin$2 }
|
|
243
253
|
}
|
|
244
254
|
});
|
|
245
255
|
return {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nitro-graphql",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "2.0.0-beta.
|
|
4
|
+
"version": "2.0.0-beta.37",
|
|
5
5
|
"description": "GraphQL integration for Nitro",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
@@ -85,9 +85,10 @@
|
|
|
85
85
|
}
|
|
86
86
|
},
|
|
87
87
|
"dependencies": {
|
|
88
|
-
"@apollo/subgraph": "^2.12.
|
|
88
|
+
"@apollo/subgraph": "^2.12.2",
|
|
89
89
|
"@graphql-codegen/core": "^5.0.0",
|
|
90
90
|
"@graphql-codegen/import-types-preset": "^3.0.1",
|
|
91
|
+
"@graphql-codegen/typed-document-node": "^6.1.5",
|
|
91
92
|
"@graphql-codegen/typescript": "^5.0.6",
|
|
92
93
|
"@graphql-codegen/typescript-generic-sdk": "^4.0.2",
|
|
93
94
|
"@graphql-codegen/typescript-operations": "^5.0.6",
|
|
@@ -106,27 +107,27 @@
|
|
|
106
107
|
"graphql-scalars": "^1.25.0",
|
|
107
108
|
"knitwork": "^1.3.0",
|
|
108
109
|
"ohash": "^2.0.11",
|
|
109
|
-
"oxc-parser": "^0.
|
|
110
|
+
"oxc-parser": "^0.102.0",
|
|
110
111
|
"pathe": "^2.0.3",
|
|
111
112
|
"tinyglobby": "^0.2.15"
|
|
112
113
|
},
|
|
113
114
|
"devDependencies": {
|
|
114
|
-
"@antfu/eslint-config": "^6.
|
|
115
|
-
"@nuxt/kit": "^4.2.
|
|
116
|
-
"@nuxt/schema": "^4.2.
|
|
117
|
-
"@types/node": "^24.10.
|
|
115
|
+
"@antfu/eslint-config": "^6.7.1",
|
|
116
|
+
"@nuxt/kit": "^4.2.2",
|
|
117
|
+
"@nuxt/schema": "^4.2.2",
|
|
118
|
+
"@types/node": "^24.10.4",
|
|
118
119
|
"@vitejs/devtools": "^0.0.0-alpha.16",
|
|
119
120
|
"@vitest/ui": "^4.0.15",
|
|
120
121
|
"bumpp": "^10.3.2",
|
|
121
122
|
"changelogen": "^0.6.2",
|
|
122
123
|
"crossws": "^0.4.1",
|
|
123
|
-
"eslint": "^9.39.
|
|
124
|
+
"eslint": "^9.39.2",
|
|
124
125
|
"graphql": "16.12.0",
|
|
125
126
|
"graphql-yoga": "5.16.2",
|
|
126
|
-
"nitro": "
|
|
127
|
-
"tsdown": "^0.
|
|
127
|
+
"nitro": "3.0.1-alpha.1",
|
|
128
|
+
"tsdown": "^0.17.4",
|
|
128
129
|
"typescript": "^5.9.3",
|
|
129
|
-
"vite": "
|
|
130
|
+
"vite": "8.0.0-beta.0",
|
|
130
131
|
"vitepress-plugin-llms": "^1.9.3",
|
|
131
132
|
"vitest": "^4.0.15"
|
|
132
133
|
},
|