@lewebsimple/nuxt-graphql 0.5.5 → 0.5.7

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.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nuxt-graphql",
3
3
  "configKey": "graphql",
4
- "version": "0.5.5",
4
+ "version": "0.5.7",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "3.6.1"
package/dist/module.mjs CHANGED
@@ -1,18 +1,18 @@
1
1
  import { mkdirSync, writeFileSync } from 'node:fs';
2
2
  import { dirname, relative, resolve } from 'node:path';
3
3
  import { defu } from 'defu';
4
- import { hash } from 'ohash';
4
+ import { GraphQLFileLoader } from '@graphql-tools/graphql-file-loader';
5
+ import { loadDocuments } from '@graphql-tools/load';
5
6
  import { stitchSchemas } from '@graphql-tools/stitch';
6
7
  import { defineNuxtModule, useLogger, createResolver, addTemplate, addServerTemplate, addTypeTemplate, addServerHandler, addPlugin, addImportsDir, addServerImportsDir } from '@nuxt/kit';
7
- import { loadDocuments as loadDocuments$1 } from '@graphql-tools/load';
8
- import { GraphQLFileLoader } from '@graphql-tools/graphql-file-loader';
9
- import { Kind, getIntrospectionQuery, buildClientSchema, GraphQLSchema } from 'graphql';
10
8
  import { codegen } from '@graphql-codegen/core';
11
9
  import * as typescriptPlugin from '@graphql-codegen/typescript';
12
10
  import * as typescriptOperationsPlugin from '@graphql-codegen/typescript-operations';
13
11
  import * as typedDocumentNodePlugin from '@graphql-codegen/typed-document-node';
12
+ import { Kind, getIntrospectionQuery, buildClientSchema, GraphQLSchema } from 'graphql';
14
13
  import { mergeHeaders } from '../dist/runtime/shared/lib/headers.js';
15
14
  import { resolveCacheConfig } from '../dist/runtime/shared/lib/cache.js';
15
+ import { hash } from 'ohash';
16
16
 
17
17
  const cyan = "\x1B[36m";
18
18
  const reset = "\x1B[0m";
@@ -41,50 +41,9 @@ declare module "#graphql/context" {
41
41
  }`.trim();
42
42
  }
43
43
 
44
- async function loadDocuments(documents) {
45
- try {
46
- return await loadDocuments$1([
47
- documents,
48
- "!**/.cache/**",
49
- "!**/.nuxt/**",
50
- "!**/.output/**",
51
- "!**/dist/**",
52
- "!**/node_modules/**"
53
- ], { loaders: [new GraphQLFileLoader()] });
54
- } catch {
55
- return [];
56
- }
57
- }
58
-
59
- async function renderFragmentsTemplate({ documents }) {
60
- const fragments = collectFragments(documents);
61
- return fragments.length === 0 ? "export { }" : `
62
- export type {
63
- ${fragments.map((name) => ` ${name}Fragment,`).join("\n")}
64
- } from "./operations";`.trim();
65
- }
66
- function collectFragments(documents) {
67
- const fragments = /* @__PURE__ */ new Set();
68
- for (const source of documents) {
69
- const doc = source.document;
70
- if (!doc) continue;
71
- for (const def of doc.definitions) {
72
- if (def.kind !== Kind.FRAGMENT_DEFINITION) continue;
73
- const name = def.name?.value;
74
- if (!name) continue;
75
- if (fragments.has(name)) {
76
- throw new Error(`Duplicate GraphQL fragment name "${name}"`);
77
- }
78
- fragments.add(name);
79
- }
80
- }
81
- return [...fragments.values()];
82
- }
83
-
84
44
  async function renderOperationsTemplate({ schema, documents }) {
85
- return await codegen({
45
+ const content = await codegen({
86
46
  filename: "operations.ts",
87
- // @graphql-codegen/core codegen supports GraphQLSchema at runtime, but types expect DocumentNode
88
47
  schema,
89
48
  documents,
90
49
  plugins: [
@@ -134,14 +93,42 @@ async function renderOperationsTemplate({ schema, documents }) {
134
93
  },
135
94
  config: {}
136
95
  });
96
+ const docs = splitDocuments(content);
97
+ const module = docs.map(({ name, object }) => `export const ${name} = ${object};`).join("\n");
98
+ const types = `${content.replace(/export const \w+ = [\s\S]*?;\n?/g, "")}
99
+ declare module "#graphql/operations" {
100
+ ${docs.map(({ name, type }) => `export type ${name} = ${type};`).join("\n ")}
101
+ }`.trim();
102
+ return { module, types };
103
+ }
104
+ function splitDocuments(content) {
105
+ const documents = [];
106
+ const documentRegex = /export const (\w+) = ([\s\S]*?) as unknown as (DocumentNode<[^>]+>);/g;
107
+ let match;
108
+ while (match = documentRegex.exec(content)) {
109
+ const [, name, object, type] = match;
110
+ if (!name || !object || !type) {
111
+ throw new Error("Invalid typed document matched while splitting documents.");
112
+ }
113
+ documents.push({ name, object: object.trim(), type });
114
+ }
115
+ return documents;
137
116
  }
138
117
 
139
118
  async function renderRegistryTemplate({ documents }) {
140
119
  const operations = collectOperations(documents);
141
- return `
142
- import type { DocumentNode } from "graphql";
120
+ const module = `
143
121
  import {
144
- ${operations.map(({ name }) => ` ${name}Document, type ${name}QueryVariables, type ${name}QueryResult,`).join("\n")}
122
+ ${operations.map(({ name }) => `${name}Document`).join(",\n ")}
123
+ } from "./operations";
124
+
125
+ export const registry = {
126
+ ${operations.map(({ name, kind }) => `${name}: { kind: "${kind}", document: ${name}Document },`).join("\n ")}
127
+ };`.trim();
128
+ const types = `
129
+ import type { DocumentNode } from "graphql";
130
+ import type {
131
+ ${operations.map(({ name, kind }) => `${name}${capitalize(kind)}Variables, ${name}${capitalize(kind)}Result,`).join("\n ")}
145
132
  } from "./operations";
146
133
 
147
134
  // Operation entry
@@ -154,7 +141,7 @@ export interface OperationEntry<TVariables, TResult, TKind extends "query" | "mu
154
141
 
155
142
  // Operation registry type
156
143
  export type OperationRegistry = {
157
- ${operations.map(({ name, kind }) => ` ${name}: OperationEntry<${name}QueryVariables, ${name}QueryResult, "${kind}">;`).join("\n")}
144
+ ${operations.map(({ name, kind }) => `${name}: OperationEntry<${name}${capitalize(kind)}Variables, ${name}${capitalize(kind)}Result, "${kind}">;`).join("\n ")}
158
145
  };
159
146
 
160
147
  // Operation name types
@@ -167,11 +154,11 @@ export type SubscriptionName = { [K in keyof OperationRegistry]: OperationRegist
167
154
  export type VariablesOf<TName extends keyof OperationRegistry> = OperationRegistry[TName]["variables"];
168
155
  export type ResultOf<TName extends keyof OperationRegistry> = OperationRegistry[TName]["result"];
169
156
 
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();
157
+ declare module "#graphql/registry" {
158
+ export const registry: { [K in keyof OperationRegistry]: { kind: OperationRegistry[K]["kind"]; document: DocumentNode; }; };
159
+ export type { OperationRegistry, OperationName, QueryName, MutationName, SubscriptionName, VariablesOf, ResultOf };
160
+ }`.trim();
161
+ return { module, types };
175
162
  }
176
163
  function collectOperations(documents) {
177
164
  const operations = /* @__PURE__ */ new Map();
@@ -187,13 +174,14 @@ function collectOperations(documents) {
187
174
  if (operations.has(name)) {
188
175
  throw new Error(`Duplicate GraphQL operation name "${name}"`);
189
176
  }
190
- operations.set(name, {
191
- name,
192
- kind: def.operation
193
- });
177
+ operations.set(name, { name, kind: def.operation });
194
178
  }
195
179
  }
196
- return [...operations.values()];
180
+ return Array.from(operations.values());
181
+ }
182
+ function capitalize(value) {
183
+ if (!value) return value;
184
+ return value.charAt(0).toUpperCase() + value.slice(1);
197
185
  }
198
186
 
199
187
  function renderLocalSchemaTemplate({ schemaModule }) {
@@ -373,36 +361,38 @@ const module$1 = defineNuxtModule({
373
361
  }
374
362
  nuxt.options.alias ||= {};
375
363
  nuxt.options.alias["#graphql"] ||= resolveBuild("graphql");
364
+ const buildCache = /* @__PURE__ */ new Map();
365
+ function cachedLoader(baseKey, loader) {
366
+ return async (...args) => {
367
+ const key = `${baseKey}:${hash(args)}`;
368
+ const cached = buildCache.get(key);
369
+ if (cached?.key === key) {
370
+ return cached.data;
371
+ }
372
+ const data = await loader(...args);
373
+ buildCache.set(key, { key, data });
374
+ return data;
375
+ };
376
+ }
376
377
  const contextModules = await Promise.all((options.yoga?.context || []).map((path) => resolveRootPath(path, true)));
377
378
  addTemplate({ filename: "graphql/context.mjs", getContents: () => renderContextTemplate({ contextModules }), write: true });
378
379
  addTemplate({ filename: "graphql/context.d.ts", getContents: () => renderContextTypesTemplate({ contextModules }), write: true });
379
380
  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
381
  const remoteExecutorModule = resolveModule("./runtime/server/lib/remote-executor");
392
- const schemaLoaders = {};
382
+ const schemaCachedLoaders = {};
393
383
  for (const [schemaName, schemaDef] of Object.entries(options.yoga?.schemas || {})) {
394
384
  if (schemaDef.type === "local") {
395
385
  const schemaModule = await resolveRootPath(schemaDef.path, true);
396
- schemaLoaders[schemaName] = cachedSchemaLoader(schemaDef, async () => await loadLocalSchema({ schemaModule }));
386
+ schemaCachedLoaders[schemaName] = cachedLoader(`schema:local:${schemaName}`, async () => await loadLocalSchema({ schemaModule }));
397
387
  addTemplate({ filename: `graphql/schemas/${schemaName}.mjs`, getContents: async () => renderLocalSchemaTemplate({ schemaModule }), write: true });
398
388
  addServerTemplate({ filename: `#graphql/schemas/${schemaName}.mjs`, getContents: async () => renderLocalSchemaTemplate({ schemaModule }) });
399
389
  } else if (schemaDef.type === "remote") {
400
- schemaLoaders[schemaName] = cachedSchemaLoader(schemaDef, async () => await introspectRemoteSchema(schemaDef));
390
+ schemaCachedLoaders[schemaName] = cachedLoader(`schema:remote:${schemaName}`, async () => await introspectRemoteSchema(schemaDef));
401
391
  const input = {
402
392
  remoteExecutorModule,
403
393
  hooksModules: await Promise.all((schemaDef.hooks || []).map((hookPath) => resolveRootPath(hookPath, true))),
404
394
  schemaDef,
405
- schemaLoader: schemaLoaders[schemaName]
395
+ schemaLoader: schemaCachedLoaders[schemaName]
406
396
  };
407
397
  addTemplate({ filename: `graphql/schemas/${schemaName}.mjs`, getContents: async () => await renderRemoteSchemaTemplate(input), write: true });
408
398
  addServerTemplate({ filename: `#graphql/schemas/${schemaName}.mjs`, getContents: async () => await renderRemoteSchemaTemplate(input) });
@@ -411,9 +401,9 @@ const module$1 = defineNuxtModule({
411
401
  }
412
402
  }
413
403
  const sdlPath = resolveRoot(options.saveSDL || "server/graphql/schema.graphql");
414
- const loadStitchedSchema = cachedSchemaLoader({ type: "stitched" }, async () => {
404
+ const loadCachedSchema = cachedLoader("schema:stitched", async () => {
415
405
  const schema = stitchSchemas({
416
- subschemas: await Promise.all(Object.values(schemaLoaders).map((loader) => loader()))
406
+ subschemas: await Promise.all(Object.values(schemaCachedLoaders).map((loader) => loader()))
417
407
  });
418
408
  const sdl = await printSchemaSDL(schema);
419
409
  mkdirSync(dirname(sdlPath), { recursive: true });
@@ -424,39 +414,48 @@ const module$1 = defineNuxtModule({
424
414
  addTemplate({ filename: "graphql/schema.mjs", getContents: () => renderSchemaTemplate({ schemaNames: Object.keys(options.yoga?.schemas || {}) }), write: true });
425
415
  addTemplate({ filename: "graphql/schema.d.ts", getContents: () => renderSchemaTypesTemplate(), write: true });
426
416
  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;
435
- }
436
- addTemplate({
437
- filename: "graphql/operations.ts",
438
- getContents: async () => await renderOperationsTemplate({
439
- schema: await loadStitchedSchema(),
440
- documents: await loadDocumentsCached(documentsGlob)
441
- }),
442
- write: true
417
+ const loadCachedDocuments = cachedLoader("documents", async (documentsGlob) => {
418
+ try {
419
+ return await loadDocuments([
420
+ documentsGlob,
421
+ "!**/.cache/**",
422
+ "!**/.nuxt/**",
423
+ "!**/.output/**",
424
+ "!**/dist/**",
425
+ "!**/node_modules/**"
426
+ ], { loaders: [new GraphQLFileLoader()] });
427
+ } catch {
428
+ return [];
429
+ }
430
+ });
431
+ const loadCachedOperations = cachedLoader("operations", async (documentsGlob) => {
432
+ const schema = await loadCachedSchema();
433
+ const documents = await loadCachedDocuments(documentsGlob);
434
+ return await renderOperationsTemplate({ schema, documents });
435
+ });
436
+ addTemplate({ filename: "graphql/operations.mjs", getContents: async () => (await loadCachedOperations(options.client?.documents || "**/*.gql")).module, write: true });
437
+ addServerTemplate({ filename: "#graphql/operations.mjs", getContents: async () => (await loadCachedOperations(options.client?.documents || "**/*.gql")).module });
438
+ addTemplate({ filename: "graphql/operations.d.ts", getContents: async () => (await loadCachedOperations(options.client?.documents || "**/*.gql")).types, write: true });
439
+ const loadCachedRegistry = cachedLoader("registry", async (documentsGlob) => {
440
+ const documents = await loadCachedDocuments(documentsGlob);
441
+ return await renderRegistryTemplate({ documents });
443
442
  });
444
443
  addTemplate({
445
- filename: "graphql/fragments.ts",
446
- getContents: async () => await renderFragmentsTemplate({
447
- documents: await loadDocumentsCached(documentsGlob)
448
- }),
444
+ filename: "graphql/registry.mjs",
445
+ getContents: async () => (await loadCachedRegistry(options.client?.documents || "**/*.gql")).module,
449
446
  write: true
450
447
  });
448
+ addServerTemplate({
449
+ filename: "#graphql/registry.mjs",
450
+ getContents: async () => (await loadCachedRegistry(options.client?.documents || "**/*.gql")).module
451
+ });
451
452
  addTemplate({
452
- filename: "graphql/registry.ts",
453
- getContents: async () => await renderRegistryTemplate({
454
- documents: await loadDocumentsCached(documentsGlob)
455
- }),
453
+ filename: "graphql/registry.d.ts",
454
+ getContents: async () => (await loadCachedRegistry(options.client?.documents || "**/*.gql")).types,
456
455
  write: true
457
456
  });
458
457
  const configPath = resolveRoot(options.saveConfig || "graphql.config.json");
459
- const config = { schema: getRelativePath(sdlPath), documents: documentsGlob };
458
+ const config = { schema: getRelativePath(sdlPath), documents: options.client?.documents || "**/*.gql" };
460
459
  mkdirSync(dirname(configPath), { recursive: true });
461
460
  writeFileSync(configPath, JSON.stringify(config, null, 2), { encoding: "utf-8" });
462
461
  logger.info(`GraphQL config saved to: ${cyan}${getRelativePath(configPath)}${reset}`);
@@ -471,7 +470,8 @@ const module$1 = defineNuxtModule({
471
470
  nuxt.hook("builder:watch", async (_event, changedPath) => {
472
471
  if (changedPath.endsWith(".gql")) {
473
472
  logger.info(`Documents change detected: ${cyan}${getRelativePath(changedPath)}${reset}`);
474
- documentsCache = null;
473
+ buildCache.delete("documents");
474
+ buildCache.delete("operations");
475
475
  }
476
476
  });
477
477
  }
@@ -3,8 +3,10 @@ type GraphQLContextFactory<TContext extends Record<string, unknown>> = (event: H
3
3
  /**
4
4
  * Define a GraphQL context factory with proper typing.
5
5
  *
6
- * @param factory Context factory function.
6
+ * @param createContext Context factory function.
7
7
  * @returns The same factory, typed for inference.
8
8
  */
9
- export declare function defineGraphQLContext<TContext extends Record<string, unknown>>(factory: GraphQLContextFactory<TContext>): GraphQLContextFactory<TContext>;
9
+ export declare function defineGraphQLContext<TContext extends Record<string, unknown>>(createContext: GraphQLContextFactory<TContext>): {
10
+ createContext: GraphQLContextFactory<TContext>;
11
+ };
10
12
  export {};
@@ -1,3 +1,3 @@
1
- export function defineGraphQLContext(factory) {
2
- return factory;
1
+ export function defineGraphQLContext(createContext) {
2
+ return { createContext };
3
3
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lewebsimple/nuxt-graphql",
3
- "version": "0.5.5",
3
+ "version": "0.5.7",
4
4
  "description": "Opinionated Nuxt module for using GraphQL",
5
5
  "repository": "lewebsimple/nuxt-graphql",
6
6
  "license": "AGPL-3.0-only",