@mannyc1/ts-release 0.0.7 → 0.3.0

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 (695) hide show
  1. package/ARCHITECTURE.md +184 -92
  2. package/CHANGELOG.md +197 -0
  3. package/LICENSE +21 -0
  4. package/README.md +404 -327
  5. package/SPEC.md +257 -310
  6. package/apps/release-ts/README.md +39 -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 +122 -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 +39346 -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 +9 -0
  82. package/dist/drivers/archive.d.ts.map +1 -0
  83. package/dist/drivers/archive.js +105 -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/python-wheel.d.ts +21 -0
  106. package/dist/drivers/python-wheel.d.ts.map +1 -0
  107. package/dist/drivers/python-wheel.js +109 -0
  108. package/dist/drivers/python-wheel.js.map +1 -0
  109. package/dist/drivers/redact.d.ts +4 -0
  110. package/dist/drivers/redact.d.ts.map +1 -0
  111. package/dist/drivers/redact.js +24 -0
  112. package/dist/drivers/redact.js.map +1 -0
  113. package/dist/drivers/seccomp-helper-source.d.ts +7 -0
  114. package/dist/drivers/seccomp-helper-source.d.ts.map +1 -0
  115. package/dist/drivers/seccomp-helper-source.js +121 -0
  116. package/dist/drivers/seccomp-helper-source.js.map +1 -0
  117. package/dist/drivers/utils.d.ts +4 -0
  118. package/dist/drivers/utils.d.ts.map +1 -0
  119. package/dist/drivers/utils.js +5 -0
  120. package/dist/drivers/utils.js.map +1 -0
  121. package/dist/drivers/workspace.d.ts +9 -0
  122. package/dist/drivers/workspace.d.ts.map +1 -0
  123. package/dist/drivers/workspace.js +53 -0
  124. package/dist/drivers/workspace.js.map +1 -0
  125. package/dist/extensions/provider-adapter.d.ts +48 -0
  126. package/dist/extensions/provider-adapter.d.ts.map +1 -0
  127. package/dist/extensions/provider-adapter.js +64 -0
  128. package/dist/extensions/provider-adapter.js.map +1 -0
  129. package/dist/host.d.ts +33 -0
  130. package/dist/host.d.ts.map +1 -0
  131. package/dist/host.js +20 -0
  132. package/dist/host.js.map +1 -0
  133. package/dist/index.d.ts +19 -1
  134. package/dist/index.d.ts.map +1 -1
  135. package/dist/index.js +12 -1
  136. package/dist/index.js.map +1 -1
  137. package/dist/model/artifact-collection.d.ts +84 -0
  138. package/dist/model/artifact-collection.d.ts.map +1 -0
  139. package/dist/model/artifact-collection.js +185 -0
  140. package/dist/model/artifact-collection.js.map +1 -0
  141. package/dist/model/authority.d.ts +89 -0
  142. package/dist/model/authority.d.ts.map +1 -0
  143. package/dist/model/authority.js +80 -0
  144. package/dist/model/authority.js.map +1 -0
  145. package/dist/model/bun-targets.d.ts +34 -0
  146. package/dist/model/bun-targets.d.ts.map +1 -0
  147. package/dist/model/bun-targets.js +17 -0
  148. package/dist/model/bun-targets.js.map +1 -0
  149. package/dist/model/canonical.d.ts +8 -0
  150. package/dist/model/canonical.d.ts.map +1 -0
  151. package/dist/model/canonical.js +205 -0
  152. package/dist/model/canonical.js.map +1 -0
  153. package/dist/model/catalog.d.ts +76 -0
  154. package/dist/model/catalog.d.ts.map +1 -0
  155. package/dist/model/catalog.js +174 -0
  156. package/dist/model/catalog.js.map +1 -0
  157. package/dist/model/digest.d.ts +53 -0
  158. package/dist/model/digest.d.ts.map +1 -0
  159. package/dist/model/digest.js +127 -0
  160. package/dist/model/digest.js.map +1 -0
  161. package/dist/model/errors.d.ts +14 -0
  162. package/dist/model/errors.d.ts.map +1 -0
  163. package/dist/model/errors.js +8 -0
  164. package/dist/model/errors.js.map +1 -0
  165. package/dist/model/primitives.d.ts +19 -0
  166. package/dist/model/primitives.d.ts.map +1 -0
  167. package/dist/model/primitives.js +18 -0
  168. package/dist/model/primitives.js.map +1 -0
  169. package/dist/model/pypi.d.ts +12 -0
  170. package/dist/model/pypi.d.ts.map +1 -0
  171. package/dist/model/pypi.js +20 -0
  172. package/dist/model/pypi.js.map +1 -0
  173. package/dist/model/python-distribution.d.ts +33 -0
  174. package/dist/model/python-distribution.d.ts.map +1 -0
  175. package/dist/model/python-distribution.js +367 -0
  176. package/dist/model/python-distribution.js.map +1 -0
  177. package/dist/model/secret-patterns.d.ts +2 -0
  178. package/dist/model/secret-patterns.d.ts.map +1 -0
  179. package/dist/model/secret-patterns.js +12 -0
  180. package/dist/model/secret-patterns.js.map +1 -0
  181. package/dist/operation-journal/authority.d.ts +3 -0
  182. package/dist/operation-journal/authority.d.ts.map +1 -0
  183. package/dist/operation-journal/authority.js +147 -0
  184. package/dist/operation-journal/authority.js.map +1 -0
  185. package/dist/operation-journal/aws/deadline.d.ts +12 -0
  186. package/dist/operation-journal/aws/deadline.d.ts.map +1 -0
  187. package/dist/operation-journal/aws/deadline.js +38 -0
  188. package/dist/operation-journal/aws/deadline.js.map +1 -0
  189. package/dist/operation-journal/aws/oidc.d.ts +27 -0
  190. package/dist/operation-journal/aws/oidc.d.ts.map +1 -0
  191. package/dist/operation-journal/aws/oidc.js +361 -0
  192. package/dist/operation-journal/aws/oidc.js.map +1 -0
  193. package/dist/operation-journal/aws/policy.d.ts +42 -0
  194. package/dist/operation-journal/aws/policy.d.ts.map +1 -0
  195. package/dist/operation-journal/aws/policy.js +404 -0
  196. package/dist/operation-journal/aws/policy.js.map +1 -0
  197. package/dist/operation-journal/aws/s3-boundary.d.ts +17 -0
  198. package/dist/operation-journal/aws/s3-boundary.d.ts.map +1 -0
  199. package/dist/operation-journal/aws/s3-boundary.js +417 -0
  200. package/dist/operation-journal/aws/s3-boundary.js.map +1 -0
  201. package/dist/operation-journal/aws.d.ts +11 -0
  202. package/dist/operation-journal/aws.d.ts.map +1 -0
  203. package/dist/operation-journal/aws.js +50 -0
  204. package/dist/operation-journal/aws.js.map +1 -0
  205. package/dist/operation-journal/canonical.d.ts +52 -0
  206. package/dist/operation-journal/canonical.d.ts.map +1 -0
  207. package/dist/operation-journal/canonical.js +282 -0
  208. package/dist/operation-journal/canonical.js.map +1 -0
  209. package/dist/operation-journal/model.d.ts +251 -0
  210. package/dist/operation-journal/model.d.ts.map +1 -0
  211. package/dist/operation-journal/model.js +56 -0
  212. package/dist/operation-journal/model.js.map +1 -0
  213. package/dist/operation-journal/reducer.d.ts +28 -0
  214. package/dist/operation-journal/reducer.d.ts.map +1 -0
  215. package/dist/operation-journal/reducer.js +73 -0
  216. package/dist/operation-journal/reducer.js.map +1 -0
  217. package/dist/operation-journal/s3.d.ts +7 -0
  218. package/dist/operation-journal/s3.d.ts.map +1 -0
  219. package/dist/operation-journal/s3.js +667 -0
  220. package/dist/operation-journal/s3.js.map +1 -0
  221. package/dist/operation-journal.d.ts +14 -0
  222. package/dist/operation-journal.d.ts.map +1 -0
  223. package/dist/operation-journal.js +12 -0
  224. package/dist/operation-journal.js.map +1 -0
  225. package/dist/platform/bun.d.ts +7 -0
  226. package/dist/platform/bun.d.ts.map +1 -0
  227. package/dist/platform/bun.js +15 -0
  228. package/dist/platform/bun.js.map +1 -0
  229. package/dist/platform/credentials.d.ts +32 -0
  230. package/dist/platform/credentials.d.ts.map +1 -0
  231. package/dist/platform/credentials.js +834 -0
  232. package/dist/platform/credentials.js.map +1 -0
  233. package/dist/platform/host-support.d.ts +2 -0
  234. package/dist/platform/host-support.d.ts.map +1 -0
  235. package/dist/platform/host-support.js +4 -0
  236. package/dist/platform/host-support.js.map +1 -0
  237. package/dist/platform/node.d.ts +7 -0
  238. package/dist/platform/node.d.ts.map +1 -0
  239. package/dist/platform/node.js +15 -0
  240. package/dist/platform/node.js.map +1 -0
  241. package/dist/platform/release-runtime.d.ts +11 -0
  242. package/dist/platform/release-runtime.d.ts.map +1 -0
  243. package/dist/platform/release-runtime.js +34 -0
  244. package/dist/platform/release-runtime.js.map +1 -0
  245. package/dist/platform/services.d.ts +15 -0
  246. package/dist/platform/services.d.ts.map +1 -0
  247. package/dist/platform/services.js +30 -0
  248. package/dist/platform/services.js.map +1 -0
  249. package/dist/platform/source-observer.d.ts +5 -0
  250. package/dist/platform/source-observer.d.ts.map +1 -0
  251. package/dist/platform/source-observer.js +159 -0
  252. package/dist/platform/source-observer.js.map +1 -0
  253. package/dist/provider-sdk.d.ts +14 -0
  254. package/dist/provider-sdk.d.ts.map +1 -0
  255. package/dist/provider-sdk.js +10 -0
  256. package/dist/provider-sdk.js.map +1 -0
  257. package/dist/publication/adapter.d.ts +212 -0
  258. package/dist/publication/adapter.d.ts.map +1 -0
  259. package/dist/publication/adapter.js +83 -0
  260. package/dist/publication/adapter.js.map +1 -0
  261. package/dist/publication/authority.d.ts +137 -0
  262. package/dist/publication/authority.d.ts.map +1 -0
  263. package/dist/publication/authority.js +233 -0
  264. package/dist/publication/authority.js.map +1 -0
  265. package/dist/publication/catalog-git.d.ts +37 -0
  266. package/dist/publication/catalog-git.d.ts.map +1 -0
  267. package/dist/publication/catalog-git.js +451 -0
  268. package/dist/publication/catalog-git.js.map +1 -0
  269. package/dist/publication/claim.d.ts +39 -0
  270. package/dist/publication/claim.d.ts.map +1 -0
  271. package/dist/publication/claim.js +31 -0
  272. package/dist/publication/claim.js.map +1 -0
  273. package/dist/publication/coordinator.d.ts +246 -0
  274. package/dist/publication/coordinator.d.ts.map +1 -0
  275. package/dist/publication/coordinator.js +370 -0
  276. package/dist/publication/coordinator.js.map +1 -0
  277. package/dist/publication/github.d.ts +36 -0
  278. package/dist/publication/github.d.ts.map +1 -0
  279. package/dist/publication/github.js +695 -0
  280. package/dist/publication/github.js.map +1 -0
  281. package/dist/publication/http.d.ts +69 -0
  282. package/dist/publication/http.d.ts.map +1 -0
  283. package/dist/publication/http.js +29 -0
  284. package/dist/publication/http.js.map +1 -0
  285. package/dist/publication/index.d.ts +5 -0
  286. package/dist/publication/index.d.ts.map +1 -0
  287. package/dist/publication/index.js +5 -0
  288. package/dist/publication/index.js.map +1 -0
  289. package/dist/publication/npm.d.ts +40 -0
  290. package/dist/publication/npm.d.ts.map +1 -0
  291. package/dist/publication/npm.js +359 -0
  292. package/dist/publication/npm.js.map +1 -0
  293. package/dist/publication/profiles.d.ts +136 -0
  294. package/dist/publication/profiles.d.ts.map +1 -0
  295. package/dist/publication/profiles.js +90 -0
  296. package/dist/publication/profiles.js.map +1 -0
  297. package/dist/publication/publisher.d.ts +82 -0
  298. package/dist/publication/publisher.d.ts.map +1 -0
  299. package/dist/publication/publisher.js +53 -0
  300. package/dist/publication/publisher.js.map +1 -0
  301. package/dist/publication/pypi.d.ts +45 -0
  302. package/dist/publication/pypi.d.ts.map +1 -0
  303. package/dist/publication/pypi.js +369 -0
  304. package/dist/publication/pypi.js.map +1 -0
  305. package/dist/publication/recovery.d.ts +663 -0
  306. package/dist/publication/recovery.d.ts.map +1 -0
  307. package/dist/publication/recovery.js +252 -0
  308. package/dist/publication/recovery.js.map +1 -0
  309. package/dist/publication/report.d.ts +1061 -0
  310. package/dist/publication/report.d.ts.map +1 -0
  311. package/dist/publication/report.js +441 -0
  312. package/dist/publication/report.js.map +1 -0
  313. package/dist/recipes/config.d.ts +296 -0
  314. package/dist/recipes/config.d.ts.map +1 -0
  315. package/dist/recipes/config.js +325 -0
  316. package/dist/recipes/config.js.map +1 -0
  317. package/dist/release/capabilities.d.ts +12 -0
  318. package/dist/release/capabilities.d.ts.map +1 -0
  319. package/dist/release/capabilities.js +395 -0
  320. package/dist/release/capabilities.js.map +1 -0
  321. package/dist/release/compiler.d.ts +5 -0
  322. package/dist/release/compiler.d.ts.map +1 -0
  323. package/dist/release/compiler.js +19 -0
  324. package/dist/release/compiler.js.map +1 -0
  325. package/dist/release/config.d.ts +5 -0
  326. package/dist/release/config.d.ts.map +1 -0
  327. package/dist/release/config.js +10 -0
  328. package/dist/release/config.js.map +1 -0
  329. package/dist/release/context.d.ts +96 -0
  330. package/dist/release/context.d.ts.map +1 -0
  331. package/dist/release/context.js +168 -0
  332. package/dist/release/context.js.map +1 -0
  333. package/dist/release/graph.d.ts +271 -0
  334. package/dist/release/graph.d.ts.map +1 -0
  335. package/dist/release/graph.js +766 -0
  336. package/dist/release/graph.js.map +1 -0
  337. package/dist/release/inspect.d.ts +88 -0
  338. package/dist/release/inspect.d.ts.map +1 -0
  339. package/dist/release/inspect.js +75 -0
  340. package/dist/release/inspect.js.map +1 -0
  341. package/dist/release/prepare.d.ts +24 -0
  342. package/dist/release/prepare.d.ts.map +1 -0
  343. package/dist/release/prepare.js +1115 -0
  344. package/dist/release/prepare.js.map +1 -0
  345. package/dist/release/prepared-ref.d.ts +60 -0
  346. package/dist/release/prepared-ref.d.ts.map +1 -0
  347. package/dist/release/prepared-ref.js +131 -0
  348. package/dist/release/prepared-ref.js.map +1 -0
  349. package/dist/release/prepared-store.d.ts +90 -0
  350. package/dist/release/prepared-store.d.ts.map +1 -0
  351. package/dist/release/prepared-store.js +339 -0
  352. package/dist/release/prepared-store.js.map +1 -0
  353. package/dist/release/prepared.d.ts +172 -0
  354. package/dist/release/prepared.d.ts.map +1 -0
  355. package/dist/release/prepared.js +268 -0
  356. package/dist/release/prepared.js.map +1 -0
  357. package/dist/release/staging.d.ts +31 -0
  358. package/dist/release/staging.d.ts.map +1 -0
  359. package/dist/release/staging.js +218 -0
  360. package/dist/release/staging.js.map +1 -0
  361. package/dist/resolve/authored.d.ts +53 -0
  362. package/dist/resolve/authored.d.ts.map +1 -0
  363. package/dist/resolve/authored.js +55 -0
  364. package/dist/resolve/authored.js.map +1 -0
  365. package/dist/resolve/encode.d.ts +3 -0
  366. package/dist/resolve/encode.d.ts.map +1 -0
  367. package/dist/resolve/encode.js +21 -0
  368. package/dist/resolve/encode.js.map +1 -0
  369. package/dist/resolve/errors.d.ts +7 -0
  370. package/dist/resolve/errors.d.ts.map +1 -0
  371. package/dist/resolve/errors.js +17 -0
  372. package/dist/resolve/errors.js.map +1 -0
  373. package/dist/resolve/facts.d.ts +12 -0
  374. package/dist/resolve/facts.d.ts.map +1 -0
  375. package/dist/resolve/facts.js +18 -0
  376. package/dist/resolve/facts.js.map +1 -0
  377. package/dist/resolve/resolve.d.ts +10 -0
  378. package/dist/resolve/resolve.d.ts.map +1 -0
  379. package/dist/resolve/resolve.js +242 -0
  380. package/dist/resolve/resolve.js.map +1 -0
  381. package/dist/store.d.ts +11 -0
  382. package/dist/store.d.ts.map +1 -0
  383. package/dist/store.js +9 -0
  384. package/dist/store.js.map +1 -0
  385. package/examples/README.md +20 -30
  386. package/examples/github-release/release.config.json +11 -18
  387. package/examples/homebrew-tap/README.md +11 -0
  388. package/examples/homebrew-tap/release.config.json +40 -28
  389. package/examples/multi-target/release.config.json +28 -53
  390. package/examples/npm-first-publish/release.config.json +23 -25
  391. package/examples/npm-only/release.config.json +22 -30
  392. package/examples/portable-cli/README.md +17 -0
  393. package/examples/portable-cli/artifacts/portable-example-0.1.0-darwin-arm64 +1 -0
  394. package/examples/portable-cli/artifacts/portable-example-0.1.0-darwin-x64 +1 -0
  395. package/examples/portable-cli/artifacts/portable-example-0.1.0-linux-arm64 +1 -0
  396. package/examples/portable-cli/artifacts/portable-example-0.1.0-linux-x64 +1 -0
  397. package/examples/portable-cli/artifacts/portable-example-0.1.0-windows-x64.exe +1 -0
  398. package/examples/portable-cli/artifacts/portable_example-0.1.0-py3-none-macosx_10_15_x86_64.whl +1 -0
  399. package/examples/portable-cli/artifacts/portable_example-0.1.0-py3-none-macosx_11_0_arm64.whl +1 -0
  400. package/examples/portable-cli/artifacts/portable_example-0.1.0-py3-none-manylinux2014_aarch64.whl +1 -0
  401. package/examples/portable-cli/artifacts/portable_example-0.1.0-py3-none-manylinux2014_x86_64.whl +1 -0
  402. package/examples/portable-cli/artifacts/portable_example-0.1.0-py3-none-win_amd64.whl +1 -0
  403. package/examples/portable-cli/package.json +9 -0
  404. package/examples/portable-cli/release.config.json +53 -0
  405. package/examples/portable-cli/src/cli.ts +3 -0
  406. package/examples/pypi-registry/README.md +8 -0
  407. package/examples/scoop-bucket/README.md +10 -0
  408. package/examples/scoop-bucket/release.config.json +40 -30
  409. package/package.json +73 -154
  410. package/src/api/api.ts +365 -0
  411. package/src/api/errors.ts +36 -0
  412. package/src/api/input.ts +92 -0
  413. package/src/api/runtime.ts +14 -0
  414. package/src/api/types.ts +103 -0
  415. package/src/capabilities/bun-targets.ts +2 -0
  416. package/src/capabilities/field-ownership.ts +60 -0
  417. package/src/capabilities/module.ts +158 -0
  418. package/src/capabilities/registry.ts +333 -0
  419. package/src/config/config.ts +48 -0
  420. package/src/correction/coordinator.ts +336 -0
  421. package/src/correction/index.ts +2 -0
  422. package/src/correction/intent.ts +172 -0
  423. package/src/drivers/archive.ts +111 -0
  424. package/src/drivers/contain.ts +20 -0
  425. package/src/drivers/environment.ts +28 -0
  426. package/src/drivers/errors.ts +6 -0
  427. package/src/drivers/glob.ts +137 -0
  428. package/src/drivers/process.ts +339 -0
  429. package/src/drivers/python-wheel.ts +145 -0
  430. package/src/drivers/redact.ts +31 -0
  431. package/src/drivers/seccomp-helper-source.ts +121 -0
  432. package/src/drivers/utils.ts +10 -0
  433. package/src/drivers/workspace.ts +46 -0
  434. package/src/extensions/provider-adapter.ts +99 -0
  435. package/src/host.ts +140 -0
  436. package/src/index.ts +64 -0
  437. package/src/model/artifact-collection.ts +237 -0
  438. package/src/model/authority.ts +116 -0
  439. package/src/model/bun-targets.ts +34 -0
  440. package/src/model/canonical.ts +205 -0
  441. package/src/model/catalog.ts +220 -0
  442. package/src/model/digest.ts +172 -0
  443. package/src/model/errors.ts +6 -0
  444. package/src/model/primitives.ts +37 -0
  445. package/src/model/pypi.ts +30 -0
  446. package/src/model/python-distribution.ts +360 -0
  447. package/src/model/secret-patterns.ts +11 -0
  448. package/src/operation-journal/authority.ts +162 -0
  449. package/src/operation-journal/aws/deadline.ts +41 -0
  450. package/src/operation-journal/aws/oidc.ts +439 -0
  451. package/src/operation-journal/aws/policy.ts +491 -0
  452. package/src/operation-journal/aws/s3-boundary.ts +562 -0
  453. package/src/operation-journal/aws.ts +60 -0
  454. package/src/operation-journal/canonical.ts +373 -0
  455. package/src/operation-journal/model.ts +301 -0
  456. package/src/operation-journal/reducer.ts +112 -0
  457. package/src/operation-journal/s3.ts +884 -0
  458. package/src/operation-journal.ts +51 -0
  459. package/src/platform/bun.ts +38 -0
  460. package/src/platform/credentials.ts +1151 -0
  461. package/src/platform/host-support.ts +4 -0
  462. package/src/platform/node.ts +38 -0
  463. package/src/platform/release-runtime.ts +47 -0
  464. package/src/platform/services.ts +57 -0
  465. package/src/platform/source-observer.ts +193 -0
  466. package/src/provider-sdk.ts +48 -0
  467. package/src/publication/adapter.ts +132 -0
  468. package/src/publication/authority.ts +397 -0
  469. package/src/publication/catalog-git.ts +603 -0
  470. package/src/publication/claim.ts +51 -0
  471. package/src/publication/coordinator.ts +578 -0
  472. package/src/publication/github.ts +1022 -0
  473. package/src/publication/http.ts +101 -0
  474. package/src/publication/index.ts +4 -0
  475. package/src/publication/npm.ts +525 -0
  476. package/src/publication/profiles.ts +94 -0
  477. package/src/publication/publisher.ts +130 -0
  478. package/src/publication/pypi.ts +463 -0
  479. package/src/publication/recovery.ts +349 -0
  480. package/src/publication/report.ts +628 -0
  481. package/src/recipes/config.ts +395 -0
  482. package/src/release/capabilities.ts +460 -0
  483. package/src/release/compiler.ts +28 -0
  484. package/src/release/config.ts +12 -0
  485. package/src/release/context.ts +223 -0
  486. package/src/release/graph.ts +866 -0
  487. package/src/release/inspect.ts +83 -0
  488. package/src/release/prepare.ts +1329 -0
  489. package/src/release/prepared-ref.ts +193 -0
  490. package/src/release/prepared-store.ts +378 -0
  491. package/src/release/prepared.ts +299 -0
  492. package/src/release/staging.ts +257 -0
  493. package/src/resolve/authored.ts +64 -0
  494. package/src/resolve/encode.ts +22 -0
  495. package/src/resolve/errors.ts +15 -0
  496. package/src/resolve/facts.ts +18 -0
  497. package/src/resolve/resolve.ts +328 -0
  498. package/src/store.ts +28 -0
  499. package/templates/README.md +55 -72
  500. package/templates/bun-cli-github/README.md +7 -9
  501. package/templates/bun-cli-github/release.config.json +35 -73
  502. package/templates/github-actions/release.yml +74 -0
  503. package/templates/github-actions/reviewed-release.yml +115 -0
  504. package/templates/multi-target-homebrew/README.md +10 -0
  505. package/templates/multi-target-homebrew/release.config.json +43 -60
  506. package/templates/multi-target-scoop/README.md +10 -0
  507. package/templates/multi-target-scoop/release.config.json +43 -62
  508. package/templates/npm-github/release.config.json +25 -38
  509. package/templates/npm-github/reviewed-release.config.json +37 -0
  510. package/templates/npm-only/README.md +10 -0
  511. package/templates/npm-only/release.config.json +15 -30
  512. package/templates/portable-cli/README.md +13 -0
  513. package/templates/portable-cli/release.config.json +53 -0
  514. package/dist/artifacts/adapter.d.ts +0 -39
  515. package/dist/artifacts/adapter.d.ts.map +0 -1
  516. package/dist/artifacts/adapter.js +0 -23
  517. package/dist/artifacts/adapter.js.map +0 -1
  518. package/dist/artifacts/registry.d.ts +0 -21
  519. package/dist/artifacts/registry.d.ts.map +0 -1
  520. package/dist/artifacts/registry.js +0 -21
  521. package/dist/artifacts/registry.js.map +0 -1
  522. package/dist/config/errors.d.ts +0 -24
  523. package/dist/config/errors.d.ts.map +0 -1
  524. package/dist/config/errors.js +0 -19
  525. package/dist/config/errors.js.map +0 -1
  526. package/dist/config/load.d.ts +0 -9
  527. package/dist/config/load.d.ts.map +0 -1
  528. package/dist/config/load.js +0 -29
  529. package/dist/config/load.js.map +0 -1
  530. package/dist/config/schema.d.ts +0 -12
  531. package/dist/config/schema.d.ts.map +0 -1
  532. package/dist/config/schema.js +0 -19
  533. package/dist/config/schema.js.map +0 -1
  534. package/dist/domain/artifact.d.ts +0 -118
  535. package/dist/domain/artifact.d.ts.map +0 -1
  536. package/dist/domain/artifact.js +0 -197
  537. package/dist/domain/artifact.js.map +0 -1
  538. package/dist/domain/evidence.d.ts +0 -59
  539. package/dist/domain/evidence.d.ts.map +0 -1
  540. package/dist/domain/evidence.js +0 -51
  541. package/dist/domain/evidence.js.map +0 -1
  542. package/dist/domain/operation.d.ts +0 -143
  543. package/dist/domain/operation.d.ts.map +0 -1
  544. package/dist/domain/operation.js +0 -198
  545. package/dist/domain/operation.js.map +0 -1
  546. package/dist/domain/release.d.ts +0 -93
  547. package/dist/domain/release.d.ts.map +0 -1
  548. package/dist/domain/release.js +0 -82
  549. package/dist/domain/release.js.map +0 -1
  550. package/dist/domain/remote-state.d.ts +0 -58
  551. package/dist/domain/remote-state.d.ts.map +0 -1
  552. package/dist/domain/remote-state.js +0 -55
  553. package/dist/domain/remote-state.js.map +0 -1
  554. package/dist/domain/target.d.ts +0 -148
  555. package/dist/domain/target.d.ts.map +0 -1
  556. package/dist/domain/target.js +0 -151
  557. package/dist/domain/target.js.map +0 -1
  558. package/dist/host/host.d.ts +0 -32
  559. package/dist/host/host.d.ts.map +0 -1
  560. package/dist/host/host.js +0 -24
  561. package/dist/host/host.js.map +0 -1
  562. package/dist/host/http-live.d.ts +0 -6
  563. package/dist/host/http-live.d.ts.map +0 -1
  564. package/dist/host/http-live.js +0 -86
  565. package/dist/host/http-live.js.map +0 -1
  566. package/dist/host/http.d.ts +0 -43
  567. package/dist/host/http.d.ts.map +0 -1
  568. package/dist/host/http.js +0 -59
  569. package/dist/host/http.js.map +0 -1
  570. package/dist/host/platform.d.ts +0 -10
  571. package/dist/host/platform.d.ts.map +0 -1
  572. package/dist/host/platform.js +0 -114
  573. package/dist/host/platform.js.map +0 -1
  574. package/dist/host/test.d.ts +0 -23
  575. package/dist/host/test.d.ts.map +0 -1
  576. package/dist/host/test.js +0 -222
  577. package/dist/host/test.js.map +0 -1
  578. package/dist/internal/workspace-path.d.ts +0 -15
  579. package/dist/internal/workspace-path.d.ts.map +0 -1
  580. package/dist/internal/workspace-path.js +0 -36
  581. package/dist/internal/workspace-path.js.map +0 -1
  582. package/dist/planner/artifact-inventory.d.ts +0 -9
  583. package/dist/planner/artifact-inventory.d.ts.map +0 -1
  584. package/dist/planner/artifact-inventory.js +0 -86
  585. package/dist/planner/artifact-inventory.js.map +0 -1
  586. package/dist/planner/create-release-plan.d.ts +0 -5
  587. package/dist/planner/create-release-plan.d.ts.map +0 -1
  588. package/dist/planner/create-release-plan.js +0 -25
  589. package/dist/planner/create-release-plan.js.map +0 -1
  590. package/dist/planner/errors.d.ts +0 -67
  591. package/dist/planner/errors.d.ts.map +0 -1
  592. package/dist/planner/errors.js +0 -58
  593. package/dist/planner/errors.js.map +0 -1
  594. package/dist/planner/evidence-recorder.d.ts +0 -28
  595. package/dist/planner/evidence-recorder.d.ts.map +0 -1
  596. package/dist/planner/evidence-recorder.js +0 -362
  597. package/dist/planner/evidence-recorder.js.map +0 -1
  598. package/dist/planner/executor.d.ts +0 -58
  599. package/dist/planner/executor.d.ts.map +0 -1
  600. package/dist/planner/executor.js +0 -147
  601. package/dist/planner/executor.js.map +0 -1
  602. package/dist/planner/normalize-release.d.ts +0 -19
  603. package/dist/planner/normalize-release.d.ts.map +0 -1
  604. package/dist/planner/normalize-release.js +0 -342
  605. package/dist/planner/normalize-release.js.map +0 -1
  606. package/dist/planner/reconcile.d.ts +0 -17
  607. package/dist/planner/reconcile.d.ts.map +0 -1
  608. package/dist/planner/reconcile.js +0 -259
  609. package/dist/planner/reconcile.js.map +0 -1
  610. package/dist/planner/render-plan.d.ts +0 -15
  611. package/dist/planner/render-plan.d.ts.map +0 -1
  612. package/dist/planner/render-plan.js +0 -231
  613. package/dist/planner/render-plan.js.map +0 -1
  614. package/dist/targets/adapter-helpers.d.ts +0 -79
  615. package/dist/targets/adapter-helpers.d.ts.map +0 -1
  616. package/dist/targets/adapter-helpers.js +0 -194
  617. package/dist/targets/adapter-helpers.js.map +0 -1
  618. package/dist/targets/adapter.d.ts +0 -17
  619. package/dist/targets/adapter.d.ts.map +0 -1
  620. package/dist/targets/adapter.js +0 -2
  621. package/dist/targets/adapter.js.map +0 -1
  622. package/dist/targets/github-release.d.ts +0 -25
  623. package/dist/targets/github-release.d.ts.map +0 -1
  624. package/dist/targets/github-release.js +0 -82
  625. package/dist/targets/github-release.js.map +0 -1
  626. package/dist/targets/github.d.ts +0 -11
  627. package/dist/targets/github.d.ts.map +0 -1
  628. package/dist/targets/github.js +0 -117
  629. package/dist/targets/github.js.map +0 -1
  630. package/dist/targets/homebrew.d.ts +0 -11
  631. package/dist/targets/homebrew.d.ts.map +0 -1
  632. package/dist/targets/homebrew.js +0 -210
  633. package/dist/targets/homebrew.js.map +0 -1
  634. package/dist/targets/live.d.ts +0 -5
  635. package/dist/targets/live.d.ts.map +0 -1
  636. package/dist/targets/live.js +0 -50
  637. package/dist/targets/live.js.map +0 -1
  638. package/dist/targets/npm.d.ts +0 -10
  639. package/dist/targets/npm.d.ts.map +0 -1
  640. package/dist/targets/npm.js +0 -112
  641. package/dist/targets/npm.js.map +0 -1
  642. package/dist/targets/pypi.d.ts +0 -11
  643. package/dist/targets/pypi.d.ts.map +0 -1
  644. package/dist/targets/pypi.js +0 -141
  645. package/dist/targets/pypi.js.map +0 -1
  646. package/dist/targets/registry.d.ts +0 -25
  647. package/dist/targets/registry.d.ts.map +0 -1
  648. package/dist/targets/registry.js +0 -34
  649. package/dist/targets/registry.js.map +0 -1
  650. package/dist/targets/scoop.d.ts +0 -11
  651. package/dist/targets/scoop.d.ts.map +0 -1
  652. package/dist/targets/scoop.js +0 -88
  653. package/dist/targets/scoop.js.map +0 -1
  654. package/dist/types/effect-internal.d.ts +0 -5
  655. package/dist/types/effect-internal.d.ts.map +0 -1
  656. package/dist/types/effect-internal.js +0 -2
  657. package/dist/types/effect-internal.js.map +0 -1
  658. package/dist/workflows/config.d.ts +0 -202
  659. package/dist/workflows/config.d.ts.map +0 -1
  660. package/dist/workflows/config.js +0 -420
  661. package/dist/workflows/config.js.map +0 -1
  662. package/dist/workflows/diagnostics.d.ts +0 -62
  663. package/dist/workflows/diagnostics.d.ts.map +0 -1
  664. package/dist/workflows/diagnostics.js +0 -530
  665. package/dist/workflows/diagnostics.js.map +0 -1
  666. package/dist/workflows/distribution.d.ts +0 -25
  667. package/dist/workflows/distribution.d.ts.map +0 -1
  668. package/dist/workflows/distribution.js +0 -24
  669. package/dist/workflows/distribution.js.map +0 -1
  670. package/dist/workflows/evidence.d.ts +0 -17
  671. package/dist/workflows/evidence.d.ts.map +0 -1
  672. package/dist/workflows/evidence.js +0 -32
  673. package/dist/workflows/evidence.js.map +0 -1
  674. package/dist/workflows/index.d.ts +0 -8
  675. package/dist/workflows/index.d.ts.map +0 -1
  676. package/dist/workflows/index.js +0 -7
  677. package/dist/workflows/index.js.map +0 -1
  678. package/dist/workflows/init.d.ts +0 -84
  679. package/dist/workflows/init.d.ts.map +0 -1
  680. package/dist/workflows/init.js +0 -487
  681. package/dist/workflows/init.js.map +0 -1
  682. package/dist/workflows/live.d.ts +0 -9
  683. package/dist/workflows/live.d.ts.map +0 -1
  684. package/dist/workflows/live.js +0 -7
  685. package/dist/workflows/live.js.map +0 -1
  686. package/dist/workflows/options.d.ts +0 -30
  687. package/dist/workflows/options.d.ts.map +0 -1
  688. package/dist/workflows/options.js +0 -16
  689. package/dist/workflows/options.js.map +0 -1
  690. package/examples/non-strict-skips/artifacts/release-example-skips-0.1.0.tgz +0 -1
  691. package/examples/non-strict-skips/release.config.json +0 -31
  692. package/examples/pypi-registry/release.config.json +0 -31
  693. package/templates/github-actions/plan-and-approved-execute.yml +0 -58
  694. package/templates/github-actions/plan-only.yml +0 -33
  695. 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,162 @@
