@jimhoyd/urlcode 0.3.0 → 0.4.0-alpha.2

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 (380) hide show
  1. package/.claude/skills/urlcode-authoring/SKILL.md +122 -0
  2. package/.claude/skills/urlcode-operations/SKILL.md +108 -0
  3. package/.claude-plugin/marketplace.json +18 -0
  4. package/CONTRIBUTING.md +30 -2
  5. package/README.md +195 -255
  6. package/ROADMAP.md +143 -15
  7. package/SECURITY.md +31 -9
  8. package/dist/BUILD-MANIFEST.json +72 -47
  9. package/dist/adapters.js +4 -23
  10. package/dist/agent-lists.js +1 -1
  11. package/dist/agents-guide.js +113 -0
  12. package/dist/authoring-files.js +60 -0
  13. package/dist/authoring.js +11 -1
  14. package/dist/aws.js +4 -3
  15. package/dist/build-cloudflare.js +11 -24
  16. package/dist/build-static.js +134 -0
  17. package/dist/bulk.js +37 -0
  18. package/dist/capabilities.js +262 -0
  19. package/dist/capability-query.js +71 -0
  20. package/dist/catalog.js +105 -0
  21. package/dist/cli.js +165 -34
  22. package/dist/client-address.js +1 -1
  23. package/dist/compliance-rules/baseline.js +9 -17
  24. package/dist/compliance-rules/privacy.js +7 -18
  25. package/dist/compliance-rules/shared.js +0 -2
  26. package/dist/compliance-rules/strict.js +5 -5
  27. package/dist/compliance.js +6 -8
  28. package/dist/conditions.js +88 -0
  29. package/dist/config.js +69 -6
  30. package/dist/context.js +155 -0
  31. package/dist/ecosystem-cli.js +88 -0
  32. package/dist/egress.js +98 -0
  33. package/dist/examples.js +92 -0
  34. package/dist/explain-cli.js +64 -0
  35. package/dist/explain.js +131 -0
  36. package/dist/extensions.js +231 -0
  37. package/dist/function-sources.js +49 -5
  38. package/dist/function-worker.js +3 -1
  39. package/dist/functions.js +84 -13
  40. package/dist/guest-api.js +29 -3
  41. package/dist/index.js +40 -6
  42. package/dist/init-with.js +165 -0
  43. package/dist/interchange-cli.js +42 -0
  44. package/dist/interchange.js +189 -0
  45. package/dist/manifest.js +109 -0
  46. package/dist/match.js +2 -2
  47. package/dist/mcp-authoring.js +147 -0
  48. package/dist/mcp.js +97 -0
  49. package/dist/observability.js +7 -21
  50. package/dist/operator-host.js +29 -0
  51. package/dist/plugins.js +12 -0
  52. package/dist/policies/agents.js +2 -2
  53. package/dist/policies/cache.js +8 -3
  54. package/dist/policies/compression.js +2 -1
  55. package/dist/policies/security.js +0 -0
  56. package/dist/policies.js +1 -1
  57. package/dist/policy.js +56 -15
  58. package/dist/prerender.js +100 -41
  59. package/dist/project-tests.js +3 -3
  60. package/dist/provider-verification.js +92 -0
  61. package/dist/proxy.js +44 -0
  62. package/dist/readiness.js +34 -11
  63. package/dist/recipes.js +41 -0
  64. package/dist/route-diff.js +106 -0
  65. package/dist/router.js +45 -7
  66. package/dist/runtime.js +164 -64
  67. package/dist/sandbox.js +48 -0
  68. package/dist/scaffold.js +0 -0
  69. package/dist/schema-query.js +62 -0
  70. package/dist/scripts/operational-drills.js +12 -54
  71. package/dist/server.js +3 -29
  72. package/dist/signals.js +24 -0
  73. package/dist/site.js +0 -0
  74. package/dist/tooling.js +96 -0
  75. package/dist/trusted-functions.js +210 -0
  76. package/dist/types/adapters.d.ts +7 -4
  77. package/dist/types/agent-lists.d.ts +0 -1
  78. package/dist/types/agents-guide.d.ts +17 -0
  79. package/dist/types/authoring-files.d.ts +10 -0
  80. package/dist/types/aws.d.ts +3 -1
  81. package/dist/types/build-cloudflare.d.ts +1 -0
  82. package/dist/types/build-static.d.ts +43 -0
  83. package/dist/types/bulk.d.ts +27 -0
  84. package/dist/types/capabilities.d.ts +64 -0
  85. package/dist/types/capability-query.d.ts +24 -0
  86. package/dist/types/catalog.d.ts +65 -0
  87. package/dist/types/client-address.d.ts +0 -1
  88. package/dist/types/compliance-rules/baseline.d.ts +1 -9
  89. package/dist/types/compliance-rules/privacy.d.ts +1 -4
  90. package/dist/types/compliance-rules/shared.d.ts +0 -2
  91. package/dist/types/compliance-rules/strict.d.ts +0 -5
  92. package/dist/types/compliance.d.ts +0 -3
  93. package/dist/types/conditions.d.ts +19 -0
  94. package/dist/types/config.d.ts +21 -2
  95. package/dist/types/context.d.ts +66 -0
  96. package/dist/types/ecosystem-cli.d.ts +17 -0
  97. package/dist/types/egress.d.ts +46 -0
  98. package/dist/types/examples.d.ts +50 -0
  99. package/dist/types/explain-cli.d.ts +11 -0
  100. package/dist/types/explain.d.ts +95 -0
  101. package/dist/types/extensions.d.ts +177 -0
  102. package/dist/types/function-sources.d.ts +9 -0
  103. package/dist/types/functions.d.ts +48 -5
  104. package/dist/types/guest-api.d.ts +1 -0
  105. package/dist/types/index.d.ts +36 -6
  106. package/dist/types/init-with.d.ts +30 -0
  107. package/dist/types/interchange-cli.d.ts +16 -0
  108. package/dist/types/interchange.d.ts +42 -0
  109. package/dist/types/manifest.d.ts +79 -0
  110. package/dist/types/match.d.ts +1 -0
  111. package/dist/types/mcp-authoring.d.ts +92 -0
  112. package/dist/types/mcp.d.ts +12 -0
  113. package/dist/types/observability.d.ts +3 -14
  114. package/dist/types/operator-host.d.ts +8 -0
  115. package/dist/types/plugins.d.ts +2 -0
  116. package/dist/types/policies/agents.d.ts +0 -2
  117. package/dist/types/policies/compression.d.ts +2 -0
  118. package/dist/types/policies/security.d.ts +0 -1
  119. package/dist/types/policy.d.ts +15 -4
  120. package/dist/types/project-tests.d.ts +3 -2
  121. package/dist/types/provider-verification.d.ts +53 -0
  122. package/dist/types/proxy.d.ts +21 -0
  123. package/dist/types/readiness.d.ts +10 -3
  124. package/dist/types/recipes.d.ts +30 -0
  125. package/dist/types/route-diff.d.ts +27 -0
  126. package/dist/types/router.d.ts +2 -1
  127. package/dist/types/runtime.d.ts +11 -27
  128. package/dist/types/sandbox.d.ts +12 -0
  129. package/dist/types/scaffold.d.ts +0 -2
  130. package/dist/types/schema-query.d.ts +12 -0
  131. package/dist/types/server.d.ts +1 -4
  132. package/dist/types/signals.d.ts +25 -0
  133. package/dist/types/site.d.ts +0 -1
  134. package/dist/types/tooling.d.ts +115 -0
  135. package/dist/types/trusted-functions.d.ts +29 -0
  136. package/dist/types/types.d.ts +71 -7
  137. package/dist/types/typescript-authoring.d.ts +12 -0
  138. package/dist/types/vercel.d.ts +3 -1
  139. package/dist/types/verify-deployment.d.ts +47 -0
  140. package/dist/types.js +37 -5
  141. package/dist/typescript-authoring.js +142 -0
  142. package/dist/vercel.js +4 -3
  143. package/dist/verify-deployment.js +270 -0
  144. package/docs/AI-AUTHORING.md +232 -15
  145. package/docs/AWS.md +4 -4
  146. package/docs/BEST-PRACTICES.md +3 -2
  147. package/docs/BULK.md +79 -0
  148. package/docs/CAPABILITIES.md +192 -0
  149. package/docs/CAPACITY.md +129 -32
  150. package/docs/CI.md +142 -0
  151. package/docs/CLOUDFLARE.md +1 -2
  152. package/docs/COMPLIANCE.md +6 -9
  153. package/docs/CONDITIONS.md +74 -0
  154. package/docs/DEPLOYMENT-CHECKS.md +108 -0
  155. package/docs/EGRESS.md +125 -0
  156. package/docs/EXTENSIONS.md +398 -0
  157. package/docs/FRAMEWORK.md +198 -0
  158. package/docs/FUNCTION-SECURITY.md +129 -32
  159. package/docs/INSTALL.md +45 -12
  160. package/docs/INTERCHANGE.md +134 -0
  161. package/docs/LOAD-TESTING.md +4 -4
  162. package/docs/MIDDLEWARE-EXAMPLES.md +75 -0
  163. package/docs/MIDDLEWARE.md +29 -16
  164. package/docs/MONITORING.md +2 -19
  165. package/docs/NEXT-PHASE-PLAN.md +98 -0
  166. package/docs/NEXT-STEPS.md +634 -0
  167. package/docs/OBSERVABILITY.md +11 -18
  168. package/docs/OPEN-DECISIONS.md +212 -0
  169. package/docs/OPERATIONAL-PROOF.md +30 -31
  170. package/docs/OPERATIONS.md +29 -35
  171. package/docs/PLUGINS.md +37 -0
  172. package/docs/POLICIES.md +23 -309
  173. package/docs/PRERENDER.md +41 -1
  174. package/docs/PROJECT-DIRECTION.md +75 -8
  175. package/docs/PROVIDER-VERIFICATION.md +84 -0
  176. package/docs/READINESS.md +21 -1
  177. package/docs/README.md +87 -34
  178. package/docs/RECIPES.md +99 -0
  179. package/docs/RELEASE-READINESS.md +57 -35
  180. package/docs/RELEASE-SECURITY.md +116 -7
  181. package/docs/RESILIENCE.md +16 -15
  182. package/docs/ROUTING.md +8 -10
  183. package/docs/SANDBOX-REVIEW.md +19 -6
  184. package/docs/SCAFFOLDING.md +0 -2
  185. package/docs/SECURITY-AUDIT.md +41 -1
  186. package/docs/SPECIFICATION.md +150 -29
  187. package/docs/SPIKE-AI-FRAMEWORK-BENCHMARK.md +287 -0
  188. package/docs/SPIKE-BUSINESS-SUITE.md +1021 -0
  189. package/docs/SPIKE-CORE-LAYERING.md +337 -0
  190. package/docs/SPIKE-DEFAULT-TRUST-MODEL.md +209 -0
  191. package/docs/SPIKE-EXTENSION-MODEL.md +419 -0
  192. package/docs/SPIKE-EXTENSIONS.md +6 -0
  193. package/docs/SPIKE-LAMBDA-COMPILE.md +201 -0
  194. package/docs/SPIKE-MONOREPO.md +322 -0
  195. package/docs/STANDARDS.md +150 -142
  196. package/docs/STARTERS.md +21 -1
  197. package/docs/STATIC.md +94 -0
  198. package/docs/TOOLING.md +295 -0
  199. package/docs/TUNNELS.md +0 -3
  200. package/docs/TYPESCRIPT-AUTHORING.md +82 -0
  201. package/docs/TYPESCRIPT.md +25 -4
  202. package/docs/USABILITY-REVIEW.md +129 -0
  203. package/docs/VERCEL.md +4 -5
  204. package/docs/VERSION-ALIGNMENT.md +205 -0
  205. package/docs/YAML-GUIDE.md +15 -479
  206. package/docs/YAML-REFERENCE.md +143 -22
  207. package/docs/policies/agents.md +1 -1
  208. package/docs/policies/cache.md +13 -0
  209. package/docs/policies/contract.md +52 -0
  210. package/docs/policies/hardened.md +56 -0
  211. package/docs/policies/interoperability.md +169 -0
  212. package/docs/policies/operations.md +45 -0
  213. package/docs/yaml/assets.md +36 -0
  214. package/docs/yaml/conditions.md +20 -0
  215. package/docs/yaml/functions.md +160 -0
  216. package/docs/yaml/middleware.md +29 -0
  217. package/docs/yaml/organization.md +74 -0
  218. package/docs/yaml/policies.md +37 -0
  219. package/docs/yaml/redirects.md +64 -0
  220. package/docs/yaml/responses.md +57 -0
  221. package/docs/yaml/site.md +24 -0
  222. package/examples/assets/example.yaml +17 -0
  223. package/examples/aws/example.yaml +20 -0
  224. package/examples/cloudflare/example.yaml +19 -0
  225. package/examples/compliance/example.yaml +11 -0
  226. package/examples/conditions/README.md +12 -0
  227. package/examples/conditions/example.yaml +19 -0
  228. package/examples/conditions/tests/requests.json +13 -0
  229. package/examples/conditions/urlcode.yaml +24 -0
  230. package/examples/cookbook/README.md +8 -4
  231. package/examples/cookbook/example.yaml +17 -0
  232. package/examples/cookbook/functions/catalog.mjs +3 -0
  233. package/examples/cookbook/functions/fail.mjs +4 -0
  234. package/examples/cookbook/functions/items.mjs +3 -0
  235. package/examples/cookbook/functions/profile.mjs +3 -0
  236. package/examples/cookbook/functions/resource.mjs +3 -0
  237. package/examples/cookbook/functions/status.mjs +3 -0
  238. package/examples/cookbook/middleware/auth.mjs +48 -0
  239. package/examples/cookbook/middleware/body.mjs +15 -0
  240. package/examples/cookbook/middleware/bucket.mjs +29 -0
  241. package/examples/cookbook/middleware/cors.mjs +21 -0
  242. package/examples/cookbook/middleware/debug.mjs +13 -0
  243. package/examples/cookbook/middleware/envelope.mjs +11 -0
  244. package/examples/cookbook/middleware/errors.mjs +11 -0
  245. package/examples/cookbook/middleware/etag.mjs +18 -0
  246. package/examples/cookbook/middleware/locale.mjs +20 -0
  247. package/examples/cookbook/middleware/maintenance.mjs +10 -0
  248. package/examples/cookbook/middleware/methods.mjs +15 -0
  249. package/examples/cookbook/middleware/negotiate.mjs +20 -0
  250. package/examples/cookbook/middleware/referer.mjs +12 -0
  251. package/examples/cookbook/middleware/request-id.mjs +16 -0
  252. package/examples/cookbook/route-index.json +676 -0
  253. package/examples/cookbook/routes/middleware.yaml +126 -0
  254. package/examples/cookbook/tests/requests.json +526 -0
  255. package/examples/cookbook/urlcode.yaml +1 -0
  256. package/examples/egress/README.md +22 -0
  257. package/examples/egress/example.yaml +19 -0
  258. package/examples/egress/urlcode.yaml +19 -0
  259. package/examples/extensions/README.md +7 -0
  260. package/examples/extensions/example.yaml +21 -0
  261. package/examples/extensions/urlcode.yaml +25 -0
  262. package/examples/monitoring/example.yaml +8 -0
  263. package/examples/prerender/README.md +2 -2
  264. package/examples/prerender/example.yaml +16 -0
  265. package/examples/provider-conformance/README.md +12 -0
  266. package/examples/provider-conformance/example.yaml +14 -0
  267. package/examples/provider-conformance/urlcode.yaml +34 -0
  268. package/examples/tunnel/example.yaml +8 -0
  269. package/examples/vercel/example.yaml +19 -0
  270. package/llms-full.txt +3084 -0
  271. package/llms.txt +61 -21
  272. package/package.json +36 -7
  273. package/packaging/claude-plugin/.claude-plugin/plugin.json +19 -0
  274. package/packaging/claude-plugin/skills/urlcode-authoring/SKILL.md +122 -0
  275. package/packaging/claude-plugin/skills/urlcode-operations/SKILL.md +108 -0
  276. package/recipes/authenticated-json-api/README.md +51 -0
  277. package/recipes/authenticated-json-api/functions/profile.mjs +5 -0
  278. package/recipes/authenticated-json-api/recipe.yaml +34 -0
  279. package/recipes/authenticated-json-api/tests/requests.json +39 -0
  280. package/recipes/authenticated-json-api/urlcode.yaml +12 -0
  281. package/recipes/contact-form/README.md +25 -0
  282. package/recipes/contact-form/functions/contact.mjs +17 -0
  283. package/recipes/contact-form/recipe.yaml +33 -0
  284. package/recipes/contact-form/tests/requests.json +47 -0
  285. package/recipes/contact-form/urlcode.yaml +18 -0
  286. package/recipes/cors-api/README.md +16 -0
  287. package/recipes/cors-api/functions/items.mjs +3 -0
  288. package/recipes/cors-api/middleware/cors.mjs +21 -0
  289. package/recipes/cors-api/recipe.yaml +26 -0
  290. package/recipes/cors-api/tests/requests.json +65 -0
  291. package/recipes/cors-api/urlcode.yaml +12 -0
  292. package/recipes/health-page/README.md +13 -0
  293. package/recipes/health-page/recipe.yaml +23 -0
  294. package/recipes/health-page/tests/requests.json +36 -0
  295. package/recipes/health-page/urlcode.yaml +19 -0
  296. package/recipes/json-api/README.md +6 -0
  297. package/recipes/json-api/functions/echo.mjs +3 -0
  298. package/recipes/json-api/recipe.yaml +25 -0
  299. package/recipes/json-api/tests/requests.json +34 -0
  300. package/recipes/json-api/urlcode.yaml +12 -0
  301. package/recipes/middleware/README.md +34 -0
  302. package/recipes/middleware/functions/catalog.mjs +3 -0
  303. package/recipes/middleware/functions/fail.mjs +4 -0
  304. package/recipes/middleware/functions/items.mjs +3 -0
  305. package/recipes/middleware/functions/profile.mjs +3 -0
  306. package/recipes/middleware/functions/resource.mjs +3 -0
  307. package/recipes/middleware/functions/status.mjs +3 -0
  308. package/recipes/middleware/middleware/auth.mjs +48 -0
  309. package/recipes/middleware/middleware/body.mjs +15 -0
  310. package/recipes/middleware/middleware/bucket.mjs +29 -0
  311. package/recipes/middleware/middleware/cors.mjs +21 -0
  312. package/recipes/middleware/middleware/debug.mjs +13 -0
  313. package/recipes/middleware/middleware/envelope.mjs +11 -0
  314. package/recipes/middleware/middleware/errors.mjs +11 -0
  315. package/recipes/middleware/middleware/etag.mjs +18 -0
  316. package/recipes/middleware/middleware/locale.mjs +20 -0
  317. package/recipes/middleware/middleware/maintenance.mjs +10 -0
  318. package/recipes/middleware/middleware/methods.mjs +15 -0
  319. package/recipes/middleware/middleware/negotiate.mjs +20 -0
  320. package/recipes/middleware/middleware/referer.mjs +12 -0
  321. package/recipes/middleware/middleware/request-id.mjs +16 -0
  322. package/recipes/middleware/public/guide.txt +1 -0
  323. package/recipes/middleware/recipe.yaml +50 -0
  324. package/recipes/middleware/tests/requests.json +528 -0
  325. package/recipes/middleware/urlcode.yaml +127 -0
  326. package/recipes/protected-download/README.md +22 -0
  327. package/recipes/protected-download/files/report.txt +1 -0
  328. package/recipes/protected-download/recipe.yaml +31 -0
  329. package/recipes/protected-download/tests/requests.json +32 -0
  330. package/recipes/protected-download/urlcode.yaml +15 -0
  331. package/recipes/redirect/README.md +7 -0
  332. package/recipes/redirect/recipe.yaml +25 -0
  333. package/recipes/redirect/tests/requests.json +19 -0
  334. package/recipes/redirect/urlcode.yaml +9 -0
  335. package/recipes/static-plus-api/README.md +15 -0
  336. package/recipes/static-plus-api/functions/info.mjs +3 -0
  337. package/recipes/static-plus-api/public/assets/index.html +3 -0
  338. package/recipes/static-plus-api/public/assets/site.css +1 -0
  339. package/recipes/static-plus-api/public/index.html +8 -0
  340. package/recipes/static-plus-api/recipe.yaml +29 -0
  341. package/recipes/static-plus-api/tests/requests.json +56 -0
  342. package/recipes/static-plus-api/urlcode.yaml +23 -0
  343. package/recipes/typescript/README.md +8 -0
  344. package/recipes/typescript/functions/hello.ts +5 -0
  345. package/recipes/typescript/recipe.yaml +23 -0
  346. package/recipes/typescript/tests/requests.json +18 -0
  347. package/recipes/typescript/urlcode.yaml +5 -0
  348. package/recipes/webhook-receiver/README.md +20 -0
  349. package/recipes/webhook-receiver/functions/receive.mjs +16 -0
  350. package/recipes/webhook-receiver/recipe.yaml +27 -0
  351. package/recipes/webhook-receiver/tests/requests.json +59 -0
  352. package/recipes/webhook-receiver/urlcode.yaml +23 -0
  353. package/schemas/recipe.schema.json +139 -0
  354. package/schemas/urlcode.schema.json +659 -110
  355. package/skills/urlcode/SKILL.md +119 -0
  356. package/starters/default/.github/workflows/urlcode.yml +23 -0
  357. package/starters/default/.mcp.json +12 -0
  358. package/starters/default/AGENTS.md +79 -0
  359. package/starters/default/urlcode.yaml +0 -1
  360. package/dist/link-api.js +0 -136
  361. package/dist/link-cli.js +0 -141
  362. package/dist/link-events.js +0 -76
  363. package/dist/link-records.js +0 -31
  364. package/dist/link-store-worker.js +0 -150
  365. package/dist/link-store.js +0 -250
  366. package/dist/management-policy.js +0 -41
  367. package/dist/sqlite-version.js +0 -6
  368. package/dist/types/link-api.d.ts +0 -30
  369. package/dist/types/link-cli.d.ts +0 -36
  370. package/dist/types/link-events.d.ts +0 -27
  371. package/dist/types/link-records.d.ts +0 -11
  372. package/dist/types/link-store-worker.d.ts +0 -1
  373. package/dist/types/link-store.d.ts +0 -130
  374. package/dist/types/management-policy.d.ts +0 -9
  375. package/dist/types/sqlite-version.d.ts +0 -1
  376. package/docs/DYNAMIC-LINKS.md +0 -561
  377. package/docs/MANAGEMENT-SECURITY.md +0 -82
  378. package/examples/live-links/README.md +0 -11
  379. package/examples/live-links/tests/requests.json +0 -6
  380. package/examples/live-links/urlcode.yaml +0 -16
