@lewebsimple/nuxt-graphql 0.6.19 → 0.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.
Files changed (63) hide show
  1. package/README.md +61 -74
  2. package/dist/module.d.mts +31 -5
  3. package/dist/module.json +3 -3
  4. package/dist/module.mjs +442 -341
  5. package/dist/runtime/app/composables/useAsyncGraphQLQuery.d.ts +14 -10
  6. package/dist/runtime/app/composables/useAsyncGraphQLQuery.js +71 -80
  7. package/dist/runtime/app/composables/useGraphQLCache.client.d.ts +9 -14
  8. package/dist/runtime/app/composables/useGraphQLCache.client.js +40 -61
  9. package/dist/runtime/app/composables/useGraphQLLoadMore.d.ts +16 -9
  10. package/dist/runtime/app/composables/useGraphQLLoadMore.js +36 -40
  11. package/dist/runtime/app/composables/useGraphQLMutation.d.ts +29 -31
  12. package/dist/runtime/app/composables/useGraphQLMutation.js +17 -32
  13. package/dist/runtime/app/composables/useGraphQLQuery.d.ts +10 -3
  14. package/dist/runtime/app/composables/useGraphQLQuery.js +4 -14
  15. package/dist/runtime/app/composables/useGraphQLSubscription.client.d.ts +4 -5
  16. package/dist/runtime/app/composables/useGraphQLSubscription.client.js +7 -5
  17. package/dist/runtime/app/lib/cache-config.d.ts +18 -0
  18. package/dist/runtime/app/lib/cache-config.js +9 -0
  19. package/dist/runtime/app/lib/cache.d.ts +81 -49
  20. package/dist/runtime/app/lib/cache.js +65 -55
  21. package/dist/runtime/app/lib/persisted.d.ts +18 -12
  22. package/dist/runtime/app/lib/persisted.js +42 -45
  23. package/dist/runtime/app/plugins/graphql-sse.client.js +1 -2
  24. package/dist/runtime/app/plugins/graphql.d.ts +24 -0
  25. package/dist/runtime/app/plugins/graphql.js +16 -0
  26. package/dist/runtime/server/api/graphql.d.ts +6 -0
  27. package/dist/runtime/server/api/graphql.js +1 -1
  28. package/dist/runtime/server/{utils/defineGraphQLContext.d.ts → lib/context.d.ts} +10 -1
  29. package/dist/runtime/server/lib/remote-executor.d.ts +42 -19
  30. package/dist/runtime/server/lib/remote-executor.js +11 -13
  31. package/dist/runtime/server/lib/yoga.d.ts +0 -1
  32. package/dist/runtime/server/lib/yoga.js +1 -2
  33. package/dist/runtime/server/tsconfig.json +1 -1
  34. package/dist/runtime/server/utils/execute-schema.d.ts +11 -0
  35. package/dist/runtime/server/utils/execute-schema.js +24 -0
  36. package/dist/runtime/shared/lib/headers.d.ts +14 -2
  37. package/dist/runtime/shared/lib/headers.js +18 -1
  38. package/dist/runtime/shared/utils/error.d.ts +39 -0
  39. package/dist/runtime/shared/utils/error.js +67 -0
  40. package/dist/runtime/shared/utils/execute.d.ts +33 -0
  41. package/dist/runtime/shared/utils/execute.js +26 -0
  42. package/dist/runtime/shared/utils/registry.d.ts +72 -0
  43. package/dist/runtime/shared/utils/registry.js +37 -0
  44. package/package.json +48 -36
  45. package/dist/runtime/app/lib/in-flight.d.ts +0 -14
  46. package/dist/runtime/app/lib/in-flight.js +0 -19
  47. package/dist/runtime/app/plugins/execute-graphql.d.ts +0 -18
  48. package/dist/runtime/app/plugins/execute-graphql.js +0 -25
  49. package/dist/runtime/server/lib/execute-graphql-schema.d.ts +0 -3
  50. package/dist/runtime/server/lib/execute-graphql-schema.js +0 -22
  51. package/dist/runtime/server/utils/defineRemoteExecutorHooks.d.ts +0 -8
  52. package/dist/runtime/server/utils/defineRemoteExecutorHooks.js +0 -3
  53. package/dist/runtime/server/utils/useGraphQLOperation.d.ts +0 -16
  54. package/dist/runtime/server/utils/useGraphQLOperation.js +0 -12
  55. package/dist/runtime/shared/lib/error.d.ts +0 -42
  56. package/dist/runtime/shared/lib/error.js +0 -52
  57. package/dist/runtime/shared/lib/registry.d.ts +0 -12
  58. package/dist/runtime/shared/lib/registry.js +0 -8
  59. package/dist/runtime/shared/lib/types.d.ts +0 -30
  60. package/dist/runtime/shared/lib/types.js +0 -0
  61. package/dist/runtime/shared/utils/execute-graphql-http.d.ts +0 -7
  62. package/dist/runtime/shared/utils/execute-graphql-http.js +0 -31
  63. /package/dist/runtime/server/{utils/defineGraphQLContext.js → lib/context.js} +0 -0
