@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
|
@@ -5,6 +5,6 @@ route, with status 404 and `text/html`. See
|
|
|
5
5
|
[site conventions](../../docs/SITE.md#notfound--404html).
|
|
6
6
|
|
|
7
7
|
```sh
|
|
8
|
-
node src/cli.ts test --project examples/not-found
|
|
9
|
-
node src/cli.ts build --target static --project examples/not-found # writes 404.html
|
|
8
|
+
node packages/core/src/cli.ts test --project examples/not-found
|
|
9
|
+
node packages/core/src/cli.ts build --target static --project examples/not-found # writes 404.html
|
|
10
10
|
```
|
|
@@ -9,9 +9,9 @@ files: [urlcode.yaml, public/index.html, public/404.html, tests/requests.json, R
|
|
|
9
9
|
tests:
|
|
10
10
|
fixtures: tests/requests.json
|
|
11
11
|
commands:
|
|
12
|
-
- node src/cli.ts validate --local --project examples/not-found
|
|
13
|
-
- node src/cli.ts test --project examples/not-found
|
|
14
|
-
- node src/cli.ts audit --project examples/not-found --expect-routes 2
|
|
12
|
+
- node packages/core/src/cli.ts validate --local --project examples/not-found
|
|
13
|
+
- node packages/core/src/cli.ts test --project examples/not-found
|
|
14
|
+
- node packages/core/src/cli.ts audit --project examples/not-found --expect-routes 2
|
|
15
15
|
behavior:
|
|
16
16
|
- an unmatched GET or HEAD is answered with the page and status 404
|
|
17
17
|
- other methods keep the plain-text 404
|
|
@@ -14,11 +14,11 @@ runs no code at all.
|
|
|
14
14
|
From the runtime checkout:
|
|
15
15
|
|
|
16
16
|
```sh
|
|
17
|
-
node src/cli.ts dev --project examples/prerender # the dynamic source, live
|
|
18
|
-
node src/cli.ts test --project examples/prerender # 7 fixtures
|
|
17
|
+
node packages/core/src/cli.ts dev --project examples/prerender # the dynamic source, live
|
|
18
|
+
node packages/core/src/cli.ts test --project examples/prerender # 7 fixtures
|
|
19
19
|
node examples/prerender/prerender.mjs examples/prerender /absolute/out
|
|
20
|
-
node src/cli.ts test --project /absolute/out # fixtures the build wrote
|
|
21
|
-
node src/cli.ts audit --project /absolute/out --expect-routes 3
|
|
20
|
+
node packages/core/src/cli.ts test --project /absolute/out # fixtures the build wrote
|
|
21
|
+
node packages/core/src/cli.ts audit --project /absolute/out --expect-routes 3
|
|
22
22
|
```
|
|
23
23
|
|
|
24
24
|
The same three URLs answer identically before and after. The difference is what
|
|
@@ -9,8 +9,8 @@ files: [urlcode.yaml, functions/page.mjs, middleware/template.mjs, prerender.mjs
|
|
|
9
9
|
tests:
|
|
10
10
|
fixtures: tests/requests.json
|
|
11
11
|
commands:
|
|
12
|
-
- node src/cli.ts test --project examples/prerender
|
|
12
|
+
- node packages/core/src/cli.ts test --project examples/prerender
|
|
13
13
|
- node examples/prerender/prerender.mjs examples/prerender /absolute/out
|
|
14
|
-
- node src/cli.ts audit --project /absolute/out --expect-routes 3
|
|
14
|
+
- node packages/core/src/cli.ts audit --project /absolute/out --expect-routes 3
|
|
15
15
|
behavior:
|
|
16
16
|
- the rendered project serves the same bytes from native page routes with no sandbox on the request path
|
|
@@ -8,7 +8,7 @@ routes: 5
|
|
|
8
8
|
files: [urlcode.yaml, README.md]
|
|
9
9
|
tests:
|
|
10
10
|
commands:
|
|
11
|
-
- node src/cli.ts validate --local --project examples/provider-conformance
|
|
12
|
-
- node src/cli.ts verify-provider --target self-hosted --origin https://owned-fixture.example
|
|
11
|
+
- node packages/core/src/cli.ts validate --local --project examples/provider-conformance
|
|
12
|
+
- node packages/core/src/cli.ts verify-provider --target self-hosted --origin https://owned-fixture.example
|
|
13
13
|
behavior:
|
|
14
14
|
- no functions, bindings, assets or policies, so every target activates it; never mix it into a real project
|
|
@@ -10,8 +10,8 @@ files: [urlcode.yaml, tests/requests.json, README.md]
|
|
|
10
10
|
tests:
|
|
11
11
|
fixtures: tests/requests.json
|
|
12
12
|
commands:
|
|
13
|
-
- node src/cli.ts validate --local --project examples/shared-blocks
|
|
14
|
-
- node src/cli.ts test --project examples/shared-blocks
|
|
15
|
-
- node src/cli.ts audit --project examples/shared-blocks --expect-routes 4
|
|
13
|
+
- node packages/core/src/cli.ts validate --local --project examples/shared-blocks
|
|
14
|
+
- node packages/core/src/cli.ts test --project examples/shared-blocks
|
|
15
|
+
- node packages/core/src/cli.ts audit --project examples/shared-blocks --expect-routes 4
|
|
16
16
|
behavior:
|
|
17
17
|
- a route's own request or response key replaces the shared block whole; nothing is deep merged
|
|
@@ -12,8 +12,8 @@ files: [urlcode.yaml, api/index.js, vercel.json, public/index.html, public/notes
|
|
|
12
12
|
tests:
|
|
13
13
|
fixtures: tests/requests.json
|
|
14
14
|
commands:
|
|
15
|
-
- node src/cli.ts validate --local --project examples/vercel
|
|
16
|
-
- node src/cli.ts test --project examples/vercel
|
|
17
|
-
- node src/cli.ts audit --project examples/vercel --expect-routes 5
|
|
15
|
+
- node packages/core/src/cli.ts validate --local --project examples/vercel
|
|
16
|
+
- node packages/core/src/cli.ts test --project examples/vercel
|
|
17
|
+
- node packages/core/src/cli.ts audit --project examples/vercel --expect-routes 5
|
|
18
18
|
behavior:
|
|
19
19
|
- every route is native, so the project activates on Vercel without the sandbox
|
package/llms-full.txt
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<!-- Generated by scripts/build-llms-full.ts (npm run docs:llms). Do not edit; edit the source documents. -->
|
|
2
|
-
<!-- Consolidated URLCode authoring reference: 16 documents, about
|
|
2
|
+
<!-- Consolidated URLCode authoring reference: 16 documents, about 61,257 tokens (estimate: characters / 4). -->
|
|
3
3
|
|
|
4
4
|
<!-- urlcode-current-version:start -->
|
|
5
5
|
# URLCode
|
|
@@ -7,10 +7,11 @@
|
|
|
7
7
|
> A portable runtime for programmable URL behavior, and the framework that grows
|
|
8
8
|
> from it: routes in YAML, functions and middleware, then accounts, administration and
|
|
9
9
|
> stored links as operator-installed extensions. Stable project format
|
|
10
|
-
> `version: "1"`. Core is Apache-2.0; this revision is `0.5.
|
|
10
|
+
> `version: "1"`. Core is Apache-2.0; this revision is `0.5.6`. `function`/`middleware`
|
|
11
11
|
> routes are trusted by default with `sandbox: true` as the per-route opt-in. The
|
|
12
|
-
> auth, admin and
|
|
13
|
-
>
|
|
12
|
+
> auth, admin, ui and store workspace packages are bundle sources. New sites install
|
|
13
|
+
> core from npm and verified executable extensions from an immutable GitHub Release;
|
|
14
|
+
> see package and channel alignment for the supported release pair.
|
|
14
15
|
<!-- urlcode-current-version:end -->
|
|
15
16
|
|
|
16
17
|
Use the schema and docs from the runtime revision you run. Do not assume Node
|
|
@@ -43,12 +44,12 @@ grants. Unsupported features fail with the route named; nothing degrades silentl
|
|
|
43
44
|
|
|
44
45
|
Source: https://github.com/jimhoyd-com/urlcode/blob/main/docs/FRAMEWORK.md
|
|
45
46
|
|
|
46
|
-
One page for people and AI agents. It says what the
|
|
47
|
+
One page for people and AI agents. It says what the six workspace packages are, how a
|
|
47
48
|
project grows from a handful of redirects into an application with accounts
|
|
48
49
|
and an administration console, and which facts an agent must not guess. Every
|
|
49
50
|
claim here is implemented in the linked repository; nothing is roadmap.
|
|
50
51
|
|
|
51
|
-
###
|
|
52
|
+
### Six workspace packages, one project shape
|
|
52
53
|
|
|
53
54
|
| Package | Source | What it adds | How a project declares it |
|
|
54
55
|
|---|---|---|---|
|
|
@@ -56,12 +57,17 @@ claim here is implemented in the linked repository; nothing is roadmap.
|
|
|
56
57
|
| `@jimhoyd/urlcode-ui` | [`packages/ui`](https://github.com/jimhoyd-com/urlcode/blob/main/packages/ui) | Shared presentation: escaped templates, shadcn/ui partials, one stylesheet with light and dark, themes, translations, the `ui` extension that serves the kit's assets | `extensions.ui` plus an asset mount route |
|
|
57
58
|
| `@jimhoyd/urlcode-auth` | [`packages/auth`](https://github.com/jimhoyd-com/urlcode/blob/main/packages/auth) | Accounts: password, passkeys, OpenID Connect, email codes, TOTP, recovery, sessions, roles, registration modes, account page, operator CLI | `extensions.auth` plus an `/account/*` mount and `policies.extensions.auth` on protected routes |
|
|
58
59
|
| `@jimhoyd/urlcode-admin` | [`packages/admin`](https://github.com/jimhoyd-com/urlcode/blob/main/packages/admin) | Administration: users, sessions, roles, audit, registration approval, two-person cases, support impersonation, health | `extensions.admin` plus an `/admin/*` mount |
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
60
|
+
| `@jimhoyd/urlcode-store` | [`packages/store`](https://github.com/jimhoyd-com/urlcode/blob/main/packages/store) | Durable bounded JSON collections exposed as a typed CRUD API | `extensions.store` plus a protected collection mount |
|
|
61
|
+
| `@jimhoyd/urlcode-forms` | [`packages/forms`](https://github.com/jimhoyd-com/urlcode/blob/main/packages/forms) | Bounded server-rendered form flows: escaped controls, admission, CSRF, validation and a fixed confirmation | `extensions.forms` plus a `GET, HEAD, POST` form mount; it composes with `ui` and optional `auth` |
|
|
62
|
+
|
|
63
|
+
All six are Apache-2.0. Core is published through npm, GitHub Releases and
|
|
64
|
+
Homebrew. The first-party executable extensions are published as signed,
|
|
65
|
+
immutable GitHub Release bundles; their source remains in these workspace
|
|
66
|
+
packages, but new sites do not install them from npm. The forms package is an
|
|
67
|
+
unreleased bundle source and is not implied by the currently recorded bundle
|
|
68
|
+
release. The legacy extension npm
|
|
69
|
+
packages are deprecated migration artifacts. A release channel is not an
|
|
70
|
+
independent assessment: review, deployment
|
|
65
71
|
evidence and an accessibility assessment are still pending
|
|
66
72
|
([issue 58](https://github.com/jimhoyd-com/urlcode/issues/58)). Their status
|
|
67
73
|
files say exactly what is built: [auth](https://github.com/jimhoyd-com/urlcode/blob/main/packages/auth/IMPLEMENTATION-STATUS.md),
|
|
@@ -101,33 +107,40 @@ Each rung's YAML is valid on every rung above it.
|
|
|
101
107
|
6. **Your own look.** A shared `presentation` (catalogue and theme variables)
|
|
102
108
|
restyles auth and admin together; the `ui` extension adds the template kit,
|
|
103
109
|
project copy, template and stylesheet overrides for kit-rendered pages.
|
|
110
|
+
7. **Bounded data and forms.** The `store` extension supplies declared durable
|
|
111
|
+
collections; the `forms` extension supplies declared browser form flows over
|
|
112
|
+
the shared UI kit. Both are trusted operator extensions, not core YAML
|
|
113
|
+
handlers. Add `auth: true` where a flow or collection is per-account.
|
|
104
114
|
|
|
105
115
|
Stored short links previously sat here as a native `link` route; that handler
|
|
106
116
|
was removed from core. A `urlcode-dynamic-link` package owned them the same way
|
|
107
117
|
`auth`/`admin` own their mounts, but it has been retired and unpublished; no
|
|
108
118
|
package occupies this rung today.
|
|
109
119
|
|
|
110
|
-
Rungs 1 to 3 need only the core package. Rungs 4 to
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
120
|
+
Rungs 1 to 3 need only the core package. Rungs 4 to 7 need a verified extension
|
|
121
|
+
bundle installed into an explicit operator host, once its source package appears
|
|
122
|
+
in a selected catalog. Auth and admin additionally need the Node/SQLite runtime
|
|
123
|
+
their packages document; forms declares Node, AWS and Vercel targets, while store
|
|
124
|
+
is currently Node-only. See each package's README ([auth](https://github.com/jimhoyd-com/urlcode/blob/main/packages/auth/README.md),
|
|
125
|
+
[admin](https://github.com/jimhoyd-com/urlcode/blob/main/packages/admin/README.md), [ui](https://github.com/jimhoyd-com/urlcode/blob/main/packages/ui/README.md),
|
|
126
|
+
[store](https://github.com/jimhoyd-com/urlcode/blob/main/packages/store/README.md), [forms](https://github.com/jimhoyd-com/urlcode/blob/main/packages/forms/README.md)) for the
|
|
114
127
|
exact requirement.
|
|
115
128
|
|
|
116
129
|
### The composition contract
|
|
117
130
|
|
|
118
|
-
An extended project starts from
|
|
119
|
-
|
|
120
|
-
|
|
131
|
+
An extended project starts from core and an immutable bundle release. The
|
|
132
|
+
release is an explicit operator choice; use the current verified tag from
|
|
133
|
+
[package and channel alignment](https://github.com/jimhoyd-com/urlcode/blob/main/docs/VERSION-ALIGNMENT.md):
|
|
121
134
|
|
|
122
135
|
```sh
|
|
123
|
-
npm install
|
|
124
|
-
urlcode init my-site --with ui,auth,admin
|
|
136
|
+
npm install @jimhoyd/urlcode
|
|
137
|
+
npx urlcode init my-site --with ui,auth,admin --bundle-release extension-bundles@v…
|
|
125
138
|
```
|
|
126
139
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
140
|
+
This produces a manifest with core only and a bundle lockfile for extensions.
|
|
141
|
+
`scripts/pack-sources.mjs` remains available to review reproducible source
|
|
142
|
+
inputs. Three files make an extended project. Nothing else is discovered by
|
|
143
|
+
convention.
|
|
131
144
|
|
|
132
145
|
```
|
|
133
146
|
site/
|
|
@@ -199,36 +212,32 @@ package behavior.
|
|
|
199
212
|
A signed declarative artifact is a separate, optional authoring input, not a
|
|
200
213
|
fifth way to compose executable behavior. A project may lock an attested
|
|
201
214
|
schema/example bundle and expose it through MCP `get_extension_artifacts` and
|
|
202
|
-
`get_extension_artifact`; the
|
|
203
|
-
executable extension path. See [signed declarative artifacts](https://github.com/jimhoyd-com/urlcode/blob/main/docs/EXTENSIONS.md#signed-declarative-artifacts).
|
|
215
|
+
`get_extension_artifact`; the verified executable bundle and explicit operator
|
|
216
|
+
host remain the executable extension path. See [signed declarative artifacts](https://github.com/jimhoyd-com/urlcode/blob/main/docs/EXTENSIONS.md#signed-declarative-artifacts).
|
|
204
217
|
|
|
205
218
|
```sh
|
|
206
219
|
urlcode serve --project /absolute/site --host-file /absolute/operator/host.mjs --origin https://site.example
|
|
207
220
|
```
|
|
208
221
|
|
|
209
|
-
`urlcode init <dir> --with ui,auth,admin
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
module's `scaffold` export and merges fragments into `app/urlcode.yaml`, one
|
|
222
|
+
`urlcode init <dir> --with ui,auth,admin --bundle-release
|
|
223
|
+
extension-bundles@v…` writes this layout in one step. It verifies and locks the
|
|
224
|
+
named GitHub Release bundles, calls each verified module's `scaffold` export,
|
|
225
|
+
and merges fragments into `app/urlcode.yaml`, one
|
|
214
226
|
explicit `host.mjs` and one `README.md`, refusing before writing a site when a
|
|
215
|
-
|
|
227
|
+
bundle is missing or two fragments collide (the contract is documented under
|
|
216
228
|
[scaffolding](https://github.com/jimhoyd-com/urlcode/blob/main/docs/EXTENSIONS.md#scaffolding-with-init---with)). `urlcode-auth init`
|
|
217
229
|
and `urlcode-admin init` write the same layout for a single package; `urlcode-auth bootstrap` creates the first
|
|
218
230
|
administrator from JSON on stdin. `inspectExtensionRevision(project)` prints
|
|
219
231
|
the SHA-256 that `projectSha256` must carry; changing extension YAML, policies
|
|
220
232
|
or mounts changes the revision and needs an explicit operator reapproval.
|
|
221
233
|
|
|
222
|
-
The presentation tooling composes the same way, by naming
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
that ship the other namespaces: each is resolved from `--project` with Node
|
|
226
|
-
package resolution and imported for the namespace it exports, so `list`,
|
|
234
|
+
The presentation tooling composes the same way, by naming logical extensions
|
|
235
|
+
rather than npm dependencies. The UI bundle is the kit until the locked auth
|
|
236
|
+
and admin bundles add their namespaces, so `list`,
|
|
227
237
|
`doctor`, `eject`, `preview` and `copy --missing` cover the `auth/*` and
|
|
228
238
|
`admin/*` templates and copy the host registers, and a project override of an
|
|
229
|
-
extension template is checked against the shipped view model.
|
|
230
|
-
|
|
231
|
-
flag already set; `@jimhoyd/urlcode-ui` still depends on neither peer.
|
|
239
|
+
extension template is checked against the shipped view model. `urlcode init
|
|
240
|
+
--with --bundle-release` writes the release pin into the generated README.
|
|
232
241
|
|
|
233
242
|
### Rules an agent must follow
|
|
234
243
|
|
|
@@ -313,6 +322,13 @@ needed schema, example or README. Context is a summary with the
|
|
|
313
322
|
constraints and exact commands, not a schema dump, and it never hides a
|
|
314
323
|
capability limit: ask `capabilities NAME` before promising a feature.
|
|
315
324
|
|
|
325
|
+
When a goal spans routes, persistence or extensions, the next bounded query can
|
|
326
|
+
be `urlcode plan-feature "goal" --project DIR --json` (MCP `plan_feature`). It
|
|
327
|
+
matches only the current compiled project, capability catalog, bundled recipes,
|
|
328
|
+
locked inert artifacts and registrations already available to the session. Read
|
|
329
|
+
its operator prerequisites and explicit gaps as constraints, not as permission
|
|
330
|
+
to select packages, storage, keys or grants in project YAML.
|
|
331
|
+
|
|
316
332
|
The complete catalogs (`urlcode capabilities`, `recipes list`), the compact
|
|
317
333
|
[llms.txt](https://github.com/jimhoyd-com/urlcode/blob/main/llms.txt) index and the generated [llms-full.txt](https://github.com/jimhoyd-com/urlcode/blob/main/llms-full.txt)
|
|
318
334
|
stay available as deliberate fallback and reference, not as the opening move.
|
|
@@ -423,7 +439,7 @@ urlcode benchmark --project ./my-links --requests 100 --concurrency 2
|
|
|
423
439
|
```
|
|
424
440
|
|
|
425
441
|
Use the intentional actual count, not always 2. Runtime checkout users can replace
|
|
426
|
-
`urlcode` with `node src/cli.ts`. Template users can use the equivalent npm scripts.
|
|
442
|
+
`urlcode` with `node packages/core/src/cli.ts`. Template users can use the equivalent npm scripts.
|
|
427
443
|
External bindings require an already reviewed policy; add `--policy` where needed.
|
|
428
444
|
The benchmark operates locally; it is not a load test of an external deployment.
|
|
429
445
|
|
|
@@ -536,9 +552,9 @@ Which handler serves the response:
|
|
|
536
552
|
Data persistence has no native handler. The operator-installed `store` extension
|
|
537
553
|
serves declared collections as a CRUD API, and `urlcode recipes search "crud store
|
|
538
554
|
persist"` finds the `store-crud` recipe. It needs the operator to install
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
555
|
+
an attested executable bundle and a host file. `init --with
|
|
556
|
+
ui,auth,store --bundle-release extension-bundles@v…` scaffolds the supported
|
|
557
|
+
npm-free form; a no-auth
|
|
542
558
|
`--with store` needs `--ack store:public-write`, which only a core release after the
|
|
543
559
|
store's first publication has, so say so rather than promising it. Report anything beyond that recipe (filtering, sorting, per-record
|
|
544
560
|
ownership, a database) as a gap. `urlcode context` lists the same built-ins so
|
|
@@ -757,7 +773,7 @@ programmatic compatibility analysis and provider verification limits.
|
|
|
757
773
|
Source: https://github.com/jimhoyd-com/urlcode/blob/main/docs/YAML-GUIDE.md
|
|
758
774
|
|
|
759
775
|
<!-- urlcode-current-version:start -->
|
|
760
|
-
This guide targets URLCode 0.5.
|
|
776
|
+
This guide targets URLCode 0.5.6. Start with the function example below,
|
|
761
777
|
then add only the fields your route needs. The authoritative machine-readable
|
|
762
778
|
shape is [JSON Schema](https://github.com/jimhoyd-com/urlcode/blob/main/schemas/urlcode.schema.json); semantic rules are in the
|
|
763
779
|
[specification](https://github.com/jimhoyd-com/urlcode/blob/main/docs/SPECIFICATION.md). Unsupported fields fail validation.
|
|
@@ -772,10 +788,10 @@ From the runtime checkout:
|
|
|
772
788
|
|
|
773
789
|
```sh
|
|
774
790
|
npm ci
|
|
775
|
-
node src/cli.ts validate --project examples/cookbook
|
|
776
|
-
node src/cli.ts test --project examples/cookbook
|
|
777
|
-
node src/cli.ts audit --project examples/cookbook --expect-routes 40
|
|
778
|
-
node src/cli.ts dev --project examples/cookbook
|
|
791
|
+
node packages/core/src/cli.ts validate --project examples/cookbook
|
|
792
|
+
node packages/core/src/cli.ts test --project examples/cookbook
|
|
793
|
+
node packages/core/src/cli.ts audit --project examples/cookbook --expect-routes 40
|
|
794
|
+
node packages/core/src/cli.ts dev --project examples/cookbook
|
|
779
795
|
```
|
|
780
796
|
|
|
781
797
|
The cookbook is a larger learning project. The normal `urlcode init ../my-links`
|
|
@@ -898,6 +914,7 @@ schema-valid combinations activate successfully.
|
|
|
898
914
|
| `routes.*.env.* (option 1).value` | string | yes | — |
|
|
899
915
|
| `routes.*.env.* (option 2)` | object | no | unknown keys rejected |
|
|
900
916
|
| `routes.*.env.* (option 2).env` | string | yes | pattern: "^[A-Za-z_][A-Za-z0-9_]*$" |
|
|
917
|
+
| `routes.*.env.* (option 2).default` | string | no | — |
|
|
901
918
|
| `routes.*.secrets` | object | no | — |
|
|
902
919
|
| `routes.*.secrets.*` | object | no | unknown keys rejected |
|
|
903
920
|
| `routes.*.secrets.*.secret` | string | yes | pattern: "^[A-Za-z_][A-Za-z0-9_]*$" |
|
|
@@ -1593,12 +1610,17 @@ parity for a `sandbox: true` route; a trusted route has no such restriction.
|
|
|
1593
1610
|
|
|
1594
1611
|
Context contains `inputs.path/query/header`, `args`, `env`, `secrets`. Arguments
|
|
1595
1612
|
may be scalar literals, input references, `{env: alias}` or `{secret: alias}`.
|
|
1596
|
-
Bindings use `{value: "literal"}`, `{env: EXTERNAL_NAME}
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1613
|
+
Bindings use `{value: "literal"}`, `{env: EXTERNAL_NAME}`,
|
|
1614
|
+
`{value: "default", env: EXTERNAL_NAME}` or `{secret: logical_name}`. The
|
|
1615
|
+
combined form resolves to the process environment variable when set and
|
|
1616
|
+
non-empty, else `value`; it needs the same operator grant as `{env: ...}`
|
|
1617
|
+
alone. Literal non-secret values need no grant. Every external environment or
|
|
1618
|
+
secret binding is denied unless an operator policy grants that exact name to
|
|
1619
|
+
the route and matches the SHA-256 of the current configuration/source
|
|
1620
|
+
snapshot. A project cannot grant itself capabilities. See
|
|
1621
|
+
[policy setup](https://github.com/jimhoyd-com/urlcode/blob/main/docs/FUNCTION-SECURITY.md). Missing bindings reject activation
|
|
1622
|
+
(the combined form always resolves, via its default). Inspection parses
|
|
1623
|
+
source without running it.
|
|
1602
1624
|
|
|
1603
1625
|
Development may read `.env.local`; process values win. Serving never reads it.
|
|
1604
1626
|
Dotenv supports single-line NAME=value, paired single/double quotes, blank lines
|
|
@@ -2833,7 +2855,7 @@ Extensions are trusted operator modules, separate from a project's own
|
|
|
2833
2855
|
`function`/`middleware` code. Auth
|
|
2834
2856
|
and admin implementations live in `urlcode-auth` and `urlcode-admin`; the runtime
|
|
2835
2857
|
supplies only the generic integration contract. No project file can import a host
|
|
2836
|
-
extension or choose
|
|
2858
|
+
extension, choose a bundle release, or choose an npm package.
|
|
2837
2859
|
|
|
2838
2860
|
Stored short links moved out of core this way too: a `urlcode-dynamic-link`
|
|
2839
2861
|
package (mount-based, like `auth`/`admin`) owned the durable link store, its CLI
|
|
@@ -2845,6 +2867,13 @@ The `store` extension is the data-owning counterpart: it serves declared,
|
|
|
2845
2867
|
bounded collections as a CRUD API from an operator-owned directory. See
|
|
2846
2868
|
[data store](https://github.com/jimhoyd-com/urlcode/blob/main/docs/STORE.md).
|
|
2847
2869
|
|
|
2870
|
+
The `forms` extension is the browser-flow counterpart: it renders bounded
|
|
2871
|
+
declared fields through the `ui` kit, validates URL-encoded submissions with
|
|
2872
|
+
its host-supplied CSRF secret, and redirects a successful submission to a
|
|
2873
|
+
fixed confirmation page. It is a trusted operator extension, needs `ui`, and
|
|
2874
|
+
may be mounted with `auth: true`; its optional `onSubmit` hook is trusted
|
|
2875
|
+
project code rather than a sandbox bridge. See the [forms package](https://github.com/jimhoyd-com/urlcode/blob/main/packages/forms/README.md).
|
|
2876
|
+
|
|
2848
2877
|
A project declares versioned configuration and exclusive route mounts:
|
|
2849
2878
|
|
|
2850
2879
|
```yaml
|
|
@@ -3229,29 +3258,24 @@ Assembly rules, in the resolved order:
|
|
|
3229
3258
|
|
|
3230
3259
|
#### Recorded versions
|
|
3231
3260
|
|
|
3232
|
-
`init --with
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
required peer refuses and names it, leaving no directory behind.
|
|
3261
|
+
`init --with --bundle-release extension-bundles@v…` writes a private
|
|
3262
|
+
`<directory>/package.json` pinning the running core and an extension bundle
|
|
3263
|
+
lockfile naming the verified archives. It does not add extension npm
|
|
3264
|
+
dependencies. Before anything is written, the selected catalog checks every
|
|
3265
|
+
required extension and core compatibility; a missing requirement or incompatible
|
|
3266
|
+
bundle refuses and names it, leaving no directory behind.
|
|
3239
3267
|
|
|
3240
3268
|
Nothing is installed. The generated site has no `node_modules` and no
|
|
3241
|
-
`package-lock.json` until you run `npm install` in it yourself, which
|
|
3242
|
-
command and
|
|
3243
|
-
comes from
|
|
3269
|
+
`package-lock.json` until you run `npm install` in it yourself for core, which
|
|
3270
|
+
the command and generated README both state as the next step. Bundle
|
|
3271
|
+
reproducibility comes from the committed lockfile and frozen cache, not npm.
|
|
3244
3272
|
|
|
3245
3273
|
- `--no-manifest` generates the site without a `package.json`, for a site whose
|
|
3246
3274
|
dependencies are managed elsewhere. Plain `urlcode init` is unchanged and
|
|
3247
3275
|
still writes no manifest; add `--manifest` to pin the runtime for a
|
|
3248
3276
|
route-only project too.
|
|
3249
|
-
- `--pin <package>=<specifier>`
|
|
3250
|
-
|
|
3251
|
-
(`--pin @jimhoyd/urlcode-auth=file:/abs/urlcode-auth-0.1.0-alpha.6.tgz`). A
|
|
3252
|
-
package installed from a local path or tarball is detected from npm's own
|
|
3253
|
-
install record and pinned by that path without any flag; the README says so,
|
|
3254
|
-
because such a pin only reproduces where that path exists.
|
|
3277
|
+
- `--pin <package>=<specifier>` is only for reviewed local source development.
|
|
3278
|
+
New first-party extension installs use the signed bundle release instead.
|
|
3255
3279
|
|
|
3256
3280
|
There is no upgrade command. Moving a generated project to newer versions today
|
|
3257
3281
|
means editing its `package.json` and re-running `npm install` yourself; nothing
|
|
@@ -3323,8 +3347,8 @@ requirements.
|
|
|
3323
3347
|
|
|
3324
3348
|
### Signed executable extension bundles
|
|
3325
3349
|
|
|
3326
|
-
Official executable extensions are
|
|
3327
|
-
|
|
3350
|
+
Official executable extensions are delivered through a separate, immutable
|
|
3351
|
+
`extension-bundles@v…` GitHub Release namespace;
|
|
3328
3352
|
it is intentionally disjoint from the permanently data-only `extensions@v…`
|
|
3329
3353
|
artifact channel above. A bundle is a bounded, frozen Node module tree produced
|
|
3330
3354
|
from reviewed first-party source, not a general extension marketplace and not
|
|
@@ -3377,10 +3401,14 @@ export default { extensions: [storeExtension({ directory: '/srv/site-data', proj
|
|
|
3377
3401
|
```
|
|
3378
3402
|
|
|
3379
3403
|
This does not make bundle code sandboxed and does not alter a route that
|
|
3380
|
-
declares `sandbox: true`; those remain distinct execution modes.
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3404
|
+
declares `sandbox: true`; those remain distinct execution modes. The signed
|
|
3405
|
+
bundle path is the supported distribution for first-party executable
|
|
3406
|
+
extensions. The legacy `@jimhoyd/urlcode-ui`, `@jimhoyd/urlcode-auth`,
|
|
3407
|
+
`@jimhoyd/urlcode-admin`, and `@jimhoyd/urlcode-store` npm packages are
|
|
3408
|
+
deprecated migration artifacts: existing projects may retain their locked
|
|
3409
|
+
copies, but new projects must use a verified bundle release. Their npm
|
|
3410
|
+
retention status is not a promise that they are available or supported for new
|
|
3411
|
+
installs.
|
|
3384
3412
|
|
|
3385
3413
|
---
|
|
3386
3414
|
|
|
@@ -3392,10 +3420,16 @@ One command produces a site that already has accounts, an administration
|
|
|
3392
3420
|
console and a presentation kit wired together:
|
|
3393
3421
|
|
|
3394
3422
|
```sh
|
|
3395
|
-
npm install @jimhoyd/urlcode
|
|
3396
|
-
urlcode init site --with ui,auth,admin
|
|
3423
|
+
npm install @jimhoyd/urlcode
|
|
3424
|
+
npx urlcode init site --with ui,auth,admin --bundle-release extension-bundles@v…
|
|
3397
3425
|
```
|
|
3398
3426
|
|
|
3427
|
+
Use the immutable bundle release recorded in [package and channel
|
|
3428
|
+
alignment](https://github.com/jimhoyd-com/urlcode/blob/main/docs/VERSION-ALIGNMENT.md). This creates a site whose npm manifest pins
|
|
3429
|
+
core only; UI, auth and admin are verified, locked GitHub Release bundles.
|
|
3430
|
+
The legacy extension npm packages are deprecated migration artifacts. New sites
|
|
3431
|
+
obtain extensions from the verified bundle release.
|
|
3432
|
+
|
|
3399
3433
|
This page is the map of what you may then change, and with which tool. It
|
|
3400
3434
|
covers three different activities that are easy to confuse:
|
|
3401
3435
|
|
|
@@ -3573,9 +3607,10 @@ not run it. With the packages named:
|
|
|
3573
3607
|
and those translations do not currently reach the console
|
|
3574
3608
|
([#227](https://github.com/jimhoyd-com/urlcode/issues/227)).
|
|
3575
3609
|
|
|
3576
|
-
`urlcode init <directory> --with ui,auth,admin
|
|
3577
|
-
|
|
3578
|
-
|
|
3610
|
+
`urlcode init <directory> --with ui,auth,admin --bundle-release
|
|
3611
|
+
extension-bundles@v…` writes these commands into the generated README with the
|
|
3612
|
+
verified bundle release pinned. The operator names the logical extensions; it
|
|
3613
|
+
does not add extension npm dependencies.
|
|
3579
3614
|
|
|
3580
3615
|
Run the extension's published `fastChecks` while editing. Theme and copy changes
|
|
3581
3616
|
need no framework build. Template and CSS checks load only the UI kit and named
|
package/llms.txt
CHANGED
|
@@ -4,10 +4,11 @@
|
|
|
4
4
|
> A portable runtime for programmable URL behavior, and the framework that grows
|
|
5
5
|
> from it: routes in YAML, functions and middleware, then accounts, administration and
|
|
6
6
|
> stored links as operator-installed extensions. Stable project format
|
|
7
|
-
> `version: "1"`. Core is Apache-2.0; this revision is `0.5.
|
|
7
|
+
> `version: "1"`. Core is Apache-2.0; this revision is `0.5.6`. `function`/`middleware`
|
|
8
8
|
> routes are trusted by default with `sandbox: true` as the per-route opt-in. The
|
|
9
|
-
> auth, admin and
|
|
10
|
-
>
|
|
9
|
+
> auth, admin, ui and store workspace packages are bundle sources. New sites install
|
|
10
|
+
> core from npm and verified executable extensions from an immutable GitHub Release;
|
|
11
|
+
> see package and channel alignment for the supported release pair.
|
|
11
12
|
<!-- urlcode-current-version:end -->
|
|
12
13
|
|
|
13
14
|
Use the schema and docs from the runtime revision you run. Do not assume Node
|
|
@@ -17,10 +18,10 @@ grants. Unsupported features fail with the route named; nothing degrades silentl
|
|
|
17
18
|
|
|
18
19
|
## Start here (read only this section for a first attempt)
|
|
19
20
|
|
|
20
|
-
1. Run `urlcode context --project DIR` (MCP `get_context`). For redirect-only work run
|
|
21
|
-
`urlcode context --project DIR --task redirects`: supported shapes with exact YAML, gaps
|
|
21
|
+
1. Run `npx --no --package @jimhoyd/urlcode urlcode context --project DIR` (MCP `get_context`). For redirect-only work run
|
|
22
|
+
`npx --no --package @jimhoyd/urlcode urlcode context --project DIR --task redirects`: supported shapes with exact YAML, gaps
|
|
22
23
|
with their exact validation error, a paste-ready `starter`, and this project's own redirects.
|
|
23
|
-
2.
|
|
24
|
+
2. After installing `@jimhoyd/urlcode`, run `npx --no --package @jimhoyd/urlcode urlcode init . --template redirects` (it works in a directory holding only `package.json`, `package-lock.json`, `node_modules` or `.git`, and merges `scripts.start` into your `package.json`): yaml, 404 page, `npm start` honoring `PORT`, fixtures. Otherwise write `urlcode.yaml`, then run `npx --no --package @jimhoyd/urlcode urlcode validate --local --project DIR` and `npx --no --package @jimhoyd/urlcode urlcode test`. `--no` refuses a registry fetch, so it always uses the installed scoped runtime.
|
|
24
25
|
3. Do not read or grep [llms-full.txt](llms-full.txt) (about 60k tokens) for a routine task; it is the
|
|
25
26
|
deliberate fallback when the steps above do not answer the question.
|
|
26
27
|
|
|
@@ -39,19 +40,20 @@ grants. Unsupported features fail with the route named; nothing degrades silentl
|
|
|
39
40
|
|
|
40
41
|
Use the highest-level declarative feature before writing a function or middleware. Custom code
|
|
41
42
|
only when the framework cannot express the requirement; then report the gap. Never invent fields
|
|
42
|
-
or bypass target limits or operator grants ([design principle](docs/PROJECT-DIRECTION.md#design-principle-declarative-first)).
|
|
43
|
+
or bypass target limits or operator grants ([design principle](https://github.com/jimhoyd-com/urlcode/blob/main/docs/PROJECT-DIRECTION.md#design-principle-declarative-first)).
|
|
43
44
|
|
|
44
45
|
| I need | Use |
|
|
45
46
|
|---|---|
|
|
46
|
-
| Security headers | `policies.security` ([security](docs/policies/security.md)) |
|
|
47
|
-
| Cache headers / cache strategy | `cacheControl` / `policies.cache` ([assets](docs/yaml/assets.md), [cache](docs/policies/cache.md)) |
|
|
48
|
-
| Body size, content type, JSON check | `request.body` ([HTTP](docs/HTTP.md)) |
|
|
47
|
+
| Security headers | `policies.security` ([security](https://github.com/jimhoyd-com/urlcode/blob/main/docs/policies/security.md)) |
|
|
48
|
+
| Cache headers / cache strategy | `cacheControl` / `policies.cache` ([assets](https://github.com/jimhoyd-com/urlcode/blob/main/docs/yaml/assets.md), [cache](https://github.com/jimhoyd-com/urlcode/blob/main/docs/policies/cache.md)) |
|
|
49
|
+
| Body size, content type, JSON check | `request.body` ([HTTP](https://github.com/jimhoyd-com/urlcode/blob/main/docs/HTTP.md)) |
|
|
49
50
|
| Restrict HTTP methods | `methods` (default GET/HEAD; 405 with `Allow`) |
|
|
50
|
-
| Rate limiting, bot/AI-crawler blocking, compression | `policies.throttle`, `policies.agents`, `policies.compression` ([policies](docs/POLICIES.md)) |
|
|
51
|
+
| Rate limiting, bot/AI-crawler blocking, compression | `policies.throttle`, `policies.agents`, `policies.compression` ([policies](https://github.com/jimhoyd-com/urlcode/blob/main/docs/POLICIES.md)) |
|
|
51
52
|
| Fixed JSON/text/headers | `respond` and `response.headers` |
|
|
52
|
-
| robots.txt, sitemap, favicon, security.txt | top-level `site` ([site](docs/SITE.md)) |
|
|
53
|
-
| Sign-in, roles, protected routes | `extensions.auth`, then `auth: true` ([extensions](docs/EXTENSIONS.md)) |
|
|
53
|
+
| robots.txt, sitemap, favicon, security.txt | top-level `site` ([site](https://github.com/jimhoyd-com/urlcode/blob/main/docs/SITE.md)) |
|
|
54
|
+
| Sign-in, roles, protected routes | `extensions.auth`, then `auth: true` ([extensions](https://github.com/jimhoyd-com/urlcode/blob/main/docs/EXTENSIONS.md)) |
|
|
54
55
|
| Persistence | operator-installed store extension, recipe `store-crud`; a database, filtering and per-record ownership beyond it are gaps |
|
|
56
|
+
| Stored short links (create, redirect, click count) | operator-installed store extension's `shortLinks` capability: a collection `key`, an HTTP(S) `destination` field, one `increments` counter, and a public `/go`-style redirect mount; no function needed (`urlcode docs search "shortLinks"`, MCP `search_docs`) |
|
|
55
57
|
|
|
56
58
|
When only code can do it, one function serves one or more routes:
|
|
57
59
|
|
|
@@ -63,10 +65,17 @@ When only code can do it, one function serves one or more routes:
|
|
|
63
65
|
export default (request, { args, route }) => Response.json({ hello: args.name });
|
|
64
66
|
```
|
|
65
67
|
|
|
68
|
+
Function handler shape: a module whose `export default` is `(request, { args, env, route })` and returns a
|
|
69
|
+
`Response` (or a promise of one). `args` holds the route's declared path inputs; the string form
|
|
70
|
+
`function: functions/hello.mjs` and the long form `function: {source: ...}` both bind every declared path input
|
|
71
|
+
(write `args: {}` to bind none). `sandbox: true` is a separate route option. `route.pattern` is the matched pattern; `env` holds route-scoped values only.
|
|
72
|
+
Search the docs with bounded output using `npx --no --package @jimhoyd/urlcode urlcode docs search "TEXT"` (MCP `search_docs`)
|
|
73
|
+
rather than grepping llms-full.txt.
|
|
74
|
+
|
|
66
75
|
Handler for the response: fixed text or JSON is `respond`; one HTML file is `page`; a directory is
|
|
67
76
|
`static`; an attachment is `download`; a short HTML snippet is `respond` `text` with a
|
|
68
77
|
`Content-Type: text/html; charset=utf-8` header. Functions are trusted by default; add
|
|
69
|
-
`sandbox: true` to opt a route in ([function security](docs/FUNCTION-SECURITY.md)).
|
|
78
|
+
`sandbox: true` to opt a route in ([function security](https://github.com/jimhoyd-com/urlcode/blob/main/docs/FUNCTION-SECURITY.md)).
|
|
70
79
|
|
|
71
80
|
After a real attempt, draft feedback only for a capability gap, repeated workaround, documentation
|
|
72
81
|
gap or suspected defect, with sanitized YAML and validation evidence. Search existing issues first;
|
|
@@ -74,9 +83,9 @@ never publish or comment without the user's approval.
|
|
|
74
83
|
|
|
75
84
|
## Reference (load one only when needed)
|
|
76
85
|
|
|
77
|
-
- Authoring: [AI authoring contract](docs/AI-AUTHORING.md), [YAML guide](docs/YAML-GUIDE.md), [field reference](docs/YAML-REFERENCE.md), [JSON Schema](schemas/urlcode.schema.json), [semantics](docs/SPECIFICATION.md), [cookbook](examples/cookbook/README.md), [recipes](docs/RECIPES.md).
|
|
86
|
+
- Authoring: [AI authoring contract](https://github.com/jimhoyd-com/urlcode/blob/main/docs/AI-AUTHORING.md), [YAML guide](https://github.com/jimhoyd-com/urlcode/blob/main/docs/YAML-GUIDE.md), [field reference](https://github.com/jimhoyd-com/urlcode/blob/main/docs/YAML-REFERENCE.md), [JSON Schema](schemas/urlcode.schema.json), [semantics](https://github.com/jimhoyd-com/urlcode/blob/main/docs/SPECIFICATION.md), [cookbook](examples/cookbook/README.md), [recipes](https://github.com/jimhoyd-com/urlcode/blob/main/docs/RECIPES.md).
|
|
78
87
|
- Skills: [authoring](.claude/skills/urlcode-authoring/SKILL.md), [operations](.claude/skills/urlcode-operations/SKILL.md).
|
|
79
|
-
- Routes and handlers: [routing](docs/ROUTING.md), [HTTP](docs/HTTP.md), [middleware](docs/MIDDLEWARE.md), [assets](docs/ASSETS.md), [conditions](docs/CONDITIONS.md), [egress](docs/EGRESS.md), [prerender](docs/PRERENDER.md), [site](docs/SITE.md), [organization](docs/ORGANIZATION.md).
|
|
80
|
-
- Extensions: [extensions](docs/EXTENSIONS.md) (including [signed declarative artifacts](docs/EXTENSIONS.md#signed-declarative-artifacts); MCP `get_extension_artifacts`), [composing a site](docs/COMPOSING-A-SITE.md), [urlcode-auth](packages/auth), [urlcode-admin](packages/admin), [urlcode-ui](packages/ui),
|
|
81
|
-
- Tooling: [tooling and MCP](docs/TOOLING.md), [TypeScript](docs/TYPESCRIPT.md), [capabilities](docs/CAPABILITIES.md), [plugins](docs/PLUGINS.md), [interchange](docs/INTERCHANGE.md), [bulk import](docs/BULK.md).
|
|
82
|
-
- Operations: [operations](docs/OPERATIONS.md), [install](docs/INSTALL.md), [deployment checks](docs/DEPLOYMENT-CHECKS.md), [readiness](docs/READINESS.md), [capacity](docs/CAPACITY.md), [resilience](docs/RESILIENCE.md), [observability](docs/OBSERVABILITY.md), [Vercel](docs/VERCEL.md), [AWS](docs/AWS.md), [Cloudflare](docs/CLOUDFLARE.md), [static hosting](docs/STATIC.md), [release readiness](docs/RELEASE-READINESS.md), [roadmap](ROADMAP.md).
|
|
88
|
+
- Routes and handlers: [routing](https://github.com/jimhoyd-com/urlcode/blob/main/docs/ROUTING.md), [HTTP](https://github.com/jimhoyd-com/urlcode/blob/main/docs/HTTP.md), [middleware](https://github.com/jimhoyd-com/urlcode/blob/main/docs/MIDDLEWARE.md), [assets](https://github.com/jimhoyd-com/urlcode/blob/main/docs/ASSETS.md), [conditions](https://github.com/jimhoyd-com/urlcode/blob/main/docs/CONDITIONS.md), [egress](https://github.com/jimhoyd-com/urlcode/blob/main/docs/EGRESS.md), [prerender](https://github.com/jimhoyd-com/urlcode/blob/main/docs/PRERENDER.md), [site](https://github.com/jimhoyd-com/urlcode/blob/main/docs/SITE.md), [organization](https://github.com/jimhoyd-com/urlcode/blob/main/docs/ORGANIZATION.md).
|
|
89
|
+
- Extensions: [extensions](https://github.com/jimhoyd-com/urlcode/blob/main/docs/EXTENSIONS.md) (including [signed declarative artifacts](https://github.com/jimhoyd-com/urlcode/blob/main/docs/EXTENSIONS.md#signed-declarative-artifacts); MCP `get_extension_artifacts`), [composing a site](https://github.com/jimhoyd-com/urlcode/blob/main/docs/COMPOSING-A-SITE.md), [package and channel alignment](https://github.com/jimhoyd-com/urlcode/blob/main/docs/VERSION-ALIGNMENT.md). New first-party executable extension installs use an attested `extension-bundles@v…` GitHub Release and an explicit host; do not add deprecated extension npm packages to a new project. [urlcode-auth](https://github.com/jimhoyd-com/urlcode/tree/main/packages/auth), [urlcode-admin](https://github.com/jimhoyd-com/urlcode/tree/main/packages/admin), [urlcode-ui](https://github.com/jimhoyd-com/urlcode/tree/main/packages/ui), [urlcode-store](https://github.com/jimhoyd-com/urlcode/tree/main/packages/store), and [urlcode-forms](https://github.com/jimhoyd-com/urlcode/tree/main/packages/forms) are workspace bundle sources. Per-route middleware is native core (`middleware:` array), not a retired extension; core has no native `link` handler, but the store extension's `shortLinks` capability covers create, invalid-destination, redirect, missing-code and click-count for stored short links without a function — declare it under `extensions.store.config.shortLinks` (`urlcode docs search "shortLinks"`, MCP `search_docs`). Only report a gap for stored-link needs beyond that (custom redirect status, non-HTTP(S) destinations, per-record ownership).
|
|
90
|
+
- Tooling: [tooling and MCP](https://github.com/jimhoyd-com/urlcode/blob/main/docs/TOOLING.md), [TypeScript](https://github.com/jimhoyd-com/urlcode/blob/main/docs/TYPESCRIPT.md), [capabilities](https://github.com/jimhoyd-com/urlcode/blob/main/docs/CAPABILITIES.md), [plugins](https://github.com/jimhoyd-com/urlcode/blob/main/docs/PLUGINS.md), [interchange](https://github.com/jimhoyd-com/urlcode/blob/main/docs/INTERCHANGE.md), [bulk import](https://github.com/jimhoyd-com/urlcode/blob/main/docs/BULK.md).
|
|
91
|
+
- Operations: [operations](https://github.com/jimhoyd-com/urlcode/blob/main/docs/OPERATIONS.md), [install](https://github.com/jimhoyd-com/urlcode/blob/main/docs/INSTALL.md), [deployment checks](https://github.com/jimhoyd-com/urlcode/blob/main/docs/DEPLOYMENT-CHECKS.md), [readiness](https://github.com/jimhoyd-com/urlcode/blob/main/docs/READINESS.md), [capacity](https://github.com/jimhoyd-com/urlcode/blob/main/docs/CAPACITY.md), [resilience](https://github.com/jimhoyd-com/urlcode/blob/main/docs/RESILIENCE.md), [observability](https://github.com/jimhoyd-com/urlcode/blob/main/docs/OBSERVABILITY.md), [Vercel](https://github.com/jimhoyd-com/urlcode/blob/main/docs/VERCEL.md), [AWS](https://github.com/jimhoyd-com/urlcode/blob/main/docs/AWS.md), [Cloudflare](https://github.com/jimhoyd-com/urlcode/blob/main/docs/CLOUDFLARE.md), [static hosting](https://github.com/jimhoyd-com/urlcode/blob/main/docs/STATIC.md), [release readiness](https://github.com/jimhoyd-com/urlcode/blob/main/docs/RELEASE-READINESS.md), [roadmap](https://github.com/jimhoyd-com/urlcode/blob/main/ROADMAP.md).
|