@jimhoyd/urlcode 0.4.2 → 0.4.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (214) hide show
  1. package/.claude/skills/urlcode-authoring/SKILL.md +57 -14
  2. package/.claude/skills/urlcode-operations/SKILL.md +4 -0
  3. package/README.md +42 -18
  4. package/SECURITY.md +5 -3
  5. package/dist/BUILD-MANIFEST.json +30 -27
  6. package/dist/agent-context.js +82 -0
  7. package/dist/agents-guide.js +42 -42
  8. package/dist/authoring.js +12 -2
  9. package/dist/body-schema.js +159 -0
  10. package/dist/build-cloudflare.js +2 -0
  11. package/dist/capabilities.js +1 -1
  12. package/dist/cli.js +28 -12
  13. package/dist/config.js +74 -6
  14. package/dist/context.js +4 -6
  15. package/dist/errors.js +3 -1
  16. package/dist/examples.js +1 -1
  17. package/dist/extensions.js +60 -2
  18. package/dist/http-policy.js +19 -4
  19. package/dist/http-response.js +2 -2
  20. package/dist/init-with.js +71 -9
  21. package/dist/mcp.js +15 -2
  22. package/dist/pattern-guard.js +32 -0
  23. package/dist/policies/security.js +0 -0
  24. package/dist/project-tests.js +35 -11
  25. package/dist/readiness.js +184 -32
  26. package/dist/recipes.js +1 -1
  27. package/dist/router.js +17 -0
  28. package/dist/runtime.js +26 -3
  29. package/dist/scaffold.js +0 -0
  30. package/dist/server.js +26 -3
  31. package/dist/site.js +0 -0
  32. package/dist/tooling.js +2 -1
  33. package/dist/types/agent-context.d.ts +44 -0
  34. package/dist/types/authoring.d.ts +3 -1
  35. package/dist/types/body-schema.d.ts +58 -0
  36. package/dist/types/config.d.ts +10 -2
  37. package/dist/types/context.d.ts +1 -1
  38. package/dist/types/errors.d.ts +9 -1
  39. package/dist/types/examples.d.ts +1 -1
  40. package/dist/types/extensions.d.ts +47 -2
  41. package/dist/types/http-policy.d.ts +3 -0
  42. package/dist/types/init-with.d.ts +10 -1
  43. package/dist/types/pattern-guard.d.ts +10 -0
  44. package/dist/types/project-tests.d.ts +9 -0
  45. package/dist/types/readiness.d.ts +68 -0
  46. package/dist/types/recipes.d.ts +1 -1
  47. package/dist/types/runtime.d.ts +4 -0
  48. package/dist/types/server.d.ts +9 -1
  49. package/dist/types/tooling.d.ts +1 -0
  50. package/dist/types/types.d.ts +13 -0
  51. package/dist/types.js +10 -2
  52. package/dist/typescript-authoring.js +5 -3
  53. package/dist/verify-deployment.js +16 -10
  54. package/examples/body-validation/README.md +16 -0
  55. package/examples/body-validation/example.yaml +17 -0
  56. package/examples/body-validation/tests/requests.json +15 -0
  57. package/examples/body-validation/urlcode.yaml +34 -0
  58. package/examples/coverage-waiver/README.md +8 -0
  59. package/examples/coverage-waiver/example.yaml +16 -0
  60. package/examples/coverage-waiver/functions/notes.mjs +2 -0
  61. package/examples/coverage-waiver/tests/requests.json +3 -0
  62. package/examples/coverage-waiver/urlcode.yaml +10 -0
  63. package/examples/data-dir/README.md +39 -0
  64. package/examples/data-dir/data/welcome.txt +1 -0
  65. package/examples/data-dir/example.yaml +22 -0
  66. package/examples/data-dir/functions/note.mjs +18 -0
  67. package/examples/data-dir/tests/requests.json +6 -0
  68. package/examples/data-dir/urlcode.yaml +6 -0
  69. package/examples/lifecycle/README.md +15 -0
  70. package/examples/lifecycle/example.yaml +19 -0
  71. package/examples/lifecycle/functions/notes.mjs +29 -0
  72. package/examples/lifecycle/tests/requests.json +12 -0
  73. package/examples/lifecycle/urlcode.yaml +29 -0
  74. package/examples/not-found/README.md +10 -0
  75. package/examples/not-found/example.yaml +17 -0
  76. package/examples/not-found/public/404.html +3 -0
  77. package/examples/not-found/public/index.html +3 -0
  78. package/examples/not-found/tests/requests.json +7 -0
  79. package/examples/not-found/urlcode.yaml +7 -0
  80. package/examples/shared-blocks/README.md +11 -0
  81. package/examples/shared-blocks/example.yaml +17 -0
  82. package/examples/shared-blocks/tests/requests.json +7 -0
  83. package/examples/shared-blocks/urlcode.yaml +37 -0
  84. package/llms-full.txt +364 -49
  85. package/llms.txt +44 -6
  86. package/package.json +15 -26
  87. package/recipes/static-page/README.md +9 -0
  88. package/recipes/static-page/public/index.html +11 -0
  89. package/recipes/static-page/recipe.yaml +21 -0
  90. package/recipes/static-page/tests/requests.json +22 -0
  91. package/recipes/static-page/urlcode.yaml +7 -0
  92. package/recipes/static-plus-api/README.md +6 -0
  93. package/recipes/static-plus-api/urlcode.yaml +4 -0
  94. package/recipes/store-crud/README.md +53 -0
  95. package/recipes/store-crud/recipe.yaml +31 -0
  96. package/recipes/store-crud/tests/requests.json +18 -0
  97. package/recipes/store-crud/urlcode.yaml +18 -0
  98. package/schemas/urlcode.schema.json +125 -60
  99. package/skills/urlcode/SKILL.md +47 -27
  100. package/starters/default/AGENTS.md +43 -43
  101. package/starters/page/README.md +14 -0
  102. package/starters/page/public/index.html +12 -0
  103. package/starters/page/tests/requests.json +17 -0
  104. package/starters/page/urlcode.yaml +6 -0
  105. package/.claude-plugin/marketplace.json +0 -18
  106. package/CONTRIBUTING.md +0 -148
  107. package/ROADMAP.md +0 -70
  108. package/docs/AI-AUTHORING.md +0 -339
  109. package/docs/ASSETS.md +0 -107
  110. package/docs/AUTH-BACKUP.md +0 -32
  111. package/docs/AWS.md +0 -86
  112. package/docs/BEST-PRACTICES.md +0 -276
  113. package/docs/BULK.md +0 -79
  114. package/docs/CAPABILITIES.md +0 -192
  115. package/docs/CAPACITY.md +0 -305
  116. package/docs/CI-FOLLOWUP-2026-09-19.md +0 -97
  117. package/docs/CI-RELEASE-AUDIT-2026-09-19.md +0 -322
  118. package/docs/CI.md +0 -147
  119. package/docs/CLOUDFLARE.md +0 -109
  120. package/docs/CODEBASE-AUDIT-2026-09-20.md +0 -284
  121. package/docs/COMPLIANCE.md +0 -239
  122. package/docs/COMPOSING-A-SITE.md +0 -287
  123. package/docs/CONDITIONS.md +0 -74
  124. package/docs/CONTAINER-PROMOTION.md +0 -74
  125. package/docs/DEPLOYMENT-CHECKS.md +0 -108
  126. package/docs/DEVELOPMENT-PIPELINE.md +0 -304
  127. package/docs/EGRESS.md +0 -125
  128. package/docs/EXTENSIONS.md +0 -403
  129. package/docs/FRAMEWORK.md +0 -217
  130. package/docs/FUNCTION-SECURITY.md +0 -251
  131. package/docs/HTTP.md +0 -129
  132. package/docs/INSTALL.md +0 -128
  133. package/docs/INTERCHANGE.md +0 -134
  134. package/docs/LOAD-TESTING.md +0 -91
  135. package/docs/LOCAL-DEVELOPMENT.md +0 -102
  136. package/docs/MIDDLEWARE-EXAMPLES.md +0 -75
  137. package/docs/MIDDLEWARE.md +0 -102
  138. package/docs/MONITORING.md +0 -115
  139. package/docs/OBSERVABILITY.md +0 -222
  140. package/docs/OPEN-DECISIONS.md +0 -149
  141. package/docs/OPERATIONAL-PROOF.md +0 -41
  142. package/docs/OPERATIONS.md +0 -201
  143. package/docs/ORGANIZATION.md +0 -135
  144. package/docs/PERFORMANCE.md +0 -72
  145. package/docs/PLUGINS.md +0 -271
  146. package/docs/POLICIES.md +0 -211
  147. package/docs/PRERENDER.md +0 -245
  148. package/docs/PROJECT-DIRECTION.md +0 -118
  149. package/docs/PROVIDER-VERIFICATION.md +0 -84
  150. package/docs/READINESS.md +0 -153
  151. package/docs/README.md +0 -93
  152. package/docs/RECIPES.md +0 -99
  153. package/docs/RELEASE-0.4.0-alpha.3.md +0 -50
  154. package/docs/RELEASE-0.4.1.md +0 -73
  155. package/docs/RELEASE-0.4.2.md +0 -30
  156. package/docs/RELEASE-READINESS.md +0 -146
  157. package/docs/RELEASE-SECURITY.md +0 -100
  158. package/docs/RESILIENCE.md +0 -161
  159. package/docs/ROUTING.md +0 -92
  160. package/docs/SANDBOX-REVIEW.md +0 -72
  161. package/docs/SCAFFOLDING.md +0 -70
  162. package/docs/SECURITY-AUDIT.md +0 -164
  163. package/docs/SITE.md +0 -150
  164. package/docs/SPECIFICATION.md +0 -359
  165. package/docs/SPIKE-AI-FRAMEWORK-BENCHMARK.md +0 -288
  166. package/docs/SPIKE-BUSINESS-SUITE.md +0 -1029
  167. package/docs/SPIKE-CORE-LAYERING.md +0 -368
  168. package/docs/SPIKE-DEFAULT-TRUST-MODEL.md +0 -207
  169. package/docs/STANDARDS.md +0 -311
  170. package/docs/STARTERS.md +0 -83
  171. package/docs/STATIC.md +0 -105
  172. package/docs/TOOLING.md +0 -298
  173. package/docs/TUNNELS.md +0 -72
  174. package/docs/TYPESCRIPT-AUTHORING.md +0 -87
  175. package/docs/TYPESCRIPT.md +0 -123
  176. package/docs/VERCEL.md +0 -114
  177. package/docs/VERSION-ALIGNMENT.md +0 -88
  178. package/docs/YAML-GUIDE.md +0 -57
  179. package/docs/YAML-REFERENCE.md +0 -449
  180. package/docs/archive/2026-09-19/EXTENSION-IMPLEMENTATION.md +0 -68
  181. package/docs/archive/2026-09-19/MANAGEMENT-SECURITY.md +0 -102
  182. package/docs/archive/2026-09-19/NEXT-PHASE-PLAN.md +0 -108
  183. package/docs/archive/2026-09-19/NEXT-STEPS.md +0 -646
  184. package/docs/archive/2026-09-19/OPEN-DECISIONS.md +0 -277
  185. package/docs/archive/2026-09-19/RELEASE-SECURITY.md +0 -186
  186. package/docs/archive/2026-09-19/ROADMAP.md +0 -387
  187. package/docs/archive/2026-09-19/SPIKE-EXTENSION-MODEL.md +0 -430
  188. package/docs/archive/2026-09-19/SPIKE-EXTENSIONS.md +0 -492
  189. package/docs/archive/2026-09-19/SPIKE-LAMBDA-COMPILE.md +0 -365
  190. package/docs/archive/2026-09-19/SPIKE-MONOREPO.md +0 -778
  191. package/docs/archive/2026-09-19/USABILITY-REVIEW.md +0 -139
  192. package/docs/archive/2026-09-20/OPEN-DECISIONS-COMPLETED.md +0 -116
  193. package/docs/archive/README.md +0 -29
  194. package/docs/policies/agents.md +0 -182
  195. package/docs/policies/cache.md +0 -152
  196. package/docs/policies/compression.md +0 -169
  197. package/docs/policies/contract.md +0 -52
  198. package/docs/policies/hardened.md +0 -56
  199. package/docs/policies/interoperability.md +0 -169
  200. package/docs/policies/operations.md +0 -45
  201. package/docs/policies/security.md +0 -161
  202. package/docs/policies/throttle.md +0 -103
  203. package/docs/yaml/assets.md +0 -36
  204. package/docs/yaml/conditions.md +0 -20
  205. package/docs/yaml/functions.md +0 -168
  206. package/docs/yaml/middleware.md +0 -31
  207. package/docs/yaml/organization.md +0 -74
  208. package/docs/yaml/policies.md +0 -37
  209. package/docs/yaml/redirects.md +0 -64
  210. package/docs/yaml/responses.md +0 -57
  211. package/docs/yaml/site.md +0 -24
  212. package/packaging/claude-plugin/.claude-plugin/plugin.json +0 -19
  213. package/packaging/claude-plugin/skills/urlcode-authoring/SKILL.md +0 -130
  214. package/packaging/claude-plugin/skills/urlcode-operations/SKILL.md +0 -108
