@anubhav-choubey/web-for-agents 0.1.0 → 0.3.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 +77 -512
- package/dist/bin.js +6 -6
- package/dist/{chunk-AZG5MLNG.js → chunk-2Y3LLYEC.js} +5 -1
- package/dist/{chunk-IF32TPGR.js → chunk-357ATBMS.js} +369 -130
- package/dist/chunk-4STTPCBR.js +25 -0
- package/dist/chunk-CGIIB6AF.js +127 -0
- package/dist/{chunk-HONWT6GK.js → chunk-K3B53RIO.js} +66 -34
- package/dist/chunk-L3AYWCSX.js +33 -0
- package/dist/chunk-MIVGE5TM.js +34 -0
- package/dist/chunk-OKCYZE6C.js +245 -0
- package/dist/{chunk-5TNG4QMP.js → chunk-PGZH33B5.js} +20 -2
- package/dist/{chunk-ZYMNO5AO.js → chunk-T42S3WRV.js} +161 -62
- package/dist/cli.js +6 -6
- package/dist/{happyDom-XVDHYJDM.js → happyDom-ZEFNMD7B.js} +3 -3
- package/dist/index.d.ts +89 -11
- package/dist/index.js +113 -246
- package/dist/overlay.js +22 -42
- package/dist/{renderChild-Y2RFSYY4.js → renderChild-PSQLAIUW.js} +27 -4
- package/dist/vite.d.ts +116 -3
- package/dist/vite.js +867 -192
- package/package.json +1 -1
- package/dist/chunk-CKXHTGGT.js +0 -25
- package/dist/chunk-FEAKVNMG.js +0 -12
- package/dist/chunk-LCLDQ3A3.js +0 -26
- package/dist/chunk-LCVI2PRP.js +0 -13
package/dist/vite.js
CHANGED
|
@@ -1,23 +1,35 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
EMPTY_OBJECT_SCHEMA,
|
|
3
|
+
schemaFromForm
|
|
4
|
+
} from "./chunk-OKCYZE6C.js";
|
|
4
5
|
import {
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
AI_BOTS,
|
|
7
|
+
scanHtml
|
|
8
|
+
} from "./chunk-CGIIB6AF.js";
|
|
9
|
+
import {
|
|
10
|
+
metaLengthWarnings
|
|
11
|
+
} from "./chunk-L3AYWCSX.js";
|
|
7
12
|
import {
|
|
8
13
|
DEFAULT_CONTENT_SELECTOR,
|
|
9
14
|
DEFAULT_SHORTCUT,
|
|
10
15
|
buildPageMarkdown,
|
|
11
16
|
escapeLinkTarget,
|
|
12
17
|
escapeMarkdownInline,
|
|
18
|
+
firstPerName,
|
|
19
|
+
linkActions,
|
|
20
|
+
markupActions,
|
|
21
|
+
markupLinks,
|
|
13
22
|
parseShortcut,
|
|
14
23
|
readPageMeta,
|
|
15
24
|
selectContentRegion
|
|
16
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-T42S3WRV.js";
|
|
17
26
|
import {
|
|
18
27
|
compareStrings
|
|
19
28
|
} from "./chunk-AAIYCJD3.js";
|
|
20
|
-
import
|
|
29
|
+
import {
|
|
30
|
+
AGENT_MAP_VERSION,
|
|
31
|
+
isValidActionName
|
|
32
|
+
} from "./chunk-4STTPCBR.js";
|
|
21
33
|
import {
|
|
22
34
|
IDLE_MS,
|
|
23
35
|
PROBE_ATTR,
|
|
@@ -25,13 +37,19 @@ import {
|
|
|
25
37
|
TEMP_BASE_ATTR,
|
|
26
38
|
prepareShell,
|
|
27
39
|
readyCheck
|
|
28
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-K3B53RIO.js";
|
|
29
41
|
import {
|
|
42
|
+
ACTION_ATTR,
|
|
43
|
+
ACTION_DESCRIPTION_ATTR,
|
|
44
|
+
ACTION_DESTRUCTIVE_ATTR,
|
|
30
45
|
AGENT_GLOBAL,
|
|
31
46
|
AGENT_MAP_PATH,
|
|
32
47
|
CONTENT_ATTR,
|
|
48
|
+
HEAD_OWNED_ATTR,
|
|
49
|
+
LINK_ACTION_SELECTOR,
|
|
33
50
|
LLMS_FULL_TXT_PATH,
|
|
34
51
|
LLMS_TXT_PATH,
|
|
52
|
+
MARKDOWN_LINK_KEY,
|
|
35
53
|
MARKDOWN_MIME,
|
|
36
54
|
PRERENDERED_ATTR,
|
|
37
55
|
ROBOTS_PATH,
|
|
@@ -41,20 +59,25 @@ import {
|
|
|
41
59
|
mountPath,
|
|
42
60
|
normalizeRoute,
|
|
43
61
|
publicUrl,
|
|
44
|
-
trimTrailingSlash
|
|
45
|
-
|
|
62
|
+
trimTrailingSlash,
|
|
63
|
+
tryResolveUrl
|
|
64
|
+
} from "./chunk-2Y3LLYEC.js";
|
|
46
65
|
import {
|
|
47
66
|
POLL_MS,
|
|
48
67
|
RenderError,
|
|
49
68
|
SERIALIZE_EXPR,
|
|
69
|
+
SNAPSHOT_GRACE_MS,
|
|
70
|
+
TimeoutError,
|
|
71
|
+
assertNoPageErrors,
|
|
50
72
|
blockedHint,
|
|
51
73
|
createDeadline,
|
|
52
74
|
createOriginPolicy,
|
|
53
75
|
readyTimeoutMessage,
|
|
54
76
|
runInPage,
|
|
77
|
+
snapshotWarning,
|
|
55
78
|
waitForReady,
|
|
56
79
|
withoutBlockedLoads
|
|
57
|
-
} from "./chunk-
|
|
80
|
+
} from "./chunk-PGZH33B5.js";
|
|
58
81
|
import {
|
|
59
82
|
LOG_PREFIX,
|
|
60
83
|
errorMessage,
|
|
@@ -77,9 +100,18 @@ function segments(route) {
|
|
|
77
100
|
function decodeSegments(route) {
|
|
78
101
|
return segments(normalizeRoute(route)).map((s) => decodeURIComponent(s));
|
|
79
102
|
}
|
|
80
|
-
function
|
|
103
|
+
function encodePathSegment(segment) {
|
|
104
|
+
return encodeURIComponent(segment).replace(/%(24|26|2B|2C|3B|3D|3A|40)/g, (m) => decodeURIComponent(m));
|
|
105
|
+
}
|
|
106
|
+
function routeOfHtmlFile(file) {
|
|
107
|
+
const segs = file.slice(0, -".html".length).split("/");
|
|
108
|
+
if (segs[segs.length - 1] === "index") segs.pop();
|
|
109
|
+
return "/" + segs.map(encodePathSegment).join("/");
|
|
110
|
+
}
|
|
111
|
+
function routeHtmlFile(route, layout = "directory") {
|
|
81
112
|
const segs = decodeSegments(route);
|
|
82
|
-
|
|
113
|
+
if (segs.length === 0) return "index.html";
|
|
114
|
+
return segs.join("/") + (layout === "flat" ? ".html" : "/index.html");
|
|
83
115
|
}
|
|
84
116
|
function routeMdFile(route) {
|
|
85
117
|
return markdownPathFor(route).slice(1).split("/").map((s) => decodeURIComponent(s)).join("/");
|
|
@@ -108,7 +140,7 @@ function isSafeRoute(route) {
|
|
|
108
140
|
var MAX_NAME_BYTES = 255;
|
|
109
141
|
var MAX_SEGMENT_BYTES = MAX_NAME_BYTES - ".md".length;
|
|
110
142
|
var MAX_ROUTE_BYTES = 1024;
|
|
111
|
-
function isRouteTooLong(route) {
|
|
143
|
+
function isRouteTooLong(route, layout = "directory") {
|
|
112
144
|
let segs;
|
|
113
145
|
try {
|
|
114
146
|
segs = decodeSegments(route);
|
|
@@ -116,9 +148,10 @@ function isRouteTooLong(route) {
|
|
|
116
148
|
return false;
|
|
117
149
|
}
|
|
118
150
|
let total = 0;
|
|
119
|
-
|
|
151
|
+
const leafMax = layout === "flat" ? MAX_NAME_BYTES - ".html".length : MAX_SEGMENT_BYTES;
|
|
152
|
+
for (const [i, s] of segs.entries()) {
|
|
120
153
|
const n = Buffer.byteLength(s, "utf8");
|
|
121
|
-
if (n > MAX_SEGMENT_BYTES) return true;
|
|
154
|
+
if (n > (i === segs.length - 1 ? leafMax : MAX_SEGMENT_BYTES)) return true;
|
|
122
155
|
total += n + 1;
|
|
123
156
|
}
|
|
124
157
|
return total > MAX_ROUTE_BYTES;
|
|
@@ -136,16 +169,16 @@ function linkToRoute(href, origin, base) {
|
|
|
136
169
|
if (u.protocol !== "http:" && u.protocol !== "https:") return null;
|
|
137
170
|
if (u.origin !== new URL(origin).origin) return null;
|
|
138
171
|
const b = trimTrailingSlash(base);
|
|
139
|
-
let
|
|
172
|
+
let path6 = u.pathname;
|
|
140
173
|
if (b !== "") {
|
|
141
|
-
if (
|
|
142
|
-
|
|
174
|
+
if (path6 !== b && !path6.startsWith(b + "/")) return null;
|
|
175
|
+
path6 = path6.slice(b.length);
|
|
143
176
|
}
|
|
144
|
-
if (
|
|
145
|
-
|
|
146
|
-
const last =
|
|
177
|
+
if (path6 === "") path6 = "/";
|
|
178
|
+
path6 = path6.replace(/\/index\.html$/, "") || "/";
|
|
179
|
+
const last = path6.split("/").pop();
|
|
147
180
|
if (/\.[a-z0-9]+$/i.test(last)) return null;
|
|
148
|
-
const route = normalizeRoute(
|
|
181
|
+
const route = normalizeRoute(path6);
|
|
149
182
|
return isSafeRoute(route) ? route : null;
|
|
150
183
|
}
|
|
151
184
|
|
|
@@ -155,14 +188,32 @@ var WEBMCP_INFO = {
|
|
|
155
188
|
api: "document.modelContext",
|
|
156
189
|
spec: "https://webmachinelearning.github.io/webmcp/"
|
|
157
190
|
};
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
191
|
+
var AGENT_PAGE_IN_PAGE_ARG = {
|
|
192
|
+
globalKey: AGENT_GLOBAL,
|
|
193
|
+
linkSelector: LINK_ACTION_SELECTOR,
|
|
194
|
+
nameAttr: ACTION_ATTR,
|
|
195
|
+
descriptionAttr: ACTION_DESCRIPTION_ATTR,
|
|
196
|
+
destructiveAttr: ACTION_DESTRUCTIVE_ATTR
|
|
197
|
+
};
|
|
198
|
+
function collectAgentPageInPage(arg) {
|
|
199
|
+
const api = window[arg.globalKey];
|
|
200
|
+
const actions = api && typeof api.actions === "function" ? api.actions() : [];
|
|
201
|
+
const links = [];
|
|
202
|
+
document.querySelectorAll(arg.linkSelector).forEach((el) => {
|
|
203
|
+
const name = (el.getAttribute(arg.nameAttr) || "").trim();
|
|
204
|
+
if (!name) return;
|
|
205
|
+
links.push({
|
|
206
|
+
name,
|
|
207
|
+
description: el.getAttribute(arg.descriptionAttr) || null,
|
|
208
|
+
destructive: el.getAttribute(arg.destructiveAttr) === "true",
|
|
209
|
+
href: el.getAttribute("href") || ""
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
return { actions, links };
|
|
161
213
|
}
|
|
162
214
|
var byName = (a, b) => compareStrings(a.name, b.name);
|
|
163
215
|
function toPage(siteUrl, p) {
|
|
164
|
-
const
|
|
165
|
-
const actions = p.actions.filter((a) => !seen.has(a.name) && !!seen.add(a.name)).sort(byName);
|
|
216
|
+
const actions = firstPerName(p.actions).sort(byName);
|
|
166
217
|
return {
|
|
167
218
|
path: p.route,
|
|
168
219
|
url: publicUrl(siteUrl, p.route),
|
|
@@ -199,14 +250,21 @@ function agentMapExtension(opts) {
|
|
|
199
250
|
return {
|
|
200
251
|
name: "agent-map",
|
|
201
252
|
inPage: collectAgentPageInPage,
|
|
202
|
-
inPageArg:
|
|
253
|
+
inPageArg: AGENT_PAGE_IN_PAGE_ARG,
|
|
203
254
|
onRoute(route, page) {
|
|
204
255
|
data.set(route, page);
|
|
205
256
|
},
|
|
206
257
|
llmsSections: () => [agentMapLlmsSection(siteUrl, fileName)],
|
|
207
258
|
finalize(ctx) {
|
|
208
259
|
const pages = ctx.pages.map((p) => {
|
|
209
|
-
const
|
|
260
|
+
const found = data.get(p.route);
|
|
261
|
+
const actions = found?.actions ?? [];
|
|
262
|
+
const links = linkActions(
|
|
263
|
+
found?.links ?? [],
|
|
264
|
+
{ pageUrl: p.url, page: p.route, taken: new Set(actions.map((a) => a.name)) },
|
|
265
|
+
ctx.warn
|
|
266
|
+
);
|
|
267
|
+
const page = { route: p.route, actions: [...actions, ...links] };
|
|
210
268
|
if (p.title) page.title = p.title;
|
|
211
269
|
if (p.description) page.description = p.description;
|
|
212
270
|
if (p.mdUrl) page.markdown = p.mdUrl;
|
|
@@ -231,6 +289,21 @@ function outputFileName(fileName) {
|
|
|
231
289
|
}
|
|
232
290
|
return rel;
|
|
233
291
|
}
|
|
292
|
+
function symlinkOnPath(outDir, rel) {
|
|
293
|
+
let p = outDir;
|
|
294
|
+
const parts = rel.split("/");
|
|
295
|
+
for (let i = 0; i < parts.length; i++) {
|
|
296
|
+
p = path.join(p, parts[i]);
|
|
297
|
+
let st;
|
|
298
|
+
try {
|
|
299
|
+
st = fs.lstatSync(p);
|
|
300
|
+
} catch {
|
|
301
|
+
return null;
|
|
302
|
+
}
|
|
303
|
+
if (st.isSymbolicLink()) return parts.slice(0, i + 1).join("/");
|
|
304
|
+
}
|
|
305
|
+
return null;
|
|
306
|
+
}
|
|
234
307
|
var short = (s, max) => s.length <= max ? s : s.slice(0, max - 1) + "\u2026";
|
|
235
308
|
function createFileStager(opts) {
|
|
236
309
|
const files = /* @__PURE__ */ new Map();
|
|
@@ -247,6 +320,14 @@ function createFileStager(opts) {
|
|
|
247
320
|
stage(fileName, source) {
|
|
248
321
|
const file = outputFileName(fileName);
|
|
249
322
|
if (inPublicDir(file)) return { file, status: "skipped" };
|
|
323
|
+
const link = symlinkOnPath(opts.outDir, file);
|
|
324
|
+
if (link !== null) {
|
|
325
|
+
if (!warned.has("link:" + file)) {
|
|
326
|
+
warned.add("link:" + file);
|
|
327
|
+
opts.warn(`${LOG_PREFIX} ${link} is a symbolic link; not writing ${file} through it`);
|
|
328
|
+
}
|
|
329
|
+
return { file, status: "skipped" };
|
|
330
|
+
}
|
|
250
331
|
const status = files.has(file) ? "replaced" : "staged";
|
|
251
332
|
files.set(file, source);
|
|
252
333
|
return { file, status };
|
|
@@ -299,34 +380,6 @@ function createFileStager(opts) {
|
|
|
299
380
|
};
|
|
300
381
|
}
|
|
301
382
|
|
|
302
|
-
// src/vite/llms.ts
|
|
303
|
-
function header(site) {
|
|
304
|
-
const blocks = [`# ${escapeMarkdownInline(site.title)}`];
|
|
305
|
-
const desc = escapeMarkdownInline(site.description);
|
|
306
|
-
if (desc) blocks.push(`> ${desc}`);
|
|
307
|
-
return blocks;
|
|
308
|
-
}
|
|
309
|
-
function buildLlmsTxt(site, pages, sections = []) {
|
|
310
|
-
const blocks = header(site);
|
|
311
|
-
const lines = [...pages].sort(byRoute).map((p) => {
|
|
312
|
-
const title = escapeMarkdownInline(p.title);
|
|
313
|
-
const desc = escapeMarkdownInline(p.description);
|
|
314
|
-
return `- [${title}](${escapeLinkTarget(p.mdUrl ?? p.url)})${desc ? `: ${desc}` : ""}`;
|
|
315
|
-
});
|
|
316
|
-
blocks.push(["## Pages", ...lines.length ? ["", ...lines] : []].join("\n"));
|
|
317
|
-
for (const s of sections) {
|
|
318
|
-
blocks.push([`## ${s.heading}`, ...s.lines.length ? ["", ...s.lines] : []].join("\n"));
|
|
319
|
-
}
|
|
320
|
-
return blocks.join("\n\n") + "\n";
|
|
321
|
-
}
|
|
322
|
-
function buildLlmsFullTxt(site, pages) {
|
|
323
|
-
const head = header(site).join("\n\n");
|
|
324
|
-
const blocks = [...pages].sort(byRoute).filter((p) => p.markdown !== void 0).map((p) => `Source: ${p.url}
|
|
325
|
-
|
|
326
|
-
${p.markdown.trim()}`);
|
|
327
|
-
return [head, blocks.join("\n\n---\n\n")].filter(Boolean).join("\n\n") + "\n";
|
|
328
|
-
}
|
|
329
|
-
|
|
330
383
|
// src/vite/prerender/happyDomProcess.ts
|
|
331
384
|
import { fork } from "child_process";
|
|
332
385
|
import { createHash } from "crypto";
|
|
@@ -352,7 +405,7 @@ function nodeModulesRoot(file) {
|
|
|
352
405
|
}
|
|
353
406
|
var sourceEntry;
|
|
354
407
|
async function childEntryFile() {
|
|
355
|
-
const { CHILD_ENTRY } = await import("./renderChild-
|
|
408
|
+
const { CHILD_ENTRY } = await import("./renderChild-PSQLAIUW.js");
|
|
356
409
|
const file = fileURLToPath(CHILD_ENTRY);
|
|
357
410
|
if (!file.endsWith(".ts")) return file;
|
|
358
411
|
return sourceEntry ??= bundleFromSource(file);
|
|
@@ -732,8 +785,18 @@ function resolvePrerender(input) {
|
|
|
732
785
|
concurrency: posInt("concurrency", input.concurrency, usesBrowser ? 4 : 8),
|
|
733
786
|
maxRoutes: posInt("maxRoutes", input.maxRoutes, 500),
|
|
734
787
|
allowOrigins,
|
|
735
|
-
isolation: resolveIsolation(input.isolation, bad)
|
|
788
|
+
isolation: resolveIsolation(input.isolation, bad),
|
|
789
|
+
fileLayout: input.fileLayout ?? "directory",
|
|
790
|
+
onTimeout: input.onTimeout ?? "fail"
|
|
736
791
|
};
|
|
792
|
+
if (out.fileLayout !== "directory" && out.fileLayout !== "flat") bad("fileLayout", '"directory" or "flat"');
|
|
793
|
+
if (out.onTimeout !== "fail" && out.onTimeout !== "snapshot") bad("onTimeout", '"fail" or "snapshot"');
|
|
794
|
+
if (input.readySelector !== void 0) {
|
|
795
|
+
if (typeof input.readySelector !== "string" || input.readySelector.trim() === "") {
|
|
796
|
+
bad("readySelector", "a non-empty string");
|
|
797
|
+
}
|
|
798
|
+
out.readySelector = input.readySelector;
|
|
799
|
+
}
|
|
737
800
|
if (input.executablePath !== void 0) out.executablePath = input.executablePath;
|
|
738
801
|
if (input.idleMs !== void 0) {
|
|
739
802
|
if (typeof input.idleMs !== "number" || !Number.isInteger(input.idleMs) || input.idleMs < 0) {
|
|
@@ -751,6 +814,90 @@ function agentOutputs(r) {
|
|
|
751
814
|
if (r.agentMap) out.push(r.agentMap.fileName);
|
|
752
815
|
return out;
|
|
753
816
|
}
|
|
817
|
+
function resolveMarkdown(input) {
|
|
818
|
+
if (input !== void 0 && (typeof input !== "object" || input === null)) {
|
|
819
|
+
throw new Error(withPrefix("markdown must be false or { contentSelector, transform }"));
|
|
820
|
+
}
|
|
821
|
+
const sel = input?.contentSelector;
|
|
822
|
+
if (sel !== void 0 && (typeof sel !== "string" || sel === "")) {
|
|
823
|
+
throw new Error(`${LOG_PREFIX} markdown.contentSelector must be a non-empty string`);
|
|
824
|
+
}
|
|
825
|
+
const out = { contentSelector: sel ?? DEFAULT_CONTENT_SELECTOR };
|
|
826
|
+
if (input?.transform !== void 0) {
|
|
827
|
+
if (typeof input.transform !== "function") throw new Error(withPrefix("markdown.transform must be a function"));
|
|
828
|
+
out.transform = input.transform;
|
|
829
|
+
}
|
|
830
|
+
return out;
|
|
831
|
+
}
|
|
832
|
+
function resolveSitemap(input) {
|
|
833
|
+
if (input === void 0 || typeof input === "boolean") return { sitemap: input ?? true, sitemapLastmod: "none" };
|
|
834
|
+
if (typeof input !== "object" || input === null || Array.isArray(input)) {
|
|
835
|
+
throw new Error(withPrefix("sitemap must be a boolean or { lastmod }"));
|
|
836
|
+
}
|
|
837
|
+
const lastmod = input.lastmod ?? "none";
|
|
838
|
+
if (lastmod !== "file" && lastmod !== "none" && typeof lastmod !== "function") {
|
|
839
|
+
throw new Error(withPrefix('sitemap.lastmod must be "file", "none" or a function'));
|
|
840
|
+
}
|
|
841
|
+
return { sitemap: true, sitemapLastmod: lastmod };
|
|
842
|
+
}
|
|
843
|
+
function resolveLlms(input, siteUrl) {
|
|
844
|
+
if (input === void 0) return {};
|
|
845
|
+
if (typeof input !== "object" || input === null || Array.isArray(input)) {
|
|
846
|
+
throw new Error(withPrefix("llms must be false or { title, description, intro, sections }"));
|
|
847
|
+
}
|
|
848
|
+
const str = (v, field, nonEmpty = false) => {
|
|
849
|
+
if (v === void 0) return void 0;
|
|
850
|
+
if (typeof v !== "string" || nonEmpty && v.trim() === "") {
|
|
851
|
+
throw new Error(withPrefix(`llms.${field} must be a ${nonEmpty ? "non-empty " : ""}string`));
|
|
852
|
+
}
|
|
853
|
+
return v;
|
|
854
|
+
};
|
|
855
|
+
const out = { ...input };
|
|
856
|
+
str(input.title, "title");
|
|
857
|
+
str(input.description, "description");
|
|
858
|
+
str(input.intro, "intro");
|
|
859
|
+
if (input.sections === void 0) return out;
|
|
860
|
+
if (!Array.isArray(input.sections)) throw new Error(withPrefix("llms.sections must be an array"));
|
|
861
|
+
out.sections = input.sections.map((sec, i) => {
|
|
862
|
+
const at = `sections[${i}]`;
|
|
863
|
+
if (typeof sec !== "object" || sec === null || Array.isArray(sec)) {
|
|
864
|
+
throw new Error(withPrefix(`llms.${at} must be an object such as { title, text, links }`));
|
|
865
|
+
}
|
|
866
|
+
const { title, text, links } = sec;
|
|
867
|
+
if (title === void 0) throw new Error(withPrefix(`llms.${at}.title is required`));
|
|
868
|
+
const s = { title: str(title, `${at}.title`, true) };
|
|
869
|
+
const t = str(text, `${at}.text`);
|
|
870
|
+
if (t !== void 0) s.text = t;
|
|
871
|
+
if (links !== void 0) {
|
|
872
|
+
if (!Array.isArray(links)) throw new Error(withPrefix(`llms.${at}.links must be an array`));
|
|
873
|
+
s.links = links.map((l, j) => {
|
|
874
|
+
const lat = `${at}.links[${j}]`;
|
|
875
|
+
if (typeof l !== "object" || l === null || Array.isArray(l)) {
|
|
876
|
+
throw new Error(withPrefix(`llms.${lat} must be an object such as { title, url, description }`));
|
|
877
|
+
}
|
|
878
|
+
const link = l;
|
|
879
|
+
if (link.title === void 0) throw new Error(withPrefix(`llms.${lat}.title is required`));
|
|
880
|
+
if (link.url === void 0) throw new Error(withPrefix(`llms.${lat}.url is required`));
|
|
881
|
+
const url = typeof link.url === "string" ? tryResolveUrl(link.url.trim(), siteUrl + "/") : null;
|
|
882
|
+
const scheme = url === null ? "" : new URL(url).protocol;
|
|
883
|
+
if (url === null || !["http:", "https:", "mailto:"].includes(scheme)) {
|
|
884
|
+
throw new Error(
|
|
885
|
+
withPrefix(`llms.${lat}.url must be an http(s) or mailto: URL, or a path on the site (got ${JSON.stringify(link.url)})`)
|
|
886
|
+
);
|
|
887
|
+
}
|
|
888
|
+
const o = { title: str(link.title, `${lat}.title`, true), url };
|
|
889
|
+
const d = str(link.description, `${lat}.description`);
|
|
890
|
+
if (d !== void 0) o.description = d;
|
|
891
|
+
return o;
|
|
892
|
+
});
|
|
893
|
+
}
|
|
894
|
+
if (!s.text?.trim() && !s.links?.length) {
|
|
895
|
+
throw new Error(withPrefix(`llms.${at} needs text or links`));
|
|
896
|
+
}
|
|
897
|
+
return s;
|
|
898
|
+
});
|
|
899
|
+
return out;
|
|
900
|
+
}
|
|
754
901
|
var AGENT_MAP_FILE = /^[A-Za-z0-9_.-]+\.json$/;
|
|
755
902
|
function resolveAgentMap(input) {
|
|
756
903
|
if (input === false) return false;
|
|
@@ -814,8 +961,8 @@ function resolveOptions(input) {
|
|
|
814
961
|
throw new Error(`${LOG_PREFIX} robots.ai.overrides.${bot} must be "allow" or "block"`);
|
|
815
962
|
}
|
|
816
963
|
}
|
|
817
|
-
for (const
|
|
818
|
-
if (/[\r\n]/.test(
|
|
964
|
+
for (const path6 of input.robots.disallow ?? []) {
|
|
965
|
+
if (/[\r\n]/.test(path6)) {
|
|
819
966
|
throw new Error(`${LOG_PREFIX} robots.disallow paths must not contain line breaks`);
|
|
820
967
|
}
|
|
821
968
|
}
|
|
@@ -826,6 +973,7 @@ function resolveOptions(input) {
|
|
|
826
973
|
const prerender = input.prerender === false ? false : resolvePrerender(input.prerender ?? {});
|
|
827
974
|
let markdown = false;
|
|
828
975
|
let llms = false;
|
|
976
|
+
const requestedLlms = input.llms === false ? false : resolveLlms(input.llms, siteUrl);
|
|
829
977
|
const requestedAgentMap = resolveAgentMap(input.agentMap);
|
|
830
978
|
let agentMap = false;
|
|
831
979
|
if (prerender === false) {
|
|
@@ -836,21 +984,15 @@ function resolveOptions(input) {
|
|
|
836
984
|
warnings.push(withPrefix(`${names} ${verb} disabled because prerender is false`));
|
|
837
985
|
}
|
|
838
986
|
} else {
|
|
839
|
-
if (input.markdown !== false)
|
|
840
|
-
|
|
841
|
-
if (sel !== void 0 && (typeof sel !== "string" || sel === "")) {
|
|
842
|
-
throw new Error(`${LOG_PREFIX} markdown.contentSelector must be a non-empty string`);
|
|
843
|
-
}
|
|
844
|
-
markdown = { contentSelector: sel ?? DEFAULT_CONTENT_SELECTOR };
|
|
845
|
-
}
|
|
846
|
-
if (input.llms !== false) llms = { ...input.llms };
|
|
987
|
+
if (input.markdown !== false) markdown = resolveMarkdown(input.markdown);
|
|
988
|
+
llms = requestedLlms;
|
|
847
989
|
agentMap = requestedAgentMap;
|
|
848
990
|
}
|
|
849
991
|
const resolved = {
|
|
850
992
|
siteUrl,
|
|
851
993
|
routes,
|
|
852
994
|
robots: input.robots,
|
|
853
|
-
|
|
995
|
+
...resolveSitemap(input.sitemap),
|
|
854
996
|
exclude,
|
|
855
997
|
prerender,
|
|
856
998
|
markdown,
|
|
@@ -883,9 +1025,9 @@ function parseHtml(html) {
|
|
|
883
1025
|
handleDisabledFileLoadingAsSuccess: true
|
|
884
1026
|
}
|
|
885
1027
|
});
|
|
886
|
-
const
|
|
1028
|
+
const document2 = new window2.DOMParser().parseFromString(html, "text/html");
|
|
887
1029
|
return {
|
|
888
|
-
document,
|
|
1030
|
+
document: document2,
|
|
889
1031
|
dispose() {
|
|
890
1032
|
window2.happyDOM.close();
|
|
891
1033
|
}
|
|
@@ -898,9 +1040,9 @@ var SHOW_TEXT = 4;
|
|
|
898
1040
|
var FILTER_ACCEPT = 1;
|
|
899
1041
|
var FILTER_REJECT = 2;
|
|
900
1042
|
var NO_TEXT = /* @__PURE__ */ new Set(["SCRIPT", "STYLE", "NOSCRIPT", "TEMPLATE"]);
|
|
901
|
-
function bodyHasText(
|
|
902
|
-
if (!
|
|
903
|
-
const walker =
|
|
1043
|
+
function bodyHasText(document2) {
|
|
1044
|
+
if (!document2.body) return false;
|
|
1045
|
+
const walker = document2.createTreeWalker(document2.body, SHOW_ELEMENT | SHOW_TEXT, {
|
|
904
1046
|
acceptNode: (n) => n.nodeType === 1 && NO_TEXT.has(n.tagName.toUpperCase()) ? FILTER_REJECT : FILTER_ACCEPT
|
|
905
1047
|
});
|
|
906
1048
|
for (let n = walker.nextNode(); n; n = walker.nextNode()) {
|
|
@@ -908,11 +1050,11 @@ function bodyHasText(document) {
|
|
|
908
1050
|
}
|
|
909
1051
|
return false;
|
|
910
1052
|
}
|
|
911
|
-
function analyzeDocument(
|
|
912
|
-
const meta = readPageMeta(
|
|
1053
|
+
function analyzeDocument(document2, opts, mode = {}) {
|
|
1054
|
+
const meta = readPageMeta(document2);
|
|
913
1055
|
const title = meta.title ?? opts.route;
|
|
914
1056
|
const links = [];
|
|
915
|
-
|
|
1057
|
+
document2.querySelectorAll("a[href]").forEach((a) => {
|
|
916
1058
|
if (a.hasAttribute("download")) return;
|
|
917
1059
|
try {
|
|
918
1060
|
const u = new URL(a.getAttribute("href"), opts.pageUrl);
|
|
@@ -920,8 +1062,8 @@ function analyzeDocument(document, opts, mode = {}) {
|
|
|
920
1062
|
} catch {
|
|
921
1063
|
}
|
|
922
1064
|
});
|
|
923
|
-
const hasText = bodyHasText(
|
|
924
|
-
const { element, source } = selectContentRegion(
|
|
1065
|
+
const hasText = bodyHasText(document2);
|
|
1066
|
+
const { element, source } = selectContentRegion(document2, {
|
|
925
1067
|
contentSelector: opts.contentSelector,
|
|
926
1068
|
...mode.inPlace ? { inPlace: true } : {}
|
|
927
1069
|
});
|
|
@@ -951,9 +1093,9 @@ var URL_ATTRS = [
|
|
|
951
1093
|
function mapSrcset(value, fn) {
|
|
952
1094
|
return value.replace(/(^|,)(\s*)([^\s,][^\s]*?)(?=,|\s|$)/g, (_m, sep2, ws, url) => sep2 + ws + fn(url));
|
|
953
1095
|
}
|
|
954
|
-
function rewriteUrls(
|
|
1096
|
+
function rewriteUrls(document2, fn, attrs = URL_ATTRS) {
|
|
955
1097
|
for (const [tag, attr] of attrs) {
|
|
956
|
-
|
|
1098
|
+
document2.querySelectorAll(`${tag}[${attr}]`).forEach((el) => {
|
|
957
1099
|
const v = el.getAttribute(attr);
|
|
958
1100
|
const next = attr === "srcset" ? mapSrcset(v, fn) : fn(v);
|
|
959
1101
|
if (next !== v) el.setAttribute(attr, next);
|
|
@@ -961,18 +1103,18 @@ function rewriteUrls(document, fn, attrs = URL_ATTRS) {
|
|
|
961
1103
|
}
|
|
962
1104
|
}
|
|
963
1105
|
function finalizePage(html, opts, analyze) {
|
|
964
|
-
const { document, dispose } = parseHtml(html);
|
|
1106
|
+
const { document: document2, dispose } = parseHtml(html);
|
|
965
1107
|
try {
|
|
966
|
-
const out = finalizeDocument(
|
|
967
|
-
return { html: out, info: analyzeDocument(
|
|
1108
|
+
const out = finalizeDocument(document2, opts);
|
|
1109
|
+
return { html: out, info: analyzeDocument(document2, analyze, { inPlace: true }) };
|
|
968
1110
|
} finally {
|
|
969
1111
|
dispose();
|
|
970
1112
|
}
|
|
971
1113
|
}
|
|
972
|
-
function finalizeDocument(
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
1114
|
+
function finalizeDocument(document2, opts) {
|
|
1115
|
+
document2.querySelectorAll(`[${PROBE_ATTR}], [${TEMP_BASE_ATTR}]`).forEach((el) => el.remove());
|
|
1116
|
+
document2.documentElement.setAttribute(PRERENDERED_ATTR, "");
|
|
1117
|
+
document2.querySelectorAll(`script[${REL_SRC_ATTR}]`).forEach((el) => {
|
|
976
1118
|
const src = el.getAttribute("src");
|
|
977
1119
|
if (src?.startsWith("/")) el.setAttribute("src", "." + src);
|
|
978
1120
|
el.removeAttribute(REL_SRC_ATTR);
|
|
@@ -980,24 +1122,24 @@ function finalizeDocument(document, opts) {
|
|
|
980
1122
|
if (opts.origin) {
|
|
981
1123
|
const origin = trimTrailingSlash(opts.origin);
|
|
982
1124
|
const attrs = opts.fullBase ? [...URL_ATTRS, ["a", "href"]] : URL_ATTRS;
|
|
983
|
-
rewriteUrls(
|
|
1125
|
+
rewriteUrls(document2, (u) => {
|
|
984
1126
|
if (!u.startsWith(origin)) return u;
|
|
985
1127
|
const rest = u.slice(origin.length);
|
|
986
1128
|
if (rest !== "" && !/^[/?#]/.test(rest)) return u;
|
|
987
|
-
const
|
|
988
|
-
if (opts.fullBase) return trimTrailingSlash(opts.fullBase) + "/" +
|
|
989
|
-
return opts.relativeBase ? "." +
|
|
1129
|
+
const path6 = rest.startsWith("/") ? rest : "/" + rest;
|
|
1130
|
+
if (opts.fullBase) return trimTrailingSlash(opts.fullBase) + "/" + path6.slice(1);
|
|
1131
|
+
return opts.relativeBase ? "." + path6 : path6;
|
|
990
1132
|
}, attrs);
|
|
991
1133
|
}
|
|
992
1134
|
if (opts.relativeBase) {
|
|
993
1135
|
const depth = routeDepth(opts.route);
|
|
994
1136
|
if (depth > 0) {
|
|
995
1137
|
const up = "../".repeat(depth);
|
|
996
|
-
rewriteUrls(
|
|
1138
|
+
rewriteUrls(document2, (u) => u.startsWith("./") ? up + u.slice(2) : u);
|
|
997
1139
|
}
|
|
998
1140
|
}
|
|
999
1141
|
const seen = /* @__PURE__ */ new Set();
|
|
1000
|
-
|
|
1142
|
+
document2.querySelectorAll("link[href]").forEach((el) => {
|
|
1001
1143
|
const rel = el.getAttribute("rel") ?? "";
|
|
1002
1144
|
if (!DEDUPE_RELS.has(rel)) return;
|
|
1003
1145
|
const key = [rel, el.getAttribute("href"), el.getAttribute("as"), el.getAttribute("media"), el.getAttribute("type")].join("\n");
|
|
@@ -1005,16 +1147,16 @@ function finalizeDocument(document, opts) {
|
|
|
1005
1147
|
else seen.add(key);
|
|
1006
1148
|
});
|
|
1007
1149
|
if (opts.markdownUrl) {
|
|
1008
|
-
let link =
|
|
1150
|
+
let link = document2.head.querySelector(`link[rel="alternate"][type="${MARKDOWN_MIME}"]`);
|
|
1009
1151
|
if (!link) {
|
|
1010
|
-
link =
|
|
1152
|
+
link = document2.createElement("link");
|
|
1011
1153
|
link.setAttribute("rel", "alternate");
|
|
1012
1154
|
link.setAttribute("type", MARKDOWN_MIME);
|
|
1013
|
-
|
|
1155
|
+
document2.head.appendChild(link);
|
|
1014
1156
|
}
|
|
1015
1157
|
link.setAttribute("href", opts.markdownUrl);
|
|
1016
1158
|
}
|
|
1017
|
-
return "<!DOCTYPE html>" +
|
|
1159
|
+
return "<!DOCTYPE html>" + document2.documentElement.outerHTML;
|
|
1018
1160
|
}
|
|
1019
1161
|
|
|
1020
1162
|
// src/vite/prerender/crawl.ts
|
|
@@ -1050,7 +1192,7 @@ async function crawlRoutes(opts, render) {
|
|
|
1050
1192
|
const seeds = [];
|
|
1051
1193
|
for (const s of [...new Set(opts.seeds.map(normalizeRoute))].sort()) {
|
|
1052
1194
|
if (!isSafeRoute(s)) continue;
|
|
1053
|
-
if (isRouteTooLong(s)) seedTooLong.push(s);
|
|
1195
|
+
if (isRouteTooLong(s, opts.fileLayout)) seedTooLong.push(s);
|
|
1054
1196
|
else if (!skip(s)) seeds.push(s);
|
|
1055
1197
|
}
|
|
1056
1198
|
const attempt = async (route, renderer) => {
|
|
@@ -1104,7 +1246,7 @@ async function crawlRoutes(opts, render) {
|
|
|
1104
1246
|
const tooLong2 = [];
|
|
1105
1247
|
const candidate = (r) => {
|
|
1106
1248
|
if (r === null || isExcluded(r, opts.exclude)) return false;
|
|
1107
|
-
if (isRouteTooLong(r)) {
|
|
1249
|
+
if (isRouteTooLong(r, opts.fileLayout)) {
|
|
1108
1250
|
tooLong2.push(r);
|
|
1109
1251
|
return false;
|
|
1110
1252
|
}
|
|
@@ -1286,7 +1428,7 @@ async function createChromeRenderer(channel, opts = {}, load = () => import("pla
|
|
|
1286
1428
|
}
|
|
1287
1429
|
const allowed = createOriginPolicy(opts.allowOrigins);
|
|
1288
1430
|
const idleMs = opts.idleMs ?? IDLE_MS;
|
|
1289
|
-
const check = readyCheck(idleMs);
|
|
1431
|
+
const check = readyCheck(idleMs, opts.readySelector);
|
|
1290
1432
|
let gone = false;
|
|
1291
1433
|
browser.on?.("disconnected", () => {
|
|
1292
1434
|
gone = true;
|
|
@@ -1303,8 +1445,9 @@ async function createChromeRenderer(channel, opts = {}, load = () => import("pla
|
|
|
1303
1445
|
return e;
|
|
1304
1446
|
};
|
|
1305
1447
|
const renderPage = async (url, timeoutMs, inPage) => {
|
|
1306
|
-
|
|
1307
|
-
|
|
1448
|
+
let deadline = createDeadline(timeoutMs);
|
|
1449
|
+
let timeoutText = readyTimeoutMessage(timeoutMs);
|
|
1450
|
+
let budgetMs = timeoutMs;
|
|
1308
1451
|
const origin = new URL(url).origin;
|
|
1309
1452
|
const blocked = [];
|
|
1310
1453
|
const opening = browser.newPage({ serviceWorkers: "block" }).then(async (p) => {
|
|
@@ -1345,22 +1488,35 @@ async function createChromeRenderer(channel, opts = {}, load = () => import("pla
|
|
|
1345
1488
|
page.on("pageerror", (e) => pageErrors.push(e.message));
|
|
1346
1489
|
let html;
|
|
1347
1490
|
let finalPath;
|
|
1491
|
+
let timedOut = false;
|
|
1348
1492
|
try {
|
|
1349
1493
|
await deadline.race(
|
|
1350
1494
|
page.goto(url, { waitUntil: "load", timeout: deadline.remaining() + 1e3 }),
|
|
1351
1495
|
timeoutText
|
|
1352
1496
|
);
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1497
|
+
try {
|
|
1498
|
+
await deadline.race(
|
|
1499
|
+
waitForReady(
|
|
1500
|
+
async () => {
|
|
1501
|
+
const r = await page.evaluate(check);
|
|
1502
|
+
return { ready: r.ready, errors: withoutBlockedLoads([...pageErrors, ...r.errors], blocked) };
|
|
1503
|
+
},
|
|
1504
|
+
timeoutMs,
|
|
1505
|
+
Math.min(POLL_MS, idleMs)
|
|
1506
|
+
),
|
|
1507
|
+
timeoutText
|
|
1508
|
+
);
|
|
1509
|
+
} catch (e) {
|
|
1510
|
+
if (!(opts.onTimeout === "snapshot" && e instanceof TimeoutError)) throw e;
|
|
1511
|
+
timedOut = true;
|
|
1512
|
+
deadline = createDeadline(SNAPSHOT_GRACE_MS);
|
|
1513
|
+
budgetMs = SNAPSHOT_GRACE_MS;
|
|
1514
|
+
timeoutText = readyTimeoutMessage(SNAPSHOT_GRACE_MS);
|
|
1515
|
+
await assertNoPageErrors(async () => {
|
|
1516
|
+
const r = await deadline.race(page.evaluate(check), timeoutText);
|
|
1517
|
+
return withoutBlockedLoads([...pageErrors, ...r.errors], blocked);
|
|
1518
|
+
});
|
|
1519
|
+
}
|
|
1364
1520
|
html = await deadline.race(page.evaluate(SERIALIZE_EXPR), timeoutText);
|
|
1365
1521
|
finalPath = new URL(page.url()).pathname;
|
|
1366
1522
|
} catch (e) {
|
|
@@ -1371,9 +1527,9 @@ async function createChromeRenderer(channel, opts = {}, load = () => import("pla
|
|
|
1371
1527
|
inPage,
|
|
1372
1528
|
(expr) => page.evaluate(expr),
|
|
1373
1529
|
deadline,
|
|
1374
|
-
|
|
1530
|
+
budgetMs
|
|
1375
1531
|
);
|
|
1376
|
-
return { html, finalPath, inPage: results };
|
|
1532
|
+
return { html, finalPath, inPage: results, ...timedOut ? { warnings: [snapshotWarning(timeoutMs)] } : {} };
|
|
1377
1533
|
} finally {
|
|
1378
1534
|
await settleWithin(page.close(), opts.pageCloseMs ?? PAGE_CLOSE_MS);
|
|
1379
1535
|
}
|
|
@@ -1397,6 +1553,10 @@ async function createChromeRenderer(channel, opts = {}, load = () => import("pla
|
|
|
1397
1553
|
// src/vite/prerender/renderers.ts
|
|
1398
1554
|
function createRendererPool(opts) {
|
|
1399
1555
|
const made = /* @__PURE__ */ new Map();
|
|
1556
|
+
const readiness = {
|
|
1557
|
+
...opts.readySelector !== void 0 ? { readySelector: opts.readySelector } : {},
|
|
1558
|
+
...opts.onTimeout !== void 0 ? { onTimeout: opts.onTimeout } : {}
|
|
1559
|
+
};
|
|
1400
1560
|
return {
|
|
1401
1561
|
get(name) {
|
|
1402
1562
|
let r = made.get(name);
|
|
@@ -1406,6 +1566,7 @@ function createRendererPool(opts) {
|
|
|
1406
1566
|
{
|
|
1407
1567
|
allowOrigins: opts.allowOrigins ?? [],
|
|
1408
1568
|
...opts.idleMs !== void 0 ? { idleMs: opts.idleMs } : {},
|
|
1569
|
+
...readiness,
|
|
1409
1570
|
...opts.syncResources ? { syncResources: opts.syncResources } : {}
|
|
1410
1571
|
},
|
|
1411
1572
|
{ codeGeneration: opts.codeGeneration === true }
|
|
@@ -1413,7 +1574,8 @@ function createRendererPool(opts) {
|
|
|
1413
1574
|
) : createChromeRenderer(name, {
|
|
1414
1575
|
...opts.executablePath !== void 0 ? { executablePath: opts.executablePath } : {},
|
|
1415
1576
|
allowOrigins: opts.allowOrigins ?? [],
|
|
1416
|
-
...opts.idleMs !== void 0 ? { idleMs: opts.idleMs } : {}
|
|
1577
|
+
...opts.idleMs !== void 0 ? { idleMs: opts.idleMs } : {},
|
|
1578
|
+
...readiness
|
|
1417
1579
|
});
|
|
1418
1580
|
made.set(name, r);
|
|
1419
1581
|
}
|
|
@@ -1433,7 +1595,25 @@ import { createServer } from "http";
|
|
|
1433
1595
|
import { realpathSync as realpathSync2 } from "fs";
|
|
1434
1596
|
import { readFile, realpath, stat } from "fs/promises";
|
|
1435
1597
|
import { extname, resolve, sep } from "path";
|
|
1436
|
-
|
|
1598
|
+
var viteParseAst;
|
|
1599
|
+
var VITE_MISSING = "prerendering needs the vite package, which is not installed: npm i -D vite. To add agent files to HTML you prerendered yourself, use web-for-agents generate, which does not need vite.";
|
|
1600
|
+
function isPackageNotFound(e, pkg) {
|
|
1601
|
+
const code = e?.code;
|
|
1602
|
+
if (code !== "ERR_MODULE_NOT_FOUND" && code !== "MODULE_NOT_FOUND") return false;
|
|
1603
|
+
return new RegExp(`(Cannot find (package|module) ['"]${pkg}['"])`).test(errorMessage(e));
|
|
1604
|
+
}
|
|
1605
|
+
async function loadViteParser(importVite = () => import("vite")) {
|
|
1606
|
+
if (viteParseAst) return viteParseAst;
|
|
1607
|
+
let mod;
|
|
1608
|
+
try {
|
|
1609
|
+
mod = await importVite();
|
|
1610
|
+
} catch (e) {
|
|
1611
|
+
if (isPackageNotFound(e, "vite")) throw new Error(withPrefix(VITE_MISSING), { cause: e });
|
|
1612
|
+
throw e;
|
|
1613
|
+
}
|
|
1614
|
+
viteParseAst = mod.parseAst;
|
|
1615
|
+
return viteParseAst;
|
|
1616
|
+
}
|
|
1437
1617
|
var TYPES = {
|
|
1438
1618
|
".html": "text/html; charset=utf-8",
|
|
1439
1619
|
".js": "text/javascript; charset=utf-8",
|
|
@@ -1458,6 +1638,8 @@ function fixImportMeta(code) {
|
|
|
1458
1638
|
}
|
|
1459
1639
|
function parenthesizeRegExps(code) {
|
|
1460
1640
|
if (!code.includes("/")) return code;
|
|
1641
|
+
const parseAst = viteParseAst;
|
|
1642
|
+
if (!parseAst) throw new Error(withPrefix("internal: loadViteParser() must run before parenthesizeRegExps"));
|
|
1461
1643
|
let ast;
|
|
1462
1644
|
try {
|
|
1463
1645
|
ast = parseAst(code, { sourceType: "module" });
|
|
@@ -1576,7 +1758,8 @@ function startStaticServer(opts) {
|
|
|
1576
1758
|
send(500, "text/plain; charset=utf-8", "Internal error");
|
|
1577
1759
|
}
|
|
1578
1760
|
});
|
|
1579
|
-
|
|
1761
|
+
const ready = compat ? loadViteParser() : Promise.resolve();
|
|
1762
|
+
return ready.then(() => new Promise((resolveP, reject) => {
|
|
1580
1763
|
server.once("error", reject);
|
|
1581
1764
|
server.listen(0, "127.0.0.1", () => {
|
|
1582
1765
|
const { port } = server.address();
|
|
@@ -1590,7 +1773,7 @@ function startStaticServer(opts) {
|
|
|
1590
1773
|
})
|
|
1591
1774
|
});
|
|
1592
1775
|
});
|
|
1593
|
-
});
|
|
1776
|
+
}));
|
|
1594
1777
|
}
|
|
1595
1778
|
|
|
1596
1779
|
// src/vite/prerender/index.ts
|
|
@@ -1626,6 +1809,8 @@ async function prerenderSite(input) {
|
|
|
1626
1809
|
...pr.executablePath !== void 0 ? { executablePath: pr.executablePath } : {},
|
|
1627
1810
|
allowOrigins: pr.allowOrigins,
|
|
1628
1811
|
...pr.idleMs !== void 0 ? { idleMs: pr.idleMs } : {},
|
|
1812
|
+
...pr.readySelector !== void 0 ? { readySelector: pr.readySelector } : {},
|
|
1813
|
+
onTimeout: pr.onTimeout,
|
|
1629
1814
|
codeGeneration: pr.isolation.codeGeneration,
|
|
1630
1815
|
syncResources
|
|
1631
1816
|
});
|
|
@@ -1647,7 +1832,8 @@ async function prerenderSite(input) {
|
|
|
1647
1832
|
contentSelector: markdown ? markdown.contentSelector : DEFAULT_CONTENT_SELECTOR,
|
|
1648
1833
|
...markdown ? { markdownUrl: (route) => publicMdUrl(options.siteUrl, route) } : {},
|
|
1649
1834
|
inPage,
|
|
1650
|
-
skipRoute: input.skipRoute
|
|
1835
|
+
skipRoute: input.skipRoute,
|
|
1836
|
+
fileLayout: pr.fileLayout
|
|
1651
1837
|
},
|
|
1652
1838
|
async (url, renderer, timeoutMs, scripts) => (await pool.get(renderer)).render(url, timeoutMs, scripts)
|
|
1653
1839
|
).catch((e) => {
|
|
@@ -1667,10 +1853,10 @@ async function prerenderSite(input) {
|
|
|
1667
1853
|
}
|
|
1668
1854
|
}
|
|
1669
1855
|
function classicScriptSrcs(html) {
|
|
1670
|
-
const { document, dispose } = parseHtml(html);
|
|
1856
|
+
const { document: document2, dispose } = parseHtml(html);
|
|
1671
1857
|
try {
|
|
1672
1858
|
const out = [];
|
|
1673
|
-
for (const el of Array.from(
|
|
1859
|
+
for (const el of Array.from(document2.querySelectorAll("script[src]"))) {
|
|
1674
1860
|
if (el.hasAttribute("async") || el.hasAttribute("defer")) continue;
|
|
1675
1861
|
const type = (el.getAttribute("type") ?? "").trim().toLowerCase();
|
|
1676
1862
|
if (type !== "" && !/^(text|application)\/(x-)?(java|ecma)script$/.test(type)) continue;
|
|
@@ -1768,16 +1954,47 @@ function buildRobots(opts) {
|
|
|
1768
1954
|
return blocks.join("\n\n") + "\n";
|
|
1769
1955
|
}
|
|
1770
1956
|
|
|
1771
|
-
// src/vite/
|
|
1772
|
-
|
|
1773
|
-
|
|
1957
|
+
// src/vite/llms.ts
|
|
1958
|
+
var BLOCK_START = /^(\d*)([#>\-+*=_`~.)])/;
|
|
1959
|
+
function paragraphs(text) {
|
|
1960
|
+
if (text === void 0) return [];
|
|
1961
|
+
return text.split(/\n\s*\n/).map((p) => escapeMarkdownInline(p)).filter(Boolean).map((p) => p.replace(BLOCK_START, "$1\\$2"));
|
|
1774
1962
|
}
|
|
1775
|
-
function
|
|
1776
|
-
const
|
|
1777
|
-
return
|
|
1963
|
+
function linkLine(title, url, description) {
|
|
1964
|
+
const desc = escapeMarkdownInline(description);
|
|
1965
|
+
return `- [${escapeMarkdownInline(title)}](${escapeLinkTarget(url)})${desc ? `: ${desc}` : ""}`;
|
|
1966
|
+
}
|
|
1967
|
+
function header(site) {
|
|
1968
|
+
const blocks = [`# ${escapeMarkdownInline(site.title)}`];
|
|
1969
|
+
const desc = escapeMarkdownInline(site.description);
|
|
1970
|
+
if (desc) blocks.push(`> ${desc}`);
|
|
1971
|
+
blocks.push(...paragraphs(site.intro));
|
|
1972
|
+
for (const sec of site.sections ?? []) {
|
|
1973
|
+
const body = [...paragraphs(sec.text)];
|
|
1974
|
+
const links = (sec.links ?? []).map((l) => linkLine(l.title, l.url, l.description));
|
|
1975
|
+
if (links.length) body.push(links.join("\n"));
|
|
1976
|
+
blocks.push([`## ${escapeMarkdownInline(sec.title)}`, ...body].join("\n\n"));
|
|
1977
|
+
}
|
|
1978
|
+
return blocks;
|
|
1778
1979
|
}
|
|
1980
|
+
function buildLlmsTxt(site, pages, sections = []) {
|
|
1981
|
+
const blocks = header(site);
|
|
1982
|
+
const lines = [...pages].sort(byRoute).map((p) => linkLine(p.title, p.mdUrl ?? p.url, p.description));
|
|
1983
|
+
blocks.push(["## Pages", ...lines.length ? ["", ...lines] : []].join("\n"));
|
|
1984
|
+
for (const s of sections) {
|
|
1985
|
+
blocks.push([`## ${s.heading}`, ...s.lines.length ? ["", ...s.lines] : []].join("\n"));
|
|
1986
|
+
}
|
|
1987
|
+
return blocks.join("\n\n") + "\n";
|
|
1988
|
+
}
|
|
1989
|
+
function buildLlmsFullTxt(site, pages) {
|
|
1990
|
+
const head = header(site).join("\n\n");
|
|
1991
|
+
const blocks = [...pages].sort(byRoute).filter((p) => p.markdown !== void 0).map((p) => `Source: ${p.url}
|
|
1779
1992
|
|
|
1780
|
-
|
|
1993
|
+
${p.markdown.trim()}`);
|
|
1994
|
+
return [head, blocks.join("\n\n---\n\n")].filter(Boolean).join("\n\n") + "\n";
|
|
1995
|
+
}
|
|
1996
|
+
|
|
1997
|
+
// src/vite/siteFiles.ts
|
|
1781
1998
|
var SPA_FALLBACK_FILE = "200.html";
|
|
1782
1999
|
var fileOf = (urlPath) => urlPath.slice(1);
|
|
1783
2000
|
function prefixed(e, context) {
|
|
@@ -1792,6 +2009,164 @@ async function callHook(ext, hook, fn) {
|
|
|
1792
2009
|
throw prefixed(e, `extension "${ext.name}" ${hook} failed`);
|
|
1793
2010
|
}
|
|
1794
2011
|
}
|
|
2012
|
+
function dropFileCollisions(pages, filesOf, taken, warn) {
|
|
2013
|
+
const kept = [];
|
|
2014
|
+
for (const page of pages) {
|
|
2015
|
+
const files = filesOf(page);
|
|
2016
|
+
const clash = files.find((f) => taken.has(f));
|
|
2017
|
+
if (clash !== void 0) {
|
|
2018
|
+
warn(
|
|
2019
|
+
`${LOG_PREFIX} skipped ${shortRoute(page.route)}: its file ${clash} is already the file of ${taken.get(clash)}`
|
|
2020
|
+
);
|
|
2021
|
+
continue;
|
|
2022
|
+
}
|
|
2023
|
+
for (const f of files) taken.set(f, shortRoute(page.route));
|
|
2024
|
+
kept.push(page);
|
|
2025
|
+
}
|
|
2026
|
+
return kept;
|
|
2027
|
+
}
|
|
2028
|
+
async function pageMarkdown(markdown, page) {
|
|
2029
|
+
const md = buildPageMarkdown(page.info.title, page.info.contentHtml, page.url);
|
|
2030
|
+
if (!markdown.transform) return md;
|
|
2031
|
+
let out;
|
|
2032
|
+
try {
|
|
2033
|
+
out = await markdown.transform({
|
|
2034
|
+
route: page.route,
|
|
2035
|
+
url: page.url,
|
|
2036
|
+
title: page.info.title,
|
|
2037
|
+
...page.info.description !== void 0 ? { description: page.info.description } : {},
|
|
2038
|
+
markdown: md,
|
|
2039
|
+
html: page.html
|
|
2040
|
+
});
|
|
2041
|
+
} catch (e) {
|
|
2042
|
+
throw prefixed(e, `markdown.transform failed for ${shortRoute(page.route)}`);
|
|
2043
|
+
}
|
|
2044
|
+
if (out === void 0) return md;
|
|
2045
|
+
if (typeof out !== "string") {
|
|
2046
|
+
throw new Error(withPrefix(`markdown.transform must return a string or undefined (got ${typeof out} for ${shortRoute(page.route)})`));
|
|
2047
|
+
}
|
|
2048
|
+
return out;
|
|
2049
|
+
}
|
|
2050
|
+
function pageLengthWarnings(listed) {
|
|
2051
|
+
return metaLengthWarnings(
|
|
2052
|
+
listed.map((p) => {
|
|
2053
|
+
const out = { route: p.route };
|
|
2054
|
+
if (p.info.titleFromDocument) out.title = p.info.title;
|
|
2055
|
+
if (p.info.description !== void 0) out.description = p.info.description;
|
|
2056
|
+
return out;
|
|
2057
|
+
})
|
|
2058
|
+
);
|
|
2059
|
+
}
|
|
2060
|
+
async function stageSiteFiles(opts, stager, { pages: allPages, listed, mdByRoute }) {
|
|
2061
|
+
const { siteUrl, markdown, llms, extensions, logger } = opts;
|
|
2062
|
+
for (const ext of extensions) {
|
|
2063
|
+
if (!ext.onRoute) continue;
|
|
2064
|
+
for (const page of listed) {
|
|
2065
|
+
await callHook(ext, `onRoute(${page.route})`, () => ext.onRoute(page.route, page.inPage[ext.name]));
|
|
2066
|
+
}
|
|
2067
|
+
}
|
|
2068
|
+
const rootPage = allPages.find((p) => p.route === "/");
|
|
2069
|
+
const rootTitle = rootPage?.info.titleFromDocument ? rootPage.info.title : void 0;
|
|
2070
|
+
const site = {
|
|
2071
|
+
url: siteUrl,
|
|
2072
|
+
title: (llms ? llms.title : void 0) ?? rootTitle ?? new URL(siteUrl).hostname
|
|
2073
|
+
};
|
|
2074
|
+
const description = (llms ? llms.description : void 0) ?? rootPage?.info.description;
|
|
2075
|
+
if (description !== void 0) site.description = description;
|
|
2076
|
+
const pages = listed.map((p) => {
|
|
2077
|
+
const out = { route: p.route, title: p.info.title, url: publicUrl(siteUrl, p.route) };
|
|
2078
|
+
if (p.info.description !== void 0) out.description = p.info.description;
|
|
2079
|
+
if (markdown) out.mdUrl = publicMdUrl(siteUrl, p.route);
|
|
2080
|
+
return out;
|
|
2081
|
+
});
|
|
2082
|
+
if (llms) {
|
|
2083
|
+
const sections = [];
|
|
2084
|
+
for (const ext of extensions) {
|
|
2085
|
+
if (ext.llmsSections) sections.push(...await callHook(ext, "llmsSections", () => ext.llmsSections()));
|
|
2086
|
+
}
|
|
2087
|
+
const llmsPages = pages.map((p) => {
|
|
2088
|
+
const md = mdByRoute.get(p.route);
|
|
2089
|
+
return md !== void 0 ? { ...p, markdown: md } : { ...p };
|
|
2090
|
+
});
|
|
2091
|
+
const llmsSite = {
|
|
2092
|
+
...site,
|
|
2093
|
+
...llms.intro !== void 0 ? { intro: llms.intro } : {},
|
|
2094
|
+
...llms.sections !== void 0 ? { sections: llms.sections } : {}
|
|
2095
|
+
};
|
|
2096
|
+
stager.stage(fileOf(LLMS_TXT_PATH), buildLlmsTxt(llmsSite, llmsPages, sections));
|
|
2097
|
+
if (markdown) stager.stage(fileOf(LLMS_FULL_TXT_PATH), buildLlmsFullTxt(llmsSite, llmsPages));
|
|
2098
|
+
}
|
|
2099
|
+
for (const ext of extensions) {
|
|
2100
|
+
if (!ext.finalize) continue;
|
|
2101
|
+
const ctx = {
|
|
2102
|
+
site,
|
|
2103
|
+
pages,
|
|
2104
|
+
emitFile: (fileName, source) => {
|
|
2105
|
+
const { file, status } = stager.stage(fileName, source);
|
|
2106
|
+
if (status === "replaced") logger.warn(`${LOG_PREFIX} extension "${ext.name}" overwrote ${file}`);
|
|
2107
|
+
},
|
|
2108
|
+
warn: (msg) => logger.warn(withPrefix(msg))
|
|
2109
|
+
};
|
|
2110
|
+
if (llms) ctx.llmsUrl = publicUrl(siteUrl, LLMS_TXT_PATH);
|
|
2111
|
+
await callHook(ext, "finalize", () => ext.finalize(ctx));
|
|
2112
|
+
}
|
|
2113
|
+
}
|
|
2114
|
+
|
|
2115
|
+
// src/vite/sitemap.ts
|
|
2116
|
+
function escapeXml(s) {
|
|
2117
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
2118
|
+
}
|
|
2119
|
+
function buildSitemap(siteUrl, routes, lastmod) {
|
|
2120
|
+
const urls = routes.map((r) => {
|
|
2121
|
+
const date = lastmod?.get(r);
|
|
2122
|
+
const mod = date !== void 0 ? `<lastmod>${escapeXml(date)}</lastmod>` : "";
|
|
2123
|
+
return ` <url><loc>${escapeXml(new URL(siteUrl + r).href)}</loc>${mod}</url>`;
|
|
2124
|
+
}).join("\n");
|
|
2125
|
+
return '<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n' + urls + "\n</urlset>\n";
|
|
2126
|
+
}
|
|
2127
|
+
function isoDate(d) {
|
|
2128
|
+
return d.toISOString().slice(0, 10);
|
|
2129
|
+
}
|
|
2130
|
+
var DATE = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
2131
|
+
var DATETIME = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(:\d{2}(\.\d+)?)?(Z|[+-]\d{2}:\d{2})$/;
|
|
2132
|
+
function validDate(s) {
|
|
2133
|
+
const m = DATE.exec(s.slice(0, 10));
|
|
2134
|
+
if (!m) return false;
|
|
2135
|
+
const d = new Date(Date.UTC(+m[1], +m[2] - 1, +m[3]));
|
|
2136
|
+
return isoDate(d) === s.slice(0, 10) && (s.length === 10 || !Number.isNaN(Date.parse(s)));
|
|
2137
|
+
}
|
|
2138
|
+
function lastmodValue(v, route) {
|
|
2139
|
+
if (v === void 0) return void 0;
|
|
2140
|
+
if (v instanceof Date && !Number.isNaN(v.getTime())) return isoDate(v);
|
|
2141
|
+
if (typeof v === "string" && (DATE.test(v) || DATETIME.test(v)) && validDate(v)) return v;
|
|
2142
|
+
const got = v instanceof Date ? "an invalid Date" : JSON.stringify(v) ?? typeof v;
|
|
2143
|
+
throw new Error(
|
|
2144
|
+
withPrefix(
|
|
2145
|
+
`sitemap.lastmod must return "YYYY-MM-DD", a W3C datetime such as "2026-01-31T09:00:00Z", a Date or undefined (got ${got} for ${shortRoute(route)})`
|
|
2146
|
+
)
|
|
2147
|
+
);
|
|
2148
|
+
}
|
|
2149
|
+
async function sitemapLastmods(lastmod, routes, fileDate) {
|
|
2150
|
+
const out = /* @__PURE__ */ new Map();
|
|
2151
|
+
if (lastmod === "none") return out;
|
|
2152
|
+
for (const route of routes) {
|
|
2153
|
+
let v;
|
|
2154
|
+
if (lastmod === "file") {
|
|
2155
|
+
v = fileDate(route);
|
|
2156
|
+
} else {
|
|
2157
|
+
try {
|
|
2158
|
+
v = await lastmod(route);
|
|
2159
|
+
} catch (e) {
|
|
2160
|
+
throw prefixed(e, `sitemap.lastmod failed for ${shortRoute(route)}`);
|
|
2161
|
+
}
|
|
2162
|
+
}
|
|
2163
|
+
const value = lastmodValue(v, route);
|
|
2164
|
+
if (value !== void 0) out.set(route, value);
|
|
2165
|
+
}
|
|
2166
|
+
return out;
|
|
2167
|
+
}
|
|
2168
|
+
|
|
2169
|
+
// src/vite/buildPlugin.ts
|
|
1795
2170
|
function isClientEnv(env) {
|
|
1796
2171
|
if (!env) return true;
|
|
1797
2172
|
if (env.config?.consumer) return env.config.consumer === "client";
|
|
@@ -1814,6 +2189,7 @@ function createBuildPlugin(resolved, extensions) {
|
|
|
1814
2189
|
const shell = fs2.readFileSync(shellFile, "utf8");
|
|
1815
2190
|
stager.stage(SPA_FALLBACK_FILE, shell);
|
|
1816
2191
|
const pr = resolved.prerender;
|
|
2192
|
+
const layout = pr === false ? "directory" : pr.fileLayout;
|
|
1817
2193
|
if (pr !== false && mayUseHappyDom(pr) && !hasPermissionModel() && !warnedPermission) {
|
|
1818
2194
|
warnedPermission = true;
|
|
1819
2195
|
logger.warn(NO_PERMISSION_MODEL_WARNING);
|
|
@@ -1825,71 +2201,35 @@ function createBuildPlugin(resolved, extensions) {
|
|
|
1825
2201
|
base,
|
|
1826
2202
|
shell,
|
|
1827
2203
|
options: resolved,
|
|
1828
|
-
skipRoute: (route) => stager.inPublicDir(routeHtmlFile(route)),
|
|
2204
|
+
skipRoute: (route) => stager.inPublicDir(routeHtmlFile(route, layout)),
|
|
1829
2205
|
extensions
|
|
1830
2206
|
});
|
|
1831
2207
|
} catch (e) {
|
|
1832
2208
|
throw prefixed(e, "prerender failed");
|
|
1833
2209
|
}
|
|
2210
|
+
const filesOf = (route) => [routeHtmlFile(route, layout), ...markdown ? [routeMdFile(route)] : []];
|
|
2211
|
+
const pages = dropFileCollisions(
|
|
2212
|
+
result.pages,
|
|
2213
|
+
(p) => filesOf(p.route),
|
|
2214
|
+
/* @__PURE__ */ new Map([[SPA_FALLBACK_FILE, `the SPA fallback (${SPA_FALLBACK_FILE})`]]),
|
|
2215
|
+
(m) => logger.warn(m)
|
|
2216
|
+
);
|
|
2217
|
+
result = { ...result, pages };
|
|
1834
2218
|
const mdByRoute = /* @__PURE__ */ new Map();
|
|
1835
|
-
|
|
1836
|
-
stager.stage(
|
|
1837
|
-
|
|
1838
|
-
const md = buildPageMarkdown(page.info.title, page.info.contentHtml, publicUrl(siteUrl, page.route));
|
|
1839
|
-
mdByRoute.set(page.route, md);
|
|
1840
|
-
stager.stage(routeMdFile(page.route), md);
|
|
2219
|
+
const stageNew = (file, source) => {
|
|
2220
|
+
if (stager.stage(file, source).status === "replaced") {
|
|
2221
|
+
throw new Error(`${LOG_PREFIX} internal error: ${file} was generated twice; nothing was written`);
|
|
1841
2222
|
}
|
|
1842
|
-
}
|
|
1843
|
-
return { result, listed: result.pages.filter((p) => p.listed), mdByRoute };
|
|
1844
|
-
};
|
|
1845
|
-
const runExtensions = async (stager, { result, listed, mdByRoute }) => {
|
|
1846
|
-
const { siteUrl, markdown, llms } = resolved;
|
|
1847
|
-
for (const ext of extensions) {
|
|
1848
|
-
if (!ext.onRoute) continue;
|
|
1849
|
-
for (const page of listed) {
|
|
1850
|
-
await callHook(ext, `onRoute(${page.route})`, () => ext.onRoute(page.route, page.inPage[ext.name]));
|
|
1851
|
-
}
|
|
1852
|
-
}
|
|
1853
|
-
const rootPage = result.pages.find((p) => p.route === "/");
|
|
1854
|
-
const rootTitle = rootPage?.info.titleFromDocument ? rootPage.info.title : void 0;
|
|
1855
|
-
const site = {
|
|
1856
|
-
url: siteUrl,
|
|
1857
|
-
title: (llms ? llms.title : void 0) ?? rootTitle ?? new URL(siteUrl).hostname
|
|
1858
2223
|
};
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
return out;
|
|
1866
|
-
});
|
|
1867
|
-
if (llms) {
|
|
1868
|
-
const sections = [];
|
|
1869
|
-
for (const ext of extensions) {
|
|
1870
|
-
if (ext.llmsSections) sections.push(...await callHook(ext, "llmsSections", () => ext.llmsSections()));
|
|
2224
|
+
for (const page of pages) {
|
|
2225
|
+
stageNew(routeHtmlFile(page.route, layout), page.html);
|
|
2226
|
+
if (markdown) {
|
|
2227
|
+
const md = await pageMarkdown(markdown, { ...page, url: publicUrl(siteUrl, page.route) });
|
|
2228
|
+
mdByRoute.set(page.route, md);
|
|
2229
|
+
stageNew(routeMdFile(page.route), md);
|
|
1871
2230
|
}
|
|
1872
|
-
const llmsPages = pages.map((p) => {
|
|
1873
|
-
const md = mdByRoute.get(p.route);
|
|
1874
|
-
return md !== void 0 ? { ...p, markdown: md } : { ...p };
|
|
1875
|
-
});
|
|
1876
|
-
stager.stage(fileOf(LLMS_TXT_PATH), buildLlmsTxt(site, llmsPages, sections));
|
|
1877
|
-
if (markdown) stager.stage(fileOf(LLMS_FULL_TXT_PATH), buildLlmsFullTxt(site, llmsPages));
|
|
1878
|
-
}
|
|
1879
|
-
for (const ext of extensions) {
|
|
1880
|
-
if (!ext.finalize) continue;
|
|
1881
|
-
const ctx = {
|
|
1882
|
-
site,
|
|
1883
|
-
pages,
|
|
1884
|
-
emitFile: (fileName, source) => {
|
|
1885
|
-
const { file, status } = stager.stage(fileName, source);
|
|
1886
|
-
if (status === "replaced") logger.warn(`${LOG_PREFIX} extension "${ext.name}" overwrote ${file}`);
|
|
1887
|
-
},
|
|
1888
|
-
warn: (msg) => logger.warn(withPrefix(msg))
|
|
1889
|
-
};
|
|
1890
|
-
if (llms) ctx.llmsUrl = publicUrl(siteUrl, LLMS_TXT_PATH);
|
|
1891
|
-
await callHook(ext, "finalize", () => ext.finalize(ctx));
|
|
1892
2231
|
}
|
|
2232
|
+
return { result, listed: pages.filter((p) => p.listed), mdByRoute };
|
|
1893
2233
|
};
|
|
1894
2234
|
const runPipeline = async () => {
|
|
1895
2235
|
const { siteUrl, markdown } = resolved;
|
|
@@ -1899,12 +2239,25 @@ function createBuildPlugin(resolved, extensions) {
|
|
|
1899
2239
|
const sitemapRoutes = rendered ? [
|
|
1900
2240
|
.../* @__PURE__ */ new Set([
|
|
1901
2241
|
...rendered.listed.map((p) => p.route),
|
|
1902
|
-
...resolved.routes.filter(
|
|
2242
|
+
...resolved.routes.filter(
|
|
2243
|
+
(r) => stager.inPublicDir(routeHtmlFile(r, pr === false ? "directory" : pr.fileLayout))
|
|
2244
|
+
)
|
|
1903
2245
|
])
|
|
1904
2246
|
].sort() : resolved.routes;
|
|
1905
|
-
if (resolved.sitemap)
|
|
2247
|
+
if (resolved.sitemap) {
|
|
2248
|
+
const buildDate = /* @__PURE__ */ new Date();
|
|
2249
|
+
const lastmod = await sitemapLastmods(resolved.sitemapLastmod, sitemapRoutes, () => buildDate);
|
|
2250
|
+
stager.stage(fileOf(SITEMAP_PATH), buildSitemap(siteUrl, sitemapRoutes, lastmod));
|
|
2251
|
+
}
|
|
1906
2252
|
stager.stage(fileOf(ROBOTS_PATH), buildRobots(resolved));
|
|
1907
|
-
if (rendered)
|
|
2253
|
+
if (rendered) {
|
|
2254
|
+
const { siteUrl: url, markdown: md, llms } = resolved;
|
|
2255
|
+
await stageSiteFiles({ siteUrl: url, markdown: md, llms, extensions, logger }, stager, {
|
|
2256
|
+
pages: rendered.result.pages,
|
|
2257
|
+
listed: rendered.listed,
|
|
2258
|
+
mdByRoute: rendered.mdByRoute
|
|
2259
|
+
});
|
|
2260
|
+
}
|
|
1908
2261
|
stager.flush();
|
|
1909
2262
|
if (pr === false || !rendered) return;
|
|
1910
2263
|
const { result, listed } = rendered;
|
|
@@ -1934,6 +2287,7 @@ function createBuildPlugin(resolved, extensions) {
|
|
|
1934
2287
|
`${LOG_PREFIX} no [${CONTENT_ATTR}] or "${markdown.contentSelector}" element on ${result.bodyFallbackRoutes.join(", ")}; content was taken from <body> minus header, nav, footer, aside`
|
|
1935
2288
|
);
|
|
1936
2289
|
}
|
|
2290
|
+
for (const w of pageLengthWarnings(listed)) logger.warn(w);
|
|
1937
2291
|
logger.info(
|
|
1938
2292
|
`${LOG_PREFIX} prerendered ${result.pages.length} routes (${listed.length} listed in llms.txt and the sitemap; the sitemap also keeps configured routes served from publicDir)`
|
|
1939
2293
|
);
|
|
@@ -1979,17 +2333,337 @@ function createBuildPlugin(resolved, extensions) {
|
|
|
1979
2333
|
};
|
|
1980
2334
|
}
|
|
1981
2335
|
|
|
2336
|
+
// src/vite/generate.ts
|
|
2337
|
+
import fs3 from "fs";
|
|
2338
|
+
import path4 from "path";
|
|
2339
|
+
|
|
2340
|
+
// src/vite/generateActions.ts
|
|
2341
|
+
function staticActions(document2) {
|
|
2342
|
+
const out = /* @__PURE__ */ new Map();
|
|
2343
|
+
for (const a of markupActions(document2)) {
|
|
2344
|
+
if (a.kind === "link" || !isValidActionName(a.name) || out.has(a.name)) continue;
|
|
2345
|
+
out.set(a.name, {
|
|
2346
|
+
name: a.name,
|
|
2347
|
+
description: a.description?.trim() || a.name,
|
|
2348
|
+
inputSchema: a.kind === "form" ? schemaFromForm(a.element) : { ...EMPTY_OBJECT_SCHEMA, properties: {} },
|
|
2349
|
+
destructive: a.destructive,
|
|
2350
|
+
readOnly: false,
|
|
2351
|
+
kind: a.kind
|
|
2352
|
+
});
|
|
2353
|
+
}
|
|
2354
|
+
return [...out.values()].sort((a, b) => compareStrings(a.name, b.name));
|
|
2355
|
+
}
|
|
2356
|
+
|
|
2357
|
+
// src/vite/generateHtml.ts
|
|
2358
|
+
function detectCharset(bytes) {
|
|
2359
|
+
if (bytes[0] === 239 && bytes[1] === 187 && bytes[2] === 191) return "utf-8";
|
|
2360
|
+
if (bytes[0] === 254 && bytes[1] === 255) return "utf-16be";
|
|
2361
|
+
if (bytes[0] === 255 && bytes[1] === 254) return "utf-16le";
|
|
2362
|
+
const head = Buffer.from(bytes.subarray(0, 1024)).toString("latin1");
|
|
2363
|
+
const m = /<meta\b[^>]*?charset\s*=\s*["']?\s*([A-Za-z0-9_:.-]+)/i.exec(head);
|
|
2364
|
+
if (m) {
|
|
2365
|
+
try {
|
|
2366
|
+
const enc = new TextDecoder(m[1]).encoding;
|
|
2367
|
+
return enc.startsWith("utf-16") ? "utf-8" : enc;
|
|
2368
|
+
} catch {
|
|
2369
|
+
}
|
|
2370
|
+
}
|
|
2371
|
+
return "utf-8";
|
|
2372
|
+
}
|
|
2373
|
+
function decodeHtml(bytes) {
|
|
2374
|
+
const charset = detectCharset(bytes);
|
|
2375
|
+
return { charset, text: new TextDecoder(charset).decode(bytes) };
|
|
2376
|
+
}
|
|
2377
|
+
var HEAD_RAW_TEXT = /* @__PURE__ */ new Set(["script", "style", "template", "textarea", "title", "noscript"]);
|
|
2378
|
+
var escapeAttr = (href) => href.replace(/&/g, "&").replace(/"/g, """).replace(/[^\x20-\x7e]/gu, (c) => `&#x${c.codePointAt(0).toString(16)};`);
|
|
2379
|
+
function isMarkdownAlternate(attrs) {
|
|
2380
|
+
const get = (n) => attrs.find((a) => a.name === n)?.value ?? "";
|
|
2381
|
+
const rel = get("rel").toLowerCase().split(/\s+/);
|
|
2382
|
+
return rel.includes("alternate") && get("type").split(";")[0].trim().toLowerCase() === MARKDOWN_MIME;
|
|
2383
|
+
}
|
|
2384
|
+
var ourLink = (attr) => `<link rel="alternate" type="${MARKDOWN_MIME}" href="${attr}" ${HEAD_OWNED_ATTR}="${MARKDOWN_LINK_KEY}">`;
|
|
2385
|
+
function setMarkdownLink(bytes, charset, href) {
|
|
2386
|
+
if (charset.startsWith("utf-16")) return null;
|
|
2387
|
+
const buf = Buffer.from(bytes);
|
|
2388
|
+
const view = buf.toString("latin1");
|
|
2389
|
+
const attr = escapeAttr(href);
|
|
2390
|
+
let headOpenEnd = -1;
|
|
2391
|
+
let headClose = -1;
|
|
2392
|
+
let bodyOpen = -1;
|
|
2393
|
+
let preamble = 0;
|
|
2394
|
+
let marked;
|
|
2395
|
+
for (const t of scanHtml(view, HEAD_RAW_TEXT)) {
|
|
2396
|
+
if (t.type === "comment") {
|
|
2397
|
+
if (headOpenEnd === -1 && /^<!doctype/i.test(view.slice(t.start, t.start + 9))) preamble = t.end;
|
|
2398
|
+
continue;
|
|
2399
|
+
}
|
|
2400
|
+
if (t.type !== "tag") continue;
|
|
2401
|
+
if (t.closing) {
|
|
2402
|
+
if (t.name === "head") {
|
|
2403
|
+
headClose = t.start;
|
|
2404
|
+
break;
|
|
2405
|
+
}
|
|
2406
|
+
continue;
|
|
2407
|
+
}
|
|
2408
|
+
if (t.name === "html" && headOpenEnd === -1) preamble = Math.max(preamble, t.end);
|
|
2409
|
+
if (t.name === "head" && headOpenEnd === -1) headOpenEnd = t.end;
|
|
2410
|
+
else if (t.name === "body") {
|
|
2411
|
+
bodyOpen = t.start;
|
|
2412
|
+
break;
|
|
2413
|
+
} else if (t.name === "link" && isMarkdownAlternate(t.attrs)) {
|
|
2414
|
+
const owner = t.attrs.find((a) => a.name === HEAD_OWNED_ATTR)?.value;
|
|
2415
|
+
if (owner !== MARKDOWN_LINK_KEY) return { bytes: buf, action: "kept" };
|
|
2416
|
+
marked ??= t;
|
|
2417
|
+
}
|
|
2418
|
+
}
|
|
2419
|
+
const splice = (start, end, text, action) => ({
|
|
2420
|
+
bytes: Buffer.concat([buf.subarray(0, start), Buffer.from(text, "latin1"), buf.subarray(end)]),
|
|
2421
|
+
action
|
|
2422
|
+
});
|
|
2423
|
+
if (marked) {
|
|
2424
|
+
const h = marked.attrs.find((a) => a.name === "href");
|
|
2425
|
+
if (h && h.valueStart !== -1) {
|
|
2426
|
+
if (h.value === attr) return { bytes: buf, action: "unchanged" };
|
|
2427
|
+
return splice(h.valueStart, h.valueEnd, h.quote ? attr : `"${attr}"`, "updated");
|
|
2428
|
+
}
|
|
2429
|
+
return splice(marked.start, marked.end, ourLink(attr), "updated");
|
|
2430
|
+
}
|
|
2431
|
+
const at = headClose !== -1 ? headClose : headOpenEnd !== -1 ? headOpenEnd : bodyOpen !== -1 ? bodyOpen : preamble;
|
|
2432
|
+
return splice(at, at, ourLink(attr), "inserted");
|
|
2433
|
+
}
|
|
2434
|
+
|
|
2435
|
+
// src/vite/generate.ts
|
|
2436
|
+
var SKIP_DIRS = /* @__PURE__ */ new Set(["assets", "node_modules"]);
|
|
2437
|
+
var SKIP_FILES = /* @__PURE__ */ new Set([SPA_FALLBACK_FILE, "404.html"]);
|
|
2438
|
+
function htmlFiles(outDir, warn) {
|
|
2439
|
+
const out = [];
|
|
2440
|
+
const walk = (dir, rel) => {
|
|
2441
|
+
for (const e of fs3.readdirSync(dir, { withFileTypes: true })) {
|
|
2442
|
+
if (e.name.startsWith(".")) continue;
|
|
2443
|
+
const r = rel ? `${rel}/${e.name}` : e.name;
|
|
2444
|
+
if (e.isSymbolicLink()) {
|
|
2445
|
+
if (e.name.endsWith(".html") || fs3.statSync(path4.join(dir, e.name), { throwIfNoEntry: false })?.isDirectory()) {
|
|
2446
|
+
warn(`${LOG_PREFIX} ${r} is a symbolic link; skipped`);
|
|
2447
|
+
}
|
|
2448
|
+
} else if (e.isDirectory()) {
|
|
2449
|
+
if (!(rel === "" && SKIP_DIRS.has(e.name))) walk(path4.join(dir, e.name), r);
|
|
2450
|
+
} else if (e.isFile() && e.name.endsWith(".html") && !SKIP_FILES.has(e.name)) {
|
|
2451
|
+
out.push(r);
|
|
2452
|
+
}
|
|
2453
|
+
}
|
|
2454
|
+
};
|
|
2455
|
+
walk(outDir, "");
|
|
2456
|
+
return out.sort(compareStrings);
|
|
2457
|
+
}
|
|
2458
|
+
var GENERATE_OPTION_KEYS = [
|
|
2459
|
+
"outDir",
|
|
2460
|
+
"siteUrl",
|
|
2461
|
+
"robots",
|
|
2462
|
+
"exclude",
|
|
2463
|
+
"sitemap",
|
|
2464
|
+
"markdown",
|
|
2465
|
+
"llms",
|
|
2466
|
+
"agentMap",
|
|
2467
|
+
"linkMarkdown",
|
|
2468
|
+
"overwrite",
|
|
2469
|
+
"logger"
|
|
2470
|
+
];
|
|
2471
|
+
async function generateAgentFiles(options) {
|
|
2472
|
+
if (!options || typeof options.outDir !== "string" || options.outDir === "") {
|
|
2473
|
+
throw new Error(withPrefix("outDir is required"));
|
|
2474
|
+
}
|
|
2475
|
+
for (const key of ["linkMarkdown", "overwrite"]) {
|
|
2476
|
+
if (options[key] !== void 0 && typeof options[key] !== "boolean") throw new Error(withPrefix(`${key} must be a boolean`));
|
|
2477
|
+
}
|
|
2478
|
+
const resolved = resolveOptions({
|
|
2479
|
+
siteUrl: options.siteUrl,
|
|
2480
|
+
robots: options.robots,
|
|
2481
|
+
...options.exclude !== void 0 ? { exclude: options.exclude } : {},
|
|
2482
|
+
...options.sitemap !== void 0 ? { sitemap: options.sitemap } : {},
|
|
2483
|
+
...options.markdown !== void 0 ? { markdown: options.markdown } : {},
|
|
2484
|
+
...options.llms !== void 0 ? { llms: options.llms } : {},
|
|
2485
|
+
...options.agentMap !== void 0 ? { agentMap: options.agentMap } : {},
|
|
2486
|
+
overlay: false
|
|
2487
|
+
});
|
|
2488
|
+
const { siteUrl, markdown } = resolved;
|
|
2489
|
+
const outDir = path4.resolve(options.outDir);
|
|
2490
|
+
if (!fs3.existsSync(outDir) || !fs3.statSync(outDir).isDirectory()) {
|
|
2491
|
+
throw new Error(`${LOG_PREFIX} ${outDir} is not a directory`);
|
|
2492
|
+
}
|
|
2493
|
+
const linkMarkdown = options.linkMarkdown ?? true;
|
|
2494
|
+
const base = options.logger ?? console;
|
|
2495
|
+
const warnings = [];
|
|
2496
|
+
const logger = {
|
|
2497
|
+
warn(msg) {
|
|
2498
|
+
warnings.push(msg);
|
|
2499
|
+
base.warn(msg);
|
|
2500
|
+
}
|
|
2501
|
+
};
|
|
2502
|
+
for (const w of resolved.warnings) logger.warn(w);
|
|
2503
|
+
const unknown = Object.keys(options).filter((k) => !GENERATE_OPTION_KEYS.includes(k));
|
|
2504
|
+
if (unknown.length > 0) {
|
|
2505
|
+
logger.warn(`${LOG_PREFIX} unknown option${unknown.length === 1 ? "" : "s"} ignored: ${unknown.join(", ")}`);
|
|
2506
|
+
}
|
|
2507
|
+
const fileByRoute = /* @__PURE__ */ new Map();
|
|
2508
|
+
for (const file of htmlFiles(outDir, (m) => logger.warn(m))) {
|
|
2509
|
+
const route = routeOfHtmlFile(file);
|
|
2510
|
+
if (!isSafeRoute(route)) {
|
|
2511
|
+
logger.warn(`${LOG_PREFIX} ${file} cannot be a page URL (its name has a backslash or similar); skipped`);
|
|
2512
|
+
continue;
|
|
2513
|
+
}
|
|
2514
|
+
if (route !== "/" && isExcluded(route, resolved.exclude)) continue;
|
|
2515
|
+
const other = fileByRoute.get(route);
|
|
2516
|
+
if (other !== void 0) {
|
|
2517
|
+
logger.warn(`${LOG_PREFIX} ${file} and ${other} are both ${shortRoute(route)}; using ${other}`);
|
|
2518
|
+
continue;
|
|
2519
|
+
}
|
|
2520
|
+
fileByRoute.set(route, file);
|
|
2521
|
+
}
|
|
2522
|
+
if (fileByRoute.size === 0) throw new Error(`${LOG_PREFIX} no .html pages found in ${outDir}`);
|
|
2523
|
+
const files = [...fileByRoute.values()];
|
|
2524
|
+
const flat = files.some((f) => f !== "index.html" && !f.endsWith("/index.html"));
|
|
2525
|
+
const dir = files.some((f) => f.endsWith("/index.html"));
|
|
2526
|
+
const fileLayout = flat && dir ? "mixed" : flat ? "flat" : "directory";
|
|
2527
|
+
const stager = createFileStager({ outDir, publicDir: "", warn: (m) => logger.warn(m) });
|
|
2528
|
+
const written = /* @__PURE__ */ new Set();
|
|
2529
|
+
const kept = [];
|
|
2530
|
+
const protectedFiles = /* @__PURE__ */ new Set([fileOf(ROBOTS_PATH), fileOf(SITEMAP_PATH), fileOf(LLMS_TXT_PATH), fileOf(LLMS_FULL_TXT_PATH)]);
|
|
2531
|
+
if (resolved.agentMap) protectedFiles.add(resolved.agentMap.fileName);
|
|
2532
|
+
const differs = (target, source) => fs3.existsSync(target) && !fs3.readFileSync(target).equals(typeof source === "string" ? Buffer.from(source) : source);
|
|
2533
|
+
const guarded = {
|
|
2534
|
+
...stager,
|
|
2535
|
+
stage(fileName, source) {
|
|
2536
|
+
const file = fileName.replace(/^\/+/, "");
|
|
2537
|
+
const target = path4.join(outDir, file);
|
|
2538
|
+
if (!options.overwrite && protectedFiles.has(file) && differs(target, source)) {
|
|
2539
|
+
if (!kept.includes(file)) {
|
|
2540
|
+
kept.push(file);
|
|
2541
|
+
logger.warn(`${LOG_PREFIX} ${file} already exists with different content; kept it (use overwrite to replace it)`);
|
|
2542
|
+
}
|
|
2543
|
+
return { file, status: "skipped" };
|
|
2544
|
+
}
|
|
2545
|
+
const r = stager.stage(fileName, source);
|
|
2546
|
+
if (r.status !== "skipped") written.add(r.file);
|
|
2547
|
+
return r;
|
|
2548
|
+
}
|
|
2549
|
+
};
|
|
2550
|
+
const pages = [];
|
|
2551
|
+
const result = [];
|
|
2552
|
+
const mdByRoute = /* @__PURE__ */ new Map();
|
|
2553
|
+
const mtimeByRoute = /* @__PURE__ */ new Map();
|
|
2554
|
+
const bodyFallback = [];
|
|
2555
|
+
const utf16 = [];
|
|
2556
|
+
const ownLinks = [];
|
|
2557
|
+
const routes = dropFileCollisions(
|
|
2558
|
+
[...fileByRoute].map(([route, file]) => ({ route, file })).sort(byRoute),
|
|
2559
|
+
(p) => markdown ? [routeMdFile(p.route)] : [],
|
|
2560
|
+
/* @__PURE__ */ new Map(),
|
|
2561
|
+
(m) => logger.warn(m)
|
|
2562
|
+
);
|
|
2563
|
+
for (const { route, file } of routes) {
|
|
2564
|
+
mtimeByRoute.set(route, fs3.statSync(path4.join(outDir, file)).mtime);
|
|
2565
|
+
const bytes = fs3.readFileSync(path4.join(outDir, file));
|
|
2566
|
+
const { charset, text: html } = decodeHtml(bytes);
|
|
2567
|
+
const url = publicUrl(siteUrl, route);
|
|
2568
|
+
const { document: document2, dispose } = parseHtml(html);
|
|
2569
|
+
let page;
|
|
2570
|
+
try {
|
|
2571
|
+
const actions = resolved.agentMap ? staticActions(document2) : [];
|
|
2572
|
+
const links = resolved.agentMap ? markupLinks(document2) : [];
|
|
2573
|
+
const info = analyzeDocument(document2, {
|
|
2574
|
+
pageUrl: url,
|
|
2575
|
+
contentSelector: markdown ? markdown.contentSelector : "main",
|
|
2576
|
+
route
|
|
2577
|
+
});
|
|
2578
|
+
const inPage = { "agent-map": { actions, links } };
|
|
2579
|
+
page = { route, info, listed: !info.noindex, inPage };
|
|
2580
|
+
} catch (e) {
|
|
2581
|
+
throw prefixed(e, `reading ${file} failed`);
|
|
2582
|
+
} finally {
|
|
2583
|
+
dispose();
|
|
2584
|
+
}
|
|
2585
|
+
pages.push(page);
|
|
2586
|
+
result.push({ route, file, listed: page.listed });
|
|
2587
|
+
if (!markdown) continue;
|
|
2588
|
+
if (page.info.contentSource === "body") bodyFallback.push(route);
|
|
2589
|
+
const md = await pageMarkdown(markdown, { route, url, info: page.info, html });
|
|
2590
|
+
mdByRoute.set(route, md);
|
|
2591
|
+
const mdFile = routeMdFile(route);
|
|
2592
|
+
if (differs(path4.join(outDir, mdFile), md)) {
|
|
2593
|
+
logger.warn(`${LOG_PREFIX} ${mdFile} already exists with different content; replacing it with the markdown of ${shortRoute(route)}`);
|
|
2594
|
+
}
|
|
2595
|
+
guarded.stage(mdFile, md);
|
|
2596
|
+
if (linkMarkdown) {
|
|
2597
|
+
const edit = setMarkdownLink(bytes, charset, publicMdUrl(siteUrl, route));
|
|
2598
|
+
if (edit === null) utf16.push(file);
|
|
2599
|
+
else if (edit.action === "kept") ownLinks.push(shortRoute(route));
|
|
2600
|
+
else if (edit.action !== "unchanged") guarded.stage(file, edit.bytes);
|
|
2601
|
+
}
|
|
2602
|
+
}
|
|
2603
|
+
const listed = pages.filter((p) => p.listed);
|
|
2604
|
+
if (resolved.sitemap) {
|
|
2605
|
+
const routes2 = listed.map((p) => p.route);
|
|
2606
|
+
const lastmod = await sitemapLastmods(resolved.sitemapLastmod, routes2, (r) => mtimeByRoute.get(r));
|
|
2607
|
+
guarded.stage(fileOf(SITEMAP_PATH), buildSitemap(siteUrl, routes2, lastmod));
|
|
2608
|
+
}
|
|
2609
|
+
guarded.stage(fileOf(ROBOTS_PATH), buildRobots(resolved));
|
|
2610
|
+
const extensions = resolved.agentMap ? [agentMapExtension({ siteUrl, fileName: resolved.agentMap.fileName })] : [];
|
|
2611
|
+
await stageSiteFiles({ siteUrl, markdown, llms: resolved.llms, extensions, logger }, guarded, {
|
|
2612
|
+
pages,
|
|
2613
|
+
listed,
|
|
2614
|
+
mdByRoute
|
|
2615
|
+
});
|
|
2616
|
+
let flushed = false;
|
|
2617
|
+
try {
|
|
2618
|
+
stager.flush();
|
|
2619
|
+
flushed = true;
|
|
2620
|
+
} finally {
|
|
2621
|
+
if (!flushed || resolved.sitemapLastmod === "file") {
|
|
2622
|
+
for (const [route, mtime] of mtimeByRoute) {
|
|
2623
|
+
const file = fileByRoute.get(route);
|
|
2624
|
+
if (!written.has(file)) continue;
|
|
2625
|
+
try {
|
|
2626
|
+
fs3.utimesSync(path4.join(outDir, file), mtime, mtime);
|
|
2627
|
+
} catch (e) {
|
|
2628
|
+
if (flushed) throw e;
|
|
2629
|
+
}
|
|
2630
|
+
}
|
|
2631
|
+
}
|
|
2632
|
+
}
|
|
2633
|
+
if (markdown && bodyFallback.length > 0) {
|
|
2634
|
+
logger.warn(
|
|
2635
|
+
`${LOG_PREFIX} no [${CONTENT_ATTR}] or "${markdown.contentSelector}" element on ${bodyFallback.join(", ")}; content was taken from <body> minus header, nav, footer, aside`
|
|
2636
|
+
);
|
|
2637
|
+
}
|
|
2638
|
+
if (ownLinks.length > 0) {
|
|
2639
|
+
base.info(`${LOG_PREFIX} kept the page's own markdown link on ${ownLinks.join(", ")}`);
|
|
2640
|
+
}
|
|
2641
|
+
if (utf16.length > 0) {
|
|
2642
|
+
logger.warn(`${LOG_PREFIX} ${utf16.join(", ")} ${utf16.length === 1 ? "is" : "are"} UTF-16; the markdown link was not added`);
|
|
2643
|
+
}
|
|
2644
|
+
for (const w of pageLengthWarnings(listed)) logger.warn(w);
|
|
2645
|
+
base.info(`${LOG_PREFIX} generated agent files for ${pages.length} pages (${listed.length} listed) in ${outDir}`);
|
|
2646
|
+
return {
|
|
2647
|
+
outDir,
|
|
2648
|
+
fileLayout,
|
|
2649
|
+
pages: result.sort(byRoute),
|
|
2650
|
+
written: [...written].sort(compareStrings),
|
|
2651
|
+
kept: kept.sort(compareStrings),
|
|
2652
|
+
warnings
|
|
2653
|
+
};
|
|
2654
|
+
}
|
|
2655
|
+
|
|
1982
2656
|
// src/vite/overlay.ts
|
|
1983
2657
|
import { existsSync as existsSync2 } from "fs";
|
|
1984
2658
|
import { createRequire as createRequire2 } from "module";
|
|
1985
|
-
import
|
|
2659
|
+
import path5 from "path";
|
|
1986
2660
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1987
2661
|
var OVERLAY_VIRTUAL_ID = "virtual:web-for-agents/overlay";
|
|
1988
2662
|
var RESOLVED_ID = "\0" + OVERLAY_VIRTUAL_ID;
|
|
1989
2663
|
var PACKAGE_NAME = "@anubhav-choubey/web-for-agents";
|
|
1990
2664
|
var OVERLAY_DEPS = ["turndown", "turndown-plugin-gfm"];
|
|
1991
2665
|
function overlayDepsFor(root) {
|
|
1992
|
-
const req = createRequire2(
|
|
2666
|
+
const req = createRequire2(path5.join(root, "noop.js"));
|
|
1993
2667
|
return OVERLAY_DEPS.map((dep) => {
|
|
1994
2668
|
try {
|
|
1995
2669
|
req.resolve(dep);
|
|
@@ -2014,7 +2688,7 @@ function overlayPlugin(o, siteUrl) {
|
|
|
2014
2688
|
name: "web-for-agents:overlay",
|
|
2015
2689
|
apply: (_config, env) => env.command === "serve" && !process.env.VITEST,
|
|
2016
2690
|
config(config) {
|
|
2017
|
-
return { optimizeDeps: { include: overlayDepsFor(
|
|
2691
|
+
return { optimizeDeps: { include: overlayDepsFor(path5.resolve(config.root ?? process.cwd())) } };
|
|
2018
2692
|
},
|
|
2019
2693
|
configResolved(config) {
|
|
2020
2694
|
base = config.base;
|
|
@@ -2045,5 +2719,6 @@ function webForAgents(options) {
|
|
|
2045
2719
|
}
|
|
2046
2720
|
export {
|
|
2047
2721
|
AI_BOTS,
|
|
2722
|
+
generateAgentFiles,
|
|
2048
2723
|
webForAgents
|
|
2049
2724
|
};
|