@homeflare/alchemy 0.15.0 → 0.19.1

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 (516) 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 +1575 -0
  13. package/dist/linux/index.js.map +38 -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 +40 -0
  39. package/dist/linux/unit-lifecycle.d.ts.map +1 -0
  40. package/dist/linux/unit-preflight.d.ts +41 -0
  41. package/dist/linux/unit-preflight.d.ts.map +1 -0
  42. package/dist/linux/unit-settle.d.ts +31 -0
  43. package/dist/linux/unit-settle.d.ts.map +1 -0
  44. package/dist/linux/unit.d.ts +35 -0
  45. package/dist/linux/unit.d.ts.map +1 -0
  46. package/dist/netbox/client.d.ts +52 -0
  47. package/dist/netbox/client.d.ts.map +1 -0
  48. package/dist/netbox/constraint-guard.d.ts +26 -0
  49. package/dist/netbox/constraint-guard.d.ts.map +1 -0
  50. package/dist/netbox/constraints.d.ts +76 -0
  51. package/dist/netbox/constraints.d.ts.map +1 -0
  52. package/dist/netbox/generated/constraints/index.d.ts +19 -0
  53. package/dist/netbox/generated/constraints/index.d.ts.map +1 -0
  54. package/dist/netbox/generated/constraints/netbox-ipam.d.ts +21 -0
  55. package/dist/netbox/generated/constraints/netbox-ipam.d.ts.map +1 -0
  56. package/dist/netbox/index.d.ts +17 -0
  57. package/dist/netbox/index.d.ts.map +1 -0
  58. package/dist/netbox/index.js +331 -0
  59. package/dist/netbox/index.js.map +18 -0
  60. package/dist/netbox/prefix-form.d.ts +54 -0
  61. package/dist/netbox/prefix-form.d.ts.map +1 -0
  62. package/dist/netbox/prefix.d.ts +80 -0
  63. package/dist/netbox/prefix.d.ts.map +1 -0
  64. package/dist/netbox/resource.d.ts +94 -0
  65. package/dist/netbox/resource.d.ts.map +1 -0
  66. package/dist/netbox/values.d.ts +24 -0
  67. package/dist/netbox/values.d.ts.map +1 -0
  68. package/dist/proxmox/api-token-form.d.ts.map +1 -1
  69. package/dist/proxmox/apply-endpoints.d.ts +30 -0
  70. package/dist/proxmox/apply-endpoints.d.ts.map +1 -0
  71. package/dist/proxmox/ceph-daemon-form.d.ts +29 -1
  72. package/dist/proxmox/ceph-daemon-form.d.ts.map +1 -1
  73. package/dist/proxmox/ceph-daemon.d.ts.map +1 -1
  74. package/dist/proxmox/ceph-flag.d.ts.map +1 -1
  75. package/dist/proxmox/ceph-fs.d.ts.map +1 -1
  76. package/dist/proxmox/ceph-osd-write.d.ts +19 -0
  77. package/dist/proxmox/ceph-osd-write.d.ts.map +1 -1
  78. package/dist/proxmox/ceph-pool.d.ts.map +1 -1
  79. package/dist/proxmox/constraints.d.ts +28 -5
  80. package/dist/proxmox/constraints.d.ts.map +1 -1
  81. package/dist/proxmox/generated/constraints/index.d.ts +1 -1
  82. package/dist/proxmox/generated/constraints/index.d.ts.map +1 -1
  83. package/dist/proxmox/generated/constraints/pbs-config.d.ts +6 -1
  84. package/dist/proxmox/generated/constraints/pbs-config.d.ts.map +1 -1
  85. package/dist/proxmox/generated/constraints/pve-access.d.ts +6 -1
  86. package/dist/proxmox/generated/constraints/pve-access.d.ts.map +1 -1
  87. package/dist/proxmox/generated/constraints/pve-cluster-backup.d.ts +23 -0
  88. package/dist/proxmox/generated/constraints/pve-cluster-backup.d.ts.map +1 -0
  89. package/dist/proxmox/generated/constraints/pve-cluster-ceph.d.ts +23 -0
  90. package/dist/proxmox/generated/constraints/pve-cluster-ceph.d.ts.map +1 -0
  91. package/dist/proxmox/generated/constraints/pve-cluster-firewall.d.ts +23 -0
  92. package/dist/proxmox/generated/constraints/pve-cluster-firewall.d.ts.map +1 -0
  93. package/dist/proxmox/generated/constraints/pve-cluster-ha.d.ts +23 -0
  94. package/dist/proxmox/generated/constraints/pve-cluster-ha.d.ts.map +1 -0
  95. package/dist/proxmox/generated/constraints/pve-cluster-metrics.d.ts +23 -0
  96. package/dist/proxmox/generated/constraints/pve-cluster-metrics.d.ts.map +1 -0
  97. package/dist/proxmox/generated/constraints/pve-cluster-notifications.d.ts +23 -0
  98. package/dist/proxmox/generated/constraints/pve-cluster-notifications.d.ts.map +1 -0
  99. package/dist/proxmox/generated/constraints/pve-cluster-replication.d.ts +23 -0
  100. package/dist/proxmox/generated/constraints/pve-cluster-replication.d.ts.map +1 -0
  101. package/dist/proxmox/generated/constraints/pve-cluster-sdn.d.ts +23 -0
  102. package/dist/proxmox/generated/constraints/pve-cluster-sdn.d.ts.map +1 -0
  103. package/dist/proxmox/generated/constraints/pve-nodes-ceph.d.ts +23 -0
  104. package/dist/proxmox/generated/constraints/pve-nodes-ceph.d.ts.map +1 -0
  105. package/dist/proxmox/generated/constraints/pve-nodes-disks.d.ts +23 -0
  106. package/dist/proxmox/generated/constraints/pve-nodes-disks.d.ts.map +1 -0
  107. package/dist/proxmox/generated/constraints/pve-nodes-lxc.d.ts +23 -0
  108. package/dist/proxmox/generated/constraints/pve-nodes-lxc.d.ts.map +1 -0
  109. package/dist/proxmox/generated/constraints/pve-nodes-network.d.ts +23 -0
  110. package/dist/proxmox/generated/constraints/pve-nodes-network.d.ts.map +1 -0
  111. package/dist/proxmox/generated/constraints/pve-nodes-qemu.d.ts +23 -0
  112. package/dist/proxmox/generated/constraints/pve-nodes-qemu.d.ts.map +1 -0
  113. package/dist/proxmox/generated/constraints/pve-pools.d.ts +6 -1
  114. package/dist/proxmox/generated/constraints/pve-pools.d.ts.map +1 -1
  115. package/dist/proxmox/generated/constraints/pve-storage.d.ts +6 -1
  116. package/dist/proxmox/generated/constraints/pve-storage.d.ts.map +1 -1
  117. package/dist/proxmox/generated/pbs/access-users.d.ts +137 -0
  118. package/dist/proxmox/generated/pbs/access-users.d.ts.map +1 -0
  119. package/dist/proxmox/generated/pbs/access.d.ts +171 -0
  120. package/dist/proxmox/generated/pbs/access.d.ts.map +1 -0
  121. package/dist/proxmox/generated/pbs/admin-datastore-store.d.ts +252 -0
  122. package/dist/proxmox/generated/pbs/admin-datastore-store.d.ts.map +1 -0
  123. package/dist/proxmox/generated/pbs/admin-metrics.d.ts +147 -0
  124. package/dist/proxmox/generated/pbs/admin-metrics.d.ts.map +1 -0
  125. package/dist/proxmox/generated/pbs/admin.d.ts +217 -0
  126. package/dist/proxmox/generated/pbs/admin.d.ts.map +1 -0
  127. package/dist/proxmox/generated/pbs/backup.d.ts +114 -0
  128. package/dist/proxmox/generated/pbs/backup.d.ts.map +1 -0
  129. package/dist/proxmox/generated/pbs/config-access-pam.d.ts +218 -0
  130. package/dist/proxmox/generated/pbs/config-access-pam.d.ts.map +1 -0
  131. package/dist/proxmox/generated/pbs/config-access.d.ts +203 -0
  132. package/dist/proxmox/generated/pbs/config-access.d.ts.map +1 -0
  133. package/dist/proxmox/generated/pbs/config-datastore.d.ts +195 -0
  134. package/dist/proxmox/generated/pbs/config-datastore.d.ts.map +1 -0
  135. package/dist/proxmox/generated/pbs/config-media-pool.d.ts +207 -0
  136. package/dist/proxmox/generated/pbs/config-media-pool.d.ts.map +1 -0
  137. package/dist/proxmox/generated/pbs/config-notifications-matchers.d.ts +159 -0
  138. package/dist/proxmox/generated/pbs/config-notifications-matchers.d.ts.map +1 -0
  139. package/dist/proxmox/generated/pbs/config-notifications.d.ts +199 -0
  140. package/dist/proxmox/generated/pbs/config-notifications.d.ts.map +1 -0
  141. package/dist/proxmox/generated/pbs/config-remote.d.ts +175 -0
  142. package/dist/proxmox/generated/pbs/config-remote.d.ts.map +1 -0
  143. package/dist/proxmox/generated/pbs/config-sync.d.ts +145 -0
  144. package/dist/proxmox/generated/pbs/config-sync.d.ts.map +1 -0
  145. package/dist/proxmox/generated/pbs/config-tape.d.ts +200 -0
  146. package/dist/proxmox/generated/pbs/config-tape.d.ts.map +1 -0
  147. package/dist/proxmox/generated/pbs/config-verify.d.ts +77 -0
  148. package/dist/proxmox/generated/pbs/config-verify.d.ts.map +1 -0
  149. package/dist/proxmox/generated/pbs/config.d.ts +119 -0
  150. package/dist/proxmox/generated/pbs/config.d.ts.map +1 -0
  151. package/dist/proxmox/generated/pbs/nodes-node-dns.d.ts +178 -0
  152. package/dist/proxmox/generated/pbs/nodes-node-dns.d.ts.map +1 -0
  153. package/dist/proxmox/generated/pbs/nodes-node-services.d.ts +205 -0
  154. package/dist/proxmox/generated/pbs/nodes-node-services.d.ts.map +1 -0
  155. package/dist/proxmox/generated/pbs/nodes-node.d.ts +166 -0
  156. package/dist/proxmox/generated/pbs/nodes-node.d.ts.map +1 -0
  157. package/dist/proxmox/generated/pbs/nodes.d.ts +171 -0
  158. package/dist/proxmox/generated/pbs/nodes.d.ts.map +1 -0
  159. package/dist/proxmox/generated/pbs/ping.d.ts +18 -0
  160. package/dist/proxmox/generated/pbs/ping.d.ts.map +1 -0
  161. package/dist/proxmox/generated/pbs/pull.d.ts +37 -0
  162. package/dist/proxmox/generated/pbs/pull.d.ts.map +1 -0
  163. package/dist/proxmox/generated/pbs/push.d.ts +36 -0
  164. package/dist/proxmox/generated/pbs/push.d.ts.map +1 -0
  165. package/dist/proxmox/generated/pbs/reader.d.ts +41 -0
  166. package/dist/proxmox/generated/pbs/reader.d.ts.map +1 -0
  167. package/dist/proxmox/generated/pbs/root.d.ts +16 -0
  168. package/dist/proxmox/generated/pbs/root.d.ts.map +1 -0
  169. package/dist/proxmox/generated/pbs/status.d.ts +54 -0
  170. package/dist/proxmox/generated/pbs/status.d.ts.map +1 -0
  171. package/dist/proxmox/generated/pbs/tape-drive.d.ts +181 -0
  172. package/dist/proxmox/generated/pbs/tape-drive.d.ts.map +1 -0
  173. package/dist/proxmox/generated/pbs/tape-media.d.ts +126 -0
  174. package/dist/proxmox/generated/pbs/tape-media.d.ts.map +1 -0
  175. package/dist/proxmox/generated/pbs/tape.d.ts +90 -0
  176. package/dist/proxmox/generated/pbs/tape.d.ts.map +1 -0
  177. package/dist/proxmox/generated/pbs/version.d.ts +20 -0
  178. package/dist/proxmox/generated/pbs/version.d.ts.map +1 -0
  179. package/dist/proxmox/generated/pbs.d.ts +44 -662
  180. package/dist/proxmox/generated/pbs.d.ts.map +1 -1
  181. package/dist/proxmox/generated/pve/access-roles.d.ts +164 -0
  182. package/dist/proxmox/generated/pve/access-roles.d.ts.map +1 -0
  183. package/dist/proxmox/generated/pve/access-users.d.ts +152 -0
  184. package/dist/proxmox/generated/pve/access-users.d.ts.map +1 -0
  185. package/dist/proxmox/generated/pve/access.d.ts +221 -0
  186. package/dist/proxmox/generated/pve/access.d.ts.map +1 -0
  187. package/dist/proxmox/generated/pve/cluster-acme-plugins-id.d.ts +45 -0
  188. package/dist/proxmox/generated/pve/cluster-acme-plugins-id.d.ts.map +1 -0
  189. package/dist/proxmox/generated/pve/cluster-acme-plugins.d.ts +47 -0
  190. package/dist/proxmox/generated/pve/cluster-acme-plugins.d.ts.map +1 -0
  191. package/dist/proxmox/generated/pve/cluster-acme-tos.d.ts +240 -0
  192. package/dist/proxmox/generated/pve/cluster-acme-tos.d.ts.map +1 -0
  193. package/dist/proxmox/generated/pve/cluster-bulk-action.d.ts +200 -0
  194. package/dist/proxmox/generated/pve/cluster-bulk-action.d.ts.map +1 -0
  195. package/dist/proxmox/generated/pve/cluster-firewall-refs.d.ts +109 -0
  196. package/dist/proxmox/generated/pve/cluster-firewall-refs.d.ts.map +1 -0
  197. package/dist/proxmox/generated/pve/cluster-firewall.d.ts +225 -0
  198. package/dist/proxmox/generated/pve/cluster-firewall.d.ts.map +1 -0
  199. package/dist/proxmox/generated/pve/cluster-ha.d.ts +199 -0
  200. package/dist/proxmox/generated/pve/cluster-ha.d.ts.map +1 -0
  201. package/dist/proxmox/generated/pve/cluster-jobs.d.ts +183 -0
  202. package/dist/proxmox/generated/pve/cluster-jobs.d.ts.map +1 -0
  203. package/dist/proxmox/generated/pve/cluster-metrics.d.ts +110 -0
  204. package/dist/proxmox/generated/pve/cluster-metrics.d.ts.map +1 -0
  205. package/dist/proxmox/generated/pve/cluster-notifications-endpoints.d.ts +224 -0
  206. package/dist/proxmox/generated/pve/cluster-notifications-endpoints.d.ts.map +1 -0
  207. package/dist/proxmox/generated/pve/cluster-notifications.d.ts +91 -0
  208. package/dist/proxmox/generated/pve/cluster-notifications.d.ts.map +1 -0
  209. package/dist/proxmox/generated/pve/cluster-options.d.ts +85 -0
  210. package/dist/proxmox/generated/pve/cluster-options.d.ts.map +1 -0
  211. package/dist/proxmox/generated/pve/cluster-qemu-custom-cpu-models-cputype.d.ts +48 -0
  212. package/dist/proxmox/generated/pve/cluster-qemu-custom-cpu-models-cputype.d.ts.map +1 -0
  213. package/dist/proxmox/generated/pve/cluster-qemu-custom-cpu-models.d.ts +45 -0
  214. package/dist/proxmox/generated/pve/cluster-qemu-custom-cpu-models.d.ts.map +1 -0
  215. package/dist/proxmox/generated/pve/cluster-replication.d.ts +130 -0
  216. package/dist/proxmox/generated/pve/cluster-replication.d.ts.map +1 -0
  217. package/dist/proxmox/generated/pve/cluster-sdn-fabrics.d.ts +220 -0
  218. package/dist/proxmox/generated/pve/cluster-sdn-fabrics.d.ts.map +1 -0
  219. package/dist/proxmox/generated/pve/cluster-sdn-ipams.d.ts +229 -0
  220. package/dist/proxmox/generated/pve/cluster-sdn-ipams.d.ts.map +1 -0
  221. package/dist/proxmox/generated/pve/cluster-sdn-vnets-vnet.d.ts +229 -0
  222. package/dist/proxmox/generated/pve/cluster-sdn-vnets-vnet.d.ts.map +1 -0
  223. package/dist/proxmox/generated/pve/cluster-sdn-vnets.d.ts +51 -0
  224. package/dist/proxmox/generated/pve/cluster-sdn-vnets.d.ts.map +1 -0
  225. package/dist/proxmox/generated/pve/cluster-sdn-zones.d.ts +225 -0
  226. package/dist/proxmox/generated/pve/cluster-sdn-zones.d.ts.map +1 -0
  227. package/dist/proxmox/generated/pve/cluster-sdn.d.ts +202 -0
  228. package/dist/proxmox/generated/pve/cluster-sdn.d.ts.map +1 -0
  229. package/dist/proxmox/generated/pve/cluster.d.ts +69 -0
  230. package/dist/proxmox/generated/pve/cluster.d.ts.map +1 -0
  231. package/dist/proxmox/generated/pve/nodes-node-ceph.d.ts +167 -0
  232. package/dist/proxmox/generated/pve/nodes-node-ceph.d.ts.map +1 -0
  233. package/dist/proxmox/generated/pve/nodes-node-config.d.ts +43 -0
  234. package/dist/proxmox/generated/pve/nodes-node-config.d.ts.map +1 -0
  235. package/dist/proxmox/generated/pve/nodes-node-disks.d.ts +225 -0
  236. package/dist/proxmox/generated/pve/nodes-node-disks.d.ts.map +1 -0
  237. package/dist/proxmox/generated/pve/nodes-node-firewall.d.ts +145 -0
  238. package/dist/proxmox/generated/pve/nodes-node-firewall.d.ts.map +1 -0
  239. package/dist/proxmox/generated/pve/nodes-node-hardware.d.ts +195 -0
  240. package/dist/proxmox/generated/pve/nodes-node-hardware.d.ts.map +1 -0
  241. package/dist/proxmox/generated/pve/nodes-node-lxc-vmid-firewall.d.ts +191 -0
  242. package/dist/proxmox/generated/pve/nodes-node-lxc-vmid-firewall.d.ts.map +1 -0
  243. package/dist/proxmox/generated/pve/nodes-node-lxc-vmid-move-volume.d.ts +33 -0
  244. package/dist/proxmox/generated/pve/nodes-node-lxc-vmid-move-volume.d.ts.map +1 -0
  245. package/dist/proxmox/generated/pve/nodes-node-lxc-vmid-mtunnel.d.ts +56 -0
  246. package/dist/proxmox/generated/pve/nodes-node-lxc-vmid-mtunnel.d.ts.map +1 -0
  247. package/dist/proxmox/generated/pve/nodes-node-lxc-vmid-resize.d.ts +28 -0
  248. package/dist/proxmox/generated/pve/nodes-node-lxc-vmid-resize.d.ts.map +1 -0
  249. package/dist/proxmox/generated/pve/nodes-node-lxc-vmid-rrd.d.ts +186 -0
  250. package/dist/proxmox/generated/pve/nodes-node-lxc-vmid-rrd.d.ts.map +1 -0
  251. package/dist/proxmox/generated/pve/nodes-node-lxc-vmid.d.ts +191 -0
  252. package/dist/proxmox/generated/pve/nodes-node-lxc-vmid.d.ts.map +1 -0
  253. package/dist/proxmox/generated/pve/nodes-node-network.d.ts +150 -0
  254. package/dist/proxmox/generated/pve/nodes-node-network.d.ts.map +1 -0
  255. package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-config.d.ts +301 -0
  256. package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-config.d.ts.map +1 -0
  257. package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-dbus-vmstate.d.ts +170 -0
  258. package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-dbus-vmstate.d.ts.map +1 -0
  259. package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-firewall-rules.d.ts +144 -0
  260. package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-firewall-rules.d.ts.map +1 -0
  261. package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-move-disk.d.ts +34 -0
  262. package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-move-disk.d.ts.map +1 -0
  263. package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-mtunnel.d.ts +137 -0
  264. package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-mtunnel.d.ts.map +1 -0
  265. package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-status.d.ts +179 -0
  266. package/dist/proxmox/generated/pve/nodes-node-qemu-vmid-status.d.ts.map +1 -0
  267. package/dist/proxmox/generated/pve/nodes-node-qemu-vmid.d.ts +143 -0
  268. package/dist/proxmox/generated/pve/nodes-node-qemu-vmid.d.ts.map +1 -0
  269. package/dist/proxmox/generated/pve/nodes-node-qemu.d.ts +158 -0
  270. package/dist/proxmox/generated/pve/nodes-node-qemu.d.ts.map +1 -0
  271. package/dist/proxmox/generated/pve/nodes-node-replication.d.ts +187 -0
  272. package/dist/proxmox/generated/pve/nodes-node-replication.d.ts.map +1 -0
  273. package/dist/proxmox/generated/pve/nodes-node-services.d.ts +115 -0
  274. package/dist/proxmox/generated/pve/nodes-node-services.d.ts.map +1 -0
  275. package/dist/proxmox/generated/pve/nodes-node-storage-storage.d.ts +202 -0
  276. package/dist/proxmox/generated/pve/nodes-node-storage-storage.d.ts.map +1 -0
  277. package/dist/proxmox/generated/pve/nodes-node-storage.d.ts +40 -0
  278. package/dist/proxmox/generated/pve/nodes-node-storage.d.ts.map +1 -0
  279. package/dist/proxmox/generated/pve/nodes-node-subscription.d.ts +173 -0
  280. package/dist/proxmox/generated/pve/nodes-node-subscription.d.ts.map +1 -0
  281. package/dist/proxmox/generated/pve/nodes-node-vzdump.d.ts +97 -0
  282. package/dist/proxmox/generated/pve/nodes-node-vzdump.d.ts.map +1 -0
  283. package/dist/proxmox/generated/pve/nodes-node.d.ts +207 -0
  284. package/dist/proxmox/generated/pve/nodes-node.d.ts.map +1 -0
  285. package/dist/proxmox/generated/pve/nodes.d.ts +236 -0
  286. package/dist/proxmox/generated/pve/nodes.d.ts.map +1 -0
  287. package/dist/proxmox/generated/pve/pools.d.ts +82 -0
  288. package/dist/proxmox/generated/pve/pools.d.ts.map +1 -0
  289. package/dist/proxmox/generated/pve/storage.d.ts +159 -0
  290. package/dist/proxmox/generated/pve/storage.d.ts.map +1 -0
  291. package/dist/proxmox/generated/pve/version.d.ts +21 -0
  292. package/dist/proxmox/generated/pve/version.d.ts.map +1 -0
  293. package/dist/proxmox/generated/pve.d.ts +69 -4766
  294. package/dist/proxmox/generated/pve.d.ts.map +1 -1
  295. package/dist/proxmox/index.js +996 -372
  296. package/dist/proxmox/index.js.map +48 -32
  297. package/dist/proxmox/lxc-lifecycle.d.ts.map +1 -1
  298. package/dist/proxmox/metric-server-form.d.ts +11 -0
  299. package/dist/proxmox/metric-server-form.d.ts.map +1 -1
  300. package/dist/proxmox/metric-server.d.ts.map +1 -1
  301. package/dist/proxmox/network-apply.d.ts.map +1 -1
  302. package/dist/proxmox/node-network-form.d.ts +15 -0
  303. package/dist/proxmox/node-network-form.d.ts.map +1 -1
  304. package/dist/proxmox/node-network.d.ts.map +1 -1
  305. package/dist/proxmox/notification-target-endpoint.d.ts +26 -0
  306. package/dist/proxmox/notification-target-endpoint.d.ts.map +1 -0
  307. package/dist/proxmox/notification-target-form.d.ts +7 -0
  308. package/dist/proxmox/notification-target-form.d.ts.map +1 -1
  309. package/dist/proxmox/notification-target.d.ts.map +1 -1
  310. package/dist/proxmox/pbs-notification-target-endpoint.d.ts +29 -0
  311. package/dist/proxmox/pbs-notification-target-endpoint.d.ts.map +1 -0
  312. package/dist/proxmox/pbs-notification-target-lifecycle.d.ts.map +1 -1
  313. package/dist/proxmox/qemu.d.ts +10 -0
  314. package/dist/proxmox/qemu.d.ts.map +1 -1
  315. package/dist/proxmox/resource-guard.d.ts +15 -0
  316. package/dist/proxmox/resource-guard.d.ts.map +1 -0
  317. package/dist/proxmox/resource-spec.d.ts +15 -4
  318. package/dist/proxmox/resource-spec.d.ts.map +1 -1
  319. package/dist/proxmox/resource.d.ts +8 -0
  320. package/dist/proxmox/resource.d.ts.map +1 -1
  321. package/dist/proxmox/sdn-apply.d.ts.map +1 -1
  322. package/dist/proxmox/sdn-subnet.d.ts.map +1 -1
  323. package/dist/proxmox/zfs-pool-write.d.ts +11 -0
  324. package/dist/proxmox/zfs-pool-write.d.ts.map +1 -1
  325. package/dist/proxmox/zfs-pool.d.ts.map +1 -1
  326. package/docs/linux-host-measured.md +56 -0
  327. package/docs/linux-host.md +192 -0
  328. package/docs/netbox.md +103 -0
  329. package/package.json +9 -1
  330. package/src/linux/directory-lifecycle.ts +220 -0
  331. package/src/linux/directory.test.ts +132 -0
  332. package/src/linux/directory.ts +71 -0
  333. package/src/linux/fake-linux-host.ts +197 -0
  334. package/src/linux/fake-systemd.ts +103 -0
  335. package/src/linux/index.ts +32 -0
  336. package/src/linux/providers.ts +26 -0
  337. package/src/linux/region.test.ts +89 -0
  338. package/src/linux/region.ts +118 -0
  339. package/src/linux/remote-file-form.ts +96 -0
  340. package/src/linux/remote-file-lifecycle.test.ts +191 -0
  341. package/src/linux/remote-file-lifecycle.ts +161 -0
  342. package/src/linux/remote-file-plan.ts +154 -0
  343. package/src/linux/remote-file.ts +88 -0
  344. package/src/linux/ssh-command.test.ts +140 -0
  345. package/src/linux/ssh-command.ts +99 -0
  346. package/src/linux/ssh-runner.ts +188 -0
  347. package/src/linux/ssh-scripts.ts +105 -0
  348. package/src/linux/systemctl.ts +145 -0
  349. package/src/linux/unit-form.ts +183 -0
  350. package/src/linux/unit-handlers.ts +73 -0
  351. package/src/linux/unit-lifecycle.test.ts +220 -0
  352. package/src/linux/unit-lifecycle.ts +175 -0
  353. package/src/linux/unit-preflight.test.ts +128 -0
  354. package/src/linux/unit-preflight.ts +100 -0
  355. package/src/linux/unit-settle.ts +110 -0
  356. package/src/linux/unit.ts +81 -0
  357. package/src/netbox/client.test.ts +67 -0
  358. package/src/netbox/client.ts +146 -0
  359. package/src/netbox/constraint-guard.ts +57 -0
  360. package/src/netbox/constraints.test.ts +114 -0
  361. package/src/netbox/constraints.ts +152 -0
  362. package/src/netbox/generated/constraints/index.ts +23 -0
  363. package/src/netbox/generated/constraints/netbox-ipam.ts +32 -0
  364. package/src/netbox/index.ts +34 -0
  365. package/src/netbox/prefix-form.test.ts +127 -0
  366. package/src/netbox/prefix-form.ts +84 -0
  367. package/src/netbox/prefix.ts +136 -0
  368. package/src/netbox/resource.ts +208 -0
  369. package/src/netbox/values.test.ts +66 -0
  370. package/src/netbox/values.ts +40 -0
  371. package/src/proxmox/api-token-form.ts +5 -0
  372. package/src/proxmox/apply-endpoints.ts +34 -0
  373. package/src/proxmox/ceph-daemon-form.ts +56 -2
  374. package/src/proxmox/ceph-daemon.ts +10 -21
  375. package/src/proxmox/ceph-flag.ts +1 -0
  376. package/src/proxmox/ceph-fs.ts +1 -0
  377. package/src/proxmox/ceph-osd-write.ts +30 -4
  378. package/src/proxmox/ceph-pool.ts +10 -0
  379. package/src/proxmox/constraints-dialect.test.ts +165 -0
  380. package/src/proxmox/constraints-forms.test.ts +228 -0
  381. package/src/proxmox/constraints-host-forms.test.ts +132 -0
  382. package/src/proxmox/constraints-live.test.ts +155 -0
  383. package/src/proxmox/constraints-node-forms.test.ts +197 -0
  384. package/src/proxmox/constraints-required.test.ts +172 -0
  385. package/src/proxmox/constraints.test.ts +8 -63
  386. package/src/proxmox/constraints.ts +31 -6
  387. package/src/proxmox/generated/constraints/index.ts +27 -3
  388. package/src/proxmox/generated/constraints/pbs-config.ts +63 -1
  389. package/src/proxmox/generated/constraints/pve-access.ts +15 -3
  390. package/src/proxmox/generated/constraints/pve-cluster-backup.ts +74 -0
  391. package/src/proxmox/generated/constraints/pve-cluster-ceph.ts +27 -0
  392. package/src/proxmox/generated/constraints/pve-cluster-firewall.ts +35 -0
  393. package/src/proxmox/generated/constraints/pve-cluster-ha.ts +55 -0
  394. package/src/proxmox/generated/constraints/pve-cluster-metrics.ts +59 -0
  395. package/src/proxmox/generated/constraints/pve-cluster-notifications.ts +80 -0
  396. package/src/proxmox/generated/constraints/pve-cluster-replication.ts +43 -0
  397. package/src/proxmox/generated/constraints/pve-cluster-sdn.ts +90 -0
  398. package/src/proxmox/generated/constraints/pve-nodes-ceph.ts +57 -0
  399. package/src/proxmox/generated/constraints/pve-nodes-disks.ts +31 -0
  400. package/src/proxmox/generated/constraints/pve-nodes-lxc.ts +82 -0
  401. package/src/proxmox/generated/constraints/pve-nodes-network.ts +77 -0
  402. package/src/proxmox/generated/constraints/pve-nodes-qemu.ts +125 -0
  403. package/src/proxmox/generated/constraints/pve-pools.ts +6 -1
  404. package/src/proxmox/generated/constraints/pve-storage.ts +8 -3
  405. package/src/proxmox/generated/pbs/access-users.ts +137 -0
  406. package/src/proxmox/generated/pbs/access.ts +232 -0
  407. package/src/proxmox/generated/pbs/admin-datastore-store.ts +238 -0
  408. package/src/proxmox/generated/pbs/admin-metrics.ts +147 -0
  409. package/src/proxmox/generated/pbs/admin.ts +225 -0
  410. package/src/proxmox/generated/pbs/backup.ts +121 -0
  411. package/src/proxmox/generated/pbs/config-access-pam.ts +228 -0
  412. package/src/proxmox/generated/pbs/config-access.ts +228 -0
  413. package/src/proxmox/generated/pbs/config-datastore.ts +217 -0
  414. package/src/proxmox/generated/pbs/config-media-pool.ts +232 -0
  415. package/src/proxmox/generated/pbs/config-notifications-matchers.ts +187 -0
  416. package/src/proxmox/generated/pbs/config-notifications.ts +221 -0
  417. package/src/proxmox/generated/pbs/config-remote.ts +192 -0
  418. package/src/proxmox/generated/pbs/config-sync.ts +167 -0
  419. package/src/proxmox/generated/pbs/config-tape.ts +226 -0
  420. package/src/proxmox/generated/pbs/config-verify.ts +87 -0
  421. package/src/proxmox/generated/pbs/config.ts +135 -0
  422. package/src/proxmox/generated/pbs/nodes-node-dns.ts +229 -0
  423. package/src/proxmox/generated/pbs/nodes-node-services.ts +181 -0
  424. package/src/proxmox/generated/pbs/nodes-node.ts +244 -0
  425. package/src/proxmox/generated/pbs/nodes.ts +160 -0
  426. package/src/proxmox/generated/pbs/ping.ts +16 -0
  427. package/src/proxmox/generated/pbs/pull.ts +37 -0
  428. package/src/proxmox/generated/pbs/push.ts +36 -0
  429. package/src/proxmox/generated/pbs/reader.ts +41 -0
  430. package/src/proxmox/generated/pbs/root.ts +16 -0
  431. package/src/proxmox/generated/pbs/status.ts +50 -0
  432. package/src/proxmox/generated/pbs/tape-drive.ts +220 -0
  433. package/src/proxmox/generated/pbs/tape-media.ts +133 -0
  434. package/src/proxmox/generated/pbs/tape.ts +92 -0
  435. package/src/proxmox/generated/pbs/version.ts +16 -0
  436. package/src/proxmox/generated/pbs.ts +44 -787
  437. package/src/proxmox/generated/pve/access-roles.ts +168 -0
  438. package/src/proxmox/generated/pve/access-users.ts +155 -0
  439. package/src/proxmox/generated/pve/access.ts +217 -0
  440. package/src/proxmox/generated/pve/cluster-acme-plugins-id.ts +367 -0
  441. package/src/proxmox/generated/pve/cluster-acme-plugins.ts +366 -0
  442. package/src/proxmox/generated/pve/cluster-acme-tos.ts +232 -0
  443. package/src/proxmox/generated/pve/cluster-bulk-action.ts +227 -0
  444. package/src/proxmox/generated/pve/cluster-firewall-refs.ts +110 -0
  445. package/src/proxmox/generated/pve/cluster-firewall.ts +236 -0
  446. package/src/proxmox/generated/pve/cluster-ha.ts +203 -0
  447. package/src/proxmox/generated/pve/cluster-jobs.ts +190 -0
  448. package/src/proxmox/generated/pve/cluster-metrics.ts +116 -0
  449. package/src/proxmox/generated/pve/cluster-notifications-endpoints.ts +244 -0
  450. package/src/proxmox/generated/pve/cluster-notifications.ts +99 -0
  451. package/src/proxmox/generated/pve/cluster-options.ts +189 -0
  452. package/src/proxmox/generated/pve/cluster-qemu-custom-cpu-models-cputype.ts +272 -0
  453. package/src/proxmox/generated/pve/cluster-qemu-custom-cpu-models.ts +268 -0
  454. package/src/proxmox/generated/pve/cluster-replication.ts +127 -0
  455. package/src/proxmox/generated/pve/cluster-sdn-fabrics.ts +218 -0
  456. package/src/proxmox/generated/pve/cluster-sdn-ipams.ts +229 -0
  457. package/src/proxmox/generated/pve/cluster-sdn-vnets-vnet.ts +245 -0
  458. package/src/proxmox/generated/pve/cluster-sdn-vnets.ts +49 -0
  459. package/src/proxmox/generated/pve/cluster-sdn-zones.ts +224 -0
  460. package/src/proxmox/generated/pve/cluster-sdn.ts +201 -0
  461. package/src/proxmox/generated/pve/cluster.ts +71 -0
  462. package/src/proxmox/generated/pve/nodes-node-ceph.ts +167 -0
  463. package/src/proxmox/generated/pve/nodes-node-config.ts +56 -0
  464. package/src/proxmox/generated/pve/nodes-node-disks.ts +237 -0
  465. package/src/proxmox/generated/pve/nodes-node-firewall.ts +239 -0
  466. package/src/proxmox/generated/pve/nodes-node-hardware.ts +215 -0
  467. package/src/proxmox/generated/pve/nodes-node-lxc-vmid-firewall.ts +232 -0
  468. package/src/proxmox/generated/pve/nodes-node-lxc-vmid-move-volume.ts +1059 -0
  469. package/src/proxmox/generated/pve/nodes-node-lxc-vmid-mtunnel.ts +49 -0
  470. package/src/proxmox/generated/pve/nodes-node-lxc-vmid-resize.ts +285 -0
  471. package/src/proxmox/generated/pve/nodes-node-lxc-vmid-rrd.ts +184 -0
  472. package/src/proxmox/generated/pve/nodes-node-lxc-vmid.ts +240 -0
  473. package/src/proxmox/generated/pve/nodes-node-network.ts +234 -0
  474. package/src/proxmox/generated/pve/nodes-node-qemu-vmid-config.ts +441 -0
  475. package/src/proxmox/generated/pve/nodes-node-qemu-vmid-dbus-vmstate.ts +215 -0
  476. package/src/proxmox/generated/pve/nodes-node-qemu-vmid-firewall-rules.ts +145 -0
  477. package/src/proxmox/generated/pve/nodes-node-qemu-vmid-move-disk.ts +664 -0
  478. package/src/proxmox/generated/pve/nodes-node-qemu-vmid-mtunnel.ts +188 -0
  479. package/src/proxmox/generated/pve/nodes-node-qemu-vmid-status.ts +233 -0
  480. package/src/proxmox/generated/pve/nodes-node-qemu-vmid.ts +187 -0
  481. package/src/proxmox/generated/pve/nodes-node-qemu.ts +204 -0
  482. package/src/proxmox/generated/pve/nodes-node-replication.ts +187 -0
  483. package/src/proxmox/generated/pve/nodes-node-services.ts +221 -0
  484. package/src/proxmox/generated/pve/nodes-node-storage-storage.ts +226 -0
  485. package/src/proxmox/generated/pve/nodes-node-storage.ts +40 -0
  486. package/src/proxmox/generated/pve/nodes-node-subscription.ts +168 -0
  487. package/src/proxmox/generated/pve/nodes-node-vzdump.ts +96 -0
  488. package/src/proxmox/generated/pve/nodes-node.ts +211 -0
  489. package/src/proxmox/generated/pve/nodes.ts +235 -0
  490. package/src/proxmox/generated/pve/pools.ts +78 -0
  491. package/src/proxmox/generated/pve/storage.ts +213 -0
  492. package/src/proxmox/generated/pve/version.ts +21 -0
  493. package/src/proxmox/generated/pve.ts +69 -7403
  494. package/src/proxmox/lxc-interior.test.ts +17 -1
  495. package/src/proxmox/lxc-lifecycle.ts +48 -9
  496. package/src/proxmox/metric-server-form.ts +10 -0
  497. package/src/proxmox/metric-server.ts +11 -2
  498. package/src/proxmox/network-apply.ts +4 -0
  499. package/src/proxmox/node-network-form.ts +19 -0
  500. package/src/proxmox/node-network.ts +9 -3
  501. package/src/proxmox/notification-target-endpoint.ts +46 -0
  502. package/src/proxmox/notification-target-form.ts +11 -0
  503. package/src/proxmox/notification-target.ts +5 -2
  504. package/src/proxmox/pbs-notification-target-endpoint.ts +45 -0
  505. package/src/proxmox/pbs-notification-target-lifecycle.ts +16 -14
  506. package/src/proxmox/qemu.ts +9 -1
  507. package/src/proxmox/resource-guard.ts +61 -0
  508. package/src/proxmox/resource-spec.ts +16 -4
  509. package/src/proxmox/resource.ts +27 -27
  510. package/src/proxmox/sdn-apply.ts +4 -0
  511. package/src/proxmox/sdn-subnet.ts +5 -0
  512. package/src/proxmox/zfs-pool-write.ts +12 -0
  513. package/src/proxmox/zfs-pool.ts +2 -1
  514. package/dist/proxmox/generated/constraints/pve-cluster.d.ts +0 -18
  515. package/dist/proxmox/generated/constraints/pve-cluster.d.ts.map +0 -1
  516. package/src/proxmox/generated/constraints/pve-cluster.ts +0 -174
