@homeflare/alchemy 0.35.0 → 0.37.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 (127) hide show
  1. package/README.md +14 -0
  2. package/dist/argocd/cluster.d.ts +102 -0
  3. package/dist/argocd/cluster.d.ts.map +1 -0
  4. package/dist/argocd/credentials.d.ts +37 -0
  5. package/dist/argocd/credentials.d.ts.map +1 -0
  6. package/dist/argocd/fake-argocd.d.ts +42 -0
  7. package/dist/argocd/fake-argocd.d.ts.map +1 -0
  8. package/dist/argocd/git-credentials.d.ts +29 -0
  9. package/dist/argocd/git-credentials.d.ts.map +1 -0
  10. package/dist/argocd/index.d.ts +19 -0
  11. package/dist/argocd/index.d.ts.map +1 -0
  12. package/dist/argocd/index.js +306 -0
  13. package/dist/argocd/index.js.map +17 -0
  14. package/dist/argocd/providers.d.ts +13 -0
  15. package/dist/argocd/providers.d.ts.map +1 -0
  16. package/dist/argocd/repo-creds.d.ts +67 -0
  17. package/dist/argocd/repo-creds.d.ts.map +1 -0
  18. package/dist/argocd/repository.d.ts +87 -0
  19. package/dist/argocd/repository.d.ts.map +1 -0
  20. package/dist/argocd/resource.d.ts +90 -0
  21. package/dist/argocd/resource.d.ts.map +1 -0
  22. package/dist/cloudflare/index.js +4 -4
  23. package/dist/cloudflare/index.js.map +3 -3
  24. package/dist/cloudflare/r2-bucket-lock.d.ts +14 -5
  25. package/dist/cloudflare/r2-bucket-lock.d.ts.map +1 -1
  26. package/dist/grafana/index.d.ts +5 -4
  27. package/dist/grafana/index.d.ts.map +1 -1
  28. package/dist/grafana/index.js +204 -90
  29. package/dist/grafana/index.js.map +7 -4
  30. package/dist/grafana/notification-policy-drop-warning.d.ts +27 -0
  31. package/dist/grafana/notification-policy-drop-warning.d.ts.map +1 -0
  32. package/dist/grafana/notification-policy-fixtures.d.ts +34 -0
  33. package/dist/grafana/notification-policy-fixtures.d.ts.map +1 -0
  34. package/dist/grafana/notification-policy-model.d.ts +53 -0
  35. package/dist/grafana/notification-policy-model.d.ts.map +1 -0
  36. package/dist/grafana/notification-policy.d.ts +57 -0
  37. package/dist/grafana/notification-policy.d.ts.map +1 -0
  38. package/dist/grafana/providers.d.ts +1 -1
  39. package/dist/grafana/providers.d.ts.map +1 -1
  40. package/dist/litellm/index.js.map +2 -2
  41. package/dist/litellm/operations.d.ts.map +1 -1
  42. package/dist/proxmox/ceph-daemon-form.d.ts +4 -5
  43. package/dist/proxmox/ceph-daemon-form.d.ts.map +1 -1
  44. package/dist/proxmox/ceph-daemon-wire.d.ts +33 -0
  45. package/dist/proxmox/ceph-daemon-wire.d.ts.map +1 -0
  46. package/dist/proxmox/ceph-daemon.d.ts +35 -0
  47. package/dist/proxmox/ceph-daemon.d.ts.map +1 -1
  48. package/dist/proxmox/ceph-fs-distilled.d.ts +14 -0
  49. package/dist/proxmox/ceph-fs-distilled.d.ts.map +1 -0
  50. package/dist/proxmox/ceph-fs-wire.d.ts +20 -11
  51. package/dist/proxmox/ceph-fs-wire.d.ts.map +1 -1
  52. package/dist/proxmox/ceph-fs.d.ts +31 -6
  53. package/dist/proxmox/ceph-fs.d.ts.map +1 -1
  54. package/dist/proxmox/ceph-osd-tree.d.ts +12 -3
  55. package/dist/proxmox/ceph-osd-tree.d.ts.map +1 -1
  56. package/dist/proxmox/ceph-osd-write.d.ts +17 -2
  57. package/dist/proxmox/ceph-osd-write.d.ts.map +1 -1
  58. package/dist/proxmox/ceph-osd.d.ts +6 -0
  59. package/dist/proxmox/ceph-osd.d.ts.map +1 -1
  60. package/dist/proxmox/ceph-pool-settle.d.ts +10 -4
  61. package/dist/proxmox/ceph-pool-settle.d.ts.map +1 -1
  62. package/dist/proxmox/ceph-pool-wire.d.ts +46 -0
  63. package/dist/proxmox/ceph-pool-wire.d.ts.map +1 -0
  64. package/dist/proxmox/ceph-pool.d.ts +10 -5
  65. package/dist/proxmox/ceph-pool.d.ts.map +1 -1
  66. package/dist/proxmox/group-wire.d.ts +1 -1
  67. package/dist/proxmox/group-wire.d.ts.map +1 -1
  68. package/dist/proxmox/index.js +611 -477
  69. package/dist/proxmox/index.js.map +15 -12
  70. package/dist/proxmox/storage-wire.d.ts +8 -1
  71. package/dist/proxmox/storage-wire.d.ts.map +1 -1
  72. package/dist/proxmox/user-wire.d.ts +1 -1
  73. package/dist/proxmox/user-wire.d.ts.map +1 -1
  74. package/docs/argocd-kubernetes.md +100 -0
  75. package/docs/argocd.md +139 -0
  76. package/docs/credentials.md +9 -0
  77. package/docs/grafana-alerting.md +3 -2
  78. package/docs/grafana-notification-policy.md +127 -0
  79. package/docs/grafana.md +12 -8
  80. package/docs/litellm.md +17 -0
  81. package/docs/peers.md +7 -0
  82. package/docs/unifi.md +45 -0
  83. package/docs/upstream-conformance.md +19 -5
  84. package/package.json +8 -3
  85. package/src/argocd/cluster.test.ts +120 -0
  86. package/src/argocd/cluster.ts +222 -0
  87. package/src/argocd/credentials.ts +38 -0
  88. package/src/argocd/fake-argocd.ts +60 -0
  89. package/src/argocd/git-credentials.ts +71 -0
  90. package/src/argocd/index.ts +40 -0
  91. package/src/argocd/providers.ts +17 -0
  92. package/src/argocd/repo-creds.test.ts +123 -0
  93. package/src/argocd/repo-creds.ts +115 -0
  94. package/src/argocd/repository.test.ts +167 -0
  95. package/src/argocd/repository.ts +165 -0
  96. package/src/argocd/resource.ts +150 -0
  97. package/src/cloudflare/r2-bucket-lock.test.ts +54 -18
  98. package/src/cloudflare/r2-bucket-lock.ts +25 -18
  99. package/src/grafana/index.ts +11 -4
  100. package/src/grafana/notification-policy-drop-warning.test.ts +163 -0
  101. package/src/grafana/notification-policy-drop-warning.ts +60 -0
  102. package/src/grafana/notification-policy-fixtures.ts +27 -0
  103. package/src/grafana/notification-policy-model.test.ts +104 -0
  104. package/src/grafana/notification-policy-model.ts +100 -0
  105. package/src/grafana/notification-policy-refusals.test.ts +119 -0
  106. package/src/grafana/notification-policy.test.ts +86 -0
  107. package/src/grafana/notification-policy.ts +191 -0
  108. package/src/grafana/providers.ts +2 -0
  109. package/src/litellm/operations.ts +8 -4
  110. package/src/proxmox/ceph-daemon-form.ts +7 -8
  111. package/src/proxmox/ceph-daemon-wire.ts +115 -0
  112. package/src/proxmox/ceph-daemon-write.test.ts +158 -0
  113. package/src/proxmox/ceph-daemon.ts +65 -47
  114. package/src/proxmox/ceph-fs-delete.test.ts +81 -0
  115. package/src/proxmox/ceph-fs-distilled.ts +102 -0
  116. package/src/proxmox/ceph-fs-wire.ts +17 -31
  117. package/src/proxmox/ceph-fs-write.test.ts +67 -0
  118. package/src/proxmox/ceph-fs.ts +66 -69
  119. package/src/proxmox/ceph-osd-tree.ts +14 -5
  120. package/src/proxmox/ceph-osd-write.test.ts +61 -0
  121. package/src/proxmox/ceph-osd-write.ts +33 -6
  122. package/src/proxmox/ceph-osd.ts +6 -0
  123. package/src/proxmox/ceph-pool-settle.ts +13 -7
  124. package/src/proxmox/ceph-pool-wire.ts +110 -0
  125. package/src/proxmox/ceph-pool-write.test.ts +145 -0
  126. package/src/proxmox/ceph-pool.ts +87 -98
  127. package/src/proxmox/distilled-task-await.test.ts +0 -124
