@homeflare/alchemy 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (417) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +62 -0
  3. package/dist/cloudflare/client.d.ts +45 -0
  4. package/dist/cloudflare/client.d.ts.map +1 -0
  5. package/dist/cloudflare/index.d.ts +11 -0
  6. package/dist/cloudflare/index.d.ts.map +1 -0
  7. package/dist/cloudflare/index.js +129 -0
  8. package/dist/cloudflare/index.js.map +13 -0
  9. package/dist/cloudflare/lock-rules.d.ts +50 -0
  10. package/dist/cloudflare/lock-rules.d.ts.map +1 -0
  11. package/dist/cloudflare/providers.d.ts +19 -0
  12. package/dist/cloudflare/providers.d.ts.map +1 -0
  13. package/dist/cloudflare/r2-bucket-lock.d.ts +100 -0
  14. package/dist/cloudflare/r2-bucket-lock.d.ts.map +1 -0
  15. package/dist/forgejo/branch-protection-form.d.ts +19 -0
  16. package/dist/forgejo/branch-protection-form.d.ts.map +1 -0
  17. package/dist/forgejo/branch-protection.d.ts +47 -0
  18. package/dist/forgejo/branch-protection.d.ts.map +1 -0
  19. package/dist/forgejo/client.d.ts +37 -0
  20. package/dist/forgejo/client.d.ts.map +1 -0
  21. package/dist/forgejo/index.d.ts +18 -0
  22. package/dist/forgejo/index.d.ts.map +1 -0
  23. package/dist/forgejo/index.js +479 -0
  24. package/dist/forgejo/index.js.map +21 -0
  25. package/dist/forgejo/org-actions-secrets.d.ts +45 -0
  26. package/dist/forgejo/org-actions-secrets.d.ts.map +1 -0
  27. package/dist/forgejo/org-label.d.ts +46 -0
  28. package/dist/forgejo/org-label.d.ts.map +1 -0
  29. package/dist/forgejo/org-team.d.ts +42 -0
  30. package/dist/forgejo/org-team.d.ts.map +1 -0
  31. package/dist/forgejo/repo-webhook-form.d.ts +27 -0
  32. package/dist/forgejo/repo-webhook-form.d.ts.map +1 -0
  33. package/dist/forgejo/repo-webhook.d.ts +46 -0
  34. package/dist/forgejo/repo-webhook.d.ts.map +1 -0
  35. package/dist/forgejo/repository.d.ts +45 -0
  36. package/dist/forgejo/repository.d.ts.map +1 -0
  37. package/dist/forgejo/resource.d.ts +83 -0
  38. package/dist/forgejo/resource.d.ts.map +1 -0
  39. package/dist/forgejo/team-member.d.ts +39 -0
  40. package/dist/forgejo/team-member.d.ts.map +1 -0
  41. package/dist/forgejo/values.d.ts +24 -0
  42. package/dist/forgejo/values.d.ts.map +1 -0
  43. package/dist/index.d.ts +18 -0
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/index.js +3 -0
  46. package/dist/index.js.map +9 -0
  47. package/dist/openbao/auth-role-form.d.ts +38 -0
  48. package/dist/openbao/auth-role-form.d.ts.map +1 -0
  49. package/dist/openbao/auth-role.d.ts +20 -0
  50. package/dist/openbao/auth-role.d.ts.map +1 -0
  51. package/dist/openbao/bao-address.d.ts +72 -0
  52. package/dist/openbao/bao-address.d.ts.map +1 -0
  53. package/dist/openbao/bao-http.d.ts +71 -0
  54. package/dist/openbao/bao-http.d.ts.map +1 -0
  55. package/dist/openbao/bao-status.d.ts +74 -0
  56. package/dist/openbao/bao-status.d.ts.map +1 -0
  57. package/dist/openbao/cloudflare-group-scope.d.ts +73 -0
  58. package/dist/openbao/cloudflare-group-scope.d.ts.map +1 -0
  59. package/dist/openbao/cloudflare-parity-catalog.d.ts +28 -0
  60. package/dist/openbao/cloudflare-parity-catalog.d.ts.map +1 -0
  61. package/dist/openbao/cloudflare-parity-snapshot.d.ts +31 -0
  62. package/dist/openbao/cloudflare-parity-snapshot.d.ts.map +1 -0
  63. package/dist/openbao/cloudflare-parity.d.ts +14 -0
  64. package/dist/openbao/cloudflare-parity.d.ts.map +1 -0
  65. package/dist/openbao/cloudflare-permission-groups-solve.d.ts +85 -0
  66. package/dist/openbao/cloudflare-permission-groups-solve.d.ts.map +1 -0
  67. package/dist/openbao/cloudflare-permission-groups.d.ts +87 -0
  68. package/dist/openbao/cloudflare-permission-groups.d.ts.map +1 -0
  69. package/dist/openbao/cloudflare-policy.d.ts +65 -0
  70. package/dist/openbao/cloudflare-policy.d.ts.map +1 -0
  71. package/dist/openbao/cloudflare-role-form.d.ts +110 -0
  72. package/dist/openbao/cloudflare-role-form.d.ts.map +1 -0
  73. package/dist/openbao/cloudflare-role-wire.d.ts +27 -0
  74. package/dist/openbao/cloudflare-role-wire.d.ts.map +1 -0
  75. package/dist/openbao/cloudflare-role.d.ts +35 -0
  76. package/dist/openbao/cloudflare-role.d.ts.map +1 -0
  77. package/dist/openbao/cloudflare-roles-config.d.ts +67 -0
  78. package/dist/openbao/cloudflare-roles-config.d.ts.map +1 -0
  79. package/dist/openbao/cloudflare-roles-expand.d.ts +76 -0
  80. package/dist/openbao/cloudflare-roles-expand.d.ts.map +1 -0
  81. package/dist/openbao/digest.d.ts +24 -0
  82. package/dist/openbao/digest.d.ts.map +1 -0
  83. package/dist/openbao/fake-bao.d.ts +40 -0
  84. package/dist/openbao/fake-bao.d.ts.map +1 -0
  85. package/dist/openbao/forgejo-bootstrap-parse.d.ts +46 -0
  86. package/dist/openbao/forgejo-bootstrap-parse.d.ts.map +1 -0
  87. package/dist/openbao/forgejo-bootstrap.d.ts +29 -0
  88. package/dist/openbao/forgejo-bootstrap.d.ts.map +1 -0
  89. package/dist/openbao/index.d.ts +18 -0
  90. package/dist/openbao/index.d.ts.map +1 -0
  91. package/dist/openbao/index.js +1158 -0
  92. package/dist/openbao/index.js.map +33 -0
  93. package/dist/openbao/mount-form.d.ts +60 -0
  94. package/dist/openbao/mount-form.d.ts.map +1 -0
  95. package/dist/openbao/mount-wire.d.ts +24 -0
  96. package/dist/openbao/mount-wire.d.ts.map +1 -0
  97. package/dist/openbao/mount.d.ts +20 -0
  98. package/dist/openbao/mount.d.ts.map +1 -0
  99. package/dist/openbao/pki-role-form.d.ts +118 -0
  100. package/dist/openbao/pki-role-form.d.ts.map +1 -0
  101. package/dist/openbao/pki-role.d.ts +50 -0
  102. package/dist/openbao/pki-role.d.ts.map +1 -0
  103. package/dist/openbao/policy-assembly.d.ts +13 -0
  104. package/dist/openbao/policy-assembly.d.ts.map +1 -0
  105. package/dist/openbao/policy-wire.d.ts +41 -0
  106. package/dist/openbao/policy-wire.d.ts.map +1 -0
  107. package/dist/openbao/policy.d.ts +83 -0
  108. package/dist/openbao/policy.d.ts.map +1 -0
  109. package/dist/openbao/proxmox-role-form.d.ts +92 -0
  110. package/dist/openbao/proxmox-role-form.d.ts.map +1 -0
  111. package/dist/openbao/proxmox-role.d.ts +47 -0
  112. package/dist/openbao/proxmox-role.d.ts.map +1 -0
  113. package/dist/openbao/ssh-role-form.d.ts +99 -0
  114. package/dist/openbao/ssh-role-form.d.ts.map +1 -0
  115. package/dist/openbao/ssh-role.d.ts +43 -0
  116. package/dist/openbao/ssh-role.d.ts.map +1 -0
  117. package/dist/proxmox/acl.d.ts +72 -0
  118. package/dist/proxmox/acl.d.ts.map +1 -0
  119. package/dist/proxmox/api-token-form.d.ts +59 -0
  120. package/dist/proxmox/api-token-form.d.ts.map +1 -0
  121. package/dist/proxmox/api-token.d.ts +159 -0
  122. package/dist/proxmox/api-token.d.ts.map +1 -0
  123. package/dist/proxmox/backup-job.d.ts +112 -0
  124. package/dist/proxmox/backup-job.d.ts.map +1 -0
  125. package/dist/proxmox/ceph-daemon-form.d.ts +70 -0
  126. package/dist/proxmox/ceph-daemon-form.d.ts.map +1 -0
  127. package/dist/proxmox/ceph-daemon.d.ts +162 -0
  128. package/dist/proxmox/ceph-daemon.d.ts.map +1 -0
  129. package/dist/proxmox/ceph-flag.d.ts +131 -0
  130. package/dist/proxmox/ceph-flag.d.ts.map +1 -0
  131. package/dist/proxmox/ceph-fs-wire.d.ts +106 -0
  132. package/dist/proxmox/ceph-fs-wire.d.ts.map +1 -0
  133. package/dist/proxmox/ceph-fs.d.ts +124 -0
  134. package/dist/proxmox/ceph-fs.d.ts.map +1 -0
  135. package/dist/proxmox/ceph-osd-tree.d.ts +154 -0
  136. package/dist/proxmox/ceph-osd-tree.d.ts.map +1 -0
  137. package/dist/proxmox/ceph-osd-write.d.ts +36 -0
  138. package/dist/proxmox/ceph-osd-write.d.ts.map +1 -0
  139. package/dist/proxmox/ceph-osd.d.ts +102 -0
  140. package/dist/proxmox/ceph-osd.d.ts.map +1 -0
  141. package/dist/proxmox/ceph-pool-form.d.ts +217 -0
  142. package/dist/proxmox/ceph-pool-form.d.ts.map +1 -0
  143. package/dist/proxmox/ceph-pool-settle.d.ts +39 -0
  144. package/dist/proxmox/ceph-pool-settle.d.ts.map +1 -0
  145. package/dist/proxmox/ceph-pool.d.ts +48 -0
  146. package/dist/proxmox/ceph-pool.d.ts.map +1 -0
  147. package/dist/proxmox/client.d.ts +64 -0
  148. package/dist/proxmox/client.d.ts.map +1 -0
  149. package/dist/proxmox/credentials.d.ts +153 -0
  150. package/dist/proxmox/credentials.d.ts.map +1 -0
  151. package/dist/proxmox/firewall-alias-form.d.ts +98 -0
  152. package/dist/proxmox/firewall-alias-form.d.ts.map +1 -0
  153. package/dist/proxmox/firewall-alias.d.ts +141 -0
  154. package/dist/proxmox/firewall-alias.d.ts.map +1 -0
  155. package/dist/proxmox/generated/pbs.d.ts +388 -0
  156. package/dist/proxmox/generated/pbs.d.ts.map +1 -0
  157. package/dist/proxmox/generated/pve.d.ts +4713 -0
  158. package/dist/proxmox/generated/pve.d.ts.map +1 -0
  159. package/dist/proxmox/group.d.ts +104 -0
  160. package/dist/proxmox/group.d.ts.map +1 -0
  161. package/dist/proxmox/ha-resource.d.ts +104 -0
  162. package/dist/proxmox/ha-resource.d.ts.map +1 -0
  163. package/dist/proxmox/ha-rule-form.d.ts +103 -0
  164. package/dist/proxmox/ha-rule-form.d.ts.map +1 -0
  165. package/dist/proxmox/ha-rule.d.ts +156 -0
  166. package/dist/proxmox/ha-rule.d.ts.map +1 -0
  167. package/dist/proxmox/index.d.ts +43 -0
  168. package/dist/proxmox/index.d.ts.map +1 -0
  169. package/dist/proxmox/index.js +2322 -0
  170. package/dist/proxmox/index.js.map +70 -0
  171. package/dist/proxmox/lease-cache.d.ts +98 -0
  172. package/dist/proxmox/lease-cache.d.ts.map +1 -0
  173. package/dist/proxmox/lxc.d.ts +59 -0
  174. package/dist/proxmox/lxc.d.ts.map +1 -0
  175. package/dist/proxmox/members.d.ts +56 -0
  176. package/dist/proxmox/members.d.ts.map +1 -0
  177. package/dist/proxmox/metric-server-form.d.ts +53 -0
  178. package/dist/proxmox/metric-server-form.d.ts.map +1 -0
  179. package/dist/proxmox/metric-server-otel.d.ts +49 -0
  180. package/dist/proxmox/metric-server-otel.d.ts.map +1 -0
  181. package/dist/proxmox/metric-server.d.ts +123 -0
  182. package/dist/proxmox/metric-server.d.ts.map +1 -0
  183. package/dist/proxmox/network-apply-read.d.ts +93 -0
  184. package/dist/proxmox/network-apply-read.d.ts.map +1 -0
  185. package/dist/proxmox/network-apply.d.ts +102 -0
  186. package/dist/proxmox/network-apply.d.ts.map +1 -0
  187. package/dist/proxmox/node-network-form.d.ts +128 -0
  188. package/dist/proxmox/node-network-form.d.ts.map +1 -0
  189. package/dist/proxmox/node-network.d.ts +173 -0
  190. package/dist/proxmox/node-network.d.ts.map +1 -0
  191. package/dist/proxmox/notification-target-form.d.ts +44 -0
  192. package/dist/proxmox/notification-target-form.d.ts.map +1 -0
  193. package/dist/proxmox/notification-target.d.ts +146 -0
  194. package/dist/proxmox/notification-target.d.ts.map +1 -0
  195. package/dist/proxmox/pbs-datastore-form.d.ts +147 -0
  196. package/dist/proxmox/pbs-datastore-form.d.ts.map +1 -0
  197. package/dist/proxmox/pbs-datastore-guard.d.ts +55 -0
  198. package/dist/proxmox/pbs-datastore-guard.d.ts.map +1 -0
  199. package/dist/proxmox/pbs-datastore.d.ts +140 -0
  200. package/dist/proxmox/pbs-datastore.d.ts.map +1 -0
  201. package/dist/proxmox/pbs-prune-job-form.d.ts +97 -0
  202. package/dist/proxmox/pbs-prune-job-form.d.ts.map +1 -0
  203. package/dist/proxmox/pbs-prune-job.d.ts +168 -0
  204. package/dist/proxmox/pbs-prune-job.d.ts.map +1 -0
  205. package/dist/proxmox/pbs-sync-job-form.d.ts +83 -0
  206. package/dist/proxmox/pbs-sync-job-form.d.ts.map +1 -0
  207. package/dist/proxmox/pbs-sync-job.d.ts +246 -0
  208. package/dist/proxmox/pbs-sync-job.d.ts.map +1 -0
  209. package/dist/proxmox/pbs-verify-job-form.d.ts +114 -0
  210. package/dist/proxmox/pbs-verify-job-form.d.ts.map +1 -0
  211. package/dist/proxmox/pbs-verify-job.d.ts +145 -0
  212. package/dist/proxmox/pbs-verify-job.d.ts.map +1 -0
  213. package/dist/proxmox/pool.d.ts +42 -0
  214. package/dist/proxmox/pool.d.ts.map +1 -0
  215. package/dist/proxmox/qemu.d.ts +46 -0
  216. package/dist/proxmox/qemu.d.ts.map +1 -0
  217. package/dist/proxmox/replication-job-form.d.ts +71 -0
  218. package/dist/proxmox/replication-job-form.d.ts.map +1 -0
  219. package/dist/proxmox/replication-job.d.ts +162 -0
  220. package/dist/proxmox/replication-job.d.ts.map +1 -0
  221. package/dist/proxmox/resource.d.ts +157 -0
  222. package/dist/proxmox/resource.d.ts.map +1 -0
  223. package/dist/proxmox/role.d.ts +97 -0
  224. package/dist/proxmox/role.d.ts.map +1 -0
  225. package/dist/proxmox/sdn-apply-read.d.ts +80 -0
  226. package/dist/proxmox/sdn-apply-read.d.ts.map +1 -0
  227. package/dist/proxmox/sdn-apply.d.ts +63 -0
  228. package/dist/proxmox/sdn-apply.d.ts.map +1 -0
  229. package/dist/proxmox/sdn-subnet-form.d.ts +111 -0
  230. package/dist/proxmox/sdn-subnet-form.d.ts.map +1 -0
  231. package/dist/proxmox/sdn-subnet.d.ts +161 -0
  232. package/dist/proxmox/sdn-subnet.d.ts.map +1 -0
  233. package/dist/proxmox/sdn-vnet.d.ts +113 -0
  234. package/dist/proxmox/sdn-vnet.d.ts.map +1 -0
  235. package/dist/proxmox/sdn-zone.d.ts +126 -0
  236. package/dist/proxmox/sdn-zone.d.ts.map +1 -0
  237. package/dist/proxmox/storage.d.ts +120 -0
  238. package/dist/proxmox/storage.d.ts.map +1 -0
  239. package/dist/proxmox/user.d.ts +107 -0
  240. package/dist/proxmox/user.d.ts.map +1 -0
  241. package/dist/proxmox/values.d.ts +134 -0
  242. package/dist/proxmox/values.d.ts.map +1 -0
  243. package/dist/proxmox/zfs-pool-write.d.ts +76 -0
  244. package/dist/proxmox/zfs-pool-write.d.ts.map +1 -0
  245. package/dist/proxmox/zfs-pool.d.ts +146 -0
  246. package/dist/proxmox/zfs-pool.d.ts.map +1 -0
  247. package/dist/talos/credentials.d.ts +30 -0
  248. package/dist/talos/credentials.d.ts.map +1 -0
  249. package/dist/talos/index.d.ts +15 -0
  250. package/dist/talos/index.d.ts.map +1 -0
  251. package/dist/talos/index.js +392 -0
  252. package/dist/talos/index.js.map +16 -0
  253. package/dist/talos/kubeconfig.d.ts +53 -0
  254. package/dist/talos/kubeconfig.d.ts.map +1 -0
  255. package/dist/talos/resource.d.ts +32 -0
  256. package/dist/talos/resource.d.ts.map +1 -0
  257. package/dist/talos/talos-bootstrap.d.ts +27 -0
  258. package/dist/talos/talos-bootstrap.d.ts.map +1 -0
  259. package/dist/talos/talos-cluster-health.d.ts +36 -0
  260. package/dist/talos/talos-cluster-health.d.ts.map +1 -0
  261. package/dist/talos/talos-machine-config.d.ts +41 -0
  262. package/dist/talos/talos-machine-config.d.ts.map +1 -0
  263. package/dist/talos/talosctl.d.ts +29 -0
  264. package/dist/talos/talosctl.d.ts.map +1 -0
  265. package/dist/talos/values.d.ts +20 -0
  266. package/dist/talos/values.d.ts.map +1 -0
  267. package/package.json +57 -0
  268. package/src/cloudflare/client.ts +76 -0
  269. package/src/cloudflare/index.ts +10 -0
  270. package/src/cloudflare/lock-rules.ts +60 -0
  271. package/src/cloudflare/providers.ts +23 -0
  272. package/src/cloudflare/r2-bucket-lock.ts +220 -0
  273. package/src/forgejo/branch-protection-form.ts +29 -0
  274. package/src/forgejo/branch-protection.ts +101 -0
  275. package/src/forgejo/client.ts +136 -0
  276. package/src/forgejo/index.ts +17 -0
  277. package/src/forgejo/org-actions-secrets.ts +99 -0
  278. package/src/forgejo/org-label.ts +100 -0
  279. package/src/forgejo/org-team.ts +105 -0
  280. package/src/forgejo/repo-webhook-form.ts +47 -0
  281. package/src/forgejo/repo-webhook.ts +118 -0
  282. package/src/forgejo/repository.ts +126 -0
  283. package/src/forgejo/resource.ts +171 -0
  284. package/src/forgejo/team-member.ts +97 -0
  285. package/src/forgejo/values.test.ts +48 -0
  286. package/src/forgejo/values.ts +61 -0
  287. package/src/index.ts +18 -0
  288. package/src/openbao/auth-role-form.ts +112 -0
  289. package/src/openbao/auth-role.ts +101 -0
  290. package/src/openbao/bao-address.test.ts +89 -0
  291. package/src/openbao/bao-address.ts +97 -0
  292. package/src/openbao/bao-http-gate.test.ts +88 -0
  293. package/src/openbao/bao-http-unix.test.ts +70 -0
  294. package/src/openbao/bao-http.test.ts +161 -0
  295. package/src/openbao/bao-http.ts +185 -0
  296. package/src/openbao/bao-status.test.ts +114 -0
  297. package/src/openbao/bao-status.ts +137 -0
  298. package/src/openbao/cloudflare-group-scope.test.ts +103 -0
  299. package/src/openbao/cloudflare-group-scope.ts +83 -0
  300. package/src/openbao/cloudflare-parity-catalog.ts +104 -0
  301. package/src/openbao/cloudflare-parity-snapshot.ts +84 -0
  302. package/src/openbao/cloudflare-parity.ts +152 -0
  303. package/src/openbao/cloudflare-permission-groups-solve.test.ts +171 -0
  304. package/src/openbao/cloudflare-permission-groups-solve.ts +197 -0
  305. package/src/openbao/cloudflare-permission-groups.test.ts +369 -0
  306. package/src/openbao/cloudflare-permission-groups.ts +299 -0
  307. package/src/openbao/cloudflare-policy.ts +180 -0
  308. package/src/openbao/cloudflare-role-form.test.ts +177 -0
  309. package/src/openbao/cloudflare-role-form.ts +183 -0
  310. package/src/openbao/cloudflare-role-wire.test.ts +132 -0
  311. package/src/openbao/cloudflare-role-wire.ts +41 -0
  312. package/src/openbao/cloudflare-role.ts +189 -0
  313. package/src/openbao/cloudflare-roles-config.ts +230 -0
  314. package/src/openbao/cloudflare-roles-expand-bucket.test.ts +134 -0
  315. package/src/openbao/cloudflare-roles-expand.ts +231 -0
  316. package/src/openbao/digest.ts +26 -0
  317. package/src/openbao/fake-bao.ts +84 -0
  318. package/src/openbao/forgejo-bootstrap-parse.test.ts +76 -0
  319. package/src/openbao/forgejo-bootstrap-parse.ts +90 -0
  320. package/src/openbao/forgejo-bootstrap.ts +181 -0
  321. package/src/openbao/index.ts +17 -0
  322. package/src/openbao/mount-form.ts +147 -0
  323. package/src/openbao/mount-wire.test.ts +108 -0
  324. package/src/openbao/mount-wire.ts +79 -0
  325. package/src/openbao/mount.ts +132 -0
  326. package/src/openbao/pki-role-form.ts +248 -0
  327. package/src/openbao/pki-role.ts +202 -0
  328. package/src/openbao/policy-assembly.test.ts +28 -0
  329. package/src/openbao/policy-assembly.ts +13 -0
  330. package/src/openbao/policy-wire.test.ts +90 -0
  331. package/src/openbao/policy-wire.ts +53 -0
  332. package/src/openbao/policy.ts +212 -0
  333. package/src/openbao/proxmox-role-form.ts +174 -0
  334. package/src/openbao/proxmox-role.ts +214 -0
  335. package/src/openbao/ssh-role-form.ts +248 -0
  336. package/src/openbao/ssh-role.ts +240 -0
  337. package/src/proxmox/acl.ts +267 -0
  338. package/src/proxmox/api-token-form.ts +122 -0
  339. package/src/proxmox/api-token.ts +222 -0
  340. package/src/proxmox/backup-job.ts +213 -0
  341. package/src/proxmox/ceph-daemon-form.ts +84 -0
  342. package/src/proxmox/ceph-daemon.ts +243 -0
  343. package/src/proxmox/ceph-flag.ts +249 -0
  344. package/src/proxmox/ceph-fs-wire.ts +246 -0
  345. package/src/proxmox/ceph-fs.ts +249 -0
  346. package/src/proxmox/ceph-osd-tree.ts +193 -0
  347. package/src/proxmox/ceph-osd-write.ts +76 -0
  348. package/src/proxmox/ceph-osd.ts +244 -0
  349. package/src/proxmox/ceph-pool-form.ts +249 -0
  350. package/src/proxmox/ceph-pool-settle.ts +70 -0
  351. package/src/proxmox/ceph-pool.ts +212 -0
  352. package/src/proxmox/client.test.ts +185 -0
  353. package/src/proxmox/client.ts +240 -0
  354. package/src/proxmox/credentials.test.ts +144 -0
  355. package/src/proxmox/credentials.ts +254 -0
  356. package/src/proxmox/firewall-alias-form.ts +112 -0
  357. package/src/proxmox/firewall-alias.ts +208 -0
  358. package/src/proxmox/generated/pbs.ts +461 -0
  359. package/src/proxmox/generated/pve.ts +7344 -0
  360. package/src/proxmox/group.ts +199 -0
  361. package/src/proxmox/ha-resource.ts +169 -0
  362. package/src/proxmox/ha-rule-form.ts +185 -0
  363. package/src/proxmox/ha-rule.ts +240 -0
  364. package/src/proxmox/index.ts +42 -0
  365. package/src/proxmox/lease-cache.test.ts +163 -0
  366. package/src/proxmox/lease-cache.ts +131 -0
  367. package/src/proxmox/lxc.ts +117 -0
  368. package/src/proxmox/members.test.ts +54 -0
  369. package/src/proxmox/members.ts +174 -0
  370. package/src/proxmox/metric-server-form.ts +128 -0
  371. package/src/proxmox/metric-server-otel.ts +99 -0
  372. package/src/proxmox/metric-server.ts +214 -0
  373. package/src/proxmox/network-apply-read.ts +228 -0
  374. package/src/proxmox/network-apply.ts +244 -0
  375. package/src/proxmox/node-network-form.ts +213 -0
  376. package/src/proxmox/node-network.ts +243 -0
  377. package/src/proxmox/notification-target-form.ts +104 -0
  378. package/src/proxmox/notification-target.ts +222 -0
  379. package/src/proxmox/pbs-datastore-form.ts +248 -0
  380. package/src/proxmox/pbs-datastore-guard.ts +105 -0
  381. package/src/proxmox/pbs-datastore.ts +271 -0
  382. package/src/proxmox/pbs-prune-job-form.ts +208 -0
  383. package/src/proxmox/pbs-prune-job.ts +227 -0
  384. package/src/proxmox/pbs-sync-job-form.ts +234 -0
  385. package/src/proxmox/pbs-sync-job.ts +258 -0
  386. package/src/proxmox/pbs-verify-job-form.ts +131 -0
  387. package/src/proxmox/pbs-verify-job.ts +227 -0
  388. package/src/proxmox/pool.test.ts +42 -0
  389. package/src/proxmox/pool.ts +80 -0
  390. package/src/proxmox/qemu.ts +89 -0
  391. package/src/proxmox/replication-job-form.ts +89 -0
  392. package/src/proxmox/replication-job.ts +248 -0
  393. package/src/proxmox/resource.ts +257 -0
  394. package/src/proxmox/role.ts +161 -0
  395. package/src/proxmox/sdn-apply-read.test.ts +152 -0
  396. package/src/proxmox/sdn-apply-read.ts +189 -0
  397. package/src/proxmox/sdn-apply.ts +154 -0
  398. package/src/proxmox/sdn-subnet-form.ts +156 -0
  399. package/src/proxmox/sdn-subnet.ts +238 -0
  400. package/src/proxmox/sdn-vnet.ts +228 -0
  401. package/src/proxmox/sdn-zone.ts +246 -0
  402. package/src/proxmox/storage.ts +245 -0
  403. package/src/proxmox/user.ts +214 -0
  404. package/src/proxmox/values.test.ts +193 -0
  405. package/src/proxmox/values.ts +203 -0
  406. package/src/proxmox/zfs-pool-write.ts +130 -0
  407. package/src/proxmox/zfs-pool.ts +253 -0
  408. package/src/talos/credentials.ts +136 -0
  409. package/src/talos/index.ts +14 -0
  410. package/src/talos/kubeconfig.ts +170 -0
  411. package/src/talos/resource.ts +31 -0
  412. package/src/talos/talos-bootstrap.ts +109 -0
  413. package/src/talos/talos-cluster-health.ts +119 -0
  414. package/src/talos/talos-machine-config.ts +146 -0
  415. package/src/talos/talosctl.ts +94 -0
  416. package/src/talos/values.test.ts +80 -0
  417. package/src/talos/values.ts +70 -0