package/README.md CHANGED
@@ -7,45 +7,46 @@
7
7
 
8
8
  Opinionated Nuxt module that wires a typed GraphQL server + client into your app.
9
9
 
10
- [ Release Notes](/CHANGELOG.md)
11
-
10
+ [Release Notes](/CHANGELOG.md)
12
11
 
13
12
  ## Features
14
13
 
15
14
  - 🧘 **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; subscriptions stripped)
17
- - 🪄 Code generation from `.gql` documents → **typed operation documents** + **registry**
18
- - 🧠 **Type-safe helpers** for **queries, mutations, and subscriptions**, shared across **client + server**
19
- - 🧊 **SSR-friendly** by default: request header forwarding + server-side schema execution helpers
15
+ - 🪡 **Combined schema** from local and/or remote schemas (remote introspection at build time; subscriptions stripped)
16
+ - 🪄 Code generation from `.gql` documents and source files → **validated schema operations and fragments**
17
+ - 🧠 **Type-safe helpers** for **queries, mutations, and subscriptions** in both **client + server**
18
+ - 🧊 **SSR-friendly** by default: request header forwarding + remote schema execution hooks
20
19
  - 🚀 **Client-side cache** for `useAsyncGraphQLQuery` (cache policies + optional persistence in localStorage)
21
- - 🧯 **Unified error model** via `GraphQLExecutionResult` and `NormalizedError`
22
-
20
+ - 🧯 **Unified error model** via `ExecuteGraphQLResult` and `NormalizedError`
23
21
 
24
22
  ## Getting started
25
23
 
26
- Install the module to your Nuxt application with one command:
24
+ Install the module and its dependencies in your project:
27
25
 
28
26
  ```bash
29
- pnpx nuxt module add @lewebsimple/nuxt-graphql
27
+ pnpm add @lewebsimple/nuxt-graphql zod
30
28
  ```
31
29
 
32
-
33
30
  ### Configuration
34
31
 
35
- Declare your schemas, context, documents glob and optional client cache in [nuxt.config.ts](nuxt.config.ts):
32
+ Add the module to your `nuxt.config.ts` and declare your schemas, context, documents glob and optional client cache:
36
33
 