@@ -1,9 +1,11 @@
1
1
  # DDoS, overload and recovery playbook
2
2
 
3
3
  This is an operator plan for the current self-hosted release, not a claim of built-in DDoS
4
- protection, managed failover or tested high availability. URLCode's sandbox and
5
- resource limits reduce some failure modes; they cannot protect a saturated
6
- network link. Keep the public origin behind your existing protected ingress.
4
+ protection, managed failover or tested high availability. URLCode's resource
5
+ limits — the HTTP admission cap either way, plus the worker pool's own
6
+ deadline/queue-less ceiling for a `sandbox: true` route — reduce some failure
7
+ modes; they cannot protect a saturated network link. Keep the public origin
8
+ behind your existing protected ingress.
7
9
 
8
10
  ## Defense responsibilities
9
11
 
@@ -11,8 +13,8 @@ network link. Keep the public origin behind your existing protected ingress.
11
13
  |---|---|---|
12
14
  | Upstream network | Hosting/CDN DDoS mitigation and an escalation contact; protect bandwidth before it reaches the origin | No network-level mitigation service |
13
15
  | Edge/proxy | TLS, per-client and aggregate request/connection budgets, header/body/time limits; restrict direct origin access | Private bind default; no automatic TLS/WAF. Optional per-instance [`throttle` and `agents` policies](POLICIES.md) as a second layer behind the edge, with `--trusted-proxies` naming the hops allowed to set `X-Forwarded-For` |
