@wpnuxt/core 2.0.0-alpha.10 → 2.0.0-alpha.11

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/LICENSE ADDED
@@ -0,0 +1,9 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2024-present - WPNuxt Team
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/dist/module.d.mts CHANGED
@@ -45,6 +45,41 @@ interface WPNuxtConfig {
45
45
  * @default true
46
46
  */
47
47
  downloadSchema: boolean;
48
+ /**
49
+ * Bearer token for authenticated schema introspection at build time.
50
+ *
51
+ * Required when your WordPress GraphQL endpoint has public introspection disabled.
52
+ * The token is sent as an `Authorization: Bearer <token>` header during:
53
+ * - Endpoint validation (introspection query)
54
+ * - Schema download (get-graphql-schema)
55
+ *
56
+ * Can also be set via `WPNUXT_SCHEMA_AUTH_TOKEN` environment variable.
57
+ *
58
+ * This token is only used at build time and is NOT included in client bundles.
59
+ */
60
+ schemaAuthToken?: string;
61
+ /**
62
+ * Whether to replace internal WordPress links with client-side navigation (NuxtLink).
63
+ *
64
+ * When enabled, clicks on `<a>` tags pointing to the WordPress domain inside
65
+ * `<WPContent>` are intercepted and handled via `navigateTo()`.
66
+ *
67
+ * @default true
68
+ */
69
+ replaceLinks?: boolean;
70
+ /**
71
+ * Whether to convert featured image `sourceUrl` values to relative paths.
72
+ *
73
+ * When enabled, a `relativePath` property is added to `featuredImage.node`
74
+ * by stripping the WordPress domain from `sourceUrl`.
75
+ *
76
+ * Set to `true` when using relative image paths with Nuxt Image or a proxy.
77
+ * Leave `false` (default) for SSG or external image providers (Vercel, Cloudflare)
78
+ * that need full URLs.
79
+ *
80
+ * @default false
81
+ */
82
+ imageRelativePaths?: boolean;
48
83
  /**
49
84
  * Whether to enable debug mode
50
85
  *
package/dist/module.d.ts CHANGED
@@ -45,6 +45,41 @@ interface WPNuxtConfig {
45
45
  * @default true
46
46
  */
47
47
  downloadSchema: boolean;
48
+ /**
49
+ * Bearer token for authenticated schema introspection at build time.
50
+ *
51
+ * Required when your WordPress GraphQL endpoint has public introspection disabled.
52
+ * The token is sent as an `Authorization: Bearer <token>` header during:
53
+ * - Endpoint validation (introspection query)
54
+ * - Schema download (get-graphql-schema)
55
+ *
56
+ * Can also be set via `WPNUXT_SCHEMA_AUTH_TOKEN` environment variable.
57
+ *
58
+ * This token is only used at build time and is NOT included in client bundles.
59
+ */
60
+ schemaAuthToken?: string;
61
+ /**
62
+ * Whether to replace internal WordPress links with client-side navigation (NuxtLink).
63
+ *
64
+ * When enabled, clicks on `<a>` tags pointing to the WordPress domain inside
65
+ * `<WPContent>` are intercepted and handled via `navigateTo()`.
66
+ *
67
+ * @default true
68
+ */
69
+ replaceLinks?: boolean;
70
+ /**
71
+ * Whether to convert featured image `sourceUrl` values to relative paths.
72
+ *
73
+ * When enabled, a `relativePath` property is added to `featuredImage.node`
74
+ * by stripping the WordPress domain from `sourceUrl`.
75
+ *
76
+ * Set to `true` when using relative image paths with Nuxt Image or a proxy.
77
+ * Leave `false` (default) for SSG or external image providers (Vercel, Cloudflare)
78
+ * that need full URLs.
79
+ *
80
+ * @default false
81
+ */
82
+ imageRelativePaths?: boolean;
48
83
  /**
49
84
  * Whether to enable debug mode
50
85
  *
package/dist/module.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wpnuxt/core",
3
- "version": "2.0.0-alpha.10",
3
+ "version": "2.0.0-alpha.11",
4
4
  "configKey": "wpNuxt",
5
5
  "compatibility": {
6
6
  "nuxt": ">=3.0.0"
package/dist/module.mjs CHANGED
@@ -2,14 +2,14 @@ import { defu } from 'defu';
2
2
  import { promises, cpSync, existsSync, readdirSync, statSync, readFileSync, writeFileSync } from 'node:fs';
3
3
  import { writeFile, rename, readFile, mkdir } from 'node:fs/promises';
4
4
  import { join, relative, dirname } from 'node:path';
5
- import { useLogger, createResolver, resolveFiles, defineNuxtModule, addPlugin, addImports, addComponentsDir, addTemplate, addTypeTemplate, hasNuxtModule, installModule } from '@nuxt/kit';
5
+ import { useLogger, createResolver, resolveFiles, defineNuxtModule, addPlugin, hasNuxtModule, addImports, addComponentsDir, addTemplate, addTypeTemplate, installModule } from '@nuxt/kit';
6
6
  import { upperFirst } from 'scule';
7
7
  import { ref } from 'vue';
8
8
  import { parse, GraphQLError } from 'graphql';
9
9
  import { execSync } from 'node:child_process';
10
10
  import { consola } from 'consola';
11
11
 
12
- const version = "2.0.0-alpha.10";
12
+ const version = "2.0.0-alpha.11";
13
13
 
14
14
  function createModuleError(module, message) {
15
15
  return new Error(formatErrorMessage(module, message));
@@ -201,7 +201,7 @@ async function prepareContext(ctx) {
201
201
  const getFragmentType = (q) => {
202
202
  if (q.fragments?.length) {
203
203
  const fragmentSuffix = q.nodes?.includes("nodes") ? "[]" : "";
204
- return q.fragments.map((f) => `${f}Fragment${fragmentSuffix}`).join(" | ");
204
+ return q.fragments.map((f) => `WithImagePath<${f}Fragment>${fragmentSuffix}`).join(" | ");
205
205
  }
206
206
  if (q.nodes?.length) {
207
207
  let typePath = `${q.name}RootQuery`;
@@ -304,6 +304,11 @@ async function prepareContext(ctx) {
304
304
  "",
305
305
  "type WPMutationResult<T> = GraphqlResponse<T>",
306
306
  "",
307
+ "/** Adds relativePath to featuredImage.node when present (injected at runtime by transformData) */",
308
+ "type WithImagePath<T> = T extends { featuredImage?: unknown }",
309
+ " ? T & { featuredImage?: { node: { relativePath?: string } } }",
310
+ " : T",
311
+ "",
307
312
  "declare module '#wpnuxt' {"
308
313
  ];
