@homeflare/alchemy 0.8.0 → 0.10.1

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 (247) hide show
  1. package/README.md +22 -11
  2. package/dist/caddy/config-lifecycle.d.ts +1 -1
  3. package/dist/caddy/config.d.ts.map +1 -1
  4. package/dist/caddy/index.js +221 -53
  5. package/dist/caddy/index.js.map +13 -9
  6. package/dist/launchd/fake-runner.d.ts +1 -0
  7. package/dist/launchd/fake-runner.d.ts.map +1 -1
  8. package/dist/launchd/fake-sudo.d.ts +1 -0
  9. package/dist/launchd/fake-sudo.d.ts.map +1 -1
  10. package/dist/launchd/host-effect.d.ts +9 -18
  11. package/dist/launchd/host-effect.d.ts.map +1 -1
  12. package/dist/launchd/host-file-lifecycle.d.ts +14 -1
  13. package/dist/launchd/host-file-lifecycle.d.ts.map +1 -1
  14. package/dist/launchd/host-file.d.ts +2 -1
  15. package/dist/launchd/host-file.d.ts.map +1 -1
  16. package/dist/launchd/index.js +345 -86
  17. package/dist/launchd/index.js.map +18 -12
  18. package/dist/launchd/job-lifecycle.d.ts +8 -1
  19. package/dist/launchd/job-lifecycle.d.ts.map +1 -1
  20. package/dist/launchd/job-preflight.d.ts +13 -1
  21. package/dist/launchd/job-preflight.d.ts.map +1 -1
  22. package/dist/launchd/job.d.ts +2 -1
  23. package/dist/launchd/job.d.ts.map +1 -1
  24. package/dist/launchd/runner.d.ts +7 -0
  25. package/dist/launchd/runner.d.ts.map +1 -1
  26. package/dist/launchd/sudo-acl.d.ts +25 -0
  27. package/dist/launchd/sudo-acl.d.ts.map +1 -0
  28. package/dist/launchd/sudo-guard.d.ts +31 -4
  29. package/dist/launchd/sudo-guard.d.ts.map +1 -1
  30. package/dist/launchd/sudo-runner.d.ts +3 -3
  31. package/dist/launchd/sudo-runner.d.ts.map +1 -1
  32. package/dist/launchd/sudo-said.d.ts +10 -0
  33. package/dist/launchd/sudo-said.d.ts.map +1 -0
  34. package/dist/openbao/auth-method-reconcile.d.ts +6 -2
  35. package/dist/openbao/auth-method-reconcile.d.ts.map +1 -1
  36. package/dist/openbao/auth-method.d.ts.map +1 -1
  37. package/dist/openbao/auth-role.d.ts.map +1 -1
  38. package/dist/openbao/cloudflare-role.d.ts.map +1 -1
  39. package/dist/openbao/fake-bao.d.ts +18 -0
  40. package/dist/openbao/fake-bao.d.ts.map +1 -1
  41. package/dist/openbao/fake-core.d.ts +39 -0
  42. package/dist/openbao/fake-core.d.ts.map +1 -0
  43. package/dist/openbao/fake-families.d.ts +6 -3
  44. package/dist/openbao/fake-families.d.ts.map +1 -1
  45. package/dist/openbao/fake-mounts.d.ts +16 -0
  46. package/dist/openbao/fake-mounts.d.ts.map +1 -0
  47. package/dist/openbao/fake-stack.d.ts +5 -1
  48. package/dist/openbao/fake-stack.d.ts.map +1 -1
  49. package/dist/openbao/index.js +541 -270
  50. package/dist/openbao/index.js.map +26 -21
  51. package/dist/openbao/jwt-config.d.ts.map +1 -1
  52. package/dist/openbao/jwt-role.d.ts.map +1 -1
  53. package/dist/openbao/kubernetes-role.d.ts.map +1 -1
  54. package/dist/openbao/mfa-enforcement.d.ts +6 -2
  55. package/dist/openbao/mfa-enforcement.d.ts.map +1 -1
  56. package/dist/openbao/mfa-totp.d.ts +6 -2
  57. package/dist/openbao/mfa-totp.d.ts.map +1 -1
  58. package/dist/openbao/mount-reconcile.d.ts +5 -1
  59. package/dist/openbao/mount-reconcile.d.ts.map +1 -1
  60. package/dist/openbao/mount.d.ts.map +1 -1
  61. package/dist/openbao/pki-role.d.ts.map +1 -1
  62. package/dist/openbao/plugin-reconcile.d.ts +6 -2
  63. package/dist/openbao/plugin-reconcile.d.ts.map +1 -1
  64. package/dist/openbao/plugin.d.ts.map +1 -1
  65. package/dist/openbao/policy.d.ts.map +1 -1
  66. package/dist/openbao/proxmox-role.d.ts.map +1 -1
  67. package/dist/openbao/role-reconcile.d.ts +11 -1
  68. package/dist/openbao/role-reconcile.d.ts.map +1 -1
  69. package/dist/openbao/ssh-role.d.ts.map +1 -1
  70. package/dist/ownership/adopt.d.ts +52 -0
  71. package/dist/ownership/adopt.d.ts.map +1 -0
  72. package/dist/ownership/probe.d.ts +13 -0
  73. package/dist/ownership/probe.d.ts.map +1 -0
  74. package/dist/ownership/resume.d.ts +40 -0
  75. package/dist/ownership/resume.d.ts.map +1 -0
  76. package/dist/ownership/rows.d.ts +33 -0
  77. package/dist/ownership/rows.d.ts.map +1 -0
  78. package/dist/ownership/whole.d.ts +14 -0
  79. package/dist/ownership/whole.d.ts.map +1 -0
  80. package/dist/proxmox/ceph-pool-form.d.ts +3 -3
  81. package/dist/proxmox/ceph-pool.d.ts.map +1 -1
  82. package/dist/proxmox/fake-bao-env.d.ts +3 -0
  83. package/dist/proxmox/fake-bao-env.d.ts.map +1 -0
  84. package/dist/proxmox/fake-pve-lxc.d.ts +42 -0
  85. package/dist/proxmox/fake-pve-lxc.d.ts.map +1 -0
  86. package/dist/proxmox/fake-pve.d.ts +38 -0
  87. package/dist/proxmox/fake-pve.d.ts.map +1 -0
  88. package/dist/proxmox/index.d.ts +6 -2
  89. package/dist/proxmox/index.d.ts.map +1 -1
  90. package/dist/proxmox/index.js +970 -186
  91. package/dist/proxmox/index.js.map +22 -9
  92. package/dist/proxmox/lxc-create-form.d.ts +6 -0
  93. package/dist/proxmox/lxc-create-form.d.ts.map +1 -0
  94. package/dist/proxmox/lxc-harness.d.ts +34 -0
  95. package/dist/proxmox/lxc-harness.d.ts.map +1 -0
  96. package/dist/proxmox/lxc-identity.d.ts +18 -0
  97. package/dist/proxmox/lxc-identity.d.ts.map +1 -0
  98. package/dist/proxmox/lxc-judge.d.ts +46 -0
  99. package/dist/proxmox/lxc-judge.d.ts.map +1 -0
  100. package/dist/proxmox/lxc-lifecycle.d.ts +68 -0
  101. package/dist/proxmox/lxc-lifecycle.d.ts.map +1 -0
  102. package/dist/proxmox/lxc-props.d.ts +139 -0
  103. package/dist/proxmox/lxc-props.d.ts.map +1 -0
  104. package/dist/proxmox/lxc-volume.d.ts +29 -0
  105. package/dist/proxmox/lxc-volume.d.ts.map +1 -0
  106. package/dist/proxmox/lxc-wire.d.ts +51 -0
  107. package/dist/proxmox/lxc-wire.d.ts.map +1 -0
  108. package/dist/proxmox/lxc.d.ts +27 -47
  109. package/dist/proxmox/lxc.d.ts.map +1 -1
  110. package/dist/proxmox/network-apply-read.d.ts +1 -1
  111. package/dist/proxmox/network-apply-read.d.ts.map +1 -1
  112. package/dist/proxmox/pbs-datastore.d.ts.map +1 -1
  113. package/dist/proxmox/resource.d.ts.map +1 -1
  114. package/dist/proxmox/update-guard.d.ts +27 -0
  115. package/dist/proxmox/update-guard.d.ts.map +1 -0
  116. package/dist/verify/args.d.ts +16 -0
  117. package/dist/verify/args.d.ts.map +1 -0
  118. package/dist/verify/cli.d.ts +3 -0
  119. package/dist/verify/cli.d.ts.map +1 -0
  120. package/dist/verify/cli.js +370 -0
  121. package/dist/verify/cli.js.map +17 -0
  122. package/dist/verify/fake-engine.d.ts +65 -0
  123. package/dist/verify/fake-engine.d.ts.map +1 -0
  124. package/dist/verify/index.d.ts +16 -0
  125. package/dist/verify/index.d.ts.map +1 -0
  126. package/dist/verify/index.js +347 -0
  127. package/dist/verify/index.js.map +16 -0
  128. package/dist/verify/plan-scope.d.ts +14 -0
  129. package/dist/verify/plan-scope.d.ts.map +1 -0
  130. package/dist/verify/recheck.d.ts +42 -0
  131. package/dist/verify/recheck.d.ts.map +1 -0
  132. package/dist/verify/report.d.ts +6 -0
  133. package/dist/verify/report.d.ts.map +1 -0
  134. package/dist/verify/rows.d.ts +67 -0
  135. package/dist/verify/rows.d.ts.map +1 -0
  136. package/dist/verify/spy.d.ts +43 -0
  137. package/dist/verify/spy.d.ts.map +1 -0
  138. package/dist/verify/verify.d.ts +43 -0
  139. package/dist/verify/verify.d.ts.map +1 -0
  140. package/docs/adopt-verify.md +119 -0
  141. package/docs/adopted-deploys.md +85 -0
  142. package/docs/credentials.md +15 -0
  143. package/docs/launchd-sudo.md +31 -6
  144. package/docs/launchd.md +7 -3
  145. package/docs/ownership.md +113 -0
  146. package/docs/proxmox-lxc.md +196 -0
  147. package/docs/proxmox.md +12 -0
  148. package/package.json +9 -2
  149. package/src/caddy/adopt-scope.test.ts +1 -1
  150. package/src/caddy/config-lifecycle.ts +1 -1
  151. package/src/caddy/config.ts +2 -1
  152. package/src/launchd/adopt-apply.test.ts +166 -0
  153. package/src/launchd/fake-runner.ts +26 -4
  154. package/src/launchd/host-effect.ts +1 -33
  155. package/src/launchd/host-file-lifecycle.ts +39 -14
  156. package/src/launchd/host-file.ts +13 -4
  157. package/src/launchd/job-lifecycle.ts +22 -14
  158. package/src/launchd/job-preflight.ts +18 -1
  159. package/src/launchd/job.ts +13 -4
  160. package/src/launchd/runner.ts +7 -0
  161. package/src/launchd/sudo-acl.ts +68 -0
  162. package/src/launchd/sudo-chain.test.ts +121 -0
  163. package/src/launchd/sudo-guard.ts +89 -10
  164. package/src/launchd/sudo-modes.test.ts +135 -0
  165. package/src/launchd/sudo-runner.ts +40 -59
  166. package/src/launchd/sudo-said.ts +58 -0
  167. package/src/openbao/README.md +5 -2
  168. package/src/openbao/REPLACE.md +13 -11
  169. package/src/openbao/adopt-core.test.ts +119 -0
  170. package/src/openbao/adopt-families.test.ts +97 -0
  171. package/src/openbao/adopt-holes.test.ts +168 -0
  172. package/src/openbao/adopt-recovery.test.ts +71 -0
  173. package/src/openbao/auth-method-reconcile.ts +15 -3
  174. package/src/openbao/auth-method.ts +15 -6
  175. package/src/openbao/auth-role.ts +14 -4
  176. package/src/openbao/cloudflare-role.ts +17 -4
  177. package/src/openbao/fake-bao.ts +52 -0
  178. package/src/openbao/fake-core.ts +141 -0
  179. package/src/openbao/fake-families.ts +11 -5
  180. package/src/openbao/fake-mounts.ts +74 -0
  181. package/src/openbao/fake-stack.ts +17 -4
  182. package/src/openbao/jwt-config.ts +10 -7
  183. package/src/openbao/jwt-role.ts +10 -7
  184. package/src/openbao/kubernetes-role.ts +13 -7
  185. package/src/openbao/mfa-enforcement.ts +20 -6
  186. package/src/openbao/mfa-totp.ts +22 -7
  187. package/src/openbao/mount-move.test.ts +2 -35
  188. package/src/openbao/mount-reconcile.ts +13 -2
  189. package/src/openbao/mount.ts +15 -6
  190. package/src/openbao/pki-role.ts +15 -4
  191. package/src/openbao/plugin-reconcile.ts +16 -5
  192. package/src/openbao/plugin.ts +17 -6
  193. package/src/openbao/policy.ts +17 -4
  194. package/src/openbao/proxmox-role.ts +13 -4
  195. package/src/openbao/rename-adoption.test.ts +32 -19
  196. package/src/openbao/role-reconcile.ts +23 -0
  197. package/src/openbao/ssh-role.ts +14 -4
  198. package/src/ownership/adopt.ts +122 -0
  199. package/src/ownership/ownership.test.ts +200 -0
  200. package/src/ownership/probe.ts +65 -0
  201. package/src/ownership/resume.ts +118 -0
  202. package/src/ownership/rows.ts +117 -0
  203. package/src/ownership/whole.test.ts +39 -0
  204. package/src/ownership/whole.ts +60 -0
  205. package/src/proxmox/adopt-noop.test.ts +112 -0
  206. package/src/proxmox/ceph-pool-adopt.test.ts +120 -0
  207. package/src/proxmox/ceph-pool-form.ts +3 -3
  208. package/src/proxmox/ceph-pool.ts +10 -3
  209. package/src/proxmox/fake-bao-env.ts +28 -0
  210. package/src/proxmox/fake-pve-lxc.ts +210 -0
  211. package/src/proxmox/fake-pve.ts +75 -0
  212. package/src/proxmox/index.test.ts +6 -6
  213. package/src/proxmox/index.ts +6 -2
  214. package/src/proxmox/lxc-adopt.test.ts +170 -0
  215. package/src/proxmox/lxc-create-form.ts +76 -0
  216. package/src/proxmox/lxc-create.test.ts +126 -0
  217. package/src/proxmox/lxc-guards.test.ts +158 -0
  218. package/src/proxmox/lxc-harness.ts +150 -0
  219. package/src/proxmox/lxc-identity.ts +43 -0
  220. package/src/proxmox/lxc-judge.test.ts +175 -0
  221. package/src/proxmox/lxc-judge.ts +196 -0
  222. package/src/proxmox/lxc-lifecycle.ts +200 -0
  223. package/src/proxmox/lxc-ownership.test.ts +159 -0
  224. package/src/proxmox/lxc-props.ts +215 -0
  225. package/src/proxmox/lxc-read.test.ts +60 -0
  226. package/src/proxmox/lxc-volume.test.ts +96 -0
  227. package/src/proxmox/lxc-volume.ts +153 -0
  228. package/src/proxmox/lxc-wire.ts +210 -0
  229. package/src/proxmox/lxc.ts +216 -93
  230. package/src/proxmox/network-apply-read.ts +3 -1
  231. package/src/proxmox/pbs-datastore.ts +4 -3
  232. package/src/proxmox/resource.ts +7 -7
  233. package/src/proxmox/update-guard.ts +31 -0
  234. package/src/verify/args.ts +82 -0
  235. package/src/verify/cli.test.ts +86 -0
  236. package/src/verify/cli.ts +49 -0
  237. package/src/verify/fake-engine.ts +182 -0
  238. package/src/verify/index.ts +37 -0
  239. package/src/verify/plan-scope.ts +34 -0
  240. package/src/verify/recheck.test.ts +56 -0
  241. package/src/verify/recheck.ts +71 -0
  242. package/src/verify/report.ts +52 -0
  243. package/src/verify/rows.ts +210 -0
  244. package/src/verify/spy.test.ts +141 -0
  245. package/src/verify/spy.ts +160 -0
  246. package/src/verify/verify.test.ts +146 -0
  247. package/src/verify/verify.ts +185 -0