14
- | Application | Validate inputs, bound expensive work, authenticate sensitive operations | Strict route/body validation; sandbox deadlines and no execution queue |
15
- | Process/container | CPU/RAM/PID limits, restart backoff, least privilege, read-only reviewed app | Worker isolation, bounded worker replacement, health and request logs |
16
+ | Application | Validate inputs, bound expensive work, authenticate sensitive operations | Strict route/body validation; a `sandbox: true` route gets worker deadlines and no execution queue, a trusted (default) route shares the HTTP admission cap with no worker ceiling |
17
+ | Process/container | CPU/RAM/PID limits, restart backoff, least privilege, read-only reviewed app | Worker isolation for `sandbox: true` routes, bounded worker replacement, health and request logs |
16
18
  | Release/recovery | Known-good artifacts, candidate verification, traffic switching, rollback drills | Local validation/tests/audit; explicit snapshot reload; no orchestration |
17
19
 
18
20
  NGINX provides request-rate controls and connection controls keyed by values such
@@ -30,7 +32,8 @@ forwarded headers to construct its public URL; set `--origin` explicitly.
30
32
 
31
33
  The optional [`throttle` policy](policies/throttle.md) adds a per-client budget
32
34
  inside the runtime, and the [`agents` policy](policies/agents.md) refuses listed
