@jimhoyd/urlcode 0.4.0-alpha.2 → 0.4.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.
Files changed (147) hide show
  1. package/.claude/skills/urlcode-authoring/SKILL.md +17 -19
  2. package/.claude/skills/urlcode-operations/SKILL.md +9 -9
  3. package/.claude-plugin/marketplace.json +1 -1
  4. package/CONTRIBUTING.md +20 -16
  5. package/README.md +59 -64
  6. package/ROADMAP.md +66 -376
  7. package/dist/BUILD-MANIFEST.json +26 -25
  8. package/dist/agents-guide.js +6 -6
  9. package/dist/authoring.js +15 -1
  10. package/dist/build-static.js +2 -0
  11. package/dist/capability-query.js +0 -1
  12. package/dist/catalog.js +0 -1
  13. package/dist/cli.js +25 -9
  14. package/dist/config.js +1 -1
  15. package/dist/explain-cli.js +4 -2
  16. package/dist/explain.js +8 -2
  17. package/dist/extensions.js +1 -1
  18. package/dist/http-response.js +1 -1
  19. package/dist/index.js +1 -0
  20. package/dist/init-with.js +36 -11
  21. package/dist/manifest.js +8 -2
  22. package/dist/mcp-authoring.js +4 -4
  23. package/dist/mcp.js +1 -1
  24. package/dist/policies/cache.js +2 -2
  25. package/dist/policies.js +3 -1
  26. package/dist/prerender.js +4 -0
  27. package/dist/project-dependencies.js +305 -0
  28. package/dist/readiness.js +3 -0
  29. package/dist/route-diff.js +12 -5
  30. package/dist/runtime.js +1 -1
  31. package/dist/trusted-functions.js +4 -5
  32. package/dist/types/authoring.d.ts +9 -1
  33. package/dist/types/capability-query.d.ts +0 -1
  34. package/dist/types/catalog.d.ts +0 -4
  35. package/dist/types/config.d.ts +1 -9
  36. package/dist/types/explain.d.ts +6 -1
  37. package/dist/types/extensions.d.ts +1 -1
  38. package/dist/types/http-response.d.ts +0 -1
  39. package/dist/types/index.d.ts +1 -0
  40. package/dist/types/init-with.d.ts +7 -13
  41. package/dist/types/manifest.d.ts +5 -2
  42. package/dist/types/project-dependencies.d.ts +78 -0
  43. package/dist/types/readiness.d.ts +2 -0
  44. package/dist/types/trusted-functions.d.ts +1 -4
  45. package/dist/types/types.d.ts +8 -1
  46. package/dist/types.js +8 -1
  47. package/dist/typescript-authoring.js +18 -7
  48. package/docs/AI-AUTHORING.md +15 -7
  49. package/docs/ASSETS.md +2 -1
  50. package/docs/AUTH-BACKUP.md +32 -0
  51. package/docs/AWS.md +9 -0
  52. package/docs/BEST-PRACTICES.md +17 -9
  53. package/docs/CAPABILITIES.md +1 -1
  54. package/docs/CI-FOLLOWUP-2026-09-19.md +97 -0
  55. package/docs/CI-RELEASE-AUDIT-2026-09-19.md +322 -0
  56. package/docs/CI.md +8 -3
  57. package/docs/CODEBASE-AUDIT-2026-09-20.md +284 -0
  58. package/docs/COMPOSING-A-SITE.md +278 -0
  59. package/docs/DEVELOPMENT-PIPELINE.md +270 -0
  60. package/docs/EXTENSIONS.md +51 -11
  61. package/docs/FRAMEWORK.md +67 -48
  62. package/docs/FUNCTION-SECURITY.md +44 -0
  63. package/docs/INSTALL.md +13 -8
  64. package/docs/LOCAL-DEVELOPMENT.md +3 -0
  65. package/docs/MIDDLEWARE.md +10 -4
  66. package/docs/OPEN-DECISIONS.md +224 -212
  67. package/docs/OPERATIONAL-PROOF.md +3 -3
  68. package/docs/OPERATIONS.md +3 -3
  69. package/docs/POLICIES.md +13 -5
  70. package/docs/PRERENDER.md +23 -11
  71. package/docs/PROJECT-DIRECTION.md +3 -3
  72. package/docs/READINESS.md +10 -5
  73. package/docs/README.md +20 -44
  74. package/docs/RELEASE-0.4.0-alpha.3.md +50 -0
  75. package/docs/RELEASE-0.4.1.md +73 -0
  76. package/docs/RELEASE-READINESS.md +6 -6
  77. package/docs/RELEASE-SECURITY.md +96 -181
  78. package/docs/RESILIENCE.md +3 -3
  79. package/docs/ROUTING.md +3 -4
  80. package/docs/SECURITY-AUDIT.md +2 -2
  81. package/docs/SPECIFICATION.md +12 -6
  82. package/docs/SPIKE-AI-FRAMEWORK-BENCHMARK.md +6 -5
  83. package/docs/SPIKE-BUSINESS-SUITE.md +14 -6
  84. package/docs/SPIKE-CORE-LAYERING.md +49 -18
  85. package/docs/SPIKE-DEFAULT-TRUST-MODEL.md +7 -5
  86. package/docs/STARTERS.md +17 -5
  87. package/docs/STATIC.md +14 -3
  88. package/docs/TOOLING.md +10 -7
  89. package/docs/TYPESCRIPT-AUTHORING.md +6 -1
  90. package/docs/VERCEL.md +10 -2
  91. package/docs/VERSION-ALIGNMENT.md +76 -201
  92. package/docs/archive/2026-09-19/EXTENSION-IMPLEMENTATION.md +68 -0
  93. package/docs/archive/2026-09-19/MANAGEMENT-SECURITY.md +102 -0
  94. package/docs/{NEXT-PHASE-PLAN.md → archive/2026-09-19/NEXT-PHASE-PLAN.md} +15 -5
  95. package/docs/{NEXT-STEPS.md → archive/2026-09-19/NEXT-STEPS.md} +15 -3
  96. package/docs/archive/2026-09-19/OPEN-DECISIONS.md +277 -0
  97. package/docs/archive/2026-09-19/RELEASE-SECURITY.md +186 -0
  98. package/docs/archive/2026-09-19/ROADMAP.md +387 -0
  99. package/docs/{SPIKE-EXTENSION-MODEL.md → archive/2026-09-19/SPIKE-EXTENSION-MODEL.md} +11 -0
  100. package/docs/{SPIKE-EXTENSIONS.md → archive/2026-09-19/SPIKE-EXTENSIONS.md} +25 -14
  101. package/docs/archive/2026-09-19/SPIKE-LAMBDA-COMPILE.md +365 -0
  102. package/docs/archive/2026-09-19/SPIKE-MONOREPO.md +778 -0
  103. package/docs/{USABILITY-REVIEW.md → archive/2026-09-19/USABILITY-REVIEW.md} +12 -2
  104. package/docs/archive/README.md +28 -0
  105. package/docs/policies/agents.md +1 -1
  106. package/docs/policies/compression.md +3 -2
  107. package/docs/policies/security.md +3 -2
  108. package/docs/yaml/functions.md +10 -2
  109. package/docs/yaml/middleware.md +5 -3
  110. package/examples/assets/example.yaml +1 -1
  111. package/examples/cookbook/middleware/envelope.mjs +4 -2
  112. package/examples/cookbook/route-index.json +1 -1
  113. package/examples/cookbook/routes/middleware.yaml +1 -1
  114. package/examples/prerender/README.md +14 -6
  115. package/examples/prerender/functions/page.mjs +4 -2
  116. package/examples/prerender/middleware/template.mjs +1 -1
  117. package/examples/prerender/prerender.mjs +1 -1
  118. package/examples/prerender/urlcode.yaml +8 -4
  119. package/llms-full.txt +503 -88
  120. package/llms.txt +6 -4
  121. package/package.json +27 -4
  122. package/packaging/claude-plugin/.claude-plugin/plugin.json +2 -2
  123. package/packaging/claude-plugin/skills/urlcode-authoring/SKILL.md +17 -19
  124. package/packaging/claude-plugin/skills/urlcode-operations/SKILL.md +9 -9
  125. package/recipes/authenticated-json-api/README.md +4 -3
  126. package/recipes/authenticated-json-api/functions/profile.mjs +2 -1
  127. package/recipes/authenticated-json-api/recipe.yaml +1 -1
  128. package/recipes/contact-form/functions/contact.mjs +2 -1
  129. package/recipes/contact-form/recipe.yaml +2 -2
  130. package/recipes/cors-api/README.md +2 -2
  131. package/recipes/cors-api/recipe.yaml +1 -1
  132. package/recipes/health-page/README.md +1 -1
  133. package/recipes/json-api/README.md +1 -1
  134. package/recipes/json-api/recipe.yaml +3 -3
  135. package/recipes/middleware/README.md +8 -4
  136. package/recipes/middleware/middleware/envelope.mjs +4 -2
  137. package/recipes/protected-download/README.md +1 -1
  138. package/recipes/protected-download/recipe.yaml +1 -1
  139. package/recipes/static-plus-api/README.md +2 -2
  140. package/recipes/static-plus-api/public/index.html +1 -1
  141. package/recipes/static-plus-api/recipe.yaml +1 -1
  142. package/recipes/static-plus-api/urlcode.yaml +1 -1
  143. package/recipes/typescript/recipe.yaml +4 -4
  144. package/skills/urlcode/SKILL.md +6 -6
  145. package/starters/default/AGENTS.md +6 -6
  146. package/docs/SPIKE-LAMBDA-COMPILE.md +0 -201
  147. package/docs/SPIKE-MONOREPO.md +0 -322
