nuxt-ai-ready 1.8.0 → 2.0.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 +0 -1
- package/dist/chunks/agent-skills.mjs +1 -1
- package/dist/chunks/prerender.mjs +7 -83
- package/dist/cli.mjs +1 -63
- package/dist/devtools/lib/ai-ready/types.ts +0 -1
- package/dist/module.d.mts +17 -8
- package/dist/module.json +1 -1
- package/dist/module.mjs +1 -1
- package/dist/runtime/server/db/drizzle/client.d.ts +4 -4
- package/dist/runtime/server/db/drizzle/index.d.ts +1 -1
- package/dist/runtime/server/db/drizzle/index.js +0 -3
- package/dist/runtime/server/db/drizzle/providers/bun.d.ts +1 -1
- package/dist/runtime/server/db/drizzle/providers/bun.js +1 -2
- package/dist/runtime/server/db/drizzle/providers/d1.d.ts +1 -1
- package/dist/runtime/server/db/drizzle/providers/d1.js +1 -2
- package/dist/runtime/server/db/drizzle/providers/libsql.d.ts +1 -1
- package/dist/runtime/server/db/drizzle/providers/libsql.js +1 -2
- package/dist/runtime/server/db/drizzle/providers/neon.d.ts +1 -1
- package/dist/runtime/server/db/drizzle/providers/neon.js +1 -2
- package/dist/runtime/server/db/drizzle/providers/node-sqlite.d.ts +8 -0
- package/dist/runtime/server/db/drizzle/providers/node-sqlite.js +15 -0
- package/dist/runtime/server/db/drizzle/providers/sqlite.d.ts +1 -1
- package/dist/runtime/server/db/drizzle/providers/sqlite.js +1 -2
- package/dist/runtime/server/db/drizzle/queries.d.ts +0 -18
- package/dist/runtime/server/db/drizzle/queries.js +2 -71
- package/dist/runtime/server/db/drizzle/raw.d.ts +1 -1
- package/dist/runtime/server/db/drizzle/raw.js +27 -0
- package/dist/runtime/server/db/queries.d.ts +0 -70
- package/dist/runtime/server/db/queries.js +10 -170
- package/dist/runtime/server/db/schema/postgres.d.ts +292 -722
- package/dist/runtime/server/db/schema/postgres.js +1 -13
- package/dist/runtime/server/db/schema/sqlite.d.ts +174 -620
- package/dist/runtime/server/db/schema/sqlite.js +1 -13
- package/dist/runtime/server/db/schema-sql.d.ts +1 -1
- package/dist/runtime/server/db/schema-sql.js +2 -12
- package/dist/runtime/server/db/shared.d.ts +0 -1
- package/dist/runtime/server/db/shared.js +4 -6
- package/dist/runtime/server/middleware/markdown.js +42 -106
- package/dist/runtime/server/plugins/markdown-negotiation.d.ts +13 -0
- package/dist/runtime/server/plugins/markdown-negotiation.js +45 -0
- package/dist/runtime/server/routes/__ai-ready/devtools.get.js +1 -2
- package/dist/runtime/server/routes/__ai-ready/status.get.js +1 -20
- package/dist/runtime/server/routes/__ai-ready-debug.get.js +2 -47
- package/dist/runtime/server/tasks/ai-ready-cron.js +1 -1
- package/dist/runtime/server/utils/content-negotiation.d.ts +2 -3
- package/dist/runtime/server/utils/cron-plan.d.ts +0 -3
- package/dist/runtime/server/utils/cron-plan.js +2 -5
- package/dist/runtime/server/utils/frontmatter.d.ts +1 -0
- package/dist/runtime/server/utils/frontmatter.js +22 -0
- package/dist/runtime/server/utils/markdown-request.d.ts +17 -1
- package/dist/runtime/server/utils/markdown-request.js +20 -11
- package/dist/runtime/server/utils/negotiation-decision.d.ts +39 -0
- package/dist/runtime/server/utils/negotiation-decision.js +30 -0
- package/dist/runtime/server/utils/negotiation-response.d.ts +34 -0
- package/dist/runtime/server/utils/negotiation-response.js +108 -0
- package/dist/runtime/server/utils/runCron.d.ts +0 -5
- package/dist/runtime/server/utils/runCron.js +4 -32
- package/dist/runtime/types.d.ts +51 -13
- package/dist/shared/{nuxt-ai-ready.B6l-68o5.mjs → nuxt-ai-ready.D8qbnNrv.mjs} +159 -84
- package/package.json +18 -18
- package/dist/runtime/server/routes/__ai-ready/indexnow.post.d.ts +0 -2
- package/dist/runtime/server/routes/__ai-ready/indexnow.post.js +0 -14
- package/dist/runtime/server/routes/indexnow-key.get.d.ts +0 -6
- package/dist/runtime/server/routes/indexnow-key.get.js +0 -9
- package/dist/runtime/server/utils/indexnow-shared.d.ts +0 -70
- package/dist/runtime/server/utils/indexnow-shared.js +0 -87
- package/dist/runtime/server/utils/indexnow.d.ts +0 -30
- package/dist/runtime/server/utils/indexnow.js +0 -119
package/README.md
CHANGED
|
@@ -26,7 +26,6 @@ Nuxt AI Ready implements both. It converts your pages to markdown, generates llm
|
|
|
26
26
|
- 🧠 **Agent Skills**: Publish verified local or external skills through the v0.2.0 discovery index
|
|
27
27
|
- 🧩 **[WebMCP](https://nuxtseo.com/ai-ready/guides/webmcp)**: Give browser agents access to built-in site tools or your own tools with `useWebMcpTool()`
|
|
28
28
|
- 🗄️ **Runtime Indexing**: Index pages on-demand without prerendering, with SQLite/D1/LibSQL support
|
|
29
|
-
- 🔔 **[IndexNow](https://nuxtseo.com/ai-ready/guides/indexnow)**: Instantly notify Bing, Yandex, and other search engines when pages change
|
|
30
29
|
- 🌏 **[i18n Aware](https://nuxtseo.com/ai-ready/guides/i18n)**: Auto-detects [`@nuxtjs/i18n`](https://i18n.nuxtjs.org/) for hreflang `Link` headers, locale-tagged frontmatter, and an Available Languages section in `llms.txt`
|
|
31
30
|
- 🧠 **[RAG Ready](https://nuxtseo.com/ai-ready/advanced/rag-example)**: Markdown output optimized for vectorizing and semantic search
|
|
32
31
|
|
|
@@ -2,7 +2,7 @@ import { createHash } from 'node:crypto';
|
|
|
2
2
|
import { realpath, readFile } from 'node:fs/promises';
|
|
3
3
|
import { resolve, isAbsolute, relative, sep } from 'node:path';
|
|
4
4
|
import { parseDocument } from 'yaml';
|
|
5
|
-
import { A as AGENT_SKILLS_SCHEMA } from '../shared/nuxt-ai-ready.
|
|
5
|
+
import { A as AGENT_SKILLS_SCHEMA } from '../shared/nuxt-ai-ready.D8qbnNrv.mjs';
|
|
6
6
|
import 'node:module';
|
|
7
7
|
import '@nuxt/kit';
|
|
8
8
|
import 'defu';
|
|
@@ -4,12 +4,11 @@ import { useNuxt, hasNuxtModule, resolveFiles } from '@nuxt/kit';
|
|
|
4
4
|
import { colorize } from 'consola/utils';
|
|
5
5
|
import { resolveLocaleFromRoute } from 'nuxtseo-shared/i18n-runtime';
|
|
6
6
|
import { collectSitemap } from 'sitemapd/parse';
|
|
7
|
-
import { withLeadingSlash,
|
|
8
|
-
import { l as logger, M as MARKDOWN_LINK_AVAILABILITY_FILE } from '../shared/nuxt-ai-ready.
|
|
7
|
+
import { withLeadingSlash, joinURL, withBase } from 'ufo';
|
|
8
|
+
import { l as logger, s as supportsNativeNodeSqlite, M as MARKDOWN_LINK_AVAILABILITY_FILE } from '../shared/nuxt-ai-ready.D8qbnNrv.mjs';
|
|
9
9
|
import { normalizePagePath, toMarkdownPath } from '../../dist/runtime/markdown-path.js';
|
|
10
10
|
import { toLogicalRoute, toDeployedRoute } from '../../dist/runtime/route-path.js';
|
|
11
11
|
import { initSchema, computeContentHash, insertPage, queryAllPages, exportDbDump } from '../../dist/runtime/server/db/shared.js';
|
|
12
|
-
import { comparePageHashes, submitToIndexNowShared } from '../../dist/runtime/server/utils/indexnow-shared.js';
|
|
13
12
|
import { buildLlmsFullTxtHeader, formatPageForLlmsFullTxt } from '../../dist/runtime/server/utils/llms-full.js';
|
|
14
13
|
import 'node:crypto';
|
|
15
14
|
import 'node:module';
|
|
@@ -22,7 +21,6 @@ import '../../dist/runtime/server/utils/discovery-response.js';
|
|
|
22
21
|
import 'pathe';
|
|
23
22
|
import 'nuxtseo-shared/i18n';
|
|
24
23
|
|
|
25
|
-
const BUILD_FETCH_TIMEOUT = 15e3;
|
|
26
24
|
const PRERENDER_PAGE_TIMEOUT = 3e4;
|
|
27
25
|
const RE_HTML_MD_EXT = /\.(html|md)$/;
|
|
28
26
|
const RE_INDEX_SUFFIX = /\/index$/;
|
|
@@ -61,46 +59,7 @@ async function findOutputMarkdownPaths(publicDir, baseURL, srcDir, ignoredPaths,
|
|
|
61
59
|
}
|
|
62
60
|
return [...paths].sort();
|
|
63
61
|
}
|
|
64
|
-
|
|
65
|
-
const metaUrl = withBase("/__ai-ready/pages.meta.json", siteUrl);
|
|
66
|
-
logger.info(`Fetching previous build meta from ${metaUrl}`);
|
|
67
|
-
const controller = new AbortController();
|
|
68
|
-
const timeoutId = setTimeout(() => controller.abort(), BUILD_FETCH_TIMEOUT);
|
|
69
|
-
const prevMeta = await fetch(metaUrl, { signal: controller.signal }).then((r) => r.ok ? r.json() : null).catch((err) => {
|
|
70
|
-
if (err.name === "AbortError") {
|
|
71
|
-
logger.warn(`Timeout fetching previous meta (${BUILD_FETCH_TIMEOUT}ms)`);
|
|
72
|
-
}
|
|
73
|
-
return null;
|
|
74
|
-
}).finally(() => clearTimeout(timeoutId));
|
|
75
|
-
if (!prevMeta?.pages) {
|
|
76
|
-
logger.info("First deploy or no previous meta - will index all pages");
|
|
77
|
-
return null;
|
|
78
|
-
}
|
|
79
|
-
logger.info(`Previous build: ${prevMeta.pageCount} pages (buildId: ${prevMeta.buildId})`);
|
|
80
|
-
if (indexNow) {
|
|
81
|
-
const keyUrl = withBase(`/${indexNow}.txt`, siteUrl);
|
|
82
|
-
const keyLive = await fetch(keyUrl, { signal: AbortSignal.timeout(5e3) }).then((r) => r.ok).catch(() => false);
|
|
83
|
-
if (!keyLive) {
|
|
84
|
-
logger.info("IndexNow key file not live yet - IndexNow submission will be skipped");
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
return prevMeta;
|
|
88
|
-
}
|
|
89
|
-
async function submitIndexNow(changedRoutes, addedRoutes, siteUrl, indexNow) {
|
|
90
|
-
const allRoutes = [...changedRoutes, ...addedRoutes];
|
|
91
|
-
if (allRoutes.length === 0) {
|
|
92
|
-
logger.debug("[indexnow] No content changes detected");
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
logger.info(`[indexnow] Submitting ${allRoutes.length} changed pages (${changedRoutes.length} modified, ${addedRoutes.length} new)`);
|
|
96
|
-
const result = await submitToIndexNowShared(allRoutes, indexNow, siteUrl, { logger });
|
|
97
|
-
if (result.success) {
|
|
98
|
-
logger.info(`[indexnow] Successfully notified search engines of ${allRoutes.length} changes`);
|
|
99
|
-
} else {
|
|
100
|
-
logger.warn(`[indexnow] Failed to submit: ${result.error}`);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
function createCrawlerState(dbPath, llmsFullTxtPath, siteInfo, llmsTxtConfig, indexNow, concurrency = 10, ftsTokenizer, i18n) {
|
|
62
|
+
function createCrawlerState(dbPath, llmsFullTxtPath, siteInfo, llmsTxtConfig, concurrency = 10, ftsTokenizer, i18n) {
|
|
104
63
|
return {
|
|
105
64
|
prerenderedRoutes: /* @__PURE__ */ new Set(),
|
|
106
65
|
errorRoutes: /* @__PURE__ */ new Set(),
|
|
@@ -110,7 +69,6 @@ function createCrawlerState(dbPath, llmsFullTxtPath, siteInfo, llmsTxtConfig, in
|
|
|
110
69
|
llmsFullTxtPath,
|
|
111
70
|
siteInfo,
|
|
112
71
|
llmsTxtConfig,
|
|
113
|
-
indexNow,
|
|
114
72
|
concurrency,
|
|
115
73
|
ftsTokenizer,
|
|
116
74
|
i18n
|
|
@@ -169,8 +127,7 @@ function createSqliteAdapter(sqlite) {
|
|
|
169
127
|
};
|
|
170
128
|
}
|
|
171
129
|
async function createPrerenderDatabase(dbPath) {
|
|
172
|
-
|
|
173
|
-
if (nodeVersion >= 22) {
|
|
130
|
+
if (supportsNativeNodeSqlite(process.versions.node || "")) {
|
|
174
131
|
const { DatabaseSync } = await import('node:sqlite');
|
|
175
132
|
const sqlite2 = new DatabaseSync(dbPath);
|
|
176
133
|
for (const pragma of PRERENDER_PRAGMAS)
|
|
@@ -341,7 +298,7 @@ async function prerenderRoute(nitro, route) {
|
|
|
341
298
|
nitro._prerenderedRoutes.push(_route);
|
|
342
299
|
return stat(filePath);
|
|
343
300
|
}
|
|
344
|
-
function setupPrerenderHandler(options, dbPath, siteInfo, llmsTxtConfig,
|
|
301
|
+
function setupPrerenderHandler(options, dbPath, siteInfo, llmsTxtConfig, extras = {}) {
|
|
345
302
|
const nuxt = useNuxt();
|
|
346
303
|
nuxt.hooks.hook("nitro:init", async (nitro) => {
|
|
347
304
|
const llmsFullTxtPath = join(nitro.options.output.publicDir, "llms-full.txt");
|
|
@@ -350,7 +307,6 @@ function setupPrerenderHandler(options, dbPath, siteInfo, llmsTxtConfig, indexNo
|
|
|
350
307
|
llmsFullTxtPath,
|
|
351
308
|
siteInfo,
|
|
352
309
|
llmsTxtConfig,
|
|
353
|
-
indexNow,
|
|
354
310
|
options.prerender?.concurrency,
|
|
355
311
|
extras.ftsTokenizer,
|
|
356
312
|
extras.i18n
|
|
@@ -423,47 +379,15 @@ function setupPrerenderHandler(options, dbPath, siteInfo, llmsTxtConfig, indexNo
|
|
|
423
379
|
logger.debug(`Writing pages.dump: ${dumpPath} (${(dumpData.length / 1024).toFixed(1)}kb)`);
|
|
424
380
|
await writeFile(dumpPath, dumpData, "utf-8");
|
|
425
381
|
logger.debug(`Created database dump at __ai-ready/pages.dump (${(dumpData.length / 1024).toFixed(1)}kb compressed)`);
|
|
426
|
-
const pageHashes = {};
|
|
427
|
-
for (const p of pages) {
|
|
428
|
-
if (p.contentHash)
|
|
429
|
-
pageHashes[p.route] = p.contentHash;
|
|
430
|
-
}
|
|
431
|
-
let prevMeta = null;
|
|
432
|
-
if (state.siteInfo?.url) {
|
|
433
|
-
prevMeta = await fetchPreviousMeta(state.siteInfo.url, state.indexNow || "");
|
|
434
|
-
}
|
|
435
|
-
const { changed, added, removed } = comparePageHashes(pageHashes, prevMeta);
|
|
436
|
-
const debug = useNuxt().options.runtimeConfig["nuxt-ai-ready"]?.debug;
|
|
437
|
-
const changes = {
|
|
438
|
-
changed: changed.length,
|
|
439
|
-
added: added.length,
|
|
440
|
-
removed: removed.length
|
|
441
|
-
};
|
|
442
|
-
if (debug) {
|
|
443
|
-
if (changed.length > 0)
|
|
444
|
-
changes.changedRoutes = changed;
|
|
445
|
-
if (added.length > 0)
|
|
446
|
-
changes.addedRoutes = added;
|
|
447
|
-
if (removed.length > 0)
|
|
448
|
-
changes.removedRoutes = removed;
|
|
449
|
-
}
|
|
450
382
|
const buildId = Date.now().toString(36);
|
|
451
383
|
const metaContent = JSON.stringify({
|
|
452
384
|
buildId,
|
|
453
385
|
pageCount: pages.length,
|
|
454
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
455
|
-
changes: prevMeta ? changes : void 0,
|
|
456
|
-
pages: pageHashes
|
|
386
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
457
387
|
});
|
|
458
388
|
logger.debug(`Writing pages.meta.json (${(metaContent.length / 1024).toFixed(1)}kb)`);
|
|
459
389
|
await writeFile(join(publicDataDir, "pages.meta.json"), metaContent, "utf-8");
|
|
460
|
-
logger.debug(`Wrote build metadata: buildId=${buildId}
|
|
461
|
-
if (prevMeta && (changed.length > 0 || added.length > 0 || removed.length > 0)) {
|
|
462
|
-
logger.info(`Content changes: ${changed.length} modified, ${added.length} new, ${removed.length} removed`);
|
|
463
|
-
}
|
|
464
|
-
if (state.indexNow && state.siteInfo?.url && prevMeta) {
|
|
465
|
-
await submitIndexNow(changed, added, state.siteInfo.url, state.indexNow);
|
|
466
|
-
}
|
|
390
|
+
logger.debug(`Wrote build metadata: buildId=${buildId}`);
|
|
467
391
|
}
|
|
468
392
|
if (state.dbPath && state.llmsTxtConfig?.markdownLinks) {
|
|
469
393
|
const availabilityFile = join(dirname(state.dbPath), MARKDOWN_LINK_AVAILABILITY_FILE);
|
package/dist/cli.mjs
CHANGED
|
@@ -42,7 +42,7 @@ const main = defineCommand({
|
|
|
42
42
|
status: () => defineCommand({
|
|
43
43
|
meta: {
|
|
44
44
|
name: "status",
|
|
45
|
-
description: "Show indexing status and
|
|
45
|
+
description: "Show indexing status and sync progress"
|
|
46
46
|
},
|
|
47
47
|
args: {
|
|
48
48
|
url: {
|
|
@@ -85,23 +85,6 @@ const main = defineCommand({
|
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
|
-
if (res.indexNow) {
|
|
89
|
-
consola.log("");
|
|
90
|
-
consola.info(colors.bold("IndexNow:"));
|
|
91
|
-
consola.info(` Pending: ${colors.yellow(res.indexNow.pending?.toString() || "0")}`);
|
|
92
|
-
consola.info(` Total submitted: ${colors.green(res.indexNow.totalSubmitted?.toString() || "0")}`);
|
|
93
|
-
if (res.indexNow.lastSubmittedAt) {
|
|
94
|
-
const date = new Date(res.indexNow.lastSubmittedAt);
|
|
95
|
-
consola.info(` Last sync: ${colors.dim(date.toISOString())}`);
|
|
96
|
-
}
|
|
97
|
-
if (res.indexNow.lastError) {
|
|
98
|
-
consola.info(` Last error: ${colors.red(res.indexNow.lastError)}`);
|
|
99
|
-
}
|
|
100
|
-
if (res.indexNow.backoff?.active) {
|
|
101
|
-
const remainMin = Math.ceil((res.indexNow.backoff.remainingMs || 0) / 6e4);
|
|
102
|
-
consola.warn(` Backoff: ${colors.yellow(`${remainMin}m remaining`)} (attempt ${res.indexNow.backoff.attempt})`);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
88
|
if (res.cron) {
|
|
106
89
|
consola.log("");
|
|
107
90
|
consola.info(colors.bold("Cron:"));
|
|
@@ -285,51 +268,6 @@ const main = defineCommand({
|
|
|
285
268
|
consola.success(`Pruned: ${colors.green(res.pruned?.toString() || "0")} routes`);
|
|
286
269
|
}
|
|
287
270
|
}
|
|
288
|
-
}),
|
|
289
|
-
indexnow: () => defineCommand({
|
|
290
|
-
meta: {
|
|
291
|
-
name: "indexnow",
|
|
292
|
-
description: "Trigger IndexNow sync"
|
|
293
|
-
},
|
|
294
|
-
args: {
|
|
295
|
-
url: {
|
|
296
|
-
type: "string",
|
|
297
|
-
alias: "u",
|
|
298
|
-
description: "Site URL (default: http://localhost:3000)",
|
|
299
|
-
default: "http://localhost:3000"
|
|
300
|
-
},
|
|
301
|
-
limit: {
|
|
302
|
-
type: "string",
|
|
303
|
-
alias: "l",
|
|
304
|
-
description: "Max URLs to submit",
|
|
305
|
-
default: "100"
|
|
306
|
-
},
|
|
307
|
-
cwd: {
|
|
308
|
-
type: "string",
|
|
309
|
-
description: "Working directory",
|
|
310
|
-
default: "."
|
|
311
|
-
}
|
|
312
|
-
},
|
|
313
|
-
async run({ args }) {
|
|
314
|
-
const cwd = resolve(args.cwd || ".");
|
|
315
|
-
const secret = await requireSecret(cwd);
|
|
316
|
-
if (!secret)
|
|
317
|
-
return;
|
|
318
|
-
const params = new URLSearchParams({
|
|
319
|
-
limit: args.limit || "100"
|
|
320
|
-
});
|
|
321
|
-
const url = `${args.url}/__ai-ready/indexnow?${params}`;
|
|
322
|
-
consola.info(`Triggering IndexNow sync at ${args.url}...`);
|
|
323
|
-
const res = await fetchJson(url, { method: "POST", headers: authHeaders(secret) });
|
|
324
|
-
if (!res)
|
|
325
|
-
return;
|
|
326
|
-
if (res.success) {
|
|
327
|
-
consola.success(`Submitted: ${colors.green(res.submitted?.toString() || "0")} URLs`);
|
|
328
|
-
consola.info(`Remaining: ${colors.yellow(res.remaining?.toString() || "0")}`);
|
|
329
|
-
} else {
|
|
330
|
-
consola.error(`Failed: ${res.error || "Unknown error"}`);
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
271
|
})
|
|
334
272
|
}
|
|
335
273
|
});
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
export interface DevtoolsConfig {
|
|
2
2
|
database: { type: string }
|
|
3
3
|
runtimeSync: { enabled: boolean, ttl: number, batchSize: number, pruneTtl: number }
|
|
4
|
-
indexNow: boolean
|
|
5
4
|
sitemapPrerendered: boolean
|
|
6
5
|
markdownCacheHeaders: { maxAge: number, swr: boolean }
|
|
7
6
|
llmsTxtCacheSeconds: number
|
package/dist/module.d.mts
CHANGED
|
@@ -31,6 +31,22 @@ interface ResolvedApiCatalogConfig {
|
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
type DatabaseType = 'sqlite' | 'bun' | 'd1' | 'libsql' | 'neon';
|
|
35
|
+
/**
|
|
36
|
+
* Database state after parsing. Every consumer reads `_tag` first, so a
|
|
37
|
+
* disabled database can never carry a driver, a path, or credentials.
|
|
38
|
+
*/
|
|
39
|
+
type ResolvedDatabase = {
|
|
40
|
+
_tag: 'Disabled';
|
|
41
|
+
} | {
|
|
42
|
+
_tag: 'Enabled';
|
|
43
|
+
type: DatabaseType;
|
|
44
|
+
filename?: string;
|
|
45
|
+
bindingName?: string;
|
|
46
|
+
url?: string;
|
|
47
|
+
authToken?: string;
|
|
48
|
+
};
|
|
49
|
+
|
|
34
50
|
interface ResolvedWebMcpConfig {
|
|
35
51
|
tools: ResolvedWebMcpToolsConfig;
|
|
36
52
|
exposedTo?: string[];
|
|
@@ -71,13 +87,7 @@ interface ModulePublicRuntimeConfig {
|
|
|
71
87
|
version: string;
|
|
72
88
|
mdreamOptions: ModuleOptions['mdreamOptions'];
|
|
73
89
|
markdownCacheHeaders: Required<NonNullable<ModuleOptions['markdownCacheHeaders']>>;
|
|
74
|
-
database:
|
|
75
|
-
type: 'sqlite' | 'bun' | 'd1' | 'libsql' | 'neon';
|
|
76
|
-
filename?: string;
|
|
77
|
-
bindingName?: string;
|
|
78
|
-
url?: string;
|
|
79
|
-
authToken?: string;
|
|
80
|
-
};
|
|
90
|
+
database: ResolvedDatabase;
|
|
81
91
|
runtimeSync: {
|
|
82
92
|
enabled: boolean;
|
|
83
93
|
ttl: number;
|
|
@@ -85,7 +95,6 @@ interface ModulePublicRuntimeConfig {
|
|
|
85
95
|
pruneTtl: number;
|
|
86
96
|
};
|
|
87
97
|
runtimeSyncSecret?: string;
|
|
88
|
-
indexNow?: string;
|
|
89
98
|
sitemapPrerendered: boolean;
|
|
90
99
|
i18n?: RuntimeI18nConfig | null;
|
|
91
100
|
ftsTokenizer?: string;
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -7,7 +7,7 @@ import 'defu';
|
|
|
7
7
|
import 'nuxt-site-config/kit';
|
|
8
8
|
import 'nuxtseo-shared/kit';
|
|
9
9
|
import 'pkg-types';
|
|
10
|
-
export { m as default } from './shared/nuxt-ai-ready.
|
|
10
|
+
export { m as default } from './shared/nuxt-ai-ready.D8qbnNrv.mjs';
|
|
11
11
|
import '../dist/runtime/server/utils/discovery-response.js';
|
|
12
12
|
import 'node:url';
|
|
13
13
|
import 'pathe';
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import type { BetterSQLite3Database } from 'drizzle-orm/better-sqlite3';
|
|
2
|
-
import type {
|
|
2
|
+
import type { SQLiteBunDatabase } from 'drizzle-orm/bun-sqlite';
|
|
3
3
|
import type { DrizzleD1Database } from 'drizzle-orm/d1';
|
|
4
4
|
import type { LibSQLDatabase } from 'drizzle-orm/libsql';
|
|
5
5
|
import type { NeonHttpDatabase } from 'drizzle-orm/neon-http';
|
|
6
|
-
import type
|
|
6
|
+
import type { NodeSQLiteDatabase } from 'drizzle-orm/node-sqlite';
|
|
7
7
|
import type { H3Event } from '#nuxtseo/h3';
|
|
8
8
|
export type DatabaseDialect = 'sqlite' | 'postgres';
|
|
9
|
-
type SQLiteDB = BetterSQLite3Database
|
|
10
|
-
type PostgresDB = NeonHttpDatabase
|
|
9
|
+
type SQLiteDB = BetterSQLite3Database | SQLiteBunDatabase | LibSQLDatabase | DrizzleD1Database | NodeSQLiteDatabase;
|
|
10
|
+
type PostgresDB = NeonHttpDatabase;
|
|
11
11
|
export interface DrizzleDatabase {
|
|
12
12
|
dialect: DatabaseDialect;
|
|
13
13
|
db: SQLiteDB | PostgresDB;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
export * from '#ai-ready-virtual/db-schema.mjs';
|
|
5
5
|
export { closeDrizzle, useDrizzle } from './client.js';
|
|
6
6
|
export type { DatabaseDialect, DrizzleDatabase } from './client.js';
|
|
7
|
-
export { completeCronRun, countPages,
|
|
7
|
+
export { completeCronRun, countPages, deleteInfoValue, deletePage, getAllPages, getContentHashes, getInfoValue, getNextSitemapToCrawl, getPageByRoute, getPageLastmods, getPendingPages, getRecentCronRuns, getSitemapStatus, initSchema, markPageIndexed, markRoutesPending, markSitemapCrawled, markSitemapCrawlPartial, markSitemapError, markSitemapSeeded, resetSitemapErrors, searchPages, seedRoutes, setInfoValue, startCronRun, syncSitemaps, upsertPage, } from './queries.js';
|
|
8
8
|
export type { CronRunOutput, PageInput, PageMetaOutput, PageOutput, SitemapOutput, } from './queries.js';
|
|
9
9
|
export { useRawDb } from './raw.js';
|
|
10
10
|
export type { RawExecutor } from './raw.js';
|
|
@@ -3,7 +3,6 @@ export { closeDrizzle, useDrizzle } from "./client.js";
|
|
|
3
3
|
export {
|
|
4
4
|
completeCronRun,
|
|
5
5
|
countPages,
|
|
6
|
-
countPagesNeedingIndexNowSync,
|
|
7
6
|
deleteInfoValue,
|
|
8
7
|
deletePage,
|
|
9
8
|
getAllPages,
|
|
@@ -12,12 +11,10 @@ export {
|
|
|
12
11
|
getNextSitemapToCrawl,
|
|
13
12
|
getPageByRoute,
|
|
14
13
|
getPageLastmods,
|
|
15
|
-
getPagesNeedingIndexNowSync,
|
|
16
14
|
getPendingPages,
|
|
17
15
|
getRecentCronRuns,
|
|
18
16
|
getSitemapStatus,
|
|
19
17
|
initSchema,
|
|
20
|
-
markIndexNowSynced,
|
|
21
18
|
markPageIndexed,
|
|
22
19
|
markRoutesPending,
|
|
23
20
|
markSitemapCrawled,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { H3Event } from '#nuxtseo/h3';
|
|
2
2
|
export declare function createClient(event?: H3Event): Promise<{
|
|
3
3
|
dialect: "sqlite";
|
|
4
|
-
db: import("drizzle-orm/bun-sqlite").
|
|
4
|
+
db: import("drizzle-orm/bun-sqlite").SQLiteBunDatabase<import("drizzle-orm").EmptyRelations> & {
|
|
5
5
|
$client: any;
|
|
6
6
|
};
|
|
7
7
|
}>;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Database } from "bun:sqlite";
|
|
2
2
|
import { drizzle } from "drizzle-orm/bun-sqlite";
|
|
3
|
-
import * as schema from "#ai-ready-virtual/db-schema.mjs";
|
|
4
3
|
import { useRuntimeConfig } from "#nuxtseo/nitro";
|
|
5
4
|
import { logger } from "../../../logger.js";
|
|
6
5
|
import { registerDriver } from "../raw.js";
|
|
@@ -10,7 +9,7 @@ export async function createClient(event) {
|
|
|
10
9
|
const dbPath = await resolveWritableDbPath(config.database.filename || ".data/ai-ready/pages.db");
|
|
11
10
|
logger.debug(`[drizzle] Opening Bun SQLite database: ${dbPath}`);
|
|
12
11
|
const sqlite = new Database(dbPath);
|
|
13
|
-
const db = drizzle(
|
|
12
|
+
const db = drizzle({ client: sqlite });
|
|
14
13
|
registerDriver(db, "better-sqlite3", sqlite);
|
|
15
14
|
return { dialect: "sqlite", db };
|
|
16
15
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { H3Event } from '#nuxtseo/h3';
|
|
2
2
|
export declare function createClient(event?: H3Event): Promise<{
|
|
3
3
|
dialect: "sqlite";
|
|
4
|
-
db: import("drizzle-orm/d1").DrizzleD1Database<
|
|
4
|
+
db: import("drizzle-orm/d1").DrizzleD1Database<import("drizzle-orm").EmptyRelations> & {
|
|
5
5
|
$client: any;
|
|
6
6
|
};
|
|
7
7
|
}>;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { drizzle } from "drizzle-orm/d1";
|
|
2
|
-
import * as schema from "#ai-ready-virtual/db-schema.mjs";
|
|
3
2
|
import { useRuntimeConfig } from "#nuxtseo/nitro";
|
|
4
3
|
import { logger } from "../../../logger.js";
|
|
5
4
|
import { registerDriver } from "../raw.js";
|
|
@@ -13,7 +12,7 @@ export async function createClient(event) {
|
|
|
13
12
|
if (!d1) {
|
|
14
13
|
throw new Error(`[ai-ready] D1 binding "${bindingName}" not found`);
|
|
15
14
|
}
|
|
16
|
-
const db = drizzle(d1
|
|
15
|
+
const db = drizzle(d1);
|
|
17
16
|
registerDriver(db, "d1", d1);
|
|
18
17
|
return { dialect: "sqlite", db };
|
|
19
18
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { H3Event } from '#nuxtseo/h3';
|
|
2
2
|
export declare function createClient(event?: H3Event): Promise<{
|
|
3
3
|
dialect: "sqlite";
|
|
4
|
-
db: import("drizzle-orm/libsql").LibSQLDatabase<
|
|
4
|
+
db: import("drizzle-orm/libsql").LibSQLDatabase<import("drizzle-orm").EmptyRelations> & {
|
|
5
5
|
$client: import("@libsql/client").Client;
|
|
6
6
|
};
|
|
7
7
|
}>;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { createClient as createLibSQLClient } from "@libsql/client";
|
|
2
2
|
import { drizzle } from "drizzle-orm/libsql";
|
|
3
|
-
import * as schema from "#ai-ready-virtual/db-schema.mjs";
|
|
4
3
|
import { useRuntimeConfig } from "#nuxtseo/nitro";
|
|
5
4
|
import { logger } from "../../../logger.js";
|
|
6
5
|
import { registerDriver } from "../raw.js";
|
|
@@ -14,7 +13,7 @@ export async function createClient(event) {
|
|
|
14
13
|
}
|
|
15
14
|
logger.debug(`[drizzle] Connecting to LibSQL: ${dbUrl}`);
|
|
16
15
|
const client = createLibSQLClient({ url: dbUrl, authToken: config.database.authToken });
|
|
17
|
-
const db = drizzle(
|
|
16
|
+
const db = drizzle({ client });
|
|
18
17
|
registerDriver(db, "libsql", client);
|
|
19
18
|
return { dialect: "sqlite", db };
|
|
20
19
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { H3Event } from '#nuxtseo/h3';
|
|
2
2
|
export declare function createClient(event?: H3Event): Promise<{
|
|
3
3
|
dialect: "postgres";
|
|
4
|
-
db: import("drizzle-orm/neon-http").NeonHttpDatabase<
|
|
4
|
+
db: import("drizzle-orm/neon-http").NeonHttpDatabase<import("drizzle-orm").EmptyRelations> & {
|
|
5
5
|
$client: import("@neondatabase/serverless").NeonQueryFunction<false, false>;
|
|
6
6
|
};
|
|
7
7
|
}>;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { neon } from "@neondatabase/serverless";
|
|
2
2
|
import { drizzle } from "drizzle-orm/neon-http";
|
|
3
|
-
import * as schema from "#ai-ready-virtual/db-schema.mjs";
|
|
4
3
|
import { useRuntimeConfig } from "#nuxtseo/nitro";
|
|
5
4
|
import { logger } from "../../../logger.js";
|
|
6
5
|
import { registerDriver } from "../raw.js";
|
|
@@ -12,7 +11,7 @@ export async function createClient(event) {
|
|
|
12
11
|
}
|
|
13
12
|
logger.debug(`[drizzle] Connecting to Neon Postgres`);
|
|
14
13
|
const sqlFn = neon(connectionString);
|
|
15
|
-
const db = drizzle(
|
|
14
|
+
const db = drizzle({ client: sqlFn });
|
|
16
15
|
registerDriver(db, "neon", sqlFn);
|
|
17
16
|
return { dialect: "postgres", db };
|
|
18
17
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { H3Event } from '#nuxtseo/h3';
|
|
2
|
+
import { DatabaseSync } from 'node:sqlite';
|
|
3
|
+
export declare function createClient(event?: H3Event): Promise<{
|
|
4
|
+
dialect: "sqlite";
|
|
5
|
+
db: import("drizzle-orm/node-sqlite").NodeSQLiteDatabase<import("drizzle-orm").EmptyRelations> & {
|
|
6
|
+
$client: DatabaseSync;
|
|
7
|
+
};
|
|
8
|
+
}>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { DatabaseSync } from "node:sqlite";
|
|
2
|
+
import { drizzle } from "drizzle-orm/node-sqlite";
|
|
3
|
+
import { useRuntimeConfig } from "#nuxtseo/nitro";
|
|
4
|
+
import { logger } from "../../../logger.js";
|
|
5
|
+
import { registerDriver } from "../raw.js";
|
|
6
|
+
import { resolveWritableDbPath } from "./dbPath.js";
|
|
7
|
+
export async function createClient(event) {
|
|
8
|
+
const config = useRuntimeConfig(event)["nuxt-ai-ready"];
|
|
9
|
+
const dbPath = await resolveWritableDbPath(config.database.filename || ".data/ai-ready/pages.db");
|
|
10
|
+
logger.debug(`[drizzle] Opening native SQLite database: ${dbPath}`);
|
|
11
|
+
const sqlite = new DatabaseSync(dbPath);
|
|
12
|
+
const db = drizzle({ client: sqlite });
|
|
13
|
+
registerDriver(db, "node-sqlite", sqlite);
|
|
14
|
+
return { dialect: "sqlite", db };
|
|
15
|
+
}
|
|
@@ -2,7 +2,7 @@ import type { H3Event } from '#nuxtseo/h3';
|
|
|
2
2
|
import Database from 'better-sqlite3';
|
|
3
3
|
export declare function createClient(event?: H3Event): Promise<{
|
|
4
4
|
dialect: "sqlite";
|
|
5
|
-
db: import("drizzle-orm/better-sqlite3").BetterSQLite3Database<
|
|
5
|
+
db: import("drizzle-orm/better-sqlite3").BetterSQLite3Database<import("drizzle-orm").EmptyRelations> & {
|
|
6
6
|
$client: Database.Database;
|
|
7
7
|
};
|
|
8
8
|
}>;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import Database from "better-sqlite3";
|
|
2
2
|
import { drizzle } from "drizzle-orm/better-sqlite3";
|
|
3
|
-
import * as schema from "#ai-ready-virtual/db-schema.mjs";
|
|
4
3
|
import { useRuntimeConfig } from "#nuxtseo/nitro";
|
|
5
4
|
import { logger } from "../../../logger.js";
|
|
6
5
|
import { registerDriver } from "../raw.js";
|
|
@@ -10,7 +9,7 @@ export async function createClient(event) {
|
|
|
10
9
|
const dbPath = await resolveWritableDbPath(config.database.filename || ".data/ai-ready/pages.db");
|
|
11
10
|
logger.debug(`[drizzle] Opening SQLite database: ${dbPath}`);
|
|
12
11
|
const sqlite = new Database(dbPath);
|
|
13
|
-
const db = drizzle(
|
|
12
|
+
const db = drizzle({ client: sqlite });
|
|
14
13
|
registerDriver(db, "better-sqlite3", sqlite);
|
|
15
14
|
return { dialect: "sqlite", db };
|
|
16
15
|
}
|
|
@@ -105,20 +105,6 @@ export declare function deleteInfoValue(event: H3Event | undefined, key: string)
|
|
|
105
105
|
* table (Postgres has no FTS5; tokenizer comparison is SQLite-only).
|
|
106
106
|
*/
|
|
107
107
|
export declare function initSchema(event?: H3Event): Promise<void>;
|
|
108
|
-
/**
|
|
109
|
-
* Get pages needing IndexNow sync
|
|
110
|
-
*/
|
|
111
|
-
export declare function getPagesNeedingIndexNowSync(event: H3Event | undefined, limit?: number): Promise<{
|
|
112
|
-
route: string;
|
|
113
|
-
}[]>;
|
|
114
|
-
/**
|
|
115
|
-
* Count pages needing IndexNow sync
|
|
116
|
-
*/
|
|
117
|
-
export declare function countPagesNeedingIndexNowSync(event: H3Event | undefined): Promise<number>;
|
|
118
|
-
/**
|
|
119
|
-
* Mark pages as synced to IndexNow
|
|
120
|
-
*/
|
|
121
|
-
export declare function markIndexNowSynced(event: H3Event | undefined, routes: string[]): Promise<void>;
|
|
122
108
|
export interface CronRunOutput {
|
|
123
109
|
id: number;
|
|
124
110
|
startedAt: number;
|
|
@@ -126,8 +112,6 @@ export interface CronRunOutput {
|
|
|
126
112
|
durationMs: number | null;
|
|
127
113
|
pagesIndexed: number;
|
|
128
114
|
pagesRemaining: number;
|
|
129
|
-
indexNowSubmitted: number;
|
|
130
|
-
indexNowRemaining: number;
|
|
131
115
|
errors: string[];
|
|
132
116
|
status: 'running' | 'success' | 'partial' | 'error';
|
|
133
117
|
}
|
|
@@ -141,8 +125,6 @@ export declare function startCronRun(event: H3Event | undefined): Promise<number
|
|
|
141
125
|
export declare function completeCronRun(event: H3Event | undefined, runId: number, result: {
|
|
142
126
|
pagesIndexed: number;
|
|
143
127
|
pagesRemaining: number;
|
|
144
|
-
indexNowSubmitted: number;
|
|
145
|
-
indexNowRemaining: number;
|
|
146
128
|
errors: string[];
|
|
147
129
|
}): Promise<void>;
|
|
148
130
|
/**
|