@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,766 @@
1
+ import * as Schema from "effect/Schema";
2
+ import * as Semver from "semver";
3
+ import { AnonymousAuthStrategy, CanonicalAudience, CredentialRef, EnvironmentName, ExternalTrustedPublishingAuthStrategy, ProviderId, ResolvedAuthStrategy, SubjectId, TokenAuthStrategy, TrustedPublishingAuthStrategy, TrustedPublishingSourceCommit } from "../model/authority.js";
4
+ import { ArtifactCollectionContract, ArtifactCollectionSelector, cardinalitiesOverlap, cardinalityIssue, collectionContractIssue } from "../model/artifact-collection.js";
5
+ import { CatalogRenderSource, CatalogRenderer, CatalogRepositoryPath, GitBranchName, GitHubRepositoryCoordinate } from "../model/catalog.js";
6
+ import { NonEmptyName, OperationId, OutputId, SafeRelativePath, Version } from "../model/primitives.js";
7
+ import { CanonicalNpmRegistryEndpoint, NpmAccess, NpmAuthentication, NpmDistTag, NpmProvenancePolicy, PyPiAuthentication, PyPiProjectName, PyPiRepository, canonicalizeNpmRegistryEndpoint, normalizePyPiProjectName, pypiRepositoryEndpoints } from "../recipes/config.js";
8
+ export class OutputDeclaration extends Schema.Class("OutputDeclaration")({
9
+ id: OutputId, path: SafeRelativePath,
10
+ kind: Schema.Literals(["file", "executable", "archive", "digest", "package"]),
11
+ mediaType: Schema.optionalKey(Schema.NonEmptyString)
12
+ }) {
13
+ }
14
+ const optional = Schema.optionalKey;
15
+ const argv = Schema.NonEmptyArray(Schema.String);
16
+ export class GraphCommandCheck extends Schema.TaggedClass()("GraphCommandCheck", {
17
+ id: OperationId, argv, cwd: SafeRelativePath, inputs: Schema.Array(OutputId)
18
+ }) {
19
+ }
20
+ export class GraphCommandArtifact extends Schema.TaggedClass()("GraphCommandArtifact", {
21
+ id: OperationId, argv, cwd: SafeRelativePath,
22
+ inputs: Schema.Array(OutputId), outputs: Schema.NonEmptyArray(OutputDeclaration)
23
+ }) {
24
+ }
25
+ export class GraphCommandCollection extends Schema.TaggedClass()("GraphCommandCollection", {
26
+ id: OperationId, argv, cwd: SafeRelativePath,
27
+ inputs: Schema.Array(OutputId), collection: ArtifactCollectionContract
28
+ }) {
29
+ }
30
+ /** Package-scoped build whose directory outputs are consumed only by npm pack. */
31
+ export class GraphNpmPackageBuild extends Schema.TaggedClass()("GraphNpmPackageBuild", {
32
+ id: OperationId,
33
+ argv,
34
+ cwd: SafeRelativePath,
35
+ inputs: Schema.Array(OutputId),
36
+ outputRoots: Schema.NonEmptyArray(SafeRelativePath)
37
+ }) {
38
+ }
39
+ export class GraphArchive extends Schema.TaggedClass()("GraphArchive", {
40
+ id: OperationId, inputs: Schema.Array(OutputId), output: OutputDeclaration,
41
+ format: Schema.Literals(["tar.gz", "zip"])
42
+ }) {
43
+ }
44
+ export class GraphChecksum extends Schema.TaggedClass()("GraphChecksum", {
45
+ id: OperationId, inputs: Schema.NonEmptyArray(OutputId), output: OutputDeclaration,
46
+ algorithm: Schema.Literals(["sha256", "sha512"])
47
+ }) {
48
+ }
49
+ export class GraphCatalogRender extends Schema.TaggedClass()("GraphCatalogRender", {
50
+ id: OperationId,
51
+ inputs: Schema.NonEmptyArray(OutputId),
52
+ output: OutputDeclaration,
53
+ version: Version,
54
+ renderer: CatalogRenderer,
55
+ sources: Schema.NonEmptyArray(CatalogRenderSource)
56
+ }) {
57
+ }
58
+ export const GraphPreparation = Schema.Union([
59
+ GraphCommandCheck, GraphCommandArtifact, GraphCommandCollection, GraphNpmPackageBuild,
60
+ GraphArchive, GraphChecksum, GraphCatalogRender
61
+ ]);
62
+ /** Safe, durable authority intent resolved before a publication enters the graph. */
63
+ export class PublicationAuthorityIntent extends Schema.Class("PublicationAuthorityIntent")({
64
+ subject: SubjectId,
65
+ provider: ProviderId,
66
+ audience: CanonicalAudience,
67
+ observationStrategies: Schema.NonEmptyArray(ResolvedAuthStrategy),
68
+ publishStrategy: ResolvedAuthStrategy
69
+ }) {
70
+ }
71
+ export class GraphNpmPublication extends Schema.TaggedClass()("GraphNpmPublication", {
72
+ id: OperationId,
73
+ packageArtifact: OutputId,
74
+ packageName: NonEmptyName,
75
+ version: Version,
76
+ registryUrl: CanonicalNpmRegistryEndpoint,
77
+ distTag: NpmDistTag,
78
+ access: NpmAccess,
79
+ authentication: NpmAuthentication,
80
+ provenance: NpmProvenancePolicy,
81
+ authority: PublicationAuthorityIntent
82
+ }) {
83
+ }
84
+ export class GraphGitHubPublication extends Schema.TaggedClass()("GraphGitHubPublication", {
85
+ id: OperationId, repository: Schema.NonEmptyString, tag: NonEmptyName, title: NonEmptyName,
86
+ draft: Schema.Boolean, prerelease: Schema.Boolean, body: optional(Schema.String), bodyArtifact: optional(OutputId),
87
+ assetIds: Schema.Array(OutputId), assetCollections: Schema.Array(ArtifactCollectionSelector),
88
+ authority: PublicationAuthorityIntent
89
+ }) {
90
+ }
91
+ export class GraphPyPiDistribution extends Schema.Class("GraphPyPiDistribution")({
92
+ artifactId: OutputId,
93
+ filename: NonEmptyName,
94
+ authority: PublicationAuthorityIntent
95
+ }) {
96
+ }
97
+ export class GraphPyPiPublication extends Schema.TaggedClass()("GraphPyPiPublication", {
98
+ id: OperationId,
99
+ project: PyPiProjectName,
100
+ version: Version,
101
+ repository: PyPiRepository,
102
+ simpleBaseUrl: Schema.NonEmptyString,
103
+ projectUrl: Schema.NonEmptyString,
104
+ uploadUrl: Schema.NonEmptyString,
105
+ authentication: PyPiAuthentication,
106
+ files: Schema.NonEmptyArray(GraphPyPiDistribution)
107
+ }) {
108
+ }
109
+ export class GraphCatalogPublication extends Schema.TaggedClass()("GraphCatalogPublication", {
110
+ id: OperationId,
111
+ catalogId: NonEmptyName,
112
+ targetArtifact: OutputId,
113
+ repository: GitHubRepositoryCoordinate,
114
+ branch: GitBranchName,
115
+ targetPath: CatalogRepositoryPath,
116
+ statePath: CatalogRepositoryPath,
117
+ version: Version,
118
+ sourceRepository: GitHubRepositoryCoordinate,
119
+ sourceTag: NonEmptyName,
120
+ renderer: CatalogRenderer,
121
+ sources: Schema.NonEmptyArray(CatalogRenderSource),
122
+ authority: PublicationAuthorityIntent
123
+ }) {
124
+ }
125
+ export const GraphPublication = Schema.Union([
126
+ GraphNpmPublication, GraphPyPiPublication, GraphGitHubPublication, GraphCatalogPublication
127
+ ]);
128
+ export class CapabilityContribution extends Schema.Class("CapabilityContribution")({
129
+ artifacts: Schema.Array(OutputDeclaration), preparations: Schema.Array(GraphPreparation),
130
+ publications: Schema.Array(GraphPublication)
131
+ }) {
132
+ }
133
+ export class ReleaseGraph extends Schema.Class("ReleaseGraph")({
134
+ artifacts: Schema.Array(OutputDeclaration), collections: Schema.Array(ArtifactCollectionContract),
135
+ preparations: Schema.Array(GraphPreparation),
136
+ publications: Schema.Array(GraphPublication)
137
+ }) {
138
+ }
139
+ export class GraphLinkError extends Schema.TaggedErrorClass()("GraphLinkError", {
140
+ kind: Schema.Literals(["duplicate", "missing", "cycle", "path", "reference"]),
141
+ value: Schema.String, reason: Schema.String
142
+ }) {
143
+ }
144
+ const authorityError = (value, reason) => new GraphLinkError({ kind: "reference", value, reason });
145
+ /**
146
+ * Canonical registry authority includes the complete normalized base path.
147
+ * Query, fragment, and user-info components can never enter a credential
148
+ * audience.
149
+ */
150
+ export const canonicalizeRegistryUrl = (value) => {
151
+ try {
152
+ return canonicalizeNpmRegistryEndpoint(value);
153
+ }
154
+ catch (cause) {
155
+ throw authorityError("publish.npm.registry", cause instanceof Error ? cause.message : String(cause));
156
+ }
157
+ };
158
+ const tokenStrategy = (value, field) => {
159
+ let name;
160
+ try {
161
+ name = EnvironmentName.make(value);
162
+ }
163
+ catch {
164
+ throw authorityError(field, "Credential references derived from tokenEnv must be portable environment variable names.");
165
+ }
166
+ return TokenAuthStrategy.make({ kind: "token", credential: CredentialRef.make(name) });
167
+ };
168
+ const anonymousStrategy = () => AnonymousAuthStrategy.make({ kind: "anonymous" });
169
+ /** Resolve npm auth once; no secret value enters the graph or prepared state. */
170
+ export const makeNpmPublicationAuthorityIntent = (input) => {
171
+ const version = input.version;
172
+ let tag;
173
+ try {
174
+ tag = NpmDistTag.make(input.distTag);
175
+ }
176
+ catch (cause) {
177
+ throw authorityError("publish.npm.distTag", cause instanceof Error ? cause.message : String(cause));
178
+ }
179
+ if (Semver.prerelease(version) !== null && tag === "latest") {
180
+ throw authorityError("publish.npm.distTag", "npm prerelease publication requires a non-latest dist-tag.");
181
+ }
182
+ const provider = ProviderId.make("npm");
183
+ const publishStrategy = input.authentication.strategy === "token"
184
+ ? tokenStrategy(input.authentication.credential, "publish.npm.authentication.credential")
185
+ : (() => {
186
+ let sourceCommit;
187
+ try {
188
+ sourceCommit = TrustedPublishingSourceCommit.make(input.sourceCommit ?? "");
189
+ }
190
+ catch {
191
+ throw authorityError("source.commit", "npm trusted publishing requires a lowercase full Git SHA (40 or 64 hex characters).");
192
+ }
193
+ return TrustedPublishingAuthStrategy.make({
194
+ kind: "trusted-publishing", identityProvider: input.authentication.attestation.provider,
195
+ runnerClass: input.authentication.attestation.runner,
196
+ repository: input.authentication.attestation.repository,
197
+ workflow: `.github/workflows/${input.authentication.attestation.workflow}`,
198
+ workflowRef: input.authentication.attestation.workflowRef,
199
+ sourceCommit,
200
+ provenanceEnvironmentContract: "github-actions-npm-provenance-v1",
201
+ allowedAction: input.authentication.attestation.allowedAction,
202
+ publisherSink: "certified-npm-cli"
203
+ });
204
+ })();
205
+ return PublicationAuthorityIntent.make({
206
+ subject: SubjectId.make(`npm:${input.packageName}@${input.version}`),
207
+ provider,
208
+ audience: CanonicalAudience.make(canonicalizeRegistryUrl(input.registryUrl)),
209
+ // Public registry observation is anonymous. This graph deliberately has
210
+ // no authenticated npm read strategy: custom/private reads remain
211
+ // unsupported until they receive a distinct typed read credential.
212
+ observationStrategies: [anonymousStrategy()],
213
+ publishStrategy
214
+ });
215
+ };
216
+ const externalPyPiStrategy = (input, authentication) => {
217
+ let sourceCommit;
218
+ try {
219
+ sourceCommit = TrustedPublishingSourceCommit.make(input.sourceCommit ?? "");
220
+ }
221
+ catch {
222
+ throw authorityError("source.commit", "External PyPI trusted publishing requires a lowercase full Git SHA.");
223
+ }
224
+ return ExternalTrustedPublishingAuthStrategy.make({
225
+ kind: "trusted-publishing",
226
+ identityProvider: "github-actions",
227
+ runnerClass: "github-hosted",
228
+ repository: authentication.repository,
229
+ workflow: `.github/workflows/${authentication.workflow}`,
230
+ workflowRef: authentication.workflowRef,
231
+ sourceCommit,
232
+ provenanceEnvironmentContract: "external-pypa-action-v1",
233
+ allowedAction: "external-pypa-action",
234
+ publisherSink: "external-host-owned",
235
+ environment: authentication.environment,
236
+ projects: authentication.projects.map(normalizePyPiProjectName)
237
+ });
238
+ };
239
+ /** Exact per-file PyPI authority; OIDC remains external-host-owned. */
240
+ export const makePyPiPublicationAuthorityIntent = (input) => {
241
+ const endpoints = pypiRepositoryEndpoints(input.repository);
242
+ const project = PyPiProjectName.make(normalizePyPiProjectName(input.project));
243
+ const provider = ProviderId.make("pypi");
244
+ const publishStrategy = input.authentication.strategy === "token"
245
+ ? tokenStrategy(input.authentication.credential, "publish.pypi.authentication.credential")
246
+ : externalPyPiStrategy(input, input.authentication);
247
+ return PublicationAuthorityIntent.make({
248
+ subject: SubjectId.make(`pypi:${input.repository}:${project}@${input.version}#${input.filename}`),
249
+ provider,
250
+ audience: CanonicalAudience.make(endpoints.uploadUrl),
251
+ observationStrategies: [anonymousStrategy()],
252
+ publishStrategy
253
+ });
254
+ };
255
+ export const makeCatalogPublicationAuthorityIntent = (input) => {
256
+ let repository;
257
+ let branch;
258
+ let targetPath;
259
+ let statePath;
260
+ try {
261
+ repository = GitHubRepositoryCoordinate.make(input.repository);
262
+ branch = GitBranchName.make(input.branch);
263
+ targetPath = CatalogRepositoryPath.make(input.targetPath);
264
+ statePath = CatalogRepositoryPath.make(input.statePath);
265
+ }
266
+ catch (cause) {
267
+ throw authorityError("publish.catalogGit", cause instanceof Error ? cause.message : String(cause));
268
+ }
269
+ if (targetPath.toString() === statePath.toString()) {
270
+ throw authorityError("publish.catalogGit", "Catalog target and managed-state paths must be distinct.");
271
+ }
272
+ const provider = ProviderId.make("catalog-git");
273
+ const audience = CanonicalAudience.make(`https://api.github.com/repos/${repository}`);
274
+ const token = tokenStrategy(input.tokenEnv, "publish.catalogGit[].tokenEnv");
275
+ return PublicationAuthorityIntent.make({
276
+ subject: SubjectId.make(`catalog-git:${repository}#refs/heads/${branch}:${targetPath}+${statePath}`),
277
+ provider,
278
+ audience,
279
+ observationStrategies: [anonymousStrategy(), token],
280
+ publishStrategy: token
281
+ });
282
+ };
283
+ const githubCoordinate = (value) => {
284
+ if (!/^[A-Za-z0-9._-]+\/[A-Za-z0-9._-]+$/u.test(value)) {
285
+ throw authorityError("publish.github.repository", "GitHub repository must be an owner/repository coordinate.");
286
+ }
287
+ return value;
288
+ };
289
+ /** Resolve GitHub auth once; anonymous observation is always attempted first. */
290
+ export const makeGitHubPublicationAuthorityIntent = (input) => {
291
+ const repository = githubCoordinate(input.repository);
292
+ const provider = ProviderId.make("github");
293
+ const publishStrategy = tokenStrategy(input.tokenEnv ?? "GITHUB_TOKEN", "publish.github.tokenEnv");
294
+ return PublicationAuthorityIntent.make({
295
+ subject: SubjectId.make(`github:${repository}#${input.tag}`),
296
+ provider,
297
+ audience: CanonicalAudience.make(`https://api.github.com/repos/${repository}`),
298
+ observationStrategies: [anonymousStrategy(), publishStrategy],
299
+ publishStrategy
300
+ });
301
+ };
302
+ const sameTokenStrategy = (left, right) => left?.kind === "token" && left.credential === right.credential;
303
+ export const npmPublicationAuthorityIssue = (publication) => {
304
+ const version = publication.version.toString();
305
+ if (Semver.valid(version) !== version) {
306
+ return "npm publication version must be canonical SemVer.";
307
+ }
308
+ if (Semver.prerelease(version) !== null && publication.distTag === "latest") {
309
+ return "npm prerelease publication must use an explicit non-latest dist-tag.";
310
+ }
311
+ if (publication.access === "restricted" && !publication.packageName.toString().startsWith("@")) {
312
+ return "npm restricted access is valid only for scoped package names.";
313
+ }
314
+ const expectedSubject = `npm:${publication.packageName}@${publication.version}`;
315
+ let expectedAudience;
316
+ try {
317
+ expectedAudience = canonicalizeRegistryUrl(publication.registryUrl);
318
+ }
319
+ catch {
320
+ return "npm publication must carry a canonical absolute registry endpoint.";
321
+ }
322
+ const { authority } = publication;
323
+ if (publication.registryUrl !== expectedAudience || authority.subject !== expectedSubject ||
324
+ authority.provider !== "npm" || authority.audience !== expectedAudience) {
325
+ return "npm publication authority must match its exact package, version, provider, and canonical registry audience.";
326
+ }
327
+ if (authority.observationStrategies[0]?.kind !== "anonymous") {
328
+ return "npm observation authority must attempt anonymous access first.";
329
+ }
330
+ if (authority.publishStrategy.kind === "token") {
331
+ return publication.authentication.strategy === "token" && publication.provenance !== "automatic" &&
332
+ authority.publishStrategy.credential === publication.authentication.credential &&
333
+ authority.observationStrategies.length === 1
334
+ ? undefined
335
+ : "npm token publication requires the exact configured mutation token, explicit provenance, and anonymous-only observation.";
336
+ }
337
+ if (authority.publishStrategy.kind === "trusted-publishing") {
338
+ const authentication = publication.authentication;
339
+ return authentication.strategy === "trusted-publishing" &&
340
+ publication.registryUrl === "https://registry.npmjs.org/" &&
341
+ authentication.attestation.allowedAction === "npm-publish-direct" &&
342
+ authority.observationStrategies.length === 1 &&
343
+ authority.publishStrategy.identityProvider === "github-actions" &&
344
+ authority.publishStrategy.runnerClass === authentication.attestation.runner &&
345
+ authority.publishStrategy.repository === authentication.attestation.repository &&
346
+ authority.publishStrategy.workflow === `.github/workflows/${authentication.attestation.workflow}` &&
347
+ authority.publishStrategy.workflowRef === authentication.attestation.workflowRef &&
348
+ /^[a-f0-9]{40}(?:[a-f0-9]{24})?$/u.test(authority.publishStrategy.sourceCommit) &&
349
+ authority.publishStrategy.provenanceEnvironmentContract === "github-actions-npm-provenance-v1" &&
350
+ authority.publishStrategy.allowedAction === authentication.attestation.allowedAction &&
351
+ authority.publishStrategy.publisherSink === "certified-npm-cli"
352
+ ? undefined
353
+ : "npm trusted publishing requires the exact direct-publish attestation, hosted workflow identity/ref, and certified npm sink.";
354
+ }
355
+ return "npm publication requires token or trusted-publishing mutation authority.";
356
+ };
357
+ export const githubPublicationAuthorityIssue = (publication) => {
358
+ let repository;
359
+ try {
360
+ repository = githubCoordinate(publication.repository);
361
+ }
362
+ catch {
363
+ return "GitHub publication must carry an owner/repository coordinate.";
364
+ }
365
+ const { authority } = publication;
366
+ if (authority.subject !== `github:${repository}#${publication.tag}` || authority.provider !== "github" ||
367
+ authority.audience !== `https://api.github.com/repos/${repository}`) {
368
+ return "GitHub publication authority must match its exact repository, tag, provider, and API audience.";
369
+ }
370
+ if (authority.publishStrategy.kind !== "token" || authority.observationStrategies.length !== 2 ||
371
+ authority.observationStrategies[0]?.kind !== "anonymous" ||
372
+ !sameTokenStrategy(authority.observationStrategies[1], authority.publishStrategy)) {
373
+ return "GitHub publication requires anonymous observation followed by its exact configured token reference.";
374
+ }
375
+ return undefined;
376
+ };
377
+ export const pyPiPublicationAuthorityIssue = (publication) => {
378
+ let project;
379
+ try {
380
+ project = normalizePyPiProjectName(publication.project);
381
+ }
382
+ catch {
383
+ return "PyPI publication must carry a valid normalized project name.";
384
+ }
385
+ const endpoints = pypiRepositoryEndpoints(publication.repository);
386
+ const expectedProjectUrl = `${endpoints.simpleBaseUrl}${encodeURIComponent(project)}/`;
387
+ if (publication.project !== project || publication.simpleBaseUrl !== endpoints.simpleBaseUrl ||
388
+ publication.projectUrl !== expectedProjectUrl || publication.uploadUrl !== endpoints.uploadUrl) {
389
+ return "PyPI publication endpoints must match its closed repository and normalized project coordinate.";
390
+ }
391
+ if (publication.files.length === 0)
392
+ return "PyPI publication requires at least one distribution file.";
393
+ const names = new Set();
394
+ for (const file of publication.files) {
395
+ const filename = file.filename.toString();
396
+ if (filename.length === 0 || filename.includes("/") || filename.includes("\\") || names.has(filename)) {
397
+ return "PyPI publication filenames must be nonempty, unique basenames.";
398
+ }
399
+ names.add(filename);
400
+ const authority = file.authority;
401
+ if (authority.subject !== `pypi:${publication.repository}:${project}@${publication.version}#${filename}` ||
402
+ authority.provider !== "pypi" || authority.audience !== endpoints.uploadUrl ||
403
+ authority.observationStrategies.length !== 1 || authority.observationStrategies[0]?.kind !== "anonymous") {
404
+ return "PyPI file authority must match its exact repository, project, version, filename, upload audience, and anonymous read strategy.";
405
+ }
406
+ if (publication.authentication.strategy === "token") {
407
+ if (authority.publishStrategy.kind !== "token" ||
408
+ authority.publishStrategy.credential !== publication.authentication.credential) {
409
+ return "PyPI token publication requires its exact project-scoped configured credential.";
410
+ }
411
+ }
412
+ else if (authority.publishStrategy.kind !== "trusted-publishing" ||
413
+ authority.publishStrategy.publisherSink !== "external-host-owned" ||
414
+ authority.publishStrategy.allowedAction !== "external-pypa-action" ||
415
+ authority.publishStrategy.repository !== publication.authentication.repository ||
416
+ authority.publishStrategy.workflow !== `.github/workflows/${publication.authentication.workflow}` ||
417
+ authority.publishStrategy.workflowRef !== publication.authentication.workflowRef ||
418
+ authority.publishStrategy.environment !== publication.authentication.environment ||
419
+ authority.publishStrategy.projects.join("\n") !== publication.authentication.projects.map(normalizePyPiProjectName).join("\n")) {
420
+ return "PyPI trusted publication must remain bound to the exact external PyPA Action workflow and complete bundled project set.";
421
+ }
422
+ }
423
+ return undefined;
424
+ };
425
+ export const catalogPublicationAuthorityIssue = (publication) => {
426
+ let repository;
427
+ let branch;
428
+ let targetPath;
429
+ let statePath;
430
+ try {
431
+ repository = GitHubRepositoryCoordinate.make(publication.repository);
432
+ branch = GitBranchName.make(publication.branch.toString());
433
+ targetPath = CatalogRepositoryPath.make(publication.targetPath.toString());
434
+ statePath = CatalogRepositoryPath.make(publication.statePath.toString());
435
+ }
436
+ catch {
437
+ return "Catalog publication must carry canonical GitHub repository, branch, and file paths.";
438
+ }
439
+ const { authority } = publication;
440
+ const token = authority.publishStrategy;
441
+ if (targetPath === statePath || targetPath.startsWith(`${statePath}/`) || statePath.startsWith(`${targetPath}/`) ||
442
+ authority.subject !== `catalog-git:${repository}#refs/heads/${branch}:${targetPath}+${statePath}` ||
443
+ authority.provider !== "catalog-git" || authority.audience !== `https://api.github.com/repos/${repository}` ||
444
+ authority.observationStrategies.length !== 2 || authority.observationStrategies[0]?.kind !== "anonymous" ||
445
+ token.kind !== "token" || !sameTokenStrategy(authority.observationStrategies[1], token)) {
446
+ return "Catalog publication authority must bind its exact GitHub repository/ref/path pair and one bundled read/write token.";
447
+ }
448
+ return undefined;
449
+ };
450
+ // `localeCompare` is environment-dependent. Graph order is an internal
451
+ // identity, so it uses the repository's plain code-point order instead.
452
+ const byId = (left, right) => {
453
+ const a = left.id.toString();
454
+ const b = right.id.toString();
455
+ return a < b ? -1 : a > b ? 1 : 0;
456
+ };
457
+ const preparationInputs = (preparation) => preparation.inputs;
458
+ const preparationOutputs = (preparation) => preparation._tag === "GraphCommandArtifact" ? preparation.outputs
459
+ : preparation._tag === "GraphArchive" || preparation._tag === "GraphChecksum" || preparation._tag === "GraphCatalogRender"
460
+ ? [preparation.output] : [];
461
+ const pathsOverlap = (left, right) => left === right || left.startsWith(`${right}/`) || right.startsWith(`${left}/`);
462
+ const portablePathsOverlap = (left, right) => pathsOverlap(left.toLocaleLowerCase("en-US"), right.toLocaleLowerCase("en-US"));
463
+ export const linkContributions = (contributions) => {
464
+ const contributedPreparations = contributions.flatMap((item) => item.preparations);
465
+ const collections = contributedPreparations.flatMap((preparation) => preparation._tag === "GraphCommandCollection" ? [preparation.collection] : [])
466
+ .sort(byId);
467
+ const collectionIds = new Map();
468
+ const collectionRoots = new Map();
469
+ for (const collection of collections) {
470
+ const id = collection.id.toString();
471
+ const previousId = [...collectionIds.keys()].find((candidate) => candidate.toLocaleLowerCase("en-US") === id.toLocaleLowerCase("en-US"));
472
+ if (previousId !== undefined)
473
+ throw new GraphLinkError({
474
+ kind: "duplicate", value: id,
475
+ reason: `Artifact collection id collides with ${previousId} under portable case folding.`
476
+ });
477
+ const issue = cardinalityIssue(collection.cardinality);
478
+ if (issue !== undefined)
479
+ throw new GraphLinkError({ kind: "reference", value: id, reason: issue });
480
+ const contractIssue = collectionContractIssue(collection);
481
+ if (contractIssue !== undefined)
482
+ throw new GraphLinkError({
483
+ kind: "reference", value: id, reason: contractIssue
484
+ });
485
+ const root = collection.root.toString();
486
+ const previousRoot = [...collectionRoots.entries()].find(([candidate]) => portablePathsOverlap(candidate, root));
487
+ if (previousRoot !== undefined)
488
+ throw new GraphLinkError({
489
+ kind: "path", value: root,
490
+ reason: `Artifact collection roots ${previousRoot[0]} (${previousRoot[1]}) and ${root} (${id}) overlap.`
491
+ });
492
+ collectionIds.set(id, collection);
493
+ collectionRoots.set(root, id);
494
+ }
495
+ const declared = contributions.flatMap((item) => item.artifacts);
496
+ const allPreparationOutputs = contributions.flatMap((item) => item.preparations.flatMap(preparationOutputs));
497
+ const artifactIds = new Set();
498
+ for (const artifact of [...declared, ...allPreparationOutputs]) {
499
+ if (artifactIds.has(artifact.id.toString()))
500
+ throw new GraphLinkError({
501
+ kind: "duplicate", value: artifact.id.toString(), reason: "Artifact id has more than one declaration or producer."
502
+ });
503
+ artifactIds.add(artifact.id.toString());
504
+ }
505
+ const artifacts = [...declared, ...allPreparationOutputs].sort(byId);
506
+ const paths = new Map();
507
+ for (const artifact of artifacts) {
508
+ const path = artifact.path.toString();
509
+ const previous = paths.get(path);
510
+ if (previous !== undefined && previous !== artifact.id.toString())
511
+ throw new GraphLinkError({
512
+ kind: "path", value: path, reason: `Artifacts ${previous} and ${artifact.id} share one output path.`
513
+ });
514
+ paths.set(path, artifact.id.toString());
515
+ if (artifact.kind !== "package") {
516
+ const collection = [...collectionRoots.entries()].find(([root]) => portablePathsOverlap(root, path));
517
+ if (collection !== undefined)
518
+ throw new GraphLinkError({
519
+ kind: "path", value: path,
520
+ reason: `Artifact ${artifact.id} overlaps collection root ${collection[0]} (${collection[1]}).`
521
+ });
522
+ }
523
+ }
524
+ const preparations = contributedPreparations.sort(byId);
525
+ const operationIds = new Set();
526
+ const producers = new Map();
527
+ for (const preparation of preparations) {
528
+ const id = preparation.id.toString();
529
+ if (operationIds.has(id))
530
+ throw new GraphLinkError({
531
+ kind: "duplicate", value: id, reason: "Preparation id has more than one producer."
532
+ });
533
+ operationIds.add(id);
534
+ if (preparation._tag === "GraphNpmPackageBuild") {
535
+ const cwd = preparation.cwd.toString();
536
+ const roots = preparation.outputRoots.map(String);
537
+ if (new Set(roots.map((root) => root.toLocaleLowerCase("en-US"))).size !== roots.length) {
538
+ throw new GraphLinkError({ kind: "path", value: id, reason: "npm package build output roots must be unique." });
539
+ }
540
+ for (let index = 0; index < roots.length; index += 1) {
541
+ const root = roots[index];
542
+ if (cwd !== "." && root !== cwd && !root.startsWith(`${cwd}/`))
543
+ throw new GraphLinkError({
544
+ kind: "path", value: root, reason: "npm package build output roots must remain inside npmPackage.path."
545
+ });
546
+ if (artifacts.some((artifact) => artifact.kind !== "package" && portablePathsOverlap(root, artifact.path.toString())) ||
547
+ [...collectionRoots.keys()].some((collection) => portablePathsOverlap(root, collection)))
548
+ throw new GraphLinkError({
549
+ kind: "path", value: root, reason: "npm package build output roots cannot overlap captured artifacts or collections."
550
+ });
551
+ for (const other of roots.slice(index + 1))
552
+ if (portablePathsOverlap(root, other))
553
+ throw new GraphLinkError({
554
+ kind: "path", value: root, reason: `npm package build output roots ${root} and ${other} overlap.`
555
+ });
556
+ }
557
+ }
558
+ if (preparation._tag === "GraphCommandCollection" && preparation.collection.producer.toString() !== id) {
559
+ throw new GraphLinkError({
560
+ kind: "reference", value: preparation.collection.id.toString(),
561
+ reason: `Artifact collection declares producer ${preparation.collection.producer} but is owned by ${id}.`
562
+ });
563
+ }
564
+ if (preparation._tag === "GraphCommandCollection") {
565
+ const root = preparation.collection.root.toString();
566
+ const overlap = preparation.inputs.map((input) => artifacts.find((artifact) => artifact.id === input))
567
+ .find((artifact) => artifact !== undefined && portablePathsOverlap(root, artifact.path.toString()));
568
+ if (overlap !== undefined)
569
+ throw new GraphLinkError({
570
+ kind: "path", value: root,
571
+ reason: `Artifact collection root overlaps read-only input ${overlap.id} at ${overlap.path}.`
572
+ });
573
+ }
574
+ for (const input of preparationInputs(preparation)) {
575
+ if (!artifactIds.has(input.toString()))
576
+ throw new GraphLinkError({
577
+ kind: "missing", value: input.toString(), reason: `Preparation ${id} references no artifact.`
578
+ });
579
+ }
580
+ for (const output of preparationOutputs(preparation)) {
581
+ const outputId = output.id.toString();
582
+ if (producers.has(outputId))
583
+ throw new GraphLinkError({
584
+ kind: "duplicate", value: outputId, reason: "Output has more than one producer."
585
+ });
586
+ if (preparation._tag === "GraphCommandArtifact" && ["directory", "package"].includes(output.kind))
587
+ throw new GraphLinkError({
588
+ kind: "path", value: outputId, reason: "Generic command outputs must be regular files."
589
+ });
590
+ if (preparation._tag === "GraphCommandArtifact" && preparation.inputs.some((input) => input.toString() === outputId))
591
+ throw new GraphLinkError({
592
+ kind: "reference", value: outputId, reason: "Command inputs and outputs must be disjoint."
593
+ });
594
+ if (preparation._tag === "GraphCommandArtifact" && preparation.inputs.some((input) => artifacts.find((artifact) => artifact.id.toString() === input.toString())?.path === output.path))
595
+ throw new GraphLinkError({
596
+ kind: "path", value: outputId, reason: "Command outputs must not overwrite input paths."
597
+ });
598
+ producers.set(outputId, id);
599
+ }
600
+ const references = preparation._tag === "GraphCommandCheck" || preparation._tag === "GraphCommandArtifact" ||
601
+ preparation._tag === "GraphCommandCollection" || preparation._tag === "GraphNpmPackageBuild"
602
+ ? preparation.argv.flatMap((part) => [...part.matchAll(/\{(input|output|collection):([^}]+)\}/gu)]) : [];
603
+ for (const reference of references) {
604
+ const direction = reference[1];
605
+ const referenced = reference[2] ?? "";
606
+ if (direction === "input" && !preparationInputs(preparation).some((input) => input.toString() === referenced)) {
607
+ throw new GraphLinkError({ kind: "reference", value: referenced, reason: "Command input reference is undeclared." });
608
+ }
609
+ if (direction === "output" && !preparationOutputs(preparation).some((output) => output.id.toString() === referenced)) {
610
+ throw new GraphLinkError({ kind: "reference", value: referenced, reason: "Command output reference is undeclared." });
611
+ }
612
+ if (direction === "collection" && (preparation._tag !== "GraphCommandCollection" ||
613
+ preparation.collection.id.toString() !== referenced)) {
614
+ throw new GraphLinkError({ kind: "reference", value: referenced, reason: "Command collection reference is undeclared." });
615
+ }
616
+ }
617
+ if (preparation._tag === "GraphCommandCheck" || preparation._tag === "GraphCommandArtifact" ||
618
+ preparation._tag === "GraphCommandCollection" || preparation._tag === "GraphNpmPackageBuild") {
619
+ for (const part of preparation.argv) {
620
+ for (const token of part.matchAll(/\{([^}]+)\}/gu)) {
621
+ const value = token[1] ?? "";
622
+ if (!value.startsWith("input:") && !value.startsWith("output:") && !value.startsWith("collection:"))
623
+ throw new GraphLinkError({
624
+ kind: "reference", value, reason: "Command paths support only declared input, output, and collection references."
625
+ });
626
+ }
627
+ }
628
+ }
629
+ }
630
+ const publications = contributions.flatMap((item) => item.publications).sort(byId);
631
+ for (const publication of publications) {
632
+ const authorityIssue = publication._tag === "GraphNpmPublication"
633
+ ? npmPublicationAuthorityIssue(publication)
634
+ : publication._tag === "GraphPyPiPublication"
635
+ ? pyPiPublicationAuthorityIssue(publication)
636
+ : publication._tag === "GraphGitHubPublication"
637
+ ? githubPublicationAuthorityIssue(publication)
638
+ : catalogPublicationAuthorityIssue(publication);
639
+ if (authorityIssue !== undefined)
640
+ throw new GraphLinkError({
641
+ kind: "reference", value: publication.id.toString(), reason: authorityIssue
642
+ });
643
+ if (publication._tag === "GraphGitHubPublication" && publication.body !== undefined && publication.bodyArtifact !== undefined) {
644
+ throw new GraphLinkError({ kind: "reference", value: publication.id.toString(), reason: "GitHub body must be inline text or one text artifact, not both." });
645
+ }
646
+ if (publication._tag === "GraphGitHubPublication") {
647
+ const selected = new Set();
648
+ for (const selector of publication.assetCollections) {
649
+ const id = selector.collection.toString();
650
+ if (selected.has(id))
651
+ throw new GraphLinkError({
652
+ kind: "duplicate", value: id, reason: "GitHub publication repeats one artifact collection selector."
653
+ });
654
+ selected.add(id);
655
+ const contract = collectionIds.get(id);
656
+ if (contract === undefined)
657
+ throw new GraphLinkError({
658
+ kind: "missing", value: id, reason: "GitHub publication selector references no artifact collection."
659
+ });
660
+ const issue = cardinalityIssue(selector.cardinality);
661
+ if (issue !== undefined)
662
+ throw new GraphLinkError({ kind: "reference", value: id, reason: issue });
663
+ if (!cardinalitiesOverlap(contract.cardinality, selector.cardinality))
664
+ throw new GraphLinkError({
665
+ kind: "reference", value: id,
666
+ reason: "GitHub publication cardinality cannot be satisfied by the producer collection contract."
667
+ });
668
+ if (selector.artifactKind !== contract.artifactKind || selector.pathSuffix !== contract.pathSuffix ||
669
+ selector.mediaType !== contract.mediaType)
670
+ throw new GraphLinkError({
671
+ kind: "reference", value: id,
672
+ reason: "GitHub publication selector kind, path suffix, and media type must exactly match its collection contract."
673
+ });
674
+ }
675
+ }
676
+ const ids = publication._tag === "GraphGitHubPublication"
677
+ ? [...publication.assetIds, ...(publication.bodyArtifact === undefined ? [] : [publication.bodyArtifact])]
678
+ : publication._tag === "GraphPyPiPublication"
679
+ ? publication.files.map((file) => file.artifactId)
680
+ : publication._tag === "GraphCatalogPublication"
681
+ ? [publication.targetArtifact]
682
+ : [publication.packageArtifact];
683
+ for (const id of ids)
684
+ if (!artifactIds.has(id.toString()) && !producers.has(id.toString())) {
685
+ throw new GraphLinkError({ kind: "missing", value: id.toString(), reason: "Publication references no artifact." });
686
+ }
687
+ if (publication._tag === "GraphNpmPublication") {
688
+ const packageArtifact = artifacts.find((artifact) => artifact.id === publication.packageArtifact);
689
+ if (packageArtifact?.kind !== "package")
690
+ throw new GraphLinkError({
691
+ kind: "reference", value: publication.packageArtifact.toString(),
692
+ reason: "npm publication must reference exactly one declared package artifact."
693
+ });
694
+ if (publication.access === "restricted" && !publication.packageName.startsWith("@"))
695
+ throw new GraphLinkError({
696
+ kind: "reference", value: publication.packageName.toString(),
697
+ reason: "npm restricted access is valid only for scoped package names."
698
+ });
699
+ }
700
+ if (publication._tag === "GraphPyPiPublication") {
701
+ for (const file of publication.files) {
702
+ const artifact = artifacts.find((candidate) => candidate.id.toString() === file.artifactId.toString());
703
+ if (artifact === undefined || artifact.kind === "package")
704
+ throw new GraphLinkError({
705
+ kind: "reference", value: file.artifactId.toString(),
706
+ reason: "PyPI distributions must reference capturable file artifacts."
707
+ });
708
+ if (artifact.path.toString().split("/").at(-1) !== file.filename.toString())
709
+ throw new GraphLinkError({
710
+ kind: "reference", value: file.artifactId.toString(),
711
+ reason: "PyPI distribution authority filename must equal the declared artifact basename."
712
+ });
713
+ }
714
+ }
715
+ if (publication._tag === "GraphGitHubPublication" && publication.bodyArtifact !== undefined) {
716
+ const body = artifacts.find((artifact) => artifact.id.toString() === publication.bodyArtifact.toString());
717
+ if (body === undefined || body.mediaType === undefined || !body.mediaType.startsWith("text/"))
718
+ throw new GraphLinkError({
719
+ kind: "reference", value: publication.bodyArtifact.toString(), reason: "GitHub body artifacts must declare a text/* media type."
720
+ });
721
+ }
722
+ if (publication._tag === "GraphGitHubPublication") {
723
+ for (const id of publication.assetIds) {
724
+ const asset = artifacts.find((artifact) => artifact.id.toString() === id.toString());
725
+ if (asset === undefined || asset.kind === "package")
726
+ throw new GraphLinkError({
727
+ kind: "reference", value: id.toString(), reason: "GitHub assets must be capturable file artifacts."
728
+ });
729
+ }
730
+ }
731
+ if (publication._tag === "GraphCatalogPublication") {
732
+ const artifact = artifacts.find((candidate) => candidate.id.toString() === publication.targetArtifact.toString());
733
+ const producer = preparations.find((candidate) => preparationOutputs(candidate).some((output) => output.id.toString() === publication.targetArtifact.toString()));
734
+ if (artifact === undefined || artifact.kind !== "file" || producer?._tag !== "GraphCatalogRender" ||
735
+ producer.renderer._tag !== publication.renderer._tag ||
736
+ producer.sources.map((source) => source.artifactId.toString()).join("\n") !==
737
+ publication.sources.map((source) => source.artifactId.toString()).join("\n")) {
738
+ throw new GraphLinkError({
739
+ kind: "reference", value: publication.targetArtifact.toString(),
740
+ reason: "Catalog delivery must reference its exact typed catalog-render output."
741
+ });
742
+ }
743
+ if (publication.targetPath.toString() === publication.statePath.toString())
744
+ throw new GraphLinkError({
745
+ kind: "path", value: publication.targetPath.toString(),
746
+ reason: "Catalog target and managed-state paths must be distinct."
747
+ });
748
+ }
749
+ }
750
+ const dependencies = new Map(preparations.map((preparation) => [preparation.id.toString(), new Set(preparationInputs(preparation).map((input) => producers.get(input.toString())).filter((value) => value !== undefined))]));
751
+ const ordered = [];
752
+ const pending = new Map(preparations.map((preparation) => [preparation.id.toString(), preparation]));
753
+ while (pending.size > 0) {
754
+ const ready = [...pending.values()].filter((preparation) => [...dependencies.get(preparation.id.toString())].every((dependency) => !pending.has(dependency))).sort(byId);
755
+ if (ready.length === 0)
756
+ throw new GraphLinkError({
757
+ kind: "cycle", value: [...pending.keys()].sort().join(","), reason: "Preparation dependency cycle."
758
+ });
759
+ for (const preparation of ready) {
760
+ pending.delete(preparation.id.toString());
761
+ ordered.push(preparation);
762
+ }
763
+ }
764
+ return ReleaseGraph.make({ artifacts, collections, preparations: ordered, publications });
765
+ };
766
+ //# sourceMappingURL=graph.js.map