1
+ import { encodeCanonicalJson } from "../model/canonical.js"
2
+ import {
3
+ JournalAuthorityMismatch,
4
+ type S3JournalAuthority
5
+ } from "./model.js"
6
+
7
+ const escapedPattern = (value: string): string => value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&")
8
+
9
+ const requireExactFields = (
10
+ value: object,
11
+ expected: ReadonlyArray<string>,
12
+ label: string
13
+ ): void => {
14
+ const actual = Object.keys(value).sort()
15
+ const fields = [...expected].sort()
16
+ if (actual.length !== fields.length || actual.some((field, index) => field !== fields[index])) {
17
+ throw JournalAuthorityMismatch.make({ reason: `${label} fields are not the exact admitted set.` })
18
+ }
19
+ }
20
+
21
+ export const validateS3JournalAuthority = (authority: S3JournalAuthority): void => {
22
+ requireExactFields(authority, [
23
+ "accountId",
24
+ "bucketArn",
25
+ "bucketName",
26
+ "bucketOwnerEnforced",
27
+ "bucketPolicyDigest",
28
+ "conditionalWritesEnforced",
29
+ "deleteDenied",
30
+ "expectedBucketOwner",
31
+ "multipartDenied",
32
+ "objectLock",
33
+ "oidc",
34
+ "oidcTrust",
35
+ "oidcTrustPolicyDigest",
36
+ "prefix",
37
+ "publicAccessBlocked",
38
+ "region",
39
+ "retentionMode",
40
+ "retentionYears",
41
+ "roleArn",
42
+ "rolePolicyDigest",
43
+ "versioning"
44
+ ], "Journal authority")
45
+ requireExactFields(authority.oidc, [
46
+ "audience",
47
+ "environment",
48
+ "eventName",
49
+ "issuer",
50
+ "jobWorkflowRef",
51
+ "jobWorkflowSha",
52
+ "ref",
53
+ "refType",
54
+ "repository",
55
+ "repositoryId",
56
+ "repositoryOwnerId",
57
+ "repositoryVisibility",
58
+ "runAttempt",
59
+ "runId",
60
+ "runnerEnvironment",
61
+ "sha",
62
+ "subject",
63
+ "workflow",
64
+ "workflowRef",
65
+ "workflowSha"
66
+ ], "Journal OIDC claims")
67
+ requireExactFields(authority.oidcTrust, [
68
+ "audience",
69
+ "environment",
70
+ "jobWorkflowRef",
71
+ "ref",
72
+ "repository",
73
+ "repositoryId",
74
+ "repositoryOwnerId",
75
+ "subject",
76
+ "workflow"
77
+ ], "Journal OIDC trust projection")
78
+ if (!/^[0-9]{12}$/u.test(authority.accountId) || authority.expectedBucketOwner !== authority.accountId) {
79
+ throw JournalAuthorityMismatch.make({ reason: "Journal AWS account and expected bucket owner are not the same exact account." })
80
+ }
81
+ if (!/^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/u.test(authority.bucketName) ||
82
+ authority.bucketArn !== `arn:aws:s3:::${authority.bucketName}`) {
83
+ throw JournalAuthorityMismatch.make({ reason: "Journal bucket identity is not canonical." })
84
+ }
85
+ if (!/^(?:af|ap|ca|eu|il|me|mx|sa|us)-[a-z]+-[0-9]$/u.test(authority.region)) {
86
+ throw JournalAuthorityMismatch.make({ reason: "Journal region is not canonical." })
87
+ }
88
+ if (authority.roleArn.length > 512 || !(new RegExp(
89
+ `^arn:aws:iam::${authority.accountId}:role\/(?:[A-Za-z0-9+=,.@_-]{1,128}\/)*[A-Za-z0-9+=,.@_-]{1,64}$`,
90
+ "u"
91
+ )).test(authority.roleArn)) {
92
+ throw JournalAuthorityMismatch.make({ reason: "Journal role does not belong to the exact bucket account." })
93
+ }
94
+ if (!/^sha256:[a-f0-9]{64}$/u.test(authority.bucketPolicyDigest) ||
95
+ !/^sha256:[a-f0-9]{64}$/u.test(authority.rolePolicyDigest) ||
96
+ !/^sha256:[a-f0-9]{64}$/u.test(authority.oidcTrustPolicyDigest)) {
97
+ throw JournalAuthorityMismatch.make({ reason: "Journal policy digests are not canonical SHA-256 values." })
98
+ }
99
+ if (authority.prefix !== "operation-journal/v1" || authority.versioning !== "Enabled" ||
100
+ authority.objectLock !== "Enabled" || authority.retentionMode !== "COMPLIANCE" ||
101
+ authority.retentionYears !== 10 || authority.bucketOwnerEnforced !== true ||
102
+ authority.publicAccessBlocked !== true || authority.deleteDenied !== true ||
103
+ authority.multipartDenied !== true || authority.conditionalWritesEnforced !== true) {
104
+ throw JournalAuthorityMismatch.make({ reason: "Journal bucket governance is not the one admitted ten-year COMPLIANCE policy." })
105
+ }
106
+ if (authority.oidc.issuer !== "https://token.actions.githubusercontent.com" ||
107
+ authority.oidc.audience !== "sts.amazonaws.com" ||
108
+ !/^[1-9][0-9]{0,19}$/u.test(authority.oidc.repositoryId) ||
109
+ !/^[1-9][0-9]{0,19}$/u.test(authority.oidc.repositoryOwnerId) ||
110
+ !/^[1-9][0-9]{0,19}$/u.test(authority.oidc.runId) ||
111
+ !/^[1-9][0-9]{0,19}$/u.test(authority.oidc.runAttempt) ||
112
+ authority.oidc.repository.length > 200 ||
113
+ !/^[A-Za-z0-9_.-]{1,100}\/[A-Za-z0-9_.-]{1,100}$/u.test(authority.oidc.repository) ||
114
+ authority.oidc.repositoryVisibility !== "public" ||
115
+ authority.oidc.eventName !== "workflow_dispatch" ||
116
+ authority.oidc.ref.length > 256 ||
117
+ !/^refs\/heads\/[A-Za-z0-9][A-Za-z0-9._/-]*$/u.test(authority.oidc.ref) ||
118
+ authority.oidc.refType !== "branch" ||
119
+ !/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u.test(authority.oidc.environment) ||
120
+ authority.oidc.runnerEnvironment !== "github-hosted" ||
121
+ !/^[ -~]{1,128}$/u.test(authority.oidc.workflow) ||
122
+ !/^[a-f0-9]{40}$/u.test(authority.oidc.sha) ||
123
+ authority.oidc.workflowSha !== authority.oidc.sha ||
124
+ authority.oidc.workflowRef.length > 512 || !(new RegExp(
125
+ `^${escapedPattern(authority.oidc.repository)}\\/.github\\/workflows\\/[A-Za-z0-9._-]+\\.ya?ml@${escapedPattern(authority.oidc.ref)}$`,
126
+ "u"
127
+ )).test(authority.oidc.workflowRef) ||
128
+ authority.oidc.jobWorkflowRef.length > 512 ||
129
+ !/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+\/\.github\/workflows\/[A-Za-z0-9._-]+\.ya?ml@[a-f0-9]{40}$/u.test(authority.oidc.jobWorkflowRef) ||
130
+ !/^[a-f0-9]{40}$/u.test(authority.oidc.jobWorkflowSha) ||
131
+ !authority.oidc.jobWorkflowRef.endsWith(`@${authority.oidc.jobWorkflowSha}`)) {
132
+ throw JournalAuthorityMismatch.make({
133
+ reason: "Journal OIDC claims do not bind the exact caller and called workflow identities."
134
+ })
135
+ }
136
+ const [repositoryOwner, repositoryName] = authority.oidc.repository.split("/") as [string, string]
137
+ const admittedSubjects = [
138
+ `repo:${authority.oidc.repository}:environment:${authority.oidc.environment}`,
139
+ `repo:${repositoryOwner}@${authority.oidc.repositoryOwnerId}/${repositoryName}@${authority.oidc.repositoryId}:environment:${authority.oidc.environment}`
140
+ ]
141
+ if (!admittedSubjects.includes(authority.oidc.subject)) {
142
+ throw JournalAuthorityMismatch.make({
143
+ reason: "Journal OIDC subject is neither the exact name-bound nor immutable-ID-bound environment subject."
144
+ })
145
+ }
146
+ const trustProjection = {
147
+ audience: authority.oidc.audience,
148
+ subject: authority.oidc.subject,
149
+ repository: authority.oidc.repository,
150
+ repositoryId: authority.oidc.repositoryId,
151
+ repositoryOwnerId: authority.oidc.repositoryOwnerId,
152
+ workflow: authority.oidc.workflow,
153
+ ref: authority.oidc.ref,
154
+ environment: authority.oidc.environment,
155
+ jobWorkflowRef: authority.oidc.jobWorkflowRef
156
+ }
157
+ if (encodeCanonicalJson(authority.oidcTrust) !== encodeCanonicalJson(trustProjection)) {
158
+ throw JournalAuthorityMismatch.make({
159
+ reason: "Journal AWS trust-policy conditions do not equal the re-observed trust-enforced OIDC claims."
160
+ })
161
+ }
162
+ }
@@ -0,0 +1,41 @@
1
+ export const operationJournalNetworkDeadlineMilliseconds = 10_000
2
+
3
+ export class OperationJournalNetworkDeadlineExceeded extends Error {
4
+ readonly name = "OperationJournalNetworkDeadlineExceeded"
5
+
6
+ constructor() {
7
+ super("The operational-journal network deadline elapsed.")
8
+ }
9
+ }
10
+
11
+ /**
12
+ * Bound one complete network operation even when the underlying transport
13
+ * ignores AbortSignal. The signal still gives cooperative transports an
14
+ * immediate opportunity to close DNS, sockets, and response streams.
15
+ */
16
+ export const withOperationJournalNetworkDeadline = async <Value>(
17
+ run: (signal: AbortSignal) => Promise<Value>,
18
+ milliseconds = operationJournalNetworkDeadlineMilliseconds
19
+ ): Promise<Value> => {
20
+ if (!Number.isSafeInteger(milliseconds) || milliseconds < 1 ||
21
+ milliseconds > operationJournalNetworkDeadlineMilliseconds) {
22
+ throw new Error("The operational-journal network deadline is not canonical.")
23
+ }
24
+ const controller = new AbortController()
25
+ let timer: ReturnType<typeof setTimeout> | undefined
26
+ const deadline = new Promise<never>((_resolve, reject) => {
27
+ timer = setTimeout(() => {
28
+ const cause = new OperationJournalNetworkDeadlineExceeded()
29
+ controller.abort(cause)
30
+ reject(cause)
31
+ }, milliseconds)
32
+ })
33
+ try {
34
+ return await Promise.race([
35
+ Promise.resolve().then(() => run(controller.signal)),
36
+ deadline
37
+ ])
38
+ } finally {
39
+ if (timer !== undefined) clearTimeout(timer)
40
+ }
41
+ }