@homeflare/alchemy 0.38.0 → 0.40.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 +32 -8
- package/dist/ceph/auth-entity.d.ts +34 -0
- package/dist/ceph/auth-entity.d.ts.map +1 -0
- package/dist/ceph/ceph-argv-config.d.ts +10 -0
- package/dist/ceph/ceph-argv-config.d.ts.map +1 -0
- package/dist/ceph/ceph-argv.d.ts +19 -0
- package/dist/ceph/ceph-argv.d.ts.map +1 -0
- package/dist/ceph/ceph-auth-form.d.ts +54 -0
- package/dist/ceph/ceph-auth-form.d.ts.map +1 -0
- package/dist/ceph/ceph-auth-parse.d.ts +56 -0
- package/dist/ceph/ceph-auth-parse.d.ts.map +1 -0
- package/dist/ceph/ceph-auth-reconcile.d.ts +35 -0
- package/dist/ceph/ceph-auth-reconcile.d.ts.map +1 -0
- package/dist/ceph/ceph-config-options.d.ts +23 -0
- package/dist/ceph/ceph-config-options.d.ts.map +1 -0
- package/dist/ceph/ceph-key-leak-assert.d.ts +25 -0
- package/dist/ceph/ceph-key-leak-assert.d.ts.map +1 -0
- package/dist/ceph/ceph-transport.d.ts +37 -0
- package/dist/ceph/ceph-transport.d.ts.map +1 -0
- package/dist/ceph/fake-ceph-dial.d.ts +35 -0
- package/dist/ceph/fake-ceph-dial.d.ts.map +1 -0
- package/dist/ceph/index.d.ts +13 -0
- package/dist/ceph/index.d.ts.map +1 -0
- package/dist/ceph/index.js +1609 -0
- package/dist/ceph/index.js.map +38 -0
- package/dist/forgejo/index.js +4 -2
- package/dist/forgejo/index.js.map +3 -3
- package/dist/forgejo/team-member.d.ts +25 -0
- package/dist/forgejo/team-member.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/proxmox/generated/constraints/index.d.ts +1 -1
- package/dist/proxmox/generated/constraints/index.d.ts.map +1 -1
- package/dist/proxmox/generated/constraints/pve-access.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-cluster-backup.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-cluster-ceph.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-cluster-firewall.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-cluster-ha.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-cluster-metrics.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-cluster-notifications.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-cluster-replication.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-cluster-sdn.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-nodes-ceph.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-nodes-disks.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-nodes-lxc.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-nodes-network.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-nodes-qemu.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-nodes-storage.d.ts +23 -0
- package/dist/proxmox/generated/constraints/pve-nodes-storage.d.ts.map +1 -0
- package/dist/proxmox/generated/constraints/pve-pools.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-storage.d.ts +1 -1
- package/dist/proxmox/index.d.ts +14 -3
- package/dist/proxmox/index.d.ts.map +1 -1
- package/dist/proxmox/index.js +574 -133
- package/dist/proxmox/index.js.map +33 -23
- package/dist/proxmox/qemu-form.d.ts +27 -18
- package/dist/proxmox/qemu-form.d.ts.map +1 -1
- package/dist/proxmox/qemu-judge.d.ts +30 -0
- package/dist/proxmox/qemu-judge.d.ts.map +1 -0
- package/dist/proxmox/qemu-lifecycle.d.ts +16 -2
- package/dist/proxmox/qemu-lifecycle.d.ts.map +1 -1
- package/dist/proxmox/qemu-net.d.ts +9 -0
- package/dist/proxmox/qemu-net.d.ts.map +1 -0
- package/dist/proxmox/qemu-props.d.ts +112 -0
- package/dist/proxmox/qemu-props.d.ts.map +1 -0
- package/dist/proxmox/qemu-volume.d.ts +27 -0
- package/dist/proxmox/qemu-volume.d.ts.map +1 -0
- package/dist/proxmox/qemu.d.ts +14 -27
- package/dist/proxmox/qemu.d.ts.map +1 -1
- package/dist/proxmox/storage-download-errors.d.ts +5 -0
- package/dist/proxmox/storage-download-errors.d.ts.map +1 -0
- package/dist/proxmox/storage-download-identity.d.ts +27 -0
- package/dist/proxmox/storage-download-identity.d.ts.map +1 -0
- package/dist/proxmox/storage-download-lifecycle.d.ts +97 -0
- package/dist/proxmox/storage-download-lifecycle.d.ts.map +1 -0
- package/dist/proxmox/storage-download-props.d.ts +36 -0
- package/dist/proxmox/storage-download-props.d.ts.map +1 -0
- package/dist/proxmox/storage-download-task.d.ts +17 -0
- package/dist/proxmox/storage-download-task.d.ts.map +1 -0
- package/dist/proxmox/storage-download.d.ts +44 -0
- package/dist/proxmox/storage-download.d.ts.map +1 -0
- package/dist/talos/credentials-write.d.ts +46 -0
- package/dist/talos/credentials-write.d.ts.map +1 -0
- package/dist/talos/credentials.d.ts +51 -9
- package/dist/talos/credentials.d.ts.map +1 -1
- package/dist/talos/fake-process.d.ts +56 -0
- package/dist/talos/fake-process.d.ts.map +1 -0
- package/dist/talos/index.d.ts +19 -4
- package/dist/talos/index.d.ts.map +1 -1
- package/dist/talos/index.js +357 -173
- package/dist/talos/index.js.map +16 -10
- package/dist/talos/kubeconfig-attrs.d.ts +4 -0
- package/dist/talos/kubeconfig-attrs.d.ts.map +1 -0
- package/dist/talos/kubeconfig.d.ts +41 -23
- package/dist/talos/kubeconfig.d.ts.map +1 -1
- package/dist/talos/machine-config-fixtures.d.ts +60 -0
- package/dist/talos/machine-config-fixtures.d.ts.map +1 -0
- package/dist/talos/machine-config-poll.d.ts +43 -0
- package/dist/talos/machine-config-poll.d.ts.map +1 -0
- package/dist/talos/machine-config-read.d.ts +49 -0
- package/dist/talos/machine-config-read.d.ts.map +1 -0
- package/dist/talos/resource.d.ts +18 -0
- package/dist/talos/resource.d.ts.map +1 -1
- package/dist/talos/talos-bootstrap-etcd.d.ts +38 -0
- package/dist/talos/talos-bootstrap-etcd.d.ts.map +1 -0
- package/dist/talos/talos-bootstrap.d.ts +87 -0
- package/dist/talos/talos-bootstrap.d.ts.map +1 -1
- package/dist/talos/talos-cluster-health.d.ts +43 -1
- package/dist/talos/talos-cluster-health.d.ts.map +1 -1
- package/dist/talos/talos-errors.d.ts +68 -0
- package/dist/talos/talos-errors.d.ts.map +1 -0
- package/dist/talos/talos-machine-config.d.ts +51 -15
- package/dist/talos/talos-machine-config.d.ts.map +1 -1
- package/dist/talos/talosctl.d.ts +7 -0
- package/dist/talos/talosctl.d.ts.map +1 -1
- package/dist/talos/values.d.ts +23 -3
- package/dist/talos/values.d.ts.map +1 -1
- package/dist/telemetry/fake-collector.d.ts +36 -0
- package/dist/telemetry/fake-collector.d.ts.map +1 -0
- package/dist/telemetry/index.d.ts +11 -0
- package/dist/telemetry/index.d.ts.map +1 -0
- package/dist/telemetry/index.js +223 -0
- package/dist/telemetry/index.js.map +12 -0
- package/dist/telemetry/layer.d.ts +86 -0
- package/dist/telemetry/layer.d.ts.map +1 -0
- package/dist/telemetry/redact-serialization.d.ts +21 -0
- package/dist/telemetry/redact-serialization.d.ts.map +1 -0
- package/dist/telemetry/redact.d.ts +46 -0
- package/dist/telemetry/redact.d.ts.map +1 -0
- package/dist/unifi/acl-rule-drift.d.ts +22 -0
- package/dist/unifi/acl-rule-drift.d.ts.map +1 -0
- package/dist/unifi/acl-rule-form.d.ts +90 -0
- package/dist/unifi/acl-rule-form.d.ts.map +1 -0
- package/dist/unifi/acl-rule-ordering-form.d.ts +49 -0
- package/dist/unifi/acl-rule-ordering-form.d.ts.map +1 -0
- package/dist/unifi/acl-rule-ordering.d.ts +54 -0
- package/dist/unifi/acl-rule-ordering.d.ts.map +1 -0
- package/dist/unifi/acl-rule.d.ts +49 -0
- package/dist/unifi/acl-rule.d.ts.map +1 -0
- package/dist/unifi/dns-policy-drift.d.ts +21 -0
- package/dist/unifi/dns-policy-drift.d.ts.map +1 -0
- package/dist/unifi/dns-policy-form.d.ts +97 -0
- package/dist/unifi/dns-policy-form.d.ts.map +1 -0
- package/dist/unifi/dns-policy.d.ts +55 -0
- package/dist/unifi/dns-policy.d.ts.map +1 -0
- package/dist/unifi/drift.d.ts +27 -0
- package/dist/unifi/drift.d.ts.map +1 -0
- package/dist/unifi/fake-unifi.d.ts +5 -1
- package/dist/unifi/fake-unifi.d.ts.map +1 -1
- package/dist/unifi/firewall-policy-drift.d.ts +26 -0
- package/dist/unifi/firewall-policy-drift.d.ts.map +1 -0
- package/dist/unifi/firewall-policy-form.d.ts +102 -0
- package/dist/unifi/firewall-policy-form.d.ts.map +1 -0
- package/dist/unifi/firewall-policy-ordering-form.d.ts +66 -0
- package/dist/unifi/firewall-policy-ordering-form.d.ts.map +1 -0
- package/dist/unifi/firewall-policy-ordering.d.ts +57 -0
- package/dist/unifi/firewall-policy-ordering.d.ts.map +1 -0
- package/dist/unifi/firewall-policy.d.ts +57 -0
- package/dist/unifi/firewall-policy.d.ts.map +1 -0
- package/dist/unifi/firewall-zone-form.d.ts +6 -0
- package/dist/unifi/firewall-zone-form.d.ts.map +1 -1
- package/dist/unifi/firewall-zone.d.ts +1 -1
- package/dist/unifi/firewall-zone.d.ts.map +1 -1
- package/dist/unifi/index.d.ts +11 -3
- package/dist/unifi/index.d.ts.map +1 -1
- package/dist/unifi/index.js +725 -60
- package/dist/unifi/index.js.map +31 -9
- package/dist/unifi/network-drift.d.ts +26 -0
- package/dist/unifi/network-drift.d.ts.map +1 -0
- package/dist/unifi/network-form.d.ts +40 -7
- package/dist/unifi/network-form.d.ts.map +1 -1
- package/dist/unifi/network.d.ts +1 -0
- package/dist/unifi/network.d.ts.map +1 -1
- package/dist/unifi/paginate.d.ts +24 -0
- package/dist/unifi/paginate.d.ts.map +1 -0
- package/dist/unifi/providers.d.ts +1 -1
- package/dist/unifi/providers.d.ts.map +1 -1
- package/dist/unifi/resource.d.ts +36 -1
- package/dist/unifi/resource.d.ts.map +1 -1
- package/dist/unifi/scan-source.d.ts +11 -0
- package/dist/unifi/scan-source.d.ts.map +1 -0
- package/dist/unifi/traffic-matching-list-drift.d.ts +22 -0
- package/dist/unifi/traffic-matching-list-drift.d.ts.map +1 -0
- package/dist/unifi/traffic-matching-list-form.d.ts +56 -0
- package/dist/unifi/traffic-matching-list-form.d.ts.map +1 -0
- package/dist/unifi/traffic-matching-list.d.ts +51 -0
- package/dist/unifi/traffic-matching-list.d.ts.map +1 -0
- package/dist/unifi/wifi-broadcast-drift.d.ts +22 -0
- package/dist/unifi/wifi-broadcast-drift.d.ts.map +1 -0
- package/dist/unifi/wifi-broadcast-form.d.ts +127 -0
- package/dist/unifi/wifi-broadcast-form.d.ts.map +1 -0
- package/dist/unifi/wifi-broadcast.d.ts +73 -0
- package/dist/unifi/wifi-broadcast.d.ts.map +1 -0
- package/docs/telemetry-spike.md +94 -0
- package/docs/telemetry.md +109 -0
- package/docs/unifi-acl-rule.md +122 -0
- package/docs/unifi-dns-policy.md +75 -0
- package/docs/unifi-firewall-policy.md +109 -0
- package/docs/unifi-traffic-matching-list.md +82 -0
- package/docs/unifi-wifi.md +120 -0
- package/docs/unifi.md +64 -3
- package/package.json +10 -2
- package/src/ceph/auth-entity.ts +74 -0
- package/src/ceph/ceph-argv-config.ts +78 -0
- package/src/ceph/ceph-argv.test.ts +226 -0
- package/src/ceph/ceph-argv.ts +189 -0
- package/src/ceph/ceph-auth-form.test.ts +103 -0
- package/src/ceph/ceph-auth-form.ts +107 -0
- package/src/ceph/ceph-auth-parse.test.ts +155 -0
- package/src/ceph/ceph-auth-parse.ts +121 -0
- package/src/ceph/ceph-auth-reconcile-secrecy.test.ts +82 -0
- package/src/ceph/ceph-auth-reconcile.test.ts +233 -0
- package/src/ceph/ceph-auth-reconcile.ts +119 -0
- package/src/ceph/ceph-config-options.test.ts +44 -0
- package/src/ceph/ceph-config-options.ts +36 -0
- package/src/ceph/ceph-key-leak-assert.ts +35 -0
- package/src/ceph/ceph-no-output-logging.test.ts +52 -0
- package/src/ceph/ceph-transport.test.ts +125 -0
- package/src/ceph/ceph-transport.ts +117 -0
- package/src/ceph/fake-ceph-dial.ts +55 -0
- package/src/ceph/index.ts +12 -0
- package/src/forgejo/team-member.test.ts +14 -0
- package/src/forgejo/team-member.ts +28 -1
- package/src/index.ts +1 -0
- package/src/proxmox/constraints-required.test.ts +1 -0
- package/src/proxmox/generated/constraints/index.ts +3 -1
- package/src/proxmox/generated/constraints/pve-access.ts +1 -1
- package/src/proxmox/generated/constraints/pve-cluster-backup.ts +1 -1
- package/src/proxmox/generated/constraints/pve-cluster-ceph.ts +1 -1
- package/src/proxmox/generated/constraints/pve-cluster-firewall.ts +1 -1
- package/src/proxmox/generated/constraints/pve-cluster-ha.ts +1 -1
- package/src/proxmox/generated/constraints/pve-cluster-metrics.ts +1 -1
- package/src/proxmox/generated/constraints/pve-cluster-notifications.ts +1 -1
- package/src/proxmox/generated/constraints/pve-cluster-replication.ts +1 -1
- package/src/proxmox/generated/constraints/pve-cluster-sdn.ts +1 -1
- package/src/proxmox/generated/constraints/pve-nodes-ceph.ts +1 -1
- package/src/proxmox/generated/constraints/pve-nodes-disks.ts +1 -1
- package/src/proxmox/generated/constraints/pve-nodes-lxc.ts +1 -1
- package/src/proxmox/generated/constraints/pve-nodes-network.ts +1 -1
- package/src/proxmox/generated/constraints/pve-nodes-qemu.ts +1 -1
- package/src/proxmox/generated/constraints/pve-nodes-storage.ts +30 -0
- package/src/proxmox/generated/constraints/pve-pools.ts +1 -1
- package/src/proxmox/generated/constraints/pve-storage.ts +1 -1
- package/src/proxmox/index.test.ts +11 -6
- package/src/proxmox/index.ts +19 -3
- package/src/proxmox/qemu-form.ts +49 -13
- package/src/proxmox/qemu-identity.test.ts +30 -0
- package/src/proxmox/qemu-judge.test.ts +65 -0
- package/src/proxmox/qemu-judge.ts +84 -0
- package/src/proxmox/qemu-lifecycle.test.ts +78 -19
- package/src/proxmox/qemu-lifecycle.ts +131 -32
- package/src/proxmox/qemu-net.test.ts +48 -0
- package/src/proxmox/qemu-net.ts +78 -0
- package/src/proxmox/qemu-ownership.test.ts +44 -0
- package/src/proxmox/qemu-props.test.ts +87 -0
- package/src/proxmox/qemu-props.ts +157 -0
- package/src/proxmox/qemu-volume.test.ts +229 -0
- package/src/proxmox/qemu-volume.ts +178 -0
- package/src/proxmox/qemu.ts +15 -29
- package/src/proxmox/storage-download-errors.ts +7 -0
- package/src/proxmox/storage-download-identity.test.ts +54 -0
- package/src/proxmox/storage-download-identity.ts +50 -0
- package/src/proxmox/storage-download-lifecycle.ts +226 -0
- package/src/proxmox/storage-download-ownership.test.ts +50 -0
- package/src/proxmox/storage-download-props.ts +38 -0
- package/src/proxmox/storage-download-task.ts +72 -0
- package/src/proxmox/storage-download.test.ts +216 -0
- package/src/proxmox/storage-download.ts +58 -0
- package/src/talos/credentials-write.test.ts +81 -0
- package/src/talos/credentials-write.ts +95 -0
- package/src/talos/credentials.test.ts +157 -0
- package/src/talos/credentials.ts +160 -90
- package/src/talos/fake-process.ts +94 -0
- package/src/talos/index.ts +39 -4
- package/src/talos/kubeconfig-attrs.ts +55 -0
- package/src/talos/kubeconfig.test.ts +256 -0
- package/src/talos/kubeconfig.ts +170 -90
- package/src/talos/machine-config-fixtures.ts +86 -0
- package/src/talos/machine-config-poll.test.ts +57 -0
- package/src/talos/machine-config-poll.ts +82 -0
- package/src/talos/machine-config-read.ts +118 -0
- package/src/talos/resource.ts +19 -0
- package/src/talos/secrets-gate.test.ts +63 -0
- package/src/talos/talos-bootstrap-etcd.ts +71 -0
- package/src/talos/talos-bootstrap.test.ts +218 -0
- package/src/talos/talos-bootstrap.ts +151 -45
- package/src/talos/talos-cluster-health.test.ts +143 -0
- package/src/talos/talos-cluster-health.ts +91 -28
- package/src/talos/talos-errors.ts +85 -0
- package/src/talos/talos-machine-config.test.ts +189 -0
- package/src/talos/talos-machine-config.ts +102 -88
- package/src/talos/talosctl.ts +8 -0
- package/src/talos/values.test.ts +34 -6
- package/src/talos/values.ts +41 -7
- package/src/telemetry/fake-collector.ts +59 -0
- package/src/telemetry/http-client-sealing.test.ts +82 -0
- package/src/telemetry/index.ts +10 -0
- package/src/telemetry/layer.test.ts +204 -0
- package/src/telemetry/layer.ts +152 -0
- package/src/telemetry/redact-serialization.ts +178 -0
- package/src/telemetry/redact.test.ts +124 -0
- package/src/telemetry/redact.ts +147 -0
- package/src/unifi/acl-rule-drift.ts +57 -0
- package/src/unifi/acl-rule-form.ts +135 -0
- package/src/unifi/acl-rule-ordering-form.ts +79 -0
- package/src/unifi/acl-rule-ordering.test.ts +141 -0
- package/src/unifi/acl-rule-ordering.ts +70 -0
- package/src/unifi/acl-rule.test.ts +183 -0
- package/src/unifi/acl-rule.ts +61 -0
- package/src/unifi/discriminated-filter-decode.test.ts +134 -0
- package/src/unifi/dns-policy-drift.ts +48 -0
- package/src/unifi/dns-policy-form.ts +142 -0
- package/src/unifi/dns-policy.test.ts +154 -0
- package/src/unifi/dns-policy.ts +67 -0
- package/src/unifi/drift.test.ts +78 -0
- package/src/unifi/drift.ts +56 -0
- package/src/unifi/errors-and-secrets.test.ts +127 -0
- package/src/unifi/fake-unifi.ts +5 -1
- package/src/unifi/firewall-policy-drift.test.ts +151 -0
- package/src/unifi/firewall-policy-drift.ts +55 -0
- package/src/unifi/firewall-policy-filter-roundtrip.test.ts +143 -0
- package/src/unifi/firewall-policy-form.ts +146 -0
- package/src/unifi/firewall-policy-ordering-form.ts +111 -0
- package/src/unifi/firewall-policy-ordering.test.ts +185 -0
- package/src/unifi/firewall-policy-ordering.ts +87 -0
- package/src/unifi/firewall-policy.test.ts +183 -0
- package/src/unifi/firewall-policy.ts +73 -0
- package/src/unifi/firewall-zone-form.ts +31 -2
- package/src/unifi/firewall-zone.test.ts +21 -1
- package/src/unifi/firewall-zone.ts +1 -1
- package/src/unifi/get-only-guard.test.ts +165 -0
- package/src/unifi/index.ts +78 -1
- package/src/unifi/network-drift.test.ts +207 -0
- package/src/unifi/network-drift.ts +80 -0
- package/src/unifi/network-form.ts +11 -39
- package/src/unifi/network.test.ts +7 -82
- package/src/unifi/network.ts +6 -6
- package/src/unifi/paginate.test.ts +252 -0
- package/src/unifi/paginate.ts +141 -0
- package/src/unifi/providers.ts +19 -1
- package/src/unifi/resource.ts +73 -3
- package/src/unifi/scan-source.ts +64 -0
- package/src/unifi/traffic-matching-list-drift.ts +40 -0
- package/src/unifi/traffic-matching-list-form.ts +77 -0
- package/src/unifi/traffic-matching-list.test.ts +202 -0
- package/src/unifi/traffic-matching-list.ts +78 -0
- package/src/unifi/wifi-broadcast-details-call.test.ts +92 -0
- package/src/unifi/wifi-broadcast-drift.ts +69 -0
- package/src/unifi/wifi-broadcast-form.ts +211 -0
- package/src/unifi/wifi-broadcast-secrets.test.ts +145 -0
- package/src/unifi/wifi-broadcast.test.ts +155 -0
- package/src/unifi/wifi-broadcast.ts +90 -0
- package/src/unifi/write-op-reference.test.ts +190 -0
package/README.md
CHANGED
|
@@ -304,14 +304,16 @@ import { ArgocdRepository, providers } from '@homeflare/alchemy/argocd';
|
|
|
304
304
|
|
|
305
305
|
## UniFi Network — `@homeflare/alchemy/unifi`
|
|
306
306
|
|
|
307
|
-
`Unifi.Network
|
|
308
|
-
Integration API 10.4.57 via
|
|
309
|
-
(2026-09-24):** `reconcile`/`delete`
|
|
310
|
-
policy —
|
|
311
|
-
and
|
|
312
|
-
`adopt(true)` is on by default via
|
|
313
|
-
**Console ID** (part of a cloud-connector base URL) is never logged,
|
|
314
|
-
state: [docs/unifi.md](./docs/unifi.md)
|
|
307
|
+
`Unifi.Network`, `Unifi.FirewallZone`, `Unifi.DnsPolicy`, `Unifi.AclRule` and
|
|
308
|
+
`Unifi.AclRuleOrdering`, generated from Ubiquiti's own UniFi Network Integration API 10.4.57 via
|
|
309
|
+
`@distilled.cloud/unifi-network`. ⛔ **READ-ONLY, by Tim's rule (2026-09-24):** `reconcile`/`delete`
|
|
310
|
+
both fail with a typed `UnifiWriteRefused` naming the policy — no family here calls a write
|
|
311
|
+
operation, only each object's own `get*` and its list counterpart. ⛔ `read` answers `Unowned` on
|
|
312
|
+
every match (never a silent adopt — `adopt(true)` is on by default via each convenience
|
|
313
|
+
constructor), and a UniFi **Console ID** (part of a cloud-connector base URL) is never logged,
|
|
314
|
+
committed or written to state: [docs/unifi.md](./docs/unifi.md) (Network/FirewallZone),
|
|
315
|
+
[docs/unifi-dns-policy.md](./docs/unifi-dns-policy.md) and
|
|
316
|
+
[docs/unifi-acl-rule.md](./docs/unifi-acl-rule.md).
|
|
315
317
|
|
|
316
318
|
```ts
|
|
317
319
|
import { declareNetwork, network, providers } from '@homeflare/alchemy/unifi';
|
|
@@ -351,6 +353,28 @@ checks you name required. ⛔ Auto-merge with nothing required merges **immediat
|
|
|
351
353
|
`bunx --bun hf-adopt-verify --config alchemy.run.ts --stage live`: Alchemy's planner, no writes,
|
|
352
354
|
each row's own diff, exit 0 only when all are no-ops. [docs/adopt-verify.md](./docs/adopt-verify.md)
|
|
353
355
|
|
|
356
|
+
## Telemetry — `@homeflare/alchemy/telemetry`
|
|
357
|
+
|
|
358
|
+
`telemetryLayer` builds an OTLP tracing/logging/metrics `Layer` for a stack's own `providers` —
|
|
359
|
+
off unless you give it real endpoints, no default collector anywhere in it.
|
|
360
|
+
|
|
361
|
+
```ts
|
|
362
|
+
import { telemetryLayer } from '@homeflare/alchemy/telemetry';
|
|
363
|
+
|
|
364
|
+
export const providers = Layer.mergeAll(
|
|
365
|
+
myProviders(),
|
|
366
|
+
telemetryLayer({
|
|
367
|
+
endpoints: { traces: 'http://<your-collector>/v1/traces' },
|
|
368
|
+
serviceName: 'my-stack',
|
|
369
|
+
}),
|
|
370
|
+
);
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
Every span — a provider's own, `HttpClient`'s, and alchemy's own plan/apply engine — is redacted
|
|
374
|
+
before export: every header dropped, every query string stripped, a denylisted host or path segment
|
|
375
|
+
blanked. Options, the redaction policy and what a spike measured actually arriving at a collector:
|
|
376
|
+
[docs/telemetry.md](./docs/telemetry.md) · [docs/telemetry-spike.md](./docs/telemetry-spike.md).
|
|
377
|
+
|
|
354
378
|
## Credentials
|
|
355
379
|
|
|
356
380
|
⛔ **Mint a short-lived, scoped token** — never a long-lived one, never a Global API Key. How each
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `Ceph.AuthEntity` (K-A4) — a Ceph client auth entity (`client.k8s-*`), minted over the ssh
|
|
3
|
+
* mon-command transport and stored only in OpenBao. Design: docs/plans/2026-09-26-ceph-mon-
|
|
4
|
+
* transport.md, "`Ceph.AuthEntity` (K-A4)"; the loop itself lives in ceph-auth-reconcile.ts, the
|
|
5
|
+
* transport in ceph-transport.ts, the allowlist in ceph-argv.ts.
|
|
6
|
+
*
|
|
7
|
+
* ⛔ `read` AND `diff` NEVER SSH. "A plan never elevates" (../linux/sudo-runner.ts's own header
|
|
8
|
+
* makes the same rule for the file family): this family's props/state comparison is the whole
|
|
9
|
+
* of `diff`, and `read` hands back exactly the attributes state already holds. Live drift is
|
|
10
|
+
* caught only at `reconcile` (which does elevate, on the admin lane) and by the post-deploy
|
|
11
|
+
* operator check — this family cannot prove live convergence at plan time, and says so rather
|
|
12
|
+
* than pretending an unprivileged probe exists where none does.
|
|
13
|
+
* ⛔ `delete` IS REFUSED UNCONDITIONALLY. `defaultRemovalPolicy: 'retain'` keeps Alchemy from ever
|
|
14
|
+
* calling it on an ordinary `destroy`, and the handler itself refuses too — belt and suspenders
|
|
15
|
+
* with ceph-argv.ts's own refusal of the `auth del` shape, so there is no path, `--adopt` or a
|
|
16
|
+
* resource-level removal-policy override included, that ever reaches it (D3).
|
|
17
|
+
* ⛔ NEVER ADOPTED. See ceph-auth-reconcile.ts's header for why the generic `refuseTakeover` is not
|
|
18
|
+
* used here.
|
|
19
|
+
* ⛔ ROWS ARE CREATES THROUGH THE FIRST-CREATE GATE, NO `adopt()` — `list` answers empty, the same
|
|
20
|
+
* as every Ceph family in this kit (ceph-pool.ts's header has the reason a non-empty list would
|
|
21
|
+
* invite exactly the takeover this family refuses).
|
|
22
|
+
*/
|
|
23
|
+
import { Resource } from 'alchemy';
|
|
24
|
+
import * as Provider from 'alchemy/Provider';
|
|
25
|
+
import type * as HttpClient from 'effect/unstable/http/HttpClient';
|
|
26
|
+
import type { CephAuthEntityAttributes, CephAuthEntityProps } from './ceph-auth-form.ts';
|
|
27
|
+
export type { CephAuthEntityAttributes, CephAuthEntityProps } from './ceph-auth-form.ts';
|
|
28
|
+
export type { CephCaps } from './ceph-auth-parse.ts';
|
|
29
|
+
export interface CephAuthEntity extends Resource<'Ceph.AuthEntity', CephAuthEntityProps, CephAuthEntityAttributes, never, HttpClient.HttpClient> {
|
|
30
|
+
}
|
|
31
|
+
/** ★ `retain` — the delete handler below refuses regardless, but this stops Alchemy calling it. */
|
|
32
|
+
export declare const CephAuthEntity: import("alchemy").ResourceClass<CephAuthEntity>;
|
|
33
|
+
export declare const CephAuthEntityProvider: () => import("effect/Layer").Layer<Provider.Provider<CephAuthEntity>, never, HttpClient.HttpClient>;
|
|
34
|
+
//# sourceMappingURL=auth-entity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-entity.d.ts","sourceRoot":"","sources":["../../src/ceph/auth-entity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAE7C,OAAO,KAAK,KAAK,UAAU,MAAM,iCAAiC,CAAC;AACnE,OAAO,KAAK,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAIzF,YAAY,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AACzF,YAAY,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErD,MAAM,WAAW,cAAe,SAAQ,QAAQ,CAC9C,iBAAiB,EACjB,mBAAmB,EACnB,wBAAwB,EACxB,KAAK,EACL,UAAU,CAAC,UAAU,CACtB;CAAG;AAEJ,mGAAmG;AACnG,eAAO,MAAM,cAAc,iDAEzB,CAAC;AASH,eAAO,MAAM,sBAAsB,qGAmBhC,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `undefined` when `value` is a safe ceph config value — exported (like `boundedEntityProblem`)
|
|
3
|
+
* so the shape itself is directly testable, since `NAMED_CONFIG_OPTIONS` being empty today means
|
|
4
|
+
* `cephCommandProblem` never reaches this check on any real argv (`namedOptionProblem` refuses
|
|
5
|
+
* first) — this stays exercised until K-D's first named option arms the path for real.
|
|
6
|
+
*/
|
|
7
|
+
export declare const configValueProblem: (value: string) => string | undefined;
|
|
8
|
+
/** `config get|set|rm <who> <name> [value]`, called with the operands after `config` stripped. */
|
|
9
|
+
export declare const configProblem: (rest: readonly string[]) => string | undefined;
|
|
10
|
+
//# sourceMappingURL=ceph-argv-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ceph-argv-config.d.ts","sourceRoot":"","sources":["../../src/ceph/ceph-argv-config.ts"],"names":[],"mappings":"AAiCA;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,UAAW,MAAM,KAAG,MAAM,GAAG,SAG0B,CAAC;AAevF,kGAAkG;AAClG,eAAO,MAAM,aAAa,SAAU,SAAS,MAAM,EAAE,KAAG,MAAM,GAAG,SAmBhE,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export { configValueProblem } from './ceph-argv-config.ts';
|
|
2
|
+
/** ★ Absolute, so neither sudo nor `ceph` is looked up on the operator's PATH. */
|
|
3
|
+
export declare const CEPH_BIN = "/usr/bin/ceph";
|
|
4
|
+
/** Every entity this transport may ever touch starts with this. */
|
|
5
|
+
export declare const ENTITY_PREFIX = "client.k8s-";
|
|
6
|
+
/** `undefined` when `entity` is a name this transport may ever create, get or re-cap. */
|
|
7
|
+
export declare const boundedEntityProblem: (entity: string) => string | undefined;
|
|
8
|
+
declare const DAEMONS: readonly ['mon', 'osd', 'mgr'];
|
|
9
|
+
/**
|
|
10
|
+
* `undefined` when `argv` is exactly an allowed ceph shape (the FULL argv `sudo -n` would run,
|
|
11
|
+
* `/usr/bin/ceph` included), else the reason it is not.
|
|
12
|
+
*/
|
|
13
|
+
export declare const cephCommandProblem: (argv: readonly string[]) => string | undefined;
|
|
14
|
+
/** The exact argv for each allowed shape, so callers never hand-assemble one that could drift. */
|
|
15
|
+
export declare const authGetArgv: (entity: string) => readonly string[];
|
|
16
|
+
export declare const authGetOrCreateArgv: (entity: string, caps: Readonly<Record<(typeof DAEMONS)[number], string>>) => readonly string[];
|
|
17
|
+
export declare const authCapsArgv: (entity: string, caps: Readonly<Record<(typeof DAEMONS)[number], string>>) => readonly string[];
|
|
18
|
+
export declare const quorumStatusArgv: () => readonly string[];
|
|
19
|
+
//# sourceMappingURL=ceph-argv.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ceph-argv.d.ts","sourceRoot":"","sources":["../../src/ceph/ceph-argv.ts"],"names":[],"mappings":"AA2BA,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAE3D,kFAAkF;AAClF,eAAO,MAAM,QAAQ,kBAAkB,CAAC;AAExC,mEAAmE;AACnE,eAAO,MAAM,aAAa,gBAAgB,CAAC;AAK3C,yFAAyF;AACzF,eAAO,MAAM,oBAAoB,WAAY,MAAM,KAAG,MAAM,GAAG,SAGiD,CAAC;AAejH,QAAA,MAAM,OAAO,YAAI,KAAK,EAAE,KAAK,EAAE,KAAK,CAAU,CAAC;AA6E/C;;;GAGG;AACH,eAAO,MAAM,kBAAkB,SAAU,SAAS,MAAM,EAAE,KAAG,MAAM,GAAG,SAWrE,CAAC;AAEF,kGAAkG;AAClG,eAAO,MAAM,WAAW,WAAY,MAAM,KAAG,SAAS,MAAM,EAM3D,CAAC;AAEF,eAAO,MAAM,mBAAmB,WACtB,MAAM,QACR,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,KACvD,SAAS,MAAM,EAOjB,CAAC;AAEF,eAAO,MAAM,YAAY,WACf,MAAM,QACR,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,KACvD,SAAS,MAAM,EAOjB,CAAC;AAEF,eAAO,MAAM,gBAAgB,QAAO,SAAS,MAAM,EAIlD,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { CephCaps } from './ceph-auth-parse.ts';
|
|
2
|
+
export type { CephCaps };
|
|
3
|
+
export type CephAuthEntityProps = {
|
|
4
|
+
/** `client.k8s-<name>` — bounded by ceph-argv.ts's allowlist, checked on every transport call. */
|
|
5
|
+
readonly entity: string;
|
|
6
|
+
readonly caps: CephCaps;
|
|
7
|
+
/** TB4 mon ssh destinations, tried in this order (D1). At least one. */
|
|
8
|
+
readonly nodes: readonly string[];
|
|
9
|
+
/** OpenBao KV-v2 mount holding Talos/Ceph material, e.g. `talos-c1` (D2). */
|
|
10
|
+
readonly mount: string;
|
|
11
|
+
};
|
|
12
|
+
export type CephAuthEntityAttributes = {
|
|
13
|
+
readonly entity: string;
|
|
14
|
+
readonly caps: CephCaps;
|
|
15
|
+
/** `sha256(key)`, hex — never the key itself. */
|
|
16
|
+
readonly fingerprint: string;
|
|
17
|
+
/** CLI-style path (`<mount>/ceph/<entity>`) — safe to persist and log; the key is not here. */
|
|
18
|
+
readonly baoPath: string;
|
|
19
|
+
/** Which mon actually answered the write that produced this row. Never key material. */
|
|
20
|
+
readonly node: string;
|
|
21
|
+
};
|
|
22
|
+
export declare const capsEqual: (a: CephCaps, b: CephCaps) => boolean;
|
|
23
|
+
/** The CLI-style path an operator's `bao kv get` would use — what `baoPath` records. */
|
|
24
|
+
export declare const cephCliPath: (mount: string, entity: string) => string;
|
|
25
|
+
/**
|
|
26
|
+
* The raw KV-v2 HTTP API path `../openbao/bao-http.ts`'s `baoRead`/`baoWrite` take — the CLI path
|
|
27
|
+
* with `data/` inserted, the same segment `bao kv get`/`bao kv put` insert themselves
|
|
28
|
+
* (`../talos/credentials.ts`'s header has the shipped-default bug this convention avoids: never
|
|
29
|
+
* include `data/` in the CLI-style path itself, only here).
|
|
30
|
+
*/
|
|
31
|
+
export declare const cephDataPath: (mount: string, entity: string) => string;
|
|
32
|
+
export type CephAuthEntityPlan = {
|
|
33
|
+
readonly action: 'noop' | 'update' | 'replace';
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Whether `output` (if any) names a different entity/mount than `news` declares — the one
|
|
37
|
+
* question both `planCephAuthEntity` and `reconcileCephAuthEntity`'s guard ask, so the comparison
|
|
38
|
+
* lives in exactly one place (rename-identity.ts's own header: "one description of which object,
|
|
39
|
+
* not twelve copies of the check").
|
|
40
|
+
*/
|
|
41
|
+
export declare const identityMoved: (news: Pick<CephAuthEntityProps, 'entity' | 'mount'>, output: CephAuthEntityAttributes | undefined) => boolean;
|
|
42
|
+
/**
|
|
43
|
+
* ⛔ STATE ONLY, NO SSH — the design's own rule for this family ("a plan never elevates"; diff and
|
|
44
|
+
* verify compare props against state, never the live cluster). `output === undefined` returns
|
|
45
|
+
* `undefined`: a brand-new row plans as a create the same way every other family in this kit
|
|
46
|
+
* does, and reconcile is where the actual ssh work — and the key material — ever appears.
|
|
47
|
+
* A moved identity plans `replace` before caps are even considered: `defaultRemovalPolicy:
|
|
48
|
+
* 'retain'` means the old generation is simply left alone (Apply.ts skips its delete under
|
|
49
|
+
* retain), and the new generation reconciles with `output: undefined`, which is exactly the
|
|
50
|
+
* "never adopted" path if the new identity already has a live entity.
|
|
51
|
+
*/
|
|
52
|
+
export declare const planCephAuthEntity: (news: CephAuthEntityProps, output: CephAuthEntityAttributes | undefined) => CephAuthEntityPlan | undefined;
|
|
53
|
+
export declare const attributesOf: (props: Pick<CephAuthEntityProps, 'caps' | 'entity' | 'mount'>, fingerprint: string, node: string) => CephAuthEntityAttributes;
|
|
54
|
+
//# sourceMappingURL=ceph-auth-form.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ceph-auth-form.d.ts","sourceRoot":"","sources":["../../src/ceph/ceph-auth-form.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErD,YAAY,EAAE,QAAQ,EAAE,CAAC;AAEzB,MAAM,MAAM,mBAAmB,GAAG;IAChC,kGAAkG;IAClG,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,wEAAwE;IACxE,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,6EAA6E;IAC7E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,iDAAiD;IACjD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,+FAA+F;IAC/F,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,wFAAwF;IACxF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,eAAO,MAAM,SAAS,MAAO,QAAQ,KAAK,QAAQ,KAAG,OACE,CAAC;AAExD,wFAAwF;AACxF,eAAO,MAAM,WAAW,UAAW,MAAM,UAAU,MAAM,KAAG,MACZ,CAAC;AAEjD;;;;;GAKG;AACH,eAAO,MAAM,YAAY,UAAW,MAAM,UAAU,MAAM,KAAG,MACR,CAAC;AAEtD,MAAM,MAAM,kBAAkB,GAAG;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAA;CAAE,CAAC;AAEpF;;;;;GAKG;AACH,eAAO,MAAM,aAAa,SAClB,IAAI,CAAC,mBAAmB,EAAE,QAAQ,GAAG,OAAO,CAAC,UAC3C,wBAAwB,GAAG,SAAS,KAC3C,OAEyF,CAAC;AAE7F;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,SACvB,mBAAmB,UACjB,wBAAwB,GAAG,SAAS,KAC3C,kBAAkB,GAAG,SAIvB,CAAC;AAEF,eAAO,MAAM,YAAY,UAChB,IAAI,CAAC,mBAAmB,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC,eAChD,MAAM,QACb,MAAM,KACX,wBAMD,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parsing for the three ceph `-f json` shapes `Ceph.AuthEntity` reads: `auth get`, `auth
|
|
3
|
+
* get-or-create` and `quorum_status`. Pure: no I/O, tested with fixture stdout
|
|
4
|
+
* (ceph-auth-parse.test.ts) — there is no live mon to capture real output from yet, so every shape
|
|
5
|
+
* below is REASONED from public Ceph documentation, not measured, and an unexpected shape is
|
|
6
|
+
* always an error, never a guess.
|
|
7
|
+
*
|
|
8
|
+
* ⛔ `parseAuthGet`'S RETURN TYPE HAS NO `key` FIELD. Decision 65 (2026-09-26, LAND finding 5)
|
|
9
|
+
* amended the design to let the observe step read `auth get`'s unfiltered stdout on every
|
|
10
|
+
* reconcile, not only on create — but the key it carries is dropped in the same breath:
|
|
11
|
+
* `parseKeyringEntry` reads it into a local binding and `parseAuthGet` never puts it in the
|
|
12
|
+
* object it returns. Not a convention, a type: there is no field here to forget to strip.
|
|
13
|
+
* ⛔ `parseQuorumStatus` FAILS CLOSED. A JSON parse error, a missing `quorum` array or an empty one
|
|
14
|
+
* all answer `{ healthy: false }`; nothing here ever calls an unparseable answer healthy.
|
|
15
|
+
*/
|
|
16
|
+
export type CephCaps = {
|
|
17
|
+
readonly mon: string;
|
|
18
|
+
readonly osd: string;
|
|
19
|
+
readonly mgr: string;
|
|
20
|
+
};
|
|
21
|
+
export type CephExecOutcome = {
|
|
22
|
+
readonly exitCode: number;
|
|
23
|
+
readonly stdout: string;
|
|
24
|
+
readonly stderr: string;
|
|
25
|
+
};
|
|
26
|
+
export type CephAuthObserved = {
|
|
27
|
+
readonly kind: 'present';
|
|
28
|
+
readonly caps: CephCaps;
|
|
29
|
+
} | {
|
|
30
|
+
readonly kind: 'absent';
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* ⚠️ ABSENCE IS RECOGNISED ONLY BY `ENOENT` IN STDERR (REASONED from `ceph auth get`'s documented
|
|
34
|
+
* error text). Any other nonzero exit — a permission problem, a malformed entity ceph itself
|
|
35
|
+
* refused, a mon mid-election — propagates as an error, never as "absent": the transient-read
|
|
36
|
+
* test every family in this kit carries.
|
|
37
|
+
*/
|
|
38
|
+
export declare const parseAuthGet: (result: CephExecOutcome, entity: string) => CephAuthObserved;
|
|
39
|
+
/**
|
|
40
|
+
* ⚠️ `get-or-create` NEVER READS AS ABSENT — REASONED: it either creates, returns the existing
|
|
41
|
+
* entity unchanged, or fails outright (e.g. an existing entity with different caps). A nonzero
|
|
42
|
+
* exit here is always an error.
|
|
43
|
+
*/
|
|
44
|
+
export declare const parseAuthGetOrCreate: (result: CephExecOutcome, entity: string) => {
|
|
45
|
+
readonly caps: CephCaps;
|
|
46
|
+
readonly key: string;
|
|
47
|
+
};
|
|
48
|
+
export type CephQuorum = {
|
|
49
|
+
readonly healthy: true;
|
|
50
|
+
} | {
|
|
51
|
+
readonly healthy: false;
|
|
52
|
+
readonly reason: string;
|
|
53
|
+
};
|
|
54
|
+
/** REASONED shape (public `ceph quorum_status -f json` docs): an object with a `quorum` array. */
|
|
55
|
+
export declare const parseQuorumStatus: (stdout: string) => CephQuorum;
|
|
56
|
+
//# sourceMappingURL=ceph-auth-parse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ceph-auth-parse.d.ts","sourceRoot":"","sources":["../../src/ceph/ceph-auth-parse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,MAAM,MAAM,QAAQ,GAAG;IAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5F,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,CAAC;AA6CF,MAAM,MAAM,gBAAgB,GACxB;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,GACrD;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC;AAEhC;;;;;GAKG;AACH,eAAO,MAAM,YAAY,WAAY,eAAe,UAAU,MAAM,KAAG,gBAOtE,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,WACvB,eAAe,UACf,MAAM,KACb;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CAOjD,CAAC;AAEF,MAAM,MAAM,UAAU,GAClB;IAAE,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAA;CAAE,GAC1B;IAAE,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzD,kGAAkG;AAClG,eAAO,MAAM,iBAAiB,WAAY,MAAM,KAAG,UAYlD,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The observe -> ensure -> sync loop `Ceph.AuthEntity`'s reconcile runs (mon-transport doc,
|
|
3
|
+
* `Ceph.AuthEntity`). Split from auth-entity.ts so the loop itself — the part a fake-runner test
|
|
4
|
+
* actually exercises — is a plain function, the same split ceph-pool.ts and ssh-role.ts use.
|
|
5
|
+
*
|
|
6
|
+
* ⛔ NEVER ADOPTS. A live entity found present while this stack holds no attributes for it is
|
|
7
|
+
* refused outright, `--adopt` included — the generic `refuseTakeover` (../ownership/adopt.ts)
|
|
8
|
+
* is deliberately NOT used here, because it honours `--adopt` and this family's own design says
|
|
9
|
+
* plainly: "Existing auth entities are recorded as observed inventory only — never adopted:
|
|
10
|
+
* adopting one would mean reading and fingerprinting its key, and a key is only ever handled for
|
|
11
|
+
* an entity this stack owns."
|
|
12
|
+
* ⛔ THE OBSERVE STEP READS `auth get`'S UNFILTERED STDOUT ON EVERY RECONCILE (decision 65,
|
|
13
|
+
* 2026-09-26, amending the design after LAND finding 5 — no node-side filter narrows it first).
|
|
14
|
+
* The key that stdout carries is dropped in the same breath: `parseAuthGet` has no `key` field in
|
|
15
|
+
* its return type at all, so there is no variable here ever holding it past that call. Only `auth
|
|
16
|
+
* get-or-create`, run once on the create branch, yields a `key` value, and it goes straight to
|
|
17
|
+
* OpenBao — never assigned to a variable this function returns, logs, or puts in the attributes
|
|
18
|
+
* it hands back — `attributesOf` takes a fingerprint, never a key.
|
|
19
|
+
* ★ CAPS DRIFT NEVER RE-MINTS THE KEY. `auth caps` changes only what an entity may do; the returned
|
|
20
|
+
* attributes reuse `output.fingerprint` unchanged.
|
|
21
|
+
* ⛔ A MOVED IDENTITY IS REFUSED HERE TOO, BELT AND SUSPENDERS WITH `planCephAuthEntity`'s
|
|
22
|
+
* `replace`. `isResolved(news)` in auth-entity.ts's `diff` can defer to the engine's own
|
|
23
|
+
* `update` fallback while any prop is still an Output (rename.ts's own header documents this
|
|
24
|
+
* exact Alchemy behaviour for every other family this pattern protects) — a case in which
|
|
25
|
+
* `planCephAuthEntity` never even runs. Reached with `output` naming a different entity/mount
|
|
26
|
+
* than `props`, this refuses before any ssh call, the same shape of guard `guardRename`
|
|
27
|
+
* (openbao/rename-identity.ts) runs first in every `Bao.*` reconcile.
|
|
28
|
+
*/
|
|
29
|
+
import * as Effect from 'effect/Effect';
|
|
30
|
+
import type * as HttpClient from 'effect/unstable/http/HttpClient';
|
|
31
|
+
import { type CephAuthEntityAttributes, type CephAuthEntityProps } from './ceph-auth-form.ts';
|
|
32
|
+
import { type CephTransportOptions } from './ceph-transport.ts';
|
|
33
|
+
export type CephAuthDeps = Pick<CephTransportOptions, 'dial' | 'log'>;
|
|
34
|
+
export declare const reconcileCephAuthEntity: (props: CephAuthEntityProps, output: CephAuthEntityAttributes | undefined, deps: CephAuthDeps) => Effect.Effect<CephAuthEntityAttributes, Error, HttpClient.HttpClient>;
|
|
35
|
+
//# sourceMappingURL=ceph-auth-reconcile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ceph-auth-reconcile.d.ts","sourceRoot":"","sources":["../../src/ceph/ceph-auth-reconcile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,KAAK,UAAU,MAAM,iCAAiC,CAAC;AAKnE,OAAO,EACL,KAAK,wBAAwB,EAC7B,KAAK,mBAAmB,EAKzB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,KAAK,oBAAoB,EAAqC,MAAM,qBAAqB,CAAC;AAEnG,MAAM,MAAM,YAAY,GAAG,IAAI,CAAC,oBAAoB,EAAE,MAAM,GAAG,KAAK,CAAC,CAAC;AA2BtE,eAAO,MAAM,uBAAuB,UAC3B,mBAAmB,UAClB,wBAAwB,GAAG,SAAS,QACtC,YAAY,KACjB,MAAM,CAAC,MAAM,CAAC,wBAAwB,EAAE,KAAK,EAAE,UAAU,CAAC,UAAU,CA2CnE,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The named Ceph config-option list — the only options `ceph config get/set/rm` may ever touch
|
|
3
|
+
* through the mon-command transport (ceph-argv.ts's `configProblem`). Design:
|
|
4
|
+
* docs/plans/2026-09-26-ceph-config-options.md, D-C1.
|
|
5
|
+
*
|
|
6
|
+
* ⛔ THE LIST STARTS EMPTY, AND EACH ADDITION IS ITS OWN REVIEWED PR LINE. Nothing in K-A4 adds to
|
|
7
|
+
* it — `CephConfigOption` (K-D) is a separate, later family; this file exists now only so the
|
|
8
|
+
* transport's allowlist has something to bound `config` against from day one, per the accepted
|
|
9
|
+
* design ("config get/set for the named option list which starts EMPTY").
|
|
10
|
+
* ⛔ NEVER ADD ONE OF THE LOCKOUT CLASSES BELOW. `mon_host`, `public_network`, `cluster_network`,
|
|
11
|
+
* `public_addr`, `cluster_addr`, every `auth_*_required` and every `key`/`keyring`-bearing
|
|
12
|
+
* option re-address the mons or de-authenticate the whole cluster — cutting every VM disk — and
|
|
13
|
+
* `isLockoutConfigOption` is a structural guard a test runs against this file's own list, not a
|
|
14
|
+
* suggestion for the reviewer of the next PR line.
|
|
15
|
+
* ⛔ NEVER ADD A SECRET-VALUED OPTION. mgr module options can hold passwords (REASONED — no live
|
|
16
|
+
* cluster to measure this against yet); a secret-bearing setting belongs in a vault-backed flow,
|
|
17
|
+
* never a `ceph config set` argv, which lands in the runner's log and the node's sudo journal.
|
|
18
|
+
*/
|
|
19
|
+
/** Starts empty. Add one reviewed option name per PR line, never a batch. */
|
|
20
|
+
export declare const NAMED_CONFIG_OPTIONS: ReadonlySet<string>;
|
|
21
|
+
/** Whether `name` is a class this transport must never read a value for, adopt, or write. */
|
|
22
|
+
export declare const isLockoutConfigOption: (name: string) => boolean;
|
|
23
|
+
//# sourceMappingURL=ceph-config-options.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ceph-config-options.d.ts","sourceRoot":"","sources":["../../src/ceph/ceph-config-options.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,6EAA6E;AAC7E,eAAO,MAAM,oBAAoB,EAAE,WAAW,CAAC,MAAM,CAAe,CAAC;AAarE,6FAA6F;AAC7F,eAAO,MAAM,qBAAqB,SAAU,MAAM,KAAG,OACE,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared by the two test files that prove `Ceph.AuthEntity` never leaks a minted key through a
|
|
3
|
+
* parse-error message: ceph-auth-parse.test.ts (direct parser calls) and
|
|
4
|
+
* ceph-auth-reconcile-secrecy.test.ts (through the full reconcile loop). Split out so the leak
|
|
5
|
+
* check and the malformed-stdout fixtures are identical in both places — the property being
|
|
6
|
+
* proved (decision 65) is the same one, and two hand-copied versions are exactly the kind of thing
|
|
7
|
+
* that quietly drifts apart.
|
|
8
|
+
*
|
|
9
|
+
* ⛔ TEST-ONLY. Nothing in `src/` imports this outside a `.test.ts` file.
|
|
10
|
+
* ★ NO HYPHEN IN THE SENTINEL. LAND red team (2026-09-26), CONFIRMED: a JSON lexer's "unexpected
|
|
11
|
+
* identifier" error for a bare (unquoted) token stops at the first character outside
|
|
12
|
+
* `[A-Za-z0-9_$]`, so a hyphenated sentinel (`sentinel-ceph-key-...`) truncates to its first
|
|
13
|
+
* word — `.not.toContain(SENTINEL)` on the FULL string then never fires even when that first
|
|
14
|
+
* word leaked. Cephx keys are base64 (`[A-Za-z0-9+/=]`, no hyphen), so this sentinel is shaped
|
|
15
|
+
* the same way, and every check here compares 8-character slices, not full-string containment.
|
|
16
|
+
*/
|
|
17
|
+
/** A cephx-shaped sentinel: looks like a real minted key, no hyphen anywhere to truncate on. */
|
|
18
|
+
export declare const KEY_SHAPED_SENTINEL = "AQDsentinelKEYsentinelKEY0123456789abcd==";
|
|
19
|
+
/** True if any 8-character window of `key` shows up anywhere in `message`. */
|
|
20
|
+
export declare const leaksSliceOf: (message: string, key?: string) => boolean;
|
|
21
|
+
/** `auth get`/`auth get-or-create` stdout with the key left as a bare (unquoted) JSON token. */
|
|
22
|
+
export declare const unquotedKeyStdout: (entity: string, key?: string) => string;
|
|
23
|
+
/** The same shape with a trailing comma after the entry — a different malformed-JSON path. */
|
|
24
|
+
export declare const trailingCommaKeyStdout: (entity: string, key?: string) => string;
|
|
25
|
+
//# sourceMappingURL=ceph-key-leak-assert.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ceph-key-leak-assert.d.ts","sourceRoot":"","sources":["../../src/ceph/ceph-key-leak-assert.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,gGAAgG;AAChG,eAAO,MAAM,mBAAmB,8CAA8C,CAAC;AAE/E,8EAA8E;AAC9E,eAAO,MAAM,YAAY,YAAa,MAAM,QAAO,MAAM,KAAyB,OAKjF,CAAC;AAEF,gGAAgG;AAChG,eAAO,MAAM,iBAAiB,WAAY,MAAM,QAAO,MAAM,KAAyB,MAC7C,CAAC;AAE1C,8FAA8F;AAC9F,eAAO,MAAM,sBAAsB,WAAY,MAAM,QAAO,MAAM,KAAyB,MAC/C,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export type CephExecResult = {
|
|
2
|
+
readonly exitCode: number;
|
|
3
|
+
readonly stdout: string;
|
|
4
|
+
readonly stderr: string;
|
|
5
|
+
};
|
|
6
|
+
/** One attempt against one mon: run `argv` (already sudo-wrapped by the caller) and report. */
|
|
7
|
+
export type CephDial = (node: string, argv: readonly string[]) => Promise<CephExecResult>;
|
|
8
|
+
/** ★ A fresh nonce per attempt — this dial never reuses a connection or a marker across calls. */
|
|
9
|
+
export declare const sshCephDial: CephDial;
|
|
10
|
+
export type CephTransportOptions = {
|
|
11
|
+
/** TB4 mon ssh destinations, tried in this order. Required; at least one. */
|
|
12
|
+
readonly nodes: readonly string[];
|
|
13
|
+
readonly dial?: CephDial;
|
|
14
|
+
/** One line per attempted argv, before it dials. @default a line on stderr */
|
|
15
|
+
readonly log?: (line: string) => void;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Run one allowed ceph shape against the first mon that answers.
|
|
19
|
+
*
|
|
20
|
+
* ⛔ THE ALLOWLIST CHECK HAPPENS BEFORE THE FIRST NODE IS EVEN TRIED — a refused argv dials no
|
|
21
|
+
* ssh at all, so a bug that builds a bad shape cannot leak so much as a connection attempt.
|
|
22
|
+
*/
|
|
23
|
+
export declare const runCephCommand: (options: CephTransportOptions, argv: readonly string[]) => Promise<CephExecResult & {
|
|
24
|
+
readonly node: string;
|
|
25
|
+
}>;
|
|
26
|
+
/**
|
|
27
|
+
* ★ LOCKOUT SAFETY, THE UFW-ESTABLISHED PATTERN: after every write, re-check quorum on a FRESH
|
|
28
|
+
* connection (a new dial, never the one the write used) and fail the row if it degraded. Never
|
|
29
|
+
* auto-repair, never continue — the caller's write is reported as failed even though it may
|
|
30
|
+
* itself have succeeded, because a write that broke quorum is not a success this transport will
|
|
31
|
+
* call one.
|
|
32
|
+
* ⚠️ THE SHAPE OF `quorum_status -f json` IS REASONED FROM PUBLIC CEPH DOCS, NOT MEASURED against
|
|
33
|
+
* this estate's Ceph release — there is no mon yet. An unparseable or missing `quorum` array
|
|
34
|
+
* fails closed as "degraded", never as "healthy"; see ceph-auth-parse.ts.
|
|
35
|
+
*/
|
|
36
|
+
export declare const assertFreshQuorum: (options: CephTransportOptions) => Promise<void>;
|
|
37
|
+
//# sourceMappingURL=ceph-transport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ceph-transport.d.ts","sourceRoot":"","sources":["../../src/ceph/ceph-transport.ts"],"names":[],"mappings":"AAyBA,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,+FAA+F;AAC/F,MAAM,MAAM,QAAQ,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;AAK1F,kGAAkG;AAClG,eAAO,MAAM,WAAW,EAAE,QAQzB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,6EAA6E;IAC7E,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC;IACzB,8EAA8E;IAC9E,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACvC,CAAC;AAIF;;;;;GAKG;AACH,eAAO,MAAM,cAAc,YAChB,oBAAoB,QACvB,SAAS,MAAM,EAAE,KACtB,OAAO,CAAC,cAAc,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAsBpD,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,iBAAiB,YAAmB,oBAAoB,KAAG,OAAO,CAAC,IAAI,CAenF,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A fake `CephDial` for the tests beside it — no ssh, no spawned process, ever. The same idea as
|
|
3
|
+
* `../linux/fake-sudo.ts` and `../openbao/fake-bao.ts`: production code is handed the real
|
|
4
|
+
* implementation, a test hands this instead, and neither one's internals change to make room for
|
|
5
|
+
* the other.
|
|
6
|
+
*
|
|
7
|
+
* ⛔ TEST-ONLY. Nothing in `src/` imports this outside a `.test.ts` file.
|
|
8
|
+
*/
|
|
9
|
+
import type { CephDial, CephExecResult } from './ceph-transport.ts';
|
|
10
|
+
/** One call this fake received. */
|
|
11
|
+
export type SeenCephCall = {
|
|
12
|
+
readonly node: string;
|
|
13
|
+
readonly argv: readonly string[];
|
|
14
|
+
};
|
|
15
|
+
/** What a scripted node answers: a result, or a thrown transport failure. */
|
|
16
|
+
export type CephAnswer = {
|
|
17
|
+
readonly kind: 'result';
|
|
18
|
+
readonly result: CephExecResult;
|
|
19
|
+
} | {
|
|
20
|
+
readonly kind: 'transport-error';
|
|
21
|
+
readonly message: string;
|
|
22
|
+
};
|
|
23
|
+
export type FakeCephDial = {
|
|
24
|
+
readonly dial: CephDial;
|
|
25
|
+
readonly seen: SeenCephCall[];
|
|
26
|
+
};
|
|
27
|
+
declare const ok: (stdout: string, exitCode?: number, stderr?: string) => CephAnswer;
|
|
28
|
+
/**
|
|
29
|
+
* `script` maps a node to the fixed sequence of answers it gives, one per call that reaches it —
|
|
30
|
+
* the last entry repeats once exhausted. A node with no entry always transport-fails, which is
|
|
31
|
+
* exactly "an unreachable mon" without a special case.
|
|
32
|
+
*/
|
|
33
|
+
export declare const fakeCephDial: (script: Readonly<Record<string, readonly CephAnswer[]>>) => FakeCephDial;
|
|
34
|
+
export { ok as fakeCephOk };
|
|
35
|
+
//# sourceMappingURL=fake-ceph-dial.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fake-ceph-dial.d.ts","sourceRoot":"","sources":["../../src/ceph/fake-ceph-dial.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAEpE,mCAAmC;AACnC,MAAM,MAAM,YAAY,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC;AAEvF,6EAA6E;AAC7E,MAAM,MAAM,UAAU,GAClB;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAA;CAAE,GAC5D;IAAE,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnE,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,YAAY,EAAE,CAAC;CAC/B,CAAC;AAEF,QAAA,MAAM,EAAE,WAAY,MAAM,yCAA8B,UAGtD,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,YAAY,WACf,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,UAAU,EAAE,CAAC,CAAC,KACtD,YAiBF,CAAC;AAEF,OAAO,EAAE,EAAE,IAAI,UAAU,EAAE,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ceph providers for Alchemy — the mon-command transport and `Ceph.AuthEntity` (K-A4).
|
|
3
|
+
*
|
|
4
|
+
* ⛔ THIS BARREL IS THE PUBLIC API, DELIBERATELY SMALLER THAN THE DIRECTORY — see
|
|
5
|
+
* `../openbao/index.ts`'s header for why. The allowlist internals (ceph-argv.ts), the parsing
|
|
6
|
+
* (ceph-auth-parse.ts) and the reconcile loop (ceph-auth-reconcile.ts) are exported by path for
|
|
7
|
+
* a future `CephConfigOption` (K-D) or a test to reach directly, not published here.
|
|
8
|
+
*/
|
|
9
|
+
export type { CephAuthEntityAttributes, CephAuthEntityProps, CephCaps } from './auth-entity.ts';
|
|
10
|
+
export { CephAuthEntity, CephAuthEntityProvider } from './auth-entity.ts';
|
|
11
|
+
export type { CephDial, CephExecResult, CephTransportOptions } from './ceph-transport.ts';
|
|
12
|
+
export { assertFreshQuorum, runCephCommand, sshCephDial } from './ceph-transport.ts';
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ceph/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,YAAY,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAChG,OAAO,EAAE,cAAc,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAC1E,YAAY,EAAE,QAAQ,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC1F,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC"}
|