@homeflare/alchemy 0.10.1 → 0.11.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 (42) hide show
  1. package/dist/caddy/index.js.map +2 -2
  2. package/dist/launchd/index.js.map +2 -2
  3. package/dist/openbao/index.js +10 -8
  4. package/dist/openbao/index.js.map +4 -4
  5. package/dist/ownership/adopting.d.ts +34 -0
  6. package/dist/ownership/adopting.d.ts.map +1 -0
  7. package/dist/ownership/probe.d.ts +15 -5
  8. package/dist/ownership/probe.d.ts.map +1 -1
  9. package/dist/ownership/rows.d.ts +12 -0
  10. package/dist/ownership/rows.d.ts.map +1 -1
  11. package/dist/ownership/store-fixture.d.ts +10 -0
  12. package/dist/ownership/store-fixture.d.ts.map +1 -0
  13. package/dist/proxmox/fake-pve-lxc.d.ts +8 -0
  14. package/dist/proxmox/fake-pve-lxc.d.ts.map +1 -1
  15. package/dist/proxmox/index.js +147 -113
  16. package/dist/proxmox/index.js.map +8 -6
  17. package/dist/proxmox/lxc-adoption.d.ts +32 -0
  18. package/dist/proxmox/lxc-adoption.d.ts.map +1 -0
  19. package/dist/proxmox/lxc-harness.d.ts +12 -0
  20. package/dist/proxmox/lxc-harness.d.ts.map +1 -1
  21. package/dist/proxmox/lxc.d.ts +5 -5
  22. package/dist/proxmox/lxc.d.ts.map +1 -1
  23. package/docs/adopted-deploys.md +4 -2
  24. package/docs/ownership.md +1 -1
  25. package/docs/proxmox-lxc-adopt.md +83 -0
  26. package/docs/proxmox-lxc.md +7 -45
  27. package/docs/proxmox.md +2 -0
  28. package/package.json +1 -1
  29. package/src/ownership/adopting.test.ts +63 -0
  30. package/src/ownership/adopting.ts +46 -0
  31. package/src/ownership/ownership.test.ts +1 -34
  32. package/src/ownership/probe.ts +27 -14
  33. package/src/ownership/rows.ts +8 -2
  34. package/src/ownership/store-fixture.ts +50 -0
  35. package/src/proxmox/fake-pve-lxc.ts +13 -1
  36. package/src/proxmox/lxc-adopt.test.ts +13 -20
  37. package/src/proxmox/lxc-adoption.ts +50 -0
  38. package/src/proxmox/lxc-guards.test.ts +6 -13
  39. package/src/proxmox/lxc-harness.ts +25 -2
  40. package/src/proxmox/lxc-ownership.test.ts +19 -14
  41. package/src/proxmox/lxc-strict-adopt.test.ts +104 -0
  42. package/src/proxmox/lxc.ts +16 -12
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Whether a `diff` or `reconcile` that holds attributes is looking at an ADOPTION — a live object
3
+ * that reached this stack's state by being FOUND, not by this resource's own create — so a family
4
+ * whose adoption must never change what it takes over (`Proxmox.Lxc`) can refuse any difference
5
+ * instead of writing it. adopt.ts and probe.ts decide WHETHER an object may be claimed; this says,
6
+ * once it is claimed, whether the claim is an adoption.
7
+ *
8
+ * ★ STATE ALREADY SAYS WHICH, AT BOTH HALVES OF A DEPLOY (alchemy 2.0.0-beta.79):
9
+ * · PLAN, A COLD ADOPTION. The probe mints an instance id no row can hold (Plan.ts
10
+ * `generateInstanceId()`), and `diff` then runs with that id and the attributes the probe
11
+ * read. So no row holds the id.
12
+ * · APPLY, THE SAME ADOPTION. Apply commits an `updating` row with `adopting: true` under that id
13
+ * BEFORE it calls reconcile, and the flag stays until the update commits (Apply.ts). An
14
+ * adoption whose apply was interrupted keeps it, so the next plan's `diff` sees it too.
15
+ * · A RECOVERED CREATE. A `creating` row with no attributes, whose live object the recovery read
16
+ * found. It is this resource's own create when the row proves it (probe.ts `provenOurs`, the
17
+ * same proof the read asked). Otherwise the plan went on only because `--adopt` said so — an
18
+ * adoption like any other.
19
+ * · Any other row with attributes is state vouching for the object: not an adoption.
20
+ * ⚠️ OUTSIDE A STACK — no Stack or State in context, or a store that errors (rows.ts) — no row
21
+ * holds anything, so every call is an adoption: the strict answer, never the permissive one. A
22
+ * family then refuses an ordinary update's write as if it were an adoption's. `alchemy deploy`
23
+ * and the Alchemist session provide both services.
24
+ */
25
+ import * as Effect from 'effect/Effect';
26
+ import type { Owner } from './adopt.ts';
27
+ /**
28
+ * Whether `owner`'s call is an adoption (header). `settled` is the family's "live matches these
29
+ * props", asked only for a recovered create, with the props of the row that recorded it.
30
+ * ⛔ A CREATE IS NEVER ONE HERE. `output` undefined is reconcile's create path, which has its own
31
+ * rule for a live object it finds (adopt.ts `refuseTakeover`).
32
+ */
33
+ export declare const adopting: <E, R>(owner: Owner, settled: (recorded: unknown) => Effect.Effect<boolean, E, R>) => Effect.Effect<boolean, never, R>;
34
+ //# sourceMappingURL=adopting.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adopting.d.ts","sourceRoot":"","sources":["../../src/ownership/adopting.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAIxC;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,GAAI,CAAC,EAAE,CAAC,SACpB,KAAK,WACH,CAAC,QAAQ,EAAE,OAAO,KAAK,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,KAC3D,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC,CAO9B,CAAC"}
@@ -1,13 +1,23 @@
1
1
  import * as Effect from 'effect/Effect';
