@homeflare/alchemy 0.38.0 → 0.40.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 (353) hide show
  1. package/README.md +32 -8
  2. package/dist/ceph/auth-entity.d.ts +34 -0
  3. package/dist/ceph/auth-entity.d.ts.map +1 -0
  4. package/dist/ceph/ceph-argv-config.d.ts +10 -0
  5. package/dist/ceph/ceph-argv-config.d.ts.map +1 -0
  6. package/dist/ceph/ceph-argv.d.ts +19 -0
  7. package/dist/ceph/ceph-argv.d.ts.map +1 -0
  8. package/dist/ceph/ceph-auth-form.d.ts +54 -0
  9. package/dist/ceph/ceph-auth-form.d.ts.map +1 -0
  10. package/dist/ceph/ceph-auth-parse.d.ts +56 -0
  11. package/dist/ceph/ceph-auth-parse.d.ts.map +1 -0
  12. package/dist/ceph/ceph-auth-reconcile.d.ts +35 -0
  13. package/dist/ceph/ceph-auth-reconcile.d.ts.map +1 -0
  14. package/dist/ceph/ceph-config-options.d.ts +23 -0
  15. package/dist/ceph/ceph-config-options.d.ts.map +1 -0
  16. package/dist/ceph/ceph-key-leak-assert.d.ts +25 -0
  17. package/dist/ceph/ceph-key-leak-assert.d.ts.map +1 -0
  18. package/dist/ceph/ceph-transport.d.ts +37 -0
  19. package/dist/ceph/ceph-transport.d.ts.map +1 -0
  20. package/dist/ceph/fake-ceph-dial.d.ts +35 -0
  21. package/dist/ceph/fake-ceph-dial.d.ts.map +1 -0
  22. package/dist/ceph/index.d.ts +13 -0
  23. package/dist/ceph/index.d.ts.map +1 -0
  24. package/dist/ceph/index.js +1609 -0
  25. package/dist/ceph/index.js.map +38 -0
  26. package/dist/forgejo/index.js +4 -2
  27. package/dist/forgejo/index.js.map +3 -3
  28. package/dist/forgejo/team-member.d.ts +25 -0
  29. package/dist/forgejo/team-member.d.ts.map +1 -1
  30. package/dist/index.d.ts +1 -0
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/proxmox/generated/constraints/index.d.ts +1 -1
  33. package/dist/proxmox/generated/constraints/index.d.ts.map +1 -1
  34. package/dist/proxmox/generated/constraints/pve-access.d.ts +1 -1
  35. package/dist/proxmox/generated/constraints/pve-cluster-backup.d.ts +1 -1
  36. package/dist/proxmox/generated/constraints/pve-cluster-ceph.d.ts +1 -1
  37. package/dist/proxmox/generated/constraints/pve-cluster-firewall.d.ts +1 -1
  38. package/dist/proxmox/generated/constraints/pve-cluster-ha.d.ts +1 -1
  39. package/dist/proxmox/generated/constraints/pve-cluster-metrics.d.ts +1 -1
  40. package/dist/proxmox/generated/constraints/pve-cluster-notifications.d.ts +1 -1
  41. package/dist/proxmox/generated/constraints/pve-cluster-replication.d.ts +1 -1
  42. package/dist/proxmox/generated/constraints/pve-cluster-sdn.d.ts +1 -1
  43. package/dist/proxmox/generated/constraints/pve-nodes-ceph.d.ts +1 -1
  44. package/dist/proxmox/generated/constraints/pve-nodes-disks.d.ts +1 -1
  45. package/dist/proxmox/generated/constraints/pve-nodes-lxc.d.ts +1 -1
  46. package/dist/proxmox/generated/constraints/pve-nodes-network.d.ts +1 -1
  47. package/dist/proxmox/generated/constraints/pve-nodes-qemu.d.ts +1 -1
  48. package/dist/proxmox/generated/constraints/pve-nodes-storage.d.ts +23 -0
  49. package/dist/proxmox/generated/constraints/pve-nodes-storage.d.ts.map +1 -0
  50. package/dist/proxmox/generated/constraints/pve-pools.d.ts +1 -1
  51. package/dist/proxmox/generated/constraints/pve-storage.d.ts +1 -1
  52. package/dist/proxmox/index.d.ts +14 -3
  53. package/dist/proxmox/index.d.ts.map +1 -1
  54. package/dist/proxmox/index.js +574 -133
  55. package/dist/proxmox/index.js.map +33 -23
  56. package/dist/proxmox/qemu-form.d.ts +27 -18
  57. package/dist/proxmox/qemu-form.d.ts.map +1 -1
  58. package/dist/proxmox/qemu-judge.d.ts +30 -0
  59. package/dist/proxmox/qemu-judge.d.ts.map +1 -0
  60. package/dist/proxmox/qemu-lifecycle.d.ts +16 -2
  61. package/dist/proxmox/qemu-lifecycle.d.ts.map +1 -1
  62. package/dist/proxmox/qemu-net.d.ts +9 -0
  63. package/dist/proxmox/qemu-net.d.ts.map +1 -0
  64. package/dist/proxmox/qemu-props.d.ts +112 -0
  65. package/dist/proxmox/qemu-props.d.ts.map +1 -0
  66. package/dist/proxmox/qemu-volume.d.ts +27 -0
  67. package/dist/proxmox/qemu-volume.d.ts.map +1 -0
  68. package/dist/proxmox/qemu.d.ts +14 -27
  69. package/dist/proxmox/qemu.d.ts.map +1 -1
  70. package/dist/proxmox/storage-download-errors.d.ts +5 -0
  71. package/dist/proxmox/storage-download-errors.d.ts.map +1 -0
  72. package/dist/proxmox/storage-download-identity.d.ts +27 -0
  73. package/dist/proxmox/storage-download-identity.d.ts.map +1 -0
  74. package/dist/proxmox/storage-download-lifecycle.d.ts +97 -0
  75. package/dist/proxmox/storage-download-lifecycle.d.ts.map +1 -0
  76. package/dist/proxmox/storage-download-props.d.ts +36 -0
  77. package/dist/proxmox/storage-download-props.d.ts.map +1 -0
  78. package/dist/proxmox/storage-download-task.d.ts +17 -0
  79. package/dist/proxmox/storage-download-task.d.ts.map +1 -0
  80. package/dist/proxmox/storage-download.d.ts +44 -0
  81. package/dist/proxmox/storage-download.d.ts.map +1 -0
  82. package/dist/talos/credentials-write.d.ts +46 -0
  83. package/dist/talos/credentials-write.d.ts.map +1 -0
  84. package/dist/talos/credentials.d.ts +51 -9
  85. package/dist/talos/credentials.d.ts.map +1 -1
  86. package/dist/talos/fake-process.d.ts +56 -0
  87. package/dist/talos/fake-process.d.ts.map +1 -0
  88. package/dist/talos/index.d.ts +19 -4
  89. package/dist/talos/index.d.ts.map +1 -1
  90. package/dist/talos/index.js +357 -173
  91. package/dist/talos/index.js.map +16 -10
  92. package/dist/talos/kubeconfig-attrs.d.ts +4 -0
  93. package/dist/talos/kubeconfig-attrs.d.ts.map +1 -0
  94. package/dist/talos/kubeconfig.d.ts +41 -23
  95. package/dist/talos/kubeconfig.d.ts.map +1 -1
  96. package/dist/talos/machine-config-fixtures.d.ts +60 -0
  97. package/dist/talos/machine-config-fixtures.d.ts.map +1 -0
  98. package/dist/talos/machine-config-poll.d.ts +43 -0
  99. package/dist/talos/machine-config-poll.d.ts.map +1 -0
  100. package/dist/talos/machine-config-read.d.ts +49 -0
  101. package/dist/talos/machine-config-read.d.ts.map +1 -0
  102. package/dist/talos/resource.d.ts +18 -0
  103. package/dist/talos/resource.d.ts.map +1 -1
  104. package/dist/talos/talos-bootstrap-etcd.d.ts +38 -0
  105. package/dist/talos/talos-bootstrap-etcd.d.ts.map +1 -0
  106. package/dist/talos/talos-bootstrap.d.ts +87 -0
  107. package/dist/talos/talos-bootstrap.d.ts.map +1 -1
  108. package/dist/talos/talos-cluster-health.d.ts +43 -1
  109. package/dist/talos/talos-cluster-health.d.ts.map +1 -1
  110. package/dist/talos/talos-errors.d.ts +68 -0
  111. package/dist/talos/talos-errors.d.ts.map +1 -0
  112. package/dist/talos/talos-machine-config.d.ts +51 -15
  113. package/dist/talos/talos-machine-config.d.ts.map +1 -1
  114. package/dist/talos/talosctl.d.ts +7 -0
  115. package/dist/talos/talosctl.d.ts.map +1 -1
  116. package/dist/talos/values.d.ts +23 -3
  117. package/dist/talos/values.d.ts.map +1 -1
  118. package/dist/telemetry/fake-collector.d.ts +36 -0
  119. package/dist/telemetry/fake-collector.d.ts.map +1 -0
  120. package/dist/telemetry/index.d.ts +11 -0
  121. package/dist/telemetry/index.d.ts.map +1 -0
  122. package/dist/telemetry/index.js +223 -0
  123. package/dist/telemetry/index.js.map +12 -0
  124. package/dist/telemetry/layer.d.ts +86 -0
  125. package/dist/telemetry/layer.d.ts.map +1 -0
  126. package/dist/telemetry/redact-serialization.d.ts +21 -0
  127. package/dist/telemetry/redact-serialization.d.ts.map +1 -0
  128. package/dist/telemetry/redact.d.ts +46 -0
  129. package/dist/telemetry/redact.d.ts.map +1 -0
  130. package/dist/unifi/acl-rule-drift.d.ts +22 -0
  131. package/dist/unifi/acl-rule-drift.d.ts.map +1 -0
  132. package/dist/unifi/acl-rule-form.d.ts +90 -0
  133. package/dist/unifi/acl-rule-form.d.ts.map +1 -0
  134. package/dist/unifi/acl-rule-ordering-form.d.ts +49 -0
  135. package/dist/unifi/acl-rule-ordering-form.d.ts.map +1 -0
  136. package/dist/unifi/acl-rule-ordering.d.ts +54 -0
  137. package/dist/unifi/acl-rule-ordering.d.ts.map +1 -0
  138. package/dist/unifi/acl-rule.d.ts +49 -0
  139. package/dist/unifi/acl-rule.d.ts.map +1 -0
  140. package/dist/unifi/dns-policy-drift.d.ts +21 -0
  141. package/dist/unifi/dns-policy-drift.d.ts.map +1 -0
  142. package/dist/unifi/dns-policy-form.d.ts +97 -0
  143. package/dist/unifi/dns-policy-form.d.ts.map +1 -0
  144. package/dist/unifi/dns-policy.d.ts +55 -0
  145. package/dist/unifi/dns-policy.d.ts.map +1 -0
  146. package/dist/unifi/drift.d.ts +27 -0
  147. package/dist/unifi/drift.d.ts.map +1 -0
  148. package/dist/unifi/fake-unifi.d.ts +5 -1
  149. package/dist/unifi/fake-unifi.d.ts.map +1 -1
  150. package/dist/unifi/firewall-policy-drift.d.ts +26 -0
  151. package/dist/unifi/firewall-policy-drift.d.ts.map +1 -0
  152. package/dist/unifi/firewall-policy-form.d.ts +102 -0
  153. package/dist/unifi/firewall-policy-form.d.ts.map +1 -0
  154. package/dist/unifi/firewall-policy-ordering-form.d.ts +66 -0
  155. package/dist/unifi/firewall-policy-ordering-form.d.ts.map +1 -0
  156. package/dist/unifi/firewall-policy-ordering.d.ts +57 -0
  157. package/dist/unifi/firewall-policy-ordering.d.ts.map +1 -0
  158. package/dist/unifi/firewall-policy.d.ts +57 -0
  159. package/dist/unifi/firewall-policy.d.ts.map +1 -0
  160. package/dist/unifi/firewall-zone-form.d.ts +6 -0
  161. package/dist/unifi/firewall-zone-form.d.ts.map +1 -1
  162. package/dist/unifi/firewall-zone.d.ts +1 -1
  163. package/dist/unifi/firewall-zone.d.ts.map +1 -1
  164. package/dist/unifi/index.d.ts +11 -3
  165. package/dist/unifi/index.d.ts.map +1 -1
  166. package/dist/unifi/index.js +725 -60
  167. package/dist/unifi/index.js.map +31 -9
  168. package/dist/unifi/network-drift.d.ts +26 -0
  169. package/dist/unifi/network-drift.d.ts.map +1 -0
  170. package/dist/unifi/network-form.d.ts +40 -7
  171. package/dist/unifi/network-form.d.ts.map +1 -1
  172. package/dist/unifi/network.d.ts +1 -0
  173. package/dist/unifi/network.d.ts.map +1 -1
  174. package/dist/unifi/paginate.d.ts +24 -0
  175. package/dist/unifi/paginate.d.ts.map +1 -0
  176. package/dist/unifi/providers.d.ts +1 -1
  177. package/dist/unifi/providers.d.ts.map +1 -1
  178. package/dist/unifi/resource.d.ts +36 -1
  179. package/dist/unifi/resource.d.ts.map +1 -1
  180. package/dist/unifi/scan-source.d.ts +11 -0
  181. package/dist/unifi/scan-source.d.ts.map +1 -0
  182. package/dist/unifi/traffic-matching-list-drift.d.ts +22 -0
  183. package/dist/unifi/traffic-matching-list-drift.d.ts.map +1 -0
  184. package/dist/unifi/traffic-matching-list-form.d.ts +56 -0
  185. package/dist/unifi/traffic-matching-list-form.d.ts.map +1 -0
  186. package/dist/unifi/traffic-matching-list.d.ts +51 -0
  187. package/dist/unifi/traffic-matching-list.d.ts.map +1 -0
  188. package/dist/unifi/wifi-broadcast-drift.d.ts +22 -0
  189. package/dist/unifi/wifi-broadcast-drift.d.ts.map +1 -0
  190. package/dist/unifi/wifi-broadcast-form.d.ts +127 -0
  191. package/dist/unifi/wifi-broadcast-form.d.ts.map +1 -0
  192. package/dist/unifi/wifi-broadcast.d.ts +73 -0
  193. package/dist/unifi/wifi-broadcast.d.ts.map +1 -0
  194. package/docs/telemetry-spike.md +94 -0
  195. package/docs/telemetry.md +109 -0
  196. package/docs/unifi-acl-rule.md +122 -0
  197. package/docs/unifi-dns-policy.md +75 -0
  198. package/docs/unifi-firewall-policy.md +109 -0
  199. package/docs/unifi-traffic-matching-list.md +82 -0
  200. package/docs/unifi-wifi.md +120 -0
  201. package/docs/unifi.md +64 -3
  202. package/package.json +10 -2
  203. package/src/ceph/auth-entity.ts +74 -0
  204. package/src/ceph/ceph-argv-config.ts +78 -0
  205. package/src/ceph/ceph-argv.test.ts +226 -0
  206. package/src/ceph/ceph-argv.ts +189 -0
  207. package/src/ceph/ceph-auth-form.test.ts +103 -0
  208. package/src/ceph/ceph-auth-form.ts +107 -0
  209. package/src/ceph/ceph-auth-parse.test.ts +155 -0
  210. package/src/ceph/ceph-auth-parse.ts +121 -0
  211. package/src/ceph/ceph-auth-reconcile-secrecy.test.ts +82 -0
  212. package/src/ceph/ceph-auth-reconcile.test.ts +233 -0
  213. package/src/ceph/ceph-auth-reconcile.ts +119 -0
  214. package/src/ceph/ceph-config-options.test.ts +44 -0
  215. package/src/ceph/ceph-config-options.ts +36 -0
  216. package/src/ceph/ceph-key-leak-assert.ts +35 -0
  217. package/src/ceph/ceph-no-output-logging.test.ts +52 -0
  218. package/src/ceph/ceph-transport.test.ts +125 -0
  219. package/src/ceph/ceph-transport.ts +117 -0
  220. package/src/ceph/fake-ceph-dial.ts +55 -0
  221. package/src/ceph/index.ts +12 -0
  222. package/src/forgejo/team-member.test.ts +14 -0
  223. package/src/forgejo/team-member.ts +28 -1
  224. package/src/index.ts +1 -0
  225. package/src/proxmox/constraints-required.test.ts +1 -0
  226. package/src/proxmox/generated/constraints/index.ts +3 -1
  227. package/src/proxmox/generated/constraints/pve-access.ts +1 -1
  228. package/src/proxmox/generated/constraints/pve-cluster-backup.ts +1 -1
  229. package/src/proxmox/generated/constraints/pve-cluster-ceph.ts +1 -1
  230. package/src/proxmox/generated/constraints/pve-cluster-firewall.ts +1 -1
  231. package/src/proxmox/generated/constraints/pve-cluster-ha.ts +1 -1
  232. package/src/proxmox/generated/constraints/pve-cluster-metrics.ts +1 -1
  233. package/src/proxmox/generated/constraints/pve-cluster-notifications.ts +1 -1
  234. package/src/proxmox/generated/constraints/pve-cluster-replication.ts +1 -1
  235. package/src/proxmox/generated/constraints/pve-cluster-sdn.ts +1 -1
  236. package/src/proxmox/generated/constraints/pve-nodes-ceph.ts +1 -1
  237. package/src/proxmox/generated/constraints/pve-nodes-disks.ts +1 -1
  238. package/src/proxmox/generated/constraints/pve-nodes-lxc.ts +1 -1
  239. package/src/proxmox/generated/constraints/pve-nodes-network.ts +1 -1
  240. package/src/proxmox/generated/constraints/pve-nodes-qemu.ts +1 -1
  241. package/src/proxmox/generated/constraints/pve-nodes-storage.ts +30 -0
  242. package/src/proxmox/generated/constraints/pve-pools.ts +1 -1
  243. package/src/proxmox/generated/constraints/pve-storage.ts +1 -1
  244. package/src/proxmox/index.test.ts +11 -6
  245. package/src/proxmox/index.ts +19 -3
  246. package/src/proxmox/qemu-form.ts +49 -13
  247. package/src/proxmox/qemu-identity.test.ts +30 -0
  248. package/src/proxmox/qemu-judge.test.ts +65 -0
  249. package/src/proxmox/qemu-judge.ts +84 -0
  250. package/src/proxmox/qemu-lifecycle.test.ts +78 -19
  251. package/src/proxmox/qemu-lifecycle.ts +131 -32
  252. package/src/proxmox/qemu-net.test.ts +48 -0
  253. package/src/proxmox/qemu-net.ts +78 -0
  254. package/src/proxmox/qemu-ownership.test.ts +44 -0
  255. package/src/proxmox/qemu-props.test.ts +87 -0
  256. package/src/proxmox/qemu-props.ts +157 -0
  257. package/src/proxmox/qemu-volume.test.ts +229 -0
  258. package/src/proxmox/qemu-volume.ts +178 -0
  259. package/src/proxmox/qemu.ts +15 -29
  260. package/src/proxmox/storage-download-errors.ts +7 -0
  261. package/src/proxmox/storage-download-identity.test.ts +54 -0
  262. package/src/proxmox/storage-download-identity.ts +50 -0
  263. package/src/proxmox/storage-download-lifecycle.ts +226 -0
  264. package/src/proxmox/storage-download-ownership.test.ts +50 -0
  265. package/src/proxmox/storage-download-props.ts +38 -0
  266. package/src/proxmox/storage-download-task.ts +72 -0
  267. package/src/proxmox/storage-download.test.ts +216 -0
  268. package/src/proxmox/storage-download.ts +58 -0
  269. package/src/talos/credentials-write.test.ts +81 -0
  270. package/src/talos/credentials-write.ts +95 -0
  271. package/src/talos/credentials.test.ts +157 -0
  272. package/src/talos/credentials.ts +160 -90
  273. package/src/talos/fake-process.ts +94 -0
  274. package/src/talos/index.ts +39 -4
  275. package/src/talos/kubeconfig-attrs.ts +55 -0
  276. package/src/talos/kubeconfig.test.ts +256 -0
  277. package/src/talos/kubeconfig.ts +170 -90
  278. package/src/talos/machine-config-fixtures.ts +86 -0
  279. package/src/talos/machine-config-poll.test.ts +57 -0
  280. package/src/talos/machine-config-poll.ts +82 -0
  281. package/src/talos/machine-config-read.ts +118 -0
  282. package/src/talos/resource.ts +19 -0
  283. package/src/talos/secrets-gate.test.ts +63 -0
  284. package/src/talos/talos-bootstrap-etcd.ts +71 -0
  285. package/src/talos/talos-bootstrap.test.ts +218 -0
  286. package/src/talos/talos-bootstrap.ts +151 -45
  287. package/src/talos/talos-cluster-health.test.ts +143 -0
  288. package/src/talos/talos-cluster-health.ts +91 -28
  289. package/src/talos/talos-errors.ts +85 -0
  290. package/src/talos/talos-machine-config.test.ts +189 -0
  291. package/src/talos/talos-machine-config.ts +102 -88
  292. package/src/talos/talosctl.ts +8 -0
  293. package/src/talos/values.test.ts +34 -6
  294. package/src/talos/values.ts +41 -7
  295. package/src/telemetry/fake-collector.ts +59 -0
  296. package/src/telemetry/http-client-sealing.test.ts +82 -0
  297. package/src/telemetry/index.ts +10 -0
  298. package/src/telemetry/layer.test.ts +204 -0
  299. package/src/telemetry/layer.ts +152 -0
  300. package/src/telemetry/redact-serialization.ts +178 -0
  301. package/src/telemetry/redact.test.ts +124 -0
  302. package/src/telemetry/redact.ts +147 -0
  303. package/src/unifi/acl-rule-drift.ts +57 -0
  304. package/src/unifi/acl-rule-form.ts +135 -0
  305. package/src/unifi/acl-rule-ordering-form.ts +79 -0
  306. package/src/unifi/acl-rule-ordering.test.ts +141 -0
  307. package/src/unifi/acl-rule-ordering.ts +70 -0
  308. package/src/unifi/acl-rule.test.ts +183 -0
  309. package/src/unifi/acl-rule.ts +61 -0
  310. package/src/unifi/discriminated-filter-decode.test.ts +134 -0
  311. package/src/unifi/dns-policy-drift.ts +48 -0
  312. package/src/unifi/dns-policy-form.ts +142 -0
  313. package/src/unifi/dns-policy.test.ts +154 -0
  314. package/src/unifi/dns-policy.ts +67 -0
  315. package/src/unifi/drift.test.ts +78 -0
  316. package/src/unifi/drift.ts +56 -0
  317. package/src/unifi/errors-and-secrets.test.ts +127 -0
  318. package/src/unifi/fake-unifi.ts +5 -1
  319. package/src/unifi/firewall-policy-drift.test.ts +151 -0
  320. package/src/unifi/firewall-policy-drift.ts +55 -0
  321. package/src/unifi/firewall-policy-filter-roundtrip.test.ts +143 -0
  322. package/src/unifi/firewall-policy-form.ts +146 -0
  323. package/src/unifi/firewall-policy-ordering-form.ts +111 -0
  324. package/src/unifi/firewall-policy-ordering.test.ts +185 -0
  325. package/src/unifi/firewall-policy-ordering.ts +87 -0
  326. package/src/unifi/firewall-policy.test.ts +183 -0
  327. package/src/unifi/firewall-policy.ts +73 -0
  328. package/src/unifi/firewall-zone-form.ts +31 -2
  329. package/src/unifi/firewall-zone.test.ts +21 -1
  330. package/src/unifi/firewall-zone.ts +1 -1
  331. package/src/unifi/get-only-guard.test.ts +165 -0
  332. package/src/unifi/index.ts +78 -1
  333. package/src/unifi/network-drift.test.ts +207 -0
  334. package/src/unifi/network-drift.ts +80 -0
  335. package/src/unifi/network-form.ts +11 -39
  336. package/src/unifi/network.test.ts +7 -82
  337. package/src/unifi/network.ts +6 -6
  338. package/src/unifi/paginate.test.ts +252 -0
  339. package/src/unifi/paginate.ts +141 -0
  340. package/src/unifi/providers.ts +19 -1
  341. package/src/unifi/resource.ts +73 -3
  342. package/src/unifi/scan-source.ts +64 -0
  343. package/src/unifi/traffic-matching-list-drift.ts +40 -0
  344. package/src/unifi/traffic-matching-list-form.ts +77 -0
  345. package/src/unifi/traffic-matching-list.test.ts +202 -0
  346. package/src/unifi/traffic-matching-list.ts +78 -0
  347. package/src/unifi/wifi-broadcast-details-call.test.ts +92 -0
  348. package/src/unifi/wifi-broadcast-drift.ts +69 -0
  349. package/src/unifi/wifi-broadcast-form.ts +211 -0
  350. package/src/unifi/wifi-broadcast-secrets.test.ts +145 -0
  351. package/src/unifi/wifi-broadcast.test.ts +155 -0
  352. package/src/unifi/wifi-broadcast.ts +90 -0
  353. package/src/unifi/write-op-reference.test.ts +190 -0
