nitro-graphql 1.7.0-beta.4 → 1.7.0

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 CHANGED
@@ -1,8 +1,15 @@
1
1
  import { StandardSchemaV1 } from "./types/standard-schema.mjs";
2
- import { ClientUtilsConfig, CodegenClientConfig, CodegenServerConfig, ExternalGraphQLService, ExternalServicePaths, FederationConfig, FileGenerationConfig, GenImport, GenericSdkConfig, NitroGraphQLOptions, PathsConfig, ScaffoldConfig, SdkConfig, SubscriptionsConfig, TypesConfig } from "./types/index.mjs";
2
+ import { ClientUtilsConfig, CodegenClientConfig, CodegenServerConfig, ExternalGraphQLService, ExternalServicePaths, FederationConfig, FileGenerationConfig, GenImport, GenericSdkConfig, NitroGraphQLOptions, PathsConfig, ScaffoldConfig, SdkConfig, SecurityConfig, SubscriptionsConfig, TypesConfig } from "./types/index.mjs";
3
3
  import * as nitropack0 from "nitropack";
4
4
 
5
5
  //#region src/index.d.ts
6
+
7
+ /**
8
+ * Resolve security config with environment-aware defaults
9
+ * In production: introspection off, playground off, errors masked, suggestions disabled
10
+ * In development: introspection on, playground on, errors shown, suggestions enabled
11
+ */
12
+ declare function resolveSecurityConfig(config?: SecurityConfig): Required<SecurityConfig>;
6
13
  declare const _default: nitropack0.NitroModule;
7
14
  //#endregion
8
- export { ClientUtilsConfig, CodegenClientConfig, CodegenServerConfig, ExternalGraphQLService, ExternalServicePaths, FederationConfig, FileGenerationConfig, GenImport, GenericSdkConfig, NitroGraphQLOptions, PathsConfig, ScaffoldConfig, SdkConfig, StandardSchemaV1, SubscriptionsConfig, TypesConfig, _default as default };
15
+ export { ClientUtilsConfig, CodegenClientConfig, CodegenServerConfig, ExternalGraphQLService, ExternalServicePaths, FederationConfig, FileGenerationConfig, GenImport, GenericSdkConfig, NitroGraphQLOptions, PathsConfig, ScaffoldConfig, SdkConfig, SecurityConfig, StandardSchemaV1, SubscriptionsConfig, TypesConfig, _default as default, resolveSecurityConfig };
package/dist/index.mjs CHANGED
@@ -14,6 +14,20 @@ import { defineNitroModule } from "nitropack/kit";
14
14
  import { dirname, join, relative, resolve } from "pathe";
15
15
 
16
16
  //#region src/index.ts
