@jimhoyd/urlcode 0.4.0-alpha.1 → 0.4.0-alpha.3
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 +36 -22
- package/.claude/skills/urlcode-operations/SKILL.md +16 -22
- package/.claude-plugin/marketplace.json +1 -1
- package/CONTRIBUTING.md +20 -16
- package/README.md +83 -80
- package/ROADMAP.md +61 -331
- package/SECURITY.md +23 -8
- package/dist/BUILD-MANIFEST.json +42 -47
- package/dist/agents-guide.js +18 -18
- package/dist/build-static.js +136 -0
- package/dist/capabilities.js +85 -31
- package/dist/capability-query.js +0 -1
- package/dist/cli.js +24 -32
- package/dist/compliance-rules/baseline.js +2 -10
- package/dist/compliance-rules/privacy.js +5 -16
- package/dist/compliance-rules/shared.js +0 -2
- package/dist/compliance.js +6 -8
- package/dist/config.js +15 -8
- package/dist/context.js +9 -10
- package/dist/examples.js +2 -2
- package/dist/explain-cli.js +7 -5
- package/dist/explain.js +10 -5
- package/dist/extensions.js +61 -2
- package/dist/function-sources.js +34 -2
- package/dist/function-worker.js +3 -1
- package/dist/functions.js +84 -13
- package/dist/guest-api.js +29 -3
- package/dist/index.js +3 -6
- package/dist/manifest.js +11 -7
- package/dist/mcp-authoring.js +2 -2
- package/dist/mcp.js +1 -1
- package/dist/observability.js +1 -21
- package/dist/policies/cache.js +8 -3
- package/dist/policies.js +3 -1
- package/dist/policy.js +28 -9
- package/dist/prerender.js +4 -0
- package/dist/project-tests.js +3 -3
- package/dist/readiness.js +35 -9
- package/dist/route-diff.js +12 -5
- package/dist/router.js +5 -7
- package/dist/runtime.js +77 -58
- package/dist/sandbox.js +48 -0
- package/dist/scaffold.js +0 -0
- package/dist/scripts/operational-drills.js +12 -54
- package/dist/server.js +3 -29
- package/dist/tooling.js +1 -1
- package/dist/trusted-functions.js +210 -0
- package/dist/types/build-static.d.ts +43 -0
- package/dist/types/capabilities.d.ts +14 -5
- package/dist/types/compliance-rules/shared.d.ts +0 -2
- package/dist/types/compliance.d.ts +0 -3
- package/dist/types/config.d.ts +2 -1
- package/dist/types/context.d.ts +2 -1
- package/dist/types/examples.d.ts +1 -1
- package/dist/types/explain.d.ts +6 -0
- package/dist/types/extensions.d.ts +55 -0
- package/dist/types/function-sources.d.ts +4 -0
- package/dist/types/functions.d.ts +48 -5
- package/dist/types/guest-api.d.ts +1 -0
- package/dist/types/index.d.ts +3 -6
- package/dist/types/manifest.d.ts +5 -3
- package/dist/types/observability.d.ts +1 -14
- package/dist/types/project-tests.d.ts +1 -2
- package/dist/types/readiness.d.ts +12 -3
- package/dist/types/router.d.ts +2 -1
- package/dist/types/runtime.d.ts +0 -27
- package/dist/types/sandbox.d.ts +12 -0
- package/dist/types/scaffold.d.ts +0 -2
- package/dist/types/server.d.ts +1 -4
- package/dist/types/tooling.d.ts +3 -3
- package/dist/types/trusted-functions.d.ts +29 -0
- package/dist/types/types.d.ts +22 -8
- package/dist/types/verify-deployment.d.ts +2 -2
- package/dist/types.js +25 -5
- package/dist/typescript-authoring.js +67 -18
- package/dist/verify-deployment.js +3 -3
- package/docs/AI-AUTHORING.md +109 -10
- package/docs/ASSETS.md +2 -1
- package/docs/AUTH-BACKUP.md +32 -0
- package/docs/AWS.md +4 -4
- package/docs/BEST-PRACTICES.md +17 -8
- package/docs/CAPABILITIES.md +30 -17
- package/docs/CAPACITY.md +128 -31
- package/docs/CI-FOLLOWUP-2026-09-19.md +97 -0
- package/docs/CI-RELEASE-AUDIT-2026-09-19.md +322 -0
- package/docs/CI.md +8 -3
- package/docs/CLOUDFLARE.md +1 -2
- package/docs/CODEBASE-AUDIT-2026-09-20.md +278 -0
- package/docs/COMPLIANCE.md +6 -9
- package/docs/DEPLOYMENT-CHECKS.md +1 -1
- package/docs/DEVELOPMENT-PIPELINE.md +181 -0
- package/docs/EXTENSIONS.md +193 -11
- package/docs/FRAMEWORK.md +53 -33
- package/docs/FUNCTION-SECURITY.md +173 -32
- package/docs/INSTALL.md +0 -5
- package/docs/LOAD-TESTING.md +4 -4
- package/docs/LOCAL-DEVELOPMENT.md +3 -0
- package/docs/MIDDLEWARE.md +27 -16
- package/docs/MONITORING.md +2 -19
- package/docs/OBSERVABILITY.md +7 -16
- package/docs/OPEN-DECISIONS.md +184 -0
- package/docs/OPERATIONAL-PROOF.md +26 -30
- package/docs/OPERATIONS.md +23 -32
- package/docs/POLICIES.md +27 -8
- package/docs/PRERENDER.md +25 -13
- package/docs/PROJECT-DIRECTION.md +35 -10
- package/docs/READINESS.md +6 -2
- package/docs/README.md +20 -41
- package/docs/RELEASE-0.4.0-alpha.3.md +50 -0
- package/docs/RELEASE-READINESS.md +50 -30
- package/docs/RELEASE-SECURITY.md +72 -86
- package/docs/RESILIENCE.md +16 -15
- package/docs/ROUTING.md +7 -10
- package/docs/SANDBOX-REVIEW.md +19 -6
- package/docs/SCAFFOLDING.md +0 -2
- package/docs/SECURITY-AUDIT.md +42 -2
- package/docs/SPECIFICATION.md +63 -27
- package/docs/SPIKE-AI-FRAMEWORK-BENCHMARK.md +288 -0
- package/docs/SPIKE-BUSINESS-SUITE.md +16 -0
- package/docs/SPIKE-CORE-LAYERING.md +368 -0
- package/docs/SPIKE-DEFAULT-TRUST-MODEL.md +211 -0
- package/docs/SPIKE-LAMBDA-COMPILE.md +12 -2
- package/docs/STARTERS.md +1 -1
- package/docs/STATIC.md +105 -0
- package/docs/TOOLING.md +17 -12
- package/docs/TUNNELS.md +0 -3
- package/docs/TYPESCRIPT-AUTHORING.md +32 -12
- package/docs/TYPESCRIPT.md +25 -4
- package/docs/VERCEL.md +4 -5
- package/docs/VERSION-ALIGNMENT.md +46 -0
- package/docs/YAML-GUIDE.md +0 -3
- package/docs/YAML-REFERENCE.md +16 -6
- package/docs/archive/2026-09-19/EXTENSION-IMPLEMENTATION.md +68 -0
- package/docs/{MANAGEMENT-SECURITY.md → archive/2026-09-19/MANAGEMENT-SECURITY.md} +20 -0
- package/docs/{NEXT-PHASE-PLAN.md → archive/2026-09-19/NEXT-PHASE-PLAN.md} +26 -8
- package/docs/{NEXT-STEPS.md → archive/2026-09-19/NEXT-STEPS.md} +274 -43
- package/docs/archive/2026-09-19/OPEN-DECISIONS.md +277 -0
- package/docs/archive/2026-09-19/RELEASE-SECURITY.md +186 -0
- package/docs/archive/2026-09-19/ROADMAP.md +386 -0
- package/docs/{SPIKE-EXTENSION-MODEL.md → archive/2026-09-19/SPIKE-EXTENSION-MODEL.md} +12 -2
- package/docs/{SPIKE-EXTENSIONS.md → archive/2026-09-19/SPIKE-EXTENSIONS.md} +28 -12
- package/docs/archive/2026-09-19/SPIKE-MONOREPO.md +776 -0
- package/docs/{USABILITY-REVIEW.md → archive/2026-09-19/USABILITY-REVIEW.md} +18 -2
- package/docs/archive/README.md +27 -0
- package/docs/policies/agents.md +1 -1
- package/docs/policies/cache.md +13 -0
- package/docs/policies/compression.md +3 -2
- package/docs/policies/security.md +3 -2
- package/examples/assets/example.yaml +2 -2
- package/examples/aws/example.yaml +1 -1
- package/examples/cloudflare/example.yaml +1 -1
- package/examples/conditions/example.yaml +1 -1
- package/examples/cookbook/example.yaml +1 -1
- package/examples/cookbook/middleware/bucket.mjs +12 -2
- package/examples/cookbook/middleware/locale.mjs +7 -3
- package/examples/cookbook/route-index.json +1 -1
- package/examples/cookbook/routes/middleware.yaml +1 -1
- package/examples/egress/example.yaml +1 -1
- package/examples/extensions/example.yaml +1 -1
- package/examples/prerender/README.md +14 -6
- package/examples/prerender/example.yaml +1 -1
- package/examples/prerender/functions/page.mjs +4 -2
- package/examples/prerender/middleware/template.mjs +1 -1
- package/examples/prerender/prerender.mjs +1 -1
- package/examples/prerender/urlcode.yaml +8 -4
- package/examples/provider-conformance/example.yaml +1 -1
- package/examples/vercel/example.yaml +1 -1
- package/llms-full.txt +686 -239
- package/llms.txt +27 -15
- package/package.json +32 -5
- package/packaging/claude-plugin/.claude-plugin/plugin.json +2 -2
- package/packaging/claude-plugin/skills/urlcode-authoring/SKILL.md +36 -22
- package/packaging/claude-plugin/skills/urlcode-operations/SKILL.md +16 -22
- package/recipes/authenticated-json-api/README.md +4 -3
- package/recipes/authenticated-json-api/functions/profile.mjs +2 -1
- package/recipes/authenticated-json-api/recipe.yaml +2 -2
- package/recipes/contact-form/functions/contact.mjs +2 -1
- package/recipes/contact-form/recipe.yaml +3 -3
- package/recipes/cors-api/README.md +2 -2
- package/recipes/cors-api/recipe.yaml +2 -2
- package/recipes/health-page/README.md +1 -1
- package/recipes/health-page/recipe.yaml +1 -1
- package/recipes/json-api/README.md +1 -1
- package/recipes/json-api/recipe.yaml +4 -4
- package/recipes/middleware/README.md +8 -4
- package/recipes/middleware/middleware/bucket.mjs +12 -2
- package/recipes/middleware/middleware/locale.mjs +7 -3
- package/recipes/middleware/recipe.yaml +1 -1
- package/recipes/protected-download/README.md +1 -1
- package/recipes/protected-download/recipe.yaml +2 -2
- package/recipes/redirect/recipe.yaml +1 -1
- package/recipes/static-plus-api/README.md +2 -2
- package/recipes/static-plus-api/public/index.html +1 -1
- package/recipes/static-plus-api/recipe.yaml +2 -2
- package/recipes/static-plus-api/urlcode.yaml +1 -1
- package/recipes/typescript/README.md +2 -1
- package/recipes/typescript/recipe.yaml +5 -5
- package/recipes/webhook-receiver/README.md +5 -1
- package/recipes/webhook-receiver/recipe.yaml +2 -1
- package/recipes/webhook-receiver/urlcode.yaml +7 -0
- package/schemas/recipe.schema.json +4 -3
- package/schemas/urlcode.schema.json +14 -41
- package/skills/urlcode/SKILL.md +32 -11
- package/starters/default/AGENTS.md +18 -18
- package/starters/default/urlcode.yaml +0 -1
- package/dist/link-api.js +0 -136
- package/dist/link-cli.js +0 -141
- package/dist/link-events.js +0 -76
- package/dist/link-records.js +0 -31
- package/dist/link-store-worker.js +0 -150
- package/dist/link-store.js +0 -250
- package/dist/management-policy.js +0 -40
- package/dist/sqlite-version.js +0 -6
- package/dist/types/link-api.d.ts +0 -30
- package/dist/types/link-cli.d.ts +0 -37
- package/dist/types/link-events.d.ts +0 -27
- package/dist/types/link-records.d.ts +0 -11
- package/dist/types/link-store-worker.d.ts +0 -1
- package/dist/types/link-store.d.ts +0 -130
- package/dist/types/management-policy.d.ts +0 -8
- package/dist/types/sqlite-version.d.ts +0 -1
- package/docs/DYNAMIC-LINKS.md +0 -61
- package/docs/links/cli.md +0 -110
- package/docs/links/limits.md +0 -175
- package/docs/links/management-api.md +0 -80
- package/docs/links/pools.md +0 -75
- package/docs/links/setup.md +0 -135
- package/docs/yaml/links.md +0 -30
- package/examples/live-links/README.md +0 -11
- package/examples/live-links/example.yaml +0 -21
- package/examples/live-links/tests/requests.json +0 -6
- package/examples/live-links/urlcode.yaml +0 -16
package/docs/STATIC.md
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Deploying to static hosting (S3 + CloudFront)
|
|
2
|
+
|
|
3
|
+
The `static` target is the bottom rung of the [capability
|
|
4
|
+
ladder](FRAMEWORK.md#the-ladder):
|
|
5
|
+
the same `urlcode.yaml` a self-hosted server or a serverless adapter runs, with
|
|
6
|
+
no server process at all. `urlcode build --target static` compiles a project
|
|
7
|
+
ahead of time into plain files and two small JSON manifests meant for an S3
|
|
8
|
+
bucket served through CloudFront — nothing here executes a request.
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
urlcode build --target static --project . --out dist --origin https://links.example
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Declarative routes only, and less than that
|
|
15
|
+
|
|
16
|
+
This target serves **redirects**, **declared responses** (`respond:`) and
|
|
17
|
+
static files (`page`, `static`, `download`) — no path parameters, no query
|
|
18
|
+
passthrough or mapping, both GET and HEAD required, `respond.status: 200` only, and no `enabled: false` or `expires`
|
|
19
|
+
(there is no server to answer a disabled or expired route with 404/410, so the
|
|
20
|
+
build refuses one instead of silently serving it forever). Everything else is
|
|
21
|
+
refused **at build time**, with the route pattern and the reason named:
|
|
22
|
+
|
|
23
|
+
| Handler / feature | Why it is refused |
|
|
24
|
+
| --- | --- |
|
|
25
|
+
| `function`, `middleware` | no server, so no dynamic or sandboxed execution |
|
|
26
|
+
| `extension`, `policies.extensions` | no server, so no operator extension registry |
|
|
27
|
+
| `proxy`, `signals` | no server, so no bounded or fire-and-forget egress |
|
|
28
|
+
| `conditional`, `match` (`conditions`) | no server, so no request-time condition matching |
|
|
29
|
+
| `parameters`, `request.body` | no server, so no request-time validation |
|
|
30
|
+
| `response.headers` | no server, so no per-request headers; set them as S3 object metadata or a CloudFront response headers policy instead |
|
|
31
|
+
| `env`, `secrets` (`bindings`) | no server, so no per-request binding resolution |
|
|
32
|
+
| every `policies.*` | no server, so no runtime policy enforcement |
|
|
33
|
+
| a redirect with a `{parameter}` in its path | S3's per-object redirect is keyed to one exact object, not a pattern |
|
|
34
|
+
| a redirect with `query.pass`/`query.map` | S3's per-object redirect cannot compute a target per request |
|
|
35
|
+
| a redirect with a `status` other than 301 | S3's per-object website redirect always answers 301 |
|
|
36
|
+
| a route not admitting both GET and HEAD, or admitting other methods | the output cannot enforce a different method set |
|
|
37
|
+
| `respond.status` other than 200 | an uploaded response object cannot preserve a custom HTTP status |
|
|
38
|
+
| a route with `enabled: false` or `expires` | no server to answer a disabled/expired route; remove the route instead |
|
|
39
|
+
|
|
40
|
+
Run `urlcode capabilities --target static` for the full catalog.
|
|
41
|
+
|
|
42
|
+
## What the build emits
|
|
43
|
+
|
|
44
|
+
`--out` (default `dist/static`) receives:
|
|
45
|
+
|
|
46
|
+
- `objects/<key>` — the actual files to upload, one per served route. A `page`
|
|
47
|
+
or `download` route becomes one file; a `static` mount becomes one file per
|
|
48
|
+
entry in its directory. Object keys match the S3 convention: the route
|
|
49
|
+
pattern with its leading `/` stripped, and `/` itself becomes `index.html`
|
|
50
|
+
(matching a bucket's own "Index document" setting). A redirect route also
|
|
51
|
+
gets a zero-byte placeholder object at its key, so it exists to carry
|
|
52
|
+
metadata.
|
|
53
|
+
- `objects.json` — `{ format, objects: [{ key, contentType, cacheControl?,
|
|
54
|
+
contentDisposition? }] }`. Plain file upload loses this metadata (S3 does not
|
|
55
|
+
reliably infer content type or cache headers from an extension-less key), so
|
|
56
|
+
a deploy step reads this file and sets each object's own `Content-Type`,
|
|
57
|
+
`Cache-Control` and `Content-Disposition` from it, for example with
|
|
58
|
+
`aws s3 cp --content-type ... --cache-control ...` per entry, or an
|
|
59
|
+
equivalent `aws s3 sync` post-processing step.
|
|
60
|
+
- `redirects.json` — `{ format, redirects: [{ key, location, status: 301 }] }`.
|
|
61
|
+
Each entry is applied as the S3 object's
|
|
62
|
+
[website redirect location](https://docs.aws.amazon.com/AmazonS3/latest/userguide/how-to-page-redirect.html)
|
|
63
|
+
metadata (`x-amz-website-redirect-location`), for example
|
|
64
|
+
`aws s3api put-object --website-redirect-location <location> --bucket ... --key <key>`.
|
|
65
|
+
S3 always answers a request for that key with a 301 to `location`
|
|
66
|
+
regardless of the object's own content — this is why a declared `status`
|
|
67
|
+
other than 301 is refused rather than silently downgraded.
|
|
68
|
+
- `manifest.json` — the same project-level semantic manifest every target
|
|
69
|
+
writes (see [tooling](TOOLING.md)).
|
|
70
|
+
|
|
71
|
+
None of these are edited by hand, and `dist/` belongs in `.gitignore`. This
|
|
72
|
+
target ships no runtime import (there is nothing to run), so there is no
|
|
73
|
+
`@jimhoyd/urlcode/static` entry point — the build output is the deployment.
|
|
74
|
+
|
|
75
|
+
## What this is not: GitHub Pages
|
|
76
|
+
|
|
77
|
+
**This target's claimed support is S3 + CloudFront, not GitHub Pages.**
|
|
78
|
+
GitHub Pages has no per-object redirect metadata and no server-side rewrite
|
|
79
|
+
layer, so a `redirect` route compiled the way this target compiles it (S3
|
|
80
|
+
object metadata) has no equivalent there — the only options are a
|
|
81
|
+
meta-refresh/JavaScript page (visibly a redirect, not an HTTP one: search
|
|
82
|
+
engines, curl and anything that does not run JavaScript sees the source page,
|
|
83
|
+
not a 3xx) or a static 404-page trick, both lower fidelity than what every
|
|
84
|
+
other target in this project does for the same route. Rather than claim a
|
|
85
|
+
portability promise this platform cannot keep, GitHub Pages is out of scope
|
|
86
|
+
for this target. If you need Pages, treat it as a distinct target with its own
|
|
87
|
+
explicit fidelity caveat, not a rename of this one.
|
|
88
|
+
|
|
89
|
+
## Verification status
|
|
90
|
+
|
|
91
|
+
This target has local build tests only (`test/static.test.ts`): the compiled
|
|
92
|
+
object layout, the redirect manifest, and every refusal above. **It has not
|
|
93
|
+
been deployed to S3 or fronted by CloudFront.** Bucket policy, CloudFront
|
|
94
|
+
caching behavior, TLS/domain setup and the exact `aws s3` invocations above are
|
|
95
|
+
unverified until a real deployment exercises them.
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
## Building pages with middleware
|
|
99
|
+
|
|
100
|
+
Use [prerendering](PRERENDER.md) to execute functions and native middleware at
|
|
101
|
+
build time, then export the generated native page routes with this target.
|
|
102
|
+
Trusted Node execution is the build default; `sandbox: true` retains its
|
|
103
|
+
restricted imports and resource limits. Neither mode adds a request-time server
|
|
104
|
+
to the static output. Authentication, request-dependent headers and other
|
|
105
|
+
per-request middleware cannot be baked into a public file safely.
|
package/docs/TOOLING.md
CHANGED
|
@@ -76,7 +76,7 @@ network. Keys always appear in this order:
|
|
|
76
76
|
- `urlcode` (package version) and `schema` (`"1"`).
|
|
77
77
|
- `project`: entry file, route count, handlers used with counts, extensions
|
|
78
78
|
declared, policies in effect at the top level and the number of routes each
|
|
79
|
-
policy applies to, requested env and secret binding names,
|
|
79
|
+
policy applies to, requested env and secret binding names,
|
|
80
80
|
`site` keys, and `files` (include, function and middleware paths). With
|
|
81
81
|
`--host-file`, `host` counts the operator module's extensions and plugins
|
|
82
82
|
without activating them.
|
|
@@ -113,13 +113,17 @@ checks. Build output remains an explicit separate build API/CLI operation.
|
|
|
113
113
|
|
|
114
114
|
The package root also exports existing operator-invoked workflow APIs:
|
|
115
115
|
`buildCloudflare(project, options)` compiles and writes a Cloudflare artifact;
|
|
116
|
-
`
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
`
|
|
122
|
-
|
|
116
|
+
`buildStatic(project, options)` compiles redirects and static files into plain
|
|
117
|
+
objects and redirect metadata for S3 + CloudFront (see [static
|
|
118
|
+
hosting](STATIC.md)); `runProjectTests(project, options)` starts the local
|
|
119
|
+
runtime, executes request fixtures and closes it; `scaffoldProject(project,
|
|
120
|
+
{dryRun})` creates missing placeholders while preserving existing files;
|
|
121
|
+
`initProject(destination)` creates the standard starter; and
|
|
122
|
+
`addRedirect(project, destination, alias?)` updates project YAML under the
|
|
123
|
+
authoring lock. `CloudflareBuildOptions`, `CloudflareBuildReport`,
|
|
124
|
+
`StaticBuildOptions`, `StaticBuildReport`, `ProjectTestOptions`,
|
|
125
|
+
`ProjectTestResult`, `ScaffoldReport` and `ScaffoldUnresolved` describe these
|
|
126
|
+
existing operations.
|
|
123
127
|
|
|
124
128
|
These SDK functions have explicit write or execution effects and are available
|
|
125
129
|
to trusted callers only. Project tests use normal runtime activation, grants and
|
|
@@ -133,8 +137,8 @@ assistant file-write, guest-execution, deployment or network authority.
|
|
|
133
137
|
|
|
134
138
|
`urlcode explain [/route] [--project DIR] [--target T] [--host-file F] [--json]`
|
|
135
139
|
prints what `explainRoute` returns: one route in detail, or without a path a
|
|
136
|
-
one-line-per-route table (methods, handler, state,
|
|
137
|
-
cache outcome and target support). `--target` narrows the support columns to
|
|
140
|
+
one-line-per-route table (methods, handler, state, execution mode, middleware
|
|
141
|
+
count, policies, cache outcome and target support). `--target` narrows the support columns to
|
|
138
142
|
one deployment target; `--host-file` supplies the operator registry so
|
|
139
143
|
extension requirements show their provider. An unknown route exits 1 and names
|
|
140
144
|
the nearest patterns. Everything comes from the compiled configuration: no
|
|
@@ -144,13 +148,14 @@ request is evaluated, no function runs and no binding is read.
|
|
|
144
148
|
`schemaVersion`, the `urlcode` version, the entry file and its includes, the
|
|
145
149
|
`revision` (the same digest `inspectExtensionRevision` returns, so an operator
|
|
146
150
|
pin can be checked against it), the config `configVersion`, every route (path,
|
|
147
|
-
methods, handler, state,
|
|
151
|
+
methods, handler, state, execution mode (`sandbox`, with `sandboxReason` when
|
|
152
|
+
the route declares one), middleware, inputs, policy names, extension
|
|
148
153
|
requirements, cache outcome, binding names, egress origins, capabilities and
|
|
149
154
|
per-target support), the union of capabilities used, extension declarations
|
|
150
155
|
(version, configuration keys, mounts and protected routes), recipe provenance
|
|
151
156
|
(from a `recipe.yaml` beside the entry file when one exists), external
|
|
152
157
|
requirements (environment and secret names, proxy and signal origins,
|
|
153
|
-
extensions
|
|
158
|
+
extensions), the function and middleware
|
|
154
159
|
modules with the routes that use them, and per-target compatibility. Without
|
|
155
160
|
`--json` a short summary prints. The manifest is deterministic: the same
|
|
156
161
|
project produces the same bytes. `urlcode build` writes the same document as
|
package/docs/TUNNELS.md
CHANGED
|
@@ -65,9 +65,6 @@ scanners that find it within minutes.
|
|
|
65
65
|
- The runtime has **no authentication and no rate limiting**. Put access control
|
|
66
66
|
in the tunnel: ngrok's OAuth, OIDC or basic auth; Cloudflare Access; a
|
|
67
67
|
Tailscale ACL.
|
|
68
|
-
- **Never tunnel the link-management API.** It is a separate listener bound to
|
|
69
|
-
loopback on purpose, holding credentials that can rewrite live links. Tunnel
|
|
70
|
-
the application port only.
|
|
71
68
|
- Prefer `serve` with a fixed snapshot, a project containing no real secrets,
|
|
72
69
|
and a tunnel you shut down when finished.
|
|
73
70
|
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
# Build-time TypeScript guests
|
|
2
2
|
|
|
3
3
|
TypeScript guest authoring is a separate build step. Serving still accepts only
|
|
4
|
-
JavaScript ES modules
|
|
5
|
-
|
|
4
|
+
JavaScript ES modules. The build never imports application modules into Node
|
|
5
|
+
or runs application code, and it is `sandbox`-aware per route
|
|
6
|
+
(docs/SPIKE-DEFAULT-TRUST-MODEL.md): a route that declares `sandbox: true` is
|
|
7
|
+
transpiled under the sandbox's own module rules (relative imports only, no
|
|
8
|
+
dynamic import/bare specifiers, the module/size limits below), exactly as
|
|
9
|
+
before; a trusted (non-`sandbox: true`) route is transpiled without those
|
|
10
|
+
import/size restrictions, since it will run with full Node access — bare/npm
|
|
11
|
+
imports, dynamic `import()`, `import.meta` — once served. Both modes still
|
|
12
|
+
diagnose only syntax, not semantics, and neither imports application code into
|
|
13
|
+
the build process in a way that executes it.
|
|
6
14
|
|
|
7
15
|
```sh
|
|
8
16
|
urlcode recipes add typescript --out ./hello-source
|
|
@@ -29,17 +37,29 @@ The trusted pinned TypeScript compiler transpiles ES2022/ES modules with fixed
|
|
|
29
37
|
settings. It does not read `tsconfig.json`, package scripts, plugins, compiler
|
|
30
38
|
transformers, dependency packages, Node declarations or ambient environment
|
|
31
39
|
files. It diagnoses syntax errors, but does **not** perform semantic type
|
|
32
|
-
checking
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
outside the project are refused. No import extension inference occurs.
|
|
40
|
+
checking, in either mode. CommonJS import/export syntax and imports outside
|
|
41
|
+
the project are always refused. Type-only relative imports are erased without
|
|
42
|
+
reading their targets.
|
|
36
43
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
44
|
+
For a `sandbox: true` route, bare/npm imports (including static type-only
|
|
45
|
+
imports), dynamic runtime imports, `import.meta` and import attributes are
|
|
46
|
+
refused, and the source graph is limited to 128 modules, 1 MiB per source and
|
|
47
|
+
4 MiB aggregate; the emitted graph must also pass the runtime's own sandboxed
|
|
48
|
+
source parser and byte limits before publication. For a trusted route, none of
|
|
49
|
+
that applies: bare/npm specifiers, dynamic `import()`, `import.meta` and
|
|
50
|
+
import attributes pass through unchanged (resolved by Node at serve time, not
|
|
51
|
+
by this build), and there is no module-count or aggregate-size ceiling — only
|
|
52
|
+
a generous 16 MiB per-source read cap that bounds authoring-time memory. A
|
|
53
|
+
module may be shared by trusted and sandboxed routes: it is emitted once, and
|
|
54
|
+
every module reachable from a `sandbox: true` route is still validated under
|
|
55
|
+
the sandbox rules and budgets above, which does not disqualify the trusted
|
|
56
|
+
route that also imports it. In both modes,
|
|
57
|
+
no import extension inference occurs — relative imports of project modules
|
|
58
|
+
still need an explicit `.ts`/`.js`/`.mjs` extension to be rewritten and
|
|
59
|
+
followed. This does not execute the modules or replace normal route, policy,
|
|
60
|
+
binding or sandbox validation at activation. Unsupported host/browser APIs
|
|
61
|
+
remain unavailable in QuickJS, even if TypeScript accepts their names. Run
|
|
62
|
+
`urlcode validate --local` and project tests on the output.
|
|
43
63
|
|
|
44
64
|
Includes are flattened into a duplicate-checked entry document. Only referenced
|
|
45
65
|
modules, page/download assets, static trees, site favicon/llms files and the
|
package/docs/TYPESCRIPT.md
CHANGED
|
@@ -16,7 +16,7 @@ beside them, and `dist/BUILD-MANIFEST.json` with a SHA-256 per emitted file.
|
|
|
16
16
|
| Import | Runtime | Declarations |
|
|
17
17
|
|---|---|---|
|
|
18
18
|
| `urlcode` | `dist/index.js` | `dist/types/index.d.ts` |
|
|
19
|
-
| `@jimhoyd/urlcode/plugins`, `@jimhoyd/urlcode/policies`, `@jimhoyd/urlcode/observability`, `@jimhoyd/urlcode/compliance`, `@jimhoyd/urlcode/prerender`, `@jimhoyd/urlcode/extensions` | `dist/<name>.js` | `dist/types/<name>.d.ts` |
|
|
19
|
+
| `@jimhoyd/urlcode/plugins`, `@jimhoyd/urlcode/policies`, `@jimhoyd/urlcode/observability`, `@jimhoyd/urlcode/compliance`, `@jimhoyd/urlcode/prerender`, `@jimhoyd/urlcode/extensions`, `@jimhoyd/urlcode/sandbox` | `dist/<name>.js` | `dist/types/<name>.d.ts` |
|
|
20
20
|
| `@jimhoyd/urlcode/aws`, `@jimhoyd/urlcode/vercel`, `@jimhoyd/urlcode/cloudflare` | `dist/<name>.js` | `dist/types/<name>.d.ts` |
|
|
21
21
|
| `@jimhoyd/urlcode/schema` | `schemas/urlcode.schema.json` | — |
|
|
22
22
|
|
|
@@ -36,9 +36,7 @@ release cannot ship a declaration that does not resolve.
|
|
|
36
36
|
## The main exported types
|
|
37
37
|
|
|
38
38
|
- `urlcode`: `Runtime`, `RuntimeOptions`, `RuntimeRequest`, `RequestTrace`,
|
|
39
|
-
`Server`, `ServerOptions`, `HostPlugin`, `Observer`, `TestPlan
|
|
40
|
-
`LinkRow`, `LinkStoreOptions`, `LinkReader`, `LinkStoreBinding`, `LinkApi`,
|
|
41
|
-
`LinkApiOptions`, `LinkEvent`, `LinkObserverOptions`.
|
|
39
|
+
`Server`, `ServerOptions`, `HostPlugin`, `Observer`, `TestPlan`.
|
|
42
40
|
- `@jimhoyd/urlcode/plugins`: `Plugin`, `PluginRuntime`, `PolicyRequest`,
|
|
43
41
|
`HandlerResult`, `HeaderPair`, `TargetName`. See [plugins](PLUGINS.md).
|
|
44
42
|
- `@jimhoyd/urlcode/policies`: `PolicyModule`, `PolicyRegistry`, `PolicyRequest`,
|
|
@@ -54,6 +52,29 @@ release cannot ship a declaration that does not resolve.
|
|
|
54
52
|
- `@jimhoyd/urlcode/aws`, `@jimhoyd/urlcode/vercel`, `@jimhoyd/urlcode/cloudflare`: `LambdaEvent`,
|
|
55
53
|
`LambdaHandler`, `LambdaHandlerOptions`; `VercelHandler`,
|
|
56
54
|
`VercelHandlerOptions`; `Artifact`, `WorkerRoute`, `Validators`.
|
|
55
|
+
- `@jimhoyd/urlcode/sandbox`: `SandboxPool`, `SandboxEntry`, `SandboxTarget`,
|
|
56
|
+
`SandboxInvocation`, `SandboxPoolOptions`, `functionFile`. The public
|
|
57
|
+
sandboxed-execution primitive: the same QuickJS/worker-thread engine that
|
|
58
|
+
already backs a `sandbox: true` `function`/`middleware` route
|
|
59
|
+
(`FunctionPool`, internally), generalized to an explicit list of
|
|
60
|
+
`{source, export}` entries instead of anything route/YAML-shaped, for an
|
|
61
|
+
extension package that needs to run a project-supplied hook through real
|
|
62
|
+
isolation when the project's own config declares `sandbox: true` on it
|
|
63
|
+
(see [EXTENSIONS.md](EXTENSIONS.md#project-level-lifecycle-hooks) and
|
|
64
|
+
[FUNCTION-SECURITY.md](FUNCTION-SECURITY.md)). There is no trusted-mode
|
|
65
|
+
export here: a hook that does not declare `sandbox: true` is ordinary
|
|
66
|
+
project code the extension `import()`s directly via
|
|
67
|
+
`ExtensionActivation.root`, no primitive required.
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
import { SandboxPool, functionFile } from '@jimhoyd/urlcode/sandbox';
|
|
71
|
+
|
|
72
|
+
const source = await functionFile(root, hookConfig.source); // root: ExtensionActivation.root
|
|
73
|
+
const entries = [{ source, export: hookConfig.export ?? 'default' }];
|
|
74
|
+
const pool = await new SandboxPool(entries, { root, workers: 1 }).start();
|
|
75
|
+
const result = await pool.execute({ entry: entries[0] }, request, context, undefined);
|
|
76
|
+
await pool.close();
|
|
77
|
+
```
|
|
57
78
|
|
|
58
79
|
```ts
|
|
59
80
|
import { startServer, type ServerOptions, type Observer } from '@jimhoyd/urlcode';
|
package/docs/VERCEL.md
CHANGED
|
@@ -5,8 +5,8 @@ The Vercel adapter runs a URLCode project as a Node function. The same
|
|
|
5
5
|
that is the point of the project format.
|
|
6
6
|
|
|
7
7
|
**This adapter serves native handlers only:** redirects, validated responses,
|
|
8
|
-
pages, static assets and downloads.
|
|
9
|
-
|
|
8
|
+
pages, static assets and downloads. `function` and `middleware` routes are
|
|
9
|
+
refused at activation, trusted or sandboxed alike, not per request, so a deployment cannot
|
|
10
10
|
half-work. See [what is not supported](#what-this-adapter-does-not-do).
|
|
11
11
|
|
|
12
12
|
A working project is in [`examples/vercel/`](../examples/vercel/).
|
|
@@ -71,9 +71,8 @@ and want it in generated URLs.
|
|
|
71
71
|
|
|
72
72
|
| Not supported | Why |
|
|
73
73
|
|---|---|
|
|
74
|
-
|
|
|
75
|
-
| Middleware | Runs in the same
|
|
76
|
-
| Stored live links | SQLite needs a durable writable file. A serverless filesystem is ephemeral and per-instance, so records would silently diverge between instances. |
|
|
74
|
+
| `function` routes | They need the self-hosted Node lifecycle; a `sandbox: true` route would additionally spawn worker threads and load the WASM engine on every cold start. Correctness is not the issue; predictable latency is, and it is unmeasured. |
|
|
75
|
+
| Middleware | Runs in the same execution mode as the route's function, and is refused with it. |
|
|
77
76
|
| `urlcode serve` operational endpoints | `/_urlcode/health` and `/_urlcode/ready` describe a long-lived process. Use Vercel's own observability. |
|
|
78
77
|
|
|
79
78
|
Each refusal happens at activation with a message naming the route, so you find
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Package and channel alignment
|
|
2
|
+
|
|
3
|
+
The package manifests and root lockfile are the version authority. Read live
|
|
4
|
+
registry and Git tag state with `npm run release:status`; do not maintain a
|
|
5
|
+
second table of changing version numbers in documentation.
|
|
6
|
+
|
|
7
|
+
| Package | Manifest | Version owner | Release tag |
|
|
8
|
+
| --- | --- | --- | --- |
|
|
9
|
+
| `@jimhoyd/urlcode` | `package.json` | Explicit core release PR | `v<version>` |
|
|
10
|
+
| `@jimhoyd/urlcode-ui` | `packages/ui/package.json` | Changesets | `@jimhoyd/urlcode-ui@<version>` |
|
|
11
|
+
| `@jimhoyd/urlcode-auth` | `packages/auth/package.json` | Changesets | `@jimhoyd/urlcode-auth@<version>` |
|
|
12
|
+
| `@jimhoyd/urlcode-admin` | `packages/admin/package.json` | Changesets | `@jimhoyd/urlcode-admin@<version>` |
|
|
13
|
+
|
|
14
|
+
Development uses workspace source. Auth and admin's `file:../..` development
|
|
15
|
+
links resolve core to this checkout, enforced by `check-workspace-links.ts`.
|
|
16
|
+
Core never imports extension packages. Release verification instead installs the
|
|
17
|
+
published lower bound of each declared peer range and checks resolution. A peer
|
|
18
|
+
floor rises when code requires a newly introduced API, not just because a sibling
|
|
19
|
+
published another version. Preserve the declared upper bound during Changesets
|
|
20
|
+
versioning; `.changeset/config.json` limits unnecessary peer rewrites.
|
|
21
|
+
|
|
22
|
+
Publishable workspace changes carry Changesets; the release PR applies them and
|
|
23
|
+
updates versions, changelogs and the lockfile together. Core stays an explicit
|
|
24
|
+
entry in that PR until a separately reviewed workspace migration. Its CLI banner
|
|
25
|
+
must match its manifest. `npm run release:check` rejects stale lockfile versions.
|
|
26
|
+
Unreleased source changes do not require moving a published tag or pretending a
|
|
27
|
+
new package has already shipped.
|
|
28
|
+
|
|
29
|
+
Alpha releases publish under `alpha`; they never automatically move npm
|
|
30
|
+
`latest`. Core's historical `latest` remains the stable 0.3.0 baseline until an
|
|
31
|
+
explicit stable release decision. Extensions have historical alpha versions on
|
|
32
|
+
`latest`; subsequent alpha publication does not keep that channel in lockstep.
|
|
33
|
+
Different channel values alone are not drift. Test the install combination you
|
|
34
|
+
recommend against peer ranges; a bare install may select an older channel.
|
|
35
|
+
`release:status` reports each declared peer floor and whether its current
|
|
36
|
+
`latest` and `alpha` satisfy the range.
|
|
37
|
+
|
|
38
|
+
The standalone `urlcode-template` is an external exact-version consumer: after a
|
|
39
|
+
runtime release, update its dependency and starter through its own reviewed PR.
|
|
40
|
+
It is not automatically released by the monorepo coordinator. The retired
|
|
41
|
+
`urlcode-docs`, `urlcode-middleware`, `urlcode-dynamic-link` and `urlcode-short`
|
|
42
|
+
repositories are not release targets.
|
|
43
|
+
|
|
44
|
+
See [the development pipeline](DEVELOPMENT-PIPELINE.md) for preparation,
|
|
45
|
+
publication order, immutable retries and credential scope, and
|
|
46
|
+
[release security](RELEASE-SECURITY.md) for provenance and limitations.
|
package/docs/YAML-GUIDE.md
CHANGED
|
@@ -37,7 +37,6 @@ Each page holds the recipes for one task; the section numbers continue across pa
|
|
|
37
37
|
| [Pages, static folders and downloads](yaml/assets.md) | 10. Pages, static folders, downloads and MIME |
|
|
38
38
|
| [Enable, disable and expire](yaml/conditions.md) | 11. Enable, disable and expire |
|
|
39
39
|
| [Bindings, split files and tests](yaml/organization.md) | 12. Environment and secret references; 13. Split files and folders; 14. Assert inputs and outputs |
|
|
40
|
-
| [Live short-link records](yaml/links.md) | 15. Live short-link records |
|
|
41
40
|
| [Policies and profiles](yaml/policies.md) | 16. Hardened profile and per-route overrides |
|
|
42
41
|
| [Site conventions](yaml/site.md) | 17. Site conventions |
|
|
43
42
|
|
|
@@ -56,5 +55,3 @@ Each page holds the recipes for one task; the section numbers continue across pa
|
|
|
56
55
|
| Automatic hot updates in `serve` | Deploy/restart or use the embedding reload API deliberately |
|
|
57
56
|
| “All examples are production-ready” | Validate your security, load and deployment requirements separately |
|
|
58
57
|
|
|
59
|
-
Live-link recipes require `dynamicLinks: true` in the entry `urlcode.yaml`; see
|
|
60
|
-
[live short-link records](yaml/links.md) and [dynamic-link opt-in](DYNAMIC-LINKS.md#explicit-project-opt-in).
|
package/docs/YAML-REFERENCE.md
CHANGED
|
@@ -20,6 +20,8 @@ schema-valid combinations activate successfully.
|
|
|
20
20
|
| `routes.*.methods` | array | no | default: ["GET","HEAD"]; minItems: 1; uniqueItems: true |
|
|
21
21
|
| `routes.*.methods[]` | string | no | enum: ["GET","HEAD","POST","PUT","PATCH","DELETE","OPTIONS"] |
|
|
22
22
|
| `routes.*.enabled` | boolean | no | — |
|
|
23
|
+
| `routes.*.sandbox` | boolean | no | default: false |
|
|
24
|
+
| `routes.*.sandboxReason` | string | no | maxLength: 500 |
|
|
23
25
|
| `routes.*.expires` | string | no | — |
|
|
24
26
|
| `routes.*.description` | string | no | maxLength: 1024 |
|
|
25
27
|
| `routes.*.parameters` | array | no | maxItems: 64 |
|
|
@@ -113,11 +115,6 @@ schema-valid combinations activate successfully.
|
|
|
113
115
|
| `routes.*.middleware[] (option 2)` | object | no | unknown keys rejected |
|
|
114
116
|
| `routes.*.middleware[] (option 2).source` | string | yes | maxLength: 1024 |
|
|
115
117
|
| `routes.*.middleware[] (option 2).export` | string | no | pattern: "^[A-Za-z_][A-Za-z0-9_]*$" |
|
|
116
|
-
| `routes.*.link` | object | no | unknown keys rejected |
|
|
117
|
-
| `routes.*.link.collection` | string | yes | pattern: "^[A-Za-z][A-Za-z0-9_-]{0,63}$" |
|
|
118
|
-
| `routes.*.link.code` | object | yes | unknown keys rejected |
|
|
119
|
-
| `routes.*.link.code.from` | constant | yes | const: "path" |
|
|
120
|
-
| `routes.*.link.code.name` | string | yes | pattern: "^[A-Za-z_][A-Za-z0-9_]*$" |
|
|
121
118
|
| `routes.*.policies` | object | no | unknown keys rejected |
|
|
122
119
|
| `routes.*.policies.profile` | string | no | pattern: "^[a-z][a-z0-9-]{0,63}$" |
|
|
123
120
|
| `routes.*.policies.throttle` | one of the shapes below | no | — |
|
|
@@ -268,9 +265,22 @@ schema-valid combinations activate successfully.
|
|
|
268
265
|
| `routes.*.auth (option 2).verified` | boolean | no | — |
|
|
269
266
|
| `routes.*.auth (option 2).freshWithinSeconds` | integer | no | minimum: 1; maximum: 3600 |
|
|
270
267
|
| `routes.*.auth (option 2).onDeny` | number / string | no | enum: [401,403,404,"sign-in"] |
|
|
268
|
+
| `routes.*.cache` | object | no | unknown keys rejected |
|
|
269
|
+
| `routes.*.cache.strategy` | string | no | enum: ["no-store","revalidate","public","immutable","swr","sie","micro","cdn-only","private"] |
|
|
270
|
+
| `routes.*.cache.maxAge` | integer | no | minimum: 0; maximum: 31536000 |
|
|
271
|
+
| `routes.*.cache.staleWhileRevalidate` | integer | no | minimum: 0; maximum: 31536000 |
|
|
272
|
+
| `routes.*.cache.staleIfError` | integer | no | minimum: 0; maximum: 31536000 |
|
|
273
|
+
| `routes.*.cache.cdnMaxAge` | integer | no | minimum: 0; maximum: 31536000 |
|
|
274
|
+
| `routes.*.cache.originTtl` | integer | no | minimum: 0; maximum: 86400 |
|
|
275
|
+
| `routes.*.cache.vary` | array | no | maxItems: 8; uniqueItems: true |
|
|
276
|
+
| `routes.*.cache.vary[]` | string | no | minLength: 1; maxLength: 128 |
|
|
277
|
+
| `routes.*.cache.statuses` | array | no | maxItems: 16; uniqueItems: true |
|
|
278
|
+
| `routes.*.cache.statuses[]` | integer | no | minimum: 200; maximum: 599 |
|
|
279
|
+
| `routes.*.cache.maxBytes` | integer | no | minimum: 0; maximum: 16777216 |
|
|
280
|
+
| `routes.*.cache.maxEntries` | integer | no | minimum: 1; maximum: 1000000 |
|
|
281
|
+
| `routes.*.cache.force` | boolean | no | default: false |
|
|
271
282
|
| `includes` | array | no | maxItems: 256; uniqueItems: true |
|
|
272
283
|
| `includes[]` | string | no | maxLength: 1024 |
|
|
273
|
-
| `dynamicLinks` | boolean | no | default: false |
|
|
274
284
|
| `policies` | object | no | unknown keys rejected |
|
|
275
285
|
| `policies.profile` | string | no | pattern: "^[a-z][a-z0-9-]{0,63}$" |
|
|
276
286
|
| `policies.throttle` | one of the shapes below | no | — |
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Historical record
|
|
2
|
+
|
|
3
|
+
Archived 2026-09-19. This records an earlier implementation or proposal, not
|
|
4
|
+
current instructions. See the [current roadmap](../../../ROADMAP.md),
|
|
5
|
+
[current contract](../../SPECIFICATION.md) and [open decisions](../../OPEN-DECISIONS.md).
|
|
6
|
+
Remaining acceptance work is not declared complete by archiving this record.
|
|
7
|
+
|
|
8
|
+
<!-- trust-model-prose: historical-file -->
|
|
9
|
+
<!-- guidance-claims: ignore-file -->
|
|
10
|
+
|
|
11
|
+
# Extension implementation sequence
|
|
12
|
+
|
|
13
|
+
PR #54 records the auth, admin, UI and extension direction. Implementation is
|
|
14
|
+
incremental; the spikes are proposals, not the implemented project schema.
|
|
15
|
+
The implemented specification remains authoritative. This sequence incorporates
|
|
16
|
+
the architectural review rather than treating contradictory spike examples as
|
|
17
|
+
requirements.
|
|
18
|
+
|
|
19
|
+
## Invariants
|
|
20
|
+
|
|
21
|
+
- Operators explicitly install trusted host extensions; project YAML never loads
|
|
22
|
+
host modules or chooses packages. Application code remains isolated in WASM.
|
|
23
|
+
- Authentication credentials stay in host processing. Guest Request headers and
|
|
24
|
+
header-derived parameters must not expose operator-declared credential headers,
|
|
25
|
+
including on public routes receiving a session cookie.
|
|
26
|
+
- Session and one-time-token changes have explicit concurrency semantics. Define
|
|
27
|
+
atomic operations before selecting a database abstraction; multi-record
|
|
28
|
+
operations cannot rely on a same-collection transaction promise.
|
|
29
|
+
- Passwords and bearer credentials use appropriate hashes. TOTP requires protected
|
|
30
|
+
recoverable key material and an operator key rotation/backup contract.
|
|
31
|
+
- Authentication forms and submission destinations belong to trusted extension
|
|
32
|
+
code. Project styling does not imply permission to replace security controls.
|
|
33
|
+
- Administrative authorization is enforced by the API, including subject-level
|
|
34
|
+
restrictions, self-promotion and last-administrator protections.
|
|
35
|
+
- Unsupported target capabilities fail explicitly. Live provider deployment
|
|
36
|
+
testing remains deferred and non-blocking; local tests do not prove deployment.
|
|
37
|
+
|
|
38
|
+
## Delivery order
|
|
39
|
+
|
|
40
|
+
1. **Credential boundary:** add an explicit host-plugin declaration for headers
|
|
41
|
+
withheld from guest requests and parameter resolution. Preserve originals for
|
|
42
|
+
host authentication, cache decisions and policy processing. Test functions,
|
|
43
|
+
middleware and routes without an authentication requirement.
|
|
44
|
+
2. **Extension registration:** explicit operator registry, versioned configuration
|
|
45
|
+
validation, route ownership/collision rules and capability reporting. No
|
|
46
|
+
automatic project host-file execution. Define policy ordering before adding
|
|
47
|
+
an auth policy.
|
|
48
|
+
3. **Session slice:** one supported login method, trusted login/logout forms,
|
|
49
|
+
protected page and JSON routes, session lookup/revocation, CSRF and no-store
|
|
50
|
+
behavior. Evaluate a maintained authentication implementation behind an
|
|
51
|
+
adapter before writing protocol engines. Define durable atomic store methods
|
|
52
|
+
and test concurrent redemption, expiry and interrupted operations.
|
|
53
|
+
4. **Administrative API and CLI:** user lookup and session revocation first;
|
|
54
|
+
audit records and narrowly scoped permissions. Add role/recovery operations
|
|
55
|
+
only with object-level rules and concurrency tests.
|
|
56
|
+
5. **UI and console:** extract components from real auth/admin flows; choose a
|
|
57
|
+
constrained renderer and asset ownership model; verify keyboard and assistive
|
|
58
|
+
technology behavior as well as automated accessibility checks.
|
|
59
|
+
6. **Additional methods and targets:** passkeys, OIDC, MFA, recovery and imports
|
|
60
|
+
each receive state-machine, abuse-budget and portability tests. Preserve
|
|
61
|
+
verification of existing credential formats across target migrations.
|
|
62
|
+
|
|
63
|
+
## Status
|
|
64
|
+
|
|
65
|
+
PR #54 is merged. The first implementation adds the operator-only
|
|
66
|
+
`Plugin.credentialHeaders` boundary, documented in [Plugins](../../PLUGINS.md).
|
|
67
|
+
The remaining items are pending; none of this document declares end-user auth,
|
|
68
|
+
admin routes, extension YAML, or a generic project store available today.
|
|
@@ -1,5 +1,25 @@
|
|
|
1
|
+
# Historical record
|
|
2
|
+
|
|
3
|
+
Archived 2026-09-19. This records an earlier implementation or proposal, not
|
|
4
|
+
current instructions. See the [current roadmap](../../../ROADMAP.md),
|
|
5
|
+
[current contract](../../SPECIFICATION.md) and [open decisions](../../OPEN-DECISIONS.md).
|
|
6
|
+
Remaining acceptance work is not declared complete by archiving this record.
|
|
7
|
+
|
|
8
|
+
<!-- trust-model-prose: historical-file -->
|
|
9
|
+
<!-- guidance-claims: ignore-file -->
|
|
10
|
+
|
|
1
11
|
# Private management and durable mutation audit
|
|
2
12
|
|
|
13
|
+
> **Retired.** This page describes the management API and mutation audit of
|
|
14
|
+
> core's native link store. That store, its `urlcode links` CLI and this
|
|
15
|
+
> management listener were removed from core when `link` was extracted, and the
|
|
16
|
+
> `urlcode-dynamic-link` package that received them has since been retired and
|
|
17
|
+
> unpublished. Nothing in the current runtime exposes this surface. The page is
|
|
18
|
+
> kept because the security reasoning — loopback-only binding, operator-owned
|
|
19
|
+
> credential policy, transactional mutation audit — is referenced by
|
|
20
|
+
> [security audit](../../SECURITY-AUDIT.md) and applies to any component that
|
|
21
|
+
> reintroduces a management listener.
|
|
22
|
+
|
|
3
23
|
Management binds only `127.0.0.1` or `::1`. Use an authenticated private tunnel
|
|
4
24
|
(e.g. SSH/VPN with loopback forwarding); never publish its port through a public
|
|
5
25
|
proxy or container port mapping. This is operator management, not an end-user
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
# Historical record
|
|
2
|
+
|
|
3
|
+
Archived 2026-09-19. This records an earlier implementation or proposal, not
|
|
4
|
+
current instructions. See the [current roadmap](../../../ROADMAP.md),
|
|
5
|
+
[current contract](../../SPECIFICATION.md) and [open decisions](../../OPEN-DECISIONS.md).
|
|
6
|
+
Remaining acceptance work is not declared complete by archiving this record.
|
|
7
|
+
|
|
8
|
+
<!-- trust-model-prose: historical-file -->
|
|
9
|
+
<!-- guidance-claims: ignore-file -->
|
|
10
|
+
|
|
1
11
|
# Next-phase implementation status
|
|
2
12
|
|
|
3
13
|
Repository review and source implementation, 2026-09-17. Phase A established
|
|
@@ -5,6 +15,13 @@ the capability catalog; the subsequent source work implements the bounded
|
|
|
5
15
|
Phase B–D features below. This describes the source additions after `0.3.0` that ship in
|
|
6
16
|
`0.4.0-alpha.1`, not a claim that provider deployments have been verified.
|
|
7
17
|
|
|
18
|
+
> **Update:** this document describes the `0.4.0-alpha.1` source work as it
|
|
19
|
+
> stood on 2026-09-17, when every `function`/`middleware` route was sandboxed.
|
|
20
|
+
> The default changed in `0.4.0-alpha.2`: those routes now run trusted and
|
|
21
|
+
> unsandboxed in the host process unless the route declares `sandbox: true`,
|
|
22
|
+
> which gives it exactly the QuickJS/WASM execution described below. See
|
|
23
|
+
> [SPIKE-DEFAULT-TRUST-MODEL.md](../../SPIKE-DEFAULT-TRUST-MODEL.md).
|
|
24
|
+
|
|
8
25
|
## Implementation and evidence
|
|
9
26
|
|
|
10
27
|
| Phase | Implemented source | Evidence and remaining limits |
|
|
@@ -21,10 +38,10 @@ Phase B–D features below. This describes the source additions after `0.3.0` th
|
|
|
21
38
|
| D: TypeScript guests | Fixed trusted build-time compiler, bounded relative graph, rewritten JavaScript imports, referenced-asset snapshot and safe new output | Transpilation is not type checking; no tsconfig/plugins/package execution or dotenv copying; runtime remains QuickJS JavaScript only |
|
|
22
39
|
| D: consolidated SDK/MCP | Inspection, semantic validation, path explanation, compatibility, conversion previews and recipe discovery; operator-rooted stdio MCP | Read-only tooling; no arbitrary path, credential, guest execution or write authority; not a remote authenticated service |
|
|
23
40
|
|
|
24
|
-
See [interchange](INTERCHANGE.md), [provider evidence](PROVIDER-VERIFICATION.md),
|
|
25
|
-
[egress](EGRESS.md), [conditions](CONDITIONS.md), [recipes](RECIPES.md),
|
|
26
|
-
[bulk measurements](BULK.md), [TypeScript authoring](TYPESCRIPT-AUTHORING.md), and
|
|
27
|
-
[tooling/MCP](TOOLING.md) for the executable interfaces and exact restrictions.
|
|
41
|
+
See [interchange](../../INTERCHANGE.md), [provider evidence](../../PROVIDER-VERIFICATION.md),
|
|
42
|
+
[egress](../../EGRESS.md), [conditions](../../CONDITIONS.md), [recipes](../../RECIPES.md),
|
|
43
|
+
[bulk measurements](../../BULK.md), [TypeScript authoring](../../TYPESCRIPT-AUTHORING.md), and
|
|
44
|
+
[tooling/MCP](../../TOOLING.md) for the executable interfaces and exact restrictions.
|
|
28
45
|
|
|
29
46
|
## Preserved architecture
|
|
30
47
|
|
|
@@ -36,10 +53,11 @@ binding resolution and activation and distinguishes implementation support from
|
|
|
36
53
|
actual deployment evidence. Unknown or unsupported targets fail closed.
|
|
37
54
|
|
|
38
55
|
Project YAML describes route behavior. Provider infrastructure and outbound
|
|
39
|
-
origin grants stay in operator configuration.
|
|
40
|
-
QuickJS/WASM guests with no host-code fallback
|
|
41
|
-
|
|
42
|
-
|
|
56
|
+
origin grants stay in operator configuration. Through `0.4.0-alpha.1`,
|
|
57
|
+
functions remained untrusted QuickJS/WASM guests with no host-code fallback
|
|
58
|
+
(see the update note above). <!-- trust-model-prose: historical -->
|
|
59
|
+
Existing explicit external bindings and new egress grants remain pinned to the
|
|
60
|
+
exact configuration/source revision. Compilation and conversion do not resolve credentials or manufacture
|
|
43
61
|
grants. File authors publish new projects without overwriting unrelated work.
|
|
44
62
|
|
|
45
63
|
The five policy modules remain the authority for their target-sensitive
|