@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.
Files changed (87) hide show
  1. package/CHANGELOG.md +73 -32
  2. package/CONTRIBUTING.md +41 -0
  3. package/README.md +227 -144
  4. package/SECURITY.md +25 -0
  5. package/dist/cli.d.ts +3 -0
  6. package/dist/cli.d.ts.map +1 -0
  7. package/dist/cli.js +39 -26
  8. package/dist/cli.js.map +1 -1
  9. package/dist/cliArgs.d.ts +8 -0
  10. package/dist/cliArgs.d.ts.map +1 -0
  11. package/dist/cliArgs.js +56 -0
  12. package/dist/cliArgs.js.map +1 -0
  13. package/dist/commands/build.d.ts +3 -0
  14. package/dist/commands/build.d.ts.map +1 -0
  15. package/dist/commands/build.js +12 -11
  16. package/dist/commands/build.js.map +1 -1
  17. package/dist/commands/init.d.ts +3 -0
  18. package/dist/commands/init.d.ts.map +1 -0
  19. package/dist/commands/init.js +8 -7
  20. package/dist/commands/init.js.map +1 -1
  21. package/dist/commands/verify.d.ts +33 -0
  22. package/dist/commands/verify.d.ts.map +1 -0
  23. package/dist/commands/verify.js +202 -117
  24. package/dist/commands/verify.js.map +1 -1
  25. package/dist/configPath.d.ts +7 -0
  26. package/dist/configPath.d.ts.map +1 -0
  27. package/dist/configPath.js +8 -0
  28. package/dist/configPath.js.map +1 -0
  29. package/dist/core/generateRobots.d.ts +3 -0
  30. package/dist/core/generateRobots.d.ts.map +1 -0
  31. package/dist/core/generateSitemap.d.ts +3 -0
  32. package/dist/core/generateSitemap.d.ts.map +1 -0
  33. package/dist/core/generateWorker.d.ts +3 -0
  34. package/dist/core/generateWorker.d.ts.map +1 -0
  35. package/dist/core/generateWorker.js +75 -75
  36. package/dist/core/generateWorker.js.map +1 -1
  37. package/dist/core/listOutputRoutes.d.ts +4 -0
  38. package/dist/core/listOutputRoutes.d.ts.map +1 -0
  39. package/dist/core/listOutputRoutes.js +40 -0
  40. package/dist/core/listOutputRoutes.js.map +1 -0
  41. package/dist/core/loadConfig.d.ts +5 -0
  42. package/dist/core/loadConfig.d.ts.map +1 -0
  43. package/dist/core/loadConfig.js +108 -58
  44. package/dist/core/loadConfig.js.map +1 -1
  45. package/dist/core/loadMarkdown.d.ts +3 -0
  46. package/dist/core/loadMarkdown.d.ts.map +1 -0
  47. package/dist/core/loadMarkdown.js +4 -3
  48. package/dist/core/loadMarkdown.js.map +1 -1
  49. package/dist/core/renderHtml.d.ts +3 -0
  50. package/dist/core/renderHtml.d.ts.map +1 -0
  51. package/dist/core/renderHtml.js +25 -10
  52. package/dist/core/renderHtml.js.map +1 -1
  53. package/dist/core/validateOutput.d.ts +28 -0
  54. package/dist/core/validateOutput.d.ts.map +1 -0
  55. package/dist/core/validateOutput.js +7 -1
  56. package/dist/core/validateOutput.js.map +1 -1
  57. package/dist/errors.d.ts +14 -0
  58. package/dist/errors.d.ts.map +1 -0
  59. package/dist/errors.js +24 -0
  60. package/dist/errors.js.map +1 -0
  61. package/dist/index.d.ts +22 -0
  62. package/dist/index.d.ts.map +1 -0
  63. package/dist/index.js +20 -0
  64. package/dist/index.js.map +1 -0
  65. package/dist/types.d.ts +53 -0
  66. package/dist/types.d.ts.map +1 -0
  67. package/dist/types.js +1 -1
  68. package/dist/types.js.map +1 -1
  69. package/docs/CONFIG.md +70 -0
  70. package/docs/deploy-cloudflare.md +40 -14
  71. package/package.json +25 -2
  72. package/rendershield.config.schema.json +100 -0
  73. package/src/cli.ts +96 -75
  74. package/src/cliArgs.ts +71 -0
  75. package/src/commands/build.ts +200 -185
  76. package/src/commands/init.ts +8 -8
  77. package/src/commands/verify.ts +451 -236
  78. package/src/configPath.ts +17 -0
  79. package/src/core/generateWorker.ts +97 -97
  80. package/src/core/listOutputRoutes.ts +51 -0
  81. package/src/core/loadConfig.ts +282 -173
  82. package/src/core/loadMarkdown.ts +9 -3
  83. package/src/core/renderHtml.ts +36 -12
  84. package/src/core/validateOutput.ts +335 -328
  85. package/src/errors.ts +48 -0
  86. package/src/index.ts +43 -0
  87. 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
