@homeflare/alchemy 0.28.0 → 0.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (210) hide show
  1. package/README.md +2 -0
  2. package/dist/caddy/admin-address.d.ts +27 -0
  3. package/dist/caddy/admin-address.d.ts.map +1 -0
  4. package/dist/caddy/admin-calls.d.ts +25 -28
  5. package/dist/caddy/admin-calls.d.ts.map +1 -1
  6. package/dist/caddy/admin.d.ts +28 -38
  7. package/dist/caddy/admin.d.ts.map +1 -1
  8. package/dist/caddy/caddy-http-client.d.ts +25 -0
  9. package/dist/caddy/caddy-http-client.d.ts.map +1 -0
  10. package/dist/caddy/config-errors.d.ts +24 -0
  11. package/dist/caddy/config-errors.d.ts.map +1 -0
  12. package/dist/caddy/config-lifecycle.d.ts +20 -49
  13. package/dist/caddy/config-lifecycle.d.ts.map +1 -1
  14. package/dist/caddy/config-reconcile.d.ts +45 -0
  15. package/dist/caddy/config-reconcile.d.ts.map +1 -0
  16. package/dist/caddy/config.d.ts +4 -3
  17. package/dist/caddy/config.d.ts.map +1 -1
  18. package/dist/caddy/fake-caddy.d.ts +10 -2
  19. package/dist/caddy/fake-caddy.d.ts.map +1 -1
  20. package/dist/caddy/index.d.ts +3 -3
  21. package/dist/caddy/index.d.ts.map +1 -1
  22. package/dist/caddy/index.js +487 -444
  23. package/dist/caddy/index.js.map +16 -12
  24. package/dist/caddy/local-admin.d.ts +20 -34
  25. package/dist/caddy/local-admin.d.ts.map +1 -1
  26. package/dist/caddy/providers.d.ts +19 -3
  27. package/dist/caddy/providers.d.ts.map +1 -1
  28. package/dist/cloudflare/mesh-node-token.d.ts +1 -1
  29. package/dist/cloudflare/mesh-node-token.d.ts.map +1 -1
  30. package/dist/forgejo/branch-protection.d.ts +4 -4
  31. package/dist/forgejo/org-actions-secrets.d.ts +4 -4
  32. package/dist/forgejo/org-label.d.ts +4 -4
  33. package/dist/forgejo/org-team.d.ts +4 -4
  34. package/dist/forgejo/repo-webhook.d.ts +4 -4
  35. package/dist/forgejo/repository.d.ts +4 -4
  36. package/dist/forgejo/team-member.d.ts +4 -4
  37. package/dist/github/declare-repo-baseline.d.ts +1 -1
  38. package/dist/github/declare-repo-baseline.d.ts.map +1 -1
  39. package/dist/github/index.d.ts +8 -4
  40. package/dist/github/index.d.ts.map +1 -1
  41. package/dist/github/index.js +63 -23
  42. package/dist/github/index.js.map +13 -12
  43. package/dist/github/repo-baseline-data.d.ts +10 -1
  44. package/dist/github/repo-baseline-data.d.ts.map +1 -1
  45. package/dist/github/repo-policy.d.ts +1 -1
  46. package/dist/github/repo-policy.d.ts.map +1 -1
  47. package/dist/github/repository-ruleset-errors.d.ts +3 -2
  48. package/dist/github/repository-ruleset-errors.d.ts.map +1 -1
  49. package/dist/github/repository-ruleset-form.d.ts.map +1 -1
  50. package/dist/github/repository-ruleset-guards.d.ts +3 -2
  51. package/dist/github/repository-ruleset-guards.d.ts.map +1 -1
  52. package/dist/github/repository-ruleset-octokit.d.ts +49 -0
  53. package/dist/github/repository-ruleset-octokit.d.ts.map +1 -1
  54. package/dist/github/repository-ruleset-probe.d.ts +2 -1
  55. package/dist/github/repository-ruleset-probe.d.ts.map +1 -1
  56. package/dist/github/repository-ruleset-props.d.ts +7 -4
  57. package/dist/github/repository-ruleset-props.d.ts.map +1 -1
  58. package/dist/github/repository-ruleset-providers.d.ts +42 -0
  59. package/dist/github/repository-ruleset-providers.d.ts.map +1 -0
  60. package/dist/github/repository-ruleset.d.ts +26 -4
  61. package/dist/github/repository-ruleset.d.ts.map +1 -1
  62. package/dist/litellm/fake-litellm.d.ts +27 -16
  63. package/dist/litellm/fake-litellm.d.ts.map +1 -1
  64. package/dist/litellm/fake-stack.d.ts +9 -4
  65. package/dist/litellm/fake-stack.d.ts.map +1 -1
  66. package/dist/litellm/index.d.ts +7 -5
  67. package/dist/litellm/index.d.ts.map +1 -1
  68. package/dist/litellm/index.js +53 -123
  69. package/dist/litellm/index.js.map +8 -8
  70. package/dist/litellm/operations.d.ts +60 -0
  71. package/dist/litellm/operations.d.ts.map +1 -0
  72. package/dist/litellm/pass-through-endpoint.d.ts +10 -28
  73. package/dist/litellm/pass-through-endpoint.d.ts.map +1 -1
  74. package/dist/litellm/pass-through-errors.d.ts +37 -0
  75. package/dist/litellm/pass-through-errors.d.ts.map +1 -0
  76. package/dist/litellm/pass-through-form.d.ts +11 -4
  77. package/dist/litellm/pass-through-form.d.ts.map +1 -1
  78. package/dist/litellm/providers.d.ts +7 -5
  79. package/dist/litellm/providers.d.ts.map +1 -1
  80. package/dist/netbox/prefix.d.ts +4 -4
  81. package/dist/paperless/custom-field.d.ts +21 -21
  82. package/dist/paperless/custom-field.d.ts.map +1 -1
  83. package/dist/paperless/document-type.d.ts +34 -4
  84. package/dist/paperless/document-type.d.ts.map +1 -1
  85. package/dist/paperless/fake-paperless.d.ts +36 -19
  86. package/dist/paperless/fake-paperless.d.ts.map +1 -1
  87. package/dist/paperless/index.d.ts +7 -2
  88. package/dist/paperless/index.d.ts.map +1 -1
  89. package/dist/paperless/index.js +164 -228
  90. package/dist/paperless/index.js.map +10 -13
  91. package/dist/paperless/matching-locate.d.ts +42 -20
  92. package/dist/paperless/matching-locate.d.ts.map +1 -1
  93. package/dist/paperless/matching-types.d.ts +47 -18
  94. package/dist/paperless/matching-types.d.ts.map +1 -1
  95. package/dist/paperless/matching.d.ts +30 -27
  96. package/dist/paperless/matching.d.ts.map +1 -1
  97. package/dist/paperless/providers.d.ts +13 -7
  98. package/dist/paperless/providers.d.ts.map +1 -1
  99. package/dist/paperless/storage-path.d.ts +34 -4
  100. package/dist/paperless/storage-path.d.ts.map +1 -1
  101. package/dist/paperless/tag.d.ts +43 -8
  102. package/dist/paperless/tag.d.ts.map +1 -1
  103. package/dist/proxmox/acl.d.ts +30 -23
  104. package/dist/proxmox/acl.d.ts.map +1 -1
  105. package/dist/proxmox/distilled-pve.d.ts +89 -0
  106. package/dist/proxmox/distilled-pve.d.ts.map +1 -0
  107. package/dist/proxmox/index.js +663 -609
  108. package/dist/proxmox/index.js.map +12 -11
  109. package/dist/proxmox/members.d.ts +29 -10
  110. package/dist/proxmox/members.d.ts.map +1 -1
  111. package/docs/caddy-admin.md +1 -1
  112. package/docs/caddy.md +3 -2
  113. package/docs/credentials.md +16 -0
  114. package/docs/litellm.md +21 -13
  115. package/docs/paperless.md +12 -0
  116. package/docs/peers.md +5 -0
  117. package/docs/repo-policy.md +16 -1
  118. package/docs/repository-ruleset.md +53 -13
  119. package/docs/upstream-conformance.md +126 -10
  120. package/package.json +5 -2
  121. package/src/caddy/admin-address.ts +71 -0
  122. package/src/caddy/admin-calls.ts +48 -100
  123. package/src/caddy/admin.ts +37 -41
  124. package/src/caddy/adopt-scope.test.ts +1 -1
  125. package/src/caddy/caddy-http-client.ts +229 -0
  126. package/src/caddy/config-adopt-provider.test.ts +139 -0
  127. package/src/caddy/config-adopt.test.ts +60 -126
  128. package/src/caddy/config-errors.ts +47 -0
  129. package/src/caddy/config-lifecycle.test.ts +55 -42
  130. package/src/caddy/config-lifecycle.ts +72 -162
  131. package/src/caddy/config-reconcile.ts +138 -0
  132. package/src/caddy/config.ts +36 -42
  133. package/src/caddy/fake-caddy.ts +20 -2
  134. package/src/caddy/index.ts +3 -8
  135. package/src/caddy/local-admin.test.ts +35 -21
  136. package/src/caddy/local-admin.ts +60 -167
  137. package/src/caddy/providers.test.ts +14 -6
  138. package/src/caddy/providers.ts +20 -4
  139. package/src/github/declare-repo-baseline.ts +6 -6
  140. package/src/github/index.ts +8 -4
  141. package/src/github/repo-baseline-data.test.ts +13 -0
  142. package/src/github/repo-baseline-data.ts +11 -2
  143. package/src/github/repo-policy-stack.test.ts +59 -0
  144. package/src/github/repo-policy.ts +3 -2
  145. package/src/github/repository-ruleset-errors.ts +6 -4
  146. package/src/github/repository-ruleset-exact-adopt-k1.test.ts +109 -0
  147. package/src/github/repository-ruleset-exact-adopt.test.ts +14 -9
  148. package/src/github/repository-ruleset-form.ts +7 -3
  149. package/src/github/repository-ruleset-guards.ts +3 -2
  150. package/src/github/repository-ruleset-octokit.test.ts +141 -0
  151. package/src/github/repository-ruleset-octokit.ts +121 -30
  152. package/src/github/repository-ruleset-probe.ts +2 -1
  153. package/src/github/repository-ruleset-props.ts +7 -4
  154. package/src/github/repository-ruleset-providers.ts +46 -0
  155. package/src/github/repository-ruleset-wire.test.ts +38 -27
  156. package/src/github/repository-ruleset.ts +27 -3
  157. package/src/litellm/fake-litellm.ts +83 -78
  158. package/src/litellm/fake-stack.ts +13 -5
  159. package/src/litellm/index.ts +7 -21
  160. package/src/litellm/operations.ts +149 -0
  161. package/src/litellm/pass-through-endpoint-delete-swallow.test.ts +17 -20
  162. package/src/litellm/pass-through-endpoint-replace.test.ts +3 -4
  163. package/src/litellm/pass-through-endpoint.test.ts +8 -8
  164. package/src/litellm/pass-through-endpoint.ts +21 -31
  165. package/src/litellm/pass-through-errors.ts +37 -0
  166. package/src/litellm/pass-through-form.ts +20 -10
  167. package/src/litellm/providers.ts +8 -7
  168. package/src/paperless/custom-field.test.ts +49 -40
  169. package/src/paperless/custom-field.ts +57 -33
  170. package/src/paperless/document-type.test.ts +48 -0
  171. package/src/paperless/document-type.ts +51 -22
  172. package/src/paperless/fake-paperless.ts +63 -72
  173. package/src/paperless/index.ts +7 -13
  174. package/src/paperless/matching-locate.test.ts +102 -0
  175. package/src/paperless/matching-locate.ts +80 -86
  176. package/src/paperless/matching-types.ts +49 -16
  177. package/src/paperless/matching.ts +77 -90
  178. package/src/paperless/providers.ts +14 -10
  179. package/src/paperless/storage-path.test.ts +56 -0
  180. package/src/paperless/storage-path.ts +53 -24
  181. package/src/paperless/tag-identity.test.ts +127 -0
  182. package/src/paperless/tag.test.ts +100 -0
  183. package/src/paperless/tag.ts +62 -32
  184. package/src/proxmox/acl.test.ts +145 -0
  185. package/src/proxmox/acl.ts +128 -150
  186. package/src/proxmox/distilled-pve.test.ts +231 -0
  187. package/src/proxmox/distilled-pve.ts +147 -0
  188. package/src/proxmox/members-timeout.test.ts +161 -0
  189. package/src/proxmox/members.test.ts +9 -0
  190. package/src/proxmox/members.ts +36 -2
  191. package/dist/litellm/client.d.ts +0 -76
  192. package/dist/litellm/client.d.ts.map +0 -1
  193. package/dist/litellm/credentials.d.ts +0 -48
  194. package/dist/litellm/credentials.d.ts.map +0 -1
  195. package/dist/litellm/generated/pass-through.d.ts +0 -71
  196. package/dist/litellm/generated/pass-through.d.ts.map +0 -1
  197. package/dist/paperless/client.d.ts +0 -37
  198. package/dist/paperless/client.d.ts.map +0 -1
  199. package/dist/paperless/credentials.d.ts +0 -40
  200. package/dist/paperless/credentials.d.ts.map +0 -1
  201. package/dist/paperless/errors.d.ts +0 -49
  202. package/dist/paperless/errors.d.ts.map +0 -1
  203. package/src/litellm/client.ts +0 -195
  204. package/src/litellm/credentials.ts +0 -73
  205. package/src/litellm/generated/pass-through.ts +0 -73
  206. package/src/paperless/client.ts +0 -88
  207. package/src/paperless/credentials.ts +0 -69
  208. package/src/paperless/errors.ts +0 -62
  209. package/src/paperless/matching-identity.test.ts +0 -194
  210. package/src/paperless/matching.test.ts +0 -128
@@ -1,235 +1,12 @@
1
1
  // src/proxmox/acl.ts
2
2
  import { Resource } from "alchemy";
3
- import { isResolved as isResolved2 } from "alchemy/Diff";
4
- import * as Provider from "alchemy/Provider";
5
- import * as Effect8 from "effect/Effect";
6
-
7
- // src/proxmox/client.ts
8
- import * as Effect4 from "effect/Effect";
9
- import * as HttpClient5 from "effect/unstable/http/HttpClient";
10
- import * as HttpClientRequest2 from "effect/unstable/http/HttpClientRequest";
11
-
12
- // src/proxmox/credentials.ts
13
- import * as Effect from "effect/Effect";
14
- import * as Option from "effect/Option";
15
- import * as FetchHttpClient from "effect/unstable/http/FetchHttpClient";
16
- import * as Headers from "effect/unstable/http/Headers";
17
- import * as HttpClient from "effect/unstable/http/HttpClient";
18
- import * as HttpClientRequest from "effect/unstable/http/HttpClientRequest";
19
- var baoVariable = (env, name) => env[`BAO_${name}`] ?? env[`VAULT_${name}`] ?? "";
20
- var mint = (target, role, env = process.env) => Effect.gen(function* () {
21
- const path = `${target.mount}/creds/${role}`;
22
- const refuse = (status2, detail) => new Error(`OpenBao GET /v1/${path} -> ${status2 === 0 ? "no response" : status2}: ${detail}`);
23
- const address = baoVariable(env, "AGENT_ADDR") || baoVariable(env, "ADDR") || "https://127.0.0.1:8200";
24
- const socket = address.startsWith("unix://") ? address.slice("unix://".length) : undefined;
25
- const base = socket === undefined ? address.replace(/\/+$/, "") : "http://localhost";
26
- const headers = { "X-Vault-Request": "true" };
27
- const namespace = baoVariable(env, "NAMESPACE");
28
- if (namespace !== "")
29
- headers["X-Vault-Namespace"] = namespace;
30
- const token = baoVariable(env, "TOKEN");
31
- if (token !== "")
32
- headers["X-Vault-Token"] = token;
33
- if (socket !== undefined && !("Bun" in globalThis)) {
34
- return yield* Effect.fail(refuse(0, "a unix:// address needs Bun fetch; this is not Bun"));
35
- }
36
- const client = yield* HttpClient.HttpClient;
37
- const redacted = yield* Headers.CurrentRedactedNames;
38
- const defaults = Option.getOrElse(yield* Effect.serviceOption(FetchHttpClient.RequestInit), () => ({}));
39
- const request = HttpClientRequest.get(`${base}/v1/${path}`).pipe(HttpClientRequest.setHeaders(headers));
40
- const exchange = client.execute(request).pipe(Effect.flatMap((response) => Effect.map(response.text, (text2) => ({ status: response.status, text: text2 }))), Effect.timeout("60 seconds"), Effect.provideService(Headers.CurrentRedactedNames, [...redacted, "x-vault-token"]));
41
- const init = { ...defaults, unix: socket };
42
- const { status, text } = yield* (socket === undefined ? exchange : Effect.provideService(exchange, FetchHttpClient.RequestInit, init)).pipe(Effect.mapError((cause) => refuse(0, cause.message)));
43
- let parsed;
44
- try {
45
- parsed = JSON.parse(text);
46
- } catch {
47
- parsed = undefined;
48
- }
49
- if (status < 200 || status >= 300) {
50
- const errors = parsed?.errors;
51
- const detail = Array.isArray(errors) ? errors.map(String).join("; ") : "not an OpenBao error body";
52
- return yield* Effect.fail(refuse(status, detail || "(no errors given)"));
53
- }
54
- const tokenId = parsed?.data?.token_id;
55
- const secret = parsed?.data?.secret;
56
- if (typeof tokenId !== "string" || typeof secret !== "string") {
57
- return yield* Effect.fail(new Error(`${target.mount}/creds/${role} returned no token_id/secret. Either this approle lacks ` + `the grant, or the mount is not ${target.mount}. Say which mount and role you needed ` + `than falling back to a stored credential -- every stored PVE token is read-only.`));
58
- }
59
- const lease = parsed?.lease_duration;
60
- const leaseSeconds = typeof lease === "number" ? lease : 0;
61
- return { leaseSeconds, secret, tokenId };
62
- });
63
- var authorization = (credential, target) => target.scheme === "pbs" ? `PBSAPIToken=${credential.tokenId}:${credential.secret}` : `PVEAPIToken=${credential.tokenId}=${credential.secret}`;
64
-
65
- // src/proxmox/lease-cache.ts
66
- import * as Cache from "effect/Cache";
67
- import * as Duration from "effect/Duration";
68
- import * as Effect2 from "effect/Effect";
69
- import * as Exit from "effect/Exit";
70
- var REMINT_MARGIN_SECONDS = 60;
71
- var keyOf = (target, role) => ({
72
- mount: target.mount,
73
- role,
74
- scheme: target.scheme
75
- });
76
- var timeToLive = (exit) => Exit.isSuccess(exit) && exit.value.leaseSeconds > REMINT_MARGIN_SECONDS ? Duration.seconds(exit.value.leaseSeconds - REMINT_MARGIN_SECONDS) : Duration.zero;
77
- var makeLeases = (mintFor) => Cache.makeWith(mintFor, { capacity: 64, requireServicesAt: "lookup", timeToLive });
78
- var targetForKey = (key) => key.scheme === "pbs" ? { api: "https://pbs.invalid/api2/json", mount: key.mount, scheme: "pbs" } : { members: [], mount: key.mount, scheme: "pve" };
79
- var leases = Effect2.runSync(makeLeases((key) => mint(targetForKey(key), key.role)));
80
- var leased = (target, role) => Cache.get(leases, keyOf(target, role));
81
-
82
- // src/proxmox/members.ts
83
- import * as Effect3 from "effect/Effect";
84
- import * as Result from "effect/Result";
85
- import * as HttpClient3 from "effect/unstable/http/HttpClient";
86
- import * as HttpClientError from "effect/unstable/http/HttpClientError";
87
- var PVE_API_PORT = 8006;
88
- var pveApiBase = (member) => `https://${member}:${String(PVE_API_PORT)}/api2/json`;
89
- var lastGoodByMount = new Map;
90
- var noteGoodMember = (target, member) => {
91
- lastGoodByMount.set(target.mount, member);
92
- };
93
- var orderedMembers = (target) => {
94
- const preferred = lastGoodByMount.get(target.mount);
95
- if (preferred === undefined || !target.members.includes(preferred))
96
- return target.members;
97
- return [preferred, ...target.members.filter((member) => member !== preferred)];
98
- };
99
- var errorCode = (cause) => {
100
- if (cause !== null && typeof cause === "object") {
101
- if ("code" in cause && typeof cause.code === "string")
102
- return cause.code;
103
- if ("cause" in cause)
104
- return errorCode(cause.cause);
105
- }
106
- return;
107
- };
108
- var isTimeoutCause = (cause) => {
109
- const code = errorCode(cause);
110
- if (code === "AbortError" || code === "ETIMEDOUT" || code === "UND_ERR_CONNECT_TIMEOUT") {
111
- return true;
112
- }
113
- return cause instanceof Error && /timed out|timeout/i.test(cause.message);
114
- };
115
- var PRE_SEND_CODES = new Set(["ConnectionRefused", "ECONNREFUSED", "ENOTFOUND", "EAI_AGAIN"]);
116
- var isCertificateCode = (code) => /^(ERR_TLS_CERT_|CERT_|UNABLE_TO_VERIFY_|DEPTH_ZERO_SELF_SIGNED|SELF_SIGNED_CERT)/.test(code);
117
- var isPreSendCause = (cause) => {
118
- const code = errorCode(cause);
119
- return code !== undefined && (PRE_SEND_CODES.has(code) || isCertificateCode(code));
120
- };
121
- var isTransportFailure = (cause) => {
122
- if (!HttpClientError.isHttpClientError(cause))
123
- return false;
124
- const tag = cause.reason._tag;
125
- return tag === "TransportError" || tag === "InvalidUrlError" || tag === "EncodeError";
126
- };
127
- var isPreSendTransport = (cause) => {
128
- if (!HttpClientError.isHttpClientError(cause))
129
- return false;
130
- const { reason } = cause;
131
- if (reason._tag === "InvalidUrlError" || reason._tag === "EncodeError")
132
- return true;
133
- if (reason._tag === "TransportError") {
134
- if (isTimeoutCause(reason.cause))
135
- return false;
136
- return isPreSendCause(reason.cause);
137
- }
138
- return false;
139
- };
140
- var describeTransport = (cause) => {
141
- if (HttpClientError.isHttpClientError(cause))
142
- return cause.message;
143
- return String(cause);
144
- };
145
- var executeOnCluster = (target, method, path, build) => Effect3.gen(function* () {
146
- const client = yield* HttpClient3.HttpClient;
147
- const isWrite = method !== "GET";
148
- const attempts = [];
149
- for (const member of orderedMembers(target)) {
150
- const outcome = yield* client.execute(build(pveApiBase(member))).pipe(Effect3.result);
151
- if (Result.isSuccess(outcome)) {
152
- noteGoodMember(target, member);
153
- return outcome.success;
154
- }
155
- const why = describeTransport(outcome.failure);
156
- attempts.push({ member, why });
157
- const mayRetry = isWrite ? isPreSendTransport(outcome.failure) : isTransportFailure(outcome.failure);
158
- if (!mayRetry) {
159
- return yield* Effect3.fail({ attempts, method, path, tag: "cluster" });
160
- }
161
- }
162
- return yield* Effect3.fail({ attempts, method, path, tag: "cluster" });
163
- });
164
-
165
- // src/proxmox/client.ts
166
- class PveError extends Error {
167
- status;
168
- method;
169
- path;
170
- constructor(status, method, path, detail) {
171
- super(`PVE ${method} ${path} -> ${String(status)}: ${detail}`);
172
- this.status = status;
173
- this.method = method;
174
- this.path = path;
175
- this.name = "PveError";
176
- }
177
- }
178
- var clusterExhausted = (method, path, attempts) => new PveError(0, method, path, `all members failed: ${attempts.map((a) => `${a.member} (${a.why})`).join("; ")}`);
179
- var encode = (form) => {
180
- const params = new URLSearchParams;
181
- for (const [key, value] of Object.entries(form)) {
182
- if (typeof value === "string")
183
- params.append(key, value);
184
- else
185
- for (const item of value)
186
- params.append(key, item);
187
- }
188
- return params.toString();
189
- };
190
- var buildRequest = (method, apiBase, path, credential, target, form) => {
191
- const url = `${apiBase}/${path}`;
192
- return HttpClientRequest2.make(method)(url).pipe(HttpClientRequest2.setHeaders({ Authorization: authorization(credential, target) }), form === undefined ? (self) => self : HttpClientRequest2.bodyText(encode(form), "application/x-www-form-urlencoded"));
193
- };
194
- var executeOne = (target, credential, method, path, form, apiBase) => Effect4.gen(function* () {
195
- const client = yield* HttpClient5.HttpClient;
196
- const request = buildRequest(method, apiBase, path, credential, target, form);
197
- return yield* client.execute(request).pipe(Effect4.mapError((cause) => new PveError(0, method, path, String(cause))));
198
- });
199
- var readResponse = (response, method, path) => Effect4.gen(function* () {
200
- if (response.status < 200 || response.status >= 300) {
201
- const detail = yield* response.text.pipe(Effect4.orElseSucceed(() => ""));
202
- return yield* Effect4.fail(new PveError(response.status, method, path, detail.slice(0, 300)));
203
- }
204
- const body = yield* response.json.pipe(Effect4.mapError((cause) => new PveError(0, method, path, String(cause))));
205
- return body.data;
206
- });
207
- var pveWith = (target, credential, method, path, form) => Effect4.gen(function* () {
208
- const response = target.scheme === "pve" ? yield* executeOnCluster(target, method, path, (apiBase) => buildRequest(method, apiBase, path, credential, target, form)).pipe(Effect4.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);
209
- return yield* readResponse(response, method, path);
210
- });
211
- var pveEnvelopeWith = (target, credential, method, path) => Effect4.gen(function* () {
212
- const response = yield* executeOnCluster(target, method, path, (apiBase) => buildRequest(method, apiBase, path, credential, target)).pipe(Effect4.mapError((failure) => failure.tag === "cluster" ? clusterExhausted(failure.method, failure.path, failure.attempts) : new PveError(0, method, path, String(failure))));
213
- if (response.status < 200 || response.status >= 300) {
214
- const detail = yield* response.text.pipe(Effect4.orElseSucceed(() => ""));
215
- return yield* Effect4.fail(new PveError(response.status, method, path, detail.slice(0, 300)));
216
- }
217
- return yield* response.json.pipe(Effect4.mapError((cause) => new PveError(0, method, path, String(cause))));
218
- });
219
- var pve = (target, role, method, path, form) => Effect4.gen(function* () {
220
- const credential = yield* leased(target, role);
221
- return yield* pveWith(target, credential, method, path, form);
222
- });
223
-
224
- // src/proxmox/resource.ts
225
3
  import { isResolved } from "alchemy/Diff";