2
2
  import type { Owner } from './adopt.ts';
3
3
  /**
4
- * A family's `read` answer. With attributes in state it is `found` as is. Without, it is the probe
5
- * or the recovery read (header): `found` is ours only when the state store records this instance
6
- * with its whole declaration AND `settled` — the family's own "live matches these props" — says so.
7
- * ⛔ `settled` NEVER FAILS THE READ. The recovery read runs with the INTERRUPTED deploy's props, so
4
+ * Whether the state store proves the live object this instance's own: a row records `ask.instanceId`
5
+ * with its whole declaration (whole.ts) AND `settled` — the family's own "live matches these props"
6
+ * — says so. The one proof ownership/ accepts for a live object state holds no attributes for; the
7
+ * recovery read (`ownedRead`) and an adoption check (adopting.ts) both ask it.
8
+ * ⛔ `settled` NEVER FAILS THE CALLER. The recovery read runs with the INTERRUPTED deploy's props, so
8
9
  * a declaration that cannot be evaluated any more (a fragments directory since moved, a group
9
10
  * name since renamed) would fail every later plan, the fix included. It reads as "not proven
10
- * ours" instead — `Unowned`, which `--adopt` resolves — with the reason logged.
11
+ * ours" instead, with the reason logged.
12
+ */
13
+ export declare const provenOurs: <E, R>(ask: {
14
+ readonly fqn: string;
15
+ readonly instanceId: string;
16
+ }, settled: Effect.Effect<boolean, E, R>) => Effect.Effect<boolean, never, R>;
17
+ /**
18
+ * A family's `read` answer. With attributes in state it is `found` as is. Without, it is the probe
19
+ * or the recovery read (header): `found` is ours only when `provenOurs` says so, else `Unowned`,
20
+ * which `--adopt` resolves.
11
21
  */
12
22
  export declare const ownedRead: <A extends object, E, R>(ask: Owner, found: A | undefined, settled: Effect.Effect<boolean, E, R>) => Effect.Effect<A | undefined, never, R>;
