@homeflare/alchemy 0.14.0 → 0.19.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 (567) hide show
  1. package/README.md +29 -0
  2. package/dist/linux/directory-lifecycle.d.ts +50 -0
  3. package/dist/linux/directory-lifecycle.d.ts.map +1 -0
  4. package/dist/linux/directory.d.ts +19 -0
  5. package/dist/linux/directory.d.ts.map +1 -0
  6. package/dist/linux/fake-linux-host.d.ts +35 -0
  7. package/dist/linux/fake-linux-host.d.ts.map +1 -0
  8. package/dist/linux/fake-systemd.d.ts +34 -0
  9. package/dist/linux/fake-systemd.d.ts.map +1 -0
  10. package/dist/linux/index.d.ts +27 -0
  11. package/dist/linux/index.d.ts.map +1 -0
  12. package/dist/linux/index.js +1554 -0
  13. package/dist/linux/index.js.map +37 -0
  14. package/dist/linux/providers.d.ts +17 -0
  15. package/dist/linux/providers.d.ts.map +1 -0
  16. package/dist/linux/region.d.ts +43 -0
  17. package/dist/linux/region.d.ts.map +1 -0
  18. package/dist/linux/remote-file-form.d.ts +47 -0
  19. package/dist/linux/remote-file-form.d.ts.map +1 -0
  20. package/dist/linux/remote-file-lifecycle.d.ts +36 -0
  21. package/dist/linux/remote-file-lifecycle.d.ts.map +1 -0
  22. package/dist/linux/remote-file-plan.d.ts +33 -0
  23. package/dist/linux/remote-file-plan.d.ts.map +1 -0
  24. package/dist/linux/remote-file.d.ts +28 -0
  25. package/dist/linux/remote-file.d.ts.map +1 -0
  26. package/dist/linux/ssh-command.d.ts +68 -0
  27. package/dist/linux/ssh-command.d.ts.map +1 -0
  28. package/dist/linux/ssh-runner.d.ts +22 -0
  29. package/dist/linux/ssh-runner.d.ts.map +1 -0
  30. package/dist/linux/ssh-scripts.d.ts +27 -0
  31. package/dist/linux/ssh-scripts.d.ts.map +1 -0
  32. package/dist/linux/systemctl.d.ts +67 -0
  33. package/dist/linux/systemctl.d.ts.map +1 -0
  34. package/dist/linux/unit-form.d.ts +78 -0
  35. package/dist/linux/unit-form.d.ts.map +1 -0
  36. package/dist/linux/unit-handlers.d.ts +15 -0
  37. package/dist/linux/unit-handlers.d.ts.map +1 -0
  38. package/dist/linux/unit-lifecycle.d.ts +44 -0
  39. package/dist/linux/unit-lifecycle.d.ts.map +1 -0
  40. package/dist/linux/unit-settle.d.ts +31 -0
  41. package/dist/linux/unit-settle.d.ts.map +1 -0
  42. package/dist/linux/unit.d.ts +35 -0
  43. package/dist/linux/unit.d.ts.map +1 -0
  44. package/dist/netbox/client.d.ts +52 -0
  45. package/dist/netbox/client.d.ts.map +1 -0
  46. package/dist/netbox/constraint-guard.d.ts +26 -0
  47. package/dist/netbox/constraint-guard.d.ts.map +1 -0
  48. package/dist/netbox/constraints.d.ts +76 -0
  49. package/dist/netbox/constraints.d.ts.map +1 -0
  50. package/dist/netbox/generated/constraints/index.d.ts +19 -0
  51. package/dist/netbox/generated/constraints/index.d.ts.map +1 -0
  52. package/dist/netbox/generated/constraints/netbox-ipam.d.ts +21 -0
  53. package/dist/netbox/generated/constraints/netbox-ipam.d.ts.map +1 -0
  54. package/dist/netbox/index.d.ts +17 -0
  55. package/dist/netbox/index.d.ts.map +1 -0
  56. package/dist/netbox/index.js +331 -0
  57. package/dist/netbox/index.js.map +18 -0
  58. package/dist/netbox/prefix-form.d.ts +54 -0
  59. package/dist/netbox/prefix-form.d.ts.map +1 -0
  60. package/dist/netbox/prefix.d.ts +80 -0
  61. package/dist/netbox/prefix.d.ts.map +1 -0
  62. package/dist/netbox/resource.d.ts +94 -0
  63. package/dist/netbox/resource.d.ts.map +1 -0
  64. package/dist/netbox/values.d.ts +24 -0
  65. package/dist/netbox/values.d.ts.map +1 -0
  66. package/dist/openbao/index.d.ts +10 -3
  67. package/dist/openbao/index.d.ts.map +1 -1
  68. package/dist/proxmox/acl.d.ts.map +1 -1
  69. package/dist/proxmox/api-token-form.d.ts.map +1 -1
  70. package/dist/proxmox/apply-endpoints.d.ts +30 -0
  71. package/dist/proxmox/apply-endpoints.d.ts.map +1 -0
  72. package/dist/proxmox/backup-job.d.ts.map +1 -1
  73. package/dist/proxmox/ceph-daemon-form.d.ts +29 -1
  74. package/dist/proxmox/ceph-daemon-form.d.ts.map +1 -1
  75. package/dist/proxmox/ceph-daemon.d.ts.map +1 -1
  76. package/dist/proxmox/ceph-flag.d.ts.map +1 -1
  77. package/dist/proxmox/ceph-fs.d.ts.map +1 -1
  78. package/dist/proxmox/ceph-osd-write.d.ts +19 -0
  79. package/dist/proxmox/ceph-osd-write.d.ts.map +1 -1
  80. package/dist/proxmox/ceph-pool.d.ts.map +1 -1
  81. package/dist/proxmox/constraint-guard.d.ts +28 -0
  82. package/dist/proxmox/constraint-guard.d.ts.map +1 -0
  83. package/dist/proxmox/constraints.d.ts +94 -0
  84. package/dist/proxmox/constraints.d.ts.map +1 -0
  85. package/dist/proxmox/firewall-alias.d.ts.map +1 -1
  86. package/dist/proxmox/generated/constraints/index.d.ts +19 -0
  87. package/dist/proxmox/generated/constraints/index.d.ts.map +1 -0
  88. package/dist/proxmox/generated/constraints/pbs-config.d.ts +23 -0
  89. package/dist/proxmox/generated/constraints/pbs-config.d.ts.map +1 -0
  90. package/dist/proxmox/generated/constraints/pve-access.d.ts +23 -0
  91. package/dist/proxmox/generated/constraints/pve-access.d.ts.map +1 -0
  92. package/dist/proxmox/generated/constraints/pve-cluster-backup.d.ts +23 -0
  93. package/dist/proxmox/generated/constraints/pve-cluster-backup.d.ts.map +1 -0
  94. package/dist/proxmox/generated/constraints/pve-cluster-ceph.d.ts +23 -0
  95. package/dist/proxmox/generated/constraints/pve-cluster-ceph.d.ts.map +1 -0
  96. package/dist/proxmox/generated/constraints/pve-cluster-firewall.d.ts +23 -0
  97. package/dist/proxmox/generated/constraints/pve-cluster-firewall.d.ts.map +1 -0
  98. package/dist/proxmox/generated/constraints/pve-cluster-ha.d.ts +23 -0
  99. package/dist/proxmox/generated/constraints/pve-cluster-ha.d.ts.map +1 -0
  100. package/dist/proxmox/generated/constraints/pve-cluster-metrics.d.ts +23 -0
  101. package/dist/proxmox/generated/constraints/pve-cluster-metrics.d.ts.map +1 -0
  102. package/dist/proxmox/generated/constraints/pve-cluster-notifications.d.ts +23 -0
  103. package/dist/proxmox/generated/constraints/pve-cluster-notifications.d.ts.map +1 -0
  104. package/dist/proxmox/generated/constraints/pve-cluster-replication.d.ts +23 -0
  105. package/dist/proxmox/generated/constraints/pve-cluster-replication.d.ts.map +1 -0
  106. package/dist/proxmox/generated/constraints/pve-cluster-sdn.d.ts +23 -0
  107. package/dist/proxmox/generated/constraints/pve-cluster-sdn.d.ts.map +1 -0
  108. package/dist/proxmox/generated/constraints/pve-nodes-ceph.d.ts +23 -0
  109. package/dist/proxmox/generated/constraints/pve-nodes-ceph.d.ts.map +1 -0
  110. package/dist/proxmox/generated/constraints/pve-nodes-disks.d.ts +23 -0
  111. package/dist/proxmox/generated/constraints/pve-nodes-disks.d.ts.map +1 -0
  112. package/dist/proxmox/generated/constraints/pve-nodes-lxc.d.ts +23 -0
  113. package/dist/proxmox/generated/constraints/pve-nodes-lxc.d.ts.map +1 -0
  114. package/dist/proxmox/generated/constraints/pve-nodes-network.d.ts +23 -0
  115. package/dist/proxmox/generated/constraints/pve-nodes-network.d.ts.map +1 -0
  116. package/dist/proxmox/generated/constraints/pve-nodes-qemu.d.ts +23 -0
  117. package/dist/proxmox/generated/constraints/pve-nodes-qemu.d.ts.map +1 -0
  118. package/dist/proxmox/generated/constraints/pve-pools.d.ts +23 -0
  119. package/dist/proxmox/generated/constraints/pve-pools.d.ts.map +1 -0
  120. package/dist/proxmox/generated/constraints/pve-storage.d.ts +23 -0
  121. package/dist/proxmox/generated/constraints/pve-storage.d.ts.map +1 -0
  122. package/dist/proxmox/generated/pbs/access-users.d.ts +137 -0
  123. package/dist/proxmox/generated/pbs/access-users.d.ts.map +1 -0
  124. package/dist/proxmox/generated/pbs/access.d.ts +171 -0
  125. package/dist/proxmox/generated/pbs/access.d.ts.map +1 -0
  126. package/dist/proxmox/generated/pbs/admin-datastore-store.d.ts +252 -0
  127. package/dist/proxmox/generated/pbs/admin-datastore-store.d.ts.map +1 -0
  128. package/dist/proxmox/generated/pbs/admin-metrics.d.ts +147 -0
  129. package/dist/proxmox/generated/pbs/admin-metrics.d.ts.map +1 -0
  130. package/dist/proxmox/generated/pbs/admin.d.ts +217 -0
  131. package/dist/proxmox/generated/pbs/admin.d.ts.map +1 -0
  132. package/dist/proxmox/generated/pbs/backup.d.ts +114 -0
  133. package/dist/proxmox/generated/pbs/backup.d.ts.map +1 -0
  134. package/dist/proxmox/generated/pbs/config-access-pam.d.ts +218 -0
  135. package/dist/proxmox/generated/pbs/config-access-pam.d.ts.map +1 -0
  136. package/dist/proxmox/generated/pbs/config-access.d.ts +203 -0
  137. package/dist/proxmox/generated/pbs/config-access.d.ts.map +1 -0
  138. package/dist/proxmox/generated/pbs/config-datastore.d.ts +195 -0
  139. package/dist/proxmox/generated/pbs/config-datastore.d.ts.map +1 -0
  140. package/dist/proxmox/generated/pbs/config-media-pool.d.ts +207 -0
  141. package/dist/proxmox/generated/pbs/config-media-pool.d.ts.map +1 -0
  142. package/dist/proxmox/generated/pbs/config-notifications-matchers.d.ts +159 -0
  143. package/dist/proxmox/generated/pbs/config-notifications-matchers.d.ts.map +1 -0
  144. package/dist/proxmox/generated/pbs/config-notifications.d.ts +199 -0
  145. package/dist/proxmox/generated/pbs/config-notifications.d.ts.map +1 -0
  146. package/dist/proxmox/generated/pbs/config-remote.d.ts +175 -0
  147. package/dist/proxmox/generated/pbs/config-remote.d.ts.map +1 -0
  148. package/dist/proxmox/generated/pbs/config-sync.d.ts +145 -0
  149. package/dist/proxmox/generated/pbs/config-sync.d.ts.map +1 -0
  150. package/dist/proxmox/generated/pbs/config-tape.d.ts +200 -0
  151. package/dist/proxmox/generated/pbs/config-tape.d.ts.map +1 -0
  152. package/dist/proxmox/generated/pbs/config-verify.d.ts +77 -0
  153. package/dist/proxmox/generated/pbs/config-verify.d.ts.map +1 -0
  154. package/dist/proxmox/generated/pbs/config.d.ts +119 -0
  155. package/dist/proxmox/generated/pbs/config.d.ts.map +1 -0
  156. package/dist/proxmox/generated/pbs/nodes-node-dns.d.ts +178 -0
  157. package/dist/proxmox/generated/pbs/nodes-node-dns.d.ts.map +1 -0
  158. package/dist/proxmox/generated/pbs/nodes-node-services.d.ts +205 -0
  159. package/dist/proxmox/generated/pbs/nodes-node-services.d.ts.map +1 -0
  160. package/dist/proxmox/generated/pbs/nodes-node.d.ts +166 -0
  161. package/dist/proxmox/generated/pbs/nodes-node.d.ts.map +1 -0
  162. package/dist/proxmox/generated/pbs/nodes.d.ts +171 -0
  163. package/dist/proxmox/generated/pbs/nodes.d.ts.map +1 -0
  164. package/dist/proxmox/generated/pbs/ping.d.ts +18 -0
  165. package/dist/proxmox/generated/pbs/ping.d.ts.map +1 -0
  166. package/dist/proxmox/generated/pbs/pull.d.ts +37 -0
  167. package/dist/proxmox/generated/pbs/pull.d.ts.map +1 -0
  168. package/dist/proxmox/generated/pbs/push.d.ts +36 -0
  169. package/dist/proxmox/generated/pbs/push.d.ts.map +1 -0
  170. package/dist/proxmox/generated/pbs/reader.d.ts +41 -0
  171. package/dist/proxmox/generated/pbs/reader.d.ts.map +1 -0
  172. package/dist/proxmox/generated/pbs/root.d.ts +16 -0
  173. package/dist/proxmox/generated/pbs/root.d.ts.map +1 -0
  174. package/dist/proxmox/generated/pbs/status.d.ts +54 -0
  175. package/dist/proxmox/generated/pbs/status.d.ts.map +1 -0
  176. package/dist/proxmox/generated/pbs/tape-drive.d.ts +181 -0
  177. package/dist/proxmox/generated/pbs/tape-drive.d.ts.map +1 -0
  178. package/dist/proxmox/generated/pbs/tape-media.d.ts +126 -0
  179. package/dist/proxmox/generated/pbs/tape-media.d.ts.map +1 -0
  180. package/dist/proxmox/generated/pbs/tape.d.ts +90 -0
  181. package/dist/proxmox/generated/pbs/tape.d.ts.map +1 -0
  182. package/dist/proxmox/generated/pbs/version.d.ts +20 -0
  183. package/dist/proxmox/generated/pbs/version.d.ts.map +1 -0
  184. package/dist/proxmox/generated/pbs.d.ts +44 -662
  185. package/dist/proxmox/generated/pbs.d.ts.map +1 -1
  186. package/dist/proxmox/generated/pve/access-roles.d.ts +164 -0
  187. package/dist/proxmox/generated/pve/access-roles.d.ts.map +1 -0
  188. package/dist/proxmox/generated/pve/access-users.d.ts +152 -0
  189. package/dist/proxmox/generated/pve/access-users.d.ts.map +1 -0
  190. package/dist/proxmox/generated/pve/access.d.ts +221 -0
  191. package/dist/proxmox/generated/pve/access.d.ts.map +1 -0
  192. package/dist/proxmox/generated/pve/cluster-acme-plugins-id.d.ts +45 -0
  193. package/dist/proxmox/generated/pve/cluster-acme-plugins-id.d.ts.map +1 -0
  194. package/dist/proxmox/generated/pve/cluster-acme-plugins.d.ts +47 -0
  195. package/dist/proxmox/generated/pve/cluster-acme-plugins.d.ts.map +1 -0
  196. package/dist/proxmox/generated/pve/cluster-acme-tos.d.ts +240 -0
  197. package/dist/proxmox/generated/pve/cluster-acme-tos.d.ts.map +1 -0
  198. package/dist/proxmox/generated/pve/cluster-bulk-action.d.ts +200 -0
  199. package/dist/proxmox/generated/pve/cluster-bulk-action.d.ts.map +1 -0
  200. package/dist/proxmox/generated/pve/cluster-firewall-refs.d.ts +109 -0
  201. package/dist/proxmox/generated/pve/cluster-firewall-refs.d.ts.map +1 -0
  202. package/dist/proxmox/generated/pve/cluster-firewall.d.ts +225 -0
  203. package/dist/proxmox/generated/pve/cluster-firewall.d.ts.map +1 -0
  204. package/dist/proxmox/generated/pve/cluster-ha.d.ts +199 -0
  205. package/dist/proxmox/generated/pve/cluster-ha.d.ts.map +1 -0
  206. package/dist/proxmox/generated/pve/cluster-jobs.d.ts +183 -0
  207. package/dist/proxmox/generated/pve/cluster-jobs.d.ts.map +1 -0
  208. package/dist/proxmox/generated/pve/cluster-metrics.d.ts +110 -0
  209. package/dist/proxmox/generated/pve/cluster-metrics.d.ts.map +1 -0
  210. package/dist/proxmox/generated/pve/cluster-notifications-endpoints.d.ts +224 -0
  211. package/dist/proxmox/generated/pve/cluster-notifications-endpoints.d.ts.map +1 -0
  212. package/dist/proxmox/generated/pve/cluster-notifications.d.ts +91 -0
  213. package/dist/proxmox/generated/pve/cluster-notifications.d.ts.map +1 -0
  214. package/dist/proxmox/generated/pve/cluster-options.d.ts +85 -0
  215. package/dist/proxmox/generated/pve/cluster-options.d.ts.map +1 -0
  216. package/dist/proxmox/generated/pve/cluster-qemu-custom-cpu-models-cputype.d.ts +48 -0
  217. package/dist/proxmox/generated/pve/cluster-qemu-custom-cpu-models-cputype.d.ts.map +1 -0
  218. package/dist/proxmox/generated/pve/cluster-qemu-custom-cpu-models.d.ts +45 -0
  219. package/dist/proxmox/generated/pve/cluster-qemu-custom-cpu-models.d.ts.map +1 -0
  220. package/dist/proxmox/generated/pve/cluster-replication.d.ts +130 -0
  221. package/dist/proxmox/generated/pve/cluster-replication.d.ts.map +1 -0
  222. package/dist/proxmox/generated/pve/cluster-sdn-fabrics.d.ts +220 -0
  223. package/dist/proxmox/generated/pve/cluster-sdn-fabrics.d.ts.map +1 -0
  224. package/dist/proxmox/generated/pve/cluster-sdn-ipams.d.ts +229 -0
  225. package/dist/proxmox/generated/pve/cluster-sdn-ipams.d.ts.map +1 -0
  226. package/dist/proxmox/generated/pve/cluster-sdn-vnets-vnet.d.ts +229 -0
  227. package/dist/proxmox/generated/pve/cluster-sdn-vnets-vnet.d.ts.map +1 -0
  228. package/dist/proxmox/generated/pve/cluster-sdn-vnets.d.ts +51 -0
  229. package/dist/proxmox/generated/pve/cluster-sdn-vnets.d.ts.map +1 -0
  230. package/dist/proxmox/generated/pve/cluster-sdn-zones.d.ts +225 -0
  231. package/dist/proxmox/generated/pve/cluster-sdn-zones.d.ts.map +1 -0
  232. package/dist/proxmox/generated/pve/cluster-sdn.d.ts +202 -0
  233. package/dist/proxmox/generated/pve/cluster-sdn.d.ts.map +1 -0
  234. package/dist/proxmox/generated/pve/cluster.d.ts +69 -0
  235. package/dist/proxmox/generated/pve/cluster.d.ts.map +1 -0
  236. package/dist/proxmox/generated/pve/nodes-node-ceph.d.ts +167 -0
  237. package/dist/proxmox/generated/pve/nodes-node-ceph.d.ts.map +1 -0
  238. package/dist/proxmox/generated/pve/nodes-node-config.d.ts +43 -0
  239. package/dist/proxmox/generated/pve/nodes-node-config.d.ts.map +1 -0
  240. package/dist/proxmox/generated/pve/nodes-node-disks.d.ts +225 -0
  241. package/dist/proxmox/generated/pve/nodes-node-disks.d.ts.map +1 -0
  242. package/dist/proxmox/generated/pve/nodes-node-firewall.d.ts +145 -0
  243. package/dist/proxmox/generated/pve/nodes-node-firewall.d.ts.map +1 -0
  244. package/dist/proxmox/generated/pve/nodes-node-hardware.d.ts +195 -0
  245. package/dist/proxmox/generated/pve/nodes-node-hardware.d.ts.map +1 -0
  246. package/dist/proxmox/generated/pve/nodes-node-lxc-vmid-firewall.d.ts +191 -0
  247. package/dist/proxmox/generated/pve/nodes-node-lxc-vmid-firewall.d.ts.map +1 -0
  248. package/dist/proxmox/generated/pve/nodes-node-lxc-vmid-move-volume.d.ts +33 -0
  249. package/dist/proxmox/generated/pve/nodes-node-lxc-vmid-move-volume.d.ts.map +1 -0
  250. package/dist/proxmox/generated/pve/nodes-node-lxc-vmid-mtunnel.d.ts +56 -0
  251. package/dist/proxmox/generated/pve/nodes-node-lxc-vmid-mtunnel.d.ts.map +1 -0
  252. package/dist/proxmox/generated/pve/nodes-node-lxc-vmid-resize.d.ts +28 -0
  253. package/dist/proxmox/generated/pve/nodes-node-lxc-vmid-resize.d.ts.map +1 -0
  254. package/dist/proxmox/generated/pve/nodes-node-lxc-vmid-rrd.d.ts +186 -0
  255. package/dist/proxmox/generated/pve/nodes-node-lxc-vmid-rrd.d.ts.map +1 -0
  256. package/dist/proxmox/generated/pve/nodes-node-lxc-vmid.d.ts +191 -0
  257. package/dist/proxmox/generated/pve/nodes-node-lxc-vmid.d.ts.map +1 -0
  258. package/dist/proxmox/generated/pve/nodes-node-network.d.ts +150 -0
  259. package/dist/proxmox/generated/pve/nodes-node-network.d.ts.map +1 -0
  260. package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-config.d.ts +301 -0
  261. package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-config.d.ts.map +1 -0
  262. package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-dbus-vmstate.d.ts +170 -0
  263. package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-dbus-vmstate.d.ts.map +1 -0
  264. package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-firewall-rules.d.ts +144 -0
  265. package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-firewall-rules.d.ts.map +1 -0
  266. package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-move-disk.d.ts +34 -0
  267. package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-move-disk.d.ts.map +1 -0
  268. package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-mtunnel.d.ts +137 -0
  269. package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-mtunnel.d.ts.map +1 -0
  270. package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-status.d.ts +179 -0
  271. package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-status.d.ts.map +1 -0
  272. package/dist/proxmox/generated/pve/nodes-node-qemu-vmid.d.ts +143 -0
  273. package/dist/proxmox/generated/pve/nodes-node-qemu-vmid.d.ts.map +1 -0
  274. package/dist/proxmox/generated/pve/nodes-node-qemu.d.ts +158 -0
  275. package/dist/proxmox/generated/pve/nodes-node-qemu.d.ts.map +1 -0
  276. package/dist/proxmox/generated/pve/nodes-node-replication.d.ts +187 -0
  277. package/dist/proxmox/generated/pve/nodes-node-replication.d.ts.map +1 -0
  278. package/dist/proxmox/generated/pve/nodes-node-services.d.ts +115 -0
  279. package/dist/proxmox/generated/pve/nodes-node-services.d.ts.map +1 -0
  280. package/dist/proxmox/generated/pve/nodes-node-storage-storage.d.ts +202 -0
  281. package/dist/proxmox/generated/pve/nodes-node-storage-storage.d.ts.map +1 -0
  282. package/dist/proxmox/generated/pve/nodes-node-storage.d.ts +40 -0
  283. package/dist/proxmox/generated/pve/nodes-node-storage.d.ts.map +1 -0
  284. package/dist/proxmox/generated/pve/nodes-node-subscription.d.ts +173 -0
  285. package/dist/proxmox/generated/pve/nodes-node-subscription.d.ts.map +1 -0
  286. package/dist/proxmox/generated/pve/nodes-node-vzdump.d.ts +97 -0
  287. package/dist/proxmox/generated/pve/nodes-node-vzdump.d.ts.map +1 -0
  288. package/dist/proxmox/generated/pve/nodes-node.d.ts +207 -0
  289. package/dist/proxmox/generated/pve/nodes-node.d.ts.map +1 -0
  290. package/dist/proxmox/generated/pve/nodes.d.ts +236 -0
  291. package/dist/proxmox/generated/pve/nodes.d.ts.map +1 -0
  292. package/dist/proxmox/generated/pve/pools.d.ts +82 -0
  293. package/dist/proxmox/generated/pve/pools.d.ts.map +1 -0
  294. package/dist/proxmox/generated/pve/storage.d.ts +159 -0
  295. package/dist/proxmox/generated/pve/storage.d.ts.map +1 -0
  296. package/dist/proxmox/generated/pve/version.d.ts +21 -0
  297. package/dist/proxmox/generated/pve/version.d.ts.map +1 -0
  298. package/dist/proxmox/generated/pve.d.ts +69 -4766
  299. package/dist/proxmox/generated/pve.d.ts.map +1 -1
  300. package/dist/proxmox/group.d.ts.map +1 -1
  301. package/dist/proxmox/ha-resource.d.ts.map +1 -1
  302. package/dist/proxmox/ha-rule.d.ts.map +1 -1
  303. package/dist/proxmox/index.d.ts +6 -1
  304. package/dist/proxmox/index.d.ts.map +1 -1
  305. package/dist/proxmox/index.js +1483 -300
  306. package/dist/proxmox/index.js.map +70 -45
  307. package/dist/proxmox/lxc-lifecycle.d.ts.map +1 -1
  308. package/dist/proxmox/metric-server-form.d.ts +11 -0
  309. package/dist/proxmox/metric-server-form.d.ts.map +1 -1
  310. package/dist/proxmox/metric-server.d.ts.map +1 -1
  311. package/dist/proxmox/network-apply.d.ts.map +1 -1
  312. package/dist/proxmox/node-network-form.d.ts +15 -0
  313. package/dist/proxmox/node-network-form.d.ts.map +1 -1
  314. package/dist/proxmox/node-network.d.ts.map +1 -1
  315. package/dist/proxmox/notification-matcher.d.ts.map +1 -1
  316. package/dist/proxmox/notification-target-endpoint.d.ts +26 -0
  317. package/dist/proxmox/notification-target-endpoint.d.ts.map +1 -0
  318. package/dist/proxmox/notification-target-form.d.ts +7 -0
  319. package/dist/proxmox/notification-target-form.d.ts.map +1 -1
  320. package/dist/proxmox/notification-target.d.ts.map +1 -1
  321. package/dist/proxmox/pbs-datastore-endpoint.d.ts +22 -0
  322. package/dist/proxmox/pbs-datastore-endpoint.d.ts.map +1 -0
  323. package/dist/proxmox/pbs-datastore.d.ts.map +1 -1
  324. package/dist/proxmox/pbs-notification-matcher.d.ts.map +1 -1
  325. package/dist/proxmox/pbs-notification-target-endpoint.d.ts +29 -0
  326. package/dist/proxmox/pbs-notification-target-endpoint.d.ts.map +1 -0
  327. package/dist/proxmox/pbs-notification-target-lifecycle.d.ts.map +1 -1
  328. package/dist/proxmox/pbs-prune-job.d.ts.map +1 -1
  329. package/dist/proxmox/pbs-sync-job-form.d.ts.map +1 -1
  330. package/dist/proxmox/pbs-verify-job.d.ts.map +1 -1
  331. package/dist/proxmox/pool.d.ts.map +1 -1
  332. package/dist/proxmox/provision-baseline.d.ts +30 -5
  333. package/dist/proxmox/provision-baseline.d.ts.map +1 -1
  334. package/dist/proxmox/qemu.d.ts +10 -0
  335. package/dist/proxmox/qemu.d.ts.map +1 -1
  336. package/dist/proxmox/replication-job.d.ts.map +1 -1
  337. package/dist/proxmox/resource-guard.d.ts +15 -0
  338. package/dist/proxmox/resource-guard.d.ts.map +1 -0
  339. package/dist/proxmox/resource-spec.d.ts +131 -0
  340. package/dist/proxmox/resource-spec.d.ts.map +1 -0
  341. package/dist/proxmox/resource.d.ts +17 -90
  342. package/dist/proxmox/resource.d.ts.map +1 -1
  343. package/dist/proxmox/role.d.ts.map +1 -1
  344. package/dist/proxmox/sdn-apply.d.ts.map +1 -1
  345. package/dist/proxmox/sdn-subnet.d.ts.map +1 -1
  346. package/dist/proxmox/sdn-vnet.d.ts.map +1 -1
  347. package/dist/proxmox/sdn-zone.d.ts.map +1 -1
  348. package/dist/proxmox/storage.d.ts.map +1 -1
  349. package/dist/proxmox/user.d.ts.map +1 -1
  350. package/dist/proxmox/zfs-pool-write.d.ts +11 -0
  351. package/dist/proxmox/zfs-pool-write.d.ts.map +1 -1
  352. package/dist/proxmox/zfs-pool.d.ts.map +1 -1
  353. package/docs/linux-host-measured.md +56 -0
  354. package/docs/linux-host.md +186 -0
  355. package/docs/netbox.md +103 -0
  356. package/docs/provision-baseline.md +34 -7
  357. package/docs/proxmox-lxc.md +40 -0
  358. package/package.json +9 -1
  359. package/src/linux/directory-lifecycle.ts +220 -0
  360. package/src/linux/directory.test.ts +132 -0
  361. package/src/linux/directory.ts +71 -0
  362. package/src/linux/fake-linux-host.ts +197 -0
  363. package/src/linux/fake-systemd.ts +103 -0
  364. package/src/linux/index.ts +32 -0
  365. package/src/linux/providers.ts +26 -0
  366. package/src/linux/region.test.ts +89 -0
  367. package/src/linux/region.ts +118 -0
  368. package/src/linux/remote-file-form.ts +96 -0
  369. package/src/linux/remote-file-lifecycle.test.ts +191 -0
  370. package/src/linux/remote-file-lifecycle.ts +161 -0
  371. package/src/linux/remote-file-plan.ts +154 -0
  372. package/src/linux/remote-file.ts +88 -0
  373. package/src/linux/ssh-command.test.ts +140 -0
  374. package/src/linux/ssh-command.ts +99 -0
  375. package/src/linux/ssh-runner.ts +188 -0
  376. package/src/linux/ssh-scripts.ts +105 -0
  377. package/src/linux/systemctl.ts +145 -0
  378. package/src/linux/unit-form.ts +183 -0
  379. package/src/linux/unit-handlers.ts +73 -0
  380. package/src/linux/unit-lifecycle.test.ts +220 -0
  381. package/src/linux/unit-lifecycle.ts +193 -0
  382. package/src/linux/unit-settle.ts +110 -0
  383. package/src/linux/unit.ts +81 -0
  384. package/src/netbox/client.test.ts +67 -0
  385. package/src/netbox/client.ts +146 -0
  386. package/src/netbox/constraint-guard.ts +57 -0
  387. package/src/netbox/constraints.test.ts +114 -0
  388. package/src/netbox/constraints.ts +152 -0
  389. package/src/netbox/generated/constraints/index.ts +23 -0
  390. package/src/netbox/generated/constraints/netbox-ipam.ts +32 -0
  391. package/src/netbox/index.ts +34 -0
  392. package/src/netbox/prefix-form.test.ts +127 -0
  393. package/src/netbox/prefix-form.ts +84 -0
  394. package/src/netbox/prefix.ts +136 -0
  395. package/src/netbox/resource.ts +208 -0
  396. package/src/netbox/values.test.ts +66 -0
  397. package/src/netbox/values.ts +40 -0
  398. package/src/openbao/index-types.test.ts +87 -0
  399. package/src/openbao/index.ts +15 -3
  400. package/src/proxmox/acl.ts +2 -0
  401. package/src/proxmox/api-token-form.ts +5 -0
  402. package/src/proxmox/apply-endpoints.ts +34 -0
  403. package/src/proxmox/backup-job.ts +2 -0
  404. package/src/proxmox/ceph-daemon-form.ts +56 -2
  405. package/src/proxmox/ceph-daemon.ts +10 -21
  406. package/src/proxmox/ceph-flag.ts +1 -0
  407. package/src/proxmox/ceph-fs.ts +1 -0
  408. package/src/proxmox/ceph-osd-write.ts +30 -4
  409. package/src/proxmox/ceph-pool.ts +10 -0
  410. package/src/proxmox/constraint-guard.ts +53 -0
  411. package/src/proxmox/constraints-dialect.test.ts +165 -0
  412. package/src/proxmox/constraints-forms.test.ts +220 -0
  413. package/src/proxmox/constraints-host-forms.test.ts +132 -0
  414. package/src/proxmox/constraints-live.test.ts +155 -0
  415. package/src/proxmox/constraints-node-forms.test.ts +188 -0
  416. package/src/proxmox/constraints-required.test.ts +172 -0
  417. package/src/proxmox/constraints.test.ts +205 -0
  418. package/src/proxmox/constraints.ts +160 -0
  419. package/src/proxmox/firewall-alias.ts +5 -0
  420. package/src/proxmox/generated/constraints/index.ts +55 -0
  421. package/src/proxmox/generated/constraints/pbs-config.ts +203 -0
  422. package/src/proxmox/generated/constraints/pve-access.ts +69 -0
  423. package/src/proxmox/generated/constraints/pve-cluster-backup.ts +74 -0
  424. package/src/proxmox/generated/constraints/pve-cluster-ceph.ts +27 -0
  425. package/src/proxmox/generated/constraints/pve-cluster-firewall.ts +35 -0
  426. package/src/proxmox/generated/constraints/pve-cluster-ha.ts +55 -0
  427. package/src/proxmox/generated/constraints/pve-cluster-metrics.ts +59 -0
  428. package/src/proxmox/generated/constraints/pve-cluster-notifications.ts +80 -0
  429. package/src/proxmox/generated/constraints/pve-cluster-replication.ts +43 -0
  430. package/src/proxmox/generated/constraints/pve-cluster-sdn.ts +90 -0
  431. package/src/proxmox/generated/constraints/pve-nodes-ceph.ts +57 -0
  432. package/src/proxmox/generated/constraints/pve-nodes-disks.ts +31 -0
  433. package/src/proxmox/generated/constraints/pve-nodes-lxc.ts +82 -0
  434. package/src/proxmox/generated/constraints/pve-nodes-network.ts +77 -0
  435. package/src/proxmox/generated/constraints/pve-nodes-qemu.ts +125 -0
  436. package/src/proxmox/generated/constraints/pve-pools.ts +31 -0
  437. package/src/proxmox/generated/constraints/pve-storage.ts +80 -0
  438. package/src/proxmox/generated/pbs/access-users.ts +137 -0
  439. package/src/proxmox/generated/pbs/access.ts +232 -0
  440. package/src/proxmox/generated/pbs/admin-datastore-store.ts +238 -0
  441. package/src/proxmox/generated/pbs/admin-metrics.ts +147 -0
  442. package/src/proxmox/generated/pbs/admin.ts +225 -0
  443. package/src/proxmox/generated/pbs/backup.ts +121 -0
  444. package/src/proxmox/generated/pbs/config-access-pam.ts +228 -0
  445. package/src/proxmox/generated/pbs/config-access.ts +228 -0
  446. package/src/proxmox/generated/pbs/config-datastore.ts +217 -0
  447. package/src/proxmox/generated/pbs/config-media-pool.ts +232 -0
  448. package/src/proxmox/generated/pbs/config-notifications-matchers.ts +187 -0
  449. package/src/proxmox/generated/pbs/config-notifications.ts +221 -0
  450. package/src/proxmox/generated/pbs/config-remote.ts +192 -0
  451. package/src/proxmox/generated/pbs/config-sync.ts +167 -0
  452. package/src/proxmox/generated/pbs/config-tape.ts +226 -0
  453. package/src/proxmox/generated/pbs/config-verify.ts +87 -0
  454. package/src/proxmox/generated/pbs/config.ts +135 -0
  455. package/src/proxmox/generated/pbs/nodes-node-dns.ts +229 -0
  456. package/src/proxmox/generated/pbs/nodes-node-services.ts +181 -0
  457. package/src/proxmox/generated/pbs/nodes-node.ts +244 -0
  458. package/src/proxmox/generated/pbs/nodes.ts +160 -0
  459. package/src/proxmox/generated/pbs/ping.ts +16 -0
  460. package/src/proxmox/generated/pbs/pull.ts +37 -0
  461. package/src/proxmox/generated/pbs/push.ts +36 -0
  462. package/src/proxmox/generated/pbs/reader.ts +41 -0
  463. package/src/proxmox/generated/pbs/root.ts +16 -0
  464. package/src/proxmox/generated/pbs/status.ts +50 -0
  465. package/src/proxmox/generated/pbs/tape-drive.ts +220 -0
  466. package/src/proxmox/generated/pbs/tape-media.ts +133 -0
  467. package/src/proxmox/generated/pbs/tape.ts +92 -0
  468. package/src/proxmox/generated/pbs/version.ts +16 -0
  469. package/src/proxmox/generated/pbs.ts +44 -787
  470. package/src/proxmox/generated/pve/access-roles.ts +168 -0
  471. package/src/proxmox/generated/pve/access-users.ts +155 -0
  472. package/src/proxmox/generated/pve/access.ts +217 -0
  473. package/src/proxmox/generated/pve/cluster-acme-plugins-id.ts +367 -0
  474. package/src/proxmox/generated/pve/cluster-acme-plugins.ts +366 -0
  475. package/src/proxmox/generated/pve/cluster-acme-tos.ts +232 -0
  476. package/src/proxmox/generated/pve/cluster-bulk-action.ts +227 -0
  477. package/src/proxmox/generated/pve/cluster-firewall-refs.ts +110 -0
  478. package/src/proxmox/generated/pve/cluster-firewall.ts +236 -0
  479. package/src/proxmox/generated/pve/cluster-ha.ts +203 -0
  480. package/src/proxmox/generated/pve/cluster-jobs.ts +190 -0
  481. package/src/proxmox/generated/pve/cluster-metrics.ts +116 -0
  482. package/src/proxmox/generated/pve/cluster-notifications-endpoints.ts +244 -0
  483. package/src/proxmox/generated/pve/cluster-notifications.ts +99 -0
  484. package/src/proxmox/generated/pve/cluster-options.ts +189 -0
  485. package/src/proxmox/generated/pve/cluster-qemu-custom-cpu-models-cputype.ts +272 -0
  486. package/src/proxmox/generated/pve/cluster-qemu-custom-cpu-models.ts +268 -0
  487. package/src/proxmox/generated/pve/cluster-replication.ts +127 -0
  488. package/src/proxmox/generated/pve/cluster-sdn-fabrics.ts +218 -0
  489. package/src/proxmox/generated/pve/cluster-sdn-ipams.ts +229 -0
  490. package/src/proxmox/generated/pve/cluster-sdn-vnets-vnet.ts +245 -0
  491. package/src/proxmox/generated/pve/cluster-sdn-vnets.ts +49 -0
  492. package/src/proxmox/generated/pve/cluster-sdn-zones.ts +224 -0
  493. package/src/proxmox/generated/pve/cluster-sdn.ts +201 -0
  494. package/src/proxmox/generated/pve/cluster.ts +71 -0
  495. package/src/proxmox/generated/pve/nodes-node-ceph.ts +167 -0
  496. package/src/proxmox/generated/pve/nodes-node-config.ts +56 -0
  497. package/src/proxmox/generated/pve/nodes-node-disks.ts +237 -0
  498. package/src/proxmox/generated/pve/nodes-node-firewall.ts +239 -0
  499. package/src/proxmox/generated/pve/nodes-node-hardware.ts +215 -0
  500. package/src/proxmox/generated/pve/nodes-node-lxc-vmid-firewall.ts +232 -0
  501. package/src/proxmox/generated/pve/nodes-node-lxc-vmid-move-volume.ts +1059 -0
  502. package/src/proxmox/generated/pve/nodes-node-lxc-vmid-mtunnel.ts +49 -0
  503. package/src/proxmox/generated/pve/nodes-node-lxc-vmid-resize.ts +285 -0
  504. package/src/proxmox/generated/pve/nodes-node-lxc-vmid-rrd.ts +184 -0
  505. package/src/proxmox/generated/pve/nodes-node-lxc-vmid.ts +240 -0
  506. package/src/proxmox/generated/pve/nodes-node-network.ts +234 -0
  507. package/src/proxmox/generated/pve/nodes-node-qemu-vmid-config.ts +441 -0
  508. package/src/proxmox/generated/pve/nodes-node-qemu-vmid-dbus-vmstate.ts +215 -0
  509. package/src/proxmox/generated/pve/nodes-node-qemu-vmid-firewall-rules.ts +145 -0
  510. package/src/proxmox/generated/pve/nodes-node-qemu-vmid-move-disk.ts +664 -0
  511. package/src/proxmox/generated/pve/nodes-node-qemu-vmid-mtunnel.ts +188 -0
  512. package/src/proxmox/generated/pve/nodes-node-qemu-vmid-status.ts +233 -0
  513. package/src/proxmox/generated/pve/nodes-node-qemu-vmid.ts +187 -0
  514. package/src/proxmox/generated/pve/nodes-node-qemu.ts +204 -0
  515. package/src/proxmox/generated/pve/nodes-node-replication.ts +187 -0
  516. package/src/proxmox/generated/pve/nodes-node-services.ts +221 -0
  517. package/src/proxmox/generated/pve/nodes-node-storage-storage.ts +226 -0
  518. package/src/proxmox/generated/pve/nodes-node-storage.ts +40 -0
  519. package/src/proxmox/generated/pve/nodes-node-subscription.ts +168 -0
  520. package/src/proxmox/generated/pve/nodes-node-vzdump.ts +96 -0
  521. package/src/proxmox/generated/pve/nodes-node.ts +211 -0
  522. package/src/proxmox/generated/pve/nodes.ts +235 -0
  523. package/src/proxmox/generated/pve/pools.ts +78 -0
  524. package/src/proxmox/generated/pve/storage.ts +213 -0
  525. package/src/proxmox/generated/pve/version.ts +21 -0
  526. package/src/proxmox/generated/pve.ts +69 -7403
  527. package/src/proxmox/group.ts +2 -0
  528. package/src/proxmox/ha-resource.ts +5 -0
  529. package/src/proxmox/ha-rule.ts +2 -0
  530. package/src/proxmox/index.ts +12 -0
  531. package/src/proxmox/lxc-interior.test.ts +77 -0
  532. package/src/proxmox/lxc-lifecycle.ts +48 -9
  533. package/src/proxmox/metric-server-form.ts +10 -0
  534. package/src/proxmox/metric-server.ts +11 -2
  535. package/src/proxmox/network-apply.ts +4 -0
  536. package/src/proxmox/node-network-form.ts +19 -0
  537. package/src/proxmox/node-network.ts +9 -3
  538. package/src/proxmox/notification-matcher.ts +5 -0
  539. package/src/proxmox/notification-target-endpoint.ts +46 -0
  540. package/src/proxmox/notification-target-form.ts +11 -0
  541. package/src/proxmox/notification-target.ts +5 -2
  542. package/src/proxmox/pbs-datastore-endpoint.ts +29 -0
  543. package/src/proxmox/pbs-datastore.ts +8 -1
  544. package/src/proxmox/pbs-notification-matcher.ts +5 -0
  545. package/src/proxmox/pbs-notification-target-endpoint.ts +45 -0
  546. package/src/proxmox/pbs-notification-target-lifecycle.ts +16 -14
  547. package/src/proxmox/pbs-prune-job.ts +2 -0
  548. package/src/proxmox/pbs-sync-job-form.ts +2 -0
  549. package/src/proxmox/pbs-verify-job.ts +2 -0
  550. package/src/proxmox/pool.ts +2 -0
  551. package/src/proxmox/provision-baseline.test.ts +38 -0
  552. package/src/proxmox/provision-baseline.ts +73 -14
  553. package/src/proxmox/provision-bootstrap.test.ts +51 -0
  554. package/src/proxmox/qemu.ts +9 -1
  555. package/src/proxmox/replication-job.ts +5 -0
  556. package/src/proxmox/resource-guard.ts +61 -0
  557. package/src/proxmox/resource-spec.ts +129 -0
  558. package/src/proxmox/resource.ts +52 -93
  559. package/src/proxmox/role.ts +2 -0
  560. package/src/proxmox/sdn-apply.ts +4 -0
  561. package/src/proxmox/sdn-subnet.ts +5 -0
  562. package/src/proxmox/sdn-vnet.ts +2 -0
  563. package/src/proxmox/sdn-zone.ts +2 -0
  564. package/src/proxmox/storage.ts +2 -0
  565. package/src/proxmox/user.ts +2 -0
  566. package/src/proxmox/zfs-pool-write.ts +12 -0
  567. package/src/proxmox/zfs-pool.ts +2 -1
