@lewebsimple/nuxt-graphql 0.2.2 → 0.3.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.
Files changed (63) hide show
  1. package/README.md +361 -55
  2. package/dist/module.d.mts +33 -21
  3. package/dist/module.json +1 -1
  4. package/dist/module.mjs +337 -373
  5. package/dist/runtime/app/composables/useGraphQLCache.client.d.ts +10 -0
  6. package/dist/runtime/app/composables/useGraphQLCache.client.js +41 -0
  7. package/dist/runtime/app/composables/useGraphQLMutation.d.ts +17 -8
  8. package/dist/runtime/app/composables/useGraphQLMutation.js +10 -9
  9. package/dist/runtime/app/composables/useGraphQLQuery.d.ts +5 -12
  10. package/dist/runtime/app/composables/useGraphQLQuery.js +74 -28
  11. package/dist/runtime/app/composables/useGraphQLSubscription.d.ts +5 -6
  12. package/dist/runtime/app/composables/useGraphQLSubscription.js +13 -12
  13. package/dist/runtime/app/lib/graphql-cache.d.ts +7 -0
  14. package/dist/runtime/app/lib/graphql-cache.js +24 -0
  15. package/dist/runtime/app/lib/persisted.d.ts +4 -0
  16. package/dist/runtime/app/lib/persisted.js +70 -0
  17. package/dist/runtime/app/plugins/graphql-request.d.ts +7 -0
  18. package/dist/runtime/app/plugins/graphql-request.js +21 -0
  19. package/dist/runtime/app/plugins/graphql-sse.client.d.ts +7 -0
  20. package/dist/runtime/app/plugins/graphql-sse.client.js +15 -0
  21. package/dist/runtime/app/types/nuxt-graphql.d.ts +37 -0
  22. package/dist/runtime/server/api/yoga-handler.js +42 -0
  23. package/dist/runtime/server/lib/define-graphql-context.d.ts +5 -0
  24. package/dist/runtime/server/lib/define-graphql-context.js +4 -0
  25. package/dist/runtime/server/lib/define-remote-exec-middleware.d.ts +30 -0
  26. package/dist/runtime/server/lib/define-remote-exec-middleware.js +3 -0
  27. package/dist/runtime/server/lib/define-yoga-middleware.d.ts +21 -0
  28. package/dist/runtime/server/lib/define-yoga-middleware.js +3 -0
  29. package/dist/runtime/server/lib/execute-server-graphql.d.ts +7 -0
  30. package/dist/runtime/server/lib/execute-server-graphql.js +34 -0
  31. package/dist/runtime/server/lib/remote-executor.d.ts +35 -0
  32. package/dist/runtime/server/lib/remote-executor.js +64 -0
  33. package/dist/runtime/server/tsconfig.json +1 -1
  34. package/dist/runtime/server/utils/useServerGraphQLMutation.d.ts +8 -14
  35. package/dist/runtime/server/utils/useServerGraphQLMutation.js +8 -11
  36. package/dist/runtime/server/utils/useServerGraphQLQuery.d.ts +2 -10
  37. package/dist/runtime/server/utils/useServerGraphQLQuery.js +3 -4
  38. package/dist/runtime/shared/lib/graphql-error.d.ts +17 -0
  39. package/dist/runtime/shared/lib/graphql-error.js +28 -0
  40. package/dist/runtime/shared/lib/headers.d.ts +3 -0
  41. package/dist/runtime/shared/lib/headers.js +39 -0
  42. package/dist/types.d.mts +13 -1
  43. package/package.json +10 -14
  44. package/dist/runtime/app/composables/useGraphQLCache.d.ts +0 -10
  45. package/dist/runtime/app/composables/useGraphQLCache.js +0 -15
  46. package/dist/runtime/app/plugins/graphql.d.ts +0 -31
  47. package/dist/runtime/app/plugins/graphql.js +0 -42
  48. package/dist/runtime/app/utils/graphql-cache.d.ts +0 -36
  49. package/dist/runtime/app/utils/graphql-cache.js +0 -65
  50. package/dist/runtime/app/utils/graphql-error.d.ts +0 -12
  51. package/dist/runtime/app/utils/graphql-error.js +0 -24
  52. package/dist/runtime/server/api/graphql-handler.js +0 -15
  53. package/dist/runtime/server/lib/constants.d.ts +0 -1
  54. package/dist/runtime/server/lib/constants.js +0 -1
  55. package/dist/runtime/server/lib/create-yoga.d.ts +0 -1
  56. package/dist/runtime/server/lib/create-yoga.js +0 -17
  57. package/dist/runtime/server/lib/default-context.d.ts +0 -7
  58. package/dist/runtime/server/lib/default-context.js +0 -1
  59. package/dist/runtime/server/utils/graphql-client.d.ts +0 -14
  60. package/dist/runtime/server/utils/graphql-client.js +0 -14
  61. package/dist/runtime/server/utils/remote-middleware.d.ts +0 -18
  62. package/dist/runtime/server/utils/remote-middleware.js +0 -0
  63. /package/dist/runtime/server/api/{graphql-handler.d.ts → yoga-handler.d.ts} +0 -0