@@ -1635,14 +1635,15 @@ var handlers = pveHandlers({
1635
1635
  var ProxmoxBackupJobProvider = () => Provider3.effect(ProxmoxBackupJob, Effect12.succeed(ProxmoxBackupJob.Provider.of(handlers)));
1636
1636
  // src/proxmox/ceph-daemon.ts
1637
1637
  import { Resource as Resource4 } from "alchemy";
1638
+ import { isResolved as isResolved4 } from "alchemy/Diff";
1638
1639
  import * as Provider4 from "alchemy/Provider";
1639
- import * as Effect13 from "effect/Effect";
1640
+ import * as Effect14 from "effect/Effect";
1640
1641
 
1641
1642
  // src/proxmox/ceph-daemon-form.ts
1642
1643
  var DAEMON_ENDPOINTS = {
1643
- mds: { create: "pve:POST /nodes/{node}/ceph/mds/{name}" },
1644
- mgr: { create: "pve:POST /nodes/{node}/ceph/mgr/{id}" },
1645
- mon: { create: "pve:POST /nodes/{node}/ceph/mon/{monid}" }
1644
+ mds: "pve:POST /nodes/{node}/ceph/mds/{name}",
1645
+ mgr: "pve:POST /nodes/{node}/ceph/mgr/{id}",
1646
+ mon: "pve:POST /nodes/{node}/ceph/mon/{monid}"
1646
1647
  };
1647
1648
  var daemonId = (props) => props.name ?? props.node;
1648
1649
  var collectionPath = (props) => `nodes/${props.node}/ceph/${props.kind}`;
@@ -1675,28 +1676,97 @@ var daemonAttributes = (live, props) => {
1675
1676
  };
1676
1677
  };
1677
1678
 
1679
+ // src/proxmox/ceph-daemon-wire.ts
1680
+ import * as nodes from "@distilled.cloud/proxmox/nodes";
1681
+ import * as Effect13 from "effect/Effect";
1682
+ var listRows = (props) => {
1683
+ const node = props.node;
1684
+ switch (props.kind) {
1685
+ case "mon":
1686
+ return runPve(props.target, "read", false, nodes.listNodeCephMon({ node })).pipe(Effect13.map((rows) => rows));
1687
+ case "mgr":
1688
+ return runPve(props.target, "read", false, nodes.listNodeCephMgr({ node })).pipe(Effect13.map((rows) => rows));
1689
+ case "mds":
1690
+ return runPve(props.target, "read", false, nodes.listNodeCephMds({ node })).pipe(Effect13.map((rows) => rows));
1691
+ }
1692
+ };
1693
+ var readDaemon = (props) => listRows(props).pipe(Effect13.map((rows) => daemonAttributes(rows, props)), Effect13.orElseSucceed(() => {
1694
+ return;
1695
+ }));
1696
+ var createDaemon = (props) => {
1697
+ const node = props.node;
1698
+ const id = daemonId(props);
1699
+ switch (props.kind) {
1700
+ case "mon":
1701
+ return runPve(props.target, "provision", true, nodes.updateNodeCephMon({
1702
+ ...props["mon-address"] === undefined ? {} : { mon_address: props["mon-address"] },
1703
+ monid: id,
1704
+ node
1705
+ }));
1706
+ case "mgr":
1707
+ return runPve(props.target, "provision", true, nodes.updateNodeCephMgr({ id, node }));
1708
+ case "mds":
1709
+ return runPve(props.target, "provision", true, nodes.updateNodeCephMds({
1710
+ ...props.hotstandby === undefined ? {} : { hotstandby: props.hotstandby ? "1" : "0" },
1711
+ name: id,
1712
+ node
1713
+ }));
1714
+ }
1715
+ };
1716
+ var deleteDaemon = (props) => {
1717
+ const node = props.node;
1718
+ const id = daemonId(props);
1719
+ switch (props.kind) {
1720
+ case "mon":
1721
+ return runPve(props.target, "provision", true, nodes.deleteNodeCephMon({ monid: id, node }));
1722
+ case "mgr":
1723
+ return runPve(props.target, "provision", true, nodes.deleteNodeCephMgr({ id, node }));
1724
+ case "mds":
1725
+ return runPve(props.target, "provision", true, nodes.deleteNodeCephMds({ name: id, node }));
1726
+ }
1727
+ };
1728
+ var notCreated = (props) => new Error(`${daemonPath(props)}: no ${props.kind} named ${daemonId(props)} in GET nodes/` + `${props.node}/ceph/${props.kind} after the create task finished. POST answers a UPID, ` + "not a result -- watch the task in the PVE UI (ceph-daemon-form.ts).");
1729
+
1678
1730
  // src/proxmox/ceph-daemon.ts
1679
1731
  var ProxmoxCephDaemon = Resource4("Proxmox.CephDaemon", {
1680
1732
  defaultRemovalPolicy: "retain"
1681
1733
  });
1682
- var handlers2 = pveHandlers({
1683
- attributes: daemonAttributes,
1684
- collection: daemonPath,
1685
- createForm,
1686
- endpoint: (props) => DAEMON_ENDPOINTS[props.kind],
1687
- matches: () => true,
1688
- path: collectionPath
1689
- });
1690
- var ProxmoxCephDaemonProvider = () => Provider4.effect(ProxmoxCephDaemon, Effect13.succeed(ProxmoxCephDaemon.Provider.of({
1691
- ...handlers2,
1692
- delete: ({ olds }) => pve(olds.target, "provision", "DELETE", daemonPath(olds))
1734
+ var reconcileDaemon = Effect14.fn(function* ({ news }) {
1735
+ const live = yield* readDaemon(news);
1736
+ yield* guardWrite2(DAEMON_ENDPOINTS[news.kind], createForm(news), live === undefined);
1737
+ if (live !== undefined)
1738
+ return live;
1739
+ yield* createDaemon(news);
1740
+ const after = yield* readDaemon(news);
1741
+ if (after === undefined)
1742
+ return yield* Effect14.die(notCreated(news));
1743
+ return after;
1744
+ });
1745
+ var ProxmoxCephDaemonProvider = () => Provider4.effect(ProxmoxCephDaemon, Effect14.succeed(ProxmoxCephDaemon.Provider.of({
1746
+ list: () => Effect14.succeed([]),
1747
+ read: ({ olds }) => readDaemon(olds),
1748
+ diff: Effect14.fn(function* ({ news, output }) {
1749
+ if (!isResolved4(news))
1750
+ return;
1751
+ yield* guardWrite2(DAEMON_ENDPOINTS[news.kind], createForm(news), output === undefined);
1752
+ if (output === undefined)
1753
+ return;
1754
+ const live = yield* readDaemon(news);
1755
+ if (live === undefined) {
1756
+ yield* guardWrite2(DAEMON_ENDPOINTS[news.kind], createForm(news), true);
1757
+ return { action: "update" };
1758
+ }
1759
+ return { action: "noop" };
1760
+ }),
1761
+ reconcile: ({ news }) => reconcileDaemon({ news }),
1762
+ delete: ({ olds }) => deleteDaemon(olds)
1693
1763
  })));
1694
1764
  // src/proxmox/ceph-flag.ts
1695
1765
  import { Resource as Resource5 } from "alchemy";
1696
1766
  import * as Provider5 from "alchemy/Provider";
1697
- import * as Effect14 from "effect/Effect";
1767
+ import * as Effect15 from "effect/Effect";
1698
1768
  var ProxmoxCephFlag = Resource5("Proxmox.CephFlag");
1699
- var handlers3 = pveHandlers({
1769
+ var handlers2 = pveHandlers({
1700
1770
  attributes: (live, props) => ({ flag: props.flag, value: bool(live) }),
1701
1771
  collection: () => "cluster/ceph/flags",
1702
1772
  createForm: (props) => ({ [props.flag]: flag(props.value) ?? "0" }),
@@ -1705,25 +1775,29 @@ var handlers3 = pveHandlers({
1705
1775
  path: (props) => `cluster/ceph/flags/${props.flag}`,
1706
1776
  updateForm: (props) => ({ value: flag(props.value) ?? "0" })
1707
1777
  });
1708
- var ProxmoxCephFlagProvider = () => Provider5.effect(ProxmoxCephFlag, Effect14.succeed(ProxmoxCephFlag.Provider.of({
1709
- ...handlers3,
1710
- delete: () => Effect14.void,
1711
- reconcile: Effect14.fn(function* ({ news }) {
1712
- const after = yield* handlers3.reconcile({ news });
1778
+ var ProxmoxCephFlagProvider = () => Provider5.effect(ProxmoxCephFlag, Effect15.succeed(ProxmoxCephFlag.Provider.of({
1779
+ ...handlers2,
1780
+ delete: () => Effect15.void,
1781
+ reconcile: Effect15.fn(function* ({ news }) {
1782
+ const after = yield* handlers2.reconcile({ news });
1713
1783
  if (after.value !== news.value) {
1714
- return yield* Effect14.die(new Error(`cluster/ceph/flags/${news.flag}: the PUT returned no error but ceph still ` + `reports the flag ${after.value ? "set" : "clear"} rather than ` + `${news.value ? "set" : "clear"}. This endpoint's success is documented as a ` + "null body, so the status code proves nothing -- check `ceph osd dump | " + "head -1` and the cluster log. `pause` in particular is two ceph flags read " + "as one; see the header."));
1784
+ return yield* Effect15.die(new Error(`cluster/ceph/flags/${news.flag}: the PUT returned no error but ceph still ` + `reports the flag ${after.value ? "set" : "clear"} rather than ` + `${news.value ? "set" : "clear"}. This endpoint's success is documented as a ` + "null body, so the status code proves nothing -- check `ceph osd dump | " + "head -1` and the cluster log. `pause` in particular is two ceph flags read " + "as one; see the header."));
1715
1785
  }
1716
1786
  return after;
1717
1787
  })
1718
1788
  })));
1719
1789
  // src/proxmox/ceph-fs.ts
1720
1790
  import { Resource as Resource6 } from "alchemy";
1721
- import { isResolved as isResolved4 } from "alchemy/Diff";
1791
+ import { isResolved as isResolved5 } from "alchemy/Diff";
1722
1792
  import * as Provider6 from "alchemy/Provider";
1723
- import * as Effect16 from "effect/Effect";
1793
+ import * as Effect18 from "effect/Effect";
1794
+
1795
+ // src/proxmox/ceph-fs-distilled.ts
1796
+ import * as nodes2 from "@distilled.cloud/proxmox/nodes";
1797
+ import * as Effect17 from "effect/Effect";
1724
1798
 
1725
1799
  // src/proxmox/ceph-fs-wire.ts
1726
- import * as Effect15 from "effect/Effect";
1800
+ import * as Effect16 from "effect/Effect";
1727
1801
  var readRow = (live, props) => {
1728
1802
  const row = (Array.isArray(live) ? live : []).filter((entry) => typeof entry === "object" && entry !== null).find((entry) => entry["name"] === props.name);
1729
1803
  if (row === undefined)
@@ -1739,6 +1813,7 @@ var readRow = (live, props) => {
1739
1813
  var POLL_SECONDS = 2;
1740
1814
  var POLL_ATTEMPTS = 45;
1741
1815
  var objectPath = (props) => `nodes/${props.node}/ceph/fs/${props.name}`;
1816
+ var CEPH_FS_CREATE = "pve:POST /nodes/{node}/ceph/fs/{name}";
1742
1817
  var field = (name, value) => value === undefined ? {} : { [name]: value };
1743
1818
  var createForm2 = (props) => ({
1744
1819
  ...field("add-storage", flag(props["add-storage"])),
@@ -1751,86 +1826,113 @@ var destroyPath = (props) => {
1751
1826
  ].filter((part) => part !== undefined);
1752
1827
  return query.length === 0 ? objectPath(props) : `${objectPath(props)}?${query.join("&")}`;
1753
1828
  };
1754
- var settle = (target, node, upid, what) => Effect15.gen(function* () {
1829
+ var settle = (target, node, upid, what) => Effect16.gen(function* () {
1755
1830
  for (let attempt = 0;attempt < POLL_ATTEMPTS; attempt += 1) {
1756
- const status = yield* pve(target, "read", "GET", `nodes/${node}/tasks/${encodeURIComponent(upid)}/status`).pipe(Effect15.orElseSucceed(() => {
1831
+ const status = yield* pve(target, "read", "GET", `nodes/${node}/tasks/${encodeURIComponent(upid)}/status`).pipe(Effect16.orElseSucceed(() => {
1757
1832
  return;
1758
1833
  }));
1759
1834
  if (status?.status === "stopped") {
1760
1835
  const exit = text(status.exitstatus);
1761
1836
  if (exit === "OK")
1762
1837
  return;
1763
- return yield* Effect15.die(new Error(`${what}: PVE task ${upid} finished with "${exit === "" ? "no exit status" : exit}". ` + "The write returned HTTP 200 because it only forked the worker -- the real error is " + `in \`pvesh get /nodes/${node}/tasks/${upid}/log\`.`));
1838
+ return yield* Effect16.die(new Error(`${what}: PVE task ${upid} finished with "${exit === "" ? "no exit status" : exit}". ` + "The write returned HTTP 200 because it only forked the worker -- the real error is " + `in \`pvesh get /nodes/${node}/tasks/${upid}/log\`.`));
1764
1839
  }
1765
- yield* Effect15.sleep(POLL_SECONDS * 1000);
1766
- }
1767
- return yield* Effect15.die(new Error(`${what}: PVE task ${upid} was still running after ` + `${String(POLL_ATTEMPTS * POLL_SECONDS)}s, or its ` + "status could not be read. Check the task log, and check that the `read` role holds " + `Sys.Audit on /nodes/${node} -- each call mints a new token, so the poller is never the ` + "task owner and is answered 403 rather than told to wait."));
1768
- });
1769
- var createFs = (props) => Effect15.gen(function* () {
1770
- const upid = text(yield* pve(props.target, "provision", "POST", objectPath(props), createForm2(props)));
1771
- if (upid === "") {
1772
- return yield* Effect15.die(new Error(`${objectPath(props)}: POST returned no task id. PVE wraps every answer in ` + '{"data":...} and can report success on a call that did nothing.'));
1840
+ yield* Effect16.sleep(POLL_SECONDS * 1000);
1773
1841
  }
1774
- yield* settle(props.target, props.node, upid, objectPath(props));
1842
+ return yield* Effect16.die(new Error(`${what}: PVE task ${upid} was still running after ` + `${String(POLL_ATTEMPTS * POLL_SECONDS)}s, or its ` + "status could not be read. Check the task log, and check that the `read` role holds " + `Sys.Audit on /nodes/${node} -- each call mints a new token, so the poller is never the ` + "task owner and is answered 403 rather than told to wait."));
1775
1843
  });
1776
- var destroyFs = (props) => Effect15.gen(function* () {
1844
+ var destroyFs = (props) => Effect16.gen(function* () {
1777
1845
  const upid = text(yield* pve(props.target, "provision", "DELETE", destroyPath(props)));
1778
1846
  if (upid !== "")
1779
1847
  yield* settle(props.target, props.node, upid, destroyPath(props));
1780
1848
  });
1781
- var notCreated = (props) => new Error(`${objectPath(props)}: the create task finished but the filesystem is not in ` + `GET nodes/${props.node}/ceph/fs. Check the task log -- a PVE worker can exit having ` + "rolled back the pools it had just made.");
1849
+ var notCreated2 = (props) => new Error(`${objectPath(props)}: the create task finished but the filesystem is not in ` + `GET nodes/${props.node}/ceph/fs. Check the task log -- a PVE worker can exit having ` + "rolled back the pools it had just made.");
1782
1850
  var notDestroyed = (props) => new Error(`${objectPath(props)}: the destroy task finished but the filesystem is still in ` + `GET nodes/${props.node}/ceph/fs. PVE refuses to destroy a CephFS while a PVE storage entry ` + "of type cephfs still references it and is not disabled.");
1783
1851
 
1852
+ // src/proxmox/ceph-fs-distilled.ts
1853
+ var readFs = (props) => runPve(props.target, "read", false, nodes2.listNodeCephFs({ node: props.node })).pipe(Effect17.map((rows) => readRow(rows, props)), Effect17.orElseSucceed(() => {
1854
+ return;
1855
+ }));
1856
+ var toDistilledCreate = (props) => ({
1857
+ ...createForm2(props),
1858
+ name: props.name,
1859
+ node: props.node
1860
+ });
1861
+ var settleCreate = (props, upid) => Effect17.gen(function* () {
1862
+ for (let attempt = 0;attempt < POLL_ATTEMPTS; attempt += 1) {
1863
+ const status = yield* runPve(props.target, "read", false, nodes2.getNodeTaskStatus({ node: props.node, upid })).pipe(Effect17.orElseSucceed(() => {
1864
+ return;
1865
+ }));
1866
+ if (status?.status === "stopped") {
1867
+ if (status.exitstatus === "OK")
1868
+ return;
1869
+ return yield* Effect17.die(new Error(`${objectPath(props)}: PVE task ${upid} finished with "${status.exitstatus ?? "no exit status"}". ` + "The write returned HTTP 200 because it only forked the worker -- the real error is " + `in \`pvesh get /nodes/${props.node}/tasks/${upid}/log\`.`));
1870
+ }
1871
+ yield* Effect17.sleep(POLL_SECONDS * 1000);
1872
+ }
1873
+ return yield* Effect17.die(new Error(`${objectPath(props)}: PVE task ${upid} was still running after ` + `${String(POLL_ATTEMPTS * POLL_SECONDS)}s, or its status could not be read. Check the ` + "task log, and check that the `read` role holds Sys.Audit on " + `/nodes/${props.node} -- each call mints a new token, so the poller is never the task ` + "owner and is answered 403 rather than told to wait."));
1874
+ });
1875
+ var createFs = (props) => Effect17.gen(function* () {
1876
+ const upid = yield* runPve(props.target, "provision", true, nodes2.updateNodeCephFs(toDistilledCreate(props)));
1877
+ if (upid === "") {
1878
+ return yield* Effect17.die(new Error(`${objectPath(props)}: POST returned no task id. PVE wraps every answer in ` + '{"data":...} and can report success on a call that did nothing.'));
1879
+ }
1880
+ yield* settleCreate(props, upid);
1881
+ });
1882
+
1784
1883
  // src/proxmox/ceph-fs.ts
1785
1884
  var ProxmoxCephFs = Resource6("Proxmox.CephFs", {
1786
1885
  defaultRemovalPolicy: "retain"
1787
1886
  });
1788
- var ops = pveOperations({
1789
- attributes: readRow,
1790
- collection: objectPath,
1791
- createForm: createForm2,
1792
- endpoint: { create: "pve:POST /nodes/{node}/ceph/fs/{name}" },
1793
- matches: () => true,
1794
- path: (props) => `nodes/${props.node}/ceph/fs`
1795
- });
1796
- var ProxmoxCephFsProvider = () => Provider6.effect(ProxmoxCephFs, Effect16.succeed(ProxmoxCephFs.Provider.of({
1797
- list: () => Effect16.succeed([]),
1798
- read: Effect16.fn(function* ({ olds }) {
1799
- return yield* ops.read(olds);
1887
+ var ProxmoxCephFsProvider = () => Provider6.effect(ProxmoxCephFs, Effect18.succeed(ProxmoxCephFs.Provider.of({
1888
+ list: () => Effect18.succeed([]),
1889
+ read: Effect18.fn(function* ({ olds }) {
1890
+ return yield* readFs(olds);
1800
1891
  }),
1801
- diff: Effect16.fn(function* ({ news, output }) {
1802
- if (output !== undefined && isResolved4(news) && news.name !== output.name) {
1892
+ diff: Effect18.fn(function* ({ news, output }) {
1893
+ if (!isResolved5(news))
1894
+ return;
1895
+ yield* guardWrite2(CEPH_FS_CREATE, createForm2(news), output === undefined);
1896
+ if (output !== undefined && news.name !== output.name) {
1803
1897
  return { action: "replace" };
1804
1898
  }
1805
- return yield* ops.diff(news, output);
1899
+ if (output === undefined)
1900
+ return;
1901
+ const live = yield* readFs(news);
1902
+ if (live === undefined) {
1903
+ yield* guardWrite2(CEPH_FS_CREATE, createForm2(news), true);
1904
+ return { action: "update" };
1905
+ }
1906
+ return { action: "noop" };
1806
1907
  }),
1807
- reconcile: Effect16.fn(function* ({ news }) {
1808
- const live = yield* ops.read(news);
1908
+ reconcile: Effect18.fn(function* ({ news }) {
1909
+ const live = yield* readFs(news);
1809
1910
  if (live !== undefined)
1810
1911
  return live;
1811
1912
  yield* createFs(news);
1812
- const after = yield* ops.read(news);
1913
+ const after = yield* readFs(news);
1813
1914
  if (after === undefined)
1814
- return yield* Effect16.die(notCreated(news));
1915
+ return yield* Effect18.die(notCreated2(news));
1815
1916
  return after;
1816
1917
  }),
1817
- delete: Effect16.fn(function* ({ olds }) {
1818
- if ((yield* ops.read(olds)) === undefined)
1918
+ delete: Effect18.fn(function* ({ olds }) {
1919
+ if ((yield* readFs(olds)) === undefined)
1819
1920
  return;
1820
1921
  yield* destroyFs(olds);
1821
- const after = yield* ops.read(olds);
1922
+ const after = yield* readFs(olds);
1822
1923
  if (after !== undefined)
1823
- return yield* Effect16.die(notDestroyed(olds));
1924
+ return yield* Effect18.die(notDestroyed(olds));
1824
1925
  })
1825
1926
  })));
1826
1927
  // src/proxmox/ceph-osd.ts
1827
1928
  import { Resource as Resource7 } from "alchemy";
1828
- import { isResolved as isResolved5 } from "alchemy/Diff";
1929
+ import { isResolved as isResolved6 } from "alchemy/Diff";
1829
1930
  import * as Provider7 from "alchemy/Provider";
1830
- import * as Effect19 from "effect/Effect";
1931
+ import * as Effect21 from "effect/Effect";
1831
1932
 
1832
1933
  // src/proxmox/ceph-osd-tree.ts
1833
- import * as Effect17 from "effect/Effect";
1934
+ import * as nodes3 from "@distilled.cloud/proxmox/nodes";
1935
+ import * as Effect19 from "effect/Effect";
1834
1936
  var branches = (node) => (Array.isArray(node["children"]) ? node["children"] : []).filter((child) => typeof child === "object" && child !== null);
1835
1937
  var osdLeaves = (tree) => {
1836
1938
  const root = tree["root"];
@@ -1856,33 +1958,42 @@ var osdAttributes = (leaf, props) => ({
1856
1958
  status: text(leaf["status"]),
1857
1959
  total_space: num(leaf["total_space"], 0)
1858
1960
  });
1859
- var readOsd = (props) => pve(props.target, "read", "GET", `nodes/${props.node}/ceph/osd`).pipe(Effect17.map((t) => {
1860
- const leaf = t === undefined ? undefined : findOsd(t, props.osdid);
1961
+ var readOsd = (props) => runPve(props.target, "read", false, nodes3.getNodeCephOsd({ node: props.node })).pipe(Effect19.map((t) => {
1962
+ const leaf = findOsd(t, props.osdid);
1861
1963
  return leaf === undefined ? undefined : osdAttributes(leaf, props);
1862
1964
  }));
1863
1965
 
1864
1966
  // src/proxmox/ceph-osd-write.ts
1865
- import * as Effect18 from "effect/Effect";
1967
+ import * as nodes4 from "@distilled.cloud/proxmox/nodes";
1968
+ import * as Effect20 from "effect/Effect";
1866
1969
  var OSD_CREATE_ENDPOINT = "pve:POST /nodes/{node}/ceph/osd";
1867
1970
  var describe = (props) => `osd.${String(props.osdid)} on ${props.node}`;
1868
1971
  var createOsdForm = (props, dev) => ({
1869
1972
  dev,
1870
1973
  ...props.device_class === undefined ? {} : { "crush-device-class": props.device_class }
1871
1974
  });
1872
- var createOsd = Effect18.fn(function* (news) {
1975
+ var createOsd = Effect20.fn(function* (news) {
1873
1976
  if (news.dev === undefined) {
1874
- return yield* Effect18.die(new Error(`${describe(news)}: no such OSD in the CRUSH tree, and no \`dev\` was declared. ` + "Without a device this resource is an ASSERTION over an OSD that must already " + "exist. Declare `dev` to let it create one -- which WIPES that device -- or fix " + "the declaration; if the disk was there yesterday, a replica is missing and Ceph " + "is degraded."));
1977
+ return yield* Effect20.die(new Error(`${describe(news)}: no such OSD in the CRUSH tree, and no \`dev\` was declared. ` + "Without a device this resource is an ASSERTION over an OSD that must already " + "exist. Declare `dev` to let it create one -- which WIPES that device -- or fix " + "the declaration; if the disk was there yesterday, a replica is missing and Ceph " + "is degraded."));
1875
1978
  }
1876
1979
  const form = createOsdForm(news, news.dev);
1877
1980
  yield* guardForm(OSD_CREATE_ENDPOINT, form, true);
1878
- yield* pve(news.target, "provision", "POST", `nodes/${news.node}/ceph/osd`, form);
1981
+ yield* runPve(news.target, "provision", true, nodes4.createNodeCephOsd({
1982
+ dev: news.dev,
1983
+ node: news.node,
1984
+ ...news.device_class === undefined ? {} : { crush_device_class: news.device_class }
1985
+ }));
1879
1986
  const created = yield* readOsd(news);
1880
1987
  if (created === undefined) {
1881
- return yield* Effect18.die(new Error(`${describe(news)}: the create returned no error but osd.${String(news.osdid)} is ` + "still absent. Ceph allocates OSD ids and cannot be told which to use, so it most " + "likely assigned a different number -- check `ceph osd tree`, and declare the id it " + "actually gave the device rather than deploying again."));
1988
+ return yield* Effect20.die(new Error(`${describe(news)}: the create returned no error but osd.${String(news.osdid)} is ` + "still absent. Ceph allocates OSD ids and cannot be told which to use, so it most " + "likely assigned a different number -- check `ceph osd tree`, and declare the id it " + "actually gave the device rather than deploying again."));
1882
1989
  }
1883
1990
  return created;
1884
1991
  });
1885
- var destroyOsd = (olds) => pve(olds.target, "provision", "DELETE", `nodes/${olds.node}/ceph/osd/${String(olds.osdid)}`, olds.cleanup === true ? { cleanup: "1" } : {});
1992
+ var destroyOsd = (olds) => runPve(olds.target, "provision", true, nodes4.deleteNodeCephOsd({
1993
+ node: olds.node,
1994
+ osdid: String(olds.osdid),
1995
+ ...olds.cleanup === true ? { cleanup: "1" } : {}
1996
+ }));
1886
1997
 
1887
1998
  // src/proxmox/ceph-osd.ts
1888
1999
  var ProxmoxCephOsd = Resource7("Proxmox.CephOsd", {
@@ -1890,16 +2001,16 @@ var ProxmoxCephOsd = Resource7("Proxmox.CephOsd", {
1890
2001
  });
1891
2002
  var settled = (live, props) => (props.host === undefined || props.host === live.host) && (props.device_class === undefined || props.device_class === live.device_class);
1892
2003
  var describe2 = (props) => `osd.${String(props.osdid)} (read via nodes/${props.node}/ceph/osd)`;
1893
- var handlers4 = {
1894
- list: () => Effect19.succeed([]),
1895
- read: Effect19.fn(function* ({ olds }) {
2004
+ var handlers3 = {
2005
+ list: () => Effect21.succeed([]),
2006
+ read: Effect21.fn(function* ({ olds }) {
1896
2007
  return yield* readOsd(olds);
1897
2008
  }),
1898
- diff: Effect19.fn(function* ({
2009
+ diff: Effect21.fn(function* ({
1899
2010
  news,
1900
2011
  output
1901
2012
  }) {
1902
- if (output === undefined || !isResolved5(news))
2013
+ if (output === undefined || !isResolved6(news))
1903
2014
  return;
1904
2015
  const live = yield* readOsd(news);
1905
2016
  if (live === undefined)
@@ -1908,29 +2019,30 @@ var handlers4 = {
1908
2019
  return { action: "update" };
1909
2020
  return settled(live, news) ? { action: "noop" } : { action: "update" };
1910
2021
  }),
1911
- reconcile: Effect19.fn(function* ({ news }) {
2022
+ reconcile: Effect21.fn(function* ({ news }) {
1912
2023
  const live = yield* readOsd(news);
1913
2024
  if (live === undefined) {
1914
2025
  return yield* createOsd(news);
1915
2026
  }
1916
2027
  if (!settled(live, news)) {
1917
- return yield* Effect19.die(new Error(`${describe2(news)}: exists but not as declared -- live host=${live.host} ` + `device_class=${live.device_class}. Nothing here moves an OSD between hosts or ` + "reclassifies it; fix the declaration, or move it deliberately with `ceph osd crush " + "move` / `ceph osd crush set-device-class` and deploy again."));
2028
+ return yield* Effect21.die(new Error(`${describe2(news)}: exists but not as declared -- live host=${live.host} ` + `device_class=${live.device_class}. Nothing here moves an OSD between hosts or ` + "reclassifies it; fix the declaration, or move it deliberately with `ceph osd crush " + "move` / `ceph osd crush set-device-class` and deploy again."));
1918
2029
  }
1919
2030
  return live;
1920
2031
  }),
1921
- delete: Effect19.fn(function* ({ olds }) {
2032
+ delete: Effect21.fn(function* ({ olds }) {
1922
2033
  yield* destroyOsd(olds);
1923
2034
  })
1924
2035
  };
1925
- var ProxmoxCephOsdProvider = () => Provider7.effect(ProxmoxCephOsd, Effect19.succeed(ProxmoxCephOsd.Provider.of(handlers4)));
2036
+ var ProxmoxCephOsdProvider = () => Provider7.effect(ProxmoxCephOsd, Effect21.succeed(ProxmoxCephOsd.Provider.of(handlers3)));
1926
2037
  // src/proxmox/ceph-pool.ts
1927
2038
  import { Resource as Resource8 } from "alchemy";
2039
+ import { isResolved as isResolved7 } from "alchemy/Diff";
1928
2040
  import * as Provider8 from "alchemy/Provider";
1929
- import * as Effect21 from "effect/Effect";
2041
+ import * as nodes7 from "@distilled.cloud/proxmox/nodes";
2042
+ import * as Effect24 from "effect/Effect";
1930
2043
 
1931
2044
  // src/proxmox/ceph-pool-form.ts
1932
2045
  var object = (props) => `nodes/${props.node}/ceph/pool/${props.name}`;
1933
- var collection = (props) => `nodes/${props.node}/ceph/pool`;
1934
2046
  var UNSET = -1;
1935
2047
  var applications = (value) => csv(Array.isArray(value) ? value.map((entry) => String(entry)) : []);
1936
2048
  var same = (declared, live, frozen = false) => declared === undefined || frozen || declared === live;
@@ -1955,92 +2067,114 @@ var createBody = (props) => ({
1955
2067
  });
1956
2068
 
1957
2069
  // src/proxmox/ceph-pool-settle.ts
1958
- import * as Effect20 from "effect/Effect";
1959
- var confirmAbsent = (props, collection2, describe3) => pve(props.target, "read", "GET", collection2).pipe(Effect20.flatMap((rows) => (rows ?? []).some((row) => row.pool_name === props.name) ? Effect20.die(new Error(`${describe3}: the cluster lists this pool but its status could not be read, ` + "so this deploy will NOT create over it. Check that the node is up and that the " + "read role holds Sys.Audit or Datastore.Audit on / -- a create here would apply " + "pg_num to a live pool and start a PG merge.")) : Effect20.void));
1960
- var settle2 = (props, read, done) => Effect20.gen(function* () {
2070
+ import * as nodes5 from "@distilled.cloud/proxmox/nodes";
2071
+ import * as Effect22 from "effect/Effect";
2072
+ var confirmAbsent = (props, describe3) => runPve(props.target, "read", false, nodes5.listNodeCephPool({ node: props.node })).pipe(Effect22.flatMap((rows) => rows.some((row) => row.pool_name === props.name) ? Effect22.die(new Error(`${describe3}: the cluster lists this pool but its status could not be read, ` + "so this deploy will NOT create over it. Check that the node is up and that the " + "read role holds Sys.Audit or Datastore.Audit on / -- a create here would apply " + "pg_num to a live pool and start a PG merge.")) : Effect22.void));
2073
+ var settle2 = (props, read, done) => Effect22.gen(function* () {
1961
2074
  for (let attempt = 0;attempt < 30; attempt += 1) {
1962
2075
  const live = yield* read(props);
1963
2076
  if (done(live))
1964
2077
  return live;
1965
- yield* Effect20.sleep("2 seconds");
2078
+ yield* Effect22.sleep("2 seconds");
1966
2079
  }
1967
2080
  return yield* read(props);
1968
2081
  });
1969
2082
 
2083
+ // src/proxmox/ceph-pool-wire.ts
2084
+ import * as nodes6 from "@distilled.cloud/proxmox/nodes";
2085
+ import * as Effect23 from "effect/Effect";
2086
+ var attributesOf3 = (live, props) => {
2087
+ const row = live;
2088
+ if (typeof row["name"] !== "string")
2089
+ return;
2090
+ return {
2091
+ applications: applications(row["application_list"]),
2092
+ crush_rule: text(row["crush_rule"]),
2093
+ id: int(row["id"], UNSET),
2094
+ min_size: int(row["min_size"], UNSET),
2095
+ name: props.name,
2096
+ node: props.node,
2097
+ nodelete: bool(row["nodelete"]),
2098
+ nopgchange: bool(row["nopgchange"]),
2099
+ nosizechange: bool(row["nosizechange"]),
2100
+ pg_autoscale_mode: text(row["pg_autoscale_mode"]),
2101
+ pg_num: int(row["pg_num"], UNSET),
2102
+ pg_num_min: int(row["pg_num_min"], UNSET),
2103
+ size: int(row["size"], UNSET),
2104
+ target_size: int(row["target_size"], UNSET),
2105
+ target_size_ratio: num(row["target_size_ratio"], UNSET)
2106
+ };
2107
+ };
2108
+ var readPoolStatus = (props) => runPve(props.target, "read", false, nodes6.getNodeCephPoolStatus({ name: props.name, node: props.node, verbose: "1" })).pipe(Effect23.map((live) => attributesOf3(live, props)), Effect23.orElseSucceed(() => {
2109
+ return;
2110
+ }));
2111
+ var CEPH_POOL_CREATE = "pve:POST /nodes/{node}/ceph/pool";
2112
+ var CEPH_POOL_UPDATE = "pve:PUT /nodes/{node}/ceph/pool/{name}";
2113
+ var toDistilledCreate2 = (props) => ({
2114
+ ...createBody(props),
2115
+ node: props.node
2116
+ });
2117
+ var toDistilledUpdate = (props) => ({
2118
+ ...updateBody(props),
2119
+ name: props.name,
2120
+ node: props.node
2121
+ });
2122
+
1970
2123
  // src/proxmox/ceph-pool.ts
1971
2124
  var ProxmoxCephPool = Resource8("Proxmox.CephPool", {
1972
2125
  defaultRemovalPolicy: "retain"
1973
2126
  });
1974
- var spec = {
1975
- attributes: (live, props) => {
1976
- if (typeof live["name"] !== "string")
2127
+ var matches3 = (attributes, props) => same(props.size, attributes.size, attributes.nosizechange) && same(props.min_size, attributes.min_size, attributes.nosizechange) && same(props.pg_autoscale_mode, attributes.pg_autoscale_mode) && same(hint(props.pg_num_min), attributes.pg_num_min, attributes.nopgchange) && same(props.crush_rule, attributes.crush_rule, attributes.crush_rule === "") && same(hint(props.target_size), attributes.target_size);
2128
+ var ProxmoxCephPoolProvider = () => Provider8.effect(ProxmoxCephPool, Effect24.succeed(ProxmoxCephPool.Provider.of({
2129
+ list: () => Effect24.succeed([]),
2130
+ read: ({ olds }) => readPoolStatus(olds),
2131
+ diff: Effect24.fn(function* ({ news, output }) {
2132
+ if (!isResolved7(news))
1977
2133
  return;
1978
- return {
1979
- applications: applications(live["application_list"]),
1980
- crush_rule: text(live["crush_rule"]),
1981
- id: int(live["id"], UNSET),
1982
- min_size: int(live["min_size"], UNSET),
1983
- name: props.name,
1984
- node: props.node,
1985
- nodelete: bool(live["nodelete"]),
1986
- nopgchange: bool(live["nopgchange"]),
1987
- nosizechange: bool(live["nosizechange"]),
1988
- pg_autoscale_mode: text(live["pg_autoscale_mode"]),
1989
- pg_num: int(live["pg_num"], UNSET),
1990
- pg_num_min: int(live["pg_num_min"], UNSET),
1991
- size: int(live["size"], UNSET),
1992
- target_size: int(live["target_size"], UNSET),
1993
- target_size_ratio: num(live["target_size_ratio"], UNSET)
1994
- };
1995
- },
1996
- collection,
1997
- createForm: createBody,
1998
- endpoint: {
1999
- create: "pve:POST /nodes/{node}/ceph/pool",
2000
- update: "pve:PUT /nodes/{node}/ceph/pool/{name}"
2001
- },
2002
- matches: (attributes, props) => same(props.size, attributes.size, attributes.nosizechange) && same(props.min_size, attributes.min_size, attributes.nosizechange) && same(props.pg_autoscale_mode, attributes.pg_autoscale_mode) && same(hint(props.pg_num_min), attributes.pg_num_min, attributes.nopgchange) && same(props.crush_rule, attributes.crush_rule, attributes.crush_rule === "") && same(hint(props.target_size), attributes.target_size),
2003
- path: (props) => `${object(props)}/status?verbose=1`,
2004
- updateForm: updateBody
2005
- };
2006
- var ops2 = pveOperations(spec);
2007
- var ProxmoxCephPoolProvider = () => Provider8.effect(ProxmoxCephPool, Effect21.succeed(ProxmoxCephPool.Provider.of({
2008
- list: () => Effect21.succeed([]),
2009
- read: ({ olds }) => ops2.read(olds),
2010
- diff: ({ news, output }) => ops2.diff(news, output),
2011
- reconcile: Effect21.fn(function* ({ news }) {
2012
- const live = yield* ops2.read(news);
2134
+ yield* guardWrite2(CEPH_POOL_CREATE, createBody(news), output === undefined);
2135
+ yield* guardWrite2(CEPH_POOL_UPDATE, updateBody(news), false);
2136
+ if (output === undefined)
2137
+ return;
2138
+ const live = yield* readPoolStatus(news);
2139
+ if (live === undefined) {
2140
+ yield* guardWrite2(CEPH_POOL_CREATE, createBody(news), true);
2141
+ return { action: "update" };
2142
+ }
2143
+ return matches3(live, news) ? { action: "noop" } : { action: "update" };
2144
+ }),
2145
+ reconcile: Effect24.fn(function* ({ news }) {
2146
+ const live = yield* readPoolStatus(news);
2013
2147
  let upid;
2014
2148
  if (live === undefined) {
2015
- yield* ops2.guardCreate(news, true);
2016
- yield* confirmAbsent(news, spec.collection(news), object(news));
2017
- upid = yield* pve(news.target, "provision", "POST", collection(news), createBody(news));
2149
+ yield* guardWrite2(CEPH_POOL_CREATE, createBody(news), true);
2150
+ yield* confirmAbsent(news, object(news));
2151
+ upid = yield* runPve(news.target, "provision", true, nodes7.createNodeCephPool(toDistilledCreate2(news)));
2018
2152
  } else {
2019
- const form = formToSend(spec.matches, live, news, updateBody(news));
2153
+ const form = formToSend(matches3, live, news, updateBody(news));
2020
2154
  if (form !== undefined) {
2021
- yield* ops2.guardUpdate(news);
2022
- upid = yield* pve(news.target, "provision", "PUT", object(news), form);
2155
+ yield* guardWrite2(CEPH_POOL_UPDATE, updateBody(news), false);
2156
+ upid = yield* runPve(news.target, "provision", true, nodes7.putNodeCephPool(toDistilledUpdate(news)));
2023
2157
  }
2024
2158
  }
2025
- const after = yield* settle2(news, ops2.read, (row) => row !== undefined && spec.matches(row, news));
2026
- if (after === undefined || !spec.matches(after, news)) {
2027
- return yield* Effect21.die(new Error(`${object(news)}: the write returned no error but the pool still does not match ` + `the declaration after 60s. PVE answered with task ${upid ?? "(none)"} -- read ` + "its log with `pvesh get /nodes/<node>/tasks/<upid>/log` to see what Ceph " + "refused."));
2159
+ const after = yield* settle2(news, readPoolStatus, (row) => row !== undefined && matches3(row, news));
2160
+ if (after === undefined || !matches3(after, news)) {
2161
+ return yield* Effect24.die(new Error(`${object(news)}: the write returned no error but the pool still does not match ` + `the declaration after 60s. PVE answered with task ${upid ?? "(none)"} -- read ` + "its log with `pvesh get /nodes/<node>/tasks/<upid>/log` to see what Ceph " + "refused."));
2028
2162
  }
2029
2163
  return after;
2030
2164
  }),
2031
- delete: Effect21.fn(function* ({ olds }) {
2032
- yield* pve(olds.target, "provision", "DELETE", object(olds));
2033
- const left = yield* settle2(olds, ops2.read, (row) => row === undefined);
2165
+ delete: Effect24.fn(function* ({ olds }) {
2166
+ yield* runPve(olds.target, "provision", true, nodes7.deleteNodeCephPool({ name: olds.name, node: olds.node }));
2167
+ const left = yield* settle2(olds, readPoolStatus, (row) => row === undefined);
2034
2168
  if (left !== undefined) {
2035
- return yield* Effect21.die(new Error(`${object(olds)}: the DELETE returned no error but the pool is still there after ` + "60s. Either a storage on it still holds RBD images, or the mons are running " + "with mon_allow_pool_delete false."));
2169
+ return yield* Effect24.die(new Error(`${object(olds)}: the DELETE returned no error but the pool is still there after ` + "60s. Either a storage on it still holds RBD images, or the mons are running " + "with mon_allow_pool_delete false."));
2036
2170
  }
2037
2171
  })
2038
2172
  })));
2039
2173
  // src/proxmox/firewall-alias.ts
2040
2174
  import { Resource as Resource9 } from "alchemy";
2041
- import { isResolved as isResolved6 } from "alchemy/Diff";
2175
+ import { isResolved as isResolved8 } from "alchemy/Diff";
2042
2176
  import * as Provider9 from "alchemy/Provider";
2043
- import * as Effect22 from "effect/Effect";
2177
+ import * as Effect25 from "effect/Effect";
2044
2178
 
2045
2179
  // src/proxmox/firewall-alias-form.ts
2046
2180
  var fold = (name) => name.trim().toLowerCase();
@@ -2060,7 +2194,7 @@ var body = (props) => {
2060
2194
 
2061
2195
  // src/proxmox/firewall-alias.ts
2062
2196
  var ProxmoxFirewallAlias = Resource9("Proxmox.FirewallAlias");
2063
- var handlers5 = pveHandlers({
2197
+ var handlers4 = pveHandlers({
2064
2198
  attributes: (live, props) => {
2065
2199
  const address = cidr(live["cidr"]);
2066
2200
  return address === "" ? undefined : {
@@ -2080,25 +2214,25 @@ var handlers5 = pveHandlers({
2080
2214
  path: (props) => `cluster/firewall/aliases/${props.name}`,
2081
2215
  updateForm: body
2082
2216
  });
2083
- var ProxmoxFirewallAliasProvider = () => Provider9.effect(ProxmoxFirewallAlias, Effect22.succeed(ProxmoxFirewallAlias.Provider.of({
2084
- ...handlers5,
2085
- diff: Effect22.fn(function* ({ news, output }) {
2086
- if (output !== undefined && isResolved6(news) && fold(news.name) !== fold(output.name)) {
2217
+ var ProxmoxFirewallAliasProvider = () => Provider9.effect(ProxmoxFirewallAlias, Effect25.succeed(ProxmoxFirewallAlias.Provider.of({
2218
+ ...handlers4,
2219
+ diff: Effect25.fn(function* ({ news, output }) {
2220
+ if (output !== undefined && isResolved8(news) && fold(news.name) !== fold(output.name)) {
2087
2221
  return { action: "replace" };
2088
2222
  }
2089
- return yield* handlers5.diff({ news, output });
2223
+ return yield* handlers4.diff({ news, output });
2090
2224
  })
2091
2225
  })));
2092
2226
  // src/proxmox/group.ts
2093
2227
  import { Resource as Resource10 } from "alchemy";
2094
- import { isResolved as isResolved7 } from "alchemy/Diff";
2228
+ import { isResolved as isResolved9 } from "alchemy/Diff";
2095
2229
  import * as Provider10 from "alchemy/Provider";
2096
2230
  import * as access4 from "@distilled.cloud/proxmox/access";
2097
- import * as Effect24 from "effect/Effect";
2231
+ import * as Effect27 from "effect/Effect";
2098
2232
 
2099
2233
  // src/proxmox/group-wire.ts
2100
2234
  import * as access3 from "@distilled.cloud/proxmox/access";
2101
- import * as Effect23 from "effect/Effect";
2235
+ import * as Effect26 from "effect/Effect";
2102
2236
  var GROUP_CREATE = "pve:POST /access/groups";
2103
2237
  var GROUP_UPDATE = "pve:PUT /access/groups/{groupid}";
2104
2238
  var storedComment = (comment2) => {
@@ -2117,14 +2251,14 @@ var updateForm = (props) => ({
2117
2251
  comment: storedComment(props.comment),
2118
2252
  groupid: props.groupid
2119
2253
  });
2120
- var attributesOf3 = (live, props) => ({
2254
+ var attributesOf4 = (live, props) => ({
2121
2255
  comment: text(live.comment),
2122
2256
  groupid: props.groupid,
2123
2257
  members: memberList(live.members)
2124
2258
  });
2125
- var matches3 = (attributes, props) => attributes.comment === storedComment(props.comment);
2126
- var readGroupOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, access3.getAccessGroup({ groupid: props.groupid }))).pipe(Effect23.map((live) => live === UNREADABLE ? UNREADABLE : live.members === undefined ? undefined : attributesOf3(live, props)));
2127
- var readGroup = (props) => readGroupOrFail(props).pipe(Effect23.orElseSucceed(() => {
2259
+ var matches4 = (attributes, props) => attributes.comment === storedComment(props.comment);
2260
+ var readGroupOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, access3.getAccessGroup({ groupid: props.groupid }))).pipe(Effect26.map((live) => live === UNREADABLE ? UNREADABLE : live.members === undefined ? undefined : attributesOf4(live, props)));
2261
+ var readGroup = (props) => readGroupOrFail(props).pipe(Effect26.orElseSucceed(() => {
2128
2262
  return;
2129
2263
  }));
2130
2264
  var dropUnreadable3 = (live) => live === UNREADABLE ? undefined : live;
@@ -2133,13 +2267,13 @@ var dropUnreadable3 = (live) => live === UNREADABLE ? undefined : live;
2133
2267
  var ProxmoxGroup = Resource10("Proxmox.Group", {
2134
2268
  defaultRemovalPolicy: "retain"
2135
2269
  });
2136
- var ProxmoxGroupProvider = () => Provider10.effect(ProxmoxGroup, Effect24.succeed(ProxmoxGroup.Provider.of({
2137
- list: () => Effect24.succeed([]),
2138
- read: Effect24.fn(function* ({ olds, output }) {
2270
+ var ProxmoxGroupProvider = () => Provider10.effect(ProxmoxGroup, Effect27.succeed(ProxmoxGroup.Provider.of({
2271
+ list: () => Effect27.succeed([]),
2272
+ read: Effect27.fn(function* ({ olds, output }) {
2139
2273
  return dropUnreadable3(yield* output === undefined ? readGroup(olds) : readGroupOrFail(olds));
2140
2274
  }),
2141
- diff: Effect24.fn(function* ({ news, output }) {
2142
- if (!isResolved7(news))
2275
+ diff: Effect27.fn(function* ({ news, output }) {
2276
+ if (!isResolved9(news))
2143
2277
  return;
2144
2278
  yield* guardWrite2(GROUP_CREATE, createForm3(news), output === undefined);
2145
2279
  yield* guardWrite2(GROUP_UPDATE, updateForm(news), false);
@@ -2154,31 +2288,31 @@ var ProxmoxGroupProvider = () => Provider10.effect(ProxmoxGroup, Effect24.succee
2154
2288
  yield* guardWrite2(GROUP_CREATE, createForm3(news), true);
2155
2289
  return { action: "update" };
2156
2290
  }
2157
- return matches3(live, news) ? { action: "noop" } : { action: "update" };
2291
+ return matches4(live, news) ? { action: "noop" } : { action: "update" };
2158
2292
  }),
2159
- reconcile: Effect24.fn(function* ({ news }) {
2293
+ reconcile: Effect27.fn(function* ({ news }) {
2160
2294
  const before = dropUnreadable3(yield* readGroup(news));
2161
2295
  yield* guardWrite2(GROUP_CREATE, createForm3(news), before === undefined);
2162
2296
  yield* guardWrite2(GROUP_UPDATE, updateForm(news), false);
2163
2297
  if (before === undefined) {
2164
2298
  yield* runPve(news.target, "provision", true, access4.createAccessGroup(createForm3(news)));
2165
- } else if (!matches3(before, news)) {
2299
+ } else if (!matches4(before, news)) {
2166
2300
  yield* runPve(news.target, "provision", true, access4.putAccessGroup(updateForm(news)));
2167
2301
  }
2168
2302
  const after = dropUnreadable3(yield* readGroup(news));
2169
2303
  if (after === undefined) {
2170
- return yield* Effect24.die(new Error(`access/groups/${news.groupid}: the write returned no error but the group 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."));
2304
+ return yield* Effect27.die(new Error(`access/groups/${news.groupid}: the write returned no error but the group 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."));
2171
2305
  }
2172
2306
  return after;
2173
2307
  }),
2174
- delete: Effect24.fn(function* ({ olds }) {
2308
+ delete: Effect27.fn(function* ({ olds }) {
2175
2309
  yield* runPve(olds.target, "provision", true, access4.deleteAccessGroup({ groupid: olds.groupid }));
2176
2310
  })
2177
2311
  })));
2178
2312
  // src/proxmox/ha-resource.ts
2179
2313
  import { Resource as Resource11 } from "alchemy";
2180
2314
  import * as Provider11 from "alchemy/Provider";
2181
- import * as Effect25 from "effect/Effect";
2315
+ import * as Effect28 from "effect/Effect";
2182
2316
  var ProxmoxHaResource = Resource11("Proxmox.HaResource");
2183
2317
  var kind = (sid) => sid.split(":")[0] ?? "";
2184
2318
  var shape3 = (props) => ({
@@ -2187,7 +2321,7 @@ var shape3 = (props) => ({
2187
2321
  max_restart: String(props.max_restart ?? 1),
2188
2322
  state: props.state ?? "started"
2189
2323
  });
2190
- var handlers6 = pveHandlers({
2324
+ var handlers5 = pveHandlers({
2191
2325
  attributes: (live, props) => ({
2192
2326
  comment: typeof live["comment"] === "string" ? live["comment"] : "",
2193
2327
  max_relocate: num(live["max_relocate"], 1),
@@ -2206,11 +2340,11 @@ var handlers6 = pveHandlers({
2206
2340
  path: (props) => `cluster/ha/resources/${props.sid}`,
2207
2341
  updateForm: shape3
2208
2342
  });
2209
- var ProxmoxHaResourceProvider = () => Provider11.effect(ProxmoxHaResource, Effect25.succeed(ProxmoxHaResource.Provider.of(handlers6)));
2343
+ var ProxmoxHaResourceProvider = () => Provider11.effect(ProxmoxHaResource, Effect28.succeed(ProxmoxHaResource.Provider.of(handlers5)));
2210
2344
  // src/proxmox/ha-rule.ts
2211
2345
  import { Resource as Resource12 } from "alchemy";
2212
2346
  import * as Provider12 from "alchemy/Provider";
2213
- import * as Effect26 from "effect/Effect";
2347
+ import * as Effect29 from "effect/Effect";
2214
2348
 
2215
2349
  // src/proxmox/ha-rule-form.ts
2216
2350
  var nodeList = (value) => {
@@ -2258,7 +2392,7 @@ var clearList = (props) => Object.entries(optional(props)).filter(([, value]) =>
2258
2392
 
2259
2393
  // src/proxmox/ha-rule.ts
2260
2394
  var ProxmoxHaRule = Resource12("Proxmox.HaRule");
2261
- var handlers7 = pveHandlers({
2395
+ var handlers6 = pveHandlers({
2262
2396
  attributes: (live, props) => {
2263
2397
  const liveType = text(live["type"]);
2264
2398
  if (liveType !== "" && liveType !== props.type)
@@ -2287,43 +2421,43 @@ var handlers7 = pveHandlers({
2287
2421
  return withClears(fields, clear);
2288
2422
  }
2289
2423
  });
2290
- var ProxmoxHaRuleProvider = () => Provider12.effect(ProxmoxHaRule, Effect26.succeed(ProxmoxHaRule.Provider.of(handlers7)));
2424
+ var ProxmoxHaRuleProvider = () => Provider12.effect(ProxmoxHaRule, Effect29.succeed(ProxmoxHaRule.Provider.of(handlers6)));
2291
2425
  // src/proxmox/lxc.ts
2292
2426
  import { Resource as Resource13 } from "alchemy";
2293
- import { isResolved as isResolved8 } from "alchemy/Diff";
2427
+ import { isResolved as isResolved10 } from "alchemy/Diff";
2294
2428
  import * as Provider13 from "alchemy/Provider";
2295
- import * as Effect36 from "effect/Effect";
2429
+ import * as Effect39 from "effect/Effect";
2296
2430
 
2297
2431
  // src/ownership/adopt.ts
2298
2432
  import { AdoptPolicy } from "alchemy/AdoptPolicy";
2299
2433
  import { AlchemyContext } from "alchemy/AlchemyContext";
2300
2434
  import { Stack as Stack3 } from "alchemy/Stack";
2301
- import * as Effect30 from "effect/Effect";
2435
+ import * as Effect33 from "effect/Effect";
2302
2436
  import * as Option5 from "effect/Option";
2303
2437
 
2304
2438
  // src/ownership/resume.ts
2305
2439
  import { Unowned } from "alchemy/AdoptPolicy";
2306
2440
  import { Artifacts } from "alchemy/Artifacts";
2307
- import * as Effect27 from "effect/Effect";
2441
+ import * as Effect30 from "effect/Effect";
2308
2442
  import * as Option2 from "effect/Option";
2309
2443
  var PROVEN = "homeflare/ownership/resumes";
2310
2444
  var UNFINISHED = "homeflare/ownership/unfinished";
2311
- var note = (key, instanceId) => Effect27.gen(function* () {
2312
- const bag = yield* Effect27.serviceOption(Artifacts);
2445
+ var note = (key, instanceId) => Effect30.gen(function* () {
2446
+ const bag = yield* Effect30.serviceOption(Artifacts);
2313
2447
  if (Option2.isSome(bag))
2314
2448
  yield* bag.value.set(key, instanceId);
2315
2449
  });
2316
- var noted = (key, instanceId) => Effect27.gen(function* () {
2317
- const bag = yield* Effect27.serviceOption(Artifacts);
2450
+ var noted = (key, instanceId) => Effect30.gen(function* () {
2451
+ const bag = yield* Effect30.serviceOption(Artifacts);
2318
2452
  if (Option2.isNone(bag))
2319
2453
  return false;
2320
2454
  return (yield* bag.value.get(key)) === instanceId;
2321
2455
  });
2322
- var noteUnfinished = (instanceId) => Effect27.as(note(UNFINISHED, instanceId), undefined);
2323
- var noteResume = (instanceId, recovered) => Effect27.gen(function* () {
2456
+ var noteUnfinished = (instanceId) => Effect30.as(note(UNFINISHED, instanceId), undefined);
2457
+ var noteResume = (instanceId, recovered) => Effect30.gen(function* () {
2324
2458
  yield* noteUnfinished(instanceId);
2325
- const unproven = () => Effect27.succeed(undefined);
2326
- const found = yield* recovered.pipe(Effect27.catch(unproven), Effect27.catchDefect(unproven));
2459
+ const unproven = () => Effect30.succeed(undefined);
2460
+ const found = yield* recovered.pipe(Effect30.catch(unproven), Effect30.catchDefect(unproven));
2327
2461
  if (found === undefined || found === null || Unowned.is(found))
2328
2462
  return;
2329
2463
  yield* note(PROVEN, instanceId);
@@ -2334,7 +2468,7 @@ var provingResumes = (service) => {
2334
2468
  const { diff, read } = service;
2335
2469
  if (diff === undefined || read === undefined)
2336
2470
  return service;
2337
- const proving = (input) => Effect27.gen(function* () {
2471
+ const proving = (input) => Effect30.gen(function* () {
2338
2472
  if (input.output === undefined) {
2339
2473
  yield* noteResume(input.instanceId, read({ ...input, output: undefined }));
2340
2474
  }
@@ -2346,12 +2480,12 @@ var provingResumes = (service) => {
2346
2480
  // src/ownership/rows.ts
2347
2481
  import { Stack as Stack2 } from "alchemy/Stack";
2348
2482
  import { State, isActionState } from "alchemy/State/State";
2349
- import * as Effect29 from "effect/Effect";
2483
+ import * as Effect32 from "effect/Effect";
2350
2484
  import * as Option4 from "effect/Option";
2351
2485
 
2352
2486
  // src/ownership/whole.ts
2353
2487
  import { Stack } from "alchemy/Stack";
2354
- import * as Effect28 from "effect/Effect";
2488
+ import * as Effect31 from "effect/Effect";
2355
2489
  import * as Option3 from "effect/Option";
2356
2490
  var absent = (value) => value === undefined || value === null;
2357
2491
  var isPlainObject = (value) => {
@@ -2377,22 +2511,22 @@ var carries = (declared, recorded) => {
2377
2511
  }
2378
2512
  return true;
2379
2513
  };
2380
- var wholeDeclaration = (fqn, props) => Effect28.map(Effect28.serviceOption(Stack), (stack) => {
2514
+ var wholeDeclaration = (fqn, props) => Effect31.map(Effect31.serviceOption(Stack), (stack) => {
2381
2515
  const declared = Option3.isSome(stack) ? stack.value.resources[fqn] : undefined;
2382
2516
  return declared !== undefined && carries(declared.Props, props);
2383
2517
  });
2384
2518
 
2385
2519
  // src/ownership/rows.ts
2386
- var storeOf = Effect29.gen(function* () {
2387
- const stack = yield* Effect29.serviceOption(Stack2);
2388
- const state = yield* Effect29.serviceOption(State);
2520
+ var storeOf = Effect32.gen(function* () {
2521
+ const stack = yield* Effect32.serviceOption(Stack2);
2522
+ const state = yield* Effect32.serviceOption(State);
2389
2523
  if (Option4.isNone(stack) || Option4.isNone(state))
2390
2524
  return;
2391
2525
  const store = yield* state.value;
2392
2526
  const where = { stack: stack.value.name, stage: stack.value.stage };
2393
2527
  return { resources: stack.value.resources, store, where };
2394
2528
  });
2395
- var rowAt = (store, where, fqn) => store.get({ ...where, fqn }).pipe(Effect29.orElseSucceed(() => {
2529
+ var rowAt = (store, where, fqn) => store.get({ ...where, fqn }).pipe(Effect32.orElseSucceed(() => {
2396
2530
  return;
2397
2531
  }));
2398
2532
  var generationOf = (row, instanceId) => {
@@ -2405,7 +2539,7 @@ var generationOf = (row, instanceId) => {
2405
2539
  }
2406
2540
  return;
2407
2541
  };
2408
- var recordedGeneration = (fqn, instanceId) => Effect29.gen(function* () {
2542
+ var recordedGeneration = (fqn, instanceId) => Effect32.gen(function* () {
2409
2543
  const found = yield* storeOf;
2410
2544
  if (found === undefined)
2411
2545
  return;
@@ -2416,14 +2550,14 @@ var recordedGeneration = (fqn, instanceId) => Effect29.gen(function* () {
2416
2550
  }
2417
2551
  return;
2418
2552
  });
2419
- var recordedInstance = (fqn, instanceId) => Effect29.gen(function* () {
2553
+ var recordedInstance = (fqn, instanceId) => Effect32.gen(function* () {
2420
2554
  const generation = yield* recordedGeneration(fqn, instanceId);
2421
2555
  if (generation === undefined)
2422
2556
  return "absent";
2423
2557
  return (yield* wholeDeclaration(fqn, generation.props)) ? "whole" : "partial";
2424
2558
  });
2425
- var isCreate = (fqn, instanceId) => Effect29.map(recordedGeneration(fqn, instanceId), (generation) => generation?.status === "creating");
2426
- var forgetRefusedCreate = (fqn, instanceId) => Effect29.gen(function* () {
2559
+ var isCreate = (fqn, instanceId) => Effect32.map(recordedGeneration(fqn, instanceId), (generation) => generation?.status === "creating");
2560
+ var forgetRefusedCreate = (fqn, instanceId) => Effect32.gen(function* () {
2427
2561
  const found = yield* storeOf;
2428
2562
  if (found === undefined)
2429
2563
  return;
@@ -2432,32 +2566,32 @@ var forgetRefusedCreate = (fqn, instanceId) => Effect29.gen(function* () {
2432
2566
  if (mine?.status !== "creating" || mine.instanceId !== instanceId || mine.attr !== undefined) {
2433
2567
  return;
2434
2568
  }
2435
- yield* found.store.delete({ ...found.where, fqn }).pipe(Effect29.ignore);
2569
+ yield* found.store.delete({ ...found.where, fqn }).pipe(Effect32.ignore);
2436
2570
  });
2437
2571
 
2438
2572
  // src/ownership/adopt.ts
2439
- var adoptEnabled = (fqn) => Effect30.gen(function* () {
2440
- const stack = yield* Effect30.serviceOption(Stack3);
2573
+ var adoptEnabled = (fqn) => Effect33.gen(function* () {
2574
+ const stack = yield* Effect33.serviceOption(Stack3);
2441
2575
  const scoped = Option5.isSome(stack) ? stack.value.resources[fqn]?.Adopt : undefined;
2442
2576
  if (scoped !== undefined)
2443
2577
  return scoped;
2444
- const policy = yield* Effect30.serviceOption(AdoptPolicy);
2578
+ const policy = yield* Effect33.serviceOption(AdoptPolicy);
2445
2579
  if (Option5.isSome(policy))
2446
2580
  return policy.value;
2447
- const context = yield* Effect30.serviceOption(AlchemyContext);
2581
+ const context = yield* Effect33.serviceOption(AlchemyContext);
2448
2582
  return Option5.isSome(context) ? context.value.adopt : false;
2449
2583
  });
2450
- var adoptable = (owner) => Effect30.gen(function* () {
2584
+ var adoptable = (owner) => Effect33.gen(function* () {
2451
2585
  if (yield* isCreate(owner.fqn, owner.instanceId))
2452
2586
  return true;
2453
2587
  return yield* unfinished(owner.instanceId);
2454
2588
  });
2455
- var adoptsAtApply = (owner) => Effect30.gen(function* () {
2589
+ var adoptsAtApply = (owner) => Effect33.gen(function* () {
2456
2590
  if (!(yield* adoptEnabled(owner.fqn)))
2457
2591
  return false;
2458
2592
  return yield* adoptable(owner);
2459
2593
  });
2460
- var refuseTakeover = (owner, what) => Effect30.gen(function* () {
2594
+ var refuseTakeover = (owner, what) => Effect33.gen(function* () {
2461
2595
  if (owner.output !== undefined)
2462
2596
  return;
2463
2597
  if (yield* resumes(owner.instanceId))
@@ -2467,25 +2601,25 @@ var refuseTakeover = (owner, what) => Effect30.gen(function* () {
2467
2601
  return;
2468
2602
  yield* forgetRefusedCreate(owner.fqn, owner.instanceId);
2469
2603
  const remedy = may ? "Deploy with --adopt (or wrap the resource in adopt(true)) to take it over, or remove it first." : "It is the new identity of a replace, which --adopt does not cover: remove it first.";
2470
- return yield* Effect30.die(new Error(`${what}: already exists, and this stack holds no state for it — the plan could not ask ` + "first (a prop was still an Output, a replace moved onto it, or it appeared after the " + `plan). Nothing was written. ${remedy}`));
2604
+ return yield* Effect33.die(new Error(`${what}: already exists, and this stack holds no state for it — the plan could not ask ` + "first (a prop was still an Output, a replace moved onto it, or it appeared after the " + `plan). Nothing was written. ${remedy}`));
2471
2605
  });
2472
2606
  var claimFor = (owner) => (what) => refuseTakeover(owner, what);
2473
2607
 
2474
2608
  // src/ownership/probe.ts
2475
2609
  import { Unowned as Unowned2 } from "alchemy/AdoptPolicy";
2476
- import * as Effect31 from "effect/Effect";
2477
- var provenOurs = (ask, settled2) => Effect31.gen(function* () {
2610
+ import * as Effect34 from "effect/Effect";
2611
+ var provenOurs = (ask, settled2) => Effect34.gen(function* () {
2478
2612
  const recorded = yield* recordedInstance(ask.fqn, ask.instanceId);
2479
2613
  if (recorded === "absent")
2480
2614
  return false;
2481
2615
  if (recorded === "partial") {
2482
- yield* Effect31.logWarning(`${ask.fqn}: the interrupted create's state row lacks part of the declaration (a prop ` + "was still an Output when it was written), so the live object is not proven ours");
2616
+ yield* Effect34.logWarning(`${ask.fqn}: the interrupted create's state row lacks part of the declaration (a prop ` + "was still an Output when it was written), so the live object is not proven ours");
2483
2617
  return false;
2484
2618
  }
2485
- const unproven = (reason) => Effect31.as(Effect31.logWarning(`${ask.fqn}: the interrupted create's object could not be compared with its props ` + `(${reason instanceof Error ? reason.message : String(reason)}), so it is not treated as ours`), false);
2486
- return yield* settled2.pipe(Effect31.catch(unproven), Effect31.catchDefect(unproven));
2619
+ const unproven = (reason) => Effect34.as(Effect34.logWarning(`${ask.fqn}: the interrupted create's object could not be compared with its props ` + `(${reason instanceof Error ? reason.message : String(reason)}), so it is not treated as ours`), false);
2620
+ return yield* settled2.pipe(Effect34.catch(unproven), Effect34.catchDefect(unproven));
2487
2621
  });
2488
- var ownedRead = (ask, found, settled2) => Effect31.gen(function* () {
2622
+ var ownedRead = (ask, found, settled2) => Effect34.gen(function* () {
2489
2623
  if (found === undefined || ask.output !== undefined)
2490
2624
  return found;
2491
2625
  return (yield* provenOurs(ask, settled2)) ? found : Unowned2(found);
@@ -2543,8 +2677,8 @@ var optionMap = (value, family, defaultKey) => {
2543
2677
  return out;
2544
2678
  };
2545
2679
  var sameMap = (left, right) => left.size === right.size && [...left].every(([key, value]) => right.get(key) === value);
2546
- var sortedForm = (map9) => [...map9].map(([key, value]) => `${key}=${value}`).sort().join(",");
2547
- var printMap = (map9, lead = []) => [...lead.filter((key) => map9.has(key)), ...[...map9.keys()].filter((k) => !lead.includes(k))].map((key) => `${key}=${map9.get(key) ?? ""}`).join(",");
2680
+ var sortedForm = (map12) => [...map12].map(([key, value]) => `${key}=${value}`).sort().join(",");
2681
+ var printMap = (map12, lead = []) => [...lead.filter((key) => map12.has(key)), ...[...map12.keys()].filter((k) => !lead.includes(k))].map((key) => `${key}=${map12.get(key) ?? ""}`).join(",");
2548
2682
  var netMaps = (declared, live) => {
2549
2683
  const want = optionMap(declared, "net");
2550
2684
  const have = optionMap(live, "net");
@@ -2690,12 +2824,12 @@ var sizeBytes = (text2) => {
2690
2824
  };
2691
2825
  var parseVolume = (text2) => {
2692
2826
  const [first] = pairs(text2, "volume");
2693
- const spec2 = first?.[0] === "volume" ? first[1] : "";
2827
+ const spec = first?.[0] === "volume" ? first[1] : "";
2694
2828
  const options = optionMap(text2, "volume", "volume");
2695
2829
  options.delete("volume");
2696
2830
  const sizeText = options.get("size");
2697
2831
  options.delete("size");
2698
- const fresh = NEW_DISK.exec(spec2);
2832
+ const fresh = NEW_DISK.exec(spec);
2699
2833
  if (fresh !== null) {
2700
2834
  const gib = `${fresh[2] ?? "0"}G`;
2701
2835
  return {
@@ -2708,18 +2842,18 @@ var parseVolume = (text2) => {
2708
2842
  };
2709
2843
  }
2710
2844
  const size = sizeText === undefined ? undefined : sizeBytes(sizeText);
2711
- if (spec2.startsWith("/")) {
2712
- const kind2 = spec2.startsWith("/dev/") ? "device" : "bind";
2713
- return { kind: kind2, options, size, sizeText, source: spec2, volname: "" };
2845
+ if (spec.startsWith("/")) {
2846
+ const kind2 = spec.startsWith("/dev/") ? "device" : "bind";
2847
+ return { kind: kind2, options, size, sizeText, source: spec, volname: "" };
2714
2848
  }
2715
- const at = spec2.indexOf(":");
2849
+ const at = spec.indexOf(":");
2716
2850
  return {
2717
2851
  kind: "volume",
2718
2852
  options,
2719
2853
  size,
2720
2854
  sizeText,
2721
- source: at === -1 ? spec2 : spec2.slice(0, at),
2722
- volname: at === -1 ? "" : spec2.slice(at + 1)
2855
+ source: at === -1 ? spec : spec.slice(0, at),
2856
+ volname: at === -1 ? "" : spec.slice(at + 1)
2723
2857
  };
2724
2858
  };
2725
2859
  var isHostPath = (volume) => volume.kind === "bind" || volume.kind === "device";
@@ -2940,11 +3074,11 @@ var identityRefusals = (news, olds, output) => {
2940
3074
  };
2941
3075
 
2942
3076
  // src/proxmox/lxc-adoption.ts
2943
- import * as Effect35 from "effect/Effect";
3077
+ import * as Effect38 from "effect/Effect";
2944
3078
 
2945
3079
  // src/ownership/adopting.ts
2946
- import * as Effect32 from "effect/Effect";
2947
- var adopting = (owner, settled2) => Effect32.gen(function* () {
3080
+ import * as Effect35 from "effect/Effect";
3081
+ var adopting = (owner, settled2) => Effect35.gen(function* () {
2948
3082
  if (owner.output === undefined)
2949
3083
  return false;
2950
3084
  const generation = yield* recordedGeneration(owner.fqn, owner.instanceId);
@@ -2956,11 +3090,11 @@ var adopting = (owner, settled2) => Effect32.gen(function* () {
2956
3090
  });
2957
3091
 
2958
3092
  // src/proxmox/lxc-lifecycle.ts
2959
- import * as Effect34 from "effect/Effect";
3093
+ import * as Effect37 from "effect/Effect";
2960
3094
 
2961
3095
  // src/proxmox/network-apply-read.ts
2962
- import * as Effect33 from "effect/Effect";
2963
- var stagedDiff = (target, node) => Effect33.gen(function* () {
3096
+ import * as Effect36 from "effect/Effect";
3097
+ var stagedDiff = (target, node) => Effect36.gen(function* () {
2964
3098
  const path = `nodes/${node}/network`;
2965
3099
  const credential = yield* leased(target, "read");
2966
3100
  const envelope = yield* pveEnvelopeWith(target, credential, "GET", path);
@@ -2973,8 +3107,8 @@ var pendingLines = (diff) => {
2973
3107
  `).filter((line) => (line.startsWith("+") || line.startsWith("-")) && !line.startsWith("+++") && !line.startsWith("---")).length;
2974
3108
  return Math.max(changed, 1);
2975
3109
  };
2976
- var pendingCount = (target, node) => stagedDiff(target, node).pipe(Effect33.map(pendingLines));
2977
- var clusterHealth = (target) => pve(target, "read", "GET", "cluster/status").pipe(Effect33.map((rows) => {
3110
+ var pendingCount = (target, node) => stagedDiff(target, node).pipe(Effect36.map(pendingLines));
3111
+ var clusterHealth = (target) => pve(target, "read", "GET", "cluster/status").pipe(Effect36.map((rows) => {
2978
3112
  const all = rows ?? [];
2979
3113
  const cluster = all.find((row) => row.type === "cluster");
2980
3114
  return {
@@ -2982,21 +3116,21 @@ var clusterHealth = (target) => pve(target, "read", "GET", "cluster/status").pip
2982
3116
  quorate: cluster === undefined ? true : bool(cluster.quorate)
2983
3117
  };
2984
3118
  }));
2985
- var degradedReason = (target) => clusterHealth(target).pipe(Effect33.map((health) => health.quorate && health.offline.length === 0 ? undefined : `quorate=${String(health.quorate)} offline=[${health.offline.join(", ")}]`));
3119
+ var degradedReason = (target) => clusterHealth(target).pipe(Effect36.map((health) => health.quorate && health.offline.length === 0 ? undefined : `quorate=${String(health.quorate)} offline=[${health.offline.join(", ")}]`));
2986
3120
  var UNREACHABLE = "the task could not be read -- the node stopped answering, or this lease cannot see it";
2987
3121
  var STILL_RUNNING = "still running when this provider stopped waiting";
2988
3122
  var ATTEMPTS = 30;
2989
- var awaitTask = (target, credential, node, upid, attempts = ATTEMPTS) => Effect33.gen(function* () {
3123
+ var awaitTask = (target, credential, node, upid, attempts = ATTEMPTS) => Effect36.gen(function* () {
2990
3124
  const path = `nodes/${node}/tasks/${upid}/status`;
2991
3125
  for (let attempt = 0;attempt < attempts; attempt += 1) {
2992
- const status = yield* pveWith(target, credential, "GET", path).pipe(Effect33.orElseSucceed(() => {
3126
+ const status = yield* pveWith(target, credential, "GET", path).pipe(Effect36.orElseSucceed(() => {
2993
3127
  return;
2994
3128
  }));
2995
3129
  if (status === undefined)
2996
3130
  return UNREACHABLE;
2997
3131
  if (status.status === "stopped")
2998
3132
  return text(status.exitstatus, "stopped with no exitstatus");
2999
- yield* Effect33.sleep("1 second");
3133
+ yield* Effect36.sleep("1 second");
3000
3134
  }
3001
3135
  return STILL_RUNNING;
3002
3136
  });
@@ -3014,43 +3148,43 @@ var LXC_ENDPOINTS = {
3014
3148
  var CREATE_POLLS = 180;
3015
3149
  var TASK_POLLS = 60;
3016
3150
  var isServerError = (error) => error instanceof PveError && error.status === 500;
3017
- var readLive = (where) => Effect34.gen(function* () {
3018
- const answer = yield* pve(where.target, "read", "GET", `${guestPath(where)}/config`).pipe(Effect34.map((data) => ({ data, error: undefined })), Effect34.catchIf(isServerError, (error) => Effect34.succeed({ data: undefined, error })));
3151
+ var readLive = (where) => Effect37.gen(function* () {
3152
+ const answer = yield* pve(where.target, "read", "GET", `${guestPath(where)}/config`).pipe(Effect37.map((data) => ({ data, error: undefined })), Effect37.catchIf(isServerError, (error) => Effect37.succeed({ data: undefined, error })));
3019
3153
  if (answer.data !== undefined && answer.data !== null)
3020
3154
  return answer.data;
3021
3155
  const rows = yield* pve(where.target, "read", "GET", "cluster/resources?type=vm");
3022
3156
  const found = (rows ?? []).find((row) => Number(row.vmid) === where.vmid);
3023
3157
  if (found !== undefined && found.node === where.node && found.type === "lxc") {
3024
- return yield* Effect34.fail(answer.error ?? new LxcRefusedError(`CT ${String(where.vmid)} is listed but its config read empty.`));
3158
+ return yield* Effect37.fail(answer.error ?? new LxcRefusedError(`CT ${String(where.vmid)} is listed but its config read empty.`));
3025
3159
  }
3026
3160
  if (found !== undefined) {
3027
- return yield* Effect34.fail(new LxcRefusedError(`vmid ${String(where.vmid)} is a ${text(found.type, "guest")} on ` + `${text(found.node, "?")}, not a container on ${where.node}. A migration is not an ` + "update and vmids are cluster-wide: declare the node it is on, or pick a free vmid."));
3161
+ return yield* Effect37.fail(new LxcRefusedError(`vmid ${String(where.vmid)} is a ${text(found.type, "guest")} on ` + `${text(found.node, "?")}, not a container on ${where.node}. A migration is not an ` + "update and vmids are cluster-wide: declare the node it is on, or pick a free vmid."));
3028
3162
  }
3029
3163
  return;
3030
3164
  });
3031
- var attributesOf4 = (where, live) => ({
3165
+ var attributesOf5 = (where, live) => ({
3032
3166
  config: storedConfig(live),
3033
3167
  node: where.node,
3034
3168
  rawKeys: rawKeysOf(live),
3035
3169
  vmid: where.vmid
3036
3170
  });
3037
- var task = (where, method, path, what, polls, form) => Effect34.gen(function* () {
3171
+ var task = (where, method, path, what, polls, form) => Effect37.gen(function* () {
3038
3172
  const credential = yield* mint(where.target, "provision");
3039
3173
  const upid = text(yield* pveWith(where.target, credential, method, path, form));
3040
3174
  if (upid === "") {
3041
- return yield* Effect34.fail(new LxcRefusedError(`${what}: PVE returned no task id, so the write cannot be confirmed and is not claimed.`));
3175
+ return yield* Effect37.fail(new LxcRefusedError(`${what}: PVE returned no task id, so the write cannot be confirmed and is not claimed.`));
3042
3176
  }
3043
3177
  const exit = yield* awaitTask(where.target, credential, where.node, upid, polls);
3044
3178
  if (exit !== "OK") {
3045
- return yield* Effect34.fail(new LxcRefusedError(`${what}: task ${upid} ended "${exit}". Read \`pvesh get /nodes/${where.node}/tasks/` + `${upid}/log\` before running the deploy again.`));
3179
+ return yield* Effect37.fail(new LxcRefusedError(`${what}: task ${upid} ended "${exit}". Read \`pvesh get /nodes/${where.node}/tasks/` + `${upid}/log\` before running the deploy again.`));
3046
3180
  }
3047
3181
  });
3048
- var createGuest = (props) => Effect34.gen(function* () {
3182
+ var createGuest = (props) => Effect37.gen(function* () {
3049
3183
  const form = createForm4(props);
3050
3184
  yield* guardForm(LXC_ENDPOINTS.create, form, true);
3051
3185
  return yield* task(props, "POST", `nodes/${props.node}/lxc`, `create CT ${String(props.vmid)}`, CREATE_POLLS, form);
3052
3186
  });
3053
- var updateGuest = (props, change, digest) => Effect34.gen(function* () {
3187
+ var updateGuest = (props, change, digest) => Effect37.gen(function* () {
3054
3188
  if (Object.keys(change.put).length > 0 || change.clear.length > 0) {
3055
3189
  const form = withClears({ ...change.put, ...digest === "" ? {} : { digest } }, change.clear);
3056
3190
  yield* guardForm(LXC_ENDPOINTS.update, form, false);
@@ -3062,47 +3196,47 @@ var updateGuest = (props, change, digest) => Effect34.gen(function* () {
3062
3196
  yield* task(props, "PUT", `${guestPath(props)}/resize`, `grow ${grow.disk} of CT ${String(props.vmid)} to ${grow.size}`, TASK_POLLS, grown);
3063
3197
  }
3064
3198
  });
3065
- var destroyGuest = (where, declared) => Effect34.gen(function* () {
3199
+ var destroyGuest = (where, declared) => Effect37.gen(function* () {
3066
3200
  const live = yield* readLive(where);
3067
3201
  if (live === undefined)
3068
3202
  return;
3069
3203
  const drift = judge(declared, live).drift;
3070
3204
  if (drift.length > 0) {
3071
- return yield* Effect34.fail(new LxcRefusedError(`destroy CT ${String(where.vmid)}: the guest on ${where.node} no longer matches its last ` + `declaration (${drift.join(", ")}), so it may not be the guest this stack made. ` + "Nothing was deleted. Delete it by hand if it should go, or declare it again."));
3205
+ return yield* Effect37.fail(new LxcRefusedError(`destroy CT ${String(where.vmid)}: the guest on ${where.node} no longer matches its last ` + `declaration (${drift.join(", ")}), so it may not be the guest this stack made. ` + "Nothing was deleted. Delete it by hand if it should go, or declare it again."));
3072
3206
  }
3073
3207
  yield* task(where, "DELETE", guestPath(where), `destroy CT ${String(where.vmid)}`, TASK_POLLS);
3074
3208
  });
3075
3209
 
3076
3210
  // src/proxmox/lxc-adoption.ts
3077
3211
  var adoptionRefusal = (props, drift) => `CT ${String(props.vmid)} on ${props.node}: adopting it would change ${drift.join(", ")}. An ` + "adoption never changes a guest, so nothing is written. Declare what is live for these keys " + "(the plan names keys, never values) and plan again; change them after the adoption, as an " + "update.";
3078
- var refuseAdoptedDrift = (owner, props, live, change) => Effect35.gen(function* () {
3212
+ var refuseAdoptedDrift = (owner, props, live, change) => Effect38.gen(function* () {
3079
3213
  if (change.drift.length === 0)
3080
3214
  return;
3081
- const settled2 = (recorded) => Effect35.sync(() => judge(recorded, live).drift.length === 0);
3215
+ const settled2 = (recorded) => Effect38.sync(() => judge(recorded, live).drift.length === 0);
3082
3216
  if (!(yield* adopting(owner, settled2)))
3083
3217
  return;
3084
- return yield* Effect35.fail(new LxcRefusedError(adoptionRefusal(props, change.drift)));
3218
+ return yield* Effect38.fail(new LxcRefusedError(adoptionRefusal(props, change.drift)));
3085
3219
  });
3086
3220
 
3087
3221
  // src/proxmox/lxc.ts
3088
3222
  var ProxmoxLxc = Resource13("Proxmox.Lxc", { defaultRemovalPolicy: "retain" });
3089
- var refused = (reasons) => Effect36.fail(new LxcRefusedError(reasons.join(`
3223
+ var refused = (reasons) => Effect39.fail(new LxcRefusedError(reasons.join(`
3090
3224
  `)));
3091
- var diff = (owner, news, olds) => Effect36.gen(function* () {
3225
+ var diff = (owner, news, olds) => Effect39.gen(function* () {
3092
3226
  const { output } = owner;
3093
3227
  const identity2 = identityRefusals(news, olds, output);
3094
3228
  if (identity2.length > 0)
3095
3229
  return yield* refused(identity2);
3096
3230
  if (output === undefined)
3097
3231
  return;
3098
- if (!isResolved8(news))
3232
+ if (!isResolved10(news))
3099
3233
  return;
3100
3234
  const live = yield* readLive(news);
3101
3235
  if (live === undefined) {
3102
3236
  const refusals = createRefusals(news);
3103
3237
  if (refusals.length > 0)
3104
3238
  return yield* refused(refusals);
3105
- yield* Effect36.logWarning(`Proxmox.Lxc ${news.node}/${String(news.vmid)}: the cluster lists no guest with this ` + "vmid -- a deploy CREATES it again from ostemplate, with new, empty volumes.");
3239
+ yield* Effect39.logWarning(`Proxmox.Lxc ${news.node}/${String(news.vmid)}: the cluster lists no guest with this ` + "vmid -- a deploy CREATES it again from ostemplate, with new, empty volumes.");
3106
3240
  return { action: "update" };
3107
3241
  }
3108
3242
  const change = judge(news, live);
@@ -3113,10 +3247,10 @@ var diff = (owner, news, olds) => Effect36.gen(function* () {
3113
3247
  if (change.drift.length === 0 && !moved)
3114
3248
  return { action: "noop" };
3115
3249
  const what = change.drift.length === 0 ? `the guest is on ${news.node} now, not ${output.node} -- a deploy re-records it, ` + "writing nothing." : `live config differs from the declaration in ${change.drift.join(", ")} -- a ` + "deploy writes these.";
3116
- yield* Effect36.logWarning(`Proxmox.Lxc ${news.node}/${String(news.vmid)}: ${what}`);
3250
+ yield* Effect39.logWarning(`Proxmox.Lxc ${news.node}/${String(news.vmid)}: ${what}`);
3117
3251
  return { action: "update" };
3118
3252
  });
3119
- var reconcile = (owner, news) => Effect36.gen(function* () {
3253
+ var reconcile = (owner, news) => Effect39.gen(function* () {
3120
3254
  const { output } = owner;
3121
3255
  const identity2 = identityRefusals(news, news, output);
3122
3256
  if (identity2.length > 0)
@@ -3155,22 +3289,22 @@ var reconcile = (owner, news) => Effect36.gen(function* () {
3155
3289
  `CT ${String(news.vmid)}: after the write, ${left.join(", ")} still differ from the ` + "declaration. PVE may have normalised the value (tags are lower-cased by default) -- " + "declare what it stores."
3156
3290
  ]);
3157
3291
  }
3158
- return attributesOf4(news, after);
3292
+ return attributesOf5(news, after);
3159
3293
  });
3160
3294
  var whereOf = (olds, output) => ({
3161
3295
  node: output?.node ?? olds.node,
3162
3296
  target: olds.target,
3163
3297
  vmid: output?.vmid ?? olds.vmid
3164
3298
  });
3165
- var read = (owner, olds) => Effect36.gen(function* () {
3299
+ var read = (owner, olds) => Effect39.gen(function* () {
3166
3300
  const where = whereOf(olds, owner.output);
3167
3301
  const live = yield* readLive(where);
3168
3302
  if (live === undefined)
3169
3303
  return;
3170
- const settled2 = Effect36.sync(() => judge(olds, live).drift.length === 0);
3171
- return yield* ownedRead(owner, attributesOf4(where, live), settled2);
3304
+ const settled2 = Effect39.sync(() => judge(olds, live).drift.length === 0);
3305
+ return yield* ownedRead(owner, attributesOf5(where, live), settled2);
3172
3306
  });
3173
- var handlers8 = {
3307
+ var handlers7 = {
3174
3308
  delete: ({ olds, output }) => destroyGuest(whereOf(olds, output), olds),
3175
3309
  diff: ({
3176
3310
  fqn,
@@ -3179,7 +3313,7 @@ var handlers8 = {
3179
3313
  olds,
3180
3314
  output
3181
3315
  }) => diff({ fqn, instanceId, output }, news, olds),
3182
- list: () => Effect36.succeed([]),
3316
+ list: () => Effect39.succeed([]),
3183
3317
  read: ({
3184
3318
  fqn,
3185
3319
  instanceId,
@@ -3193,11 +3327,11 @@ var handlers8 = {
3193
3327
  output
3194
3328
  }) => reconcile({ fqn, instanceId, output }, news)
3195
3329
  };
3196
- var ProxmoxLxcProvider = () => Provider13.effect(ProxmoxLxc, Effect36.succeed(ProxmoxLxc.Provider.of(handlers8)).pipe(Effect36.map(provingResumes)));
3330
+ var ProxmoxLxcProvider = () => Provider13.effect(ProxmoxLxc, Effect39.succeed(ProxmoxLxc.Provider.of(handlers7)).pipe(Effect39.map(provingResumes)));
3197
3331
  // src/proxmox/metric-server.ts
3198
3332
  import { Resource as Resource14 } from "alchemy";
3199
3333
  import * as Provider14 from "alchemy/Provider";
3200
- import * as Effect37 from "effect/Effect";
3334
+ import * as Effect40 from "effect/Effect";
3201
3335
 
3202
3336
  // src/proxmox/metric-server-form.ts
3203
3337
  var UNSET2 = -1;
@@ -3277,7 +3411,7 @@ var matchesType = (attributes, props) => {
3277
3411
  return socket && attributes.path === (props.path ?? "");
3278
3412
  return socket && attributes.influxdbproto === (props.influxdbproto ?? "") && attributes.organization === (props.organization ?? "") && attributes.bucket === (props.bucket ?? "") && attributes["api-path-prefix"] === (props["api-path-prefix"] ?? "") && attributes["max-body-size"] === (props["max-body-size"] ?? UNSET2) && attributes["verify-certificate"] === (props["verify-certificate"] !== false);
3279
3413
  };
3280
- var handlers9 = pveHandlers({
3414
+ var handlers8 = pveHandlers({
3281
3415
  attributes: (live, props) => {
3282
3416
  const liveType = text(live["type"]);
3283
3417
  if (liveType !== "" && liveType !== props.type)
@@ -3310,12 +3444,12 @@ var handlers9 = pveHandlers({
3310
3444
  path: (props) => `cluster/metrics/server/${props.id}`,
3311
3445
  updateForm: update
3312
3446
  });
3313
- var ProxmoxMetricServerProvider = () => Provider14.effect(ProxmoxMetricServer, Effect37.succeed(ProxmoxMetricServer.Provider.of(handlers9)));
3447
+ var ProxmoxMetricServerProvider = () => Provider14.effect(ProxmoxMetricServer, Effect40.succeed(ProxmoxMetricServer.Provider.of(handlers8)));
3314
3448
  // src/proxmox/network-apply.ts
3315
3449
  import { Resource as Resource15 } from "alchemy";
3316
- import { isResolved as isResolved9 } from "alchemy/Diff";
3450
+ import { isResolved as isResolved11 } from "alchemy/Diff";
3317
3451
  import * as Provider15 from "alchemy/Provider";
3318
- import * as Effect38 from "effect/Effect";
3452
+ import * as Effect41 from "effect/Effect";
3319
3453
 
3320
3454
  // src/proxmox/apply-endpoints.ts
3321
3455
  var NETWORK_APPLY_ENDPOINT = "pve:PUT /nodes/{node}/network";
@@ -3325,15 +3459,15 @@ var guardSdnApply = guardForm(SDN_APPLY_ENDPOINT, {}, true);
3325
3459
 
3326
3460
  // src/proxmox/network-apply.ts
3327
3461
  var ProxmoxNetworkApply = Resource15("Proxmox.NetworkApply");
3328
- var read2 = (props) => pendingCount(props.target, props.node).pipe(Effect38.map((pending) => ({ node: props.node, pending })));
3329
- var diff2 = (news) => Effect38.gen(function* () {
3330
- if (!isResolved9(news))
3462
+ var read2 = (props) => pendingCount(props.target, props.node).pipe(Effect41.map((pending) => ({ node: props.node, pending })));
3463
+ var diff2 = (news) => Effect41.gen(function* () {
3464
+ if (!isResolved11(news))
3331
3465
  return;
3332
3466
  const { pending } = yield* read2(news);
3333
3467
  return pending === 0 ? { action: "noop" } : { action: "update" };
3334
3468
  });
3335
- var refuse = (node, why) => Effect38.die(new Error(`Proxmox.NetworkApply ${node}: ${why}`));
3336
- var apply = (props) => Effect38.gen(function* () {
3469
+ var refuse = (node, why) => Effect41.die(new Error(`Proxmox.NetworkApply ${node}: ${why}`));
3470
+ var apply = (props) => Effect41.gen(function* () {
3337
3471
  const node = props.node;
3338
3472
  const staged = yield* pendingCount(props.target, node);
3339
3473
  if (staged === 0)
@@ -3362,20 +3496,20 @@ var apply = (props) => Effect38.gen(function* () {
3362
3496
  }
3363
3497
  return { node, pending: left };
3364
3498
  });
3365
- var handlers10 = {
3366
- delete: () => Effect38.void,
3499
+ var handlers9 = {
3500
+ delete: () => Effect41.void,
3367
3501
  diff: ({ news }) => diff2(news),
3368
- list: () => Effect38.succeed([]),
3502
+ list: () => Effect41.succeed([]),
3369
3503
  read: ({ olds }) => read2(olds),
3370
3504
  reconcile: ({ news }) => apply(news)
3371
3505
  };
3372
- var ProxmoxNetworkApplyProvider = () => Provider15.effect(ProxmoxNetworkApply, Effect38.succeed(ProxmoxNetworkApply.Provider.of(handlers10)));
3506
+ var ProxmoxNetworkApplyProvider = () => Provider15.effect(ProxmoxNetworkApply, Effect41.succeed(ProxmoxNetworkApply.Provider.of(handlers9)));
3373
3507
  // src/proxmox/node-network.ts
3374
3508
  import { Resource as Resource16 } from "alchemy";
3375
- import { isResolved as isResolved10 } from "alchemy/Diff";
3509
+ import { isResolved as isResolved12 } from "alchemy/Diff";
3376
3510
  import * as Provider16 from "alchemy/Provider";
3377
- import * as nodes2 from "@distilled.cloud/proxmox/nodes";
3378
- import * as Effect40 from "effect/Effect";
3511
+ import * as nodes9 from "@distilled.cloud/proxmox/nodes";
3512
+ import * as Effect43 from "effect/Effect";
3379
3513
 
3380
3514
  // src/proxmox/node-network-form.ts
3381
3515
  var NODE_NETWORK_CREATE = "pve:POST /nodes/{node}/network";
@@ -3417,9 +3551,9 @@ var updateForm2 = (props) => {
3417
3551
  };
3418
3552
 
3419
3553
  // src/proxmox/node-network-wire.ts
3420
- import * as nodes from "@distilled.cloud/proxmox/nodes";
3421
- import * as Effect39 from "effect/Effect";
3422
- var attributesOf5 = (live, props) => {
3554
+ import * as nodes8 from "@distilled.cloud/proxmox/nodes";
3555
+ import * as Effect42 from "effect/Effect";
3556
+ var attributesOf6 = (live, props) => {
3423
3557
  const data = live;
3424
3558
  const liveType = text(data["type"]);
3425
3559
  if (liveType !== "" && liveType !== props.type)
@@ -3452,16 +3586,16 @@ var attributesOf5 = (live, props) => {
3452
3586
  "vlan-raw-device": text(data["vlan-raw-device"])
3453
3587
  };
3454
3588
  };
3455
- var readInterfaceOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, nodes.getNodeNetwork({ iface: props.iface, node: props.node })).pipe(Effect39.catchTag("ParameterVerificationFailed", (error) => error.errors["iface"] === "interface does not exist" ? Effect39.succeed(undefined) : Effect39.fail(error)))).pipe(Effect39.map((live) => {
3589
+ var readInterfaceOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, nodes8.getNodeNetwork({ iface: props.iface, node: props.node })).pipe(Effect42.catchTag("ParameterVerificationFailed", (error) => error.errors["iface"] === "interface does not exist" ? Effect42.succeed(undefined) : Effect42.fail(error)))).pipe(Effect42.map((live) => {
3456
3590
  if (live === UNREADABLE)
3457
3591
  return UNREADABLE;
3458
- return live === undefined ? undefined : attributesOf5(live, props);
3592
+ return live === undefined ? undefined : attributesOf6(live, props);
3459
3593
  }));
3460
- var readInterface = (props) => readInterfaceOrFail(props).pipe(Effect39.orElseSucceed(() => {
3594
+ var readInterface = (props) => readInterfaceOrFail(props).pipe(Effect42.orElseSucceed(() => {
3461
3595
  return;
3462
3596
  }));
3463
3597
  var dropUnreadable4 = (live) => live === UNREADABLE ? undefined : live;
3464
- var matches4 = (attributes, props) => attributes.cidr === (props.cidr ?? "") && same2(props.gateway, attributes.gateway) && same2(props.autostart, attributes.autostart) && same2(props.mtu, attributes.mtu) && sameComment(props.comments, attributes.comments) && sameList(props.bridge_ports, attributes.bridge_ports) && sameList(props.bridge_vids, attributes.bridge_vids) && same2(props.bridge_vlan_aware, attributes.bridge_vlan_aware) && sameList(props.slaves, attributes.slaves) && same2(props.bond_mode, attributes.bond_mode) && same2(props.bond_xmit_hash_policy, attributes.bond_xmit_hash_policy) && same2(props["bond-primary"], attributes["bond-primary"]) && same2(props["vlan-id"], attributes["vlan-id"]) && same2(props["vlan-raw-device"], attributes["vlan-raw-device"]);
3598
+ var matches5 = (attributes, props) => attributes.cidr === (props.cidr ?? "") && same2(props.gateway, attributes.gateway) && same2(props.autostart, attributes.autostart) && same2(props.mtu, attributes.mtu) && sameComment(props.comments, attributes.comments) && sameList(props.bridge_ports, attributes.bridge_ports) && sameList(props.bridge_vids, attributes.bridge_vids) && same2(props.bridge_vlan_aware, attributes.bridge_vlan_aware) && sameList(props.slaves, attributes.slaves) && same2(props.bond_mode, attributes.bond_mode) && same2(props.bond_xmit_hash_policy, attributes.bond_xmit_hash_policy) && same2(props["bond-primary"], attributes["bond-primary"]) && same2(props["vlan-id"], attributes["vlan-id"]) && same2(props["vlan-raw-device"], attributes["vlan-raw-device"]);
3465
3599
 
3466
3600
  // src/proxmox/node-network.ts
3467
3601
  var ProxmoxNodeNetwork = Resource16("Proxmox.NodeNetwork", {
@@ -3473,22 +3607,22 @@ var RENAMED = {
3473
3607
  "vlan-raw-device": "vlan_raw_device"
3474
3608
  };
3475
3609
  var toDistilled = (form) => Object.fromEntries(Object.entries(form).map(([key, value]) => [RENAMED[key] ?? key, value]));
3476
- var toDistilledCreate = (props) => ({
3610
+ var toDistilledCreate3 = (props) => ({
3477
3611
  ...toDistilled(createForm5(props)),
3478
3612
  node: props.node
3479
3613
  });
3480
- var toDistilledUpdate = (props) => ({
3614
+ var toDistilledUpdate2 = (props) => ({
3481
3615
  ...toDistilled(updateForm2(props)),
3482
3616
  iface: props.iface,
3483
3617
  node: props.node
3484
3618
  });
3485
- var ProxmoxNodeNetworkProvider = () => Provider16.effect(ProxmoxNodeNetwork, Effect40.succeed(ProxmoxNodeNetwork.Provider.of({
3486
- list: () => Effect40.succeed([]),
3487
- read: Effect40.fn(function* ({ olds, output }) {
3619
+ var ProxmoxNodeNetworkProvider = () => Provider16.effect(ProxmoxNodeNetwork, Effect43.succeed(ProxmoxNodeNetwork.Provider.of({
3620
+ list: () => Effect43.succeed([]),
3621
+ read: Effect43.fn(function* ({ olds, output }) {
3488
3622
  return dropUnreadable4(yield* output === undefined ? readInterface(olds) : readInterfaceOrFail(olds));
3489
3623
  }),
3490
- diff: Effect40.fn(function* ({ news, output }) {
3491
- if (!isResolved10(news))
3624
+ diff: Effect43.fn(function* ({ news, output }) {
3625
+ if (!isResolved12(news))
3492
3626
  return;
3493
3627
  yield* guardWrite2(NODE_NETWORK_CREATE, createForm5(news), output === undefined);
3494
3628
  yield* guardWrite2(NODE_NETWORK_UPDATE, updateForm2(news), false);
@@ -3503,31 +3637,31 @@ var ProxmoxNodeNetworkProvider = () => Provider16.effect(ProxmoxNodeNetwork, Eff
3503
3637
  yield* guardWrite2(NODE_NETWORK_CREATE, createForm5(news), true);
3504
3638
  return { action: "update" };
3505
3639
  }
3506
- return matches4(live, news) ? { action: "noop" } : { action: "update" };
3640
+ return matches5(live, news) ? { action: "noop" } : { action: "update" };
3507
3641
  }),
3508
- reconcile: Effect40.fn(function* ({ news }) {
3642
+ reconcile: Effect43.fn(function* ({ news }) {
3509
3643
  const before = dropUnreadable4(yield* readInterface(news));
3510
3644
  yield* guardWrite2(NODE_NETWORK_CREATE, createForm5(news), before === undefined);
3511
3645
  yield* guardWrite2(NODE_NETWORK_UPDATE, updateForm2(news), false);
3512
3646
  if (before === undefined) {
3513
- yield* runPve(news.target, "provision", true, nodes2.createNodeNetwork(toDistilledCreate(news)));
3514
- } else if (!matches4(before, news)) {
3515
- yield* runPve(news.target, "provision", true, nodes2.putNodeNetwork2(toDistilledUpdate(news)));
3647
+ yield* runPve(news.target, "provision", true, nodes9.createNodeNetwork(toDistilledCreate3(news)));
3648
+ } else if (!matches5(before, news)) {
3649
+ yield* runPve(news.target, "provision", true, nodes9.putNodeNetwork2(toDistilledUpdate2(news)));
3516
3650
  }
3517
3651
  const after = dropUnreadable4(yield* readInterface(news));
3518
3652
  if (after === undefined) {
3519
- return yield* Effect40.die(new Error(`nodes/${news.node}/network/${news.iface}: wrote with no error, but the ` + 'interface is still absent -- PVE wraps every answer in {"data":...} and can ' + "report success on a call that did nothing, so read back rather than trust it."));
3653
+ return yield* Effect43.die(new Error(`nodes/${news.node}/network/${news.iface}: wrote with no error, but the ` + 'interface is still absent -- PVE wraps every answer in {"data":...} and can ' + "report success on a call that did nothing, so read back rather than trust it."));
3520
3654
  }
3521
3655
  return after;
3522
3656
  }),
3523
- delete: Effect40.fn(function* ({ olds }) {
3524
- yield* runPve(olds.target, "provision", true, nodes2.deleteNodeNetwork2({ iface: olds.iface, node: olds.node }));
3657
+ delete: Effect43.fn(function* ({ olds }) {
3658
+ yield* runPve(olds.target, "provision", true, nodes9.deleteNodeNetwork2({ iface: olds.iface, node: olds.node }));
3525
3659
  })
3526
3660
  })));
3527
3661
  // src/proxmox/notification-matcher.ts
3528
3662
  import { Resource as Resource17 } from "alchemy";
3529
3663
  import * as Provider17 from "alchemy/Provider";
3530
- import * as Effect41 from "effect/Effect";
3664
+ import * as Effect44 from "effect/Effect";
3531
3665
 
3532
3666
  // src/proxmox/notification-matcher-form.ts
3533
3667
  var list = (value) => Array.isArray(value) ? value.map((item) => String(item)) : [];
@@ -3605,7 +3739,7 @@ var matcherUpdateForm = (fields) => {
3605
3739
 
3606
3740
  // src/proxmox/notification-matcher.ts
3607
3741
  var ProxmoxNotificationMatcher = Resource17("Proxmox.NotificationMatcher");
3608
- var handlers11 = pveHandlers({
3742
+ var handlers10 = pveHandlers({
3609
3743
  attributes: (live, props) => matcherAttributes(live, props.name),
3610
3744
  collection: () => "cluster/notifications/matchers",
3611
3745
  createForm: matcherCreateForm,
@@ -3617,11 +3751,11 @@ var handlers11 = pveHandlers({
3617
3751
  path: (props) => `cluster/notifications/matchers/${props.name}`,
3618
3752
  updateForm: matcherUpdateForm
3619
3753
  });
3620
- var ProxmoxNotificationMatcherProvider = () => Provider17.effect(ProxmoxNotificationMatcher, Effect41.succeed(ProxmoxNotificationMatcher.Provider.of(handlers11)));
3754
+ var ProxmoxNotificationMatcherProvider = () => Provider17.effect(ProxmoxNotificationMatcher, Effect44.succeed(ProxmoxNotificationMatcher.Provider.of(handlers10)));
3621
3755
  // src/proxmox/notification-target.ts
3622
3756
  import { Resource as Resource18 } from "alchemy";
3623
3757
  import * as Provider18 from "alchemy/Provider";
3624
- import * as Effect42 from "effect/Effect";
3758
+ import * as Effect45 from "effect/Effect";
3625
3759
 
3626
3760
  // src/proxmox/notification-target-endpoint.ts
3627
3761
  var ENDPOINTS = {
@@ -3677,7 +3811,7 @@ var createShape = (props) => ({
3677
3811
 
3678
3812
  // src/proxmox/notification-target.ts
3679
3813
  var ProxmoxNotificationTarget = Resource18("Proxmox.NotificationTarget");
3680
- var handlers12 = pveHandlers({
3814
+ var handlers11 = pveHandlers({
3681
3815
  attributes: (live, props) => ({
3682
3816
  author: text(live["author"]),
3683
3817
  body: text(live["body"]),
@@ -3703,15 +3837,15 @@ var handlers12 = pveHandlers({
3703
3837
  path: (props) => `cluster/notifications/endpoints/${props.type}/${props.name}`,
3704
3838
  updateForm: shape4
3705
3839
  });
3706
- var ProxmoxNotificationTargetProvider = () => Provider18.effect(ProxmoxNotificationTarget, Effect42.succeed(ProxmoxNotificationTarget.Provider.of(handlers12)));
3840
+ var ProxmoxNotificationTargetProvider = () => Provider18.effect(ProxmoxNotificationTarget, Effect45.succeed(ProxmoxNotificationTarget.Provider.of(handlers11)));
3707
3841
  // src/proxmox/pbs-datastore.ts
3708
3842
  import { Resource as Resource19 } from "alchemy";
3709
- import { isResolved as isResolved11 } from "alchemy/Diff";
3843
+ import { isResolved as isResolved13 } from "alchemy/Diff";
3710
3844
  import * as Provider19 from "alchemy/Provider";
3711
- import * as Effect46 from "effect/Effect";
3845
+ import * as Effect49 from "effect/Effect";
3712
3846
 
3713
3847
  // src/proxmox/pbs-datastore-form.ts
3714
- import * as Effect43 from "effect/Effect";
3848
+ import * as Effect46 from "effect/Effect";
3715
3849
  var attributes = (live, props) => ({
3716
3850
  backend: propertyString(live["backend"]),
3717
3851
  comment: text(live["comment"]),
@@ -3734,7 +3868,7 @@ var attributes = (live, props) => ({
3734
3868
  "verify-new": bool(live["verify-new"])
3735
3869
  });
3736
3870
  var same4 = (declared, live) => declared === undefined || declared === live;
3737
- var matches5 = (live, props) => same4(props.comment, live.comment) && same4(props["gc-schedule"]?.trim(), live["gc-schedule"]) && same4(props["prune-schedule"]?.trim(), live["prune-schedule"]) && same4(props["keep-last"], live["keep-last"]) && same4(props["keep-hourly"], live["keep-hourly"]) && same4(props["keep-daily"], live["keep-daily"]) && same4(props["keep-weekly"], live["keep-weekly"]) && same4(props["keep-monthly"], live["keep-monthly"]) && same4(props["keep-yearly"], live["keep-yearly"]) && same4(props["notify-user"], live["notify-user"]) && same4(props["counter-reset-schedule"]?.trim(), live["counter-reset-schedule"]) && (props["notification-thresholds"] === undefined || propertyString(props["notification-thresholds"]) === live["notification-thresholds"]) && same4(props["verify-new"], live["verify-new"]) && (props.notify === undefined || propertyString(props.notify) === live.notify) && (props.tuning === undefined || propertyString(props.tuning) === live.tuning) && (props["maintenance-mode"] === undefined || propertyString(props["maintenance-mode"], "type") === live["maintenance-mode"]);
3871
+ var matches6 = (live, props) => same4(props.comment, live.comment) && same4(props["gc-schedule"]?.trim(), live["gc-schedule"]) && same4(props["prune-schedule"]?.trim(), live["prune-schedule"]) && same4(props["keep-last"], live["keep-last"]) && same4(props["keep-hourly"], live["keep-hourly"]) && same4(props["keep-daily"], live["keep-daily"]) && same4(props["keep-weekly"], live["keep-weekly"]) && same4(props["keep-monthly"], live["keep-monthly"]) && same4(props["keep-yearly"], live["keep-yearly"]) && same4(props["notify-user"], live["notify-user"]) && same4(props["counter-reset-schedule"]?.trim(), live["counter-reset-schedule"]) && (props["notification-thresholds"] === undefined || propertyString(props["notification-thresholds"]) === live["notification-thresholds"]) && same4(props["verify-new"], live["verify-new"]) && (props.notify === undefined || propertyString(props.notify) === live.notify) && (props.tuning === undefined || propertyString(props.tuning) === live.tuning) && (props["maintenance-mode"] === undefined || propertyString(props["maintenance-mode"], "type") === live["maintenance-mode"]);
3738
3872
  var set2 = (key, value) => value === undefined ? {} : { [key]: value };
3739
3873
  var count = (value) => value === undefined ? undefined : String(value);
3740
3874
  var mutable = (props) => ({
@@ -3763,35 +3897,35 @@ var createForm6 = (props) => ({
3763
3897
  });
3764
3898
  var updateForm3 = (props) => mutable(props);
3765
3899
  var object2 = (props) => `config/datastore/${props.name}`;
3766
- var readOne = (props) => pve(props.target, "read", "GET", object2(props)).pipe(Effect43.map((live) => live === undefined || typeof live["name"] !== "string" ? undefined : attributes(live, props)), Effect43.orElseSucceed(() => {
3900
+ var readOne = (props) => pve(props.target, "read", "GET", object2(props)).pipe(Effect46.map((live) => live === undefined || typeof live["name"] !== "string" ? undefined : attributes(live, props)), Effect46.orElseSucceed(() => {
3767
3901
  return;
3768
3902
  }));
3769
3903
 
3770
3904
  // src/proxmox/pbs-datastore-guard.ts
3771
- import * as Effect44 from "effect/Effect";
3905
+ import * as Effect47 from "effect/Effect";
3772
3906
  var samePath = (left, right) => {
3773
3907
  const trim = (value) => value.length > 1 ? value.replace(/\/+$/, "") : value;
3774
3908
  return trim(left) === trim(right);
3775
3909
  };
3776
- var guardPath = (live, props) => live.path === "" || samePath(live.path, props.path) ? Effect44.void : Effect44.die(new Error(`${object2(props)}: declared path ${props.path} but PBS holds ${live.path}. \`path\` ` + "is create-only, so this cannot be reconciled and will NOT be planned as a silent " + "noop: backups would keep landing in the old directory behind a green plan. Correct " + "the declaration, or remove the datastore and declare a new one -- the contents live, " + "because `destroy-data` is never sent."));
3777
- var guardBackend = (live, props) => props.backend === undefined || propertyString(props.backend) === live.backend ? Effect44.void : Effect44.die(new Error(`${object2(props)}: declared backend ${props.backend} but PBS holds ` + `${live.backend === "" ? "(none — a local datastore)" : live.backend}. \`backend\` ` + "is create-only: PBS has no update for it, so this cannot be reconciled and will NOT " + "be planned as a silent noop. Correct the declaration to match what is really there, " + "or remove the datastore and declare a new one -- the contents live, because " + "`destroy-data` is never sent."));
3778
- var settle3 = (read3, done) => Effect44.gen(function* () {
3910
+ var guardPath = (live, props) => live.path === "" || samePath(live.path, props.path) ? Effect47.void : Effect47.die(new Error(`${object2(props)}: declared path ${props.path} but PBS holds ${live.path}. \`path\` ` + "is create-only, so this cannot be reconciled and will NOT be planned as a silent " + "noop: backups would keep landing in the old directory behind a green plan. Correct " + "the declaration, or remove the datastore and declare a new one -- the contents live, " + "because `destroy-data` is never sent."));
3911
+ var guardBackend = (live, props) => props.backend === undefined || propertyString(props.backend) === live.backend ? Effect47.void : Effect47.die(new Error(`${object2(props)}: declared backend ${props.backend} but PBS holds ` + `${live.backend === "" ? "(none — a local datastore)" : live.backend}. \`backend\` ` + "is create-only: PBS has no update for it, so this cannot be reconciled and will NOT " + "be planned as a silent noop. Correct the declaration to match what is really there, " + "or remove the datastore and declare a new one -- the contents live, because " + "`destroy-data` is never sent."));
3912
+ var settle3 = (read3, done) => Effect47.gen(function* () {
3779
3913
  for (let attempt = 0;attempt < 60; attempt += 1) {
3780
3914
  const live = yield* read3;
3781
3915
  if (done(live))
3782
3916
  return live;
3783
- yield* Effect44.sleep("2 seconds");
3917
+ yield* Effect47.sleep("2 seconds");
3784
3918
  }
3785
3919
  return yield* read3;
3786
3920
  });
3787
3921
 
3788
3922
  // src/proxmox/pbs-datastore-endpoint.ts
3789
- import * as Effect45 from "effect/Effect";
3923
+ import * as Effect48 from "effect/Effect";
3790
3924
  var DATASTORE_ENDPOINT = {
3791
3925
  create: "pbs:POST /config/datastore",
3792
3926
  update: "pbs:PUT /config/datastore/{name}"
3793
3927
  };
3794
- var guardDatastoreForms = (props) => Effect45.gen(function* () {
3928
+ var guardDatastoreForms = (props) => Effect48.gen(function* () {
3795
3929
  yield* guardForm(DATASTORE_ENDPOINT.create, createForm6(props), true);
3796
3930
  yield* guardForm(DATASTORE_ENDPOINT.update, updateForm3(props), false);
3797
3931
  });
@@ -3800,11 +3934,11 @@ var guardDatastoreForms = (props) => Effect45.gen(function* () {
3800
3934
  var PbsDatastore = Resource19("Pbs.Datastore", {
3801
3935
  defaultRemovalPolicy: "retain"
3802
3936
  });
3803
- var PbsDatastoreProvider = () => Provider19.effect(PbsDatastore, Effect46.succeed(PbsDatastore.Provider.of({
3804
- list: () => Effect46.succeed([]),
3937
+ var PbsDatastoreProvider = () => Provider19.effect(PbsDatastore, Effect49.succeed(PbsDatastore.Provider.of({
3938
+ list: () => Effect49.succeed([]),
3805
3939
  read: ({ olds }) => readOne(olds),
3806
- diff: ({ news, output }) => Effect46.gen(function* () {
3807
- if (!isResolved11(news))
3940
+ diff: ({ news, output }) => Effect49.gen(function* () {
3941
+ if (!isResolved13(news))
3808
3942
  return;
3809
3943
  yield* guardDatastoreForms(news);
3810
3944
  if (output === undefined)
@@ -3814,9 +3948,9 @@ var PbsDatastoreProvider = () => Provider19.effect(PbsDatastore, Effect46.succee
3814
3948
  return { action: "update" };
3815
3949
  yield* guardPath(live, news);
3816
3950
  yield* guardBackend(live, news);
3817
- return matches5(live, news) ? { action: "noop" } : { action: "update" };
3951
+ return matches6(live, news) ? { action: "noop" } : { action: "update" };
3818
3952
  }),
3819
- reconcile: Effect46.fn(function* ({ news }) {
3953
+ reconcile: Effect49.fn(function* ({ news }) {
3820
3954
  yield* guardDatastoreForms(news);
3821
3955
  const live = yield* readOne(news);
3822
3956
  let upid;
@@ -3825,31 +3959,31 @@ var PbsDatastoreProvider = () => Provider19.effect(PbsDatastore, Effect46.succee
3825
3959
  } else {
3826
3960
  yield* guardPath(live, news);
3827
3961
  yield* guardBackend(live, news);
3828
- const form = formToSend(matches5, live, news, updateForm3(news));
3962
+ const form = formToSend(matches6, live, news, updateForm3(news));
3829
3963
  if (form !== undefined) {
3830
3964
  yield* pve(news.target, "provision", "PUT", object2(news), form);
3831
3965
  }
3832
3966
  }
3833
- const after = yield* settle3(readOne(news), (row) => row !== undefined && matches5(row, news));
3834
- if (after === undefined || !matches5(after, news)) {
3835
- return yield* Effect46.die(new Error(`${object2(news)}: the write returned no error but the datastore still does not ` + `match the declaration after 120s. PBS answered with task ${upid ?? "(none)"} ` + "-- read it with `proxmox-backup-manager task log <upid>`. A slow disk is a " + "plausible cause (see `settle`); a create over an existing chunk store is not, " + "because PBS refuses that outright rather than timing out."));
3967
+ const after = yield* settle3(readOne(news), (row) => row !== undefined && matches6(row, news));
3968
+ if (after === undefined || !matches6(after, news)) {
3969
+ return yield* Effect49.die(new Error(`${object2(news)}: the write returned no error but the datastore still does not ` + `match the declaration after 120s. PBS answered with task ${upid ?? "(none)"} ` + "-- read it with `proxmox-backup-manager task log <upid>`. A slow disk is a " + "plausible cause (see `settle`); a create over an existing chunk store is not, " + "because PBS refuses that outright rather than timing out."));
3836
3970
  }
3837
3971
  return after;
3838
3972
  }),
3839
- delete: Effect46.fn(function* ({ olds }) {
3973
+ delete: Effect49.fn(function* ({ olds }) {
3840
3974
  yield* pve(olds.target, "provision", "DELETE", object2(olds));
3841
3975
  const left = yield* settle3(readOne(olds), (row) => row === undefined);
3842
3976
  if (left !== undefined) {
3843
- return yield* Effect46.die(new Error(`${object2(olds)}: the DELETE returned no error but the datastore is still in ` + "datastore.cfg after 120s. Either a backup, verify or GC task still holds it, " + "or the provision role lacks Datastore.Allocate on /datastore/" + `${olds.name}. Read the task log with \`proxmox-backup-manager task log <upid>\`.`));
3977
+ return yield* Effect49.die(new Error(`${object2(olds)}: the DELETE returned no error but the datastore is still in ` + "datastore.cfg after 120s. Either a backup, verify or GC task still holds it, " + "or the provision role lacks Datastore.Allocate on /datastore/" + `${olds.name}. Read the task log with \`proxmox-backup-manager task log <upid>\`.`));
3844
3978
  }
3845
3979
  })
3846
3980
  })));
3847
3981
  // src/proxmox/pbs-notification-matcher.ts
3848
3982
  import { Resource as Resource20 } from "alchemy";
3849
3983
  import * as Provider20 from "alchemy/Provider";
3850
- import * as Effect47 from "effect/Effect";
3984
+ import * as Effect50 from "effect/Effect";
3851
3985
  var PbsNotificationMatcher = Resource20("Pbs.NotificationMatcher");
3852
- var handlers13 = pveHandlers({
3986
+ var handlers12 = pveHandlers({
3853
3987
  attributes: (live, props) => matcherAttributes(live, props.name),
3854
3988
  collection: () => "config/notifications/matchers",
3855
3989
  createForm: matcherCreateForm,
@@ -3861,15 +3995,15 @@ var handlers13 = pveHandlers({
3861
3995
  path: (props) => `config/notifications/matchers/${props.name}`,
3862
3996
  updateForm: matcherUpdateForm
3863
3997
  });
3864
- var PbsNotificationMatcherProvider = () => Provider20.effect(PbsNotificationMatcher, Effect47.succeed(PbsNotificationMatcher.Provider.of(handlers13)));
3998
+ var PbsNotificationMatcherProvider = () => Provider20.effect(PbsNotificationMatcher, Effect50.succeed(PbsNotificationMatcher.Provider.of(handlers12)));
3865
3999
  // src/proxmox/pbs-notification-target.ts
3866
4000
  import { Resource as Resource21 } from "alchemy";
3867
4001
  import * as Provider21 from "alchemy/Provider";
3868
- import * as Effect49 from "effect/Effect";
4002
+ import * as Effect52 from "effect/Effect";
3869
4003
 
3870
4004
  // src/proxmox/pbs-notification-target-lifecycle.ts
3871
- import { isResolved as isResolved12 } from "alchemy/Diff";
3872
- import * as Effect48 from "effect/Effect";
4005
+ import { isResolved as isResolved14 } from "alchemy/Diff";
4006
+ import * as Effect51 from "effect/Effect";
3873
4007
 
3874
4008
  // src/proxmox/pbs-notification-target-endpoint.ts
3875
4009
  var ENDPOINTS2 = {
@@ -4146,12 +4280,12 @@ var targetForm = (props, groups, carry, mode) => {
4146
4280
 
4147
4281
  // src/proxmox/pbs-notification-target-lifecycle.ts
4148
4282
  var path = (props) => `config/notifications/endpoints/${props.type}/${props.name}`;
4149
- var readLive2 = (props) => pve(props.target, "read", "GET", path(props)).pipe(Effect48.map((data) => data == null ? undefined : targetAttributes(data, props)), Effect48.orElseSucceed(() => {
4283
+ var readLive2 = (props) => pve(props.target, "read", "GET", path(props)).pipe(Effect51.map((data) => data == null ? undefined : targetAttributes(data, props)), Effect51.orElseSucceed(() => {
4150
4284
  return;
4151
4285
  }));
4152
4286
  var refuse2 = (props) => {
4153
4287
  const reasons = refusals(props);
4154
- return reasons.length === 0 ? Effect48.void : Effect48.die(new Error(`${path(props)}: ${reasons.join("; ")}.`));
4288
+ return reasons.length === 0 ? Effect51.void : Effect51.die(new Error(`${path(props)}: ${reasons.join("; ")}.`));
4155
4289
  };
4156
4290
  var toCarry = (live, props, groups, sealed) => {
4157
4291
  const header = headerState(live, props, groups) === "stale";
@@ -4163,17 +4297,17 @@ var requireValues = (props, groups, carry) => {
4163
4297
  ...carry.header ? groups.header.missing : [],
4164
4298
  ...carry.sealed ? groups.sealed.missing : []
4165
4299
  ];
4166
- return missing.length === 0 ? Effect48.void : Effect48.die(new Error(`${path(props)}: this write must send write-only values, and ${missing.join(", ")} ` + "is unset or empty in the deploying environment. Export it and deploy again."));
4300
+ return missing.length === 0 ? Effect51.void : Effect51.die(new Error(`${path(props)}: this write must send write-only values, and ${missing.join(", ")} ` + "is unset or empty in the deploying environment. Export it and deploy again."));
4167
4301
  };
4168
- var handlers14 = {
4169
- list: () => Effect48.succeed([]),
4170
- read: ({ olds, output }) => (output === undefined ? refuse2(olds) : Effect48.void).pipe(Effect48.andThen(readLive2(olds)), Effect48.map((live) => live === undefined ? undefined : { ...live, sealed: output?.sealed ?? "" })),
4302
+ var handlers13 = {
4303
+ list: () => Effect51.succeed([]),
4304
+ read: ({ olds, output }) => (output === undefined ? refuse2(olds) : Effect51.void).pipe(Effect51.andThen(readLive2(olds)), Effect51.map((live) => live === undefined ? undefined : { ...live, sealed: output?.sealed ?? "" })),
4171
4305
  diff: ({
4172
4306
  news,
4173
4307
  olds,
4174
4308
  output
4175
- }) => Effect48.gen(function* () {
4176
- if (output === undefined || !isResolved12(news))
4309
+ }) => Effect51.gen(function* () {
4310
+ if (output === undefined || !isResolved14(news))
4177
4311
  return;
4178
4312
  if (olds !== undefined && (olds.type !== news.type || olds.name !== news.name)) {
4179
4313
  return { action: "replace", deleteFirst: olds.name === news.name };
@@ -4184,7 +4318,7 @@ var handlers14 = {
4184
4318
  return { action: "update" };
4185
4319
  return toCarry(live, news, resolveGroups(news), output.sealed) === undefined ? { action: "noop" } : { action: "update" };
4186
4320
  }),
4187
- reconcile: ({ news, output }) => Effect48.gen(function* () {
4321
+ reconcile: ({ news, output }) => Effect51.gen(function* () {
4188
4322
  yield* refuse2(news);
4189
4323
  const groups = resolveGroups(news);
4190
4324
  const live = yield* readLive2(news);
@@ -4192,10 +4326,10 @@ var handlers14 = {
4192
4326
  if (live === undefined) {
4193
4327
  const carry = { header: true, sealed: true };
4194
4328
  yield* requireValues(news, groups, carry);
4195
- const collection2 = `config/notifications/endpoints/${news.type}`;
4329
+ const collection = `config/notifications/endpoints/${news.type}`;
4196
4330
  const form = targetForm(news, groups, carry, "create");
4197
4331
  yield* guardForm(pbsTargetEndpoint(news).create, form, true);
4198
- yield* pve(news.target, "provision", "POST", collection2, form);
4332
+ yield* pve(news.target, "provision", "POST", collection, form);
4199
4333
  sealed = seal(groups.sealed.values);
4200
4334
  } else {
4201
4335
  const carry = toCarry(live, news, groups, sealed);
@@ -4210,7 +4344,7 @@ var handlers14 = {
4210
4344
  }
4211
4345
  const after = yield* readLive2(news);
4212
4346
  if (after === undefined) {
4213
- return yield* Effect48.die(new Error(`${path(news)}: the write returned no error but the target is still absent.`));
4347
+ return yield* Effect51.die(new Error(`${path(news)}: the write returned no error but the target is still absent.`));
4214
4348
  }
4215
4349
  return { ...after, sealed };
4216
4350
  }),
@@ -4219,11 +4353,11 @@ var handlers14 = {
4219
4353
 
4220
4354
  // src/proxmox/pbs-notification-target.ts
4221
4355
  var PbsNotificationTarget = Resource21("Pbs.NotificationTarget");
4222
- var PbsNotificationTargetProvider = () => Provider21.effect(PbsNotificationTarget, Effect49.succeed(PbsNotificationTarget.Provider.of(handlers14)));
4356
+ var PbsNotificationTargetProvider = () => Provider21.effect(PbsNotificationTarget, Effect52.succeed(PbsNotificationTarget.Provider.of(handlers13)));
4223
4357
  // src/proxmox/pbs-prune-job.ts
4224
4358
  import { Resource as Resource22 } from "alchemy";
4225
4359
  import * as Provider22 from "alchemy/Provider";
4226
- import * as Effect50 from "effect/Effect";
4360
+ import * as Effect53 from "effect/Effect";
4227
4361
 
4228
4362
  // src/proxmox/pbs-prune-job-form.ts
4229
4363
  var KEEP_KEYS = [
@@ -4281,7 +4415,7 @@ var updateBody2 = (props) => {
4281
4415
  // src/proxmox/pbs-prune-job.ts
4282
4416
  var PbsPruneJob = Resource22("Pbs.PruneJob");
4283
4417
  var same6 = (declared2, live) => declared2 === undefined || declared2 === live;
4284
- var handlers15 = pveHandlers({
4418
+ var handlers14 = pveHandlers({
4285
4419
  attributes: (live, props) => ({
4286
4420
  comment: text(live["comment"], ""),
4287
4421
  disable: bool(live["disable"], false),
@@ -4299,11 +4433,11 @@ var handlers15 = pveHandlers({
4299
4433
  path: (props) => `config/prune/${props.id}`,
4300
4434
  updateForm: updateBody2
4301
4435
  });
4302
- var PbsPruneJobProvider = () => Provider22.effect(PbsPruneJob, Effect50.succeed(PbsPruneJob.Provider.of(handlers15)));
4436
+ var PbsPruneJobProvider = () => Provider22.effect(PbsPruneJob, Effect53.succeed(PbsPruneJob.Provider.of(handlers14)));
4303
4437
  // src/proxmox/pbs-sync-job.ts
4304
4438
  import { Resource as Resource23 } from "alchemy";
4305
4439
  import * as Provider23 from "alchemy/Provider";
4306
- import * as Effect51 from "effect/Effect";
4440
+ import * as Effect54 from "effect/Effect";
4307
4441
 
4308
4442
  // src/proxmox/pbs-sync-job-form.ts
4309
4443
  var UNSET4 = -1;
@@ -4351,7 +4485,7 @@ var createBody4 = (props) => ({
4351
4485
  ...props["sync-direction"] === undefined ? {} : { "sync-direction": props["sync-direction"] }
4352
4486
  });
4353
4487
  var updateBody3 = (props) => shape6(props);
4354
- var handlers16 = pveHandlers({
4488
+ var handlers15 = pveHandlers({
4355
4489
  attributes: (live, props) => ({
4356
4490
  comment: text(live["comment"], ""),
4357
4491
  "group-filter": filters(live["group-filter"]),
@@ -4380,11 +4514,11 @@ var handlers16 = pveHandlers({
4380
4514
 
4381
4515
  // src/proxmox/pbs-sync-job.ts
4382
4516
  var PbsSyncJob = Resource23("Pbs.SyncJob");
4383
- var PbsSyncJobProvider = () => Provider23.effect(PbsSyncJob, Effect51.succeed(PbsSyncJob.Provider.of(handlers16)));
4517
+ var PbsSyncJobProvider = () => Provider23.effect(PbsSyncJob, Effect54.succeed(PbsSyncJob.Provider.of(handlers15)));
4384
4518
  // src/proxmox/pbs-verify-job.ts
4385
4519
  import { Resource as Resource24 } from "alchemy";
4386
4520
  import * as Provider24 from "alchemy/Provider";
4387
- import * as Effect52 from "effect/Effect";
4521
+ import * as Effect55 from "effect/Effect";
4388
4522
 
4389
4523
  // src/proxmox/pbs-verify-job-form.ts
4390
4524
  var rechecks = (ignoreVerified, outdatedAfter) => {
@@ -4406,7 +4540,7 @@ var shape7 = (props) => ({
4406
4540
 
4407
4541
  // src/proxmox/pbs-verify-job.ts
4408
4542
  var PbsVerifyJob = Resource24("Pbs.VerifyJob");
4409
- var handlers17 = pveHandlers({
4543
+ var handlers16 = pveHandlers({
4410
4544
  attributes: (live, props) => {
4411
4545
  const ignoreVerified = bool(live["ignore-verified"], true);
4412
4546
  const outdatedAfter = int(live["outdated-after"], -1);
@@ -4429,11 +4563,11 @@ var handlers17 = pveHandlers({
4429
4563
  path: (props) => `config/verify/${props.id}`,
4430
4564
  updateForm: shape7
4431
4565
  });
4432
- var PbsVerifyJobProvider = () => Provider24.effect(PbsVerifyJob, Effect52.succeed(PbsVerifyJob.Provider.of(handlers17)));
4566
+ var PbsVerifyJobProvider = () => Provider24.effect(PbsVerifyJob, Effect55.succeed(PbsVerifyJob.Provider.of(handlers16)));
4433
4567
  // src/proxmox/pool.ts
4434
4568
  import { Resource as Resource25 } from "alchemy";
4435
4569
  import * as Provider25 from "alchemy/Provider";
4436
- import * as Effect53 from "effect/Effect";
4570
+ import * as Effect56 from "effect/Effect";
4437
4571
  var ProxmoxPool = Resource25("Proxmox.Pool");
4438
4572
  var poolCreateForm = (props) => ({
4439
4573
  comment: props.comment ?? "",
@@ -4442,7 +4576,7 @@ var poolCreateForm = (props) => ({
4442
4576
  var poolUpdateForm = (props) => ({
4443
4577
  comment: props.comment ?? ""
4444
4578
  });
4445
- var handlers18 = pveHandlers({
4579
+ var handlers17 = pveHandlers({
4446
4580
  attributes: (live, props) => {
4447
4581
  const row = live;
4448
4582
  return {
@@ -4458,7 +4592,7 @@ var handlers18 = pveHandlers({
4458
4592
  path: (props) => `pools/${props.poolid}`,
4459
4593
  updateForm: poolUpdateForm
4460
4594
  });
4461
- var ProxmoxPoolProvider = () => Provider25.effect(ProxmoxPool, Effect53.succeed(ProxmoxPool.Provider.of(handlers18)));
4595
+ var ProxmoxPoolProvider = () => Provider25.effect(ProxmoxPool, Effect56.succeed(ProxmoxPool.Provider.of(handlers17)));
4462
4596
  // src/proxmox/provision-baseline.ts
4463
4597
  var PROVISION_PRIVILEGES = Object.freeze([
4464
4598
  "Datastore.Allocate",
@@ -4651,14 +4785,14 @@ echo 'provision baseline: done. Next: point the OpenBao proxmox mount at these u
4651
4785
  // src/proxmox/provision-declare.ts
4652
4786
  import { adopt } from "alchemy/AdoptPolicy";
4653
4787
  import * as RemovalPolicy from "alchemy/RemovalPolicy";
4654
- import * as Effect57 from "effect/Effect";
4788
+ import * as Effect60 from "effect/Effect";
4655
4789
 
4656
4790
  // src/proxmox/role.ts
4657
4791
  import { Resource as Resource26 } from "alchemy";
4658
- import { isResolved as isResolved13 } from "alchemy/Diff";
4792
+ import { isResolved as isResolved15 } from "alchemy/Diff";
4659
4793
  import * as Provider26 from "alchemy/Provider";
4660
4794
  import * as access5 from "@distilled.cloud/proxmox/access";
4661
- import * as Effect54 from "effect/Effect";
4795
+ import * as Effect57 from "effect/Effect";
4662
4796
 
4663
4797
  // src/proxmox/role-wire.ts
4664
4798
  var ROLE_CREATE = "pve:POST /access/roles";
@@ -4673,28 +4807,28 @@ var updateForm4 = (props) => ({
4673
4807
  roleid: props.roleid
4674
4808
  });
4675
4809
  var find2 = (rows, roleid) => rows.find((row) => row.roleid === roleid);
4676
- var attributesOf6 = (row, props) => ({
4810
+ var attributesOf7 = (row, props) => ({
4677
4811
  privs: canonical2(row.privs === undefined ? [] : row.privs.split(",")),
4678
4812
  roleid: props.roleid
4679
4813
  });
4680
- var matches6 = (attributes2, props) => canonical2(attributes2.privs).join(",") === canonical2(props.privs).join(",");
4814
+ var matches7 = (attributes2, props) => canonical2(attributes2.privs).join(",") === canonical2(props.privs).join(",");
4681
4815
 
4682
4816
  // src/proxmox/role.ts
4683
4817
  var ProxmoxRole = Resource26("Proxmox.Role");
4684
- var readRole = (props) => readOrUnreadable(runPve(props.target, "read", false, access5.listAccessRoles({}))).pipe(Effect54.map((rows) => {
4818
+ var readRole = (props) => readOrUnreadable(runPve(props.target, "read", false, access5.listAccessRoles({}))).pipe(Effect57.map((rows) => {
4685
4819
  if (rows === UNREADABLE)
4686
4820
  return UNREADABLE;
4687
4821
  const row = find2(rows, props.roleid);
4688
- return row === undefined ? undefined : attributesOf6(row, props);
4822
+ return row === undefined ? undefined : attributesOf7(row, props);
4689
4823
  }));
4690
4824
  var dropUnreadable5 = (live) => live === UNREADABLE ? undefined : live;
4691
- var ProxmoxRoleProvider = () => Provider26.effect(ProxmoxRole, Effect54.succeed(ProxmoxRole.Provider.of({
4692
- list: () => Effect54.succeed([]),
4693
- read: Effect54.fn(function* ({ olds }) {
4825
+ var ProxmoxRoleProvider = () => Provider26.effect(ProxmoxRole, Effect57.succeed(ProxmoxRole.Provider.of({
4826
+ list: () => Effect57.succeed([]),
4827
+ read: Effect57.fn(function* ({ olds }) {
4694
4828
  return dropUnreadable5(yield* readRole(olds));
4695
4829
  }),
4696
- diff: Effect54.fn(function* ({ news, output }) {
4697
- if (!isResolved13(news))
4830
+ diff: Effect57.fn(function* ({ news, output }) {
4831
+ if (!isResolved15(news))
4698
4832
  return;
4699
4833
  yield* guardWrite2(ROLE_CREATE, createForm7(news), output === undefined);
4700
4834
  yield* guardWrite2(ROLE_UPDATE, updateForm4(news), false);
@@ -4709,38 +4843,38 @@ var ProxmoxRoleProvider = () => Provider26.effect(ProxmoxRole, Effect54.succeed(
4709
4843
  yield* guardWrite2(ROLE_CREATE, createForm7(news), true);
4710
4844
  return { action: "update" };
4711
4845
  }
4712
- return matches6(live, news) ? { action: "noop" } : { action: "update" };
4846
+ return matches7(live, news) ? { action: "noop" } : { action: "update" };
4713
4847
  }),
4714
- reconcile: Effect54.fn(function* ({ news }) {
4848
+ reconcile: Effect57.fn(function* ({ news }) {
4715
4849
  const before = dropUnreadable5(yield* readRole(news));
4716
4850
  yield* guardWrite2(ROLE_CREATE, createForm7(news), before === undefined);
4717
4851
  yield* guardWrite2(ROLE_UPDATE, updateForm4(news), false);
4718
4852
  if (before === undefined) {
4719
4853
  yield* runPve(news.target, "provision", true, access5.createAccessRole(createForm7(news)));
4720
- } else if (!matches6(before, news)) {
4854
+ } else if (!matches7(before, news)) {
4721
4855
  yield* runPve(news.target, "provision", true, access5.putAccessRole(updateForm4(news)));
4722
4856
  }
4723
4857
  const after = dropUnreadable5(yield* readRole(news));
4724
4858
  if (after === undefined) {
4725
- return yield* Effect54.die(new Error(`access/roles/${news.roleid}: the write returned no error but the role 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."));
4859
+ return yield* Effect57.die(new Error(`access/roles/${news.roleid}: the write returned no error but the role 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."));
4726
4860
  }
4727
4861
  return after;
4728
4862
  }),
4729
- delete: Effect54.fn(function* ({ olds }) {
4863
+ delete: Effect57.fn(function* ({ olds }) {
4730
4864
  yield* runPve(olds.target, "provision", true, access5.deleteAccessRole({ roleid: olds.roleid }));
4731
4865
  })
4732
4866
  })));
4733
4867
 
4734
4868
  // src/proxmox/user.ts
4735
4869
  import { Resource as Resource27 } from "alchemy";
4736
- import { isResolved as isResolved14 } from "alchemy/Diff";
4870
+ import { isResolved as isResolved16 } from "alchemy/Diff";
4737
4871
  import * as Provider27 from "alchemy/Provider";
4738
4872
  import * as access7 from "@distilled.cloud/proxmox/access";
4739
- import * as Effect56 from "effect/Effect";
4873
+ import * as Effect59 from "effect/Effect";
4740
4874
 
4741
4875
  // src/proxmox/user-wire.ts
4742
4876
  import * as access6 from "@distilled.cloud/proxmox/access";
4743
- import * as Effect55 from "effect/Effect";
4877
+ import * as Effect58 from "effect/Effect";
4744
4878
  var USER_CREATE = "pve:POST /access/users";
4745
4879
  var USER_UPDATE = "pve:PUT /access/users/{userid}";
4746
4880
  var int2 = (value) => {
@@ -4770,7 +4904,7 @@ var updateForm5 = (props) => ({
4770
4904
  ...shape8(props),
4771
4905
  userid: props.userid
4772
4906
  });
4773
- var attributesOf7 = (live, props) => ({
4907
+ var attributesOf8 = (live, props) => ({
4774
4908
  comment: text(live.comment),
4775
4909
  email: text(live.email),
4776
4910
  enable: bool(live.enable, true),
@@ -4781,22 +4915,22 @@ var attributesOf7 = (live, props) => ({
4781
4915
  tokens: tokenNames(live.tokens),
4782
4916
  userid: props.userid
4783
4917
  });
4784
- var matches7 = (attributes2, props) => attributes2.comment === (props.comment ?? "") && attributes2.email === (props.email ?? "") && attributes2.enable === (props.enable !== false) && attributes2.expire === (props.expire ?? 0) && attributes2.firstname === (props.firstname ?? "") && attributes2.lastname === (props.lastname ?? "") && attributes2.groups.join(",") === groupSet(props.groups).join(",");
4785
- var readUserOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, access6.getAccessUser({ userid: props.userid }))).pipe(Effect55.map((live) => live === UNREADABLE ? UNREADABLE : attributesOf7(live, props)));
4786
- var readUser = (props) => readUserOrFail(props).pipe(Effect55.orElseSucceed(() => {
4918
+ var matches8 = (attributes2, props) => attributes2.comment === (props.comment ?? "") && attributes2.email === (props.email ?? "") && attributes2.enable === (props.enable !== false) && attributes2.expire === (props.expire ?? 0) && attributes2.firstname === (props.firstname ?? "") && attributes2.lastname === (props.lastname ?? "") && attributes2.groups.join(",") === groupSet(props.groups).join(",");
4919
+ var readUserOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, access6.getAccessUser({ userid: props.userid }))).pipe(Effect58.map((live) => live === UNREADABLE ? UNREADABLE : attributesOf8(live, props)));
4920
+ var readUser = (props) => readUserOrFail(props).pipe(Effect58.orElseSucceed(() => {
4787
4921
  return;
4788
4922
  }));
4789
4923
  var dropUnreadable6 = (live) => live === UNREADABLE ? undefined : live;
4790
4924
 
4791
4925
  // src/proxmox/user.ts
4792
4926
  var ProxmoxUser = Resource27("Proxmox.User");
4793
- var ProxmoxUserProvider = () => Provider27.effect(ProxmoxUser, Effect56.succeed(ProxmoxUser.Provider.of({
4794
- list: () => Effect56.succeed([]),
4795
- read: Effect56.fn(function* ({ olds, output }) {
4927
+ var ProxmoxUserProvider = () => Provider27.effect(ProxmoxUser, Effect59.succeed(ProxmoxUser.Provider.of({
4928
+ list: () => Effect59.succeed([]),
4929
+ read: Effect59.fn(function* ({ olds, output }) {
4796
4930
  return dropUnreadable6(yield* output === undefined ? readUser(olds) : readUserOrFail(olds));
4797
4931
  }),
4798
- diff: Effect56.fn(function* ({ news, output }) {
4799
- if (!isResolved14(news))
4932
+ diff: Effect59.fn(function* ({ news, output }) {
4933
+ if (!isResolved16(news))
4800
4934
  return;
4801
4935
  yield* guardWrite2(USER_CREATE, createForm8(news), output === undefined);
4802
4936
  yield* guardWrite2(USER_UPDATE, updateForm5(news), false);
@@ -4811,31 +4945,31 @@ var ProxmoxUserProvider = () => Provider27.effect(ProxmoxUser, Effect56.succeed(
4811
4945
  yield* guardWrite2(USER_CREATE, createForm8(news), true);
4812
4946
  return { action: "update" };
4813
4947
  }
4814
- return matches7(live, news) ? { action: "noop" } : { action: "update" };
4948
+ return matches8(live, news) ? { action: "noop" } : { action: "update" };
4815
4949
  }),
4816
- reconcile: Effect56.fn(function* ({ news }) {
4950
+ reconcile: Effect59.fn(function* ({ news }) {
4817
4951
  const before = dropUnreadable6(yield* readUser(news));
4818
4952
  yield* guardWrite2(USER_CREATE, createForm8(news), before === undefined);
4819
4953
  yield* guardWrite2(USER_UPDATE, updateForm5(news), false);
4820
4954
  if (before === undefined) {
4821
4955
  yield* runPve(news.target, "provision", true, access7.createAccessUser(createForm8(news)));
4822
- } else if (!matches7(before, news)) {
4956
+ } else if (!matches8(before, news)) {
4823
4957
  yield* runPve(news.target, "provision", true, access7.putAccessUser(updateForm5(news)));
4824
4958
  }
4825
4959
  const after = dropUnreadable6(yield* readUser(news));
4826
4960
  if (after === undefined) {
4827
- return yield* Effect56.die(new Error(`access/users/${news.userid}: the write returned no error but the account 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."));
4961
+ return yield* Effect59.die(new Error(`access/users/${news.userid}: the write returned no error but the account 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."));
4828
4962
  }
4829
4963
  return after;
4830
4964
  }),
4831
- delete: Effect56.fn(function* ({ olds }) {
4965
+ delete: Effect59.fn(function* ({ olds }) {
4832
4966
  yield* runPve(olds.target, "provision", true, access7.deleteAccessUser({ userid: olds.userid }));
4833
4967
  })
4834
4968
  })));
4835
4969
 
4836
4970
  // src/proxmox/provision-declare.ts
4837
- var declareProvisionBaseline = (id, target, names2 = {}, options = {}) => Effect57.gen(function* () {
4838
- const baseline = yield* Effect57.try({
4971
+ var declareProvisionBaseline = (id, target, names2 = {}, options = {}) => Effect60.gen(function* () {
4972
+ const baseline = yield* Effect60.try({
4839
4973
  catch: (cause) => cause instanceof Error ? cause : new Error(String(cause)),
4840
4974
  try: () => provisionBaseline(names2)
4841
4975
  });
@@ -4849,13 +4983,13 @@ var declareProvisionBaseline = (id, target, names2 = {}, options = {}) => Effect
4849
4983
  target
4850
4984
  }));
4851
4985
  const group = yield* owned(ProxmoxGroup(`${id}-mint-group`, { ...baseline.group, target }));
4852
- const users = yield* Effect57.all(baseline.users.map((user) => owned(ProxmoxUser(`${id}-${user.lane}-user`, {
4986
+ const users = yield* Effect60.all(baseline.users.map((user) => owned(ProxmoxUser(`${id}-${user.lane}-user`, {
4853
4987
  comment: user.comment,
4854
4988
  groups: [...user.groups],
4855
4989
  target,
4856
4990
  userid: user.userid
4857
4991
  }))));
4858
- const grants = yield* Effect57.all(baseline.grants.map((grant) => owned(ProxmoxAcl(`${id}-${grant.lane}-grant`, {
4992
+ const grants = yield* Effect60.all(baseline.grants.map((grant) => owned(ProxmoxAcl(`${id}-${grant.lane}-grant`, {
4859
4993
  path: "/",
4860
4994
  propagate: true,
4861
4995
  roleid: grant.roleid,
@@ -4868,7 +5002,7 @@ var declareProvisionBaseline = (id, target, names2 = {}, options = {}) => Effect
4868
5002
  // src/proxmox/qemu.ts
4869
5003
  import { Resource as Resource28 } from "alchemy";
4870
5004
  import * as Provider28 from "alchemy/Provider";
4871
- import * as Effect58 from "effect/Effect";
5005
+ import * as Effect61 from "effect/Effect";
4872
5006
  var ProxmoxVm = Resource28("Proxmox.Vm");
4873
5007
  var createForm9 = (props) => ({ ...shape9(props), vmid: String(props.vmid) });
4874
5008
  var shape9 = (props) => ({
@@ -4879,7 +5013,7 @@ var shape9 = (props) => ({
4879
5013
  sockets: String(props.sockets ?? 1),
4880
5014
  ...props.net0 === undefined ? {} : { net0: props.net0 }
4881
5015
  });
4882
- var handlers19 = pveHandlers({
5016
+ var handlers18 = pveHandlers({
4883
5017
  attributes: (live, props) => ({
4884
5018
  cores: num(live["cores"], 1),
4885
5019
  memory: num(live["memory"], 512),
@@ -4899,11 +5033,11 @@ var handlers19 = pveHandlers({
4899
5033
  path: (props) => `nodes/${props.node}/qemu/${String(props.vmid)}/config`,
4900
5034
  updateForm: shape9
4901
5035
  });
4902
- var ProxmoxVmProvider = () => Provider28.effect(ProxmoxVm, Effect58.succeed(ProxmoxVm.Provider.of(handlers19)));
5036
+ var ProxmoxVmProvider = () => Provider28.effect(ProxmoxVm, Effect61.succeed(ProxmoxVm.Provider.of(handlers18)));
4903
5037
  // src/proxmox/replication-job.ts
4904
5038
  import { Resource as Resource29 } from "alchemy";
4905
5039
  import * as Provider29 from "alchemy/Provider";
4906
- import * as Effect59 from "effect/Effect";
5040
+ import * as Effect62 from "effect/Effect";
4907
5041
 
4908
5042
  // src/proxmox/replication-job-form.ts
4909
5043
  var DEFAULT_SCHEDULE = "*/15";
@@ -4933,7 +5067,7 @@ var rateOf = (value) => {
4933
5067
  const parsed = Number.parseFloat(text(value));
4934
5068
  return Number.isFinite(parsed) ? parsed : 0;
4935
5069
  };
4936
- var handlers20 = pveHandlers({
5070
+ var handlers19 = pveHandlers({
4937
5071
  attributes: (live, props) => ({
4938
5072
  comment: text(live["comment"], ""),
4939
5073
  disable: bool(live["disable"], false),
@@ -4957,15 +5091,15 @@ var handlers20 = pveHandlers({
4957
5091
  path: (props) => `cluster/replication/${jobId(props)}`,
4958
5092
  updateForm: updateBody4
4959
5093
  });
4960
- var ProxmoxReplicationJobProvider = () => Provider29.effect(ProxmoxReplicationJob, Effect59.succeed(ProxmoxReplicationJob.Provider.of(handlers20)));
5094
+ var ProxmoxReplicationJobProvider = () => Provider29.effect(ProxmoxReplicationJob, Effect62.succeed(ProxmoxReplicationJob.Provider.of(handlers19)));
4961
5095
  // src/proxmox/sdn-apply.ts
4962
5096
  import { Resource as Resource30 } from "alchemy";
4963
- import { isResolved as isResolved15 } from "alchemy/Diff";
5097
+ import { isResolved as isResolved17 } from "alchemy/Diff";
4964
5098
  import * as Provider30 from "alchemy/Provider";
4965
- import * as Effect61 from "effect/Effect";
5099
+ import * as Effect64 from "effect/Effect";
4966
5100
 
4967
5101
  // src/proxmox/sdn-apply-read.ts
4968
- import * as Effect60 from "effect/Effect";
5102
+ import * as Effect63 from "effect/Effect";
4969
5103
  var MARKED = [
4970
5104
  "cluster/sdn/zones",
4971
5105
  "cluster/sdn/vnets",
@@ -4974,7 +5108,7 @@ var MARKED = [
4974
5108
  "cluster/sdn/route-maps"
4975
5109
  ];
4976
5110
  var subsystemAbsent = (error) => error instanceof PveError && error.status === 501;
4977
- var markedPending = (target) => Effect60.all(MARKED.map((collection2) => pve(target, "read", "GET", `${collection2}?pending=1`).pipe(Effect60.map((rows) => (rows ?? []).filter((row) => row.state !== undefined).length), Effect60.catchIf(subsystemAbsent, () => Effect60.succeed(0)))), { concurrency: "unbounded" }).pipe(Effect60.map((counts) => counts.reduce((total, count2) => total + count2, 0)));
5111
+ var markedPending = (target) => Effect63.all(MARKED.map((collection) => pve(target, "read", "GET", `${collection}?pending=1`).pipe(Effect63.map((rows) => (rows ?? []).filter((row) => row.state !== undefined).length), Effect63.catchIf(subsystemAbsent, () => Effect63.succeed(0)))), { concurrency: "unbounded" }).pipe(Effect63.map((counts) => counts.reduce((total, count2) => total + count2, 0)));
4978
5112
  var fabricStaged = (staged, running) => {
4979
5113
  if (staged === undefined && running === undefined)
4980
5114
  return 0;
@@ -4982,9 +5116,9 @@ var fabricStaged = (staged, running) => {
4982
5116
  return "inconsistent";
4983
5117
  return staged === running ? 0 : 1;
4984
5118
  };
4985
- var fabricPending = (target) => Effect60.all(["pending", "running"].map((view) => pve(target, "read", "GET", `cluster/sdn/fabrics/all?${view}=1`).pipe(Effect60.map(canonical3), Effect60.catchIf(subsystemAbsent, () => Effect60.succeed(undefined)))), { concurrency: "unbounded" }).pipe(Effect60.flatMap(([staged, running]) => {
5119
+ var fabricPending = (target) => Effect63.all(["pending", "running"].map((view) => pve(target, "read", "GET", `cluster/sdn/fabrics/all?${view}=1`).pipe(Effect63.map(canonical3), Effect63.catchIf(subsystemAbsent, () => Effect63.succeed(undefined)))), { concurrency: "unbounded" }).pipe(Effect63.flatMap(([staged, running]) => {
4986
5120
  const verdict = fabricStaged(staged, running);
4987
- return verdict === "inconsistent" ? Effect60.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.")) : Effect60.succeed(verdict);
5121
+ return verdict === "inconsistent" ? Effect63.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.")) : Effect63.succeed(verdict);
4988
5122
  }));
4989
5123
  var canonical3 = (value) => JSON.stringify(sortDeep(value));
4990
5124
  var sortDeep = (value) => {
@@ -4997,23 +5131,23 @@ var sortDeep = (value) => {
4997
5131
  }
4998
5132
  return value;
4999
5133
  };
5000
- var sdnPendingCount = (target) => Effect60.all([markedPending(target), fabricPending(target)], { concurrency: "unbounded" }).pipe(Effect60.map(([marked, fabric]) => marked + fabric));
5134
+ var sdnPendingCount = (target) => Effect63.all([markedPending(target), fabricPending(target)], { concurrency: "unbounded" }).pipe(Effect63.map(([marked, fabric]) => marked + fabric));
5001
5135
 
5002
5136
  // src/proxmox/sdn-apply.ts
5003
5137
  var ProxmoxSdnApply = Resource30("Proxmox.SdnApply");
5004
- var read3 = (props) => sdnPendingCount(props.target).pipe(Effect61.map((pending) => ({ pending })));
5005
- var ProxmoxSdnApplyProvider = () => Provider30.effect(ProxmoxSdnApply, Effect61.succeed(ProxmoxSdnApply.Provider.of({
5006
- list: () => Effect61.succeed([]),
5007
- read: Effect61.fn(function* ({ olds }) {
5138
+ var read3 = (props) => sdnPendingCount(props.target).pipe(Effect64.map((pending) => ({ pending })));
5139
+ var ProxmoxSdnApplyProvider = () => Provider30.effect(ProxmoxSdnApply, Effect64.succeed(ProxmoxSdnApply.Provider.of({
5140
+ list: () => Effect64.succeed([]),
5141
+ read: Effect64.fn(function* ({ olds }) {
5008
5142
  return yield* read3(olds);
5009
5143
  }),
5010
- diff: Effect61.fn(function* ({ news }) {
5011
- if (!isResolved15(news))
5144
+ diff: Effect64.fn(function* ({ news }) {
5145
+ if (!isResolved17(news))
5012
5146
  return;
5013
5147
  const { pending } = yield* read3(news);
5014
5148
  return pending === 0 ? { action: "noop" } : { action: "update" };
5015
5149
  }),
5016
- reconcile: Effect61.fn(function* ({ news }) {
5150
+ reconcile: Effect64.fn(function* ({ news }) {
5017
5151
  const staged = yield* read3(news);
5018
5152
  if (staged.pending === 0)
5019
5153
  return staged;
@@ -5021,16 +5155,16 @@ var ProxmoxSdnApplyProvider = () => Provider30.effect(ProxmoxSdnApply, Effect61.
5021
5155
  yield* pve(news.target, "provision", "PUT", "cluster/sdn");
5022
5156
  const after = yield* read3(news);
5023
5157
  if (after.pending !== 0) {
5024
- return yield* Effect61.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."));
5158
+ return yield* Effect64.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."));
5025
5159
  }
5026
5160
  return after;
5027
5161
  }),
5028
- delete: () => Effect61.void
5162
+ delete: () => Effect64.void
5029
5163
  })));
5030
5164
  // src/proxmox/sdn-subnet.ts
5031
5165
  import { Resource as Resource31 } from "alchemy";
5032
5166
  import * as Provider31 from "alchemy/Provider";
5033
- import * as Effect62 from "effect/Effect";
5167
+ import * as Effect65 from "effect/Effect";
5034
5168
 
5035
5169
  // src/proxmox/sdn-subnet-form.ts
5036
5170
  var subnetId = (props) => `${props.zone}-${props.cidr.replace("/", "-")}`;
@@ -5061,7 +5195,7 @@ var updateForm6 = (props) => {
5061
5195
 
5062
5196
  // src/proxmox/sdn-subnet.ts
5063
5197
  var ProxmoxSdnSubnet = Resource31("Proxmox.SdnSubnet");
5064
- var handlers21 = pveHandlers({
5198
+ var handlers20 = pveHandlers({
5065
5199
  attributes: (live, props) => {
5066
5200
  const liveVnet = text(live["vnet"]);
5067
5201
  if (liveVnet !== "" && liveVnet !== props.vnet)
@@ -5090,11 +5224,11 @@ var handlers21 = pveHandlers({
5090
5224
  path: (props) => `cluster/sdn/vnets/${props.vnet}/subnets/${subnetId(props)}`,
5091
5225
  updateForm: updateForm6
5092
5226
  });
5093
- var ProxmoxSdnSubnetProvider = () => Provider31.effect(ProxmoxSdnSubnet, Effect62.succeed(ProxmoxSdnSubnet.Provider.of(handlers21)));
5227
+ var ProxmoxSdnSubnetProvider = () => Provider31.effect(ProxmoxSdnSubnet, Effect65.succeed(ProxmoxSdnSubnet.Provider.of(handlers20)));
5094
5228
  // src/proxmox/sdn-vnet.ts
5095
5229
  import { Resource as Resource32 } from "alchemy";
5096
5230
  import * as Provider32 from "alchemy/Provider";
5097
- import * as Effect63 from "effect/Effect";
5231
+ import * as Effect66 from "effect/Effect";
5098
5232
  var ProxmoxSdnVnet = Resource32("Proxmox.SdnVnet");
5099
5233
  var tagOf = (value) => typeof value === "number" ? value : undefined;
5100
5234
  var shape11 = (props) => {
@@ -5114,7 +5248,7 @@ var updateForm7 = (props) => {
5114
5248
  ];
5115
5249
  return withClears(shape11(props), unset2);
5116
5250
  };
5117
- var handlers22 = pveHandlers({
5251
+ var handlers21 = pveHandlers({
5118
5252
  readRole: "provision",
5119
5253
  attributes: (live, props) => ({
5120
5254
  alias: typeof live["alias"] === "string" ? live["alias"] : "",
@@ -5132,11 +5266,11 @@ var handlers22 = pveHandlers({
5132
5266
  path: (props) => `cluster/sdn/vnets/${props.vnet}`,
5133
5267
  updateForm: updateForm7
5134
5268
  });
5135
- var ProxmoxSdnVnetProvider = () => Provider32.effect(ProxmoxSdnVnet, Effect63.succeed(ProxmoxSdnVnet.Provider.of(handlers22)));
5269
+ var ProxmoxSdnVnetProvider = () => Provider32.effect(ProxmoxSdnVnet, Effect66.succeed(ProxmoxSdnVnet.Provider.of(handlers21)));
5136
5270
  // src/proxmox/sdn-zone.ts
5137
5271
  import { Resource as Resource33 } from "alchemy";
5138
5272
  import * as Provider33 from "alchemy/Provider";
5139
- import * as Effect64 from "effect/Effect";
5273
+ import * as Effect67 from "effect/Effect";
5140
5274
  var ProxmoxSdnZone = Resource33("Proxmox.SdnZone");
5141
5275
  var sameIpam = (live, declared2) => (live === "" ? "pve" : live) === (declared2 === undefined || declared2 === "" ? "pve" : declared2);
5142
5276
  var body6 = (props) => ({
@@ -5157,7 +5291,7 @@ var clearable = {
5157
5291
  vlan: ["dns", "dnszone", "ipam", "mtu", "nodes"],
5158
5292
  vxlan: ["dns", "dnszone", "ipam", "mtu", "nodes"]
5159
5293
  };
5160
- var handlers23 = pveHandlers({
5294
+ var handlers22 = pveHandlers({
5161
5295
  readRole: "provision",
5162
5296
  attributes: (live, props) => {
5163
5297
  const liveType = text(live["type"]);
@@ -5189,13 +5323,13 @@ var handlers23 = pveHandlers({
5189
5323
  return withClears(fields, clear);
5190
5324
  }
5191
5325
  });
5192
- var ProxmoxSdnZoneProvider = () => Provider33.effect(ProxmoxSdnZone, Effect64.succeed(ProxmoxSdnZone.Provider.of(handlers23)));
5326
+ var ProxmoxSdnZoneProvider = () => Provider33.effect(ProxmoxSdnZone, Effect67.succeed(ProxmoxSdnZone.Provider.of(handlers22)));
5193
5327
  // src/proxmox/storage.ts
5194
5328
  import { Resource as Resource34 } from "alchemy";
5195
- import { isResolved as isResolved16 } from "alchemy/Diff";
5329
+ import { isResolved as isResolved18 } from "alchemy/Diff";
5196
5330
  import * as Provider34 from "alchemy/Provider";
5197
5331
  import * as storage2 from "@distilled.cloud/proxmox/storage";
5198
- import * as Effect66 from "effect/Effect";
5332
+ import * as Effect69 from "effect/Effect";
5199
5333
 
5200
5334
  // src/proxmox/storage-form.ts
5201
5335
  var STORAGE_CREATE = "pve:POST /storage";
@@ -5222,17 +5356,17 @@ var updateForm8 = (props) => ({
5222
5356
  ...mutable2(props),
5223
5357
  storage: props.storage
5224
5358
  });
5225
- var toDistilledCreate2 = (props) => underscored(createForm11(props));
5226
- var toDistilledUpdate2 = (props) => underscored(updateForm8(props));
5359
+ var toDistilledCreate4 = (props) => underscored(createForm11(props));
5360
+ var toDistilledUpdate3 = (props) => underscored(updateForm8(props));
5227
5361
 
5228
5362
  // src/proxmox/storage-wire.ts
5229
5363
  import * as storage from "@distilled.cloud/proxmox/storage";
5230
- import * as Effect65 from "effect/Effect";
5364
+ import * as Effect68 from "effect/Effect";
5231
5365
  var str2 = (value, fallback = "") => typeof value === "string" ? value : fallback;
5232
5366
  var tokens = (value) => value.split(",").map((part) => part.trim()).filter((part) => part !== "").sort().join(",");
5233
5367
  var sameList2 = (declared2, live) => declared2 === undefined || tokens(declared2) === tokens(live);
5234
5368
  var same7 = (declared2, live) => declared2 === undefined || declared2 === live;
5235
- var attributesOf8 = (live, props) => {
5369
+ var attributesOf9 = (live, props) => {
5236
5370
  const data = live;
5237
5371
  return {
5238
5372
  comment: str2(data["comment"]),
@@ -5246,24 +5380,24 @@ var attributesOf8 = (live, props) => {
5246
5380
  type: str2(data["type"], props.type)
5247
5381
  };
5248
5382
  };
5249
- var readStorageOrFail = (props) => readOrUnreadable(runPve(props.target, "provision", false, storage.getStorage({ storage: props.storage }))).pipe(Effect65.map((live) => live === UNREADABLE ? UNREADABLE : attributesOf8(live, props)));
5250
- var readStorage = (props) => readStorageOrFail(props).pipe(Effect65.orElseSucceed(() => {
5383
+ var readStorageOrFail = (props) => readOrUnreadable(runPve(props.target, "provision", false, storage.getStorage({ storage: props.storage }))).pipe(Effect68.map((live) => live === UNREADABLE ? UNREADABLE : attributesOf9(live, props)));
5384
+ var readStorage = (props) => readStorageOrFail(props).pipe(Effect68.orElseSucceed(() => {
5251
5385
  return;
5252
5386
  }));
5253
5387
  var dropUnreadable7 = (live) => live === UNREADABLE ? undefined : live;
5254
- var matches8 = (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);
5388
+ var matches9 = (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);
5255
5389
 
5256
5390
  // src/proxmox/storage.ts
5257
5391
  var ProxmoxStorage = Resource34("Proxmox.Storage", {
5258
5392
  defaultRemovalPolicy: "retain"
5259
5393
  });
5260
- var ProxmoxStorageProvider = () => Provider34.effect(ProxmoxStorage, Effect66.succeed(ProxmoxStorage.Provider.of({
5261
- list: () => Effect66.succeed([]),
5262
- read: Effect66.fn(function* ({ olds, output }) {
5394
+ var ProxmoxStorageProvider = () => Provider34.effect(ProxmoxStorage, Effect69.succeed(ProxmoxStorage.Provider.of({
5395
+ list: () => Effect69.succeed([]),
5396
+ read: Effect69.fn(function* ({ olds, output }) {
5263
5397
  return dropUnreadable7(yield* output === undefined ? readStorage(olds) : readStorageOrFail(olds));
5264
5398
  }),
5265
- diff: Effect66.fn(function* ({ news, output }) {
5266
- if (!isResolved16(news))
5399
+ diff: Effect69.fn(function* ({ news, output }) {
5400
+ if (!isResolved18(news))
5267
5401
  return;
5268
5402
  yield* guardWrite2(STORAGE_CREATE, createForm11(news), output === undefined);
5269
5403
  yield* guardWrite2(STORAGE_UPDATE, updateForm8(news), false);
@@ -5278,61 +5412,61 @@ var ProxmoxStorageProvider = () => Provider34.effect(ProxmoxStorage, Effect66.su
5278
5412
  yield* guardWrite2(STORAGE_CREATE, createForm11(news), true);
5279
5413
  return { action: "update" };
5280
5414
  }
5281
- return matches8(live, news) ? { action: "noop" } : { action: "update" };
5415
+ return matches9(live, news) ? { action: "noop" } : { action: "update" };
5282
5416
  }),
5283
- reconcile: Effect66.fn(function* ({ news }) {
5417
+ reconcile: Effect69.fn(function* ({ news }) {
5284
5418
  const before = dropUnreadable7(yield* readStorage(news));
5285
5419
  yield* guardWrite2(STORAGE_CREATE, createForm11(news), before === undefined);
5286
5420
  yield* guardWrite2(STORAGE_UPDATE, updateForm8(news), false);
5287
5421
  if (before === undefined) {
5288
- yield* runPve(news.target, "provision", true, storage2.createStorage(toDistilledCreate2(news)));
5289
- } else if (!matches8(before, news)) {
5290
- yield* runPve(news.target, "provision", true, storage2.putStorage(toDistilledUpdate2(news)));
5422
+ yield* runPve(news.target, "provision", true, storage2.createStorage(toDistilledCreate4(news)));
5423
+ } else if (!matches9(before, news)) {
5424
+ yield* runPve(news.target, "provision", true, storage2.putStorage(toDistilledUpdate3(news)));
5291
5425
  }
5292
5426
  const after = dropUnreadable7(yield* readStorage(news));
5293
5427
  if (after === undefined) {
5294
- return yield* Effect66.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."));
5428
+ return yield* Effect69.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."));
5295
5429
  }
5296
5430
  return after;
5297
5431
  }),
5298
- delete: Effect66.fn(function* ({ olds }) {
5432
+ delete: Effect69.fn(function* ({ olds }) {
5299
5433
  yield* runPve(olds.target, "provision", true, storage2.deleteStorage({ storage: olds.storage }));
5300
5434
  })
5301
5435
  })));
5302
5436
  // src/proxmox/zfs-pool.ts
5303
5437
  import { Resource as Resource35 } from "alchemy";
5304
- import { isResolved as isResolved17 } from "alchemy/Diff";
5438
+ import { isResolved as isResolved19 } from "alchemy/Diff";
5305
5439
  import * as Provider35 from "alchemy/Provider";
5306
- import * as Effect69 from "effect/Effect";
5440
+ import * as Effect72 from "effect/Effect";
5307
5441
 
5308
5442
  // src/proxmox/zfs-pool-wire.ts
5309
- import * as nodes3 from "@distilled.cloud/proxmox/nodes";
5310
- import * as Effect67 from "effect/Effect";
5443
+ import * as nodes10 from "@distilled.cloud/proxmox/nodes";
5444
+ import * as Effect70 from "effect/Effect";
5311
5445
  var leafDevices = (children) => Array.isArray(children) ? children.flatMap((entry) => {
5312
5446
  const vdev = entry;
5313
5447
  const nested = leafDevices(vdev.children);
5314
5448
  return nested.length > 0 ? nested : [text(vdev.name)].filter((name) => name !== "");
5315
5449
  }) : [];
5316
- var attributesOf9 = (live, props) => ({
5450
+ var attributesOf10 = (live, props) => ({
5317
5451
  devices: leafDevices(live.children).join(","),
5318
5452
  errors: text(live.errors, "unknown"),
5319
5453
  name: props.name,
5320
5454
  node: props.node,
5321
5455
  state: text(live.state, "unknown")
5322
5456
  });
5323
- var readPoolOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, nodes3.getNodeDiskZfs({ name: props.name, node: props.node }))).pipe(Effect67.map((live) => {
5457
+ var readPoolOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, nodes10.getNodeDiskZfs({ name: props.name, node: props.node }))).pipe(Effect70.map((live) => {
5324
5458
  if (live === UNREADABLE)
5325
5459
  return UNREADABLE;
5326
- return text(live.name) === "" ? undefined : attributesOf9(live, props);
5460
+ return text(live.name) === "" ? undefined : attributesOf10(live, props);
5327
5461
  }));
5328
- var readPool = (props) => readPoolOrFail(props).pipe(Effect67.orElseSucceed(() => {
5462
+ var readPool = (props) => readPoolOrFail(props).pipe(Effect70.orElseSucceed(() => {
5329
5463
  return;
5330
5464
  }));
5331
5465
  var dropUnreadable8 = (live) => live === UNREADABLE ? undefined : live;
5332
5466
 
5333
5467
  // src/proxmox/zfs-pool-form.ts
5334
- import * as Effect68 from "effect/Effect";
5335
- import * as nodes4 from "@distilled.cloud/proxmox/nodes";
5468
+ import * as Effect71 from "effect/Effect";
5469
+ import * as nodes11 from "@distilled.cloud/proxmox/nodes";
5336
5470
  var ZFS_POOL_CREATE = "pve:POST /nodes/{node}/disks/zfs";
5337
5471
  var zfsPoolCreateEndpoint = (props) => props.devices === undefined || props.raidlevel === undefined ? undefined : ZFS_POOL_CREATE;
5338
5472
  var createForm12 = (props) => ({
@@ -5343,7 +5477,7 @@ var createForm12 = (props) => ({
5343
5477
  ...props.compression === undefined ? {} : { compression: props.compression },
5344
5478
  ...props["draid-config"] === undefined ? {} : { "draid-config": props["draid-config"] }
5345
5479
  });
5346
- var toDistilledCreate3 = (props) => {
5480
+ var toDistilledCreate5 = (props) => {
5347
5481
  const form = createForm12(props);
5348
5482
  return {
5349
5483
  ...form,
@@ -5352,41 +5486,41 @@ var toDistilledCreate3 = (props) => {
5352
5486
  };
5353
5487
  };
5354
5488
  var SETTLE_ATTEMPTS = 30;
5355
- var createPool = (props, read4) => Effect68.gen(function* () {
5489
+ var createPool = (props, read4) => Effect71.gen(function* () {
5356
5490
  const existing = yield* read4(props);
5357
5491
  if (existing !== undefined)
5358
5492
  return existing;
5359
5493
  if (props.devices === undefined || props.raidlevel === undefined) {
5360
- return yield* Effect68.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."));
5494
+ return yield* Effect71.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."));
5361
5495
  }
5362
5496
  yield* guardForm(zfsPoolCreateEndpoint(props), asForm2(createForm12(props)), true);
5363
- const upid = yield* runPve(props.target, "provision", true, nodes4.createNodeDiskZfs(toDistilledCreate3(props)));
5364
- const settle4 = (attempts) => Effect68.gen(function* () {
5497
+ const upid = yield* runPve(props.target, "provision", true, nodes11.createNodeDiskZfs(toDistilledCreate5(props)));
5498
+ const settle4 = (attempts) => Effect71.gen(function* () {
5365
5499
  const live = yield* read4(props);
5366
5500
  if (live !== undefined || attempts <= 0)
5367
5501
  return live;
5368
- yield* Effect68.sleep("2 seconds");
5502
+ yield* Effect71.sleep("2 seconds");
5369
5503
  return yield* settle4(attempts - 1);
5370
5504
  });
5371
5505
  const after = yield* settle4(SETTLE_ATTEMPTS);
5372
5506
  if (after === undefined) {
5373
- return yield* Effect68.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."));
5507
+ return yield* Effect71.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."));
5374
5508
  }
5375
5509
  return after;
5376
5510
  });
5377
- var destroyPool = (props) => runPve(props.target, "provision", true, nodes4.deleteNodeDiskZfs({ name: props.name, node: props.node }));
5511
+ var destroyPool = (props) => runPve(props.target, "provision", true, nodes11.deleteNodeDiskZfs({ name: props.name, node: props.node }));
5378
5512
 
5379
5513
  // src/proxmox/zfs-pool.ts
5380
5514
  var ProxmoxZfsPool = Resource35("Proxmox.ZfsPool", {
5381
5515
  defaultRemovalPolicy: "retain"
5382
5516
  });
5383
- var ProxmoxZfsPoolProvider = () => Provider35.effect(ProxmoxZfsPool, Effect69.succeed(ProxmoxZfsPool.Provider.of({
5384
- list: () => Effect69.succeed([]),
5385
- read: Effect69.fn(function* ({ olds, output }) {
5517
+ var ProxmoxZfsPoolProvider = () => Provider35.effect(ProxmoxZfsPool, Effect72.succeed(ProxmoxZfsPool.Provider.of({
5518
+ list: () => Effect72.succeed([]),
5519
+ read: Effect72.fn(function* ({ olds, output }) {
5386
5520
  return dropUnreadable8(yield* output === undefined ? readPool(olds) : readPoolOrFail(olds));
5387
5521
  }),
5388
- diff: Effect69.fn(function* ({ news, output }) {
5389
- if (!isResolved17(news))
5522
+ diff: Effect72.fn(function* ({ news, output }) {
5523
+ if (!isResolved19(news))
5390
5524
  return;
5391
5525
  yield* guardForm(zfsPoolCreateEndpoint(news), asForm2(createForm12(news)), output === undefined);
5392
5526
  if (output === undefined)
@@ -5402,10 +5536,10 @@ var ProxmoxZfsPoolProvider = () => Provider35.effect(ProxmoxZfsPool, Effect69.su
5402
5536
  }
5403
5537
  return { action: "noop" };
5404
5538
  }),
5405
- reconcile: Effect69.fn(function* ({ news }) {
5406
- return yield* createPool(news, (props) => readPool(props).pipe(Effect69.map(dropUnreadable8)));
5539
+ reconcile: Effect72.fn(function* ({ news }) {
5540
+ return yield* createPool(news, (props) => readPool(props).pipe(Effect72.map(dropUnreadable8)));
5407
5541
  }),
5408
- delete: Effect69.fn(function* ({ olds }) {
5542
+ delete: Effect72.fn(function* ({ olds }) {
5409
5543
  yield* destroyPool(olds);
5410
5544
  })
5411
5545
  })));
@@ -5485,5 +5619,5 @@ export {
5485
5619
  violations
5486
5620
  };
5487
5621
 
5488
- //# debugId=AF866CF2F0A2718F64756E2164756E21
5622
+ //# debugId=483DD0A45E397D2364756E2164756E21
5489
5623
  //# sourceMappingURL=index.js.map