33
- User-Agents before a body is read or the sandbox starts. Both are a second
35
+ User-Agents before a body is read or the function/middleware call starts,
36
+ trusted or sandboxed. Both are a second
34
37
  layer behind the edge, not a replacement for it: counters are per instance,
35
38
  the socket and admission limits still apply first, and a flood still costs
36
39
  connections. The client identity is the socket peer unless
@@ -50,8 +53,8 @@ is not implemented; adding a reverse proxy does not bypass runtime execution.
50
53
  | Failure or traffic pattern | Current consequence | Mitigation / recovery |
51
54
  |---|---|---|
52
55
  | High-rate ordinary requests | Event-loop, logging, bandwidth or socket exhaustion | Filter/rate-limit upstream; scale only within measured resource/cost budgets |
53
- | Flood of functions or middleware | Two default worker slots fill; further calls receive 503 | Bound programmable traffic before the origin; isolate heavy workloads |
54
- | Infinite/slow application code | Shared invocation deadline returns 504; worker terminated/replaced | Identify bad release/route with protected diagnostics; roll back or block route at ingress |
56
+ | Flood of functions or middleware | Two default worker slots fill for `sandbox: true` routes; further calls receive 503. Trusted (default) routes shed load through the in-flight admission cap instead | Bound programmable traffic before the origin; isolate heavy workloads |
57
+ | Infinite/slow application code | Shared invocation deadline returns 504; a `sandbox: true` worker is terminated/replaced, while a trusted route blocking the event loop synchronously cannot be preempted ([capacity](CAPACITY.md)) | Identify bad release/route with protected diagnostics; roll back or block route at ingress |
55
58
  | Guest invalid response or failure | Generic 502 | Compare with last deployment; run fixture on a private candidate |
