@homeflare/alchemy 0.37.6 → 0.37.7

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 (80) hide show
  1. package/dist/proxmox/firewall-alias-config.d.ts +36 -0
  2. package/dist/proxmox/firewall-alias-config.d.ts.map +1 -0
  3. package/dist/proxmox/firewall-alias-form.d.ts +3 -1
  4. package/dist/proxmox/firewall-alias-form.d.ts.map +1 -1
  5. package/dist/proxmox/firewall-alias-lifecycle.d.ts +43 -0
  6. package/dist/proxmox/firewall-alias-lifecycle.d.ts.map +1 -0
  7. package/dist/proxmox/firewall-alias.d.ts +2 -8
  8. package/dist/proxmox/firewall-alias.d.ts.map +1 -1
  9. package/dist/proxmox/index.js +795 -526
  10. package/dist/proxmox/index.js.map +23 -10
  11. package/dist/proxmox/lxc-errors.d.ts +12 -0
  12. package/dist/proxmox/lxc-errors.d.ts.map +1 -0
  13. package/dist/proxmox/lxc-lifecycle.d.ts +9 -31
  14. package/dist/proxmox/lxc-lifecycle.d.ts.map +1 -1
  15. package/dist/proxmox/lxc-read.d.ts +4 -0
  16. package/dist/proxmox/lxc-read.d.ts.map +1 -0
  17. package/dist/proxmox/lxc-task.d.ts +15 -0
  18. package/dist/proxmox/lxc-task.d.ts.map +1 -0
  19. package/dist/proxmox/network-apply-read.d.ts +7 -14
  20. package/dist/proxmox/network-apply-read.d.ts.map +1 -1
  21. package/dist/proxmox/network-apply-run.d.ts +7 -0
  22. package/dist/proxmox/network-apply-run.d.ts.map +1 -0
  23. package/dist/proxmox/network-apply.d.ts +2 -3
  24. package/dist/proxmox/network-apply.d.ts.map +1 -1
  25. package/dist/proxmox/qemu-errors.d.ts +5 -0
  26. package/dist/proxmox/qemu-errors.d.ts.map +1 -0
  27. package/dist/proxmox/qemu-form.d.ts +22 -0
  28. package/dist/proxmox/qemu-form.d.ts.map +1 -0
  29. package/dist/proxmox/qemu-lifecycle.d.ts +26 -0
  30. package/dist/proxmox/qemu-lifecycle.d.ts.map +1 -0
  31. package/dist/proxmox/qemu-read.d.ts +5 -0
  32. package/dist/proxmox/qemu-read.d.ts.map +1 -0
  33. package/dist/proxmox/qemu-task.d.ts +9 -0
  34. package/dist/proxmox/qemu-task.d.ts.map +1 -0
  35. package/dist/proxmox/qemu.d.ts +9 -14
  36. package/dist/proxmox/qemu.d.ts.map +1 -1
  37. package/dist/proxmox/replication-firewall-fixtures.d.ts +30 -0
  38. package/dist/proxmox/replication-firewall-fixtures.d.ts.map +1 -0
  39. package/dist/proxmox/replication-job-config.d.ts +56 -0
  40. package/dist/proxmox/replication-job-config.d.ts.map +1 -0
  41. package/dist/proxmox/replication-job-lifecycle.d.ts +62 -0
  42. package/dist/proxmox/replication-job-lifecycle.d.ts.map +1 -0
  43. package/dist/proxmox/replication-job.d.ts +5 -6
  44. package/dist/proxmox/replication-job.d.ts.map +1 -1
  45. package/dist/release/archive.d.ts.map +1 -1
  46. package/dist/release/index.js +3 -2
  47. package/dist/release/index.js.map +3 -3
  48. package/docs/proxmox-lxc-distilled.md +56 -0
  49. package/docs/proxmox-replication-firewall-distilled.md +53 -0
  50. package/docs/proxmox-sdk-migration.md +23 -18
  51. package/package.json +2 -2
  52. package/src/proxmox/firewall-alias-config.ts +39 -0
  53. package/src/proxmox/firewall-alias-form.ts +1 -1
  54. package/src/proxmox/firewall-alias-lifecycle.ts +100 -0
  55. package/src/proxmox/firewall-alias.ts +4 -67
  56. package/src/proxmox/lxc-create.test.ts +4 -1
  57. package/src/proxmox/lxc-distilled.test.ts +239 -0
  58. package/src/proxmox/lxc-errors.ts +9 -0
  59. package/src/proxmox/lxc-lifecycle.ts +31 -113
  60. package/src/proxmox/lxc-read.test.ts +29 -6
  61. package/src/proxmox/lxc-read.ts +88 -0
  62. package/src/proxmox/lxc-task.ts +71 -0
  63. package/src/proxmox/network-apply-distilled.test.ts +76 -0
  64. package/src/proxmox/network-apply-read.ts +18 -39
  65. package/src/proxmox/network-apply-run.ts +97 -0
  66. package/src/proxmox/network-apply.ts +5 -94
  67. package/src/proxmox/qemu-errors.ts +7 -0
  68. package/src/proxmox/qemu-form.ts +15 -0
  69. package/src/proxmox/qemu-lifecycle.test.ts +171 -0
  70. package/src/proxmox/qemu-lifecycle.ts +134 -0
  71. package/src/proxmox/qemu-read.ts +73 -0
  72. package/src/proxmox/qemu-task.ts +64 -0
  73. package/src/proxmox/qemu.ts +11 -44
  74. package/src/proxmox/replication-firewall-fixtures.ts +71 -0
  75. package/src/proxmox/replication-firewall-lifecycle.test.ts +109 -0
  76. package/src/proxmox/replication-firewall-wire.test.ts +173 -0
  77. package/src/proxmox/replication-job-config.ts +79 -0
  78. package/src/proxmox/replication-job-lifecycle.ts +113 -0
  79. package/src/proxmox/replication-job.ts +7 -84
  80. package/src/release/archive.ts +4 -1
@@ -1774,14 +1774,6 @@ var pveWith = (target, credential, method, path, form) => Effect14.gen(function*
1774
1774
  const response = target.scheme === "pve" ? yield* executeOnCluster(target, method, path, (apiBase) => buildRequest(method, apiBase, path, credential, target, form)).pipe(Effect14.mapError((failure) => failure.tag === "cluster" ? clusterExhausted(failure.method, failure.path, failure.attempts) : new PveError(0, method, path, String(failure)))) : yield* executeOne(target, credential, method, path, form, target.api);
1775
1775
  return yield* readResponse(response, method, path);
1776
1776
  });
1777
- var pveEnvelopeWith = (target, credential, method, path) => Effect14.gen(function* () {
1778
- const response = yield* executeOnCluster(target, method, path, (apiBase) => buildRequest(method, apiBase, path, credential, target)).pipe(Effect14.mapError((failure) => failure.tag === "cluster" ? clusterExhausted(failure.method, failure.path, failure.attempts) : new PveError(0, method, path, String(failure))));
1779
- if (response.status < 200 || response.status >= 300) {
1780
- const detail = yield* response.text.pipe(Effect14.orElseSucceed(() => ""));
1781
- return yield* Effect14.fail(new PveError(response.status, method, path, detail.slice(0, 300)));
1782
- }
1783
- return yield* response.json.pipe(Effect14.mapError((cause) => new PveError(0, method, path, String(cause))));
1784
- });
1785
1777
  var pve = (target, role, method, path, form) => Effect14.gen(function* () {
1786
1778
  const credential = yield* leased(target, role);
1787
1779
  return yield* pveWith(target, credential, method, path, form);
@@ -2231,8 +2223,13 @@ var ProxmoxCephPoolProvider = () => Provider8.effect(ProxmoxCephPool, Effect24.s
2231
2223
  })));
2232
2224
  // src/proxmox/firewall-alias.ts
2233
2225
  import { Resource as Resource9 } from "alchemy";
2234
- import { isResolved as isResolved9 } from "alchemy/Diff";
2235
2226
  import * as Provider9 from "alchemy/Provider";
2227
+ import * as Effect26 from "effect/Effect";
2228
+
2229
+ // src/proxmox/firewall-alias-lifecycle.ts
2230
+ import { isResolved as isResolved9 } from "alchemy/Diff";
2231
+ import * as cluster3 from "@distilled.cloud/proxmox/cluster";
2232
+ import { ProxmoxParseError as ProxmoxParseError2 } from "@distilled.cloud/proxmox/Errors";
2236
2233
  import * as Effect25 from "effect/Effect";
2237
2234
 
2238
2235
  // src/proxmox/firewall-alias-form.ts
@@ -2251,12 +2248,11 @@ var body = (props) => {
2251
2248
  return { cidr: cidr(props.cidr), ...note === "" ? {} : { comment: note } };
2252
2249
  };
2253
2250
 
