@wpnuxt/core 1.0.0-edge.8 → 2.0.0-alpha.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.
Files changed (68) hide show
  1. package/dist/client-options.d.mts +1 -0
  2. package/dist/client-options.d.ts +1 -0
  3. package/dist/client-options.mjs +1 -0
  4. package/dist/module.d.mts +72 -82
  5. package/dist/module.d.ts +72 -82
  6. package/dist/module.json +4 -5
  7. package/dist/module.mjs +431 -268
  8. package/dist/runtime/app/graphqlMiddleware.clientOptions.d.ts +0 -0
  9. package/dist/runtime/app/graphqlMiddleware.clientOptions.js +12 -0
  10. package/dist/runtime/components/WPNuxtLogo.d.vue.ts +0 -0
  11. package/dist/runtime/components/WPNuxtLogo.vue +7 -7
  12. package/dist/runtime/components/WPNuxtLogo.vue.d.ts +0 -0
  13. package/dist/runtime/composables/useWPContent.d.ts +0 -5
  14. package/dist/runtime/composables/useWPContent.js +30 -16
  15. package/dist/runtime/plugins/graphqlConfig.d.ts +0 -0
  16. package/dist/runtime/plugins/graphqlConfig.js +17 -0
  17. package/dist/runtime/plugins/graphqlErrors.d.ts +0 -0
  18. package/dist/runtime/plugins/graphqlErrors.js +9 -0
  19. package/dist/runtime/queries/GeneralSettings.gql +0 -2
  20. package/dist/runtime/queries/Menu.gql +0 -2
  21. package/dist/runtime/queries/Node.gql +0 -3
  22. package/dist/runtime/queries/Pages.gql +0 -2
  23. package/dist/runtime/queries/Posts.gql +15 -2
  24. package/dist/runtime/queries/fragments/GeneralSettings.fragment.gql +1 -1
  25. package/dist/runtime/queries/fragments/NodeWithContentEditor.fragment.gql +3 -0
  26. package/dist/runtime/queries/fragments/NodeWithFeaturedImage.fragment.gql +0 -2
  27. package/dist/runtime/queries/fragments/NodeWithFeaturedImageToMediaItemConnectionEdge.fragment.gql +0 -2
  28. package/dist/runtime/queries/fragments/Page.fragment.gql +1 -4
  29. package/dist/runtime/queries/fragments/Post.fragment.gql +9 -5
  30. package/dist/runtime/server/graphqlMiddleware.serverOptions.d.ts +0 -0
  31. package/dist/runtime/server/graphqlMiddleware.serverOptions.js +18 -0
  32. package/dist/runtime/server/tsconfig.json +3 -0
  33. package/dist/runtime/util/images.d.ts +0 -2
  34. package/dist/runtime/util/images.js +11 -3
  35. package/dist/server-options.d.mts +2 -0
  36. package/dist/server-options.d.ts +2 -0
  37. package/dist/server-options.mjs +1 -0
  38. package/dist/types.d.mts +2 -2
  39. package/package.json +50 -79
  40. package/README.md +0 -80
  41. package/dist/module.cjs +0 -5
  42. package/dist/runtime/app/graphqlMiddleware.serverOptions.d.ts +0 -2
  43. package/dist/runtime/app/graphqlMiddleware.serverOptions.js +0 -11
  44. package/dist/runtime/components/StagingBanner.vue +0 -107
  45. package/dist/runtime/components/WordPressLogo.vue +0 -15
  46. package/dist/runtime/composables/index.d.ts +0 -3
  47. package/dist/runtime/composables/index.js +0 -3
  48. package/dist/runtime/composables/isStaging.d.ts +0 -1
  49. package/dist/runtime/composables/isStaging.js +0 -6
  50. package/dist/runtime/composables/useFeaturedImage.d.ts +0 -2
  51. package/dist/runtime/composables/useFeaturedImage.js +0 -7
  52. package/dist/runtime/composables/usePrevNextPost.d.ts +0 -4
  53. package/dist/runtime/composables/usePrevNextPost.js +0 -25
  54. package/dist/runtime/composables/useWPUri.d.ts +0 -8
  55. package/dist/runtime/composables/useWPUri.js +0 -23
  56. package/dist/runtime/plugins/vue-sanitize-directive.d.ts +0 -2
  57. package/dist/runtime/plugins/vue-sanitize-directive.js +0 -5
  58. package/dist/runtime/server/api/purgeCache.get.d.ts +0 -5
  59. package/dist/runtime/server/api/purgeCache.get.js +0 -9
  60. package/dist/runtime/server/api/wpContent.post.d.ts +0 -9
  61. package/dist/runtime/server/api/wpContent.post.js +0 -50
  62. package/dist/runtime/server/index.d.ts +0 -1
  63. package/dist/runtime/server/index.js +0 -8
  64. package/dist/runtime/server/storage.d.ts +0 -3
  65. package/dist/runtime/server/storage.js +0 -11
  66. package/dist/runtime/util/logger.d.ts +0 -3
  67. package/dist/runtime/util/logger.js +0 -25
  68. package/dist/types.d.ts +0 -7
