@lewebsimple/nuxt-graphql 0.1.14 → 0.2.1
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 +1 -2
- package/dist/module.d.mts +20 -8
- package/dist/module.json +1 -1
- package/dist/module.mjs +296 -210
- package/dist/runtime/{composables → app/composables}/useGraphQLCache.d.ts +1 -1
- package/dist/runtime/{composables → app/composables}/useGraphQLMutation.d.ts +2 -3
- package/dist/runtime/{composables → app/composables}/useGraphQLQuery.d.ts +1 -1
- package/dist/runtime/{composables → app/composables}/useGraphQLSubscription.d.ts +1 -1
- package/dist/runtime/app/plugins/graphql.d.ts +31 -0
- package/dist/runtime/{plugins → app/plugins}/graphql.js +1 -0
- package/dist/runtime/server/api/graphql-handler.d.ts +2 -0
- package/dist/runtime/server/api/graphql-handler.js +14 -0
- package/dist/runtime/server/lib/constants.d.ts +1 -0
- package/dist/runtime/server/lib/constants.js +1 -0
- package/dist/runtime/server/lib/create-yoga.d.ts +1 -0
- package/dist/runtime/server/lib/create-yoga.js +17 -0
- package/dist/runtime/server/utils/useServerGraphQLMutation.d.ts +2 -3
- package/dist/runtime/server/utils/useServerGraphQLQuery.d.ts +1 -1
- package/package.json +8 -4
- package/dist/runtime/plugins/graphql.d.ts +0 -10
- package/dist/runtime/types/graphql-client.d.ts +0 -28
- package/dist/runtime/utils/helpers.d.ts +0 -1
- package/dist/runtime/utils/helpers.js +0 -0
- package/dist/templates/yoga-handler.mjs +0 -35
- /package/dist/runtime/{composables → app/composables}/useGraphQLCache.js +0 -0
- /package/dist/runtime/{composables → app/composables}/useGraphQLMutation.js +0 -0
- /package/dist/runtime/{composables → app/composables}/useGraphQLQuery.js +0 -0
- /package/dist/runtime/{composables → app/composables}/useGraphQLSubscription.js +0 -0
- /package/dist/runtime/{utils → app/utils}/graphql-cache.d.ts +0 -0
- /package/dist/runtime/{utils → app/utils}/graphql-cache.js +0 -0
- /package/dist/runtime/{utils → app/utils}/graphql-error.d.ts +0 -0
- /package/dist/runtime/{utils → app/utils}/graphql-error.js +0 -0
- /package/dist/runtime/server/{graphql → lib}/default-context.d.ts +0 -0
- /package/dist/runtime/server/{graphql → lib}/default-context.js +0 -0
package/README.md
CHANGED
|
@@ -14,6 +14,7 @@ Opinionated Nuxt module for using GraphQL Yoga with graphql-request / graphql-ss
|
|
|
14
14
|
- 🧘♂️ GraphQL Yoga server handler with user-provided schema / context
|
|
15
15
|
- 📄 Auto-import GraphQL documents from `**/*.gql` (configurable)
|
|
16
16
|
- 🧩 Type-safe composables to call operations by name, i.e. `useGraphQLQuery("Hello")`
|
|
17
|
+
- 🧵 Optional stitching of local schema with remote schemas (custom headers), with stitched SDL emitted to `server/graphql/schema.graphql`
|
|
17
18
|
|
|
18
19
|
## Quick Setup
|
|
19
20
|
|
|
@@ -30,8 +31,6 @@ Optionnally adjust options in your Nuxt config. The defaults shown below:
|
|
|
30
31
|
export default defineNuxtConfig({
|
|
31
32
|
modules: ["@lewebsimple/nuxt-graphql"],
|
|
32
33
|
graphql: {
|
|
33
|
-
// GraphQL HTTP endpoint served by Yoga
|
|
34
|
-
endpoint: "/api/graphql",
|
|
35
34
|
// Codegen controls document scanning and outputs
|
|
36
35
|
codegen: {
|
|
37
36
|
enabled: true,
|
package/dist/module.d.mts
CHANGED
|
@@ -1,19 +1,31 @@
|
|
|
1
1
|
import * as _nuxt_schema from '@nuxt/schema';
|
|
2
|
-
import { GraphQLCacheConfig } from '../dist/runtime/utils/graphql-cache.js';
|
|
3
|
-
import { CodegenConfig } from '@graphql-codegen/cli';
|
|
2
|
+
import { GraphQLCacheConfig } from '../dist/runtime/app/utils/graphql-cache.js';
|
|
4
3
|
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
type LocalSchema = {
|
|
5
|
+
type: "local";
|
|
6
|
+
path: string;
|
|
7
|
+
};
|
|
8
|
+
type RemoteSchema = {
|
|
9
|
+
type: "remote";
|
|
10
|
+
url: string;
|
|
7
11
|
headers?: Record<string, string>;
|
|
8
|
-
|
|
12
|
+
};
|
|
13
|
+
type SchemaDefinition = LocalSchema | RemoteSchema;
|
|
14
|
+
|
|
15
|
+
interface ModuleOptions {
|
|
16
|
+
context?: string;
|
|
17
|
+
schemas: Record<string, SchemaDefinition>;
|
|
9
18
|
codegen?: {
|
|
10
|
-
|
|
11
|
-
|
|
19
|
+
documents?: string;
|
|
20
|
+
saveSchema?: string;
|
|
12
21
|
scalars?: Record<string, string | {
|
|
13
22
|
input: string;
|
|
14
23
|
output: string;
|
|
15
24
|
}>;
|
|
16
|
-
|
|
25
|
+
};
|
|
26
|
+
client?: {
|
|
27
|
+
cache?: Partial<GraphQLCacheConfig>;
|
|
28
|
+
headers?: Record<string, string>;
|
|
17
29
|
};
|
|
18
30
|
}
|
|
19
31
|
declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { useLogger, defineNuxtModule, createResolver, getLayerDirectories,
|
|
1
|
+
import { useLogger, defineNuxtModule, createResolver, getLayerDirectories, addServerHandler, addPlugin, addImportsDir, addServerImportsDir } from '@nuxt/kit';
|
|
2
|
+
import { join, parse, relative, dirname } from 'node:path';
|
|
2
3
|
import { existsSync, readFileSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
3
|
-
import { join, dirname, relative } from 'node:path';
|
|
4
4
|
import { glob } from 'tinyglobby';
|
|
5
5
|
import { generate } from '@graphql-codegen/cli';
|
|
6
|
-
import { parse, Kind } from 'graphql';
|
|
6
|
+
import { parse as parse$1, Kind, getIntrospectionQuery, buildClientSchema, printSchema } from 'graphql';
|
|
7
|
+
import { GRAPHQL_ENDPOINT } from '../dist/runtime/server/lib/constants.js';
|
|
7
8
|
|
|
8
9
|
const logger = useLogger("@lewebsimple/nuxt-graphql");
|
|
9
10
|
const blue = "\x1B[34m";
|
|
@@ -43,8 +44,16 @@ function writeFileIfChanged(path, content) {
|
|
|
43
44
|
writeFileSync(path, content, "utf-8");
|
|
44
45
|
return true;
|
|
45
46
|
}
|
|
47
|
+
function toImportPath(from, to) {
|
|
48
|
+
const { dir, name } = parse(to);
|
|
49
|
+
let importPath = relative(dirname(from), join(dir, name));
|
|
50
|
+
if (!importPath.startsWith(".")) {
|
|
51
|
+
importPath = "./" + importPath;
|
|
52
|
+
}
|
|
53
|
+
return importPath;
|
|
54
|
+
}
|
|
46
55
|
|
|
47
|
-
async function
|
|
56
|
+
async function loadSchemaSdl(schemaPath) {
|
|
48
57
|
const { createJiti } = await import('jiti');
|
|
49
58
|
const jiti = createJiti(import.meta.url, { interopDefault: true });
|
|
50
59
|
const module = await jiti.import(schemaPath);
|
|
@@ -54,7 +63,67 @@ async function loadGraphQLSchema(schemaPath) {
|
|
|
54
63
|
const { printSchema, lexicographicSortSchema } = await import('graphql');
|
|
55
64
|
return printSchema(lexicographicSortSchema(module.schema));
|
|
56
65
|
}
|
|
57
|
-
function
|
|
66
|
+
async function runCodegen({ schema, documents, operationsPath, zodPath, scalars }) {
|
|
67
|
+
const generates = {
|
|
68
|
+
[operationsPath]: {
|
|
69
|
+
schema,
|
|
70
|
+
documents,
|
|
71
|
+
plugins: ["typescript", "typescript-operations", "typed-document-node"],
|
|
72
|
+
config: {
|
|
73
|
+
useTypeImports: true,
|
|
74
|
+
enumsAsTypes: true,
|
|
75
|
+
skipTypename: true,
|
|
76
|
+
documentVariableSuffix: "Document",
|
|
77
|
+
documentMode: "documentNode",
|
|
78
|
+
strictScalars: true,
|
|
79
|
+
defaultScalarType: "never",
|
|
80
|
+
scalars
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
if (zodPath) {
|
|
85
|
+
const zodScalars = {};
|
|
86
|
+
if (scalars) {
|
|
87
|
+
for (const [name, config] of Object.entries(scalars)) {
|
|
88
|
+
const inputType = typeof config === "string" ? config : config.input;
|
|
89
|
+
switch (inputType) {
|
|
90
|
+
case "Date":
|
|
91
|
+
zodScalars[name] = "z.coerce.date()";
|
|
92
|
+
break;
|
|
93
|
+
case "number":
|
|
94
|
+
zodScalars[name] = "z.coerce.number()";
|
|
95
|
+
break;
|
|
96
|
+
case "boolean":
|
|
97
|
+
zodScalars[name] = "z.coerce.boolean()";
|
|
98
|
+
break;
|
|
99
|
+
default:
|
|
100
|
+
zodScalars[name] = "z.string()";
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
generates[zodPath] = {
|
|
105
|
+
schema,
|
|
106
|
+
documents,
|
|
107
|
+
plugins: ["typescript-validation-schema"],
|
|
108
|
+
config: {
|
|
109
|
+
schema: "zodv4",
|
|
110
|
+
importFrom: "#graphql/operations",
|
|
111
|
+
useTypeImports: true,
|
|
112
|
+
directives: {
|
|
113
|
+
constraint: {
|
|
114
|
+
minLength: "min",
|
|
115
|
+
maxLength: "max",
|
|
116
|
+
pattern: "regex"
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
scalarSchemas: zodScalars
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
await generate({ generates, silent: true, errorsOnly: true }, true);
|
|
124
|
+
}
|
|
125
|
+
function analyzeDocuments(documents) {
|
|
126
|
+
const docs = documents.map((path) => ({ path, content: readFileSync(path, "utf-8") }));
|
|
58
127
|
const byFile = /* @__PURE__ */ new Map();
|
|
59
128
|
const operationsByType = {
|
|
60
129
|
query: [],
|
|
@@ -64,7 +133,7 @@ function analyzeGraphQLDocuments(docs) {
|
|
|
64
133
|
const operationNameToFile = /* @__PURE__ */ new Map();
|
|
65
134
|
const fragmentNameToFile = /* @__PURE__ */ new Map();
|
|
66
135
|
for (const doc of docs) {
|
|
67
|
-
const ast = parse(doc.content);
|
|
136
|
+
const ast = parse$1(doc.content);
|
|
68
137
|
const defs = [];
|
|
69
138
|
for (const def of ast.definitions) {
|
|
70
139
|
if (def.kind === Kind.FRAGMENT_DEFINITION) {
|
|
@@ -101,11 +170,26 @@ function analyzeGraphQLDocuments(docs) {
|
|
|
101
170
|
}
|
|
102
171
|
return { byFile, operationsByType };
|
|
103
172
|
}
|
|
104
|
-
function
|
|
105
|
-
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
173
|
+
function formatDefinitions(defs) {
|
|
174
|
+
if (defs.length === 0) return "";
|
|
175
|
+
const colorOf = (def) => {
|
|
176
|
+
if (def.kind === "fragment") return green;
|
|
177
|
+
switch (def.type) {
|
|
178
|
+
case "query":
|
|
179
|
+
return blue;
|
|
180
|
+
case "mutation":
|
|
181
|
+
return magenta;
|
|
182
|
+
case "subscription":
|
|
183
|
+
return yellow;
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
return defs.map((def) => `${colorOf(def)}${def.name}${reset}`).join(`${dim} / ${reset}`);
|
|
187
|
+
}
|
|
188
|
+
function writeRegistryModule(registryPath, { operationsByType }) {
|
|
189
|
+
const queries = operationsByType.query.map((o) => o.name);
|
|
190
|
+
const mutations = operationsByType.mutation.map((o) => o.name);
|
|
191
|
+
const subscriptions = operationsByType.subscription.map((o) => o.name);
|
|
192
|
+
const content = [
|
|
109
193
|
`import type { TypedDocumentNode } from "@graphql-typed-document-node/core";`,
|
|
110
194
|
`import * as ops from "#graphql/operations";`,
|
|
111
195
|
``,
|
|
@@ -113,138 +197,135 @@ function generateRegistryByTypeSource(analysis) {
|
|
|
113
197
|
`type VariablesOf<T> = T extends { __apiType?: (variables: infer V) => infer _ } ? V : never;`
|
|
114
198
|
];
|
|
115
199
|
if (queries.length > 0) {
|
|
116
|
-
|
|
200
|
+
content.push(
|
|
117
201
|
``,
|
|
202
|
+
`// Queries`,
|
|
118
203
|
`export const queries = {`,
|
|
119
204
|
...queries.map((name) => ` ${name}: ops.${name}Document,`),
|
|
120
205
|
`} as const;`
|
|
121
206
|
);
|
|
122
207
|
} else {
|
|
123
|
-
|
|
208
|
+
content.push(``, `export const queries = {} as const;`);
|
|
124
209
|
}
|
|
125
|
-
|
|
210
|
+
content.push(
|
|
211
|
+
``,
|
|
126
212
|
`export type QueryName = keyof typeof queries;`,
|
|
127
213
|
`export type QueryResult<N extends QueryName> = ResultOf<(typeof queries)[N]>;`,
|
|
128
214
|
`export type QueryVariables<N extends QueryName> = VariablesOf<(typeof queries)[N]>;`
|
|
129
215
|
);
|
|
130
216
|
if (mutations.length > 0) {
|
|
131
|
-
|
|
217
|
+
content.push(
|
|
132
218
|
``,
|
|
219
|
+
`// Mutations`,
|
|
133
220
|
`export const mutations = {`,
|
|
134
221
|
...mutations.map((name) => ` ${name}: ops.${name}Document,`),
|
|
135
222
|
`} as const;`
|
|
136
223
|
);
|
|
137
224
|
} else {
|
|
138
|
-
|
|
225
|
+
content.push(``, `export const mutations = {} as const;`);
|
|
139
226
|
}
|
|
140
|
-
|
|
227
|
+
content.push(
|
|
228
|
+
``,
|
|
141
229
|
`export type MutationName = keyof typeof mutations;`,
|
|
142
230
|
`export type MutationResult<N extends MutationName> = ResultOf<(typeof mutations)[N]>;`,
|
|
143
231
|
`export type MutationVariables<N extends MutationName> = VariablesOf<(typeof mutations)[N]>;`
|
|
144
232
|
);
|
|
145
233
|
if (subscriptions.length > 0) {
|
|
146
|
-
|
|
234
|
+
content.push(
|
|
147
235
|
``,
|
|
236
|
+
`// Subscriptions`,
|
|
148
237
|
`export const subscriptions = {`,
|
|
149
238
|
...subscriptions.map((name) => ` ${name}: ops.${name}Document,`),
|
|
150
239
|
`} as const;`
|
|
151
240
|
);
|
|
152
241
|
} else {
|
|
153
|
-
|
|
242
|
+
content.push(``, `export const subscriptions = {} as const;`);
|
|
154
243
|
}
|
|
155
|
-
|
|
244
|
+
content.push(
|
|
245
|
+
``,
|
|
156
246
|
`export type SubscriptionName = keyof typeof subscriptions;`,
|
|
157
247
|
`export type SubscriptionResult<N extends SubscriptionName> = ResultOf<(typeof subscriptions)[N]>;`,
|
|
158
248
|
`export type SubscriptionVariables<N extends SubscriptionName> = VariablesOf<(typeof subscriptions)[N]>;`
|
|
159
249
|
);
|
|
160
|
-
return
|
|
250
|
+
return writeFileIfChanged(registryPath, content.join("\n") + "\n");
|
|
161
251
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
case "mutation":
|
|
170
|
-
return magenta;
|
|
171
|
-
case "subscription":
|
|
172
|
-
return yellow;
|
|
173
|
-
}
|
|
174
|
-
};
|
|
175
|
-
return defs.map((def) => `${colorOf(def)}${def.name}${reset}`).join(`${dim} / ${reset}`);
|
|
176
|
-
}
|
|
177
|
-
async function runCodegen(options) {
|
|
178
|
-
const { schema, documents, operationsFile, schemasFile, scalars, generates: customGenerates } = options;
|
|
179
|
-
if (documents.length === 0) {
|
|
180
|
-
logger.warn("No GraphQL documents found");
|
|
181
|
-
return;
|
|
182
|
-
}
|
|
183
|
-
const zodScalars = {};
|
|
184
|
-
if (scalars) {
|
|
185
|
-
for (const [name, config] of Object.entries(scalars)) {
|
|
186
|
-
const inputType = typeof config === "string" ? config : config.input;
|
|
187
|
-
switch (inputType) {
|
|
188
|
-
case "Date":
|
|
189
|
-
zodScalars[name] = "z.coerce.date()";
|
|
190
|
-
break;
|
|
191
|
-
case "number":
|
|
192
|
-
zodScalars[name] = "z.coerce.number()";
|
|
193
|
-
break;
|
|
194
|
-
case "boolean":
|
|
195
|
-
zodScalars[name] = "z.coerce.boolean()";
|
|
196
|
-
break;
|
|
197
|
-
default:
|
|
198
|
-
zodScalars[name] = "z.string()";
|
|
199
|
-
}
|
|
200
|
-
}
|
|
252
|
+
|
|
253
|
+
const schemaHeader = "/* GraphQL */";
|
|
254
|
+
const escapeSDL = (sdl) => sdl.replace(/`/g, "\\`");
|
|
255
|
+
const serializeSDL = (sdl) => `${schemaHeader} \`${escapeSDL(sdl)}\``;
|
|
256
|
+
function writeLocalSchemaModule(localPath, modulePath) {
|
|
257
|
+
if (!existsSync(localPath)) {
|
|
258
|
+
throw new Error(`Local schema file not found at path: ${localPath}`);
|
|
201
259
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
scalars
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
};
|
|
220
|
-
if (schemasFile) {
|
|
221
|
-
generates[schemasFile] = {
|
|
222
|
-
schema,
|
|
223
|
-
documents,
|
|
224
|
-
plugins: ["typescript-validation-schema"],
|
|
225
|
-
config: {
|
|
226
|
-
schema: "zodv4",
|
|
227
|
-
importFrom: "#graphql/operations",
|
|
228
|
-
useTypeImports: true,
|
|
229
|
-
directives: {
|
|
230
|
-
constraint: {
|
|
231
|
-
minLength: "min",
|
|
232
|
-
maxLength: "max",
|
|
233
|
-
pattern: "regex"
|
|
234
|
-
}
|
|
235
|
-
},
|
|
236
|
-
scalarSchemas: zodScalars
|
|
237
|
-
}
|
|
238
|
-
};
|
|
239
|
-
if (customGenerates) {
|
|
240
|
-
Object.assign(generates, customGenerates);
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
await generate({ generates, silent: true, errorsOnly: true }, true);
|
|
244
|
-
logger.success(`Generated types for ${documents.length} document(s)`);
|
|
245
|
-
} catch (error) {
|
|
246
|
-
logger.error("GraphQL codegen failed:", error instanceof Error ? error.message : error);
|
|
260
|
+
const content = [
|
|
261
|
+
`export { schema } from ${JSON.stringify(toImportPath(modulePath, localPath))};`
|
|
262
|
+
].join("\n");
|
|
263
|
+
return writeFileIfChanged(modulePath, content);
|
|
264
|
+
}
|
|
265
|
+
async function writeRemoteSchemaSdl({ url, headers }, sdlPath) {
|
|
266
|
+
const response = await fetch(url, {
|
|
267
|
+
method: "POST",
|
|
268
|
+
headers: { "Content-Type": "application/json", ...headers },
|
|
269
|
+
body: JSON.stringify({ query: getIntrospectionQuery() })
|
|
270
|
+
});
|
|
271
|
+
const json = await response.json();
|
|
272
|
+
if (json.errors) {
|
|
273
|
+
throw new Error(`Failed to fetch remote schema from ${url}: ${JSON.stringify(json.errors)}`);
|
|
247
274
|
}
|
|
275
|
+
const schema = buildClientSchema(json.data);
|
|
276
|
+
const sdl = printSchema(schema);
|
|
277
|
+
const content = [`export const sdl = ${serializeSDL(sdl)};`, ""].join("\n");
|
|
278
|
+
return writeFileIfChanged(sdlPath, content);
|
|
279
|
+
}
|
|
280
|
+
function writeRemoteSchemaModule({ url, headers }, remoteSdlPath, modulePath) {
|
|
281
|
+
const headerSource = headers && Object.keys(headers).length > 0 ? JSON.stringify(headers, null, 2) : "{}";
|
|
282
|
+
const content = [
|
|
283
|
+
`import { buildSchema, print } from "graphql";`,
|
|
284
|
+
`import type { Executor } from "@graphql-tools/utils";`,
|
|
285
|
+
`import type { SubschemaConfig } from "@graphql-tools/delegate";`,
|
|
286
|
+
`import { sdl } from ${JSON.stringify(toImportPath(modulePath, remoteSdlPath))};`,
|
|
287
|
+
``,
|
|
288
|
+
`const endpoint = ${JSON.stringify(url)};`,
|
|
289
|
+
`const headers = ${headerSource} as Record<string, string>;`,
|
|
290
|
+
``,
|
|
291
|
+
`const executor: Executor = async ({ document, variables }) => {`,
|
|
292
|
+
` const query = typeof document === "string" ? document : print(document);`,
|
|
293
|
+
` const response = await fetch(endpoint, {`,
|
|
294
|
+
` method: "POST",`,
|
|
295
|
+
` headers: { "Content-Type": "application/json", ...headers },`,
|
|
296
|
+
` body: JSON.stringify({ query, variables }),`,
|
|
297
|
+
` });`,
|
|
298
|
+
``,
|
|
299
|
+
` return response.json();`,
|
|
300
|
+
`};`,
|
|
301
|
+
``,
|
|
302
|
+
`export const schema: SubschemaConfig = {`,
|
|
303
|
+
` schema: buildSchema(sdl),`,
|
|
304
|
+
` executor,`,
|
|
305
|
+
`};`,
|
|
306
|
+
``
|
|
307
|
+
].join("\n");
|
|
308
|
+
return writeFileIfChanged(modulePath, content);
|
|
309
|
+
}
|
|
310
|
+
function writeStitchedSchemaModule(schemaNames, modulePath) {
|
|
311
|
+
const schemas = schemaNames.map((name) => ({
|
|
312
|
+
path: `./schemas/${name}`,
|
|
313
|
+
ref: `${name}Schema`
|
|
314
|
+
}));
|
|
315
|
+
const content = [
|
|
316
|
+
`import { stitchSchemas } from "@graphql-tools/stitch";`,
|
|
317
|
+
`import type { GraphQLSchema } from "graphql";`,
|
|
318
|
+
`import type { SubschemaConfig } from "@graphql-tools/delegate";`,
|
|
319
|
+
...schemas.map(({ path, ref }) => `import { schema as ${ref} } from ${JSON.stringify(path)};`),
|
|
320
|
+
``,
|
|
321
|
+
`const subschemas: Array<GraphQLSchema | SubschemaConfig> = [`,
|
|
322
|
+
...schemas.map(({ ref }) => ` ${ref},`),
|
|
323
|
+
`];`,
|
|
324
|
+
``,
|
|
325
|
+
`export const schema = stitchSchemas({ subschemas });`,
|
|
326
|
+
``
|
|
327
|
+
].join("\n");
|
|
328
|
+
return writeFileIfChanged(modulePath, content);
|
|
248
329
|
}
|
|
249
330
|
|
|
250
331
|
const module$1 = defineNuxtModule({
|
|
@@ -253,124 +334,129 @@ const module$1 = defineNuxtModule({
|
|
|
253
334
|
configKey: "graphql"
|
|
254
335
|
},
|
|
255
336
|
defaults: {
|
|
256
|
-
|
|
337
|
+
schemas: {},
|
|
257
338
|
codegen: {
|
|
258
|
-
|
|
259
|
-
|
|
339
|
+
documents: "**/*.gql",
|
|
340
|
+
saveSchema: "server/graphql/schema.graphql"
|
|
341
|
+
},
|
|
342
|
+
client: {
|
|
343
|
+
headers: {},
|
|
344
|
+
cache: {
|
|
345
|
+
enabled: false,
|
|
346
|
+
ttl: 6e4,
|
|
347
|
+
storage: "memory"
|
|
348
|
+
}
|
|
260
349
|
}
|
|
261
350
|
},
|
|
262
351
|
async setup(options, nuxt) {
|
|
263
352
|
const { resolve } = createResolver(import.meta.url);
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
353
|
+
const layerRootDirs = getLayerDirectories(nuxt).map(({ root }) => root);
|
|
354
|
+
const stitchedPath = join(nuxt.options.buildDir, "graphql/schema.ts");
|
|
355
|
+
const sdlPath = join(nuxt.options.rootDir, options.codegen?.saveSchema || ".nuxt/graphql/schema.graphql");
|
|
356
|
+
nuxt.options.alias ||= {};
|
|
357
|
+
if (!Object.keys(options.schemas || {}).length) {
|
|
358
|
+
throw new Error("No GraphQL schemas configured. Please set 'graphql.schemas' with at least one local or remote schema.");
|
|
268
359
|
}
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
const contextPath = await findSingleFile(layerServerDirs, "graphql/context.{ts,mjs}") || resolve("./runtime/server/graphql/default-context.ts");
|
|
278
|
-
nuxt.hook("nitro:config", (config) => {
|
|
279
|
-
config.alias ||= {};
|
|
280
|
-
config.alias["#graphql/schema"] = schemaPath;
|
|
281
|
-
config.alias["#graphql/context"] = contextPath;
|
|
282
|
-
});
|
|
283
|
-
const endpoint = options.endpoint ?? "/api/graphql";
|
|
284
|
-
addServerTemplate({
|
|
285
|
-
filename: "graphql/yoga-handler",
|
|
286
|
-
getContents: () => readFileSync(resolve("./templates/yoga-handler.mjs"), "utf-8").replace("{{endpoint}}", endpoint)
|
|
287
|
-
});
|
|
288
|
-
addServerHandler({ route: endpoint, handler: "graphql/yoga-handler" });
|
|
289
|
-
nuxt.hook("listen", (_, { url }) => {
|
|
290
|
-
logger.success(`GraphQL Yoga ready at ${cyan}${url.replace(/\/$/, "")}${endpoint}${reset}`);
|
|
291
|
-
});
|
|
292
|
-
nuxt.options.runtimeConfig.public.graphql = {
|
|
293
|
-
endpoint,
|
|
294
|
-
headers: options.headers || {},
|
|
295
|
-
cache: {
|
|
296
|
-
enabled: options.cache?.enabled ?? false,
|
|
297
|
-
ttl: options.cache?.ttl ?? 6e4,
|
|
298
|
-
storage: options.cache?.storage ?? "memory"
|
|
360
|
+
async function setupContextSchemas() {
|
|
361
|
+
let contextPath;
|
|
362
|
+
if (options.context) {
|
|
363
|
+
contextPath = await findSingleFile(layerRootDirs, options.context, true);
|
|
364
|
+
logger.info(`Using GraphQL context from ${cyan}${relative(nuxt.options.rootDir, contextPath)}${reset}`);
|
|
365
|
+
} else {
|
|
366
|
+
contextPath = resolve("./runtime/server/graphql/context");
|
|
367
|
+
logger.info(`Using default GraphQL context`);
|
|
299
368
|
}
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
const [schema, documents] = await Promise.all([
|
|
316
|
-
loadGraphQLSchema(schemaPath),
|
|
317
|
-
findMultipleFiles(layerRootDirs, codegenPattern)
|
|
318
|
-
]);
|
|
319
|
-
const docs = documents.map((document) => ({ path: document, content: readFileSync(document, "utf-8") }));
|
|
320
|
-
const analysis = analyzeGraphQLDocuments(docs);
|
|
321
|
-
for (const doc of docs) {
|
|
322
|
-
const relativePath = doc.path.startsWith(rootDir) ? doc.path.slice(rootDir.length + 1) : doc.path;
|
|
323
|
-
const defs = analysis.byFile.get(doc.path) ?? [];
|
|
324
|
-
logger.info(`${cyan}${relativePath}${reset} [${formatDefinitions(defs)}]`);
|
|
369
|
+
const schemasPath = {};
|
|
370
|
+
for (const [name, schemaDef] of Object.entries(options.schemas)) {
|
|
371
|
+
schemasPath[name] = join(nuxt.options.buildDir, `graphql/schemas/${name}.ts`);
|
|
372
|
+
if (schemaDef.type === "local") {
|
|
373
|
+
const localPath = await findSingleFile(layerRootDirs, schemaDef.path, true);
|
|
374
|
+
writeLocalSchemaModule(localPath, schemasPath[name]);
|
|
375
|
+
logger.info(`Local GraphQL schema "${blue}${name}${reset}" loaded from ${cyan}${relative(nuxt.options.rootDir, localPath)}${reset}`);
|
|
376
|
+
} else if (schemaDef.type === "remote") {
|
|
377
|
+
const remoteSdlPath = join(nuxt.options.buildDir, `graphql/schemas/${name}-sdl.ts`);
|
|
378
|
+
await writeRemoteSchemaSdl(schemaDef, remoteSdlPath);
|
|
379
|
+
writeRemoteSchemaModule(schemaDef, remoteSdlPath, schemasPath[name]);
|
|
380
|
+
logger.info(`Remote GraphQL schema "${magenta}${name}${reset}" loaded from ${cyan}${schemaDef.url}${reset}`);
|
|
381
|
+
} else {
|
|
382
|
+
throw new Error(`Unknown schema type for schema '${name}'`);
|
|
383
|
+
}
|
|
325
384
|
}
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
385
|
+
writeStitchedSchemaModule(Object.keys(options.schemas), stitchedPath);
|
|
386
|
+
nuxt.hook("nitro:config", (config) => {
|
|
387
|
+
config.alias ||= {};
|
|
388
|
+
config.alias["#graphql/context"] = contextPath;
|
|
389
|
+
for (const name of Object.keys(options.schemas)) {
|
|
390
|
+
config.alias[`#graphql/schemas/${name}`] = schemasPath[name];
|
|
391
|
+
}
|
|
392
|
+
config.alias["#graphql/schema"] = stitchedPath;
|
|
333
393
|
});
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
const
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
394
|
+
}
|
|
395
|
+
async function setupCodegen() {
|
|
396
|
+
const configPath = join(nuxt.options.rootDir, ".graphqlrc");
|
|
397
|
+
const operationsPath = nuxt.options.alias["#graphql/operations"] = join(nuxt.options.buildDir, "graphql/operations.ts");
|
|
398
|
+
const registryPath = nuxt.options.alias["#graphql/registry"] = join(nuxt.options.buildDir, "graphql/registry.ts");
|
|
399
|
+
const zodPath = nuxt.options.alias["#graphql/zod"] = join(nuxt.options.buildDir, "graphql/zod.ts");
|
|
400
|
+
async function generate() {
|
|
401
|
+
try {
|
|
402
|
+
const sdlContent = await loadSchemaSdl(stitchedPath);
|
|
403
|
+
writeFileIfChanged(sdlPath, sdlContent);
|
|
404
|
+
const documentsPattern = options.codegen?.documents ?? "**/*.gql";
|
|
405
|
+
const documents = await findMultipleFiles(layerRootDirs, documentsPattern);
|
|
406
|
+
await runCodegen({ schema: sdlPath, documents, operationsPath, zodPath, scalars: options.codegen?.scalars });
|
|
407
|
+
const analysis = analyzeDocuments(documents);
|
|
408
|
+
analysis.byFile.forEach((defs, path) => {
|
|
409
|
+
const relativePath = relative(nuxt.options.rootDir, path);
|
|
410
|
+
logger.info(`${cyan}${relativePath}${reset} [${formatDefinitions(defs)}]`);
|
|
411
|
+
});
|
|
412
|
+
writeRegistryModule(registryPath, analysis);
|
|
413
|
+
const config = {
|
|
414
|
+
schema: relative(nuxt.options.rootDir, sdlPath),
|
|
415
|
+
documents: documentsPattern
|
|
416
|
+
};
|
|
417
|
+
writeFileIfChanged(configPath, JSON.stringify(config, null, 2));
|
|
418
|
+
} catch (error) {
|
|
419
|
+
logger.warn(`GraphQL codegen failed: ${error.message}`);
|
|
420
|
+
}
|
|
346
421
|
}
|
|
347
|
-
|
|
348
|
-
|
|
422
|
+
nuxt.hook("prepare:types", async ({ references }) => {
|
|
423
|
+
await generate();
|
|
424
|
+
references.push({ path: operationsPath });
|
|
425
|
+
references.push({ path: registryPath });
|
|
426
|
+
references.push({ path: zodPath });
|
|
427
|
+
});
|
|
428
|
+
if (nuxt.options.dev) {
|
|
429
|
+
nuxt.hook("builder:watch", async (event, path) => {
|
|
430
|
+
if (path.endsWith(".gql")) {
|
|
431
|
+
await generate();
|
|
432
|
+
}
|
|
433
|
+
});
|
|
349
434
|
}
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
if (existsSync(schemasFile)) references.push({ path: schemasFile });
|
|
356
|
-
});
|
|
357
|
-
if (nuxt.options.dev) {
|
|
358
|
-
nuxt.hook("builder:watch", async (event, path) => {
|
|
359
|
-
if (path.endsWith(".gql")) {
|
|
360
|
-
await generate();
|
|
361
|
-
}
|
|
435
|
+
}
|
|
436
|
+
function setupYogaHandler() {
|
|
437
|
+
addServerHandler({ route: GRAPHQL_ENDPOINT, handler: resolve("./runtime/server/api/graphql-handler") });
|
|
438
|
+
nuxt.hook("listen", (_, { url }) => {
|
|
439
|
+
logger.success(`GraphQL Yoga ready at ${cyan}${url.replace(/\/$/, "")}${GRAPHQL_ENDPOINT}${reset}`);
|
|
362
440
|
});
|
|
363
441
|
}
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
442
|
+
function setupClient() {
|
|
443
|
+
nuxt.options.runtimeConfig.public.graphql = {
|
|
444
|
+
endpoint: GRAPHQL_ENDPOINT,
|
|
445
|
+
headers: options.client?.headers || {},
|
|
446
|
+
cache: {
|
|
447
|
+
enabled: options.client?.cache?.enabled ?? false,
|
|
448
|
+
ttl: options.client?.cache?.ttl ?? 6e4,
|
|
449
|
+
storage: options.client?.cache?.storage ?? "memory"
|
|
450
|
+
}
|
|
451
|
+
};
|
|
452
|
+
addPlugin(resolve("./runtime/app/plugins/graphql"));
|
|
453
|
+
addImportsDir(resolve("./runtime/app/composables"));
|
|
454
|
+
addServerImportsDir(resolve("./runtime/server/utils"));
|
|
455
|
+
}
|
|
456
|
+
await setupContextSchemas();
|
|
457
|
+
await setupCodegen();
|
|
458
|
+
setupYogaHandler();
|
|
459
|
+
setupClient();
|
|
374
460
|
}
|
|
375
461
|
});
|
|
376
462
|
|
|
@@ -5,6 +5,6 @@ import type { QueryName, QueryVariables } from "#graphql/registry";
|
|
|
5
5
|
* @returns Object with enabled flag and invalidate function
|
|
6
6
|
*/
|
|
7
7
|
export declare function useGraphQLCache(): {
|
|
8
|
-
enabled:
|
|
8
|
+
enabled: boolean;
|
|
9
9
|
invalidate: <N extends QueryName>(operationName?: N, variables?: QueryVariables<N>) => Promise<void>;
|
|
10
10
|
};
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { type MutationName, type MutationResult
|
|
2
|
-
import type { IsEmptyObject } from "../utils/helpers.js";
|
|
1
|
+
import { type MutationName, type MutationResult } from "#graphql/registry";
|
|
3
2
|
/**
|
|
4
3
|
* Client-side GraphQL mutation composable
|
|
5
4
|
*
|
|
@@ -7,7 +6,7 @@ import type { IsEmptyObject } from "../utils/helpers.js";
|
|
|
7
6
|
* @returns Object with mutate function and pending state
|
|
8
7
|
*/
|
|
9
8
|
export declare function useGraphQLMutation<N extends MutationName>(operationName: N): {
|
|
10
|
-
mutate: (
|
|
9
|
+
mutate: (variables: MutationVariables<N>, headers?: HeadersInit | undefined) => Promise<{
|
|
11
10
|
data: MutationResult<N> | null;
|
|
12
11
|
error: Error | null;
|
|
13
12
|
}>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { AsyncData, AsyncDataOptions } from "#app";
|
|
2
2
|
import { type QueryName, type QueryResult, type QueryVariables } from "#graphql/registry";
|
|
3
3
|
import { type CacheOptions } from "../utils/graphql-cache.js";
|
|
4
|
-
import type { IsEmptyObject } from "
|
|
4
|
+
import type { IsEmptyObject } from "../../../helpers/is-empty-object.js";
|
|
5
5
|
export interface UseGraphQLQueryOptions<T> extends AsyncDataOptions<T> {
|
|
6
6
|
cache?: CacheOptions | false;
|
|
7
7
|
headers?: HeadersInit;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type MaybeRefOrGetter, type Ref } from "vue";
|
|
2
2
|
import { type SubscriptionName, type SubscriptionResult, type SubscriptionVariables } from "#graphql/registry";
|
|
3
3
|
import { type GraphQLClientError } from "../utils/graphql-error.js";
|
|
4
|
-
import type { IsEmptyObject } from "
|
|
4
|
+
import type { IsEmptyObject } from "../../../helpers/is-empty-object.js";
|
|
5
5
|
export type UseGraphQLSubscriptionReturn<N extends SubscriptionName> = {
|
|
6
6
|
data: Ref<SubscriptionResult<N> | null>;
|
|
7
7
|
error: Ref<GraphQLClientError | null>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { GraphQLClient } from "graphql-request";
|
|
2
|
+
import { type Client as SSEClient } from "graphql-sse";
|
|
3
|
+
import { type GraphQLClientError } from "../utils/graphql-error.js";
|
|
4
|
+
import type { GraphQLCacheConfig } from "../utils/graphql-cache.js";
|
|
5
|
+
declare const _default: import("#app").Plugin<{
|
|
6
|
+
graphql: () => GraphQLClient;
|
|
7
|
+
graphqlSSE: () => SSEClient;
|
|
8
|
+
}> & import("#app").ObjectPlugin<{
|
|
9
|
+
graphql: () => GraphQLClient;
|
|
10
|
+
graphqlSSE: () => SSEClient;
|
|
11
|
+
}>;
|
|
12
|
+
export default _default;
|
|
13
|
+
declare module "#app" {
|
|
14
|
+
interface NuxtApp {
|
|
15
|
+
$graphql: () => GraphQLClient;
|
|
16
|
+
$graphqlSSE: () => SSEClient;
|
|
17
|
+
}
|
|
18
|
+
interface RuntimeNuxtHooks {
|
|
19
|
+
"graphql:error": (error: GraphQLClientError) => void;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
declare module "nuxt/schema" {
|
|
23
|
+
interface PublicRuntimeConfig {
|
|
24
|
+
graphql: {
|
|
25
|
+
endpoint: string;
|
|
26
|
+
headers: Record<string, string>;
|
|
27
|
+
cache: GraphQLCacheConfig;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { defineEventHandler, toWebRequest, sendWebResponse, createError } from "h3";
|
|
2
|
+
import { getYoga } from "../lib/create-yoga.js";
|
|
3
|
+
export default defineEventHandler(async (event) => {
|
|
4
|
+
try {
|
|
5
|
+
const request = toWebRequest(event);
|
|
6
|
+
const context = {};
|
|
7
|
+
const response = await getYoga().handleRequest(request, context);
|
|
8
|
+
return sendWebResponse(event, response);
|
|
9
|
+
} catch (error) {
|
|
10
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
11
|
+
console.error("GraphQL Server Error:", message);
|
|
12
|
+
throw createError({ statusCode: 500, message: "GraphQL server error" });
|
|
13
|
+
}
|
|
14
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const GRAPHQL_ENDPOINT = "/api/graphql";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const GRAPHQL_ENDPOINT = "/api/graphql";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function getYoga(): import("graphql-yoga").YogaServerInstance<Record<string, any>, Record<string, any>>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { createYoga } from "graphql-yoga";
|
|
2
|
+
import { schema } from "#graphql/schema";
|
|
3
|
+
import { GRAPHQL_ENDPOINT } from "./constants.js";
|
|
4
|
+
let yoga = null;
|
|
5
|
+
export function getYoga() {
|
|
6
|
+
if (!yoga) {
|
|
7
|
+
yoga = createYoga({
|
|
8
|
+
schema,
|
|
9
|
+
graphqlEndpoint: GRAPHQL_ENDPOINT,
|
|
10
|
+
fetchAPI: globalThis,
|
|
11
|
+
graphiql: process.env.NODE_ENV !== "production",
|
|
12
|
+
// @ts-expect-error Subscriptions type missing in module context
|
|
13
|
+
subscriptions: { protocol: "SSE" }
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
return yoga;
|
|
17
|
+
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { H3Event } from "h3";
|
|
2
|
-
import { type MutationName, type MutationResult
|
|
3
|
-
import type { IsEmptyObject } from "../../utils/helpers.js";
|
|
2
|
+
import { type MutationName, type MutationResult } from "#graphql/registry";
|
|
4
3
|
/**
|
|
5
4
|
* Server-side GraphQL mutation composable
|
|
6
5
|
*
|
|
@@ -9,7 +8,7 @@ import type { IsEmptyObject } from "../../utils/helpers.js";
|
|
|
9
8
|
* @returns Object with mutate function
|
|
10
9
|
*/
|
|
11
10
|
export declare function useServerGraphQLMutation<N extends MutationName>(event: H3Event, operationName: N): Promise<{
|
|
12
|
-
mutate: (
|
|
11
|
+
mutate: (variables: MutationVariables<N>, headers?: HeadersInit | undefined) => Promise<{
|
|
13
12
|
data: MutationResult<N> | null;
|
|
14
13
|
error: Error | null;
|
|
15
14
|
}>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { H3Event } from "h3";
|
|
2
2
|
import { type QueryName, type QueryResult, type QueryVariables } from "#graphql/registry";
|
|
3
|
-
import type { IsEmptyObject } from "
|
|
3
|
+
import type { IsEmptyObject } from "../../../helpers/is-empty-object.js";
|
|
4
4
|
/**
|
|
5
5
|
* Server-side GraphQL query composable
|
|
6
6
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lewebsimple/nuxt-graphql",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Opinionated Nuxt module for using GraphQL",
|
|
5
5
|
"repository": "lewebsimple/nuxt-graphql",
|
|
6
6
|
"license": "MIT",
|
|
@@ -39,6 +39,10 @@
|
|
|
39
39
|
"@graphql-codegen/typed-document-node": "^6.1.5",
|
|
40
40
|
"@graphql-codegen/typescript": "^5.0.7",
|
|
41
41
|
"@graphql-codegen/typescript-operations": "^5.0.7",
|
|
42
|
+
"@graphql-tools/delegate": "^12.0.2",
|
|
43
|
+
"@graphql-tools/stitch": "^10.1.6",
|
|
44
|
+
"@graphql-tools/utils": "^10.11.0",
|
|
45
|
+
"@graphql-tools/wrap": "^11.1.2",
|
|
42
46
|
"@graphql-typed-document-node/core": "^3.2.0",
|
|
43
47
|
"@nuxt/kit": "^4.2.2",
|
|
44
48
|
"graphql": "^16.12.0",
|
|
@@ -59,13 +63,13 @@
|
|
|
59
63
|
"@nuxt/schema": "^4.2.2",
|
|
60
64
|
"@nuxt/test-utils": "^3.22.0",
|
|
61
65
|
"@types/node": "latest",
|
|
62
|
-
"@vitest/coverage-v8": "^
|
|
66
|
+
"@vitest/coverage-v8": "^3.2.4",
|
|
63
67
|
"changelogen": "^0.6.2",
|
|
64
68
|
"eslint": "^9.39.2",
|
|
65
69
|
"nuxt": "^4.2.2",
|
|
66
70
|
"typescript": "~5.9.3",
|
|
67
|
-
"vitest": "^
|
|
68
|
-
"vue-tsc": "^3.2.
|
|
71
|
+
"vitest": "^3.2.4",
|
|
72
|
+
"vue-tsc": "^3.2.2"
|
|
69
73
|
},
|
|
70
74
|
"publishConfig": {
|
|
71
75
|
"access": "public"
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { GraphQLClient } from "graphql-request";
|
|
2
|
-
import { type Client as SSEClient } from "graphql-sse";
|
|
3
|
-
declare const _default: import("nuxt/app").Plugin<{
|
|
4
|
-
graphql: () => GraphQLClient;
|
|
5
|
-
graphqlSSE: () => SSEClient;
|
|
6
|
-
}> & import("nuxt/app").ObjectPlugin<{
|
|
7
|
-
graphql: () => GraphQLClient;
|
|
8
|
-
graphqlSSE: () => SSEClient;
|
|
9
|
-
}>;
|
|
10
|
-
export default _default;
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import type { GraphQLClient } from "graphql-request";
|
|
2
|
-
import type { Client as SSEClient } from "graphql-sse";
|
|
3
|
-
import type { GraphQLClientError } from "../utils/graphql-error";
|
|
4
|
-
|
|
5
|
-
// Extend NuxtApp with GraphQL clients
|
|
6
|
-
declare module "#app" {
|
|
7
|
-
interface NuxtApp {
|
|
8
|
-
$graphql: () => GraphQLClient;
|
|
9
|
-
$graphqlSSE: () => SSEClient;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
interface RuntimeNuxtHooks {
|
|
13
|
-
"graphql:error": (error: GraphQLClientError) => void;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// Extend Nuxt runtime config with GraphQL options
|
|
18
|
-
declare module "nuxt/schema" {
|
|
19
|
-
interface PublicRuntimeConfig {
|
|
20
|
-
graphql: {
|
|
21
|
-
endpoint: string;
|
|
22
|
-
headers: Record<string, string>;
|
|
23
|
-
cache: GraphQLCacheConfig;
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export { };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export type IsEmptyObject<T> = T extends Record<string, never> ? true : keyof T extends never ? true : false;
|
|
File without changes
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { createYoga } from "graphql-yoga";
|
|
2
|
-
import { defineEventHandler, toWebRequest, sendWebResponse, createError } from "h3";
|
|
3
|
-
import { schema } from "#graphql/schema";
|
|
4
|
-
import { createContext } from "#graphql/context";
|
|
5
|
-
import { useLogger } from "@nuxt/kit";
|
|
6
|
-
|
|
7
|
-
let yoga = null;
|
|
8
|
-
|
|
9
|
-
function getYoga() {
|
|
10
|
-
if (!yoga) {
|
|
11
|
-
yoga = createYoga({
|
|
12
|
-
schema,
|
|
13
|
-
graphqlEndpoint: "{{endpoint}}",
|
|
14
|
-
fetchAPI: globalThis,
|
|
15
|
-
graphiql: process.env.NODE_ENV !== "production",
|
|
16
|
-
subscriptions: { protocol: "SSE" },
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
return yoga;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export default defineEventHandler(async (event) => {
|
|
23
|
-
const logger = useLogger();
|
|
24
|
-
try {
|
|
25
|
-
const request = toWebRequest(event);
|
|
26
|
-
const context = await createContext(event);
|
|
27
|
-
const response = await getYoga().handleRequest(request, context);
|
|
28
|
-
return sendWebResponse(event, response);
|
|
29
|
-
}
|
|
30
|
-
catch (error) {
|
|
31
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
32
|
-
logger.error("GraphQL Server Error:", message);
|
|
33
|
-
throw createError({ statusCode: 500, message: "GraphQL server error" });
|
|
34
|
-
}
|
|
35
|
-
});
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|