@homeflare/alchemy 0.35.0 → 0.37.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.
- package/README.md +14 -0
- package/dist/argocd/cluster.d.ts +102 -0
- package/dist/argocd/cluster.d.ts.map +1 -0
- package/dist/argocd/credentials.d.ts +37 -0
- package/dist/argocd/credentials.d.ts.map +1 -0
- package/dist/argocd/fake-argocd.d.ts +42 -0
- package/dist/argocd/fake-argocd.d.ts.map +1 -0
- package/dist/argocd/git-credentials.d.ts +29 -0
- package/dist/argocd/git-credentials.d.ts.map +1 -0
- package/dist/argocd/index.d.ts +19 -0
- package/dist/argocd/index.d.ts.map +1 -0
- package/dist/argocd/index.js +306 -0
- package/dist/argocd/index.js.map +17 -0
- package/dist/argocd/providers.d.ts +13 -0
- package/dist/argocd/providers.d.ts.map +1 -0
- package/dist/argocd/repo-creds.d.ts +67 -0
- package/dist/argocd/repo-creds.d.ts.map +1 -0
- package/dist/argocd/repository.d.ts +87 -0
- package/dist/argocd/repository.d.ts.map +1 -0
- package/dist/argocd/resource.d.ts +90 -0
- package/dist/argocd/resource.d.ts.map +1 -0
- package/dist/cloudflare/index.js +4 -4
- package/dist/cloudflare/index.js.map +3 -3
- package/dist/cloudflare/r2-bucket-lock.d.ts +14 -5
- package/dist/cloudflare/r2-bucket-lock.d.ts.map +1 -1
- package/dist/grafana/index.d.ts +5 -4
- package/dist/grafana/index.d.ts.map +1 -1
- package/dist/grafana/index.js +204 -90
- package/dist/grafana/index.js.map +7 -4
- package/dist/grafana/notification-policy-drop-warning.d.ts +27 -0
- package/dist/grafana/notification-policy-drop-warning.d.ts.map +1 -0
- package/dist/grafana/notification-policy-fixtures.d.ts +34 -0
- package/dist/grafana/notification-policy-fixtures.d.ts.map +1 -0
- package/dist/grafana/notification-policy-model.d.ts +53 -0
- package/dist/grafana/notification-policy-model.d.ts.map +1 -0
- package/dist/grafana/notification-policy.d.ts +57 -0
- package/dist/grafana/notification-policy.d.ts.map +1 -0
- package/dist/grafana/providers.d.ts +1 -1
- package/dist/grafana/providers.d.ts.map +1 -1
- package/dist/litellm/index.js.map +2 -2
- package/dist/litellm/operations.d.ts.map +1 -1
- package/dist/proxmox/ceph-daemon-form.d.ts +4 -5
- package/dist/proxmox/ceph-daemon-form.d.ts.map +1 -1
- package/dist/proxmox/ceph-daemon-wire.d.ts +33 -0
- package/dist/proxmox/ceph-daemon-wire.d.ts.map +1 -0
- package/dist/proxmox/ceph-daemon.d.ts +35 -0
- package/dist/proxmox/ceph-daemon.d.ts.map +1 -1
- package/dist/proxmox/ceph-fs-distilled.d.ts +14 -0
- package/dist/proxmox/ceph-fs-distilled.d.ts.map +1 -0
- package/dist/proxmox/ceph-fs-wire.d.ts +20 -11
- package/dist/proxmox/ceph-fs-wire.d.ts.map +1 -1
- package/dist/proxmox/ceph-fs.d.ts +31 -6
- package/dist/proxmox/ceph-fs.d.ts.map +1 -1
- package/dist/proxmox/ceph-osd-tree.d.ts +12 -3
- package/dist/proxmox/ceph-osd-tree.d.ts.map +1 -1
- package/dist/proxmox/ceph-osd-write.d.ts +17 -2
- package/dist/proxmox/ceph-osd-write.d.ts.map +1 -1
- package/dist/proxmox/ceph-osd.d.ts +6 -0
- package/dist/proxmox/ceph-osd.d.ts.map +1 -1
- package/dist/proxmox/ceph-pool-settle.d.ts +10 -4
- package/dist/proxmox/ceph-pool-settle.d.ts.map +1 -1
- package/dist/proxmox/ceph-pool-wire.d.ts +46 -0
- package/dist/proxmox/ceph-pool-wire.d.ts.map +1 -0
- package/dist/proxmox/ceph-pool.d.ts +10 -5
- package/dist/proxmox/ceph-pool.d.ts.map +1 -1
- package/dist/proxmox/group-wire.d.ts +1 -1
- package/dist/proxmox/group-wire.d.ts.map +1 -1
- package/dist/proxmox/index.js +611 -477
- package/dist/proxmox/index.js.map +15 -12
- package/dist/proxmox/storage-wire.d.ts +8 -1
- package/dist/proxmox/storage-wire.d.ts.map +1 -1
- package/dist/proxmox/user-wire.d.ts +1 -1
- package/dist/proxmox/user-wire.d.ts.map +1 -1
- package/docs/argocd-kubernetes.md +100 -0
- package/docs/argocd.md +139 -0
- package/docs/credentials.md +9 -0
- package/docs/grafana-alerting.md +3 -2
- package/docs/grafana-notification-policy.md +127 -0
- package/docs/grafana.md +12 -8
- package/docs/litellm.md +17 -0
- package/docs/peers.md +7 -0
- package/docs/unifi.md +45 -0
- package/docs/upstream-conformance.md +19 -5
- package/package.json +8 -3
- package/src/argocd/cluster.test.ts +120 -0
- package/src/argocd/cluster.ts +222 -0
- package/src/argocd/credentials.ts +38 -0
- package/src/argocd/fake-argocd.ts +60 -0
- package/src/argocd/git-credentials.ts +71 -0
- package/src/argocd/index.ts +40 -0
- package/src/argocd/providers.ts +17 -0
- package/src/argocd/repo-creds.test.ts +123 -0
- package/src/argocd/repo-creds.ts +115 -0
- package/src/argocd/repository.test.ts +167 -0
- package/src/argocd/repository.ts +165 -0
- package/src/argocd/resource.ts +150 -0
- package/src/cloudflare/r2-bucket-lock.test.ts +54 -18
- package/src/cloudflare/r2-bucket-lock.ts +25 -18
- package/src/grafana/index.ts +11 -4
- package/src/grafana/notification-policy-drop-warning.test.ts +163 -0
- package/src/grafana/notification-policy-drop-warning.ts +60 -0
- package/src/grafana/notification-policy-fixtures.ts +27 -0
- package/src/grafana/notification-policy-model.test.ts +104 -0
- package/src/grafana/notification-policy-model.ts +100 -0
- package/src/grafana/notification-policy-refusals.test.ts +119 -0
- package/src/grafana/notification-policy.test.ts +86 -0
- package/src/grafana/notification-policy.ts +191 -0
- package/src/grafana/providers.ts +2 -0
- package/src/litellm/operations.ts +8 -4
- package/src/proxmox/ceph-daemon-form.ts +7 -8
- package/src/proxmox/ceph-daemon-wire.ts +115 -0
- package/src/proxmox/ceph-daemon-write.test.ts +158 -0
- package/src/proxmox/ceph-daemon.ts +65 -47
- package/src/proxmox/ceph-fs-delete.test.ts +81 -0
- package/src/proxmox/ceph-fs-distilled.ts +102 -0
- package/src/proxmox/ceph-fs-wire.ts +17 -31
- package/src/proxmox/ceph-fs-write.test.ts +67 -0
- package/src/proxmox/ceph-fs.ts +66 -69
- package/src/proxmox/ceph-osd-tree.ts +14 -5
- package/src/proxmox/ceph-osd-write.test.ts +61 -0
- package/src/proxmox/ceph-osd-write.ts +33 -6
- package/src/proxmox/ceph-osd.ts +6 -0
- package/src/proxmox/ceph-pool-settle.ts +13 -7
- package/src/proxmox/ceph-pool-wire.ts +110 -0
- package/src/proxmox/ceph-pool-write.test.ts +145 -0
- package/src/proxmox/ceph-pool.ts +87 -98
- package/src/proxmox/distilled-task-await.test.ts +0 -124
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
"sources": ["../src/litellm/pass-through-endpoint.ts", "../src/litellm/operations.ts", "../src/litellm/pass-through-errors.ts", "../src/litellm/pass-through-form.ts", "../src/litellm/providers.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
5
|
"/**\n * `LiteLLM.PassThroughEndpoint` — one row in LiteLLM's `general_settings.pass_through_endpoints`.\n *\n * ★ ADOPT-FRIENDLY BY id, NOT BY PATH. `output?.id` is used as the object's live id once the\n * engine has one — from our own prior create (the deterministic physical name) or from an\n * adopted foreign row — and `read` computes a FRESH physical name only for a resource the\n * engine has never resolved before. This is S7/S9's \"output is a cache of stable identifiers,\n * not proof the object exists\" and S13's \"an adopted object keeps its live name as an explicit\n * prop\", applied to an id LiteLLM lets a client choose (`_types.py:2192` at v1.100.0: create\n * takes a caller-supplied `id`, else `uuid4()`).\n *\n * ⛔ A PATH HELD BY AN `is_from_config` ROW IS REFUSED, NOT ADOPTED. A DB row on the same path\n * overrides it at runtime (`pass_through_endpoints.py` merges DB after config, at the tag) — so\n * creating one would silently take over a route the operator declared in `config.yaml`, the\n * exact \"DB row silently overrides the file\" the task names. `is_from_config` rows are also\n * never updated or deleted by this provider, for the same reason.\n * ⛔ A DB ROW WITH NO `id` (path-only, `_types.py`'s \"backwards compatibility\" case) CANNOT BE\n * ADDRESSED by the id-keyed update/delete calls this provider uses, so it is refused rather than\n * silently adopted into an id-based lifecycle it cannot actually manage — see docs/litellm.md.\n * ⛔ NO CREDENTIAL IS A PROP (S25). `LITELLM_PROXY_URL`/`LITELLM_PROXY_API_KEY` are read at call\n * time by `@distilled.cloud/litellm`'s own `CredentialsFromEnv` (providers.ts) — the same two\n * variable names the retired hand-rolled `credentials.ts` read.\n */\nimport { Resource } from 'alchemy';\nimport { Unowned } from 'alchemy/AdoptPolicy';\nimport { isResolved } from 'alchemy/Diff';\nimport type { Input } from 'alchemy/Input';\nimport { createPhysicalName } from 'alchemy/PhysicalName';\nimport * as Provider from 'alchemy/Provider';\nimport type { Stack } from 'alchemy/Stack';\nimport type { Stage } from 'alchemy/Stage';\nimport type * as misc from '@distilled.cloud/litellm/misc';\nimport * as Effect from 'effect/Effect';\nimport * as Predicate from 'effect/Predicate';\nimport {\n type LitellmRequirements,\n createPassThroughEndpoint,\n deletePassThroughEndpoint,\n listPassThroughEndpoints,\n updatePassThroughEndpoint,\n} from './operations.ts';\nimport {\n LitellmConfigPathConflictError,\n LitellmLiteralSecretHeaderError,\n LitellmUnaddressableRowError,\n} from './pass-through-errors.ts';\nimport {\n type PassThroughEndpointAttributes,\n type PassThroughEndpointProps,\n createBody,\n literalSecretHeaders,\n matches,\n needsReplace,\n updateBody,\n} from './pass-through-form.ts';\n\nexport type { PassThroughEndpointAttributes, PassThroughEndpointProps };\nexport {\n LitellmConfigPathConflictError,\n LitellmLiteralSecretHeaderError,\n LitellmUnaddressableRowError,\n type PassThroughEndpointError,\n} from './pass-through-errors.ts';\n\nexport interface LiteLLMPassThroughEndpoint extends Resource<\n 'LiteLLM.PassThroughEndpoint',\n PassThroughEndpointProps,\n PassThroughEndpointAttributes,\n never,\n LitellmRequirements | Stack | Stage\n> {}\n\nexport const LiteLLMPassThroughEndpoint = Resource<LiteLLMPassThroughEndpoint>(\n 'LiteLLM.PassThroughEndpoint',\n);\n\nexport const isLiteLLMPassThroughEndpoint = (value: unknown): value is LiteLLMPassThroughEndpoint =>\n Predicate.hasProperty(value, 'Type') && value.Type === 'LiteLLM.PassThroughEndpoint';\n\nconst toAttributes = (\n row: misc.PassThroughGenericEndpoint,\n fallbackId: string,\n): PassThroughEndpointAttributes => ({\n ...row,\n id: row.id ?? fallbackId,\n});\n\nconst physicalIdOf = (logicalId: string, instanceId: string) =>\n createPhysicalName({ id: logicalId, instanceId, lowercase: true, maxLength: 64 });\n\n/**\n * Find this resource's live row (by id) and, when absent, the row that already holds its `path`\n * (a config-file row to refuse, or a DB row LiteLLM did not give an id — also refused, see the\n * file header — or a genuine foreign DB row to hand back `Unowned`).\n */\nconst locate = (\n rows: readonly misc.PassThroughGenericEndpoint[],\n objectId: string,\n path: string,\n): {\n readonly mine: misc.PassThroughGenericEndpoint | undefined;\n readonly conflict: misc.PassThroughGenericEndpoint | undefined;\n} => {\n const mine = rows.find((row) => row.id === objectId);\n const conflict = mine === undefined ? rows.find((row) => row.path === path) : undefined;\n return { conflict, mine };\n};\n\n/** The typed refusal for a `path` conflict that cannot ever be adopted (config row, or no id). */\nconst conflictRefusal = (conflict: misc.PassThroughGenericEndpoint, path: string) =>\n conflict.is_from_config === true\n ? new LitellmConfigPathConflictError({ path })\n : new LitellmUnaddressableRowError({ path });\n\n/** `read`'s answer for a path conflict: `Unowned` when it is a real, addressable DB row — a typed refusal otherwise. */\nconst readConflict = (conflict: misc.PassThroughGenericEndpoint, path: string) =>\n conflict.is_from_config !== true && conflict.id !== undefined && conflict.id !== null\n ? Effect.succeed(Unowned(toAttributes(conflict, conflict.id)))\n : Effect.fail(conflictRefusal(conflict, path));\n\nconst refuseLiteralSecrets = (headers: Readonly<Record<string, unknown>> | undefined) => {\n const bad = literalSecretHeaders(headers);\n return bad.length === 0\n ? Effect.void\n : Effect.fail(new LitellmLiteralSecretHeaderError({ headers: bad }));\n};\n\n/** ⛔ TEST-ONLY EXPORT. Not on index.ts's barrel — a lifecycle test calls these directly against the fake. */\nexport const passThroughHandlers = {\n read: ({\n id,\n instanceId,\n olds,\n output,\n }: {\n id: string;\n instanceId: string;\n olds: PassThroughEndpointProps;\n output: PassThroughEndpointAttributes | undefined;\n }) =>\n Effect.gen(function* () {\n const objectId = output?.id ?? (yield* physicalIdOf(id, instanceId));\n const rows = yield* listPassThroughEndpoints();\n const { conflict, mine } = locate(rows, objectId, olds.path);\n if (mine !== undefined) return toAttributes(mine, objectId);\n if (conflict === undefined) return undefined;\n return yield* readConflict(conflict, olds.path);\n }),\n\n diff: ({\n news,\n output,\n }: {\n news: Input<PassThroughEndpointProps>;\n output: PassThroughEndpointAttributes | undefined;\n }) =>\n Effect.gen(function* () {\n if (!isResolved(news)) return undefined;\n yield* refuseLiteralSecrets(news.headers);\n if (output === undefined) return undefined;\n // ⛔ deleteFirst: TRUE — a create-first replace mints a new instanceId/id before the old row\n // on `path` is gone, so the new generation's `reconcile` would refuse it as a foreign\n // conflict (Apply.ts). Same fix this kit's other unique-identity providers use.\n if (needsReplace(output, news)) return { action: 'replace', deleteFirst: true } as const;\n return matches(output, news)\n ? ({ action: 'noop' } as const)\n : ({ action: 'update' } as const);\n }),\n\n reconcile: ({\n id,\n instanceId,\n news,\n output,\n }: {\n id: string;\n instanceId: string;\n news: PassThroughEndpointProps;\n output: PassThroughEndpointAttributes | undefined;\n }) =>\n Effect.gen(function* () {\n yield* refuseLiteralSecrets(news.headers);\n const objectId = output?.id ?? (yield* physicalIdOf(id, instanceId));\n const rows = yield* listPassThroughEndpoints();\n const { conflict, mine } = locate(rows, objectId, news.path);\n\n if (mine === undefined) {\n // ⚠️ A CONFLICT HERE — reconcile, not read — means ownership shifted between plan and\n // apply (a config row or a foreign DB row landed on this path after `read` cleared it).\n // `read` gates a genuine adopt by returning `Unowned`; reconcile itself never adopts,\n // so ANY conflict here fails rather than risking a second row on one path.\n if (conflict !== undefined) return yield* Effect.fail(conflictRefusal(conflict, news.path));\n yield* createPassThroughEndpoint(createBody(news, objectId));\n } else if (mine.is_from_config === true) {\n // ⛔ NEVER UPDATE OR DELETE AN `is_from_config` ROW, even one this resource's own\n // deterministic id happens to match (a config.yaml author could in principle choose the\n // same id `createPhysicalName` would). Refuse rather than silently editing the file's row.\n return yield* Effect.fail(new LitellmConfigPathConflictError({ path: news.path }));\n } else if (needsReplace(toAttributes(mine, objectId), news)) {\n yield* deletePassThroughEndpoint(objectId);\n yield* createPassThroughEndpoint(createBody(news, objectId));\n } else if (!matches(toAttributes(mine, objectId), news)) {\n const body = updateBody(news);\n if (Object.keys(body).length > 0) yield* updatePassThroughEndpoint(objectId, body);\n }\n\n const after = (yield* listPassThroughEndpoints()).find((row) => row.id === objectId);\n if (after === undefined) {\n return yield* Effect.die(\n new Error(\n `LiteLLM.PassThroughEndpoint ${news.path}: the write returned no error but id ` +\n `${objectId} is still absent from GET /config/pass_through_endpoint — read back ` +\n 'rather than trusting the call that just returned.',\n ),\n );\n }\n return toAttributes(after, objectId);\n }),\n\n delete: ({\n id,\n instanceId,\n olds,\n output,\n }: {\n id: string;\n instanceId: string;\n olds: PassThroughEndpointProps;\n output: PassThroughEndpointAttributes;\n }) =>\n Effect.gen(function* () {\n const objectId = output.id ?? (yield* physicalIdOf(id, instanceId));\n const rows = yield* listPassThroughEndpoints();\n const live = rows.find((row) => row.id === objectId);\n // ⛔ NEVER DELETE AN `is_from_config` ROW, and a DB row this resource never created (a path\n // match with a different id) is not this resource's to remove either.\n if (live === undefined || live.is_from_config === true || live.path !== olds.path) return;\n yield* deletePassThroughEndpoint(objectId);\n }),\n\n list: () => Effect.succeed([]),\n};\n\nexport const LiteLLMPassThroughEndpointProvider = () =>\n Provider.effect(\n LiteLLMPassThroughEndpoint,\n Effect.succeed(LiteLLMPassThroughEndpoint.Provider.of(passThroughHandlers)),\n );\n",
|
|
6
|
-
"/**\n * The four LiteLLM `/config/pass_through_endpoint*` calls this package writes to and reads from —\n * now through `@distilled.cloud/litellm`'s typed operations (S23), not a hand-rolled `HttpClient`\n * client. `client.ts` is retired; nothing else in this package imported it.\n *\n * ⛔ STILL WRAPPED IN A PER-BASE-URL SEMAPHORE, UNCHANGED FROM `client.ts`. LiteLLM stores every\n * pass-through endpoint in ONE `general_settings.pass_through_endpoints` list\n * (`pass_through_endpoints.py` at tag v1.100.0, mirrored in the SDK's own `misc.ts` docstrings),\n * so create/update/delete are each a read-modify-write of the WHOLE list through\n * `update_config_general_settings`. Two of this package's own calls racing each other — two\n * endpoints created in the same deploy — would each read the list, add their own row and write\n * it back, and the second write would silently drop the first row. The SDK has no opinion on\n * this: it is a quirk of how THIS vendor stores the resource, not a distilled protocol concern,\n * so it stays here, one layer above the typed calls. One permit per proxy serialises this\n * package's own writes; it cannot serialise against the LiteLLM UI or a second deploy process,\n * which is why `pass-through-endpoint.ts`'s `reconcile` reads back after writing rather than\n * trusting the call that just returned (docs/litellm.md).\n * ⛔ NO STATUS SNIFFING (S21). Every failure the SDK's own typed operations declare — `BadRequest`\n * (400), `NotFound` (404 on update only), `UnprocessableEntity` (422) plus the shared\n * `Unauthorized`/`TooManyRequests`/`InternalServerError`/`BadGateway`/`ServiceUnavailable`/\n * `GatewayTimeout` every operation carries — is a distilled patch's doing\n * (`@distilled.cloud/litellm`'s own `patches/misc/*.json`, applied at generation time), never a\n * status check here or in `pass-through-endpoint.ts`. Deleting an id LiteLLM does not have\n * answers `BadRequest` (measured against the tag's `pass_through_endpoint_delete` — the id is\n * looked up in the list and a miss raises `HTTPException(400)`, not 404) — but so does a\n * genuinely-live row when the caller isn't PROXY_ADMIN, or the DB is disconnected. Telling those\n * apart by re-listing, not by the `BadRequest`'s message text, is `pass-through-endpoint.ts`'s\n * `deletePassThroughEndpoint`'s own job (S21 — a status-and-a-real-read decision, never body\n * text) — this file only forwards the typed error.\n */\nimport * as misc from '@distilled.cloud/litellm/misc';\nimport { Credentials } from '@distilled.cloud/litellm/Credentials';\nimport type { LitellmOpContext } from '@distilled.cloud/litellm/Protocol';\nimport type { ConfigError } from '@distilled.cloud/litellm/Errors';\nimport * as Effect from 'effect/Effect';\nimport * as Semaphore from 'effect/Semaphore';\n\nexport type { LitellmOpContext } from '@distilled.cloud/litellm/Protocol';\nexport type LitellmRequirements = LitellmOpContext;\nexport type {\n PassThroughEndpointResponse,\n PassThroughGenericEndpoint,\n PassThroughGuardrailSettings,\n} from '@distilled.cloud/litellm/misc';\n\nconst semaphores = new Map<string, Semaphore.Semaphore>();\n\n/** One semaphore per base URL, created on first use. Never `Hash.structure` (S18) — a plain Map key. */\nconst semaphoreFor = (baseUrl: string): Effect.Effect<Semaphore.Semaphore> =>\n Effect.sync(() => {\n const existing = semaphores.get(baseUrl);\n if (existing !== undefined) return existing;\n const created = Semaphore.makeUnsafe(1);\n semaphores.set(baseUrl, created);\n return created;\n });\n\n/**\n * Serialises a write against this call's own base URL — see the file header.\n *\n *
|
|
6
|
+
"/**\n * The four LiteLLM `/config/pass_through_endpoint*` calls this package writes to and reads from —\n * now through `@distilled.cloud/litellm`'s typed operations (S23), not a hand-rolled `HttpClient`\n * client. `client.ts` is retired; nothing else in this package imported it.\n *\n * ⛔ STILL WRAPPED IN A PER-BASE-URL SEMAPHORE, UNCHANGED FROM `client.ts`. LiteLLM stores every\n * pass-through endpoint in ONE `general_settings.pass_through_endpoints` list\n * (`pass_through_endpoints.py` at tag v1.100.0, mirrored in the SDK's own `misc.ts` docstrings),\n * so create/update/delete are each a read-modify-write of the WHOLE list through\n * `update_config_general_settings`. Two of this package's own calls racing each other — two\n * endpoints created in the same deploy — would each read the list, add their own row and write\n * it back, and the second write would silently drop the first row. The SDK has no opinion on\n * this: it is a quirk of how THIS vendor stores the resource, not a distilled protocol concern,\n * so it stays here, one layer above the typed calls. One permit per proxy serialises this\n * package's own writes; it cannot serialise against the LiteLLM UI or a second deploy process,\n * which is why `pass-through-endpoint.ts`'s `reconcile` reads back after writing rather than\n * trusting the call that just returned (docs/litellm.md).\n * ⛔ NO STATUS SNIFFING (S21). Every failure the SDK's own typed operations declare — `BadRequest`\n * (400), `NotFound` (404 on update only), `UnprocessableEntity` (422) plus the shared\n * `Unauthorized`/`TooManyRequests`/`InternalServerError`/`BadGateway`/`ServiceUnavailable`/\n * `GatewayTimeout` every operation carries — is a distilled patch's doing\n * (`@distilled.cloud/litellm`'s own `patches/misc/*.json`, applied at generation time), never a\n * status check here or in `pass-through-endpoint.ts`. Deleting an id LiteLLM does not have\n * answers `BadRequest` (measured against the tag's `pass_through_endpoint_delete` — the id is\n * looked up in the list and a miss raises `HTTPException(400)`, not 404) — but so does a\n * genuinely-live row when the caller isn't PROXY_ADMIN, or the DB is disconnected. Telling those\n * apart by re-listing, not by the `BadRequest`'s message text, is `pass-through-endpoint.ts`'s\n * `deletePassThroughEndpoint`'s own job (S21 — a status-and-a-real-read decision, never body\n * text) — this file only forwards the typed error.\n */\nimport * as misc from '@distilled.cloud/litellm/misc';\nimport { Credentials } from '@distilled.cloud/litellm/Credentials';\nimport type { LitellmOpContext } from '@distilled.cloud/litellm/Protocol';\nimport type { ConfigError } from '@distilled.cloud/litellm/Errors';\nimport * as Effect from 'effect/Effect';\nimport * as Semaphore from 'effect/Semaphore';\n\nexport type { LitellmOpContext } from '@distilled.cloud/litellm/Protocol';\nexport type LitellmRequirements = LitellmOpContext;\nexport type {\n PassThroughEndpointResponse,\n PassThroughGenericEndpoint,\n PassThroughGuardrailSettings,\n} from '@distilled.cloud/litellm/misc';\n\nconst semaphores = new Map<string, Semaphore.Semaphore>();\n\n/** One semaphore per base URL, created on first use. Never `Hash.structure` (S18) — a plain Map key. */\nconst semaphoreFor = (baseUrl: string): Effect.Effect<Semaphore.Semaphore> =>\n Effect.sync(() => {\n const existing = semaphores.get(baseUrl);\n if (existing !== undefined) return existing;\n const created = Semaphore.makeUnsafe(1);\n semaphores.set(baseUrl, created);\n return created;\n });\n\n/**\n * Serialises a write against this call's own base URL — see the file header.\n *\n * ⚠️ `Credentials` itself ends in `Effect.orDie` on a missing/misspelled env var (Q6, decision\n * 49 \"upstream wins\", 2026-09-24, matching distilled's own convention — 73 of 80 packages'\n * `credentials.ts` do the same at `homeflare/base`), so resolving it here can no longer fail\n * typed. The `| ConfigError` this function still adds to its return type stays only because\n * `@distilled.cloud/litellm`'s own `LitellmOpError` (protocol.ts) unconditionally declares\n * `ConfigError` as a member of every generated operation's error union regardless of\n * `Credentials`'s own type — so `E` (the wrapped operation's error) already contains it, and\n * this widening is a genuine no-op for callers, not dead type-state left over from the revert.\n */\nconst mutate = <A, E>(\n io: Effect.Effect<A, E, LitellmOpContext>,\n): Effect.Effect<A, E | ConfigError, LitellmOpContext> =>\n Effect.gen(function* () {\n const resolve = yield* Credentials;\n const creds = yield* resolve;\n const semaphore = yield* semaphoreFor(creds.apiBaseUrl);\n return yield* semaphore.withPermits(1)(io);\n });\n\n/** GET /config/pass_through_endpoint — every row, config-file and DB alike. Not under the semaphore: reads don't race the field. */\nexport const listPassThroughEndpoints = (): Effect.Effect<\n readonly misc.PassThroughGenericEndpoint[],\n misc.GetPassThroughEndpointsConfigPassThroughEndpointGetError,\n LitellmOpContext\n> =>\n misc\n .getPassThroughEndpointsConfigPassThroughEndpointGet({})\n .pipe(Effect.map((response) => response.endpoints));\n\n/** POST /config/pass_through_endpoint. `body` carries `id` — see pass-through-form.ts. */\nexport const createPassThroughEndpoint = (\n body: misc.PassThroughGenericEndpoint,\n): Effect.Effect<\n void,\n misc.CreatePassThroughEndpointsConfigPassThroughEndpointPostError,\n LitellmOpContext\n> => mutate(misc.createPassThroughEndpointsConfigPassThroughEndpointPost(body).pipe(Effect.asVoid));\n\n/**\n * POST /config/pass_through_endpoint/{endpoint_id}. Merges with `exclude_none` — see\n * pass-through-form.ts. `body` is `pass-through-form.ts`'s own `UpdateBody`, not a blanket\n * `Partial<>` — `path`/`target` are the two fields the SDK's request type still requires\n * non-optionally on an update.\n */\nexport const updatePassThroughEndpoint = (\n endpointId: string,\n body: Partial<Omit<misc.PassThroughGenericEndpoint, 'path' | 'target'>> &\n Pick<misc.PassThroughGenericEndpoint, 'path' | 'target'>,\n): Effect.Effect<\n void,\n misc.UpdatePassThroughEndpointsConfigPassThroughEndpointEndpointIdPostError,\n LitellmOpContext\n> =>\n mutate(\n misc\n .updatePassThroughEndpointsConfigPassThroughEndpointEndpointIdPost({\n ...body,\n endpoint_id: endpointId,\n })\n .pipe(Effect.asVoid),\n );\n\n/**\n * DELETE /config/pass_through_endpoint?endpoint_id=… — idempotent BY THIS FUNCTION, not by the\n * vendor. ⚠️ Measured at v1.100.0: deleting an id the list does not have raises `HTTPException(400)`\n * from `pass_through_endpoint_delete`, which the SDK decodes as a typed `BadRequest` — but the SAME\n * route also raises the SAME `BadRequest` for `not_allowed_access` (a non-PROXY_ADMIN caller) or a\n * disconnected DB, on a row that never got deleted. A `BadRequest` alone cannot tell the two apart,\n * so THIS FUNCTION DOESN'T GUESS FROM THE TAG ALONE: on `BadRequest` it re-lists (a GET — no\n * PROXY_ADMIN required) and only treats the delete as already-done if `endpointId` is genuinely\n * absent; otherwise the delete failed and this re-fails with the ORIGINAL error, not a message\n * match (S21 — a status-and-a-real-read decision, never body text).\n */\nexport const deletePassThroughEndpoint = (\n endpointId: string,\n): Effect.Effect<\n void,\n misc.DeletePassThroughEndpointsConfigPassThroughEndpointDeleteError,\n LitellmOpContext\n> =>\n mutate(\n misc\n .deletePassThroughEndpointsConfigPassThroughEndpointDelete({ endpoint_id: endpointId })\n .pipe(\n Effect.asVoid,\n Effect.catchTag('BadRequest', (original) =>\n Effect.gen(function* () {\n const rows = yield* listPassThroughEndpoints();\n if (rows.some((row) => row.id === endpointId)) return yield* Effect.fail(original);\n }),\n ),\n ),\n );\n",
|
|
7
7
|
"/**\n * The typed refusals `LiteLLM.PassThroughEndpoint` raises on top of `@distilled.cloud/litellm`'s\n * own SDK errors — split out of pass-through-endpoint.ts to keep that file under the house's\n * 250-line cap once this migration added the four named SDK error-union re-exports.\n */\nimport type * as misc from '@distilled.cloud/litellm/misc';\nimport * as Data from 'effect/Data';\n\nexport class LitellmConfigPathConflictError extends Data.TaggedError(\n 'LitellmConfigPathConflictError',\n)<{\n readonly path: string;\n}> {}\nexport class LitellmUnaddressableRowError extends Data.TaggedError('LitellmUnaddressableRowError')<{\n readonly path: string;\n}> {}\nexport class LitellmLiteralSecretHeaderError extends Data.TaggedError(\n 'LitellmLiteralSecretHeaderError',\n)<{\n readonly headers: readonly string[];\n}> {}\n\n/**\n * ⛔ THE FOUR SDK ERROR UNIONS, NAMED, NOT `LitellmOpError` ALONE. `catchTag`'s tag-literal\n * inference needs a concrete union to resolve `\"BadRequest\"`/`\"NotFound\"` against (the same\n * reason `netbox/resource.ts` leaves `NotFound` folding to each resource file, not its shared\n * engine) — `operations.ts` already returns each call's own precise per-operation error type, so\n * this is just their union, not a re-widening.\n */\nexport type PassThroughEndpointError =\n | misc.GetPassThroughEndpointsConfigPassThroughEndpointGetError\n | misc.CreatePassThroughEndpointsConfigPassThroughEndpointPostError\n | misc.UpdatePassThroughEndpointsConfigPassThroughEndpointEndpointIdPostError\n | misc.DeletePassThroughEndpointsConfigPassThroughEndpointDeleteError\n | LitellmConfigPathConflictError\n | LitellmUnaddressableRowError\n | LitellmLiteralSecretHeaderError;\n",
|
|
8
8
|
"/**\n * The wire body for a `LiteLLM.PassThroughEndpoint`, the comparison that decides whether it needs\n * writing, and the refusals that stop a plan before it writes anything unsafe.\n *\n * ★ EXTRACTED SO IT CAN BE TESTED WITHOUT A SERVER — the same reason netbox keeps `prefix-form.ts`\n * beside `prefix.ts` (S32/testing-and-docs.md).\n *\n * ⛔ PROPS ARE `@distilled.cloud/litellm`'s OWN GENERATED TYPE, MINUS THE TWO FIELDS THIS RESOURCE\n * OWNS ITSELF: `id` (a deterministic physical name — pass-through-endpoint.ts) and\n * `is_from_config` (response-only; the vendor sets it, a declaration never does). Deriving\n * `Props` with `Omit<>` rather than hand-typing it means a vendor schema change the SDK's own\n * next regeneration picks up is felt here as a compiler error, not silently ignored — the same\n * reason this used to derive from the kit's own hand-generated `./generated/pass-through.ts`\n * (retired by this migration: the SDK's type is the same shape, generated from the same LiteLLM\n * 1.100.0 OpenAPI document, and keeping a second copy would only drift).\n */\nimport { deepEqual } from 'alchemy/Diff';\nimport type * as Generated from '@distilled.cloud/litellm/misc';\n\nexport type PassThroughEndpointProps = Omit<\n Generated.PassThroughGenericEndpoint,\n 'id' | 'is_from_config'\n>;\n\n/** What `read` returns: the props plus the two vendor-owned fields, `id` now guaranteed present. */\nexport type PassThroughEndpointAttributes = Omit<Generated.PassThroughGenericEndpoint, 'id'> & {\n readonly id: string;\n};\n\n/** ⚠️ NetBox `settled()`'s pattern: only fields the SCHEMA gives a vendor default for, copied from it (not assumed). */\nexport const settled = (props: PassThroughEndpointProps) => ({\n auth: props.auth ?? true,\n cost_per_request: props.cost_per_request ?? 0,\n default_query_params: props.default_query_params ?? {},\n headers: props.headers ?? {},\n include_subpath: props.include_subpath ?? false,\n});\n\n/** The three fields whose absence the vendor's `exclude_none` update can never write (see client.ts). */\nexport const NULLABLE_FIELDS = ['timeout', 'methods', 'guardrails'] as const;\n\nconst isUnset = (value: unknown): boolean => value === undefined || value === null;\n\n/**\n * ⚠️ BUILT AS A WIDER RECORD AND PRUNED, NOT AS THE GENERATED TYPE DIRECTLY.\n * `exactOptionalPropertyTypes` is on (packages/config/tsconfig.base.json), so writing\n * `timeout: undefined` into a `{ timeout?: number | null }` is a type error rather than an\n * absent key — the same reason `codegen/openapi.ts`'s `prune` exists, and the same fix.\n */\nconst prune = (value: Record<string, unknown>): Record<string, unknown> =>\n Object.fromEntries(Object.entries(value).filter(([, v]) => v !== undefined));\n\n/**\n * Full body for CREATE. `id` is the deterministic physical name (pass-through-endpoint.ts), sent\n * so a failed create is recoverable by `read` rather than orphaning a second row on retry.\n */\nexport const createBody = (\n props: PassThroughEndpointProps,\n id: string,\n): Generated.PassThroughGenericEndpoint =>\n prune({\n ...settled(props),\n guardrails: isUnset(props.guardrails) ? undefined : props.guardrails,\n id,\n methods: isUnset(props.methods) ? undefined : props.methods,\n path: props.path,\n target: props.target,\n timeout: isUnset(props.timeout) ? undefined : props.timeout,\n }) as unknown as Generated.PassThroughGenericEndpoint;\n\n/**\n * Partial body for UPDATE (`POST /{id}`). ⛔ ONLY FIELDS THIS DECLARATION ACTUALLY SETS — the\n * vendor merges the parsed body with `model_dump(exclude_none=True)` (measured at v1.100.0), so an\n * `undefined` OR an explicit `null` here would be dropped by the server anyway; sending neither is\n * the same outcome with no request made when nothing changed (`Object.keys(body).length === 0`\n * checked by the caller in pass-through-endpoint.ts).\n *\n * ⛔ `path`/`target` ARE NOT `Partial` HERE, UNLIKE EVERY OTHER FIELD. The SDK's own update\n * request type requires both non-optionally (the vendor's PATCH route still wants the full\n * route/target pair on every call, unlike the other fields' `exclude_none` merge) — typing them\n * as always-present here is what lets `operations.ts`'s `updatePassThroughEndpoint` pass this\n * straight to the SDK without an unsafe cast.\n */\nexport type UpdateBody = Partial<Omit<Generated.PassThroughGenericEndpoint, 'path' | 'target'>> &\n Pick<Generated.PassThroughGenericEndpoint, 'path' | 'target'>;\n\nexport const updateBody = (props: PassThroughEndpointProps): UpdateBody =>\n prune({\n ...settled(props),\n guardrails: isUnset(props.guardrails) ? undefined : props.guardrails,\n methods: isUnset(props.methods) ? undefined : props.methods,\n path: props.path,\n target: props.target,\n timeout: isUnset(props.timeout) ? undefined : props.timeout,\n }) as UpdateBody;\n\n/**\n * Whether ANY of the three nullable fields went from set (in `live`) to unset (in `props`) — the\n * one case `updateBody` cannot express, because the vendor's `exclude_none` merge silently keeps\n * the old value instead of clearing it. Detected here so `pass-through-endpoint.ts` can plan a\n * `replace` (delete-then-create) instead of an update that would look like it worked.\n */\nexport const needsReplace = (\n live: PassThroughEndpointAttributes,\n props: PassThroughEndpointProps,\n): boolean => NULLABLE_FIELDS.some((field) => !isUnset(live[field]) && isUnset(props[field]));\n\n/** Whether the live object already says what the declaration says — the `diff` \"noop\" test. */\nexport const matches = (\n live: PassThroughEndpointAttributes,\n props: PassThroughEndpointProps,\n): boolean => {\n const fixed = settled(props);\n return (\n live.target === props.target &&\n live.auth === fixed.auth &&\n live.cost_per_request === fixed.cost_per_request &&\n live.include_subpath === fixed.include_subpath &&\n deepEqual(live.headers, fixed.headers) &&\n deepEqual(live.default_query_params, fixed.default_query_params) &&\n (isUnset(props.timeout) ? isUnset(live.timeout) : live.timeout === props.timeout) &&\n (isUnset(props.methods) ? isUnset(live.methods) : deepEqual(live.methods, props.methods)) &&\n (isUnset(props.guardrails)\n ? isUnset(live.guardrails)\n : deepEqual(live.guardrails, props.guardrails))\n );\n};\n\n/**\n * A literal secret in a forwarded header (S25, house rule — not a vendor one; see\n * pass-through-endpoint.ts). Case-insensitive on the header name; the reference form is LiteLLM's\n * own, `os.environ/NAME` (`set_env_variables_in_header`, pass_through_endpoints.py:117-160 at the\n * tag) — a missing variable on the proxy host leaves that literal string in the header, which\n * nothing in the API can detect, so this is enforced here rather than trusted to the vendor.\n */\nconst SECRET_HEADER_NAMES = new Set(['authorization', 'x-api-key', 'cf-aig-authorization']);\n\nexport const literalSecretHeaders = (\n headers: Readonly<Record<string, unknown>> | undefined,\n): readonly string[] =>\n Object.entries(headers ?? {})\n .filter(\n ([name, value]) =>\n SECRET_HEADER_NAMES.has(name.toLowerCase()) && !String(value).includes('os.environ/'),\n )\n .map(([name]) => name);\n",
|
|
9
9
|
"/**\n * The LiteLLM provider, with its credential source, as one layer for a stack.\n *\n * Layer.mergeAll(litellmProviders(), …the stack's other providers)\n *\n * ★ THE DEFAULT READS `LITELLM_PROXY_URL`/`LITELLM_PROXY_API_KEY` AT CALL TIME, through\n * `@distilled.cloud/litellm`'s own `CredentialsFromEnv` — the same two variable names the\n * retired hand-rolled `credentials.ts` read — never at layer build. Pass another\n * `Layer.Layer<Credentials>` (see the SDK's own `credentials({ apiKey, baseUrl })` in a test) to\n * source them another way.\n * ⚠️ `HttpClient` is NOT provided here. It is ambient in every Alchemy runtime the same way it is\n * for `netboxProviders`-style families in this kit; a stack that already deploys anything over\n * HTTP already has one.\n */\nimport { type Credentials, CredentialsFromEnv } from '@distilled.cloud/litellm/Credentials';\nimport * as Layer from 'effect/Layer';\nimport { LiteLLMPassThroughEndpointProvider } from './pass-through-endpoint.ts';\n\nexport const litellmProviders = (creds: Layer.Layer<Credentials> = CredentialsFromEnv) =>\n LiteLLMPassThroughEndpointProvider().pipe(Layer.provide(creds));\n"
|
|
10
10
|
],
|
|
11
|
-
"mappings": ";AAuBA;AACA;AACA;AAEA;AACA;AAIA;AACA;;;ACHA;AACA;AAGA;AACA;AAUA,IAAM,aAAa,IAAI;AAGvB,IAAM,eAAe,CAAC,YACb,YAAK,MAAM;AAAA,EAChB,MAAM,WAAW,WAAW,IAAI,OAAO;AAAA,EACvC,IAAI,aAAa;AAAA,IAAW,OAAO;AAAA,EACnC,MAAM,UAAoB,qBAAW,CAAC;AAAA,EACtC,WAAW,IAAI,SAAS,OAAO;AAAA,EAC/B,OAAO;AAAA,CACR;
|
|
11
|
+
"mappings": "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",
|
|
12
12
|
"debugId": "F883BA858F0CF3AD64756E2164756E21",
|
|
13
13
|
"names": []
|
|
14
14
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"operations.d.ts","sourceRoot":"","sources":["../../src/litellm/operations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,OAAO,KAAK,IAAI,MAAM,+BAA+B,CAAC;AAEtD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAE1E,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAGxC,YAAY,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAC1E,MAAM,MAAM,mBAAmB,GAAG,gBAAgB,CAAC;AACnD,YAAY,EACV,2BAA2B,EAC3B,0BAA0B,EAC1B,4BAA4B,GAC7B,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"operations.d.ts","sourceRoot":"","sources":["../../src/litellm/operations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,OAAO,KAAK,IAAI,MAAM,+BAA+B,CAAC;AAEtD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAE1E,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAGxC,YAAY,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAC1E,MAAM,MAAM,mBAAmB,GAAG,gBAAgB,CAAC;AACnD,YAAY,EACV,2BAA2B,EAC3B,0BAA0B,EAC1B,4BAA4B,GAC7B,MAAM,+BAA+B,CAAC;AAoCvC,oIAAoI;AACpI,eAAO,MAAM,wBAAwB,QAAO,MAAM,CAAC,MAAM,CACvD,SAAS,IAAI,CAAC,0BAA0B,EAAE,EAC1C,IAAI,CAAC,wDAAwD,EAC7D,gBAAgB,CAIqC,CAAC;AAExD,0FAA0F;AAC1F,eAAO,MAAM,yBAAyB,SAC9B,IAAI,CAAC,0BAA0B,KACpC,MAAM,CAAC,MAAM,CACd,IAAI,EACJ,IAAI,CAAC,4DAA4D,EACjE,gBAAgB,CACiF,CAAC;AAEpG;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,eACxB,MAAM,QACZ,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,0BAA0B,EAAE,MAAM,GAAG,QAAQ,CAAC,CAAC,GACrE,IAAI,CAAC,IAAI,CAAC,0BAA0B,EAAE,MAAM,GAAG,QAAQ,CAAC,KACzD,MAAM,CAAC,MAAM,CACd,IAAI,EACJ,IAAI,CAAC,sEAAsE,EAC3E,gBAAgB,CASf,CAAC;AAEJ;;;;;;;;;;GAUG;AACH,eAAO,MAAM,yBAAyB,eACxB,MAAM,KACjB,MAAM,CAAC,MAAM,CACd,IAAI,EACJ,IAAI,CAAC,8DAA8D,EACnE,gBAAgB,CAcf,CAAC"}
|
|
@@ -29,23 +29,22 @@
|
|
|
29
29
|
*
|
|
30
30
|
*/
|
|
31
31
|
import type { CephDaemonAttributes, CephDaemonKind, CephDaemonProps } from './ceph-daemon.ts';
|
|
32
|
-
import type {
|
|
32
|
+
import type { EndpointKey } from './constraints.ts';
|
|
33
33
|
/**
|
|
34
34
|
* The vendor endpoint each kind is created at, as the generated tables key it.
|
|
35
35
|
*
|
|
36
36
|
* ⛔ ONE PER KIND, NOT A `{type}` PATH. PVE registers `mds`, `mgr` and `mon` as three separate
|
|
37
37
|
* nodes with three separate parameter schemas — `hotstandby` belongs to the first and
|
|
38
38
|
* `mon-address` to the third — so a single key would enforce one kind's rules on all three.
|
|
39
|
-
*
|
|
39
|
+
* `ceph-daemon.ts` indexes this by `props.kind` for exactly that reason, on every `guardWrite`.
|
|
40
40
|
* ⛔ THE STRINGS MUST STAY LITERALS. `codegen/constraints.ts` finds the endpoints to table by
|
|
41
41
|
* SCANNING THIS PACKAGE'S TEXT, so a key assembled from `props.kind` would be tabled by
|
|
42
42
|
* nothing and `constraintsFor` would throw on the first deploy that reached it.
|
|
43
43
|
* ⚠️ THE PARAMETER NAMES DIFFER AND ARE THE VENDOR'S OWN — `{name}`, `{id}`, `{monid}`. The
|
|
44
44
|
* generator resolves each against the schema, so a tidied-up spelling stops the build.
|
|
45
|
-
* ⚠️ NO `update`
|
|
46
|
-
* `updateForm` either.
|
|
45
|
+
* ⚠️ NO `update` HERE: none of the three kinds has a PUT — ceph-daemon-wire.ts's own header.
|
|
47
46
|
*/
|
|
48
|
-
export declare const DAEMON_ENDPOINTS: Readonly<Record<CephDaemonKind,
|
|
47
|
+
export declare const DAEMON_ENDPOINTS: Readonly<Record<CephDaemonKind, EndpointKey>>;
|
|
49
48
|
/**
|
|
50
49
|
* PVE defaults the id to the nodename for all three kinds, and that default is resolved HERE
|
|
51
50
|
* rather than left to PVE, because the id is a PATH SEGMENT: create, delete and the row lookup in
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ceph-daemon-form.d.ts","sourceRoot":"","sources":["../../src/proxmox/ceph-daemon-form.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,OAAO,KAAK,EAAE,oBAAoB,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAC9F,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"ceph-daemon-form.d.ts","sourceRoot":"","sources":["../../src/proxmox/ceph-daemon-form.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,OAAO,KAAK,EAAE,oBAAoB,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAC9F,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAGpD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,gBAAgB,EAAE,QAAQ,CAAC,MAAM,CAAC,cAAc,EAAE,WAAW,CAAC,CAI1E,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,UAAW,eAAe,WAA6B,CAAC;AAE7E;;;;;GAKG;AACH,eAAO,MAAM,cAAc,UAAW,eAAe,WAA6C,CAAC;AAEnG,kGAAkG;AAClG,eAAO,MAAM,UAAU,UAAW,eAAe,WAAkD,CAAC;AAEpG;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,UAAU,UAAW,eAAe,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAMxE,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,OAAO,SAAU,OAAO,SAAS,eAAe,wCAGV,CAAC;AAEpD;;;;;;;;;GASG;AACH,eAAO,MAAM,gBAAgB,SACrB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,SACtB,eAAe,KACrB,oBAAoB,GAAG,SAiBzB,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `Proxmox.CephDaemon`'s distilled wire lane: one dispatch per kind, because mon/mgr/mds are three
|
|
3
|
+
* separate distilled operations with three separate request shapes (`{node,monid}` /
|
|
4
|
+
* `{node,id}` / `{node,name}`) — the SAME reason `DAEMON_ENDPOINTS` (ceph-daemon-form.ts) is a
|
|
5
|
+
* per-kind table rather than one templated string.
|
|
6
|
+
*
|
|
7
|
+
* ⛔ ONE READ FUNCTION, NOT THE readXOrFail/foldingX PAIR — the same deliberate, measured
|
|
8
|
+
* departure ceph-pool-wire.ts and ceph-fs-distilled.ts explain in full: this family's
|
|
9
|
+
* pre-migration `pveOperations.read` (resource.ts) already folded every failure unconditionally,
|
|
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.
|
|
12
|
+
*
|
|
13
|
+
* ⚠️ `mon_address` IS THE ONE RENAME THIS FAMILY NEEDS — distilled's generator maps the wire name
|
|
14
|
+
* `mon-address` to `mon_address` on `UpdateNodeCephMonRequest` (`T.Body("mon-address")`,
|
|
15
|
+
* confirmed against its schema), the same one-key pattern node-network-form.ts's `RENAMED`
|
|
16
|
+
* table carries for three fields. `hotstandby` needs no rename.
|
|
17
|
+
*/
|
|
18
|
+
import * as nodes from '@distilled.cloud/proxmox/nodes';
|
|
19
|
+
import * as Effect from 'effect/Effect';
|
|
20
|
+
import type { CephDaemonKind, CephDaemonProps } from './ceph-daemon.ts';
|
|
21
|
+
/** ⛔ FOLDS EVERY FAILURE TO `undefined` — see this file's own header for why. */
|
|
22
|
+
export declare const readDaemon: (props: CephDaemonProps) => Effect.Effect<import("./ceph-daemon.ts").CephDaemonAttributes | undefined, never, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
23
|
+
/** POST — distilled's generator misnames it "update" (checked against `T.Http`); it is a create. */
|
|
24
|
+
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
|
+
/** ⚠️ NO FLAGS ON ANY OF THE THREE — unlike CephFs/CephOsd, nothing here is at risk of a
|
|
26
|
+
* DELETE-body PVE would ignore, because nothing here is ever sent. */
|
|
27
|
+
export declare const deleteDaemon: (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>;
|
|
28
|
+
/** Re-exported so ceph-daemon.ts can narrow a switch exhaustively without importing the union twice. */
|
|
29
|
+
export type { CephDaemonKind };
|
|
30
|
+
/** ★ Moved here from ceph-daemon.ts's `reconcile` for the 250-line cap — matches ceph-fs.ts's own
|
|
31
|
+
* `notCreated`/`notDestroyed` seam: the message, not the decision to die, lives with the calls. */
|
|
32
|
+
export declare const notCreated: (props: CephDaemonProps) => Error;
|
|
33
|
+
//# sourceMappingURL=ceph-daemon-wire.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ceph-daemon-wire.d.ts","sourceRoot":"","sources":["../../src/proxmox/ceph-daemon-wire.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;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,iFAAiF;AACjF,eAAO,MAAM,UAAU,UAAW,eAAe,4IAI9C,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"}
|
|
@@ -45,9 +45,14 @@
|
|
|
45
45
|
* needs no widening for once. ⚠️ `Sys.Modify` on the ROOT path is broad — it also buys
|
|
46
46
|
* datacenter options and every other cluster-wide config write — so it is worth knowing that
|
|
47
47
|
* this credential already has it rather than discovering it the next time something is scoped.
|
|
48
|
+
*
|
|
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; `readDaemon` there keeps this family's
|
|
51
|
+
* pre-migration single-fold shape (ceph-pool-wire.ts explains why that is not left unfixed).
|
|
48
52
|
*/
|
|
49
53
|
import { Resource } from 'alchemy';
|
|
50
54
|
import * as Provider from 'alchemy/Provider';
|
|
55
|
+
import * as Effect from 'effect/Effect';
|
|
51
56
|
import { type PveRequirements, type WithTarget } from './resource.ts';
|
|
52
57
|
/**
|
|
53
58
|
* Which Ceph daemon this is. The discriminant picks the collection, the create parameters and
|
|
@@ -158,5 +163,35 @@ export interface ProxmoxCephDaemon extends Resource<'Proxmox.CephDaemon', CephDa
|
|
|
158
163
|
}
|
|
159
164
|
/** ★ `retain` by default — a mon carrying quorum cannot be rebuilt. See the ★ in resource.ts. */
|
|
160
165
|
export declare const ProxmoxCephDaemon: import("alchemy").ResourceClass<ProxmoxCephDaemon>;
|
|
166
|
+
/**
|
|
167
|
+
* ⛔ TOTAL, AND THIS IS THE REASON THE FILE EXISTS RATHER THAN A SHORTCUT PAST WRITING IT. Every
|
|
168
|
+
* field a declaration can carry is CREATE-ONLY and unreadable — `mon-address` comes back as a
|
|
169
|
+
* different kind of string, `hotstandby` comes back as a state Ceph elects — and every field
|
|
170
|
+
* the read returns is assigned by Ceph: state, rank, quorum, fs_name, standby_replay, addr,
|
|
171
|
+
* version. Nothing is left that is both declared and readable. So the honest comparison is
|
|
172
|
+
* "does a daemon of this kind and name exist", which `readDaemon` has already answered by
|
|
173
|
+
* returning a value at all, and anything further would be a diff no write could ever satisfy.
|
|
174
|
+
* ⛔ AND ON THIS FAMILY THAT DIFF IS NOT MERELY NOISY. There is no PUT, so a false mismatch
|
|
175
|
+
* would have to be a REPLACE — and replace on a mon is delete-then-create against a live
|
|
176
|
+
* quorum. A forever-diff here is a forever-OUTAGE-RISK.
|
|
177
|
+
* ⚠️ THE PRICE, STATED PLAINLY: editing `hotstandby` or `mon-address` on a declared daemon
|
|
178
|
+
* plans as `noop` and never applies. Same bargain storage.ts strikes for a changed `type`.
|
|
179
|
+
* Change one by removing the declaration and re-adding it, ONE DAEMON AT A TIME, reading the
|
|
180
|
+
* ⛔ on destroy in the header first.
|
|
181
|
+
*/
|
|
182
|
+
/**
|
|
183
|
+
* ★ The factory's shape with no `updateForm`: create if absent, else read back untouched.
|
|
184
|
+
* ⛔ `guardWrite` RUNS RIGHT AFTER THE READ, UNCONDITIONALLY, NOT ONLY ON THE CREATE BRANCH —
|
|
185
|
+
* found on adversarial review, 2026-09-24, matching node-network.ts's own `reconcile`.
|
|
186
|
+
* `reconcile` also runs for an ADOPTED row with no fresh `diff` first (Plan.ts forces it after
|
|
187
|
+
* the probe even when `diff` said noop), so a guard only on the create branch would let a
|
|
188
|
+
* caller that skips `diff` (a resumed apply, a verify harness) reach `createDaemon` with
|
|
189
|
+
* `mon-address` — a real vendor rule — unchecked.
|
|
190
|
+
* ★ EXPORTED SO A TEST CAN CALL IT DIRECTLY, bypassing `diff` — the shape the review's own proof
|
|
191
|
+
* needed: `findProvider` gives back the wrapped service, this gives the plain function.
|
|
192
|
+
*/
|
|
193
|
+
export declare const reconcileDaemon: (args_0: {
|
|
194
|
+
news: CephDaemonProps;
|
|
195
|
+
}) => Effect.Effect<CephDaemonAttributes, Error | import("effect/unstable/http/HttpClientError").HttpClientError | import("./credential-errors.ts").PveCredentialDenied, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
161
196
|
export declare const ProxmoxCephDaemonProvider: () => import("effect/Layer").Layer<Provider.Provider<ProxmoxCephDaemon>, never, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
162
197
|
//# sourceMappingURL=ceph-daemon.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ceph-daemon.d.ts","sourceRoot":"","sources":["../../src/proxmox/ceph-daemon.ts"],"names":[],"mappings":"AAAA
|
|
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;;;;;;;;;OASG;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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as Effect from 'effect/Effect';
|
|
2
|
+
import type { CephFsProps } from './ceph-fs.ts';
|
|
3
|
+
/**
|
|
4
|
+
* The index, read via distilled — the same shape `readRow` (ceph-fs-wire.ts) already narrows.
|
|
5
|
+
*
|
|
6
|
+
* ⛔ FOLDS EVERY FAILURE TO `undefined`, matching the pre-migration `pveOperations.read` this
|
|
7
|
+
* family used (`resource.ts`, `Effect.orElseSucceed`) — the same single-fold shape
|
|
8
|
+
* ceph-pool-wire.ts's `readPoolStatus` preserves and explains: this migration's own rule is
|
|
9
|
+
* behaviour surviving byte-for-byte, not the newer dual-path pattern gaining a new family.
|
|
10
|
+
*/
|
|
11
|
+
export declare const readFs: (props: CephFsProps) => Effect.Effect<import("./ceph-fs.ts").CephFsAttributes | undefined, never, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
12
|
+
/** POST the create, then wait for the worker. ⛔ The caller still reads back; see ceph-fs.ts. */
|
|
13
|
+
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
|
+
//# sourceMappingURL=ceph-fs-distilled.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ceph-fs-distilled.d.ts","sourceRoot":"","sources":["../../src/proxmox/ceph-fs-distilled.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAIhD;;;;;;;GAOG;AACH,eAAO,MAAM,MAAM,UAAW,WAAW,oIAItC,CAAC;AA2CJ,gGAAgG;AAChG,eAAO,MAAM,QAAQ,UAAW,WAAW,kNAoBvC,CAAC"}
|
|
@@ -48,6 +48,17 @@
|
|
|
48
48
|
* user needs 'Sys.Audit' permissions on '/nodes/<node>' if they are not the owner of the task."
|
|
49
49
|
* Grant it on the `read` role, or every create burns the full cap below and reports the wrong
|
|
50
50
|
* cause.
|
|
51
|
+
*
|
|
52
|
+
* ★ AS OF 2026-09-24 (decision 43's walk-down, 2c) THIS FILE IS `client.ts`'s HALF ONLY. The read
|
|
53
|
+
* (`readRow`) moved to `ceph-fs-distilled.ts`, and so did the create — `nodes.updateNodeCephFs`
|
|
54
|
+
* (distilled's own misnamed POST, confirmed against its `T.Http` annotation) plus a SEPARATE
|
|
55
|
+
* distilled `settle`, using the raw `getNodeTaskStatus` operation in its own tolerant poll loop
|
|
56
|
+
* rather than `Task.awaitTask`, which does not tolerate a poll failure the way this family needs
|
|
57
|
+
* (network-apply-read.ts's own header has the fuller reasoning). `destroyFs` stays HERE,
|
|
58
|
+
* unmigrated: distilled types `remove_pools`/`remove_storages` as `T.Body` on a DELETE, and the
|
|
59
|
+
* ⛔ two paragraphs up is the MEASURED reason PVE would silently ignore both flags if sent that
|
|
60
|
+
* way — a real protocol gap, not a judgement call. `settle` below is still shared where it can
|
|
61
|
+
* be: `createForm`/`objectPath`/`destroyPath` are pure and reused by the distilled file too.
|
|
51
62
|
*/
|
|
52
63
|
import * as Effect from 'effect/Effect';
|
|
53
64
|
import type { CephFsAttributes, CephFsProps } from './ceph-fs.ts';
|
|
@@ -63,24 +74,22 @@ import type { CephFsAttributes, CephFsProps } from './ceph-fs.ts';
|
|
|
63
74
|
* `reconcile` takes the create branch on exactly that signal.
|
|
64
75
|
*/
|
|
65
76
|
export declare const readRow: (live: Record<string, unknown>, props: CephFsProps) => CephFsAttributes | undefined;
|
|
77
|
+
/**
|
|
78
|
+
* ⚠️ SHORT POLLS, LOW CAP. Ninety seconds covers two pool creates plus the ten seconds `createfs`
|
|
79
|
+
* itself spends waiting for an MDS to go active, and is short enough that a stuck task fails the
|
|
80
|
+
* deploy rather than parking it for the afternoon.
|
|
81
|
+
*/
|
|
82
|
+
export declare const POLL_SECONDS = 2;
|
|
83
|
+
export declare const POLL_ATTEMPTS = 45;
|
|
66
84
|
/** ⚠️ `nodes/{n}/ceph/fs/{name}` — the POST and DELETE target, and NOT where a read goes. */
|
|
67
85
|
export declare const objectPath: (props: CephFsProps) => string;
|
|
86
|
+
/** The vendor rules `createForm` is checked against — `guardWrite`, distilled-guard.ts. */
|
|
87
|
+
export declare const CEPH_FS_CREATE = "pve:POST /nodes/{node}/ceph/fs/{name}";
|
|
68
88
|
/**
|
|
69
89
|
* ⚠️ `name` IS DELIBERATELY ABSENT FROM THE FORM. It is already the last segment of the path being
|
|
70
90
|
* POSTed to — the metric-server.ts case again — and a second copy can only ever disagree with it.
|
|
71
91
|
*/
|
|
72
92
|
export declare const createForm: (props: CephFsProps) => Record<string, string>;
|
|
73
|
-
/**
|
|
74
|
-
* POST the create, then wait for the worker. ⛔ The caller still reads back; see ceph-fs.ts.
|
|
75
|
-
*
|
|
76
|
-
* ⚠️ A CREATE NEEDS A RUNNING *AND* A STANDBY MDS, and refuses BEFORE it forks -- "no running
|
|
77
|
-
* Metadata Server (MDS) found!" / "no standby Metadata Server (MDS) found!" are synchronous, so
|
|
78
|
-
* they surface as a failed POST rather than as a silent worker. C1 has three (MEASURED: node-c
|
|
79
|
-
* `up:active` for cephfs-c1, node-b and node-d `up:standby`), so this is a note for a smaller cluster.
|
|
80
|
-
* ⚠️ BOTH WRITES CHECK `Sys.Modify` ON `/` -- the root, with the breadth metric-server.ts warns
|
|
81
|
-
* about: granting it buys datacenter options and every other cluster-wide config write too.
|
|
82
|
-
*/
|
|
83
|
-
export declare const createFs: (props: CephFsProps) => Effect.Effect<undefined, Error | import("./credential-errors.ts").PveCredentialDenied, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
84
93
|
/**
|
|
85
94
|
* DELETE the filesystem, then wait for the worker.
|
|
86
95
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ceph-fs-wire.d.ts","sourceRoot":"","sources":["../../src/proxmox/ceph-fs-wire.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"ceph-fs-wire.d.ts","sourceRoot":"","sources":["../../src/proxmox/ceph-fs-wire.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6DG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAKlE;;;;;;;;;;GAUG;AACH,eAAO,MAAM,OAAO,SACZ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,SACtB,WAAW,KACjB,gBAAgB,GAAG,SAkBrB,CAAC;AAKF;;;;GAIG;AAEH,eAAO,MAAM,YAAY,IAAI,CAAC;AAC9B,eAAO,MAAM,aAAa,KAAK,CAAC;AAEhC,6FAA6F;AAC7F,eAAO,MAAM,UAAU,UAAW,WAAW,WAAgD,CAAC;AAE9F,2FAA2F;AAC3F,eAAO,MAAM,cAAc,0CAA0C,CAAC;AAMtE;;;GAGG;AACH,eAAO,MAAM,UAAU,UAAW,WAAW,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAGnE,CAAC;AA2DH;;;;;;;;;GASG;AACH,eAAO,MAAM,SAAS,UAAW,WAAW,4IAQxC,CAAC;AAEL;;;;;;;;GAQG;AACH,eAAO,MAAM,UAAU,UAAW,WAAW,UAK1C,CAAC;AAEJ,eAAO,MAAM,YAAY,UAAW,WAAW,UAK5C,CAAC"}
|
|
@@ -19,12 +19,21 @@
|
|
|
19
19
|
* below returns the INDEX and `attributes` picks this filesystem out of the array client-side —
|
|
20
20
|
* the shape acl.ts uses for the one flat `GET /access/acl`. The POST goes to the `{name}` path,
|
|
21
21
|
* so `collection()` is the LONGER of the two strings, the mirror of metric-server.ts.
|
|
22
|
-
* ⚠️ AND THAT IS WHY
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
22
|
+
* ⚠️ AND THAT IS WHY EVERY HANDLER BELOW IS HAND-WRITTEN rather than taken from a factory. A
|
|
23
|
+
* factory `destroy` deletes the read path, which here is the index: `DELETE /nodes/{node}/
|
|
24
|
+
* ceph/fs` is not a route, so it would fail every destroy while the filesystem stayed exactly
|
|
25
|
+
* where it was. `reconcile` is hand-written for a second, independent reason — the forked
|
|
26
|
+
* worker — set out in ceph-fs-wire.ts. acl.ts is the precedent for a family that genuinely
|
|
27
|
+
* does not fit a shared shape.
|
|
28
|
+
*
|
|
29
|
+
* ★ MIGRATED OFF `client.ts`'s generic `pve()` ONTO `@distilled.cloud/proxmox`'s typed
|
|
30
|
+
* `nodes.listNodeCephFs`/`updateNodeCephFs` for the READ and the CREATE (2026-09-24, decision
|
|
31
|
+
* 43's walk-down, 2c — ceph-fs-distilled.ts). `destroyFs` STAYS on `client.ts`, unmigrated:
|
|
32
|
+
* distilled types the delete's `remove-pools`/`remove-storages` flags as a request BODY, and
|
|
33
|
+
* this file's own next ⛔ (unchanged from before this migration) is the measured reason PVE
|
|
34
|
+
* would silently ignore both on a DELETE sent that way — ceph-fs-wire.ts's header has the fuller
|
|
35
|
+
* evidence. `readFs`/`diff`/`reconcile` keep the SAME single-fold, present-is-settled shape this
|
|
36
|
+
* family always had; see ceph-pool-wire.ts's own header for why that is not a bug left unfixed.
|
|
28
37
|
*
|
|
29
38
|
* ⛔ CREATING A CephFS CREATES TWO CEPH POOLS, AND A `Proxmox.CephPool` MUST NOT ALSO DECLARE THEM.
|
|
30
39
|
* `createfs` builds `<name>_data` and `<name>_metadata` itself and refuses outright if either
|
|
@@ -120,5 +129,21 @@ export interface ProxmoxCephFs extends Resource<'Proxmox.CephFs', CephFsProps, C
|
|
|
120
129
|
}
|
|
121
130
|
/** ★ `retain` by default — a filesystem holding data cannot be rebuilt. See the ★ in resource.ts. */
|
|
122
131
|
export declare const ProxmoxCephFs: import("alchemy").ResourceClass<ProxmoxCephFs>;
|
|
132
|
+
/**
|
|
133
|
+
* ⛔ NOTHING IS COMPARED, AND THAT IS THE MOST DELIBERATE LINE IN THIS FILE. A CephFS has no
|
|
134
|
+
* readable, writable field: the index returns only the name and the pools behind it, and every
|
|
135
|
+
* prop this resource accepts is create-time or delete-time. So "present" IS "settled", and the
|
|
136
|
+
* only honest comparison is none at all.
|
|
137
|
+
* ⚠️ THE TEMPTING ADDITION IS `pg_num`, AND IT WOULD BE THE WORST BUG THIS PACKAGE HAS SHIPPED.
|
|
138
|
+
* It is not in the index at all, so it can only be read from the pool endpoint — where the
|
|
139
|
+
* autoscaler owns it. MEASURED on C1 today: created at 128, live at 32, with the metadata
|
|
140
|
+
* pool already scheduled down to 16. Compared, that is an eternal mismatch — and since there
|
|
141
|
+
* is no update path, treating this as a diff would plan a REPLACE. The plan would destroy and
|
|
142
|
+
* rebuild a live filesystem on every deploy, triggered by a daemon on its own schedule.
|
|
143
|
+
* ⚠️ `data_pools` AND `metadata_pool_id` ARE OUT FOR THE ORDINARY REASONS: a set PVE returns
|
|
144
|
+
* in its own order, and an integer id for something written as a name. `name` is out because
|
|
145
|
+
* it is the FILTER that produced these attributes, so comparing it is true by construction —
|
|
146
|
+
* an identity change is handled in `diff`, not here. `node` is out because it is a route.
|
|
147
|
+
*/
|
|
123
148
|
export declare const ProxmoxCephFsProvider: () => import("effect/Layer").Layer<Provider.Provider<ProxmoxCephFs>, never, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
124
149
|
//# sourceMappingURL=ceph-fs.d.ts.map
|
|
@@ -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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiEG;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,mIAkF/B,CAAC"}
|
|
@@ -56,6 +56,7 @@
|
|
|
56
56
|
* maintenance — the churn-that-reads-like-drift that keeps `digest` out of storage.ts.
|
|
57
57
|
*
|
|
58
58
|
*/
|
|
59
|
+
import * as nodes from '@distilled.cloud/proxmox/nodes';
|
|
59
60
|
import * as Effect from 'effect/Effect';
|
|
60
61
|
import type { CephOsdProps } from './ceph-osd.ts';
|
|
61
62
|
/** A CRUSH node. Buckets carry `children`; an OSD leaf carries `type: 'osd'`. */
|
|
@@ -146,9 +147,17 @@ export declare const osdAttributes: (leaf: CrushNode, props: CephOsdProps) => Ce
|
|
|
146
147
|
* ★ IT LIVES HERE RATHER THAN IN ceph-osd.ts BECAUSE THE READ SIDE IS THIS FILE'S WHOLE JOB —
|
|
147
148
|
* `findOsd` and `osdAttributes` are the two halves it composes, and keeping the caller beside
|
|
148
149
|
* them is what let ceph-osd.ts come back under the 250-line cap when create and delete were
|
|
149
|
-
* added.
|
|
150
|
-
*
|
|
150
|
+
* added.
|
|
151
|
+
*
|
|
152
|
+
* ★ MIGRATED OFF `client.ts`'s `pve()` ONTO `@distilled.cloud/proxmox`'s typed `nodes.
|
|
153
|
+
* getNodeCephOsd` (2026-09-24, decision 43, 2c) — the tree endpoint, confirmed against
|
|
154
|
+
* distilled's own schema to still answer `{flags?, root: unknown}`, matching the shape
|
|
155
|
+
* `osdLeaves` already walks. ⛔ STILL NO `Effect.orElseSucceed` — the ⛔ on `handlers.read` in
|
|
156
|
+
* ceph-osd.ts is unchanged and is still the reason: this path is a collection that always
|
|
157
|
+
* exists while Ceph is installed, so a failure here is never "the OSD is gone" and must
|
|
158
|
+
* propagate rather than fold. This is the one migrated Ceph family that does NOT match
|
|
159
|
+
* ceph-pool-wire.ts's/ceph-fs-distilled.ts's single-fold shape, because it never had it.
|
|
151
160
|
*/
|
|
152
|
-
export declare const readOsd: (props: CephOsdProps) => Effect.Effect<CephOsdAttributes | undefined, Error | import("./credential-errors.ts").PveCredentialDenied, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
161
|
+
export declare const readOsd: (props: CephOsdProps) => Effect.Effect<CephOsdAttributes | undefined, Error | import("./distilled-pve.ts").PveClusterExhausted | import("./credential-errors.ts").PveCredentialDenied | import("effect/Cause").TimeoutError | nodes.ProxmoxOpError, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
153
162
|
export {};
|
|
154
163
|
//# sourceMappingURL=ceph-osd-tree.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ceph-osd-tree.d.ts","sourceRoot":"","sources":["../../src/proxmox/ceph-osd-tree.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyDG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAIlD,iFAAiF;AACjF,KAAK,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAOzC;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,SAAS,SAAU,SAAS,KAAG,SAAS,EAQpD,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,OAAO,SAAU,SAAS,SAAS,MAAM,0BACiB,CAAC;AAExE,MAAM,WAAW,iBAAiB;IAChC,0EAA0E;IAC1E,KAAK,EAAE,MAAM,CAAC;IACd,6DAA6D;IAC7D,IAAI,EAAE,MAAM,CAAC;IACb,wDAAwD;IACxD,IAAI,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,YAAY,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB,mFAAmF;IACnF,MAAM,EAAE,MAAM,CAAC;IACf,iGAAiG;IACjG,EAAE,EAAE,OAAO,CAAC;IACZ,8FAA8F;IAC9F,YAAY,EAAE,MAAM,CAAC;IACrB,kGAAkG;IAClG,QAAQ,EAAE,MAAM,CAAC;IACjB,4FAA4F;IAC5F,GAAG,EAAE,MAAM,CAAC;IACZ,iGAAiG;IACjG,WAAW,EAAE,MAAM,CAAC;IACpB,uFAAuF;IACvF,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,aAAa,SAAU,SAAS,SAAS,YAAY,KAAG,iBAanE,CAAC;AAEH
|
|
1
|
+
{"version":3,"file":"ceph-osd-tree.d.ts","sourceRoot":"","sources":["../../src/proxmox/ceph-osd-tree.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyDG;AACH,OAAO,KAAK,KAAK,MAAM,gCAAgC,CAAC;AACxD,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAIlD,iFAAiF;AACjF,KAAK,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAOzC;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,SAAS,SAAU,SAAS,KAAG,SAAS,EAQpD,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,OAAO,SAAU,SAAS,SAAS,MAAM,0BACiB,CAAC;AAExE,MAAM,WAAW,iBAAiB;IAChC,0EAA0E;IAC1E,KAAK,EAAE,MAAM,CAAC;IACd,6DAA6D;IAC7D,IAAI,EAAE,MAAM,CAAC;IACb,wDAAwD;IACxD,IAAI,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,YAAY,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB,mFAAmF;IACnF,MAAM,EAAE,MAAM,CAAC;IACf,iGAAiG;IACjG,EAAE,EAAE,OAAO,CAAC;IACZ,8FAA8F;IAC9F,YAAY,EAAE,MAAM,CAAC;IACrB,kGAAkG;IAClG,QAAQ,EAAE,MAAM,CAAC;IACjB,4FAA4F;IAC5F,GAAG,EAAE,MAAM,CAAC;IACZ,iGAAiG;IACjG,WAAW,EAAE,MAAM,CAAC;IACpB,uFAAuF;IACvF,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,aAAa,SAAU,SAAS,SAAS,YAAY,KAAG,iBAanE,CAAC;AAEH;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,OAAO,UAAW,YAAY,qRAMxC,CAAC"}
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* `defaultRemovalPolicy: 'retain'`, so removing a declaration does NOT reach `destroyOsd` — a
|
|
12
12
|
* caller opts in with `.pipe(RemovalPolicy.destroy())`.
|
|
13
13
|
*/
|
|
14
|
+
import * as nodes from '@distilled.cloud/proxmox/nodes';
|
|
14
15
|
import * as Effect from 'effect/Effect';
|
|
15
16
|
import type { CephOsdProps } from './ceph-osd.ts';
|
|
16
17
|
import type { EndpointKey } from './constraints.ts';
|
|
@@ -32,7 +33,7 @@ export declare const OSD_CREATE_ENDPOINT: EndpointKey;
|
|
|
32
33
|
* ⚠️ `dev` is `string | undefined` on the props and non-optional here: `createOsd` refuses first.
|
|
33
34
|
*/
|
|
34
35
|
export declare const createOsdForm: (props: CephOsdProps, dev: string) => Record<string, string>;
|
|
35
|
-
export declare const createOsd: (news: CephOsdProps) => Effect.Effect<import("./ceph-osd-tree.ts").CephOsdAttributes, Error | import("./credential-errors.ts").PveCredentialDenied, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
36
|
+
export declare const createOsd: (news: CephOsdProps) => Effect.Effect<import("./ceph-osd-tree.ts").CephOsdAttributes, Error | import("effect/unstable/http/HttpClientError").HttpClientError | import("./credential-errors.ts").PveCredentialDenied, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
36
37
|
/**
|
|
37
38
|
* ⛔ REMOVING THE DECLARATION REMOVES THE ASSERTION, NOT THE REPLICA, AND THAT ASYMMETRY IS THE
|
|
38
39
|
* POINT. `DELETE /nodes/{node}/ceph/osd/{osdid}` takes a replica out of a live pool — with
|
|
@@ -50,6 +51,20 @@ export declare const createOsd: (news: CephOsdProps) => Effect.Effect<import("./
|
|
|
50
51
|
*
|
|
51
52
|
* ⚠️ `cleanup` DEFAULTS TO FALSE, so the logical volumes survive and the disk can be re-added
|
|
52
53
|
* without a rebuild. Ceph still starts backfilling the missing copies the moment the OSD goes.
|
|
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).
|
|
53
68
|
*/
|
|
54
|
-
export declare const destroyOsd: (olds: CephOsdProps) => Effect.Effect<
|
|
69
|
+
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>;
|
|
55
70
|
//# 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,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,UAAU,SAAU,YAAY,8PAU1C,CAAC"}
|
|
@@ -33,6 +33,12 @@
|
|
|
33
33
|
* `hf-provision@pve!…` token would likely be answered 403 however wide its role. That is a
|
|
34
34
|
* reason to leave the write lane closed, not something to confirm by trying: if the reasoning
|
|
35
35
|
* is wrong, the confirmation costs a disk.
|
|
36
|
+
*
|
|
37
|
+
* ★ MIGRATED OFF `client.ts` ONTO `@distilled.cloud/proxmox` (2026-09-24, decision 43, 2c) — this
|
|
38
|
+
* file itself never called `pve()` directly, so nothing here changed; ceph-osd-tree.ts's own
|
|
39
|
+
* header has the read side (still no `Effect.orElseSucceed`, unlike every other migrated Ceph
|
|
40
|
+
* family), ceph-osd-write.ts's has the write side and the one pre-existing, out-of-scope gap
|
|
41
|
+
* this migration carries forward rather than fixes.
|
|
36
42
|
*/
|
|
37
43
|
import { Resource } from 'alchemy';
|
|
38
44
|
import * as Provider from 'alchemy/Provider';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ceph-osd.d.ts","sourceRoot":"","sources":["../../src/proxmox/ceph-osd.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"ceph-osd.d.ts","sourceRoot":"","sources":["../../src/proxmox/ceph-osd.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAGnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAE7C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAG5D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD;;;GAGG;AACH,YAAY,EAAE,iBAAiB,EAAE,CAAC;AAElC,MAAM,WAAW,YAAa,SAAQ,UAAU;IAC9C;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,8FAA8F;IAC9F,KAAK,EAAE,MAAM,CAAC;IACd;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;;;;OAQG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,cAAe,SAAQ,QAAQ,CAC9C,iBAAiB,EACjB,YAAY,EACZ,iBAAiB,EACjB,KAAK,EACL,eAAe,CAChB;CAAG;AAEJ;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc,iDAEzB,CAAC;AA+HH,eAAO,MAAM,sBAAsB,oIACoD,CAAC"}
|
|
@@ -6,14 +6,15 @@
|
|
|
6
6
|
* synchronous. Ceph's are not — a pool delete returns before the PGs are gone — so this file is
|
|
7
7
|
* the polling that difference forces, and ceph-pool.ts is the declaration.
|
|
8
8
|
*/
|
|
9
|
+
import * as nodes from '@distilled.cloud/proxmox/nodes';
|
|
9
10
|
import * as Effect from 'effect/Effect';
|
|
10
11
|
import type { CephPoolAttributes, CephPoolProps } from './ceph-pool-form.ts';
|
|
11
12
|
import type { PveRequirements } from './resource.ts';
|
|
12
13
|
/**
|
|
13
14
|
* ⚠️ THE DEPENDENCIES ARE PASSED IN RATHER THAN IMPORTED, and that is what made this file
|
|
14
|
-
* separable at all. `
|
|
15
|
-
* ceph-pool.ts; importing
|
|
16
|
-
* definitions of one path. Passing
|
|
15
|
+
* separable at all. `ops.read` — now `readPoolStatus` (ceph-pool-wire.ts) — is a module-level
|
|
16
|
+
* binding in ceph-pool.ts; importing it back would be a runtime cycle, and duplicating it would
|
|
17
|
+
* be two definitions of one path. Passing it is the pattern zfs-pool-write.ts already uses.
|
|
17
18
|
*/
|
|
18
19
|
export type PoolRead = (props: CephPoolProps) => Effect.Effect<CephPoolAttributes | undefined, never, PveRequirements>;
|
|
19
20
|
/**
|
|
@@ -23,8 +24,13 @@ export type PoolRead = (props: CephPoolProps) => Effect.Effect<CephPoolAttribute
|
|
|
23
24
|
* rather than folded, so "I could not ask" fails the deploy instead of creating over live data.
|
|
24
25
|
* An empty list is trusted: the collection 403s when the role is too narrow rather than
|
|
25
26
|
* filtering, so `[]` really does mean a cluster with no pools.
|
|
27
|
+
*
|
|
28
|
+
* ⚠️ `describe` IS STILL A PLAIN STRING (ceph-pool.ts builds it from `object`/`collection` in
|
|
29
|
+
* ceph-pool-form.ts) — this function no longer takes a `collection` PATH, since
|
|
30
|
+
* `nodes.listNodeCephPool` addresses the endpoint itself; the parameter list keeps `describe`
|
|
31
|
+
* only, to name the object in the refusal message.
|
|
26
32
|
*/
|
|
27
|
-
export declare const confirmAbsent: (props: CephPoolProps,
|
|
33
|
+
export declare const confirmAbsent: (props: CephPoolProps, describe: string) => Effect.Effect<void, Error | import("./distilled-pve.ts").PveClusterExhausted | import("./credential-errors.ts").PveCredentialDenied | import("effect/Cause").TimeoutError | nodes.ProxmoxOpError, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
28
34
|
/**
|
|
29
35
|
* Wait for the cluster to agree, then answer the last thing it said.
|
|
30
36
|
*
|
|
@@ -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,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;;;;;GAKG;AACH,MAAM,MAAM,QAAQ,GAAG,CACrB,KAAK,EAAE,aAAa,KACjB,MAAM,CAAC,MAAM,CAAC,kBAAkB,GAAG,SAAS,EAAE,KAAK,EAAE,eAAe,CAAC,CAAC;AAE3E
|
|
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;;;;;GAKG;AACH,MAAM,MAAM,QAAQ,GAAG,CACrB,KAAK,EAAE,aAAa,KACjB,MAAM,CAAC,MAAM,CAAC,kBAAkB,GAAG,SAAS,EAAE,KAAK,EAAE,eAAe,CAAC,CAAC;AAE3E;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,aAAa,UAAW,aAAa,YAAY,MAAM,4PAcjE,CAAC;AAEJ;;;;;;;;;GASG;AACH,eAAO,MAAM,MAAM,UACV,aAAa,QACd,QAAQ,QACR,CAAC,IAAI,EAAE,kBAAkB,GAAG,SAAS,KAAK,OAAO,+GASrD,CAAC"}
|