- ### Added
11
-
12
- - `verify --prod <url>`: production check that asserts `x-rendershield: bot-hit` and runs the same HTML contract validation as build.
13
- - Worker response header `x-rendershield`: `bot-hit` | `bot-fallback` | `pass-through` so routing is observable without inferring from HTML.
14
- - CLI `--version` / `-V`: prints version from package.json.
15
- - Vitest test suite: contract validation, loadConfig (including sitemap/robots path preservation and worker validation), path safety, and integration build.
16
-
17
- ### Fixed
18
-
19
- - Config: sitemap and robots `path` are preserved and defaulted when only `enabled` is set; no longer lost when using boolean flags.
20
- - Config: when `worker.enabled` is true, full worker object is kept (lovableOrigin, rewriteRouteBases, etc.) instead of being replaced by the flag.
21
- - Worker: 500 error response body is generic ("Service temporarily unavailable.") to avoid leaking internals.
22
- - JSON-LD in generated HTML: script body is no longer HTML-escaped so contract validation and crawlers can parse it.
23
-
24
- ### Changed
25
-
26
- - Help text shows version and documents that `verify --prod` requires `x-rendershield: bot-hit`.
27
- - TypeScript: reduced `any`; use `unknown` and typed interfaces in CLI, loadConfig, validateOutput, loadMarkdown.
28
- - README: added "Production check" for `verify --prod`.
29
-
30
- ## [0.3.0] - 2025-02-18
31
-
32
- - Initial npm release with init, build, verify, optional Cloudflare Worker, and HTML contract validation.
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.
@@ -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 ensures crawlers receive complete, static HTML instead of an empty
4
- JavaScript shell without changing how humans experience your app.
5
-
6
- It prerenders content ahead of time and can route crawler requests to that output
7
- at the edge, while normal users continue to receive the SPA.
8
-
9
- No frameworks required.
10
- No vendor lock-in.
11
- No guessing what bots see.
12
-
13
- If a page builds, the HTML is complete. If it isn’t, the build fails.
14
-
15
- ---
16
-
17
- ## What problem this solves
18
-
19
- Many modern apps technically work but are invisible to:
20
-
21
- - search engines
22
- - social preview scrapers
23
- - AI crawlers
24
-
25
- The content exists only after JavaScript executes.
26
- Crawlers do not wait.
27
-
28
- RenderShield fixes this by generating static, bot-readable HTML and refusing
29
- to ship incomplete output.
30
-
31
- ---
32
-
33
- ## What RenderShield does
34
-
35
- - Converts structured content into full static HTML pages
36
- - Injects:
37
- - title
38
- - meta description
39
- - canonical link
40
- - Open Graph tags
41
- - Twitter tags
42
- - JSON-LD (Article)
43
- - Generates:
44
- - index.html per route
45
- - sitemap.xml
46
- - robots.txt
47
- - optional Cloudflare Worker
48
- - Validates output
49
- - missing title, metadata, or content causes the build to fail
50
-
51
- If it builds, crawlers will see real content.
52
-
53
- ---
54
-
55
- ## What it does not do
56
-
57
- - It does not run your application
58
- - It does not execute JavaScript for bots
59
- - It does not guess content
60
- - It does not promise rankings, traffic, or citations
61
- - It does not replace your SPA
62
-
63
- It guarantees one thing only:
64
- that crawlers receive complete HTML.
65
-
66
- ---
67
-
68
- ## Quickstart
69
-
70
- 1) Install dependencies
71
-
72
- Run:
73
-
74
- npm install
75
-
76
- 2) Initialize RenderShield
77
-
78
- Run:
79
-
80
- npm run build
81
-
82
- This creates:
83
- - rendershield.config.json
84
- - sample content
85
- - a prerender output directory
86
-
87
- 3) Add content
88
-
89
- Place structured content under:
90
-
91
- content/
92
-
93
- 4) Build prerendered output
94
-
95
- Run:
96
-
97
- node dist/cli.js build
98
-
99
- Output is written to:
100
-
101
- dist-prerender/
102
-
103
- 5) Verify output
104
-
105
- Run:
106
-
107
- node dist/cli.js verify
108
-
109
- This prints curl commands you can use to confirm crawler behavior.
110
-
111
- **Production check:** After deploying the Worker, run:
112
-
113
- `rendershield verify --prod https://your-domain.com`
114
-
115
- This fetches the URL as a bot and asserts the response has `x-rendershield: bot-hit` (proving the Worker served prerendered HTML). If the header is missing or `bot-fallback`, the command fails.
116
-
117
- ---
118
-
119
- ## Deployment
120
-
121
- RenderShield is designed to run behind Cloudflare.
122
-
123
- A Worker routes crawler requests to prerendered HTML while passing all other
124
- traffic through unchanged.
125
-
126
- See:
127
- docs/deploy-cloudflare.md
128
-
129
- ---
130
-
131
- ## Philosophy
132
-
133
- RenderShield is intentionally boring.
134
-
135
- It does not attempt to outsmart crawlers or simulate browsers.
136
- It produces correct HTML and refuses to ship broken output.
137
-
138
- If crawlers cannot read it, the build fails.
139
-
140
- ---
141
-
142
- ## License
143
-
144
- MIT License
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,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -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 verify [--prod <url>]
17
-
18
- verify Print curl commands for local/build output.
19
- verify --prod Fetch URL as bot and human; verify bot sees full HTML and contract fields.
20
- Requires x-rendershield: bot-hit from the Worker.
21
-
22
- Notes:
23
- - Config file: rendershield.config.json
24
- - Content: content/<collection>/**/*.md (frontmatter required)
25
- - Output: dist-prerender/
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 args = process.argv.slice(2);
30
- const cmd = args[0]?.trim();
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
- const verifyArgs = args.slice(1);
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 prodIdx = verifyArgs.indexOf("--prod");
55
- const prodUrl = prodIdx >= 0 && verifyArgs[prodIdx + 1] ? verifyArgs[prodIdx + 1].trim() : undefined;
56
- await cmdVerify(undefined, prodUrl ? { prodUrl } : undefined);
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 = err instanceof Error ? err.message : String(err);
77
+ const msg = formatCliError(err);
65
78
  console.error(`\nRenderShield error: ${msg}\n`);
66
79
  process.exit(1);
67
80
  }