nuxt-ai-ready 0.12.2 → 1.0.0

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.
Files changed (52) hide show
  1. package/dist/cli.mjs +54 -12
  2. package/dist/devtools/200.html +1 -0
  3. package/dist/devtools/404.html +1 -0
  4. package/dist/devtools/_nuxt/B3LnU2ld.js +2 -0
  5. package/dist/devtools/_nuxt/BJy7_Lqa.js +30 -0
  6. package/dist/devtools/_nuxt/DevtoolsPanel.DAmYbc9j.css +1 -0
  7. package/dist/devtools/_nuxt/DevtoolsSection.aQbMzM3b.css +1 -0
  8. package/dist/devtools/_nuxt/DmG3LGyr.js +1 -0
  9. package/dist/devtools/_nuxt/DyapScGI.js +1 -0
  10. package/dist/devtools/_nuxt/ShOy6-p1.js +1 -0
  11. package/dist/devtools/_nuxt/Ud9k3yqB.js +1 -0
  12. package/dist/devtools/_nuxt/builds/latest.json +1 -0
  13. package/dist/devtools/_nuxt/builds/meta/cd2130f1-f79d-4ea7-b399-0dcc99955804.json +1 -0
  14. package/dist/devtools/_nuxt/entry.CZtw_6f4.css +1 -0
  15. package/dist/devtools/_nuxt/fira-code.Bc8wnsZt.woff2 +0 -0
  16. package/dist/devtools/_nuxt/hubot-sans.DLGyhQVu.woff2 +0 -0
  17. package/dist/devtools/_nuxt/index.Bvm0ah1m.css +1 -0
  18. package/dist/devtools/_nuxt/llms-txt.Bd3XkKsE.css +1 -0
  19. package/dist/devtools/_nuxt/pNxHs6n0.js +1 -0
  20. package/dist/devtools/_nuxt/w8OrmFD1.js +1 -0
  21. package/dist/devtools/debug/index.html +1 -0
  22. package/dist/devtools/docs/index.html +1 -0
  23. package/dist/devtools/index.html +1 -0
  24. package/dist/devtools/llms-txt/index.html +1 -0
  25. package/dist/devtools/pages/index.html +1 -0
  26. package/dist/module.d.mts +1 -1
  27. package/dist/module.json +1 -1
  28. package/dist/module.mjs +46 -91
  29. package/dist/runtime/app/plugins/md-hints.prerender.d.ts +1 -1
  30. package/dist/runtime/llms-txt-format.js +11 -4
  31. package/dist/runtime/server/db/queries.d.ts +2 -2
  32. package/dist/runtime/server/db/queries.js +24 -14
  33. package/dist/runtime/server/mcp/resources/pages.js +19 -10
  34. package/dist/runtime/server/routes/__ai-ready/cron.get.js +4 -10
  35. package/dist/runtime/server/routes/__ai-ready/devtools.get.d.ts +2 -0
  36. package/dist/runtime/server/routes/__ai-ready/devtools.get.js +52 -0
  37. package/dist/runtime/server/routes/__ai-ready/indexnow.post.js +3 -7
  38. package/dist/runtime/server/routes/__ai-ready/poll.post.js +7 -11
  39. package/dist/runtime/server/routes/__ai-ready/prune.post.js +5 -7
  40. package/dist/runtime/server/routes/__ai-ready/restore.post.js +4 -10
  41. package/dist/runtime/server/routes/__ai-ready/status.get.js +3 -7
  42. package/dist/runtime/server/routes/__ai-ready-debug.get.d.ts +1 -1
  43. package/dist/runtime/server/routes/__ai-ready-debug.get.js +7 -3
  44. package/dist/runtime/server/routes/llms.txt.get.js +2 -2
  45. package/dist/runtime/server/utils/auth.d.ts +9 -0
  46. package/dist/runtime/server/utils/auth.js +20 -0
  47. package/dist/runtime/server/utils/indexPage.js +1 -1
  48. package/dist/runtime/server/utils/runCron.js +3 -3
  49. package/dist/runtime/server/utils.d.ts +1 -1
  50. package/dist/runtime/server/utils.js +10 -13
  51. package/dist/runtime/types.d.ts +18 -17
  52. package/package.json +28 -37