@@ -0,0 +1,6 @@
1
+ import { type LxcProps } from './lxc-props.ts';
2
+ /** Why this declaration cannot be CREATED by an API token, if it cannot. */
3
+ export declare const createRefusals: (props: LxcProps) => string[];
4
+ /** The create body: every declared key with a value, plus the create-time instructions. */
5
+ export declare const createForm: (props: LxcProps) => Record<string, string>;
6
+ //# sourceMappingURL=lxc-create-form.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lxc-create-form.d.ts","sourceRoot":"","sources":["../../src/proxmox/lxc-create-form.ts"],"names":[],"mappings":"AAUA,OAAO,EACL,KAAK,QAAQ,EAMd,MAAM,gBAAgB,CAAC;AAiBxB,4EAA4E;AAC5E,eAAO,MAAM,cAAc,UAAW,QAAQ,KAAG,MAAM,EA2BtD,CAAC;AAEF,2FAA2F;AAC3F,eAAO,MAAM,UAAU,UAAW,QAAQ,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAUjE,CAAC"}
@@ -0,0 +1,34 @@
1
+ import * as Effect from 'effect/Effect';
2
+ import type { PveTarget } from './credentials.ts';
3
+ import { type FakePve } from './fake-pve-lxc.ts';
4
+ export declare const TARGET: PveTarget;
5
+ /**
6
+ * A PRODUCTION-SHAPED config — the same keys and the same spellings pvesh printed, PVE's defaults
7
+ * written out — with every VALUE a placeholder: TEST-NET addresses, RFC 7042 documentation MACs,
8
+ * and a made-up pool, VLAN, mount path, gid and sizes.
9
+ * ⛔ SHAPE ONLY. This file ships in the npm tarball (`files` includes `src`), so nothing here may be
10
+ * the estate's real topology — sizes, VLANs and bridges included, not only addresses.
11
+ */
12
+ export declare const LIVE: Readonly<Record<string, unknown>>;
13
+ /** Put `config` live on the fake as `node/vmid`, with a digest as PVE would add. */
14
+ export declare const seed: (fake: FakePve, node: string, vmid: number, config?: Readonly<Record<string, unknown>>) => void;
15
+ /** What the CLI would set for one run: `adopt` is `--adopt`. */
16
+ export type RunOptions = {
17
+ readonly adopt?: boolean;
18
+ };
19
+ export type Run = {
20
+ /** Planned action per FQN, deletions included; empty when the plan itself failed. */
21
+ readonly actions: Readonly<Record<string, string>>;
22
+ /** The failure sentence, or `''`. */
23
+ readonly failure: string;
24
+ readonly warnings: readonly string[];
25
+ };
26
+ export declare const lxcEngine: (fake: FakePve) => {
27
+ /** Plan only — what `alchemy plan` shows. Nothing is applied and no state is written. */
28
+ plan: (declare: Effect.Effect<unknown, unknown, unknown>, options?: RunOptions) => Promise<Run>;
29
+ /** Plan, then apply. */
30
+ deploy: (declare: Effect.Effect<unknown, unknown, unknown>, options?: RunOptions) => Promise<Run>;
31
+ /** The stored row's status, or undefined when there is none. */
32
+ status: (fqn: string) => "created" | "creating" | "deleting" | "replaced" | "replacing" | "updated" | "updating" | undefined;
33
+ };
34
+ //# sourceMappingURL=lxc-harness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lxc-harness.d.ts","sourceRoot":"","sources":["../../src/proxmox/lxc-harness.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAKxC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAElD,OAAO,EAAyB,KAAK,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAGxE,eAAO,MAAM,MAAM,EAAE,SAIpB,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAsBlD,CAAC;AAEF,oFAAoF;AACpF,eAAO,MAAM,IAAI,SAAU,OAAO,QAAQ,MAAM,QAAQ,MAAM,qDAE7D,CAAC;AAQF,gEAAgE;AAChE,MAAM,MAAM,UAAU,GAAG;IAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAEtD,MAAM,MAAM,GAAG,GAAG;IAChB,qFAAqF;IACrF,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACnD,qCAAqC;IACrC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC,CAAC;AAIF,eAAO,MAAM,SAAS,SAAU,OAAO;IA8CnC,yFAAyF;IACzF,IAAI,YAAY,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,YAAW,UAAU;IAE7E,wBAAwB;IACxB,MAAM,YAAY,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,YAAW,UAAU;IAE/E,gEAAgE;IAChE,MAAM,QAAQ,MAAM;CAEvB,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * What makes a `Proxmox.Lxc` a DIFFERENT guest: a new vmid, or another template. Judged by `diff`
3
+ * and `reconcile` in lxc.ts before anything else, and never planned as a replace — see lxc.ts.
4
+ */
5
+ import type { LxcAttributes, LxcProps } from './lxc-props.ts';
6
+ /**
7
+ * ⛔ IDENTITY IS JUDGED BEFORE `isResolved(news)`. That guard returns early when ANY prop is still
8
+ * an Output, and the engine then plans `update` — which, for a new vmid, would build a second
9
+ * guest and orphan the first (the openbao rename lesson, rename.ts). A template is identity
10
+ * too: it is consumed at create, so a different one is a different guest.
11
+ * ★ `node` IS NOT JUDGED HERE, BECAUSE A NODE CHANGE CAN BE THE DECLARATION CATCHING UP. HA fails
12
+ * a guest over, or somebody runs `pct migrate`; the guest is on its new node before any line
13
+ * says so. `readLive` at the declared node settles both cases: the guest is there (follow it,
14
+ * and re-record state with a write-free update), or it is elsewhere and the read FAILS naming
15
+ * where — asking to move a guest is a migration, and this resource does not migrate.
16
+ */
17
+ export declare const identityRefusals: (news: unknown, olds: LxcProps, output: LxcAttributes | undefined) => string[];
18
+ //# sourceMappingURL=lxc-identity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lxc-identity.d.ts","sourceRoot":"","sources":["../../src/proxmox/lxc-identity.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAQ9D;;;;;;;;;;GAUG;AACH,eAAO,MAAM,gBAAgB,SACrB,OAAO,QACP,QAAQ,UACN,aAAa,GAAG,SAAS,KAChC,MAAM,EAeR,CAAC"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Declared against live: what a deploy would write to a container, and what it must refuse.
3
+ *
4
+ * ★ ONE PURE FUNCTION DECIDES FOR BOTH `diff` AND `reconcile`, so the plan and the write cannot
5
+ * disagree about what is drift. This is resource.ts's `matches` guard grown up: an adopted guest
6
+ * that already says what the declaration says produces an empty change, and an empty change is
7
+ * not a write — adopting a running container must cost nothing.
8
+ *
9
+ * ⛔ SOME CHANGES NO API TOKEN CAN MAKE, AND THEY ARE REFUSED AT PLAN RATHER THAN 403'd MID-DEPLOY.
10
+ * `PVE::LXC::check_ct_modify_config_perm` (pve-container 6.1.14) returns early only for
11
+ * `$authuser eq 'root@pam'`, and a token's authuser is `root@pam!name` at best. So for a token:
12
+ * - `devN` — "configuring device passthrough is only allowed for root@pam";
13
+ * - a bind or device `mpN`/`rootfs` — "mount point type … is only allowed for root@pam";
14
+ * - `features` on a privileged guest, or any feature but `nesting` — root@pam only.
15
+ * Each refusal names the `pct set` to run on the node instead. After it, declare the value and
16
+ * the next plan compares it like any other key.
17
+ */
18
+ import { type LxcProps } from './lxc-props.ts';
19
+ export type LxcChange = {
20
+ /** Keys to `PUT …/config`, as PVE's wire strings. */
21
+ readonly put: Record<string, string>;
22
+ /** Keys to remove with `delete=`. */
23
+ readonly clear: readonly string[];
24
+ /** Mount points to grow, one `PUT …/resize` each, after the config PUT. */
25
+ readonly resize: readonly {
26
+ readonly disk: string;
27
+ readonly size: string;
28
+ }[];
29
+ /** Why the change cannot be made as an update. Non-empty means nothing is written. */
30
+ readonly refuse: readonly string[];
31
+ /** Every declared key that differs from live, refused or not — what a plan should name. */
32
+ readonly drift: readonly string[];
33
+ };
34
+ /** A refusal naming the `pct set` to run instead. `''` is a removal, so it names `--delete`. */
35
+ export declare const rootOnly: (vmid: number, key: string, value: string, why: string) => string;
36
+ /**
37
+ * PVE's own `features` rule, on the value actually SENT (`sent` undefined means `delete=features`):
38
+ * nesting alone needs `VM.Allocate`, anything else is root@pam's.
39
+ * ⚠️ MIRRORED KEY FOR KEY, DEFAULTS INCLUDED, because PVE does not drop them: a live `keyctl=0`
40
+ * against a sent value without `keyctl` is a change to PVE (`'0' ne ''`) and makes the write
41
+ * root-only. `scalarForm` drops off keys from what is sent for the same reason.
42
+ */
43
+ export declare const featuresNeedRoot: (live: string, sent: string | undefined, unprivileged: boolean) => boolean;
44
+ export declare const featureWhy: (unprivileged: boolean) => string;
45
+ export declare const judge: (props: LxcProps, live: Record<string, unknown>) => LxcChange;
46
+ //# sourceMappingURL=lxc-judge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lxc-judge.d.ts","sourceRoot":"","sources":["../../src/proxmox/lxc-judge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EACL,KAAK,QAAQ,EAMd,MAAM,gBAAgB,CAAC;AAexB,MAAM,MAAM,SAAS,GAAG;IACtB,qDAAqD;IACrD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,qCAAqC;IACrC,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,EAAE,SAAS;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC7E,sFAAsF;IACtF,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,2FAA2F;IAC3F,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC,CAAC;AAKF,gGAAgG;AAChG,eAAO,MAAM,QAAQ,SAAU,MAAM,OAAO,MAAM,SAAS,MAAM,OAAO,MAAM,KAAG,MAGhD,CAAC;AAQlC;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,SACrB,MAAM,QACN,MAAM,GAAG,SAAS,gBACV,OAAO,KACpB,OASF,CAAC;AAEF,eAAO,MAAM,UAAU,iBAAkB,OAAO,KAAG,MACoC,CAAC;AAExF,eAAO,MAAM,KAAK,UAAW,QAAQ,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,SAmGtE,CAAC"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * The calls a `Proxmox.Lxc` makes: read one config, create, update in place, grow, delete.
3
+ *
4
+ * ⛔ A READ FAILURE IS A FAILURE HERE, NOT "ABSENT" — THE ONE PLACE THIS PACKAGE DEPARTS FROM
5
+ * resource.ts. `pveOperations.read` folds every error into `undefined`, which for a guest means a
6
+ * 403 or a node that did not answer plans a CREATE over a running container. PVE answers a
7
+ * missing guest with HTTP 500, `Configuration file 'nodes/<node>/lxc/<vmid>.conf' does not
8
+ * exist` (pve-guest-common `AbstractConfig::load_config`), so only a 500 may mean absent — and
9
+ * even then only after the cluster says so, below. Anything else fails the plan.
10
+ *
11
+ * ⛔ "ABSENT" IS DECIDED BY THE WHOLE CLUSTER, NOT BY THE ERROR TEXT. A config lives under its
12
+ * node, so a guest migrated to another node — or a QEMU VM holding the same cluster-wide vmid —
13
+ * also reads as missing at the declared path. `GET /cluster/resources?type=vm` settles it: the
14
+ * vmid nowhere is absent; the vmid anywhere else FAILS the read with where it is; the vmid on
15
+ * the declared node fails with PVE's own error. ★ Keyed on the cluster rather than on matching
16
+ * the message, so a PVE that words it differently still cannot turn into a create.
17
+ *
18
+ * ⚠️ CREATE, RESIZE AND DELETE ARE ASYNCHRONOUS; A CONFIG PUT IS NOT. The first three answer a
19
+ * UPID the moment PVE forks the worker (`NodesNodeLxcPostReturn`, `…ResizePutReturn`,
20
+ * `…VmidDeleteReturn` are all `string`), so each waits for its task's exitstatus. `PUT …/config`
21
+ * answers `null` after writing (`…ConfigPutReturn`), so it needs no wait.
22
+ * ⛔ EACH TASK IS POLLED WITH THE CREDENTIAL THAT STARTED IT — see `awaitTask`: only the owner
23
+ * skips `Sys.Audit`. A fresh `provision` mint per write gives the full 300s lease a create needs;
24
+ * a cached lease can be handed out with 60s left (lease-cache.ts).
25
+ */
26
+ import * as Effect from 'effect/Effect';
27
+ import { type PveTarget } from './credentials.ts';
28
+ import { type LxcChange } from './lxc-judge.ts';
29
+ import type { LxcAttributes, LxcProps } from './lxc-props.ts';
30
+ /** A plan-time or apply-time refusal. Nothing was written when one of these is raised. */
31
+ export declare class LxcRefusedError extends Error {
32
+ readonly name = "LxcRefusedError";
33
+ }
34
+ /** Where one guest lives. Its identity, and nothing else. */
35
+ export type LxcWhere = {
36
+ readonly target: PveTarget;
37
+ readonly node: string;
38
+ readonly vmid: number;
39
+ };
40
+ export declare const guestPath: (where: LxcWhere) => string;
41
+ /** The live config, or undefined when no guest holds this vmid anywhere in the cluster. */
42
+ export declare const readLive: (where: LxcWhere) => Effect.Effect<Record<string, unknown> | undefined, Error | LxcRefusedError, import("effect/unstable/http/HttpClient").HttpClient>;
43
+ export declare const attributesOf: (where: LxcWhere, live: Record<string, unknown>) => LxcAttributes;
44
+ /** POST the create and wait for the template to unpack. ⛔ Refusals are the caller's to check. */
45
+ export declare const createGuest: (props: LxcProps) => Effect.Effect<undefined, Error | LxcRefusedError, import("effect/unstable/http/HttpClient").HttpClient>;
46
+ /**
47
+ * Apply a judged change: the config PUT first, then each resize.
48
+ * ⚠️ IN THAT ORDER BECAUSE A MOUNT POINT'S PUT CARRIES ITS LIVE `size=`, and the resize rewrites it.
49
+ * ⛔ THE PUT CARRIES THE `digest` OF THE CONFIG IT WAS JUDGED AGAINST. PVE refuses the write if the
50
+ * file changed since (`assert_if_modified`), so an edit landing between reconcile's own read and
51
+ * its PUT fails the deploy instead of being overwritten by a change computed from the older file.
52
+ * ⚠️ THE DIGEST IS THE DEPLOY'S READ, NOT THE PLAN'S. A hand edit between `plan` and `deploy` is
53
+ * seen by reconcile's fresh judge instead: a declared key edited meanwhile is written back to the
54
+ * declaration (even after a plan that warned of nothing), an undeclared one is left alone.
55
+ */
56
+ export declare const updateGuest: (props: LxcProps, change: LxcChange, digest: string) => Effect.Effect<void, Error | LxcRefusedError, import("effect/unstable/http/HttpClient").HttpClient>;
57
+ /**
58
+ * ⛔ NO `force`, NO `purge`, NO STOP FIRST. PVE refuses to destroy a running or protected guest,
59
+ * and that refusal is kept: stopping a guest so a delete can proceed is an operator's decision.
60
+ * Reached only under `RemovalPolicy.destroy()` — this resource retains by default.
61
+ * ⛔ AND ONLY THE GUEST THIS STACK DECLARED. State holds a vmid, and a vmid is reusable: after a
62
+ * hand `pct destroy` and a new `pct create` at the same id, "delete CT 150" is somebody else's
63
+ * container and all its volumes. So the live guest is judged against the last declaration
64
+ * first; one that no longer matches is refused with the keys that differ, and deleting it (or
65
+ * declaring it again) is the operator's call.
66
+ */
67
+ export declare const destroyGuest: (where: LxcWhere, declared: LxcProps) => Effect.Effect<undefined, Error | LxcRefusedError, import("effect/unstable/http/HttpClient").HttpClient>;
68
+ //# sourceMappingURL=lxc-lifecycle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lxc-lifecycle.d.ts","sourceRoot":"","sources":["../../src/proxmox/lxc-lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,EAAE,KAAK,SAAS,EAAQ,MAAM,kBAAkB,CAAC;AAExD,OAAO,EAAE,KAAK,SAAS,EAAS,MAAM,gBAAgB,CAAC;AACvD,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAK9D,0FAA0F;AAC1F,qBAAa,eAAgB,SAAQ,KAAK;IACxC,SAAkB,IAAI,qBAAqB;CAC5C;AAED,6DAA6D;AAC7D,MAAM,MAAM,QAAQ,GAAG;IAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpG,eAAO,MAAM,SAAS,UAAW,QAAQ,WAAoD,CAAC;AAY9F,2FAA2F;AAC3F,eAAO,MAAM,QAAQ,UAAW,QAAQ,sIAqCpC,CAAC;AAEL,eAAO,MAAM,YAAY,UAAW,QAAQ,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,aAK5E,CAAC;AAgCH,iGAAiG;AACjG,eAAO,MAAM,WAAW,UAAW,QAAQ,4GAQxC,CAAC;AAEJ;;;;;;;;;GASG;AACH,eAAO,MAAM,WAAW,UAAW,QAAQ,UAAU,SAAS,UAAU,MAAM,uGAmB1E,CAAC;AAEL;;;;;;;;;GASG;AACH,eAAO,MAAM,YAAY,UAAW,QAAQ,YAAY,QAAQ,4GAe5D,CAAC"}
@@ -0,0 +1,139 @@
1
+ import type { WithTarget } from './resource.ts';
2
+ /** A PVE boolean as pvesh prints it (`1`) or as TypeScript writes it (`true`). The same value. */
3
+ export type PveFlag = boolean | 0 | 1;
4
+ export interface LxcProps extends WithTarget {
5
+ /**
6
+ * The node that hosts it. ⛔ This resource never migrates: naming another node plans only when
7
+ * the guest is already there (after HA or `pct migrate`), and then writes nothing.
8
+ */
9
+ node: string;
10
+ /** ⛔ CLUSTER-WIDE primary key, shared with QEMU VMs. Required, never allocated here. */
11
+ vmid: number;
12
+ /**
13
+ * `local:vztmpl/debian-13-standard_13.1-2_amd64.tar.zst`. ⚠️ CREATE-ONLY AND NOT READABLE BACK:
14
+ * PVE consumes it while unpacking the rootfs. Optional, because an adopted guest was built from a
15
+ * template nobody recorded; required only when this resource has to create the guest.
16
+ */
17
+ ostemplate?: string;
18
+ /** Start the guest once, after its create finishes (PVE's create `start`). ⚠️ Never compared. */
19
+ start?: PveFlag;
20
+ /**
21
+ * ⛔ READ-ONLY AFTER CREATE. PVE refuses to change it ("unable to modify read-only option"), so a
22
+ * differing value is refused at plan. Absent from a live config means `0`: privileged. On create,
23
+ * PVE's own default is `1`.
24
+ */
25
+ unprivileged?: PveFlag;
26
+ hostname?: string;
27
+ arch?: string;
28
+ ostype?: string;
29
+ cores?: number;
30
+ /** `0` means no limit. May be fractional (`1.5`). */
31
+ cpulimit?: number;
32
+ cpuunits?: number;
33
+ /** MiB. */
34
+ memory?: number;
35
+ /** MiB. */
36
+ swap?: number;
37
+ /**
38
+ * `local-zfs:subvol-100-disk-0,size=40G` as read, or `local-zfs:40` (40 GiB, new volume) to
39
+ * create. See lxc-volume.ts for what may change: options in place, size up only.
40
+ */
41
+ rootfs?: string;
42
+ /** `nesting=1,keyctl=1`. ⛔ Only `nesting` is writable by an API token — see lxc-judge.ts. */
43
+ features?: string;
44
+ onboot?: PveFlag;
45
+ /** `order=1,up=30,down=60`. */
46
+ startup?: string;
47
+ protection?: PveFlag;
48
+ /** Free text. ⚠️ PVE stores it as `#` comment lines and hands it back with a trailing newline. */
49
+ description?: string;
50
+ /** `a;b`. ⚠️ Compared as a set; PVE sorts and, by default, lowercases them. */
51
+ tags?: string;
52
+ /** Space-separated. Order is meaningful to a resolver, so it is compared in order. */
53
+ nameserver?: string;
54
+ searchdomain?: string;
55
+ timezone?: string;
56
+ console?: PveFlag;
57
+ tty?: number;
58
+ cmode?: string;
59
+ /** `tank:subvol-100-disk-1,mp=/data,backup=1,size=100G`, or `tank:100,mp=/data` to create. */
60
+ [mount: `mp${number}`]: string | undefined;
61
+ /** `name=eth0,bridge=vmbr0,ip=dhcp`. ⚠️ An undeclared `hwaddr` keeps the live MAC. */
62
+ [nic: `net${number}`]: string | undefined;
63
+ /** `/dev/net/tun`, `/dev/dri/renderD128,gid=44,mode=0660`. ⛔ root@pam only — see lxc-judge.ts. */
64
+ [device: `dev${number}`]: string | undefined;
65
+ /** ⛔ A secret. See the header. */
66
+ password?: never;
67
+ /** ⛔ Treated as a secret here. See the header. */
68
+ 'ssh-public-keys'?: never;
69
+ /** ⛔ Can carry anything, and a read token cannot even see it. See the header. */
70
+ env?: never;
71
+ }
72
+ export interface LxcAttributes {
73
+ node: string;
74
+ vmid: number;
75
+ /**
76
+ * The live config, each value as PVE's own string: every key this resource MANAGES
77
+ * (`isManagedKey`), declared or not, minus the keys in `UNSTORED`.
78
+ * ★ A MAP RATHER THAN TYPED FIELDS so a plan can show whatever managed key the guest carries.
79
+ * ⛔ AN ALLOWLIST, NOT "EVERYTHING BUT A DENYLIST" — see `storedConfig`.
80
+ */
81
+ config: Record<string, string>;
82
+ /**
83
+ * The raw `lxc.*` lines in the guest's config file — NAMES ONLY.
84
+ * ⚠️ A GAP, NOT A FEATURE: PVE's API returns these but cannot set them (`lxc.prlimit.memlock`,
85
+ * `lxc.cgroup2.devices.allow`, `lxc.mount.entry`). They are edited in `/etc/pve/lxc/<vmid>.conf`
86
+ * on the node, so this resource reports that they exist and never compares them. ⛔ Values are
87
+ * not stored: `lxc.environment` is one of the keys PVE allows there.
88
+ */
89
+ rawKeys: string[];
90
+ }
91
+ /**
92
+ * Keys a read returns that state never keeps.
93
+ * ⚠️ `digest` covers the whole file and `lock` is transient (a running backup), so either would
94
+ * rewrite state on every read; `env` and `lxc` are the secret risks in the header and above.
95
+ * ⛔ `description` IS THE GUEST'S "NOTES" PANEL IN THE PVE UI, where people paste credentials. A
96
+ * declared one is already in props; an undeclared one is not this resource's to copy into an
97
+ * unencrypted state store.
98
+ */
99
+ export declare const UNSTORED: ReadonlySet<string>;
100
+ /** The indexed families, with PVE's own limits (pve-container `$MAX_*`, 6.1.14). */
101
+ export declare const INDEXED: {
102
+ readonly dev: 256;
103
+ readonly mp: 256;
104
+ readonly net: 32;
105
+ };
106
+ export type IndexedFamily = keyof typeof INDEXED;
107
+ /** `mp3` → `['mp', 3]`; anything else → undefined. ⚠️ `mp03` is not a PVE key. */
108
+ export declare const indexedKey: (key: string) => readonly [IndexedFamily, number] | undefined;
109
+ /** Props that are not config keys: where the guest lives, and create-time instructions. */
110
+ export declare const NOT_CONFIG: ReadonlySet<string>;
111
+ /**
112
+ * A declaration read by key. ⚠️ The cast is the one place the three template-literal index
113
+ * signatures meet a plain string key; every reader goes through here rather than casting again.
114
+ */
115
+ export declare const declaredValue: (props: LxcProps, key: string) => unknown;
116
+ /** The declared config keys with a value, in a stable order. `''` counts: it means "absent". */
117
+ export declare const declaredKeys: (props: LxcProps) => string[];
118
+ /** One declared value as PVE's wire string. Booleans go as `1`/`0`, numbers as their decimal. */
119
+ export declare const wireValue: (value: unknown) => string;
120
+ /**
121
+ * A key this resource compares and may write: a scalar lxc-wire.ts knows, `unprivileged`, `rootfs`,
122
+ * or an indexed `mpN`/`netN`/`devN`. ★ ONE PREDICATE FOR THE THREE PLACES THAT ASK: `judge` refuses
123
+ * any other declared key, `createRefusals` refuses it before a POST, and `storedConfig` keeps
124
+ * nothing else. ⛔ Without the create half, a key smuggled past the types (a cast, a JS caller:
125
+ * `password`, `force`, `restore`, `hookscript`) went into the create body verbatim.
126
+ */
127
+ export declare const isManagedKey: (key: string) => boolean;
128
+ /**
129
+ * The live config as strings: managed keys only, the unstored ones dropped.
130
+ * ⛔ AN ALLOWLIST, BECAUSE A DENYLIST IS SURPRISED BY THE NEXT PVE RELEASE. `env` joined the config
131
+ * in PVE 9 with application containers, and `entrypoint` with it — a command line, which can
132
+ * carry a token as an argument. Under "store everything except UNSTORED" each new key lands in
133
+ * the unencrypted state store until somebody notices; under this, it is not stored until this
134
+ * resource manages it. `hookscript`, `unusedN`, `parent` and `lock` are dropped the same way.
135
+ */
136
+ export declare const storedConfig: (live: Record<string, unknown>) => Record<string, string>;
137
+ /** `[["lxc.prlimit.memlock","unlimited"]]` → `['lxc.prlimit.memlock']`. Values are dropped. */
138
+ export declare const rawKeysOf: (live: Record<string, unknown>) => string[];
139
+ //# sourceMappingURL=lxc-props.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lxc-props.d.ts","sourceRoot":"","sources":["../../src/proxmox/lxc-props.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD,kGAAkG;AAClG,MAAM,MAAM,OAAO,GAAG,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC;AAEtC,MAAM,WAAW,QAAS,SAAQ,UAAU;IAC1C;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,wFAAwF;IACxF,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iGAAiG;IACjG,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW;IACX,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6FAA6F;IAC7F,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,+BAA+B;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,kGAAkG;IAClG,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+EAA+E;IAC/E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sFAAsF;IACtF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8FAA8F;IAC9F,CAAC,KAAK,EAAE,KAAK,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAAC;IAC3C,sFAAsF;IACtF,CAAC,GAAG,EAAE,MAAM,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAAC;IAC1C,kGAAkG;IAClG,CAAC,MAAM,EAAE,MAAM,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAAC;IAC7C,kCAAkC;IAClC,QAAQ,CAAC,EAAE,KAAK,CAAC;IACjB,kDAAkD;IAClD,iBAAiB,CAAC,EAAE,KAAK,CAAC;IAC1B,iFAAiF;IACjF,GAAG,CAAC,EAAE,KAAK,CAAC;CACb;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb;;;;;OAKG;IACH,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B;;;;;;OAMG;IACH,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,QAAQ,EAAE,WAAW,CAAC,MAAM,CAOvC,CAAC;AAEH,oFAAoF;AACpF,eAAO,MAAM,OAAO;aAClB,GAAG,EAAE,GAAG;aACR,EAAE,EAAE,GAAG;aACP,GAAG,EAAE,EAAE;CACC,CAAC;AAEX,MAAM,MAAM,aAAa,GAAG,MAAM,OAAO,OAAO,CAAC;AAEjD,kFAAkF;AAClF,eAAO,MAAM,UAAU,QAAS,MAAM,KAAG,SAAS,CAAC,aAAa,EAAE,MAAM,CAAC,GAAG,SAM3E,CAAC;AAEF,2FAA2F;AAC3F,eAAO,MAAM,UAAU,EAAE,WAAW,CAAC,MAAM,CAMzC,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,aAAa,UAAW,QAAQ,OAAO,MAAM,KAAG,OACT,CAAC;AAErD,gGAAgG;AAChG,eAAO,MAAM,YAAY,UAAW,QAAQ,KAAG,MAAM,EAG1C,CAAC;AAEZ,iGAAiG;AACjG,eAAO,MAAM,SAAS,UAAW,OAAO,KAAG,MACmB,CAAC;AAE/D;;;;;;GAMG;AACH,eAAO,MAAM,YAAY,QAAS,MAAM,KAAG,OAIZ,CAAC;AAEhC;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY,SAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAQjF,CAAC;AAEF,+FAA+F;AAC/F,eAAO,MAAM,SAAS,SAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,MAAM,EAM/D,CAAC"}
@@ -0,0 +1,29 @@
1
+ /** PVE's `parse_size`: `\d+(\.\d+)?[KMGT]?`, binary units, bare means bytes. */
2
+ export declare const sizeBytes: (text: string) => number | undefined;
3
+ export type Volume = {
4
+ readonly kind: 'new' | 'volume' | 'bind' | 'device';
5
+ /** `new`/`volume`: the storage id. `bind`/`device`: the host path. */
6
+ readonly source: string;
7
+ /** `volume` only: the name after `storage:`. */
8
+ readonly volname: string;
9
+ /** From `size=`, or the new-disk GiB. Undefined when neither says. */
10
+ readonly size: number | undefined;
11
+ /** The size as written, for a resize request. */
12
+ readonly sizeText: string | undefined;
13
+ /** Every other option, comparable. */
14
+ readonly options: Map<string, string>;
15
+ };
16
+ /** PVE's `classify_mountpoint`, plus the new-disk spelling a declaration may use. */
17
+ export declare const parseVolume: (text: string) => Volume;
18
+ /** What one mount point needs. At most one of `refuse` / `rootOnly` is set, and then nothing else. */
19
+ export type VolumeVerdict = {
20
+ readonly refuse?: string;
21
+ readonly rootOnly?: boolean;
22
+ /** The value to PUT, built on the LIVE volume id. */
23
+ readonly put?: string;
24
+ /** An absolute size to hand `PUT …/resize`, which only ever grows. */
25
+ readonly resize?: string;
26
+ };
27
+ export declare const isHostPath: (volume: Volume) => boolean;
28
+ export declare const judgeVolume: (key: string, declared: string, live: string) => VolumeVerdict;
29
+ //# sourceMappingURL=lxc-volume.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lxc-volume.d.ts","sourceRoot":"","sources":["../../src/proxmox/lxc-volume.ts"],"names":[],"mappings":"AAgCA,gFAAgF;AAChF,eAAO,MAAM,SAAS,SAAU,MAAM,KAAG,MAAM,GAAG,SAIjD,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG;IACnB,QAAQ,CAAC,IAAI,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;IACpD,sEAAsE;IACtE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,gDAAgD;IAChD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,sEAAsE;IACtE,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,iDAAiD;IACjD,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,sCAAsC;IACtC,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACvC,CAAC;AAEF,qFAAqF;AACrF,eAAO,MAAM,WAAW,SAAU,MAAM,KAAG,MAiC1C,CAAC;AAEF,sGAAsG;AACtG,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,qDAAqD;IACrD,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,sEAAsE;IACtE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF,eAAO,MAAM,UAAU,WAAY,MAAM,YAAuD,CAAC;AAcjG,eAAO,MAAM,WAAW,QAAS,MAAM,YAAY,MAAM,QAAQ,MAAM,KAAG,aAuCzE,CAAC"}
@@ -0,0 +1,51 @@
1
+ /** `a=1,b=2` → `[['a','1'],['b','2']]`. A bare token is `defaultKey`'s value. */
2
+ export declare const pairs: (value: string, defaultKey?: string) => [string, string][];
3
+ /**
4
+ * A key's default, per family: the value PVE treats absence as.
5
+ * ⚠️ `replicate` DEFAULTS ON and everything else here defaults off. `backup` on a mount point is
6
+ * off when absent: vzdump skips any `mpN` without `backup=1` (the rootfs is always included).
7
+ */
8
+ declare const DEFAULTS: Readonly<Record<string, Readonly<Record<string, string>>>>;
9
+ /** A property string as a map of comparable values, with `family`'s defaults dropped. */
10
+ export declare const optionMap: (value: string, family: keyof typeof DEFAULTS, defaultKey?: string) => Map<string, string>;
11
+ export declare const sameMap: (left: Map<string, string>, right: Map<string, string>) => boolean;
12
+ /** A map as one order-free string, for comparing and for naming a value in a message. */
13
+ export declare const sortedForm: (map: Map<string, string>) => string;
14
+ /** A map back to a property string, `lead` keys first — PVE wants `name` and the volume first. */
15
+ export declare const printMap: (map: Map<string, string>, lead?: readonly string[]) => string;
16
+ /**
17
+ * `net` maps for comparison. ⚠️ AN UNDECLARED `hwaddr` IS PVE'S, NOT DRIFT: PVE generates one on
18
+ * create, so the live MAC is dropped before comparing when the declaration names none.
19
+ */
20
+ export declare const netMaps: (declared: string, live: string) => {
21
+ have: Map<string, string>;
22
+ want: Map<string, string>;
23
+ };
24
+ /**
25
+ * The `net` value to PUT: the declaration, plus the live MAC when it names none.
26
+ * ⛔ WITHOUT THE LIVE MAC, A PUT OF AN UNCHANGED NIC WOULD GENERATE A NEW ONE — a new MAC is a new
27
+ * DHCP lease and a new IPv6 link-local address for a guest that only had its MTU edited.
28
+ */
29
+ export declare const netWrite: (declared: string, live: string | undefined) => string;
30
+ /** Tags as PVE stores them: split on `;`, `,` or space, deduplicated, sorted, lower-cased. */
31
+ export declare const tagSet: (value: string) => string;
32
+ /** A resolver list: order matters, the separator does not. */
33
+ export declare const orderedList: (value: string) => string;
34
+ /**
35
+ * ⚠️ PVE STORES A DESCRIPTION AS `#` COMMENT LINES AND READS EACH BACK WITH `"\n"` APPENDED
36
+ * (`parse_pct_config`), so `foo` comes back `foo\n`. Trailing whitespace is not the value.
37
+ */
38
+ export declare const descriptionText: (value: string) => string;
39
+ /** How each scalar config key is compared. A key missing here is not one this resource manages. */
40
+ export declare const SCALAR_KINDS: Readonly<Record<string, 'text' | 'number' | 'flag' | 'form'>>;
41
+ /** Keys a declaration may set to `''` to mean "remove it". `delete=` takes them; nothing else may. */
42
+ export declare const CLEARABLE: ReadonlySet<string>;
43
+ /**
44
+ * What an absent key means, from the confdesc defaults. ⚠️ Only these compare equal to absence;
45
+ * `cores` absent means "every host core", which no number declares.
46
+ */
47
+ export declare const SCALAR_DEFAULTS: Readonly<Record<string, string>>;
48
+ /** One scalar value in its comparable spelling. */
49
+ export declare const scalarForm: (key: string, value: string) => string;
50
+ export {};
51
+ //# sourceMappingURL=lxc-wire.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lxc-wire.d.ts","sourceRoot":"","sources":["../../src/proxmox/lxc-wire.ts"],"names":[],"mappings":"AAiBA,iFAAiF;AACjF,eAAO,MAAM,KAAK,UAAW,MAAM,eAAe,MAAM,KAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EASrE,CAAC;AAEP;;;;GAIG;AACH,QAAA,MAAM,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAKxE,CAAC;AAkCF,yFAAyF;AACzF,eAAO,MAAM,SAAS,UACb,MAAM,UACL,MAAM,OAAO,QAAQ,eAChB,MAAM,KAClB,GAAG,CAAC,MAAM,EAAE,MAAM,CAQpB,CAAC;AAEF,eAAO,MAAM,OAAO,SAAU,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,SAAS,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,YACY,CAAC;AAE1F,yFAAyF;AACzF,eAAO,MAAM,UAAU,QAAS,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,WAIrC,CAAC;AAEf,kGAAkG;AAClG,eAAO,MAAM,QAAQ,QAAS,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,SAAQ,SAAS,MAAM,EAAE,WAG5D,CAAC;AAEf;;;GAGG;AACH,eAAO,MAAM,OAAO,aAAc,MAAM,QAAQ,MAAM;;;CAKrD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,QAAQ,aAAc,MAAM,QAAQ,MAAM,GAAG,SAAS,WAKlE,CAAC;AAEF,8FAA8F;AAC9F,eAAO,MAAM,MAAM,UAAW,MAAM,WAItB,CAAC;AAEf,8DAA8D;AAC9D,eAAO,MAAM,WAAW,UAAW,MAAM,WAI3B,CAAC;AAEf;;;GAGG;AACH,eAAO,MAAM,eAAe,UAAW,MAAM,WAA8B,CAAC;AAE5E,mGAAmG;AACnG,eAAO,MAAM,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAC,CAqBtF,CAAC;AAEF,sGAAsG;AACtG,eAAO,MAAM,SAAS,EAAE,WAAW,CAAC,MAAM,CAQxC,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAU5D,CAAC;AAEF,mDAAmD;AACnD,eAAO,MAAM,UAAU,QAAS,MAAM,SAAS,MAAM,KAAG,MAUvD,CAAC"}
@@ -1,59 +1,39 @@
1
1
  /**
2
- * `Proxmox.Lxc` — a container, declared. This is what the estate's provision credential exists for.
2
+ * `Proxmox.Lxc` — a container, declared: adopted as it runs, or created from a template.
3
3
  *
4
- * ★ `hf-provision@pve` HOLDS EXACTLY THE ROLE THIS NEEDS, and nothing more: `LXCProvisioner` on `/`
5
- * grants VM.Allocate, VM.Audit, VM.Config.{CPU,Disk,HWType,Memory,Network,Options},
6
- * VM.PowerMgmt, Datastore.AllocateSpace, Datastore.Audit, SDN.Use, Sys.Audit. Read that list as a
7
- * specification: the credential was scoped to provision containers and to do nothing else.
4
+ * ★ `hf-provision@pve` HOLDS EXACTLY THE ROLE THIS NEEDS: `LXCProvisioner` on `/` grants
5
+ * VM.Allocate, VM.Audit, VM.Config.{CPU,Disk,HWType,Memory,Network,Options}, VM.PowerMgmt,
6
+ * Datastore.AllocateSpace, Datastore.Audit, SDN.Use, Sys.Audit. What that role cannot do — device
7
+ * passthrough, bind mounts, features beyond nesting — PVE keeps for root@pam, and lxc-judge.ts
8
+ * refuses at plan with the `pct set` to run instead.
8
9
  *
9
- * ⛔ `vmid` IS THE PRIMARY KEY AND IT IS CLUSTER-WIDE, not per node. Two resources declaring the
10
- * same vmid on different nodes are the same object, and PVE will refuse the second with
11
- * "already exists". It is required rather than allocated here: letting the provider pick the next
12
- * free id would make the identity of a container depend on the order plans happened to run in.
10
+ * ⛔ NOTHING HERE PLANS A REPLACE, AND NOTHING DESTROYS A GUEST BY DEFAULT. A replace of a guest is
11
+ * a delete of a running machine and its disks, so every change PVE cannot make in place — a new
12
+ * vmid, another template, an unprivileged flip, a storage move, a smaller disk, a move to
13
+ * another node — FAILS the plan with a sentence instead. `defaultRemovalPolicy: 'retain'`:
14
+ * dropping the declaration drops the state row and leaves the guest running; only
15
+ * `RemovalPolicy.destroy()` reaches `destroyGuest`, which deletes only a guest that still
16
+ * matches its last declaration, and PVE still refuses a running or protected one.
17
+ * ⛔ AND NOTHING HERE WRITES A VOLUME IT DID NOT ALLOCATE. A create takes `storage:GiB` only
18
+ * (lxc-create-form.ts), and a deploy that planned a create never writes onto a guest it finds.
13
19
  *
14
- * ⚠️ MOST FIELDS ARE CREATE-TIME. `ostemplate` and `storage` are consumed when the rootfs is built
15
- * and are not readable back afterwards, so they are deliberately NOT compared in `matches` --
16
- * a provider that diffed them would report an update on every plan, forever. What is compared is
17
- * what PVE will actually tell you about a running container.
20
+ * ⚠️ AN ADOPTION ALWAYS PLANS `adopted`, EVEN WHEN IT WOULD WRITE. alchemy 2.0.0-beta.79 turns a
21
+ * cold adoption's diff into an update whatever it answered (Plan.ts, `forceUpdateAfterAdoption`)
22
+ * and prints no property diff for it. So `diff` LOGS the keys a deploy would write, by name
23
+ * (never by value), as a warning — the only place a plan can say the declaration is not the live
24
+ * config yet. A clean adoption logs nothing, and its deploy writes nothing (lxc-judge.ts).
25
+ *
26
+ * ⚠️ POWER STATE IS NOT DECLARED. `onboot` is config; start and stop are an operator's act, as for
27
+ * `Proxmox.Vm`. `start: 1` starts a guest once, after the create that built it, and never again.
18
28
  */