56
59
  | Repeated worker exits | Replacement backs off (250 ms doubling to 30 s) and keeps retrying; readiness stays 503 until every slot serves | Contain the cause; load is shed meanwhile. Replacement never stops, because a guest deadline is reachable from ordinary request input and must not disable functions until an operator restarts |
57
60
  | Large/slow requests | 64 admitted application requests, body/header limits and receipt timeouts; copies still consume memory | Smaller proxy/body budgets and connection admission limits |
@@ -120,8 +123,8 @@ Choose RTO (acceptable recovery time) and RPO (acceptable data loss) per deploym
120
123
  URLCode does not promise values. A stateless YAML deployment can be recreated
121
124
  from retained immutable artifacts, subject to recovery of DNS/ingress and secret
122
125
  access. Log loss is possible under pressure and has a separate retention target.
123
- Stored live-link records and future app-owned state need their own backups and restore
124
- verification; Git route configuration does not back up runtime data.
126
+ Future app-owned or extension-owned durable state needs its own backups and
127
+ restore verification; Git route configuration does not back up runtime data.
125
128
 
126
129
  A rollback needs the previous app/runtime and its matching policy and compatible
127
130
  secret bindings. The health version combines configuration and asset digests;
@@ -153,8 +156,6 @@ admission/fairness, production metrics/exporters, dedicated slow-reader protecti
153
156
  provider-level mitigation validation and sustained failure/soak testing. These are
154
157
  free-runtime/operator requirements.
155
158
 
156
- For optional live links, protect the separate management listener and token, bound
157
- its traffic, and back up the SQLite store with the documented closed-store or
158
- SQLite-aware procedure. Store worker failure returns 503; stop the cause before
159
- reloading/restarting. An uncertain mutation may have committed. See
160
- [dynamic-link recovery](DYNAMIC-LINKS.md).
159
+ Core has no durable store of its own to recover; a future durable-state
160
+ extension (such as the planned `urlcode-dynamic-link`) is responsible for its
161
+ own management listener, backup and recovery procedure once it exists.
package/docs/ROUTING.md CHANGED
@@ -1,4 +1,4 @@
1
- # Route matching and new links
1
+ # Route matching
2
2
 
3
3
  ## Supported path patterns
4
4
 
@@ -49,7 +49,7 @@ route returning 405, 404, 410 or 400 does not fall through to another route.
49
49
  Likewise, a missing file in the longest selected static mount does not fall back
50
50
  to a shorter mount. See [HTTP](HTTP.md) and [the contract](SPECIFICATION.md).
51
51
 
52
- ## Adding a configured link today
52
+ ## Adding a configured redirect today
53
53
 