309
314
  queries.forEach((f) => {
@@ -350,11 +355,15 @@ async function validateWordPressEndpoint(wordpressUrl, graphqlEndpoint = "/graph
350
355
  try {
351
356
  const controller = new AbortController();
352
357
  const timeout = setTimeout(() => controller.abort(), 1e4);
358
+ const headers = {
359
+ "Content-Type": "application/json"
360
+ };
361
+ if (options.authToken) {
362
+ headers["Authorization"] = `Bearer ${options.authToken}`;
363
+ }
353
364
  const response = await fetch(fullUrl, {
354
365
  method: "POST",
355
- headers: {
356
- "Content-Type": "application/json"
357
- },
366
+ headers,
358
367
  body: JSON.stringify({
359
368
  query: "{ __typename }"
360
369
  }),
@@ -397,7 +406,8 @@ Make sure WPGraphQL plugin is installed and activated on your WordPress site.`
397
406
  }
398
407
  if (options.schemaPath && !existsSync(options.schemaPath)) {
399
408
  try {
400
- execSync(`npx get-graphql-schema "${fullUrl}" > "${options.schemaPath}"`, {
409
+ const authFlag = options.authToken ? ` -h "Authorization=Bearer ${options.authToken}"` : "";
410
+ execSync(`npx get-graphql-schema "${fullUrl}"${authFlag} > "${options.schemaPath}"`, {
401
411
  stdio: "pipe",
402
412
  timeout: 6e4
403
413
  // 60 second timeout
@@ -785,6 +795,8 @@ const module$1 = defineNuxtModule({
785
795
  warnOnOverride: true
786
796
  },
787
797
  downloadSchema: true,
798
+ replaceLinks: true,
799
+ imageRelativePaths: false,
788
800
  debug: false,
789
801
  cache: {
790
802
  enabled: true,
@@ -814,7 +826,7 @@ const module$1 = defineNuxtModule({
814
826
  await validateWordPressEndpoint(
815
827
  wpNuxtConfig.wordpressUrl,
816
828
  wpNuxtConfig.graphqlEndpoint,
817
- { schemaPath }
829
+ { schemaPath, authToken: wpNuxtConfig.schemaAuthToken }
818
830
  );
819
831
  logger.debug("Schema downloaded successfully");
820
832
  } else {
@@ -822,7 +834,8 @@ const module$1 = defineNuxtModule({
822
834
  try {
823
835
  await validateWordPressEndpoint(
824
836
  wpNuxtConfig.wordpressUrl,
825
- wpNuxtConfig.graphqlEndpoint
837
+ wpNuxtConfig.graphqlEndpoint,
838
+ { authToken: wpNuxtConfig.schemaAuthToken }
826
839
  );
827
840
  logger.debug("WordPress endpoint validation passed");
828
841
  } catch (error) {
@@ -854,11 +867,39 @@ const module$1 = defineNuxtModule({
854
867
  };
855
868
  logger.debug(`Server-side caching enabled for GraphQL requests (maxAge: ${maxAge}s, SWR: ${wpNuxtConfig.cache?.swr !== false})`);
856
869
  }
870
+ {
871
+ const nitroOptions = nuxt.options;
872
+ nitroOptions.nitro = nitroOptions.nitro || {};
873
+ nitroOptions.nitro.routeRules = nitroOptions.nitro.routeRules || {};
874
+ nitroOptions.nitro.routeRules["/wp-content/uploads/**"] = {
875
+ proxy: `${wpNuxtConfig.wordpressUrl}/wp-content/uploads/**`
876
+ };
877
+ logger.debug(`Configured WordPress uploads proxy: /wp-content/uploads/** \u2192 ${wpNuxtConfig.wordpressUrl}/wp-content/uploads/**`);
878
+ }
879
+ if (hasNuxtModule("@nuxt/image")) {
880
+ const imageConfig = nuxt.options.image || {};
881
+ const provider = process.env.NUXT_IMAGE_PROVIDER || imageConfig.provider || "ipx";
882
+ if (provider === "ipx") {
883
+ const wpHost = new URL(wpNuxtConfig.wordpressUrl).host;
884
+ const domains = imageConfig.domains || [];
885
+ if (!domains.includes(wpHost)) {
886
+ domains.push(wpHost);
887
+ }
888
+ imageConfig.domains = domains;
889
+ const alias = imageConfig.alias || {};
890
+ alias["/wp-content"] = `${wpNuxtConfig.wordpressUrl}/wp-content`;
891
+ imageConfig.alias = alias;
892
+ nuxt.options.image = imageConfig;
893
+ logger.debug(`Configured IPX for WordPress: alias /wp-content \u2192 ${wpNuxtConfig.wordpressUrl}/wp-content, domain '${wpHost}' added`);
894
+ }
895
+ }
857
896
  configureVercelSettings(nuxt, logger);
858
897
  addImports([
859
898
  { name: "useWPContent", as: "useWPContent", from: resolver.resolve("./runtime/composables/useWPContent") },
860
899
  { name: "useAsyncWPContent", as: "useAsyncWPContent", from: resolver.resolve("./runtime/composables/useWPContent") },
861
900
  { name: "getRelativeImagePath", as: "getRelativeImagePath", from: resolver.resolve("./runtime/util/images") },
901
+ { name: "isInternalLink", as: "isInternalLink", from: resolver.resolve("./runtime/util/links") },
902
+ { name: "toRelativePath", as: "toRelativePath", from: resolver.resolve("./runtime/util/links") },
862
903
  { name: "usePrevNextPost", as: "usePrevNextPost", from: resolver.resolve("./runtime/composables/usePrevNextPost") }
863
904
  // Note: useGraphqlMutation is auto-imported via nuxt-graphql-middleware with includeComposables: true
864
905
  ]);
@@ -908,6 +949,7 @@ function loadConfig(options, nuxt) {
908
949
  const config = defu({
909
950
  wordpressUrl: process.env.WPNUXT_WORDPRESS_URL,
910
951
  graphqlEndpoint: process.env.WPNUXT_GRAPHQL_ENDPOINT,
952
+ schemaAuthToken: process.env.WPNUXT_SCHEMA_AUTH_TOKEN,
911
953
  // Only override downloadSchema if env var is explicitly set
912
954
  downloadSchema: process.env.WPNUXT_DOWNLOAD_SCHEMA !== void 0 ? process.env.WPNUXT_DOWNLOAD_SCHEMA === "true" : void 0,
913
955
  debug: process.env.WPNUXT_DEBUG ? process.env.WPNUXT_DEBUG === "true" : void 0
@@ -919,6 +961,8 @@ function loadConfig(options, nuxt) {
919
961
  nuxt.options.runtimeConfig.public.wpNuxt = {
920
962
  wordpressUrl: config.wordpressUrl,
921
963
  graphqlEndpoint: config.graphqlEndpoint,
964
+ replaceLinks: config.replaceLinks ?? true,
965
+ imageRelativePaths: config.imageRelativePaths ?? false,
922
966
  cache: {
923
967
  enabled: config.cache?.enabled ?? true,
924
968
  maxAge: config.cache?.maxAge ?? 300,
@@ -1125,6 +1169,14 @@ async function registerModules(nuxt, resolver, wpNuxtConfig, mergedQueriesFolder
1125
1169
  scalars: {
1126
1170
  DateTime: "string",
1127
1171
  ID: "string"
1172
+ },
1173
+ // Pass auth headers for schema download when token is configured
1174
+ ...wpNuxtConfig.schemaAuthToken && {
1175
+ urlSchemaOptions: {
1176
+ headers: {
1177
+ Authorization: `Bearer ${wpNuxtConfig.schemaAuthToken}`
1178
+ }
1179
+ }
1128
1180
  }
1129
1181
  },
1130
1182
  experimental: {
File without changes
@@ -0,0 +1,60 @@
1
+ <script setup>
2
+ import { isInternalLink, toRelativePath } from "../util/links";
3
+ import { ref, resolveComponent, onMounted, onBeforeUnmount, useRuntimeConfig, navigateTo } from "#imports";
4
+ const props = defineProps({
5
+ node: { type: Object, required: false, default: void 0 },
6
+ replaceLinks: { type: Boolean, required: false, default: void 0 }
7
+ });
8
+ const containerRef = ref(null);
9
+ const blockRenderer = resolveComponent("BlockRenderer");
10
+ const hasBlockRenderer = typeof blockRenderer !== "string";
11
+ function shouldReplaceLinks() {
12
+ if (props.replaceLinks !== void 0) {
13
+ return props.replaceLinks;
14
+ }
15
+ const config = useRuntimeConfig();
16
+ return config.public.wpNuxt?.replaceLinks !== false;
17
+ }
18
+ function onClick(event) {
19
+ if (!shouldReplaceLinks()) return;
20
+ if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
21
+ const anchor = event.target?.closest?.("a");
22
+ if (!anchor) return;
23
+ const href = anchor.getAttribute("href");
24
+ if (!href) return;
25
+ if (anchor.getAttribute("target") === "_blank") return;
26
+ if (anchor.hasAttribute("download")) return;
27
+ if (anchor.getAttribute("rel")?.includes("external")) return;
28
+ const trimmed = href.trim();
29
+ if (/^(?:mailto|tel|javascript|ftp):/i.test(trimmed)) return;
30
+ const config = useRuntimeConfig();
31
+ const wordpressUrl = config.public.wpNuxt?.wordpressUrl;
32
+ if (isInternalLink(href, wordpressUrl)) {
33
+ event.preventDefault();
34
+ navigateTo(toRelativePath(href));
35
+ }
36
+ }
37
+ onMounted(() => {
38
+ containerRef.value?.addEventListener("click", onClick);
39
+ });
40
+ onBeforeUnmount(() => {
41
+ containerRef.value?.removeEventListener("click", onClick);
42
+ });
43
+ </script>
44
+
45
+ <template>
46
+ <div ref="containerRef">
47
+ <template v-if="node">
48
+ <component
49
+ :is="blockRenderer"
50
+ v-if="hasBlockRenderer && node.editorBlocks?.length"
51
+ :node="node"
52
+ />
53
+ <div
54
+ v-else-if="node.content"
55
+ v-sanitize-html="node.content"
56
+ />
57
+ </template>
58
+ <slot v-else />
59
+ </div>
60
+ </template>
File without changes
@@ -1,5 +1,5 @@
1
1
  import { transformData, normalizeUriParam } from "../util/content.js";
2
- import { computed, ref, watch as vueWatch, useAsyncGraphqlQuery } from "#imports";
2
+ import { computed, ref, watch as vueWatch, useAsyncGraphqlQuery, useRuntimeConfig } from "#imports";
3
3
  const defaultGetCachedData = (key, app, ctx) => {
4
4
  if (app.isHydrating) {
5
5
  return app.payload.data[key];
@@ -11,6 +11,8 @@ const defaultGetCachedData = (key, app, ctx) => {
11
11
  };
12
12
  const noCacheGetCachedData = () => void 0;
13
13
  export const useWPContent = (queryName, nodes, fixImagePaths, params, options) => {
14
+ const runtimeWpNuxt = useRuntimeConfig().public.wpNuxt;
15
+ const imageRelativePaths = runtimeWpNuxt?.imageRelativePaths ?? fixImagePaths;
14
16
  const {
15
17
  clientCache,
16
18
  getCachedData: userGetCachedData,
@@ -93,7 +95,7 @@ export const useWPContent = (queryName, nodes, fixImagePaths, params, options) =
93
95
  try {
94
96
  const queryResult = data.value && typeof data.value === "object" && data.value !== null && "data" in data.value ? data.value.data : void 0;
95
97
  if (!queryResult) return void 0;
96
- const result = transformData(queryResult, nodes, fixImagePaths);
98
+ const result = transformData(queryResult, nodes, imageRelativePaths);
97
99
  if (import.meta.dev && String(queryName) === "Menu" && !result) {
98
100
  console.warn(
99
101
  `[wpnuxt] Menu not found. This usually means no classic WordPress menu exists with the specified name.
@@ -5,8 +5,8 @@ query Pages($limit: Int = 10) {
5
5
  }
6
6
  }
7
7
  }
8
- query PageByUri($uri: String!) {
9
- nodeByUri(uri: $uri) {
8
+ query PageByUri($uri: ID!) {
9
+ page(id: $uri, idType: URI) {
10
10
  ...Page
11
11
  }
12
12
  }
@@ -5,8 +5,8 @@ query Posts($limit: Int = 10) {
5
5
  }
6
6
  }
7
7
  }
8
- query PostByUri($uri: String!) {
9
- nodeByUri(uri: $uri) {
8
+ query PostByUri($uri: ID!) {
9
+ post(id: $uri, idType: URI) {
10
10
  ...Post
11
11
  }
12
12
  }
@@ -4,12 +4,15 @@
4
4
  * Actual types are generated at runtime in consuming applications.
5
5
  */
6
6
 
7
- import type { Ref, ComputedRef, WatchSource, WatchCallback, WatchOptions } from 'vue'
7
+ import type { Ref, ComputedRef, Component, WatchSource, WatchCallback, WatchOptions } from 'vue'
8
8
  import type { NuxtApp } from 'nuxt/app'
9
9
 
10
- // Stub for #imports - Vue reactivity
10
+ // Stub for #imports - Vue reactivity & lifecycle
11
11
  export function computed<T>(getter: () => T): ComputedRef<T>
12
12
  export function ref<T>(value: T): Ref<T>
13
+ export function resolveComponent(name: string): Component | string
14
+ export function onMounted(callback: () => void): void
15
+ export function onBeforeUnmount(callback: () => void): void
13
16
  export function watch<T>(
14
17
  source: WatchSource<T> | WatchSource<T>[],
15
18
  callback: WatchCallback<T>,
@@ -21,6 +24,7 @@ export function defineNuxtPlugin(plugin: (nuxtApp: NuxtApp) => void | Promise<vo
21
24
  export function useNuxtApp(): NuxtApp
22
25
  export function useRuntimeConfig(): Record<string, unknown>
23
26
  export function useRoute(): { path: string, params: Record<string, string>, query: Record<string, string> }
27
+ export function navigateTo(to: string): Promise<void>
24
28
 
25
29
  // Stub for #imports - nuxt-graphql-middleware
26
30
  export function useAsyncGraphqlQuery<T = unknown>(
@@ -8,15 +8,23 @@ export const findData = (data, nodes) => {
8
8
  return void 0;
9
9
  }, data);
10
10
  };
11
+ function addRelativePath(item) {
12
+ if (!item || typeof item !== "object" || !("featuredImage" in item)) return;
13
+ const featuredImage = item.featuredImage;
14
+ if (featuredImage && typeof featuredImage === "object" && "node" in featuredImage) {
15
+ const node = featuredImage.node;
16
+ if (node && typeof node === "object" && "sourceUrl" in node && typeof node.sourceUrl === "string") {
17
+ node.relativePath = getRelativeImagePath(node.sourceUrl);
18
+ }
19
+ }
20
+ }
11
21
  export const transformData = (data, nodes, fixImagePaths) => {
12
22
  const transformedData = findData(data, nodes);
13
- if (fixImagePaths && transformedData && typeof transformedData === "object" && "featuredImage" in transformedData) {
14
- const featuredImage = transformedData.featuredImage;
15
- if (featuredImage && typeof featuredImage === "object" && "node" in featuredImage) {
16
- const node = featuredImage.node;
17
- if (node && typeof node === "object" && "sourceUrl" in node && typeof node.sourceUrl === "string") {
18
- node.relativePath = getRelativeImagePath(node.sourceUrl);
19
- }
23
+ if (fixImagePaths && transformedData) {
24
+ if (Array.isArray(transformedData)) {
25
+ transformedData.forEach(addRelativePath);
26
+ } else {
27
+ addRelativePath(transformedData);
20
28
  }
21
29
  }
22
30
  return transformedData;
File without changes
@@ -0,0 +1,40 @@
1
+ function isInternalLink(url, wordpressUrl) {
2
+ if (!url || typeof url !== "string") {
3
+ return false;
4
+ }
5
+ const trimmed = url.trim();
6
+ if (trimmed.startsWith("/") && !trimmed.startsWith("//")) {
7
+ return true;
8
+ }
9
+ if (/^(?!https?:\/\/)/i.test(trimmed) && !trimmed.startsWith("//")) {
10
+ return false;
11
+ }
12
+ if (!wordpressUrl || typeof wordpressUrl !== "string") {
13
+ return false;
14
+ }
15
+ try {
16
+ const fullUrl = trimmed.startsWith("//") ? `https:${trimmed}` : trimmed;
17
+ const parsedUrl = new URL(fullUrl);
18
+ const parsedWp = new URL(wordpressUrl);
19
+ return parsedUrl.hostname === parsedWp.hostname;
20
+ } catch {
21
+ return false;
22
+ }
23
+ }
24
+ function toRelativePath(url) {
25
+ if (!url || typeof url !== "string") {
26
+ return "";
27
+ }
28
+ const trimmed = url.trim();
29
+ if (trimmed.startsWith("/") && !trimmed.startsWith("//")) {
30
+ return trimmed;
31
+ }
32
+ try {
33
+ const fullUrl = trimmed.startsWith("//") ? `https:${trimmed}` : trimmed;
34
+ const parsed = new URL(fullUrl);
35
+ return parsed.pathname + parsed.search + parsed.hash;
36
+ } catch {
37
+ return trimmed;
38
+ }
39
+ }
40
+ export { isInternalLink, toRelativePath };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wpnuxt/core",
3
- "version": "2.0.0-alpha.10",
3
+ "version": "2.0.0-alpha.11",
4
4
  "description": "Nuxt module for WordPress integration via GraphQL (WPGraphQL)",
5
5
  "keywords": [
6
6
  "nuxt",
@@ -27,10 +27,12 @@
27
27
  },
28
28
  "./server-options": {
29
29
  "types": "./dist/server-options.d.mts",
30
+ "development": "./src/server-options.ts",
30
31
  "import": "./dist/server-options.mjs"
31
32
  },
32
33
  "./client-options": {
33
34
  "types": "./dist/client-options.d.mts",
35
+ "development": "./src/client-options.ts",
34
36
  "import": "./dist/client-options.mjs"
35
37
  }
36
38
  },
@@ -43,7 +45,7 @@
43
45
  "access": "public"
44
46
  },
45
47
  "dependencies": {
46
- "@nuxt/kit": "4.3.0",
48
+ "@nuxt/kit": "4.3.1",
47
49
  "@radya/nuxt-dompurify": "^1.0.5",
48
50
  "consola": "^3.4.0",
49
51
  "defu": "^6.1.4",
@@ -54,10 +56,10 @@
54
56
  "devDependencies": {
55
57
  "@nuxt/devtools": "^3.1.1",
56
58
  "@nuxt/module-builder": "^1.0.2",
57
- "@nuxt/schema": "4.3.0",
58
- "@nuxt/test-utils": "^3.23.0",
59
- "@types/node": "^25.2.1",
60
- "nuxt": "4.3.0",
59
+ "@nuxt/schema": "4.3.1",
60
+ "@nuxt/test-utils": "^4.0.0",
61
+ "@types/node": "^25.2.2",
62
+ "nuxt": "4.3.1",
61
63
  "vitest": "^4.0.18",
62
64
  "vue-tsc": "^3.2.3"
63
65
  },