@wpnuxt/core 2.0.0-alpha.4 → 2.0.0-alpha.6
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
package/dist/module.mjs
CHANGED
|
@@ -8,6 +8,13 @@ import { ref } from 'vue';
|
|
|
8
8
|
import { parse, GraphQLError } from 'graphql';
|
|
9
9
|
import { execSync } from 'node:child_process';
|
|
10
10
|
|
|
11
|
+
function createModuleError(module, message) {
|
|
12
|
+
return new Error(formatErrorMessage(module, message));
|
|
13
|
+
}
|
|
14
|
+
function formatErrorMessage(module, message) {
|
|
15
|
+
return `[wpnuxt:${module}] ${message}`;
|
|
16
|
+
}
|
|
17
|
+
|
|
11
18
|
function randHashGenerator(length = 12) {
|
|
12
19
|
return Math.random().toString(36).substring(2, 2 + length).toUpperCase().padEnd(length, "0");
|
|
13
20
|
}
|
|
@@ -38,14 +45,14 @@ async function mergeQueries(nuxt, wpNuxtConfig, resolver) {
|
|
|
38
45
|
|
|
39
46
|
const _parseDoc = async (doc) => {
|
|
40
47
|
if (!doc || typeof doc !== "string" || doc.trim().length === 0) {
|
|
41
|
-
throw
|
|
48
|
+
throw createModuleError("core", "Invalid GraphQL document - document is empty or not a string");
|
|
42
49
|
}
|
|
43
50
|
try {
|
|
44
51
|
const { definitions } = parse(doc);
|
|
45
52
|
const operations = definitions.filter(({ kind }) => kind === "OperationDefinition").map((definition) => {
|
|
46
53
|
const operationDefinition = definition;
|
|
47
54
|
if (!operationDefinition.name?.value) {
|
|
48
|
-
throw
|
|
55
|
+
throw createModuleError("core", "GraphQL operation is missing a name. All queries and mutations must have a name.");
|
|
49
56
|
}
|
|
50
57
|
const query = {
|
|
51
58
|
name: operationDefinition.name.value.trim(),
|
|
@@ -60,7 +67,7 @@ const _parseDoc = async (doc) => {
|
|
|
60
67
|
return operations;
|
|
61
68
|
} catch (error) {
|
|
62
69
|
if (error instanceof GraphQLError) {
|
|
63
|
-
throw
|
|
70
|
+
throw createModuleError("core", `Failed to parse GraphQL document - ${error.message}`);
|
|
64
71
|
}
|
|
65
72
|
throw error;
|
|
66
73
|
}
|
|
@@ -83,6 +90,31 @@ function processSelections(selections, level, query, canExtract = true) {
|
|
|
83
90
|
const parseDoc = _parseDoc;
|
|
84
91
|
|
|
85
92
|
const SCHEMA_PATTERN = /schema\.(?:gql|graphql)$/i;
|
|
93
|
+
const COMPLEXITY_THRESHOLDS = {
|
|
94
|
+
/** Maximum recommended extraction depth */
|
|
95
|
+
maxDepth: 5,
|
|
96
|
+
/** Maximum recommended number of fragments */
|
|
97
|
+
maxFragments: 4
|
|
98
|
+
};
|
|
99
|
+
function analyzeQueryComplexity(queries) {
|
|
100
|
+
const logger = getLogger();
|
|
101
|
+
for (const query of queries) {
|
|
102
|
+
const warnings = [];
|
|
103
|
+
const depth = query.nodes?.length ?? 0;
|
|
104
|
+
if (depth > COMPLEXITY_THRESHOLDS.maxDepth) {
|
|
105
|
+
warnings.push(`deep extraction path (${depth} levels)`);
|
|
106
|
+
}
|
|
107
|
+
const fragmentCount = query.fragments?.length ?? 0;
|
|
108
|
+
if (fragmentCount > COMPLEXITY_THRESHOLDS.maxFragments) {
|
|
109
|
+
warnings.push(`many fragments (${fragmentCount})`);
|
|
110
|
+
}
|
|
111
|
+
if (warnings.length > 0) {
|
|
112
|
+
logger.warn(
|
|
113
|
+
`Query "${query.name}" may be expensive: ${warnings.join(", ")}. Consider splitting into smaller queries or reducing data fetched.`
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
86
118
|
const allowDocument = (f, resolver) => {
|
|
87
119
|
if (SCHEMA_PATTERN.test(f)) return false;
|
|
88
120
|
try {
|
|
@@ -106,6 +138,7 @@ async function prepareContext(ctx) {
|
|
|
106
138
|
}
|
|
107
139
|
const queries = ctx.fns.filter((f) => f.operation === "query");
|
|
108
140
|
const mutations = ctx.fns.filter((f) => f.operation === "mutation");
|
|
141
|
+
analyzeQueryComplexity(queries);
|
|
109
142
|
const fnName = (fn) => ctx.composablesPrefix + upperFirst(fn);
|
|
110
143
|
const mutationFnName = (fn) => `useMutation${upperFirst(fn)}`;
|
|
111
144
|
const formatNodes = (nodes) => nodes?.map((n) => `'${n}'`).join(",") ?? "";
|
|
@@ -246,7 +279,7 @@ async function validateWordPressEndpoint(wordpressUrl, graphqlEndpoint = "/graph
|
|
|
246
279
|
clearTimeout(timeout);
|
|
247
280
|
if (!response.ok) {
|
|
248
281
|
throw new Error(
|
|
249
|
-
`[
|
|
282
|
+
`[wpnuxt:core] WordPress GraphQL endpoint returned HTTP ${response.status}.
|
|
250
283
|
|
|
251
284
|
URL: ${fullUrl}
|
|
252
285
|
|
|
@@ -261,7 +294,7 @@ Check your wpNuxt.wordpressUrl configuration in nuxt.config.ts`
|
|
|
261
294
|
const data = await response.json();
|
|
262
295
|
if (!data || typeof data !== "object") {
|
|
263
296
|
throw new Error(
|
|
264
|
-
`[
|
|
297
|
+
`[wpnuxt:core] WordPress GraphQL endpoint returned invalid response.
|
|
265
298
|
|
|
266
299
|
URL: ${fullUrl}
|
|
267
300
|
|
|
@@ -271,7 +304,7 @@ The endpoint did not return valid JSON. Make sure WPGraphQL plugin is installed
|
|
|
271
304
|
if (data.errors && !data.data) {
|
|
272
305
|
const errorMessage = data.errors[0]?.message || "Unknown error";
|
|
273
306
|
throw new Error(
|
|
274
|
-
`[
|
|
307
|
+
`[wpnuxt:core] WordPress GraphQL endpoint returned an error: ${errorMessage}
|
|
275
308
|
|
|
276
309
|
URL: ${fullUrl}
|
|
277
310
|
|
|
@@ -289,7 +322,7 @@ Make sure WPGraphQL plugin is installed and activated on your WordPress site.`
|
|
|
289
322
|
} catch (err) {
|
|
290
323
|
const error = err;
|
|
291
324
|
throw new Error(
|
|
292
|
-
`[
|
|
325
|
+
`[wpnuxt:core] Failed to download GraphQL schema.
|
|
293
326
|
|
|
294
327
|
URL: ${fullUrl}
|
|
295
328
|
Error: ${error.stderr?.toString() || error.message}
|
|
@@ -299,14 +332,14 @@ Make sure WPGraphQL plugin is installed and activated on your WordPress site.`
|
|
|
299
332
|
}
|
|
300
333
|
}
|
|
301
334
|
} catch (error) {
|
|
302
|
-
if (error instanceof Error && error.message.startsWith("[
|
|
335
|
+
if (error instanceof Error && error.message.startsWith("[wpnuxt:core]")) {
|
|
303
336
|
throw error;
|
|
304
337
|
}
|
|
305
338
|
const err = error;
|
|
306
339
|
const errorCode = err.code || err.cause?.code || "";
|
|
307
340
|
if (err.name === "AbortError") {
|
|
308
341
|
throw new Error(
|
|
309
|
-
`[
|
|
342
|
+
`[wpnuxt:core] WordPress GraphQL endpoint timed out after 10 seconds.
|
|
310
343
|
|
|
311
344
|
URL: ${fullUrl}
|
|
312
345
|
|
|
@@ -315,7 +348,7 @@ The server did not respond in time. Check if the WordPress site is accessible.`
|
|
|
315
348
|
}
|
|
316
349
|
if (errorCode === "ENOTFOUND" || err.message?.includes("getaddrinfo")) {
|
|
317
350
|
throw new Error(
|
|
318
|
-
`[
|
|
351
|
+
`[wpnuxt:core] WordPress site not found - DNS lookup failed.
|
|
319
352
|
|
|
320
353
|
URL: ${fullUrl}
|
|
321
354
|
|
|
@@ -329,7 +362,7 @@ Check your wpNuxt.wordpressUrl configuration in nuxt.config.ts`
|
|
|
329
362
|
}
|
|
330
363
|
if (errorCode === "ECONNREFUSED") {
|
|
331
364
|
throw new Error(
|
|
332
|
-
`[
|
|
365
|
+
`[wpnuxt:core] Connection refused to WordPress site.
|
|
333
366
|
|
|
334
367
|
URL: ${fullUrl}
|
|
335
368
|
|
|
@@ -337,7 +370,7 @@ The server is not accepting connections. Check if the WordPress site is running.
|
|
|
337
370
|
);
|
|
338
371
|
}
|
|
339
372
|
throw new Error(
|
|
340
|
-
`[
|
|
373
|
+
`[wpnuxt:core] Failed to connect to WordPress GraphQL endpoint.
|
|
341
374
|
|
|
342
375
|
URL: ${fullUrl}
|
|
343
376
|
Error: ${err.message || "Unknown error"}
|
|
@@ -373,8 +406,11 @@ function patchWPGraphQLSchema(schemaPath) {
|
|
|
373
406
|
|
|
374
407
|
const module$1 = defineNuxtModule({
|
|
375
408
|
meta: {
|
|
376
|
-
name: "wpnuxt",
|
|
377
|
-
configKey: "wpNuxt"
|
|
409
|
+
name: "@wpnuxt/core",
|
|
410
|
+
configKey: "wpNuxt",
|
|
411
|
+
compatibility: {
|
|
412
|
+
nuxt: ">=3.0.0"
|
|
413
|
+
}
|
|
378
414
|
},
|
|
379
415
|
defaults: {
|
|
380
416
|
wordpressUrl: void 0,
|
|
@@ -404,15 +440,32 @@ const module$1 = defineNuxtModule({
|
|
|
404
440
|
const mergedQueriesFolder = await mergeQueries(nuxt, wpNuxtConfig, resolver);
|
|
405
441
|
await setupServerOptions(nuxt, resolver, logger);
|
|
406
442
|
await setupClientOptions(nuxt, resolver, logger);
|
|
443
|
+
const schemaPath = join(nuxt.options.rootDir, "schema.graphql");
|
|
444
|
+
const schemaExists = existsSync(schemaPath);
|
|
407
445
|
if (wpNuxtConfig.downloadSchema) {
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
446
|
+
if (!schemaExists) {
|
|
447
|
+
logger.debug(`Downloading schema from: ${wpNuxtConfig.wordpressUrl}${wpNuxtConfig.graphqlEndpoint}`);
|
|
448
|
+
await validateWordPressEndpoint(
|
|
449
|
+
wpNuxtConfig.wordpressUrl,
|
|
450
|
+
wpNuxtConfig.graphqlEndpoint,
|
|
451
|
+
{ schemaPath }
|
|
452
|
+
);
|
|
453
|
+
logger.debug("Schema downloaded successfully");
|
|
454
|
+
} else {
|
|
455
|
+
nuxt.hook("ready", async () => {
|
|
456
|
+
try {
|
|
457
|
+
await validateWordPressEndpoint(
|
|
458
|
+
wpNuxtConfig.wordpressUrl,
|
|
459
|
+
wpNuxtConfig.graphqlEndpoint
|
|
460
|
+
);
|
|
461
|
+
logger.debug("WordPress endpoint validation passed");
|
|
462
|
+
} catch (error) {
|
|
463
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
464
|
+
logger.warn(`WordPress endpoint validation failed: ${message.split("\n")[0]}`);
|
|
465
|
+
logger.warn("App will continue with existing schema.graphql file");
|
|
466
|
+
}
|
|
467
|
+
});
|
|
468
|
+
}
|
|
416
469
|
}
|
|
417
470
|
await registerModules(nuxt, resolver, wpNuxtConfig, mergedQueriesFolder);
|
|
418
471
|
nuxt.hook("devtools:customTabs", (tabs) => {
|
|
@@ -500,10 +553,10 @@ function loadConfig(options, nuxt) {
|
|
|
500
553
|
}
|
|
501
554
|
};
|
|
502
555
|
if (!config.wordpressUrl?.trim()) {
|
|
503
|
-
throw
|
|
556
|
+
throw createModuleError("core", "WordPress URL is required. Set it in nuxt.config.ts or via WPNUXT_WORDPRESS_URL environment variable.");
|
|
504
557
|
}
|
|
505
558
|
if (config.wordpressUrl.endsWith("/")) {
|
|
506
|
-
throw
|
|
559
|
+
throw createModuleError("core", `WordPress URL should not have a trailing slash: ${config.wordpressUrl}`);
|
|
507
560
|
}
|
|
508
561
|
return config;
|
|
509
562
|
}
|
|
@@ -1,36 +1,102 @@
|
|
|
1
1
|
import { getRelativeImagePath } from "../util/images.js";
|
|
2
|
-
import { computed, useAsyncGraphqlQuery } from "#imports";
|
|
3
|
-
function defaultGetCachedData(key, nuxtApp, ctx) {
|
|
4
|
-
if (nuxtApp.isHydrating) {
|
|
5
|
-
return nuxtApp.payload.data[key];
|
|
6
|
-
}
|
|
7
|
-
if (ctx.cause === "refresh:manual" || ctx.cause === "refresh:hook") {
|
|
8
|
-
return void 0;
|
|
9
|
-
}
|
|
10
|
-
return nuxtApp.payload.data[key] ?? nuxtApp.static.data[key];
|
|
11
|
-
}
|
|
2
|
+
import { computed, ref, watch as vueWatch, useAsyncGraphqlQuery } from "#imports";
|
|
12
3
|
export const useWPContent = (queryName, nodes, fixImagePaths, params, options) => {
|
|
13
|
-
const {
|
|
4
|
+
const {
|
|
5
|
+
clientCache,
|
|
6
|
+
cacheKey,
|
|
7
|
+
getCachedData: userGetCachedData,
|
|
8
|
+
retry: retryOption,
|
|
9
|
+
retryDelay: retryDelayOption,
|
|
10
|
+
timeout: timeoutOption,
|
|
11
|
+
...restOptions
|
|
12
|
+
} = options ?? {};
|
|
13
|
+
const maxRetries = retryOption === false ? 0 : retryOption ?? 0;
|
|
14
|
+
const baseRetryDelay = retryDelayOption ?? 1e3;
|
|
15
|
+
const retryCount = ref(0);
|
|
16
|
+
const isRetrying = ref(false);
|
|
17
|
+
const timeoutMs = timeoutOption ?? 0;
|
|
14
18
|
const graphqlCaching = clientCache === false ? { client: false } : restOptions.graphqlCaching ?? { client: true };
|
|
15
19
|
const paramsKey = params ? JSON.stringify(params) : "{}";
|
|
16
20
|
const baseKey = `wpnuxt-${String(queryName)}-${paramsKey}`;
|
|
17
21
|
const finalKey = cacheKey ? `${baseKey}-${cacheKey}` : baseKey;
|
|
18
|
-
const effectiveGetCachedData = userGetCachedData ?? (clientCache === false ? () => void 0 :
|
|
22
|
+
const effectiveGetCachedData = userGetCachedData ?? (clientCache === false ? () => void 0 : void 0);
|
|
23
|
+
let abortController;
|
|
24
|
+
let timeoutId;
|
|
25
|
+
if (timeoutMs > 0) {
|
|
26
|
+
abortController = new AbortController();
|
|
27
|
+
timeoutId = setTimeout(() => {
|
|
28
|
+
abortController?.abort();
|
|
29
|
+
if (import.meta.dev) {
|
|
30
|
+
console.warn(`[wpnuxt] Query "${String(queryName)}" timed out after ${timeoutMs}ms`);
|
|
31
|
+
}
|
|
32
|
+
}, timeoutMs);
|
|
33
|
+
}
|
|
19
34
|
const mergedOptions = {
|
|
20
35
|
...restOptions,
|
|
21
36
|
graphqlCaching,
|
|
22
37
|
// Explicit key ensures consistent cache lookups
|
|
23
38
|
key: finalKey,
|
|
24
|
-
getCachedData
|
|
39
|
+
// Only set getCachedData if user provided one or wants to disable caching
|
|
40
|
+
// Otherwise let nuxt-graphql-middleware handle it with $graphqlCache
|
|
41
|
+
...effectiveGetCachedData && { getCachedData: effectiveGetCachedData },
|
|
42
|
+
// Pass abort signal for timeout support
|
|
43
|
+
...abortController && {
|
|
44
|
+
fetchOptions: {
|
|
45
|
+
...restOptions.fetchOptions ?? {},
|
|
46
|
+
signal: abortController.signal
|
|
47
|
+
}
|
|
48
|
+
}
|
|
25
49
|
};
|
|
26
50
|
const { data, pending, refresh, execute, clear, error, status } = useAsyncGraphqlQuery(
|
|
27
51
|
queryName,
|
|
28
52
|
params ?? {},
|
|
29
53
|
mergedOptions
|
|
30
54
|
);
|
|
55
|
+
const transformError = ref(null);
|
|
56
|
+
if (timeoutId !== void 0) {
|
|
57
|
+
vueWatch(pending, (isPending) => {
|
|
58
|
+
if (!isPending && timeoutId !== void 0) {
|
|
59
|
+
clearTimeout(timeoutId);
|
|
60
|
+
timeoutId = void 0;
|
|
61
|
+
}
|
|
62
|
+
}, { immediate: true });
|
|
63
|
+
}
|
|
64
|
+
if (maxRetries > 0) {
|
|
65
|
+
vueWatch(error, async (newError) => {
|
|
66
|
+
if (newError && !isRetrying.value && retryCount.value < maxRetries && import.meta.client) {
|
|
67
|
+
isRetrying.value = true;
|
|
68
|
+
retryCount.value++;
|
|
69
|
+
const delay = baseRetryDelay * Math.pow(2, retryCount.value - 1);
|
|
70
|
+
if (import.meta.dev) {
|
|
71
|
+
console.warn(`[wpnuxt] Query "${String(queryName)}" failed, retrying in ${delay}ms (attempt ${retryCount.value}/${maxRetries})`);
|
|
72
|
+
}
|
|
73
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
74
|
+
try {
|
|
75
|
+
await refresh();
|
|
76
|
+
} finally {
|
|
77
|
+
isRetrying.value = false;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
vueWatch(data, (newData) => {
|
|
82
|
+
if (newData && retryCount.value > 0) {
|
|
83
|
+
retryCount.value = 0;
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
}
|
|
31
87
|
const transformedData = computed(() => {
|
|
32
|
-
|
|
33
|
-
|
|
88
|
+
transformError.value = null;
|
|
89
|
+
try {
|
|
90
|
+
const queryResult = data.value && typeof data.value === "object" && data.value !== null && "data" in data.value ? data.value.data : void 0;
|
|
91
|
+
if (!queryResult) return void 0;
|
|
92
|
+
return transformData(queryResult, nodes, fixImagePaths);
|
|
93
|
+
} catch (err) {
|
|
94
|
+
if (import.meta.dev) {
|
|
95
|
+
console.warn(`[wpnuxt] Data transformation error for "${String(queryName)}":`, err);
|
|
96
|
+
}
|
|
97
|
+
transformError.value = err instanceof Error ? err : new Error("Failed to transform query response");
|
|
98
|
+
return void 0;
|
|
99
|
+
}
|
|
34
100
|
});
|
|
35
101
|
return {
|
|
36
102
|
data: transformedData,
|
|
@@ -39,7 +105,13 @@ export const useWPContent = (queryName, nodes, fixImagePaths, params, options) =
|
|
|
39
105
|
execute,
|
|
40
106
|
clear,
|
|
41
107
|
error,
|
|
42
|
-
status
|
|
108
|
+
status,
|
|
109
|
+
/** Error from data transformation (separate from fetch error) */
|
|
110
|
+
transformError,
|
|
111
|
+
/** Current retry attempt count (0 if no retries or retries disabled) */
|
|
112
|
+
retryCount,
|
|
113
|
+
/** Whether a retry is currently in progress */
|
|
114
|
+
isRetrying
|
|
43
115
|
};
|
|
44
116
|
};
|
|
45
117
|
const transformData = (data, nodes, fixImagePaths) => {
|
|
File without changes
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export function createWPNuxtError(code, message, options) {
|
|
2
|
+
return {
|
|
3
|
+
code,
|
|
4
|
+
message,
|
|
5
|
+
details: options?.details,
|
|
6
|
+
query: options?.query,
|
|
7
|
+
timestamp: Date.now()
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
export function isWPNuxtError(error) {
|
|
11
|
+
return typeof error === "object" && error !== null && "code" in error && "message" in error && "timestamp" in error && typeof error.code === "string" && typeof error.message === "string" && typeof error.timestamp === "number";
|
|
12
|
+
}
|
|
13
|
+
export function success(data) {
|
|
14
|
+
return { success: true, data, error: null };
|
|
15
|
+
}
|
|
16
|
+
export function failure(error) {
|
|
17
|
+
return { success: false, data: null, error };
|
|
18
|
+
}
|
|
19
|
+
export function fromError(error, code = "NETWORK_ERROR", query) {
|
|
20
|
+
let errorCode = code;
|
|
21
|
+
if (error.name === "AbortError") {
|
|
22
|
+
errorCode = "TIMEOUT_ERROR";
|
|
23
|
+
} else if (error.message?.includes("GraphQL")) {
|
|
24
|
+
errorCode = "GRAPHQL_ERROR";
|
|
25
|
+
} else if (error.message?.includes("401") || error.message?.includes("403")) {
|
|
26
|
+
errorCode = "AUTH_ERROR";
|
|
27
|
+
}
|
|
28
|
+
return createWPNuxtError(errorCode, error.message, {
|
|
29
|
+
details: error.stack,
|
|
30
|
+
query
|
|
31
|
+
});
|
|
32
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wpnuxt/core",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.6",
|
|
4
4
|
"description": "Nuxt module for WordPress integration via GraphQL (WPGraphQL)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"nuxt",
|
|
@@ -47,18 +47,18 @@
|
|
|
47
47
|
"@radya/nuxt-dompurify": "^1.0.5",
|
|
48
48
|
"defu": "^6.1.4",
|
|
49
49
|
"graphql": "^16.12.0",
|
|
50
|
-
"nuxt-graphql-middleware": "5.3.
|
|
50
|
+
"nuxt-graphql-middleware": "5.3.2",
|
|
51
51
|
"scule": "^1.3.0"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@nuxt/devtools": "^3.1.1",
|
|
55
55
|
"@nuxt/module-builder": "^1.0.2",
|
|
56
56
|
"@nuxt/schema": "4.2.2",
|
|
57
|
-
"@nuxt/test-utils": "^3.
|
|
58
|
-
"@types/node": "^25.0.
|
|
57
|
+
"@nuxt/test-utils": "^3.23.0",
|
|
58
|
+
"@types/node": "^25.0.9",
|
|
59
59
|
"nuxt": "4.2.2",
|
|
60
|
-
"vitest": "^4.0.
|
|
61
|
-
"vue-tsc": "^3.2.
|
|
60
|
+
"vitest": "^4.0.17",
|
|
61
|
+
"vue-tsc": "^3.2.2"
|
|
62
62
|
},
|
|
63
63
|
"peerDependencies": {
|
|
64
64
|
"nuxt": "^4.0.0"
|