@homeflare/alchemy 0.38.0 → 0.39.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 (165) hide show
  1. package/README.md +22 -0
  2. package/dist/forgejo/index.js +4 -2
  3. package/dist/forgejo/index.js.map +3 -3
  4. package/dist/forgejo/team-member.d.ts +25 -0
  5. package/dist/forgejo/team-member.d.ts.map +1 -1
  6. package/dist/proxmox/generated/constraints/index.d.ts +1 -1
  7. package/dist/proxmox/generated/constraints/index.d.ts.map +1 -1
  8. package/dist/proxmox/generated/constraints/pve-access.d.ts +1 -1
  9. package/dist/proxmox/generated/constraints/pve-cluster-backup.d.ts +1 -1
  10. package/dist/proxmox/generated/constraints/pve-cluster-ceph.d.ts +1 -1
  11. package/dist/proxmox/generated/constraints/pve-cluster-firewall.d.ts +1 -1
  12. package/dist/proxmox/generated/constraints/pve-cluster-ha.d.ts +1 -1
  13. package/dist/proxmox/generated/constraints/pve-cluster-metrics.d.ts +1 -1
  14. package/dist/proxmox/generated/constraints/pve-cluster-notifications.d.ts +1 -1
  15. package/dist/proxmox/generated/constraints/pve-cluster-replication.d.ts +1 -1
  16. package/dist/proxmox/generated/constraints/pve-cluster-sdn.d.ts +1 -1
  17. package/dist/proxmox/generated/constraints/pve-nodes-ceph.d.ts +1 -1
  18. package/dist/proxmox/generated/constraints/pve-nodes-disks.d.ts +1 -1
  19. package/dist/proxmox/generated/constraints/pve-nodes-lxc.d.ts +1 -1
  20. package/dist/proxmox/generated/constraints/pve-nodes-network.d.ts +1 -1
  21. package/dist/proxmox/generated/constraints/pve-nodes-qemu.d.ts +1 -1
  22. package/dist/proxmox/generated/constraints/pve-nodes-storage.d.ts +23 -0
  23. package/dist/proxmox/generated/constraints/pve-nodes-storage.d.ts.map +1 -0
  24. package/dist/proxmox/generated/constraints/pve-pools.d.ts +1 -1
  25. package/dist/proxmox/generated/constraints/pve-storage.d.ts +1 -1
  26. package/dist/proxmox/index.d.ts +14 -3
  27. package/dist/proxmox/index.d.ts.map +1 -1
  28. package/dist/proxmox/index.js +565 -133
  29. package/dist/proxmox/index.js.map +33 -23
  30. package/dist/proxmox/qemu-form.d.ts +27 -18
  31. package/dist/proxmox/qemu-form.d.ts.map +1 -1
  32. package/dist/proxmox/qemu-judge.d.ts +30 -0
  33. package/dist/proxmox/qemu-judge.d.ts.map +1 -0
  34. package/dist/proxmox/qemu-lifecycle.d.ts +16 -2
  35. package/dist/proxmox/qemu-lifecycle.d.ts.map +1 -1
  36. package/dist/proxmox/qemu-net.d.ts +9 -0
  37. package/dist/proxmox/qemu-net.d.ts.map +1 -0
  38. package/dist/proxmox/qemu-props.d.ts +112 -0
  39. package/dist/proxmox/qemu-props.d.ts.map +1 -0
  40. package/dist/proxmox/qemu-volume.d.ts +17 -0
  41. package/dist/proxmox/qemu-volume.d.ts.map +1 -0
  42. package/dist/proxmox/qemu.d.ts +14 -27
  43. package/dist/proxmox/qemu.d.ts.map +1 -1
  44. package/dist/proxmox/storage-download-errors.d.ts +5 -0
  45. package/dist/proxmox/storage-download-errors.d.ts.map +1 -0
  46. package/dist/proxmox/storage-download-identity.d.ts +27 -0
  47. package/dist/proxmox/storage-download-identity.d.ts.map +1 -0
  48. package/dist/proxmox/storage-download-lifecycle.d.ts +97 -0
  49. package/dist/proxmox/storage-download-lifecycle.d.ts.map +1 -0
  50. package/dist/proxmox/storage-download-props.d.ts +36 -0
  51. package/dist/proxmox/storage-download-props.d.ts.map +1 -0
  52. package/dist/proxmox/storage-download-task.d.ts +17 -0
  53. package/dist/proxmox/storage-download-task.d.ts.map +1 -0
  54. package/dist/proxmox/storage-download.d.ts +44 -0
  55. package/dist/proxmox/storage-download.d.ts.map +1 -0
  56. package/dist/telemetry/fake-collector.d.ts +36 -0
  57. package/dist/telemetry/fake-collector.d.ts.map +1 -0
  58. package/dist/telemetry/index.d.ts +11 -0
  59. package/dist/telemetry/index.d.ts.map +1 -0
  60. package/dist/telemetry/index.js +223 -0
  61. package/dist/telemetry/index.js.map +12 -0
  62. package/dist/telemetry/layer.d.ts +86 -0
  63. package/dist/telemetry/layer.d.ts.map +1 -0
  64. package/dist/telemetry/redact-serialization.d.ts +21 -0
  65. package/dist/telemetry/redact-serialization.d.ts.map +1 -0
  66. package/dist/telemetry/redact.d.ts +46 -0
  67. package/dist/telemetry/redact.d.ts.map +1 -0
  68. package/dist/unifi/drift.d.ts +27 -0
  69. package/dist/unifi/drift.d.ts.map +1 -0
  70. package/dist/unifi/fake-unifi.d.ts +5 -1
  71. package/dist/unifi/fake-unifi.d.ts.map +1 -1
  72. package/dist/unifi/firewall-zone-form.d.ts +6 -0
  73. package/dist/unifi/firewall-zone-form.d.ts.map +1 -1
  74. package/dist/unifi/firewall-zone.d.ts +1 -1
  75. package/dist/unifi/firewall-zone.d.ts.map +1 -1
  76. package/dist/unifi/index.d.ts +4 -3
  77. package/dist/unifi/index.d.ts.map +1 -1
  78. package/dist/unifi/index.js +138 -58
  79. package/dist/unifi/index.js.map +10 -8
  80. package/dist/unifi/network-drift.d.ts +26 -0
  81. package/dist/unifi/network-drift.d.ts.map +1 -0
  82. package/dist/unifi/network-form.d.ts +40 -7
  83. package/dist/unifi/network-form.d.ts.map +1 -1
  84. package/dist/unifi/network.d.ts +1 -0
  85. package/dist/unifi/network.d.ts.map +1 -1
  86. package/dist/unifi/paginate.d.ts +36 -0
  87. package/dist/unifi/paginate.d.ts.map +1 -0
  88. package/dist/unifi/resource.d.ts +36 -1
  89. package/dist/unifi/resource.d.ts.map +1 -1
  90. package/docs/telemetry-spike.md +94 -0
  91. package/docs/telemetry.md +109 -0
  92. package/docs/unifi.md +56 -0
  93. package/package.json +6 -2
  94. package/src/forgejo/team-member.test.ts +14 -0
  95. package/src/forgejo/team-member.ts +28 -1
  96. package/src/proxmox/constraints-required.test.ts +1 -0
  97. package/src/proxmox/generated/constraints/index.ts +3 -1
  98. package/src/proxmox/generated/constraints/pve-access.ts +1 -1
  99. package/src/proxmox/generated/constraints/pve-cluster-backup.ts +1 -1
  100. package/src/proxmox/generated/constraints/pve-cluster-ceph.ts +1 -1
  101. package/src/proxmox/generated/constraints/pve-cluster-firewall.ts +1 -1
  102. package/src/proxmox/generated/constraints/pve-cluster-ha.ts +1 -1
  103. package/src/proxmox/generated/constraints/pve-cluster-metrics.ts +1 -1
  104. package/src/proxmox/generated/constraints/pve-cluster-notifications.ts +1 -1
  105. package/src/proxmox/generated/constraints/pve-cluster-replication.ts +1 -1
  106. package/src/proxmox/generated/constraints/pve-cluster-sdn.ts +1 -1
  107. package/src/proxmox/generated/constraints/pve-nodes-ceph.ts +1 -1
  108. package/src/proxmox/generated/constraints/pve-nodes-disks.ts +1 -1
  109. package/src/proxmox/generated/constraints/pve-nodes-lxc.ts +1 -1
  110. package/src/proxmox/generated/constraints/pve-nodes-network.ts +1 -1
  111. package/src/proxmox/generated/constraints/pve-nodes-qemu.ts +1 -1
  112. package/src/proxmox/generated/constraints/pve-nodes-storage.ts +30 -0
  113. package/src/proxmox/generated/constraints/pve-pools.ts +1 -1
  114. package/src/proxmox/generated/constraints/pve-storage.ts +1 -1
  115. package/src/proxmox/index.test.ts +11 -6
  116. package/src/proxmox/index.ts +19 -3
  117. package/src/proxmox/qemu-form.ts +49 -13
  118. package/src/proxmox/qemu-identity.test.ts +30 -0
  119. package/src/proxmox/qemu-judge.test.ts +65 -0
  120. package/src/proxmox/qemu-judge.ts +84 -0
  121. package/src/proxmox/qemu-lifecycle.test.ts +78 -19
  122. package/src/proxmox/qemu-lifecycle.ts +131 -32
  123. package/src/proxmox/qemu-net.test.ts +48 -0
  124. package/src/proxmox/qemu-net.ts +78 -0
  125. package/src/proxmox/qemu-ownership.test.ts +44 -0
  126. package/src/proxmox/qemu-props.test.ts +87 -0
  127. package/src/proxmox/qemu-props.ts +157 -0
  128. package/src/proxmox/qemu-volume.test.ts +80 -0
  129. package/src/proxmox/qemu-volume.ts +121 -0
  130. package/src/proxmox/qemu.ts +15 -29
  131. package/src/proxmox/storage-download-errors.ts +7 -0
  132. package/src/proxmox/storage-download-identity.test.ts +54 -0
  133. package/src/proxmox/storage-download-identity.ts +50 -0
  134. package/src/proxmox/storage-download-lifecycle.ts +226 -0
  135. package/src/proxmox/storage-download-ownership.test.ts +50 -0
  136. package/src/proxmox/storage-download-props.ts +38 -0
  137. package/src/proxmox/storage-download-task.ts +72 -0
  138. package/src/proxmox/storage-download.test.ts +216 -0
  139. package/src/proxmox/storage-download.ts +58 -0
  140. package/src/telemetry/fake-collector.ts +59 -0
  141. package/src/telemetry/http-client-sealing.test.ts +82 -0
  142. package/src/telemetry/index.ts +10 -0
  143. package/src/telemetry/layer.test.ts +204 -0
  144. package/src/telemetry/layer.ts +152 -0
  145. package/src/telemetry/redact-serialization.ts +178 -0
  146. package/src/telemetry/redact.test.ts +124 -0
  147. package/src/telemetry/redact.ts +147 -0
  148. package/src/unifi/drift.test.ts +78 -0
  149. package/src/unifi/drift.ts +56 -0
  150. package/src/unifi/errors-and-secrets.test.ts +127 -0
  151. package/src/unifi/fake-unifi.ts +5 -1
  152. package/src/unifi/firewall-zone-form.ts +31 -2
  153. package/src/unifi/firewall-zone.test.ts +21 -1
  154. package/src/unifi/firewall-zone.ts +1 -1
  155. package/src/unifi/get-only-guard.test.ts +165 -0
  156. package/src/unifi/index.ts +15 -1
  157. package/src/unifi/network-drift.test.ts +207 -0
  158. package/src/unifi/network-drift.ts +80 -0
  159. package/src/unifi/network-form.ts +11 -39
  160. package/src/unifi/network.test.ts +7 -82
  161. package/src/unifi/network.ts +6 -6
  162. package/src/unifi/paginate.test.ts +228 -0
  163. package/src/unifi/paginate.ts +129 -0
  164. package/src/unifi/resource.ts +73 -3
  165. package/src/unifi/write-op-reference.test.ts +236 -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,152 @@ 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 fresh = NEW_DISK2.exec(text3) ?? NEW_CLOUDINIT.exec(text3);
