nuxt-graphql-middleware 5.0.0-alpha.5 → 5.0.0-alpha.6
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/client/200.html +7 -7
- package/dist/client/404.html +7 -7
- package/dist/client/_nuxt/{CZ2Qwgdk.js → B4KMzhZo.js} +1 -1
- package/dist/client/_nuxt/BawWjxPx.js +25 -0
- package/dist/client/_nuxt/BtHrwWER.js +1 -0
- package/dist/client/_nuxt/BvMfLM9s.js +1 -0
- package/dist/client/_nuxt/{GOrnHr4p.js → DkAo05uu.js} +1 -1
- package/dist/client/_nuxt/builds/latest.json +1 -1
- package/dist/client/_nuxt/builds/meta/9b9c571e-ce30-465b-8174-06afbdca446b.json +1 -0
- package/dist/client/index.html +7 -7
- package/dist/module.d.mts +192 -162
- package/dist/module.d.ts +192 -162
- package/dist/module.json +2 -2
- package/dist/module.mjs +889 -563
- package/dist/runtime/components/CodeFrame.vue +1 -1
- package/dist/runtime/composables/useAsyncGraphqlQuery.js +9 -1
- package/dist/runtime/server/api/mutation.js +28 -0
- package/dist/runtime/server/api/query.js +29 -0
- package/dist/runtime/server/api/upload.d.ts +2 -0
- package/dist/runtime/{serverHandler → server/api}/upload.js +11 -9
- package/dist/runtime/{serverHandler → server}/helpers/index.d.ts +8 -10
- package/dist/runtime/{serverHandler → server}/helpers/index.js +8 -25
- package/dist/runtime/server/utils/doGraphqlRequest.d.ts +18 -0
- package/dist/runtime/server/utils/doGraphqlRequest.js +67 -0
- package/dist/runtime/settings/index.d.ts +26 -2
- package/dist/runtime/settings/index.js +19 -13
- package/package.json +8 -6
- package/dist/client/_nuxt/BS583yk8.js +0 -25
- package/dist/client/_nuxt/DpxjPVZy.js +0 -1
- package/dist/client/_nuxt/builds/meta/c22c2916-33e9-427d-b6fe-10f11766c207.json +0 -1
- package/dist/client/_nuxt/exxdaCPN.js +0 -1
- package/dist/runtime/serverHandler/index.js +0 -78
- package/dist/runtime/serverHandler/tsconfig.json +0 -3
- /package/dist/runtime/{serverHandler → server/api}/debug.d.ts +0 -0
- /package/dist/runtime/{serverHandler → server/api}/debug.js +0 -0
- /package/dist/runtime/{serverHandler/index.d.ts → server/api/mutation.d.ts} +0 -0
- /package/dist/runtime/{serverHandler/upload.d.ts → server/api/query.d.ts} +0 -0
package/dist/module.mjs
CHANGED
|
@@ -1,92 +1,26 @@
|
|
|
1
|
-
import { loadSchema } from '@graphql-tools/load';
|
|
2
1
|
import { fileURLToPath } from 'url';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { useLogger, resolveFiles, defineNuxtModule, resolveAlias, createResolver, addImports, addServerImports, addTypeTemplate, addTemplate, addServerHandler, addPlugin } from '@nuxt/kit';
|
|
6
|
-
import { onDevToolsInitialized, extendServerRpc } from '@nuxt/devtools-kit';
|
|
7
|
-
import { existsSync } from 'fs';
|
|
8
|
-
import { GraphqlMiddlewareTemplate } from '../dist/runtime/settings/index.js';
|
|
2
|
+
import { useLogger, addTemplate, addServerTemplate, addTypeTemplate, resolveAlias, createResolver, resolveFiles, addPlugin, addServerHandler, addImports, addServerImports, useNitro, defineNuxtModule } from '@nuxt/kit';
|
|
3
|
+
import { Template } from '../dist/runtime/settings/index.js';
|
|
9
4
|
import fs from 'node:fs/promises';
|
|
10
|
-
import { existsSync
|
|
11
|
-
import {
|
|
12
|
-
import * as PluginSchemaAst from '@graphql-codegen/schema-ast';
|
|
5
|
+
import { existsSync, promises } from 'node:fs';
|
|
6
|
+
import { relative } from 'pathe';
|
|
13
7
|
import { basename } from 'node:path';
|
|
14
8
|
import { printSourceLocation, parse, OperationTypeNode, Source } from 'graphql';
|
|
15
9
|
import { Generator, FieldNotFoundError, TypeNotFoundError, FragmentNotFoundError } from 'graphql-typescript-deluxe';
|
|
16
|
-
import
|
|
10
|
+
import color from 'picocolors';
|
|
17
11
|
import { validateGraphQlDocuments } from '@graphql-tools/utils';
|
|
12
|
+
import { generate } from '@graphql-codegen/cli';
|
|
13
|
+
import * as PluginSchemaAst from '@graphql-codegen/schema-ast';
|
|
14
|
+
import { loadSchema } from '@graphql-tools/load';
|
|
15
|
+
import { defu } from 'defu';
|
|
16
|
+
import * as micromatch from 'micromatch';
|
|
17
|
+
import { ConfirmPrompt } from '@clack/core';
|
|
18
|
+
import isUnicodeSupported from 'is-unicode-supported';
|
|
19
|
+
import { existsSync as existsSync$1 } from 'fs';
|
|
20
|
+
import { onDevToolsInitialized, extendServerRpc } from '@nuxt/devtools-kit';
|
|
18
21
|
|
|
19
22
|
const name = "nuxt-graphql-middleware";
|
|
20
|
-
const version = "5.0.0-alpha.
|
|
21
|
-
|
|
22
|
-
const DEVTOOLS_UI_ROUTE = "/__nuxt-graphql-middleware";
|
|
23
|
-
const DEVTOOLS_UI_LOCAL_PORT = 3300;
|
|
24
|
-
function setupDevToolsUI(nuxt, clientPath) {
|
|
25
|
-
const isProductionBuild = existsSync(clientPath);
|
|
26
|
-
if (isProductionBuild) {
|
|
27
|
-
nuxt.hook("vite:serverCreated", async (server) => {
|
|
28
|
-
const sirv = await import('sirv').then((r) => r.default || r);
|
|
29
|
-
server.middlewares.use(
|
|
30
|
-
DEVTOOLS_UI_ROUTE,
|
|
31
|
-
sirv(clientPath, { dev: true, single: true })
|
|
32
|
-
);
|
|
33
|
-
});
|
|
34
|
-
} else {
|
|
35
|
-
nuxt.hook("vite:extendConfig", (config) => {
|
|
36
|
-
config.server = config.server || {};
|
|
37
|
-
config.server.proxy = config.server.proxy || {};
|
|
38
|
-
config.server.proxy[DEVTOOLS_UI_ROUTE] = {
|
|
39
|
-
target: "http://localhost:" + DEVTOOLS_UI_LOCAL_PORT + DEVTOOLS_UI_ROUTE,
|
|
40
|
-
changeOrigin: true,
|
|
41
|
-
followRedirects: true,
|
|
42
|
-
rewrite: (path) => path.replace(DEVTOOLS_UI_ROUTE, "")
|
|
43
|
-
};
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
nuxt.hook("devtools:customTabs", (tabs) => {
|
|
47
|
-
tabs.push({
|
|
48
|
-
// unique identifier
|
|
49
|
-
name: "nuxt-graphql-middleware",
|
|
50
|
-
// title to display in the tab
|
|
51
|
-
title: "GraphQL Middleware",
|
|
52
|
-
// any icon from Iconify, or a URL to an image
|
|
53
|
-
icon: "akar-icons:graphql-fill",
|
|
54
|
-
// iframe view
|
|
55
|
-
view: {
|
|
56
|
-
type: "iframe",
|
|
57
|
-
src: DEVTOOLS_UI_ROUTE
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function pluginLoader(name) {
|
|
64
|
-
switch (name) {
|
|
65
|
-
case "@graphql-codegen/schema-ast":
|
|
66
|
-
return Promise.resolve(PluginSchemaAst);
|
|
67
|
-
}
|
|
68
|
-
throw new Error(`graphql-codegen plugin not found: ${name}`);
|
|
69
|
-
}
|
|
70
|
-
function generateSchema(moduleOptions, dest, writeToDisk) {
|
|
71
|
-
const pluginConfig = moduleOptions.codegenSchemaConfig?.urlSchemaOptions;
|
|
72
|
-
const schemaAstConfig = moduleOptions.codegenSchemaConfig?.schemaAstConfig || {
|
|
73
|
-
sort: true
|
|
74
|
-
};
|
|
75
|
-
const config = {
|
|
76
|
-
schema: moduleOptions.graphqlEndpoint,
|
|
77
|
-
pluginLoader,
|
|
78
|
-
silent: true,
|
|
79
|
-
errorsOnly: true,
|
|
80
|
-
config: pluginConfig,
|
|
81
|
-
generates: {
|
|
82
|
-
[dest]: {
|
|
83
|
-
plugins: ["schema-ast"],
|
|
84
|
-
config: schemaAstConfig
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
};
|
|
88
|
-
return generate(config, writeToDisk).then((v) => v[0]);
|
|
89
|
-
}
|
|
23
|
+
const version = "5.0.0-alpha.6";
|
|
90
24
|
|
|
91
25
|
const logger = useLogger(name);
|
|
92
26
|
const defaultOptions = {
|
|
@@ -98,59 +32,26 @@ const defaultOptions = {
|
|
|
98
32
|
includeComposables: true,
|
|
99
33
|
documents: [],
|
|
100
34
|
devtools: true,
|
|
101
|
-
errorOverlay: true
|
|
35
|
+
errorOverlay: true,
|
|
36
|
+
graphqlConfigFilePath: "./graphql.config.ts"
|
|
102
37
|
};
|
|
103
38
|
function validateOptions(options) {
|
|
104
39
|
if (!options.graphqlEndpoint) {
|
|
105
40
|
throw new Error("Missing graphqlEndpoint.");
|
|
106
41
|
}
|
|
107
42
|
}
|
|
108
|
-
async function getSchemaPath(schemaPath, options, resolver, writeToDisk = false) {
|
|
109
|
-
const dest = resolver(schemaPath);
|
|
110
|
-
if (!options.downloadSchema) {
|
|
111
|
-
const fileExists2 = await fs.access(dest).then(() => true).catch(() => false);
|
|
112
|
-
if (!fileExists2) {
|
|
113
|
-
logger.error(
|
|
114
|
-
'"downloadSchema" is set to false but no schema exists at ' + dest
|
|
115
|
-
);
|
|
116
|
-
throw new Error("Missing GraphQL schema.");
|
|
117
|
-
}
|
|
118
|
-
const schemaContent = await fs.readFile(dest).then((v) => v.toString());
|
|
119
|
-
return { schemaPath, schemaContent };
|
|
120
|
-
}
|
|
121
|
-
if (!options.graphqlEndpoint) {
|
|
122
|
-
throw new Error("Missing graphqlEndpoint config.");
|
|
123
|
-
}
|
|
124
|
-
const result = await generateSchema(options, dest, writeToDisk);
|
|
125
|
-
return { schemaPath, schemaContent: result.content };
|
|
126
|
-
}
|
|
127
43
|
const fileExists = (path, extensions = ["js", "ts", "mjs"]) => {
|
|
128
44
|
if (!path) {
|
|
129
45
|
return null;
|
|
130
|
-
} else if (existsSync
|
|
46
|
+
} else if (existsSync(path)) {
|
|
131
47
|
return path;
|
|
132
48
|
}
|
|
133
49
|
const extension = extensions.find(
|
|
134
|
-
(extension2) => existsSync
|
|
50
|
+
(extension2) => existsSync(`${path}.${extension2}`)
|
|
135
51
|
);
|
|
136
52
|
return extension ? `${path}.${extension}` : null;
|
|
137
53
|
};
|
|
138
54
|
|
|
139
|
-
function generateResponseTypeTemplate(operations, context) {
|
|
140
|
-
const allTypes = operations.map((v) => v.typeName).sort();
|
|
141
|
-
return `import type {
|
|
142
|
-
${allTypes.join(",\n ")}
|
|
143
|
-
} from './../graphql-operations'
|
|
144
|
-
import type { GraphqlResponseAdditions } from './server-options'
|
|
145
|
-
import type { GraphqlServerResponse } from '${context.runtimeTypesPath}'
|
|
146
|
-
|
|
147
|
-
export type GraphqlMiddlewareResponseUnion =
|
|
148
|
-
| ${allTypes.join("\n | ") || "never"}
|
|
149
|
-
|
|
150
|
-
export type GraphqlResponse<T> = GraphqlServerResponse<T> & GraphqlResponseAdditions
|
|
151
|
-
export type GraphqlResponseTyped = GraphqlResponse<GraphqlMiddlewareResponseUnion>`;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
55
|
const SYMBOL_CROSS = "x";
|
|
155
56
|
const SYMBOL_CHECK = "\u2714";
|
|
156
57
|
function getMaxLengths(entries) {
|
|
@@ -175,11 +76,11 @@ function logAllEntries(entries) {
|
|
|
175
76
|
let prevHadError = false;
|
|
176
77
|
for (const entry of entries) {
|
|
177
78
|
const hasErrors = entry.errors.length > 0;
|
|
178
|
-
const icon = hasErrors ?
|
|
79
|
+
const icon = hasErrors ? color.red(SYMBOL_CROSS) : color.green(SYMBOL_CHECK);
|
|
179
80
|
const type = entry.type.padEnd(lengths.type);
|
|
180
|
-
const namePadded =
|
|
181
|
-
const name = hasErrors ?
|
|
182
|
-
const path =
|
|
81
|
+
const namePadded = color.bold(entry.name.padEnd(lengths.name));
|
|
82
|
+
const name = hasErrors ? color.red(namePadded) : color.green(namePadded);
|
|
83
|
+
const path = color.dim(entry.path);
|
|
183
84
|
const parts = [icon, type, name, path];
|
|
184
85
|
if (hasErrors && !prevHadError) {
|
|
185
86
|
process.stdout.write("-".repeat(process.stdout.columns) + "\n");
|
|
@@ -188,10 +89,10 @@ function logAllEntries(entries) {
|
|
|
188
89
|
if (hasErrors) {
|
|
189
90
|
const errorLines = [];
|
|
190
91
|
entry.errors.forEach((error) => {
|
|
191
|
-
let output =
|
|
92
|
+
let output = color.red(error.message);
|
|
192
93
|
if (error.source && error.locations) {
|
|
193
94
|
for (const location of error.locations) {
|
|
194
|
-
output += "\n\n" +
|
|
95
|
+
output += "\n\n" + color.red(printSourceLocation(error.source, location));
|
|
195
96
|
}
|
|
196
97
|
}
|
|
197
98
|
errorLines.push(output);
|
|
@@ -238,7 +139,24 @@ class CollectedFile {
|
|
|
238
139
|
}
|
|
239
140
|
}
|
|
240
141
|
|
|
241
|
-
function
|
|
142
|
+
function ResponseTypes(operations, helper) {
|
|
143
|
+
const allTypes = operations.map((v) => v.typeName).sort();
|
|
144
|
+
return `import type {
|
|
145
|
+
${allTypes.join(",\n ")}
|
|
146
|
+
} from './../graphql-operations'
|
|
147
|
+
import type { GraphqlResponseAdditions } from './server-options'
|
|
148
|
+
import type { GraphqlServerResponse } from '${helper.paths.runtimeTypes}'
|
|
149
|
+
|
|
150
|
+
declare module '#nuxt-graphql-middleware/response' {
|
|
151
|
+
export type GraphqlMiddlewareResponseUnion =
|
|
152
|
+
| ${allTypes.join("\n | ") || "never"}
|
|
153
|
+
|
|
154
|
+
export type GraphqlResponse<T> = GraphqlServerResponse<T> & GraphqlResponseAdditions
|
|
155
|
+
export type GraphqlResponseTyped = GraphqlResponse<GraphqlMiddlewareResponseUnion>
|
|
156
|
+
}`;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function NitroTypes(operations, serverApiPrefix) {
|
|
242
160
|
const endpoints = [];
|
|
243
161
|
const imports = [];
|
|
244
162
|
for (const operation of operations) {
|
|
@@ -262,7 +180,7 @@ ${endpoints.sort().join("\n")}
|
|
|
262
180
|
}`;
|
|
263
181
|
}
|
|
264
182
|
|
|
265
|
-
function
|
|
183
|
+
function OperationSources(operations, srcDir) {
|
|
266
184
|
const lines = [];
|
|
267
185
|
for (const operation of operations) {
|
|
268
186
|
const filePath = relative(srcDir, operation.filePath);
|
|
@@ -277,12 +195,24 @@ export const operationSources = {
|
|
|
277
195
|
`;
|
|
278
196
|
}
|
|
279
197
|
|
|
198
|
+
function OperationTypes(generatorOutput) {
|
|
199
|
+
const typesFile = generatorOutput.getTypes();
|
|
200
|
+
let output = "";
|
|
201
|
+
const enumImports = typesFile.getTypeScriptEnumDependencies();
|
|
202
|
+
if (enumImports.length) {
|
|
203
|
+
output += `import type { ${enumImports.join(", ")} } from './enums'
|
|
204
|
+
|
|
205
|
+
`;
|
|
206
|
+
}
|
|
207
|
+
output += typesFile.getSource();
|
|
208
|
+
return output;
|
|
209
|
+
}
|
|
210
|
+
|
|
280
211
|
class Collector {
|
|
281
|
-
constructor(schema,
|
|
212
|
+
constructor(schema, helper) {
|
|
282
213
|
this.schema = schema;
|
|
283
|
-
this.
|
|
284
|
-
|
|
285
|
-
const mappedOptions = { ...generatorOptions };
|
|
214
|
+
this.helper = helper;
|
|
215
|
+
const mappedOptions = { ...helper.options.codegenConfig };
|
|
286
216
|
if (!mappedOptions.output) {
|
|
287
217
|
mappedOptions.output = {};
|
|
288
218
|
}
|
|
@@ -310,35 +240,23 @@ class Collector {
|
|
|
310
240
|
*/
|
|
311
241
|
rpcItems = /* @__PURE__ */ new Map();
|
|
312
242
|
/**
|
|
313
|
-
* The generated
|
|
314
|
-
*/
|
|
315
|
-
outputTypes = "";
|
|
316
|
-
/**
|
|
317
|
-
* The generated TypeScript enum template output.
|
|
318
|
-
*/
|
|
319
|
-
outputEnums = "";
|
|
320
|
-
/**
|
|
321
|
-
* The generated oeprations file.
|
|
322
|
-
*/
|
|
323
|
-
outputOperations = "";
|
|
324
|
-
/**
|
|
325
|
-
* The generated oepration types file.
|
|
243
|
+
* The generated templates.
|
|
326
244
|
*/
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
245
|
+
templates = /* @__PURE__ */ new Map();
|
|
246
|
+
async reset() {
|
|
247
|
+
this.files.clear();
|
|
248
|
+
this.generator.reset();
|
|
249
|
+
this.operationTimestamps.clear();
|
|
250
|
+
this.rpcItems.clear();
|
|
251
|
+
}
|
|
252
|
+
async updateSchema(schema) {
|
|
253
|
+
this.schema = schema;
|
|
254
|
+
this.generator.updateSchema(schema);
|
|
255
|
+
await this.reset();
|
|
256
|
+
await this.initDocuments();
|
|
257
|
+
}
|
|
340
258
|
filePathToBuildRelative(filePath) {
|
|
341
|
-
return "./" +
|
|
259
|
+
return "./" + this.helper.toBuildRelative(filePath);
|
|
342
260
|
}
|
|
343
261
|
filePathToSourceRelative(filePath) {
|
|
344
262
|
return "./" + relative(process.cwd(), filePath);
|
|
@@ -351,16 +269,15 @@ class Collector {
|
|
|
351
269
|
errors
|
|
352
270
|
};
|
|
353
271
|
}
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
272
|
+
updateTemplate(template, content) {
|
|
273
|
+
this.templates.set(template, content);
|
|
274
|
+
}
|
|
275
|
+
getTemplate(template) {
|
|
276
|
+
const content = this.templates.get(template);
|
|
277
|
+
if (content === void 0) {
|
|
278
|
+
throw new Error(`Missing template content: ${template}`);
|
|
361
279
|
}
|
|
362
|
-
|
|
363
|
-
return output;
|
|
280
|
+
return content;
|
|
364
281
|
}
|
|
365
282
|
/**
|
|
366
283
|
* Executes code gen and performs validation for operations.
|
|
@@ -369,26 +286,32 @@ class Collector {
|
|
|
369
286
|
const output = this.generator.build();
|
|
370
287
|
const operations = output.getCollectedOperations();
|
|
371
288
|
const generatedCode = output.getGeneratedCode();
|
|
372
|
-
this.
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
this.
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
289
|
+
this.updateTemplate(
|
|
290
|
+
Template.Documents,
|
|
291
|
+
output.getOperationsFile({
|
|
292
|
+
exportName: "documents",
|
|
293
|
+
minify: !this.helper.isDev
|
|
294
|
+
}).getSource()
|
|
295
|
+
);
|
|
296
|
+
this.updateTemplate(
|
|
297
|
+
Template.OperationTypesAll,
|
|
298
|
+
output.getOperationTypesFile({
|
|
299
|
+
importFrom: "./../graphql-operations"
|
|
300
|
+
}).getSource()
|
|
384
301
|
);
|
|
385
|
-
this.
|
|
386
|
-
|
|
387
|
-
this.
|
|
302
|
+
this.updateTemplate(
|
|
303
|
+
Template.NitroTypes,
|
|
304
|
+
NitroTypes(operations, this.helper.options.serverApiPrefix)
|
|
388
305
|
);
|
|
389
|
-
this.
|
|
390
|
-
|
|
391
|
-
|
|
306
|
+
this.updateTemplate(Template.OperationTypes, OperationTypes(output));
|
|
307
|
+
this.updateTemplate(
|
|
308
|
+
Template.ResponseTypes,
|
|
309
|
+
ResponseTypes(operations, this.helper)
|
|
310
|
+
);
|
|
311
|
+
this.updateTemplate(Template.Enums, output.buildFile(["enum"]).getSource());
|
|
312
|
+
this.updateTemplate(
|
|
313
|
+
Template.OperationSources,
|
|
314
|
+
OperationSources(operations, this.helper.paths.root)
|
|
392
315
|
);
|
|
393
316
|
const fragmentMap = /* @__PURE__ */ new Map();
|
|
394
317
|
const operationSourceMap = /* @__PURE__ */ new Map();
|
|
@@ -418,7 +341,7 @@ class Collector {
|
|
|
418
341
|
} else {
|
|
419
342
|
this.operationTimestamps.set(operation.graphqlName, operation.timestamp);
|
|
420
343
|
}
|
|
421
|
-
const shouldLog = errors.length || !this.
|
|
344
|
+
const shouldLog = errors.length || !this.helper.options.logOnlyErrors;
|
|
422
345
|
if (shouldLog) {
|
|
423
346
|
logEntries.push(this.operationToLogEntry(operation, errors));
|
|
424
347
|
}
|
|
@@ -466,31 +389,45 @@ class Collector {
|
|
|
466
389
|
logError(error) {
|
|
467
390
|
let output = `${SYMBOL_CROSS}`;
|
|
468
391
|
output += this.buildErrorMessage(error);
|
|
469
|
-
logger.error(
|
|
392
|
+
logger.error(color.red(output));
|
|
470
393
|
}
|
|
471
394
|
/**
|
|
472
|
-
*
|
|
395
|
+
* Initialise the collector.
|
|
396
|
+
*
|
|
397
|
+
* In dev mode, the method will call itself recursively until all documents
|
|
398
|
+
* are valid.
|
|
399
|
+
*
|
|
400
|
+
* If not in dev mode the method will throw an error when documents are not
|
|
401
|
+
* valid.
|
|
473
402
|
*/
|
|
474
|
-
async
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
403
|
+
async init() {
|
|
404
|
+
try {
|
|
405
|
+
await this.initDocuments();
|
|
406
|
+
} catch (e) {
|
|
407
|
+
if (this.helper.isDev) {
|
|
408
|
+
const shouldRevalidate = await this.helper.prompt.confirm(
|
|
409
|
+
"Do you want to revalidate the GraphQL documents?"
|
|
410
|
+
);
|
|
411
|
+
if (shouldRevalidate === "yes") {
|
|
412
|
+
await this.reset();
|
|
413
|
+
return this.init();
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
throw new Error("Graphql document validation failed.");
|
|
479
417
|
}
|
|
480
|
-
return [];
|
|
481
418
|
}
|
|
482
419
|
/**
|
|
483
420
|
* Initialise the collector.
|
|
484
421
|
*/
|
|
485
|
-
async
|
|
422
|
+
async initDocuments() {
|
|
486
423
|
try {
|
|
487
|
-
const files = await this.getImportPatternFiles();
|
|
424
|
+
const files = await this.helper.getImportPatternFiles();
|
|
488
425
|
for (const filePath of files) {
|
|
489
426
|
await this.addFile(filePath);
|
|
490
427
|
}
|
|
491
|
-
const nuxtConfigDocuments = this.
|
|
428
|
+
const nuxtConfigDocuments = this.helper.options.documents.join("\n\n");
|
|
492
429
|
if (nuxtConfigDocuments.length) {
|
|
493
|
-
const filePath = this.
|
|
430
|
+
const filePath = this.helper.paths.nuxtConfig;
|
|
494
431
|
const file = new CollectedFile(filePath, nuxtConfigDocuments, false);
|
|
495
432
|
this.files.set(filePath, file);
|
|
496
433
|
this.generator.add({
|
|
@@ -510,6 +447,9 @@ class Collector {
|
|
|
510
447
|
*/
|
|
511
448
|
async addFile(filePath) {
|
|
512
449
|
const file = await CollectedFile.fromFilePath(filePath);
|
|
450
|
+
if (!file.fileContents) {
|
|
451
|
+
return null;
|
|
452
|
+
}
|
|
513
453
|
this.files.set(filePath, file);
|
|
514
454
|
this.generator.add({
|
|
515
455
|
filePath,
|
|
@@ -518,26 +458,32 @@ class Collector {
|
|
|
518
458
|
return file;
|
|
519
459
|
}
|
|
520
460
|
async handleAdd(filePath) {
|
|
521
|
-
|
|
522
|
-
if (!matching.includes(filePath)) {
|
|
461
|
+
if (!this.helper.matchesImportPattern(filePath)) {
|
|
523
462
|
return false;
|
|
524
463
|
}
|
|
525
|
-
await this.addFile(filePath);
|
|
526
|
-
return
|
|
464
|
+
const result = await this.addFile(filePath);
|
|
465
|
+
return !!result;
|
|
527
466
|
}
|
|
528
467
|
async handleChange(filePath) {
|
|
468
|
+
if (!this.helper.matchesImportPattern(filePath)) {
|
|
469
|
+
return false;
|
|
470
|
+
}
|
|
529
471
|
const file = this.files.get(filePath);
|
|
530
472
|
if (!file) {
|
|
531
|
-
return
|
|
473
|
+
return this.handleAdd(filePath);
|
|
532
474
|
}
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
475
|
+
try {
|
|
476
|
+
const needsUpdate = await file.update();
|
|
477
|
+
if (!needsUpdate) {
|
|
478
|
+
return false;
|
|
479
|
+
}
|
|
480
|
+
this.generator.update({
|
|
481
|
+
filePath,
|
|
482
|
+
documentNode: file.parsed
|
|
483
|
+
});
|
|
484
|
+
} catch {
|
|
485
|
+
return this.handleUnlink(filePath);
|
|
536
486
|
}
|
|
537
|
-
this.generator.update({
|
|
538
|
-
filePath,
|
|
539
|
-
documentNode: file.parsed
|
|
540
|
-
});
|
|
541
487
|
return true;
|
|
542
488
|
}
|
|
543
489
|
handleUnlink(filePath) {
|
|
@@ -566,6 +512,7 @@ class Collector {
|
|
|
566
512
|
*/
|
|
567
513
|
async handleWatchEvent(event, filePath) {
|
|
568
514
|
let hasChanged = false;
|
|
515
|
+
const oldOperationTimestamps = new Map(this.operationTimestamps);
|
|
569
516
|
try {
|
|
570
517
|
if (event === "add") {
|
|
571
518
|
hasChanged = await this.handleAdd(filePath);
|
|
@@ -575,7 +522,6 @@ class Collector {
|
|
|
575
522
|
hasChanged = this.handleUnlink(filePath);
|
|
576
523
|
} else if (event === "unlinkDir") {
|
|
577
524
|
hasChanged = this.handleUnlinkDir(filePath);
|
|
578
|
-
} else if (event === "addDir") {
|
|
579
525
|
}
|
|
580
526
|
if (hasChanged) {
|
|
581
527
|
this.buildState();
|
|
@@ -586,327 +532,537 @@ class Collector {
|
|
|
586
532
|
this.logError(e);
|
|
587
533
|
return {
|
|
588
534
|
hasChanged: false,
|
|
535
|
+
affectedOperations: [],
|
|
589
536
|
error: { message: this.buildErrorMessage(e) }
|
|
590
537
|
};
|
|
591
538
|
}
|
|
539
|
+
const affectedOperations = [];
|
|
592
540
|
if (hasChanged) {
|
|
593
541
|
logger.success("Finished GraphQL code update successfully.");
|
|
542
|
+
for (const [name, newTimestamp] of this.operationTimestamps) {
|
|
543
|
+
const oldTimestamp = oldOperationTimestamps.get(name);
|
|
544
|
+
if (!oldTimestamp || oldTimestamp !== newTimestamp) {
|
|
545
|
+
affectedOperations.push(name);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
594
548
|
}
|
|
595
|
-
return { hasChanged };
|
|
549
|
+
return { hasChanged, affectedOperations };
|
|
596
550
|
}
|
|
597
551
|
/**
|
|
598
|
-
*
|
|
552
|
+
* Adds a virtual template (not written to disk) for both Nuxt and Nitro.
|
|
553
|
+
*
|
|
554
|
+
* For some reason a template written to disk works for both Nuxt and Nitro,
|
|
555
|
+
* but a virtual template requires adding two templates.
|
|
599
556
|
*/
|
|
600
|
-
|
|
601
|
-
|
|
557
|
+
addVirtualTemplate(template) {
|
|
558
|
+
const getContents = () => this.getTemplate(template);
|
|
559
|
+
addTemplate({
|
|
560
|
+
filename: template,
|
|
561
|
+
getContents
|
|
562
|
+
});
|
|
563
|
+
addServerTemplate({
|
|
564
|
+
// Since this is a virtual template, the name must match the final
|
|
565
|
+
// alias, example:
|
|
566
|
+
// - nuxt-graphql-middleware/foobar.mjs => #nuxt-graphql-middleware/foobar
|
|
567
|
+
//
|
|
568
|
+
// That way we can reference the same template using the alias in both
|
|
569
|
+
// Nuxt and Nitro environments.
|
|
570
|
+
filename: "#" + template.replace(".mjs", ""),
|
|
571
|
+
getContents
|
|
572
|
+
});
|
|
602
573
|
}
|
|
603
574
|
/**
|
|
604
|
-
*
|
|
575
|
+
* Adds a template that dependes on Collector state.
|
|
605
576
|
*/
|
|
606
|
-
|
|
607
|
-
|
|
577
|
+
addTemplate(template) {
|
|
578
|
+
if (template.endsWith(".d.ts")) {
|
|
579
|
+
addTypeTemplate(
|
|
580
|
+
{
|
|
581
|
+
filename: template,
|
|
582
|
+
write: true,
|
|
583
|
+
getContents: () => this.getTemplate(template)
|
|
584
|
+
},
|
|
585
|
+
{
|
|
586
|
+
nuxt: true,
|
|
587
|
+
nitro: true
|
|
588
|
+
}
|
|
589
|
+
);
|
|
590
|
+
} else {
|
|
591
|
+
addTemplate({
|
|
592
|
+
filename: template,
|
|
593
|
+
write: true,
|
|
594
|
+
getContents: () => this.getTemplate(template)
|
|
595
|
+
});
|
|
596
|
+
}
|
|
608
597
|
}
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
class SchemaProvider {
|
|
601
|
+
constructor(helper) {
|
|
602
|
+
this.helper = helper;
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* The raw schema content.
|
|
606
|
+
*/
|
|
607
|
+
schemaContent = "";
|
|
609
608
|
/**
|
|
610
|
-
*
|
|
609
|
+
* The parsed schema object.
|
|
611
610
|
*/
|
|
612
|
-
|
|
613
|
-
|
|
611
|
+
schema = null;
|
|
612
|
+
async init() {
|
|
613
|
+
try {
|
|
614
|
+
await this.loadSchema();
|
|
615
|
+
} catch (error) {
|
|
616
|
+
logger.error(error);
|
|
617
|
+
const hasLoaded = await this.loadFromDiskFallback();
|
|
618
|
+
if (!hasLoaded) {
|
|
619
|
+
throw new Error("Failed to load GraphQL schema.");
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
async loadFromDiskFallback() {
|
|
624
|
+
const hasSchemaOnDisk = await this.hasSchemaOnDisk();
|
|
625
|
+
if (this.helper.isDev && hasSchemaOnDisk && this.helper.options.downloadSchema) {
|
|
626
|
+
const shouldUseFromDisk = await this.helper.prompt.confirm(
|
|
627
|
+
"Do you want to continue with the previously downloaded schema from disk?"
|
|
628
|
+
);
|
|
629
|
+
if (shouldUseFromDisk === "yes") {
|
|
630
|
+
await this.loadSchema({ forceDisk: true });
|
|
631
|
+
return true;
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
return false;
|
|
614
635
|
}
|
|
615
636
|
/**
|
|
616
|
-
*
|
|
637
|
+
* Loads the schema from disk.
|
|
638
|
+
*
|
|
639
|
+
* @returns The schema contents from disk.
|
|
617
640
|
*/
|
|
618
|
-
|
|
619
|
-
|
|
641
|
+
async loadSchemaFromDisk() {
|
|
642
|
+
const fileExists = await this.hasSchemaOnDisk();
|
|
643
|
+
if (!fileExists) {
|
|
644
|
+
logger.error(
|
|
645
|
+
'"downloadSchema" is set to false but no schema exists at ' + this.helper.paths.schema
|
|
646
|
+
);
|
|
647
|
+
throw new Error("Missing GraphQL schema.");
|
|
648
|
+
}
|
|
649
|
+
logger.info(`Loading GraphQL schema from disk: ${this.helper.paths.schema}`);
|
|
650
|
+
return await fs.readFile(this.helper.paths.schema).then((v) => v.toString());
|
|
620
651
|
}
|
|
621
652
|
/**
|
|
622
|
-
*
|
|
653
|
+
* Downloads the schema and saves it to disk.
|
|
654
|
+
*
|
|
655
|
+
* @returns The schema contents.
|
|
623
656
|
*/
|
|
624
|
-
|
|
625
|
-
|
|
657
|
+
downloadSchema() {
|
|
658
|
+
const endpoint = this.helper.options.graphqlEndpoint;
|
|
659
|
+
if (!endpoint) {
|
|
660
|
+
throw new Error("Missing graphqlEndpoint config.");
|
|
661
|
+
}
|
|
662
|
+
const pluginConfig = this.helper.options.codegenSchemaConfig?.urlSchemaOptions;
|
|
663
|
+
const schemaAstConfig = this.helper.options.codegenSchemaConfig?.schemaAstConfig || {
|
|
664
|
+
sort: true
|
|
665
|
+
};
|
|
666
|
+
const config = {
|
|
667
|
+
schema: endpoint,
|
|
668
|
+
pluginLoader: (name) => {
|
|
669
|
+
switch (name) {
|
|
670
|
+
case "@graphql-codegen/schema-ast":
|
|
671
|
+
return Promise.resolve(PluginSchemaAst);
|
|
672
|
+
}
|
|
673
|
+
throw new Error(`graphql-codegen plugin not found: ${name}`);
|
|
674
|
+
},
|
|
675
|
+
silent: true,
|
|
676
|
+
errorsOnly: true,
|
|
677
|
+
config: pluginConfig,
|
|
678
|
+
generates: {
|
|
679
|
+
[this.helper.paths.schema]: {
|
|
680
|
+
plugins: ["schema-ast"],
|
|
681
|
+
config: schemaAstConfig
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
};
|
|
685
|
+
logger.info(`Downloading GraphQL schema from "${endpoint}".`);
|
|
686
|
+
return generate(config, true).then((v) => v[0]?.content);
|
|
626
687
|
}
|
|
627
688
|
/**
|
|
628
|
-
*
|
|
689
|
+
* Determine if the schema exists on disk.
|
|
690
|
+
*
|
|
691
|
+
* @returns True if the schema file exists on disk.
|
|
629
692
|
*/
|
|
630
|
-
|
|
631
|
-
return this.
|
|
693
|
+
hasSchemaOnDisk() {
|
|
694
|
+
return fs.access(this.helper.paths.schema).then(() => true).catch(() => false);
|
|
632
695
|
}
|
|
633
696
|
/**
|
|
634
|
-
*
|
|
697
|
+
* Load the schema either from disk or by downloading it.
|
|
698
|
+
*
|
|
699
|
+
* @param forceDownload - Forces downloading the schema.
|
|
635
700
|
*/
|
|
636
|
-
|
|
637
|
-
|
|
701
|
+
async loadSchema(opts) {
|
|
702
|
+
if (opts?.forceDisk) {
|
|
703
|
+
this.schemaContent = await this.loadSchemaFromDisk();
|
|
704
|
+
} else if (this.helper.options.downloadSchema || opts?.forceDownload) {
|
|
705
|
+
this.schemaContent = await this.downloadSchema();
|
|
706
|
+
} else {
|
|
707
|
+
this.schemaContent = await this.loadSchemaFromDisk();
|
|
708
|
+
}
|
|
709
|
+
this.schema = await loadSchema(this.schemaContent, {
|
|
710
|
+
loaders: []
|
|
711
|
+
});
|
|
638
712
|
}
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
713
|
+
/**
|
|
714
|
+
* Get the schema.
|
|
715
|
+
*
|
|
716
|
+
* @returns The parsed GraphQL schema object.
|
|
717
|
+
*/
|
|
718
|
+
getSchema() {
|
|
719
|
+
if (!this.schema) {
|
|
720
|
+
throw new Error("Failed to load schema.");
|
|
721
|
+
}
|
|
722
|
+
return this.schema;
|
|
649
723
|
}
|
|
650
|
-
export const documents: Documents
|
|
651
|
-
}`;
|
|
652
724
|
}
|
|
653
725
|
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
726
|
+
const unicode = isUnicodeSupported();
|
|
727
|
+
const s = (c, fallback) => unicode ? c : fallback;
|
|
728
|
+
const S_BAR = s("\u2502", "|");
|
|
729
|
+
const S_STEP_ACTIVE = s("\u25C6", "*");
|
|
730
|
+
const S_STEP_CANCEL = s("\u25A0", "x");
|
|
731
|
+
const S_STEP_ERROR = s("\u25B2", "x");
|
|
732
|
+
const S_STEP_SUBMIT = s("\u25C7", "o");
|
|
733
|
+
const S_RADIO_ACTIVE = s("\u25CF", ">");
|
|
734
|
+
const S_RADIO_INACTIVE = s("\u25CB", " ");
|
|
735
|
+
const S_BAR_END = s("\u2514", "\u2014");
|
|
736
|
+
const symbol = (state) => {
|
|
737
|
+
switch (state) {
|
|
738
|
+
case "initial":
|
|
739
|
+
case "active":
|
|
740
|
+
return color.cyan(S_STEP_ACTIVE);
|
|
741
|
+
case "cancel":
|
|
742
|
+
return color.red(S_STEP_CANCEL);
|
|
743
|
+
case "error":
|
|
744
|
+
return color.yellow(S_STEP_ERROR);
|
|
745
|
+
case "submit":
|
|
746
|
+
return color.green(S_STEP_SUBMIT);
|
|
747
|
+
}
|
|
748
|
+
};
|
|
749
|
+
class ConsolePrompt {
|
|
750
|
+
abortController = null;
|
|
751
|
+
confirm(message) {
|
|
752
|
+
this.abort();
|
|
753
|
+
this.abortController = new AbortController();
|
|
754
|
+
const active = "Yes";
|
|
755
|
+
const inactive = "No";
|
|
756
|
+
return new ConfirmPrompt({
|
|
757
|
+
active,
|
|
758
|
+
inactive,
|
|
759
|
+
initialValue: true,
|
|
760
|
+
signal: this.abortController.signal,
|
|
761
|
+
render() {
|
|
762
|
+
const title = `${color.gray(S_BAR)}
|
|
763
|
+
${symbol(this.state)} ${message}
|
|
764
|
+
`;
|
|
765
|
+
const value = this.value ? active : inactive;
|
|
766
|
+
switch (this.state) {
|
|
767
|
+
case "submit":
|
|
768
|
+
return `${title}${color.gray(S_BAR)} ${color.dim(value)}`;
|
|
769
|
+
case "cancel":
|
|
770
|
+
return `${title}${color.gray(S_BAR)} ${color.strikethrough(
|
|
771
|
+
color.dim(value)
|
|
772
|
+
)}
|
|
773
|
+
${color.gray(S_BAR)}`;
|
|
774
|
+
default: {
|
|
775
|
+
return `${title}${color.cyan(S_BAR)} ${this.value ? `${color.green(S_RADIO_ACTIVE)} ${active}` : `${color.dim(S_RADIO_INACTIVE)} ${color.dim(active)}`} ${color.dim("/")} ${!this.value ? `${color.green(S_RADIO_ACTIVE)} ${inactive}` : `${color.dim(S_RADIO_INACTIVE)} ${color.dim(inactive)}`}
|
|
776
|
+
${color.cyan(S_BAR_END)}
|
|
777
|
+
`;
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
}).prompt().then((v) => {
|
|
782
|
+
const result = v;
|
|
783
|
+
if (result === true) {
|
|
784
|
+
return "yes";
|
|
785
|
+
} else if (result === false) {
|
|
786
|
+
return "no";
|
|
787
|
+
}
|
|
788
|
+
return "cancel";
|
|
658
789
|
});
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
name,
|
|
665
|
-
configKey: "graphqlMiddleware",
|
|
666
|
-
version,
|
|
667
|
-
compatibility: {
|
|
668
|
-
nuxt: ">=3.15.0"
|
|
669
|
-
}
|
|
670
|
-
},
|
|
671
|
-
defaults: defaultOptions,
|
|
672
|
-
async setup(passedOptions, nuxt) {
|
|
673
|
-
const options = defu({}, passedOptions, defaultOptions);
|
|
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);
|
|
790
|
+
}
|
|
791
|
+
abort() {
|
|
792
|
+
if (this.abortController) {
|
|
793
|
+
this.abortController.abort();
|
|
794
|
+
this.abortController = null;
|
|
681
795
|
}
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
class ModuleHelper {
|
|
800
|
+
constructor(nuxt, moduleUrl, options) {
|
|
801
|
+
this.nuxt = nuxt;
|
|
682
802
|
const isModuleBuild = process.env.MODULE_BUILD === "true" && nuxt.options._prepare;
|
|
803
|
+
const mergedOptions = defu({}, options, defaultOptions);
|
|
804
|
+
if (!mergedOptions.autoImportPatterns) {
|
|
805
|
+
mergedOptions.autoImportPatterns = [
|
|
806
|
+
"~~/**/*.{gql,graphql}",
|
|
807
|
+
"!node_modules"
|
|
808
|
+
];
|
|
809
|
+
}
|
|
683
810
|
if (isModuleBuild) {
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
811
|
+
mergedOptions.graphqlEndpoint = "http://localhost";
|
|
812
|
+
mergedOptions.downloadSchema = false;
|
|
813
|
+
mergedOptions.schemaPath = "~~/schema.graphql";
|
|
814
|
+
mergedOptions.autoImportPatterns = [
|
|
688
815
|
"~~/playground/**/*.{gql,graphql}",
|
|
689
816
|
"!node_modules"
|
|
690
817
|
];
|
|
691
818
|
}
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
}
|
|
695
|
-
options
|
|
696
|
-
(pattern) => {
|
|
697
|
-
return resolveAlias(pattern);
|
|
698
|
-
}
|
|
699
|
-
);
|
|
819
|
+
mergedOptions.autoImportPatterns = (mergedOptions.autoImportPatterns || []).map((pattern) => {
|
|
820
|
+
return resolveAlias(pattern);
|
|
821
|
+
});
|
|
822
|
+
this.options = mergedOptions;
|
|
700
823
|
if (!nuxt.options._prepare) {
|
|
701
|
-
validateOptions(options);
|
|
824
|
+
validateOptions(this.options);
|
|
702
825
|
}
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
resolveAlias(options.schemaPath),
|
|
711
|
-
options,
|
|
712
|
-
rootResolver.resolve,
|
|
713
|
-
options.downloadSchema
|
|
714
|
-
);
|
|
715
|
-
const schema = await loadSchema(schemaContent, {
|
|
716
|
-
loaders: []
|
|
717
|
-
});
|
|
718
|
-
const runtimeDir = fileURLToPath(new URL("./runtime", import.meta.url));
|
|
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);
|
|
826
|
+
this.isDev = nuxt.options.dev;
|
|
827
|
+
this.resolvers = {
|
|
828
|
+
module: createResolver(moduleUrl),
|
|
829
|
+
server: createResolver(nuxt.options.serverDir),
|
|
830
|
+
src: createResolver(nuxt.options.srcDir),
|
|
831
|
+
app: createResolver(nuxt.options.dir.app),
|
|
832
|
+
root: createResolver(nuxt.options.rootDir)
|
|
724
833
|
};
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
runtimeTypesPath: toBuildRelative(
|
|
738
|
-
moduleResolver.resolve("./runtime/types.ts")
|
|
739
|
-
)
|
|
834
|
+
this.paths = {
|
|
835
|
+
runtimeTypes: "",
|
|
836
|
+
root: nuxt.options.rootDir,
|
|
837
|
+
nuxtConfig: this.resolvers.root.resolve("nuxt.config.ts"),
|
|
838
|
+
serverDir: nuxt.options.serverDir,
|
|
839
|
+
schema: this.resolvers.root.resolve(
|
|
840
|
+
resolveAlias(this.options.schemaPath)
|
|
841
|
+
),
|
|
842
|
+
serverOptions: this.findServerOptions(),
|
|
843
|
+
clientOptions: this.findClientOptions(),
|
|
844
|
+
moduleBuildDir: nuxt.options.buildDir + "/nuxt-graphql-middleware",
|
|
845
|
+
moduleTypesDir: nuxt.options.buildDir + "/graphql-operations"
|
|
740
846
|
};
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
context,
|
|
744
|
-
options.documents,
|
|
745
|
-
options.codegenConfig
|
|
847
|
+
this.paths.runtimeTypes = this.toModuleBuildRelative(
|
|
848
|
+
this.resolvers.module.resolve("./runtime/types.ts")
|
|
746
849
|
);
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
});
|
|
850
|
+
}
|
|
851
|
+
resolvers;
|
|
852
|
+
paths;
|
|
853
|
+
isDev;
|
|
854
|
+
options;
|
|
855
|
+
prompt = new ConsolePrompt();
|
|
856
|
+
/**
|
|
857
|
+
* Find the path to the graphqlMiddleware.serverOptions.ts file.
|
|
858
|
+
*/
|
|
859
|
+
findServerOptions() {
|
|
860
|
+
const newPath = this.resolvers.server.resolve(
|
|
861
|
+
"graphqlMiddleware.serverOptions"
|
|
862
|
+
);
|
|
863
|
+
const serverPath = fileExists(newPath);
|
|
864
|
+
if (serverPath) {
|
|
865
|
+
return serverPath;
|
|
764
866
|
}
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
"useAsyncGraphqlQuery"
|
|
778
|
-
];
|
|
779
|
-
if (options.enableFileUploads) {
|
|
780
|
-
nuxtComposables.push("useGraphqlUploadMutation");
|
|
867
|
+
const candidates = [
|
|
868
|
+
this.resolvers.root.resolve("graphqlMiddleware.serverOptions"),
|
|
869
|
+
this.resolvers.root.resolve("app/graphqlMiddleware.serverOptions"),
|
|
870
|
+
this.resolvers.src.resolve("graphqlMiddleware.serverOptions")
|
|
871
|
+
];
|
|
872
|
+
for (let i = 0; i < candidates.length; i++) {
|
|
873
|
+
const path = candidates[i];
|
|
874
|
+
const filePath = fileExists(path);
|
|
875
|
+
if (filePath) {
|
|
876
|
+
throw new Error(
|
|
877
|
+
`The graphqlMiddleware.serverOptions file should be placed in Nuxt's <serverDir> ("${this.paths.serverDir}/graphqlMiddleware.serverOptions.ts").`
|
|
878
|
+
);
|
|
781
879
|
}
|
|
782
|
-
nuxtComposables.forEach((name2) => {
|
|
783
|
-
addImports({
|
|
784
|
-
from: moduleResolver.resolve("./runtime/composables/" + name2),
|
|
785
|
-
name: name2
|
|
786
|
-
});
|
|
787
|
-
});
|
|
788
|
-
const serverUtils = ["useGraphqlQuery", "useGraphqlMutation"].map(
|
|
789
|
-
(name2) => {
|
|
790
|
-
return {
|
|
791
|
-
from: moduleResolver.resolve("./runtime/server/utils/" + name2),
|
|
792
|
-
name: name2
|
|
793
|
-
};
|
|
794
|
-
}
|
|
795
|
-
);
|
|
796
|
-
addServerImports(serverUtils);
|
|
797
880
|
}
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
881
|
+
logger.info("No graphqlMiddleware.serverOptions file found.");
|
|
882
|
+
return null;
|
|
883
|
+
}
|
|
884
|
+
findClientOptions() {
|
|
885
|
+
const clientOptionsPath = this.resolvers.app.resolve(
|
|
886
|
+
"graphqlMiddleware.clientOptions"
|
|
887
|
+
);
|
|
888
|
+
if (fileExists(clientOptionsPath)) {
|
|
889
|
+
return clientOptionsPath;
|
|
890
|
+
}
|
|
891
|
+
return null;
|
|
892
|
+
}
|
|
893
|
+
/**
|
|
894
|
+
* Transform the path relative to the module's build directory.
|
|
895
|
+
*
|
|
896
|
+
* @param path - The absolute path.
|
|
897
|
+
*
|
|
898
|
+
* @returns The path relative to the module's build directory.
|
|
899
|
+
*/
|
|
900
|
+
toModuleBuildRelative(path) {
|
|
901
|
+
return relative(this.paths.moduleBuildDir, path);
|
|
902
|
+
}
|
|
903
|
+
/**
|
|
904
|
+
* Transform the path relative to the Nuxt build directory.
|
|
905
|
+
*
|
|
906
|
+
* @param path - The absolute path.
|
|
907
|
+
*
|
|
908
|
+
* @returns The path relative to the module's build directory.
|
|
909
|
+
*/
|
|
910
|
+
toBuildRelative(path) {
|
|
911
|
+
return relative(this.nuxt.options.buildDir, path);
|
|
912
|
+
}
|
|
913
|
+
/**
|
|
914
|
+
* Get all file paths that match the import patterns.
|
|
915
|
+
*/
|
|
916
|
+
async getImportPatternFiles() {
|
|
917
|
+
return resolveFiles(
|
|
918
|
+
this.nuxt.options.srcDir,
|
|
919
|
+
this.options.autoImportPatterns,
|
|
920
|
+
{
|
|
921
|
+
followSymbolicLinks: false
|
|
812
922
|
}
|
|
923
|
+
);
|
|
924
|
+
}
|
|
925
|
+
matchesImportPattern(filePath) {
|
|
926
|
+
return micromatch.isMatch(filePath, this.options.autoImportPatterns);
|
|
927
|
+
}
|
|
928
|
+
addAlias(name, path) {
|
|
929
|
+
this.nuxt.options.alias[name] = path;
|
|
930
|
+
const pathFromName = `./${name.substring(1)}`;
|
|
931
|
+
this.nuxt.options.nitro.typescript ||= {};
|
|
932
|
+
this.nuxt.options.nitro.typescript.tsConfig ||= {};
|
|
933
|
+
this.nuxt.options.nitro.typescript.tsConfig.compilerOptions ||= {};
|
|
934
|
+
this.nuxt.options.nitro.typescript.tsConfig.compilerOptions.paths ||= {};
|
|
935
|
+
this.nuxt.options.nitro.typescript.tsConfig.compilerOptions.paths[name] = [
|
|
936
|
+
pathFromName
|
|
937
|
+
];
|
|
938
|
+
this.nuxt.options.nitro.typescript.tsConfig.compilerOptions.paths[name + "/*"] = [pathFromName + "/*"];
|
|
939
|
+
}
|
|
940
|
+
inlineNitroExternals(arg) {
|
|
941
|
+
const path = typeof arg === "string" ? arg : arg.dst;
|
|
942
|
+
this.nuxt.options.nitro.externals = this.nuxt.options.nitro.externals || {};
|
|
943
|
+
this.nuxt.options.nitro.externals.inline = this.nuxt.options.nitro.externals.inline || [];
|
|
944
|
+
this.nuxt.options.nitro.externals.inline.push(path);
|
|
945
|
+
}
|
|
946
|
+
addTemplate(template, cb) {
|
|
947
|
+
const content = cb(this);
|
|
948
|
+
if (template.endsWith("d.ts")) {
|
|
949
|
+
addTypeTemplate({
|
|
950
|
+
filename: template,
|
|
951
|
+
write: true,
|
|
952
|
+
getContents: () => content
|
|
953
|
+
});
|
|
954
|
+
} else {
|
|
955
|
+
addTemplate({
|
|
956
|
+
filename: template,
|
|
957
|
+
write: true,
|
|
958
|
+
getContents: () => content
|
|
959
|
+
});
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
addPlugin(path) {
|
|
963
|
+
addPlugin(this.resolvers.module.resolve(path), {
|
|
964
|
+
append: false
|
|
813
965
|
});
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
966
|
+
}
|
|
967
|
+
addServerHandler(name, path, method) {
|
|
968
|
+
addServerHandler({
|
|
969
|
+
handler: this.resolvers.module.resolve("./runtime/server/api/" + name),
|
|
970
|
+
route: this.options.serverApiPrefix + path,
|
|
971
|
+
method
|
|
818
972
|
});
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
973
|
+
}
|
|
974
|
+
addComposable(name) {
|
|
975
|
+
addImports({
|
|
976
|
+
from: this.resolvers.module.resolve("./runtime/composables/" + name),
|
|
977
|
+
name
|
|
823
978
|
});
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
979
|
+
}
|
|
980
|
+
addServerUtil(name) {
|
|
981
|
+
addServerImports([
|
|
982
|
+
{
|
|
983
|
+
from: this.resolvers.module.resolve("./runtime/server/utils/" + name),
|
|
984
|
+
name
|
|
985
|
+
}
|
|
986
|
+
]);
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
function GraphqlConfig(helper) {
|
|
991
|
+
const patterns = helper.options.autoImportPatterns || [];
|
|
992
|
+
const configPath = helper.resolvers.root.resolve(
|
|
993
|
+
(helper.options.graphqlConfigFilePath || "").replace(
|
|
994
|
+
"/graphql.config.ts",
|
|
995
|
+
""
|
|
996
|
+
)
|
|
997
|
+
);
|
|
998
|
+
const schemaPath = "./" + relative(configPath, helper.paths.schema);
|
|
999
|
+
const documents = patterns.filter((v) => !v.includes("!")).map((pattern) => {
|
|
1000
|
+
return "./" + relative(configPath, helper.resolvers.root.resolve(pattern));
|
|
1001
|
+
});
|
|
1002
|
+
return `
|
|
1003
|
+
import type { IGraphQLConfig } from 'graphql-config'
|
|
1004
|
+
|
|
1005
|
+
const schema = ${JSON.stringify(schemaPath)}
|
|
1006
|
+
|
|
1007
|
+
const documents: string[] = ${JSON.stringify(documents, null, 2)};
|
|
1008
|
+
|
|
1009
|
+
const config: IGraphQLConfig = {
|
|
1010
|
+
schema,
|
|
1011
|
+
documents,
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
export default config
|
|
1015
|
+
`;
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
function DocumentTypes() {
|
|
1019
|
+
return `
|
|
1020
|
+
import type { Query, Mutation } from './operations'
|
|
1021
|
+
|
|
1022
|
+
declare module '#nuxt-graphql-middleware/documents' {
|
|
1023
|
+
export type Documents = {
|
|
1024
|
+
query: Record<keyof Query, string>
|
|
1025
|
+
mutation: Record<keyof Mutation, string>
|
|
1026
|
+
}
|
|
1027
|
+
export const documents: Documents
|
|
1028
|
+
}`;
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
function Types() {
|
|
1032
|
+
return `declare module '#nuxt-graphql-middleware/sources' {
|
|
1033
|
+
export const operationSources: Record<string, string>
|
|
1034
|
+
}`;
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
function HelpersTypes() {
|
|
1038
|
+
return `export const serverApiPrefix: string;
|
|
1039
|
+
export function getEndpoint(operation: string, operationName: string): string`;
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
function Helpers(helper) {
|
|
1043
|
+
return `export const serverApiPrefix = '${helper.options.serverApiPrefix}'
|
|
828
1044
|
export function getEndpoint(operation, operationName) {
|
|
829
|
-
return '${
|
|
1045
|
+
return '${helper.options.serverApiPrefix}' + '/' + operation + '/' + operationName
|
|
830
1046
|
}
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
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
|
-
});
|
|
850
|
-
const templateDocuments = addTemplate({
|
|
851
|
-
filename: GraphqlMiddlewareTemplate.Documents,
|
|
852
|
-
write: true,
|
|
853
|
-
getContents: () => collector.getTemplateOperations()
|
|
854
|
-
});
|
|
855
|
-
inlineNitroExternals(templateDocuments.dst);
|
|
856
|
-
addTypeTemplate({
|
|
857
|
-
filename: GraphqlMiddlewareTemplate.ResponseTypes,
|
|
858
|
-
write: true,
|
|
859
|
-
getContents: () => collector.getTemplateResponseTypes()
|
|
860
|
-
});
|
|
861
|
-
addTypeTemplate({
|
|
862
|
-
write: true,
|
|
863
|
-
filename: "nuxt-graphql-middleware/documents.d.ts",
|
|
864
|
-
getContents: () => generateDocumentTypesTemplate()
|
|
865
|
-
});
|
|
866
|
-
const findServerOptions = () => {
|
|
867
|
-
const newPath = serverResolver.resolve("graphqlMiddleware.serverOptions");
|
|
868
|
-
const serverPath = fileExists(newPath);
|
|
869
|
-
if (serverPath) {
|
|
870
|
-
return serverPath;
|
|
871
|
-
}
|
|
872
|
-
const candidates = [
|
|
873
|
-
rootResolver.resolve("graphqlMiddleware.serverOptions"),
|
|
874
|
-
rootResolver.resolve("app/graphqlMiddleware.serverOptions"),
|
|
875
|
-
srcResolver.resolve("graphqlMiddleware.serverOptions")
|
|
876
|
-
];
|
|
877
|
-
for (let i = 0; i < candidates.length; i++) {
|
|
878
|
-
const path = candidates[i];
|
|
879
|
-
const filePath = fileExists(path);
|
|
880
|
-
if (filePath) {
|
|
881
|
-
logger.warn(
|
|
882
|
-
`The graphqlMiddleware.serverOptions file should be placed in Nuxt's <serverDir> ("${nuxt.options.serverDir}/graphqlMiddleware.serverOptions.ts"). The new path will be enforced in the next major release.`
|
|
883
|
-
);
|
|
884
|
-
return filePath;
|
|
885
|
-
}
|
|
886
|
-
}
|
|
887
|
-
logger.info("No graphqlMiddleware.serverOptions file found.");
|
|
888
|
-
};
|
|
889
|
-
const resolvedServerOptionsPath = findServerOptions();
|
|
890
|
-
const moduleTypesPath = toBuildRelative(moduleResolver.resolve("./types"));
|
|
891
|
-
const resolvedPathRelative = resolvedServerOptionsPath ? toBuildRelative(resolvedServerOptionsPath) : null;
|
|
892
|
-
const template = addTemplate({
|
|
893
|
-
filename: "nuxt-graphql-middleware/server-options.mjs",
|
|
894
|
-
write: true,
|
|
895
|
-
getContents: () => {
|
|
896
|
-
const serverOptionsLine = resolvedPathRelative ? `import serverOptions from '${resolvedPathRelative}'` : `const serverOptions = {}`;
|
|
897
|
-
return `
|
|
1047
|
+
`;
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
function ServerOptions(helper) {
|
|
1051
|
+
const resolvedPathRelative = helper.paths.serverOptions ? helper.toModuleBuildRelative(helper.paths.serverOptions) : null;
|
|
1052
|
+
const serverOptionsLine = resolvedPathRelative ? `import serverOptions from '${resolvedPathRelative}'` : `const serverOptions = {}`;
|
|
1053
|
+
return `
|
|
898
1054
|
${serverOptionsLine}
|
|
899
1055
|
export { serverOptions }
|
|
900
1056
|
`;
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
function ServerOptionsTypes(helper) {
|
|
1060
|
+
const resolvedPathRelative = helper.paths.serverOptions ? helper.toModuleBuildRelative(helper.paths.serverOptions) : null;
|
|
1061
|
+
const serverOptionsLineTypes = resolvedPathRelative ? `import serverOptions from '${resolvedPathRelative}'` : `const serverOptions: GraphqlMiddlewareServerOptions = {}`;
|
|
1062
|
+
const moduleTypesPath = helper.toModuleBuildRelative(
|
|
1063
|
+
helper.resolvers.module.resolve("./types")
|
|
1064
|
+
);
|
|
1065
|
+
return `
|
|
910
1066
|
import type { GraphqlMiddlewareServerOptions } from '${moduleTypesPath}'
|
|
911
1067
|
${serverOptionsLineTypes}
|
|
912
1068
|
|
|
@@ -914,112 +1070,282 @@ export type GraphqlResponseAdditions =
|
|
|
914
1070
|
typeof serverOptions extends GraphqlMiddlewareServerOptions<infer R, any, any> ? R : {}
|
|
915
1071
|
|
|
916
1072
|
export { serverOptions }`;
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
}
|
|
939
|
-
});
|
|
940
|
-
addTemplate({
|
|
941
|
-
filename: "nuxt-graphql-middleware/client-options.d.ts",
|
|
942
|
-
write: true,
|
|
943
|
-
getContents: () => {
|
|
944
|
-
if (clientOptionsImport) {
|
|
945
|
-
return `import type { GraphqlClientOptions } from '${context.runtimeTypesPath}'
|
|
946
|
-
${clientOptionsImport}
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
function ClientOptions(helper) {
|
|
1076
|
+
if (helper.paths.clientOptions) {
|
|
1077
|
+
const pathRelative = helper.toModuleBuildRelative(
|
|
1078
|
+
helper.paths.clientOptions
|
|
1079
|
+
);
|
|
1080
|
+
return `import clientOptions from '${pathRelative}'
|
|
1081
|
+
export { clientOptions }
|
|
1082
|
+
`;
|
|
1083
|
+
}
|
|
1084
|
+
return `export const clientOptions = {}`;
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
function ClientOptionsTypes(helper) {
|
|
1088
|
+
if (helper.paths.clientOptions) {
|
|
1089
|
+
const pathRelative = helper.toModuleBuildRelative(
|
|
1090
|
+
helper.paths.clientOptions
|
|
1091
|
+
);
|
|
1092
|
+
return `import type { GraphqlClientOptions } from '${helper.paths.runtimeTypes}'
|
|
1093
|
+
import { clientOptions } from '${pathRelative}'
|
|
947
1094
|
|
|
948
1095
|
export type GraphqlClientContext = typeof clientOptions extends GraphqlClientOptions<infer R> ? R : {}
|
|
949
1096
|
|
|
950
1097
|
export { clientOptions }`;
|
|
951
|
-
|
|
952
|
-
|
|
1098
|
+
}
|
|
1099
|
+
return `
|
|
1100
|
+
import type { GraphqlClientOptions } from '${helper.paths.runtimeTypes}'
|
|
953
1101
|
export const clientOptions: GraphqlClientOptions
|
|
954
1102
|
|
|
955
1103
|
export type GraphqlClientContext = {}
|
|
956
1104
|
`;
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
const DEVTOOLS_UI_ROUTE = "/__nuxt-graphql-middleware";
|
|
1108
|
+
const DEVTOOLS_UI_LOCAL_PORT = 3300;
|
|
1109
|
+
function setupDevToolsUI(nuxt, clientPath) {
|
|
1110
|
+
const isProductionBuild = existsSync$1(clientPath);
|
|
1111
|
+
if (isProductionBuild) {
|
|
1112
|
+
nuxt.hook("vite:serverCreated", async (server) => {
|
|
1113
|
+
const sirv = await import('sirv').then((r) => r.default || r);
|
|
1114
|
+
server.middlewares.use(
|
|
1115
|
+
DEVTOOLS_UI_ROUTE,
|
|
1116
|
+
sirv(clientPath, { dev: true, single: true })
|
|
1117
|
+
);
|
|
962
1118
|
});
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
1119
|
+
} else {
|
|
1120
|
+
nuxt.hook("vite:extendConfig", (config) => {
|
|
1121
|
+
config.server = config.server || {};
|
|
1122
|
+
config.server.proxy = config.server.proxy || {};
|
|
1123
|
+
config.server.proxy[DEVTOOLS_UI_ROUTE] = {
|
|
1124
|
+
target: "http://localhost:" + DEVTOOLS_UI_LOCAL_PORT + DEVTOOLS_UI_ROUTE,
|
|
1125
|
+
changeOrigin: true,
|
|
1126
|
+
followRedirects: true,
|
|
1127
|
+
rewrite: (path) => path.replace(DEVTOOLS_UI_ROUTE, "")
|
|
1128
|
+
};
|
|
971
1129
|
});
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
1130
|
+
}
|
|
1131
|
+
nuxt.hook("devtools:customTabs", (tabs) => {
|
|
1132
|
+
tabs.push({
|
|
1133
|
+
// unique identifier
|
|
1134
|
+
name: "nuxt-graphql-middleware",
|
|
1135
|
+
// title to display in the tab
|
|
1136
|
+
title: "GraphQL Middleware",
|
|
1137
|
+
// any icon from Iconify, or a URL to an image
|
|
1138
|
+
icon: "akar-icons:graphql-fill",
|
|
1139
|
+
// iframe view
|
|
1140
|
+
view: {
|
|
1141
|
+
type: "iframe",
|
|
1142
|
+
src: DEVTOOLS_UI_ROUTE
|
|
1143
|
+
}
|
|
984
1144
|
});
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
1145
|
+
});
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
const RPC_NAMESPACE = "nuxt-graphql-middleware";
|
|
1149
|
+
class DevModeHandler {
|
|
1150
|
+
constructor(nuxt, schemaProvider, collector, helper) {
|
|
1151
|
+
this.nuxt = nuxt;
|
|
1152
|
+
this.schemaProvider = schemaProvider;
|
|
1153
|
+
this.collector = collector;
|
|
1154
|
+
this.helper = helper;
|
|
1155
|
+
}
|
|
1156
|
+
devToolsRpc = null;
|
|
1157
|
+
nitro = null;
|
|
1158
|
+
viteWebSocket = null;
|
|
1159
|
+
operationsToReload = /* @__PURE__ */ new Set();
|
|
1160
|
+
init() {
|
|
1161
|
+
this.nuxt.hooks.hookOnce("ready", this.onReady.bind(this));
|
|
1162
|
+
this.nuxt.hooks.hookOnce(
|
|
1163
|
+
"vite:serverCreated",
|
|
1164
|
+
this.onViteServerCreated.bind(this)
|
|
1165
|
+
);
|
|
1166
|
+
this.nuxt.hook("builder:watch", this.onBuilderWatch.bind(this));
|
|
1167
|
+
if (this.helper.options.devtools) {
|
|
1168
|
+
const clientPath = this.helper.resolvers.module.resolve("./client");
|
|
1169
|
+
setupDevToolsUI(this.nuxt, clientPath);
|
|
1170
|
+
onDevToolsInitialized(() => {
|
|
1171
|
+
this.devToolsRpc = extendServerRpc(
|
|
1172
|
+
RPC_NAMESPACE,
|
|
1173
|
+
{
|
|
1174
|
+
// register server RPC functions
|
|
1175
|
+
getModuleOptions: () => {
|
|
1176
|
+
return this.helper.options;
|
|
1177
|
+
},
|
|
1178
|
+
getDocuments: () => {
|
|
1179
|
+
return [...this.collector.rpcItems.values()];
|
|
993
1180
|
}
|
|
994
|
-
}
|
|
995
|
-
|
|
996
|
-
};
|
|
997
|
-
addServerHandler({
|
|
998
|
-
handler: moduleResolver.resolve("./runtime/serverHandler/debug"),
|
|
999
|
-
route: options.serverApiPrefix + "/debug"
|
|
1181
|
+
}
|
|
1182
|
+
);
|
|
1000
1183
|
});
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
onReady() {
|
|
1187
|
+
this.nitro = useNitro();
|
|
1188
|
+
this.nitro.hooks.hook("compiled", this.onNitroCompiled.bind(this));
|
|
1189
|
+
}
|
|
1190
|
+
async onBuilderWatch(event, pathAbsolute) {
|
|
1191
|
+
if (pathAbsolute === this.helper.paths.schema) {
|
|
1192
|
+
return;
|
|
1193
|
+
}
|
|
1194
|
+
if (!pathAbsolute.match(/\.(gql|graphql)$/)) {
|
|
1195
|
+
return;
|
|
1196
|
+
}
|
|
1197
|
+
this.helper.prompt.abort();
|
|
1198
|
+
const { hasChanged, affectedOperations, error } = await this.collector.handleWatchEvent(event, pathAbsolute);
|
|
1199
|
+
if (error) {
|
|
1200
|
+
this.sendError(error);
|
|
1201
|
+
await this.helper.prompt.confirm("Do you want to download and update the GraphQL schema?").then(async (shouldReload) => {
|
|
1202
|
+
if (shouldReload !== "yes") {
|
|
1007
1203
|
return;
|
|
1008
1204
|
}
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
)
|
|
1013
|
-
|
|
1014
|
-
sendError(error);
|
|
1015
|
-
}
|
|
1016
|
-
if (hasChanged) {
|
|
1017
|
-
if (rpc) {
|
|
1018
|
-
rpc.broadcast.documentsUpdated([...collector.rpcItems.values()]);
|
|
1019
|
-
}
|
|
1205
|
+
try {
|
|
1206
|
+
await this.schemaProvider.loadSchema({ forceDownload: true });
|
|
1207
|
+
await this.collector.updateSchema(this.schemaProvider.getSchema());
|
|
1208
|
+
} catch (e) {
|
|
1209
|
+
logger.error(e);
|
|
1020
1210
|
}
|
|
1021
1211
|
});
|
|
1212
|
+
return;
|
|
1213
|
+
}
|
|
1214
|
+
if (!hasChanged) {
|
|
1215
|
+
return;
|
|
1216
|
+
}
|
|
1217
|
+
if (this.nitro) {
|
|
1218
|
+
await this.nitro.hooks.callHook("rollup:reload");
|
|
1022
1219
|
}
|
|
1220
|
+
if (affectedOperations.length) {
|
|
1221
|
+
affectedOperations.forEach(
|
|
1222
|
+
(operation) => this.operationsToReload.add(operation)
|
|
1223
|
+
);
|
|
1224
|
+
}
|
|
1225
|
+
if (this.devToolsRpc) {
|
|
1226
|
+
try {
|
|
1227
|
+
this.devToolsRpc.broadcast.documentsUpdated([
|
|
1228
|
+
...this.collector.rpcItems.values()
|
|
1229
|
+
]);
|
|
1230
|
+
} catch {
|
|
1231
|
+
logger.info(
|
|
1232
|
+
"Failed to update GraphQL documents in dev tools. The documents might be stale."
|
|
1233
|
+
);
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
onViteServerCreated(server) {
|
|
1238
|
+
this.viteWebSocket = server.ws;
|
|
1239
|
+
}
|
|
1240
|
+
sendError(error) {
|
|
1241
|
+
if (!this.viteWebSocket) {
|
|
1242
|
+
return;
|
|
1243
|
+
}
|
|
1244
|
+
this.viteWebSocket.send({
|
|
1245
|
+
type: "error",
|
|
1246
|
+
err: {
|
|
1247
|
+
message: error.message,
|
|
1248
|
+
stack: ""
|
|
1249
|
+
}
|
|
1250
|
+
});
|
|
1251
|
+
}
|
|
1252
|
+
onNitroCompiled() {
|
|
1253
|
+
if (!this.operationsToReload.size) {
|
|
1254
|
+
return;
|
|
1255
|
+
}
|
|
1256
|
+
const operations = [...this.operationsToReload.values()];
|
|
1257
|
+
this.operationsToReload.clear();
|
|
1258
|
+
if (!this.viteWebSocket) {
|
|
1259
|
+
return;
|
|
1260
|
+
}
|
|
1261
|
+
this.viteWebSocket.send({
|
|
1262
|
+
type: "custom",
|
|
1263
|
+
event: "nuxt-graphql-middleware:reload",
|
|
1264
|
+
data: { operations }
|
|
1265
|
+
});
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
|
|
1269
|
+
const module = defineNuxtModule({
|
|
1270
|
+
meta: {
|
|
1271
|
+
name,
|
|
1272
|
+
configKey: "graphqlMiddleware",
|
|
1273
|
+
version,
|
|
1274
|
+
compatibility: {
|
|
1275
|
+
nuxt: ">=3.16.0"
|
|
1276
|
+
}
|
|
1277
|
+
},
|
|
1278
|
+
defaults: defaultOptions,
|
|
1279
|
+
async setup(passedOptions, nuxt) {
|
|
1280
|
+
const helper = new ModuleHelper(nuxt, import.meta.url, passedOptions);
|
|
1281
|
+
const schemaProvider = new SchemaProvider(helper);
|
|
1282
|
+
await schemaProvider.init();
|
|
1283
|
+
const collector = new Collector(schemaProvider.getSchema(), helper);
|
|
1284
|
+
await collector.init();
|
|
1285
|
+
nuxt.options.appConfig.graphqlMiddleware = {
|
|
1286
|
+
clientCacheEnabled: !!helper.options.clientCache?.enabled,
|
|
1287
|
+
clientCacheMaxSize: helper.options.clientCache?.maxSize ?? 100
|
|
1288
|
+
};
|
|
1289
|
+
nuxt.options.runtimeConfig.graphqlMiddleware = {
|
|
1290
|
+
graphqlEndpoint: helper.options.graphqlEndpoint || ""
|
|
1291
|
+
};
|
|
1292
|
+
nuxt.options.build.transpile.push(
|
|
1293
|
+
fileURLToPath(new URL("./runtime", import.meta.url))
|
|
1294
|
+
);
|
|
1295
|
+
helper.inlineNitroExternals(helper.resolvers.module.resolve("./runtime"));
|
|
1296
|
+
helper.inlineNitroExternals(helper.paths.moduleBuildDir);
|
|
1297
|
+
helper.addAlias("#nuxt-graphql-middleware", helper.paths.moduleBuildDir);
|
|
1298
|
+
helper.addAlias("#graphql-operations", helper.paths.moduleTypesDir);
|
|
1299
|
+
helper.addPlugin("./runtime/plugins/provideState");
|
|
1300
|
+
if (helper.isDev && helper.options.errorOverlay) {
|
|
1301
|
+
helper.addPlugin("./runtime/plugins/devMode");
|
|
1302
|
+
}
|
|
1303
|
+
helper.addServerHandler("query", "/query/:name", "get");
|
|
1304
|
+
helper.addServerHandler("mutation", "/mutation/:name", "post");
|
|
1305
|
+
if (helper.options.enableFileUploads) {
|
|
1306
|
+
helper.addServerHandler("upload", "/upload/:name", "post");
|
|
1307
|
+
}
|
|
1308
|
+
if (helper.isDev) {
|
|
1309
|
+
helper.addServerHandler("debug", "/debug", "get");
|
|
1310
|
+
}
|
|
1311
|
+
if (helper.options.includeComposables) {
|
|
1312
|
+
helper.addComposable("useGraphqlQuery");
|
|
1313
|
+
helper.addComposable("useGraphqlMutation");
|
|
1314
|
+
helper.addComposable("useGraphqlState");
|
|
1315
|
+
helper.addComposable("useAsyncGraphqlQuery");
|
|
1316
|
+
if (helper.options.enableFileUploads) {
|
|
1317
|
+
helper.addComposable("useGraphqlUploadMutation");
|
|
1318
|
+
}
|
|
1319
|
+
helper.addServerUtil("useGraphqlQuery");
|
|
1320
|
+
helper.addServerUtil("useGraphqlMutation");
|
|
1321
|
+
helper.addServerUtil("doGraphqlRequest");
|
|
1322
|
+
}
|
|
1323
|
+
helper.addTemplate(Template.ClientOptions, ClientOptions);
|
|
1324
|
+
helper.addTemplate(Template.ClientOptionsTypes, ClientOptionsTypes);
|
|
1325
|
+
helper.addTemplate(Template.DocumentTypes, DocumentTypes);
|
|
1326
|
+
helper.addTemplate(Template.GraphqlConfig, GraphqlConfig);
|
|
1327
|
+
helper.addTemplate(Template.Helpers, Helpers);
|
|
1328
|
+
helper.addTemplate(Template.HelpersTypes, HelpersTypes);
|
|
1329
|
+
helper.addTemplate(Template.ServerOptions, ServerOptions);
|
|
1330
|
+
helper.addTemplate(Template.ServerOptionsTypes, ServerOptionsTypes);
|
|
1331
|
+
helper.addTemplate(Template.Types, Types);
|
|
1332
|
+
collector.addTemplate(Template.Enums);
|
|
1333
|
+
collector.addTemplate(Template.NitroTypes);
|
|
1334
|
+
collector.addTemplate(Template.OperationSources);
|
|
1335
|
+
collector.addTemplate(Template.OperationTypes);
|
|
1336
|
+
collector.addTemplate(Template.OperationTypesAll);
|
|
1337
|
+
collector.addTemplate(Template.ResponseTypes);
|
|
1338
|
+
collector.addVirtualTemplate(Template.Documents);
|
|
1339
|
+
if (!helper.isDev) {
|
|
1340
|
+
return;
|
|
1341
|
+
}
|
|
1342
|
+
const devModeHandler = new DevModeHandler(
|
|
1343
|
+
nuxt,
|
|
1344
|
+
schemaProvider,
|
|
1345
|
+
collector,
|
|
1346
|
+
helper
|
|
1347
|
+
);
|
|
1348
|
+
devModeHandler.init();
|
|
1023
1349
|
}
|
|
1024
1350
|
});
|
|
1025
1351
|
|