@homeflare/alchemy 0.31.1 → 0.32.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 (166) hide show
  1. package/README.md +44 -7
  2. package/dist/grafana/index.d.ts +6 -5
  3. package/dist/grafana/index.d.ts.map +1 -1
  4. package/dist/linux/container-form.d.ts +129 -0
  5. package/dist/linux/container-form.d.ts.map +1 -0
  6. package/dist/linux/container-generator.d.ts +74 -0
  7. package/dist/linux/container-generator.d.ts.map +1 -0
  8. package/dist/linux/container-handlers.d.ts +15 -0
  9. package/dist/linux/container-handlers.d.ts.map +1 -0
  10. package/dist/linux/container-lifecycle.d.ts +37 -0
  11. package/dist/linux/container-lifecycle.d.ts.map +1 -0
  12. package/dist/linux/container-preflight.d.ts +34 -0
  13. package/dist/linux/container-preflight.d.ts.map +1 -0
  14. package/dist/linux/container-secrets.d.ts +37 -0
  15. package/dist/linux/container-secrets.d.ts.map +1 -0
  16. package/dist/linux/container-settle.d.ts +34 -0
  17. package/dist/linux/container-settle.d.ts.map +1 -0
  18. package/dist/linux/container.d.ts +30 -0
  19. package/dist/linux/container.d.ts.map +1 -0
  20. package/dist/linux/fake-quadlet.d.ts +25 -0
  21. package/dist/linux/fake-quadlet.d.ts.map +1 -0
  22. package/dist/linux/index.d.ts +6 -3
  23. package/dist/linux/index.d.ts.map +1 -1
  24. package/dist/linux/index.js +641 -268
  25. package/dist/linux/index.js.map +15 -7
  26. package/dist/linux/providers.d.ts +1 -1
  27. package/dist/linux/providers.d.ts.map +1 -1
  28. package/dist/linux/systemctl.d.ts +7 -1
  29. package/dist/linux/systemctl.d.ts.map +1 -1
  30. package/dist/opnsense/alias-form.d.ts +29 -0
  31. package/dist/opnsense/alias-form.d.ts.map +1 -0
  32. package/dist/opnsense/alias.d.ts +81 -0
  33. package/dist/opnsense/alias.d.ts.map +1 -0
  34. package/dist/opnsense/category-form.d.ts +10 -0
  35. package/dist/opnsense/category-form.d.ts.map +1 -0
  36. package/dist/opnsense/category.d.ts +58 -0
  37. package/dist/opnsense/category.d.ts.map +1 -0
  38. package/dist/opnsense/credentials.d.ts +36 -0
  39. package/dist/opnsense/credentials.d.ts.map +1 -0
  40. package/dist/opnsense/fake-opnsense.d.ts +51 -0
  41. package/dist/opnsense/fake-opnsense.d.ts.map +1 -0
  42. package/dist/opnsense/group-form.d.ts +11 -0
  43. package/dist/opnsense/group-form.d.ts.map +1 -0
  44. package/dist/opnsense/group.d.ts +62 -0
  45. package/dist/opnsense/group.d.ts.map +1 -0
  46. package/dist/opnsense/index.d.ts +16 -0
  47. package/dist/opnsense/index.d.ts.map +1 -0
  48. package/dist/opnsense/index.js +211 -0
  49. package/dist/opnsense/index.js.map +20 -0
  50. package/dist/opnsense/policy.d.ts +20 -0
  51. package/dist/opnsense/policy.d.ts.map +1 -0
  52. package/dist/opnsense/providers.d.ts +13 -0
  53. package/dist/opnsense/providers.d.ts.map +1 -0
  54. package/dist/opnsense/resource.d.ts +74 -0
  55. package/dist/opnsense/resource.d.ts.map +1 -0
  56. package/dist/opnsense/wire.d.ts +39 -0
  57. package/dist/opnsense/wire.d.ts.map +1 -0
  58. package/dist/proxmox/acl.d.ts.map +1 -1
  59. package/dist/proxmox/api-token.d.ts.map +1 -1
  60. package/dist/proxmox/group-wire.d.ts +44 -5
  61. package/dist/proxmox/group-wire.d.ts.map +1 -1
  62. package/dist/proxmox/group.d.ts.map +1 -1
  63. package/dist/proxmox/index.js +326 -264
  64. package/dist/proxmox/index.js.map +13 -11
  65. package/dist/proxmox/role.d.ts.map +1 -1
  66. package/dist/proxmox/storage-form.d.ts +54 -0
  67. package/dist/proxmox/storage-form.d.ts.map +1 -0
  68. package/dist/proxmox/storage-wire.d.ts +56 -0
  69. package/dist/proxmox/storage-wire.d.ts.map +1 -0
  70. package/dist/proxmox/storage.d.ts +55 -60
  71. package/dist/proxmox/storage.d.ts.map +1 -1
  72. package/dist/proxmox/user-wire.d.ts +34 -5
  73. package/dist/proxmox/user-wire.d.ts.map +1 -1
  74. package/dist/proxmox/user.d.ts +6 -6
  75. package/dist/proxmox/user.d.ts.map +1 -1
  76. package/dist/unifi/fake-unifi.d.ts +48 -0
  77. package/dist/unifi/fake-unifi.d.ts.map +1 -0
  78. package/dist/unifi/firewall-zone-form.d.ts +40 -0
  79. package/dist/unifi/firewall-zone-form.d.ts.map +1 -0
  80. package/dist/unifi/firewall-zone.d.ts +50 -0
  81. package/dist/unifi/firewall-zone.d.ts.map +1 -0
  82. package/dist/unifi/index.d.ts +13 -0
  83. package/dist/unifi/index.d.ts.map +1 -0
  84. package/dist/unifi/index.js +190 -0
  85. package/dist/unifi/index.js.map +16 -0
  86. package/dist/unifi/network-form.d.ts +67 -0
  87. package/dist/unifi/network-form.d.ts.map +1 -0
  88. package/dist/unifi/network.d.ts +67 -0
  89. package/dist/unifi/network.d.ts.map +1 -0
  90. package/dist/unifi/policy.d.ts +20 -0
  91. package/dist/unifi/policy.d.ts.map +1 -0
  92. package/dist/unifi/providers.d.ts +13 -0
  93. package/dist/unifi/providers.d.ts.map +1 -0
  94. package/dist/unifi/resource.d.ts +64 -0
  95. package/dist/unifi/resource.d.ts.map +1 -0
  96. package/dist/verify/fake-engine.d.ts +14 -0
  97. package/dist/verify/fake-engine.d.ts.map +1 -1
  98. package/docs/grafana.md +47 -17
  99. package/docs/opnsense.md +146 -0
  100. package/docs/provider-standard.md +1 -1
  101. package/docs/quadlet-container.md +132 -0
  102. package/docs/unifi.md +93 -0
  103. package/docs/upstream-conformance.md +14 -4
  104. package/package.json +13 -3
  105. package/src/grafana/index.ts +6 -5
  106. package/src/linux/container-fixture.test.ts +92 -0
  107. package/src/linux/container-form.ts +243 -0
  108. package/src/linux/container-generator.test.ts +195 -0
  109. package/src/linux/container-generator.ts +113 -0
  110. package/src/linux/container-handlers.ts +73 -0
  111. package/src/linux/container-lifecycle.test.ts +209 -0
  112. package/src/linux/container-lifecycle.ts +217 -0
  113. package/src/linux/container-preflight.ts +97 -0
  114. package/src/linux/container-secrets.test.ts +171 -0
  115. package/src/linux/container-secrets.ts +112 -0
  116. package/src/linux/container-settle.ts +97 -0
  117. package/src/linux/container.ts +60 -0
  118. package/src/linux/fake-quadlet.ts +127 -0
  119. package/src/linux/index.ts +11 -3
  120. package/src/linux/providers.ts +2 -0
  121. package/src/linux/systemctl.ts +9 -0
  122. package/src/opnsense/alias-form.test.ts +89 -0
  123. package/src/opnsense/alias-form.ts +53 -0
  124. package/src/opnsense/alias.test.ts +203 -0
  125. package/src/opnsense/alias.ts +117 -0
  126. package/src/opnsense/category-form.test.ts +54 -0
  127. package/src/opnsense/category-form.ts +20 -0
  128. package/src/opnsense/category.test.ts +138 -0
  129. package/src/opnsense/category.ts +82 -0
  130. package/src/opnsense/credentials.ts +41 -0
  131. package/src/opnsense/fake-opnsense.ts +79 -0
  132. package/src/opnsense/group-form.test.ts +75 -0
  133. package/src/opnsense/group-form.ts +25 -0
  134. package/src/opnsense/group.test.ts +141 -0
  135. package/src/opnsense/group.ts +78 -0
  136. package/src/opnsense/index.ts +45 -0
  137. package/src/opnsense/policy.ts +49 -0
  138. package/src/opnsense/providers.ts +21 -0
  139. package/src/opnsense/resource.ts +146 -0
  140. package/src/opnsense/wire.ts +56 -0
  141. package/src/opnsense/write-refusal.test.ts +148 -0
  142. package/src/proxmox/acl.ts +10 -4
  143. package/src/proxmox/api-token.ts +20 -12
  144. package/src/proxmox/group-wire.ts +62 -8
  145. package/src/proxmox/group.ts +23 -35
  146. package/src/proxmox/read-failure-propagation.test.ts +183 -0
  147. package/src/proxmox/role.ts +9 -2
  148. package/src/proxmox/storage-form.ts +144 -0
  149. package/src/proxmox/storage-read-failure.test.ts +214 -0
  150. package/src/proxmox/storage-wire.ts +124 -0
  151. package/src/proxmox/storage.ts +165 -175
  152. package/src/proxmox/user-wire.ts +44 -8
  153. package/src/proxmox/user.ts +29 -27
  154. package/src/unifi/fake-unifi.ts +60 -0
  155. package/src/unifi/firewall-zone-form.ts +65 -0
  156. package/src/unifi/firewall-zone.test.ts +88 -0
  157. package/src/unifi/firewall-zone.ts +66 -0
  158. package/src/unifi/index.ts +26 -0
  159. package/src/unifi/network-form.ts +207 -0
  160. package/src/unifi/network.test.ts +209 -0
  161. package/src/unifi/network.ts +83 -0
  162. package/src/unifi/policy.ts +37 -0
  163. package/src/unifi/providers.ts +15 -0
  164. package/src/unifi/resource.test.ts +133 -0
  165. package/src/unifi/resource.ts +131 -0
  166. package/src/verify/fake-engine.ts +23 -0
