nuxt-ai-ready 1.4.0 → 1.5.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.
- package/README.md +2 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +7 -4
- package/dist/runtime/app/plugins/md-alternate.server.js +2 -2
- package/dist/runtime/app/plugins/md-hints.prerender.js +3 -7
- package/dist/runtime/markdown-path.d.ts +1 -0
- package/dist/runtime/markdown-path.js +6 -0
- package/dist/runtime/server/db/drizzle/providers/libsql.js +6 -1
- package/dist/runtime/server/middleware/markdown.js +12 -11
- package/dist/runtime/server/utils/link-header.d.ts +3 -1
- package/dist/runtime/server/utils/link-header.js +11 -6
- package/dist/runtime/server/utils.d.ts +1 -2
- package/dist/runtime/server/utils.js +3 -5
- package/dist/runtime/types.d.ts +6 -0
- package/package.json +23 -23
package/README.md
CHANGED
|
@@ -41,6 +41,8 @@ npx nuxi@latest module add nuxt-ai-ready
|
|
|
41
41
|
> npx skilld add nuxt-ai-ready
|
|
42
42
|
> ```
|
|
43
43
|
|
|
44
|
+
💡 Made your site AI-ready? Preview how a page converts to LLM-readable markdown with the free [HTML→Markdown tool](https://nuxtseo.com/tools/html-to-markdown), or track how AI engines index, rank and cite your site with [Nuxt SEO Pro](https://nuxtseo.com/pro).
|
|
45
|
+
|
|
44
46
|
## Documentation
|
|
45
47
|
|
|
46
48
|
[📖 Read the full documentation](https://nuxtseo.com/ai-ready) for more information.
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -10,6 +10,7 @@ import { readPackageJSON, resolvePackageJSON } from 'pkg-types';
|
|
|
10
10
|
import { parseSitemapXml } from '@nuxtjs/sitemap/utils';
|
|
11
11
|
import { colorize } from 'consola/utils';
|
|
12
12
|
import { withBase } from 'ufo';
|
|
13
|
+
import { toMarkdownPath } from '../dist/runtime/markdown-path.js';
|
|
13
14
|
import { initSchema, computeContentHash, insertPage, queryAllPages, exportDbDump } from '../dist/runtime/server/db/shared.js';
|
|
14
15
|
import { comparePageHashes, submitToIndexNowShared } from '../dist/runtime/server/utils/indexnow-shared.js';
|
|
15
16
|
import { buildLlmsFullTxtHeader, formatPageForLlmsFullTxt } from '../dist/runtime/server/utils/llms-full.js';
|
|
@@ -163,7 +164,7 @@ async function processSitemapEntry(state, nuxt, nitro, entry) {
|
|
|
163
164
|
if (state.prerenderedRoutes.has(route)) {
|
|
164
165
|
return { crawled: false, skipped: true };
|
|
165
166
|
}
|
|
166
|
-
const mdRoute = route
|
|
167
|
+
const mdRoute = toMarkdownPath(route);
|
|
167
168
|
const mdUrl = withBase(mdRoute, nitro.options.baseURL);
|
|
168
169
|
logger.debug(`Fetching markdown for ${route} \u2192 ${mdUrl}`);
|
|
169
170
|
const res = await globalThis.$fetch(mdUrl, {
|
|
@@ -675,11 +676,13 @@ const module$1 = defineNuxtModule({
|
|
|
675
676
|
nuxt.options.robots = robotsOpts;
|
|
676
677
|
const groups = robotsOpts.groups || [];
|
|
677
678
|
robotsOpts.groups = groups;
|
|
678
|
-
|
|
679
|
+
const group = {
|
|
679
680
|
userAgent: "*",
|
|
680
|
-
contentUsage: [`train-ai=${config.contentSignal.aiTrain ? "y" : "n"}`],
|
|
681
681
|
contentSignal: [`ai-train=${config.contentSignal.aiTrain ? "yes" : "no"}`, `search=${config.contentSignal.search ? "yes" : "no"}`, `ai-input=${config.contentSignal.aiInput ? "yes" : "no"}`]
|
|
682
|
-
}
|
|
682
|
+
};
|
|
683
|
+
if (config.contentSignal.contentUsage !== false)
|
|
684
|
+
group.contentUsage = [`train-ai=${config.contentSignal.aiTrain ? "y" : "n"}`];
|
|
685
|
+
groups.push(group);
|
|
683
686
|
}
|
|
684
687
|
registerTypeTemplates();
|
|
685
688
|
const defaultLlmsTxtSections = [];
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { defineNuxtPlugin, useHead, useRequestURL } from "nuxt/app";
|
|
2
|
+
import { toMarkdownPath } from "../../markdown-path.js";
|
|
2
3
|
export default defineNuxtPlugin({
|
|
3
4
|
setup() {
|
|
4
5
|
const url = useRequestURL();
|
|
@@ -6,10 +7,9 @@ export default defineNuxtPlugin({
|
|
|
6
7
|
const lastSegment = path.split("/").pop() || "";
|
|
7
8
|
if (lastSegment.includes("."))
|
|
8
9
|
return;
|
|
9
|
-
const mdPath = path === "/" ? "/index.md" : `${path.replace(/\/$/, "")}.md`;
|
|
10
10
|
useHead({
|
|
11
11
|
link: [
|
|
12
|
-
{ rel: "alternate", type: "text/markdown", href:
|
|
12
|
+
{ rel: "alternate", type: "text/markdown", href: toMarkdownPath(path) }
|
|
13
13
|
]
|
|
14
14
|
});
|
|
15
15
|
}
|
|
@@ -1,21 +1,17 @@
|
|
|
1
1
|
import { isPathFile } from "nuxt-site-config/urls";
|
|
2
2
|
import { defineNuxtPlugin, prerenderRoutes } from "nuxt/app";
|
|
3
|
+
import { toMarkdownPath } from "../../markdown-path.js";
|
|
3
4
|
export default defineNuxtPlugin({
|
|
4
5
|
setup(nuxtApp) {
|
|
5
6
|
if (!import.meta.prerender) {
|
|
6
7
|
return;
|
|
7
8
|
}
|
|
8
9
|
nuxtApp.hooks.hook("app:rendered", (ctx) => {
|
|
9
|
-
|
|
10
|
+
const url = ctx.ssrContext?.url || "";
|
|
10
11
|
if (isPathFile(url) || ctx.ssrContext?.error || ctx.ssrContext?.noSSR) {
|
|
11
12
|
return;
|
|
12
13
|
}
|
|
13
|
-
|
|
14
|
-
url = `${url}index.md`;
|
|
15
|
-
} else {
|
|
16
|
-
url = `${url}.md`;
|
|
17
|
-
}
|
|
18
|
-
prerenderRoutes(url);
|
|
14
|
+
prerenderRoutes(toMarkdownPath(url));
|
|
19
15
|
});
|
|
20
16
|
}
|
|
21
17
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function toMarkdownPath(path: string): string;
|
|
@@ -4,9 +4,14 @@ import { useRuntimeConfig } from "nitropack/runtime";
|
|
|
4
4
|
import * as schema from "#ai-ready-virtual/db-schema.mjs";
|
|
5
5
|
import { logger } from "../../../logger.js";
|
|
6
6
|
import { registerDriver } from "../raw.js";
|
|
7
|
+
import { resolveWritableDbPath } from "./dbPath.js";
|
|
7
8
|
export async function createClient(event) {
|
|
8
9
|
const config = useRuntimeConfig(event)["nuxt-ai-ready"];
|
|
9
|
-
|
|
10
|
+
let dbUrl = config.database.url || `file:${config.database.filename || ".data/ai-ready/pages.db"}`;
|
|
11
|
+
if (dbUrl.startsWith("file:") && !dbUrl.startsWith("file://")) {
|
|
12
|
+
const resolved = await resolveWritableDbPath(dbUrl.slice("file:".length));
|
|
13
|
+
dbUrl = `file:${resolved}`;
|
|
14
|
+
}
|
|
10
15
|
logger.debug(`[drizzle] Connecting to LibSQL: ${dbUrl}`);
|
|
11
16
|
const client = createLibSQLClient({ url: dbUrl, authToken: config.database.authToken });
|
|
12
17
|
const db = drizzle(client, { schema });
|
|
@@ -9,14 +9,14 @@ import { buildFrontmatter } from "../utils/frontmatter.js";
|
|
|
9
9
|
import { computeLocaleAlternates, resolveLocaleFromRoute } from "../utils/i18n.js";
|
|
10
10
|
import { buildLinkHeader } from "../utils/link-header.js";
|
|
11
11
|
const INTERNAL_HEADER = "x-ai-ready-internal";
|
|
12
|
-
function setNegotiationHeaders(event, path, config) {
|
|
12
|
+
function setNegotiationHeaders(event, path, config, resolveUrl) {
|
|
13
13
|
setHeader(event, "vary", "Accept, Sec-Fetch-Dest");
|
|
14
|
-
setHeader(event, "link", buildLinkHeader(path, "html", config));
|
|
14
|
+
setHeader(event, "link", buildLinkHeader(path, "html", config, resolveUrl));
|
|
15
15
|
}
|
|
16
|
-
function setMarkdownHeaders(event, path, config) {
|
|
16
|
+
function setMarkdownHeaders(event, path, config, resolveUrl) {
|
|
17
17
|
setHeader(event, "content-type", "text/markdown; charset=utf-8");
|
|
18
18
|
setHeader(event, "vary", "Accept, Sec-Fetch-Dest");
|
|
19
|
-
setHeader(event, "link", buildLinkHeader(path, "markdown", config));
|
|
19
|
+
setHeader(event, "link", buildLinkHeader(path, "markdown", config, resolveUrl));
|
|
20
20
|
if (config.markdownCacheHeaders) {
|
|
21
21
|
const { maxAge, swr } = config.markdownCacheHeaders;
|
|
22
22
|
const cacheControl = swr ? `public, max-age=${maxAge}, stale-while-revalidate=${maxAge}` : `public, max-age=${maxAge}`;
|
|
@@ -65,9 +65,10 @@ export default defineEventHandler(async (event) => {
|
|
|
65
65
|
}
|
|
66
66
|
const { path, isExplicit, negotiation } = renderInfo;
|
|
67
67
|
const config = useRuntimeConfig(event)["nuxt-ai-ready"];
|
|
68
|
-
const
|
|
68
|
+
const resolveUrl = (path2) => withSiteUrl(event, path2);
|
|
69
|
+
const canonicalUrl = resolveUrl(path);
|
|
69
70
|
if (negotiation === "html") {
|
|
70
|
-
setNegotiationHeaders(event, path, config);
|
|
71
|
+
setNegotiationHeaders(event, path, config, resolveUrl);
|
|
71
72
|
return;
|
|
72
73
|
}
|
|
73
74
|
if (!isExplicit) {
|
|
@@ -85,7 +86,7 @@ export default defineEventHandler(async (event) => {
|
|
|
85
86
|
canonical_url: canonicalUrl,
|
|
86
87
|
last_updated: contentPage.updatedAt || (/* @__PURE__ */ new Date()).toISOString()
|
|
87
88
|
});
|
|
88
|
-
setMarkdownHeaders(event, path, config);
|
|
89
|
+
setMarkdownHeaders(event, path, config, resolveUrl);
|
|
89
90
|
return `${frontmatter}
|
|
90
91
|
${contentPage.markdown}`;
|
|
91
92
|
}
|
|
@@ -98,7 +99,7 @@ ${contentPage.markdown}`;
|
|
|
98
99
|
return null;
|
|
99
100
|
});
|
|
100
101
|
if (!response) {
|
|
101
|
-
setMarkdownHeaders(event, path, config);
|
|
102
|
+
setMarkdownHeaders(event, path, config, resolveUrl);
|
|
102
103
|
return notFoundMarkdown(canonicalUrl, path, config);
|
|
103
104
|
}
|
|
104
105
|
if (response.status >= 300 && response.status < 400) {
|
|
@@ -113,12 +114,12 @@ ${contentPage.markdown}`;
|
|
|
113
114
|
}
|
|
114
115
|
}
|
|
115
116
|
if (!response.ok) {
|
|
116
|
-
setMarkdownHeaders(event, path, config);
|
|
117
|
+
setMarkdownHeaders(event, path, config, resolveUrl);
|
|
117
118
|
return notFoundMarkdown(canonicalUrl, path, config);
|
|
118
119
|
}
|
|
119
120
|
const contentType = response.headers.get("content-type") || "";
|
|
120
121
|
if (!contentType.includes("text/html")) {
|
|
121
|
-
setMarkdownHeaders(event, path, config);
|
|
122
|
+
setMarkdownHeaders(event, path, config, resolveUrl);
|
|
122
123
|
return notFoundMarkdown(canonicalUrl, path, config);
|
|
123
124
|
}
|
|
124
125
|
const html = await response.text();
|
|
@@ -144,6 +145,6 @@ ${contentPage.markdown}`;
|
|
|
144
145
|
additionalFrontmatter
|
|
145
146
|
}
|
|
146
147
|
);
|
|
147
|
-
setMarkdownHeaders(event, path, config);
|
|
148
|
+
setMarkdownHeaders(event, path, config, resolveUrl);
|
|
148
149
|
return result.markdown;
|
|
149
150
|
});
|
|
@@ -7,7 +7,9 @@ import type { ModulePublicRuntimeConfig } from '../../../module.js';
|
|
|
7
7
|
* `encodeURI` preserves `/` separators and other reserved URL characters.
|
|
8
8
|
*/
|
|
9
9
|
export declare function encodePathForHeader(path: string): string;
|
|
10
|
+
type LinkUrlResolver = (path: string) => string;
|
|
10
11
|
/**
|
|
11
12
|
* Build a comma-joined Link header value with the standard alternates plus i18n hreflang variants.
|
|
12
13
|
*/
|
|
13
|
-
export declare function buildLinkHeader(path: string, variant: 'html' | 'markdown', config: ModulePublicRuntimeConfig): string;
|
|
14
|
+
export declare function buildLinkHeader(path: string, variant: 'html' | 'markdown', config: ModulePublicRuntimeConfig, resolveUrl?: LinkUrlResolver): string;
|
|
15
|
+
export {};
|
|
@@ -1,13 +1,18 @@
|
|
|
1
|
+
import { toMarkdownPath } from "../../markdown-path.js";
|
|
1
2
|
import { computeLocaleAlternates } from "./i18n.js";
|
|
2
3
|
export function encodePathForHeader(path) {
|
|
3
4
|
return encodeURI(path);
|
|
4
5
|
}
|
|
5
|
-
function
|
|
6
|
-
if (
|
|
7
|
-
return
|
|
8
|
-
|
|
6
|
+
function resolveHeaderUrl(path, resolveUrl) {
|
|
7
|
+
if (!resolveUrl)
|
|
8
|
+
return path;
|
|
9
|
+
try {
|
|
10
|
+
return resolveUrl(path);
|
|
11
|
+
} catch {
|
|
12
|
+
return path;
|
|
13
|
+
}
|
|
9
14
|
}
|
|
10
|
-
export function buildLinkHeader(path, variant, config) {
|
|
15
|
+
export function buildLinkHeader(path, variant, config, resolveUrl) {
|
|
11
16
|
const parts = [];
|
|
12
17
|
if (variant === "html") {
|
|
13
18
|
parts.push(`<${encodePathForHeader(toMarkdownPath(path))}>; rel="alternate"; type="text/markdown"`);
|
|
@@ -18,7 +23,7 @@ export function buildLinkHeader(path, variant, config) {
|
|
|
18
23
|
const alternates = computeLocaleAlternates(path, config.i18n);
|
|
19
24
|
for (const alt of alternates) {
|
|
20
25
|
const href = variant === "markdown" ? toMarkdownPath(alt.path) : alt.path;
|
|
21
|
-
parts.push(`<${encodePathForHeader(href)}>; rel="alternate"; hreflang="${alt.hreflang}"`);
|
|
26
|
+
parts.push(`<${encodePathForHeader(resolveHeaderUrl(href, resolveUrl))}>; rel="alternate"; hreflang="${alt.hreflang}"`);
|
|
22
27
|
}
|
|
23
28
|
}
|
|
24
29
|
return parts.join(", ");
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ContentNegotiationResult } from '@mdream/js/negotiate';
|
|
2
2
|
import type { H3Event } from 'h3';
|
|
3
3
|
import type { ModulePublicRuntimeConfig } from '../../module.js';
|
|
4
|
+
export { toMarkdownPath } from '../markdown-path.js';
|
|
4
5
|
export declare function negotiateRepresentation(event: H3Event): ContentNegotiationResult;
|
|
5
6
|
export declare function getMarkdownRenderInfo(event: H3Event, explicitOnly?: boolean): {
|
|
6
7
|
path: string;
|
|
@@ -9,7 +10,6 @@ export declare function getMarkdownRenderInfo(event: H3Event, explicitOnly?: boo
|
|
|
9
10
|
} | {
|
|
10
11
|
notAcceptable: true;
|
|
11
12
|
} | null;
|
|
12
|
-
export declare function toMarkdownPath(path: string): string;
|
|
13
13
|
export declare function clientPrefersMarkdown(event: H3Event): boolean;
|
|
14
14
|
export declare function extractLastUpdated(html: string): string | undefined;
|
|
15
15
|
interface ConvertHtmlOptions {
|
|
@@ -32,4 +32,3 @@ export declare function convertHtmlToMarkdown(html: string, url: string, mdreamO
|
|
|
32
32
|
metaKeywords: string;
|
|
33
33
|
textContent: string;
|
|
34
34
|
}>;
|
|
35
|
-
export {};
|
|
@@ -3,6 +3,7 @@ import { getBotInfo } from "@nuxtjs/robots/util";
|
|
|
3
3
|
import { getHeader, getHeaders } from "h3";
|
|
4
4
|
import { htmlToMarkdown } from "mdream";
|
|
5
5
|
import { useNitroApp } from "nitropack/runtime";
|
|
6
|
+
export { toMarkdownPath } from "../markdown-path.js";
|
|
6
7
|
const RE_NBSP = /\u00A0/g;
|
|
7
8
|
function normalizeWhitespace(text) {
|
|
8
9
|
return text.replace(RE_NBSP, " ");
|
|
@@ -47,6 +48,8 @@ function buildMdreamOptions(url, mdreamOptions, meta, extractUpdatedAt, addition
|
|
|
47
48
|
};
|
|
48
49
|
}
|
|
49
50
|
export function negotiateRepresentation(event) {
|
|
51
|
+
if (import.meta.prerender || getHeader(event, "x-nitro-prerender"))
|
|
52
|
+
return "html";
|
|
50
53
|
const accept = getHeader(event, "accept");
|
|
51
54
|
const secFetchDest = getHeader(event, "sec-fetch-dest");
|
|
52
55
|
if (negotiateContent(accept) === "markdown")
|
|
@@ -91,11 +94,6 @@ function normalizePath(path) {
|
|
|
91
94
|
return path.slice(0, -5) || "/";
|
|
92
95
|
return path;
|
|
93
96
|
}
|
|
94
|
-
export function toMarkdownPath(path) {
|
|
95
|
-
if (path === "/" || path.endsWith("/"))
|
|
96
|
-
return `${path}index.md`;
|
|
97
|
-
return `${path}.md`;
|
|
98
|
-
}
|
|
99
97
|
export function clientPrefersMarkdown(event) {
|
|
100
98
|
return negotiateRepresentation(event) === "markdown";
|
|
101
99
|
}
|
package/dist/runtime/types.d.ts
CHANGED
|
@@ -42,6 +42,12 @@ export interface ModuleOptions {
|
|
|
42
42
|
* Allow Training or fine-tuning AI models.
|
|
43
43
|
*/
|
|
44
44
|
aiTrain?: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Emit the draft Content-Usage robots.txt directive.
|
|
47
|
+
* Set to false to avoid robots.txt validators that do not support it yet.
|
|
48
|
+
* @default true
|
|
49
|
+
*/
|
|
50
|
+
contentUsage?: boolean;
|
|
45
51
|
/**
|
|
46
52
|
* Allow building a search index and providing search results (e.g., returning hyperlinks and short excerpts from your website's contents).
|
|
47
53
|
* Search does not include providing AI-generated search summaries.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nuxt-ai-ready",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.5.1",
|
|
5
5
|
"description": "Best practice AI & LLM discoverability for Nuxt sites.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Harlan Wilton",
|
|
@@ -57,56 +57,56 @@
|
|
|
57
57
|
}
|
|
58
58
|
},
|
|
59
59
|
"dependencies": {
|
|
60
|
-
"@mdream/js": "^1.
|
|
60
|
+
"@mdream/js": "^1.4.1",
|
|
61
61
|
"@nuxt/kit": "^4.4.8",
|
|
62
62
|
"citty": "^0.2.2",
|
|
63
63
|
"consola": "^3.4.2",
|
|
64
64
|
"defu": "^6.1.7",
|
|
65
65
|
"drizzle-orm": "^0.45.2",
|
|
66
|
-
"mdream": "^1.
|
|
67
|
-
"nuxt-site-config": "^4.1.
|
|
68
|
-
"nuxtseo-shared": "^5.
|
|
66
|
+
"mdream": "^1.4.1",
|
|
67
|
+
"nuxt-site-config": "^4.1.1",
|
|
68
|
+
"nuxtseo-shared": "^5.3.1",
|
|
69
69
|
"pathe": "^2.0.3",
|
|
70
70
|
"pkg-types": "^2.3.1",
|
|
71
|
-
"site-config-stack": "^4.
|
|
71
|
+
"site-config-stack": "^4.1.1",
|
|
72
72
|
"ufo": "^1.6.4",
|
|
73
73
|
"uncrypto": "^0.1.3"
|
|
74
74
|
},
|
|
75
75
|
"devDependencies": {
|
|
76
|
-
"@antfu/eslint-config": "^9.
|
|
77
|
-
"@arethetypeswrong/cli": "^0.18.
|
|
78
|
-
"@libsql/client": "^0.17.
|
|
76
|
+
"@antfu/eslint-config": "^9.1.0",
|
|
77
|
+
"@arethetypeswrong/cli": "^0.18.4",
|
|
78
|
+
"@libsql/client": "^0.17.4",
|
|
79
79
|
"@nuxt/content": "^3.14.0",
|
|
80
80
|
"@nuxt/module-builder": "^1.0.2",
|
|
81
81
|
"@nuxt/test-utils": "^4.0.3",
|
|
82
82
|
"@nuxtjs/eslint-config-typescript": "^12.1.0",
|
|
83
83
|
"@nuxtjs/mcp-toolkit": "^0.17.2",
|
|
84
|
-
"@nuxtjs/robots": "^6.
|
|
85
|
-
"@nuxtjs/sitemap": "^8.2.
|
|
84
|
+
"@nuxtjs/robots": "^6.1.1",
|
|
85
|
+
"@nuxtjs/sitemap": "^8.2.1",
|
|
86
86
|
"@types/better-sqlite3": "^7.6.13",
|
|
87
|
-
"@vitest/coverage-v8": "^4.1.
|
|
87
|
+
"@vitest/coverage-v8": "^4.1.9",
|
|
88
88
|
"@vue/test-utils": "^2.4.11",
|
|
89
89
|
"@vueuse/nuxt": "^14.3.0",
|
|
90
|
-
"better-sqlite3": "^12.
|
|
90
|
+
"better-sqlite3": "^12.11.1",
|
|
91
91
|
"bumpp": "^11.1.0",
|
|
92
|
-
"eslint": "^10.
|
|
92
|
+
"eslint": "^10.5.0",
|
|
93
93
|
"eslint-plugin-harlanzw": "^0.17.0",
|
|
94
94
|
"execa": "^9.6.1",
|
|
95
|
-
"happy-dom": "^20.10.
|
|
95
|
+
"happy-dom": "^20.10.6",
|
|
96
96
|
"nitropack": "^2.13.4",
|
|
97
97
|
"nuxt": "^4.4.8",
|
|
98
|
-
"nuxt-site-config": "^4.1.
|
|
99
|
-
"nuxtseo-layer-devtools": "^5.
|
|
100
|
-
"playwright": "^1.
|
|
101
|
-
"playwright-core": "^1.
|
|
98
|
+
"nuxt-site-config": "^4.1.1",
|
|
99
|
+
"nuxtseo-layer-devtools": "^5.3.1",
|
|
100
|
+
"playwright": "^1.61.1",
|
|
101
|
+
"playwright-core": "^1.61.1",
|
|
102
102
|
"tinyglobby": "^0.2.17",
|
|
103
103
|
"typescript": "^6.0.3",
|
|
104
104
|
"unbuild": "^3.6.1",
|
|
105
|
-
"vitest": "^4.1.
|
|
106
|
-
"vue": "^3.5.
|
|
105
|
+
"vitest": "^4.1.9",
|
|
106
|
+
"vue": "^3.5.38",
|
|
107
107
|
"vue-router": "^5.1.0",
|
|
108
|
-
"vue-tsc": "^3.3.
|
|
109
|
-
"wrangler": "^4.
|
|
108
|
+
"vue-tsc": "^3.3.5",
|
|
109
|
+
"wrangler": "^4.104.0",
|
|
110
110
|
"zod": "^4.4.3"
|
|
111
111
|
},
|
|
112
112
|
"scripts": {
|