@mannyc1/ts-release 0.0.6 → 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 (639) hide show
  1. package/ARCHITECTURE.md +124 -87
  2. package/CHANGELOG.md +115 -0
  3. package/LICENSE +21 -0
  4. package/README.md +272 -540
  5. package/SPEC.md +206 -305
  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 +61 -154
  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 -59
  440. package/templates/bun-cli-github/README.md +12 -0
  441. package/templates/bun-cli-github/release.config.json +51 -0
  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/config/errors.d.ts +0 -24
  455. package/dist/config/errors.d.ts.map +0 -1
  456. package/dist/config/errors.js +0 -19
  457. package/dist/config/errors.js.map +0 -1
  458. package/dist/config/load.d.ts +0 -9
  459. package/dist/config/load.d.ts.map +0 -1
  460. package/dist/config/load.js +0 -29
  461. package/dist/config/load.js.map +0 -1
  462. package/dist/config/schema.d.ts +0 -12
  463. package/dist/config/schema.d.ts.map +0 -1
  464. package/dist/config/schema.js +0 -19
  465. package/dist/config/schema.js.map +0 -1
  466. package/dist/domain/artifact.d.ts +0 -36
  467. package/dist/domain/artifact.d.ts.map +0 -1
  468. package/dist/domain/artifact.js +0 -29
  469. package/dist/domain/artifact.js.map +0 -1
  470. package/dist/domain/evidence.d.ts +0 -108
  471. package/dist/domain/evidence.d.ts.map +0 -1
  472. package/dist/domain/evidence.js +0 -96
  473. package/dist/domain/evidence.js.map +0 -1
  474. package/dist/domain/operation.d.ts +0 -153
  475. package/dist/domain/operation.d.ts.map +0 -1
  476. package/dist/domain/operation.js +0 -320
  477. package/dist/domain/operation.js.map +0 -1
  478. package/dist/domain/release.d.ts +0 -141
  479. package/dist/domain/release.d.ts.map +0 -1
  480. package/dist/domain/release.js +0 -127
  481. package/dist/domain/release.js.map +0 -1
  482. package/dist/domain/remote-state.d.ts +0 -85
  483. package/dist/domain/remote-state.d.ts.map +0 -1
  484. package/dist/domain/remote-state.js +0 -77
  485. package/dist/domain/remote-state.js.map +0 -1
  486. package/dist/domain/status.d.ts +0 -43
  487. package/dist/domain/status.d.ts.map +0 -1
  488. package/dist/domain/status.js +0 -51
  489. package/dist/domain/status.js.map +0 -1
  490. package/dist/domain/target.d.ts +0 -135
  491. package/dist/domain/target.d.ts.map +0 -1
  492. package/dist/domain/target.js +0 -137
  493. package/dist/domain/target.js.map +0 -1
  494. package/dist/host/host.d.ts +0 -32
  495. package/dist/host/host.d.ts.map +0 -1
  496. package/dist/host/host.js +0 -24
  497. package/dist/host/host.js.map +0 -1
  498. package/dist/host/http-live.d.ts +0 -6
  499. package/dist/host/http-live.d.ts.map +0 -1
  500. package/dist/host/http-live.js +0 -86
  501. package/dist/host/http-live.js.map +0 -1
  502. package/dist/host/http.d.ts +0 -43
  503. package/dist/host/http.d.ts.map +0 -1
  504. package/dist/host/http.js +0 -59
  505. package/dist/host/http.js.map +0 -1
  506. package/dist/host/platform.d.ts +0 -10
  507. package/dist/host/platform.d.ts.map +0 -1
  508. package/dist/host/platform.js +0 -114
  509. package/dist/host/platform.js.map +0 -1
  510. package/dist/host/test.d.ts +0 -23
  511. package/dist/host/test.d.ts.map +0 -1
  512. package/dist/host/test.js +0 -222
  513. package/dist/host/test.js.map +0 -1
  514. package/dist/internal/workflow-phases.d.ts +0 -3
  515. package/dist/internal/workflow-phases.d.ts.map +0 -1
  516. package/dist/internal/workflow-phases.js +0 -2
  517. package/dist/internal/workflow-phases.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 -84
  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 -81
  531. package/dist/planner/errors.d.ts.map +0 -1
  532. package/dist/planner/errors.js +0 -70
  533. package/dist/planner/errors.js.map +0 -1
  534. package/dist/planner/evidence-recorder.d.ts +0 -26
  535. package/dist/planner/evidence-recorder.d.ts.map +0 -1
  536. package/dist/planner/evidence-recorder.js +0 -330
  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 -159
  541. package/dist/planner/executor.js.map +0 -1
  542. package/dist/planner/normalize-release.d.ts +0 -16
  543. package/dist/planner/normalize-release.d.ts.map +0 -1
  544. package/dist/planner/normalize-release.js +0 -218
  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 -261
  549. package/dist/planner/reconcile.js.map +0 -1
  550. package/dist/planner/release-eligibility.d.ts +0 -39
  551. package/dist/planner/release-eligibility.d.ts.map +0 -1
  552. package/dist/planner/release-eligibility.js +0 -578
  553. package/dist/planner/release-eligibility.js.map +0 -1
  554. package/dist/planner/render-plan.d.ts +0 -15
  555. package/dist/planner/render-plan.d.ts.map +0 -1
  556. package/dist/planner/render-plan.js +0 -238
  557. package/dist/planner/render-plan.js.map +0 -1
  558. package/dist/planner/status.d.ts +0 -40
  559. package/dist/planner/status.d.ts.map +0 -1
  560. package/dist/planner/status.js +0 -313
  561. package/dist/planner/status.js.map +0 -1
  562. package/dist/targets/adapter-helpers.d.ts +0 -64
  563. package/dist/targets/adapter-helpers.d.ts.map +0 -1
  564. package/dist/targets/adapter-helpers.js +0 -124
  565. package/dist/targets/adapter-helpers.js.map +0 -1
  566. package/dist/targets/adapter.d.ts +0 -17
  567. package/dist/targets/adapter.d.ts.map +0 -1
  568. package/dist/targets/adapter.js +0 -2
  569. package/dist/targets/adapter.js.map +0 -1
  570. package/dist/targets/github-release.d.ts +0 -25
  571. package/dist/targets/github-release.d.ts.map +0 -1
  572. package/dist/targets/github-release.js +0 -82
  573. package/dist/targets/github-release.js.map +0 -1
  574. package/dist/targets/github.d.ts +0 -11
  575. package/dist/targets/github.d.ts.map +0 -1
  576. package/dist/targets/github.js +0 -125
  577. package/dist/targets/github.js.map +0 -1
  578. package/dist/targets/homebrew.d.ts +0 -11
  579. package/dist/targets/homebrew.d.ts.map +0 -1
  580. package/dist/targets/homebrew.js +0 -97
  581. package/dist/targets/homebrew.js.map +0 -1
  582. package/dist/targets/live.d.ts +0 -5
  583. package/dist/targets/live.d.ts.map +0 -1
  584. package/dist/targets/live.js +0 -50
  585. package/dist/targets/live.js.map +0 -1
  586. package/dist/targets/npm.d.ts +0 -10
  587. package/dist/targets/npm.d.ts.map +0 -1
  588. package/dist/targets/npm.js +0 -118
  589. package/dist/targets/npm.js.map +0 -1
  590. package/dist/targets/pypi.d.ts +0 -11
  591. package/dist/targets/pypi.d.ts.map +0 -1
  592. package/dist/targets/pypi.js +0 -103
  593. package/dist/targets/pypi.js.map +0 -1
  594. package/dist/targets/registry.d.ts +0 -25
  595. package/dist/targets/registry.d.ts.map +0 -1
  596. package/dist/targets/registry.js +0 -34
  597. package/dist/targets/registry.js.map +0 -1
  598. package/dist/targets/scoop.d.ts +0 -11
  599. package/dist/targets/scoop.d.ts.map +0 -1
  600. package/dist/targets/scoop.js +0 -78
  601. package/dist/targets/scoop.js.map +0 -1
  602. package/dist/types/effect-internal.d.ts +0 -5
  603. package/dist/types/effect-internal.d.ts.map +0 -1
  604. package/dist/types/effect-internal.js +0 -2
  605. package/dist/types/effect-internal.js.map +0 -1
  606. package/dist/workflows/config.d.ts +0 -252
  607. package/dist/workflows/config.d.ts.map +0 -1
  608. package/dist/workflows/config.js +0 -465
  609. package/dist/workflows/config.js.map +0 -1
  610. package/dist/workflows/diagnostics.d.ts +0 -62
  611. package/dist/workflows/diagnostics.d.ts.map +0 -1
  612. package/dist/workflows/diagnostics.js +0 -527
  613. package/dist/workflows/diagnostics.js.map +0 -1
  614. package/dist/workflows/evidence.d.ts +0 -26
  615. package/dist/workflows/evidence.d.ts.map +0 -1
  616. package/dist/workflows/evidence.js +0 -44
  617. package/dist/workflows/evidence.js.map +0 -1
  618. package/dist/workflows/index.d.ts +0 -7
  619. package/dist/workflows/index.d.ts.map +0 -1
  620. package/dist/workflows/index.js +0 -6
  621. package/dist/workflows/index.js.map +0 -1
  622. package/dist/workflows/init.d.ts +0 -84
  623. package/dist/workflows/init.d.ts.map +0 -1
  624. package/dist/workflows/init.js +0 -441
  625. package/dist/workflows/init.js.map +0 -1
  626. package/dist/workflows/live.d.ts +0 -9
  627. package/dist/workflows/live.d.ts.map +0 -1
  628. package/dist/workflows/live.js +0 -7
  629. package/dist/workflows/live.js.map +0 -1
  630. package/dist/workflows/options.d.ts +0 -30
  631. package/dist/workflows/options.d.ts.map +0 -1
  632. package/dist/workflows/options.js +0 -16
  633. package/dist/workflows/options.js.map +0 -1
  634. package/examples/non-strict-skips/artifacts/release-example-skips-0.1.0.tgz +0 -1
  635. package/examples/non-strict-skips/release.config.json +0 -31
  636. package/examples/pypi-registry/release.config.json +0 -31
  637. package/templates/github-actions/plan-and-approved-execute.yml +0 -58
  638. package/templates/github-actions/plan-only.yml +0 -33
  639. package/templates/github-actions/trusted-publishing.yml +0 -61