17
+ /**
18
+ * Resolve security config with environment-aware defaults
19
+ * In production: introspection off, playground off, errors masked, suggestions disabled
20
+ * In development: introspection on, playground on, errors shown, suggestions enabled
21
+ */
22
+ function resolveSecurityConfig(config) {
23
+ const isProd = process.env.NODE_ENV === "production";
24
+ return {
25
+ introspection: config?.introspection ?? !isProd,
26
+ playground: config?.playground ?? !isProd,
27
+ maskErrors: config?.maskErrors ?? isProd,
28
+ disableSuggestions: config?.disableSuggestions ?? isProd
29
+ };
30
+ }
17
31
  var src_default = defineNitroModule({
18
32
  name: "nitro-graphql",
19
33
  async setup(nitro) {
@@ -50,13 +64,15 @@ var src_default = defineNitroModule({
50
64
  };
51
65
  }
52
66
  });
67
+ const securityConfig = resolveSecurityConfig(nitro.options.graphql?.security);
53
68
  nitro.options.runtimeConfig.graphql = defu(nitro.options.runtimeConfig.graphql || {}, {
54
69
  endpoint: {
55
70
  graphql: "/api/graphql",
56
71
  healthCheck: "/api/graphql/health",
57
72
  ws: "/api/graphql/ws"
58
73
  },
59
- playground: true
74
+ playground: securityConfig.playground,
75
+ security: securityConfig
60
76
  });
61
77
  if (nitro.options.graphql?.federation?.enabled) consola.info(`Apollo Federation enabled for service: ${nitro.options.graphql.federation.serviceName || "unnamed"}`);
62
78
  const graphqlBuildDir = resolve(nitro.options.buildDir, "graphql");
@@ -118,19 +134,28 @@ var src_default = defineNitroModule({
118
134
  const docs = await scanDocs(nitro);
119
135
  nitro.scanDocuments = docs;
120
136
  if (nitro.options.dev) {
137
+ const runtimeSecurityConfig = nitro.options.runtimeConfig.graphql?.security;
138
+ const isProd = process.env.NODE_ENV === "production";
121
139
  consola.box({
122
140
  title: "Nitro GraphQL",
123
141
  message: [
124
142
  `Framework: ${nitro.options.graphql?.framework || "Not configured"}`,
143
+ `Environment: ${isProd ? "production" : "development"}`,
125
144
  `Schemas: ${schemas.length}`,
126
145
  `Resolvers: ${resolvers.length}`,
127
146
  `Directives: ${directives$1.length}`,
128
147
  `Documents: ${docs.length}`,
129
148
  "",
149
+ "Security:",
150
+ `├─ Introspection: ${runtimeSecurityConfig?.introspection ? "enabled" : "disabled"}`,
151
+ `├─ Playground: ${runtimeSecurityConfig?.playground ? "enabled" : "disabled"}`,
152
+ `├─ Error Masking: ${runtimeSecurityConfig?.maskErrors ? "enabled" : "disabled"}`,
153
+ `└─ Field Suggestions: ${runtimeSecurityConfig?.disableSuggestions ? "disabled" : "enabled"}`,
154
+ "",
130
155
  "Debug Dashboard: /_nitro/graphql/debug"
131
156
  ].join("\n"),
132
157
  style: {
133
- borderColor: "cyan",
158
+ borderColor: isProd ? "yellow" : "cyan",
134
159
  borderStyle: "rounded"
135
160
  }
136
161
  });
@@ -196,6 +221,8 @@ var src_default = defineNitroModule({
196
221
  route: wsEndpoint,
197
222
  handler: join(runtime, "apollo-server-ws")
198
223
  });
224
+ nitro.options.plugins ??= [];
225
+ nitro.options.plugins.push(join(runtime, "ws-shutdown"));
199
226
  consola.info(`[nitro-graphql] WebSocket subscriptions enabled at: ${wsEndpoint}`);
200
227
  }
201
228
  if (nitro.options.dev) {
@@ -350,4 +377,4 @@ declare module 'h3' {
350
377
  });
351
378
 
352
379
  //#endregion
353
- export { src_default as default };
380
+ export { src_default as default, resolveSecurityConfig };
package/dist/rollup.mjs CHANGED
@@ -187,7 +187,10 @@ export { importedConfig }
187
187
  function virtualModuleConfig(app) {
188
188
  app.options.virtual ??= {};
189
189
  app.options.virtual["#nitro-internal-virtual/module-config"] = () => {
190
- const moduleConfig = app.options.graphql || {};
190
+ const moduleConfig = {
191
+ ...app.options.graphql,
192
+ security: app.options.runtimeConfig.graphql?.security
193
+ };
191
194
  return `export const moduleConfig = ${JSON.stringify(moduleConfig, null, 2)};`;
192
195
  };
193
196
  }
@@ -1,6 +1,12 @@
1
- import * as h37 from "h3";
1
+ import * as h39 from "h3";
2
2
 
3
3
  //#region src/routes/apollo-server-ws.d.ts
4
- declare const _default: h37.EventHandler<h37.EventHandlerRequest, never>;
4
+
5
+ /**
6
+ * Gracefully shutdown all WebSocket connections.
7
+ * Called by the Nitro runtime plugin on server close.
8
+ */
9
+ declare function shutdownAllConnections(): Promise<void>;
10
+ declare const _default: h39.EventHandler<h39.EventHandlerRequest, never>;
5
11
  //#endregion
6
- export { _default as default };
12
+ export { _default as default, shutdownAllConnections };
@@ -13,6 +13,34 @@ const isDev = process.env.NODE_ENV === "development";
13
13
  function devLog(message, ...args) {
14
14
  if (isDev) console.log(message, ...args);
15
15
  }
16
+ const WS_STATE_KEY = "__nitro_graphql_ws_apollo__";
17
+ function getWsState() {
18
+ if (!globalThis[WS_STATE_KEY]) globalThis[WS_STATE_KEY] = {
19
+ activePeers: /* @__PURE__ */ new Set(),
20
+ cleanupFns: /* @__PURE__ */ new Map()
21
+ };
22
+ return globalThis[WS_STATE_KEY];
23
+ }
24
+ /**
25
+ * Gracefully shutdown all WebSocket connections.
26
+ * Called by the Nitro runtime plugin on server close.
27
+ */
28
+ async function shutdownAllConnections() {
29
+ const state = getWsState();
30
+ const peers = Array.from(state.activePeers);
31
+ if (peers.length > 0) devLog(`[Apollo WS] Shutting down ${peers.length} connection(s)...`);
32
+ for (const peer of peers) {
33
+ const cleanup = state.cleanupFns.get(peer);
34
+ if (cleanup) try {
35
+ await cleanup();
36
+ } catch {}
37
+ try {
38
+ peer.close(1012, "Service Restart");
39
+ } catch {}
40
+ }
41
+ state.activePeers.clear();
42
+ state.cleanupFns.clear();
43
+ }
16
44
  const DEFAULT_MAX_SUBSCRIPTIONS_PER_PEER = 20;
17
45
  const DEFAULT_PING_INTERVAL_MS = 15e3;
18
46
  const DEFAULT_PONG_TIMEOUT_MS = 5e3;
@@ -250,6 +278,12 @@ async function getSchema() {
250
278
  }
251
279
  var apollo_server_ws_default = defineWebSocketHandler({
252
280
  async open(peer) {
281
+ const state = getWsState();
282
+ state.activePeers.add(peer);
283
+ state.cleanupFns.set(peer, async () => {
284
+ stopKeepAlive(peer);
285
+ await cleanupSubscriptions(peer, true);
286
+ });
253
287
  devLog("[Apollo WS] Client connected");
254
288
  peer.context.subscriptions = /* @__PURE__ */ new Map();
255
289
  },
@@ -285,6 +319,9 @@ var apollo_server_ws_default = defineWebSocketHandler({
285
319
  }
286
320
  },
287
321
  async close(peer, details) {
322
+ const state = getWsState();
323
+ state.activePeers.delete(peer);
324
+ state.cleanupFns.delete(peer);
288
325
  devLog("[Apollo WS] Client disconnected:", details);
289
326
  stopKeepAlive(peer);
290
327
  await cleanupSubscriptions(peer, true);
@@ -295,4 +332,4 @@ var apollo_server_ws_default = defineWebSocketHandler({
295
332
  });
296
333
 
297
334
  //#endregion
298
- export { apollo_server_ws_default as default };
335
+ export { apollo_server_ws_default as default, shutdownAllConnections };
@@ -1,6 +1,6 @@
1
- import * as h39 from "h3";
1
+ import * as h35 from "h3";
2
2
 
3
3
  //#region src/routes/apollo-server.d.ts
4
- declare const _default: h39.EventHandler<h39.EventHandlerRequest, Promise<any>>;
4
+ declare const _default: h35.EventHandler<h35.EventHandlerRequest, Promise<any>>;
5
5
  //#endregion
6
6
  export { _default as default };
@@ -10,6 +10,7 @@ import { schemas } from "#nitro-internal-virtual/server-schemas";
10
10
  import { makeExecutableSchema } from "@graphql-tools/schema";
11
11
  import { defineEventHandler } from "h3";
12
12
  import { ApolloServer } from "@apollo/server";
13
+ import { ApolloServerPluginLandingPageDisabled } from "@apollo/server/plugin/disabled";
13
14
  import { ApolloServerPluginLandingPageLocalDefault } from "@apollo/server/plugin/landingPage/default";
14
15
  import { startServerAndCreateH3Handler } from "nitro-graphql/utils/apollo";
15
16
 
@@ -64,10 +65,34 @@ let apolloServer = null;
64
65
  let serverStarted = false;
65
66
  async function createApolloServer() {
66
67
  if (!apolloServer) {
67
- apolloServer = new ApolloServer(defu({
68
- schema: await createMergedSchema(),
68
+ const schema = await createMergedSchema();
69
+ const securityConfig = moduleConfig.security || {
69
70
  introspection: true,
70
- plugins: [ApolloServerPluginLandingPageLocalDefault({ embed: true })]
71
+ playground: true,
72
+ maskErrors: false,
73
+ disableSuggestions: false
74
+ };
75
+ const plugins = [];
76
+ if (securityConfig.playground) plugins.push(ApolloServerPluginLandingPageLocalDefault({ embed: true }));
77
+ else plugins.push(ApolloServerPluginLandingPageDisabled());
78
+ apolloServer = new ApolloServer(defu({
79
+ schema,
80
+ introspection: securityConfig.introspection,
81
+ plugins,
82
+ formatError: securityConfig.maskErrors ? (formattedError, _error) => {
83
+ const code = formattedError?.extensions?.code;
84
+ if (code && [
85
+ "BAD_USER_INPUT",
86
+ "GRAPHQL_VALIDATION_FAILED",
87
+ "UNAUTHENTICATED",
88
+ "FORBIDDEN",
89
+ "BAD_REQUEST"
90
+ ].includes(code)) return formattedError;
91
+ return {
92
+ message: "Internal server error",
93
+ extensions: { code: "INTERNAL_SERVER_ERROR" }
94
+ };
95
+ } : void 0
71
96
  }, importedConfig));
72
97
  if (!serverStarted) {
73
98
  await apolloServer.start();
@@ -1,4 +1,4 @@
1
- import * as h33 from "h3";
1
+ import * as h30 from "h3";
2
2
 
3
3
  //#region src/routes/debug.d.ts
4
4
 
@@ -10,7 +10,7 @@ import * as h33 from "h3";
10
10
  * - /_nitro/graphql/debug - HTML dashboard
11
11
  * - /_nitro/graphql/debug?format=json - JSON API
12
12
  */
13
- declare const _default: h33.EventHandler<h33.EventHandlerRequest, Promise<string | {
13
+ declare const _default: h30.EventHandler<h30.EventHandlerRequest, Promise<string | {
14
14
  timestamp: string;
15
15
  environment: {
16
16
  dev: any;
@@ -1,6 +1,12 @@
1
- import * as h35 from "h3";
1
+ import * as h31 from "h3";
2
2
 
3
3
  //#region src/routes/graphql-yoga-ws.d.ts
4
- declare const _default: h35.EventHandler<h35.EventHandlerRequest, never>;
4
+
5
+ /**
6
+ * Gracefully shutdown all WebSocket connections.
7
+ * Called by the Nitro runtime plugin on server close.
8
+ */
9
+ declare function shutdownAllConnections(): Promise<void>;
10
+ declare const _default: h31.EventHandler<h31.EventHandlerRequest, never>;
5
11
  //#endregion
6
- export { _default as default };
12
+ export { _default as default, shutdownAllConnections };
@@ -13,6 +13,34 @@ const isDev = process.env.NODE_ENV === "development";
13
13
  function devLog(message, ...args) {
14
14
  if (isDev) console.log(message, ...args);
15
15
  }
16
+ const WS_STATE_KEY = "__nitro_graphql_ws_yoga__";
17
+ function getWsState() {
18
+ if (!globalThis[WS_STATE_KEY]) globalThis[WS_STATE_KEY] = {
19
+ activePeers: /* @__PURE__ */ new Set(),
20
+ cleanupFns: /* @__PURE__ */ new Map()
21
+ };
22
+ return globalThis[WS_STATE_KEY];
23
+ }
24
+ /**
25
+ * Gracefully shutdown all WebSocket connections.
26
+ * Called by the Nitro runtime plugin on server close.
27
+ */
28
+ async function shutdownAllConnections() {
29
+ const state = getWsState();
30
+ const peers = Array.from(state.activePeers);
31
+ if (peers.length > 0) devLog(`[GraphQL WS] Shutting down ${peers.length} connection(s)...`);
32
+ for (const peer of peers) {
33
+ const cleanup = state.cleanupFns.get(peer);
34
+ if (cleanup) try {
35
+ await cleanup();
36
+ } catch {}
37
+ try {
38
+ peer.close(1012, "Service Restart");
39
+ } catch {}
40
+ }
41
+ state.activePeers.clear();
42
+ state.cleanupFns.clear();
43
+ }
16
44
  const DEFAULT_MAX_SUBSCRIPTIONS_PER_PEER = 20;
17
45
  const DEFAULT_PING_INTERVAL_MS = 15e3;
18
46
  const DEFAULT_PONG_TIMEOUT_MS = 5e3;
@@ -250,6 +278,12 @@ async function getSchema() {
250
278
  }
251
279
  var graphql_yoga_ws_default = defineWebSocketHandler({
252
280
  async open(peer) {
281
+ const state = getWsState();
282
+ state.activePeers.add(peer);
283
+ state.cleanupFns.set(peer, async () => {
284
+ stopKeepAlive(peer);
285
+ await cleanupSubscriptions(peer, true);
286
+ });
253
287
  devLog("[GraphQL WS] Client connected");
254
288
  peer.context.subscriptions = /* @__PURE__ */ new Map();
255
289
  },
@@ -285,6 +319,9 @@ var graphql_yoga_ws_default = defineWebSocketHandler({
285
319
  }
286
320
  },
287
321
  async close(peer, details) {
322
+ const state = getWsState();
323
+ state.activePeers.delete(peer);
324
+ state.cleanupFns.delete(peer);
288
325
  devLog("[GraphQL WS] Client disconnected:", details);
289
326
  stopKeepAlive(peer);
290
327
  await cleanupSubscriptions(peer, true);
@@ -295,4 +332,4 @@ var graphql_yoga_ws_default = defineWebSocketHandler({
295
332
  });
296
333
 
297
334
  //#endregion
298
- export { graphql_yoga_ws_default as default };
335
+ export { graphql_yoga_ws_default as default, shutdownAllConnections };
@@ -1,6 +1,6 @@
1
- import * as h30 from "h3";
1
+ import * as h33 from "h3";
2
2
 
3
3
  //#region src/routes/graphql-yoga.d.ts
4
- declare const _default: h30.EventHandler<h30.EventHandlerRequest, Promise<Response>>;
4
+ declare const _default: h33.EventHandler<h33.EventHandlerRequest, Promise<Response>>;
5
5
  //#endregion
6
6
  export { _default as default };
@@ -77,12 +77,23 @@ async function createMergedSchema() {
77
77
  }
78
78
  let yoga;
79
79
  var graphql_yoga_default = defineEventHandler(async (event) => {
80
- if (!yoga) yoga = createYoga(defu({
81
- schema: await createMergedSchema(),
82
- graphqlEndpoint: "/api/graphql",
83
- landingPage: false,
84
- renderGraphiQL: () => apolloSandboxHtml
85
- }, importedConfig));
80
+ if (!yoga) {
81
+ const schema = await createMergedSchema();
82
+ const securityConfig = moduleConfig.security || {
83
+ introspection: true,
84
+ playground: true,
85
+ maskErrors: false,
86
+ disableSuggestions: false
87
+ };
88
+ yoga = createYoga(defu({
89
+ schema,
90
+ graphqlEndpoint: "/api/graphql",
91
+ landingPage: securityConfig.playground,
92
+ graphiql: securityConfig.playground ? { defaultQuery: "# Welcome to the GraphQL Playground" } : false,
93
+ renderGraphiQL: securityConfig.playground ? () => apolloSandboxHtml : void 0,
94
+ maskedErrors: securityConfig.maskErrors
95
+ }, importedConfig));
96
+ }
86
97
  const request = toWebRequest(event);
87
98
  const response = await yoga.handleRequest(request, event);
88
99
  return new Response(response.body, response);
@@ -1,7 +1,7 @@
1
- import * as h31 from "h3";
1
+ import * as h37 from "h3";
2
2
 
3
3
  //#region src/routes/health.d.ts
4
- declare const _default: h31.EventHandler<h31.EventHandlerRequest, Promise<{
4
+ declare const _default: h37.EventHandler<h37.EventHandlerRequest, Promise<{
5
5
  status: string;
6
6
  message: string;
7
7
  timestamp: string;
@@ -0,0 +1,11 @@
1
+ import * as nitropack0 from "nitropack";
2
+
3
+ //#region src/routes/ws-shutdown.d.ts
4
+
5
+ /**
6
+ * Nitro runtime plugin for graceful WebSocket shutdown.
7
+ * Registered when subscriptions are enabled.
8
+ */
9
+ declare const _default: nitropack0.NitroAppPlugin;
10
+ //#endregion
11
+ export { _default as default };
@@ -0,0 +1,22 @@
1
+ import { defineNitroPlugin } from "nitropack/runtime";
2
+
3
+ //#region src/routes/ws-shutdown.ts
4
+ /**
5
+ * Nitro runtime plugin for graceful WebSocket shutdown.
6
+ * Registered when subscriptions are enabled.
7
+ */
8
+ var ws_shutdown_default = defineNitroPlugin((nitroApp) => {
9
+ nitroApp.hooks.hook("close", async () => {
10
+ if (globalThis.__nitro_graphql_ws_yoga__?.activePeers?.size > 0) try {
11
+ const { shutdownAllConnections } = await import("./graphql-yoga-ws.mjs");
12
+ await shutdownAllConnections();
13
+ } catch {}
14
+ if (globalThis.__nitro_graphql_ws_apollo__?.activePeers?.size > 0) try {
15
+ const { shutdownAllConnections } = await import("./apollo-server-ws.mjs");
16
+ await shutdownAllConnections();
17
+ } catch {}
18
+ });
19
+ });
20
+
21
+ //#endregion
22
+ export { ws_shutdown_default as default };
@@ -58,8 +58,6 @@ type SubscriptionTransport = 'websocket' | 'sse' | 'auto';
58
58
  interface TransportOptions {
59
59
  /** Transport type: 'websocket' (default), 'sse', or 'auto' (WS first, SSE fallback) */
60
60
  transport?: SubscriptionTransport;
61
- /** Shorthand for { transport: 'sse' } */
62
- sse?: boolean;
63
61
  }
64
62
  interface SubscriptionOptions<TVariables = Record<string, unknown>> {
65
63
  query: string;
@@ -564,7 +564,6 @@ function createSession(endpoint, connectionParams, maxRetries, connectionTimeout
564
564
  * Resolve transport type from options
565
565
  */
566
566
  function resolveTransport(options) {
567
- if (options?.sse) return "sse";
568
567
  return options?.transport ?? "websocket";
569
568
  }
570
569
  function createSubscriptionClient(config = {}) {
@@ -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;
@@ -198,6 +205,34 @@ interface SubscriptionsConfig {
198
205
  /** WebSocket protocol (currently only graphql-ws is supported) */
199
206
  protocol?: 'graphql-ws';
200
207
  }
208
+ /**
209
+ * Security configuration for production environments
210
+ * All options auto-detect based on NODE_ENV when not explicitly set
211
+ */
212
+ interface SecurityConfig {
213
+ /**
214
+ * Enable GraphQL introspection queries
215
+ * @default true in development, false in production
216
+ */
217
+ introspection?: boolean;
218
+ /**
219
+ * Enable GraphQL playground/sandbox UI
220
+ * @default true in development, false in production
221
+ */
222
+ playground?: boolean;
223
+ /**
224
+ * Mask internal error details in responses
225
+ * When enabled, internal errors show "Internal server error" instead of actual message
226
+ * @default false in development, true in production
227
+ */
228
+ maskErrors?: boolean;
229
+ /**
230
+ * Disable "Did you mean X?" field suggestions in error messages
231
+ * Prevents attackers from discovering field names via brute force
232
+ * @default false in development, true in production
233
+ */
234
+ disableSuggestions?: boolean;
235
+ }
201
236
  interface NitroGraphQLOptions {
202
237
  framework: 'graphql-yoga' | 'apollo-server';
203
238
  endpoint?: {
@@ -256,6 +291,11 @@ interface NitroGraphQLOptions {
256
291
  * Customize base directories for file generation
257
292
  */
258
293
  paths?: PathsConfig;
294
+ /**
295
+ * Security configuration for production environments
296
+ * Auto-detects NODE_ENV and applies secure defaults in production
297
+ */
298
+ security?: SecurityConfig;
259
299
  }
260
300
  //#endregion
261
- export { ClientUtilsConfig, CodegenClientConfig, CodegenServerConfig, ExternalGraphQLService, ExternalServicePaths, FederationConfig, FileGenerationConfig, GenImport, GenericSdkConfig, NitroGraphQLOptions, PathsConfig, ScaffoldConfig, SdkConfig, SubscriptionsConfig, TypesConfig };
301
+ export { ClientUtilsConfig, CodegenClientConfig, CodegenServerConfig, ExternalGraphQLService, ExternalServicePaths, FederationConfig, FileGenerationConfig, GenImport, GenericSdkConfig, NitroGraphQLOptions, PathsConfig, ScaffoldConfig, SdkConfig, SecurityConfig, SubscriptionsConfig, TypesConfig };
@@ -7,9 +7,10 @@ import { printSchemaWithDirectives } from "@graphql-tools/utils";
7
7
  import { createHash } from "node:crypto";
8
8
  import { codegen } from "@graphql-codegen/core";
9
9
  import { preset } from "@graphql-codegen/import-types-preset";
10
- import { plugin } from "@graphql-codegen/typescript";
11
- import { plugin as plugin$1 } from "@graphql-codegen/typescript-generic-sdk";
12
- import { plugin as plugin$2 } from "@graphql-codegen/typescript-operations";
10
+ import { plugin } from "@graphql-codegen/typed-document-node";
11
+ import { plugin as plugin$1 } from "@graphql-codegen/typescript";
12
+ import { plugin as plugin$2 } from "@graphql-codegen/typescript-generic-sdk";
13
+ import { plugin as plugin$3 } from "@graphql-codegen/typescript-operations";
13
14
  import { GraphQLFileLoader } from "@graphql-tools/graphql-file-loader";
14
15
  import { loadDocuments, loadSchemaSync } from "@graphql-tools/load";
15
16
  import { UrlLoader } from "@graphql-tools/url-loader";
@@ -207,7 +208,7 @@ async function generateClientTypes(schema, docs, config = {}, sdkConfig = {}, ou
207
208
  plugins: [{ pluginContent: {} }, { typescript: {} }],
208
209
  pluginMap: {
209
210
  pluginContent: { plugin: pluginContent },
210
- typescript: { plugin }
211
+ typescript: { plugin: plugin$1 }
211
212
  }
212
213
  }),
213
214
  sdk: `// THIS FILE IS GENERATED, DO NOT EDIT!
@@ -236,21 +237,28 @@ export function getSdk(requester: Requester): Sdk {
236
237
  }
237
238
  `
238
239
  };
240
+ const enableTypedDocumentNode = config.typedDocumentNode === true;
241
+ const plugins = [
242
+ { pluginContent: {} },
243
+ { typescript: {} },
244
+ { typescriptOperations: {} }
245
+ ];
246
+ const pluginMap = {
247
+ pluginContent: { plugin: pluginContent },
248
+ typescript: { plugin: plugin$1 },
249
+ typescriptOperations: { plugin: plugin$3 }
250
+ };
251
+ if (enableTypedDocumentNode) {
252
+ plugins.push({ typedDocumentNode: {} });
253
+ pluginMap.typedDocumentNode = { plugin };
254
+ }
239
255
  const output = await codegen({
240
256
  filename: outputPath || "client-types.generated.ts",
241
257
  schema: parse(printSchemaWithDirectives(schema)),
242
258
  documents: [...docs],
243
259
  config: mergedConfig,
244
- plugins: [
245
- { pluginContent: {} },
246
- { typescript: {} },
247
- { typescriptOperations: {} }
248
- ],
249
- pluginMap: {
250
- pluginContent: { plugin: pluginContent },
251
- typescript: { plugin },
252
- typescriptOperations: { plugin: plugin$2 }
253
- }
260
+ plugins,
261
+ pluginMap
254
262
  });
255
263
  const typesPath = virtualTypesPath || (serviceName ? `#graphql/client/${serviceName}` : "#graphql/client");
256
264
  const sdkOutput = await preset.buildGeneratesSection({
@@ -262,7 +270,7 @@ export function getSdk(requester: Requester): Sdk {
262
270
  plugins: [{ pluginContent: {} }, { typescriptGenericSdk: {} }],
263
271
  pluginMap: {
264
272
  pluginContent: { plugin: pluginContent },
265
- typescriptGenericSdk: { plugin: plugin$1 }
273
+ typescriptGenericSdk: { plugin: plugin$2 }
266
274
  }
267
275
  });
268
276
  const sdkContent = (await Promise.all(sdkOutput.map(async (config$1) => {
@@ -380,8 +388,6 @@ export interface UseSubscriptionOptions<T> {
380
388
  onStateChange?: (state: ConnectionState) => void
381
389
  /** Use existing session for multiplexing (pass result from useSubscriptionSession) */
382
390
  session?: UseSubscriptionSessionReturn
383
- /** Use SSE transport instead of WebSocket (shorthand for transport: 'sse') */
384
- sse?: boolean
385
391
  /** Transport type: 'websocket' (default), 'sse', or 'auto' (WS first, SSE fallback) */
386
392
  transport?: SubscriptionTransport
387
393
  }
@@ -565,7 +571,6 @@ function createUseSubscription<TData, TVariables = undefined>(
565
571
 
566
572
  // Resolve transport options
567
573
  const transportOptions: TransportOptions = {
568
- sse: options.sse,
569
574
  transport: options.transport,
570
575
  }
571
576
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nitro-graphql",
3
3
  "type": "module",
4
- "version": "1.7.0-beta.4",
4
+ "version": "1.7.0",
5
5
  "description": "GraphQL integration for Nitro",
6
6
  "license": "MIT",
7
7
  "repository": {
@@ -55,10 +55,6 @@
55
55
  "./nuxt": {
56
56
  "types": "./dist/ecosystem/nuxt.d.mts",
57
57
  "import": "./dist/ecosystem/nuxt.mjs"
58
- },
59
- "./subscribe": {
60
- "types": "./dist/subscribe/index.d.mts",
61
- "import": "./dist/subscribe/index.mjs"
62
58
  }
63
59
  },
64
60
  "module": "./dist/index.mjs",
@@ -89,10 +85,11 @@
89
85
  "@apollo/subgraph": "^2.12.2",
90
86
  "@graphql-codegen/core": "^5.0.0",
91
87
  "@graphql-codegen/import-types-preset": "^3.0.1",
92
- "@graphql-codegen/typescript": "^5.0.6",
88
+ "@graphql-codegen/typed-document-node": "^6.1.5",
89
+ "@graphql-codegen/typescript": "^5.0.7",
93
90
  "@graphql-codegen/typescript-generic-sdk": "^4.0.2",
94
- "@graphql-codegen/typescript-operations": "^5.0.6",
95
- "@graphql-codegen/typescript-resolvers": "^5.1.4",
91
+ "@graphql-codegen/typescript-operations": "^5.0.7",
92
+ "@graphql-codegen/typescript-resolvers": "^5.1.5",
96
93
  "@graphql-tools/graphql-file-loader": "^8.1.8",
97
94
  "@graphql-tools/load": "^8.1.7",
98
95
  "@graphql-tools/load-files": "^7.0.1",
@@ -107,24 +104,24 @@
107
104
  "graphql-scalars": "^1.25.0",
108
105
  "knitwork": "^1.3.0",
109
106
  "ohash": "^2.0.11",
110
- "oxc-parser": "^0.102.0",
107
+ "oxc-parser": "^0.104.0",
111
108
  "pathe": "^2.0.3",
112
109
  "tinyglobby": "^0.2.15"
113
110
  },
114
111
  "devDependencies": {
115
- "@antfu/eslint-config": "^6.6.1",
112
+ "@antfu/eslint-config": "^6.7.2",
116
113
  "@nuxt/kit": "^4.2.2",
117
114
  "@nuxt/schema": "^4.2.2",
118
- "@types/node": "^24.10.3",
115
+ "@types/node": "^25.0.3",
119
116
  "bumpp": "^10.3.2",
120
117
  "changelogen": "^0.6.2",
121
118
  "crossws": "0.3.5",
122
- "eslint": "^9.39.1",
119
+ "eslint": "^9.39.2",
123
120
  "graphql": "16.11.0",
124
- "graphql-yoga": "^5.17.1",
121
+ "graphql-yoga": "^5.18.0",
125
122
  "h3": "1.15.3",
126
123
  "nitropack": "^2.12.9",
127
- "tsdown": "^0.17.2",
124
+ "tsdown": "^0.18.2",
128
125
  "typescript": "^5.9.3",
129
126
  "vitepress-plugin-llms": "^1.9.3"
130
127
  },
@@ -143,7 +140,6 @@
143
140
  "docs:build": "cd .docs && pnpm install && pnpm build",
144
141
  "docs:preview": "cd .docs && pnpm preview",
145
142
  "lint": "eslint .",
146
- "lint:fix": "eslint . --fix",
147
- "typecheck": "tsc --noEmit"
143
+ "lint:fix": "eslint . --fix"
148
144
  }
149
145
  }