@homeflare/alchemy 0.1.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 (417) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +62 -0
  3. package/dist/cloudflare/client.d.ts +45 -0
  4. package/dist/cloudflare/client.d.ts.map +1 -0
  5. package/dist/cloudflare/index.d.ts +11 -0
  6. package/dist/cloudflare/index.d.ts.map +1 -0
  7. package/dist/cloudflare/index.js +129 -0
  8. package/dist/cloudflare/index.js.map +13 -0
  9. package/dist/cloudflare/lock-rules.d.ts +50 -0
  10. package/dist/cloudflare/lock-rules.d.ts.map +1 -0
  11. package/dist/cloudflare/providers.d.ts +19 -0
  12. package/dist/cloudflare/providers.d.ts.map +1 -0
  13. package/dist/cloudflare/r2-bucket-lock.d.ts +100 -0
  14. package/dist/cloudflare/r2-bucket-lock.d.ts.map +1 -0
  15. package/dist/forgejo/branch-protection-form.d.ts +19 -0
  16. package/dist/forgejo/branch-protection-form.d.ts.map +1 -0
  17. package/dist/forgejo/branch-protection.d.ts +47 -0
  18. package/dist/forgejo/branch-protection.d.ts.map +1 -0
  19. package/dist/forgejo/client.d.ts +37 -0
  20. package/dist/forgejo/client.d.ts.map +1 -0
  21. package/dist/forgejo/index.d.ts +18 -0
  22. package/dist/forgejo/index.d.ts.map +1 -0
  23. package/dist/forgejo/index.js +479 -0
  24. package/dist/forgejo/index.js.map +21 -0
  25. package/dist/forgejo/org-actions-secrets.d.ts +45 -0
  26. package/dist/forgejo/org-actions-secrets.d.ts.map +1 -0
  27. package/dist/forgejo/org-label.d.ts +46 -0
  28. package/dist/forgejo/org-label.d.ts.map +1 -0
  29. package/dist/forgejo/org-team.d.ts +42 -0
  30. package/dist/forgejo/org-team.d.ts.map +1 -0
  31. package/dist/forgejo/repo-webhook-form.d.ts +27 -0
  32. package/dist/forgejo/repo-webhook-form.d.ts.map +1 -0
  33. package/dist/forgejo/repo-webhook.d.ts +46 -0
  34. package/dist/forgejo/repo-webhook.d.ts.map +1 -0
  35. package/dist/forgejo/repository.d.ts +45 -0
  36. package/dist/forgejo/repository.d.ts.map +1 -0
  37. package/dist/forgejo/resource.d.ts +83 -0
  38. package/dist/forgejo/resource.d.ts.map +1 -0
  39. package/dist/forgejo/team-member.d.ts +39 -0
  40. package/dist/forgejo/team-member.d.ts.map +1 -0
  41. package/dist/forgejo/values.d.ts +24 -0
  42. package/dist/forgejo/values.d.ts.map +1 -0
  43. package/dist/index.d.ts +18 -0
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/index.js +3 -0
  46. package/dist/index.js.map +9 -0
  47. package/dist/openbao/auth-role-form.d.ts +38 -0
  48. package/dist/openbao/auth-role-form.d.ts.map +1 -0
  49. package/dist/openbao/auth-role.d.ts +20 -0
  50. package/dist/openbao/auth-role.d.ts.map +1 -0
  51. package/dist/openbao/bao-address.d.ts +72 -0
  52. package/dist/openbao/bao-address.d.ts.map +1 -0
  53. package/dist/openbao/bao-http.d.ts +71 -0
  54. package/dist/openbao/bao-http.d.ts.map +1 -0
  55. package/dist/openbao/bao-status.d.ts +74 -0
  56. package/dist/openbao/bao-status.d.ts.map +1 -0
  57. package/dist/openbao/cloudflare-group-scope.d.ts +73 -0
  58. package/dist/openbao/cloudflare-group-scope.d.ts.map +1 -0
  59. package/dist/openbao/cloudflare-parity-catalog.d.ts +28 -0
  60. package/dist/openbao/cloudflare-parity-catalog.d.ts.map +1 -0
  61. package/dist/openbao/cloudflare-parity-snapshot.d.ts +31 -0
  62. package/dist/openbao/cloudflare-parity-snapshot.d.ts.map +1 -0
  63. package/dist/openbao/cloudflare-parity.d.ts +14 -0
  64. package/dist/openbao/cloudflare-parity.d.ts.map +1 -0
  65. package/dist/openbao/cloudflare-permission-groups-solve.d.ts +85 -0
  66. package/dist/openbao/cloudflare-permission-groups-solve.d.ts.map +1 -0
  67. package/dist/openbao/cloudflare-permission-groups.d.ts +87 -0
  68. package/dist/openbao/cloudflare-permission-groups.d.ts.map +1 -0
  69. package/dist/openbao/cloudflare-policy.d.ts +65 -0
  70. package/dist/openbao/cloudflare-policy.d.ts.map +1 -0
  71. package/dist/openbao/cloudflare-role-form.d.ts +110 -0
  72. package/dist/openbao/cloudflare-role-form.d.ts.map +1 -0
  73. package/dist/openbao/cloudflare-role-wire.d.ts +27 -0
  74. package/dist/openbao/cloudflare-role-wire.d.ts.map +1 -0
  75. package/dist/openbao/cloudflare-role.d.ts +35 -0
  76. package/dist/openbao/cloudflare-role.d.ts.map +1 -0
  77. package/dist/openbao/cloudflare-roles-config.d.ts +67 -0
  78. package/dist/openbao/cloudflare-roles-config.d.ts.map +1 -0
  79. package/dist/openbao/cloudflare-roles-expand.d.ts +76 -0
  80. package/dist/openbao/cloudflare-roles-expand.d.ts.map +1 -0
  81. package/dist/openbao/digest.d.ts +24 -0
  82. package/dist/openbao/digest.d.ts.map +1 -0
  83. package/dist/openbao/fake-bao.d.ts +40 -0
  84. package/dist/openbao/fake-bao.d.ts.map +1 -0
  85. package/dist/openbao/forgejo-bootstrap-parse.d.ts +46 -0
  86. package/dist/openbao/forgejo-bootstrap-parse.d.ts.map +1 -0
  87. package/dist/openbao/forgejo-bootstrap.d.ts +29 -0
  88. package/dist/openbao/forgejo-bootstrap.d.ts.map +1 -0
  89. package/dist/openbao/index.d.ts +18 -0
  90. package/dist/openbao/index.d.ts.map +1 -0
  91. package/dist/openbao/index.js +1158 -0
  92. package/dist/openbao/index.js.map +33 -0
  93. package/dist/openbao/mount-form.d.ts +60 -0
  94. package/dist/openbao/mount-form.d.ts.map +1 -0
  95. package/dist/openbao/mount-wire.d.ts +24 -0
  96. package/dist/openbao/mount-wire.d.ts.map +1 -0
  97. package/dist/openbao/mount.d.ts +20 -0
  98. package/dist/openbao/mount.d.ts.map +1 -0
  99. package/dist/openbao/pki-role-form.d.ts +118 -0
  100. package/dist/openbao/pki-role-form.d.ts.map +1 -0
  101. package/dist/openbao/pki-role.d.ts +50 -0
  102. package/dist/openbao/pki-role.d.ts.map +1 -0
  103. package/dist/openbao/policy-assembly.d.ts +13 -0
  104. package/dist/openbao/policy-assembly.d.ts.map +1 -0
  105. package/dist/openbao/policy-wire.d.ts +41 -0
  106. package/dist/openbao/policy-wire.d.ts.map +1 -0
  107. package/dist/openbao/policy.d.ts +83 -0
  108. package/dist/openbao/policy.d.ts.map +1 -0
  109. package/dist/openbao/proxmox-role-form.d.ts +92 -0
  110. package/dist/openbao/proxmox-role-form.d.ts.map +1 -0
  111. package/dist/openbao/proxmox-role.d.ts +47 -0
  112. package/dist/openbao/proxmox-role.d.ts.map +1 -0
  113. package/dist/openbao/ssh-role-form.d.ts +99 -0
  114. package/dist/openbao/ssh-role-form.d.ts.map +1 -0
  115. package/dist/openbao/ssh-role.d.ts +43 -0
  116. package/dist/openbao/ssh-role.d.ts.map +1 -0
  117. package/dist/proxmox/acl.d.ts +72 -0
  118. package/dist/proxmox/acl.d.ts.map +1 -0
  119. package/dist/proxmox/api-token-form.d.ts +59 -0
  120. package/dist/proxmox/api-token-form.d.ts.map +1 -0
  121. package/dist/proxmox/api-token.d.ts +159 -0
  122. package/dist/proxmox/api-token.d.ts.map +1 -0
  123. package/dist/proxmox/backup-job.d.ts +112 -0
  124. package/dist/proxmox/backup-job.d.ts.map +1 -0
  125. package/dist/proxmox/ceph-daemon-form.d.ts +70 -0
  126. package/dist/proxmox/ceph-daemon-form.d.ts.map +1 -0
  127. package/dist/proxmox/ceph-daemon.d.ts +162 -0
  128. package/dist/proxmox/ceph-daemon.d.ts.map +1 -0
  129. package/dist/proxmox/ceph-flag.d.ts +131 -0
  130. package/dist/proxmox/ceph-flag.d.ts.map +1 -0
  131. package/dist/proxmox/ceph-fs-wire.d.ts +106 -0
  132. package/dist/proxmox/ceph-fs-wire.d.ts.map +1 -0
  133. package/dist/proxmox/ceph-fs.d.ts +124 -0
  134. package/dist/proxmox/ceph-fs.d.ts.map +1 -0
  135. package/dist/proxmox/ceph-osd-tree.d.ts +154 -0
  136. package/dist/proxmox/ceph-osd-tree.d.ts.map +1 -0
  137. package/dist/proxmox/ceph-osd-write.d.ts +36 -0
  138. package/dist/proxmox/ceph-osd-write.d.ts.map +1 -0
  139. package/dist/proxmox/ceph-osd.d.ts +102 -0
  140. package/dist/proxmox/ceph-osd.d.ts.map +1 -0
  141. package/dist/proxmox/ceph-pool-form.d.ts +217 -0
  142. package/dist/proxmox/ceph-pool-form.d.ts.map +1 -0
  143. package/dist/proxmox/ceph-pool-settle.d.ts +39 -0
  144. package/dist/proxmox/ceph-pool-settle.d.ts.map +1 -0
  145. package/dist/proxmox/ceph-pool.d.ts +48 -0
  146. package/dist/proxmox/ceph-pool.d.ts.map +1 -0
  147. package/dist/proxmox/client.d.ts +64 -0
  148. package/dist/proxmox/client.d.ts.map +1 -0
  149. package/dist/proxmox/credentials.d.ts +153 -0
  150. package/dist/proxmox/credentials.d.ts.map +1 -0
  151. package/dist/proxmox/firewall-alias-form.d.ts +98 -0
  152. package/dist/proxmox/firewall-alias-form.d.ts.map +1 -0
  153. package/dist/proxmox/firewall-alias.d.ts +141 -0
  154. package/dist/proxmox/firewall-alias.d.ts.map +1 -0
  155. package/dist/proxmox/generated/pbs.d.ts +388 -0
  156. package/dist/proxmox/generated/pbs.d.ts.map +1 -0
  157. package/dist/proxmox/generated/pve.d.ts +4713 -0
  158. package/dist/proxmox/generated/pve.d.ts.map +1 -0
  159. package/dist/proxmox/group.d.ts +104 -0
  160. package/dist/proxmox/group.d.ts.map +1 -0
  161. package/dist/proxmox/ha-resource.d.ts +104 -0
  162. package/dist/proxmox/ha-resource.d.ts.map +1 -0
  163. package/dist/proxmox/ha-rule-form.d.ts +103 -0
  164. package/dist/proxmox/ha-rule-form.d.ts.map +1 -0
  165. package/dist/proxmox/ha-rule.d.ts +156 -0
  166. package/dist/proxmox/ha-rule.d.ts.map +1 -0
  167. package/dist/proxmox/index.d.ts +43 -0
  168. package/dist/proxmox/index.d.ts.map +1 -0
  169. package/dist/proxmox/index.js +2322 -0
  170. package/dist/proxmox/index.js.map +70 -0
  171. package/dist/proxmox/lease-cache.d.ts +98 -0
  172. package/dist/proxmox/lease-cache.d.ts.map +1 -0
  173. package/dist/proxmox/lxc.d.ts +59 -0
  174. package/dist/proxmox/lxc.d.ts.map +1 -0
  175. package/dist/proxmox/members.d.ts +56 -0
  176. package/dist/proxmox/members.d.ts.map +1 -0
  177. package/dist/proxmox/metric-server-form.d.ts +53 -0
  178. package/dist/proxmox/metric-server-form.d.ts.map +1 -0
  179. package/dist/proxmox/metric-server-otel.d.ts +49 -0
  180. package/dist/proxmox/metric-server-otel.d.ts.map +1 -0
  181. package/dist/proxmox/metric-server.d.ts +123 -0
  182. package/dist/proxmox/metric-server.d.ts.map +1 -0
  183. package/dist/proxmox/network-apply-read.d.ts +93 -0
  184. package/dist/proxmox/network-apply-read.d.ts.map +1 -0
  185. package/dist/proxmox/network-apply.d.ts +102 -0
  186. package/dist/proxmox/network-apply.d.ts.map +1 -0
  187. package/dist/proxmox/node-network-form.d.ts +128 -0
  188. package/dist/proxmox/node-network-form.d.ts.map +1 -0
  189. package/dist/proxmox/node-network.d.ts +173 -0
  190. package/dist/proxmox/node-network.d.ts.map +1 -0
  191. package/dist/proxmox/notification-target-form.d.ts +44 -0
  192. package/dist/proxmox/notification-target-form.d.ts.map +1 -0
  193. package/dist/proxmox/notification-target.d.ts +146 -0
  194. package/dist/proxmox/notification-target.d.ts.map +1 -0
  195. package/dist/proxmox/pbs-datastore-form.d.ts +147 -0
  196. package/dist/proxmox/pbs-datastore-form.d.ts.map +1 -0
  197. package/dist/proxmox/pbs-datastore-guard.d.ts +55 -0
  198. package/dist/proxmox/pbs-datastore-guard.d.ts.map +1 -0
  199. package/dist/proxmox/pbs-datastore.d.ts +140 -0
  200. package/dist/proxmox/pbs-datastore.d.ts.map +1 -0
  201. package/dist/proxmox/pbs-prune-job-form.d.ts +97 -0
  202. package/dist/proxmox/pbs-prune-job-form.d.ts.map +1 -0
  203. package/dist/proxmox/pbs-prune-job.d.ts +168 -0
  204. package/dist/proxmox/pbs-prune-job.d.ts.map +1 -0
  205. package/dist/proxmox/pbs-sync-job-form.d.ts +83 -0
  206. package/dist/proxmox/pbs-sync-job-form.d.ts.map +1 -0
  207. package/dist/proxmox/pbs-sync-job.d.ts +246 -0
  208. package/dist/proxmox/pbs-sync-job.d.ts.map +1 -0
  209. package/dist/proxmox/pbs-verify-job-form.d.ts +114 -0
  210. package/dist/proxmox/pbs-verify-job-form.d.ts.map +1 -0
  211. package/dist/proxmox/pbs-verify-job.d.ts +145 -0
  212. package/dist/proxmox/pbs-verify-job.d.ts.map +1 -0
  213. package/dist/proxmox/pool.d.ts +42 -0
  214. package/dist/proxmox/pool.d.ts.map +1 -0
  215. package/dist/proxmox/qemu.d.ts +46 -0
  216. package/dist/proxmox/qemu.d.ts.map +1 -0
  217. package/dist/proxmox/replication-job-form.d.ts +71 -0
  218. package/dist/proxmox/replication-job-form.d.ts.map +1 -0
  219. package/dist/proxmox/replication-job.d.ts +162 -0
  220. package/dist/proxmox/replication-job.d.ts.map +1 -0
  221. package/dist/proxmox/resource.d.ts +157 -0
  222. package/dist/proxmox/resource.d.ts.map +1 -0
  223. package/dist/proxmox/role.d.ts +97 -0
  224. package/dist/proxmox/role.d.ts.map +1 -0
  225. package/dist/proxmox/sdn-apply-read.d.ts +80 -0
  226. package/dist/proxmox/sdn-apply-read.d.ts.map +1 -0
  227. package/dist/proxmox/sdn-apply.d.ts +63 -0
  228. package/dist/proxmox/sdn-apply.d.ts.map +1 -0
  229. package/dist/proxmox/sdn-subnet-form.d.ts +111 -0
  230. package/dist/proxmox/sdn-subnet-form.d.ts.map +1 -0
  231. package/dist/proxmox/sdn-subnet.d.ts +161 -0
  232. package/dist/proxmox/sdn-subnet.d.ts.map +1 -0
  233. package/dist/proxmox/sdn-vnet.d.ts +113 -0
  234. package/dist/proxmox/sdn-vnet.d.ts.map +1 -0
  235. package/dist/proxmox/sdn-zone.d.ts +126 -0
  236. package/dist/proxmox/sdn-zone.d.ts.map +1 -0
  237. package/dist/proxmox/storage.d.ts +120 -0
  238. package/dist/proxmox/storage.d.ts.map +1 -0
  239. package/dist/proxmox/user.d.ts +107 -0
  240. package/dist/proxmox/user.d.ts.map +1 -0
  241. package/dist/proxmox/values.d.ts +134 -0
  242. package/dist/proxmox/values.d.ts.map +1 -0
  243. package/dist/proxmox/zfs-pool-write.d.ts +76 -0
  244. package/dist/proxmox/zfs-pool-write.d.ts.map +1 -0
  245. package/dist/proxmox/zfs-pool.d.ts +146 -0
  246. package/dist/proxmox/zfs-pool.d.ts.map +1 -0
  247. package/dist/talos/credentials.d.ts +30 -0
  248. package/dist/talos/credentials.d.ts.map +1 -0
  249. package/dist/talos/index.d.ts +15 -0
  250. package/dist/talos/index.d.ts.map +1 -0
  251. package/dist/talos/index.js +392 -0
  252. package/dist/talos/index.js.map +16 -0
  253. package/dist/talos/kubeconfig.d.ts +53 -0
  254. package/dist/talos/kubeconfig.d.ts.map +1 -0
  255. package/dist/talos/resource.d.ts +32 -0
  256. package/dist/talos/resource.d.ts.map +1 -0
  257. package/dist/talos/talos-bootstrap.d.ts +27 -0
  258. package/dist/talos/talos-bootstrap.d.ts.map +1 -0
  259. package/dist/talos/talos-cluster-health.d.ts +36 -0
  260. package/dist/talos/talos-cluster-health.d.ts.map +1 -0
  261. package/dist/talos/talos-machine-config.d.ts +41 -0
  262. package/dist/talos/talos-machine-config.d.ts.map +1 -0
  263. package/dist/talos/talosctl.d.ts +29 -0
  264. package/dist/talos/talosctl.d.ts.map +1 -0
  265. package/dist/talos/values.d.ts +20 -0
  266. package/dist/talos/values.d.ts.map +1 -0
  267. package/package.json +57 -0
  268. package/src/cloudflare/client.ts +76 -0
  269. package/src/cloudflare/index.ts +10 -0
  270. package/src/cloudflare/lock-rules.ts +60 -0
  271. package/src/cloudflare/providers.ts +23 -0
  272. package/src/cloudflare/r2-bucket-lock.ts +220 -0
  273. package/src/forgejo/branch-protection-form.ts +29 -0
  274. package/src/forgejo/branch-protection.ts +101 -0
  275. package/src/forgejo/client.ts +136 -0
  276. package/src/forgejo/index.ts +17 -0
  277. package/src/forgejo/org-actions-secrets.ts +99 -0
  278. package/src/forgejo/org-label.ts +100 -0
  279. package/src/forgejo/org-team.ts +105 -0
  280. package/src/forgejo/repo-webhook-form.ts +47 -0
  281. package/src/forgejo/repo-webhook.ts +118 -0
  282. package/src/forgejo/repository.ts +126 -0
  283. package/src/forgejo/resource.ts +171 -0
  284. package/src/forgejo/team-member.ts +97 -0
  285. package/src/forgejo/values.test.ts +48 -0
  286. package/src/forgejo/values.ts +61 -0
  287. package/src/index.ts +18 -0
  288. package/src/openbao/auth-role-form.ts +112 -0
  289. package/src/openbao/auth-role.ts +101 -0
  290. package/src/openbao/bao-address.test.ts +89 -0
  291. package/src/openbao/bao-address.ts +97 -0
  292. package/src/openbao/bao-http-gate.test.ts +88 -0
  293. package/src/openbao/bao-http-unix.test.ts +70 -0
  294. package/src/openbao/bao-http.test.ts +161 -0
  295. package/src/openbao/bao-http.ts +185 -0
  296. package/src/openbao/bao-status.test.ts +114 -0
  297. package/src/openbao/bao-status.ts +137 -0
  298. package/src/openbao/cloudflare-group-scope.test.ts +103 -0
  299. package/src/openbao/cloudflare-group-scope.ts +83 -0
  300. package/src/openbao/cloudflare-parity-catalog.ts +104 -0
  301. package/src/openbao/cloudflare-parity-snapshot.ts +84 -0
  302. package/src/openbao/cloudflare-parity.ts +152 -0
  303. package/src/openbao/cloudflare-permission-groups-solve.test.ts +171 -0
  304. package/src/openbao/cloudflare-permission-groups-solve.ts +197 -0
  305. package/src/openbao/cloudflare-permission-groups.test.ts +369 -0
  306. package/src/openbao/cloudflare-permission-groups.ts +299 -0
  307. package/src/openbao/cloudflare-policy.ts +180 -0
  308. package/src/openbao/cloudflare-role-form.test.ts +177 -0
  309. package/src/openbao/cloudflare-role-form.ts +183 -0
  310. package/src/openbao/cloudflare-role-wire.test.ts +132 -0
  311. package/src/openbao/cloudflare-role-wire.ts +41 -0
  312. package/src/openbao/cloudflare-role.ts +189 -0
  313. package/src/openbao/cloudflare-roles-config.ts +230 -0
  314. package/src/openbao/cloudflare-roles-expand-bucket.test.ts +134 -0
  315. package/src/openbao/cloudflare-roles-expand.ts +231 -0
  316. package/src/openbao/digest.ts +26 -0
  317. package/src/openbao/fake-bao.ts +84 -0
  318. package/src/openbao/forgejo-bootstrap-parse.test.ts +76 -0
  319. package/src/openbao/forgejo-bootstrap-parse.ts +90 -0
  320. package/src/openbao/forgejo-bootstrap.ts +181 -0
  321. package/src/openbao/index.ts +17 -0
  322. package/src/openbao/mount-form.ts +147 -0
  323. package/src/openbao/mount-wire.test.ts +108 -0
  324. package/src/openbao/mount-wire.ts +79 -0
  325. package/src/openbao/mount.ts +132 -0
  326. package/src/openbao/pki-role-form.ts +248 -0
  327. package/src/openbao/pki-role.ts +202 -0
  328. package/src/openbao/policy-assembly.test.ts +28 -0
  329. package/src/openbao/policy-assembly.ts +13 -0
  330. package/src/openbao/policy-wire.test.ts +90 -0
  331. package/src/openbao/policy-wire.ts +53 -0
  332. package/src/openbao/policy.ts +212 -0
  333. package/src/openbao/proxmox-role-form.ts +174 -0
  334. package/src/openbao/proxmox-role.ts +214 -0
  335. package/src/openbao/ssh-role-form.ts +248 -0
  336. package/src/openbao/ssh-role.ts +240 -0
  337. package/src/proxmox/acl.ts +267 -0
  338. package/src/proxmox/api-token-form.ts +122 -0
  339. package/src/proxmox/api-token.ts +222 -0
  340. package/src/proxmox/backup-job.ts +213 -0
  341. package/src/proxmox/ceph-daemon-form.ts +84 -0
  342. package/src/proxmox/ceph-daemon.ts +243 -0
  343. package/src/proxmox/ceph-flag.ts +249 -0
  344. package/src/proxmox/ceph-fs-wire.ts +246 -0
  345. package/src/proxmox/ceph-fs.ts +249 -0
  346. package/src/proxmox/ceph-osd-tree.ts +193 -0
  347. package/src/proxmox/ceph-osd-write.ts +76 -0
  348. package/src/proxmox/ceph-osd.ts +244 -0
  349. package/src/proxmox/ceph-pool-form.ts +249 -0
  350. package/src/proxmox/ceph-pool-settle.ts +70 -0
  351. package/src/proxmox/ceph-pool.ts +212 -0
  352. package/src/proxmox/client.test.ts +185 -0
  353. package/src/proxmox/client.ts +240 -0
  354. package/src/proxmox/credentials.test.ts +144 -0
  355. package/src/proxmox/credentials.ts +254 -0
  356. package/src/proxmox/firewall-alias-form.ts +112 -0
  357. package/src/proxmox/firewall-alias.ts +208 -0
  358. package/src/proxmox/generated/pbs.ts +461 -0
  359. package/src/proxmox/generated/pve.ts +7344 -0
  360. package/src/proxmox/group.ts +199 -0
  361. package/src/proxmox/ha-resource.ts +169 -0
  362. package/src/proxmox/ha-rule-form.ts +185 -0
  363. package/src/proxmox/ha-rule.ts +240 -0
  364. package/src/proxmox/index.ts +42 -0
  365. package/src/proxmox/lease-cache.test.ts +163 -0
  366. package/src/proxmox/lease-cache.ts +131 -0
  367. package/src/proxmox/lxc.ts +117 -0
  368. package/src/proxmox/members.test.ts +54 -0
  369. package/src/proxmox/members.ts +174 -0
  370. package/src/proxmox/metric-server-form.ts +128 -0
  371. package/src/proxmox/metric-server-otel.ts +99 -0
  372. package/src/proxmox/metric-server.ts +214 -0
  373. package/src/proxmox/network-apply-read.ts +228 -0
  374. package/src/proxmox/network-apply.ts +244 -0
  375. package/src/proxmox/node-network-form.ts +213 -0
  376. package/src/proxmox/node-network.ts +243 -0
  377. package/src/proxmox/notification-target-form.ts +104 -0
  378. package/src/proxmox/notification-target.ts +222 -0
  379. package/src/proxmox/pbs-datastore-form.ts +248 -0
  380. package/src/proxmox/pbs-datastore-guard.ts +105 -0
  381. package/src/proxmox/pbs-datastore.ts +271 -0
  382. package/src/proxmox/pbs-prune-job-form.ts +208 -0
  383. package/src/proxmox/pbs-prune-job.ts +227 -0
  384. package/src/proxmox/pbs-sync-job-form.ts +234 -0
  385. package/src/proxmox/pbs-sync-job.ts +258 -0
  386. package/src/proxmox/pbs-verify-job-form.ts +131 -0
  387. package/src/proxmox/pbs-verify-job.ts +227 -0
  388. package/src/proxmox/pool.test.ts +42 -0
  389. package/src/proxmox/pool.ts +80 -0
  390. package/src/proxmox/qemu.ts +89 -0
  391. package/src/proxmox/replication-job-form.ts +89 -0
  392. package/src/proxmox/replication-job.ts +248 -0
  393. package/src/proxmox/resource.ts +257 -0
  394. package/src/proxmox/role.ts +161 -0
  395. package/src/proxmox/sdn-apply-read.test.ts +152 -0
  396. package/src/proxmox/sdn-apply-read.ts +189 -0
  397. package/src/proxmox/sdn-apply.ts +154 -0
  398. package/src/proxmox/sdn-subnet-form.ts +156 -0
  399. package/src/proxmox/sdn-subnet.ts +238 -0
  400. package/src/proxmox/sdn-vnet.ts +228 -0
  401. package/src/proxmox/sdn-zone.ts +246 -0
  402. package/src/proxmox/storage.ts +245 -0
  403. package/src/proxmox/user.ts +214 -0
  404. package/src/proxmox/values.test.ts +193 -0
  405. package/src/proxmox/values.ts +203 -0
  406. package/src/proxmox/zfs-pool-write.ts +130 -0
  407. package/src/proxmox/zfs-pool.ts +253 -0
  408. package/src/talos/credentials.ts +136 -0
  409. package/src/talos/index.ts +14 -0
  410. package/src/talos/kubeconfig.ts +170 -0
  411. package/src/talos/resource.ts +31 -0
  412. package/src/talos/talos-bootstrap.ts +109 -0
  413. package/src/talos/talos-cluster-health.ts +119 -0
  414. package/src/talos/talos-machine-config.ts +146 -0
  415. package/src/talos/talosctl.ts +94 -0
  416. package/src/talos/values.test.ts +80 -0
  417. package/src/talos/values.ts +70 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudflare-permission-groups-solve.d.ts","sourceRoot":"","sources":["../../src/openbao/cloudflare-permission-groups-solve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAEjE,MAAM,WAAW,WAAW;IAC1B,+CAA+C;IAC/C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,QAAQ;IACvB,mEAAmE;IACnE,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC;AAED,wFAAwF;AACxF,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,MAAM;IACrB,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7C,QAAQ,CAAC,SAAS,EAAE,SAAS,QAAQ,EAAE,CAAC;IACxC,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,QAAQ,CAAC,YAAY,EAAE,SAAS,aAAa,EAAE,CAAC;CACjD;AAED;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,aACf,SAAS,YAAY,EAAE,QAC3B,WAAW,CAAC,MAAM,EAAE,SAAS,UAAU,EAAE,CAAC,KAC/C,WAAW,EAmBV,CAAC;AAIL,eAAO,MAAM,WAAW,iBAAkB,SAAS,WAAW,EAAE,KAAG,MAsElE,CAAC;AAEF,wEAAwE;AACxE,eAAO,MAAM,gBAAgB,WAAY,MAAM,KAAG,MAAM,EAYvD,CAAC"}
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Permission-group (name, SCOPE) → ID, behind ONE interface with two sources.
3
+ *
4
+ * ⛔ THE KEY IS THE PAIR, AND THAT IS NOT PEDANTRY. MEASURED 2026-09-15 the hour the grant went
5
+ * live: of the account's 401 groups, SEVEN names are listed twice — `Access: Apps and Policies
6
+ * Read`/`Revoke`/`Write`, `Disable ESC Read`/`Write`, `Logs Read`/`Write` — each pair one id
7
+ * scoped `com.cloudflare.api.account` and one scoped `com.cloudflare.api.account.zone`. Keyed by
8
+ * name alone the whole plan fails as ambiguous; keyed by name alone and forgiving, cfhf.py:148's
9
+ * last-one-wins picks a group gated at the wrong scope and the token is refused at first use.
10
+ * The asking ENTRY says which: its `scope` (roles.yaml `groups_scope:`), else its resource.
11
+ *
12
+ * ★ A SERVICE, NOT A TABLE. roles.yaml names groups (`DNS Read`); a role stores IDs. apply-roles.py
13
+ * resolved them per account with a Cloudflare parent credential (cfhf.py:147-148), which agents
14
+ * may not use. So Bao.CloudflareRole asks this service, and the stack chooses the source:
15
+ *
16
+ * a) `permissionGroupsFromEngine` — `GET <mount>/permission-groups` on the Cloudflare engine,
17
+ * answered under the mount's own parent. ★ DEPLOYED AND WIRED 2026-09-15: `bao path-help
18
+ * cloudflare-<account>-platform` lists `^permission-groups$` on plugin v0.0.0-dev, and
19
+ * cloudflare-roles.ts now provides this source to the stack.
20
+ * b) `permissionGroupsFromLiveRoles` — ⚠️ TEMPORARY, AND STILL HERE ON PURPOSE. 2026-09-15: no
21
+ * longer the stack's source, and NOT yet deletable. Two things gate that — (1) the live
22
+ * `result_info` envelope pinned in ../../platform/secrets/vault/plugin/cloudflare/
23
+ * client_result_info.go, whose own header names this deletion as what it gates, and (2)
24
+ * cloudflare-parity.ts, which calls cloudflare-permission-groups-solve.ts directly for the
25
+ * OFFLINE proof against a production export and has no engine to ask. So (b) and the solver
26
+ * stay, one import from being the layer again (cloudflare-roles.ts), until the last step of
27
+ * docs/ledger/openbao-permission-groups-engine-2026-09-15.md is done.
28
+ *
29
+ * ⛔ AN UNKNOWN NAME FAILS THE OPERATION. Dropping it would write a policy one group short, and the
30
+ * engine refuses an empty ID (path_roles.go:181-185) but not a SHORTER list: the minted token is
31
+ * quietly narrower than declared, and the consumer finds out at 403.
32
+ */
33
+ import * as Context from 'effect/Context';
34
+ import * as Effect from 'effect/Effect';
35
+ import type * as HttpClient from 'effect/unstable/http/HttpClient';
36
+ import type { BaoError } from './bao-status.ts';
37
+ import type { ExpandedRole } from './cloudflare-roles-expand.ts';
38
+ export declare class CloudflareGroupsError extends Error {
39
+ readonly scope: string;
40
+ readonly problems: readonly string[];
41
+ constructor(scope: string, problems: readonly string[]);
42
+ }
43
+ /** ⛔ Keyed by `groupKey(name, scope)` throughout — see cloudflare-group-scope.ts. */
44
+ type Groups = ReadonlyMap<string, string>;
45
+ /** One group a role asks for: its name, and the scope the entry naming it is gated at. */
46
+ export interface GroupRef {
47
+ readonly name: string;
48
+ readonly scope: string;
49
+ }
50
+ declare const CloudflarePermissionGroups_base: Context.ServiceClass<CloudflarePermissionGroups, "homeflare/openbao/CloudflarePermissionGroups", {
51
+ /** The ID of every ref, keyed by `groupKey` — or a failure naming what did not resolve. */
52
+ readonly resolve: (mount: string, refs: readonly GroupRef[]) => Effect.Effect<Groups, BaoError | CloudflareGroupsError, HttpClient.HttpClient>;
53
+ }>;
54
+ export declare class CloudflarePermissionGroups extends CloudflarePermissionGroups_base {
55
+ }
56
+ /**
57
+ * ★ ONE FETCH PER MOUNT PER RUN, not one per role — 586 roles would otherwise ask 586 times.
58
+ * ⚠️ A FAILURE IS CACHED TOO (Effect.cached keeps the Exit), so one sealed-vault 503 fails every
59
+ * role on that mount for the rest of the run. That is the honest outcome for a plan: retrying
60
+ * 586 times against a sealed server would only make the failure slower.
61
+ */
62
+ export declare const permissionGroupsFromEngine: () => Effect.Effect<{
63
+ /** The ID of every ref, keyed by `groupKey` — or a failure naming what did not resolve. */
64
+ readonly resolve: (mount: string, refs: readonly GroupRef[]) => Effect.Effect<Groups, BaoError | CloudflareGroupsError, HttpClient.HttpClient>;
65
+ }, never, never>;
66
+ /**
67
+ * b) ⚠️ TEMPORARY, AND NO LONGER THE STACK'S SOURCE SINCE 2026-09-15 — see the header for the two
68
+ * things that gate deleting it. Reads every DECLARED role of an account — no LIST, because an
69
+ * undeclared live role carries IDs with no names to pair them with — and solves the account at
70
+ * once.
71
+ * 🔴 WHAT RETIRED IT, 2026-09-15 10:13: `alchemy deploy` could not create
72
+ * `cloudflare-{<account>,testing}-platform/roles/r2-backup-mini` — `unknown group "Workers R2
73
+ * Storage Bucket Item Write" — no live role on account <account> carries it; a NEW group needs
74
+ * the engine endpoint`. That is this source's documented blind spot arriving, not a bug in it.
75
+ *
76
+ * ★ PER ACCOUNT, NOT PER MOUNT, BECAUSE ONE MOUNT CANNOT SOLVE ITSELF. MEASURED on the snapshot:
77
+ * `aimto-app-alchemy-os-create` on the platform mount pairs `Email Routing Rules Write` and
78
+ * `DNS Write` with two unknown IDs, and neither group appears alone on that mount. The dns and
79
+ * security mounts of the same account isolate them. apply-roles.py's map was per account too
80
+ * (apply-roles.py:117).
81
+ */
82
+ export declare const permissionGroupsFromLiveRoles: (declared: ReadonlyMap<string, readonly ExpandedRole[]>) => Effect.Effect<{
83
+ /** The ID of every ref, keyed by `groupKey` — or a failure naming what did not resolve. */
84
+ readonly resolve: (mount: string, refs: readonly GroupRef[]) => Effect.Effect<Groups, BaoError | CloudflareGroupsError, HttpClient.HttpClient>;
85
+ }, never, never>;
86
+ export {};
87
+ //# sourceMappingURL=cloudflare-permission-groups.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudflare-permission-groups.d.ts","sourceRoot":"","sources":["../../src/openbao/cloudflare-permission-groups.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAC;AAC1C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,KAAK,UAAU,MAAM,iCAAiC,CAAC;AAEnE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAShD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAGjE,qBAAa,qBAAsB,SAAQ,KAAK;IAE5C,QAAQ,CAAC,KAAK,EAAE,MAAM;IACtB,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE;IAFtC,YACW,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,SAAS,MAAM,EAAE,EAIrC;CACF;AAED,qFAAqF;AACrF,KAAK,MAAM,GAAG,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAG1C,0FAA0F;AAC1F,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;;IAKG,2FAA2F;sBACzE,CAChB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,SAAS,QAAQ,EAAE,KACtB,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,GAAG,qBAAqB,EAAE,UAAU,CAAC,UAAU,CAAC;;AAPvF,qBAAa,0BAA2B,SAAQ,+BASG;CAAG;AA4HtD;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B;IAxInC,2FAA2F;sBACzE,CAChB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,SAAS,QAAQ,EAAE,KACtB,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,GAAG,qBAAqB,EAAE,UAAU,CAAC,UAAU,CAAC;gBAsJnF,CAAC;AAEL;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,6BAA6B,aAC9B,WAAW,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,CAAC;IA7KpD,2FAA2F;sBACzE,CAChB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,SAAS,QAAQ,EAAE,KACtB,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,GAAG,qBAAqB,EAAE,UAAU,CAAC,UAAU,CAAC;gBA+NnF,CAAC"}
@@ -0,0 +1,65 @@
1
+ import type { DeclaredPolicy } from './cloudflare-roles-expand.ts';
2
+ export interface WirePolicy {
3
+ readonly effect: string;
4
+ readonly resources: Readonly<Record<string, string>>;
5
+ readonly groupIds: readonly string[];
6
+ }
7
+ /** A declared entry with its IDs, still carrying how its group order is to be compared. */
8
+ export interface ResolvedPolicy extends WirePolicy {
9
+ readonly groupOrder: DeclaredPolicy['groupOrder'];
10
+ }
11
+ /**
12
+ * One name at every scope — what a source that cannot see scopes can honestly offer.
13
+ *
14
+ * ⚠️ IT IS A WIDENING, AND IT IS THE ASYMMETRY BETWEEN THE TWO SOURCES. The live-roles bootstrap
15
+ * and cloudflare-permission-groups-solve.ts recover `name → id` from roles that carry ids and no
16
+ * scopes, so they cannot tell the seven two-id names apart; the id they learned is offered for
17
+ * whatever scope an entry asks. The engine source keys by (name, scope) and never does this.
18
+ */
19
+ export declare const atEveryScope: (byName: ReadonlyMap<string, string>) => ReadonlyMap<string, string>;
20
+ /**
21
+ * Declared names to IDs, or the names `ids` lacks.
22
+ *
23
+ * ⛔ AN ENTRY LOOKS ITS GROUPS UP AT ITS OWN SCOPE (`groupKey`), not by name: a zone entry and an
24
+ * account entry of the same role can name one group and mean two different ids.
25
+ * ★ THE ACCOUNT ENTRY IS SORTED BY ID, EXACTLY AS cfhf.py:180 DID. ⚠️ Plain `sort()`, never
26
+ * `localeCompare`: Python's `sorted()` on str is codepoint order, and JavaScript's default sort
27
+ * is UTF-16 code-unit order, which agree on the lowercase hex these IDs are made of.
28
+ */
29
+ export declare const resolvePolicies: (declared: readonly DeclaredPolicy[], ids: ReadonlyMap<string, string>) => {
30
+ readonly policies: ResolvedPolicy[];
31
+ readonly missing: string[];
32
+ };
33
+ /**
34
+ * The live `policies` string parsed, or undefined when it is not a policy document.
35
+ *
36
+ * ⚠️ UNDEFINED IS NOT ABSENCE. It means the role exists and its policies could not be read, which
37
+ * compares unequal to every declaration — so it plans `update`, and reconcile's re-read refuses
38
+ * to call a write that still reads back like that a success.
39
+ */
40
+ export declare const parseLivePolicies: (raw: unknown) => WirePolicy[] | undefined;
41
+ /**
42
+ * The `policies` field for a write — the array cfhf.py:174-180 built, serialized.
43
+ *
44
+ * ⚠️ NOT BYTE-IDENTICAL TO WHAT PYTHON SENT, AND IT NEED NOT BE. `json.dumps` put a space after
45
+ * every `:` and `,`; this emits none. The engine unmarshals the string into structs
46
+ * (path_roles.go:161-166) and stores those, never the text, so the stored role and the read
47
+ * that diff compares are the same either way.
48
+ */
49
+ export declare const policiesJson: (policies: readonly WirePolicy[]) => string;
50
+ /**
51
+ * ⛔ THE POLICY EQUALITY.
52
+ *
53
+ * • Entry count and entry ORDER must match: cfhf.py always wrote the scope entry first and the
54
+ * account entry second (cfhf.py:174-180).
55
+ * • Within an entry: effect, the resource map, and the group IDs — IN ORDER for a `declared`
56
+ * entry, because cfhf.py:175 kept yaml order; AS A SORTED LIST for a `by-id` entry, because
57
+ * cfhf.py:180 sorted it, so its order never carried meaning.
58
+ *
59
+ * ⚠️ NOT ORDER-INSENSITIVE EVERYWHERE, ON PURPOSE. Cloudflare treats a group list as a set, so a
60
+ * reordered `declared` entry mints an identical token — and still plans `update` here. The
61
+ * Python would have rewritten it as well, and an adoption that is noop only up to reordering
62
+ * would not prove the port exact.
63
+ */
64
+ export declare const samePolicies: (want: readonly ResolvedPolicy[], have: readonly WirePolicy[]) => boolean;
65
+ //# sourceMappingURL=cloudflare-policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudflare-policy.d.ts","sourceRoot":"","sources":["../../src/openbao/cloudflare-policy.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAEnE,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACrD,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC;AAED,2FAA2F;AAC3F,MAAM,WAAW,cAAe,SAAQ,UAAU;IAChD,QAAQ,CAAC,UAAU,EAAE,cAAc,CAAC,YAAY,CAAC,CAAC;CACnD;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY,WAAY,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,KAAG,WAAW,CAAC,MAAM,EAAE,MAAM,CAK1F,CAAC;AAEJ;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe,aAChB,SAAS,cAAc,EAAE,OAC9B,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,KAC/B;IAAE,QAAQ,CAAC,QAAQ,EAAE,cAAc,EAAE,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAwBnE,CAAC;AA4BF;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,QAAS,OAAO,KAAG,UAAU,EAAE,GAAG,SAa/D,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY,aAAc,SAAS,UAAU,EAAE,WAOzD,CAAC;AAaJ;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,YAAY,SAAU,SAAS,cAAc,EAAE,QAAQ,SAAS,UAAU,EAAE,YAUrF,CAAC"}
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Props, attributes and field comparison for Bao.CloudflareRole — the resource is
3
+ * cloudflare-role.ts, the policy document rules are cloudflare-policy.ts.
4
+ *
5
+ * MEASURED from the engine (house/platform/secrets/vault/plugin/cloudflare/path_roles.go) and the
6
+ * 2026-09-14 snapshot of all 586 live roles:
7
+ * • A role is name, description, policies, ttl and max_ttl AND NOTHING ELSE (path_roles.go:14-20
8
+ * stores those; :204-210 returns them). Every snapshot read carries exactly those five keys, so
9
+ * `differences` below covers the whole server-side object — no unmanaged field can drift
10
+ * behind a green plan.
11
+ * • ttl and max_ttl are TypeDurationSecond (:73-80) and read back as integer seconds.
12
+ * • ⚠️ A WRITE MERGES, IT DOES NOT REPLACE (:117-146). The handler loads the stored role and
13
+ * overwrites only the fields present — the opposite of the proxmox engine, where an omitted
14
+ * field is zeroed. writeBody sends all four anyway, so a write always lands the whole
15
+ * declaration and can never leave an old description behind a new policy.
16
+ *
17
+ * ⛔ NO SECRET IN PROPS OR ATTRIBUTES, AND THERE IS NONE TO LEAK. A role is permission-group IDs, a
18
+ * zone or account resource, a sentence and two TTLs. The parent token lives at `<mount>/config`
19
+ * and a minted token at `<mount>/creds/<name>`; nothing in this family reads either path. Keep
20
+ * it that way — Alchemy persists attributes unencrypted (see policy.ts).
21
+ */
22
+ import { type ResolvedPolicy, type WirePolicy } from './cloudflare-policy.ts';
23
+ import type { DeclaredPolicy } from './cloudflare-roles-expand.ts';
24
+ export interface BaoCloudflareRoleProps {
25
+ /** Mount of the Cloudflare secrets engine, e.g. `cloudflare-<account>-dns`. */
26
+ mount: string;
27
+ /** Role name. ⛔ Consumers mint by it — see cloudflare-roles-expand.ts before changing one. */
28
+ name: string;
29
+ /** The description as written: a zone role's carries its ` (zone: <name>)` suffix. */
30
+ description: string;
31
+ /** Default lease TTL, e.g. `5m`. */
32
+ ttl: string;
33
+ /** Maximum lease TTL, e.g. `1h`. */
34
+ maxTtl: string;
35
+ /**
36
+ * Policy entries, groups by NAME. The provider resolves them through CloudflarePermissionGroups
37
+ * at diff and reconcile time; an ID is never a prop, so a plan can never persist a guessed one.
38
+ */
39
+ policies: DeclaredPolicy[];
40
+ }
41
+ export interface BaoCloudflareRoleAttributes {
42
+ mount: string;
43
+ name: string;
44
+ description: string;
45
+ /** Live ttl in seconds, as the engine stores it. */
46
+ ttl: number;
47
+ /** Live max_ttl in seconds. */
48
+ maxTtl: number;
49
+ /** Live `policies` JSON — group IDs and a resource, never a credential. */
50
+ policies: string;
51
+ /** SHA-256 of the fields above — safe to persist; see policy.ts. */
52
+ digest: string;
53
+ }
54
+ /** One live role, as a read returns it. */
55
+ export interface LiveCloudflareRole {
56
+ readonly name: string;
57
+ readonly description: string;
58
+ readonly ttl: number | undefined;
59
+ readonly maxTtl: number | undefined;
60
+ readonly policiesText: string;
61
+ /** Undefined when `policies` is not a policy document — see parseLivePolicies. */
62
+ readonly policies: readonly WirePolicy[] | undefined;
63
+ }
64
+ export interface RoleDifference {
65
+ readonly field: 'description' | 'max_ttl' | 'policies' | 'ttl';
66
+ readonly want: string;
67
+ readonly have: string;
68
+ }
69
+ /** `cloudflare-<account>-dns/roles/homeflare-dev-dns-read` — read, write and delete use it. */
70
+ export declare const rolePath: (mount: string, name: string) => string;
71
+ /** A read's `data`, shaped. Lenient on purpose: a malformed field compares unequal, loudly. */
72
+ export declare const liveRoleOf: (data: Readonly<Record<string, unknown>>) => LiveCloudflareRole;
73
+ /**
74
+ * ⚠️ Every value is taken from `live`, the prop only standing in for a missing `name` — the same
75
+ * split the sibling families use, so a read never launders the declaration back as "current".
76
+ */
77
+ export declare const attributesOf: (props: Pick<BaoCloudflareRoleProps, 'mount' | 'name'>, live: LiveCloudflareRole) => BaoCloudflareRoleAttributes;
78
+ /**
79
+ * Why reconcile must refuse this declaration, or undefined.
80
+ *
81
+ * ⛔ AN UNPARSEABLE TTL IS A REFUSAL, NOT A ZERO: it can never equal the live seconds, so it would
82
+ * plan `update` forever. ⛔ AN EMPTY POLICY LIST OR AN ENTRY WITH NO GROUPS IS A REFUSAL TOO — the
83
+ * engine rejects both (path_roles.go:147-149, :175-180), and saying so before the write names the
84
+ * declaration instead of quoting the server.
85
+ */
86
+ export declare const refusalOf: (props: BaoCloudflareRoleProps) => string | undefined;
87
+ /**
88
+ * The body for `PUT <mount>/roles/<name>` — the four `k=v` pairs apply-roles.py:157-162 sent.
89
+ *
90
+ * ★ THE TTLs GO AS THE DECLARED TEXT (`5m`), which is what `bao write ttl=5m` put in the JSON body,
91
+ * and TypeDurationSecond parses it server-side. `policies` is a string because the field is a
92
+ * string (path_roles.go:67-68), not because the engine wants the whole body stringly-typed.
93
+ */
94
+ export declare const writeBody: (props: BaoCloudflareRoleProps, policies: readonly WirePolicy[]) => {
95
+ description: string;
96
+ max_ttl: string;
97
+ policies: string;
98
+ ttl: string;
99
+ };
100
+ /**
101
+ * Every field where live differs from the resolved declaration. Empty means noop.
102
+ *
103
+ * ⛔ apply-roles.py --verify COMPARED NONE OF THESE. It lists `<mount>/roles` and reports names
104
+ * only: MISSING when roles.yaml has a role the vault lacks, UNTRACKED for the reverse
105
+ * (apply-roles.py:136-141, :167-173, :179-185). It never read a role. So this equality is new: the
106
+ * four fields --apply WRITES (apply-roles.py:157-162), compared the way the engine reads them back
107
+ * — durations as seconds, description exactly, policies by the rules in samePolicies.
108
+ */
109
+ export declare const differences: (props: Pick<BaoCloudflareRoleProps, 'description' | 'maxTtl' | 'ttl'>, policies: readonly ResolvedPolicy[], live: LiveCloudflareRole) => RoleDifference[];
110
+ //# sourceMappingURL=cloudflare-role-form.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudflare-role-form.d.ts","sourceRoot":"","sources":["../../src/openbao/cloudflare-role-form.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,UAAU,EAIhB,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAInE,MAAM,WAAW,sBAAsB;IACrC,+EAA+E;IAC/E,KAAK,EAAE,MAAM,CAAC;IACd,8FAA8F;IAC9F,IAAI,EAAE,MAAM,CAAC;IACb,sFAAsF;IACtF,WAAW,EAAE,MAAM,CAAC;IACpB,oCAAoC;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,oCAAoC;IACpC,MAAM,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,QAAQ,EAAE,cAAc,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,2BAA2B;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,oDAAoD;IACpD,GAAG,EAAE,MAAM,CAAC;IACZ,+BAA+B;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,CAAC;IACjB,oEAAoE;IACpE,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,2CAA2C;AAC3C,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,kFAAkF;IAClF,QAAQ,CAAC,QAAQ,EAAE,SAAS,UAAU,EAAE,GAAG,SAAS,CAAC;CACtD;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,SAAS,GAAG,UAAU,GAAG,KAAK,CAAC;IAC/D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,+FAA+F;AAC/F,eAAO,MAAM,QAAQ,UAAW,MAAM,QAAQ,MAAM,WAAwC,CAAC;AAK7F,+FAA+F;AAC/F,eAAO,MAAM,UAAU,SAAU,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,KAAG,kBAOnE,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,YAAY,UAChB,IAAI,CAAC,sBAAsB,EAAE,OAAO,GAAG,MAAM,CAAC,QAC/C,kBAAkB,KACvB,2BAUF,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,SAAS,UAAW,sBAAsB,KAAG,MAAM,GAAG,SASlE,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,SAAS,UAAW,sBAAsB,YAAY,SAAS,UAAU,EAAE;IACtF,WAAW;IACX,OAAO;IACP,QAAQ;IACR,GAAG;CACH,CAAC;AAOH;;;;;;;;GAQG;AACH,eAAO,MAAM,WAAW,UACf,IAAI,CAAC,sBAAsB,EAAE,aAAa,GAAG,QAAQ,GAAG,KAAK,CAAC,YAC3D,SAAS,cAAc,EAAE,QAC7B,kBAAkB,KACvB,cAAc,EAehB,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * The OpenBao calls Bao.CloudflareRole and the live-roles bootstrap make — read, write and delete
3
+ * of `<mount>/roles/<name>`. Split out so each can be tested against fake-bao.
4
+ */
5
+ import * as Effect from 'effect/Effect';
6
+ import type * as HttpClient from 'effect/unstable/http/HttpClient';
7
+ import type { BaoError } from './bao-status.ts';
8
+ import { type LiveCloudflareRole } from './cloudflare-role-form.ts';
9
+ /**
10
+ * The live role, or undefined when the engine answers 404.
11
+ *
12
+ * ⚠️ A MISSING MOUNT AND A MISSING ROLE BOTH READ AS UNDEFINED — both are a 404 from OpenBao, the
13
+ * first as "no handler for route". That is proxmox-role.ts's ⚠️ in full: the WRITE is what tells
14
+ * them apart, and it lets OpenBao's own `errors` through. A 403 or 503 is never absence
15
+ * (bao-status.ts).
16
+ */
17
+ export declare const readCloudflareRole: (mount: string, name: string) => Effect.Effect<LiveCloudflareRole | undefined, BaoError, HttpClient.HttpClient>;
18
+ /** ★ `PUT`, which is what `bao write` sent (bao-http.ts). A 404 here fails — see readCloudflareRole. */
19
+ export declare const writeCloudflareRole: (mount: string, name: string, body: Readonly<Record<string, string>>) => Effect.Effect<void, BaoError, HttpClient.HttpClient>;
20
+ /**
21
+ * Idempotent as Alchemy requires — already gone (404) is success, a refusal is not.
22
+ *
23
+ * ⚠️ THE ENGINE'S DELETE IS ONE STORAGE DELETE (path_roles.go:214-216). Tokens the role already
24
+ * minted are leases, and they live to their own expiry.
25
+ */
26
+ export declare const deleteCloudflareRole: (mount: string, name: string) => Effect.Effect<void, BaoError, HttpClient.HttpClient>;
27
+ //# sourceMappingURL=cloudflare-role-wire.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudflare-role-wire.d.ts","sourceRoot":"","sources":["../../src/openbao/cloudflare-role-wire.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,KAAK,UAAU,MAAM,iCAAiC,CAAC;AAEnE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,KAAK,kBAAkB,EAAwB,MAAM,2BAA2B,CAAC;AAE1F;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,UACtB,MAAM,QACP,MAAM,KACX,MAAM,CAAC,MAAM,CAAC,kBAAkB,GAAG,SAAS,EAAE,QAAQ,EAAE,UAAU,CAAC,UAAU,CAG7E,CAAC;AAEJ,wGAAwG;AACxG,eAAO,MAAM,mBAAmB,UACvB,MAAM,QACP,MAAM,QACN,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,yDACS,CAAC;AAElD;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,UAAW,MAAM,QAAQ,MAAM,yDAC9B,CAAC"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * A role on one of the six Cloudflare secrets-engine mounts — what one consumer may mint: the
3
+ * Cloudflare policy its tokens carry and the lease bounds they get. METADATA ONLY.
4
+ *
5
+ * ★ THE PORT OF apply-roles.py's WRITE. roles.yaml expands to these (cloudflare-roles-expand.ts),
6
+ * and what used to be `bao write <mount>/roles/<name> ttl= max_ttl= description= policies=` is
7
+ * reconcile below. The props name permission groups; CloudflarePermissionGroups turns them into
8
+ * IDs at diff and reconcile time.
9
+ *
10
+ * ⛔ NO SECRET IN PROPS OR ATTRIBUTES — see cloudflare-role-form.ts. ⛔ AND ISSUANCE IS NOT THIS
11
+ * RESOURCE: `<mount>/creds/<name>` returns a LIVE Cloudflare token, and a token declared as a
12
+ * resource would outlive its lease in Alchemy's unencrypted state (proxmox-role.ts has the four
13
+ * places it would land). This declares the door; minting is a runtime call.
14
+ *
15
+ * ★ `defaultRemovalPolicy: 'retain'` — deleting a role breaks every consumer that mints from it,
16
+ * and apply-roles.py never deleted one either: an unexplained role was reported UNTRACKED and
17
+ * left alone (apply-roles.py:190-196). Opt in with `.pipe(RemovalPolicy.destroy())`.
18
+ */
19
+ import { Resource } from 'alchemy';
20
+ import * as Provider from 'alchemy/Provider';
21
+ import type * as HttpClient from 'effect/unstable/http/HttpClient';
22
+ import { CloudflarePermissionGroups } from './cloudflare-permission-groups.ts';
23
+ import { type BaoCloudflareRoleAttributes, type BaoCloudflareRoleProps } from './cloudflare-role-form.ts';
24
+ export type { BaoCloudflareRoleAttributes, BaoCloudflareRoleProps };
25
+ /**
26
+ * ⚠️ CloudflarePermissionGroups IS NOT A REQUIREMENT OF THE RESOURCE. The provider takes it once, when
27
+ * it is built (`yield* CloudflarePermissionGroups` below), and alchemy.run.ts supplies it to the
28
+ * provider layer with `Layer.provide`. Listing it here as well made it a requirement of the STACK
29
+ * body, which Alchemy only lets name its own provider and stack services — tsc refused the wiring.
30
+ */
31
+ export interface BaoCloudflareRole extends Resource<'Bao.CloudflareRole', BaoCloudflareRoleProps, BaoCloudflareRoleAttributes, never, HttpClient.HttpClient> {
32
+ }
33
+ export declare const BaoCloudflareRole: import("alchemy").ResourceClass<BaoCloudflareRole>;
34
+ export declare const BaoCloudflareRoleProvider: () => import("effect/Layer").Layer<Provider.Provider<BaoCloudflareRole>, never, CloudflarePermissionGroups | HttpClient.HttpClient>;
35
+ //# sourceMappingURL=cloudflare-role.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudflare-role.d.ts","sourceRoot":"","sources":["../../src/openbao/cloudflare-role.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAE7C,OAAO,KAAK,KAAK,UAAU,MAAM,iCAAiC,CAAC;AAEnE,OAAO,EAAE,0BAA0B,EAAiB,MAAM,mCAAmC,CAAC;AAE9F,OAAO,EACL,KAAK,2BAA2B,EAChC,KAAK,sBAAsB,EAM5B,MAAM,2BAA2B,CAAC;AAOnC,YAAY,EAAE,2BAA2B,EAAE,sBAAsB,EAAE,CAAC;AAEpE;;;;;GAKG;AACH,MAAM,WAAW,iBAAkB,SAAQ,QAAQ,CACjD,oBAAoB,EACpB,sBAAsB,EACtB,2BAA2B,EAC3B,KAAK,EACL,UAAU,CAAC,UAAU,CACtB;CAAG;AAEJ,eAAO,MAAM,iBAAiB,oDAE5B,CAAC;AAEH,eAAO,MAAM,yBAAyB,qIA+HnC,CAAC"}
@@ -0,0 +1,67 @@
1
+ /** One `zone_roles` or `account_roles` entry. */
2
+ export interface RoleTemplate {
3
+ readonly name: string;
4
+ readonly groups: readonly string[];
5
+ /** Duration text exactly as written (`5m`), which is what apply-roles.py sent. */
6
+ readonly ttl: string;
7
+ readonly maxTtl: string;
8
+ readonly desc: string;
9
+ /** `zones:` narrowing. Undefined or empty narrows nothing — `if only and …` (cfroles.py:78). */
10
+ readonly zones: readonly string[] | undefined;
11
+ readonly zoneTypes: readonly string[];
12
+ /** Account-scoped groups on a ZONE role. Ignored on account roles, as cfroles.py:101 ignores it. */
13
+ readonly accountGroups: readonly string[];
14
+ /**
15
+ * One R2 bucket NAME, narrowing an account role's resource to that bucket alone.
16
+ *
17
+ * ⛔ BUCKET IS THE FINEST GRAIN R2 HAS — A PREFIX CANNOT BE SCOPED. So one repository per
18
+ * instance in its own bucket is the only least-privilege shape for a backup credential, and
19
+ * this field is what expresses it. Undefined leaves the role account-wide, which is what every
20
+ * role declared before 2026-09-15 is.
21
+ * ⚠️ IT ONLY MEANS ANYTHING WITH THE `Bucket Item` GROUPS. `Workers R2 Storage Write` is gated at
22
+ * the ACCOUNT scope, so pairing it with a bucket resource is a token Cloudflare will mint and
23
+ * that will then be refused on every call. roles.yaml says which pair goes with which.
24
+ */
25
+ readonly bucket: string | undefined;
26
+ /**
27
+ * The bucket's jurisdiction, which is part of its resource id and not cosmetic — a bucket
28
+ * created in `default` is a different resource from the same name under `eu`. Defaults to
29
+ * `default`, which is what every bucket in this estate is (measured: `r2_bucket_get` reports
30
+ * `jurisdiction default` on all 34).
31
+ */
32
+ readonly bucketJurisdiction: string;
33
+ /**
34
+ * roles.yaml `groups_scope:` — the scope this template's `groups:` NAMES resolve at, as a
35
+ * GROUP_SCOPES value. Undefined means the entry's own resource namespace, which is every
36
+ * template written before 2026-09-15.
37
+ *
38
+ * ⛔ IT SAYS WHICH ID, NOT WHICH RESOURCE. `groups_scope: zone` on an ACCOUNT role keeps the
39
+ * account resource and takes the zone-scoped id of each name — Cloudflare's "all zones from
40
+ * this account" (cf-mint-analytics-tokens.py:155-158). It is meaningful only for the seven
41
+ * names the engine lists at two scopes; anywhere else the name has one id and answers alike.
42
+ */
43
+ readonly groupsScope: string | undefined;
44
+ }
45
+ export interface SurfaceSpec {
46
+ readonly zoneRoles: readonly RoleTemplate[];
47
+ readonly accountRoles: readonly RoleTemplate[];
48
+ }
49
+ export interface AccountSpec {
50
+ /** The key under `accounts:` — the `<account>` in `cloudflare-<account>-<surface>`. */
51
+ readonly key: string;
52
+ readonly id: string;
53
+ readonly zones: 'all' | readonly string[];
54
+ readonly surfaces: readonly string[];
55
+ }
56
+ export interface RolesConfig {
57
+ readonly namespace: string;
58
+ readonly surfaces: Readonly<Record<string, SurfaceSpec>>;
59
+ /** In file order, which is the order apply-roles.py walked them (apply-roles.py:111). */
60
+ readonly accounts: readonly AccountSpec[];
61
+ }
62
+ export declare class RolesConfigError extends Error {
63
+ constructor(where: string, problem: string);
64
+ }
65
+ /** Parse and check roles.yaml. Throws RolesConfigError naming the first bad field. */
66
+ export declare const parseRolesConfig: (yaml: string) => RolesConfig;
67
+ //# sourceMappingURL=cloudflare-roles-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudflare-roles-config.d.ts","sourceRoot":"","sources":["../../src/openbao/cloudflare-roles-config.ts"],"names":[],"mappings":"AAuBA,iDAAiD;AACjD,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,kFAAkF;IAClF,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,gGAAgG;IAChG,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IAC9C,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,oGAAoG;IACpG,QAAQ,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1C;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC;;;;;OAKG;IACH,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC;;;;;;;;;OASG;IACH,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;CAC1C;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,SAAS,EAAE,SAAS,YAAY,EAAE,CAAC;IAC5C,QAAQ,CAAC,YAAY,EAAE,SAAS,YAAY,EAAE,CAAC;CAChD;AAED,MAAM,WAAW,WAAW;IAC1B,uFAAuF;IACvF,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,SAAS,MAAM,EAAE,CAAC;IAC1C,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;IACzD,yFAAyF;IACzF,QAAQ,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,CAAC;CAC3C;AAED,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,YAAY,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAGzC;CACF;AAyHD,sFAAsF;AACtF,eAAO,MAAM,gBAAgB,SAAU,MAAM,KAAG,WAc/C,CAAC"}
@@ -0,0 +1,76 @@
1
+ import type { AccountSpec, RolesConfig } from './cloudflare-roles-config.ts';
2
+ /** A zone as the expansion needs it — what cfhf.py load_account listed (cfhf.py:134-146). */
3
+ export interface CloudflareZone {
4
+ readonly name: string;
5
+ readonly id: string;
6
+ /** From the `type=internal` listing. ⚠️ Shares its NAME with the public zone, never its id. */
7
+ readonly internal: boolean;
8
+ }
9
+ /**
10
+ * One policy entry, groups by name.
11
+ *
12
+ * ★ `groupOrder` CARRIES A PYTHON RULE THAT ONLY EXISTS AFTER RESOLUTION. cfhf.py:180 sorts the
13
+ * account entry's group IDS — not its names — so that order cannot be computed here, only
14
+ * promised. A `declared` entry keeps roles.yaml order, exactly as cfhf.py:175 emitted it.
15
+ */
16
+ export interface DeclaredPolicy {
17
+ readonly effect: 'allow';
18
+ readonly resource: string;
19
+ readonly groups: readonly string[];
20
+ readonly groupOrder: 'declared' | 'by-id';
21
+ /**
22
+ * The scope these NAMES resolve at, when it is not this entry's own resource namespace —
23
+ * roles.yaml `groups_scope:`, already a GROUP_SCOPES value. Undefined on every entry that does
24
+ * not say otherwise, which is 639 of the estate's 643 group references.
25
+ *
26
+ * ⛔ IT MOVES THE LOOKUP, NEVER THE RESOURCE. The entry still binds the groups to the resource
27
+ * above; only the id chosen for each name changes. That is the shape Cloudflare calls "all
28
+ * zones from an account" — the ACCOUNT resource carrying ZONE-scoped groups
29
+ * (house/nix/homeflare-config/scripts/cf-mint-analytics-tokens.py:155-158, beside a working
30
+ * token). Without this field the resource is the only witness, and it says `account`.
31
+ */
32
+ readonly scope?: string;
33
+ }
34
+ /** What apply-roles.py wrote to the KV catalog for one role (apply-roles.py:58-62). */
35
+ export interface CatalogView {
36
+ readonly description: string;
37
+ readonly zone: string | null;
38
+ readonly ttl: string;
39
+ readonly maxTtl: string;
40
+ readonly permissions: readonly string[];
41
+ }
42
+ export interface ExpandedRole {
43
+ readonly account: string;
44
+ readonly accountId: string;
45
+ readonly mount: string;
46
+ readonly surface: string;
47
+ readonly name: string;
48
+ /** Exactly what apply-roles.py:160-161 wrote — the zone suffix included. */
49
+ readonly description: string;
50
+ readonly ttl: string;
51
+ readonly maxTtl: string;
52
+ readonly policies: readonly DeclaredPolicy[];
53
+ readonly catalog: CatalogView;
54
+ }
55
+ /** cfroles.py:18-20 — `example.com` → `homeflare-dev`. */
56
+ export declare const slug: (name: string) => string;
57
+ /**
58
+ * cfroles.py:23-38. ⛔ THE `-internal` SUFFIX IS WHAT KEEPS TWO ZONES OF ONE NAME APART. Slugging
59
+ * both example.com zones alike would leave two roles fighting for one name, and whichever
60
+ * wrote last would silently own it.
61
+ */
62
+ export declare const zoneSlug: (zone: CloudflareZone) => string;
63
+ /** cfroles.py:46-47 — one mount, and so one parent token, per (account, surface). */
64
+ export declare const mountName: (account: string, surface: string) => string;
65
+ /** cfroles.py:50-104 for one account, in the Python's order: per surface, zone roles first. */
66
+ export declare const expandAccount: (config: RolesConfig, account: AccountSpec, zones: readonly CloudflareZone[]) => ExpandedRole[];
67
+ /**
68
+ * Every account's roles, grouped by mount.
69
+ *
70
+ * ⛔ A DUPLICATE ROLE ON ONE MOUNT IS AN ERROR HERE. apply-roles.py wrote both and the last write
71
+ * won in silence (apply-roles.py:157-162); declared, they are two resources fighting over one
72
+ * object. ⚠️ A MISSING ZONE INVENTORY IS AN ERROR TOO — an empty one is not, because an account
73
+ * with no zones is real, and the Python expanded it to account roles only.
74
+ */
75
+ export declare const expandAll: (config: RolesConfig, zonesByAccount: Readonly<Record<string, readonly CloudflareZone[]>>) => ReadonlyMap<string, readonly ExpandedRole[]>;
76
+ //# sourceMappingURL=cloudflare-roles-expand.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudflare-roles-expand.d.ts","sourceRoot":"","sources":["../../src/openbao/cloudflare-roles-expand.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,WAAW,EAAgB,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAE3F,6FAA6F;AAC7F,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,+FAA+F;IAC/F,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC5B;AAED;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC;IAC1C;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,uFAAuF;AACvF,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;CACzC;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,4EAA4E;IAC5E,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,SAAS,cAAc,EAAE,CAAC;IAC7C,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;CAC/B;AAED,0DAA0D;AAC1D,eAAO,MAAM,IAAI,SAAU,MAAM,WAIL,CAAC;AAE7B;;;;GAIG;AACH,eAAO,MAAM,QAAQ,SAAU,cAAc,WACY,CAAC;AAE1D,qFAAqF;AACrF,eAAO,MAAM,SAAS,YAAa,MAAM,WAAW,MAAM,WAAuC,CAAC;AAkFlG,+FAA+F;AAC/F,eAAO,MAAM,aAAa,WAChB,WAAW,WACV,WAAW,SACb,SAAS,cAAc,EAAE,KAC/B,YAAY,EAwBd,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,SAAS,WACZ,WAAW,kBACH,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,cAAc,EAAE,CAAC,CAAC,KAClE,WAAW,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,CAgB7C,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * The digest every Bao.* family persists instead of a value — moved here from the retired
3
+ * bao-shell.ts, unchanged, when the package stopped shelling out to `bao`.
4
+ */
5
+ /** ⚠️ Bun's hasher, not node:crypto — this runs under `bun --bun alchemy`. */
6
+ /**
7
+ * The only form a policy body may be hashed or compared in.
8
+ *
9
+ * ⛔ OPENBAO STRIPS THE TRAILING NEWLINE AND THAT ALONE WAS A FOREVER-DIFF. MEASURED on the live
10
+ * server: the assembler emits each fragment followed by a newline, so `homeflare-llm` goes in as
11
+ * 41 lines and `bao policy read` hands back 40 — identical text, one `\n` apart, two different
12
+ * digests. Every plan therefore reported `update`, every deploy rewrote the same policy, and the
13
+ * stack could never settle. It was invisible until the stack planned for the first time today.
14
+ * ★ THE HTTP API HANDS BACK THE SAME STRIPPED TEXT. `bao policy read` printed `data.policy` of
15
+ * `GET /v1/sys/policies/acl/<name>` (openbao v2.6.2 api/sys_policy.go:60-81), which is what
16
+ * policy-wire.ts now reads directly — so the canonicalisation is still load-bearing.
17
+ *
18
+ * ⚠️ `trimEnd` ONLY. Leading and interior whitespace are part of the HCL and must not be touched —
19
+ * a policy that differs by an indent really is a different document, and quietly folding that
20
+ * away would hide an edit rather than a formatting artifact.
21
+ */
22
+ export declare const canonical: (text: string) => string;
23
+ export declare const sha256: (text: string) => string;
24
+ //# sourceMappingURL=digest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"digest.d.ts","sourceRoot":"","sources":["../../src/openbao/digest.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,8EAA8E;AAC9E;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,SAAS,SAAU,MAAM,WAAmB,CAAC;AAE1D,eAAO,MAAM,MAAM,SAAU,MAAM,WACmC,CAAC"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * A fake OpenBao for the tests beside it — `Bun.serve` on an ephemeral 127.0.0.1 port, or on a unix
3
+ * socket the way an agent listener can be.
4
+ *
5
+ * ⛔ TEST-ONLY, AND NEVER A REAL VAULT. No provider imports this file, it forwards nowhere, and every
6
+ * helper below runs with an EXPLICIT environment rather than `process.env`, so a BAO_ADDR or
7
+ * BAO_TOKEN in the shell running the tests can never be read or contacted.
8
+ */
9
+ import * as Effect from 'effect/Effect';
10
+ import type * as HttpClient from 'effect/unstable/http/HttpClient';
11
+ import type { BaoEnvironment } from './bao-address.ts';
12
+ /** One request the fake received. */
13
+ export type Seen = {
14
+ readonly method: string;
15
+ readonly path: string;
16
+ readonly headers: Headers;
17
+ readonly body: string;
18
+ };
19
+ /** What the fake answers: a status and a JSON value, or raw text for a body that is not JSON. */
20
+ export type Reply = {
21
+ readonly status: number;
22
+ readonly json?: unknown;
23
+ readonly text?: string;
24
+ };
25
+ export type Fake = {
26
+ readonly address: string;
27
+ readonly seen: Seen[];
28
+ stop(): void;
29
+ };
30
+ /** ★ An answer may be async, so a test can HOLD requests open and count how many overlap. */
31
+ type Answer = (seen: Seen) => Reply | Promise<Reply>;
32
+ export declare const fakeBao: (answer: Answer, unix?: string) => Fake;
33
+ /** Run `body` against a fresh fake, and stop it whatever happens. */
34
+ export declare const withFake: (answer: Answer, body: (bao: Fake) => Promise<void>, unix?: string) => Promise<void>;
35
+ /** The effect's success, through the real FetchHttpClient, under `env` only. */
36
+ export declare const run: <A, E>(env: BaoEnvironment, effect: Effect.Effect<A, E, HttpClient.HttpClient>) => Promise<A>;
37
+ /** The effect's failure — rejects if it succeeded. */
38
+ export declare const runFailure: <A, E>(env: BaoEnvironment, effect: Effect.Effect<A, E, HttpClient.HttpClient>) => Promise<E>;
39
+ export {};
40
+ //# sourceMappingURL=fake-bao.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fake-bao.d.ts","sourceRoot":"","sources":["../../src/openbao/fake-bao.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,KAAK,KAAK,UAAU,MAAM,iCAAiC,CAAC;AACnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAGvD,qCAAqC;AACrC,MAAM,MAAM,IAAI,GAAG;IACjB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,iGAAiG;AACjG,MAAM,MAAM,KAAK,GAAG;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjG,MAAM,MAAM,IAAI,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;IAAC,IAAI,IAAI,IAAI,CAAA;CAAE,CAAC;AAErF,6FAA6F;AAC7F,KAAK,MAAM,GAAG,CAAC,IAAI,EAAE,IAAI,KAAK,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;AAErD,eAAO,MAAM,OAAO,WAAY,MAAM,SAAS,MAAM,KAAG,IAwBvD,CAAC;AAEF,qEAAqE;AACrE,eAAO,MAAM,QAAQ,WACX,MAAM,QACR,CAAC,GAAG,EAAE,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,SAC3B,MAAM,kBAQd,CAAC;AAKF,gFAAgF;AAChF,eAAO,MAAM,GAAG,GAAI,CAAC,EAAE,CAAC,OACjB,cAAc,UACX,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,UAAU,CAAC,UAAU,CAAC,eACP,CAAC;AAE9C,sDAAsD;AACtD,eAAO,MAAM,UAAU,GAAI,CAAC,EAAE,CAAC,OACxB,cAAc,UACX,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,UAAU,CAAC,UAAU,CAAC,eACM,CAAC"}