226
- import * as Effect7 from "effect/Effect";
227
-
228
- // src/proxmox/resource-guard.ts
4
+ import * as Provider from "alchemy/Provider";
5
+ import * as access from "@distilled.cloud/proxmox/access";
229
6
  import * as Effect6 from "effect/Effect";
230
7
 
231
8
  // src/proxmox/constraint-guard.ts
232
- import * as Effect5 from "effect/Effect";
9
+ import * as Effect from "effect/Effect";
233
10
 
234
11
  // src/proxmox/constraints.ts
235
12
  var lengthOf = (value) => [...value].length;
@@ -1187,151 +964,283 @@ var constraintsFor = (key) => {
1187
964
  return table;
1188
965
  };
1189
966
  var formViolations = (key, form, presence) => violations(constraintsFor(key), form, { presence });
1190
- var guardForm = (key, form, presence) => Effect5.suspend(() => {
967
+ var guardForm = (key, form, presence) => Effect.suspend(() => {
1191
968
  if (key === undefined)
1192
- return Effect5.void;
969
+ return Effect.void;
1193
970
  const found = formViolations(key, form, presence);
1194
- return found.length === 0 ? Effect5.void : Effect5.die(new Error(refusal(key, found)));
971
+ return found.length === 0 ? Effect.void : Effect.die(new Error(refusal(key, found)));
1195
972
  });
1196
973
 
1197
- // src/proxmox/resource-guard.ts
1198
- var specGuards = (spec) => {
1199
- const endpointsOf = (props) => typeof spec.endpoint === "function" ? spec.endpoint(props) : spec.endpoint;
1200
- const guardCreate = (props, presence) => Effect6.suspend(() => {
1201
- const create = endpointsOf(props)?.create;
1202
- return create === undefined ? Effect6.void : guardForm(create, spec.createForm(props), presence);
1203
- });
1204
- const guardUpdate = (props) => Effect6.suspend(() => {
1205
- const update = endpointsOf(props)?.update;
1206
- if (update === undefined)
1207
- return Effect6.void;
1208
- const form = spec.updateForm?.(props);
1209
- return form === undefined ? Effect6.void : guardForm(update, form, false);
1210
- });
1211
- return { guardCreate, guardUpdate };
1212
- };
974
+ // src/proxmox/distilled-pve.ts
975
+ import * as Effect5 from "effect/Effect";
976
+ import * as Result2 from "effect/Result";
977
+ import { credentials as distilledPveCredentials } from "@distilled.cloud/proxmox/Credentials";
978
+ import * as ProxmoxRetry from "@distilled.cloud/proxmox/Retry";
1213
979
 
1214
- // src/proxmox/update-guard.ts
1215
- var formToSend = (matches, live, props, form) => matches(live, props) || Object.keys(form).length === 0 ? undefined : form;
980
+ // src/proxmox/lease-cache.ts
981
+ import * as Cache from "effect/Cache";
982
+ import * as Duration from "effect/Duration";
983
+ import * as Effect3 from "effect/Effect";
984
+ import * as Exit from "effect/Exit";
1216
985
 
1217
- // src/proxmox/resource.ts
1218
- var pveOperations = (spec) => {
1219
- const { guardCreate, guardUpdate } = specGuards(spec);
1220
- const read = (props) => pve(props.target, spec.readRole ?? "read", "GET", spec.path(props)).pipe(Effect7.map((data) => data == null ? undefined : spec.attributes(data, props)), Effect7.orElseSucceed(() => {
1221
- return;
1222
- }));
1223
- return {
1224
- guardCreate,
1225
- guardUpdate,
1226
- read,
1227
- diff: (news, output) => Effect7.gen(function* () {
1228
- if (!isResolved(news))
1229
- return;
1230
- yield* guardCreate(news, output === undefined);
1231
- yield* guardUpdate(news);
1232
- if (output === undefined)
1233
- return;
1234
- const live = yield* read(news);
1235
- if (live === undefined) {
1236
- yield* guardCreate(news, true);
1237
- return { action: "update" };
1238
- }
1239
- if (spec.matches(live, news))
1240
- return { action: "noop" };
1241
- return spec.updateForm === undefined ? { action: "replace" } : { action: "update" };
1242
- }),
1243
- reconcile: (news) => Effect7.gen(function* () {
1244
- const live = yield* read(news);
1245
- yield* guardCreate(news, live === undefined);
1246
- yield* guardUpdate(news);
1247
- if (live === undefined) {
1248
- yield* pve(news.target, "provision", "POST", spec.collection(news), spec.createForm(news));
1249
- } else if (spec.updateForm !== undefined) {
1250
- const form = formToSend(spec.matches, live, news, spec.updateForm(news));
1251
- if (form !== undefined) {
1252
- yield* pve(news.target, "provision", "PUT", spec.path(news), form);
1253
- }
1254
- }
1255
- const after = yield* read(news);
1256
- if (after === undefined) {
1257
- return yield* Effect7.die(new Error(`${spec.path(news)}: the write returned no error but the object 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."));
1258
- }
1259
- return after;
1260
- }),
1261
- destroy: (olds) => pve(olds.target, "provision", "DELETE", spec.path(olds))
1262
- };
986
+ // src/proxmox/credentials.ts
987
+ import * as Effect2 from "effect/Effect";
988
+ import * as Option from "effect/Option";
989
+ import * as FetchHttpClient from "effect/unstable/http/FetchHttpClient";
990
+ import * as Headers from "effect/unstable/http/Headers";
991
+ import * as HttpClient from "effect/unstable/http/HttpClient";
992
+ import * as HttpClientRequest from "effect/unstable/http/HttpClientRequest";
993
+ var baoVariable = (env, name) => env[`BAO_${name}`] ?? env[`VAULT_${name}`] ?? "";
994
+ var mint = (target, role, env = process.env) => Effect2.gen(function* () {
995
+ const path = `${target.mount}/creds/${role}`;
996
+ const refuse = (status2, detail) => new Error(`OpenBao GET /v1/${path} -> ${status2 === 0 ? "no response" : status2}: ${detail}`);
997
+ const address = baoVariable(env, "AGENT_ADDR") || baoVariable(env, "ADDR") || "https://127.0.0.1:8200";
998
+ const socket = address.startsWith("unix://") ? address.slice("unix://".length) : undefined;
999
+ const base = socket === undefined ? address.replace(/\/+$/, "") : "http://localhost";
1000
+ const headers = { "X-Vault-Request": "true" };
1001
+ const namespace = baoVariable(env, "NAMESPACE");
1002
+ if (namespace !== "")
1003
+ headers["X-Vault-Namespace"] = namespace;
1004
+ const token = baoVariable(env, "TOKEN");
1005
+ if (token !== "")
1006
+ headers["X-Vault-Token"] = token;
1007
+ if (socket !== undefined && !("Bun" in globalThis)) {
1008
+ return yield* Effect2.fail(refuse(0, "a unix:// address needs Bun fetch; this is not Bun"));
1009
+ }
1010
+ const client = yield* HttpClient.HttpClient;
1011
+ const redacted = yield* Headers.CurrentRedactedNames;
1012
+ const defaults = Option.getOrElse(yield* Effect2.serviceOption(FetchHttpClient.RequestInit), () => ({}));
1013
+ const request = HttpClientRequest.get(`${base}/v1/${path}`).pipe(HttpClientRequest.setHeaders(headers));
1014
+ const exchange = client.execute(request).pipe(Effect2.flatMap((response) => Effect2.map(response.text, (text2) => ({ status: response.status, text: text2 }))), Effect2.timeout("60 seconds"), Effect2.provideService(Headers.CurrentRedactedNames, [...redacted, "x-vault-token"]));
1015
+ const init = { ...defaults, unix: socket };
1016
+ const { status, text } = yield* (socket === undefined ? exchange : Effect2.provideService(exchange, FetchHttpClient.RequestInit, init)).pipe(Effect2.mapError((cause) => refuse(0, cause.message)));
1017
+ let parsed;
1018
+ try {
1019
+ parsed = JSON.parse(text);
1020
+ } catch {
1021
+ parsed = undefined;
1022
+ }
1023
+ if (status < 200 || status >= 300) {
1024
+ const errors = parsed?.errors;
1025
+ const detail = Array.isArray(errors) ? errors.map(String).join("; ") : "not an OpenBao error body";
1026
+ return yield* Effect2.fail(refuse(status, detail || "(no errors given)"));
1027
+ }
1028
+ const tokenId = parsed?.data?.token_id;
1029
+ const secret = parsed?.data?.secret;
1030
+ if (typeof tokenId !== "string" || typeof secret !== "string") {
1031
+ return yield* Effect2.fail(new Error(`${target.mount}/creds/${role} returned no token_id/secret. Either this approle lacks ` + `the grant, or the mount is not ${target.mount}. Say which mount and role you needed ` + `than falling back to a stored credential -- every stored PVE token is read-only.`));
1032
+ }
1033
+ const lease = parsed?.lease_duration;
1034
+ const leaseSeconds = typeof lease === "number" ? lease : 0;
1035
+ return { leaseSeconds, secret, tokenId };
1036
+ });
1037
+ var authorization = (credential, target) => target.scheme === "pbs" ? `PBSAPIToken=${credential.tokenId}:${credential.secret}` : `PVEAPIToken=${credential.tokenId}=${credential.secret}`;
1038
+
1039
+ // src/proxmox/lease-cache.ts
1040
+ var REMINT_MARGIN_SECONDS = 60;
1041
+ var keyOf = (target, role) => ({
1042
+ mount: target.mount,
1043
+ role,
1044
+ scheme: target.scheme
1045
+ });
1046
+ var timeToLive = (exit) => Exit.isSuccess(exit) && exit.value.leaseSeconds > REMINT_MARGIN_SECONDS ? Duration.seconds(exit.value.leaseSeconds - REMINT_MARGIN_SECONDS) : Duration.zero;
1047
+ var makeLeases = (mintFor) => Cache.makeWith(mintFor, { capacity: 64, requireServicesAt: "lookup", timeToLive });
1048
+ var targetForKey = (key) => key.scheme === "pbs" ? { api: "https://pbs.invalid/api2/json", mount: key.mount, scheme: "pbs" } : { members: [], mount: key.mount, scheme: "pve" };
1049
+ var leases = Effect3.runSync(makeLeases((key) => mint(targetForKey(key), key.role)));
1050
+ var leased = (target, role) => Cache.get(leases, keyOf(target, role));
1051
+
1052
+ // src/proxmox/members.ts
1053
+ import * as Cause from "effect/Cause";
1054
+ import * as Effect4 from "effect/Effect";
1055
+ import * as Result from "effect/Result";
1056
+ import * as HttpClient3 from "effect/unstable/http/HttpClient";
1057
+ import * as HttpClientError from "effect/unstable/http/HttpClientError";
1058
+ var PVE_API_PORT = 8006;
1059
+ var pveApiBase = (member) => `https://${member}:${String(PVE_API_PORT)}/api2/json`;
1060
+ var MEMBER_TIMEOUT = "20 seconds";
1061
+ var lastGoodByMount = new Map;
1062
+ var noteGoodMember = (target, member) => {
1063
+ lastGoodByMount.set(target.mount, member);
1263
1064
  };
1264
- var pveHandlers = (spec) => {
1265
- const ops = pveOperations(spec);
1266
- return {
1267
- list: () => Effect7.succeed([]),
1268
- read: ({ olds }) => ops.read(olds),
1269
- diff: ({ news, output }) => ops.diff(news, output),
1270
- reconcile: ({ news }) => ops.reconcile(news),
1271
- delete: ({ olds }) => ops.destroy(olds)
1272
- };
1065
+ var orderedMembers = (target) => {
1066
+ const preferred = lastGoodByMount.get(target.mount);
1067
+ if (preferred === undefined || !target.members.includes(preferred))
1068
+ return target.members;
1069
+ return [preferred, ...target.members.filter((member) => member !== preferred)];
1273
1070
  };
1071
+ var errorCode = (cause) => {
1072
+ if (cause !== null && typeof cause === "object") {
1073
+ if ("code" in cause && typeof cause.code === "string")
1074
+ return cause.code;
1075
+ if ("cause" in cause)
1076
+ return errorCode(cause.cause);
1077
+ }
1078
+ return;
1079
+ };
1080
+ var isTimeoutCause = (cause) => {
1081
+ const code = errorCode(cause);
1082
+ if (code === "AbortError" || code === "ETIMEDOUT" || code === "UND_ERR_CONNECT_TIMEOUT") {
1083
+ return true;
1084
+ }
1085
+ return cause instanceof Error && /timed out|timeout/i.test(cause.message);
1086
+ };
1087
+ var PRE_SEND_CODES = new Set(["ConnectionRefused", "ECONNREFUSED", "ENOTFOUND", "EAI_AGAIN"]);
1088
+ var isCertificateCode = (code) => /^(ERR_TLS_CERT_|CERT_|UNABLE_TO_VERIFY_|DEPTH_ZERO_SELF_SIGNED|SELF_SIGNED_CERT)/.test(code);
1089
+ var isPreSendCause = (cause) => {
1090
+ const code = errorCode(cause);
1091
+ return code !== undefined && (PRE_SEND_CODES.has(code) || isCertificateCode(code));
1092
+ };
1093
+ var isTransportFailure = (cause) => {
1094
+ if (Cause.isTimeoutError(cause))
1095
+ return true;
1096
+ if (!HttpClientError.isHttpClientError(cause))
1097
+ return false;
1098
+ const tag = cause.reason._tag;
1099
+ return tag === "TransportError" || tag === "InvalidUrlError" || tag === "EncodeError";
1100
+ };
1101
+ var isPreSendTransport = (cause) => {
1102
+ if (!HttpClientError.isHttpClientError(cause))
1103
+ return false;
1104
+ const { reason } = cause;
1105
+ if (reason._tag === "InvalidUrlError" || reason._tag === "EncodeError")
1106
+ return true;
1107
+ if (reason._tag === "TransportError") {
1108
+ if (isTimeoutCause(reason.cause))
1109
+ return false;
1110
+ return isPreSendCause(reason.cause);
1111
+ }
1112
+ return false;
1113
+ };
1114
+ var describeTransport = (cause) => {
1115
+ if (Cause.isTimeoutError(cause))
1116
+ return `timed out after ${String(MEMBER_TIMEOUT)}`;
1117
+ if (HttpClientError.isHttpClientError(cause))
1118
+ return cause.message;
1119
+ return String(cause);
1120
+ };
1121
+ var executeOnCluster = (target, method, path, build, timeout3 = MEMBER_TIMEOUT) => Effect4.gen(function* () {
1122
+ const client = yield* HttpClient3.HttpClient;
1123
+ const isWrite = method !== "GET";
1124
+ const attempts = [];
1125
+ for (const member of orderedMembers(target)) {
1126
+ const outcome = yield* client.execute(build(pveApiBase(member))).pipe(Effect4.timeout(timeout3), Effect4.result);
1127
+ if (Result.isSuccess(outcome)) {
1128
+ noteGoodMember(target, member);
1129
+ return outcome.success;
1130
+ }
1131
+ const why = describeTransport(outcome.failure);
1132
+ attempts.push({ member, why });
1133
+ const mayRetry = isWrite ? isPreSendTransport(outcome.failure) : isTransportFailure(outcome.failure);
1134
+ if (!mayRetry) {
1135
+ return yield* Effect4.fail({ attempts, method, path, tag: "cluster" });
1136
+ }
1137
+ }
1138
+ return yield* Effect4.fail({ attempts, method, path, tag: "cluster" });
1139
+ });
1140
+
1141
+ // src/proxmox/distilled-pve.ts
1142
+ class PveClusterExhausted extends Error {
1143
+ attempts;
1144
+ constructor(attempts) {
1145
+ super(`all members failed: ${attempts.map((a) => `${a.member} (${a.why})`).join("; ")}`);
1146
+ this.attempts = attempts;
1147
+ this.name = "PveClusterExhausted";
1148
+ }
1149
+ }
1150
+ var runPveWith = (target, credential, isWrite, op, timeout4 = MEMBER_TIMEOUT) => Effect5.gen(function* () {
1151
+ const attempts = [];
1152
+ for (const member of orderedMembers(target)) {
1153
+ const credLayer = distilledPveCredentials({
1154
+ baseUrl: pveApiBase(member),
1155
+ secret: credential.secret,
1156
+ tokenId: credential.tokenId
1157
+ });
1158
+ const outcome = yield* op.pipe(ProxmoxRetry.none, Effect5.provide(credLayer), Effect5.timeout(timeout4), Effect5.result);
1159
+ if (Result2.isSuccess(outcome)) {
1160
+ noteGoodMember(target, member);
1161
+ return outcome.success;
1162
+ }
1163
+ const mayRetry = isWrite ? isPreSendTransport(outcome.failure) : isTransportFailure(outcome.failure);
1164
+ if (!mayRetry)
1165
+ return yield* Effect5.fail(outcome.failure);
1166
+ attempts.push({ member, why: describeTransport(outcome.failure) });
1167
+ }
1168
+ return yield* Effect5.fail(new PveClusterExhausted(attempts));
1169
+ });
1170
+ var runPve = (target, role, isWrite, op) => Effect5.gen(function* () {
1171
+ const credential = yield* leased(target, role);
1172
+ return yield* runPveWith(target, credential, isWrite, op);
1173
+ });
1274
1174
 
1275
1175
  // src/proxmox/acl.ts
1276
1176
  var ProxmoxAcl = Resource("Proxmox.Acl");
1277
1177
  var normalize = (raw) => `/${raw.split("/").filter(Boolean).join("/")}`;
1278
1178
  var SUBJECT_FIELD = { group: "groups", token: "tokens", user: "users" };
1179
+ var ENDPOINT = "pve:PUT /access/acl";
1279
1180
  var tuple = (props) => ({
1280
1181
  path: normalize(props.path),
1281
1182
  roles: props.roleid,
1282
1183
  [SUBJECT_FIELD[props.type]]: props.ugid
1283
1184
  });
1284
1185
  var bind = (props) => ({
1285
- propagate: props.propagate === false ? "0" : "1",
1286
- ...tuple(props)
1186
+ ...tuple(props),
1187
+ propagate: props.propagate === false ? "0" : "1"
1287
1188
  });
1189
+ var asForm = (body) => Object.fromEntries(Object.entries(body).filter((e) => e[1] !== undefined));
1190
+ var guardWrite = (props) => guardForm(ENDPOINT, asForm(bind(props)), true);
1288
1191
  var identity = (grant) => [normalize(grant.path), grant.type, grant.ugid, grant.roleid].join(" ");
1289
- var find = (live, props) => (Array.isArray(live) ? live : []).filter((row) => typeof row === "object" && row !== null).find((row) => row["path"] === normalize(props.path) && row["type"] === props.type && row["ugid"] === props.ugid && row["roleid"] === props.roleid);
1192
+ var find = (rows, props) => rows.find((row) => row.path === normalize(props.path) && row.type === props.type && row.ugid === props.ugid && row.roleid === props.roleid);
1290
1193
  var propagates = (row) => {
1291
- const value = row["propagate"];
1194
+ const value = row.propagate;
1292
1195
  return value === undefined || value === 1 || value === true || value === "1";
1293
1196
  };
1294
- var ops = pveOperations({
1295
- attributes: (live, props) => {
1296
- const row = find(live, props);
1297
- return {
1298
- bound: row !== undefined,
1299
- path: normalize(props.path),
1300
- propagate: row !== undefined && propagates(row),
1301
- roleid: props.roleid,
1302
- type: props.type,
1303
- ugid: props.ugid
1304
- };
1305
- },
1306
- readRole: "provision",
1307
- collection: () => "access/acl",
1308
- createForm: bind,
1309
- endpoint: { create: "pve:PUT /access/acl", update: "pve:PUT /access/acl" },
1310
- matches: (attributes, props) => attributes.bound && attributes.propagate === (props.propagate !== false),
1311
- path: () => "access/acl",
1312
- updateForm: bind
1313
- });
1314
- var ProxmoxAclProvider = () => Provider.effect(ProxmoxAcl, Effect8.succeed(ProxmoxAcl.Provider.of({
1315
- list: () => Effect8.succeed([]),
1316
- read: Effect8.fn(function* ({ olds }) {
1317
- return yield* ops.read(olds);
1197
+ var attributesOf = (rows, props) => {
1198
+ const row = find(rows, props);
1199
+ return {
1200
+ bound: row !== undefined,
1201
+ path: normalize(props.path),
1202
+ propagate: row !== undefined && propagates(row),
1203
+ roleid: props.roleid,
1204
+ type: props.type,
1205
+ ugid: props.ugid
1206
+ };
1207
+ };
1208
+ var matches = (attributes, props) => attributes.bound && attributes.propagate === (props.propagate !== false);
1209
+ var readAttributes = (props) => runPve(props.target, "provision", false, access.listAccessAcl({})).pipe(Effect6.map((rows) => attributesOf(rows, props)), Effect6.orElseSucceed(() => {
1210
+ return;
1211
+ }));
1212
+ var ProxmoxAclProvider = () => Provider.effect(ProxmoxAcl, Effect6.succeed(ProxmoxAcl.Provider.of({
1213
+ list: () => Effect6.succeed([]),
1214
+ read: Effect6.fn(function* ({ olds }) {
1215
+ return yield* readAttributes(olds);
1318
1216
  }),
1319
- diff: Effect8.fn(function* ({ news, output }) {
1320
- if (output !== undefined && isResolved2(news) && identity(news) !== identity(output)) {
1217
+ diff: Effect6.fn(function* ({ news, output }) {
1218
+ if (output !== undefined && isResolved(news) && identity(news) !== identity(output)) {
1321
1219
  return { action: "replace" };
1322
1220
  }
1323
- return yield* ops.diff(news, output);
1221
+ if (!isResolved(news))
1222
+ return;
1223
+ yield* guardWrite(news);
1224
+ if (output === undefined)
1225
+ return;
1226
+ const live = yield* readAttributes(news);
1227
+ return live !== undefined && matches(live, news) ? { action: "noop" } : { action: "update" };
1324
1228
  }),
1325
- reconcile: Effect8.fn(function* ({ news }) {
1326
- const after = yield* ops.reconcile(news);
1327
- if (!after.bound) {
1328
- return yield* Effect8.die(new Error(`access/acl: the write returned no error but ${identity(news)} is still not ` + "bound. Either the PUT did nothing, or the read credential cannot see the " + "grant -- GET /access/acl is filtered to paths you may MODIFY permissions on, " + "so a read-only role is answered [] rather than 403."));
1229
+ reconcile: Effect6.fn(function* ({ news }) {
1230
+ const before = yield* readAttributes(news);
1231
+ yield* guardWrite(news);
1232
+ if (before === undefined || !matches(before, news)) {
1233
+ yield* runPve(news.target, "provision", true, access.putAccessAcl(bind(news)));
1234
+ }
1235
+ const after = yield* readAttributes(news);
1236
+ if (after === undefined || !after.bound) {
1237
+ return yield* Effect6.die(new Error(`access/acl: the write returned no error but ${identity(news)} is still not ` + "bound. Either the PUT did nothing, or the read credential cannot see the " + "grant -- GET /access/acl is filtered to paths you may MODIFY permissions on, " + "so a read-only role is answered [] rather than 403."));
1329
1238
  }
1330
1239
  return after;
1331
1240
  }),
1332
- delete: Effect8.fn(function* ({ olds }) {
1333
- const removal = { delete: "1", ...tuple(olds) };
1334
- yield* pve(olds.target, "provision", "PUT", "access/acl", removal);
1241
+ delete: Effect6.fn(function* ({ olds }) {
1242
+ const removal = { ...tuple(olds), delete: "1" };
1243
+ yield* runPve(olds.target, "provision", true, access.putAccessAcl(removal));
1335
1244
  })
1336
1245
  })));
1337
1246
  // src/proxmox/alertmanager-body.ts
@@ -1387,7 +1296,7 @@ var alertmanagerAlertBody = (options = {}) => {
1387
1296
  // src/proxmox/api-token.ts
1388
1297
  import { Resource as Resource2 } from "alchemy";
1389
1298
  import * as Provider2 from "alchemy/Provider";
1390
- import * as Effect9 from "effect/Effect";
1299
+ import * as Effect10 from "effect/Effect";
1391
1300
 
1392
1301
  // src/proxmox/values.ts
1393
1302
  var num = (value, fallback) => typeof value === "number" ? value : fallback;
@@ -1464,26 +1373,171 @@ var apiTokenSpec = {
1464
1373
  updateForm: shape
1465
1374
  };
1466
1375
 
1376
+ // src/proxmox/resource.ts
1377
+ import { isResolved as isResolved2 } from "alchemy/Diff";
1378
+ import * as Effect9 from "effect/Effect";
1379
+
1380
+ // src/proxmox/client.ts
1381
+ import * as Effect7 from "effect/Effect";
1382
+ import * as HttpClient5 from "effect/unstable/http/HttpClient";
1383
+ import * as HttpClientRequest2 from "effect/unstable/http/HttpClientRequest";
1384
+ class PveError extends Error {
1385
+ status;
1386
+ method;
1387
+ path;
1388
+ constructor(status, method, path, detail) {
1389
+ super(`PVE ${method} ${path} -> ${String(status)}: ${detail}`);
1390
+ this.status = status;
1391
+ this.method = method;
1392
+ this.path = path;
1393
+ this.name = "PveError";
1394
+ }
1395
+ }
1396
+ var clusterExhausted = (method, path, attempts) => new PveError(0, method, path, `all members failed: ${attempts.map((a) => `${a.member} (${a.why})`).join("; ")}`);
1397
+ var encode = (form) => {
1398
+ const params = new URLSearchParams;
1399
+ for (const [key, value] of Object.entries(form)) {
1400
+ if (typeof value === "string")
1401
+ params.append(key, value);
1402
+ else
1403
+ for (const item of value)
1404
+ params.append(key, item);
1405
+ }
1406
+ return params.toString();
1407
+ };
1408
+ var buildRequest = (method, apiBase, path, credential, target, form) => {
1409
+ const url = `${apiBase}/${path}`;
1410
+ return HttpClientRequest2.make(method)(url).pipe(HttpClientRequest2.setHeaders({ Authorization: authorization(credential, target) }), form === undefined ? (self) => self : HttpClientRequest2.bodyText(encode(form), "application/x-www-form-urlencoded"));
1411
+ };
1412
+ var executeOne = (target, credential, method, path, form, apiBase) => Effect7.gen(function* () {
1413
+ const client = yield* HttpClient5.HttpClient;
1414
+ const request = buildRequest(method, apiBase, path, credential, target, form);
1415
+ return yield* client.execute(request).pipe(Effect7.mapError((cause) => new PveError(0, method, path, String(cause))));
1416
+ });
1417
+ var readResponse = (response, method, path) => Effect7.gen(function* () {
1418
+ if (response.status < 200 || response.status >= 300) {
1419
+ const detail = yield* response.text.pipe(Effect7.orElseSucceed(() => ""));
1420
+ return yield* Effect7.fail(new PveError(response.status, method, path, detail.slice(0, 300)));
1421
+ }
1422
+ const body = yield* response.json.pipe(Effect7.mapError((cause) => new PveError(0, method, path, String(cause))));
1423
+ return body.data;
1424
+ });
1425
+ var pveWith = (target, credential, method, path, form) => Effect7.gen(function* () {
1426
+ const response = target.scheme === "pve" ? yield* executeOnCluster(target, method, path, (apiBase) => buildRequest(method, apiBase, path, credential, target, form)).pipe(Effect7.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);
1427
+ return yield* readResponse(response, method, path);
1428
+ });
1429
+ var pveEnvelopeWith = (target, credential, method, path) => Effect7.gen(function* () {
1430
+ const response = yield* executeOnCluster(target, method, path, (apiBase) => buildRequest(method, apiBase, path, credential, target)).pipe(Effect7.mapError((failure) => failure.tag === "cluster" ? clusterExhausted(failure.method, failure.path, failure.attempts) : new PveError(0, method, path, String(failure))));
1431
+ if (response.status < 200 || response.status >= 300) {
1432
+ const detail = yield* response.text.pipe(Effect7.orElseSucceed(() => ""));
1433
+ return yield* Effect7.fail(new PveError(response.status, method, path, detail.slice(0, 300)));
1434
+ }
1435
+ return yield* response.json.pipe(Effect7.mapError((cause) => new PveError(0, method, path, String(cause))));
1436
+ });
1437
+ var pve = (target, role, method, path, form) => Effect7.gen(function* () {
1438
+ const credential = yield* leased(target, role);
1439
+ return yield* pveWith(target, credential, method, path, form);
1440
+ });
1441
+
1442
+ // src/proxmox/resource-guard.ts
1443
+ import * as Effect8 from "effect/Effect";
1444
+ var specGuards = (spec) => {
1445
+ const endpointsOf = (props) => typeof spec.endpoint === "function" ? spec.endpoint(props) : spec.endpoint;
1446
+ const guardCreate = (props, presence) => Effect8.suspend(() => {
1447
+ const create = endpointsOf(props)?.create;
1448
+ return create === undefined ? Effect8.void : guardForm(create, spec.createForm(props), presence);
1449
+ });
1450
+ const guardUpdate = (props) => Effect8.suspend(() => {
1451
+ const update = endpointsOf(props)?.update;
1452
+ if (update === undefined)
1453
+ return Effect8.void;
1454
+ const form = spec.updateForm?.(props);
1455
+ return form === undefined ? Effect8.void : guardForm(update, form, false);
1456
+ });
1457
+ return { guardCreate, guardUpdate };
1458
+ };
1459
+
1460
+ // src/proxmox/update-guard.ts
1461
+ var formToSend = (matches2, live, props, form) => matches2(live, props) || Object.keys(form).length === 0 ? undefined : form;
1462
+
1463
+ // src/proxmox/resource.ts
1464
+ var pveOperations = (spec) => {
1465
+ const { guardCreate, guardUpdate } = specGuards(spec);
1466
+ const read = (props) => pve(props.target, spec.readRole ?? "read", "GET", spec.path(props)).pipe(Effect9.map((data) => data == null ? undefined : spec.attributes(data, props)), Effect9.orElseSucceed(() => {
1467
+ return;
1468
+ }));
1469
+ return {
1470
+ guardCreate,
1471
+ guardUpdate,
1472
+ read,
1473
+ diff: (news, output) => Effect9.gen(function* () {
1474
+ if (!isResolved2(news))
1475
+ return;
1476
+ yield* guardCreate(news, output === undefined);
1477
+ yield* guardUpdate(news);
1478
+ if (output === undefined)
1479
+ return;
1480
+ const live = yield* read(news);
1481
+ if (live === undefined) {
1482
+ yield* guardCreate(news, true);
1483
+ return { action: "update" };
1484
+ }
1485
+ if (spec.matches(live, news))
1486
+ return { action: "noop" };
1487
+ return spec.updateForm === undefined ? { action: "replace" } : { action: "update" };
1488
+ }),
1489
+ reconcile: (news) => Effect9.gen(function* () {
1490
+ const live = yield* read(news);
1491
+ yield* guardCreate(news, live === undefined);
1492
+ yield* guardUpdate(news);
1493
+ if (live === undefined) {
1494
+ yield* pve(news.target, "provision", "POST", spec.collection(news), spec.createForm(news));
1495
+ } else if (spec.updateForm !== undefined) {
1496
+ const form = formToSend(spec.matches, live, news, spec.updateForm(news));
1497
+ if (form !== undefined) {
1498
+ yield* pve(news.target, "provision", "PUT", spec.path(news), form);
1499
+ }
1500
+ }
1501
+ const after = yield* read(news);
1502
+ if (after === undefined) {
1503
+ return yield* Effect9.die(new Error(`${spec.path(news)}: the write returned no error but the object 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."));
1504
+ }
1505
+ return after;
1506
+ }),
1507
+ destroy: (olds) => pve(olds.target, "provision", "DELETE", spec.path(olds))
1508
+ };
1509
+ };
1510
+ var pveHandlers = (spec) => {
1511
+ const ops = pveOperations(spec);
1512
+ return {
1513
+ list: () => Effect9.succeed([]),
1514
+ read: ({ olds }) => ops.read(olds),
1515
+ diff: ({ news, output }) => ops.diff(news, output),
1516
+ reconcile: ({ news }) => ops.reconcile(news),
1517
+ delete: ({ olds }) => ops.destroy(olds)
1518
+ };
1519
+ };
1520
+
1467
1521
  // src/proxmox/api-token.ts
1468
1522
  var ProxmoxApiToken = Resource2("Proxmox.ApiToken", {
1469
1523
  defaultRemovalPolicy: "retain"
1470
1524
  });
1471
- var ops2 = pveOperations(apiTokenSpec);
1525
+ var ops = pveOperations(apiTokenSpec);
1472
1526
  var handlers = {
1473
1527
  ...pveHandlers(apiTokenSpec),
1474
- reconcile: Effect9.fn(function* ({ news }) {
1475
- const live = yield* ops2.read(news);
1528
+ reconcile: Effect10.fn(function* ({ news }) {
1529
+ const live = yield* ops.read(news);
1476
1530
  if (live === undefined) {
1477
- return yield* Effect9.die(new Error(`${news.userid}!${news.tokenid}: this resource does not create API tokens. PVE returns ` + "the secret only in the create response and it cannot be stored, so a token made here " + "would be a live credential nobody holds. Create it with `pveum user token add` and " + "capture the value, or mint a short-lived one from the OpenBao proxmox mount " + "(`bao read proxmox-c1/creds/<role>`) -- then declare it here to manage it."));
1531
+ return yield* Effect10.die(new Error(`${news.userid}!${news.tokenid}: this resource does not create API tokens. PVE returns ` + "the secret only in the create response and it cannot be stored, so a token made here " + "would be a live credential nobody holds. Create it with `pveum user token add` and " + "capture the value, or mint a short-lived one from the OpenBao proxmox mount " + "(`bao read proxmox-c1/creds/<role>`) -- then declare it here to manage it."));
1478
1532
  }
1479
- return yield* ops2.reconcile(news);
1533
+ return yield* ops.reconcile(news);
1480
1534
  })
1481
1535
  };
1482
- var ProxmoxApiTokenProvider = () => Provider2.effect(ProxmoxApiToken, Effect9.succeed(ProxmoxApiToken.Provider.of(handlers)));
1536
+ var ProxmoxApiTokenProvider = () => Provider2.effect(ProxmoxApiToken, Effect10.succeed(ProxmoxApiToken.Provider.of(handlers)));
1483
1537
  // src/proxmox/backup-job.ts
1484
1538
  import { Resource as Resource3 } from "alchemy";
1485
1539
  import * as Provider3 from "alchemy/Provider";
1486
- import * as Effect10 from "effect/Effect";
1540
+ import * as Effect11 from "effect/Effect";
1487
1541
  var ProxmoxBackupJob = Resource3("Proxmox.BackupJob");
1488
1542
  var shape2 = (props) => ({
1489
1543
  all: props.all === true ? "1" : "0",
@@ -1527,11 +1581,11 @@ var handlers2 = pveHandlers({
1527
1581
  path: (props) => `cluster/backup/${props.id}`,
1528
1582
  updateForm: shape2
1529
1583
  });
1530
- var ProxmoxBackupJobProvider = () => Provider3.effect(ProxmoxBackupJob, Effect10.succeed(ProxmoxBackupJob.Provider.of(handlers2)));
1584
+ var ProxmoxBackupJobProvider = () => Provider3.effect(ProxmoxBackupJob, Effect11.succeed(ProxmoxBackupJob.Provider.of(handlers2)));
1531
1585
  // src/proxmox/ceph-daemon.ts
1532
1586
  import { Resource as Resource4 } from "alchemy";
1533
1587
  import * as Provider4 from "alchemy/Provider";
1534
- import * as Effect11 from "effect/Effect";
1588
+ import * as Effect12 from "effect/Effect";
1535
1589
 
1536
1590
  // src/proxmox/ceph-daemon-form.ts
1537
1591
  var DAEMON_ENDPOINTS = {
@@ -1582,14 +1636,14 @@ var handlers3 = pveHandlers({
1582
1636
  matches: () => true,
1583
1637
  path: collectionPath
1584
1638
  });
1585
- var ProxmoxCephDaemonProvider = () => Provider4.effect(ProxmoxCephDaemon, Effect11.succeed(ProxmoxCephDaemon.Provider.of({
1639
+ var ProxmoxCephDaemonProvider = () => Provider4.effect(ProxmoxCephDaemon, Effect12.succeed(ProxmoxCephDaemon.Provider.of({
1586
1640
  ...handlers3,
1587
1641
  delete: ({ olds }) => pve(olds.target, "provision", "DELETE", daemonPath(olds))
1588
1642
  })));
1589
1643
  // src/proxmox/ceph-flag.ts
1590
1644
  import { Resource as Resource5 } from "alchemy";
1591
1645
  import * as Provider5 from "alchemy/Provider";
1592
- import * as Effect12 from "effect/Effect";
1646
+ import * as Effect13 from "effect/Effect";
1593
1647
  var ProxmoxCephFlag = Resource5("Proxmox.CephFlag");
1594
1648
  var handlers4 = pveHandlers({
1595
1649
  attributes: (live, props) => ({ flag: props.flag, value: bool(live) }),
@@ -1600,13 +1654,13 @@ var handlers4 = pveHandlers({
1600
1654
  path: (props) => `cluster/ceph/flags/${props.flag}`,
1601
1655
  updateForm: (props) => ({ value: flag(props.value) ?? "0" })
1602
1656
  });
1603
- var ProxmoxCephFlagProvider = () => Provider5.effect(ProxmoxCephFlag, Effect12.succeed(ProxmoxCephFlag.Provider.of({
1657
+ var ProxmoxCephFlagProvider = () => Provider5.effect(ProxmoxCephFlag, Effect13.succeed(ProxmoxCephFlag.Provider.of({
1604
1658
  ...handlers4,
1605
- delete: () => Effect12.void,
1606
- reconcile: Effect12.fn(function* ({ news }) {
1659
+ delete: () => Effect13.void,
1660
+ reconcile: Effect13.fn(function* ({ news }) {
1607
1661
  const after = yield* handlers4.reconcile({ news });
1608
1662
  if (after.value !== news.value) {
1609
- return yield* Effect12.die(new Error(`cluster/ceph/flags/${news.flag}: the PUT returned no error but ceph still ` + `reports the flag ${after.value ? "set" : "clear"} rather than ` + `${news.value ? "set" : "clear"}. This endpoint's success is documented as a ` + "null body, so the status code proves nothing -- check `ceph osd dump | " + "head -1` and the cluster log. `pause` in particular is two ceph flags read " + "as one; see the header."));
1663
+ return yield* Effect13.die(new Error(`cluster/ceph/flags/${news.flag}: the PUT returned no error but ceph still ` + `reports the flag ${after.value ? "set" : "clear"} rather than ` + `${news.value ? "set" : "clear"}. This endpoint's success is documented as a ` + "null body, so the status code proves nothing -- check `ceph osd dump | " + "head -1` and the cluster log. `pause` in particular is two ceph flags read " + "as one; see the header."));
1610
1664
  }
1611
1665
  return after;
1612
1666
  })
@@ -1615,10 +1669,10 @@ var ProxmoxCephFlagProvider = () => Provider5.effect(ProxmoxCephFlag, Effect12.s
1615
1669
  import { Resource as Resource6 } from "alchemy";
1616
1670
  import { isResolved as isResolved3 } from "alchemy/Diff";
1617
1671
  import * as Provider6 from "alchemy/Provider";
1618
- import * as Effect14 from "effect/Effect";
1672
+ import * as Effect15 from "effect/Effect";
1619
1673
 
1620
1674
  // src/proxmox/ceph-fs-wire.ts
1621
- import * as Effect13 from "effect/Effect";
1675
+ import * as Effect14 from "effect/Effect";
1622
1676
  var readRow = (live, props) => {
1623
1677
  const row = (Array.isArray(live) ? live : []).filter((entry) => typeof entry === "object" && entry !== null).find((entry) => entry["name"] === props.name);
1624
1678
  if (row === undefined)
@@ -1646,29 +1700,29 @@ var destroyPath = (props) => {
1646
1700
  ].filter((part) => part !== undefined);
1647
1701
  return query.length === 0 ? objectPath(props) : `${objectPath(props)}?${query.join("&")}`;
1648
1702
  };
1649
- var settle = (target, node, upid, what) => Effect13.gen(function* () {
1703
+ var settle = (target, node, upid, what) => Effect14.gen(function* () {
1650
1704
  for (let attempt = 0;attempt < POLL_ATTEMPTS; attempt += 1) {
1651
- const status = yield* pve(target, "read", "GET", `nodes/${node}/tasks/${encodeURIComponent(upid)}/status`).pipe(Effect13.orElseSucceed(() => {
1705
+ const status = yield* pve(target, "read", "GET", `nodes/${node}/tasks/${encodeURIComponent(upid)}/status`).pipe(Effect14.orElseSucceed(() => {
1652
1706
  return;
1653
1707
  }));
1654
1708
  if (status?.status === "stopped") {
1655
1709
  const exit = text(status.exitstatus);
1656
1710
  if (exit === "OK")
1657
1711
  return;
1658
- return yield* Effect13.die(new Error(`${what}: PVE task ${upid} finished with "${exit === "" ? "no exit status" : exit}". ` + "The write returned HTTP 200 because it only forked the worker -- the real error is " + `in \`pvesh get /nodes/${node}/tasks/${upid}/log\`.`));
1712
+ return yield* Effect14.die(new Error(`${what}: PVE task ${upid} finished with "${exit === "" ? "no exit status" : exit}". ` + "The write returned HTTP 200 because it only forked the worker -- the real error is " + `in \`pvesh get /nodes/${node}/tasks/${upid}/log\`.`));
1659
1713
  }
1660
- yield* Effect13.sleep(POLL_SECONDS * 1000);
1714
+ yield* Effect14.sleep(POLL_SECONDS * 1000);
1661
1715
  }
1662
- return yield* Effect13.die(new Error(`${what}: PVE task ${upid} was still running after ` + `${String(POLL_ATTEMPTS * POLL_SECONDS)}s, or its ` + "status could not be read. Check the task log, and check that the `read` role holds " + `Sys.Audit on /nodes/${node} -- each call mints a new token, so the poller is never the ` + "task owner and is answered 403 rather than told to wait."));
1716
+ return yield* Effect14.die(new Error(`${what}: PVE task ${upid} was still running after ` + `${String(POLL_ATTEMPTS * POLL_SECONDS)}s, or its ` + "status could not be read. Check the task log, and check that the `read` role holds " + `Sys.Audit on /nodes/${node} -- each call mints a new token, so the poller is never the ` + "task owner and is answered 403 rather than told to wait."));
1663
1717
  });
1664
- var createFs = (props) => Effect13.gen(function* () {
1718
+ var createFs = (props) => Effect14.gen(function* () {
1665
1719
  const upid = text(yield* pve(props.target, "provision", "POST", objectPath(props), createForm2(props)));
1666
1720
  if (upid === "") {
1667
- return yield* Effect13.die(new Error(`${objectPath(props)}: POST returned no task id. PVE wraps every answer in ` + '{"data":...} and can report success on a call that did nothing.'));
1721
+ return yield* Effect14.die(new Error(`${objectPath(props)}: POST returned no task id. PVE wraps every answer in ` + '{"data":...} and can report success on a call that did nothing.'));
1668
1722
  }
1669
1723
  yield* settle(props.target, props.node, upid, objectPath(props));
1670
1724
  });
1671
- var destroyFs = (props) => Effect13.gen(function* () {
1725
+ var destroyFs = (props) => Effect14.gen(function* () {
1672
1726
  const upid = text(yield* pve(props.target, "provision", "DELETE", destroyPath(props)));
1673
1727
  if (upid !== "")
1674
1728
  yield* settle(props.target, props.node, upid, destroyPath(props));
@@ -1680,7 +1734,7 @@ var notDestroyed = (props) => new Error(`${objectPath(props)}: the destroy task
1680
1734
  var ProxmoxCephFs = Resource6("Proxmox.CephFs", {
1681
1735
  defaultRemovalPolicy: "retain"
1682
1736
  });
1683
- var ops3 = pveOperations({
1737
+ var ops2 = pveOperations({
1684
1738
  attributes: readRow,
1685
1739
  collection: objectPath,
1686
1740
  createForm: createForm2,
@@ -1688,44 +1742,44 @@ var ops3 = pveOperations({
1688
1742
  matches: () => true,
1689
1743
  path: (props) => `nodes/${props.node}/ceph/fs`
1690
1744
  });
1691
- var ProxmoxCephFsProvider = () => Provider6.effect(ProxmoxCephFs, Effect14.succeed(ProxmoxCephFs.Provider.of({
1692
- list: () => Effect14.succeed([]),
1693
- read: Effect14.fn(function* ({ olds }) {
1694
- return yield* ops3.read(olds);
1745
+ var ProxmoxCephFsProvider = () => Provider6.effect(ProxmoxCephFs, Effect15.succeed(ProxmoxCephFs.Provider.of({
1746
+ list: () => Effect15.succeed([]),
1747
+ read: Effect15.fn(function* ({ olds }) {
1748
+ return yield* ops2.read(olds);
1695
1749
  }),
1696
- diff: Effect14.fn(function* ({ news, output }) {
1750
+ diff: Effect15.fn(function* ({ news, output }) {
1697
1751
  if (output !== undefined && isResolved3(news) && news.name !== output.name) {
1698
1752
  return { action: "replace" };
1699
1753
  }
1700
- return yield* ops3.diff(news, output);
1754
+ return yield* ops2.diff(news, output);
1701
1755
  }),
1702
- reconcile: Effect14.fn(function* ({ news }) {
1703
- const live = yield* ops3.read(news);
1756
+ reconcile: Effect15.fn(function* ({ news }) {
1757
+ const live = yield* ops2.read(news);
1704
1758
  if (live !== undefined)
1705
1759
  return live;
1706
1760
  yield* createFs(news);
1707
- const after = yield* ops3.read(news);
1761
+ const after = yield* ops2.read(news);
1708
1762
  if (after === undefined)
1709
- return yield* Effect14.die(notCreated(news));
1763
+ return yield* Effect15.die(notCreated(news));
1710
1764
  return after;
1711
1765
  }),
1712
- delete: Effect14.fn(function* ({ olds }) {
1713
- if ((yield* ops3.read(olds)) === undefined)
1766
+ delete: Effect15.fn(function* ({ olds }) {
1767
+ if ((yield* ops2.read(olds)) === undefined)
1714
1768
  return;
1715
1769
  yield* destroyFs(olds);
1716
- const after = yield* ops3.read(olds);
1770
+ const after = yield* ops2.read(olds);
1717
1771
  if (after !== undefined)
1718
- return yield* Effect14.die(notDestroyed(olds));
1772
+ return yield* Effect15.die(notDestroyed(olds));
1719
1773
  })
1720
1774
  })));
1721
1775
  // src/proxmox/ceph-osd.ts
1722
1776
  import { Resource as Resource7 } from "alchemy";
1723
1777
  import { isResolved as isResolved4 } from "alchemy/Diff";
1724
1778
  import * as Provider7 from "alchemy/Provider";
1725
- import * as Effect17 from "effect/Effect";
1779
+ import * as Effect18 from "effect/Effect";
1726
1780
 
1727
1781
  // src/proxmox/ceph-osd-tree.ts
1728
- import * as Effect15 from "effect/Effect";
1782
+ import * as Effect16 from "effect/Effect";
1729
1783
  var branches = (node) => (Array.isArray(node["children"]) ? node["children"] : []).filter((child) => typeof child === "object" && child !== null);
1730
1784
  var osdLeaves = (tree) => {
1731
1785
  const root = tree["root"];
@@ -1751,29 +1805,29 @@ var osdAttributes = (leaf, props) => ({
1751
1805
  status: text(leaf["status"]),
1752
1806
  total_space: num(leaf["total_space"], 0)
1753
1807
  });
1754
- var readOsd = (props) => pve(props.target, "read", "GET", `nodes/${props.node}/ceph/osd`).pipe(Effect15.map((t) => {
1808
+ var readOsd = (props) => pve(props.target, "read", "GET", `nodes/${props.node}/ceph/osd`).pipe(Effect16.map((t) => {
1755
1809
  const leaf = t === undefined ? undefined : findOsd(t, props.osdid);
1756
1810
  return leaf === undefined ? undefined : osdAttributes(leaf, props);
1757
1811
  }));
1758
1812
 
1759
1813
  // src/proxmox/ceph-osd-write.ts
1760
- import * as Effect16 from "effect/Effect";
1814
+ import * as Effect17 from "effect/Effect";
1761
1815
  var OSD_CREATE_ENDPOINT = "pve:POST /nodes/{node}/ceph/osd";
1762
1816
  var describe = (props) => `osd.${String(props.osdid)} on ${props.node}`;
1763
1817
  var createOsdForm = (props, dev) => ({
1764
1818
  dev,
1765
1819
  ...props.device_class === undefined ? {} : { "crush-device-class": props.device_class }
1766
1820
  });
1767
- var createOsd = Effect16.fn(function* (news) {
1821
+ var createOsd = Effect17.fn(function* (news) {
1768
1822
  if (news.dev === undefined) {
1769
- return yield* Effect16.die(new Error(`${describe(news)}: no such OSD in the CRUSH tree, and no \`dev\` was declared. ` + "Without a device this resource is an ASSERTION over an OSD that must already " + "exist. Declare `dev` to let it create one -- which WIPES that device -- or fix " + "the declaration; if the disk was there yesterday, a replica is missing and Ceph " + "is degraded."));
1823
+ return yield* Effect17.die(new Error(`${describe(news)}: no such OSD in the CRUSH tree, and no \`dev\` was declared. ` + "Without a device this resource is an ASSERTION over an OSD that must already " + "exist. Declare `dev` to let it create one -- which WIPES that device -- or fix " + "the declaration; if the disk was there yesterday, a replica is missing and Ceph " + "is degraded."));
1770
1824
  }
1771
1825
  const form = createOsdForm(news, news.dev);
1772
1826
  yield* guardForm(OSD_CREATE_ENDPOINT, form, true);
1773
1827
  yield* pve(news.target, "provision", "POST", `nodes/${news.node}/ceph/osd`, form);
1774
1828
  const created = yield* readOsd(news);
1775
1829
  if (created === undefined) {
1776
- return yield* Effect16.die(new Error(`${describe(news)}: the create returned no error but osd.${String(news.osdid)} is ` + "still absent. Ceph allocates OSD ids and cannot be told which to use, so it most " + "likely assigned a different number -- check `ceph osd tree`, and declare the id it " + "actually gave the device rather than deploying again."));
1830
+ return yield* Effect17.die(new Error(`${describe(news)}: the create returned no error but osd.${String(news.osdid)} is ` + "still absent. Ceph allocates OSD ids and cannot be told which to use, so it most " + "likely assigned a different number -- check `ceph osd tree`, and declare the id it " + "actually gave the device rather than deploying again."));
1777
1831
  }
1778
1832
  return created;
1779
1833
  });
@@ -1786,11 +1840,11 @@ var ProxmoxCephOsd = Resource7("Proxmox.CephOsd", {
1786
1840
  var settled = (live, props) => (props.host === undefined || props.host === live.host) && (props.device_class === undefined || props.device_class === live.device_class);
1787
1841
  var describe2 = (props) => `osd.${String(props.osdid)} (read via nodes/${props.node}/ceph/osd)`;
1788
1842
  var handlers5 = {
1789
- list: () => Effect17.succeed([]),
1790
- read: Effect17.fn(function* ({ olds }) {
1843
+ list: () => Effect18.succeed([]),
1844
+ read: Effect18.fn(function* ({ olds }) {
1791
1845
  return yield* readOsd(olds);
1792
1846
  }),
1793
- diff: Effect17.fn(function* ({
1847
+ diff: Effect18.fn(function* ({
1794
1848
  news,
1795
1849
  output
1796
1850
  }) {
@@ -1803,25 +1857,25 @@ var handlers5 = {
1803
1857
  return { action: "update" };
1804
1858
  return settled(live, news) ? { action: "noop" } : { action: "update" };
1805
1859
  }),
1806
- reconcile: Effect17.fn(function* ({ news }) {
1860
+ reconcile: Effect18.fn(function* ({ news }) {
1807
1861
  const live = yield* readOsd(news);
1808
1862
  if (live === undefined) {
1809
1863
  return yield* createOsd(news);
1810
1864
  }
1811
1865
  if (!settled(live, news)) {
1812
- return yield* Effect17.die(new Error(`${describe2(news)}: exists but not as declared -- live host=${live.host} ` + `device_class=${live.device_class}. Nothing here moves an OSD between hosts or ` + "reclassifies it; fix the declaration, or move it deliberately with `ceph osd crush " + "move` / `ceph osd crush set-device-class` and deploy again."));
1866
+ return yield* Effect18.die(new Error(`${describe2(news)}: exists but not as declared -- live host=${live.host} ` + `device_class=${live.device_class}. Nothing here moves an OSD between hosts or ` + "reclassifies it; fix the declaration, or move it deliberately with `ceph osd crush " + "move` / `ceph osd crush set-device-class` and deploy again."));
1813
1867
  }
1814
1868
  return live;
1815
1869
  }),
1816
- delete: Effect17.fn(function* ({ olds }) {
1870
+ delete: Effect18.fn(function* ({ olds }) {
1817
1871
  yield* destroyOsd(olds);
1818
1872
  })
1819
1873
  };
1820
- var ProxmoxCephOsdProvider = () => Provider7.effect(ProxmoxCephOsd, Effect17.succeed(ProxmoxCephOsd.Provider.of(handlers5)));
1874
+ var ProxmoxCephOsdProvider = () => Provider7.effect(ProxmoxCephOsd, Effect18.succeed(ProxmoxCephOsd.Provider.of(handlers5)));
1821
1875
  // src/proxmox/ceph-pool.ts
1822
1876
  import { Resource as Resource8 } from "alchemy";
1823
1877
  import * as Provider8 from "alchemy/Provider";
1824
- import * as Effect19 from "effect/Effect";
1878
+ import * as Effect20 from "effect/Effect";
1825
1879
 
1826
1880
  // src/proxmox/ceph-pool-form.ts
1827
1881
  var object = (props) => `nodes/${props.node}/ceph/pool/${props.name}`;
@@ -1850,14 +1904,14 @@ var createBody = (props) => ({
1850
1904
  });
1851
1905
 
1852
1906
  // src/proxmox/ceph-pool-settle.ts
1853
- import * as Effect18 from "effect/Effect";
1854
- var confirmAbsent = (props, collection2, describe3) => pve(props.target, "read", "GET", collection2).pipe(Effect18.flatMap((rows) => (rows ?? []).some((row) => row.pool_name === props.name) ? Effect18.die(new Error(`${describe3}: the cluster lists this pool but its status could not be read, ` + "so this deploy will NOT create over it. Check that the node is up and that the " + "read role holds Sys.Audit or Datastore.Audit on / -- a create here would apply " + "pg_num to a live pool and start a PG merge.")) : Effect18.void));
1855
- var settle2 = (props, read, done) => Effect18.gen(function* () {
1907
+ import * as Effect19 from "effect/Effect";
1908
+ var confirmAbsent = (props, collection2, describe3) => pve(props.target, "read", "GET", collection2).pipe(Effect19.flatMap((rows) => (rows ?? []).some((row) => row.pool_name === props.name) ? Effect19.die(new Error(`${describe3}: the cluster lists this pool but its status could not be read, ` + "so this deploy will NOT create over it. Check that the node is up and that the " + "read role holds Sys.Audit or Datastore.Audit on / -- a create here would apply " + "pg_num to a live pool and start a PG merge.")) : Effect19.void));
1909
+ var settle2 = (props, read, done) => Effect19.gen(function* () {
1856
1910
  for (let attempt = 0;attempt < 30; attempt += 1) {
1857
1911
  const live = yield* read(props);
1858
1912
  if (done(live))
1859
1913
  return live;
1860
- yield* Effect18.sleep("2 seconds");
1914
+ yield* Effect19.sleep("2 seconds");
1861
1915
  }
1862
1916
  return yield* read(props);
1863
1917
  });
@@ -1898,36 +1952,36 @@ var spec = {
1898
1952
  path: (props) => `${object(props)}/status?verbose=1`,
1899
1953
  updateForm: updateBody
1900
1954
  };
1901
- var ops4 = pveOperations(spec);
1902
- var ProxmoxCephPoolProvider = () => Provider8.effect(ProxmoxCephPool, Effect19.succeed(ProxmoxCephPool.Provider.of({
1903
- list: () => Effect19.succeed([]),
1904
- read: ({ olds }) => ops4.read(olds),
1905
- diff: ({ news, output }) => ops4.diff(news, output),
1906
- reconcile: Effect19.fn(function* ({ news }) {
1907
- const live = yield* ops4.read(news);
1955
+ var ops3 = pveOperations(spec);
1956
+ var ProxmoxCephPoolProvider = () => Provider8.effect(ProxmoxCephPool, Effect20.succeed(ProxmoxCephPool.Provider.of({
1957
+ list: () => Effect20.succeed([]),
1958
+ read: ({ olds }) => ops3.read(olds),
1959
+ diff: ({ news, output }) => ops3.diff(news, output),
1960
+ reconcile: Effect20.fn(function* ({ news }) {
1961
+ const live = yield* ops3.read(news);
1908
1962
  let upid;
1909
1963
  if (live === undefined) {
1910
- yield* ops4.guardCreate(news, true);
1964
+ yield* ops3.guardCreate(news, true);
1911
1965
  yield* confirmAbsent(news, spec.collection(news), object(news));
1912
1966
  upid = yield* pve(news.target, "provision", "POST", collection(news), createBody(news));
1913
1967
  } else {
1914
1968
  const form = formToSend(spec.matches, live, news, updateBody(news));
1915
1969
  if (form !== undefined) {
1916
- yield* ops4.guardUpdate(news);
1970
+ yield* ops3.guardUpdate(news);
1917
1971
  upid = yield* pve(news.target, "provision", "PUT", object(news), form);
1918
1972
  }
1919
1973
  }
1920
- const after = yield* settle2(news, ops4.read, (row) => row !== undefined && spec.matches(row, news));
1974
+ const after = yield* settle2(news, ops3.read, (row) => row !== undefined && spec.matches(row, news));
1921
1975
  if (after === undefined || !spec.matches(after, news)) {
1922
- return yield* Effect19.die(new Error(`${object(news)}: the write returned no error but the pool still does not match ` + `the declaration after 60s. PVE answered with task ${upid ?? "(none)"} -- read ` + "its log with `pvesh get /nodes/<node>/tasks/<upid>/log` to see what Ceph " + "refused."));
1976
+ return yield* Effect20.die(new Error(`${object(news)}: the write returned no error but the pool still does not match ` + `the declaration after 60s. PVE answered with task ${upid ?? "(none)"} -- read ` + "its log with `pvesh get /nodes/<node>/tasks/<upid>/log` to see what Ceph " + "refused."));
1923
1977
  }
1924
1978
  return after;
1925
1979
  }),
1926
- delete: Effect19.fn(function* ({ olds }) {
1980
+ delete: Effect20.fn(function* ({ olds }) {
1927
1981
  yield* pve(olds.target, "provision", "DELETE", object(olds));
1928
- const left = yield* settle2(olds, ops4.read, (row) => row === undefined);
1982
+ const left = yield* settle2(olds, ops3.read, (row) => row === undefined);
1929
1983
  if (left !== undefined) {
1930
- return yield* Effect19.die(new Error(`${object(olds)}: the DELETE returned no error but the pool is still there after ` + "60s. Either a storage on it still holds RBD images, or the mons are running " + "with mon_allow_pool_delete false."));
1984
+ return yield* Effect20.die(new Error(`${object(olds)}: the DELETE returned no error but the pool is still there after ` + "60s. Either a storage on it still holds RBD images, or the mons are running " + "with mon_allow_pool_delete false."));
1931
1985
  }
1932
1986
  })
1933
1987
  })));
@@ -1935,7 +1989,7 @@ var ProxmoxCephPoolProvider = () => Provider8.effect(ProxmoxCephPool, Effect19.s
1935
1989
  import { Resource as Resource9 } from "alchemy";
1936
1990
  import { isResolved as isResolved5 } from "alchemy/Diff";
1937
1991
  import * as Provider9 from "alchemy/Provider";
1938
- import * as Effect20 from "effect/Effect";
1992
+ import * as Effect21 from "effect/Effect";
1939
1993
 
1940
1994
  // src/proxmox/firewall-alias-form.ts
1941
1995
  var fold = (name) => name.trim().toLowerCase();
@@ -1975,9 +2029,9 @@ var handlers6 = pveHandlers({
1975
2029
  path: (props) => `cluster/firewall/aliases/${props.name}`,
1976
2030
  updateForm: body
1977
2031
  });
1978
- var ProxmoxFirewallAliasProvider = () => Provider9.effect(ProxmoxFirewallAlias, Effect20.succeed(ProxmoxFirewallAlias.Provider.of({
2032
+ var ProxmoxFirewallAliasProvider = () => Provider9.effect(ProxmoxFirewallAlias, Effect21.succeed(ProxmoxFirewallAlias.Provider.of({
1979
2033
  ...handlers6,
1980
- diff: Effect20.fn(function* ({ news, output }) {
2034
+ diff: Effect21.fn(function* ({ news, output }) {
1981
2035
  if (output !== undefined && isResolved5(news) && fold(news.name) !== fold(output.name)) {
1982
2036
  return { action: "replace" };
1983
2037
  }
@@ -1987,7 +2041,7 @@ var ProxmoxFirewallAliasProvider = () => Provider9.effect(ProxmoxFirewallAlias,
1987
2041
  // src/proxmox/group.ts
1988
2042
  import { Resource as Resource10 } from "alchemy";
1989
2043
  import * as Provider10 from "alchemy/Provider";
1990
- import * as Effect21 from "effect/Effect";
2044
+ import * as Effect22 from "effect/Effect";
1991
2045
  var ProxmoxGroup = Resource10("Proxmox.Group", {
1992
2046
  defaultRemovalPolicy: "retain"
1993
2047
  });
@@ -2012,11 +2066,11 @@ var handlers7 = pveHandlers({
2012
2066
  path: (props) => `access/groups/${props.groupid}`,
2013
2067
  updateForm: (props) => ({ comment: storedComment(props.comment) })
2014
2068
  });
2015
- var ProxmoxGroupProvider = () => Provider10.effect(ProxmoxGroup, Effect21.succeed(ProxmoxGroup.Provider.of(handlers7)));
2069
+ var ProxmoxGroupProvider = () => Provider10.effect(ProxmoxGroup, Effect22.succeed(ProxmoxGroup.Provider.of(handlers7)));
2016
2070
  // src/proxmox/ha-resource.ts
2017
2071
  import { Resource as Resource11 } from "alchemy";
2018
2072
  import * as Provider11 from "alchemy/Provider";
2019
- import * as Effect22 from "effect/Effect";
2073
+ import * as Effect23 from "effect/Effect";
2020
2074
  var ProxmoxHaResource = Resource11("Proxmox.HaResource");
2021
2075
  var kind = (sid) => sid.split(":")[0] ?? "";
2022
2076
  var shape3 = (props) => ({
@@ -2044,11 +2098,11 @@ var handlers8 = pveHandlers({
2044
2098
  path: (props) => `cluster/ha/resources/${props.sid}`,
2045
2099
  updateForm: shape3
2046
2100
  });
2047
- var ProxmoxHaResourceProvider = () => Provider11.effect(ProxmoxHaResource, Effect22.succeed(ProxmoxHaResource.Provider.of(handlers8)));
2101
+ var ProxmoxHaResourceProvider = () => Provider11.effect(ProxmoxHaResource, Effect23.succeed(ProxmoxHaResource.Provider.of(handlers8)));
2048
2102
  // src/proxmox/ha-rule.ts
2049
2103
  import { Resource as Resource12 } from "alchemy";
2050
2104
  import * as Provider12 from "alchemy/Provider";
2051
- import * as Effect23 from "effect/Effect";
2105
+ import * as Effect24 from "effect/Effect";
2052
2106
 
2053
2107
  // src/proxmox/ha-rule-form.ts
2054
2108
  var nodeList = (value) => {
@@ -2125,43 +2179,43 @@ var handlers9 = pveHandlers({
2125
2179
  return withClears(fields, clear);
2126
2180
  }
2127
2181
  });
2128
- var ProxmoxHaRuleProvider = () => Provider12.effect(ProxmoxHaRule, Effect23.succeed(ProxmoxHaRule.Provider.of(handlers9)));
2182
+ var ProxmoxHaRuleProvider = () => Provider12.effect(ProxmoxHaRule, Effect24.succeed(ProxmoxHaRule.Provider.of(handlers9)));
2129
2183
  // src/proxmox/lxc.ts
2130
2184
  import { Resource as Resource13 } from "alchemy";
2131
2185
  import { isResolved as isResolved6 } from "alchemy/Diff";
2132
2186
  import * as Provider13 from "alchemy/Provider";
2133
- import * as Effect33 from "effect/Effect";
2187
+ import * as Effect34 from "effect/Effect";
2134
2188
 
2135
2189
  // src/ownership/adopt.ts
2136
2190
  import { AdoptPolicy } from "alchemy/AdoptPolicy";
2137
2191
  import { AlchemyContext } from "alchemy/AlchemyContext";
2138
2192
  import { Stack as Stack3 } from "alchemy/Stack";
2139
- import * as Effect27 from "effect/Effect";
2193
+ import * as Effect28 from "effect/Effect";
2140
2194
  import * as Option5 from "effect/Option";
2141
2195
 
2142
2196
  // src/ownership/resume.ts
2143
2197
  import { Unowned } from "alchemy/AdoptPolicy";
2144
2198
  import { Artifacts } from "alchemy/Artifacts";
2145
- import * as Effect24 from "effect/Effect";
2199
+ import * as Effect25 from "effect/Effect";
2146
2200
  import * as Option2 from "effect/Option";
2147
2201
  var PROVEN = "homeflare/ownership/resumes";
2148
2202
  var UNFINISHED = "homeflare/ownership/unfinished";
2149
- var note = (key, instanceId) => Effect24.gen(function* () {
2150
- const bag = yield* Effect24.serviceOption(Artifacts);
2203
+ var note = (key, instanceId) => Effect25.gen(function* () {
2204
+ const bag = yield* Effect25.serviceOption(Artifacts);
2151
2205
  if (Option2.isSome(bag))
2152
2206
  yield* bag.value.set(key, instanceId);
2153
2207
  });
2154
- var noted = (key, instanceId) => Effect24.gen(function* () {
2155
- const bag = yield* Effect24.serviceOption(Artifacts);
2208
+ var noted = (key, instanceId) => Effect25.gen(function* () {
2209
+ const bag = yield* Effect25.serviceOption(Artifacts);
2156
2210
  if (Option2.isNone(bag))
2157
2211
  return false;
2158
2212
  return (yield* bag.value.get(key)) === instanceId;
2159
2213
  });
2160
- var noteUnfinished = (instanceId) => Effect24.as(note(UNFINISHED, instanceId), undefined);
2161
- var noteResume = (instanceId, recovered) => Effect24.gen(function* () {
2214
+ var noteUnfinished = (instanceId) => Effect25.as(note(UNFINISHED, instanceId), undefined);
2215
+ var noteResume = (instanceId, recovered) => Effect25.gen(function* () {
2162
2216
  yield* noteUnfinished(instanceId);
2163
- const unproven = () => Effect24.succeed(undefined);
2164
- const found = yield* recovered.pipe(Effect24.catch(unproven), Effect24.catchDefect(unproven));
2217
+ const unproven = () => Effect25.succeed(undefined);
2218
+ const found = yield* recovered.pipe(Effect25.catch(unproven), Effect25.catchDefect(unproven));
2165
2219
  if (found === undefined || found === null || Unowned.is(found))
2166
2220
  return;
2167
2221
  yield* note(PROVEN, instanceId);
@@ -2172,7 +2226,7 @@ var provingResumes = (service) => {
2172
2226
  const { diff, read } = service;
2173
2227
  if (diff === undefined || read === undefined)
2174
2228
  return service;
2175
- const proving = (input) => Effect24.gen(function* () {
2229
+ const proving = (input) => Effect25.gen(function* () {
2176
2230
  if (input.output === undefined) {
2177
2231
  yield* noteResume(input.instanceId, read({ ...input, output: undefined }));
2178
2232
  }
@@ -2184,12 +2238,12 @@ var provingResumes = (service) => {
2184
2238
  // src/ownership/rows.ts
2185
2239
  import { Stack as Stack2 } from "alchemy/Stack";
2186
2240
  import { State, isActionState } from "alchemy/State/State";
2187
- import * as Effect26 from "effect/Effect";
2241
+ import * as Effect27 from "effect/Effect";
2188
2242
  import * as Option4 from "effect/Option";
2189
2243
 
2190
2244
  // src/ownership/whole.ts
2191
2245
  import { Stack } from "alchemy/Stack";
2192
- import * as Effect25 from "effect/Effect";
2246
+ import * as Effect26 from "effect/Effect";
2193
2247
  import * as Option3 from "effect/Option";
2194
2248
  var absent = (value) => value === undefined || value === null;
2195
2249
  var isPlainObject = (value) => {
@@ -2215,22 +2269,22 @@ var carries = (declared, recorded) => {
2215
2269
  }
2216
2270
  return true;
2217
2271
  };
2218
- var wholeDeclaration = (fqn, props) => Effect25.map(Effect25.serviceOption(Stack), (stack) => {
2272
+ var wholeDeclaration = (fqn, props) => Effect26.map(Effect26.serviceOption(Stack), (stack) => {
2219
2273
  const declared = Option3.isSome(stack) ? stack.value.resources[fqn] : undefined;
2220
2274
  return declared !== undefined && carries(declared.Props, props);
2221
2275
  });
2222
2276
 
2223
2277
  // src/ownership/rows.ts
2224
- var storeOf = Effect26.gen(function* () {
2225
- const stack = yield* Effect26.serviceOption(Stack2);
2226
- const state = yield* Effect26.serviceOption(State);
2278
+ var storeOf = Effect27.gen(function* () {
2279
+ const stack = yield* Effect27.serviceOption(Stack2);
2280
+ const state = yield* Effect27.serviceOption(State);
2227
2281
  if (Option4.isNone(stack) || Option4.isNone(state))
2228
2282
  return;
2229
2283
  const store = yield* state.value;
2230
2284
  const where = { stack: stack.value.name, stage: stack.value.stage };
2231
2285
  return { resources: stack.value.resources, store, where };
2232
2286
  });
2233
- var rowAt = (store, where, fqn) => store.get({ ...where, fqn }).pipe(Effect26.orElseSucceed(() => {
2287
+ var rowAt = (store, where, fqn) => store.get({ ...where, fqn }).pipe(Effect27.orElseSucceed(() => {
2234
2288
  return;
2235
2289
  }));
2236
2290
  var generationOf = (row, instanceId) => {
@@ -2243,7 +2297,7 @@ var generationOf = (row, instanceId) => {
2243
2297
  }
2244
2298
  return;
2245
2299
  };
2246
- var recordedGeneration = (fqn, instanceId) => Effect26.gen(function* () {
2300
+ var recordedGeneration = (fqn, instanceId) => Effect27.gen(function* () {
2247
2301
  const found = yield* storeOf;
2248
2302
  if (found === undefined)
2249
2303
  return;
@@ -2254,14 +2308,14 @@ var recordedGeneration = (fqn, instanceId) => Effect26.gen(function* () {
2254
2308
  }
2255
2309
  return;
2256
2310
  });
2257
- var recordedInstance = (fqn, instanceId) => Effect26.gen(function* () {
2311
+ var recordedInstance = (fqn, instanceId) => Effect27.gen(function* () {
2258
2312
  const generation = yield* recordedGeneration(fqn, instanceId);
2259
2313
  if (generation === undefined)
2260
2314
  return "absent";
2261
2315
  return (yield* wholeDeclaration(fqn, generation.props)) ? "whole" : "partial";
2262
2316
  });
2263
- var isCreate = (fqn, instanceId) => Effect26.map(recordedGeneration(fqn, instanceId), (generation) => generation?.status === "creating");
2264
- var forgetRefusedCreate = (fqn, instanceId) => Effect26.gen(function* () {
2317
+ var isCreate = (fqn, instanceId) => Effect27.map(recordedGeneration(fqn, instanceId), (generation) => generation?.status === "creating");
2318
+ var forgetRefusedCreate = (fqn, instanceId) => Effect27.gen(function* () {
2265
2319
  const found = yield* storeOf;
2266
2320
  if (found === undefined)
2267
2321
  return;
@@ -2270,32 +2324,32 @@ var forgetRefusedCreate = (fqn, instanceId) => Effect26.gen(function* () {
2270
2324
  if (mine?.status !== "creating" || mine.instanceId !== instanceId || mine.attr !== undefined) {
2271
2325
  return;
2272
2326
  }
2273
- yield* found.store.delete({ ...found.where, fqn }).pipe(Effect26.ignore);
2327
+ yield* found.store.delete({ ...found.where, fqn }).pipe(Effect27.ignore);
2274
2328
  });
2275
2329
 
2276
2330
  // src/ownership/adopt.ts
2277
- var adoptEnabled = (fqn) => Effect27.gen(function* () {
2278
- const stack = yield* Effect27.serviceOption(Stack3);
2331
+ var adoptEnabled = (fqn) => Effect28.gen(function* () {
2332
+ const stack = yield* Effect28.serviceOption(Stack3);
2279
2333
  const scoped = Option5.isSome(stack) ? stack.value.resources[fqn]?.Adopt : undefined;
2280
2334
  if (scoped !== undefined)
2281
2335
  return scoped;
2282
- const policy = yield* Effect27.serviceOption(AdoptPolicy);
2336
+ const policy = yield* Effect28.serviceOption(AdoptPolicy);
2283
2337
  if (Option5.isSome(policy))
2284
2338
  return policy.value;
2285
- const context = yield* Effect27.serviceOption(AlchemyContext);
2339
+ const context = yield* Effect28.serviceOption(AlchemyContext);
2286
2340
  return Option5.isSome(context) ? context.value.adopt : false;
2287
2341
  });
2288
- var adoptable = (owner) => Effect27.gen(function* () {
2342
+ var adoptable = (owner) => Effect28.gen(function* () {
2289
2343
  if (yield* isCreate(owner.fqn, owner.instanceId))
2290
2344
  return true;
2291
2345
  return yield* unfinished(owner.instanceId);
2292
2346
  });
2293
- var adoptsAtApply = (owner) => Effect27.gen(function* () {
2347
+ var adoptsAtApply = (owner) => Effect28.gen(function* () {
2294
2348
  if (!(yield* adoptEnabled(owner.fqn)))
2295
2349
  return false;
2296
2350
  return yield* adoptable(owner);
2297
2351
  });
2298
- var refuseTakeover = (owner, what) => Effect27.gen(function* () {
2352
+ var refuseTakeover = (owner, what) => Effect28.gen(function* () {
2299
2353
  if (owner.output !== undefined)
2300
2354
  return;
2301
2355
  if (yield* resumes(owner.instanceId))
@@ -2305,25 +2359,25 @@ var refuseTakeover = (owner, what) => Effect27.gen(function* () {
2305
2359
  return;
2306
2360
  yield* forgetRefusedCreate(owner.fqn, owner.instanceId);
2307
2361
  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.";
2308
- return yield* Effect27.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}`));
2362
+ return yield* Effect28.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}`));
2309
2363
  });
2310
2364
  var claimFor = (owner) => (what) => refuseTakeover(owner, what);
2311
2365
 
2312
2366
  // src/ownership/probe.ts
2313
2367
  import { Unowned as Unowned2 } from "alchemy/AdoptPolicy";
2314
- import * as Effect28 from "effect/Effect";
2315
- var provenOurs = (ask, settled2) => Effect28.gen(function* () {
2368
+ import * as Effect29 from "effect/Effect";
2369
+ var provenOurs = (ask, settled2) => Effect29.gen(function* () {
2316
2370
  const recorded = yield* recordedInstance(ask.fqn, ask.instanceId);
2317
2371
  if (recorded === "absent")
2318
2372
  return false;
2319
2373
  if (recorded === "partial") {
2320
- yield* Effect28.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");
2374
+ yield* Effect29.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");
2321
2375
  return false;
2322
2376
  }
2323
- const unproven = (reason) => Effect28.as(Effect28.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);
2324
- return yield* settled2.pipe(Effect28.catch(unproven), Effect28.catchDefect(unproven));
2377
+ const unproven = (reason) => Effect29.as(Effect29.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);
2378
+ return yield* settled2.pipe(Effect29.catch(unproven), Effect29.catchDefect(unproven));
2325
2379
  });
2326
- var ownedRead = (ask, found, settled2) => Effect28.gen(function* () {
2380
+ var ownedRead = (ask, found, settled2) => Effect29.gen(function* () {
2327
2381
  if (found === undefined || ask.output !== undefined)
2328
2382
  return found;
2329
2383
  return (yield* provenOurs(ask, settled2)) ? found : Unowned2(found);
@@ -2381,8 +2435,8 @@ var optionMap = (value, family, defaultKey) => {
2381
2435
  return out;
2382
2436
  };
2383
2437
  var sameMap = (left, right) => left.size === right.size && [...left].every(([key, value]) => right.get(key) === value);
2384
- var sortedForm = (map6) => [...map6].map(([key, value]) => `${key}=${value}`).sort().join(",");
2385
- var printMap = (map6, lead = []) => [...lead.filter((key) => map6.has(key)), ...[...map6.keys()].filter((k) => !lead.includes(k))].map((key) => `${key}=${map6.get(key) ?? ""}`).join(",");
2438
+ var sortedForm = (map7) => [...map7].map(([key, value]) => `${key}=${value}`).sort().join(",");
2439
+ var printMap = (map7, lead = []) => [...lead.filter((key) => map7.has(key)), ...[...map7.keys()].filter((k) => !lead.includes(k))].map((key) => `${key}=${map7.get(key) ?? ""}`).join(",");
2386
2440
  var netMaps = (declared, live) => {
2387
2441
  const want = optionMap(declared, "net");
2388
2442
  const have = optionMap(live, "net");
@@ -2778,11 +2832,11 @@ var identityRefusals = (news, olds, output) => {
2778
2832
  };
2779
2833
 
2780
2834
  // src/proxmox/lxc-adoption.ts
2781
- import * as Effect32 from "effect/Effect";
2835
+ import * as Effect33 from "effect/Effect";
2782
2836
 
2783
2837
  // src/ownership/adopting.ts
2784
- import * as Effect29 from "effect/Effect";
2785
- var adopting = (owner, settled2) => Effect29.gen(function* () {
2838
+ import * as Effect30 from "effect/Effect";
2839
+ var adopting = (owner, settled2) => Effect30.gen(function* () {
2786
2840
  if (owner.output === undefined)
2787
2841
  return false;
2788
2842
  const generation = yield* recordedGeneration(owner.fqn, owner.instanceId);
@@ -2794,11 +2848,11 @@ var adopting = (owner, settled2) => Effect29.gen(function* () {
2794
2848
  });
2795
2849
 
2796
2850
  // src/proxmox/lxc-lifecycle.ts
2797
- import * as Effect31 from "effect/Effect";
2851
+ import * as Effect32 from "effect/Effect";
2798
2852
 
2799
2853
  // src/proxmox/network-apply-read.ts
2800
- import * as Effect30 from "effect/Effect";
2801
- var stagedDiff = (target, node) => Effect30.gen(function* () {
2854
+ import * as Effect31 from "effect/Effect";
2855
+ var stagedDiff = (target, node) => Effect31.gen(function* () {
2802
2856
  const path = `nodes/${node}/network`;
2803
2857
  const credential = yield* leased(target, "read");
2804
2858
  const envelope = yield* pveEnvelopeWith(target, credential, "GET", path);
@@ -2811,8 +2865,8 @@ var pendingLines = (diff) => {
2811
2865
  `).filter((line) => (line.startsWith("+") || line.startsWith("-")) && !line.startsWith("+++") && !line.startsWith("---")).length;
2812
2866
  return Math.max(changed, 1);
2813
2867
  };
2814
- var pendingCount = (target, node) => stagedDiff(target, node).pipe(Effect30.map(pendingLines));
2815
- var clusterHealth = (target) => pve(target, "read", "GET", "cluster/status").pipe(Effect30.map((rows) => {
2868
+ var pendingCount = (target, node) => stagedDiff(target, node).pipe(Effect31.map(pendingLines));
2869
+ var clusterHealth = (target) => pve(target, "read", "GET", "cluster/status").pipe(Effect31.map((rows) => {
2816
2870
  const all = rows ?? [];
2817
2871
  const cluster = all.find((row) => row.type === "cluster");
2818
2872
  return {
@@ -2820,21 +2874,21 @@ var clusterHealth = (target) => pve(target, "read", "GET", "cluster/status").pip
2820
2874
  quorate: cluster === undefined ? true : bool(cluster.quorate)
2821
2875
  };
2822
2876
  }));
2823
- var degradedReason = (target) => clusterHealth(target).pipe(Effect30.map((health) => health.quorate && health.offline.length === 0 ? undefined : `quorate=${String(health.quorate)} offline=[${health.offline.join(", ")}]`));
2877
+ var degradedReason = (target) => clusterHealth(target).pipe(Effect31.map((health) => health.quorate && health.offline.length === 0 ? undefined : `quorate=${String(health.quorate)} offline=[${health.offline.join(", ")}]`));
2824
2878
  var UNREACHABLE = "the task could not be read -- the node stopped answering, or this lease cannot see it";
2825
2879
  var STILL_RUNNING = "still running when this provider stopped waiting";
2826
2880
  var ATTEMPTS = 30;
2827
- var awaitTask = (target, credential, node, upid, attempts = ATTEMPTS) => Effect30.gen(function* () {
2881
+ var awaitTask = (target, credential, node, upid, attempts = ATTEMPTS) => Effect31.gen(function* () {
2828
2882
  const path = `nodes/${node}/tasks/${upid}/status`;
2829
2883
  for (let attempt = 0;attempt < attempts; attempt += 1) {
2830
- const status = yield* pveWith(target, credential, "GET", path).pipe(Effect30.orElseSucceed(() => {
2884
+ const status = yield* pveWith(target, credential, "GET", path).pipe(Effect31.orElseSucceed(() => {
2831
2885
  return;
2832
2886
  }));
2833
2887
  if (status === undefined)
2834
2888
  return UNREACHABLE;
2835
2889
  if (status.status === "stopped")
2836
2890
  return text(status.exitstatus, "stopped with no exitstatus");
2837
- yield* Effect30.sleep("1 second");
2891
+ yield* Effect31.sleep("1 second");
2838
2892
  }
2839
2893
  return STILL_RUNNING;
2840
2894
  });
@@ -2852,43 +2906,43 @@ var LXC_ENDPOINTS = {
2852
2906
  var CREATE_POLLS = 180;
2853
2907
  var TASK_POLLS = 60;
2854
2908
  var isServerError = (error) => error instanceof PveError && error.status === 500;
2855
- var readLive = (where) => Effect31.gen(function* () {
2856
- const answer = yield* pve(where.target, "read", "GET", `${guestPath(where)}/config`).pipe(Effect31.map((data) => ({ data, error: undefined })), Effect31.catchIf(isServerError, (error) => Effect31.succeed({ data: undefined, error })));
2909
+ var readLive = (where) => Effect32.gen(function* () {
2910
+ const answer = yield* pve(where.target, "read", "GET", `${guestPath(where)}/config`).pipe(Effect32.map((data) => ({ data, error: undefined })), Effect32.catchIf(isServerError, (error) => Effect32.succeed({ data: undefined, error })));
2857
2911
  if (answer.data !== undefined && answer.data !== null)
2858
2912
  return answer.data;
2859
2913
  const rows = yield* pve(where.target, "read", "GET", "cluster/resources?type=vm");
2860
2914
  const found = (rows ?? []).find((row) => Number(row.vmid) === where.vmid);
2861
2915
  if (found !== undefined && found.node === where.node && found.type === "lxc") {
2862
- return yield* Effect31.fail(answer.error ?? new LxcRefusedError(`CT ${String(where.vmid)} is listed but its config read empty.`));
2916
+ return yield* Effect32.fail(answer.error ?? new LxcRefusedError(`CT ${String(where.vmid)} is listed but its config read empty.`));
2863
2917
  }
2864
2918
  if (found !== undefined) {
2865
- return yield* Effect31.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."));
2919
+ return yield* Effect32.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."));
2866
2920
  }
2867
2921
  return;
2868
2922
  });
2869
- var attributesOf = (where, live) => ({
2923
+ var attributesOf2 = (where, live) => ({
2870
2924
  config: storedConfig(live),
2871
2925
  node: where.node,
2872
2926
  rawKeys: rawKeysOf(live),
2873
2927
  vmid: where.vmid
2874
2928
  });
2875
- var task = (where, method, path, what, polls, form) => Effect31.gen(function* () {
2929
+ var task = (where, method, path, what, polls, form) => Effect32.gen(function* () {
2876
2930
  const credential = yield* mint(where.target, "provision");
2877
2931
  const upid = text(yield* pveWith(where.target, credential, method, path, form));
2878
2932
  if (upid === "") {
2879
- return yield* Effect31.fail(new LxcRefusedError(`${what}: PVE returned no task id, so the write cannot be confirmed and is not claimed.`));
2933
+ return yield* Effect32.fail(new LxcRefusedError(`${what}: PVE returned no task id, so the write cannot be confirmed and is not claimed.`));
2880
2934
  }
2881
2935
  const exit = yield* awaitTask(where.target, credential, where.node, upid, polls);
2882
2936
  if (exit !== "OK") {
2883
- return yield* Effect31.fail(new LxcRefusedError(`${what}: task ${upid} ended "${exit}". Read \`pvesh get /nodes/${where.node}/tasks/` + `${upid}/log\` before running the deploy again.`));
2937
+ return yield* Effect32.fail(new LxcRefusedError(`${what}: task ${upid} ended "${exit}". Read \`pvesh get /nodes/${where.node}/tasks/` + `${upid}/log\` before running the deploy again.`));
2884
2938
  }
2885
2939
  });
2886
- var createGuest = (props) => Effect31.gen(function* () {
2940
+ var createGuest = (props) => Effect32.gen(function* () {
2887
2941
  const form = createForm3(props);
2888
2942
  yield* guardForm(LXC_ENDPOINTS.create, form, true);
2889
2943
  return yield* task(props, "POST", `nodes/${props.node}/lxc`, `create CT ${String(props.vmid)}`, CREATE_POLLS, form);
2890
2944
  });
2891
- var updateGuest = (props, change, digest) => Effect31.gen(function* () {
2945
+ var updateGuest = (props, change, digest) => Effect32.gen(function* () {
2892
2946
  if (Object.keys(change.put).length > 0 || change.clear.length > 0) {
2893
2947
  const form = withClears({ ...change.put, ...digest === "" ? {} : { digest } }, change.clear);
2894
2948
  yield* guardForm(LXC_ENDPOINTS.update, form, false);
@@ -2900,33 +2954,33 @@ var updateGuest = (props, change, digest) => Effect31.gen(function* () {
2900
2954
  yield* task(props, "PUT", `${guestPath(props)}/resize`, `grow ${grow.disk} of CT ${String(props.vmid)} to ${grow.size}`, TASK_POLLS, grown);
2901
2955
  }
2902
2956
  });
2903
- var destroyGuest = (where, declared) => Effect31.gen(function* () {
2957
+ var destroyGuest = (where, declared) => Effect32.gen(function* () {
2904
2958
  const live = yield* readLive(where);
2905
2959
  if (live === undefined)
2906
2960
  return;
2907
2961
  const drift = judge(declared, live).drift;
2908
2962
  if (drift.length > 0) {
2909
- return yield* Effect31.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."));
2963
+ return yield* Effect32.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."));
2910
2964
  }
2911
2965
  yield* task(where, "DELETE", guestPath(where), `destroy CT ${String(where.vmid)}`, TASK_POLLS);
2912
2966
  });
2913
2967
 
2914
2968
  // src/proxmox/lxc-adoption.ts
2915
2969
  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.";
2916
- var refuseAdoptedDrift = (owner, props, live, change) => Effect32.gen(function* () {
2970
+ var refuseAdoptedDrift = (owner, props, live, change) => Effect33.gen(function* () {
2917
2971
  if (change.drift.length === 0)
2918
2972
  return;
2919
- const settled2 = (recorded) => Effect32.sync(() => judge(recorded, live).drift.length === 0);
2973
+ const settled2 = (recorded) => Effect33.sync(() => judge(recorded, live).drift.length === 0);
2920
2974
  if (!(yield* adopting(owner, settled2)))
2921
2975
  return;
2922
- return yield* Effect32.fail(new LxcRefusedError(adoptionRefusal(props, change.drift)));
2976
+ return yield* Effect33.fail(new LxcRefusedError(adoptionRefusal(props, change.drift)));
2923
2977
  });
2924
2978
 
2925
2979
  // src/proxmox/lxc.ts
2926
2980
  var ProxmoxLxc = Resource13("Proxmox.Lxc", { defaultRemovalPolicy: "retain" });
2927
- var refused = (reasons) => Effect33.fail(new LxcRefusedError(reasons.join(`
2981
+ var refused = (reasons) => Effect34.fail(new LxcRefusedError(reasons.join(`
2928
2982
  `)));
2929
- var diff = (owner, news, olds) => Effect33.gen(function* () {
2983
+ var diff = (owner, news, olds) => Effect34.gen(function* () {
2930
2984
  const { output } = owner;
2931
2985
  const identity2 = identityRefusals(news, olds, output);
2932
2986
  if (identity2.length > 0)
@@ -2940,7 +2994,7 @@ var diff = (owner, news, olds) => Effect33.gen(function* () {
2940
2994
  const refusals = createRefusals(news);
2941
2995
  if (refusals.length > 0)
2942
2996
  return yield* refused(refusals);
2943
- yield* Effect33.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.");
2997
+ yield* Effect34.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.");
2944
2998
  return { action: "update" };
2945
2999
  }
2946
3000
  const change = judge(news, live);
@@ -2951,10 +3005,10 @@ var diff = (owner, news, olds) => Effect33.gen(function* () {
2951
3005
  if (change.drift.length === 0 && !moved)
2952
3006
  return { action: "noop" };
2953
3007
  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.";
2954
- yield* Effect33.logWarning(`Proxmox.Lxc ${news.node}/${String(news.vmid)}: ${what}`);
3008
+ yield* Effect34.logWarning(`Proxmox.Lxc ${news.node}/${String(news.vmid)}: ${what}`);
2955
3009
  return { action: "update" };
2956
3010
  });
2957
- var reconcile = (owner, news) => Effect33.gen(function* () {
3011
+ var reconcile = (owner, news) => Effect34.gen(function* () {
2958
3012
  const { output } = owner;
2959
3013
  const identity2 = identityRefusals(news, news, output);
2960
3014
  if (identity2.length > 0)
@@ -2993,20 +3047,20 @@ var reconcile = (owner, news) => Effect33.gen(function* () {
2993
3047
  `CT ${String(news.vmid)}: after the write, ${left.join(", ")} still differ from the ` + "declaration. PVE may have normalised the value (tags are lower-cased by default) -- " + "declare what it stores."
2994
3048
  ]);
2995
3049
  }
2996
- return attributesOf(news, after);
3050
+ return attributesOf2(news, after);
2997
3051
  });
2998
3052
  var whereOf = (olds, output) => ({
2999
3053
  node: output?.node ?? olds.node,
3000
3054
  target: olds.target,
3001
3055
  vmid: output?.vmid ?? olds.vmid
3002
3056
  });
3003
- var read = (owner, olds) => Effect33.gen(function* () {
3057
+ var read = (owner, olds) => Effect34.gen(function* () {
3004
3058
  const where = whereOf(olds, owner.output);
3005
3059
  const live = yield* readLive(where);
3006
3060
  if (live === undefined)
3007
3061
  return;
3008
- const settled2 = Effect33.sync(() => judge(olds, live).drift.length === 0);
3009
- return yield* ownedRead(owner, attributesOf(where, live), settled2);
3062
+ const settled2 = Effect34.sync(() => judge(olds, live).drift.length === 0);
3063
+ return yield* ownedRead(owner, attributesOf2(where, live), settled2);
3010
3064
  });
3011
3065
  var handlers10 = {
3012
3066
  delete: ({ olds, output }) => destroyGuest(whereOf(olds, output), olds),
@@ -3017,7 +3071,7 @@ var handlers10 = {
3017
3071
  olds,
3018
3072
  output
3019
3073
  }) => diff({ fqn, instanceId, output }, news, olds),
3020
- list: () => Effect33.succeed([]),
3074
+ list: () => Effect34.succeed([]),
3021
3075
  read: ({
3022
3076
  fqn,
3023
3077
  instanceId,
@@ -3031,11 +3085,11 @@ var handlers10 = {
3031
3085
  output
3032
3086
  }) => reconcile({ fqn, instanceId, output }, news)
3033
3087
  };
3034
- var ProxmoxLxcProvider = () => Provider13.effect(ProxmoxLxc, Effect33.succeed(ProxmoxLxc.Provider.of(handlers10)).pipe(Effect33.map(provingResumes)));
3088
+ var ProxmoxLxcProvider = () => Provider13.effect(ProxmoxLxc, Effect34.succeed(ProxmoxLxc.Provider.of(handlers10)).pipe(Effect34.map(provingResumes)));
3035
3089
  // src/proxmox/metric-server.ts
3036
3090
  import { Resource as Resource14 } from "alchemy";
3037
3091
  import * as Provider14 from "alchemy/Provider";
3038
- import * as Effect34 from "effect/Effect";
3092
+ import * as Effect35 from "effect/Effect";
3039
3093
 
3040
3094
  // src/proxmox/metric-server-form.ts
3041
3095
  var UNSET2 = -1;
@@ -3148,12 +3202,12 @@ var handlers11 = pveHandlers({
3148
3202
  path: (props) => `cluster/metrics/server/${props.id}`,
3149
3203
  updateForm: update
3150
3204
  });
3151
- var ProxmoxMetricServerProvider = () => Provider14.effect(ProxmoxMetricServer, Effect34.succeed(ProxmoxMetricServer.Provider.of(handlers11)));
3205
+ var ProxmoxMetricServerProvider = () => Provider14.effect(ProxmoxMetricServer, Effect35.succeed(ProxmoxMetricServer.Provider.of(handlers11)));
3152
3206
  // src/proxmox/network-apply.ts
3153
3207
  import { Resource as Resource15 } from "alchemy";
3154
3208
  import { isResolved as isResolved7 } from "alchemy/Diff";
3155
3209
  import * as Provider15 from "alchemy/Provider";
3156
- import * as Effect35 from "effect/Effect";
3210
+ import * as Effect36 from "effect/Effect";
3157
3211
 
3158
3212
  // src/proxmox/apply-endpoints.ts
3159
3213
  var NETWORK_APPLY_ENDPOINT = "pve:PUT /nodes/{node}/network";
@@ -3163,15 +3217,15 @@ var guardSdnApply = guardForm(SDN_APPLY_ENDPOINT, {}, true);
3163
3217
 
3164
3218
  // src/proxmox/network-apply.ts
3165
3219
  var ProxmoxNetworkApply = Resource15("Proxmox.NetworkApply");
3166
- var read2 = (props) => pendingCount(props.target, props.node).pipe(Effect35.map((pending) => ({ node: props.node, pending })));
3167
- var diff2 = (news) => Effect35.gen(function* () {
3220
+ var read2 = (props) => pendingCount(props.target, props.node).pipe(Effect36.map((pending) => ({ node: props.node, pending })));
3221
+ var diff2 = (news) => Effect36.gen(function* () {
3168
3222
  if (!isResolved7(news))
3169
3223
  return;
3170
3224
  const { pending } = yield* read2(news);
3171
3225
  return pending === 0 ? { action: "noop" } : { action: "update" };
3172
3226
  });
3173
- var refuse = (node, why) => Effect35.die(new Error(`Proxmox.NetworkApply ${node}: ${why}`));
3174
- var apply = (props) => Effect35.gen(function* () {
3227
+ var refuse = (node, why) => Effect36.die(new Error(`Proxmox.NetworkApply ${node}: ${why}`));
3228
+ var apply = (props) => Effect36.gen(function* () {
3175
3229
  const node = props.node;
3176
3230
  const staged = yield* pendingCount(props.target, node);
3177
3231
  if (staged === 0)
@@ -3201,17 +3255,17 @@ var apply = (props) => Effect35.gen(function* () {
3201
3255
  return { node, pending: left };
3202
3256
  });
3203
3257
  var handlers12 = {
3204
- delete: () => Effect35.void,
3258
+ delete: () => Effect36.void,
3205
3259
  diff: ({ news }) => diff2(news),
3206
- list: () => Effect35.succeed([]),
3260
+ list: () => Effect36.succeed([]),
3207
3261
  read: ({ olds }) => read2(olds),
3208
3262
  reconcile: ({ news }) => apply(news)
3209
3263
  };
3210
- var ProxmoxNetworkApplyProvider = () => Provider15.effect(ProxmoxNetworkApply, Effect35.succeed(ProxmoxNetworkApply.Provider.of(handlers12)));
3264
+ var ProxmoxNetworkApplyProvider = () => Provider15.effect(ProxmoxNetworkApply, Effect36.succeed(ProxmoxNetworkApply.Provider.of(handlers12)));
3211
3265
  // src/proxmox/node-network.ts
3212
3266
  import { Resource as Resource16 } from "alchemy";
3213
3267
  import * as Provider16 from "alchemy/Provider";
3214
- import * as Effect36 from "effect/Effect";
3268
+ import * as Effect37 from "effect/Effect";
3215
3269
 
3216
3270
  // src/proxmox/node-network-form.ts
3217
3271
  var UNSET3 = -1;
@@ -3250,7 +3304,7 @@ var updateBody2 = (props) => {
3250
3304
  const fields = body4(props);
3251
3305
  return withClears(fields, clear);
3252
3306
  };
3253
- var readAttributes = (live, props) => {
3307
+ var readAttributes2 = (live, props) => {
3254
3308
  const liveType = text(live["type"]);
3255
3309
  if (liveType !== "" && liveType !== props.type)
3256
3310
  return;
@@ -3288,7 +3342,7 @@ var ProxmoxNodeNetwork = Resource16("Proxmox.NodeNetwork", {
3288
3342
  defaultRemovalPolicy: "retain"
3289
3343
  });
3290
3344
  var handlers13 = pveHandlers({
3291
- attributes: readAttributes,
3345
+ attributes: readAttributes2,
3292
3346
  collection: (props) => `nodes/${props.node}/network`,
3293
3347
  createForm: createBody3,
3294
3348
  endpoint: {
@@ -3299,11 +3353,11 @@ var handlers13 = pveHandlers({
3299
3353
  path: (props) => `nodes/${props.node}/network/${props.iface}`,
3300
3354
  updateForm: updateBody2
3301
3355
  });
3302
- var ProxmoxNodeNetworkProvider = () => Provider16.effect(ProxmoxNodeNetwork, Effect36.succeed(ProxmoxNodeNetwork.Provider.of(handlers13)));
3356
+ var ProxmoxNodeNetworkProvider = () => Provider16.effect(ProxmoxNodeNetwork, Effect37.succeed(ProxmoxNodeNetwork.Provider.of(handlers13)));
3303
3357
  // src/proxmox/notification-matcher.ts
3304
3358
  import { Resource as Resource17 } from "alchemy";
3305
3359
  import * as Provider17 from "alchemy/Provider";
3306
- import * as Effect37 from "effect/Effect";
3360
+ import * as Effect38 from "effect/Effect";
3307
3361
 
3308
3362
  // src/proxmox/notification-matcher-form.ts
3309
3363
  var list = (value) => Array.isArray(value) ? value.map((item) => String(item)) : [];
@@ -3393,11 +3447,11 @@ var handlers14 = pveHandlers({
3393
3447
  path: (props) => `cluster/notifications/matchers/${props.name}`,
3394
3448
  updateForm: matcherUpdateForm
3395
3449
  });
3396
- var ProxmoxNotificationMatcherProvider = () => Provider17.effect(ProxmoxNotificationMatcher, Effect37.succeed(ProxmoxNotificationMatcher.Provider.of(handlers14)));
3450
+ var ProxmoxNotificationMatcherProvider = () => Provider17.effect(ProxmoxNotificationMatcher, Effect38.succeed(ProxmoxNotificationMatcher.Provider.of(handlers14)));
3397
3451
  // src/proxmox/notification-target.ts
3398
3452
  import { Resource as Resource18 } from "alchemy";
3399
3453
  import * as Provider18 from "alchemy/Provider";
3400
- import * as Effect38 from "effect/Effect";
3454
+ import * as Effect39 from "effect/Effect";
3401
3455
 
3402
3456
  // src/proxmox/notification-target-endpoint.ts
3403
3457
  var ENDPOINTS = {
@@ -3479,15 +3533,15 @@ var handlers15 = pveHandlers({
3479
3533
  path: (props) => `cluster/notifications/endpoints/${props.type}/${props.name}`,
3480
3534
  updateForm: shape4
3481
3535
  });
3482
- var ProxmoxNotificationTargetProvider = () => Provider18.effect(ProxmoxNotificationTarget, Effect38.succeed(ProxmoxNotificationTarget.Provider.of(handlers15)));
3536
+ var ProxmoxNotificationTargetProvider = () => Provider18.effect(ProxmoxNotificationTarget, Effect39.succeed(ProxmoxNotificationTarget.Provider.of(handlers15)));
3483
3537
  // src/proxmox/pbs-datastore.ts
3484
3538
  import { Resource as Resource19 } from "alchemy";
3485
3539
  import { isResolved as isResolved8 } from "alchemy/Diff";
3486
3540
  import * as Provider19 from "alchemy/Provider";
3487
- import * as Effect42 from "effect/Effect";
3541
+ import * as Effect43 from "effect/Effect";
3488
3542
 
3489
3543
  // src/proxmox/pbs-datastore-form.ts
3490
- import * as Effect39 from "effect/Effect";
3544
+ import * as Effect40 from "effect/Effect";
3491
3545
  var attributes = (live, props) => ({
3492
3546
  backend: propertyString(live["backend"]),
3493
3547
  comment: text(live["comment"]),
@@ -3510,7 +3564,7 @@ var attributes = (live, props) => ({
3510
3564
  "verify-new": bool(live["verify-new"])
3511
3565
  });
3512
3566
  var same4 = (declared, live) => declared === undefined || declared === live;
3513
- var matches = (live, props) => same4(props.comment, live.comment) && same4(props["gc-schedule"]?.trim(), live["gc-schedule"]) && same4(props["prune-schedule"]?.trim(), live["prune-schedule"]) && same4(props["keep-last"], live["keep-last"]) && same4(props["keep-hourly"], live["keep-hourly"]) && same4(props["keep-daily"], live["keep-daily"]) && same4(props["keep-weekly"], live["keep-weekly"]) && same4(props["keep-monthly"], live["keep-monthly"]) && same4(props["keep-yearly"], live["keep-yearly"]) && same4(props["notify-user"], live["notify-user"]) && same4(props["counter-reset-schedule"]?.trim(), live["counter-reset-schedule"]) && (props["notification-thresholds"] === undefined || propertyString(props["notification-thresholds"]) === live["notification-thresholds"]) && same4(props["verify-new"], live["verify-new"]) && (props.notify === undefined || propertyString(props.notify) === live.notify) && (props.tuning === undefined || propertyString(props.tuning) === live.tuning) && (props["maintenance-mode"] === undefined || propertyString(props["maintenance-mode"], "type") === live["maintenance-mode"]);
3567
+ var matches2 = (live, props) => same4(props.comment, live.comment) && same4(props["gc-schedule"]?.trim(), live["gc-schedule"]) && same4(props["prune-schedule"]?.trim(), live["prune-schedule"]) && same4(props["keep-last"], live["keep-last"]) && same4(props["keep-hourly"], live["keep-hourly"]) && same4(props["keep-daily"], live["keep-daily"]) && same4(props["keep-weekly"], live["keep-weekly"]) && same4(props["keep-monthly"], live["keep-monthly"]) && same4(props["keep-yearly"], live["keep-yearly"]) && same4(props["notify-user"], live["notify-user"]) && same4(props["counter-reset-schedule"]?.trim(), live["counter-reset-schedule"]) && (props["notification-thresholds"] === undefined || propertyString(props["notification-thresholds"]) === live["notification-thresholds"]) && same4(props["verify-new"], live["verify-new"]) && (props.notify === undefined || propertyString(props.notify) === live.notify) && (props.tuning === undefined || propertyString(props.tuning) === live.tuning) && (props["maintenance-mode"] === undefined || propertyString(props["maintenance-mode"], "type") === live["maintenance-mode"]);
3514
3568
  var set2 = (key, value) => value === undefined ? {} : { [key]: value };
3515
3569
  var count = (value) => value === undefined ? undefined : String(value);
3516
3570
  var mutable = (props) => ({
@@ -3539,35 +3593,35 @@ var createForm4 = (props) => ({
3539
3593
  });
3540
3594
  var updateForm = (props) => mutable(props);
3541
3595
  var object2 = (props) => `config/datastore/${props.name}`;
3542
- var readOne = (props) => pve(props.target, "read", "GET", object2(props)).pipe(Effect39.map((live) => live === undefined || typeof live["name"] !== "string" ? undefined : attributes(live, props)), Effect39.orElseSucceed(() => {
3596
+ var readOne = (props) => pve(props.target, "read", "GET", object2(props)).pipe(Effect40.map((live) => live === undefined || typeof live["name"] !== "string" ? undefined : attributes(live, props)), Effect40.orElseSucceed(() => {
3543
3597
  return;
3544
3598
  }));
3545
3599
 
3546
3600
  // src/proxmox/pbs-datastore-guard.ts
3547
- import * as Effect40 from "effect/Effect";
3601
+ import * as Effect41 from "effect/Effect";
3548
3602
  var samePath = (left, right) => {
3549
3603
  const trim = (value) => value.length > 1 ? value.replace(/\/+$/, "") : value;
3550
3604
  return trim(left) === trim(right);
3551
3605
  };
3552
- var guardPath = (live, props) => live.path === "" || samePath(live.path, props.path) ? Effect40.void : Effect40.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."));
3553
- var guardBackend = (live, props) => props.backend === undefined || propertyString(props.backend) === live.backend ? Effect40.void : Effect40.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."));
3554
- var settle3 = (read3, done) => Effect40.gen(function* () {
3606
+ var guardPath = (live, props) => live.path === "" || samePath(live.path, props.path) ? Effect41.void : Effect41.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."));
3607
+ var guardBackend = (live, props) => props.backend === undefined || propertyString(props.backend) === live.backend ? Effect41.void : Effect41.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."));
3608
+ var settle3 = (read3, done) => Effect41.gen(function* () {
3555
3609
  for (let attempt = 0;attempt < 60; attempt += 1) {
3556
3610
  const live = yield* read3;
3557
3611
  if (done(live))
3558
3612
  return live;
3559
- yield* Effect40.sleep("2 seconds");
3613
+ yield* Effect41.sleep("2 seconds");
3560
3614
  }
3561
3615
  return yield* read3;
3562
3616
  });
3563
3617
 
3564
3618
  // src/proxmox/pbs-datastore-endpoint.ts
3565
- import * as Effect41 from "effect/Effect";
3619
+ import * as Effect42 from "effect/Effect";
3566
3620
  var DATASTORE_ENDPOINT = {
3567
3621
  create: "pbs:POST /config/datastore",
3568
3622
  update: "pbs:PUT /config/datastore/{name}"
3569
3623
  };
3570
- var guardDatastoreForms = (props) => Effect41.gen(function* () {
3624
+ var guardDatastoreForms = (props) => Effect42.gen(function* () {
3571
3625
  yield* guardForm(DATASTORE_ENDPOINT.create, createForm4(props), true);
3572
3626
  yield* guardForm(DATASTORE_ENDPOINT.update, updateForm(props), false);
3573
3627
  });
@@ -3576,10 +3630,10 @@ var guardDatastoreForms = (props) => Effect41.gen(function* () {
3576
3630
  var PbsDatastore = Resource19("Pbs.Datastore", {
3577
3631
  defaultRemovalPolicy: "retain"
3578
3632
  });
3579
- var PbsDatastoreProvider = () => Provider19.effect(PbsDatastore, Effect42.succeed(PbsDatastore.Provider.of({
3580
- list: () => Effect42.succeed([]),
3633
+ var PbsDatastoreProvider = () => Provider19.effect(PbsDatastore, Effect43.succeed(PbsDatastore.Provider.of({
3634
+ list: () => Effect43.succeed([]),
3581
3635
  read: ({ olds }) => readOne(olds),
3582
- diff: ({ news, output }) => Effect42.gen(function* () {
3636
+ diff: ({ news, output }) => Effect43.gen(function* () {
3583
3637
  if (!isResolved8(news))
3584
3638
  return;
3585
3639
  yield* guardDatastoreForms(news);
@@ -3590,9 +3644,9 @@ var PbsDatastoreProvider = () => Provider19.effect(PbsDatastore, Effect42.succee
3590
3644
  return { action: "update" };
3591
3645
  yield* guardPath(live, news);
3592
3646
  yield* guardBackend(live, news);
3593
- return matches(live, news) ? { action: "noop" } : { action: "update" };
3647
+ return matches2(live, news) ? { action: "noop" } : { action: "update" };
3594
3648
  }),
3595
- reconcile: Effect42.fn(function* ({ news }) {
3649
+ reconcile: Effect43.fn(function* ({ news }) {
3596
3650
  yield* guardDatastoreForms(news);
3597
3651
  const live = yield* readOne(news);
3598
3652
  let upid;
@@ -3601,29 +3655,29 @@ var PbsDatastoreProvider = () => Provider19.effect(PbsDatastore, Effect42.succee
3601
3655
  } else {
3602
3656
  yield* guardPath(live, news);
3603
3657
  yield* guardBackend(live, news);
3604
- const form = formToSend(matches, live, news, updateForm(news));
3658
+ const form = formToSend(matches2, live, news, updateForm(news));
3605
3659
  if (form !== undefined) {
3606
3660
  yield* pve(news.target, "provision", "PUT", object2(news), form);
3607
3661
  }
3608
3662
  }
3609
- const after = yield* settle3(readOne(news), (row) => row !== undefined && matches(row, news));
3610
- if (after === undefined || !matches(after, news)) {
3611
- return yield* Effect42.die(new Error(`${object2(news)}: the write returned no error but the datastore still does not ` + `match the declaration after 120s. PBS answered with task ${upid ?? "(none)"} ` + "-- read it with `proxmox-backup-manager task log <upid>`. A slow disk is a " + "plausible cause (see `settle`); a create over an existing chunk store is not, " + "because PBS refuses that outright rather than timing out."));
3663
+ const after = yield* settle3(readOne(news), (row) => row !== undefined && matches2(row, news));
3664
+ if (after === undefined || !matches2(after, news)) {
3665
+ return yield* Effect43.die(new Error(`${object2(news)}: the write returned no error but the datastore still does not ` + `match the declaration after 120s. PBS answered with task ${upid ?? "(none)"} ` + "-- read it with `proxmox-backup-manager task log <upid>`. A slow disk is a " + "plausible cause (see `settle`); a create over an existing chunk store is not, " + "because PBS refuses that outright rather than timing out."));
3612
3666
  }
3613
3667
  return after;
3614
3668
  }),
3615
- delete: Effect42.fn(function* ({ olds }) {
3669
+ delete: Effect43.fn(function* ({ olds }) {
3616
3670
  yield* pve(olds.target, "provision", "DELETE", object2(olds));
3617
3671
  const left = yield* settle3(readOne(olds), (row) => row === undefined);
3618
3672
  if (left !== undefined) {
3619
- return yield* Effect42.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>\`.`));
3673
+ return yield* Effect43.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>\`.`));
3620
3674
  }
3621
3675
  })
3622
3676
  })));
3623
3677
  // src/proxmox/pbs-notification-matcher.ts
3624
3678
  import { Resource as Resource20 } from "alchemy";
3625
3679
  import * as Provider20 from "alchemy/Provider";
3626
- import * as Effect43 from "effect/Effect";
3680
+ import * as Effect44 from "effect/Effect";
3627
3681
  var PbsNotificationMatcher = Resource20("Pbs.NotificationMatcher");
3628
3682
  var handlers16 = pveHandlers({
3629
3683
  attributes: (live, props) => matcherAttributes(live, props.name),
@@ -3637,15 +3691,15 @@ var handlers16 = pveHandlers({
3637
3691
  path: (props) => `config/notifications/matchers/${props.name}`,
3638
3692
  updateForm: matcherUpdateForm
3639
3693
  });
3640
- var PbsNotificationMatcherProvider = () => Provider20.effect(PbsNotificationMatcher, Effect43.succeed(PbsNotificationMatcher.Provider.of(handlers16)));
3694
+ var PbsNotificationMatcherProvider = () => Provider20.effect(PbsNotificationMatcher, Effect44.succeed(PbsNotificationMatcher.Provider.of(handlers16)));
3641
3695
  // src/proxmox/pbs-notification-target.ts
3642
3696
  import { Resource as Resource21 } from "alchemy";
3643
3697
  import * as Provider21 from "alchemy/Provider";
3644
- import * as Effect45 from "effect/Effect";
3698
+ import * as Effect46 from "effect/Effect";
3645
3699
 
3646
3700
  // src/proxmox/pbs-notification-target-lifecycle.ts
3647
3701
  import { isResolved as isResolved9 } from "alchemy/Diff";
3648
- import * as Effect44 from "effect/Effect";
3702
+ import * as Effect45 from "effect/Effect";
3649
3703
 
3650
3704
  // src/proxmox/pbs-notification-target-endpoint.ts
3651
3705
  var ENDPOINTS2 = {
@@ -3922,12 +3976,12 @@ var targetForm = (props, groups, carry, mode) => {
3922
3976
 
3923
3977
  // src/proxmox/pbs-notification-target-lifecycle.ts
3924
3978
  var path = (props) => `config/notifications/endpoints/${props.type}/${props.name}`;
3925
- var readLive2 = (props) => pve(props.target, "read", "GET", path(props)).pipe(Effect44.map((data) => data == null ? undefined : targetAttributes(data, props)), Effect44.orElseSucceed(() => {
3979
+ var readLive2 = (props) => pve(props.target, "read", "GET", path(props)).pipe(Effect45.map((data) => data == null ? undefined : targetAttributes(data, props)), Effect45.orElseSucceed(() => {
3926
3980
  return;
3927
3981
  }));
3928
3982
  var refuse2 = (props) => {
3929
3983
  const reasons = refusals(props);
3930
- return reasons.length === 0 ? Effect44.void : Effect44.die(new Error(`${path(props)}: ${reasons.join("; ")}.`));
3984
+ return reasons.length === 0 ? Effect45.void : Effect45.die(new Error(`${path(props)}: ${reasons.join("; ")}.`));
3931
3985
  };
3932
3986
  var toCarry = (live, props, groups, sealed) => {
3933
3987
  const header = headerState(live, props, groups) === "stale";
@@ -3939,16 +3993,16 @@ var requireValues = (props, groups, carry) => {
3939
3993
  ...carry.header ? groups.header.missing : [],
3940
3994
  ...carry.sealed ? groups.sealed.missing : []
3941
3995
  ];
3942
- return missing.length === 0 ? Effect44.void : Effect44.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."));
3996
+ return missing.length === 0 ? Effect45.void : Effect45.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."));
3943
3997
  };
3944
3998
  var handlers17 = {
3945
- list: () => Effect44.succeed([]),
3946
- read: ({ olds, output }) => (output === undefined ? refuse2(olds) : Effect44.void).pipe(Effect44.andThen(readLive2(olds)), Effect44.map((live) => live === undefined ? undefined : { ...live, sealed: output?.sealed ?? "" })),
3999
+ list: () => Effect45.succeed([]),
4000
+ read: ({ olds, output }) => (output === undefined ? refuse2(olds) : Effect45.void).pipe(Effect45.andThen(readLive2(olds)), Effect45.map((live) => live === undefined ? undefined : { ...live, sealed: output?.sealed ?? "" })),
3947
4001
  diff: ({
3948
4002
  news,
3949
4003
  olds,
3950
4004
  output
3951
- }) => Effect44.gen(function* () {
4005
+ }) => Effect45.gen(function* () {
3952
4006
  if (output === undefined || !isResolved9(news))
3953
4007
  return;
3954
4008
  if (olds !== undefined && (olds.type !== news.type || olds.name !== news.name)) {
@@ -3960,7 +4014,7 @@ var handlers17 = {
3960
4014
  return { action: "update" };
3961
4015
  return toCarry(live, news, resolveGroups(news), output.sealed) === undefined ? { action: "noop" } : { action: "update" };
3962
4016
  }),
3963
- reconcile: ({ news, output }) => Effect44.gen(function* () {
4017
+ reconcile: ({ news, output }) => Effect45.gen(function* () {
3964
4018
  yield* refuse2(news);
3965
4019
  const groups = resolveGroups(news);
3966
4020
  const live = yield* readLive2(news);
@@ -3986,7 +4040,7 @@ var handlers17 = {
3986
4040
  }
3987
4041
  const after = yield* readLive2(news);
3988
4042
  if (after === undefined) {
3989
- return yield* Effect44.die(new Error(`${path(news)}: the write returned no error but the target is still absent.`));
4043
+ return yield* Effect45.die(new Error(`${path(news)}: the write returned no error but the target is still absent.`));
3990
4044
  }
3991
4045
  return { ...after, sealed };
3992
4046
  }),
@@ -3995,11 +4049,11 @@ var handlers17 = {
3995
4049
 
3996
4050
  // src/proxmox/pbs-notification-target.ts
3997
4051
  var PbsNotificationTarget = Resource21("Pbs.NotificationTarget");
3998
- var PbsNotificationTargetProvider = () => Provider21.effect(PbsNotificationTarget, Effect45.succeed(PbsNotificationTarget.Provider.of(handlers17)));
4052
+ var PbsNotificationTargetProvider = () => Provider21.effect(PbsNotificationTarget, Effect46.succeed(PbsNotificationTarget.Provider.of(handlers17)));
3999
4053
  // src/proxmox/pbs-prune-job.ts
4000
4054
  import { Resource as Resource22 } from "alchemy";
4001
4055
  import * as Provider22 from "alchemy/Provider";
4002
- import * as Effect46 from "effect/Effect";
4056
+ import * as Effect47 from "effect/Effect";
4003
4057
 
4004
4058
  // src/proxmox/pbs-prune-job-form.ts
4005
4059
  var KEEP_KEYS = [
@@ -4075,11 +4129,11 @@ var handlers18 = pveHandlers({
4075
4129
  path: (props) => `config/prune/${props.id}`,
4076
4130
  updateForm: updateBody3
4077
4131
  });
4078
- var PbsPruneJobProvider = () => Provider22.effect(PbsPruneJob, Effect46.succeed(PbsPruneJob.Provider.of(handlers18)));
4132
+ var PbsPruneJobProvider = () => Provider22.effect(PbsPruneJob, Effect47.succeed(PbsPruneJob.Provider.of(handlers18)));
4079
4133
  // src/proxmox/pbs-sync-job.ts
4080
4134
  import { Resource as Resource23 } from "alchemy";
4081
4135
  import * as Provider23 from "alchemy/Provider";
4082
- import * as Effect47 from "effect/Effect";
4136
+ import * as Effect48 from "effect/Effect";
4083
4137
 
4084
4138
  // src/proxmox/pbs-sync-job-form.ts
4085
4139
  var UNSET4 = -1;
@@ -4156,11 +4210,11 @@ var handlers19 = pveHandlers({
4156
4210
 
4157
4211
  // src/proxmox/pbs-sync-job.ts
4158
4212
  var PbsSyncJob = Resource23("Pbs.SyncJob");
4159
- var PbsSyncJobProvider = () => Provider23.effect(PbsSyncJob, Effect47.succeed(PbsSyncJob.Provider.of(handlers19)));
4213
+ var PbsSyncJobProvider = () => Provider23.effect(PbsSyncJob, Effect48.succeed(PbsSyncJob.Provider.of(handlers19)));
4160
4214
  // src/proxmox/pbs-verify-job.ts
4161
4215
  import { Resource as Resource24 } from "alchemy";
4162
4216
  import * as Provider24 from "alchemy/Provider";
4163
- import * as Effect48 from "effect/Effect";
4217
+ import * as Effect49 from "effect/Effect";
4164
4218
 
4165
4219
  // src/proxmox/pbs-verify-job-form.ts
4166
4220
  var rechecks = (ignoreVerified, outdatedAfter) => {
@@ -4205,11 +4259,11 @@ var handlers20 = pveHandlers({
4205
4259
  path: (props) => `config/verify/${props.id}`,
4206
4260
  updateForm: shape7
4207
4261
  });
4208
- var PbsVerifyJobProvider = () => Provider24.effect(PbsVerifyJob, Effect48.succeed(PbsVerifyJob.Provider.of(handlers20)));
4262
+ var PbsVerifyJobProvider = () => Provider24.effect(PbsVerifyJob, Effect49.succeed(PbsVerifyJob.Provider.of(handlers20)));
4209
4263
  // src/proxmox/pool.ts
4210
4264
  import { Resource as Resource25 } from "alchemy";
4211
4265
  import * as Provider25 from "alchemy/Provider";
4212
- import * as Effect49 from "effect/Effect";
4266
+ import * as Effect50 from "effect/Effect";
4213
4267
  var ProxmoxPool = Resource25("Proxmox.Pool");
4214
4268
  var poolCreateForm = (props) => ({
4215
4269
  comment: props.comment ?? "",
@@ -4234,7 +4288,7 @@ var handlers21 = pveHandlers({
4234
4288
  path: (props) => `pools/${props.poolid}`,
4235
4289
  updateForm: poolUpdateForm
4236
4290
  });
4237
- var ProxmoxPoolProvider = () => Provider25.effect(ProxmoxPool, Effect49.succeed(ProxmoxPool.Provider.of(handlers21)));
4291
+ var ProxmoxPoolProvider = () => Provider25.effect(ProxmoxPool, Effect50.succeed(ProxmoxPool.Provider.of(handlers21)));
4238
4292
  // src/proxmox/provision-baseline.ts
4239
4293
  var PROVISION_PRIVILEGES = Object.freeze([
4240
4294
  "Datastore.Allocate",
@@ -4427,12 +4481,12 @@ echo 'provision baseline: done. Next: point the OpenBao proxmox mount at these u
4427
4481
  // src/proxmox/provision-declare.ts
4428
4482
  import { adopt } from "alchemy/AdoptPolicy";
4429
4483
  import * as RemovalPolicy from "alchemy/RemovalPolicy";
4430
- import * as Effect52 from "effect/Effect";
4484
+ import * as Effect53 from "effect/Effect";
4431
4485
 
4432
4486
  // src/proxmox/role.ts
4433
4487
  import { Resource as Resource26 } from "alchemy";
4434
4488
  import * as Provider26 from "alchemy/Provider";
4435
- import * as Effect50 from "effect/Effect";
4489
+ import * as Effect51 from "effect/Effect";
4436
4490
  var ProxmoxRole = Resource26("Proxmox.Role");
4437
4491
  var canonical2 = (privs) => [...new Set(privs.map((priv) => priv.trim()).filter((priv) => priv.length > 0))].sort();
4438
4492
  var livePrivs = (live) => {
@@ -4450,12 +4504,12 @@ var handlers22 = pveHandlers({
4450
4504
  path: (props) => `access/roles/${props.roleid}`,
4451
4505
  updateForm: (props) => ({ privs: canonical2(props.privs).join(",") })
4452
4506
  });
4453
- var ProxmoxRoleProvider = () => Provider26.effect(ProxmoxRole, Effect50.succeed(ProxmoxRole.Provider.of(handlers22)));
4507
+ var ProxmoxRoleProvider = () => Provider26.effect(ProxmoxRole, Effect51.succeed(ProxmoxRole.Provider.of(handlers22)));
4454
4508
 
4455
4509
  // src/proxmox/user.ts
4456
4510
  import { Resource as Resource27 } from "alchemy";
4457
4511
  import * as Provider27 from "alchemy/Provider";
4458
- import * as Effect51 from "effect/Effect";
4512
+ import * as Effect52 from "effect/Effect";
4459
4513
  var ProxmoxUser = Resource27("Proxmox.User");
4460
4514
  var str2 = (value) => typeof value === "string" ? value : "";
4461
4515
  var int2 = (value) => {
@@ -4496,11 +4550,11 @@ var handlers23 = pveHandlers({
4496
4550
  path: (props) => `access/users/${props.userid}`,
4497
4551
  updateForm: shape8
4498
4552
  });
4499
- var ProxmoxUserProvider = () => Provider27.effect(ProxmoxUser, Effect51.succeed(ProxmoxUser.Provider.of(handlers23)));
4553
+ var ProxmoxUserProvider = () => Provider27.effect(ProxmoxUser, Effect52.succeed(ProxmoxUser.Provider.of(handlers23)));
4500
4554
 
4501
4555
  // src/proxmox/provision-declare.ts
4502
- var declareProvisionBaseline = (id, target, names2 = {}, options = {}) => Effect52.gen(function* () {
4503
- const baseline = yield* Effect52.try({
4556
+ var declareProvisionBaseline = (id, target, names2 = {}, options = {}) => Effect53.gen(function* () {
4557
+ const baseline = yield* Effect53.try({
4504
4558
  catch: (cause) => cause instanceof Error ? cause : new Error(String(cause)),
4505
4559
  try: () => provisionBaseline(names2)
4506
4560
  });
@@ -4514,13 +4568,13 @@ var declareProvisionBaseline = (id, target, names2 = {}, options = {}) => Effect
4514
4568
  target
4515
4569
  }));
4516
4570
  const group = yield* owned(ProxmoxGroup(`${id}-mint-group`, { ...baseline.group, target }));
4517
- const users = yield* Effect52.all(baseline.users.map((user) => owned(ProxmoxUser(`${id}-${user.lane}-user`, {
4571
+ const users = yield* Effect53.all(baseline.users.map((user) => owned(ProxmoxUser(`${id}-${user.lane}-user`, {
4518
4572
  comment: user.comment,
4519
4573
  groups: [...user.groups],
4520
4574
  target,
4521
4575
  userid: user.userid
4522
4576
  }))));
4523
- const grants = yield* Effect52.all(baseline.grants.map((grant) => owned(ProxmoxAcl(`${id}-${grant.lane}-grant`, {
4577
+ const grants = yield* Effect53.all(baseline.grants.map((grant) => owned(ProxmoxAcl(`${id}-${grant.lane}-grant`, {
4524
4578
  path: "/",
4525
4579
  propagate: true,
4526
4580
  roleid: grant.roleid,
@@ -4533,7 +4587,7 @@ var declareProvisionBaseline = (id, target, names2 = {}, options = {}) => Effect
4533
4587
  // src/proxmox/qemu.ts
4534
4588
  import { Resource as Resource28 } from "alchemy";
4535
4589
  import * as Provider28 from "alchemy/Provider";
4536
- import * as Effect53 from "effect/Effect";
4590
+ import * as Effect54 from "effect/Effect";
4537
4591
  var ProxmoxVm = Resource28("Proxmox.Vm");
4538
4592
  var createForm5 = (props) => ({ ...shape9(props), vmid: String(props.vmid) });
4539
4593
  var shape9 = (props) => ({
@@ -4564,11 +4618,11 @@ var handlers24 = pveHandlers({
4564
4618
  path: (props) => `nodes/${props.node}/qemu/${String(props.vmid)}/config`,
4565
4619
  updateForm: shape9
4566
4620
  });
4567
- var ProxmoxVmProvider = () => Provider28.effect(ProxmoxVm, Effect53.succeed(ProxmoxVm.Provider.of(handlers24)));
4621
+ var ProxmoxVmProvider = () => Provider28.effect(ProxmoxVm, Effect54.succeed(ProxmoxVm.Provider.of(handlers24)));
4568
4622
  // src/proxmox/replication-job.ts
4569
4623
  import { Resource as Resource29 } from "alchemy";
4570
4624
  import * as Provider29 from "alchemy/Provider";
4571
- import * as Effect54 from "effect/Effect";
4625
+ import * as Effect55 from "effect/Effect";
4572
4626
 
4573
4627
  // src/proxmox/replication-job-form.ts
4574
4628
  var DEFAULT_SCHEDULE = "*/15";
@@ -4622,15 +4676,15 @@ var handlers25 = pveHandlers({
4622
4676
  path: (props) => `cluster/replication/${jobId(props)}`,
4623
4677
  updateForm: updateBody5
4624
4678
  });
4625
- var ProxmoxReplicationJobProvider = () => Provider29.effect(ProxmoxReplicationJob, Effect54.succeed(ProxmoxReplicationJob.Provider.of(handlers25)));
4679
+ var ProxmoxReplicationJobProvider = () => Provider29.effect(ProxmoxReplicationJob, Effect55.succeed(ProxmoxReplicationJob.Provider.of(handlers25)));
4626
4680
  // src/proxmox/sdn-apply.ts
4627
4681
  import { Resource as Resource30 } from "alchemy";
4628
4682
  import { isResolved as isResolved10 } from "alchemy/Diff";
4629
4683
  import * as Provider30 from "alchemy/Provider";
4630
- import * as Effect56 from "effect/Effect";
4684
+ import * as Effect57 from "effect/Effect";
4631
4685
 
4632
4686
  // src/proxmox/sdn-apply-read.ts
4633
- import * as Effect55 from "effect/Effect";
4687
+ import * as Effect56 from "effect/Effect";
4634
4688
  var MARKED = [
4635
4689
  "cluster/sdn/zones",
4636
4690
  "cluster/sdn/vnets",
@@ -4639,7 +4693,7 @@ var MARKED = [
4639
4693
  "cluster/sdn/route-maps"
4640
4694
  ];
4641
4695
  var subsystemAbsent = (error) => error instanceof PveError && error.status === 501;
4642
- var markedPending = (target) => Effect55.all(MARKED.map((collection2) => pve(target, "read", "GET", `${collection2}?pending=1`).pipe(Effect55.map((rows) => (rows ?? []).filter((row) => row.state !== undefined).length), Effect55.catchIf(subsystemAbsent, () => Effect55.succeed(0)))), { concurrency: "unbounded" }).pipe(Effect55.map((counts) => counts.reduce((total, count2) => total + count2, 0)));
4696
+ var markedPending = (target) => Effect56.all(MARKED.map((collection2) => pve(target, "read", "GET", `${collection2}?pending=1`).pipe(Effect56.map((rows) => (rows ?? []).filter((row) => row.state !== undefined).length), Effect56.catchIf(subsystemAbsent, () => Effect56.succeed(0)))), { concurrency: "unbounded" }).pipe(Effect56.map((counts) => counts.reduce((total, count2) => total + count2, 0)));
4643
4697
  var fabricStaged = (staged, running) => {
4644
4698
  if (staged === undefined && running === undefined)
4645
4699
  return 0;
@@ -4647,9 +4701,9 @@ var fabricStaged = (staged, running) => {
4647
4701
  return "inconsistent";
4648
4702
  return staged === running ? 0 : 1;
4649
4703
  };
4650
- var fabricPending = (target) => Effect55.all(["pending", "running"].map((view) => pve(target, "read", "GET", `cluster/sdn/fabrics/all?${view}=1`).pipe(Effect55.map(canonical3), Effect55.catchIf(subsystemAbsent, () => Effect55.succeed(undefined)))), { concurrency: "unbounded" }).pipe(Effect55.flatMap(([staged, running]) => {
4704
+ var fabricPending = (target) => Effect56.all(["pending", "running"].map((view) => pve(target, "read", "GET", `cluster/sdn/fabrics/all?${view}=1`).pipe(Effect56.map(canonical3), Effect56.catchIf(subsystemAbsent, () => Effect56.succeed(undefined)))), { concurrency: "unbounded" }).pipe(Effect56.flatMap(([staged, running]) => {
4651
4705
  const verdict = fabricStaged(staged, running);
4652
- return verdict === "inconsistent" ? Effect55.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.")) : Effect55.succeed(verdict);
4706
+ return verdict === "inconsistent" ? Effect56.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.")) : Effect56.succeed(verdict);
4653
4707
  }));
4654
4708
  var canonical3 = (value) => JSON.stringify(sortDeep(value));
4655
4709
  var sortDeep = (value) => {
@@ -4662,23 +4716,23 @@ var sortDeep = (value) => {
4662
4716
  }
4663
4717
  return value;
4664
4718
  };
4665
- var sdnPendingCount = (target) => Effect55.all([markedPending(target), fabricPending(target)], { concurrency: "unbounded" }).pipe(Effect55.map(([marked, fabric]) => marked + fabric));
4719
+ var sdnPendingCount = (target) => Effect56.all([markedPending(target), fabricPending(target)], { concurrency: "unbounded" }).pipe(Effect56.map(([marked, fabric]) => marked + fabric));
4666
4720
 
4667
4721
  // src/proxmox/sdn-apply.ts
4668
4722
  var ProxmoxSdnApply = Resource30("Proxmox.SdnApply");
4669
- var read3 = (props) => sdnPendingCount(props.target).pipe(Effect56.map((pending) => ({ pending })));
4670
- var ProxmoxSdnApplyProvider = () => Provider30.effect(ProxmoxSdnApply, Effect56.succeed(ProxmoxSdnApply.Provider.of({
4671
- list: () => Effect56.succeed([]),
4672
- read: Effect56.fn(function* ({ olds }) {
4723
+ var read3 = (props) => sdnPendingCount(props.target).pipe(Effect57.map((pending) => ({ pending })));
4724
+ var ProxmoxSdnApplyProvider = () => Provider30.effect(ProxmoxSdnApply, Effect57.succeed(ProxmoxSdnApply.Provider.of({
4725
+ list: () => Effect57.succeed([]),
4726
+ read: Effect57.fn(function* ({ olds }) {
4673
4727
  return yield* read3(olds);
4674
4728
  }),
4675
- diff: Effect56.fn(function* ({ news }) {
4729
+ diff: Effect57.fn(function* ({ news }) {
4676
4730
  if (!isResolved10(news))
4677
4731
  return;
4678
4732
  const { pending } = yield* read3(news);
4679
4733
  return pending === 0 ? { action: "noop" } : { action: "update" };
4680
4734
  }),
4681
- reconcile: Effect56.fn(function* ({ news }) {
4735
+ reconcile: Effect57.fn(function* ({ news }) {
4682
4736
  const staged = yield* read3(news);
4683
4737
  if (staged.pending === 0)
4684
4738
  return staged;
@@ -4686,16 +4740,16 @@ var ProxmoxSdnApplyProvider = () => Provider30.effect(ProxmoxSdnApply, Effect56.
4686
4740
  yield* pve(news.target, "provision", "PUT", "cluster/sdn");
4687
4741
  const after = yield* read3(news);
4688
4742
  if (after.pending !== 0) {
4689
- return yield* Effect56.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."));
4743
+ return yield* Effect57.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."));
4690
4744
  }
4691
4745
  return after;
4692
4746
  }),
4693
- delete: () => Effect56.void
4747
+ delete: () => Effect57.void
4694
4748
  })));
4695
4749
  // src/proxmox/sdn-subnet.ts
4696
4750
  import { Resource as Resource31 } from "alchemy";
4697
4751
  import * as Provider31 from "alchemy/Provider";
4698
- import * as Effect57 from "effect/Effect";
4752
+ import * as Effect58 from "effect/Effect";
4699
4753
 
4700
4754
  // src/proxmox/sdn-subnet-form.ts
4701
4755
  var subnetId = (props) => `${props.zone}-${props.cidr.replace("/", "-")}`;
@@ -4755,11 +4809,11 @@ var handlers26 = pveHandlers({
4755
4809
  path: (props) => `cluster/sdn/vnets/${props.vnet}/subnets/${subnetId(props)}`,
4756
4810
  updateForm: updateForm2
4757
4811
  });
4758
- var ProxmoxSdnSubnetProvider = () => Provider31.effect(ProxmoxSdnSubnet, Effect57.succeed(ProxmoxSdnSubnet.Provider.of(handlers26)));
4812
+ var ProxmoxSdnSubnetProvider = () => Provider31.effect(ProxmoxSdnSubnet, Effect58.succeed(ProxmoxSdnSubnet.Provider.of(handlers26)));
4759
4813
  // src/proxmox/sdn-vnet.ts
4760
4814
  import { Resource as Resource32 } from "alchemy";
4761
4815
  import * as Provider32 from "alchemy/Provider";
4762
- import * as Effect58 from "effect/Effect";
4816
+ import * as Effect59 from "effect/Effect";
4763
4817
  var ProxmoxSdnVnet = Resource32("Proxmox.SdnVnet");
4764
4818
  var tagOf = (value) => typeof value === "number" ? value : undefined;
4765
4819
  var shape11 = (props) => {
@@ -4797,11 +4851,11 @@ var handlers27 = pveHandlers({
4797
4851
  path: (props) => `cluster/sdn/vnets/${props.vnet}`,
4798
4852
  updateForm: updateForm3
4799
4853
  });
4800
- var ProxmoxSdnVnetProvider = () => Provider32.effect(ProxmoxSdnVnet, Effect58.succeed(ProxmoxSdnVnet.Provider.of(handlers27)));
4854
+ var ProxmoxSdnVnetProvider = () => Provider32.effect(ProxmoxSdnVnet, Effect59.succeed(ProxmoxSdnVnet.Provider.of(handlers27)));
4801
4855
  // src/proxmox/sdn-zone.ts
4802
4856
  import { Resource as Resource33 } from "alchemy";
4803
4857
  import * as Provider33 from "alchemy/Provider";
4804
- import * as Effect59 from "effect/Effect";
4858
+ import * as Effect60 from "effect/Effect";
4805
4859
  var ProxmoxSdnZone = Resource33("Proxmox.SdnZone");
4806
4860
  var sameIpam = (live, declared2) => (live === "" ? "pve" : live) === (declared2 === undefined || declared2 === "" ? "pve" : declared2);
4807
4861
  var body6 = (props) => ({
@@ -4854,11 +4908,11 @@ var handlers28 = pveHandlers({
4854
4908
  return withClears(fields, clear);
4855
4909
  }
4856
4910
  });
4857
- var ProxmoxSdnZoneProvider = () => Provider33.effect(ProxmoxSdnZone, Effect59.succeed(ProxmoxSdnZone.Provider.of(handlers28)));
4911
+ var ProxmoxSdnZoneProvider = () => Provider33.effect(ProxmoxSdnZone, Effect60.succeed(ProxmoxSdnZone.Provider.of(handlers28)));
4858
4912
  // src/proxmox/storage.ts
4859
4913
  import { Resource as Resource34 } from "alchemy";
4860
4914
  import * as Provider34 from "alchemy/Provider";
4861
- import * as Effect60 from "effect/Effect";
4915
+ import * as Effect61 from "effect/Effect";
4862
4916
  var ProxmoxStorage = Resource34("Proxmox.Storage", {
4863
4917
  defaultRemovalPolicy: "retain"
4864
4918
  });
@@ -4904,14 +4958,14 @@ var handlers29 = pveHandlers({
4904
4958
  path: (props) => `storage/${props.storage}`,
4905
4959
  updateForm: mutable2
4906
4960
  });
4907
- var ProxmoxStorageProvider = () => Provider34.effect(ProxmoxStorage, Effect60.succeed(ProxmoxStorage.Provider.of(handlers29)));
4961
+ var ProxmoxStorageProvider = () => Provider34.effect(ProxmoxStorage, Effect61.succeed(ProxmoxStorage.Provider.of(handlers29)));
4908
4962
  // src/proxmox/zfs-pool.ts
4909
4963
  import { Resource as Resource35 } from "alchemy";
4910
4964
  import * as Provider35 from "alchemy/Provider";
4911
- import * as Effect62 from "effect/Effect";
4965
+ import * as Effect63 from "effect/Effect";
4912
4966
 
4913
4967
  // src/proxmox/zfs-pool-write.ts
4914
- import * as Effect61 from "effect/Effect";
4968
+ import * as Effect62 from "effect/Effect";
4915
4969
  var ZFS_POOL_ENDPOINT = { create: "pve:POST /nodes/{node}/disks/zfs" };
4916
4970
  var zfsPoolEndpoint = (props) => props.devices === undefined || props.raidlevel === undefined ? {} : ZFS_POOL_ENDPOINT;
4917
4971
  var createForm7 = (props) => ({
@@ -4923,24 +4977,24 @@ var createForm7 = (props) => ({
4923
4977
  ...props["draid-config"] === undefined ? {} : { "draid-config": props["draid-config"] }
4924
4978
  });
4925
4979
  var SETTLE_ATTEMPTS = 30;
4926
- var createPool = (props, collection2, path2, read4) => Effect61.gen(function* () {
4980
+ var createPool = (props, collection2, path2, read4) => Effect62.gen(function* () {
4927
4981
  const existing = yield* read4(props);
4928
4982
  if (existing !== undefined)
4929
4983
  return existing;
4930
4984
  if (props.devices === undefined || props.raidlevel === undefined) {
4931
- return yield* Effect61.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."));
4985
+ return yield* Effect62.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."));
4932
4986
  }
4933
4987
  const upid = yield* pve(props.target, "provision", "POST", collection2, createForm7(props));
4934
- const settle4 = (attempts) => Effect61.gen(function* () {
4988
+ const settle4 = (attempts) => Effect62.gen(function* () {
4935
4989
  const live = yield* read4(props);
4936
4990
  if (live !== undefined || attempts <= 0)
4937
4991
  return live;
4938
- yield* Effect61.sleep("2 seconds");
4992
+ yield* Effect62.sleep("2 seconds");
4939
4993
  return yield* settle4(attempts - 1);
4940
4994
  });
4941
4995
  const after = yield* settle4(SETTLE_ATTEMPTS);
4942
4996
  if (after === undefined) {
4943
- return yield* Effect61.die(new Error(`${path2}: POST returned ${text(upid, "(no UPID)")} but the pool has not appeared. That ` + "POST only forks a `zfscreate` worker, so the task holds the real error -- read it " + `with \`pvesh get /nodes/${props.node}/tasks/<upid>/log\`. NOTHING WAS RETRIED AND ` + "NOTHING WAS CLEANED UP: if the worker reached `zpool create`, the declared devices " + "have already been written to."));
4997
+ return yield* Effect62.die(new Error(`${path2}: POST returned ${text(upid, "(no UPID)")} but the pool has not appeared. That ` + "POST only forks a `zfscreate` worker, so the task holds the real error -- read it " + `with \`pvesh get /nodes/${props.node}/tasks/<upid>/log\`. NOTHING WAS RETRIED AND ` + "NOTHING WAS CLEANED UP: if the worker reached `zpool create`, the declared devices " + "have already been written to."));
4944
4998
  }
4945
4999
  return after;
4946
5000
  });
@@ -4975,15 +5029,15 @@ var spec2 = {
4975
5029
  var ProxmoxZfsPool = Resource35("Proxmox.ZfsPool", {
4976
5030
  defaultRemovalPolicy: "retain"
4977
5031
  });
4978
- var ops5 = pveOperations(spec2);
5032
+ var ops4 = pveOperations(spec2);
4979
5033
  var handlers30 = {
4980
5034
  ...pveHandlers(spec2),
4981
- delete: Effect62.fn(function* ({ olds }) {
5035
+ delete: Effect63.fn(function* ({ olds }) {
4982
5036
  yield* destroyPool(olds, spec2.path(olds));
4983
5037
  }),
4984
- reconcile: ({ news }) => createPool(news, spec2.collection(news), spec2.path(news), ops5.read)
5038
+ reconcile: ({ news }) => createPool(news, spec2.collection(news), spec2.path(news), ops4.read)
4985
5039
  };
4986
- var ProxmoxZfsPoolProvider = () => Provider35.effect(ProxmoxZfsPool, Effect62.succeed(ProxmoxZfsPool.Provider.of(handlers30)));
5040
+ var ProxmoxZfsPoolProvider = () => Provider35.effect(ProxmoxZfsPool, Effect63.succeed(ProxmoxZfsPool.Provider.of(handlers30)));
4987
5041
  export {
4988
5042
  PROVISION_DEFAULTS,
4989
5043
  PROVISION_PRIVILEGES,
@@ -5060,5 +5114,5 @@ export {
5060
5114
  violations
5061
5115
  };
5062
5116
 
5063
- //# debugId=F5942CE0240303BA64756E2164756E21
5117
+ //# debugId=FBBA36EF988E48B764756E2164756E21
5064
5118
  //# sourceMappingURL=index.js.map