@jimhoyd/urlcode 0.4.8 → 0.5.5

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 (58) hide show
  1. package/README.md +18 -18
  2. package/dist/BUILD-MANIFEST.json +27 -23
  3. package/dist/agents-guide.js +8 -4
  4. package/dist/authoring.js +81 -7
  5. package/dist/build-cloudflare.js +1 -0
  6. package/dist/build-static.js +1 -0
  7. package/dist/cli.js +39 -14
  8. package/dist/config.js +7 -1
  9. package/dist/context.js +32 -4
  10. package/dist/ecosystem-cli.js +6 -0
  11. package/dist/explain-cli.js +1 -1
  12. package/dist/explain.js +2 -2
  13. package/dist/extension-artifacts.js +28 -34
  14. package/dist/extension-bundles.js +62 -0
  15. package/dist/extension-transport.js +41 -0
  16. package/dist/extensions.js +4 -0
  17. package/dist/feature-plan.js +99 -0
  18. package/dist/functions.js +2 -1
  19. package/dist/index.js +4 -2
  20. package/dist/init-with.js +55 -23
  21. package/dist/interchange.js +1 -1
  22. package/dist/match.js +23 -5
  23. package/dist/mcp.js +6 -2
  24. package/dist/readiness.js +2 -2
  25. package/dist/review.js +206 -0
  26. package/dist/router.js +35 -10
  27. package/dist/runtime.js +1 -0
  28. package/dist/tooling.js +4 -0
  29. package/dist/types/agents-guide.d.ts +6 -1
  30. package/dist/types/authoring.d.ts +3 -1
  31. package/dist/types/context.d.ts +12 -0
  32. package/dist/types/explain.d.ts +3 -0
  33. package/dist/types/extension-artifacts.d.ts +15 -4
  34. package/dist/types/extension-bundles.d.ts +49 -0
  35. package/dist/types/extension-transport.d.ts +31 -0
  36. package/dist/types/extensions.d.ts +4 -0
  37. package/dist/types/feature-plan.d.ts +67 -0
  38. package/dist/types/functions.d.ts +4 -0
  39. package/dist/types/index.d.ts +4 -2
  40. package/dist/types/init-with.d.ts +6 -1
  41. package/dist/types/match.d.ts +1 -0
  42. package/dist/types/review.d.ts +30 -0
  43. package/dist/types/tooling.d.ts +4 -0
  44. package/dist/types/types.d.ts +10 -1
  45. package/dist/types.js +10 -3
  46. package/docs/AI-AUTHORING.md +466 -0
  47. package/docs/FUNCTION-SECURITY.md +251 -0
  48. package/docs/README.md +96 -0
  49. package/docs/TOOLING.md +422 -0
  50. package/docs/YAML-REFERENCE.md +473 -0
  51. package/llms-full.txt +190 -83
  52. package/llms.txt +73 -128
  53. package/package.json +15 -4
  54. package/recipes/redirect/README.md +2 -2
  55. package/recipes/store-crud/README.md +9 -10
  56. package/recipes/store-crud/recipe.yaml +1 -1
  57. package/schemas/urlcode.schema.json +3 -0
  58. package/starters/default/AGENTS.md +2 -2
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.4.8`. `function`/`middleware`
7
+ > `version: "1"`. Core is Apache-2.0; this revision is `0.5.5`. `function`/`middleware`
8
8
  > routes are trusted by default with `sandbox: true` as the per-route opt-in. The
9
- > auth, admin and ui extension packages in this repository are versioned at the same
10
- > revision; confirm what is published with `npm run release:status`.
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
@@ -15,132 +16,76 @@ or fetch inside a `sandbox: true` function, regex routes, database access,
15
16
  global middleware, YAML interpolation, or packages named in YAML. Secrets need external revision-pinned
16
17
  grants. Unsupported features fail with the route named; nothing degrades silently.
17
18
 
18
- Agents that explicitly want the complete consolidated reference in one fetch should read
19
- [llms-full.txt](llms-full.txt), generated from the documents below (about 50k tokens, estimated).
19
+ ## Start here (read only this section for a first attempt)
20
20
 
21
- ## Building only redirects? Start here
22
-
23
- Run `urlcode context --project DIR --task redirects` (MCP `get_context {"task":"redirects"}`)
24
- first: one bounded call returning every supported shape below with exact YAML, the
25
- gaps with their exact validation error, and this project's own redirects cheaper
26
- than reading this file or the recipe catalog. `urlcode recipes search redirect` and
27
- `urlcode recipes show redirect` give a runnable starting project.
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
23
+ with their exact validation error, a paste-ready `starter`, and this project's own redirects.
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.
25
+ 3. Do not read or grep [llms-full.txt](llms-full.txt) (about 60k tokens) for a routine task; it is the
26
+ deliberate fallback when the steps above do not answer the question.
28
27
 
29
28
  | Shape | Supported? | Use |
30
29
  |---|---|---|
31
- | Fixed redirect, any of 301/302/303/307/308 (302 default) | Yes | `redirect: {url, status}` — [redirects](docs/yaml/redirects.md) |
32
- | Parameterized path (`/users/{id}` to `/profiles/{id}`) | Yes | `{name}` placeholder in `redirect.url`, naming a declared path parameter |
33
- | Fixed-depth suffix (`/legacy/a/b` to `/modern/a/b`) | Yes, one route per depth | same as above with one placeholder per segment |
34
- | Query-string preservation | Yes, opt-in only | `redirect.query.pass` (explicit allowlist) / `query.map` |
35
- | Method-preserving redirect (keep POST body) | Yes | `methods` plus `status: 307` or `308` |
36
- | 404 for unmatched paths | Yes | `site.notFound` (a project-relative `.html` file) |
37
- | Wildcard/suffix redirect (`/legacy/*` to `/modern/*`, any depth) | No | terminal `/*` and `{rest...}` are refused on `redirect`; report the gap ([open decision](docs/OPEN-DECISIONS.md)) |
38
- | Host-based, scheme-based or relative-URL redirect | No | destination must be a literal absolute `https://host/path`; report the gap |
39
-
40
- ## Declarative-first default
41
-
42
- > Use URLCode's highest-level declarative features whenever possible. Generate custom code only when the framework cannot express the requirement.
43
-
44
- Check the installed version's primitives, YAML configuration, policies, supported
45
- extensions and recipes/templates before writing a custom function or middleware.
46
- Keep necessary custom code focused and report the capability gap; never invent
47
- fields or bypass target limits or operator grants. See [the design principle](docs/PROJECT-DIRECTION.md#design-principle-declarative-first).
48
-
49
- ## Need X? Use this built-in first
50
-
51
- Route a task to the feature before writing code. Every row is off unless declared.
52
-
53
- | I need | Use | Where |
54
- |---|---|---|
55
- | Security headers (CSP, HSTS, nosniff, frame and referrer policy) | `policies.security` (`headers: oshp`, or `profile: hardened`) | [security](docs/policies/security.md), [policies](docs/POLICIES.md) |
56
- | Cache headers for a page, download or static folder | `cacheControl`, exactly one of `no-cache` (default), `no-store`, `public, max-age=3600`, `public, max-age=31536000, immutable` | [assets](docs/yaml/assets.md) |
57
- | Cache strategy or origin cache for any route | `policies.cache` | [cache](docs/policies/cache.md) |
58
- | Request body size, required body, content type, JSON syntax check | `request.body` (`maxBytes`, `required`, `contentTypes`, `format`); 413/415/400 | [HTTP](docs/HTTP.md) |
59
- | Restrict or allow HTTP methods | `methods` (default GET/HEAD); 405 with `Allow` | [HTTP](docs/HTTP.md) |
60
- | Rate limiting | `policies.throttle` | [throttle](docs/policies/throttle.md) |
61
- | Block bots or AI crawlers | `policies.agents`; `robots` via `site` | [agents](docs/policies/agents.md), [site](docs/SITE.md) |
62
- | Compression | `policies.compression` | [compression](docs/policies/compression.md) |
63
- | Fixed JSON, text or headers with no code | `respond` and `response.headers` | [HTTP](docs/HTTP.md) |
64
- | robots.txt, sitemap, favicon, security.txt | top-level `site` | [site](docs/SITE.md) |
65
- | Sign-in, roles, protected routes | `extensions.auth`, then `auth: true` on the route | [extensions](docs/EXTENSIONS.md) |
66
-
67
- Which handler serves the response:
68
-
69
- | The response is | Handler | Recipe |
70
- |---|---|---|
71
- | Fixed text or JSON | `respond` | `health-page` |
72
- | A short HTML snippet | `respond` `text` plus `response.headers` `Content-Type: text/html; charset=utf-8` | `docs/HTTP.md` |
73
- | One HTML file | `page` | `static-page` |
74
- | A directory of files | `static` | `static-plus-api` |
75
- | An attachment | `download` | `protected-download` |
76
-
77
- Persistence: core has no storage handler, but the operator-installed store extension serves declared collections as a CRUD API; `urlcode recipes search "crud store persist"` finds the `store-crud` recipe (operator installs the package; `init --with store` is not yet available from npm, #323). Gaps to report rather than invent: a database, filtering or per-record ownership beyond that recipe, CORS, and a native link store. `urlcode context`
78
- prints the same pointer for the project in front of you.
79
-
80
- After a real authoring attempt, draft feedback only for a capability gap,
81
- repeated workaround, documentation/discovery gap or suspected defect. Include
82
- the runtime/target, sanitized YAML, observed validation/test evidence, expected
83
- behavior and a proposed fixture. Search existing URLCode issues first. Never
84
- publish or comment on an issue without the user's explicit approval.
85
-
86
- ## Authoring
87
- - [AI authoring contract](docs/AI-AUTHORING.md): workflow, capability matrix, checks.
88
- - [Authoring skill](.claude/skills/urlcode-authoring/SKILL.md): loadable authoring skill shipped with this revision; see [distribution](docs/AI-AUTHORING.md#agent-skills).
89
- - [Operations skill](.claude/skills/urlcode-operations/SKILL.md): loadable deployment/verification/resilience skill shipped with this revision.
90
- - [YAML guide](docs/YAML-GUIDE.md): recipes for all handlers and common options.
91
- - [JSON Schema](schemas/urlcode.schema.json): accepted fields and types.
92
- - [Field reference](docs/YAML-REFERENCE.md): generated exhaustive field inventory.
93
- - [Semantics](docs/SPECIFICATION.md): validation, defaults and sandbox API.
94
- - [Runnable cookbook](examples/cookbook/README.md): 25 routes with HTTP fixtures.
95
- - [Route matching](docs/ROUTING.md): precedence, non-greedy parameters, updates.
96
- - [Middleware](docs/MIDDLEWARE.md): next(), state, ordering and native body limits.
97
- - [Policies](docs/POLICIES.md): optional host-enforced `policies`/`profiles` keys, all off by default: `throttle`, `agents`, `security`, `compression`, `cache`; merge rules and per-target support.
98
- - [Plugins](docs/PLUGINS.md): host hook API operators pass in code; never named in YAML.
99
- - [TypeScript](docs/TYPESCRIPT.md): the package ships declarations for every export (`urlcode`, `@jimhoyd/urlcode/plugins`, `@jimhoyd/urlcode/policies`, `@jimhoyd/urlcode/observability`, `@jimhoyd/urlcode/compliance`, `@jimhoyd/urlcode/prerender`, `@jimhoyd/urlcode/sandbox`, `@jimhoyd/urlcode/aws`, `@jimhoyd/urlcode/vercel`, `@jimhoyd/urlcode/cloudflare`); the runtime source is TypeScript, `dist/` is its stripped JavaScript.
100
- - [HTTP](docs/HTTP.md): methods, request bodies and response headers.
101
- - [Assets](docs/ASSETS.md): pages, MIME, downloads, cache and ranges.
102
- - [Site conventions](docs/SITE.md): optional top-level `site` key, all off by default: `robots`, `sitemap`, `favicon`, `securityTxt`, `llms` generate native routes; declared routes win; absolute URLs need `--origin`.
103
- - [Prerendering](docs/PRERENDER.md): `@jimhoyd/urlcode/prerender` build helper and recipe; render function/middleware routes once into native page routes, no request-time guest code.
104
- - [Organization](docs/ORGANIZATION.md): entry point and included files.
105
-
106
- ## Start here
107
- - [The framework](docs/FRAMEWORK.md): four packages, the ladder from redirects to a full app, the composition contract, the rules an agent must follow.
108
- - [AI authoring contract](docs/AI-AUTHORING.md): workflow, capability matrix, copyable task prompt, checks.
109
- - [JSON Schema](schemas/urlcode.schema.json) and [field reference](docs/YAML-REFERENCE.md): every accepted field.
110
- - [YAML guide](docs/YAML-GUIDE.md) and [runnable cookbook](examples/cookbook/README.md): recipes with HTTP fixtures.
111
- - [Semantics](docs/SPECIFICATION.md): validation, defaults, sandbox API.
112
-
113
- ## Routes and handlers
114
- - [Routing](docs/ROUTING.md): exact and `{param}` paths, precedence, `/*` only on static and extension mounts.
115
- - [HTTP](docs/HTTP.md): methods, validated inputs, bodies, response headers, cookies.
116
- - [Function security](docs/FUNCTION-SECURITY.md): trusted and unsandboxed by default, `sandbox: true` QuickJS/WASM opt-in, Request/Response subset, operator grants.
117
- - [Middleware](docs/MIDDLEWARE.md) and [examples](docs/MIDDLEWARE-EXAMPLES.md): `next()`, state, ordering; also `urlcode recipes add middleware`.
118
- - [Assets](docs/ASSETS.md): pages, static, downloads, MIME, ranges. [Prerender](docs/PRERENDER.md): render once, no request-time code.
119
- - [Conditions](docs/CONDITIONS.md): exact predicates, disjoint redirect/respond cases, no-store.
120
- - [Egress](docs/EGRESS.md): bounded HTTPS proxy and best-effort signals behind operator grants; self-hosted only.
121
- - [Policies](docs/POLICIES.md): `throttle`, `agents`, `security`, `compression`, `cache`; all off unless declared. [Site](docs/SITE.md): robots, sitemap, favicon, security.txt, llms.txt.
122
- - [Organization](docs/ORGANIZATION.md), [best practices](docs/BEST-PRACTICES.md), [scaffolding](docs/SCAFFOLDING.md).
123
- - [Interchange](docs/INTERCHANGE.md), [bulk import](docs/BULK.md), [recipes](docs/RECIPES.md) (`urlcode recipes search`, `examples search`), [TypeScript guests](docs/TYPESCRIPT-AUTHORING.md).
124
-
125
- ## Extensions (accounts, administration, presentation)
126
- - [Extensions](docs/EXTENSIONS.md): `extensions.<name>` blocks, mounts, policies, operator registration, the shared trusted hook primitive and its machine-readable hook contracts. UI/auth/admin project hooks run trusted in-process; contract v1 rejects `sandbox: true`.
127
- - [Signed declarative artifacts](docs/EXTENSIONS.md#signed-declarative-artifacts): project-pinned, attested JSON/Markdown data for offline tooling. MCP `get_extension_artifacts` verifies/inventories a committed lock and `get_extension_artifact` reads one bounded member; neither installs or activates an npm extension.
128
- - [Composing a site](docs/COMPOSING-A-SITE.md): what `urlcode init site --with ui,auth,admin` wires, which `--with` combinations are supported, the presentation override paths under `ui/`, and per-package lifecycle hook input, verdict, timing and failure semantics. Separates declarative configuration, project functions and the TypeScript a new extension needs.
129
- - [urlcode-auth](packages/auth): npm: @jimhoyd/urlcode-auth; accounts, sessions, MFA, roles, account page; its own llms.txt. Lives in this repository as a workspace package.
130
- - [urlcode-admin](packages/admin): npm: @jimhoyd/urlcode-admin; users, sessions, roles, audit, cases; its own llms.txt. Lives in this repository as a workspace package.
131
- - [urlcode-ui](packages/ui): npm: @jimhoyd/urlcode-ui; escaped templates, shadcn/ui partials, themes, translations; its own llms.txt. Lives in this repository as a workspace package, not in a separate repository.
132
- - urlcode-middleware (retired): per-route middleware briefly lived here as an extension-seam alternative; the package was unpublished at 0.1.0-alpha.2 and its repository deleted. This is not a gap — per-route middleware is native to core via the `middleware:` array (docs/MIDDLEWARE.md); use that.
133
- - urlcode-dynamic-link (retired): stored short links briefly lived here as a mount-based extension; the package was unpublished and its repository deleted. Core has no native `link` handler and no supported extension provides stored links — report them as a gap.
134
- - [Plugins](docs/PLUGINS.md): host hook API in operator code, never named in YAML.
135
-
136
- ## Tooling and API
137
- - [Tooling SDK and MCP](docs/TOOLING.md): `urlcode mcp`, read-only inspection, validation, conversion previews.
138
- - [TypeScript](docs/TYPESCRIPT.md): declarations for `@jimhoyd/urlcode` and its `/plugins`, `/policies`, `/observability`, `/compliance`, `/prerender`, `/extensions`, `/sandbox`, `/aws`, `/vercel`, `/cloudflare` entries.
139
- - [Capabilities](docs/CAPABILITIES.md): per-target support; `urlcode capabilities --target NAME`.
140
-
141
- ## Operations
142
- - [Operations](docs/OPERATIONS.md), [install](docs/INSTALL.md), [deployment checks](docs/DEPLOYMENT-CHECKS.md), [CI action](docs/CI.md).
143
- - [Readiness](docs/READINESS.md), [capacity](docs/CAPACITY.md), [resilience](docs/RESILIENCE.md), [observability](docs/OBSERVABILITY.md).
144
- - [Vercel](docs/VERCEL.md), [AWS](docs/AWS.md), [Cloudflare](docs/CLOUDFLARE.md): adapters with local conformance tests; no provider deployment verified yet.
145
- - [Static hosting](docs/STATIC.md): `urlcode build --target static` compiles redirects/pages/static/downloads to S3 + CloudFront objects and redirect metadata; no server, so function/middleware/extension/proxy/signals/conditions/parameters/bindings/policies are all refused; GitHub Pages is explicitly out of scope.
146
- - [Release readiness](docs/RELEASE-READINESS.md), [roadmap](ROADMAP.md): what is proven, what is planned.
30
+ | Fixed redirect, 301/302/303/307/308 (302 default) | Yes | `redirect: {url, status}` |
31
+ | Parameterized path (`/users/{id}` to `/profiles/{id}`) | Yes | `{name}` in `redirect.url`, naming a declared path parameter |
32
+ | Root-relative destination (`/users/{id}` to `/profiles/{id}`) | Yes | `redirect.url: /profiles/{id}`: one leading slash, path only |
33
+ | Wildcard suffix (`/legacy/**` to `/modern/{**}`, any depth) | Yes | terminal `/**` key with a literal prefix; `{**}` is the remaining segments (redirect only; not static or Cloudflare) |
34
+ | Query-string preservation | Yes, opt-in | `redirect.query.pass` / `query.map` |
35
+ | Method-preserving redirect | Yes | `methods` plus `status: 307` or `308` |
36
+ | 404 for unmatched paths | Yes | `site.notFound` (project-relative `.html`) |
37
+ | Host or scheme chosen from the request | No | destination is a literal absolute `https://` URL or a root-relative path; report the gap |
38
+
39
+ ## Declarative-first
40
+
41
+ Use the highest-level declarative feature before writing a function or middleware. Custom code
42
+ only when the framework cannot express the requirement; then report the gap. Never invent fields
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)).
44
+
45
+ | I need | Use |
46
+ |---|---|
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)) |
50
+ | Restrict HTTP methods | `methods` (default GET/HEAD; 405 with `Allow`) |
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)) |
52
+ | Fixed JSON/text/headers | `respond` and `response.headers` |
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)) |
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`) |
57
+
58
+ When only code can do it, one function serves one or more routes:
59
+
60
+ ```yaml
61
+ /hello/{name}:
62
+ function: functions/hello.mjs # binds args.name; context.route.pattern is "/hello/{name}"
63
+ ```
64
+ ```js
65
+ export default (request, { args, route }) => Response.json({ hello: args.name });
66
+ ```
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
+
75
+ Handler for the response: fixed text or JSON is `respond`; one HTML file is `page`; a directory is
76
+ `static`; an attachment is `download`; a short HTML snippet is `respond` `text` with a
77
+ `Content-Type: text/html; charset=utf-8` header. Functions are trusted by default; add
78
+ `sandbox: true` to opt a route in ([function security](https://github.com/jimhoyd-com/urlcode/blob/main/docs/FUNCTION-SECURITY.md)).
79
+
80
+ After a real attempt, draft feedback only for a capability gap, repeated workaround, documentation
81
+ gap or suspected defect, with sanitized YAML and validation evidence. Search existing issues first;
82
+ never publish or comment without the user's approval.
83
+
84
+ ## Reference (load one only when needed)
85
+
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).
87
+ - Skills: [authoring](.claude/skills/urlcode-authoring/SKILL.md), [operations](.claude/skills/urlcode-operations/SKILL.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).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jimhoyd/urlcode",
3
- "version": "0.4.8",
3
+ "version": "0.5.5",
4
4
  "description": "Portable runtime for programmable URL behavior",
5
5
  "type": "module",
6
6
  "workspaces": [
@@ -62,6 +62,10 @@
62
62
  "types": "./dist/types/extensions.d.ts",
63
63
  "default": "./dist/extensions.js"
64
64
  },
65
+ "./extension-bundles": {
66
+ "types": "./dist/types/extension-bundles.d.ts",
67
+ "default": "./dist/extension-bundles.js"
68
+ },
65
69
  "./sandbox": {
66
70
  "types": "./dist/types/sandbox.d.ts",
67
71
  "default": "./dist/sandbox.js"
@@ -69,7 +73,7 @@
69
73
  "./package.json": "./package.json"
70
74
  },
71
75
  "files": [
72
- ".claude",
76
+ ".claude/skills",
73
77
  "dist",
74
78
  "schemas",
75
79
  "data",
@@ -81,19 +85,25 @@
81
85
  "llms-full.txt",
82
86
  "NOTICE",
83
87
  "recipes",
84
- "skills"
88
+ "skills",
89
+ "docs/AI-AUTHORING.md",
90
+ "docs/YAML-REFERENCE.md",
91
+ "docs/TOOLING.md",
92
+ "docs/FUNCTION-SECURITY.md"
85
93
  ],
86
94
  "scripts": {
87
95
  "build": "node --disable-warning=ExperimentalWarning scripts/build.ts",
96
+ "prepare": "node --disable-warning=ExperimentalWarning scripts/build.ts --quiet",
88
97
  "typecheck": "tsc -p tsconfig.json",
89
98
  "test": "node --conditions=development --test test/*.test.ts",
99
+ "test:shard": "node --conditions=development --test",
90
100
  "lint": "eslint .",
91
101
  "check": "npm run check:code && npm run check:docs",
92
102
  "check:code": "node scripts/check.ts && node scripts/check-release-tags.ts && node scripts/check-workspace-links.ts && node scripts/check-issue-labels.ts && npm run release:check",
93
103
  "test:workerd": "node scripts/workerd-parity.ts",
94
104
  "verify": "npm run lint && npm run typecheck && npm run check && npm run build && npm test && npm run verify:workspaces",
95
105
  "workspace:styles": "npm run styles --workspace @jimhoyd/urlcode-ui",
96
- "verify:workspaces": "npm run verify --workspace @jimhoyd/urlcode-ui && npm run verify --workspace @jimhoyd/urlcode-auth && npm run verify --workspace @jimhoyd/urlcode-admin && npm run verify --workspace @jimhoyd/urlcode-store && npm run audit:packages && npm run test:workspace-integration",
106
+ "verify:workspaces": "npm run verify --workspace @jimhoyd/urlcode-ui && npm run verify --workspace @jimhoyd/urlcode-auth && npm run verify --workspace @jimhoyd/urlcode-admin && npm run verify --workspace @jimhoyd/urlcode-store && npm run verify --workspace @jimhoyd/urlcode-forms && npm run audit:packages && npm run test:workspace-integration",
97
107
  "audit:packages": "node scripts/package-audit.ts --all",
98
108
  "test:package": "npm run build && npm run test:package:built",
99
109
  "dev": "node src/cli.ts dev --project starters/default",
@@ -110,6 +120,7 @@
110
120
  "docs:llms": "node scripts/build-llms-full.ts",
111
121
  "docs:cookbook-index": "node scripts/build-cookbook-index.ts",
112
122
  "artifacts:prepare": "node --disable-warning=ExperimentalWarning scripts/prepare-extension-artifacts.ts",
123
+ "bundles:prepare": "node --disable-warning=ExperimentalWarning scripts/prepare-extension-bundles.ts",
113
124
  "check:downstream-skills": "node scripts/check-downstream-skill-drift.ts",
114
125
  "sync:agents": "node scripts/sync-agent-lists.ts",
115
126
  "check:docs": "node scripts/check-trust-model-prose.ts && node scripts/check-version-statements.ts && node scripts/check-local-links.ts && node scripts/check-guidance-claims.ts && node scripts/generate-yaml-reference.ts --check && node scripts/build-llms-full.ts --check && node scripts/build-cookbook-index.ts --check && node scripts/generate-claude-plugin.ts --check",
@@ -14,8 +14,8 @@ Run `urlcode validate --local --project .` and `urlcode serve --project .`.
14
14
  default). Add top-level `site: {notFound: 404.html}` for a custom 404 page
15
15
  instead of the plain default.
16
16
 
17
- For the shapes this recipe does not cover — a wildcard/suffix redirect that
18
- matches any depth (`/legacy/*`), or a host/scheme-based redirect — run
17
+ For the shapes this recipe does not cover — a root-relative or `/**` suffix
18
+ redirect, or a host/scheme-based redirect — run
19
19
  `urlcode context --project . --task redirects` (MCP `get_context
20
20
  {"task":"redirects"}`) for the exact supported alternative and the exact
21
21
  validation error, or see [docs/OPEN-DECISIONS.md](../../docs/OPEN-DECISIONS.md).
@@ -1,8 +1,8 @@
1
1
  # Store CRUD
2
2
 
3
3
  `/api/todos/*` is a persistent JSON CRUD API. The project declares one
4
- collection and its mount; the operator-installed `store` extension
5
- (`@jimhoyd/urlcode-store`) serves it and keeps the data in the operator's
4
+ collection and its mount; the operator-installed `store` extension serves it
5
+ from a verified bundle and keeps the data in the operator's
6
6
  directory. There is no handler code. Full contract, limits and guarantees:
7
7
  [docs/STORE.md](../../docs/STORE.md).
8
8
 
@@ -10,20 +10,19 @@ directory. There is no handler code. Full contract, limits and guarantees:
10
10
 
11
11
  The store is not core and does not activate on its own.
12
12
 
13
- - The operator installs `@jimhoyd/urlcode-store` next to `@jimhoyd/urlcode`
14
- and registers it in a host file kept outside the project.
15
- - The package is on npm (`@jimhoyd/urlcode-store`).
16
- `urlcode init --with ui,auth,store` scaffolds a protected site from the
17
- published packages. A no-auth `init --with store` needs `--ack store:public-write`,
18
- which the core published at the store's first release does not have, so write the host file below by hand until a
19
- newer core is released.
13
+ - The operator selects the signed `store` bundle release and registers it in a
14
+ host file kept outside the project.
15
+ - `urlcode init --with ui,auth,store --bundle-release extension-bundles@v…`
16
+ scaffolds a protected site from verified bundles. A no-auth `init --with
17
+ store` needs `--ack store:public-write`.
20
18
  - The data directory must be outside the project. It is single-writer: one
21
19
  server process per directory.
22
20
 
23
21
  ```js
24
22
  // /operator/host.mjs -- trusted operator code, never part of the project
25
23
  import {inspectExtensionRevision} from '@jimhoyd/urlcode/extensions';
26
- import {storeExtension} from '@jimhoyd/urlcode-store';
24
+ import {loadExtensionBundle} from '@jimhoyd/urlcode/extension-bundles';
25
+ const {storeExtension} = await loadExtensionBundle(process.env.URLCODE_PROJECT, 'store');
27
26
  const projectSha256 = await inspectExtensionRevision(process.env.URLCODE_PROJECT);
28
27
  export default {extensions: [storeExtension({directory: '/operator/data/store', projectSha256})]};
29
28
  ```
@@ -7,7 +7,7 @@ targets: {self-hosted: conditional, cloudflare: refused, aws: conditional, verce
7
7
  routes: 1
8
8
  services:
9
9
  - name: store extension
10
- description: An operator host file registering storeExtension from @jimhoyd/urlcode-store, with a data directory outside the project. The operator installs the package; `urlcode init --with ui,auth,store` scaffolds a protected host, and the README shows a hand-written one.
10
+ description: An operator host file registering the verified store bundle, with a data directory outside the project. `urlcode init --with ui,auth,store --bundle-release extension-bundles@v…` scaffolds a protected host, and the README shows a hand-written one.
11
11
  grants:
12
12
  - kind: extension
13
13
  description: The registration pins projectSha256 to this exact revision; editing a collection or the mount needs operator review and a new pin.
@@ -703,6 +703,9 @@
703
703
  "env": {
704
704
  "type": "string",
705
705
  "pattern": "^[A-Za-z_][A-Za-z0-9_]*$"
706
+ },
707
+ "default": {
708
+ "type": "string"
706
709
  }
707
710
  },
708
711
  "required": [
@@ -15,7 +15,7 @@ static serving and authentication. Read this file before changing anything.
15
15
  (limits; `--target NAME` before promising a provider), `get_schema`,
16
16
  `recipes search TEXT`/`search_recipes` then `recipes add NAME --out DIR`,
17
17
  `explain` and, with an operator host file, `get_extensions`. Bare
18
- `capabilities` and `recipes list` are complete catalogs: fallback, not step one.
18
+ `capabilities` and `recipes list` are complete catalogs: fallback, not step one. Do not read or grep `llms-full.txt` or the packaged docs for a routine task.
19
19
  4. Use URLCode's highest-level declarative features whenever possible. Generate custom code only when the framework cannot express the requirement. Check supported extensions and recipes first; explain any capability gap.
20
20
 
21
21
  ## MCP
@@ -49,7 +49,7 @@ skill only in a React frontend with `components.json`; start with `shadcn info
49
49
  A `function`/`middleware` is trusted, in-process Node with only declared
50
50
  `args`/`env`/`secrets`. Add `sandbox: true` for code needing isolation, not
51
51
  merely untrusted input. The sandbox is text/JSON-only; use `proxy`/a binding and
52
- record the reason in `sandboxReason`.
52
+ record the reason in `sandboxReason`. Try `redirect` (relative or `/**`) or `respond` first; a function gets `context.route.pattern`.
53
53
 
54
54
  ## Checks that count as evidence
55
55