@wpnuxt/core 2.0.0-beta.5 → 2.0.0-beta.7
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.d.mts +15 -0
- package/dist/module.d.ts +15 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +126 -26
- package/dist/runtime/composables/useWPContent.js +8 -2
- package/dist/runtime/queries/Node.gql +1 -0
- package/dist/runtime/server/api/wpnuxt/revalidate.post.d.ts +0 -0
- package/dist/runtime/server/api/wpnuxt/revalidate.post.js +36 -0
- package/package.json +11 -11
package/dist/module.d.mts
CHANGED
|
@@ -111,6 +111,21 @@ interface WPNuxtConfig {
|
|
|
111
111
|
* @default true
|
|
112
112
|
*/
|
|
113
113
|
swr?: boolean;
|
|
114
|
+
/**
|
|
115
|
+
* Secret token for the cache revalidation webhook endpoint.
|
|
116
|
+
*
|
|
117
|
+
* When set, WPNuxt registers a POST endpoint at `/api/_wpnuxt/revalidate`
|
|
118
|
+
* that WordPress can call to purge all cached GraphQL responses immediately.
|
|
119
|
+
*
|
|
120
|
+
* On self-hosted (Node.js), purges Nitro's internal handler cache.
|
|
121
|
+
* On Vercel, also purges the CDN cache when `VERCEL_TOKEN` and
|
|
122
|
+
* `VERCEL_PROJECT_ID` environment variables are set.
|
|
123
|
+
*
|
|
124
|
+
* Can also be set via `WPNUXT_REVALIDATE_SECRET` environment variable.
|
|
125
|
+
*
|
|
126
|
+
* @see https://wpnuxt.com/guide/caching#webhook-revalidation
|
|
127
|
+
*/
|
|
128
|
+
revalidateSecret?: string;
|
|
114
129
|
};
|
|
115
130
|
}
|
|
116
131
|
|
package/dist/module.d.ts
CHANGED
|
@@ -111,6 +111,21 @@ interface WPNuxtConfig {
|
|
|
111
111
|
* @default true
|
|
112
112
|
*/
|
|
113
113
|
swr?: boolean;
|
|
114
|
+
/**
|
|
115
|
+
* Secret token for the cache revalidation webhook endpoint.
|
|
116
|
+
*
|
|
117
|
+
* When set, WPNuxt registers a POST endpoint at `/api/_wpnuxt/revalidate`
|
|
118
|
+
* that WordPress can call to purge all cached GraphQL responses immediately.
|
|
119
|
+
*
|
|
120
|
+
* On self-hosted (Node.js), purges Nitro's internal handler cache.
|
|
121
|
+
* On Vercel, also purges the CDN cache when `VERCEL_TOKEN` and
|
|
122
|
+
* `VERCEL_PROJECT_ID` environment variables are set.
|
|
123
|
+
*
|
|
124
|
+
* Can also be set via `WPNUXT_REVALIDATE_SECRET` environment variable.
|
|
125
|
+
*
|
|
126
|
+
* @see https://wpnuxt.com/guide/caching#webhook-revalidation
|
|
127
|
+
*/
|
|
128
|
+
revalidateSecret?: string;
|
|
114
129
|
};
|
|
115
130
|
}
|
|
116
131
|
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -2,13 +2,13 @@ import { defu } from 'defu';
|
|
|
2
2
|
import { promises, cpSync, existsSync, readdirSync, statSync, mkdirSync, 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, addServerHandler, addImports, addComponentsDir, addTemplate, addTypeTemplate, hasNuxtModule, installModule } from '@nuxt/kit';
|
|
6
6
|
import { upperFirst } from 'scule';
|
|
7
7
|
import { parse, GraphQLError, visit, print } from 'graphql';
|
|
8
8
|
import { execSync } from 'node:child_process';
|
|
9
9
|
import { consola } from 'consola';
|
|
10
10
|
|
|
11
|
-
const version = "2.0.0-beta.
|
|
11
|
+
const version = "2.0.0-beta.7";
|
|
12
12
|
|
|
13
13
|
function createModuleError(module, message) {
|
|
14
14
|
return new Error(formatErrorMessage(module, message));
|
|
@@ -71,9 +71,42 @@ async function mergeQueries(nuxt, wpNuxtConfig, resolver) {
|
|
|
71
71
|
logger.debug("Extending queries:", userQueryPath);
|
|
72
72
|
copyGraphqlFiles(userQueryPath, queryOutputPath);
|
|
73
73
|
}
|
|
74
|
+
await addCustomFragmentsToNodeQuery(queryOutputPath, userQueryPath, logger);
|
|
74
75
|
logger.debug("Merged queries folder:", queryOutputPath);
|
|
75
76
|
return queryOutputPath;
|
|
76
77
|
}
|
|
78
|
+
const FRAGMENT_DEF_PATTERN = /fragment\s+(\w+)\s+on\s+(\w+)/;
|
|
79
|
+
async function addCustomFragmentsToNodeQuery(queryOutputPath, userQueryPath, logger) {
|
|
80
|
+
const userFragmentsDir = join(userQueryPath, "fragments");
|
|
81
|
+
if (!existsSync(userFragmentsDir)) return;
|
|
82
|
+
const customFragments = [];
|
|
83
|
+
for (const file of readdirSync(userFragmentsDir)) {
|
|
84
|
+
if (!file.endsWith(".gql") && !file.endsWith(".graphql")) continue;
|
|
85
|
+
const content = await promises.readFile(join(userFragmentsDir, file), "utf-8");
|
|
86
|
+
const match = content.match(FRAGMENT_DEF_PATTERN);
|
|
87
|
+
if (!match) continue;
|
|
88
|
+
const name = match[1];
|
|
89
|
+
const type = match[2];
|
|
90
|
+
if (name && type && name === type) {
|
|
91
|
+
customFragments.push({ name, type });
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (customFragments.length === 0) return;
|
|
95
|
+
const nodeGqlPath = join(queryOutputPath, "Node.gql");
|
|
96
|
+
if (!existsSync(nodeGqlPath)) return;
|
|
97
|
+
let nodeGql = await promises.readFile(nodeGqlPath, "utf-8");
|
|
98
|
+
const spreads = customFragments.map((f) => ` ... on ${f.type} { ...${f.name} }`).join("\n");
|
|
99
|
+
nodeGql = nodeGql.replace(
|
|
100
|
+
/(\s+\.\.\.Post)\n(\s+\}\n\})/,
|
|
101
|
+
`$1
|
|
102
|
+
${spreads}
|
|
103
|
+
$2`
|
|
104
|
+
);
|
|
105
|
+
await promises.writeFile(nodeGqlPath, nodeGql, "utf-8");
|
|
106
|
+
logger.debug(
|
|
107
|
+
`Added custom content type fragments to NodeByUri: ${customFragments.map((f) => f.name).join(", ")}`
|
|
108
|
+
);
|
|
109
|
+
}
|
|
77
110
|
function findConflicts(userQueryPath, outputPath) {
|
|
78
111
|
const conflicts = [];
|
|
79
112
|
function walk(dir) {
|
|
@@ -152,6 +185,11 @@ function processSelections(selections, level, query, canExtract = true) {
|
|
|
152
185
|
if (hasSingleField && canExtract && firstSelection.kind === "Field") {
|
|
153
186
|
query.nodes?.push(firstSelection.name.value.trim());
|
|
154
187
|
}
|
|
188
|
+
const hasFragments = selections.some((s) => s.kind === "FragmentSpread");
|
|
189
|
+
const hasCustomFields = selections.some((s) => s.kind === "Field" && s.name.value !== "__typename");
|
|
190
|
+
if (hasFragments && hasCustomFields) {
|
|
191
|
+
query.hasInlineFields = true;
|
|
192
|
+
}
|
|
155
193
|
selections.forEach((s) => {
|
|
156
194
|
if (s.kind === "FragmentSpread") {
|
|
157
195
|
query.fragments?.push(s.name.value.trim());
|
|
@@ -216,21 +254,21 @@ async function prepareContext(ctx) {
|
|
|
216
254
|
const mutationFnName = (fn) => `useMutation${upperFirst(fn)}`;
|
|
217
255
|
const formatNodes = (nodes) => nodes?.map((n) => `'${n}'`).join(",") ?? "";
|
|
218
256
|
const getFragmentType = (q) => {
|
|
219
|
-
if (q.fragments?.length) {
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
typePath = `${typePath}[number]`;
|
|
257
|
+
if (q.hasInlineFields || !q.fragments?.length) {
|
|
258
|
+
if (q.nodes?.length) {
|
|
259
|
+
let typePath = `${q.name}RootQuery`;
|
|
260
|
+
for (const node of q.nodes) {
|
|
261
|
+
typePath = `NonNullable<${typePath}>['${node}']`;
|
|
262
|
+
}
|
|
263
|
+
if (q.nodes.includes("nodes")) {
|
|
264
|
+
typePath = `${typePath}[number]`;
|
|
265
|
+
}
|
|
266
|
+
return typePath;
|
|
230
267
|
}
|
|
231
|
-
return
|
|
268
|
+
return `${q.name}RootQuery`;
|
|
232
269
|
}
|
|
233
|
-
|
|
270
|
+
const fragmentSuffix = q.nodes?.includes("nodes") ? "[]" : "";
|
|
271
|
+
return q.fragments.map((f) => `WithImagePath<${f}Fragment>${fragmentSuffix}`).join(" | ");
|
|
234
272
|
};
|
|
235
273
|
const queryFnExp = (q, typed = false) => {
|
|
236
274
|
const functionName = fnName(q.name);
|
|
@@ -270,10 +308,10 @@ async function prepareContext(ctx) {
|
|
|
270
308
|
const typeSet = /* @__PURE__ */ new Set();
|
|
271
309
|
queries.forEach((o) => {
|
|
272
310
|
typeSet.add(`${o.name}QueryVariables`);
|
|
273
|
-
if (o.fragments?.length) {
|
|
274
|
-
o.fragments.forEach((f) => typeSet.add(`${f}Fragment`));
|
|
275
|
-
} else {
|
|
311
|
+
if (o.hasInlineFields || !o.fragments?.length) {
|
|
276
312
|
typeSet.add(`${o.name}RootQuery`);
|
|
313
|
+
} else {
|
|
314
|
+
o.fragments.forEach((f) => typeSet.add(`${f}Fragment`));
|
|
277
315
|
}
|
|
278
316
|
});
|
|
279
317
|
mutations.forEach((m) => {
|
|
@@ -431,6 +469,7 @@ URL: ${fullUrl}
|
|
|
431
469
|
Make sure WPGraphQL plugin is installed and activated on your WordPress site.`
|
|
432
470
|
);
|
|
433
471
|
}
|
|
472
|
+
await checkWPGraphQLVersion(fullUrl, headers);
|
|
434
473
|
if (options.schemaPath && !existsSync(options.schemaPath)) {
|
|
435
474
|
try {
|
|
436
475
|
const authFlag = options.authToken ? ` -h "Authorization=Bearer ${options.authToken}"` : "";
|
|
@@ -500,6 +539,41 @@ Check your wpNuxt.wordpressUrl configuration in nuxt.config.ts`
|
|
|
500
539
|
);
|
|
501
540
|
}
|
|
502
541
|
}
|
|
542
|
+
async function checkWPGraphQLVersion(fullUrl, headers) {
|
|
543
|
+
try {
|
|
544
|
+
const controller = new AbortController();
|
|
545
|
+
const timeout = setTimeout(() => controller.abort(), 1e4);
|
|
546
|
+
const response = await fetch(fullUrl, {
|
|
547
|
+
method: "POST",
|
|
548
|
+
headers,
|
|
549
|
+
body: JSON.stringify({
|
|
550
|
+
query: '{ __type(name: "MediaDetails") { fields { name } } }'
|
|
551
|
+
}),
|
|
552
|
+
signal: controller.signal
|
|
553
|
+
});
|
|
554
|
+
clearTimeout(timeout);
|
|
555
|
+
if (!response.ok) return;
|
|
556
|
+
const data = await response.json();
|
|
557
|
+
const fields = data?.data?.__type?.fields || [];
|
|
558
|
+
const hasFilePath = fields.some((f) => f.name === "filePath");
|
|
559
|
+
if (!hasFilePath) {
|
|
560
|
+
throw new Error(
|
|
561
|
+
`[wpnuxt:core] WPGraphQL version is too old. WPNuxt v2 requires WPGraphQL >= 2.0.0.
|
|
562
|
+
|
|
563
|
+
URL: ${fullUrl}
|
|
564
|
+
|
|
565
|
+
The installed WPGraphQL version does not support required schema features.
|
|
566
|
+
Please update the WPGraphQL plugin on your WordPress site to version 2.0.0 or later.
|
|
567
|
+
|
|
568
|
+
Download: https://wordpress.org/plugins/wp-graphql/`
|
|
569
|
+
);
|
|
570
|
+
}
|
|
571
|
+
} catch (error) {
|
|
572
|
+
if (error instanceof Error && error.message.startsWith("[wpnuxt:core]")) {
|
|
573
|
+
throw error;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
}
|
|
503
577
|
const PROBLEMATIC_INTERFACES = /* @__PURE__ */ new Set([
|
|
504
578
|
"Connection",
|
|
505
579
|
"Edge",
|
|
@@ -809,16 +883,38 @@ const module$1 = defineNuxtModule({
|
|
|
809
883
|
});
|
|
810
884
|
if (wpNuxtConfig.cache?.enabled !== false) {
|
|
811
885
|
const maxAge = wpNuxtConfig.cache?.maxAge ?? 300;
|
|
886
|
+
const swr = wpNuxtConfig.cache?.swr !== false;
|
|
812
887
|
const nitroOptions = nuxt.options;
|
|
813
888
|
nitroOptions.nitro = nitroOptions.nitro || {};
|
|
814
889
|
nitroOptions.nitro.routeRules = nitroOptions.nitro.routeRules || {};
|
|
815
|
-
nitroOptions.nitro.
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
890
|
+
const isVercel = process.env.VERCEL === "1" || nitroOptions.nitro.preset === "vercel";
|
|
891
|
+
if (isVercel) {
|
|
892
|
+
const swrValue = swr ? `, stale-while-revalidate=${maxAge}` : "";
|
|
893
|
+
nitroOptions.nitro.routeRules["/api/wpnuxt/query/**"] = {
|
|
894
|
+
headers: {
|
|
895
|
+
"Vercel-CDN-Cache-Control": `s-maxage=${maxAge}${swrValue}`,
|
|
896
|
+
"Vercel-Cache-Tag": "wpnuxt"
|
|
897
|
+
}
|
|
898
|
+
};
|
|
899
|
+
logger.debug(`Vercel CDN caching enabled for GraphQL queries (s-maxage: ${maxAge}s, SWR: ${swr})`);
|
|
900
|
+
} else {
|
|
901
|
+
nitroOptions.nitro.routeRules["/api/wpnuxt/query/**"] = {
|
|
902
|
+
cache: {
|
|
903
|
+
maxAge,
|
|
904
|
+
swr
|
|
905
|
+
}
|
|
906
|
+
};
|
|
907
|
+
logger.debug(`Server-side caching enabled for GraphQL queries (maxAge: ${maxAge}s, SWR: ${swr})`);
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
if (wpNuxtConfig.cache?.revalidateSecret) {
|
|
911
|
+
const revalidateHandler = resolver.resolve("./runtime/server/api/wpnuxt/revalidate.post");
|
|
912
|
+
addServerHandler({
|
|
913
|
+
route: "/api/_wpnuxt/revalidate",
|
|
914
|
+
method: "post",
|
|
915
|
+
handler: revalidateHandler
|
|
916
|
+
});
|
|
917
|
+
logger.info("Cache revalidation endpoint registered at POST /api/_wpnuxt/revalidate");
|
|
822
918
|
}
|
|
823
919
|
{
|
|
824
920
|
const nitroOptions = nuxt.options;
|
|
@@ -906,7 +1002,8 @@ async function loadConfig(options, nuxt) {
|
|
|
906
1002
|
schemaAuthToken: process.env.WPNUXT_SCHEMA_AUTH_TOKEN,
|
|
907
1003
|
// Only override downloadSchema if env var is explicitly set
|
|
908
1004
|
downloadSchema: process.env.WPNUXT_DOWNLOAD_SCHEMA !== void 0 ? process.env.WPNUXT_DOWNLOAD_SCHEMA === "true" : void 0,
|
|
909
|
-
debug: process.env.WPNUXT_DEBUG ? process.env.WPNUXT_DEBUG === "true" : void 0
|
|
1005
|
+
debug: process.env.WPNUXT_DEBUG ? process.env.WPNUXT_DEBUG === "true" : void 0,
|
|
1006
|
+
cache: process.env.WPNUXT_REVALIDATE_SECRET ? { revalidateSecret: process.env.WPNUXT_REVALIDATE_SECRET } : void 0
|
|
910
1007
|
}, options);
|
|
911
1008
|
if (config.downloadSchema === void 0) {
|
|
912
1009
|
config.downloadSchema = true;
|
|
@@ -935,6 +1032,9 @@ async function loadConfig(options, nuxt) {
|
|
|
935
1032
|
swr: config.cache?.swr ?? true
|
|
936
1033
|
}
|
|
937
1034
|
};
|
|
1035
|
+
if (config.cache?.revalidateSecret) {
|
|
1036
|
+
nuxt.options.runtimeConfig.wpNuxtRevalidateSecret = config.cache.revalidateSecret;
|
|
1037
|
+
}
|
|
938
1038
|
return config;
|
|
939
1039
|
}
|
|
940
1040
|
async function setupServerOptions(nuxt, resolver, logger) {
|
|
@@ -53,11 +53,12 @@ export const useWPContent = (queryName, nodes, fixImagePaths, params, options) =
|
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
};
|
|
56
|
-
const
|
|
56
|
+
const asyncResult = useAsyncGraphqlQuery(
|
|
57
57
|
String(queryName),
|
|
58
58
|
normalizedParams ?? {},
|
|
59
59
|
asyncDataOptions
|
|
60
60
|
);
|
|
61
|
+
const { data, pending, refresh, execute, clear, error, status } = asyncResult;
|
|
61
62
|
const transformError = ref(null);
|
|
62
63
|
if (timeoutId !== void 0) {
|
|
63
64
|
vueWatch(pending, (isPending) => {
|
|
@@ -118,7 +119,7 @@ See: https://wpnuxt.com/guide/menus`
|
|
|
118
119
|
return void 0;
|
|
119
120
|
}
|
|
120
121
|
});
|
|
121
|
-
|
|
122
|
+
const returnValue = {
|
|
122
123
|
data: transformedData,
|
|
123
124
|
pending,
|
|
124
125
|
refresh,
|
|
@@ -133,4 +134,9 @@ See: https://wpnuxt.com/guide/menus`
|
|
|
133
134
|
/** Whether a retry is currently in progress */
|
|
134
135
|
isRetrying
|
|
135
136
|
};
|
|
137
|
+
const thenable = asyncResult;
|
|
138
|
+
return Object.assign(
|
|
139
|
+
thenable.then(() => returnValue),
|
|
140
|
+
returnValue
|
|
141
|
+
);
|
|
136
142
|
};
|
|
File without changes
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { createConsola } from "consola";
|
|
2
|
+
import { defineEventHandler, readBody, createError } from "h3";
|
|
3
|
+
const logger = createConsola().withTag("wpnuxt");
|
|
4
|
+
export default defineEventHandler(async (event) => {
|
|
5
|
+
const body = await readBody(event);
|
|
6
|
+
const { wpNuxtRevalidateSecret } = useRuntimeConfig(event);
|
|
7
|
+
if (!wpNuxtRevalidateSecret || body?.secret !== wpNuxtRevalidateSecret) {
|
|
8
|
+
throw createError({ statusCode: 401, statusMessage: "Invalid secret" });
|
|
9
|
+
}
|
|
10
|
+
const storage = useStorage("cache:nitro:handlers");
|
|
11
|
+
const keys = await storage.getKeys();
|
|
12
|
+
const wpnuxtKeys = keys.filter((k) => k.includes("wpnuxt"));
|
|
13
|
+
await Promise.all(wpnuxtKeys.map((key) => storage.removeItem(key)));
|
|
14
|
+
let vercelPurged = false;
|
|
15
|
+
if (process.env.VERCEL && process.env.VERCEL_TOKEN && process.env.VERCEL_PROJECT_ID) {
|
|
16
|
+
try {
|
|
17
|
+
const response = await fetch(`https://api.vercel.com/v1/edge-cache/invalidate-by-tags?projectIdOrName=${process.env.VERCEL_PROJECT_ID}`, {
|
|
18
|
+
method: "POST",
|
|
19
|
+
headers: {
|
|
20
|
+
"Authorization": `Bearer ${process.env.VERCEL_TOKEN}`,
|
|
21
|
+
"Content-Type": "application/json"
|
|
22
|
+
},
|
|
23
|
+
body: JSON.stringify({ tags: ["wpnuxt"] })
|
|
24
|
+
});
|
|
25
|
+
vercelPurged = response.ok;
|
|
26
|
+
if (!response.ok) {
|
|
27
|
+
logger.warn(`Vercel cache purge failed: ${response.status} ${response.statusText}`);
|
|
28
|
+
}
|
|
29
|
+
} catch (error) {
|
|
30
|
+
logger.warn("Vercel cache purge request failed:", error);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const purged = wpnuxtKeys.length;
|
|
34
|
+
logger.info(`Cache revalidated: purged ${purged} Nitro entries${vercelPurged ? ", Vercel CDN cache purged" : ""}`);
|
|
35
|
+
return { success: true, purged, vercelPurged };
|
|
36
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wpnuxt/core",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.7",
|
|
4
4
|
"description": "Nuxt module for WordPress integration via GraphQL (WPGraphQL)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"nuxt",
|
|
@@ -46,23 +46,23 @@
|
|
|
46
46
|
"access": "public"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@nuxt/kit": "4.
|
|
50
|
-
"consola": "^3.4.
|
|
49
|
+
"@nuxt/kit": "4.4.2",
|
|
50
|
+
"consola": "^3.4.2",
|
|
51
51
|
"defu": "^6.1.4",
|
|
52
|
-
"dompurify": "^3.
|
|
53
|
-
"graphql": "^16.
|
|
52
|
+
"dompurify": "^3.3.3",
|
|
53
|
+
"graphql": "^16.13.1",
|
|
54
54
|
"nuxt-graphql-middleware": "5.3.2",
|
|
55
55
|
"scule": "^1.3.0"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
|
-
"@nuxt/devtools": "^3.2.
|
|
58
|
+
"@nuxt/devtools": "^3.2.3",
|
|
59
59
|
"@nuxt/module-builder": "^1.0.2",
|
|
60
|
-
"@nuxt/schema": "4.
|
|
60
|
+
"@nuxt/schema": "4.4.2",
|
|
61
61
|
"@nuxt/test-utils": "^4.0.0",
|
|
62
|
-
"@types/node": "^25.
|
|
63
|
-
"nuxt": "4.
|
|
64
|
-
"vitest": "^4.0
|
|
65
|
-
"vue-tsc": "^3.2.
|
|
62
|
+
"@types/node": "^25.5.0",
|
|
63
|
+
"nuxt": "^4.4.2",
|
|
64
|
+
"vitest": "^4.1.0",
|
|
65
|
+
"vue-tsc": "^3.2.5"
|
|
66
66
|
},
|
|
67
67
|
"peerDependencies": {
|
|
68
68
|
"nuxt": ">=3.17.0"
|