@@ -176,6 +176,8 @@ const handlers = pveHandlers<GroupProps, GroupAttributes>({
176
176
  * `resource.ts` states once in the ⛔ on adoption: a field deliberately out of `matches` is a
177
177
  * field this resource does not manage.
178
178
  */
179
+ /** The vendor rules these forms are checked against at plan time — resource-spec.ts. */
180
+ endpoint: { create: 'pve:POST /access/groups', update: 'pve:PUT /access/groups/{groupid}' },
179
181
  matches: (attributes, props) => attributes.comment === storedComment(props.comment),
180
182
  path: (props) => `access/groups/${props.groupid}`,
181
183
  /**
@@ -137,6 +137,11 @@ const handlers = pveHandlers<HaResourceProps, HaResourceAttributes>({
137
137
  * ⚠️ `sid` AND `type` ARE NOT COMPARED EITHER: sid is the path, so a change there is a different
138
138
  * object, and type is create-only — it is read back from the prefix, never edited.
139
139
  */
140
+ /** The vendor rules these forms are checked against at plan time — resource-spec.ts. */
141
+ endpoint: {
142
+ create: 'pve:POST /cluster/ha/resources',
143
+ update: 'pve:PUT /cluster/ha/resources/{sid}',
144
+ },
140
145
  matches: (attributes, props) =>
141
146
  attributes.state === (props.state ?? 'started') &&
142
147
  attributes.comment === (props.comment ?? '') &&
@@ -206,6 +206,8 @@ const handlers = pveHandlers<HaRuleProps, HaRuleAttributes>({
206
206
  * ⚠️ THE COMMENT IS COMPARED AS PVE WILL STORE IT, not as it was declared — `commentText` and
207
207
  * its ⛔ explain why a `%XX` in a comment does not survive the round trip.
208
208
  */
209
+ /** The vendor rules these forms are checked against at plan time — resource-spec.ts. */
210
+ endpoint: { create: 'pve:POST /cluster/ha/rules', update: 'pve:PUT /cluster/ha/rules/{rule}' },
209
211
  matches: (attributes, props) =>
210
212
  attributes.resources === csv(props.resources) &&
211
213
  attributes.affinity === props.affinity &&
@@ -18,6 +18,9 @@
18
18
  * ★ THE NOTIFICATION FAMILIES JOINED 2026-09-22: PBS targets and matchers, the PVE matcher, the
19
19
  * `FromEnv` shape their write-only values take, and the Alertmanager body template
20
20
  * (docs/pbs-notifications.md; the template alone: docs/pbs-alertmanager-body.md).
21
+ * ★ THE VENDOR CONSTRAINT READER JOINED 2026-09-22 (codegen/README.md). `constraintsFor` and
22
+ * `violations` are exported so a CONSUMING stack can assert its own declarations offline — the
23
+ * `deploy:pbs` that failed on a 128-character comment had no way to ask that question.
21
24
  * ★ Anything else unlisted is still reachable by path if you genuinely need
22
25
  * it — that is a deliberate, visible act rather than an accident of barrelling.
23
26
  */
@@ -30,6 +33,13 @@ export { ProxmoxCephFlagProvider } from './ceph-flag.ts';
30
33
  export { ProxmoxCephFsProvider } from './ceph-fs.ts';
31
34
  export { ProxmoxCephOsdProvider } from './ceph-osd.ts';
32
35
  export { ProxmoxCephPool, ProxmoxCephPoolProvider } from './ceph-pool.ts';
36
+ export { constraintsFor, formViolations } from './constraint-guard.ts';
37
+ export {
38
+ type EndpointConstraints,
39
+ type EndpointKey,
40
+ type ParamConstraint,
41
+ violations,
42
+ } from './constraints.ts';
33
43
  export { ProxmoxFirewallAliasProvider } from './firewall-alias.ts';
34
44
  export { ProxmoxGroup, ProxmoxGroupProvider } from './group.ts';
35
45
  export { ProxmoxHaResource, ProxmoxHaResourceProvider } from './ha-resource.ts';
@@ -63,7 +73,9 @@ export { ProxmoxPool, ProxmoxPoolProvider } from './pool.ts';
63
73
  export {
64
74
  PROVISION_DEFAULTS,
65
75
  PROVISION_PRIVILEGES,
76
+ type CoreProvisionNames,
66
77
  type ProvisionBaseline,
78
+ type ProvisionComments,
67
79
  type ProvisionLane,
68
80
  type ProvisionNames,
69
81
  type ResolvedProvisionNames,
@@ -0,0 +1,77 @@
1
+ /**
2
+ * PVE exposes no way to reach INSIDE a container, and this pins that as a measured fact rather
3
+ * than a thing people keep re-deriving.
4
+ *
5
+ * ★ WHY A TEST AND NOT ONLY A DOC. `Proxmox.Lxc` declares a guest's PVE-level config and nothing
6
+ * within its filesystem, and every consumer that meets that limit goes looking for the resource
7
+ * that must surely exist — an exec, a file write, a cloud-init. It does not, for containers. A
8
+ * grep proves that once; this proves it on every run, and fails the day PVE adds one, which is
9
+ * exactly when the kit would want to wrap it.
10
+ * ⛔ THE POSITIVE CONTROL IS LOAD BEARING. A test that only asserts absence passes for free if the
11
+ * generated file's comment shape ever changes. QEMU's `agent/exec` and `agent/file-write` are
12
+ * asserted present in the same pass, so a format change fails here instead of going quiet.
13
+ * ⚠️ SIBLING FAMILIES ARE NOT AT PARITY. QEMU and LXC sit under the same `/nodes/{node}/…` tree
14
+ * and have completely different reach. Never infer one family's endpoints from the other's.
15
+ */
16
+ import { describe, expect, test } from 'bun:test';
17
+ import { readdirSync } from 'node:fs';
18
+ import { fileURLToPath } from 'node:url';
19
+ import { join } from 'node:path';
20
+
21
+ /**
22
+ * ⚠️ THE GENERATED TYPES ARE A DIRECTORY NOW, NOT ONE FILE. `generated/pve.ts` became a barrel of
23
+ * `export *` lines when codegen/types.ts split the 678 endpoints across files that fit the house
24
+ * cap, so reading that path alone would find no endpoint at all — and every absence assertion
25
+ * below would pass on an empty list. That is what the first test guards.
26
+ */
27
+ const dir = fileURLToPath(new URL('./generated/pve/', import.meta.url));
28
+ const schema = (
29
+ await Promise.all(
30
+ readdirSync(dir)
31
+ .sort()
32
+ .map((name) => Bun.file(join(dir, name)).text()),
33
+ )
34
+ ).join('\n');
35
+
36
+ /** Every endpoint the generated schema documents, as `METHOD /path`. */
37
+ const endpoints = [...schema.matchAll(/(GET|POST|PUT|DELETE) (\/[A-Za-z0-9/{}_.-]+)/g)].map(
38
+ (match) => `${match[1]} ${match[2]}`,
39
+ );
40
+
41
+ const under = (prefix: string) =>
42
+ endpoints.filter((line) => line.slice(line.indexOf(' ') + 1).startsWith(prefix));
43
+
44
+ const LXC = '/nodes/{node}/lxc/{vmid}';
45
+ const QEMU = '/nodes/{node}/qemu/{vmid}';
46
+
47
+ describe('a container has no interior API', () => {
48
+ test('the schema was parsed at all', () => {
49
+ // ⛔ Without this, every absence assertion below would pass on an empty list.
50
+ expect(endpoints.length).toBeGreaterThan(100);
51
+ expect(under(LXC).length).toBeGreaterThan(20);
52
+ });
53
+
54
+ test('QEMU can exec and write files inside a guest — the positive control', () => {
55
+ expect(under(QEMU)).toContain(`POST ${QEMU}/agent/exec`);
56
+ expect(under(QEMU)).toContain(`POST ${QEMU}/agent/file-write`);
57
+ expect(under(QEMU)).toContain(`GET ${QEMU}/agent/file-read`);
58
+ });
59
+
60
+ test('no LXC endpoint execs, reads or writes a file, or takes cloud-init', () => {
61
+ // ⛔ So a generic, vendor-API-based Resource for a container's interior cannot be written:
62
+ // there is nothing to wrap. What is left is an image baked before create, a first-boot
63
+ // artifact, or a recorded human step — see docs/proxmox-lxc.md.
64
+ const reaching = under(LXC).filter((line) =>
65
+ /\/(agent|exec|file-read|file-write|cloudinit|cloud-init)(\/|$)/.test(line),
66
+ );
67
+ expect(reaching).toEqual([]);
68
+ });
69
+
70
+ test('the only LXC reach inside is an interactive console, which is not declarative', () => {
71
+ // ⚠️ `termproxy` and `vncwebsocket` open a terminal for a person. They are not an API a
72
+ // resource can diff, and the kit wraps neither.
73
+ const consoles = under(LXC).filter((line) => /(termproxy|vncwebsocket|spiceproxy)/.test(line));
74
+ expect(consoles.length).toBeGreaterThan(0);
75
+ expect(schema.includes('LxcExec')).toBe(false);
76
+ });
77
+ });
@@ -25,6 +25,8 @@
25
25
  */
26
26
  import * as Effect from 'effect/Effect';
27
27
  import { PveError, pve, pveWith } from './client.ts';
28
+ import { guardForm } from './constraint-guard.ts';
29
+ import type { EndpointKey } from './constraints.ts';
28
30
  import { type PveTarget, mint } from './credentials.ts';
29
31
  import { createForm } from './lxc-create-form.ts';
30
32
  import { type LxcChange, judge } from './lxc-judge.ts';
@@ -43,6 +45,26 @@ export type LxcWhere = { readonly target: PveTarget; readonly node: string; read
43
45
 
44
46
  export const guestPath = (where: LxcWhere) => `nodes/${where.node}/lxc/${String(where.vmid)}`;
45
47
 
48
+ /**
49
+ * The three vendor endpoints a guest is written through, as the generated tables key them.
50
+ *
51
+ * ⛔ DECLARED HERE RATHER THAN ON A SPEC BECAUSE `Proxmox.Lxc` HAS NO SPEC — lxc.ts writes all
52
+ * five handlers by hand (a guest reads failures as failures, waits on tasks and grows disks
53
+ * through a second endpoint), so it cannot inherit the shared guard from resource.ts. Without
54
+ * these three it would be the largest write surface in the package with nothing checking the
55
+ * body: `POST /nodes/{node}/lxc` alone carries 26 constrained parameters.
56
+ * ⚠️ THREE, NOT TWO. `resize` is a separate PVE endpoint with its own schema — `disk` against an
57
+ * enum of `rootfs` and `mp0..mp255`, `size` against PVE's `+<n>` / `<n>` pattern — and it is
58
+ * the one lxc-volume.ts drives.
59
+ * ⛔ `{vmid}` AND `{node}` ARE PATH SEGMENTS, NOT FORM KEYS, on the two PUTs. On the POST `vmid`
60
+ * IS a form key and is required, which is why `createForm` sends it.
61
+ */
62
+ const LXC_ENDPOINTS = {
63
+ create: 'pve:POST /nodes/{node}/lxc' as EndpointKey,
64
+ resize: 'pve:PUT /nodes/{node}/lxc/{vmid}/resize' as EndpointKey,
65
+ update: 'pve:PUT /nodes/{node}/lxc/{vmid}/config' as EndpointKey,
66
+ };
67
+
46
68
  /** How long each task may run, in one-second polls. ⚠️ A cap, not an estimate. */
47
69
  const CREATE_POLLS = 180;
48
70
  const TASK_POLLS = 60;
@@ -132,14 +154,25 @@ const task = (
132
154
 
133
155
  /** POST the create and wait for the template to unpack. ⛔ Refusals are the caller's to check. */
134
156
  export const createGuest = (props: LxcProps) =>
135
- task(
136
- props,
137
- 'POST',
138
- `nodes/${props.node}/lxc`,
139
- `create CT ${String(props.vmid)}`,
140
- CREATE_POLLS,
141
- createForm(props),
142
- );
157
+ Effect.gen(function* () {
158
+ const form = createForm(props);
159
+ /**
160
+ * ⛔ BEFORE THE POST, AND WITH PRESENCE, BECAUSE THIS IS UNCONDITIONALLY A CREATE. Reached
161
+ * only when the guest is absent (lxc.ts's reconcile), so the vendor's required parameters
162
+ * really are about to go on the wire — `ostemplate` and `vmid`, both of which
163
+ * `createRefusals` already insists on, plus every bound the schema carries and nothing here
164
+ * knew: `cores` 1..8192, `memory` ≥ 16, `hostname` as a dns-name, `tags`, `startup`.
165
+ */
166
+ yield* guardForm(LXC_ENDPOINTS.create, form, true);
167
+ return yield* task(
168
+ props,
169
+ 'POST',
170
+ `nodes/${props.node}/lxc`,
171
+ `create CT ${String(props.vmid)}`,
172
+ CREATE_POLLS,
173
+ form,
174
+ );
175
+ });
143
176
 
144
177
  /**
145
178
  * Apply a judged change: the config PUT first, then each resize.
@@ -158,16 +191,22 @@ export const updateGuest = (props: LxcProps, change: LxcChange, digest: string)
158
191
  { ...change.put, ...(digest === '' ? {} : { digest }) },
159
192
  change.clear,
160
193
  );
194
+ /** ⚠️ NO PRESENCE: this form is partial by construction — it is `judge`'s answer. */
195
+ yield* guardForm(LXC_ENDPOINTS.update, form, false);
161
196
  yield* pve(props.target, 'provision', 'PUT', `${guestPath(props)}/config`, form);
162
197
  }
163
198
  for (const grow of change.resize) {
199
+ const grown = { disk: grow.disk, size: grow.size };
200
+ // ⛔ WITH PRESENCE: `disk` and `size` are both required and both always sent, so this is a
201
+ // value check over PVE's own `+<n>` size pattern and its `rootfs|mp0..mp255` enum.
202
+ yield* guardForm(LXC_ENDPOINTS.resize, grown, true);
164
203
  yield* task(
165
204
  props,
166
205
  'PUT',
167
206
  `${guestPath(props)}/resize`,
168
207
  `grow ${grow.disk} of CT ${String(props.vmid)} to ${grow.size}`,
169
208
  TASK_POLLS,
170
- { disk: grow.disk, size: grow.size },
209
+ grown,
171
210
  );
172
211
  }
173
212
  });
@@ -126,3 +126,13 @@ export const update = (props: MetricServerProps) => {
126
126
  .map(([option]) => option);
127
127
  return withClears(body(props), clear);
128
128
  };
129
+
130
+ /**
131
+ * The create form: `body` plus the one field only a POST takes.
132
+ *
133
+ * ★ EXPORTED SO THE CONSTRAINT PROOF CAN RUN THE REAL FORM. `metric-server.ts` built this inline
134
+ * in its spec, which meant the only way to check it against PVE's table was to retype it in a
135
+ * test — and a retyped form proves the test, not the provider.
136
+ * ⚠️ `type` IS REQUIRED ON CREATE AND REFUSED ON UPDATE; `id` is the path, never the body.
137
+ */
138
+ export const createBody = (props: MetricServerProps) => ({ ...body(props), type: props.type });
@@ -31,7 +31,7 @@
31
31
  import { Resource } from 'alchemy';
32
32
  import * as Provider from 'alchemy/Provider';
33
33
  import * as Effect from 'effect/Effect';
34
- import { UNSET, body, update } from './metric-server-form.ts';
34
+ import { UNSET, createBody, update } from './metric-server-form.ts';
35
35
  import {
36
36
  type MetricServerOtelAttributes,
37
37
  type MetricServerOtelProps,
@@ -186,7 +186,16 @@ const handlers = pveHandlers<MetricServerProps, MetricServerAttributes>({
186
186
  /** ⛔ THE SAME STRING AS `path`, DELIBERATELY — see the ⛔ in the header. */
187
187
  collection: (props) => `cluster/metrics/server/${props.id}`,
188
188
  /** ⚠️ `type` IS REQUIRED ON CREATE; `id` IS NOT SENT, because the id is the path. */
189
- createForm: (props) => ({ ...body(props), type: props.type }),
189
+ createForm: createBody,
190
+ /**
191
+ * The vendor rules both forms are checked against at plan time — resource-spec.ts.
192
+ * ⚠️ POST AND PUT ARE THE SAME PATH HERE, and they are still two different tables: only the
193
+ * POST marks `type` required, and only the PUT accepts `delete` and `digest`.
194
+ */
195
+ endpoint: {
196
+ create: 'pve:POST /cluster/metrics/server/{id}',
197
+ update: 'pve:PUT /cluster/metrics/server/{id}',
198
+ },
190
199
  /**
191
200
  * ⛔ `id` and `type` are absent: one is the key the object was read by, the other is refused
192
201
  * rather than updated. Everything type-specific is `matchesType`'s, above.
@@ -50,6 +50,7 @@ import { isResolved } from 'alchemy/Diff';
50
50
  import type { Input } from 'alchemy/Input';
51
51
  import * as Provider from 'alchemy/Provider';
52
52
  import * as Effect from 'effect/Effect';
53
+ import { guardNetworkApply } from './apply-endpoints.ts';
53
54
  import { pveWith } from './client.ts';
54
55
  import { mint } from './credentials.ts';
55
56
  import { awaitTask, degradedReason, pendingCount } from './network-apply-read.ts';
@@ -172,6 +173,9 @@ const apply = (props: NetworkApplyProps) =>
172
173
  * not have. The `provision` lease is 300s and non-renewable, which is far longer than a
173
174
  * reload and is the reason no renew path is reached for.
174
175
  */
176
+ // ⛔ BEFORE THE MINT AND THE RELOAD. The apply takes no body, so this is the lookup rather
177
+ // than a value check: a vendor that moved this endpoint fails here, not mid-ifreload.
178
+ yield* guardNetworkApply;
175
179
  const credential = yield* mint(props.target, 'provision');
176
180
  const upid = yield* pveWith<string>(props.target, credential, 'PUT', `nodes/${node}/network`);
177
181
  if (upid === undefined) {
@@ -132,6 +132,25 @@ export const body = (props: NodeNetworkProps): Record<string, string> => ({
132
132
  type: props.type,
133
133
  });
134
134
 
135
+ /**
136
+ * The create form: `body` plus the name of the interface being created.
137
+ *
138
+ * 🔴 `iface` WAS MISSING UNTIL 2026-09-22, AND EVERY CREATE THIS FAMILY HAS EVER PLANNED WOULD
139
+ * HAVE 400ed. `POST /nodes/{node}/network` declares `iface` REQUIRED (`pve-iface`, 2..20) and
140
+ * `{node}` is its only path parameter, so the name has to travel in the BODY — unlike the PUT,
141
+ * where `/network/{iface}` carries it and `updateBody` is right to leave it out. Nothing caught
142
+ * it because no NodeNetwork has been created from a declaration yet: C1's three nodes were all
143
+ * adopted, which takes the PUT path. Found by wiring this family to the vendor's own table,
144
+ * which is exactly the 128-character comment again with a different parameter.
145
+ *
146
+ * ⚠️ NOT ADDED TO `body`, BECAUSE THE PUT MUST NOT CARRY IT. `additionalProperties => 0` on the
147
+ * update schema makes a second copy of the name a 400 rather than an ignored hint.
148
+ */
149
+ export const createBody = (props: NodeNetworkProps): Record<string, string> => ({
150
+ ...body(props),
151
+ iface: props.iface,
152
+ });
153
+
135
154
  /**
136
155
  * The update form: `body` plus the two fields that can only be cleared explicitly.
137
156
  *
@@ -69,7 +69,7 @@ import { Resource } from 'alchemy';
69
69
  import * as Provider from 'alchemy/Provider';
70
70
  import * as Effect from 'effect/Effect';
71
71
  import {
72
- body,
72
+ createBody,
73
73
  readAttributes,
74
74
  same,
75
75
  sameComment,
@@ -199,8 +199,14 @@ export const ProxmoxNodeNetwork = Resource<ProxmoxNodeNetwork>('Proxmox.NodeNetw
199
199
  const handlers = pveHandlers<NodeNetworkProps, NodeNetworkAttributes>({
200
200
  attributes: readAttributes,
201
201
  collection: (props) => `nodes/${props.node}/network`,
202
- /** ⚠️ No `delete` parameter on a POST — see the ⚠️ on `updateBody`. */
203
- createForm: body,
202
+ /** ⚠️ No `delete` parameter on a POST — see the ⚠️ on `updateBody`. `iface` IS in the create
203
+ * body though, and was missing until 2026-09-22 — the 🔴 on `createBody`. */
204
+ createForm: createBody,
205
+ /** The vendor rules both forms are checked against at plan time — resource-spec.ts. */
206
+ endpoint: {
207
+ create: 'pve:POST /nodes/{node}/network',
208
+ update: 'pve:PUT /nodes/{node}/network/{iface}',
209
+ },
204
210
  /**
205
211
  * ⛔ `cidr` IS THE ONLY FIELD COMPARED WHEN UNDECLARED, AND THAT ASYMMETRY IS THE POINT. Every
206
212
  * other field here follows storage.ts: undeclared means unmanaged, so it is neither sent nor
@@ -64,6 +64,11 @@ const handlers = pveHandlers<NotificationMatcherProps, NotificationMatcherAttrib
64
64
  attributes: (live, props) => matcherAttributes(live, props.name),
65
65
  collection: () => 'cluster/notifications/matchers',
66
66
  createForm: matcherCreateForm,
67
+ /** The vendor rules these forms are checked against at plan time — resource-spec.ts. */
68
+ endpoint: {
69
+ create: 'pve:POST /cluster/notifications/matchers',
70
+ update: 'pve:PUT /cluster/notifications/matchers/{name}',
71
+ },
67
72
  matches: matcherMatches,
68
73
  path: (props) => `cluster/notifications/matchers/${props.name}`,
69
74
  updateForm: matcherUpdateForm,
@@ -0,0 +1,46 @@
1
+ /**
2
+ * `Proxmox.NotificationTarget`'s eight vendor endpoints — one create and one update per family.
3
+ *
4
+ * ⛔ PVE REGISTERS ONE PATH PER TYPE, NOT A `{type}` PARAMETER, AND THE FOUR SCHEMAS DIFFER IN
5
+ * WHAT THEY REQUIRE: gotify wants `server` and `token`, smtp `server` and `from-address`,
6
+ * webhook `url` and `method`, sendmail nothing but its name. One key for all four would enforce
7
+ * gotify's rules on a sendmail target and let three families through unchecked, which is why
8
+ * `PveSpec['endpoint']` admits a function of props.
9
+ *
10
+ * ⛔ THE STRINGS ARE LITERALS AND MUST STAY LITERALS. `codegen/constraints.ts` finds the endpoints
11
+ * to table by SCANNING THIS PACKAGE'S TEXT, so `` `pve:POST …/${props.type}` `` would be tabled
12
+ * by nothing and `constraintsFor` would throw on the first deploy that reached it.
13
+ *
14
+ * ⚠️ GOTIFY'S CREATE CAN NEVER SATISFY ITS OWN TABLE, AND THAT IS THE TRUTH RATHER THAN A BUG
15
+ * HERE. `token` is required by PVE and is a write-only secret, so it is not a prop — props are
16
+ * persisted to the state store unencrypted (the third ⛔ in notification-target.ts). A gotify
17
+ * target is created out of band and then DECLARED, which is an adopt followed by updates; the
18
+ * shared guard only demands the create form's required parameters when a create is really about
19
+ * to happen (`resource-guard.ts`), so declaring an existing gotify target still plans clean and
20
+ * asking to CREATE one is refused at plan time with `token: required` instead of by a 400.
21
+ */
22
+ import type { NotificationTargetProps } from './notification-target.ts';
23
+ import type { EndpointPair } from './resource-spec.ts';
24
+
25
+ const ENDPOINTS: Readonly<Record<NotificationTargetProps['type'], EndpointPair>> = {
26
+ gotify: {
27
+ create: 'pve:POST /cluster/notifications/endpoints/gotify',
28
+ update: 'pve:PUT /cluster/notifications/endpoints/gotify/{name}',
29
+ },
30
+ sendmail: {
31
+ create: 'pve:POST /cluster/notifications/endpoints/sendmail',
32
+ update: 'pve:PUT /cluster/notifications/endpoints/sendmail/{name}',
33
+ },
34
+ smtp: {
35
+ create: 'pve:POST /cluster/notifications/endpoints/smtp',
36
+ update: 'pve:PUT /cluster/notifications/endpoints/smtp/{name}',
37
+ },
38
+ webhook: {
39
+ create: 'pve:POST /cluster/notifications/endpoints/webhook',
40
+ update: 'pve:PUT /cluster/notifications/endpoints/webhook/{name}',
41
+ },
42
+ };
43
+
44
+ /** The pair this declaration writes. ⚠️ `type` is identity here, so it never changes under a row. */
45
+ export const targetEndpoint = (props: NotificationTargetProps): EndpointPair =>
46
+ ENDPOINTS[props.type];
@@ -102,3 +102,14 @@ export const shape = (props: NotificationTargetProps): Record<string, string> =>
102
102
  ...set('url', props.url),
103
103
  ...set('username', props.username),
104
104
  });
105
+
106
+ /**
107
+ * The create form: `shape` plus the name PVE takes in the body exactly once.
108
+ *
109
+ * ★ EXPORTED SO THE CONSTRAINT PROOF CAN RUN THE REAL FORM rather than a retyped copy of it.
110
+ * ⛔ `name` IS CREATE-ONLY: PVE takes it in the body on the POST and in the path forever after.
111
+ */
112
+ export const createShape = (props: NotificationTargetProps): Record<string, string> => ({
113
+ ...shape(props),
114
+ name: props.name,
115
+ });
@@ -53,7 +53,8 @@
53
53
  import { Resource } from 'alchemy';
54
54
  import * as Provider from 'alchemy/Provider';
55
55
  import * as Effect from 'effect/Effect';
56
- import { addressList, headerList, portOf, shape } from './notification-target-form.ts';
56
+ import { targetEndpoint } from './notification-target-endpoint.ts';
57
+ import { addressList, createShape, headerList, portOf, shape } from './notification-target-form.ts';
57
58
  import { type PveRequirements, type WithTarget, pveHandlers } from './resource.ts';
58
59
  import { text } from './values.ts';
59
60
 
@@ -180,7 +181,9 @@ const handlers = pveHandlers<NotificationTargetProps, NotificationTargetAttribut
180
181
  }),
181
182
  collection: (props) => `cluster/notifications/endpoints/${props.type}`,
182
183
  /** ⛔ `name` is create-only: PVE takes it in the body once, and in the path forever after. */
183
- createForm: (props) => ({ ...shape(props), name: props.name }),
184
+ createForm: createShape,
185
+ /** ⚠️ A function, because the type picks the endpoint — see `targetEndpoint`. */
186
+ endpoint: targetEndpoint,
184
187
  /**
185
188
  * Each line reads "not declared, or equal"; `disable` is the one field with no undeclared case.
186
189
  *
@@ -0,0 +1,29 @@
1
+ /**
2
+ * `Pbs.Datastore`'s two vendor endpoints, and the plan-time check over its two forms.
3
+ *
4
+ * ★ A FILE OF ITS OWN BECAUSE THIS FAMILY DOES NOT USE `pveHandlers`. It writes its own `diff` and
5
+ * `reconcile` (a create answers with a task id, so it settles rather than reading back once), so
6
+ * it cannot inherit the guard from resource.ts — and a copy of the two calls inside that already
7
+ * long file is exactly the per-resource copy-paste the shared handler exists to prevent.
8
+ *
9
+ * ⛔ THE FOUR FIELDS THAT MADE THIS WORTH DOING, from the PBS 4.2.6 schema: `comment` is
10
+ * maxLength 128 with a no-control-characters pattern, `name` is 3..32 with a safe-id pattern,
11
+ * and every `keep-*` has minimum 1. All four were `string`/`number` with the limits in prose.
12
+ */
13
+ import * as Effect from 'effect/Effect';
14
+ import { guardForm } from './constraint-guard.ts';
15
+ import type { EndpointKey } from './constraints.ts';
16
+ import { createForm, updateForm } from './pbs-datastore-form.ts';
17
+ import type { PbsDatastoreProps } from './pbs-datastore.ts';
18
+
19
+ export const DATASTORE_ENDPOINT: { readonly create: EndpointKey; readonly update: EndpointKey } = {
20
+ create: 'pbs:POST /config/datastore',
21
+ update: 'pbs:PUT /config/datastore/{name}',
22
+ };
23
+
24
+ /** ⚠️ Presence on create only — an update form is partial by design (update-guard.ts). */
25
+ export const guardDatastoreForms = (props: PbsDatastoreProps): Effect.Effect<void> =>
26
+ Effect.gen(function* () {
27
+ yield* guardForm(DATASTORE_ENDPOINT.create, createForm(props), true);
28
+ yield* guardForm(DATASTORE_ENDPOINT.update, updateForm(props), false);
29
+ });
@@ -64,6 +64,7 @@ import {
64
64
  updateForm,
65
65
  } from './pbs-datastore-form.ts';
66
66
  import { guardBackend, guardPath, settle } from './pbs-datastore-guard.ts';
67
+ import { guardDatastoreForms } from './pbs-datastore-endpoint.ts';
67
68
  import type { PveRequirements } from './resource.ts';
68
69
  import { formToSend } from './update-guard.ts';
69
70
 
@@ -181,7 +182,11 @@ export const PbsDatastoreProvider = () =>
181
182
  */
182
183
  diff: ({ news, output }) =>
183
184
  Effect.gen(function* () {
184
- if (output === undefined || !isResolved(news)) return undefined;
185
+ if (!isResolved(news)) return undefined;
186
+ // ⛔ BEFORE the `output === undefined` return: that branch IS the create, which is the
187
+ // one this family has never checked. resource.ts carries the argument in full.
188
+ yield* guardDatastoreForms(news);
189
+ if (output === undefined) return undefined;
185
190
  const live = yield* readOne(news);
186
191
  // ⚠️ `update`, not `create` — Alchemy's Diff admits only noop/update/replace, and an
187
192
  // object Alchemy has state for but PBS does not is drift for reconcile to repair.
@@ -198,6 +203,8 @@ export const PbsDatastoreProvider = () =>
198
203
  * ⛔ THE `matches` GUARD BEFORE THE PUT IS resource.ts's, AND IT IS WHY ADOPTION IS FREE.
199
204
  */
200
205
  reconcile: Effect.fn(function* ({ news }) {
206
+ // ⚠️ Again here: an ADOPTED row's diff answer is discarded by Alchemy and reconcile runs.
207
+ yield* guardDatastoreForms(news);
201
208
  const live = yield* readOne(news);
202
209
  let upid: string | undefined;
203
210
  if (live === undefined) {
@@ -69,6 +69,11 @@ const handlers = pveHandlers<PbsNotificationMatcherProps, NotificationMatcherAtt
69
69
  attributes: (live, props) => matcherAttributes(live, props.name),
70
70
  collection: () => 'config/notifications/matchers',
71
71
  createForm: matcherCreateForm,
72
+ /** The vendor rules these forms are checked against at plan time — resource-spec.ts. */
73
+ endpoint: {
74
+ create: 'pbs:POST /config/notifications/matchers',
75
+ update: 'pbs:PUT /config/notifications/matchers/{name}',
76
+ },
72
77
  matches: matcherMatches,
73
78
  path: (props) => `config/notifications/matchers/${props.name}`,
74
79
  updateForm: matcherUpdateForm,
@@ -0,0 +1,45 @@
1
+ /**
2
+ * `Pbs.NotificationTarget`'s six vendor endpoints — one create and one update per family.
3
+ *
4
+ * 🔴 THIS FAMILY WAS THE ONE THE 2026-09-22 SWEEP NEARLY MISSED, and it carries the very
5
+ * parameter the incident was about: `comment` is `maxLength: 128` with a no-control-characters
6
+ * pattern on all three PBS creates, exactly as it is on `POST /config/verify`. A 129-character
7
+ * comment on a notification target would have failed the same way, half a deploy in, on the
8
+ * family whose whole purpose is to make failures visible.
9
+ *
10
+ * ⛔ PBS REGISTERS ONE PATH PER TYPE, NOT A `{type}` PARAMETER, and the three schemas differ:
11
+ * smtp requires `server` and `from-address`, webhook `url` and `method`, sendmail nothing but
12
+ * its name. One key would enforce one family's rules on all three.
13
+ * ⛔ THE STRINGS MUST STAY LITERALS. `codegen/constraints.ts` finds the endpoints to table by
14
+ * SCANNING THIS PACKAGE'S TEXT, so a key built from `props.type` would be tabled by nothing.
15
+ *
16
+ * ⚠️ NO GOTIFY KEY, BECAUSE THIS RESOURCE HAS NO GOTIFY TYPE. `PbsNotificationTargetType` is
17
+ * sendmail | smtp | webhook; PBS 4.2 does publish a gotify endpoint, and nothing here writes to
18
+ * it. ⛔ `scripts/proxmox-ownership-pbs.ts` says otherwise — it claims all four families
19
+ * through the shared `notificationEndpoints` helper — so `docs/api-coverage.md` credits this
20
+ * resource with twelve write endpoints where it really makes nine. That is an overclaim in the
21
+ * hand-written ownership ledger, recorded here rather than fixed in passing: correcting it
22
+ * regenerates a report built from a DIFFERENT (older, 9.2.4) schema manifest, which is its own
23
+ * change with its own diff.
24
+ */
25
+ import type { PbsNotificationTargetProps } from './pbs-notification-target.ts';
26
+ import type { EndpointPair } from './resource-spec.ts';
27
+
28
+ const ENDPOINTS: Readonly<Record<PbsNotificationTargetProps['type'], EndpointPair>> = {
29
+ sendmail: {
30
+ create: 'pbs:POST /config/notifications/endpoints/sendmail',
31
+ update: 'pbs:PUT /config/notifications/endpoints/sendmail/{name}',
32
+ },
33
+ smtp: {
34
+ create: 'pbs:POST /config/notifications/endpoints/smtp',
35
+ update: 'pbs:PUT /config/notifications/endpoints/smtp/{name}',
36
+ },
37
+ webhook: {
38
+ create: 'pbs:POST /config/notifications/endpoints/webhook',
39
+ update: 'pbs:PUT /config/notifications/endpoints/webhook/{name}',
40
+ },
41
+ };
42
+
43
+ /** The pair this declaration writes. ⚠️ `type` is identity here — changing it is a replace. */
44
+ export const pbsTargetEndpoint = (props: PbsNotificationTargetProps): EndpointPair =>
45
+ ENDPOINTS[props.type];
@@ -15,6 +15,8 @@ import { isResolved } from 'alchemy/Diff';
15
15
  import type { Input } from 'alchemy/Input';
16
16
  import * as Effect from 'effect/Effect';
17
17
  import { pve } from './client.ts';
18
+ import { guardForm } from './constraint-guard.ts';
19
+ import { pbsTargetEndpoint } from './pbs-notification-target-endpoint.ts';
18
20
  import type {
19
21
  PbsNotificationTargetAttributes,
20
22
  PbsNotificationTargetProps,
@@ -142,25 +144,25 @@ export const handlers = {
142
144
  const carry = { header: true, sealed: true } as const;
143
145
  yield* requireValues(news, groups, carry);
144
146
  const collection = `config/notifications/endpoints/${news.type}`;
145
- yield* pve(
146
- news.target,
147
- 'provision',
148
- 'POST',
149
- collection,
150
- targetForm(news, groups, carry, 'create'),
151
- );
147
+ const form = targetForm(news, groups, carry, 'create');
148
+ /**
149
+ * ⛔ WITH PRESENCE, BECAUSE THIS BRANCH IS UNCONDITIONALLY THE CREATE. PBS marks `name` on
150
+ * every family and `server`/`from-address` on smtp, `url`/`method` on webhook — and it
151
+ * is the same `comment: maxLength 128` that failed `POST /config/verify`.
152
+ * ⚠️ THE FORM CARRIES SECRETS ON THIS PATH. `violations` reads values and builds only the
153
+ * parameter NAME into its message (constraints.ts), so a refusal never quotes one.
154
+ */
155
+ yield* guardForm(pbsTargetEndpoint(news).create, form, true);
156
+ yield* pve(news.target, 'provision', 'POST', collection, form);
152
157
  sealed = seal(groups.sealed.values);
153
158
  } else {
154
159
  const carry = toCarry(live, news, groups, sealed);
155
160
  if (carry !== undefined) {
156
161
  yield* requireValues(news, groups, carry);
157
- yield* pve(
158
- news.target,
159
- 'provision',
160
- 'PUT',
161
- path(news),
162
- targetForm(news, groups, carry, 'update'),
163
- );
162
+ const form = targetForm(news, groups, carry, 'update');
163
+ /** ⚠️ NO PRESENCE: an update form is partial by design — it carries what `toCarry` said. */
164
+ yield* guardForm(pbsTargetEndpoint(news).update, form, false);
165
+ yield* pve(news.target, 'provision', 'PUT', path(news), form);
164
166
  if (carry.sealed) sealed = seal(groups.sealed.values);
165
167
  }
166
168
  }
@@ -194,6 +194,8 @@ const handlers = pveHandlers<PruneJobProps, PruneJobAttributes>({
194
194
  * compared unconditionally. A changed `store` is an update, not a replace: PBS accepts `store`
195
195
  * on PUT, so the job is re-pointed in place.
196
196
  */
197
+ /** The vendor rules these forms are checked against at plan time — resource-spec.ts. */
198
+ endpoint: { create: 'pbs:POST /config/prune', update: 'pbs:PUT /config/prune/{id}' },
197
199
  matches: (attributes, props) =>
198
200
  attributes.schedule === props.schedule &&
199
201
  attributes.store === props.store &&
@@ -209,6 +209,8 @@ export const handlers = pveHandlers<SyncJobProps, SyncJobAttributes>({
209
209
  * ⚠️ `id`, `group-filter` AND `sync-direction` ARE OUT. The first is the path, a change to which
210
210
  * is a different object; the other two are argued on their props in pbs-sync-job.ts.
211
211
  */
212
+ /** The vendor rules these forms are checked against at plan time — resource-spec.ts. */
213
+ endpoint: { create: 'pbs:POST /config/sync', update: 'pbs:PUT /config/sync/{id}' },
212
214
  matches: (attributes, props) =>
213
215
  attributes['remove-vanished'] === (props['remove-vanished'] === true) &&
214
216
  attributes.store === props.store &&