37
34
  ```ts
38
35
  export default defineNuxtConfig({
39
36
  modules: ["@lewebsimple/nuxt-graphql"],
40
37
  graphql: {
38
+ // GraphQL server configuration
41
39
  server: {
40
+ // Optional: custom GraphQL context factories (defaults to empty context)
41
+ context: ["server/graphql/context.ts"],
42
+
42
43
  // Schemas to stitch together (local and/or remote)
43
- schema: {
44
+ schema: [
44
45
  // Local schema example
45
- local: { type: "local", path: "server/graphql/schema.ts" },
46
-
46
+ { type: "local", path: "server/graphql/schema.ts" },
47
+
47
48
  // Remote schema example
48
- swapi: {
49
+ {
49
50
  type: "remote",
50
51
  url: "https://swapi-graphql.netlify.app/graphql",
51
52
  // Optional: static headers for this remote
@@ -55,15 +56,13 @@ export default defineNuxtConfig({
55
56
  // Optional: per-remote execution hooks
56
57
  hooks: ["server/graphql/swapi-hooks.ts"],
57
58
  },
58
- },
59
-
60
- // Optional: custom GraphQL context factories (defaults to [])
61
- context: ["server/graphql/context.ts"],
59
+ ],
62
60
  },
63
61
 
62
+ // GraphQL client configuration
64
63
  client: {
65
- // Optional: documents glob (defaults to **/*.gql)
66
- documents: "**/*.gql",
64
+ // Optional: documents globs (defaults to **/*.gql)
65
+ documents: ["**/*.gql"],
67
66
 
68
67
  // Optional: headers forwarded from SSR to graphql-request (defaults to ["authorization", "cookie"])
69
68
  ssrForwardHeaders: ["authorization", "cookie"],
@@ -80,7 +79,7 @@ export default defineNuxtConfig({
80
79
  },
81
80
  },
82
81
 
83
- // Optional: save path for the stitched SDL (defaults to "server/graphql/schema.graphql")
82
+ // Optional: save path for the stitched SDL (defaults to ".nuxt/graphql/schema.graphql")
84
83
  saveSDL: "server/graphql/schema.graphql",
85
84
 
86
85
  // Optional: save path for the generated GraphQL config (defaults to "graphql.config.json")
@@ -89,7 +88,6 @@ export default defineNuxtConfig({
89
88
  });
90
89
  ```
91
90
 
92
-
93
91
  ### Define GraphQL schema (local and/or remote)
94
92
 
95
93
  **Local schemas** must live under `server/` and export a `GraphQLSchema` as `schema`.