package/dist/cli.mjs CHANGED
@@ -14,6 +14,9 @@ async function getSecret(cwd) {
14
14
  }
15
15
  return fsp.readFile(secretPath, "utf-8").then((s) => s.trim()).catch(() => null);
16
16
  }
17
+ function authHeaders(secret) {
18
+ return { Authorization: `Bearer ${secret}` };
19
+ }
17
20
  const main = defineCommand({
18
21
  meta: {
19
22
  name: "nuxt-ai-ready",
@@ -46,9 +49,9 @@ const main = defineCommand({
46
49
  consola.error("No secret found. Run `nuxi dev` or `nuxi build` first to generate one.");
47
50
  return;
48
51
  }
49
- const url = `${args.url}/__ai-ready/status?secret=${secret}`;
52
+ const url = `${args.url}/__ai-ready/status`;
50
53
  consola.info(`Fetching status from ${args.url}...`);
51
- const res = await fetch(url).then((r) => r.json()).catch((err) => {
54
+ const res = await fetch(url, { headers: authHeaders(secret) }).then((r) => r.json()).catch((err) => {
52
55
  consola.error(`Failed to connect: ${err.message}`);
53
56
  return null;
54
57
  });
@@ -58,6 +61,20 @@ const main = defineCommand({
58
61
  consola.info(`Total pages: ${colors.cyan(res.total?.toString() || "0")}`);
59
62
  consola.info(`Indexed: ${colors.green(res.indexed?.toString() || "0")}`);
60
63
  consola.info(`Pending: ${colors.yellow(res.pending?.toString() || "0")}`);
64
+ if (res.activity) {
65
+ consola.log("");
66
+ consola.info(colors.bold("Activity:"));
67
+ consola.info(` Last 1h: ${colors.cyan(res.activity.last1h?.toString() || "0")} pages indexed`);
68
+ consola.info(` Last 24h: ${colors.cyan(res.activity.last24h?.toString() || "0")} pages indexed`);
69
+ if (res.activity.recentPages?.length) {
70
+ consola.info(` Recent:`);
71
+ for (const p of res.activity.recentPages.slice(0, 5)) {
72
+ const ago = Date.now() - p.indexedAt;
73
+ const agoStr = ago < 6e4 ? `${Math.round(ago / 1e3)}s` : ago < 36e5 ? `${Math.round(ago / 6e4)}m` : `${Math.round(ago / 36e5)}h`;
74
+ consola.info(` ${colors.dim(`${agoStr} ago`)} ${p.route} ${colors.dim(p.title || "")}`);
75
+ }
76
+ }
77
+ }
61
78
  if (res.indexNow) {
62
79
  consola.log("");
63
80
  consola.info(colors.bold("IndexNow:"));
@@ -65,11 +82,36 @@ const main = defineCommand({
65
82
  consola.info(` Total submitted: ${colors.green(res.indexNow.totalSubmitted?.toString() || "0")}`);
66
83
  if (res.indexNow.lastSubmittedAt) {
67
84
  const date = new Date(res.indexNow.lastSubmittedAt);
68
- consola.info(` Last submitted: ${colors.dim(date.toISOString())}`);
85
+ consola.info(` Last sync: ${colors.dim(date.toISOString())}`);
69
86
  }
70
87
  if (res.indexNow.lastError) {
71
88
  consola.info(` Last error: ${colors.red(res.indexNow.lastError)}`);
72
89
  }
90
+ if (res.indexNow.backoff?.active) {
91
+ const remainMin = Math.ceil((res.indexNow.backoff.remainingMs || 0) / 6e4);
92
+ consola.warn(` Backoff: ${colors.yellow(`${remainMin}m remaining`)} (attempt ${res.indexNow.backoff.attempt})`);
93
+ }
94
+ }
95
+ if (res.cron) {
96
+ consola.log("");
97
+ consola.info(colors.bold("Cron:"));
98
+ if (res.cron.lock?.held) {
99
+ consola.warn(` Lock: ${colors.yellow("held")} (${Math.round((res.cron.lock.elapsedMs || 0) / 1e3)}s)`);
100
+ }
101
+ if (res.cron.recentRuns?.length) {
102
+ for (const run of res.cron.recentRuns) {
103
+ const status = run.status === "success" ? colors.green(run.status) : run.status === "error" ? colors.red(run.status) : colors.yellow(run.status);
104
+ consola.info(` ${colors.dim(new Date(run.startedAt).toLocaleTimeString())} ${status} ${colors.dim(`${run.durationMs || 0}ms`)} ${run.pagesIndexed ? `${run.pagesIndexed} indexed` : ""}`);
105
+ }
106
+ }
107
+ }
108
+ if (res.sitemaps?.length) {
109
+ consola.log("");
110
+ consola.info(colors.bold("Sitemaps:"));
111
+ for (const s of res.sitemaps) {
112
+ const err = s.errorCount > 0 ? colors.red(` (${s.errorCount} errors)`) : "";
113
+ consola.info(` ${s.name}: ${colors.cyan(s.urlCount?.toString() || "0")} URLs${err}`);
114
+ }
73
115
  }
74
116
  }
75
117
  }),
@@ -109,7 +151,7 @@ const main = defineCommand({
109
151
  consola.error("No secret found. Run `nuxi dev` or `nuxi build` first.");
110
152
  return;
111
153
  }
112
- const params = new URLSearchParams({ secret });
154
+ const params = new URLSearchParams();
113
155
  if (args.all) {
114
156
  params.set("all", "true");
115
157
  } else {
@@ -117,7 +159,7 @@ const main = defineCommand({
117
159
  }
118
160
  const url = `${args.url}/__ai-ready/poll?${params}`;
119
161
  consola.info(`Triggering poll at ${args.url}...`);
120
- const res = await fetch(url, { method: "POST" }).then((r) => r.json()).catch((err) => {
162
+ const res = await fetch(url, { method: "POST", headers: authHeaders(secret) }).then((r) => r.json()).catch((err) => {
121
163
  consola.error(`Failed: ${err.message}`);
122
164
  return null;
123
165
  });
@@ -164,13 +206,13 @@ const main = defineCommand({
164
206
  consola.error("No secret found. Run `nuxi dev` or `nuxi build` first.");
165
207
  return;
166
208
  }
167
- const params = new URLSearchParams({ secret });
209
+ const params = new URLSearchParams();
168
210
  if (!args.clear) {
169
211
  params.set("clear", "false");
170
212
  }
171
213
  const url = `${args.url}/__ai-ready/restore?${params}`;
172
214
  consola.info(`Restoring database at ${args.url}...`);
173
- const res = await fetch(url, { method: "POST" }).then((r) => r.json()).catch((err) => {
215
+ const res = await fetch(url, { method: "POST", headers: authHeaders(secret) }).then((r) => r.json()).catch((err) => {
174
216
  consola.error(`Failed: ${err.message}`);
175
217
  return null;
176
218
  });
@@ -217,15 +259,16 @@ const main = defineCommand({
217
259
  return;
218
260
  }
219
261
  const params = new URLSearchParams();
220
- if (secret)
221
- params.set("secret", secret);
222
262
  if (args.dry)
223
263
  params.set("dry", "true");
224
264
  if (args.ttl)
225
265
  params.set("ttl", args.ttl);
226
266
  const url = `${args.url}/__ai-ready/prune?${params}`;
227
267
  consola.info(`${args.dry ? "Previewing" : "Pruning"} stale routes at ${args.url}...`);
228
- const res = await fetch(url, { method: "POST" }).then((r) => r.json()).catch((err) => {
268
+ const res = await fetch(url, {
269
+ method: "POST",
270
+ headers: secret ? authHeaders(secret) : void 0
271
+ }).then((r) => r.json()).catch((err) => {
229
272
  consola.error(`Failed: ${err.message}`);
230
273
  return null;
231
274
  });
@@ -278,12 +321,11 @@ const main = defineCommand({
278
321
  return;
279
322
  }
280
323
  const params = new URLSearchParams({
281
- secret,
282
324
  limit: args.limit || "100"
283
325
  });
284
326
  const url = `${args.url}/__ai-ready/indexnow?${params}`;
285
327
  consola.info(`Triggering IndexNow sync at ${args.url}...`);
286
- const res = await fetch(url, { method: "POST" }).then((r) => r.json()).catch((err) => {
328
+ const res = await fetch(url, { method: "POST", headers: authHeaders(secret) }).then((r) => r.json()).catch((err) => {
287
329
  consola.error(`Failed: ${err.message}`);
288
330
  return null;
289
331
  });
@@ -0,0 +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.CZtw_6f4.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/__nuxt-ai-ready/_nuxt/BJy7_Lqa.js"><script type="module" src="/__nuxt-ai-ready/_nuxt/BJy7_Lqa.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:"cd2130f1-f79d-4ea7-b399-0dcc99955804",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1774506022715,false]</script></body></html>
@@ -0,0 +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.CZtw_6f4.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/__nuxt-ai-ready/_nuxt/BJy7_Lqa.js"><script type="module" src="/__nuxt-ai-ready/_nuxt/BJy7_Lqa.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:"cd2130f1-f79d-4ea7-b399-0dcc99955804",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1774506022715,false]</script></body></html>
@@ -0,0 +1,2 @@
1
+ import{d as B,o as t,c as e,n as j,a as m,h as F,b as o,r as C,e as g,_ as q,i as K,G as M,u as A,j as d,k as S,F as h,l as b,t as i,m as T,p as O,g as N,w,q as R,f as y,s as H}from"./BJy7_Lqa.js";import{_ as J}from"./Ud9k3yqB.js";import{_ as Q,a as W}from"./DmG3LGyr.js";import{_ as X}from"./w8OrmFD1.js";const Y=["role"],Z={class:"devtools-alert-content"},tt={key:0,class:"devtools-alert-action"},et=B({__name:"DevtoolsAlert",props:{icon:{},variant:{default:"info"}},setup(_){const p={info:"carbon:information",warning:"carbon:warning",error:"carbon:close-outline",success:"carbon:checkmark-outline",production:"carbon:cloud"};return(u,x)=>{const l=F;return t(),e("div",{class:j(["devtools-alert",`devtools-alert-${_.variant}`]),role:_.variant==="error"?"alert":"status"},[m(l,{name:_.icon||p[_.variant],class:"devtools-alert-icon","aria-hidden":"true"},null,8,["name"]),o("div",Z,[C(u.$slots,"default",{},void 0,!0)]),u.$slots.action?(t(),e("div",tt,[C(u.$slots,"action",{},void 0,!0)])):g("",!0)],10,Y)}}}),ot=Object.assign(q(et,[["__scopeId","data-v-222dd034"]]),{__name:"DevtoolsAlert"}),st={class:"space-y-4"},nt={class:"flex items-center gap-2"},lt=["onClick"],at={key:0,class:"py-8 text-center"},rt={key:0,class:"relative"},ct={class:"text-xs font-mono whitespace-pre-wrap p-4 rounded-lg bg-[var(--color-surface-sunken)] text-[var(--color-text)] overflow-auto max-h-[600px]"},it={key:1,class:"relative"},ut={class:"text-xs font-mono whitespace-pre-wrap p-4 rounded-lg bg-[var(--color-surface-sunken)] text-[var(--color-text-muted)] overflow-auto max-h-[600px]"},dt={key:0,class:"space-y-3"},mt={class:"text-sm font-semibold text-[var(--color-text)] mb-1"},_t={key:0,class:"space-y-1 mt-2"},vt={class:"font-medium text-[var(--color-text)]"},pt={key:0,class:"text-[var(--color-text-muted)]"},xt={class:"font-mono text-[var(--color-text-subtle)]"},ft={key:1,class:"text-xs text-[var(--color-text-muted)]"},bt=B({__name:"llms-txt",setup(_){const p=K(M),u=y(()=>p?.value?.isDev??!0),x=y(()=>p?.value?.llmsTxt),l=H("llms-txt"),{data:I}=A("llms-txt-content",async()=>{if(!d.value)return null;try{return await d.value("/llms.txt",{responseType:"text"})}catch{return null}},{watch:[d,S]}),{data:P,status:V}=A("llms-full-content",async()=>{if(!d.value||l.value!=="llms-full")return null;try{return await d.value("/llms-full.txt",{responseType:"text"})}catch{return null}},{watch:[d,S,l]}),k=y(()=>l.value==="llms-full"?P.value:I.value),D=y(()=>{const c=x.value;if(!c)return"";const a=["# {Site Name}","","> {Site Description}",""];for(const s of c.sections||[]){if(a.push(`## ${s.title}`),s.description){const n=Array.isArray(s.description)?s.description:[s.description];for(const v of n)a.push("",v)}for(const n of s.links||[]){const v=n.description?`: ${n.description}`:"";a.push(`- [${n.title}](${n.href})${v}`)}a.push("")}if(c.notes){const s=Array.isArray(c.notes)?c.notes:[c.notes];for(const n of s)a.push(n)}return a.join(`
2
+ `)});return(c,a)=>{const s=ot,n=R,v=J,z=Q,E=W,G=F,L=X;return t(),e("div",st,[o("div",nt,[(t(),e(h,null,b([{key:"llms-txt",label:"llms.txt"},{key:"llms-full",label:"llms-full.txt"}],r=>o("button",{key:r.key,type:"button",class:j(["px-3 py-1.5 text-xs font-medium rounded-md transition-all cursor-pointer",l.value===r.key?"bg-[var(--seo-green)] text-white":"bg-[var(--color-surface-elevated)] text-[var(--color-text-muted)] hover:text-[var(--color-text)]"]),onClick:$=>l.value=r.key},i(r.label),11,lt)),64))]),u.value&&!T(O)?(t(),N(s,{key:0,variant:"info"},{default:w(()=>[...a[0]||(a[0]=[o("p",{class:"font-medium mb-1"}," Template Preview ",-1),o("p",{class:"text-sm opacity-80"}," This shows the llms.txt structure from your config. Actual content with page data is generated during prerendering. Switch to production mode to see live content. ",-1)])]),_:1})):g("",!0),m(E,{title:l.value==="llms-txt"?"llms.txt":"llms-full.txt"},{default:w(()=>[l.value==="llms-full"&&T(V)==="pending"?(t(),e("div",at,[m(n)])):(t(),e(h,{key:1},[k.value?(t(),e("div",rt,[m(v,{text:k.value,class:"absolute top-2 right-2 z-10"},null,8,["text"]),o("pre",ct,i(k.value),1)])):u.value&&D.value?(t(),e("div",it,[o("pre",ut,i(D.value),1)])):(t(),N(z,{key:2,icon:"carbon:document",title:"No content available",description:"llms.txt content is generated during prerendering. Run `nuxi generate` or switch to production mode."}))],64))]),_:1},8,["title"]),m(L,{text:"Configured Sections",icon:"carbon:list-boxes"},{default:w(()=>[x.value?.sections?.length?(t(),e("div",dt,[(t(!0),e(h,null,b(x.value.sections,(r,$)=>(t(),e("div",{key:$,class:"p-3 rounded-lg bg-[var(--color-surface-elevated)] border border-[var(--color-border)]"},[o("h4",mt,i(r.title),1),r.links?.length?(t(),e("div",_t,[(t(!0),e(h,null,b(r.links,(f,U)=>(t(),e("div",{key:U,class:"flex items-start gap-2 text-xs"},[m(G,{name:"carbon:link",class:"w-3 h-3 mt-0.5 text-[var(--color-text-muted)]"}),o("div",null,[o("span",vt,i(f.title),1),f.description?(t(),e("span",pt,", "+i(f.description),1)):g("",!0),o("div",xt,i(f.href),1)])]))),128))])):g("",!0)]))),128))])):(t(),e("p",ft," No custom sections configured. "))]),_:1})])}}});export{bt as default};