@jimhoyd/urlcode 0.3.0 → 0.4.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/urlcode-authoring/SKILL.md +122 -0
- package/.claude/skills/urlcode-operations/SKILL.md +108 -0
- package/.claude-plugin/marketplace.json +18 -0
- package/CONTRIBUTING.md +30 -2
- package/README.md +195 -255
- package/ROADMAP.md +143 -15
- package/SECURITY.md +31 -9
- package/dist/BUILD-MANIFEST.json +72 -47
- package/dist/adapters.js +4 -23
- package/dist/agent-lists.js +1 -1
- package/dist/agents-guide.js +113 -0
- package/dist/authoring-files.js +60 -0
- package/dist/authoring.js +11 -1
- package/dist/aws.js +4 -3
- package/dist/build-cloudflare.js +11 -24
- package/dist/build-static.js +134 -0
- package/dist/bulk.js +37 -0
- package/dist/capabilities.js +262 -0
- package/dist/capability-query.js +71 -0
- package/dist/catalog.js +105 -0
- package/dist/cli.js +165 -34
- package/dist/client-address.js +1 -1
- package/dist/compliance-rules/baseline.js +9 -17
- package/dist/compliance-rules/privacy.js +7 -18
- package/dist/compliance-rules/shared.js +0 -2
- package/dist/compliance-rules/strict.js +5 -5
- package/dist/compliance.js +6 -8
- package/dist/conditions.js +88 -0
- package/dist/config.js +69 -6
- package/dist/context.js +155 -0
- package/dist/ecosystem-cli.js +88 -0
- package/dist/egress.js +98 -0
- package/dist/examples.js +92 -0
- package/dist/explain-cli.js +64 -0
- package/dist/explain.js +131 -0
- package/dist/extensions.js +231 -0
- package/dist/function-sources.js +49 -5
- package/dist/function-worker.js +3 -1
- package/dist/functions.js +84 -13
- package/dist/guest-api.js +29 -3
- package/dist/index.js +40 -6
- package/dist/init-with.js +165 -0
- package/dist/interchange-cli.js +42 -0
- package/dist/interchange.js +189 -0
- package/dist/manifest.js +109 -0
- package/dist/match.js +2 -2
- package/dist/mcp-authoring.js +147 -0
- package/dist/mcp.js +97 -0
- package/dist/observability.js +7 -21
- package/dist/operator-host.js +29 -0
- package/dist/plugins.js +12 -0
- package/dist/policies/agents.js +2 -2
- package/dist/policies/cache.js +8 -3
- package/dist/policies/compression.js +2 -1
- package/dist/policies/security.js +0 -0
- package/dist/policies.js +1 -1
- package/dist/policy.js +56 -15
- package/dist/prerender.js +100 -41
- package/dist/project-tests.js +3 -3
- package/dist/provider-verification.js +92 -0
- package/dist/proxy.js +44 -0
- package/dist/readiness.js +34 -11
- package/dist/recipes.js +41 -0
- package/dist/route-diff.js +106 -0
- package/dist/router.js +45 -7
- package/dist/runtime.js +164 -64
- package/dist/sandbox.js +48 -0
- package/dist/scaffold.js +0 -0
- package/dist/schema-query.js +62 -0
- package/dist/scripts/operational-drills.js +12 -54
- package/dist/server.js +3 -29
- package/dist/signals.js +24 -0
- package/dist/site.js +0 -0
- package/dist/tooling.js +96 -0
- package/dist/trusted-functions.js +210 -0
- package/dist/types/adapters.d.ts +7 -4
- package/dist/types/agent-lists.d.ts +0 -1
- package/dist/types/agents-guide.d.ts +17 -0
- package/dist/types/authoring-files.d.ts +10 -0
- package/dist/types/aws.d.ts +3 -1
- package/dist/types/build-cloudflare.d.ts +1 -0
- package/dist/types/build-static.d.ts +43 -0
- package/dist/types/bulk.d.ts +27 -0
- package/dist/types/capabilities.d.ts +64 -0
- package/dist/types/capability-query.d.ts +24 -0
- package/dist/types/catalog.d.ts +65 -0
- package/dist/types/client-address.d.ts +0 -1
- package/dist/types/compliance-rules/baseline.d.ts +1 -9
- package/dist/types/compliance-rules/privacy.d.ts +1 -4
- package/dist/types/compliance-rules/shared.d.ts +0 -2
- package/dist/types/compliance-rules/strict.d.ts +0 -5
- package/dist/types/compliance.d.ts +0 -3
- package/dist/types/conditions.d.ts +19 -0
- package/dist/types/config.d.ts +21 -2
- package/dist/types/context.d.ts +66 -0
- package/dist/types/ecosystem-cli.d.ts +17 -0
- package/dist/types/egress.d.ts +46 -0
- package/dist/types/examples.d.ts +50 -0
- package/dist/types/explain-cli.d.ts +11 -0
- package/dist/types/explain.d.ts +95 -0
- package/dist/types/extensions.d.ts +177 -0
- package/dist/types/function-sources.d.ts +9 -0
- package/dist/types/functions.d.ts +48 -5
- package/dist/types/guest-api.d.ts +1 -0
- package/dist/types/index.d.ts +36 -6
- package/dist/types/init-with.d.ts +30 -0
- package/dist/types/interchange-cli.d.ts +16 -0
- package/dist/types/interchange.d.ts +42 -0
- package/dist/types/manifest.d.ts +79 -0
- package/dist/types/match.d.ts +1 -0
- package/dist/types/mcp-authoring.d.ts +92 -0
- package/dist/types/mcp.d.ts +12 -0
- package/dist/types/observability.d.ts +3 -14
- package/dist/types/operator-host.d.ts +8 -0
- package/dist/types/plugins.d.ts +2 -0
- package/dist/types/policies/agents.d.ts +0 -2
- package/dist/types/policies/compression.d.ts +2 -0
- package/dist/types/policies/security.d.ts +0 -1
- package/dist/types/policy.d.ts +15 -4
- package/dist/types/project-tests.d.ts +3 -2
- package/dist/types/provider-verification.d.ts +53 -0
- package/dist/types/proxy.d.ts +21 -0
- package/dist/types/readiness.d.ts +10 -3
- package/dist/types/recipes.d.ts +30 -0
- package/dist/types/route-diff.d.ts +27 -0
- package/dist/types/router.d.ts +2 -1
- package/dist/types/runtime.d.ts +11 -27
- package/dist/types/sandbox.d.ts +12 -0
- package/dist/types/scaffold.d.ts +0 -2
- package/dist/types/schema-query.d.ts +12 -0
- package/dist/types/server.d.ts +1 -4
- package/dist/types/signals.d.ts +25 -0
- package/dist/types/site.d.ts +0 -1
- package/dist/types/tooling.d.ts +115 -0
- package/dist/types/trusted-functions.d.ts +29 -0
- package/dist/types/types.d.ts +71 -7
- package/dist/types/typescript-authoring.d.ts +12 -0
- package/dist/types/vercel.d.ts +3 -1
- package/dist/types/verify-deployment.d.ts +47 -0
- package/dist/types.js +37 -5
- package/dist/typescript-authoring.js +142 -0
- package/dist/vercel.js +4 -3
- package/dist/verify-deployment.js +270 -0
- package/docs/AI-AUTHORING.md +232 -15
- package/docs/AWS.md +4 -4
- package/docs/BEST-PRACTICES.md +3 -2
- package/docs/BULK.md +79 -0
- package/docs/CAPABILITIES.md +192 -0
- package/docs/CAPACITY.md +129 -32
- package/docs/CI.md +142 -0
- package/docs/CLOUDFLARE.md +1 -2
- package/docs/COMPLIANCE.md +6 -9
- package/docs/CONDITIONS.md +74 -0
- package/docs/DEPLOYMENT-CHECKS.md +108 -0
- package/docs/EGRESS.md +125 -0
- package/docs/EXTENSIONS.md +398 -0
- package/docs/FRAMEWORK.md +198 -0
- package/docs/FUNCTION-SECURITY.md +129 -32
- package/docs/INSTALL.md +45 -12
- package/docs/INTERCHANGE.md +134 -0
- package/docs/LOAD-TESTING.md +4 -4
- package/docs/MIDDLEWARE-EXAMPLES.md +75 -0
- package/docs/MIDDLEWARE.md +29 -16
- package/docs/MONITORING.md +2 -19
- package/docs/NEXT-PHASE-PLAN.md +98 -0
- package/docs/NEXT-STEPS.md +634 -0
- package/docs/OBSERVABILITY.md +11 -18
- package/docs/OPEN-DECISIONS.md +212 -0
- package/docs/OPERATIONAL-PROOF.md +30 -31
- package/docs/OPERATIONS.md +29 -35
- package/docs/PLUGINS.md +37 -0
- package/docs/POLICIES.md +23 -309
- package/docs/PRERENDER.md +41 -1
- package/docs/PROJECT-DIRECTION.md +75 -8
- package/docs/PROVIDER-VERIFICATION.md +84 -0
- package/docs/READINESS.md +21 -1
- package/docs/README.md +87 -34
- package/docs/RECIPES.md +99 -0
- package/docs/RELEASE-READINESS.md +57 -35
- package/docs/RELEASE-SECURITY.md +116 -7
- package/docs/RESILIENCE.md +16 -15
- package/docs/ROUTING.md +8 -10
- package/docs/SANDBOX-REVIEW.md +19 -6
- package/docs/SCAFFOLDING.md +0 -2
- package/docs/SECURITY-AUDIT.md +41 -1
- package/docs/SPECIFICATION.md +150 -29
- package/docs/SPIKE-AI-FRAMEWORK-BENCHMARK.md +287 -0
- package/docs/SPIKE-BUSINESS-SUITE.md +1021 -0
- package/docs/SPIKE-CORE-LAYERING.md +337 -0
- package/docs/SPIKE-DEFAULT-TRUST-MODEL.md +209 -0
- package/docs/SPIKE-EXTENSION-MODEL.md +419 -0
- package/docs/SPIKE-EXTENSIONS.md +6 -0
- package/docs/SPIKE-LAMBDA-COMPILE.md +201 -0
- package/docs/SPIKE-MONOREPO.md +322 -0
- package/docs/STANDARDS.md +150 -142
- package/docs/STARTERS.md +21 -1
- package/docs/STATIC.md +94 -0
- package/docs/TOOLING.md +295 -0
- package/docs/TUNNELS.md +0 -3
- package/docs/TYPESCRIPT-AUTHORING.md +82 -0
- package/docs/TYPESCRIPT.md +25 -4
- package/docs/USABILITY-REVIEW.md +129 -0
- package/docs/VERCEL.md +4 -5
- package/docs/VERSION-ALIGNMENT.md +205 -0
- package/docs/YAML-GUIDE.md +15 -479
- package/docs/YAML-REFERENCE.md +143 -22
- package/docs/policies/agents.md +1 -1
- package/docs/policies/cache.md +13 -0
- package/docs/policies/contract.md +52 -0
- package/docs/policies/hardened.md +56 -0
- package/docs/policies/interoperability.md +169 -0
- package/docs/policies/operations.md +45 -0
- package/docs/yaml/assets.md +36 -0
- package/docs/yaml/conditions.md +20 -0
- package/docs/yaml/functions.md +160 -0
- package/docs/yaml/middleware.md +29 -0
- package/docs/yaml/organization.md +74 -0
- package/docs/yaml/policies.md +37 -0
- package/docs/yaml/redirects.md +64 -0
- package/docs/yaml/responses.md +57 -0
- package/docs/yaml/site.md +24 -0
- package/examples/assets/example.yaml +17 -0
- package/examples/aws/example.yaml +20 -0
- package/examples/cloudflare/example.yaml +19 -0
- package/examples/compliance/example.yaml +11 -0
- package/examples/conditions/README.md +12 -0
- package/examples/conditions/example.yaml +19 -0
- package/examples/conditions/tests/requests.json +13 -0
- package/examples/conditions/urlcode.yaml +24 -0
- package/examples/cookbook/README.md +8 -4
- package/examples/cookbook/example.yaml +17 -0
- package/examples/cookbook/functions/catalog.mjs +3 -0
- package/examples/cookbook/functions/fail.mjs +4 -0
- package/examples/cookbook/functions/items.mjs +3 -0
- package/examples/cookbook/functions/profile.mjs +3 -0
- package/examples/cookbook/functions/resource.mjs +3 -0
- package/examples/cookbook/functions/status.mjs +3 -0
- package/examples/cookbook/middleware/auth.mjs +48 -0
- package/examples/cookbook/middleware/body.mjs +15 -0
- package/examples/cookbook/middleware/bucket.mjs +29 -0
- package/examples/cookbook/middleware/cors.mjs +21 -0
- package/examples/cookbook/middleware/debug.mjs +13 -0
- package/examples/cookbook/middleware/envelope.mjs +11 -0
- package/examples/cookbook/middleware/errors.mjs +11 -0
- package/examples/cookbook/middleware/etag.mjs +18 -0
- package/examples/cookbook/middleware/locale.mjs +20 -0
- package/examples/cookbook/middleware/maintenance.mjs +10 -0
- package/examples/cookbook/middleware/methods.mjs +15 -0
- package/examples/cookbook/middleware/negotiate.mjs +20 -0
- package/examples/cookbook/middleware/referer.mjs +12 -0
- package/examples/cookbook/middleware/request-id.mjs +16 -0
- package/examples/cookbook/route-index.json +676 -0
- package/examples/cookbook/routes/middleware.yaml +126 -0
- package/examples/cookbook/tests/requests.json +526 -0
- package/examples/cookbook/urlcode.yaml +1 -0
- package/examples/egress/README.md +22 -0
- package/examples/egress/example.yaml +19 -0
- package/examples/egress/urlcode.yaml +19 -0
- package/examples/extensions/README.md +7 -0
- package/examples/extensions/example.yaml +21 -0
- package/examples/extensions/urlcode.yaml +25 -0
- package/examples/monitoring/example.yaml +8 -0
- package/examples/prerender/README.md +2 -2
- package/examples/prerender/example.yaml +16 -0
- package/examples/provider-conformance/README.md +12 -0
- package/examples/provider-conformance/example.yaml +14 -0
- package/examples/provider-conformance/urlcode.yaml +34 -0
- package/examples/tunnel/example.yaml +8 -0
- package/examples/vercel/example.yaml +19 -0
- package/llms-full.txt +3084 -0
- package/llms.txt +61 -21
- package/package.json +36 -7
- package/packaging/claude-plugin/.claude-plugin/plugin.json +19 -0
- package/packaging/claude-plugin/skills/urlcode-authoring/SKILL.md +122 -0
- package/packaging/claude-plugin/skills/urlcode-operations/SKILL.md +108 -0
- package/recipes/authenticated-json-api/README.md +51 -0
- package/recipes/authenticated-json-api/functions/profile.mjs +5 -0
- package/recipes/authenticated-json-api/recipe.yaml +34 -0
- package/recipes/authenticated-json-api/tests/requests.json +39 -0
- package/recipes/authenticated-json-api/urlcode.yaml +12 -0
- package/recipes/contact-form/README.md +25 -0
- package/recipes/contact-form/functions/contact.mjs +17 -0
- package/recipes/contact-form/recipe.yaml +33 -0
- package/recipes/contact-form/tests/requests.json +47 -0
- package/recipes/contact-form/urlcode.yaml +18 -0
- package/recipes/cors-api/README.md +16 -0
- package/recipes/cors-api/functions/items.mjs +3 -0
- package/recipes/cors-api/middleware/cors.mjs +21 -0
- package/recipes/cors-api/recipe.yaml +26 -0
- package/recipes/cors-api/tests/requests.json +65 -0
- package/recipes/cors-api/urlcode.yaml +12 -0
- package/recipes/health-page/README.md +13 -0
- package/recipes/health-page/recipe.yaml +23 -0
- package/recipes/health-page/tests/requests.json +36 -0
- package/recipes/health-page/urlcode.yaml +19 -0
- package/recipes/json-api/README.md +6 -0
- package/recipes/json-api/functions/echo.mjs +3 -0
- package/recipes/json-api/recipe.yaml +25 -0
- package/recipes/json-api/tests/requests.json +34 -0
- package/recipes/json-api/urlcode.yaml +12 -0
- package/recipes/middleware/README.md +34 -0
- package/recipes/middleware/functions/catalog.mjs +3 -0
- package/recipes/middleware/functions/fail.mjs +4 -0
- package/recipes/middleware/functions/items.mjs +3 -0
- package/recipes/middleware/functions/profile.mjs +3 -0
- package/recipes/middleware/functions/resource.mjs +3 -0
- package/recipes/middleware/functions/status.mjs +3 -0
- package/recipes/middleware/middleware/auth.mjs +48 -0
- package/recipes/middleware/middleware/body.mjs +15 -0
- package/recipes/middleware/middleware/bucket.mjs +29 -0
- package/recipes/middleware/middleware/cors.mjs +21 -0
- package/recipes/middleware/middleware/debug.mjs +13 -0
- package/recipes/middleware/middleware/envelope.mjs +11 -0
- package/recipes/middleware/middleware/errors.mjs +11 -0
- package/recipes/middleware/middleware/etag.mjs +18 -0
- package/recipes/middleware/middleware/locale.mjs +20 -0
- package/recipes/middleware/middleware/maintenance.mjs +10 -0
- package/recipes/middleware/middleware/methods.mjs +15 -0
- package/recipes/middleware/middleware/negotiate.mjs +20 -0
- package/recipes/middleware/middleware/referer.mjs +12 -0
- package/recipes/middleware/middleware/request-id.mjs +16 -0
- package/recipes/middleware/public/guide.txt +1 -0
- package/recipes/middleware/recipe.yaml +50 -0
- package/recipes/middleware/tests/requests.json +528 -0
- package/recipes/middleware/urlcode.yaml +127 -0
- package/recipes/protected-download/README.md +22 -0
- package/recipes/protected-download/files/report.txt +1 -0
- package/recipes/protected-download/recipe.yaml +31 -0
- package/recipes/protected-download/tests/requests.json +32 -0
- package/recipes/protected-download/urlcode.yaml +15 -0
- package/recipes/redirect/README.md +7 -0
- package/recipes/redirect/recipe.yaml +25 -0
- package/recipes/redirect/tests/requests.json +19 -0
- package/recipes/redirect/urlcode.yaml +9 -0
- package/recipes/static-plus-api/README.md +15 -0
- package/recipes/static-plus-api/functions/info.mjs +3 -0
- package/recipes/static-plus-api/public/assets/index.html +3 -0
- package/recipes/static-plus-api/public/assets/site.css +1 -0
- package/recipes/static-plus-api/public/index.html +8 -0
- package/recipes/static-plus-api/recipe.yaml +29 -0
- package/recipes/static-plus-api/tests/requests.json +56 -0
- package/recipes/static-plus-api/urlcode.yaml +23 -0
- package/recipes/typescript/README.md +8 -0
- package/recipes/typescript/functions/hello.ts +5 -0
- package/recipes/typescript/recipe.yaml +23 -0
- package/recipes/typescript/tests/requests.json +18 -0
- package/recipes/typescript/urlcode.yaml +5 -0
- package/recipes/webhook-receiver/README.md +20 -0
- package/recipes/webhook-receiver/functions/receive.mjs +16 -0
- package/recipes/webhook-receiver/recipe.yaml +27 -0
- package/recipes/webhook-receiver/tests/requests.json +59 -0
- package/recipes/webhook-receiver/urlcode.yaml +23 -0
- package/schemas/recipe.schema.json +139 -0
- package/schemas/urlcode.schema.json +659 -110
- package/skills/urlcode/SKILL.md +119 -0
- package/starters/default/.github/workflows/urlcode.yml +23 -0
- package/starters/default/.mcp.json +12 -0
- package/starters/default/AGENTS.md +79 -0
- 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 -41
- package/dist/sqlite-version.js +0 -6
- package/dist/types/link-api.d.ts +0 -30
- package/dist/types/link-cli.d.ts +0 -36
- 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 -9
- package/dist/types/sqlite-version.d.ts +0 -1
- package/docs/DYNAMIC-LINKS.md +0 -561
- package/docs/MANAGEMENT-SECURITY.md +0 -82
- package/examples/live-links/README.md +0 -11
- package/examples/live-links/tests/requests.json +0 -6
- package/examples/live-links/urlcode.yaml +0 -16
package/docs/README.md
CHANGED
|
@@ -1,58 +1,111 @@
|
|
|
1
1
|
# URLCode documentation
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
> **Public documentation is authored in a separate `urlcode-docs` repository,
|
|
4
|
+
> not generated from this tree.** New reader-facing pages belong there; `docs/`
|
|
5
|
+
> here keeps contributor and maintainer material (local development, CI, release
|
|
6
|
+
> process, reviews, spikes, plans and the generated field reference). The
|
|
7
|
+
> reader-facing pages still listed below are being migrated.
|
|
8
|
+
>
|
|
9
|
+
> `urlcode-docs` is currently private, so it isn't publicly browsable yet —
|
|
10
|
+
> until it is, this file and this repository's README are the practical
|
|
11
|
+
> reference.
|
|
5
12
|
|
|
6
|
-
|
|
13
|
+
Start with [the framework](FRAMEWORK.md): the four packages, the ladder from
|
|
14
|
+
redirects to a full application, the composition contract and the rules an AI
|
|
15
|
+
agent must follow. [Project direction](PROJECT-DIRECTION.md) states the
|
|
16
|
+
boundary and the license. Use documentation pinned to your runtime revision;
|
|
7
17
|
`version: "1"` is the stable project-format contract for this release line.
|
|
8
18
|
|
|
19
|
+
## Author a project
|
|
20
|
+
|
|
9
21
|
| Goal | Start here |
|
|
10
22
|
|---|---|
|
|
11
23
|
| Install the CLI | [Installation](INSTALL.md) |
|
|
12
|
-
| Generate placeholders from YAML | [Scaffolding](SCAFFOLDING.md) |
|
|
13
24
|
| Write YAML with examples | [YAML guide and recipes](YAML-GUIDE.md) |
|
|
14
25
|
| Look up every accepted field | [Generated field reference](YAML-REFERENCE.md), [JSON Schema](../schemas/urlcode.schema.json) |
|
|
15
26
|
| Let an AI build routes | [AI authoring guide](AI-AUTHORING.md), [llms.txt](../llms.txt) |
|
|
27
|
+
| Load authoring/operations rules into an agent | [Authoring skill](../.claude/skills/urlcode-authoring/SKILL.md), [operations skill](../.claude/skills/urlcode-operations/SKILL.md), [how they are distributed](AI-AUTHORING.md#agent-skills) |
|
|
16
28
|
| Run examples | [25-route cookbook](../examples/cookbook/README.md), [prerender recipe](../examples/prerender/README.md), [small starter](STARTERS.md) |
|
|
17
|
-
| Explore a standalone application | [URLCode
|
|
18
|
-
| Explore a static docs-site integration |
|
|
19
|
-
| Create/update short links live | [Dynamic links, storage and management API](DYNAMIC-LINKS.md) |
|
|
29
|
+
| Explore a standalone application | [URLCode Short demo](https://github.com/jimhoyd-com/urlcode-short), [build retrospective](https://github.com/jimhoyd-com/urlcode-short/blob/main/docs/BUILD-RETROSPECTIVE.md) |
|
|
30
|
+
| Explore a static docs-site integration | URLCode Docs project (private repository; not yet publicly browsable) |
|
|
20
31
|
| Understand exact behavior | [Specification](SPECIFICATION.md), [routing](ROUTING.md), [HTTP](HTTP.md) |
|
|
21
|
-
|
|
|
22
|
-
|
|
|
32
|
+
| Run examples | [40-route cookbook](../examples/cookbook/README.md), [prerender recipe](../examples/prerender/README.md), [small starter](STARTERS.md) |
|
|
33
|
+
| Let an AI build routes | [The framework](FRAMEWORK.md), [AI authoring guide](AI-AUTHORING.md), [llms.txt](../llms.txt), [SDK and read-only MCP](TOOLING.md) |
|
|
34
|
+
| Reuse code around routes | [Middleware](MIDDLEWARE.md), [middleware examples](MIDDLEWARE-EXAMPLES.md) |
|
|
35
|
+
| Handle secrets and decide what to sandbox | [Function security](FUNCTION-SECURITY.md) |
|
|
36
|
+
| Author guest functions in TypeScript | [Build-time guest transpilation](TYPESCRIPT-AUTHORING.md) |
|
|
37
|
+
| Serve pages, files and downloads | [Assets](ASSETS.md) |
|
|
38
|
+
| Publish a site with no request-time guest code | [Prerendering helper and recipe](PRERENDER.md) |
|
|
39
|
+
| Select response branches | [Exact conditions](CONDITIONS.md) |
|
|
40
|
+
| Proxy an API or emit a webhook | [Bounded egress and operator grants](EGRESS.md) |
|
|
41
|
+
| Throttle, block agents, set security headers, compress or cache | [Policies](POLICIES.md): [throttle](policies/throttle.md), [agents](policies/agents.md), [security](policies/security.md), [compression](policies/compression.md), [cache](policies/cache.md) |
|
|
42
|
+
| Generate robots.txt, sitemap.xml, favicon, security.txt and llms.txt | [Site conventions](SITE.md) |
|
|
43
|
+
| Organize YAML across folders | [Organization](ORGANIZATION.md), [readability practices](BEST-PRACTICES.md) |
|
|
44
|
+
| Generate placeholders from YAML | [Scaffolding](SCAFFOLDING.md) |
|
|
45
|
+
| Convert provider redirect files | [Strict interchange and conversion reports](INTERCHANGE.md) |
|
|
46
|
+
| Import thousands of redirects | [Bulk import and scale evidence](BULK.md) |
|
|
47
|
+
| Reuse local project recipes | [Recipe catalog](RECIPES.md) |
|
|
48
|
+
| Check declared configuration against standards-referenced rules | [Compliance](COMPLIANCE.md) |
|
|
49
|
+
|
|
50
|
+
## Extend the runtime
|
|
51
|
+
|
|
52
|
+
| Goal | Start here |
|
|
53
|
+
|---|---|
|
|
54
|
+
| Add accounts, sign-in and protected routes | [urlcode-auth](https://github.com/jimhoyd-com/urlcode-auth#readme) |
|
|
55
|
+
| Manage users, sessions, roles and audit | [urlcode-admin](https://github.com/jimhoyd-com/urlcode-admin#readme) |
|
|
56
|
+
| Restyle every extension page and translate copy | [urlcode-ui](https://github.com/jimhoyd-com/urlcode-ui#readme), [ui contract](https://github.com/jimhoyd-com/urlcode-ui/blob/main/CONTRACT.md) |
|
|
57
|
+
| Write or install a versioned extension | [Extensions](EXTENSIONS.md), [example fixture](../examples/extensions/README.md) |
|
|
58
|
+
| Know which core version an extension package supports, and how it says so | [Core version alignment](VERSION-ALIGNMENT.md) |
|
|
23
59
|
| Add host behavior in operator code | [Plugins](PLUGINS.md) |
|
|
24
60
|
| Use the API from TypeScript | [TypeScript: shipped declarations, exports, build and fidelity](TYPESCRIPT.md) |
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
|
29
|
-
|
|
30
|
-
|
|
|
31
|
-
| Organize YAML across folders | [Organization](ORGANIZATION.md) |
|
|
32
|
-
| Work locally | [Local development](LOCAL-DEVELOPMENT.md) |
|
|
33
|
-
| Share a local project publicly | [Tunnels](TUNNELS.md) |
|
|
34
|
-
| Watch a deployment | [Monitoring](MONITORING.md) |
|
|
35
|
-
| Wire your own monitoring or scrape metrics | [Observability](OBSERVABILITY.md) |
|
|
36
|
-
| Load test a deployment | [Load testing](LOAD-TESTING.md) |
|
|
37
|
-
| Deploy to Vercel | [Vercel adapter](VERCEL.md) |
|
|
38
|
-
| Deploy to AWS Lambda | [AWS adapter](AWS.md) |
|
|
39
|
-
| Deploy to Cloudflare Workers | [Cloudflare target](CLOUDFLARE.md) |
|
|
40
|
-
| Handle secrets/untrusted code | [Function security](FUNCTION-SECURITY.md) |
|
|
61
|
+
|
|
62
|
+
## Operate and deploy
|
|
63
|
+
|
|
64
|
+
| Goal | Start here |
|
|
65
|
+
|---|---|
|
|
66
|
+
| Work locally | [Local development](LOCAL-DEVELOPMENT.md), [tunnels](TUNNELS.md) |
|
|
41
67
|
| Prove responses and counts | [Readiness](READINESS.md) |
|
|
42
|
-
|
|
|
43
|
-
| Prepare for overload/DDoS/recovery | [Resilience playbook](RESILIENCE.md) |
|
|
68
|
+
| Check pull requests of a project on GitHub | [CI action, route diffs and the starter workflow](CI.md) |
|
|
44
69
|
| Deploy and roll back | [Operations](OPERATIONS.md) |
|
|
45
70
|
| Review security findings and gaps | [Internal security audit](SECURITY-AUDIT.md) |
|
|
46
71
|
| Assess release readiness | [Evidence and open gates](RELEASE-READINESS.md) |
|
|
47
72
|
| See unfinished work | [Roadmap](../ROADMAP.md) |
|
|
48
73
|
| Read the design behind policies, plugins and templates | [Extensions spike](SPIKE-EXTENSIONS.md) |
|
|
74
|
+
| Read the design for an authentication and authorization plugin | [Auth spike](SPIKE-AUTH.md) |
|
|
75
|
+
| Read the design for the administration extension that manages users | [Admin spike](SPIKE-ADMIN.md) |
|
|
76
|
+
| Read the design for the shared template kit every extension renders with | [UI kit spike](SPIKE-UI.md) |
|
|
77
|
+
| Read the review of the extension model, its precedents and alignment | [Extension model review](SPIKE-EXTENSION-MODEL.md) |
|
|
78
|
+
| Read the design for compiling function routes into per-route Lambdas | [Lambda compile spike](SPIKE-LAMBDA-COMPILE.md) |
|
|
79
|
+
| Verify a running deployment matches the project | [Deployment checks](DEPLOYMENT-CHECKS.md) |
|
|
80
|
+
| Inspect target support | [Capabilities and normalized representation](CAPABILITIES.md) |
|
|
81
|
+
| Deploy to Vercel, AWS Lambda or Cloudflare Workers | [Vercel](VERCEL.md), [AWS](AWS.md), [Cloudflare](CLOUDFLARE.md), [provider verification evidence](PROVIDER-VERIFICATION.md) |
|
|
82
|
+
| Watch a deployment | [Monitoring](MONITORING.md), [observability](OBSERVABILITY.md) |
|
|
83
|
+
| Estimate concurrency and memory | [Capacity and limits](CAPACITY.md), [measurements](PERFORMANCE.md), [load testing](LOAD-TESTING.md) |
|
|
84
|
+
| Prepare for overload, DDoS and recovery | [Resilience playbook](RESILIENCE.md) |
|
|
49
85
|
|
|
50
|
-
|
|
51
|
-
Infrastructure limits are deployment settings, not fields to invent in route YAML.
|
|
86
|
+
## Evidence, reviews and design records
|
|
52
87
|
|
|
53
|
-
|
|
88
|
+
These are dated records, not guides. They say what has been checked and what
|
|
89
|
+
has not, and why the design is the way it is.
|
|
54
90
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
91
|
+
| Record | What it is |
|
|
92
|
+
|---|---|
|
|
93
|
+
| [Release readiness](RELEASE-READINESS.md) | Verified safeguards, open gates, supported scope |
|
|
94
|
+
| [Usability review](USABILITY-REVIEW.md) | Where the framework is easier or harder than the tools it replaces, and ranked changes |
|
|
95
|
+
| [Next steps](NEXT-STEPS.md) | The phased plan: agent discovery, context compression, retrieval, the ladder, benchmarks and the remaining proof gaps |
|
|
96
|
+
| [AI-first framework benchmark spike](SPIKE-AI-FRAMEWORK-BENCHMARK.md) | Proposed research-first, independent-agent application and runtime benchmark with a verified issue/improvement loop |
|
|
97
|
+
| [Next-phase implementation status](NEXT-PHASE-PLAN.md) | Source additions after 0.3.0 shipped in 0.4.0-alpha.1, and their evidence limits |
|
|
98
|
+
| [Security review](SECURITY-AUDIT.md) | Internal findings and fixes; not an independent test |
|
|
99
|
+
| [Standards audit](STANDARDS.md) | How the runtime conforms to the RFCs it touches |
|
|
100
|
+
| [Sandbox review package](SANDBOX-REVIEW.md) | What an independent reviewer needs; assessment not yet performed |
|
|
101
|
+
| [Operational drills](OPERATIONAL-PROOF.md) | Deployment acceptance drills CI runs |
|
|
102
|
+
| [Release security](RELEASE-SECURITY.md) | Candidate signing and publication process |
|
|
103
|
+
| [Core version alignment](VERSION-ALIGNMENT.md) | The supported core floor for each downstream repository, how it is declared, and the publish-then-raise-then-regenerate order |
|
|
104
|
+
| [Extension model review](SPIKE-EXTENSION-MODEL.md) | Why extensions are shaped this way, with framework precedents |
|
|
105
|
+
| [Extensions spike](SPIKE-EXTENSIONS.md) | The design behind policies and plugins; implemented |
|
|
106
|
+
| [Lambda compile spike](SPIKE-LAMBDA-COMPILE.md) | Proposal: per-route Lambdas for functions; not implemented |
|
|
107
|
+
| Auth, admin and UI spikes | Live in their repositories: [auth](https://github.com/jimhoyd-com/urlcode-auth/blob/main/docs/SPIKE-AUTH.md), [admin](https://github.com/jimhoyd-com/urlcode-admin/blob/main/docs/SPIKE-ADMIN.md), [ui](https://github.com/jimhoyd-com/urlcode-ui/blob/main/docs/SPIKE-UI.md) |
|
|
108
|
+
| [Roadmap](../ROADMAP.md) | Implemented versus planned |
|
|
109
|
+
|
|
110
|
+
Examples are educational unless backed by the runnable cookbook and fixtures.
|
|
111
|
+
Infrastructure limits are deployment settings, not fields to invent in route YAML.
|
package/docs/RECIPES.md
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Local recipes
|
|
2
|
+
|
|
3
|
+
Recipes are ordinary version-controlled URLCode projects shipped with the
|
|
4
|
+
runtime. There is no network registry, install script, provider account or
|
|
5
|
+
project-code execution during authoring. Search them before writing a common
|
|
6
|
+
route by hand: the catalog is the vocabulary of behavior the runtime already
|
|
7
|
+
supports, and every recipe validates, tests and audits.
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
urlcode recipes list
|
|
11
|
+
urlcode recipes search "webhook json" # id, description, tags, capabilities
|
|
12
|
+
urlcode recipes search webhook --json
|
|
13
|
+
urlcode recipes show webhook-receiver # metadata first, then every file
|
|
14
|
+
urlcode recipes add webhook-receiver --out ./orders-hook --dry-run
|
|
15
|
+
urlcode recipes add webhook-receiver --out ./orders-hook
|
|
16
|
+
urlcode validate --local --project ./orders-hook
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## The catalog
|
|
20
|
+
|
|
21
|
+
| Recipe | Complexity | What it shows | Needs |
|
|
22
|
+
|---|---|---|---|
|
|
23
|
+
| `redirect` | starter | Permanent redirect forwarding one allowlisted query key | nothing |
|
|
24
|
+
| `health-page` | starter | Native `/health` text and `/status` JSON, no-store | nothing |
|
|
25
|
+
| `json-api` | starter | Bounded JSON body echoed by a sandboxed function | self-hosted runtime |
|
|
26
|
+
| `webhook-receiver` | starter | JSON event with a type header, shape-checked, `202` | self-hosted runtime |
|
|
27
|
+
| `typescript` | intermediate | Typed guest transpiled by `build-typescript` | build step |
|
|
28
|
+
| `static-plus-api` | intermediate | Page, static directory and one JSON function | self-hosted runtime |
|
|
29
|
+
| `cors-api` | intermediate | Preflight and CORS headers from route middleware | self-hosted runtime |
|
|
30
|
+
| `contact-form` | intermediate | Validated message, fixed signal to a hook after the response | signal grant (`--policy`) |
|
|
31
|
+
| `middleware` | advanced | Fourteen reusable middleware patterns ([described here](MIDDLEWARE-EXAMPLES.md)) | self-hosted runtime |
|
|
32
|
+
| `authenticated-json-api` | advanced | Function behind `auth: true` | operator auth extension, `--host-file`, `--origin` |
|
|
33
|
+
| `protected-download` | advanced | Native attachment behind `auth: true` | operator auth extension, `--host-file`, `--origin` |
|
|
34
|
+
|
|
35
|
+
Each recipe contains a README, `tests/requests.json` and editable files.
|
|
36
|
+
Replace example destinations and review the resulting files before use. The
|
|
37
|
+
authenticated recipes declare `extensions.auth` and protect their route with
|
|
38
|
+
the short form described in [extensions](EXTENSIONS.md); their README shows the
|
|
39
|
+
minimal host-file fixture that reproduces the bundled tests. Nothing in the
|
|
40
|
+
catalog verifies webhook signatures: the sandbox has no crypto or network API,
|
|
41
|
+
so signed webhooks belong behind an operator extension or a trusted host.
|
|
42
|
+
|
|
43
|
+
## `recipe.yaml`
|
|
44
|
+
|
|
45
|
+
Every recipe carries `recipe.yaml`, validated against
|
|
46
|
+
[`schemas/recipe.schema.json`](../schemas/recipe.schema.json) by `npm run check`:
|
|
47
|
+
|
|
48
|
+
- `id`, `description`, `tags`, `complexity` (`starter`, `intermediate`,
|
|
49
|
+
`advanced`): written by hand; `search` matches id, description, tags and
|
|
50
|
+
capabilities, every word must match, and whole-tag or id hits rank first.
|
|
51
|
+
- `capabilities`, `targets`, `routes`: derived from the capability preflight
|
|
52
|
+
(`analyzeProjectCapabilities` per target after site expansion). The check
|
|
53
|
+
refuses a hand-edited value that differs, so a recipe cannot claim a target
|
|
54
|
+
it does not activate on. `targets` is `compatible`, or the strongest issue
|
|
55
|
+
(`conditional`, `unknown`, `refused`); `routes` is the `--expect-routes` value.
|
|
56
|
+
- `services` (external services), `grants` (operator grants, never from project
|
|
57
|
+
files), `inputs` (what to edit), `files` (the copy list), `tests` (fixtures
|
|
58
|
+
and the exact commands) and `behavior` (one observable statement per line).
|
|
59
|
+
|
|
60
|
+
`show` prints this metadata before the file contents so a reader sees what a
|
|
61
|
+
recipe needs before its files scroll past; `--json` returns the same object with
|
|
62
|
+
a `content` map. `list` prints one line per recipe, or the metadata with `--json`.
|
|
63
|
+
|
|
64
|
+
## Examples
|
|
65
|
+
|
|
66
|
+
`examples/*/example.yaml` uses the same schema, and `urlcode examples search
|
|
67
|
+
<text> [--json]` returns the smallest matching runnable example first with the
|
|
68
|
+
file to read. The cookbook's forty routes are indexed per route in the generated
|
|
69
|
+
[`examples/cookbook/route-index.json`](../examples/cookbook/route-index.json)
|
|
70
|
+
(handler, methods, capabilities, policies and middleware module names as tags;
|
|
71
|
+
`npm run docs:cookbook-index` regenerates it and `npm run check` refuses a stale
|
|
72
|
+
copy), so a search for `etag` answers the cookbook and its `/versioned` route.
|
|
73
|
+
Entries without a `urlcode.yaml` (operator rules, monitoring configuration,
|
|
74
|
+
scripts) are `runnable: false` and carry no derived fields.
|
|
75
|
+
|
|
76
|
+
## Adding a recipe
|
|
77
|
+
|
|
78
|
+
`add` creates a new standalone directory. It refuses an existing destination,
|
|
79
|
+
even an empty directory; it never merges or overwrites existing project routes.
|
|
80
|
+
Review or copy selected declarations manually when combining projects. Dry-run
|
|
81
|
+
reads and validates the packaged recipe and checks the destination, but writes
|
|
82
|
+
nothing. The output parent must already exist and be owned by the caller.
|
|
83
|
+
Dependencies are written first and the complete `urlcode.yaml` is published by
|
|
84
|
+
rename last. A failed write removes the new directory. This is atomic project
|
|
85
|
+
activation, not an atomic directory replacement or a guarantee against a local
|
|
86
|
+
attacker concurrently replacing the caller's output directories.
|
|
87
|
+
|
|
88
|
+
## SDK and MCP
|
|
89
|
+
|
|
90
|
+
The SDK provides `listRecipes()`, `searchRecipes(text)`, `showRecipe(name)`,
|
|
91
|
+
`addRecipe(name, output, {dryRun})`, `listExamples()` and `searchExamples(text)`.
|
|
92
|
+
Catalog names are a fixed list in code; metadata and file lists come from each
|
|
93
|
+
schema-checked `recipe.yaml` and are returned as copies. Unknown names and
|
|
94
|
+
arbitrary paths/URLs fail closed. The stdio MCP server adds `search_recipes` and
|
|
95
|
+
`search_examples` beside `recipes_list` and `recipes_show`
|
|
96
|
+
([tooling](TOOLING.md)). Integration tests run every recipe through the real
|
|
97
|
+
runtime with its fixtures and audit it with its declared route count (after
|
|
98
|
+
building the TypeScript recipe, with a fixture registry for the authenticated
|
|
99
|
+
ones and the generated policy for the contact form).
|
|
@@ -1,41 +1,59 @@
|
|
|
1
1
|
# Release readiness
|
|
2
2
|
|
|
3
|
-
Status:
|
|
3
|
+
Status: `0.4.0-alpha.2` (`package.json`) alpha of the extension contract and
|
|
4
|
+
agent tooling on top of the `0.3.0` self-hosted release; `0.4.0-alpha.1` is the
|
|
5
|
+
most recent alpha actually published; the npm dist-tags for `@jimhoyd/urlcode`
|
|
6
|
+
were `latest` = `0.3.0` and `alpha` = `0.4.0-alpha.1` when checked against the
|
|
7
|
+
registry on 2026-09-19, so the repository's `0.4.0-alpha.2` is unpublished (see
|
|
8
|
+
"Packaging" below). Production approval remains specific to
|
|
4
9
|
the workload and deployment environment.
|
|
5
10
|
This register describes the current public runtime, not future promises.
|
|
6
11
|
Use the contract and docs from the same pinned commit as your installed runtime.
|
|
7
12
|
|
|
8
13
|
## What is aligned
|
|
9
14
|
|
|
10
|
-
- One portable YAML project, explicit includes,
|
|
15
|
+
- One portable YAML project, explicit includes, one handler per route (redirect, respond, page, static, download, function, proxy, conditional or extension),
|
|
11
16
|
per-route middleware and consistent request/response validation.
|
|
12
17
|
- One starter with a function route first and an ordinary redirect second.
|
|
13
18
|
Clone urlcode-template or use `urlcode init`; neither requires a database.
|
|
14
19
|
- Native handlers avoid user-code execution unless middleware is attached.
|
|
15
|
-
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
20
|
+
- Functions/middleware run trusted and unsandboxed by default (in-process,
|
|
21
|
+
full Node access); `sandbox: true` opts a route into isolated QuickJS/WASM
|
|
22
|
+
with no ambient filesystem, network or Node APIs (docs/SPIKE-DEFAULT-TRUST-MODEL.md).
|
|
23
|
+
Host bindings require external revision-pinned approval either way.
|
|
19
24
|
- The runtime is released under Apache-2.0.
|
|
20
25
|
|
|
21
26
|
## Regression evidence
|
|
22
27
|
|
|
23
28
|
`npm run verify` is the lint, syntax/schema-reference and unit/HTTP regression gate.
|
|
24
29
|
`npm run test:package` installs the packed artifact and exercises initialized apps,
|
|
25
|
-
route audits, bounded benchmarks
|
|
26
|
-
Linux/macOS/Windows and tests the container
|
|
30
|
+
route audits, bounded benchmarks and assets. On a push to `main`, CI runs Node
|
|
31
|
+
22/24/26 on Linux/macOS/Windows (nine combinations) and tests the container
|
|
32
|
+
under resource restrictions; a pull request runs the same Node versions on
|
|
33
|
+
Linux only (`.github/workflows/ci.yml`'s matrix), with the macOS/Windows legs
|
|
34
|
+
deferred to the post-merge run.
|
|
27
35
|
|
|
28
36
|
| Area | Covered behavior | Practical limit |
|
|
29
37
|
|---|---|---|
|
|
30
38
|
| Routing and HTTP | Exact/parameter/static precedence, methods, inputs, assets, middleware and response assertions | Stable 0.1 contract; unsupported semantics reject rather than emulate |
|
|
31
|
-
| Isolation |
|
|
32
|
-
| Overload | Function
|
|
33
|
-
| Worker replacement | Repeated guest deadlines shed load and the pool returns to service after backoff, rather than latching off for the life of the process |
|
|
34
|
-
|
|
|
35
|
-
|
|
|
36
|
-
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
| Isolation | `sandbox: true` capability/permission boundaries, deadlines, memory and invalid outputs; the trusted default's grant scoping | Not an independent security assessment or multi-tenant service certification; trusted-route code safety is the project's own call |
|
|
40
|
+
| Overload | Function pool queue caps; HTTP admission saturation, separate bounded probe budget, health availability and recovery after upload completion/disconnect | 64 application requests default; no fairness, upstream DDoS protection or end-to-end deadline |
|
|
41
|
+
| Worker replacement | Repeated guest deadlines shed load and the pool returns to service after backoff, rather than latching off for the life of the process | Bounded by the configured worker count; no cross-process load balancing |
|
|
42
|
+
| Shutdown | New work rejects; repeated close shares completion | Existing deadlines can still fail during shutdown |
|
|
43
|
+
| Activation/recovery | Invalid reload retains last-good snapshot; corrupt revision metadata rejects activation | No deployment orchestration |
|
|
44
|
+
| Packaging | Packed installation and starter examples tested; sensitive files excluded | `0.3.0` and `0.4.0-alpha.1` are published to npm as `@jimhoyd/urlcode` (`latest` and `alpha` dist-tags respectively; dist-tags verified against the npm registry on 2026-09-19, when the repository stood at the unpublished `0.4.0-alpha.2`). Published extension packages on the same date: `@jimhoyd/urlcode-auth@0.1.0-alpha.2`, `@jimhoyd/urlcode-admin@0.1.0-alpha.2`, `@jimhoyd/urlcode-ui@0.1.0-alpha.4`, `@jimhoyd/urlcode-short@0.1.0-alpha.1`, `@jimhoyd/urlcode-dynamic-link@0.1.0-alpha.1`, `@jimhoyd/urlcode-middleware@0.1.0-alpha.1`. Observed in passing: auth's dist-tags are split — `alpha` points at `0.1.0-alpha.2` while `latest` still points at `0.1.0-alpha.1`, so a plain `npm install @jimhoyd/urlcode-auth` resolves the older alpha. GitHub Releases attach a Homebrew formula (`urlcode.rb`) for manual copy into a tap, not an automated Homebrew Core/tap publish. No provider adapter guarantee. |
|
|
45
|
+
|
|
46
|
+
`npm run check:downstream-skills` is a manual, advisory report worth running
|
|
47
|
+
before a release: it diffs core's `.claude/skills/` copies against copies
|
|
48
|
+
vendored by downstream repositories (currently `urlcode-template`) when that
|
|
49
|
+
repository is cloned as a sibling checkout, and prints how many lines differ
|
|
50
|
+
per skill. It never fails and never asserts which side is correct -- a
|
|
51
|
+
downstream repo commonly pins an older published core version, and
|
|
52
|
+
divergence from core's current `main` can be the *correct* reflection of
|
|
53
|
+
that pin rather than staleness (see issue #155). It is not part of `check`
|
|
54
|
+
or `verify` because it depends on an out-of-repo sibling checkout that
|
|
55
|
+
normal CI does not have; it is a prompt to review the diff against the
|
|
56
|
+
downstream pin, not a pass/fail gate.
|
|
39
57
|
|
|
40
58
|
`npm audit --omit=dev` now runs in CI and fails the build on any runtime advisory;
|
|
41
59
|
development-only advisories are reported without blocking. Dependabot proposes npm,
|
|
@@ -49,22 +67,20 @@ These remain open. Record workload, runtime/app/image revisions, environment,
|
|
|
49
67
|
commands, results and owner for each exercise; do not convert a passing local
|
|
50
68
|
benchmark into a universal throughput claim.
|
|
51
69
|
|
|
52
|
-
1. Independent review of host/sandbox boundaries
|
|
70
|
+
1. Independent review of host/sandbox boundaries.
|
|
53
71
|
2. Sustained load and soak on intended hardware, through the actual TLS/proxy
|
|
54
72
|
path: successful throughput, tail latency, 503/504 rate, RSS and recovery.
|
|
55
73
|
`urlcode benchmark --target` measures a running deployment through its real
|
|
56
74
|
path and separates shed responses from transport errors; see
|
|
57
75
|
[load testing](LOAD-TESTING.md). The tool is GET/HEAD only and caps at 300
|
|
58
76
|
seconds, so it does not by itself close this gate.
|
|
59
|
-
Include mixed native/function
|
|
60
|
-
3.
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
4.
|
|
64
|
-
exercises with the chosen supervisor, ingress and persistent storage.
|
|
65
|
-
5. Alerting and ownership for sustained errors, latency, readiness, dropped logs,
|
|
77
|
+
Include mixed native/function workloads and slow peers.
|
|
78
|
+
3. Kill/restart, resource exhaustion and rolling deployment/rollback
|
|
79
|
+
exercises with the chosen supervisor and ingress. A future durable-state
|
|
80
|
+
extension needs its own backup/restore drill; core has no durable store.
|
|
81
|
+
4. Alerting and ownership for sustained errors, latency, readiness, dropped logs,
|
|
66
82
|
disk space, restarts and backups. Pick service objectives for the actual app.
|
|
67
|
-
|
|
83
|
+
5. Stable-release support commitments before packaging/public reuse claims.
|
|
68
84
|
Private security reporting and the current support baseline are documented in
|
|
69
85
|
SECURITY.md.
|
|
70
86
|
|
|
@@ -72,12 +88,13 @@ License selection is resolved: URLCode is released under the Apache License 2.0,
|
|
|
72
88
|
`package.json` declares it, and the repository carries the full license text.
|
|
73
89
|
The remaining gates above are engineering and operational, not legal.
|
|
74
90
|
|
|
75
|
-
The
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
execution target
|
|
80
|
-
capabilities
|
|
91
|
+
The unreleased next-phase source now includes strict bulk/provider interchange,
|
|
92
|
+
local recipes, TypeScript authoring, bounded self-hosted proxy/signals and read-only
|
|
93
|
+
MCP. Local AWS/Vercel/Cloudflare adapter tests and deployment probe tooling exist,
|
|
94
|
+
but actual provider deployments remain unverified. Node process/container hosting
|
|
95
|
+
remains the reference execution target. Guest networking, durable signals and
|
|
96
|
+
realtime capabilities are not provided. See [implementation status](NEXT-PHASE-PLAN.md)
|
|
97
|
+
and [roadmap](../ROADMAP.md); these additions do not close the operational gates above.
|
|
81
98
|
|
|
82
99
|
The [internal security audit](SECURITY-AUDIT.md) records reproduced findings, fixes
|
|
83
100
|
and prioritized gaps. Its regressions supplement these gates; they do not replace
|
|
@@ -86,10 +103,15 @@ independent assessment or real deployment exercises.
|
|
|
86
103
|
## Hardening follow-up
|
|
87
104
|
|
|
88
105
|
Implemented: bounded YAML workers and aggregate source budgets, cooperative route
|
|
89
|
-
compilation deadline,
|
|
90
|
-
|
|
91
|
-
|
|
106
|
+
compilation deadline, scoped/expiring/revocable operator credentials for host
|
|
107
|
+
bindings, executable local/CI operational drills, and a main-only candidate
|
|
108
|
+
signing/SBOM workflow. The loopback-only management API and its atomic SQLite
|
|
109
|
+
mutation audits were part of the `link`/`dynamicLinks` store that PR #126
|
|
110
|
+
removed from core; that functionality, and its hardening, now belongs to the
|
|
111
|
+
`urlcode-dynamic-link` extension (docs/EXTENSIONS.md), published on npm as
|
|
112
|
+
`@jimhoyd/urlcode-dynamic-link@0.1.0-alpha.1` as of 2026-09-19, not this
|
|
113
|
+
runtime.
|
|
92
114
|
|
|
93
115
|
Still required: [independent review](SANDBOX-REVIEW.md), [actual deployment proof](OPERATIONAL-PROOF.md),
|
|
94
|
-
and publication/support arrangements. The Apache-2.0 license and the 0.
|
|
116
|
+
and publication/support arrangements. The Apache-2.0 license and the 0.3.0 self-hosted
|
|
95
117
|
release do not close the security and deployment gates. See [release process](RELEASE-SECURITY.md).
|
package/docs/RELEASE-SECURITY.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Candidate and release security process
|
|
2
2
|
|
|
3
|
-
URLCode 0.
|
|
3
|
+
URLCode 0.3.0 is the Apache-2.0 self-hosted baseline; licensing is defined
|
|
4
4
|
in [LICENSE](../LICENSE). Two workflows share one audited build path and differ
|
|
5
5
|
only in what they do with its output:
|
|
6
6
|
|
|
@@ -14,6 +14,16 @@ only in what they do with its output:
|
|
|
14
14
|
Neither workflow is a statement that a release is production-ready; see
|
|
15
15
|
[release readiness](RELEASE-READINESS.md).
|
|
16
16
|
|
|
17
|
+
## Publishing an alpha
|
|
18
|
+
|
|
19
|
+
An alpha such as `0.4.0-alpha.1` follows the same path: tag `v0.4.0-alpha.1`
|
|
20
|
+
on a commit that is already on main. The release workflow publishes to npm
|
|
21
|
+
only when the repository variable `PUBLISH_NPM` is `true` and the npm trusted
|
|
22
|
+
publisher for this repository and `release.yml` exists; otherwise the run is
|
|
23
|
+
artifacts-only (a GitHub release with the signed tarball). Publish order is
|
|
24
|
+
core → ui → auth → admin, because the extension packages declare
|
|
25
|
+
`@jimhoyd/urlcode >=0.4.0-alpha.1 <0.5.0` and must resolve the core alpha.
|
|
26
|
+
|
|
17
27
|
1. Report vulnerabilities privately through [GitHub advisories](https://github.com/jimhoyd-com/urlcode/security/advisories/new).
|
|
18
28
|
The maintainer triages impact, confirms affected exact revisions, coordinates a
|
|
19
29
|
fix/retest privately, and publishes an advisory with upgrade guidance when safe.
|
|
@@ -47,10 +57,23 @@ Neither workflow is a statement that a release is production-ready; see
|
|
|
47
57
|
signing key is stored. Signing permissions exist only in this manual job; build
|
|
48
58
|
commands run in a container without passing GitHub tokens. Candidate files are
|
|
49
59
|
retained as GitHub Actions artifacts for 30 days. A release additionally attaches
|
|
50
|
-
them to the GitHub release, and publishes to npm
|
|
51
|
-
|
|
60
|
+
them to the GitHub release, and publishes to npm and to GHCR when those
|
|
61
|
+
repository variables are enabled.
|
|
62
|
+
|
|
63
|
+
**npm publication holds no credential.** The registry is configured with a
|
|
64
|
+
trusted publisher naming this repository and `release.yml`, so the publish
|
|
65
|
+
step exchanges the job's OIDC identity for a credential that lives for the
|
|
66
|
+
length of one publish. There is no npm token in the repository's secrets to
|
|
67
|
+
leak, revoke or rotate, and a fork or another workflow cannot publish under
|
|
68
|
+
this package's name. Provenance is generated on that same identity, so
|
|
69
|
+
`--provenance` is not passed and its absence is not a downgrade.
|
|
70
|
+
|
|
71
|
+
A bearer token would silently take precedence over this exchange, so the
|
|
72
|
+
publish step must reference none; `test/release.test.ts` fails if one
|
|
73
|
+
reappears in it, and checks the npm and Node floors below which the exchange
|
|
74
|
+
is not attempted at all.
|
|
52
75
|
5. Download the candidate for the intended commit and verify **each file**, e.g.
|
|
53
|
-
`gh attestation verify urlcode-0.
|
|
76
|
+
`gh attestation verify jimhoyd-urlcode-0.3.0.tgz --repo jimhoyd-com/urlcode --signer-workflow jimhoyd-com/urlcode/.github/workflows/candidate.yml --source-ref refs/heads/main --source-digest APPROVED_COMMIT_SHA`
|
|
54
77
|
(use `release.yml` as the signer workflow for a tagged release).
|
|
55
78
|
Check the verified provenance's source commit against the approved commit, and
|
|
56
79
|
compare package/SBOM hashes with the signed manifest. A signature establishes
|
|
@@ -67,6 +90,92 @@ The SBOM describes npm dependencies; it is not a complete OS/container SBOM. Hos
|
|
|
67
90
|
runners and action runtimes remain platform-controlled. Digest pins improve supply
|
|
68
91
|
chain integrity but do not prove byte-for-byte reproducibility or engine safety.
|
|
69
92
|
Signing verification must be demonstrated on a successful main workflow run before
|
|
70
|
-
claiming a candidate has been signed. Workflow definition alone is not that evidence
|
|
71
|
-
`release.yml`
|
|
72
|
-
|
|
93
|
+
claiming a candidate has been signed. Workflow definition alone is not that evidence.
|
|
94
|
+
`release.yml` ran successfully for the first time publishing `v0.4.0-alpha.1`
|
|
95
|
+
(2026-09-18), after the fixes below; treat any repository whose workflow has not
|
|
96
|
+
had a real successful tagged run the same way this one was treated before that.
|
|
97
|
+
|
|
98
|
+
## What broke on every first release, and why
|
|
99
|
+
|
|
100
|
+
Four repositories (core, ui, auth, admin) each cut their first tagged release in
|
|
101
|
+
the same session. Every one hit a subset of the same bugs, because each
|
|
102
|
+
`release.yml` was written and reviewed but never actually run end-to-end against
|
|
103
|
+
a real tag before. None of this is repository-specific; check for all of it
|
|
104
|
+
before trusting an unexercised release workflow:
|
|
105
|
+
|
|
106
|
+
- **`npm ci` on the bare runner's root-owned npm.** A build that runs entirely
|
|
107
|
+
inside a pinned Docker image never calls `actions/setup-node`, so a later
|
|
108
|
+
`npm install --global npm@11.5.1` (needed for the trusted-publishing floor)
|
|
109
|
+
hits the runner's preinstalled, root-owned npm and fails `EACCES`. Add
|
|
110
|
+
`actions/setup-node` before any step that installs global npm packages, even
|
|
111
|
+
if the main build never touches the runner's own Node.
|
|
112
|
+
- **The floor check must run after the pin, not before.** A guard asserting
|
|
113
|
+
"npm ≥ 11.5.1" is useless directly after `setup-node` with `node-version: '22'`,
|
|
114
|
+
which bundles npm ~10.9.x — it can never pass. The floor only means something
|
|
115
|
+
once the publish step's own `npm install --global npm@11.5.1` has actually run.
|
|
116
|
+
- **`npm publish` refuses an unqualified prerelease.** `You must specify a tag
|
|
117
|
+
using --tag when publishing a prerelease version.` npm's safety default is
|
|
118
|
+
`latest`; a prerelease must derive an explicit dist-tag from its version
|
|
119
|
+
(`0.1.0-alpha.1` → `alpha`, anything without a `-` → `latest`) and pass
|
|
120
|
+
`--tag`. This path is only exercised by a package's *first* prerelease, so it
|
|
121
|
+
silently sat broken in every repository until each hit it for the first time.
|
|
122
|
+
- **`npm pack --pack-destination candidate` needs `candidate/` to exist first.**
|
|
123
|
+
npm does not create the destination directory; `mkdir -p candidate` first.
|
|
124
|
+
- **A private repository's unauthenticated `git fetch origin main` cannot work.**
|
|
125
|
+
If checkout uses `persist-credentials: false` (correct, for a step that
|
|
126
|
+
should not need write access) and the repo is private, `git fetch` fails
|
|
127
|
+
`could not read Username for 'https://github.com'` before ever reaching the
|
|
128
|
+
version check. Compare the tag against main through the GitHub API instead
|
|
129
|
+
(`gh api repos/OWNER/REPO/compare/main...SHA --jq .status`, expecting
|
|
130
|
+
`identical` or `behind`) — it needs no credentials and stays read-only. Public
|
|
131
|
+
repositories can keep the plain fetch; it works there.
|
|
132
|
+
- **`--conditions=development` in `npm run verify`'s test script resolves peers
|
|
133
|
+
to source that a real npm install never ships.** The regular CI job symlinks
|
|
134
|
+
sibling checkouts in place of `node_modules`, so `./src/*.ts` exists and the
|
|
135
|
+
flag is correct there. A release installs real published tarballs of its
|
|
136
|
+
peers, which only ever ship `dist/`, so the same flag makes every import of a
|
|
137
|
+
peer fail `ERR_MODULE_NOT_FOUND`. Drop the flag for the release-workflow test
|
|
138
|
+
invocation specifically (run `node scripts/check-sqlite.mjs` explicitly first,
|
|
139
|
+
since bypassing `npm test` skips that pretest hook), and audit any test file
|
|
140
|
+
that separately hardcodes the flag in a spawned child process — it has to be
|
|
141
|
+
fixed the same way, independently, wherever it appears.
|
|
142
|
+
- **A peer-install command with the wrong flag combination is a silent no-op.**
|
|
143
|
+
`npm install --no-save --no-package-lock --ignore-scripts --legacy-peer-deps
|
|
144
|
+
<peer>@<version>` installed *nothing*, with no error, when the target package
|
|
145
|
+
names already appear in `peerDependencies` — `npm ci` earlier reports "added N
|
|
146
|
+
packages" as if it worked. Confirm the install actually happened
|
|
147
|
+
(`ls node_modules/@scope/*/package.json` and print each version) rather than
|
|
148
|
+
trusting the exit code; `--no-save --ignore-scripts <specs>` (no
|
|
149
|
+
`--no-package-lock`, no `--legacy-peer-deps`) is the version that works, paired
|
|
150
|
+
with `git diff --exit-code -- package.json package-lock.json` to prove nothing
|
|
151
|
+
was recorded as a dependency.
|
|
152
|
+
- **A version published from an unbuilt checkout is burned forever.** npm never
|
|
153
|
+
allows a version to be replaced. `@jimhoyd/urlcode-auth@0.1.0-alpha.1` reached
|
|
154
|
+
the registry from something other than the CI workflow (a manual `npm
|
|
155
|
+
publish` run before `npm run build` had produced `dist/`), so the published
|
|
156
|
+
tarball contained only metadata files and no code. Every consumer's typecheck
|
|
157
|
+
failed with `Cannot find module '@jimhoyd/urlcode-auth'` — a real, correct
|
|
158
|
+
failure, not a bug in the consumer. The only fix is bumping to a new version
|
|
159
|
+
and publishing that instead; nothing can repair or unpublish the bad one.
|
|
160
|
+
**Never run `npm publish` by hand outside the release workflow** — the
|
|
161
|
+
workflow is the only place that reliably builds before packing.
|
|
162
|
+
- **`ENEEDAUTH` on `npm publish` under trusted publishing usually means the
|
|
163
|
+
registry-side configuration doesn't exist or doesn't permit direct publish
|
|
164
|
+
yet**, not a workflow bug. Trusted publishing needs an entry under the
|
|
165
|
+
package's npm settings ("Trusted Publisher") naming the exact GitHub
|
|
166
|
+
org/repo and workflow filename, with no environment set unless the workflow
|
|
167
|
+
declares one; recent npm UI changes default new configurations to
|
|
168
|
+
"stage publish" only; "allow npm publish" (direct publish, which is what
|
|
169
|
+
this project's workflows do) must be explicitly enabled too. A wrong
|
|
170
|
+
org/repo/workflow match tends to surface as a 404, not `ENEEDAUTH`;
|
|
171
|
+
`ENEEDAUTH` is the signature of no matching configuration existing at all.
|
|
172
|
+
- **Publish order matters and is easy to get backwards.** Extension packages
|
|
173
|
+
declare `@jimhoyd/urlcode >=X <Y` as a peer range; publish core before ui,
|
|
174
|
+
auth or admin, or their own release-workflow peer-install step has nothing
|
|
175
|
+
real to resolve against.
|
|
176
|
+
|
|
177
|
+
None of the above is exotic; all nine bugs were found by actually running each
|
|
178
|
+
workflow against a real tag, one release at a time, and reading the actual
|
|
179
|
+
failure rather than guessing from the workflow source. Treat "the workflow file
|
|
180
|
+
looks right" and "the workflow has actually published successfully once" as two
|
|
181
|
+
different, unrelated claims.
|