@lewebsimple/nuxt-graphql 0.5.3 → 0.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/module.d.mts +1 -2
- package/dist/module.json +1 -1
- package/dist/module.mjs +182 -184
- package/dist/runtime/app/composables/useAsyncGraphQLQuery.d.ts +1 -2
- package/dist/runtime/app/composables/useAsyncGraphQLQuery.js +1 -2
- package/dist/runtime/app/composables/useGraphQLCache.client.js +1 -1
- package/dist/runtime/server/lib/remote-executor.d.ts +2 -4
- package/dist/runtime/server/lib/yoga.d.ts +2 -1
- package/dist/runtime/server/tsconfig.json +2 -2
- package/dist/runtime/{app → shared}/lib/cache.d.ts +9 -3
- package/dist/runtime/{app → shared}/lib/cache.js +9 -0
- package/package.json +1 -1
- package/dist/runtime/server/lib/default-context.d.ts +0 -5
- package/dist/runtime/server/lib/default-context.js +0 -2
- package/dist/runtime/shared/lib/cache-config.d.ts +0 -42
- package/dist/runtime/shared/lib/cache-config.js +0 -9
package/dist/module.d.mts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import * as _nuxt_schema from '@nuxt/schema';
|
|
2
2
|
import { HeadersInput } from '../dist/runtime/shared/lib/headers.js';
|
|
3
|
-
import { CacheConfig } from '../dist/runtime/shared/lib/cache-config.js';
|
|
4
3
|
|
|
5
4
|
interface LocalSchemaDef {
|
|
6
5
|
type: "local";
|
|
@@ -39,7 +38,7 @@ interface NuxtGraphQLModuleOptions {
|
|
|
39
38
|
/**
|
|
40
39
|
* Global cache configuration for queries.
|
|
41
40
|
*/
|
|
42
|
-
cache?: Partial<
|
|
41
|
+
cache?: Partial<GraphQLCacheConfig>;
|
|
43
42
|
/**
|
|
44
43
|
* GraphQL documents glob pattern.
|
|
45
44
|
* Default: "**\/*.gql"
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { dirname, relative, resolve } from 'node:path';
|
|
3
|
-
import { defineNuxtModule, useLogger, createResolver, addTemplate, addServerTemplate, addTypeTemplate, addServerHandler, addPlugin, addImportsDir, addServerImportsDir } from '@nuxt/kit';
|
|
4
3
|
import { defu } from 'defu';
|
|
5
4
|
import { hash } from 'ohash';
|
|
5
|
+
import { stitchSchemas } from '@graphql-tools/stitch';
|
|
6
|
+
import { defineNuxtModule, useLogger, createResolver, addTemplate, addServerTemplate, addTypeTemplate, addServerHandler, addPlugin, addImportsDir, addServerImportsDir } from '@nuxt/kit';
|
|
6
7
|
import { loadDocuments as loadDocuments$1 } from '@graphql-tools/load';
|
|
7
8
|
import { GraphQLFileLoader } from '@graphql-tools/graphql-file-loader';
|
|
8
9
|
import { Kind, getIntrospectionQuery, buildClientSchema, GraphQLSchema } from 'graphql';
|
|
@@ -11,28 +12,33 @@ import * as typescriptPlugin from '@graphql-codegen/typescript';
|
|
|
11
12
|
import * as typescriptOperationsPlugin from '@graphql-codegen/typescript-operations';
|
|
12
13
|
import * as typedDocumentNodePlugin from '@graphql-codegen/typed-document-node';
|
|
13
14
|
import { mergeHeaders } from '../dist/runtime/shared/lib/headers.js';
|
|
14
|
-
import {
|
|
15
|
-
import { resolveCacheConfig } from '../dist/runtime/shared/lib/cache-config.js';
|
|
15
|
+
import { resolveCacheConfig } from '../dist/runtime/shared/lib/cache.js';
|
|
16
16
|
|
|
17
17
|
const cyan = "\x1B[36m";
|
|
18
18
|
const reset = "\x1B[0m";
|
|
19
19
|
|
|
20
20
|
function renderContextTemplate({ contextModules }) {
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
return
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
21
|
+
const contextImports = contextModules.map((contextModule, index) => `import { createContext as createContext${index} } from '${contextModule}';`);
|
|
22
|
+
const contexts = contextModules.map((_, index) => `createContext${index}(event)`);
|
|
23
|
+
return `
|
|
24
|
+
${contextImports.join("\n")}
|
|
25
|
+
|
|
26
|
+
export async function createContext(event) {
|
|
27
|
+
const parts = await Promise.all([${contexts.join(", ")}]);
|
|
28
|
+
return Object.assign({}, ...parts);
|
|
29
|
+
}`.trim();
|
|
30
|
+
}
|
|
31
|
+
function renderContextTypesTemplate({ contextModules }) {
|
|
32
|
+
const contextImports = contextModules.map((module, index) => `import createContext${index} from ${JSON.stringify(module)};`);
|
|
33
|
+
const contextTypes = ["{}", ...contextModules.map((_, index) => `Awaited<ReturnType<typeof createContext${index}>>`)];
|
|
34
|
+
return `
|
|
35
|
+
import type { H3Event } from "h3";
|
|
36
|
+
${contextImports.join("\n")}
|
|
37
|
+
|
|
38
|
+
declare module "#graphql/context" {
|
|
39
|
+
export type GraphQLContext = ${contextTypes.join(" & ")};
|
|
40
|
+
export function createContext(event: H3Event): Promise<GraphQLContext>;
|
|
41
|
+
}`.trim();
|
|
36
42
|
}
|
|
37
43
|
|
|
38
44
|
async function loadDocuments(documents) {
|
|
@@ -52,14 +58,10 @@ async function loadDocuments(documents) {
|
|
|
52
58
|
|
|
53
59
|
async function renderFragmentsTemplate({ documents }) {
|
|
54
60
|
const fragments = collectFragments(documents);
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
`export type {`,
|
|
60
|
-
...fragments.map((name) => ` ${name}Fragment,`),
|
|
61
|
-
`} from "./operations";`
|
|
62
|
-
].join("\n");
|
|
61
|
+
return fragments.length === 0 ? "export { }" : `
|
|
62
|
+
export type {
|
|
63
|
+
${fragments.map((name) => ` ${name}Fragment,`).join("\n")}
|
|
64
|
+
} from "./operations";`.trim();
|
|
63
65
|
}
|
|
64
66
|
function collectFragments(documents) {
|
|
65
67
|
const fragments = /* @__PURE__ */ new Set();
|
|
@@ -80,7 +82,7 @@ function collectFragments(documents) {
|
|
|
80
82
|
}
|
|
81
83
|
|
|
82
84
|
async function renderOperationsTemplate({ schema, documents }) {
|
|
83
|
-
|
|
85
|
+
return await codegen({
|
|
84
86
|
filename: "operations.ts",
|
|
85
87
|
// @graphql-codegen/core codegen supports GraphQLSchema at runtime, but types expect DocumentNode
|
|
86
88
|
schema,
|
|
@@ -132,51 +134,44 @@ async function renderOperationsTemplate({ schema, documents }) {
|
|
|
132
134
|
},
|
|
133
135
|
config: {}
|
|
134
136
|
});
|
|
135
|
-
return output;
|
|
136
137
|
}
|
|
137
138
|
|
|
138
139
|
async function renderRegistryTemplate({ documents }) {
|
|
139
140
|
const operations = collectOperations(documents);
|
|
140
|
-
return
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
...operations.map(
|
|
175
|
-
({ name, kind }) => ` ${name}: { kind: "${kind}", document: ${name}Document },`
|
|
176
|
-
),
|
|
177
|
-
`};`,
|
|
178
|
-
``
|
|
179
|
-
].join("\n");
|
|
141
|
+
return `
|
|
142
|
+
import type { DocumentNode } from "graphql";
|
|
143
|
+
import {
|
|
144
|
+
${operations.map(({ name }) => ` ${name}Document, type ${name}QueryVariables, type ${name}QueryResult,`).join("\n")}
|
|
145
|
+
} from "./operations";
|
|
146
|
+
|
|
147
|
+
// Operation entry
|
|
148
|
+
export interface OperationEntry<TVariables, TResult, TKind extends "query" | "mutation" | "subscription"> {
|
|
149
|
+
kind: TKind;
|
|
150
|
+
variables: TVariables;
|
|
151
|
+
result: TResult;
|
|
152
|
+
document: DocumentNode;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Operation registry type
|
|
156
|
+
export type OperationRegistry = {
|
|
157
|
+
${operations.map(({ name, kind }) => ` ${name}: OperationEntry<${name}QueryVariables, ${name}QueryResult, "${kind}">;`).join("\n")}
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
// Operation name types
|
|
161
|
+
export type OperationName = keyof OperationRegistry;
|
|
162
|
+
export type QueryName = { [K in keyof OperationRegistry]: OperationRegistry[K]["kind"] extends "query" ? K : never }[keyof OperationRegistry];
|
|
163
|
+
export type MutationName = { [K in keyof OperationRegistry]: OperationRegistry[K]["kind"] extends "mutation" ? K : never }[keyof OperationRegistry];
|
|
164
|
+
export type SubscriptionName = { [K in keyof OperationRegistry]: OperationRegistry[K]["kind"] extends "subscription" ? K : never }[keyof OperationRegistry];
|
|
165
|
+
|
|
166
|
+
// Projection helpers (variables / result)
|
|
167
|
+
export type VariablesOf<TName extends keyof OperationRegistry> = OperationRegistry[TName]["variables"];
|
|
168
|
+
export type ResultOf<TName extends keyof OperationRegistry> = OperationRegistry[TName]["result"];
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
// Runtime registry (document + kind only)
|
|
172
|
+
export const registry: { [K in keyof OperationRegistry]: { kind: OperationRegistry[K]["kind"]; document: DocumentNode; }; } = {
|
|
173
|
+
${operations.map(({ name, kind }) => ` ${name}: { kind: "${kind}", document: ${name}Document}, `).join("\n")}
|
|
174
|
+
};`.trim();
|
|
180
175
|
}
|
|
181
176
|
function collectOperations(documents) {
|
|
182
177
|
const operations = /* @__PURE__ */ new Map();
|
|
@@ -201,41 +196,61 @@ function collectOperations(documents) {
|
|
|
201
196
|
return [...operations.values()];
|
|
202
197
|
}
|
|
203
198
|
|
|
204
|
-
function renderLocalSchemaTemplate({
|
|
205
|
-
return `export { schema } from ${JSON.stringify(
|
|
199
|
+
function renderLocalSchemaTemplate({ schemaModule }) {
|
|
200
|
+
return `export { schema } from ${JSON.stringify(schemaModule)};`;
|
|
206
201
|
}
|
|
207
|
-
async function
|
|
202
|
+
async function renderRemoteSchemaTemplate({ remoteExecutorModule, hooksModules, schemaDef, schemaLoader }) {
|
|
203
|
+
const importHooks = hooksModules.map((hookPath, index) => `import hooks${index} from ${JSON.stringify(hookPath)};`);
|
|
204
|
+
const hooks = hooksModules.map((_, index) => `hooks${index}`);
|
|
205
|
+
const { url, headers } = schemaDef;
|
|
206
|
+
const schema = await schemaLoader();
|
|
207
|
+
const sdl = await printSchemaSDL(schema);
|
|
208
|
+
return `
|
|
209
|
+
import { buildSchema } from "graphql";
|
|
210
|
+
import { createRemoteExecutor } from ${JSON.stringify(remoteExecutorModule)};
|
|
211
|
+
${importHooks.join("\n")}
|
|
212
|
+
|
|
213
|
+
const sdl = /* GraphQL */ \`${sdl.replace(/`/g, "\\`")}\`;
|
|
214
|
+
|
|
215
|
+
export const schema = {
|
|
216
|
+
schema: buildSchema(sdl),
|
|
217
|
+
executor: createRemoteExecutor({
|
|
218
|
+
url: ${JSON.stringify(url)},
|
|
219
|
+
headers: ${JSON.stringify(headers || {})},
|
|
220
|
+
hooks: [${hooks.join(", ")}]
|
|
221
|
+
}),
|
|
222
|
+
};
|
|
223
|
+
`.trim();
|
|
224
|
+
}
|
|
225
|
+
function renderSchemaTemplate({ schemaNames }) {
|
|
226
|
+
const importSchemas = schemaNames.map((name) => `import { schema as ${name}Schema } from ${JSON.stringify(`./schemas/${name}`)};`);
|
|
227
|
+
const schemas = schemaNames.map((name) => `${name}Schema`);
|
|
228
|
+
return `
|
|
229
|
+
import { stitchSchemas } from "@graphql-tools/stitch";
|
|
230
|
+
${importSchemas.join("\n")}
|
|
231
|
+
|
|
232
|
+
export const schema = stitchSchemas({
|
|
233
|
+
subschemas: [${schemas.join(", ")}],
|
|
234
|
+
});`.trim();
|
|
235
|
+
}
|
|
236
|
+
function renderSchemaTypesTemplate() {
|
|
237
|
+
return `
|
|
238
|
+
import type { GraphQLSchema } from "graphql";
|
|
239
|
+
|
|
240
|
+
declare module "#graphql/schema" {
|
|
241
|
+
export const schema: GraphQLSchema;
|
|
242
|
+
}
|
|
243
|
+
`.trim();
|
|
244
|
+
}
|
|
245
|
+
async function loadLocalSchema({ schemaModule }) {
|
|
208
246
|
const { createJiti } = await import('jiti');
|
|
209
247
|
const jiti = createJiti(import.meta.url, { interopDefault: true });
|
|
210
|
-
const module = await jiti.import(
|
|
248
|
+
const module = await jiti.import(schemaModule);
|
|
211
249
|
if (!module.schema || !(module.schema instanceof Object) || typeof module.schema.getQueryType !== "function") {
|
|
212
|
-
throw new Error(`${
|
|
250
|
+
throw new Error(`${schemaModule} must export a valid 'schema' of type GraphQLSchema.`);
|
|
213
251
|
}
|
|
214
252
|
return module.schema;
|
|
215
253
|
}
|
|
216
|
-
async function renderRemoteSchemaTemplate({ remoteExecutorModule, type, hooks, ...schemaDef }) {
|
|
217
|
-
const schema = await introspectRemoteSchema(schemaDef);
|
|
218
|
-
const sdl = await printSchemaSDL(schema);
|
|
219
|
-
const imports = (hooks || []).map((hookPath, index) => `import hooks${index} from ${JSON.stringify(hookPath)};`);
|
|
220
|
-
return [
|
|
221
|
-
`import { buildSchema } from "graphql";`,
|
|
222
|
-
`import type { SubschemaConfig } from "@graphql-tools/delegate";`,
|
|
223
|
-
`import { createRemoteExecutor } from ${JSON.stringify(remoteExecutorModule)};`,
|
|
224
|
-
...imports,
|
|
225
|
-
``,
|
|
226
|
-
`const sdl = /* GraphQL */ \`${sdl.replace(/`/g, "\\`")}\`;`,
|
|
227
|
-
``,
|
|
228
|
-
`export const schema: SubschemaConfig = {`,
|
|
229
|
-
` schema: buildSchema(sdl),`,
|
|
230
|
-
` executor: createRemoteExecutor({`,
|
|
231
|
-
` ...${JSON.stringify(schemaDef)},`,
|
|
232
|
-
` hooks: [`,
|
|
233
|
-
...(hooks || []).map((_, index) => ` hooks${index},`),
|
|
234
|
-
` ]`,
|
|
235
|
-
` }),`,
|
|
236
|
-
`};`
|
|
237
|
-
].join("\n");
|
|
238
|
-
}
|
|
239
254
|
async function introspectRemoteSchema({ url, headers }) {
|
|
240
255
|
const response = await fetch(url, {
|
|
241
256
|
method: "POST",
|
|
@@ -265,34 +280,9 @@ async function printSchemaSDL(schema) {
|
|
|
265
280
|
const { printSchema, lexicographicSortSchema } = await import('graphql');
|
|
266
281
|
return printSchema(lexicographicSortSchema(schema));
|
|
267
282
|
}
|
|
268
|
-
function renderStitchedSchemaTemplate({ schemaNames }) {
|
|
269
|
-
return [
|
|
270
|
-
`import type { GraphQLSchema } from "graphql"; `,
|
|
271
|
-
`import type { SubschemaConfig } from "@graphql-tools/delegate"; `,
|
|
272
|
-
`import { stitchSchemas } from "@graphql-tools/stitch"; `,
|
|
273
|
-
...schemaNames.map((name) => `import { schema as ${name}Schema } from ${JSON.stringify(`./schemas/${name}`)}; `),
|
|
274
|
-
``,
|
|
275
|
-
`const subschemas: Array<GraphQLSchema | SubschemaConfig> = [`,
|
|
276
|
-
...schemaNames.map((name) => ` ${name}Schema, `),
|
|
277
|
-
`]; `,
|
|
278
|
-
``,
|
|
279
|
-
`export const schema = stitchSchemas({ subschemas }); `
|
|
280
|
-
].join("\n");
|
|
281
|
-
}
|
|
282
|
-
async function loadStitchedSchema(schemaDefs) {
|
|
283
|
-
const subschemas = [];
|
|
284
|
-
for (const schemaDef of Object.values(schemaDefs)) {
|
|
285
|
-
if (schemaDef.type === "local") {
|
|
286
|
-
subschemas.push(await loadLocalSchema(schemaDef));
|
|
287
|
-
} else if (schemaDef.type === "remote") {
|
|
288
|
-
subschemas.push(await introspectRemoteSchema(schemaDef));
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
return stitchSchemas({ subschemas });
|
|
292
|
-
}
|
|
293
283
|
|
|
294
284
|
function renderAppTypesTemplate() {
|
|
295
|
-
return
|
|
285
|
+
return `
|
|
296
286
|
import type { GraphQLClient } from "graphql-request";
|
|
297
287
|
import type { Client as SSEClient } from "graphql-sse";
|
|
298
288
|
|
|
@@ -311,20 +301,10 @@ declare module "#app" {
|
|
|
311
301
|
}
|
|
312
302
|
|
|
313
303
|
export {};
|
|
314
|
-
|
|
304
|
+
`.trim();
|
|
315
305
|
}
|
|
316
306
|
function renderServerTypesTemplate() {
|
|
317
|
-
return
|
|
318
|
-
import type { GraphQLSchema } from "graphql";
|
|
319
|
-
|
|
320
|
-
declare module "#graphql/context" {
|
|
321
|
-
export type { GraphQLContext };
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
declare module "#graphql/schema" {
|
|
325
|
-
export const schema: GraphQLSchema;
|
|
326
|
-
}
|
|
327
|
-
|
|
307
|
+
return `
|
|
328
308
|
declare module "h3" {
|
|
329
309
|
interface H3EventContext {
|
|
330
310
|
_graphqlInFlightRequestsMap?: Map<string, Promise<unknown>>;
|
|
@@ -332,24 +312,34 @@ declare module "h3" {
|
|
|
332
312
|
}
|
|
333
313
|
|
|
334
314
|
export {};
|
|
335
|
-
|
|
315
|
+
`.trim();
|
|
336
316
|
}
|
|
337
317
|
function renderSharedTypesTemplate() {
|
|
338
|
-
return
|
|
318
|
+
return `
|
|
339
319
|
import type { DocumentNode } from "graphql";
|
|
340
320
|
import type { CacheConfig } from "nuxt-graphql/runtime/shared/lib/cache-config";
|
|
341
321
|
|
|
322
|
+
declare global {
|
|
323
|
+
type GraphQLCacheConfig = {
|
|
324
|
+
policy: "no-cache" | "cache-first" | "network-first" | "swr";
|
|
325
|
+
ttl?: number;
|
|
326
|
+
keyPrefix: string;
|
|
327
|
+
keyVersion: string | number;
|
|
328
|
+
};;
|
|
329
|
+
}
|
|
330
|
+
|
|
342
331
|
declare module "nuxt/schema" {
|
|
343
332
|
interface PublicRuntimeConfig {
|
|
344
333
|
graphql: {
|
|
345
|
-
cacheConfig
|
|
334
|
+
cacheConfig: GraphQLCacheConfig;
|
|
346
335
|
ssrForwardHeaders: string[];
|
|
347
336
|
};
|
|
348
337
|
}
|
|
349
338
|
}
|
|
350
339
|
|
|
351
|
-
export {};
|
|
352
|
-
|
|
340
|
+
export { };
|
|
341
|
+
|
|
342
|
+
`.trim();
|
|
353
343
|
}
|
|
354
344
|
|
|
355
345
|
const module$1 = defineNuxtModule({
|
|
@@ -383,88 +373,96 @@ const module$1 = defineNuxtModule({
|
|
|
383
373
|
}
|
|
384
374
|
nuxt.options.alias ||= {};
|
|
385
375
|
nuxt.options.alias["#graphql"] ||= resolveBuild("graphql");
|
|
386
|
-
const contextModules = [
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
376
|
+
const contextModules = await Promise.all((options.yoga?.context || []).map((path) => resolveRootPath(path, true)));
|
|
377
|
+
addTemplate({ filename: "graphql/context.mjs", getContents: () => renderContextTemplate({ contextModules }), write: true });
|
|
378
|
+
addTemplate({ filename: "graphql/context.d.ts", getContents: () => renderContextTypesTemplate({ contextModules }), write: true });
|
|
379
|
+
addServerTemplate({ filename: "#graphql/context.mjs", getContents: () => renderContextTemplate({ contextModules }) });
|
|
380
|
+
const schemasCache = /* @__PURE__ */ new Map([]);
|
|
381
|
+
function cachedSchemaLoader(schemaDef, loader) {
|
|
382
|
+
return async () => {
|
|
383
|
+
const key = `schemaDef:${hash(schemaDef)}`;
|
|
384
|
+
const cached = schemasCache.get(key);
|
|
385
|
+
if (cached?.key === key) return cached.data;
|
|
386
|
+
const schema = await loader();
|
|
387
|
+
schemasCache.set(key, { key, data: schema });
|
|
388
|
+
return schema;
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
const remoteExecutorModule = resolveModule("./runtime/server/lib/remote-executor");
|
|
392
|
+
const schemaLoaders = {};
|
|
393
393
|
for (const [schemaName, schemaDef] of Object.entries(options.yoga?.schemas || {})) {
|
|
394
394
|
if (schemaDef.type === "local") {
|
|
395
|
-
const
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
};
|
|
399
|
-
schemaDefs[schemaName] = localSchemaDef;
|
|
400
|
-
addTemplate({ filename: `graphql/schemas/${schemaName}.ts`, getContents: async () => renderLocalSchemaTemplate({ ...localSchemaDef }), write: true });
|
|
401
|
-
addServerTemplate({ filename: `#graphql/schemas/${schemaName}.ts`, getContents: async () => renderLocalSchemaTemplate({ ...localSchemaDef }) });
|
|
395
|
+
const schemaModule = await resolveRootPath(schemaDef.path, true);
|
|
396
|
+
schemaLoaders[schemaName] = cachedSchemaLoader(schemaDef, async () => await loadLocalSchema({ schemaModule }));
|
|
397
|
+
addTemplate({ filename: `graphql/schemas/${schemaName}.mjs`, getContents: async () => renderLocalSchemaTemplate({ schemaModule }), write: true });
|
|
398
|
+
addServerTemplate({ filename: `#graphql/schemas/${schemaName}.mjs`, getContents: async () => renderLocalSchemaTemplate({ schemaModule }) });
|
|
402
399
|
} else if (schemaDef.type === "remote") {
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
400
|
+
schemaLoaders[schemaName] = cachedSchemaLoader(schemaDef, async () => await introspectRemoteSchema(schemaDef));
|
|
401
|
+
const input = {
|
|
402
|
+
remoteExecutorModule,
|
|
403
|
+
hooksModules: await Promise.all((schemaDef.hooks || []).map((hookPath) => resolveRootPath(hookPath, true))),
|
|
404
|
+
schemaDef,
|
|
405
|
+
schemaLoader: schemaLoaders[schemaName]
|
|
407
406
|
};
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
addServerTemplate({ filename: `#graphql/schemas/${schemaName}.ts`, getContents: async () => await renderRemoteSchemaTemplate({ ...remoteSchemaDef }) });
|
|
407
|
+
addTemplate({ filename: `graphql/schemas/${schemaName}.mjs`, getContents: async () => await renderRemoteSchemaTemplate(input), write: true });
|
|
408
|
+
addServerTemplate({ filename: `#graphql/schemas/${schemaName}.mjs`, getContents: async () => await renderRemoteSchemaTemplate(input) });
|
|
411
409
|
} else {
|
|
412
410
|
throw new Error(`Unknown schema type for schema "${schemaName}"`);
|
|
413
411
|
}
|
|
414
412
|
}
|
|
415
|
-
addTemplate({ filename: "graphql/schema.ts", getContents: () => renderStitchedSchemaTemplate({ schemaNames: Object.keys(options.yoga?.schemas || {}) }), write: true });
|
|
416
|
-
addServerTemplate({ filename: "#graphql/schema.ts", getContents: () => renderStitchedSchemaTemplate({ schemaNames: Object.keys(options.yoga?.schemas || {}) }) });
|
|
417
|
-
let documentsCache = null;
|
|
418
|
-
async function getDocuments(glob) {
|
|
419
|
-
const key = `documents:${glob}`;
|
|
420
|
-
if (documentsCache?.key === key) return documentsCache.data;
|
|
421
|
-
const documents = await loadDocuments(glob);
|
|
422
|
-
documentsCache = { key, data: documents };
|
|
423
|
-
return documents;
|
|
424
|
-
}
|
|
425
413
|
const sdlPath = resolveRoot(options.saveSDL || "server/graphql/schema.graphql");
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
const schema = await loadStitchedSchema(schemaDefs2);
|
|
431
|
-
schemaCache = { key, data: schema };
|
|
414
|
+
const loadStitchedSchema = cachedSchemaLoader({ type: "stitched" }, async () => {
|
|
415
|
+
const schema = stitchSchemas({
|
|
416
|
+
subschemas: await Promise.all(Object.values(schemaLoaders).map((loader) => loader()))
|
|
417
|
+
});
|
|
432
418
|
const sdl = await printSchemaSDL(schema);
|
|
433
419
|
mkdirSync(dirname(sdlPath), { recursive: true });
|
|
434
420
|
writeFileSync(sdlPath, sdl, { encoding: "utf-8" });
|
|
435
421
|
logger.info(`GraphQL SDL saved to: ${cyan}${getRelativePath(sdlPath)}${reset}`);
|
|
436
422
|
return schema;
|
|
423
|
+
});
|
|
424
|
+
addTemplate({ filename: "graphql/schema.mjs", getContents: () => renderSchemaTemplate({ schemaNames: Object.keys(options.yoga?.schemas || {}) }), write: true });
|
|
425
|
+
addTemplate({ filename: "graphql/schema.d.ts", getContents: () => renderSchemaTypesTemplate(), write: true });
|
|
426
|
+
addServerTemplate({ filename: "#graphql/schema.mjs", getContents: () => renderSchemaTemplate({ schemaNames: Object.keys(options.yoga?.schemas || {}) }) });
|
|
427
|
+
const documentsGlob = options.client?.documents || "**/*.gql";
|
|
428
|
+
let documentsCache = null;
|
|
429
|
+
async function loadDocumentsCached(glob) {
|
|
430
|
+
const key = `documents:${glob}`;
|
|
431
|
+
if (documentsCache?.key === key) return documentsCache.data;
|
|
432
|
+
const documents = await loadDocuments(glob);
|
|
433
|
+
documentsCache = { key, data: documents };
|
|
434
|
+
return documents;
|
|
437
435
|
}
|
|
438
436
|
addTemplate({
|
|
439
437
|
filename: "graphql/operations.ts",
|
|
440
438
|
getContents: async () => await renderOperationsTemplate({
|
|
441
|
-
schema: await
|
|
442
|
-
documents: await
|
|
439
|
+
schema: await loadStitchedSchema(),
|
|
440
|
+
documents: await loadDocumentsCached(documentsGlob)
|
|
443
441
|
}),
|
|
444
442
|
write: true
|
|
445
443
|
});
|
|
446
444
|
addTemplate({
|
|
447
445
|
filename: "graphql/fragments.ts",
|
|
448
446
|
getContents: async () => await renderFragmentsTemplate({
|
|
449
|
-
documents: await
|
|
447
|
+
documents: await loadDocumentsCached(documentsGlob)
|
|
450
448
|
}),
|
|
451
449
|
write: true
|
|
452
450
|
});
|
|
453
451
|
addTemplate({
|
|
454
452
|
filename: "graphql/registry.ts",
|
|
455
453
|
getContents: async () => await renderRegistryTemplate({
|
|
456
|
-
documents: await
|
|
454
|
+
documents: await loadDocumentsCached(documentsGlob)
|
|
457
455
|
}),
|
|
458
456
|
write: true
|
|
459
457
|
});
|
|
460
|
-
addTypeTemplate({ filename: "types/nuxt-graphql.app.d.ts", getContents: () => renderAppTypesTemplate() }, { nuxt: true });
|
|
461
|
-
addTypeTemplate({ filename: "types/nuxt-graphql.server.d.ts", getContents: () => renderServerTypesTemplate() }, { nitro: true });
|
|
462
|
-
addTypeTemplate({ filename: "types/nuxt-graphql.shared.d.ts", getContents: () => renderSharedTypesTemplate() }, { nuxt: true, nitro: true });
|
|
463
458
|
const configPath = resolveRoot(options.saveConfig || "graphql.config.json");
|
|
464
|
-
const config = { schema: getRelativePath(sdlPath), documents:
|
|
459
|
+
const config = { schema: getRelativePath(sdlPath), documents: documentsGlob };
|
|
465
460
|
mkdirSync(dirname(configPath), { recursive: true });
|
|
466
461
|
writeFileSync(configPath, JSON.stringify(config, null, 2), { encoding: "utf-8" });
|
|
467
462
|
logger.info(`GraphQL config saved to: ${cyan}${getRelativePath(configPath)}${reset}`);
|
|
463
|
+
addTypeTemplate({ filename: "types/nuxt-graphql.app.d.ts", getContents: () => renderAppTypesTemplate() }, { nuxt: true });
|
|
464
|
+
addTypeTemplate({ filename: "types/nuxt-graphql.server.d.ts", getContents: () => renderServerTypesTemplate() }, { nitro: true, node: true });
|
|
465
|
+
addTypeTemplate({ filename: "types/nuxt-graphql.shared.d.ts", getContents: () => renderSharedTypesTemplate() }, { nuxt: true, nitro: true, node: true });
|
|
468
466
|
nuxt.options.runtimeConfig.public.graphql = defu(nuxt.options.runtimeConfig.public.graphql, {
|
|
469
467
|
cacheConfig: resolveCacheConfig(options.client?.cache),
|
|
470
468
|
ssrForwardHeaders: options.client?.ssrForwardHeaders || ["authorization", "cookie"]
|
|
@@ -2,10 +2,9 @@ import { useAsyncData, type AsyncDataOptions } from "#app";
|
|
|
2
2
|
import type { QueryName, ResultOf, VariablesOf } from "#graphql/registry";
|
|
3
3
|
import { type MaybeRefOrGetter } from "#imports";
|
|
4
4
|
import { type ExecuteGraphQLHTTPOptions } from "../lib/execute-http.js";
|
|
5
|
-
import { type CacheConfig } from "../../shared/lib/cache-config.js";
|
|
6
5
|
import type { IsEmptyObject } from "../../shared/lib/utils.js";
|
|
7
6
|
type UseAsyncGraphQLQueryOptions<TName extends QueryName> = ExecuteGraphQLHTTPOptions & {
|
|
8
|
-
cache?: Partial<
|
|
7
|
+
cache?: Partial<GraphQLCacheConfig>;
|
|
9
8
|
} & AsyncDataOptions<ResultOf<TName>>;
|
|
10
9
|
/**
|
|
11
10
|
* Async GraphQL query composable with caching support.
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { useAsyncData, useNuxtData, useRuntimeConfig } from "#app";
|
|
2
2
|
import { computed, toValue } from "#imports";
|
|
3
|
-
import { getCacheKeyParts } from "../lib/cache.js";
|
|
4
3
|
import { executeGraphQLHTTP } from "../lib/execute-http.js";
|
|
5
4
|
import { getInFlightRequests } from "../lib/in-flight.js";
|
|
6
5
|
import { getPersistedEntry, setPersistedEntry } from "../lib/persisted.js";
|
|
7
|
-
import { resolveCacheConfig } from "../../shared/lib/cache
|
|
6
|
+
import { getCacheKeyParts, resolveCacheConfig } from "../../shared/lib/cache.js";
|
|
8
7
|
export function useAsyncGraphQLQuery(operationName, ...args) {
|
|
9
8
|
const [variables, options] = args;
|
|
10
9
|
const isClient = import.meta.client;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { clearNuxtData, useRuntimeConfig } from "#imports";
|
|
2
|
-
import { getCacheKeyParts } from "
|
|
2
|
+
import { getCacheKeyParts } from "../../shared/lib/cache.js";
|
|
3
3
|
import { deletePersistedByPrefix, deletePersistedEntry } from "../lib/persisted.js";
|
|
4
4
|
export function useGraphQLCache() {
|
|
5
5
|
const { public: { graphql: { cacheConfig } } } = useRuntimeConfig();
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import type { Executor } from "@graphql-tools/utils";
|
|
2
|
-
import { type HeadersInput } from "../../shared/lib/headers.js";
|
|
3
2
|
import type { GraphQLRemoteExecHooks } from "../utils/defineRemoteExecutorHooks.js";
|
|
4
|
-
type
|
|
5
|
-
|
|
6
|
-
headers?: HeadersInput;
|
|
3
|
+
import type { RemoteSchemaDef } from "../../../lib/schemas.js";
|
|
4
|
+
type CreateRemoteExecutorInput = Pick<RemoteSchemaDef, "url" | "headers"> & {
|
|
7
5
|
hooks: GraphQLRemoteExecHooks[];
|
|
8
6
|
};
|
|
9
7
|
/**
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import type { GraphQLContext } from "#graphql/context";
|
|
1
2
|
/**
|
|
2
3
|
* Get or create the singleton GraphQL Yoga instance.
|
|
3
4
|
*
|
|
4
5
|
* @returns GraphQL Yoga server instance.
|
|
5
6
|
*/
|
|
6
|
-
export declare function getYogaInstance(): import("graphql-yoga").YogaServerInstance<
|
|
7
|
+
export declare function getYogaInstance(): import("graphql-yoga").YogaServerInstance<GraphQLContext, {}>;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
{
|
|
2
|
-
"extends": "../../../.nuxt/tsconfig.server.json"
|
|
3
|
-
}
|
|
2
|
+
"extends": "../../../.nuxt/tsconfig.server.json"
|
|
3
|
+
}
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Merge the default cache config with user overrides.
|
|
3
|
+
*
|
|
4
|
+
* @param overrides Partial cache config overrides.
|
|
5
|
+
* @returns Resolved cache configuration.
|
|
6
|
+
*/
|
|
7
|
+
export declare function resolveCacheConfig(...overrides: Array<Partial<GraphQLCacheConfig> | undefined>): GraphQLCacheConfig;
|
|
2
8
|
type CacheKeyParts = {
|
|
3
9
|
key: string;
|
|
4
10
|
opPrefix: string;
|
|
@@ -6,7 +12,7 @@ type CacheKeyParts = {
|
|
|
6
12
|
/**
|
|
7
13
|
* Build cache key parts from config, operation name, and variables.
|
|
8
14
|
*
|
|
9
|
-
* @param {
|
|
15
|
+
* @param {GraphQLCacheConfig} options Cache configuration.
|
|
10
16
|
* @param options.keyPrefix Cache key prefix.
|
|
11
17
|
* @param options.keyVersion Cache key version.
|
|
12
18
|
* @param operationName Operation name.
|
|
@@ -14,5 +20,5 @@ type CacheKeyParts = {
|
|
|
14
20
|
* @param scope Optional cache scope segment.
|
|
15
21
|
* @returns Key parts including full key and operation prefix.
|
|
16
22
|
*/
|
|
17
|
-
export declare function getCacheKeyParts({ keyPrefix, keyVersion }:
|
|
23
|
+
export declare function getCacheKeyParts({ keyPrefix, keyVersion }: GraphQLCacheConfig, operationName: string, variables: unknown, scope?: string): CacheKeyParts;
|
|
18
24
|
export {};
|
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
import { hash } from "ohash";
|
|
2
|
+
const defaultCacheConfig = {
|
|
3
|
+
keyPrefix: "gql",
|
|
4
|
+
keyVersion: "1",
|
|
5
|
+
policy: "no-cache",
|
|
6
|
+
ttl: void 0
|
|
7
|
+
};
|
|
8
|
+
export function resolveCacheConfig(...overrides) {
|
|
9
|
+
return Object.assign({}, defaultCacheConfig, ...overrides);
|
|
10
|
+
}
|
|
2
11
|
export function getCacheKeyParts({ keyPrefix, keyVersion }, operationName, variables, scope) {
|
|
3
12
|
const parts = [keyPrefix, keyVersion];
|
|
4
13
|
if (scope) parts.push(scope);
|
package/package.json
CHANGED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
type GraphQLCachePolicy = "no-cache" | "cache-first" | "network-first" | "swr";
|
|
2
|
-
export type CacheConfig = {
|
|
3
|
-
/**
|
|
4
|
-
* Prefix used for all persisted cache keys.
|
|
5
|
-
*
|
|
6
|
-
* Used for namespacing and bulk invalidation.
|
|
7
|
-
* Default: 'graphql'
|
|
8
|
-
*/
|
|
9
|
-
keyPrefix: string;
|
|
10
|
-
/**
|
|
11
|
-
* Version included in cache keys.
|
|
12
|
-
*
|
|
13
|
-
* Changing this value invalidates all existing cache entries.
|
|
14
|
-
* Default: '1'
|
|
15
|
-
*/
|
|
16
|
-
keyVersion: string | number;
|
|
17
|
-
/**
|
|
18
|
-
* Cache strategy used by useAsyncGraphQLQuery.
|
|
19
|
-
*
|
|
20
|
-
* - 'no-cache' → always fetch, never read/write cache
|
|
21
|
-
* - 'cache-first' → return cache if valid, otherwise fetch
|
|
22
|
-
* - 'network-first' → fetch first, fallback to cache on failure
|
|
23
|
-
* - 'swr' → return cache immediately, revalidate in background
|
|
24
|
-
*/
|
|
25
|
-
policy: GraphQLCachePolicy;
|
|
26
|
-
/**
|
|
27
|
-
* Time-to-live in seconds.
|
|
28
|
-
*
|
|
29
|
-
* - undefined → inherit from higher-level config
|
|
30
|
-
* - 0 → never expires
|
|
31
|
-
* - > 0 → expires after TTL
|
|
32
|
-
*/
|
|
33
|
-
ttl?: number;
|
|
34
|
-
};
|
|
35
|
-
/**
|
|
36
|
-
* Merge the default cache config with user overrides.
|
|
37
|
-
*
|
|
38
|
-
* @param overrides Partial cache config overrides.
|
|
39
|
-
* @returns Resolved cache configuration.
|
|
40
|
-
*/
|
|
41
|
-
export declare function resolveCacheConfig(...overrides: Array<Partial<CacheConfig> | undefined>): CacheConfig;
|
|
42
|
-
export {};
|