19
29
  import { Resource } from 'alchemy';
20
30
  import * as Provider from 'alchemy/Provider';
21
- import { type PveRequirements, type WithTarget } from './resource.ts';
22
- export interface LxcProps extends WithTarget {
23
- /** Which node hosts it. Moving a container between nodes is a migration, not an update. */
24
- node: string;
25
- /** ⛔ CLUSTER-WIDE primary key. Required, never auto-allocated — see the ⛔ above. */
26
- vmid: number;
27
- /** e.g. `local:vztmpl/debian-13-standard_13.0-1_amd64.tar.zst`. Create-time only. */
28
- ostemplate: string;
29
- /** Storage for the rootfs, e.g. `local-zfs`. Create-time only. */
30
- storage: string;
31
- hostname?: string;
32
- /** MiB. Mutable. */
33
- memory?: number;
34
- cores?: number;
35
- /** e.g. `name=eth0,bridge=vmbr0,ip=dhcp`. Mutable. */
36
- net0?: string;
37
- /** Start on boot. Mutable. */
38
- onboot?: boolean;
39
- }
40
- export interface LxcAttributes {
41
- vmid: number;
42
- node: string;
43
- hostname: string;
44
- memory: number;
45
- cores: number;
46
- onboot: boolean;
47
- /** `running` | `stopped`. Reported, never declared — power state is not configuration. */
48
- status: string;
49
- }
31
+ import type { LxcAttributes, LxcProps } from './lxc-props.ts';
32
+ import type { PveRequirements } from './resource.ts';
33
+ export type { LxcAttributes, LxcProps } from './lxc-props.ts';
50
34
  export interface ProxmoxLxc extends Resource<'Proxmox.Lxc', LxcProps, LxcAttributes, never, PveRequirements> {
51
35
  }