@@ -0,0 +1,80 @@
1
+ /**
2
+ * What is staged on the SDN, across the WHOLE surface the apply publishes — not just the two
3
+ * collections this package declares resources for.
4
+ *
5
+ * 🔴 THE GAP THIS FILE CLOSES, AND IT WAS FOUND BY ALMOST DECLARING THE APPLY. `pendingCount` in
6
+ * sdn-apply.ts counted `cluster/sdn/zones` and `cluster/sdn/vnets`. TB4 has zero of each — and a
7
+ * staged OSPF FABRIC that nothing counted. MEASURED 2026-09-13 on n2:
8
+ *
9
+ * /etc/pve/sdn/fabrics.cfg ospf_fabric: tb4, area 1, ip_prefix 10.100.0.0/24
10
+ * ospf_node: tb4_n2/n3/n4, interfaces en05 + en06,
11
+ * ip 10.100.0.102 / .103 / .104
12
+ * /etc/network/interfaces.d/sdn the file PVE GENERATES from it, carrying those /32s
13
+ *
14
+ * Those addresses are Ceph's `cluster_network`. So `diff` would have answered `noop` for ever
15
+ * while `PUT /cluster/sdn` republished the fabric and reloaded networking on all three nodes at
16
+ * once — the simultaneity the NetworkApply chain exists to prevent, arriving through the door
17
+ * nobody was watching.
18
+ *
19
+ * ⛔ THE SURFACE IS NOT UNIFORM, AND ASSUMING IT WAS IS WHAT MADE THE GAP INVISIBLE. Measured, one
20
+ * request per collection, per query:
21
+ *
22
+ * zones, vnets, controllers, prefix-lists, route-maps accept ?pending=1 and ?running=1,
23
+ * and mark a staged row with `state`
24
+ * fabrics accepts both, and its rows carry NO
25
+ * `state` marker at all
26
+ * ipams, dns REJECT both with HTTP 400,
27
+ * "property is not defined in schema"
28
+ *
29
+ * ⛔ SO A `state`-ONLY TEST IS WRONG FOR FABRICS, AND `orElseSucceed(() => 0)` IS WORSE THAN WRONG
30
+ * FOR ipams AND dns. The old code folded an unreadable collection to zero — right for a cluster
31
+ * with no SDN at all, and indistinguishable from "this collection rejects the question". Adding
32
+ * ipams and dns to the old list would have counted them as 0 for ever and read as coverage.
33
+ */
34
+ import * as Effect from 'effect/Effect';
35
+ import type { PveTarget } from './credentials.ts';
36
+ /**
37
+ * Collections with NO pending view at all.
38
+ *
39
+ * ⚠️ NAMED RATHER THAN SILENTLY SKIPPED. `ipams` and `dns` answer HTTP 400 to both `?pending=1` and
40
+ * `?running=1`, so there is no way to ask them what is staged. They are a REAL blind spot: an
41
+ * ipam edited by hand is published by the apply and cannot be seen from here. TB4 has one ipam
42
+ * (`pve`, the built-in) and zero dns entries, so the blind spot is currently empty — which is a
43
+ * fact about today, not a property of the design.
44
+ */
45
+ export declare const UNDIFFABLE: readonly ['cluster/sdn/ipams', 'cluster/sdn/dns'];
46
+ /**
47
+ * Whether a failed read means "this SDN subsystem does not exist here" — the ONE failure that may
48
+ * read as nothing staged.
49
+ *
50
+ * 🔴 IT USED TO BE EVERY FAILURE. `orElseSucceed` caught 401, 403, 5xx and a dropped connection
51
+ * along with the 501 it was written for, so an expired read lease or a missing grant answered
52
+ * "nothing staged": `diff` said noop, and the read-back after a real apply said settled while
53
+ * objects were still staged. The fabric views were worse because they are COMPARED — one view
54
+ * failing while the other succeeded read as a DIFFERENCE, which is `PUT /cluster/sdn` and a
55
+ * network reload carrying Ceph's cluster network on all three nodes, over a timeout. Found in
56
+ * review on 2026-09-14 and confirmed by reading.
57
+ * ⛔ SO ANYTHING ELSE FAILS THE READ. A plan that stops on an unreadable SDN is loud and safe; a
58
+ * plan that guesses is neither.
59
+ */
60
+ export declare const subsystemAbsent: (error: unknown) => boolean;
61
+ /**
62
+ * Staged fabric changes from the two canonical views, where `undefined` is a view whose subsystem
63
+ * answered 501.
64
+ *
65
+ * ⛔ ONE VIEW ABSENT AND ONE PRESENT IS NOT A DIFFERENCE. It is one endpoint answering two
66
+ * questions inconsistently, and a difference is exactly what triggers the publish — so it is
67
+ * refused rather than counted.
68
+ */
69
+ export declare const fabricStaged: (staged: string | undefined, running: string | undefined) => number | 'inconsistent';
70
+ /** Stable JSON with `digest` removed and every array sorted, so only real differences show. */
71
+ export declare const canonical: (value: unknown) => string;
72
+ /**
73
+ * How many staged changes the apply would publish, across everything it is capable of publishing.
74
+ *
75
+ * ⛔ ZERO HERE IS THE ONLY THING THAT MAKES DECLARING THE APPLY SAFE. `reconcile` runs on CREATE —
76
+ * Alchemy always calls it the first time a resource appears — and `PUT /cluster/sdn` regenerates
77
+ * `/etc/network/interfaces.d/sdn` on every node. On TB4 that file carries Ceph's cluster network.
78
+ */
79
+ export declare const sdnPendingCount: (target: PveTarget) => Effect.Effect<number, Error, import("effect/unstable/http/HttpClient").HttpClient>;
80
+ //# sourceMappingURL=sdn-apply-read.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sdn-apply-read.d.ts","sourceRoot":"","sources":["../../src/proxmox/sdn-apply-read.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAwBlD;;;;;;;;GAQG;AACH,eAAO,MAAM,UAAU,YAAI,mBAAmB,EAAE,iBAAiB,CAAU,CAAC;AAE5E;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,eAAe,UAAW,OAAO,KAAG,OACE,CAAC;AAqBpD;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY,WACf,MAAM,GAAG,SAAS,WACjB,MAAM,GAAG,SAAS,KAC1B,MAAM,GAAG,cAIX,CAAC;AAuCF,+FAA+F;AAC/F,eAAO,MAAM,SAAS,UAAW,OAAO,KAAG,MAAyC,CAAC;AAiBrF;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,WAAY,SAAS,uFAG9C,CAAC"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * `Proxmox.SdnApply` — the call that makes a declared network real.
3
+ *
4
+ * ⛔ WITHOUT THIS RESOURCE, EVERY SDN DEPLOY IS A GREEN PLAN THAT CHANGES NO NETWORK. Writes under
5
+ * `cluster/sdn/*` edit files in `/etc/pve/sdn/` and touch nothing on any node. `PUT /cluster/sdn`
6
+ * is the apply, and it is CLUSTER-WIDE — it publishes every staged object at once, not the one
7
+ * that happened to reconcile.
8
+ *
9
+ * ★ MEASURED ON TB4 ON 2026-09-13, NOT INFERRED. A probe zone was created, inspected and removed:
10
+ *
11
+ * pvesh create /cluster/sdn/zones --zone zzprobe --type simple
12
+ * GET /cluster/sdn/zones/zzprobe -> {"digest":"c438…","type":"simple","zone":"zzprobe"}
13
+ * GET /cluster/sdn/zones/zzprobe?pending=1 -> {"digest":null,"pending":{},"state":"new",…}
14
+ * GET /cluster/sdn/zones?running=1 -> [] ⬅ THE APPLIED CONFIG WAS EMPTY
15
+ *
16
+ * So the plain read — the one `pveOperations` performs — answers from the STAGED file and cannot
17
+ * tell staged from applied. `state` appears only under `?pending=1`, and `?running=1` is the
18
+ * applied view. That is the whole basis for this resource.
19
+ *
20
+ * ★ IT IS A RESOURCE RATHER THAN A HOOK SO THAT THE GRAPH ORDERS IT. Pass the zones and vnets it
21
+ * should follow in `after`; Alchemy orders by data flow, so reading their attributes is what
22
+ * puts the apply last. A stack-level hook would fire on every run, including runs where no SDN
23
+ * object changed, and would be invisible in `plan`.
24
+ *
25
+ * ⚠️ ONE APPLY PER STACK. Two of these would each publish the other's staged half, so whichever
26
+ * ran first would apply a zone its own declaration had not finished writing. Declare one.
27
+ *
28
+ * ⚠️ THE COLLECTION READ IS DELIBERATE, AND IT IS WHAT LETS THE READ LEASE SEE ANYTHING AT ALL.
29
+ * `GET /cluster/sdn/zones/{zone}` is checked against SDN.Allocate — read the ⛔ in sdn-zone.ts —
30
+ * but `GET /cluster/sdn/zones` is "list entries where you have SDN.Audit or SDN.Allocate", so
31
+ * the collection answers an auditor-shaped credential. This resource only ever reads collections.
32
+ */
33
+ import { Resource } from 'alchemy';
34
+ import * as Provider from 'alchemy/Provider';
35
+ import type { PveRequirements } from './resource.ts';
36
+ import type { WithTarget } from './resource.ts';
37
+ export interface SdnApplyProps extends WithTarget {
38
+ /**
39
+ * The staged objects this apply publishes.
40
+ *
41
+ * ⚠️ IT IS NEVER READ, AND IT IS NOT DECORATION. Alchemy orders resources by DATA FLOW, so the
42
+ * only way to say "after the zones" is to consume something the zones produced. Pass their
43
+ * attributes here — `after: [zone.zone, vnet.vnet]` — and the apply lands last. Leave it out
44
+ * and the apply may run BEFORE the zone it was meant to publish, which plans green and
45
+ * changes nothing.
46
+ */
47
+ after?: readonly unknown[];
48
+ }
49
+ export interface SdnApplyAttributes {
50
+ /**
51
+ * How many SDN objects are still staged.
52
+ *
53
+ * ⚠️ ZERO IS THE ONLY SETTLED VALUE. Anything above it means the running config and the staged
54
+ * config disagree — which is drift whether this stack caused it or somebody staged a zone in
55
+ * the UI and walked away.
56
+ */
57
+ pending: number;
58
+ }
59
+ export interface ProxmoxSdnApply extends Resource<'Proxmox.SdnApply', SdnApplyProps, SdnApplyAttributes, never, PveRequirements> {
60
+ }
61
+ export declare const ProxmoxSdnApply: import("alchemy").ResourceClass<ProxmoxSdnApply>;
62
+ export declare const ProxmoxSdnApplyProvider: () => import("effect/Layer").Layer<Provider.Provider<ProxmoxSdnApply>, never, import("effect/unstable/http/HttpClient").HttpClient>;
63
+ //# sourceMappingURL=sdn-apply.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sdn-apply.d.ts","sourceRoot":"","sources":["../../src/proxmox/sdn-apply.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAGnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAG7C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAGhD,MAAM,WAAW,aAAc,SAAQ,UAAU;IAC/C;;;;;;;;OAQG;IACH,KAAK,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,kBAAkB;IACjC;;;;;;OAMG;IACH,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAgB,SAAQ,QAAQ,CAC/C,kBAAkB,EAClB,aAAa,EACb,kBAAkB,EAClB,KAAK,EACL,eAAe,CAChB;CAAG;AAEJ,eAAO,MAAM,eAAe,kDAAgD,CAAC;AAK7E,eAAO,MAAM,uBAAuB,qIA0EjC,CAAC"}
@@ -0,0 +1,111 @@
1
+ /**
2
+ * How a subnet crosses the wire in both directions, and what PVE actually calls its path.
3
+ *
4
+ * ★ SPLIT OUT OF sdn-subnet.ts TO KEEP BOTH FILES UNDER THE 250-LINE CAP, on the seam
5
+ * node-network-form.ts cuts rather than at a convenient line number: this file owns the
6
+ * COERCIONS in BOTH directions plus the derived id, because a read that normalises differently
7
+ * from the write that produced it is exactly how a forever-diff is born. sdn-subnet.ts answers
8
+ * "what is a subnet, and when has it changed". Nothing here calls the cluster.
9
+ *
10
+ * ⚠️ THE `import type` BACK TO sdn-subnet.ts IS A CYCLE ON PAPER ONLY — type-only, so it is erased
11
+ * before anything runs and `SdnSubnetProps` stays in the file that declares the resource.
12
+ */
13
+ import type { SdnSubnetProps } from './sdn-subnet.ts';
14
+ /** One DHCP pool. PVE's property-string keys are `start-address`/`end-address`; see `rangeString`. */
15
+ export type DhcpRange = {
16
+ start: string;
17
+ end: string;
18
+ };
19
+ /**
20
+ * The id PVE files a subnet under — and therefore the path segment GET, PUT and DELETE address it
21
+ * by, which is NOT the value POST is handed.
22
+ *
23
+ * ⛔ MEASURED from `/usr/share/perl5/PVE/API2/Network/SDN/Subnets.pm` on pve-manager 9.2.11, in
24
+ * the create handler: `my $id = $cidr =~ s/\//-/r; $id = "$zoneid-$id";`. So `subnet=10.0.0.0/24`
25
+ * goes out and `house-10.0.0.0-24` is what exists afterwards. A CIDR cannot be a path segment
26
+ * anyway — it carries a slash — so there is no spelling of this endpoint that takes the CIDR.
27
+ *
28
+ * ⚠️ `.replace`, NOT `.replaceAll`, AND THE PARITY IS DELIBERATE. Perl's `s/\//-/r` has no `/g`, so
29
+ * it rewrites the FIRST slash only. A CIDR has exactly one, so the two agree on every legal
30
+ * input; they would stop agreeing on an illegal one, and agreeing with PVE is the point.
31
+ */
32
+ export declare const subnetId: (props: Pick<SdnSubnetProps, 'cidr' | 'zone'>) => string;
33
+ /**
34
+ * DHCP ranges, from either shape, as one comparable string.
35
+ *
36
+ * ⛔ THIS FAMILY'S WRITE SHAPE AND READ SHAPE ARE DIFFERENT, WHICH IS THE CLASSIC FOREVER-DIFF.
37
+ * MEASURED from the API module: `$scfg->{'dhcp-range'} = get_dhcp_ranges($scfg)` runs
38
+ * `parse_property_string` over every stored element, so a range WRITTEN as the string
39
+ * `start-address=10.0.0.10,end-address=10.0.0.20` is READ BACK as the object
40
+ * `{"start-address":"10.0.0.10","end-address":"10.0.0.20"}`. `propertyString` in values.ts
41
+ * flattens both shapes to one sorted form and exists for exactly this — see its own ⚠️.
42
+ *
43
+ * ⚠️ AND IT IS A LIST, SO ORDER MUST NOT BE MEANING. PVE validates only that ranges do not overlap
44
+ * and stores them in the order given; two declarations naming the same pools the other way round
45
+ * are the same subnet. Sorting is what stops that being an update, exactly as `csv` does for a
46
+ * zone's `nodes`.
47
+ *
48
+ * ⚠️ `;` IS THE JOINER BECAUSE `,` AND `=` ARE BOTH INSIDE THE VALUES. It never appears in an IPv4
49
+ * or IPv6 address or in a property-string key, so the joined form cannot be ambiguous.
50
+ */
51
+ export declare const dhcpRanges: (value: unknown) => string;
52
+ /** The declared side of that same comparison, through the same funnel so it cannot drift. */
53
+ export declare const declaredRanges: (range: DhcpRange | undefined) => string;
54
+ /**
55
+ * Every optional this resource MANAGES: the value to send, or `undefined` meaning "clear it".
56
+ *
57
+ * ⛔ ONE TABLE FEEDS BOTH HALVES OF AN UPDATE, the way metric-server-form.ts does it, and for the
58
+ * same measured reason: A PUT THAT OMITS A FIELD DOES NOT CLEAR IT. PVE merges the form into the
59
+ * existing section (`$data->{$_} = $opts->{$_} for keys $opts->%*`), so dropping `gateway` from a
60
+ * declaration leaves the old gateway in place and `matches` asks for the same update forever.
61
+ * Deriving the form and the `delete=` list from one map makes "managed but not clearable"
62
+ * impossible to write here.
63
+ *
64
+ * ⛔ AND THE TWO HALVES MUST NOT OVERLAP. MEASURED in `PVE::SectionConfig::delete_from_config`
65
+ * (SectionConfig.pm:1853): naming a key in BOTH the form and `delete=` dies with "cannot set and
66
+ * delete property '<k>' at the same time!". Because both halves are read off this one map, an
67
+ * entry is in exactly one of them by construction.
68
+ *
69
+ * ⛔ NOTHING SET OUT OF BAND MAY BE LISTED HERE. A field in this map is CLEARED the moment it is
70
+ * undeclared, so a live subnet whose DHCP pool an operator widened in the UI is narrowed back on
71
+ * the next deploy. That is full ownership, the same bargain sdn-vnet.ts strikes over `alias`, and
72
+ * it is a bargain rather than an accident only while this list stays deliberate.
73
+ *
74
+ * ⚠️ `snat` IS ABSENT ON PURPOSE AND LIVES IN `body` INSTEAD. It is a boolean, and `0` and "never
75
+ * declared" are the same subnet to PVE and to `matches`, so sending an explicit `0` converges
76
+ * without a `delete=` — the same choice sdn-vnet.ts makes for `vlanaware` and `isolate-ports`.
77
+ */
78
+ export declare const optional: (props: SdnSubnetProps) => Record<string, string | undefined>;
79
+ /**
80
+ * The fields sent on EVERY write, create and update alike.
81
+ *
82
+ * ⚠️ `vnet` IS SENT THOUGH THE URL ALREADY CARRIES IT. PVE's handler reads `$param->{vnet}` to
83
+ * resolve the zone for its permission check, and it is a declared parameter of both the create
84
+ * and the update schema, so sending the same value the path carries is accepted and removes this
85
+ * file's dependence on the router injecting a path placeholder into the parameter hash.
86
+ */
87
+ export declare const body: (props: SdnSubnetProps) => Record<string, string>;
88
+ /**
89
+ * ⚠️ `type` IS HARDCODED, NOT A PROP. PVE's create schema declares it as an enum with exactly one
90
+ * member, `subnet`, so a prop for it could only ever hold one value — and the POST refuses to
91
+ * proceed without it, which is the parameter-verification error sdn-vnet.ts records.
92
+ */
93
+ export declare const createForm: (props: SdnSubnetProps) => Record<string, string>;
94
+ /**
95
+ * ★ CLEARING AN OPTION THAT WAS NEVER SET IS A SILENT NO-OP, AND THIS IS MEASURED RATHER THAN
96
+ * HOPED FOR. sdn-vnet.ts flags the same `delete=` habit as REASONED-not-measured and warns that a
97
+ * first update on a bare object would carry `delete=alias,tag`. Read off the code both endpoints
98
+ * share — `PVE::SectionConfig::delete_from_config`, SectionConfig.pm:1853-1866 — the loop dies
99
+ * only for an option that is unknown to the plugin, not optional, fixed, or also being set; for
100
+ * an option simply absent from the section it runs `delete $config->{$k}` on a missing key and
101
+ * moves on. All four keys above are `optional => 1` in `SubnetPlugin::options`, so a bare
102
+ * subnet's first update carries `delete=dhcp-dns-server,dhcp-range,dnszoneprefix,gateway` and
103
+ * PVE accepts it. `vnet` is `optional => 0` there and is never in this list.
104
+ *
105
+ * ⚠️ TWO OF THOSE FOUR NAMES ARE HYPHENATED, WHICH NO OTHER FAMILY HERE HAS PUT IN A `delete=`.
106
+ * The parameter's format is `pve-configid-list`, and a name that failed it would 400 the whole
107
+ * update rather than skip one field. MEASURED: `$CONFIGID_RE` is `qr/[a-z][a-z0-9_-]+/i`
108
+ * (JSONSchema.pm:30), so a hyphen after the first character is legal and all four pass.
109
+ */
110
+ export declare const updateForm: (props: SdnSubnetProps) => Record<string, string>;
111
+ //# sourceMappingURL=sdn-subnet-form.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sdn-subnet-form.d.ts","sourceRoot":"","sources":["../../src/proxmox/sdn-subnet-form.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAGtD,sGAAsG;AACtG,MAAM,MAAM,SAAS,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,QAAQ,UAAW,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAAC,WACpB,CAAC;AAKlD;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,UAAU,UAAW,OAAO,KAAG,MAK9B,CAAC;AAEf,6FAA6F;AAC7F,eAAO,MAAM,cAAc,UAAW,SAAS,GAAG,SAAS,WACE,CAAC;AAU9D;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,QAAQ,UAAW,cAAc,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAKhF,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,IAAI,UAAW,cAAc,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAQhE,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,UAAU,UAAW,cAAc,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAItE,CAAC;AAEH;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,UAAU,UAAW,cAAc,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAKvE,CAAC"}
@@ -0,0 +1,161 @@
1
+ /**
2
+ * `Proxmox.SdnSubnet` — the addresses on a declared bridge: the CIDR, its gateway, its DHCP pool.
3
+ *
4
+ * ★ THE THIRD LINK OF ONE CHAIN, AND THE ORDER IS DATA FLOW RATHER THAN CONVENTION. A subnet
5
+ * belongs to a vnet and a vnet belongs to a zone. MEASURED and recorded in sdn-vnet.ts: creating
6
+ * a vnet is permission-checked at `/sdn/zones/-`, so a missing zone surfaces as a PERMISSION
7
+ * error rather than as "no such zone". One level deeper the same shape holds — PVE's
8
+ * `check_vnet_access` looks the vnet's ZONE up and checks `/sdn/zones/<zone>/<vnet>` — so a
9
+ * subnet declared against a vnet that does not exist yet dies inside that lookup, with the vnet
10
+ * named and the zone not. Pass the zone and vnet resources' OWN attributes into `zone` and
11
+ * `vnet`; a literal buys no ordering, and here it also buys a wrong path.
12
+ *
13
+ * ⛔ THE ID PVE FILES A SUBNET UNDER IS NOT THE ONE YOU WRITE, AND IT IS THIS FAMILY'S SHARPEST
14
+ * EDGE. `POST` takes `subnet=10.0.0.0/24` while GET, PUT and DELETE address `house-10.0.0.0-24`.
15
+ * One PVE parameter name, `subnet`, carrying two different values — so they are named APART here,
16
+ * `cidr` for the declared one and `subnetId` for the derived one, for the reason values.ts gives
17
+ * about `flag`: a name that means two things is a bug waiting for whoever reads one meaning. The
18
+ * derivation, and its measurement, live in `subnetId` in sdn-subnet-form.ts.
19
+ *
20
+ * ⛔ WHICH IS WHY `zone` IS A PROP THOUGH PVE NEVER ACCEPTS IT ON A SUBNET WRITE. The path cannot
21
+ * be built without it and it is knowable only from the VNET. Declare the wrong zone and the id is
22
+ * wrong: the POST still succeeds, because PVE computes the real id itself from the vnet, and the
23
+ * read-back then looks for a subnet that is not there. The factory's guard in resource.ts DIES on
24
+ * that first deploy — "the write returned no error but the object is still absent" — which is
25
+ * loud and immediate, and much better than the alternative it replaces: a plan that says create,
26
+ * forever, against a subnet PVE insists is already defined.
27
+ *
28
+ * ⛔ SDN WRITES ARE STAGED, NOT APPLIED — the same trap as sdn-zone.ts and sdn-vnet.ts, and it
29
+ * walks straight through the factory's read-back, which proves the staging file and nothing more.
30
+ * Nothing here applies. `Proxmox.SdnApply` (sdn-apply.ts) publishes the whole staged config with
31
+ * `PUT /cluster/sdn`; declare one and pass this resource's `subnetId` in its `after`.
32
+ *
33
+ * ⛔ AND `Proxmox.SdnApply` CANNOT YET SEE A STAGED SUBNET, SO ITS PLAN WILL LIE ABOUT THIS FAMILY.
34
+ * MEASURED: its `COLLECTIONS` list is `cluster/sdn/zones` and `cluster/sdn/vnets`, while
35
+ * `PVE::Network::SDN::pending_config` keys the pending view on a SEPARATE `subnets` section of
36
+ * the running config. A run that stages only a subnet therefore leaves both counted collections
37
+ * at zero, the apply diffs as `noop`, and the subnet never reaches a node. It is NOT fixable by
38
+ * adding a string to that list: the subnet index is PER VNET
39
+ * (`cluster/sdn/vnets/{vnet}/subnets?pending=1`), so SdnApply needs the vnet names before it can
40
+ * count them. Until that lands, a subnet-only change needs `pvesh set /cluster/sdn` by hand.
41
+ *
42
+ * ★ THE READ LANE IS ENOUGH HERE, AND THAT IS A REAL DIFFERENCE FROM BOTH SIBLINGS. The zone and
43
+ * vnet ITEM reads are gated on SDN.Allocate, which is why each sets `readRole: 'provision'`. This
44
+ * one is not. MEASURED from the cluster's own schema on 2026-09-13:
45
+ *
46
+ * GET /cluster/sdn/vnets/{vnet}/subnets/{subnet}
47
+ * -> "Require 'SDN.Audit' or 'SDN.Allocate' permissions on '/sdn/zones/<zone>/<vnet>'"
48
+ *
49
+ * and `GET /access/acl` the same day shows `hf-read@pve` holding the built-in PVEAuditor — whose
50
+ * seven privileges include SDN.Audit — at `/` with propagate=1. So the default 3600s auditor
51
+ * lease reads this family, and a `readRole: 'provision'` here would be privilege nobody needed.
52
+ * Writes are a different answer: POST, PUT and DELETE all require SDN.Allocate on
53
+ * `/sdn/zones/<zone>/<vnet>`, which `LXCProvisioner` gained on 2026-09-13.
54
+ *
55
+ * ⚠️ NO LIVE SUBNET EXISTS ON TB4 TO ROUND-TRIP AGAINST — there are no SDN zones and no vnets, so
56
+ * there can be no subnets. Every claim above is read off PVE 9.2.11's own schema and Perl sources
57
+ * on n2, and the noop argument below rests on those rather than on a plan this file has watched.
58
+ *
59
+ * ⚠️ TWO REFUSALS TO EXPECT, both from `SubnetPlugin::on_update_hook`: PVE will not put a subnet on
60
+ * a vnet with `vlanaware` set ("you can't add a subnet on a vlanaware vnet"), and it rejects a
61
+ * gateway outside the CIDR unless the mask is /32. Both are create-time 400s, not drift.
62
+ */
63
+ import { Resource } from 'alchemy';
64
+ import * as Provider from 'alchemy/Provider';
65
+ import { type PveRequirements, type WithTarget } from './resource.ts';
66
+ import { type DhcpRange } from './sdn-subnet-form.ts';
67
+ export interface SdnSubnetProps extends WithTarget {
68
+ /**
69
+ * The vnet whose bridge carries these addresses. Identity AND a written field.
70
+ *
71
+ * ⛔ MOVING A SUBNET BETWEEN VNETS IS NOT SOMETHING THIS RESOURCE CAN DO, and the symptom is
72
+ * worth knowing before you meet it. The id is built from the zone and the CIDR, so it does not
73
+ * change; but the read goes to `.../vnets/<declared>/subnets/<id>`, and PVE answers a subnet
74
+ * filed under another vnet with `raise_param_exc({ vnet => "wrong vnet" })`. `read` folds that
75
+ * into "absent", reconcile POSTs, and PVE refuses with "sdn subnet object ID ... already
76
+ * defined". Loud and accurate, but it does not converge: change the vnet by removing the
77
+ * declaration and writing a new one.
78
+ */
79
+ vnet: string;
80
+ /**
81
+ * The zone that vnet lives in. ⚠️ PATH INPUT ONLY — PVE accepts no `zone` on a subnet write, and
82
+ * nothing here sends one. It is a prop because the path cannot be spelled without it.
83
+ */
84
+ zone: string;
85
+ /** `10.0.0.0/24`. Identity: PVE builds the id from it, so a new CIDR is a new subnet. */
86
+ cidr: string;
87
+ /** Handed to guests as their default route, and registered in the zone's IPAM as `<vnet>-gw`. */
88
+ gateway?: string;
89
+ /**
90
+ * Masquerade this subnet. ⚠️ INERT UNTIL THE CLUSTER FIREWALL IS ON — PVE's own description is
91
+ * "enable masquerade for this subnet if pve-firewall", and TB4's cluster firewall was empty and
92
+ * disabled when this was written. It still round-trips, so declaring it does not diff.
93
+ */
94
+ snat?: boolean;
95
+ /** `adm` -> `<hostname>.adm.example.internal` for records the zone's DNS plugin registers. */
96
+ dnszoneprefix?: string;
97
+ /** ⚠️ WIRE NAME `dhcp-dns-server`; see the ⚠️ on `isolatePorts` in sdn-vnet.ts about mappings. */
98
+ dhcpDnsServer?: string;
99
+ /**
100
+ * ⛔ ONE POOL, NOT A LIST, AND THE LIMIT IS THE CLIENT'S RATHER THAN PVE'S. `dhcp-range` is a PVE
101
+ * `type => 'array'` parameter, and an array reaches a form-encoded body only as a REPEATED KEY
102
+ * — which `client.ts` cannot express, because `pve()` takes `Record<string, string>` and one
103
+ * key holds one value. A single occurrence works today because `PVE::RESTHandler`'s
104
+ * `$normalize_legacy_param_formats` wraps a scalar into `[$value]` for an array parameter, so
105
+ * the type is declared as one range and a second one is unspellable rather than silently lost.
106
+ * ⛔ THAT COERCION IS MARKED FOR REMOVAL. Its own comment in RESTHandler.pm reads "mark the
107
+ * behaviour deprecated with 9.x, and remove it with 10.x", and this cluster runs 9.2.11 — so on
108
+ * PVE 10 every write carrying a range becomes a hard 400. The fix is not here: it is a form
109
+ * type in client.ts that admits repeated keys.
110
+ * ⚠️ A LIVE SUBNET CARRYING TWO POOLS IS THEREFORE NARROWED TO ONE by the first deploy that
111
+ * declares one. `matches` compares the WHOLE live list, so the narrowing is visible in the plan
112
+ * as an update rather than happening quietly, and it converges.
113
+ */
114
+ dhcpRange?: DhcpRange;
115
+ }
116
+ /**
117
+ * ⛔ NO `digest` HERE, for the reason sdn-zone.ts gives: PVE returns the digest of the WHOLE
118
+ * subnets.cfg, so declaring a SECOND subnet would rewrite this one's stored attributes and
119
+ * comparing it would report an update on a subnet nobody touched.
120
+ */
121
+ export interface SdnSubnetAttributes {
122
+ /** `<zone>-<network>-<mask>` — the path segment, and the name to use in `pvesh`. */
123
+ subnetId: string;
124
+ vnet: string;
125
+ zone: string;
126
+ /** `10.0.0.0/24`, as PVE reassembles it from the id. */
127
+ cidr: string;
128
+ /** Prefix length, so a guest's `ip=10.0.0.5/24` can be built from a reference. */
129
+ mask: number;
130
+ gateway: string;
131
+ snat: boolean;
132
+ dnszoneprefix: string;
133
+ dhcpDnsServer: string;
134
+ /** Normalised and sorted — never compare a raw PVE value to it. See `dhcpRanges`. */
135
+ dhcpRange: string;
136
+ /** ⚠️ THE REMINDER IN THE STATE ITSELF: staged config. No value here says a node has the subnet. */
137
+ readonly staged: true;
138
+ }
139
+ export interface ProxmoxSdnSubnet extends Resource<'Proxmox.SdnSubnet', SdnSubnetProps, SdnSubnetAttributes, never, PveRequirements> {
140
+ }
141
+ /**
142
+ * ⚠️ NO `defaultRemovalPolicy: 'retain'`, UNLIKE THE SEVEN FAMILIES THAT CARRY IT, AND THE ★ IN
143
+ * resource.ts IS THE TEST IT FAILS: a subnet's whole content is a CIDR, a gateway and a pool,
144
+ * which a line of TypeScript rebuilds exactly. The part that is NOT rebuildable is the guest
145
+ * addresses the zone's IPAM handed out, and PVE guards that itself — MEASURED in the built-in
146
+ * `pve` IPAM plugin, which answers a delete with "cannot delete subnet '<cidr>', not empty"
147
+ * whenever anything beyond the gateway still holds an address. That refusal is surfaced as-is.
148
+ */
149
+ export declare const ProxmoxSdnSubnet: import("alchemy").ResourceClass<ProxmoxSdnSubnet>;
150
+ /**
151
+ * ⛔ `list` IS EMPTY LIKE EVERY OTHER RESOURCE HERE. `GET /cluster/sdn/vnets/{vnet}/subnets` answers
152
+ * with every subnet on that bridge, guest addresses and all; adopting one would invite Alchemy to
153
+ * narrow or delete a network nobody declared. Adoption stays an explicit act.
154
+ *
155
+ * ⛔ AND A DELETE IS STAGED TOO, WHICH IS THE HALF PEOPLE FORGET. The section leaves subnets.cfg and
156
+ * Alchemy drops the resource, but the gateway stays on the bridge and DHCP keeps answering until
157
+ * something applies `PUT /cluster/sdn`: a destroy nobody applies reads as complete in the plan and
158
+ * has not happened on the cluster.
159
+ */
160
+ export declare const ProxmoxSdnSubnetProvider: () => import("effect/Layer").Layer<Provider.Provider<ProxmoxSdnSubnet>, never, import("effect/unstable/http/HttpClient").HttpClient>;
161
+ //# sourceMappingURL=sdn-subnet.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sdn-subnet.d.ts","sourceRoot":"","sources":["../../src/proxmox/sdn-subnet.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6DG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAE7C,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,UAAU,EAAe,MAAM,eAAe,CAAC;AACnF,OAAO,EACL,KAAK,SAAS,EAMf,MAAM,sBAAsB,CAAC;AAG9B,MAAM,WAAW,cAAe,SAAQ,UAAU;IAChD;;;;;;;;;;OAUG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,yFAAyF;IACzF,IAAI,EAAE,MAAM,CAAC;IACb,iGAAiG;IACjG,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,8FAA8F;IAC9F,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kGAAkG;IAClG,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;;;;;;;;;;OAcG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAED;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,oFAAoF;IACpF,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,wDAAwD;IACxD,IAAI,EAAE,MAAM,CAAC;IACb,kFAAkF;IAClF,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,qFAAqF;IACrF,SAAS,EAAE,MAAM,CAAC;IAClB,oGAAoG;IACpG,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC;CACvB;AAED,MAAM,WAAW,gBAAiB,SAAQ,QAAQ,CAChD,mBAAmB,EACnB,cAAc,EACd,mBAAmB,EACnB,KAAK,EACL,eAAe,CAChB;CAAG;AAEJ;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,mDAAkD,CAAC;AA4DhF;;;;;;;;;GASG;AACH,eAAO,MAAM,wBAAwB,sIACsD,CAAC"}
@@ -0,0 +1,113 @@
1
+ /**
2
+ * `Proxmox.SdnVnet` — the bridge a guest actually attaches to.
3
+ *
4
+ * ★ THIS IS THE OBJECT THAT CLOSES THE GAP BETWEEN A DECLARED CONTAINER AND A DECLARED NETWORK.
5
+ * `Proxmox.Lxc` takes `net0: name=eth0,bridge=vmbr0,ip=dhcp`, in which the bridge is a string
6
+ * nothing checks. A vnet's id IS the bridge PVE builds on every node of its zone, so declaring
7
+ * the vnet and passing its `bridge` attribute into `net0` turns that string into a reference
8
+ * Alchemy can order and a plan can show.
9
+ *
10
+ * ⚠️ MEASURED: CREATING A VNET CHECKS PERMISSION AT `/sdn/zones/-`, NOT AT THE VNET. The ACL path
11
+ * is the ZONE's, so a vnet whose zone does not exist yet fails as a PERMISSION error rather than
12
+ * as "no such zone" — and you go off widening a role that was never the problem. `zone` is
13
+ * therefore a hard dependency edge, not a convention: pass the zone resource's own attribute so
14
+ * Alchemy creates the zone first. A zone name typed in as a literal buys no ordering at all.
15
+ *
16
+ * ⛔ THE READ-BACK AFTER A WRITE PROVES THE STAGING FILE AND NOTHING MORE — the same trap as
17
+ * `sdn-zone`, and it walks straight through the factory's guard. PVE's SDN endpoints write
18
+ * `/etc/pve/sdn/vnets.cfg`; nothing reaches a node's `/etc/network/interfaces` until
19
+ * `PUT /cluster/sdn` applies the staged config. `pveOperations.reconcile` reads back and refuses
20
+ * when an object is absent, and a vnet that exists only on paper SATISFIES that read: reconcile
21
+ * reports success, the next plan says noop, and no bridge exists anywhere on the cluster.
22
+ * This resource does NOT issue the apply, deliberately. One vnet's reconcile cannot decide to
23
+ * commit every other pending SDN change in the cluster, including ones a human staged in the UI
24
+ * and has not finished. Apply stays an operator's act — `pvesh set /cluster/sdn`.
25
+ *
26
+ * ★ SUBNETS ARE A SIBLING RESOURCE, NOT A FIELD HERE. The gateway and the DHCP ranges guests take
27
+ * addresses from hang off `cluster/sdn/vnets/{vnet}/subnets`, which MEASURED refuses a POST that
28
+ * omits `type` or `subnet` ("parameter verification failed"). Same factory, one path deeper, and
29
+ * it depends on this resource the way this one depends on the zone.
30
+ *
31
+ * ⛔ read/diff NEED SDN.Allocate TOO, NOT SDN.Audit — corrected 2026-09-13 against the cluster's
32
+ * schema. `GET /cluster/sdn/vnets/{vnet}` is checked against SDN.Allocate exactly as the zone
33
+ * item endpoint is, while only the COLLECTION read accepts SDN.Audit. An auditor-shaped `read`
34
+ * lease is therefore refused, and `pveOperations.read` turns that refusal into "absent" rather
35
+ * than an error — see the ⛔ in sdn-zone.ts and docs/privileges.md.
36
+ *
37
+ * ⚠️ PRIVILEGES, AND THE ESTATE'S CREDENTIAL HELD NONE OF THEM UNTIL 2026-09-13. reconcile and
38
+ * delete mint `provision` and need SDN.Allocate on `/sdn/zones`, or on the one zone if scoped. `LXCProvisioner` grants
39
+ * SDN.Use, which is what a GUEST needs in order to attach to a vnet and NOT what creating one
40
+ * needs, so a container declared on this vnet works today while the vnet itself 403s. Widen
41
+ * deliberately, the way Pool.Allocate was:
42
+ * `pveum role modify LXCProvisioner --privs "<existing>,SDN.Allocate,SDN.Audit"` over SSH,
43
+ * preserving every existing privilege.
44
+ */
45
+ import { Resource } from 'alchemy';
46
+ import * as Provider from 'alchemy/Provider';
47
+ import { type PveRequirements, type WithTarget } from './resource.ts';
48
+ export interface SdnVnetProps extends WithTarget {
49
+ /**
50
+ * ⛔ THE PRIMARY KEY AND THE BRIDGE NAME AT ONCE. PVE caps it at eight alphanumeric characters
51
+ * because it becomes a real interface on every node in the zone. There is no rename: a new id
52
+ * is a new bridge, and every guest whose `net0` still names the old one stays on the old one.
53
+ */
54
+ vnet: string;
55
+ /**
56
+ * The SDN zone that owns it. Mutable — a vnet can be moved between zones — but see the ⚠️ at the
57
+ * top of this file: the zone has to exist first, and passing a zone resource's attribute instead
58
+ * of a literal is the only thing that makes Alchemy order them.
59
+ */
60
+ zone: string;
61
+ /** Free text shown in the UI. Mutable; clear it by dropping the prop, never by passing `''`. */
62
+ alias?: string;
63
+ /** VLAN id or VXLAN VNI, depending on the zone's type. Mutable. Absent means untagged. */
64
+ tag?: number;
65
+ /** Let guests on this bridge carry their own VLAN tags. Mutable. */
66
+ vlanaware?: boolean;
67
+ /**
68
+ * Stop guests on this bridge from reaching each other directly. Mutable.
69
+ * ⚠️ The wire name is `isolate-ports`, with a hyphen — see the ⚠️ on `shape` for why that costs
70
+ * attention in two places rather than one.
71
+ */
72
+ isolatePorts?: boolean;
73
+ }
74
+ export interface SdnVnetAttributes {
75
+ vnet: string;
76
+ /**
77
+ * The same string as `vnet`, duplicated on purpose: it is the name a guest's `net0` must carry.
78
+ * Referencing it from a `Proxmox.Lxc`'s props is what makes Alchemy build the network before the
79
+ * container. A hardcoded `vmbr1` in `net0` is a string nothing checks and nothing orders.
80
+ */
81
+ bridge: string;
82
+ zone: string;
83
+ alias: string;
84
+ /**
85
+ * Absent when the vnet is untagged — see `tagOf` for why this is optional and not `0`.
86
+ * ⚠️ `| undefined` IS LOAD-BEARING under exactOptionalPropertyTypes: the attributes
87
+ * builder always sets this key, writing `undefined` for an untagged vnet, so the type
88
+ * must permit a present-but-undefined value as well as an absent one. Without it the
89
+ * read path does not typecheck, and 0 is a real VLAN id so it cannot be the sentinel.
90
+ */
91
+ tag?: number | undefined;
92
+ vlanaware: boolean;
93
+ isolatePorts: boolean;
94
+ }
95
+ export interface ProxmoxSdnVnet extends Resource<'Proxmox.SdnVnet', SdnVnetProps, SdnVnetAttributes, never, PveRequirements> {
96
+ }
97
+ export declare const ProxmoxSdnVnet: import("alchemy").ResourceClass<ProxmoxSdnVnet>;
98
+ /**
99
+ * ⛔ EMPTY, LIKE EVERY OTHER RESOURCE IN THIS PACKAGE. `GET /cluster/sdn/vnets` answers
100
+ * with every vnet on the cluster, and on an estate already running SDN those are
101
+ * load-bearing bridges with guests on them. Returning them would invite Alchemy to
102
+ * adopt — and therefore one day delete — a network nobody declared here. Adoption is an
103
+ * explicit act.
104
+
105
+ *
106
+ * ⛔ A DELETE IS STAGED LIKE EVERY OTHER SDN WRITE. The vnet leaves `vnets.cfg` at once and
107
+ * the bridge stays up on every node until `PUT /cluster/sdn` applies the removal, so a
108
+ * plan reporting "1 deleted" has taken nothing off the network yet. Nothing here applies
109
+ * on the operator's behalf: see the ⛔ at the top of this file.
110
+
111
+ */
112
+ export declare const ProxmoxSdnVnetProvider: () => import("effect/Layer").Layer<Provider.Provider<ProxmoxSdnVnet>, never, import("effect/unstable/http/HttpClient").HttpClient>;
113
+ //# sourceMappingURL=sdn-vnet.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sdn-vnet.d.ts","sourceRoot":"","sources":["../../src/proxmox/sdn-vnet.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAE7C,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,UAAU,EAAe,MAAM,eAAe,CAAC;AAGnF,MAAM,WAAW,YAAa,SAAQ,UAAU;IAC9C;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,gGAAgG;IAChG,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0FAA0F;IAC1F,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,oEAAoE;IACpE,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd;;;;;;OAMG;IACH,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,cAAe,SAAQ,QAAQ,CAC9C,iBAAiB,EACjB,YAAY,EACZ,iBAAiB,EACjB,KAAK,EACL,eAAe,CAChB;CAAG;AAEJ,eAAO,MAAM,cAAc,iDAA8C,CAAC;AAyG1E;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,sBAAsB,oIACoD,CAAC"}