@homeflare/alchemy 0.42.0 → 0.43.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 (80) hide show
  1. package/dist/litellm/budget-errors.d.ts +36 -0
  2. package/dist/litellm/budget-errors.d.ts.map +1 -0
  3. package/dist/litellm/budget-form.d.ts +50 -0
  4. package/dist/litellm/budget-form.d.ts.map +1 -0
  5. package/dist/litellm/budget-operations.d.ts +20 -0
  6. package/dist/litellm/budget-operations.d.ts.map +1 -0
  7. package/dist/litellm/budget.d.ts +61 -0
  8. package/dist/litellm/budget.d.ts.map +1 -0
  9. package/dist/litellm/fake-litellm.d.ts +5 -0
  10. package/dist/litellm/fake-litellm.d.ts.map +1 -1
  11. package/dist/litellm/index.d.ts +2 -0
  12. package/dist/litellm/index.d.ts.map +1 -1
  13. package/dist/litellm/index.js +125 -2
  14. package/dist/litellm/index.js.map +9 -5
  15. package/dist/litellm/operations.d.ts +22 -0
  16. package/dist/litellm/operations.d.ts.map +1 -1
  17. package/dist/litellm/providers.d.ts +1 -1
  18. package/dist/litellm/providers.d.ts.map +1 -1
  19. package/dist/openbao/auth-role-form.d.ts +9 -0
  20. package/dist/openbao/auth-role-form.d.ts.map +1 -1
  21. package/dist/openbao/auth-role-wire.d.ts.map +1 -1
  22. package/dist/openbao/fake-engines-roles.d.ts.map +1 -1
  23. package/dist/openbao/index.js +9 -6
  24. package/dist/openbao/index.js.map +4 -4
  25. package/dist/postgres/connection.d.ts +20 -2
  26. package/dist/postgres/connection.d.ts.map +1 -1
  27. package/dist/postgres/database-sql.d.ts +1 -1
  28. package/dist/postgres/database-sql.d.ts.map +1 -1
  29. package/dist/postgres/database.d.ts +1 -1
  30. package/dist/postgres/database.d.ts.map +1 -1
  31. package/dist/postgres/index.d.ts +5 -3
  32. package/dist/postgres/index.d.ts.map +1 -1
  33. package/dist/postgres/index.js +124 -38
  34. package/dist/postgres/index.js.map +8 -7
  35. package/dist/postgres/providers.d.ts +4 -2
  36. package/dist/postgres/providers.d.ts.map +1 -1
  37. package/dist/postgres/psql-executor.d.ts +21 -0
  38. package/dist/postgres/psql-executor.d.ts.map +1 -0
  39. package/dist/proxmox/ceph-flag-types.d.ts +57 -0
  40. package/dist/proxmox/ceph-flag-types.d.ts.map +1 -0
  41. package/dist/proxmox/ceph-flag-wire.d.ts +77 -0
  42. package/dist/proxmox/ceph-flag-wire.d.ts.map +1 -0
  43. package/dist/proxmox/ceph-flag.d.ts +15 -50
  44. package/dist/proxmox/ceph-flag.d.ts.map +1 -1
  45. package/dist/proxmox/ceph-osd-write.d.ts +10 -13
  46. package/dist/proxmox/ceph-osd-write.d.ts.map +1 -1
  47. package/dist/proxmox/index.js +772 -740
  48. package/dist/proxmox/index.js.map +8 -7
  49. package/docs/litellm-budget.md +55 -0
  50. package/docs/litellm.md +7 -6
  51. package/docs/postgres.md +22 -0
  52. package/docs/proxmox-sdk-migration.md +45 -0
  53. package/package.json +3 -3
  54. package/src/litellm/budget-errors.ts +38 -0
  55. package/src/litellm/budget-form.ts +94 -0
  56. package/src/litellm/budget-operations.ts +51 -0
  57. package/src/litellm/budget.test.ts +105 -0
  58. package/src/litellm/budget.ts +127 -0
  59. package/src/litellm/fake-litellm.ts +50 -1
  60. package/src/litellm/index.ts +13 -0
  61. package/src/litellm/operations.ts +1 -1
  62. package/src/litellm/providers.ts +4 -1
  63. package/src/openbao/auth-role-form.test.ts +37 -0
  64. package/src/openbao/auth-role-form.ts +12 -1
  65. package/src/openbao/auth-role-wire.test.ts +1 -0
  66. package/src/openbao/auth-role-wire.ts +13 -1
  67. package/src/openbao/distilled-retry.test.ts +1 -0
  68. package/src/openbao/fake-engines-roles.ts +7 -1
  69. package/src/postgres/connection.ts +37 -3
  70. package/src/postgres/database-sql.ts +4 -3
  71. package/src/postgres/database.ts +3 -2
  72. package/src/postgres/index.ts +10 -3
  73. package/src/postgres/providers.ts +15 -2
  74. package/src/postgres/psql-executor.test.ts +106 -0
  75. package/src/postgres/psql-executor.ts +130 -0
  76. package/src/proxmox/ceph-flag-types.ts +70 -0
  77. package/src/proxmox/ceph-flag-wire.test.ts +72 -0
  78. package/src/proxmox/ceph-flag-wire.ts +123 -0
  79. package/src/proxmox/ceph-flag.ts +77 -130
  80. package/src/proxmox/ceph-osd-write.ts +10 -13
