@wpnuxt/core 2.0.0-beta.2 → 2.0.0-beta.4

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/module.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@wpnuxt/core",
3
- "version": "2.0.0-beta.2",
3
+ "version": "2.0.0-beta.4",
4
4
  "configKey": "wpNuxt",
5
5
  "compatibility": {
6
- "nuxt": ">=3.0.0"
6
+ "nuxt": ">=3.17.0"
7
7
  },
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "1.0.2",
package/dist/module.mjs CHANGED
@@ -1,15 +1,14 @@
1
- import { consola } from 'consola';
2
1
  import { defu } from 'defu';
3
- import { promises, cpSync, existsSync, readdirSync, statSync, readFileSync, writeFileSync } from 'node:fs';
2
+ import { promises, cpSync, existsSync, readdirSync, statSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
4
3
  import { writeFile, rename, readFile, mkdir } from 'node:fs/promises';
5
4
  import { join, relative, dirname } from 'node:path';
6
- import { useLogger, createResolver, resolveFiles, defineNuxtModule, addPlugin, hasNuxtModule, addImports, addComponentsDir, addTemplate, addTypeTemplate, installModule } from '@nuxt/kit';
5
+ import { useLogger, createResolver, resolveFiles, defineNuxtModule, addPlugin, addImports, addComponentsDir, addTemplate, addTypeTemplate, hasNuxtModule, installModule } from '@nuxt/kit';
7
6
  import { upperFirst } from 'scule';
8
- import { ref } from 'vue';
9
- import { parse, GraphQLError } from 'graphql';
7
+ import { parse, GraphQLError, visit, print } from 'graphql';
10
8
  import { execSync } from 'node:child_process';
9
+ import { consola } from 'consola';
11
10
 
12
- const version = "2.0.0-beta.2";
11
+ const version = "2.0.0-beta.4";
13
12
 
14
13
  function createModuleError(module, message) {
15
14
  return new Error(formatErrorMessage(module, message));
@@ -44,13 +43,13 @@ async function atomicWriteFile(path, content) {
44
43
  function randHashGenerator(length = 12) {
45
44
  return Math.random().toString(36).substring(2, 2 + length).toUpperCase().padEnd(length, "0");
46
45
  }
47
- const loggerRef = ref();
46
+ let loggerInstance;
48
47
  const initLogger = (debug) => {
49
- loggerRef.value = useLogger("wpnuxt", { level: debug ? 4 : 3 });
50
- return loggerRef.value;
48
+ loggerInstance = useLogger("wpnuxt", { level: debug ? 4 : 3 });
49
+ return loggerInstance;
51
50
  };
52
51
  function getLogger() {
53
- return loggerRef.value;
52
+ return loggerInstance;
54
53
  }
55
54
  async function mergeQueries(nuxt, wpNuxtConfig, resolver) {
56
55
  const logger = getLogger();
@@ -70,7 +69,7 @@ async function mergeQueries(nuxt, wpNuxtConfig, resolver) {
70
69
  }
71
70
  if (existsSync(userQueryPath)) {
72
71
  logger.debug("Extending queries:", userQueryPath);
73
- cpSync(userQueryPath, queryOutputPath, { recursive: true });
72
+ copyGraphqlFiles(userQueryPath, queryOutputPath);
74
73
  }
75
74
  logger.debug("Merged queries folder:", queryOutputPath);
76
75
  return queryOutputPath;
@@ -98,6 +97,20 @@ function findConflicts(userQueryPath, outputPath) {
98
97
  }
99
98
  return conflicts;
100
99
  }
100
+ function copyGraphqlFiles(src, dest) {
101
+ const entries = readdirSync(src);
102
+ for (const entry of entries) {
103
+ const srcPath = join(src, entry);
104
+ const destPath = join(dest, entry);
105
+ const stat = statSync(srcPath);
106
+ if (stat.isDirectory()) {
107
+ mkdirSync(destPath, { recursive: true });
108
+ copyGraphqlFiles(srcPath, destPath);
109
+ } else if (entry.endsWith(".gql") || entry.endsWith(".graphql")) {
110
+ cpSync(srcPath, destPath);
111
+ }
112
+ }
113
+ }
101
114
 
102
115
  const _parseDoc = async (doc) => {
103
116
  if (!doc || typeof doc !== "string" || doc.trim().length === 0) {
@@ -110,8 +123,12 @@ const _parseDoc = async (doc) => {
110
123
  if (!operationDefinition.name?.value) {
111
124
  throw createModuleError("core", "GraphQL operation is missing a name. All queries and mutations must have a name.");
112
125
  }
126
+ const name = operationDefinition.name.value.trim();
127
+ if (!/^[a-z_$][\w$]*$/i.test(name)) {
128
+ throw createModuleError("core", `Invalid GraphQL operation name "${name}". Operation names must be valid JavaScript identifiers (start with a letter, underscore, or $ and contain only letters, numbers, underscores, or $).`);
129
+ }
113
130
  const query = {
114
- name: operationDefinition.name.value.trim(),
131
+ name,
115
132
  nodes: [],
116
133
  fragments: [],
117
134
  params: {},
@@ -281,7 +298,17 @@ async function prepareContext(ctx) {
281
298
  " watch?: unknown[]",
282
299
  " /** Transform function to alter the result */",
283
300
  " transform?: (input: unknown) => unknown",
284
- " /** Additional options to pass to useAsyncGraphqlQuery */",
301
+ " /** Enable client-side GraphQL caching. Default: true. Set to false for real-time data. */",
302
+ " clientCache?: boolean",
303
+ " /** Custom function to control when cached data should be used. */",
304
+ " getCachedData?: (key: string, nuxtApp: unknown, ctx: unknown) => unknown",
305
+ " /** Number of automatic retries on failure. Set to 0 or false to disable. Default: 0 (disabled) */",
306
+ " retry?: number | false",
307
+ " /** Base delay in milliseconds between retries (uses exponential backoff). Default: 1000 */",
308
+ " retryDelay?: number",
309
+ " /** Request timeout in milliseconds. Default: 0 (disabled). Set to e.g. 30000 for 30 seconds. */",
310
+ " timeout?: number",
311
+ " /** Additional options to pass to useAsyncData */",
285
312
  " [key: string]: unknown",
286
313
  "}",
287
314
  "",
@@ -473,29 +500,31 @@ Check your wpNuxt.wordpressUrl configuration in nuxt.config.ts`
473
500
  );
474
501
  }
475
502
  }
476
- function patchWPGraphQLSchema(schemaPath) {
477
- let schema = readFileSync(schemaPath, "utf-8");
478
- const problematicInterfaces = [
479
- "Connection",
480
- "Edge",
481
- "OneToOneConnection"
482
- ];
483
- problematicInterfaces.push("NodeWithEditorBlocks");
484
- for (const iface of problematicInterfaces) {
485
- schema = schema.replace(
486
- new RegExp(`implements\\s+${iface}\\s*\\{`, "g"),
487
- "{"
488
- );
489
- schema = schema.replace(
490
- new RegExp(`implements\\s+${iface}\\s+&\\s+`, "g"),
491
- "implements "
492
- );
493
- schema = schema.replace(
494
- new RegExp(`\\s*&\\s*${iface}(?=\\s*[&{])`, "g"),
495
- ""
503
+ const PROBLEMATIC_INTERFACES = /* @__PURE__ */ new Set([
504
+ "Connection",
505
+ "Edge",
506
+ "OneToOneConnection",
507
+ "NodeWithEditorBlocks"
508
+ ]);
509
+ function patchSchemaText(schemaText) {
510
+ const ast = parse(schemaText);
511
+ function filterInterfaces(node) {
512
+ if (!node.interfaces?.length) return void 0;
513
+ const filtered = node.interfaces.filter(
514
+ (iface) => !PROBLEMATIC_INTERFACES.has(iface.name.value)
496
515
  );
516
+ if (filtered.length === node.interfaces.length) return void 0;
517
+ return { ...node, interfaces: filtered };
497
518
  }
498
- writeFileSync(schemaPath, schema);
519
+ const patched = visit(ast, {
520
+ ObjectTypeDefinition: filterInterfaces,
521
+ InterfaceTypeDefinition: filterInterfaces
522
+ });
523
+ return print(patched);
524
+ }
525
+ function patchWPGraphQLSchema(schemaPath) {
526
+ const schema = readFileSync(schemaPath, "utf-8");
527
+ writeFileSync(schemaPath, patchSchemaText(schema));
499
528
  }
500
529
 
501
530
  async function runInstall(nuxt) {
@@ -548,71 +577,31 @@ WPNUXT_WORDPRESS_URL=https://your-wordpress-site.com
548
577
  # Optional: Enable debug mode for verbose logging
549
578
  # WPNUXT_DEBUG=true
550
579
  `;
551
- function isInteractiveEnvironment() {
552
- return !(process.env.CI === "true" || process.env.CI === "1" || process.env.VITEST === "true" || process.env.TEST === "true" || process.env.NODE_ENV === "test");
553
- }
554
580
  async function checkExistingEnvConfig(nuxt, envPath) {
555
581
  const nuxtConfig = nuxt.options;
556
582
  if (nuxtConfig.wpNuxt?.wordpressUrl) {
557
- return { hasUrl: true, source: "nuxt.config.ts", envContent: "" };
583
+ return { hasUrl: true, source: "nuxt.config.ts" };
558
584
  }
559
585
  if (process.env.WPNUXT_WORDPRESS_URL) {
560
- return { hasUrl: true, source: "WPNUXT_WORDPRESS_URL env var", envContent: "" };
586
+ return { hasUrl: true, source: "WPNUXT_WORDPRESS_URL env var" };
561
587
  }
562
588
  if (existsSync(envPath)) {
563
589
  const envContent = await readFile(envPath, "utf-8");
564
590
  if (/^WPNUXT_WORDPRESS_URL\s*=\s*.+/m.test(envContent)) {
565
- return { hasUrl: true, source: ".env file", envContent };
591
+ return { hasUrl: true, source: ".env file" };
566
592
  }
567
- return { hasUrl: false, envContent };
593
+ return { hasUrl: false };
568
594
  }
569
- return { hasUrl: false, envContent: "" };
595
+ return { hasUrl: false };
570
596
  }
571
597
  async function setupEnvFiles(nuxt, logger) {
572
598
  const envPath = join(nuxt.options.rootDir, ".env");
573
599
  const envExamplePath = join(nuxt.options.rootDir, ".env.example");
574
600
  try {
575
601
  const existingConfig = await checkExistingEnvConfig(nuxt, envPath);
576
- let envContent = existingConfig.envContent;
577
- let urlConfigured = false;
578
- if (existingConfig.hasUrl) {
602
+ const urlConfigured = existingConfig.hasUrl;
603
+ if (urlConfigured) {
579
604
  logger.debug(`WordPress URL already configured in ${existingConfig.source}`);
580
- urlConfigured = true;
581
- } else if (isInteractiveEnvironment()) {
582
- consola.box({
583
- title: "WPNuxt Setup",
584
- message: "Configure your WordPress connection"
585
- });
586
- const wordpressUrl = await consola.prompt(
587
- "What is your WordPress site URL?",
588
- {
589
- type: "text",
590
- placeholder: "https://your-wordpress-site.com",
591
- initial: ""
592
- }
593
- );
594
- if (wordpressUrl && typeof wordpressUrl === "string" && wordpressUrl.trim()) {
595
- const validation = validateWordPressUrl(wordpressUrl);
596
- if (!validation.valid) {
597
- logger.warn(`Invalid URL: ${validation.error}`);
598
- logger.info("Skipped WordPress URL configuration. Add WPNUXT_WORDPRESS_URL to your .env file later.");
599
- } else {
600
- const envLine = `WPNUXT_WORDPRESS_URL=${validation.normalizedUrl}
601
- `;
602
- if (envContent) {
603
- envContent = envContent.trimEnd() + "\n\n" + envLine;
604
- } else {
605
- envContent = envLine;
606
- }
607
- await atomicWriteFile(envPath, envContent);
608
- logger.success(`WordPress URL saved to .env: ${validation.normalizedUrl}`);
609
- urlConfigured = true;
610
- }
611
- } else {
612
- logger.info("Skipped WordPress URL configuration. Add WPNUXT_WORDPRESS_URL to your .env file later.");
613
- }
614
- } else {
615
- logger.debug("Non-interactive environment detected, skipping WordPress URL prompt");
616
605
  }
617
606
  let exampleContent = "";
618
607
  let exampleUpdated = false;
@@ -714,65 +703,23 @@ async function setupGitignore(nuxt, logger) {
714
703
  return { name: "Gitignore", success: false, message };
715
704
  }
716
705
  }
717
- const QUERIES_README = `# Custom GraphQL Queries
718
-
719
- Place your custom \`.gql\` or \`.graphql\` files here to extend or override the default WPNuxt queries.
720
-
721
- ## How it works
722
-
723
- 1. Files here are merged with WPNuxt's default queries during build
724
- 2. If a file has the same name as a default query, yours will override it
725
- 3. New files will generate new composables automatically
726
-
727
- ## Example
728
-
729
- Create a file \`CustomPosts.gql\`:
730
-
731
- \`\`\`graphql
732
- query CustomPosts($first: Int = 10) {
733
- posts(first: $first) {
734
- nodes {
735
- id
736
- title
737
- date
738
- # Add your custom fields here
739
- }
740
- }
741
- }
742
- \`\`\`
743
-
744
- This generates \`useCustomPosts()\` and \`useAsyncCustomPosts()\` composables.
745
-
746
- ## Available Fragments
747
-
748
- You can use these fragments from WPNuxt's defaults:
749
- - \`...Post\` - Standard post fields
750
- - \`...Page\` - Standard page fields
751
- - \`...ContentNode\` - Common content fields
752
- - \`...FeaturedImage\` - Featured image with sizes
753
-
754
- ## Documentation
755
-
756
- See https://wpnuxt.com/guide/custom-queries for more details.
757
- `;
758
706
  async function setupQueriesFolder(nuxt, logger) {
759
- const queriesPath = join(nuxt.options.rootDir, "extend", "queries");
760
- const readmePath = join(queriesPath, "README.md");
707
+ const queriesPath = join(nuxt.options.srcDir || nuxt.options.rootDir, "extend", "queries");
708
+ const displayPath = relative(nuxt.options.rootDir, queriesPath) || "extend/queries";
761
709
  try {
762
- if (existsSync(readmePath)) {
763
- logger.debug("extend/queries/ folder already exists");
710
+ if (existsSync(queriesPath)) {
711
+ logger.debug(`${displayPath}/ folder already exists`);
764
712
  return { name: "Queries folder", success: true, skipped: true };
765
713
  }
766
714
  await mkdir(queriesPath, { recursive: true });
767
- await atomicWriteFile(readmePath, QUERIES_README);
768
715
  return {
769
716
  name: "Queries folder",
770
717
  success: true,
771
- message: "Created extend/queries/ for custom GraphQL queries"
718
+ message: `Created ${displayPath}/ for custom GraphQL queries`
772
719
  };
773
720
  } catch (error) {
774
721
  const message = error instanceof Error ? error.message : String(error);
775
- logger.warn(`Failed to setup extend/queries/ folder: ${message}`);
722
+ logger.warn(`Failed to setup ${displayPath}/ folder: ${message}`);
776
723
  return { name: "Queries folder", success: false, message };
777
724
  }
778
725
  }
@@ -783,7 +730,7 @@ const module$1 = defineNuxtModule({
783
730
  version,
784
731
  configKey: "wpNuxt",
785
732
  compatibility: {
786
- nuxt: ">=3.0.0"
733
+ nuxt: ">=3.17.0"
787
734
  }
788
735
  },
789
736
  defaults: {
@@ -882,29 +829,26 @@ const module$1 = defineNuxtModule({
882
829
  };
883
830
  logger.debug(`Configured WordPress uploads proxy: /wp-content/uploads/** \u2192 ${wpNuxtConfig.wordpressUrl}/wp-content/uploads/**`);
884
831
  }
885
- nuxt.hook("modules:done", () => {
886
- if (hasNuxtModule("@nuxt/image")) {
887
- const imageConfig = nuxt.options.image || {};
888
- const provider = process.env.NUXT_IMAGE_PROVIDER || imageConfig.provider || "ipx";
889
- if (provider === "ipx") {
890
- const wpHost = new URL(wpNuxtConfig.wordpressUrl).host;
891
- const domains = imageConfig.domains || [];
892
- if (!domains.includes(wpHost)) {
893
- domains.push(wpHost);
894
- }
895
- imageConfig.domains = domains;
896
- const alias = imageConfig.alias || {};
897
- alias["/wp-content"] = `${wpNuxtConfig.wordpressUrl}/wp-content`;
898
- imageConfig.alias = alias;
899
- nuxt.options.image = imageConfig;
900
- logger.debug(`Configured IPX for WordPress: alias /wp-content \u2192 ${wpNuxtConfig.wordpressUrl}/wp-content, domain '${wpHost}' added`);
832
+ {
833
+ const imageConfig = nuxt.options.image || {};
834
+ const provider = process.env.NUXT_IMAGE_PROVIDER || imageConfig.provider || "ipx";
835
+ if (provider === "ipx") {
836
+ const wpHost = new URL(wpNuxtConfig.wordpressUrl).host;
837
+ const domains = imageConfig.domains || [];
838
+ if (!domains.includes(wpHost)) {
839
+ domains.push(wpHost);
901
840
  }
841
+ imageConfig.domains = domains;
842
+ const alias = imageConfig.alias || {};
843
+ alias["/wp-content"] = `${wpNuxtConfig.wordpressUrl}/wp-content`;
844
+ imageConfig.alias = alias;
845
+ nuxt.options.image = imageConfig;
846
+ logger.debug(`Configured IPX for WordPress: alias /wp-content \u2192 ${wpNuxtConfig.wordpressUrl}/wp-content, domain '${wpHost}' added`);
902
847
  }
903
- });
848
+ }
904
849
  configureVercelSettings(nuxt, logger);
905
850
  addImports([
906
851
  { name: "useWPContent", as: "useWPContent", from: resolver.resolve("./runtime/composables/useWPContent") },
907
- { name: "useAsyncWPContent", as: "useAsyncWPContent", from: resolver.resolve("./runtime/composables/useWPContent") },
908
852
  { name: "getRelativeImagePath", as: "getRelativeImagePath", from: resolver.resolve("./runtime/util/images") },
909
853
  { name: "isInternalLink", as: "isInternalLink", from: resolver.resolve("./runtime/util/links") },
910
854
  { name: "toRelativePath", as: "toRelativePath", from: resolver.resolve("./runtime/util/links") },
@@ -971,38 +915,13 @@ async function loadConfig(options, nuxt) {
971
915
  if (nuxt.options._prepare) {
972
916
  return null;
973
917
  }
974
- if (nuxt.options.dev && process.stdout.isTTY) {
975
- const wordpressUrl = await consola.prompt(
976
- "Enter your WordPress site URL (must have WPGraphQL installed):",
977
- { type: "text", placeholder: "https://your-wordpress-site.com" }
978
- );
979
- if (wordpressUrl && typeof wordpressUrl === "string" && wordpressUrl.trim()) {
980
- const validation = validateWordPressUrl(wordpressUrl);
981
- if (validation.valid && validation.normalizedUrl) {
982
- config.wordpressUrl = validation.normalizedUrl;
983
- const envPath = join(nuxt.options.rootDir, ".env");
984
- const envLine = `WPNUXT_WORDPRESS_URL=${validation.normalizedUrl}
985
- `;
986
- if (existsSync(envPath)) {
987
- const existing = await readFile(envPath, "utf-8");
988
- await atomicWriteFile(envPath, existing.trimEnd() + "\n" + envLine);
989
- } else {
990
- await atomicWriteFile(envPath, envLine);
991
- }
992
- consola.success(`WordPress URL saved to .env: ${validation.normalizedUrl}`);
993
- } else {
994
- throw createModuleError("core", `Invalid WordPress URL: ${validation.error}`);
995
- }
996
- } else {
997
- throw createModuleError("core", "WordPress URL is required. Set it in nuxt.config.ts or via WPNUXT_WORDPRESS_URL environment variable.");
998
- }
999
- } else {
1000
- throw createModuleError("core", "WordPress URL is required. Set it in nuxt.config.ts or via WPNUXT_WORDPRESS_URL environment variable.");
1001
- }
918
+ throw createModuleError("core", "WordPress URL is required. Set it in nuxt.config.ts or via WPNUXT_WORDPRESS_URL environment variable.");
1002
919
  }
1003
- if (config.wordpressUrl.endsWith("/")) {
1004
- throw createModuleError("core", `WordPress URL should not have a trailing slash: ${config.wordpressUrl}`);
920
+ const validation = validateWordPressUrl(config.wordpressUrl);
921
+ if (!validation.valid) {
922
+ throw createModuleError("core", `Invalid WordPress URL: ${validation.error}`);
1005
923
  }
924
+ config.wordpressUrl = validation.normalizedUrl;
1006
925
  nuxt.options.runtimeConfig.public.wordpressUrl = config.wordpressUrl;
1007
926
  nuxt.options.runtimeConfig.public.wpNuxt = {
1008
927
  wordpressUrl: config.wordpressUrl,
@@ -1018,53 +937,7 @@ async function loadConfig(options, nuxt) {
1018
937
  };
1019
938
  return config;
1020
939
  }
1021
- const SERVER_OPTIONS_TEMPLATE = `import { defineGraphqlServerOptions } from '@wpnuxt/core/server-options'
1022
- import { getHeader, getCookie } from 'h3'
1023
- import { useRuntimeConfig } from '#imports'
1024
-
1025
- /**
1026
- * WPNuxt default server options for nuxt-graphql-middleware.
1027
- *
1028
- * This enables:
1029
- * - Cookie forwarding for WordPress preview mode
1030
- * - Authorization header forwarding for authenticated requests
1031
- * - Auth token from cookie for @wpnuxt/auth
1032
- * - Consistent error logging
1033
- *
1034
- * Users can customize by creating their own server/graphqlMiddleware.serverOptions.ts
1035
- */
1036
- export default defineGraphqlServerOptions({
1037
- async serverFetchOptions(event, _operation, _operationName, _context) {
1038
- // Get auth token from Authorization header or from cookie
1039
- let authorization = getHeader(event, 'authorization') || ''
1040
-
1041
- // If no Authorization header, check for auth token in cookie (@wpnuxt/auth)
1042
- if (!authorization) {
1043
- const config = useRuntimeConfig().public.wpNuxtAuth as { cookieName?: string } | undefined
1044
- const cookieName = config?.cookieName || 'wpnuxt-auth-token'
1045
- const authToken = getCookie(event, cookieName)
1046
- if (authToken) {
1047
- authorization = \`Bearer \${authToken}\`
1048
- }
1049
- }
1050
-
1051
- return {
1052
- headers: {
1053
- // Forward WordPress auth cookies for previews
1054
- Cookie: getHeader(event, 'cookie') || '',
1055
- // Forward authorization header or token from cookie
1056
- Authorization: authorization
1057
- }
1058
- }
1059
- },
1060
-
1061
- async onServerError(event, error, _operation, operationName) {
1062
- const url = event.node.req.url || 'unknown'
1063
- console.error(\`[WPNuxt] GraphQL error in \${operationName} (\${url}):\`, error.message)
1064
- }
1065
- })
1066
- `;
1067
- async function setupServerOptions(nuxt, _resolver, logger) {
940
+ async function setupServerOptions(nuxt, resolver, logger) {
1068
941
  const serverDir = nuxt.options.serverDir;
1069
942
  const targetPath = join(serverDir, "graphqlMiddleware.serverOptions.ts");
1070
943
  if (existsSync(targetPath)) {
@@ -1074,39 +947,14 @@ async function setupServerOptions(nuxt, _resolver, logger) {
1074
947
  if (!existsSync(serverDir)) {
1075
948
  await mkdir(serverDir, { recursive: true });
1076
949
  }
1077
- await writeFile(targetPath, SERVER_OPTIONS_TEMPLATE);
950
+ const template = readFileSync(
951
+ resolver.resolve("./runtime/server/graphqlMiddleware.serverOptions.ts"),
952
+ "utf-8"
953
+ );
954
+ await writeFile(targetPath, template);
1078
955
  logger.debug("Created graphqlMiddleware.serverOptions.ts with WPNuxt defaults (cookie/auth forwarding)");
1079
956
  }
1080
- const CLIENT_OPTIONS_TEMPLATE = `import { defineGraphqlClientOptions } from '@wpnuxt/core/client-options'
1081
- import { useRoute } from '#imports'
1082
-
1083
- /**
1084
- * WPNuxt default client options for nuxt-graphql-middleware.
1085
- *
1086
- * This enables passing client context to the server for:
1087
- * - Preview mode (passes preview flag and token from URL query params)
1088
- *
1089
- * The context is available in serverFetchOptions via context.client
1090
- * All values must be strings (nuxt-graphql-middleware requirement)
1091
- *
1092
- * Users can customize by creating their own app/graphqlMiddleware.clientOptions.ts
1093
- */
1094
- export default defineGraphqlClientOptions<{
1095
- preview?: string
1096
- previewToken?: string
1097
- }>({
1098
- buildClientContext() {
1099
- const route = useRoute()
1100
-
1101
- return {
1102
- // Context values must be strings - use 'true'/'false' instead of boolean
1103
- preview: route.query.preview === 'true' ? 'true' : undefined,
1104
- previewToken: route.query.token as string | undefined
1105
- }
1106
- }
1107
- })
1108
- `;
1109
- async function setupClientOptions(nuxt, _resolver, logger) {
957
+ async function setupClientOptions(nuxt, resolver, logger) {
1110
958
  const appDir = nuxt.options.dir.app;
1111
959
  const targetPath = join(appDir, "graphqlMiddleware.clientOptions.ts");
1112
960
  if (existsSync(targetPath)) {
@@ -1116,11 +964,15 @@ async function setupClientOptions(nuxt, _resolver, logger) {
1116
964
  if (!existsSync(appDir)) {
1117
965
  await mkdir(appDir, { recursive: true });
1118
966
  }
1119
- await writeFile(targetPath, CLIENT_OPTIONS_TEMPLATE);
967
+ const template = readFileSync(
968
+ resolver.resolve("./runtime/app/graphqlMiddleware.clientOptions.ts"),
969
+ "utf-8"
970
+ );
971
+ await writeFile(targetPath, template);
1120
972
  logger.debug("Created graphqlMiddleware.clientOptions.ts with WPNuxt defaults (preview mode support)");
1121
973
  }
1122
974
  function configureTrailingSlash(nuxt, logger) {
1123
- const handlerPath = join(nuxt.options.buildDir, "wpnuxt", "trailing-slash-handler.ts");
975
+ const handlerPath = join(nuxt.options.buildDir, "wpnuxt", "trailing-slash-handler.ts").replace(/\\/g, "/");
1124
976
  const handlerCode = `import { defineEventHandler, sendRedirect, getRequestURL } from 'h3'
1125
977
 
1126
978
  export default defineEventHandler((event) => {
@@ -1,4 +1,4 @@
1
- import { defineGraphqlClientOptions } from "nuxt-graphql-middleware/client-options";
1
+ import { defineGraphqlClientOptions } from "@wpnuxt/core/client-options";
2
2
  import { useRoute } from "#imports";
3
3
  export default defineGraphqlClientOptions({
4
4
  buildClientContext() {
@@ -1,6 +1,6 @@
1
1
  import { useWPContent } from "./useWPContent.js";
2
- export async function usePrevNextPost(currentSlug) {
3
- const { data, execute } = useWPContent("Posts", ["posts", "nodes"], false, { limit: 100 });
2
+ export async function usePrevNextPost(currentSlug, limit = 1e3) {
3
+ const { data, execute } = useWPContent("Posts", ["posts", "nodes"], false, { limit });
4
4
  await execute();
5
5
  const allPosts = data.value || [];
6
6
  if (!allPosts.length) {
@@ -1,29 +1,35 @@
1
1
  import { defineNuxtPlugin } from "#imports";
2
2
  export default defineNuxtPlugin((nuxtApp) => {
3
- let sanitize;
4
3
  if (import.meta.server) {
5
- sanitize = (html) => html;
6
- } else {
7
- let purify = null;
8
- sanitize = (html) => {
9
- if (purify) {
10
- return purify.sanitize(html);
4
+ nuxtApp.vueApp.directive("sanitize-html", {
5
+ getSSRProps(binding) {
6
+ return { innerHTML: binding.value };
11
7
  }
12
- return html;
13
- };
14
- import("dompurify").then((DOMPurify) => {
15
- purify = DOMPurify.default(window);
16
8
  });
9
+ return;
10
+ }
11
+ let purify = null;
12
+ const purifyReady = import("dompurify").then((DOMPurify) => {
13
+ purify = DOMPurify.default(window);
14
+ });
15
+ function setSanitizedHtml(el, html) {
16
+ if (purify) {
17
+ el.innerHTML = purify.sanitize(html);
18
+ } else {
19
+ purifyReady.then(() => {
20
+ el.innerHTML = purify.sanitize(html);
21
+ });
22
+ }
17
23
  }
18
24
  nuxtApp.vueApp.directive("sanitize-html", {
19
25
  created(el, binding) {
20
- el.innerHTML = sanitize(binding.value);
26
+ setSanitizedHtml(el, binding.value);
21
27
  },
22
28
  updated(el, binding) {
23
- el.innerHTML = sanitize(binding.value);
29
+ setSanitizedHtml(el, binding.value);
24
30
  },
25
31
  getSSRProps(binding) {
26
- return { innerHTML: sanitize(binding.value) };
32
+ return { innerHTML: binding.value };
27
33
  }
28
34
  });
29
35
  });
@@ -10,8 +10,8 @@ query PageByUri($uri: ID!) {
10
10
  ...Page
11
11
  }
12
12
  }
13
- query PageById($id: ID!) {
14
- page(id: $id, idType: DATABASE_ID, asPreview: true) {
13
+ query PageById($id: ID!, $asPreview: Boolean = false) {
14
+ page(id: $id, idType: DATABASE_ID, asPreview: $asPreview) {
15
15
  ...Page
16
16
  }
17
17
  }
@@ -29,7 +29,21 @@ fragment MediaItem on MediaItem {
29
29
  isTermNode
30
30
  # lastEditedBy
31
31
  link
32
- # mediaDetails
32
+ mediaDetails {
33
+ file
34
+ filePath
35
+ height
36
+ width
37
+ sizes {
38
+ file
39
+ fileSize
40
+ height
41
+ mimeType
42
+ name
43
+ sourceUrl
44
+ width
45
+ }
46
+ }
33
47
  mediaItemId
34
48
  mediaItemUrl
35
49
  mediaType
@@ -1,13 +1,23 @@
1
- import { defineGraphqlServerOptions } from "nuxt-graphql-middleware/server-options";
2
- import { getHeader } from "h3";
1
+ import { defineGraphqlServerOptions } from "@wpnuxt/core/server-options";
2
+ import { getHeader, getCookie } from "h3";
3
+ import { useRuntimeConfig } from "#imports";
3
4
  export default defineGraphqlServerOptions({
4
5
  async serverFetchOptions(event, _operation, _operationName, _context) {
6
+ let authorization = getHeader(event, "authorization") || "";
7
+ if (!authorization) {
8
+ const config = useRuntimeConfig().public.wpNuxtAuth;
9
+ const cookieName = config?.cookieName || "wpnuxt-auth-token";
10
+ const authToken = getCookie(event, cookieName);
11
+ if (authToken) {
12
+ authorization = `Bearer ${authToken}`;
13
+ }
14
+ }
5
15
  return {
6
16
  headers: {
7
17
  // Forward WordPress auth cookies for previews
8
18
  Cookie: getHeader(event, "cookie") || "",
9
- // Forward authorization header if present
10
- Authorization: getHeader(event, "authorization") || ""
19
+ // Forward authorization header or token from cookie
20
+ Authorization: authorization
11
21
  }
12
22
  };
13
23
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wpnuxt/core",
3
- "version": "2.0.0-beta.2",
3
+ "version": "2.0.0-beta.4",
4
4
  "description": "Nuxt module for WordPress integration via GraphQL (WPGraphQL)",
5
5
  "keywords": [
6
6
  "nuxt",
@@ -55,7 +55,7 @@
55
55
  "scule": "^1.3.0"
56
56
  },
57
57
  "devDependencies": {
58
- "@nuxt/devtools": "^3.2.0",
58
+ "@nuxt/devtools": "^3.2.1",
59
59
  "@nuxt/module-builder": "^1.0.2",
60
60
  "@nuxt/schema": "4.3.1",
61
61
  "@nuxt/test-utils": "^4.0.0",
@@ -65,7 +65,7 @@
65
65
  "vue-tsc": "^3.2.3"
66
66
  },
67
67
  "peerDependencies": {
68
- "nuxt": "^4.0.0"
68
+ "nuxt": ">=3.17.0"
69
69
  },
70
70
  "scripts": {
71
71
  "build": "nuxt-module-build build",
@@ -73,7 +73,6 @@
73
73
  "lint": "eslint src",
74
74
  "test": "vitest run",
75
75
  "test:watch": "vitest watch",
76
- "typecheck": "vue-tsc --noEmit",
77
- "clean": "rm -rf dist .nuxt node_modules"
76
+ "typecheck": "vue-tsc --noEmit"
78
77
  }
79
78
  }