13
23
  //# sourceMappingURL=probe.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"probe.d.ts","sourceRoot":"","sources":["../../src/ownership/probe.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGxC;;;;;;;;GAQG;AACH,eAAO,MAAM,SAAS,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,CAAC,OACzC,KAAK,SACH,CAAC,GAAG,SAAS,WACX,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,KACpC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,SAAS,EAAE,KAAK,EAAE,CAAC,CAsBpC,CAAC"}
1
+ {"version":3,"file":"probe.d.ts","sourceRoot":"","sources":["../../src/ownership/probe.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGxC;;;;;;;;;GASG;AACH,eAAO,MAAM,UAAU,GAAI,CAAC,EAAE,CAAC,OACxB;IAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAAE,WACjD,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,KACpC,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC,CAoB9B,CAAC;AAEL;;;;GAIG;AACH,eAAO,MAAM,SAAS,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,CAAC,OACzC,KAAK,SACH,CAAC,GAAG,SAAS,WACX,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,KACpC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,SAAS,EAAE,KAAK,EAAE,CAAC,CAIpC,CAAC"}
@@ -1,4 +1,16 @@
1
1
  import * as Effect from 'effect/Effect';
2
+ /** One generation of a persisted row, as far as ownership/ reads it. */
3
+ export type Generation = {
4
+ readonly instanceId?: unknown;
5
+ readonly status?: unknown;
6
+ readonly props?: unknown;
7
+ readonly attr?: unknown;
8
+ readonly old?: unknown;
9
+ /** Set by Apply on the `updating` row of an adoption, until that update commits (Apply.ts). */
10
+ readonly adopting?: unknown;
11
+ };
12
+ /** The generation `instanceId` names — at the FQN, or at a former FQN `renamedFrom` names. */
13
+ export declare const recordedGeneration: (fqn: string, instanceId: string) => Effect.Effect<Generation | undefined>;
2
14
  /**
3
15
  * What the state store says of `instanceId` for this resource (at its FQN, or at a former FQN its
4
16
  * `renamedFrom` names — the planner migrates that row before it recovers it):
@@ -1 +1 @@
1
- {"version":3,"file":"rows.d.ts","sourceRoot":"","sources":["../../src/ownership/rows.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAkDxC;;;;;;;;;GASG;AACH,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,CAAC;AAEtD,eAAO,MAAM,gBAAgB,QAAS,MAAM,cAAc,MAAM,KAAG,MAAM,CAAC,MAAM,CAAC,QAAQ,CAKrF,CAAC;AAEL;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,QAAS,MAAM,cAAc,MAAM,KAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAI7E,CAAC;AAEJ;;;;;;;;;;GAUG;AACH,eAAO,MAAM,mBAAmB,QAAS,MAAM,cAAc,MAAM,KAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAUpF,CAAC"}
1
+ {"version":3,"file":"rows.d.ts","sourceRoot":"","sources":["../../src/ownership/rows.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAmBxC,wEAAwE;AACxE,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC;IACvB,+FAA+F;IAC/F,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAC;AAaF,8FAA8F;AAC9F,eAAO,MAAM,kBAAkB,QACxB,MAAM,cACC,MAAM,KACjB,MAAM,CAAC,MAAM,CAAC,UAAU,GAAG,SAAS,CASnC,CAAC;AAEL;;;;;;;;;GASG;AACH,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,CAAC;AAEtD,eAAO,MAAM,gBAAgB,QAAS,MAAM,cAAc,MAAM,KAAG,MAAM,CAAC,MAAM,CAAC,QAAQ,CAKrF,CAAC;AAEL;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,QAAS,MAAM,cAAc,MAAM,KAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAI7E,CAAC;AAEJ;;;;;;;;;;GAUG;AACH,eAAO,MAAM,mBAAmB,QAAS,MAAM,cAAc,MAAM,KAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAUpF,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { ResourceState } from 'alchemy/State/ResourceState';
2
+ import * as Effect from 'effect/Effect';
3
+ /** A row with no attributes: `creating`, or `replacing` when it carries an `old` generation. */
4
+ export declare const row: (fqn: string, instanceId: string, old?: unknown, props?: unknown) => ResourceState;
5
+ /**
6
+ * A stack `s` at stage `test` whose store holds `rows`: `A` and `B` declared with a `name`, and `Z`
7
+ * declared `renamedFrom('X')`.
8
+ */
9
+ export declare const withStore: <A>(rows: Record<string, ResourceState>, effect: Effect.Effect<A>) => Promise<A>;
10
+ //# sourceMappingURL=store-fixture.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store-fixture.d.ts","sourceRoot":"","sources":["../../src/ownership/store-fixture.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAGjE,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,gGAAgG;AAChG,eAAO,MAAM,GAAG,QACT,MAAM,cACC,MAAM,QACZ,OAAO,UACN,OAAO,KACb,aAO6B,CAAC;AAEjC;;;GAGG;AACH,eAAO,MAAM,SAAS,GAAI,CAAC,QACnB,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,UAC3B,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,KACvB,OAAO,CAAC,CAAC,CAgBT,CAAC"}
@@ -22,6 +22,14 @@ export type FakePve = {
22
22
  * keyed `node/vmid` — a guest that appears between a plan and its deploy.
23
23
  */
24
24
  readonly vanish: Map<string, number>;
25
+ /**
26
+ * Hand edits that land mid-deploy, keyed `node/vmid`: once that guest's config has been read
27
+ * `after` more times, `set` is merged into it — a change made between a plan and its apply.
28
+ */
29
+ readonly edits: Map<string, {
30
+ after: number;
31
+ readonly set: Record<string, unknown>;
32
+ }>;
25
33
  /** Config keys a `PUT …/config` accepts with 200 and then does not store. */
26
34
  readonly ignore: Set<string>;
27
35
  /** How every task ends, and whether a task-starting call answers with no UPID at all. */
@@ -1 +1 @@
1
- {"version":3,"file":"fake-pve-lxc.d.ts","sourceRoot":"","sources":["../../src/proxmox/fake-pve-lxc.ts"],"names":[],"mappings":"AAkBA,MAAM,MAAM,IAAI,GAAG;IACjB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG;IACpB,6FAA6F;IAC7F,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACtD,mFAAmF;IACnF,QAAQ,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACzE,4FAA4F;IAC5F,QAAQ,CAAC,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IACtE;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,6EAA6E;IAC7E,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC7B,yFAAyF;IACzF,QAAQ,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,OAAO,CAAA;KAAE,CAAC;IACjD,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,OAAO,KAAK,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,IAAI,CAAC;CAC3B,CAAC;AAEF,+FAA+F;AAC/F,eAAO,MAAM,WAAW,eAAe,CAAC;AACxC,eAAO,MAAM,QAAQ,yBAAyB,CAAC;AAwC/C,eAAO,MAAM,OAAO,QAAO,OAoH1B,CAAC;AAEF,8FAA8F;AAC9F,eAAO,MAAM,QAAQ,SAAU,OAAO,aAG0C,CAAC"}
1
+ {"version":3,"file":"fake-pve-lxc.d.ts","sourceRoot":"","sources":["../../src/proxmox/fake-pve-lxc.ts"],"names":[],"mappings":"AAkBA,MAAM,MAAM,IAAI,GAAG;IACjB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG;IACpB,6FAA6F;IAC7F,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACtD,mFAAmF;IACnF,QAAQ,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACzE,4FAA4F;IAC5F,QAAQ,CAAC,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IACtE;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,CAAC;IACtF,6EAA6E;IAC7E,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC7B,yFAAyF;IACzF,QAAQ,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,OAAO,CAAA;KAAE,CAAC;IACjD,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,OAAO,KAAK,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,IAAI,CAAC;CAC3B,CAAC;AAEF,+FAA+F;AAC/F,eAAO,MAAM,WAAW,eAAe,CAAC;AACxC,eAAO,MAAM,QAAQ,yBAAyB,CAAC;AAwC/C,eAAO,MAAM,OAAO,QAAO,OA2H1B,CAAC;AAEF,8FAA8F;AAC9F,eAAO,MAAM,QAAQ,SAAU,OAAO,aAG0C,CAAC"}