nuxt-graphql-middleware 5.0.0-alpha.2 → 5.0.0-alpha.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.
Files changed (44) hide show
  1. package/dist/client/200.html +2 -2
  2. package/dist/client/404.html +2 -2
  3. package/dist/client/_nuxt/builds/latest.json +1 -1
  4. package/dist/client/_nuxt/builds/meta/c22c2916-33e9-427d-b6fe-10f11766c207.json +1 -0
  5. package/dist/client/index.html +2 -2
  6. package/dist/module.d.mts +20 -4
  7. package/dist/module.d.ts +20 -4
  8. package/dist/module.json +2 -2
  9. package/dist/module.mjs +352 -219
  10. package/dist/runtime/components/CodeFrame.vue +61 -0
  11. package/dist/runtime/components/DevModeOverlay.vue +60 -0
  12. package/dist/runtime/components/ErrorExtensions.vue +23 -0
  13. package/dist/runtime/components/ErrorGroup.vue +89 -0
  14. package/dist/runtime/composables/nuxtApp.d.ts +2 -2
  15. package/dist/runtime/composables/nuxtApp.js +21 -1
  16. package/dist/runtime/composables/useAsyncGraphqlQuery.d.ts +7 -7
  17. package/dist/runtime/composables/useAsyncGraphqlQuery.js +1 -1
  18. package/dist/runtime/composables/useGraphqlMutation.d.ts +4 -4
  19. package/dist/runtime/composables/useGraphqlMutation.js +1 -1
  20. package/dist/runtime/composables/useGraphqlQuery.d.ts +4 -4
  21. package/dist/runtime/composables/useGraphqlQuery.js +1 -1
  22. package/dist/runtime/composables/useGraphqlState.d.ts +1 -1
  23. package/dist/runtime/composables/useGraphqlUploadMutation.d.ts +4 -4
  24. package/dist/runtime/composables/useGraphqlUploadMutation.js +2 -2
  25. package/dist/runtime/css/output.css +1 -0
  26. package/dist/runtime/helpers/composables.d.ts +17 -20
  27. package/dist/runtime/helpers/composables.js +0 -5
  28. package/dist/runtime/plugins/devMode.d.ts +2 -0
  29. package/dist/runtime/plugins/devMode.js +23 -0
  30. package/dist/runtime/plugins/provideState.d.ts +1 -1
  31. package/dist/runtime/server/utils/index.d.ts +1 -1
  32. package/dist/runtime/server/utils/index.js +1 -1
  33. package/dist/runtime/server/utils/useGraphqlMutation.d.ts +4 -4
  34. package/dist/runtime/server/utils/useGraphqlQuery.d.ts +4 -4
  35. package/dist/runtime/serverHandler/debug.js +3 -7
  36. package/dist/runtime/serverHandler/helpers/index.d.ts +2 -2
  37. package/dist/runtime/serverHandler/index.js +4 -4
  38. package/dist/runtime/serverHandler/upload.js +4 -4
  39. package/dist/runtime/serverOptions/defineGraphqlServerOptions.d.ts +3 -2
  40. package/dist/runtime/settings/index.d.ts +29 -4
  41. package/dist/runtime/settings/index.js +10 -3
  42. package/dist/runtime/types.d.ts +8 -2
  43. package/package.json +14 -8
  44. package/dist/client/_nuxt/builds/meta/f823ebfd-daab-468f-8f6f-07a236da64bd.json +0 -1
package/dist/module.mjs CHANGED
@@ -2,22 +2,22 @@ import { loadSchema } from '@graphql-tools/load';
2
2
  import { fileURLToPath } from 'url';
3
3
  import { relative } from 'pathe';
4
4
  import { defu } from 'defu';
5
- import { useLogger, resolveFiles, defineNuxtModule, resolveAlias, createResolver, addImports, addServerImports, addTemplate, addServerHandler, addPlugin } from '@nuxt/kit';
5
+ import { useLogger, resolveFiles, defineNuxtModule, resolveAlias, createResolver, addImports, addServerImports, addTypeTemplate, addTemplate, addServerHandler, addPlugin } from '@nuxt/kit';
6
6
  import { onDevToolsInitialized, extendServerRpc } from '@nuxt/devtools-kit';
7
7
  import { existsSync } from 'fs';
8
8
  import { GraphqlMiddlewareTemplate } from '../dist/runtime/settings/index.js';
9
- import { promises, existsSync as existsSync$1 } from 'node:fs';
9
+ import fs from 'node:fs/promises';
10
+ import { existsSync as existsSync$1, promises } from 'node:fs';
10
11
  import { generate } from '@graphql-codegen/cli';
11
12
  import * as PluginSchemaAst from '@graphql-codegen/schema-ast';
12
13
  import { basename } from 'node:path';
13
- import { Source, parse, printSourceLocation } from 'graphql';
14
- import { Generator } from 'graphql-typescript-deluxe';
15
- import { pascalCase } from 'change-case-all';
14
+ import { printSourceLocation, parse, OperationTypeNode, Source } from 'graphql';
15
+ import { Generator, FieldNotFoundError, TypeNotFoundError, FragmentNotFoundError } from 'graphql-typescript-deluxe';
16
16
  import colors from 'picocolors';