6049
+ if (fresh !== null) {
6050
+ return {
6051
+ kind: "fresh",
6052
+ options: new Map,
6053
+ size: undefined,
6054
+ source: fresh[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
+ return { kind: "volume", options, size, source, volname };
6069
+ };
6070
+ var printOptions = (source, volname, options, size) => [
6071
+ `${source}:${volname}`,
6072
+ ...[...options].map(([k, v]) => `${k}=${v}`),
6073
+ ...size === undefined ? [] : [`size=${size}`]
6074
+ ].join(",");
6075
+ var judgeDisk = (key, declared2, live) => {
6076
+ const want = parseDisk(declared2);
6077
+ const have = parseDisk(live);
6078
+ if (want.source !== have.source) {
6079
+ return {
6080
+ 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."
6081
+ };
6082
+ }
6083
+ if (want.kind === "fresh")
6084
+ return {};
6085
+ if (want.volname !== have.volname) {
6086
+ return {
6087
+ 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."
6088
+ };
6089
+ }
6090
+ if (want.size !== undefined && have.size !== undefined && want.size !== have.size) {
6091
+ return {
6092
+ 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."
6093
+ };
6094
+ }
6095
+ if (sameMap(want.options, have.options))
6096
+ return {};
6097
+ return { put: printOptions(have.source, have.volname, want.options, have.size) };
6098
+ };
6099
+
6100
+ // src/proxmox/qemu-net.ts
6101
+ var NIC_MODELS = [
6102
+ "e1000",
6103
+ "e1000e",
6104
+ "i82551",
6105
+ "i82557b",
6106
+ "i82559er",
6107
+ "i82562",
6108
+ "i82801",
6109
+ "ne2k_isa",
6110
+ "ne2k_pci",
6111
+ "pcnet",
6112
+ "rtl8139",
6113
+ "virtio",
6114
+ "vmxnet3"
6115
+ ];
6116
+ var netPairs = (value) => new Map(value.split(",").map((part) => part.trim()).filter((part) => part !== "").map((part) => {
6117
+ const at = part.indexOf("=");
6118
+ return at === -1 ? [part, ""] : [part.slice(0, at), part.slice(at + 1)];
6119
+ }));
6120
+ var modelKey = (map31) => NIC_MODELS.find((model) => map31.has(model));
6121
+ var netMaps2 = (declared2, live) => {
6122
+ const want = netPairs(declared2);
6123
+ const have = netPairs(live);
6124
+ const wantModel = modelKey(want);
6125
+ const haveModel = modelKey(have);
6126
+ if (wantModel !== undefined && (want.get(wantModel) ?? "") === "" && haveModel !== undefined) {
6127
+ want.set(wantModel, have.get(haveModel) ?? "");
6128
+ }
6129
+ return { have, want };
6130
+ };
6131
+ var sameNet = (declared2, live) => {
6132
+ const { have, want } = netMaps2(declared2, live);
6133
+ return have.size === want.size && [...want].every(([k, v]) => have.get(k) === v);
6134
+ };
6135
+ var netWrite2 = (declared2, live) => {
6136
+ const want = netPairs(declared2);
6137
+ const wantModel = modelKey(want);
6138
+ const have = netPairs(live);
6139
+ const haveModel = modelKey(have);
6140
+ if (wantModel !== undefined && (want.get(wantModel) ?? "") === "" && haveModel !== undefined) {
6141
+ want.set(wantModel, have.get(haveModel) ?? "");
6142
+ }
6143
+ return [...want].map(([k, v]) => v === "" ? k : `${k}=${v}`).join(",");
6144
+ };
6145
+
6146
+ // src/proxmox/qemu-judge.ts
6147
+ var judge2 = (props, config7) => {
6148
+ const put = {};
6149
+ const refuse3 = [];
6150
+ const drift = new Set;
6151
+ for (const key of declaredKeys2(props)) {
6152
+ const want = wireValue2(declaredValue2(props, key));
6153
+ const have = config7[key];
6154
+ const family = indexedKey2(key)?.[0];
6155
+ if (family === "scsi" || family === "ide") {
6156
+ if (have === undefined) {
6157
+ drift.add(key);
6158
+ put[key] = want;
6159
+ } else {
6160
+ const verdict = judgeDisk(key, want, have);
6161
+ if (verdict.refuse !== undefined) {
6162
+ drift.add(key);
6163
+ refuse3.push(verdict.refuse);
6164
+ } else if (verdict.put !== undefined) {
6165
+ drift.add(key);
6166
+ put[key] = verdict.put;
6167
+ }
6168
+ }
6169
+ continue;
6170
+ }
6171
+ if (family === "net") {
6172
+ if (have === undefined) {
6173
+ drift.add(key);
6174
+ put[key] = want;
6175
+ } else if (!sameNet(want, have)) {
6176
+ drift.add(key);
6177
+ put[key] = netWrite2(want, have);
6178
+ }
6179
+ continue;
6180
+ }
6181
+ if (want !== (have ?? "")) {
6182
+ drift.add(key);
6183
+ put[key] = want;
6184
+ }
6185
+ }
6186
+ return { drift: [...drift].sort(), put, refuse: refuse3 };
6187
+ };
6188
+ 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.";
6189
+
5983
6190
  // src/proxmox/qemu-read.ts
5984
6191
  import * as cluster10 from "@distilled.cloud/proxmox/cluster";
5985
6192
  import * as nodes15 from "@distilled.cloud/proxmox/nodes";
@@ -6040,15 +6247,11 @@ var qemuTask = (props, operation, what, polls) => Effect83.gen(function* () {
6040
6247
  var CREATE_POLLS2 = 180;
6041
6248
  var DELETE_POLLS = 60;
6042
6249
  var attributesOf9 = (live, props) => ({
6043
- cores: int(live.cores, 1),
6044
- memory: int(live.memory, 512),
6045
- name: typeof live.name === "string" ? live.name : "",
6250
+ config: storedConfig2(live),
6046
6251
  node: props.node,
6047
- onboot: live.onboot === 1 || live.onboot === true,
6048
- sockets: int(live.sockets, 1),
6049
6252
  vmid: props.vmid
6050
6253
  });
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);
6254
+ var matches9 = (attributes2, props) => declaredKeys2(props).filter(isManagedKey2).every((key) => attributes2.config[key] === wireValue2(declaredValue2(props, key)));
6052
6255
  var spec5 = {
6053
6256
  attributes: attributesOf9,
6054
6257
  collection: (props) => `nodes/${props.node}/qemu`,
@@ -6059,84 +6262,310 @@ var spec5 = {
6059
6262
  },
6060
6263
  matches: matches9,
6061
6264
  path: (props) => `nodes/${props.node}/qemu/${String(props.vmid)}/config`,
6062
- updateForm: shape9
6265
+ updateForm: updateForm6
6063
6266
  };
6064
6267
  var { guardCreate: guardCreate10, guardUpdate: guardUpdate10 } = specGuards(spec5);
6065
6268
  var readQemu = (props) => readVm(props).pipe(Effect84.map((live) => live === undefined ? undefined : attributesOf9(live, props)));
6066
6269
  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));
6270
+ var refuseUnmanaged = (props) => {
6271
+ const refused2 = formRefusals(props);
6272
+ return refused2.length === 0 ? Effect84.void : Effect84.fail(new QemuRefusedError(refused2.join(`
6273
+ `)));
6274
+ };
6275
+ var refuseChange = (change) => change.refuse.length === 0 ? Effect84.void : Effect84.fail(new QemuRefusedError(change.refuse.join(`
6276
+ `)));
6067
6277
  var qemuHandlers = {
6068
6278
  list: () => Effect84.succeed([]),
6069
- read: ({ olds }) => readQemu(olds),
6279
+ read: Effect84.fn(function* ({
6280
+ fqn,
6281
+ instanceId,
6282
+ olds,
6283
+ output
6284
+ }) {
6285
+ const found = yield* readQemu(olds);
6286
+ const settled2 = Effect84.sync(() => found !== undefined && judge2(olds, found.config).drift.length === 0);
6287
+ return yield* ownedRead({ fqn, instanceId, output }, found, settled2);
6288
+ }),
6070
6289
  diff: Effect84.fn(function* ({
6071
6290
  news,
6291
+ olds,
6072
6292
  output
6073
6293
  }) {
6074
6294
  if (!isResolved26(news))
6075
6295
  return;
6296
+ const identity2 = identityRefusal(news.vmid, output?.vmid ?? olds.vmid);
6297
+ if (identity2 !== undefined)
6298
+ return yield* Effect84.fail(new QemuRefusedError(identity2));
6299
+ yield* refuseUnmanaged(news);
6076
6300
  yield* guardCreate10(news, output === undefined);
6077
6301
  yield* guardUpdate10(news);
6078
6302
  if (output === undefined)
6079
6303
  return;
6080
6304
  const live = yield* readQemu(news);
6081
6305
  if (live === undefined) {
6306
+ 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
6307
  yield* guardCreate10(news, true);
6083
6308
  return { action: "update" };
6084
6309
  }
6085
- return { action: spec5.matches(live, news) ? "noop" : "update" };
6310
+ const change = judge2(news, live.config);
6311
+ yield* refuseChange(change);
6312
+ return { action: change.drift.length === 0 ? "noop" : "update" };
6086
6313
  }),
6087
- reconcile: Effect84.fn(function* ({ news }) {
6314
+ reconcile: Effect84.fn(function* ({
6315
+ fqn,
6316
+ instanceId,
6317
+ news,
6318
+ olds,
6319
+ output
6320
+ }) {
6321
+ const identity2 = identityRefusal(news.vmid, output?.vmid ?? olds?.vmid);
6322
+ if (identity2 !== undefined)
6323
+ return yield* Effect84.fail(new QemuRefusedError(identity2));
6324
+ yield* refuseUnmanaged(news);
6088
6325
  const live = yield* readQemu(news);
6089
6326
  yield* guardCreate10(news, live === undefined);
6090
6327
  yield* guardUpdate10(news);
6091
6328
  if (live === undefined) {
6092
6329
  yield* qemuTask(news, nodes17.createNodeQemu({ ...createForm9(news), node: news.node }), `create VM ${String(news.vmid)}`, CREATE_POLLS2);
6093
6330
  } 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) }));
6331
+ yield* refuseTakeover({ fqn, instanceId, output }, `Proxmox.Vm VM ${String(news.vmid)} on ${news.node}`);
6332
+ const change = judge2(news, live.config);
6333
+ yield* refuseChange(change);
6334
+ if (Object.keys(change.put).length > 0) {
6335
+ yield* runPve(news.target, "provision", true, nodes17.putNodeQemuConfig({ ...change.put, node: news.node, vmid: String(news.vmid) }));
6097
6336
  }
6098
6337
  }
6099
6338
  const after = yield* readQemu(news);
6100
6339
  if (after === undefined) {
6101
6340
  return yield* Effect84.fail(new QemuRefusedError(`${spec5.path(news)}: write returned success but the VM is still absent`));
6102
6341
  }
6342
+ const left = judge2(news, after.config);
6343
+ if (left.drift.length > 0) {
6344
+ 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."));
6345
+ }
6103
6346
  return after;
6104
6347
  }),
