@mannyc1/ts-release 0.0.7 → 0.2.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.
Files changed (635) hide show
  1. package/ARCHITECTURE.md +124 -92
  2. package/CHANGELOG.md +115 -0
  3. package/LICENSE +21 -0
  4. package/README.md +278 -324
  5. package/SPEC.md +206 -310
  6. package/apps/release-ts/README.md +32 -0
  7. package/apps/release-ts/src/cli/command.ts +164 -0
  8. package/apps/release-ts/src/cli/commands.ts +351 -0
  9. package/apps/release-ts/src/cli/main.ts +43 -0
  10. package/apps/release-ts/src/cli/node-main.ts +49 -0
  11. package/apps/ts-release-agents/LICENSE +21 -0
  12. package/apps/ts-release-agents/README.md +21 -0
  13. package/apps/ts-release-agents/evals/cases.json +11 -0
  14. package/apps/ts-release-agents/manifests/claude.json +5 -0
  15. package/apps/ts-release-agents/manifests/codex.json +5 -0
  16. package/apps/ts-release-agents/package.json +11 -0
  17. package/apps/ts-release-agents/skills/release/SKILL.md +48 -0
  18. package/apps/ts-release-agents/skills/release/references/configuration.md +18 -0
  19. package/apps/ts-release-agents/skills/release/references/recovery.md +10 -0
  20. package/apps/ts-release-agents/skills/release/references/staged-workflow.md +12 -0
  21. package/apps/ts-release-agents/skills/release/references/target-selection.md +13 -0
  22. package/apps/ts-release-agents/skills/release/references/verification.md +14 -0
  23. package/apps/ts-release-agents/src/build.ts +105 -0
  24. package/apps/ts-release-agents/src/check.ts +117 -0
  25. package/apps/ts-release-agents/src/install.ts +121 -0
  26. package/apps/ts-release-agents/test/contract.test.ts +56 -0
  27. package/apps/ts-release-agents/tsconfig.json +5 -0
  28. package/dist/api/api.d.ts +15 -0
  29. package/dist/api/api.d.ts.map +1 -0
  30. package/dist/api/api.js +244 -0
  31. package/dist/api/api.js.map +1 -0
  32. package/dist/api/errors.d.ts +39 -0
  33. package/dist/api/errors.d.ts.map +1 -0
  34. package/dist/api/errors.js +32 -0
  35. package/dist/api/errors.js.map +1 -0
  36. package/dist/api/input.d.ts +10 -0
  37. package/dist/api/input.d.ts.map +1 -0
  38. package/dist/api/input.js +73 -0
  39. package/dist/api/input.js.map +1 -0
  40. package/dist/api/runtime.d.ts +18 -0
  41. package/dist/api/runtime.d.ts.map +1 -0
  42. package/dist/api/runtime.js +7 -0
  43. package/dist/api/runtime.js.map +1 -0
  44. package/dist/api/types.d.ts +76 -0
  45. package/dist/api/types.d.ts.map +1 -0
  46. package/dist/api/types.js +17 -0
  47. package/dist/api/types.js.map +1 -0
  48. package/dist/bin/ts-release.js +39239 -0
  49. package/dist/capabilities/bun-targets.d.ts +3 -0
  50. package/dist/capabilities/bun-targets.d.ts.map +1 -0
  51. package/dist/capabilities/bun-targets.js +3 -0
  52. package/dist/capabilities/bun-targets.js.map +1 -0
  53. package/dist/capabilities/field-ownership.d.ts +17 -0
  54. package/dist/capabilities/field-ownership.d.ts.map +1 -0
  55. package/dist/capabilities/field-ownership.js +40 -0
  56. package/dist/capabilities/field-ownership.js.map +1 -0
  57. package/dist/capabilities/module.d.ts +91 -0
  58. package/dist/capabilities/module.d.ts.map +1 -0
  59. package/dist/capabilities/module.js +2 -0
  60. package/dist/capabilities/module.js.map +1 -0
  61. package/dist/capabilities/registry.d.ts +829 -0
  62. package/dist/capabilities/registry.d.ts.map +1 -0
  63. package/dist/capabilities/registry.js +291 -0
  64. package/dist/capabilities/registry.js.map +1 -0
  65. package/dist/config/config.d.ts +6 -0
  66. package/dist/config/config.d.ts.map +1 -0
  67. package/dist/config/config.js +42 -0
  68. package/dist/config/config.js.map +1 -0
  69. package/dist/correction/coordinator.d.ts +248 -0
  70. package/dist/correction/coordinator.d.ts.map +1 -0
  71. package/dist/correction/coordinator.js +274 -0
  72. package/dist/correction/coordinator.js.map +1 -0
  73. package/dist/correction/index.d.ts +3 -0
  74. package/dist/correction/index.d.ts.map +1 -0
  75. package/dist/correction/index.js +3 -0
  76. package/dist/correction/index.js.map +1 -0
  77. package/dist/correction/intent.d.ts +111 -0
  78. package/dist/correction/intent.d.ts.map +1 -0
  79. package/dist/correction/intent.js +146 -0
  80. package/dist/correction/intent.js.map +1 -0
  81. package/dist/drivers/archive.d.ts +8 -0
  82. package/dist/drivers/archive.d.ts.map +1 -0
  83. package/dist/drivers/archive.js +101 -0
  84. package/dist/drivers/archive.js.map +1 -0
  85. package/dist/drivers/contain.d.ts +6 -0
  86. package/dist/drivers/contain.d.ts.map +1 -0
  87. package/dist/drivers/contain.js +17 -0
  88. package/dist/drivers/contain.js.map +1 -0
  89. package/dist/drivers/environment.d.ts +4 -0
  90. package/dist/drivers/environment.d.ts.map +1 -0
  91. package/dist/drivers/environment.js +18 -0
  92. package/dist/drivers/environment.js.map +1 -0
  93. package/dist/drivers/errors.d.ts +9 -0
  94. package/dist/drivers/errors.d.ts.map +1 -0
  95. package/dist/drivers/errors.js +6 -0
  96. package/dist/drivers/errors.js.map +1 -0
  97. package/dist/drivers/glob.d.ts +2 -0
  98. package/dist/drivers/glob.d.ts.map +1 -0
  99. package/dist/drivers/glob.js +162 -0
  100. package/dist/drivers/glob.js.map +1 -0
  101. package/dist/drivers/process.d.ts +48 -0
  102. package/dist/drivers/process.d.ts.map +1 -0
  103. package/dist/drivers/process.js +257 -0
  104. package/dist/drivers/process.js.map +1 -0
  105. package/dist/drivers/redact.d.ts +4 -0
  106. package/dist/drivers/redact.d.ts.map +1 -0
  107. package/dist/drivers/redact.js +24 -0
  108. package/dist/drivers/redact.js.map +1 -0
  109. package/dist/drivers/seccomp-helper-source.d.ts +7 -0
  110. package/dist/drivers/seccomp-helper-source.d.ts.map +1 -0
  111. package/dist/drivers/seccomp-helper-source.js +121 -0
  112. package/dist/drivers/seccomp-helper-source.js.map +1 -0
  113. package/dist/drivers/utils.d.ts +4 -0
  114. package/dist/drivers/utils.d.ts.map +1 -0
  115. package/dist/drivers/utils.js +5 -0
  116. package/dist/drivers/utils.js.map +1 -0
  117. package/dist/drivers/workspace.d.ts +6 -0
  118. package/dist/drivers/workspace.d.ts.map +1 -0
  119. package/dist/drivers/workspace.js +49 -0
  120. package/dist/drivers/workspace.js.map +1 -0
  121. package/dist/extensions/provider-adapter.d.ts +48 -0
  122. package/dist/extensions/provider-adapter.d.ts.map +1 -0
  123. package/dist/extensions/provider-adapter.js +64 -0
  124. package/dist/extensions/provider-adapter.js.map +1 -0
  125. package/dist/host.d.ts +33 -0
  126. package/dist/host.d.ts.map +1 -0
  127. package/dist/host.js +20 -0
  128. package/dist/host.js.map +1 -0
  129. package/dist/index.d.ts +19 -1
  130. package/dist/index.d.ts.map +1 -1
  131. package/dist/index.js +12 -1
  132. package/dist/index.js.map +1 -1
  133. package/dist/model/artifact-collection.d.ts +84 -0
  134. package/dist/model/artifact-collection.d.ts.map +1 -0
  135. package/dist/model/artifact-collection.js +185 -0
  136. package/dist/model/artifact-collection.js.map +1 -0
  137. package/dist/model/authority.d.ts +89 -0
  138. package/dist/model/authority.d.ts.map +1 -0
  139. package/dist/model/authority.js +80 -0
  140. package/dist/model/authority.js.map +1 -0
  141. package/dist/model/bun-targets.d.ts +34 -0
  142. package/dist/model/bun-targets.d.ts.map +1 -0
  143. package/dist/model/bun-targets.js +17 -0
  144. package/dist/model/bun-targets.js.map +1 -0
  145. package/dist/model/canonical.d.ts +8 -0
  146. package/dist/model/canonical.d.ts.map +1 -0
  147. package/dist/model/canonical.js +205 -0
  148. package/dist/model/canonical.js.map +1 -0
  149. package/dist/model/catalog.d.ts +76 -0
  150. package/dist/model/catalog.d.ts.map +1 -0
  151. package/dist/model/catalog.js +174 -0
  152. package/dist/model/catalog.js.map +1 -0
  153. package/dist/model/digest.d.ts +53 -0
  154. package/dist/model/digest.d.ts.map +1 -0
  155. package/dist/model/digest.js +127 -0
  156. package/dist/model/digest.js.map +1 -0
  157. package/dist/model/errors.d.ts +14 -0
  158. package/dist/model/errors.d.ts.map +1 -0
  159. package/dist/model/errors.js +8 -0
  160. package/dist/model/errors.js.map +1 -0
  161. package/dist/model/primitives.d.ts +19 -0
  162. package/dist/model/primitives.d.ts.map +1 -0
  163. package/dist/model/primitives.js +18 -0
  164. package/dist/model/primitives.js.map +1 -0
  165. package/dist/model/pypi.d.ts +12 -0
  166. package/dist/model/pypi.d.ts.map +1 -0
  167. package/dist/model/pypi.js +20 -0
  168. package/dist/model/pypi.js.map +1 -0
  169. package/dist/model/python-distribution.d.ts +33 -0
  170. package/dist/model/python-distribution.d.ts.map +1 -0
  171. package/dist/model/python-distribution.js +367 -0
  172. package/dist/model/python-distribution.js.map +1 -0
  173. package/dist/model/secret-patterns.d.ts +2 -0
  174. package/dist/model/secret-patterns.d.ts.map +1 -0
  175. package/dist/model/secret-patterns.js +12 -0
  176. package/dist/model/secret-patterns.js.map +1 -0
  177. package/dist/platform/bun.d.ts +7 -0
  178. package/dist/platform/bun.d.ts.map +1 -0
  179. package/dist/platform/bun.js +15 -0
  180. package/dist/platform/bun.js.map +1 -0
  181. package/dist/platform/credentials.d.ts +32 -0
  182. package/dist/platform/credentials.d.ts.map +1 -0
  183. package/dist/platform/credentials.js +772 -0
  184. package/dist/platform/credentials.js.map +1 -0
  185. package/dist/platform/host-support.d.ts +2 -0
  186. package/dist/platform/host-support.d.ts.map +1 -0
  187. package/dist/platform/host-support.js +4 -0
  188. package/dist/platform/host-support.js.map +1 -0
  189. package/dist/platform/node.d.ts +7 -0
  190. package/dist/platform/node.d.ts.map +1 -0
  191. package/dist/platform/node.js +15 -0
  192. package/dist/platform/node.js.map +1 -0
  193. package/dist/platform/release-runtime.d.ts +11 -0
  194. package/dist/platform/release-runtime.d.ts.map +1 -0
  195. package/dist/platform/release-runtime.js +34 -0
  196. package/dist/platform/release-runtime.js.map +1 -0
  197. package/dist/platform/services.d.ts +15 -0
  198. package/dist/platform/services.d.ts.map +1 -0
  199. package/dist/platform/services.js +30 -0
  200. package/dist/platform/services.js.map +1 -0
  201. package/dist/platform/source-observer.d.ts +5 -0
  202. package/dist/platform/source-observer.d.ts.map +1 -0
  203. package/dist/platform/source-observer.js +159 -0
  204. package/dist/platform/source-observer.js.map +1 -0
  205. package/dist/provider-sdk.d.ts +14 -0
  206. package/dist/provider-sdk.d.ts.map +1 -0
  207. package/dist/provider-sdk.js +10 -0
  208. package/dist/provider-sdk.js.map +1 -0
  209. package/dist/publication/adapter.d.ts +212 -0
  210. package/dist/publication/adapter.d.ts.map +1 -0
  211. package/dist/publication/adapter.js +83 -0
  212. package/dist/publication/adapter.js.map +1 -0
  213. package/dist/publication/authority.d.ts +137 -0
  214. package/dist/publication/authority.d.ts.map +1 -0
  215. package/dist/publication/authority.js +233 -0
  216. package/dist/publication/authority.js.map +1 -0
  217. package/dist/publication/catalog-git.d.ts +37 -0
  218. package/dist/publication/catalog-git.d.ts.map +1 -0
  219. package/dist/publication/catalog-git.js +451 -0
  220. package/dist/publication/catalog-git.js.map +1 -0
  221. package/dist/publication/claim.d.ts +39 -0
  222. package/dist/publication/claim.d.ts.map +1 -0
  223. package/dist/publication/claim.js +31 -0
  224. package/dist/publication/claim.js.map +1 -0
  225. package/dist/publication/coordinator.d.ts +246 -0
  226. package/dist/publication/coordinator.d.ts.map +1 -0
  227. package/dist/publication/coordinator.js +370 -0
  228. package/dist/publication/coordinator.js.map +1 -0
  229. package/dist/publication/github.d.ts +36 -0
  230. package/dist/publication/github.d.ts.map +1 -0
  231. package/dist/publication/github.js +644 -0
  232. package/dist/publication/github.js.map +1 -0
  233. package/dist/publication/http.d.ts +69 -0
  234. package/dist/publication/http.d.ts.map +1 -0
  235. package/dist/publication/http.js +29 -0
  236. package/dist/publication/http.js.map +1 -0
  237. package/dist/publication/index.d.ts +5 -0
  238. package/dist/publication/index.d.ts.map +1 -0
  239. package/dist/publication/index.js +5 -0
  240. package/dist/publication/index.js.map +1 -0
  241. package/dist/publication/npm.d.ts +40 -0
  242. package/dist/publication/npm.d.ts.map +1 -0
  243. package/dist/publication/npm.js +359 -0
  244. package/dist/publication/npm.js.map +1 -0
  245. package/dist/publication/profiles.d.ts +136 -0
  246. package/dist/publication/profiles.d.ts.map +1 -0
  247. package/dist/publication/profiles.js +90 -0
  248. package/dist/publication/profiles.js.map +1 -0
  249. package/dist/publication/publisher.d.ts +82 -0
  250. package/dist/publication/publisher.d.ts.map +1 -0
  251. package/dist/publication/publisher.js +53 -0
  252. package/dist/publication/publisher.js.map +1 -0
  253. package/dist/publication/pypi.d.ts +45 -0
  254. package/dist/publication/pypi.d.ts.map +1 -0
  255. package/dist/publication/pypi.js +369 -0
  256. package/dist/publication/pypi.js.map +1 -0
  257. package/dist/publication/recovery.d.ts +663 -0
  258. package/dist/publication/recovery.d.ts.map +1 -0
  259. package/dist/publication/recovery.js +252 -0
  260. package/dist/publication/recovery.js.map +1 -0
  261. package/dist/publication/report.d.ts +1061 -0
  262. package/dist/publication/report.d.ts.map +1 -0
  263. package/dist/publication/report.js +441 -0
  264. package/dist/publication/report.js.map +1 -0
  265. package/dist/recipes/config.d.ts +296 -0
  266. package/dist/recipes/config.d.ts.map +1 -0
  267. package/dist/recipes/config.js +325 -0
  268. package/dist/recipes/config.js.map +1 -0
  269. package/dist/release/capabilities.d.ts +12 -0
  270. package/dist/release/capabilities.d.ts.map +1 -0
  271. package/dist/release/capabilities.js +395 -0
  272. package/dist/release/capabilities.js.map +1 -0
  273. package/dist/release/compiler.d.ts +5 -0
  274. package/dist/release/compiler.d.ts.map +1 -0
  275. package/dist/release/compiler.js +19 -0
  276. package/dist/release/compiler.js.map +1 -0
  277. package/dist/release/config.d.ts +5 -0
  278. package/dist/release/config.d.ts.map +1 -0
  279. package/dist/release/config.js +10 -0
  280. package/dist/release/config.js.map +1 -0
  281. package/dist/release/context.d.ts +96 -0
  282. package/dist/release/context.d.ts.map +1 -0
  283. package/dist/release/context.js +168 -0
  284. package/dist/release/context.js.map +1 -0
  285. package/dist/release/graph.d.ts +271 -0
  286. package/dist/release/graph.d.ts.map +1 -0
  287. package/dist/release/graph.js +766 -0
  288. package/dist/release/graph.js.map +1 -0
  289. package/dist/release/inspect.d.ts +88 -0
  290. package/dist/release/inspect.d.ts.map +1 -0
  291. package/dist/release/inspect.js +75 -0
  292. package/dist/release/inspect.js.map +1 -0
  293. package/dist/release/prepare.d.ts +24 -0
  294. package/dist/release/prepare.d.ts.map +1 -0
  295. package/dist/release/prepare.js +1116 -0
  296. package/dist/release/prepare.js.map +1 -0
  297. package/dist/release/prepared-ref.d.ts +60 -0
  298. package/dist/release/prepared-ref.d.ts.map +1 -0
  299. package/dist/release/prepared-ref.js +131 -0
  300. package/dist/release/prepared-ref.js.map +1 -0
  301. package/dist/release/prepared-store.d.ts +90 -0
  302. package/dist/release/prepared-store.d.ts.map +1 -0
  303. package/dist/release/prepared-store.js +337 -0
  304. package/dist/release/prepared-store.js.map +1 -0
  305. package/dist/release/prepared.d.ts +172 -0
  306. package/dist/release/prepared.d.ts.map +1 -0
  307. package/dist/release/prepared.js +268 -0
  308. package/dist/release/prepared.js.map +1 -0
  309. package/dist/release/staging.d.ts +31 -0
  310. package/dist/release/staging.d.ts.map +1 -0
  311. package/dist/release/staging.js +218 -0
  312. package/dist/release/staging.js.map +1 -0
  313. package/dist/resolve/authored.d.ts +53 -0
  314. package/dist/resolve/authored.d.ts.map +1 -0
  315. package/dist/resolve/authored.js +55 -0
  316. package/dist/resolve/authored.js.map +1 -0
  317. package/dist/resolve/encode.d.ts +3 -0
  318. package/dist/resolve/encode.d.ts.map +1 -0
  319. package/dist/resolve/encode.js +21 -0
  320. package/dist/resolve/encode.js.map +1 -0
  321. package/dist/resolve/errors.d.ts +7 -0
  322. package/dist/resolve/errors.d.ts.map +1 -0
  323. package/dist/resolve/errors.js +17 -0
  324. package/dist/resolve/errors.js.map +1 -0
  325. package/dist/resolve/facts.d.ts +12 -0
  326. package/dist/resolve/facts.d.ts.map +1 -0
  327. package/dist/resolve/facts.js +18 -0
  328. package/dist/resolve/facts.js.map +1 -0
  329. package/dist/resolve/resolve.d.ts +10 -0
  330. package/dist/resolve/resolve.d.ts.map +1 -0
  331. package/dist/resolve/resolve.js +242 -0
  332. package/dist/resolve/resolve.js.map +1 -0
  333. package/dist/store.d.ts +11 -0
  334. package/dist/store.d.ts.map +1 -0
  335. package/dist/store.js +9 -0
  336. package/dist/store.js.map +1 -0
  337. package/examples/README.md +20 -30
  338. package/examples/github-release/release.config.json +11 -18
  339. package/examples/homebrew-tap/README.md +11 -0
  340. package/examples/homebrew-tap/release.config.json +40 -28
  341. package/examples/multi-target/release.config.json +28 -53
  342. package/examples/npm-first-publish/release.config.json +23 -25
  343. package/examples/npm-only/release.config.json +22 -30
  344. package/examples/portable-cli/README.md +17 -0
  345. package/examples/portable-cli/artifacts/portable-example-0.1.0-darwin-arm64 +1 -0
  346. package/examples/portable-cli/artifacts/portable-example-0.1.0-darwin-x64 +1 -0
  347. package/examples/portable-cli/artifacts/portable-example-0.1.0-linux-arm64 +1 -0
  348. package/examples/portable-cli/artifacts/portable-example-0.1.0-linux-x64 +1 -0
  349. package/examples/portable-cli/artifacts/portable-example-0.1.0-windows-x64.exe +1 -0
  350. package/examples/portable-cli/artifacts/portable_example-0.1.0-py3-none-macosx_10_15_x86_64.whl +1 -0
  351. package/examples/portable-cli/artifacts/portable_example-0.1.0-py3-none-macosx_11_0_arm64.whl +1 -0
  352. package/examples/portable-cli/artifacts/portable_example-0.1.0-py3-none-manylinux2014_aarch64.whl +1 -0
  353. package/examples/portable-cli/artifacts/portable_example-0.1.0-py3-none-manylinux2014_x86_64.whl +1 -0
  354. package/examples/portable-cli/artifacts/portable_example-0.1.0-py3-none-win_amd64.whl +1 -0
  355. package/examples/portable-cli/package.json +9 -0
  356. package/examples/portable-cli/release.config.json +53 -0
  357. package/examples/portable-cli/src/cli.ts +3 -0
  358. package/examples/pypi-registry/README.md +8 -0
  359. package/examples/scoop-bucket/README.md +10 -0
  360. package/examples/scoop-bucket/release.config.json +40 -30
  361. package/package.json +60 -156
  362. package/src/api/api.ts +365 -0
  363. package/src/api/errors.ts +36 -0
  364. package/src/api/input.ts +92 -0
  365. package/src/api/runtime.ts +14 -0
  366. package/src/api/types.ts +103 -0
  367. package/src/capabilities/bun-targets.ts +2 -0
  368. package/src/capabilities/field-ownership.ts +60 -0
  369. package/src/capabilities/module.ts +158 -0
  370. package/src/capabilities/registry.ts +333 -0
  371. package/src/config/config.ts +48 -0
  372. package/src/correction/coordinator.ts +336 -0
  373. package/src/correction/index.ts +2 -0
  374. package/src/correction/intent.ts +172 -0
  375. package/src/drivers/archive.ts +102 -0
  376. package/src/drivers/contain.ts +20 -0
  377. package/src/drivers/environment.ts +28 -0
  378. package/src/drivers/errors.ts +6 -0
  379. package/src/drivers/glob.ts +137 -0
  380. package/src/drivers/process.ts +340 -0
  381. package/src/drivers/redact.ts +31 -0
  382. package/src/drivers/seccomp-helper-source.ts +121 -0
  383. package/src/drivers/utils.ts +10 -0
  384. package/src/drivers/workspace.ts +40 -0
  385. package/src/extensions/provider-adapter.ts +99 -0
  386. package/src/host.ts +140 -0
  387. package/src/index.ts +64 -0
  388. package/src/model/artifact-collection.ts +237 -0
  389. package/src/model/authority.ts +116 -0
  390. package/src/model/bun-targets.ts +34 -0
  391. package/src/model/canonical.ts +205 -0
  392. package/src/model/catalog.ts +220 -0
  393. package/src/model/digest.ts +172 -0
  394. package/src/model/errors.ts +6 -0
  395. package/src/model/primitives.ts +37 -0
  396. package/src/model/pypi.ts +30 -0
  397. package/src/model/python-distribution.ts +360 -0
  398. package/src/model/secret-patterns.ts +11 -0
  399. package/src/platform/bun.ts +38 -0
  400. package/src/platform/credentials.ts +1083 -0
  401. package/src/platform/host-support.ts +4 -0
  402. package/src/platform/node.ts +38 -0
  403. package/src/platform/release-runtime.ts +47 -0
  404. package/src/platform/services.ts +57 -0
  405. package/src/platform/source-observer.ts +193 -0
  406. package/src/provider-sdk.ts +48 -0
  407. package/src/publication/adapter.ts +132 -0
  408. package/src/publication/authority.ts +397 -0
  409. package/src/publication/catalog-git.ts +603 -0
  410. package/src/publication/claim.ts +51 -0
  411. package/src/publication/coordinator.ts +578 -0
  412. package/src/publication/github.ts +954 -0
  413. package/src/publication/http.ts +101 -0
  414. package/src/publication/index.ts +4 -0
  415. package/src/publication/npm.ts +525 -0
  416. package/src/publication/profiles.ts +94 -0
  417. package/src/publication/publisher.ts +130 -0
  418. package/src/publication/pypi.ts +463 -0
  419. package/src/publication/recovery.ts +349 -0
  420. package/src/publication/report.ts +628 -0
  421. package/src/recipes/config.ts +395 -0
  422. package/src/release/capabilities.ts +459 -0
  423. package/src/release/compiler.ts +28 -0
  424. package/src/release/config.ts +12 -0
  425. package/src/release/context.ts +223 -0
  426. package/src/release/graph.ts +866 -0
  427. package/src/release/inspect.ts +83 -0
  428. package/src/release/prepare.ts +1331 -0
  429. package/src/release/prepared-ref.ts +193 -0
  430. package/src/release/prepared-store.ts +377 -0
  431. package/src/release/prepared.ts +299 -0
  432. package/src/release/staging.ts +257 -0
  433. package/src/resolve/authored.ts +64 -0
  434. package/src/resolve/encode.ts +22 -0
  435. package/src/resolve/errors.ts +15 -0
  436. package/src/resolve/facts.ts +18 -0
  437. package/src/resolve/resolve.ts +328 -0
  438. package/src/store.ts +28 -0
  439. package/templates/README.md +55 -72
  440. package/templates/bun-cli-github/README.md +7 -9
  441. package/templates/bun-cli-github/release.config.json +35 -73
  442. package/templates/github-actions/release.yml +57 -0
  443. package/templates/github-actions/reviewed-release.yml +80 -0
  444. package/templates/multi-target-homebrew/README.md +10 -0
  445. package/templates/multi-target-homebrew/release.config.json +43 -60
  446. package/templates/multi-target-scoop/README.md +10 -0
  447. package/templates/multi-target-scoop/release.config.json +43 -62
  448. package/templates/npm-github/release.config.json +25 -38
  449. package/templates/npm-github/reviewed-release.config.json +37 -0
  450. package/templates/npm-only/README.md +10 -0
  451. package/templates/npm-only/release.config.json +15 -30
  452. package/templates/portable-cli/README.md +13 -0
  453. package/templates/portable-cli/release.config.json +53 -0
  454. package/dist/artifacts/adapter.d.ts +0 -39
  455. package/dist/artifacts/adapter.d.ts.map +0 -1
  456. package/dist/artifacts/adapter.js +0 -23
  457. package/dist/artifacts/adapter.js.map +0 -1
  458. package/dist/artifacts/registry.d.ts +0 -21
  459. package/dist/artifacts/registry.d.ts.map +0 -1
  460. package/dist/artifacts/registry.js +0 -21
  461. package/dist/artifacts/registry.js.map +0 -1
  462. package/dist/config/errors.d.ts +0 -24
  463. package/dist/config/errors.d.ts.map +0 -1
  464. package/dist/config/errors.js +0 -19
  465. package/dist/config/errors.js.map +0 -1
  466. package/dist/config/load.d.ts +0 -9
  467. package/dist/config/load.d.ts.map +0 -1
  468. package/dist/config/load.js +0 -29
  469. package/dist/config/load.js.map +0 -1
  470. package/dist/config/schema.d.ts +0 -12
  471. package/dist/config/schema.d.ts.map +0 -1
  472. package/dist/config/schema.js +0 -19
  473. package/dist/config/schema.js.map +0 -1
  474. package/dist/domain/artifact.d.ts +0 -118
  475. package/dist/domain/artifact.d.ts.map +0 -1
  476. package/dist/domain/artifact.js +0 -197
  477. package/dist/domain/artifact.js.map +0 -1
  478. package/dist/domain/evidence.d.ts +0 -59
  479. package/dist/domain/evidence.d.ts.map +0 -1
  480. package/dist/domain/evidence.js +0 -51
  481. package/dist/domain/evidence.js.map +0 -1
  482. package/dist/domain/operation.d.ts +0 -143
  483. package/dist/domain/operation.d.ts.map +0 -1
  484. package/dist/domain/operation.js +0 -198
  485. package/dist/domain/operation.js.map +0 -1
  486. package/dist/domain/release.d.ts +0 -93
  487. package/dist/domain/release.d.ts.map +0 -1
  488. package/dist/domain/release.js +0 -82
  489. package/dist/domain/release.js.map +0 -1
  490. package/dist/domain/remote-state.d.ts +0 -58
  491. package/dist/domain/remote-state.d.ts.map +0 -1
  492. package/dist/domain/remote-state.js +0 -55
  493. package/dist/domain/remote-state.js.map +0 -1
  494. package/dist/domain/target.d.ts +0 -148
  495. package/dist/domain/target.d.ts.map +0 -1
  496. package/dist/domain/target.js +0 -151
  497. package/dist/domain/target.js.map +0 -1
  498. package/dist/host/host.d.ts +0 -32
  499. package/dist/host/host.d.ts.map +0 -1
  500. package/dist/host/host.js +0 -24
  501. package/dist/host/host.js.map +0 -1
  502. package/dist/host/http-live.d.ts +0 -6
  503. package/dist/host/http-live.d.ts.map +0 -1
  504. package/dist/host/http-live.js +0 -86
  505. package/dist/host/http-live.js.map +0 -1
  506. package/dist/host/http.d.ts +0 -43
  507. package/dist/host/http.d.ts.map +0 -1
  508. package/dist/host/http.js +0 -59
  509. package/dist/host/http.js.map +0 -1
  510. package/dist/host/platform.d.ts +0 -10
  511. package/dist/host/platform.d.ts.map +0 -1
  512. package/dist/host/platform.js +0 -114
  513. package/dist/host/platform.js.map +0 -1
  514. package/dist/host/test.d.ts +0 -23
  515. package/dist/host/test.d.ts.map +0 -1
  516. package/dist/host/test.js +0 -222
  517. package/dist/host/test.js.map +0 -1
  518. package/dist/internal/workspace-path.d.ts +0 -15
  519. package/dist/internal/workspace-path.d.ts.map +0 -1
  520. package/dist/internal/workspace-path.js +0 -36
  521. package/dist/internal/workspace-path.js.map +0 -1
  522. package/dist/planner/artifact-inventory.d.ts +0 -9
  523. package/dist/planner/artifact-inventory.d.ts.map +0 -1
  524. package/dist/planner/artifact-inventory.js +0 -86
  525. package/dist/planner/artifact-inventory.js.map +0 -1
  526. package/dist/planner/create-release-plan.d.ts +0 -5
  527. package/dist/planner/create-release-plan.d.ts.map +0 -1
  528. package/dist/planner/create-release-plan.js +0 -25
  529. package/dist/planner/create-release-plan.js.map +0 -1
  530. package/dist/planner/errors.d.ts +0 -67
  531. package/dist/planner/errors.d.ts.map +0 -1
  532. package/dist/planner/errors.js +0 -58
  533. package/dist/planner/errors.js.map +0 -1
  534. package/dist/planner/evidence-recorder.d.ts +0 -28
  535. package/dist/planner/evidence-recorder.d.ts.map +0 -1
  536. package/dist/planner/evidence-recorder.js +0 -362
  537. package/dist/planner/evidence-recorder.js.map +0 -1
  538. package/dist/planner/executor.d.ts +0 -58
  539. package/dist/planner/executor.d.ts.map +0 -1
  540. package/dist/planner/executor.js +0 -147
  541. package/dist/planner/executor.js.map +0 -1
  542. package/dist/planner/normalize-release.d.ts +0 -19
  543. package/dist/planner/normalize-release.d.ts.map +0 -1
  544. package/dist/planner/normalize-release.js +0 -342
  545. package/dist/planner/normalize-release.js.map +0 -1
  546. package/dist/planner/reconcile.d.ts +0 -17
  547. package/dist/planner/reconcile.d.ts.map +0 -1
  548. package/dist/planner/reconcile.js +0 -259
  549. package/dist/planner/reconcile.js.map +0 -1
  550. package/dist/planner/render-plan.d.ts +0 -15
  551. package/dist/planner/render-plan.d.ts.map +0 -1
  552. package/dist/planner/render-plan.js +0 -231
  553. package/dist/planner/render-plan.js.map +0 -1
  554. package/dist/targets/adapter-helpers.d.ts +0 -79
  555. package/dist/targets/adapter-helpers.d.ts.map +0 -1
  556. package/dist/targets/adapter-helpers.js +0 -194
  557. package/dist/targets/adapter-helpers.js.map +0 -1
  558. package/dist/targets/adapter.d.ts +0 -17
  559. package/dist/targets/adapter.d.ts.map +0 -1
  560. package/dist/targets/adapter.js +0 -2
  561. package/dist/targets/adapter.js.map +0 -1
  562. package/dist/targets/github-release.d.ts +0 -25
  563. package/dist/targets/github-release.d.ts.map +0 -1
  564. package/dist/targets/github-release.js +0 -82
  565. package/dist/targets/github-release.js.map +0 -1
  566. package/dist/targets/github.d.ts +0 -11
  567. package/dist/targets/github.d.ts.map +0 -1
  568. package/dist/targets/github.js +0 -117
  569. package/dist/targets/github.js.map +0 -1
  570. package/dist/targets/homebrew.d.ts +0 -11
  571. package/dist/targets/homebrew.d.ts.map +0 -1
  572. package/dist/targets/homebrew.js +0 -210
  573. package/dist/targets/homebrew.js.map +0 -1
  574. package/dist/targets/live.d.ts +0 -5
  575. package/dist/targets/live.d.ts.map +0 -1
  576. package/dist/targets/live.js +0 -50
  577. package/dist/targets/live.js.map +0 -1
  578. package/dist/targets/npm.d.ts +0 -10
  579. package/dist/targets/npm.d.ts.map +0 -1
  580. package/dist/targets/npm.js +0 -112
  581. package/dist/targets/npm.js.map +0 -1
  582. package/dist/targets/pypi.d.ts +0 -11
  583. package/dist/targets/pypi.d.ts.map +0 -1
  584. package/dist/targets/pypi.js +0 -141
  585. package/dist/targets/pypi.js.map +0 -1
  586. package/dist/targets/registry.d.ts +0 -25
  587. package/dist/targets/registry.d.ts.map +0 -1
  588. package/dist/targets/registry.js +0 -34
  589. package/dist/targets/registry.js.map +0 -1
  590. package/dist/targets/scoop.d.ts +0 -11
  591. package/dist/targets/scoop.d.ts.map +0 -1
  592. package/dist/targets/scoop.js +0 -88
  593. package/dist/targets/scoop.js.map +0 -1
  594. package/dist/types/effect-internal.d.ts +0 -5
  595. package/dist/types/effect-internal.d.ts.map +0 -1
  596. package/dist/types/effect-internal.js +0 -2
  597. package/dist/types/effect-internal.js.map +0 -1
  598. package/dist/workflows/config.d.ts +0 -202
  599. package/dist/workflows/config.d.ts.map +0 -1
  600. package/dist/workflows/config.js +0 -420
  601. package/dist/workflows/config.js.map +0 -1
  602. package/dist/workflows/diagnostics.d.ts +0 -62
  603. package/dist/workflows/diagnostics.d.ts.map +0 -1
  604. package/dist/workflows/diagnostics.js +0 -530
  605. package/dist/workflows/diagnostics.js.map +0 -1
  606. package/dist/workflows/distribution.d.ts +0 -25
  607. package/dist/workflows/distribution.d.ts.map +0 -1
  608. package/dist/workflows/distribution.js +0 -24
  609. package/dist/workflows/distribution.js.map +0 -1
  610. package/dist/workflows/evidence.d.ts +0 -17
  611. package/dist/workflows/evidence.d.ts.map +0 -1
  612. package/dist/workflows/evidence.js +0 -32
  613. package/dist/workflows/evidence.js.map +0 -1
  614. package/dist/workflows/index.d.ts +0 -8
  615. package/dist/workflows/index.d.ts.map +0 -1
  616. package/dist/workflows/index.js +0 -7
  617. package/dist/workflows/index.js.map +0 -1
  618. package/dist/workflows/init.d.ts +0 -84
  619. package/dist/workflows/init.d.ts.map +0 -1
  620. package/dist/workflows/init.js +0 -487
  621. package/dist/workflows/init.js.map +0 -1
  622. package/dist/workflows/live.d.ts +0 -9
  623. package/dist/workflows/live.d.ts.map +0 -1
  624. package/dist/workflows/live.js +0 -7
  625. package/dist/workflows/live.js.map +0 -1
  626. package/dist/workflows/options.d.ts +0 -30
  627. package/dist/workflows/options.d.ts.map +0 -1
  628. package/dist/workflows/options.js +0 -16
  629. package/dist/workflows/options.js.map +0 -1
  630. package/examples/non-strict-skips/artifacts/release-example-skips-0.1.0.tgz +0 -1
  631. package/examples/non-strict-skips/release.config.json +0 -31
  632. package/examples/pypi-registry/release.config.json +0 -31
  633. package/templates/github-actions/plan-and-approved-execute.yml +0 -58
  634. package/templates/github-actions/plan-only.yml +0 -33
  635. package/templates/github-actions/trusted-publishing.yml +0 -61
