@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,99 @@
1
+ export interface BaoSshRoleProps {
2
+ /** Role name, as `<mount>/roles/{name}` takes it. */
3
+ name: string;
4
+ /** Secrets engine mount, no trailing slash. Defaults to `ssh`; `ssh-host` also exists. */
5
+ mount?: string;
6
+ /** Principals a certificate may carry. `['*']` is OpenBao's wildcard. */
7
+ allowedUsers: readonly string[];
8
+ /** Principal used when a sign request does not name one. */
9
+ defaultUser?: string;
10
+ /** Sign user certificates. Defaults to false — OpenBao's own default. */
11
+ allowUserCertificates?: boolean;
12
+ /** Sign host certificates. Defaults to false — OpenBao's own default. */
13
+ allowHostCertificates?: boolean;
14
+ /** Host-cert roles only: the domains a host certificate may claim. */
15
+ allowedDomains?: readonly string[];
16
+ /** Host-cert roles only: allow `host.example.com` under an allowed `example.com`. */
17
+ allowSubdomains?: boolean;
18
+ /** Host-cert roles only: allow the bare allowed domain itself. */
19
+ allowBareDomains?: boolean;
20
+ /**
21
+ * Extensions a REQUESTER may ask for — not the ones that get stamped on. `[]` means none
22
+ * may be requested, which is what all three live roles carry; `['*']` allows any.
23
+ */
24
+ allowedExtensions?: readonly string[];
25
+ /** Extensions stamped on every certificate, e.g. `{ 'permit-pty': '' }`. */
26
+ defaultExtensions?: Readonly<Record<string, string>>;
27
+ /** Critical options a requester may ask for — `force-command`, `source-address`. */
28
+ allowedCriticalOptions?: readonly string[];
29
+ /** Critical options stamped on every certificate. See the ⛔ on erasure in ssh-role.ts. */
30
+ defaultCriticalOptions?: Readonly<Record<string, string>>;
31
+ /** ⛔ Skeleton-key flag — read the ⛔ in ssh-role.ts before setting this true. */
32
+ allowEmptyPrincipals?: boolean;
33
+ /** Certificate lifetime, e.g. `4h`. ⛔ `0` is NOT "no expiry" — see ssh-role.ts. */
34
+ ttl: string;
35
+ /** Ceiling on a requested lifetime, e.g. `8h`. */
36
+ maxTtl: string;
37
+ }
38
+ /**
39
+ * Every prop resolved to the value the full-replace write will actually produce.
40
+ *
41
+ * ★ Derived rather than retyped: `Required` is the whole difference between the two, and a
42
+ * hand-copied twin is the kind of thing that silently loses a field in review.
43
+ */
44
+ export type BaoSshRoleForm = Required<BaoSshRoleProps>;
45
+ /** ⛔ NO SECRET HERE — names, flags, TTLs and a digest. The CA key is out of scope. */
46
+ export interface BaoSshRoleAttributes extends Omit<BaoSshRoleForm, 'maxTtl' | 'ttl'> {
47
+ /**
48
+ * ⚠️ SECONDS, NOT A DURATION STRING. OpenBao stores seconds and a plan should show what is
49
+ * stored; `4h` in the props and 14400 here are the same role. Rendering seconds back
50
+ * into `4h` needs a table of unit rules that mount-form.ts and auth-role-form.ts each
51
+ * already carry a private copy of — a third copy is how the three drift apart.
52
+ */
53
+ ttlSeconds: number;
54
+ maxTtlSeconds: number;
55
+ /** Always `ca` on a healthy role. Stored so an otp/dynamic role reads as a mismatch. */
56
+ keyType: string;
57
+ /** SHA-256 of the managed fields — safe to persist; see policy.ts. */
58
+ digest: string;
59
+ }
60
+ /** Mount path without a trailing slash; `ssh` when the caller did not say. */
61
+ export declare const mountOf: (mount: string | undefined) => string;
62
+ export declare const readPath: (mount: string | undefined, name: string) => string;
63
+ /**
64
+ * ⚠️ SETS, NOT SEQUENCES. OpenBao stores these as one comma-separated string and promises
65
+ * nothing about the order it hands back. Sorting and de-duplicating on BOTH sides is what
66
+ * stops every plan from reporting an update on a role nobody touched.
67
+ */
68
+ export declare const csvList: (value: unknown) => readonly string[];
69
+ /**
70
+ * ⚠️ A MAP WITH NO PROMISED ORDER. Key order also decides the digest and the argv, so it is
71
+ * normalised once here and everything else reads the sorted copy.
72
+ */
73
+ export declare const extMap: (value: unknown) => Record<string, string>;
74
+ /** ⛔ Every default here is what the WRITE produces, not what felt sensible. */
75
+ export declare const resolve: (props: BaoSshRoleProps) => BaoSshRoleForm;
76
+ export declare const attributesOf: (form: BaoSshRoleForm, live: Record<string, unknown>) => BaoSshRoleAttributes;
77
+ /**
78
+ * ⛔ EVERY MANAGED FIELD IS SENT ON EVERY WRITE, INCLUDING THE FALSE ONES. The role write is
79
+ * a full replace (see ssh-role.ts), so an omitted field is not "left alone" — it is reset.
80
+ * Sending the resolved form makes the body and the declaration the same statement. All
81
+ * strings, exactly the `k=v` pairs `bao write` sent, for `PUT <mount>/roles/<name>`.
82
+ */
83
+ export declare const writeBody: (form: BaoSshRoleForm) => Record<string, string>;
84
+ /**
85
+ * ⛔ AN UNPARSEABLE TTL IS A PLAN THAT NEVER GOES GREEN. parseDuration understands `0` and
86
+ * `<n>[smhd]` and nothing else. A prop like `4h30m` writes fine, reads back as 16200,
87
+ * fails to parse on the want side, and reports `update` forever — and a resource that is
88
+ * always dirty is one nobody reads the plan for any more.
89
+ */
90
+ export declare const badDurations: (form: BaoSshRoleForm) => readonly string[];
91
+ /**
92
+ * True when live already matches the declaration on every managed field.
93
+ * ⛔ NOTHING IS SKIPPED FOR BEING UNDEFINED. mount.ts and auth-role.ts can treat an absent
94
+ * prop as "don't care" because their writes are partial tunes; this one cannot, because
95
+ * the write resets whatever it omits. Comparing the resolved form is what keeps a
96
+ * hand-edited role from surviving forever behind a green plan.
97
+ */
98
+ export declare const matches: (attributes: BaoSshRoleAttributes, form: BaoSshRoleForm) => boolean;
99
+ //# sourceMappingURL=ssh-role-form.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ssh-role-form.d.ts","sourceRoot":"","sources":["../../src/openbao/ssh-role-form.ts"],"names":[],"mappings":"AAgBA,MAAM,WAAW,eAAe;IAC9B,qDAAqD;IACrD,IAAI,EAAE,MAAM,CAAC;IACb,0FAA0F;IAC1F,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yEAAyE;IACzE,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,4DAA4D;IAC5D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yEAAyE;IACzE,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,yEAAyE;IACzE,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,sEAAsE;IACtE,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,qFAAqF;IACrF,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,kEAAkE;IAClE,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,4EAA4E;IAC5E,iBAAiB,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACrD,oFAAoF;IACpF,sBAAsB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C,0FAA0F;IAC1F,sBAAsB,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC1D,gFAAgF;IAChF,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,mFAAmF;IACnF,GAAG,EAAE,MAAM,CAAC;IACZ,kDAAkD;IAClD,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC,eAAe,CAAC,CAAC;AAEvD,sFAAsF;AACtF,MAAM,WAAW,oBAAqB,SAAQ,IAAI,CAAC,cAAc,EAAE,QAAQ,GAAG,KAAK,CAAC;IAClF;;;;;OAKG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,wFAAwF;IACxF,OAAO,EAAE,MAAM,CAAC;IAChB,sEAAsE;IACtE,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,8EAA8E;AAC9E,eAAO,MAAM,OAAO,UAAW,MAAM,GAAG,SAAS,WAAyC,CAAC;AAE3F,eAAO,MAAM,QAAQ,UAAW,MAAM,GAAG,SAAS,QAAQ,MAAM,WAC7B,CAAC;AAMpC;;;;GAIG;AACH,eAAO,MAAM,OAAO,UAAW,OAAO,KAAG,SAAS,MAAM,EAOvD,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,MAAM,UAAW,OAAO,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAM5D,CAAC;AAEF,+EAA+E;AAC/E,eAAO,MAAM,OAAO,UAAW,eAAe,KAAG,cAiB/C,CAAC;AAEH,eAAO,MAAM,YAAY,SACjB,cAAc,QACd,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC5B,oBAqBF,CAAC;AAgBF;;;;;GAKG;AACH,eAAO,MAAM,SAAS,SAAU,cAAc,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAgBpE,CAAC;AAoBH;;;;;GAKG;AACH,eAAO,MAAM,YAAY,SAAU,cAAc,KAAG,SAAS,MAAM,EACuB,CAAC;AAE3F;;;;;;GAMG;AACH,eAAO,MAAM,OAAO,eAAgB,oBAAoB,QAAQ,cAAc,YAe9B,CAAC"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * An OpenBao SSH secrets-engine role — `<mount>/roles/{name}`, `key_type=ca`. METADATA ONLY.
3
+ *
4
+ * ⛔ THE SIGNING KEY IS OUT OF SCOPE AND MUST STAY OUT. `ssh/config/ca` holds (or generates)
5
+ * the CA private key and `ssh/sign/<role>` issues certificates. Neither is declarable
6
+ * here, for the reason policy.ts spells out: Alchemy persists attributes to its state
7
+ * store WITHOUT encrypting them, that store is the `alchemy` Postgres, and pg-backup.sh
8
+ * dumps it nightly to CT100. A CA key there would outlive the vault that guards it. This
9
+ * resource declares the SHAPE a signature must satisfy — principals, extensions, TTLs.
10
+ *
11
+ * ⛔ THE ROLE WRITE IS A FULL REPLACE, NOT A PATCH. OpenBao rebuilds the role entry from the
12
+ * request body, so any field the write omits reverts to its ZERO value. Two things follow:
13
+ * `resolve` in ssh-role-form.ts fills every optional prop with the default the write would
14
+ * produce and `matches` compares all of it (an omitted prop asserts the default, it never
15
+ * means "don't care"); and `wouldErase` below names the fields this resource does NOT
16
+ * declare, so reconcile can REFUSE instead of quietly dropping someone's key-length floor.
17
+ *
18
+ * ⛔ `allowEmptyPrincipals: true` WITH AN EMPTY `allowedUsers` IS A SKELETON KEY. OpenBao
19
+ * will sign a certificate carrying no principals, and OpenSSH accepts such a certificate
20
+ * for ANY user on ANY host that trusts the CA. It defaults to false, and all three roles
21
+ * on the live engine carry false (MEASURED). Do not set it true without pinning
22
+ * `defaultCriticalOptions['force-command']` in the same declaration.
23
+ *
24
+ * ⛔ `ttl: '0'` DOES NOT MEAN "NO EXPIRY" AND IT DOES NOT MEAN "SHORT". It means the mount's
25
+ * `default_lease_ttl`, and the live `ssh` mount leaves that at 0, which means the SYSTEM
26
+ * default — 768h. A 32-day SSH certificate is the opposite of what an SSH CA is for.
27
+ * State the duration. MEASURED: the live `node-admin` and `tim` roles are ttl 14400 /
28
+ * max_ttl 28800 (4h / 8h); `ssh-host/roles/host` is 31536000 (365d), as a host cert should.
29
+ *
30
+ * ★ `defaultRemovalPolicy: 'retain'`. Deleting this role locks every operator out of the
31
+ * estate — the memory note "operator SSH is homeflare-bot@<host>" is this CA. Opt in with
32
+ * `.pipe(RemovalPolicy.destroy())`; see resource.ts in house/proxmox.
33
+ */
34
+ import { Resource } from 'alchemy';
35
+ import * as Provider from 'alchemy/Provider';
36
+ import type * as HttpClient from 'effect/unstable/http/HttpClient';
37
+ import { type BaoSshRoleAttributes, type BaoSshRoleProps } from './ssh-role-form.ts';
38
+ export type { BaoSshRoleAttributes, BaoSshRoleProps };
39
+ export interface BaoSshRole extends Resource<'Bao.SshRole', BaoSshRoleProps, BaoSshRoleAttributes, never, HttpClient.HttpClient> {
40
+ }
41
+ export declare const BaoSshRole: import("alchemy").ResourceClass<BaoSshRole>;
42
+ export declare const BaoSshRoleProvider: () => import("effect/Layer").Layer<Provider.Provider<BaoSshRole>, never, HttpClient.HttpClient>;
43
+ //# sourceMappingURL=ssh-role.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ssh-role.d.ts","sourceRoot":"","sources":["../../src/openbao/ssh-role.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAE7C,OAAO,KAAK,KAAK,UAAU,MAAM,iCAAiC,CAAC;AAEnE,OAAO,EACL,KAAK,oBAAoB,EAEzB,KAAK,eAAe,EAQrB,MAAM,oBAAoB,CAAC;AAE5B,YAAY,EAAE,oBAAoB,EAAE,eAAe,EAAE,CAAC;AAEtD,MAAM,WAAW,UAAW,SAAQ,QAAQ,CAC1C,aAAa,EACb,eAAe,EACf,oBAAoB,EACpB,KAAK,EACL,UAAU,CAAC,UAAU,CACtB;CAAG;AAEJ,eAAO,MAAM,UAAU,6CAErB,CAAC;AAyDH,eAAO,MAAM,kBAAkB,iGAsH5B,CAAC"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * `Proxmox.Acl` — one grant: a role bound to a subject at a path. The line that makes a role real.
3
+ *
4
+ * ★ USERS, GROUPS, ROLES AND TOKENS ARE ALL INERT UNTIL AN ACL BINDS THEM. A role is a named list
5
+ * of privileges that grants nothing by itself; a user can do nothing until
6
+ * {path, user|group|token, role} exists. That is what makes those four families worth declaring,
7
+ * and why the grants that let OpenBao mint a PVE token today are only clicks somebody made once.
8
+ *
9
+ * ⛔ THE ONE FAMILY THAT DOES NOT FIT `pveOperations` AS WRITTEN, AND THE MISFIT IS MEASURED. The
10
+ * cluster's own schema — `/pve-docs/api-viewer/apidoc.js`, read unauthenticated 2026-09-13 —
11
+ * lists exactly TWO methods on `/access/acl`: GET and PUT. There is no DELETE (it answers
12
+ * "Method 'DELETE /access/acl' not implemented") and, less famously, NO POST either. So create
13
+ * and update are the SAME call, `PUT /access/acl`, and removal is that PUT with `delete=1` —
14
+ * which is why `delete` below does not use `ops.destroy`.
15
+ * ⚠️ THE REAL FIX BELONGS IN `resource.ts`: give `PveSpec` a `deleteForm` and the method to go
16
+ * with it, and this override disappears. Until then it is local and loud — do not "restore
17
+ * symmetry" by pointing `delete` at `ops.destroy`, which reports every removal as a 501 while
18
+ * the grant stays exactly where it was.
19
+ *
20
+ * ⛔ A SINGLE GRANT HAS NO URL OF ITS OWN. `GET /access/acl` answers ONE FLAT LIST for the whole
21
+ * cluster, so identity is the tuple (path, type, ugid, roleid), matched client-side in
22
+ * `attributes` below. Two resources declaring the SAME tuple are the SAME grant — Alchemy sees
23
+ * two resource ids, not one collision — and deleting either takes the access away from both,
24
+ * the same hazard as two guests declaring one vmid.
25
+ *
26
+ * ⛔ AND THAT LIST IS FILTERED BY WHO IS ASKING. The schema's own words for GET: "The returned list
27
+ * is restricted to objects where you have rights to modify permissions." A credential that can
28
+ * read the cluster but not modify permissions is answered `[]` — not a 403, not an error — so
29
+ * the mount's `read` role needs permission-modify rights on the declared path exactly as
30
+ * `provision` does. Work reported on a grant that is plainly there means that role is too narrow.
31
+ */
32
+ import { Resource } from 'alchemy';
33
+ import * as Provider from 'alchemy/Provider';
34
+ import { type PveRequirements, type WithTarget } from './resource.ts';
35
+ /** PVE's three kinds of subject. The read answers this word; the write wants its plural. */
36
+ export type AclSubjectType = 'user' | 'group' | 'token';
37
+ export interface AclProps extends WithTarget {
38
+ /**
39
+ * The PVE object path the grant is ON — `/`, `/pool/house`, `/vms/101`, `/storage/local-zfs`.
40
+ * ⚠️ NOT THE API PATH: `spec.path` below is the endpoint (`access/acl`). PVE's API overloads the
41
+ * word, so this file does too rather than renaming a field the cluster calls `path`.
42
+ */
43
+ path: string;
44
+ /** Which kind of subject `ugid` names. Identity: changing it is a different grant. */
45
+ type: AclSubjectType;
46
+ /** `tim@pve`, `admins`, `hf-provision@pve!hf-provision-…`. Identity. */
47
+ ugid: string;
48
+ /** The role bound here, e.g. `PVEAuditor`. ⚠️ It must exist — PVE refuses an unknown roleid. */
49
+ roleid: string;
50
+ /** Inherit down the path. PVE's default is ON, and this is the grant's ONLY mutable field. */
51
+ propagate?: boolean;
52
+ }
53
+ export interface AclAttributes {
54
+ path: string;
55
+ type: AclSubjectType;
56
+ ugid: string;
57
+ roleid: string;
58
+ propagate: boolean;
59
+ /**
60
+ * ⛔ PRESENCE AS AN ATTRIBUTE, AND IT IS WHAT MAKES THE FACTORY WORK HERE. `attributes` never
61
+ * returns undefined: if it did, `reconcile` would take the create branch and POST to
62
+ * `access/acl`, which PVE does not implement. Present-but-unbound sends every write down the
63
+ * PUT branch instead, the only branch PVE has. The cost: the factory's read-back guard cannot
64
+ * fire, so `reconcile` below re-checks this field itself and dies with the same honesty.
65
+ */
66
+ bound: boolean;
67
+ }
68
+ export interface ProxmoxAcl extends Resource<'Proxmox.Acl', AclProps, AclAttributes, never, PveRequirements> {
69
+ }
70
+ export declare const ProxmoxAcl: import("alchemy").ResourceClass<ProxmoxAcl>;
71
+ export declare const ProxmoxAclProvider: () => import("effect/Layer").Layer<Provider.Provider<ProxmoxAcl>, never, import("effect/unstable/http/HttpClient").HttpClient>;
72
+ //# sourceMappingURL=acl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"acl.d.ts","sourceRoot":"","sources":["../../src/proxmox/acl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAG7C,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,UAAU,EAAiB,MAAM,eAAe,CAAC;AAErF,4FAA4F;AAC5F,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;AAExD,MAAM,WAAW,QAAS,SAAQ,UAAU;IAC1C;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,sFAAsF;IACtF,IAAI,EAAE,cAAc,CAAC;IACrB,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;IACb,gGAAgG;IAChG,MAAM,EAAE,MAAM,CAAC;IACf,8FAA8F;IAC9F,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,cAAc,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,OAAO,CAAC;IACnB;;;;;;OAMG;IACH,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,UAAW,SAAQ,QAAQ,CAC1C,aAAa,EACb,QAAQ,EACR,aAAa,EACb,KAAK,EACL,eAAe,CAChB;CAAG;AAEJ,eAAO,MAAM,UAAU,6CAAsC,CAAC;AAmH9D,eAAO,MAAM,kBAAkB,gIAqE5B,CAAC"}
@@ -0,0 +1,59 @@
1
+ import type { ApiTokenAttributes, ApiTokenProps } from './api-token.ts';
2
+ /**
3
+ * What a write to a PVE API token actually does, and the form that does it.
4
+ *
5
+ * ★ SPLIT OUT OF api-token.ts TO KEEP BOTH FILES UNDER THE 250-LINE CAP, and the seam is the one
6
+ * metric-server-form.ts draws: this file answers "what does PVE store when this form arrives",
7
+ * api-token.ts answers "what a token is and when it has changed". Nothing here reads the
8
+ * cluster and nothing here decides a diff.
9
+ *
10
+ * ⚠️ THE `import type` BACK TO api-token.ts IS A CYCLE ON PAPER ONLY. It is type-only, so it is
11
+ * erased before anything runs and `ApiTokenProps` stays in the file that declares the resource.
12
+ *
13
+ * ⛔ THE WRITE SEMANTICS BELOW ARE READ FROM THE CLUSTER'S OWN PERL RATHER THAN INFERRED FROM THE
14
+ * API SCHEMA — `/usr/share/perl5/PVE/API2/User.pm`, subs `generate_token` and
15
+ * `update_token_info`, read over SSH on n2 on 2026-09-13. The two disagree in exactly the place
16
+ * that costs a forever-diff: the schema gives `expire` the default "same as user", and the code
17
+ * never implements it. api-token.ts records what that means.
18
+ */
19
+ import type { PveSpec } from './resource.ts';
20
+ /**
21
+ * `<userid>!<tokenid>` — the name the rest of PVE calls this object by.
22
+ *
23
+ * ★ IT IS WHAT AN ACL BINDS. `Proxmox.Acl` with `type: 'token'` wants exactly this string as its
24
+ * `ugid`, so reporting it as an attribute is what lets a privilege-separated token be granted
25
+ * anything at all without somebody retyping the join by hand.
26
+ *
27
+ * ⚠️ DERIVED, NOT READ. MEASURED: `GET /access/users/monitoring@pve/token/exporter` answers
28
+ * `{"expire":0,"privsep":0}` and echoes back neither half of its own identity. So this is built
29
+ * from props, cannot disagree with the path the read used, and is therefore true by
30
+ * construction — which is why it is reported and never compared.
31
+ */
32
+ export declare const fullTokenid: (props: ApiTokenProps) => string;
33
+ /**
34
+ * Everything a token has, in the form PVE wants. Create and update send exactly this.
35
+ *
36
+ * ⛔ `userid` AND `tokenid` ARE NOT IN IT, and that is not an omission. Both are path segments of
37
+ * `access/users/{userid}/token/{tokenid}` — which is the path the POST goes to as well as the
38
+ * PUT — so a second copy in the body can only ever disagree with the path it was sent to.
39
+ * metric-server.ts omits its `id` for the same reason and says so there.
40
+ *
41
+ * ⚠️ EVERY FIELD IS SENT ON EVERY WRITE, THE EMPTY COMMENT INCLUDED, BECAUSE A PUT MERGES.
42
+ * MEASURED in `update_token_info`: `$token->{comment} = $param->{comment} if defined(...)`
43
+ * followed by `delete $token->{comment} if (!length $token->{comment})`. So `comment=` is how a
44
+ * comment is CLEARED; omitting it leaves the old text in place while `matches` goes on asking
45
+ * for an update the update cannot make. user.ts writes the same reasoning out for `groups`.
46
+ * ⚠️ THE `delete=` PARAMETER IS NOT USED AND WOULD NOT HELP. Its whitelist in that sub is
47
+ * literally `my $deletable = { comment => 1 };`, and anything else answers
48
+ * "unknown option '<k>'" — so `expire` and `privsep` have no clear path at all, which is the
49
+ * other half of why both are required props rather than optional ones.
50
+ *
51
+ * ⚠️ `flag()` FROM values.ts IS DELIBERATELY NOT USED FOR `privsep`. Its entire job is turning an
52
+ * UNDECLARED boolean into `undefined` so the field is omitted from the form; `privsep` is a
53
+ * required prop precisely so that it is never undeclared, so there is nothing for it to do and
54
+ * its `string | undefined` return would have to be asserted away to fit `Record<string,string>`.
55
+ * An assertion here would be a claim about the prop that the type already makes properly.
56
+ */
57
+ export declare const shape: (props: ApiTokenProps) => Record<string, string>;
58
+ export declare const apiTokenSpec: PveSpec<ApiTokenProps, ApiTokenAttributes>;
59
+ //# sourceMappingURL=api-token-form.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-token-form.d.ts","sourceRoot":"","sources":["../../src/proxmox/api-token-form.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACxE;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAG7C;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,WAAW,UAAW,aAAa,WAAuC,CAAC;AAExF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,KAAK,UAAW,aAAa,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAIhE,CAAC;AAEH,eAAO,MAAM,YAAY,EAAE,OAAO,CAAC,aAAa,EAAE,kBAAkB,CAwDnE,CAAC"}
@@ -0,0 +1,159 @@
1
+ /**
2
+ * `Proxmox.ApiToken` — a PVE API token: the thing a service actually authenticates as.
3
+ *
4
+ * ⛔ THE SECRET EXISTS FOR ONE HTTP RESPONSE AND THEN NOWHERE. MEASURED from the cluster's own
5
+ * schema (`/usr/share/pve-docs/api-viewer/apidoc.js` on n2, 2026-09-13): POST returns
6
+ * `["full-tokenid","info","value"]`; PUT returns `["comment","expire","full-tokenid","privsep",
7
+ * "value"]` with `value` present ONLY when `regenerate` was set; GET returns
8
+ * `["comment","expire","privsep"]` and never the secret. A live token agrees —
9
+ * `GET /access/users/monitoring@pve/token/exporter` answers `{"expire":0,"privsep":0}`. PVE says
10
+ * it plainly on the POST: the value "needs to be stored as it cannot be retrieved afterwards".
11
+ *
12
+ * ⛔ SO A TOKEN THIS RESOURCE CREATES IS UNUSABLE, AND SAYING SO IS THE POINT OF THIS BLOCK. The
13
+ * secret may not become an attribute: Alchemy persists attributes UNENCRYPTED, and this estate's
14
+ * state store is a Postgres dumped nightly (the ⛔ in credentials.ts). So `reconcile` drops the
15
+ * value on the floor, and what lands is a live credential in `/etc/pve/user.cfg` whose secret
16
+ * nobody holds. No `regenerate` rescues it, because a regenerated value is discarded the same
17
+ * way. The only escape is an operator who captured the value out of band — which this provider
18
+ * gives them no way to do.
19
+ * ★ SO POINT THIS FAMILY AT TOKENS THAT ALREADY EXIST. `comment`, `expire` and `privsep` are the
20
+ * whole of a token's policy, and declaring them is real work: it is how `expire` stops being
21
+ * whatever somebody typed in 2024. Mint NEW tokens where the secret can be caught — OpenBao's
22
+ * `proxmox-tb4` mount, or a human at `pveum user token add`.
23
+ * ⚠️ THE CREATE PATH IS LEFT REACHABLE RATHER THAN STUBBED. A create that silently did nothing
24
+ * would be the same lie as the stubbed delete resource.ts's ★ refuses; the honest arrangement
25
+ * is a create that works and a header that says what it produces.
26
+ *
27
+ * ⛔ THERE IS NO `regenerate` PROP, AND IT IS NOT AN OVERSIGHT. PVE's own description: "All users
28
+ * of the previous secret will lose access after this operation." A prop for it would revoke a
29
+ * live credential during a deploy whose plan said `update`, and hand back a replacement this
30
+ * provider is obliged to throw away — breakage with no recovery. Rotation belongs to the mount
31
+ * that owns the lease, or to a human who is watching.
32
+ *
33
+ * ⚠️ THERE IS A SECOND WRITER TO THESE OBJECTS AND IT IS THE ONE THIS PROVIDER RUNS ON. OpenBao's
34
+ * `proxmox-tb4` engine mints PVE tokens under `hf-read@pve` and `hf-provision@pve` — read from
35
+ * `house/platform/secrets/vault/plugin-proxmox/proxmox/`: `privsep=0` (client.go), `expire` set
36
+ * to the lease deadline, and an id the plugin CHOOSES,
37
+ * `hf-<role>-<actor>-<entity6>-<stamp>-<nonce>` (tokenname.go). Revocation and WAL rollback look
38
+ * up that one exact id (wal.go); neither sweeps a prefix. So the two systems cannot collide on
39
+ * one object by accident — but they share the USER: `hf-read@pve` held three live leases when
40
+ * this was written, and `Proxmox.User` deleting that account takes every one of them with it.
41
+ * ⛔ DO NOT DECLARE A TOKEN UNDER A MINT USER. `expire` is what makes that dangerous rather than
42
+ * untidy: point this resource at a lease token with the wrong expire and a 300-second
43
+ * credential becomes a permanent one — and on `hf-provision@pve` that credential carries
44
+ * `Permissions.Modify` at `/`. docs/privileges.md records what those 27 privileges buy.
45
+ *
46
+ * ⚠️ PRIVILEGES, AND THE READ LANE CANNOT DO IT. MEASURED: all four methods on this path check
47
+ * `['or', ['userid-param','self'], ['userid-group', ['User.Modify']]]` — with no `Sys.Audit`
48
+ * alternative, unlike `GET /access/users/{userid}`, which has one. And
49
+ * `pvesh get /access/permissions --userid hf-read@pve --path /access/groups` answers the seven
50
+ * PVEAuditor audit privileges and no `User.Modify`, while `hf-provision@pve` has it. So the
51
+ * 3600s read lease reaches at most its OWN account's tokens and is refused for every other
52
+ * userid — which `read` in resource.ts folds into "absent", so the plan says create and the POST
53
+ * then fails with "Token already exists". Hence `readRole: 'provision'` below, for the same
54
+ * reason storage.ts, sdn-zone.ts and sdn-vnet.ts set it, at the same cost: every plan mints a
55
+ * 300s non-renewable provision lease just to read.
56
+ */
57
+ import { Resource } from 'alchemy';
58
+ import * as Provider from 'alchemy/Provider';
59
+ import { type PveRequirements, type WithTarget } from './resource.ts';
60
+ export interface ApiTokenProps extends WithTarget {
61
+ /**
62
+ * The account that owns the token, realm-qualified: `tofu@pve`, `root@pam`. Identity.
63
+ *
64
+ * ⚠️ THE ACCOUNT MUST ALREADY EXIST. Every method here runs `check_user_exist` first, so a
65
+ * token named under a missing user fails the READ (folded to "absent") and then fails the
66
+ * create with "no such user" — the honest error, arriving one step after the misleading plan.
67
+ * Sequence a `Proxmox.User` ahead of it and the ordering takes care of itself.
68
+ */
69
+ userid: string;
70
+ /**
71
+ * The token's own name, unique within the account. Identity.
72
+ *
73
+ * ⚠️ PVE HAS NO RENAME, AND HERE THAT COSTS MORE THAN IT DOES FOR A USER. Editing this prop (or
74
+ * `userid`) points `path` at a DIFFERENT token, which reads as absent and is then created —
75
+ * leaving the old token LIVE, with its secret still working, invisible to the plan, while the
76
+ * new one is the unusable kind described at the top. Rename by declaring a delete and a
77
+ * create, the way user.ts says for an account.
78
+ * ⛔ `diff` IS NOT OVERRIDDEN TO SAY `replace` THE WAY acl.ts DOES, AND THE DIFFERENCE IS THE
79
+ * OBJECT. There, replace removes a grant that can be rebuilt from its own tuple; here it
80
+ * would DELETE a live token — destroying an irrecoverable secret, and everything using it —
81
+ * to tidy up a name. Leaving the old token standing is the lesser harm, and saying so here
82
+ * is what keeps it from looking like an omission.
83
+ * ⚠️ PATTERN `[A-Za-z][A-Za-z0-9.\-_]+`: a letter first, two characters minimum. The schema
84
+ * declares no maxLength; the OpenBao plugin assumes a conservative 64 rather than finding the
85
+ * real limit in production, and so should anything else.
86
+ */
87
+ tokenid: string;
88
+ /**
89
+ * Free text in `pveum user token list` and the UI. Empty is how it is cleared — see `shape`.
90
+ * ⚠️ ANY CHARACTER IS SAFE HERE, MEASURED, and it was worth checking: `user.cfg` is a
91
+ * colon-delimited line, so a comment holding a colon or a newline is the obvious place for a
92
+ * round-trip to lose a character and diff forever. PVE escapes it — `encode_text` turns
93
+ * `a:b\nc%d` into `a%3Ab%0Ac%25d` and `decode_text` gives it back byte for byte.
94
+ */
95
+ comment?: string;
96
+ /**
97
+ * Seconds since the epoch, or 0 for "never expires".
98
+ *
99
+ * ⛔ REQUIRED, AND THE SCHEMA WILL TELL YOU IT NEED NOT BE. It declares the default "same as
100
+ * user", and the code never implements it: `generate_token` writes `expire` only when the
101
+ * parameter is defined, `user.cfg` stores a token as `token:<id>:<expire>:<privsep>:<comment>:`
102
+ * with no absent state, and the parser does `$expire = 0 if !$expire` (AccessControl.pm:1624).
103
+ * MEASURED end to end: every token on this cluster that was created without an expire reads
104
+ * back `"expire":0`. So "same as user" is documentation of an intention, not behaviour.
105
+ * ⛔ WHICH IS WHY IT IS NOT OPTIONAL-DEFAULTING-TO-0. That spelling reads identically and is far
106
+ * worse: an omitted `expire` would then quietly WRITE 0 over a live deadline, turning an
107
+ * expiring credential into a permanent one, and the plan would call it an update. Requiring
108
+ * the field makes "this token never expires" a sentence somebody had to type.
109
+ */
110
+ expire: number;
111
+ /**
112
+ * True keeps the token's privileges separate from its owner's — it gets NOTHING until an ACL
113
+ * names `fullTokenid`. False gives it the owner's privileges entire.
114
+ *
115
+ * ⛔ REQUIRED FOR THE SAME REASON AS `expire`, AND THE BLAST RADIUS IS LARGER. PVE's API default
116
+ * is 1, every token on this cluster is 0 (measured), and `user.cfg` materialises it either way
117
+ * — `$privsep = $privsep ? 1 : 0` (AccessControl.pm:1622), so there is no unset state to
118
+ * preserve. Were this optional, adopting a live token without mentioning `privsep` would plan
119
+ * an update to 1 and STRIP a working credential of every privilege it has, silently: PVE
120
+ * returns 401/403 to the service, nothing errors here, and `tofu@pve!apply` simply stops
121
+ * working. Required, so adopting a token is a sentence that states what it is.
122
+ * ⚠️ AND `false` IS NOT A SHRUG. It is a token with its owner's whole privilege set; under a
123
+ * provisioning account that is the account's full authority with a separate secret.
124
+ */
125
+ privsep: boolean;
126
+ }
127
+ export interface ApiTokenAttributes {
128
+ userid: string;
129
+ tokenid: string;
130
+ /** `<userid>!<tokenid>` — what `Proxmox.Acl` binds as its `ugid`. Derived; never compared. */
131
+ fullTokenid: string;
132
+ comment: string;
133
+ expire: number;
134
+ privsep: boolean;
135
+ }
136
+ export interface ProxmoxApiToken extends Resource<'Proxmox.ApiToken', ApiTokenProps, ApiTokenAttributes, never, PveRequirements> {
137
+ }
138
+ /**
139
+ * ★ `retain` BY DEFAULT, AND THIS IS THE PLAINEST CASE FOR IT IN THE PACKAGE. A token's contents
140
+ * are one irreplaceable secret: delete it and the value is gone, a replacement is a DIFFERENT
141
+ * value, and every holder loses access the instant `cfs_write_file` returns — with no error
142
+ * raised anywhere near them. The live cluster's tokens are `monitoring@pve!exporter` (the PVE
143
+ * exporter feeding VictoriaMetrics), `mcp@pve!executor`, `tofu@pve!apply`, `tofu@pve!ro`,
144
+ * `sablier@pve!sablier` and `vaultmint@pve!engine` — the last being the parent credential the
145
+ * OpenBao mount itself authenticates with, so orphaning that one would stop every plan in this
146
+ * package, this resource included. `delete` is FULLY IMPLEMENTED (DELETE is a real method on
147
+ * this path, measured) and runs the moment a caller opts in with `.pipe(RemovalPolicy.destroy())`.
148
+ * See the ★ in resource.ts, which explains the convention once.
149
+ */
150
+ export declare const ProxmoxApiToken: import("alchemy").ResourceClass<ProxmoxApiToken>;
151
+ /**
152
+ * ⛔ `list` IS EMPTY, AND FOR THIS FAMILY THAT MATTERS MORE THAN THE GENERIC ARGUMENT IN
153
+ * resource.ts. A token index handed to Alchemy would offer up `vaultmint@pve!engine` and every
154
+ * live OpenBao lease for adoption — and adoption is what makes a later plan willing to delete.
155
+ * The mount's leases in particular appear and vanish on their own; anything that adopted one
156
+ * would report drift against a credential that was never its to hold.
157
+ */
158
+ export declare const ProxmoxApiTokenProvider: () => import("effect/Layer").Layer<Provider.Provider<ProxmoxApiToken>, never, import("effect/unstable/http/HttpClient").HttpClient>;
159
+ //# sourceMappingURL=api-token.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-token.d.ts","sourceRoot":"","sources":["../../src/proxmox/api-token.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAG7C,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,UAAU,EAA8B,MAAM,eAAe,CAAC;AAElG,MAAM,WAAW,aAAc,SAAQ,UAAU;IAC/C;;;;;;;OAOG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;;;;;;;;;;;;;;;OAgBG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;;;;;;;;OAaG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;;;;;;;;;;;;OAaG;IACH,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,8FAA8F;IAC9F,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAOlB;AAED,MAAM,WAAW,eAAgB,SAAQ,QAAQ,CAC/C,kBAAkB,EAClB,aAAa,EACb,kBAAkB,EAClB,KAAK,EACL,eAAe,CAChB;CAAG;AAEJ;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,eAAe,kDAE1B,CAAC;AA6CH;;;;;;GAMG;AACH,eAAO,MAAM,uBAAuB,qIACqD,CAAC"}
@@ -0,0 +1,112 @@
1
+ /**
2
+ * `Proxmox.BackupJob` — the vzdump schedule, declared. The one object whose drift nothing else on
3
+ * the cluster reveals.
4
+ *
5
+ * ★ WHY THIS ONE EARNS ITS PLACE. A hand-made vzdump job drifts silently: a schedule moved by an
6
+ * hour, a retention trimmed to `keep-last=1`, or `enabled 0` set during a maintenance window and
7
+ * never set back. All three look like a healthy cluster from every angle except a restore.
8
+ * Declared here, `diff` reads the LIVE job on every plan, so a hand edit surfaces as
9
+ * `1 to update` that day rather than on the day somebody needs last night's backup and finds a
10
+ * week-old one, or none.
11
+ *
12
+ * ⛔ PVE GENERATES `id` WHEN YOU OMIT IT, WHICH MAKES OMITTING IT THE WORST BUG THIS RESOURCE
13
+ * COULD CARRY. PVE's own API schema says so in one parenthesis — `id`: "Job ID (will be
14
+ * autogenerated)." — and a generated id looks like `backup-f56d8ab7-d524`. A resource that
15
+ * POSTed without an id would create a SECOND job beside the first on EVERY reconcile, and the
16
+ * read-back in `pveOperations` would still pass, because a job did appear: that check asks "is
17
+ * the object there", not "is it the one I meant". So `id` is a REQUIRED prop and is always sent
18
+ * on create. To adopt a job that already exists, declare its existing id; any other id is a new
19
+ * job beside it, not an adoption.
20
+ * ★ AN EXPLICIT id ALSO CLOSES A SECOND HOLE. `pveOperations.read` turns ANY failed GET into
21
+ * "absent" — an expired lease, a 403, a node that did not answer — and reconcile then POSTs.
22
+ * With an id, PVE refuses a duplicate section id and the deploy fails loudly; without one, that
23
+ * same swallowed error would have quietly doubled the cluster's backup jobs.
24
+ *
25
+ * ⚠️ `Sys.Modify` ON `/` IS THE GATE AND IT IS NOT A SMALL GRANT. PVE has no Backup.* privilege:
26
+ * create, update and delete of a vzdump job are all checked against `Sys.Modify` at `/` — the
27
+ * same privilege that covers node network configuration. A credential that can declare backup
28
+ * jobs can also rewrite the cluster's networking. That is PVE's granularity rather than a choice
29
+ * made here, and it is exactly why widening a role for this should be a decision rather than a
30
+ * reaction to a 403.
31
+ */
32
+ import { Resource } from 'alchemy';
33
+ import * as Provider from 'alchemy/Provider';
34
+ import { type PveRequirements, type WithTarget } from './resource.ts';
35
+ /**
36
+ * ⚠️ THE PROPS ARE PVE'S OWN KEY NAMES, DASHES INCLUDED. `notes-template` rather than
37
+ * `notesTemplate` is deliberate: `createForm` is then a copy rather than a translation table,
38
+ * and a translation table is one more place for a key to be renamed and silently never sent. A
39
+ * field that is never sent reads back as whatever it already was, which is indistinguishable
40
+ * from "PVE ignored me".
41
+ */
42
+ export interface BackupJobProps extends WithTarget {
43
+ /** ⛔ The primary key, REQUIRED. Never let PVE generate it — see the ⛔ above. */
44
+ id: string;
45
+ /** A subset of systemd calendar events, e.g. `01:00` or `mon..fri 02:30`. */
46
+ schedule: string;
47
+ /** Target storage id. That storage's own retention applies unless `prune-backups` overrides it. */
48
+ storage?: string;
49
+ mode?: 'snapshot' | 'suspend' | 'stop';
50
+ /** PVE's default is enabled. A disabled job is a backup that silently is not happening. */
51
+ enabled?: boolean;
52
+ /** Back up every guest. ⚠️ Pick exactly one of `all`, `vmid` and `pool` — see `shape` below. */
53
+ all?: boolean;
54
+ vmid?: readonly number[];
55
+ pool?: string;
56
+ /** Guest ids to skip. PVE reads this as "all guests except these", so it belongs with `all`. */
57
+ exclude?: readonly number[];
58
+ /** Retention, as a property string: `keep-daily=7,keep-weekly=4`. */
59
+ 'prune-backups'?: string;
60
+ /** Supports {{cluster}}, {{guestname}}, {{node}} and {{vmid}}. Single line only. */
61
+ 'notes-template'?: string;
62
+ 'notification-mode'?: 'auto' | 'legacy-sendmail' | 'notification-system';
63
+ /** Run a missed job as soon as the scheduler is back. */
64
+ 'repeat-missed'?: boolean;
65
+ /** VM-only fleecing, as a property string: `enabled=1,storage=<id>`. See `propertyString`. */
66
+ fleecing?: string;
67
+ comment?: string;
68
+ }
69
+ export interface BackupJobAttributes {
70
+ id: string;
71
+ schedule: string;
72
+ storage: string;
73
+ mode: string;
74
+ enabled: boolean;
75
+ all: boolean;
76
+ /** Sorted and comma-joined, so re-ordering a declaration is not a diff. See `guestList`. */
77
+ vmid: string;
78
+ pool: string;
79
+ exclude: string;
80
+ /** Flattened and sorted — never the raw value PVE returned. See `propertyString`. */
81
+ 'prune-backups': string;
82
+ 'notes-template': string;
83
+ 'notification-mode': string;
84
+ 'repeat-missed': boolean;
85
+ fleecing: string;
86
+ comment: string;
87
+ /**
88
+ * PVE's own estimate, epoch seconds. REPORTED, NEVER COMPARED: `next-run` in `matches` would
89
+ * report an update every time the clock passed a scheduled run. It is here so a plan can show
90
+ * that a job is still due — a `next-run` of 0 is a job the scheduler will not run.
91
+ */
92
+ 'next-run': number;
93
+ }
94
+ export interface ProxmoxBackupJob extends Resource<'Proxmox.BackupJob', BackupJobProps, BackupJobAttributes, never, PveRequirements> {
95
+ }
96
+ export declare const ProxmoxBackupJob: import("alchemy").ResourceClass<ProxmoxBackupJob>;
97
+ /**
98
+ * ⛔ Empty for the same reason as every other resource here: adoption must be explicit.
99
+ * `GET /cluster/backup` would hand back the job somebody made by hand, and adopting it
100
+ * implicitly would give Alchemy the right to DELETE a cluster's only backup schedule the
101
+ * first time a line left a stack file.
102
+
103
+ *
104
+ * ⚠️ DELETING THE JOB DOES NOT DELETE THE BACKUPS, AND THAT CUTS BOTH WAYS. The archives
105
+ * stay on the storage, so this looks harmless today; it is destructive in six months,
106
+ * when the schedule that should have replaced them has not run since. PVE will not
107
+ * refuse this the way it refuses to delete a pool still holding guests — nothing depends
108
+ * on a backup job — so the plan line is the only warning anyone gets.
109
+
110
+ */
111
+ export declare const ProxmoxBackupJobProvider: () => import("effect/Layer").Layer<Provider.Provider<ProxmoxBackupJob>, never, import("effect/unstable/http/HttpClient").HttpClient>;
112
+ //# sourceMappingURL=backup-job.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backup-job.d.ts","sourceRoot":"","sources":["../../src/proxmox/backup-job.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAE7C,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,UAAU,EAAe,MAAM,eAAe,CAAC;AAGnF;;;;;;GAMG;AACH,MAAM,WAAW,cAAe,SAAQ,UAAU;IAChD,gFAAgF;IAChF,EAAE,EAAE,MAAM,CAAC;IACX,6EAA6E;IAC7E,QAAQ,EAAE,MAAM,CAAC;IACjB,mGAAmG;IACnG,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,UAAU,GAAG,SAAS,GAAG,MAAM,CAAC;IACvC,2FAA2F;IAC3F,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,gGAAgG;IAChG,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gGAAgG;IAChG,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B,qEAAqE;IACrE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,oFAAoF;IACpF,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mBAAmB,CAAC,EAAE,MAAM,GAAG,iBAAiB,GAAG,qBAAqB,CAAC;IACzE,yDAAyD;IACzD,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,8FAA8F;IAC9F,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,OAAO,CAAC;IACb,4FAA4F;IAC5F,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,qFAAqF;IACrF,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,eAAe,EAAE,OAAO,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gBAAiB,SAAQ,QAAQ,CAChD,mBAAmB,EACnB,cAAc,EACd,mBAAmB,EACnB,KAAK,EACL,eAAe,CAChB;CAAG;AAEJ,eAAO,MAAM,gBAAgB,mDAAkD,CAAC;AA2FhF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,wBAAwB,sIACsD,CAAC"}