2254
- // src/proxmox/firewall-alias.ts
2255
- var ProxmoxFirewallAlias = Resource9("Proxmox.FirewallAlias");
2256
- var handlers3 = pveHandlers({
2251
+ // src/proxmox/firewall-alias-config.ts
2252
+ var firewallAliasSpec = {
2257
2253
  attributes: (live, props) => {
2258
2254
  const address = cidr(live["cidr"]);
2259
- return address === "" ? undefined : {
2255
+ return {
2260
2256
  cidr: address,
2261
2257
  comment: comment(live["comment"]),
2262
2258
  ipversion: int(live["ipversion"], 0),
@@ -2272,26 +2268,74 @@ var handlers3 = pveHandlers({
2272
2268
  matches: (attributes, props) => attributes.cidr === cidr(props.cidr) && attributes.comment === comment(props.comment),
2273
2269
  path: (props) => `cluster/firewall/aliases/${props.name}`,
2274
2270
  updateForm: body
2275
- });
2276
- var ProxmoxFirewallAliasProvider = () => Provider9.effect(ProxmoxFirewallAlias, Effect25.succeed(ProxmoxFirewallAlias.Provider.of({
2277
- ...handlers3,
2278
- diff: Effect25.fn(function* ({ news, output }) {
2279
- if (output !== undefined && isResolved9(news) && fold(news.name) !== fold(output.name)) {
2271
+ };
2272
+
2273
+ // src/proxmox/firewall-alias-lifecycle.ts
2274
+ var { guardCreate: guardCreate2, guardUpdate: guardUpdate2 } = specGuards(firewallAliasSpec);
2275
+ var readFirewallAlias = (props) => runPve(props.target, "read", false, cluster3.getClusterFirewallAlias({ name: props.name })).pipe(Effect25.flatMap((live) => {
2276
+ if (live === null || typeof live !== "object" || Array.isArray(live) || !("name" in live) || typeof live.name !== "string" || fold(live.name) !== fold(props.name) || !("cidr" in live) || typeof live.cidr !== "string" || cidr(live.cidr) === "") {
2277
+ return Effect25.fail(new ProxmoxParseError2({
2278
+ body: undefined,
2279
+ cause: "Firewall alias response does not match the requested vendor identity"
2280
+ }));
2281
+ }
2282
+ return Effect25.succeed(firewallAliasSpec.attributes({ ...live }, props));
2283
+ }), Effect25.catchTag("FirewallAliasNotFound", () => Effect25.succeed(undefined)));
2284
+ var deleteFirewallAlias = (props) => runPve(props.target, "provision", true, cluster3.deleteClusterFirewallAlias({ name: props.name }));
2285
+ var firewallAliasHandlers = {
2286
+ list: () => Effect25.succeed([]),
2287
+ read: ({ olds }) => readFirewallAlias(olds),
2288
+ diff: Effect25.fn(function* ({
2289
+ news,
2290
+ output
2291
+ }) {
2292
+ if (!isResolved9(news))
2293
+ return;
2294
+ yield* guardCreate2(news, output === undefined);
2295
+ yield* guardUpdate2(news);
2296
+ if (output === undefined)
2297
+ return;
2298
+ if (fold(news.name) !== fold(output.name))
2280
2299
  return { action: "replace" };
2300
+ const live = yield* readFirewallAlias(news);
2301
+ if (live === undefined) {
2302
+ yield* guardCreate2(news, true);
2303
+ return { action: "update" };
2281
2304
  }
2282
- return yield* handlers3.diff({ news, output });
2283
- })
2284
- })));
2305
+ return { action: firewallAliasSpec.matches(live, news) ? "noop" : "update" };
2306
+ }),
2307
+ reconcile: Effect25.fn(function* ({ news }) {
2308
+ const live = yield* readFirewallAlias(news);
2309
+ yield* guardCreate2(news, live === undefined);
2310
+ yield* guardUpdate2(news);
2311
+ if (live === undefined) {
2312
+ yield* runPve(news.target, "provision", true, cluster3.createClusterFirewallAlias(firewallAliasSpec.createForm(news)));
2313
+ } else {
2314
+ const form = formToSend(firewallAliasSpec.matches, live, news, firewallAliasSpec.updateForm(news));
2315
+ if (form !== undefined)
2316
+ yield* runPve(news.target, "provision", true, cluster3.putClusterFirewallAlias({ ...form, name: news.name }));
2317
+ }
2318
+ const after = yield* readFirewallAlias(news);
2319
+ if (after === undefined)
2320
+ return yield* Effect25.fail(new Error(`${firewallAliasSpec.path(news)}: write returned success but the resource is still absent`));
2321
+ return after;
2322
+ }),
2323
+ delete: ({ olds }) => deleteFirewallAlias(olds)
2324
+ };
2325
+
2326
+ // src/proxmox/firewall-alias.ts
2327
+ var ProxmoxFirewallAlias = Resource9("Proxmox.FirewallAlias");
2328
+ var ProxmoxFirewallAliasProvider = () => Provider9.effect(ProxmoxFirewallAlias, Effect26.succeed(ProxmoxFirewallAlias.Provider.of(firewallAliasHandlers)));
2285
2329
  // src/proxmox/group.ts
2286
2330
  import { Resource as Resource10 } from "alchemy";
2287
2331
  import { isResolved as isResolved10 } from "alchemy/Diff";
2288
2332
  import * as Provider10 from "alchemy/Provider";
2289
2333
  import * as access4 from "@distilled.cloud/proxmox/access";
2290
- import * as Effect27 from "effect/Effect";
2334
+ import * as Effect28 from "effect/Effect";
2291
2335
 
2292
2336
  // src/proxmox/group-wire.ts
2293
2337
  import * as access3 from "@distilled.cloud/proxmox/access";
2294
- import * as Effect26 from "effect/Effect";
2338
+ import * as Effect27 from "effect/Effect";
2295
2339
  var GROUP_CREATE = "pve:POST /access/groups";
2296
2340
  var GROUP_UPDATE = "pve:PUT /access/groups/{groupid}";
2297
2341
  var storedComment = (comment2) => {
@@ -2316,20 +2360,20 @@ var attributesOf4 = (live, props) => ({
2316
2360
  members: memberList(live.members)
2317
2361
  });
2318
2362
  var matches4 = (attributes, props) => attributes.comment === storedComment(props.comment);
2319
- var readGroupOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, access3.getAccessGroup({ groupid: props.groupid }))).pipe(Effect26.map((live) => live === UNREADABLE ? UNREADABLE : live.members === undefined ? undefined : attributesOf4(live, props)));
2320
- var readGroup = (props) => readGroupOrFail(props).pipe(Effect26.catchTag("GroupNotFound", () => Effect26.succeed(undefined)));
2363
+ var readGroupOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, access3.getAccessGroup({ groupid: props.groupid }))).pipe(Effect27.map((live) => live === UNREADABLE ? UNREADABLE : live.members === undefined ? undefined : attributesOf4(live, props)));
2364
+ var readGroup = (props) => readGroupOrFail(props).pipe(Effect27.catchTag("GroupNotFound", () => Effect27.succeed(undefined)));
2321
2365
  var dropUnreadable3 = (live) => live === UNREADABLE ? undefined : live;
2322
2366
 
2323
2367
  // src/proxmox/group.ts
2324
2368
  var ProxmoxGroup = Resource10("Proxmox.Group", {
2325
2369
  defaultRemovalPolicy: "retain"
2326
2370
  });
2327
- var ProxmoxGroupProvider = () => Provider10.effect(ProxmoxGroup, Effect27.succeed(ProxmoxGroup.Provider.of({
2328
- list: () => Effect27.succeed([]),
2329
- read: Effect27.fn(function* ({ olds, output }) {
2371
+ var ProxmoxGroupProvider = () => Provider10.effect(ProxmoxGroup, Effect28.succeed(ProxmoxGroup.Provider.of({
2372
+ list: () => Effect28.succeed([]),
2373
+ read: Effect28.fn(function* ({ olds, output }) {
2330
2374
  return dropUnreadable3(yield* output === undefined ? readGroup(olds) : readGroupOrFail(olds));
2331
2375
  }),
2332
- diff: Effect27.fn(function* ({ news, output }) {
2376
+ diff: Effect28.fn(function* ({ news, output }) {
2333
2377
  if (!isResolved10(news))
2334
2378
  return;
2335
2379
  yield* guardWrite2(GROUP_CREATE, createForm3(news), output === undefined);
@@ -2347,7 +2391,7 @@ var ProxmoxGroupProvider = () => Provider10.effect(ProxmoxGroup, Effect27.succee
2347
2391
  }
2348
2392
  return matches4(live, news) ? { action: "noop" } : { action: "update" };
2349
2393
  }),
2350
- reconcile: Effect27.fn(function* ({ news }) {
2394
+ reconcile: Effect28.fn(function* ({ news }) {
2351
2395
  const before = dropUnreadable3(yield* readGroup(news));
2352
2396
  yield* guardWrite2(GROUP_CREATE, createForm3(news), before === undefined);
2353
2397
  yield* guardWrite2(GROUP_UPDATE, updateForm(news), false);
@@ -2358,18 +2402,18 @@ var ProxmoxGroupProvider = () => Provider10.effect(ProxmoxGroup, Effect27.succee
2358
2402
  }
2359
2403
  const after = dropUnreadable3(yield* readGroup(news));
2360
2404
  if (after === undefined) {
2361
- return yield* Effect27.die(new Error(`access/groups/${news.groupid}: the write returned no error but the group is ` + 'still absent. PVE wraps every answer in {"data":...} and can report success ' + "on a call that did nothing -- read back rather than trusting the status code."));
2405
+ return yield* Effect28.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."));
2362
2406
  }
2363
2407
  return after;
2364
2408
  }),
2365
- delete: Effect27.fn(function* ({ olds }) {
2409
+ delete: Effect28.fn(function* ({ olds }) {
2366
2410
  yield* runPve(olds.target, "provision", true, access4.deleteAccessGroup({ groupid: olds.groupid }));
2367
2411
  })
2368
2412
  })));
2369
2413
  // src/proxmox/ha-resource.ts
2370
2414
  import { Resource as Resource11 } from "alchemy";
2371
2415
  import * as Provider11 from "alchemy/Provider";
2372
- import * as Effect28 from "effect/Effect";
2416
+ import * as Effect29 from "effect/Effect";
2373
2417
  var ProxmoxHaResource = Resource11("Proxmox.HaResource");
2374
2418
  var kind = (sid) => sid.split(":")[0] ?? "";
2375
2419
  var shape3 = (props) => ({
@@ -2378,7 +2422,7 @@ var shape3 = (props) => ({
2378
2422
  max_restart: String(props.max_restart ?? 1),
2379
2423
  state: props.state ?? "started"
2380
2424
  });
2381
- var handlers4 = pveHandlers({
2425
+ var handlers3 = pveHandlers({
2382
2426
  attributes: (live, props) => ({
2383
2427
  comment: typeof live["comment"] === "string" ? live["comment"] : "",
2384
2428
  max_relocate: num(live["max_relocate"], 1),
@@ -2397,11 +2441,11 @@ var handlers4 = pveHandlers({
2397
2441
  path: (props) => `cluster/ha/resources/${props.sid}`,
2398
2442
  updateForm: shape3
2399
2443
  });
2400
- var ProxmoxHaResourceProvider = () => Provider11.effect(ProxmoxHaResource, Effect28.succeed(ProxmoxHaResource.Provider.of(handlers4)));
2444
+ var ProxmoxHaResourceProvider = () => Provider11.effect(ProxmoxHaResource, Effect29.succeed(ProxmoxHaResource.Provider.of(handlers3)));
2401
2445
  // src/proxmox/ha-rule.ts
2402
2446
  import { Resource as Resource12 } from "alchemy";
2403
2447
  import * as Provider12 from "alchemy/Provider";
2404
- import * as Effect29 from "effect/Effect";
2448
+ import * as Effect30 from "effect/Effect";
2405
2449
 
2406
2450
  // src/proxmox/ha-rule-form.ts
2407
2451
  var nodeList = (value) => {
@@ -2449,7 +2493,7 @@ var clearList = (props) => Object.entries(optional(props)).filter(([, value]) =>
2449
2493
 
2450
2494
  // src/proxmox/ha-rule.ts
2451
2495
  var ProxmoxHaRule = Resource12("Proxmox.HaRule");
2452
- var handlers5 = pveHandlers({
2496
+ var handlers4 = pveHandlers({
2453
2497
  attributes: (live, props) => {
2454
2498
  const liveType = text(live["type"]);
2455
2499
  if (liveType !== "" && liveType !== props.type)
@@ -2478,43 +2522,43 @@ var handlers5 = pveHandlers({
2478
2522
  return withClears(fields, clear);
2479
2523
  }
2480
2524
  });
2481
- var ProxmoxHaRuleProvider = () => Provider12.effect(ProxmoxHaRule, Effect29.succeed(ProxmoxHaRule.Provider.of(handlers5)));
2525
+ var ProxmoxHaRuleProvider = () => Provider12.effect(ProxmoxHaRule, Effect30.succeed(ProxmoxHaRule.Provider.of(handlers4)));
2482
2526
  // src/proxmox/lxc.ts
2483
2527
  import { Resource as Resource13 } from "alchemy";
2484
2528
  import { isResolved as isResolved11 } from "alchemy/Diff";
2485
2529
  import * as Provider13 from "alchemy/Provider";
2486
- import * as Effect39 from "effect/Effect";
2530
+ import * as Effect41 from "effect/Effect";
2487
2531
 
2488
2532
  // src/ownership/adopt.ts
2489
2533
  import { AdoptPolicy } from "alchemy/AdoptPolicy";
2490
2534
  import { AlchemyContext } from "alchemy/AlchemyContext";
2491
2535
  import { Stack as Stack3 } from "alchemy/Stack";
2492
- import * as Effect33 from "effect/Effect";
2536
+ import * as Effect34 from "effect/Effect";
2493
2537
  import * as Option5 from "effect/Option";
2494
2538
 
2495
2539
  // src/ownership/resume.ts
2496
2540
  import { Unowned } from "alchemy/AdoptPolicy";
2497
2541
  import { Artifacts } from "alchemy/Artifacts";
2498
- import * as Effect30 from "effect/Effect";
2542
+ import * as Effect31 from "effect/Effect";
2499
2543
  import * as Option2 from "effect/Option";
2500
2544
  var PROVEN = "homeflare/ownership/resumes";
2501
2545
  var UNFINISHED = "homeflare/ownership/unfinished";
2502
- var note = (key, instanceId) => Effect30.gen(function* () {
2503
- const bag = yield* Effect30.serviceOption(Artifacts);
2546
+ var note = (key, instanceId) => Effect31.gen(function* () {
2547
+ const bag = yield* Effect31.serviceOption(Artifacts);
2504
2548
  if (Option2.isSome(bag))
2505
2549
  yield* bag.value.set(key, instanceId);
2506
2550
  });
2507
- var noted = (key, instanceId) => Effect30.gen(function* () {
2508
- const bag = yield* Effect30.serviceOption(Artifacts);
2551
+ var noted = (key, instanceId) => Effect31.gen(function* () {
2552
+ const bag = yield* Effect31.serviceOption(Artifacts);
2509
2553
  if (Option2.isNone(bag))
2510
2554
  return false;
2511
2555
  return (yield* bag.value.get(key)) === instanceId;
2512
2556
  });
2513
- var noteUnfinished = (instanceId) => Effect30.as(note(UNFINISHED, instanceId), undefined);
2514
- var noteResume = (instanceId, recovered) => Effect30.gen(function* () {
2557
+ var noteUnfinished = (instanceId) => Effect31.as(note(UNFINISHED, instanceId), undefined);
2558
+ var noteResume = (instanceId, recovered) => Effect31.gen(function* () {
2515
2559
  yield* noteUnfinished(instanceId);
2516
- const unproven = () => Effect30.succeed(undefined);
2517
- const found = yield* recovered.pipe(Effect30.catch(unproven), Effect30.catchDefect(unproven));
2560
+ const unproven = () => Effect31.succeed(undefined);
2561
+ const found = yield* recovered.pipe(Effect31.catch(unproven), Effect31.catchDefect(unproven));
2518
2562
  if (found === undefined || found === null || Unowned.is(found))
2519
2563
  return;
2520
2564
  yield* note(PROVEN, instanceId);
@@ -2525,7 +2569,7 @@ var provingResumes = (service) => {
2525
2569
  const { diff, read } = service;
2526
2570
  if (diff === undefined || read === undefined)
2527
2571
  return service;
2528
- const proving = (input) => Effect30.gen(function* () {
2572
+ const proving = (input) => Effect31.gen(function* () {
2529
2573
  if (input.output === undefined) {
2530
2574
  yield* noteResume(input.instanceId, read({ ...input, output: undefined }));
2531
2575
  }
@@ -2537,12 +2581,12 @@ var provingResumes = (service) => {
2537
2581
  // src/ownership/rows.ts
2538
2582
  import { Stack as Stack2 } from "alchemy/Stack";
2539
2583
  import { State, isActionState } from "alchemy/State/State";
2540
- import * as Effect32 from "effect/Effect";
2584
+ import * as Effect33 from "effect/Effect";
2541
2585
  import * as Option4 from "effect/Option";
2542
2586
 
2543
2587
  // src/ownership/whole.ts
2544
2588
  import { Stack } from "alchemy/Stack";
2545
- import * as Effect31 from "effect/Effect";
2589
+ import * as Effect32 from "effect/Effect";
2546
2590
  import * as Option3 from "effect/Option";
2547
2591
  var absent = (value) => value === undefined || value === null;
2548
2592
  var isPlainObject = (value) => {
@@ -2568,22 +2612,22 @@ var carries = (declared, recorded) => {
2568
2612
  }
2569
2613
  return true;
2570
2614
  };
2571
- var wholeDeclaration = (fqn, props) => Effect31.map(Effect31.serviceOption(Stack), (stack) => {
2615
+ var wholeDeclaration = (fqn, props) => Effect32.map(Effect32.serviceOption(Stack), (stack) => {
2572
2616
  const declared = Option3.isSome(stack) ? stack.value.resources[fqn] : undefined;
2573
2617
  return declared !== undefined && carries(declared.Props, props);
2574
2618
  });
2575
2619
 
2576
2620
  // src/ownership/rows.ts
2577
- var storeOf = Effect32.gen(function* () {
2578
- const stack = yield* Effect32.serviceOption(Stack2);
2579
- const state = yield* Effect32.serviceOption(State);
2621
+ var storeOf = Effect33.gen(function* () {
2622
+ const stack = yield* Effect33.serviceOption(Stack2);
2623
+ const state = yield* Effect33.serviceOption(State);
2580
2624
  if (Option4.isNone(stack) || Option4.isNone(state))
2581
2625
  return;
2582
2626
  const store = yield* state.value;
2583
2627
  const where = { stack: stack.value.name, stage: stack.value.stage };
2584
2628
  return { resources: stack.value.resources, store, where };
2585
2629
  });
2586
- var rowAt = (store, where, fqn) => store.get({ ...where, fqn }).pipe(Effect32.orElseSucceed(() => {
2630
+ var rowAt = (store, where, fqn) => store.get({ ...where, fqn }).pipe(Effect33.orElseSucceed(() => {
2587
2631
  return;
2588
2632
  }));
2589
2633
  var generationOf = (row, instanceId) => {
@@ -2596,7 +2640,7 @@ var generationOf = (row, instanceId) => {
2596
2640
  }
2597
2641
  return;
2598
2642
  };
2599
- var recordedGeneration = (fqn, instanceId) => Effect32.gen(function* () {
2643
+ var recordedGeneration = (fqn, instanceId) => Effect33.gen(function* () {
2600
2644
  const found = yield* storeOf;
2601
2645
  if (found === undefined)
2602
2646
  return;
@@ -2607,14 +2651,14 @@ var recordedGeneration = (fqn, instanceId) => Effect32.gen(function* () {
2607
2651
  }
2608
2652
  return;
2609
2653
  });
2610
- var recordedInstance = (fqn, instanceId) => Effect32.gen(function* () {
2654
+ var recordedInstance = (fqn, instanceId) => Effect33.gen(function* () {
2611
2655
  const generation = yield* recordedGeneration(fqn, instanceId);
2612
2656
  if (generation === undefined)
2613
2657
  return "absent";
2614
2658
  return (yield* wholeDeclaration(fqn, generation.props)) ? "whole" : "partial";
2615
2659
  });
2616
- var isCreate = (fqn, instanceId) => Effect32.map(recordedGeneration(fqn, instanceId), (generation) => generation?.status === "creating");
2617
- var forgetRefusedCreate = (fqn, instanceId) => Effect32.gen(function* () {
2660
+ var isCreate = (fqn, instanceId) => Effect33.map(recordedGeneration(fqn, instanceId), (generation) => generation?.status === "creating");
2661
+ var forgetRefusedCreate = (fqn, instanceId) => Effect33.gen(function* () {
2618
2662
  const found = yield* storeOf;
2619
2663
  if (found === undefined)
2620
2664
  return;
@@ -2623,32 +2667,32 @@ var forgetRefusedCreate = (fqn, instanceId) => Effect32.gen(function* () {
2623
2667
  if (mine?.status !== "creating" || mine.instanceId !== instanceId || mine.attr !== undefined) {
2624
2668
  return;
2625
2669
  }
2626
- yield* found.store.delete({ ...found.where, fqn }).pipe(Effect32.ignore);
2670
+ yield* found.store.delete({ ...found.where, fqn }).pipe(Effect33.ignore);
2627
2671
  });
2628
2672
 
2629
2673
  // src/ownership/adopt.ts
2630
- var adoptEnabled = (fqn) => Effect33.gen(function* () {
2631
- const stack = yield* Effect33.serviceOption(Stack3);
2674
+ var adoptEnabled = (fqn) => Effect34.gen(function* () {
2675
+ const stack = yield* Effect34.serviceOption(Stack3);
2632
2676
  const scoped = Option5.isSome(stack) ? stack.value.resources[fqn]?.Adopt : undefined;
2633
2677
  if (scoped !== undefined)
2634
2678
  return scoped;
2635
- const policy = yield* Effect33.serviceOption(AdoptPolicy);
2679
+ const policy = yield* Effect34.serviceOption(AdoptPolicy);
2636
2680
  if (Option5.isSome(policy))
2637
2681
  return policy.value;
2638
- const context = yield* Effect33.serviceOption(AlchemyContext);
2682
+ const context = yield* Effect34.serviceOption(AlchemyContext);
2639
2683
  return Option5.isSome(context) ? context.value.adopt : false;
2640
2684
  });
2641
- var adoptable = (owner) => Effect33.gen(function* () {
2685
+ var adoptable = (owner) => Effect34.gen(function* () {
2642
2686
  if (yield* isCreate(owner.fqn, owner.instanceId))
2643
2687
  return true;
2644
2688
  return yield* unfinished(owner.instanceId);
2645
2689
  });
2646
- var adoptsAtApply = (owner) => Effect33.gen(function* () {
2690
+ var adoptsAtApply = (owner) => Effect34.gen(function* () {
2647
2691
  if (!(yield* adoptEnabled(owner.fqn)))
2648
2692
  return false;
2649
2693
  return yield* adoptable(owner);
2650
2694
  });
2651
- var refuseTakeover = (owner, what) => Effect33.gen(function* () {
2695
+ var refuseTakeover = (owner, what) => Effect34.gen(function* () {
2652
2696
  if (owner.output !== undefined)
2653
2697
  return;
2654
2698
  if (yield* resumes(owner.instanceId))
@@ -2658,25 +2702,25 @@ var refuseTakeover = (owner, what) => Effect33.gen(function* () {
2658
2702
  return;
2659
2703
  yield* forgetRefusedCreate(owner.fqn, owner.instanceId);
2660
2704
  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.";
2661
- return yield* Effect33.die(new Error(`${what}: already exists, and this stack holds no state for it — the plan could not ask ` + "first (a prop was still an Output, a replace moved onto it, or it appeared after the " + `plan). Nothing was written. ${remedy}`));
2705
+ return yield* Effect34.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}`));
2662
2706
  });
2663
2707
  var claimFor = (owner) => (what) => refuseTakeover(owner, what);
2664
2708
 
2665
2709
  // src/ownership/probe.ts
2666
2710
  import { Unowned as Unowned2 } from "alchemy/AdoptPolicy";
2667
- import * as Effect34 from "effect/Effect";
2668
- var provenOurs = (ask, settled2) => Effect34.gen(function* () {
2711
+ import * as Effect35 from "effect/Effect";
2712
+ var provenOurs = (ask, settled2) => Effect35.gen(function* () {
2669
2713
  const recorded = yield* recordedInstance(ask.fqn, ask.instanceId);
2670
2714
  if (recorded === "absent")
2671
2715
  return false;
2672
2716
  if (recorded === "partial") {
2673
- yield* Effect34.logWarning(`${ask.fqn}: the interrupted create's state row lacks part of the declaration (a prop ` + "was still an Output when it was written), so the live object is not proven ours");
2717
+ yield* Effect35.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");
2674
2718
  return false;
2675
2719
  }
2676
- const unproven = (reason) => Effect34.as(Effect34.logWarning(`${ask.fqn}: the interrupted create's object could not be compared with its props ` + `(${reason instanceof Error ? reason.message : String(reason)}), so it is not treated as ours`), false);
2677
- return yield* settled2.pipe(Effect34.catch(unproven), Effect34.catchDefect(unproven));
2720
+ const unproven = (reason) => Effect35.as(Effect35.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);
2721
+ return yield* settled2.pipe(Effect35.catch(unproven), Effect35.catchDefect(unproven));
2678
2722
  });
2679
- var ownedRead = (ask, found, settled2) => Effect34.gen(function* () {
2723
+ var ownedRead = (ask, found, settled2) => Effect35.gen(function* () {
2680
2724
  if (found === undefined || ask.output !== undefined)
2681
2725
  return found;
2682
2726
  return (yield* provenOurs(ask, settled2)) ? found : Unowned2(found);
@@ -3131,11 +3175,11 @@ var identityRefusals = (news, olds, output) => {
3131
3175
  };
3132
3176
 
3133
3177
  // src/proxmox/lxc-adoption.ts
3134
- import * as Effect38 from "effect/Effect";
3178
+ import * as Effect40 from "effect/Effect";
3135
3179
 
3136
3180
  // src/ownership/adopting.ts
3137
- import * as Effect35 from "effect/Effect";
3138
- var adopting = (owner, settled2) => Effect35.gen(function* () {
3181
+ import * as Effect36 from "effect/Effect";
3182
+ var adopting = (owner, settled2) => Effect36.gen(function* () {
3139
3183
  if (owner.output === undefined)
3140
3184
  return false;
3141
3185
  const generation = yield* recordedGeneration(owner.fqn, owner.instanceId);
@@ -3147,56 +3191,70 @@ var adopting = (owner, settled2) => Effect35.gen(function* () {
3147
3191
  });
3148
3192
 
3149
3193
  // src/proxmox/lxc-lifecycle.ts
3150
- import * as Effect37 from "effect/Effect";
3194
+ import * as Effect39 from "effect/Effect";
3195
+ import * as nodes10 from "@distilled.cloud/proxmox/nodes";
3151
3196
 
3152
- // src/proxmox/network-apply-read.ts
3153
- import * as Effect36 from "effect/Effect";
3154
- var stagedDiff = (target, node) => Effect36.gen(function* () {
3155
- const path = `nodes/${node}/network`;
3156
- const credential = yield* leased(target, "read");
3157
- const envelope = yield* pveEnvelopeWith(target, credential, "GET", path);
3158
- return text(envelope.changes);
3197
+ // src/proxmox/lxc-errors.ts
3198
+ class LxcRefusedError extends Error {
3199
+ name = "LxcRefusedError";
3200
+ }
3201
+
3202
+ // src/proxmox/lxc-read.ts
3203
+ import * as cluster4 from "@distilled.cloud/proxmox/cluster";
3204
+ import * as nodes8 from "@distilled.cloud/proxmox/nodes";
3205
+ import * as Effect37 from "effect/Effect";
3206
+ var readLive = (where) => Effect37.gen(function* () {
3207
+ const credential = yield* leased(where.target, "read");
3208
+ const answer = yield* runPveWith(where.target, credential, false, nodes8.getNodeLxcConfig({ node: where.node, vmid: String(where.vmid) })).pipe(Effect37.map((data) => ({ data, error: undefined })), Effect37.catchTag("LxcConfigNotFound", (error) => Effect37.succeed({ data: undefined, error })));
3209
+ if (answer.error === undefined) {
3210
+ const live = answer.data;
3211
+ if (live === null || typeof live !== "object" || Array.isArray(live) || !("digest" in live) || typeof live.digest !== "string" || live.digest === "") {
3212
+ return yield* Effect37.fail(new LxcRefusedError(`CT ${String(where.vmid)}: config read did not return a valid digest-bearing config.`));
3213
+ }
3214
+ return live;
3215
+ }
3216
+ const rows = yield* runPveWith(where.target, credential, false, cluster4.listClusterResources({ type: "vm" }));
3217
+ if (!Array.isArray(rows) || rows.some((row) => !Number.isSafeInteger(Number(row?.vmid)) || Number(row?.vmid) <= 0 || typeof row?.node !== "string" || row.node === "" || !["lxc", "qemu"].includes(row.type))) {
3218
+ return yield* Effect37.fail(new LxcRefusedError("The cluster guest index did not identify its rows."));
3219
+ }
3220
+ const found = rows.find((row) => Number(row.vmid) === where.vmid);
3221
+ if (found !== undefined && found.node === where.node && found.type === "lxc") {
3222
+ return yield* Effect37.fail(answer.error);
3223
+ }
3224
+ if (found !== undefined) {
3225
+ return yield* Effect37.fail(new LxcRefusedError(`vmid ${String(where.vmid)} is a ${text(found.type, "guest")} on ` + `${text(found.node, "?")}, not a container on ${where.node}. A migration is not an ` + "update and vmids are cluster-wide: declare the node it is on, or pick a free vmid."));
3226
+ }
3227
+ return;
3159
3228
  });
3160
- var pendingLines = (diff) => {
3161
- if (diff === "")
3162
- return 0;
3163
- const changed = diff.split(`
3164
- `).filter((line) => (line.startsWith("+") || line.startsWith("-")) && !line.startsWith("+++") && !line.startsWith("---")).length;
3165
- return Math.max(changed, 1);
3166
- };
3167
- var pendingCount = (target, node) => stagedDiff(target, node).pipe(Effect36.map(pendingLines));
3168
- var clusterHealth = (target) => pve(target, "read", "GET", "cluster/status").pipe(Effect36.map((rows) => {
3169
- const all = rows ?? [];
3170
- const cluster3 = all.find((row) => row.type === "cluster");
3171
- return {
3172
- offline: all.filter((row) => row.type === "node" && !bool(row.online)).map((row) => text(row.name, "<unnamed>")),
3173
- quorate: cluster3 === undefined ? true : bool(cluster3.quorate)
3174
- };
3175
- }));
3176
- var degradedReason = (target) => clusterHealth(target).pipe(Effect36.map((health) => health.quorate && health.offline.length === 0 ? undefined : `quorate=${String(health.quorate)} offline=[${health.offline.join(", ")}]`));
3177
- var UNREACHABLE = "the task could not be read -- the node stopped answering, or this lease cannot see it";
3178
- var STILL_RUNNING = "still running when this provider stopped waiting";
3179
- var ATTEMPTS = 30;
3180
- var awaitTask = (target, credential, node, upid, attempts = ATTEMPTS) => Effect36.gen(function* () {
3181
- const path = `nodes/${node}/tasks/${upid}/status`;
3182
- for (let attempt = 0;attempt < attempts; attempt += 1) {
3183
- const status = yield* pveWith(target, credential, "GET", path).pipe(Effect36.orElseSucceed(() => {
3229
+
3230
+ // src/proxmox/lxc-task.ts
3231
+ import * as nodes9 from "@distilled.cloud/proxmox/nodes";
3232
+ import * as Effect38 from "effect/Effect";
3233
+ var lxcTask = (where, operation, what, polls) => Effect38.gen(function* () {
3234
+ const credential = yield* mint(where.target, "provision");
3235
+ const upid = text(yield* runPveWith(where.target, credential, true, operation));
3236
+ if (upid === "")
3237
+ return yield* Effect38.fail(new LxcRefusedError(`${what}: PVE returned no task id, so the write cannot be confirmed and is not claimed.`));
3238
+ let exit = "still running when this provider stopped waiting";
3239
+ for (let attempt = 0;attempt < polls; attempt++) {
3240
+ const status = yield* runPveWith(where.target, credential, false, nodes9.getNodeTaskStatus({ node: where.node, upid })).pipe(Effect38.orElseSucceed(() => {
3184
3241
  return;
3185
3242
  }));
3186
- if (status === undefined)
3187
- return UNREACHABLE;
3188
- if (status.status === "stopped")
3189
- return text(status.exitstatus, "stopped with no exitstatus");
3190
- yield* Effect36.sleep("1 second");
3243
+ if (status === undefined || status.status === undefined) {
3244
+ exit = "the task could not be read -- the node stopped answering, or this lease cannot see it";
3245
+ break;
3246
+ }
3247
+ if (status.status === "stopped") {
3248
+ exit = text(status.exitstatus, "stopped with no exitstatus");
3249
+ break;
3250
+ }
3251
+ yield* Effect38.sleep("1 second");
3191
3252
  }
3192
- return STILL_RUNNING;
3253
+ if (exit !== "OK")
3254
+ return yield* Effect38.fail(new LxcRefusedError(`${what}: task ${upid} ended "${exit}". Read \`pvesh get /nodes/${where.node}/tasks/` + `${upid}/log\` before running the deploy again.`));
3193
3255
  });
3194
3256
 
3195
3257
  // src/proxmox/lxc-lifecycle.ts
3196
- class LxcRefusedError extends Error {
3197
- name = "LxcRefusedError";
3198
- }
3199
- var guestPath = (where) => `nodes/${where.node}/lxc/${String(where.vmid)}`;
3200
3258
  var LXC_ENDPOINTS = {
3201
3259
  create: "pve:POST /nodes/{node}/lxc",
3202
3260
  resize: "pve:PUT /nodes/{node}/lxc/{vmid}/resize",
@@ -3204,82 +3262,61 @@ var LXC_ENDPOINTS = {
3204
3262
  };
3205
3263
  var CREATE_POLLS = 180;
3206
3264
  var TASK_POLLS = 60;
3207
- var isServerError = (error) => error instanceof PveError && error.status === 500;
3208
- var readLive = (where) => Effect37.gen(function* () {
3209
- const answer = yield* pve(where.target, "read", "GET", `${guestPath(where)}/config`).pipe(Effect37.map((data) => ({ data, error: undefined })), Effect37.catchIf(isServerError, (error) => Effect37.succeed({ data: undefined, error })));
3210
- if (answer.data !== undefined && answer.data !== null)
3211
- return answer.data;
3212
- const rows = yield* pve(where.target, "read", "GET", "cluster/resources?type=vm");
3213
- const found = (rows ?? []).find((row) => Number(row.vmid) === where.vmid);
3214
- if (found !== undefined && found.node === where.node && found.type === "lxc") {
3215
- return yield* Effect37.fail(answer.error ?? new LxcRefusedError(`CT ${String(where.vmid)} is listed but its config read empty.`));
3216
- }
3217
- if (found !== undefined) {
3218
- return yield* Effect37.fail(new LxcRefusedError(`vmid ${String(where.vmid)} is a ${text(found.type, "guest")} on ` + `${text(found.node, "?")}, not a container on ${where.node}. A migration is not an ` + "update and vmids are cluster-wide: declare the node it is on, or pick a free vmid."));
3219
- }
3220
- return;
3221
- });
3222
3265
  var attributesOf5 = (where, live) => ({
3223
3266
  config: storedConfig(live),
3224
3267
  node: where.node,
3225
3268
  rawKeys: rawKeysOf(live),
3226
3269
  vmid: where.vmid
3227
3270
  });
3228
- var task = (where, method, path, what, polls, form) => Effect37.gen(function* () {
3229
- const credential = yield* mint(where.target, "provision");
3230
- const upid = text(yield* pveWith(where.target, credential, method, path, form));
3231
- if (upid === "") {
3232
- return yield* Effect37.fail(new LxcRefusedError(`${what}: PVE returned no task id, so the write cannot be confirmed and is not claimed.`));
3233
- }
3234
- const exit = yield* awaitTask(where.target, credential, where.node, upid, polls);
3235
- if (exit !== "OK") {
3236
- return yield* Effect37.fail(new LxcRefusedError(`${what}: task ${upid} ended "${exit}". Read \`pvesh get /nodes/${where.node}/tasks/` + `${upid}/log\` before running the deploy again.`));
3237
- }
3238
- });
3239
- var createGuest = (props) => Effect37.gen(function* () {
3271
+ var createGuest = (props) => Effect39.gen(function* () {
3240
3272
  const form = createForm4(props);
3241
3273
  yield* guardForm(LXC_ENDPOINTS.create, form, true);
3242
- return yield* task(props, "POST", `nodes/${props.node}/lxc`, `create CT ${String(props.vmid)}`, CREATE_POLLS, form);
3274
+ return yield* lxcTask(props, nodes10.createNodeLxc({
3275
+ ...form,
3276
+ node: props.node,
3277
+ vmid: String(props.vmid),
3278
+ ostemplate: text(form["ostemplate"])
3279
+ }), `create CT ${String(props.vmid)}`, CREATE_POLLS);
3243
3280
  });
3244
- var updateGuest = (props, change, digest) => Effect37.gen(function* () {
3281
+ var updateGuest = (props, change, digest) => Effect39.gen(function* () {
3245
3282
  if (Object.keys(change.put).length > 0 || change.clear.length > 0) {
3246
3283
  const form = withClears({ ...change.put, ...digest === "" ? {} : { digest } }, change.clear);
3247
3284
  yield* guardForm(LXC_ENDPOINTS.update, form, false);
3248
- yield* pve(props.target, "provision", "PUT", `${guestPath(props)}/config`, form);
3285
+ yield* runPve(props.target, "provision", true, nodes10.putNodeLxcConfig({ ...form, node: props.node, vmid: String(props.vmid) }));
3249
3286
  }
3250
3287
  for (const grow of change.resize) {
3251
3288
  const grown = { disk: grow.disk, size: grow.size };
3252
3289
  yield* guardForm(LXC_ENDPOINTS.resize, grown, true);
3253
- yield* task(props, "PUT", `${guestPath(props)}/resize`, `grow ${grow.disk} of CT ${String(props.vmid)} to ${grow.size}`, TASK_POLLS, grown);
3290
+ yield* lxcTask(props, nodes10.putNodeLxcResize({ ...grown, node: props.node, vmid: String(props.vmid) }), `grow ${grow.disk} of CT ${String(props.vmid)} to ${grow.size}`, TASK_POLLS);
3254
3291
  }
3255
3292
  });
3256
- var destroyGuest = (where, declared) => Effect37.gen(function* () {
3293
+ var destroyGuest = (where, declared) => Effect39.gen(function* () {
3257
3294
  const live = yield* readLive(where);
3258
3295
  if (live === undefined)
3259
3296
  return;
3260
3297
  const drift = judge(declared, live).drift;
3261
3298
  if (drift.length > 0) {
3262
- return yield* Effect37.fail(new LxcRefusedError(`destroy CT ${String(where.vmid)}: the guest on ${where.node} no longer matches its last ` + `declaration (${drift.join(", ")}), so it may not be the guest this stack made. ` + "Nothing was deleted. Delete it by hand if it should go, or declare it again."));
3299
+ return yield* Effect39.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."));
3263
3300
  }
3264
- yield* task(where, "DELETE", guestPath(where), `destroy CT ${String(where.vmid)}`, TASK_POLLS);
3301
+ yield* lxcTask(where, nodes10.deleteNodeLxc({ node: where.node, vmid: String(where.vmid) }), `destroy CT ${String(where.vmid)}`, TASK_POLLS);
3265
3302
  });
3266
3303
 
3267
3304
  // src/proxmox/lxc-adoption.ts
3268
3305
  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.";
3269
- var refuseAdoptedDrift = (owner, props, live, change) => Effect38.gen(function* () {
3306
+ var refuseAdoptedDrift = (owner, props, live, change) => Effect40.gen(function* () {
3270
3307
  if (change.drift.length === 0)
3271
3308
  return;
3272
- const settled2 = (recorded) => Effect38.sync(() => judge(recorded, live).drift.length === 0);
3309
+ const settled2 = (recorded) => Effect40.sync(() => judge(recorded, live).drift.length === 0);
3273
3310
  if (!(yield* adopting(owner, settled2)))
3274
3311
  return;
3275
- return yield* Effect38.fail(new LxcRefusedError(adoptionRefusal(props, change.drift)));
3312
+ return yield* Effect40.fail(new LxcRefusedError(adoptionRefusal(props, change.drift)));
3276
3313
  });
3277
3314
 
3278
3315
  // src/proxmox/lxc.ts
3279
3316
  var ProxmoxLxc = Resource13("Proxmox.Lxc", { defaultRemovalPolicy: "retain" });
3280
- var refused = (reasons) => Effect39.fail(new LxcRefusedError(reasons.join(`
3317
+ var refused = (reasons) => Effect41.fail(new LxcRefusedError(reasons.join(`
3281
3318
  `)));
3282
- var diff = (owner, news, olds) => Effect39.gen(function* () {
3319
+ var diff = (owner, news, olds) => Effect41.gen(function* () {
3283
3320
  const { output } = owner;
3284
3321
  const identity2 = identityRefusals(news, olds, output);
3285
3322
  if (identity2.length > 0)
@@ -3293,7 +3330,7 @@ var diff = (owner, news, olds) => Effect39.gen(function* () {
3293
3330
  const refusals = createRefusals(news);
3294
3331
  if (refusals.length > 0)
3295
3332
  return yield* refused(refusals);
3296
- yield* Effect39.logWarning(`Proxmox.Lxc ${news.node}/${String(news.vmid)}: the cluster lists no guest with this ` + "vmid -- a deploy CREATES it again from ostemplate, with new, empty volumes.");
3333
+ yield* Effect41.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.");
3297
3334
  return { action: "update" };
3298
3335
  }
3299
3336
  const change = judge(news, live);
@@ -3304,10 +3341,10 @@ var diff = (owner, news, olds) => Effect39.gen(function* () {
3304
3341
  if (change.drift.length === 0 && !moved)
3305
3342
  return { action: "noop" };
3306
3343
  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.";
3307
- yield* Effect39.logWarning(`Proxmox.Lxc ${news.node}/${String(news.vmid)}: ${what}`);
3344
+ yield* Effect41.logWarning(`Proxmox.Lxc ${news.node}/${String(news.vmid)}: ${what}`);
3308
3345
  return { action: "update" };
3309
3346
  });
3310
- var reconcile = (owner, news) => Effect39.gen(function* () {
3347
+ var reconcile = (owner, news) => Effect41.gen(function* () {
3311
3348
  const { output } = owner;
3312
3349
  const identity2 = identityRefusals(news, news, output);
3313
3350
  if (identity2.length > 0)
@@ -3353,15 +3390,15 @@ var whereOf = (olds, output) => ({
3353
3390
  target: olds.target,
3354
3391
  vmid: output?.vmid ?? olds.vmid
3355
3392
  });
3356
- var read = (owner, olds) => Effect39.gen(function* () {
3393
+ var read = (owner, olds) => Effect41.gen(function* () {
3357
3394
  const where = whereOf(olds, owner.output);
3358
3395
  const live = yield* readLive(where);
3359
3396
  if (live === undefined)
3360
3397
  return;
3361
- const settled2 = Effect39.sync(() => judge(olds, live).drift.length === 0);
3398
+ const settled2 = Effect41.sync(() => judge(olds, live).drift.length === 0);
3362
3399
  return yield* ownedRead(owner, attributesOf5(where, live), settled2);
3363
3400
  });
3364
- var handlers6 = {
3401
+ var handlers5 = {
3365
3402
  delete: ({ olds, output }) => destroyGuest(whereOf(olds, output), olds),
3366
3403
  diff: ({
3367
3404
  fqn,
@@ -3370,7 +3407,7 @@ var handlers6 = {
3370
3407
  olds,
3371
3408
  output
3372
3409
  }) => diff({ fqn, instanceId, output }, news, olds),
3373
- list: () => Effect39.succeed([]),
3410
+ list: () => Effect41.succeed([]),
3374
3411
  read: ({
3375
3412
  fqn,
3376
3413
  instanceId,
@@ -3384,11 +3421,11 @@ var handlers6 = {
3384
3421
  output
3385
3422
  }) => reconcile({ fqn, instanceId, output }, news)
3386
3423
  };
3387
- var ProxmoxLxcProvider = () => Provider13.effect(ProxmoxLxc, Effect39.succeed(ProxmoxLxc.Provider.of(handlers6)).pipe(Effect39.map(provingResumes)));
3424
+ var ProxmoxLxcProvider = () => Provider13.effect(ProxmoxLxc, Effect41.succeed(ProxmoxLxc.Provider.of(handlers5)).pipe(Effect41.map(provingResumes)));
3388
3425
  // src/proxmox/metric-server.ts
3389
3426
  import { Resource as Resource14 } from "alchemy";
3390
3427
  import { isResolved as isResolved12 } from "alchemy/Diff";
3391
- import * as cluster4 from "@distilled.cloud/proxmox/cluster";
3428
+ import * as cluster6 from "@distilled.cloud/proxmox/cluster";
3392
3429
 
3393
3430
  // src/proxmox/metric-server-form.ts
3394
3431
  var UNSET2 = -1;
@@ -3502,15 +3539,15 @@ var metricServerSpec = {
3502
3539
  };
3503
3540
 
3504
3541
  // src/proxmox/metric-server-distilled.ts
3505
- import * as cluster3 from "@distilled.cloud/proxmox/cluster";
3506
- import { ProxmoxParseError as ProxmoxParseError2 } from "@distilled.cloud/proxmox/Errors";
3507
- import * as Effect40 from "effect/Effect";
3542
+ import * as cluster5 from "@distilled.cloud/proxmox/cluster";
3543
+ import { ProxmoxParseError as ProxmoxParseError3 } from "@distilled.cloud/proxmox/Errors";
3544
+ import * as Effect42 from "effect/Effect";
3508
3545
  import * as Schema2 from "effect/Schema";
3509
- var readMetricServerRow = (props) => runPve(props.target, "read", false, cluster3.getClusterMetricsServer({ id: props.id })).pipe(Effect40.flatMap((body4) => Schema2.decodeUnknownEffect(Schema2.Record(Schema2.String, Schema2.Unknown))(body4).pipe(Effect40.mapError(() => new ProxmoxParseError2({
3546
+ var readMetricServerRow = (props) => runPve(props.target, "read", false, cluster5.getClusterMetricsServer({ id: props.id })).pipe(Effect42.flatMap((body4) => Schema2.decodeUnknownEffect(Schema2.Record(Schema2.String, Schema2.Unknown))(body4).pipe(Effect42.mapError(() => new ProxmoxParseError3({
3510
3547
  body: undefined,
3511
3548
  cause: "Metric server response must be an object"
3512
- })))), Effect40.catchTag("MetricServerNotFound", () => Effect40.succeed(undefined)), Effect40.catchTag("NotFound", () => Effect40.succeed(undefined)));
3513
- var readMetricServer = (props) => readMetricServerRow(props).pipe(Effect40.map((row) => row === undefined ? undefined : metricServerSpec.attributes(row, props)));
3549
+ })))), Effect42.catchTag("MetricServerNotFound", () => Effect42.succeed(undefined)), Effect42.catchTag("NotFound", () => Effect42.succeed(undefined)));
3550
+ var readMetricServer = (props) => readMetricServerRow(props).pipe(Effect42.map((row) => row === undefined ? undefined : metricServerSpec.attributes(row, props)));
3514
3551
  var metricServerRequest = (props, form) => ({
3515
3552
  ...asForm2({
3516
3553
  api_path_prefix: form["api-path-prefix"],
@@ -3535,51 +3572,51 @@ var metricServerRequest = (props, form) => ({
3535
3572
  port: String(props.port),
3536
3573
  server: props.server
3537
3574
  });
3538
- var deleteMetricServer = (props) => Effect40.gen(function* () {
3575
+ var deleteMetricServer = (props) => Effect42.gen(function* () {
3539
3576
  if ((yield* readMetricServerRow(props)) === undefined)
3540
3577
  return;
3541
- yield* runPve(props.target, "provision", true, cluster3.deleteClusterMetricsServer({ id: props.id }));
3578
+ yield* runPve(props.target, "provision", true, cluster5.deleteClusterMetricsServer({ id: props.id }));
3542
3579
  });
3543
3580
 
3544
3581
  // src/proxmox/metric-server.ts
3545
3582
  import * as Provider14 from "alchemy/Provider";
3546
- import * as Effect41 from "effect/Effect";
3583
+ import * as Effect43 from "effect/Effect";
3547
3584
  var ProxmoxMetricServer = Resource14("Proxmox.MetricServer");
3548
- var { guardCreate: guardCreate2, guardUpdate: guardUpdate2 } = specGuards(metricServerSpec);
3549
- var ProxmoxMetricServerProvider = () => Provider14.effect(ProxmoxMetricServer, Effect41.succeed(ProxmoxMetricServer.Provider.of({
3550
- list: () => Effect41.succeed([]),
3585
+ var { guardCreate: guardCreate3, guardUpdate: guardUpdate3 } = specGuards(metricServerSpec);
3586
+ var ProxmoxMetricServerProvider = () => Provider14.effect(ProxmoxMetricServer, Effect43.succeed(ProxmoxMetricServer.Provider.of({
3587
+ list: () => Effect43.succeed([]),
3551
3588
  read: ({ olds }) => readMetricServer(olds),
3552
- diff: Effect41.fn(function* ({ news, output }) {
3589
+ diff: Effect43.fn(function* ({ news, output }) {
3553
3590
  if (!isResolved12(news))
3554
3591
  return;
3555
- yield* guardCreate2(news, output === undefined);
3556
- yield* guardUpdate2(news);
3592
+ yield* guardCreate3(news, output === undefined);
3593
+ yield* guardUpdate3(news);
3557
3594
  if (output === undefined)
3558
3595
  return;
3559
3596
  const live = yield* readMetricServer(news);
3560
3597
  if (live === undefined) {
3561
- yield* guardCreate2(news, true);
3598
+ yield* guardCreate3(news, true);
3562
3599
  return { action: "update" };
3563
3600
  }
3564
3601
  return { action: metricServerSpec.matches(live, news) ? "noop" : "update" };
3565
3602
  }),
3566
- reconcile: Effect41.fn(function* ({ news }) {
3603
+ reconcile: Effect43.fn(function* ({ news }) {
3567
3604
  const live = yield* readMetricServer(news);
3568
- yield* guardCreate2(news, live === undefined);
3569
- yield* guardUpdate2(news);
3605
+ yield* guardCreate3(news, live === undefined);
3606
+ yield* guardUpdate3(news);
3570
3607
  if (live === undefined) {
3571
- yield* runPve(news.target, "provision", true, cluster4.updateClusterMetricsServer({
3608
+ yield* runPve(news.target, "provision", true, cluster6.updateClusterMetricsServer({
3572
3609
  ...metricServerRequest(news, metricServerSpec.createForm(news)),
3573
3610
  type: news.type
3574
3611
  }));
3575
3612
  } else {
3576
3613
  const form = formToSend(metricServerSpec.matches, live, news, metricServerSpec.updateForm(news));
3577
3614
  if (form !== undefined)
3578
- yield* runPve(news.target, "provision", true, cluster4.putClusterMetricsServer(metricServerRequest(news, form)));
3615
+ yield* runPve(news.target, "provision", true, cluster6.putClusterMetricsServer(metricServerRequest(news, form)));
3579
3616
  }
3580
3617
  const after = yield* readMetricServer(news);
3581
3618
  if (after === undefined)
3582
- return yield* Effect41.fail(new Error(`${metricServerSpec.path(news)}: write returned success but the resource is still absent`));
3619
+ return yield* Effect43.fail(new Error(`${metricServerSpec.path(news)}: write returned success but the resource is still absent`));
3583
3620
  return after;
3584
3621
  }),
3585
3622
  delete: ({ olds }) => deleteMetricServer(olds)
@@ -3588,7 +3625,11 @@ var ProxmoxMetricServerProvider = () => Provider14.effect(ProxmoxMetricServer, E
3588
3625
  import { Resource as Resource15 } from "alchemy";
3589
3626
  import { isResolved as isResolved13 } from "alchemy/Diff";
3590
3627
  import * as Provider15 from "alchemy/Provider";
3591
- import * as Effect42 from "effect/Effect";
3628
+ import * as Effect46 from "effect/Effect";
3629
+
3630
+ // src/proxmox/network-apply-run.ts
3631
+ import * as nodes12 from "@distilled.cloud/proxmox/nodes";
3632
+ import * as Effect45 from "effect/Effect";
3592
3633
 
3593
3634
  // src/proxmox/apply-endpoints.ts
3594
3635
  var NETWORK_APPLY_ENDPOINT = "pve:PUT /nodes/{node}/network";
@@ -3596,17 +3637,52 @@ var SDN_APPLY_ENDPOINT = "pve:PUT /cluster/sdn";
3596
3637
  var guardNetworkApply = guardForm(NETWORK_APPLY_ENDPOINT, {}, true);
3597
3638
  var guardSdnApply = guardForm(SDN_APPLY_ENDPOINT, {}, true);
3598
3639
 
3599
- // src/proxmox/network-apply.ts
3600
- var ProxmoxNetworkApply = Resource15("Proxmox.NetworkApply");
3601
- var read2 = (props) => pendingCount(props.target, props.node).pipe(Effect42.map((pending) => ({ node: props.node, pending })));
3602
- var diff2 = (news) => Effect42.gen(function* () {
3603
- if (!isResolved13(news))
3604
- return;
3605
- const { pending } = yield* read2(news);
3606
- return pending === 0 ? { action: "noop" } : { action: "update" };
3640
+ // src/proxmox/network-apply-read.ts
3641
+ import * as cluster7 from "@distilled.cloud/proxmox/cluster";
3642
+ import * as nodes11 from "@distilled.cloud/proxmox/nodes";
3643
+ import * as Effect44 from "effect/Effect";
3644
+ var stagedDiff = (target, node) => Effect44.gen(function* () {
3645
+ const credential = yield* leased(target, "read");
3646
+ const live = yield* runPveWith(target, credential, false, nodes11.listNodeNetwork({ node }));
3647
+ return Array.isArray(live) ? "" : live.changes;
3648
+ });
3649
+ var pendingLines = (diff2) => {
3650
+ if (diff2 === "")
3651
+ return 0;
3652
+ const changed = diff2.split(`
3653
+ `).filter((line) => (line.startsWith("+") || line.startsWith("-")) && !line.startsWith("+++") && !line.startsWith("---")).length;
3654
+ return Math.max(changed, 1);
3655
+ };
3656
+ var pendingCount = (target, node) => stagedDiff(target, node).pipe(Effect44.map(pendingLines));
3657
+ var clusterHealth = (target) => runPve(target, "read", false, cluster7.listClusterStatus({})).pipe(Effect44.map((rows) => {
3658
+ const all = rows ?? [];
3659
+ const cluster8 = all.find((row) => row.type === "cluster");
3660
+ return {
3661
+ offline: all.filter((row) => row.type === "node" && !bool(row.online)).map((row) => text(row.name, "<unnamed>")),
3662
+ quorate: cluster8 === undefined ? true : bool(cluster8.quorate)
3663
+ };
3664
+ }));
3665
+ var degradedReason = (target) => clusterHealth(target).pipe(Effect44.map((health) => health.quorate && health.offline.length === 0 ? undefined : `quorate=${String(health.quorate)} offline=[${health.offline.join(", ")}]`));
3666
+ var UNREACHABLE = "the task could not be read -- the node stopped answering, or this lease cannot see it";
3667
+ var STILL_RUNNING = "still running when this provider stopped waiting";
3668
+ var ATTEMPTS = 30;
3669
+ var awaitTask = (target, credential, node, upid, attempts = ATTEMPTS) => Effect44.gen(function* () {
3670
+ for (let attempt = 0;attempt < attempts; attempt += 1) {
3671
+ const status = yield* runPveWith(target, credential, false, nodes11.getNodeTaskStatus({ node, upid })).pipe(Effect44.orElseSucceed(() => {
3672
+ return;
3673
+ }));
3674
+ if (status === undefined)
3675
+ return UNREACHABLE;
3676
+ if (status.status === "stopped")
3677
+ return text(status.exitstatus, "stopped with no exitstatus");
3678
+ yield* Effect44.sleep("1 second");
3679
+ }
3680
+ return STILL_RUNNING;
3607
3681
  });
3608
- var refuse = (node, why) => Effect42.die(new Error(`Proxmox.NetworkApply ${node}: ${why}`));
3609
- var apply = (props) => Effect42.gen(function* () {
3682
+
3683
+ // src/proxmox/network-apply-run.ts
3684
+ var refuse = (node, why) => Effect45.die(new Error(`Proxmox.NetworkApply ${node}: ${why}`));
3685
+ var applyNetwork = (props) => Effect45.gen(function* () {
3610
3686
  const node = props.node;
3611
3687
  const staged = yield* pendingCount(props.target, node);
3612
3688
  if (staged === 0)
@@ -3617,8 +3693,8 @@ var apply = (props) => Effect42.gen(function* () {
3617
3693
  }
3618
3694
  yield* guardNetworkApply;
3619
3695
  const credential = yield* mint(props.target, "provision");
3620
- const upid = yield* pveWith(props.target, credential, "PUT", `nodes/${node}/network`);
3621
- if (upid === undefined) {
3696
+ const upid = text(yield* runPveWith(props.target, credential, true, nodes12.putNodeNetwork({ node })));
3697
+ if (upid === "") {
3622
3698
  return yield* refuse(node, 'the apply returned no UPID. PVE wraps every answer in {"data":...} and can report success ' + "on a call that did nothing -- the reload cannot be confirmed, so it is not claimed.");
3623
3699
  }
3624
3700
  const exitstatus = yield* awaitTask(props.target, credential, node, upid);
@@ -3635,20 +3711,30 @@ var apply = (props) => Effect42.gen(function* () {
3635
3711
  }
3636
3712
  return { node, pending: left };
3637
3713
  });
3638
- var handlers7 = {
3639
- delete: () => Effect42.void,
3714
+
3715
+ // src/proxmox/network-apply.ts
3716
+ var ProxmoxNetworkApply = Resource15("Proxmox.NetworkApply");
3717
+ var read2 = (props) => pendingCount(props.target, props.node).pipe(Effect46.map((pending) => ({ node: props.node, pending })));
3718
+ var diff2 = (news) => Effect46.gen(function* () {
3719
+ if (!isResolved13(news))
3720
+ return;
3721
+ const { pending } = yield* read2(news);
3722
+ return pending === 0 ? { action: "noop" } : { action: "update" };
3723
+ });
3724
+ var handlers6 = {
3725
+ delete: () => Effect46.void,
3640
3726
  diff: ({ news }) => diff2(news),
3641
- list: () => Effect42.succeed([]),
3727
+ list: () => Effect46.succeed([]),
3642
3728
  read: ({ olds }) => read2(olds),
3643
- reconcile: ({ news }) => apply(news)
3729
+ reconcile: ({ news }) => applyNetwork(news)
3644
3730
  };
3645
- var ProxmoxNetworkApplyProvider = () => Provider15.effect(ProxmoxNetworkApply, Effect42.succeed(ProxmoxNetworkApply.Provider.of(handlers7)));
3731
+ var ProxmoxNetworkApplyProvider = () => Provider15.effect(ProxmoxNetworkApply, Effect46.succeed(ProxmoxNetworkApply.Provider.of(handlers6)));
3646
3732
  // src/proxmox/node-network.ts
3647
3733
  import { Resource as Resource16 } from "alchemy";
3648
3734
  import { isResolved as isResolved14 } from "alchemy/Diff";
3649
3735
  import * as Provider16 from "alchemy/Provider";
3650
- import * as nodes9 from "@distilled.cloud/proxmox/nodes";
3651
- import * as Effect44 from "effect/Effect";
3736
+ import * as nodes14 from "@distilled.cloud/proxmox/nodes";
3737
+ import * as Effect48 from "effect/Effect";
3652
3738
 
3653
3739
  // src/proxmox/node-network-form.ts
3654
3740
  var NODE_NETWORK_CREATE = "pve:POST /nodes/{node}/network";
@@ -3690,8 +3776,8 @@ var updateForm2 = (props) => {
3690
3776
  };
3691
3777
 
3692
3778
  // src/proxmox/node-network-wire.ts
3693
- import * as nodes8 from "@distilled.cloud/proxmox/nodes";
3694
- import * as Effect43 from "effect/Effect";
3779
+ import * as nodes13 from "@distilled.cloud/proxmox/nodes";
3780
+ import * as Effect47 from "effect/Effect";
3695
3781
  var attributesOf6 = (live, props) => {
3696
3782
  const data = live;
3697
3783
  const liveType = text(data["type"]);
@@ -3725,12 +3811,12 @@ var attributesOf6 = (live, props) => {
3725
3811
  "vlan-raw-device": text(data["vlan-raw-device"])
3726
3812
  };
3727
3813
  };
3728
- var readInterfaceOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, nodes8.getNodeNetwork({ iface: props.iface, node: props.node })).pipe(Effect43.catchTag("NetworkInterfaceNotFound", () => Effect43.succeed(undefined)))).pipe(Effect43.map((live) => {
3814
+ var readInterfaceOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, nodes13.getNodeNetwork({ iface: props.iface, node: props.node })).pipe(Effect47.catchTag("NetworkInterfaceNotFound", () => Effect47.succeed(undefined)))).pipe(Effect47.map((live) => {
3729
3815
  if (live === UNREADABLE)
3730
3816
  return UNREADABLE;
3731
3817
  return live === undefined ? undefined : attributesOf6(live, props);
3732
3818
  }));
3733
- var readInterface = (props) => readInterfaceOrFail(props).pipe(Effect43.orElseSucceed(() => {
3819
+ var readInterface = (props) => readInterfaceOrFail(props).pipe(Effect47.orElseSucceed(() => {
3734
3820
  return;
3735
3821
  }));
3736
3822
  var dropUnreadable4 = (live) => live === UNREADABLE ? undefined : live;
@@ -3755,12 +3841,12 @@ var toDistilledUpdate2 = (props) => ({
3755
3841
  iface: props.iface,
3756
3842
  node: props.node
3757
3843
  });
3758
- var ProxmoxNodeNetworkProvider = () => Provider16.effect(ProxmoxNodeNetwork, Effect44.succeed(ProxmoxNodeNetwork.Provider.of({
3759
- list: () => Effect44.succeed([]),
3760
- read: Effect44.fn(function* ({ olds, output }) {
3844
+ var ProxmoxNodeNetworkProvider = () => Provider16.effect(ProxmoxNodeNetwork, Effect48.succeed(ProxmoxNodeNetwork.Provider.of({
3845
+ list: () => Effect48.succeed([]),
3846
+ read: Effect48.fn(function* ({ olds, output }) {
3761
3847
  return dropUnreadable4(yield* output === undefined ? readInterface(olds) : readInterfaceOrFail(olds));
3762
3848
  }),
3763
- diff: Effect44.fn(function* ({ news, output }) {
3849
+ diff: Effect48.fn(function* ({ news, output }) {
3764
3850
  if (!isResolved14(news))
3765
3851
  return;
3766
3852
  yield* guardWrite2(NODE_NETWORK_CREATE, createForm5(news), output === undefined);
@@ -3778,33 +3864,33 @@ var ProxmoxNodeNetworkProvider = () => Provider16.effect(ProxmoxNodeNetwork, Eff
3778
3864
  }
3779
3865
  return matches5(live, news) ? { action: "noop" } : { action: "update" };
3780
3866
  }),
3781
- reconcile: Effect44.fn(function* ({ news }) {
3867
+ reconcile: Effect48.fn(function* ({ news }) {
3782
3868
  const before = dropUnreadable4(yield* readInterface(news));
3783
3869
  yield* guardWrite2(NODE_NETWORK_CREATE, createForm5(news), before === undefined);
3784
3870
  yield* guardWrite2(NODE_NETWORK_UPDATE, updateForm2(news), false);
3785
3871
  if (before === undefined) {
3786
- yield* runPve(news.target, "provision", true, nodes9.createNodeNetwork(toDistilledCreate3(news)));
3872
+ yield* runPve(news.target, "provision", true, nodes14.createNodeNetwork(toDistilledCreate3(news)));
3787
3873
  } else if (!matches5(before, news)) {
3788
- yield* runPve(news.target, "provision", true, nodes9.putNodeNetwork2(toDistilledUpdate2(news)));
3874
+ yield* runPve(news.target, "provision", true, nodes14.putNodeNetwork2(toDistilledUpdate2(news)));
3789
3875
  }
3790
3876
  const after = dropUnreadable4(yield* readInterface(news));
3791
3877
  if (after === undefined) {
3792
- return yield* Effect44.die(new Error(`nodes/${news.node}/network/${news.iface}: wrote with no error, but the ` + 'interface is still absent -- PVE wraps every answer in {"data":...} and can ' + "report success on a call that did nothing, so read back rather than trust it."));
3878
+ return yield* Effect48.die(new Error(`nodes/${news.node}/network/${news.iface}: wrote with no error, but the ` + 'interface is still absent -- PVE wraps every answer in {"data":...} and can ' + "report success on a call that did nothing, so read back rather than trust it."));
3793
3879
  }
3794
3880
  return after;
3795
3881
  }),
3796
- delete: Effect44.fn(function* ({ olds }) {
3797
- yield* runPve(olds.target, "provision", true, nodes9.deleteNodeNetwork2({ iface: olds.iface, node: olds.node }));
3882
+ delete: Effect48.fn(function* ({ olds }) {
3883
+ yield* runPve(olds.target, "provision", true, nodes14.deleteNodeNetwork2({ iface: olds.iface, node: olds.node }));
3798
3884
  })
3799
3885
  })));
3800
3886
  // src/proxmox/notification-matcher.ts
3801
3887
  import { Resource as Resource17 } from "alchemy";
3802
3888
  import * as Provider17 from "alchemy/Provider";
3803
- import * as Effect48 from "effect/Effect";
3889
+ import * as Effect52 from "effect/Effect";
3804
3890
 
3805
3891
  // src/proxmox/notification-matcher-lifecycle.ts
3806
3892
  import { isResolved as isResolved15 } from "alchemy/Diff";
3807
- import * as Effect47 from "effect/Effect";
3893
+ import * as Effect51 from "effect/Effect";
3808
3894
 
3809
3895
  // src/proxmox/notification-matcher-form.ts
3810
3896
  var list = (value) => Array.isArray(value) ? value.map((item) => String(item)) : [];
@@ -3881,49 +3967,49 @@ var matcherUpdateForm = (fields) => {
3881
3967
  };
3882
3968
 
3883
3969
  // src/proxmox/notification-matcher-distilled.ts
3884
- import * as cluster5 from "@distilled.cloud/proxmox/cluster";
3885
- import * as Effect46 from "effect/Effect";
3970
+ import * as cluster8 from "@distilled.cloud/proxmox/cluster";
3971
+ import * as Effect50 from "effect/Effect";
3886
3972
 
3887
3973
  // src/proxmox/notification-sdk-input.ts
3888
- import { ProxmoxParseError as ProxmoxParseError3 } from "@distilled.cloud/proxmox/Errors";
3974
+ import { ProxmoxParseError as ProxmoxParseError4 } from "@distilled.cloud/proxmox/Errors";
3889
3975
  import * as Data2 from "effect/Data";
3890
- import * as Effect45 from "effect/Effect";
3976
+ import * as Effect49 from "effect/Effect";
3891
3977
  import * as Schema3 from "effect/Schema";
3892
3978
 
3893
3979
  class NotificationRequestInvalid extends Data2.TaggedError("NotificationRequestInvalid") {
3894
3980
  }
3895
- var notificationRequest = (schema, fields) => Schema3.decodeUnknownEffect(Schema3.toType(schema), { onExcessProperty: "error" })(Object.fromEntries(Object.entries(fields).map(([key, value]) => [key.replaceAll("-", "_"), value]))).pipe(Effect45.mapError(() => new NotificationRequestInvalid({ operation: "PVE notification write" })));
3896
- var notificationResponse = (schema) => (body5) => Schema3.decodeUnknownEffect(Schema3.toType(schema))(body5).pipe(Effect45.as(body5), Effect45.mapError(() => new ProxmoxParseError3({
3981
+ var notificationRequest = (schema, fields) => Schema3.decodeUnknownEffect(Schema3.toType(schema), { onExcessProperty: "error" })(Object.fromEntries(Object.entries(fields).map(([key, value]) => [key.replaceAll("-", "_"), value]))).pipe(Effect49.mapError(() => new NotificationRequestInvalid({ operation: "PVE notification write" })));
3982
+ var notificationResponse = (schema) => (body5) => Schema3.decodeUnknownEffect(Schema3.toType(schema))(body5).pipe(Effect49.as(body5), Effect49.mapError(() => new ProxmoxParseError4({
3897
3983
  body: undefined,
3898
3984
  cause: "PVE notification response does not match its SDK schema"
3899
3985
  })));
3900
3986
 
3901
3987
  // src/proxmox/notification-matcher-distilled.ts
3902
- var readMatcher = (props) => runPve(props.target, "read", false, cluster5.getClusterNotificationMatcher({ name: props.name })).pipe(Effect46.flatMap(notificationResponse(cluster5.GetClusterNotificationMatcherResponse)), Effect46.map((live) => matcherAttributes({
3988
+ var readMatcher = (props) => runPve(props.target, "read", false, cluster8.getClusterNotificationMatcher({ name: props.name })).pipe(Effect50.flatMap(notificationResponse(cluster8.GetClusterNotificationMatcherResponse)), Effect50.map((live) => matcherAttributes({
3903
3989
  ...live,
3904
3990
  "invert-match": live.invert_match,
3905
3991
  "match-calendar": live.match_calendar,
3906
3992
  "match-field": live.match_field,
3907
3993
  "match-severity": live.match_severity
3908
- }, props.name)), Effect46.catchTag("NotFound", () => Effect46.succeed(undefined)));
3909
- var createMatcher = (props) => Effect46.gen(function* () {
3910
- const input = yield* notificationRequest(cluster5.CreateClusterNotificationMatcherRequest, matcherCreateForm(props));
3911
- yield* runPve(props.target, "provision", true, cluster5.createClusterNotificationMatcher(input));
3994
+ }, props.name)), Effect50.catchTag("NotFound", () => Effect50.succeed(undefined)));
3995
+ var createMatcher = (props) => Effect50.gen(function* () {
3996
+ const input = yield* notificationRequest(cluster8.CreateClusterNotificationMatcherRequest, matcherCreateForm(props));
3997
+ yield* runPve(props.target, "provision", true, cluster8.createClusterNotificationMatcher(input));
3912
3998
  });
3913
- var updateMatcher = (props) => Effect46.gen(function* () {
3914
- const input = yield* notificationRequest(cluster5.PutClusterNotificationMatcherRequest, {
3999
+ var updateMatcher = (props) => Effect50.gen(function* () {
4000
+ const input = yield* notificationRequest(cluster8.PutClusterNotificationMatcherRequest, {
3915
4001
  ...matcherUpdateForm(props),
3916
4002
  name: props.name
3917
4003
  });
3918
- yield* runPve(props.target, "provision", true, cluster5.putClusterNotificationMatcher(input));
4004
+ yield* runPve(props.target, "provision", true, cluster8.putClusterNotificationMatcher(input));
3919
4005
  });
3920
- var deleteMatcher = (props) => runPve(props.target, "provision", true, cluster5.deleteClusterNotificationMatcher({ name: props.name })).pipe(Effect46.catchTag("NotFound", () => Effect46.void));
4006
+ var deleteMatcher = (props) => runPve(props.target, "provision", true, cluster8.deleteClusterNotificationMatcher({ name: props.name })).pipe(Effect50.catchTag("NotFound", () => Effect50.void));
3921
4007
 
3922
4008
  // src/proxmox/notification-matcher-lifecycle.ts
3923
- var guard = (props, create) => guardForm("pve:POST /cluster/notifications/matchers", matcherCreateForm(props), create).pipe(Effect47.andThen(guardForm("pve:PUT /cluster/notifications/matchers/{name}", matcherUpdateForm(props), false)));
4009
+ var guard = (props, create) => guardForm("pve:POST /cluster/notifications/matchers", matcherCreateForm(props), create).pipe(Effect51.andThen(guardForm("pve:PUT /cluster/notifications/matchers/{name}", matcherUpdateForm(props), false)));
3924
4010
  var matcherHandlers = {
3925
- list: () => Effect47.succeed([]),
3926
- read: ({ olds }) => Effect47.gen(function* () {
4011
+ list: () => Effect51.succeed([]),
4012
+ read: ({ olds }) => Effect51.gen(function* () {
3927
4013
  const live = yield* readMatcher(olds);
3928
4014
  yield* guard(olds, live === undefined);
3929
4015
  return live;
@@ -3932,7 +4018,7 @@ var matcherHandlers = {
3932
4018
  news,
3933
4019
  olds,
3934
4020
  output
3935
- }) => Effect47.gen(function* () {
4021
+ }) => Effect51.gen(function* () {
3936
4022
  if (!isResolved15(news))
3937
4023
  return;
3938
4024
  if (olds.name !== news.name)
@@ -3947,7 +4033,7 @@ var matcherHandlers = {
3947
4033
  }
3948
4034
  return { action: matcherMatches(live, news) ? "noop" : "update" };
3949
4035
  }),
3950
- reconcile: ({ news }) => Effect47.gen(function* () {
4036
+ reconcile: ({ news }) => Effect51.gen(function* () {
3951
4037
  const live = yield* readMatcher(news);
3952
4038
  yield* guard(news, live === undefined);
3953
4039
  if (live === undefined)
@@ -3956,7 +4042,7 @@ var matcherHandlers = {
3956
4042
  yield* updateMatcher(news);
3957
4043
  const after = yield* readMatcher(news);
3958
4044
  if (after === undefined)
3959
- return yield* Effect47.die(new Error(`Notification matcher ${news.name}: write returned but read-back is absent.`));
4045
+ return yield* Effect51.die(new Error(`Notification matcher ${news.name}: write returned but read-back is absent.`));
3960
4046
  return after;
3961
4047
  }),
3962
4048
  delete: ({ olds }) => deleteMatcher(olds)
@@ -3964,15 +4050,15 @@ var matcherHandlers = {
3964
4050
 
3965
4051
  // src/proxmox/notification-matcher.ts
3966
4052
  var ProxmoxNotificationMatcher = Resource17("Proxmox.NotificationMatcher");
3967
- var ProxmoxNotificationMatcherProvider = () => Provider17.effect(ProxmoxNotificationMatcher, Effect48.succeed(ProxmoxNotificationMatcher.Provider.of(matcherHandlers)));
4053
+ var ProxmoxNotificationMatcherProvider = () => Provider17.effect(ProxmoxNotificationMatcher, Effect52.succeed(ProxmoxNotificationMatcher.Provider.of(matcherHandlers)));
3968
4054
  // src/proxmox/notification-target.ts
3969
4055
  import { Resource as Resource18 } from "alchemy";
3970
4056
  import * as Provider18 from "alchemy/Provider";
3971
- import * as Effect51 from "effect/Effect";
4057
+ import * as Effect55 from "effect/Effect";
3972
4058
 
3973
4059
  // src/proxmox/notification-target-lifecycle.ts
3974
4060
  import { isResolved as isResolved16 } from "alchemy/Diff";
3975
- import * as Effect50 from "effect/Effect";
4061
+ import * as Effect54 from "effect/Effect";
3976
4062
 
3977
4063
  // src/proxmox/notification-target-endpoint.ts
3978
4064
  var ENDPOINTS = {
@@ -4055,30 +4141,30 @@ var targetSpec = {
4055
4141
  };
4056
4142
 
4057
4143
  // src/proxmox/notification-target-distilled.ts
4058
- import * as cluster6 from "@distilled.cloud/proxmox/cluster";
4059
- import * as Effect49 from "effect/Effect";
4144
+ import * as cluster9 from "@distilled.cloud/proxmox/cluster";
4145
+ import * as Effect53 from "effect/Effect";
4060
4146
  var read3 = (props) => {
4061
4147
  const request = { name: props.name };
4062
4148
  switch (props.type) {
4063
4149
  case "gotify":
4064
- return cluster6.getClusterNotificationEndpointGotify(request).pipe(Effect49.flatMap(notificationResponse(cluster6.GetClusterNotificationEndpointGotifyResponse)), Effect49.map((row) => ({ ...row })));
4150
+ return cluster9.getClusterNotificationEndpointGotify(request).pipe(Effect53.flatMap(notificationResponse(cluster9.GetClusterNotificationEndpointGotifyResponse)), Effect53.map((row) => ({ ...row })));
4065
4151
  case "sendmail":
4066
- return cluster6.getClusterNotificationEndpointSendmail(request).pipe(Effect49.flatMap(notificationResponse(cluster6.GetClusterNotificationEndpointSendmailResponse)), Effect49.map((row) => ({
4152
+ return cluster9.getClusterNotificationEndpointSendmail(request).pipe(Effect53.flatMap(notificationResponse(cluster9.GetClusterNotificationEndpointSendmailResponse)), Effect53.map((row) => ({
4067
4153
  ...row,
4068
4154
  "from-address": row.from_address,
4069
4155
  "mailto-user": row.mailto_user
4070
4156
  })));
4071
4157
  case "smtp":
4072
- return cluster6.getClusterNotificationEndpointSmtp(request).pipe(Effect49.flatMap(notificationResponse(cluster6.GetClusterNotificationEndpointSmtpResponse)), Effect49.map((row) => ({
4158
+ return cluster9.getClusterNotificationEndpointSmtp(request).pipe(Effect53.flatMap(notificationResponse(cluster9.GetClusterNotificationEndpointSmtpResponse)), Effect53.map((row) => ({
4073
4159
  ...row,
4074
4160
  "from-address": row.from_address,
4075
4161
  "mailto-user": row.mailto_user
4076
4162
  })));
4077
4163
  case "webhook":
4078
- return cluster6.getClusterNotificationEndpointWebhook(request).pipe(Effect49.flatMap(notificationResponse(cluster6.GetClusterNotificationEndpointWebhookResponse)), Effect49.map((row) => ({ ...row })));
4164
+ return cluster9.getClusterNotificationEndpointWebhook(request).pipe(Effect53.flatMap(notificationResponse(cluster9.GetClusterNotificationEndpointWebhookResponse)), Effect53.map((row) => ({ ...row })));
4079
4165
  }
4080
4166
  };
4081
- var readTarget = (props) => runPve(props.target, "read", false, read3(props)).pipe(Effect49.map((row) => targetSpec.attributes(row, props)), Effect49.catchTag("NotFound", () => Effect49.succeed(undefined)));
4167
+ var readTarget = (props) => runPve(props.target, "read", false, read3(props)).pipe(Effect53.map((row) => targetSpec.attributes(row, props)), Effect53.catchTag("NotFound", () => Effect53.succeed(undefined)));
4082
4168
  var fields = (props, create) => {
4083
4169
  const form = {
4084
4170
  ...create ? createShape(props) : shape4(props),
@@ -4112,40 +4198,40 @@ var fields = (props, create) => {
4112
4198
  };
4113
4199
  var validateTargetWrite = (props, create) => {
4114
4200
  const schema = create ? {
4115
- sendmail: cluster6.CreateClusterNotificationEndpointSendmailRequest,
4116
- smtp: cluster6.CreateClusterNotificationEndpointSmtpRequest,
4117
- gotify: cluster6.CreateClusterNotificationEndpointGotifyRequest,
4118
- webhook: cluster6.CreateClusterNotificationEndpointWebhookRequest
4201
+ sendmail: cluster9.CreateClusterNotificationEndpointSendmailRequest,
4202
+ smtp: cluster9.CreateClusterNotificationEndpointSmtpRequest,
4203
+ gotify: cluster9.CreateClusterNotificationEndpointGotifyRequest,
4204
+ webhook: cluster9.CreateClusterNotificationEndpointWebhookRequest
4119
4205
  }[props.type] : {
4120
- sendmail: cluster6.PutClusterNotificationEndpointSendmailRequest,
4121
- smtp: cluster6.PutClusterNotificationEndpointSmtpRequest,
4122
- gotify: cluster6.PutClusterNotificationEndpointGotifyRequest,
4123
- webhook: cluster6.PutClusterNotificationEndpointWebhookRequest
4206
+ sendmail: cluster9.PutClusterNotificationEndpointSendmailRequest,
4207
+ smtp: cluster9.PutClusterNotificationEndpointSmtpRequest,
4208
+ gotify: cluster9.PutClusterNotificationEndpointGotifyRequest,
4209
+ webhook: cluster9.PutClusterNotificationEndpointWebhookRequest
4124
4210
  }[props.type];
4125
- return notificationRequest(schema, fields(props, create)).pipe(Effect49.asVoid);
4211
+ return notificationRequest(schema, fields(props, create)).pipe(Effect53.asVoid);
4126
4212
  };
4127
4213
  var createTarget = (props) => {
4128
4214
  const form = fields(props, true);
4129
- const operation = props.type === "sendmail" ? notificationRequest(cluster6.CreateClusterNotificationEndpointSendmailRequest, form).pipe(Effect49.flatMap(cluster6.createClusterNotificationEndpointSendmail)) : props.type === "smtp" ? notificationRequest(cluster6.CreateClusterNotificationEndpointSmtpRequest, form).pipe(Effect49.flatMap(cluster6.createClusterNotificationEndpointSmtp)) : props.type === "gotify" ? notificationRequest(cluster6.CreateClusterNotificationEndpointGotifyRequest, form).pipe(Effect49.flatMap(cluster6.createClusterNotificationEndpointGotify)) : notificationRequest(cluster6.CreateClusterNotificationEndpointWebhookRequest, form).pipe(Effect49.flatMap(cluster6.createClusterNotificationEndpointWebhook));
4215
+ const operation = props.type === "sendmail" ? notificationRequest(cluster9.CreateClusterNotificationEndpointSendmailRequest, form).pipe(Effect53.flatMap(cluster9.createClusterNotificationEndpointSendmail)) : props.type === "smtp" ? notificationRequest(cluster9.CreateClusterNotificationEndpointSmtpRequest, form).pipe(Effect53.flatMap(cluster9.createClusterNotificationEndpointSmtp)) : props.type === "gotify" ? notificationRequest(cluster9.CreateClusterNotificationEndpointGotifyRequest, form).pipe(Effect53.flatMap(cluster9.createClusterNotificationEndpointGotify)) : notificationRequest(cluster9.CreateClusterNotificationEndpointWebhookRequest, form).pipe(Effect53.flatMap(cluster9.createClusterNotificationEndpointWebhook));
4130
4216
  return runPve(props.target, "provision", true, operation);
4131
4217
  };
4132
4218
  var updateTarget = (props) => {
4133
4219
  const form = fields(props, false);
4134
- const operation = props.type === "sendmail" ? notificationRequest(cluster6.PutClusterNotificationEndpointSendmailRequest, form).pipe(Effect49.flatMap(cluster6.putClusterNotificationEndpointSendmail)) : props.type === "smtp" ? notificationRequest(cluster6.PutClusterNotificationEndpointSmtpRequest, form).pipe(Effect49.flatMap(cluster6.putClusterNotificationEndpointSmtp)) : props.type === "gotify" ? notificationRequest(cluster6.PutClusterNotificationEndpointGotifyRequest, form).pipe(Effect49.flatMap(cluster6.putClusterNotificationEndpointGotify)) : notificationRequest(cluster6.PutClusterNotificationEndpointWebhookRequest, form).pipe(Effect49.flatMap(cluster6.putClusterNotificationEndpointWebhook));
4220
+ const operation = props.type === "sendmail" ? notificationRequest(cluster9.PutClusterNotificationEndpointSendmailRequest, form).pipe(Effect53.flatMap(cluster9.putClusterNotificationEndpointSendmail)) : props.type === "smtp" ? notificationRequest(cluster9.PutClusterNotificationEndpointSmtpRequest, form).pipe(Effect53.flatMap(cluster9.putClusterNotificationEndpointSmtp)) : props.type === "gotify" ? notificationRequest(cluster9.PutClusterNotificationEndpointGotifyRequest, form).pipe(Effect53.flatMap(cluster9.putClusterNotificationEndpointGotify)) : notificationRequest(cluster9.PutClusterNotificationEndpointWebhookRequest, form).pipe(Effect53.flatMap(cluster9.putClusterNotificationEndpointWebhook));
4135
4221
  return runPve(props.target, "provision", true, operation);
4136
4222
  };
4137
4223
  var deleteTarget = (props) => {
4138
4224
  const request = { name: props.name };
4139
- const operation = props.type === "sendmail" ? cluster6.deleteClusterNotificationEndpointSendmail(request) : props.type === "smtp" ? cluster6.deleteClusterNotificationEndpointSmtp(request) : props.type === "gotify" ? cluster6.deleteClusterNotificationEndpointGotify(request) : cluster6.deleteClusterNotificationEndpointWebhook(request);
4140
- return runPve(props.target, "provision", true, operation).pipe(Effect49.catchTag("NotFound", () => Effect49.void));
4225
+ const operation = props.type === "sendmail" ? cluster9.deleteClusterNotificationEndpointSendmail(request) : props.type === "smtp" ? cluster9.deleteClusterNotificationEndpointSmtp(request) : props.type === "gotify" ? cluster9.deleteClusterNotificationEndpointGotify(request) : cluster9.deleteClusterNotificationEndpointWebhook(request);
4226
+ return runPve(props.target, "provision", true, operation).pipe(Effect53.catchTag("NotFound", () => Effect53.void));
4141
4227
  };
4142
4228
 
4143
4229
  // src/proxmox/notification-target-lifecycle.ts
4144
- var { guardCreate: guardCreate3, guardUpdate: guardUpdate3 } = specGuards(targetSpec);
4145
- var guard2 = (props, create) => guardCreate3(props, create).pipe(Effect50.andThen(guardUpdate3(props)));
4230
+ var { guardCreate: guardCreate4, guardUpdate: guardUpdate4 } = specGuards(targetSpec);
4231
+ var guard2 = (props, create) => guardCreate4(props, create).pipe(Effect54.andThen(guardUpdate4(props)));
4146
4232
  var targetHandlers = {
4147
- list: () => Effect50.succeed([]),
4148
- read: ({ olds }) => Effect50.gen(function* () {
4233
+ list: () => Effect54.succeed([]),
4234
+ read: ({ olds }) => Effect54.gen(function* () {
4149
4235
  const live = yield* readTarget(olds);
4150
4236
  yield* guard2(olds, live === undefined);
4151
4237
  return live;
@@ -4154,7 +4240,7 @@ var targetHandlers = {
4154
4240
  news,
4155
4241
  olds,
4156
4242
  output
4157
- }) => Effect50.gen(function* () {
4243
+ }) => Effect54.gen(function* () {
4158
4244
  if (!isResolved16(news))
4159
4245
  return;
4160
4246
  if (olds.name !== news.name || olds.type !== news.type) {
@@ -4173,7 +4259,7 @@ var targetHandlers = {
4173
4259
  }
4174
4260
  return { action: targetSpec.matches(live, news) ? "noop" : "update" };
4175
4261
  }),
4176
- reconcile: ({ news }) => Effect50.gen(function* () {
4262
+ reconcile: ({ news }) => Effect54.gen(function* () {
4177
4263
  const live = yield* readTarget(news);
4178
4264
  yield* guard2(news, live === undefined);
4179
4265
  if (live === undefined)
@@ -4182,7 +4268,7 @@ var targetHandlers = {
4182
4268
  yield* updateTarget(news);
4183
4269
  const after = yield* readTarget(news);
4184
4270
  if (after === undefined)
4185
- return yield* Effect50.die(new Error(`Notification target ${news.name}: write returned but read-back is absent.`));
4271
+ return yield* Effect54.die(new Error(`Notification target ${news.name}: write returned but read-back is absent.`));
4186
4272
  return after;
4187
4273
  }),
4188
4274
  delete: ({ olds }) => deleteTarget(olds)
@@ -4190,15 +4276,15 @@ var targetHandlers = {
4190
4276
 
4191
4277
  // src/proxmox/notification-target.ts
4192
4278
  var ProxmoxNotificationTarget = Resource18("Proxmox.NotificationTarget");
4193
- var ProxmoxNotificationTargetProvider = () => Provider18.effect(ProxmoxNotificationTarget, Effect51.succeed(ProxmoxNotificationTarget.Provider.of(targetHandlers)));
4279
+ var ProxmoxNotificationTargetProvider = () => Provider18.effect(ProxmoxNotificationTarget, Effect55.succeed(ProxmoxNotificationTarget.Provider.of(targetHandlers)));
4194
4280
  // src/proxmox/pbs-datastore.ts
4195
4281
  import { Resource as Resource19 } from "alchemy";
4196
4282
  import * as Provider19 from "alchemy/Provider";
4197
- import * as Effect57 from "effect/Effect";
4283
+ import * as Effect61 from "effect/Effect";
4198
4284
 
4199
4285
  // src/proxmox/pbs-datastore-lifecycle.ts
4200
4286
  import { isResolved as isResolved17 } from "alchemy/Diff";
4201
- import * as Effect56 from "effect/Effect";
4287
+ import * as Effect60 from "effect/Effect";
4202
4288
 
4203
4289
  // src/proxmox/pbs-datastore-form.ts
4204
4290
  var attributes = (live, props) => ({
@@ -4255,18 +4341,18 @@ var object2 = (props) => `config/datastore/${props.name}`;
4255
4341
 
4256
4342
  // src/proxmox/pbs-datastore-wire.ts
4257
4343
  import * as config from "@distilled.cloud/proxmox-backup/config";
4258
- import * as Effect53 from "effect/Effect";
4344
+ import * as Effect57 from "effect/Effect";
4259
4345
 
4260
4346
  // src/proxmox/distilled-pbs.ts
4261
4347
  import { credentials } from "@distilled.cloud/proxmox-backup/Credentials";
4262
4348
  import * as Retry from "@distilled.cloud/proxmox-backup/Retry";
4263
- import * as Effect52 from "effect/Effect";
4264
- var runPbsWith = (target, credential, op, timeout5 = MEMBER_TIMEOUT) => op.pipe(Retry.none, Effect52.provide(credentials({
4349
+ import * as Effect56 from "effect/Effect";
4350
+ var runPbsWith = (target, credential, op, timeout5 = MEMBER_TIMEOUT) => op.pipe(Retry.none, Effect56.provide(credentials({
4265
4351
  baseUrl: target.api,
4266
4352
  secret: credential.secret,
4267
4353
  tokenId: credential.tokenId
4268
- })), Effect52.timeout(timeout5));
4269
- var runPbs = (target, role, op) => Effect52.gen(function* () {
4354
+ })), Effect56.timeout(timeout5));
4355
+ var runPbs = (target, role, op) => Effect56.gen(function* () {
4270
4356
  const credential = yield* leased(target, role);
4271
4357
  return yield* runPbsWith(target, credential, op);
4272
4358
  });
@@ -4316,52 +4402,52 @@ var wire = (row) => ({
4316
4402
  "prune-schedule": row.prune_schedule,
4317
4403
  "verify-new": row.verify_new
4318
4404
  });
4319
- var readOne = (props) => runPbs(props.target, "read", config.getConfigDatastore({ name: props.name })).pipe(Effect53.map((live) => attributes(wire(live), props)), Effect53.catchTag("DatastoreNotFound", () => Effect53.succeed(undefined)));
4405
+ var readOne = (props) => runPbs(props.target, "read", config.getConfigDatastore({ name: props.name })).pipe(Effect57.map((live) => attributes(wire(live), props)), Effect57.catchTag("DatastoreNotFound", () => Effect57.succeed(undefined)));
4320
4406
  var createOne = (props) => runPbs(props.target, "provision", config.createConfigDatastore(createRequest(props)));
4321
4407
  var updateOne = (props) => runPbs(props.target, "provision", config.putConfigDatastore(updateRequest(props)));
4322
- var deleteOne = (props) => Effect53.gen(function* () {
4408
+ var deleteOne = (props) => Effect57.gen(function* () {
4323
4409
  if ((yield* readOne(props)) === undefined)
4324
4410
  return;
4325
4411
  return yield* runPbs(props.target, "provision", config.deleteConfigDatastore({ name: props.name }));
4326
4412
  });
4327
4413
 
4328
4414
  // src/proxmox/pbs-datastore-guard.ts
4329
- import * as Effect54 from "effect/Effect";
4415
+ import * as Effect58 from "effect/Effect";
4330
4416
  var samePath = (left, right) => {
4331
4417
  const trim = (value) => value.length > 1 ? value.replace(/\/+$/, "") : value;
4332
4418
  return trim(left) === trim(right);
4333
4419
  };
4334
- var guardPath = (live, props) => live.path === "" || samePath(live.path, props.path) ? Effect54.void : Effect54.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."));
4335
- var guardBackend = (live, props) => props.backend === undefined || propertyString(props.backend) === live.backend ? Effect54.void : Effect54.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."));
4336
- var settle2 = (read4, done) => Effect54.gen(function* () {
4420
+ var guardPath = (live, props) => live.path === "" || samePath(live.path, props.path) ? Effect58.void : Effect58.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."));
4421
+ var guardBackend = (live, props) => props.backend === undefined || propertyString(props.backend) === live.backend ? Effect58.void : Effect58.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."));
4422
+ var settle2 = (read4, done) => Effect58.gen(function* () {
4337
4423
  for (let attempt = 0;attempt < 60; attempt += 1) {
4338
4424
  const live = yield* read4;
4339
4425
  if (done(live))
4340
4426
  return live;
4341
- yield* Effect54.sleep("2 seconds");
4427
+ yield* Effect58.sleep("2 seconds");
4342
4428
  }
4343
4429
  return yield* read4;
4344
4430
  });
4345
4431
 
4346
4432
  // src/proxmox/pbs-datastore-endpoint.ts
4347
- import * as Effect55 from "effect/Effect";
4433
+ import * as Effect59 from "effect/Effect";
4348
4434
  var DATASTORE_ENDPOINT = {
4349
4435
  create: "pbs:POST /config/datastore",
4350
4436
  update: "pbs:PUT /config/datastore/{name}"
4351
4437
  };
4352
- var guardDatastoreForms = (props) => Effect55.gen(function* () {
4438
+ var guardDatastoreForms = (props) => Effect59.gen(function* () {
4353
4439
  yield* guardForm(DATASTORE_ENDPOINT.create, createForm6(props), true);
4354
4440
  yield* guardForm(DATASTORE_ENDPOINT.update, updateForm3(props), false);
4355
4441
  });
4356
4442
 
4357
4443
  // src/proxmox/pbs-datastore-lifecycle.ts
4358
- var handlers8 = {
4359
- list: () => Effect56.succeed([]),
4444
+ var handlers7 = {
4445
+ list: () => Effect60.succeed([]),
4360
4446
  read: ({ olds }) => readOne(olds),
4361
4447
  diff: ({
4362
4448
  news,
4363
4449
  output
4364
- }) => Effect56.gen(function* () {
4450
+ }) => Effect60.gen(function* () {
4365
4451
  if (!isResolved17(news))
4366
4452
  return;
4367
4453
  yield* guardDatastoreForms(news);
@@ -4374,7 +4460,7 @@ var handlers8 = {
4374
4460
  yield* guardBackend(live, news);
4375
4461
  return matches6(live, news) ? { action: "noop" } : { action: "update" };
4376
4462
  }),
4377
- reconcile: Effect56.fn(function* ({ news }) {
4463
+ reconcile: Effect60.fn(function* ({ news }) {
4378
4464
  yield* guardDatastoreForms(news);
4379
4465
  const live = yield* readOne(news);
4380
4466
  if (live === undefined) {
@@ -4389,15 +4475,15 @@ var handlers8 = {
4389
4475
  }
4390
4476
  const after = yield* settle2(readOne(news), (row) => row !== undefined && matches6(row, news));
4391
4477
  if (after === undefined || !matches6(after, news)) {
4392
- return yield* Effect56.die(new Error(`${object2(news)}: the write returned no error but the datastore still does not ` + "match the declaration after 120s. Check the PBS task list " + "-- 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."));
4478
+ return yield* Effect60.die(new Error(`${object2(news)}: the write returned no error but the datastore still does not ` + "match the declaration after 120s. Check the PBS task list " + "-- 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."));
4393
4479
  }
4394
4480
  return after;
4395
4481
  }),
4396
- delete: Effect56.fn(function* ({ olds }) {
4482
+ delete: Effect60.fn(function* ({ olds }) {
4397
4483
  yield* deleteOne(olds);
4398
4484
  const left = yield* settle2(readOne(olds), (row) => row === undefined);
4399
4485
  if (left !== undefined) {
4400
- return yield* Effect56.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>\`.`));
4486
+ return yield* Effect60.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>\`.`));
4401
4487
  }
4402
4488
  })
4403
4489
  };
@@ -4406,36 +4492,36 @@ var handlers8 = {
4406
4492
  var PbsDatastore = Resource19("Pbs.Datastore", {
4407
4493
  defaultRemovalPolicy: "retain"
4408
4494
  });
4409
- var PbsDatastoreProvider = () => Provider19.effect(PbsDatastore, Effect57.succeed(PbsDatastore.Provider.of(handlers8)));
4495
+ var PbsDatastoreProvider = () => Provider19.effect(PbsDatastore, Effect61.succeed(PbsDatastore.Provider.of(handlers7)));
4410
4496
  // src/proxmox/pbs-notification-matcher.ts
4411
4497
  import { Resource as Resource20 } from "alchemy";
4412
4498
  import * as Provider20 from "alchemy/Provider";
4413
4499
  import { isResolved as isResolved18 } from "alchemy/Diff";
4414
- import * as Effect60 from "effect/Effect";
4500
+ import * as Effect64 from "effect/Effect";
4415
4501
 
4416
4502
  // src/proxmox/pbs-notification-matcher-distilled.ts
4417
4503
  import * as config2 from "@distilled.cloud/proxmox-backup/config";
4418
- import * as Effect59 from "effect/Effect";
4504
+ import * as Effect63 from "effect/Effect";
4419
4505
 
4420
4506
  // src/proxmox/pbs-notification-input.ts
4421
4507
  import * as Data3 from "effect/Data";
4422
- import * as Effect58 from "effect/Effect";
4508
+ import * as Effect62 from "effect/Effect";
4423
4509
  import * as Schema4 from "effect/Schema";
4424
4510
 
4425
4511
  class PbsNotificationInputRefusal extends Data3.TaggedError("PbsNotificationInputRefusal") {
4426
4512
  }
4427
- var notificationInput = (schema, fields2) => Schema4.decodeUnknownEffect(Schema4.toType(schema))(fields2).pipe(Effect58.mapError(() => new PbsNotificationInputRefusal({
4513
+ var notificationInput = (schema, fields2) => Schema4.decodeUnknownEffect(Schema4.toType(schema))(fields2).pipe(Effect62.mapError(() => new PbsNotificationInputRefusal({
4428
4514
  message: "PBS notification fields do not match the SDK request schema; no PBS request was sent."
4429
4515
  })));
4430
4516
 
4431
4517
  // src/proxmox/pbs-notification-matcher-distilled.ts
4432
- var readMatcher2 = (props) => runPbs(props.target, "read", config2.getConfigNotificationMatcher({ name: props.name })).pipe(Effect59.map((row) => matcherAttributes({
4518
+ var readMatcher2 = (props) => runPbs(props.target, "read", config2.getConfigNotificationMatcher({ name: props.name })).pipe(Effect63.map((row) => matcherAttributes({
4433
4519
  ...row,
4434
4520
  "invert-match": row.invert_match,
4435
4521
  "match-calendar": row.match_calendar,
4436
4522
  "match-field": row.match_field,
4437
4523
  "match-severity": row.match_severity
4438
- }, props.name)), Effect59.catchTag("NotFound", () => Effect59.succeed(undefined)));
4524
+ }, props.name)), Effect63.catchTag("NotFound", () => Effect63.succeed(undefined)));
4439
4525
  var requestFields = (props, form) => ({
4440
4526
  ...form,
4441
4527
  invert_match: form["invert-match"],
@@ -4444,65 +4530,65 @@ var requestFields = (props, form) => ({
4444
4530
  match_severity: form["match-severity"],
4445
4531
  name: props.name
4446
4532
  });
4447
- var createMatcher2 = (props, form) => runPbs(props.target, "provision", notificationInput(config2.CreateConfigNotificationMatcherRequest, requestFields(props, form)).pipe(Effect59.flatMap(config2.createConfigNotificationMatcher)));
4448
- var updateMatcher2 = (props, form) => runPbs(props.target, "provision", notificationInput(config2.PutConfigNotificationMatcherRequest, requestFields(props, form)).pipe(Effect59.flatMap(config2.putConfigNotificationMatcher)));
4449
- var deleteMatcher2 = (props) => runPbs(props.target, "provision", config2.deleteConfigNotificationMatcher({ name: props.name })).pipe(Effect59.catchTag("NotFound", () => Effect59.void));
4533
+ var createMatcher2 = (props, form) => runPbs(props.target, "provision", notificationInput(config2.CreateConfigNotificationMatcherRequest, requestFields(props, form)).pipe(Effect63.flatMap(config2.createConfigNotificationMatcher)));
4534
+ var updateMatcher2 = (props, form) => runPbs(props.target, "provision", notificationInput(config2.PutConfigNotificationMatcherRequest, requestFields(props, form)).pipe(Effect63.flatMap(config2.putConfigNotificationMatcher)));
4535
+ var deleteMatcher2 = (props) => runPbs(props.target, "provision", config2.deleteConfigNotificationMatcher({ name: props.name })).pipe(Effect63.catchTag("NotFound", () => Effect63.void));
4450
4536
 
4451
4537
  // src/proxmox/pbs-notification-matcher.ts
4452
4538
  var PbsNotificationMatcher = Resource20("Pbs.NotificationMatcher");
4453
- var guardCreate4 = (props, requirePresence) => guardForm("pbs:POST /config/notifications/matchers", matcherCreateForm(props), requirePresence);
4454
- var guardUpdate4 = (props) => guardForm("pbs:PUT /config/notifications/matchers/{name}", matcherUpdateForm(props), false);
4455
- var handlers9 = {
4456
- list: () => Effect60.succeed([]),
4539
+ var guardCreate5 = (props, requirePresence) => guardForm("pbs:POST /config/notifications/matchers", matcherCreateForm(props), requirePresence);
4540
+ var guardUpdate5 = (props) => guardForm("pbs:PUT /config/notifications/matchers/{name}", matcherUpdateForm(props), false);
4541
+ var handlers8 = {
4542
+ list: () => Effect64.succeed([]),
4457
4543
  read: ({ olds }) => readMatcher2(olds),
4458
4544
  diff: ({
4459
4545
  news,
4460
4546
  olds,
4461
4547
  output
4462
- }) => Effect60.gen(function* () {
4548
+ }) => Effect64.gen(function* () {
4463
4549
  if (!isResolved18(news))
4464
4550
  return;
4465
- yield* guardCreate4(news, output === undefined);
4466
- yield* guardUpdate4(news);
4551
+ yield* guardCreate5(news, output === undefined);
4552
+ yield* guardUpdate5(news);
4467
4553
  if (output === undefined)
4468
4554
  return;
4469
4555
  if (olds.name !== news.name)
4470
4556
  return { action: "replace" };
4471
4557
  const live = yield* readMatcher2(news);
4472
4558
  if (live === undefined) {
4473
- yield* guardCreate4(news, true);
4559
+ yield* guardCreate5(news, true);
4474
4560
  return { action: "update" };
4475
4561
  }
4476
4562
  return { action: matcherMatches(live, news) ? "noop" : "update" };
4477
4563
  }),
4478
- reconcile: ({ news }) => Effect60.gen(function* () {
4564
+ reconcile: ({ news }) => Effect64.gen(function* () {
4479
4565
  const live = yield* readMatcher2(news);
4480
- yield* guardCreate4(news, live === undefined);
4481
- yield* guardUpdate4(news);
4566
+ yield* guardCreate5(news, live === undefined);
4567
+ yield* guardUpdate5(news);
4482
4568
  if (live === undefined)
4483
4569
  yield* createMatcher2(news, matcherCreateForm(news));
4484
4570
  else if (!matcherMatches(live, news))
4485
4571
  yield* updateMatcher2(news, matcherUpdateForm(news));
4486
4572
  const after = yield* readMatcher2(news);
4487
4573
  if (after === undefined)
4488
- return yield* Effect60.fail(new Error(`config/notifications/matchers/${news.name}: the write returned no error but the matcher is still absent.`));
4574
+ return yield* Effect64.fail(new Error(`config/notifications/matchers/${news.name}: the write returned no error but the matcher is still absent.`));
4489
4575
  return after;
4490
4576
  }),
4491
4577
  delete: ({ olds }) => deleteMatcher2(olds)
4492
4578
  };
4493
- var PbsNotificationMatcherProvider = () => Provider20.effect(PbsNotificationMatcher, Effect60.succeed(PbsNotificationMatcher.Provider.of(handlers9)));
4579
+ var PbsNotificationMatcherProvider = () => Provider20.effect(PbsNotificationMatcher, Effect64.succeed(PbsNotificationMatcher.Provider.of(handlers8)));
4494
4580
  // src/proxmox/pbs-notification-target.ts
4495
4581
  import { Resource as Resource21 } from "alchemy";
4496
4582
  import * as Provider21 from "alchemy/Provider";
4497
- import * as Effect63 from "effect/Effect";
4583
+ import * as Effect67 from "effect/Effect";
4498
4584
 
4499
4585
  // src/proxmox/pbs-notification-target-lifecycle.ts
4500
4586
  import { isResolved as isResolved19 } from "alchemy/Diff";
4501
- import * as Effect62 from "effect/Effect";
4587
+ import * as Effect66 from "effect/Effect";
4502
4588
 
4503
4589
  // src/proxmox/pbs-notification-target-distilled.ts
4504
4590
  import * as config3 from "@distilled.cloud/proxmox-backup/config";
4505
- import * as Effect61 from "effect/Effect";
4591
+ import * as Effect65 from "effect/Effect";
4506
4592
 
4507
4593
  // src/proxmox/pbs-notification-target-wire.ts
4508
4594
  import { Buffer as Buffer2 } from "node:buffer";
@@ -4603,22 +4689,22 @@ var requestFields2 = (props, form) => ({
4603
4689
  var read4 = (props) => {
4604
4690
  switch (props.type) {
4605
4691
  case "sendmail":
4606
- return config3.getConfigNotificationEndpointSendmail({ name: props.name }).pipe(Effect61.map((row) => ({
4692
+ return config3.getConfigNotificationEndpointSendmail({ name: props.name }).pipe(Effect65.map((row) => ({
4607
4693
  ...row,
4608
4694
  "from-address": row.from_address,
4609
4695
  "mailto-user": row.mailto_user
4610
4696
  })));
4611
4697
  case "smtp":
4612
- return config3.getConfigNotificationEndpointSmtp({ name: props.name }).pipe(Effect61.map((row) => ({
4698
+ return config3.getConfigNotificationEndpointSmtp({ name: props.name }).pipe(Effect65.map((row) => ({
4613
4699
  ...row,
4614
4700
  "from-address": row.from_address,
4615
4701
  "mailto-user": row.mailto_user
4616
4702
  })));
4617
4703
  case "webhook":
4618
- return config3.getConfigNotificationEndpointWebhook({ name: props.name }).pipe(Effect61.map((row) => ({ ...row })));
4704
+ return config3.getConfigNotificationEndpointWebhook({ name: props.name }).pipe(Effect65.map((row) => ({ ...row })));
4619
4705
  }
4620
4706
  };
4621
- var readTarget2 = (props) => runPbs(props.target, "read", read4(props)).pipe(Effect61.map((row) => targetAttributes(row, props)), Effect61.catchTag("NotFound", () => Effect61.succeed(undefined)));
4707
+ var readTarget2 = (props) => runPbs(props.target, "read", read4(props)).pipe(Effect65.map((row) => targetAttributes(row, props)), Effect65.catchTag("NotFound", () => Effect65.succeed(undefined)));
4622
4708
  var validateTargetWrite2 = (props, form, mode) => {
4623
4709
  const schema = mode === "create" ? {
4624
4710
  sendmail: config3.CreateConfigNotificationEndpointSendmailRequest,
@@ -4629,22 +4715,22 @@ var validateTargetWrite2 = (props, form, mode) => {
4629
4715
  smtp: config3.PutConfigNotificationEndpointSmtpRequest,
4630
4716
  webhook: config3.PutConfigNotificationEndpointWebhookRequest
4631
4717
  }[props.type];
4632
- return notificationInput(schema, requestFields2(props, form)).pipe(Effect61.asVoid);
4718
+ return notificationInput(schema, requestFields2(props, form)).pipe(Effect65.asVoid);
4633
4719
  };
4634
4720
  var createTarget2 = (props, form) => {
4635
4721
  const fields2 = requestFields2(props, form);
4636
- const operation = props.type === "sendmail" ? notificationInput(config3.CreateConfigNotificationEndpointSendmailRequest, fields2).pipe(Effect61.flatMap(config3.createConfigNotificationEndpointSendmail)) : props.type === "smtp" ? notificationInput(config3.CreateConfigNotificationEndpointSmtpRequest, fields2).pipe(Effect61.flatMap(config3.createConfigNotificationEndpointSmtp)) : notificationInput(config3.CreateConfigNotificationEndpointWebhookRequest, fields2).pipe(Effect61.flatMap(config3.createConfigNotificationEndpointWebhook));
4722
+ const operation = props.type === "sendmail" ? notificationInput(config3.CreateConfigNotificationEndpointSendmailRequest, fields2).pipe(Effect65.flatMap(config3.createConfigNotificationEndpointSendmail)) : props.type === "smtp" ? notificationInput(config3.CreateConfigNotificationEndpointSmtpRequest, fields2).pipe(Effect65.flatMap(config3.createConfigNotificationEndpointSmtp)) : notificationInput(config3.CreateConfigNotificationEndpointWebhookRequest, fields2).pipe(Effect65.flatMap(config3.createConfigNotificationEndpointWebhook));
4637
4723
  return runPbs(props.target, "provision", operation);
4638
4724
  };
4639
4725
  var updateTarget2 = (props, form) => {
4640
4726
  const fields2 = requestFields2(props, form);
4641
- const operation = props.type === "sendmail" ? notificationInput(config3.PutConfigNotificationEndpointSendmailRequest, fields2).pipe(Effect61.flatMap(config3.putConfigNotificationEndpointSendmail)) : props.type === "smtp" ? notificationInput(config3.PutConfigNotificationEndpointSmtpRequest, fields2).pipe(Effect61.flatMap(config3.putConfigNotificationEndpointSmtp)) : notificationInput(config3.PutConfigNotificationEndpointWebhookRequest, fields2).pipe(Effect61.flatMap(config3.putConfigNotificationEndpointWebhook));
4727
+ const operation = props.type === "sendmail" ? notificationInput(config3.PutConfigNotificationEndpointSendmailRequest, fields2).pipe(Effect65.flatMap(config3.putConfigNotificationEndpointSendmail)) : props.type === "smtp" ? notificationInput(config3.PutConfigNotificationEndpointSmtpRequest, fields2).pipe(Effect65.flatMap(config3.putConfigNotificationEndpointSmtp)) : notificationInput(config3.PutConfigNotificationEndpointWebhookRequest, fields2).pipe(Effect65.flatMap(config3.putConfigNotificationEndpointWebhook));
4642
4728
  return runPbs(props.target, "provision", operation);
4643
4729
  };
4644
4730
  var deleteTarget2 = (props) => {
4645
4731
  const request = { name: props.name };
4646
4732
  const operation = props.type === "sendmail" ? config3.deleteConfigNotificationEndpointSendmail(request) : props.type === "smtp" ? config3.deleteConfigNotificationEndpointSmtp(request) : config3.deleteConfigNotificationEndpointWebhook(request);
4647
- return runPbs(props.target, "provision", operation).pipe(Effect61.catchTag("NotFound", () => Effect61.void));
4733
+ return runPbs(props.target, "provision", operation).pipe(Effect65.catchTag("NotFound", () => Effect65.void));
4648
4734
  };
4649
4735
 
4650
4736
  // src/proxmox/pbs-notification-target-endpoint.ts
@@ -4835,7 +4921,7 @@ var targetForm = (props, groups, carry, mode) => {
4835
4921
  var path = (props) => `config/notifications/endpoints/${props.type}/${props.name}`;
4836
4922
  var refuse2 = (props) => {
4837
4923
  const reasons = refusals(props);
4838
- return reasons.length === 0 ? Effect62.void : Effect62.die(new Error(`${path(props)}: ${reasons.join("; ")}.`));
4924
+ return reasons.length === 0 ? Effect66.void : Effect66.die(new Error(`${path(props)}: ${reasons.join("; ")}.`));
4839
4925
  };
4840
4926
  var toCarry = (live, props, groups, sealed) => {
4841
4927
  const header = headerState(live, props, groups) === "stale";
@@ -4847,16 +4933,16 @@ var requireValues = (props, groups, carry) => {
4847
4933
  ...carry.header ? groups.header.missing : [],
4848
4934
  ...carry.sealed ? groups.sealed.missing : []
4849
4935
  ];
4850
- return missing.length === 0 ? Effect62.void : Effect62.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."));
4936
+ return missing.length === 0 ? Effect66.void : Effect66.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."));
4851
4937
  };
4852
- var handlers10 = {
4853
- list: () => Effect62.succeed([]),
4854
- read: ({ olds, output }) => (output === undefined ? refuse2(olds) : Effect62.void).pipe(Effect62.andThen(readTarget2(olds)), Effect62.map((live) => live === undefined ? undefined : { ...live, sealed: output?.sealed ?? "" })),
4938
+ var handlers9 = {
4939
+ list: () => Effect66.succeed([]),
4940
+ read: ({ olds, output }) => (output === undefined ? refuse2(olds) : Effect66.void).pipe(Effect66.andThen(readTarget2(olds)), Effect66.map((live) => live === undefined ? undefined : { ...live, sealed: output?.sealed ?? "" })),
4855
4941
  diff: ({
4856
4942
  news,
4857
4943
  olds,
4858
4944
  output
4859
- }) => Effect62.gen(function* () {
4945
+ }) => Effect66.gen(function* () {
4860
4946
  if (output === undefined || !isResolved19(news))
4861
4947
  return;
4862
4948
  yield* refuse2(news);
@@ -4878,7 +4964,7 @@ var handlers10 = {
4878
4964
  return { action: "update" };
4879
4965
  return toCarry(live, news, resolveGroups(news), output.sealed) === undefined ? { action: "noop" } : { action: "update" };
4880
4966
  }),
4881
- reconcile: ({ news, output }) => Effect62.gen(function* () {
4967
+ reconcile: ({ news, output }) => Effect66.gen(function* () {
4882
4968
  yield* refuse2(news);
4883
4969
  const groups = resolveGroups(news);
4884
4970
  const live = yield* readTarget2(news);
@@ -4903,7 +4989,7 @@ var handlers10 = {
4903
4989
  }
4904
4990
  const after = yield* readTarget2(news);
4905
4991
  if (after === undefined) {
4906
- return yield* Effect62.die(new Error(`${path(news)}: the write returned no error but the target is still absent.`));
4992
+ return yield* Effect66.die(new Error(`${path(news)}: the write returned no error but the target is still absent.`));
4907
4993
  }
4908
4994
  return { ...after, sealed };
4909
4995
  }),
@@ -4912,15 +4998,15 @@ var handlers10 = {
4912
4998
 
4913
4999
  // src/proxmox/pbs-notification-target.ts
4914
5000
  var PbsNotificationTarget = Resource21("Pbs.NotificationTarget");
4915
- var PbsNotificationTargetProvider = () => Provider21.effect(PbsNotificationTarget, Effect63.succeed(PbsNotificationTarget.Provider.of(handlers10)));
5001
+ var PbsNotificationTargetProvider = () => Provider21.effect(PbsNotificationTarget, Effect67.succeed(PbsNotificationTarget.Provider.of(handlers9)));
4916
5002
  // src/proxmox/pbs-prune-job.ts
4917
5003
  import { Resource as Resource22 } from "alchemy";
4918
5004
  import * as Provider22 from "alchemy/Provider";
4919
- import * as Effect66 from "effect/Effect";
5005
+ import * as Effect70 from "effect/Effect";
4920
5006
 
4921
5007
  // src/proxmox/pbs-prune-job-lifecycle.ts
4922
5008
  import { isResolved as isResolved20 } from "alchemy/Diff";
4923
- import * as Effect65 from "effect/Effect";
5009
+ import * as Effect69 from "effect/Effect";
4924
5010
 
4925
5011
  // src/proxmox/pbs-prune-job-form.ts
4926
5012
  var KEEP_KEYS = [
@@ -4998,7 +5084,7 @@ var spec = {
4998
5084
 
4999
5085
  // src/proxmox/pbs-prune-job-wire.ts
5000
5086
  import * as config4 from "@distilled.cloud/proxmox-backup/config";
5001
- import * as Effect64 from "effect/Effect";
5087
+ import * as Effect68 from "effect/Effect";
5002
5088
  var members2 = (form) => ({
5003
5089
  ...form["comment"] === undefined ? {} : { comment: form["comment"] },
5004
5090
  ...form["disable"] === undefined ? {} : { disable: form["disable"] },
@@ -5033,48 +5119,48 @@ var wire2 = (row) => ({
5033
5119
  "keep-yearly": row.keep_yearly,
5034
5120
  "max-depth": row.max_depth
5035
5121
  });
5036
- var readOne2 = (props) => runPbs(props.target, "read", config4.getConfigPrune({ id: props.id })).pipe(Effect64.map((row) => spec.attributes(wire2(row), props)), Effect64.catchTag("PruneJobNotFound", () => Effect64.succeed(undefined)));
5122
+ var readOne2 = (props) => runPbs(props.target, "read", config4.getConfigPrune({ id: props.id })).pipe(Effect68.map((row) => spec.attributes(wire2(row), props)), Effect68.catchTag("PruneJobNotFound", () => Effect68.succeed(undefined)));
5037
5123
  var createOne2 = (props) => runPbs(props.target, "provision", config4.createConfigPrune(createRequest2(props)));
5038
5124
  var updateOne2 = (props) => runPbs(props.target, "provision", config4.putConfigPrune(updateRequest2(props)));
5039
- var deleteOne2 = (props) => Effect64.gen(function* () {
5125
+ var deleteOne2 = (props) => Effect68.gen(function* () {
5040
5126
  if ((yield* readOne2(props)) === undefined)
5041
5127
  return;
5042
5128
  return yield* runPbs(props.target, "provision", config4.deleteConfigPrune({ id: props.id }));
5043
5129
  });
5044
5130
 
5045
5131
  // src/proxmox/pbs-prune-job-lifecycle.ts
5046
- var { guardCreate: guardCreate5, guardUpdate: guardUpdate5 } = specGuards(spec);
5047
- var handlers11 = {
5048
- list: () => Effect65.succeed([]),
5132
+ var { guardCreate: guardCreate6, guardUpdate: guardUpdate6 } = specGuards(spec);
5133
+ var handlers10 = {
5134
+ list: () => Effect69.succeed([]),
5049
5135
  read: ({ olds }) => readOne2(olds),
5050
5136
  diff: ({
5051
5137
  news,
5052
5138
  output
5053
- }) => Effect65.gen(function* () {
5139
+ }) => Effect69.gen(function* () {
5054
5140
  if (!isResolved20(news))
5055
5141
  return;
5056
- yield* guardCreate5(news, output === undefined);
5057
- yield* guardUpdate5(news);
5142
+ yield* guardCreate6(news, output === undefined);
5143
+ yield* guardUpdate6(news);
5058
5144
  if (output === undefined)
5059
5145
  return;
5060
5146
  const live = yield* readOne2(news);
5061
5147
  if (live === undefined) {
5062
- yield* guardCreate5(news, true);
5148
+ yield* guardCreate6(news, true);
5063
5149
  return { action: "update" };
5064
5150
  }
5065
5151
  return { action: spec.matches(live, news) ? "noop" : "update" };
5066
5152
  }),
5067
- reconcile: ({ news }) => Effect65.gen(function* () {
5153
+ reconcile: ({ news }) => Effect69.gen(function* () {
5068
5154
  const live = yield* readOne2(news);
5069
- yield* guardCreate5(news, live === undefined);
5070
- yield* guardUpdate5(news);
5155
+ yield* guardCreate6(news, live === undefined);
5156
+ yield* guardUpdate6(news);
5071
5157
  if (live === undefined)
5072
5158
  yield* createOne2(news);
5073
5159
  else if (!spec.matches(live, news))
5074
5160
  yield* updateOne2(news);
5075
5161
  const after = yield* readOne2(news);
5076
5162
  if (after === undefined) {
5077
- return yield* Effect65.fail(new Error(`${spec.path(news)}: write succeeded but job is absent.`));
5163
+ return yield* Effect69.fail(new Error(`${spec.path(news)}: write succeeded but job is absent.`));
5078
5164
  }
5079
5165
  return after;
5080
5166
  }),
@@ -5083,15 +5169,15 @@ var handlers11 = {
5083
5169
 
5084
5170
  // src/proxmox/pbs-prune-job.ts
5085
5171
  var PbsPruneJob = Resource22("Pbs.PruneJob");
5086
- var PbsPruneJobProvider = () => Provider22.effect(PbsPruneJob, Effect66.succeed(PbsPruneJob.Provider.of(handlers11)));
5172
+ var PbsPruneJobProvider = () => Provider22.effect(PbsPruneJob, Effect70.succeed(PbsPruneJob.Provider.of(handlers10)));
5087
5173
  // src/proxmox/pbs-sync-job.ts
5088
5174
  import { Resource as Resource23 } from "alchemy";
5089
5175
  import * as Provider23 from "alchemy/Provider";
5090
- import * as Effect69 from "effect/Effect";
5176
+ import * as Effect73 from "effect/Effect";
5091
5177
 
5092
5178
  // src/proxmox/pbs-sync-job-lifecycle.ts
5093
5179
  import { isResolved as isResolved21 } from "alchemy/Diff";
5094
- import * as Effect68 from "effect/Effect";
5180
+ import * as Effect72 from "effect/Effect";
5095
5181
 
5096
5182
  // src/proxmox/pbs-sync-job-form.ts
5097
5183
  var UNSET4 = -1;
@@ -5168,7 +5254,7 @@ var spec2 = {
5168
5254
 
5169
5255
  // src/proxmox/pbs-sync-job-wire.ts
5170
5256
  import * as config5 from "@distilled.cloud/proxmox-backup/config";
5171
- import * as Effect67 from "effect/Effect";
5257
+ import * as Effect71 from "effect/Effect";
5172
5258
  var members3 = (form) => ({
5173
5259
  ...form["remote-store"] === undefined ? {} : { remote_store: form["remote-store"] },
5174
5260
  ...form["remove-vanished"] === undefined ? {} : { remove_vanished: form["remove-vanished"] },
@@ -5207,45 +5293,45 @@ var wire3 = (row) => ({
5207
5293
  "sync-direction": row.sync_direction,
5208
5294
  "group-filter": row.group_filter
5209
5295
  });
5210
- var readOne3 = (props) => runPbs(props.target, "read", config5.getConfigSync({ id: props.id })).pipe(Effect67.map((row) => spec2.attributes(wire3(row), props)), Effect67.catchTag("SyncJobNotFound", () => Effect67.succeed(undefined)));
5296
+ var readOne3 = (props) => runPbs(props.target, "read", config5.getConfigSync({ id: props.id })).pipe(Effect71.map((row) => spec2.attributes(wire3(row), props)), Effect71.catchTag("SyncJobNotFound", () => Effect71.succeed(undefined)));
5211
5297
  var createOne3 = (props) => runPbs(props.target, "provision", config5.syncConfig(createRequest3(props)));
5212
5298
  var updateOne3 = (props) => runPbs(props.target, "provision", config5.putConfigSync(updateRequest3(props)));
5213
- var deleteOne3 = (props) => Effect67.gen(function* () {
5299
+ var deleteOne3 = (props) => Effect71.gen(function* () {
5214
5300
  if ((yield* readOne3(props)) === undefined)
5215
5301
  return;
5216
5302
  return yield* runPbs(props.target, "provision", config5.deleteConfigSync({ id: props.id }));
5217
5303
  });
5218
5304
 
5219
5305
  // src/proxmox/pbs-sync-job-lifecycle.ts
5220
- var { guardCreate: guardCreate6, guardUpdate: guardUpdate6 } = specGuards(spec2);
5221
- var handlers12 = {
5222
- list: () => Effect68.succeed([]),
5306
+ var { guardCreate: guardCreate7, guardUpdate: guardUpdate7 } = specGuards(spec2);
5307
+ var handlers11 = {
5308
+ list: () => Effect72.succeed([]),
5223
5309
  read: ({ olds }) => readOne3(olds),
5224
- diff: ({ news, output }) => Effect68.gen(function* () {
5310
+ diff: ({ news, output }) => Effect72.gen(function* () {
5225
5311
  if (!isResolved21(news))
5226
5312
  return;
5227
- yield* guardCreate6(news, output === undefined);
5228
- yield* guardUpdate6(news);
5313
+ yield* guardCreate7(news, output === undefined);
5314
+ yield* guardUpdate7(news);
5229
5315
  if (output === undefined)
5230
5316
  return;
5231
5317
  const live = yield* readOne3(news);
5232
5318
  if (live === undefined) {
5233
- yield* guardCreate6(news, true);
5319
+ yield* guardCreate7(news, true);
5234
5320
  return { action: "update" };
5235
5321
  }
5236
5322
  return { action: spec2.matches(live, news) ? "noop" : "update" };
5237
5323
  }),
5238
- reconcile: ({ news }) => Effect68.gen(function* () {
5324
+ reconcile: ({ news }) => Effect72.gen(function* () {
5239
5325
  const live = yield* readOne3(news);
5240
- yield* guardCreate6(news, live === undefined);
5241
- yield* guardUpdate6(news);
5326
+ yield* guardCreate7(news, live === undefined);
5327
+ yield* guardUpdate7(news);
5242
5328
  if (live === undefined)
5243
5329
  yield* createOne3(news);
5244
5330
  else if (!spec2.matches(live, news))
5245
5331
  yield* updateOne3(news);
5246
5332
  const after = yield* readOne3(news);
5247
5333
  if (after === undefined) {
5248
- return yield* Effect68.fail(new Error(`${spec2.path(news)}: write succeeded but job is absent.`));
5334
+ return yield* Effect72.fail(new Error(`${spec2.path(news)}: write succeeded but job is absent.`));
5249
5335
  }
5250
5336
  return after;
5251
5337
  }),
@@ -5254,15 +5340,15 @@ var handlers12 = {
5254
5340
 
5255
5341
  // src/proxmox/pbs-sync-job.ts
5256
5342
  var PbsSyncJob = Resource23("Pbs.SyncJob");
5257
- var PbsSyncJobProvider = () => Provider23.effect(PbsSyncJob, Effect69.succeed(PbsSyncJob.Provider.of(handlers12)));
5343
+ var PbsSyncJobProvider = () => Provider23.effect(PbsSyncJob, Effect73.succeed(PbsSyncJob.Provider.of(handlers11)));
5258
5344
  // src/proxmox/pbs-verify-job.ts
5259
5345
  import { Resource as Resource24 } from "alchemy";
5260
5346
  import * as Provider24 from "alchemy/Provider";
5261
- import * as Effect72 from "effect/Effect";
5347
+ import * as Effect76 from "effect/Effect";
5262
5348
 
5263
5349
  // src/proxmox/pbs-verify-job-lifecycle.ts
5264
5350
  import { isResolved as isResolved22 } from "alchemy/Diff";
5265
- import * as Effect71 from "effect/Effect";
5351
+ import * as Effect75 from "effect/Effect";
5266
5352
 
5267
5353
  // src/proxmox/pbs-verify-job-form.ts
5268
5354
  var rechecks = (ignoreVerified, outdatedAfter) => {
@@ -5309,7 +5395,7 @@ var spec3 = {
5309
5395
 
5310
5396
  // src/proxmox/pbs-verify-job-wire.ts
5311
5397
  import * as config6 from "@distilled.cloud/proxmox-backup/config";
5312
- import * as Effect70 from "effect/Effect";
5398
+ import * as Effect74 from "effect/Effect";
5313
5399
  var members4 = (form) => ({
5314
5400
  ...form["ignore-verified"] === undefined ? {} : { ignore_verified: form["ignore-verified"] },
5315
5401
  ...form["store"] === undefined ? {} : { store: form["store"] },
@@ -5334,48 +5420,48 @@ var wire4 = (row) => ({
5334
5420
  "max-depth": row.max_depth,
5335
5421
  "outdated-after": row.outdated_after
5336
5422
  });
5337
- var readOne4 = (props) => runPbs(props.target, "read", config6.getConfigVerify({ id: props.id })).pipe(Effect70.map((row) => spec3.attributes(wire4(row), props)), Effect70.catchTag("VerifyJobNotFound", () => Effect70.succeed(undefined)));
5423
+ var readOne4 = (props) => runPbs(props.target, "read", config6.getConfigVerify({ id: props.id })).pipe(Effect74.map((row) => spec3.attributes(wire4(row), props)), Effect74.catchTag("VerifyJobNotFound", () => Effect74.succeed(undefined)));
5338
5424
  var createOne4 = (props) => runPbs(props.target, "provision", config6.verifyConfig(createRequest4(props)));
5339
5425
  var updateOne4 = (props) => runPbs(props.target, "provision", config6.putConfigVerify(updateRequest4(props)));
5340
- var deleteOne4 = (props) => Effect70.gen(function* () {
5426
+ var deleteOne4 = (props) => Effect74.gen(function* () {
5341
5427
  if ((yield* readOne4(props)) === undefined)
5342
5428
  return;
5343
5429
  return yield* runPbs(props.target, "provision", config6.deleteConfigVerify({ id: props.id }));
5344
5430
  });
5345
5431
 
5346
5432
  // src/proxmox/pbs-verify-job-lifecycle.ts
5347
- var { guardCreate: guardCreate7, guardUpdate: guardUpdate7 } = specGuards(spec3);
5348
- var handlers13 = {
5349
- list: () => Effect71.succeed([]),
5433
+ var { guardCreate: guardCreate8, guardUpdate: guardUpdate8 } = specGuards(spec3);
5434
+ var handlers12 = {
5435
+ list: () => Effect75.succeed([]),
5350
5436
  read: ({ olds }) => readOne4(olds),
5351
5437
  diff: ({
5352
5438
  news,
5353
5439
  output
5354
- }) => Effect71.gen(function* () {
5440
+ }) => Effect75.gen(function* () {
5355
5441
  if (!isResolved22(news))
5356
5442
  return;
5357
- yield* guardCreate7(news, output === undefined);
5358
- yield* guardUpdate7(news);
5443
+ yield* guardCreate8(news, output === undefined);
5444
+ yield* guardUpdate8(news);
5359
5445
  if (output === undefined)
5360
5446
  return;
5361
5447
  const live = yield* readOne4(news);
5362
5448
  if (live === undefined) {
5363
- yield* guardCreate7(news, true);
5449
+ yield* guardCreate8(news, true);
5364
5450
  return { action: "update" };
5365
5451
  }
5366
5452
  return { action: spec3.matches(live, news) ? "noop" : "update" };
5367
5453
  }),
5368
- reconcile: ({ news }) => Effect71.gen(function* () {
5454
+ reconcile: ({ news }) => Effect75.gen(function* () {
5369
5455
  const live = yield* readOne4(news);
5370
- yield* guardCreate7(news, live === undefined);
5371
- yield* guardUpdate7(news);
5456
+ yield* guardCreate8(news, live === undefined);
5457
+ yield* guardUpdate8(news);
5372
5458
  if (live === undefined)
5373
5459
  yield* createOne4(news);
5374
5460
  else if (!spec3.matches(live, news))
5375
5461
  yield* updateOne4(news);
5376
5462
  const after = yield* readOne4(news);
5377
5463
  if (after === undefined) {
5378
- return yield* Effect71.fail(new Error(`${spec3.path(news)}: write succeeded but job is absent.`));
5464
+ return yield* Effect75.fail(new Error(`${spec3.path(news)}: write succeeded but job is absent.`));
5379
5465
  }
5380
5466
  return after;
5381
5467
  }),
@@ -5384,15 +5470,15 @@ var handlers13 = {
5384
5470
 
5385
5471
  // src/proxmox/pbs-verify-job.ts
5386
5472
  var PbsVerifyJob = Resource24("Pbs.VerifyJob");
5387
- var PbsVerifyJobProvider = () => Provider24.effect(PbsVerifyJob, Effect72.succeed(PbsVerifyJob.Provider.of(handlers13)));
5473
+ var PbsVerifyJobProvider = () => Provider24.effect(PbsVerifyJob, Effect76.succeed(PbsVerifyJob.Provider.of(handlers12)));
5388
5474
  // src/proxmox/pool.ts
5389
5475
  import { Resource as Resource25 } from "alchemy";
5390
5476
  import { isResolved as isResolved23 } from "alchemy/Diff";
5391
5477
  import * as Provider25 from "alchemy/Provider";
5392
5478
  import * as pools from "@distilled.cloud/proxmox/pools";
5393
- import { ProxmoxParseError as ProxmoxParseError4 } from "@distilled.cloud/proxmox/Errors";
5479
+ import { ProxmoxParseError as ProxmoxParseError5 } from "@distilled.cloud/proxmox/Errors";
5394
5480
  import * as Schema5 from "effect/Schema";
5395
- import * as Effect73 from "effect/Effect";
5481
+ import * as Effect77 from "effect/Effect";
5396
5482
  var ProxmoxPool = Resource25("Proxmox.Pool");
5397
5483
  var poolCreateForm = (props) => ({
5398
5484
  comment: props.comment ?? "",
@@ -5417,33 +5503,33 @@ var spec4 = {
5417
5503
  path: (props) => `pools/${props.poolid}`,
5418
5504
  updateForm: poolUpdateForm
5419
5505
  };
5420
- var { guardCreate: guardCreate8, guardUpdate: guardUpdate8 } = specGuards(spec4);
5421
- var readPool = (props) => runPve(props.target, "read", false, pools.getPool({ poolid: props.poolid })).pipe(Effect73.flatMap((live) => Schema5.decodeUnknownEffect(Schema5.toType(pools.GetPoolResponse))(live).pipe(Effect73.mapError(() => new ProxmoxParseError4({
5506
+ var { guardCreate: guardCreate9, guardUpdate: guardUpdate9 } = specGuards(spec4);
5507
+ var readPool = (props) => runPve(props.target, "read", false, pools.getPool({ poolid: props.poolid })).pipe(Effect77.flatMap((live) => Schema5.decodeUnknownEffect(Schema5.toType(pools.GetPoolResponse))(live).pipe(Effect77.mapError(() => new ProxmoxParseError5({
5422
5508
  body: undefined,
5423
5509
  cause: "Pool response does not match its vendor schema"
5424
- })), Effect73.as(live))), Effect73.map((live) => spec4.attributes({ ...live }, props)), Effect73.catchTag("PoolNotFound", () => Effect73.succeed(undefined)), Effect73.catchTag("NotFound", () => Effect73.succeed(undefined)));
5425
- var deletePool2 = (props) => runPve(props.target, "provision", true, pools.deletePool({ poolid: props.poolid })).pipe(Effect73.catchTag("PoolNotFound", () => Effect73.void), Effect73.catchTag("NotFound", () => Effect73.void));
5426
- var ProxmoxPoolProvider = () => Provider25.effect(ProxmoxPool, Effect73.succeed(ProxmoxPool.Provider.of({
5427
- list: () => Effect73.succeed([]),
5510
+ })), Effect77.as(live))), Effect77.map((live) => spec4.attributes({ ...live }, props)), Effect77.catchTag("PoolNotFound", () => Effect77.succeed(undefined)), Effect77.catchTag("NotFound", () => Effect77.succeed(undefined)));
5511
+ var deletePool2 = (props) => runPve(props.target, "provision", true, pools.deletePool({ poolid: props.poolid })).pipe(Effect77.catchTag("PoolNotFound", () => Effect77.void), Effect77.catchTag("NotFound", () => Effect77.void));
5512
+ var ProxmoxPoolProvider = () => Provider25.effect(ProxmoxPool, Effect77.succeed(ProxmoxPool.Provider.of({
5513
+ list: () => Effect77.succeed([]),
5428
5514
  read: ({ olds }) => readPool(olds),
5429
- diff: Effect73.fn(function* ({ news, output }) {
5515
+ diff: Effect77.fn(function* ({ news, output }) {
5430
5516
  if (!isResolved23(news))
5431
5517
  return;
5432
- yield* guardCreate8(news, output === undefined);
5433
- yield* guardUpdate8(news);
5518
+ yield* guardCreate9(news, output === undefined);
5519
+ yield* guardUpdate9(news);
5434
5520
  if (output === undefined)
5435
5521
  return;
5436
5522
  const live = yield* readPool(news);
5437
5523
  if (live === undefined) {
5438
- yield* guardCreate8(news, true);
5524
+ yield* guardCreate9(news, true);
5439
5525
  return { action: "update" };
5440
5526
  }
5441
5527
  return { action: spec4.matches(live, news) ? "noop" : "update" };
5442
5528
  }),
5443
- reconcile: Effect73.fn(function* ({ news }) {
5529
+ reconcile: Effect77.fn(function* ({ news }) {
5444
5530
  const live = yield* readPool(news);
5445
- yield* guardCreate8(news, live === undefined);
5446
- yield* guardUpdate8(news);
5531
+ yield* guardCreate9(news, live === undefined);
5532
+ yield* guardUpdate9(news);
5447
5533
  if (live === undefined) {
5448
5534
  yield* runPve(news.target, "provision", true, pools.createPool(poolCreateForm(news)));
5449
5535
  } else {
@@ -5456,7 +5542,7 @@ var ProxmoxPoolProvider = () => Provider25.effect(ProxmoxPool, Effect73.succeed(
5456
5542
  }
5457
5543
  const after = yield* readPool(news);
5458
5544
  if (after === undefined)
5459
- return yield* Effect73.fail(new Error(`pools/${news.poolid}: write returned success but the pool is still absent`));
5545
+ return yield* Effect77.fail(new Error(`pools/${news.poolid}: write returned success but the pool is still absent`));
5460
5546
  return after;
5461
5547
  }),
5462
5548
  delete: ({ olds }) => deletePool2(olds)
@@ -5653,14 +5739,14 @@ echo 'provision baseline: done. Next: point the OpenBao proxmox mount at these u
5653
5739
  // src/proxmox/provision-declare.ts
5654
5740
  import { adopt } from "alchemy/AdoptPolicy";
5655
5741
  import * as RemovalPolicy from "alchemy/RemovalPolicy";
5656
- import * as Effect77 from "effect/Effect";
5742
+ import * as Effect81 from "effect/Effect";
5657
5743
 
5658
5744
  // src/proxmox/role.ts
5659
5745
  import { Resource as Resource26 } from "alchemy";
5660
5746
  import { isResolved as isResolved24 } from "alchemy/Diff";
5661
5747
  import * as Provider26 from "alchemy/Provider";
5662
5748
  import * as access5 from "@distilled.cloud/proxmox/access";
5663
- import * as Effect74 from "effect/Effect";
5749
+ import * as Effect78 from "effect/Effect";
5664
5750
 
5665
5751
  // src/proxmox/role-wire.ts
5666
5752
  var ROLE_CREATE = "pve:POST /access/roles";
@@ -5683,19 +5769,19 @@ var matches7 = (attributes2, props) => canonical2(attributes2.privs).join(",") =
5683
5769
 
5684
5770
  // src/proxmox/role.ts
5685
5771
  var ProxmoxRole = Resource26("Proxmox.Role");
5686
- var readRole = (props) => readOrUnreadable(runPve(props.target, "read", false, access5.listAccessRoles({}))).pipe(Effect74.map((rows) => {
5772
+ var readRole = (props) => readOrUnreadable(runPve(props.target, "read", false, access5.listAccessRoles({}))).pipe(Effect78.map((rows) => {
5687
5773
  if (rows === UNREADABLE)
5688
5774
  return UNREADABLE;
5689
5775
  const row = find2(rows, props.roleid);
5690
5776
  return row === undefined ? undefined : attributesOf7(row, props);
5691
5777
  }));
5692
5778
  var dropUnreadable5 = (live) => live === UNREADABLE ? undefined : live;
5693
- var ProxmoxRoleProvider = () => Provider26.effect(ProxmoxRole, Effect74.succeed(ProxmoxRole.Provider.of({
5694
- list: () => Effect74.succeed([]),
5695
- read: Effect74.fn(function* ({ olds }) {
5779
+ var ProxmoxRoleProvider = () => Provider26.effect(ProxmoxRole, Effect78.succeed(ProxmoxRole.Provider.of({
5780
+ list: () => Effect78.succeed([]),
5781
+ read: Effect78.fn(function* ({ olds }) {
5696
5782
  return dropUnreadable5(yield* readRole(olds));
5697
5783
  }),
5698
- diff: Effect74.fn(function* ({ news, output }) {
5784
+ diff: Effect78.fn(function* ({ news, output }) {
5699
5785
  if (!isResolved24(news))
5700
5786
  return;
5701
5787
  yield* guardWrite2(ROLE_CREATE, createForm7(news), output === undefined);
@@ -5713,7 +5799,7 @@ var ProxmoxRoleProvider = () => Provider26.effect(ProxmoxRole, Effect74.succeed(
5713
5799
  }
5714
5800
  return matches7(live, news) ? { action: "noop" } : { action: "update" };
5715
5801
  }),
5716
- reconcile: Effect74.fn(function* ({ news }) {
5802
+ reconcile: Effect78.fn(function* ({ news }) {
5717
5803
  const before = dropUnreadable5(yield* readRole(news));
5718
5804
  yield* guardWrite2(ROLE_CREATE, createForm7(news), before === undefined);
5719
5805
  yield* guardWrite2(ROLE_UPDATE, updateForm4(news), false);
@@ -5724,11 +5810,11 @@ var ProxmoxRoleProvider = () => Provider26.effect(ProxmoxRole, Effect74.succeed(
5724
5810
  }
5725
5811
  const after = dropUnreadable5(yield* readRole(news));
5726
5812
  if (after === undefined) {
5727
- return yield* Effect74.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."));
5813
+ return yield* Effect78.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."));
5728
5814
  }
5729
5815
  return after;
5730
5816
  }),
5731
- delete: Effect74.fn(function* ({ olds }) {
5817
+ delete: Effect78.fn(function* ({ olds }) {
5732
5818
  yield* runPve(olds.target, "provision", true, access5.deleteAccessRole({ roleid: olds.roleid }));
5733
5819
  })
5734
5820
  })));
@@ -5738,11 +5824,11 @@ import { Resource as Resource27 } from "alchemy";
5738
5824
  import { isResolved as isResolved25 } from "alchemy/Diff";
5739
5825
  import * as Provider27 from "alchemy/Provider";
5740
5826
  import * as access7 from "@distilled.cloud/proxmox/access";
5741
- import * as Effect76 from "effect/Effect";
5827
+ import * as Effect80 from "effect/Effect";
5742
5828
 
5743
5829
  // src/proxmox/user-wire.ts
5744
5830
  import * as access6 from "@distilled.cloud/proxmox/access";
5745
- import * as Effect75 from "effect/Effect";
5831
+ import * as Effect79 from "effect/Effect";
5746
5832
  var USER_CREATE = "pve:POST /access/users";
5747
5833
  var USER_UPDATE = "pve:PUT /access/users/{userid}";
5748
5834
  var int2 = (value) => {
@@ -5784,18 +5870,18 @@ var attributesOf8 = (live, props) => ({
5784
5870
  userid: props.userid
5785
5871
  });
5786
5872
  var matches8 = (attributes2, props) => attributes2.comment === (props.comment ?? "") && attributes2.email === (props.email ?? "") && attributes2.enable === (props.enable !== false) && attributes2.expire === (props.expire ?? 0) && attributes2.firstname === (props.firstname ?? "") && attributes2.lastname === (props.lastname ?? "") && attributes2.groups.join(",") === groupSet(props.groups).join(",");
5787
- var readUserOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, access6.getAccessUser({ userid: props.userid }))).pipe(Effect75.map((live) => live === UNREADABLE ? UNREADABLE : attributesOf8(live, props)));
5788
- var readUser = (props) => readUserOrFail(props).pipe(Effect75.catchTag("UserNotFound", () => Effect75.succeed(undefined)));
5873
+ var readUserOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, access6.getAccessUser({ userid: props.userid }))).pipe(Effect79.map((live) => live === UNREADABLE ? UNREADABLE : attributesOf8(live, props)));
5874
+ var readUser = (props) => readUserOrFail(props).pipe(Effect79.catchTag("UserNotFound", () => Effect79.succeed(undefined)));
5789
5875
  var dropUnreadable6 = (live) => live === UNREADABLE ? undefined : live;
5790
5876
 
5791
5877
  // src/proxmox/user.ts
5792
5878
  var ProxmoxUser = Resource27("Proxmox.User");
5793
- var ProxmoxUserProvider = () => Provider27.effect(ProxmoxUser, Effect76.succeed(ProxmoxUser.Provider.of({
5794
- list: () => Effect76.succeed([]),
5795
- read: Effect76.fn(function* ({ olds, output }) {
5879
+ var ProxmoxUserProvider = () => Provider27.effect(ProxmoxUser, Effect80.succeed(ProxmoxUser.Provider.of({
5880
+ list: () => Effect80.succeed([]),
5881
+ read: Effect80.fn(function* ({ olds, output }) {
5796
5882
  return dropUnreadable6(yield* output === undefined ? readUser(olds) : readUserOrFail(olds));
5797
5883
  }),
5798
- diff: Effect76.fn(function* ({ news, output }) {
5884
+ diff: Effect80.fn(function* ({ news, output }) {
5799
5885
  if (!isResolved25(news))
5800
5886
  return;
5801
5887
  yield* guardWrite2(USER_CREATE, createForm8(news), output === undefined);
@@ -5813,7 +5899,7 @@ var ProxmoxUserProvider = () => Provider27.effect(ProxmoxUser, Effect76.succeed(
5813
5899
  }
5814
5900
  return matches8(live, news) ? { action: "noop" } : { action: "update" };
5815
5901
  }),
5816
- reconcile: Effect76.fn(function* ({ news }) {
5902
+ reconcile: Effect80.fn(function* ({ news }) {
5817
5903
  const before = dropUnreadable6(yield* readUser(news));
5818
5904
  yield* guardWrite2(USER_CREATE, createForm8(news), before === undefined);
5819
5905
  yield* guardWrite2(USER_UPDATE, updateForm5(news), false);
@@ -5824,18 +5910,18 @@ var ProxmoxUserProvider = () => Provider27.effect(ProxmoxUser, Effect76.succeed(
5824
5910
  }
5825
5911
  const after = dropUnreadable6(yield* readUser(news));
5826
5912
  if (after === undefined) {
5827
- return yield* Effect76.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."));
5913
+ return yield* Effect80.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."));
5828
5914
  }
5829
5915
  return after;
5830
5916
  }),
5831
- delete: Effect76.fn(function* ({ olds }) {
5917
+ delete: Effect80.fn(function* ({ olds }) {
5832
5918
  yield* runPve(olds.target, "provision", true, access7.deleteAccessUser({ userid: olds.userid }));
5833
5919
  })
5834
5920
  })));
5835
5921
 
5836
5922
  // src/proxmox/provision-declare.ts
5837
- var declareProvisionBaseline = (id, target, names2 = {}, options = {}) => Effect77.gen(function* () {
5838
- const baseline = yield* Effect77.try({
5923
+ var declareProvisionBaseline = (id, target, names2 = {}, options = {}) => Effect81.gen(function* () {
5924
+ const baseline = yield* Effect81.try({
5839
5925
  catch: (cause) => cause instanceof Error ? cause : new Error(String(cause)),
5840
5926
  try: () => provisionBaseline(names2)
5841
5927
  });
@@ -5849,13 +5935,13 @@ var declareProvisionBaseline = (id, target, names2 = {}, options = {}) => Effect
5849
5935
  target
5850
5936
  }));
5851
5937
  const group = yield* owned(ProxmoxGroup(`${id}-mint-group`, { ...baseline.group, target }));
5852
- const users = yield* Effect77.all(baseline.users.map((user) => owned(ProxmoxUser(`${id}-${user.lane}-user`, {
5938
+ const users = yield* Effect81.all(baseline.users.map((user) => owned(ProxmoxUser(`${id}-${user.lane}-user`, {
5853
5939
  comment: user.comment,
5854
5940
  groups: [...user.groups],
5855
5941
  target,
5856
5942
  userid: user.userid
5857
5943
  }))));
5858
- const grants = yield* Effect77.all(baseline.grants.map((grant) => owned(ProxmoxAcl(`${id}-${grant.lane}-grant`, {
5944
+ const grants = yield* Effect81.all(baseline.grants.map((grant) => owned(ProxmoxAcl(`${id}-${grant.lane}-grant`, {
5859
5945
  path: "/",
5860
5946
  propagate: true,
5861
5947
  roleid: grant.roleid,
@@ -5868,9 +5954,14 @@ var declareProvisionBaseline = (id, target, names2 = {}, options = {}) => Effect
5868
5954
  // src/proxmox/qemu.ts
5869
5955
  import { Resource as Resource28 } from "alchemy";
5870
5956
  import * as Provider28 from "alchemy/Provider";
5871
- import * as Effect78 from "effect/Effect";
5872
- var ProxmoxVm = Resource28("Proxmox.Vm");
5873
- var createForm9 = (props) => ({ ...shape9(props), vmid: String(props.vmid) });
5957
+ import * as Effect85 from "effect/Effect";
5958
+
5959
+ // src/proxmox/qemu-lifecycle.ts
5960
+ import { isResolved as isResolved26 } from "alchemy/Diff";
5961
+ import * as nodes17 from "@distilled.cloud/proxmox/nodes";
5962
+ import * as Effect84 from "effect/Effect";
5963
+
5964
+ // src/proxmox/qemu-form.ts
5874
5965
  var shape9 = (props) => ({
5875
5966
  cores: String(props.cores ?? 1),
5876
5967
  memory: String(props.memory ?? 512),
@@ -5879,31 +5970,155 @@ var shape9 = (props) => ({
5879
5970
  sockets: String(props.sockets ?? 1),
5880
5971
  ...props.net0 === undefined ? {} : { net0: props.net0 }
5881
5972
  });
5882
- var handlers14 = pveHandlers({
5883
- attributes: (live, props) => ({
5884
- cores: num(live["cores"], 1),
5885
- memory: num(live["memory"], 512),
5886
- name: typeof live["name"] === "string" ? live["name"] : "",
5887
- node: props.node,
5888
- onboot: live["onboot"] === 1 || live["onboot"] === true,
5889
- sockets: num(live["sockets"], 1),
5890
- vmid: props.vmid
5891
- }),
5973
+ var createForm9 = (props) => ({ ...shape9(props), vmid: String(props.vmid) });
5974
+
5975
+ // src/proxmox/qemu-errors.ts
5976
+ class QemuRefusedError extends Error {
5977
+ constructor(message) {
5978
+ super(message);
5979
+ this.name = "QemuRefusedError";
5980
+ }
5981
+ }
5982
+
5983
+ // src/proxmox/qemu-read.ts
5984
+ import * as cluster10 from "@distilled.cloud/proxmox/cluster";
5985
+ import * as nodes15 from "@distilled.cloud/proxmox/nodes";
5986
+ import * as Effect82 from "effect/Effect";
5987
+ var guestTypes = ["lxc", "qemu"];
5988
+ var readVm = (props) => Effect82.gen(function* () {
5989
+ const credential = yield* leased(props.target, "read");
5990
+ const answer = yield* runPveWith(props.target, credential, false, nodes15.getNodeQemuConfig({ node: props.node, vmid: String(props.vmid) })).pipe(Effect82.map((data) => ({ data, error: undefined })), Effect82.catchTag("QemuConfigNotFound", (error) => Effect82.succeed({ data: undefined, error })));
5991
+ if (answer.error === undefined) {
5992
+ const live = answer.data;
5993
+ if (typeof live.digest !== "string" || live.digest === "") {
5994
+ return yield* Effect82.fail(new QemuRefusedError(`VM ${String(props.vmid)}: config read did not return a digest-bearing config.`));
5995
+ }
5996
+ return live;
5997
+ }
5998
+ const rows = yield* runPveWith(props.target, credential, false, cluster10.listClusterResources({ type: "vm" }));
5999
+ if (!Array.isArray(rows) || rows.some((row) => !Number.isSafeInteger(Number(row?.vmid)) || Number(row?.vmid) <= 0 || typeof row?.node !== "string" || row.node === "" || !guestTypes.includes(row.type))) {
6000
+ return yield* Effect82.fail(new QemuRefusedError("The cluster guest index did not identify its rows."));
6001
+ }
6002
+ const found = rows.find((row) => Number(row.vmid) === props.vmid);
6003
+ if (found === undefined)
6004
+ return;
6005
+ if (found.node === props.node && found.type === "qemu")
6006
+ return yield* Effect82.fail(answer.error);
6007
+ return yield* Effect82.fail(new QemuRefusedError(`vmid ${String(props.vmid)} is a ${text(found.type, "guest")} on ` + `${text(found.node, "?")}, not a VM on ${props.node}. A migration is not an ` + "update and vmids are cluster-wide: declare the node it is on, or pick a free vmid."));
6008
+ });
6009
+
6010
+ // src/proxmox/qemu-task.ts
6011
+ import * as nodes16 from "@distilled.cloud/proxmox/nodes";
6012
+ import * as Effect83 from "effect/Effect";
6013
+ var qemuTask = (props, operation, what, polls) => Effect83.gen(function* () {
6014
+ const credential = yield* mint(props.target, "provision");
6015
+ const upid = text(yield* runPveWith(props.target, credential, true, operation));
6016
+ if (upid === "") {
6017
+ return yield* Effect83.fail(new QemuRefusedError(`${what}: PVE returned no task id, so the write cannot be confirmed and is not claimed.`));
6018
+ }
6019
+ let exit = "still running when this provider stopped waiting";
6020
+ for (let attempt = 0;attempt < polls; attempt++) {
6021
+ const status = yield* runPveWith(props.target, credential, false, nodes16.getNodeTaskStatus({ node: props.node, upid })).pipe(Effect83.orElseSucceed(() => {
6022
+ return;
6023
+ }));
6024
+ if (status === undefined || status.status === undefined) {
6025
+ exit = "the task could not be read";
6026
+ break;
6027
+ }
6028
+ if (status.status === "stopped") {
6029
+ exit = text(status.exitstatus, "stopped with no exitstatus");
6030
+ break;
6031
+ }
6032
+ yield* Effect83.sleep("1 second");
6033
+ }
6034
+ if (exit !== "OK") {
6035
+ return yield* Effect83.fail(new QemuRefusedError(`${what}: task ${upid} ended "${exit}". Read the task log before running the deploy again.`));
6036
+ }
6037
+ });
6038
+
6039
+ // src/proxmox/qemu-lifecycle.ts
6040
+ var CREATE_POLLS2 = 180;
6041
+ var DELETE_POLLS = 60;
6042
+ var attributesOf9 = (live, props) => ({
6043
+ cores: int(live.cores, 1),
6044
+ memory: int(live.memory, 512),
6045
+ name: typeof live.name === "string" ? live.name : "",
6046
+ node: props.node,
6047
+ onboot: live.onboot === 1 || live.onboot === true,
6048
+ sockets: int(live.sockets, 1),
6049
+ vmid: props.vmid
6050
+ });
6051
+ var matches9 = (attributes2, props) => attributes2.name === (props.name ?? `vm${String(props.vmid)}`) && attributes2.memory === (props.memory ?? 512) && attributes2.cores === (props.cores ?? 1) && attributes2.sockets === (props.sockets ?? 1) && attributes2.onboot === (props.onboot === true);
6052
+ var spec5 = {
6053
+ attributes: attributesOf9,
5892
6054
  collection: (props) => `nodes/${props.node}/qemu`,
5893
6055
  createForm: createForm9,
5894
6056
  endpoint: {
5895
6057
  create: "pve:POST /nodes/{node}/qemu",
5896
6058
  update: "pve:PUT /nodes/{node}/qemu/{vmid}/config"
5897
6059
  },
5898
- matches: (attributes2, props) => attributes2.name === (props.name ?? `vm${String(props.vmid)}`) && attributes2.memory === (props.memory ?? 512) && attributes2.cores === (props.cores ?? 1) && attributes2.sockets === (props.sockets ?? 1) && attributes2.onboot === (props.onboot === true),
6060
+ matches: matches9,
5899
6061
  path: (props) => `nodes/${props.node}/qemu/${String(props.vmid)}/config`,
5900
6062
  updateForm: shape9
5901
- });
5902
- var ProxmoxVmProvider = () => Provider28.effect(ProxmoxVm, Effect78.succeed(ProxmoxVm.Provider.of(handlers14)));
6063
+ };
6064
+ var { guardCreate: guardCreate10, guardUpdate: guardUpdate10 } = specGuards(spec5);
6065
+ var readQemu = (props) => readVm(props).pipe(Effect84.map((live) => live === undefined ? undefined : attributesOf9(live, props)));
6066
+ var deleteQemu = (props) => qemuTask(props, nodes17.deleteNodeQemu({ node: props.node, vmid: String(props.vmid) }), `destroy VM ${String(props.vmid)}`, DELETE_POLLS).pipe(Effect84.catchTag("QemuConfigNotFound", () => Effect84.void));
6067
+ var qemuHandlers = {
6068
+ list: () => Effect84.succeed([]),
6069
+ read: ({ olds }) => readQemu(olds),
6070
+ diff: Effect84.fn(function* ({
6071
+ news,
6072
+ output
6073
+ }) {
6074
+ if (!isResolved26(news))
6075
+ return;
6076
+ yield* guardCreate10(news, output === undefined);
6077
+ yield* guardUpdate10(news);
6078
+ if (output === undefined)
6079
+ return;
6080
+ const live = yield* readQemu(news);
6081
+ if (live === undefined) {
6082
+ yield* guardCreate10(news, true);
6083
+ return { action: "update" };
6084
+ }
6085
+ return { action: spec5.matches(live, news) ? "noop" : "update" };
6086
+ }),
6087
+ reconcile: Effect84.fn(function* ({ news }) {
6088
+ const live = yield* readQemu(news);
6089
+ yield* guardCreate10(news, live === undefined);
6090
+ yield* guardUpdate10(news);
6091
+ if (live === undefined) {
6092
+ yield* qemuTask(news, nodes17.createNodeQemu({ ...createForm9(news), node: news.node }), `create VM ${String(news.vmid)}`, CREATE_POLLS2);
6093
+ } else {
6094
+ const form = formToSend(spec5.matches, live, news, spec5.updateForm(news));
6095
+ if (form !== undefined) {
6096
+ yield* runPve(news.target, "provision", true, nodes17.putNodeQemuConfig({ ...form, node: news.node, vmid: String(news.vmid) }));
6097
+ }
6098
+ }
6099
+ const after = yield* readQemu(news);
6100
+ if (after === undefined) {
6101
+ return yield* Effect84.fail(new QemuRefusedError(`${spec5.path(news)}: write returned success but the VM is still absent`));
6102
+ }
6103
+ return after;
6104
+ }),
6105
+ delete: ({ olds }) => deleteQemu(olds)
6106
+ };
6107
+
6108
+ // src/proxmox/qemu.ts
6109
+ var ProxmoxVm = Resource28("Proxmox.Vm");
6110
+ var ProxmoxVmProvider = () => Provider28.effect(ProxmoxVm, Effect85.succeed(ProxmoxVm.Provider.of(qemuHandlers)));
5903
6111
  // src/proxmox/replication-job.ts
5904
6112
  import { Resource as Resource29 } from "alchemy";
5905
6113
  import * as Provider29 from "alchemy/Provider";
5906
- import * as Effect79 from "effect/Effect";
6114
+ import * as Effect87 from "effect/Effect";
6115
+
6116
+ // src/proxmox/replication-job-lifecycle.ts
6117
+ import { isResolved as isResolved27 } from "alchemy/Diff";
6118
+ import * as cluster11 from "@distilled.cloud/proxmox/cluster";
6119
+ import { ProxmoxParseError as ProxmoxParseError6 } from "@distilled.cloud/proxmox/Errors";
6120
+ import * as Effect86 from "effect/Effect";
6121
+ import * as Schema6 from "effect/Schema";
5907
6122
 
5908
6123
  // src/proxmox/replication-job-form.ts
5909
6124
  var DEFAULT_SCHEDULE = "*/15";
@@ -5925,15 +6140,14 @@ var updateBody4 = (props) => ({
5925
6140
  delete: "remove_job"
5926
6141
  });
5927
6142
 
5928
- // src/proxmox/replication-job.ts
5929
- var ProxmoxReplicationJob = Resource29("Proxmox.ReplicationJob");
6143
+ // src/proxmox/replication-job-config.ts
5930
6144
  var rateOf = (value) => {
5931
6145
  if (typeof value === "number")
5932
6146
  return value;
5933
6147
  const parsed = Number.parseFloat(text(value));
5934
6148
  return Number.isFinite(parsed) ? parsed : 0;
5935
6149
  };
5936
- var handlers15 = pveHandlers({
6150
+ var replicationJobSpec = {
5937
6151
  attributes: (live, props) => ({
5938
6152
  comment: text(live["comment"], ""),
5939
6153
  disable: bool(live["disable"], false),
@@ -5956,16 +6170,71 @@ var handlers15 = pveHandlers({
5956
6170
  matches: (attributes2, props) => attributes2.remove_job === "" && attributes2.schedule === (props.schedule ?? DEFAULT_SCHEDULE) && attributes2.disable === (props.disable === true) && attributes2.comment === (props.comment ?? "") && (props.rate === undefined || attributes2.rate === props.rate),
5957
6171
  path: (props) => `cluster/replication/${jobId(props)}`,
5958
6172
  updateForm: updateBody4
6173
+ };
6174
+
6175
+ // src/proxmox/replication-job-lifecycle.ts
6176
+ var { guardCreate: guardCreate11, guardUpdate: guardUpdate11 } = specGuards(replicationJobSpec);
6177
+ var malformed = () => new ProxmoxParseError6({
6178
+ body: undefined,
6179
+ cause: "Replication job response does not match the requested vendor identity"
5959
6180
  });
5960
- var ProxmoxReplicationJobProvider = () => Provider29.effect(ProxmoxReplicationJob, Effect79.succeed(ProxmoxReplicationJob.Provider.of(handlers15)));
6181
+ var readReplicationJob = (props) => runPve(props.target, "read", false, cluster11.getClusterReplication({ id: jobId(props) })).pipe(Effect86.flatMap((live) => Schema6.decodeUnknownEffect(Schema6.toType(cluster11.GetClusterReplicationResponse))({
6182
+ ...live,
6183
+ guest: int(live.guest, Number.NaN),
6184
+ jobnum: int(live.jobnum, Number.NaN),
6185
+ rate: undefined
6186
+ }).pipe(Effect86.mapError(malformed), Effect86.as(live))), Effect86.flatMap((live) => live.id === jobId(props) && int(live.guest, Number.NaN) === props.guest && int(live.jobnum, Number.NaN) === props.jobnum ? Effect86.succeed(replicationJobSpec.attributes({ ...live }, props)) : Effect86.fail(malformed())), Effect86.catchTag("ReplicationJobNotFound", () => Effect86.succeed(undefined)));
6187
+ var deleteReplicationJob = (props) => runPve(props.target, "provision", true, cluster11.deleteClusterReplication({ id: jobId(props) })).pipe(Effect86.catchTag("ReplicationJobNotFound", () => Effect86.void));
6188
+ var replicationJobHandlers = {
6189
+ list: () => Effect86.succeed([]),
6190
+ read: ({ olds }) => readReplicationJob(olds),
6191
+ diff: Effect86.fn(function* ({
6192
+ news,
6193
+ output
6194
+ }) {
6195
+ if (!isResolved27(news))
6196
+ return;
6197
+ yield* guardCreate11(news, output === undefined);
6198
+ yield* guardUpdate11(news);
6199
+ if (output === undefined)
6200
+ return;
6201
+ const live = yield* readReplicationJob(news);
6202
+ if (live === undefined) {
6203
+ yield* guardCreate11(news, true);
6204
+ return { action: "update" };
6205
+ }
6206
+ return { action: replicationJobSpec.matches(live, news) ? "noop" : "update" };
6207
+ }),
6208
+ reconcile: Effect86.fn(function* ({ news }) {
6209
+ const live = yield* readReplicationJob(news);
6210
+ yield* guardCreate11(news, live === undefined);
6211
+ yield* guardUpdate11(news);
6212
+ if (live === undefined) {
6213
+ yield* runPve(news.target, "provision", true, cluster11.createClusterReplication(replicationJobSpec.createForm(news)));
6214
+ } else {
6215
+ const form = formToSend(replicationJobSpec.matches, live, news, replicationJobSpec.updateForm(news));
6216
+ if (form !== undefined)
6217
+ yield* runPve(news.target, "provision", true, cluster11.putClusterReplication({ ...form, id: jobId(news) }));
6218
+ }
6219
+ const after = yield* readReplicationJob(news);
6220
+ if (after === undefined)
6221
+ return yield* Effect86.fail(new Error(`${replicationJobSpec.path(news)}: write returned success but the resource is still absent`));
6222
+ return after;
6223
+ }),
6224
+ delete: ({ olds }) => deleteReplicationJob(olds)
6225
+ };
6226
+
6227
+ // src/proxmox/replication-job.ts
6228
+ var ProxmoxReplicationJob = Resource29("Proxmox.ReplicationJob");
6229
+ var ProxmoxReplicationJobProvider = () => Provider29.effect(ProxmoxReplicationJob, Effect87.succeed(ProxmoxReplicationJob.Provider.of(replicationJobHandlers)));
5961
6230
  // src/proxmox/sdn-apply.ts
5962
6231
  import { Resource as Resource30 } from "alchemy";
5963
- import { isResolved as isResolved26 } from "alchemy/Diff";
6232
+ import { isResolved as isResolved28 } from "alchemy/Diff";
5964
6233
  import * as Provider30 from "alchemy/Provider";
5965
- import * as Effect81 from "effect/Effect";
6234
+ import * as Effect89 from "effect/Effect";
5966
6235
 
5967
6236
  // src/proxmox/sdn-apply-read.ts
5968
- import * as Effect80 from "effect/Effect";
6237
+ import * as Effect88 from "effect/Effect";
5969
6238
  var MARKED = [
5970
6239
  "cluster/sdn/zones",
5971
6240
  "cluster/sdn/vnets",
@@ -5974,7 +6243,7 @@ var MARKED = [
5974
6243
  "cluster/sdn/route-maps"
5975
6244
  ];
5976
6245
  var subsystemAbsent = (error) => error instanceof PveError && error.status === 501;
5977
- var markedPending = (target) => Effect80.all(MARKED.map((collection) => pve(target, "read", "GET", `${collection}?pending=1`).pipe(Effect80.map((rows) => (rows ?? []).filter((row) => row.state !== undefined).length), Effect80.catchIf(subsystemAbsent, () => Effect80.succeed(0)))), { concurrency: "unbounded" }).pipe(Effect80.map((counts) => counts.reduce((total, count2) => total + count2, 0)));
6246
+ var markedPending = (target) => Effect88.all(MARKED.map((collection) => pve(target, "read", "GET", `${collection}?pending=1`).pipe(Effect88.map((rows) => (rows ?? []).filter((row) => row.state !== undefined).length), Effect88.catchIf(subsystemAbsent, () => Effect88.succeed(0)))), { concurrency: "unbounded" }).pipe(Effect88.map((counts) => counts.reduce((total, count2) => total + count2, 0)));
5978
6247
  var fabricStaged = (staged, running) => {
5979
6248
  if (staged === undefined && running === undefined)
5980
6249
  return 0;
@@ -5982,9 +6251,9 @@ var fabricStaged = (staged, running) => {
5982
6251
  return "inconsistent";
5983
6252
  return staged === running ? 0 : 1;
5984
6253
  };
5985
- var fabricPending = (target) => Effect80.all(["pending", "running"].map((view) => pve(target, "read", "GET", `cluster/sdn/fabrics/all?${view}=1`).pipe(Effect80.map(canonical3), Effect80.catchIf(subsystemAbsent, () => Effect80.succeed(undefined)))), { concurrency: "unbounded" }).pipe(Effect80.flatMap(([staged, running]) => {
6254
+ var fabricPending = (target) => Effect88.all(["pending", "running"].map((view) => pve(target, "read", "GET", `cluster/sdn/fabrics/all?${view}=1`).pipe(Effect88.map(canonical3), Effect88.catchIf(subsystemAbsent, () => Effect88.succeed(undefined)))), { concurrency: "unbounded" }).pipe(Effect88.flatMap(([staged, running]) => {
5986
6255
  const verdict = fabricStaged(staged, running);
5987
- return verdict === "inconsistent" ? Effect80.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.")) : Effect80.succeed(verdict);
6256
+ return verdict === "inconsistent" ? Effect88.die(new Error("cluster/sdn/fabrics/all answered 501 for one of ?pending=1 and ?running=1 and not " + "the other. Refusing to read that as a staged fabric change.")) : Effect88.succeed(verdict);
5988
6257
  }));
5989
6258
  var canonical3 = (value) => JSON.stringify(sortDeep(value));
5990
6259
  var sortDeep = (value) => {
@@ -5997,23 +6266,23 @@ var sortDeep = (value) => {
5997
6266
  }
5998
6267
  return value;
5999
6268
  };
6000
- var sdnPendingCount = (target) => Effect80.all([markedPending(target), fabricPending(target)], { concurrency: "unbounded" }).pipe(Effect80.map(([marked, fabric]) => marked + fabric));
6269
+ var sdnPendingCount = (target) => Effect88.all([markedPending(target), fabricPending(target)], { concurrency: "unbounded" }).pipe(Effect88.map(([marked, fabric]) => marked + fabric));
6001
6270
 
6002
6271
  // src/proxmox/sdn-apply.ts
6003
6272
  var ProxmoxSdnApply = Resource30("Proxmox.SdnApply");
6004
- var read5 = (props) => sdnPendingCount(props.target).pipe(Effect81.map((pending) => ({ pending })));
6005
- var ProxmoxSdnApplyProvider = () => Provider30.effect(ProxmoxSdnApply, Effect81.succeed(ProxmoxSdnApply.Provider.of({
6006
- list: () => Effect81.succeed([]),
6007
- read: Effect81.fn(function* ({ olds }) {
6273
+ var read5 = (props) => sdnPendingCount(props.target).pipe(Effect89.map((pending) => ({ pending })));
6274
+ var ProxmoxSdnApplyProvider = () => Provider30.effect(ProxmoxSdnApply, Effect89.succeed(ProxmoxSdnApply.Provider.of({
6275
+ list: () => Effect89.succeed([]),
6276
+ read: Effect89.fn(function* ({ olds }) {
6008
6277
  return yield* read5(olds);
6009
6278
  }),
6010
- diff: Effect81.fn(function* ({ news }) {
6011
- if (!isResolved26(news))
6279
+ diff: Effect89.fn(function* ({ news }) {
6280
+ if (!isResolved28(news))
6012
6281
  return;
6013
6282
  const { pending } = yield* read5(news);
6014
6283
  return pending === 0 ? { action: "noop" } : { action: "update" };
6015
6284
  }),
6016
- reconcile: Effect81.fn(function* ({ news }) {
6285
+ reconcile: Effect89.fn(function* ({ news }) {
6017
6286
  const staged = yield* read5(news);
6018
6287
  if (staged.pending === 0)
6019
6288
  return staged;
@@ -6021,16 +6290,16 @@ var ProxmoxSdnApplyProvider = () => Provider30.effect(ProxmoxSdnApply, Effect81.
6021
6290
  yield* pve(news.target, "provision", "PUT", "cluster/sdn");
6022
6291
  const after = yield* read5(news);
6023
6292
  if (after.pending !== 0) {
6024
- return yield* Effect81.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."));
6293
+ return yield* Effect89.die(new Error(`PUT /cluster/sdn returned no error but ${String(after.pending)} SDN object(s) ` + "are still staged. The running config does not match the declared one -- check " + "`pvesh get /cluster/sdn/zones --pending 1` for the objects PVE refused."));
6025
6294
  }
6026
6295
  return after;
6027
6296
  }),
6028
- delete: () => Effect81.void
6297
+ delete: () => Effect89.void
6029
6298
  })));
6030
6299
  // src/proxmox/sdn-subnet.ts
6031
6300
  import { Resource as Resource31 } from "alchemy";
6032
6301
  import * as Provider31 from "alchemy/Provider";
6033
- import * as Effect82 from "effect/Effect";
6302
+ import * as Effect90 from "effect/Effect";
6034
6303
 
6035
6304
  // src/proxmox/sdn-subnet-form.ts
6036
6305
  var subnetId = (props) => `${props.zone}-${props.cidr.replace("/", "-")}`;
@@ -6061,7 +6330,7 @@ var updateForm6 = (props) => {
6061
6330
 
6062
6331
  // src/proxmox/sdn-subnet.ts
6063
6332
  var ProxmoxSdnSubnet = Resource31("Proxmox.SdnSubnet");
6064
- var handlers16 = pveHandlers({
6333
+ var handlers13 = pveHandlers({
6065
6334
  attributes: (live, props) => {
6066
6335
  const liveVnet = text(live["vnet"]);
6067
6336
  if (liveVnet !== "" && liveVnet !== props.vnet)
@@ -6090,11 +6359,11 @@ var handlers16 = pveHandlers({
6090
6359
  path: (props) => `cluster/sdn/vnets/${props.vnet}/subnets/${subnetId(props)}`,
6091
6360
  updateForm: updateForm6
6092
6361
  });
6093
- var ProxmoxSdnSubnetProvider = () => Provider31.effect(ProxmoxSdnSubnet, Effect82.succeed(ProxmoxSdnSubnet.Provider.of(handlers16)));
6362
+ var ProxmoxSdnSubnetProvider = () => Provider31.effect(ProxmoxSdnSubnet, Effect90.succeed(ProxmoxSdnSubnet.Provider.of(handlers13)));
6094
6363
  // src/proxmox/sdn-vnet.ts
6095
6364
  import { Resource as Resource32 } from "alchemy";
6096
6365
  import * as Provider32 from "alchemy/Provider";
6097
- import * as Effect83 from "effect/Effect";
6366
+ import * as Effect91 from "effect/Effect";
6098
6367
  var ProxmoxSdnVnet = Resource32("Proxmox.SdnVnet");
6099
6368
  var tagOf = (value) => typeof value === "number" ? value : undefined;
6100
6369
  var shape11 = (props) => {
@@ -6114,7 +6383,7 @@ var updateForm7 = (props) => {
6114
6383
  ];
6115
6384
  return withClears(shape11(props), unset2);
6116
6385
  };
6117
- var handlers17 = pveHandlers({
6386
+ var handlers14 = pveHandlers({
6118
6387
  readRole: "provision",
6119
6388
  attributes: (live, props) => ({
6120
6389
  alias: typeof live["alias"] === "string" ? live["alias"] : "",
@@ -6132,11 +6401,11 @@ var handlers17 = pveHandlers({
6132
6401
  path: (props) => `cluster/sdn/vnets/${props.vnet}`,
6133
6402
  updateForm: updateForm7
6134
6403
  });
6135
- var ProxmoxSdnVnetProvider = () => Provider32.effect(ProxmoxSdnVnet, Effect83.succeed(ProxmoxSdnVnet.Provider.of(handlers17)));
6404
+ var ProxmoxSdnVnetProvider = () => Provider32.effect(ProxmoxSdnVnet, Effect91.succeed(ProxmoxSdnVnet.Provider.of(handlers14)));
6136
6405
  // src/proxmox/sdn-zone.ts
6137
6406
  import { Resource as Resource33 } from "alchemy";
6138
6407
  import * as Provider33 from "alchemy/Provider";
6139
- import * as Effect84 from "effect/Effect";
6408
+ import * as Effect92 from "effect/Effect";
6140
6409
  var ProxmoxSdnZone = Resource33("Proxmox.SdnZone");
6141
6410
  var sameIpam = (live, declared2) => (live === "" ? "pve" : live) === (declared2 === undefined || declared2 === "" ? "pve" : declared2);
6142
6411
  var body6 = (props) => ({
@@ -6157,7 +6426,7 @@ var clearable = {
6157
6426
  vlan: ["dns", "dnszone", "ipam", "mtu", "nodes"],
6158
6427
  vxlan: ["dns", "dnszone", "ipam", "mtu", "nodes"]
6159
6428
  };
6160
- var handlers18 = pveHandlers({
6429
+ var handlers15 = pveHandlers({
6161
6430
  readRole: "provision",
6162
6431
  attributes: (live, props) => {
6163
6432
  const liveType = text(live["type"]);
@@ -6189,13 +6458,13 @@ var handlers18 = pveHandlers({
6189
6458
  return withClears(fields2, clear);
6190
6459
  }
6191
6460
  });
6192
- var ProxmoxSdnZoneProvider = () => Provider33.effect(ProxmoxSdnZone, Effect84.succeed(ProxmoxSdnZone.Provider.of(handlers18)));
6461
+ var ProxmoxSdnZoneProvider = () => Provider33.effect(ProxmoxSdnZone, Effect92.succeed(ProxmoxSdnZone.Provider.of(handlers15)));
6193
6462
  // src/proxmox/storage.ts
6194
6463
  import { Resource as Resource34 } from "alchemy";
6195
- import { isResolved as isResolved27 } from "alchemy/Diff";
6464
+ import { isResolved as isResolved29 } from "alchemy/Diff";
6196
6465
  import * as Provider34 from "alchemy/Provider";
6197
6466
  import * as storage2 from "@distilled.cloud/proxmox/storage";
6198
- import * as Effect86 from "effect/Effect";
6467
+ import * as Effect94 from "effect/Effect";
6199
6468
 
6200
6469
  // src/proxmox/storage-form.ts
6201
6470
  var STORAGE_CREATE = "pve:POST /storage";
@@ -6227,12 +6496,12 @@ var toDistilledUpdate3 = (props) => underscored(updateForm8(props));
6227
6496
 
6228
6497
  // src/proxmox/storage-wire.ts
6229
6498
  import * as storage from "@distilled.cloud/proxmox/storage";
6230
- import * as Effect85 from "effect/Effect";
6499
+ import * as Effect93 from "effect/Effect";
6231
6500
  var str2 = (value, fallback = "") => typeof value === "string" ? value : fallback;
6232
6501
  var tokens = (value) => value.split(",").map((part) => part.trim()).filter((part) => part !== "").sort().join(",");
6233
6502
  var sameList2 = (declared2, live) => declared2 === undefined || tokens(declared2) === tokens(live);
6234
6503
  var same7 = (declared2, live) => declared2 === undefined || declared2 === live;
6235
- var attributesOf9 = (live, props) => {
6504
+ var attributesOf10 = (live, props) => {
6236
6505
  const data = live;
6237
6506
  return {
6238
6507
  comment: str2(data["comment"]),
@@ -6246,22 +6515,22 @@ var attributesOf9 = (live, props) => {
6246
6515
  type: str2(data["type"], props.type)
6247
6516
  };
6248
6517
  };
6249
- var readStorageOrFail = (props) => readOrUnreadable(runPve(props.target, "provision", false, storage.getStorage({ storage: props.storage }))).pipe(Effect85.map((live) => live === UNREADABLE ? UNREADABLE : attributesOf9(live, props)));
6250
- var readStorage = (props) => readStorageOrFail(props).pipe(Effect85.catchTag("StorageNotFound", () => Effect85.succeed(undefined)));
6518
+ var readStorageOrFail = (props) => readOrUnreadable(runPve(props.target, "provision", false, storage.getStorage({ storage: props.storage }))).pipe(Effect93.map((live) => live === UNREADABLE ? UNREADABLE : attributesOf10(live, props)));
6519
+ var readStorage = (props) => readStorageOrFail(props).pipe(Effect93.catchTag("StorageNotFound", () => Effect93.succeed(undefined)));
6251
6520
  var dropUnreadable7 = (live) => live === UNREADABLE ? undefined : live;
6252
- var matches9 = (attributes2, props) => sameList2(props.content, attributes2.content) && sameList2(props.nodes, attributes2.nodes) && sameList2(props["prune-backups"], attributes2["prune-backups"]) && same7(props.disable, attributes2.disable) && same7(props.shared, attributes2.shared) && same7(props.preallocation, attributes2.preallocation) && same7(props.comment, attributes2.comment);
6521
+ var matches10 = (attributes2, props) => sameList2(props.content, attributes2.content) && sameList2(props.nodes, attributes2.nodes) && sameList2(props["prune-backups"], attributes2["prune-backups"]) && same7(props.disable, attributes2.disable) && same7(props.shared, attributes2.shared) && same7(props.preallocation, attributes2.preallocation) && same7(props.comment, attributes2.comment);
6253
6522
 
6254
6523
  // src/proxmox/storage.ts
6255
6524
  var ProxmoxStorage = Resource34("Proxmox.Storage", {
6256
6525
  defaultRemovalPolicy: "retain"
6257
6526
  });
6258
- var ProxmoxStorageProvider = () => Provider34.effect(ProxmoxStorage, Effect86.succeed(ProxmoxStorage.Provider.of({
6259
- list: () => Effect86.succeed([]),
6260
- read: Effect86.fn(function* ({ olds, output }) {
6527
+ var ProxmoxStorageProvider = () => Provider34.effect(ProxmoxStorage, Effect94.succeed(ProxmoxStorage.Provider.of({
6528
+ list: () => Effect94.succeed([]),
6529
+ read: Effect94.fn(function* ({ olds, output }) {
6261
6530
  return dropUnreadable7(yield* output === undefined ? readStorage(olds) : readStorageOrFail(olds));
6262
6531
  }),
6263
- diff: Effect86.fn(function* ({ news, output }) {
6264
- if (!isResolved27(news))
6532
+ diff: Effect94.fn(function* ({ news, output }) {
6533
+ if (!isResolved29(news))
6265
6534
  return;
6266
6535
  yield* guardWrite2(STORAGE_CREATE, createForm11(news), output === undefined);
6267
6536
  yield* guardWrite2(STORAGE_UPDATE, updateForm8(news), false);
@@ -6276,61 +6545,61 @@ var ProxmoxStorageProvider = () => Provider34.effect(ProxmoxStorage, Effect86.su
6276
6545
  yield* guardWrite2(STORAGE_CREATE, createForm11(news), true);
6277
6546
  return { action: "update" };
6278
6547
  }
6279
- return matches9(live, news) ? { action: "noop" } : { action: "update" };
6548
+ return matches10(live, news) ? { action: "noop" } : { action: "update" };
6280
6549
  }),
6281
- reconcile: Effect86.fn(function* ({ news }) {
6550
+ reconcile: Effect94.fn(function* ({ news }) {
6282
6551
  const before = dropUnreadable7(yield* readStorage(news));
6283
6552
  yield* guardWrite2(STORAGE_CREATE, createForm11(news), before === undefined);
6284
6553
  yield* guardWrite2(STORAGE_UPDATE, updateForm8(news), false);
6285
6554
  if (before === undefined) {
6286
6555
  yield* runPve(news.target, "provision", true, storage2.createStorage(toDistilledCreate4(news)));
6287
- } else if (!matches9(before, news)) {
6556
+ } else if (!matches10(before, news)) {
6288
6557
  yield* runPve(news.target, "provision", true, storage2.putStorage(toDistilledUpdate3(news)));
6289
6558
  }
6290
6559
  const after = dropUnreadable7(yield* readStorage(news));
6291
6560
  if (after === undefined) {
6292
- return yield* Effect86.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."));
6561
+ return yield* Effect94.die(new Error(`storage/${news.storage}: the write returned no error but the storage is still ` + 'absent. PVE wraps every answer in {"data":...} and can report success on a ' + "call that did nothing -- read back rather than trusting the status code."));
6293
6562
  }
6294
6563
  return after;
6295
6564
  }),
6296
- delete: Effect86.fn(function* ({ olds }) {
6565
+ delete: Effect94.fn(function* ({ olds }) {
6297
6566
  yield* runPve(olds.target, "provision", true, storage2.deleteStorage({ storage: olds.storage }));
6298
6567
  })
6299
6568
  })));
6300
6569
  // src/proxmox/zfs-pool.ts
6301
6570
  import { Resource as Resource35 } from "alchemy";
6302
- import { isResolved as isResolved28 } from "alchemy/Diff";
6571
+ import { isResolved as isResolved30 } from "alchemy/Diff";
6303
6572
  import * as Provider35 from "alchemy/Provider";
6304
- import * as Effect89 from "effect/Effect";
6573
+ import * as Effect97 from "effect/Effect";
6305
6574
 
6306
6575
  // src/proxmox/zfs-pool-wire.ts
6307
- import * as nodes10 from "@distilled.cloud/proxmox/nodes";
6308
- import * as Effect87 from "effect/Effect";
6576
+ import * as nodes18 from "@distilled.cloud/proxmox/nodes";
6577
+ import * as Effect95 from "effect/Effect";
6309
6578
  var leafDevices = (children) => Array.isArray(children) ? children.flatMap((entry) => {
6310
6579
  const vdev = entry;
6311
6580
  const nested = leafDevices(vdev.children);
6312
6581
  return nested.length > 0 ? nested : [text(vdev.name)].filter((name) => name !== "");
6313
6582
  }) : [];
6314
- var attributesOf10 = (live, props) => ({
6583
+ var attributesOf11 = (live, props) => ({
6315
6584
  devices: leafDevices(live.children).join(","),
6316
6585
  errors: text(live.errors, "unknown"),
6317
6586
  name: props.name,
6318
6587
  node: props.node,
6319
6588
  state: text(live.state, "unknown")
6320
6589
  });
6321
- var readPoolOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, nodes10.getNodeDiskZfs({ name: props.name, node: props.node }))).pipe(Effect87.map((live) => {
6590
+ var readPoolOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, nodes18.getNodeDiskZfs({ name: props.name, node: props.node }))).pipe(Effect95.map((live) => {
6322
6591
  if (live === UNREADABLE)
6323
6592
  return UNREADABLE;
6324
- return text(live.name) === "" ? undefined : attributesOf10(live, props);
6593
+ return text(live.name) === "" ? undefined : attributesOf11(live, props);
6325
6594
  }));
6326
- var readPool2 = (props) => readPoolOrFail(props).pipe(Effect87.orElseSucceed(() => {
6595
+ var readPool2 = (props) => readPoolOrFail(props).pipe(Effect95.orElseSucceed(() => {
6327
6596
  return;
6328
6597
  }));
6329
6598
  var dropUnreadable8 = (live) => live === UNREADABLE ? undefined : live;
6330
6599
 
6331
6600
  // src/proxmox/zfs-pool-form.ts
6332
- import * as Effect88 from "effect/Effect";
6333
- import * as nodes11 from "@distilled.cloud/proxmox/nodes";
6601
+ import * as Effect96 from "effect/Effect";
6602
+ import * as nodes19 from "@distilled.cloud/proxmox/nodes";
6334
6603
  var ZFS_POOL_CREATE = "pve:POST /nodes/{node}/disks/zfs";
6335
6604
  var zfsPoolCreateEndpoint = (props) => props.devices === undefined || props.raidlevel === undefined ? undefined : ZFS_POOL_CREATE;
6336
6605
  var createForm12 = (props) => ({
@@ -6350,41 +6619,41 @@ var toDistilledCreate5 = (props) => {
6350
6619
  };
6351
6620
  };
6352
6621
  var SETTLE_ATTEMPTS = 30;
6353
- var createPool2 = (props, read6) => Effect88.gen(function* () {
6622
+ var createPool2 = (props, read6) => Effect96.gen(function* () {
6354
6623
  const existing = yield* read6(props);
6355
6624
  if (existing !== undefined)
6356
6625
  return existing;
6357
6626
  if (props.devices === undefined || props.raidlevel === undefined) {
6358
- return yield* Effect88.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."));
6627
+ return yield* Effect96.die(new Error(`${props.node}/${props.name}: this is an adopt-only declaration (no \`devices\` or ` + "`raidlevel`) and the pool is not there to adopt. An adopt-only Proxmox.ZfsPool never " + "creates -- declare both fields for a pool this resource should build, or point this " + "declaration at a pool that already exists on this node."));
6359
6628
  }
6360
6629
  yield* guardForm(zfsPoolCreateEndpoint(props), asForm2(createForm12(props)), true);
6361
- const upid = yield* runPve(props.target, "provision", true, nodes11.createNodeDiskZfs(toDistilledCreate5(props)));
6362
- const settle3 = (attempts) => Effect88.gen(function* () {
6630
+ const upid = yield* runPve(props.target, "provision", true, nodes19.createNodeDiskZfs(toDistilledCreate5(props)));
6631
+ const settle3 = (attempts) => Effect96.gen(function* () {
6363
6632
  const live = yield* read6(props);
6364
6633
  if (live !== undefined || attempts <= 0)
6365
6634
  return live;
6366
- yield* Effect88.sleep("2 seconds");
6635
+ yield* Effect96.sleep("2 seconds");
6367
6636
  return yield* settle3(attempts - 1);
6368
6637
  });
6369
6638
  const after = yield* settle3(SETTLE_ATTEMPTS);
6370
6639
  if (after === undefined) {
6371
- return yield* Effect88.die(new Error(`nodes/${props.node}/disks/zfs/${props.name}: POST returned ${text(upid, "(no UPID)")} ` + "but the pool has not appeared. That POST only forks a `zfscreate` worker, so the task " + `holds the real error -- read it with \`pvesh get /nodes/${props.node}/tasks/<upid>/log\`. ` + "NOTHING WAS RETRIED AND NOTHING WAS CLEANED UP: if the worker reached `zpool create`, " + "the declared devices have already been written to. DO NOT RE-RUN THIS DEPLOY BEFORE " + 'READING THAT LOG: `read` cannot tell "the worker is still running" from "the pool is ' + 'genuinely gone", so a re-run this soon can POST a SECOND `zpool create` at the SAME ' + "devices while the first one is still mid-write -- confirm the task finished (one way " + "or the other) before trying again."));
6640
+ return yield* Effect96.die(new Error(`nodes/${props.node}/disks/zfs/${props.name}: POST returned ${text(upid, "(no UPID)")} ` + "but the pool has not appeared. That POST only forks a `zfscreate` worker, so the task " + `holds the real error -- read it with \`pvesh get /nodes/${props.node}/tasks/<upid>/log\`. ` + "NOTHING WAS RETRIED AND NOTHING WAS CLEANED UP: if the worker reached `zpool create`, " + "the declared devices have already been written to. DO NOT RE-RUN THIS DEPLOY BEFORE " + 'READING THAT LOG: `read` cannot tell "the worker is still running" from "the pool is ' + 'genuinely gone", so a re-run this soon can POST a SECOND `zpool create` at the SAME ' + "devices while the first one is still mid-write -- confirm the task finished (one way " + "or the other) before trying again."));
6372
6641
  }
6373
6642
  return after;
6374
6643
  });
6375
- var destroyPool = (props) => runPve(props.target, "provision", true, nodes11.deleteNodeDiskZfs({ name: props.name, node: props.node }));
6644
+ var destroyPool = (props) => runPve(props.target, "provision", true, nodes19.deleteNodeDiskZfs({ name: props.name, node: props.node }));
6376
6645
 
6377
6646
  // src/proxmox/zfs-pool.ts
6378
6647
  var ProxmoxZfsPool = Resource35("Proxmox.ZfsPool", {
6379
6648
  defaultRemovalPolicy: "retain"
6380
6649
  });
6381
- var ProxmoxZfsPoolProvider = () => Provider35.effect(ProxmoxZfsPool, Effect89.succeed(ProxmoxZfsPool.Provider.of({
6382
- list: () => Effect89.succeed([]),
6383
- read: Effect89.fn(function* ({ olds, output }) {
6650
+ var ProxmoxZfsPoolProvider = () => Provider35.effect(ProxmoxZfsPool, Effect97.succeed(ProxmoxZfsPool.Provider.of({
6651
+ list: () => Effect97.succeed([]),
6652
+ read: Effect97.fn(function* ({ olds, output }) {
6384
6653
  return dropUnreadable8(yield* output === undefined ? readPool2(olds) : readPoolOrFail(olds));
6385
6654
  }),
6386
- diff: Effect89.fn(function* ({ news, output }) {
6387
- if (!isResolved28(news))
6655
+ diff: Effect97.fn(function* ({ news, output }) {
6656
+ if (!isResolved30(news))
6388
6657
  return;
6389
6658
  yield* guardForm(zfsPoolCreateEndpoint(news), asForm2(createForm12(news)), output === undefined);
6390
6659
  if (output === undefined)
@@ -6400,10 +6669,10 @@ var ProxmoxZfsPoolProvider = () => Provider35.effect(ProxmoxZfsPool, Effect89.su
6400
6669
  }
6401
6670
  return { action: "noop" };
6402
6671
  }),
6403
- reconcile: Effect89.fn(function* ({ news }) {
6404
- return yield* createPool2(news, (props) => readPool2(props).pipe(Effect89.map(dropUnreadable8)));
6672
+ reconcile: Effect97.fn(function* ({ news }) {
6673
+ return yield* createPool2(news, (props) => readPool2(props).pipe(Effect97.map(dropUnreadable8)));
6405
6674
  }),
6406
- delete: Effect89.fn(function* ({ olds }) {
6675
+ delete: Effect97.fn(function* ({ olds }) {
6407
6676
  yield* destroyPool(olds);
6408
6677
  })
6409
6678
  })));
@@ -6483,5 +6752,5 @@ export {
6483
6752
  violations
6484
6753
  };
6485
6754
 
6486
- //# debugId=14E701EEC70A7BD764756E2164756E21
6755
+ //# debugId=B5C51EB76E4323A364756E2164756E21
6487
6756
  //# sourceMappingURL=index.js.map