@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
@@ -0,0 +1,136 @@
1
+ /**
2
+ * `Netbox.Prefix` — one IP prefix and the decision recorded against it.
3
+ *
4
+ * ★ WHY THIS OBJECT CLASS IS THE FIRST ONE, AND NOT `Device`, `VLAN` OR `Site`. Three reasons,
5
+ * each measurable rather than aesthetic:
6
+ *
7
+ * 1. **It is the only interesting NetBox object with no foreign-key prerequisite.** MEASURED in
8
+ * the 4.7.0 schema: `WritablePrefixRequest.required` is exactly `["prefix"]`. A `VLAN` needs
9
+ * `vid` AND `name` and belongs to a group or site; a `Device` needs a role, a type, a site
10
+ * and usually a manufacturer — four more Resources before the first one can be declared.
11
+ * A scaffold that cannot declare anything until five families exist proves nothing.
12
+ * 2. **It is what the estate's NetBox is FOR.** The house's own IPAM agent describes its job as
13
+ * reconciling "what the network IS against what NetBox says it was DECIDED to be". A prefix
14
+ * is the atom of that decision. The estate has prefixes whose status is currently recorded
15
+ * only in an SSH config comment and a retirement doc — a management VLAN, a Thunderbolt
16
+ * point-to-point, and three ranges that are retired and still resolve in people's heads.
17
+ * 3. **`status: 'deprecated'` makes retirement declarable.** That is the move this unlocks:
18
+ * a retired range stops being folklore and becomes a line in a stack file with a reviewable
19
+ * diff. No other NetBox class turns an estate decision into one field this cleanly.
20
+ *
21
+ * ⚠️ ADOPT-FRIENDLY BY CONSTRUCTION. `locate` filters on the exact `prefix`; `identifies` then
22
+ * picks the declared VRF, because NetBox allows the same CIDR in two VRFs and in the global
23
+ * table. An instance that already holds `10.0.0.0/24` is BOUND, never duplicated — and ⛔ an
24
+ * adopt never clears prose it did not declare (prefix-form.ts).
25
+ *
26
+ * ⛔ THIS RESOURCE DOES NOT REMOVE PREFIXES IT DOES NOT DECLARE, and `defaultRemovalPolicy` is
27
+ * `retain` (resource.ts). Deleting a prefix in NetBox reparents its children and detaches its
28
+ * IP assignments; the record of why it existed survives only in the change log.
29
+ *
30
+ * ⛔ NO CREDENTIAL IS A PROP. `NETBOX_URL` and `NETBOX_TOKEN` are read from the environment at
31
+ * call time — the house convention, and the only shape that keeps a token out of Alchemy state.
32
+ */
33
+ import { Resource } from 'alchemy';
34
+ import * as Provider from 'alchemy/Provider';
35
+ import * as Effect from 'effect/Effect';
36
+ import { prefixBody, prefixMatches } from './prefix-form.ts';
37
+ import { type NetboxRequirements, netboxHandlers } from './resource.ts';
38
+ import { choice, fk, text } from './values.ts';
39
+
40
+ /**
41
+ * ⚠️ THE FOUR VALUES ARE THE VENDOR'S, NOT OURS — copied from the generated table, which is
42
+ * generated from NetBox's own enum. The table is what ENFORCES them; this type is what makes
43
+ * the mistake visible in an editor.
44
+ */
45
+ export type PrefixStatus = 'container' | 'active' | 'reserved' | 'deprecated';
46
+
47
+ export interface PrefixProps {
48
+ /** CIDR, exactly as NetBox stores it — `10.0.0.0/24`. The stable key for locate. */
49
+ prefix: string;
50
+ /**
51
+ * VRF id, or omitted for the global table.
52
+ *
53
+ * ⛔ PART OF THE IDENTITY, NOT A SETTING. NetBox's uniqueness on a prefix is per-VRF, so a
54
+ * locate that ignored it could match two rows — which `soleMatch` refuses rather than
55
+ * guessing between.
56
+ */
57
+ vrf?: number;
58
+ status?: PrefixStatus;
59
+ /** ⚠️ `maxLength: 200` in the schema; the generated table enforces it at plan time. */
60
+ description?: string;
61
+ /** Free text. ⚠️ NetBox states no length limit, so nothing here checks one. */
62
+ comments?: string;
63
+ tenant?: number;
64
+ vlan?: number;
65
+ /** All addresses inside are usable. */
66
+ isPool?: boolean;
67
+ markUtilized?: boolean;
68
+ }
69
+
70
+ export interface PrefixAttributes {
71
+ prefixId: number;
72
+ prefix: string;
73
+ status: string;
74
+ description: string;
75
+ comments: string;
76
+ vrf: number | undefined;
77
+ tenant: number | undefined;
78
+ vlan: number | undefined;
79
+ isPool: boolean;
80
+ markUtilized: boolean;
81
+ }
82
+
83
+ export interface NetboxPrefix extends Resource<
84
+ 'Netbox.Prefix',
85
+ PrefixProps,
86
+ PrefixAttributes,
87
+ never,
88
+ NetboxRequirements
89
+ > {}
90
+
91
+ export const NetboxPrefix = Resource<NetboxPrefix>('Netbox.Prefix', {
92
+ defaultRemovalPolicy: 'retain',
93
+ });
94
+
95
+ const handlers = netboxHandlers<PrefixProps, PrefixAttributes>({
96
+ attributes: (live, props) => {
97
+ const id = live['id'];
98
+ if (typeof id !== 'number') return undefined;
99
+ return {
100
+ comments: text(live['comments']),
101
+ description: text(live['description']),
102
+ isPool: live['is_pool'] === true,
103
+ markUtilized: live['mark_utilized'] === true,
104
+ prefix: text(live['prefix']) || props.prefix,
105
+ prefixId: id,
106
+ status: choice(live['status']),
107
+ tenant: fk(live['tenant']),
108
+ vlan: fk(live['vlan']),
109
+ vrf: fk(live['vrf']),
110
+ };
111
+ },
112
+ collection: 'ipam/prefixes',
113
+ createBody: prefixBody,
114
+ describe: (props) => `ipam/prefixes ${props.prefix}`,
115
+ endpoint: {
116
+ create: 'netbox:POST /api/ipam/prefixes/',
117
+ update: 'netbox:PATCH /api/ipam/prefixes/{id}/',
118
+ },
119
+ /**
120
+ * 🔴 THE VRF IS **NOT** IN THIS FILTER, AND THE REASON IS A GUESS THAT WAS CAUGHT. This read
121
+ * `vrf_id=null` for the global table — NetBox does define `FILTERS_NULL_CHOICE_VALUE = 'null'`
122
+ * and does honour it on filters that opt in. ⛔ MEASURED IN THE VENDOR'S OWN SOURCE at
123
+ * v4.7.0: `PrefixFilterSet.vrf_id` is a plain `django_filters.ModelMultipleChoiceFilter` with
124
+ * no `null_value`, so `'null'` is validated against the VRF queryset, fails, and NetBox
125
+ * answers 400 under strict filtering — on EVERY plan for EVERY global prefix.
126
+ * ★ So the CIDR narrows server-side with a filter the document plainly declares, and `identifies`
127
+ * picks the VRF in this process. One extra page of candidates, no vendor semantics guessed.
128
+ */
129
+ identifies: (live, props) => fk(live['vrf']) === props.vrf,
130
+ locate: (props) => [['prefix', props.prefix]],
131
+ matches: prefixMatches,
132
+ updateBody: prefixBody,
133
+ });
134
+
135
+ export const NetboxPrefixProvider = () =>
136
+ Provider.effect(NetboxPrefix, Effect.succeed(NetboxPrefix.Provider.of(handlers)));
@@ -0,0 +1,208 @@
1
+ /**
2
+ * One shape for every NetBox object — the same four operations, different path and JSON body.
3
+ *
4
+ * ⛔ THE ALTERNATIVE IS COPYING THE SAME HANDLERS PER RESOURCE. Prefixes, VLANs, devices, tenants
5
+ * and interfaces are all create / read / update / delete over `/api` with JSON bodies and a
6
+ * numeric primary key. Hand-rolling the fourth copy is where someone drops the read-back or the
7
+ * constraint guard and the plan lies.
8
+ *
9
+ * ★ ADOPT IS THE DEFAULT POSTURE, NOT A FLAG. `reconcile` LOCATES before it writes: an object the
10
+ * estate already has is bound, not duplicated. NetBox is a record that predates this code by
11
+ * years; a provider that created a second `10.20.10.0/24` on first deploy would be worse than
12
+ * no provider.
13
+ *
14
+ * ★ `defaultRemovalPolicy: 'retain'` ON EVERY FAMILY. NetBox holds the estate's record of what
15
+ * the network was DECIDED to be, and deleting a row deletes history — child prefixes reparent,
16
+ * IP assignments detach, and the change log is the only trace left. `retain` means the engine
17
+ * skips `delete` when a resource is orphaned unless the caller opts into
18
+ * `.pipe(RemovalPolicy.destroy())`. The `delete` handler is FULLY IMPLEMENTED anyway: a stub
19
+ * that silently does nothing lies to whoever reads the plan.
20
+ */
21
+ import { isResolved } from 'alchemy/Diff';
22
+ import type { Input } from 'alchemy/Input';
23
+ import * as Effect from 'effect/Effect';
24
+ import type * as HttpClient from 'effect/unstable/http/HttpClient';
25
+ import { NetboxError, type NetboxList, type NetboxRow, netbox, soleMatch } from './client.ts';
26
+ import { guardBody } from './constraint-guard.ts';
27
+ import type { EndpointKey, NetboxBody } from './constraints.ts';
28
+
29
+ /**
30
+ * ★ WHAT EVERY OPERATION HERE NEEDS FROM THE RUNTIME, AND NOTHING MORE. The token comes from
31
+ * `NETBOX_TOKEN` in the environment, so there is no process to spawn and no `bao` to shell out
32
+ * to. Declaring a service you never use is not harmless — it makes a stack provide a layer for
33
+ * nothing, and it hides the one service you DO need.
34
+ */
35
+ export type NetboxRequirements = HttpClient.HttpClient;
36
+
37
+ export interface NetboxSpec<Props extends object, Attributes> {
38
+ /** `ipam/prefixes` — where a new one is POSTed and where `locate` filters. */
39
+ readonly collection: string;
40
+ /**
41
+ * The query that narrows the candidates, as `URLSearchParams` pairs.
42
+ *
43
+ * ⛔ ONLY FILTERS THE VENDOR DOCUMENT DECLARES, AND ONLY IN THE FORM IT DECLARES THEM. A
44
+ * filter NetBox rejects answers 400, which `absentOn404` correctly does NOT fold to "absent" —
45
+ * so a guessed filter shape is a hard failure on every plan, not a soft one.
46
+ * ★ IT DOES NOT HAVE TO BE UNIQUE. `identifies` finishes the job in this process, where the
47
+ * rule is readable and testable offline.
48
+ */
49
+ readonly locate: (props: Props) => readonly (readonly [string, string])[];
50
+ /**
51
+ * Which of the returned rows IS this object.
52
+ *
53
+ * 🔴 THIS EXISTS BECAUSE THE OBVIOUS ALTERNATIVE WAS A GUESS. `Netbox.Prefix` first narrowed
54
+ * server-side with `vrf_id=null`, the sentinel NetBox uses elsewhere for "no foreign key".
55
+ * ⛔ MEASURED IN THE VENDOR'S OWN SOURCE at v4.7.0: `PrefixFilterSet.vrf_id` is a plain
56
+ * `django_filters.ModelMultipleChoiceFilter` with NO `null_value`, so `'null'` is validated
57
+ * against the VRF queryset, fails, and NetBox answers 400 under strict filtering. The
58
+ * sentinel is real (`FILTERS_NULL_CHOICE_VALUE = 'null'`) but it is opt-in per filter, and
59
+ * this one did not opt in.
60
+ * ★ SO THE DISCRIMINATOR MOVED INTO THIS PROCESS. It costs one page of candidates and buys a
61
+ * rule that can be read, tested without a server, and cannot be wrong about a vendor's
62
+ * filter semantics. Omit it when `locate` really is unique on its own.
63
+ */
64
+ readonly identifies?: (live: NetboxRow, props: Props) => boolean;
65
+ readonly attributes: (live: NetboxRow, props: Props) => Attributes | undefined;
66
+ readonly createBody: (props: Props) => NetboxBody;
67
+ /** ⚠️ PARTIAL BY DESIGN: NetBox updates are PATCH, so presence is not checked on this body. */
68
+ readonly updateBody?: (props: Props) => NetboxBody;
69
+ readonly matches: (attributes: Attributes, props: Props) => boolean;
70
+ /** The generated constraint table to check each body against, by endpoint key. */
71
+ readonly endpoint: { readonly create: EndpointKey; readonly update?: EndpointKey };
72
+ /** For the message `soleMatch` raises and for read-back failures. */
73
+ readonly describe: (props: Props) => string;
74
+ }
75
+
76
+ /** ⚠️ Only 404 folds to "absent". A 403 or a 502 is a real failure — folding it would plan a create over an existing object. */
77
+ const absentOn404 = <A>(io: Effect.Effect<A, NetboxError, NetboxRequirements>) =>
78
+ io.pipe(
79
+ Effect.catchIf(
80
+ (cause): cause is NetboxError => cause instanceof NetboxError && cause.status === 404,
81
+ () => Effect.succeed(undefined as A),
82
+ ),
83
+ );
84
+
85
+ /**
86
+ * ⚠️ NOT `limit=1`, AND NOT `limit=2` EITHER. One row is all a caller wants, but the page has to
87
+ * be wide enough for `identifies` to see every candidate `locate` matched — a prefix that
88
+ * exists in several VRFs comes back several times, and a page of two would hide the third.
89
+ * ★ TWENTY, AND THE NUMBER IS AN ASSERTION: a natural key matching more than twenty rows is not
90
+ * a natural key. `count` is checked against it, so the failure is "your filter is too broad"
91
+ * rather than a silent truncation.
92
+ */
93
+ const LOCATE_PAGE = 20;
94
+
95
+ const query = (pairs: readonly (readonly [string, string])[]): string =>
96
+ new URLSearchParams([
97
+ ...pairs.map(([k, v]) => [k, v] as [string, string]),
98
+ ['limit', String(LOCATE_PAGE)],
99
+ ]).toString();
100
+
101
+ export const netboxOperations = <Props extends object, Attributes>(
102
+ spec: NetboxSpec<Props, Attributes>,
103
+ ) => {
104
+ const fetchLive = (props: Props) =>
105
+ absentOn404(
106
+ netbox<NetboxList<NetboxRow>>('GET', `${spec.collection}/?${query(spec.locate(props))}`),
107
+ ).pipe(
108
+ Effect.map((list) => {
109
+ if (list !== undefined && list.count > LOCATE_PAGE) {
110
+ throw new Error(
111
+ `${spec.describe(props)}: the locate filter matched ${String(list.count)} rows, more ` +
112
+ `than the ${String(LOCATE_PAGE)}-row page this reads. That is not a natural key — ` +
113
+ 'narrow the filter rather than paging through candidates.',
114
+ );
115
+ }
116
+ const rows = list?.results ?? [];
117
+ const narrow = spec.identifies;
118
+ return soleMatch(
119
+ narrow === undefined ? rows : rows.filter((row) => narrow(row, props)),
120
+ spec.describe(props),
121
+ );
122
+ }),
123
+ );
124
+
125
+ /** ⛔ The numeric `id` is the wire path. NetBox has no update-by-natural-key. */
126
+ const objectPath = (live: NetboxRow): string => `${spec.collection}/${String(live['id'])}`;
127
+
128
+ const read = (props: Props) =>
129
+ fetchLive(props).pipe(
130
+ Effect.map((live) => (live === undefined ? undefined : spec.attributes(live, props))),
131
+ );
132
+
133
+ return {
134
+ read,
135
+
136
+ diff: (news: Input<Props>, output: Attributes | undefined) =>
137
+ Effect.gen(function* () {
138
+ if (output === undefined || !isResolved(news)) return undefined;
139
+ const live = yield* read(news);
140
+ if (live === undefined) return { action: 'update' } as const;
141
+ if (spec.matches(live, news)) return { action: 'noop' } as const;
142
+ return spec.updateBody === undefined
143
+ ? ({ action: 'replace' } as const)
144
+ : ({ action: 'update' } as const);
145
+ }),
146
+
147
+ reconcile: (news: Props) =>
148
+ Effect.gen(function* () {
149
+ const before = yield* fetchLive(news);
150
+ if (before === undefined) {
151
+ const body = spec.createBody(news);
152
+ // ⛔ GUARD BEFORE THE REQUEST, WITH PRESENCE ON. This is the only place a missing
153
+ // required property can still be caught locally.
154
+ yield* guardBody(spec.endpoint.create, body, true);
155
+ yield* netbox('POST', `${spec.collection}/`, body);
156
+ } else if (spec.updateBody !== undefined) {
157
+ const mapped = spec.attributes(before, news);
158
+ // ⚠️ ADOPTION IS THE `mapped === undefined` CASE TOO: a row this spec cannot map is not
159
+ // a row to PATCH blindly.
160
+ if (mapped !== undefined && !spec.matches(mapped, news)) {
161
+ const body = spec.updateBody(news);
162
+ yield* guardBody(spec.endpoint.update, body, false);
163
+ if (Object.keys(body).length > 0) {
164
+ yield* netbox('PATCH', `${objectPath(before)}/`, body);
165
+ }
166
+ }
167
+ }
168
+ const after = yield* read(news);
169
+ if (after === undefined) {
170
+ return yield* Effect.die(
171
+ new Error(
172
+ `${spec.describe(news)}: the write returned no error but the object is still ` +
173
+ 'absent. NetBox returns the object it wrote — read back rather than trusting the ' +
174
+ 'status code.',
175
+ ),
176
+ );
177
+ }
178
+ return after;
179
+ }),
180
+
181
+ destroy: (olds: Props) =>
182
+ Effect.gen(function* () {
183
+ const live = yield* fetchLive(olds);
184
+ if (live === undefined) return;
185
+ yield* netbox('DELETE', `${objectPath(live)}/`);
186
+ }),
187
+ };
188
+ };
189
+
190
+ /**
191
+ * The five provider handlers for a spec'd NetBox object, wired once.
192
+ *
193
+ * ⚠️ `list` answers empty. NetBox index endpoints return the whole estate — tens of thousands of
194
+ * rows on a real instance — so adoption stays explicit rather than sweeping.
195
+ */
196
+ export const netboxHandlers = <Props extends object, Attributes extends object>(
197
+ spec: NetboxSpec<Props, Attributes>,
198
+ ) => {
199
+ const ops = netboxOperations(spec);
200
+ return {
201
+ list: () => Effect.succeed([]),
202
+ read: ({ olds }: { olds: Props }) => ops.read(olds),
203
+ diff: ({ news, output }: { news: Input<Props>; output: Attributes | undefined }) =>
204
+ ops.diff(news, output),
205
+ reconcile: ({ news }: { news: Props }) => ops.reconcile(news),
206
+ delete: ({ olds }: { olds: Props }) => ops.destroy(olds),
207
+ };
208
+ };
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Read-versus-write asymmetry — the bug that makes a resource never converge.
3
+ *
4
+ * 🔴 THE SHAPE IS DIFFERENT IN EACH DIRECTION AND NOTHING IN THE TYPES SAYS SO. Measured in the
5
+ * NetBox 4.7.0 document: a prefix is WRITTEN with `status: "active"` and READ BACK as
6
+ * `status: {value: "active", label: "Active"}`; a foreign key is written as `4` and read back
7
+ * as `{id: 4, url: …, display: …}`. A `matches` that compared those directly would report drift
8
+ * on every plan, for every object, forever — and each "update" would PATCH the same value back.
9
+ */
10
+ import { describe, expect, test } from 'bun:test';
11
+ import { bool, choice, fk, text } from './values.ts';
12
+
13
+ describe('a choice field reads back as an object', () => {
14
+ test('the object form reduces to the string a declaration writes', () => {
15
+ expect(choice({ label: 'Active', value: 'active' })).toBe('active');
16
+ });
17
+
18
+ /** ⚠️ Both directions must work: a fixture or a brief serialisation gives the bare string. */
19
+ test('the bare string passes through unchanged', () => {
20
+ expect(choice('deprecated')).toBe('deprecated');
21
+ });
22
+
23
+ test('anything else is empty rather than undefined, so a comparison stays total', () => {
24
+ expect(choice(undefined)).toBe('');
25
+ expect(choice(null)).toBe('');
26
+ expect(choice({ label: 'Active' })).toBe('');
27
+ });
28
+ });
29
+
30
+ describe('a foreign key reads back as a nested object', () => {
31
+ test('the nested object reduces to its id', () => {
32
+ expect(
33
+ fk({ display: 'HomeFlare', id: 4, url: 'https://example.invalid/api/tenancy/tenants/4/' }),
34
+ ).toBe(4);
35
+ });
36
+
37
+ test('the bare integer passes through', () => {
38
+ expect(fk(7)).toBe(7);
39
+ });
40
+
41
+ /**
42
+ * ⛔ `undefined`, NOT `0`. A cleared foreign key and "tenant 0" are different facts, and zero
43
+ * is falsy — a `matches` written against it would treat an unset tenant as a match for every
44
+ * declaration that omitted one.
45
+ */
46
+ test('an absent or unrecognisable key is undefined', () => {
47
+ expect(fk(null)).toBeUndefined();
48
+ expect(fk(undefined)).toBeUndefined();
49
+ expect(fk({ display: 'no id here' })).toBeUndefined();
50
+ });
51
+ });
52
+
53
+ describe('text and booleans', () => {
54
+ /** ⚠️ NetBox stores an empty string for absent text, never null — so `''` is the settled value. */
55
+ test('absent text settles to the empty string', () => {
56
+ expect(text(undefined)).toBe('');
57
+ expect(text(null)).toBe('');
58
+ expect(text('a note')).toBe('a note');
59
+ });
60
+
61
+ test('only a real true is true', () => {
62
+ expect(bool(true)).toBe(true);
63
+ expect(bool('true')).toBe(false);
64
+ expect(bool(1)).toBe(false);
65
+ });
66
+ });
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Reading a NetBox row into settled values.
3
+ *
4
+ * ⛔ A NETBOX READ AND A NETBOX WRITE ARE NOT THE SAME SHAPE, AND THIS IS WHERE THAT IS HANDLED.
5
+ * MEASURED in the 4.7.0 document: `WritablePrefixRequest.status` is a bare string enum
6
+ * (`"active"`), while `Prefix.status` on the way back is an OBJECT — `{value, label}`. A `diff`
7
+ * that compared the declared string against the live object would see drift on every plan, for
8
+ * every prefix, forever, and each "update" would PATCH the same value back.
9
+ * ⚠️ The same asymmetry holds for every choice field in NetBox (`dcim` device `status`,
10
+ * `ipam` IP `role`, …). Anything read through `choice` is safe against it.
11
+ */
12
+
13
+ /** ⚠️ `''` for absent, not `undefined` — NetBox stores an empty string, never null, for text. */
14
+ export const text = (value: unknown): string => (typeof value === 'string' ? value : '');
15
+
16
+ export const bool = (value: unknown): boolean => value === true;
17
+
18
+ /** A `{value, label}` choice object, reduced to the string a declaration writes. */
19
+ export const choice = (value: unknown): string => {
20
+ if (typeof value === 'string') return value;
21
+ if (typeof value === 'object' && value !== null && 'value' in value) {
22
+ return text((value as { value: unknown }).value);
23
+ }
24
+ return '';
25
+ };
26
+
27
+ /**
28
+ * A foreign key, as the integer a declaration writes.
29
+ *
30
+ * ⚠️ IT ARRIVES AS A NESTED OBJECT ON READ AND AN INTEGER ON WRITE — `{id, url, display, …}`
31
+ * versus `4`. Comparing the two directly is the same never-converges bug as `choice`.
32
+ */
33
+ export const fk = (value: unknown): number | undefined => {
34
+ if (typeof value === 'number') return value;
35
+ if (typeof value === 'object' && value !== null && 'id' in value) {
36
+ const id = (value as { id: unknown }).id;
37
+ return typeof id === 'number' ? id : undefined;
38
+ }
39
+ return undefined;
40
+ };
@@ -0,0 +1,87 @@
1
+ /**
2
+ * The barrel's TYPE surface, pinned.
3
+ *
4
+ * ⛔ THIS IS THE TEST FOR A BUG THAT ONLY A CONSUMER COULD SEE. Every `Bao.*` family already
5
+ * re-exported its `…Props` and `…Attributes` from its own module, but `index.ts` forwarded only
6
+ * the VALUES for seven of them. A consumer that may not deep-import — which is every consumer,
7
+ * by the estate's adoption rules — therefore could not name the props of the very Resource the
8
+ * barrel handed it, and had to write the shape out and hope it stayed in step.
9
+ * MEASURED 2026-09-22 in homeflare-openbao, which did exactly that for `BaoProxmoxRole`.
10
+ *
11
+ * ★ A TYPE-ONLY TEST, ON PURPOSE. Nothing here runs; `tsc --noEmit` is the assertion. If a family's
12
+ * props stop being reachable from the package entry, this file stops compiling, which is the
13
+ * only moment anyone would otherwise notice — at the next consumer, in another repo.
14
+ */
15
+ import type {
16
+ BaoAuthMethodAttributes,
17
+ BaoAuthMethodProps,
18
+ BaoAuthRoleAttributes,
19
+ BaoAuthRoleProps,
20
+ BaoCloudflareRoleAttributes,
21
+ BaoCloudflareRoleProps,
22
+ BaoJwtRoleAttributes,
23
+ BaoMountAttributes,
24
+ BaoMountProps,
25
+ BaoPkiRoleAttributes,
26
+ BaoPkiRoleProps,
27
+ BaoPluginAttributes,
28
+ BaoPluginProps,
29
+ BaoPolicyAttributes,
30
+ BaoPolicyProps,
31
+ BaoProxmoxRoleAttributes,
32
+ BaoProxmoxRoleProps,
33
+ BaoSshRoleAttributes,
34
+ BaoSshRoleProps,
35
+ } from './index.ts';
36
+ import { expect, test } from 'bun:test';
37
+
38
+ /**
39
+ * ⛔ The one a consumer was already missing. `mount` + `name` + `mintUser` + `ttl` + `maxTtl` IS the
40
+ * whole role, so a consumer that writes this shape out by hand is writing the entire
41
+ * server-side state of the family — including `mintUser`, which is its security boundary.
42
+ */
43
+ const proxmoxRole: BaoProxmoxRoleProps = {
44
+ maxTtl: '30m',
45
+ mintUser: 'hf-provision@pve',
46
+ mount: 'proxmox-ops',
47
+ name: 'provision',
48
+ ttl: '5m',
49
+ };
50
+
51
+ const mount: BaoMountProps = { path: 'proxmox-ops', type: 'openbao-plugin-secrets-proxmox' };
52
+
53
+ /** ⛔ The plugin catalog key — a consumer needs this to declare a registration at all. */
54
+ const plugin: BaoPluginProps = {
55
+ command: 'openbao-plugin-secrets-proxmox',
56
+ name: 'openbao-plugin-secrets-proxmox',
57
+ sha256: 'a'.repeat(64),
58
+ type: 'secret',
59
+ version: 'v0.0.0-dev',
60
+ };
61
+
62
+ /** ★ Named so the attribute types are reachable too: a consumer reads outputs as well as writing props. */
63
+ type Reachable =
64
+ | BaoAuthMethodAttributes
65
+ | BaoAuthMethodProps
66
+ | BaoAuthRoleAttributes
67
+ | BaoAuthRoleProps
68
+ | BaoCloudflareRoleAttributes
69
+ | BaoCloudflareRoleProps
70
+ | BaoJwtRoleAttributes
71
+ | BaoMountAttributes
72
+ | BaoPkiRoleAttributes
73
+ | BaoPkiRoleProps
74
+ | BaoProxmoxRoleAttributes
75
+ | BaoPluginAttributes
76
+ | BaoPolicyAttributes
77
+ | BaoPolicyProps
78
+ | BaoSshRoleAttributes
79
+ | BaoSshRoleProps;
80
+
81
+ test("every openbao family's props are reachable from the package entry", () => {
82
+ const reachable: Reachable[] = [];
83
+ expect(reachable).toEqual([]);
84
+ expect(proxmoxRole.mintUser).toBe('hf-provision@pve');
85
+ expect(mount.type).toBe('openbao-plugin-secrets-proxmox');
86
+ expect(plugin.version).toBe('v0.0.0-dev');
87
+ });
@@ -23,11 +23,13 @@ export {
23
23
  revokeSelf,
24
24
  revokeSelfEffect,
25
25
  } from './approle-login.ts';
