@jimhoyd/urlcode 0.4.0-alpha.1 → 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 (191) hide show
  1. package/.claude/skills/urlcode-authoring/SKILL.md +24 -8
  2. package/.claude/skills/urlcode-operations/SKILL.md +10 -16
  3. package/.claude-plugin/marketplace.json +1 -1
  4. package/README.md +75 -62
  5. package/ROADMAP.md +61 -16
  6. package/SECURITY.md +23 -8
  7. package/dist/BUILD-MANIFEST.json +38 -43
  8. package/dist/agents-guide.js +18 -18
  9. package/dist/build-static.js +134 -0
  10. package/dist/capabilities.js +85 -31
  11. package/dist/capability-query.js +0 -1
  12. package/dist/cli.js +23 -31
  13. package/dist/compliance-rules/baseline.js +2 -10
  14. package/dist/compliance-rules/privacy.js +5 -16
  15. package/dist/compliance-rules/shared.js +0 -2
  16. package/dist/compliance.js +6 -8
  17. package/dist/config.js +15 -8
  18. package/dist/context.js +9 -10
  19. package/dist/examples.js +2 -2
  20. package/dist/explain-cli.js +3 -3
  21. package/dist/explain.js +5 -6
  22. package/dist/extensions.js +61 -2
  23. package/dist/function-sources.js +34 -2
  24. package/dist/function-worker.js +3 -1
  25. package/dist/functions.js +84 -13
  26. package/dist/guest-api.js +29 -3
  27. package/dist/index.js +3 -6
  28. package/dist/manifest.js +5 -7
  29. package/dist/mcp.js +1 -1
  30. package/dist/observability.js +1 -21
  31. package/dist/policies/cache.js +8 -3
  32. package/dist/policy.js +28 -9
  33. package/dist/project-tests.js +3 -3
  34. package/dist/readiness.js +32 -9
  35. package/dist/router.js +5 -7
  36. package/dist/runtime.js +77 -58
  37. package/dist/sandbox.js +48 -0
  38. package/dist/scaffold.js +0 -0
  39. package/dist/scripts/operational-drills.js +12 -54
  40. package/dist/server.js +3 -29
  41. package/dist/tooling.js +1 -1
  42. package/dist/trusted-functions.js +210 -0
  43. package/dist/types/build-static.d.ts +43 -0
  44. package/dist/types/capabilities.d.ts +14 -5
  45. package/dist/types/compliance-rules/shared.d.ts +0 -2
  46. package/dist/types/compliance.d.ts +0 -3
  47. package/dist/types/config.d.ts +2 -1
  48. package/dist/types/context.d.ts +2 -1
  49. package/dist/types/examples.d.ts +1 -1
  50. package/dist/types/extensions.d.ts +55 -0
  51. package/dist/types/function-sources.d.ts +4 -0
  52. package/dist/types/functions.d.ts +48 -5
  53. package/dist/types/guest-api.d.ts +1 -0
  54. package/dist/types/index.d.ts +3 -6
  55. package/dist/types/manifest.d.ts +1 -3
  56. package/dist/types/observability.d.ts +1 -14
  57. package/dist/types/project-tests.d.ts +1 -2
  58. package/dist/types/readiness.d.ts +10 -3
  59. package/dist/types/router.d.ts +2 -1
  60. package/dist/types/runtime.d.ts +0 -27
  61. package/dist/types/sandbox.d.ts +12 -0
  62. package/dist/types/scaffold.d.ts +0 -2
  63. package/dist/types/server.d.ts +1 -4
  64. package/dist/types/tooling.d.ts +3 -3
  65. package/dist/types/trusted-functions.d.ts +29 -0
  66. package/dist/types/types.d.ts +14 -7
  67. package/dist/types/verify-deployment.d.ts +2 -2
  68. package/dist/types.js +17 -4
  69. package/dist/typescript-authoring.js +55 -17
  70. package/dist/verify-deployment.js +3 -3
  71. package/docs/AI-AUTHORING.md +104 -9
  72. package/docs/AWS.md +4 -4
  73. package/docs/BEST-PRACTICES.md +3 -2
  74. package/docs/CAPABILITIES.md +29 -16
  75. package/docs/CAPACITY.md +128 -31
  76. package/docs/CLOUDFLARE.md +1 -2
  77. package/docs/COMPLIANCE.md +6 -9
  78. package/docs/DEPLOYMENT-CHECKS.md +1 -1
  79. package/docs/EXTENSIONS.md +183 -11
  80. package/docs/FRAMEWORK.md +35 -19
  81. package/docs/FUNCTION-SECURITY.md +129 -32
  82. package/docs/INSTALL.md +0 -5
  83. package/docs/LOAD-TESTING.md +4 -4
  84. package/docs/MIDDLEWARE.md +27 -16
  85. package/docs/MONITORING.md +2 -19
  86. package/docs/NEXT-PHASE-PLAN.md +12 -4
  87. package/docs/NEXT-STEPS.md +259 -40
  88. package/docs/OBSERVABILITY.md +7 -16
  89. package/docs/OPEN-DECISIONS.md +212 -0
  90. package/docs/OPERATIONAL-PROOF.md +26 -30
  91. package/docs/OPERATIONS.md +23 -32
  92. package/docs/POLICIES.md +15 -4
  93. package/docs/PRERENDER.md +2 -2
  94. package/docs/PROJECT-DIRECTION.md +34 -9
  95. package/docs/README.md +13 -11
  96. package/docs/RELEASE-READINESS.md +49 -29
  97. package/docs/RELEASE-SECURITY.md +89 -3
  98. package/docs/RESILIENCE.md +16 -15
  99. package/docs/ROUTING.md +8 -10
  100. package/docs/SANDBOX-REVIEW.md +19 -6
  101. package/docs/SCAFFOLDING.md +0 -2
  102. package/docs/SECURITY-AUDIT.md +40 -0
  103. package/docs/SPECIFICATION.md +60 -26
  104. package/docs/SPIKE-AI-FRAMEWORK-BENCHMARK.md +287 -0
  105. package/docs/SPIKE-BUSINESS-SUITE.md +8 -0
  106. package/docs/SPIKE-CORE-LAYERING.md +337 -0
  107. package/docs/SPIKE-DEFAULT-TRUST-MODEL.md +209 -0
  108. package/docs/SPIKE-EXTENSION-MODEL.md +2 -2
  109. package/docs/SPIKE-EXTENSIONS.md +5 -0
  110. package/docs/SPIKE-LAMBDA-COMPILE.md +4 -2
  111. package/docs/SPIKE-MONOREPO.md +322 -0
  112. package/docs/STARTERS.md +1 -1
  113. package/docs/STATIC.md +94 -0
  114. package/docs/TOOLING.md +13 -9
  115. package/docs/TUNNELS.md +0 -3
  116. package/docs/TYPESCRIPT-AUTHORING.md +27 -12
  117. package/docs/TYPESCRIPT.md +25 -4
  118. package/docs/USABILITY-REVIEW.md +7 -1
  119. package/docs/VERCEL.md +4 -5
  120. package/docs/VERSION-ALIGNMENT.md +205 -0
  121. package/docs/YAML-GUIDE.md +0 -3
  122. package/docs/YAML-REFERENCE.md +16 -6
  123. package/docs/policies/cache.md +13 -0
  124. package/examples/assets/example.yaml +1 -1
  125. package/examples/aws/example.yaml +1 -1
  126. package/examples/cloudflare/example.yaml +1 -1
  127. package/examples/conditions/example.yaml +1 -1
  128. package/examples/cookbook/example.yaml +1 -1
  129. package/examples/cookbook/middleware/bucket.mjs +12 -2
  130. package/examples/cookbook/middleware/locale.mjs +7 -3
  131. package/examples/egress/example.yaml +1 -1
  132. package/examples/extensions/example.yaml +1 -1
  133. package/examples/prerender/README.md +2 -2
  134. package/examples/prerender/example.yaml +1 -1
  135. package/examples/provider-conformance/example.yaml +1 -1
  136. package/examples/vercel/example.yaml +1 -1
  137. package/llms-full.txt +594 -219
  138. package/llms.txt +23 -12
  139. package/package.json +10 -3
  140. package/packaging/claude-plugin/.claude-plugin/plugin.json +1 -1
  141. package/packaging/claude-plugin/skills/urlcode-authoring/SKILL.md +24 -8
  142. package/packaging/claude-plugin/skills/urlcode-operations/SKILL.md +10 -16
  143. package/recipes/authenticated-json-api/recipe.yaml +1 -1
  144. package/recipes/contact-form/recipe.yaml +1 -1
  145. package/recipes/cors-api/recipe.yaml +1 -1
  146. package/recipes/health-page/recipe.yaml +1 -1
  147. package/recipes/json-api/recipe.yaml +1 -1
  148. package/recipes/middleware/middleware/bucket.mjs +12 -2
  149. package/recipes/middleware/middleware/locale.mjs +7 -3
  150. package/recipes/middleware/recipe.yaml +1 -1
  151. package/recipes/protected-download/recipe.yaml +1 -1
  152. package/recipes/redirect/recipe.yaml +1 -1
  153. package/recipes/static-plus-api/recipe.yaml +1 -1
  154. package/recipes/typescript/README.md +2 -1
  155. package/recipes/typescript/recipe.yaml +1 -1
  156. package/recipes/webhook-receiver/README.md +5 -1
  157. package/recipes/webhook-receiver/recipe.yaml +2 -1
  158. package/recipes/webhook-receiver/urlcode.yaml +7 -0
  159. package/schemas/recipe.schema.json +4 -3
  160. package/schemas/urlcode.schema.json +14 -41
  161. package/skills/urlcode/SKILL.md +29 -8
  162. package/starters/default/AGENTS.md +18 -18
  163. package/starters/default/urlcode.yaml +0 -1
  164. package/dist/link-api.js +0 -136
  165. package/dist/link-cli.js +0 -141
  166. package/dist/link-events.js +0 -76
  167. package/dist/link-records.js +0 -31
  168. package/dist/link-store-worker.js +0 -150
  169. package/dist/link-store.js +0 -250
  170. package/dist/management-policy.js +0 -40
  171. package/dist/sqlite-version.js +0 -6
  172. package/dist/types/link-api.d.ts +0 -30
  173. package/dist/types/link-cli.d.ts +0 -37
  174. package/dist/types/link-events.d.ts +0 -27
  175. package/dist/types/link-records.d.ts +0 -11
  176. package/dist/types/link-store-worker.d.ts +0 -1
  177. package/dist/types/link-store.d.ts +0 -130
  178. package/dist/types/management-policy.d.ts +0 -8
  179. package/dist/types/sqlite-version.d.ts +0 -1
  180. package/docs/DYNAMIC-LINKS.md +0 -61
  181. package/docs/MANAGEMENT-SECURITY.md +0 -82
  182. package/docs/links/cli.md +0 -110
  183. package/docs/links/limits.md +0 -175
  184. package/docs/links/management-api.md +0 -80
  185. package/docs/links/pools.md +0 -75
  186. package/docs/links/setup.md +0 -135
  187. package/docs/yaml/links.md +0 -30
  188. package/examples/live-links/README.md +0 -11
  189. package/examples/live-links/example.yaml +0 -21
  190. package/examples/live-links/tests/requests.json +0 -6
  191. package/examples/live-links/urlcode.yaml +0 -16
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: urlcode-authoring
3
- description: Author or modify a URLCode project — write and edit urlcode.yaml routes, function and middleware modules, pages, static assets, downloads and stored links, then validate and test them. Use whenever a urlcode.yaml file is present or referenced, when the user mentions URLCode, @jimhoyd/urlcode, urlcode routes/handlers/policies/site keys, or asks for redirects, short links or request functions in a URLCode project. Loads the implemented capability matrix so unsupported features are reported as gaps instead of invented.
3
+ description: Author or modify a URLCode project — write and edit urlcode.yaml routes, function and middleware modules, pages, static assets and downloads, then validate and test them. Use whenever a urlcode.yaml file is present or referenced, when the user mentions URLCode, @jimhoyd/urlcode, urlcode routes/handlers/policies/site keys, or asks for redirects or request functions in a URLCode project. Loads the implemented capability matrix so unsupported features are reported as gaps instead of invented.
4
4
  ---
