@lewebsimple/nuxt-graphql 0.6.20 → 0.7.1

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 +69 -73
  2. package/dist/module.d.mts +31 -5
  3. package/dist/module.json +3 -3
  4. package/dist/module.mjs +449 -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 +49 -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,11 @@ 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`.
197
191
  - Fragments are not executable by themselves and are not part of the registry.
198
192
 
199
193
  Example with a fragment:
@@ -214,12 +208,13 @@ query SwapiFilms {
214
208
  }
215
209
  ```
216
210
 
217
- From TypeScript, you can also use fragment types explicitly when needed:
211
+ From TypeScript, you can also use fragment types explicitly when needed (see below):
218
212
 
219
213
  ```ts
220
- import type { TheFilmFragment } from "#graphql/operations";
214
+ import type { TheFilmFragment, SwapiFilmsVariables } from "#graphql/types";
221
215
  ```
222
216
 
217
+ ⚠️ These types are inferred from the Zod schemas and cannot be used as top-level in component props, i.e. `defineProps<TheFilmFragment>()` breaks but `defineProps<{ film: TheFilmFragment }>()` works just fine.
223
218
 
224
219
  ### Use the auto-imported composables
225
220
 
@@ -227,20 +222,19 @@ The auto-imported composables allow executing queries, mutations, and subscripti
227
222
 
228
223
  ```ts
229
224
  // Cached query via useAsyncData
230
- const { data, pending, error, refresh } = await useAsyncGraphQLQuery("HelloWorld", undefined);
225
+ const { data, pending, error, refresh } = await useAsyncGraphQLQuery("HelloWorld", {});
231
226
 
232
227
  // Direct HTTP query (SafeResult)
233
- const { data: queryData, error: queryError } = await useGraphQLQuery("HelloWorld");
228
+ const { data: queryData, error: queryError } = await useGraphQLQuery("HelloWorld", {});
234
229
 
235
230
  // Mutation (SafeResult)
236
231
  const { mutate, pending: mutationPending } = useGraphQLMutation("Ping");
237
232
  const { data: mutationData, error: mutationError } = await mutate({ message: "Hello!" });
238
233
 
239
234
  // Subscription (client-only, SSE)
240
- const { data, error, start, stop } = useGraphQLSubscription("Time");
235
+ const { data, error, start, stop } = useGraphQLSubscription("Time", {});
241
236
  ```
242
237
 
243
-
244
238
  ### Use the auto-imported server utils
245
239
 
246
240
  In server routes, you can execute queries and mutations directly against the stitched schema (no HTTP roundtrip):
@@ -248,18 +242,21 @@ In server routes, you can execute queries and mutations directly against the sti
248
242
  ```ts
249
243
  export default defineEventHandler(async (event) => {
250
244
  // Server-side GraphQL query example
251
- const { data: queryData, error: queryError } = await useGraphQLOperation(event, "HelloWorld" );
245
+ const { data, error } = await executeSchemaOperation(event, "HelloWorld", {});
252
246
 
253
- // Server-side GraphQL mutation example
254
- const { data: mutationData } = await useGraphQLOperation(event, "Ping", { message: queryData?.hello ?? "Pong" },
255
- );
256
-
257
- return { queryData, mutationData, queryError };
247
+ return { data, error };
258
248
  });
259
249
  ```
260
250
 
261
- Server helpers return a `GraphQLExecutionResult` in the same format as some composables, i.e. `{ data: TResult, error: null } | { data: null, error: NormalizedError }`
251
+ Server helpers return a `ExecuteGraphQLResult` in the same format as some composables, i.e. `{ data: TResult, error: null } | { data: null, error: NormalizedError }`
252
+
253
+ ### Type-safety
262
254
 
255
+ All enum, fragment and operation variables & result types are re-exported from `#graphql/types` for your convenience:
256
+
257
+ ```ts
258
+ import type { TheFilmFragment } from "#graphql/types";
259
+ ```
263
260
 
264
261
  ### Query caching (client-side only)
265
262
 
@@ -279,12 +276,16 @@ Server helpers return a `GraphQLExecutionResult` in the same format as some comp
279
276
  #### Per-query overrides
280
277
 
281
278
  ```ts
282
- const { data } = await useAsyncGraphQLQuery("HelloWorld", undefined, {
283
- cache: {
284
- policy: "network-first",
285
- ttl: undefined, // disable persistence for this call
279
+ const { data } = await useAsyncGraphQLQuery(
280
+ "HelloWorld",
281
+ {},
282
+ {
283
+ cache: {
284
+ policy: "network-first",
285
+ ttl: undefined, // disable persistence for this call
286
+ },
286
287
  },
287
- });
288
+ );
288
289
  ```
289
290
 
290
291
  #### Cache manipulation