26
+ export type { BaoAuthMethodAttributes, BaoAuthMethodProps } from './auth-method.ts';
26
27
  export { BaoAuthMethod, BaoAuthMethodProvider } from './auth-method.ts';
27
- export type { BaoAuthRoleProps } from './auth-role.ts';
28
+ export type { BaoAuthRoleAttributes, BaoAuthRoleProps } from './auth-role.ts';
28
29
  export { BaoAuthRole, BaoAuthRoleProvider } from './auth-role.ts';
29
30
  export type { BaoIdentity, BaoIdentityExpected, BaoIdentityFailure } from './bao-identity.ts';
30
31
  export { BaoIdentityError, assertBaoIdentity, assertBaoIdentityEffect } from './bao-identity.ts';
32
+ export type { BaoCloudflareRoleAttributes, BaoCloudflareRoleProps } from './cloudflare-role.ts';
31
33
  export { BaoCloudflareRole, BaoCloudflareRoleProvider } from './cloudflare-role.ts';
32
34
  export {
33
35
  CloudflarePermissionGroups,
@@ -42,7 +44,12 @@ export type { HostAppRolesInput, HostRoleClass, HostRoleHost } from './host-appr
42
44
  export { HOST_ROLE_SEPARATOR, hostAppRoles, hostRoleName } from './host-approles.ts';
43
45
  export type { BaoJwtAuthConfigProps } from './jwt-config.ts';
44
46
  export { BaoJwtAuthConfig, BaoJwtAuthConfigProvider } from './jwt-config.ts';
45
- export type { BaoJwtRoleProps, BaoJwtRoleType } from './jwt-role.ts';
47
+ export type {
48
+ BaoJwtCallbackMode,
49
+ BaoJwtRoleAttributes,
50
+ BaoJwtRoleProps,
51
+ BaoJwtRoleType,
52
+ } from './jwt-role.ts';
46
53
  export { BaoJwtRole, BaoJwtRoleProvider } from './jwt-role.ts';
47
54
  export type { BaoKubernetesAliasSource, BaoKubernetesRoleProps } from './kubernetes-role.ts';
48
55
  export { BaoKubernetesRole, BaoKubernetesRoleProvider } from './kubernetes-role.ts';
@@ -50,10 +57,15 @@ export type { BaoMfaLoginEnforcementProps } from './mfa-enforcement.ts';
50
57
  export { BaoMfaLoginEnforcement, BaoMfaLoginEnforcementProvider } from './mfa-enforcement.ts';
51
58
  export type { BaoMfaTotpMethodProps, BaoTotpAlgorithm } from './mfa-totp.ts';
52
59
  export { BaoMfaTotpMethod, BaoMfaTotpMethodProvider } from './mfa-totp.ts';
60
+ export type { BaoMountAttributes, BaoMountProps } from './mount.ts';
53
61
  export { BaoMount, BaoMountProvider } from './mount.ts';
62
+ export type { BaoPkiRoleAttributes, BaoPkiRoleProps } from './pki-role.ts';
54
63
  export { BaoPkiRole, BaoPkiRoleProvider } from './pki-role.ts';
55
- export type { BaoPluginProps, BaoPluginType } from './plugin.ts';
64
+ export type { BaoPluginAttributes, BaoPluginProps, BaoPluginType } from './plugin.ts';
56
65
  export { BaoPlugin, BaoPluginProvider } from './plugin.ts';
66
+ export type { BaoPolicyAttributes, BaoPolicyProps } from './policy.ts';
57
67
  export { BaoPolicy, BaoPolicyProvider } from './policy.ts';
68
+ export type { BaoProxmoxRoleAttributes, BaoProxmoxRoleProps } from './proxmox-role.ts';
58
69
  export { BaoProxmoxRole, BaoProxmoxRoleProvider } from './proxmox-role.ts';
70
+ export type { BaoSshRoleAttributes, BaoSshRoleProps } from './ssh-role.ts';
59
71
  export { BaoSshRole, BaoSshRoleProvider } from './ssh-role.ts';
@@ -189,6 +189,8 @@ const ops = pveOperations<AclProps, AclAttributes>({
189
189
  * the props they came from is true by construction. An identity change is a DIFFERENT grant,
190
190
  * which `diff` in the provider handles.
191
191
  */
192
+ /** The vendor rules these forms are checked against at plan time — resource-spec.ts. */
193
+ endpoint: { create: 'pve:PUT /access/acl', update: 'pve:PUT /access/acl' },
192
194
  matches: (attributes, props) =>
193
195
  attributes.bound && attributes.propagate === (props.propagate !== false),
194
196
  path: () => 'access/acl',
@@ -103,6 +103,11 @@ export const apiTokenSpec: PveSpec<ApiTokenProps, ApiTokenAttributes> = {
103
103
  */
104
104
  collection: (props) => `access/users/${props.userid}/token/${props.tokenid}`,
105
105
  createForm: shape,
106
+ /** The vendor rules both forms are checked against at plan time — resource-spec.ts. */
107
+ endpoint: {
108
+ create: 'pve:POST /access/users/{userid}/token/{tokenid}',
109
+ update: 'pve:PUT /access/users/{userid}/token/{tokenid}',
110
+ },
106
111
  /**
107
112
  * ⚠️ EXACTLY THE THREE FIELDS A PUT CAN PUT BACK, WHICH IS ALSO EXACTLY WHAT THE GET REPORTS.
108
113
  * MEASURED, by replaying these two functions over the live GET bodies of all four token
@@ -0,0 +1,34 @@
1
+ /**
2
+ * The two applies, and the vendor endpoints they publish through.
3
+ *
4
+ * ★ AN ACTION ENDPOINT IS STILL WIRED, EVEN THOUGH ITS TABLE IS EMPTY, AND THE REASON IS THE
5
+ * GENERATOR RATHER THAN THE VALIDATOR. `PUT /nodes/{node}/network` and `PUT /cluster/sdn` take
6
+ * no body at all — there is nothing for a length or a range to be wrong about — but
7
+ * `codegen/constraints.ts` RESOLVES every key named in this package against the vendor's own
8
+ * schema and STOPS when one is absent. So the key buys the thing these two families most need:
9
+ * a PVE that moves, renames or withdraws the apply fails `bun run check` instead of failing an
10
+ * `ifreload -a` on three nodes at once.
11
+ * ⚠️ AND THE LOOKUP IS NOT FREE EITHER. `constraintsFor` throws when a key has no table, so a
12
+ * checkout whose generated tables were never refreshed refuses the apply with the command to
13
+ * run rather than quietly doing nothing — the same defect `constraint-guard.ts` names.
14
+ *
15
+ * ⛔ NEITHER OF THESE IS A CREATE, AND NEITHER FAMILY HAS A `PveSpec`. Both write their own five
16
+ * handlers (an apply is not an object — see the ⛔ in each file), so they reach the shared check
17
+ * through `guardForm` by name, exactly as `pbs-datastore-endpoint.ts` does.
18
+ */
19
+ import type * as Effect from 'effect/Effect';
20
+ import { guardForm } from './constraint-guard.ts';
21
+ import type { EndpointKey } from './constraints.ts';
22
+
23
+ /** ⚠️ `{node}` is a path segment, so this really does take no form keys at all. */
24
+ export const NETWORK_APPLY_ENDPOINT: EndpointKey = 'pve:PUT /nodes/{node}/network';
25
+
26
+ /**
27
+ * ⛔ CLUSTER-WIDE. One PUT publishes every staged zone, vnet and subnet on every node; there is no
28
+ * per-object apply and no pre-apply veto. `sdn-apply.ts` is the whole argument.
29
+ */
30
+ export const SDN_APPLY_ENDPOINT: EndpointKey = 'pve:PUT /cluster/sdn';
31
+
32
+ export const guardNetworkApply: Effect.Effect<void> = guardForm(NETWORK_APPLY_ENDPOINT, {}, true);
33
+
34
+ export const guardSdnApply: Effect.Effect<void> = guardForm(SDN_APPLY_ENDPOINT, {}, true);
@@ -173,6 +173,8 @@ const handlers = pveHandlers<BackupJobProps, BackupJobAttributes>({
173
173
  /** ⛔ `id` IS SENT AND IS NOT OPTIONAL. Everything above depends on PVE not inventing one. */
174
174
  createForm: (props) => ({ ...shape(props), id: props.id }),
175
175
  /** Each line reads "not declared, or equal"; the five defaulted fields have no undeclared case. */
176
+ /** The vendor rules these forms are checked against at plan time — resource-spec.ts. */
177
+ endpoint: { create: 'pve:POST /cluster/backup', update: 'pve:PUT /cluster/backup/{id}' },
176
178
  matches: (attributes, props) =>
177
179
  attributes.schedule === props.schedule &&
178
180
  attributes.enabled === (props.enabled !== false) &&