5
5
 
6
6
  # Authoring URLCode projects
@@ -11,6 +11,15 @@ validates. Features outside that contract do not silently degrade — they fail
11
11
  validation. So the cost of guessing is a broken project, and the whole job here
12
12
  is to author only what the pinned revision implements and then prove it.
13
13
 
14
+ ## Declarative-first default
15
+
16
+ > Use URLCode's highest-level declarative features whenever possible. Generate custom code only when the framework cannot express the requirement.
17
+
18
+ Check the installed version's primitives, YAML configuration, policies, supported
19
+ extensions and recipes/templates before writing a custom function or middleware.
20
+ Keep necessary custom code focused and report the capability gap; never invent
21
+ fields or bypass target limits or operator grants. See `docs/PROJECT-DIRECTION.md` in the installed runtime.
22
+
14
23
  ## Read the contract before writing YAML
15
24
 
16
25
  Documentation, schema and runtime must come from the **same revision**. Read from
@@ -35,8 +44,9 @@ checkout you are working in — never from memory of another version.
35
44
  tests and the pinned runtime version. Preserve the user's organization,
36
45
  naming and unrelated routes.
37
46
  - Choose exactly one handler per route — `function`, `redirect`, `respond`,
38
- `page`, `static`, `download` or `link` plus optional ordered middleware.
39
- Prefer a native handler when code is unnecessary.
47
+ `page`, `static`, `download`, `conditional`, `proxy` or an `extension` mount
48
+ — plus optional ordered middleware. Prefer a native handler when code is
49
+ unnecessary.
40
50
  - Declare each path placeholder as a required string. Paths match whole