@@ -303,16 +304,16 @@ cache.write("AllFilms", {}, (current) => ({ ...current, films: [...current.films
303
304
 
304
305
  // Update cached query asynchronously (in-memory + persisted)
305
306
  await cache.update("AllFilms", {}, newValue);
306
- await cache.update("AllFilms", {}, (current) => ({ ...current, films: [...current.films, newFilm] }));
307
+ await cache.update("AllFilms", {}, (current) => ({
308
+ ...current,
309
+ films: [...current.films, newFilm],
310
+ }));
307
311
 
308
312
  // 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
313
+ await cache.invalidate("HelloWorld"); // All entries for operation
314
+ await cache.invalidate(); // All entries
312
315
  ```
313
316
 
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
317
  #### Optimistic updates
317
318
 
318
319
  `useGraphQLMutation` supports optimistic updates via lifecycle hooks:
@@ -321,18 +322,18 @@ await cache.invalidate(); // All entries
321
322
  const { mutate } = useGraphQLMutation("AddFilm", {
322
323
  onMutate: async (variables) => {
323
324
  const cache = useGraphQLCache();
324
-
325
+
325
326
  // Snapshot current value for rollback
326
327
  const snapshot = cache.read("AllFilms", {});
327
-
328
+
328
329
  // Optimistically update cache
329
330
  await cache.update("AllFilms", {}, (current) => ({
330
- films: [...(current?.films ?? []), { id: 'temp', title: variables.title }]
331
+ films: [...(current?.films ?? []), { id: "temp", title: variables.title }],
331
332
  }));
332
-
333
+
333
334
  return { snapshot };
334
335
  },
335
-
336
+
336
337
  onError: (error, variables, context) => {
337
338
  const cache = useGraphQLCache();
338
339
  // Rollback on error (sync for instant UI update)
@@ -340,25 +341,24 @@ const { mutate } = useGraphQLMutation("AddFilm", {
340
341
  cache.write("AllFilms", {}, context.snapshot);
341
342
  }
342
343
  },
343
-
344
+
344
345
  onSuccess: (data, variables, context) => {
345
346
  // Replace optimistic temp ID with real ID from server
346
347
  const cache = useGraphQLCache();
347
348
  cache.update("AllFilms", {}, (current) => ({
348
- films: current?.films.map(f => f.id === 'temp' ? data.addFilm : f) ?? []
349
+ films: current?.films.map((f) => (f.id === "temp" ? data.addFilm : f)) ?? [],
349
350
  }));
350
351
  },
351
-
352
+
352
353
  onSettled: (result, variables, context) => {
353
354
  // Always runs after mutation (success or error)
354
- console.log('Mutation completed');
355
- }
355
+ console.log("Mutation completed");
356
+ },
356
357
  });
357
358
 
358
359
  const result = await mutate({ title: "New Film" });
359
360
  ```
360
361
 
361
-
362
362
  ### Remote executor hooks (optional, per remote)
363
363
 
364
364
  You can define custom logic around the remote executor for each remote schema by using the auto-imported `defineRemoteExecutorHooks` helper.
@@ -376,17 +376,17 @@ export default defineRemoteExecutorHooks({
376
376
  const { remoteAuthToken } = context || {};
377
377
  request.extensions = defu(request.extensions, {
378
378
  headers: {
379
- "XAuthorization": `Bearer ${remoteAuthToken || ""}`,
379
+ Authorization: `Bearer ${remoteAuthToken || ""}`,
380
380
  },
381
381
  });
382
382
  },
383
-
383
+
384
384
  onResult(result, context) {
385
385
  // You can also access context in onResult
386
386
  console.log("User from context:", context?.user);
387
387
  console.log("Result:", result.data);
388
388
  },
389
-
389
+
390
390
  onError(error, context) {
391
391
  // And in onError for logging/monitoring
392
392
  console.error("Remote execution failed for user:", context?.user?.id);
@@ -394,7 +394,6 @@ export default defineRemoteExecutorHooks({
394
394
  });
395
395
  ```
396
396
 
397
-
398
397
  ## Contribution
399
398
 
400
399
  <details>
@@ -426,16 +425,13 @@ export default defineRemoteExecutorHooks({
426
425
 
427
426
  </details>
428
427
 
429
-
430
428
  <!-- Badges -->
429
+
431
430
  [npm-version-src]: https://img.shields.io/npm/v/@lewebsimple/nuxt-graphql/latest.svg?style=flat&colorA=020420&colorB=00DC82
432
431
  [npm-version-href]: https://npmjs.com/package/@lewebsimple/nuxt-graphql
433
-
434
432
  [npm-downloads-src]: https://img.shields.io/npm/dm/@lewebsimple/nuxt-graphql.svg?style=flat&colorA=020420&colorB=00DC82
435
433
  [npm-downloads-href]: https://npm.chart.dev/@lewebsimple/nuxt-graphql
436
-
437
434
  [license-src]: https://img.shields.io/npm/l/@lewebsimple/nuxt-graphql.svg?style=flat&colorA=020420&colorB=00DC82
438
435
  [license-href]: https://npmjs.com/package/@lewebsimple/nuxt-graphql
439
-
440
436
  [nuxt-src]: https://img.shields.io/badge/Nuxt-020420?logo=nuxt
441
437
  [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.20",
4
+ "version": "0.7.1",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
- "unbuild": "3.6.1"
7
+ "unbuild": "unknown"
8
8
  }
9
9
  }