@@ -0,0 +1,360 @@
1
+ import { gunzipSync, inflateRawSync } from "node:zlib"
2
+ import * as Schema from "effect/Schema"
3
+ import { normalizePyPiProjectName, PyPiProjectName } from "./pypi.js"
4
+ import { NonEmptyName, Version } from "./primitives.js"
5
+
6
+ const metadataLimit = 4 * 1024 * 1024
7
+ const archiveLimit = 512 * 1024 * 1024
8
+
9
+ export class PythonDistributionError
10
+ extends Schema.TaggedErrorClass<PythonDistributionError>()("PythonDistributionError", {
11
+ filename: Schema.NonEmptyString,
12
+ reason: Schema.NonEmptyString
13
+ }) {}
14
+
15
+ export class WheelDistribution extends Schema.TaggedClass<WheelDistribution>()("wheel", {
16
+ project: PyPiProjectName,
17
+ version: Version,
18
+ metadataVersion: NonEmptyName,
19
+ pythonTag: NonEmptyName,
20
+ abiTag: NonEmptyName,
21
+ platformTag: NonEmptyName,
22
+ mediaType: Schema.Literal("application/zip")
23
+ }) {}
24
+
25
+ export class SourceDistribution extends Schema.TaggedClass<SourceDistribution>()("sdist", {
26
+ project: PyPiProjectName,
27
+ version: Version,
28
+ metadataVersion: NonEmptyName,
29
+ pythonTag: Schema.Literal("source"),
30
+ mediaType: Schema.Literal("application/gzip")
31
+ }) {}
32
+
33
+ export const PythonDistribution = Schema.Union([WheelDistribution, SourceDistribution])
34
+ export type PythonDistribution = typeof PythonDistribution.Type
35
+
36
+ const fail = (filename: string, reason: string): never => {
37
+ throw PythonDistributionError.make({ filename, reason })
38
+ }
39
+
40
+ const safePath = (filename: string, path: string): string => {
41
+ const checked = path.endsWith("/") ? path.slice(0, -1) : path
42
+ if (path.length === 0 || path.includes("\0") || path.includes("\\") || path.startsWith("/") ||
43
+ checked.length === 0 || /^[A-Za-z]:/u.test(path) || checked.split("/").some((part) => part === ".." || part === "")) {
44
+ fail(filename, "Distribution archive contains a malformed or escaping path.")
45
+ }
46
+ return path
47
+ }
48
+
49
+ const utf8 = (filename: string, bytes: Uint8Array): string => {
50
+ try { return new TextDecoder("utf-8", { fatal: true }).decode(bytes) } catch {
51
+ return fail(filename, "Distribution metadata or archive path is not valid UTF-8.")
52
+ }
53
+ }
54
+
55
+ type CoreMetadata = {
56
+ readonly name: string
57
+ readonly project: string
58
+ readonly version: string
59
+ readonly metadataVersion: string
60
+ }
61
+
62
+ const coreMetadata = (filename: string, bytes: Uint8Array): CoreMetadata => {
63
+ if (bytes.length === 0 || bytes.length > metadataLimit) fail(filename, "Distribution core metadata has an invalid size.")
64
+ const lines = utf8(filename, bytes).replaceAll("\r\n", "\n").split("\n")
65
+ const values = new Map<string, Array<string>>()
66
+ let current: string | undefined
67
+ for (const line of lines) {
68
+ if (line === "") break
69
+ if (/^[ \t]/u.test(line)) {
70
+ if (current === undefined) fail(filename, "Distribution core metadata begins with a continuation line.")
71
+ const prior = values.get(current!)!
72
+ prior[prior.length - 1] = `${prior.at(-1)!}\n${line.slice(1)}`
73
+ continue
74
+ }
75
+ const index = line.indexOf(":")
76
+ if (index <= 0) fail(filename, "Distribution core metadata contains a malformed header.")
77
+ current = line.slice(0, index).toLowerCase()
78
+ const value = line.slice(index + 1).trim()
79
+ values.set(current, [...(values.get(current) ?? []), value])
80
+ }
81
+ const one = (name: string): string => {
82
+ const found = values.get(name)
83
+ const value = found?.length === 1 ? found[0] : undefined
84
+ if (value === undefined || value.length === 0) fail(filename, `Distribution metadata requires exactly one ${name} field.`)
85
+ return value!
86
+ }
87
+ const name = one("name")
88
+ const version = one("version")
89
+ const metadataVersion = one("metadata-version")
90
+ if (!/^\d+\.\d+$/u.test(metadataVersion)) fail(filename, "Distribution Metadata-Version must use major.minor form.")
91
+ if (!/^[A-Za-z0-9][A-Za-z0-9.!+_-]*$/u.test(version)) fail(filename, "Distribution Version is not a conservative Python package version.")
92
+ let project: string
93
+ try { project = normalizePyPiProjectName(name) } catch {
94
+ return fail(filename, "Distribution Name is not a valid PyPI project name.")
95
+ }
96
+ return { name, project, version, metadataVersion }
97
+ }
98
+
99
+ const u16 = (filename: string, view: DataView, offset: number): number => {
100
+ if (offset < 0 || offset + 2 > view.byteLength) fail(filename, "ZIP structure is truncated.")
101
+ return view.getUint16(offset, true)
102
+ }
103
+
104
+ const u32 = (filename: string, view: DataView, offset: number): number => {
105
+ if (offset < 0 || offset + 4 > view.byteLength) fail(filename, "ZIP structure is truncated.")
106
+ return view.getUint32(offset, true)
107
+ }
108
+
109
+ type ZipEntry = {
110
+ readonly path: string
111
+ readonly flags: number
112
+ readonly method: number
113
+ readonly crc32: number
114
+ readonly compressedSize: number
115
+ readonly uncompressedSize: number
116
+ readonly localOffset: number
117
+ }
118
+
119
+ const crcTable = Array.from({ length: 256 }, (_, value) => {
120
+ let crc = value
121
+ for (let bit = 0; bit < 8; bit += 1) crc = (crc & 1) === 1 ? 0xedb88320 ^ (crc >>> 1) : crc >>> 1
122
+ return crc >>> 0
123
+ })
124
+
125
+ const crc32 = (data: Uint8Array): number => {
126
+ let crc = 0xffffffff
127
+ for (const byte of data) crc = (crc >>> 8) ^ crcTable[(crc ^ byte) & 0xff]!
128
+ return (crc ^ 0xffffffff) >>> 0
129
+ }
130
+
131
+ const zipEntries = (filename: string, bytes: Uint8Array): ReadonlyArray<ZipEntry> => {
132
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength)
133
+ let eocd = -1
134
+ const minimum = Math.max(0, bytes.length - 65_557)
135
+ for (let offset = bytes.length - 22; offset >= minimum; offset -= 1) {
136
+ if (u32(filename, view, offset) === 0x06054b50) { eocd = offset; break }
137
+ }
138
+ if (eocd < 0 || u16(filename, view, eocd + 4) !== 0 || u16(filename, view, eocd + 6) !== 0) {
139
+ fail(filename, "Wheel ZIP must be a single-disk archive with an end record.")
140
+ }
141
+ const count = u16(filename, view, eocd + 10)
142
+ const size = u32(filename, view, eocd + 12)
143
+ const start = u32(filename, view, eocd + 16)
144
+ if (count === 0 || count === 0xffff || start === 0xffffffff || size === 0xffffffff || start + size > eocd) {
145
+ fail(filename, "Wheel ZIP central directory is invalid or requires unsupported ZIP64 fields.")
146
+ }
147
+ const entries: Array<ZipEntry> = []
148
+ const paths = new Set<string>()
149
+ let offset = start
150
+ for (let index = 0; index < count; index += 1) {
151
+ if (u32(filename, view, offset) !== 0x02014b50) fail(filename, "Wheel ZIP central directory entry is malformed.")
152
+ const flags = u16(filename, view, offset + 8)
153
+ const method = u16(filename, view, offset + 10)
154
+ const crc32 = u32(filename, view, offset + 16)
155
+ const compressedSize = u32(filename, view, offset + 20)
156
+ const uncompressedSize = u32(filename, view, offset + 24)
157
+ const nameLength = u16(filename, view, offset + 28)
158
+ const extraLength = u16(filename, view, offset + 30)
159
+ const commentLength = u16(filename, view, offset + 32)
160
+ const externalAttributes = u32(filename, view, offset + 38)
161
+ const localOffset = u32(filename, view, offset + 42)
162
+ const end = offset + 46 + nameLength + extraLength + commentLength
163
+ if (end > start + size || (flags & 1) !== 0 || ![0, 8].includes(method)) {
164
+ fail(filename, "Wheel ZIP uses an encrypted, unsupported, or truncated entry.")
165
+ }
166
+ const path = safePath(filename, utf8(filename, bytes.subarray(offset + 46, offset + 46 + nameLength)))
167
+ const mode = externalAttributes >>> 16
168
+ if ((mode & 0o170000) === 0o120000) fail(filename, "Wheel ZIP contains a symbolic link.")
169
+ if (paths.has(path)) fail(filename, "Wheel ZIP repeats an archive path.")
170
+ paths.add(path)
171
+ if ([compressedSize, uncompressedSize, localOffset].includes(0xffffffff)) {
172
+ fail(filename, "Wheel ZIP entry requires unsupported ZIP64 fields.")
173
+ }
174
+ entries.push({ path, flags, method, crc32, compressedSize, uncompressedSize, localOffset })
175
+ offset = end
176
+ }
177
+ if (offset !== start + size) fail(filename, "Wheel ZIP central directory has trailing or missing data.")
178
+ return entries
179
+ }
180
+
181
+ const zipContents = (filename: string, archive: Uint8Array, entry: ZipEntry): Uint8Array => {
182
+ if (entry.uncompressedSize > metadataLimit) fail(filename, "Wheel metadata entry exceeds the supported bound.")
183
+ const view = new DataView(archive.buffer, archive.byteOffset, archive.byteLength)
184
+ if (u32(filename, view, entry.localOffset) !== 0x04034b50) fail(filename, "Wheel ZIP local entry is malformed.")
185
+ if (u16(filename, view, entry.localOffset + 6) !== entry.flags ||
186
+ u16(filename, view, entry.localOffset + 8) !== entry.method ||
187
+ u32(filename, view, entry.localOffset + 14) !== entry.crc32 ||
188
+ u32(filename, view, entry.localOffset + 18) !== entry.compressedSize ||
189
+ u32(filename, view, entry.localOffset + 22) !== entry.uncompressedSize) {
190
+ fail(filename, "Wheel ZIP local entry disagrees with its central directory.")
191
+ }
192
+ const nameLength = u16(filename, view, entry.localOffset + 26)
193
+ const extraLength = u16(filename, view, entry.localOffset + 28)
194
+ const start = entry.localOffset + 30 + nameLength + extraLength
195
+ const localPath = safePath(filename, utf8(filename, archive.subarray(entry.localOffset + 30, entry.localOffset + 30 + nameLength)))
196
+ if (localPath !== entry.path) fail(filename, "Wheel ZIP local path disagrees with its central directory.")
197
+ const end = start + entry.compressedSize
198
+ if (end > archive.length) fail(filename, "Wheel ZIP entry bytes are truncated.")
199
+ const compressed = archive.subarray(start, end)
200
+ let result: Uint8Array
201
+ try {
202
+ result = entry.method === 0 ? new Uint8Array(compressed) : new Uint8Array(inflateRawSync(compressed, { maxOutputLength: metadataLimit }))
203
+ } catch {
204
+ return fail(filename, "Wheel ZIP metadata could not be decompressed.")
205
+ }
206
+ if (result.length !== entry.uncompressedSize) fail(filename, "Wheel ZIP metadata size disagrees with its central directory.")
207
+ if (crc32(result) !== entry.crc32) fail(filename, "Wheel ZIP metadata CRC disagrees with its central directory.")
208
+ return result
209
+ }
210
+
211
+ const wheel = (filename: string, bytes: Uint8Array, expectedProject: string, expectedVersion: string): WheelDistribution => {
212
+ const entries = zipEntries(filename, bytes)
213
+ const metadataEntries = entries.filter((entry) => /^[^/]+\.dist-info\/METADATA$/u.test(entry.path))
214
+ if (metadataEntries.length !== 1) fail(filename, "Wheel requires exactly one top-level dist-info/METADATA entry.")
215
+ const metadataEntry = metadataEntries[0]!
216
+ const distInfo = metadataEntry.path.slice(0, -"/METADATA".length)
217
+ const wheelEntry = entries.find((entry) => entry.path === `${distInfo}/WHEEL`)
218
+ if (wheelEntry === undefined) fail(filename, "Wheel requires WHEEL metadata beside core metadata.")
219
+ const metadata = coreMetadata(filename, zipContents(filename, bytes, metadataEntry))
220
+ if (metadata.project !== expectedProject || metadata.version !== expectedVersion) {
221
+ fail(filename, "Wheel embedded project/version disagrees with the resolved publication coordinate.")
222
+ }
223
+ const wheelProject = metadata.project.replaceAll("-", "_")
224
+ const wheelVersion = metadata.version.replaceAll("-", "_")
225
+ if (distInfo !== `${wheelProject}-${wheelVersion}.dist-info`) {
226
+ fail(filename, "Wheel dist-info directory disagrees with embedded project/version metadata.")
227
+ }
228
+ const escaped = (value: string): string => value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&")
229
+ const match = new RegExp(
230
+ `^${escaped(wheelProject)}-${escaped(wheelVersion)}(?:-[0-9][0-9A-Za-z_]*)?-([A-Za-z0-9_.]+)-([A-Za-z0-9_.]+)-([A-Za-z0-9_.]+)\\.whl$`,
231
+ "u"
232
+ ).exec(filename)
233
+ if (match === null) fail(filename, "Wheel filename disagrees with embedded project/version or has malformed compatibility tags.")
234
+ const [pythonTag, abiTag, platformTag] = match!.slice(1) as [string, string, string]
235
+ const expanded = new Set(pythonTag.split(".").flatMap((python) =>
236
+ abiTag.split(".").flatMap((abi) => platformTag.split(".").map((platform) => `${python}-${abi}-${platform}`))))
237
+ const wheelTags = utf8(filename, zipContents(filename, bytes, wheelEntry!)).replaceAll("\r\n", "\n")
238
+ .split("\n").filter((line) => line.startsWith("Tag: ")).map((line) => line.slice(5).trim())
239
+ if (wheelTags.length === 0 || wheelTags.some((tag) => !expanded.has(tag))) {
240
+ fail(filename, "Wheel WHEEL tags do not agree with its filename compatibility tags.")
241
+ }
242
+ return WheelDistribution.make({
243
+ project: PyPiProjectName.make(metadata.project),
244
+ version: Version.make(metadata.version),
245
+ metadataVersion: NonEmptyName.make(metadata.metadataVersion),
246
+ pythonTag: NonEmptyName.make(pythonTag),
247
+ abiTag: NonEmptyName.make(abiTag),
248
+ platformTag: NonEmptyName.make(platformTag),
249
+ mediaType: "application/zip"
250
+ })
251
+ }
252
+
253
+ const tarString = (bytes: Uint8Array): string => {
254
+ const nul = bytes.indexOf(0)
255
+ return new TextDecoder("utf-8", { fatal: true }).decode(nul < 0 ? bytes : bytes.subarray(0, nul))
256
+ }
257
+
258
+ const tarOctal = (filename: string, bytes: Uint8Array): number => {
259
+ const value = tarString(bytes).trim().replace(/^0+/u, "") || "0"
260
+ if (!/^[0-7]+$/u.test(value)) fail(filename, "Source distribution tar contains an invalid octal field.")
261
+ const parsed = Number.parseInt(value, 8)
262
+ if (!Number.isSafeInteger(parsed) || parsed < 0) fail(filename, "Source distribution tar size is out of range.")
263
+ return parsed
264
+ }
265
+
266
+ const pax = (filename: string, bytes: Uint8Array): Readonly<Record<string, string>> => {
267
+ const text = utf8(filename, bytes)
268
+ const values: Record<string, string> = {}
269
+ let offset = 0
270
+ while (offset < text.length) {
271
+ const space = text.indexOf(" ", offset)
272
+ if (space < 0) fail(filename, "Source distribution PAX record is malformed.")
273
+ const length = Number(text.slice(offset, space))
274
+ if (!Number.isSafeInteger(length) || length <= space - offset + 1 || offset + length > text.length || text[offset + length - 1] !== "\n") {
275
+ fail(filename, "Source distribution PAX record has an invalid length.")
276
+ }
277
+ const record = text.slice(space + 1, offset + length - 1)
278
+ const equals = record.indexOf("=")
279
+ if (equals <= 0) fail(filename, "Source distribution PAX record is missing a key.")
280
+ values[record.slice(0, equals)] = record.slice(equals + 1)
281
+ offset += length
282
+ }
283
+ return values
284
+ }
285
+
286
+ const sdist = (filename: string, bytes: Uint8Array, expectedProject: string, expectedVersion: string): SourceDistribution => {
287
+ let tar: Uint8Array
288
+ try { tar = new Uint8Array(gunzipSync(bytes, { maxOutputLength: archiveLimit })) } catch {
289
+ return fail(filename, "Source distribution is not a bounded valid gzip stream.")
290
+ }
291
+ let offset = 0
292
+ let pendingPax: Readonly<Record<string, string>> = {}
293
+ const metadata: Array<{ readonly path: string, readonly bytes: Uint8Array }> = []
294
+ while (offset + 512 <= tar.length) {
295
+ const header = tar.subarray(offset, offset + 512)
296
+ if (header.every((byte) => byte === 0)) {
297
+ if (!tar.subarray(offset).every((byte) => byte === 0)) fail(filename, "Source distribution tar has nonzero data after its end marker.")
298
+ break
299
+ }
300
+ let checksum = 0
301
+ for (let index = 0; index < 512; index += 1) checksum += index >= 148 && index < 156 ? 32 : header[index]!
302
+ if (checksum !== tarOctal(filename, header.subarray(148, 156))) fail(filename, "Source distribution tar header checksum is invalid.")
303
+ const size = tarOctal(filename, header.subarray(124, 136))
304
+ const dataStart = offset + 512
305
+ const dataEnd = dataStart + size
306
+ if (dataEnd > tar.length) fail(filename, "Source distribution tar entry is truncated.")
307
+ const type = String.fromCharCode(header[156]!)
308
+ const rawName = tarString(header.subarray(0, 100))
309
+ const prefix = tarString(header.subarray(345, 500))
310
+ const rawPath = prefix.length === 0 ? rawName : `${prefix}/${rawName}`
311
+ if (type === "x") {
312
+ pendingPax = pax(filename, tar.subarray(dataStart, dataEnd))
313
+ } else {
314
+ const path = safePath(filename, pendingPax.path ?? rawPath)
315
+ pendingPax = {}
316
+ if (type === "1" || type === "2") fail(filename, "Source distribution tar contains a hard or symbolic link.")
317
+ if (!["\0", "0", "5"].includes(type)) fail(filename, "Source distribution tar contains an unsupported entry type.")
318
+ if ((type === "\0" || type === "0") && /\/PKG-INFO$/u.test(path)) {
319
+ if (size > metadataLimit) fail(filename, "Source distribution PKG-INFO exceeds the supported bound.")
320
+ metadata.push({ path, bytes: tar.subarray(dataStart, dataEnd) })
321
+ }
322
+ }
323
+ offset = dataStart + Math.ceil(size / 512) * 512
324
+ }
325
+ if (metadata.length !== 1 || metadata[0]!.path.split("/").length !== 2) {
326
+ fail(filename, "Source distribution requires exactly one root-directory PKG-INFO entry.")
327
+ }
328
+ const parsed = coreMetadata(filename, metadata[0]!.bytes)
329
+ if (parsed.project !== expectedProject || parsed.version !== expectedVersion) {
330
+ fail(filename, "Source distribution embedded project/version disagrees with the resolved publication coordinate.")
331
+ }
332
+ const suffix = `-${parsed.version}.tar.gz`
333
+ if (!filename.endsWith(suffix) || normalizePyPiProjectName(filename.slice(0, -suffix.length)) !== parsed.project) {
334
+ fail(filename, "Source distribution filename disagrees with embedded project/version metadata.")
335
+ }
336
+ const root = metadata[0]!.path.split("/")[0]!
337
+ if (!root.endsWith(`-${parsed.version}`) || normalizePyPiProjectName(root.slice(0, -(`-${parsed.version}`).length)) !== parsed.project) {
338
+ fail(filename, "Source distribution root directory disagrees with embedded project/version metadata.")
339
+ }
340
+ return SourceDistribution.make({
341
+ project: PyPiProjectName.make(parsed.project),
342
+ version: Version.make(parsed.version),
343
+ metadataVersion: NonEmptyName.make(parsed.metadataVersion),
344
+ pythonTag: "source",
345
+ mediaType: "application/gzip"
346
+ })
347
+ }
348
+
349
+ /** Strictly validate prebuilt distribution bytes against resolved identity. */
350
+ export const inspectPythonDistribution = (
351
+ filename: string,
352
+ bytes: Uint8Array,
353
+ expectedProject: string,
354
+ expectedVersion: string
355
+ ): PythonDistribution => {
356
+ if (filename.includes("/") || filename.includes("\\") || filename.length === 0) fail(filename || "<empty>", "Distribution filename must be a basename.")
357
+ if (filename.endsWith(".whl")) return wheel(filename, bytes, expectedProject, expectedVersion)
358
+ if (filename.endsWith(".tar.gz")) return sdist(filename, bytes, expectedProject, expectedVersion)
359
+ return fail(filename, "Only .whl and .tar.gz source distributions are supported.")
360
+ }
@@ -0,0 +1,11 @@
1
+ // The one home for token-shaped denylist patterns. Load-bearing for child
2
+ // output redaction and shipped-plugin checks.
3
+ export const secretPatterns: ReadonlyArray<RegExp> = [
4
+ /ghp_[A-Za-z0-9]{20,}/u,
5
+ /gho_[A-Za-z0-9]{20,}/u,
6
+ /github_pat_[A-Za-z0-9_]{20,}/u,
7
+ /xox[abps]-[A-Za-z0-9-]{10,}/u,
8
+ /AKIA[0-9A-Z]{16}/u,
9
+ /npm_[A-Za-z0-9]{30,}/u,
10
+ /-----BEGIN [A-Z ]*PRIVATE KEY/u
11
+ ]
@@ -0,0 +1,38 @@
1
+ import * as BunChildProcessSpawner from "@effect/platform-bun/BunChildProcessSpawner"
2
+ import * as BunFileSystem from "@effect/platform-bun/BunFileSystem"
3
+ import * as BunHttpClient from "@effect/platform-bun/BunHttpClient"
4
+ import * as BunPath from "@effect/platform-bun/BunPath"
5
+ import * as Layer from "effect/Layer"
6
+ import { join } from "node:path"
7
+ import type { ReleaseApiLayer } from "../api/types.js"
8
+ import { SourceObserverLive } from "./source-observer.js"
9
+ import { makeReleaseServicesLive } from "./services.js"
10
+ import {
11
+ makeLocalPreparedReleaseStore,
12
+ type PreparedReleaseStoreShape
13
+ } from "../release/prepared-store.js"
14
+ import type { PublicationClaimStoreShape } from "../publication/claim.js"
15
+
16
+ const bunHost = Layer.mergeAll(
17
+ BunChildProcessSpawner.layer.pipe(Layer.provide(Layer.mergeAll(
18
+ BunFileSystem.layer,
19
+ BunPath.layer
20
+ ))),
21
+ BunHttpClient.layer,
22
+ SourceObserverLive
23
+ )
24
+
25
+ /** A custom Bun host takes one already-selected durable store service. */
26
+ export const makeBunReleaseLayer = (
27
+ preparedStore: PreparedReleaseStoreShape,
28
+ publicationClaimStore?: PublicationClaimStoreShape
29
+ ): ReleaseApiLayer => makeReleaseServicesLive(preparedStore, publicationClaimStore).pipe(Layer.provide(bunHost))
30
+
31
+ const defaultBunStore = makeLocalPreparedReleaseStore(join(
32
+ process.cwd(),
33
+ ".release",
34
+ "ts-release",
35
+ "prepared"
36
+ ))
37
+
38
+ export const BunReleaseLayer: ReleaseApiLayer = makeBunReleaseLayer(defaultBunStore)