@@ -9,6 +9,8 @@
9
9
  * the results under whatever logical grouping it wants.
10
10
  */
11
11
  import * as Layer from 'effect/Layer';
12
- import { type PostgresConnectionConfig } from './connection.ts';
13
- export declare const postgresProviders: (config: PostgresConnectionConfig) => Layer.Layer<import("alchemy").Provider<import("./database.ts").PostgresDatabase>, never, never>;
12
+ import { type PostgresConnectionConfig, type PostgresRunnerConfig } from './connection.ts';
13
+ export declare const postgresProviders: (config: PostgresConnectionConfig) => Layer.Layer<import("./connection.ts").PostgresConnection | import("alchemy").Provider<import("./database.ts").PostgresDatabase>, never, never>;
14
+ /** The same provider over a command runner (`psql-executor.ts`) — for a loopback-only cluster. */
15
+ export declare const postgresRunnerProviders: (config: PostgresRunnerConfig) => Layer.Layer<import("./connection.ts").PostgresConnection | import("alchemy").Provider<import("./database.ts").PostgresDatabase>, never, never>;
14
16
  //# sourceMappingURL=providers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../../src/postgres/providers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,KAAK,wBAAwB,EAAsB,MAAM,iBAAiB,CAAC;AAGpF,eAAO,MAAM,iBAAiB,WAAY,wBAAwB,oGACU,CAAC"}