package/dist/module.mjs CHANGED
@@ -1,70 +1,76 @@
1
- import { promises, statSync, existsSync, cpSync } from 'node:fs';
2
- import { resolveFiles, defineNuxtModule, createResolver, addPlugin, addImports, addComponent, addServerHandler, installModule, hasNuxtModule, addTemplate, addTypeTemplate } from '@nuxt/kit';
3
- import { join } from 'pathe';
4
- import consola, { createConsola } from 'consola';
5
- import { ref } from 'vue';
1
+ import { defu } from 'defu';
2
+ import { promises, cpSync, existsSync, statSync, mkdirSync, writeFileSync } 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 { parse } from 'graphql';
8
-
9
- const name = "@wpnuxt/core";
10
- const version = "1.0.0-edge.8";
6
+ import { ref } from 'vue';
7
+ import { parse, GraphQLError } from 'graphql';
11
8
 
9
+ function randHashGenerator(length = 12) {
10
+ return Math.random().toString(36).substring(2, 2 + length).toUpperCase().padEnd(length, "0");
11
+ }
12
12
  const loggerRef = ref();
13
- const initLogger = (logLevel) => {
14
- loggerRef.value = createConsola({
15
- level: logLevel ? logLevel : 3,
16
- formatOptions: {
17
- colors: true,
18
- compact: true,
19
- date: true,
20
- fancy: true
21
- }
22
- }).withTag("wpnuxt");
13
+ const initLogger = (debug) => {
14
+ loggerRef.value = useLogger("wpnuxt", { level: debug ? 4 : 3 });
23
15
  return loggerRef.value;
24
16
  };
25
- const getLogger = () => {
26
- if (loggerRef.value) {
27
- return loggerRef.value;
28
- }
29
- };
30
- function validateConfig(options) {
31
- if (!options.wordpressUrl || options.wordpressUrl.length === 0) {
32
- throw new Error("WPNuxt error: WordPress url is missing");
33
- } else if (options.wordpressUrl.substring(options.wordpressUrl.length - 1) === "/") {
34
- throw new Error("WPNuxt error: WordPress url should not have a trailing slash: " + options.wordpressUrl);
35
- }
36
- if (options.frontendUrl && options.frontendUrl.substring(options.frontendUrl.length - 1) === "/") {
37
- throw new Error("WPNuxt error: frontend url should not have a trailing slash: " + options.frontendUrl);
17
+ function getLogger() {
18
+ return loggerRef.value;
19
+ }
20
+ async function mergeQueries(nuxt, wpNuxtConfig, resolver) {
21
+ const logger = getLogger();
22
+ const baseDir = nuxt.options.srcDir || nuxt.options.rootDir;
23
+ const { resolve } = createResolver(baseDir);
24
+ const queryOutputPath = resolve(wpNuxtConfig.queries.mergedOutputFolder);
25
+ const userQueryPath = resolve(wpNuxtConfig.queries.extendFolder);
26
+ const defaultQueriesPath = resolver.resolve("./runtime/queries");
27
+ await promises.rm(queryOutputPath, { recursive: true, force: true });
28
+ cpSync(defaultQueriesPath, queryOutputPath, { recursive: true });
29
+ if (existsSync(userQueryPath)) {
30
+ logger.debug("Extending queries:", userQueryPath);
31
+ cpSync(userQueryPath, queryOutputPath, { recursive: true });
38
32
  }
33
+ logger.debug("Merged queries folder:", queryOutputPath);
34
+ return queryOutputPath;
39
35
  }
40
36
 
41
37
  const _parseDoc = async (doc) => {
42
- const { definitions } = parse(doc);
43
- const operations = definitions.filter(({ kind }) => kind === "OperationDefinition").map((definition) => {
44
- const operationDefinition = definition;
45
- if (!operationDefinition.name?.value) {
46
- throw new Error(`Operation name missing in: ${doc}`);
38
+ if (!doc || typeof doc !== "string" || doc.trim().length === 0) {
39
+ throw new Error("WPNuxt: Invalid GraphQL document - document is empty or not a string");
40
+ }
41
+ try {
42
+ const { definitions } = parse(doc);
43
+ const operations = definitions.filter(({ kind }) => kind === "OperationDefinition").map((definition) => {
44
+ const operationDefinition = definition;
45
+ if (!operationDefinition.name?.value) {
46
+ throw new Error("WPNuxt: GraphQL operation is missing a name. All queries and mutations must have a name.");
47
+ }
48
+ const query = {
49
+ name: operationDefinition.name.value.trim(),
50
+ nodes: [],
51
+ fragments: [],
52
+ params: {},
53
+ operation: operationDefinition.operation
54
+ };
55
+ processSelections(operationDefinition.selectionSet.selections, 0, query);
56
+ return query;
57
+ });
58
+ return operations;
59
+ } catch (error) {
60
+ if (error instanceof GraphQLError) {
61
+ throw new TypeError(`WPNuxt: Failed to parse GraphQL document - ${error.message}`);
47
62
  }
48
- const query = {
49
- name: operationDefinition.name.value.trim(),
50
- nodes: [],
51
- fragments: [],
52
- params: {}
53
- };
54
- processSelections(operationDefinition.selectionSet.selections, 0, query);
55
- return query;
56
- });
57
- return operations;
63
+ throw error;
64
+ }
58
65
  };
59
66
  function processSelections(selections, level, query) {
60
- if (!selections || selections.length === 0)
61
- return;
62
- if (selections.length === 1 && selections[0].kind === "Field") {
63
- query.nodes.push(selections[0].name.value.trim());
67
+ if (!selections || selections.length === 0) return;
68
+ if (selections.length === 1 && selections[0]?.kind === "Field") {
69
+ query.nodes?.push(selections[0].name.value.trim());
64
70
  }
65
71
  selections.forEach((s) => {
66
72
  if (s.kind === "FragmentSpread") {
67
- query.fragments.push(s.name.value.trim());
73
+ query.fragments?.push(s.name.value.trim());
68
74
  } else if (s.selectionSet?.selections) {
69
75
  processSelections(s.selectionSet.selections, level + 1, query);
70
76
  }
@@ -72,242 +78,240 @@ function processSelections(selections, level, query) {
72
78
  }
73
79
  const parseDoc = _parseDoc;
74
80
 
81
+ const SCHEMA_PATTERN = /schema\.(?:gql|graphql)$/i;
82
+ const allowDocument = (f, resolver) => {
83
+ if (SCHEMA_PATTERN.test(f)) return false;
84
+ try {
85
+ return statSync(resolver.resolve(f)).size > 0;
86
+ } catch {
87
+ return false;
88
+ }
89
+ };
90
+ async function generateWPNuxtComposables(ctx, queryOutputPath, resolver) {
91
+ const gqlMatch = "**/*.{gql,graphql}";
92
+ const documents = [];
93
+ const files = (await resolveFiles(queryOutputPath, [gqlMatch, "!**/schemas"], { followSymbolicLinks: false })).filter((doc) => allowDocument(doc, resolver));
94
+ documents.push(...files);
95
+ ctx.docs = documents;
96
+ await prepareContext(ctx);
97
+ }
75
98
  async function prepareContext(ctx) {
76
99
  const logger = getLogger();
77
100
  if (ctx.docs) {
78
101
  await prepareFunctions(ctx);
79
102
  }
103
+ const queries = ctx.fns.filter((f) => f.operation === "query");
104
+ const mutations = ctx.fns.filter((f) => f.operation === "mutation");
80
105
  const fnName = (fn) => ctx.composablesPrefix + upperFirst(fn);
81
- const fnExp = (q, typed = false) => {
82
- const functionName = fnName(q.name);
106
+ const mutationFnName = (fn) => `useMutation${upperFirst(fn)}`;
107
+ const formatNodes = (nodes) => nodes?.map((n) => `'${n}'`).join(",") ?? "";
108
+ const getFragmentType = (q) => {
109
+ const fragmentSuffix = q.fragments?.length && q.nodes?.includes("nodes") ? "[]" : "";
110
+ return q.fragments?.length ? q.fragments.map((f) => `${f}Fragment${fragmentSuffix}`).join(" | ") : "any";
111
+ };
112
+ const queryFnExp = (q, typed = false, lazy = false) => {
113
+ const baseName = fnName(q.name);
114
+ const functionName = lazy ? `useLazy${q.name}` : baseName;
83
115
  if (!typed) {
84
- return `export const ${functionName} = (params) => useWPContent('${q.name}', [${q.nodes?.map((n) => `'${n}'`).join(",")}], false, params)`;
116
+ if (lazy) {
117
+ return `export const ${functionName} = (params, options) => useWPContent('${q.name}', [${formatNodes(q.nodes)}], false, params, { ...options, lazy: true })`;
118
+ }
119
+ return `export const ${functionName} = (params, options) => useWPContent('${q.name}', [${formatNodes(q.nodes)}], false, params, options)`;
85
120
  }
86
- const fragmentSuffix = q.fragments?.length && q.nodes?.includes("nodes") ? "[]" : "";
87
- const fragments = q.fragments?.length ? q.fragments.map((f) => `${f}Fragment${fragmentSuffix}`).join(" | ") : "any";
88
- return ` export const ${functionName}: (params?: ${q.name}QueryVariables) => AsyncData<${fragments}, FetchError | null | undefined>`;
121
+ return ` export const ${functionName}: (params?: ${q.name}QueryVariables, options?: WPContentOptions) => WPContentResult<${getFragmentType(q)}>`;
122
+ };
123
+ const mutationFnExp = (m, typed = false) => {
124
+ const functionName = mutationFnName(m.name);
125
+ if (!typed) {
126
+ return `export const ${functionName} = (variables, options) => useGraphqlMutation('${m.name}', variables, options)`;
127
+ }
128
+ return ` export const ${functionName}: (variables: ${m.name}MutationVariables, options?: WPMutationOptions) => Promise<WPMutationResult<${m.name}Mutation>>`;
129
+ };
130
+ ctx.generateImports = () => {
131
+ const imports = [];
132
+ queries.forEach((f) => {
133
+ imports.push(queryFnExp(f, false, false));
134
+ imports.push(queryFnExp(f, false, true));
135
+ });
136
+ mutations.forEach((m) => {
137
+ imports.push(mutationFnExp(m, false));
138
+ });
139
+ return imports.join("\n");
89
140
  };
90
- ctx.generateImports = () => [
91
- ...ctx.fns.map((f) => fnExp(f))
92
- ].join("\n");
93
- const types = [];
94
- ctx.fns.forEach((o) => types.push(...getQueryTypeTemplate(o)));
95
- ctx.generateDeclarations = () => [
96
- `import type { ${[...new Set(types)].join(", ")} } from '#build/graphql-operations'`,
97
- "import { AsyncData } from 'nuxt/app'",
98
- "import { FetchError } from 'ofetch'",
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) }));
141
+ const typeSet = /* @__PURE__ */ new Set();
142
+ queries.forEach((o) => {
143
+ typeSet.add(`${o.name}QueryVariables`);
144
+ o.fragments?.forEach((f) => typeSet.add(`${f}Fragment`));
145
+ });
146
+ mutations.forEach((m) => {
147
+ typeSet.add(`${m.name}MutationVariables`);
148
+ typeSet.add(`${m.name}Mutation`);
149
+ });
150
+ ctx.generateDeclarations = () => {
151
+ const declarations = [
152
+ `import type { ${[...typeSet].join(", ")} } from '#build/graphql-operations'`,
153
+ "import type { ComputedRef, Ref } from 'vue'",
154
+ "import type { AsyncDataRequestStatus } from '#app'",
155
+ "import type { GraphqlResponse } from 'nuxt-graphql-middleware/types'",
156
+ "",
157
+ "export interface WPContentOptions {",
158
+ " /** Whether to resolve the async function after loading the route, instead of blocking client-side navigation. Default: false */",
159
+ " lazy?: boolean",
160
+ " /** Whether to fetch data on the server (during SSR). Default: true */",
161
+ " server?: boolean",
162
+ " /** Whether to fetch immediately. Default: true */",
163
+ " immediate?: boolean",
164
+ " /** Watch reactive sources to auto-refresh */",
165
+ " watch?: unknown[]",
166
+ " /** Transform function to alter the result */",
167
+ " transform?: (input: unknown) => unknown",
168
+ " /** Additional options to pass to useAsyncGraphqlQuery */",
169
+ " [key: string]: unknown",
170
+ "}",
171
+ "",
172
+ "export interface WPMutationOptions {",
173
+ " /** Fetch options to pass to the request */",
174
+ " fetchOptions?: RequestInit",
175
+ " /** Additional options */",
176
+ " [key: string]: unknown",
177
+ "}",
178
+ "",
179
+ "interface WPContentResult<T> {",
180
+ " data: ComputedRef<T | undefined>",
181
+ " pending: Ref<boolean>",
182
+ " refresh: () => Promise<void>",
183
+ " execute: () => Promise<void>",
184
+ " clear: () => void",
185
+ " error: Ref<Error | undefined>",
186
+ " status: Ref<AsyncDataRequestStatus>",
187
+ "}",
188
+ "",
189
+ "type WPMutationResult<T> = GraphqlResponse<T>",
190
+ "",
191
+ "declare module '#wpnuxt' {"
192
+ ];
193
+ queries.forEach((f) => {
194
+ declarations.push(queryFnExp(f, true, false));
195
+ declarations.push(queryFnExp(f, true, true));
196
+ });
197
+ mutations.forEach((m) => {
198
+ declarations.push(mutationFnExp(m, true));
199
+ });
200
+ declarations.push("}");
201
+ return declarations.join("\n");
202
+ };
203
+ ctx.fnImports = [
204
+ // Auto-import query composables (regular and lazy variants)
205
+ ...queries.flatMap((fn) => [
206
+ { from: "#wpnuxt", name: fnName(fn.name) },
207
+ { from: "#wpnuxt", name: `useLazy${fn.name}` }
208
+ ]),
209
+ // Auto-import mutation composables
210
+ ...mutations.map((m) => ({ from: "#wpnuxt", name: mutationFnName(m.name) }))
211
+ ];
106
212
  logger.debug("generated WPNuxt composables: ");
107
- ctx.fns.forEach((f) => logger.debug(` ${fnName(f.name)}()`));
108
- }
109
- function getQueryTypeTemplate(q) {
110
- const types = [];
111
- types.push(`${q.name}QueryVariables`);
112
- if (q.fragments && q.fragments.length > 0) {
113
- q.fragments.forEach((f) => types.push(`${f}Fragment`));
114
- }
115
- return types;
213
+ queries.forEach((f) => {
214
+ logger.debug(` ${fnName(f.name)}()`);
215
+ logger.debug(` useLazy${f.name}()`);
216
+ });
217
+ mutations.forEach((m) => {
218
+ logger.debug(` ${mutationFnName(m.name)}()`);
219
+ });
116
220
  }
117
221
  async function prepareFunctions(ctx) {
118
222
  if (!ctx.docs) {
119
223
  getLogger().error("no GraphQL query documents were found!");
120
224
  return;
121
225
  }
122
- for await (const doc of ctx.docs) {
123
- const operations = await parseDoc(await promises.readFile(doc, "utf8"));
124
- operations.forEach((query) => {
125
- ctx.fns.push(query);
126
- });
127
- }
128
- }
129
-
130
- const allowDocument = (f, resolver) => {
131
- const isSchema = f.match(/([^/]+)\.(gql|graphql)$/)?.[0]?.toLowerCase().includes("schema");
132
- return !isSchema && !!statSync(resolver.resolve(f)).size;
133
- };
134
- async function generateWPNuxtComposables(ctx, queryOutputPath, resolver) {
135
- const gqlMatch = "**/*.{gql,graphql}";
136
- const documents = [];
137
- const files = (await resolveFiles(queryOutputPath, [gqlMatch, "!**/schemas"], { followSymbolicLinks: false })).filter((doc) => allowDocument(doc, resolver));
138
- documents.push(...files);
139
- ctx.docs = documents;
140
- await prepareContext(ctx);
226
+ const operations = await Promise.all(
227
+ ctx.docs.map(async (doc) => {
228
+ const content = await promises.readFile(doc, "utf8");
229
+ return parseDoc(content);
230
+ })
231
+ );
232
+ operations.flat().forEach((query) => {
233
+ ctx.fns.push(query);
234
+ });
141
235
  }
142
236
 
143
- const defaultConfigs = {
144
- wordpressUrl: "",
145
- frontendUrl: "",
146
- defaultMenuName: "main",
147
- enableCache: true,
148
- staging: false,
149
- logLevel: 3,
150
- composablesPrefix: "useWP"
151
- };
152
- const module = defineNuxtModule({
237
+ const module$1 = defineNuxtModule({
153
238
  meta: {
154
- name,
155
- version,
156
- configKey: "wpNuxt",
157
- nuxt: ">=3.1.0"
239
+ name: "wpnuxt",
240
+ configKey: "wpNuxt"
241
+ },
242
+ defaults: {
243
+ wordpressUrl: void 0,
244
+ graphqlEndpoint: "/graphql",
245
+ queries: {
246
+ extendFolder: "extend/queries/",
247
+ mergedOutputFolder: ".queries/"
248
+ },
249
+ downloadSchema: true,
250
+ debug: false,
251
+ cache: {
252
+ enabled: true,
253
+ maxAge: 60 * 5,
254
+ // 5 minutes
255
+ swr: true
256
+ }
158
257
  },
159
- // Default configuration options of the Nuxt module
160
- defaults: defaultConfigs,
161
258
  async setup(options, nuxt) {
162
259
  const startTime = (/* @__PURE__ */ new Date()).getTime();
163
- consola.log("::: Starting WPNuxt setup ::: ");
164
- const publicWPNuxtConfig = {
165
- wordpressUrl: process.env.WPNUXT_WORDPRESS_URL || options.wordpressUrl,
166
- frontendUrl: process.env.WPNUXT_FRONTEND_URL || options.frontendUrl,
167
- defaultMenuName: process.env.WPNUXT_DEFAULT_MENU_NAME || options.defaultMenuName,
168
- enableCache: process.env.WPNUXT_ENABLE_CACHE ? process.env.WPNUXT_ENABLE_CACHE === "true" : options.enableCache,
169
- staging: process.env.WPNUXT_STAGING === "true" || options.staging,
170
- downloadSchema: process.env.WPNUXT_DOWNLOAD_SCHEMA === "true" || options.downloadSchema,
171
- logLevel: process.env.WPNUXT_LOG_LEVEL ? Number.parseInt(process.env.WPNUXT_LOG_LEVEL) : options.logLevel,
172
- composablesPrefix: process.env.WPNUXT_COMPOSABLES_PREFIX || options.composablesPrefix
173
- };
174
- nuxt.options.runtimeConfig.public.wpNuxt = publicWPNuxtConfig;
175
- validateConfig(publicWPNuxtConfig);
176
- const logger = initLogger(publicWPNuxtConfig.logLevel);
177
- logger.info("Connecting GraphQL to", publicWPNuxtConfig.wordpressUrl);
178
- logger.info("frontendUrl:", publicWPNuxtConfig.frontendUrl);
179
- if (publicWPNuxtConfig.enableCache)
180
- logger.info("Cache enabled");
181
- logger.debug("Debug mode enabled, log level:", publicWPNuxtConfig.logLevel);
182
- if (publicWPNuxtConfig.staging)
183
- logger.info("Staging enabled");
184
- const { resolve } = createResolver(import.meta.url);
185
- const resolveRuntimeModule = (path) => resolve("./runtime", path);
186
- const srcResolver = createResolver(nuxt.options.srcDir);
187
- nuxt.options.alias["#wpnuxt"] = resolve(nuxt.options.buildDir, "wpnuxt");
188
- nuxt.options.alias["#wpnuxt/*"] = resolve(nuxt.options.buildDir, "wpnuxt", "*");
189
- nuxt.options.alias["#wpnuxt/types"] = resolve("./types");
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")
260
+ const wpNuxtConfig = loadConfig(options, nuxt);
261
+ const logger = initLogger(wpNuxtConfig.debug);
262
+ logger.debug("Starting WPNuxt in debug mode");
263
+ const resolver = createResolver(import.meta.url);
264
+ nuxt.options.runtimeConfig.public.buildHash = randHashGenerator();
265
+ addPlugin(resolver.resolve("./runtime/plugins/graphqlConfig"));
266
+ addPlugin(resolver.resolve("./runtime/plugins/graphqlErrors"));
267
+ const mergedQueriesFolder = await mergeQueries(nuxt, wpNuxtConfig, resolver);
268
+ setupServerOptions(nuxt, resolver, logger);
269
+ setupClientOptions(nuxt, resolver, logger);
270
+ await registerModules(nuxt, resolver, wpNuxtConfig, mergedQueriesFolder);
271
+ nuxt.hook("devtools:customTabs", (tabs) => {
272
+ const middlewareTab = tabs.find((tab) => tab.name === "nuxt-graphql-middleware");
273
+ if (middlewareTab) {
274
+ middlewareTab.title = "WPNuxt GraphQL";
275
+ middlewareTab.icon = "simple-icons:wordpress";
276
+ }
220
277
  });
221
- await installModule("@vueuse/nuxt", {});
222
- const queryOutputPath = resolve((nuxt.options.srcDir || nuxt.options.rootDir) + "/.queries/");
223
- await promises.rm(queryOutputPath, { recursive: true, force: true });
224
- const userQueryPath = "~/extend/queries/".replace(/^(~~|@@)/, nuxt.options.rootDir).replace(/^(~|@)/, nuxt.options.srcDir);
225
- const userQueryPathExists = existsSync(userQueryPath);
226
- cpSync(resolveRuntimeModule("./queries/"), queryOutputPath, { recursive: true });
227
- if (hasNuxtModule("@wpnuxt/blocks")) {
228
- logger.debug("Loading @wpnuxt/blocks");
229
- for (const m of nuxt.options._installedModules) {
230
- if (m.meta.name === "@wpnuxt/blocks" && m.entryPath) {
231
- let blocksQueriesPath;
232
- if (m.entryPath.startsWith("../src/module")) {
233
- blocksQueriesPath = join(nuxt.options.rootDir, "../src/runtime/queries/");
234
- } else {
235
- blocksQueriesPath = join("./node_modules", m.entryPath, "dist/runtime/queries/");
236
- }
237
- cpSync(blocksQueriesPath, queryOutputPath, { recursive: true });
278
+ if (wpNuxtConfig.cache?.enabled !== false) {
279
+ const maxAge = wpNuxtConfig.cache?.maxAge ?? 300;
280
+ nuxt.options.nitro.routeRules = nuxt.options.nitro.routeRules || {};
281
+ nuxt.options.nitro.routeRules["/api/wpnuxt/**"] = {
282
+ cache: {
283
+ maxAge,
284
+ swr: wpNuxtConfig.cache?.swr !== false
238
285
  }
239
- }
240
- } else {
241
- logger.debug("Tip: Install the @wpnuxt/blocks module if you want to render Gutenberg blocks with separate vue components");
242
- }
243
- if (userQueryPathExists) {
244
- logger.debug("Extending queries:", userQueryPath);
245
- cpSync(resolve(userQueryPath), queryOutputPath, { recursive: true });
286
+ };
287
+ logger.debug(`Server-side caching enabled for GraphQL requests (maxAge: ${maxAge}s, SWR: ${wpNuxtConfig.cache?.swr !== false})`);
246
288
  }
247
- logger.debug("Copied merged queries in folder:", queryOutputPath);
248
- await installModule("nuxt-graphql-middleware", {
249
- debug: publicWPNuxtConfig.logLevel ? publicWPNuxtConfig.logLevel > 3 : false,
250
- graphqlEndpoint: `${publicWPNuxtConfig.wordpressUrl}/graphql`,
251
- downloadSchema: publicWPNuxtConfig.downloadSchema,
252
- codegenConfig: {
253
- silent: false,
254
- skipTypename: true,
255
- useTypeImports: true,
256
- // inlineFragmentTypes: 'combine',
257
- dedupeFragments: true,
258
- onlyOperationTypes: true,
259
- avoidOptionals: false,
260
- maybeValue: "T | undefined",
261
- disableOnBuild: false,
262
- gqlImport: "graphql-request#wpnuxt",
263
- namingConvention: {
264
- enumValues: "change-case-all#upperCaseFirst"
265
- },
266
- documents: [
267
- resolve("!./graphql/**/*")
268
- ]
269
- },
270
- codegenSchemaConfig: {
271
- urlSchemaOptions: {
272
- headers: {
273
- Authorization: "server-token"
274
- }
275
- }
276
- },
277
- outputDocuments: true,
278
- autoImportPatterns: queryOutputPath,
279
- includeComposables: true,
280
- devtools: true
281
- });
282
- const resolvedPath = resolveRuntimeModule("./app/graphqlMiddleware.serverOptions");
283
- const template = addTemplate({
284
- filename: "graphqlMiddleware.serverOptions.ts",
285
- write: true,
286
- getContents: () => `
287
- import type { GraphqlMiddlewareServerOptions } from '#graphql-middleware/types'
288
- import serverOptions from '${resolvedPath}'
289
- import type { GraphqlServerResponse } from '#graphql-middleware/types'
290
- import type { GraphqlMiddlewareResponseUnion } from '#build/nuxt-graphql-middleware'
291
-
292
- type GraphqlResponseAdditions =
293
- typeof serverOptions extends GraphqlMiddlewareServerOptions<infer R> ? R : {}
294
-
295
- export type GraphqlResponse<T> = GraphqlServerResponse<T> & GraphqlResponseAdditions
296
-
297
- export type GraphqlResponseTyped = GraphqlResponse<GraphqlMiddlewareResponseUnion>
298
-
299
- export { serverOptions }
300
- `
289
+ configureVercelSettings(nuxt, logger);
290
+ addImports([
291
+ { name: "useWPContent", as: "useWPContent", from: resolver.resolve("./runtime/composables/useWPContent") },
292
+ { name: "useAsyncWPContent", as: "useAsyncWPContent", from: resolver.resolve("./runtime/composables/useWPContent") }
293
+ // Note: useGraphqlMutation is auto-imported via nuxt-graphql-middleware with includeComposables: true
294
+ ]);
295
+ addComponentsDir({
296
+ path: resolver.resolve("./runtime/components"),
297
+ pathPrefix: false,
298
+ prefix: "",
299
+ global: true
301
300
  });
302
- nuxt.options.nitro.externals.inline.push(template.dst);
303
- nuxt.options.alias["#graphql-middleware-server-options-build"] = template.dst;
304
301
  logger.trace("Start generating composables");
305
- const ctx = await {
302
+ const ctx = {
306
303
  fns: [],
307
304
  fnImports: [],
308
- composablesPrefix: publicWPNuxtConfig.composablesPrefix
305
+ composablesPrefix: "use"
309
306
  };
310
- await generateWPNuxtComposables(ctx, queryOutputPath, srcResolver);
307
+ await generateWPNuxtComposables(ctx, mergedQueriesFolder, createResolver(nuxt.options.srcDir));
308
+ nuxt.options.alias["#wpnuxt"] = resolver.resolve(nuxt.options.buildDir, "wpnuxt");
309
+ nuxt.options.alias["#wpnuxt/*"] = resolver.resolve(nuxt.options.buildDir, "wpnuxt", "*");
310
+ nuxt.options.alias["#wpnuxt/types"] = resolver.resolve("./types");
311
+ nuxt.options.nitro.alias = nuxt.options.nitro.alias || {};
312
+ nuxt.options.nitro.alias["#wpnuxt/types"] = resolver.resolve("./types");
313
+ nuxt.options.nitro.externals = nuxt.options.nitro.externals || {};
314
+ nuxt.options.nitro.externals.inline = nuxt.options.nitro.externals.inline || [];
311
315
  addTemplate({
312
316
  write: true,
313
317
  filename: "wpnuxt/index.mjs",
@@ -321,16 +325,175 @@ const module = defineNuxtModule({
321
325
  nuxt.hook("imports:extend", (autoimports) => {
322
326
  autoimports.push(...ctx.fnImports || []);
323
327
  });
324
- nuxt.hook("nitro:init", async (nitro) => {
325
- const keys = await nitro.storage.getKeys("cache:content");
326
- keys.forEach(async (key) => {
327
- if (key.startsWith("cache:content"))
328
- await nitro.storage.removeItem(key);
329
- });
330
- });
331
- const endTime = (/* @__PURE__ */ new Date()).getTime();
332
- logger.success("::: Finished WPNuxt setup in " + (endTime - startTime) + "ms ::: ");
328
+ logger.trace("Finished generating composables");
329
+ logger.info(`WPNuxt module loaded in ${(/* @__PURE__ */ new Date()).getTime() - startTime}ms`);
333
330
  }
334
331
  });
332
+ function loadConfig(options, nuxt) {
333
+ const config = defu({
334
+ wordpressUrl: process.env.WPNUXT_WORDPRESS_URL,
335
+ graphqlEndpoint: process.env.WPNUXT_GRAPHQL_ENDPOINT,
336
+ downloadSchema: process.env.WPNUXT_DOWNLOAD_SCHEMA ? process.env.WPNUXT_DOWNLOAD_SCHEMA === "true" : void 0,
337
+ debug: process.env.WPNUXT_DEBUG ? process.env.WPNUXT_DEBUG === "true" : void 0
338
+ }, options);
339
+ nuxt.options.runtimeConfig.public.wordpressUrl = config.wordpressUrl;
340
+ nuxt.options.runtimeConfig.public.wpNuxt = {
341
+ wordpressUrl: config.wordpressUrl,
342
+ graphqlEndpoint: config.graphqlEndpoint,
343
+ cache: {
344
+ enabled: config.cache?.enabled ?? true,
345
+ maxAge: config.cache?.maxAge ?? 300,
346
+ swr: config.cache?.swr ?? true
347
+ }
348
+ };
349
+ if (!config.wordpressUrl?.trim()) {
350
+ throw new Error("WPNuxt error: WordPress url is missing");
351
+ }
352
+ if (config.wordpressUrl.endsWith("/")) {
353
+ throw new Error(`WPNuxt error: WordPress url should not have a trailing slash: ${config.wordpressUrl}`);
354
+ }
355
+ return config;
356
+ }
357
+ const SERVER_OPTIONS_TEMPLATE = `import { defineGraphqlServerOptions } from '@wpnuxt/core/server-options'
358
+ import { getHeader } from 'h3'
359
+
360
+ /**
361
+ * WPNuxt default server options for nuxt-graphql-middleware.
362
+ *
363
+ * This enables:
364
+ * - Cookie forwarding for WordPress preview mode
365
+ * - Authorization header forwarding for authenticated requests
366
+ * - Consistent error logging
367
+ *
368
+ * Users can customize by creating their own server/graphqlMiddleware.serverOptions.ts
369
+ */
370
+ export default defineGraphqlServerOptions({
371
+ async serverFetchOptions(event, _operation, _operationName, _context) {
372
+ return {
373
+ headers: {
374
+ // Forward WordPress auth cookies for previews
375
+ Cookie: getHeader(event, 'cookie') || '',
376
+ // Forward authorization header if present
377
+ Authorization: getHeader(event, 'authorization') || ''
378
+ }
379
+ }
380
+ },
381
+
382
+ async onServerError(event, error, _operation, operationName) {
383
+ const url = event.node.req.url || 'unknown'
384
+ console.error(\`[WPNuxt] GraphQL error in \${operationName} (\${url}):\`, error.message)
385
+ }
386
+ })
387
+ `;
388
+ function setupServerOptions(nuxt, _resolver, logger) {
389
+ const serverDir = nuxt.options.serverDir;
390
+ const targetPath = join(serverDir, "graphqlMiddleware.serverOptions.ts");
391
+ if (existsSync(targetPath)) {
392
+ logger.debug("Using existing graphqlMiddleware.serverOptions.ts from project");
393
+ return;
394
+ }
395
+ if (!existsSync(serverDir)) {
396
+ mkdirSync(serverDir, { recursive: true });
397
+ }
398
+ writeFileSync(targetPath, SERVER_OPTIONS_TEMPLATE);
399
+ logger.debug("Created graphqlMiddleware.serverOptions.ts with WPNuxt defaults (cookie/auth forwarding)");
400
+ }
401
+ const CLIENT_OPTIONS_TEMPLATE = `import { defineGraphqlClientOptions } from '@wpnuxt/core/client-options'
402
+ import { useRoute } from '#imports'
403
+
404
+ /**
405
+ * WPNuxt default client options for nuxt-graphql-middleware.
406
+ *
407
+ * This enables passing client context to the server for:
408
+ * - Preview mode (passes preview flag and token from URL query params)
409
+ *
410
+ * The context is available in serverFetchOptions via context.client
411
+ * All values must be strings (nuxt-graphql-middleware requirement)
412
+ *
413
+ * Users can customize by creating their own app/graphqlMiddleware.clientOptions.ts
414
+ */
415
+ export default defineGraphqlClientOptions<{
416
+ preview?: string
417
+ previewToken?: string
418
+ }>({
419
+ buildClientContext() {
420
+ const route = useRoute()
421
+
422
+ return {
423
+ // Context values must be strings - use 'true'/'false' instead of boolean
424
+ preview: route.query.preview === 'true' ? 'true' : undefined,
425
+ previewToken: route.query.token as string | undefined
426
+ }
427
+ }
428
+ })
429
+ `;
430
+ function setupClientOptions(nuxt, _resolver, logger) {
431
+ const appDir = nuxt.options.dir.app;
432
+ const targetPath = join(appDir, "graphqlMiddleware.clientOptions.ts");
433
+ if (existsSync(targetPath)) {
434
+ logger.debug("Using existing graphqlMiddleware.clientOptions.ts from project");
435
+ return;
436
+ }
437
+ if (!existsSync(appDir)) {
438
+ mkdirSync(appDir, { recursive: true });
439
+ }
440
+ writeFileSync(targetPath, CLIENT_OPTIONS_TEMPLATE);
441
+ logger.debug("Created graphqlMiddleware.clientOptions.ts with WPNuxt defaults (preview mode support)");
442
+ }
443
+ function configureVercelSettings(nuxt, logger) {
444
+ const isVercel = process.env.VERCEL === "1" || nuxt.options.nitro.preset === "vercel";
445
+ if (isVercel) {
446
+ logger.debug("Vercel deployment detected, applying recommended settings");
447
+ nuxt.options.nitro.future = nuxt.options.nitro.future || {};
448
+ if (nuxt.options.nitro.future.nativeSWR === void 0) {
449
+ nuxt.options.nitro.future.nativeSWR = true;
450
+ logger.debug("Enabled nitro.future.nativeSWR for Vercel ISR compatibility");
451
+ }
452
+ nuxt.options.routeRules = nuxt.options.routeRules || {};
453
+ if (!nuxt.options.routeRules["/**"]) {
454
+ nuxt.options.routeRules["/**"] = { ssr: true };
455
+ logger.debug("Enabled SSR for all routes (routeRules['/**'] = { ssr: true })");
456
+ }
457
+ }
458
+ }
459
+ async function registerModules(nuxt, resolver, wpNuxtConfig, mergedQueriesFolder) {
460
+ const logger = getLogger();
461
+ async function registerModule(name, key, options) {
462
+ if (!hasNuxtModule(name)) {
463
+ await installModule(name, options);
464
+ } else {
465
+ logger.debug(`${name} module already registered, using the 'graphqlMiddleware' config from nuxt.config.ts`);
466
+ nuxt.options[key] = defu(nuxt.options[key], options);
467
+ }
468
+ }
469
+ await registerModule("nuxt-graphql-middleware", "graphql", {
470
+ debug: wpNuxtConfig.debug,
471
+ graphqlEndpoint: `${wpNuxtConfig.wordpressUrl}${wpNuxtConfig.graphqlEndpoint}`,
472
+ autoImportPatterns: [mergedQueriesFolder],
473
+ includeComposables: true,
474
+ downloadSchema: wpNuxtConfig.downloadSchema,
475
+ enableFileUploads: true,
476
+ // Use WPNuxt-branded API route prefix
477
+ serverApiPrefix: "/api/wpnuxt",
478
+ clientCache: {
479
+ // Enable or disable the caching feature.
480
+ enabled: true,
481
+ // Cache a maximum of 50 queries (default: 100).
482
+ maxSize: 50
483
+ },
484
+ codegenConfig: {
485
+ // WordPress-specific scalar mappings
486
+ scalars: {
487
+ DateTime: "string",
488
+ ID: "string"
489
+ }
490
+ },
491
+ experimental: {
492
+ // Use improved query parameter encoding for better URL handling
493
+ improvedQueryParamEncoding: true
494
+ }
495
+ });
496
+ await registerModule("@radya/nuxt-dompurify", "dompurify", {});
497
+ }
335
498
 
336
- export { module as default };
499
+ export { module$1 as default };