@lewebsimple/nuxt-graphql 0.4.0 → 0.5.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/README.md +134 -188
- package/dist/module.d.mts +74 -22
- package/dist/module.json +2 -2
- package/dist/module.mjs +408 -369
- package/dist/runtime/app/composables/useAsyncGraphQLQuery.d.ts +19 -0
- package/dist/runtime/app/composables/useAsyncGraphQLQuery.js +82 -0
- package/dist/runtime/app/composables/useGraphQLCache.client.d.ts +10 -7
- package/dist/runtime/app/composables/useGraphQLCache.client.js +16 -31
- package/dist/runtime/app/composables/useGraphQLMutation.d.ts +10 -18
- package/dist/runtime/app/composables/useGraphQLMutation.js +7 -11
- package/dist/runtime/app/composables/useGraphQLQuery.d.ts +11 -9
- package/dist/runtime/app/composables/useGraphQLQuery.js +20 -78
- package/dist/runtime/app/composables/useGraphQLSubscription.client.d.ts +19 -0
- package/dist/runtime/app/composables/{useGraphQLSubscription.js → useGraphQLSubscription.client.js} +9 -14
- package/dist/runtime/app/lib/cache.d.ts +18 -0
- package/dist/runtime/app/lib/cache.js +9 -0
- package/dist/runtime/app/lib/execute-http.d.ts +14 -0
- package/dist/runtime/app/lib/execute-http.js +8 -0
- package/dist/runtime/app/lib/in-flight.d.ts +14 -0
- package/dist/runtime/app/lib/{graphql-cache.js → in-flight.js} +2 -7
- package/dist/runtime/app/lib/persisted.d.ts +26 -0
- package/dist/runtime/app/plugins/graphql-request.d.ts +7 -2
- package/dist/runtime/app/plugins/graphql-request.js +13 -14
- package/dist/runtime/app/plugins/graphql-sse.client.d.ts +7 -2
- package/dist/runtime/server/api/graphql.d.ts +8 -0
- package/dist/runtime/server/api/graphql.js +16 -0
- package/dist/runtime/server/lib/context.d.ts +10 -0
- package/dist/runtime/server/lib/context.js +3 -0
- package/dist/runtime/server/lib/default-context.d.ts +5 -0
- package/dist/runtime/server/lib/default-context.js +2 -0
- package/dist/runtime/server/lib/default-schema.d.ts +7 -0
- package/dist/runtime/server/lib/default-schema.js +18 -0
- package/dist/runtime/server/lib/execute-schema.d.ts +11 -0
- package/dist/runtime/server/lib/execute-schema.js +23 -0
- package/dist/runtime/server/lib/remote-executor.d.ts +29 -34
- package/dist/runtime/server/lib/remote-executor.js +27 -59
- package/dist/runtime/server/lib/schemas.d.ts +14 -0
- package/dist/runtime/server/lib/schemas.js +3 -0
- package/dist/runtime/server/lib/yoga.d.ts +6 -0
- package/dist/runtime/server/lib/yoga.js +20 -0
- package/dist/runtime/server/utils/useServerGraphQLMutation.d.ts +16 -8
- package/dist/runtime/server/utils/useServerGraphQLMutation.js +12 -11
- package/dist/runtime/server/utils/useServerGraphQLQuery.d.ts +16 -3
- package/dist/runtime/server/utils/useServerGraphQLQuery.js +16 -4
- package/dist/runtime/shared/lib/cache-config.d.ts +42 -0
- package/dist/runtime/{app → shared}/lib/cache-config.js +3 -3
- package/dist/runtime/shared/lib/error.d.ts +56 -0
- package/dist/runtime/shared/lib/error.js +61 -0
- package/dist/runtime/shared/lib/headers.d.ts +13 -3
- package/dist/runtime/shared/lib/headers.js +10 -35
- package/dist/runtime/shared/lib/registry.d.ts +12 -0
- package/dist/runtime/shared/lib/registry.js +8 -0
- package/dist/runtime/shared/lib/utils.d.ts +1 -0
- package/dist/runtime/shared/lib/utils.js +0 -0
- package/dist/runtime/{app → shared}/types/nuxt-graphql.d.ts +1 -5
- package/dist/types.d.mts +4 -0
- package/package.json +19 -33
- package/dist/helpers.d.mts +0 -3
- package/dist/helpers.mjs +0 -3
- package/dist/runtime/app/composables/useGraphQLSubscription.d.ts +0 -17
- package/dist/runtime/app/lib/cache-config.d.ts +0 -8
- package/dist/runtime/app/lib/graphql-cache.d.ts +0 -7
- package/dist/runtime/server/api/yoga-handler.d.ts +0 -2
- package/dist/runtime/server/api/yoga-handler.js +0 -42
- package/dist/runtime/server/lib/define-graphql-context.d.ts +0 -5
- package/dist/runtime/server/lib/define-graphql-context.js +0 -4
- package/dist/runtime/server/lib/define-remote-exec-middleware.d.ts +0 -30
- package/dist/runtime/server/lib/define-remote-exec-middleware.js +0 -3
- package/dist/runtime/server/lib/define-yoga-middleware.d.ts +0 -21
- package/dist/runtime/server/lib/define-yoga-middleware.js +0 -3
- package/dist/runtime/server/lib/execute-server-graphql.d.ts +0 -7
- package/dist/runtime/server/lib/execute-server-graphql.js +0 -34
- package/dist/runtime/shared/lib/graphql-error.d.ts +0 -17
- package/dist/runtime/shared/lib/graphql-error.js +0 -28
package/README.md
CHANGED
|
@@ -13,12 +13,12 @@ Opinionated Nuxt module that wires a typed GraphQL server + client into your app
|
|
|
13
13
|
## Features
|
|
14
14
|
|
|
15
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
|
|
18
|
-
- 🧠 **Type-safe
|
|
19
|
-
- 🧊 **SSR-friendly** by default: request header
|
|
20
|
-
- 🚀 **
|
|
21
|
-
-
|
|
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
|
|
20
|
+
- 🚀 **Client-side cache** for `useAsyncGraphQLQuery` (cache policies + optional persistence in localStorage)
|
|
21
|
+
- 🧯 **Unified error model** via `SafeResult` and `NormalizedError`
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
## Getting started
|
|
@@ -26,80 +26,83 @@ Opinionated Nuxt module that wires a typed GraphQL server + client into your app
|
|
|
26
26
|
Install the module to your Nuxt application with one command:
|
|
27
27
|
|
|
28
28
|
```bash
|
|
29
|
-
pnpx
|
|
29
|
+
pnpx nuxt module add @lewebsimple/nuxt-graphql
|
|
30
30
|
```
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
### Configuration
|
|
34
34
|
|
|
35
|
-
Declare your schemas, context, documents glob and
|
|
35
|
+
Declare your schemas, context, documents glob and optional client cache in [nuxt.config.ts](nuxt.config.ts):
|
|
36
36
|
|
|
37
37
|
```ts
|
|
38
38
|
export default defineNuxtConfig({
|
|
39
39
|
modules: ["@lewebsimple/nuxt-graphql"],
|
|
40
40
|
graphql: {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
41
|
+
yoga: {
|
|
42
|
+
// Schemas to stitch together (local and/or remote)
|
|
43
|
+
schemas: {
|
|
44
|
+
local: {
|
|
45
|
+
type: "local",
|
|
46
|
+
path: "server/graphql/schema.ts",
|
|
47
|
+
},
|
|
48
|
+
// Remote schema example
|
|
49
|
+
swapi: {
|
|
50
|
+
type: "remote",
|
|
51
|
+
url: "https://swapi-graphql.netlify.app/graphql",
|
|
52
|
+
// Optional: static headers for this remote
|
|
53
|
+
headers: {
|
|
54
|
+
"X-Static-Header": "static-header-value",
|
|
55
|
+
},
|
|
56
|
+
// Optional: per-remote execution hooks
|
|
57
|
+
hooks: ["server/graphql/swapi-hooks.ts"],
|
|
54
58
|
},
|
|
55
|
-
// Optional: per-remote execution middleware (onRequest / onResponse / onError hooks)
|
|
56
|
-
middleware: "server/graphql/swapi-middleware.ts",
|
|
57
59
|
},
|
|
60
|
+
|
|
61
|
+
// Optional: custom GraphQL context factories (defaults to [])
|
|
62
|
+
context: ["server/graphql/context.ts"],
|
|
58
63
|
},
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
// Persist cache entries in localStorage with TTL in seconds
|
|
78
|
-
// - 0 = never expires
|
|
79
|
-
// - undefined = persistence disabled
|
|
80
|
-
ttl: 60,
|
|
64
|
+
|
|
65
|
+
client: {
|
|
66
|
+
// Optional: documents glob (defaults to **/*.gql)
|
|
67
|
+
documents: "**/*.gql",
|
|
68
|
+
|
|
69
|
+
// Optional: headers forwarded from SSR to graphql-request (defaults to ["authorization", "cookie"])
|
|
70
|
+
ssrForwardHeaders: ["authorization", "cookie"],
|
|
71
|
+
|
|
72
|
+
// Optional: query caching (client-side only, for useAsyncGraphQLQuery)
|
|
73
|
+
cache: {
|
|
74
|
+
policy: "cache-first", // "no-cache" | "cache-first" | "network-first" | "swr"
|
|
75
|
+
keyVersion: "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
|
+
},
|
|
81
82
|
},
|
|
82
83
|
|
|
83
|
-
// Optional: save path for the
|
|
84
|
-
|
|
84
|
+
// Optional: save path for the stitched SDL (defaults to "server/graphql/schema.graphql")
|
|
85
|
+
saveSDL: "server/graphql/schema.graphql",
|
|
86
|
+
|
|
87
|
+
// Optional: save path for the generated GraphQL config (defaults to "graphql.config.json")
|
|
88
|
+
saveConfig: "graphql.config.json",
|
|
85
89
|
},
|
|
86
90
|
});
|
|
87
91
|
```
|
|
88
92
|
|
|
89
93
|
|
|
90
|
-
### Define
|
|
94
|
+
### Define schema(s) (local and/or remote)
|
|
91
95
|
|
|
92
|
-
**Local schemas** must
|
|
96
|
+
**Local schemas** must live under `server/` and export a `GraphQLSchema` as `schema`. You can use the provided `defineGraphQLSchema` helper for type-safety.
|
|
93
97
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
For the example configuration above, create `server/graphql/schema.ts`:
|
|
98
|
+
For the example configuration above, create [server/graphql/schema.ts](server/graphql/schema.ts):
|
|
97
99
|
|
|
98
100
|
```ts
|
|
99
101
|
import { createSchema } from "graphql-yoga";
|
|
102
|
+
import { defineGraphQLSchema } from "@lewebsimple/nuxt-graphql";
|
|
100
103
|
import type { GraphQLContext } from "#graphql/context";
|
|
101
104
|
|
|
102
|
-
|
|
105
|
+
const schema = createSchema<GraphQLContext>({
|
|
103
106
|
typeDefs: /* GraphQL */ `
|
|
104
107
|
type Query {
|
|
105
108
|
hello: String!
|
|
@@ -130,19 +133,21 @@ export const schema = createSchema<GraphQLContext>({
|
|
|
130
133
|
},
|
|
131
134
|
},
|
|
132
135
|
});
|
|
136
|
+
|
|
137
|
+
export default defineGraphQLSchema({ schema });
|
|
133
138
|
```
|
|
134
139
|
|
|
135
|
-
**Remote schemas** are introspected at build time from the required endpoint URL
|
|
140
|
+
**Remote schemas** are introspected at build time from the required endpoint URL and executed via an HTTP executor at runtime. Subscriptions are stripped from remote schemas.
|
|
136
141
|
|
|
137
142
|
|
|
138
|
-
### Define
|
|
143
|
+
### Define GraphQL context factories (optional)
|
|
139
144
|
|
|
140
|
-
|
|
145
|
+
Context factories are optional and run on the server in order. Their return types are merged into a single `GraphQLContext` type.
|
|
141
146
|
|
|
142
|
-
For example,
|
|
147
|
+
For example, create [server/graphql/context.ts](server/graphql/context.ts):
|
|
143
148
|
|
|
144
149
|
```ts
|
|
145
|
-
import { defineGraphQLContext } from "@lewebsimple/nuxt-graphql
|
|
150
|
+
import { defineGraphQLContext } from "@lewebsimple/nuxt-graphql";
|
|
146
151
|
import { getUserSession } from "nuxt-auth-utils";
|
|
147
152
|
|
|
148
153
|
export default defineGraphQLContext(async (event) => {
|
|
@@ -154,19 +159,20 @@ export default defineGraphQLContext(async (event) => {
|
|
|
154
159
|
```
|
|
155
160
|
|
|
156
161
|
|
|
157
|
-
### Write GraphQL documents (
|
|
162
|
+
### Write GraphQL documents (.gql)
|
|
158
163
|
|
|
159
|
-
Write operations in `.gql`
|
|
164
|
+
Write operations in `.gql` files; operation names become registry keys like `useGraphQLQuery("HelloWorld")`.
|
|
160
165
|
|
|
161
166
|
⚠️ Operation names are required and must be unique.
|
|
162
167
|
|
|
163
168
|
By default, the module scans `**/*.gql` and generates:
|
|
164
169
|
|
|
165
|
-
- Typed documents in `#graphql/
|
|
166
|
-
- Operation registry
|
|
167
|
-
-
|
|
170
|
+
- Typed documents and types in virtual modules under the `#graphql/operations` alias (internal)
|
|
171
|
+
- Operation registry in virtual modules under the `#graphql/registry` alias (internal)
|
|
172
|
+
- Fragment types in virtual modules under the `#graphql/fragments` alias
|
|
173
|
+
|
|
174
|
+
Example document files:
|
|
168
175
|
|
|
169
|
-
Example document files (filenaming convention can vary):
|
|
170
176
|
```graphql
|
|
171
177
|
# app/graphql/HelloWorld.query.gql
|
|
172
178
|
query HelloWorld {
|
|
@@ -190,15 +196,14 @@ subscription Time {
|
|
|
190
196
|
|
|
191
197
|
That's it! You can now use Nuxt GraphQL in your Nuxt app ✨
|
|
192
198
|
|
|
199
|
+
|
|
193
200
|
### Fragments
|
|
194
201
|
|
|
195
202
|
Fragments are fully supported and are the recommended way to share selection sets across operations.
|
|
196
203
|
|
|
197
204
|
- Fragment names must be unique across all `.gql` files (duplicates throw during generation).
|
|
198
|
-
-
|
|
199
|
-
|
|
200
|
-
- and a document constant like `TheFilmFragmentDoc`
|
|
201
|
-
- 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`).
|
|
205
|
+
- Fragment types are re-exported from `#graphql/fragments`.
|
|
206
|
+
- Fragments are not executable by themselves and are not part of the registry.
|
|
202
207
|
|
|
203
208
|
Example with a fragment:
|
|
204
209
|
|
|
@@ -218,108 +223,92 @@ query SwapiFilms {
|
|
|
218
223
|
}
|
|
219
224
|
```
|
|
220
225
|
|
|
221
|
-
From TypeScript, you can also use fragment types explicitly when
|
|
226
|
+
From TypeScript, you can also use fragment types explicitly when needed:
|
|
222
227
|
|
|
223
228
|
```ts
|
|
224
|
-
import type { TheFilmFragment } from "#graphql/
|
|
229
|
+
import type { TheFilmFragment } from "#graphql/fragments";
|
|
225
230
|
```
|
|
226
231
|
|
|
227
232
|
|
|
228
233
|
### Use the auto-imported composables
|
|
229
234
|
|
|
230
|
-
The auto-imported
|
|
235
|
+
The auto-imported composables allow executing queries, mutations, and subscriptions based on their registry name with full type-safety (variables and return value).
|
|
231
236
|
|
|
232
237
|
```ts
|
|
233
|
-
//
|
|
234
|
-
const { data, pending, error, refresh } = await
|
|
235
|
-
"HelloWorld",
|
|
236
|
-
undefined,
|
|
238
|
+
// Cached query via useAsyncData
|
|
239
|
+
const { data, pending, error, refresh } = await useAsyncGraphQLQuery(
|
|
240
|
+
"HelloWorld",
|
|
241
|
+
undefined,
|
|
237
242
|
{
|
|
238
|
-
// Custom request headers
|
|
239
243
|
headers: {
|
|
240
|
-
"X-Request-Header": "request-header-value"
|
|
244
|
+
"X-Request-Header": "request-header-value",
|
|
241
245
|
},
|
|
242
|
-
// Additional useAsyncData options
|
|
243
|
-
// lazy: true,
|
|
244
246
|
},
|
|
245
247
|
);
|
|
246
248
|
|
|
247
|
-
//
|
|
248
|
-
const {
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
},
|
|
253
|
-
});
|
|
254
|
-
const { data, pending, error } = await mutate({ message: "Hello from ping mutation!" }, {
|
|
255
|
-
// Each `mutate` call may send additional headers
|
|
249
|
+
// Direct HTTP query (SafeResult)
|
|
250
|
+
const { data: queryData, error: queryError } = await useGraphQLQuery("HelloWorld");
|
|
251
|
+
|
|
252
|
+
// Mutation (SafeResult)
|
|
253
|
+
const { mutate, pending: mutationPending } = useGraphQLMutation("Ping", {
|
|
256
254
|
headers: {
|
|
257
|
-
"X-
|
|
255
|
+
"X-Request-Header": "request-header-value",
|
|
258
256
|
},
|
|
259
257
|
});
|
|
258
|
+
const { data: mutationData, error: mutationError } = await mutate({ message: "Hello!" });
|
|
260
259
|
|
|
261
260
|
// Subscription (client-only, SSE)
|
|
262
261
|
const { data, error, start, stop } = useGraphQLSubscription("Time");
|
|
263
|
-
// data and error are shallowRef
|
|
264
262
|
```
|
|
265
263
|
|
|
264
|
+
|
|
266
265
|
### Use the auto-imported server-side utilities
|
|
267
266
|
|
|
268
|
-
In server routes, you can execute
|
|
267
|
+
In server routes, you can execute queries and mutations directly against the stitched schema (no HTTP roundtrip):
|
|
269
268
|
|
|
270
269
|
```ts
|
|
271
270
|
export default defineEventHandler(async (event) => {
|
|
272
271
|
// Server-side GraphQL query example
|
|
273
|
-
const {
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
});
|
|
272
|
+
const { data: queryData, error: queryError } = await useServerGraphQLQuery(
|
|
273
|
+
event,
|
|
274
|
+
"HelloWorld",
|
|
275
|
+
);
|
|
278
276
|
|
|
279
277
|
// Server-side GraphQL mutation example
|
|
280
|
-
const {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
},
|
|
284
|
-
|
|
285
|
-
const { ping } = await mutate({ message: hello }, {
|
|
286
|
-
headers: {
|
|
287
|
-
"X-Mutation-Header": "mutation-header-value",
|
|
288
|
-
},
|
|
289
|
-
});
|
|
278
|
+
const { data: mutationData } = await useServerGraphQLMutation(
|
|
279
|
+
event,
|
|
280
|
+
"Ping",
|
|
281
|
+
{ message: queryData?.hello ?? "fallback" },
|
|
282
|
+
);
|
|
290
283
|
|
|
291
|
-
return {
|
|
284
|
+
return { queryData, mutationData, queryError };
|
|
292
285
|
});
|
|
293
286
|
```
|
|
294
287
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
Also, resulting data is returned directly from `useServerGraphQLQuery` and `mutate` (throws an error on failure).
|
|
288
|
+
Server helpers return a `SafeResult` in the same format as the client helpers.
|
|
298
289
|
|
|
299
290
|
|
|
300
291
|
### Query caching (client-side only)
|
|
301
292
|
|
|
302
|
-
`
|
|
293
|
+
`useAsyncGraphQLQuery` can cache query results based on the global cache configuration and per-query overrides.
|
|
303
294
|
|
|
304
|
-
- In-flight requests are
|
|
305
|
-
-
|
|
306
|
-
-
|
|
295
|
+
- In-flight requests are deduplicated (same operation + variables → one network call).
|
|
296
|
+
- In-memory cache uses Nuxt `useAsyncData`/`useNuxtData`.
|
|
297
|
+
- Persisted cache stores entries in localStorage for ttl seconds (0 = never expires).
|
|
307
298
|
|
|
308
299
|
#### Cache policies
|
|
309
300
|
|
|
310
|
-
-
|
|
311
|
-
-
|
|
312
|
-
-
|
|
313
|
-
-
|
|
301
|
+
- "no-cache": always fetches from the network (still dedupes in-flight).
|
|
302
|
+
- "cache-first": returns cached value when present, otherwise fetches.
|
|
303
|
+
- "network-first": tries the network first, falls back to cached value on error.
|
|
304
|
+
- "swr": returns cached value immediately and refreshes in the background.
|
|
314
305
|
|
|
315
306
|
#### Per-query overrides
|
|
316
307
|
|
|
317
|
-
Caching configuration can be overridden per-query:
|
|
318
|
-
|
|
319
308
|
```ts
|
|
320
|
-
const { data } = await
|
|
309
|
+
const { data } = await useAsyncGraphQLQuery("HelloWorld", undefined, {
|
|
321
310
|
cache: {
|
|
322
|
-
|
|
311
|
+
policy: "network-first",
|
|
323
312
|
ttl: undefined, // disable persistence for this call
|
|
324
313
|
},
|
|
325
314
|
});
|
|
@@ -327,92 +316,49 @@ const { data } = await useGraphQLQuery("HelloWorld", undefined, {
|
|
|
327
316
|
|
|
328
317
|
#### Manual invalidation
|
|
329
318
|
|
|
330
|
-
On the client, `useGraphQLCache()`
|
|
319
|
+
On the client, `useGraphQLCache()` can invalidate in-memory and persisted entries:
|
|
331
320
|
|
|
332
321
|
```ts
|
|
333
|
-
const {
|
|
322
|
+
const { invalidate } = useGraphQLCache();
|
|
334
323
|
|
|
335
324
|
// Invalidate a single entry (operation + variables)
|
|
336
|
-
await
|
|
325
|
+
await invalidate({ operation: "HelloWorld", variables: {} });
|
|
337
326
|
|
|
338
|
-
// Invalidate all entries for an operation
|
|
339
|
-
await
|
|
340
|
-
|
|
341
|
-
// Optional: target a specific layer
|
|
342
|
-
await invalidateByOperation("HelloWorld", { layer: "persisted" });
|
|
327
|
+
// Invalidate all entries for an operation
|
|
328
|
+
await invalidate({ operation: "HelloWorld" });
|
|
343
329
|
|
|
344
330
|
// Invalidate all entries
|
|
345
|
-
await
|
|
346
|
-
```
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
### Yoga middleware (optional)
|
|
350
|
-
|
|
351
|
-
You can define custom logic around the Yoga event handler by using the provided `defineYogaMiddleware` helper with the following hooks:
|
|
352
|
-
- `onRequest` runs before Yoga handles the request;
|
|
353
|
-
- `onResponse` runs after and can replace the outgoing `Response` via `setResponse`.
|
|
354
|
-
|
|
355
|
-
For the example configuration above, create `server/graphql/yoga-middleware.ts`:
|
|
356
|
-
|
|
357
|
-
```ts
|
|
358
|
-
import { defineYogaMiddleware } from "@lewebsimple/nuxt-graphql/helpers";
|
|
359
|
-
import { getUserSession } from "nuxt-auth-utils";
|
|
360
|
-
|
|
361
|
-
export default defineYogaMiddleware({
|
|
362
|
-
async onRequest({ event, context, request }) {
|
|
363
|
-
const session = await getUserSession(event);
|
|
364
|
-
if (!session?.user) {
|
|
365
|
-
throw createError({ statusCode: 401, message: "Unauthorized" });
|
|
366
|
-
}
|
|
367
|
-
},
|
|
368
|
-
async onResponse({ event, context, request, response, setResponse }) {
|
|
369
|
-
setHeader(event, "X-Custom-Yoga-Middleware-Response-Header", "my-custom-value");
|
|
370
|
-
},
|
|
371
|
-
});
|
|
331
|
+
await invalidate();
|
|
372
332
|
```
|
|
373
333
|
|
|
374
|
-
### Remote executor middleware (optional, per remote)
|
|
375
334
|
|
|
376
|
-
|
|
377
|
-
- `onRequest` runs before the fetch (headers are mutable);
|
|
378
|
-
- `onResponse` runs after an OK response before JSON parsing (cloned response);
|
|
379
|
-
- `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).
|
|
335
|
+
### Remote executor hooks (optional, per remote)
|
|
380
336
|
|
|
381
|
-
|
|
337
|
+
You can define custom logic around the remote executor for each remote schema by using the provided `defineRemoteExecutorHooks` helper.
|
|
382
338
|
|
|
383
|
-
For the example configuration above, create
|
|
339
|
+
For the example configuration above, create [server/graphql/swapi-hooks.ts](server/graphql/swapi-hooks.ts):
|
|
384
340
|
|
|
385
341
|
```ts
|
|
386
|
-
import {
|
|
387
|
-
|
|
388
|
-
export default
|
|
389
|
-
onRequest(
|
|
390
|
-
|
|
391
|
-
|
|
342
|
+
import { defineRemoteExecutorHooks } from "@lewebsimple/nuxt-graphql";
|
|
343
|
+
|
|
344
|
+
export default defineRemoteExecutorHooks({
|
|
345
|
+
onRequest(request) {
|
|
346
|
+
// Dynamically inject headers
|
|
347
|
+
request.extensions ??= {};
|
|
348
|
+
request.extensions.headers = {
|
|
349
|
+
...request.extensions.headers,
|
|
350
|
+
"X-Remote-Exec-Request-Header": "custom-value",
|
|
351
|
+
};
|
|
392
352
|
},
|
|
393
|
-
|
|
394
|
-
console.log(
|
|
353
|
+
onResult(result) {
|
|
354
|
+
console.log("Remote result", result);
|
|
395
355
|
},
|
|
396
|
-
onError(
|
|
397
|
-
console.error(
|
|
356
|
+
onError(error) {
|
|
357
|
+
console.error("Remote error", error);
|
|
398
358
|
},
|
|
399
359
|
});
|
|
400
360
|
```
|
|
401
361
|
|
|
402
|
-
### Client error hook (optional)
|
|
403
|
-
|
|
404
|
-
Handle normalized GraphQL errors globally on the client (toast, logging, etc.).
|
|
405
|
-
|
|
406
|
-
The client calls the `graphql:error` Nuxt hook when a `graphql-request` response contains errors:
|
|
407
|
-
|
|
408
|
-
```ts
|
|
409
|
-
export default defineNuxtPlugin((nuxtApp) => {
|
|
410
|
-
nuxtApp.hook("graphql:error", (error) => {
|
|
411
|
-
console.error("GraphQL error", error);
|
|
412
|
-
});
|
|
413
|
-
});
|
|
414
|
-
```
|
|
415
|
-
|
|
416
362
|
|
|
417
363
|
## Contribution
|
|
418
364
|
|
package/dist/module.d.mts
CHANGED
|
@@ -1,36 +1,88 @@
|
|
|
1
1
|
import * as _nuxt_schema from '@nuxt/schema';
|
|
2
|
-
import {
|
|
2
|
+
import { HeadersInput } from '../dist/runtime/shared/lib/headers.js';
|
|
3
|
+
import { CacheConfig } from '../dist/runtime/shared/lib/cache-config.js';
|
|
4
|
+
export { defineGraphQLContext } from '../dist/runtime/server/lib/context.js';
|
|
5
|
+
export { defineRemoteExecutorHooks } from '../dist/runtime/server/lib/remote-executor.js';
|
|
3
6
|
|
|
4
|
-
|
|
5
|
-
* Find multiple files across directories
|
|
6
|
-
*
|
|
7
|
-
* @param dirs Directories to search in
|
|
8
|
-
* @param pattern Glob pattern relative to each directory
|
|
9
|
-
* @returns Array of found file paths
|
|
10
|
-
*/
|
|
11
|
-
type GlobPattern = string | string[];
|
|
12
|
-
|
|
13
|
-
type LocalSchemaDef = {
|
|
7
|
+
interface LocalSchemaDef {
|
|
14
8
|
type: "local";
|
|
9
|
+
/**
|
|
10
|
+
* Path to a server-side module exporting
|
|
11
|
+
* `export default defineLocalGraphQLSchema({ schema })`
|
|
12
|
+
* Resolved from rootDir.
|
|
13
|
+
*/
|
|
15
14
|
path: string;
|
|
16
|
-
}
|
|
17
|
-
|
|
15
|
+
}
|
|
16
|
+
interface RemoteSchemaDef {
|
|
18
17
|
type: "remote";
|
|
18
|
+
/**
|
|
19
|
+
* Remote GraphQL endpoint.
|
|
20
|
+
* Used for build-time introspection and runtime delegation.
|
|
21
|
+
*/
|
|
19
22
|
url: string;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
+
/**
|
|
24
|
+
* Static headers applied to all delegated requests.
|
|
25
|
+
* `null` unsets a header.
|
|
26
|
+
*/
|
|
27
|
+
headers?: HeadersInput;
|
|
28
|
+
/**
|
|
29
|
+
* Paths to remote execution hook modules.
|
|
30
|
+
* Resolved from rootDir.
|
|
31
|
+
*/
|
|
32
|
+
hooks?: string[];
|
|
33
|
+
}
|
|
23
34
|
type SchemaDef = LocalSchemaDef | RemoteSchemaDef;
|
|
24
35
|
|
|
25
36
|
interface NuxtGraphQLModuleOptions {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
37
|
+
/**
|
|
38
|
+
* Client-side GraphQL configuration (HTTP + cache).
|
|
39
|
+
*/
|
|
40
|
+
client?: {
|
|
41
|
+
/**
|
|
42
|
+
* Global cache configuration for queries.
|
|
43
|
+
*/
|
|
44
|
+
cache?: Partial<CacheConfig>;
|
|
45
|
+
/**
|
|
46
|
+
* GraphQL documents glob pattern.
|
|
47
|
+
* Default: "**\/*.gql"
|
|
48
|
+
*/
|
|
49
|
+
documents?: string;
|
|
50
|
+
/**
|
|
51
|
+
* Headers forwarded from the SSR request to graphql-request.
|
|
52
|
+
* Default: ["authorization", "cookie"]
|
|
53
|
+
*/
|
|
54
|
+
ssrForwardHeaders?: string[];
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Where to write graphql.config.json.
|
|
58
|
+
* Resolved from rootDir.
|
|
59
|
+
* Default: ./graphql.config.json
|
|
60
|
+
*/
|
|
29
61
|
saveConfig?: string;
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
62
|
+
/**
|
|
63
|
+
* Where to write the stitched GraphQL SDL.
|
|
64
|
+
* Resolved from rootDir.
|
|
65
|
+
* Default: server/graphql/schema.graphql
|
|
66
|
+
*/
|
|
67
|
+
saveSDL?: string;
|
|
68
|
+
/**
|
|
69
|
+
* Server-side GraphQL configuration (Yoga + execution).
|
|
70
|
+
*/
|
|
71
|
+
yoga?: {
|
|
72
|
+
/**
|
|
73
|
+
* Paths to GraphQL context factories.
|
|
74
|
+
* Must live in server/.
|
|
75
|
+
* Resolved from rootDir.
|
|
76
|
+
*/
|
|
77
|
+
context?: string[];
|
|
78
|
+
/**
|
|
79
|
+
* GraphQL schemas to stitch.
|
|
80
|
+
* Key = schemaName.
|
|
81
|
+
*/
|
|
82
|
+
schemas?: Record<string, SchemaDef>;
|
|
83
|
+
};
|
|
33
84
|
}
|
|
85
|
+
|
|
34
86
|
declare const _default: _nuxt_schema.NuxtModule<NuxtGraphQLModuleOptions, NuxtGraphQLModuleOptions, false>;
|
|
35
87
|
|
|
36
88
|
export { _default as default };
|