36
+ /** ★ `retain` by default — a guest's disks cannot be rebuilt from a line. See resource.ts. */
52
37
  export declare const ProxmoxLxc: import("alchemy").ResourceClass<ProxmoxLxc>;
53
- /**
54
- * ⛔ PVE REFUSES TO DELETE A RUNNING CONTAINER, and that refusal is kept — `handlers.delete`
55
- * passes it straight through. Stopping a guest so that a `destroy` can proceed is a decision an
56
- * operator makes, not one a plan makes on their behalf while they are reading the diff.
57
- */
58
38
  export declare const ProxmoxLxcProvider: () => import("effect/Layer").Layer<Provider.Provider<ProxmoxLxc>, never, import("effect/unstable/http/HttpClient").HttpClient>;
59
39
  //# sourceMappingURL=lxc.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"lxc.d.ts","sourceRoot":"","sources":["../../src/proxmox/lxc.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAE7C,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,UAAU,EAAe,MAAM,eAAe,CAAC;AAGnF,MAAM,WAAW,QAAS,SAAQ,UAAU;IAC1C,2FAA2F;IAC3F,IAAI,EAAE,MAAM,CAAC;IACb,oFAAoF;IACpF,IAAI,EAAE,MAAM,CAAC;IACb,qFAAqF;IACrF,UAAU,EAAE,MAAM,CAAC;IACnB,kEAAkE;IAClE,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oBAAoB;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sDAAsD;IACtD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,8BAA8B;IAC9B,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,0FAA0F;IAC1F,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,UAAW,SAAQ,QAAQ,CAC1C,aAAa,EACb,QAAQ,EACR,aAAa,EACb,KAAK,EACL,eAAe,CAChB;CAAG;AAEJ,eAAO,MAAM,UAAU,6CAAsC,CAAC;AAgD9D;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,gIACgD,CAAC"}
