@homeflare/alchemy 0.37.0 → 0.37.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.
- package/dist/proxmox/ceph-daemon-wire.d.ts +5 -7
- package/dist/proxmox/ceph-daemon-wire.d.ts.map +1 -1
- package/dist/proxmox/ceph-daemon.d.ts +7 -8
- package/dist/proxmox/ceph-daemon.d.ts.map +1 -1
- package/dist/proxmox/ceph-fs-distilled.d.ts +24 -5
- package/dist/proxmox/ceph-fs-distilled.d.ts.map +1 -1
- package/dist/proxmox/ceph-fs.d.ts +4 -5
- package/dist/proxmox/ceph-fs.d.ts.map +1 -1
- package/dist/proxmox/ceph-pool-settle.d.ts +9 -8
- package/dist/proxmox/ceph-pool-settle.d.ts.map +1 -1
- package/dist/proxmox/ceph-pool-wire.d.ts +11 -20
- package/dist/proxmox/ceph-pool-wire.d.ts.map +1 -1
- package/dist/proxmox/group-wire.d.ts +7 -12
- package/dist/proxmox/group-wire.d.ts.map +1 -1
- package/dist/proxmox/index.js +7 -19
- package/dist/proxmox/index.js.map +13 -13
- package/dist/proxmox/storage-wire.d.ts +7 -10
- package/dist/proxmox/storage-wire.d.ts.map +1 -1
- package/dist/proxmox/unreadable-read.d.ts +7 -7
- package/dist/proxmox/user-wire.d.ts +7 -10
- package/dist/proxmox/user-wire.d.ts.map +1 -1
- package/dist/proxmox/user.d.ts +5 -5
- package/docs/distilled-interim.md +15 -3
- package/docs/provider-standard.md +24 -6
- package/docs/proxmox.md +20 -0
- package/docs/upstream-conformance-bun.md +67 -0
- package/docs/upstream-conformance-conforms.md +55 -0
- package/docs/upstream-conformance-families.md +95 -0
- package/docs/upstream-conformance-grafana.md +106 -0
- package/docs/upstream-conformance.md +20 -298
- package/package.json +1 -1
- package/src/proxmox/ceph-daemon-wire.ts +4 -7
- package/src/proxmox/ceph-daemon.ts +7 -8
- package/src/proxmox/ceph-fs-distilled.ts +7 -9
- package/src/proxmox/ceph-fs.ts +8 -10
- package/src/proxmox/ceph-pool-settle.ts +11 -10
- package/src/proxmox/ceph-pool-wire.ts +11 -20
- package/src/proxmox/ceph-pool-write.test.ts +9 -8
- package/src/proxmox/group-wire.ts +7 -12
- package/src/proxmox/read-failure-propagation.test.ts +5 -5
- package/src/proxmox/storage-wire.ts +9 -10
- package/src/proxmox/typed-absence.test.ts +146 -0
- package/src/proxmox/unreadable-read.ts +7 -7
- package/src/proxmox/user-wire.ts +7 -10
- package/src/proxmox/user.ts +5 -5
|
@@ -4,11 +4,9 @@
|
|
|
4
4
|
* `{node,id}` / `{node,name}`) — the SAME reason `DAEMON_ENDPOINTS` (ceph-daemon-form.ts) is a
|
|
5
5
|
* per-kind table rather than one templated string.
|
|
6
6
|
*
|
|
7
|
-
* ⛔
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* with no `output`-branching, so `readDaemon` below reproduces that exact single-fold shape
|
|
11
|
-
* rather than gaining the newer dual-path pattern along the way.
|
|
7
|
+
* ⛔ ABSENCE IS A SUCCESSFUL INDEX WITH NO MATCHING ROW. The original transport swap
|
|
8
|
+
* preserved `pveOperations.read`'s catch-all fold; the 2026-09-24 follow-up removes it. A failed
|
|
9
|
+
* mon/mgr/mds list proves nothing about whether a daemon exists, so its SDK error propagates.
|
|
12
10
|
*
|
|
13
11
|
* ⚠️ `mon_address` IS THE ONE RENAME THIS FAMILY NEEDS — distilled's generator maps the wire name
|
|
14
12
|
* `mon-address` to `mon_address` on `UpdateNodeCephMonRequest` (`T.Body("mon-address")`,
|
|
@@ -18,8 +16,8 @@
|
|
|
18
16
|
import * as nodes from '@distilled.cloud/proxmox/nodes';
|
|
19
17
|
import * as Effect from 'effect/Effect';
|
|
20
18
|
import type { CephDaemonKind, CephDaemonProps } from './ceph-daemon.ts';
|
|
21
|
-
/**
|
|
22
|
-
export declare const readDaemon: (props: CephDaemonProps) => Effect.Effect<import("./ceph-daemon.ts").CephDaemonAttributes | undefined,
|
|
19
|
+
/** A missing row is absent; a failed index read keeps its typed SDK error. */
|
|
20
|
+
export declare const readDaemon: (props: CephDaemonProps) => Effect.Effect<import("./ceph-daemon.ts").CephDaemonAttributes | undefined, Error | import("./distilled-pve.ts").PveClusterExhausted | import("./credential-errors.ts").PveCredentialDenied | import("effect/Cause").TimeoutError | nodes.ProxmoxOpError, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
23
21
|
/** POST — distilled's generator misnames it "update" (checked against `T.Http`); it is a create. */
|
|
24
22
|
export declare const createDaemon: (props: CephDaemonProps) => Effect.Effect<string, Error | import("./distilled-pve.ts").PveClusterExhausted | import("./credential-errors.ts").PveCredentialDenied | import("effect/Cause").TimeoutError | nodes.ProxmoxOpError, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
25
23
|
/** ⚠️ NO FLAGS ON ANY OF THE THREE — unlike CephFs/CephOsd, nothing here is at risk of a
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ceph-daemon-wire.d.ts","sourceRoot":"","sources":["../../src/proxmox/ceph-daemon-wire.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"ceph-daemon-wire.d.ts","sourceRoot":"","sources":["../../src/proxmox/ceph-daemon-wire.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,KAAK,MAAM,gCAAgC,CAAC;AACxD,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AA+BxE,8EAA8E;AAC9E,eAAO,MAAM,UAAU,UAAW,eAAe,mTAG9C,CAAC;AAEJ,oGAAoG;AACpG,eAAO,MAAM,YAAY,UAAW,eAAe,8PA6BlD,CAAC;AAEF;wEACwE;AACxE,eAAO,MAAM,YAAY,UAAW,eAAe,8PAWlD,CAAC;AAEF,wGAAwG;AACxG,YAAY,EAAE,cAAc,EAAE,CAAC;AAE/B;oGACoG;AACpG,eAAO,MAAM,UAAU,UAAW,eAAe,UAK9C,CAAC"}
|
|
@@ -47,8 +47,8 @@
|
|
|
47
47
|
* this credential already has it rather than discovering it the next time something is scoped.
|
|
48
48
|
*
|
|
49
49
|
* ★ MIGRATED OFF `client.ts` (2026-09-24, decision 43, 2c) — ceph-daemon-wire.ts has the rename
|
|
50
|
-
* and why no protocol gap blocks any of the three kinds
|
|
51
|
-
*
|
|
50
|
+
* and why no protocol gap blocks any of the three kinds. The follow-up removes the preserved
|
|
51
|
+
* catch-all read fold: only a successful index without this daemon proves absence.
|
|
52
52
|
*/
|
|
53
53
|
import { Resource } from 'alchemy';
|
|
54
54
|
import * as Provider from 'alchemy/Provider';
|
|
@@ -68,12 +68,11 @@ export interface CephDaemonProps extends WithTarget {
|
|
|
68
68
|
/**
|
|
69
69
|
* The node the daemon RUNS on. Identity — a daemon cannot be moved, only destroyed and rebuilt.
|
|
70
70
|
* ⚠️ It is also the node whose API is asked, and the read is only as available as that node: a
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
* but the message will point at the daemon rather than at the node that would not answer.
|
|
71
|
+
* failed index now propagates its error. Before the typed-read follow-up, a down node,
|
|
72
|
+
* missing Ceph installation or 403 was folded to "absent"; its daemons planned `update`
|
|
73
|
+
* and reconcile POSTed a create for a mon that already existed. PVE refused with "monitor
|
|
74
|
+
* already exists", then read-back failed again, obscuring the original node read error.
|
|
75
|
+
* That incident is why collection failure can never prove a daemon is missing.
|
|
77
76
|
*/
|
|
78
77
|
node: string;
|
|
79
78
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ceph-daemon.d.ts","sourceRoot":"","sources":["../../src/proxmox/ceph-daemon.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAIxC,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,UAAU,EAAE,MAAM,eAAe,CAAC;AAEtE;;;;;;;GAOG;AACH,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;AAEnD,MAAM,WAAW,eAAgB,SAAQ,UAAU;IACjD,IAAI,EAAE,cAAc,CAAC;IACrB
|
|
1
|
+
{"version":3,"file":"ceph-daemon.d.ts","sourceRoot":"","sources":["../../src/proxmox/ceph-daemon.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAIxC,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,UAAU,EAAE,MAAM,eAAe,CAAC;AAEtE;;;;;;;GAOG;AACH,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;AAEnD,MAAM,WAAW,eAAgB,SAAQ,UAAU;IACjD,IAAI,EAAE,cAAc,CAAC;IACrB;;;;;;;;OAQG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;;;OAKG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;;;;OAQG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;;;;;;;OAWG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,cAAc,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;;OAOG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;;;OAQG;IACH,KAAK,EAAE,MAAM,CAAC;IACd,uGAAuG;IACvG,IAAI,EAAE,MAAM,CAAC;IACb,mGAAmG;IACnG,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,yFAAyF;IACzF,MAAM,EAAE,OAAO,CAAC;IAChB,+EAA+E;IAC/E,aAAa,EAAE,OAAO,CAAC;IACvB;;;;;OAKG;IACH,MAAM,EAAE,MAAM,CAAC;IACf,iGAAiG;IACjG,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,iBAAkB,SAAQ,QAAQ,CACjD,oBAAoB,EACpB,eAAe,EACf,oBAAoB,EACpB,KAAK,EACL,eAAe,CAChB;CAAG;AAEJ,iGAAiG;AACjG,eAAO,MAAM,iBAAiB,oDAE5B,CAAC;AAEH;;;;;;;;;;;;;;;GAeG;AACH;;;;;;;;;;GAUG;AACH,eAAO,MAAM,eAAe;UAA0C,eAAe;8NAQnF,CAAC;AAEH,eAAO,MAAM,yBAAyB,uIA8BnC,CAAC"}
|
|
@@ -1,14 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `Proxmox.CephFs`'s distilled half: the index read and the create — see ceph-fs-wire.ts's own
|
|
3
|
+
* header for why `destroyFs` stays there, on `client.ts`, unmigrated.
|
|
4
|
+
*
|
|
5
|
+
* ⛔ `nodes.updateNodeCephFs` IS distilled's GENERATOR MISNAMING A CREATE, NOT A SECOND ENDPOINT.
|
|
6
|
+
* Checked directly against its schema (`T.Http({ method: "POST", uri:
|
|
7
|
+
* "/nodes/{node}/ceph/fs/{name}" })`) rather than trusted from the function name — it is the
|
|
8
|
+
* SAME single write PVE registers, `createfs`. Harmless once named here for what it is.
|
|
9
|
+
*
|
|
10
|
+
* ★ THE SETTLE POLL IS A SEPARATE FUNCTION FROM ceph-fs-wire.ts's, NOT A SHARED ONE, because it
|
|
11
|
+
* calls a different task-status operation on a different transport — `nodes.getNodeTaskStatus`
|
|
12
|
+
* here, `pve()` there — but the POLICY is identical on purpose: same cadence
|
|
13
|
+
* (`POLL_SECONDS`/`POLL_ATTEMPTS`, imported, not retyped), same "an unreadable status is not
|
|
14
|
+
* settled yet, not a failure" tolerance. That tolerance is why this calls the RAW distilled
|
|
15
|
+
* operation directly. The former SDK `Task.awaitTask` propagated poll failures; SDK PR #265
|
|
16
|
+
* removed that helper because polling policy belongs in the provider. This bounded wait
|
|
17
|
+
* still tolerates a missing `Sys.Audit` grant or a node mid-restart until its deadline.
|
|
18
|
+
*/
|
|
19
|
+
import * as nodes from '@distilled.cloud/proxmox/nodes';
|
|
1
20
|
import * as Effect from 'effect/Effect';
|
|
2
21
|
import type { CephFsProps } from './ceph-fs.ts';
|
|
3
22
|
/**
|
|
4
23
|
* The index, read via distilled — the same shape `readRow` (ceph-fs-wire.ts) already narrows.
|
|
5
24
|
*
|
|
6
|
-
* ⛔
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
25
|
+
* ⛔ ABSENCE IS A SUCCESSFUL INDEX WITH NO MATCHING FILESYSTEM. The transport swap
|
|
26
|
+
* initially preserved the generic factory's catch-all fold. The 2026-09-24 follow-up removes it:
|
|
27
|
+
* a failed list is not proof that a filesystem is missing. Task polling below retains its
|
|
28
|
+
* separate bounded wait policy; it does not decide whether a resource exists.
|
|
10
29
|
*/
|
|
11
|
-
export declare const readFs: (props: CephFsProps) => Effect.Effect<import("./ceph-fs.ts").CephFsAttributes | undefined,
|
|
30
|
+
export declare const readFs: (props: CephFsProps) => Effect.Effect<import("./ceph-fs.ts").CephFsAttributes | undefined, Error | import("./distilled-pve.ts").PveClusterExhausted | import("./credential-errors.ts").PveCredentialDenied | import("effect/Cause").TimeoutError | nodes.ProxmoxOpError, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
12
31
|
/** POST the create, then wait for the worker. ⛔ The caller still reads back; see ceph-fs.ts. */
|
|
13
32
|
export declare const createFs: (props: CephFsProps) => Effect.Effect<undefined, Error | import("effect/unstable/http/HttpClientError").HttpClientError | import("./credential-errors.ts").PveCredentialDenied, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
14
33
|
//# sourceMappingURL=ceph-fs-distilled.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ceph-fs-distilled.d.ts","sourceRoot":"","sources":["../../src/proxmox/ceph-fs-distilled.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ceph-fs-distilled.d.ts","sourceRoot":"","sources":["../../src/proxmox/ceph-fs-distilled.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,KAAK,KAAK,MAAM,gCAAgC,CAAC;AACxD,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAIhD;;;;;;;GAOG;AACH,eAAO,MAAM,MAAM,UAAW,WAAW,2SAGtC,CAAC;AA2CJ,gGAAgG;AAChG,eAAO,MAAM,QAAQ,UAAW,WAAW,kNAoBvC,CAAC"}
|
|
@@ -29,11 +29,10 @@
|
|
|
29
29
|
* ★ MIGRATED OFF `client.ts`'s generic `pve()` ONTO `@distilled.cloud/proxmox`'s typed
|
|
30
30
|
* `nodes.listNodeCephFs`/`updateNodeCephFs` for the READ and the CREATE (2026-09-24, decision
|
|
31
31
|
* 43's walk-down, 2c — ceph-fs-distilled.ts). `destroyFs` STAYS on `client.ts`, unmigrated:
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* family always had; see ceph-pool-wire.ts's own header for why that is not a bug left unfixed.
|
|
32
|
+
* the SDK originally put `remove-pools`/`remove-storages` in a DELETE body, which PVE ignores.
|
|
33
|
+
* SDK PR #265 fixes that protocol gap; migrating `destroyFs` remains a separate change.
|
|
34
|
+
* The typed-read follow-up removes the catch-all fold from `readFs`: a failed index must
|
|
35
|
+
* fail read/diff/reconcile/delete, not report a missing filesystem or a successful destroy.
|
|
37
36
|
*
|
|
38
37
|
* ⛔ CREATING A CephFS CREATES TWO CEPH POOLS, AND A `Proxmox.CephPool` MUST NOT ALSO DECLARE THEM.
|
|
39
38
|
* `createfs` builds `<name>_data` and `<name>_metadata` itself and refuses outright if either
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ceph-fs.d.ts","sourceRoot":"","sources":["../../src/proxmox/ceph-fs.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"ceph-fs.d.ts","sourceRoot":"","sources":["../../src/proxmox/ceph-fs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgEG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAK7C,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,UAAU,EAAE,MAAM,eAAe,CAAC;AAEtE,MAAM,WAAW,WAAY,SAAQ,UAAU;IAC7C,2FAA2F;IAC3F,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;;;;;OAUG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,+FAA+F;IAC/F,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,4FAA4F;IAC5F,SAAS,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IACH,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,aAAc,SAAQ,QAAQ,CAC7C,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,KAAK,EACL,eAAe,CAChB;CAAG;AAEJ,qGAAqG;AACrG,eAAO,MAAM,aAAa,gDAExB,CAAC;AAEH;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,qBAAqB,mIAiF/B,CAAC"}
|
|
@@ -15,15 +15,16 @@ import type { PveRequirements } from './resource.ts';
|
|
|
15
15
|
* separable at all. `ops.read` — now `readPoolStatus` (ceph-pool-wire.ts) — is a module-level
|
|
16
16
|
* binding in ceph-pool.ts; importing it back would be a runtime cycle, and duplicating it would
|
|
17
17
|
* be two definitions of one path. Passing it is the pattern zfs-pool-write.ts already uses.
|
|
18
|
+
* The error parameter preserves the reader's typed failures through settle; it is not `never`.
|
|
18
19
|
*/
|
|
19
|
-
export type PoolRead = (props: CephPoolProps) => Effect.Effect<CephPoolAttributes | undefined,
|
|
20
|
+
export type PoolRead<E> = (props: CephPoolProps) => Effect.Effect<CephPoolAttributes | undefined, E, PveRequirements>;
|
|
20
21
|
/**
|
|
21
|
-
* ⛔ THE GUARD ON THE CREATE.
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
* An empty list is trusted: the collection
|
|
26
|
-
* filtering, so `[]` really does mean a cluster with no pools.
|
|
22
|
+
* ⛔ THE GUARD ON THE CREATE. The original read folded 403s/timeouts into absence, so this
|
|
23
|
+
* independent index check prevented creating over a live pool. The typed reader now
|
|
24
|
+
* propagates those failures, but a `CephPoolNotFound` must still not override a listed pool:
|
|
25
|
+
* the measured PG-merge risk warrants keeping both observations. Failed index reads also
|
|
26
|
+
* propagate. An empty list is trusted: the collection refuses a narrow role with 403 rather
|
|
27
|
+
* than filtering, so `[]` really does mean a cluster with no pools.
|
|
27
28
|
*
|
|
28
29
|
* ⚠️ `describe` IS STILL A PLAIN STRING (ceph-pool.ts builds it from `object`/`collection` in
|
|
29
30
|
* ceph-pool-form.ts) — this function no longer takes a `collection` PATH, since
|
|
@@ -41,5 +42,5 @@ export declare const confirmAbsent: (props: CephPoolProps, describe: string) =>
|
|
|
41
42
|
* ⚠️ SHORT POLLS, LOW CAP: 2s apart, 30 tries, about a minute. A pool create takes seconds; one
|
|
42
43
|
* still unsettled after a minute is a fault to surface, not a wait to lengthen.
|
|
43
44
|
*/
|
|
44
|
-
export declare const settle: (props: CephPoolProps, read: PoolRead
|
|
45
|
+
export declare const settle: <E>(props: CephPoolProps, read: PoolRead<E>, done: (live: CephPoolAttributes | undefined) => boolean) => Effect.Effect<CephPoolAttributes | undefined, E, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
45
46
|
//# sourceMappingURL=ceph-pool-settle.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ceph-pool-settle.d.ts","sourceRoot":"","sources":["../../src/proxmox/ceph-pool-settle.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,KAAK,MAAM,gCAAgC,CAAC;AACxD,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAE7E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAErD
|
|
1
|
+
{"version":3,"file":"ceph-pool-settle.d.ts","sourceRoot":"","sources":["../../src/proxmox/ceph-pool-settle.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,KAAK,MAAM,gCAAgC,CAAC;AACxD,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAE7E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAErD;;;;;;GAMG;AACH,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI,CACxB,KAAK,EAAE,aAAa,KACjB,MAAM,CAAC,MAAM,CAAC,kBAAkB,GAAG,SAAS,EAAE,CAAC,EAAE,eAAe,CAAC,CAAC;AAEvE;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,aAAa,UAAW,aAAa,YAAY,MAAM,4PAcjE,CAAC;AAEJ;;;;;;;;;GASG;AACH,eAAO,MAAM,MAAM,GAAI,CAAC,SACf,aAAa,QACd,QAAQ,CAAC,CAAC,CAAC,QACX,CAAC,IAAI,EAAE,kBAAkB,GAAG,SAAS,KAAK,OAAO,2GASrD,CAAC"}
|
|
@@ -7,35 +7,26 @@
|
|
|
7
7
|
* PVE form, unaware distilled exists: this file is the ONLY place that translates one into a
|
|
8
8
|
* typed distilled request.
|
|
9
9
|
*
|
|
10
|
-
* ⛔
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* (`Effect.orElseSucceed(() => undefined)`, no `output`-branching, checked directly against
|
|
18
|
-
* `resource.ts` 2026-09-24). This migration's own rule is that every existing refusal and guard
|
|
19
|
-
* survives byte-for-byte — not that it gets upgraded on the way past. `readPoolStatus` below
|
|
20
|
-
* reproduces that exact single-fold shape; it does not add the newer pattern.
|
|
21
|
-
* ⚠️ WORTH A LATER, SEPARATELY-SCOPED DECISION: this means CephPool (like CephDaemon) still folds
|
|
22
|
-
* a refused OpenBao mint into "absent" too, same as every other pre-`unreadable-read.ts` family
|
|
23
|
-
* — the cries-wolf class `Proxmox.NodeNetwork`/`Proxmox.ZfsPool`/`Proxmox.Storage` were fixed
|
|
24
|
-
* against. Noted here rather than fixed here, since fixing it is a behaviour change this PR's
|
|
25
|
-
* own rules do not ask for.
|
|
10
|
+
* ⛔ ONLY TYPED ABSENCE MAY REACH A CREATE. The transport migration deliberately preserved
|
|
11
|
+
* `pveOperations.read`'s catch-all `Effect.orElseSucceed(() => undefined)` to avoid changing
|
|
12
|
+
* behavior during the swap. That also hid refused credentials and transient failures, risking
|
|
13
|
+
* a false update/create. SDK PR #265 added the measured `CephPoolNotFound` tag; the follow-up
|
|
14
|
+
* now catches only it. One reader serves read/diff/reconcile/settle, so all propagate other
|
|
15
|
+
* failures. `confirmAbsent` still checks the index before create: a missing status alone must
|
|
16
|
+
* never override a pool that the index lists (the PG-merge incident, ceph-pool-settle.ts).
|
|
26
17
|
*/
|
|
27
18
|
import * as nodes from '@distilled.cloud/proxmox/nodes';
|
|
28
19
|
import * as Effect from 'effect/Effect';
|
|
29
20
|
import { type CephPoolAttributes, type CephPoolProps } from './ceph-pool-form.ts';
|
|
30
21
|
/**
|
|
31
|
-
* The live pool, or `undefined`
|
|
32
|
-
*
|
|
33
|
-
*
|
|
22
|
+
* The live pool, or `undefined` only for the SDK's measured `CephPoolNotFound`. The initial
|
|
23
|
+
* transport swap preserved `ops.read`'s catch-all fold; the 2026-09-24 follow-up removes that ambiguity.
|
|
24
|
+
* Read, reconcile and settle now propagate every other failure instead of assuming absence.
|
|
34
25
|
*
|
|
35
26
|
* ⛔ `verbose=1` IS WHAT MAKES `applications` VISIBLE AT ALL — ceph-pool.ts's own header has the
|
|
36
27
|
* measured reason and the cost (two extra, unguarded mon commands PVE runs to answer it).
|
|
37
28
|
*/
|
|
38
|
-
export declare const readPoolStatus: (props: CephPoolProps) => Effect.Effect<CephPoolAttributes | undefined,
|
|
29
|
+
export declare const readPoolStatus: (props: CephPoolProps) => Effect.Effect<CephPoolAttributes | undefined, Error | import("./distilled-pve.ts").PveClusterExhausted | import("./credential-errors.ts").PveCredentialDenied | import("effect/Cause").TimeoutError | nodes.ProxmoxOpError, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
39
30
|
/** The two endpoints, as the keys `guardWrite` (distilled-guard.ts) checks both forms against. */
|
|
40
31
|
export declare const CEPH_POOL_CREATE = "pve:POST /nodes/{node}/ceph/pool";
|
|
41
32
|
export declare const CEPH_POOL_UPDATE = "pve:PUT /nodes/{node}/ceph/pool/{name}";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ceph-pool-wire.d.ts","sourceRoot":"","sources":["../../src/proxmox/ceph-pool-wire.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"ceph-pool-wire.d.ts","sourceRoot":"","sources":["../../src/proxmox/ceph-pool-wire.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,KAAK,MAAM,gCAAgC,CAAC;AACxD,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAKnB,MAAM,qBAAqB,CAAC;AAqC7B;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,UAAW,aAAa,sRAShD,CAAC;AAEJ,kGAAkG;AAClG,eAAO,MAAM,gBAAgB,qCAAqC,CAAC;AACnE,eAAO,MAAM,gBAAgB,2CAA2C,CAAC;AAEzE,iGAAiG;AACjG,eAAO,MAAM,iBAAiB,UAAW,aAAa,KAAG,KAAK,CAAC,yBAIb,CAAC;AAEnD,8FAA8F;AAC9F,eAAO,MAAM,iBAAiB,UAAW,aAAa,KAAG,KAAK,CAAC,sBAKhB,CAAC"}
|
|
@@ -50,19 +50,14 @@ export declare const matches: (attributes: GroupAttributes, props: GroupProps) =
|
|
|
50
50
|
*/
|
|
51
51
|
export declare const readGroupOrFail: (props: GroupProps) => Effect.Effect<typeof UNREADABLE | GroupAttributes | undefined, import("@distilled.cloud/caddy").BadGateway | import("@distilled.cloud/caddy").BadRequest | import("@distilled.cloud/caddy").ConfigError | Error | import("@distilled.cloud/caddy").GatewayTimeout | access.GroupNotFound | import("effect/unstable/http/HttpClientError").HttpClientError | import("@distilled.cloud/caddy").InternalServerError | import("@distilled.cloud/proxmox/Errors").ParameterVerificationFailed | import("@distilled.cloud/proxmox/Errors").ProxmoxParseError | import("./distilled-pve.ts").PveClusterExhausted | import("@distilled.cloud/caddy").ServiceUnavailable | import("effect/Cause").TimeoutError | import("@distilled.cloud/caddy").TooManyRequests | import("@distilled.cloud/caddy").Unauthorized | import("@distilled.cloud/proxmox/Errors").UnknownProxmoxError, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
52
52
|
/**
|
|
53
|
-
* ⛔
|
|
54
|
-
* PVE
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
* ⛔ `group.ts`'s `diff` does **NOT** use this — found 2026-09-24, the SAME bug class as the
|
|
60
|
-
* credential denial fix: folding a TRANSIENT failure (a `PveClusterExhausted`, the encoding bug
|
|
61
|
-
* above) into "absent" at PLAN TIME is exactly what forced a false `update` with nothing
|
|
62
|
-
* compared. `diff` calls `readGroupOrFail` directly instead, so a genuine failure there
|
|
63
|
-
* propagates and fails the whole plan loudly — never silently misreports one row.
|
|
53
|
+
* ⛔ ONLY `GroupNotFound` MEANS ABSENT. The initial distilled transport swap preserved a
|
|
54
|
+
* catch-all fold because PVE reports missing objects as HTTP 500. SDK PR 265 now types that
|
|
55
|
+
* measured message, so permission errors, unrelated 500s and exhausted transports propagate
|
|
56
|
+
* instead of triggering a speculative create (decision 49 follow-up, 2026-09-24).
|
|
57
|
+
* ★ `readGroupOrFail` remains the strict path used for an already-confirmed state row. This
|
|
58
|
+
* change narrows cold reads/reconcile without changing that existing drift/diff contract.
|
|
64
59
|
*/
|
|
65
|
-
export declare const readGroup: (props: GroupProps) => Effect.Effect<typeof UNREADABLE | GroupAttributes | undefined,
|
|
60
|
+
export declare const readGroup: (props: GroupProps) => Effect.Effect<typeof UNREADABLE | GroupAttributes | undefined, import("@distilled.cloud/caddy").BadGateway | import("@distilled.cloud/caddy").BadRequest | import("@distilled.cloud/caddy").ConfigError | Error | import("@distilled.cloud/caddy").GatewayTimeout | import("effect/unstable/http/HttpClientError").HttpClientError | import("@distilled.cloud/caddy").InternalServerError | import("@distilled.cloud/proxmox/Errors").ParameterVerificationFailed | import("@distilled.cloud/proxmox/Errors").ProxmoxParseError | import("./distilled-pve.ts").PveClusterExhausted | import("@distilled.cloud/caddy").ServiceUnavailable | import("effect/Cause").TimeoutError | import("@distilled.cloud/caddy").TooManyRequests | import("@distilled.cloud/caddy").Unauthorized | import("@distilled.cloud/proxmox/Errors").UnknownProxmoxError, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
66
61
|
/** `read`/`reconcile` return `Attributes | undefined`; only `diff` tells `UNREADABLE` apart. */
|
|
67
62
|
export declare const dropUnreadable: (live: GroupAttributes | Unreadable | undefined) => GroupAttributes | undefined;
|
|
68
63
|
//# sourceMappingURL=group-wire.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"group-wire.d.ts","sourceRoot":"","sources":["../../src/proxmox/group-wire.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,MAAM,MAAM,iCAAiC,CAAC;AAC1D,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,KAAK,UAAU,EAAoB,MAAM,sBAAsB,CAAC;AAGrF,eAAO,MAAM,YAAY,4BAA4B,CAAC;AACtD,eAAO,MAAM,YAAY,qCAAqC,CAAC;AAE/D;;;;;;;;GAQG;AACH,eAAO,MAAM,aAAa,YAAa,MAAM,GAAG,SAAS,WAGxD,CAAC;AAQF,eAAO,MAAM,UAAU,UAAW,UAAU,KAAG,MAAM,CAAC,wBAGpD,CAAC;AAEH,iGAAiG;AACjG,eAAO,MAAM,UAAU,UAAW,UAAU,KAAG,MAAM,CAAC,qBAGpD,CAAC;AAaH;;;GAGG;AACH,eAAO,MAAM,OAAO,eAAgB,eAAe,SAAS,UAAU,YACjB,CAAC;AAEtD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,eAAe,UAAW,UAAU,o4BAW9C,CAAC;AAEJ
|
|
1
|
+
{"version":3,"file":"group-wire.d.ts","sourceRoot":"","sources":["../../src/proxmox/group-wire.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,MAAM,MAAM,iCAAiC,CAAC;AAC1D,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,KAAK,UAAU,EAAoB,MAAM,sBAAsB,CAAC;AAGrF,eAAO,MAAM,YAAY,4BAA4B,CAAC;AACtD,eAAO,MAAM,YAAY,qCAAqC,CAAC;AAE/D;;;;;;;;GAQG;AACH,eAAO,MAAM,aAAa,YAAa,MAAM,GAAG,SAAS,WAGxD,CAAC;AAQF,eAAO,MAAM,UAAU,UAAW,UAAU,KAAG,MAAM,CAAC,wBAGpD,CAAC;AAEH,iGAAiG;AACjG,eAAO,MAAM,UAAU,UAAW,UAAU,KAAG,MAAM,CAAC,qBAGpD,CAAC;AAaH;;;GAGG;AACH,eAAO,MAAM,OAAO,eAAgB,eAAe,SAAS,UAAU,YACjB,CAAC;AAEtD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,eAAe,UAAW,UAAU,o4BAW9C,CAAC;AAEJ;;;;;;;GAOG;AACH,eAAO,MAAM,SAAS,UAAW,UAAU,62BACqD,CAAC;AAEjG,gGAAgG;AAChG,eAAO,MAAM,cAAc,SAAU,eAAe,GAAG,UAAU,GAAG,SAAS,gCACrC,CAAC"}
|
package/dist/proxmox/index.js
CHANGED
|
@@ -1690,9 +1690,7 @@ var listRows = (props) => {
|
|
|
1690
1690
|
return runPve(props.target, "read", false, nodes.listNodeCephMds({ node })).pipe(Effect13.map((rows) => rows));
|
|
1691
1691
|
}
|
|
1692
1692
|
};
|
|
1693
|
-
var readDaemon = (props) => listRows(props).pipe(Effect13.map((rows) => daemonAttributes(rows, props))
|
|
1694
|
-
return;
|
|
1695
|
-
}));
|
|
1693
|
+
var readDaemon = (props) => listRows(props).pipe(Effect13.map((rows) => daemonAttributes(rows, props)));
|
|
1696
1694
|
var createDaemon = (props) => {
|
|
1697
1695
|
const node = props.node;
|
|
1698
1696
|
const id = daemonId(props);
|
|
@@ -1850,9 +1848,7 @@ var notCreated2 = (props) => new Error(`${objectPath(props)}: the create task fi
|
|
|
1850
1848
|
var notDestroyed = (props) => new Error(`${objectPath(props)}: the destroy task finished but the filesystem is still in ` + `GET nodes/${props.node}/ceph/fs. PVE refuses to destroy a CephFS while a PVE storage entry ` + "of type cephfs still references it and is not disabled.");
|
|
1851
1849
|
|
|
1852
1850
|
// src/proxmox/ceph-fs-distilled.ts
|
|
1853
|
-
var readFs = (props) => runPve(props.target, "read", false, nodes2.listNodeCephFs({ node: props.node })).pipe(Effect17.map((rows) => readRow(rows, props))
|
|
1854
|
-
return;
|
|
1855
|
-
}));
|
|
1851
|
+
var readFs = (props) => runPve(props.target, "read", false, nodes2.listNodeCephFs({ node: props.node })).pipe(Effect17.map((rows) => readRow(rows, props)));
|
|
1856
1852
|
var toDistilledCreate = (props) => ({
|
|
1857
1853
|
...createForm2(props),
|
|
1858
1854
|
name: props.name,
|
|
@@ -2105,9 +2101,7 @@ var attributesOf3 = (live, props) => {
|
|
|
2105
2101
|
target_size_ratio: num(row["target_size_ratio"], UNSET)
|
|
2106
2102
|
};
|
|
2107
2103
|
};
|
|
2108
|
-
var readPoolStatus = (props) => runPve(props.target, "read", false, nodes6.getNodeCephPoolStatus({ name: props.name, node: props.node, verbose: "1" })).pipe(Effect23.map((live) => attributesOf3(live, props)), Effect23.
|
|
2109
|
-
return;
|
|
2110
|
-
}));
|
|
2104
|
+
var readPoolStatus = (props) => runPve(props.target, "read", false, nodes6.getNodeCephPoolStatus({ name: props.name, node: props.node, verbose: "1" })).pipe(Effect23.map((live) => attributesOf3(live, props)), Effect23.catchTag("CephPoolNotFound", () => Effect23.succeed(undefined)));
|
|
2111
2105
|
var CEPH_POOL_CREATE = "pve:POST /nodes/{node}/ceph/pool";
|
|
2112
2106
|
var CEPH_POOL_UPDATE = "pve:PUT /nodes/{node}/ceph/pool/{name}";
|
|
2113
2107
|
var toDistilledCreate2 = (props) => ({
|
|
@@ -2258,9 +2252,7 @@ var attributesOf4 = (live, props) => ({
|
|
|
2258
2252
|
});
|
|
2259
2253
|
var matches4 = (attributes, props) => attributes.comment === storedComment(props.comment);
|
|
2260
2254
|
var readGroupOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, access3.getAccessGroup({ groupid: props.groupid }))).pipe(Effect26.map((live) => live === UNREADABLE ? UNREADABLE : live.members === undefined ? undefined : attributesOf4(live, props)));
|
|
2261
|
-
var readGroup = (props) => readGroupOrFail(props).pipe(Effect26.
|
|
2262
|
-
return;
|
|
2263
|
-
}));
|
|
2255
|
+
var readGroup = (props) => readGroupOrFail(props).pipe(Effect26.catchTag("GroupNotFound", () => Effect26.succeed(undefined)));
|
|
2264
2256
|
var dropUnreadable3 = (live) => live === UNREADABLE ? undefined : live;
|
|
2265
2257
|
|
|
2266
2258
|
// src/proxmox/group.ts
|
|
@@ -4917,9 +4909,7 @@ var attributesOf8 = (live, props) => ({
|
|
|
4917
4909
|
});
|
|
4918
4910
|
var matches8 = (attributes2, props) => attributes2.comment === (props.comment ?? "") && attributes2.email === (props.email ?? "") && attributes2.enable === (props.enable !== false) && attributes2.expire === (props.expire ?? 0) && attributes2.firstname === (props.firstname ?? "") && attributes2.lastname === (props.lastname ?? "") && attributes2.groups.join(",") === groupSet(props.groups).join(",");
|
|
4919
4911
|
var readUserOrFail = (props) => readOrUnreadable(runPve(props.target, "read", false, access6.getAccessUser({ userid: props.userid }))).pipe(Effect58.map((live) => live === UNREADABLE ? UNREADABLE : attributesOf8(live, props)));
|
|
4920
|
-
var readUser = (props) => readUserOrFail(props).pipe(Effect58.
|
|
4921
|
-
return;
|
|
4922
|
-
}));
|
|
4912
|
+
var readUser = (props) => readUserOrFail(props).pipe(Effect58.catchTag("UserNotFound", () => Effect58.succeed(undefined)));
|
|
4923
4913
|
var dropUnreadable6 = (live) => live === UNREADABLE ? undefined : live;
|
|
4924
4914
|
|
|
4925
4915
|
// src/proxmox/user.ts
|
|
@@ -5381,9 +5371,7 @@ var attributesOf9 = (live, props) => {
|
|
|
5381
5371
|
};
|
|
5382
5372
|
};
|
|
5383
5373
|
var readStorageOrFail = (props) => readOrUnreadable(runPve(props.target, "provision", false, storage.getStorage({ storage: props.storage }))).pipe(Effect68.map((live) => live === UNREADABLE ? UNREADABLE : attributesOf9(live, props)));
|
|
5384
|
-
var readStorage = (props) => readStorageOrFail(props).pipe(Effect68.
|
|
5385
|
-
return;
|
|
5386
|
-
}));
|
|
5374
|
+
var readStorage = (props) => readStorageOrFail(props).pipe(Effect68.catchTag("StorageNotFound", () => Effect68.succeed(undefined)));
|
|
5387
5375
|
var dropUnreadable7 = (live) => live === UNREADABLE ? undefined : live;
|
|
5388
5376
|
var matches9 = (attributes2, props) => sameList2(props.content, attributes2.content) && sameList2(props.nodes, attributes2.nodes) && sameList2(props["prune-backups"], attributes2["prune-backups"]) && same7(props.disable, attributes2.disable) && same7(props.shared, attributes2.shared) && same7(props.preallocation, attributes2.preallocation) && same7(props.comment, attributes2.comment);
|
|
5389
5377
|
|
|
@@ -5619,5 +5607,5 @@ export {
|
|
|
5619
5607
|
violations
|
|
5620
5608
|
};
|
|
5621
5609
|
|
|
5622
|
-
//# debugId=
|
|
5610
|
+
//# debugId=34DF7A874403817964756E2164756E21
|
|
5623
5611
|
//# sourceMappingURL=index.js.map
|