@lownoise-studio/rendershield 0.3.1 → 1.1.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/CHANGELOG.md +73 -32
- package/CONTRIBUTING.md +41 -0
- package/README.md +227 -144
- package/SECURITY.md +25 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +39 -26
- package/dist/cli.js.map +1 -1
- package/dist/cliArgs.d.ts +8 -0
- package/dist/cliArgs.d.ts.map +1 -0
- package/dist/cliArgs.js +56 -0
- package/dist/cliArgs.js.map +1 -0
- package/dist/commands/build.d.ts +3 -0
- package/dist/commands/build.d.ts.map +1 -0
- package/dist/commands/build.js +12 -11
- package/dist/commands/build.js.map +1 -1
- package/dist/commands/init.d.ts +3 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +8 -7
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/verify.d.ts +33 -0
- package/dist/commands/verify.d.ts.map +1 -0
- package/dist/commands/verify.js +202 -117
- package/dist/commands/verify.js.map +1 -1
- package/dist/configPath.d.ts +7 -0
- package/dist/configPath.d.ts.map +1 -0
- package/dist/configPath.js +8 -0
- package/dist/configPath.js.map +1 -0
- package/dist/core/generateRobots.d.ts +3 -0
- package/dist/core/generateRobots.d.ts.map +1 -0
- package/dist/core/generateSitemap.d.ts +3 -0
- package/dist/core/generateSitemap.d.ts.map +1 -0
- package/dist/core/generateWorker.d.ts +3 -0
- package/dist/core/generateWorker.d.ts.map +1 -0
- package/dist/core/generateWorker.js +75 -75
- package/dist/core/generateWorker.js.map +1 -1
- package/dist/core/listOutputRoutes.d.ts +4 -0
- package/dist/core/listOutputRoutes.d.ts.map +1 -0
- package/dist/core/listOutputRoutes.js +40 -0
- package/dist/core/listOutputRoutes.js.map +1 -0
- package/dist/core/loadConfig.d.ts +5 -0
- package/dist/core/loadConfig.d.ts.map +1 -0
- package/dist/core/loadConfig.js +108 -58
- package/dist/core/loadConfig.js.map +1 -1
- package/dist/core/loadMarkdown.d.ts +3 -0
- package/dist/core/loadMarkdown.d.ts.map +1 -0
- package/dist/core/loadMarkdown.js +4 -3
- package/dist/core/loadMarkdown.js.map +1 -1
- package/dist/core/renderHtml.d.ts +3 -0
- package/dist/core/renderHtml.d.ts.map +1 -0
- package/dist/core/renderHtml.js +25 -10
- package/dist/core/renderHtml.js.map +1 -1
- package/dist/core/validateOutput.d.ts +28 -0
- package/dist/core/validateOutput.d.ts.map +1 -0
- package/dist/core/validateOutput.js +7 -1
- package/dist/core/validateOutput.js.map +1 -1
- package/dist/errors.d.ts +14 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +24 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +53 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -1
- package/dist/types.js.map +1 -1
- package/docs/CONFIG.md +70 -0
- package/docs/deploy-cloudflare.md +40 -14
- package/package.json +25 -2
- package/rendershield.config.schema.json +100 -0
- package/src/cli.ts +96 -75
- package/src/cliArgs.ts +71 -0
- package/src/commands/build.ts +200 -185
- package/src/commands/init.ts +8 -8
- package/src/commands/verify.ts +451 -236
- package/src/configPath.ts +17 -0
- package/src/core/generateWorker.ts +97 -97
- package/src/core/listOutputRoutes.ts +51 -0
- package/src/core/loadConfig.ts +282 -173
- package/src/core/loadMarkdown.ts +9 -3
- package/src/core/renderHtml.ts +36 -12
- package/src/core/validateOutput.ts +335 -328
- package/src/errors.ts +48 -0
- package/src/index.ts +43 -0
- package/src/types.ts +5 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,32 +1,73 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
All notable changes to this project will be documented in this file.
|
|
4
|
-
|
|
5
|
-
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
-
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
-
|
|
8
|
-
## [Unreleased]
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
-
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [1.1.0] - 2026-08-23
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- `verify --check` and `verify --all --check`: validate built HTML locally against the bot contract (no network).
|
|
15
|
+
- `verify --prod --all`: production-check every route discovered from build output.
|
|
16
|
+
- Global `--config <path>` for `init`, `build`, and `verify`.
|
|
17
|
+
- `worker.spaOrigin` (replaces `lovableOrigin`; old name still accepted on read).
|
|
18
|
+
- Config reference ([docs/CONFIG.md](docs/CONFIG.md)) and `rendershield.config.schema.json`.
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- `VerifyLocalResult` / `VerifyProdResult` return a `pages` array (multi-route aware).
|
|
23
|
+
- `init` default Worker origin field is `spaOrigin`.
|
|
24
|
+
|
|
25
|
+
## [1.0.0] - 2026-08-23
|
|
26
|
+
|
|
27
|
+
### Added
|
|
28
|
+
|
|
29
|
+
- **Programmatic API**: import `@lownoise-studio/rendershield` for `cmdInit`, `cmdBuild`, `cmdVerify`, config loading, HTML rendering, contract validation, and artifact generators.
|
|
30
|
+
- **`RenderShieldError`**: stable error codes (`CONFIG_MISSING`, `CONFIG_INVALID`, `OUTPUT_PATH_UNSAFE`, `CONTENT_INVALID`, `BUILD_FAILED`, `VALIDATION_FAILED`, `VERIFY_FAILED`, `CLI_INVALID_ARGS`) with optional `details` for library consumers.
|
|
31
|
+
- **TypeScript declarations**: published `.d.ts` via `package.json` `types` and `exports` map.
|
|
32
|
+
- **CI**: GitHub Actions workflow runs build and tests on Node 18, 20, and 22.
|
|
33
|
+
- **Docs**: `CONTRIBUTING.md` and `SECURITY.md`.
|
|
34
|
+
- Tests for `cmdInit`, local and `--prod` `cmdVerify`, public API exports, and `schemaType` rendering.
|
|
35
|
+
- `schemaType` config field now drives JSON-LD `@type` (`Article`, `BlogPosting`, `WebPage`).
|
|
36
|
+
|
|
37
|
+
### Fixed
|
|
38
|
+
|
|
39
|
+
- `verify` without build output now exits with failure (`VERIFY_FAILED`) instead of succeeding silently.
|
|
40
|
+
- `verify --prod` without a URL is rejected with `CLI_INVALID_ARGS` instead of falling back to local verify.
|
|
41
|
+
|
|
42
|
+
### Changed
|
|
43
|
+
|
|
44
|
+
- `cmdVerify` returns structured `VerifyResult` on success for programmatic use.
|
|
45
|
+
- CLI errors include error codes when thrown as `RenderShieldError`.
|
|
46
|
+
- `package.json`: `engines.node >= 18`, `exports`, `keywords`; sample `content/**` no longer published to npm.
|
|
47
|
+
- README: npm install / `npx` quickstart and programmatic API section.
|
|
48
|
+
|
|
49
|
+
## [0.3.1] - 2025-02-18
|
|
50
|
+
|
|
51
|
+
### Added
|
|
52
|
+
|
|
53
|
+
- `verify --prod <url>`: production check that asserts `x-rendershield: bot-hit` and runs the same HTML contract validation as build.
|
|
54
|
+
- Worker response header `x-rendershield`: `bot-hit` | `bot-fallback` | `pass-through` so routing is observable without inferring from HTML.
|
|
55
|
+
- CLI `--version` / `-V`: prints version from package.json.
|
|
56
|
+
- Vitest test suite: contract validation, loadConfig (including sitemap/robots path preservation and worker validation), path safety, and integration build.
|
|
57
|
+
|
|
58
|
+
### Fixed
|
|
59
|
+
|
|
60
|
+
- Config: sitemap and robots `path` are preserved and defaulted when only `enabled` is set; no longer lost when using boolean flags.
|
|
61
|
+
- Config: when `worker.enabled` is true, full worker object is kept (lovableOrigin, rewriteRouteBases, etc.) instead of being replaced by the flag.
|
|
62
|
+
- Worker: 500 error response body is generic ("Service temporarily unavailable.") to avoid leaking internals.
|
|
63
|
+
- JSON-LD in generated HTML: script body is no longer HTML-escaped so contract validation and crawlers can parse it.
|
|
64
|
+
|
|
65
|
+
### Changed
|
|
66
|
+
|
|
67
|
+
- Help text shows version and documents that `verify --prod` requires `x-rendershield: bot-hit`.
|
|
68
|
+
- TypeScript: reduced `any`; use `unknown` and typed interfaces in CLI, loadConfig, validateOutput, loadMarkdown.
|
|
69
|
+
- README: added "Production check" for `verify --prod`.
|
|
70
|
+
|
|
71
|
+
## [0.3.0] - 2025-02-18
|
|
72
|
+
|
|
73
|
+
- Initial npm release with init, build, verify, optional Cloudflare Worker, and HTML contract validation.
|
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Contributing to RenderShield
|
|
2
|
+
|
|
3
|
+
Thank you for your interest in contributing.
|
|
4
|
+
|
|
5
|
+
## Development setup
|
|
6
|
+
|
|
7
|
+
Requirements: **Node.js 18+**
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
git clone https://github.com/Lownoise-Studio/rendershield.git
|
|
11
|
+
cd rendershield
|
|
12
|
+
npm install
|
|
13
|
+
npm test
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
`npm test` runs `tsc` then Vitest. Tests import from `dist/`, so always build before running tests manually.
|
|
17
|
+
|
|
18
|
+
## Making changes
|
|
19
|
+
|
|
20
|
+
1. Create a branch from `main`.
|
|
21
|
+
2. Keep changes focused — RenderShield is intentionally narrow in scope.
|
|
22
|
+
3. Add or update tests for behavior changes.
|
|
23
|
+
4. Run `npm test` before opening a pull request.
|
|
24
|
+
5. Update `CHANGELOG.md` under `[Unreleased]` for user-visible changes.
|
|
25
|
+
|
|
26
|
+
## Pull requests
|
|
27
|
+
|
|
28
|
+
- Describe the problem and the approach.
|
|
29
|
+
- Link related issues when applicable.
|
|
30
|
+
- Ensure CI passes (build + tests on Node 18, 20, 22).
|
|
31
|
+
|
|
32
|
+
## Code style
|
|
33
|
+
|
|
34
|
+
- TypeScript strict mode; prefer `unknown` over `any`.
|
|
35
|
+
- Match existing module layout (`src/commands`, `src/core`).
|
|
36
|
+
- Throw `RenderShieldError` with a stable code for user-facing failures.
|
|
37
|
+
- Avoid drive-by refactors unrelated to the change.
|
|
38
|
+
|
|
39
|
+
## Reporting issues
|
|
40
|
+
|
|
41
|
+
Use [GitHub Issues](https://github.com/Lownoise-Studio/rendershield/issues). Include Node version, command run, and full error output.
|
package/README.md
CHANGED
|
@@ -1,144 +1,227 @@
|
|
|
1
|
-
# RenderShield
|
|
2
|
-
|
|
3
|
-
RenderShield
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
It prerenders content ahead of time and
|
|
7
|
-
at the edge, while normal users continue to receive
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
No
|
|
11
|
-
No
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
-
|
|
41
|
-
-
|
|
42
|
-
-
|
|
43
|
-
-
|
|
44
|
-
-
|
|
45
|
-
-
|
|
46
|
-
|
|
47
|
-
-
|
|
48
|
-
-
|
|
49
|
-
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
- It does not
|
|
62
|
-
|
|
63
|
-
It
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
npm
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
1
|
+
# RenderShield
|
|
2
|
+
|
|
3
|
+
RenderShield produces complete, static HTML for crawlers — and can prove
|
|
4
|
+
that bots receive it in production.
|
|
5
|
+
|
|
6
|
+
It prerenders structured content ahead of time and optionally routes crawler
|
|
7
|
+
requests to that output at the edge, while normal users continue to receive
|
|
8
|
+
your SPA.
|
|
9
|
+
|
|
10
|
+
No frameworks required.
|
|
11
|
+
No browser rendering.
|
|
12
|
+
No guessing what bots see.
|
|
13
|
+
|
|
14
|
+
If a page builds, the HTML contract is satisfied.
|
|
15
|
+
If `verify --prod` passes for a URL, that URL is receiving prerendered HTML to bots in production.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## What problem this solves
|
|
20
|
+
|
|
21
|
+
Modern SPAs often render content only after JavaScript executes.
|
|
22
|
+
|
|
23
|
+
Search engines, social scrapers, and AI crawlers may:
|
|
24
|
+
|
|
25
|
+
- see an empty shell
|
|
26
|
+
- see partial metadata
|
|
27
|
+
- receive inconsistent output
|
|
28
|
+
|
|
29
|
+
RenderShield enforces two guarantees:
|
|
30
|
+
|
|
31
|
+
- **Build-time contract** — Generated HTML must contain required metadata and content.
|
|
32
|
+
- **Production routing proof** — Bots must receive prerendered HTML (verified via header).
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## What RenderShield does
|
|
37
|
+
|
|
38
|
+
- Converts structured content (Markdown) into full static HTML pages
|
|
39
|
+
- Injects:
|
|
40
|
+
- `<title>`
|
|
41
|
+
- meta description
|
|
42
|
+
- canonical link
|
|
43
|
+
- Open Graph tags
|
|
44
|
+
- Twitter tags
|
|
45
|
+
- JSON-LD (Article, BlogPosting, WebPage)
|
|
46
|
+
- Generates:
|
|
47
|
+
- index.html per route
|
|
48
|
+
- sitemap.xml
|
|
49
|
+
- robots.txt
|
|
50
|
+
- optional Cloudflare Worker
|
|
51
|
+
- Validates output:
|
|
52
|
+
- missing title, metadata, or article body causes the build to fail
|
|
53
|
+
- Verifies behavior:
|
|
54
|
+
- `verify` (local) — prints curl smoke-test commands for built output; fails if output is missing (does not fetch URLs or validate HTML)
|
|
55
|
+
- `verify --prod <url>` — fetches production as Googlebot, asserts `x-rendershield: bot-hit`, and validates the HTML contract; fails if the Worker is missing or falling back
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## What it does not do
|
|
60
|
+
|
|
61
|
+
- It does not execute your application
|
|
62
|
+
- It does not render JavaScript for bots
|
|
63
|
+
- It does not guess content
|
|
64
|
+
- It does not guarantee rankings or traffic
|
|
65
|
+
- It does not replace your SPA
|
|
66
|
+
|
|
67
|
+
It guarantees one thing only:
|
|
68
|
+
that bot-facing HTML meets a defined contract —
|
|
69
|
+
and (optionally) that production routing serves it.
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Quickstart
|
|
74
|
+
|
|
75
|
+
Requires **Node.js 18+**.
|
|
76
|
+
|
|
77
|
+
### From npm
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
npm install -D @lownoise-studio/rendershield
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
npx rendershield init
|
|
85
|
+
npx rendershield build
|
|
86
|
+
npx rendershield verify
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Add a script to `package.json` if you prefer:
|
|
90
|
+
|
|
91
|
+
```json
|
|
92
|
+
{
|
|
93
|
+
"scripts": {
|
|
94
|
+
"prerender": "rendershield build",
|
|
95
|
+
"prerender:verify": "rendershield verify"
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### From source
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
git clone https://github.com/Lownoise-Studio/rendershield.git
|
|
104
|
+
cd rendershield
|
|
105
|
+
npm install
|
|
106
|
+
npm run build
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
**Initialize**
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
npx rendershield init
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Or:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
npm run start -- init
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**Add content**
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
content/blog/
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**Build**
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
rendershield build
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Or with npx:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
npx rendershield build
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
**Output**
|
|
140
|
+
|
|
141
|
+
```
|
|
142
|
+
dist-prerender/
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
**Local verify**
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
rendershield verify
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Prints curl commands for a built page (from `dist-prerender/`). Use this after `build` to get smoke-test commands for your Worker setup. Exits with code 1 if output is missing; it does **not** fetch URLs or validate HTML.
|
|
152
|
+
|
|
153
|
+
**Local contract check (CI-friendly)**
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
rendershield verify --check
|
|
157
|
+
rendershield verify --all --check
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Validates built HTML against the same bot contract as `build`, without network access.
|
|
161
|
+
|
|
162
|
+
**Production verify (after deploying Worker)**
|
|
163
|
+
|
|
164
|
+
Pass a **prerendered route URL** (not just the domain root):
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
rendershield verify --prod https://your-domain.com/blog/hello-world
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
This command:
|
|
171
|
+
|
|
172
|
+
- Fetches the URL as Googlebot (and as a human browser for comparison)
|
|
173
|
+
- Requires `x-rendershield: bot-hit` on the bot response
|
|
174
|
+
- Validates metadata + JSON-LD + article content on the bot response
|
|
175
|
+
- Exits with code 1 if anything fails
|
|
176
|
+
|
|
177
|
+
Proves routing for **that URL** only. Use `rendershield verify --prod --all` to check every route from build output.
|
|
178
|
+
|
|
179
|
+
Config reference: [docs/CONFIG.md](docs/CONFIG.md) · JSON Schema: `rendershield.config.schema.json`
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Programmatic API
|
|
184
|
+
|
|
185
|
+
RenderShield can be used as a library:
|
|
186
|
+
|
|
187
|
+
```ts
|
|
188
|
+
import { cmdBuild, loadConfig, checkPrerenderContract, RenderShieldError } from "@lownoise-studio/rendershield";
|
|
189
|
+
|
|
190
|
+
await cmdBuild(process.cwd());
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Exported commands, config loaders, HTML renderer, contract validators, and artifact generators are available from the package root. Errors throw `RenderShieldError` with stable `code` values for CI and tooling. ESM `import` only (no CommonJS `require`).
|
|
194
|
+
|
|
195
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup.
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## Deployment
|
|
200
|
+
|
|
201
|
+
Designed for Cloudflare Workers.
|
|
202
|
+
|
|
203
|
+
The generated Worker (enabled by default in `init`; set `worker.enabled: false` to skip):
|
|
204
|
+
|
|
205
|
+
- Rewrites bot requests on configured route bases (e.g. `/blog/`)
|
|
206
|
+
- Sets `x-rendershield` on all responses
|
|
207
|
+
- Makes routing observable and testable
|
|
208
|
+
|
|
209
|
+
See: [docs/deploy-cloudflare.md](docs/deploy-cloudflare.md)
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## Philosophy
|
|
214
|
+
|
|
215
|
+
RenderShield is intentionally narrow.
|
|
216
|
+
|
|
217
|
+
It does not attempt to simulate browsers.
|
|
218
|
+
It does not promise SEO outcomes.
|
|
219
|
+
It enforces a deterministic HTML contract and observable crawler routing.
|
|
220
|
+
|
|
221
|
+
Boring on purpose.
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## License
|
|
226
|
+
|
|
227
|
+
MIT
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Supported versions
|
|
4
|
+
|
|
5
|
+
| Version | Supported |
|
|
6
|
+
| ------- | --------- |
|
|
7
|
+
| 1.0.x | Yes |
|
|
8
|
+
| < 1.0 | No |
|
|
9
|
+
|
|
10
|
+
## Reporting a vulnerability
|
|
11
|
+
|
|
12
|
+
Please **do not** open a public GitHub issue for security vulnerabilities.
|
|
13
|
+
|
|
14
|
+
Email security reports to the maintainers via the contact listed on the [GitHub repository](https://github.com/Lownoise-Studio/rendershield). Include:
|
|
15
|
+
|
|
16
|
+
- A description of the issue and potential impact
|
|
17
|
+
- Steps to reproduce
|
|
18
|
+
- Affected versions
|
|
19
|
+
- Any suggested fix, if you have one
|
|
20
|
+
|
|
21
|
+
We aim to acknowledge reports within **5 business days** and will coordinate disclosure and a fix before publishing details.
|
|
22
|
+
|
|
23
|
+
## Scope notes
|
|
24
|
+
|
|
25
|
+
RenderShield generates static HTML and an optional Cloudflare Worker template. Deployment, DNS, TLS, and Worker binding configuration are the operator's responsibility. Security issues in generated Worker routing logic or path-safety checks in the build command are in scope for this project.
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
CHANGED
|
@@ -3,31 +3,40 @@ import { createRequire } from "node:module";
|
|
|
3
3
|
import { cmdInit } from "./commands/init.js";
|
|
4
4
|
import { cmdBuild } from "./commands/build.js";
|
|
5
5
|
import { cmdVerify } from "./commands/verify.js";
|
|
6
|
+
import { formatCliError, renderShieldError } from "./errors.js";
|
|
7
|
+
import { extractGlobalOptions, parseVerifyArgs } from "./cliArgs.js";
|
|
6
8
|
const require = createRequire(import.meta.url);
|
|
7
9
|
const pkg = require("../package.json");
|
|
8
10
|
const VERSION = pkg.version ?? "0.0.0";
|
|
9
11
|
function printHelp() {
|
|
10
|
-
console.log(`
|
|
11
|
-
RenderShield v${VERSION} — boring bot-aware prerendering.
|
|
12
|
-
|
|
13
|
-
Usage:
|
|
14
|
-
rendershield init
|
|
15
|
-
rendershield build
|
|
16
|
-
rendershield
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
-
|
|
12
|
+
console.log(`
|
|
13
|
+
RenderShield v${VERSION} — boring bot-aware prerendering.
|
|
14
|
+
|
|
15
|
+
Usage:
|
|
16
|
+
rendershield [--config <path>] init
|
|
17
|
+
rendershield [--config <path>] build
|
|
18
|
+
rendershield [--config <path>] verify [options]
|
|
19
|
+
|
|
20
|
+
Global:
|
|
21
|
+
--config <path> Config file (default: rendershield.config.json)
|
|
22
|
+
|
|
23
|
+
Verify:
|
|
24
|
+
verify Print curl smoke-test commands for first built page
|
|
25
|
+
verify --check Validate built HTML contract (first page)
|
|
26
|
+
verify --all --check Validate contract for every built page
|
|
27
|
+
verify --prod <url> Fetch URL as bot; require x-rendershield: bot-hit + contract
|
|
28
|
+
verify --prod --all Check every route from build output in production
|
|
29
|
+
|
|
30
|
+
Notes:
|
|
31
|
+
- Content: content/<collection>/**/*.md (frontmatter required)
|
|
32
|
+
- Output: dist-prerender/ (see config)
|
|
33
|
+
- Config reference: docs/CONFIG.md
|
|
26
34
|
`);
|
|
27
35
|
}
|
|
28
36
|
async function main() {
|
|
29
|
-
const
|
|
30
|
-
const cmd =
|
|
37
|
+
const { options: globalOptions, rest } = extractGlobalOptions(process.argv.slice(2));
|
|
38
|
+
const cmd = rest[0]?.trim();
|
|
39
|
+
const cmdArgs = rest.slice(1);
|
|
31
40
|
if (!cmd || cmd === "-h" || cmd === "--help") {
|
|
32
41
|
printHelp();
|
|
33
42
|
process.exit(0);
|
|
@@ -38,22 +47,26 @@ async function main() {
|
|
|
38
47
|
}
|
|
39
48
|
try {
|
|
40
49
|
if (cmd === "init") {
|
|
41
|
-
await cmdInit();
|
|
50
|
+
await cmdInit(undefined, globalOptions);
|
|
42
51
|
return;
|
|
43
52
|
}
|
|
44
53
|
if (cmd === "build") {
|
|
45
|
-
await cmdBuild();
|
|
54
|
+
await cmdBuild(undefined, globalOptions);
|
|
46
55
|
return;
|
|
47
56
|
}
|
|
48
57
|
if (cmd === "verify") {
|
|
49
|
-
|
|
50
|
-
if (verifyArgs.includes("-h") || verifyArgs.includes("--help")) {
|
|
58
|
+
if (cmdArgs.includes("-h") || cmdArgs.includes("--help")) {
|
|
51
59
|
printHelp();
|
|
52
60
|
process.exit(0);
|
|
53
61
|
}
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
62
|
+
const verifyOptions = parseVerifyArgs(cmdArgs, globalOptions);
|
|
63
|
+
if (verifyOptions.prod && !verifyOptions.prodUrl && !verifyOptions.all) {
|
|
64
|
+
throw renderShieldError("CLI_INVALID_ARGS", "verify --prod requires a URL, or use --prod --all. Example: rendershield verify --prod https://example.com/blog/hello-world");
|
|
65
|
+
}
|
|
66
|
+
if (verifyOptions.all && !verifyOptions.check && !verifyOptions.prod) {
|
|
67
|
+
throw renderShieldError("CLI_INVALID_ARGS", "verify --all requires --check (local) or --prod (production). Example: rendershield verify --all --check");
|
|
68
|
+
}
|
|
69
|
+
await cmdVerify(undefined, verifyOptions);
|
|
57
70
|
return;
|
|
58
71
|
}
|
|
59
72
|
console.error(`Unknown command: ${cmd}\n`);
|
|
@@ -61,7 +74,7 @@ async function main() {
|
|
|
61
74
|
process.exit(1);
|
|
62
75
|
}
|
|
63
76
|
catch (err) {
|
|
64
|
-
const msg =
|
|
77
|
+
const msg = formatCliError(err);
|
|
65
78
|
console.error(`\nRenderShield error: ${msg}\n`);
|
|
66
79
|
process.exit(1);
|
|
67
80
|
}
|