@@ -1,304 +0,0 @@
1
- # Development and release pipeline
2
-
3
- The repository uses npm workspaces, independent package versions, and Changesets
4
- for UI, auth and admin. Core remains at the repository root and is explicitly
5
- included in the shared release inventory. Moving it is not required to use the
6
- same release checks and coordinator.
7
-
8
- ## Pull requests and main pushes
9
-
10
- Every PR and every push to main starts `verify`. A complete Git diff selects one
11
- of two lanes:
12
-
13
- - **Prose:** root project Markdown, `docs/**/*.md`, `llms.txt`, `llms-full.txt`,
14
- `benchmarks/agent/README.md`, `benchmarks/results/README.md` and each
15
- package's `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md` and `GOVERNANCE.md` run
16
- guidance/generated-resource checks, runtime audit, and the required container
17
- job. CodeQL retains its repository policy.
18
- - **Full:** all other changes, mixed changes, and empty, unclassifiable or
19
- unavailable diffs run static checks once and core and workspace suites
20
- separately. Both suites retain Linux on Node 22/24/26. Main adds
21
- Windows/macOS on Node 24. PRs add those platform legs for runtime, CLI,
22
- SQLite, fixture, dependency, workflow and unknown changes; known UI
23
- presentation-only changes omit them. Package, action, cookbook,
24
- reproducibility and operational checks retain their coverage.
25
-
26
- A pull request is classified against its merge base; a push to main is
27
- classified tip to tip from the event's `before`/`after` SHAs, so a force-push or
28
- rewritten history is measured by what actually moved. Classification fails
29
- closed: a missing, malformed or all-zero SHA (branch creation or deletion), and
30
- history this checkout cannot read, select full verification. Scheduled and
31
- manually dispatched runs are never classified from paths at all, so exact-SHA
32
- release coverage cannot silently become a docs-only run.
33
-
34
- The prose allowlist is deliberately narrow, and it is a list of reviewed,
35
- non-executable contributor prose rather than "every Markdown file". Skills,
36
- starters, recipes, examples, schemas, manifests, workflows, benchmark prompts,
37
- tasks, answers and acceptance notes, and any package document that ships inside
38
- a published tarball or is read by an agent surface (`README.md`, `SECURITY.md`,
39
- `CONTRACT.md`, `THREAT-MODEL.md`, `IMPLEMENTATION-STATUS.md`, `AGENTS.md`,
40
- `CHANGELOG.md`) select full checks. Anything feeding a generator stays in the
41
- code lane. A rename from source into docs also selects full checks, because the
42
- diff is read without rename detection and shows both paths. Every prose path is
43
- still covered by the always-run `docs` job, which walks all authored Markdown.
44
- No required workflow uses `paths-ignore`.
45
-
46
- The always-run `docs` job runs `npm run check:docs`; in the full lane the
47
- `static` job runs `npm run check:code`, which is the rest of `npm run check`.
48
- The two together are exactly `npm run check`, which stays complete for local
49
- use. This removes a duplicated dependency install plus seven repeated checks on
50
- the same commit, not meaningful wall time: the sampled documentation checking
51
- was about two seconds. Job names, lane selection and `verify-complete`
52
- dependencies are unchanged.
53
-
54
- `verify-complete` accepts only the results specified by the successful plan.
55
- Failed, canceled, missing or unexpectedly skipped work fails the gate. Required
56
- check names (`verify-complete`, `container`) and CodeQL enforcement are preserved.
57
- The repository ruleset currently does not require a branch to be up to date;
58
- release publication separately requires verification of the exact main commit.
59
-
60
- ```sh
61
- npm run check:docs # prose checks without the runtime suite
62
- npm run check:code # everything in `check` except the prose checks
63
- npm run ci:plan -- BASE_SHA HEAD_SHA # previews as a pull request outside Actions
64
- npm run ci:report -- RUN_ID # read GitHub job/step durations
65
- npm run ci:history -- 100 2026-09-19 # group historical timing samples
66
- npm run verify # full local validation remains available
67
- npm run test:package # builds and installs a real archive
68
- ```
69
-
70
- CI uses `test:package:built` only after building in that same job. Core tests and
71
- workspace tests run in separate jobs to shorten their serial critical path;
72
- this increases job setup overhead and needs monitoring for runner queue pressure.
73
- After building all three extensions, the workspace job also runs the real
74
- `init --with ui,auth,admin` scaffold integration. Missing workspace outputs fail
75
- instead of silently skipping an absent external checkout.
76
- The [audit](CI-RELEASE-AUDIT-2026-09-19.md) records the previous timings.
77
- The [follow-up measurements](CI-FOLLOWUP-2026-09-19.md) record early compact-main observations; issue #185 contains the later decision
78
- and current sample sizes.
79
-
80
- ## Version preparation and release ownership
81
-
82
- Core remains at the repository root. Independent extension versions remain
83
- supported; a coordinated version is an explicit maintainer choice, not a
84
- permanent fixed-version policy. An explicitly selected stable version exits
85
- Changesets alpha pre-mode when no package remains on alpha; subsequent stable
86
- patches stay out of pre-mode. Feature PRs record workspace release intent in
87
- Changesets; core release notes remain an explicit maintainer responsibility.
88
-
89
- `release:check` checks manifest/lock versions and peer ranges, CLI and MCP
90
- versions, generated plugin metadata, local peer compatibility, and channel policy.
91
- The preparation helper updates these together, adds release notes and extension
92
- changelogs, and records the version decision. Pending Changesets must be
93
- explicitly consumed; they are archived under `.changeset/pre/` and their summaries
94
- included in the release notes. Review the resulting diff and peer minimums.
95
-
96
- ```sh
97
- # Example only: choose the next intended version before executing.
98
- npm run release:prepare -- --version 0.4.1 --consume-changesets
99
- # Apply local edits on a clean non-main branch; no remote writes or publication:
100
- npm run release:prepare -- --version 0.4.1 --consume-changesets --execute
101
- ```
102
-
103
- An optional `--notes PATH` adds reviewed maintainer notes. Dry runs do not change
104
- files. Preparation rejects downgrades, reused local tags, dirty checkouts and
105
- stale plans. A stable target removes `.changeset/pre.json` once no package
106
- remains on alpha, publishes to npm `latest`, and leaves the historical `alpha`
107
- pointer unchanged. Alpha targets
108
- require existing alpha mode; the helper never silently re-enters prerelease mode.
109
- It does not invoke a permanent Changesets fixed-version policy.
110
-
111
- ## GitHub Actions release buttons
112
-
113
- The Actions page exposes `release core`, `release UI`, `release auth`, `release
114
- admin` and `release all packages`. Each manual workflow accepts an exact stable
115
- or alpha version and whether to consume relevant pending Changesets. The four
116
- package workflows update and publish only their selected package. `release all
117
- packages` aligns and publishes the complete train in core → UI → auth → admin
118
- order. A Changeset spanning selected and unselected packages is rejected; use
119
- the all-packages workflow or split the change intentionally.
120
-
121
- All five buttons call the same serialized reusable workflow. It creates a
122
- release PR, waits for normal required checks, merges without bypass, runs the
123
- exact-commit full matrix and signed candidate, publishes the selected immutable
124
- tag, checks registry installability, and verifies the current four-package
125
- consumer combination. A core release also updates the standalone starter. The
126
- workflow is resumable: rerun the same button and version after repairing a
127
- failure. It reuses matching PRs, tags, candidates and successful publishers.
128
-
129
- Configure `RELEASE_AUTOMATION_TOKEN` as a repository Actions secret. Prefer a
130
- repository-scoped GitHub App token when available. A fine-grained PAT is also
131
- supported when it is limited to `urlcode` and `urlcode-template` with Contents,
132
- Pull requests and Actions read/write. The repositories are public, so the
133
- coordinator can inspect their check runs without an additional token
134
- permission. The token owner needs ordinary write access. Do not grant ruleset
135
- bypass, administration, approval or package-registry credentials; npm
136
- publishers continue to use their workflow OIDC identities. Dispatch from
137
- `main`.
138
-
139
- ## One-command local release and resume
140
-
141
- Inspect without writing:
142
-
143
- ```sh
144
- npm run release:status # registry channels, peer compatibility, tag SHAs
145
- npm run release:plan # manifest-derived inventory
146
- npm run release:run # ordered states at this checkout: pending/resume/unchanged
147
- npm run release:run -- --version 0.4.1 --consume-changesets
148
- npm run release:run -- --version 0.4.2 --package auth --consume-changesets
149
- ```
150
-
151
- For an explicitly authorized coordinated release:
152
-
153
- ```sh
154
- npm run release:run -- --version 0.4.1 --consume-changesets --execute
155
- npm run release:run -- --version 0.4.2 --package auth --consume-changesets --execute
156
- ```
157
-
158
- `--execute` authorizes the entire sequence: create the release branch/PR, wait
159
- for checks and merge, run the release gates, create version tags, publish, verify
160
- an installed consumer, and create/check/merge the starter update. It never
161
- approves a review or bypasses a required check. A required human review still
162
- blocks merging. No write or publication occurs without `--execute`.
163
-
164
- The coordinator works in a temporary clone and prints its location. It prepares
165
- `codex/release-VERSION`, or resumes the existing PR/branch after checking its
166
- versions and receipt. It checks out the actual merged SHA and reinstalls that
167
- commit's locked dependencies. Repeating the command discovers existing PRs,
168
- gates, tags and workflow state rather than creating another version. Temporary
169
- release clones are retained for diagnosis and can be removed after completion.
170
-
171
- For an independently prepared release PR already merged to main, use a clean
172
- checkout of its exact commit:
173
-
174
- ```sh
175
- npm run release:run -- --execute
176
- ```
177
-
178
- The coordinator creates `codex/release-validation/SHA` at the already-merged
179
- commit when gates are missing. An existing validation branch must name that
180
- exact SHA; it is never moved. This lets main advance without changing the release
181
- being tested. The branches remain as audit/resume references. It dispatches full
182
- `ci.yml` and `candidate.yml`, reuses existing successful runs, and waits for
183
- running ones. A failed gate stops with its run ID; diagnose it and rerun that
184
- exact run before resuming. Compact PR/main checks cannot replace the full
185
- OS/Node matrix or CodeQL on the selected commit.
186
-
187
- Before creating any version tags, it downloads and verifies the candidate bundle.
188
- A green run with missing artifacts does not authorize tags. New version tags are
189
- annotated with the source commit, chosen candidate run ID and the SHA256 of its
190
- signed manifest. The manifest binds every package and supporting asset by hash. Every package in a
191
- resumed train must select that same candidate. Neither a later candidate of the
192
- same source nor a newer main commit can silently replace the chosen bytes.
193
- A successful rerun of the same candidate ID cannot substitute a changed bundle: its
194
- manifest must still match the immutable checksum in the release tag.
195
- After tags exist, rerun package publishers rather than the pinned candidate run.
196
- If a later attempt of that candidate run fails, the coordinator stops even when
197
- an earlier attempt succeeded; it does not infer which attempt should be trusted.
198
-
199
- Publication is sequential: core → UI → auth → admin, skipping unchanged published
200
- versions. Each publisher must succeed and its version must be readable through
201
- npm's abbreviated install metadata, with a downloadable SHA512-verified tarball,
202
- before dependents begin. Bounded retries handle propagation, transport failures,
203
- 429 and server errors; authentication and integrity failures stop immediately.
204
- Afterward, an external consumer with a fresh npm cache installs the four exact
205
- registry versions, checks its peer tree and imports, and generates the combined
206
- extension scaffold in dependency order (`ui,auth,admin`). The candidate archive
207
- smoke uses the same scaffold check before any package is published.
208
-
209
- The standalone starter helper updates the exact core pin, lockfile, matching
210
- schema/docs links and guide from the installed published core package, then runs
211
- validation/tests/audit/benchmark,
212
- and opens a resumable PR. The coordinator waits for checks and merges it, checking
213
- for a newer template pin immediately before merge. `--skip-template` explicitly
214
- leaves this follow-up to the maintainer. To run only that follow-up:
215
-
216
- ```sh
217
- npm run release:template -- --version 0.4.1 --execute
218
- ```
219
-
220
- That standalone helper opens a PR but does not merge it. All helpers stop on
221
- errors; rerun after diagnosis. A failed publisher is retried at most once per
222
- coordinator invocation and must pass the original-byte recovery checks below.
223
-
224
- The maintainer identity needs repository Contents, Actions and Pull requests
225
- write, plus Checks read, on the affected repositories. GitHub App installations
226
- should be scoped to URLCode and its template. No ruleset bypass or long-lived
227
- npm token is needed. The workflow `GITHUB_TOKEN` must not create the triggering
228
- version tags because its push events do not start ordinary push workflows.
229
- [GitHub App guidance](https://docs.github.com/en/apps/creating-github-apps/about-creating-github-apps/deciding-when-to-build-a-github-app)
230
-
231
- ## Build once, publish verified bytes
232
-
233
- The four publisher filenames remain unchanged for npm trusted-publisher identity.
234
- The candidate builds in the digest-pinned environment, runs verification,
235
- packaging and local operational checks, packs all four packages, and tests an
236
- isolated combined consumer. The signed bundle contains all four archives,
237
- SBOM, Homebrew formula, source/build manifest, train identity and checksums.
238
- The manifest binds it to the candidate run as well as the commit.
239
-
240
- Publishers verify the selected candidate's workflow provenance, exact source SHA,
241
- run identity, manifest/package identities and hashes. They publish the selected
242
- package's existing archive without rebuilding it. Auth/admin still run isolated
243
- compatibility tests against their actual published peer floors; temporary test
244
- builds do not replace the promoted archive. This preserves the distinction
245
- between workspace compatibility and registry compatibility.
246
-
247
- Each package's GitHub release stores the complete signed bundle for durable
248
- recovery. Supporting sibling archives are candidate evidence: an independent
249
- package release does not imply every sibling archive was published to npm.
250
- Candidate and release Actions artifacts retain 90 days; retention is not an
251
- archival guarantee. Keep independent last-good copies for deployment rollback.
252
-
253
- ## Recovery, immutable tags and channels
254
-
255
- A retry restores the original retained bundle, or recovers the complete verified
256
- bundle from that package's GitHub release. Missing, incomplete or unverifiable
257
- originals stop the retry. It never rebuilds archives or substitutes a new
258
- candidate. If publication stopped before a complete durable release existed and
259
- the retained artifact is gone, a new version may be required.
260
-
261
- Existing npm versions must match SHA512 integrity; existing GitHub assets must
262
- match byte for byte. Partial npm/GitHub/GHCR success is possible and cannot be
263
- made atomic. Fix registry identity/settings where appropriate and resume the
264
- original run. A source change requires a new version and tag. Never delete,
265
- recreate, move or force-push version tags.
266
-
267
- These recovery changes apply to releases made with the new workflows. They cannot
268
- change the immutable workflow source at `0.4.0-alpha.3` or repair that historical
269
- run by rerunning it. The missing-artifact behavior observed there is recorded in
270
- [issue #223](https://github.com/jimhoyd-com/urlcode/issues/223).
271
-
272
- npm uses OIDC with pinned npm 11.5.1. Alpha versions use npm/GHCR `alpha`, and
273
- GitHub prerelease classification with `--latest=false`. Existing `latest`
274
- pointers are not promoted by this flow. Core GHCR publication remains conditional
275
- on `PUBLISH_CONTAINER=true`; its existing version/channel identity guards remain.
276
- Historical GHCR verification is still a separate follow-up. Digest promotion of a
277
- tested image is design only, in [CONTAINER-PROMOTION.md](CONTAINER-PROMOTION.md);
278
- the publisher still builds from source.
279
-
280
- The [Immutable release tags rule](https://github.com/jimhoyd-com/urlcode/rules/23712319)
281
- blocks updates/deletions of `v*` and `@jimhoyd/urlcode-*@*`, permits creation, and
282
- has no bypass actors. Main protection is unchanged. Source and artifact checks
283
- are not an independent security assessment, provider deployment or recovery
284
- proof. The next explicitly authorized new release must exercise the complete
285
- new promotion/recovery path. Progress and remaining work are recorded in
286
- [issue #185](https://github.com/jimhoyd-com/urlcode/issues/185).
287
-
288
- ### Windows fixture cleanup
289
-
290
- Auth/admin tests register resources with their package-local `test/cleanup.ts`.
291
- Cleanup runs in reverse acquisition order: close servers and SQLite services
292
- before deleting temporary directories, including services reopened by a test.
293
- Every registered callback is attempted even if another closer throws, and the
294
- combined error fails the test. Register each closer as soon as its resource opens.
295
- The suites use a five-minute test-file timeout so a stuck fixture is diagnosed
296
- before the CI job limit. Node applies this limit to whole test files too; the
297
- large auth-core file legitimately exceeds two minutes on Windows Node 22.
298
- Windows regression coverage runs on Node 24 for platform-sensitive PRs and
299
- main; nightly/manual runs cover Node 22/24/26.
300
-
301
- Failed auth service initialization also waits for its SQLite worker to terminate
302
- before rejecting. Callers can clean up or retry after a rejected open without
303
- racing a remaining database handle; configuration identity failures still fail
304
- closed with the same error code.
package/docs/EGRESS.md DELETED
@@ -1,125 +0,0 @@
1
- # Bounded proxy and webhook transport
2
-
3
- Outbound requests use a host-owned HTTPS transport. Guests do not receive a fetch
4
- API. Project declarations express behavior; an external operator policy, pinned
5
- to the complete project revision, grants exact HTTPS origins separately to proxy
6
- and signal operations. A configured destination never grants its own authority.
7
- Binding injection uses existing explicitly granted secrets, resolved before the
8
- host transport receives a literal header value. Never log those values.
9
-
10
- The transport resolves the destination for each request, refuses any DNS response
11
- containing a nonpublic address, and pins its connection lookup to one validated
12
- answer. HTTPS certificate and hostname verification remain enabled. There is no
13
- connection pool, fallback address, redirect following, or automatic retry. Private,
14
- loopback, link-local, documentation, multicast, IPv4-mapped IPv6 and transition
15
- addresses are refused. IPv6 filtering is deliberately conservative: 2001::/16,
16
- 2002::/16 and 3fff::/16 are refused along with addresses outside ordinary global
17
- unicast. Network-level egress controls remain useful defense in depth.
18
-
19
- Default limits per client are 16 simultaneous requests, five seconds including
20
- DNS, 1 MiB request and response bodies and 16 KiB headers. Excess concurrency is
21
- refused immediately. Requests use bounded buffering rather than streaming. Abort
22
- and shutdown destroy active HTTP requests; unresolved system DNS operations may
23
- finish in the background but cannot open a socket after cancellation. Those DNS
24
- operations retain a separate concurrency slot until they settle, so repeatedly
25
- timing out DNS cannot create an unbounded underlying lookup backlog. A shared
26
- 64-operation DNS cap also spans all client instances and runtime reloads in the
27
- host Node isolate; closing a client does not release an unresolved DNS slot. Closing a
28
- client refuses future requests and drains its bounded outstanding promises.
29
- Errors carry only a fixed category, never a destination, request, header or secret.
30
-
31
- Proxy destinations have a literal HTTPS authority. Path placeholders are encoded
32
- as individual components; dot-segment values are refused. Query names and incoming
33
- and outgoing headers require explicit selection. Host, framing, hop-by-hop and
34
- proxy-authorization headers cannot be supplied. Ambient authorization, cookies,
35
- forwarding metadata (the entire `x-forwarded-*` family) and Set-Cookie cannot be selected. Explicit host-resolved
36
- Authorization injection is supported. Set-Cookie forwarding is deliberately
37
- unsupported because multiple cookie fields cannot safely be represented by the
38
- portable scalar header contract. Upstream redirects are returned as responses;
39
- Location is forwarded only if explicitly selected and is never fetched. Headers
40
- nominated by an incoming or upstream Connection field are removed even if selected.
41
- Header names are normalized to lowercase; array-valued upstream fields are omitted.
42
- An encoded request body requires explicitly selecting its Content-Encoding
43
- header; literal header injection cannot change or replace that coding. Bodies
44
- remain raw bytes, including content encoding; select Content-Encoding when
45
- forwarding compressed responses. No transparent decompression occurs.
46
-
47
- Webhook signals are best effort. The broker schedules work after the caller's
48
- synchronous emit operation, with eight concurrent deliveries by default and no
49
- queue. Saturation and closed brokers drop new events. Each event contains only
50
- version, declared route pattern, status and method: never the actual request URL,
51
- parameters, body, client identity, incoming headers or bindings. The webhook
52
- receives a POST with JSON. Only 2xx responses count as delivered; all other status
53
- codes and transport failures count as failed. Delivery order is unspecified,
54
- there are no retries or durability guarantees, and shutdown aborts outstanding
55
- work and awaits settlement. Counter snapshots report accepted, delivered, failed
56
- and dropped events without including destination data. Applications must not use
57
- these signals for guaranteed billing, audit retention or job execution.
58
-
59
- The transport is a new security-sensitive host bridge. Unit tests and CI are not
60
- an independent assessment or proof of hostile multi-tenant readiness. Public
61
- provider network deployments require separate operator-owned fixtures and evidence.
62
-
63
- ## Project declarations and external grants
64
-
65
- ```yaml
66
- version: "1"
67
- routes:
68
- /items/{id}:
69
- proxy:
70
- url: https://api.example.com/items/{id}
71
- query: [page]
72
- requestHeaders: [accept]
73
- responseHeaders: [content-type, content-encoding]
74
- headers:
75
- authorization: {secret: API_TOKEN}
76
- parameters:
77
- - {name: id, in: path, required: true, schema: {type: string}}
78
- secrets:
79
- API_TOKEN: {secret: UPSTREAM_AUTHORIZATION}
80
- signals:
81
- - url: https://hooks.example.com/events
82
- ```
83
-
84
- An injected secret is the complete header value (for example an operator-provided
85
- Bearer value); interpolation and ambient credentials are not supported. Each
86
- proxy placeholder must name a declared string path parameter. Proxy routes refuse
87
- middleware in this initial implementation: middleware cannot safely authorize an
88
- already materialized upstream request. Use host request policies before egress.
89
- Proxy routes require cache disabled or `no-store`; explicit cache declarations
90
- cannot override this. Responses always remove CDN cache directives and receive
91
- `Cache-Control: no-store`. Compressed upstream bytes are refused if their
92
- Content-Encoding field was not explicitly selected; it cannot be overridden by
93
- route response headers.
94
-
95
- The external version-1 policy has the existing `projectSha256` and route grants:
96
-
97
- ```json
98
- {"version":1,"projectSha256":"<reviewed revision hash>","routes":{"/items/{id}":{"secrets":["UPSTREAM_AUTHORIZATION"],"egress":{"proxy":["https://api.example.com"],"signals":["https://hooks.example.com"]}}}}
99
- ```
100
-
101
- Use `permissions` to generate requested grants for review. Exact origin strings
102
- omit a trailing slash and the default 443 port. Nondefault ports are explicit.
103
- Proxy and signal purposes are independent even when they share an origin. Every
104
- route's grant is checked against the current revision before credentials, assets,
105
- workers or network clients are activated. Each runtime shares one bounded proxy
106
- client and one bounded signal client, with at most 64 origins per purpose.
107
-
108
- Signals emit when route execution and response policies produce a result,
109
- including guest middleware responses and returned error status codes. Thrown
110
- handler errors and host request-policy/plugin short circuits (including cache
111
- hits) do not emit. HEAD requests and generated readiness probes do not emit.
112
- The response never waits for webhook delivery. Counter events contain only
113
- accepted/delivered/failed/dropped outcomes and counts and are exposed through
114
- runtime metrics and the Prometheus `signals_total` series. A closed runtime stops
115
- new requests, aborts egress and drains bounded pending work. Client disconnects
116
- are not currently propagated into the runtime transport; the five-second deadline
117
- still applies. All non-self-hosted targets currently refuse proxy and signals.
118
- See the [executable example](../examples/egress/README.md).
119
-
120
- Revision hashes also include declared project policies, profiles and site
121
- configuration. Changing an inherited pre-egress restriction invalidates grants
122
- just like changing a route or function source. Projects with these declarations
123
- must regenerate and review their operator policy after upgrading to this hash
124
- coverage; an old grant is intentionally refused rather than silently retaining
125
- network authority under changed behavior.