1
+ {"version":3,"file":"lxc.d.ts","sourceRoot":"","sources":["../../src/proxmox/lxc.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAGnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAiB7C,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAGrD,YAAY,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE9D,MAAM,WAAW,UAAW,SAAQ,QAAQ,CAC1C,aAAa,EACb,QAAQ,EACR,aAAa,EACb,KAAK,EACL,eAAe,CAChB;CAAG;AAEJ,8FAA8F;AAC9F,eAAO,MAAM,UAAU,6CAA0E,CAAC;AA4KlG,eAAO,MAAM,kBAAkB,gIAI5B,CAAC"}
@@ -89,5 +89,5 @@ export declare const UNREACHABLE = "the task could not be read -- the node stopp
89
89
  * is not the owner — which is why this takes a `PveCredential` and the caller keeps one lease
90
90
  * across both calls, instead of widening the provisioning role to read its own tasks.
91
91
  */
92
- export declare const awaitTask: (target: PveTarget, credential: PveCredential, node: string, upid: string) => Effect.Effect<string, never, import("effect/unstable/http/HttpClient").HttpClient>;
92
+ export declare const awaitTask: (target: PveTarget, credential: PveCredential, node: string, upid: string, attempts?: number) => Effect.Effect<string, never, import("effect/unstable/http/HttpClient").HttpClient>;
93
93
  //# sourceMappingURL=network-apply-read.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"network-apply-read.d.ts","sourceRoot":"","sources":["../../src/proxmox/network-apply-read.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAatE,oGAAoG;AACpG,MAAM,MAAM,aAAa,GAAG;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC;AA0B7E;;;;;;;;;GASG;AACH,eAAO,MAAM,YAAY,SAAU,MAAM,WAWxC,CAAC;AAEF,mFAAmF;AACnF,eAAO,MAAM,YAAY,WAAY,SAAS,QAAQ,MAAM,uFACH,CAAC;AAiC1D;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,cAAc,WAAY,SAAS,mGAO7C,CAAC;AAEJ;;;GAGG;AACH,eAAO,MAAM,WAAW,0FACiE,CAAC;AAY1F;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,SAAS,WACZ,SAAS,cACL,aAAa,QACnB,MAAM,QACN,MAAM,uFAgCV,CAAC"}
1
+ {"version":3,"file":"network-apply-read.d.ts","sourceRoot":"","sources":["../../src/proxmox/network-apply-read.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAatE,oGAAoG;AACpG,MAAM,MAAM,aAAa,GAAG;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC;AA0B7E;;;;;;;;;GASG;AACH,eAAO,MAAM,YAAY,SAAU,MAAM,WAWxC,CAAC;AAEF,mFAAmF;AACnF,eAAO,MAAM,YAAY,WAAY,SAAS,QAAQ,MAAM,uFACH,CAAC;AAiC1D;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,cAAc,WAAY,SAAS,mGAO7C,CAAC;AAEJ;;;GAGG;AACH,eAAO,MAAM,WAAW,0FACiE,CAAC;AAY1F;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,SAAS,WACZ,SAAS,cACL,aAAa,QACnB,MAAM,QACN,MAAM,aAEF,MAAM,uFAgCd,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"pbs-datastore.d.ts","sourceRoot":"","sources":["../../src/proxmox/pbs-datastore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAG7C,OAAO,EACL,KAAK,sBAAsB,EAC3B,KAAK,SAAS,EAMf,MAAM,yBAAyB,CAAC;AAEjC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAErD,YAAY,EAAE,sBAAsB,EAAE,SAAS,EAAE,CAAC;AAElD;;;;;;GAMG;AACH,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,SAAS,CAAC;IAClB,6FAA6F;IAC7F,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;;;;OASG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0EAA0E;IAC1E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gGAAgG;IAChG,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,kGAAkG;IAClG,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kFAAkF;IAClF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,+EAA+E;IAC/E,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,+FAA+F;IAC/F,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;;;OAQG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iGAAiG;IACjG,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC;;;OAGG;IACH,yBAAyB,CAAC,EAAE,MAAM,CAAC;CACpC;AAED,MAAM,WAAW,YAAa,SAAQ,QAAQ,CAC5C,eAAe,EACf,iBAAiB,EACjB,sBAAsB,EACtB,KAAK,EACL,eAAe,CAChB;CAAG;AAEJ,uFAAuF;AACvF,eAAO,MAAM,YAAY,+CAEvB,CAAC;AAEH,eAAO,MAAM,oBAAoB,kIA4G9B,CAAC"}
1
+ {"version":3,"file":"pbs-datastore.d.ts","sourceRoot":"","sources":["../../src/proxmox/pbs-datastore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAG7C,OAAO,EACL,KAAK,sBAAsB,EAC3B,KAAK,SAAS,EAMf,MAAM,yBAAyB,CAAC;AAEjC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAGrD,YAAY,EAAE,sBAAsB,EAAE,SAAS,EAAE,CAAC;AAElD;;;;;;GAMG;AACH,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,SAAS,CAAC;IAClB,6FAA6F;IAC7F,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;;;;OASG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0EAA0E;IAC1E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gGAAgG;IAChG,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,kGAAkG;IAClG,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kFAAkF;IAClF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,+EAA+E;IAC/E,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,+FAA+F;IAC/F,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;;;OAQG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iGAAiG;IACjG,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC;;;OAGG;IACH,yBAAyB,CAAC,EAAE,MAAM,CAAC;CACpC;AAED,MAAM,WAAW,YAAa,SAAQ,QAAQ,CAC5C,eAAe,EACf,iBAAiB,EACjB,sBAAsB,EACtB,KAAK,EACL,eAAe,CAChB;CAAG;AAEJ,uFAAuF;AACvF,eAAO,MAAM,YAAY,+CAEvB,CAAC;AAEH,eAAO,MAAM,oBAAoB,kIA4G9B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"resource.d.ts","sourceRoot":"","sources":["../../src/proxmox/resource.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,KAAK,UAAU,MAAM,iCAAiC,CAAC;AAEnE,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAEjF;;;;;;;;;;;;;;;;;;GAkBG;AAEH;;;;;GAKG;AACH;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,eAAe,GAAG,UAAU,CAAC,UAAU,CAAC;AAEpD,MAAM,MAAM,UAAU,GAAG;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,CAAC;AAC/C,MAAM,MAAM,aAAa,GAAG;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,CAAC;AAClD,MAAM,MAAM,aAAa,GAAG;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,CAAC;AAElD,MAAM,MAAM,OAAO,CAAC,KAAK,SAAS,aAAa,EAAE,UAAU,IAAI;IAC7D,yFAAyF;IACzF,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,MAAM,CAAC;IACxC,2DAA2D;IAC3D,QAAQ,CAAC,UAAU,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,MAAM,CAAC;IAC9C,qFAAqF;IACrF,QAAQ,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,KAAK,KAAK,UAAU,GAAG,SAAS,CAAC;IAC7F,0EAA0E;IAC1E,QAAQ,CAAC,UAAU,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9D;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/D,oEAAoE;IACpE,QAAQ,CAAC,OAAO,EAAE,CAAC,UAAU,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC;IACpE;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,KAAK,SAAS,aAAa,EAAE,UAAU,QAC7D,OAAO,CAAC,KAAK,EAAE,UAAU,CAAC;kBAGX,KAAK;iBAiBX,KAAK,CAAC,KAAK,CAAC,UAAU,UAAU,GAAG,SAAS;yBASZ,QAAQ;;yBACF,MAAM;;yBAGtC,SAAS;;sBAIV,KAAK;IA6DvB;;;;OAIG;oBACa,KAAK;CAExB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,eAAO,MAAM,WAAW,GAAI,KAAK,SAAS,aAAa,EAAE,UAAU,SAAS,MAAM,QAC1E,OAAO,CAAC,KAAK,EAAE,UAAU,CAAC;IAI9B,IAAI;IACJ,IAAI,aAAa;QAAE,IAAI,EAAE,KAAK,CAAA;KAAE;IAChC,IAAI,qBAAqB;QAAE,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;QAAC,MAAM,EAAE,UAAU,GAAG,SAAS,CAAA;KAAE;yBAtHlC,QAAQ;;yBACF,MAAM;;yBAGtC,SAAS;;IAoH5B,SAAS,aAAa;QAAE,IAAI,EAAE,KAAK,CAAA;KAAE;IACrC,MAAM,aAAa;QAAE,IAAI,EAAE,KAAK,CAAA;KAAE;CAErC,CAAC"}
1
+ {"version":3,"file":"resource.d.ts","sourceRoot":"","sources":["../../src/proxmox/resource.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,KAAK,UAAU,MAAM,iCAAiC,CAAC;AAEnE,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAGjF;;;;;;;;;;;;;;;;;;GAkBG;AAEH;;;;;GAKG;AACH;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,eAAe,GAAG,UAAU,CAAC,UAAU,CAAC;AAEpD,MAAM,MAAM,UAAU,GAAG;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,CAAC;AAC/C,MAAM,MAAM,aAAa,GAAG;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,CAAC;AAClD,MAAM,MAAM,aAAa,GAAG;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,CAAC;AAElD,MAAM,MAAM,OAAO,CAAC,KAAK,SAAS,aAAa,EAAE,UAAU,IAAI;IAC7D,yFAAyF;IACzF,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,MAAM,CAAC;IACxC,2DAA2D;IAC3D,QAAQ,CAAC,UAAU,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,MAAM,CAAC;IAC9C,qFAAqF;IACrF,QAAQ,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,KAAK,KAAK,UAAU,GAAG,SAAS,CAAC;IAC7F,0EAA0E;IAC1E,QAAQ,CAAC,UAAU,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9D;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/D,oEAAoE;IACpE,QAAQ,CAAC,OAAO,EAAE,CAAC,UAAU,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC;IACpE;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,KAAK,SAAS,aAAa,EAAE,UAAU,QAC7D,OAAO,CAAC,KAAK,EAAE,UAAU,CAAC;kBAGX,KAAK;iBAiBX,KAAK,CAAC,KAAK,CAAC,UAAU,UAAU,GAAG,SAAS;yBASZ,QAAQ;;yBACF,MAAM;;yBAGtC,SAAS;;sBAIV,KAAK;IA4DvB;;;;OAIG;oBACa,KAAK;CAExB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,eAAO,MAAM,WAAW,GAAI,KAAK,SAAS,aAAa,EAAE,UAAU,SAAS,MAAM,QAC1E,OAAO,CAAC,KAAK,EAAE,UAAU,CAAC;IAI9B,IAAI;IACJ,IAAI,aAAa;QAAE,IAAI,EAAE,KAAK,CAAA;KAAE;IAChC,IAAI,qBAAqB;QAAE,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;QAAC,MAAM,EAAE,UAAU,GAAG,SAAS,CAAA;KAAE;yBArHlC,QAAQ;;yBACF,MAAM;;yBAGtC,SAAS;;IAmH5B,SAAS,aAAa;QAAE,IAAI,EAAE,KAAK,CAAA;KAAE;IACrC,MAAM,aAAa;QAAE,IAAI,EAAE,KAAK,CAAA;KAAE;CAErC,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Whether an update has anything to write — decided ONCE for every PVE and PBS family.
3
+ *
4
+ * ⛔ AN ADOPTED ROW IS RECONCILED EVEN WHEN ITS DIFF SAID `noop`, SO THIS GUARD IS WHAT MAKES
5
+ * ADOPTION FREE. alchemy beta.79 Plan.ts sets `forceUpdateAfterAdoption` after the cold-start
6
+ * probe and turns a `noop` diff into an update; Apply.ts then calls `reconcile` for the
7
+ * `adopted` action exactly as for `update`. The plan prints `adopted` either way, so nothing on
8
+ * screen tells a matching object from a drifting one. docs/adopt-verify.md has the table of
9
+ * what each family does on that path.
10
+ *
11
+ * 🔴 THE FAMILY THAT DID NOT HAVE IT. `Proxmox.CephPool` wrote its own reconcile and PUT the
12
+ * declared set whenever the pool existed, so adopting a pool that already matched sent
13
+ * `setpool` and forked a worker on the live cluster (found 2026-09-21 by tracing every family).
14
+ * resource.ts and pbs-datastore.ts each had the guard inline; three copies of one predicate is
15
+ * how the fourth family forgets it, so it lives here and all three call it.
16
+ *
17
+ * ★ `matches` IS THE SAME PREDICATE `diff` USES, so "the diff said noop" and "reconcile writes
18
+ * nothing" cannot disagree. A field left OUT of `matches` is one the family does not manage, so
19
+ * its drift is not this write's to repair.
20
+ *
21
+ * ⚠️ AN EMPTY FORM IS ALSO NOT A WRITE. `updateForm` can legitimately answer `{}` — a storage
22
+ * declaring only `storage`, `type` and its locator has no mutable field at all — and PUTting an
23
+ * empty body is a pointless write at best and a 400 that reads as a broken provider at worst.
24
+ * (Moved here from resource.ts with the guard it explains.)
25
+ */
26
+ export declare const formToSend: <Attributes, Props, Form extends object>(matches: (attributes: Attributes, props: Props) => boolean, live: Attributes, props: Props, form: Form) => Form | undefined;
27
+ //# sourceMappingURL=update-guard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-guard.d.ts","sourceRoot":"","sources":["../../src/proxmox/update-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,UAAU,GAAI,UAAU,EAAE,KAAK,EAAE,IAAI,SAAS,MAAM,WACtD,CAAC,UAAU,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,KAAK,OAAO,QACpD,UAAU,SACT,KAAK,QACN,IAAI,KACT,IAAI,GAAG,SAAwF,CAAC"}