@@ -1226,9 +1226,7 @@ var unreadableWarning = (type, identity2) => Effect6.logWarning(`${type} ${ident
1226
1226
 
1227
1227
  // src/proxmox/acl.ts
1228
1228
  var ProxmoxAcl = Resource("Proxmox.Acl");
1229
- var readAttributes = (props) => readOrUnreadable(runPve(props.target, "provision", false, access.listAccessAcl({}))).pipe(Effect7.map((rows) => rows === UNREADABLE ? UNREADABLE : attributesOf(rows, props)), Effect7.orElseSucceed(() => {
1230
- return;
1231
- }));
1229
+ var readAttributes = (props) => readOrUnreadable(runPve(props.target, "provision", false, access.listAccessAcl({}))).pipe(Effect7.map((rows) => rows === UNREADABLE ? UNREADABLE : attributesOf(rows, props)));
1232
1230
  var dropUnreadable = (live) => live === UNREADABLE ? undefined : live;
1233
1231
  var ProxmoxAclProvider = () => Provider.effect(ProxmoxAcl, Effect7.succeed(ProxmoxAcl.Provider.of({
1234
1232
  list: () => Effect7.succeed([]),
@@ -1398,9 +1396,10 @@ var guardWrite2 = (endpoint, body, presence) => guardForm(endpoint, asForm2(body
1398
1396
  var ProxmoxApiToken = Resource2("Proxmox.ApiToken", {
1399
1397
  defaultRemovalPolicy: "retain"
1400
1398
  });
1401
- var readToken = (props) => readOrUnreadable(runPve(props.target, "provision", false, access2.getAccessUserToken(props))).pipe(Effect8.map((live) => live === UNREADABLE ? UNREADABLE : attributesOf2(live, props)), Effect8.orElseSucceed(() => {
1402
- return;
1403
- }));
1399
+ var readToken = (props) => {
1400
+ const label = { tokenid: props.tokenid, userid: props.userid };
1401
+ return readOrUnreadable(runPve(props.target, "provision", false, access2.getAccessUserToken(label))).pipe(Effect8.map((live) => live === UNREADABLE ? UNREADABLE : attributesOf2(live, props)));
1402
+ };
1404
1403
  var dropUnreadable2 = (live) => live === UNREADABLE ? undefined : live;
1405
1404
  var ProxmoxApiTokenProvider = () => Provider2.effect(ProxmoxApiToken, Effect8.succeed(ProxmoxApiToken.Provider.of({
1406
1405
  list: () => Effect8.succeed([]),
@@ -2094,10 +2093,12 @@ var ProxmoxFirewallAliasProvider = () => Provider9.effect(ProxmoxFirewallAlias,
2094
2093
  import { Resource as Resource10 } from "alchemy";
2095
2094
  import { isResolved as isResolved7 } from "alchemy/Diff";
2096
2095
  import * as Provider10 from "alchemy/Provider";
2097
- import * as access3 from "@distilled.cloud/proxmox/access";
2098
- import * as Effect23 from "effect/Effect";
2096
+ import * as access4 from "@distilled.cloud/proxmox/access";
2097
+ import * as Effect24 from "effect/Effect";
2099
2098
 
2100
2099
  // src/proxmox/group-wire.ts
2100
+ import * as access3 from "@distilled.cloud/proxmox/access";
2101
+ import * as Effect23 from "effect/Effect";
2101
2102
  var GROUP_CREATE = "pve:POST /access/groups";
2102
2103
  var GROUP_UPDATE = "pve:PUT /access/groups/{groupid}";
2103
2104
  var storedComment = (comment2) => {
@@ -2122,28 +2123,29 @@ var attributesOf3 = (live, props) => ({
2122
2123
  members: memberList(live.members)
2123
2124
  });
2124
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(() => {
2128
+ return;
2129
+ }));
2130
+ var dropUnreadable3 = (live) => live === UNREADABLE ? undefined : live;
2125
2131
 
2126
2132
  // src/proxmox/group.ts
2127
2133
  var ProxmoxGroup = Resource10("Proxmox.Group", {
2128
2134
  defaultRemovalPolicy: "retain"
2129
2135
  });
2130
- var readGroup = (props) => readOrUnreadable(runPve(props.target, "read", false, access3.getAccessGroup(props))).pipe(Effect23.map((live) => live === UNREADABLE ? UNREADABLE : live.members === undefined ? undefined : attributesOf3(live, props)), Effect23.orElseSucceed(() => {
2131
- return;
2132
- }));
2133
- var dropUnreadable3 = (live) => live === UNREADABLE ? undefined : live;
2134
- var ProxmoxGroupProvider = () => Provider10.effect(ProxmoxGroup, Effect23.succeed(ProxmoxGroup.Provider.of({
2135
- list: () => Effect23.succeed([]),
2136
- read: Effect23.fn(function* ({ olds }) {
2137
- return dropUnreadable3(yield* readGroup(olds));
2136
+ var ProxmoxGroupProvider = () => Provider10.effect(ProxmoxGroup, Effect24.succeed(ProxmoxGroup.Provider.of({
2137
+ list: () => Effect24.succeed([]),
2138
+ read: Effect24.fn(function* ({ olds, output }) {
2139
+ return dropUnreadable3(yield* output === undefined ? readGroup(olds) : readGroupOrFail(olds));
2138
2140
  }),
2139
- diff: Effect23.fn(function* ({ news, output }) {
2141
+ diff: Effect24.fn(function* ({ news, output }) {
2140
2142
  if (!isResolved7(news))
2141
2143
  return;
2142
2144
  yield* guardWrite2(GROUP_CREATE, createForm3(news), output === undefined);
2143
2145
  yield* guardWrite2(GROUP_UPDATE, updateForm(news), false);
2144
2146
  if (output === undefined)
2145
2147
  return;
2146
- const live = yield* readGroup(news);
2148
+ const live = yield* readGroupOrFail(news);
2147
2149
  if (live === UNREADABLE) {
2148
2150
  yield* unreadableWarning("Proxmox.Group", news.groupid);
2149
2151
  return { action: "noop" };
@@ -2154,29 +2156,29 @@ var ProxmoxGroupProvider = () => Provider10.effect(ProxmoxGroup, Effect23.succee
2154
2156
  }
2155
2157
  return matches3(live, news) ? { action: "noop" } : { action: "update" };
2156
2158
  }),
2157
- reconcile: Effect23.fn(function* ({ news }) {
2159
+ reconcile: Effect24.fn(function* ({ news }) {
2158
2160
  const before = dropUnreadable3(yield* readGroup(news));
2159
2161
  yield* guardWrite2(GROUP_CREATE, createForm3(news), before === undefined);
2160
2162
  yield* guardWrite2(GROUP_UPDATE, updateForm(news), false);
2161
2163
  if (before === undefined) {
2162
- yield* runPve(news.target, "provision", true, access3.createAccessGroup(createForm3(news)));
2164
+ yield* runPve(news.target, "provision", true, access4.createAccessGroup(createForm3(news)));
2163
2165
  } else if (!matches3(before, news)) {
2164
- yield* runPve(news.target, "provision", true, access3.putAccessGroup(updateForm(news)));
2166
+ yield* runPve(news.target, "provision", true, access4.putAccessGroup(updateForm(news)));
2165
2167
  }
2166
2168
  const after = dropUnreadable3(yield* readGroup(news));
2167
2169
  if (after === undefined) {
2168
- return yield* Effect23.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."));
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."));
2169
2171
  }
2170
2172
  return after;
2171
2173
  }),
2172
- delete: Effect23.fn(function* ({ olds }) {
2173
- yield* runPve(olds.target, "provision", true, access3.deleteAccessGroup({ groupid: olds.groupid }));
2174
+ delete: Effect24.fn(function* ({ olds }) {
2175
+ yield* runPve(olds.target, "provision", true, access4.deleteAccessGroup({ groupid: olds.groupid }));
2174
2176
  })
2175
2177
  })));
2176
2178
  // src/proxmox/ha-resource.ts
2177
2179
  import { Resource as Resource11 } from "alchemy";
2178
2180
  import * as Provider11 from "alchemy/Provider";
2179
- import * as Effect24 from "effect/Effect";
2181
+ import * as Effect25 from "effect/Effect";
2180
2182
  var ProxmoxHaResource = Resource11("Proxmox.HaResource");
2181
2183
  var kind = (sid) => sid.split(":")[0] ?? "";
2182
2184
  var shape3 = (props) => ({
@@ -2204,11 +2206,11 @@ var handlers6 = pveHandlers({
2204
2206
  path: (props) => `cluster/ha/resources/${props.sid}`,
2205
2207
  updateForm: shape3
2206
2208
  });
2207
- var ProxmoxHaResourceProvider = () => Provider11.effect(ProxmoxHaResource, Effect24.succeed(ProxmoxHaResource.Provider.of(handlers6)));
2209
+ var ProxmoxHaResourceProvider = () => Provider11.effect(ProxmoxHaResource, Effect25.succeed(ProxmoxHaResource.Provider.of(handlers6)));
2208
2210
  // src/proxmox/ha-rule.ts
2209
2211
  import { Resource as Resource12 } from "alchemy";
2210
2212
  import * as Provider12 from "alchemy/Provider";
2211
- import * as Effect25 from "effect/Effect";
2213
+ import * as Effect26 from "effect/Effect";
2212
2214
 
2213
2215
  // src/proxmox/ha-rule-form.ts
2214
2216
  var nodeList = (value) => {
@@ -2285,43 +2287,43 @@ var handlers7 = pveHandlers({
2285
2287
  return withClears(fields, clear);
2286
2288
  }
2287
2289
  });
2288
- var ProxmoxHaRuleProvider = () => Provider12.effect(ProxmoxHaRule, Effect25.succeed(ProxmoxHaRule.Provider.of(handlers7)));
2290
+ var ProxmoxHaRuleProvider = () => Provider12.effect(ProxmoxHaRule, Effect26.succeed(ProxmoxHaRule.Provider.of(handlers7)));
2289
2291
  // src/proxmox/lxc.ts
2290
2292
  import { Resource as Resource13 } from "alchemy";
2291
2293
  import { isResolved as isResolved8 } from "alchemy/Diff";
2292
2294
  import * as Provider13 from "alchemy/Provider";
2293
- import * as Effect35 from "effect/Effect";
2295
+ import * as Effect36 from "effect/Effect";
2294
2296
 
2295
2297
  // src/ownership/adopt.ts
2296
2298
  import { AdoptPolicy } from "alchemy/AdoptPolicy";
2297
2299
  import { AlchemyContext } from "alchemy/AlchemyContext";
2298
2300
  import { Stack as Stack3 } from "alchemy/Stack";
2299
- import * as Effect29 from "effect/Effect";
2301
+ import * as Effect30 from "effect/Effect";
2300
2302
  import * as Option5 from "effect/Option";
2301
2303
 
2302
2304
  // src/ownership/resume.ts
2303
2305
  import { Unowned } from "alchemy/AdoptPolicy";
2304
2306
  import { Artifacts } from "alchemy/Artifacts";
2305
- import * as Effect26 from "effect/Effect";
2307
+ import * as Effect27 from "effect/Effect";
2306
2308
  import * as Option2 from "effect/Option";
2307
2309
  var PROVEN = "homeflare/ownership/resumes";
2308
2310
  var UNFINISHED = "homeflare/ownership/unfinished";
2309
- var note = (key, instanceId) => Effect26.gen(function* () {
2310
- const bag = yield* Effect26.serviceOption(Artifacts);
2311
+ var note = (key, instanceId) => Effect27.gen(function* () {
2312
+ const bag = yield* Effect27.serviceOption(Artifacts);
2311
2313
  if (Option2.isSome(bag))
2312
2314
  yield* bag.value.set(key, instanceId);
2313
2315
  });
2314
- var noted = (key, instanceId) => Effect26.gen(function* () {
2315
- const bag = yield* Effect26.serviceOption(Artifacts);
2316
+ var noted = (key, instanceId) => Effect27.gen(function* () {
2317
+ const bag = yield* Effect27.serviceOption(Artifacts);
2316
2318
  if (Option2.isNone(bag))
2317
2319
  return false;
2318
2320
  return (yield* bag.value.get(key)) === instanceId;
2319
2321
  });
2320
- var noteUnfinished = (instanceId) => Effect26.as(note(UNFINISHED, instanceId), undefined);
2321
- var noteResume = (instanceId, recovered) => Effect26.gen(function* () {
2322
+ var noteUnfinished = (instanceId) => Effect27.as(note(UNFINISHED, instanceId), undefined);
2323
+ var noteResume = (instanceId, recovered) => Effect27.gen(function* () {
2322
2324
  yield* noteUnfinished(instanceId);
2323
- const unproven = () => Effect26.succeed(undefined);
2324
- const found = yield* recovered.pipe(Effect26.catch(unproven), Effect26.catchDefect(unproven));
2325
+ const unproven = () => Effect27.succeed(undefined);
2326
+ const found = yield* recovered.pipe(Effect27.catch(unproven), Effect27.catchDefect(unproven));
2325
2327
  if (found === undefined || found === null || Unowned.is(found))
2326
2328
  return;
2327
2329
  yield* note(PROVEN, instanceId);
@@ -2332,7 +2334,7 @@ var provingResumes = (service) => {
2332
2334
  const { diff, read } = service;
2333
2335
  if (diff === undefined || read === undefined)
2334
2336
  return service;
2335
- const proving = (input) => Effect26.gen(function* () {
2337
+ const proving = (input) => Effect27.gen(function* () {
2336
2338
  if (input.output === undefined) {
2337
2339
  yield* noteResume(input.instanceId, read({ ...input, output: undefined }));
2338
2340
  }
@@ -2344,12 +2346,12 @@ var provingResumes = (service) => {
2344
2346
  // src/ownership/rows.ts
2345
2347
  import { Stack as Stack2 } from "alchemy/Stack";
2346
2348
  import { State, isActionState } from "alchemy/State/State";
2347
- import * as Effect28 from "effect/Effect";
2349
+ import * as Effect29 from "effect/Effect";
2348
2350
  import * as Option4 from "effect/Option";
2349
2351
 
2350
2352
  // src/ownership/whole.ts
2351
2353
  import { Stack } from "alchemy/Stack";
2352
- import * as Effect27 from "effect/Effect";
2354
+ import * as Effect28 from "effect/Effect";
2353
2355
  import * as Option3 from "effect/Option";
2354
2356
  var absent = (value) => value === undefined || value === null;
2355
2357
  var isPlainObject = (value) => {
@@ -2375,22 +2377,22 @@ var carries = (declared, recorded) => {
2375
2377
  }
2376
2378
  return true;
2377
2379
  };
2378
- var wholeDeclaration = (fqn, props) => Effect27.map(Effect27.serviceOption(Stack), (stack) => {
2380
+ var wholeDeclaration = (fqn, props) => Effect28.map(Effect28.serviceOption(Stack), (stack) => {
2379
2381
  const declared = Option3.isSome(stack) ? stack.value.resources[fqn] : undefined;
2380
2382
  return declared !== undefined && carries(declared.Props, props);
2381
2383
  });
2382
2384
 
2383
2385
  // src/ownership/rows.ts
2384
- var storeOf = Effect28.gen(function* () {
2385
- const stack = yield* Effect28.serviceOption(Stack2);
2386
- const state = yield* Effect28.serviceOption(State);
2386
+ var storeOf = Effect29.gen(function* () {
2387
+ const stack = yield* Effect29.serviceOption(Stack2);
2388
+ const state = yield* Effect29.serviceOption(State);
2387
2389
  if (Option4.isNone(stack) || Option4.isNone(state))
2388
2390
  return;
2389
2391
  const store = yield* state.value;
2390
2392
  const where = { stack: stack.value.name, stage: stack.value.stage };
2391
2393
  return { resources: stack.value.resources, store, where };
2392
2394
  });
2393
- var rowAt = (store, where, fqn) => store.get({ ...where, fqn }).pipe(Effect28.orElseSucceed(() => {
2395
+ var rowAt = (store, where, fqn) => store.get({ ...where, fqn }).pipe(Effect29.orElseSucceed(() => {
2394
2396
  return;
2395
2397
  }));
2396
2398
  var generationOf = (row, instanceId) => {
@@ -2403,7 +2405,7 @@ var generationOf = (row, instanceId) => {
2403
2405
  }
2404
2406
  return;
2405
2407
  };
2406
- var recordedGeneration = (fqn, instanceId) => Effect28.gen(function* () {
2408
+ var recordedGeneration = (fqn, instanceId) => Effect29.gen(function* () {
2407
2409
  const found = yield* storeOf;
2408
2410
  if (found === undefined)
2409
2411
  return;
@@ -2414,14 +2416,14 @@ var recordedGeneration = (fqn, instanceId) => Effect28.gen(function* () {
2414
2416
  }
2415
2417
  return;
2416
2418
  });
2417
- var recordedInstance = (fqn, instanceId) => Effect28.gen(function* () {
2419
+ var recordedInstance = (fqn, instanceId) => Effect29.gen(function* () {
2418
2420
  const generation = yield* recordedGeneration(fqn, instanceId);
2419
2421
  if (generation === undefined)
2420
2422
  return "absent";
2421
2423
  return (yield* wholeDeclaration(fqn, generation.props)) ? "whole" : "partial";
2422
2424
  });
2423
- var isCreate = (fqn, instanceId) => Effect28.map(recordedGeneration(fqn, instanceId), (generation) => generation?.status === "creating");
2424
- var forgetRefusedCreate = (fqn, instanceId) => Effect28.gen(function* () {
2425
+ var isCreate = (fqn, instanceId) => Effect29.map(recordedGeneration(fqn, instanceId), (generation) => generation?.status === "creating");
2426
+ var forgetRefusedCreate = (fqn, instanceId) => Effect29.gen(function* () {
2425
2427
  const found = yield* storeOf;
2426
2428
  if (found === undefined)
2427
2429
  return;
@@ -2430,32 +2432,32 @@ var forgetRefusedCreate = (fqn, instanceId) => Effect28.gen(function* () {
2430
2432
  if (mine?.status !== "creating" || mine.instanceId !== instanceId || mine.attr !== undefined) {
2431
2433
  return;
2432
2434
  }
2433
- yield* found.store.delete({ ...found.where, fqn }).pipe(Effect28.ignore);
2435
+ yield* found.store.delete({ ...found.where, fqn }).pipe(Effect29.ignore);
2434
2436
  });
2435
2437
 
2436
2438
  // src/ownership/adopt.ts
2437
- var adoptEnabled = (fqn) => Effect29.gen(function* () {
2438
- const stack = yield* Effect29.serviceOption(Stack3);
2439
+ var adoptEnabled = (fqn) => Effect30.gen(function* () {
2440
+ const stack = yield* Effect30.serviceOption(Stack3);
2439
2441
  const scoped = Option5.isSome(stack) ? stack.value.resources[fqn]?.Adopt : undefined;
2440
2442
  if (scoped !== undefined)
2441
2443
  return scoped;
2442
- const policy = yield* Effect29.serviceOption(AdoptPolicy);
2444
+ const policy = yield* Effect30.serviceOption(AdoptPolicy);
2443
2445
  if (Option5.isSome(policy))
2444
2446
  return policy.value;
2445
- const context = yield* Effect29.serviceOption(AlchemyContext);
2447
+ const context = yield* Effect30.serviceOption(AlchemyContext);
2446
2448
  return Option5.isSome(context) ? context.value.adopt : false;
2447
2449
  });
2448
- var adoptable = (owner) => Effect29.gen(function* () {
2450
+ var adoptable = (owner) => Effect30.gen(function* () {
2449
2451
  if (yield* isCreate(owner.fqn, owner.instanceId))
2450
2452
  return true;
2451
2453
  return yield* unfinished(owner.instanceId);
2452
2454
  });
2453
- var adoptsAtApply = (owner) => Effect29.gen(function* () {
2455
+ var adoptsAtApply = (owner) => Effect30.gen(function* () {
2454
2456
  if (!(yield* adoptEnabled(owner.fqn)))
2455
2457
  return false;
2456
2458
  return yield* adoptable(owner);
2457
2459
  });
2458
- var refuseTakeover = (owner, what) => Effect29.gen(function* () {
2460
+ var refuseTakeover = (owner, what) => Effect30.gen(function* () {
2459
2461
  if (owner.output !== undefined)
2460
2462
  return;
2461
2463
  if (yield* resumes(owner.instanceId))
@@ -2465,25 +2467,25 @@ var refuseTakeover = (owner, what) => Effect29.gen(function* () {
2465
2467
  return;
2466
2468
  yield* forgetRefusedCreate(owner.fqn, owner.instanceId);
2467
2469
  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.";
2468
- return yield* Effect29.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}`));
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}`));
2469
2471
  });
2470
2472
  var claimFor = (owner) => (what) => refuseTakeover(owner, what);
2471
2473
 
2472
2474
  // src/ownership/probe.ts
2473
2475
  import { Unowned as Unowned2 } from "alchemy/AdoptPolicy";
2474
- import * as Effect30 from "effect/Effect";
2475
- var provenOurs = (ask, settled2) => Effect30.gen(function* () {
2476
+ import * as Effect31 from "effect/Effect";
2477
+ var provenOurs = (ask, settled2) => Effect31.gen(function* () {
2476
2478
  const recorded = yield* recordedInstance(ask.fqn, ask.instanceId);
2477
2479
  if (recorded === "absent")
2478
2480
  return false;
2479
2481
  if (recorded === "partial") {
2480
- yield* Effect30.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");
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");
2481
2483
  return false;
2482
2484
  }
2483
- const unproven = (reason) => Effect30.as(Effect30.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);
2484
- return yield* settled2.pipe(Effect30.catch(unproven), Effect30.catchDefect(unproven));
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));
2485
2487
  });
2486
- var ownedRead = (ask, found, settled2) => Effect30.gen(function* () {
2488
+ var ownedRead = (ask, found, settled2) => Effect31.gen(function* () {
2487
2489
  if (found === undefined || ask.output !== undefined)
2488
2490
  return found;
2489
2491
  return (yield* provenOurs(ask, settled2)) ? found : Unowned2(found);
@@ -2938,11 +2940,11 @@ var identityRefusals = (news, olds, output) => {
2938
2940
  };
2939
2941
 
2940
2942
  // src/proxmox/lxc-adoption.ts
2941
- import * as Effect34 from "effect/Effect";
2943
+ import * as Effect35 from "effect/Effect";
2942
2944
 
2943
2945
  // src/ownership/adopting.ts
2944
- import * as Effect31 from "effect/Effect";
2945
- var adopting = (owner, settled2) => Effect31.gen(function* () {
2946
+ import * as Effect32 from "effect/Effect";
2947
+ var adopting = (owner, settled2) => Effect32.gen(function* () {
2946
2948
  if (owner.output === undefined)
2947
2949
  return false;
2948
2950
  const generation = yield* recordedGeneration(owner.fqn, owner.instanceId);
@@ -2954,11 +2956,11 @@ var adopting = (owner, settled2) => Effect31.gen(function* () {
2954
2956
  });
2955
2957
 
2956
2958
  // src/proxmox/lxc-lifecycle.ts
2957
- import * as Effect33 from "effect/Effect";
2959
+ import * as Effect34 from "effect/Effect";
2958
2960
 
2959
2961
  // src/proxmox/network-apply-read.ts
2960
- import * as Effect32 from "effect/Effect";
2961
- var stagedDiff = (target, node) => Effect32.gen(function* () {
2962
+ import * as Effect33 from "effect/Effect";
2963
+ var stagedDiff = (target, node) => Effect33.gen(function* () {
2962
2964
  const path = `nodes/${node}/network`;
2963
2965
  const credential = yield* leased(target, "read");
2964
2966
  const envelope = yield* pveEnvelopeWith(target, credential, "GET", path);
@@ -2971,8 +2973,8 @@ var pendingLines = (diff) => {
2971
2973
  `).filter((line) => (line.startsWith("+") || line.startsWith("-")) && !line.startsWith("+++") && !line.startsWith("---")).length;
