@wpnuxt/core 1.0.0-edge.9 → 2.0.0-alpha.2
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-options.d.mts +1 -0
- package/dist/client-options.d.ts +1 -0
- package/dist/client-options.mjs +1 -0
- package/dist/module.d.mts +72 -82
- package/dist/module.d.ts +72 -82
- package/dist/module.json +4 -5
- package/dist/module.mjs +601 -271
- package/dist/runtime/app/graphqlMiddleware.clientOptions.d.ts +0 -0
- package/dist/runtime/app/graphqlMiddleware.clientOptions.js +12 -0
- package/dist/runtime/components/WPNuxtLogo.d.vue.ts +0 -0
- package/dist/runtime/components/WPNuxtLogo.vue +7 -7
- package/dist/runtime/components/WPNuxtLogo.vue.d.ts +0 -0
- package/dist/runtime/composables/useWPContent.d.ts +0 -5
- package/dist/runtime/composables/useWPContent.js +30 -16
- package/dist/runtime/plugins/graphqlConfig.d.ts +0 -0
- package/dist/runtime/plugins/graphqlConfig.js +17 -0
- package/dist/runtime/plugins/graphqlErrors.d.ts +0 -0
- package/dist/runtime/plugins/graphqlErrors.js +9 -0
- package/dist/runtime/queries/GeneralSettings.gql +0 -2
- package/dist/runtime/queries/Menu.gql +0 -2
- package/dist/runtime/queries/Node.gql +0 -3
- package/dist/runtime/queries/Pages.gql +0 -2
- package/dist/runtime/queries/Posts.gql +15 -2
- package/dist/runtime/queries/Viewer.gql +4 -4
- package/dist/runtime/queries/fragments/GeneralSettings.fragment.gql +0 -1
- package/dist/runtime/queries/fragments/NodeWithFeaturedImage.fragment.gql +0 -2
- package/dist/runtime/queries/fragments/NodeWithFeaturedImageToMediaItemConnectionEdge.fragment.gql +0 -2
- package/dist/runtime/queries/fragments/Page.fragment.gql +0 -4
- package/dist/runtime/queries/fragments/Post.fragment.gql +8 -5
- package/dist/runtime/server/graphqlMiddleware.serverOptions.d.ts +0 -0
- package/dist/runtime/server/graphqlMiddleware.serverOptions.js +18 -0
- package/dist/runtime/server/tsconfig.json +3 -0
- package/dist/runtime/types/stub.d.ts +22 -0
- package/dist/runtime/util/images.d.ts +0 -2
- package/dist/runtime/util/images.js +11 -3
- package/dist/server-options.d.mts +2 -0
- package/dist/server-options.d.ts +2 -0
- package/dist/server-options.mjs +1 -0
- package/dist/types.d.mts +2 -2
- package/package.json +50 -79
- package/README.md +0 -80
- package/dist/module.cjs +0 -5
- package/dist/runtime/app/graphqlMiddleware.serverOptions.d.ts +0 -2
- package/dist/runtime/app/graphqlMiddleware.serverOptions.js +0 -11
- package/dist/runtime/components/StagingBanner.vue +0 -107
- package/dist/runtime/components/WordPressLogo.vue +0 -15
- package/dist/runtime/composables/index.d.ts +0 -3
- package/dist/runtime/composables/index.js +0 -3
- package/dist/runtime/composables/isStaging.d.ts +0 -1
- package/dist/runtime/composables/isStaging.js +0 -6
- package/dist/runtime/composables/useFeaturedImage.d.ts +0 -2
- package/dist/runtime/composables/useFeaturedImage.js +0 -7
- package/dist/runtime/composables/usePrevNextPost.d.ts +0 -4
- package/dist/runtime/composables/usePrevNextPost.js +0 -25
- package/dist/runtime/composables/useWPUri.d.ts +0 -8
- package/dist/runtime/composables/useWPUri.js +0 -23
- package/dist/runtime/plugins/vue-sanitize-directive.d.ts +0 -2
- package/dist/runtime/plugins/vue-sanitize-directive.js +0 -5
- package/dist/runtime/server/api/purgeCache.get.d.ts +0 -5
- package/dist/runtime/server/api/purgeCache.get.js +0 -9
- package/dist/runtime/server/api/wpContent.post.d.ts +0 -9
- package/dist/runtime/server/api/wpContent.post.js +0 -50
- package/dist/runtime/server/index.d.ts +0 -1
- package/dist/runtime/server/index.js +0 -8
- package/dist/runtime/server/storage.d.ts +0 -3
- package/dist/runtime/server/storage.js +0 -11
- package/dist/runtime/util/logger.d.ts +0 -3
- package/dist/runtime/util/logger.js +0 -25
- package/dist/types.d.ts +0 -7
package/dist/module.mjs
CHANGED
|
@@ -1,70 +1,77 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { join } from '
|
|
4
|
-
import
|
|
5
|
-
import { ref } from 'vue';
|
|
1
|
+
import { defu } from 'defu';
|
|
2
|
+
import { promises, cpSync, existsSync, statSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { useLogger, createResolver, resolveFiles, defineNuxtModule, addPlugin, addImports, addComponentsDir, addTemplate, addTypeTemplate, hasNuxtModule, installModule } from '@nuxt/kit';
|
|
6
5
|
import { upperFirst } from 'scule';
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const version = "1.0.0-edge.9";
|
|
6
|
+
import { ref } from 'vue';
|
|
7
|
+
import { parse, GraphQLError } from 'graphql';
|
|
8
|
+
import { execSync } from 'node:child_process';
|
|
11
9
|
|
|
10
|
+
function randHashGenerator(length = 12) {
|
|
11
|
+
return Math.random().toString(36).substring(2, 2 + length).toUpperCase().padEnd(length, "0");
|
|
12
|
+
}
|
|
12
13
|
const loggerRef = ref();
|
|
13
|
-
const initLogger = (
|
|
14
|
-
loggerRef.value =
|
|
15
|
-
level: logLevel ? logLevel : 3,
|
|
16
|
-
formatOptions: {
|
|
17
|
-
colors: true,
|
|
18
|
-
compact: true,
|
|
19
|
-
date: true,
|
|
20
|
-
fancy: true
|
|
21
|
-
}
|
|
22
|
-
}).withTag("wpnuxt");
|
|
14
|
+
const initLogger = (debug) => {
|
|
15
|
+
loggerRef.value = useLogger("wpnuxt", { level: debug ? 4 : 3 });
|
|
23
16
|
return loggerRef.value;
|
|
24
17
|
};
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
|
|
18
|
+
function getLogger() {
|
|
19
|
+
return loggerRef.value;
|
|
20
|
+
}
|
|
21
|
+
async function mergeQueries(nuxt, wpNuxtConfig, resolver) {
|
|
22
|
+
const logger = getLogger();
|
|
23
|
+
const baseDir = nuxt.options.srcDir || nuxt.options.rootDir;
|
|
24
|
+
const { resolve } = createResolver(baseDir);
|
|
25
|
+
const queryOutputPath = resolve(wpNuxtConfig.queries.mergedOutputFolder);
|
|
26
|
+
const userQueryPath = resolve(wpNuxtConfig.queries.extendFolder);
|
|
27
|
+
const defaultQueriesPath = resolver.resolve("./runtime/queries");
|
|
28
|
+
await promises.rm(queryOutputPath, { recursive: true, force: true });
|
|
29
|
+
cpSync(defaultQueriesPath, queryOutputPath, { recursive: true });
|
|
30
|
+
if (existsSync(userQueryPath)) {
|
|
31
|
+
logger.debug("Extending queries:", userQueryPath);
|
|
32
|
+
cpSync(userQueryPath, queryOutputPath, { recursive: true });
|
|
38
33
|
}
|
|
34
|
+
logger.debug("Merged queries folder:", queryOutputPath);
|
|
35
|
+
return queryOutputPath;
|
|
39
36
|
}
|
|
40
37
|
|
|
41
38
|
const _parseDoc = async (doc) => {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
39
|
+
if (!doc || typeof doc !== "string" || doc.trim().length === 0) {
|
|
40
|
+
throw new Error("WPNuxt: Invalid GraphQL document - document is empty or not a string");
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
const { definitions } = parse(doc);
|
|
44
|
+
const operations = definitions.filter(({ kind }) => kind === "OperationDefinition").map((definition) => {
|
|
45
|
+
const operationDefinition = definition;
|
|
46
|
+
if (!operationDefinition.name?.value) {
|
|
47
|
+
throw new Error("WPNuxt: GraphQL operation is missing a name. All queries and mutations must have a name.");
|
|
48
|
+
}
|
|
49
|
+
const query = {
|
|
50
|
+
name: operationDefinition.name.value.trim(),
|
|
51
|
+
nodes: [],
|
|
52
|
+
fragments: [],
|
|
53
|
+
params: {},
|
|
54
|
+
operation: operationDefinition.operation
|
|
55
|
+
};
|
|
56
|
+
processSelections(operationDefinition.selectionSet.selections, 0, query);
|
|
57
|
+
return query;
|
|
58
|
+
});
|
|
59
|
+
return operations;
|
|
60
|
+
} catch (error) {
|
|
61
|
+
if (error instanceof GraphQLError) {
|
|
62
|
+
throw new TypeError(`WPNuxt: Failed to parse GraphQL document - ${error.message}`);
|
|
47
63
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
nodes: [],
|
|
51
|
-
fragments: [],
|
|
52
|
-
params: {}
|
|
53
|
-
};
|
|
54
|
-
processSelections(operationDefinition.selectionSet.selections, 0, query);
|
|
55
|
-
return query;
|
|
56
|
-
});
|
|
57
|
-
return operations;
|
|
64
|
+
throw error;
|
|
65
|
+
}
|
|
58
66
|
};
|
|
59
67
|
function processSelections(selections, level, query) {
|
|
60
|
-
if (!selections || selections.length === 0)
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
query.nodes.push(selections[0].name.value.trim());
|
|
68
|
+
if (!selections || selections.length === 0) return;
|
|
69
|
+
if (selections.length === 1 && selections[0]?.kind === "Field") {
|
|
70
|
+
query.nodes?.push(selections[0].name.value.trim());
|
|
64
71
|
}
|
|
65
72
|
selections.forEach((s) => {
|
|
66
73
|
if (s.kind === "FragmentSpread") {
|
|
67
|
-
query.fragments
|
|
74
|
+
query.fragments?.push(s.name.value.trim());
|
|
68
75
|
} else if (s.selectionSet?.selections) {
|
|
69
76
|
processSelections(s.selectionSet.selections, level + 1, query);
|
|
70
77
|
}
|
|
@@ -72,248 +79,393 @@ function processSelections(selections, level, query) {
|
|
|
72
79
|
}
|
|
73
80
|
const parseDoc = _parseDoc;
|
|
74
81
|
|
|
82
|
+
const SCHEMA_PATTERN = /schema\.(?:gql|graphql)$/i;
|
|
83
|
+
const allowDocument = (f, resolver) => {
|
|
84
|
+
if (SCHEMA_PATTERN.test(f)) return false;
|
|
85
|
+
try {
|
|
86
|
+
return statSync(resolver.resolve(f)).size > 0;
|
|
87
|
+
} catch {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
async function generateWPNuxtComposables(ctx, queryOutputPath, resolver) {
|
|
92
|
+
const gqlMatch = "**/*.{gql,graphql}";
|
|
93
|
+
const documents = [];
|
|
94
|
+
const files = (await resolveFiles(queryOutputPath, [gqlMatch, "!**/schemas"], { followSymbolicLinks: false })).filter((doc) => allowDocument(doc, resolver));
|
|
95
|
+
documents.push(...files);
|
|
96
|
+
ctx.docs = documents;
|
|
97
|
+
await prepareContext(ctx);
|
|
98
|
+
}
|
|
75
99
|
async function prepareContext(ctx) {
|
|
76
100
|
const logger = getLogger();
|
|
77
101
|
if (ctx.docs) {
|
|
78
102
|
await prepareFunctions(ctx);
|
|
79
103
|
}
|
|
104
|
+
const queries = ctx.fns.filter((f) => f.operation === "query");
|
|
105
|
+
const mutations = ctx.fns.filter((f) => f.operation === "mutation");
|
|
80
106
|
const fnName = (fn) => ctx.composablesPrefix + upperFirst(fn);
|
|
81
|
-
const
|
|
82
|
-
|
|
107
|
+
const mutationFnName = (fn) => `useMutation${upperFirst(fn)}`;
|
|
108
|
+
const formatNodes = (nodes) => nodes?.map((n) => `'${n}'`).join(",") ?? "";
|
|
109
|
+
const getFragmentType = (q) => {
|
|
110
|
+
const fragmentSuffix = q.fragments?.length && q.nodes?.includes("nodes") ? "[]" : "";
|
|
111
|
+
return q.fragments?.length ? q.fragments.map((f) => `${f}Fragment${fragmentSuffix}`).join(" | ") : "any";
|
|
112
|
+
};
|
|
113
|
+
const queryFnExp = (q, typed = false, lazy = false) => {
|
|
114
|
+
const baseName = fnName(q.name);
|
|
115
|
+
const functionName = lazy ? `useLazy${q.name}` : baseName;
|
|
83
116
|
if (!typed) {
|
|
84
|
-
|
|
117
|
+
if (lazy) {
|
|
118
|
+
return `export const ${functionName} = (params, options) => useWPContent('${q.name}', [${formatNodes(q.nodes)}], false, params, { ...options, lazy: true })`;
|
|
119
|
+
}
|
|
120
|
+
return `export const ${functionName} = (params, options) => useWPContent('${q.name}', [${formatNodes(q.nodes)}], false, params, options)`;
|
|
85
121
|
}
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
122
|
+
return ` export const ${functionName}: (params?: ${q.name}QueryVariables, options?: WPContentOptions) => WPContentResult<${getFragmentType(q)}>`;
|
|
123
|
+
};
|
|
124
|
+
const mutationFnExp = (m, typed = false) => {
|
|
125
|
+
const functionName = mutationFnName(m.name);
|
|
126
|
+
if (!typed) {
|
|
127
|
+
return `export const ${functionName} = (variables, options) => useGraphqlMutation('${m.name}', variables, options)`;
|
|
128
|
+
}
|
|
129
|
+
return ` export const ${functionName}: (variables: ${m.name}MutationVariables, options?: WPMutationOptions) => Promise<WPMutationResult<${m.name}Mutation>>`;
|
|
130
|
+
};
|
|
131
|
+
ctx.generateImports = () => {
|
|
132
|
+
const imports = [];
|
|
133
|
+
queries.forEach((f) => {
|
|
134
|
+
imports.push(queryFnExp(f, false, false));
|
|
135
|
+
imports.push(queryFnExp(f, false, true));
|
|
136
|
+
});
|
|
137
|
+
mutations.forEach((m) => {
|
|
138
|
+
imports.push(mutationFnExp(m, false));
|
|
139
|
+
});
|
|
140
|
+
return imports.join("\n");
|
|
141
|
+
};
|
|
142
|
+
const typeSet = /* @__PURE__ */ new Set();
|
|
143
|
+
queries.forEach((o) => {
|
|
144
|
+
typeSet.add(`${o.name}QueryVariables`);
|
|
145
|
+
o.fragments?.forEach((f) => typeSet.add(`${f}Fragment`));
|
|
146
|
+
});
|
|
147
|
+
mutations.forEach((m) => {
|
|
148
|
+
typeSet.add(`${m.name}MutationVariables`);
|
|
149
|
+
typeSet.add(`${m.name}Mutation`);
|
|
150
|
+
});
|
|
151
|
+
ctx.generateDeclarations = () => {
|
|
152
|
+
const declarations = [
|
|
153
|
+
`import type { ${[...typeSet].join(", ")} } from '#build/graphql-operations'`,
|
|
154
|
+
"import type { ComputedRef, Ref } from 'vue'",
|
|
155
|
+
"import type { AsyncDataRequestStatus } from '#app'",
|
|
156
|
+
"import type { GraphqlResponse } from 'nuxt-graphql-middleware/types'",
|
|
157
|
+
"",
|
|
158
|
+
"export interface WPContentOptions {",
|
|
159
|
+
" /** Whether to resolve the async function after loading the route, instead of blocking client-side navigation. Default: false */",
|
|
160
|
+
" lazy?: boolean",
|
|
161
|
+
" /** Whether to fetch data on the server (during SSR). Default: true */",
|
|
162
|
+
" server?: boolean",
|
|
163
|
+
" /** Whether to fetch immediately. Default: true */",
|
|
164
|
+
" immediate?: boolean",
|
|
165
|
+
" /** Watch reactive sources to auto-refresh */",
|
|
166
|
+
" watch?: unknown[]",
|
|
167
|
+
" /** Transform function to alter the result */",
|
|
168
|
+
" transform?: (input: unknown) => unknown",
|
|
169
|
+
" /** Additional options to pass to useAsyncGraphqlQuery */",
|
|
170
|
+
" [key: string]: unknown",
|
|
171
|
+
"}",
|
|
172
|
+
"",
|
|
173
|
+
"export interface WPMutationOptions {",
|
|
174
|
+
" /** Fetch options to pass to the request */",
|
|
175
|
+
" fetchOptions?: RequestInit",
|
|
176
|
+
" /** Additional options */",
|
|
177
|
+
" [key: string]: unknown",
|
|
178
|
+
"}",
|
|
179
|
+
"",
|
|
180
|
+
"interface WPContentResult<T> {",
|
|
181
|
+
" data: ComputedRef<T | undefined>",
|
|
182
|
+
" pending: Ref<boolean>",
|
|
183
|
+
" refresh: () => Promise<void>",
|
|
184
|
+
" execute: () => Promise<void>",
|
|
185
|
+
" clear: () => void",
|
|
186
|
+
" error: Ref<Error | undefined>",
|
|
187
|
+
" status: Ref<AsyncDataRequestStatus>",
|
|
188
|
+
"}",
|
|
189
|
+
"",
|
|
190
|
+
"type WPMutationResult<T> = GraphqlResponse<T>",
|
|
191
|
+
"",
|
|
192
|
+
"declare module '#wpnuxt' {"
|
|
193
|
+
];
|
|
194
|
+
queries.forEach((f) => {
|
|
195
|
+
declarations.push(queryFnExp(f, true, false));
|
|
196
|
+
declarations.push(queryFnExp(f, true, true));
|
|
197
|
+
});
|
|
198
|
+
mutations.forEach((m) => {
|
|
199
|
+
declarations.push(mutationFnExp(m, true));
|
|
200
|
+
});
|
|
201
|
+
declarations.push("}");
|
|
202
|
+
return declarations.join("\n");
|
|
89
203
|
};
|
|
90
|
-
ctx.
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
"declare module '#wpnuxt' {",
|
|
100
|
-
...[
|
|
101
|
-
...ctx.fns.map((f) => fnExp(f, true))
|
|
102
|
-
],
|
|
103
|
-
"}"
|
|
104
|
-
].join("\n");
|
|
105
|
-
ctx.fnImports = ctx.fns.map((fn) => ({ from: "#wpnuxt", name: fnName(fn.name) }));
|
|
204
|
+
ctx.fnImports = [
|
|
205
|
+
// Auto-import query composables (regular and lazy variants)
|
|
206
|
+
...queries.flatMap((fn) => [
|
|
207
|
+
{ from: "#wpnuxt", name: fnName(fn.name) },
|
|
208
|
+
{ from: "#wpnuxt", name: `useLazy${fn.name}` }
|
|
209
|
+
]),
|
|
210
|
+
// Auto-import mutation composables
|
|
211
|
+
...mutations.map((m) => ({ from: "#wpnuxt", name: mutationFnName(m.name) }))
|
|
212
|
+
];
|
|
106
213
|
logger.debug("generated WPNuxt composables: ");
|
|
107
|
-
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
}
|
|
115
|
-
return types;
|
|
214
|
+
queries.forEach((f) => {
|
|
215
|
+
logger.debug(` ${fnName(f.name)}()`);
|
|
216
|
+
logger.debug(` useLazy${f.name}()`);
|
|
217
|
+
});
|
|
218
|
+
mutations.forEach((m) => {
|
|
219
|
+
logger.debug(` ${mutationFnName(m.name)}()`);
|
|
220
|
+
});
|
|
116
221
|
}
|
|
117
222
|
async function prepareFunctions(ctx) {
|
|
118
223
|
if (!ctx.docs) {
|
|
119
224
|
getLogger().error("no GraphQL query documents were found!");
|
|
120
225
|
return;
|
|
121
226
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
227
|
+
const operations = await Promise.all(
|
|
228
|
+
ctx.docs.map(async (doc) => {
|
|
229
|
+
const content = await promises.readFile(doc, "utf8");
|
|
230
|
+
return parseDoc(content);
|
|
231
|
+
})
|
|
232
|
+
);
|
|
233
|
+
operations.flat().forEach((query) => {
|
|
234
|
+
ctx.fns.push(query);
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
async function validateWordPressEndpoint(wordpressUrl, graphqlEndpoint = "/graphql", options = {}) {
|
|
239
|
+
const fullUrl = `${wordpressUrl}${graphqlEndpoint}`;
|
|
240
|
+
try {
|
|
241
|
+
const controller = new AbortController();
|
|
242
|
+
const timeout = setTimeout(() => controller.abort(), 1e4);
|
|
243
|
+
const response = await fetch(fullUrl, {
|
|
244
|
+
method: "POST",
|
|
245
|
+
headers: {
|
|
246
|
+
"Content-Type": "application/json"
|
|
247
|
+
},
|
|
248
|
+
body: JSON.stringify({
|
|
249
|
+
query: "{ __typename }"
|
|
250
|
+
}),
|
|
251
|
+
signal: controller.signal
|
|
126
252
|
});
|
|
253
|
+
clearTimeout(timeout);
|
|
254
|
+
if (!response.ok) {
|
|
255
|
+
throw new Error(
|
|
256
|
+
`[WPNuxt] WordPress GraphQL endpoint returned HTTP ${response.status}.
|
|
257
|
+
|
|
258
|
+
URL: ${fullUrl}
|
|
259
|
+
|
|
260
|
+
Possible causes:
|
|
261
|
+
- The WordPress site is down or unreachable
|
|
262
|
+
- WPGraphQL plugin is not installed or activated
|
|
263
|
+
- The GraphQL endpoint path is incorrect (default: /graphql)
|
|
264
|
+
|
|
265
|
+
Check your wpNuxt.wordpressUrl configuration in nuxt.config.ts`
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
const data = await response.json();
|
|
269
|
+
if (!data || typeof data !== "object") {
|
|
270
|
+
throw new Error(
|
|
271
|
+
`[WPNuxt] WordPress GraphQL endpoint returned invalid response.
|
|
272
|
+
|
|
273
|
+
URL: ${fullUrl}
|
|
274
|
+
|
|
275
|
+
The endpoint did not return valid JSON. Make sure WPGraphQL plugin is installed and activated.`
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
if (data.errors && !data.data) {
|
|
279
|
+
const errorMessage = data.errors[0]?.message || "Unknown error";
|
|
280
|
+
throw new Error(
|
|
281
|
+
`[WPNuxt] WordPress GraphQL endpoint returned an error: ${errorMessage}
|
|
282
|
+
|
|
283
|
+
URL: ${fullUrl}
|
|
284
|
+
|
|
285
|
+
Make sure WPGraphQL plugin is installed and activated on your WordPress site.`
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
if (options.schemaPath && !existsSync(options.schemaPath)) {
|
|
289
|
+
try {
|
|
290
|
+
execSync(`npx get-graphql-schema "${fullUrl}" > "${options.schemaPath}"`, {
|
|
291
|
+
stdio: "pipe",
|
|
292
|
+
timeout: 6e4
|
|
293
|
+
// 60 second timeout
|
|
294
|
+
});
|
|
295
|
+
patchWPGraphQLSchema(options.schemaPath);
|
|
296
|
+
} catch (err) {
|
|
297
|
+
const error = err;
|
|
298
|
+
throw new Error(
|
|
299
|
+
`[WPNuxt] Failed to download GraphQL schema.
|
|
300
|
+
|
|
301
|
+
URL: ${fullUrl}
|
|
302
|
+
Error: ${error.stderr?.toString() || error.message}
|
|
303
|
+
|
|
304
|
+
Make sure WPGraphQL plugin is installed and activated on your WordPress site.`
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
} catch (error) {
|
|
309
|
+
if (error instanceof Error && error.message.startsWith("[WPNuxt]")) {
|
|
310
|
+
throw error;
|
|
311
|
+
}
|
|
312
|
+
const err = error;
|
|
313
|
+
const errorCode = err.code || err.cause?.code || "";
|
|
314
|
+
if (err.name === "AbortError") {
|
|
315
|
+
throw new Error(
|
|
316
|
+
`[WPNuxt] WordPress GraphQL endpoint timed out after 10 seconds.
|
|
317
|
+
|
|
318
|
+
URL: ${fullUrl}
|
|
319
|
+
|
|
320
|
+
The server did not respond in time. Check if the WordPress site is accessible.`
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
if (errorCode === "ENOTFOUND" || err.message?.includes("getaddrinfo")) {
|
|
324
|
+
throw new Error(
|
|
325
|
+
`[WPNuxt] WordPress site not found - DNS lookup failed.
|
|
326
|
+
|
|
327
|
+
URL: ${fullUrl}
|
|
328
|
+
|
|
329
|
+
The domain could not be resolved. Please check:
|
|
330
|
+
- The URL is spelled correctly (no typos)
|
|
331
|
+
- The domain exists and is properly configured
|
|
332
|
+
- Your network connection is working
|
|
333
|
+
|
|
334
|
+
Check your wpNuxt.wordpressUrl configuration in nuxt.config.ts`
|
|
335
|
+
);
|
|
336
|
+
}
|
|
337
|
+
if (errorCode === "ECONNREFUSED") {
|
|
338
|
+
throw new Error(
|
|
339
|
+
`[WPNuxt] Connection refused to WordPress site.
|
|
340
|
+
|
|
341
|
+
URL: ${fullUrl}
|
|
342
|
+
|
|
343
|
+
The server is not accepting connections. Check if the WordPress site is running.`
|
|
344
|
+
);
|
|
345
|
+
}
|
|
346
|
+
throw new Error(
|
|
347
|
+
`[WPNuxt] Failed to connect to WordPress GraphQL endpoint.
|
|
348
|
+
|
|
349
|
+
URL: ${fullUrl}
|
|
350
|
+
Error: ${err.message || "Unknown error"}
|
|
351
|
+
|
|
352
|
+
Check your wpNuxt.wordpressUrl configuration in nuxt.config.ts`
|
|
353
|
+
);
|
|
127
354
|
}
|
|
128
355
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
356
|
+
function patchWPGraphQLSchema(schemaPath) {
|
|
357
|
+
let schema = readFileSync(schemaPath, "utf-8");
|
|
358
|
+
const problematicInterfaces = [
|
|
359
|
+
"Connection",
|
|
360
|
+
"Edge",
|
|
361
|
+
"OneToOneConnection"
|
|
362
|
+
];
|
|
363
|
+
problematicInterfaces.push("NodeWithEditorBlocks");
|
|
364
|
+
for (const iface of problematicInterfaces) {
|
|
365
|
+
schema = schema.replace(
|
|
366
|
+
new RegExp(`implements\\s+${iface}\\s*\\{`, "g"),
|
|
367
|
+
"{"
|
|
368
|
+
);
|
|
369
|
+
schema = schema.replace(
|
|
370
|
+
new RegExp(`implements\\s+${iface}\\s+&\\s+`, "g"),
|
|
371
|
+
"implements "
|
|
372
|
+
);
|
|
373
|
+
schema = schema.replace(
|
|
374
|
+
new RegExp(`\\s*&\\s*${iface}(?=\\s*[&{])`, "g"),
|
|
375
|
+
""
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
writeFileSync(schemaPath, schema);
|
|
141
379
|
}
|
|
142
380
|
|
|
143
|
-
const
|
|
144
|
-
wordpressUrl: "",
|
|
145
|
-
frontendUrl: "",
|
|
146
|
-
defaultMenuName: "main",
|
|
147
|
-
enableCache: true,
|
|
148
|
-
staging: false,
|
|
149
|
-
logLevel: 3,
|
|
150
|
-
composablesPrefix: "useWP"
|
|
151
|
-
};
|
|
152
|
-
const module = defineNuxtModule({
|
|
381
|
+
const module$1 = defineNuxtModule({
|
|
153
382
|
meta: {
|
|
154
|
-
name,
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
383
|
+
name: "wpnuxt",
|
|
384
|
+
configKey: "wpNuxt"
|
|
385
|
+
},
|
|
386
|
+
defaults: {
|
|
387
|
+
wordpressUrl: void 0,
|
|
388
|
+
graphqlEndpoint: "/graphql",
|
|
389
|
+
queries: {
|
|
390
|
+
extendFolder: "extend/queries/",
|
|
391
|
+
mergedOutputFolder: ".queries/"
|
|
392
|
+
},
|
|
393
|
+
downloadSchema: true,
|
|
394
|
+
debug: false,
|
|
395
|
+
cache: {
|
|
396
|
+
enabled: true,
|
|
397
|
+
maxAge: 60 * 5,
|
|
398
|
+
// 5 minutes
|
|
399
|
+
swr: true
|
|
400
|
+
}
|
|
158
401
|
},
|
|
159
|
-
// Default configuration options of the Nuxt module
|
|
160
|
-
defaults: defaultConfigs,
|
|
161
402
|
async setup(options, nuxt) {
|
|
162
403
|
const startTime = (/* @__PURE__ */ new Date()).getTime();
|
|
163
|
-
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
nuxt.options.nitro.alias = nuxt.options.nitro.alias || {};
|
|
191
|
-
nuxt.options.nitro.alias["#wpnuxt/types"] = resolve("./types");
|
|
192
|
-
nuxt.options.nitro.externals = nuxt.options.nitro.externals || {};
|
|
193
|
-
nuxt.options.nitro.externals.inline = nuxt.options.nitro.externals.inline || [];
|
|
194
|
-
addPlugin({
|
|
195
|
-
src: resolveRuntimeModule("plugins/vue-sanitize-directive")
|
|
196
|
-
});
|
|
197
|
-
addImports([
|
|
198
|
-
{ name: "isStaging", as: "isStaging", from: resolveRuntimeModule("./composables/isStaging") },
|
|
199
|
-
{ name: "useWPContent", as: "useWPContent", from: resolveRuntimeModule("./composables/useWPContent") },
|
|
200
|
-
{ name: "parseDoc", as: "parseDoc", from: resolveRuntimeModule("./composables/useParser") },
|
|
201
|
-
{ name: "usePrevNextPost", as: "usePrevNextPost", from: resolveRuntimeModule("./composables/usePrevNextPost") },
|
|
202
|
-
{ name: "loginUser", as: "loginUser", from: resolveRuntimeModule("./composables/user") },
|
|
203
|
-
{ name: "logoutUser", as: "logoutUser", from: resolveRuntimeModule("./composables/user") },
|
|
204
|
-
{ name: "getCurrentUserId", as: "getCurrentUserId", from: resolveRuntimeModule("./composables/user") },
|
|
205
|
-
{ name: "getCurrentUserName", as: "getCurrentUserName", from: resolveRuntimeModule("./composables/user") },
|
|
206
|
-
{ name: "useTokens", as: "useTokens", from: resolveRuntimeModule("./composables/useTokens") },
|
|
207
|
-
{ name: "useWPUri", as: "useWPUri", from: resolveRuntimeModule("./composables/useWPUri") },
|
|
208
|
-
{ name: "useFeaturedImage", as: "useFeaturedImage", from: resolveRuntimeModule("./composables/useFeaturedImage") }
|
|
209
|
-
]);
|
|
210
|
-
addComponent({ name: "StagingBanner", filePath: resolveRuntimeModule("./components/StagingBanner") });
|
|
211
|
-
addComponent({ name: "WPNuxtLogo", filePath: resolveRuntimeModule("./components/WPNuxtLogo") });
|
|
212
|
-
addComponent({ name: "WordPressLogo", filePath: resolveRuntimeModule("./components/WordPressLogo") });
|
|
213
|
-
addServerHandler({
|
|
214
|
-
route: "/api/wpContent",
|
|
215
|
-
handler: resolveRuntimeModule("./server/api/wpContent.post")
|
|
216
|
-
});
|
|
217
|
-
addServerHandler({
|
|
218
|
-
route: "/api/purgeCache",
|
|
219
|
-
handler: resolveRuntimeModule("./server/api/purgeCache.get")
|
|
404
|
+
const wpNuxtConfig = loadConfig(options, nuxt);
|
|
405
|
+
const logger = initLogger(wpNuxtConfig.debug);
|
|
406
|
+
logger.debug("Starting WPNuxt in debug mode");
|
|
407
|
+
const resolver = createResolver(import.meta.url);
|
|
408
|
+
nuxt.options.runtimeConfig.public.buildHash = randHashGenerator();
|
|
409
|
+
addPlugin(resolver.resolve("./runtime/plugins/graphqlConfig"));
|
|
410
|
+
addPlugin(resolver.resolve("./runtime/plugins/graphqlErrors"));
|
|
411
|
+
const mergedQueriesFolder = await mergeQueries(nuxt, wpNuxtConfig, resolver);
|
|
412
|
+
setupServerOptions(nuxt, resolver, logger);
|
|
413
|
+
setupClientOptions(nuxt, resolver, logger);
|
|
414
|
+
if (wpNuxtConfig.downloadSchema) {
|
|
415
|
+
const schemaPath = join(nuxt.options.rootDir, "schema.graphql");
|
|
416
|
+
logger.debug(`Validating WordPress endpoint: ${wpNuxtConfig.wordpressUrl}${wpNuxtConfig.graphqlEndpoint}`);
|
|
417
|
+
await validateWordPressEndpoint(
|
|
418
|
+
wpNuxtConfig.wordpressUrl,
|
|
419
|
+
wpNuxtConfig.graphqlEndpoint,
|
|
420
|
+
{ schemaPath }
|
|
421
|
+
);
|
|
422
|
+
logger.debug("WordPress endpoint validation passed");
|
|
423
|
+
}
|
|
424
|
+
await registerModules(nuxt, resolver, wpNuxtConfig, mergedQueriesFolder);
|
|
425
|
+
nuxt.hook("devtools:customTabs", (tabs) => {
|
|
426
|
+
const middlewareTab = tabs.find((tab) => tab.name === "nuxt-graphql-middleware");
|
|
427
|
+
if (middlewareTab) {
|
|
428
|
+
middlewareTab.title = "WPNuxt GraphQL";
|
|
429
|
+
middlewareTab.icon = "simple-icons:wordpress";
|
|
430
|
+
}
|
|
220
431
|
});
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
for (const m of nuxt.options._installedModules) {
|
|
229
|
-
if (m.meta.name === "@wpnuxt/blocks" && m.entryPath) {
|
|
230
|
-
logger.debug("Loading queries from @wpnuxt/blocks");
|
|
231
|
-
let blocksQueriesPath;
|
|
232
|
-
if (m.entryPath.startsWith("../")) {
|
|
233
|
-
blocksQueriesPath = join(nuxt.options.rootDir, "../", m.entryPath, "./runtime/queries/");
|
|
234
|
-
} else {
|
|
235
|
-
blocksQueriesPath = join("./node_modules", m.entryPath, "dist/runtime/queries/");
|
|
236
|
-
}
|
|
237
|
-
cpSync(blocksQueriesPath, queryOutputPath, { recursive: true });
|
|
432
|
+
if (wpNuxtConfig.cache?.enabled !== false) {
|
|
433
|
+
const maxAge = wpNuxtConfig.cache?.maxAge ?? 300;
|
|
434
|
+
nuxt.options.nitro.routeRules = nuxt.options.nitro.routeRules || {};
|
|
435
|
+
nuxt.options.nitro.routeRules["/api/wpnuxt/**"] = {
|
|
436
|
+
cache: {
|
|
437
|
+
maxAge,
|
|
438
|
+
swr: wpNuxtConfig.cache?.swr !== false
|
|
238
439
|
}
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
logger.debug("Tip: Install the @wpnuxt/blocks module if you want to render Gutenberg blocks with separate vue components");
|
|
242
|
-
addTemplate({
|
|
243
|
-
write: true,
|
|
244
|
-
filename: "wpnuxt/blocks.mjs",
|
|
245
|
-
getContents: () => `export { }`
|
|
246
|
-
});
|
|
247
|
-
nuxt.options.alias["#wpnuxt/blocks"] = resolve(nuxt.options.buildDir, "wpnuxt/blocks");
|
|
440
|
+
};
|
|
441
|
+
logger.debug(`Server-side caching enabled for GraphQL requests (maxAge: ${maxAge}s, SWR: ${wpNuxtConfig.cache?.swr !== false})`);
|
|
248
442
|
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
skipTypename: true,
|
|
261
|
-
useTypeImports: true,
|
|
262
|
-
// inlineFragmentTypes: 'combine',
|
|
263
|
-
dedupeFragments: true,
|
|
264
|
-
onlyOperationTypes: true,
|
|
265
|
-
avoidOptionals: false,
|
|
266
|
-
maybeValue: "T | undefined",
|
|
267
|
-
disableOnBuild: false,
|
|
268
|
-
gqlImport: "graphql-request#wpnuxt",
|
|
269
|
-
namingConvention: {
|
|
270
|
-
enumValues: "change-case-all#upperCaseFirst"
|
|
271
|
-
},
|
|
272
|
-
documents: [
|
|
273
|
-
resolve("!./graphql/**/*")
|
|
274
|
-
]
|
|
275
|
-
},
|
|
276
|
-
codegenSchemaConfig: {
|
|
277
|
-
urlSchemaOptions: {
|
|
278
|
-
headers: {
|
|
279
|
-
Authorization: "server-token"
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
},
|
|
283
|
-
outputDocuments: true,
|
|
284
|
-
autoImportPatterns: queryOutputPath,
|
|
285
|
-
includeComposables: true,
|
|
286
|
-
devtools: true
|
|
287
|
-
});
|
|
288
|
-
const resolvedPath = resolveRuntimeModule("./app/graphqlMiddleware.serverOptions");
|
|
289
|
-
const template = addTemplate({
|
|
290
|
-
filename: "graphqlMiddleware.serverOptions.ts",
|
|
291
|
-
write: true,
|
|
292
|
-
getContents: () => `
|
|
293
|
-
import type { GraphqlMiddlewareServerOptions } from '#graphql-middleware/types'
|
|
294
|
-
import serverOptions from '${resolvedPath}'
|
|
295
|
-
import type { GraphqlServerResponse } from '#graphql-middleware/types'
|
|
296
|
-
import type { GraphqlMiddlewareResponseUnion } from '#build/nuxt-graphql-middleware'
|
|
297
|
-
|
|
298
|
-
type GraphqlResponseAdditions =
|
|
299
|
-
typeof serverOptions extends GraphqlMiddlewareServerOptions<infer R> ? R : {}
|
|
300
|
-
|
|
301
|
-
export type GraphqlResponse<T> = GraphqlServerResponse<T> & GraphqlResponseAdditions
|
|
302
|
-
|
|
303
|
-
export type GraphqlResponseTyped = GraphqlResponse<GraphqlMiddlewareResponseUnion>
|
|
304
|
-
|
|
305
|
-
export { serverOptions }
|
|
306
|
-
`
|
|
443
|
+
configureVercelSettings(nuxt, logger);
|
|
444
|
+
addImports([
|
|
445
|
+
{ name: "useWPContent", as: "useWPContent", from: resolver.resolve("./runtime/composables/useWPContent") },
|
|
446
|
+
{ name: "useAsyncWPContent", as: "useAsyncWPContent", from: resolver.resolve("./runtime/composables/useWPContent") }
|
|
447
|
+
// Note: useGraphqlMutation is auto-imported via nuxt-graphql-middleware with includeComposables: true
|
|
448
|
+
]);
|
|
449
|
+
addComponentsDir({
|
|
450
|
+
path: resolver.resolve("./runtime/components"),
|
|
451
|
+
pathPrefix: false,
|
|
452
|
+
prefix: "",
|
|
453
|
+
global: true
|
|
307
454
|
});
|
|
308
|
-
nuxt.options.nitro.externals.inline.push(template.dst);
|
|
309
|
-
nuxt.options.alias["#graphql-middleware-server-options-build"] = template.dst;
|
|
310
455
|
logger.trace("Start generating composables");
|
|
311
|
-
const ctx =
|
|
456
|
+
const ctx = {
|
|
312
457
|
fns: [],
|
|
313
458
|
fnImports: [],
|
|
314
|
-
composablesPrefix:
|
|
459
|
+
composablesPrefix: "use"
|
|
315
460
|
};
|
|
316
|
-
await generateWPNuxtComposables(ctx,
|
|
461
|
+
await generateWPNuxtComposables(ctx, mergedQueriesFolder, createResolver(nuxt.options.srcDir));
|
|
462
|
+
nuxt.options.alias["#wpnuxt"] = resolver.resolve(nuxt.options.buildDir, "wpnuxt");
|
|
463
|
+
nuxt.options.alias["#wpnuxt/*"] = resolver.resolve(nuxt.options.buildDir, "wpnuxt", "*");
|
|
464
|
+
nuxt.options.alias["#wpnuxt/types"] = resolver.resolve("./types");
|
|
465
|
+
nuxt.options.nitro.alias = nuxt.options.nitro.alias || {};
|
|
466
|
+
nuxt.options.nitro.alias["#wpnuxt/types"] = resolver.resolve("./types");
|
|
467
|
+
nuxt.options.nitro.externals = nuxt.options.nitro.externals || {};
|
|
468
|
+
nuxt.options.nitro.externals.inline = nuxt.options.nitro.externals.inline || [];
|
|
317
469
|
addTemplate({
|
|
318
470
|
write: true,
|
|
319
471
|
filename: "wpnuxt/index.mjs",
|
|
@@ -327,16 +479,194 @@ const module = defineNuxtModule({
|
|
|
327
479
|
nuxt.hook("imports:extend", (autoimports) => {
|
|
328
480
|
autoimports.push(...ctx.fnImports || []);
|
|
329
481
|
});
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
keys.forEach(async (key) => {
|
|
333
|
-
if (key.startsWith("cache:content"))
|
|
334
|
-
await nitro.storage.removeItem(key);
|
|
335
|
-
});
|
|
336
|
-
});
|
|
337
|
-
const endTime = (/* @__PURE__ */ new Date()).getTime();
|
|
338
|
-
logger.success("::: Finished WPNuxt setup in " + (endTime - startTime) + "ms ::: ");
|
|
482
|
+
logger.trace("Finished generating composables");
|
|
483
|
+
logger.info(`WPNuxt module loaded in ${(/* @__PURE__ */ new Date()).getTime() - startTime}ms`);
|
|
339
484
|
}
|
|
340
485
|
});
|
|
486
|
+
function loadConfig(options, nuxt) {
|
|
487
|
+
const config = defu({
|
|
488
|
+
wordpressUrl: process.env.WPNUXT_WORDPRESS_URL,
|
|
489
|
+
graphqlEndpoint: process.env.WPNUXT_GRAPHQL_ENDPOINT,
|
|
490
|
+
// Only override downloadSchema if env var is explicitly set
|
|
491
|
+
downloadSchema: process.env.WPNUXT_DOWNLOAD_SCHEMA !== void 0 ? process.env.WPNUXT_DOWNLOAD_SCHEMA === "true" : void 0,
|
|
492
|
+
debug: process.env.WPNUXT_DEBUG ? process.env.WPNUXT_DEBUG === "true" : void 0
|
|
493
|
+
}, options);
|
|
494
|
+
if (config.downloadSchema === void 0) {
|
|
495
|
+
config.downloadSchema = true;
|
|
496
|
+
}
|
|
497
|
+
nuxt.options.runtimeConfig.public.wordpressUrl = config.wordpressUrl;
|
|
498
|
+
nuxt.options.runtimeConfig.public.wpNuxt = {
|
|
499
|
+
wordpressUrl: config.wordpressUrl,
|
|
500
|
+
graphqlEndpoint: config.graphqlEndpoint,
|
|
501
|
+
cache: {
|
|
502
|
+
enabled: config.cache?.enabled ?? true,
|
|
503
|
+
maxAge: config.cache?.maxAge ?? 300,
|
|
504
|
+
swr: config.cache?.swr ?? true
|
|
505
|
+
}
|
|
506
|
+
};
|
|
507
|
+
if (!config.wordpressUrl?.trim()) {
|
|
508
|
+
throw new Error("WPNuxt error: WordPress url is missing");
|
|
509
|
+
}
|
|
510
|
+
if (config.wordpressUrl.endsWith("/")) {
|
|
511
|
+
throw new Error(`WPNuxt error: WordPress url should not have a trailing slash: ${config.wordpressUrl}`);
|
|
512
|
+
}
|
|
513
|
+
return config;
|
|
514
|
+
}
|
|
515
|
+
const SERVER_OPTIONS_TEMPLATE = `import { defineGraphqlServerOptions } from '@wpnuxt/core/server-options'
|
|
516
|
+
import { getHeader, getCookie } from 'h3'
|
|
517
|
+
import { useRuntimeConfig } from '#imports'
|
|
518
|
+
|
|
519
|
+
/**
|
|
520
|
+
* WPNuxt default server options for nuxt-graphql-middleware.
|
|
521
|
+
*
|
|
522
|
+
* This enables:
|
|
523
|
+
* - Cookie forwarding for WordPress preview mode
|
|
524
|
+
* - Authorization header forwarding for authenticated requests
|
|
525
|
+
* - Auth token from cookie for @wpnuxt/auth
|
|
526
|
+
* - Consistent error logging
|
|
527
|
+
*
|
|
528
|
+
* Users can customize by creating their own server/graphqlMiddleware.serverOptions.ts
|
|
529
|
+
*/
|
|
530
|
+
export default defineGraphqlServerOptions({
|
|
531
|
+
async serverFetchOptions(event, _operation, _operationName, _context) {
|
|
532
|
+
// Get auth token from Authorization header or from cookie
|
|
533
|
+
let authorization = getHeader(event, 'authorization') || ''
|
|
534
|
+
|
|
535
|
+
// If no Authorization header, check for auth token in cookie (@wpnuxt/auth)
|
|
536
|
+
if (!authorization) {
|
|
537
|
+
const config = useRuntimeConfig().public.wpNuxtAuth as { cookieName?: string } | undefined
|
|
538
|
+
const cookieName = config?.cookieName || 'wpnuxt-auth-token'
|
|
539
|
+
const authToken = getCookie(event, cookieName)
|
|
540
|
+
if (authToken) {
|
|
541
|
+
authorization = \`Bearer \${authToken}\`
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
return {
|
|
546
|
+
headers: {
|
|
547
|
+
// Forward WordPress auth cookies for previews
|
|
548
|
+
Cookie: getHeader(event, 'cookie') || '',
|
|
549
|
+
// Forward authorization header or token from cookie
|
|
550
|
+
Authorization: authorization
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
},
|
|
554
|
+
|
|
555
|
+
async onServerError(event, error, _operation, operationName) {
|
|
556
|
+
const url = event.node.req.url || 'unknown'
|
|
557
|
+
console.error(\`[WPNuxt] GraphQL error in \${operationName} (\${url}):\`, error.message)
|
|
558
|
+
}
|
|
559
|
+
})
|
|
560
|
+
`;
|
|
561
|
+
function setupServerOptions(nuxt, _resolver, logger) {
|
|
562
|
+
const serverDir = nuxt.options.serverDir;
|
|
563
|
+
const targetPath = join(serverDir, "graphqlMiddleware.serverOptions.ts");
|
|
564
|
+
if (existsSync(targetPath)) {
|
|
565
|
+
logger.debug("Using existing graphqlMiddleware.serverOptions.ts from project");
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
if (!existsSync(serverDir)) {
|
|
569
|
+
mkdirSync(serverDir, { recursive: true });
|
|
570
|
+
}
|
|
571
|
+
writeFileSync(targetPath, SERVER_OPTIONS_TEMPLATE);
|
|
572
|
+
logger.debug("Created graphqlMiddleware.serverOptions.ts with WPNuxt defaults (cookie/auth forwarding)");
|
|
573
|
+
}
|
|
574
|
+
const CLIENT_OPTIONS_TEMPLATE = `import { defineGraphqlClientOptions } from '@wpnuxt/core/client-options'
|
|
575
|
+
import { useRoute } from '#imports'
|
|
576
|
+
|
|
577
|
+
/**
|
|
578
|
+
* WPNuxt default client options for nuxt-graphql-middleware.
|
|
579
|
+
*
|
|
580
|
+
* This enables passing client context to the server for:
|
|
581
|
+
* - Preview mode (passes preview flag and token from URL query params)
|
|
582
|
+
*
|
|
583
|
+
* The context is available in serverFetchOptions via context.client
|
|
584
|
+
* All values must be strings (nuxt-graphql-middleware requirement)
|
|
585
|
+
*
|
|
586
|
+
* Users can customize by creating their own app/graphqlMiddleware.clientOptions.ts
|
|
587
|
+
*/
|
|
588
|
+
export default defineGraphqlClientOptions<{
|
|
589
|
+
preview?: string
|
|
590
|
+
previewToken?: string
|
|
591
|
+
}>({
|
|
592
|
+
buildClientContext() {
|
|
593
|
+
const route = useRoute()
|
|
594
|
+
|
|
595
|
+
return {
|
|
596
|
+
// Context values must be strings - use 'true'/'false' instead of boolean
|
|
597
|
+
preview: route.query.preview === 'true' ? 'true' : undefined,
|
|
598
|
+
previewToken: route.query.token as string | undefined
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
})
|
|
602
|
+
`;
|
|
603
|
+
function setupClientOptions(nuxt, _resolver, logger) {
|
|
604
|
+
const appDir = nuxt.options.dir.app;
|
|
605
|
+
const targetPath = join(appDir, "graphqlMiddleware.clientOptions.ts");
|
|
606
|
+
if (existsSync(targetPath)) {
|
|
607
|
+
logger.debug("Using existing graphqlMiddleware.clientOptions.ts from project");
|
|
608
|
+
return;
|
|
609
|
+
}
|
|
610
|
+
if (!existsSync(appDir)) {
|
|
611
|
+
mkdirSync(appDir, { recursive: true });
|
|
612
|
+
}
|
|
613
|
+
writeFileSync(targetPath, CLIENT_OPTIONS_TEMPLATE);
|
|
614
|
+
logger.debug("Created graphqlMiddleware.clientOptions.ts with WPNuxt defaults (preview mode support)");
|
|
615
|
+
}
|
|
616
|
+
function configureVercelSettings(nuxt, logger) {
|
|
617
|
+
const isVercel = process.env.VERCEL === "1" || nuxt.options.nitro.preset === "vercel";
|
|
618
|
+
if (isVercel) {
|
|
619
|
+
logger.debug("Vercel deployment detected, applying recommended settings");
|
|
620
|
+
nuxt.options.nitro.future = nuxt.options.nitro.future || {};
|
|
621
|
+
if (nuxt.options.nitro.future.nativeSWR === void 0) {
|
|
622
|
+
nuxt.options.nitro.future.nativeSWR = true;
|
|
623
|
+
logger.debug("Enabled nitro.future.nativeSWR for Vercel ISR compatibility");
|
|
624
|
+
}
|
|
625
|
+
nuxt.options.routeRules = nuxt.options.routeRules || {};
|
|
626
|
+
if (!nuxt.options.routeRules["/**"]) {
|
|
627
|
+
nuxt.options.routeRules["/**"] = { ssr: true };
|
|
628
|
+
logger.debug("Enabled SSR for all routes (routeRules['/**'] = { ssr: true })");
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
async function registerModules(nuxt, resolver, wpNuxtConfig, mergedQueriesFolder) {
|
|
633
|
+
const logger = getLogger();
|
|
634
|
+
async function registerModule(name, key, options) {
|
|
635
|
+
if (!hasNuxtModule(name)) {
|
|
636
|
+
await installModule(name, options);
|
|
637
|
+
} else {
|
|
638
|
+
logger.debug(`${name} module already registered, using the 'graphqlMiddleware' config from nuxt.config.ts`);
|
|
639
|
+
nuxt.options[key] = defu(nuxt.options[key], options);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
await registerModule("nuxt-graphql-middleware", "graphql", {
|
|
643
|
+
debug: wpNuxtConfig.debug,
|
|
644
|
+
graphqlEndpoint: `${wpNuxtConfig.wordpressUrl}${wpNuxtConfig.graphqlEndpoint}`,
|
|
645
|
+
autoImportPatterns: [mergedQueriesFolder],
|
|
646
|
+
includeComposables: true,
|
|
647
|
+
downloadSchema: wpNuxtConfig.downloadSchema ?? true,
|
|
648
|
+
enableFileUploads: true,
|
|
649
|
+
// Use WPNuxt-branded API route prefix
|
|
650
|
+
serverApiPrefix: "/api/wpnuxt",
|
|
651
|
+
clientCache: {
|
|
652
|
+
// Enable or disable the caching feature.
|
|
653
|
+
enabled: true,
|
|
654
|
+
// Cache a maximum of 50 queries (default: 100).
|
|
655
|
+
maxSize: 50
|
|
656
|
+
},
|
|
657
|
+
codegenConfig: {
|
|
658
|
+
// WordPress-specific scalar mappings
|
|
659
|
+
scalars: {
|
|
660
|
+
DateTime: "string",
|
|
661
|
+
ID: "string"
|
|
662
|
+
}
|
|
663
|
+
},
|
|
664
|
+
experimental: {
|
|
665
|
+
// Use improved query parameter encoding for better URL handling
|
|
666
|
+
improvedQueryParamEncoding: true
|
|
667
|
+
}
|
|
668
|
+
});
|
|
669
|
+
await registerModule("@radya/nuxt-dompurify", "dompurify", {});
|
|
670
|
+
}
|
|
341
671
|
|
|
342
|
-
export { module as default };
|
|
672
|
+
export { module$1 as default };
|