6105
6348
  delete: ({ olds }) => deleteQemu(olds)
6106
6349
  };
6107
6350
 
6108
6351
  // src/proxmox/qemu.ts
6109
- var ProxmoxVm = Resource28("Proxmox.Vm");
6352
+ var ProxmoxVm = Resource28("Proxmox.Vm", { defaultRemovalPolicy: "retain" });
6110
6353
  var ProxmoxVmProvider = () => Provider28.effect(ProxmoxVm, Effect85.succeed(ProxmoxVm.Provider.of(qemuHandlers)));
6111
- // src/proxmox/replication-job.ts
6354
+ // src/proxmox/storage-download.ts
6112
6355
  import { Resource as Resource29 } from "alchemy";
6113
6356
  import * as Provider29 from "alchemy/Provider";
6357
+ import * as Effect88 from "effect/Effect";
6358
+
6359
+ // src/proxmox/storage-download-lifecycle.ts
6360
+ import { isResolved as isResolved27 } from "alchemy/Diff";
6361
+ import * as nodes19 from "@distilled.cloud/proxmox/nodes";
6114
6362
  import * as Effect87 from "effect/Effect";
6115
6363
 
6364
+ // src/proxmox/storage-download-identity.ts
6365
+ var PINNED = [
6366
+ "checksum",
6367
+ "checksumAlgorithm",
6368
+ "compression",
6369
+ "url",
6370
+ "verifyCertificates"
6371
+ ];
6372
+ var judgeIdentity = (news, olds) => {
6373
+ if (olds === undefined)
6374
+ return { kind: "same" };
6375
+ if (news.filename !== olds.filename || news.storage !== olds.storage) {
6376
+ return { kind: "replace" };
6377
+ }
6378
+ const changed = PINNED.filter((key) => news[key] !== olds[key]);
6379
+ if (changed.length === 0)
6380
+ return { kind: "same" };
6381
+ return {
6382
+ kind: "pin-changed",
6383
+ 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."
6384
+ };
6385
+ };
6386
+
6387
+ // src/proxmox/storage-download-errors.ts
6388
+ class StorageDownloadRefusedError extends Error {
6389
+ constructor(message) {
6390
+ super(message);
6391
+ this.name = "StorageDownloadRefusedError";
6392
+ }
6393
+ }
6394
+
6395
+ // src/proxmox/storage-download-task.ts
6396
+ import * as nodes18 from "@distilled.cloud/proxmox/nodes";
6397
+ import * as Effect86 from "effect/Effect";
6398
+ var storageDownloadTask = (where, operation, what, polls) => Effect86.gen(function* () {
6399
+ const credential = yield* mint(where.target, "provision");
6400
+ const upid = text(yield* runPveWith(where.target, credential, true, operation));
6401
+ if (upid === "") {
6402
+ return yield* Effect86.fail(new StorageDownloadRefusedError(`${what}: PVE returned no task id, so the write cannot be confirmed and is not claimed.`));
6403
+ }
6404
+ let exit = "still running when this provider stopped waiting";
6405
+ for (let attempt = 0;attempt < polls; attempt++) {
6406
+ const status = yield* runPveWith(where.target, credential, false, nodes18.getNodeTaskStatus({ node: where.node, upid })).pipe(Effect86.orElseSucceed(() => {
6407
+ return;
6408
+ }));
6409
+ if (status === undefined || status.status === undefined) {
6410
+ exit = "the task could not be read";
6411
+ break;
6412
+ }
6413
+ if (status.status === "stopped") {
6414
+ exit = text(status.exitstatus, "stopped with no exitstatus");
6415
+ break;
6416
+ }
6417
+ yield* Effect86.sleep("1 second");
6418
+ }
6419
+ if (exit !== "OK") {
6420
+ return yield* Effect86.fail(new StorageDownloadRefusedError(`${what}: task ${upid} ended "${exit}". Read the task log before running the deploy again.`));
6421
+ }
6422
+ });
6423
+
6424
+ // src/proxmox/storage-download-lifecycle.ts
6425
+ var CREATE_POLLS3 = 600;
6426
+ var DELETE_POLLS2 = 60;
6427
+ var DOWNLOAD_ENDPOINT = "pve:POST /nodes/{node}/storage/{storage}/download-url";
6428
+ var downloadForm = (props) => ({
6429
+ checksum: props.checksum,
6430
+ "checksum-algorithm": props.checksumAlgorithm,
6431
+ ...props.compression === undefined ? {} : { compression: props.compression },
6432
+ content: "import",
6433
+ filename: props.filename,
6434
+ node: props.node,
6435
+ storage: props.storage,
6436
+ url: props.url,
6437
+ ...props.verifyCertificates === undefined ? {} : { "verify-certificates": props.verifyCertificates ? "1" : "0" }
6438
+ });
6439
+ var createRefusals2 = (props) => {
6440
+ const refuse3 = [];
6441
+ if (props.checksum.trim() === "") {
6442
+ refuse3.push(`${props.filename}: checksum is required — an unpinned download is not a declaration.`);
6443
+ }
6444
+ return refuse3.concat(formViolations(DOWNLOAD_ENDPOINT, downloadForm(props), true).map((why) => `${props.filename}: ${why}`));
6445
+ };
6446
+ var readDownload = (props) => Effect87.gen(function* () {
6447
+ const rows = yield* runPve(props.target, "read", false, nodes19.listNodeStorageContent({
6448
+ content: "import",
6449
+ node: props.node,
6450
+ storage: props.storage
6451
+ }));
6452
+ if (!Array.isArray(rows)) {
6453
+ return yield* Effect87.fail(new StorageDownloadRefusedError(`${props.storage}: the content list did not come back as a list.`));
6454
+ }
6455
+ const found = rows.find((row) => row.volid.endsWith(`/${props.filename}`));
6456
+ if (found === undefined)
6457
+ return;
6458
+ return {
6459
+ filename: props.filename,
6460
+ format: text(found.format, "raw"),
6461
+ node: props.node,
6462
+ size: int(found.size, 0),
6463
+ storage: props.storage,
6464
+ volid: text(found.volid, "")
6465
+ };
6466
+ });
6467
+ var destroyDownload = (props) => Effect87.gen(function* () {
6468
+ const live = yield* readDownload(props);
6469
+ if (live === undefined)
6470
+ return;
6471
+ yield* storageDownloadTask(props, nodes19.deleteNodeStorageContent({
6472
+ node: props.node,
6473
+ storage: props.storage,
6474
+ volume: live.volid
6475
+ }), `delete ${live.volid}`, DELETE_POLLS2);
6476
+ });
6477
+ var storageDownloadHandlers = {
6478
+ list: () => Effect87.succeed([]),
6479
+ read: Effect87.fn(function* ({
6480
+ fqn,
6481
+ instanceId,
6482
+ olds,
6483
+ output
6484
+ }) {
6485
+ const found = yield* readDownload(olds);
6486
+ return yield* ownedRead({ fqn, instanceId, output }, found, Effect87.succeed(true));
6487
+ }),
6488
+ diff: Effect87.fn(function* ({
6489
+ news,
6490
+ olds,
6491
+ output
6492
+ }) {
6493
+ if (!isResolved27(news))
6494
+ return;
6495
+ const refused2 = createRefusals2(news);
6496
+ if (refused2.length > 0) {
6497
+ return yield* Effect87.fail(new StorageDownloadRefusedError(refused2.join(`
6498
+ `)));
6499
+ }
6500
+ if (output === undefined)
6501
+ return;
6502
+ const identity2 = judgeIdentity(news, olds);
6503
+ if (identity2.kind === "replace")
6504
+ return { action: "replace" };
6505
+ const live = yield* readDownload(news);
6506
+ if (identity2.kind === "pin-changed" && live !== undefined) {
6507
+ return yield* Effect87.fail(new StorageDownloadRefusedError(identity2.refuse));
6508
+ }
6509
+ return { action: live === undefined ? "update" : "noop" };
6510
+ }),
6511
+ reconcile: Effect87.fn(function* ({
6512
+ fqn,
6513
+ instanceId,
6514
+ news,
6515
+ output
6516
+ }) {
6517
+ const refused2 = createRefusals2(news);
6518
+ if (refused2.length > 0) {
6519
+ return yield* Effect87.fail(new StorageDownloadRefusedError(refused2.join(`
6520
+ `)));
6521
+ }
6522
+ const live = yield* readDownload(news);
6523
+ if (live === undefined) {
6524
+ yield* storageDownloadTask(news, nodes19.downloadNodesStorageUrl(downloadForm(news)), `download ${news.filename} onto ${news.storage}`, CREATE_POLLS3);
6525
+ } else {
6526
+ yield* refuseTakeover({ fqn, instanceId, output }, `Proxmox.StorageDownload ${news.filename} on ${news.storage}`);
6527
+ }
6528
+ const after = yield* readDownload(news);
6529
+ if (after === undefined) {
6530
+ 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."));
6531
+ }
6532
+ return after;
6533
+ }),
6534
+ delete: ({ olds }) => destroyDownload(olds)
6535
+ };
6536
+
6537
+ // src/proxmox/storage-download.ts
6538
+ var ProxmoxStorageDownload = Resource29("Proxmox.StorageDownload");
6539
+ var ProxmoxStorageDownloadProvider = () => Provider29.effect(ProxmoxStorageDownload, Effect88.succeed(ProxmoxStorageDownload.Provider.of(storageDownloadHandlers)));
6540
+ // src/proxmox/replication-job.ts
6541
+ import { Resource as Resource30 } from "alchemy";
6542
+ import * as Provider30 from "alchemy/Provider";
6543
+ import * as Effect90 from "effect/Effect";
6544
+
6116
6545
  // src/proxmox/replication-job-lifecycle.ts