2972
2974
  return Math.max(changed, 1);
2973
2975
  };
2974
- var pendingCount = (target, node) => stagedDiff(target, node).pipe(Effect32.map(pendingLines));
2975
- var clusterHealth = (target) => pve(target, "read", "GET", "cluster/status").pipe(Effect32.map((rows) => {
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) => {
2976
2978
  const all = rows ?? [];
2977
2979
  const cluster = all.find((row) => row.type === "cluster");
2978
2980
  return {
@@ -2980,21 +2982,21 @@ var clusterHealth = (target) => pve(target, "read", "GET", "cluster/status").pip
2980
2982
  quorate: cluster === undefined ? true : bool(cluster.quorate)
2981
2983
  };
2982
2984
  }));
2983
- var degradedReason = (target) => clusterHealth(target).pipe(Effect32.map((health) => health.quorate && health.offline.length === 0 ? undefined : `quorate=${String(health.quorate)} offline=[${health.offline.join(", ")}]`));
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(", ")}]`));
2984
2986
  var UNREACHABLE = "the task could not be read -- the node stopped answering, or this lease cannot see it";
2985
2987
  var STILL_RUNNING = "still running when this provider stopped waiting";
2986
2988
  var ATTEMPTS = 30;
2987
- var awaitTask = (target, credential, node, upid, attempts = ATTEMPTS) => Effect32.gen(function* () {
2989
+ var awaitTask = (target, credential, node, upid, attempts = ATTEMPTS) => Effect33.gen(function* () {
2988
2990
  const path = `nodes/${node}/tasks/${upid}/status`;
2989
2991
  for (let attempt = 0;attempt < attempts; attempt += 1) {
2990
- const status = yield* pveWith(target, credential, "GET", path).pipe(Effect32.orElseSucceed(() => {
2992
+ const status = yield* pveWith(target, credential, "GET", path).pipe(Effect33.orElseSucceed(() => {
2991
2993
  return;
2992
2994
  }));
2993
2995
  if (status === undefined)
2994
2996
  return UNREACHABLE;
2995
2997
  if (status.status === "stopped")
2996
2998
  return text(status.exitstatus, "stopped with no exitstatus");
2997
- yield* Effect32.sleep("1 second");
2999
+ yield* Effect33.sleep("1 second");
2998
3000
  }
2999
3001
  return STILL_RUNNING;
3000
3002
  });
@@ -3012,17 +3014,17 @@ var LXC_ENDPOINTS = {
3012
3014
  var CREATE_POLLS = 180;
3013
3015
  var TASK_POLLS = 60;
3014
3016
  var isServerError = (error) => error instanceof PveError && error.status === 500;
3015
- var readLive = (where) => Effect33.gen(function* () {
3016
- const answer = yield* pve(where.target, "read", "GET", `${guestPath(where)}/config`).pipe(Effect33.map((data) => ({ data, error: undefined })), Effect33.catchIf(isServerError, (error) => Effect33.succeed({ data: undefined, error })));
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 })));
3017
3019
  if (answer.data !== undefined && answer.data !== null)
3018
3020
  return answer.data;
3019
3021
  const rows = yield* pve(where.target, "read", "GET", "cluster/resources?type=vm");
3020
3022
  const found = (rows ?? []).find((row) => Number(row.vmid) === where.vmid);
3021
3023
  if (found !== undefined && found.node === where.node && found.type === "lxc") {
3022
- return yield* Effect33.fail(answer.error ?? new LxcRefusedError(`CT ${String(where.vmid)} is listed but its config read empty.`));
3024
+ return yield* Effect34.fail(answer.error ?? new LxcRefusedError(`CT ${String(where.vmid)} is listed but its config read empty.`));
3023
3025
  }
3024
3026
  if (found !== undefined) {
3025
- return yield* Effect33.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."));
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."));
3026
3028
  }
3027
3029
  return;
3028
3030
  });
@@ -3032,23 +3034,23 @@ var attributesOf4 = (where, live) => ({
3032
3034
  rawKeys: rawKeysOf(live),
3033
3035
  vmid: where.vmid
3034
3036
  });
3035
- var task = (where, method, path, what, polls, form) => Effect33.gen(function* () {
3037
+ var task = (where, method, path, what, polls, form) => Effect34.gen(function* () {
3036
3038
  const credential = yield* mint(where.target, "provision");
3037
3039
  const upid = text(yield* pveWith(where.target, credential, method, path, form));
3038
3040
  if (upid === "") {
3039
- return yield* Effect33.fail(new LxcRefusedError(`${what}: PVE returned no task id, so the write cannot be confirmed and is not claimed.`));
3041
+ return yield* Effect34.fail(new LxcRefusedError(`${what}: PVE returned no task id, so the write cannot be confirmed and is not claimed.`));
3040
3042
  }
3041
3043
  const exit = yield* awaitTask(where.target, credential, where.node, upid, polls);
3042
3044
  if (exit !== "OK") {
3043
- return yield* Effect33.fail(new LxcRefusedError(`${what}: task ${upid} ended "${exit}". Read \`pvesh get /nodes/${where.node}/tasks/` + `${upid}/log\` before running the deploy again.`));
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.`));
3044
3046
  }
3045
3047
  });
3046
- var createGuest = (props) => Effect33.gen(function* () {
3048
+ var createGuest = (props) => Effect34.gen(function* () {
3047
3049
  const form = createForm4(props);
3048
3050
  yield* guardForm(LXC_ENDPOINTS.create, form, true);
3049
3051
  return yield* task(props, "POST", `nodes/${props.node}/lxc`, `create CT ${String(props.vmid)}`, CREATE_POLLS, form);
3050
3052
  });
3051
- var updateGuest = (props, change, digest) => Effect33.gen(function* () {
3053
+ var updateGuest = (props, change, digest) => Effect34.gen(function* () {
3052
3054
  if (Object.keys(change.put).length > 0 || change.clear.length > 0) {
3053
3055
  const form = withClears({ ...change.put, ...digest === "" ? {} : { digest } }, change.clear);
3054
3056
  yield* guardForm(LXC_ENDPOINTS.update, form, false);
@@ -3060,33 +3062,33 @@ var updateGuest = (props, change, digest) => Effect33.gen(function* () {
3060
3062
  yield* task(props, "PUT", `${guestPath(props)}/resize`, `grow ${grow.disk} of CT ${String(props.vmid)} to ${grow.size}`, TASK_POLLS, grown);
3061
3063
  }
3062
3064
  });
3063
- var destroyGuest = (where, declared) => Effect33.gen(function* () {
3065
+ var destroyGuest = (where, declared) => Effect34.gen(function* () {
3064
3066
  const live = yield* readLive(where);
3065
3067
  if (live === undefined)
3066
3068
  return;
3067
3069
  const drift = judge(declared, live).drift;
3068
3070
  if (drift.length > 0) {
3069
- return yield* Effect33.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."));
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."));
3070
3072
  }
3071
3073
  yield* task(where, "DELETE", guestPath(where), `destroy CT ${String(where.vmid)}`, TASK_POLLS);
3072
3074
  });
3073
3075
 
3074
3076
  // src/proxmox/lxc-adoption.ts
3075
3077
  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.";
3076
- var refuseAdoptedDrift = (owner, props, live, change) => Effect34.gen(function* () {
3078
+ var refuseAdoptedDrift = (owner, props, live, change) => Effect35.gen(function* () {
3077
3079
  if (change.drift.length === 0)
3078
3080
  return;
3079
- const settled2 = (recorded) => Effect34.sync(() => judge(recorded, live).drift.length === 0);
3081
+ const settled2 = (recorded) => Effect35.sync(() => judge(recorded, live).drift.length === 0);
3080
3082
  if (!(yield* adopting(owner, settled2)))
3081
3083
  return;
3082
- return yield* Effect34.fail(new LxcRefusedError(adoptionRefusal(props, change.drift)));
3084
+ return yield* Effect35.fail(new LxcRefusedError(adoptionRefusal(props, change.drift)));
3083
3085
  });
3084
3086
 
3085
3087
  // src/proxmox/lxc.ts
3086
3088
  var ProxmoxLxc = Resource13("Proxmox.Lxc", { defaultRemovalPolicy: "retain" });
3087
- var refused = (reasons) => Effect35.fail(new LxcRefusedError(reasons.join(`
3089
+ var refused = (reasons) => Effect36.fail(new LxcRefusedError(reasons.join(`
3088
3090
  `)));
