@lownoise-studio/rendershield 0.1.6 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +32 -0
- package/README.md +6 -0
- package/dist/cli.js +35 -15
- package/dist/cli.js.map +1 -1
- package/dist/commands/build.js +96 -0
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/init.js +7 -7
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/verify.js +132 -38
- package/dist/commands/verify.js.map +1 -1
- package/dist/core/generateWorker.js +85 -68
- package/dist/core/generateWorker.js.map +1 -1
- package/dist/core/loadConfig.js +74 -6
- package/dist/core/loadConfig.js.map +1 -1
- package/dist/core/loadMarkdown.js.map +1 -1
- package/dist/core/renderHtml.js +5 -1
- package/dist/core/renderHtml.js.map +1 -1
- package/dist/core/validateOutput.js +154 -29
- package/dist/core/validateOutput.js.map +1 -1
- package/package.json +7 -3
- package/src/cli.ts +75 -54
- package/src/commands/build.ts +185 -72
- package/src/commands/init.ts +7 -7
- package/src/commands/verify.ts +236 -114
- package/src/core/generateWorker.ts +97 -80
- package/src/core/loadConfig.ts +173 -74
- package/src/core/loadMarkdown.ts +2 -2
- package/src/core/renderHtml.ts +5 -1
- package/src/core/validateOutput.ts +217 -37
|
@@ -1,77 +1,94 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
const require = createRequire(import.meta.url);
|
|
3
|
+
let VERSION = "0.0.0";
|
|
4
|
+
try {
|
|
5
|
+
const pkg = require("../../package.json");
|
|
6
|
+
VERSION = pkg.version ?? "0.0.0";
|
|
7
|
+
}
|
|
8
|
+
catch {
|
|
9
|
+
VERSION = "unknown";
|
|
10
|
+
}
|
|
1
11
|
function jsStringArray(arr) {
|
|
2
12
|
return `[${arr.map((s) => JSON.stringify(s)).join(", ")}]`;
|
|
3
13
|
}
|
|
4
14
|
export function generateWorkerJs(cfg) {
|
|
5
15
|
const patterns = cfg.worker.botUserAgentPatterns.map((p) => p.toLowerCase());
|
|
6
16
|
const rewriteBases = cfg.worker.rewriteRouteBases;
|
|
7
|
-
return `/**
|
|
8
|
-
* RenderShield Worker (generated)
|
|
9
|
-
* Serves prerendered /index.html to bots on selected route bases.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
const BOT_SUBSTRINGS = ${jsStringArray(patterns)};
|
|
13
|
-
const REWRITE_BASES = ${jsStringArray(rewriteBases)};
|
|
14
|
-
|
|
15
|
-
function isBot(ua) {
|
|
16
|
-
const s = (ua || "").toLowerCase();
|
|
17
|
-
return BOT_SUBSTRINGS.some((sub) => s.includes(sub));
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function shouldRewrite(pathname) {
|
|
21
|
-
return REWRITE_BASES.some((base) => pathname.startsWith(base));
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function toIndexHtml(pathname) {
|
|
25
|
-
let p = pathname;
|
|
26
|
-
if (!p.endsWith("/")) p += "/";
|
|
27
|
-
return p + "index.html";
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export default {
|
|
31
|
-
async fetch(request, env, ctx) {
|
|
32
|
-
const url = new URL(request.url);
|
|
33
|
-
const ua = request.headers.get("User-Agent") || "";
|
|
34
|
-
const bot = isBot(ua);
|
|
35
|
-
|
|
36
|
-
const isGetLike = request.method === "GET" || request.method === "HEAD";
|
|
37
|
-
const rewrite = bot && isGetLike && shouldRewrite(url.pathname);
|
|
38
|
-
|
|
39
|
-
try {
|
|
40
|
-
if (!rewrite)
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}
|
|
17
|
+
return `/**
|
|
18
|
+
* RenderShield Worker (generated) v${VERSION}
|
|
19
|
+
* Serves prerendered /index.html to bots on selected route bases.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
const BOT_SUBSTRINGS = ${jsStringArray(patterns)};
|
|
23
|
+
const REWRITE_BASES = ${jsStringArray(rewriteBases)};
|
|
24
|
+
|
|
25
|
+
function isBot(ua) {
|
|
26
|
+
const s = (ua || "").toLowerCase();
|
|
27
|
+
return BOT_SUBSTRINGS.some((sub) => s.includes(sub));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function shouldRewrite(pathname) {
|
|
31
|
+
return REWRITE_BASES.some((base) => pathname.startsWith(base));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function toIndexHtml(pathname) {
|
|
35
|
+
let p = pathname;
|
|
36
|
+
if (!p.endsWith("/")) p += "/";
|
|
37
|
+
return p + "index.html";
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export default {
|
|
41
|
+
async fetch(request, env, ctx) {
|
|
42
|
+
const url = new URL(request.url);
|
|
43
|
+
const ua = request.headers.get("User-Agent") || "";
|
|
44
|
+
const bot = isBot(ua);
|
|
45
|
+
|
|
46
|
+
const isGetLike = request.method === "GET" || request.method === "HEAD";
|
|
47
|
+
const rewrite = bot && isGetLike && shouldRewrite(url.pathname);
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
if (!rewrite) {
|
|
51
|
+
const passResp = await fetch(request);
|
|
52
|
+
const out = new Response(passResp.body, passResp);
|
|
53
|
+
out.headers.set("x-rendershield", "pass-through");
|
|
54
|
+
return out;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const origin = ${JSON.stringify(cfg.worker.lovableOrigin)};
|
|
58
|
+
const finalPath = toIndexHtml(url.pathname);
|
|
59
|
+
const originUrl = origin + finalPath + url.search;
|
|
60
|
+
|
|
61
|
+
const headers = new Headers();
|
|
62
|
+
headers.set("Accept", "text/html");
|
|
63
|
+
headers.set("User-Agent", ua);
|
|
64
|
+
|
|
65
|
+
const resp = await fetch(originUrl, { method: "GET", headers });
|
|
66
|
+
|
|
67
|
+
if (!resp.ok) {
|
|
68
|
+
const fallbackUrl = origin + url.pathname + url.search;
|
|
69
|
+
const fb = await fetch(fallbackUrl, { method: "GET", headers });
|
|
70
|
+
const out = new Response(fb.body, fb);
|
|
71
|
+
out.headers.set("x-rendershield", "bot-fallback");
|
|
72
|
+
${cfg.worker.debugHeaders ? `out.headers.set("X-Bot-Detected", "true");
|
|
73
|
+
out.headers.set("X-Prerender-Fallback", "true");
|
|
74
|
+
out.headers.set("X-Requested-Path", url.pathname);` : ""}
|
|
75
|
+
return out;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const out = new Response(resp.body, resp);
|
|
79
|
+
out.headers.set("x-rendershield", "bot-hit");
|
|
80
|
+
${cfg.worker.debugHeaders ? `out.headers.set("X-Bot-Detected", "true");
|
|
81
|
+
out.headers.set("X-Prerender", "true");
|
|
82
|
+
out.headers.set("X-Final-Path", finalPath);` : ""}
|
|
83
|
+
return out;
|
|
84
|
+
} catch (err) {
|
|
85
|
+
return new Response("Service temporarily unavailable.", {
|
|
86
|
+
status: 500,
|
|
87
|
+
headers: { "Content-Type": "text/plain; charset=utf-8" }
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
};
|
|
75
92
|
`;
|
|
76
93
|
}
|
|
77
94
|
//# sourceMappingURL=generateWorker.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generateWorker.js","sourceRoot":"","sources":["../../src/core/generateWorker.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"generateWorker.js","sourceRoot":"","sources":["../../src/core/generateWorker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAG5C,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,IAAI,OAAO,GAAG,OAAO,CAAC;AACtB,IAAI,CAAC;IACH,MAAM,GAAG,GAAG,OAAO,CAAC,oBAAoB,CAAyB,CAAC;IAClE,OAAO,GAAG,GAAG,CAAC,OAAO,IAAI,OAAO,CAAC;AACnC,CAAC;AAAC,MAAM,CAAC;IACP,OAAO,GAAG,SAAS,CAAC;AACtB,CAAC;AAED,SAAS,aAAa,CAAC,GAAa;IAClC,OAAO,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;AAC7D,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,GAAuB;IACtD,MAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;IAC7E,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,CAAC,iBAAiB,CAAC;IAElD,OAAO;sCAC6B,OAAO;;;;yBAIpB,aAAa,CAAC,QAAQ,CAAC;wBACxB,aAAa,CAAC,YAAY,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uBAkC5B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC;;;;;;;;;;;;;;;UAerD,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC;;2DAEuB,CAAC,CAAC,CAAC,EAAE;;;;;;QAMxD,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC;;kDAEgB,CAAC,CAAC,CAAC,EAAE;;;;;;;;;;CAUtD,CAAC;AACF,CAAC"}
|
package/dist/core/loadConfig.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import fs from "fs-extra";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
const CONFIG_NAME = "rendershield.config.json";
|
|
4
|
+
const DEFAULT_SITEMAP_PATH = "/sitemap.xml";
|
|
5
|
+
const DEFAULT_ROBOTS_PATH = "/robots.txt";
|
|
4
6
|
function isObject(v) {
|
|
5
7
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
6
8
|
}
|
|
@@ -13,10 +15,51 @@ function coerceBoolFlag(parsed, key, defaultEnabled) {
|
|
|
13
15
|
if (!isObject(v)) {
|
|
14
16
|
throw new Error(`${key} must be an object like { "enabled": true }`);
|
|
15
17
|
}
|
|
16
|
-
|
|
18
|
+
const enabled = v.enabled;
|
|
19
|
+
if (typeof enabled !== "boolean") {
|
|
17
20
|
throw new Error(`${key}.enabled must be a boolean`);
|
|
18
21
|
}
|
|
19
|
-
return { enabled
|
|
22
|
+
return { enabled };
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Worker config policy: strict mode.
|
|
26
|
+
* When worker.enabled is true, all of lovableOrigin, rewriteRouteBases, and
|
|
27
|
+
* botUserAgentPatterns are required and must be non-empty. No defaults are
|
|
28
|
+
* supplied — build fails with a crisp error.
|
|
29
|
+
* lovableOrigin: must be http: or https: only (no file:, javascript:, protocol-relative).
|
|
30
|
+
* botUserAgentPatterns: substring match only (not regex); empty strings rejected to avoid overmatching.
|
|
31
|
+
*/
|
|
32
|
+
function validateWorkerWhenEnabled(parsed) {
|
|
33
|
+
const worker = parsed.worker;
|
|
34
|
+
if (!worker?.lovableOrigin || typeof worker.lovableOrigin !== "string") {
|
|
35
|
+
throw new Error(`worker.lovableOrigin is required when worker.enabled is true. Example: "https://your-site.lovable.app"`);
|
|
36
|
+
}
|
|
37
|
+
let url;
|
|
38
|
+
try {
|
|
39
|
+
url = new URL(worker.lovableOrigin);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
throw new Error(`worker.lovableOrigin must be a valid URL. Got: "${worker.lovableOrigin}"`);
|
|
43
|
+
}
|
|
44
|
+
const scheme = url.protocol.toLowerCase();
|
|
45
|
+
if (scheme !== "http:" && scheme !== "https:") {
|
|
46
|
+
throw new Error(`worker.lovableOrigin must use http or https. Got: "${url.protocol}"`);
|
|
47
|
+
}
|
|
48
|
+
if (!Array.isArray(worker.rewriteRouteBases) ||
|
|
49
|
+
worker.rewriteRouteBases.length === 0) {
|
|
50
|
+
throw new Error(`worker.rewriteRouteBases must be a non-empty array when worker.enabled is true. Example: ["/blog/"]`);
|
|
51
|
+
}
|
|
52
|
+
if (!Array.isArray(worker.botUserAgentPatterns) ||
|
|
53
|
+
worker.botUserAgentPatterns.length === 0) {
|
|
54
|
+
throw new Error(`worker.botUserAgentPatterns must be a non-empty array when worker.enabled is true. Example: ["googlebot", "bingbot"]`);
|
|
55
|
+
}
|
|
56
|
+
// Substring match only; empty string would match every User-Agent
|
|
57
|
+
for (let i = 0; i < worker.botUserAgentPatterns.length; i++) {
|
|
58
|
+
const p = worker.botUserAgentPatterns[i];
|
|
59
|
+
if (typeof p !== "string" || p.trim() === "") {
|
|
60
|
+
throw new Error(`worker.botUserAgentPatterns[${i}] must be a non-empty string (substring match). Empty or invalid entry would overmatch.`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
20
63
|
}
|
|
21
64
|
export async function loadConfig(cwd = process.cwd()) {
|
|
22
65
|
const p = path.join(cwd, CONFIG_NAME);
|
|
@@ -51,10 +94,35 @@ export async function loadConfig(cwd = process.cwd()) {
|
|
|
51
94
|
}
|
|
52
95
|
if (!parsed?.output?.outDir)
|
|
53
96
|
throw new Error(`output.outDir is required`);
|
|
54
|
-
// Validate + default these optional sections
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
97
|
+
// Validate + default these optional sections (preserve path so it is not lost)
|
|
98
|
+
const sitemapFlag = coerceBoolFlag(parsed, "sitemap", true);
|
|
99
|
+
const sitemapObj = parsed.sitemap;
|
|
100
|
+
const sitemapPathVal = sitemapObj?.path;
|
|
101
|
+
const sitemapPath = typeof sitemapPathVal === "string" && sitemapPathVal.trim().startsWith("/")
|
|
102
|
+
? sitemapPathVal.trim()
|
|
103
|
+
: DEFAULT_SITEMAP_PATH;
|
|
104
|
+
parsed.sitemap = { enabled: sitemapFlag.enabled, path: sitemapPath };
|
|
105
|
+
const robotsFlag = coerceBoolFlag(parsed, "robots", true);
|
|
106
|
+
const robotsObj = parsed.robots;
|
|
107
|
+
const robotsPathVal = robotsObj?.path;
|
|
108
|
+
const robotsPath = typeof robotsPathVal === "string" && robotsPathVal.trim().startsWith("/")
|
|
109
|
+
? robotsPathVal.trim()
|
|
110
|
+
: DEFAULT_ROBOTS_PATH;
|
|
111
|
+
parsed.robots = { enabled: robotsFlag.enabled, path: robotsPath };
|
|
112
|
+
const workerFlag = coerceBoolFlag(parsed, "worker", true);
|
|
113
|
+
if (workerFlag.enabled) {
|
|
114
|
+
validateWorkerWhenEnabled(parsed);
|
|
115
|
+
// Keep parsed.worker as the full object from JSON (already validated)
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
parsed.worker = {
|
|
119
|
+
enabled: false,
|
|
120
|
+
lovableOrigin: "",
|
|
121
|
+
rewriteRouteBases: [],
|
|
122
|
+
botUserAgentPatterns: [],
|
|
123
|
+
debugHeaders: false,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
58
126
|
return parsed;
|
|
59
127
|
}
|
|
60
128
|
//# sourceMappingURL=loadConfig.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loadConfig.js","sourceRoot":"","sources":["../../src/core/loadConfig.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1B,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B,MAAM,WAAW,GAAG,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"loadConfig.js","sourceRoot":"","sources":["../../src/core/loadConfig.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loadMarkdown.js","sourceRoot":"","sources":["../../src/core/loadMarkdown.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,WAAW,CAAC;AAC3B,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1B,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,UAAU,MAAM,aAAa,CAAC;AAGrC,MAAM,EAAE,GAAG,IAAI,UAAU,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC;AAE7E,MAAM,eAAe,GAAG,iDAAiD,CAAC;AAE1E,SAAS,aAAa,CAAC,
|
|
1
|
+
{"version":3,"file":"loadMarkdown.js","sourceRoot":"","sources":["../../src/core/loadMarkdown.ts"],"names":[],"mappings":"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"}
|
package/dist/core/renderHtml.js
CHANGED
|
@@ -50,7 +50,11 @@ export function renderPageHtml(cfg, doc) {
|
|
|
50
50
|
<meta name="twitter:description" content="${escapeHtml(description)}">
|
|
51
51
|
<meta name="twitter:image" content="${escapeHtml(ogImageUrl)}">
|
|
52
52
|
|
|
53
|
-
<script type="application/ld+json">${
|
|
53
|
+
<script type="application/ld+json">${(() => {
|
|
54
|
+
const raw = JSON.stringify(jsonLd);
|
|
55
|
+
// Case-insensitive: </script> and </SCRIPT> etc. must not break out of the tag
|
|
56
|
+
return raw.replace(/<\/script>/gi, "<\\/script>");
|
|
57
|
+
})()}</script>
|
|
54
58
|
</head>
|
|
55
59
|
<body>
|
|
56
60
|
<main>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderHtml.js","sourceRoot":"","sources":["../../src/core/renderHtml.ts"],"names":[],"mappings":"AAEA,SAAS,UAAU,CAAC,CAAS;IAC3B,OAAO,CAAC;SACL,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC;SACxB,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC;SACvB,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC;SACvB,UAAU,CAAC,GAAG,EAAE,QAAQ,CAAC;SACzB,UAAU,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;AAC/B,CAAC;AAED,SAAS,OAAO,CAAC,IAAY,EAAE,QAAgB;IAC7C,MAAM,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACxD,MAAM,CAAC,GAAG,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,QAAQ,EAAE,CAAC;IAC/D,OAAO,CAAC,GAAG,CAAC,CAAC;AACf,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,GAAuB,EAAE,GAAgB;IACtE,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,aAAa,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC;IACpE,MAAM,UAAU,GAAG,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,MAAM,CAAC;QAClD,CAAC,CAAC,GAAG,CAAC,UAAU;QAChB,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,aAAa,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC;IAEpD,MAAM,KAAK,GAAG,GAAG,GAAG,CAAC,KAAK,MAAM,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;IACpD,MAAM,WAAW,GAAG,GAAG,CAAC,OAAO,CAAC;IAEhC,MAAM,MAAM,GAAG;QACb,UAAU,EAAE,oBAAoB;QAChC,OAAO,EAAE,SAAS;QAClB,QAAQ,EAAE,GAAG,CAAC,KAAK;QACnB,MAAM,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,UAAU,EAAE;QACxD,aAAa,EAAE,GAAG,CAAC,aAAa;QAChC,KAAK,EAAE,UAAU;QACjB,gBAAgB,EAAE,YAAY;KAC/B,CAAC;IAEF,0DAA0D;IAC1D,wFAAwF;IACxF,MAAM,IAAI,GAAG;;;;;;WAMJ,UAAU,CAAC,KAAK,CAAC;sCACU,UAAU,CAAC,WAAW,CAAC;gCAC7B,UAAU,CAAC,YAAY,CAAC;;;uCAGjB,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC;6CACf,UAAU,CAAC,WAAW,CAAC;uCAC7B,UAAU,CAAC,UAAU,CAAC;qCACxB,UAAU,CAAC,YAAY,CAAC;;;wCAGrB,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC;8CACf,UAAU,CAAC,WAAW,CAAC;wCAC7B,UAAU,CAAC,UAAU,CAAC;;uCAEvB,
|
|
1
|
+
{"version":3,"file":"renderHtml.js","sourceRoot":"","sources":["../../src/core/renderHtml.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const DEFAULT_ALLOWED_JSON_LD_TYPES = ["Article", "BlogPosting", "WebPage"];
|
|
1
2
|
function hasNonEmptyTitle(html) {
|
|
2
3
|
const m = html.match(/<title>([\s\S]*?)<\/title>/i);
|
|
3
4
|
if (!m)
|
|
@@ -6,7 +7,6 @@ function hasNonEmptyTitle(html) {
|
|
|
6
7
|
return text.length > 0;
|
|
7
8
|
}
|
|
8
9
|
function getMetaContent(html, name) {
|
|
9
|
-
// matches: <meta name="description" content="...">
|
|
10
10
|
const re = new RegExp(`<meta\\s+[^>]*name=["']${escapeRegExp(name)}["'][^>]*>`, "i");
|
|
11
11
|
const tag = html.match(re)?.[0];
|
|
12
12
|
if (!tag)
|
|
@@ -30,11 +30,101 @@ function getOgContent(html, property) {
|
|
|
30
30
|
const contentMatch = tag.match(/content=["']([^"']+)["']/i);
|
|
31
31
|
return contentMatch?.[1]?.trim() ?? null;
|
|
32
32
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
/** Returns all JSON-LD script tag contents (order preserved). Many pages emit multiple: WebPage, BreadcrumbList, Organization, etc. */
|
|
34
|
+
function getAllJsonLdScripts(html) {
|
|
35
|
+
const re = /<script\s+[^>]*type=["']application\/ld\+json["'][^>]*>([\s\S]*?)<\/script>/gi;
|
|
36
|
+
const out = [];
|
|
37
|
+
let m;
|
|
38
|
+
while ((m = re.exec(html)) !== null) {
|
|
39
|
+
const content = (m[1] ?? "").trim();
|
|
40
|
+
if (content.length > 0)
|
|
41
|
+
out.push(content);
|
|
42
|
+
}
|
|
43
|
+
return out;
|
|
44
|
+
}
|
|
45
|
+
/** Normalize @type: schema.org allows string or array of strings. Return array of lowercase types. */
|
|
46
|
+
function normalizeJsonLdTypes(typeValue) {
|
|
47
|
+
if (typeValue == null)
|
|
48
|
+
return [];
|
|
49
|
+
if (typeof typeValue === "string")
|
|
50
|
+
return [typeValue.toLowerCase().trim()].filter(Boolean);
|
|
51
|
+
if (Array.isArray(typeValue)) {
|
|
52
|
+
return typeValue
|
|
53
|
+
.filter((t) => typeof t === "string")
|
|
54
|
+
.map((t) => t.toLowerCase().trim())
|
|
55
|
+
.filter(Boolean);
|
|
56
|
+
}
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
/** Validate a single JSON-LD node (object). Returns true if it satisfies the contract. */
|
|
60
|
+
function validateJsonLdNode(node, location, allowedTypes) {
|
|
61
|
+
const types = normalizeJsonLdTypes(node["@type"]);
|
|
62
|
+
if (types.length === 0) {
|
|
63
|
+
throw new Error(`Invalid JSON-LD at ${location}: missing or invalid @type. Required (string or array of strings).`);
|
|
64
|
+
}
|
|
65
|
+
const allowedSet = new Set(allowedTypes.map((t) => t.toLowerCase()));
|
|
66
|
+
const hasAllowedType = types.some((t) => allowedSet.has(t));
|
|
67
|
+
if (!hasAllowedType) {
|
|
68
|
+
throw new Error(`Invalid JSON-LD at ${location}: @type "${String(node["@type"])}" is not in allowed list [${allowedTypes.join(", ")}]. Add it to allowedJsonLdTypes if your page uses this type.`);
|
|
69
|
+
}
|
|
70
|
+
const primaryType = types[0];
|
|
71
|
+
const missing = [];
|
|
72
|
+
if (!node["@context"])
|
|
73
|
+
missing.push("@context");
|
|
74
|
+
if (!node["@type"])
|
|
75
|
+
missing.push("@type");
|
|
76
|
+
if (!node.headline && !node.name)
|
|
77
|
+
missing.push("headline or name");
|
|
78
|
+
const articleLike = ["article", "blogposting"];
|
|
79
|
+
if (articleLike.includes(primaryType) && !node.datePublished) {
|
|
80
|
+
missing.push("datePublished");
|
|
81
|
+
}
|
|
82
|
+
if (missing.length > 0) {
|
|
83
|
+
throw new Error(`Invalid JSON-LD at ${location}: missing required fields: ${missing.join(", ")}.`);
|
|
84
|
+
}
|
|
85
|
+
if (node.datePublished && typeof node.datePublished === "string") {
|
|
86
|
+
const dateMatch = node.datePublished.match(/^\d{4}-\d{2}-\d{2}/);
|
|
87
|
+
if (!dateMatch) {
|
|
88
|
+
throw new Error(`Invalid JSON-LD at ${location}: datePublished must be YYYY-MM-DD or ISO 8601. Got: "${node.datePublished}"`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Validates JSON-LD: valid JSON, @type in allowed list, required fields.
|
|
94
|
+
* Accepts single object or array of objects (at least one item must satisfy the contract).
|
|
95
|
+
* @type may be string or array of strings (e.g. ["Article","NewsArticle"]).
|
|
96
|
+
*/
|
|
97
|
+
function validateJsonLdSchema(jsonLd, context, allowedTypes) {
|
|
98
|
+
const { routePath, sourcePath } = context;
|
|
99
|
+
const location = sourcePath ? `route ${routePath} (source: ${sourcePath})` : `route ${routePath}`;
|
|
100
|
+
let parsed;
|
|
101
|
+
try {
|
|
102
|
+
parsed = JSON.parse(jsonLd);
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
const preview = jsonLd.length > 200 ? jsonLd.slice(0, 200) + "…" : jsonLd;
|
|
106
|
+
throw new Error(`Invalid JSON-LD at ${location}: JSON parse error. Ensure the script tag contains valid JSON. Preview: ${preview}`);
|
|
107
|
+
}
|
|
108
|
+
const items = Array.isArray(parsed) ? parsed : [parsed];
|
|
109
|
+
if (items.length === 0) {
|
|
110
|
+
throw new Error(`Invalid JSON-LD at ${location}: empty array or missing object.`);
|
|
111
|
+
}
|
|
112
|
+
let lastErr = null;
|
|
113
|
+
for (let i = 0; i < items.length; i++) {
|
|
114
|
+
const item = items[i];
|
|
115
|
+
if (typeof item !== "object" || item === null || Array.isArray(item))
|
|
116
|
+
continue;
|
|
117
|
+
try {
|
|
118
|
+
validateJsonLdNode(item, location, allowedTypes);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
catch (e) {
|
|
122
|
+
lastErr = e instanceof Error ? e : new Error(String(e));
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (lastErr)
|
|
126
|
+
throw lastErr;
|
|
127
|
+
throw new Error(`Invalid JSON-LD at ${location}: no item in the array satisfies the required type contract (allowed: [${allowedTypes.join(", ")}]).`);
|
|
38
128
|
}
|
|
39
129
|
function getArticleInnerHtml(html) {
|
|
40
130
|
const m = html.match(/<article\b[^>]*>([\s\S]*?)<\/article>/i);
|
|
@@ -58,42 +148,86 @@ function wordCount(s) {
|
|
|
58
148
|
function escapeRegExp(s) {
|
|
59
149
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
60
150
|
}
|
|
151
|
+
function formatErrorContext(params) {
|
|
152
|
+
const lines = [];
|
|
153
|
+
lines.push(`- routePath: ${params.routePath}`);
|
|
154
|
+
lines.push(`- outFile: ${params.outFile}`);
|
|
155
|
+
if (params.sourcePath) {
|
|
156
|
+
lines.push(`- sourcePath: ${params.sourcePath}`);
|
|
157
|
+
}
|
|
158
|
+
return lines.join("\n");
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Runs the same contract checks as validatePrerenderHtml but returns a result instead of throwing.
|
|
162
|
+
* Used by verify --prod to report whether production HTML satisfies the bot contract.
|
|
163
|
+
*/
|
|
164
|
+
export function checkPrerenderContract(html, options = {}) {
|
|
165
|
+
const routePath = options.routePath ?? "(production)";
|
|
166
|
+
const allowedJsonLdTypes = options.allowedJsonLdTypes ?? DEFAULT_ALLOWED_JSON_LD_TYPES;
|
|
167
|
+
const missing = collectContractMissing(html, routePath, options.sourcePath, allowedJsonLdTypes);
|
|
168
|
+
return { ok: missing.length === 0, missing };
|
|
169
|
+
}
|
|
61
170
|
export function validatePrerenderHtml(params) {
|
|
62
|
-
const { html,
|
|
171
|
+
const { html, routePath, sourcePath, allowedJsonLdTypes = DEFAULT_ALLOWED_JSON_LD_TYPES, } = params;
|
|
172
|
+
const missing = collectContractMissing(html, routePath, sourcePath, allowedJsonLdTypes);
|
|
173
|
+
if (missing.length > 0) {
|
|
174
|
+
const context = formatErrorContext(params);
|
|
175
|
+
const msg = `RenderShield validation failed for prerendered page:\n` +
|
|
176
|
+
context +
|
|
177
|
+
`\nMissing/invalid requirements:\n` +
|
|
178
|
+
missing.map((m) => `- ${m}`).join("\n") +
|
|
179
|
+
`\n\nFix the source content or renderer so bots receive complete HTML. Check frontmatter and template (title, excerpt, datePublished, coverImage, slug).`;
|
|
180
|
+
throw new Error(msg);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
/** Shared contract checks; returns missing list. validatePrerenderHtml throws when missing.length > 0. */
|
|
184
|
+
function collectContractMissing(html, routePath, sourcePath, allowedJsonLdTypes) {
|
|
63
185
|
const missing = [];
|
|
64
|
-
// 1) Title
|
|
65
186
|
if (!hasNonEmptyTitle(html))
|
|
66
187
|
missing.push("Missing or empty <title>");
|
|
67
|
-
// 2) Meta description
|
|
68
188
|
const desc = getMetaContent(html, "description");
|
|
69
189
|
if (!desc)
|
|
70
190
|
missing.push('Missing <meta name="description" content="...">');
|
|
71
|
-
// 3) Canonical
|
|
72
191
|
const canonical = getLinkHref(html, "canonical");
|
|
73
192
|
if (!canonical)
|
|
74
193
|
missing.push('Missing <link rel="canonical" href="...">');
|
|
75
|
-
// 4) Open Graph tags
|
|
76
194
|
const ogTitle = getOgContent(html, "og:title");
|
|
77
195
|
const ogDesc = getOgContent(html, "og:description");
|
|
78
196
|
const ogImg = getOgContent(html, "og:image");
|
|
79
197
|
const ogUrl = getOgContent(html, "og:url");
|
|
80
198
|
if (!ogTitle)
|
|
81
199
|
missing.push("Missing Open Graph tag: og:title");
|
|
82
|
-
if (!ogDesc)
|
|
200
|
+
if (!ogDesc) {
|
|
83
201
|
missing.push("Missing Open Graph tag: og:description");
|
|
202
|
+
}
|
|
203
|
+
else if (ogDesc.length > 200) {
|
|
204
|
+
missing.push(`Open Graph description too long (${ogDesc.length} chars). Max 200.`);
|
|
205
|
+
}
|
|
84
206
|
if (!ogImg)
|
|
85
207
|
missing.push("Missing Open Graph tag: og:image");
|
|
86
208
|
if (!ogUrl)
|
|
87
209
|
missing.push("Missing Open Graph tag: og:url");
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
if (!jsonLd) {
|
|
210
|
+
const jsonLdScripts = getAllJsonLdScripts(html);
|
|
211
|
+
if (jsonLdScripts.length === 0) {
|
|
91
212
|
missing.push('Missing JSON-LD: <script type="application/ld+json">...</script>');
|
|
92
213
|
}
|
|
93
|
-
else
|
|
94
|
-
|
|
214
|
+
else {
|
|
215
|
+
let onePassed = false;
|
|
216
|
+
for (const scriptContent of jsonLdScripts) {
|
|
217
|
+
if (scriptContent.length <= 20)
|
|
218
|
+
continue;
|
|
219
|
+
try {
|
|
220
|
+
validateJsonLdSchema(scriptContent, { routePath, sourcePath }, allowedJsonLdTypes);
|
|
221
|
+
onePassed = true;
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
catch {
|
|
225
|
+
// continue to next script
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
if (!onePassed)
|
|
229
|
+
missing.push("No JSON-LD script satisfied the required type contract.");
|
|
95
230
|
}
|
|
96
|
-
// 6) Article content
|
|
97
231
|
const articleInner = getArticleInnerHtml(html);
|
|
98
232
|
if (!articleInner) {
|
|
99
233
|
missing.push("Missing <article>...</article>");
|
|
@@ -101,21 +235,12 @@ export function validatePrerenderHtml(params) {
|
|
|
101
235
|
else {
|
|
102
236
|
const text = stripTags(articleInner);
|
|
103
237
|
const words = wordCount(text);
|
|
104
|
-
// Require either enough characters or enough words
|
|
105
238
|
const okByChars = text.length >= 80;
|
|
106
239
|
const okByWords = words >= 20;
|
|
107
240
|
if (!okByChars && !okByWords) {
|
|
108
|
-
missing.push(`Article content too short (
|
|
241
|
+
missing.push(`Article content too short (${words} words, ${text.length} chars). Require >= 20 words or >= 80 chars.`);
|
|
109
242
|
}
|
|
110
243
|
}
|
|
111
|
-
|
|
112
|
-
const msg = `RenderShield validation failed for prerendered page:\n` +
|
|
113
|
-
`- routePath: ${routePath}\n` +
|
|
114
|
-
`- outFile: ${outFile}\n` +
|
|
115
|
-
`Missing/invalid requirements:\n` +
|
|
116
|
-
missing.map((m) => `- ${m}`).join("\n") +
|
|
117
|
-
`\n\nFix the source content or renderer so bots receive complete HTML.`;
|
|
118
|
-
throw new Error(msg);
|
|
119
|
-
}
|
|
244
|
+
return missing;
|
|
120
245
|
}
|
|
121
246
|
//# sourceMappingURL=validateOutput.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validateOutput.js","sourceRoot":"","sources":["../../src/core/validateOutput.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"validateOutput.js","sourceRoot":"","sources":["../../src/core/validateOutput.ts"],"names":[],"mappings":"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"}
|