@@ -1,3 +1,13 @@
1
+ # Historical record
2
+
3
+ Archived 2026-09-19. This records an earlier implementation or proposal, not
4
+ current instructions. See the [current roadmap](../../../ROADMAP.md),
5
+ [current contract](../../SPECIFICATION.md) and [open decisions](../../OPEN-DECISIONS.md).
6
+ Remaining acceptance work is not declared complete by archiving this record.
7
+
8
+ <!-- trust-model-prose: historical-file -->
9
+ <!-- guidance-claims: ignore-file -->
10
+
1
11
  # Usability review: URLCode against the tools people reach for instead
2
12
 
3
13
  Status: an honest assessment written 2026-09-18 against the source in the four
@@ -10,12 +20,12 @@ that would matter most. It does not change any contract by itself.
10
20
  > execution mode. Where the table below credits functions and middleware with
11
21
  > isolation, that now describes a route declaring `sandbox: true`; the default
12
22
  > is trusted, in-process execution with full Node, npm and filesystem access.
13
- > See [SPIKE-DEFAULT-TRUST-MODEL.md](SPIKE-DEFAULT-TRUST-MODEL.md).
23
+ > See [SPIKE-DEFAULT-TRUST-MODEL.md](../../SPIKE-DEFAULT-TRUST-MODEL.md).
14
24
 