17
17
  import { validateGraphQlDocuments } from '@graphql-tools/utils';
18
18
 
19
19
  const name = "nuxt-graphql-middleware";
20
- const version = "5.0.0-alpha.2";
20
+ const version = "5.0.0-alpha.5";
21
21
 
22
22
  const DEVTOOLS_UI_ROUTE = "/__nuxt-graphql-middleware";
23
23
  const DEVTOOLS_UI_LOCAL_PORT = 3300;
@@ -97,7 +97,8 @@ const defaultOptions = {
97
97
  debug: false,
98
98
  includeComposables: true,
99
99
  documents: [],
100
- devtools: true
100
+ devtools: true,
101
+ errorOverlay: true
101
102
  };
102
103
  function validateOptions(options) {
103
104
  if (!options.graphqlEndpoint) {
@@ -107,14 +108,14 @@ function validateOptions(options) {
107
108
  async function getSchemaPath(schemaPath, options, resolver, writeToDisk = false) {
108
109
  const dest = resolver(schemaPath);
109
110
  if (!options.downloadSchema) {
110
- const fileExists2 = await promises.access(dest).then(() => true).catch(() => false);
111
+ const fileExists2 = await fs.access(dest).then(() => true).catch(() => false);
111
112
  if (!fileExists2) {
112
113
  logger.error(
113
114
  '"downloadSchema" is set to false but no schema exists at ' + dest
114
115
  );
115
116
  throw new Error("Missing GraphQL schema.");
116
117
  }
117
- const schemaContent = await promises.readFile(dest).then((v) => v.toString());
118
+ const schemaContent = await fs.readFile(dest).then((v) => v.toString());
118
119
  return { schemaPath, schemaContent };
119
120
  }
120
121
  if (!options.graphqlEndpoint) {
@@ -135,112 +136,23 @@ const fileExists = (path, extensions = ["js", "ts", "mjs"]) => {
135
136
  return extension ? `${path}.${extension}` : null;
136
137
  };
137
138
 
138
- function groupOperationsByType(ops) {
139
- const result = {
140
- query: {},
141
- mutation: {},
142
- subscription: {}
143
- };
144
- for (const op of ops) {
145
- result[op.operationType][op.graphqlName] = {
146
- hasVariables: op.hasVariables,
147
- variablesOptional: !op.needsVariables
148
- };
149
- }
150
- return result;
151
- }
152
- function buildOperationTypeCode(operationMetadata, typeName, serverApiPrefix) {
153
- const imports = [];
154
- const resultTypes = [];
155
- let code = "";
156
- let nitroCode = "";
157
- const operationNames = Object.keys(operationMetadata);
158
- if (operationNames.length === 0) {
159
- return { code, nitroCode, imports, resultTypes };
160
- }
161
- const lines = [];
162
- const nitroLines = [];
163
- for (const name of operationNames) {
164
- const nameResult = pascalCase(`${name}${typeName}`);
165
- const nameVariables = pascalCase(`${name}${typeName}Variables`);
166
- resultTypes.push(nameResult);
167
- imports.push(nameResult);
168
- const { hasVariables, variablesOptional } = operationMetadata[name];
169
- if (hasVariables) {
170
- imports.push(nameVariables);
171
- }
172
- const variablesType = hasVariables ? nameVariables : "null";
173
- lines.push(
174
- ` ${name}: [${variablesType}, ${variablesOptional ? "true" : "false"}, ${nameResult}]`
175
- );
176
- nitroLines.push(`
177
- '${serverApiPrefix}/${typeName.toLowerCase()}/${name}': {
178
- 'default': GraphqlResponse<${nameResult}>
179
- }`);
180
- }
181
- code += ` export type GraphqlMiddleware${typeName} = {
182
- ${lines.join(",\n")}
183
- }
184
- `;
185
- nitroCode += nitroLines.join("\n");
186
- return { code, nitroCode, imports, resultTypes };
187
- }
188
- function generateContextTemplate(collectedOperations, serverApiPrefix) {
189
- const grouped = groupOperationsByType(collectedOperations);
190
- const queryResult = buildOperationTypeCode(
191
- grouped.query,
192
- "Query",
193
- serverApiPrefix
194
- );
195
- const mutationResult = buildOperationTypeCode(
196
- grouped.mutation,
197
- "Mutation",
198
- serverApiPrefix
199
- );
200
- const subscriptionResult = buildOperationTypeCode(
201
- grouped.subscription,
202
- "Subscription",
203
- serverApiPrefix
204
- );
205
- const allImports = [
206
- ...queryResult.imports,
207
- ...mutationResult.imports,
208
- ...subscriptionResult.imports
209
- ];
210
- const allResultTypes = [
211
- ...queryResult.resultTypes,
212
- ...mutationResult.resultTypes,
213
- ...subscriptionResult.resultTypes
214
- ];
215
- const combinedCode = [
216
- queryResult.code,
217
- mutationResult.code,
218
- subscriptionResult.code
219
- ].join("\n");
220
- const combinedNitroCode = [
221
- queryResult.nitroCode,
222
- mutationResult.nitroCode,
223
- subscriptionResult.nitroCode
224
- ].join("\n");
225
- return `
226
- import type { GraphqlResponse } from '#graphql-middleware-server-options-build'
227
- import type {
228
- ${allImports.join(",\n ")}
139
+ function generateResponseTypeTemplate(operations, context) {
140
+ const allTypes = operations.map((v) => v.typeName).sort();
141
+ return `import type {
142
+ ${allTypes.join(",\n ")}
229
143
  } from './../graphql-operations'
144
+ import type { GraphqlResponseAdditions } from './server-options'
145
+ import type { GraphqlServerResponse } from '${context.runtimeTypesPath}'
230
146
 
231
- declare module '#nuxt-graphql-middleware/generated-types' {
232
- export type GraphqlMiddlewareResponseUnion = ${allResultTypes.join(" | ")}
233
- ${combinedCode}
234
- }
147
+ export type GraphqlMiddlewareResponseUnion =
148
+ | ${allTypes.join("\n | ") || "never"}
235
149
 
236
- declare module 'nitropack' {
237
- interface InternalApi {
238
- ${combinedNitroCode}
239
- }
240
- }
241
- `;
150
+ export type GraphqlResponse<T> = GraphqlServerResponse<T> & GraphqlResponseAdditions
151
+ export type GraphqlResponseTyped = GraphqlResponse<GraphqlMiddlewareResponseUnion>`;
242
152
  }
243
153
 
154
+ const SYMBOL_CROSS = "x";
155
+ const SYMBOL_CHECK = "\u2714";
244
156
  function getMaxLengths(entries) {
245
157
  let name = 0;
246
158
  let path = 0;
@@ -263,7 +175,7 @@ function logAllEntries(entries) {
263
175
  let prevHadError = false;
264
176
  for (const entry of entries) {
265
177
  const hasErrors = entry.errors.length > 0;
266
- const icon = hasErrors ? colors.red("x") : colors.green("\u2714");
178
+ const icon = hasErrors ? colors.red(SYMBOL_CROSS) : colors.green(SYMBOL_CHECK);
267
179
  const type = entry.type.padEnd(lengths.type);
268
180
  const namePadded = colors.bold(entry.name.padEnd(lengths.name));
269
181
  const name = hasErrors ? colors.red(namePadded) : colors.green(namePadded);
@@ -293,6 +205,7 @@ function logAllEntries(entries) {
293
205
  }
294
206
  logger.restoreStd();
295
207
  }
208
+
296
209
  class CollectedFile {
297
210
  filePath;
298
211
  fileContents;
@@ -324,12 +237,61 @@ class CollectedFile {
324
237
  return false;
325
238
  }
326
239
  }
240
+
241
+ function generateNitroTypes(operations, serverApiPrefix) {
242
+ const endpoints = [];
243
+ const imports = [];
244
+ for (const operation of operations) {
245
+ imports.push(operation.typeName);
246
+ const method = operation.operationType === OperationTypeNode.QUERY ? "get" : "post";
247
+ endpoints.push(
248
+ ` '${serverApiPrefix}/${operation.operationType}/${operation.graphqlName}': {
249
+ '${method}': GraphqlResponse<${operation.typeName}>
250
+ }`
251
+ );
252
+ }
253
+ return `import type { GraphqlResponse } from './response'
254
+ import type {
255
+ ${imports.sort().join(",\n ")}
256
+ } from './../graphql-operations'
257
+
258
+ declare module 'nitropack/types' {
259
+ interface InternalApi {
260
+ ${endpoints.sort().join("\n")}
261
+ }
262
+ }`;
263
+ }
264
+
265
+ function generateSourcesTemplate(operations, srcDir) {
266
+ const lines = [];
267
+ for (const operation of operations) {
268
+ const filePath = relative(srcDir, operation.filePath);
269
+ lines.push(
270
+ `${operation.operationType}_${operation.graphqlName}: '${filePath}',`
271
+ );
272
+ }
273
+ return `
274
+ export const operationSources = {
275
+ ${lines.join("\n ")}
276
+ }
277
+ `;
278
+ }
279
+
327
280
  class Collector {
328
- constructor(schema, context, nuxtConfigDocuments = [], generatorOptions) {
281
+ constructor(schema, context, nuxtConfigDocuments = [], generatorOptions = {}) {
329
282
  this.schema = schema;
330
283
  this.context = context;
331
284
  this.nuxtConfigDocuments = nuxtConfigDocuments;
332
- this.generator = new Generator(schema, generatorOptions);
285
+ const mappedOptions = { ...generatorOptions };
286
+ if (!mappedOptions.output) {
287
+ mappedOptions.output = {};
288
+ }
289
+ if (!mappedOptions.output.buildTypeDocFilePath) {
290
+ mappedOptions.output.buildTypeDocFilePath = (filePath) => {
291
+ return this.filePathToBuildRelative(filePath);
292
+ };
293
+ }
294
+ this.generator = new Generator(schema, mappedOptions);
333
295
  }
334
296
  /**
335
297
  * All collected files.
@@ -351,29 +313,55 @@ class Collector {
351
313
  * The generated TypeScript type template output.
352
314
  */
353
315
  outputTypes = "";
316
+ /**
317
+ * The generated TypeScript enum template output.
318
+ */
319
+ outputEnums = "";
354
320
  /**
355
321
  * The generated oeprations file.
356
322
  */
357
323
  outputOperations = "";
324
+ /**
325
+ * The generated oepration types file.
326
+ */
327
+ outputOperationTypes = "";
358
328
  /**
359
329
  * The generated context template file.
360
330
  */
361
- outputContext = "";
331
+ outputResponseTypes = "";
332
+ /**
333
+ * The generated nitro template file.
334
+ */
335
+ outputNitroTypes = "";
362
336
  /**
363
- * Whether we need to rebuild the Generator state.
337
+ * The generated nitro template file.
364
338
  */
365
- needsRebuild = false;
366
- filePathToRelative(filePath) {
339
+ outputSources = "";
340
+ filePathToBuildRelative(filePath) {
367
341
  return "./" + relative(this.context.buildDir, filePath);
368
342
  }
343
+ filePathToSourceRelative(filePath) {
344
+ return "./" + relative(process.cwd(), filePath);
345
+ }
369
346
  operationToLogEntry(operation, errors) {
370
347
  return {
371
348
  name: operation.graphqlName,
372
349
  type: operation.operationType,
373
- path: operation.filePath,
350
+ path: this.filePathToSourceRelative(operation.filePath),
374
351
  errors
375
352
  };
376
353
  }
354
+ buildOutputTypes(file) {
355
+ let output = "";
356
+ const enumImports = file.getTypeScriptEnumDependencies();
357
+ if (enumImports.length) {
358
+ output += `import type { ${enumImports.join(", ")} } from './enums'
359
+
360
+ `;
361
+ }
362
+ output += file.getSource();
363
+ return output;
364
+ }
377
365
  /**
378
366
  * Executes code gen and performs validation for operations.
379
367
  */
@@ -381,12 +369,27 @@ class Collector {
381
369
  const output = this.generator.build();
382
370
  const operations = output.getCollectedOperations();
383
371
  const generatedCode = output.getGeneratedCode();
384
- this.outputOperations = output.getOperationsFile();
385
- this.outputTypes = output.getEverything();
386
- this.outputContext = generateContextTemplate(
372
+ this.outputOperations = output.getOperationsFile({
373
+ exportName: "documents",
374
+ minify: !this.context.isDev
375
+ }).getSource();
376
+ this.outputOperationTypes = output.getOperationTypesFile({
377
+ importFrom: "./../graphql-operations"
378
+ }).getSource();
379
+ this.outputEnums = output.buildFile(["enum"]).getSource();
380
+ this.outputTypes = this.buildOutputTypes(output.getTypes());
381
+ this.outputResponseTypes = generateResponseTypeTemplate(
382
+ operations,
383
+ this.context
384
+ );
385
+ this.outputNitroTypes = generateNitroTypes(
387
386
  operations,
388
387
  this.context.serverApiPrefix
389
388
  );
389
+ this.outputSources = generateSourcesTemplate(
390
+ operations,
391
+ this.context.rootDir
392
+ );
390
393
  const fragmentMap = /* @__PURE__ */ new Map();
391
394
  const operationSourceMap = /* @__PURE__ */ new Map();
392
395
  for (const code of generatedCode) {
@@ -415,7 +418,10 @@ class Collector {
415
418
  } else {
416
419
  this.operationTimestamps.set(operation.graphqlName, operation.timestamp);
417
420
  }
418
- logEntries.push(this.operationToLogEntry(operation, errors));
421
+ const shouldLog = errors.length || !this.context.logOnlyErrors;
422
+ if (shouldLog) {
423
+ logEntries.push(this.operationToLogEntry(operation, errors));
424
+ }
419
425
  }
420
426
  logAllEntries(logEntries);
421
427
  if (hasErrors) {
@@ -439,6 +445,29 @@ class Collector {
439
445
  }
440
446
  }
441
447
  }
448
+ buildErrorMessage(error) {
449
+ let output = "";
450
+ if (error instanceof FieldNotFoundError || error instanceof TypeNotFoundError || error instanceof FragmentNotFoundError) {
451
+ const filePath = error.context?.filePath;
452
+ const file = filePath ? this.files.get(filePath) : null;
453
+ if (filePath) {
454
+ output += ` | ${this.filePathToSourceRelative(filePath)}
455
+ `;
456
+ }
457
+ output += "\n" + error.message + "\n\n";
458
+ if (file) {
459
+ output += file.fileContents;
460
+ }
461
+ } else if (error instanceof Error) {
462
+ output += "\n" + error.message;
463
+ }
464
+ return output;
465
+ }
466
+ logError(error) {
467
+ let output = `${SYMBOL_CROSS}`;
468
+ output += this.buildErrorMessage(error);
469
+ logger.error(colors.red(output));
470
+ }
442
471
  /**
443
472
  * Get all file paths that match the import patterns.
444
473
  */
@@ -454,21 +483,27 @@ class Collector {
454
483
  * Initialise the collector.
455
484
  */
456
485
  async init() {
457
- const files = await this.getImportPatternFiles();
458
- for (const filePath of files) {
459
- await this.addFile(filePath);
460
- }
461
- this.nuxtConfigDocuments.forEach((docString, i) => {
462
- const pseudoPath = `nuxt.config.ts[${i}]`;
463
- const file = new CollectedFile(pseudoPath, docString, false);
464
- this.files.set(pseudoPath, file);
465
- this.generator.add({
466
- filePath: this.filePathToRelative("nuxt.config.ts"),
467
- documentNode: file.parsed
468
- });
469
- });
470
- this.buildState();
471
- logger.success("All GraphQL documents are valid.");
486
+ try {
487
+ const files = await this.getImportPatternFiles();
488
+ for (const filePath of files) {
489
+ await this.addFile(filePath);
490
+ }
491
+ const nuxtConfigDocuments = this.nuxtConfigDocuments.join("\n\n");
492
+ if (nuxtConfigDocuments.length) {
493
+ const filePath = this.context.nuxtConfigPath;
494
+ const file = new CollectedFile(filePath, nuxtConfigDocuments, false);
495
+ this.files.set(filePath, file);
496
+ this.generator.add({
497
+ filePath,
498
+ documentNode: file.parsed
499
+ });
500
+ }
501
+ this.buildState();
502
+ logger.success("All GraphQL documents are valid.");
503
+ } catch (e) {
504
+ this.logError(e);
505
+ throw new Error("GraphQL document validation failed.");
506
+ }
472
507
  }
473
508
  /**
474
509
  * Add a file.
@@ -477,12 +512,16 @@ class Collector {
477
512
  const file = await CollectedFile.fromFilePath(filePath);
478
513
  this.files.set(filePath, file);
479
514
  this.generator.add({
480
- filePath: this.filePathToRelative(filePath),
515
+ filePath,
481
516
  documentNode: file.parsed
482
517
  });
483
518
  return file;
484
519
  }
485
520
  async handleAdd(filePath) {
521
+ const matching = await this.getImportPatternFiles();
522
+ if (!matching.includes(filePath)) {
523
+ return false;
524
+ }
486
525
  await this.addFile(filePath);
487
526
  return true;
488
527
  }
@@ -496,7 +535,7 @@ class Collector {
496
535
  return false;
497
536
  }
498
537
  this.generator.update({
499
- filePath: this.filePathToRelative(filePath),
538
+ filePath,
500
539
  documentNode: file.parsed
501
540
  });
502
541
  return true;
@@ -507,7 +546,7 @@ class Collector {
507
546
  return false;
508
547
  }
509
548
  this.files.delete(filePath);
510
- this.generator.remove(this.filePathToRelative(filePath));
549
+ this.generator.remove(filePath);
511
550
  return true;
512
551
  }
513
552
  handleUnlinkDir(folderPath) {
@@ -544,13 +583,16 @@ class Collector {
544
583
  } catch (e) {
545
584
  this.generator.resetCaches();
546
585
  logger.error("Failed to update GraphQL code.");
547
- logger.error(e);
548
- return false;
586
+ this.logError(e);
587
+ return {
588
+ hasChanged: false,
589
+ error: { message: this.buildErrorMessage(e) }
590
+ };
549
591
  }
550
592
  if (hasChanged) {
551
- logger.success("Finished GraphQL code update.");
593
+ logger.success("Finished GraphQL code update successfully.");
552
594
  }
553
- return hasChanged;
595
+ return { hasChanged };
554
596
  }
555
597
  /**
556
598
  * Get the TypeScript types template contents.
@@ -558,11 +600,17 @@ class Collector {
558
600
  getTemplateTypes() {
559
601
  return this.outputTypes;
560
602
  }
603
+ /**
604
+ * Get the TypeScript Enums template contents.
605
+ */
606
+ getTemplateEnums() {
607
+ return this.outputEnums;
608
+ }
561
609
  /**
562
610
  * Get the context template contents.
563
611
  */
564
- getTemplateContext() {
565
- return this.outputContext;
612
+ getTemplateResponseTypes() {
613
+ return this.outputResponseTypes;
566
614
  }
567
615
  /**
568
616
  * Get the operations template contents.
@@ -570,8 +618,46 @@ class Collector {
570
618
  getTemplateOperations() {
571
619
  return this.outputOperations;
572
620
  }
621
+ /**
622
+ * Get the operation types template contents.
623
+ */
624
+ getTemplateOperationTypes() {
625
+ return this.outputOperationTypes;
626
+ }
627
+ /**
628
+ * Get the nitro types template contents.
629
+ */
630
+ getTemplateNitroTypes() {
631
+ return this.outputNitroTypes;
632
+ }
633
+ /**
634
+ * Get the nitro types template contents.
635
+ */
636
+ getTemplateSources() {
637
+ return this.outputSources;
638
+ }
639
+ }
640
+
641
+ function generateDocumentTypesTemplate() {
642
+ return `
643
+ import type { Query, Mutation } from './operations'
644
+
645
+ declare module '#nuxt-graphql-middleware/documents' {
646
+ export type Documents = {
647
+ query: Record<keyof Query, string>
648
+ mutation: Record<keyof Mutation, string>
649
+ }
650
+ export const documents: Documents
651
+ }`;
573
652
  }
574
653
 
654
+ function useViteWebSocket(nuxt) {
655
+ return new Promise((resolve) => {
656
+ nuxt.hooks.hook("vite:serverCreated", (viteServer) => {
657
+ resolve(viteServer.ws);
658
+ });
659
+ });
660
+ }
575
661
  const RPC_NAMESPACE = "nuxt-graphql-middleware";
576
662
  const module = defineNuxtModule({
577
663
  meta: {
@@ -579,14 +665,19 @@ const module = defineNuxtModule({
579
665
  configKey: "graphqlMiddleware",
580
666
  version,
581
667
  compatibility: {
582
- nuxt: ">=3.13.0"
668
+ nuxt: ">=3.15.0"
583
669
  }
584
670
  },
585
671
  defaults: defaultOptions,
586
672
  async setup(passedOptions, nuxt) {
587
673
  const options = defu({}, passedOptions, defaultOptions);
588
- function addAlias(name2, aliasPath) {
589
- nuxt.options.alias[name2] = aliasPath;
674
+ function addAlias(name2, path) {
675
+ nuxt.options.alias[name2] = path;
676
+ }
677
+ function inlineNitroExternals(path) {
678
+ nuxt.options.nitro.externals = nuxt.options.nitro.externals || {};
679
+ nuxt.options.nitro.externals.inline = nuxt.options.nitro.externals.inline || [];
680
+ nuxt.options.nitro.externals.inline.push(path);
590
681
  }
591
682
  const isModuleBuild = process.env.MODULE_BUILD === "true" && nuxt.options._prepare;
592
683
  if (isModuleBuild) {
@@ -626,12 +717,26 @@ const module = defineNuxtModule({
626
717
  });
627
718
  const runtimeDir = fileURLToPath(new URL("./runtime", import.meta.url));
628
719
  nuxt.options.build.transpile.push(runtimeDir);
720
+ const nuxtGraphqlMiddlewareBuildDir = nuxt.options.buildDir + "/nuxt-graphql-middleware";
721
+ const operationTypesBuildDir = nuxt.options.buildDir + "/graphql-operations";
722
+ const toBuildRelative = (path) => {
723
+ return relative(nuxtGraphqlMiddlewareBuildDir, path);
724
+ };
725
+ addAlias("#nuxt-graphql-middleware", nuxtGraphqlMiddlewareBuildDir);
726
+ addAlias("#graphql-operations", operationTypesBuildDir);
629
727
  const context = {
728
+ isDev: nuxt.options.dev,
630
729
  patterns: options.autoImportPatterns || [],
631
730
  srcDir: nuxt.options.srcDir,
731
+ rootDir: nuxt.options.rootDir,
632
732
  buildDir: srcResolver.resolve(nuxt.options.buildDir),
733
+ nuxtConfigPath: rootResolver.resolve("nuxt.config.ts"),
633
734
  schemaPath,
634
- serverApiPrefix: options.serverApiPrefix
735
+ serverApiPrefix: options.serverApiPrefix,
736
+ logOnlyErrors: !!options.logOnlyErrors,
737
+ runtimeTypesPath: toBuildRelative(
738
+ moduleResolver.resolve("./runtime/types.ts")
739
+ )
635
740
  };
636
741
  const collector = new Collector(
637
742
  schema,
@@ -657,9 +762,6 @@ const module = defineNuxtModule({
657
762
  });
658
763
  });
659
764
  }
660
- nuxt.options.runtimeConfig.public["nuxt-graphql-middleware"] = {
661
- serverApiPrefix: options.serverApiPrefix
662
- };
663
765
  nuxt.options.appConfig.graphqlMiddleware = {
664
766
  clientCacheEnabled: !!options.clientCache?.enabled,
665
767
  clientCacheMaxSize: options.clientCache?.maxSize || 100
@@ -693,44 +795,73 @@ const module = defineNuxtModule({
693
795
  );
694
796
  addServerImports(serverUtils);
695
797
  }
696
- const templateTypescript = addTemplate({
798
+ addTypeTemplate({
697
799
  filename: GraphqlMiddlewareTemplate.OperationTypes,
698
800
  write: true,
699
801
  getContents: () => collector.getTemplateTypes()
700
802
  });
701
- addAlias("#graphql-operations", templateTypescript.dst);
803
+ addTypeTemplate({
804
+ filename: GraphqlMiddlewareTemplate.Types,
805
+ write: true,
806
+ getContents: () => {
807
+ return `
808
+ declare module '#nuxt-graphql-middleware/sources' {
809
+ export const operationSources: Record<string, string>
810
+ }
811
+ `;
812
+ }
813
+ });
814
+ addTemplate({
815
+ filename: GraphqlMiddlewareTemplate.Enums,
816
+ write: true,
817
+ getContents: () => collector.getTemplateEnums()
818
+ });
819
+ addTemplate({
820
+ filename: GraphqlMiddlewareTemplate.OperationSources,
821
+ write: true,
822
+ getContents: () => collector.getTemplateSources()
823
+ });
824
+ addTemplate({
825
+ filename: GraphqlMiddlewareTemplate.Helpers,
826
+ write: true,
827
+ getContents: () => `export const serverApiPrefix = '${context.serverApiPrefix}'
828
+ export function getEndpoint(operation, operationName) {
829
+ return '${context.serverApiPrefix}' + '/' + operation + '/' + operationName
830
+ }
831
+ `
832
+ });
833
+ addTypeTemplate({
834
+ filename: GraphqlMiddlewareTemplate.HelpersTypes,
835
+ write: true,
836
+ getContents: () => `export const serverApiPrefix: string;
837
+ export function getEndpoint(operation: string, operationName: string): string
838
+ `
839
+ });
840
+ addTypeTemplate({
841
+ filename: GraphqlMiddlewareTemplate.NitroTypes,
842
+ write: true,
843
+ getContents: () => collector.getTemplateNitroTypes()
844
+ });
845
+ addTypeTemplate({
846
+ filename: GraphqlMiddlewareTemplate.OperationTypesAll,
847
+ write: true,
848
+ getContents: () => collector.getTemplateOperationTypes()
849
+ });
702
850
  const templateDocuments = addTemplate({
703
851
  filename: GraphqlMiddlewareTemplate.Documents,
704
852
  write: true,
705
853
  getContents: () => collector.getTemplateOperations()
706
854
  });
707
- addAlias("#graphql-documents", templateDocuments.dst);
708
- const templateContext = addTemplate({
709
- filename: GraphqlMiddlewareTemplate.ComposableContext,
855
+ inlineNitroExternals(templateDocuments.dst);
856
+ addTypeTemplate({
857
+ filename: GraphqlMiddlewareTemplate.ResponseTypes,
710
858
  write: true,
711
- getContents: () => collector.getTemplateContext()
859
+ getContents: () => collector.getTemplateResponseTypes()
712
860
  });
713
- addAlias("#nuxt-graphql-middleware/generated-types", templateContext.dst);
714
- addTemplate({
861
+ addTypeTemplate({
715
862
  write: true,
716
- filename: "nuxt-graphql-middleware/graphql-documents.d.ts",
717
- getContents: () => {
718
- return `
719
- import type {
720
- GraphqlMiddlewareQuery,
721
- GraphqlMiddlewareMutation,
722
- } from '#nuxt-graphql-middleware/generated-types'
723
-
724
- declare module '#graphql-documents' {
725
- type Operations = {
726
- query: GraphqlMiddlewareQuery
727
- mutation: GraphqlMiddlewareMutation
728
- }
729
- const operations: Operations
730
- export { operations, Operations }
731
- }
732
- `;
733
- }
863
+ filename: "nuxt-graphql-middleware/documents.d.ts",
864
+ getContents: () => generateDocumentTypesTemplate()
734
865
  });
735
866
  const findServerOptions = () => {
736
867
  const newPath = serverResolver.resolve("graphqlMiddleware.serverOptions");
@@ -755,14 +886,11 @@ declare module '#graphql-documents' {
755
886
  }
756
887
  logger.info("No graphqlMiddleware.serverOptions file found.");
757
888
  };
758
- const resolvedPath = findServerOptions();
759
- const moduleTypesPath = relative(
760
- nuxt.options.buildDir,
761
- moduleResolver.resolve("./types")
762
- );
763
- const resolvedPathRelative = resolvedPath ? relative(nuxt.options.buildDir, resolvedPath) : null;
889
+ const resolvedServerOptionsPath = findServerOptions();
890
+ const moduleTypesPath = toBuildRelative(moduleResolver.resolve("./types"));
891
+ const resolvedPathRelative = resolvedServerOptionsPath ? toBuildRelative(resolvedServerOptionsPath) : null;
764
892
  const template = addTemplate({
765
- filename: "graphqlMiddleware.serverOptions.mjs",
893
+ filename: "nuxt-graphql-middleware/server-options.mjs",
766
894
  write: true,
767
895
  getContents: () => {
768
896
  const serverOptionsLine = resolvedPathRelative ? `import serverOptions from '${resolvedPathRelative}'` : `const serverOptions = {}`;
@@ -772,26 +900,20 @@ export { serverOptions }
772
900
  `;
773
901
  }
774
902
  });
903
+ inlineNitroExternals(template.dst);
775
904
  addTemplate({
776
- filename: "graphqlMiddleware.serverOptions.d.ts",
905
+ filename: "nuxt-graphql-middleware/server-options.d.ts",
777
906
  write: true,
778
907
  getContents: () => {
779
908
  const serverOptionsLineTypes = resolvedPathRelative ? `import serverOptions from '${resolvedPathRelative}'` : `const serverOptions: GraphqlMiddlewareServerOptions = {}`;
780
909
  return `
781
910
  import type { GraphqlMiddlewareServerOptions } from '${moduleTypesPath}'
782
911
  ${serverOptionsLineTypes}
783
- import type { GraphqlServerResponse } from '${runtimeTypesPath}'
784
- import type { GraphqlMiddlewareResponseUnion } from '#nuxt-graphql-middleware/generated-types'
785
912
 
786
- type GraphqlResponseAdditions =
913
+ export type GraphqlResponseAdditions =
787
914
  typeof serverOptions extends GraphqlMiddlewareServerOptions<infer R, any, any> ? R : {}
788
915
 
789
- export type GraphqlResponse<T> = GraphqlServerResponse<T> & GraphqlResponseAdditions
790
-
791
- export type GraphqlResponseTyped = GraphqlResponse<GraphqlMiddlewareResponseUnion>
792
-
793
- export { serverOptions }
794
- `;
916
+ export { serverOptions }`;
795
917
  }
796
918
  });
797
919
  const getClientOptionsImport = () => {
@@ -799,13 +921,13 @@ export { serverOptions }
799
921
  "graphqlMiddleware.clientOptions"
800
922
  );
801
923
  if (fileExists(clientOptionsPath)) {
802
- const pathRelative = relative(nuxt.options.buildDir, clientOptionsPath);
924
+ const pathRelative = toBuildRelative(clientOptionsPath);
803
925
  return `import clientOptions from '${pathRelative}'`;
804
926
  }
805
927
  };
806
928
  const clientOptionsImport = getClientOptionsImport();
807
- const clientOptionsTemplate = addTemplate({
808
- filename: "graphqlMiddleware.clientOptions.mjs",
929
+ addTemplate({
930
+ filename: "nuxt-graphql-middleware/client-options.mjs",
809
931
  write: true,
810
932
  getContents: () => {
811
933
  if (clientOptionsImport) {
@@ -815,39 +937,25 @@ export { clientOptions }`;
815
937
  return `export const clientOptions = {}`;
816
938
  }
817
939
  });
818
- const runtimeTypesPath = relative(
819
- nuxt.options.buildDir,
820
- moduleResolver.resolve("./runtime/types.ts")
821
- );
822
940
  addTemplate({
823
- filename: "graphqlMiddleware.clientOptions.d.ts",
941
+ filename: "nuxt-graphql-middleware/client-options.d.ts",
824
942
  write: true,
825
943
  getContents: () => {
826
944
  if (clientOptionsImport) {
827
- return `import type { GraphqlClientOptions } from '${runtimeTypesPath}'
945
+ return `import type { GraphqlClientOptions } from '${context.runtimeTypesPath}'
828
946
  ${clientOptionsImport}
829
947
 
830
948
  export type GraphqlClientContext = typeof clientOptions extends GraphqlClientOptions<infer R> ? R : {}
831
949
 
832
950
  export { clientOptions }`;
833
951
  }
834
- return `import type { GraphqlClientOptions } from '${runtimeTypesPath}'
952
+ return `import type { GraphqlClientOptions } from '${context.runtimeTypesPath}'
835
953
  export const clientOptions: GraphqlClientOptions
836
954
 
837
955
  export type GraphqlClientContext = {}
838
956
  `;
839
957
  }
840
958
  });
841
- addAlias("#graphql-middleware-client-options", clientOptionsTemplate.dst);
842
- nuxt.options.nitro.externals = nuxt.options.nitro.externals || {};
843
- nuxt.options.nitro.externals.inline = nuxt.options.nitro.externals.inline || [];
844
- nuxt.options.nitro.externals.inline.push(template.dst);
845
- nuxt.options.nitro.externals.inline.push(templateDocuments.dst);
846
- addAlias("#graphql-middleware-server-options-build", template.dst);
847
- addAlias(
848
- "#graphql-middleware/types",
849
- moduleResolver.resolve("./runtime/types.ts")
850
- );
851
959
  addServerHandler({
852
960
  handler: moduleResolver.resolve("./runtime/serverHandler/index"),
853
961
  route: options.serverApiPrefix + "/:operation/:name"
@@ -861,6 +969,11 @@ export type GraphqlClientContext = {}
861
969
  addPlugin(moduleResolver.resolve("./runtime/plugins/provideState"), {
862
970
  append: false
863
971
  });
972
+ if (context.isDev && options.errorOverlay) {
973
+ addPlugin(moduleResolver.resolve("./runtime/plugins/devMode"), {
974
+ append: false
975
+ });
976
+ }
864
977
  nuxt.hook("nitro:config", (nitroConfig) => {
865
978
  nitroConfig.externals = defu(
866
979
  typeof nitroConfig.externals === "object" ? nitroConfig.externals : {},
@@ -870,10 +983,22 @@ export type GraphqlClientContext = {}
870
983
  );
871
984
  });
872
985
  if (nuxt.options.dev || nuxt.options._prepare) {
986
+ let sendError = function(error) {
987
+ wsPromise.then((ws) => {
988
+ ws.send({
989
+ type: "error",
990
+ err: {
991
+ message: error.message,
992
+ stack: ""
993
+ }
994
+ });
995
+ });
996
+ };
873
997
  addServerHandler({
874
998
  handler: moduleResolver.resolve("./runtime/serverHandler/debug"),
875
999
  route: options.serverApiPrefix + "/debug"
876
1000
  });
1001
+ const wsPromise = useViteWebSocket(nuxt);
877
1002
  nuxt.hook("builder:watch", async (event, pathAbsolute) => {
878
1003
  if (pathAbsolute === schemaPath) {
879
1004
  return;
@@ -881,9 +1006,17 @@ export type GraphqlClientContext = {}
881
1006
  if (!pathAbsolute.match(/\.(gql|graphql)$/)) {
882
1007
  return;
883
1008
  }
884
- const hasChanged = await collector.handleWatchEvent(event, pathAbsolute);
885
- if (hasChanged && rpc) {
886
- rpc.broadcast.documentsUpdated([...collector.rpcItems.values()]);
1009
+ const { hasChanged, error } = await collector.handleWatchEvent(
1010
+ event,
1011
+ pathAbsolute
1012
+ );
1013
+ if (error) {
1014
+ sendError(error);
1015
+ }
1016
+ if (hasChanged) {
1017
+ if (rpc) {
1018
+ rpc.broadcast.documentsUpdated([...collector.rpcItems.values()]);
1019
+ }
887
1020
  }
888
1021
  });
889
1022
  }