nitro-graphql 1.4.3 → 1.5.0
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/README.md +551 -0
- package/dist/ecosystem/nuxt.js +1 -3
- package/dist/index.js +56 -15
- package/dist/rollup.js +156 -39
- package/dist/routes/apollo-server.d.ts +2 -2
- package/dist/routes/apollo-server.js +10 -17
- package/dist/routes/debug.d.ts +61 -0
- package/dist/routes/debug.js +449 -0
- package/dist/routes/graphql-yoga.d.ts +2 -2
- package/dist/routes/graphql-yoga.js +13 -20
- package/dist/routes/health.d.ts +2 -2
- package/dist/types/standard-schema.d.ts +2 -2
- package/dist/utils/apollo.js +2 -3
- package/dist/utils/client-codegen.js +30 -48
- package/dist/utils/directive-parser.js +7 -16
- package/dist/utils/index.js +69 -49
- package/dist/utils/server-codegen.js +3 -5
- package/dist/utils/type-generation.js +10 -21
- package/package.json +21 -25
|
@@ -29,8 +29,7 @@ function pluginContent(_schema, _documents, _config, _info) {
|
|
|
29
29
|
};
|
|
30
30
|
}
|
|
31
31
|
async function graphQLLoadSchemaSync(schemaPointers, data = {}) {
|
|
32
|
-
const
|
|
33
|
-
const filteredPointers = [...pointers, "!**/vfs/**"];
|
|
32
|
+
const filteredPointers = [...Array.isArray(schemaPointers) ? schemaPointers : [schemaPointers], "!**/vfs/**"];
|
|
34
33
|
let result;
|
|
35
34
|
try {
|
|
36
35
|
result = loadSchemaSync(filteredPointers, {
|
|
@@ -58,8 +57,7 @@ async function loadExternalSchema(service, buildDir) {
|
|
|
58
57
|
const defaultPath = resolve(buildDir, "graphql", "schemas", `${service.name}.graphql`);
|
|
59
58
|
const schemaFilePath = service.downloadPath ? resolve(service.downloadPath) : defaultPath;
|
|
60
59
|
if (existsSync(schemaFilePath)) try {
|
|
61
|
-
|
|
62
|
-
return result$1;
|
|
60
|
+
return loadSchemaSync([schemaFilePath], { loaders: [new GraphQLFileLoader()] });
|
|
63
61
|
} catch {
|
|
64
62
|
consola$1.warn(`[graphql:${service.name}] Cached schema invalid, loading from source`);
|
|
65
63
|
}
|
|
@@ -70,14 +68,13 @@ async function loadExternalSchema(service, buildDir) {
|
|
|
70
68
|
if (hasLocalFiles) loaders.push(new GraphQLFileLoader());
|
|
71
69
|
if (hasUrls) loaders.push(new UrlLoader());
|
|
72
70
|
if (loaders.length === 0) throw new Error("No appropriate loaders found for schema sources");
|
|
73
|
-
|
|
71
|
+
return loadSchemaSync(schemas, {
|
|
74
72
|
loaders,
|
|
75
73
|
...Object.keys(headers).length > 0 && { headers }
|
|
76
74
|
});
|
|
77
|
-
return result;
|
|
78
75
|
} catch (error) {
|
|
79
76
|
consola$1.error(`[graphql:${service.name}] Failed to load external schema:`, error);
|
|
80
|
-
return
|
|
77
|
+
return;
|
|
81
78
|
}
|
|
82
79
|
}
|
|
83
80
|
/**
|
|
@@ -91,7 +88,7 @@ function isUrl(path) {
|
|
|
91
88
|
*/
|
|
92
89
|
async function downloadAndSaveSchema(service, buildDir) {
|
|
93
90
|
const downloadMode = service.downloadSchema;
|
|
94
|
-
if (!downloadMode || downloadMode === "manual") return
|
|
91
|
+
if (!downloadMode || downloadMode === "manual") return;
|
|
95
92
|
const defaultPath = resolve(buildDir, "graphql", "schemas", `${service.name}.graphql`);
|
|
96
93
|
const schemaFilePath = service.downloadPath ? resolve(service.downloadPath) : defaultPath;
|
|
97
94
|
try {
|
|
@@ -104,15 +101,13 @@ async function downloadAndSaveSchema(service, buildDir) {
|
|
|
104
101
|
if (downloadMode === "always") {
|
|
105
102
|
shouldDownload = true;
|
|
106
103
|
if (fileExists && hasUrlSchemas) try {
|
|
107
|
-
const
|
|
104
|
+
const remoteSchemaString = printSchemaWithDirectives(loadSchemaSync(schemas.filter(isUrl), {
|
|
108
105
|
loaders: [new UrlLoader()],
|
|
109
106
|
...Object.keys(headers).length > 0 && { headers }
|
|
110
|
-
});
|
|
111
|
-
const remoteSchemaString = printSchemaWithDirectives(remoteSchema);
|
|
107
|
+
}));
|
|
112
108
|
const remoteHash = createHash("md5").update(remoteSchemaString).digest("hex");
|
|
113
109
|
const localSchemaString = readFileSync(schemaFilePath, "utf-8");
|
|
114
|
-
|
|
115
|
-
if (remoteHash === localHash) {
|
|
110
|
+
if (remoteHash === createHash("md5").update(localSchemaString).digest("hex")) {
|
|
116
111
|
shouldDownload = false;
|
|
117
112
|
consola$1.info(`[graphql:${service.name}] Schema is up-to-date, using cached version`);
|
|
118
113
|
}
|
|
@@ -137,24 +132,21 @@ async function downloadAndSaveSchema(service, buildDir) {
|
|
|
137
132
|
} else if (downloadMode === true || downloadMode === "once") shouldDownload = !fileExists;
|
|
138
133
|
if (shouldDownload) {
|
|
139
134
|
if (hasUrlSchemas && hasLocalSchemas) {
|
|
140
|
-
const
|
|
135
|
+
const schemaString = printSchemaWithDirectives(loadSchemaSync(schemas, {
|
|
141
136
|
loaders: [new GraphQLFileLoader(), new UrlLoader()],
|
|
142
137
|
...Object.keys(headers).length > 0 && { headers }
|
|
143
|
-
});
|
|
144
|
-
const schemaString = printSchemaWithDirectives(schema);
|
|
138
|
+
}));
|
|
145
139
|
mkdirSync(dirname(schemaFilePath), { recursive: true });
|
|
146
140
|
writeFileSync(schemaFilePath, schemaString, "utf-8");
|
|
147
141
|
} else if (hasUrlSchemas) {
|
|
148
|
-
const
|
|
142
|
+
const schemaString = printSchemaWithDirectives(loadSchemaSync(schemas, {
|
|
149
143
|
loaders: [new UrlLoader()],
|
|
150
144
|
...Object.keys(headers).length > 0 && { headers }
|
|
151
|
-
});
|
|
152
|
-
const schemaString = printSchemaWithDirectives(schema);
|
|
145
|
+
}));
|
|
153
146
|
mkdirSync(dirname(schemaFilePath), { recursive: true });
|
|
154
147
|
writeFileSync(schemaFilePath, schemaString, "utf-8");
|
|
155
148
|
} else if (hasLocalSchemas) {
|
|
156
|
-
const
|
|
157
|
-
const schemaString = printSchemaWithDirectives(schema);
|
|
149
|
+
const schemaString = printSchemaWithDirectives(loadSchemaSync(schemas, { loaders: [new GraphQLFileLoader()] }));
|
|
158
150
|
mkdirSync(dirname(schemaFilePath), { recursive: true });
|
|
159
151
|
writeFileSync(schemaFilePath, schemaString, "utf-8");
|
|
160
152
|
}
|
|
@@ -162,13 +154,12 @@ async function downloadAndSaveSchema(service, buildDir) {
|
|
|
162
154
|
return schemaFilePath;
|
|
163
155
|
} catch (error) {
|
|
164
156
|
consola$1.error(`[graphql:${service.name}] Failed to download/copy schema:`, error);
|
|
165
|
-
return
|
|
157
|
+
return;
|
|
166
158
|
}
|
|
167
159
|
}
|
|
168
160
|
async function loadGraphQLDocuments(patterns) {
|
|
169
161
|
try {
|
|
170
|
-
|
|
171
|
-
return result;
|
|
162
|
+
return await loadDocuments(patterns, { loaders: [new GraphQLFileLoader()] });
|
|
172
163
|
} catch (e) {
|
|
173
164
|
if ((e.message || "").includes("Unable to find any GraphQL type definitions for the following pointers:")) return [];
|
|
174
165
|
else throw e;
|
|
@@ -180,7 +171,7 @@ async function generateClientTypes(schema, docs, config = {}, sdkConfig = {}, ou
|
|
|
180
171
|
return false;
|
|
181
172
|
}
|
|
182
173
|
const serviceLabel = serviceName ? `:${serviceName}` : "";
|
|
183
|
-
const
|
|
174
|
+
const mergedConfig = defu$1({
|
|
184
175
|
emitLegacyCommonJSImports: false,
|
|
185
176
|
useTypeImports: true,
|
|
186
177
|
enumsAsTypes: true,
|
|
@@ -204,12 +195,11 @@ async function generateClientTypes(schema, docs, config = {}, sdkConfig = {}, ou
|
|
|
204
195
|
output: "File"
|
|
205
196
|
}
|
|
206
197
|
}
|
|
207
|
-
};
|
|
208
|
-
const mergedConfig = defu$1(defaultConfig, config);
|
|
198
|
+
}, config);
|
|
209
199
|
const mergedSdkConfig = defu$1(mergedConfig, sdkConfig);
|
|
210
200
|
try {
|
|
211
|
-
if (docs.length === 0) {
|
|
212
|
-
|
|
201
|
+
if (docs.length === 0) return {
|
|
202
|
+
types: await codegen({
|
|
213
203
|
filename: outputPath || "client-types.generated.ts",
|
|
214
204
|
schema: parse(printSchemaWithDirectives(schema)),
|
|
215
205
|
documents: [],
|
|
@@ -219,8 +209,8 @@ async function generateClientTypes(schema, docs, config = {}, sdkConfig = {}, ou
|
|
|
219
209
|
pluginContent: { plugin: pluginContent },
|
|
220
210
|
typescript: { plugin }
|
|
221
211
|
}
|
|
222
|
-
})
|
|
223
|
-
|
|
212
|
+
}),
|
|
213
|
+
sdk: `// THIS FILE IS GENERATED, DO NOT EDIT!
|
|
224
214
|
/* eslint-disable eslint-comments/no-unlimited-disable */
|
|
225
215
|
/* tslint:disable */
|
|
226
216
|
/* eslint-disable */
|
|
@@ -244,12 +234,8 @@ export function getSdk(requester: Requester): Sdk {
|
|
|
244
234
|
}
|
|
245
235
|
}
|
|
246
236
|
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
types: output$1,
|
|
250
|
-
sdk: sdkContent$1
|
|
251
|
-
};
|
|
252
|
-
}
|
|
237
|
+
`
|
|
238
|
+
};
|
|
253
239
|
const output = await codegen({
|
|
254
240
|
filename: outputPath || "client-types.generated.ts",
|
|
255
241
|
schema: parse(printSchemaWithDirectives(schema)),
|
|
@@ -279,16 +265,14 @@ export function getSdk(requester: Requester): Sdk {
|
|
|
279
265
|
typescriptGenericSdk: { plugin: plugin$1 }
|
|
280
266
|
}
|
|
281
267
|
});
|
|
282
|
-
const results = await Promise.all(sdkOutput.map(async (config$1) => {
|
|
283
|
-
return {
|
|
284
|
-
file: config$1.filename,
|
|
285
|
-
content: await codegen(config$1)
|
|
286
|
-
};
|
|
287
|
-
}));
|
|
288
|
-
const sdkContent = results[0]?.content || "";
|
|
289
268
|
return {
|
|
290
269
|
types: output,
|
|
291
|
-
sdk:
|
|
270
|
+
sdk: (await Promise.all(sdkOutput.map(async (config$1) => {
|
|
271
|
+
return {
|
|
272
|
+
file: config$1.filename,
|
|
273
|
+
content: await codegen(config$1)
|
|
274
|
+
};
|
|
275
|
+
})))[0]?.content || ""
|
|
292
276
|
};
|
|
293
277
|
} catch (error) {
|
|
294
278
|
consola$1.warn(`[graphql${serviceLabel}] Client type generation failed:`, error);
|
|
@@ -299,9 +283,7 @@ export function getSdk(requester: Requester): Sdk {
|
|
|
299
283
|
* Generate client types for external GraphQL service
|
|
300
284
|
*/
|
|
301
285
|
async function generateExternalClientTypes(service, schema, docs) {
|
|
302
|
-
|
|
303
|
-
const sdkConfig = service.codegen?.clientSDK || {};
|
|
304
|
-
return generateClientTypes(schema, docs, config, sdkConfig, void 0, service.name);
|
|
286
|
+
return generateClientTypes(schema, docs, service.codegen?.client || {}, service.codegen?.clientSDK || {}, void 0, service.name);
|
|
305
287
|
}
|
|
306
288
|
|
|
307
289
|
//#endregion
|
|
@@ -109,14 +109,12 @@ var DirectiveParser = class {
|
|
|
109
109
|
*/
|
|
110
110
|
extractStringLiteral(node) {
|
|
111
111
|
if (node?.type === "Literal" && typeof node.value === "string") return node.value;
|
|
112
|
-
return void 0;
|
|
113
112
|
}
|
|
114
113
|
/**
|
|
115
114
|
* Extract boolean literal value
|
|
116
115
|
*/
|
|
117
116
|
extractBooleanLiteral(node) {
|
|
118
117
|
if (node?.type === "Literal" && typeof node.value === "boolean") return node.value;
|
|
119
|
-
return void 0;
|
|
120
118
|
}
|
|
121
119
|
/**
|
|
122
120
|
* Extract array of strings
|
|
@@ -169,7 +167,6 @@ var DirectiveParser = class {
|
|
|
169
167
|
*/
|
|
170
168
|
extractLiteralValue(node) {
|
|
171
169
|
if (node?.type === "Literal") return node.value;
|
|
172
|
-
return void 0;
|
|
173
170
|
}
|
|
174
171
|
};
|
|
175
172
|
/**
|
|
@@ -177,15 +174,12 @@ var DirectiveParser = class {
|
|
|
177
174
|
*/
|
|
178
175
|
function generateDirectiveSchema(directive) {
|
|
179
176
|
let args = "";
|
|
180
|
-
if (directive.args && Object.keys(directive.args).length > 0) {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
});
|
|
187
|
-
args = `(${argDefs.join(", ")})`;
|
|
188
|
-
}
|
|
177
|
+
if (directive.args && Object.keys(directive.args).length > 0) args = `(${Object.entries(directive.args).map(([name, arg]) => {
|
|
178
|
+
let defaultValue = "";
|
|
179
|
+
if (arg.defaultValue !== void 0) if (typeof arg.defaultValue === "string") defaultValue = ` = "${arg.defaultValue}"`;
|
|
180
|
+
else defaultValue = ` = ${arg.defaultValue}`;
|
|
181
|
+
return `${name}: ${arg.type}${defaultValue}`;
|
|
182
|
+
}).join(", ")})`;
|
|
189
183
|
const locations = directive.locations.join(" | ");
|
|
190
184
|
return `directive @${directive.name}${args} on ${locations}`;
|
|
191
185
|
}
|
|
@@ -220,10 +214,7 @@ ${directiveSchemas.join("\n\n")}`;
|
|
|
220
214
|
const targetDir = dirname(directivesPath);
|
|
221
215
|
if (!existsSync(targetDir)) mkdirSync(targetDir, { recursive: true });
|
|
222
216
|
let shouldWrite = true;
|
|
223
|
-
if (existsSync(directivesPath))
|
|
224
|
-
const existingContent = readFileSync(directivesPath, "utf-8");
|
|
225
|
-
shouldWrite = existingContent !== content;
|
|
226
|
-
}
|
|
217
|
+
if (existsSync(directivesPath)) shouldWrite = readFileSync(directivesPath, "utf-8") !== content;
|
|
227
218
|
if (shouldWrite) writeFileSync(directivesPath, content, "utf-8");
|
|
228
219
|
if (!nitro.scanSchemas.includes(directivesPath)) nitro.scanSchemas.push(directivesPath);
|
|
229
220
|
}
|
package/dist/utils/index.js
CHANGED
|
@@ -44,56 +44,83 @@ function relativeWithDot(from, to) {
|
|
|
44
44
|
return RELATIVE_RE.test(rel) ? rel : `./${rel}`;
|
|
45
45
|
}
|
|
46
46
|
async function scanGraphql(nitro) {
|
|
47
|
-
|
|
48
|
-
return files.map((f) => f.fullPath);
|
|
47
|
+
return (await scanFiles(nitro, "graphql")).map((f) => f.fullPath);
|
|
49
48
|
}
|
|
50
49
|
async function scanResolvers(nitro) {
|
|
51
50
|
const files = await scanFiles(nitro, "graphql", "**/*.resolver.{ts,js}");
|
|
52
51
|
const exportName = [];
|
|
53
|
-
|
|
52
|
+
const VALID_DEFINE_FUNCTIONS = [
|
|
53
|
+
"defineResolver",
|
|
54
|
+
"defineQuery",
|
|
55
|
+
"defineMutation",
|
|
56
|
+
"defineType",
|
|
57
|
+
"defineSubscription",
|
|
58
|
+
"defineDirective"
|
|
59
|
+
];
|
|
60
|
+
for (const file of files) try {
|
|
54
61
|
const fileContent = await readFile(file.fullPath, "utf-8");
|
|
55
62
|
const parsed = await parseAsync(file.fullPath, fileContent);
|
|
56
63
|
const exports = {
|
|
57
64
|
imports: [],
|
|
58
65
|
specifier: file.fullPath
|
|
59
66
|
};
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
type
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
type
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
type
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
type
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
type
|
|
91
|
-
|
|
92
|
-
|
|
67
|
+
let hasDefaultExport = false;
|
|
68
|
+
let hasNamedExport = false;
|
|
69
|
+
const namedExports = [];
|
|
70
|
+
for (const node of parsed.program.body) {
|
|
71
|
+
if (node.type === "ExportDefaultDeclaration") hasDefaultExport = true;
|
|
72
|
+
if (node.type === "ExportNamedDeclaration" && node.declaration && node.declaration.type === "VariableDeclaration") {
|
|
73
|
+
for (const decl of node.declaration.declarations) if (decl.type === "VariableDeclarator" && decl.init && decl.id.type === "Identifier") {
|
|
74
|
+
hasNamedExport = true;
|
|
75
|
+
namedExports.push(decl.id.name);
|
|
76
|
+
if (decl.init && decl.init.type === "CallExpression") {
|
|
77
|
+
if (decl.init.callee.type === "Identifier" && decl.init.callee.name === "defineResolver") exports.imports.push({
|
|
78
|
+
name: decl.id.name,
|
|
79
|
+
type: "resolver",
|
|
80
|
+
as: `_${hash(decl.id.name + file.fullPath).replace(/-/g, "").slice(0, 6)}`
|
|
81
|
+
});
|
|
82
|
+
if (decl.init.callee.type === "Identifier" && decl.init.callee.name === "defineQuery") exports.imports.push({
|
|
83
|
+
name: decl.id.name,
|
|
84
|
+
type: "query",
|
|
85
|
+
as: `_${hash(decl.id.name + file.fullPath).replace(/-/g, "").slice(0, 6)}`
|
|
86
|
+
});
|
|
87
|
+
if (decl.init.callee.type === "Identifier" && decl.init.callee.name === "defineMutation") exports.imports.push({
|
|
88
|
+
name: decl.id.name,
|
|
89
|
+
type: "mutation",
|
|
90
|
+
as: `_${hash(decl.id.name + file.fullPath).replace(/-/g, "").slice(0, 6)}`
|
|
91
|
+
});
|
|
92
|
+
if (decl.init.callee.type === "Identifier" && decl.init.callee.name === "defineType") exports.imports.push({
|
|
93
|
+
name: decl.id.name,
|
|
94
|
+
type: "type",
|
|
95
|
+
as: `_${hash(decl.id.name + file.fullPath).replace(/-/g, "").slice(0, 6)}`
|
|
96
|
+
});
|
|
97
|
+
if (decl.init.callee.type === "Identifier" && decl.init.callee.name === "defineSubscription") exports.imports.push({
|
|
98
|
+
name: decl.id.name,
|
|
99
|
+
type: "subscription",
|
|
100
|
+
as: `_${hash(decl.id.name + file.fullPath).replace(/-/g, "").slice(0, 6)}`
|
|
101
|
+
});
|
|
102
|
+
if (decl.init.callee.type === "Identifier" && decl.init.callee.name === "defineDirective") exports.imports.push({
|
|
103
|
+
name: decl.id.name,
|
|
104
|
+
type: "directive",
|
|
105
|
+
as: `_${hash(decl.id.name + file.fullPath).replace(/-/g, "").slice(0, 6)}`
|
|
106
|
+
});
|
|
107
|
+
}
|
|
93
108
|
}
|
|
94
109
|
}
|
|
95
110
|
}
|
|
111
|
+
if (nitro.options.dev) {
|
|
112
|
+
const relPath = relative(nitro.options.rootDir, file.fullPath);
|
|
113
|
+
if (hasDefaultExport && !hasNamedExport) nitro.logger.warn(`[nitro-graphql] ${relPath}: Using default export instead of named export. Resolvers must use named exports like "export const myResolver = defineQuery(...)". Default exports are not detected.`);
|
|
114
|
+
if (exports.imports.length === 0 && hasNamedExport) {
|
|
115
|
+
const validFunctions = VALID_DEFINE_FUNCTIONS.join(", ");
|
|
116
|
+
nitro.logger.warn(`[nitro-graphql] ${relPath}: File has named exports [${namedExports.join(", ")}] but none use the required define functions (${validFunctions}). Exports will not be registered.`);
|
|
117
|
+
}
|
|
118
|
+
if (!hasDefaultExport && !hasNamedExport) nitro.logger.warn(`[nitro-graphql] ${relPath}: No exports found. Resolver files must export resolvers using defineResolver, defineQuery, defineMutation, etc.`);
|
|
119
|
+
}
|
|
96
120
|
if (exports.imports.length > 0) exportName.push(exports);
|
|
121
|
+
} catch (error) {
|
|
122
|
+
const relPath = relative(nitro.options.rootDir, file.fullPath);
|
|
123
|
+
nitro.logger.error(`[nitro-graphql] Failed to parse resolver file ${relPath}:`, error);
|
|
97
124
|
}
|
|
98
125
|
return exportName;
|
|
99
126
|
}
|
|
@@ -123,12 +150,10 @@ async function scanDirectives(nitro) {
|
|
|
123
150
|
return exportName;
|
|
124
151
|
}
|
|
125
152
|
async function scanTypeDefs(nitro) {
|
|
126
|
-
|
|
127
|
-
return files.map((f) => f.fullPath);
|
|
153
|
+
return (await scanFiles(nitro, "graphql", "**/*.typedef.{ts,js}")).map((f) => f.fullPath);
|
|
128
154
|
}
|
|
129
155
|
async function scanSchemas(nitro) {
|
|
130
|
-
|
|
131
|
-
return files.map((f) => f.fullPath);
|
|
156
|
+
return (await scanFiles(nitro, "graphql", "**/*.graphql")).map((f) => f.fullPath);
|
|
132
157
|
}
|
|
133
158
|
async function scanDocs(nitro) {
|
|
134
159
|
const files = await scanDir(nitro, nitro.options.rootDir, nitro.graphql.dir.client, "**/*.graphql");
|
|
@@ -141,16 +166,12 @@ async function scanDocs(nitro) {
|
|
|
141
166
|
seenPaths.add(file.fullPath);
|
|
142
167
|
return true;
|
|
143
168
|
});
|
|
144
|
-
const
|
|
145
|
-
const externalPatterns = externalServices.flatMap((service) => service.documents || []);
|
|
169
|
+
const externalPatterns = (nitro.options.graphql?.externalServices || []).flatMap((service) => service.documents || []);
|
|
146
170
|
return allFiles.filter((f) => !f.path.startsWith("external/")).filter((f) => {
|
|
147
171
|
const relativePath = f.path;
|
|
148
172
|
for (const pattern of externalPatterns) {
|
|
149
173
|
const clientDirPattern = `${nitro.graphql.dir.client}/`;
|
|
150
|
-
|
|
151
|
-
const patternDir = cleanPattern.split("/")[0];
|
|
152
|
-
const fileDir = relativePath.split("/")[0];
|
|
153
|
-
if (patternDir === fileDir) return false;
|
|
174
|
+
if (pattern.replace(/* @__PURE__ */ new RegExp(`^${clientDirPattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}`), "").split("/")[0] === relativePath.split("/")[0]) return false;
|
|
154
175
|
}
|
|
155
176
|
return true;
|
|
156
177
|
}).map((f) => f.fullPath);
|
|
@@ -213,7 +234,7 @@ async function scanFiles(nitro, name, globPattern = GLOB_SCAN_PATTERN) {
|
|
|
213
234
|
});
|
|
214
235
|
}
|
|
215
236
|
async function scanDir(nitro, dir, name, globPattern = GLOB_SCAN_PATTERN) {
|
|
216
|
-
|
|
237
|
+
return (await glob(join(name, globPattern), {
|
|
217
238
|
cwd: dir,
|
|
218
239
|
dot: true,
|
|
219
240
|
ignore: nitro.options.ignore,
|
|
@@ -224,8 +245,7 @@ async function scanDir(nitro, dir, name, globPattern = GLOB_SCAN_PATTERN) {
|
|
|
224
245
|
return [];
|
|
225
246
|
}
|
|
226
247
|
throw error;
|
|
227
|
-
})
|
|
228
|
-
return fileNames.map((fullPath) => {
|
|
248
|
+
})).map((fullPath) => {
|
|
229
249
|
return {
|
|
230
250
|
fullPath,
|
|
231
251
|
path: relative(join(dir, name), fullPath)
|
|
@@ -21,7 +21,7 @@ function pluginContent(_schema, _documents, _config, _info) {
|
|
|
21
21
|
};
|
|
22
22
|
}
|
|
23
23
|
async function generateTypes(selectFremework, schema, config = {}, outputPath) {
|
|
24
|
-
const
|
|
24
|
+
const mergedConfig = defu$1({
|
|
25
25
|
scalars: {
|
|
26
26
|
DateTime: DateTimeResolver.extensions.codegenScalarType,
|
|
27
27
|
DateTimeISO: DateTimeISOResolver.extensions.codegenScalarType,
|
|
@@ -43,9 +43,8 @@ async function generateTypes(selectFremework, schema, config = {}, outputPath) {
|
|
|
43
43
|
declarationKind: "interface",
|
|
44
44
|
enumsAsTypes: true,
|
|
45
45
|
...config.federation?.enabled && { federation: true }
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
const output = await codegen({
|
|
46
|
+
}, config.codegen?.server);
|
|
47
|
+
return await codegen({
|
|
49
48
|
filename: outputPath || "types.generated.ts",
|
|
50
49
|
schema: parse(printSchemaWithDirectives(schema)),
|
|
51
50
|
documents: [],
|
|
@@ -131,7 +130,6 @@ type ResolverReturnTypeObject<T extends object> =
|
|
|
131
130
|
consola.withTag("graphql").error("Error generating types:", e);
|
|
132
131
|
return "";
|
|
133
132
|
});
|
|
134
|
-
return output;
|
|
135
133
|
}
|
|
136
134
|
|
|
137
135
|
//#endregion
|
|
@@ -31,8 +31,7 @@ function generateNuxtOfetchClient(clientDir, serviceName = "default") {
|
|
|
31
31
|
const serviceDir = resolve(clientDir, serviceName);
|
|
32
32
|
const ofetchPath = resolve(serviceDir, "ofetch.ts");
|
|
33
33
|
if (!existsSync(serviceDir)) mkdirSync(serviceDir, { recursive: true });
|
|
34
|
-
if (!existsSync(ofetchPath))
|
|
35
|
-
const ofetchContent = `// This file is auto-generated once by nitro-graphql for quick start
|
|
34
|
+
if (!existsSync(ofetchPath)) writeFileSync(ofetchPath, `// This file is auto-generated once by nitro-graphql for quick start
|
|
36
35
|
// You can modify this file according to your needs
|
|
37
36
|
import type { Requester } from './sdk'
|
|
38
37
|
import { getSdk } from './sdk'
|
|
@@ -54,9 +53,7 @@ export function createGraphQLClient(endpoint: string): Requester {
|
|
|
54
53
|
}
|
|
55
54
|
}
|
|
56
55
|
|
|
57
|
-
export const $sdk = getSdk(createGraphQLClient('/api/graphql'))
|
|
58
|
-
writeFileSync(ofetchPath, ofetchContent, "utf-8");
|
|
59
|
-
}
|
|
56
|
+
export const $sdk = getSdk(createGraphQLClient('/api/graphql'))`, "utf-8");
|
|
60
57
|
}
|
|
61
58
|
function generateExternalOfetchClient(clientDir, serviceName, endpoint) {
|
|
62
59
|
const serviceDir = resolve(clientDir, serviceName);
|
|
@@ -64,7 +61,7 @@ function generateExternalOfetchClient(clientDir, serviceName, endpoint) {
|
|
|
64
61
|
if (!existsSync(serviceDir)) mkdirSync(serviceDir, { recursive: true });
|
|
65
62
|
if (!existsSync(ofetchPath)) {
|
|
66
63
|
const capitalizedServiceName = serviceName.charAt(0).toUpperCase() + serviceName.slice(1);
|
|
67
|
-
|
|
64
|
+
writeFileSync(ofetchPath, `// This file is auto-generated once by nitro-graphql for quick start
|
|
68
65
|
// You can modify this file according to your needs
|
|
69
66
|
import type { Sdk, Requester } from './sdk'
|
|
70
67
|
import { getSdk } from './sdk'
|
|
@@ -86,8 +83,7 @@ export function create${capitalizedServiceName}GraphQLClient(endpoint: string =
|
|
|
86
83
|
}
|
|
87
84
|
}
|
|
88
85
|
|
|
89
|
-
export const $${serviceName}Sdk: Sdk = getSdk(create${capitalizedServiceName}GraphQLClient())
|
|
90
|
-
writeFileSync(ofetchPath, ofetchContent, "utf-8");
|
|
86
|
+
export const $${serviceName}Sdk: Sdk = getSdk(create${capitalizedServiceName}GraphQLClient())`, "utf-8");
|
|
91
87
|
}
|
|
92
88
|
}
|
|
93
89
|
/**
|
|
@@ -127,8 +123,7 @@ function validateNoDuplicateTypes(schemas, schemaStrings) {
|
|
|
127
123
|
schemaStrings.forEach((schemaContent, index) => {
|
|
128
124
|
const fileName = basename(schemas[index]);
|
|
129
125
|
try {
|
|
130
|
-
|
|
131
|
-
document.definitions.forEach((def) => {
|
|
126
|
+
parse(schemaContent).definitions.forEach((def) => {
|
|
132
127
|
if (def.kind === "ObjectTypeDefinition" || def.kind === "InterfaceTypeDefinition" || def.kind === "UnionTypeDefinition" || def.kind === "EnumTypeDefinition" || def.kind === "InputObjectTypeDefinition" || def.kind === "ScalarTypeDefinition") {
|
|
133
128
|
const typeName = def.name.value;
|
|
134
129
|
if ([
|
|
@@ -148,8 +143,7 @@ function validateNoDuplicateTypes(schemas, schemaStrings) {
|
|
|
148
143
|
const content = schemaStrings[i];
|
|
149
144
|
if (!content) return false;
|
|
150
145
|
try {
|
|
151
|
-
|
|
152
|
-
return doc.definitions.some((d) => (d.kind === "ObjectTypeDefinition" || d.kind === "InterfaceTypeDefinition" || d.kind === "UnionTypeDefinition" || d.kind === "EnumTypeDefinition" || d.kind === "InputObjectTypeDefinition" || d.kind === "ScalarTypeDefinition") && d.name.value === typeName);
|
|
146
|
+
return parse(content).definitions.some((d) => (d.kind === "ObjectTypeDefinition" || d.kind === "InterfaceTypeDefinition" || d.kind === "UnionTypeDefinition" || d.kind === "EnumTypeDefinition" || d.kind === "InputObjectTypeDefinition" || d.kind === "ScalarTypeDefinition") && d.name.value === typeName);
|
|
153
147
|
} catch {
|
|
154
148
|
return false;
|
|
155
149
|
}
|
|
@@ -189,10 +183,8 @@ async function serverTypeGeneration(app) {
|
|
|
189
183
|
consola.info("No GraphQL definitions found for server type generation.");
|
|
190
184
|
return;
|
|
191
185
|
}
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
const isValid = validateNoDuplicateTypes(schemas, schemaStrings);
|
|
195
|
-
if (!isValid) return;
|
|
186
|
+
const schemaStrings = loadFilesSync(schemas).map((schema$1) => typeof schema$1 === "string" ? schema$1 : schema$1.loc?.source?.body || "").filter(Boolean);
|
|
187
|
+
if (!validateNoDuplicateTypes(schemas, schemaStrings)) return;
|
|
196
188
|
const federationEnabled = app.options.graphql?.federation?.enabled === true;
|
|
197
189
|
const mergedSchemas = mergeTypeDefs([schemaStrings.join("\n\n")], {
|
|
198
190
|
throwOnConflict: true,
|
|
@@ -214,8 +206,7 @@ async function serverTypeGeneration(app) {
|
|
|
214
206
|
}
|
|
215
207
|
async function clientTypeGeneration(nitro) {
|
|
216
208
|
try {
|
|
217
|
-
|
|
218
|
-
if (hasServerSchema) await generateMainClientTypes(nitro);
|
|
209
|
+
if (nitro.scanSchemas && nitro.scanSchemas.length > 0) await generateMainClientTypes(nitro);
|
|
219
210
|
if (nitro.options.graphql?.externalServices?.length) await generateExternalServicesTypes(nitro);
|
|
220
211
|
} catch (error) {
|
|
221
212
|
consola.error("Client schema generation error:", error);
|
|
@@ -259,9 +250,7 @@ async function generateMainClientTypes(nitro) {
|
|
|
259
250
|
return;
|
|
260
251
|
}
|
|
261
252
|
const graphqlString = readFileSync(schemaFilePath, "utf-8");
|
|
262
|
-
const
|
|
263
|
-
const schema = federationEnabled ? buildSubgraphSchema([{ typeDefs: parse(graphqlString) }]) : buildSchema(graphqlString);
|
|
264
|
-
const types = await generateClientTypes(schema, loadDocs, nitro.options.graphql?.codegen?.client ?? {}, nitro.options.graphql?.codegen?.clientSDK ?? {});
|
|
253
|
+
const types = await generateClientTypes(nitro.options.graphql?.federation?.enabled === true ? buildSubgraphSchema([{ typeDefs: parse(graphqlString) }]) : buildSchema(graphqlString), loadDocs, nitro.options.graphql?.codegen?.client ?? {}, nitro.options.graphql?.codegen?.clientSDK ?? {});
|
|
265
254
|
if (types === false) return;
|
|
266
255
|
const clientTypesPath = resolve(nitro.options.buildDir, "types", "nitro-graphql-client.d.ts");
|
|
267
256
|
const defaultServiceDir = resolve(nitro.graphql.clientDir, "default");
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nitro-graphql",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.5.0",
|
|
5
5
|
"description": "GraphQL integration for Nitro",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"sideEffects": false,
|
|
@@ -60,7 +60,6 @@
|
|
|
60
60
|
],
|
|
61
61
|
"peerDependencies": {
|
|
62
62
|
"@apollo/server": "^5.0.0",
|
|
63
|
-
"@apollo/subgraph": "^2.0.0",
|
|
64
63
|
"@apollo/utils.withrequired": "^3.0.0",
|
|
65
64
|
"@as-integrations/h3": "^2.0.0",
|
|
66
65
|
"graphql": "^16.11.0",
|
|
@@ -71,9 +70,6 @@
|
|
|
71
70
|
"@apollo/server": {
|
|
72
71
|
"optional": true
|
|
73
72
|
},
|
|
74
|
-
"@apollo/subgraph": {
|
|
75
|
-
"optional": true
|
|
76
|
-
},
|
|
77
73
|
"@apollo/utils.withrequired": {
|
|
78
74
|
"optional": true
|
|
79
75
|
},
|
|
@@ -82,46 +78,46 @@
|
|
|
82
78
|
}
|
|
83
79
|
},
|
|
84
80
|
"dependencies": {
|
|
85
|
-
"@
|
|
81
|
+
"@apollo/subgraph": "^2.11.3",
|
|
82
|
+
"@graphql-codegen/core": "^5.0.0",
|
|
86
83
|
"@graphql-codegen/import-types-preset": "^3.0.1",
|
|
87
|
-
"@graphql-codegen/typescript": "^
|
|
84
|
+
"@graphql-codegen/typescript": "^5.0.2",
|
|
88
85
|
"@graphql-codegen/typescript-generic-sdk": "^4.0.2",
|
|
89
|
-
"@graphql-codegen/typescript-operations": "^
|
|
90
|
-
"@graphql-codegen/typescript-resolvers": "^
|
|
91
|
-
"@graphql-tools/graphql-file-loader": "^8.1.
|
|
86
|
+
"@graphql-codegen/typescript-operations": "^5.0.2",
|
|
87
|
+
"@graphql-codegen/typescript-resolvers": "^5.1.0",
|
|
88
|
+
"@graphql-tools/graphql-file-loader": "^8.1.2",
|
|
92
89
|
"@graphql-tools/load": "^8.1.2",
|
|
93
90
|
"@graphql-tools/load-files": "^7.0.1",
|
|
94
91
|
"@graphql-tools/merge": "^9.1.1",
|
|
95
92
|
"@graphql-tools/schema": "^10.0.25",
|
|
96
|
-
"@graphql-tools/url-loader": "^
|
|
93
|
+
"@graphql-tools/url-loader": "^9.0.0",
|
|
97
94
|
"@graphql-tools/utils": "^10.9.1",
|
|
98
95
|
"chokidar": "^4.0.3",
|
|
99
96
|
"consola": "^3.4.2",
|
|
100
97
|
"defu": "^6.1.4",
|
|
101
98
|
"graphql-config": "^5.1.5",
|
|
102
|
-
"graphql-scalars": "^1.
|
|
99
|
+
"graphql-scalars": "^1.25.0",
|
|
103
100
|
"knitwork": "^1.2.0",
|
|
104
101
|
"ohash": "^2.0.11",
|
|
105
|
-
"oxc-parser": "^0.
|
|
102
|
+
"oxc-parser": "^0.95.0",
|
|
106
103
|
"pathe": "^2.0.3",
|
|
107
|
-
"tinyglobby": "^0.2.
|
|
104
|
+
"tinyglobby": "^0.2.15"
|
|
108
105
|
},
|
|
109
106
|
"devDependencies": {
|
|
110
|
-
"@antfu/eslint-config": "^
|
|
111
|
-
"@
|
|
112
|
-
"@nuxt/
|
|
113
|
-
"@
|
|
114
|
-
"
|
|
115
|
-
"bumpp": "^10.2.3",
|
|
107
|
+
"@antfu/eslint-config": "^6.0.0",
|
|
108
|
+
"@nuxt/kit": "^4.1.3",
|
|
109
|
+
"@nuxt/schema": "^4.1.3",
|
|
110
|
+
"@types/node": "^24.9.1",
|
|
111
|
+
"bumpp": "^10.3.1",
|
|
116
112
|
"changelogen": "^0.6.2",
|
|
117
113
|
"crossws": "0.3.5",
|
|
118
|
-
"eslint": "^9.
|
|
114
|
+
"eslint": "^9.38.0",
|
|
119
115
|
"graphql": "16.11.0",
|
|
120
|
-
"graphql-yoga": "^5.
|
|
116
|
+
"graphql-yoga": "^5.16.0",
|
|
121
117
|
"h3": "1.15.3",
|
|
122
|
-
"nitropack": "^2.12.
|
|
123
|
-
"tsdown": "^0.
|
|
124
|
-
"typescript": "^5.9.
|
|
118
|
+
"nitropack": "^2.12.7",
|
|
119
|
+
"tsdown": "^0.15.9",
|
|
120
|
+
"typescript": "^5.9.3"
|
|
125
121
|
},
|
|
126
122
|
"resolutions": {
|
|
127
123
|
"nitro-graphql": "link:."
|