@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,64 @@
1
+ /**
2
+ * One authenticated call to the Proxmox VE API.
3
+ *
4
+ * ★ PLAIN `fetch`, NO TLS ESCAPE HATCH, AND THAT IS A MEASURED CHOICE RATHER THAN AN OMISSION.
5
+ * Proxmox is usually met with `curl -k` because a fresh install serves its own self-signed
6
+ * certificate — I reached for `-k` myself before checking. This cluster serves a real Let's
7
+ * Encrypt certificate (`CN=cluster-tb4.example.com`), and strict TLS answers 401, i.e. the
8
+ * handshake succeeds and only the credential is missing. So there is no `rejectUnauthorized`
9
+ * option here to be left switched on by accident in somebody else's estate.
10
+ *
11
+ * ⚠️ EVERY PVE ANSWER IS WRAPPED IN `{"data": ...}`, errors included — a failed call can still be
12
+ * HTTP 200 with `{"data": null}`. Unwrapping is not cosmetic; a caller that reads the envelope
13
+ * as the payload sees `undefined` and calls it "absent".
14
+ */
15
+ import * as Effect from 'effect/Effect';
16
+ import * as HttpClient from 'effect/unstable/http/HttpClient';
17
+ import { type ApiTarget, type PveCredential, type PveRole, type PveTarget } from './credentials.ts';
18
+ export declare class PveError extends Error {
19
+ readonly status: number;
20
+ readonly method: string;
21
+ readonly path: string;
22
+ constructor(status: number, method: string, path: string, detail: string);
23
+ }
24
+ /**
25
+ * A form body, where a value may be a LIST.
26
+ *
27
+ * ⛔ PVE AND PBS SPELL A MULTI-VALUED FIELD DIFFERENTLY, AND THE LIST FORM IS FOR PBS. PBS is Rust:
28
+ * its schemas use `type: array` — `delete` on every update endpoint is one — and its urlencoded
29
+ * decoder builds that array from REPEATED KEYS (`delete=a&delete=b`). PVE's Perl takes a comma
30
+ * string for the same idea, which is what `withClears` in values.ts produces, and for the one
31
+ * PVE field that genuinely needs repetition it wants a NUL-joined value instead (see
32
+ * notification-target.ts). So: PVE callers pass strings and are unaffected; a PBS caller that
33
+ * needs an array passes one and gets repeated keys rather than reaching for PVE's encoding.
34
+ */
35
+ export type PveForm = Record<string, readonly string[] | string>;
36
+ /** A call that already holds a credential. Used when one mint serves several calls. */
37
+ export declare const pveWith: <T>(target: ApiTarget, credential: PveCredential, method: 'GET' | 'POST' | 'PUT' | 'DELETE', path: string, form?: PveForm) => Effect.Effect<T | undefined, PveError, HttpClient.HttpClient>;
38
+ /**
39
+ * Like `pveWith`, but returns the full JSON body — for endpoints whose answer lives beside `data`.
40
+ *
41
+ * ⚠️ `network-apply-read.ts` is the caller today; the local fetch there should fold into this once
42
+ * the envelope shape is stable across both paths.
43
+ */
44
+ export declare const pveEnvelopeWith: (target: PveTarget, credential: PveCredential, method: 'GET' | 'POST' | 'PUT' | 'DELETE', path: string) => Effect.Effect<Record<string, unknown>, PveError, HttpClient.HttpClient>;
45
+ /**
46
+ * Make one call on a credential for `role`, REUSING a still-valid lease rather than minting one.
47
+ *
48
+ * 🔴 IT USED TO MINT PER CALL, AND AT 98 RESOURCES THAT STOPPED BEING FREE. One plan plus deploy
49
+ * of the TB4 stack left 760 token entries in `/etc/pve/user.cfg` — read, diff, reconcile and the
50
+ * read-back each minted their own, and `/etc/pve` is a replicated cluster filesystem every node
51
+ * has to agree on. src/lease-cache.ts carries the measurement and the safety argument.
52
+ *
53
+ * ⚠️ `pveWith` IS STILL THERE AND STILL TAKES AN EXPLICIT CREDENTIAL. network-apply.ts needs ONE
54
+ * identity across its apply and its task poll — PVE only skips the task-status privilege check
55
+ * for the task's OWNER — and it threads a lease through by hand for that. Caching makes that
56
+ * property easier to hold, never weaker, but the explicit path stays because that caller is
57
+ * reasoning about identity rather than about cost.
58
+ *
59
+ * ★ TASK POLL ON A DIFFERENT MEMBER THAN THE APPLY STILL HOLDS: the owner is the token id, not the
60
+ * node that received the PUT. Any member serves any task path; the privilege skip is keyed on
61
+ * whether the caller IS the task's owner.
62
+ */
63
+ export declare const pve: <T>(target: ApiTarget, role: PveRole, method: 'GET' | 'POST' | 'PUT' | 'DELETE', path: string, form?: PveForm) => Effect.Effect<T | undefined, Error, HttpClient.HttpClient>;
64
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/proxmox/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,UAAU,MAAM,iCAAiC,CAAC;AAE9D,OAAO,EACL,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,KAAK,OAAO,EACZ,KAAK,SAAS,EAEf,MAAM,kBAAkB,CAAC;AAI1B,qBAAa,QAAS,SAAQ,KAAK;IAE/B,QAAQ,CAAC,MAAM,EAAE,MAAM;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM;IAHvB,YACW,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACrB,MAAM,EAAE,MAAM,EAIf;CACF;AAcD;;;;;;;;;;GAUG;AACH,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAAC,CAAC;AA8FjE,uFAAuF;AACvF,eAAO,MAAM,OAAO,GAAI,CAAC,UACf,SAAS,cACL,aAAa,UACjB,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,QACnC,MAAM,SACL,OAAO,kEAgBZ,CAAC;AAEL;;;;;GAKG;AACH,eAAO,MAAM,eAAe,WAClB,SAAS,cACL,aAAa,UACjB,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,QACnC,MAAM,4EAmBV,CAAC;AAEL;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,GAAG,GAAI,CAAC,UACX,SAAS,QACX,OAAO,UACL,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,QACnC,MAAM,SACL,OAAO,+DAKZ,CAAC"}
@@ -0,0 +1,153 @@
1
+ /**
2
+ * The PVE credential a reconcile runs with: minted from OpenBao, alive for five minutes.
3
+ *
4
+ * ⛔ THERE IS NO STATIC WRITE TOKEN IN THIS ESTATE, AND THAT IS DELIBERATE. Every PVE token stored
5
+ * in `kv/infra/proxmox/*` is read-only — PVEAuditor on media/ops/tb4, Audit on pbs, all as
6
+ * `monitoring@pve`. The MCP proxmox client says why in its own header: the auditor token bounds
7
+ * what a BUG can do, independently of what the code bounds. Adding a long-lived write token to
8
+ * that shelf would delete the outer lock for every reader of the shelf, not just for this
9
+ * provider.
10
+ *
11
+ * ★ SO WRITES COME FROM A DYNAMIC MOUNT INSTEAD, which the estate already built: `proxmox-tb4/`
12
+ * exposes two roles — `read` (ttl 3600s) and `provision` (ttl 300s, max 1800s, NOT renewable).
13
+ * A mint returns a PVE API token of its own, `hf-provision@pve!hf-provision-…-<timestamp>-<id>`,
14
+ * which expires on its own whether or not anything cleans up. Same shape as
15
+ * `cloudflare-<account>-<surface>/creds/<role>`, same reason.
16
+ * ⚠️ THAT PATH IS WRITTEN WITH `<surface>` RATHER THAN A GLOB ON PURPOSE: a `*` followed by
17
+ * a slash CLOSES THIS BLOCK COMMENT, and everything below it then parses as code. It cost
18
+ * six TS1005/TS1443 errors pointing at innocent lines twenty rows further down.
19
+ *
20
+ * ⚠️ FIVE MINUTES IS THE DESIGN, NOT AN OBSTACLE. A reconcile that cannot finish inside the lease
21
+ * should mint again rather than ask for a longer one: the short lease is what makes a leaked
22
+ * token uninteresting. `provision` is explicitly non-renewable, so there is no renew path to
23
+ * reach for.
24
+ *
25
+ * ⛔ THE SECRET NEVER TOUCHES DISK, A LOG, OR ALCHEMY STATE. Alchemy persists resource attributes
26
+ * WITHOUT encryption — StateEncoding.ts writes `Redacted` as `{"@redacted": <plaintext>}` — and
27
+ * this estate's state store is the `alchemy` Postgres, which pg-backup.sh dumps nightly. A PVE
28
+ * secret that reached an attribute would outlive its 300s lease by months, in four places.
29
+ * Nothing here returns it to a resource; it is used to build a header and then dropped.
30
+ */
31
+ import * as Effect from 'effect/Effect';
32
+ import * as HttpClient from 'effect/unstable/http/HttpClient';
33
+ /**
34
+ * ★ NO SESSION, ON PURPOSE, AND THIS IS WHAT UNBLOCKED `wip/bao-policy`.
35
+ * `CommandExecutor.run` requires a `ScopedPlanStatusSession`, and Alchemy gives one to
36
+ * `reconcile` and `delete` but NOT to `read` or `diff` — so a provider built on `run` can only
37
+ * ever write. Alchemy's OWN Docker provider does not use `CommandExecutor` for this at all: it
38
+ * takes `ChildProcessSpawner` and pipes `ChildProcess.make(...)` through `spawner.spawn`, which
39
+ * needs a `Scope` and nothing else (Docker.ts:476-553). That was the pattern here until
40
+ * 2026-09-14, when `mint` moved to `HttpClient` — which needs no session either, so `mint` is
41
+ * still callable from all four operations.
42
+ *
43
+ * ⛔ DO NOT SATISFY THE OLD SIGNATURE BY FAKING A SESSION. A session carries plan status Alchemy
44
+ * uses to report progress; inventing one would make read and diff report work they are not doing.
45
+ */
46
+ /** Which role a call needs. `read` for read/diff, `provision` for reconcile/delete. */
47
+ export type PveRole = 'read' | 'provision';
48
+ /**
49
+ * Where credentials come from, and which cluster they are for.
50
+ *
51
+ * ⚠️ A PARAMETER, NOT A CONSTANT, SO THIS PACKAGE CAN LEAVE THE ESTATE. Everything
52
+ * HomeFlare-specific — the mount name, the API host — belongs in the stack that declares
53
+ * resources, not in the provider. Anyone with an OpenBao mount that vends Proxmox API tokens can
54
+ * use this file unchanged; that is the whole difference between a provider and a script.
55
+ */
56
+ export type PveTarget = {
57
+ /** OpenBao mount that vends API tokens for this host, e.g. `proxmox-tb4`. */
58
+ readonly mount: string;
59
+ /**
60
+ * mgmt hostnames for cluster members, e.g. `n2.mgmt.example.com`. Any member's :8006 API
61
+ * manages the whole cluster; `client.ts` failovers across them.
62
+ */
63
+ readonly members: readonly string[];
64
+ /**
65
+ * Which product answers at `api`. Defaults to `pve`.
66
+ *
67
+ * ★ PBS IS THE SAME CLIENT WITH A DIFFERENT AUTHORIZATION HEADER, AND THAT IS WHY THERE IS NO
68
+ * SECOND CLIENT HERE. Proxmox Backup Server speaks the same `/api2/json` paths, wraps every
69
+ * answer in the same `{"data": …}` envelope, and its OpenBao mount vends the same
70
+ * `{token_id, secret}` shape — so `mint`, `pve()` and `pveOperations` all work against it
71
+ * unchanged. The ONE difference is the header scheme: PVE spells it
72
+ * `PVEAPIToken=<id>=<secret>` and PBS spells it `PBSAPIToken=<id>:<secret>` — a different
73
+ * prefix AND a different separator.
74
+ *
75
+ * ⛔ IT IS REQUIRED, NOT OPTIONAL, AND THAT IS THE WHOLE TYPE-SAFETY ARGUMENT. A PBS target and
76
+ * a PVE target are the same two strings, so with an OPTIONAL discriminant TypeScript's
77
+ * structural typing would accept a PBS host wherever a PVE one belongs — and `pve()` would
78
+ * then build `PVEAPIToken=<id>=<secret>` against a server wanting
79
+ * `PBSAPIToken=<id>:<secret>`. Every call 401s, `pveOperations.read` folds that into "absent",
80
+ * the plan says CREATE for an object that is plainly there, the POST is refused, and not one
81
+ * symptom points at the header. Required, the mistake is a compile error instead.
82
+ *
83
+ * ⚠️ REASONED FROM PBS'S DOCUMENTED SCHEME, NOT MEASURED. The estate has no PBS credential yet
84
+ * (there is no PBS mount in OpenBao), and an unauthenticated probe cannot tell the schemes
85
+ * apart — `https://pbs.example.com:8007/api2/json/nodes` answers 401 to a missing header, a
86
+ * PVE-shaped one and a PBS-shaped one alike. The first real token will confirm or correct it,
87
+ * and a wrong guess fails closed with a 401 rather than doing something odd.
88
+ */
89
+ readonly scheme: 'pve';
90
+ };
91
+ /** The same client against a Proxmox Backup Server. See the ⛔ on `scheme` above. */
92
+ export type PbsTarget = {
93
+ readonly mount: string;
94
+ readonly api: string;
95
+ readonly scheme: 'pbs';
96
+ };
97
+ /** Either product. What `pve()` and `pveOperations` accept; what a RESOURCE accepts is narrower. */
98
+ export type ApiTarget = PbsTarget | PveTarget;
99
+ /**
100
+ * What a mint returns.
101
+ *
102
+ * ⚠️ `secret` IS PRESENT AND MUST NOT BE PERSISTED. It is typed as a plain string rather than
103
+ * `Redacted` on purpose: Alchemy's Redacted is a STATE-ENCODING marker, not encryption, so
104
+ * wrapping it would imply a protection that does not exist. The protection here is that this
105
+ * value never leaves the function that builds the Authorization header.
106
+ */
107
+ export type PveCredential = {
108
+ /** `hf-provision@pve!hf-provision-…` — an identifier, safe to log. */
109
+ readonly tokenId: string;
110
+ /** ⛔ NEVER LOG, NEVER PERSIST, NEVER RETURN FROM A RESOURCE. */
111
+ readonly secret: string;
112
+ /** Seconds the lease was granted for, as reported by OpenBao. */
113
+ readonly leaseSeconds: number;
114
+ };
115
+ /** The environment `mint` resolves OpenBao from — `process.env` unless a test passes its own. */
116
+ export type BaoEnvironment = Readonly<Record<string, string | undefined>>;
117
+ /**
118
+ * Mint one credential for `role`: `GET /v1/<mount>/creds/<role>` on OpenBao's HTTP API.
119
+ *
120
+ * 🔴 IT SHELLED OUT TO `bao read -format=json` UNTIL 2026-09-14. The case for the CLI was that one
121
+ * client could not disagree with `bao kv get` about what this machine may do. house/openbao then
122
+ * learned twice what deciding by stderr costs — every failure read as absent, and two commands
123
+ * said "absent" in different words — so this reads STATUS CODES: 2xx is a credential, and 403
124
+ * (denied), 404 (no such role or mount — a mint has no "absent"), 503 (sealed) all fail.
125
+ * ★ THE ENVIRONMENT CONTRACT IS STILL THE CLI's, READ THE CLI's WAY, which keeps the case above
126
+ * true (openbao v2.6.2 api/client.go:34-66, 370, 503-507, 761-762, 776-785): BAO_AGENT_ADDR over
127
+ * BAO_ADDR over https://127.0.0.1:8200; BAO_NAMESPACE as X-Vault-Namespace; BAO_TOKEN as
128
+ * X-Vault-Token; X-Vault-Request always. house/openbao/src/bao-address.ts has the long form.
129
+ * ★ AGENT MODE IS NO BAO_TOKEN AND NO TOKEN HEADER. An Agent or Proxy listener with
130
+ * `api_proxy { use_auto_auth_token = true }` (or the older `cache { … }`) substitutes its
131
+ * auto-auth token exactly when a request carries none — command/agentproxyshared/cache/handler.go
132
+ * :29-38, command/agent.go:517-541, command/agent/config/config.go:288-292, and
133
+ * website/content/docs/agent-and-proxy/agent/apiproxy.mdx:57-62. The CLI's token-file fallback
134
+ * is deliberately not read. ⚠️ So an unset BAO_TOKEN aimed at a SERVER rather than an agent is a
135
+ * 403, which reads like a missing grant rather than a missing variable.
136
+ * ★ UNIX SOCKETS: `unix:///path` is plain HTTP to `localhost` over that socket, as the CLI does it
137
+ * (api/client.go:654-667). Bun's fetch takes a `unix` option; `FetchHttpClient.RequestInit` is
138
+ * Effect's documented way to pass fetch options, read from the calling fiber (effect
139
+ * FetchHttpClient.ts:59-72). Off Bun it REFUSES, rather than reach http://localhost:80.
140
+ */
141
+ export declare const mint: (target: ApiTarget, role: PveRole, env?: BaoEnvironment) => Effect.Effect<{
142
+ leaseSeconds: number;
143
+ secret: string;
144
+ tokenId: string;
145
+ }, Error, HttpClient.HttpClient>;
146
+ /**
147
+ * The header PVE wants. `PVEAPIToken=<tokenid>=<secret>`.
148
+ *
149
+ * ⚠️ THE SEPARATOR IS `=`, NOT `:`. Proxmox rejects the colon form with a 401 that says only
150
+ * "authentication failure", which reads as a bad credential rather than as a malformed header.
151
+ */
152
+ export declare const authorization: (credential: PveCredential, target: ApiTarget) => string;
153
+ //# sourceMappingURL=credentials.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../../src/proxmox/credentials.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAIxC,OAAO,KAAK,UAAU,MAAM,iCAAiC,CAAC;AAG9D;;;;;;;;;;;;GAYG;AACH,uFAAuF;AACvF,MAAM,MAAM,OAAO,GAAG,MAAM,GAAG,WAAW,CAAC;AAE3C;;;;;;;GAOG;AACH,MAAM,MAAM,SAAS,GAAG;IACtB,6EAA6E;IAC7E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC;CACxB,CAAC;AAEF,oFAAoF;AACpF,MAAM,MAAM,SAAS,GAAG;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC;CACxB,CAAC;AAEF,oGAAoG;AACpG,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;AAE9C;;;;;;;GAOG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,sEAAsE;IACtE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,gEAAgE;IAChE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,iEAAiE;IACjE,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B,CAAC;AAEF,iGAAiG;AACjG,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;AAM1E;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,IAAI,WAAY,SAAS,QAAQ,OAAO,QAAO,cAAc;;;;gCAuFtE,CAAC;AAEL;;;;;GAKG;AACH,eAAO,MAAM,aAAa,eAAgB,aAAa,UAAU,SAAS,KAAG,MAGf,CAAC"}
@@ -0,0 +1,98 @@
1
+ /**
2
+ * A firewall alias on the wire: what PVE stores, and what it quietly changes on the way.
3
+ *
4
+ * ★ SPLIT OUT OF firewall-alias.ts TO KEEP BOTH FILES UNDER THE 250-LINE CAP, and the seam is the
5
+ * same one metric-server.ts and node-network.ts cut: this file answers "what does the cluster do
6
+ * to a value", firewall-alias.ts answers "what is an alias and when has it changed". Nothing here
7
+ * reads the cluster and nothing here decides a diff.
8
+ *
9
+ * ⛔ THE PUT IS A FULL REPLACE, WHICH IS THE EXACT INVERSE OF metric-server.ts — DO NOT COPY THAT
10
+ * FILE'S RULE OVER HERE. A metric server is a SectionConfig section and a PUT merges into it, so
11
+ * an omitted field SURVIVES and a managed optional needs a matching `delete=` or it can never be
12
+ * cleared. An alias is not: `update_alias` builds `$data = { name, cidr }`, adds `comment` only
13
+ * when it is truthy, and assigns the whole hash over the old one. So an omitted `comment` is
14
+ * CLEARED here, there is no `delete` parameter on this endpoint at all, and sending
15
+ * `comment=''` would be a second spelling of the same thing.
16
+ *
17
+ * ⚠️ THE SAME REPLACE MAKES `cidr` REQUIRED ON EVERY UPDATE. PVE's PUT schema does not mark it
18
+ * optional, and the Perl would build an entry with an undefined cidr if it could — so `body`
19
+ * below sends it on update as well as on create, rather than treating it as "only send what
20
+ * changed".
21
+ */
22
+ import type { FirewallAliasProps } from './firewall-alias.ts';
23
+ /**
24
+ * The alias key, as PVE computes it.
25
+ *
26
+ * ⚠️ EVERY ENTRY POINT LOWERS THE NAME AND NOTHING LOWERS THE STORED ONE: create, read, update and
27
+ * delete all start `my $name = lc($param->{name})`, while the entry keeps `name => $param->{name}`
28
+ * as written. So this is identity, and the stored spelling is decoration. Used by `diff` to tell
29
+ * an edit from a different alias — a comparison of the raw names would call a re-capitalisation a
30
+ * replace, and delete an alias to put back the same one.
31
+ */
32
+ export declare const fold: (name: string) => string;
33
+ /**
34
+ * A CIDR reduced to the one form PVE will hand back.
35
+ *
36
+ * ⛔ MEASURED by running the cluster's own `PVE::Firewall::parse_alias` on n2 (pve-manager 9.2.11,
37
+ * 2026-09-13) — a pure function over a string, no config read and none written:
38
+ * `10.1.1.5/32` -> `10.1.1.5` a /32 host suffix is STRIPPED
39
+ * `2001:0DB8::1/128`-> `2001:0DB8::1` a /128 is stripped, and the case is NOT folded
40
+ * `2001:db8::/32` -> `2001:db8::/32` a /32 on IPv6 is a real prefix and SURVIVES
41
+ * `parse_ip_or_cidr` is where it happens: `s|/32$||` under the IPv4 branch and `s|/128$||` under
42
+ * the IPv6 one. Unmatched, a declared `10.1.1.5/32` reads back as `10.1.1.5` and reports an
43
+ * update on every plan for the rest of time, each deploy writing back a value it already holds.
44
+ *
45
+ * ⛔ SO THE STRIP IS VERSION-AWARE, AND AN UNCONDITIONAL `/32` WOULD CORRUPT THE COMPARISON. A
46
+ * colon cannot appear in an IPv4 address and must appear in an IPv6 one, which is the whole
47
+ * discriminator PVE's own two regexes come down to here. Reading `2001:db8::/32` as
48
+ * `2001:db8::` would make a /32 prefix compare equal to a single host.
49
+ *
50
+ * ⚠️ AND IT STOPS THERE, ON PURPOSE. PVE does not lowercase, zero-pad or compress an IPv6 literal,
51
+ * so neither may this: it stores what it was handed and gives that back, which means any spelling
52
+ * is stable once written. Canonicalising further would make `matches` call two DIFFERENT stored
53
+ * strings equal and report noop over real drift — the same lie as missing a rewrite, pointed the
54
+ * other way.
55
+ */
56
+ export declare const cidr: (value: unknown) => string;
57
+ /**
58
+ * A comment reduced to the one form PVE will hand back.
59
+ *
60
+ * ⚠️ AN ALIAS COMMENT IS A TRAILING `#` ON ITS LINE IN `cluster.fw`, AND THE ROUND TRIP TRIMS IT.
61
+ * MEASURED with the same parser run: `Cmt 10.2.0.0/16 # spaced comment ` comes back as
62
+ * `spaced comment`. `parse_alias` strips the surrounding whitespace (`s/\s*#\s*(.*?)\s*$//`) and
63
+ * `format_aliases` refuses to write a blank one at all, so an untrimmed declaration would diff
64
+ * against its own stored form forever.
65
+ *
66
+ * ⛔ A COMMENT OF EXACTLY `0` CANNOT BE STORED, AND READING THAT AS DRIFT WOULD LOOP FOREVER.
67
+ * MEASURED: `Zero 10.3.0.0/16 # 0` parses to an entry with NO comment key. Both the create and
68
+ * the update guard with Perl's `if $param->{comment}`, and `'0'` is false in Perl — so the string
69
+ * is dropped before it ever reaches the file, on write as well as on read. Folded to `''` here
70
+ * because that is what the cluster will do with it: a declaration asking for something PVE will
71
+ * not keep should plan as noop and be documented, not diff on every plan and be unfixable by the
72
+ * very PUT the diff asks for.
73
+ *
74
+ * ⚠️ A LINE FEED IS A 400, NOT A TRUNCATION. `pve_fw_verify_comment_spec` dies with "comment must
75
+ * not contain a line feed", which is the honest answer and is left to PVE rather than silently
76
+ * flattened here — flattening would store something the declaration did not say.
77
+ */
78
+ export declare const comment: (value: unknown) => string;
79
+ /**
80
+ * Everything mutable, in the form PVE wants. Create adds `name`; update sends exactly this.
81
+ *
82
+ * ⚠️ `name` IS NOT SENT ON UPDATE BECAUSE IT IS ALREADY THE LAST SEGMENT OF THE PATH BEING PUT TO,
83
+ * and a second copy can only disagree with it — the same reasoning metric-server.ts gives for
84
+ * omitting its `id`. PVE takes the path segment as `$param->{name}` and writes it back as the
85
+ * stored spelling, so a PUT for any other reason also re-capitalises the entry to match the
86
+ * declaration. That is a side effect worth knowing about and not worth causing on its own.
87
+ *
88
+ * ⚠️ THE NORMALISED CIDR IS WHAT GETS WRITTEN, NOT THE DECLARED SPELLING. PVE stores the parameter
89
+ * verbatim into `cluster.fw` and only strips the host suffix when it reads the file back, so
90
+ * sending `10.1.1.5` rather than `10.1.1.5/32` leaves the file saying exactly what the next read
91
+ * will answer. Both settle; this one leaves no pair of values that merely happen to agree.
92
+ *
93
+ * ⚠️ `rename` IS DELIBERATELY ABSENT — see the ⚠️ on renames in firewall-alias.ts. A `rename` in
94
+ * this form would be a second, invisible identity for the object, set from a field the resource
95
+ * does not have.
96
+ */
97
+ export declare const body: (props: FirewallAliasProps) => Record<string, string>;
98
+ //# sourceMappingURL=firewall-alias-form.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"firewall-alias-form.d.ts","sourceRoot":"","sources":["../../src/proxmox/firewall-alias-form.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAG9D;;;;;;;;GAQG;AACH,eAAO,MAAM,IAAI,SAAU,MAAM,WAA8B,CAAC;AAEhE;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,IAAI,UAAW,OAAO,WAIlC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,OAAO,UAAW,OAAO,WAGrC,CAAC;AAEF;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,IAAI,UAAW,kBAAkB,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAGrE,CAAC"}
@@ -0,0 +1,141 @@
1
+ /**
2
+ * `Proxmox.FirewallAlias` — a named network the cluster firewall can be written in terms of.
3
+ *
4
+ * ★ WHY THIS FAMILY AND NOT FIREWALL RULES, WHICH IS THE ONE EVERYONE REACHES FOR FIRST. A rule is
5
+ * addressed BY POSITION — `/cluster/firewall/rules/{pos}` — so inserting a rule renumbers every
6
+ * rule below it. A position-keyed resource therefore RETARGETS ITSELF at somebody else's rule the
7
+ * moment anything is inserted above it, and it does so while the plan looks clean: the path still
8
+ * resolves, the read still succeeds, the diff is simply computed against the wrong object.
9
+ * Aliases, ipsets and security groups are the firewall objects with STABLE IDENTITY — a name, not
10
+ * an index — and they are the ones worth declaring. Rules belong in this package only once
11
+ * somebody models the whole ordered list as ONE resource, which is a different shape from
12
+ * `PveSpec` and should look different.
13
+ *
14
+ * ★ AND THE ALIAS IS THE PIECE THAT EARNS THE MOST BY BEING DECLARED. `10.1.0.0/16` spelled into
15
+ * nine rules is nine places to edit and one to forget; `HomeLan` spelled into nine rules is one
16
+ * place, resolved by PVE at compile time. The alias is the object that has to be right.
17
+ *
18
+ * ⛔ PVE REWRITES THE CIDR ON READ, AND THAT IS THE FOREVER-DIFF THIS RESOURCE IS SHAPED AROUND.
19
+ * A declared `10.1.1.5/32` reads back as `10.1.1.5`. `cidr()` in `firewall-alias-form.ts` applies
20
+ * exactly the cluster's own transformation to BOTH sides and carries the measurements; read that
21
+ * comment before touching either side of `matches` below.
22
+ *
23
+ * ⛔ `ipversion` IS RETURNED BY THE READ AND REFUSED BY EVERY WRITE. `parse_alias` derives it from
24
+ * the address and `read_alias` hands the parsed entry straight back, while POST and PUT declare
25
+ * `additionalProperties: 0` with no such parameter — sending it is a 400, not an ignored hint. It
26
+ * is REPORTED as an attribute so a plan can say whether an alias is v4 or v6, and kept OUT of
27
+ * `matches`, exactly like `pool.members` and `user.tokens`.
28
+ *
29
+ * ⚠️ `digest` NEVER REACHES THIS PROVIDER, which is a better answer than keeping it out of
30
+ * `matches`. The LIST read runs its entries through `copy_list_with_digest` and stamps one — and
31
+ * it changes whenever ANYTHING else in the firewall config changes, so a resource that stored it
32
+ * would diff on a rule somebody else edited. The SINGLE-OBJECT read this resource uses returns
33
+ * `$aliases->{$name}` raw, with no digest in it at all. None is sent on write either:
34
+ * `PVE::Tools::assert_if_modified` skips the comparison when either side is undef, and the API
35
+ * handler already holds `lock_clusterfw_conf(10, ...)` for the whole read-modify-write. So
36
+ * declining optimistic locking buys last-writer-wins between two concurrent editors, not a torn
37
+ * file — and the alternative, storing a cluster-wide digest per alias, buys a permanent diff.
38
+ *
39
+ * ⚠️ THE NAME IS CASE-FOLDED FOR IDENTITY AND PRESERVED FOR DISPLAY, which reads as a bug until you
40
+ * see both halves. The config is keyed `$aliases->{lc($data->{name})}` while the entry stores the
41
+ * name as written, and the item GET lowers its path segment too — so `homelan` and `HomeLan` are
42
+ * ONE alias, reachable by either spelling. `name` is therefore reported from the live config and
43
+ * kept OUT of `matches`: rewriting an alias to change its capitalisation is a cosmetic write to
44
+ * the file every node recompiles its firewall from.
45
+ * ⛔ AND TWO DECLARATIONS DIFFERING ONLY IN CASE ARE THE SAME OBJECT, which is the `acl.ts`
46
+ * hazard again. Alchemy sees two resource ids, the cluster sees one alias, and deleting either
47
+ * takes it away from both.
48
+ *
49
+ * ⚠️ A RENAME IS MODELLED AS A REPLACE, NOT AS AN UPDATE, AND THE REJECTED OPTION WAS REAL. PVE's
50
+ * PUT does take a `rename` parameter and Alchemy's `reconcile` does receive `olds`, so an
51
+ * in-place rename was available. It was rejected because using it means hand-writing `reconcile`
52
+ * as well as `diff` and branching on four states — old present or absent, new present or absent —
53
+ * each branch a fresh way to write the wrong object, and all of it to buy only the gap between
54
+ * the create and the delete. What a rename must NOT be is silent, which is what the factory alone
55
+ * would make it: the read at the NEW path answers absent, `diff` says update, reconcile POSTs a
56
+ * SECOND alias, and the old one stays in `cluster.fw` with its old CIDR — still resolving in
57
+ * every rule that names it, and invisible to every later plan. `diff` below says `replace`.
58
+ * ⚠️ CREATE-FIRST, as Alchemy defaults and as `acl.ts` argues: the new alias exists before the
59
+ * old one goes, so a rules change can be sequenced between the two generations.
60
+ *
61
+ * ⚠️ PRIVILEGES, AND FOR ONCE NOTHING NEEDS WIDENING. MEASURED 2026-09-13 from the cluster's own
62
+ * schema and its live ACL: the item GET checks `["perm","/",["Sys.Audit"]]`, POST/PUT/DELETE
63
+ * check `["perm","/",["Sys.Modify"]]`, `hf-read@pve` holds `PVEAuditor` at `/` with propagate and
64
+ * `hf-provision@pve` holds `LXCProvisioner` at `/` with propagate. Both privileges are already
65
+ * held, so `readRole` stays the default `read` lane — unlike storage/sdn-zone/sdn-vnet, whose
66
+ * ITEM reads are gated on an allocate privilege the auditor cannot have.
67
+ * ⚠️ `Sys.Modify` ON `/` IS STILL A BIG HAMMER — it is the same grant `metric-server.ts` warns
68
+ * about, and there is no `/firewall` object to scope a narrower role to.
69
+ *
70
+ * ⚠️ DELETION IS FULLY IMPLEMENTED AND THE DEFAULT POLICY IS DELIBERATELY NOT `retain`. The ★ in
71
+ * `resource.ts` reserves `retain` for objects whose CONTENTS cannot be rebuilt from a line of
72
+ * TypeScript; an alias is a name, a CIDR and a comment, all three of them in the declaration, so
73
+ * recreating one is exact and free. The real hazard is referential — PVE checks nothing before
74
+ * removing an alias, and a rule naming a removed one fails to compile — and `retain` would not
75
+ * fix that, it would only leave an undeclared alias on the cluster forever. Sequence the rules,
76
+ * or pipe `RemovalPolicy.retain()` at the declaration site where the reason is visible.
77
+ *
78
+ * ⚠️ `local_network` IS THE ONE ALIAS NAME WITH CLUSTER-WIDE MEANING. `compile_ipsets` reads
79
+ * `aliases->{local_network}` to decide what the `management` ipset covers, and SYNTHESISES one
80
+ * from the node's own subnet when it is missing — in memory, never written back to the file.
81
+ * Declaring it is stable, because PVE leaves a present one alone. DELETING it hands that decision
82
+ * silently back to autodetection, which is drift no plan will ever show.
83
+ *
84
+ * ⚠️ NO SECRET LIVES IN THIS FAMILY, so nothing here has to be typed `never` to keep it out of
85
+ * Alchemy's unencrypted state the way `metric-server.ts` does with its `token`. A name, a CIDR and
86
+ * a free-text comment are the whole object, and all three are the declaration's own values read
87
+ * back — not a credential held by the cluster.
88
+ *
89
+ * ⚠️ ACCEPTANCE, STATED HONESTLY: `GET /cluster/firewall/aliases` ANSWERS `[]` ON THIS CLUSTER and
90
+ * the cluster firewall is disabled, so there was no live alias to declare and NO create/plan/noop
91
+ * round trip was run. What is measured is the published schema, the API module's Perl, and the
92
+ * cluster's own `parse_alias` exercised on sample lines. Whoever declares the first alias should
93
+ * confirm the SECOND plan says noop before trusting this file.
94
+ */
95
+ import { Resource } from 'alchemy';
96
+ import * as Provider from 'alchemy/Provider';
97
+ import { type PveRequirements, type WithTarget } from './resource.ts';
98
+ export interface FirewallAliasProps extends WithTarget {
99
+ /**
100
+ * PVE's `pve-fw-alias`: a letter, then at least one more of letter/digit/`-`/`_`, to 64 chars.
101
+ * ⚠️ IDENTITY, CASE-INSENSITIVELY — see the ⚠️ on folding in the header. A two-character minimum
102
+ * is real: a one-letter name is refused by the pattern, not silently accepted.
103
+ */
104
+ name: string;
105
+ /**
106
+ * An IP or a network, e.g. `10.1.0.0/16`, `10.1.1.5`, `2001:db8::/32`.
107
+ * ⚠️ A `/32` (or `/128`) SUFFIX IS DROPPED BY PVE AND BY `cidr()` ALIKE, so declaring one is
108
+ * harmless — it simply is not what comes back. Anything `parse_ip_or_cidr` refuses is a 400.
109
+ */
110
+ cidr: string;
111
+ /**
112
+ * Free text, stored as a trailing `#` comment on the alias's line in `cluster.fw`.
113
+ * ⚠️ TRIMMED, AND A LINE FEED IS REFUSED. A comment of exactly `0` cannot be stored at all — the
114
+ * ⛔ in `firewall-alias-form.ts` measures why, and why declaring one plans as noop.
115
+ */
116
+ comment?: string;
117
+ }
118
+ export interface FirewallAliasAttributes {
119
+ /** The spelling held in `cluster.fw`, which need not be the declared one. Never compared. */
120
+ name: string;
121
+ /** Normalised the way PVE normalises it, so it is comparable with a declaration. */
122
+ cidr: string;
123
+ comment: string;
124
+ /**
125
+ * 4 or 6, derived by PVE from the address. Reported so a plan can show which stack an alias
126
+ * covers; never compared, because no write accepts it.
127
+ */
128
+ ipversion: number;
129
+ }
130
+ export interface ProxmoxFirewallAlias extends Resource<'Proxmox.FirewallAlias', FirewallAliasProps, FirewallAliasAttributes, never, PveRequirements> {
131
+ }
132
+ export declare const ProxmoxFirewallAlias: import("alchemy").ResourceClass<ProxmoxFirewallAlias>;
133
+ /**
134
+ * ⛔ ONE HANDLER IS OVERRIDDEN AND THE REST COME FROM THE FACTORY, for the reason `acl.ts` spells
135
+ * out at length: the factory answers `replace` only for an object with no update path, and this
136
+ * one has a PUT. Left to delegate, a changed `name` would read absent at the new path, plan as an
137
+ * update, and quietly leave the old alias behind. Everything else — the empty `list`, the read,
138
+ * the read-back-guarded reconcile, the delete — is the factory's, unchanged.
139
+ */
140
+ export declare const ProxmoxFirewallAliasProvider: () => import("effect/Layer").Layer<Provider.Provider<ProxmoxFirewallAlias>, never, import("effect/unstable/http/HttpClient").HttpClient>;
141
+ //# sourceMappingURL=firewall-alias.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"firewall-alias.d.ts","sourceRoot":"","sources":["../../src/proxmox/firewall-alias.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6FG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAG7C,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,UAAU,EAAe,MAAM,eAAe,CAAC;AAGnF,MAAM,WAAW,kBAAmB,SAAQ,UAAU;IACpD;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,uBAAuB;IACtC,6FAA6F;IAC7F,IAAI,EAAE,MAAM,CAAC;IACb,oFAAoF;IACpF,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,oBAAqB,SAAQ,QAAQ,CACpD,uBAAuB,EACvB,kBAAkB,EAClB,uBAAuB,EACvB,KAAK,EACL,eAAe,CAChB;CAAG;AAEJ,eAAO,MAAM,oBAAoB,uDAA0D,CAAC;AAuC5F;;;;;;GAMG;AACH,eAAO,MAAM,4BAA4B,0IAiBtC,CAAC"}