6117
- import { isResolved as isResolved27 } from "alchemy/Diff";
6546
+ import { isResolved as isResolved28 } from "alchemy/Diff";
6118
6547
  import * as cluster11 from "@distilled.cloud/proxmox/cluster";
6119
6548
  import { ProxmoxParseError as ProxmoxParseError6 } from "@distilled.cloud/proxmox/Errors";
6120
- import * as Effect86 from "effect/Effect";
6549
+ import * as Effect89 from "effect/Effect";
6121
6550
  import * as Schema6 from "effect/Schema";
6122
6551
 
6123
6552
  // src/proxmox/replication-job-form.ts
6124
6553
  var DEFAULT_SCHEDULE = "*/15";
6125
6554
  var jobId = (props) => `${String(props.guest)}-${String(props.jobnum)}`;
6126
- var shape10 = (props) => ({
6555
+ var shape9 = (props) => ({
6127
6556
  comment: props.comment ?? "",
6128
6557
  disable: props.disable === true ? "1" : "0",
6129
6558
  schedule: props.schedule ?? DEFAULT_SCHEDULE,
6130
6559
  ...props.rate === undefined ? {} : { rate: String(props.rate) }
6131
6560
  });
6132
6561
  var createBody5 = (props) => ({
6133
- ...shape10(props),
6562
+ ...shape9(props),
6134
6563
  id: jobId(props),
6135
6564
  target: props.targetNode,
6136
6565
  type: "local"
6137
6566
  });
6138
6567
  var updateBody4 = (props) => ({
6139
- ...shape10(props),
6568
+ ...shape9(props),
6140
6569
  delete: "remove_job"
6141
6570
  });
6142
6571
 
@@ -6178,21 +6607,21 @@ var malformed = () => new ProxmoxParseError6({
6178
6607
  body: undefined,
6179
6608
  cause: "Replication job response does not match the requested vendor identity"
6180
6609
  });
6181
- var readReplicationJob = (props) => runPve(props.target, "read", false, cluster11.getClusterReplication({ id: jobId(props) })).pipe(Effect86.flatMap((live) => Schema6.decodeUnknownEffect(Schema6.toType(cluster11.GetClusterReplicationResponse))({
6610
+ var readReplicationJob = (props) => runPve(props.target, "read", false, cluster11.getClusterReplication({ id: jobId(props) })).pipe(Effect89.flatMap((live) => Schema6.decodeUnknownEffect(Schema6.toType(cluster11.GetClusterReplicationResponse))({
6182
6611
  ...live,
6183
6612
  guest: int(live.guest, Number.NaN),
6184
6613
  jobnum: int(live.jobnum, Number.NaN),
6185
6614
  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));
6615
+ }).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)));
6616
+ var deleteReplicationJob = (props) => runPve(props.target, "provision", true, cluster11.deleteClusterReplication({ id: jobId(props) })).pipe(Effect89.catchTag("ReplicationJobNotFound", () => Effect89.void));
6188
6617
  var replicationJobHandlers = {
6189
- list: () => Effect86.succeed([]),
6618
+ list: () => Effect89.succeed([]),
6190
6619
  read: ({ olds }) => readReplicationJob(olds),
6191
- diff: Effect86.fn(function* ({
6620
+ diff: Effect89.fn(function* ({
6192
6621
  news,
6193
6622
  output
6194
6623
  }) {
6195
- if (!isResolved27(news))
6624
+ if (!isResolved28(news))
6196
6625
  return;
6197
6626
  yield* guardCreate11(news, output === undefined);
6198
6627
  yield* guardUpdate11(news);
@@ -6205,36 +6634,36 @@ var replicationJobHandlers = {
6205
6634
  }
6206
6635
  return { action: replicationJobSpec.matches(live, news) ? "noop" : "update" };
6207
6636
  }),
6208
- reconcile: Effect86.fn(function* ({ news }) {
6637
+ reconcile: Effect89.fn(function* ({ news }) {
6209
6638
  const live = yield* readReplicationJob(news);
6210
6639
  yield* guardCreate11(news, live === undefined);
6211
6640
  yield* guardUpdate11(news);
6212
6641
  if (live === undefined) {
6213
6642
  yield* runPve(news.target, "provision", true, cluster11.createClusterReplication(replicationJobSpec.createForm(news)));
6214
6643
  } 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) }));
6644
+ const form2 = formToSend(replicationJobSpec.matches, live, news, replicationJobSpec.updateForm(news));
6645
+ if (form2 !== undefined)
6646
+ yield* runPve(news.target, "provision", true, cluster11.putClusterReplication({ ...form2, id: jobId(news) }));
6218
6647
  }
6219
6648
  const after = yield* readReplicationJob(news);
6220
6649
  if (after === undefined)
6221
- return yield* Effect86.fail(new Error(`${replicationJobSpec.path(news)}: write returned success but the resource is still absent`));
6650
+ return yield* Effect89.fail(new Error(`${replicationJobSpec.path(news)}: write returned success but the resource is still absent`));
6222
6651
  return after;
6223
6652
  }),
6224
6653
  delete: ({ olds }) => deleteReplicationJob(olds)
6225
6654
  };
6226
6655
 
6227
6656
  // src/proxmox/replication-job.ts
6228
- var ProxmoxReplicationJob = Resource29("Proxmox.ReplicationJob");
6229
- var ProxmoxReplicationJobProvider = () => Provider29.effect(ProxmoxReplicationJob, Effect87.succeed(ProxmoxReplicationJob.Provider.of(replicationJobHandlers)));
6657
+ var ProxmoxReplicationJob = Resource30("Proxmox.ReplicationJob");
6658
+ var ProxmoxReplicationJobProvider = () => Provider30.effect(ProxmoxReplicationJob, Effect90.succeed(ProxmoxReplicationJob.Provider.of(replicationJobHandlers)));
6230
6659
  // 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";
6660
+ import { Resource as Resource31 } from "alchemy";
6661
+ import { isResolved as isResolved29 } from "alchemy/Diff";
6662
+ import * as Provider31 from "alchemy/Provider";
6663
+ import * as Effect92 from "effect/Effect";
6235
6664
 
6236
6665
  // src/proxmox/sdn-apply-read.ts
6237
- import * as Effect88 from "effect/Effect";
6666
+ import * as Effect91 from "effect/Effect";
6238
6667
  var MARKED = [
6239
6668
  "cluster/sdn/zones",
6240
6669
  "cluster/sdn/vnets",
@@ -6243,7 +6672,7 @@ var MARKED = [
6243
6672
  "cluster/sdn/route-maps"
6244
6673
  ];
6245
6674
  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)));
6675
+ 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
6676
  var fabricStaged = (staged, running) => {
6248
6677
  if (staged === undefined && running === undefined)
6249
6678
  return 0;
@@ -6251,9 +6680,9 @@ var fabricStaged = (staged, running) => {
6251
6680
  return "inconsistent";
6252
6681
  return staged === running ? 0 : 1;
6253
6682
  };
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]) => {
6683
+ 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
6684
  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);