@@ -0,0 +1,146 @@
1
+ /**
2
+ * One authenticated call to the NetBox REST API at `/api`.
3
+ *
4
+ * ⚠️ `Authorization: Token <value>`, NOT `Bearer`. NetBox is Django REST Framework using DRF's own
5
+ * `TokenAuthentication`. MEASURED on this estate's own instance while it was up: `Bearer`
6
+ * returns 401 and `Token` returns 200. ⛔ A wrong scheme and a wrong credential are
7
+ * indistinguishable in the response, which is why this is written down rather than inferred.
8
+ *
9
+ * ⚠️ NETBOX DOES NOT WRAP A DETAIL RESPONSE THE WAY PVE DOES — a GET of one object returns the
10
+ * object. A LIST, however, IS wrapped: `{count, next, previous, results: [...]}`. A caller that
11
+ * treats a list like a detail sees `undefined` and calls a healthy object absent, which plans a
12
+ * create over something that already exists.
13
+ *
14
+ * ⛔ THE TOKEN IS NEVER A PROP. It is read from `NETBOX_TOKEN` at call time only. Alchemy persists
15
+ * attributes unencrypted; nothing stored here may be a credential.
16
+ */
17
+ import * as Effect from 'effect/Effect';
18
+ import * as HttpClient from 'effect/unstable/http/HttpClient';
19
+ import * as HttpClientRequest from 'effect/unstable/http/HttpClientRequest';
20
+
21
+ const PATH_PREFIX = '/api';
22
+
23
+ /**
24
+ * The instance, from `NETBOX_URL`. Trailing slash stripped.
25
+ *
26
+ * ⛔ NO DEFAULT HOSTNAME AND NO DEFAULT PORT. A published package that fell back to a loopback
27
+ * address would let a consumer who forgot the variable watch every call fail against a machine
28
+ * that is not theirs, instead of being told which variable is missing.
29
+ * ⚠️ Read at CALL time, never at module scope — a value captured at import is pinned to whatever
30
+ * the first isolate saw.
31
+ */
32
+ export const apiBase = (): string => {
33
+ const raw = process.env['NETBOX_URL'];
34
+ if (raw === undefined || raw.trim() === '') {
35
+ throw new Error(
36
+ 'NETBOX_URL is not set. Point it at your NetBox instance, e.g. https://netbox.example.com',
37
+ );
38
+ }
39
+ return raw.trim().replace(/\/$/, '');
40
+ };
41
+
42
+ export class NetboxError extends Error {
43
+ constructor(
44
+ readonly status: number,
45
+ readonly method: string,
46
+ readonly path: string,
47
+ detail: string,
48
+ ) {
49
+ super(`NetBox ${method} ${path} -> ${String(status)}: ${detail}`);
50
+ this.name = 'NetboxError';
51
+ }
52
+ }
53
+
54
+ const token = (): Effect.Effect<string, NetboxError> =>
55
+ Effect.gen(function* () {
56
+ const raw = process.env['NETBOX_TOKEN'];
57
+ if (raw === undefined || raw.trim() === '') {
58
+ return yield* Effect.fail(
59
+ new NetboxError(
60
+ 0,
61
+ 'GET',
62
+ '',
63
+ 'NETBOX_TOKEN is unset. Mint a scoped token and export it — never store it in Alchemy props.',
64
+ ),
65
+ );
66
+ }
67
+ return raw.trim();
68
+ });
69
+
70
+ /** A NetBox list response. ⚠️ Paginated: `next` is a URL, not a cursor to guess at. */
71
+ export interface NetboxList<T> {
72
+ readonly count: number;
73
+ readonly next: string | null;
74
+ readonly results: readonly T[];
75
+ }
76
+
77
+ export type NetboxRow = Record<string, unknown>;
78
+
79
+ /** One JSON call. Returns the parsed body, or `undefined` when the response is empty (DELETE). */
80
+ export const netbox = <T>(
81
+ method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE',
82
+ path: string,
83
+ body?: Record<string, unknown>,
84
+ ) =>
85
+ Effect.gen(function* () {
86
+ const credential = yield* token();
87
+ const url = `${apiBase()}${PATH_PREFIX}/${path.replace(/^\//, '')}`;
88
+ /**
89
+ * ★ THROUGH `HttpClient`, NOT THE GLOBAL `fetch` — the idiom Alchemy's own providers follow.
90
+ * It buys a typed error channel, interruption when a plan is cancelled, the runtime's
91
+ * tracing, and a client a test can replace without monkey-patching a global.
92
+ */
93
+ const client = yield* HttpClient.HttpClient;
94
+ /**
95
+ * ⛔ THE CONTENT TYPE GOES ON `bodyText`, NOT IN THE HEADER MAP. `bodyText(s)` with no second
96
+ * argument sets `text/plain` and OVERWRITES a `Content-Type` set by `setHeaders`, because it
97
+ * is piped afterwards. That shipped `@homeflare/alchemy/forgejo` unable to write at all —
98
+ * every create and update in the package, broken identically, for as long as the only
99
+ * credential on the shelf was read-only and so never reached a request body.
100
+ */
101
+ const request = HttpClientRequest.make(method)(url).pipe(
102
+ HttpClientRequest.setHeaders({
103
+ Accept: 'application/json',
104
+ Authorization: `Token ${credential}`,
105
+ }),
106
+ body === undefined
107
+ ? (self) => self
108
+ : HttpClientRequest.bodyText(JSON.stringify(body), 'application/json'),
109
+ );
110
+ const response = yield* client
111
+ .execute(request)
112
+ .pipe(Effect.mapError((cause) => new NetboxError(0, method, path, String(cause))));
113
+ // ⛔ Status first, body once — a NetBox error body is JSON but a reverse proxy's 502 is not.
114
+ // ⚠️ AND A 502 IS THE EXPECTED SYMPTOM WHEN NETBOX IS DOWN BUT ITS FRONT DOOR IS UP, which
115
+ // is the state the reference instance has been in since 2026-09-14. Folding it to "absent"
116
+ // would plan a create for every object that already exists.
117
+ if (response.status < 200 || response.status >= 300) {
118
+ const detail = yield* response.text.pipe(Effect.orElseSucceed(() => ''));
119
+ return yield* Effect.fail(
120
+ new NetboxError(response.status, method, path, detail.slice(0, 300)),
121
+ );
122
+ }
123
+ // ⚠️ 204 AND AN EMPTY BODY ARE REAL: a DELETE answers no content, and parsing an empty body
124
+ // throws. Read the text once and parse only when there is something to parse.
125
+ const text = yield* response.text.pipe(
126
+ Effect.mapError((cause) => new NetboxError(0, method, path, String(cause))),
127
+ );
128
+ return (text === '' ? undefined : JSON.parse(text)) as T;
129
+ });
130
+
131
+ /**
132
+ * The single row a filtered list returns, or `undefined`.
133
+ *
134
+ * ⛔ MORE THAN ONE MATCH IS A DEFECT, NOT A REASON TO TAKE THE FIRST. A `locate` filter that is
135
+ * not unique would let adopt bind to whichever row NetBox happened to order first, and the next
136
+ * plan would bind to the other one and report drift that is not there.
137
+ */
138
+ export const soleMatch = <T>(rows: readonly T[], describe: string): T | undefined => {
139
+ if (rows.length > 1) {
140
+ throw new Error(
141
+ `${describe} matched ${String(rows.length)} NetBox objects. An object's identity must be ` +
142
+ 'unique; narrow it (the VRF, the site, the tenant) rather than taking the first row.',
143
+ );
144
+ }
145
+ return rows[0];
146
+ };
@@ -0,0 +1,57 @@
1
+ /**
2
+ * The generated tables, looked up by endpoint, and the refusal that stops a plan.
3
+ *
4
+ * ★ ONE FILE BETWEEN THE PROVIDERS AND THE GENERATED DATA, so `resource.ts` gains three lines
5
+ * rather than an import of the generated module and a merge, and so a family that writes its
6
+ * own handlers reaches the same check by the same name.
7
+ *
8
+ * ⛔ AN UNKNOWN KEY IS A DEFECT, NOT A REASON TO SKIP THE CHECK. Silently passing would put us
9
+ * back where this started: a declaration nothing checked, and a plan that says so in no way at
10
+ * all. The generator resolves every key in its source scan against the vendor document, so a
11
+ * key that is absent here means the tables were not regenerated — which the message says.
12
+ */
13
+ import * as Effect from 'effect/Effect';
14
+ import {
15
+ type EndpointConstraints,
16
+ type EndpointKey,
17
+ type NetboxBody,
18
+ refusal,
19
+ violations,
20
+ } from './constraints.ts';
21
+ import { NETBOX_CONSTRAINTS } from './generated/constraints/index.ts';
22
+
23
+ export { NETBOX_CONSTRAINTS };
24
+
25
+ export const constraintsFor = (key: EndpointKey): EndpointConstraints => {
26
+ const table = NETBOX_CONSTRAINTS[key];
27
+ if (table === undefined) {
28
+ throw new Error(
29
+ `no vendor constraint table for '${key}'. It is named in this package but not generated: ` +
30
+ 'run `bun codegen/netbox.ts` (see codegen/README.md).',
31
+ );
32
+ }
33
+ return table;
34
+ };
35
+
36
+ /** Every vendor rule this body breaks. Pure — a test calls it with a literal body. */
37
+ export const bodyViolations = (
38
+ key: EndpointKey,
39
+ body: NetboxBody,
40
+ presence: boolean,
41
+ ): readonly string[] => violations(constraintsFor(key), body, { presence });
42
+
43
+ /**
44
+ * ⛔ `Effect.die`, NOT `Effect.fail`. A declaration the vendor would reject is a DEFECT in the
45
+ * stack file, not a recoverable condition: there is no retry and no fallback that makes a
46
+ * 201-character description legal.
47
+ */
48
+ export const guardBody = (
49
+ key: EndpointKey | undefined,
50
+ body: NetboxBody,
51
+ presence: boolean,
52
+ ): Effect.Effect<void> =>
53
+ Effect.suspend(() => {
54
+ if (key === undefined) return Effect.void;
55
+ const found = bodyViolations(key, body, presence);
56
+ return found.length === 0 ? Effect.void : Effect.die(new Error(refusal(key, found)));
57
+ });
@@ -0,0 +1,114 @@
1
+ /**
2
+ * The constraint reader over a JSON body — and the four ways a naive one gets it wrong.
3
+ *
4
+ * ★ EVERY RULE EXERCISED HERE COMES FROM THE GENERATED TABLE, not a literal invented in this
5
+ * file, wherever a real endpoint states it. A test that made up its own `maxLength` would pass
6
+ * forever while the committed table said something else.
7
+ */
8
+ import { describe, expect, test } from 'bun:test';
9
+ import { bodyViolations, constraintsFor } from './constraint-guard.ts';
10
+ import { violations } from './constraints.ts';
11
+
12
+ const CREATE = 'netbox:POST /api/ipam/prefixes/';
13
+ const UPDATE = 'netbox:PATCH /api/ipam/prefixes/{id}/';
14
+
15
+ describe('the generated table is the one being read', () => {
16
+ test('the prefix create table carries NetBox 4.7.0 own rules', () => {
17
+ const table = constraintsFor(CREATE);
18
+ expect(table['prefix']?.required).toBe(true);
19
+ expect(table['description']?.maxLength).toBe(200);
20
+ expect(table['status']?.enum).toEqual(['container', 'active', 'reserved', 'deprecated']);
21
+ });
22
+
23
+ /** ⛔ An unknown key is a defect: the tables were not regenerated, and silence would hide it. */
24
+ test('an endpoint nobody generated throws rather than passing everything', () => {
25
+ expect(() => constraintsFor('netbox:POST /api/dcim/devices/')).toThrow(
26
+ /no vendor constraint table/,
27
+ );
28
+ });
29
+ });
30
+
31
+ describe('what it refuses', () => {
32
+ test('a description one character over the vendor limit', () => {
33
+ const found = bodyViolations(
34
+ CREATE,
35
+ { description: 'x'.repeat(201), prefix: '10.0.0.0/24' },
36
+ true,
37
+ );
38
+ expect(found).toEqual(['description: at most 200 characters']);
39
+ });
40
+
41
+ test('exactly the limit is accepted', () => {
42
+ expect(
43
+ bodyViolations(CREATE, { description: 'x'.repeat(200), prefix: '10.0.0.0/24' }, true),
44
+ ).toEqual([]);
45
+ });
46
+
47
+ /**
48
+ * ⚠️ `[...value].length`, NOT `value.length`. An emoji is two UTF-16 code units and ONE
49
+ * character; Django counts characters. Counting code units would refuse a description NetBox
50
+ * accepts — rejecting a legal value at plan time being the failure worse than the 400.
51
+ */
52
+ test('a 200-character description made of astral characters is accepted', () => {
53
+ const found = bodyViolations(
54
+ CREATE,
55
+ { description: '🌐'.repeat(200), prefix: '10.0.0.0/24' },
56
+ true,
57
+ );
58
+ expect(found).toEqual([]);
59
+ });
60
+
61
+ test('a status outside the vendor enum', () => {
62
+ const found = bodyViolations(CREATE, { prefix: '10.0.0.0/24', status: 'retired' }, true);
63
+ expect(found).toEqual(['status: must be one of container, active, reserved, deprecated']);
64
+ });
65
+ });
66
+
67
+ describe('presence is a create-only rule', () => {
68
+ /** ⛔ A PATCH is deliberately partial; requiring presence would refuse every ordinary edit. */
69
+ test('a missing required property is refused on create and allowed on update', () => {
70
+ expect(bodyViolations(CREATE, { status: 'active' }, true)).toEqual(['prefix: required']);
71
+ expect(bodyViolations(UPDATE, { status: 'active' }, false)).toEqual([]);
72
+ });
73
+
74
+ /**
75
+ * ⚠️ `null` IS A VALUE, NOT AN ABSENCE. NetBox clears a nullable foreign key with an explicit
76
+ * null, so a presence check that used `value === undefined` would call it missing.
77
+ */
78
+ test('an explicit null satisfies presence and trips no string rule', () => {
79
+ expect(bodyViolations(CREATE, { prefix: null }, true)).toEqual([]);
80
+ });
81
+ });
82
+
83
+ describe('a JSON body is not a form, and that changes the checks', () => {
84
+ /**
85
+ * ⛔ THE REASON THIS READER IS NOT THE PROXMOX ONE. `Number(false)` is 0, so a body that
86
+ * coerced its values would pass a boolean straight through a `minimum: 0` and report nothing.
87
+ */
88
+ test('a boolean is never coerced into a numeric bound', () => {
89
+ const table = { count: { minimum: 1, type: 'integer' } } as const;
90
+ expect(violations(table, { count: false })).toEqual([]);
91
+ expect(violations(table, { count: 0 })).toEqual(['count: at least 1']);
92
+ });
93
+
94
+ test('an empty string is not treated as zero', () => {
95
+ const table = { count: { minimum: 0, type: 'integer' } } as const;
96
+ expect(violations(table, { count: '' })).toEqual([]);
97
+ });
98
+
99
+ /** ⚠️ An array is a repeated value — tags and every many-to-many — so each element is checked. */
100
+ test('every element of an array faces the same rule', () => {
101
+ const table = { names: { maxLength: 3, type: 'string' } } as const;
102
+ expect(violations(table, { names: ['ok', 'toolong', 'alsotoolong'] })).toEqual([
103
+ 'names: at most 3 characters',
104
+ 'names: at most 3 characters',
105
+ ]);
106
+ });
107
+
108
+ /** ⚠️ The table carries the CONSTRAINED properties, not every property. */
109
+ test('a key the table does not mention is not an error', () => {
110
+ expect(bodyViolations(CREATE, { prefix: '10.0.0.0/24', vrf: 4, whatever: 'x' }, true)).toEqual(
111
+ [],
112
+ );
113
+ });
114
+ });
@@ -0,0 +1,152 @@
1
+ /**
2
+ * NetBox's own rules, checked here, before the request is built.
3
+ *
4
+ * 🔴 THE INCIDENT THIS PATTERN EXISTS FOR, 2026-09-22 (Proxmox, not NetBox). `homeflare-proxmox`'s
5
+ * first `deploy:pbs` adopted ten objects and then failed its one create:
6
+ * `comment: value may only be 128 characters long`. Half a deploy in, on the server, from a
7
+ * limit the vendor publishes in its own schema and the generated type did not carry. Plan was
8
+ * green, `bun run check` was green, the adopt verifier was green. ★ NetBox gets the same
9
+ * treatment BEFORE its first write rather than after it.
10
+ *
11
+ * ★ SO THE TABLE IS GENERATED AND THIS FILE IS THE READER. `generated/constraints/*` is emitted
12
+ * from NetBox's own OpenAPI document by `bun codegen/netbox.ts`; nothing here is hand-typed,
13
+ * because a hand-typed limit is tribal knowledge that does not run.
14
+ *
15
+ * ⛔ A SEPARATE READER FROM `../proxmox/constraints.ts`, AND IT IS NOT DUPLICATION. That one
16
+ * checks a `PveForm` — every value already a string, because PVE takes form encoding. A NetBox
17
+ * body is JSON: a number stays a number, a boolean stays a boolean, a foreign key is an
18
+ * integer, and `String(value)` on any of them would make `minimum: 0` pass for `false` and
19
+ * `maxLength` meaningless. Sharing one reader would mean stringifying at the door, which is
20
+ * exactly the mangling the Proxmox version's own ⛔ warns about.
21
+ *
22
+ * ⚠️ WHAT IT DELIBERATELY DOES NOT ENFORCE, so nobody reads a green plan as more than it is:
23
+ * - a `format` NAME (`uri`, `email`, `date-time`): a validator DRF implements server-side.
24
+ * Recorded, never checked.
25
+ * - a pattern the generator could not carry faithfully (codegen/py-pattern.ts). Recorded
26
+ * verbatim as `patternSource`, never checked.
27
+ * - UNIQUENESS, VRF containment, custom-field validators, and every other rule that lives in
28
+ * Django rather than in the schema. Those still arrive as a server-side 400.
29
+ * Each is a fact in the table rather than a guess, which is the rule this follows: if the
30
+ * vendor did not state it, it is not enforced and the table says so.
31
+ */
32
+
33
+ export interface ParamConstraint {
34
+ readonly type?: string;
35
+ /** From the schema's `required` array. ⚠️ Checked on CREATE only — see `violations`. */
36
+ readonly required?: boolean;
37
+ readonly maxLength?: number;
38
+ readonly minLength?: number;
39
+ readonly minimum?: number;
40
+ readonly maximum?: number;
41
+ readonly enum?: readonly string[];
42
+ /** A JavaScript-safe translation. Absent when Python's dialect could not be carried over. */
43
+ readonly pattern?: string;
44
+ /** The vendor's own spelling, always — what a violation message quotes, and the audit trail. */
45
+ readonly patternSource?: string;
46
+ /** DRF's server-side validator name. Recorded so a reader knows what is NOT checked here. */
47
+ readonly format?: string;
48
+ readonly default?: string;
49
+ }
50
+
51
+ export type EndpointConstraints = Readonly<Record<string, ParamConstraint>>;
52
+
53
+ /** `netbox:POST /api/ipam/prefixes/` — exactly how the generated tables key an endpoint. */
54
+ export type EndpointKey = string;
55
+
56
+ /** A NetBox request body: JSON, with the types the schema declares. */
57
+ export type NetboxBody = Record<string, unknown>;
58
+
59
+ export interface ViolationOptions {
60
+ /**
61
+ * Check that every schema-required property is present.
62
+ *
63
+ * ⛔ CREATE ONLY. A NetBox update is a PATCH and is deliberately PARTIAL — it carries the fields
64
+ * that changed and nothing else — so requiring presence there would refuse every ordinary
65
+ * edit.
66
+ */
67
+ readonly presence?: boolean;
68
+ }
69
+
70
+ /**
71
+ * ⚠️ `[...value].length`, NOT `value.length`. Django counts characters (Python `len` on a `str`
72
+ * counts code points); JavaScript counts UTF-16 code units, so an emoji in a description counts
73
+ * twice and a 200-character limit would refuse a description NetBox accepts. Rejecting a legal
74
+ * value at plan time is the one failure mode worse than the server 400 this replaces.
75
+ */
76
+ const lengthOf = (value: string): number => [...value].length;
77
+
78
+ const checkString = (name: string, value: string, rule: ParamConstraint): string[] => {
79
+ const out: string[] = [];
80
+ if (rule.maxLength !== undefined && lengthOf(value) > rule.maxLength) {
81
+ out.push(`${name}: at most ${String(rule.maxLength)} characters`);
82
+ }
83
+ if (rule.minLength !== undefined && lengthOf(value) < rule.minLength) {
84
+ out.push(`${name}: at least ${String(rule.minLength)} characters`);
85
+ }
86
+ if (rule.enum !== undefined && !rule.enum.includes(value)) {
87
+ out.push(`${name}: must be one of ${rule.enum.join(', ')}`);
88
+ }
89
+ if (rule.pattern !== undefined && !new RegExp(rule.pattern).test(value)) {
90
+ out.push(`${name}: must match ${rule.patternSource ?? rule.pattern}`);
91
+ }
92
+ return out;
93
+ };
94
+
95
+ /**
96
+ * ⛔ BOUNDS ARE CHECKED ONLY ON A REAL NUMBER, NEVER ON A COERCED ONE. `Number(false)` is 0 and
97
+ * `Number('')` is 0, so coercing would silently pass a boolean and an empty string through a
98
+ * `minimum: 0`. A NetBox body carries real numbers; anything else is a type error upstream.
99
+ */
100
+ const checkNumber = (name: string, value: number, rule: ParamConstraint): string[] => {
101
+ const out: string[] = [];
102
+ if (!Number.isFinite(value)) return out;
103
+ if (rule.minimum !== undefined && value < rule.minimum) {
104
+ out.push(`${name}: at least ${String(rule.minimum)}`);
105
+ }
106
+ if (rule.maximum !== undefined && value > rule.maximum) {
107
+ out.push(`${name}: at most ${String(rule.maximum)}`);
108
+ }
109
+ return out;
110
+ };
111
+
112
+ const checkValue = (name: string, value: unknown, rule: ParamConstraint): readonly string[] => {
113
+ if (typeof value === 'string') return checkString(name, value, rule);
114
+ if (typeof value === 'number') return checkNumber(name, value, rule);
115
+ return [];
116
+ };
117
+
118
+ /**
119
+ * Every vendor rule this body breaks, in the order the properties are declared. Pure: no network,
120
+ * no clock, no environment — so `diff` can call it and a test can call it with a literal.
121
+ *
122
+ * ⚠️ A KEY THE TABLE DOES NOT MENTION IS NOT AN ERROR. The table carries the constrained
123
+ * properties, not every property, and a body may legitimately send an unconstrained one.
124
+ * ⚠️ `null` IS A VALUE, NOT AN ABSENCE. NetBox uses explicit `null` to CLEAR a nullable foreign
125
+ * key, so it must not trip the presence check — and no string or number rule applies to it.
126
+ */
127
+ export const violations = (
128
+ table: EndpointConstraints,
129
+ body: NetboxBody,
130
+ options: ViolationOptions = {},
131
+ ): readonly string[] => {
132
+ const out: string[] = [];
133
+ for (const [name, rule] of Object.entries(table)) {
134
+ if (!Object.hasOwn(body, name)) {
135
+ if (options.presence === true && rule.required === true) out.push(`${name}: required`);
136
+ continue;
137
+ }
138
+ const value = body[name];
139
+ // ⚠️ AN ARRAY IS A REPEATED VALUE (tags, and every many-to-many), so every element faces the
140
+ // same rule rather than the array being skipped as "not a scalar".
141
+ for (const item of Array.isArray(value) ? value : [value]) {
142
+ out.push(...checkValue(name, item, rule));
143
+ }
144
+ }
145
+ return out;
146
+ };
147
+
148
+ /** The message a plan dies with. ⛔ Names the endpoint, because the rule belongs to the vendor. */
149
+ export const refusal = (endpoint: EndpointKey, found: readonly string[]): string =>
150
+ `${endpoint} would be rejected by the vendor:\n - ${found.join('\n - ')}\n` +
151
+ "These are NetBox's own limits, read from its published OpenAPI document " +
152
+ '(packages/alchemy/src/netbox/generated/constraints). Fix the declaration.';
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Every generated NetBox constraint table, merged — DO NOT EDIT BY HAND.
3
+ *
4
+ * Run: bun codegen/netbox.ts
5
+ *
6
+ * ⚠️ EVERY KEY IS PREFIXED `netbox:` FOR THE SAME REASON THE PROXMOX TABLES ARE PREFIXED. One
7
+ * estate runs several vendors and the reader is shared; an unprefixed `POST /api/…` would be
8
+ * one vendor away from colliding.
9
+ */
10
+ import type { EndpointConstraints } from '../../constraints.ts';
11
+ import { NETBOX_IPAM_CONSTRAINTS } from './netbox-ipam.ts';
12
+
13
+ export const NETBOX_CONSTRAINTS: Readonly<Record<string, EndpointConstraints>> = {
14
+ ...NETBOX_IPAM_CONSTRAINTS,
15
+ };
16
+
17
+ /**
18
+ * sha256 of the merged table, truncated.
19
+ *
20
+ * ★ A DIGEST OF THE DATA, NOT OF THE FILE TEXT, so reformatting is not a stale generation while
21
+ * changing a 200 to a 201 by hand is. `tests/netbox-manifest.test.ts` recomputes it.
22
+ */
23
+ export const NETBOX_CONSTRAINTS_DIGEST = '1de1cebe7491d94f';
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Generated NetBox REST API (OpenAPI 3.0.3) request-body constraints for `/api/ipam` — DO NOT EDIT BY HAND.
3
+ *
4
+ * Run: bun codegen/netbox.ts
5
+ * Manifest entry: `netbox-openapi` — NetBox REST API (OpenAPI 3.0.3) 4.7.0
6
+ * sha256 be7f971179b1d6ba, vendor repository, pinned to the release tag
7
+ * contrib/openapi.json in netbox-community/netbox, at tag v4.7.0
8
+ *
9
+ * 2 of this product's 949 POST/PUT/PATCH/DELETE endpoints are tabled across all
10
+ * areas: the ones this package writes to, named in its own source. Every other vendor write
11
+ * endpoint is UNTABLED and therefore unchecked at plan time.
12
+ *
13
+ * ⚠️ A `patternSource` with no `pattern` beside it could NOT be carried into a JavaScript
14
+ * RegExp faithfully — Python's `\w` is Unicode and JavaScript's is ASCII
15
+ * (codegen/py-pattern.ts). It is recorded and NOT enforced.
16
+ * ⚠️ A FOREIGN KEY CARRIES ONLY ITS TYPE. `tenant`, `vlan`, `role` and friends are
17
+ * `integer|object` in the schema, and the related object's own rules do not govern them.
18
+ */
19
+ import type { EndpointConstraints } from '../../constraints.ts';
20
+
21
+ export const NETBOX_IPAM_CONSTRAINTS: Readonly<Record<string, EndpointConstraints>> = {
22
+ "netbox:PATCH /api/ipam/prefixes/{id}/": {
23
+ "description": {"maxLength":200,"type":"string"},
24
+ "prefix": {"minLength":1,"type":"string"},
25
+ "status": {"enum":["container","active","reserved","deprecated"],"type":"string"},
26
+ },
27
+ "netbox:POST /api/ipam/prefixes/": {
28
+ "description": {"maxLength":200,"type":"string"},
29
+ "prefix": {"minLength":1,"required":true,"type":"string"},
30
+ "status": {"enum":["container","active","reserved","deprecated"],"type":"string"},
31
+ },
32
+ };
@@ -0,0 +1,34 @@
1
+ /**
2
+ * NetBox providers for Alchemy.
3
+ *
4
+ * ⛔ THIS BARREL IS THE PUBLIC API, AND IT IS DELIBERATELY SMALLER THAN THE DIRECTORY. These are
5
+ * the symbols a real stack consumes; the rest of the files are internals a provider needs but a
6
+ * consumer should not depend on. An `export *` here would publish every helper as API and make
7
+ * the next refactor a breaking change.
8
+ * ★ The constraint reader IS exported, because a consumer writing its own family needs the same
9
+ * guard — and because a table nobody can reach is a table nobody uses.
10
+ */
11
+ export { NetboxError, apiBase } from './client.ts';
12
+ export {
13
+ NETBOX_CONSTRAINTS,
14
+ bodyViolations,
15
+ constraintsFor,
16
+ guardBody,
17
+ } from './constraint-guard.ts';
18
+ export {
19
+ type EndpointConstraints,
20
+ type EndpointKey,
21
+ type NetboxBody,
22
+ type ParamConstraint,
23
+ refusal,
24
+ violations,
25
+ } from './constraints.ts';
26
+ export { NETBOX_CONSTRAINTS_DIGEST } from './generated/constraints/index.ts';
27
+ export {
28
+ NetboxPrefix,
29
+ NetboxPrefixProvider,
30
+ type PrefixAttributes,
31
+ type PrefixProps,
32
+ type PrefixStatus,
33
+ } from './prefix.ts';
34
+ export { type NetboxRequirements, type NetboxSpec, netboxHandlers } from './resource.ts';