3089
- var diff = (owner, news, olds) => Effect35.gen(function* () {
3091
+ var diff = (owner, news, olds) => Effect36.gen(function* () {
3090
3092
  const { output } = owner;
3091
3093
  const identity2 = identityRefusals(news, olds, output);
3092
3094
  if (identity2.length > 0)
@@ -3100,7 +3102,7 @@ var diff = (owner, news, olds) => Effect35.gen(function* () {
3100
3102
  const refusals = createRefusals(news);
3101
3103
  if (refusals.length > 0)
3102
3104
  return yield* refused(refusals);
3103
- yield* Effect35.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.");
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.");
3104
3106
  return { action: "update" };
3105
3107
  }
3106
3108
  const change = judge(news, live);
@@ -3111,10 +3113,10 @@ var diff = (owner, news, olds) => Effect35.gen(function* () {
3111
3113
  if (change.drift.length === 0 && !moved)
3112
3114
  return { action: "noop" };
3113
3115
  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.";
3114
- yield* Effect35.logWarning(`Proxmox.Lxc ${news.node}/${String(news.vmid)}: ${what}`);
3116
+ yield* Effect36.logWarning(`Proxmox.Lxc ${news.node}/${String(news.vmid)}: ${what}`);
3115
3117
  return { action: "update" };
3116
3118
  });
3117
- var reconcile = (owner, news) => Effect35.gen(function* () {
3119
+ var reconcile = (owner, news) => Effect36.gen(function* () {
3118
3120
  const { output } = owner;
3119
3121
  const identity2 = identityRefusals(news, news, output);
3120
3122
  if (identity2.length > 0)
@@ -3160,12 +3162,12 @@ var whereOf = (olds, output) => ({
3160
3162
  target: olds.target,
3161
3163
  vmid: output?.vmid ?? olds.vmid
3162
3164
  });
3163
- var read = (owner, olds) => Effect35.gen(function* () {
3165
+ var read = (owner, olds) => Effect36.gen(function* () {
3164
3166
  const where = whereOf(olds, owner.output);
3165
3167
  const live = yield* readLive(where);
3166
3168
  if (live === undefined)
3167
3169
  return;
3168
- const settled2 = Effect35.sync(() => judge(olds, live).drift.length === 0);
3170
+ const settled2 = Effect36.sync(() => judge(olds, live).drift.length === 0);
3169
3171
  return yield* ownedRead(owner, attributesOf4(where, live), settled2);
3170
3172
  });
3171
3173
  var handlers8 = {
@@ -3177,7 +3179,7 @@ var handlers8 = {
3177
3179
  olds,
3178
3180
  output
3179
3181
  }) => diff({ fqn, instanceId, output }, news, olds),
3180
- list: () => Effect35.succeed([]),
3182
+ list: () => Effect36.succeed([]),
3181
3183
  read: ({
3182
3184
  fqn,
3183
3185
  instanceId,
@@ -3191,11 +3193,11 @@ var handlers8 = {
3191
3193
  output
3192
3194
  }) => reconcile({ fqn, instanceId, output }, news)
3193
3195
  };
3194
- var ProxmoxLxcProvider = () => Provider13.effect(ProxmoxLxc, Effect35.succeed(ProxmoxLxc.Provider.of(handlers8)).pipe(Effect35.map(provingResumes)));
3196
+ var ProxmoxLxcProvider = () => Provider13.effect(ProxmoxLxc, Effect36.succeed(ProxmoxLxc.Provider.of(handlers8)).pipe(Effect36.map(provingResumes)));
3195
3197
  // src/proxmox/metric-server.ts
3196
3198
  import { Resource as Resource14 } from "alchemy";
3197
3199
  import * as Provider14 from "alchemy/Provider";
3198
- import * as Effect36 from "effect/Effect";
3200
+ import * as Effect37 from "effect/Effect";
3199
3201
 
3200
3202
  // src/proxmox/metric-server-form.ts
3201
3203
  var UNSET2 = -1;
@@ -3308,12 +3310,12 @@ var handlers9 = pveHandlers({
3308
3310
  path: (props) => `cluster/metrics/server/${props.id}`,
3309
3311
  updateForm: update
3310
3312
  });
3311
- var ProxmoxMetricServerProvider = () => Provider14.effect(ProxmoxMetricServer, Effect36.succeed(ProxmoxMetricServer.Provider.of(handlers9)));
3313
+ var ProxmoxMetricServerProvider = () => Provider14.effect(ProxmoxMetricServer, Effect37.succeed(ProxmoxMetricServer.Provider.of(handlers9)));
3312
3314
  // src/proxmox/network-apply.ts
3313
3315
  import { Resource as Resource15 } from "alchemy";
3314
3316
  import { isResolved as isResolved9 } from "alchemy/Diff";
3315
3317
  import * as Provider15 from "alchemy/Provider";
3316
- import * as Effect37 from "effect/Effect";
3318
+ import * as Effect38 from "effect/Effect";
3317
3319
 
3318
3320
  // src/proxmox/apply-endpoints.ts
3319
3321
  var NETWORK_APPLY_ENDPOINT = "pve:PUT /nodes/{node}/network";
@@ -3323,15 +3325,15 @@ var guardSdnApply = guardForm(SDN_APPLY_ENDPOINT, {}, true);
3323
3325
 
3324
3326
  // src/proxmox/network-apply.ts
3325
3327
  var ProxmoxNetworkApply = Resource15("Proxmox.NetworkApply");
3326
- var read2 = (props) => pendingCount(props.target, props.node).pipe(Effect37.map((pending) => ({ node: props.node, pending })));
3327
- var diff2 = (news) => Effect37.gen(function* () {
3328
+ var read2 = (props) => pendingCount(props.target, props.node).pipe(Effect38.map((pending) => ({ node: props.node, pending })));
3329
+ var diff2 = (news) => Effect38.gen(function* () {
3328
3330
  if (!isResolved9(news))
3329
3331
  return;
3330
3332
  const { pending } = yield* read2(news);
3331
3333
  return pending === 0 ? { action: "noop" } : { action: "update" };
3332
3334
  });
3333
- var refuse = (node, why) => Effect37.die(new Error(`Proxmox.NetworkApply ${node}: ${why}`));
3334
- var apply = (props) => Effect37.gen(function* () {
3335
+ var refuse = (node, why) => Effect38.die(new Error(`Proxmox.NetworkApply ${node}: ${why}`));
3336
+ var apply = (props) => Effect38.gen(function* () {
3335
3337
  const node = props.node;
3336
3338
  const staged = yield* pendingCount(props.target, node);
3337
3339
  if (staged === 0)
@@ -3361,17 +3363,17 @@ var apply = (props) => Effect37.gen(function* () {
3361
3363
  return { node, pending: left };
3362
3364
  });
3363
3365
  var handlers10 = {
3364
- delete: () => Effect37.void,
3366
+ delete: () => Effect38.void,
3365
3367
  diff: ({ news }) => diff2(news),
3366
- list: () => Effect37.succeed([]),
3368
+ list: () => Effect38.succeed([]),
3367
3369
  read: ({ olds }) => read2(olds),
3368
3370
  reconcile: ({ news }) => apply(news)
3369
3371
  };
3370
- var ProxmoxNetworkApplyProvider = () => Provider15.effect(ProxmoxNetworkApply, Effect37.succeed(ProxmoxNetworkApply.Provider.of(handlers10)));
3372
+ var ProxmoxNetworkApplyProvider = () => Provider15.effect(ProxmoxNetworkApply, Effect38.succeed(ProxmoxNetworkApply.Provider.of(handlers10)));
3371
3373
  // src/proxmox/node-network.ts
3372
3374
  import { Resource as Resource16 } from "alchemy";
3373
3375
  import * as Provider16 from "alchemy/Provider";
3374
- import * as Effect38 from "effect/Effect";
3376
+ import * as Effect39 from "effect/Effect";
3375
3377
 
3376
3378
  // src/proxmox/node-network-form.ts
3377
3379
  var UNSET3 = -1;
@@ -3459,11 +3461,11 @@ var handlers11 = pveHandlers({
3459
3461
  path: (props) => `nodes/${props.node}/network/${props.iface}`,
3460
3462
  updateForm: updateBody2
3461
3463
  });
3462
- var ProxmoxNodeNetworkProvider = () => Provider16.effect(ProxmoxNodeNetwork, Effect38.succeed(ProxmoxNodeNetwork.Provider.of(handlers11)));
3464
+ var ProxmoxNodeNetworkProvider = () => Provider16.effect(ProxmoxNodeNetwork, Effect39.succeed(ProxmoxNodeNetwork.Provider.of(handlers11)));
3463
3465
  // src/proxmox/notification-matcher.ts
3464
3466
  import { Resource as Resource17 } from "alchemy";
3465
3467
  import * as Provider17 from "alchemy/Provider";
3466
- import * as Effect39 from "effect/Effect";
3468
+ import * as Effect40 from "effect/Effect";
3467
3469
 
3468
3470
  // src/proxmox/notification-matcher-form.ts
3469
3471
  var list = (value) => Array.isArray(value) ? value.map((item) => String(item)) : [];
@@ -3553,11 +3555,11 @@ var handlers12 = pveHandlers({
3553
3555
  path: (props) => `cluster/notifications/matchers/${props.name}`,
3554
3556
  updateForm: matcherUpdateForm
3555
3557
  });
3556
- var ProxmoxNotificationMatcherProvider = () => Provider17.effect(ProxmoxNotificationMatcher, Effect39.succeed(ProxmoxNotificationMatcher.Provider.of(handlers12)));
3558
+ var ProxmoxNotificationMatcherProvider = () => Provider17.effect(ProxmoxNotificationMatcher, Effect40.succeed(ProxmoxNotificationMatcher.Provider.of(handlers12)));
3557
3559
  // src/proxmox/notification-target.ts
3558
3560
  import { Resource as Resource18 } from "alchemy";
3559
3561
  import * as Provider18 from "alchemy/Provider";
3560
- import * as Effect40 from "effect/Effect";
3562
+ import * as Effect41 from "effect/Effect";
3561
3563
 
3562
3564
  // src/proxmox/notification-target-endpoint.ts
3563
3565
  var ENDPOINTS = {
@@ -3639,15 +3641,15 @@ var handlers13 = pveHandlers({
3639
3641
  path: (props) => `cluster/notifications/endpoints/${props.type}/${props.name}`,
3640
3642
  updateForm: shape4
3641
3643
  });
3642
- var ProxmoxNotificationTargetProvider = () => Provider18.effect(ProxmoxNotificationTarget, Effect40.succeed(ProxmoxNotificationTarget.Provider.of(handlers13)));
3644
+ var ProxmoxNotificationTargetProvider = () => Provider18.effect(ProxmoxNotificationTarget, Effect41.succeed(ProxmoxNotificationTarget.Provider.of(handlers13)));
3643
3645
  // src/proxmox/pbs-datastore.ts
3644
3646
  import { Resource as Resource19 } from "alchemy";
3645
3647
  import { isResolved as isResolved10 } from "alchemy/Diff";
3646
3648
  import * as Provider19 from "alchemy/Provider";
3647
- import * as Effect44 from "effect/Effect";
3649
+ import * as Effect45 from "effect/Effect";
3648
3650
 
3649
3651
  // src/proxmox/pbs-datastore-form.ts
3650
- import * as Effect41 from "effect/Effect";
3652
+ import * as Effect42 from "effect/Effect";
3651
3653
  var attributes = (live, props) => ({
3652
3654
  backend: propertyString(live["backend"]),
3653
3655
  comment: text(live["comment"]),
@@ -3699,35 +3701,35 @@ var createForm5 = (props) => ({
3699
3701
  });
3700
3702
  var updateForm2 = (props) => mutable(props);
3701
3703
  var object2 = (props) => `config/datastore/${props.name}`;
3702
- var readOne = (props) => pve(props.target, "read", "GET", object2(props)).pipe(Effect41.map((live) => live === undefined || typeof live["name"] !== "string" ? undefined : attributes(live, props)), Effect41.orElseSucceed(() => {
3704
+ var readOne = (props) => pve(props.target, "read", "GET", object2(props)).pipe(Effect42.map((live) => live === undefined || typeof live["name"] !== "string" ? undefined : attributes(live, props)), Effect42.orElseSucceed(() => {
3703
3705
  return;
3704
3706
  }));
3705
3707
 
3706
3708
  // src/proxmox/pbs-datastore-guard.ts
3707
- import * as Effect42 from "effect/Effect";
3709
+ import * as Effect43 from "effect/Effect";
3708
3710
  var samePath = (left, right) => {
3709
3711
  const trim = (value) => value.length > 1 ? value.replace(/\/+$/, "") : value;
3710
3712
  return trim(left) === trim(right);
3711
3713
  };
3712
- var guardPath = (live, props) => live.path === "" || samePath(live.path, props.path) ? Effect42.void : Effect42.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."));
3713
- var guardBackend = (live, props) => props.backend === undefined || propertyString(props.backend) === live.backend ? Effect42.void : Effect42.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."));
3714
- var settle3 = (read3, done) => Effect42.gen(function* () {
3714
+ var guardPath = (live, props) => live.path === "" || samePath(live.path, props.path) ? Effect43.void : Effect43.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."));
3715
+ var guardBackend = (live, props) => props.backend === undefined || propertyString(props.backend) === live.backend ? Effect43.void : Effect43.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."));
3716
+ var settle3 = (read3, done) => Effect43.gen(function* () {
3715
3717
  for (let attempt = 0;attempt < 60; attempt += 1) {
3716
3718
  const live = yield* read3;
3717
3719
  if (done(live))
3718
3720
  return live;
3719
- yield* Effect42.sleep("2 seconds");
3721
+ yield* Effect43.sleep("2 seconds");
3720
3722
  }
3721
3723
  return yield* read3;
3722
3724
  });
3723
3725
 
3724
3726
  // src/proxmox/pbs-datastore-endpoint.ts
3725
- import * as Effect43 from "effect/Effect";
3727
+ import * as Effect44 from "effect/Effect";
3726
3728
  var DATASTORE_ENDPOINT = {
3727
3729
  create: "pbs:POST /config/datastore",
3728
3730
  update: "pbs:PUT /config/datastore/{name}"
3729
3731
  };
3730
- var guardDatastoreForms = (props) => Effect43.gen(function* () {
3732
+ var guardDatastoreForms = (props) => Effect44.gen(function* () {
3731
3733
  yield* guardForm(DATASTORE_ENDPOINT.create, createForm5(props), true);
3732
3734
  yield* guardForm(DATASTORE_ENDPOINT.update, updateForm2(props), false);
3733
3735
  });
@@ -3736,10 +3738,10 @@ var guardDatastoreForms = (props) => Effect43.gen(function* () {
3736
3738
  var PbsDatastore = Resource19("Pbs.Datastore", {
3737
3739
  defaultRemovalPolicy: "retain"
3738
3740
  });
3739
- var PbsDatastoreProvider = () => Provider19.effect(PbsDatastore, Effect44.succeed(PbsDatastore.Provider.of({
3740
- list: () => Effect44.succeed([]),
3741
+ var PbsDatastoreProvider = () => Provider19.effect(PbsDatastore, Effect45.succeed(PbsDatastore.Provider.of({
3742
+ list: () => Effect45.succeed([]),
3741
3743
  read: ({ olds }) => readOne(olds),
3742
- diff: ({ news, output }) => Effect44.gen(function* () {
3744
+ diff: ({ news, output }) => Effect45.gen(function* () {
3743
3745
  if (!isResolved10(news))
3744
3746
  return;
3745
3747
  yield* guardDatastoreForms(news);
@@ -3752,7 +3754,7 @@ var PbsDatastoreProvider = () => Provider19.effect(PbsDatastore, Effect44.succee
3752
3754
  yield* guardBackend(live, news);
3753
3755
  return matches4(live, news) ? { action: "noop" } : { action: "update" };
3754
3756
  }),
3755
- reconcile: Effect44.fn(function* ({ news }) {
3757
+ reconcile: Effect45.fn(function* ({ news }) {
3756
3758
  yield* guardDatastoreForms(news);
3757
3759
  const live = yield* readOne(news);
3758
3760
  let upid;
@@ -3768,22 +3770,22 @@ var PbsDatastoreProvider = () => Provider19.effect(PbsDatastore, Effect44.succee
3768
3770
  }
3769
3771
  const after = yield* settle3(readOne(news), (row) => row !== undefined && matches4(row, news));
3770
3772
  if (after === undefined || !matches4(after, news)) {
3771
- return yield* Effect44.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."));
3773
+ return yield* Effect45.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."));
3772
3774
  }
3773
3775
  return after;
3774
3776
  }),
3775
- delete: Effect44.fn(function* ({ olds }) {
3777
+ delete: Effect45.fn(function* ({ olds }) {
3776
3778
  yield* pve(olds.target, "provision", "DELETE", object2(olds));
3777
3779
  const left = yield* settle3(readOne(olds), (row) => row === undefined);
3778
3780
  if (left !== undefined) {
3779
- return yield* Effect44.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>\`.`));
3781
+ return yield* Effect45.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>\`.`));
3780
3782
  }
3781
3783
  })
3782
3784
  })));
3783
3785
  // src/proxmox/pbs-notification-matcher.ts
3784
3786
  import { Resource as Resource20 } from "alchemy";
3785
3787
  import * as Provider20 from "alchemy/Provider";
3786
- import * as Effect45 from "effect/Effect";
3788
+ import * as Effect46 from "effect/Effect";
3787
3789
  var PbsNotificationMatcher = Resource20("Pbs.NotificationMatcher");
3788
3790
  var handlers14 = pveHandlers({
3789
3791
  attributes: (live, props) => matcherAttributes(live, props.name),
@@ -3797,15 +3799,15 @@ var handlers14 = pveHandlers({
3797
3799
  path: (props) => `config/notifications/matchers/${props.name}`,
3798
3800
  updateForm: matcherUpdateForm
3799
3801
  });
3800
- var PbsNotificationMatcherProvider = () => Provider20.effect(PbsNotificationMatcher, Effect45.succeed(PbsNotificationMatcher.Provider.of(handlers14)));
3802
+ var PbsNotificationMatcherProvider = () => Provider20.effect(PbsNotificationMatcher, Effect46.succeed(PbsNotificationMatcher.Provider.of(handlers14)));
3801
3803
  // src/proxmox/pbs-notification-target.ts
3802
3804
  import { Resource as Resource21 } from "alchemy";
3803
3805
  import * as Provider21 from "alchemy/Provider";
3804
- import * as Effect47 from "effect/Effect";
3806
+ import * as Effect48 from "effect/Effect";
3805
3807
 
3806
3808
  // src/proxmox/pbs-notification-target-lifecycle.ts
3807
3809
  import { isResolved as isResolved11 } from "alchemy/Diff";
3808
- import * as Effect46 from "effect/Effect";
3810
+ import * as Effect47 from "effect/Effect";
3809
3811
 
3810
3812
  // src/proxmox/pbs-notification-target-endpoint.ts
3811
3813
  var ENDPOINTS2 = {
@@ -4082,12 +4084,12 @@ var targetForm = (props, groups, carry, mode) => {
4082
4084
 
4083
4085
  // src/proxmox/pbs-notification-target-lifecycle.ts
4084
4086
  var path = (props) => `config/notifications/endpoints/${props.type}/${props.name}`;
4085
- var readLive2 = (props) => pve(props.target, "read", "GET", path(props)).pipe(Effect46.map((data) => data == null ? undefined : targetAttributes(data, props)), Effect46.orElseSucceed(() => {
4087
+ var readLive2 = (props) => pve(props.target, "read", "GET", path(props)).pipe(Effect47.map((data) => data == null ? undefined : targetAttributes(data, props)), Effect47.orElseSucceed(() => {
4086
4088
  return;
4087
4089
  }));
4088
4090
  var refuse2 = (props) => {
4089
4091
  const reasons = refusals(props);
4090
- return reasons.length === 0 ? Effect46.void : Effect46.die(new Error(`${path(props)}: ${reasons.join("; ")}.`));
4092
+ return reasons.length === 0 ? Effect47.void : Effect47.die(new Error(`${path(props)}: ${reasons.join("; ")}.`));
4091
4093
  };
4092
4094
  var toCarry = (live, props, groups, sealed) => {
4093
4095
  const header = headerState(live, props, groups) === "stale";
@@ -4099,16 +4101,16 @@ var requireValues = (props, groups, carry) => {
4099
4101
  ...carry.header ? groups.header.missing : [],
4100
4102
  ...carry.sealed ? groups.sealed.missing : []
4101
4103
  ];
4102
- return missing.length === 0 ? Effect46.void : Effect46.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."));
4104
+ return missing.length === 0 ? Effect47.void : Effect47.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."));
4103
4105
  };
4104
4106
  var handlers15 = {
4105
- list: () => Effect46.succeed([]),
4106
- read: ({ olds, output }) => (output === undefined ? refuse2(olds) : Effect46.void).pipe(Effect46.andThen(readLive2(olds)), Effect46.map((live) => live === undefined ? undefined : { ...live, sealed: output?.sealed ?? "" })),
4107
+ list: () => Effect47.succeed([]),
4108
+ read: ({ olds, output }) => (output === undefined ? refuse2(olds) : Effect47.void).pipe(Effect47.andThen(readLive2(olds)), Effect47.map((live) => live === undefined ? undefined : { ...live, sealed: output?.sealed ?? "" })),
4107
4109
  diff: ({
4108
4110
  news,
4109
4111
  olds,
4110
4112
  output
4111
- }) => Effect46.gen(function* () {
4113
+ }) => Effect47.gen(function* () {
4112
4114
  if (output === undefined || !isResolved11(news))
4113
4115
  return;
4114
4116
  if (olds !== undefined && (olds.type !== news.type || olds.name !== news.name)) {
@@ -4120,7 +4122,7 @@ var handlers15 = {
4120
4122
  return { action: "update" };
4121
4123
  return toCarry(live, news, resolveGroups(news), output.sealed) === undefined ? { action: "noop" } : { action: "update" };
4122
4124
  }),
4123
- reconcile: ({ news, output }) => Effect46.gen(function* () {
4125
+ reconcile: ({ news, output }) => Effect47.gen(function* () {
4124
4126
  yield* refuse2(news);
4125
4127
  const groups = resolveGroups(news);
4126
4128
  const live = yield* readLive2(news);
@@ -4146,7 +4148,7 @@ var handlers15 = {
4146
4148
  }
4147
4149
  const after = yield* readLive2(news);
4148
4150
  if (after === undefined) {
4149
- return yield* Effect46.die(new Error(`${path(news)}: the write returned no error but the target is still absent.`));
4151
+ return yield* Effect47.die(new Error(`${path(news)}: the write returned no error but the target is still absent.`));
4150
4152
  }
4151
4153
  return { ...after, sealed };
4152
4154
  }),
@@ -4155,11 +4157,11 @@ var handlers15 = {
4155
4157
 
4156
4158
  // src/proxmox/pbs-notification-target.ts
4157
4159
  var PbsNotificationTarget = Resource21("Pbs.NotificationTarget");
4158
- var PbsNotificationTargetProvider = () => Provider21.effect(PbsNotificationTarget, Effect47.succeed(PbsNotificationTarget.Provider.of(handlers15)));
4160
+ var PbsNotificationTargetProvider = () => Provider21.effect(PbsNotificationTarget, Effect48.succeed(PbsNotificationTarget.Provider.of(handlers15)));
4159
4161
  // src/proxmox/pbs-prune-job.ts
4160
4162
  import { Resource as Resource22 } from "alchemy";
4161
4163
  import * as Provider22 from "alchemy/Provider";
4162
- import * as Effect48 from "effect/Effect";
4164
+ import * as Effect49 from "effect/Effect";
4163
4165
 
4164
4166
  // src/proxmox/pbs-prune-job-form.ts
4165
4167
  var KEEP_KEYS = [
@@ -4235,11 +4237,11 @@ var handlers16 = pveHandlers({
4235
4237
  path: (props) => `config/prune/${props.id}`,
4236
4238
  updateForm: updateBody3
4237
4239
  });
4238
- var PbsPruneJobProvider = () => Provider22.effect(PbsPruneJob, Effect48.succeed(PbsPruneJob.Provider.of(handlers16)));
4240
+ var PbsPruneJobProvider = () => Provider22.effect(PbsPruneJob, Effect49.succeed(PbsPruneJob.Provider.of(handlers16)));
4239
4241
  // src/proxmox/pbs-sync-job.ts
4240
4242
  import { Resource as Resource23 } from "alchemy";
4241
4243
  import * as Provider23 from "alchemy/Provider";
4242
- import * as Effect49 from "effect/Effect";
4244
+ import * as Effect50 from "effect/Effect";
4243
4245
 
4244
4246
  // src/proxmox/pbs-sync-job-form.ts
4245
4247
  var UNSET4 = -1;
@@ -4316,11 +4318,11 @@ var handlers17 = pveHandlers({
4316
4318
 
4317
4319
  // src/proxmox/pbs-sync-job.ts
4318
4320
  var PbsSyncJob = Resource23("Pbs.SyncJob");
4319
- var PbsSyncJobProvider = () => Provider23.effect(PbsSyncJob, Effect49.succeed(PbsSyncJob.Provider.of(handlers17)));
4321
+ var PbsSyncJobProvider = () => Provider23.effect(PbsSyncJob, Effect50.succeed(PbsSyncJob.Provider.of(handlers17)));
4320
4322
  // src/proxmox/pbs-verify-job.ts
4321
4323
  import { Resource as Resource24 } from "alchemy";
4322
4324
  import * as Provider24 from "alchemy/Provider";
4323
- import * as Effect50 from "effect/Effect";
4325
+ import * as Effect51 from "effect/Effect";
4324
4326
 
4325
4327
  // src/proxmox/pbs-verify-job-form.ts
4326
4328
  var rechecks = (ignoreVerified, outdatedAfter) => {
@@ -4365,11 +4367,11 @@ var handlers18 = pveHandlers({
4365
4367
  path: (props) => `config/verify/${props.id}`,
4366
4368
  updateForm: shape7
4367
4369
  });
4368
- var PbsVerifyJobProvider = () => Provider24.effect(PbsVerifyJob, Effect50.succeed(PbsVerifyJob.Provider.of(handlers18)));
4370
+ var PbsVerifyJobProvider = () => Provider24.effect(PbsVerifyJob, Effect51.succeed(PbsVerifyJob.Provider.of(handlers18)));
4369
4371
  // src/proxmox/pool.ts
4370
4372
  import { Resource as Resource25 } from "alchemy";
4371
4373
  import * as Provider25 from "alchemy/Provider";
4372
- import * as Effect51 from "effect/Effect";
4374
+ import * as Effect52 from "effect/Effect";
4373
4375
  var ProxmoxPool = Resource25("Proxmox.Pool");
4374
4376
  var poolCreateForm = (props) => ({
4375
4377
  comment: props.comment ?? "",
@@ -4394,7 +4396,7 @@ var handlers19 = pveHandlers({
4394
4396
  path: (props) => `pools/${props.poolid}`,
4395
4397
  updateForm: poolUpdateForm
4396
4398
  });
4397
- var ProxmoxPoolProvider = () => Provider25.effect(ProxmoxPool, Effect51.succeed(ProxmoxPool.Provider.of(handlers19)));
4399
+ var ProxmoxPoolProvider = () => Provider25.effect(ProxmoxPool, Effect52.succeed(ProxmoxPool.Provider.of(handlers19)));
4398
4400
  // src/proxmox/provision-baseline.ts
4399
4401
  var PROVISION_PRIVILEGES = Object.freeze([
4400
4402
  "Datastore.Allocate",
@@ -4587,14 +4589,14 @@ echo 'provision baseline: done. Next: point the OpenBao proxmox mount at these u
4587
4589
  // src/proxmox/provision-declare.ts
4588
4590
  import { adopt } from "alchemy/AdoptPolicy";
4589
4591
  import * as RemovalPolicy from "alchemy/RemovalPolicy";
4590
- import * as Effect54 from "effect/Effect";
4592
+ import * as Effect56 from "effect/Effect";
4591
4593
 
4592
4594
  // src/proxmox/role.ts
4593
4595
  import { Resource as Resource26 } from "alchemy";
4594
4596
  import { isResolved as isResolved12 } from "alchemy/Diff";
4595
4597
  import * as Provider26 from "alchemy/Provider";
4596
- import * as access4 from "@distilled.cloud/proxmox/access";
4597
- import * as Effect52 from "effect/Effect";
4598
+ import * as access5 from "@distilled.cloud/proxmox/access";
4599
+ import * as Effect53 from "effect/Effect";
4598
4600
 
4599
4601
  // src/proxmox/role-wire.ts
4600
4602
  var ROLE_CREATE = "pve:POST /access/roles";
@@ -4617,21 +4619,19 @@ var matches5 = (attributes2, props) => canonical2(attributes2.privs).join(",") =
4617
4619
 
4618
4620
  // src/proxmox/role.ts
4619
4621
  var ProxmoxRole = Resource26("Proxmox.Role");
4620
- var readRole = (props) => readOrUnreadable(runPve(props.target, "read", false, access4.listAccessRoles({}))).pipe(Effect52.map((rows) => {
4622
+ var readRole = (props) => readOrUnreadable(runPve(props.target, "read", false, access5.listAccessRoles({}))).pipe(Effect53.map((rows) => {
4621
4623
  if (rows === UNREADABLE)
4622
4624
  return UNREADABLE;
4623
4625
  const row = find2(rows, props.roleid);
4624
4626
  return row === undefined ? undefined : attributesOf5(row, props);
4625
- }), Effect52.orElseSucceed(() => {
4626
- return;
4627
4627
  }));
4628
4628
  var dropUnreadable4 = (live) => live === UNREADABLE ? undefined : live;
4629
- var ProxmoxRoleProvider = () => Provider26.effect(ProxmoxRole, Effect52.succeed(ProxmoxRole.Provider.of({
4630
- list: () => Effect52.succeed([]),
4631
- read: Effect52.fn(function* ({ olds }) {
4629
+ var ProxmoxRoleProvider = () => Provider26.effect(ProxmoxRole, Effect53.succeed(ProxmoxRole.Provider.of({
4630
+ list: () => Effect53.succeed([]),
4631
+ read: Effect53.fn(function* ({ olds }) {
4632
4632
  return dropUnreadable4(yield* readRole(olds));
4633
4633
  }),
4634
- diff: Effect52.fn(function* ({ news, output }) {
4634
+ diff: Effect53.fn(function* ({ news, output }) {
4635
4635
  if (!isResolved12(news))
4636
4636
  return;
4637
4637
  yield* guardWrite2(ROLE_CREATE, createForm6(news), output === undefined);
@@ -4649,23 +4649,23 @@ var ProxmoxRoleProvider = () => Provider26.effect(ProxmoxRole, Effect52.succeed(
4649
4649
  }
4650
4650
  return matches5(live, news) ? { action: "noop" } : { action: "update" };
4651
4651
  }),
4652
- reconcile: Effect52.fn(function* ({ news }) {
4652
+ reconcile: Effect53.fn(function* ({ news }) {
4653
4653
  const before = dropUnreadable4(yield* readRole(news));
4654
4654
  yield* guardWrite2(ROLE_CREATE, createForm6(news), before === undefined);
4655
4655
  yield* guardWrite2(ROLE_UPDATE, updateForm3(news), false);
4656
4656
  if (before === undefined) {
4657
- yield* runPve(news.target, "provision", true, access4.createAccessRole(createForm6(news)));
4657
+ yield* runPve(news.target, "provision", true, access5.createAccessRole(createForm6(news)));
4658
4658
  } else if (!matches5(before, news)) {
4659
- yield* runPve(news.target, "provision", true, access4.putAccessRole(updateForm3(news)));
4659
+ yield* runPve(news.target, "provision", true, access5.putAccessRole(updateForm3(news)));
4660
4660
  }
4661
4661
  const after = dropUnreadable4(yield* readRole(news));
4662
4662
  if (after === undefined) {
4663
- return yield* Effect52.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."));
4663
+ return yield* Effect53.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."));
4664
4664
  }
4665
4665
  return after;
4666
4666
  }),
4667
- delete: Effect52.fn(function* ({ olds }) {
4668
- yield* runPve(olds.target, "provision", true, access4.deleteAccessRole({ roleid: olds.roleid }));
4667
+ delete: Effect53.fn(function* ({ olds }) {
4668
+ yield* runPve(olds.target, "provision", true, access5.deleteAccessRole({ roleid: olds.roleid }));
4669
4669
  })
4670
4670
  })));
4671
4671
 
@@ -4673,10 +4673,12 @@ var ProxmoxRoleProvider = () => Provider26.effect(ProxmoxRole, Effect52.succeed(
4673
4673
  import { Resource as Resource27 } from "alchemy";
4674
4674
  import { isResolved as isResolved13 } from "alchemy/Diff";
4675
4675
  import * as Provider27 from "alchemy/Provider";
4676
- import * as access5 from "@distilled.cloud/proxmox/access";
4677
- import * as Effect53 from "effect/Effect";
4676
+ import * as access7 from "@distilled.cloud/proxmox/access";
4677
+ import * as Effect55 from "effect/Effect";
4678
4678
 
4679
4679
  // src/proxmox/user-wire.ts
4680
+ import * as access6 from "@distilled.cloud/proxmox/access";
4681
+ import * as Effect54 from "effect/Effect";
4680
4682
  var USER_CREATE = "pve:POST /access/users";
4681
4683
  var USER_UPDATE = "pve:PUT /access/users/{userid}";
4682
4684
  var int2 = (value) => {
@@ -4718,26 +4720,27 @@ var attributesOf6 = (live, props) => ({
4718
4720
  userid: props.userid
4719
4721
  });
4720
4722
  var matches6 = (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(",");
4721
-
4722
- // src/proxmox/user.ts
4723
- var ProxmoxUser = Resource27("Proxmox.User");
4724
- var readUser = (props) => readOrUnreadable(runPve(props.target, "read", false, access5.getAccessUser(props))).pipe(Effect53.map((live) => live === UNREADABLE ? UNREADABLE : attributesOf6(live, props)), Effect53.orElseSucceed(() => {
4723
+ var readUserOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, access6.getAccessUser({ userid: props.userid }))).pipe(Effect54.map((live) => live === UNREADABLE ? UNREADABLE : attributesOf6(live, props)));
4724
+ var readUser = (props) => readUserOrFail(props).pipe(Effect54.orElseSucceed(() => {
4725
4725
  return;
4726
4726
  }));
4727
4727
  var dropUnreadable5 = (live) => live === UNREADABLE ? undefined : live;
4728
- var ProxmoxUserProvider = () => Provider27.effect(ProxmoxUser, Effect53.succeed(ProxmoxUser.Provider.of({
4729
- list: () => Effect53.succeed([]),
4730
- read: Effect53.fn(function* ({ olds }) {
4731
- return dropUnreadable5(yield* readUser(olds));
4728
+
4729
+ // src/proxmox/user.ts
4730
+ var ProxmoxUser = Resource27("Proxmox.User");
4731
+ var ProxmoxUserProvider = () => Provider27.effect(ProxmoxUser, Effect55.succeed(ProxmoxUser.Provider.of({
4732
+ list: () => Effect55.succeed([]),
4733
+ read: Effect55.fn(function* ({ olds, output }) {
4734
+ return dropUnreadable5(yield* output === undefined ? readUser(olds) : readUserOrFail(olds));
4732
4735
  }),
4733
- diff: Effect53.fn(function* ({ news, output }) {
4736
+ diff: Effect55.fn(function* ({ news, output }) {
4734
4737
  if (!isResolved13(news))
4735
4738
  return;
4736
4739
  yield* guardWrite2(USER_CREATE, createForm7(news), output === undefined);
4737
4740
  yield* guardWrite2(USER_UPDATE, updateForm4(news), false);
4738
4741
  if (output === undefined)
4739
4742
  return;
4740
- const live = yield* readUser(news);
4743
+ const live = yield* readUserOrFail(news);
4741
4744
  if (live === UNREADABLE) {
4742
4745
  yield* unreadableWarning("Proxmox.User", news.userid);
4743
4746
  return { action: "noop" };
@@ -4748,29 +4751,29 @@ var ProxmoxUserProvider = () => Provider27.effect(ProxmoxUser, Effect53.succeed(
4748
4751
  }
4749
4752
  return matches6(live, news) ? { action: "noop" } : { action: "update" };
4750
4753
  }),
4751
- reconcile: Effect53.fn(function* ({ news }) {
4754
+ reconcile: Effect55.fn(function* ({ news }) {
4752
4755
  const before = dropUnreadable5(yield* readUser(news));
4753
4756
  yield* guardWrite2(USER_CREATE, createForm7(news), before === undefined);
4754
4757
  yield* guardWrite2(USER_UPDATE, updateForm4(news), false);
4755
4758
  if (before === undefined) {
4756
- yield* runPve(news.target, "provision", true, access5.createAccessUser(createForm7(news)));
4759
+ yield* runPve(news.target, "provision", true, access7.createAccessUser(createForm7(news)));
4757
4760
  } else if (!matches6(before, news)) {
4758
- yield* runPve(news.target, "provision", true, access5.putAccessUser(updateForm4(news)));
4761
+ yield* runPve(news.target, "provision", true, access7.putAccessUser(updateForm4(news)));
4759
4762
  }
4760
4763
  const after = dropUnreadable5(yield* readUser(news));
4761
4764
  if (after === undefined) {
4762
- return yield* Effect53.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."));
4765
+ return yield* Effect55.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."));
4763
4766
  }
4764
4767
  return after;
4765
4768
  }),
4766
- delete: Effect53.fn(function* ({ olds }) {
4767
- yield* runPve(olds.target, "provision", true, access5.deleteAccessUser({ userid: olds.userid }));
4769
+ delete: Effect55.fn(function* ({ olds }) {
4770
+ yield* runPve(olds.target, "provision", true, access7.deleteAccessUser({ userid: olds.userid }));
4768
4771
  })
4769
4772
  })));
4770
4773
 
4771
4774
  // src/proxmox/provision-declare.ts
4772
- var declareProvisionBaseline = (id, target, names2 = {}, options = {}) => Effect54.gen(function* () {
4773
- const baseline = yield* Effect54.try({
4775
+ var declareProvisionBaseline = (id, target, names2 = {}, options = {}) => Effect56.gen(function* () {
4776
+ const baseline = yield* Effect56.try({
4774
4777
  catch: (cause) => cause instanceof Error ? cause : new Error(String(cause)),
4775
4778
  try: () => provisionBaseline(names2)
4776
4779
  });
@@ -4784,13 +4787,13 @@ var declareProvisionBaseline = (id, target, names2 = {}, options = {}) => Effect
4784
4787
  target
4785
4788
  }));
4786
4789
  const group = yield* owned(ProxmoxGroup(`${id}-mint-group`, { ...baseline.group, target }));
4787
- const users = yield* Effect54.all(baseline.users.map((user) => owned(ProxmoxUser(`${id}-${user.lane}-user`, {
4790
+ const users = yield* Effect56.all(baseline.users.map((user) => owned(ProxmoxUser(`${id}-${user.lane}-user`, {
4788
4791
  comment: user.comment,
4789
4792
  groups: [...user.groups],
4790
4793
  target,
4791
4794
  userid: user.userid
4792
4795
  }))));
4793
- const grants = yield* Effect54.all(baseline.grants.map((grant) => owned(ProxmoxAcl(`${id}-${grant.lane}-grant`, {
4796
+ const grants = yield* Effect56.all(baseline.grants.map((grant) => owned(ProxmoxAcl(`${id}-${grant.lane}-grant`, {
4794
4797
  path: "/",
4795
4798
  propagate: true,
4796
4799
  roleid: grant.roleid,
@@ -4803,7 +4806,7 @@ var declareProvisionBaseline = (id, target, names2 = {}, options = {}) => Effect
4803
4806
  // src/proxmox/qemu.ts
4804
4807
  import { Resource as Resource28 } from "alchemy";
4805
4808
  import * as Provider28 from "alchemy/Provider";
4806
- import * as Effect55 from "effect/Effect";
4809
+ import * as Effect57 from "effect/Effect";
4807
4810
  var ProxmoxVm = Resource28("Proxmox.Vm");
4808
4811
  var createForm8 = (props) => ({ ...shape9(props), vmid: String(props.vmid) });
4809
4812
  var shape9 = (props) => ({
@@ -4834,11 +4837,11 @@ var handlers20 = pveHandlers({
4834
4837
  path: (props) => `nodes/${props.node}/qemu/${String(props.vmid)}/config`,
4835
4838
  updateForm: shape9
4836
4839
  });
4837
- var ProxmoxVmProvider = () => Provider28.effect(ProxmoxVm, Effect55.succeed(ProxmoxVm.Provider.of(handlers20)));
4840
+ var ProxmoxVmProvider = () => Provider28.effect(ProxmoxVm, Effect57.succeed(ProxmoxVm.Provider.of(handlers20)));
4838
4841
  // src/proxmox/replication-job.ts
4839
4842
  import { Resource as Resource29 } from "alchemy";
4840
4843
  import * as Provider29 from "alchemy/Provider";
4841
- import * as Effect56 from "effect/Effect";
4844
+ import * as Effect58 from "effect/Effect";
4842
4845
 
4843
4846
  // src/proxmox/replication-job-form.ts
4844
4847
  var DEFAULT_SCHEDULE = "*/15";
@@ -4892,15 +4895,15 @@ var handlers21 = pveHandlers({
4892
4895
  path: (props) => `cluster/replication/${jobId(props)}`,
4893
4896
  updateForm: updateBody5
4894
4897
  });
4895
- var ProxmoxReplicationJobProvider = () => Provider29.effect(ProxmoxReplicationJob, Effect56.succeed(ProxmoxReplicationJob.Provider.of(handlers21)));
4898
+ var ProxmoxReplicationJobProvider = () => Provider29.effect(ProxmoxReplicationJob, Effect58.succeed(ProxmoxReplicationJob.Provider.of(handlers21)));
4896
4899
  // src/proxmox/sdn-apply.ts
4897
4900
  import { Resource as Resource30 } from "alchemy";
4898
4901
  import { isResolved as isResolved14 } from "alchemy/Diff";
4899
4902
  import * as Provider30 from "alchemy/Provider";
4900
- import * as Effect58 from "effect/Effect";
4903
+ import * as Effect60 from "effect/Effect";
4901
4904
 
4902
4905
  // src/proxmox/sdn-apply-read.ts
4903
- import * as Effect57 from "effect/Effect";
4906
+ import * as Effect59 from "effect/Effect";
4904
4907
  var MARKED = [
4905
4908
  "cluster/sdn/zones",
4906
4909
  "cluster/sdn/vnets",
@@ -4909,7 +4912,7 @@ var MARKED = [
4909
4912
  "cluster/sdn/route-maps"
4910
4913
  ];
4911
4914
  var subsystemAbsent = (error) => error instanceof PveError && error.status === 501;
4912
- var markedPending = (target) => Effect57.all(MARKED.map((collection2) => pve(target, "read", "GET", `${collection2}?pending=1`).pipe(Effect57.map((rows) => (rows ?? []).filter((row) => row.state !== undefined).length), Effect57.catchIf(subsystemAbsent, () => Effect57.succeed(0)))), { concurrency: "unbounded" }).pipe(Effect57.map((counts) => counts.reduce((total, count2) => total + count2, 0)));
4915
+ var markedPending = (target) => Effect59.all(MARKED.map((collection2) => pve(target, "read", "GET", `${collection2}?pending=1`).pipe(Effect59.map((rows) => (rows ?? []).filter((row) => row.state !== undefined).length), Effect59.catchIf(subsystemAbsent, () => Effect59.succeed(0)))), { concurrency: "unbounded" }).pipe(Effect59.map((counts) => counts.reduce((total, count2) => total + count2, 0)));
4913
4916
  var fabricStaged = (staged, running) => {
4914
4917
  if (staged === undefined && running === undefined)
4915
4918
  return 0;
@@ -4917,9 +4920,9 @@ var fabricStaged = (staged, running) => {
4917
4920
  return "inconsistent";
4918
4921
  return staged === running ? 0 : 1;
4919
4922
  };
4920
- var fabricPending = (target) => Effect57.all(["pending", "running"].map((view) => pve(target, "read", "GET", `cluster/sdn/fabrics/all?${view}=1`).pipe(Effect57.map(canonical3), Effect57.catchIf(subsystemAbsent, () => Effect57.succeed(undefined)))), { concurrency: "unbounded" }).pipe(Effect57.flatMap(([staged, running]) => {
4923
+ var fabricPending = (target) => Effect59.all(["pending", "running"].map((view) => pve(target, "read", "GET", `cluster/sdn/fabrics/all?${view}=1`).pipe(Effect59.map(canonical3), Effect59.catchIf(subsystemAbsent, () => Effect59.succeed(undefined)))), { concurrency: "unbounded" }).pipe(Effect59.flatMap(([staged, running]) => {
4921
4924
  const verdict = fabricStaged(staged, running);
4922
- return verdict === "inconsistent" ? Effect57.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.")) : Effect57.succeed(verdict);
4925
+ return verdict === "inconsistent" ? Effect59.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.")) : Effect59.succeed(verdict);
4923
4926
  }));
4924
4927
  var canonical3 = (value) => JSON.stringify(sortDeep(value));
4925
4928
  var sortDeep = (value) => {
@@ -4932,23 +4935,23 @@ var sortDeep = (value) => {
4932
4935
  }
4933
4936
  return value;
4934
4937
  };
4935
- var sdnPendingCount = (target) => Effect57.all([markedPending(target), fabricPending(target)], { concurrency: "unbounded" }).pipe(Effect57.map(([marked, fabric]) => marked + fabric));
4938
+ var sdnPendingCount = (target) => Effect59.all([markedPending(target), fabricPending(target)], { concurrency: "unbounded" }).pipe(Effect59.map(([marked, fabric]) => marked + fabric));
4936
4939
 
4937
4940
  // src/proxmox/sdn-apply.ts
4938
4941
  var ProxmoxSdnApply = Resource30("Proxmox.SdnApply");
4939
- var read3 = (props) => sdnPendingCount(props.target).pipe(Effect58.map((pending) => ({ pending })));
4940
- var ProxmoxSdnApplyProvider = () => Provider30.effect(ProxmoxSdnApply, Effect58.succeed(ProxmoxSdnApply.Provider.of({
4941
- list: () => Effect58.succeed([]),
4942
- read: Effect58.fn(function* ({ olds }) {
4942
+ var read3 = (props) => sdnPendingCount(props.target).pipe(Effect60.map((pending) => ({ pending })));
4943
+ var ProxmoxSdnApplyProvider = () => Provider30.effect(ProxmoxSdnApply, Effect60.succeed(ProxmoxSdnApply.Provider.of({
4944
+ list: () => Effect60.succeed([]),
4945
+ read: Effect60.fn(function* ({ olds }) {
4943
4946
  return yield* read3(olds);
4944
4947
  }),
4945
- diff: Effect58.fn(function* ({ news }) {
4948
+ diff: Effect60.fn(function* ({ news }) {
4946
4949
  if (!isResolved14(news))
4947
4950
  return;
4948
4951
  const { pending } = yield* read3(news);
4949
4952
  return pending === 0 ? { action: "noop" } : { action: "update" };
4950
4953
  }),
4951
- reconcile: Effect58.fn(function* ({ news }) {
4954
+ reconcile: Effect60.fn(function* ({ news }) {
4952
4955
  const staged = yield* read3(news);
4953
4956
  if (staged.pending === 0)
4954
4957
  return staged;
@@ -4956,16 +4959,16 @@ var ProxmoxSdnApplyProvider = () => Provider30.effect(ProxmoxSdnApply, Effect58.
4956
4959
  yield* pve(news.target, "provision", "PUT", "cluster/sdn");
4957
4960
  const after = yield* read3(news);
4958
4961
  if (after.pending !== 0) {
4959
- return yield* Effect58.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."));
4962
+ return yield* Effect60.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."));
4960
4963
  }
4961
4964
  return after;
4962
4965
  }),
4963
- delete: () => Effect58.void
4966
+ delete: () => Effect60.void
4964
4967
  })));
4965
4968
  // src/proxmox/sdn-subnet.ts
4966
4969
  import { Resource as Resource31 } from "alchemy";
4967
4970
  import * as Provider31 from "alchemy/Provider";
4968
- import * as Effect59 from "effect/Effect";
4971
+ import * as Effect61 from "effect/Effect";
4969
4972
 
4970
4973
  // src/proxmox/sdn-subnet-form.ts
4971
4974
  var subnetId = (props) => `${props.zone}-${props.cidr.replace("/", "-")}`;
@@ -5025,11 +5028,11 @@ var handlers22 = pveHandlers({
5025
5028
  path: (props) => `cluster/sdn/vnets/${props.vnet}/subnets/${subnetId(props)}`,
5026
5029
  updateForm: updateForm5
5027
5030
  });
5028
- var ProxmoxSdnSubnetProvider = () => Provider31.effect(ProxmoxSdnSubnet, Effect59.succeed(ProxmoxSdnSubnet.Provider.of(handlers22)));
5031
+ var ProxmoxSdnSubnetProvider = () => Provider31.effect(ProxmoxSdnSubnet, Effect61.succeed(ProxmoxSdnSubnet.Provider.of(handlers22)));
5029
5032
  // src/proxmox/sdn-vnet.ts
5030
5033
  import { Resource as Resource32 } from "alchemy";
5031
5034
  import * as Provider32 from "alchemy/Provider";
5032
- import * as Effect60 from "effect/Effect";
5035
+ import * as Effect62 from "effect/Effect";
5033
5036
  var ProxmoxSdnVnet = Resource32("Proxmox.SdnVnet");
5034
5037
  var tagOf = (value) => typeof value === "number" ? value : undefined;
5035
5038
  var shape11 = (props) => {
@@ -5067,11 +5070,11 @@ var handlers23 = pveHandlers({
5067
5070
  path: (props) => `cluster/sdn/vnets/${props.vnet}`,
5068
5071
  updateForm: updateForm6
5069
5072
  });
5070
- var ProxmoxSdnVnetProvider = () => Provider32.effect(ProxmoxSdnVnet, Effect60.succeed(ProxmoxSdnVnet.Provider.of(handlers23)));
5073
+ var ProxmoxSdnVnetProvider = () => Provider32.effect(ProxmoxSdnVnet, Effect62.succeed(ProxmoxSdnVnet.Provider.of(handlers23)));
5071
5074
  // src/proxmox/sdn-zone.ts
5072
5075
  import { Resource as Resource33 } from "alchemy";
5073
5076
  import * as Provider33 from "alchemy/Provider";
5074
- import * as Effect61 from "effect/Effect";
5077
+ import * as Effect63 from "effect/Effect";
5075
5078
  var ProxmoxSdnZone = Resource33("Proxmox.SdnZone");
5076
5079
  var sameIpam = (live, declared2) => (live === "" ? "pve" : live) === (declared2 === undefined || declared2 === "" ? "pve" : declared2);
5077
5080
  var body6 = (props) => ({
@@ -5124,67 +5127,126 @@ var handlers24 = pveHandlers({
5124
5127
  return withClears(fields, clear);
5125
5128
  }
5126
5129
  });
5127
- var ProxmoxSdnZoneProvider = () => Provider33.effect(ProxmoxSdnZone, Effect61.succeed(ProxmoxSdnZone.Provider.of(handlers24)));
5130
+ var ProxmoxSdnZoneProvider = () => Provider33.effect(ProxmoxSdnZone, Effect63.succeed(ProxmoxSdnZone.Provider.of(handlers24)));
5128
5131
  // src/proxmox/storage.ts
5129
5132
  import { Resource as Resource34 } from "alchemy";
5133
+ import { isResolved as isResolved15 } from "alchemy/Diff";
5130
5134
  import * as Provider34 from "alchemy/Provider";
5131
- import * as Effect62 from "effect/Effect";
5132
- var ProxmoxStorage = Resource34("Proxmox.Storage", {
5133
- defaultRemovalPolicy: "retain"
5134
- });
5135
- var str2 = (value, fallback = "") => typeof value === "string" ? value : fallback;
5135
+ import * as storage2 from "@distilled.cloud/proxmox/storage";
5136
+ import * as Effect65 from "effect/Effect";
5137
+
5138
+ // src/proxmox/storage-form.ts
5139
+ var STORAGE_CREATE = "pve:POST /storage";
5140
+ var STORAGE_UPDATE = "pve:PUT /storage/{storage}";
5136
5141
  var field6 = (name, value) => value === undefined ? {} : { [name]: value };
5137
5142
  var locatorForm = (locator) => ({ ...locator });
5138
- var tokens = (value) => value.split(",").map((part) => part.trim()).filter((part) => part !== "").sort().join(",");
5139
- var sameList2 = (declared2, live) => declared2 === undefined || tokens(declared2) === tokens(live);
5140
- var same7 = (declared2, live) => declared2 === undefined || declared2 === live;
5143
+ var underscored = (form) => Object.fromEntries(Object.entries(form).map(([key, value]) => [key.replaceAll("-", "_"), value]));
5141
5144
  var mutable2 = (props) => ({
5142
5145
  ...field6("comment", props.comment),
5143
5146
  ...field6("content", props.content),
5144
5147
  ...field6("disable", flag(props.disable)),
5145
- ...field6("maxfiles", props.maxfiles === undefined ? undefined : String(props.maxfiles)),
5146
5148
  ...field6("nodes", props.nodes),
5147
5149
  ...field6("preallocation", props.preallocation),
5148
5150
  ...field6("prune-backups", props["prune-backups"]),
5149
5151
  ...field6("shared", flag(props.shared))
5150
5152
  });
5151
- var handlers25 = pveHandlers({
5152
- readRole: "provision",
5153
- attributes: (live, props) => ({
5154
- comment: str2(live["comment"]),
5155
- content: str2(live["content"]),
5156
- disable: bool(live["disable"]),
5157
- maxfiles: typeof live["maxfiles"] === "number" ? live["maxfiles"] : -1,
5158
- nodes: str2(live["nodes"]),
5159
- preallocation: str2(live["preallocation"]),
5160
- "prune-backups": str2(live["prune-backups"]),
5161
- shared: bool(live["shared"]),
5153
+ var createForm10 = (props) => ({
5154
+ ...locatorForm(props.locator),
5155
+ ...mutable2(props),
5156
+ storage: props.storage,
5157
+ type: props.type
5158
+ });
5159
+ var updateForm7 = (props) => ({
5160
+ ...mutable2(props),
5161
+ storage: props.storage
5162
+ });
5163
+ var toDistilledCreate = (props) => underscored(createForm10(props));
5164
+ var toDistilledUpdate = (props) => underscored(updateForm7(props));
5165
+
5166
+ // src/proxmox/storage-wire.ts
5167
+ import * as storage from "@distilled.cloud/proxmox/storage";
5168
+ import * as Effect64 from "effect/Effect";
5169
+ var str2 = (value, fallback = "") => typeof value === "string" ? value : fallback;
5170
+ var tokens = (value) => value.split(",").map((part) => part.trim()).filter((part) => part !== "").sort().join(",");
5171
+ var sameList2 = (declared2, live) => declared2 === undefined || tokens(declared2) === tokens(live);
5172
+ var same7 = (declared2, live) => declared2 === undefined || declared2 === live;
5173
+ var attributesOf7 = (live, props) => {
5174
+ const data = live;
5175
+ return {
5176
+ comment: str2(data["comment"]),
5177
+ content: str2(data["content"]),
5178
+ disable: bool(data["disable"]),
5179
+ nodes: str2(data["nodes"]),
5180
+ preallocation: str2(data["preallocation"]),
5181
+ "prune-backups": str2(data["prune-backups"]),
5182
+ shared: bool(data["shared"]),
5162
5183
  storage: props.storage,
5163
- type: str2(live["type"], props.type)
5184
+ type: str2(data["type"], props.type)
5185
+ };
5186
+ };
5187
+ var readStorageOrFail = (props) => readOrUnreadable(runPve(props.target, "provision", false, storage.getStorage({ storage: props.storage }))).pipe(Effect64.map((live) => live === UNREADABLE ? UNREADABLE : attributesOf7(live, props)));
5188
+ var readStorage = (props) => readStorageOrFail(props).pipe(Effect64.orElseSucceed(() => {
5189
+ return;
5190
+ }));
5191
+ var dropUnreadable6 = (live) => live === UNREADABLE ? undefined : live;
5192
+ var matches7 = (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);
5193
+
5194
+ // src/proxmox/storage.ts
5195
+ var ProxmoxStorage = Resource34("Proxmox.Storage", {
5196
+ defaultRemovalPolicy: "retain"
5197
+ });
5198
+ var ProxmoxStorageProvider = () => Provider34.effect(ProxmoxStorage, Effect65.succeed(ProxmoxStorage.Provider.of({
5199
+ list: () => Effect65.succeed([]),
5200
+ read: Effect65.fn(function* ({ olds, output }) {
5201
+ return dropUnreadable6(yield* output === undefined ? readStorage(olds) : readStorageOrFail(olds));
5164
5202
  }),
5165
- collection: () => "storage",
5166
- createForm: (props) => ({
5167
- ...locatorForm(props.locator),
5168
- ...mutable2(props),
5169
- storage: props.storage,
5170
- type: props.type
5203
+ diff: Effect65.fn(function* ({ news, output }) {
5204
+ if (!isResolved15(news))
5205
+ return;
5206
+ yield* guardWrite2(STORAGE_CREATE, createForm10(news), output === undefined);
5207
+ yield* guardWrite2(STORAGE_UPDATE, updateForm7(news), false);
5208
+ if (output === undefined)
5209
+ return;
5210
+ const live = yield* readStorageOrFail(news);
5211
+ if (live === UNREADABLE) {
5212
+ yield* unreadableWarning("Proxmox.Storage", news.storage);
5213
+ return { action: "noop" };
5214
+ }
5215
+ if (live === undefined) {
5216
+ yield* guardWrite2(STORAGE_CREATE, createForm10(news), true);
5217
+ return { action: "update" };
5218
+ }
5219
+ return matches7(live, news) ? { action: "noop" } : { action: "update" };
5171
5220
  }),
5172
- endpoint: { create: "pve:POST /storage", update: "pve:PUT /storage/{storage}" },
5173
- matches: (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) && same7(props.maxfiles, attributes2.maxfiles),
5174
- path: (props) => `storage/${props.storage}`,
5175
- updateForm: mutable2
5176
- });
5177
- var ProxmoxStorageProvider = () => Provider34.effect(ProxmoxStorage, Effect62.succeed(ProxmoxStorage.Provider.of(handlers25)));
5221
+ reconcile: Effect65.fn(function* ({ news }) {
5222
+ const before = dropUnreadable6(yield* readStorage(news));
5223
+ yield* guardWrite2(STORAGE_CREATE, createForm10(news), before === undefined);
5224
+ yield* guardWrite2(STORAGE_UPDATE, updateForm7(news), false);
5225
+ if (before === undefined) {
5226
+ yield* runPve(news.target, "provision", true, storage2.createStorage(toDistilledCreate(news)));
5227
+ } else if (!matches7(before, news)) {
5228
+ yield* runPve(news.target, "provision", true, storage2.putStorage(toDistilledUpdate(news)));
5229
+ }
5230
+ const after = dropUnreadable6(yield* readStorage(news));
5231
+ if (after === undefined) {
5232
+ return yield* Effect65.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."));
5233
+ }
5234
+ return after;
5235
+ }),
5236
+ delete: Effect65.fn(function* ({ olds }) {
5237
+ yield* runPve(olds.target, "provision", true, storage2.deleteStorage({ storage: olds.storage }));
5238
+ })
5239
+ })));
5178
5240
  // src/proxmox/zfs-pool.ts
5179
5241
  import { Resource as Resource35 } from "alchemy";
5180
5242
  import * as Provider35 from "alchemy/Provider";
5181
- import * as Effect64 from "effect/Effect";
5243
+ import * as Effect67 from "effect/Effect";
5182
5244
 
5183
5245
  // src/proxmox/zfs-pool-write.ts
5184
- import * as Effect63 from "effect/Effect";
5246
+ import * as Effect66 from "effect/Effect";
5185
5247
  var ZFS_POOL_ENDPOINT = { create: "pve:POST /nodes/{node}/disks/zfs" };
5186
5248
  var zfsPoolEndpoint = (props) => props.devices === undefined || props.raidlevel === undefined ? {} : ZFS_POOL_ENDPOINT;
5187
- var createForm10 = (props) => ({
5249
+ var createForm11 = (props) => ({
5188
5250
  ...props.devices === undefined ? {} : { devices: props.devices.join(",") },
5189
5251
  name: props.name,
5190
5252
  ...props.raidlevel === undefined ? {} : { raidlevel: props.raidlevel },
@@ -5193,24 +5255,24 @@ var createForm10 = (props) => ({
5193
5255
  ...props["draid-config"] === undefined ? {} : { "draid-config": props["draid-config"] }
5194
5256
  });
5195
5257
  var SETTLE_ATTEMPTS = 30;
5196
- var createPool = (props, collection2, path2, read4) => Effect63.gen(function* () {
5258
+ var createPool = (props, collection2, path2, read4) => Effect66.gen(function* () {
5197
5259
  const existing = yield* read4(props);
5198
5260
  if (existing !== undefined)
5199
5261
  return existing;
5200
5262
  if (props.devices === undefined || props.raidlevel === undefined) {
5201
- return yield* Effect63.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."));
5263
+ return yield* Effect66.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."));
5202
5264
  }
5203
- const upid = yield* pve(props.target, "provision", "POST", collection2, createForm10(props));
5204
- const settle4 = (attempts) => Effect63.gen(function* () {
5265
+ const upid = yield* pve(props.target, "provision", "POST", collection2, createForm11(props));
5266
+ const settle4 = (attempts) => Effect66.gen(function* () {
5205
5267
  const live = yield* read4(props);
5206
5268
  if (live !== undefined || attempts <= 0)
5207
5269
  return live;
5208
- yield* Effect63.sleep("2 seconds");
5270
+ yield* Effect66.sleep("2 seconds");
5209
5271
  return yield* settle4(attempts - 1);
5210
5272
  });
5211
5273
  const after = yield* settle4(SETTLE_ATTEMPTS);
5212
5274
  if (after === undefined) {
5213
- return yield* Effect63.die(new Error(`${path2}: 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."));
5275
+ return yield* Effect66.die(new Error(`${path2}: 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."));
5214
5276
  }
5215
5277
  return after;
5216
5278
  });
@@ -5235,7 +5297,7 @@ var spec2 = {
5235
5297
  };
5236
5298
  },
5237
5299
  collection: (props) => `nodes/${props.node}/disks/zfs`,
5238
- createForm: createForm10,
5300
+ createForm: createForm11,
5239
5301
  endpoint: zfsPoolEndpoint,
5240
5302
  matches: () => true,
5241
5303
  path: (props) => `nodes/${props.node}/disks/zfs/${props.name}`
@@ -5246,14 +5308,14 @@ var ProxmoxZfsPool = Resource35("Proxmox.ZfsPool", {
5246
5308
  defaultRemovalPolicy: "retain"
5247
5309
  });
5248
5310
  var ops3 = pveOperations(spec2);
5249
- var handlers26 = {
5311
+ var handlers25 = {
5250
5312
  ...pveHandlers(spec2),
5251
- delete: Effect64.fn(function* ({ olds }) {
5313
+ delete: Effect67.fn(function* ({ olds }) {
5252
5314
  yield* destroyPool(olds, spec2.path(olds));
5253
5315
  }),
5254
5316
  reconcile: ({ news }) => createPool(news, spec2.collection(news), spec2.path(news), ops3.read)
5255
5317
  };
5256
- var ProxmoxZfsPoolProvider = () => Provider35.effect(ProxmoxZfsPool, Effect64.succeed(ProxmoxZfsPool.Provider.of(handlers26)));
5318
+ var ProxmoxZfsPoolProvider = () => Provider35.effect(ProxmoxZfsPool, Effect67.succeed(ProxmoxZfsPool.Provider.of(handlers25)));
5257
5319
  export {
5258
5320
  PROVISION_DEFAULTS,
5259
5321
  PROVISION_PRIVILEGES,
@@ -5330,5 +5392,5 @@ export {
5330
5392
  violations
5331
5393
  };
5332
5394
 
5333
- //# debugId=71A5FC632D2B3D7F64756E2164756E21
5395
+ //# debugId=1F128D1971E713E364756E2164756E21
5334
5396
  //# sourceMappingURL=index.js.map