6685
+ 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
6686
  }));
6258
6687
  var canonical3 = (value) => JSON.stringify(sortDeep(value));
6259
6688
  var sortDeep = (value) => {
@@ -6266,23 +6695,23 @@ var sortDeep = (value) => {
6266
6695
  }
6267
6696
  return value;
6268
6697
  };
6269
- var sdnPendingCount = (target) => Effect88.all([markedPending(target), fabricPending(target)], { concurrency: "unbounded" }).pipe(Effect88.map(([marked, fabric]) => marked + fabric));
6698
+ var sdnPendingCount = (target) => Effect91.all([markedPending(target), fabricPending(target)], { concurrency: "unbounded" }).pipe(Effect91.map(([marked, fabric]) => marked + fabric));
6270
6699
 
6271
6700
  // 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 }) {
6701
+ var ProxmoxSdnApply = Resource31("Proxmox.SdnApply");
6702
+ var read5 = (props) => sdnPendingCount(props.target).pipe(Effect92.map((pending) => ({ pending })));
6703
+ var ProxmoxSdnApplyProvider = () => Provider31.effect(ProxmoxSdnApply, Effect92.succeed(ProxmoxSdnApply.Provider.of({
6704
+ list: () => Effect92.succeed([]),
6705
+ read: Effect92.fn(function* ({ olds }) {
6277
6706
  return yield* read5(olds);
6278
6707
  }),
6279
- diff: Effect89.fn(function* ({ news }) {
6280
- if (!isResolved28(news))
6708
+ diff: Effect92.fn(function* ({ news }) {
6709
+ if (!isResolved29(news))
6281
6710
  return;
6282
6711
  const { pending } = yield* read5(news);
6283
6712
  return pending === 0 ? { action: "noop" } : { action: "update" };
6284
6713
  }),
6285
- reconcile: Effect89.fn(function* ({ news }) {
6714
+ reconcile: Effect92.fn(function* ({ news }) {
6286
6715
  const staged = yield* read5(news);
6287
6716
  if (staged.pending === 0)
6288
6717
  return staged;
@@ -6290,16 +6719,16 @@ var ProxmoxSdnApplyProvider = () => Provider30.effect(ProxmoxSdnApply, Effect89.
6290
6719
  yield* pve(news.target, "provision", "PUT", "cluster/sdn");
6291
6720
  const after = yield* read5(news);
6292
6721
  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."));
6722
+ 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
6723
  }
6295
6724
  return after;
6296
6725
  }),
6297
- delete: () => Effect89.void
6726
+ delete: () => Effect92.void
6298
6727
  })));
6299
6728
  // 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";
6729
+ import { Resource as Resource32 } from "alchemy";
6730
+ import * as Provider32 from "alchemy/Provider";
6731
+ import * as Effect93 from "effect/Effect";
6303
6732
 
6304
6733
  // src/proxmox/sdn-subnet-form.ts
6305
6734
  var subnetId = (props) => `${props.zone}-${props.cidr.replace("/", "-")}`;
@@ -6323,13 +6752,13 @@ var createForm10 = (props) => ({
6323
6752
  subnet: props.cidr,
6324
6753
  type: "subnet"
6325
6754
  });
6326
- var updateForm6 = (props) => {
6755
+ var updateForm7 = (props) => {
6327
6756
  const clear = Object.entries(optional3(props)).filter(([, value]) => value === undefined).map(([key]) => key);
6328
6757
  return withClears(body5(props), clear);
6329
6758
  };
6330
6759
 
6331
6760
  // src/proxmox/sdn-subnet.ts
6332
- var ProxmoxSdnSubnet = Resource31("Proxmox.SdnSubnet");
6761
+ var ProxmoxSdnSubnet = Resource32("Proxmox.SdnSubnet");
6333
6762
  var handlers13 = pveHandlers({
6334
6763
  attributes: (live, props) => {
6335
6764
  const liveVnet = text(live["vnet"]);
@@ -6357,16 +6786,16 @@ var handlers13 = pveHandlers({
6357
6786
  },
6358
6787
  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
6788
  path: (props) => `cluster/sdn/vnets/${props.vnet}/subnets/${subnetId(props)}`,
6360
- updateForm: updateForm6
6789
+ updateForm: updateForm7
6361
6790
  });
6362
- var ProxmoxSdnSubnetProvider = () => Provider31.effect(ProxmoxSdnSubnet, Effect90.succeed(ProxmoxSdnSubnet.Provider.of(handlers13)));
6791
+ var ProxmoxSdnSubnetProvider = () => Provider32.effect(ProxmoxSdnSubnet, Effect93.succeed(ProxmoxSdnSubnet.Provider.of(handlers13)));
6363
6792
  // 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");
6793
+ import { Resource as Resource33 } from "alchemy";
6794
+ import * as Provider33 from "alchemy/Provider";
6795
+ import * as Effect94 from "effect/Effect";
6796
+ var ProxmoxSdnVnet = Resource33("Proxmox.SdnVnet");
6368
6797
  var tagOf = (value) => typeof value === "number" ? value : undefined;
6369
- var shape11 = (props) => {
6798
+ var shape10 = (props) => {
6370
6799
  const alias = props.alias ?? "";
6371
6800
  return {
6372
6801
  "isolate-ports": props.isolatePorts === true ? "1" : "0",
@@ -6376,12 +6805,12 @@ var shape11 = (props) => {
6376
6805
  ...props.tag === undefined ? {} : { tag: String(props.tag) }
6377
6806
  };
6378
6807
  };
6379
- var updateForm7 = (props) => {
6808
+ var updateForm8 = (props) => {
6380
6809
  const unset2 = [
6381
6810
  ...(props.alias ?? "") === "" ? ["alias"] : [],
6382
6811
  ...props.tag === undefined ? ["tag"] : []
6383
6812
  ];
6384
- return withClears(shape11(props), unset2);
6813
+ return withClears(shape10(props), unset2);
6385
6814
  };
6386
6815
  var handlers14 = pveHandlers({
6387
6816
  readRole: "provision",
@@ -6395,18 +6824,18 @@ var handlers14 = pveHandlers({
6395
6824
  zone: typeof live["zone"] === "string" ? live["zone"] : ""
6396
6825
  }),
6397
6826
  collection: () => "cluster/sdn/vnets",
6398
- createForm: (props) => ({ ...shape11(props), vnet: props.vnet }),
6827
+ createForm: (props) => ({ ...shape10(props), vnet: props.vnet }),
6399
6828
  endpoint: { create: "pve:POST /cluster/sdn/vnets", update: "pve:PUT /cluster/sdn/vnets/{vnet}" },
6400
6829
  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
6830
  path: (props) => `cluster/sdn/vnets/${props.vnet}`,
6402
- updateForm: updateForm7
6831
+ updateForm: updateForm8
6403
6832
  });
6404
- var ProxmoxSdnVnetProvider = () => Provider32.effect(ProxmoxSdnVnet, Effect91.succeed(ProxmoxSdnVnet.Provider.of(handlers14)));
6833
+ var ProxmoxSdnVnetProvider = () => Provider33.effect(ProxmoxSdnVnet, Effect94.succeed(ProxmoxSdnVnet.Provider.of(handlers14)));
6405
6834
  // 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");
6835
+ import { Resource as Resource34 } from "alchemy";
6836
+ import * as Provider34 from "alchemy/Provider";
6837
+ import * as Effect95 from "effect/Effect";
6838
+ var ProxmoxSdnZone = Resource34("Proxmox.SdnZone");
6410
6839
  var sameIpam = (live, declared2) => (live === "" ? "pve" : live) === (declared2 === undefined || declared2 === "" ? "pve" : declared2);
6411
6840
  var body6 = (props) => ({
6412
6841
  ...props.bridge === undefined ? {} : { bridge: props.bridge },
@@ -6458,20 +6887,20 @@ var handlers15 = pveHandlers({
6458
6887
  return withClears(fields2, clear);
6459
6888
  }
6460
6889
  });
6461
- var ProxmoxSdnZoneProvider = () => Provider33.effect(ProxmoxSdnZone, Effect92.succeed(ProxmoxSdnZone.Provider.of(handlers15)));
6890
+ var ProxmoxSdnZoneProvider = () => Provider34.effect(ProxmoxSdnZone, Effect95.succeed(ProxmoxSdnZone.Provider.of(handlers15)));
6462
6891
  // 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";
6892
+ import { Resource as Resource35 } from "alchemy";
6893
+ import { isResolved as isResolved30 } from "alchemy/Diff";
6894
+ import * as Provider35 from "alchemy/Provider";
6466
6895
  import * as storage2 from "@distilled.cloud/proxmox/storage";
6467
- import * as Effect94 from "effect/Effect";
6896
+ import * as Effect97 from "effect/Effect";
6468
6897
 
6469
6898
  // src/proxmox/storage-form.ts
6470
6899
  var STORAGE_CREATE = "pve:POST /storage";
6471
6900
  var STORAGE_UPDATE = "pve:PUT /storage/{storage}";
6472
6901
  var field6 = (name, value) => value === undefined ? {} : { [name]: value };
6473
6902
  var locatorForm = (locator) => ({ ...locator });
6474
- var underscored = (form) => Object.fromEntries(Object.entries(form).map(([key, value]) => [key.replaceAll("-", "_"), value]));
6903
+ var underscored = (form2) => Object.fromEntries(Object.entries(form2).map(([key, value]) => [key.replaceAll("-", "_"), value]));
6475
6904
  var mutable2 = (props) => ({
6476
6905
  ...field6("comment", props.comment),
6477
6906
  ...field6("content", props.content),
@@ -6487,16 +6916,16 @@ var createForm11 = (props) => ({
6487
6916
  storage: props.storage,
6488
6917
  type: props.type
6489
6918
  });
6490
- var updateForm8 = (props) => ({
6919
+ var updateForm9 = (props) => ({
6491
6920
  ...mutable2(props),
6492
6921
  storage: props.storage
6493
6922
  });
6494
6923
  var toDistilledCreate4 = (props) => underscored(createForm11(props));
6495
- var toDistilledUpdate3 = (props) => underscored(updateForm8(props));
6924
+ var toDistilledUpdate3 = (props) => underscored(updateForm9(props));
6496
6925
 
6497
6926
  // src/proxmox/storage-wire.ts
6498
6927
  import * as storage from "@distilled.cloud/proxmox/storage";
6499
- import * as Effect93 from "effect/Effect";
6928
+ import * as Effect96 from "effect/Effect";
6500
6929
  var str2 = (value, fallback = "") => typeof value === "string" ? value : fallback;
6501
6930
  var tokens = (value) => value.split(",").map((part) => part.trim()).filter((part) => part !== "").sort().join(",");
6502
6931
  var sameList2 = (declared2, live) => declared2 === undefined || tokens(declared2) === tokens(live);
@@ -6515,25 +6944,25 @@ var attributesOf10 = (live, props) => {
6515
6944
  type: str2(data["type"], props.type)
6516
6945
  };
6517
6946
  };
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)));
6947
+ var readStorageOrFail = (props) => readOrUnreadable(runPve(props.target, "provision", false, storage.getStorage({ storage: props.storage }))).pipe(Effect96.map((live) => live === UNREADABLE ? UNREADABLE : attributesOf10(live, props)));
6948
+ var readStorage = (props) => readStorageOrFail(props).pipe(Effect96.catchTag("StorageNotFound", () => Effect96.succeed(undefined)));
6520
6949
  var dropUnreadable7 = (live) => live === UNREADABLE ? undefined : live;
6521
6950
  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
6951
 
6523
6952
  // src/proxmox/storage.ts
6524
- var ProxmoxStorage = Resource34("Proxmox.Storage", {
6953
+ var ProxmoxStorage = Resource35("Proxmox.Storage", {
6525
6954
  defaultRemovalPolicy: "retain"
6526
6955
  });
6527
- var ProxmoxStorageProvider = () => Provider34.effect(ProxmoxStorage, Effect94.succeed(ProxmoxStorage.Provider.of({
6528
- list: () => Effect94.succeed([]),
6529
- read: Effect94.fn(function* ({ olds, output }) {
6956
+ var ProxmoxStorageProvider = () => Provider35.effect(ProxmoxStorage, Effect97.succeed(ProxmoxStorage.Provider.of({
6957
+ list: () => Effect97.succeed([]),
6958
+ read: Effect97.fn(function* ({ olds, output }) {
6530
6959
  return dropUnreadable7(yield* output === undefined ? readStorage(olds) : readStorageOrFail(olds));
6531
6960
  }),
6532
- diff: Effect94.fn(function* ({ news, output }) {
6533
- if (!isResolved29(news))
6961
+ diff: Effect97.fn(function* ({ news, output }) {
6962
+ if (!isResolved30(news))
6534
6963
  return;
6535
6964
  yield* guardWrite2(STORAGE_CREATE, createForm11(news), output === undefined);
6536
- yield* guardWrite2(STORAGE_UPDATE, updateForm8(news), false);
6965
+ yield* guardWrite2(STORAGE_UPDATE, updateForm9(news), false);
6537
6966
  if (output === undefined)
6538
6967
  return;
6539
6968
  const live = yield* readStorageOrFail(news);
@@ -6547,10 +6976,10 @@ var ProxmoxStorageProvider = () => Provider34.effect(ProxmoxStorage, Effect94.su
6547
6976
  }
6548
6977
  return matches10(live, news) ? { action: "noop" } : { action: "update" };
6549
6978
  }),
6550
- reconcile: Effect94.fn(function* ({ news }) {
6979
+ reconcile: Effect97.fn(function* ({ news }) {
6551
6980
  const before = dropUnreadable7(yield* readStorage(news));
6552
6981
  yield* guardWrite2(STORAGE_CREATE, createForm11(news), before === undefined);
6553
- yield* guardWrite2(STORAGE_UPDATE, updateForm8(news), false);
6982
+ yield* guardWrite2(STORAGE_UPDATE, updateForm9(news), false);
6554
6983
  if (before === undefined) {
6555
6984
  yield* runPve(news.target, "provision", true, storage2.createStorage(toDistilledCreate4(news)));
6556
6985
  } else if (!matches10(before, news)) {
@@ -6558,23 +6987,23 @@ var ProxmoxStorageProvider = () => Provider34.effect(ProxmoxStorage, Effect94.su
6558
6987
  }
6559
6988
  const after = dropUnreadable7(yield* readStorage(news));
6560
6989
  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."));
6990
+ 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
6991
  }
6563
6992
  return after;
6564
6993
  }),
6565
- delete: Effect94.fn(function* ({ olds }) {
6994
+ delete: Effect97.fn(function* ({ olds }) {
6566
6995
  yield* runPve(olds.target, "provision", true, storage2.deleteStorage({ storage: olds.storage }));
6567
6996
  })
6568
6997
  })));
6569
6998
  // 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";
6999
+ import { Resource as Resource36 } from "alchemy";
7000
+ import { isResolved as isResolved31 } from "alchemy/Diff";
7001
+ import * as Provider36 from "alchemy/Provider";
7002
+ import * as Effect100 from "effect/Effect";
6574
7003
 
6575
7004
  // src/proxmox/zfs-pool-wire.ts
6576
- import * as nodes18 from "@distilled.cloud/proxmox/nodes";
6577
- import * as Effect95 from "effect/Effect";
7005
+ import * as nodes20 from "@distilled.cloud/proxmox/nodes";
7006
+ import * as Effect98 from "effect/Effect";
6578
7007
  var leafDevices = (children) => Array.isArray(children) ? children.flatMap((entry) => {
6579
7008
  const vdev = entry;
6580
7009
  const nested = leafDevices(vdev.children);
@@ -6587,19 +7016,19 @@ var attributesOf11 = (live, props) => ({
6587
7016
  node: props.node,
6588
7017
  state: text(live.state, "unknown")
6589
7018
  });
6590
- var readPoolOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, nodes18.getNodeDiskZfs({ name: props.name, node: props.node }))).pipe(Effect95.map((live) => {
7019
+ var readPoolOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, nodes20.getNodeDiskZfs({ name: props.name, node: props.node }))).pipe(Effect98.map((live) => {
6591
7020
  if (live === UNREADABLE)
6592
7021
  return UNREADABLE;
6593
7022
  return text(live.name) === "" ? undefined : attributesOf11(live, props);
6594
7023
  }));
6595
- var readPool2 = (props) => readPoolOrFail(props).pipe(Effect95.orElseSucceed(() => {
7024
+ var readPool2 = (props) => readPoolOrFail(props).pipe(Effect98.orElseSucceed(() => {
6596
7025
  return;
6597
7026
  }));
6598
7027
  var dropUnreadable8 = (live) => live === UNREADABLE ? undefined : live;
6599
7028
 
6600
7029
  // src/proxmox/zfs-pool-form.ts
6601
- import * as Effect96 from "effect/Effect";
6602
- import * as nodes19 from "@distilled.cloud/proxmox/nodes";
7030
+ import * as Effect99 from "effect/Effect";
7031
+ import * as nodes21 from "@distilled.cloud/proxmox/nodes";
6603
7032
  var ZFS_POOL_CREATE = "pve:POST /nodes/{node}/disks/zfs";
6604
7033
  var zfsPoolCreateEndpoint = (props) => props.devices === undefined || props.raidlevel === undefined ? undefined : ZFS_POOL_CREATE;
6605
7034
  var createForm12 = (props) => ({
@@ -6611,49 +7040,49 @@ var createForm12 = (props) => ({
6611
7040
  ...props["draid-config"] === undefined ? {} : { "draid-config": props["draid-config"] }
6612
7041
  });
6613
7042
  var toDistilledCreate5 = (props) => {
6614
- const form = createForm12(props);
7043
+ const form2 = createForm12(props);
6615
7044
  return {
6616
- ...form,
6617
- draid_config: form["draid-config"],
7045
+ ...form2,
7046
+ draid_config: form2["draid-config"],
6618
7047
  node: props.node
6619
7048
  };
6620
7049
  };
6621
7050
  var SETTLE_ATTEMPTS = 30;
6622
- var createPool2 = (props, read6) => Effect96.gen(function* () {
7051
+ var createPool2 = (props, read6) => Effect99.gen(function* () {
6623
7052
  const existing = yield* read6(props);
6624
7053
  if (existing !== undefined)
6625
7054
  return existing;
6626
7055
  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."));
7056
+ 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
7057
  }
6629
7058
  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* () {
7059
+ const upid = yield* runPve(props.target, "provision", true, nodes21.createNodeDiskZfs(toDistilledCreate5(props)));
7060
+ const settle3 = (attempts) => Effect99.gen(function* () {
6632
7061
  const live = yield* read6(props);
6633
7062
  if (live !== undefined || attempts <= 0)
6634
7063
  return live;
6635
- yield* Effect96.sleep("2 seconds");
7064
+ yield* Effect99.sleep("2 seconds");
6636
7065
  return yield* settle3(attempts - 1);
6637
7066
  });
6638
7067
  const after = yield* settle3(SETTLE_ATTEMPTS);
6639
7068
  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."));
7069
+ 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
7070
  }
6642
7071
  return after;
6643
7072
  });
6644
- var destroyPool = (props) => runPve(props.target, "provision", true, nodes19.deleteNodeDiskZfs({ name: props.name, node: props.node }));
7073
+ var destroyPool = (props) => runPve(props.target, "provision", true, nodes21.deleteNodeDiskZfs({ name: props.name, node: props.node }));
6645
7074
 
6646
7075
  // src/proxmox/zfs-pool.ts
6647
- var ProxmoxZfsPool = Resource35("Proxmox.ZfsPool", {
7076
+ var ProxmoxZfsPool = Resource36("Proxmox.ZfsPool", {
6648
7077
  defaultRemovalPolicy: "retain"
6649
7078
  });
6650
- var ProxmoxZfsPoolProvider = () => Provider35.effect(ProxmoxZfsPool, Effect97.succeed(ProxmoxZfsPool.Provider.of({
6651
- list: () => Effect97.succeed([]),
6652
- read: Effect97.fn(function* ({ olds, output }) {
7079
+ var ProxmoxZfsPoolProvider = () => Provider36.effect(ProxmoxZfsPool, Effect100.succeed(ProxmoxZfsPool.Provider.of({
7080
+ list: () => Effect100.succeed([]),
7081
+ read: Effect100.fn(function* ({ olds, output }) {
6653
7082
  return dropUnreadable8(yield* output === undefined ? readPool2(olds) : readPoolOrFail(olds));
6654
7083
  }),
6655
- diff: Effect97.fn(function* ({ news, output }) {
6656
- if (!isResolved30(news))
7084
+ diff: Effect100.fn(function* ({ news, output }) {
7085
+ if (!isResolved31(news))
6657
7086
  return;
6658
7087
  yield* guardForm(zfsPoolCreateEndpoint(news), asForm2(createForm12(news)), output === undefined);
6659
7088
  if (output === undefined)
@@ -6669,10 +7098,10 @@ var ProxmoxZfsPoolProvider = () => Provider35.effect(ProxmoxZfsPool, Effect97.su
6669
7098
  }
6670
7099
  return { action: "noop" };
6671
7100
  }),
6672
- reconcile: Effect97.fn(function* ({ news }) {
6673
- return yield* createPool2(news, (props) => readPool2(props).pipe(Effect97.map(dropUnreadable8)));
7101
+ reconcile: Effect100.fn(function* ({ news }) {
7102
+ return yield* createPool2(news, (props) => readPool2(props).pipe(Effect100.map(dropUnreadable8)));
6674
7103
  }),
6675
- delete: Effect97.fn(function* ({ olds }) {
7104
+ delete: Effect100.fn(function* ({ olds }) {
6676
7105
  yield* destroyPool(olds);
6677
7106
  })
6678
7107
  })));
@@ -6737,9 +7166,12 @@ export {
6737
7166
  ProxmoxSdnZone,
6738
7167
  ProxmoxSdnZoneProvider,
6739
7168
  ProxmoxStorage,
7169
+ ProxmoxStorageDownload,
7170
+ ProxmoxStorageDownloadProvider,
6740
7171
  ProxmoxStorageProvider,
6741
7172
  ProxmoxUser,
6742
7173
  ProxmoxUserProvider,
7174
+ ProxmoxVm,
6743
7175
  ProxmoxVmProvider,
6744
7176
  ProxmoxZfsPool,
6745
7177
  ProxmoxZfsPoolProvider,
@@ -6752,5 +7184,5 @@ export {
6752
7184
  violations
6753
7185
  };
6754
7186
 
6755
- //# debugId=B5C51EB76E4323A364756E2164756E21
7187
+ //# debugId=E0687F0E088322E564756E2164756E21
6756
7188
  //# sourceMappingURL=index.js.map