@@ -135,8 +133,7 @@ export const schema = createSchema<GraphQLContext>({
135
133
 
136
134
  **Remote schemas** are introspected at build time from the endpoint URL and executed via an HTTP executor at runtime. Subscriptions are stripped from remote schemas.
137
135
 
138
- The final schema is stitched from the all of the defined local / remote schemas.
139
-
136
+ The final schema combines the all of the defined local / remote schemas.
140
137
 
141
138
  ### Define GraphQL context (optional)
142
139
 
@@ -155,10 +152,9 @@ export default defineGraphQLContext(async (event) => {
155
152
  });
156
153
  ```
157
154
 
158
-
159
155
  ### Write GraphQL documents (.gql)
160
156
 
161
- By default, the module scans `**/*.gql` files for **named operations** and **fragments** which are converted into **types** and **typed document nodes** in `#graphql/operations`. The operations are exposed by name in `#graphql/registry` to allow type-safe execution with the provided **composables** and **server utils**.
157
+ By default, the module scans `**/*.gql` files for **named operations** and **fragments** which are converted into **types** and **typed document nodes**. The operations are exposed by name in `#graphql/registry` to allow type-safe execution with the provided **composables** and **server utils**.
162
158
 
163
159
  ⚠️ Operation names are required and must be unique.
164
160
 
@@ -187,13 +183,12 @@ subscription Time {
187
183
 
188
184
  That's it! You can now use Nuxt GraphQL in your Nuxt app ✨
189
185
 
190
-
191
186
  ### Fragments
192
187
 
193
188
  Fragments are fully supported and are the recommended way to share selection sets across operations.
194
189
 
195
190
  - Fragment names must be unique across all `.gql` files (duplicates throw during generation).
196
- - Fragment types are re-exported from `#graphql/operations`.
191
+ - Fragment types are re-exported from `#graphql/types`.
197
192
  - Fragments are not executable by themselves and are not part of the registry.
198
193
 
199
194
  Example with a fragment:
@@ -217,30 +212,28 @@ query SwapiFilms {
217
212
  From TypeScript, you can also use fragment types explicitly when needed:
218
213
 
219
214
  ```ts
220
- import type { TheFilmFragment } from "#graphql/operations";
215
+ import type { TheFilmFragment } from "#graphql/types";
221
216
  ```
222
217
 
223
-
224
218
  ### Use the auto-imported composables
225
219
 
226
220
  The auto-imported composables allow executing queries, mutations, and subscriptions based on their registry name with full type-safety (variables and return value).
227
221
 
228
222
  ```ts
229
223
  // Cached query via useAsyncData
230
- const { data, pending, error, refresh } = await useAsyncGraphQLQuery("HelloWorld", undefined);
224
+ const { data, pending, error, refresh } = await useAsyncGraphQLQuery("HelloWorld", {});
231
225
 
232
226
  // Direct HTTP query (SafeResult)
233
- const { data: queryData, error: queryError } = await useGraphQLQuery("HelloWorld");
227
+ const { data: queryData, error: queryError } = await useGraphQLQuery("HelloWorld", {});
234
228
 
235
229
  // Mutation (SafeResult)
236
230
  const { mutate, pending: mutationPending } = useGraphQLMutation("Ping");
237
231
  const { data: mutationData, error: mutationError } = await mutate({ message: "Hello!" });
238
232
 
239
233
  // Subscription (client-only, SSE)
240
- const { data, error, start, stop } = useGraphQLSubscription("Time");
234
+ const { data, error, start, stop } = useGraphQLSubscription("Time", {});
241
235
  ```
242
236
 
243
-
244
237
  ### Use the auto-imported server utils
245
238
 
246
239
  In server routes, you can execute queries and mutations directly against the stitched schema (no HTTP roundtrip):
@@ -248,18 +241,13 @@ In server routes, you can execute queries and mutations directly against the sti
248
241
  ```ts
249
242
  export default defineEventHandler(async (event) => {
250
243
  // Server-side GraphQL query example
251
- const { data: queryData, error: queryError } = await useGraphQLOperation(event, "HelloWorld" );
252
-
253
- // Server-side GraphQL mutation example
254
- const { data: mutationData } = await useGraphQLOperation(event, "Ping", { message: queryData?.hello ?? "Pong" },
255
- );
244
+ const { data, error } = await executeSchemaOperation(event, "HelloWorld", {});
256
245
 
257
- return { queryData, mutationData, queryError };
246
+ return { data, error };
258
247
  });
259
248
  ```
260
249
 
261
- Server helpers return a `GraphQLExecutionResult` in the same format as some composables, i.e. `{ data: TResult, error: null } | { data: null, error: NormalizedError }`
262
-
250
+ Server helpers return a `ExecuteGraphQLResult` in the same format as some composables, i.e. `{ data: TResult, error: null } | { data: null, error: NormalizedError }`
263
251
 
264
252
  ### Query caching (client-side only)
265
253
 
@@ -279,12 +267,16 @@ Server helpers return a `GraphQLExecutionResult` in the same format as some comp
279
267
  #### Per-query overrides
280
268
 
281
269
  ```ts
282
- const { data } = await useAsyncGraphQLQuery("HelloWorld", undefined, {
283
- cache: {
284
- policy: "network-first",
285
- ttl: undefined, // disable persistence for this call
270
+ const { data } = await useAsyncGraphQLQuery(
271
+ "HelloWorld",
272
+ {},
273
+ {
274
+ cache: {
275
+ policy: "network-first",
276
+ ttl: undefined, // disable persistence for this call
277
+ },
286
278
  },
287
- });
279
+ );
288
280
  ```
289
281
 
290
282
  #### Cache manipulation
@@ -303,16 +295,16 @@ cache.write("AllFilms", {}, (current) => ({ ...current, films: [...current.films
303
295
 
304
296
  // Update cached query asynchronously (in-memory + persisted)
305
297
  await cache.update("AllFilms", {}, newValue);
306
- await cache.update("AllFilms", {}, (current) => ({ ...current, films: [...current.films, newFilm] }));
298
+ await cache.update("AllFilms", {}, (current) => ({
299
+ ...current,
300
+ films: [...current.films, newFilm],
301
+ }));
307
302
 
308
303
  // Invalidate cache entries
309
- await cache.invalidate("HelloWorld", {}); // Exact match (operation + variables)
310
- await cache.invalidate("HelloWorld"); // All entries for operation
311
- await cache.invalidate(); // All entries
304
+ await cache.invalidate("HelloWorld"); // All entries for operation
305
+ await cache.invalidate(); // All entries
312
306
  ```
313
307
 
314
- > **⚠️ Important:** Cache manipulation methods (`read`, `write`, `update`, `invalidate`) are incompatible with the `transform` option on `useAsyncGraphQLQuery`. If you need to use cache invalidation or manipulation, do not use the `transform` option. Instead, transform the data after retrieving it from the composable.
315
-
316
308
  #### Optimistic updates
317
309
 
318
310
  `useGraphQLMutation` supports optimistic updates via lifecycle hooks:
@@ -321,18 +313,18 @@ await cache.invalidate(); // All entries
321
313
  const { mutate } = useGraphQLMutation("AddFilm", {
322
314
  onMutate: async (variables) => {
323
315
  const cache = useGraphQLCache();
324
-
316
+
325
317
  // Snapshot current value for rollback
326
318
  const snapshot = cache.read("AllFilms", {});
327
-
319
+
328
320
  // Optimistically update cache
329
321
  await cache.update("AllFilms", {}, (current) => ({
330
- films: [...(current?.films ?? []), { id: 'temp', title: variables.title }]
322
+ films: [...(current?.films ?? []), { id: "temp", title: variables.title }],
331
323
  }));
332
-
324
+
333
325
  return { snapshot };
334
326
  },
335
-
327
+
336
328
  onError: (error, variables, context) => {
337
329
  const cache = useGraphQLCache();
338
330
  // Rollback on error (sync for instant UI update)
@@ -340,25 +332,24 @@ const { mutate } = useGraphQLMutation("AddFilm", {
340
332
  cache.write("AllFilms", {}, context.snapshot);
341
333
  }
342
334
  },
343
-
335
+
344
336
  onSuccess: (data, variables, context) => {
345
337
  // Replace optimistic temp ID with real ID from server
346
338
  const cache = useGraphQLCache();
347
339
  cache.update("AllFilms", {}, (current) => ({
348
- films: current?.films.map(f => f.id === 'temp' ? data.addFilm : f) ?? []
340
+ films: current?.films.map((f) => (f.id === "temp" ? data.addFilm : f)) ?? [],
349
341
  }));
350
342
  },
351
-
343
+
352
344
  onSettled: (result, variables, context) => {
353
345
  // Always runs after mutation (success or error)
354
- console.log('Mutation completed');
355
- }
346
+ console.log("Mutation completed");
347
+ },
356
348
  });
357
349
 
358
350
  const result = await mutate({ title: "New Film" });
359
351
  ```
360
352
 
361
-
362
353
  ### Remote executor hooks (optional, per remote)
363
354
 
364
355
  You can define custom logic around the remote executor for each remote schema by using the auto-imported `defineRemoteExecutorHooks` helper.
@@ -376,17 +367,17 @@ export default defineRemoteExecutorHooks({
376
367
  const { remoteAuthToken } = context || {};
377
368
  request.extensions = defu(request.extensions, {
378
369
  headers: {
379
- "XAuthorization": `Bearer ${remoteAuthToken || ""}`,
370
+ Authorization: `Bearer ${remoteAuthToken || ""}`,
380
371
  },
381
372
  });
382
373
  },
383
-
374
+
384
375
  onResult(result, context) {
385
376
  // You can also access context in onResult
386
377
  console.log("User from context:", context?.user);
387
378
  console.log("Result:", result.data);
388
379
  },
389
-
380
+
390
381
  onError(error, context) {
391
382
  // And in onError for logging/monitoring
392
383
  console.error("Remote execution failed for user:", context?.user?.id);
@@ -394,7 +385,6 @@ export default defineRemoteExecutorHooks({
394
385
  });
395
386
  ```
396
387
 
397
-
398
388
  ## Contribution
399
389
 
400
390
  <details>
@@ -426,16 +416,13 @@ export default defineRemoteExecutorHooks({
426
416
 
427
417
  </details>
428
418
 
429
-
430
419
  <!-- Badges -->
420
+
431
421
  [npm-version-src]: https://img.shields.io/npm/v/@lewebsimple/nuxt-graphql/latest.svg?style=flat&colorA=020420&colorB=00DC82
432
422
  [npm-version-href]: https://npmjs.com/package/@lewebsimple/nuxt-graphql
433
-
434
423
  [npm-downloads-src]: https://img.shields.io/npm/dm/@lewebsimple/nuxt-graphql.svg?style=flat&colorA=020420&colorB=00DC82
435
424
  [npm-downloads-href]: https://npm.chart.dev/@lewebsimple/nuxt-graphql
436
-
437
425
  [license-src]: https://img.shields.io/npm/l/@lewebsimple/nuxt-graphql.svg?style=flat&colorA=020420&colorB=00DC82
438
426
  [license-href]: https://npmjs.com/package/@lewebsimple/nuxt-graphql
439
-
440
427
  [nuxt-src]: https://img.shields.io/badge/Nuxt-020420?logo=nuxt
441
428
  [nuxt-href]: https://nuxt.com
package/dist/module.d.mts CHANGED
@@ -1,32 +1,58 @@
1
1
  import * as _nuxt_schema from '@nuxt/schema';
2
- import { HeadersInput } from '../dist/runtime/shared/lib/headers.js';
3
- import { CacheConfig } from '../dist/runtime/shared/lib/types.js';
2
+ import { CacheConfig } from '../dist/runtime/app/lib/cache-config.js';
4
3
 
4
+ /** Local schema definition. */
5
5
  type LocalSchemaDef = {
6
+ /** Schema source type. */
6
7
  type: "local";
8
+ /** Path to a module exporting `schema`. */
7
9
  path: string;
8
10
  };
11
+ /** Remote schema definition. */
9
12
  type RemoteSchemaDef = {
13
+ /** Schema source type. */
10
14
  type: "remote";
15
+ /** Remote GraphQL endpoint URL. */
11
16
  endpoint: string;
12
- headers?: HeadersInput;
17
+ /** Static headers for introspection and execution. */
18
+ headers?: Record<string, string>;
19
+ /** Hook module paths used by the remote executor. */
13
20
  hooks?: string[];
14
21
  };
22
+ /** Supported schema definition union. */
15
23
  type SchemaDef = LocalSchemaDef | RemoteSchemaDef;
16
24
 
25
+ /** Module configuration accepted by `nuxt.config` under `graphql`. */
17
26
  interface NuxtGraphQLModuleOptions {
27
+ /** Client-side GraphQL options. */
18
28
  client?: {
19
- documents?: string;
29
+ /** Document globs used for code generation. */
30
+ documents?: string[];
31
+ /** Runtime cache configuration overrides. */
20
32
  cache?: Partial<CacheConfig>;
33
+ /** Incoming SSR header names to forward to GraphQL HTTP calls. */
21
34
  ssrForwardHeaders?: string[];
22
35
  };
36
+ /** Server-side GraphQL options. */
23
37
  server?: {
38
+ /** Context factory module paths. */
24
39
  context?: string[];
25
- schema?: Record<string, SchemaDef>;
40
+ /** Local and remote schema definitions. */
41
+ schema?: SchemaDef[];
26
42
  };
43
+ /** Optional output path for generated `graphql.config.json`. */
27
44
  saveConfig?: string;
45
+ /** Optional output path for generated schema SDL file. */
28
46
  saveSDL?: string;
29
47
  }
48
+ declare module "nuxt/schema" {
49
+ interface PublicRuntimeConfig {
50
+ graphql: {
51
+ cacheConfig: CacheConfig;
52
+ ssrForwardHeaders: string[];
53
+ };
54
+ }
55
+ }
30
56
  declare const _default: _nuxt_schema.NuxtModule<NuxtGraphQLModuleOptions, NuxtGraphQLModuleOptions, false>;
31
57
 
32
58
  export { _default as default };
package/dist/module.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
- "name": "@lewebsimple/nuxt-graphql",
2
+ "name": "nuxt-graphql",
3
3
  "configKey": "graphql",
4
- "version": "0.6.19",
4
+ "version": "0.7.0",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
- "unbuild": "3.6.1"
7
+ "unbuild": "unknown"
8
8
  }
9
9
  }