1
+ {"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../../src/postgres/providers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,EACL,KAAK,wBAAwB,EAC7B,KAAK,oBAAoB,EAG1B,MAAM,iBAAiB,CAAC;AAOzB,eAAO,MAAM,iBAAiB,WAAY,wBAAwB,mJACe,CAAC;AAElF,kGAAkG;AAClG,eAAO,MAAM,uBAAuB,WAAY,oBAAoB,mJACmB,CAAC"}
@@ -0,0 +1,21 @@
1
+ import { type PgExecutor } from './database-sql.ts';
2
+ export interface PsqlResult {
3
+ readonly code: number;
4
+ readonly stdout: string;
5
+ readonly stderr: string;
6
+ }
7
+ /** Runs one `psql` argv (starting with `psql`) with `stdin` and answers its exit. The consumer's
8
+ * implementation prepends the transport (`ssh … sudo -n podman exec -i <container>`) and owns
9
+ * the timeout and output bound: the kit sets neither. */
10
+ export type PsqlRunner = (call: {
11
+ readonly argv: readonly string[];
12
+ readonly stdin: string;
13
+ }) => Promise<PsqlResult>;
14
+ export interface PsqlTarget {
15
+ readonly database: string;
16
+ readonly username: string;
17
+ }
18
+ /** Replace `$1…$n` with string literals; refuses a non-string param or a missing one. */
19
+ export declare const inlineParams: (sql: string, params: ReadonlyArray<unknown>) => string;
20
+ export declare const makePsqlExecutor: (run: PsqlRunner, target: PsqlTarget) => PgExecutor;
21
+ //# sourceMappingURL=psql-executor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"psql-executor.d.ts","sourceRoot":"","sources":["../../src/postgres/psql-executor.ts"],"names":[],"mappings":"AAyBA,OAAO,EAAE,KAAK,UAAU,EAAsB,MAAM,mBAAmB,CAAC;AAExE,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;yDAEyD;AACzD,MAAM,MAAM,UAAU,GAAG,CAAC,IAAI,EAAE;IAC9B,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;AAE1B,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,yFAAyF;AACzF,eAAO,MAAM,YAAY,QAAS,MAAM,UAAU,aAAa,CAAC,OAAO,CAAC,KAAG,MASnE,CAAC;AAgCT,eAAO,MAAM,gBAAgB,QAAS,UAAU,UAAU,UAAU,KAAG,UAyCrE,CAAC"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Flag names, props and attributes for `Proxmox.CephFlag`.
3
+ *
4
+ * ★ SPLIT OUT OF ceph-flag.ts FOR THE 250-LINE CAP. The comments stay with the types they
5
+ * explain; nothing here talks to the cluster.
6
+ */
7
+ import type { WithTarget } from './resource-spec.ts';
8
+ /**
9
+ * PVE's eleven flags, spelled as `PVE::Ceph::Tools::get_possible_osd_flags` spells them.
10
+ *
11
+ * ⚠️ THE ENUM IS CLOSED AND A TYPO IS A 400, WHICH IS WHY THIS IS A UNION AND NOT `string`. Both
12
+ * the GET and the PUT declare `additionalProperties => 0` over exactly this list.
13
+ * ⚠️ CEPH HAS FLAGS PVE DOES NOT MODEL, and four of them are always on. MEASURED on C1:
14
+ * `ceph osd dump` reports `flags sortbitwise,recovery_deletes,purged_snapdirs,pglog_hardlimit`.
15
+ * PVE reads that same string and answers only about its own eleven, so the others can neither
16
+ * leak in here nor be set from here — `noautoscale` and `nosnaptrim` included.
17
+ * ⛔ IF SOMEBODY LATER "IMPROVES" THE READ BY PARSING `osd dump` DIRECTLY, those four become
18
+ * permanently-set flags that nothing declares: a forever-diff on a brand new cluster.
19
+ */
20
+ export type CephFlagName = 'nobackfill' | 'nodeep-scrub' | 'nodown' | 'noin' | 'noout' | 'norebalance' | 'norecover' | 'noscrub' | 'notieragent' | 'noup' | 'pause';
21
+ export interface CephFlagProps extends WithTarget {
22
+ /**
23
+ * Which flag. PVE's primary key here, and the last segment of the path.
24
+ *
25
+ * ⚠️ EDITING IT IN PLACE ORPHANS THE OLD FLAG RATHER THAN MOVING ANYTHING. `diff` reads the NEW
26
+ * path and reconcile writes it, while the old flag keeps whatever this stack last put there.
27
+ * There is deliberately no replace override for it — acl.ts needs one because its `delete`
28
+ * removes a real grant, and `delete` here is inert by design, so a replace would do exactly
29
+ * what an update already does. Declare a second resource and set the old one to `value: false`
30
+ * rather than renaming this one.
31
+ * ⛔ TWO RESOURCES DECLARING THE SAME FLAG ARE ONE CLUSTER OBJECT, and Alchemy sees two ids
32
+ * rather than a collision — the acl.ts hazard exactly. Disagreeing, they take turns winning
33
+ * and BOTH plan `update` for ever; agreeing, deleting either leaves the flag where the other
34
+ * put it. One declaration per flag per cluster.
35
+ */
36
+ flag: CephFlagName;
37
+ /**
38
+ * Set the flag (`true`) or clear it (`false`).
39
+ *
40
+ * ⛔ REQUIRED, WITH NO DEFAULT — see the second ⛔ in the header, which is the whole safety
41
+ * argument for this family. It is also the only field PVE accepts on this endpoint, and it is
42
+ * not optional in the schema either: omitting it from the form is a 400, not an untouched
43
+ * flag. (The BULK endpoint is the one where omission means "leave it alone"; this is not it.)
44
+ */
45
+ value: boolean;
46
+ }
47
+ export interface CephFlagAttributes {
48
+ /**
49
+ * ⚠️ REPORTED, NEVER COMPARED. It is the path key the read was made WITH, copied back out of
50
+ * props, so comparing it against props would be true by construction — the same reasoning
51
+ * acl.ts gives for the four identity fields it also declines to diff.
52
+ */
53
+ flag: CephFlagName;
54
+ /** Whether ceph has the flag set right now. The only field `matches` looks at. */
55
+ value: boolean;
56
+ }
57
+ //# sourceMappingURL=ceph-flag-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ceph-flag-types.d.ts","sourceRoot":"","sources":["../../src/proxmox/ceph-flag-types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,YAAY,GACpB,YAAY,GACZ,cAAc,GACd,QAAQ,GACR,MAAM,GACN,OAAO,GACP,aAAa,GACb,WAAW,GACX,SAAS,GACT,aAAa,GACb,MAAM,GACN,OAAO,CAAC;AAEZ,MAAM,WAAW,aAAc,SAAQ,UAAU;IAC/C;;;;;;;;;;;;;OAaG;IACH,IAAI,EAAE,YAAY,CAAC;IACnB;;;;;;;OAOG;IACH,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,IAAI,EAAE,YAAY,CAAC;IACnB,kFAAkF;IAClF,KAAK,EAAE,OAAO,CAAC;CAChB"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * `Proxmox.CephFlag`'s distilled wire lane: the read and the single-flag write.
3
+ *
4
+ * ★ SPLIT OUT OF ceph-flag.ts FOR THE 250-LINE CAP, mirroring ceph-pool-wire.ts's split by "touches
5
+ * the cluster or not" — ceph-flag.ts keeps the header, the props/attributes shapes, `matches` and
6
+ * the provider wiring; this file is the only place that calls `runPve` for this family.
7
+ *
8
+ * ⛔ NEITHER OPERATION HERE DECLARES A TYPED ABSENCE (`errors: []` on both `getClusterCephFlag` and
9
+ * `putClusterCephFlag`, MEASURED in distilled-proxmox/src/services/cluster.ts) — UNLIKE
10
+ * ceph-pool-wire.ts's `CephPoolNotFound`. All eleven flags always exist (ceph-flag.ts's own ⛔ on
11
+ * `CephFlagName` and on the old unreachable create branch), so there is no absence case to fold
12
+ * here. `readClusterCephFlag` therefore has no `catchTag` at all and lets every failure — a
13
+ * refused credential, a timeout, cluster exhaustion — propagate to the caller exactly as it
14
+ * arrived, rather than inventing an "absent" this family does not have. Simpler than
15
+ * ceph-pool-wire.ts's case, not harder.
16
+ * ⚠️ THIS IS A BEHAVIOR CHANGE FROM THE PRE-MIGRATION FACTORY, AND A DELIBERATE ONE. The old
17
+ * `pveOperations.read` folded EVERY failure into `undefined` via `Effect.orElseSucceed`, so an
18
+ * expired lease or node-b being down looked identical to "the flag is absent" (which cannot
19
+ * happen — see ceph-flag.ts). Now such a failure propagates as itself: a caller sees the real
20
+ * error (an expired 300s lease, node-b down, ceph not configured) rather than a misleading
21
+ * "absent" that would have sent `diff`/`reconcile` down a create path this endpoint has never
22
+ * implemented. Same advice as the old comment gave, sharper because the failure is no longer
23
+ * disguised.
24
+ *
25
+ * ⛔ THE PER-FLAG PUT IS SYNCHRONOUS (`$rados->mon_command` inline, MEASURED in Ceph.pm — see
26
+ * ceph-flag.ts's header), which is what makes reading back immediately after
27
+ * `writeClusterCephFlag` fair rather than a race against a worker task, unlike ceph-pool.ts's
28
+ * forked-worker writes.
29
+ */
30
+ import * as cluster from '@distilled.cloud/proxmox/cluster';
31
+ import * as Effect from 'effect/Effect';
32
+ import type { CephFlagAttributes, CephFlagProps } from './ceph-flag.ts';
33
+ /** The one endpoint this family writes, as `guardWrite` (distilled-guard.ts) keys it. */
34
+ export declare const CEPH_FLAG_UPDATE = "pve:PUT /cluster/ceph/flags/{flag}";
35
+ /**
36
+ * ⛔ DIE ON THE POST-TRANSFORM SHAPE, NOT THE PRE-TRANSFORM ONE. `bool` treats a missing value as
37
+ * `false` because most callers hand it an optional PVE form field where that is correct — but
38
+ * here it would read an unmeasured "no answer" as "flag is clear". distilled's
39
+ * `transformResponse` maps a `{"data":null}` body to `{}` BEFORE this function sees it (a shape
40
+ * `get_flag`'s `type => 'boolean'` schema does not document and this PVE has never produced).
41
+ * Guarding only `null`/`undefined` lets that `{}` through, and `bool({})` is `false` — a plan
42
+ * of `noop` over a set brake, with no read-back guard, because `reconcile`'s guard only fires
43
+ * on a write. A success here is a scalar (`true`/`false`/`0`/`1`/`'0'`/`'1'`). Anything else,
44
+ * including the empty object the protocol substitutes for null, is the unmeasured shape.
45
+ */
46
+ export declare const scalarFlagOrDie: (live: unknown, props: CephFlagProps) => Effect.Effect<string | number | boolean, never, never>;
47
+ /**
48
+ * The live flag, as attributes.
49
+ *
50
+ * ⚠️ NO ABSENCE TAG, ON PURPOSE. Both operations declare `errors: []` (see the file header), so
51
+ * there is nothing to `catchTag` except `PveCredentialDenied`, and that one is caught by the
52
+ * caller that plans (`readClusterCephFlagForDiff`) — not here. `read` and `reconcile` must
53
+ * still see a refused mint as itself.
54
+ */
55
+ export declare const readClusterCephFlag: (props: CephFlagProps) => Effect.Effect<CephFlagAttributes, Error | import("./distilled-pve.ts").PveClusterExhausted | import("./credential-errors.ts").PveCredentialDenied | import("effect/Cause").TimeoutError | cluster.ProxmoxOpError, import("effect/unstable/http/HttpClient").HttpClient>;
56
+ /**
57
+ * The same read, with a refused mint turned into `UNREADABLE`.
58
+ *
59
+ * ⛔ `diff` MUST NOT FAIL ON A REFUSED READ. Alchemy runs every resource's `diff` under
60
+ * `Effect.exit` and fails the whole plan if one fails (unreadable-read.ts). A lane that cannot
61
+ * mint `read` would otherwise abort every other row, not just this flag. `read` and
62
+ * `reconcile` keep the propagating form above.
63
+ */
64
+ export declare const readClusterCephFlagForDiff: (props: CephFlagProps) => Effect.Effect<typeof import("./unreadable-read.ts").UNREADABLE | CephFlagAttributes, import("@distilled.cloud/caddy").BadGateway | import("@distilled.cloud/caddy").BadRequest | import("@distilled.cloud/caddy").ConfigError | import("@distilled.cloud/caddy").Conflict | Error | import("@distilled.cloud/caddy").Forbidden | import("@distilled.cloud/caddy").GatewayTimeout | import("effect/unstable/http/HttpClientError").HttpClientError | import("@distilled.cloud/caddy").InternalServerError | import("@distilled.cloud/caddy").Locked | import("@distilled.cloud/caddy").NotFound | 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("@distilled.cloud/caddy").UnprocessableEntity, import("effect/unstable/http/HttpClient").HttpClient>;
65
+ /**
66
+ * ⚠️ ONLY `value` GOES IN THE BODY. `flag` is already bound by the path and the PUT declares
67
+ * `additionalProperties => 0`, so a second copy in the form could only disagree with the URL.
68
+ * ⚠️ THE `?? '0'` IS UNREACHABLE, AND IS WRITTEN RATHER THAN CAST AWAY. `flag()` types its answer
69
+ * `string | undefined` because it serves OPTIONAL props, and `value` here is required, so the
70
+ * branch cannot be taken; a cast would claim a proof the type system has not made.
71
+ */
72
+ export declare const updateForm: (props: CephFlagProps) => {
73
+ value: string;
74
+ };
75
+ /** The actual `putClusterCephFlag` call — `updateForm`'s own `value`, so the two cannot disagree. */
76
+ export declare const writeClusterCephFlag: (props: CephFlagProps) => Effect.Effect<cluster.PutClusterCephFlagResponse, Error | import("./distilled-pve.ts").PveClusterExhausted | import("./credential-errors.ts").PveCredentialDenied | import("effect/Cause").TimeoutError | cluster.ProxmoxOpError, import("effect/unstable/http/HttpClient").HttpClient>;
77
+ //# sourceMappingURL=ceph-flag-wire.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ceph-flag-wire.d.ts","sourceRoot":"","sources":["../../src/proxmox/ceph-flag-wire.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,OAAO,KAAK,OAAO,MAAM,kCAAkC,CAAC;AAC5D,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAKxE,yFAAyF;AACzF,eAAO,MAAM,gBAAgB,uCAAuC,CAAC;AAkBrE;;;;;;;;;;GAUG;AACH,eAAO,MAAM,eAAe,SAAU,OAAO,SAAS,aAAa,2DAalE,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB,UAAW,aAAa,4QAIrD,CAAC;AAEJ;;;;;;;GAOG;AACH,eAAO,MAAM,0BAA0B,UAAW,aAAa,ymCACjB,CAAC;AAE/C;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,UAAW,aAAa;;CAA0C,CAAC;AAE1F,qGAAqG;AACrG,eAAO,MAAM,oBAAoB,UAAW,aAAa,4RAMtD,CAAC"}
@@ -74,58 +74,23 @@
74
74
  */
75
75
  import { Resource } from 'alchemy';
76
76
  import * as Provider from 'alchemy/Provider';
77
- import { type PveRequirements, type WithTarget } from './resource.ts';
78
- /**
79
- * PVE's eleven flags, spelled as `PVE::Ceph::Tools::get_possible_osd_flags` spells them.
80
- *
81
- * ⚠️ THE ENUM IS CLOSED AND A TYPO IS A 400, WHICH IS WHY THIS IS A UNION AND NOT `string`. Both
82
- * the GET and the PUT declare `additionalProperties => 0` over exactly this list.
83
- * ⚠️ CEPH HAS FLAGS PVE DOES NOT MODEL, and four of them are always on. MEASURED on C1:
84
- * `ceph osd dump` reports `flags sortbitwise,recovery_deletes,purged_snapdirs,pglog_hardlimit`.
85
- * PVE reads that same string and answers only about its own eleven, so the others can neither
86
- * leak in here nor be set from here — `noautoscale` and `nosnaptrim` included.
87
- * ⛔ IF SOMEBODY LATER "IMPROVES" THE READ BY PARSING `osd dump` DIRECTLY, those four become
88
- * permanently-set flags that nothing declares: a forever-diff on a brand new cluster.
89
- */
90
- export type CephFlagName = 'nobackfill' | 'nodeep-scrub' | 'nodown' | 'noin' | 'noout' | 'norebalance' | 'norecover' | 'noscrub' | 'notieragent' | 'noup' | 'pause';
91
- export interface CephFlagProps extends WithTarget {
92
- /**
93
- * Which flag. PVE's primary key here, and the last segment of the path.
94
- *
95
- * ⚠️ EDITING IT IN PLACE ORPHANS THE OLD FLAG RATHER THAN MOVING ANYTHING. `diff` reads the NEW
96
- * path and reconcile writes it, while the old flag keeps whatever this stack last put there.
97
- * There is deliberately no replace override for it — acl.ts needs one because its `delete`
98
- * removes a real grant, and `delete` here is inert by design, so a replace would do exactly
99
- * what an update already does. Declare a second resource and set the old one to `value: false`
100
- * rather than renaming this one.
101
- * ⛔ TWO RESOURCES DECLARING THE SAME FLAG ARE ONE CLUSTER OBJECT, and Alchemy sees two ids
102
- * rather than a collision — the acl.ts hazard exactly. Disagreeing, they take turns winning
103
- * and BOTH plan `update` for ever; agreeing, deleting either leaves the flag where the other
104
- * put it. One declaration per flag per cluster.
105
- */
106
- flag: CephFlagName;
107
- /**
108
- * Set the flag (`true`) or clear it (`false`).
109
- *
110
- * ⛔ REQUIRED, WITH NO DEFAULT — see the second ⛔ in the header, which is the whole safety
111
- * argument for this family. It is also the only field PVE accepts on this endpoint, and it is
112
- * not optional in the schema either: omitting it from the form is a 400, not an untouched
113
- * flag. (The BULK endpoint is the one where omission means "leave it alone"; this is not it.)
114
- */
115
- value: boolean;
116
- }
117
- export interface CephFlagAttributes {
118
- /**
119
- * ⚠️ REPORTED, NEVER COMPARED. It is the path key the read was made WITH, copied back out of
120
- * props, so comparing it against props would be true by construction — the same reasoning
121
- * acl.ts gives for the four identity fields it also declines to diff.
122
- */
123
- flag: CephFlagName;
124
- /** Whether ceph has the flag set right now. The only field `matches` looks at. */
125
- value: boolean;
126
- }
77
+ import type { CephFlagAttributes, CephFlagProps } from './ceph-flag-types.ts';
78
+ import type { PveRequirements } from './resource-spec.ts';
79
+ export type { CephFlagAttributes, CephFlagName, CephFlagProps } from './ceph-flag-types.ts';
127
80
  export interface ProxmoxCephFlag extends Resource<'Proxmox.CephFlag', CephFlagProps, CephFlagAttributes, never, PveRequirements> {
128
81
  }
129
82
  export declare const ProxmoxCephFlag: import("alchemy").ResourceClass<ProxmoxCephFlag>;
83
+ /**
84
+ * ★ MIGRATED OFF `pveHandlers`/`client.ts`'s generic `pve()` ONTO `@distilled.cloud/proxmox`'s
85
+ * typed `cluster.getClusterCephFlag`/`cluster.putClusterCephFlag` (ceph-flag-wire.ts).
86
+ * `pveHandlers` cannot run a distilled operation, so `diff`/`reconcile` are hand-written here,
87
+ * the same way ceph-pool.ts and backup-job.ts hand-write theirs for the same reason.
88
+ *
89
+ * ⛔ THIS FAMILY HAS NO CREATE KEY, AND THAT IS THE VENDOR'S DOING, NOT AN OMISSION HERE. PVE
90
+ * registers only `PUT /cluster/ceph/flags/{flag}`; `POST /cluster/ceph/flags` does not exist
91
+ * (constraints-forms.test.ts's own regression test), which is why the second ⛔ in the header
92
+ * above calls the create branch unreachable — there is no create form and no create endpoint to
93
+ * guard, only `CEPH_FLAG_UPDATE`.
94
+ */
130
95
  export declare const ProxmoxCephFlagProvider: () => import("effect/Layer").Layer<Provider.Provider<ProxmoxCephFlag>, never, import("effect/unstable/http/HttpClient").HttpClient>;
131
96
  //# sourceMappingURL=ceph-flag.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ceph-flag.d.ts","sourceRoot":"","sources":["../../src/proxmox/ceph-flag.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyEG;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;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,YAAY,GACpB,YAAY,GACZ,cAAc,GACd,QAAQ,GACR,MAAM,GACN,OAAO,GACP,aAAa,GACb,WAAW,GACX,SAAS,GACT,aAAa,GACb,MAAM,GACN,OAAO,CAAC;AAEZ,MAAM,WAAW,aAAc,SAAQ,UAAU;IAC/C;;;;;;;;;;;;;OAaG;IACH,IAAI,EAAE,YAAY,CAAC;IACnB;;;;;;;OAOG;IACH,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,IAAI,EAAE,YAAY,CAAC;IACnB,kFAAkF;IAClF,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,eAAgB,SAAQ,QAAQ,CAC/C,kBAAkB,EAClB,aAAa,EACb,kBAAkB,EAClB,KAAK,EACL,eAAe,CAChB;CAAG;AAEJ,eAAO,MAAM,eAAe,kDAAgD,CAAC;AAsD7E,eAAO,MAAM,uBAAuB,qIA4CjC,CAAC"}
1
+ {"version":3,"file":"ceph-flag.d.ts","sourceRoot":"","sources":["../../src/proxmox/ceph-flag.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyEG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAY7C,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC9E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAG1D,YAAY,EAAE,kBAAkB,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE5F,MAAM,WAAW,eAAgB,SAAQ,QAAQ,CAC/C,kBAAkB,EAClB,aAAa,EACb,kBAAkB,EAClB,KAAK,EACL,eAAe,CAChB;CAAG;AAEJ,eAAO,MAAM,eAAe,kDAAgD,CAAC;AAc7E;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,uBAAuB,qIAoEjC,CAAC"}
@@ -52,19 +52,16 @@ export declare const createOsd: (news: CephOsdProps) => Effect.Effect<import("./
52
52
  * ⚠️ `cleanup` DEFAULTS TO FALSE, so the logical volumes survive and the disk can be re-added
53
53
  * without a rebuild. Ceph still starts backfilling the missing copies the moment the OSD goes.
54
54
  *
55
- * ⚠️ `cleanup` RIDES A DELETE BODY, ON `client.ts` AND ON DISTILLED ALIKE — PRE-EXISTING, NOT
56
- * INTRODUCED HERE. `client.ts`'s own `buildRequest` (client.ts) puts `form` in the body for
57
- * every method, DELETE included, and CHECKED against distilled's generated
58
- * `DeleteNodeCephOsdRequest`: `cleanup` carries no `T.Query()` annotation either, so it also
59
- * defaults to a body field. ceph-fs-wire.ts's own ⛔ (measured from PVE's `AnyEvent.pm`) is that
60
- * PVE's server never reads a body on DELETE — so `cleanup=1` was ALREADY silently ignored by
61
- * the live cluster before this migration, on the unmigrated code too. Migrating carries the
62
- * SAME behaviour forward exactly, byte-for-byte, rather than introducing a new gap; unlike
63
- * `Proxmox.CephFs`'s delete, this is not a reason to keep the call on the hand client. It has
64
- * zero practical effect today regardless, since the whole DELETE 403s for this package's
65
- * credential either way (the root-only ⛔ at the top of ceph-osd.ts) — flagged separately as a
66
- * pre-existing, out-of-scope bug worth its own fix (move `cleanup` into the query string, the
67
- * way `destroyPath` in ceph-fs-wire.ts already does).
55
+ * ★ CORRECTED 2026-09-28: `cleanup` IS QUERY-BOUND ON DISTILLED, NOT BODY. This comment previously
56
+ * claimed `DeleteNodeCephOsdRequest.cleanup` carried no `T.Query()` annotation and so rode the
57
+ * DELETE body, silently ignored by PVE's server (which never reads a body on DELETE, per
58
+ * ceph-fs-wire.ts's measurement of `AnyEvent.pm`). That was true of the old `client.ts` hand
59
+ * client, but distilled-proxmox's generated schema
60
+ * (`packages/distilled-proxmox/src/services/nodes.ts`) declares
61
+ * `cleanup: S.optional(S.String.pipe(T.Query()))` — query-bound — as of SDK 0.3.0, the same fix
62
+ * that landed for the sibling `Proxmox.CephFs`'s `destroyFs`. Since this file already runs on
63
+ * distilled (`import * as nodes from '@distilled.cloud/proxmox/nodes'`), `cleanup: '1'` below
64
+ * reaches PVE correctly today. No code change needed here; this was a stale doc claim only.
68
65
  */
69
66
  export declare const destroyOsd: (olds: CephOsdProps) => 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>;
70
67
  //# sourceMappingURL=ceph-osd-write.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ceph-osd-write.d.ts","sourceRoot":"","sources":["../../src/proxmox/ceph-osd-write.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,KAAK,MAAM,gCAAgC,CAAC;AACxD,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAGpD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,mBAAmB,EAAE,WAA+C,CAAC;AAIlF;;;GAGG;AACH,eAAO,MAAM,aAAa,UAAW,YAAY,OAAO,MAAM,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAGpF,CAAC;AAEH,eAAO,MAAM,SAAS,4QAsCpB,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,UAAU,SAAU,YAAY,8PAU1C,CAAC"}
1
+ {"version":3,"file":"ceph-osd-write.d.ts","sourceRoot":"","sources":["../../src/proxmox/ceph-osd-write.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,KAAK,MAAM,gCAAgC,CAAC;AACxD,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAGpD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,mBAAmB,EAAE,WAA+C,CAAC;AAIlF;;;GAGG;AACH,eAAO,MAAM,aAAa,UAAW,YAAY,OAAO,MAAM,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAGpF,CAAC;AAEH,eAAO,MAAM,SAAS,4QAsCpB,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,eAAO,MAAM,UAAU,SAAU,YAAY,8PAU1C,CAAC"}