@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 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<CacheConfig>;
41
+ cache?: Partial<GraphQLCacheConfig>;
43
42
  /**
44
43
  * GraphQL documents glob pattern.
45
44
  * Default: "**\/*.gql"
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nuxt-graphql",
3
3
  "configKey": "graphql",
4
- "version": "0.5.3",
4
+ "version": "0.5.5",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "3.6.1"
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 { stitchSchemas } from '@graphql-tools/stitch';
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 imports = contextModules.map((module, index) => `import context${index} from ${JSON.stringify(module)};`);
22
- const types = contextModules.map((_, index) => `Awaited<ReturnType<typeof context${index}>>`);
23
- return [
24
- `import type { H3Event } from "h3";`,
25
- ...imports,
26
- "",
27
- `export type GraphQLContext = ${types.join("\n & ")};`,
28
- "",
29
- "export async function createContext(event: H3Event): Promise<GraphQLContext> {",
30
- " const parts = await Promise.all([",
31
- ...contextModules.map((_, index) => ` context${index}(event),`),
32
- " ]);",
33
- " return Object.assign({}, ...parts) as GraphQLContext;",
34
- "}"
35
- ].join("\n");
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
- if (fragments.length === 0) {
56
- return `export { }`;
57
- }
58
- return [
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
- const output = await codegen({
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
- `import type { DocumentNode } from "graphql";`,
142
- `import {`,
143
- ...operations.map(
144
- ({ name }) => ` ${name}Document, type ${name}QueryVariables, type ${name}QueryResult,`
145
- ),
146
- `} from "./operations";`,
147
- ``,
148
- // Operation entry
149
- `export interface OperationEntry<TVariables, TResult, TKind extends "query" | "mutation" | "subscription"> {`,
150
- ` kind: TKind;`,
151
- ` variables: TVariables;`,
152
- ` result: TResult;`,
153
- ` document: DocumentNode;`,
154
- `}`,
155
- ``,
156
- // Operation registry type
157
- `export type OperationRegistry = {`,
158
- ...operations.map(
159
- ({ name, kind }) => ` ${name}: OperationEntry<${name}QueryVariables, ${name}QueryResult, "${kind}">;`
160
- ),
161
- `};`,
162
- ``,
163
- // Operation name types
164
- `export type QueryName = { [K in keyof OperationRegistry]: OperationRegistry[K]["kind"] extends "query" ? K : never }[keyof OperationRegistry];`,
165
- `export type MutationName = { [K in keyof OperationRegistry]: OperationRegistry[K]["kind"] extends "mutation" ? K : never }[keyof OperationRegistry];`,
166
- `export type SubscriptionName = { [K in keyof OperationRegistry]: OperationRegistry[K]["kind"] extends "subscription" ? K : never }[keyof OperationRegistry];`,
167
- ``,
168
- // Projection helpers (variables / result)
169
- `export type VariablesOf<TName extends keyof OperationRegistry> = OperationRegistry[TName]["variables"];`,
170
- `export type ResultOf<TName extends keyof OperationRegistry> = OperationRegistry[TName]["result"];`,
171
- ``,
172
- // Runtime registry (document + kind only)
173
- `export const registry: { [K in keyof OperationRegistry]: { kind: OperationRegistry[K]["kind"]; document: DocumentNode; }; } = {`,
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({ path }) {
205
- return `export { schema } from ${JSON.stringify(path)};`;
199
+ function renderLocalSchemaTemplate({ schemaModule }) {
200
+ return `export { schema } from ${JSON.stringify(schemaModule)};`;
206
201
  }
207
- async function loadLocalSchema({ path }) {
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(path);
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(`${path} must export a valid 'schema' of type GraphQLSchema.`);
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 `// Nuxt GraphQL types (app)
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 `// Nuxt GraphQL types (server)
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 `// Nuxt GraphQL types (shared)
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?: 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
- resolveModule("./runtime/server/lib/default-context"),
388
- ...await Promise.all((options.yoga?.context || []).map((path) => resolveRootPath(path, true)))
389
- ];
390
- addTemplate({ filename: "graphql/context.ts", getContents: () => renderContextTemplate({ contextModules }), write: true });
391
- addServerTemplate({ filename: "#graphql/#context.ts", getContents: () => renderContextTemplate({ contextModules }) });
392
- const schemaDefs = {};
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 localSchemaDef = {
396
- ...schemaDef,
397
- path: await resolveRootPath(schemaDef.path, true)
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
- const remoteSchemaDef = {
404
- ...schemaDef,
405
- hooks: await Promise.all((schemaDef.hooks || []).map((hookPath) => resolveRootPath(hookPath, true))),
406
- remoteExecutorModule: resolveModule("./runtime/server/lib/remote-executor")
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
- schemaDefs[schemaName] = remoteSchemaDef;
409
- addTemplate({ filename: `graphql/schemas/${schemaName}.ts`, getContents: async () => await renderRemoteSchemaTemplate({ ...remoteSchemaDef }), write: true });
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
- let schemaCache = null;
427
- async function getStitchedSchema(schemaDefs2) {
428
- const key = `schema:${hash(schemaDefs2)}`;
429
- if (schemaCache?.key === key) return schemaCache.data;
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 getStitchedSchema(schemaDefs),
442
- documents: await getDocuments(options.client?.documents || "**/*.gql")
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 getDocuments(options.client?.documents || "**/*.gql")
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 getDocuments(options.client?.documents || "**/*.gql")
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: options.client?.documents || "**/*.gql" };
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<CacheConfig>;
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-config.js";
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 "../lib/cache.js";
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 CreateRemoteExecutorInput = {
5
- url: string;
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
- import type { CacheConfig } from "../../shared/lib/cache-config.js";
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 {CacheConfig} options Cache configuration.
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 }: CacheConfig, operationName: string, variables: unknown, scope?: string): CacheKeyParts;
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,6 +1,6 @@
1
1
  {
2
2
  "name": "@lewebsimple/nuxt-graphql",
3
- "version": "0.5.3",
3
+ "version": "0.5.5",
4
4
  "description": "Opinionated Nuxt module for using GraphQL",
5
5
  "repository": "lewebsimple/nuxt-graphql",
6
6
  "license": "AGPL-3.0-only",
@@ -1,5 +0,0 @@
1
- /**
2
- * Default empty GraphQL context factory.
3
- */
4
- declare const _default: (event: import("h3").H3Event) => {} | Promise<{}>;
5
- export default _default;
@@ -1,2 +0,0 @@
1
- import { defineGraphQLContext } from "../utils/defineGraphQLContext.js";
2
- export default defineGraphQLContext(() => ({}));
@@ -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 {};
@@ -1,9 +0,0 @@
1
- const defaultCacheConfig = {
2
- keyPrefix: "gql",
3
- keyVersion: "1",
4
- policy: "no-cache",
5
- ttl: void 0
6
- };
7
- export function resolveCacheConfig(...overrides) {
8
- return Object.assign({}, defaultCacheConfig, ...overrides);
9
- }