54
54
  ```sh
55
55
  urlcode add https://example.com/new-page --alias new-link --project ./my-links
@@ -83,13 +83,11 @@ and needs no route rebuild or service restart. The same distinction applies to
83
83
  any per-visitor session record. Git owns route behavior and code; user-created records have
84
84
  their own persistence, backup and export lifecycle.
85
85
 
86
- This is now implemented for short-link redirects through the optional `link`
87
- handler, local SQLite storage, CLI and a separate authenticated management API.
88
- See [dynamic links](DYNAMIC-LINKS.md) for complete YAML, setup, consistency and
89
- backup details. No route reload is needed for committed record changes.
86
+ Core has no native handler for this today: the `link` handler that implemented
87
+ it was removed. Stored short links are moving to a future
88
+ `urlcode-dynamic-link` extension package (mount-based, like `auth`/`admin`,
89
+ not yet published); a project needing them declares an `extension` mount once
90
+ that package exists.
90
91
 
91
92
  Functions still cannot access databases, the filesystem or network directly.
92
- The native link handler performs the bounded lookup, and middleware can wrap a
93
- successful redirect. General application state and realtime sessions remain
94
- future work. SQLite is optional and supports local same-host processes; a
95
- multi-host deployment needs a different adapter. A cache is not the durable store.
93
+ General application state and realtime sessions remain future work.
@@ -1,9 +1,19 @@
1
1
  # Independent sandbox review gate
2
2
 
3
+ Scope: this gate is about the `sandbox: true` execution path only —
4
+ `function`/`middleware` routes run trusted and unsandboxed by default
5
+ (docs/SPIKE-DEFAULT-TRUST-MODEL.md), and a trusted route's full Node access is
6
+ by design, not a gap this review closes. Nothing here claims to review
7
+ arbitrary trusted project code; that trust is the project's own call, made
8
+ per route.
9
+
3
10
  Status: **external assessment not performed**. Internal source review, CI, CodeQL
4
11
  and adversarial regressions are useful evidence, not an independent sign-off.
5
- Do not host anonymous hostile multi-tenant code before this gate is closed.
6
- No unrestricted Node execution fallback is permitted.
12
+ Do not host anonymous hostile multi-tenant code in a `sandbox: true` route
13
+ before this gate is closed, and do not run untrusted/unreviewed code in a
14
+ trusted (non-`sandbox`) route at all — that path was never sandboxed and this
15
+ gate does not apply to it. No unrestricted Node execution fallback is
16
+ permitted *within a route that declared `sandbox: true`*.
7
17
 
8
18
  ## Review package
9
19
 
@@ -15,14 +25,17 @@ resource settings. Give a reviewer independent of the implementation access to:
15
25
  module graph, import denial, export validation, binding grants and message bridge.
16
26
  - `src/config.ts`, `src/config-worker.ts`, router and assets: parser/schema limits,
17
27
  file containment, activation, memory amplification and host-side compilation.
18
- - HTTP server, management API/policy and link-store worker: request smuggling,
19
- admission, body/response framing, authorization, revocation and atomic audit.
20
- - `test/sandbox.test.ts`, middleware/config/links/logging/reload tests, Dockerfile,
28
+ - HTTP server and policy: request smuggling, admission, body/response framing.
29
+ - `test/sandbox.test.ts`, middleware/config/logging/reload tests, Dockerfile,
21
30
  protected workflows and `docs/FUNCTION-SECURITY.md`.
31
+ - `src/runtime.ts`'s dispatch decision (`route.sandbox ? pool : trusted`) and
32
+ `src/trusted-functions.ts`: confirm a route that declares `sandbox: true`
33
+ can never be dispatched through the trusted, in-process path by any code
34
+ path, and that `sandbox: false`/absent never reaches `FunctionPool`.
22
35
 
23
36
  Run `npm ci --ignore-scripts`, `npm run verify`, `npm run test:package`, and
24
37
  `node scripts/operational-drills.ts`. Record the exact commands and result files.
25
- CI adds constrained-container and real disposable-volume exhaustion tests.
38
+ CI adds a constrained-container test.
26
39
  Use only disposable local/staging systems with synthetic data.
27
40
 
28
41
  ## Threat model and required probes
@@ -68,5 +68,3 @@ Scaffolding does not recursively invent dependencies imported by existing code,
68
68
  crawl HTML/CSS links, generate binary content, or implement your business logic.
69
69
  See [readiness checks](READINESS.md) and [asset behavior](ASSETS.md).
70
70
 
71
- Scaffolding enforces the entry-level `dynamicLinks` opt-in for `link` handlers
72
- and reports the effective boolean. It never enables this capability for you.
@@ -1,3 +1,38 @@
1
+ # Security review — 2026-09-18
2
+
3
+ Scope: trust-model change (docs/SPIKE-DEFAULT-TRUST-MODEL.md). `function`/
4
+ `middleware` routes now run trusted and unsandboxed by default, with
5
+ `sandbox: true` as an explicit per-route opt-in to the isolation this document's
6
+ earlier entries describe. This is a maintainer-decided policy reversal, not a
7
+ finding; it is recorded here because it changes what every earlier entry's
8
+ "guest"/"sandbox" language means going forward.
9
+
10
+ **What did not change:** the `sandbox: true` execution path — QuickJS/WASM
11
+ isolation, module-graph restriction, fresh heap per call, worker deadline —
12
+ is byte-for-byte the same as every earlier entry describes; nothing in this
13
+ change touched `src/functions.ts`, `src/function-worker.ts` or `src/guest-api.ts`.
14
+ Binding grants are unaffected either way: `env`/`secrets` still reach only a
15
+ route that explicitly declared them and an operator policy pinned to the
16
+ project revision explicitly granted, whether that route is trusted or
17
+ sandboxed.
18
+
19
+ **What did change, and the resulting residual risk:** a `function`/
20
+ `middleware` route with no `sandbox` field (the common case going forward, and
21
+ every existing project's routes after an upgrade with no YAML change) now runs
22
+ in the host process with full Node access — the isolation earlier entries'
23
+ "remaining gaps" language assumed for *all* guest code no longer applies to
24
+ it. The residual-risk framing in earlier entries ("before exposing hostile
25
+ multi-tenant workloads, obtain independent review of WASM/host boundaries")
26
+ is scoped to `sandbox: true` routes specifically; it was never a claim that
27
+ covered a route that opts out of the sandbox, and after this change most
28
+ routes do exactly that by default. Whether a given project's own function/
29
+ middleware code is safe to trust with full host access is now the project's
30
+ judgment call, not something this runtime's isolation reviews (past or
31
+ future) can speak to. New source review of the dispatch decision itself
32
+ (`src/runtime.ts`, `src/trusted-functions.ts`, `src/policy.ts`'s split
33
+ grant-hashing) accompanies the change; see the pull request that introduced
34
+ `sandbox` for its own description of what was and was not verified.
35
+
1
36
  # Security review — 2026-09-17
2
37
 
3
38
  Scope: follow-up source review of worker/connection replacement, probe admission,
@@ -5,6 +40,11 @@ request correlation, operational logging, dependency/release supply chain and th
5
40
  live-link Node requirement. Regression tests accompany the fixes. Internal review,
6
41
  not an independent penetration test.
7
42
 
43
+ This is a dated record, not current guidance. The `link` handler, its SQLite
44
+ store and the link-store/management findings below were removed from core in
45
+ a later change; they describe the runtime as it existed on this date, not the
46
+ current one.
47
+
8
48
  ## Findings fixed in this revision
9
49
 
10
50
  | Finding | Impact and evidence | Fix / regression |
@@ -100,7 +140,7 @@ repository-governance follow-up pins them and enables dependency maintenance,
100
140
  secret protection, CodeQL and private reporting; see [governance](../GOVERNANCE.md).
101
141
  CI now also gates runtime advisories with `npm audit --omit=dev`. A manual main-only
102
142
  signed candidate/SBOM workflow is now defined; see
103
- [release security](RELEASE-SECURITY.md). It does not publish to registries. The 0.1.0 release is licensed under
143
+ [release security](RELEASE-SECURITY.md). A tagged release publishes to npm with provenance. The 0.1.0 release is licensed under
104
144
  Apache-2.0; the license does not close the independent-review gates.
105
145
 
106
146
  **Application responsibility:** HTML/JS assets are active browser content; choose
@@ -1,8 +1,9 @@
1
- # Implemented 0.1 contract
1
+ # Implemented project contract
2
2
 
3
3
  This document and [JSON Schema](../schemas/urlcode.schema.json) describe
4
- 0.2.0. `version: "1"` is the stable project-format contract for the 0.1 release
5
- line. Later planned features are rejected until implemented.
4
+ the source contract, including unreleased additions after 0.3.0.
5
+ `version: "1"` remains the project-format contract. Unsupported fields
6
+ are rejected rather than interpreted as future behavior.
6
7
 
7
8
  ## Files and validation
8
9
 
@@ -29,12 +30,12 @@ deadline; individual synchronous operations are not preempted. At most 1,000 par
29
30
  Keys are absolute case-sensitive paths. Trailing slashes are significant.
30
31
  Parameters occupy whole segments, e.g. `/p/{id}`, with distinct identifier names.
31
32
  Each parameter matches exactly one nonempty segment, never across `/`; it is not
32
- greedy. No regex paths, host matching or dot segments. Only static directory mounts
33
+ greedy. No regex paths, client-controlled host dispatch or dot segments. Only static directory mounts
33
34
  support a terminal `/*` wildcard with an otherwise literal path. Route keys cannot contain
34
35
  percent encoding, spaces, backslashes or query strings. Path length is limited
35
36
  to 2,048 characters and 32 segments. `/_urlcode` is reserved.
36
37
 
37
- One handler per route: `function`, `redirect`, `page`, `static`, `download`, `respond` or `link`.
38
+ One handler per route: `function`, `redirect`, `page`, `static`, `download`, `respond`, `conditional`, `proxy` or an `extension` mount.
38
39
  See [asset configuration](ASSETS.md) for file handlers. Optional properties:
39
40
 
40
41
  - `methods`: unique HTTP methods; default GET and HEAD. Explicit lists are exact;
@@ -55,8 +56,8 @@ Requests decode the path once; invalid UTF-8/percent encoding, encoded slashes o
55
56
  backslashes, control characters and dot segments return 400. Query values decode
56
57
  once. Incoming query data is not automatically forwarded.
57
58
 
58
- See [route matching and new links](ROUTING.md) for examples, precedence, wildcard
59
- limits, reload behavior and the distinction between YAML routes and live link data.
59
+ See [route matching](ROUTING.md) for examples, precedence, wildcard
60
+ limits and reload behavior.
60
61
 
61
62
  The optional top-level `site` block (entry file only) generates native routes
62
63
  for site conventions: `robots` → `/robots.txt`, `sitemap` → `/sitemap.xml`,
@@ -67,6 +68,37 @@ path wins and the generated one is logged as shadowed. Absolute URLs come from
67
68
  the operator's `--origin`; `sitemap` refuses activation without one. See
68
69
  [site conventions](SITE.md).
69
70
 
71
+ ## Exact conditions and duplicate-path alternatives
72
+
73
+ Optional route `match` conjunctively compares exact query/header/cookie strings,
74
+ an uppercase method and the canonical authority of the operator-configured
75
+ public origin. Host/forwarded headers never select the trusted host. A guard
76
+ mismatch returns 404 without trying a less-specific path; route method admission
77
+ still applies after the guard. Conditions are not authentication or authorization.
78
+
79
+ The `conditional` handler puts alternatives under one existing route key:
80
+ `cases` contains 1–16 `{match, redirect}` or `{match, respond}` entries; optional
81
+ `fallback` contains exactly one redirect/respond handler. Duplicate YAML paths
82
+ remain invalid. Cases must be provably disjoint: each pair needs a shared
83
+ predicate with different required values. Cases run before fallback; no matching
84
+ case and no fallback returns 404. Nested cases and branch-local bindings,
85
+ middleware or policy are unsupported. Shared inputs, methods, headers,
86
+ middleware and policies stay at route level.
87
+
88
+ Each query/header/cookie map has 1–16 comparisons; names have at most 128
89
+ characters and values 1,024. Query comparisons use decoded raw strings without
90
+ parameter defaults/coercion. Cookies use unquoted wire values and an 8 KiB input
91
+ limit. Missing and empty are different. Duplicate examined scalar inputs return
92
+ 400 when the transport exposes their counts. Header names normalize to lowercase;
93
+ authentication and transport headers cannot be predicates. No regex, geo/device
94
+ inference, wildcard or arbitrary-code conditions are supported.
95
+
96
+ Conditional routing requires cache disabled or no-store and forces downstream
97
+ no-store responses. Explicit fixtures are required for branch coverage.
98
+ Self-hosted, AWS and Vercel use the shared matcher; Cloudflare refuses conditions
99
+ until its artifact compiler supports them. See [conditions](CONDITIONS.md) and
100
+ the [executable example](../examples/conditions).
101
+
70
102
  ## HTTP request/response configuration
71
103
 
72
104
  Routes accept `request.body` validation and `response.headers` overrides. The
@@ -125,15 +157,11 @@ keys preserve repeated values. Headers are forwarded only through explicit maps.
125
157
 
126
158
  ## Stored links
127
159
 
128
- The entry `urlcode.yaml` must opt in with `dynamicLinks: true` (default false).
129
- Included files cannot set this project-level flag. Parameterized redirects and
130
- functions do not require it.
131
-
132
- `link: {collection: links, code: {from: path, name: code}}` resolves a declared
133
- path input against an operator-bound store. GET/HEAD only. The logical collection
134
- is portable; file paths and store credentials are external deployment bindings.
135
- No general storage capability is exposed to guest code. See [dynamic links](DYNAMIC-LINKS.md)
136
- for validation, persistence, mutation, expiry and read-after-write behavior.
160
+ Core has no native `link` handler or `dynamicLinks` project flag; both were
161
+ removed. Stored short links are moving to a future `urlcode-dynamic-link`
162
+ extension package (mount-based, like `auth`/`admin`), not yet published. A
163
+ project needing them declares an `extension` mount once that package exists;
164
+ there is no in-core replacement or deprecation shim for `link`/`dynamicLinks`.
137
165
 
138
166
  ## Functions
139
167
 
@@ -161,9 +189,52 @@ export default function hello(request, { args, env }) {
161
189
  }
162
190
  ```
163
191
 
192
+ `function` also accepts a string: `function: functions/hello.mjs`. Document
193
+ validation normalizes it to the long form above before routing, auditing,
194
+ explaining or hashing the project: `source` is the string, `args` maps every
195
+ `{param}` segment of the path to `{from: path, name: param}`, and each such
196
+ parameter the route does not already declare under `parameters` (by name, with
197
+ `in: path`) is appended as `{in: path, required: true, schema: {type: string,
198
+ minLength: 1, maxLength: 128}}`. Declared parameters keep their own schema and
199
+ order. The string must be a project-relative `.mjs` or `.js` path without `..`
200
+ segments; anything else is refused with the route path named. A `middleware`
201
+ entry may likewise be a string, normalized to `{source: <string>}`. Only the
202
+ long form exists after loading, so `routes`, `audit`, `explain`, revision hashes
203
+ and the field reference describe the expansion.
204
+
164
205
  ES modules only (`.mjs` or `.js`, independent of Node package settings).
165
- TypeScript is not included. `export` defaults to `default`. Functions execute
166
- inside QuickJS/WASM, never through Node imports. Only relative `.js`/`.mjs`
206
+ [Build-time TypeScript authoring](TYPESCRIPT-AUTHORING.md) can produce these
207
+ JavaScript modules in a separate output project; serving does not transpile them.
208
+ The build never imports application code into Node, uses fixed compiler settings,
209
+ and does not perform semantic type checking. Grants must target the built
210
+ configuration/source revision. `export` defaults to `default`.
211
+
212
+ ### Trust: unsandboxed by default, `sandbox: true` opt-in
213
+
214
+ A route's `function`/`middleware` chain runs one of two ways, chosen by the
215
+ route's `sandbox` field (false or absent — the default — versus `true`; see
216
+ [docs/SPIKE-DEFAULT-TRUST-MODEL.md](SPIKE-DEFAULT-TRUST-MODEL.md)):
217
+
218
+ - **`sandbox` false/absent (trusted, the default):** the module is imported
219
+ directly into the host process with ordinary Node module resolution — bare
220
+ specifiers, `node:` builtins, npm packages and dynamic `import()` all work,
221
+ none of the module-graph/source-size limits below apply, and there is no
222
+ fresh-heap-per-call reset (module-level state persists across requests like
223
+ any other Node server). The handler/middleware signature and `context`
224
+ shape are unchanged from the sandboxed contract below; a trusted function
225
+ additionally has the full Fetch API, Node built-ins and the filesystem
226
+ available to it, not just the guest text/JSON subset. `args`/`env`/
227
+ `secrets` are exactly what the route declares and an operator grants,
228
+ identically to the sandboxed path.
229
+ - **`sandbox: true`:** the rest of this section, unchanged from every earlier
230
+ release. A sandboxed route's functions and middleware execute inside
231
+ QuickJS/WASM, never through Node imports.
232
+
233
+ The remainder of this section (module restrictions, the guest API subset,
234
+ guest limits and deadlines) describes the `sandbox: true` path specifically,
235
+ unless stated otherwise.
236
+
237
+ Only relative `.js`/`.mjs`
167
238
  project imports are supported, with a snapshotted dependency graph. No bare/npm,
168
239
  Node built-in, remote, dynamic source imports or `import.meta`. Runtime-created
169
240
  imports remain restricted to the route's middleware and handler dependency graphs; there is no fallback.
@@ -176,7 +247,8 @@ delete/get/has/entries/getSetCookie; Response constructor with string/null body,
176
247
  Requests decode body bytes as UTF-8. Binary/streaming bodies, URL helpers,
177
248
  fetch/WebSocket, crypto and filesystem are not exposed. Promise/async and
178
249
  bounded timers (128 pending per invocation) work inside the guest. Unsupported
179
- APIs fail; they never execute on the host. Do not claim full browser/Node API parity.
250
+ APIs fail; they never execute on the host. Do not claim full browser/Node API
251
+ parity for a `sandbox: true` route; a trusted route has no such restriction.
180
252
 
181
253
  Context contains `inputs.path/query/header`, `args`, `env`, `secrets`. Arguments
182
254
  may be scalar literals, input references, `{env: alias}` or `{secret: alias}`.
@@ -192,12 +264,17 @@ Dotenv supports single-line NAME=value, paired single/double quotes, blank lines
192
264
  and full-line comments, without expansion/escapes/shell execution. Loading a
193
265
  value does not authorize exposing it to a function; the policy still applies.
194
266
 
195
- Every invocation has a fresh guest heap and module state. No cross-request
196
- counters, cached secrets or prototype mutation. QuickJS heap limit is 32 MiB,
197
- stack limit 512 KiB; outer worker and deployment limits are additional defenses,
198
- not a claim that total process RSS is capped at 32 MiB. Two workers, no queue;
199
- saturation returns 503. The independent 5-second deadline terminates a worker
200
- and returns 504. Generic failures return 502; worker replacement is bounded.
267
+ A `sandbox: true` invocation has a fresh guest heap and module state every
268
+ time. No cross-request counters, cached secrets or prototype mutation. QuickJS
269
+ heap limit is 32 MiB, stack limit 512 KiB; outer worker and deployment limits
270
+ are additional defenses, not a claim that total process RSS is capped at 32
271
+ MiB. Two workers, no queue; saturation returns 503. The independent 5-second
272
+ deadline terminates a worker and returns 504. Generic failures return 502;
273
+ worker replacement is bounded. A trusted route has none of this: no fresh
274
+ heap/module reset, no fixed worker-pool ceiling (bounded instead by ordinary
275
+ Node concurrency and the HTTP admission cap), and its deadline races the
276
+ call's promise rather than force-terminating a worker — see
277
+ [capacity](CAPACITY.md) for both models side by side.
201
278
 
202
279
  HEAD invokes the handler as HEAD and suppresses body output. Code must guard
203
280
  its own application side effects when future brokered integrations are enabled.
@@ -206,11 +283,18 @@ not arbitrary Host/forwarded headers. Request/response bodies default to 1 MiB;
206
283
  response headers 16 KiB, maximum 256 pairs. Hop-by-hop headers are stripped;
207
284
  cookies are preserved individually. Default response cache policy is `no-store`.
208
285
 
209
- No unrestricted host execution option exists. Network integrations and persistent
210
- state need future explicit, tested capability brokers. Approved secrets can be
211
- returned by code that receives them; isolation does not automatically enforce
286
+ A trusted (non-`sandbox`) route already has unrestricted host execution by
287
+ design — that is the point of the default described above. For a `sandbox:
288
+ true` route, there is no unrestricted host-execution fallback: declarative
289
+ proxy and webhook signals use the separately granted host broker described in
290
+ [egress](EGRESS.md), and that route's guests still have no fetch API or
291
+ general persistent state capability. Approved secrets can be returned by code
292
+ that receives them, in either mode; isolation does not automatically enforce
212
293
  information-flow rules on authorized inputs. Keep grants narrow and review the
213
- exact pinned revision. The sandbox still needs independent security review before hostile multi-tenant use.
294
+ exact pinned revision. The `sandbox: true` path still needs independent
295
+ security review before hostile multi-tenant use of that specific mode; that
296
+ review's scope was never a claim about a route that opts out of the sandbox
297
+ (see [docs/SANDBOX-REVIEW.md](SANDBOX-REVIEW.md)).
214
298
 
215
299
  ## Reload and status
216
300
 
@@ -230,3 +314,40 @@ The health `version` combines route-definition and asset-representation digests,
230
314
  not a full artifact digest
231
315
  or secret fingerprint. Production release identity should be the Git commit and
232
316
  container image digest. See [operations](OPERATIONS.md).
317
+
318
+ See [capabilities and normalized route representation](CAPABILITIES.md) for the target catalog,
319
+ programmatic compatibility analysis and provider verification limits.
320
+
321
+ ## Authoring, conversion and verification tools
322
+
323
+ [Interchange](INTERCHANGE.md) imports and exports a strict literal redirect
324
+ subset with source diagnostics and dry-run reports. Provider conversions refuse
325
+ semantic differences by default; explicit acknowledgment retains warnings and
326
+ never reports lossless behavior. [Bulk import](BULK.md) shards CSV/JSON/YAML rows
327
+ into ordinary includes while retaining runtime resource limits. [Recipes](RECIPES.md)
328
+ are local Git-owned examples; they grant no capabilities. [Build-time TypeScript](TYPESCRIPT-AUTHORING.md)
329
+ is separate from runtime execution.
330
+
331
+ The [tooling SDK and optional local MCP](TOOLING.md) inspect and validate without
332
+ executing handlers or reading binding values. [Provider conformance](PROVIDER-VERIFICATION.md)
333
+ distinguishes local adapter replay from actual deployment observations; no real
334
+ provider deployment is implied by CI. [Proxy and signal egress](EGRESS.md) requires
335
+ external revision-pinned operator grants and bounded host-owned transport;
336
+ project declarations cannot grant network authority to themselves or guests.
337
+
338
+ ## Bounded outbound behavior
339
+
340
+ The proxy handler and webhook signals require external revision-pinned origin
341
+ grants. [Egress](EGRESS.md) specifies request and response semantics, DNS pinning,
342
+ header filtering, size/time/concurrency limits, secret binding, signal guarantees
343
+ and shutdown. Project declarations cannot grant network authority to themselves.
344
+ All non-self-hosted targets refuse these capabilities.
345
+
346
+ ## Operator-installed extension handlers
347
+
348
+ The optional `extensions` map declares version-1 extension configuration.
349
+ `extension: name` handlers require exclusive literal `/prefix/*` mounts and
350
+ explicit operator registration pinned to the project revision. Optional
351
+ `policies.extensions` requirements are validated by the named extension and
352
+ authorized before cache access. See [extension contracts](EXTENSIONS.md) for
353
+ configuration, trust boundaries, lifecycle and target restrictions.