nuxt-ai-ready 1.3.2 → 1.3.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/devtools/200.html +1 -1
- package/dist/devtools/404.html +1 -1
- package/dist/devtools/_nuxt/{CG4YVUJc.js → B79_Suj8.js} +1 -1
- package/dist/devtools/_nuxt/{DGjxyRbU.js → BxZ17gC1.js} +1 -1
- package/dist/devtools/_nuxt/{CW4u22fk.js → CXxgQd7T.js} +1 -1
- package/dist/devtools/_nuxt/{nscivqEG.js → DQ3joNC8.js} +10 -10
- package/dist/devtools/_nuxt/{DsIImnSh.js → DQhdjwv3.js} +1 -1
- package/dist/devtools/_nuxt/{D1cMhZtf.js → DaGccE64.js} +1 -1
- package/dist/devtools/_nuxt/{DevtoolsPanel.CkdsJGul.css → DevtoolsPanel.DMk0hJ4w.css} +1 -1
- package/dist/devtools/_nuxt/builds/latest.json +1 -1
- package/dist/devtools/_nuxt/builds/meta/957d2ff6-c798-4b14-9a4c-b6d80a8e2ffe.json +1 -0
- package/dist/devtools/_nuxt/entry.DXQs-riX.css +1 -0
- package/dist/devtools/_nuxt/{CPVPS-Dp.js → fLpD8y9n.js} +1 -1
- package/dist/devtools/_nuxt/index.Dz3IMhwB.css +1 -0
- package/dist/devtools/debug/index.html +1 -1
- package/dist/devtools/docs/index.html +1 -1
- package/dist/devtools/index.html +1 -1
- package/dist/devtools/llms-txt/index.html +1 -1
- package/dist/devtools/pages/index.html +1 -1
- package/dist/module.json +1 -1
- package/dist/runtime/server/db/drizzle/queries.js +9 -5
- package/dist/runtime/server/db/queries.js +18 -12
- package/dist/runtime/server/middleware/markdown.js +5 -17
- package/dist/runtime/server/utils/indexnow.js +8 -3
- package/dist/runtime/server/utils/link-header.d.ts +13 -0
- package/dist/runtime/server/utils/link-header.js +25 -0
- package/package.json +15 -15
- package/dist/devtools/_nuxt/builds/meta/69a96361-b999-4d67-86d2-e31b3909be29.json +0 -1
- package/dist/devtools/_nuxt/entry.BbygA2Ya.css +0 -1
- package/dist/devtools/_nuxt/index.e05QIQpk.css +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/__nuxt-ai-ready/_nuxt/entry.
|
|
1
|
+
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/__nuxt-ai-ready/_nuxt/entry.DXQs-riX.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/__nuxt-ai-ready/_nuxt/DQ3joNC8.js"><script type="module" src="/__nuxt-ai-ready/_nuxt/DQ3joNC8.js" crossorigin></script><script>"use strict";(()=>{const t=window,e=document.documentElement,c=["dark","light"],n=getStorageValue("localStorage","nuxt-color-mode")||"system";let i=n==="system"?u():n;const r=e.getAttribute("data-color-mode-forced");r&&(i=r),l(i),t["__NUXT_COLOR_MODE__"]={preference:n,value:i,getColorScheme:u,addColorScheme:l,removeColorScheme:d};function l(o){const s=""+o+"",a="";e.classList?e.classList.add(s):e.className+=" "+s,a&&e.setAttribute("data-"+a,o)}function d(o){const s=""+o+"",a="";e.classList?e.classList.remove(s):e.className=e.className.replace(new RegExp(s,"g"),""),a&&e.removeAttribute("data-"+a)}function f(o){return t.matchMedia("(prefers-color-scheme"+o+")")}function u(){if(t.matchMedia&&f("").media!=="not all"){for(const o of c)if(f(":"+o).matches)return o}return"light"}})();function getStorageValue(t,e){switch(t){case"localStorage":return window.localStorage.getItem(e);case"sessionStorage":return window.sessionStorage.getItem(e);case"cookie":return getCookie(e);default:return null}}function getCookie(t){const c=("; "+window.document.cookie).split("; "+t+"=");if(c.length===2)return c.pop()?.split(";").shift()}</script></head><body><div id="__nuxt" class="isolate"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__nuxt-ai-ready",buildId:"957d2ff6-c798-4b14-9a4c-b6d80a8e2ffe",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1779022491890,false]</script></body></html>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/__nuxt-ai-ready/_nuxt/entry.
|
|
1
|
+
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/__nuxt-ai-ready/_nuxt/entry.DXQs-riX.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/__nuxt-ai-ready/_nuxt/DQ3joNC8.js"><script type="module" src="/__nuxt-ai-ready/_nuxt/DQ3joNC8.js" crossorigin></script><script>"use strict";(()=>{const t=window,e=document.documentElement,c=["dark","light"],n=getStorageValue("localStorage","nuxt-color-mode")||"system";let i=n==="system"?u():n;const r=e.getAttribute("data-color-mode-forced");r&&(i=r),l(i),t["__NUXT_COLOR_MODE__"]={preference:n,value:i,getColorScheme:u,addColorScheme:l,removeColorScheme:d};function l(o){const s=""+o+"",a="";e.classList?e.classList.add(s):e.className+=" "+s,a&&e.setAttribute("data-"+a,o)}function d(o){const s=""+o+"",a="";e.classList?e.classList.remove(s):e.className=e.className.replace(new RegExp(s,"g"),""),a&&e.removeAttribute("data-"+a)}function f(o){return t.matchMedia("(prefers-color-scheme"+o+")")}function u(){if(t.matchMedia&&f("").media!=="not all"){for(const o of c)if(f(":"+o).matches)return o}return"light"}})();function getStorageValue(t,e){switch(t){case"localStorage":return window.localStorage.getItem(e);case"sessionStorage":return window.sessionStorage.getItem(e);case"cookie":return getCookie(e);default:return null}}function getCookie(t){const c=("; "+window.document.cookie).split("; "+t+"=");if(c.length===2)return c.pop()?.split(";").shift()}</script></head><body><div id="__nuxt" class="isolate"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__nuxt-ai-ready",buildId:"957d2ff6-c798-4b14-9a4c-b6d80a8e2ffe",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1779022491892,false]</script></body></html>
|
package/dist/devtools/index.html
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/__nuxt-ai-ready/_nuxt/entry.
|
|
1
|
+
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/__nuxt-ai-ready/_nuxt/entry.DXQs-riX.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/__nuxt-ai-ready/_nuxt/DQ3joNC8.js"><script type="module" src="/__nuxt-ai-ready/_nuxt/DQ3joNC8.js" crossorigin></script><script>"use strict";(()=>{const t=window,e=document.documentElement,c=["dark","light"],n=getStorageValue("localStorage","nuxt-color-mode")||"system";let i=n==="system"?u():n;const r=e.getAttribute("data-color-mode-forced");r&&(i=r),l(i),t["__NUXT_COLOR_MODE__"]={preference:n,value:i,getColorScheme:u,addColorScheme:l,removeColorScheme:d};function l(o){const s=""+o+"",a="";e.classList?e.classList.add(s):e.className+=" "+s,a&&e.setAttribute("data-"+a,o)}function d(o){const s=""+o+"",a="";e.classList?e.classList.remove(s):e.className=e.className.replace(new RegExp(s,"g"),""),a&&e.removeAttribute("data-"+a)}function f(o){return t.matchMedia("(prefers-color-scheme"+o+")")}function u(){if(t.matchMedia&&f("").media!=="not all"){for(const o of c)if(f(":"+o).matches)return o}return"light"}})();function getStorageValue(t,e){switch(t){case"localStorage":return window.localStorage.getItem(e);case"sessionStorage":return window.sessionStorage.getItem(e);case"cookie":return getCookie(e);default:return null}}function getCookie(t){const c=("; "+window.document.cookie).split("; "+t+"=");if(c.length===2)return c.pop()?.split(";").shift()}</script></head><body><div id="__nuxt" class="isolate"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__nuxt-ai-ready",buildId:"957d2ff6-c798-4b14-9a4c-b6d80a8e2ffe",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1779022491892,false]</script></body></html>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/__nuxt-ai-ready/_nuxt/entry.
|
|
1
|
+
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/__nuxt-ai-ready/_nuxt/entry.DXQs-riX.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/__nuxt-ai-ready/_nuxt/DQ3joNC8.js"><script type="module" src="/__nuxt-ai-ready/_nuxt/DQ3joNC8.js" crossorigin></script><script>"use strict";(()=>{const t=window,e=document.documentElement,c=["dark","light"],n=getStorageValue("localStorage","nuxt-color-mode")||"system";let i=n==="system"?u():n;const r=e.getAttribute("data-color-mode-forced");r&&(i=r),l(i),t["__NUXT_COLOR_MODE__"]={preference:n,value:i,getColorScheme:u,addColorScheme:l,removeColorScheme:d};function l(o){const s=""+o+"",a="";e.classList?e.classList.add(s):e.className+=" "+s,a&&e.setAttribute("data-"+a,o)}function d(o){const s=""+o+"",a="";e.classList?e.classList.remove(s):e.className=e.className.replace(new RegExp(s,"g"),""),a&&e.removeAttribute("data-"+a)}function f(o){return t.matchMedia("(prefers-color-scheme"+o+")")}function u(){if(t.matchMedia&&f("").media!=="not all"){for(const o of c)if(f(":"+o).matches)return o}return"light"}})();function getStorageValue(t,e){switch(t){case"localStorage":return window.localStorage.getItem(e);case"sessionStorage":return window.sessionStorage.getItem(e);case"cookie":return getCookie(e);default:return null}}function getCookie(t){const c=("; "+window.document.cookie).split("; "+t+"=");if(c.length===2)return c.pop()?.split(";").shift()}</script></head><body><div id="__nuxt" class="isolate"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__nuxt-ai-ready",buildId:"957d2ff6-c798-4b14-9a4c-b6d80a8e2ffe",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1779022491892,false]</script></body></html>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/__nuxt-ai-ready/_nuxt/entry.
|
|
1
|
+
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/__nuxt-ai-ready/_nuxt/entry.DXQs-riX.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/__nuxt-ai-ready/_nuxt/DQ3joNC8.js"><script type="module" src="/__nuxt-ai-ready/_nuxt/DQ3joNC8.js" crossorigin></script><script>"use strict";(()=>{const t=window,e=document.documentElement,c=["dark","light"],n=getStorageValue("localStorage","nuxt-color-mode")||"system";let i=n==="system"?u():n;const r=e.getAttribute("data-color-mode-forced");r&&(i=r),l(i),t["__NUXT_COLOR_MODE__"]={preference:n,value:i,getColorScheme:u,addColorScheme:l,removeColorScheme:d};function l(o){const s=""+o+"",a="";e.classList?e.classList.add(s):e.className+=" "+s,a&&e.setAttribute("data-"+a,o)}function d(o){const s=""+o+"",a="";e.classList?e.classList.remove(s):e.className=e.className.replace(new RegExp(s,"g"),""),a&&e.removeAttribute("data-"+a)}function f(o){return t.matchMedia("(prefers-color-scheme"+o+")")}function u(){if(t.matchMedia&&f("").media!=="not all"){for(const o of c)if(f(":"+o).matches)return o}return"light"}})();function getStorageValue(t,e){switch(t){case"localStorage":return window.localStorage.getItem(e);case"sessionStorage":return window.sessionStorage.getItem(e);case"cookie":return getCookie(e);default:return null}}function getCookie(t){const c=("; "+window.document.cookie).split("; "+t+"=");if(c.length===2)return c.pop()?.split(";").shift()}</script></head><body><div id="__nuxt" class="isolate"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__nuxt-ai-ready",buildId:"957d2ff6-c798-4b14-9a4c-b6d80a8e2ffe",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1779022491892,false]</script></body></html>
|
package/dist/module.json
CHANGED
|
@@ -464,11 +464,15 @@ export async function markIndexNowSynced(event, routes) {
|
|
|
464
464
|
return;
|
|
465
465
|
const client = await useDrizzle(event);
|
|
466
466
|
const now = Date.now();
|
|
467
|
-
const
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
467
|
+
const D1_MAX_IN_ROUTES = 99;
|
|
468
|
+
for (let i = 0; i < routes.length; i += D1_MAX_IN_ROUTES) {
|
|
469
|
+
const batch = routes.slice(i, i + D1_MAX_IN_ROUTES);
|
|
470
|
+
const placeholders = batch.map(() => "?").join(",");
|
|
471
|
+
await client.db.run(
|
|
472
|
+
sql.raw(`UPDATE ai_ready_pages SET indexnow_synced_at = ? WHERE route IN (${placeholders})`),
|
|
473
|
+
[now, ...batch]
|
|
474
|
+
);
|
|
475
|
+
}
|
|
472
476
|
}
|
|
473
477
|
function rowToCronRun(row) {
|
|
474
478
|
return {
|
|
@@ -381,16 +381,27 @@ export async function countPagesNeedingIndexNowSync(event) {
|
|
|
381
381
|
`);
|
|
382
382
|
return row?.count || 0;
|
|
383
383
|
}
|
|
384
|
+
const D1_MAX_IN_ROUTES = 99;
|
|
385
|
+
function chunk(items, size) {
|
|
386
|
+
const out = [];
|
|
387
|
+
for (let i = 0; i < items.length; i += size)
|
|
388
|
+
out.push(items.slice(i, i + size));
|
|
389
|
+
return out;
|
|
390
|
+
}
|
|
391
|
+
async function markRoutesSyncedChunked(db, routes, now) {
|
|
392
|
+
for (const batch of chunk(routes, D1_MAX_IN_ROUTES)) {
|
|
393
|
+
const placeholders = batch.map(() => "?").join(",");
|
|
394
|
+
await db.exec(
|
|
395
|
+
`UPDATE ai_ready_pages SET indexnow_synced_at = ? WHERE route IN (${placeholders})`,
|
|
396
|
+
[now, ...batch]
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
384
400
|
export async function markIndexNowSynced(event, routes) {
|
|
385
401
|
const db = await getDb(event);
|
|
386
402
|
if (!db || routes.length === 0)
|
|
387
403
|
return;
|
|
388
|
-
|
|
389
|
-
const placeholders = routes.map(() => "?").join(",");
|
|
390
|
-
await db.exec(
|
|
391
|
-
`UPDATE ai_ready_pages SET indexnow_synced_at = ? WHERE route IN (${placeholders})`,
|
|
392
|
-
[now, ...routes]
|
|
393
|
-
);
|
|
404
|
+
await markRoutesSyncedChunked(db, routes, Date.now());
|
|
394
405
|
}
|
|
395
406
|
export async function updateIndexNowStats(event, submitted, error) {
|
|
396
407
|
const db = await getDb(event);
|
|
@@ -422,13 +433,8 @@ export async function batchIndexNowUpdate(event, routes, submitted) {
|
|
|
422
433
|
if (!db || routes.length === 0)
|
|
423
434
|
return;
|
|
424
435
|
const now = Date.now();
|
|
425
|
-
const placeholders = routes.map(() => "?").join(",");
|
|
426
436
|
await Promise.all([
|
|
427
|
-
|
|
428
|
-
db.exec(
|
|
429
|
-
`UPDATE ai_ready_pages SET indexnow_synced_at = ? WHERE route IN (${placeholders})`,
|
|
430
|
-
[now, ...routes]
|
|
431
|
-
),
|
|
437
|
+
markRoutesSyncedChunked(db, routes, now),
|
|
432
438
|
// Atomic increment total submitted
|
|
433
439
|
db.exec(`
|
|
434
440
|
INSERT INTO _ai_ready_info (id, value) VALUES ('indexnow_total_submitted', ?)
|
|
@@ -7,23 +7,8 @@ import { convertHtmlToMarkdown, extractLastUpdated, getMarkdownRenderInfo, toMar
|
|
|
7
7
|
import { tryGetContentMarkdown } from "../utils/content.js";
|
|
8
8
|
import { buildFrontmatter } from "../utils/frontmatter.js";
|
|
9
9
|
import { computeLocaleAlternates, resolveLocaleFromRoute } from "../utils/i18n.js";
|
|
10
|
+
import { buildLinkHeader } from "../utils/link-header.js";
|
|
10
11
|
const INTERNAL_HEADER = "x-ai-ready-internal";
|
|
11
|
-
function buildLinkHeader(path, variant, config) {
|
|
12
|
-
const parts = [];
|
|
13
|
-
if (variant === "html") {
|
|
14
|
-
parts.push(`<${toMarkdownPath(path)}>; rel="alternate"; type="text/markdown"`);
|
|
15
|
-
} else {
|
|
16
|
-
parts.push(`<${path}>; rel="alternate"; type="text/html"`);
|
|
17
|
-
}
|
|
18
|
-
if (config.i18n) {
|
|
19
|
-
const alternates = computeLocaleAlternates(path, config.i18n);
|
|
20
|
-
for (const alt of alternates) {
|
|
21
|
-
const href = variant === "markdown" ? toMarkdownPath(alt.path) : alt.path;
|
|
22
|
-
parts.push(`<${href}>; rel="alternate"; hreflang="${alt.hreflang}"`);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
return parts.join(", ");
|
|
26
|
-
}
|
|
27
12
|
function setNegotiationHeaders(event, path, config) {
|
|
28
13
|
setHeader(event, "vary", "Accept, Sec-Fetch-Dest");
|
|
29
14
|
setHeader(event, "link", buildLinkHeader(path, "html", config));
|
|
@@ -138,7 +123,10 @@ ${contentPage.markdown}`;
|
|
|
138
123
|
}
|
|
139
124
|
const html = await response.text();
|
|
140
125
|
logger.debug(`[markdown] Fetched HTML for ${path} (${html.length} bytes)`);
|
|
141
|
-
const dbPage = await queryPages(event, { route: path }).catch(() =>
|
|
126
|
+
const dbPage = await queryPages(event, { route: path }).catch((err) => {
|
|
127
|
+
logger.debug(`[markdown] DB lookup failed for ${path}:`, err);
|
|
128
|
+
return void 0;
|
|
129
|
+
});
|
|
142
130
|
const lastUpdated = dbPage?.updatedAt || extractLastUpdated(html) || (/* @__PURE__ */ new Date()).toISOString();
|
|
143
131
|
const additionalFrontmatter = {
|
|
144
132
|
canonical_url: canonicalUrl,
|
|
@@ -16,17 +16,22 @@ import { createUniversalContext } from "./context.js";
|
|
|
16
16
|
import { submitToIndexNowShared } from "./indexnow-shared.js";
|
|
17
17
|
const BACKOFF_MINUTES = [5, 10, 20, 40, 60];
|
|
18
18
|
async function getBackoffInfo(event) {
|
|
19
|
-
const value = await getInfoValue(event, "indexnow_backoff").catch(() =>
|
|
19
|
+
const value = await getInfoValue(event, "indexnow_backoff").catch((err) => {
|
|
20
|
+
logger.debug("[indexnow] Failed to read backoff state:", err);
|
|
21
|
+
return null;
|
|
22
|
+
});
|
|
20
23
|
if (!value)
|
|
21
24
|
return null;
|
|
22
25
|
return JSON.parse(value);
|
|
23
26
|
}
|
|
24
27
|
async function setBackoffInfo(event, info) {
|
|
25
28
|
if (info) {
|
|
26
|
-
await setInfoValue(event, "indexnow_backoff", JSON.stringify(info)).catch(() => {
|
|
29
|
+
await setInfoValue(event, "indexnow_backoff", JSON.stringify(info)).catch((err) => {
|
|
30
|
+
logger.debug("[indexnow] Failed to persist backoff state:", err);
|
|
27
31
|
});
|
|
28
32
|
} else {
|
|
29
|
-
await deleteInfoValue(event, "indexnow_backoff").catch(() => {
|
|
33
|
+
await deleteInfoValue(event, "indexnow_backoff").catch((err) => {
|
|
34
|
+
logger.debug("[indexnow] Failed to clear backoff state:", err);
|
|
30
35
|
});
|
|
31
36
|
}
|
|
32
37
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ModulePublicRuntimeConfig } from '../../../module.js';
|
|
2
|
+
/**
|
|
3
|
+
* Encode a URL path for safe inclusion in an HTTP header value.
|
|
4
|
+
* HTTP header values must be ASCII-only per RFC 9110 §5.5, so paths containing
|
|
5
|
+
* non-Latin characters (e.g. Chinese, Cyrillic) must be percent-encoded or
|
|
6
|
+
* Cloudflare (and other RFC-compliant runtimes) will reject the header.
|
|
7
|
+
* `encodeURI` preserves `/` separators and other reserved URL characters.
|
|
8
|
+
*/
|
|
9
|
+
export declare function encodePathForHeader(path: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* Build a comma-joined Link header value with the standard alternates plus i18n hreflang variants.
|
|
12
|
+
*/
|
|
13
|
+
export declare function buildLinkHeader(path: string, variant: 'html' | 'markdown', config: ModulePublicRuntimeConfig): string;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { computeLocaleAlternates } from "./i18n.js";
|
|
2
|
+
export function encodePathForHeader(path) {
|
|
3
|
+
return encodeURI(path);
|
|
4
|
+
}
|
|
5
|
+
function toMarkdownPath(path) {
|
|
6
|
+
if (path === "/" || path.endsWith("/"))
|
|
7
|
+
return `${path}index.md`;
|
|
8
|
+
return `${path}.md`;
|
|
9
|
+
}
|
|
10
|
+
export function buildLinkHeader(path, variant, config) {
|
|
11
|
+
const parts = [];
|
|
12
|
+
if (variant === "html") {
|
|
13
|
+
parts.push(`<${encodePathForHeader(toMarkdownPath(path))}>; rel="alternate"; type="text/markdown"`);
|
|
14
|
+
} else {
|
|
15
|
+
parts.push(`<${encodePathForHeader(path)}>; rel="alternate"; type="text/html"`);
|
|
16
|
+
}
|
|
17
|
+
if (config.i18n) {
|
|
18
|
+
const alternates = computeLocaleAlternates(path, config.i18n);
|
|
19
|
+
for (const alt of alternates) {
|
|
20
|
+
const href = variant === "markdown" ? toMarkdownPath(alt.path) : alt.path;
|
|
21
|
+
parts.push(`<${encodePathForHeader(href)}>; rel="alternate"; hreflang="${alt.hreflang}"`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return parts.join(", ");
|
|
25
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nuxt-ai-ready",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.3.
|
|
4
|
+
"version": "1.3.6",
|
|
5
5
|
"description": "Best practice AI & LLM discoverability for Nuxt sites.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Harlan Wilton",
|
|
@@ -58,11 +58,11 @@
|
|
|
58
58
|
},
|
|
59
59
|
"dependencies": {
|
|
60
60
|
"@mdream/js": "^1.1.0",
|
|
61
|
-
"@nuxt/kit": "^4.4.
|
|
61
|
+
"@nuxt/kit": "^4.4.5",
|
|
62
62
|
"citty": "^0.2.2",
|
|
63
63
|
"consola": "^3.4.2",
|
|
64
64
|
"defu": "^6.1.7",
|
|
65
|
-
"drizzle-orm": "^0.45.
|
|
65
|
+
"drizzle-orm": "^0.45.2",
|
|
66
66
|
"mdream": "^1.1.0",
|
|
67
67
|
"nuxt-site-config": "^4.0.8",
|
|
68
68
|
"nuxtseo-shared": "^5.1.3",
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
"uncrypto": "^0.1.3"
|
|
74
74
|
},
|
|
75
75
|
"devDependencies": {
|
|
76
|
-
"@antfu/eslint-config": "^
|
|
76
|
+
"@antfu/eslint-config": "^9.0.0",
|
|
77
77
|
"@arethetypeswrong/cli": "^0.18.2",
|
|
78
78
|
"@libsql/client": "^0.17.3",
|
|
79
79
|
"@nuxt/content": "^3.13.0",
|
|
@@ -84,27 +84,27 @@
|
|
|
84
84
|
"@nuxtjs/robots": "^6.0.8",
|
|
85
85
|
"@nuxtjs/sitemap": "^8.0.15",
|
|
86
86
|
"@types/better-sqlite3": "^7.6.13",
|
|
87
|
-
"@vitest/coverage-v8": "^4.1.
|
|
87
|
+
"@vitest/coverage-v8": "^4.1.6",
|
|
88
88
|
"@vue/test-utils": "^2.4.10",
|
|
89
89
|
"@vueuse/nuxt": "^14.3.0",
|
|
90
|
-
"better-sqlite3": "^12.
|
|
90
|
+
"better-sqlite3": "^12.10.0",
|
|
91
91
|
"bumpp": "^11.1.0",
|
|
92
|
-
"eslint": "^10.
|
|
93
|
-
"eslint-plugin-harlanzw": "^0.
|
|
92
|
+
"eslint": "^10.4.0",
|
|
93
|
+
"eslint-plugin-harlanzw": "^0.15.0",
|
|
94
94
|
"execa": "^9.6.1",
|
|
95
95
|
"happy-dom": "^20.9.0",
|
|
96
|
-
"nuxt": "^4.4.
|
|
96
|
+
"nuxt": "^4.4.5",
|
|
97
97
|
"nuxt-site-config": "^4.0.8",
|
|
98
|
-
"playwright": "^1.
|
|
99
|
-
"playwright-core": "^1.
|
|
98
|
+
"playwright": "^1.60.0",
|
|
99
|
+
"playwright-core": "^1.60.0",
|
|
100
100
|
"tinyglobby": "^0.2.16",
|
|
101
101
|
"typescript": "^6.0.3",
|
|
102
102
|
"unbuild": "^3.6.1",
|
|
103
|
-
"vitest": "^4.1.
|
|
103
|
+
"vitest": "^4.1.6",
|
|
104
104
|
"vue": "^3.5.34",
|
|
105
|
-
"vue-router": "^5.0.
|
|
106
|
-
"vue-tsc": "^3.2.
|
|
107
|
-
"wrangler": "^4.
|
|
105
|
+
"vue-router": "^5.0.7",
|
|
106
|
+
"vue-tsc": "^3.2.9",
|
|
107
|
+
"wrangler": "^4.92.0",
|
|
108
108
|
"zod": "^4.4.3"
|
|
109
109
|
},
|
|
110
110
|
"scripts": {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"id":"69a96361-b999-4d67-86d2-e31b3909be29","timestamp":1778236373198,"prerendered":[]}
|