@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,147 @@
1
+ /**
2
+ * A PBS datastore on the wire: the transport that reaches PBS, the form it wants, and the coercion
3
+ * back to something comparable.
4
+ *
5
+ * ★ SPLIT OUT OF pbs-datastore.ts FOR THE 250-LINE CAP, the seam notification-target-form.ts uses:
6
+ * this file is everything that touches PBS's encoding, and the resource file is the declaration
7
+ * and the five handlers. The `import type` back is erased, so it is a cycle on paper only.
8
+ *
9
+ * ⛔ THIS FILE IS OVER THE 250-LINE CAP AND THE EXTRACTION IS NAMED RATHER THAN FUDGED. `PbsTarget`,
10
+ * `PbsRole`, `PbsError`, `pbsAuthorization`, `PveForm`, `encode`, `pbs` and `settle` — about 150
11
+ * lines — are a PBS CLIENT, not a datastore form, and belong in `pbs-client.ts`. Lifting them
12
+ * leaves this file near 200 and costs nothing but a move. It was not done here only because the
13
+ * family was commissioned as a two-file split; ceph-pool is the in-package precedent for three
14
+ * (ceph-pool.ts + ceph-pool-form.ts + ceph-pool-settle.ts, 532 lines for one family). Everything
15
+ * in that list is also what Pbs.SyncJob, Pbs.PruneJob and Pbs.Remote will each need unchanged,
16
+ * so the second PBS family forces the move anyway. ⛔ DO NOT MEET THE CAP BY CUTTING COMMENTS.
17
+ */
18
+ import * as Effect from 'effect/Effect';
19
+ import { type PveForm } from './client.ts';
20
+ import type { PbsTarget as ApiPbsTarget } from './credentials.ts';
21
+ import type { PbsDatastoreProps } from './pbs-datastore.ts';
22
+ /**
23
+ * ★ PBS REUSES THE PVE CLIENT RATHER THAN OWNING ONE. An earlier draft of this file carried its
24
+ * own `PbsTarget`, `PbsError`, `pbsAuthorization`, form encoder and `pve()` — a near-copy of
25
+ * client.ts differing in one header. They are gone: `PveTarget` now carries a `scheme`, and
26
+ * `authorization()` spells the header `PBSAPIToken=<id>:<secret>` when it is `'pbs'`. The
27
+ * insight that survived is the FORM TYPE — PBS decodes a multi-valued field from repeated keys
28
+ * where PVE wants a comma string — and that now lives on `PveForm` in client.ts, so both
29
+ * products share one encoder and neither can reach for the other's convention by accident.
30
+ *
31
+ * 🔴 THIS ALIAS SAID `= PveTarget` AND IT WAS WRONG — Pbs.Datastore REQUIRED A PVE TARGET. When
32
+ * `credentials.ts` grew a real `PbsTarget` with `scheme: 'pbs'`, this line was left pointing at
33
+ * the PVE type, which pins `scheme: 'pve'`. So the one family that most needs the discriminant
34
+ * was the one family that refused the correct value: declaring a datastore against the PBS host
35
+ * failed to compile with `Type '"pbs"' is not assignable to type 'Input<"pve">'`, and passing a
36
+ * PVE target compiled fine and would have 401'd every call — which `read` folds into "absent",
37
+ * so the plan would say CREATE for a datastore holding the estate's backups.
38
+ * ⛔ IT SURVIVED BECAUSE NOTHING EVER DECLARED ONE. The provider was registered in
39
+ * alchemy.run.ts from the day it was written and `pveHandlers`' `list` answers empty, so
40
+ * registration exercises no call site at all. Three sibling families import `PbsTarget` from
41
+ * credentials.ts directly and were always correct; only the one with its own alias drifted.
42
+ * ★ THE LESSON, WHICH IS NOT ABOUT THIS TYPE: a provider nobody has declared an instance of is
43
+ * not tested by anything, including tsc.
44
+ */
45
+ export type PbsTarget = ApiPbsTarget;
46
+ export interface PbsDatastoreAttributes {
47
+ name: string;
48
+ /**
49
+ * ⚠️ READ FROM PBS, NEVER ECHOED FROM PROPS. Echoing the declared path would make a divergent or
50
+ * unreadable datastore look like agreement, and this is the field whose divergence means the
51
+ * backups are going somewhere nobody declared. `''` when PBS did not say.
52
+ */
53
+ path: string;
54
+ comment: string;
55
+ 'gc-schedule': string;
56
+ 'prune-schedule': string;
57
+ 'keep-last': number;
58
+ 'keep-hourly': number;
59
+ 'keep-daily': number;
60
+ 'keep-weekly': number;
61
+ 'keep-monthly': number;
62
+ 'keep-yearly': number;
63
+ /** Normalised property strings — sorted and canonicalised, so key order is never a diff. */
64
+ notify: string;
65
+ 'notify-user': string;
66
+ 'verify-new': boolean;
67
+ tuning: string;
68
+ 'maintenance-mode': string;
69
+ /** ⚠️ Create-only. Canonicalised property string; `''` on a plain local datastore. */
70
+ backend: string;
71
+ 'counter-reset-schedule': string;
72
+ 'notification-thresholds': string;
73
+ }
74
+ /**
75
+ * ⚠️ `digest` IS DELIBERATELY NOT AN ATTRIBUTE, for storage.ts's reason exactly: PBS returns one on
76
+ * every read and it covers `datastore.cfg` as a FILE, not this section of it, so keeping it would
77
+ * rewrite this resource's state whenever an unrelated datastore was edited — churn that reads
78
+ * like drift. It is not sent on writes either, so this family never joins PBS's optimistic-locking
79
+ * dance and last write wins, as everywhere else in this package.
80
+ */
81
+ export declare const attributes: (live: Record<string, unknown>, props: PbsDatastoreProps) => PbsDatastoreAttributes;
82
+ /**
83
+ * ⛔ DECLARING WHAT IS LIVE MUST PLAN noop, AND EVERY OMISSION IS DELIBERATE. Out: `name` (the
84
+ * address the read was made at — true by construction, never a diff); `path` (create-only, so
85
+ * comparing it could only plan an update no PUT can apply — pbs-datastore.ts guards it by dying
86
+ * instead, see the ⛔ on the prop); `digest` (not an attribute, above); and every field the
87
+ * declaration does not mention, because undeclared is UNMANAGED here.
88
+ * ⚠️ A SCHEDULE THAT NEVER SETTLES MEANS PBS NORMALISED IT. Calendar events are compared as trimmed
89
+ * strings; if a version rewrites `sat 18:15` as `Sat 18:15` the plan asks for the same update
90
+ * forever. The fix is to declare the spelling PBS stores, never to stop comparing it.
91
+ */
92
+ export declare const matches: (live: PbsDatastoreAttributes, props: PbsDatastoreProps) => boolean;
93
+ /**
94
+ * ⚠️ `path` IS SENT ONCE, HERE, AND NEVER AGAIN — the fact the whole `path` guard hangs off.
95
+ * ⚠️ `reuse-datastore` IS NOT SENT, AND THE REFUSAL IT CAUSES IS A FEATURE: without it PBS refuses
96
+ * a create against a directory that already holds a chunk store, which is the difference between
97
+ * building a new store and silently adopting somebody else's backups. Adopt out of band.
98
+ * ⚠️ NEITHER IS `backing-device`. A removable datastore's UUID is a property of the hardware in the
99
+ * slot, not of the declaration; one that could re-point it is one that can send backups to the
100
+ * wrong drive.
101
+ */
102
+ export declare const createForm: (props: PbsDatastoreProps) => PveForm;
103
+ /**
104
+ * ⛔ THERE IS NO `delete` LIST HERE, AND THAT IS A CHOICE ABOUT BACKUPS RATHER THAN AN OMISSION.
105
+ * sdn-vnet.ts derives one from absent props, which is right for an alias and wrong for a
106
+ * retention policy: a declaration that simply fails to mention `keep-daily` would strip it, and a
107
+ * prune job whose keeps have all been stripped is one PBS version away from a prune job that
108
+ * keeps nothing. So undeclared is UNMANAGED, as in storage.ts and backup-job.ts.
109
+ * ⚠️ THE PRICE IS THAT DROPPING A LINE DOES NOT CLEAR A FIELD. Clear one out of band:
110
+ * `proxmox-backup-manager datastore update <name> --delete keep-daily`. It does not cost a
111
+ * forever-diff, because an undeclared field is not compared either.
112
+ * ⛔ WHEN SOMEBODY ADDS ONE, IT TAKES TWO STEPS AND SKIPPING EITHER IS A SILENT BUG. First build
113
+ * it with `values.withClears`, which drops a cleared key from the body — CLEAR WINS — because
114
+ * PBS applies its deletes BEFORE its sets, so a key both set and deleted keeps its value: the
115
+ * declaration would say "unset this", the PUT would succeed, and the next plan would ask for
116
+ * the very same update forever. (PVE instead DIES on that pair; the two behaviours want the
117
+ * same guard.) Second, split the comma-joined value `withClears` produces into a real array —
118
+ * PBS's `delete` is `type: array` and wants REPEATED KEYS, and a comma string arrives as one
119
+ * element that fails the enum check. `PveForm` and `encode` already carry arrays for exactly
120
+ * this. ⚠️ REASONED FROM THE PUBLISHED SCHEMA, NOT PROVEN ON A WIRE.
121
+ */
122
+ export declare const updateForm: (props: PbsDatastoreProps) => PveForm;
123
+ export declare const object: (props: PbsDatastoreProps) => string;
124
+ /**
125
+ * The live datastore, or undefined.
126
+ *
127
+ * ⛔ `name` IS THE PRESENCE TEST, NOT THE STATUS CODE — PBS does not answer 404 for a section that
128
+ * is missing from `datastore.cfg`, it answers a generic error, so there is no code to key off.
129
+ * ⛔ A MISSING READ PRIVILEGE THEREFORE LOOKS EXACTLY LIKE ABSENCE, because the fold below cannot
130
+ * tell them apart. The signature is a plan that says CREATE followed by PBS answering
131
+ * "datastore '<name>' already exists." — that pair means Datastore.Audit, not a missing
132
+ * datastore. It is loud and non-destructive, which is the only reason the fold is tolerable here;
133
+ * see the ⛔ on `readRole` in resource.ts for the PVE families where it is not.
134
+ * ⛔ ON THE DELETE PATH THE SAME FOLD IS A LIE, AND THIS IS THE ONE HAZARD IN THIS FAMILY I COULD
135
+ * NOT CLOSE. `delete` settles by polling this read until it answers `undefined` — and a `read`
136
+ * role that lacks `Datastore.Audit` answers `undefined` from the very first poll, so EVERY delete
137
+ * would report success while the datastore stood. Worse, the two lanes are different leases: the
138
+ * DELETE goes out under `provision` and may genuinely fail, and this read cannot see that it did.
139
+ * ★ THE SHAPE OF THE FIX IS ALREADY IN THIS PACKAGE: `confirmAbsent` in ceph-pool-settle.ts asks
140
+ * a SECOND, DIFFERENT question — does the collection LIST this object? — and lets a failure
141
+ * PROPAGATE rather than folding it, so "I could not ask" fails the deploy instead of passing
142
+ * it. Add the same over `GET /config/datastore` before anyone relies on a reported deletion.
143
+ * ⚠️ UNTIL THEN THE PRECONDITION IS EXPLICIT: the `read` role MUST hold `Datastore.Audit` on the
144
+ * datastore, or this provider cannot tell a deletion from a refusal.
145
+ */
146
+ export declare const readOne: (props: PbsDatastoreProps) => Effect.Effect<PbsDatastoreAttributes | undefined, never, import("effect/unstable/http/HttpClient").HttpClient>;
147
+ //# sourceMappingURL=pbs-datastore-form.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pbs-datastore-form.d.ts","sourceRoot":"","sources":["../../src/proxmox/pbs-datastore-form.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,KAAK,OAAO,EAAO,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,SAAS,IAAI,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAClE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAG5D;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,MAAM,SAAS,GAAG,YAAY,CAAC;AAErC,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,4FAA4F;IAC5F,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,OAAO,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,kBAAkB,EAAE,MAAM,CAAC;IAC3B,sFAAsF;IACtF,OAAO,EAAE,MAAM,CAAC;IAChB,wBAAwB,EAAE,MAAM,CAAC;IACjC,yBAAyB,EAAE,MAAM,CAAC;CACnC;AAED;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,SACf,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,SACtB,iBAAiB,KACvB,sBAoBD,CAAC;AAIH;;;;;;;;;GASG;AACH,eAAO,MAAM,OAAO,SAAU,sBAAsB,SAAS,iBAAiB,YAkBK,CAAC;AAqCpF;;;;;;;;GAQG;AACH,eAAO,MAAM,UAAU,UAAW,iBAAiB,KAAG,OASpD,CAAC;AAEH;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,UAAU,UAAW,iBAAiB,KAAG,OAAyB,CAAC;AAEhF,eAAO,MAAM,MAAM,UAAW,iBAAiB,WAAqC,CAAC;AAErF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,OAAO,UAAW,iBAAiB,mHAM7C,CAAC"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * The two things a datastore write needs that are not form-building: refusing a moved `path`, and
3
+ * waiting for PBS to finish.
4
+ *
5
+ * ★ SPLIT OUT OF pbs-datastore-form.ts FOR THE 250-LINE CAP, and the seam is real. That file turns
6
+ * a declaration into a form; this one is the SAFETY GUARD and the POLLING. A reader asking "can
7
+ * this destroy my backups" has one short file to read rather than a long one to search.
8
+ */
9
+ import * as Effect from 'effect/Effect';
10
+ import { type PbsDatastoreAttributes } from './pbs-datastore-form.ts';
11
+ import type { PbsDatastoreProps } from './pbs-datastore.ts';
12
+ /**
13
+ * ⛔ THE `path` GUARD, YIELDED FROM BOTH `diff` AND `reconcile`. Both need it: `diff` catches a
14
+ * changed declaration, and `reconcile` catches an ADOPTION, which Alchemy routes straight past
15
+ * `diff` (Apply.ts:980, :1045). `''` is skipped — an unreadable path is not a divergent one.
16
+ */
17
+ export declare const guardPath: (live: PbsDatastoreAttributes, props: PbsDatastoreProps) => Effect.Effect<void, never, never>;
18
+ /**
19
+ * ⛔ THE `backend` GUARD, AND IT MATTERS MORE THAN `path`. A wrong `path` sends backups to the
20
+ * wrong directory on the same machine; a wrong `backend` is the difference between a datastore
21
+ * on local disk and one in a Cloudflare R2 bucket. MEASURED on 4.2: `datastore create` takes
22
+ * `--backend`, `datastore update` does not, and `backend` is not in update's `--delete` enum —
23
+ * so divergence CANNOT be reconciled, and the only honest options are to refuse or to lie.
24
+ *
25
+ * ⚠️ AN UNDECLARED `backend` IS NOT A DIVERGENCE. Undeclared is unmanaged everywhere in this
26
+ * family, and this guard keeps that rule: it fires only when the declaration says something and
27
+ * PBS says something else. Adopting `r2-offsite` without mentioning `backend` still plans noop.
28
+ *
29
+ * ⚠️ COMPARED AS A CANONICAL PROPERTY STRING, so `bucket=x,type=s3` and `type=s3,bucket=x` are the
30
+ * same backend and key order cannot deadlock a plan — the reason `samePath` trims a slash.
31
+ */
32
+ export declare const guardBackend: (live: PbsDatastoreAttributes, props: PbsDatastoreProps) => Effect.Effect<void, never, never>;
33
+ /**
34
+ * Wait for PBS to finish, then answer the last thing it said.
35
+ *
36
+ * ⛔ IT EXISTS BECAUSE A PBS CREATE IS A FORKED WORKER AND THE CONFIG SECTION IS WRITTEN LAST.
37
+ * `POST /config/datastore` answers with a UPID while a `create-datastore` task builds the chunk
38
+ * store's 65536 directories; only when that finishes does the section reach `datastore.cfg`. An
39
+ * immediate read-back therefore sees a datastore that is not there yet, and the factory's "the
40
+ * write returned no error but the object is still absent" would fire on a create going perfectly.
41
+ * The DELETE forks a worker too. ⚠️ DOCUMENTED FROM THE PUBLISHED SCHEMA, NOT MEASURED — I hold
42
+ * no PBS token. If a create turns out to be synchronous, the first poll simply succeeds.
43
+ * ★ IT TAKES THE READ AS AN EFFECT RATHER THAN A FUNCTION — the one simplification over
44
+ * ceph-pool-settle.ts: an Effect is a description, so re-running it re-reads and no dependency
45
+ * has to be threaded back in to avoid a cycle.
46
+ * ⚠️ 2s APART, 60 TRIES, ABOUT TWO MINUTES — longer than ceph-pool's minute, and REASONED rather
47
+ * than measured: 65536 `mkdir`s is seconds on NVMe and can be a minute on a slow or USB disk.
48
+ * Anything still unsettled after two minutes is a fault to surface, not a wait to lengthen, and
49
+ * the caller's message points at the task log, which is where the real answer is. `Effect.sleep`
50
+ * yields between polls; nothing here parks a call on one long wait.
51
+ * ⚠️ POLLING THE TASK STATUS INSTEAD WOULD BE WORSE, for ceph-pool-settle.ts's reason: every call
52
+ * mints a FRESH token, so the token asking about the task is not the one that started it.
53
+ */
54
+ export declare const settle: <A, E, R>(read: Effect.Effect<A, E, R>, done: (live: A) => boolean) => Effect.Effect<A, E, R>;
55
+ //# sourceMappingURL=pbs-datastore-guard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pbs-datastore-guard.d.ts","sourceRoot":"","sources":["../../src/proxmox/pbs-datastore-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,KAAK,sBAAsB,EAAU,MAAM,yBAAyB,CAAC;AAC9E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAmB5D;;;;GAIG;AACH,eAAO,MAAM,SAAS,SAAU,sBAAsB,SAAS,iBAAiB,sCAWzE,CAAC;AAER;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,YAAY,SAAU,sBAAsB,SAAS,iBAAiB,sCAY5E,CAAC;AAER;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,MAAM,GAAI,CAAC,EAAE,CAAC,EAAE,CAAC,QAAQ,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,2BAQpF,CAAC"}
@@ -0,0 +1,140 @@
1
+ /**
2
+ * `Pbs.Datastore` — one section of Proxmox Backup Server's `datastore.cfg`, declared.
3
+ *
4
+ * ★ PBS IS A SIBLING OF PVE, NOT A PART OF IT. The estate runs both — PVE carries a storage of
5
+ * `type: pbs` — so declaring the datastore turns `Proxmox.Storage`'s `locator.datastore` from a
6
+ * string nothing checks into a reference Alchemy can order, as `Proxmox.SdnVnet` did for a bridge.
7
+ *
8
+ * ⛔ DIFFERENT HOST, DIFFERENT REALM, DIFFERENT AUTH HEADER. MEASURED 2026-09-13, strict TLS, no
9
+ * `-k` anywhere: `GET https://pbs.example.com:8007/api2/json/ping` answers 200
10
+ * `{"data":{"pong":true}}` against a Let's Encrypt certificate for CN=pbs.example.com;
11
+ * `/version` and `/config/datastore` answer 401 "authentication failed";
12
+ * `pbs.mgmt.example.com:8007` answers 401 and its certificate verifies too; and
13
+ * `/access/domains` lists the realms `pbs`, `pam` and an openid realm `Schenanigans`. So the
14
+ * prefix, the `{"data": …}` envelope and the strict-TLS story are PVE's exactly — and only the
15
+ * credential differs. There is no `pve` realm here; a PVE token cannot authenticate at all.
16
+ * The header differs too, which is why `pve()` exists rather than `pve()` being reused — see the
17
+ * ⛔ on `pbsAuthorization` in pbs-datastore-form.ts.
18
+ *
19
+ * ⛔ THERE IS NO OPENBAO MOUNT FOR PBS TODAY, SO NOTHING HERE CAN DEPLOY YET. `PbsTarget.mount` is
20
+ * a parameter for the reason `PveTarget.mount` is — the provider must be able to leave this
21
+ * estate — but the estate has nothing to put in it. MEASURED: under the `claude-code` approle,
22
+ * `bao token capabilities` answers `deny` for `proxmox-tb4/creds/{read,provision}`,
23
+ * `proxmox-ops/creds/read` and every `…pbs…` path tried, and `sys/mounts` is 403 — so I could
24
+ * not enumerate the mounts to PROVE a PBS one is absent. That it is absent is the brief's
25
+ * statement, not my measurement.
26
+ * ★ WHAT THE MOUNT MUST VEND, so `mint()` is reused unchanged: `bao read -format=json
27
+ * <mount>/creds/<role>` answering `{"data":{"token_id":…,"secret":…}}`, where `token_id` is a
28
+ * PBS token id `user@realm!tokenname` — `hf-read@pbs!…` and `hf-provision@pbs!…`. Same short,
29
+ * non-renewable lease contract as `proxmox-tb4`.
30
+ * ⚠️ PBS HAS NO DYNAMIC-SECRETS PLUGIN OF ITS OWN — OpenBao's Proxmox support is a PVE thing — so
31
+ * the mount is a small custom vendor against `POST /access/users/{id}/token/{name}`. Say which
32
+ * mount and role you needed rather than reaching for the read-only `monitoring@pbs` token on
33
+ * the kv shelf: widening that would delete the outer lock for every reader of the shelf.
34
+ *
35
+ * ⛔ A DATASTORE HOLDS THE BACKUPS, SO `retain` IS THE DEFAULT AND `delete` IS FULLY IMPLEMENTED —
36
+ * the ★ on removal policy in resource.ts has the whole reasoning. A stub returning `Effect.void`
37
+ * would report a deletion that never happened, and this is the family where that lie costs most.
38
+ *
39
+ * ⚠️ PRIVILEGES, READ OFF THE PUBLISHED SCHEMA RATHER THAN OFF THIS HOST:
40
+ * read GET config/datastore/{name} Datastore.Audit on /datastore/{name}
41
+ * create POST config/datastore Datastore.Allocate on /datastore
42
+ * update PUT config/datastore/{name} Datastore.Modify on /datastore/{name}
43
+ * delete DELETE config/datastore/{name} Datastore.Allocate on /datastore/{name}
44
+ * Built-in `DatastoreAdmin` at `/datastore` covers all four; `DatastoreAudit` covers the read
45
+ * lane alone, which is what the `read` role should hold.
46
+ *
47
+ * ⛔ NO SECRET IS A PROP OR AN ATTRIBUTE, AND THIS FAMILY IS CLEAN BY CONSTRUCTION: a datastore
48
+ * section holds no password, token or key — encryption keys belong to the backup CLIENT. Every
49
+ * field below is a name, a path, a schedule, a count or a policy string, all of which are safe in
50
+ * a state store Alchemy writes UNENCRYPTED and this estate dumps to CT100 nightly.
51
+ */
52
+ import { Resource } from 'alchemy';
53
+ import * as Provider from 'alchemy/Provider';
54
+ import { type PbsDatastoreAttributes, type PbsTarget } from './pbs-datastore-form.ts';
55
+ import type { PveRequirements } from './resource.ts';
56
+ export type { PbsDatastoreAttributes, PbsTarget };
57
+ /**
58
+ * ⚠️ PBS'S OWN KEY NAMES, HYPHENS INCLUDED — backup-job.ts's rule: the form is then a copy rather
59
+ * than a translation table, and a translation table is one more place for a key to be renamed and
60
+ * silently never sent.
61
+ * ⚠️ AN UNDECLARED FIELD IS NEITHER SENT NOR COMPARED — storage.ts's rule, not sdn-vnet.ts's, and
62
+ * for a retention policy the choice is not close: see the ⛔ on `updateForm`.
63
+ */
64
+ export interface PbsDatastoreProps {
65
+ target: PbsTarget;
66
+ /** PBS's primary key. Create-only: there is no rename, and a new name is a new datastore. */
67
+ name: string;
68
+ /**
69
+ * Absolute path to the datastore directory.
70
+ *
71
+ * ⛔ CREATE-ONLY, AND THE ONE FIELD THIS FILE REFUSES TO LET DRIFT QUIETLY. PBS's update endpoint
72
+ * does not accept `path`, so comparing it in `matches` could only plan an update no PUT can
73
+ * apply — the forever-diff storage.ts avoids by letting its create-only `type` plan as NOOP.
74
+ * Here a silent noop is the wrong trade: the operator would read a green plan while PBS kept
75
+ * writing backups to the old directory. So `diff` and `reconcile` compare it themselves and DIE
76
+ * with both values named. A path change is remove-and-redeclare, deliberately.
77
+ */
78
+ path: string;
79
+ comment?: string;
80
+ /** Calendar event for garbage collection, e.g. `daily` or `sat 18:15`. */
81
+ 'gc-schedule'?: string;
82
+ /** Calendar event for the built-in prune job. Retention itself is the `keep-*` fields below. */
83
+ 'prune-schedule'?: string;
84
+ /** ⚠️ PBS's minimum is 1 for every keep-*. A declared `0` is refused, and does not mean "off". */
85
+ 'keep-last'?: number;
86
+ 'keep-hourly'?: number;
87
+ 'keep-daily'?: number;
88
+ 'keep-weekly'?: number;
89
+ 'keep-monthly'?: number;
90
+ 'keep-yearly'?: number;
91
+ /**
92
+ * Legacy notification routing: `gc=<never|always|error>`, and the same for `verify` and `sync`.
93
+ * ⚠️ PBS 3.2+ picks between this and the notification system with `notification-mode`, which is
94
+ * NOT declarable here: flipping a live datastore between the two silently changes who hears
95
+ * about a failed verify, and silence is the failure mode that costs most (notification-target.ts).
96
+ */
97
+ notify?: string;
98
+ /** PBS user id legacy notifications go to. PBS's schema default is `root@pam`. */
99
+ 'notify-user'?: string;
100
+ /** Verify every new backup the moment it completes. PBS's default is false. */
101
+ 'verify-new'?: boolean;
102
+ /** Property string: `chunk-order=<none|inode>,sync-level=<none|file|filesystem>`, and more. */
103
+ tuning?: string;
104
+ /**
105
+ * Takes the datastore out of service: `type=<offline|read-only|unmount>`, optional
106
+ * `message=<text>`. PBS's default key is `type`, so the bare `offline` normalises to the same
107
+ * string here and either spelling is safe.
108
+ * ⛔ NEVER DECLARE `type=delete`. PBS sets that itself while destroying a datastore's contents.
109
+ * ⚠️ A `message` CONTAINING A COMMA BREAKS THE COMPARISON, not the write: `propertyString` splits
110
+ * on commas and does not honour PBS's quoting, so the two sides never compare equal and the
111
+ * plan asks for the same update forever. Keep the message comma-free.
112
+ */
113
+ 'maintenance-mode'?: string;
114
+ /**
115
+ * ⛔ CREATE-ONLY, LIKE `path`, AND FOR A SHARPER REASON. MEASURED on the live 4.2 host:
116
+ * `datastore create --help` offers `--backend`, `datastore update --help` does NOT, and
117
+ * `backend` is absent from update's `--delete` enum. PBS will not move a datastore between
118
+ * local disk and object storage, ever.
119
+ * ★ IT IS A PROP AT ALL BECAUSE THE ESTATE HAS ONE. `r2-offsite` holds
120
+ * `type=s3,client=cloudflare-r2,bucket=homeflare-pbs`. Leaving it undeclared would still plan
121
+ * noop — undeclared is unmanaged here — but the declaration would then describe a LOCAL
122
+ * datastore, and anyone recreating from it would get exactly that: an empty directory on the
123
+ * mini's disk where the offsite copy used to be, behind a green plan the whole way.
124
+ * ⚠️ A property string. Compared canonically, so key order is never a diff.
125
+ */
126
+ backend?: string;
127
+ /** ⚠️ S3 request counters reset on this calendar event. Mutable; in update's `--delete` enum. */
128
+ 'counter-reset-schedule'?: string;
129
+ /**
130
+ * ⚠️ S3 request-count thresholds that raise a notification, e.g. `s3-put=700000,s3-get=200000`.
131
+ * A property string, compared canonically. Mutable.
132
+ */
133
+ 'notification-thresholds'?: string;
134
+ }
135
+ export interface PbsDatastore extends Resource<'Pbs.Datastore', PbsDatastoreProps, PbsDatastoreAttributes, never, PveRequirements> {
136
+ }
137
+ /** ★ `retain` by default — a datastore holds the backups. See the ★ in resource.ts. */
138
+ export declare const PbsDatastore: import("alchemy").ResourceClass<PbsDatastore>;
139
+ export declare const PbsDatastoreProvider: () => import("effect/Layer").Layer<Provider.Provider<PbsDatastore>, never, import("effect/unstable/http/HttpClient").HttpClient>;
140
+ //# sourceMappingURL=pbs-datastore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pbs-datastore.d.ts","sourceRoot":"","sources":["../../src/proxmox/pbs-datastore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAG7C,OAAO,EACL,KAAK,sBAAsB,EAC3B,KAAK,SAAS,EAMf,MAAM,yBAAyB,CAAC;AAEjC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAErD,YAAY,EAAE,sBAAsB,EAAE,SAAS,EAAE,CAAC;AAElD;;;;;;GAMG;AACH,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,SAAS,CAAC;IAClB,6FAA6F;IAC7F,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;;;;OASG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0EAA0E;IAC1E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gGAAgG;IAChG,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,kGAAkG;IAClG,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kFAAkF;IAClF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,+EAA+E;IAC/E,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,+FAA+F;IAC/F,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;;;OAQG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iGAAiG;IACjG,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC;;;OAGG;IACH,yBAAyB,CAAC,EAAE,MAAM,CAAC;CACpC;AAED,MAAM,WAAW,YAAa,SAAQ,QAAQ,CAC5C,eAAe,EACf,iBAAiB,EACjB,sBAAsB,EACtB,KAAK,EACL,eAAe,CAChB;CAAG;AAEJ,uFAAuF;AACvF,eAAO,MAAM,YAAY,+CAEvB,CAAC;AAEH,eAAO,MAAM,oBAAoB,kIA4G9B,CAAC"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * A prune job's wire half — and, deliberately, EVERY LINE THAT CAN DELETE A BACKUP.
3
+ *
4
+ * ★ SPLIT OUT OF pbs-prune-job.ts ON THE SEAM replication-job-form.ts USES: that file answers
5
+ * "what is a prune job and when has it changed", this one answers "how does a declaration become
6
+ * a PBS write". The one deliberate departure from that seam is `keepsMatch`, which is diff logic
7
+ * and lives here anyway — see the ★ below, which is the reason the cut falls where it does.
8
+ *
9
+ * ★ THE SIX RETENTION WINDOWS ARE TOUCHED IN THREE PLACES AND ALL THREE ARE IN THIS FILE: sent by
10
+ * `keepForm`, read back by `keepAttributes`, compared by `keepsMatch`. The three must stay in
11
+ * step — a window written but not compared is a diff that never settles, and one compared but not
12
+ * written is an update reported on every plan forever — and this is the half of the resource
13
+ * where being wrong costs backups rather than a confusing plan. Keeping all three on one screen
14
+ * is what makes that review possible in one sitting instead of a grep across two files.
15
+ *
16
+ * ⚠️ THE `import type` BACK TO pbs-prune-job.ts IS A CYCLE ON PAPER ONLY. It is type-only, erased
17
+ * before anything runs, so `PruneJobProps` stays the resource's public shape in the file that
18
+ * declares the resource rather than being moved somewhere odd to dodge the arrow.
19
+ *
20
+ * ⚠️ FORM ENCODING IS THE ONE TRANSPORT ASSUMPTION THIS FAMILY RESTS ON, AND IT IS REASONED RATHER
21
+ * THAN MEASURED. `pveWith` sends `application/x-www-form-urlencoded`; PBS's REST server accepts
22
+ * that alongside JSON and parses each value through the parameter schema, which is how its own
23
+ * ExtJS GUI talks to it. I could not prove it: there is no credential for this host (see the ⛔ in
24
+ * pbs-prune-job.ts) and the only unauthenticated endpoint that would have distinguished a 400
25
+ * "bad parameters" from a 401 is the login form, which is not a thing to poke on a live box. If
26
+ * PBS turns out to want JSON here, every key and value below is still right and only the
27
+ * transport is wrong — VERIFY THIS FIRST, before anything else in these two files.
28
+ */
29
+ import type { PruneJobAttributes, PruneJobProps } from './pbs-prune-job.ts';
30
+ /**
31
+ * The six retention windows, in PBS's own spelling.
32
+ *
33
+ * ⚠️ ONE LIST, READ THREE TIMES — by `keepForm` on the way to the wire, by `keepsMatch` on the way
34
+ * back, and by `keepsSomething` in the guard. Two hand-kept copies of six key names is how a
35
+ * seventh window gets added to one of them and silently never sent, which for this family means
36
+ * never applied and never noticed until a restore.
37
+ */
38
+ export declare const KEEP_KEYS: readonly ['keep-last', 'keep-hourly', 'keep-daily', 'keep-weekly', 'keep-monthly', 'keep-yearly'];
39
+ export type KeepKey = (typeof KEEP_KEYS)[number];
40
+ /**
41
+ * The six windows off the wire, where `0` MEANS ABSENT.
42
+ *
43
+ * ⛔ ZERO IS A SENTINEL HERE AND CAN NEVER BE A LIVE VALUE, which is the only reason it is safe to
44
+ * use one. MEASURED from the published PBS schema: every `keep-*` carries `minimum: 1`, so PBS
45
+ * cannot store a zero and cannot be sent one — `keep-daily=0` is a 400, not a wipe. A field that
46
+ * comes back missing is a window that is not part of this job's policy, and `keepsMatch` must be
47
+ * able to tell that apart from "the declaration asked for zero", which it cannot express either.
48
+ */
49
+ export declare const keepAttributes: (live: Record<string, unknown>) => Pick<PruneJobAttributes, KeepKey>;
50
+ /**
51
+ * ⚠️ AN UNDECLARED WINDOW IS NOT COMPARED, AND THAT IS THE SAFETY MODEL RATHER THAN AN OVERSIGHT.
52
+ * A `keep-weekly` an operator set by hand on an adopted job is not drift this stack repairs —
53
+ * repairing it would mean narrowing retention nobody asked to narrow. The cost is stated rather
54
+ * than hidden: deleting a `keep-daily` line from a declaration plans as a NOOP and changes
55
+ * nothing on the server. See the ⛔ on `updateBody` for why clearing is a hand operation.
56
+ */
57
+ export declare const keepsMatch: (attributes: Pick<PruneJobAttributes, KeepKey>, props: PruneJobProps) => boolean;
58
+ /**
59
+ * ⛔ `id` IS SENT AND IS NOT OPTIONAL, for backup-job.ts's reason sharpened by this API's shape.
60
+ * MEASURED: `id` is a REQUIRED parameter of `POST /config/prune` — PBS does not generate one —
61
+ * so an omitted id is a 400 rather than a duplicate job. That is the good case; the bad one is
62
+ * the id being WRONG. `pveOperations.read` folds every failed GET into "absent", so a 403 or an
63
+ * expired lease reads as "no such job", the plan says create, and a second prune job appears
64
+ * beside the first with this declaration's retention applied to the same datastore. Two prune
65
+ * jobs on one store do not negotiate: each deletes what its own windows do not keep.
66
+ */
67
+ export declare const createBody: (props: PruneJobProps) => Record<string, string>;
68
+ /**
69
+ * ⛔ THERE IS NO `delete` LIST HERE AND `withClears()` IS DELIBERATELY NOT IMPORTED. Two
70
+ * independent reasons, either of which alone would be enough.
71
+ *
72
+ * FIRST, THE WIRE SHAPE IS NOT PVE'S. MEASURED from the published PBS schema, `PUT
73
+ * /config/prune/{id}` declares `delete` as `{"type":"array","items":{"type":"string","enum":[
74
+ * "comment","disable","ns","max-depth","keep-last","keep-hourly","keep-daily","keep-weekly",
75
+ * "keep-monthly","keep-yearly"]}}` — an ARRAY of enum members. PVE's `delete` is a comma-joined
76
+ * string, which is exactly what `withClears()` builds, and a form-encoded array is built by
77
+ * REPEATING the key. `delete=comment,disable` is therefore ONE item that is in no enum: a 400,
78
+ * not a clear.
79
+ * ⚠️ AND THE CORRECT SHAPE IS NOT EXPRESSIBLE TODAY. `pveWith` takes `Record<string, string>` and
80
+ * runs it through `new URLSearchParams`, which cannot repeat a key from a plain object. A PBS
81
+ * clear list needs a client that can, and that is a change to client.ts rather than to this
82
+ * file — so a clear list could not be shipped here even if it were wanted.
83
+ *
84
+ * SECOND, AND THIS ONE WOULD STAND ANYWAY: CLEARING A `keep-*` IS THE MOST DESTRUCTIVE THING
85
+ * THIS API CAN DO. Removing `keep-last` from a job that had it does not restore a default — PBS
86
+ * has no default retention — it NARROWS what survives the next run. So an undeclared field is
87
+ * unmanaged, and a window this stack never mentioned is one it never widens and never removes.
88
+ * Dropping a `keep-daily` line from a declaration therefore does NOTHING on purpose; clear it by
89
+ * hand, having first looked at what it is holding.
90
+ *
91
+ * ★ THE DISJOINTNESS `withClears()` EXISTS TO ENFORCE IS THEREFORE VACUOUS HERE: with no clear list
92
+ * there is no key that can be set and deleted in one call, which is the failure it guards. If a
93
+ * later change does add one it must go through `withClears()` AND teach the client to repeat the
94
+ * key — half of that is a 400, and the other half is PVE's spelling sent to a PBS host.
95
+ */
96
+ export declare const updateBody: (props: PruneJobProps) => Record<string, string>;
97
+ //# sourceMappingURL=pbs-prune-job-form.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pbs-prune-job-form.d.ts","sourceRoot":"","sources":["../../src/proxmox/pbs-prune-job-form.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAG5E;;;;;;;GAOG;AACH,eAAO,MAAM,SAAS,YACpB,WAAW,EACX,aAAa,EACb,YAAY,EACZ,aAAa,EACb,cAAc,EACd,aAAa,CACL,CAAC;AAEX,MAAM,MAAM,OAAO,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC;AAYjD;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc,SACnB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC5B,IAAI,CAAC,kBAAkB,EAAE,OAAO,CAOjC,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,eAAgB,IAAI,CAAC,kBAAkB,EAAE,OAAO,CAAC,SAAS,aAAa,YACR,CAAC;AA0EvF;;;;;;;;GAQG;AACH,eAAO,MAAM,UAAU,UAAW,aAAa,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAGtE,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,UAAU,UAAW,aAAa,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAGtE,CAAC"}
@@ -0,0 +1,168 @@
1
+ /**
2
+ * `Pbs.PruneJob` — a Proxmox Backup Server retention schedule, declared. PBS is a SIBLING of PVE,
3
+ * so this family reuses `pveHandlers` wholesale rather than growing a second factory.
4
+ *
5
+ * ⛔ THIS IS THE ONE RESOURCE IN THIS PACKAGE THAT DESTROYS DATA ON AN ORDINARY *UPDATE*. CephPool,
6
+ * ZfsPool and Storage can destroy data too — which is exactly why they default to `retain` and
7
+ * make a caller opt in with `destroy()`, and that guard covers DELETE and nothing else. Here the
8
+ * destruction rides a plain `1 to update` that no removal policy has any opinion about. A wrong
9
+ * `keep-*` does not fail: it succeeds. The PUT returns 200, and the NEXT SCHEDULED RUN — minutes
10
+ * or days later, with nobody watching — removes every snapshot that fell outside the new window.
11
+ * There is no undo, PBS does not ask, and nothing about the deploy looks unusual.
12
+ * ★ CONCRETELY, SO NOBODY HAS TO IMAGINE IT: a live job with `keep-daily 30`, a declaration
13
+ * saying `keep-daily: 7`. `matches` reports an update, the PUT lands, and twenty-three days of
14
+ * daily backups are gone at the next run. The plan showed one word. READ THE `keep-*` HALF OF
15
+ * EVERY PLAN TWICE; it is the only warning there is.
16
+ * ⚠️ THE ONE THING THAT CANNOT HAPPEN IS A SILENT ZERO. MEASURED from the published schema: every
17
+ * `keep-*` carries `minimum: 1`, so a literal `keep-daily=0` is a 400 rather than a wipe. And
18
+ * an UNDECLARED window is not sent as zero either — it is not sent at all, because undeclared
19
+ * means unmanaged here exactly as it does in storage.ts. A window this stack never named is one
20
+ * it never narrows. `0` in the attributes below therefore means ABSENT, never a real setting.
21
+ *
22
+ * ⛔ `max-depth` UNSET IS THE WIDEST SCOPE, NOT THE NARROWEST, AND IT IS THE ONE FIELD WHERE
23
+ * "UNMANAGED" IS NOT THE SAFE ANSWER. MEASURED, quoting the published schema's own description:
24
+ * "0 == no recursion, empty == automatic full recursion". So a job that names an `ns` but leaves
25
+ * `max-depth` alone prunes every namespace BENEATH that one too, with these windows. Declare it.
26
+ * `-1` in the attributes means "absent from prune.cfg", the sentinel storage.ts uses for
27
+ * `maxfiles`, because `0` here is a real and very different setting.
28
+ *
29
+ * ⛔ THE CREDENTIAL DOES NOT EXIST YET, SO NOTHING BELOW HAS EVER MADE A CALL. PBS is a different
30
+ * host and a different auth realm from PVE. MEASURED 2026-09-13: pbs.example.com:8007 answers
31
+ * HTTP 401 under STRICT TLS behind a real Let's Encrypt certificate (CN=pbs.example.com, issuer
32
+ * YR1, valid 2026-09-02 to 2026-12-01) — so there is no `-k` to reach for and `client.ts` needs
33
+ * no TLS escape hatch, exactly as on PVE. What it does need is a header it cannot build today.
34
+ * PBS's documented form is `Authorization: PBSAPIToken=TOKENID:TOKENSECRET` (measured from the
35
+ * published PBS documentation, 2026-09-13) while `authorization()` in credentials.ts builds
36
+ * `PVEAPIToken=<tokenid>=<secret>`: BOTH the scheme and the separator differ. A wrong separator
37
+ * answers 401 "authentication failure", which reads as a bad credential rather than as a
38
+ * malformed header — the same trap credentials.ts already records for PVE's colon form.
39
+ * ⛔ AND THERE IS NO MOUNT TO MINT FROM. `mint()` runs `bao read <mount>/creds/<role>`; no
40
+ * OpenBao mount vends PBS tokens — `proxmox-tb4` and `proxmox-ops` vend PVE ones. The
41
+ * `kv/infra/proxmox` shelf holds a READ-ONLY `Audit` token for PBS, and a read-only token
42
+ * cannot create a prune job. I could not confirm that shelf's contents: this machine's
43
+ * claude-code approle answers 403 on `sys/mounts` AND on `kv/metadata/infra/proxmox`
44
+ * (MEASURED). What is needed is a dynamic PBS mount vending a `provision` role with
45
+ * `Datastore.Modify` — say that, rather than reaching for the stored auditor token.
46
+ *
47
+ * ★ WHAT A `PbsTarget` NEEDS, AND WHY IT IS ALMOST `PveTarget`. Structurally `PveTarget` already
48
+ * fits a PBS host: a credential mount name and an `/api2/json` base are the whole of it, and PBS
49
+ * shares the `{"data": …}` envelope, the four-operation shape and the read-back discipline —
50
+ * which is exactly why this file declares a spec and stops. The single thing `PveTarget` cannot
51
+ * carry is WHICH AUTHORIZATION SCHEME the host at the other end speaks, so `PbsTarget` below adds
52
+ * that and nothing else rather than bending the PVE type in silence.
53
+ *
54
+ * ⚠️ WHICH VERSION THIS IS AUTHORED AGAINST, BECAUSE PRUNE JOBS MOVED. The paths and every field
55
+ * below are MEASURED from the PBS API as published at pbs.proxmox.com/docs/api-viewer, fetched
56
+ * 2026-09-13 — current PBS 4.x. Before PBS 2.2 there was no `/config/prune` at all: retention
57
+ * lived on the datastore section itself, as `keep-*` plus `prune-schedule` under
58
+ * `/config/datastore/{name}`. Against anything older every path here 404s, `pveOperations.read`
59
+ * folds that into "absent", and the plan says create forever. Check `GET /api2/json/version`
60
+ * before the first plan.
61
+ *
62
+ * ★ THE READ LANE NEEDS NOTHING EXTRA, UNLIKE THREE PVE FAMILIES — so there is no `readRole:
63
+ * 'provision'` below and there should not be one. MEASURED: `GET /config/prune/{id}` requires
64
+ * "Datastore.Audit or Datastore.Verify on job's datastore", i.e. the AUDIT privilege is enough
65
+ * for the ITEM read. That is precisely what `Proxmox.Storage` and the two SDN families could not
66
+ * say, and it is why the ⛔ on `readRole` in resource.ts does not claim a fourth family here.
67
+ * ⚠️ THE WRITE PRIVILEGES ARE NOT ONE PRIVILEGE, AND DELETE IS THE ODD ONE OUT. MEASURED: POST
68
+ * and PUT require `Datastore.Modify` on the job's datastore; DELETE requires `Datastore.Verify`.
69
+ * A credential that can create and edit a prune job cannot necessarily remove one, and the
70
+ * symptom is a destroy that 403s long after the creates worked.
71
+ *
72
+ * ⚠️ RUNTIME STATUS IS NOT HERE AND WAS NOT FORGOTTEN. `last-run-endtime` and friends come from
73
+ * `/admin/prune`, not from this endpoint: MEASURED, `GET /config/prune/{id}` returns exactly
74
+ * comment, disable, id, the six keep-*, max-depth, ns, schedule and store — no digest, no status.
75
+ * Reporting a last-run time would make a plan's output change when nothing changed, and a plan
76
+ * whose output moves on its own is one people stop reading. `/admin/prune/{id}/run` triggers a
77
+ * prune by hand and is deliberately not modelled: running one is an act, not a declaration.
78
+ */
79
+ import { Resource } from 'alchemy';
80
+ import * as Provider from 'alchemy/Provider';
81
+ import type { PbsTarget } from './credentials.ts';
82
+ import { type PveRequirements, type WithPbsTarget } from './resource.ts';
83
+ /**
84
+ * ⚠️ THE PROPS ARE PBS'S OWN KEY NAMES, HYPHENS INCLUDED, for backup-job.ts's reason: the form
85
+ * builder is then a copy rather than a translation table, and a translation table is one more
86
+ * place for a key to be renamed and silently never sent. Here a field that is never sent is a
87
+ * retention window that never applies.
88
+ */
89
+ export interface PruneJobProps extends WithPbsTarget {
90
+ /** ⛔ A PBS host, not a PVE one. See `PbsTarget` and the credential ⛔ in the header. */
91
+ target: PbsTarget;
92
+ /**
93
+ * ⛔ The primary key, REQUIRED, and PBS does not generate one. Measured: 3–32 chars matching
94
+ * `^[A-Za-z0-9_][A-Za-z0-9._\-]*$`. To adopt a job that exists, declare its existing id — any
95
+ * other id is a SECOND prune job on the same datastore, and two prune jobs do not negotiate.
96
+ */
97
+ id: string;
98
+ /** ⚠️ The datastore this prunes. Changing it re-points the job rather than adding one: the old
99
+ * store stops being pruned and the new one starts, with these windows, at the next run. */
100
+ store: string;
101
+ /**
102
+ * A systemd calendar event, e.g. `daily` or `sat 02:30`. ⛔ REQUIRED — measured, it is the one
103
+ * non-optional field of `POST /config/prune` besides `id` and `store`, and it is NOT in the PUT
104
+ * `delete` enum, so there is no way to un-schedule a job short of disabling or removing it.
105
+ * ⚠️ THIS COMPARES STRINGS, NOT MEANINGS. A calendar event has many equivalent spellings and PBS
106
+ * stores the one it was handed; declare the spelling the server echoes back.
107
+ */
108
+ schedule: string;
109
+ /** Namespace to prune, `''` or unset for the root one. ⚠️ Scope, so read it with `max-depth`. */
110
+ ns?: string;
111
+ /** ⛔ UNSET MEANS FULL RECURSION, NOT NONE — see the ⛔ in the header. 0–7. Declare it. */
112
+ 'max-depth'?: number;
113
+ /** ⚠️ Undeclared is UNMANAGED, so a job somebody disabled by hand stays disabled. That is the
114
+ * deliberate direction for a destructive job: never switch one on that nobody asked for. */
115
+ disable?: boolean;
116
+ comment?: string;
117
+ /** ⚠️ Every window below is `minimum: 1` (measured) and undeclared means unmanaged. */
118
+ 'keep-last'?: number;
119
+ 'keep-hourly'?: number;
120
+ 'keep-daily'?: number;
121
+ 'keep-weekly'?: number;
122
+ 'keep-monthly'?: number;
123
+ 'keep-yearly'?: number;
124
+ }
125
+ export interface PruneJobAttributes {
126
+ id: string;
127
+ store: string;
128
+ schedule: string;
129
+ ns: string;
130
+ /** ⚠️ `-1` is ABSENT — and absent means full recursion. `0` is the real "no recursion" setting. */
131
+ 'max-depth': number;
132
+ disable: boolean;
133
+ comment: string;
134
+ /** ⚠️ `0` is ABSENT in all six. PBS's own minimum is 1, so zero can never be a live value. */
135
+ 'keep-last': number;
136
+ 'keep-hourly': number;
137
+ 'keep-daily': number;
138
+ 'keep-weekly': number;
139
+ 'keep-monthly': number;
140
+ 'keep-yearly': number;
141
+ }
142
+ export interface PbsPruneJob extends Resource<'Pbs.PruneJob', PruneJobProps, PruneJobAttributes, never, PveRequirements> {
143
+ }
144
+ /**
145
+ * ★ NO `defaultRemovalPolicy: 'retain'`, UNLIKE Storage AND ZfsPool, AND THE REASON IS THE REVERSE
146
+ * OF THEIRS. Destroying this resource destroys a POLICY, and a policy is a line of TypeScript.
147
+ * The archives it would have trimmed are not touched by the DELETE — see the ⚠️ on the provider.
148
+ */
149
+ export declare const PbsPruneJob: import("alchemy").ResourceClass<PbsPruneJob>;
150
+ /**
151
+ * ⛔ `list` IS EMPTY like every other family here, and the stakes are the usual ones read backwards.
152
+ * `GET /config/prune` hands back every prune job on the server, the ones an operator tuned by
153
+ * hand included. Adopting those would give Alchemy the right to REWRITE their retention the first
154
+ * time a declaration disagreed — and rewriting retention is deleting backups. Adoption stays an
155
+ * explicit act: name the id you mean.
156
+ *
157
+ * ⚠️ THE DELETE IS THE SAFE DIRECTION, AND IT IS STILL NOT FREE. Removing a prune job deletes
158
+ * NOTHING: the archives that survived the last run stay exactly where they are. What goes away is
159
+ * the only thing trimming that datastore, so the failure mode is a datastore that fills up weeks
160
+ * later — an outage with no obvious cause and no backup written during it. Nothing on the server
161
+ * depends on a prune job, so PBS will not refuse this the way PVE refuses to delete a pool still
162
+ * holding guests; the plan line is the only warning anyone gets.
163
+ * ⚠️ DELETE ALSO NEEDS A DIFFERENT PRIVILEGE FROM THE WRITES — `Datastore.Verify`, not
164
+ * `Datastore.Modify`. See the ⚠️ in the header before assuming a working create means a working
165
+ * destroy.
166
+ */
167
+ export declare const PbsPruneJobProvider: () => import("effect/Layer").Layer<Provider.Provider<PbsPruneJob>, never, import("effect/unstable/http/HttpClient").HttpClient>;
168
+ //# sourceMappingURL=pbs-prune-job.d.ts.map