41
51
  segments: no regex, no greedy captures, no wildcard handlers.
42
52
  - Bind typed inputs through `args` or context. There is no `${...}`
@@ -56,8 +66,14 @@ mistakes that recur:
56
66
  - No YAML anchors, aliases, template interpolation or remote includes.
57
67
  - No recursive includes or glob discovery; includes are explicit.
58
68
  - No regex, optional or greedy route segments, and no host-based routing.
59
- - The sandbox is text/JSON `Request`/`Response` only: **no** `fetch`, Node or
60
- npm APIs, filesystem, WebSocket, streaming or crypto API.
69
+ - `function`/`middleware` routes run trusted and unsandboxed by default: full
70
+ Node, npm, filesystem and `fetch` access, in-process, like any other project
71
+ code. `sandbox: true` opts a route into isolation — reach for it when that
72
+ route's own code warrants it (untrusted input, an unreviewed contribution, a
73
+ particularly sensitive secret), not reflexively on every route. A
74
+ `sandbox: true` route gets a text/JSON `Request`/`Response` sandbox only:
75
+ **no** `fetch`, Node or npm APIs, filesystem, WebSocket, streaming or crypto
76
+ API.
61
77
  - No global middleware, Express compatibility or automatic auth.
62
78
  - `policies` accepts only `throttle`, `agents`, `security`, `compression` and
63
79
  `cache`, every key off unless declared; `hardened` is the only built-in
@@ -68,9 +84,9 @@ mistakes that recur:
68
84
  only and off unless declared; a declared route at the same path wins. Its
69
85
  generated routes count toward `--expect-routes`, and `site.sitemap` needs
70
86
  `--origin` on every command that activates the project.
71
- - `dynamicLinks: true` belongs in the entry `urlcode.yaml` only, and only for
72
- live `link` handlers not for includes, and not for parameterized redirects
73
- or functions.
87
+ - There is no native `link` handler or `dynamicLinks` project flag. Stored
88
+ short links are moving to a future `urlcode-dynamic-link` extension package,
89
+ not yet published; report that as a gap, never invent a `link` field.
74
90
  - Infrastructure (proxy ranges, storage URLs, vendor rule identifiers) is an
75
91
  operator flag, never route YAML.
76
92
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: urlcode-operations
3
- description: Deploy, verify, monitor and operate a URLCode project — process/container deployment, release readiness, verifying a live deployment against the project, capacity/audit/benchmark, observability, DDoS/overload resilience, and private management (grants, live-link credentials). Use when the user asks to deploy, check readiness, verify a running deployment, size/benchmark a project, monitor it, plan for overload, or manage live links/bindings. Reports operational limits and unimplemented capabilities as gaps instead of inventing mitigations.
3
+ description: Deploy, verify, monitor and operate a URLCode project — process/container deployment, release readiness, verifying a live deployment against the project, capacity/audit/benchmark, observability, DDoS/overload resilience, and operator binding grants. Use when the user asks to deploy, check readiness, verify a running deployment, size/benchmark a project, monitor it, plan for overload, or manage bindings. Reports operational limits and unimplemented capabilities as gaps instead of inventing mitigations.
4
4
  ---
5
5
 
6
6
  # Operating a URLCode deployment
@@ -30,9 +30,7 @@ another version.
30
30
  overload and DDoS; what layer each defense belongs to.
31
31
  6. `docs/MONITORING.md` and `docs/OBSERVABILITY.md` — health/ready probes,
32
32
  logs, metrics format, what is and is not exported.
33
- 7. `docs/MANAGEMENT-SECURITY.md` — the private management API: credential
34
- policy shape, scope, loopback-only binding.
35
- 8. `docs/POLICIES.md` and `docs/FUNCTION-SECURITY.md` — per-target policy
33
+ 7. `docs/POLICIES.md` and `docs/FUNCTION-SECURITY.md` — per-target policy
36
34
  support and the operator binding-grant process, needed whenever a
37
35
  deployment or verification step touches either.
38
36
 
@@ -71,8 +69,8 @@ urlcode verify-deployment --project ./my-links --target https://links.example \
71
69
  Run the actual commands and report actual results, never "should work" or
72
70
  "should be reachable". `verify-deployment` needs a real target; do not
73
71
  simulate its output. In a runtime checkout, substitute `node src/cli.ts` for
74
- `urlcode`. Pass `--policy`/`--link-store` where a snapshot needs bindings
75
- already reviewed by the operator.
72
+ `urlcode`. Pass `--policy` where a snapshot needs bindings already reviewed
73
+ by the operator.
76
74
 
77
75
  ## Hard limits — report these as gaps, never invent around them
78
76
 
@@ -84,12 +82,9 @@ already reviewed by the operator.
84
82
  - `verify-deployment` has no infrastructure access, uses no credential,
85
83
  follows no redirect and offers no `--insecure`. It cannot check anything a
86
84
  read-only HTTP probe cannot observe.
87
- - The private management API binds only `127.0.0.1`/`::1`; it is never meant
88
- to be exposed through a public proxy or container port mapping, and browser
89
- Origin requests are rejected regardless.
90
- - A management credentials policy is operator-owned, outside the application,
91
- never in YAML or Git, at most 64 KiB, mode 600, at most 128 credentials with
92
- explicit collection/action allowlists — no wildcards.
85
+ - Core has no durable store and no private management API of its own; stored
86
+ short links are moving to a future `urlcode-dynamic-link` extension
87
+ package, not yet published.
93
88
  - Sandbox concurrency, worker slots and execution deadlines are shared across
94
89
  every programmable route in a snapshot; there is no per-route fairness or
95
90
  reserved capacity, and awaiting a guest timer still occupies a slot.
@@ -102,10 +97,9 @@ responsibility that covers it instead of inventing a flag.
102
97
 
103
98
  ## Boundaries
104
99
 
105
- - Never generate or approve an operator binding grant, or a management
106
- credentials policy, on the user's behalf. Both are the operator's own
107
- reviewed decision; produce the shape and let them fill in and store the
108
- real secret.
100
+ - Never generate or approve an operator binding grant on the user's behalf.
101
+ That is the operator's own reviewed decision; produce the shape and let
102
+ them fill in and store the real secret.
109
103
  - Keep every credential, token and policy file out of source, examples and
110
104
  Git. A synthetic example value is fine; a real one is never committed.
111
105
  - Do not deploy, expose a service, rotate a credential, or run
@@ -6,7 +6,7 @@
6
6
  },
7
7
  "metadata": {
8
8
  "description": "Claude plugins published from the URLCode repository.",
9
- "version": "0.4.0-alpha.1"
9
+ "version": "0.4.0-alpha.2"
10
10
  },
11
11
  "plugins": [
12
12
  {
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # URLCode
2
2
 
3
3
  **A portable runtime for programmable URL behavior, and the framework that grows
4
- from it.** Declare an application's public URL surface in YAML, add isolated
5
- JavaScript only where declarative handlers are not enough, and run the same
4
+ from it.** Declare an application's public URL surface in YAML, add JavaScript
5
+ only where declarative handlers are not enough, and run the same
6
6
  project locally, in a container, on your own infrastructure or on a provider
7
7
  adapter. When the project gets serious, add accounts and an administration
8
8
  console as operator-installed extensions instead of building them again.
@@ -26,16 +26,22 @@ infrastructure for AI-built software, not a framework for building AI models.
26
26
 
27
27
  A project is a `urlcode.yaml` with `version: "1"`. Each route has exactly one
28
28
  handler: `redirect`, `respond`, `page`, `static`, `download`, `function`,
29
- `link`, `proxy`, `conditional` or an `extension` mount, with optional ordered
29
+ `proxy`, `conditional` or an `extension` mount, with optional ordered
30
30
  `middleware`. The runtime validates the whole project before serving it,
31
31
  compiles it once, and refuses anything a target cannot enforce with the route
32
- named. Functions run in a QuickJS/WebAssembly sandbox with a fresh heap per
33
- call and no Node, filesystem or network; secrets reach them only through
34
- operator grants pinned to the project revision.
35
-
36
- URLCode is not a URL shortener: short links are one handler. It is not a
37
- general Node web framework: guest code cannot reach the host. It is not a
38
- provider configuration format: infrastructure settings stay out of route YAML.
32
+ named. Functions and middleware run trusted, in-process, with full Node
33
+ access by default; a route opts into an isolated QuickJS/WebAssembly sandbox
34
+ with a fresh heap per call and no Node, filesystem or network by declaring
35
+ `sandbox: true`. Either way, secrets reach them only through operator grants
36
+ pinned to the project revision.
37
+
38
+ URLCode is not a URL shortener: stored short links are an operator-installed
39
+ extension, not core's job. It is not a
40
+ general Node web framework: routing, validation, middleware wiring and
41
+ policies are declared in YAML, not hand-wired; isolating a specific route's
42
+ code from the host is an explicit `sandbox: true` opt-in, not something every
43
+ route gets by writing a handler. It is not a provider configuration format:
44
+ infrastructure settings stay out of route YAML.
39
45
  See [project direction](docs/PROJECT-DIRECTION.md).
40
46
 
41
47
  ## The framework
@@ -47,10 +53,20 @@ an AI agent must follow are in [the framework](docs/FRAMEWORK.md).
47
53
 
48
54
  | Package | Adds | Status |
49
55
  |---|---|---|
50
- | [urlcode](https://github.com/jimhoyd-com/urlcode) (this repository) | Runtime, CLI, policies, live links, provider adapters, extension contract | `0.4.0-alpha.1` (alpha) on top of the `0.3.0` release, Apache-2.0 |
51
- | [urlcode-ui](https://github.com/jimhoyd-com/urlcode-ui) | Shared presentation: escaped templates, shadcn/ui partials, themes, translations | `0.1.0-alpha.1` on npm, alpha: review pending |
52
- | [urlcode-auth](https://github.com/jimhoyd-com/urlcode-auth) | Accounts: password, passkeys, OIDC, email codes, TOTP, sessions, roles, account page | `0.1.0-alpha.1` on npm, alpha: review pending |
53
- | [urlcode-admin](https://github.com/jimhoyd-com/urlcode-admin) | Administration: users, sessions, roles, audit, approvals, cases, impersonation | `0.1.0-alpha.1` on npm, alpha: review pending |
56
+ | [urlcode](https://github.com/jimhoyd-com/urlcode) (this repository) | Runtime, CLI, policies, provider adapters, extension contract | `0.4.0-alpha.2` (alpha) on top of the `0.3.0` release, Apache-2.0 |
57
+ | [urlcode-ui](https://github.com/jimhoyd-com/urlcode-ui) | Shared presentation: escaped templates, shadcn/ui partials, themes, translations | `0.1.0-alpha.5` on npm, alpha: review pending |
58
+ | [urlcode-auth](https://github.com/jimhoyd-com/urlcode-auth) | Accounts: password, passkeys, OIDC, email codes, TOTP, sessions, roles, account page | `0.1.0-alpha.3` on npm, alpha: review pending |
59
+ | [urlcode-admin](https://github.com/jimhoyd-com/urlcode-admin) | Administration: users, sessions, roles, audit, approvals, cases, impersonation | `0.1.0-alpha.3` on npm, alpha: review pending |
60
+ | [urlcode-dynamic-link](https://github.com/jimhoyd-com/urlcode-dynamic-link) | Stored short links: the mount-based successor to core's removed `link` handler | `0.1.0-alpha.2` on npm, alpha: review pending |
61
+ | [urlcode-middleware](https://github.com/jimhoyd-com/urlcode-middleware) | Per-route middleware through the extension seam, alongside core's native array | `0.1.0-alpha.2` on npm, alpha: review pending |
62
+ | [urlcode-short](https://github.com/jimhoyd-com/urlcode-short) | A complete link shortener assembled from the packages above | `0.1.0-alpha.2` on npm, alpha: review pending |
63
+
64
+ Every version in this table is the one published to npm under the `alpha`
65
+ dist-tag, and they are released together in the order core → ui → auth →
66
+ admin → dynamic-link/middleware → short. The authoritative cross-repository
67
+ register, including each package's declared peer ranges and the rules that
68
+ keep them consistent, is
69
+ [docs/VERSION-ALIGNMENT.md](docs/VERSION-ALIGNMENT.md).
54
70
 
55
71
  ```yaml
56
72
  version: "1"
@@ -74,23 +90,26 @@ it. Cross-repository acceptance is tracked in
74
90
 
75
91
  ## Status
76
92
 
77
- `0.4.0-alpha.1` is the current release of the extension contract and the
78
- agent tooling, on top of the `0.3.0` self-hosted release. It adds the
79
- extension contract, capabilities and provider conformance, strict redirect
80
- interchange, bulk import, recipes and search, TypeScript guest authoring,
81
- conditions, bounded proxy and signals, and the MCP read and authoring modes;
82
- use the schema and docs from the runtime revision you run.
93
+ `0.4.0-alpha.2` is the current release of the extension contract and the
94
+ agent tooling, on top of the `0.3.0` self-hosted release. `0.4.0-alpha.1`
95
+ added the extension contract, capabilities and provider conformance, strict
96
+ redirect interchange, bulk import, recipes and search, TypeScript guest
97
+ authoring, conditions, bounded proxy and signals, and the MCP read and
98
+ authoring modes. `0.4.0-alpha.2` then made `function` and `middleware` routes
99
+ run trusted and unsandboxed by default, with `sandbox: true` as a per-route
100
+ opt-in, and removed the native `link:`/`dynamicLinks:` YAML shape. That is a
101
+ behaviour change for existing projects with no YAML edit; read
102
+ [the roadmap entry](ROADMAP.md) before upgrading. Use the schema and docs from
103
+ the runtime revision you run.
83
104
  The [roadmap](ROADMAP.md) separates implemented from planned, and
84
105
  [release readiness](docs/RELEASE-READINESS.md) records what is proven and
85
106
  what is not: provider deployments, soak and independent security review
86
107
  remain open.
87
108
 
88
- Live-link storage uses separate bounded reader/writer pools. It requires a Node
89
- build containing a patched SQLite version — 3.51.3 or newer, 3.50.7, or 3.44.6 —
90
- which some current releases on a supported Node line do not carry. Run
91
- `urlcode doctor` and check `liveLinks` before relying on it; everything else
92
- runs on any supported Node.
93
- See [pool controls and scaling limits](docs/DYNAMIC-LINKS.md#separate-reader-and-writer-pools).
109
+ Stored short links have moved out of core into
110
+ [urlcode-dynamic-link](https://github.com/jimhoyd-com/urlcode-dynamic-link)
111
+ (mount-based, like `auth`/`admin`, published on npm); core no longer has a
112
+ native `link` handler.
94
113
 
95
114
  URLCode is free and open-source software licensed under the
96
115
  [Apache License 2.0](LICENSE). Commercial use, modification, redistribution and
@@ -123,42 +142,36 @@ npm ci
123
142
  npm run dev
124
143
  ```
125
144
 
126
- Live stored-link routes require **`dynamicLinks: true`** in the entry `urlcode.yaml`;
127
- the starter explicitly sets false. Ordinary functions and parameterized redirects
128
- do not need it. [Live-link setup](docs/DYNAMIC-LINKS.md).
129
-
130
145
  ## Built with URLCode
131
146
 
132
- [urlcode-shortener](https://github.com/jimhoyd-com/urlcode-shortener) is a
133
- standalone, account-free demo built on URLCode's public runtime and storage APIs.
147
+ [urlcode-short](https://github.com/jimhoyd-com/urlcode-short) is a
148
+ standalone, account-free demo built on URLCode's public runtime. It predates
149
+ this repository's removal of the native link-store API from core; its
150
+ retrospective should be read alongside that change, not as current guidance.
134
151
  It combines short links that expire after one hour or less, QR downloads, and a
135
- shadcn/ui + Tailwind frontend. URLCode handles the page/assets and stored-link
136
- redirects; the application adds anonymous creation and its own limits.
152
+ shadcn/ui + Tailwind frontend. URLCode handles the page/assets and routing; the
153
+ application adds anonymous creation, stored-link storage and its own limits.
137
154
 
138
- Read its [build retrospective](https://github.com/jimhoyd-com/urlcode-shortener/blob/main/docs/BUILD-RETROSPECTIVE.md)
155
+ Read its [build retrospective](https://github.com/jimhoyd-com/urlcode-short/blob/main/docs/BUILD-RETROSPECTIVE.md)
139
156
  for what the runtime supplied, what the application still needed, and proposed
140
157
  improvements. The demo's license, hosting and production validation remain open;
141
158
  it does not change URLCode's Apache-2.0 license or guest isolation model.
142
159
 
143
- [urlcode-docs](https://github.com/jimhoyd-com/urlcode-docs) demonstrates URLCode
144
- hosting a static documentation site with shadcn/ui and Tailwind. It syncs this
145
- repository’s Markdown and examples at a pinned revision, applies templates through
146
- sandboxed middleware during the build, and serves the output through native
147
- page/static/download routes. This repository remains the documentation source of
148
- truth. See the [docs-site retrospective](https://github.com/jimhoyd-com/urlcode-docs/blob/main/docs/BUILD-RETROSPECTIVE.md)
149
- for reuse, integration work and upstream improvements. Hosting and a public domain
150
- are not yet selected; the original site-code license is pending.
160
+ `urlcode-docs` demonstrates URLCode hosting a static documentation site with
161
+ shadcn/ui and Tailwind: content authored directly in that repository, applying
162
+ templates through its own sandbox-opted-in (`sandbox: true`) middleware during
163
+ the build, served through native page/static/download routes. That repository
164
+ is currently private, so it isn't publicly browsable yet. Hosting and a public
165
+ domain are not yet selected; the original site-code license is pending.
151
166
 
152
167
  ## Start from YAML
153
168
 
154
169
  Already wrote `urlcode.yaml`? Run `urlcode scaffold --project ./my-links --dry-run`,
155
170
  then remove `--dry-run` to create missing modules, pages and directories. Existing
156
171
  files are preserved; code placeholders return 501 until implemented.
157
- [Scaffolding guide](docs/SCAFFOLDING.md).
158
- Live-link storage and the auth extension need a Node build whose SQLite is
159
- 3.51.3 or newer, 3.50.7 or 3.44.6. `urlcode doctor` reports `liveLinks`;
160
- everything else runs on any supported Node (22.13+ installed, 22.18+ to run
161
- the TypeScript source).
172
+ [Scaffolding guide](docs/SCAFFOLDING.md). Node 22.13+ installed, 22.18+ to run
173
+ the TypeScript source; the separate `urlcode-auth` extension may have its own
174
+ SQLite build requirement, unverified from this repository.
162
175
 
163
176
  ## Try it
164
177
 
@@ -204,9 +217,6 @@ and [middleware](docs/MIDDLEWARE.md).
204
217
 
205
218
  - **Pages, files, downloads:** `page`, `static`, `download` with MIME detection,
206
219
  ETags, ranges and safety limits. [Assets](docs/ASSETS.md).
207
- - **Live short links:** a `link` route on an optional SQLite store; create,
208
- update and delete without reloads through the CLI or the private management
209
- API. [Dynamic links](docs/DYNAMIC-LINKS.md).
210
220
  - **HTTP:** methods, validated path/query/header inputs, body limits, response
211
221
  headers and cookies. [HTTP](docs/HTTP.md).
212
222
  - **Policies and site conventions:** throttle, agents, security headers,
@@ -227,11 +237,13 @@ and [middleware](docs/MIDDLEWARE.md).
227
237
  Self-hosted Node process or container first. `@jimhoyd/urlcode/vercel` and
228
238
  `@jimhoyd/urlcode/aws` serve declarative projects as native handlers;
229
239
  `urlcode build --target cloudflare` compiles redirects and declared responses
230
- into a Worker. Each target refuses at activation or build time what it cannot
240
+ into a Worker; `urlcode build --target static` compiles redirects and static
241
+ files into plain objects and redirect metadata for S3 + CloudFront, with no
242
+ server at all. Each target refuses at activation or build time what it cannot
231
243
  run, with the route named. None has been exercised on its provider yet; the
232
244
  adapters have local conformance tests only. [Operations](docs/OPERATIONS.md),
233
245
  [capabilities](docs/CAPABILITIES.md), [Vercel](docs/VERCEL.md), [AWS](docs/AWS.md),
234
- [Cloudflare](docs/CLOUDFLARE.md).
246
+ [Cloudflare](docs/CLOUDFLARE.md), [static hosting](docs/STATIC.md).
235
247
 
236
248
  ## For AI agents
237
249
 
@@ -244,10 +256,11 @@ inspection, validation and conversion previews over stdio, and
244
256
 
245
257
  ## Documentation
246
258
 
247
- Full documentation lives in
248
- [urlcode-docs](https://github.com/jimhoyd-com/urlcode-docs). It is authored
249
- there directly, not generated from this repository, and it is where new guides,
250
- references and recipes belong.
259
+ Full documentation is authored in a separate `urlcode-docs` repository, where
260
+ new guides, references and recipes belong — but that repository is currently
261
+ private, so its content isn't publicly browsable yet. Until it's made public,
262
+ the practical reference is this README and [`docs/`](docs/README.md) in this
263
+ repository.
251
264
 
252
265
  `docs/` in this repository is contributor and maintainer material — local
253
266
  development, CI, the release process, reviews and the generated field
@@ -256,11 +269,11 @@ reference. Reader-facing pages still under `docs/` are being migrated.
256
269
  ## Built with URLCode
257
270
 
258
271
  [urlcode-short](https://github.com/jimhoyd-com/urlcode-short), an
259
- account-free short-link demo with a shadcn/ui front end, and
260
- [urlcode-docs](https://github.com/jimhoyd-com/urlcode-docs), a static
261
- documentation site rendered through sandboxed middleware at build time. Both are
262
- ordinary consumers of the public runtime; their retrospectives list what the
263
- runtime supplied and what they still had to build.
272
+ account-free short-link demo with a shadcn/ui front end, and `urlcode-docs`, a
273
+ static documentation site rendered through its own sandbox-opted-in middleware
274
+ at build time (currently a private repository). Both are ordinary consumers of
275
+ the public runtime; urlcode-short's retrospective lists what the runtime
276
+ supplied and what it still had to build.
264
277
 
265
278
  ## License and contributing
266
279
 
package/ROADMAP.md CHANGED
@@ -1,7 +1,8 @@
1
1
  # Public roadmap
2
2
 
3
3
  URLCode is a portable runtime for programmable URL behavior, not a URL
4
- shortener. Live links are one handler in the broader project contract. The
4
+ shortener. Stored short links are an operator-installed extension, not a core
5
+ handler. The
5
6
  [project direction](docs/PROJECT-DIRECTION.md) explains how application
6
7
  projects and provider adapters fit without redefining or restricting the free
7
8
  runtime.
@@ -11,7 +12,37 @@ separate late phase. The stable 0.1 self-hosted release covers much of M0/M1 plu
11
12
  process/container packaging and benchmarks. Provider adapters and the remaining
12
13
  production-readiness gates remain open.
13
14
 
14
- ## 0.4.0-alpha.1 — current alpha
15
+ ## 0.4.0-alpha.2 — current alpha
16
+
17
+ `0.4.0-alpha.2` is a behavior-changing release on top of `0.4.0-alpha.1`:
18
+ **`function` and `middleware` routes now run trusted and unsandboxed by
19
+ default** — in the host process, with full Node/filesystem/network access,
20
+ exactly like any other project code — instead of always dispatching through
21
+ the QuickJS/WebAssembly worker pool. Sandboxing is now an explicit per-route
22
+ opt-in via `sandbox: true`; a route that declares it gets exactly the
23
+ isolation every earlier alpha provided, unchanged. See
24
+ [docs/SPIKE-DEFAULT-TRUST-MODEL.md](docs/SPIKE-DEFAULT-TRUST-MODEL.md) for
25
+ the maintainer's decision and rationale, and
26
+ [docs/FUNCTION-SECURITY.md](docs/FUNCTION-SECURITY.md) for the resulting
27
+ contract of both execution modes.
28
+
29
+ **This changes existing projects with no YAML edit.** Every `function`/
30
+ `middleware` route that does not declare `sandbox` — which, before this
31
+ release, meant every such route in every existing project — now runs trusted
32
+ instead of sandboxed the moment the runtime is upgraded to `0.4.0-alpha.2` or
33
+ later. Binding grants (`env`/`secrets`) are unaffected: a route still
34
+ receives only what it declares and an operator policy pins to the project
35
+ revision, whether trusted or sandboxed. Review which of your project's
36
+ `function`/`middleware` routes handle input or code you would not otherwise
37
+ trust with full Node/filesystem/network access, and add `sandbox: true` to
38
+ those specifically (docs/AI-AUTHORING.md's "Deciding when a route needs
39
+ `sandbox: true`") before upgrading a project that relies on the old,
40
+ always-sandboxed behavior. An operator policy pinned to a project's revision
41
+ is invalidated by this upgrade regardless of whether the project's own YAML
42
+ changed, since the project hash includes the trust-model-affecting change;
43
+ re-derive and re-approve it (`urlcode permissions`) after upgrading.
44
+
45
+ ## 0.4.0-alpha.1
15
46
 
16
47
  `0.4.0-alpha.1` is the first alpha of the extension contract and the agent
17
48
  tooling on top of the `0.3.0` self-hosted release. It carries: the
@@ -86,8 +117,10 @@ signals. See [conditions](docs/CONDITIONS.md), [egress](docs/EGRESS.md),
86
117
 
87
118
  Bundled Git-owned recipes, safe bulk imports into route includes, build-time
88
119
  TypeScript guest transpilation, read-only inspection APIs and optional stdio
89
- MCP tooling are available. The runtime still executes only JavaScript inside
90
- QuickJS/WASM; TypeScript authoring does not add host execution. Bulk benchmarks
120
+ MCP tooling are available. The runtime still executes only JavaScript, and
121
+ TypeScript authoring adds no execution mode: transpilation happens at build
122
+ time, is not type checking, and a `sandbox: true` route's emitted JavaScript
123
+ runs inside QuickJS/WASM exactly as before. Bulk benchmarks
91
124
  successfully cover 1,000, 10,000 and 100,000 routes without relaxing parser
92
125
  limits. See [recipes](docs/RECIPES.md), [bulk evidence](docs/BULK.md),
93
126
  [TypeScript authoring](docs/TYPESCRIPT-AUTHORING.md) and
@@ -140,9 +173,10 @@ deployment returns byte-identical status, body and headers to the self-hosted
140
173
  server. Bindings arrive through a `URLCODE_POLICY` environment variable holding
141
174
  the same revision-pinned grant document the operator policy file carries.
142
175
 
143
- Native handlers only: isolated functions, middleware and stored live links are
144
- refused at activation, because every cold start would pay worker and WASM
145
- startup and a serverless filesystem cannot hold a durable link store. The
176
+ Native handlers only: `function` and `middleware` routes are refused at
177
+ activation, trusted or sandboxed alike, because they need the self-hosted Node
178
+ lifecycle and a sandboxed one would pay worker and WASM startup on every cold
179
+ start. The
146
180
  `@jimhoyd/urlcode/aws` does the same for a Lambda Function URL or API Gateway HTTP API.
147
181
  Payload format 2.0 only: format 1.0 supplies an already-decoded path and query,
148
182
  and this runtime rejects ambiguous encoding deliberately, so rebuilding a target
@@ -161,7 +195,7 @@ generation, so it gets a compiler rather than an adapter: `urlcode build
161
195
  validators, and `@jimhoyd/urlcode/cloudflare` serves them with the same matching, request
162
196
  policy and response policy as every other host. Declarative routes only —
163
197
  redirects and declared responses with parameters, defaults, validation, response
164
- headers, `enabled` and `expires`. Functions, middleware, stored links, assets and
198
+ headers, `enabled` and `expires`. Functions, middleware, assets and
165
199
  bindings are refused at build time with the route named, so an unsupported
166
200
  project fails the build instead of the deployment. Bindings are refused even as
167
201
  literals, because a build artifact must never carry a secret.
@@ -202,18 +236,25 @@ does not cover.
202
236
 
203
237
  ## Hardening checkpoint — alpha.8
204
238
 
205
- Bound HTTP admission and inactive sockets, drain accepted link writes on shutdown,
206
- reject invalid store metadata, and correct management defaults/method responses.
239
+ Bound HTTP admission and inactive sockets, and correct management
240
+ defaults/method responses.
207
241
  The [readiness register](docs/RELEASE-READINESS.md) distinguishes tested safeguards
208
242
  from deployment and stable-release gates. Feature breadth does not imply stability.
209
243
 
210
- ## Live short links — alpha.8
244
+ ## Live short links — alpha.8 (removed from core, superseded)
211
245
 
212
246
  Implemented an optional native `link` handler, local SQLite persistence, CLI CRUD
213
- and a separate authenticated management API. Links become visible without YAML
214
- changes/reloads; versioned writes prevent silent lost updates. No guest storage
215
- or network access is added. Same-host only; distributed storage, general state,
216
- user accounts and provider adapters remain open. See [dynamic links](docs/DYNAMIC-LINKS.md).
247
+ and a separate authenticated management API. Links became visible without YAML
248
+ changes/reloads; versioned writes prevented silent lost updates. No guest storage
249
+ or network access was added. Same-host only; distributed storage, general state,
250
+ user accounts and provider adapters remained open.
251
+
252
+ This native `link` handler, its SQLite store, CLI and management API were
253
+ removed from core in the layering work that followed: stored short links are
254
+ moving to a future `urlcode-dynamic-link` extension package (mount-based, like
255
+ `auth`/`admin`, not yet published). A project that used `link`/`dynamicLinks`
256
+ needs that extension once it ships; there is no in-core replacement or
257
+ deprecation shim.
217
258
 
218
259
  ## Middleware — alpha.7
219
260
 
@@ -254,13 +295,17 @@ Bulk tools, recipes and best-effort signals were added in the unreleased next-ph
254
295
 
255
296
  ## Security correction — 0.1.0-alpha.2
256
297
 
298
+ <!-- trust-model-prose: historical -->
257
299
  All function code is untrusted. Node host execution has been replaced by
258
300
  QuickJS/WebAssembly isolation with fresh invocation state, no ambient host or
259
301
  network APIs, bounded resources, restricted module graphs and revision-pinned
260
302
  operator binding policy. This protection is part of the free product. See the
261
303
  [security model](docs/FUNCTION-SECURITY.md). Full Fetch/Node
262
304
  API compatibility and network integrations were not part of that alpha and
263
- remain outside the 0.1 contract.
305
+ remain outside the 0.1 contract. That default was superseded in
306
+ `0.4.0-alpha.2`, which made this isolation the per-route `sandbox: true`
307
+ opt-in instead (see
308
+ [docs/SPIKE-DEFAULT-TRUST-MODEL.md](docs/SPIKE-DEFAULT-TRUST-MODEL.md)).
264
309
 
265
310
  ## Earlier implementation checkpoint — 0.1.0-alpha.1
266
311
 
package/SECURITY.md CHANGED
@@ -1,13 +1,28 @@
1
1
  # Security
2
2
 
3
- Application functions are **untrusted by default**. Alpha.2 replaces direct Node
4
- execution with QuickJS/WebAssembly isolation. Worker threads alone are not the
5
- security boundary. There is no unrestricted host-execution fallback.
6
-
7
- Guests have no Node, filesystem, shell, network or ambient process-environment
8
- access. Each invocation gets fresh state and bounded resources. Imports stay
9
- inside a snapshotted project module graph. Binding grants come from operator
10
- policy outside the project and are pinned to the configuration/code revision.
3
+ Project `function`/`middleware` code is **trusted and unsandboxed by default**:
4
+ it runs directly in the host process, exactly like any other project code,
5
+ with full Node, filesystem and network access (docs/SPIKE-DEFAULT-TRUST-MODEL.md).
6
+ A route opts into isolation explicitly with `sandbox: true`, which dispatches
7
+ that route through the QuickJS/WebAssembly worker pool instead unchanged
8
+ from the isolation this project has always provided, still the boundary to
9
+ reach for when a route's code specifically warrants it (input from a source
10
+ the project doesn't fully trust, a contribution nobody has reviewed, logic
11
+ handling an especially sensitive secret).
12
+
13
+ A `sandbox: true` guest has no Node, filesystem, shell, network or ambient
14
+ process-environment access. Each invocation gets fresh state and bounded
15
+ resources. Imports stay inside a snapshotted project module graph. Binding
16
+ grants — for a trusted route as much as a sandboxed one — come from operator
17
+ policy outside the project and are pinned to the configuration/code revision;
18
+ trusting a route's code by default does not grant it any `env`/`secrets` it
19
+ was not explicitly declared and pinned to receive. This is a claim about what
20
+ URLCode injects into `context.env`/`context.secrets` for a route, not an
21
+ access-control boundary on trusted code itself: a trusted (non-`sandbox`)
22
+ route runs with full Node access by design, so its own code can read
23
+ `process.env`, the filesystem or the network independently of anything the
24
+ binding grant declared or withheld. The grant only governs what URLCode hands
25
+ that code through `context`; it is not a restriction the code is confined to.
11
26
  See the [security model and policy instructions](docs/FUNCTION-SECURITY.md).
12
27
 
13
28
  The host/runtime and sandbox engine still require patching, independent review