@@ -0,0 +1,205 @@
1
+ import { createHash } from "node:crypto"
2
+
3
+ export type Json =
4
+ | boolean
5
+ | null
6
+ | number
7
+ | string
8
+ | ReadonlyArray<Json>
9
+ | { readonly [key: string]: Json }
10
+
11
+ class StrictJsonParser {
12
+ private index = 0
13
+ constructor(private readonly text: string) {}
14
+
15
+ parse(): Json {
16
+ this.space()
17
+ const value = this.value()
18
+ this.space()
19
+ if (this.index !== this.text.length) this.fail("trailing input")
20
+ return value
21
+ }
22
+
23
+ private fail(reason: string): never {
24
+ throw new Error(`Invalid strict JSON at ${this.index}: ${reason}`)
25
+ }
26
+
27
+ private space(): void {
28
+ while (/[\t\n\r ]/u.test(this.text[this.index] ?? "")) this.index += 1
29
+ }
30
+
31
+ private take(expected: string): void {
32
+ if (!this.text.startsWith(expected, this.index)) this.fail(`expected ${expected}`)
33
+ this.index += expected.length
34
+ }
35
+
36
+ private value(): Json {
37
+ const token = this.text[this.index]
38
+ if (token === "{") return this.object()
39
+ if (token === "[") return this.array()
40
+ if (token === '"') return this.string()
41
+ if (token === "t") {
42
+ this.take("true")
43
+ return true
44
+ }
45
+ if (token === "f") {
46
+ this.take("false")
47
+ return false
48
+ }
49
+ if (token === "n") {
50
+ this.take("null")
51
+ return null
52
+ }
53
+ if (token === "-" || token !== undefined && /[0-9]/u.test(token)) return this.number()
54
+ return this.fail("expected value")
55
+ }
56
+
57
+ private string(): string {
58
+ const start = this.index
59
+ this.index += 1
60
+ let escaped = false
61
+ while (this.index < this.text.length) {
62
+ const character = this.text[this.index]!
63
+ if (!escaped && character === '"') {
64
+ this.index += 1
65
+ const value = JSON.parse(this.text.slice(start, this.index)) as string
66
+ if (value !== value.normalize("NFC")) this.fail("non-NFC string")
67
+ return value
68
+ }
69
+ if (!escaped && character.codePointAt(0)! < 0x20) this.fail("control character")
70
+ escaped = !escaped && character === "\\"
71
+ this.index += 1
72
+ }
73
+ return this.fail("unterminated string")
74
+ }
75
+
76
+ private number(): number {
77
+ const match = /^-?(?:0|[1-9][0-9]*)/u.exec(this.text.slice(this.index))
78
+ if (match === null) return this.fail("invalid number")
79
+ const token = match[0]
80
+ const next = this.text[this.index + token.length]
81
+ if (next === "." || next === "e" || next === "E") this.fail("float")
82
+ this.index += token.length
83
+ const value = Number(token)
84
+ if (!Number.isSafeInteger(value) || Object.is(value, -0)) this.fail("unsafe integer")
85
+ return value
86
+ }
87
+
88
+ private array(): ReadonlyArray<Json> {
89
+ this.index += 1
90
+ this.space()
91
+ const result: Array<Json> = []
92
+ if (this.text[this.index] === "]") {
93
+ this.index += 1
94
+ return result
95
+ }
96
+ while (true) {
97
+ result.push(this.value())
98
+ this.space()
99
+ if (this.text[this.index] === "]") {
100
+ this.index += 1
101
+ return result
102
+ }
103
+ this.take(",")
104
+ this.space()
105
+ }
106
+ }
107
+
108
+ private object(): { readonly [key: string]: Json } {
109
+ this.index += 1
110
+ this.space()
111
+ const result: Record<string, Json> = {}
112
+ if (this.text[this.index] === "}") {
113
+ this.index += 1
114
+ return result
115
+ }
116
+ while (true) {
117
+ if (this.text[this.index] !== '"') this.fail("expected object key")
118
+ const key = this.string()
119
+ if (Object.hasOwn(result, key)) this.fail(`duplicate key ${key}`)
120
+ this.space()
121
+ this.take(":")
122
+ this.space()
123
+ result[key] = this.value()
124
+ this.space()
125
+ if (this.text[this.index] === "}") {
126
+ this.index += 1
127
+ return result
128
+ }
129
+ this.take(",")
130
+ this.space()
131
+ }
132
+ }
133
+ }
134
+
135
+ const codePointOrder = (left: string, right: string): number => {
136
+ const a = [...left]
137
+ const b = [...right]
138
+ let index = 0
139
+ while (index < Math.min(a.length, b.length)) {
140
+ const difference = a[index]!.codePointAt(0)! - b[index]!.codePointAt(0)!
141
+ if (difference !== 0) return difference
142
+ index += 1
143
+ }
144
+ return a.length - b.length
145
+ }
146
+
147
+ const canonicalArray = (value: ReadonlyArray<unknown>, parents: Set<object>): string => {
148
+ let index = 0
149
+ while (index < value.length) {
150
+ if (!Object.hasOwn(value, index)) throw new Error("sparse array")
151
+ index += 1
152
+ }
153
+ return `[${value.map((item) => canonical(item, parents)).join(",")}]`
154
+ }
155
+
156
+ const canonicalObject = (value: object, parents: Set<object>): string => {
157
+ if (Object.getPrototypeOf(value) !== Object.prototype) throw new Error("non-plain object")
158
+ const entries = Object.entries(value).map(([key, item]) => [key.normalize("NFC"), item] as const)
159
+ if (new Set(entries.map(([key]) => key)).size !== entries.length) {
160
+ throw new Error("normalized key collision")
161
+ }
162
+ entries.sort(([left], [right]) => codePointOrder(left, right))
163
+ return `{${entries.map(([key, item]) =>
164
+ `${JSON.stringify(key)}:${canonical(item, parents)}`).join(",")}}`
165
+ }
166
+
167
+ const canonical = (value: unknown, parents: Set<object>): string => {
168
+ if (value === null || typeof value === "boolean") return JSON.stringify(value)
169
+ if (typeof value === "string") return JSON.stringify(value.normalize("NFC"))
170
+ if (typeof value === "number") {
171
+ if (!Number.isSafeInteger(value) || Object.is(value, -0)) throw new Error("unsafe number")
172
+ return String(value)
173
+ }
174
+ if (typeof value !== "object") throw new Error("non-JSON value")
175
+ if (parents.has(value)) throw new Error("cyclic value")
176
+ parents.add(value)
177
+ try {
178
+ return Array.isArray(value)
179
+ ? canonicalArray(value, parents)
180
+ : canonicalObject(value, parents)
181
+ } finally {
182
+ parents.delete(value)
183
+ }
184
+ }
185
+
186
+ const frame = (value: Uint8Array): Uint8Array => {
187
+ const result = new Uint8Array(value.length + 4)
188
+ new DataView(result.buffer).setUint32(0, value.length, false)
189
+ result.set(value, 4)
190
+ return result
191
+ }
192
+
193
+ export const parseStrictJson = (text: string): Json => new StrictJsonParser(text).parse()
194
+ export const encodeCanonicalJson = (value: unknown): string =>
195
+ `${canonical(value, new Set())}\n`
196
+ export const hashFramed = (domain: string, parts: ReadonlyArray<Uint8Array>): string => {
197
+ const hash = createHash("sha256")
198
+ hash.update(frame(new TextEncoder().encode(domain.normalize("NFC"))))
199
+ parts.forEach((part) => {
200
+ hash.update(frame(part))
201
+ })
202
+ return hash.digest("hex")
203
+ }
204
+ export const hashCanonical = (domain: string, value: unknown): string =>
205
+ hashFramed(domain, [new TextEncoder().encode(encodeCanonicalJson(value))])
@@ -0,0 +1,220 @@
1
+ import * as Schema from "effect/Schema"
2
+ import * as Semver from "semver"
3
+ import { encodeCanonicalJson, parseStrictJson } from "./canonical.js"
4
+ import { Sha256Digest } from "./digest.js"
5
+ import { NonEmptyName, OutputId, SafeRelativePath, Version } from "./primitives.js"
6
+
7
+ const optional = Schema.optionalKey
8
+
9
+ export const GitHubRepositoryCoordinate = Schema.NonEmptyString.check(Schema.makeFilter(
10
+ (value: string) => /^[A-Za-z0-9._-]+\/[A-Za-z0-9._-]+$/u.test(value)
11
+ ? undefined
12
+ : "Catalog repository must be an owner/repository coordinate."
13
+ )).pipe(Schema.brand("GitHubRepositoryCoordinate"))
14
+ export type GitHubRepositoryCoordinate = typeof GitHubRepositoryCoordinate.Type
15
+
16
+ export const GitBranchName = Schema.NonEmptyString.check(Schema.makeFilter((value: string) =>
17
+ !value.startsWith("-") && !value.startsWith("/") && !value.endsWith("/") && !value.endsWith(".") &&
18
+ !value.endsWith(".lock") && !value.includes("..") && !value.includes("//") && !value.includes("@{") &&
19
+ !/[~^:?*[\\\u0000-\u001f\u007f]/u.test(value)
20
+ ? undefined
21
+ : "Catalog branch must be one canonical Git branch name."))
22
+ .pipe(Schema.brand("GitBranchName"))
23
+ export type GitBranchName = typeof GitBranchName.Type
24
+
25
+ export const CatalogRepositoryPath = SafeRelativePath.check(Schema.makeFilter((value) =>
26
+ value.toString() !== "." ? undefined : "Catalog repository paths must identify files."))
27
+ .pipe(Schema.brand("CatalogRepositoryPath"))
28
+ export type CatalogRepositoryPath = typeof CatalogRepositoryPath.Type
29
+
30
+ export const CatalogArchitecture = Schema.Literals(["x64", "arm64"])
31
+ export type CatalogArchitecture = typeof CatalogArchitecture.Type
32
+
33
+ export class CatalogRenderSource extends Schema.Class<CatalogRenderSource>("CatalogRenderSource")({
34
+ artifactId: OutputId,
35
+ architecture: CatalogArchitecture,
36
+ url: Schema.NonEmptyString,
37
+ filename: NonEmptyName
38
+ }) {}
39
+
40
+ export class PreparedCatalogDownload extends Schema.Class<PreparedCatalogDownload>("PreparedCatalogDownload")({
41
+ architecture: CatalogArchitecture,
42
+ url: Schema.NonEmptyString,
43
+ filename: NonEmptyName,
44
+ sha256: Sha256Digest
45
+ }) {}
46
+
47
+ const rendererFields = {
48
+ name: NonEmptyName,
49
+ description: Schema.NonEmptyString,
50
+ homepage: Schema.NonEmptyString,
51
+ license: optional(Schema.NonEmptyString)
52
+ }
53
+
54
+ export class HomebrewRenderer extends Schema.TaggedClass<HomebrewRenderer>()("homebrew", {
55
+ ...rendererFields,
56
+ installPath: NonEmptyName
57
+ }) {}
58
+
59
+ export class ScoopRenderer extends Schema.TaggedClass<ScoopRenderer>()("scoop", {
60
+ ...rendererFields,
61
+ bin: NonEmptyName
62
+ }) {}
63
+
64
+ export const CatalogRenderer = Schema.Union([HomebrewRenderer, ScoopRenderer])
65
+ export type CatalogRenderer = typeof CatalogRenderer.Type
66
+
67
+ export class PreparedCatalogRenderer
68
+ extends Schema.Class<PreparedCatalogRenderer>("PreparedCatalogRenderer")({
69
+ renderer: CatalogRenderer,
70
+ downloads: Schema.NonEmptyArray(PreparedCatalogDownload)
71
+ }) {}
72
+
73
+ export const CatalogManagedStatus = Schema.Literals(["active", "corrected", "superseded"])
74
+
75
+ export class CatalogManagedState extends Schema.Class<CatalogManagedState>("CatalogManagedState")({
76
+ schemaVersion: Schema.Literal("ts-release/catalog-state/v2"),
77
+ catalogId: NonEmptyName,
78
+ renderer: Schema.Literals(["homebrew", "scoop"]),
79
+ generation: Version,
80
+ status: CatalogManagedStatus,
81
+ targetDigest: Sha256Digest,
82
+ sourceRepository: GitHubRepositoryCoordinate,
83
+ sourceTag: NonEmptyName,
84
+ correctionId: optional(Sha256Digest),
85
+ reason: optional(Schema.NonEmptyString),
86
+ replacementVersion: optional(Version)
87
+ }) {}
88
+
89
+ export const encodeCatalogManagedState = (value: CatalogManagedState): Uint8Array =>
90
+ new TextEncoder().encode(encodeCanonicalJson(Schema.encodeSync(CatalogManagedState)(value)))
91
+
92
+ export const decodeCatalogManagedState = (bytes: Uint8Array): CatalogManagedState | undefined => {
93
+ try {
94
+ const text = new TextDecoder("utf-8", { fatal: true }).decode(bytes)
95
+ const value = Schema.decodeUnknownSync(CatalogManagedState, { onExcessProperty: "error" })(parseStrictJson(text))
96
+ if (Semver.valid(value.generation.toString()) !== value.generation.toString()) return undefined
97
+ const canonical = encodeCatalogManagedState(value)
98
+ return canonical.length === bytes.length && canonical.every((byte, index) => byte === bytes[index])
99
+ ? value
100
+ : undefined
101
+ } catch {
102
+ return undefined
103
+ }
104
+ }
105
+
106
+ export const canonicalCatalogVersion = (value: string): Version => {
107
+ const parsed = Semver.valid(value)
108
+ if (parsed === null || parsed !== value) throw new Error(`Catalog generation requires a canonical semantic version, got ${JSON.stringify(value)}.`)
109
+ return Version.make(value)
110
+ }
111
+
112
+ export const compareCatalogVersions = (left: string, right: string): number => {
113
+ canonicalCatalogVersion(left)
114
+ canonicalCatalogVersion(right)
115
+ return Semver.compare(left, right)
116
+ }
117
+
118
+ const assertDownloads = (downloads: ReadonlyArray<PreparedCatalogDownload>): void => {
119
+ if (downloads.length === 0) throw new Error("Catalog renderer requires at least one download.")
120
+ const architectures = downloads.map((download) => download.architecture)
121
+ if (new Set(architectures).size !== architectures.length) {
122
+ throw new Error("Catalog renderer repeats an architecture.")
123
+ }
124
+ for (const download of downloads) {
125
+ const url = new URL(download.url)
126
+ if (url.protocol !== "https:" || url.username !== "" || url.password !== "" || url.hash !== "") {
127
+ throw new Error("Catalog download URLs must be credential-free HTTPS URLs.")
128
+ }
129
+ }
130
+ }
131
+
132
+ const rubyString = (value: string): string => JSON.stringify(value)
133
+ const formulaClass = (value: string): string => value.split(/[^A-Za-z0-9]+/u).filter(Boolean)
134
+ .map((part) => `${part.slice(0, 1).toUpperCase()}${part.slice(1)}`).join("") || "GeneratedFormula"
135
+
136
+ const homebrewDownload = (download: PreparedCatalogDownload, indent: string): ReadonlyArray<string> => [
137
+ `${indent}url ${rubyString(download.url)}`,
138
+ `${indent}sha256 ${rubyString(download.sha256.hex)}`
139
+ ]
140
+
141
+ const renderHomebrew = (
142
+ version: Version,
143
+ renderer: HomebrewRenderer,
144
+ downloads: ReadonlyArray<PreparedCatalogDownload>
145
+ ): string => {
146
+ const lines = [
147
+ `class ${formulaClass(renderer.name)} < Formula`,
148
+ ` desc ${rubyString(renderer.description)}`,
149
+ ` homepage ${rubyString(renderer.homepage)}`,
150
+ ...(renderer.license === undefined ? [] : [` license ${rubyString(renderer.license)}`]),
151
+ ` version ${rubyString(version.toString())}`
152
+ ]
153
+ if (downloads.length === 1) {
154
+ lines.push(...homebrewDownload(downloads[0]!, " "))
155
+ } else {
156
+ lines.push("", " on_macos do")
157
+ for (const architecture of ["arm64", "x64"] as const) {
158
+ const download = downloads.find((candidate) => candidate.architecture === architecture)
159
+ if (download === undefined) continue
160
+ lines.push(` ${architecture === "arm64" ? "on_arm" : "on_intel"} do`)
161
+ lines.push(...homebrewDownload(download, " "))
162
+ lines.push(" end")
163
+ }
164
+ lines.push(" end")
165
+ }
166
+ lines.push(
167
+ "",
168
+ " def install",
169
+ ` bin.install ${rubyString(renderer.installPath)} => ${rubyString(renderer.name)}`,
170
+ " end",
171
+ "",
172
+ " test do",
173
+ ` assert_predicate bin/${rubyString(renderer.name)}, :executable?`,
174
+ " end",
175
+ "end",
176
+ ""
177
+ )
178
+ return lines.join("\n")
179
+ }
180
+
181
+ const scoopDownload = (download: PreparedCatalogDownload): Readonly<Record<string, string>> => ({
182
+ url: download.url,
183
+ hash: download.sha256.hex
184
+ })
185
+
186
+ const renderScoop = (
187
+ version: Version,
188
+ renderer: ScoopRenderer,
189
+ downloads: ReadonlyArray<PreparedCatalogDownload>
190
+ ): string => {
191
+ const common: Record<string, unknown> = {
192
+ version: version.toString(),
193
+ description: renderer.description,
194
+ homepage: renderer.homepage,
195
+ ...(renderer.license === undefined ? {} : { license: renderer.license })
196
+ }
197
+ const value = downloads.length === 1
198
+ ? { ...common, ...scoopDownload(downloads[0]!), bin: renderer.bin.toString() }
199
+ : {
200
+ ...common,
201
+ architecture: Object.fromEntries(downloads
202
+ .slice()
203
+ .sort((left, right) => left.architecture < right.architecture ? -1 : 1)
204
+ .map((download) => [download.architecture === "x64" ? "64bit" : "arm64", scoopDownload(download)])),
205
+ bin: renderer.bin.toString()
206
+ }
207
+ return `${JSON.stringify(value, null, 2)}\n`
208
+ }
209
+
210
+ export const renderCatalog = (
211
+ version: Version,
212
+ renderer: CatalogRenderer,
213
+ downloads: ReadonlyArray<PreparedCatalogDownload>
214
+ ): Uint8Array => {
215
+ canonicalCatalogVersion(version.toString())
216
+ assertDownloads(downloads)
217
+ return new TextEncoder().encode(renderer._tag === "homebrew"
218
+ ? renderHomebrew(version, renderer, downloads)
219
+ : renderScoop(version, renderer, downloads))
220
+ }
@@ -0,0 +1,172 @@
1
+ import * as Schema from "effect/Schema"
2
+ import { createHash } from "node:crypto"
3
+
4
+ const lowercaseHex = (algorithm: "sha1" | "sha256" | "sha512", length: number) =>
5
+ Schema.String.check(Schema.makeFilter((value: string) =>
6
+ new RegExp(`^[a-f0-9]{${length}}$`, "u").test(value)
7
+ ? undefined
8
+ : `${algorithm} digest bytes must be exactly ${length} lowercase hexadecimal characters.`
9
+ )).pipe(Schema.brand(`${algorithm}Hex`))
10
+
11
+ export const Sha1Hex = lowercaseHex("sha1", 40)
12
+ export type Sha1Hex = typeof Sha1Hex.Type
13
+
14
+ export const Sha256Hex = lowercaseHex("sha256", 64)
15
+ export type Sha256Hex = typeof Sha256Hex.Type
16
+
17
+ export const Sha512Hex = lowercaseHex("sha512", 128)
18
+ export type Sha512Hex = typeof Sha512Hex.Type
19
+
20
+ export class Sha1Digest
21
+ extends Schema.TaggedClass<Sha1Digest>()("Sha1Digest", {
22
+ algorithm: Schema.Literal("sha1"),
23
+ hex: Sha1Hex
24
+ }) {}
25
+
26
+ export class Sha256Digest
27
+ extends Schema.TaggedClass<Sha256Digest>()("Sha256Digest", {
28
+ algorithm: Schema.Literal("sha256"),
29
+ hex: Sha256Hex
30
+ }) {}
31
+
32
+ export class Sha512Digest
33
+ extends Schema.TaggedClass<Sha512Digest>()("Sha512Digest", {
34
+ algorithm: Schema.Literal("sha512"),
35
+ hex: Sha512Hex
36
+ }) {}
37
+
38
+ export const AlgorithmDigest = Schema.Union([
39
+ Sha1Digest,
40
+ Sha256Digest,
41
+ Sha512Digest
42
+ ])
43
+ export type AlgorithmDigest = typeof AlgorithmDigest.Type
44
+
45
+ export const DigestEncoding = Schema.Literals([
46
+ "sha1-hex",
47
+ "sha256-hex",
48
+ "sha512-hex",
49
+ "github-sha256",
50
+ "npm-sha512-sri",
51
+ "npm-sha1-shasum"
52
+ ])
53
+ export type DigestEncoding = typeof DigestEncoding.Type
54
+
55
+ export class DigestCodecError
56
+ extends Schema.TaggedErrorClass<DigestCodecError>()("DigestCodecError", {
57
+ encoding: DigestEncoding,
58
+ reason: Schema.NonEmptyString
59
+ }) {}
60
+
61
+ const decodeHex = (
62
+ value: unknown,
63
+ encoding: "sha1-hex" | "sha256-hex" | "sha512-hex",
64
+ length: 40 | 64 | 128
65
+ ): string => {
66
+ if (typeof value !== "string" ||
67
+ !new RegExp(`^[a-f0-9]{${length}}$`, "u").test(value)) {
68
+ throw new DigestCodecError({
69
+ encoding,
70
+ reason: `Value is not a canonical ${encoding} digest encoding.`
71
+ })
72
+ }
73
+ return value
74
+ }
75
+
76
+ export const parseSha1Hex = (value: unknown): Sha1Digest => Sha1Digest.make({
77
+ algorithm: "sha1",
78
+ hex: Sha1Hex.make(decodeHex(value, "sha1-hex", 40))
79
+ })
80
+
81
+ export const parseSha256Hex = (value: unknown): Sha256Digest => Sha256Digest.make({
82
+ algorithm: "sha256",
83
+ hex: Sha256Hex.make(decodeHex(value, "sha256-hex", 64))
84
+ })
85
+
86
+ export const parseSha512Hex = (value: unknown): Sha512Digest => Sha512Digest.make({
87
+ algorithm: "sha512",
88
+ hex: Sha512Hex.make(decodeHex(value, "sha512-hex", 128))
89
+ })
90
+
91
+ export const formatSha1Hex = (digest: Sha1Digest): Sha1Hex => digest.hex
92
+ export const formatSha256Hex = (digest: Sha256Digest): Sha256Hex => digest.hex
93
+ export const formatSha512Hex = (digest: Sha512Digest): Sha512Hex => digest.hex
94
+
95
+ export const parseGitHubSha256 = (value: unknown): Sha256Digest => {
96
+ if (typeof value !== "string" || !value.startsWith("sha256:")) {
97
+ throw new DigestCodecError({
98
+ encoding: "github-sha256",
99
+ reason: "GitHub SHA-256 must use the canonical sha256:<lowercase-hex> encoding."
100
+ })
101
+ }
102
+ try {
103
+ return parseSha256Hex(value.slice("sha256:".length))
104
+ } catch {
105
+ throw new DigestCodecError({
106
+ encoding: "github-sha256",
107
+ reason: "GitHub SHA-256 must use the canonical sha256:<lowercase-hex> encoding."
108
+ })
109
+ }
110
+ }
111
+
112
+ export const formatGitHubSha256 = (digest: Sha256Digest): string =>
113
+ `sha256:${formatSha256Hex(digest)}`
114
+
115
+ export const parseNpmSha512Sri = (value: unknown): Sha512Digest => {
116
+ if (typeof value !== "string" || !value.startsWith("sha512-")) {
117
+ throw new DigestCodecError({
118
+ encoding: "npm-sha512-sri",
119
+ reason: "npm SHA-512 integrity must use the canonical sha512-<base64> SRI encoding."
120
+ })
121
+ }
122
+ const encoded = value.slice("sha512-".length)
123
+ if (!/^[A-Za-z0-9+/]{86}==$/u.test(encoded)) {
124
+ throw new DigestCodecError({
125
+ encoding: "npm-sha512-sri",
126
+ reason: "npm SHA-512 integrity contains malformed or noncanonical base64."
127
+ })
128
+ }
129
+ const bytes = Buffer.from(encoded, "base64")
130
+ if (bytes.length !== 64 || bytes.toString("base64") !== encoded) {
131
+ throw new DigestCodecError({
132
+ encoding: "npm-sha512-sri",
133
+ reason: "npm SHA-512 integrity contains malformed or noncanonical base64."
134
+ })
135
+ }
136
+ return parseSha512Hex(bytes.toString("hex"))
137
+ }
138
+
139
+ export const formatNpmSha512Sri = (digest: Sha512Digest): string =>
140
+ `sha512-${Buffer.from(formatSha512Hex(digest), "hex").toString("base64")}`
141
+
142
+ export const parseNpmSha1Shasum = (value: unknown): Sha1Digest => {
143
+ try {
144
+ const parsed = parseSha1Hex(value)
145
+ return Sha1Digest.make({ algorithm: "sha1", hex: parsed.hex })
146
+ } catch {
147
+ throw new DigestCodecError({
148
+ encoding: "npm-sha1-shasum",
149
+ reason: "npm shasum must be exactly 40 lowercase hexadecimal SHA-1 characters."
150
+ })
151
+ }
152
+ }
153
+
154
+ export const formatNpmSha1Shasum = (digest: Sha1Digest): string =>
155
+ formatSha1Hex(digest)
156
+
157
+ const hashHex = (algorithm: "sha1" | "sha256" | "sha512", bytes: Uint8Array): string =>
158
+ createHash(algorithm).update(bytes).digest("hex")
159
+
160
+ export const sha1Digest = (bytes: Uint8Array): Sha1Digest =>
161
+ parseSha1Hex(hashHex("sha1", bytes))
162
+
163
+ export const sha256Digest = (bytes: Uint8Array): Sha256Digest =>
164
+ parseSha256Hex(hashHex("sha256", bytes))
165
+
166
+ export const sha512Digest = (bytes: Uint8Array): Sha512Digest =>
167
+ parseSha512Hex(hashHex("sha512", bytes))
168
+
169
+ export const digestEquals = (
170
+ left: AlgorithmDigest,
171
+ right: AlgorithmDigest
172
+ ): boolean => left.algorithm === right.algorithm && left.hex === right.hex
@@ -0,0 +1,6 @@
1
+ import * as Schema from "effect/Schema"
2
+
3
+ const reason = { reason: Schema.String }
4
+ export const MISSING_COMMIT = "source.commit is required and could not be observed from the repository."
5
+ export class ConfigValueError extends Schema.TaggedErrorClass<ConfigValueError>()("ConfigValueError", reason) {}
6
+ export class ConfigDecodeError extends Schema.TaggedErrorClass<ConfigDecodeError>()("ConfigDecodeError", reason) {}
@@ -0,0 +1,37 @@
1
+ import * as Schema from "effect/Schema"
2
+
3
+ const identifier = <const Name extends string>(name: Name) =>
4
+ Schema.NonEmptyString.pipe(Schema.brand(name))
5
+
6
+ export const OperationId = identifier("OperationId"); export type OperationId = typeof OperationId.Type
7
+ export const OutputId = identifier("OutputId"); export type OutputId = typeof OutputId.Type
8
+ export const Digest = identifier("Digest"); export type Digest = typeof Digest.Type
9
+ export const NonEmptyName = identifier("NonEmptyName"); export type NonEmptyName = typeof NonEmptyName.Type
10
+ export const Version = identifier("Version"); export type Version = typeof Version.Type
11
+
12
+ export const isSafeRelativePath = (value: string): boolean =>
13
+ value.trim().length > 0 &&
14
+ !value.startsWith("/") &&
15
+ !value.startsWith("\\") &&
16
+ !/^[A-Za-z]:[\\/]/u.test(value) &&
17
+ !value.split(/[\\/]+/u).includes("..")
18
+
19
+ export const SafeRelativePath = Schema.String.check(
20
+ Schema.makeFilter((value: string) =>
21
+ isSafeRelativePath(value)
22
+ ? undefined
23
+ : "Path must be nonempty, relative, and contain no parent traversal.")
24
+ ).pipe(Schema.brand("SafeRelativePath"))
25
+ export type SafeRelativePath = typeof SafeRelativePath.Type
26
+
27
+ export const SafeArchivePattern = Schema.String.check(
28
+ Schema.makeFilter((value: string) =>
29
+ isSafeRelativePath(value) ? undefined : "Archive pattern must be relative and contain no parent traversal.")
30
+ ).pipe(Schema.brand("SafeArchivePattern"))
31
+ export type SafeArchivePattern = typeof SafeArchivePattern.Type
32
+
33
+ export const WorkspaceRoot = Schema.String.check(
34
+ Schema.makeFilter((value: string) =>
35
+ value.startsWith("/") ? undefined : "WorkspaceRoot must be absolute.")
36
+ ).pipe(Schema.brand("WorkspaceRoot"))
37
+ export type WorkspaceRoot = typeof WorkspaceRoot.Type
@@ -0,0 +1,30 @@
1
+ import * as Schema from "effect/Schema"
2
+
3
+ export const PyPiRepository = Schema.Literals(["pypi", "testpypi"])
4
+ export type PyPiRepository = typeof PyPiRepository.Type
5
+
6
+ export const normalizePyPiProjectName = (value: string): string => {
7
+ if (!/^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/u.test(value)) {
8
+ throw new Error("PyPI project names may contain only ASCII letters, digits, period, underscore, and hyphen.")
9
+ }
10
+ return value.toLowerCase().replace(/[-_.]+/gu, "-")
11
+ }
12
+
13
+ export const PyPiProjectName = Schema.NonEmptyString.check(Schema.makeFilter((value: string) => {
14
+ try {
15
+ return normalizePyPiProjectName(value) === value ? undefined : "PyPI project name must be normalized."
16
+ } catch (cause) {
17
+ return cause instanceof Error ? cause.message : String(cause)
18
+ }
19
+ })).pipe(Schema.brand("PyPiProjectName"))
20
+ export type PyPiProjectName = typeof PyPiProjectName.Type
21
+
22
+ export interface PyPiRepositoryEndpoints {
23
+ readonly simpleBaseUrl: string
24
+ readonly uploadUrl: string
25
+ }
26
+
27
+ export const pypiRepositoryEndpoints = (repository: PyPiRepository): PyPiRepositoryEndpoints =>
28
+ repository === "pypi"
29
+ ? { simpleBaseUrl: "https://pypi.org/simple/", uploadUrl: "https://upload.pypi.org/legacy/" }
30
+ : { simpleBaseUrl: "https://test.pypi.org/simple/", uploadUrl: "https://test.pypi.org/legacy/" }