package/README.md CHANGED
@@ -5,23 +5,23 @@
5
5
  [![License][license-src]][license-href]
6
6
  [![Nuxt][nuxt-src]][nuxt-href]
7
7
 
8
- Opinionated Nuxt module that ships a stitched GraphQL Yoga server, typed GraphQL Codegen, and client/server composables powered by graphql-request and graphql-sse.
8
+ Opinionated Nuxt module that wires a typed GraphQL server + client into your app.
9
+
10
+ [✨  Release Notes](/CHANGELOG.md)
9
11
 
10
- - ✨ [Release Notes](/CHANGELOG.md)
11
- - 🏀 [Online playground](https://stackblitz.com/github/lewebsimple/nuxt-graphql?file=playground%2Fapp.vue)
12
12
 
13
13
  ## Features
14
14
 
15
- - 🧘‍♂️ GraphQL Yoga handler at `/api/graphql` with GraphiQL in development.
16
- - 🪡 Schema stitching: mix local schemas and remote endpoints (with per-source headers). Stitched SDL is emitted to `server/graphql/schema.graphql` (configurable).
17
- - 🚦 Remote middleware hooks: per-remote `onRequest` / `onResponse` callbacks to tweak headers, log responses, or short-circuit requests before forwarding.
18
- - 🪄 Code generation: scans named operations in `**/*.gql` (across Nuxt layers), generates typed documents, operations, registry (`#graphql/registry`), and optional Zod validation.
19
- - 🧩 Typed composables: `useGraphQLQuery`, `useGraphQLMutation`, `useGraphQLSubscription` consume registry names (e.g. `useGraphQLQuery("Hello")`). Server equivalents mirror the API for Nitro handlers.
20
- - 🚀 Caching and dedupe: in-memory or localStorage TTL cache, in-flight request deduplication, and refresh callbacks driven by runtime config.
21
- - 📡 SSE subscriptions: client-only via graphql-sse, using the same registry documents.
22
- - 🛡️SSR-friendly clients: forward `cookie` and `authorization` headers automatically on the server.
15
+ - 🧘 **GraphQL Yoga** server at `/api/graphql` (**GraphiQL** in dev) + **SSE subscriptions**
16
+ - 🪡 **Stitched schema** from local and/or remote schemas (remote introspection at build time)
17
+ - 🪄 Code generation from `.gql` documents **typed documents nodes** + **Zod** input schemas output
18
+ - 🧠 **Type-safe GraphQL helpers** for **queries, mutations, and subscriptions**, driven by **operation names** and shared across **client + server routes**
19
+ - 🧊 **SSR-friendly** by default: request header/cookie forwarding + no-HTTP server execution helpers
20
+ - 🚀 **Query caching** for `useGraphQLQuery` (cache policies + optional persistence in localStorage)
21
+ - 🪝 **Optional hooks**: Yoga middleware + per-remote executor middleware + client error hook (`graphql:error`)
22
+
23
23
 
24
- ## Quick start
24
+ ## Getting started
25
25
 
26
26
  Install the module to your Nuxt application with one command:
27
27
 
@@ -29,85 +29,391 @@ Install the module to your Nuxt application with one command:
29
29
  pnpx nuxi module add @lewebsimple/nuxt-graphql
30
30
  ```
31
31
 
32
- Configure at least one schema (local or remote) and optionnally your context (path to your context factory). Example with a local schema and remote stitched source:
32
+
33
+ ### Configuration
34
+
35
+ Declare your schemas, context, documents glob and any optional middleware in `nuxt.config.ts`:
33
36
 
34
37
  ```ts
35
- // nuxt.config.ts
36
38
  export default defineNuxtConfig({
37
39
  modules: ["@lewebsimple/nuxt-graphql"],
38
40
  graphql: {
39
- // Optional: path to your GraphQL context factory
40
- // Defaults to src/runtime/server/lib/default-context.ts if omitted
41
- context: "server/graphql/context.ts",
41
+ // Schemas to stitch together (local and/or remote)
42
42
  schemas: {
43
- local: { type: "local", path: "server/graphql/schema.ts" },
43
+ local: {
44
+ type: "local",
45
+ path: "server/graphql/schema.ts",
46
+ },
47
+ // Remote schema example
44
48
  swapi: {
45
49
  type: "remote",
46
- url: "https://swapi-graphql.netlify.app/.netlify/functions/index",
50
+ url: "https://swapi-graphql.netlify.app/graphql",
51
+ // Optional: static headers for this remote
52
+ headers: {
53
+ "X-Static-Header": "static-header-value",
54
+ },
55
+ // Optional: per-remote execution middleware (onRequest / onResponse / onError hooks)
47
56
  middleware: "server/graphql/swapi-middleware.ts",
48
57
  },
49
58
  },
50
- codegen: {
51
- documents: "**/*.gql", // only named operations allowed
52
- saveSchema: "server/graphql/schema.graphql",
59
+
60
+ // Optional: custom GraphQL context (defaults to {})
61
+ context: "server/graphql/context.ts",
62
+
63
+ // Optional: documents glob (defaults to **/*.gql)
64
+ documents: "**/*.gql",
65
+
66
+ // Optional: Yoga middleware (onRequest / onResponse hooks)
67
+ middleware: "server/graphql/yoga-middleware.ts",
68
+
69
+ // Optional: query caching (client-side only)
70
+ // - In-memory cache uses Nuxt `useAsyncData`/`useNuxtData`
71
+ // - Persistence in localStorage is enabled when `ttl` is set
72
+ // - Version / prefix allow cache invalidation accross deployments
73
+ cache: {
74
+ cachePolicy: "cache-first", // "no-cache" | "cache-first" | "network-first" | "swr"
75
+ cacheVersion: "1",
76
+ keyPrefix: "gql",
77
+ // Persist cache entries in localStorage with TTL in seconds
78
+ // - 0 = never expires
79
+ // - undefined = persistence disabled
80
+ ttl: 60,
81
+ },
82
+
83
+ // Optional: save path for the generated stitched SDL (defaults to .nuxt/graphql/schema.graphql)
84
+ sdl: "server/graphql/schema.graphql",
85
+ },
86
+ });
87
+ ```
88
+
89
+
90
+ ### Define your schema(s) (local and/or remote)
91
+
92
+ **Local schemas** must be located inside `server/` and export an executable `GraphQLSchema` using the tool of your choice (graphql-yoga, Pothos, etc).
93
+
94
+ ⚠️ Using auto-imported utilities or importing from aliases might break code generation.
95
+
96
+ For the example configuration above, create `server/graphql/schema.ts`:
97
+
98
+ ```ts
99
+ import { createSchema } from "graphql-yoga";
100
+ import type { GraphQLContext } from "#graphql/context";
101
+
102
+ export const schema = createSchema<GraphQLContext>({
103
+ typeDefs: /* GraphQL */ `
104
+ type Query {
105
+ hello: String!
106
+ }
107
+ type Mutation {
108
+ ping(message: String!): String!
109
+ }
110
+ type Subscription {
111
+ time: String!
112
+ }
113
+ `,
114
+ resolvers: {
115
+ Query: {
116
+ hello: () => "Hello from Nuxt GraphQL!",
117
+ },
118
+ Mutation: {
119
+ ping: (_parent, args) => `pong: ${args.message}`,
53
120
  },
54
- client: {
55
- cache: { enabled: true, ttl: 60_000, storage: "memory" },
56
- headers: {},
121
+ Subscription: {
122
+ time: {
123
+ subscribe: async function* () {
124
+ while (true) {
125
+ yield { time: new Date().toISOString() };
126
+ await new Promise((r) => setTimeout(r, 1000));
127
+ }
128
+ },
129
+ },
57
130
  },
58
131
  },
59
132
  });
60
133
  ```
61
134
 
62
- Define context (optional) in `server/graphql/context.ts`:
135
+ **Remote schemas** are introspected at build time from the required endpoint URL. Each remote can be configured with optional static headers and remote execution middleware (see configuration above).
136
+
137
+
138
+ ### Define a type-safe GraphQL context (optional)
139
+
140
+ The GraphQL context can be user-defined with the provided `defineGraphQLContext` helper. This ensures proper server-side typing by inferring the type from the return value of the context creation function. The `GraphQLContext` type can be imported from the `#graphql/context` server alias.
141
+
142
+ For example, providing the user from the `nuxt-auth-utils` session with the configuration above, create `server/graphql/context.ts`:
63
143
 
64
144
  ```ts
65
- import type { H3Event } from "h3";
145
+ import { defineGraphQLContext } from "@lewebsimple/nuxt-graphql";
146
+ import { getUserSession } from "nuxt-auth-utils";
147
+
148
+ export default defineGraphQLContext(async (event) => {
149
+ const session = await getUserSession(event);
150
+ return {
151
+ user: session?.user ?? null,
152
+ };
153
+ });
154
+ ```
66
155
 
67
- export async function createContext(event: H3Event) {
68
- return { event, user: event.context.user };
156
+
157
+ ### Write GraphQL documents (`.gql`)
158
+
159
+ Write operations in `.gql` document files; operation names become registry keys like `useGraphQLQuery("HelloWorld")`.
160
+
161
+ ⚠️ Operation names are required and must be unique.
162
+
163
+ By default, the module scans `**/*.gql` and generates:
164
+
165
+ - Typed documents in `#graphql/typed-documents`
166
+ - Operation registry by name in `#graphql/registry` (used internally)
167
+ - Zod schemas in `#graphql/zod`
168
+ - A `graphql.config.json` at the project root (editor tooling)
169
+
170
+ Example document files (filenaming convention can vary):
171
+ ```graphql
172
+ # app/graphql/HelloWorld.query.gql
173
+ query HelloWorld {
174
+ hello
69
175
  }
70
176
  ```
71
177
 
72
- Write named operations in `.gql` files and use the auto-generated composables by operation name:
178
+ ```graphql
179
+ # app/graphql/Ping.mutation.gql
180
+ mutation Ping($message: String!) {
181
+ ping(message: $message)
182
+ }
183
+ ```
73
184
 
74
- ```ts
75
- const { data, pending, error } = useGraphQLQuery("Hello", { name: "world" });
76
- const { mutate } = useGraphQLMutation("Ping");
77
- const { data: time } = useGraphQLSubscription("Time");
185
+ ```graphql
186
+ # app/graphql/Time.subscription.gql
187
+ subscription Time {
188
+ time
189
+ }
78
190
  ```
79
191
 
80
192
  That's it! You can now use Nuxt GraphQL in your Nuxt app ✨
81
193
 
82
- Yoga GraphiQL is available at `http://localhost:3000/api/graphql` by default.
194
+ ### Fragments
195
+
196
+ Fragments are fully supported and are the recommended way to share selection sets across operations.
197
+
198
+ - Fragment names must be unique across all `.gql` files (duplicates throw during generation).
199
+ - Fragments are generated into `#graphql/typed-documents` by GraphQL Codegen:
200
+ - a TypeScript type like `TheFilmFragment`
201
+ - and a document constant like `TheFilmFragmentDoc`
202
+ - Fragments are **not executable by themselves** (GraphQL requires an operation), and they are **not part of the `#graphql/registry`**. The auto-imported composables and server utilities only accept operation names (`query` / `mutation` / `subscription`).
83
203
 
84
- Optional: add a remote middleware at `server/graphql/swapi-middleware.ts` to adjust headers or log activity for stitched sources:
204
+ Example with a fragment:
205
+
206
+ ```graphql
207
+ # app/graphql/SwapiFilms.query.gql
208
+ fragment TheFilm on Film {
209
+ title
210
+ releaseDate
211
+ }
212
+
213
+ query SwapiFilms {
214
+ allFilms {
215
+ films {
216
+ ...TheFilm
217
+ }
218
+ }
219
+ }
220
+ ```
221
+
222
+ From TypeScript, you can also use fragment types explicitly when you need them:
85
223
 
86
224
  ```ts
87
- export default {
88
- async onRequest({ fetchOptions }) {
89
- return {
90
- ...fetchOptions,
91
- headers: {
92
- ...fetchOptions.headers,
93
- "x-swapi-api-key": process.env.SWAPI_TOKEN ?? "",
94
- },
95
- };
225
+ import type { TheFilmFragment } from "#graphql/typed-documents";
226
+ ```
227
+
228
+
229
+ ### Use the auto-imported composables
230
+
231
+ The auto-imported operation composables allow executing **queries**, **mutations** and **subscriptions** based on their registry name with full type-safety (variables and return value).
232
+
233
+ ```ts
234
+ // Query (useAsyncData under the hood)
235
+ const { data, pending, error, refresh } = await useGraphQLQuery(
236
+ "HelloWorld", // Registry name, i.e. "query HelloWorld { hello }"
237
+ undefined, // Type-safe variables
238
+ {
239
+ // Custom request headers
240
+ headers: {
241
+ "X-Request-Header": "request-header-value"
242
+ },
243
+ // Additional useAsyncData options
244
+ // lazy: true,
245
+ },
246
+ );
247
+
248
+ // Mutation
249
+ const { mutate } = useGraphQLMutation("Ping", {
250
+ // Custom request headers
251
+ headers: {
252
+ "X-Request-Header": "request-header-value"
253
+ },
254
+ });
255
+ const { data, pending, error } = await mutate({ message: "Hello from ping mutation!" }, {
256
+ // Each `mutate` call may send additional headers
257
+ headers: {
258
+ "X-Mutate-Header": "mutate-header-value",
259
+ },
260
+ });
261
+
262
+ // Subscription (client-only, SSE)
263
+ const { data, error, start, stop } = useGraphQLSubscription("Time");
264
+ // data and error are shallowRef
265
+ ```
266
+
267
+ ### Use the auto-imported server-side utilities
268
+
269
+ In server routes, you can execute **queries** and **mutations** directly against the stitched schema (no HTTP roundtrip):
270
+
271
+ ```ts
272
+ export default defineEventHandler(async (event) => {
273
+ // Server-side GraphQL query example
274
+ const { hello } = await useServerGraphQLQuery(event, "HelloWorld", undefined, {
275
+ headers: {
276
+ "X-Server-Header": "server-header-value",
277
+ },
278
+ });
279
+
280
+ // Server-side GraphQL mutation example
281
+ const { mutate } = useServerGraphQLMutation(event, "Ping", {
282
+ headers: {
283
+ "X-Server-Header": "server-header-value",
284
+ },
285
+ });
286
+ const { ping } = await mutate({ message: hello }, {
287
+ headers: {
288
+ "X-Mutation-Header": "mutation-header-value",
289
+ },
290
+ });
291
+
292
+ return { ping };
293
+ });
294
+ ```
295
+
296
+ The function signature is almost identical to the auto-imported composables, except you need to pass `event` as the first argument (and of course queries don't rely on `useAsyncData`).
297
+
298
+ Also, resulting data is returned directly from `useServerGraphQLQuery` and `mutate` (throws an error on failure).
299
+
300
+
301
+ ### Query caching (client-side only)
302
+
303
+ `useGraphQLQuery` can cache **query results** based on the global cache configuration (see configuration above) and per-query overrides (see below).
304
+
305
+ - In-flight requests are **deduplicated** (same operation + variables → one network call).
306
+ - **In-memory** cache uses Nuxt `useAsyncData`/`useNuxtData`.
307
+ - **Persisted** cache stores entries in `localStorage` for `ttl` seconds (`0` = never expires).
308
+
309
+ #### Cache policies
310
+
311
+ - `"no-cache"`: always fetches from the network (still dedupes in-flight).
312
+ - `"cache-first"`: returns cached value when present, otherwise fetches.
313
+ - `"network-first"`: tries the network first, falls back to cached value on error.
314
+ - `"swr"` (stale-while-revalidate): returns cached value immediately (when present) and refreshes in the background.
315
+
316
+ #### Per-query overrides
317
+
318
+ Caching configuration can be overridden per-query:
319
+
320
+ ```ts
321
+ const { data } = await useGraphQLQuery("HelloWorld", undefined, {
322
+ cache: {
323
+ cachePolicy: "network-first",
324
+ ttl: undefined, // disable persistence for this call
96
325
  },
97
- async onResponse({ operationName }) {
98
- console.log(`[SWAPI] completed ${operationName ?? "unknown"}`);
326
+ });
327
+ ```
328
+
329
+ #### Manual invalidation
330
+
331
+ On the client, `useGraphQLCache()` is used to invalidate in-memory and/or persisted entries:
332
+
333
+ ```ts
334
+ const { invalidateByKey, invalidateByOperation, invalidateAll } = useGraphQLCache();
335
+
336
+ // Invalidate a single entry (operation + variables)
337
+ await invalidateByKey("HelloWorld", {});
338
+
339
+ // Invalidate all entries for an operation (all variables)
340
+ await invalidateByOperation("HelloWorld");
341
+
342
+ // Optional: target a specific layer
343
+ await invalidateByOperation("HelloWorld", { layer: "persisted" });
344
+
345
+ // Invalidate all entries
346
+ await invalidateAll();
347
+ ```
348
+
349
+
350
+ ### Yoga middleware (optional)
351
+
352
+ You can define custom logic around the Yoga event handler by using the provided `defineYogaMiddleware` helper with the following hooks:
353
+ - `onRequest` runs before Yoga handles the request;
354
+ - `onResponse` runs after and can replace the outgoing `Response` via `setResponse`.
355
+
356
+ For the example configuration above, create `server/graphql/yoga-middleware.ts`:
357
+
358
+ ```ts
359
+ import { defineYogaMiddleware } from "@lewebsimple/nuxt-graphql";
360
+ import { getUserSession } from "nuxt-auth-utils";
361
+
362
+ export default defineYogaMiddleware({
363
+ async onRequest({ event, context, request }) {
364
+ const session = await getUserSession(event);
365
+ if (!session?.user) {
366
+ throw createError({ statusCode: 401, message: "Unauthorized" });
367
+ }
99
368
  },
100
- } satisfies RemoteMiddleware
369
+ async onResponse({ event, context, request, response, setResponse }) {
370
+ setHeader(event, "X-Custom-Yoga-Middleware-Response-Header", "my-custom-value");
371
+ },
372
+ });
101
373
  ```
102
374
 
103
- Both hooks are optional; return a new `RequestInit` from `onRequest` to override the outgoing fetch, or use `onResponse` for side-effects such as metrics and logging.
375
+ ### Remote executor middleware (optional, per remote)
376
+
377
+ You can define custom logic around the remote executor (from `@graphql-tools/utils`) for each one of your remote schema by using the provided `defineRemoteExecMiddleware` helper with the following hooks:
378
+ - `onRequest` runs before the fetch (headers are mutable);
379
+ - `onResponse` runs after an OK response before JSON parsing (cloned response);
380
+ - `onError` runs for non-2xx responses, GraphQL errors returned in the payload, JSON parse failures, or network errors (the `response` can be `undefined` in that last case).
381
+
382
+ ⚠️ Remote executor middlewares don't have access to the H3 `event` handled by Yoga since they are executed in the context of the delegated subschema resolution.
104
383
 
105
- ## Development notes
384
+ For the example configuration above, create `server/graphql/swapi-middleware.ts`:
385
+
386
+ ```ts
387
+ import { defineRemoteExecMiddleware } from "@lewebsimple/nuxt-graphql";
388
+
389
+ export default defineRemoteExecMiddleware({
390
+ onRequest({ remoteName, operationName, context, fetchOptions }) {
391
+ console.log(`SWAPI Request Middleware [${remoteName} - ${operationName}]`);
392
+ fetchOptions.headers.set("X-Remote-Exec-Request-Header", "custom-value");
393
+ },
394
+ onResponse({ remoteName, operationName, context, response }) {
395
+ console.log(`SWAPI Response Middleware [${remoteName} - ${operationName}]`);
396
+ },
397
+ onError({ remoteName, operationName, error }) {
398
+ console.error(`SWAPI Error Middleware [${remoteName} - ${operationName}]:`, error);
399
+ },
400
+ });
401
+ ```
402
+
403
+ ### Client error hook (optional)
404
+
405
+ Handle normalized GraphQL errors globally on the client (toast, logging, etc.).
406
+
407
+ The client calls the `graphql:error` Nuxt hook when a `graphql-request` response contains errors:
408
+
409
+ ```ts
410
+ export default defineNuxtPlugin((nuxtApp) => {
411
+ nuxtApp.hook("graphql:error", (error) => {
412
+ console.error("GraphQL error", error);
413
+ });
414
+ });
415
+ ```
106
416
 
107
- - Generated artifacts live under `.nuxt/graphql` and `.graphqlrc`; they are rewritten only when contents change.
108
- - Operations must be **named and unique**; duplicates or unnamed operations fail codegen.
109
- - SSE subscriptions are client-only; do not call `$graphqlSSE` on the server.
110
- - Cache defaults come from `runtimeConfig.public.graphql.cache`; pass `cache: false` to per-call options to bypass.
111
417
 
112
418
  ## Contribution
113
419
 
@@ -151,5 +457,5 @@ Both hooks are optional; return a new `RequestInit` from `onRequest` to override
151
457
  [license-src]: https://img.shields.io/npm/l/@lewebsimple/nuxt-graphql.svg?style=flat&colorA=020420&colorB=00DC82
152
458
  [license-href]: https://npmjs.com/package/@lewebsimple/nuxt-graphql
153
459
 
154
- [nuxt-src]: https://img.shields.io/badge/Nuxt-020420?logo=nuxt.js
460
+ [nuxt-src]: https://img.shields.io/badge/Nuxt-020420?logo=nuxt
155
461
  [nuxt-href]: https://nuxt.com
package/dist/module.d.mts CHANGED
@@ -1,35 +1,47 @@
1
1
  import * as _nuxt_schema from '@nuxt/schema';
2
- import { GraphQLCacheConfig } from '../dist/runtime/app/utils/graphql-cache.js';
2
+ export { defineGraphQLContext } from '../dist/runtime/server/lib/define-graphql-context.js';
3
+ export { defineRemoteExecMiddleware } from '../dist/runtime/server/lib/define-remote-exec-middleware.js';
4
+ export { defineYogaMiddleware } from '../dist/runtime/server/lib/define-yoga-middleware.js';
3
5
 
4
- type LocalSchema = {
6
+ /**
7
+ * Find multiple files across directories
8
+ *
9
+ * @param dirs Directories to search in
10
+ * @param pattern Glob pattern relative to each directory
11
+ * @returns Array of found file paths
12
+ */
13
+ type GlobPattern = string | string[];
14
+
15
+ type CachePolicy = "no-cache" | "cache-first" | "network-first" | "swr";
16
+ interface CacheConfig {
17
+ cachePolicy: CachePolicy;
18
+ cacheVersion: string;
19
+ keyPrefix: string;
20
+ ttl?: number;
21
+ }
22
+
23
+ type LocalSchemaDef = {
5
24
  type: "local";
6
25
  path: string;
7
26
  };
8
- type RemoteSchema = {
27
+ type RemoteSchemaDef = {
9
28
  type: "remote";
10
29
  url: string;
11
- headers?: Record<string, string>;
30
+ headers?: HeadersInit;
12
31
  middleware?: string;
13
32
  };
14
- type SchemaDefinition = LocalSchema | RemoteSchema;
33
+ type SchemaDef = LocalSchemaDef | RemoteSchemaDef;
15
34
 
16
- interface ModuleOptions {
35
+ interface NuxtGraphQLModuleOptions {
36
+ schemas: Record<string, SchemaDef>;
17
37
  context?: string;
18
- schemas: Record<string, SchemaDefinition>;
19
- codegen?: {
20
- documents?: string;
21
- saveSchema?: string;
22
- scalars?: Record<string, string | {
23
- input: string;
24
- output: string;
25
- }>;
26
- };
27
- client?: {
28
- cache?: Partial<GraphQLCacheConfig>;
29
- headers?: Record<string, string>;
30
- };
38
+ documents?: GlobPattern;
39
+ saveConfig?: string;
40
+ saveSdl?: string;
41
+ middleware?: string;
42
+ cache?: Partial<CacheConfig>;
31
43
  }
32
- declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
44
+ declare const _default: _nuxt_schema.NuxtModule<NuxtGraphQLModuleOptions, NuxtGraphQLModuleOptions, false>;
33
45
 
34
46
  export { _default as default };
35
- export type { ModuleOptions };
47
+ export type { NuxtGraphQLModuleOptions };
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lewebsimple/nuxt-graphql",
3
3
  "configKey": "graphql",
4
- "version": "0.2.2",
4
+ "version": "0.3.0",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "3.6.1"