@@ -677,6 +677,16 @@ var PVE_NODES_QEMU_CONSTRAINTS = {
677
677
  }
678
678
  };
679
679
 
680
+ // src/proxmox/generated/constraints/pve-nodes-storage.ts
681
+ var PVE_NODES_STORAGE_CONSTRAINTS = {
682
+ "pve:POST /nodes/{node}/storage/{storage}/download-url": {
683
+ "checksum-algorithm": { enum: ["md5", "sha1", "sha224", "sha256", "sha384", "sha512"], type: "string" },
684
+ content: { enum: ["iso", "vztmpl", "import"], format: "pve-storage-content", required: true, type: "string" },
685
+ filename: { maxLength: 255, required: true, type: "string" },
686
+ url: { pattern: "^https?://.*\\n?$", patternSource: "https?://.*", required: true, type: "string" }
687
+ }
688
+ };
689
+
680
690
  // src/proxmox/generated/constraints/pve-pools.ts
681
691
  var PVE_POOLS_CONSTRAINTS = {
682
692
  "pve:POST /pools": {
@@ -947,6 +957,7 @@ var PROXMOX_CONSTRAINTS = {
947
957
  ...PVE_NODES_LXC_CONSTRAINTS,
948
958
  ...PVE_NODES_NETWORK_CONSTRAINTS,
949
959
  ...PVE_NODES_QEMU_CONSTRAINTS,
960
+ ...PVE_NODES_STORAGE_CONSTRAINTS,
950
961
  ...PVE_POOLS_CONSTRAINTS,
951
962
  ...PVE_STORAGE_CONSTRAINTS,
952
963
  ...PBS_CONFIG_CONSTRAINTS
@@ -5961,16 +5972,66 @@ import { isResolved as isResolved26 } from "alchemy/Diff";
5961
5972
  import * as nodes17 from "@distilled.cloud/proxmox/nodes";
5962
5973
  import * as Effect84 from "effect/Effect";
5963
5974
 
5975
+ // src/proxmox/qemu-props.ts
5976
+ var NOT_CONFIG2 = new Set(["node", "target", "vmid"]);
5977
+ var INDEXED2 = {
5978
+ ide: 4,
5979
+ ipconfig: 32,
5980
+ net: 32,
5981
+ scsi: 31,
5982
+ serial: 4
5983
+ };
5984
+ var indexedKey2 = (key) => {
5985
+ const match = /^(ide|ipconfig|net|scsi|serial)(0|[1-9]\d*)$/.exec(key);
5986
+ if (match === null)
5987
+ return;
5988
+ const family = match[1];
5989
+ const index = Number(match[2]);
5990
+ return index < INDEXED2[family] ? [family, index] : undefined;
5991
+ };
5992
+ var SCALAR_KEYS = new Set([
5993
+ "agent",
5994
+ "boot",
5995
+ "cores",
5996
+ "cpu",
5997
+ "memory",
5998
+ "name",
5999
+ "onboot",
6000
+ "scsihw",
6001
+ "sockets"
6002
+ ]);
6003
+ var isManagedKey2 = (key) => SCALAR_KEYS.has(key) || indexedKey2(key) !== undefined;
6004
+ var declaredValue2 = (props, key) => props[key];
6005
+ var declaredKeys2 = (props) => Object.keys(props).filter((key) => !NOT_CONFIG2.has(key) && declaredValue2(props, key) !== undefined).sort();
6006
+ var wireValue2 = (value) => value === true ? "1" : value === false ? "0" : String(value);
6007
+ var storedConfig2 = (live) => {
6008
+ const out = {};
6009
+ for (const [key, value] of Object.entries(live)) {
6010
+ if (!isManagedKey2(key))
6011
+ continue;
6012
+ if (value === null || value === undefined || typeof value === "object")
6013
+ continue;
6014
+ out[key] = wireValue2(value);
6015
+ }
6016
+ return out;
6017
+ };
6018
+
5964
6019
  // src/proxmox/qemu-form.ts
5965
- var shape9 = (props) => ({
5966
- cores: String(props.cores ?? 1),
5967
- memory: String(props.memory ?? 512),
5968
- name: props.name ?? `vm${String(props.vmid)}`,
5969
- onboot: props.onboot === true ? "1" : "0",
5970
- sockets: String(props.sockets ?? 1),
5971
- ...props.net0 === undefined ? {} : { net0: props.net0 }
6020
+ var formRefusals = (props) => declaredKeys2(props).filter((key) => !isManagedKey2(key)).map((key) => `${key}: not a config key this resource manages (vmid ${String(props.vmid)}).`);
6021
+ var form = (props) => {
6022
+ const out = {};
6023
+ for (const key of declaredKeys2(props)) {
6024
+ if (!isManagedKey2(key))
6025
+ continue;
6026
+ out[key] = wireValue2(declaredValue2(props, key));
6027
+ }
6028
+ return out;
6029
+ };
6030
+ var createForm9 = (props) => ({
6031
+ ...form(props),
6032
+ vmid: String(props.vmid)
5972
6033
  });
5973
- var createForm9 = (props) => ({ ...shape9(props), vmid: String(props.vmid) });
6034
+ var updateForm6 = form;
5974
6035
 
5975
6036
  // src/proxmox/qemu-errors.ts
5976
6037
  class QemuRefusedError extends Error {
@@ -5980,6 +6041,161 @@ class QemuRefusedError extends Error {
5980
6041
  }
5981
6042
  }
5982
6043
 
6044
+ // src/proxmox/qemu-volume.ts
6045
+ var NEW_DISK2 = /^([^:\s]+):(\d+(?:\.\d+)?)$/;
6046
+ var NEW_CLOUDINIT = /^([^:\s]+):cloudinit$/;
6047
+ var parseDisk = (text3) => {
6048
+ const bare = NEW_DISK2.exec(text3) ?? NEW_CLOUDINIT.exec(text3);
6049
+ if (bare !== null) {
6050
+ return {
6051
+ kind: "fresh",
6052
+ options: new Map,
6053
+ size: undefined,
6054
+ source: bare[1] ?? "",
6055
+ volname: ""
6056
+ };
6057
+ }
6058
+ const [first, ...rest] = text3.split(",");
6059
+ const at = (first ?? "").indexOf(":");
6060
+ const source = at === -1 ? first ?? "" : (first ?? "").slice(0, at);
6061
+ const volname = at === -1 ? "" : (first ?? "").slice(at + 1);
6062
+ const options = new Map(rest.map((part) => {
6063
+ const eq = part.indexOf("=");
6064
+ return eq === -1 ? [part, ""] : [part.slice(0, eq), part.slice(eq + 1)];
6065
+ }));
6066
+ const size = options.get("size");
6067
+ options.delete("size");
6068
+ if (volname === "0" && options.has("import-from")) {
6069
+ options.delete("import-from");
6070
+ return { kind: "fresh", options, size: undefined, source, volname: "" };
6071
+ }
6072
+ return { kind: "volume", options, size, source, volname };
6073
+ };
6074
+ var printOptions = (source, volname, options, size) => [
6075
+ `${source}:${volname}`,
6076
+ ...[...options].map(([k, v]) => `${k}=${v}`),
6077
+ ...size === undefined ? [] : [`size=${size}`]
6078
+ ].join(",");
6079
+ var judgeDisk = (key, declared2, live) => {
6080
+ const want = parseDisk(declared2);
6081
+ const have = parseDisk(live);
6082
+ if (want.source !== have.source) {
6083
+ return {
6084
+ refuse: `${key}: the volume is on ${have.source}, declared on ${want.source}. Moving a disk ` + "between storages is not an update this resource makes -- move it by hand, then declare it."
6085
+ };
6086
+ }
6087
+ if (want.kind === "fresh") {
6088
+ if (want.options.size === 0)
6089
+ return {};
6090
+ if ([...want.options].every(([k, v]) => have.options.get(k) === v))
6091
+ return {};
6092
+ return { put: printOptions(have.source, have.volname, want.options, have.size) };
6093
+ }
6094
+ if (want.volname !== have.volname) {
6095
+ return {
6096
+ refuse: `${key}: declared volume ${want.volname} is not the live ${have.volname}. Writing it ` + "would detach the live volume to unusedN; attach or swap volumes by hand."
6097
+ };
6098
+ }
6099
+ if (want.size !== undefined && have.size !== undefined && want.size !== have.size) {
6100
+ return {
6101
+ refuse: `${key}: declared size ${want.size} differs from the live ${have.size}. This resource does ` + "not resize a disk -- grow it by hand (`qm resize`) and declare the size it then reports."
6102
+ };
6103
+ }
6104
+ if (sameMap(want.options, have.options))
6105
+ return {};
6106
+ return { put: printOptions(have.source, have.volname, want.options, have.size) };
6107
+ };
6108
+
6109
+ // src/proxmox/qemu-net.ts
6110
+ var NIC_MODELS = [
6111
+ "e1000",
6112
+ "e1000e",
6113
+ "i82551",
6114
+ "i82557b",
6115
+ "i82559er",
6116
+ "i82562",
6117
+ "i82801",
6118
+ "ne2k_isa",
6119
+ "ne2k_pci",
6120
+ "pcnet",
6121
+ "rtl8139",
6122
+ "virtio",
6123
+ "vmxnet3"
6124
+ ];
6125
+ var netPairs = (value) => new Map(value.split(",").map((part) => part.trim()).filter((part) => part !== "").map((part) => {
6126
+ const at = part.indexOf("=");
6127
+ return at === -1 ? [part, ""] : [part.slice(0, at), part.slice(at + 1)];
6128
+ }));
6129
+ var modelKey = (map31) => NIC_MODELS.find((model) => map31.has(model));
6130
+ var netMaps2 = (declared2, live) => {
6131
+ const want = netPairs(declared2);
6132
+ const have = netPairs(live);
6133
+ const wantModel = modelKey(want);
6134
+ const haveModel = modelKey(have);
6135
+ if (wantModel !== undefined && (want.get(wantModel) ?? "") === "" && haveModel !== undefined) {
6136
+ want.set(wantModel, have.get(haveModel) ?? "");
6137
+ }
6138
+ return { have, want };
6139
+ };
6140
+ var sameNet = (declared2, live) => {
6141
+ const { have, want } = netMaps2(declared2, live);
6142
+ return have.size === want.size && [...want].every(([k, v]) => have.get(k) === v);
6143
+ };
6144
+ var netWrite2 = (declared2, live) => {
6145
+ const want = netPairs(declared2);
6146
+ const wantModel = modelKey(want);
6147
+ const have = netPairs(live);
6148
+ const haveModel = modelKey(have);
6149
+ if (wantModel !== undefined && (want.get(wantModel) ?? "") === "" && haveModel !== undefined) {
6150
+ want.set(wantModel, have.get(haveModel) ?? "");
6151
+ }
6152
+ return [...want].map(([k, v]) => v === "" ? k : `${k}=${v}`).join(",");
6153
+ };
6154
+
6155
+ // src/proxmox/qemu-judge.ts
6156
+ var judge2 = (props, config7) => {
6157
+ const put = {};
6158
+ const refuse3 = [];
6159
+ const drift = new Set;
6160
+ for (const key of declaredKeys2(props)) {
6161
+ const want = wireValue2(declaredValue2(props, key));
6162
+ const have = config7[key];
6163
+ const family = indexedKey2(key)?.[0];
6164
+ if (family === "scsi" || family === "ide") {
6165
+ if (have === undefined) {
6166
+ drift.add(key);
6167
+ put[key] = want;
6168
+ } else {
6169
+ const verdict = judgeDisk(key, want, have);
6170
+ if (verdict.refuse !== undefined) {
6171
+ drift.add(key);
6172
+ refuse3.push(verdict.refuse);
6173
+ } else if (verdict.put !== undefined) {
6174
+ drift.add(key);
6175
+ put[key] = verdict.put;
6176
+ }
6177
+ }
6178
+ continue;
6179
+ }
6180
+ if (family === "net") {
6181
+ if (have === undefined) {
6182
+ drift.add(key);
6183
+ put[key] = want;
6184
+ } else if (!sameNet(want, have)) {
6185
+ drift.add(key);
6186
+ put[key] = netWrite2(want, have);
6187
+ }
6188
+ continue;
6189
+ }
6190
+ if (want !== (have ?? "")) {
6191
+ drift.add(key);
6192
+ put[key] = want;
6193
+ }
6194
+ }
6195
+ return { drift: [...drift].sort(), put, refuse: refuse3 };
6196
+ };
6197
+ var identityRefusal = (vmid, was) => was === undefined || vmid === was ? undefined : `vmid: ${String(was)} -> ${String(vmid)} is a different VM. Declare it as a new resource; ` + "this one is retained when its declaration goes.";
6198
+
5983
6199
  // src/proxmox/qemu-read.ts
5984
6200
  import * as cluster10 from "@distilled.cloud/proxmox/cluster";
5985
6201
  import * as nodes15 from "@distilled.cloud/proxmox/nodes";
@@ -6040,15 +6256,11 @@ var qemuTask = (props, operation, what, polls) => Effect83.gen(function* () {
6040
6256
  var CREATE_POLLS2 = 180;
6041
6257
  var DELETE_POLLS = 60;
6042
6258
  var attributesOf9 = (live, props) => ({
6043
- cores: int(live.cores, 1),
6044
- memory: int(live.memory, 512),
6045
- name: typeof live.name === "string" ? live.name : "",
6259
+ config: storedConfig2(live),
6046
6260
  node: props.node,
6047
- onboot: live.onboot === 1 || live.onboot === true,
6048
- sockets: int(live.sockets, 1),
6049
6261
  vmid: props.vmid
6050
6262
  });
6051
- var matches9 = (attributes2, props) => attributes2.name === (props.name ?? `vm${String(props.vmid)}`) && attributes2.memory === (props.memory ?? 512) && attributes2.cores === (props.cores ?? 1) && attributes2.sockets === (props.sockets ?? 1) && attributes2.onboot === (props.onboot === true);
6263
+ var matches9 = (attributes2, props) => declaredKeys2(props).filter(isManagedKey2).every((key) => attributes2.config[key] === wireValue2(declaredValue2(props, key)));
6052
6264
  var spec5 = {
6053
6265
  attributes: attributesOf9,
6054
6266
  collection: (props) => `nodes/${props.node}/qemu`,
@@ -6059,84 +6271,310 @@ var spec5 = {
6059
6271
  },
6060
6272
  matches: matches9,
6061
6273
  path: (props) => `nodes/${props.node}/qemu/${String(props.vmid)}/config`,
6062
- updateForm: shape9
6274
+ updateForm: updateForm6
6063
6275
  };
6064
6276
  var { guardCreate: guardCreate10, guardUpdate: guardUpdate10 } = specGuards(spec5);
6065
6277
  var readQemu = (props) => readVm(props).pipe(Effect84.map((live) => live === undefined ? undefined : attributesOf9(live, props)));
6066
6278
  var deleteQemu = (props) => qemuTask(props, nodes17.deleteNodeQemu({ node: props.node, vmid: String(props.vmid) }), `destroy VM ${String(props.vmid)}`, DELETE_POLLS).pipe(Effect84.catchTag("QemuConfigNotFound", () => Effect84.void));
6279
+ var refuseUnmanaged = (props) => {
6280
+ const refused2 = formRefusals(props);
6281
+ return refused2.length === 0 ? Effect84.void : Effect84.fail(new QemuRefusedError(refused2.join(`
6282
+ `)));
6283
+ };
6284
+ var refuseChange = (change) => change.refuse.length === 0 ? Effect84.void : Effect84.fail(new QemuRefusedError(change.refuse.join(`
6285
+ `)));
6067
6286
  var qemuHandlers = {
6068
6287
  list: () => Effect84.succeed([]),
6069
- read: ({ olds }) => readQemu(olds),
6288
+ read: Effect84.fn(function* ({
6289
+ fqn,
6290
+ instanceId,
6291
+ olds,
6292
+ output
6293
+ }) {
6294
+ const found = yield* readQemu(olds);
6295
+ const settled2 = Effect84.sync(() => found !== undefined && judge2(olds, found.config).drift.length === 0);
6296
+ return yield* ownedRead({ fqn, instanceId, output }, found, settled2);
6297
+ }),
6070
6298
  diff: Effect84.fn(function* ({
6071
6299
  news,
6300
+ olds,
6072
6301
  output
6073
6302
  }) {
6074
6303
  if (!isResolved26(news))
6075
6304
  return;
6305
+ const identity2 = identityRefusal(news.vmid, output?.vmid ?? olds.vmid);
6306
+ if (identity2 !== undefined)
6307
+ return yield* Effect84.fail(new QemuRefusedError(identity2));
6308
+ yield* refuseUnmanaged(news);
6076
6309
  yield* guardCreate10(news, output === undefined);
6077
6310
  yield* guardUpdate10(news);
6078
6311
  if (output === undefined)
6079
6312
  return;
6080
6313
  const live = yield* readQemu(news);
6081
6314
  if (live === undefined) {
6315
+ yield* Effect84.logWarning(`Proxmox.Vm ${news.node}/${String(news.vmid)}: the cluster lists no VM with this vmid -- ` + "a deploy CREATES it again, with new, empty volumes.");
6082
6316
  yield* guardCreate10(news, true);
6083
6317
  return { action: "update" };
6084
6318
  }
6085
- return { action: spec5.matches(live, news) ? "noop" : "update" };
6319
+ const change = judge2(news, live.config);
6320
+ yield* refuseChange(change);
6321
+ return { action: change.drift.length === 0 ? "noop" : "update" };
6086
6322
  }),
6087
- reconcile: Effect84.fn(function* ({ news }) {
6323
+ reconcile: Effect84.fn(function* ({
6324
+ fqn,
6325
+ instanceId,
6326
+ news,
6327
+ olds,
6328
+ output
6329
+ }) {
6330
+ const identity2 = identityRefusal(news.vmid, output?.vmid ?? olds?.vmid);
6331
+ if (identity2 !== undefined)
6332
+ return yield* Effect84.fail(new QemuRefusedError(identity2));
6333
+ yield* refuseUnmanaged(news);
6088
6334
  const live = yield* readQemu(news);
6089
6335
  yield* guardCreate10(news, live === undefined);
6090
6336
  yield* guardUpdate10(news);
6091
6337
  if (live === undefined) {
6092
6338
  yield* qemuTask(news, nodes17.createNodeQemu({ ...createForm9(news), node: news.node }), `create VM ${String(news.vmid)}`, CREATE_POLLS2);
6093
6339
  } else {
6094
- const form = formToSend(spec5.matches, live, news, spec5.updateForm(news));
6095
- if (form !== undefined) {
6096
- yield* runPve(news.target, "provision", true, nodes17.putNodeQemuConfig({ ...form, node: news.node, vmid: String(news.vmid) }));
6340
+ yield* refuseTakeover({ fqn, instanceId, output }, `Proxmox.Vm VM ${String(news.vmid)} on ${news.node}`);
6341
+ const change = judge2(news, live.config);
6342
+ yield* refuseChange(change);
6343
+ if (Object.keys(change.put).length > 0) {
6344
+ yield* runPve(news.target, "provision", true, nodes17.putNodeQemuConfig({ ...change.put, node: news.node, vmid: String(news.vmid) }));
6097
6345
  }
6098
6346
  }
6099
6347
  const after = yield* readQemu(news);
6100
6348
  if (after === undefined) {
6101
6349
  return yield* Effect84.fail(new QemuRefusedError(`${spec5.path(news)}: write returned success but the VM is still absent`));
6102
6350
  }
6351
+ const left = judge2(news, after.config);
6352
+ if (left.drift.length > 0) {
6353
+ return yield* Effect84.fail(new QemuRefusedError(`${spec5.path(news)}: after the write, ${left.drift.join(", ")} still differ from the ` + "declaration. PVE may have normalised the value -- declare what it stores."));
6354
+ }
6103
6355
  return after;
6104
6356
  }),
6105
6357
  delete: ({ olds }) => deleteQemu(olds)
6106
6358
  };
6107
6359
 
6108
6360
  // src/proxmox/qemu.ts
6109
- var ProxmoxVm = Resource28("Proxmox.Vm");
6361
+ var ProxmoxVm = Resource28("Proxmox.Vm", { defaultRemovalPolicy: "retain" });
6110
6362
  var ProxmoxVmProvider = () => Provider28.effect(ProxmoxVm, Effect85.succeed(ProxmoxVm.Provider.of(qemuHandlers)));
6111
- // src/proxmox/replication-job.ts
6363
+ // src/proxmox/storage-download.ts
6112
6364
  import { Resource as Resource29 } from "alchemy";
6113
6365
  import * as Provider29 from "alchemy/Provider";
6366
+ import * as Effect88 from "effect/Effect";
6367
+
6368
+ // src/proxmox/storage-download-lifecycle.ts
6369
+ import { isResolved as isResolved27 } from "alchemy/Diff";
6370
+ import * as nodes19 from "@distilled.cloud/proxmox/nodes";
6114
6371
  import * as Effect87 from "effect/Effect";
6115
6372
 
6373
+ // src/proxmox/storage-download-identity.ts
6374
+ var PINNED = [
6375
+ "checksum",
6376
+ "checksumAlgorithm",
6377
+ "compression",
6378
+ "url",
6379
+ "verifyCertificates"
6380
+ ];
6381
+ var judgeIdentity = (news, olds) => {
6382
+ if (olds === undefined)
6383
+ return { kind: "same" };
6384
+ if (news.filename !== olds.filename || news.storage !== olds.storage) {
6385
+ return { kind: "replace" };
6386
+ }
6387
+ const changed = PINNED.filter((key) => news[key] !== olds[key]);
6388
+ if (changed.length === 0)
6389
+ return { kind: "same" };
6390
+ return {
6391
+ kind: "pin-changed",
6392
+ refuse: `${news.filename}: ${changed.join(", ")} changed but filename did not. filename is the ` + "identity -- PVE does not record what a volume was downloaded from, so this declaration " + "cannot be verified or rewritten in place. Change filename to force a new download."
6393
+ };
6394
+ };
6395
+
6396
+ // src/proxmox/storage-download-errors.ts
6397
+ class StorageDownloadRefusedError extends Error {
6398
+ constructor(message) {
6399
+ super(message);
6400
+ this.name = "StorageDownloadRefusedError";
6401
+ }
6402
+ }
6403
+
6404
+ // src/proxmox/storage-download-task.ts
6405
+ import * as nodes18 from "@distilled.cloud/proxmox/nodes";
6406
+ import * as Effect86 from "effect/Effect";
6407
+ var storageDownloadTask = (where, operation, what, polls) => Effect86.gen(function* () {
6408
+ const credential = yield* mint(where.target, "provision");
6409
+ const upid = text(yield* runPveWith(where.target, credential, true, operation));
6410
+ if (upid === "") {
6411
+ return yield* Effect86.fail(new StorageDownloadRefusedError(`${what}: PVE returned no task id, so the write cannot be confirmed and is not claimed.`));
6412
+ }
6413
+ let exit = "still running when this provider stopped waiting";
6414
+ for (let attempt = 0;attempt < polls; attempt++) {
6415
+ const status = yield* runPveWith(where.target, credential, false, nodes18.getNodeTaskStatus({ node: where.node, upid })).pipe(Effect86.orElseSucceed(() => {
6416
+ return;
6417
+ }));
6418
+ if (status === undefined || status.status === undefined) {
6419
+ exit = "the task could not be read";
6420
+ break;
6421
+ }
6422
+ if (status.status === "stopped") {
6423
+ exit = text(status.exitstatus, "stopped with no exitstatus");
6424
+ break;
6425
+ }
6426
+ yield* Effect86.sleep("1 second");
6427
+ }
6428
+ if (exit !== "OK") {
6429
+ return yield* Effect86.fail(new StorageDownloadRefusedError(`${what}: task ${upid} ended "${exit}". Read the task log before running the deploy again.`));
6430
+ }
6431
+ });
6432
+
6433
+ // src/proxmox/storage-download-lifecycle.ts
6434
+ var CREATE_POLLS3 = 600;
6435
+ var DELETE_POLLS2 = 60;
6436
+ var DOWNLOAD_ENDPOINT = "pve:POST /nodes/{node}/storage/{storage}/download-url";
6437
+ var downloadForm = (props) => ({
6438
+ checksum: props.checksum,
6439
+ "checksum-algorithm": props.checksumAlgorithm,
6440
+ ...props.compression === undefined ? {} : { compression: props.compression },
6441
+ content: "import",
6442
+ filename: props.filename,
6443
+ node: props.node,
6444
+ storage: props.storage,
6445
+ url: props.url,
6446
+ ...props.verifyCertificates === undefined ? {} : { "verify-certificates": props.verifyCertificates ? "1" : "0" }
6447
+ });
6448
+ var createRefusals2 = (props) => {
6449
+ const refuse3 = [];
6450
+ if (props.checksum.trim() === "") {
6451
+ refuse3.push(`${props.filename}: checksum is required — an unpinned download is not a declaration.`);
6452
+ }
6453
+ return refuse3.concat(formViolations(DOWNLOAD_ENDPOINT, downloadForm(props), true).map((why) => `${props.filename}: ${why}`));
6454
+ };
6455
+ var readDownload = (props) => Effect87.gen(function* () {
6456
+ const rows = yield* runPve(props.target, "read", false, nodes19.listNodeStorageContent({
6457
+ content: "import",
6458
+ node: props.node,
6459
+ storage: props.storage
6460
+ }));
6461
+ if (!Array.isArray(rows)) {
6462
+ return yield* Effect87.fail(new StorageDownloadRefusedError(`${props.storage}: the content list did not come back as a list.`));
6463
+ }
6464
+ const found = rows.find((row) => row.volid.endsWith(`/${props.filename}`));
6465
+ if (found === undefined)
6466
+ return;
6467
+ return {
6468
+ filename: props.filename,
6469
+ format: text(found.format, "raw"),
6470
+ node: props.node,
6471
+ size: int(found.size, 0),
6472
+ storage: props.storage,
6473
+ volid: text(found.volid, "")
6474
+ };
6475
+ });
6476
+ var destroyDownload = (props) => Effect87.gen(function* () {
6477
+ const live = yield* readDownload(props);
6478
+ if (live === undefined)
6479
+ return;
6480
+ yield* storageDownloadTask(props, nodes19.deleteNodeStorageContent({
6481
+ node: props.node,
6482
+ storage: props.storage,
6483
+ volume: live.volid
6484
+ }), `delete ${live.volid}`, DELETE_POLLS2);
6485
+ });
6486
+ var storageDownloadHandlers = {
6487
+ list: () => Effect87.succeed([]),
6488
+ read: Effect87.fn(function* ({
6489
+ fqn,
6490
+ instanceId,
6491
+ olds,
6492
+ output
6493
+ }) {
6494
+ const found = yield* readDownload(olds);
6495
+ return yield* ownedRead({ fqn, instanceId, output }, found, Effect87.succeed(true));
6496
+ }),
6497
+ diff: Effect87.fn(function* ({
6498
+ news,
6499
+ olds,
6500
+ output
6501
+ }) {
6502
+ if (!isResolved27(news))
6503
+ return;
6504
+ const refused2 = createRefusals2(news);
6505
+ if (refused2.length > 0) {
6506
+ return yield* Effect87.fail(new StorageDownloadRefusedError(refused2.join(`
6507
+ `)));
6508
+ }
6509
+ if (output === undefined)
6510
+ return;
6511
+ const identity2 = judgeIdentity(news, olds);
6512
+ if (identity2.kind === "replace")
6513
+ return { action: "replace" };
6514
+ const live = yield* readDownload(news);
6515
+ if (identity2.kind === "pin-changed" && live !== undefined) {
6516
+ return yield* Effect87.fail(new StorageDownloadRefusedError(identity2.refuse));
6517
+ }
6518
+ return { action: live === undefined ? "update" : "noop" };
6519
+ }),
6520
+ reconcile: Effect87.fn(function* ({
6521
+ fqn,
6522
+ instanceId,
6523
+ news,
6524
+ output
6525
+ }) {
6526
+ const refused2 = createRefusals2(news);
6527
+ if (refused2.length > 0) {
6528
+ return yield* Effect87.fail(new StorageDownloadRefusedError(refused2.join(`
6529
+ `)));
6530
+ }
6531
+ const live = yield* readDownload(news);
6532
+ if (live === undefined) {
6533
+ yield* storageDownloadTask(news, nodes19.downloadNodesStorageUrl(downloadForm(news)), `download ${news.filename} onto ${news.storage}`, CREATE_POLLS3);
6534
+ } else {
6535
+ yield* refuseTakeover({ fqn, instanceId, output }, `Proxmox.StorageDownload ${news.filename} on ${news.storage}`);
6536
+ }
6537
+ const after = yield* readDownload(news);
6538
+ if (after === undefined) {
6539
+ return yield* Effect87.fail(new StorageDownloadRefusedError(`${news.filename}: the write returned no error but ${news.storage} still has no ` + "matching content — PVE may have normalised the filename; read it back by hand."));
6540
+ }
6541
+ return after;
6542
+ }),
6543
+ delete: ({ olds }) => destroyDownload(olds)
6544
+ };
6545
+
6546
+ // src/proxmox/storage-download.ts
6547
+ var ProxmoxStorageDownload = Resource29("Proxmox.StorageDownload");
6548
+ var ProxmoxStorageDownloadProvider = () => Provider29.effect(ProxmoxStorageDownload, Effect88.succeed(ProxmoxStorageDownload.Provider.of(storageDownloadHandlers)));
6549
+ // src/proxmox/replication-job.ts
6550
+ import { Resource as Resource30 } from "alchemy";
6551
+ import * as Provider30 from "alchemy/Provider";
6552
+ import * as Effect90 from "effect/Effect";
6553
+
6116
6554
  // src/proxmox/replication-job-lifecycle.ts
6117
- import { isResolved as isResolved27 } from "alchemy/Diff";
6555
+ import { isResolved as isResolved28 } from "alchemy/Diff";
6118
6556
  import * as cluster11 from "@distilled.cloud/proxmox/cluster";
6119
6557
  import { ProxmoxParseError as ProxmoxParseError6 } from "@distilled.cloud/proxmox/Errors";
6120
- import * as Effect86 from "effect/Effect";
6558
+ import * as Effect89 from "effect/Effect";
6121
6559
  import * as Schema6 from "effect/Schema";
6122
6560
 
6123
6561
  // src/proxmox/replication-job-form.ts
6124
6562
  var DEFAULT_SCHEDULE = "*/15";
6125
6563
  var jobId = (props) => `${String(props.guest)}-${String(props.jobnum)}`;
6126
- var shape10 = (props) => ({
6564
+ var shape9 = (props) => ({
6127
6565
  comment: props.comment ?? "",
6128
6566
  disable: props.disable === true ? "1" : "0",
6129
6567
  schedule: props.schedule ?? DEFAULT_SCHEDULE,
6130
6568
  ...props.rate === undefined ? {} : { rate: String(props.rate) }
6131
6569
  });
6132
6570
  var createBody5 = (props) => ({
6133
- ...shape10(props),
6571
+ ...shape9(props),
6134
6572
  id: jobId(props),
6135
6573
  target: props.targetNode,
6136
6574
  type: "local"
6137
6575
  });
6138
6576
  var updateBody4 = (props) => ({
6139
- ...shape10(props),
6577
+ ...shape9(props),
6140
6578
  delete: "remove_job"
6141
6579
  });
6142
6580
 
@@ -6178,21 +6616,21 @@ var malformed = () => new ProxmoxParseError6({
6178
6616
  body: undefined,
6179
6617
  cause: "Replication job response does not match the requested vendor identity"
6180
6618
  });
6181
- var readReplicationJob = (props) => runPve(props.target, "read", false, cluster11.getClusterReplication({ id: jobId(props) })).pipe(Effect86.flatMap((live) => Schema6.decodeUnknownEffect(Schema6.toType(cluster11.GetClusterReplicationResponse))({
6619
+ var readReplicationJob = (props) => runPve(props.target, "read", false, cluster11.getClusterReplication({ id: jobId(props) })).pipe(Effect89.flatMap((live) => Schema6.decodeUnknownEffect(Schema6.toType(cluster11.GetClusterReplicationResponse))({
6182
6620
  ...live,
6183
6621
  guest: int(live.guest, Number.NaN),
6184
6622
  jobnum: int(live.jobnum, Number.NaN),
6185
6623
  rate: undefined
6186
- }).pipe(Effect86.mapError(malformed), Effect86.as(live))), Effect86.flatMap((live) => live.id === jobId(props) && int(live.guest, Number.NaN) === props.guest && int(live.jobnum, Number.NaN) === props.jobnum ? Effect86.succeed(replicationJobSpec.attributes({ ...live }, props)) : Effect86.fail(malformed())), Effect86.catchTag("ReplicationJobNotFound", () => Effect86.succeed(undefined)));
6187
- var deleteReplicationJob = (props) => runPve(props.target, "provision", true, cluster11.deleteClusterReplication({ id: jobId(props) })).pipe(Effect86.catchTag("ReplicationJobNotFound", () => Effect86.void));
6624
+ }).pipe(Effect89.mapError(malformed), Effect89.as(live))), Effect89.flatMap((live) => live.id === jobId(props) && int(live.guest, Number.NaN) === props.guest && int(live.jobnum, Number.NaN) === props.jobnum ? Effect89.succeed(replicationJobSpec.attributes({ ...live }, props)) : Effect89.fail(malformed())), Effect89.catchTag("ReplicationJobNotFound", () => Effect89.succeed(undefined)));
6625
+ var deleteReplicationJob = (props) => runPve(props.target, "provision", true, cluster11.deleteClusterReplication({ id: jobId(props) })).pipe(Effect89.catchTag("ReplicationJobNotFound", () => Effect89.void));
6188
6626
  var replicationJobHandlers = {
6189
- list: () => Effect86.succeed([]),
6627
+ list: () => Effect89.succeed([]),
6190
6628
  read: ({ olds }) => readReplicationJob(olds),
6191
- diff: Effect86.fn(function* ({
6629
+ diff: Effect89.fn(function* ({
6192
6630
  news,
6193
6631
  output
6194
6632
  }) {
6195
- if (!isResolved27(news))
6633
+ if (!isResolved28(news))
6196
6634
  return;
6197
6635
  yield* guardCreate11(news, output === undefined);
6198
6636
  yield* guardUpdate11(news);
@@ -6205,36 +6643,36 @@ var replicationJobHandlers = {
6205
6643
  }
6206
6644
  return { action: replicationJobSpec.matches(live, news) ? "noop" : "update" };
6207
6645
  }),
6208
- reconcile: Effect86.fn(function* ({ news }) {
6646
+ reconcile: Effect89.fn(function* ({ news }) {
6209
6647
  const live = yield* readReplicationJob(news);
6210
6648
  yield* guardCreate11(news, live === undefined);
6211
6649
  yield* guardUpdate11(news);
6212
6650
  if (live === undefined) {
6213
6651
  yield* runPve(news.target, "provision", true, cluster11.createClusterReplication(replicationJobSpec.createForm(news)));
6214
6652
  } else {
6215
- const form = formToSend(replicationJobSpec.matches, live, news, replicationJobSpec.updateForm(news));
6216
- if (form !== undefined)
6217
- yield* runPve(news.target, "provision", true, cluster11.putClusterReplication({ ...form, id: jobId(news) }));
6653
+ const form2 = formToSend(replicationJobSpec.matches, live, news, replicationJobSpec.updateForm(news));
6654
+ if (form2 !== undefined)
6655
+ yield* runPve(news.target, "provision", true, cluster11.putClusterReplication({ ...form2, id: jobId(news) }));
6218
6656
  }
6219
6657
  const after = yield* readReplicationJob(news);
6220
6658
  if (after === undefined)
6221
- return yield* Effect86.fail(new Error(`${replicationJobSpec.path(news)}: write returned success but the resource is still absent`));
6659
+ return yield* Effect89.fail(new Error(`${replicationJobSpec.path(news)}: write returned success but the resource is still absent`));
6222
6660
  return after;
6223
6661
  }),
6224
6662
  delete: ({ olds }) => deleteReplicationJob(olds)
6225
6663
  };
6226
6664
 
6227
6665
  // src/proxmox/replication-job.ts
6228
- var ProxmoxReplicationJob = Resource29("Proxmox.ReplicationJob");
6229
- var ProxmoxReplicationJobProvider = () => Provider29.effect(ProxmoxReplicationJob, Effect87.succeed(ProxmoxReplicationJob.Provider.of(replicationJobHandlers)));
6666
+ var ProxmoxReplicationJob = Resource30("Proxmox.ReplicationJob");
6667
+ var ProxmoxReplicationJobProvider = () => Provider30.effect(ProxmoxReplicationJob, Effect90.succeed(ProxmoxReplicationJob.Provider.of(replicationJobHandlers)));
6230
6668
  // src/proxmox/sdn-apply.ts
6231
- import { Resource as Resource30 } from "alchemy";
6232
- import { isResolved as isResolved28 } from "alchemy/Diff";
6233
- import * as Provider30 from "alchemy/Provider";
6234
- import * as Effect89 from "effect/Effect";
6669
+ import { Resource as Resource31 } from "alchemy";
6670
+ import { isResolved as isResolved29 } from "alchemy/Diff";
6671
+ import * as Provider31 from "alchemy/Provider";
6672
+ import * as Effect92 from "effect/Effect";
6235
6673
 
6236
6674
  // src/proxmox/sdn-apply-read.ts
6237
- import * as Effect88 from "effect/Effect";
6675
+ import * as Effect91 from "effect/Effect";
6238
6676
  var MARKED = [
6239
6677
  "cluster/sdn/zones",
6240
6678
  "cluster/sdn/vnets",
@@ -6243,7 +6681,7 @@ var MARKED = [
6243
6681
  "cluster/sdn/route-maps"
6244
6682
  ];
6245
6683
  var subsystemAbsent = (error) => error instanceof PveError && error.status === 501;
6246
- var markedPending = (target) => Effect88.all(MARKED.map((collection) => pve(target, "read", "GET", `${collection}?pending=1`).pipe(Effect88.map((rows) => (rows ?? []).filter((row) => row.state !== undefined).length), Effect88.catchIf(subsystemAbsent, () => Effect88.succeed(0)))), { concurrency: "unbounded" }).pipe(Effect88.map((counts) => counts.reduce((total, count2) => total + count2, 0)));
6684
+ var markedPending = (target) => Effect91.all(MARKED.map((collection) => pve(target, "read", "GET", `${collection}?pending=1`).pipe(Effect91.map((rows) => (rows ?? []).filter((row) => row.state !== undefined).length), Effect91.catchIf(subsystemAbsent, () => Effect91.succeed(0)))), { concurrency: "unbounded" }).pipe(Effect91.map((counts) => counts.reduce((total, count2) => total + count2, 0)));
6247
6685
  var fabricStaged = (staged, running) => {
6248
6686
  if (staged === undefined && running === undefined)
6249
6687
  return 0;
@@ -6251,9 +6689,9 @@ var fabricStaged = (staged, running) => {
6251
6689
  return "inconsistent";
6252
6690
  return staged === running ? 0 : 1;
6253
6691
  };
6254
- var fabricPending = (target) => Effect88.all(["pending", "running"].map((view) => pve(target, "read", "GET", `cluster/sdn/fabrics/all?${view}=1`).pipe(Effect88.map(canonical3), Effect88.catchIf(subsystemAbsent, () => Effect88.succeed(undefined)))), { concurrency: "unbounded" }).pipe(Effect88.flatMap(([staged, running]) => {
6692
+ var fabricPending = (target) => Effect91.all(["pending", "running"].map((view) => pve(target, "read", "GET", `cluster/sdn/fabrics/all?${view}=1`).pipe(Effect91.map(canonical3), Effect91.catchIf(subsystemAbsent, () => Effect91.succeed(undefined)))), { concurrency: "unbounded" }).pipe(Effect91.flatMap(([staged, running]) => {
6255
6693
  const verdict = fabricStaged(staged, running);
6256
- return verdict === "inconsistent" ? Effect88.die(new Error("cluster/sdn/fabrics/all answered 501 for one of ?pending=1 and ?running=1 and not " + "the other. Refusing to read that as a staged fabric change.")) : Effect88.succeed(verdict);
6694
+ return verdict === "inconsistent" ? Effect91.die(new Error("cluster/sdn/fabrics/all answered 501 for one of ?pending=1 and ?running=1 and not " + "the other. Refusing to read that as a staged fabric change.")) : Effect91.succeed(verdict);
6257
6695
  }));
6258
6696
  var canonical3 = (value) => JSON.stringify(sortDeep(value));
6259
6697
  var sortDeep = (value) => {
@@ -6266,23 +6704,23 @@ var sortDeep = (value) => {
6266
6704
  }
6267
6705
  return value;
6268
6706
  };
6269
- var sdnPendingCount = (target) => Effect88.all([markedPending(target), fabricPending(target)], { concurrency: "unbounded" }).pipe(Effect88.map(([marked, fabric]) => marked + fabric));
6707
+ var sdnPendingCount = (target) => Effect91.all([markedPending(target), fabricPending(target)], { concurrency: "unbounded" }).pipe(Effect91.map(([marked, fabric]) => marked + fabric));
6270
6708
 
6271
6709
  // src/proxmox/sdn-apply.ts
6272
- var ProxmoxSdnApply = Resource30("Proxmox.SdnApply");
6273
- var read5 = (props) => sdnPendingCount(props.target).pipe(Effect89.map((pending) => ({ pending })));
6274
- var ProxmoxSdnApplyProvider = () => Provider30.effect(ProxmoxSdnApply, Effect89.succeed(ProxmoxSdnApply.Provider.of({
6275
- list: () => Effect89.succeed([]),
6276
- read: Effect89.fn(function* ({ olds }) {
6710
+ var ProxmoxSdnApply = Resource31("Proxmox.SdnApply");
6711
+ var read5 = (props) => sdnPendingCount(props.target).pipe(Effect92.map((pending) => ({ pending })));
6712
+ var ProxmoxSdnApplyProvider = () => Provider31.effect(ProxmoxSdnApply, Effect92.succeed(ProxmoxSdnApply.Provider.of({
6713
+ list: () => Effect92.succeed([]),
6714
+ read: Effect92.fn(function* ({ olds }) {
6277
6715
  return yield* read5(olds);
6278
6716
  }),
6279
- diff: Effect89.fn(function* ({ news }) {
6280
- if (!isResolved28(news))
6717
+ diff: Effect92.fn(function* ({ news }) {
6718
+ if (!isResolved29(news))
6281
6719
  return;
6282
6720
  const { pending } = yield* read5(news);
6283
6721
  return pending === 0 ? { action: "noop" } : { action: "update" };
6284
6722
  }),
6285
- reconcile: Effect89.fn(function* ({ news }) {
6723
+ reconcile: Effect92.fn(function* ({ news }) {
6286
6724
  const staged = yield* read5(news);
6287
6725
  if (staged.pending === 0)
6288
6726
  return staged;
@@ -6290,16 +6728,16 @@ var ProxmoxSdnApplyProvider = () => Provider30.effect(ProxmoxSdnApply, Effect89.
6290
6728
  yield* pve(news.target, "provision", "PUT", "cluster/sdn");
6291
6729
  const after = yield* read5(news);
6292
6730
  if (after.pending !== 0) {
6293
- return yield* Effect89.die(new Error(`PUT /cluster/sdn returned no error but ${String(after.pending)} SDN object(s) ` + "are still staged. The running config does not match the declared one -- check " + "`pvesh get /cluster/sdn/zones --pending 1` for the objects PVE refused."));
6731
+ return yield* Effect92.die(new Error(`PUT /cluster/sdn returned no error but ${String(after.pending)} SDN object(s) ` + "are still staged. The running config does not match the declared one -- check " + "`pvesh get /cluster/sdn/zones --pending 1` for the objects PVE refused."));
6294
6732
  }
6295
6733
  return after;
6296
6734
  }),
6297
- delete: () => Effect89.void
6735
+ delete: () => Effect92.void
6298
6736
  })));
6299
6737
  // src/proxmox/sdn-subnet.ts
6300
- import { Resource as Resource31 } from "alchemy";
6301
- import * as Provider31 from "alchemy/Provider";
6302
- import * as Effect90 from "effect/Effect";
6738
+ import { Resource as Resource32 } from "alchemy";
6739
+ import * as Provider32 from "alchemy/Provider";
6740
+ import * as Effect93 from "effect/Effect";
6303
6741
 
6304
6742
  // src/proxmox/sdn-subnet-form.ts
6305
6743
  var subnetId = (props) => `${props.zone}-${props.cidr.replace("/", "-")}`;
@@ -6323,13 +6761,13 @@ var createForm10 = (props) => ({
6323
6761
  subnet: props.cidr,
6324
6762
  type: "subnet"
6325
6763
  });
6326
- var updateForm6 = (props) => {
6764
+ var updateForm7 = (props) => {
6327
6765
  const clear = Object.entries(optional3(props)).filter(([, value]) => value === undefined).map(([key]) => key);
6328
6766
  return withClears(body5(props), clear);
6329
6767
  };
6330
6768
 
6331
6769
  // src/proxmox/sdn-subnet.ts
6332
- var ProxmoxSdnSubnet = Resource31("Proxmox.SdnSubnet");
6770
+ var ProxmoxSdnSubnet = Resource32("Proxmox.SdnSubnet");
6333
6771
  var handlers13 = pveHandlers({
6334
6772
  attributes: (live, props) => {
6335
6773
  const liveVnet = text(live["vnet"]);
@@ -6357,16 +6795,16 @@ var handlers13 = pveHandlers({
6357
6795
  },
6358
6796
  matches: (attributes2, props) => attributes2.gateway === (props.gateway ?? "") && attributes2.snat === (props.snat === true) && attributes2.dnszoneprefix === (props.dnszoneprefix ?? "") && attributes2.dhcpDnsServer === (props.dhcpDnsServer ?? "") && attributes2.dhcpRange === declaredRanges(props.dhcpRange),
6359
6797
  path: (props) => `cluster/sdn/vnets/${props.vnet}/subnets/${subnetId(props)}`,
6360
- updateForm: updateForm6
6798
+ updateForm: updateForm7
6361
6799
  });
6362
- var ProxmoxSdnSubnetProvider = () => Provider31.effect(ProxmoxSdnSubnet, Effect90.succeed(ProxmoxSdnSubnet.Provider.of(handlers13)));
6800
+ var ProxmoxSdnSubnetProvider = () => Provider32.effect(ProxmoxSdnSubnet, Effect93.succeed(ProxmoxSdnSubnet.Provider.of(handlers13)));
6363
6801
  // src/proxmox/sdn-vnet.ts
6364
- import { Resource as Resource32 } from "alchemy";
6365
- import * as Provider32 from "alchemy/Provider";
6366
- import * as Effect91 from "effect/Effect";
6367
- var ProxmoxSdnVnet = Resource32("Proxmox.SdnVnet");
6802
+ import { Resource as Resource33 } from "alchemy";
6803
+ import * as Provider33 from "alchemy/Provider";
6804
+ import * as Effect94 from "effect/Effect";
6805
+ var ProxmoxSdnVnet = Resource33("Proxmox.SdnVnet");
6368
6806
  var tagOf = (value) => typeof value === "number" ? value : undefined;
6369
- var shape11 = (props) => {
6807
+ var shape10 = (props) => {
6370
6808
  const alias = props.alias ?? "";
6371
6809
  return {
6372
6810
  "isolate-ports": props.isolatePorts === true ? "1" : "0",
@@ -6376,12 +6814,12 @@ var shape11 = (props) => {
6376
6814
  ...props.tag === undefined ? {} : { tag: String(props.tag) }
6377
6815
  };
6378
6816
  };
6379
- var updateForm7 = (props) => {
6817
+ var updateForm8 = (props) => {
6380
6818
  const unset2 = [
6381
6819
  ...(props.alias ?? "") === "" ? ["alias"] : [],
6382
6820
  ...props.tag === undefined ? ["tag"] : []
6383
6821
  ];
6384
- return withClears(shape11(props), unset2);
6822
+ return withClears(shape10(props), unset2);
6385
6823
  };
6386
6824
  var handlers14 = pveHandlers({
6387
6825
  readRole: "provision",
@@ -6395,18 +6833,18 @@ var handlers14 = pveHandlers({
6395
6833
  zone: typeof live["zone"] === "string" ? live["zone"] : ""
6396
6834
  }),
6397
6835
  collection: () => "cluster/sdn/vnets",
6398
- createForm: (props) => ({ ...shape11(props), vnet: props.vnet }),
6836
+ createForm: (props) => ({ ...shape10(props), vnet: props.vnet }),
6399
6837
  endpoint: { create: "pve:POST /cluster/sdn/vnets", update: "pve:PUT /cluster/sdn/vnets/{vnet}" },
6400
6838
  matches: (attributes2, props) => attributes2.zone === props.zone && attributes2.alias === (props.alias ?? "") && attributes2.tag === props.tag && attributes2.vlanaware === (props.vlanaware === true) && attributes2.isolatePorts === (props.isolatePorts === true),
6401
6839
  path: (props) => `cluster/sdn/vnets/${props.vnet}`,
6402
- updateForm: updateForm7
6840
+ updateForm: updateForm8
6403
6841
  });
6404
- var ProxmoxSdnVnetProvider = () => Provider32.effect(ProxmoxSdnVnet, Effect91.succeed(ProxmoxSdnVnet.Provider.of(handlers14)));
6842
+ var ProxmoxSdnVnetProvider = () => Provider33.effect(ProxmoxSdnVnet, Effect94.succeed(ProxmoxSdnVnet.Provider.of(handlers14)));
6405
6843
  // src/proxmox/sdn-zone.ts
6406
- import { Resource as Resource33 } from "alchemy";
6407
- import * as Provider33 from "alchemy/Provider";
6408
- import * as Effect92 from "effect/Effect";
6409
- var ProxmoxSdnZone = Resource33("Proxmox.SdnZone");
6844
+ import { Resource as Resource34 } from "alchemy";
6845
+ import * as Provider34 from "alchemy/Provider";
6846
+ import * as Effect95 from "effect/Effect";
6847
+ var ProxmoxSdnZone = Resource34("Proxmox.SdnZone");
6410
6848
  var sameIpam = (live, declared2) => (live === "" ? "pve" : live) === (declared2 === undefined || declared2 === "" ? "pve" : declared2);
6411
6849
  var body6 = (props) => ({
6412
6850
  ...props.bridge === undefined ? {} : { bridge: props.bridge },
@@ -6458,20 +6896,20 @@ var handlers15 = pveHandlers({
6458
6896
  return withClears(fields2, clear);
6459
6897
  }
6460
6898
  });
6461
- var ProxmoxSdnZoneProvider = () => Provider33.effect(ProxmoxSdnZone, Effect92.succeed(ProxmoxSdnZone.Provider.of(handlers15)));
6899
+ var ProxmoxSdnZoneProvider = () => Provider34.effect(ProxmoxSdnZone, Effect95.succeed(ProxmoxSdnZone.Provider.of(handlers15)));
6462
6900
  // src/proxmox/storage.ts
6463
- import { Resource as Resource34 } from "alchemy";
6464
- import { isResolved as isResolved29 } from "alchemy/Diff";
6465
- import * as Provider34 from "alchemy/Provider";
6901
+ import { Resource as Resource35 } from "alchemy";
6902
+ import { isResolved as isResolved30 } from "alchemy/Diff";
6903
+ import * as Provider35 from "alchemy/Provider";
6466
6904
  import * as storage2 from "@distilled.cloud/proxmox/storage";
6467
- import * as Effect94 from "effect/Effect";
6905
+ import * as Effect97 from "effect/Effect";
6468
6906
 
6469
6907
  // src/proxmox/storage-form.ts
6470
6908
  var STORAGE_CREATE = "pve:POST /storage";
6471
6909
  var STORAGE_UPDATE = "pve:PUT /storage/{storage}";
6472
6910
  var field6 = (name, value) => value === undefined ? {} : { [name]: value };
6473
6911
  var locatorForm = (locator) => ({ ...locator });
6474
- var underscored = (form) => Object.fromEntries(Object.entries(form).map(([key, value]) => [key.replaceAll("-", "_"), value]));
6912
+ var underscored = (form2) => Object.fromEntries(Object.entries(form2).map(([key, value]) => [key.replaceAll("-", "_"), value]));
6475
6913
  var mutable2 = (props) => ({
6476
6914
  ...field6("comment", props.comment),
6477
6915
  ...field6("content", props.content),
@@ -6487,16 +6925,16 @@ var createForm11 = (props) => ({
6487
6925
  storage: props.storage,
6488
6926
  type: props.type
6489
6927
  });
6490
- var updateForm8 = (props) => ({
6928
+ var updateForm9 = (props) => ({
6491
6929
  ...mutable2(props),
6492
6930
  storage: props.storage
6493
6931
  });
6494
6932
  var toDistilledCreate4 = (props) => underscored(createForm11(props));
6495
- var toDistilledUpdate3 = (props) => underscored(updateForm8(props));
6933
+ var toDistilledUpdate3 = (props) => underscored(updateForm9(props));
6496
6934
 
6497
6935
  // src/proxmox/storage-wire.ts
6498
6936
  import * as storage from "@distilled.cloud/proxmox/storage";
6499
- import * as Effect93 from "effect/Effect";
6937
+ import * as Effect96 from "effect/Effect";
6500
6938
  var str2 = (value, fallback = "") => typeof value === "string" ? value : fallback;
6501
6939
  var tokens = (value) => value.split(",").map((part) => part.trim()).filter((part) => part !== "").sort().join(",");
6502
6940
  var sameList2 = (declared2, live) => declared2 === undefined || tokens(declared2) === tokens(live);
@@ -6515,25 +6953,25 @@ var attributesOf10 = (live, props) => {
6515
6953
  type: str2(data["type"], props.type)
6516
6954
  };
6517
6955
  };
6518
- var readStorageOrFail = (props) => readOrUnreadable(runPve(props.target, "provision", false, storage.getStorage({ storage: props.storage }))).pipe(Effect93.map((live) => live === UNREADABLE ? UNREADABLE : attributesOf10(live, props)));
6519
- var readStorage = (props) => readStorageOrFail(props).pipe(Effect93.catchTag("StorageNotFound", () => Effect93.succeed(undefined)));
6956
+ var readStorageOrFail = (props) => readOrUnreadable(runPve(props.target, "provision", false, storage.getStorage({ storage: props.storage }))).pipe(Effect96.map((live) => live === UNREADABLE ? UNREADABLE : attributesOf10(live, props)));
6957
+ var readStorage = (props) => readStorageOrFail(props).pipe(Effect96.catchTag("StorageNotFound", () => Effect96.succeed(undefined)));
6520
6958
  var dropUnreadable7 = (live) => live === UNREADABLE ? undefined : live;
6521
6959
  var matches10 = (attributes2, props) => sameList2(props.content, attributes2.content) && sameList2(props.nodes, attributes2.nodes) && sameList2(props["prune-backups"], attributes2["prune-backups"]) && same7(props.disable, attributes2.disable) && same7(props.shared, attributes2.shared) && same7(props.preallocation, attributes2.preallocation) && same7(props.comment, attributes2.comment);
6522
6960
 
6523
6961
  // src/proxmox/storage.ts
6524
- var ProxmoxStorage = Resource34("Proxmox.Storage", {
6962
+ var ProxmoxStorage = Resource35("Proxmox.Storage", {
6525
6963
  defaultRemovalPolicy: "retain"
6526
6964
  });
6527
- var ProxmoxStorageProvider = () => Provider34.effect(ProxmoxStorage, Effect94.succeed(ProxmoxStorage.Provider.of({
6528
- list: () => Effect94.succeed([]),
6529
- read: Effect94.fn(function* ({ olds, output }) {
6965
+ var ProxmoxStorageProvider = () => Provider35.effect(ProxmoxStorage, Effect97.succeed(ProxmoxStorage.Provider.of({
6966
+ list: () => Effect97.succeed([]),
6967
+ read: Effect97.fn(function* ({ olds, output }) {
6530
6968
  return dropUnreadable7(yield* output === undefined ? readStorage(olds) : readStorageOrFail(olds));
6531
6969
  }),
6532
- diff: Effect94.fn(function* ({ news, output }) {
6533
- if (!isResolved29(news))
6970
+ diff: Effect97.fn(function* ({ news, output }) {
6971
+ if (!isResolved30(news))
6534
6972
  return;
6535
6973
  yield* guardWrite2(STORAGE_CREATE, createForm11(news), output === undefined);
6536
- yield* guardWrite2(STORAGE_UPDATE, updateForm8(news), false);
6974
+ yield* guardWrite2(STORAGE_UPDATE, updateForm9(news), false);
6537
6975
  if (output === undefined)
6538
6976
  return;
6539
6977
  const live = yield* readStorageOrFail(news);
@@ -6547,10 +6985,10 @@ var ProxmoxStorageProvider = () => Provider34.effect(ProxmoxStorage, Effect94.su
6547
6985
  }
6548
6986
  return matches10(live, news) ? { action: "noop" } : { action: "update" };
6549
6987
  }),
6550
- reconcile: Effect94.fn(function* ({ news }) {
6988
+ reconcile: Effect97.fn(function* ({ news }) {
6551
6989
  const before = dropUnreadable7(yield* readStorage(news));
6552
6990
  yield* guardWrite2(STORAGE_CREATE, createForm11(news), before === undefined);
6553
- yield* guardWrite2(STORAGE_UPDATE, updateForm8(news), false);
6991
+ yield* guardWrite2(STORAGE_UPDATE, updateForm9(news), false);
6554
6992
  if (before === undefined) {
6555
6993
  yield* runPve(news.target, "provision", true, storage2.createStorage(toDistilledCreate4(news)));
6556
6994
  } else if (!matches10(before, news)) {
@@ -6558,23 +6996,23 @@ var ProxmoxStorageProvider = () => Provider34.effect(ProxmoxStorage, Effect94.su
6558
6996
  }
6559
6997
  const after = dropUnreadable7(yield* readStorage(news));
6560
6998
  if (after === undefined) {
6561
- return yield* Effect94.die(new Error(`storage/${news.storage}: the write returned no error but the storage is still ` + 'absent. PVE wraps every answer in {"data":...} and can report success on a ' + "call that did nothing -- read back rather than trusting the status code."));
6999
+ return yield* Effect97.die(new Error(`storage/${news.storage}: the write returned no error but the storage is still ` + 'absent. PVE wraps every answer in {"data":...} and can report success on a ' + "call that did nothing -- read back rather than trusting the status code."));
6562
7000
  }
6563
7001
  return after;
6564
7002
  }),
6565
- delete: Effect94.fn(function* ({ olds }) {
7003
+ delete: Effect97.fn(function* ({ olds }) {
6566
7004
  yield* runPve(olds.target, "provision", true, storage2.deleteStorage({ storage: olds.storage }));
6567
7005
  })
6568
7006
  })));
6569
7007
  // src/proxmox/zfs-pool.ts
6570
- import { Resource as Resource35 } from "alchemy";
6571
- import { isResolved as isResolved30 } from "alchemy/Diff";
6572
- import * as Provider35 from "alchemy/Provider";
6573
- import * as Effect97 from "effect/Effect";
7008
+ import { Resource as Resource36 } from "alchemy";
7009
+ import { isResolved as isResolved31 } from "alchemy/Diff";
7010
+ import * as Provider36 from "alchemy/Provider";
7011
+ import * as Effect100 from "effect/Effect";
6574
7012
 
6575
7013
  // src/proxmox/zfs-pool-wire.ts
6576
- import * as nodes18 from "@distilled.cloud/proxmox/nodes";
6577
- import * as Effect95 from "effect/Effect";
7014
+ import * as nodes20 from "@distilled.cloud/proxmox/nodes";
7015
+ import * as Effect98 from "effect/Effect";
6578
7016
  var leafDevices = (children) => Array.isArray(children) ? children.flatMap((entry) => {
6579
7017
  const vdev = entry;
6580
7018
  const nested = leafDevices(vdev.children);
@@ -6587,19 +7025,19 @@ var attributesOf11 = (live, props) => ({
6587
7025
  node: props.node,
6588
7026
  state: text(live.state, "unknown")
6589
7027
  });
6590
- var readPoolOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, nodes18.getNodeDiskZfs({ name: props.name, node: props.node }))).pipe(Effect95.map((live) => {
7028
+ var readPoolOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, nodes20.getNodeDiskZfs({ name: props.name, node: props.node }))).pipe(Effect98.map((live) => {
6591
7029
  if (live === UNREADABLE)
6592
7030
  return UNREADABLE;
6593
7031
  return text(live.name) === "" ? undefined : attributesOf11(live, props);
6594
7032
  }));
6595
- var readPool2 = (props) => readPoolOrFail(props).pipe(Effect95.orElseSucceed(() => {
7033
+ var readPool2 = (props) => readPoolOrFail(props).pipe(Effect98.orElseSucceed(() => {
6596
7034
  return;
6597
7035
  }));
6598
7036
  var dropUnreadable8 = (live) => live === UNREADABLE ? undefined : live;
6599
7037
 
6600
7038
  // src/proxmox/zfs-pool-form.ts
6601
- import * as Effect96 from "effect/Effect";
6602
- import * as nodes19 from "@distilled.cloud/proxmox/nodes";
7039
+ import * as Effect99 from "effect/Effect";
7040
+ import * as nodes21 from "@distilled.cloud/proxmox/nodes";
6603
7041
  var ZFS_POOL_CREATE = "pve:POST /nodes/{node}/disks/zfs";
6604
7042
  var zfsPoolCreateEndpoint = (props) => props.devices === undefined || props.raidlevel === undefined ? undefined : ZFS_POOL_CREATE;
6605
7043
  var createForm12 = (props) => ({
@@ -6611,49 +7049,49 @@ var createForm12 = (props) => ({
6611
7049
  ...props["draid-config"] === undefined ? {} : { "draid-config": props["draid-config"] }
6612
7050
  });
6613
7051
  var toDistilledCreate5 = (props) => {
6614
- const form = createForm12(props);
7052
+ const form2 = createForm12(props);
6615
7053
  return {
6616
- ...form,
6617
- draid_config: form["draid-config"],
7054
+ ...form2,
7055
+ draid_config: form2["draid-config"],
6618
7056
  node: props.node
6619
7057
  };
6620
7058
  };
6621
7059
  var SETTLE_ATTEMPTS = 30;
6622
- var createPool2 = (props, read6) => Effect96.gen(function* () {
7060
+ var createPool2 = (props, read6) => Effect99.gen(function* () {
6623
7061
  const existing = yield* read6(props);
6624
7062
  if (existing !== undefined)
6625
7063
  return existing;
6626
7064
  if (props.devices === undefined || props.raidlevel === undefined) {
6627
- return yield* Effect96.die(new Error(`${props.node}/${props.name}: this is an adopt-only declaration (no \`devices\` or ` + "`raidlevel`) and the pool is not there to adopt. An adopt-only Proxmox.ZfsPool never " + "creates -- declare both fields for a pool this resource should build, or point this " + "declaration at a pool that already exists on this node."));
7065
+ return yield* Effect99.die(new Error(`${props.node}/${props.name}: this is an adopt-only declaration (no \`devices\` or ` + "`raidlevel`) and the pool is not there to adopt. An adopt-only Proxmox.ZfsPool never " + "creates -- declare both fields for a pool this resource should build, or point this " + "declaration at a pool that already exists on this node."));
6628
7066
  }
6629
7067
  yield* guardForm(zfsPoolCreateEndpoint(props), asForm2(createForm12(props)), true);
6630
- const upid = yield* runPve(props.target, "provision", true, nodes19.createNodeDiskZfs(toDistilledCreate5(props)));
6631
- const settle3 = (attempts) => Effect96.gen(function* () {
7068
+ const upid = yield* runPve(props.target, "provision", true, nodes21.createNodeDiskZfs(toDistilledCreate5(props)));
7069
+ const settle3 = (attempts) => Effect99.gen(function* () {
6632
7070
  const live = yield* read6(props);
6633
7071
  if (live !== undefined || attempts <= 0)
6634
7072
  return live;
6635
- yield* Effect96.sleep("2 seconds");
7073
+ yield* Effect99.sleep("2 seconds");
6636
7074
  return yield* settle3(attempts - 1);
6637
7075
  });
6638
7076
  const after = yield* settle3(SETTLE_ATTEMPTS);
6639
7077
  if (after === undefined) {
6640
- return yield* Effect96.die(new Error(`nodes/${props.node}/disks/zfs/${props.name}: POST returned ${text(upid, "(no UPID)")} ` + "but the pool has not appeared. That POST only forks a `zfscreate` worker, so the task " + `holds the real error -- read it with \`pvesh get /nodes/${props.node}/tasks/<upid>/log\`. ` + "NOTHING WAS RETRIED AND NOTHING WAS CLEANED UP: if the worker reached `zpool create`, " + "the declared devices have already been written to. DO NOT RE-RUN THIS DEPLOY BEFORE " + 'READING THAT LOG: `read` cannot tell "the worker is still running" from "the pool is ' + 'genuinely gone", so a re-run this soon can POST a SECOND `zpool create` at the SAME ' + "devices while the first one is still mid-write -- confirm the task finished (one way " + "or the other) before trying again."));
7078
+ return yield* Effect99.die(new Error(`nodes/${props.node}/disks/zfs/${props.name}: POST returned ${text(upid, "(no UPID)")} ` + "but the pool has not appeared. That POST only forks a `zfscreate` worker, so the task " + `holds the real error -- read it with \`pvesh get /nodes/${props.node}/tasks/<upid>/log\`. ` + "NOTHING WAS RETRIED AND NOTHING WAS CLEANED UP: if the worker reached `zpool create`, " + "the declared devices have already been written to. DO NOT RE-RUN THIS DEPLOY BEFORE " + 'READING THAT LOG: `read` cannot tell "the worker is still running" from "the pool is ' + 'genuinely gone", so a re-run this soon can POST a SECOND `zpool create` at the SAME ' + "devices while the first one is still mid-write -- confirm the task finished (one way " + "or the other) before trying again."));
6641
7079
  }
6642
7080
  return after;
6643
7081
  });
6644
- var destroyPool = (props) => runPve(props.target, "provision", true, nodes19.deleteNodeDiskZfs({ name: props.name, node: props.node }));
7082
+ var destroyPool = (props) => runPve(props.target, "provision", true, nodes21.deleteNodeDiskZfs({ name: props.name, node: props.node }));
6645
7083
 
6646
7084
  // src/proxmox/zfs-pool.ts
6647
- var ProxmoxZfsPool = Resource35("Proxmox.ZfsPool", {
7085
+ var ProxmoxZfsPool = Resource36("Proxmox.ZfsPool", {
6648
7086
  defaultRemovalPolicy: "retain"
6649
7087
  });
6650
- var ProxmoxZfsPoolProvider = () => Provider35.effect(ProxmoxZfsPool, Effect97.succeed(ProxmoxZfsPool.Provider.of({
6651
- list: () => Effect97.succeed([]),
6652
- read: Effect97.fn(function* ({ olds, output }) {
7088
+ var ProxmoxZfsPoolProvider = () => Provider36.effect(ProxmoxZfsPool, Effect100.succeed(ProxmoxZfsPool.Provider.of({
7089
+ list: () => Effect100.succeed([]),
7090
+ read: Effect100.fn(function* ({ olds, output }) {
6653
7091
  return dropUnreadable8(yield* output === undefined ? readPool2(olds) : readPoolOrFail(olds));
6654
7092
  }),
6655
- diff: Effect97.fn(function* ({ news, output }) {
6656
- if (!isResolved30(news))
7093
+ diff: Effect100.fn(function* ({ news, output }) {
7094
+ if (!isResolved31(news))
6657
7095
  return;
6658
7096
  yield* guardForm(zfsPoolCreateEndpoint(news), asForm2(createForm12(news)), output === undefined);
6659
7097
  if (output === undefined)
@@ -6669,10 +7107,10 @@ var ProxmoxZfsPoolProvider = () => Provider35.effect(ProxmoxZfsPool, Effect97.su
6669
7107
  }
6670
7108
  return { action: "noop" };
6671
7109
  }),
6672
- reconcile: Effect97.fn(function* ({ news }) {
6673
- return yield* createPool2(news, (props) => readPool2(props).pipe(Effect97.map(dropUnreadable8)));
7110
+ reconcile: Effect100.fn(function* ({ news }) {
7111
+ return yield* createPool2(news, (props) => readPool2(props).pipe(Effect100.map(dropUnreadable8)));
6674
7112
  }),
6675
- delete: Effect97.fn(function* ({ olds }) {
7113
+ delete: Effect100.fn(function* ({ olds }) {
6676
7114
  yield* destroyPool(olds);
6677
7115
  })
6678
7116
  })));
@@ -6737,9 +7175,12 @@ export {
6737
7175
  ProxmoxSdnZone,
6738
7176
  ProxmoxSdnZoneProvider,
6739
7177
  ProxmoxStorage,
7178
+ ProxmoxStorageDownload,
7179
+ ProxmoxStorageDownloadProvider,
6740
7180
  ProxmoxStorageProvider,
6741
7181
  ProxmoxUser,
6742
7182
  ProxmoxUserProvider,
7183
+ ProxmoxVm,
6743
7184
  ProxmoxVmProvider,
6744
7185
  ProxmoxZfsPool,
6745
7186
  ProxmoxZfsPoolProvider,
@@ -6752,5 +7193,5 @@ export {
6752
7193
  violations
6753
7194
  };
6754
7195
 
6755
- //# debugId=B5C51EB76E4323A364756E2164756E21
7196
+ //# debugId=CF5040306473FBD564756E2164756E21
6756
7197
  //# sourceMappingURL=index.js.map