nuxt-ai-ready 0.6.2 → 0.7.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.
- package/README.md +1 -0
- package/dist/module.d.mts +12 -1
- package/dist/module.json +1 -1
- package/dist/module.mjs +226 -352
- package/dist/runtime/index.d.ts +5 -7
- package/dist/runtime/index.js +14 -3
- package/dist/runtime/llms-txt-format.d.ts +8 -0
- package/dist/runtime/llms-txt-format.js +32 -0
- package/dist/runtime/llms-txt-utils.d.ts +2 -5
- package/dist/runtime/llms-txt-utils.js +31 -88
- package/dist/runtime/server/db/index.d.ts +3 -7
- package/dist/runtime/server/db/index.js +14 -31
- package/dist/runtime/server/db/queries.d.ts +106 -26
- package/dist/runtime/server/db/queries.js +330 -33
- package/dist/runtime/server/db/schema-sql.d.ts +3 -0
- package/dist/runtime/server/db/schema-sql.js +71 -0
- package/dist/runtime/server/db/shared.d.ts +88 -0
- package/dist/runtime/server/db/shared.js +117 -0
- package/dist/runtime/server/mcp/resources/pages.js +11 -3
- package/dist/runtime/server/mcp/tools/list-pages.js +33 -7
- package/dist/runtime/server/mcp/tools/search-pages.js +3 -3
- package/dist/runtime/server/middleware/markdown.js +2 -3
- package/dist/runtime/server/middleware/markdown.prerender.js +6 -5
- package/dist/runtime/server/plugins/db-restore.js +10 -8
- package/dist/runtime/server/plugins/sitemap-seeder.js +44 -0
- package/dist/runtime/server/routes/__ai-ready/indexnow.post.d.ts +2 -0
- package/dist/runtime/server/routes/__ai-ready/indexnow.post.js +18 -0
- package/dist/runtime/server/routes/__ai-ready/poll.post.d.ts +8 -0
- package/dist/runtime/server/routes/__ai-ready/poll.post.js +25 -0
- package/dist/runtime/server/routes/__ai-ready/prune.post.d.ts +14 -0
- package/dist/runtime/server/routes/__ai-ready/prune.post.js +21 -0
- package/dist/runtime/server/routes/__ai-ready/status.get.d.ts +2 -0
- package/dist/runtime/server/routes/__ai-ready/status.get.js +28 -0
- package/dist/runtime/server/routes/__ai-ready-debug.get.js +13 -14
- package/dist/runtime/server/routes/indexnow-key.get.d.ts +6 -0
- package/dist/runtime/server/routes/indexnow-key.get.js +10 -0
- package/dist/runtime/server/routes/llms-full.txt.get.d.ts +1 -1
- package/dist/runtime/server/routes/llms-full.txt.get.js +34 -3
- package/dist/runtime/server/tasks/ai-ready-index.d.ts +11 -0
- package/dist/runtime/server/tasks/ai-ready-index.js +39 -0
- package/dist/runtime/server/utils/batchIndex.d.ts +26 -0
- package/dist/runtime/server/utils/batchIndex.js +53 -0
- package/dist/runtime/server/utils/indexPage.d.ts +8 -2
- package/dist/runtime/server/utils/indexPage.js +38 -23
- package/dist/runtime/server/utils/indexnow.d.ts +27 -0
- package/dist/runtime/server/utils/indexnow.js +66 -0
- package/dist/runtime/server/utils/keywords.d.ts +0 -4
- package/dist/runtime/server/utils/keywords.js +0 -3
- package/dist/runtime/server/utils/llms-full.d.ts +11 -0
- package/dist/runtime/server/utils/llms-full.js +39 -0
- package/dist/runtime/server/utils/sitemap.js +3 -3
- package/dist/runtime/server/utils.d.ts +12 -10
- package/dist/runtime/server/utils.js +63 -94
- package/dist/runtime/types.d.ts +64 -40
- package/package.json +28 -29
- package/dist/runtime/mcp.d.ts +0 -32
- package/dist/runtime/mcp.js +0 -5
- package/dist/runtime/server/db/dump.d.ts +0 -29
- package/dist/runtime/server/db/dump.js +0 -29
- package/dist/runtime/server/db/schema.d.ts +0 -8
- package/dist/runtime/server/db/schema.js +0 -124
- package/dist/runtime/server/plugins/page-indexer.js +0 -68
- package/dist/runtime/server/tsconfig.json +0 -3
- package/dist/runtime/server/utils/pageData.d.ts +0 -28
- package/dist/runtime/server/utils/pageData.js +0 -43
- package/mcp.d.ts +0 -4
- /package/dist/runtime/{nuxt → app}/plugins/md-hints.prerender.d.ts +0 -0
- /package/dist/runtime/{nuxt → app}/plugins/md-hints.prerender.js +0 -0
- /package/dist/runtime/server/plugins/{page-indexer.d.ts → sitemap-seeder.d.ts} +0 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nuxt-ai-ready",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.7.0",
|
|
5
5
|
"description": "Best practice AI & LLM discoverability for Nuxt sites.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Harlan Wilton",
|
|
@@ -25,20 +25,24 @@
|
|
|
25
25
|
".": {
|
|
26
26
|
"types": "./dist/types.d.mts",
|
|
27
27
|
"import": "./dist/module.mjs"
|
|
28
|
-
},
|
|
29
|
-
"./mcp": {
|
|
30
|
-
"types": "./mcp.d.ts",
|
|
31
|
-
"import": "./dist/runtime/mcp.js"
|
|
32
28
|
}
|
|
33
29
|
},
|
|
34
30
|
"main": "./dist/module.mjs",
|
|
35
31
|
"files": [
|
|
36
|
-
"dist"
|
|
37
|
-
"mcp.d.ts"
|
|
32
|
+
"dist"
|
|
38
33
|
],
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"@nuxtjs/sitemap": "^7.0.0",
|
|
36
|
+
"better-sqlite3": "^11.0.0 || ^12.0.0"
|
|
37
|
+
},
|
|
38
|
+
"peerDependenciesMeta": {
|
|
39
|
+
"better-sqlite3": {
|
|
40
|
+
"optional": true
|
|
41
|
+
}
|
|
42
|
+
},
|
|
39
43
|
"dependencies": {
|
|
40
44
|
"@clack/prompts": "^0.11.0",
|
|
41
|
-
"@nuxt/kit": "4.2.2",
|
|
45
|
+
"@nuxt/kit": "^4.2.2",
|
|
42
46
|
"consola": "^3.4.2",
|
|
43
47
|
"db0": "^0.3.4",
|
|
44
48
|
"defu": "^6.1.4",
|
|
@@ -50,15 +54,6 @@
|
|
|
50
54
|
"std-env": "3.10.0",
|
|
51
55
|
"ufo": "^1.6.2"
|
|
52
56
|
},
|
|
53
|
-
"peerDependencies": {
|
|
54
|
-
"@nuxtjs/sitemap": "^7.5.2",
|
|
55
|
-
"better-sqlite3": "^12.5.0"
|
|
56
|
-
},
|
|
57
|
-
"peerDependenciesMeta": {
|
|
58
|
-
"better-sqlite3": {
|
|
59
|
-
"optional": true
|
|
60
|
-
}
|
|
61
|
-
},
|
|
62
57
|
"devDependencies": {
|
|
63
58
|
"@antfu/eslint-config": "^6.7.3",
|
|
64
59
|
"@arethetypeswrong/cli": "^0.18.2",
|
|
@@ -70,14 +65,16 @@
|
|
|
70
65
|
"@nuxtjs/color-mode": "^4.0.0",
|
|
71
66
|
"@nuxtjs/eslint-config-typescript": "^12.1.0",
|
|
72
67
|
"@nuxtjs/i18n": "^10.2.1",
|
|
73
|
-
"@nuxtjs/mcp-toolkit": "^0.6.
|
|
68
|
+
"@nuxtjs/mcp-toolkit": "^0.6.2",
|
|
74
69
|
"@nuxtjs/robots": "^5.6.7",
|
|
75
70
|
"@nuxtjs/sitemap": "^7.5.2",
|
|
71
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
76
72
|
"@vitest/coverage-v8": "^4.0.16",
|
|
73
|
+
"@vue/test-utils": "^2.4.6",
|
|
77
74
|
"@vueuse/nuxt": "^14.1.0",
|
|
78
|
-
"agents": "^0.3.
|
|
79
|
-
"ai": "^6.0.
|
|
80
|
-
"better-sqlite3": "^12.
|
|
75
|
+
"agents": "^0.3.4",
|
|
76
|
+
"ai": "^6.0.27",
|
|
77
|
+
"better-sqlite3": "^12.6.0",
|
|
81
78
|
"bumpp": "^10.3.2",
|
|
82
79
|
"eslint": "^9.39.2",
|
|
83
80
|
"execa": "^9.6.1",
|
|
@@ -92,21 +89,23 @@
|
|
|
92
89
|
"vue": "^3.5.26",
|
|
93
90
|
"vue-router": "^4.6.4",
|
|
94
91
|
"vue-tsc": "^3.2.2",
|
|
92
|
+
"wrangler": "^4.58.0",
|
|
95
93
|
"zod": "^4.3.5"
|
|
96
94
|
},
|
|
97
95
|
"resolutions": {
|
|
98
96
|
"nuxt-ai-ready": "workspace:*"
|
|
99
97
|
},
|
|
100
98
|
"scripts": {
|
|
101
|
-
"lint": "eslint .
|
|
99
|
+
"lint": "eslint .",
|
|
100
|
+
"lint:fix": "eslint . --fix",
|
|
102
101
|
"build": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxt-module-build build",
|
|
103
|
-
"dev": "
|
|
104
|
-
"dev:minimal": "
|
|
105
|
-
"prepare:fixtures": "
|
|
106
|
-
"dev:build": "
|
|
107
|
-
"dev:build:minimal": "
|
|
108
|
-
"dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxt-module-build build &&
|
|
109
|
-
"dev:prepare:minimal": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxt-module-build build &&
|
|
102
|
+
"dev": "nuxt dev playground",
|
|
103
|
+
"dev:minimal": "nuxt dev playground",
|
|
104
|
+
"prepare:fixtures": "nuxt prepare playground && nuxt prepare playground && nuxt prepare test/fixtures/basic",
|
|
105
|
+
"dev:build": "nuxt build playground",
|
|
106
|
+
"dev:build:minimal": "nuxt build playground",
|
|
107
|
+
"dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxt-module-build build && nuxt prepare playground",
|
|
108
|
+
"dev:prepare:minimal": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxt-module-build build && nuxt prepare playground",
|
|
110
109
|
"release": "pnpm build && bumpp -x \"npx changelogen --output=CHANGELOG.md\"",
|
|
111
110
|
"test": "pnpm run prepare:fixtures && vitest",
|
|
112
111
|
"test:unit": "vitest run --project=unit",
|
package/dist/runtime/mcp.d.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
export declare const tools: readonly [{
|
|
2
|
-
name: string;
|
|
3
|
-
description: string;
|
|
4
|
-
inputSchema: {};
|
|
5
|
-
cache: "1h";
|
|
6
|
-
handler(): Promise<{
|
|
7
|
-
content: {
|
|
8
|
-
type: "text";
|
|
9
|
-
text: string;
|
|
10
|
-
}[];
|
|
11
|
-
}>;
|
|
12
|
-
}, import("@nuxtjs/mcp-toolkit").McpToolDefinition<Readonly<{
|
|
13
|
-
[k: string]: import("zod/v4/core").$ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>;
|
|
14
|
-
}>, Readonly<{
|
|
15
|
-
[k: string]: import("zod/v4/core").$ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>;
|
|
16
|
-
}>>];
|
|
17
|
-
export declare const resources: readonly [{
|
|
18
|
-
uri: string;
|
|
19
|
-
name: string;
|
|
20
|
-
description: string;
|
|
21
|
-
metadata: {
|
|
22
|
-
mimeType: string;
|
|
23
|
-
};
|
|
24
|
-
cache: "1h";
|
|
25
|
-
handler(uri: URL): Promise<{
|
|
26
|
-
contents: {
|
|
27
|
-
uri: string;
|
|
28
|
-
mimeType: string;
|
|
29
|
-
text: string;
|
|
30
|
-
}[];
|
|
31
|
-
}>;
|
|
32
|
-
}];
|
package/dist/runtime/mcp.js
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import type { DatabaseAdapter } from './schema.js';
|
|
2
|
-
export interface DumpRow {
|
|
3
|
-
route: string;
|
|
4
|
-
route_key: string;
|
|
5
|
-
title: string;
|
|
6
|
-
description: string;
|
|
7
|
-
markdown: string;
|
|
8
|
-
headings: string;
|
|
9
|
-
keywords: string;
|
|
10
|
-
updated_at: string;
|
|
11
|
-
indexed_at: number;
|
|
12
|
-
is_error: number;
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* Export all pages as JSON for dump
|
|
16
|
-
*/
|
|
17
|
-
export declare function exportDump(db: DatabaseAdapter): Promise<DumpRow[]>;
|
|
18
|
-
/**
|
|
19
|
-
* Compress dump data to base64 gzip
|
|
20
|
-
*/
|
|
21
|
-
export declare function compressDump(data: DumpRow[]): Promise<string>;
|
|
22
|
-
/**
|
|
23
|
-
* Decompress dump from base64 gzip
|
|
24
|
-
*/
|
|
25
|
-
export declare function decompressDump(base64: string): Promise<DumpRow[]>;
|
|
26
|
-
/**
|
|
27
|
-
* Import dump into database
|
|
28
|
-
*/
|
|
29
|
-
export declare function importDump(db: DatabaseAdapter, rows: DumpRow[]): Promise<void>;
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
export async function exportDump(db) {
|
|
2
|
-
return db.all(`
|
|
3
|
-
SELECT route, route_key, title, description, markdown, headings, keywords, updated_at, indexed_at, is_error
|
|
4
|
-
FROM ai_ready_pages
|
|
5
|
-
`);
|
|
6
|
-
}
|
|
7
|
-
export async function compressDump(data) {
|
|
8
|
-
const json = JSON.stringify(data);
|
|
9
|
-
const encoder = new TextEncoder();
|
|
10
|
-
const stream = new Blob([encoder.encode(json)]).stream();
|
|
11
|
-
const compressed = stream.pipeThrough(new CompressionStream("gzip"));
|
|
12
|
-
const buffer = await new Response(compressed).arrayBuffer();
|
|
13
|
-
return Buffer.from(buffer).toString("base64");
|
|
14
|
-
}
|
|
15
|
-
export async function decompressDump(base64) {
|
|
16
|
-
const buffer = Buffer.from(base64, "base64");
|
|
17
|
-
const stream = new Blob([buffer]).stream();
|
|
18
|
-
const decompressed = stream.pipeThrough(new DecompressionStream("gzip"));
|
|
19
|
-
const text = await new Response(decompressed).text();
|
|
20
|
-
return JSON.parse(text);
|
|
21
|
-
}
|
|
22
|
-
export async function importDump(db, rows) {
|
|
23
|
-
for (const row of rows) {
|
|
24
|
-
await db.exec(`
|
|
25
|
-
INSERT OR REPLACE INTO ai_ready_pages (route, route_key, title, description, markdown, headings, keywords, updated_at, indexed_at, is_error)
|
|
26
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
27
|
-
`, [row.route, row.route_key, row.title, row.description, row.markdown, row.headings, row.keywords, row.updated_at, row.indexed_at, row.is_error]);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
export declare const SCHEMA_VERSION = "v1.1.0";
|
|
2
|
-
export declare const createTablesSQL = "\nCREATE TABLE IF NOT EXISTS ai_ready_pages (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n route TEXT UNIQUE NOT NULL,\n route_key TEXT UNIQUE NOT NULL,\n title TEXT NOT NULL DEFAULT '',\n description TEXT NOT NULL DEFAULT '',\n markdown TEXT NOT NULL DEFAULT '',\n headings TEXT NOT NULL DEFAULT '[]',\n keywords TEXT NOT NULL DEFAULT '[]',\n updated_at TEXT NOT NULL,\n indexed_at INTEGER NOT NULL,\n is_error INTEGER NOT NULL DEFAULT 0\n);\n\nCREATE INDEX IF NOT EXISTS idx_ai_ready_pages_route ON ai_ready_pages(route);\nCREATE INDEX IF NOT EXISTS idx_ai_ready_pages_is_error ON ai_ready_pages(is_error);\n\nCREATE VIRTUAL TABLE IF NOT EXISTS ai_ready_pages_fts USING fts5(\n route, title, description, markdown, headings, keywords,\n content=ai_ready_pages, content_rowid=id\n);\n\nCREATE TRIGGER IF NOT EXISTS ai_ready_pages_ai AFTER INSERT ON ai_ready_pages BEGIN\n INSERT INTO ai_ready_pages_fts(rowid, route, title, description, markdown, headings, keywords)\n VALUES (new.id, new.route, new.title, new.description, new.markdown, new.headings, new.keywords);\nEND;\n\nCREATE TRIGGER IF NOT EXISTS ai_ready_pages_ad AFTER DELETE ON ai_ready_pages BEGIN\n INSERT INTO ai_ready_pages_fts(ai_ready_pages_fts, rowid, route, title, description, markdown, headings, keywords)\n VALUES('delete', old.id, old.route, old.title, old.description, old.markdown, old.headings, old.keywords);\nEND;\n\nCREATE TRIGGER IF NOT EXISTS ai_ready_pages_au AFTER UPDATE ON ai_ready_pages BEGIN\n INSERT INTO ai_ready_pages_fts(ai_ready_pages_fts, rowid, route, title, description, markdown, headings, keywords)\n VALUES('delete', old.id, old.route, old.title, old.description, old.markdown, old.headings, old.keywords);\n INSERT INTO ai_ready_pages_fts(rowid, route, title, description, markdown, headings, keywords)\n VALUES (new.id, new.route, new.title, new.description, new.markdown, new.headings, new.keywords);\nEND;\n\nCREATE TABLE IF NOT EXISTS _ai_ready_info (\n id TEXT PRIMARY KEY,\n version TEXT,\n checksum TEXT,\n ready INTEGER DEFAULT 0\n);\n";
|
|
3
|
-
export interface DatabaseAdapter {
|
|
4
|
-
all: <T>(sql: string, params?: unknown[]) => Promise<T[]>;
|
|
5
|
-
first: <T>(sql: string, params?: unknown[]) => Promise<T | undefined>;
|
|
6
|
-
exec: (sql: string, params?: unknown[]) => Promise<void>;
|
|
7
|
-
}
|
|
8
|
-
export declare function initSchema(db: DatabaseAdapter): Promise<void>;
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
export const SCHEMA_VERSION = "v1.1.0";
|
|
2
|
-
const DROP_TABLES_SQL = [
|
|
3
|
-
"DROP TABLE IF EXISTS ai_ready_pages_fts",
|
|
4
|
-
"DROP TABLE IF EXISTS ai_ready_pages",
|
|
5
|
-
"DROP TABLE IF EXISTS _ai_ready_info",
|
|
6
|
-
// Legacy unprefixed tables (migration from v1.0.0)
|
|
7
|
-
"DROP TABLE IF EXISTS pages_fts",
|
|
8
|
-
"DROP TABLE IF EXISTS pages"
|
|
9
|
-
];
|
|
10
|
-
export const createTablesSQL = `
|
|
11
|
-
CREATE TABLE IF NOT EXISTS ai_ready_pages (
|
|
12
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
13
|
-
route TEXT UNIQUE NOT NULL,
|
|
14
|
-
route_key TEXT UNIQUE NOT NULL,
|
|
15
|
-
title TEXT NOT NULL DEFAULT '',
|
|
16
|
-
description TEXT NOT NULL DEFAULT '',
|
|
17
|
-
markdown TEXT NOT NULL DEFAULT '',
|
|
18
|
-
headings TEXT NOT NULL DEFAULT '[]',
|
|
19
|
-
keywords TEXT NOT NULL DEFAULT '[]',
|
|
20
|
-
updated_at TEXT NOT NULL,
|
|
21
|
-
indexed_at INTEGER NOT NULL,
|
|
22
|
-
is_error INTEGER NOT NULL DEFAULT 0
|
|
23
|
-
);
|
|
24
|
-
|
|
25
|
-
CREATE INDEX IF NOT EXISTS idx_ai_ready_pages_route ON ai_ready_pages(route);
|
|
26
|
-
CREATE INDEX IF NOT EXISTS idx_ai_ready_pages_is_error ON ai_ready_pages(is_error);
|
|
27
|
-
|
|
28
|
-
CREATE VIRTUAL TABLE IF NOT EXISTS ai_ready_pages_fts USING fts5(
|
|
29
|
-
route, title, description, markdown, headings, keywords,
|
|
30
|
-
content=ai_ready_pages, content_rowid=id
|
|
31
|
-
);
|
|
32
|
-
|
|
33
|
-
CREATE TRIGGER IF NOT EXISTS ai_ready_pages_ai AFTER INSERT ON ai_ready_pages BEGIN
|
|
34
|
-
INSERT INTO ai_ready_pages_fts(rowid, route, title, description, markdown, headings, keywords)
|
|
35
|
-
VALUES (new.id, new.route, new.title, new.description, new.markdown, new.headings, new.keywords);
|
|
36
|
-
END;
|
|
37
|
-
|
|
38
|
-
CREATE TRIGGER IF NOT EXISTS ai_ready_pages_ad AFTER DELETE ON ai_ready_pages BEGIN
|
|
39
|
-
INSERT INTO ai_ready_pages_fts(ai_ready_pages_fts, rowid, route, title, description, markdown, headings, keywords)
|
|
40
|
-
VALUES('delete', old.id, old.route, old.title, old.description, old.markdown, old.headings, old.keywords);
|
|
41
|
-
END;
|
|
42
|
-
|
|
43
|
-
CREATE TRIGGER IF NOT EXISTS ai_ready_pages_au AFTER UPDATE ON ai_ready_pages BEGIN
|
|
44
|
-
INSERT INTO ai_ready_pages_fts(ai_ready_pages_fts, rowid, route, title, description, markdown, headings, keywords)
|
|
45
|
-
VALUES('delete', old.id, old.route, old.title, old.description, old.markdown, old.headings, old.keywords);
|
|
46
|
-
INSERT INTO ai_ready_pages_fts(rowid, route, title, description, markdown, headings, keywords)
|
|
47
|
-
VALUES (new.id, new.route, new.title, new.description, new.markdown, new.headings, new.keywords);
|
|
48
|
-
END;
|
|
49
|
-
|
|
50
|
-
CREATE TABLE IF NOT EXISTS _ai_ready_info (
|
|
51
|
-
id TEXT PRIMARY KEY,
|
|
52
|
-
version TEXT,
|
|
53
|
-
checksum TEXT,
|
|
54
|
-
ready INTEGER DEFAULT 0
|
|
55
|
-
);
|
|
56
|
-
`;
|
|
57
|
-
export async function initSchema(db) {
|
|
58
|
-
const needsRebuild = await checkSchemaVersion(db);
|
|
59
|
-
if (needsRebuild) {
|
|
60
|
-
for (const sql of DROP_TABLES_SQL) {
|
|
61
|
-
await db.exec(sql);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
const statements = [
|
|
65
|
-
// Main table
|
|
66
|
-
`CREATE TABLE IF NOT EXISTS ai_ready_pages (
|
|
67
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
68
|
-
route TEXT UNIQUE NOT NULL,
|
|
69
|
-
route_key TEXT UNIQUE NOT NULL,
|
|
70
|
-
title TEXT NOT NULL DEFAULT '',
|
|
71
|
-
description TEXT NOT NULL DEFAULT '',
|
|
72
|
-
markdown TEXT NOT NULL DEFAULT '',
|
|
73
|
-
headings TEXT NOT NULL DEFAULT '[]',
|
|
74
|
-
keywords TEXT NOT NULL DEFAULT '[]',
|
|
75
|
-
updated_at TEXT NOT NULL,
|
|
76
|
-
indexed_at INTEGER NOT NULL,
|
|
77
|
-
is_error INTEGER NOT NULL DEFAULT 0
|
|
78
|
-
)`,
|
|
79
|
-
// Indexes
|
|
80
|
-
`CREATE INDEX IF NOT EXISTS idx_ai_ready_pages_route ON ai_ready_pages(route)`,
|
|
81
|
-
`CREATE INDEX IF NOT EXISTS idx_ai_ready_pages_is_error ON ai_ready_pages(is_error)`,
|
|
82
|
-
// FTS5 virtual table
|
|
83
|
-
`CREATE VIRTUAL TABLE IF NOT EXISTS ai_ready_pages_fts USING fts5(
|
|
84
|
-
route, title, description, markdown, headings, keywords,
|
|
85
|
-
content=ai_ready_pages, content_rowid=id
|
|
86
|
-
)`,
|
|
87
|
-
// Triggers for FTS sync
|
|
88
|
-
`CREATE TRIGGER IF NOT EXISTS ai_ready_pages_ai AFTER INSERT ON ai_ready_pages BEGIN
|
|
89
|
-
INSERT INTO ai_ready_pages_fts(rowid, route, title, description, markdown, headings, keywords)
|
|
90
|
-
VALUES (new.id, new.route, new.title, new.description, new.markdown, new.headings, new.keywords);
|
|
91
|
-
END`,
|
|
92
|
-
`CREATE TRIGGER IF NOT EXISTS ai_ready_pages_ad AFTER DELETE ON ai_ready_pages BEGIN
|
|
93
|
-
INSERT INTO ai_ready_pages_fts(ai_ready_pages_fts, rowid, route, title, description, markdown, headings, keywords)
|
|
94
|
-
VALUES('delete', old.id, old.route, old.title, old.description, old.markdown, old.headings, old.keywords);
|
|
95
|
-
END`,
|
|
96
|
-
`CREATE TRIGGER IF NOT EXISTS ai_ready_pages_au AFTER UPDATE ON ai_ready_pages BEGIN
|
|
97
|
-
INSERT INTO ai_ready_pages_fts(ai_ready_pages_fts, rowid, route, title, description, markdown, headings, keywords)
|
|
98
|
-
VALUES('delete', old.id, old.route, old.title, old.description, old.markdown, old.headings, old.keywords);
|
|
99
|
-
INSERT INTO ai_ready_pages_fts(rowid, route, title, description, markdown, headings, keywords)
|
|
100
|
-
VALUES (new.id, new.route, new.title, new.description, new.markdown, new.headings, new.keywords);
|
|
101
|
-
END`,
|
|
102
|
-
// Info table
|
|
103
|
-
`CREATE TABLE IF NOT EXISTS _ai_ready_info (
|
|
104
|
-
id TEXT PRIMARY KEY,
|
|
105
|
-
version TEXT,
|
|
106
|
-
checksum TEXT,
|
|
107
|
-
ready INTEGER DEFAULT 0
|
|
108
|
-
)`
|
|
109
|
-
];
|
|
110
|
-
for (const statement of statements) {
|
|
111
|
-
await db.exec(statement);
|
|
112
|
-
}
|
|
113
|
-
await db.exec(
|
|
114
|
-
"INSERT OR REPLACE INTO _ai_ready_info (id, version) VALUES (?, ?)",
|
|
115
|
-
["schema", SCHEMA_VERSION]
|
|
116
|
-
);
|
|
117
|
-
}
|
|
118
|
-
async function checkSchemaVersion(db) {
|
|
119
|
-
const info = await db.first(
|
|
120
|
-
"SELECT version FROM _ai_ready_info WHERE id = ?",
|
|
121
|
-
["schema"]
|
|
122
|
-
).catch(() => null);
|
|
123
|
-
return !info || info.version !== SCHEMA_VERSION;
|
|
124
|
-
}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import { defineNitroPlugin, useRuntimeConfig } from "nitropack/runtime";
|
|
2
|
-
import { useDatabase } from "../db/index.js";
|
|
3
|
-
import { getPage, isPageFresh, upsertPage } from "../db/queries.js";
|
|
4
|
-
import { logger } from "../logger.js";
|
|
5
|
-
import { convertHtmlToMarkdownMeta } from "../utils.js";
|
|
6
|
-
import { extractKeywords, stripMarkdown } from "../utils/keywords.js";
|
|
7
|
-
export default defineNitroPlugin((nitro) => {
|
|
8
|
-
const config = useRuntimeConfig()["nuxt-ai-ready"];
|
|
9
|
-
const ttl = config.ttl ?? 0;
|
|
10
|
-
nitro.hooks.hook("afterResponse", (event, response) => {
|
|
11
|
-
const body = response?.body;
|
|
12
|
-
const path = event.path;
|
|
13
|
-
if (path.startsWith("/api") || path.startsWith("/_") || path.startsWith("/@") || path.endsWith(".md") || path.includes(".")) {
|
|
14
|
-
return;
|
|
15
|
-
}
|
|
16
|
-
const contentType = event.node.res.getHeader("content-type");
|
|
17
|
-
if (!contentType?.toString().includes("text/html"))
|
|
18
|
-
return;
|
|
19
|
-
const status = event.node.res.statusCode;
|
|
20
|
-
if (status >= 400)
|
|
21
|
-
return;
|
|
22
|
-
event.waitUntil((async () => {
|
|
23
|
-
const html = typeof body === "string" ? body : null;
|
|
24
|
-
if (!html) {
|
|
25
|
-
logger.debug(`[runtime-indexing] Skipping ${path} - no HTML body`);
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
const db = await useDatabase(event);
|
|
29
|
-
if (ttl > 0 && await isPageFresh(db, path, ttl)) {
|
|
30
|
-
logger.debug(`[runtime-indexing] Skipping ${path} - still fresh`);
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
const existing = await getPage(db, path);
|
|
34
|
-
const isUpdate = !!existing;
|
|
35
|
-
const isError = html.includes("__NUXT_ERROR__") || html.includes("nuxt-error-page");
|
|
36
|
-
const result = await convertHtmlToMarkdownMeta(html, path, config.mdreamOptions);
|
|
37
|
-
const updatedAt = result.updatedAt || (/* @__PURE__ */ new Date()).toISOString();
|
|
38
|
-
const headings = JSON.stringify(result.headings);
|
|
39
|
-
const keywords = extractKeywords(stripMarkdown(result.markdown), result.metaKeywords);
|
|
40
|
-
await upsertPage(db, {
|
|
41
|
-
route: path,
|
|
42
|
-
title: result.title,
|
|
43
|
-
description: result.description,
|
|
44
|
-
markdown: result.markdown,
|
|
45
|
-
headings,
|
|
46
|
-
keywords,
|
|
47
|
-
updatedAt,
|
|
48
|
-
isError
|
|
49
|
-
});
|
|
50
|
-
logger.debug(`[runtime-indexing] Indexed: ${path} "${result.title}"`);
|
|
51
|
-
if (!isError) {
|
|
52
|
-
const hookContext = {
|
|
53
|
-
route: path,
|
|
54
|
-
title: result.title,
|
|
55
|
-
description: result.description,
|
|
56
|
-
headings,
|
|
57
|
-
keywords,
|
|
58
|
-
markdown: result.markdown,
|
|
59
|
-
updatedAt,
|
|
60
|
-
isUpdate
|
|
61
|
-
};
|
|
62
|
-
await nitro.hooks.callHook("ai-ready:page:indexed", hookContext);
|
|
63
|
-
}
|
|
64
|
-
})().catch((err) => {
|
|
65
|
-
logger.error(`[runtime-indexing] Failed to index ${path}:`, err);
|
|
66
|
-
}));
|
|
67
|
-
});
|
|
68
|
-
});
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import type { H3Event } from 'h3';
|
|
2
|
-
/** Page entry from database */
|
|
3
|
-
export interface PageEntry {
|
|
4
|
-
route: string;
|
|
5
|
-
title: string;
|
|
6
|
-
description: string;
|
|
7
|
-
headings: string;
|
|
8
|
-
keywords: string[];
|
|
9
|
-
updatedAt: string;
|
|
10
|
-
}
|
|
11
|
-
/** Page data includes markdown content */
|
|
12
|
-
export interface PageData extends PageEntry {
|
|
13
|
-
markdown: string;
|
|
14
|
-
}
|
|
15
|
-
/** Page list item for MCP tools/resources */
|
|
16
|
-
export interface PageListItem {
|
|
17
|
-
route: string;
|
|
18
|
-
title: string;
|
|
19
|
-
description: string;
|
|
20
|
-
headings?: string;
|
|
21
|
-
keywords?: string[];
|
|
22
|
-
}
|
|
23
|
-
/** Read page data - returns page data indexed by route */
|
|
24
|
-
export declare function getPages(event?: H3Event): Promise<Map<string, PageEntry>>;
|
|
25
|
-
/** Get error routes detected during prerender */
|
|
26
|
-
export declare function getErrorRoutes(event?: H3Event): Promise<Set<string>>;
|
|
27
|
-
/** Get pages as flat list for MCP consumption */
|
|
28
|
-
export declare function getPagesList(event?: H3Event): Promise<PageListItem[]>;
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { useDatabase } from "../db/index.js";
|
|
2
|
-
import { getAllPages as dbGetAllPages, getErrorRoutes as dbGetErrorRoutes } from "../db/queries.js";
|
|
3
|
-
function getEventFromContext(providedEvent) {
|
|
4
|
-
if (providedEvent) return providedEvent;
|
|
5
|
-
const { useEvent } = require("nitropack/runtime");
|
|
6
|
-
return useEvent().catch(() => void 0);
|
|
7
|
-
}
|
|
8
|
-
export async function getPages(event) {
|
|
9
|
-
if (import.meta.dev) return /* @__PURE__ */ new Map();
|
|
10
|
-
if (import.meta.prerender) {
|
|
11
|
-
return (await readPrerenderedData()).pages;
|
|
12
|
-
}
|
|
13
|
-
const db = await useDatabase(getEventFromContext(event));
|
|
14
|
-
const pages = await dbGetAllPages(db);
|
|
15
|
-
return new Map(pages.map((p) => [p.route, p]));
|
|
16
|
-
}
|
|
17
|
-
export async function getErrorRoutes(event) {
|
|
18
|
-
if (import.meta.dev) return /* @__PURE__ */ new Set();
|
|
19
|
-
if (import.meta.prerender) {
|
|
20
|
-
return (await readPrerenderedData()).errorRoutes;
|
|
21
|
-
}
|
|
22
|
-
const db = await useDatabase(getEventFromContext(event));
|
|
23
|
-
const routes = await dbGetErrorRoutes(db);
|
|
24
|
-
return new Set(routes);
|
|
25
|
-
}
|
|
26
|
-
export async function getPagesList(event) {
|
|
27
|
-
const pages = await getPages(event);
|
|
28
|
-
return Array.from(pages.values()).map((p) => ({
|
|
29
|
-
route: p.route,
|
|
30
|
-
title: p.title || p.route,
|
|
31
|
-
description: p.description || "",
|
|
32
|
-
headings: p.headings || void 0,
|
|
33
|
-
keywords: p.keywords?.length ? p.keywords : void 0
|
|
34
|
-
}));
|
|
35
|
-
}
|
|
36
|
-
async function readPrerenderedData() {
|
|
37
|
-
const m = await import("#ai-ready-virtual/read-page-data.mjs");
|
|
38
|
-
const data = await m.readPageDataFromFilesystem();
|
|
39
|
-
return {
|
|
40
|
-
pages: new Map(data.pages?.map((p) => [p.route, p]) || []),
|
|
41
|
-
errorRoutes: new Set(data.errorRoutes || [])
|
|
42
|
-
};
|
|
43
|
-
}
|
package/mcp.d.ts
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|