15
25
  ## 1. Who the competitors are, by rung
16
26
 
17
27
  URLCode is not one product; it competes with a different tool on each rung
18
- of [the ladder](FRAMEWORK.md#the-ladder).
28
+ of [the ladder](../../FRAMEWORK.md#the-ladder).
19
29
 
20
30
  | Rung | What people use today | Where URLCode is better | Where it is worse today |
21
31
  |---|---|---|---|
@@ -0,0 +1,28 @@
1
+ # Historical records
2
+
3
+ These documents retain earlier reasoning and evidence. They are not authoring
4
+ instructions or an active backlog. Read [the current roadmap](../../ROADMAP.md),
5
+ [open decisions](../OPEN-DECISIONS.md) and [implemented contract](../SPECIFICATION.md)
6
+ first. An old example can describe a removed feature or an earlier trust model.
7
+
8
+ Archived on 2026-09-19 after checking the current code:
9
+
10
+ | Record | Why archived | Current owner of remaining work |
11
+ |---|---|---|
12
+ | [Monorepo spike](2026-09-19/SPIKE-MONOREPO.md) | The migration it proposed is complete: ui, auth and admin are workspace packages and all three have been released from this repository | [Development pipeline](../DEVELOPMENT-PIPELINE.md) and [release security](../RELEASE-SECURITY.md) |
13
+ | [Previous roadmap](2026-09-19/ROADMAP.md) | Release chronology mixed with current planning | Current roadmap and release readiness |
14
+ | [Detailed phases](2026-09-19/NEXT-STEPS.md) | Most authoring/tooling/UI work delivered; repeated stale backlog | Current roadmap, issues and open decisions |
15
+ | [Previous decisions](2026-09-19/OPEN-DECISIONS.md) | Mixed settled releases, obsolete repository counts and live questions | Current open decisions |
16
+ | [Next-phase implementation](2026-09-19/NEXT-PHASE-PLAN.md) | Delivered source snapshot for alpha.1 | Specification and provider evidence |
17
+ | [Extension delivery sequence](2026-09-19/EXTENSION-IMPLEMENTATION.md) | Registration, auth/admin and UI now implemented | Package status files and core issue 58 |
18
+ | [Policy/extension exploration](2026-09-19/SPIKE-EXTENSIONS.md) | Main design delivered; obsolete link APIs | Policies, plugins and extensions guides |
19
+ | [Extension model review](2026-09-19/SPIKE-EXTENSION-MODEL.md) | Historical design rationale | Current extension contract |
20
+ | [Usability review](2026-09-19/USABILITY-REVIEW.md) | Predates trusted execution and retired packages | New benchmark observations |
21
+ | [Management security](2026-09-19/MANAGEMENT-SECURITY.md) | Describes the removed core link-management API | No current core replacement |
22
+ | [Lambda compile spike](2026-09-19/SPIKE-LAMBDA-COMPILE.md) | Proposal declined 2026-09-19 in favour of one Node deployment per project | Open decisions; AWS and Vercel guides |
23
+
24
+ Open proposals stay outside the archive with their status stated at the top.
25
+ The accepted trust-by-default decision remains directly linked from the current
26
+ security contract; its `SPIKE-` filename is retained for existing references.
27
+ Security audits and operational evidence remain available: “implemented” never
28
+ means their unperformed review, deployment or recovery work is complete.
@@ -65,7 +65,7 @@ Matching is string matching. A client can claim any `User-Agent`, and the
65
65
  genuine search crawlers publish the way to check a claim (reverse DNS for
66
66
  Googlebot, bingbot and Applebot; the IETF `web-bot-auth` HTTP Message
67
67
  Signature drafts for newer agents). That verification needs network calls and
68
- vendor data, so it belongs in a [host plugin](../SPIKE-EXTENSIONS.md) that
68
+ vendor data, so it belongs in a [host plugin](../archive/2026-09-19/SPIKE-EXTENSIONS.md) that
69
69
  runs after this policy, not in the runtime.
70
70
 
71
71
  ## Bundled lists
@@ -1,8 +1,9 @@
1
1
  # Compression policy
2
2
 
3
3
  `policies.compression` negotiates a content coding (RFC 9110 §12.5.3) on the
4
- host, outside the sandbox, for every result a route produces: `respond`
5
- bodies, function results, asset responses, cache hits and early denials.
4
+ host, outside function/middleware execution trusted or sandboxed alike for
5
+ every result a route produces: `respond` bodies, function results, asset
6
+ responses, cache hits and early denials.
6
7
  It runs last in the response phase, after the cache store and the security
7
8
  headers, so every header it reads is final. Asset snapshots are compressed
8
9
  once at load and served by reference (the NGINX `gzip_static` / Caddy
@@ -1,7 +1,8 @@
1
1
  # Security headers policy
2
2
 
3
- `policies.security` adds response security headers on the host, outside the
4
- sandbox, to every result a route produces: redirects, `respond` bodies,
3
+ `policies.security` adds response security headers on the host, outside
4
+ function/middleware execution -- trusted or sandboxed alike -- to every result
5
+ a route produces: redirects, `respond` bodies,
5
6
  function results, asset responses, cache hits and early denials from the
6
7
  `agents` and `throttle` policies. Values are the OWASP Secure Headers
7
8
  Project best-practice recommendations (OSHP 2024 best practices,
@@ -53,8 +53,16 @@ short form: `middleware: [middleware/headers.mjs]` means
53
53
  `middleware: [{source: middleware/headers.mjs}]`. The path must be
54
54
  project-relative, end in `.mjs` or `.js` and contain no `..` segment.
55
55
  Methods default to GET and HEAD. Function paths resolve from the project root,
56
- not the YAML file's directory. `.js` and `.mjs` ES modules work; TypeScript, Node
57
- APIs, npm imports, network access and filesystem access do not.
56
+ not the YAML file's directory. Modules are ES modules either way: `.mjs` always
57
+ works, while a trusted `.js` module is loaded by Node and therefore needs the
58
+ nearest `package.json` to say `"type": "module"` (a `sandbox: true` route reads
59
+ `.js` as ESM regardless). Serving never transpiles TypeScript; build it first
60
+ with [TypeScript authoring](../TYPESCRIPT-AUTHORING.md). The route above
61
+ declares no `sandbox`, so it runs trusted and in-process: Node APIs, npm
62
+ imports, network and filesystem access are all available to it, exactly as they
63
+ are to any other Node code in the host. Add `sandbox: true` to trade them away
64
+ for isolation -- inside the guest none of them exist. See
65
+ [trust model and sandbox opt-in](../FUNCTION-SECURITY.md).
58
66
 
59
67
  ## 4. Input types and constraints
60
68
 
@@ -23,7 +23,9 @@ export async function decorate(request, context, next) {
23
23
 
24
24
  Entries run in declared order before the handler and reverse order afterward.
25
25
  Return a Response early to skip downstream code; call `next()` at most once.
26
- Up to 16 middleware entries share one sandbox/deadline and approved route
27
- bindings. Native bodies are opaque; preserving them requires retaining original
28
- status/headers. Return a new Response to replace native content or destination.
26
+ Up to 16 middleware entries share the route's execution mode, one deadline and
27
+ one set of approved route bindings; the mode is the route's `sandbox` field, not
28
+ a per-entry choice. On a `sandbox: true` route native bodies are opaque;
29
+ preserving them requires retaining original status/headers. Return a new
30
+ Response to replace native content or destination.
29
31
  YAML response headers apply last. See [middleware](../MIDDLEWARE.md) for details.
@@ -14,4 +14,4 @@ tests:
14
14
  - node src/cli.ts audit --project examples/assets --expect-routes 5
15
15
  behavior:
16
16
  - native page, static and download routes serve snapshotted files with explicit caching
17
- - one sandboxed function shows the two kinds of route side by side
17
+ - one trusted function shows the two kinds of route side by side
@@ -1,5 +1,7 @@
1
- // Wrap successful JSON function responses in a stable envelope. Native bodies are
2
- // opaque and pass through untouched; only readable JSON is rewritten.
1
+ // Wrap successful JSON function responses in a stable envelope. Only a JSON body
2
+ // this chain can actually read is rewritten; everything else passes through
3
+ // untouched -- on a `sandbox: true` route that includes every native body, which
4
+ // the guest cannot read at all.
3
5
  export default async function envelope(request, context, next) {
4
6
  const response = await next();
5
7
  if (!response.ok || !(response.headers.get('content-type') || '').startsWith('application/json')) return response;
@@ -367,7 +367,7 @@
367
367
  "bindings",
368
368
  "auth"
369
369
  ],
370
- "description": "HTTP Basic authentication decoded inside the guest"
370
+ "description": "HTTP Basic authentication decoded in trusted middleware"
371
371
  },
372
372
  {
373
373
  "path": "/cors/data",
@@ -12,7 +12,7 @@ routes:
12
12
  export: bearer
13
13
  respond: {json: {private: true}}
14
14
  /admin/panel:
15
- description: HTTP Basic authentication decoded inside the guest
15
+ description: HTTP Basic authentication decoded in trusted middleware
16
16
  env:
17
17
  ADMIN_USER: {value: admin}
18
18
  ADMIN_PASSWORD: {value: cookbook-password}
@@ -1,8 +1,15 @@
1
1
  # Prerender a dynamic project into a native static one
2
2
 
3
3
  Three pages rendered by a function and one shared template middleware, then
4
- rendered once at build time into a project that serves the same bytes with
5
- native `page` routes and no sandbox on the request path.
4
+ rendered once at build time into a project that serves the same bytes with no
5
+ code on the request path at all.
6
+
7
+ The source routes run trusted and in-process, which is the default for
8
+ `function`/`middleware` and the right choice here: the page code is reviewed
9
+ first-party code that reads nothing but the literal arguments in
10
+ `urlcode.yaml`. Prerendering does not depend on that — a route declaring
11
+ `sandbox: true` prerenders the same way — and either way the generated project
12
+ runs no code at all.
6
13
 
7
14
  From the runtime checkout:
8
15
 
@@ -15,17 +22,18 @@ node src/cli.ts audit --project /absolute/out --expect-routes 3
15
22
  ```
16
23
 
17
24
  The same three URLs answer identically before and after. The difference is what
18
- runs to serve them: the source project runs function and middleware code per
19
- request, the generated project reads a prevalidated byte buffer.
25
+ runs to serve them: the source project executes the function and its middleware
26
+ per request, the generated project reads a prevalidated byte buffer and runs no
27
+ project code at all.
20
28
 
21
29
  | | Source project | Generated project |
22
30
  |---|---|---|
23
31
  | Handlers | 3 × `function` | 3 × `page` |
24
32
  | Middleware | shared template | none |
25
- | Guest execution per request | yes | none |
33
+ | Project code per request | function + middleware | none |
26
34
  | Content | reviewed literals in YAML | rendered HTML files |
27
35
 
28
- `prerender.mjs` is operator build tooling that runs in Node, not guest code. The
36
+ `prerender.mjs` is operator build tooling, not a route handler. The
29
37
  orchestration lives in the runtime's build helper:
30
38
 
31
39
  ```js
@@ -1,6 +1,8 @@
1
1
  // One page's content, supplied as reviewed literal arguments in urlcode.yaml.
2
- // This runs in the QuickJS/WASM sandbox with no filesystem, network or host
3
- // code, at build time exactly as it would at request time.
2
+ // This runs trusted and in-process -- the default for a function route -- at
3
+ // build time exactly as it would at request time. It reads nothing but its
4
+ // own args, so there is nothing here for `sandbox: true` to isolate; adding it
5
+ // would cost worker-pool capacity for no gain.
4
6
  export function page(request, {args}) {
5
7
  return new Response(args.body, {headers: {'content-type': 'text/html; charset=utf-8'}});
6
8
  }
@@ -22,7 +22,7 @@ export async function template(request, context, next) {
22
22
  <h1>${title}</h1>
23
23
  ${content}
24
24
  </main>
25
- <footer>Prerendered at build time. No guest code runs to serve this page.</footer>
25
+ <footer>Prerendered at build time. No project code runs to serve this page.</footer>
26
26
  </body>
27
27
  </html>
28
28
  `, {status: response.status, headers: {'content-type': 'text/html; charset=utf-8'}});
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  // Prerender recipe: render this project's function/middleware routes once, at
3
3
  // build time, into a native page project that serves the same bytes with no
4
- // guest execution on the request path.
4
+ // project code on the request path.
5
5
  //
6
6
  // The orchestration that is easy to get wrong — runtime lifecycle, response
7
7
  // validation, budgets, byte fidelity and output-path safety — lives in the
@@ -2,6 +2,10 @@ version: "1"
2
2
  # The dynamic source of the site. Every page is a function response wrapped by
3
3
  # one shared template middleware, so `dev` serves it live while you edit. The
4
4
  # prerender recipe renders these routes once and emits a native page project.
5
+ # No route declares `sandbox: true`: this is reviewed first-party code taking
6
+ # literal arguments from this file, which is the trusted default's case, not an
7
+ # exception to it (docs/AI-AUTHORING.md, "Deciding when a route needs
8
+ # `sandbox: true`").
5
9
  routes:
6
10
  /:
7
11
  description: Home page rendered by a function and the shared template
@@ -16,7 +20,7 @@ routes:
16
20
  body: |
17
21
  <p>This page is generated by a function and wrapped by shared template
18
22
  middleware. Running the prerender recipe turns it into a native page
19
- route that serves the same bytes with no sandbox on the request path.</p>
23
+ route that serves the same bytes with no code on the request path.</p>
20
24
  <ul>
21
25
  <li><a href="/guide">Guide</a></li>
22
26
  <li><a href="/about">About</a></li>
@@ -32,9 +36,9 @@ routes:
32
36
  args:
33
37
  title: Guide
34
38
  body: |
35
- <p>Content is reviewed literal input in YAML. Guest code never reads the
36
- filesystem, so a larger site generates this project from host-prepared
37
- content before rendering.</p>
39
+ <p>Content is reviewed literal input in YAML rather than anything this
40
+ code goes and reads, so a larger site generates this project from
41
+ host-prepared content before rendering.</p>
38
42
  /about:
39
43
  description: A third page proving the template is shared, not copied
40
44
  middleware: