@jimhoyd/urlcode 0.5.0 → 0.5.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/urlcode-authoring/SKILL.md +1 -1
- package/.claude/skills/urlcode-operations/SKILL.md +1 -1
- package/README.md +13 -16
- package/dist/BUILD-MANIFEST.json +21 -18
- package/dist/agents-guide.js +1 -1
- package/dist/authoring.js +50 -9
- package/dist/capabilities.js +1 -1
- package/dist/cli.js +20 -7
- package/dist/ecosystem-cli.js +6 -0
- package/dist/explain-cli.js +1 -1
- package/dist/explain.js +2 -2
- package/dist/extension-artifacts.js +10 -23
- package/dist/extension-bundles.js +8 -16
- package/dist/extension-transport.js +41 -0
- package/dist/feature-plan.js +99 -0
- package/dist/index.js +2 -2
- package/dist/mcp.js +6 -2
- package/dist/policies/agents.js +1 -1
- package/dist/policies/security.js +1 -1
- package/dist/policies.js +1 -1
- package/dist/review.js +206 -0
- package/dist/router.js +15 -2
- package/dist/scripts/operational-drills.js +1 -1
- package/dist/tooling.js +4 -0
- package/dist/types/authoring.d.ts +2 -0
- package/dist/types/explain.d.ts +3 -0
- package/dist/types/extension-artifacts.d.ts +2 -4
- package/dist/types/extension-transport.d.ts +31 -0
- package/dist/types/feature-plan.d.ts +67 -0
- package/dist/types/index.d.ts +2 -2
- package/dist/types/review.d.ts +30 -0
- package/dist/types/tooling.d.ts +4 -0
- package/dist/types/types.d.ts +9 -1
- package/dist/types.js +10 -3
- package/docs/AI-AUTHORING.md +466 -0
- package/docs/FUNCTION-SECURITY.md +251 -0
- package/docs/README.md +96 -0
- package/docs/TOOLING.md +422 -0
- package/docs/YAML-REFERENCE.md +473 -0
- package/examples/assets/example.yaml +3 -3
- package/examples/aws/example.yaml +3 -3
- package/examples/cloudflare/example.yaml +3 -3
- package/examples/compliance/README.md +1 -1
- package/examples/compliance/example.yaml +1 -1
- package/examples/conditions/example.yaml +3 -3
- package/examples/cookbook/README.md +4 -4
- package/examples/cookbook/example.yaml +3 -3
- package/examples/coverage-waiver/example.yaml +3 -3
- package/examples/egress/example.yaml +2 -2
- package/examples/extensions/example.yaml +1 -1
- package/examples/lifecycle/example.yaml +2 -2
- package/examples/not-found/README.md +2 -2
- package/examples/not-found/example.yaml +3 -3
- package/examples/prerender/README.md +4 -4
- package/examples/prerender/example.yaml +2 -2
- package/examples/provider-conformance/example.yaml +2 -2
- package/examples/shared-blocks/example.yaml +3 -3
- package/examples/vercel/example.yaml +3 -3
- package/llms-full.txt +119 -84
- package/llms.txt +28 -19
- package/package.json +19 -13
- package/recipes/store-crud/README.md +9 -10
- package/recipes/store-crud/recipe.yaml +1 -1
- package/schemas/urlcode.schema.json +3 -0
- package/skills/urlcode/SKILL.md +1 -1
- package/starters/default/AGENTS.md +1 -1
- package/starters/default/README.md +2 -2
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
# Function execution: trusted by default, sandboxed opt-in
|
|
2
|
+
|
|
3
|
+
`function` and `middleware` routes run **trusted and unsandboxed by default**:
|
|
4
|
+
in the host process, with full Node, filesystem and network access, exactly
|
|
5
|
+
like any other project code (docs/SPIKE-DEFAULT-TRUST-MODEL.md). This is a
|
|
6
|
+
deliberate, maintainer-decided reversal of alpha.2's blanket sandbox — see
|
|
7
|
+
that spike document for the full rationale. It is a call the project makes,
|
|
8
|
+
not a property the runtime can verify: URLCode cannot know whether your code
|
|
9
|
+
is safe to trust, only whether you asked for isolation.
|
|
10
|
+
|
|
11
|
+
Declare `sandbox: true` on a route when its code specifically warrants
|
|
12
|
+
isolation: it processes input from a source the project doesn't fully trust
|
|
13
|
+
(a third-party webhook payload, for example), it is a contribution nobody on
|
|
14
|
+
the team has reviewed, or it handles a secret sensitive enough that a bug in
|
|
15
|
+
that one route should not be able to reach the rest of the process or the
|
|
16
|
+
filesystem. A sandboxed route runs in QuickJS inside WebAssembly, in a
|
|
17
|
+
separate worker thread, with none of the host access described below — its
|
|
18
|
+
guarantees are unchanged from every earlier release and are described in
|
|
19
|
+
full in the rest of this document. Absence of `sandbox` (or `sandbox: false`)
|
|
20
|
+
means trusted; there is no separate `unsafe`/`trusted` field to opt back into
|
|
21
|
+
the old sandboxed-by-default behavior — set `sandbox: true` per route instead.
|
|
22
|
+
|
|
23
|
+
**Either way, binding grants are unaffected.** Trusting a route's code by
|
|
24
|
+
default does not grant it any `env`/`secrets` it was not explicitly declared
|
|
25
|
+
in YAML and approved by an operator policy pinned to the project revision
|
|
26
|
+
(see "Granting selected bindings" below). A trusted function only *can* do
|
|
27
|
+
more with Node once it runs — it does not receive anything more than a
|
|
28
|
+
sandboxed one would.
|
|
29
|
+
|
|
30
|
+
This is a claim about `context`/`context.secrets` injection, not an
|
|
31
|
+
access-control guarantee on trusted code. The binding grant governs only what
|
|
32
|
+
URLCode hands a route through `context`; it does not restrict what trusted
|
|
33
|
+
(non-`sandbox`) code can independently do, because that code has full Node
|
|
34
|
+
access by design. A trusted function can read `process.env`, open files or
|
|
35
|
+
make network calls on its own regardless of what its route was or was not
|
|
36
|
+
granted — withholding a binding grant limits what URLCode gives the code
|
|
37
|
+
through `context`, not what the code itself, running with full Node access,
|
|
38
|
+
can go and get. A sandboxed route has no such independent access: the guest
|
|
39
|
+
API is all it has, so its binding grant *is* effectively its whole reach into
|
|
40
|
+
the environment. Trusted code's reach is not bounded that way; treat the
|
|
41
|
+
grant as scoping `context`, not as scoping the process.
|
|
42
|
+
|
|
43
|
+
## Migrating to the trusted default
|
|
44
|
+
|
|
45
|
+
If you are upgrading a project from a release before this change shipped:
|
|
46
|
+
**every existing `function` and `middleware` route silently changes execution
|
|
47
|
+
mode**, from sandboxed to trusted, unless it already has (or you add)
|
|
48
|
+
`sandbox: true`. This is a real behavior change on upgrade, not a
|
|
49
|
+
documentation update — a route that used to run with no filesystem or network
|
|
50
|
+
access will, after the upgrade, run with full Node access unless you opt it
|
|
51
|
+
back into the sandbox.
|
|
52
|
+
|
|
53
|
+
Before upgrading:
|
|
54
|
+
|
|
55
|
+
- List every `function` and `middleware` route in the project.
|
|
56
|
+
- For each one, decide whether you fully trust that code to run in-process
|
|
57
|
+
with full Node/filesystem/network access — the same trust you would extend
|
|
58
|
+
to any other code you deploy to that server.
|
|
59
|
+
- Add `sandbox: true` explicitly to any route whose code you do not fully
|
|
60
|
+
trust, that processes input from a source you don't control, or that handles
|
|
61
|
+
a secret binding you want isolated — before you upgrade, not after.
|
|
62
|
+
- Routes you do want running trusted need no change; that is now the default.
|
|
63
|
+
|
|
64
|
+
The change moves the sandbox from an unconditional guarantee to an explicit,
|
|
65
|
+
per-route choice, mainly for performance: the previous blanket sandbox capped
|
|
66
|
+
concurrency at two workers with no queue shared across every function route on
|
|
67
|
+
the server, which does not scale to real concurrent traffic. It also brings
|
|
68
|
+
first-party code in line with how the rest of the Node ecosystem treats
|
|
69
|
+
deployed application code. The sandbox itself is unchanged for routes that opt
|
|
70
|
+
into it; only the default for routes that declare neither option has changed.
|
|
71
|
+
|
|
72
|
+
## What "sandboxed" (`sandbox: true`) still guarantees
|
|
73
|
+
|
|
74
|
+
- Function sources are parsed/snapshotted without importing them into Node.
|
|
75
|
+
- Code runs in QuickJS inside WebAssembly, with no host JS functions/objects
|
|
76
|
+
exposed to the guest. Request/response/context use a JSON/string boundary.
|
|
77
|
+
- No `process`, `require`, Node built-ins, filesystem, shell, sockets, fetch,
|
|
78
|
+
WebSocket, workers, native extensions or ambient environment is available.
|
|
79
|
+
- Module resolution is restricted to the route's declared middleware and function relative JavaScript
|
|
80
|
+
dependency graphs inside the project. Symlink escapes, remote/bare imports and
|
|
81
|
+
dynamic imports in source fail. Runtime-created imports cannot broaden access.
|
|
82
|
+
- A fresh guest heap/module state per invocation prevents state crossing requests.
|
|
83
|
+
- 32 MiB guest heap, 512 KiB stack, source/input/output/header limits, bounded
|
|
84
|
+
concurrency, guest interruption and an independent worker termination deadline.
|
|
85
|
+
- External bindings are denied by default. Project YAML cannot self-authorize.
|
|
86
|
+
Operator grants are exact-name, route-scoped and pinned to configuration/source.
|
|
87
|
+
|
|
88
|
+
The guest API is intentionally narrower than Node or full Fetch; see the
|
|
89
|
+
[implemented contract](SPECIFICATION.md). A function moving from trusted to
|
|
90
|
+
`sandbox: true` that uses Node/network or binary/stream APIs must be rewritten
|
|
91
|
+
for the supported guest profile, or stay trusted. Redirects need none of this
|
|
92
|
+
machinery either way.
|
|
93
|
+
|
|
94
|
+
This engine — worker spawning, the module-allowlist walk, the two-layer
|
|
95
|
+
deadline, `maxBytes` and response-shape validation — is one implementation
|
|
96
|
+
shared by route dispatch and by `@jimhoyd/urlcode/sandbox`'s `SandboxPool`.
|
|
97
|
+
That public HTTP-shaped primitive remains available to extension authors, but
|
|
98
|
+
project extension hooks use arbitrary typed values and contract v1 runs them
|
|
99
|
+
trusted in-process; it rejects `sandbox: true` rather than claiming HTTP sandbox
|
|
100
|
+
semantics apply to them. See [extensions](EXTENSIONS.md#project-level-lifecycle-hooks).
|
|
101
|
+
|
|
102
|
+
## What the trusted default can and can't do
|
|
103
|
+
|
|
104
|
+
A trusted route (no `sandbox`, or `sandbox: false`) has none of the guest
|
|
105
|
+
restrictions above:
|
|
106
|
+
|
|
107
|
+
- Full Node built-ins, `process`, the filesystem, `fetch`, sockets, workers
|
|
108
|
+
and npm packages are available, exactly as in any other Node module.
|
|
109
|
+
- Module resolution is ordinary Node ESM resolution: bare specifiers, dynamic
|
|
110
|
+
`import()` and node_modules all work. There is no dependency-graph allowlist
|
|
111
|
+
and no per-module/total source-size budget (function-sources.ts's
|
|
112
|
+
`MODULE_LIMIT`/`MODULE_BYTE_LIMIT`/`TOTAL_BYTE_LIMIT` apply only to what a
|
|
113
|
+
sandboxed snapshot bundles).
|
|
114
|
+
- Node's own module cache is shared across invocations and across the whole
|
|
115
|
+
process; there is no fresh heap per call. Module-level state persists
|
|
116
|
+
between requests exactly like an ordinary long-running Node server, so a
|
|
117
|
+
trusted function that mutates shared/global state affects later requests
|
|
118
|
+
the way hand-written server code would.
|
|
119
|
+
- There is no worker-thread deadline that force-terminates a stuck call. A
|
|
120
|
+
trusted invocation races a configurable timeout, but that race can only
|
|
121
|
+
reject the *call*; it cannot preempt code that blocks the event loop
|
|
122
|
+
synchronously. See [capacity](CAPACITY.md) for what this means for one slow
|
|
123
|
+
or hung trusted route's effect on the rest of the process.
|
|
124
|
+
- A snapshot reload re-imports a trusted route's own entry file fresh (each
|
|
125
|
+
reload gets its own cache-busted module registration), so editing the
|
|
126
|
+
`source` file a route declares and reloading picks up the change, the same
|
|
127
|
+
as the sandboxed pool rebuilding from scratch. A file that entry file
|
|
128
|
+
merely *imports* is not similarly busted: Node's own module cache is
|
|
129
|
+
keyed by the resolved URL of that import statement, which this runtime
|
|
130
|
+
does not rewrite, so an edited dependency two files deep from the route
|
|
131
|
+
keeps serving its old content until the process restarts. Restructure a
|
|
132
|
+
route so the code you expect to hot-reload is the declared entry file
|
|
133
|
+
itself, or restart rather than reload after editing a trusted route's
|
|
134
|
+
dependencies. A `sandbox: true` route has no such gap: reload always
|
|
135
|
+
rebuilds its whole snapshot, dependencies included.
|
|
136
|
+
|
|
137
|
+
What does **not** change with trust: `args` are still exactly the validated
|
|
138
|
+
values the route declares (never raw request input), and `env`/`secrets` are
|
|
139
|
+
still exactly what the route's YAML requests and an operator policy grants,
|
|
140
|
+
pinned to the project revision — trust changes where code runs, not what
|
|
141
|
+
it is handed *through `context`*. It does not change what the code can go get
|
|
142
|
+
on its own once it is running; see "binding grants are unaffected" above for
|
|
143
|
+
that distinction.
|
|
144
|
+
|
|
145
|
+
## Trusted code, not trusted requests
|
|
146
|
+
|
|
147
|
+
"Trusted" describes the code's authorship — first-party project code you
|
|
148
|
+
reviewed and deployed — not the requests it handles. Every request, in either
|
|
149
|
+
mode, still carries client-controlled path, query, header and body data that is
|
|
150
|
+
exactly as adversarial as it always was. Running trusted means that code
|
|
151
|
+
executes with full Node access if it mishandles that input; it does not mean
|
|
152
|
+
the input itself became safe to trust. Declare `parameters` and `request.body`
|
|
153
|
+
validation in YAML, check `args` and any other request data again inside
|
|
154
|
+
function/middleware code, and implement your own authentication and
|
|
155
|
+
authorization — no route, sandboxed or trusted, adds automatic auth.
|
|
156
|
+
`sandbox: true` narrows what a bug or an unreviewed dependency in the *code*
|
|
157
|
+
can do with that same request data; it is not a substitute for validating or
|
|
158
|
+
authenticating the request itself.
|
|
159
|
+
|
|
160
|
+
## Granting selected bindings
|
|
161
|
+
|
|
162
|
+
An application may request a named binding in YAML, but only an operator can
|
|
163
|
+
approve it. Inspect what the app requests without executing any module:
|
|
164
|
+
|
|
165
|
+
```sh
|
|
166
|
+
urlcode permissions --project /srv/my-links
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
This prints a proposed JSON shape with `version: 1`, `projectSha256` and `routes`.
|
|
170
|
+
It grants nothing. Review the code/configuration and keep only necessary bindings.
|
|
171
|
+
Save the policy **outside the application checkout**, in an operator-controlled
|
|
172
|
+
file; never let application authors or deployment artifacts overwrite it.
|
|
173
|
+
|
|
174
|
+
```json
|
|
175
|
+
{
|
|
176
|
+
"version": 1,
|
|
177
|
+
"projectSha256": "REPLACE_WITH_THE_REVIEWED_PROJECT_DIGEST",
|
|
178
|
+
"routes": {
|
|
179
|
+
"/customer/{id}": {
|
|
180
|
+
"env": ["API_MODE"],
|
|
181
|
+
"secrets": ["customer_api_key"]
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
The placeholder deliberately does not validate. Use the actual digest produced
|
|
188
|
+
by inspection. Then, with values securely injected into the process:
|
|
189
|
+
|
|
190
|
+
```sh
|
|
191
|
+
urlcode validate --project /srv/my-links --policy /etc/urlcode/my-links-policy.json
|
|
192
|
+
urlcode serve --project /srv/my-links --policy /etc/urlcode/my-links-policy.json
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
`dev`, `test` and `validate --local` use the same policy rules even for `.env.local`.
|
|
196
|
+
The JavaScript API accepts an equivalent operator-supplied `permissions` object.
|
|
197
|
+
Every config change invalidates the grant, and so does a module change within
|
|
198
|
+
what the approval digest actually hashes: for a sandboxed route, its
|
|
199
|
+
middleware/function sources and their full dependency graph; for a trusted
|
|
200
|
+
route, only its own entry-file source (see the next paragraph — a trusted
|
|
201
|
+
route's transitive dependencies are explicitly **not** part of that digest).
|
|
202
|
+
Inspect/review the new revision before updating the operator file. Policies
|
|
203
|
+
are read at startup, not hot-reloaded. A failed development candidate leaves
|
|
204
|
+
the previous approved snapshot running.
|
|
205
|
+
|
|
206
|
+
Granting a secret deliberately makes it available to every middleware and function
|
|
207
|
+
in that route, trusted or sandboxed alike. A sandboxed route's middleware
|
|
208
|
+
sources and their full dependency graph are included in the approval digest,
|
|
209
|
+
as before; a trusted route's own entry-file source is included too, so
|
|
210
|
+
changing that file's content invalidates the grant, but a change to a helper
|
|
211
|
+
module it merely imports does not by itself (see function-sources.ts's
|
|
212
|
+
`collectTrustedSources`) — a known, documented gap versus the sandboxed path's
|
|
213
|
+
full dependency-graph hashing: a trusted route's grant scope is entry-file-only,
|
|
214
|
+
not transitive. Either way, code can include any granted data
|
|
215
|
+
in its HTTP response: neither the sandbox nor the trusted default promises
|
|
216
|
+
secrecy from code that was explicitly authorized to read a value. Minimize
|
|
217
|
+
grants, use scoped/short-lived credentials and revoke/restart when needed.
|
|
218
|
+
Other routes get none of that context.
|
|
219
|
+
|
|
220
|
+
## Next capability work
|
|
221
|
+
|
|
222
|
+
Outbound requests need a host-owned broker with explicit destination/method
|
|
223
|
+
allowlists, private/metadata/loopback-address restrictions, DNS/rebinding defenses,
|
|
224
|
+
redirect revalidation, deadlines and byte/concurrency limits. Application YAML
|
|
225
|
+
must not grant those permissions. Persistent state needs similarly scoped access.
|
|
226
|
+
Until such brokers are implemented and tested, these capabilities are unavailable
|
|
227
|
+
to a *sandboxed* route. Provider adapters must preserve a `sandbox: true`
|
|
228
|
+
route's isolation or reject deployment; they cannot silently downgrade a
|
|
229
|
+
route that explicitly asked for the sandbox into unrestricted Node execution.
|
|
230
|
+
(A trusted route, by contrast, already has unrestricted Node execution by
|
|
231
|
+
design on the self-hosted target — see "What the trusted default can and
|
|
232
|
+
can't do" above; non-Node targets refuse `function`/`middleware` entirely,
|
|
233
|
+
trusted or sandboxed, since neither execution mode exists there.)
|
|
234
|
+
|
|
235
|
+
## Verification and remaining risk
|
|
236
|
+
|
|
237
|
+
Tests attempt constructor/eval escapes, Node/filesystem/shell/network imports,
|
|
238
|
+
runtime-created imports, cross-request prototype/state pollution, oversized
|
|
239
|
+
allocations, loops, unauthorized secret requests and stale/repo-local policies.
|
|
240
|
+
These are regression tests, not a proof of complete security.
|
|
241
|
+
|
|
242
|
+
The URLCode host, parser, QuickJS/WASM engine, native runtime and dependencies
|
|
243
|
+
remain trusted computing components that need patching and review. Guest heap
|
|
244
|
+
limits do not cap all host/WASM RSS; use OS/container memory/CPU/PID limits as an
|
|
245
|
+
additional layer. Native engine bugs or resource exhaustion remain residual risks.
|
|
246
|
+
For a public arbitrary-code/multi-tenant service, require independent security
|
|
247
|
+
review plus process/VM-level isolation and operational controls before launch.
|
|
248
|
+
Do not advertise this release as an audited hostile multi-tenant hosting platform.
|
|
249
|
+
|
|
250
|
+
Implementation references: [QuickJS/WASM project](https://github.com/justjake/quickjs-emscripten)
|
|
251
|
+
and its [runtime isolation/limits API](https://github.com/justjake/quickjs-emscripten/blob/main/doc/quickjs-emscripten/classes/QuickJSRuntime.md).
|
package/docs/README.md
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# URLCode documentation
|
|
2
|
+
|
|
3
|
+
Choose a starting point, then use the topic directory below when you need detail.
|
|
4
|
+
Use documentation from the same pinned revision as your runtime.
|
|
5
|
+
|
|
6
|
+
| I want to… | Start here |
|
|
7
|
+
|---|---|
|
|
8
|
+
| Understand what URLCode does | [Framework](FRAMEWORK.md) |
|
|
9
|
+
| Build my first project | [Installation](INSTALL.md), then [YAML guide](YAML-GUIDE.md) |
|
|
10
|
+
| Build a site with UI, accounts and admin | [Composing a site](COMPOSING-A-SITE.md) |
|
|
11
|
+
| Have an AI author a project | [AI authoring](AI-AUTHORING.md), [agent index](../llms.txt) |
|
|
12
|
+
| Deploy and operate a project | [Operations](OPERATIONS.md) |
|
|
13
|
+
| Contribute to URLCode | [Contributing](../CONTRIBUTING.md), [local development](LOCAL-DEVELOPMENT.md) |
|
|
14
|
+
|
|
15
|
+
The [specification](SPECIFICATION.md) owns implemented semantics; the
|
|
16
|
+
[generated field reference](YAML-REFERENCE.md) lists accepted fields.
|
|
17
|
+
[Project direction](PROJECT-DIRECTION.md) explains the product boundary.
|
|
18
|
+
|
|
19
|
+
## Author a project
|
|
20
|
+
|
|
21
|
+
| Goal | Start here |
|
|
22
|
+
|---|---|
|
|
23
|
+
| Install the CLI | [Installation](INSTALL.md) |
|
|
24
|
+
| Write YAML with examples | [YAML guide and recipes](YAML-GUIDE.md) |
|
|
25
|
+
| Look up every accepted field | [Generated field reference](YAML-REFERENCE.md), [JSON Schema](../schemas/urlcode.schema.json) |
|
|
26
|
+
| Load authoring/operations rules into an agent | [Authoring skill](../.claude/skills/urlcode-authoring/SKILL.md), [operations skill](../.claude/skills/urlcode-operations/SKILL.md), [how they are distributed](AI-AUTHORING.md#agent-skills) |
|
|
27
|
+
| Understand exact behavior | [Specification](SPECIFICATION.md), [routing](ROUTING.md), [HTTP](HTTP.md) |
|
|
28
|
+
| Run examples | [Executable cookbook](../examples/cookbook/README.md), [prerender recipe](../examples/prerender/README.md), [small starter](STARTERS.md) |
|
|
29
|
+
| Let an AI build routes | [The framework](FRAMEWORK.md), [AI authoring guide](AI-AUTHORING.md), [llms.txt](../llms.txt), [SDK and read-only MCP](TOOLING.md) |
|
|
30
|
+
| Reuse code around routes | [Middleware](MIDDLEWARE.md), [middleware examples](MIDDLEWARE-EXAMPLES.md) |
|
|
31
|
+
| Handle secrets and decide what to sandbox | [Function security](FUNCTION-SECURITY.md) |
|
|
32
|
+
| Author guest functions in TypeScript | [Build-time guest transpilation](TYPESCRIPT-AUTHORING.md) |
|
|
33
|
+
| Serve pages, files and downloads | [Assets](ASSETS.md) |
|
|
34
|
+
| Publish a site with no request-time guest code | [Prerendering helper and recipe](PRERENDER.md) |
|
|
35
|
+
| Select response branches | [Exact conditions](CONDITIONS.md) |
|
|
36
|
+
| Proxy an API or emit a webhook | [Bounded egress and operator grants](EGRESS.md) |
|
|
37
|
+
| Throttle, block agents, set security headers, compress or cache | [Policies](POLICIES.md): [throttle](policies/throttle.md), [agents](policies/agents.md), [security](policies/security.md), [compression](policies/compression.md), [cache](policies/cache.md) |
|
|
38
|
+
| Generate robots.txt, sitemap.xml, favicon, security.txt and llms.txt | [Site conventions](SITE.md) |
|
|
39
|
+
| Organize YAML across folders | [Organization](ORGANIZATION.md), [readability practices](BEST-PRACTICES.md) |
|
|
40
|
+
| Generate placeholders from YAML | [Scaffolding](SCAFFOLDING.md) |
|
|
41
|
+
| Convert provider redirect files | [Strict interchange and conversion reports](INTERCHANGE.md) |
|
|
42
|
+
| Import thousands of redirects | [Bulk import and scale evidence](BULK.md) |
|
|
43
|
+
| Reuse local project recipes | [Recipe catalog](RECIPES.md) |
|
|
44
|
+
| Check declared configuration against standards-referenced rules | [Compliance](COMPLIANCE.md) |
|
|
45
|
+
|
|
46
|
+
## Extend the runtime
|
|
47
|
+
|
|
48
|
+
| Goal | Start here |
|
|
49
|
+
|---|---|
|
|
50
|
+
| Add accounts, sign-in and protected routes | [urlcode-auth](../packages/auth#readme), [auth security](../packages/auth/SECURITY.md) |
|
|
51
|
+
| Manage users, sessions, roles and audit | [urlcode-admin](../packages/admin#readme) |
|
|
52
|
+
| Restyle every extension page and translate copy | [urlcode-ui](../packages/ui#readme), [ui contract](../packages/ui/CONTRACT.md) |
|
|
53
|
+
| Serve a declared collection as a CRUD API (`store` extension) | [Data store](STORE.md) |
|
|
54
|
+
| Write or install a versioned extension | [Extensions](EXTENSIONS.md), [example fixture](../examples/extensions/README.md) |
|
|
55
|
+
| Pin verified data-only extension schemas for tools or agents | [Signed declarative artifacts](EXTENSIONS.md#signed-declarative-artifacts), [tooling and MCP](TOOLING.md) |
|
|
56
|
+
| Know which core version an extension package supports, and how it says so | [Core version alignment](VERSION-ALIGNMENT.md) |
|
|
57
|
+
| Add host behavior in operator code | [Plugins](PLUGINS.md) |
|
|
58
|
+
| Use the API from TypeScript | [TypeScript: shipped declarations, exports, build and fidelity](TYPESCRIPT.md) |
|
|
59
|
+
| Implement URLCode behavior in another runtime | [Runtime implementation guide](RUNTIME-IMPLEMENTATION.md) |
|
|
60
|
+
|
|
61
|
+
## Operate and deploy
|
|
62
|
+
|
|
63
|
+
| Goal | Start here |
|
|
64
|
+
|---|---|
|
|
65
|
+
| Work locally | [Local development](LOCAL-DEVELOPMENT.md), [tunnels](TUNNELS.md) |
|
|
66
|
+
| Prove responses and counts | [Readiness](READINESS.md) |
|
|
67
|
+
| Check pull requests of a project on GitHub | [CI action, route diffs and the starter workflow](CI.md) |
|
|
68
|
+
| Deploy and roll back | [Operations](OPERATIONS.md) |
|
|
69
|
+
| Review security boundaries and reporting | [Security](../SECURITY.md), [sandbox review](SANDBOX-REVIEW.md) |
|
|
70
|
+
| Assess release readiness | [Evidence and open gates](RELEASE-READINESS.md) |
|
|
71
|
+
| See unfinished work | [Roadmap](../ROADMAP.md) |
|
|
72
|
+
| Verify a running deployment matches the project | [Deployment checks](DEPLOYMENT-CHECKS.md) |
|
|
73
|
+
| Inspect target support | [Capabilities and normalized representation](CAPABILITIES.md) |
|
|
74
|
+
| Deploy to Vercel, AWS Lambda or Cloudflare Workers | [Vercel](VERCEL.md), [AWS](AWS.md), [Cloudflare](CLOUDFLARE.md), [provider verification evidence](PROVIDER-VERIFICATION.md) |
|
|
75
|
+
| Watch a deployment | [Monitoring](MONITORING.md), [observability](OBSERVABILITY.md) |
|
|
76
|
+
| Estimate concurrency and memory | [Capacity and limits](CAPACITY.md), [load testing](LOAD-TESTING.md) |
|
|
77
|
+
| Prepare for overload, DDoS and recovery | [Resilience playbook](RESILIENCE.md) |
|
|
78
|
+
|
|
79
|
+
## Direction and evidence
|
|
80
|
+
|
|
81
|
+
Start with [principles and open decisions](OPEN-DECISIONS.md) for a plain-language
|
|
82
|
+
review and [the roadmap](../ROADMAP.md) for next work. Current behavior belongs
|
|
83
|
+
in the guides above and the [specification](SPECIFICATION.md).
|
|
84
|
+
|
|
85
|
+
- [Release readiness](RELEASE-READINESS.md), [sandbox review](SANDBOX-REVIEW.md)
|
|
86
|
+
and [provider evidence](PROVIDER-VERIFICATION.md)
|
|
87
|
+
distinguish implementation from evidence still missing.
|
|
88
|
+
- [Version alignment](VERSION-ALIGNMENT.md) and [release security](RELEASE-SECURITY.md)
|
|
89
|
+
describe peer compatibility and publication.
|
|
90
|
+
- Framework-comparison research and evidence live in the separate
|
|
91
|
+
[URLCode benchmark repository](https://github.com/jimhoyd-com/urlcode-benchmark);
|
|
92
|
+
they are not implementation promises.
|
|
93
|
+
- Historical maintainer planning and review records are maintained privately; current roadmap, open decisions, and public contracts are authoritative.
|
|
94
|
+
|
|
95
|
+
Examples are educational unless backed by runnable fixtures. Infrastructure
|
|
96
|
+
limits are deployment settings, not fields to invent in route YAML.
|