@homeflare/alchemy 0.39.0 → 0.41.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 +10 -8
- package/dist/caddy/index.js.map +2 -2
- 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 +1610 -0
- package/dist/ceph/index.js.map +38 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/launchd/fake-runner.d.ts.map +1 -1
- package/dist/launchd/index.d.ts +1 -1
- package/dist/launchd/index.d.ts.map +1 -1
- package/dist/launchd/index.js +7 -1
- package/dist/launchd/index.js.map +5 -5
- package/dist/launchd/local-runner.d.ts.map +1 -1
- package/dist/launchd/runner.d.ts +21 -0
- package/dist/launchd/runner.d.ts.map +1 -1
- package/dist/launchd/sudo-runner.d.ts.map +1 -1
- package/dist/linux/directory-lifecycle.d.ts.map +1 -1
- package/dist/linux/fake-linux-host.d.ts.map +1 -1
- package/dist/linux/index.d.ts +1 -1
- package/dist/linux/index.d.ts.map +1 -1
- package/dist/linux/index.js +16 -4
- package/dist/linux/index.js.map +7 -7
- package/dist/linux/ssh-runner.d.ts.map +1 -1
- package/dist/linux/sudo-runner.d.ts.map +1 -1
- package/dist/opnsense/alias-form.d.ts +14 -1
- package/dist/opnsense/alias-form.d.ts.map +1 -1
- package/dist/opnsense/alias.d.ts +1 -1
- package/dist/opnsense/alias.d.ts.map +1 -1
- package/dist/opnsense/group-form.d.ts +8 -2
- package/dist/opnsense/group-form.d.ts.map +1 -1
- package/dist/opnsense/group.d.ts +1 -1
- package/dist/opnsense/group.d.ts.map +1 -1
- package/dist/opnsense/index.js +15 -7
- package/dist/opnsense/index.js.map +7 -7
- package/dist/opnsense/wire.d.ts +42 -12
- package/dist/opnsense/wire.d.ts.map +1 -1
- package/dist/proxmox/index.js +62 -39
- package/dist/proxmox/index.js.map +8 -7
- package/dist/proxmox/qemu-volume.d.ts +12 -2
- package/dist/proxmox/qemu-volume.d.ts.map +1 -1
- package/dist/proxmox/storage-form.d.ts +28 -3
- package/dist/proxmox/storage-form.d.ts.map +1 -1
- package/dist/proxmox/storage-plugin-options.d.ts +2 -0
- package/dist/proxmox/storage-plugin-options.d.ts.map +1 -0
- package/dist/proxmox/storage-wire.d.ts +28 -1
- package/dist/proxmox/storage-wire.d.ts.map +1 -1
- package/dist/proxmox/storage.d.ts +6 -1
- package/dist/proxmox/storage.d.ts.map +1 -1
- package/dist/release/index.d.ts +1 -1
- package/dist/release/index.d.ts.map +1 -1
- package/dist/release/index.js.map +2 -2
- 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/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/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/index.d.ts +7 -0
- package/dist/unifi/index.d.ts.map +1 -1
- package/dist/unifi/index.js +588 -3
- package/dist/unifi/index.js.map +24 -4
- package/dist/unifi/paginate.d.ts +0 -12
- package/dist/unifi/paginate.d.ts.map +1 -1
- package/dist/unifi/providers.d.ts +1 -1
- package/dist/unifi/providers.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/distilled-interim.md +7 -0
- package/docs/launchd.md +5 -3
- package/docs/provider-standard.md +5 -1
- package/docs/talos-argocd-dogfood.md +160 -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 +10 -5
- package/package.json +7 -3
- 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/index.ts +1 -0
- package/src/launchd/fake-runner.ts +2 -0
- package/src/launchd/index.ts +8 -1
- package/src/launchd/local-runner.ts +16 -1
- package/src/launchd/runner.ts +22 -0
- package/src/launchd/sudo-runner.ts +3 -0
- package/src/linux/directory-lifecycle.ts +18 -3
- package/src/linux/directory-sudo.test.ts +59 -0
- package/src/linux/directory.test.ts +34 -8
- package/src/linux/fake-linux-host.ts +2 -0
- package/src/linux/index.ts +1 -0
- package/src/linux/ssh-runner.ts +4 -0
- package/src/linux/sudo-runner.ts +3 -0
- package/src/opnsense/alias-form.test.ts +24 -12
- package/src/opnsense/alias-form.ts +20 -7
- package/src/opnsense/alias.test.ts +13 -6
- package/src/opnsense/alias.ts +16 -10
- package/src/opnsense/group-form.test.ts +12 -8
- package/src/opnsense/group-form.ts +13 -4
- package/src/opnsense/group.test.ts +18 -7
- package/src/opnsense/group.ts +10 -3
- package/src/opnsense/wire.ts +57 -12
- package/src/proxmox/qemu-volume.test.ts +153 -4
- package/src/proxmox/qemu-volume.ts +71 -14
- package/src/proxmox/storage-form.ts +48 -8
- package/src/proxmox/storage-plugin-options.ts +45 -0
- package/src/proxmox/storage-update.test.ts +183 -0
- package/src/proxmox/storage-wire.ts +54 -7
- package/src/proxmox/storage.ts +18 -6
- package/src/release/index.ts +1 -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/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/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/index.ts +63 -0
- package/src/unifi/paginate.test.ts +24 -0
- package/src/unifi/paginate.ts +15 -3
- package/src/unifi/providers.ts +19 -1
- 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 +8 -54
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `Unifi.AclRule`'s `matches` AND `driftOf` (B6) — both built on the ONE field list below, the
|
|
3
|
+
* same `fieldDrift`-is-the-only-comparison shape `network-drift.ts`'s header explains (MEDIUM-4,
|
|
4
|
+
* red team, 2026-09-26): `matches(attrs, props) === (driftOf(live, props).length === 0)` is true
|
|
5
|
+
* BY CONSTRUCTION.
|
|
6
|
+
*
|
|
7
|
+
* ⚠️ `stripNullish: true` ON EVERY FIELD BY DEFAULT (`drift.ts`'s `defaultEqual`) — same "UniFi's
|
|
8
|
+
* JSON answers `null`, a declaration omits" tolerance `network-drift.ts` documents.
|
|
9
|
+
* ⛔ `enforcingDeviceFilter`/`protocolFilter` RUN THROUGH `acl-rule-form.ts`'s normalizers on BOTH
|
|
10
|
+
* sides before comparing — never applied to only `live` or only `declared` (that specific gap is
|
|
11
|
+
* what MEDIUM-4's own mutant found in `network-drift.ts`; see its header).
|
|
12
|
+
*/
|
|
13
|
+
import type * as aclRules from '@distilled.cloud/unifi-network/access_control_acl_rules';
|
|
14
|
+
import { type AclRuleAttributes, type AclRuleProps } from './acl-rule-form.ts';
|
|
15
|
+
export declare const matches: (attributes: AclRuleAttributes, props: AclRuleProps) => boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Per-field live-vs-declared drift straight from one live read — the task's own API
|
|
18
|
+
* (`driftOf(live, props)`), so `homeflare-network`'s pre-import drift check never has to derive
|
|
19
|
+
* `attributesOf` itself just to call this.
|
|
20
|
+
*/
|
|
21
|
+
export declare const driftOf: (live: aclRules.ACLRule, props: AclRuleProps) => import("./drift.ts").FieldDrift[];
|
|
22
|
+
//# sourceMappingURL=acl-rule-drift.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"acl-rule-drift.d.ts","sourceRoot":"","sources":["../../src/unifi/acl-rule-drift.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,KAAK,QAAQ,MAAM,yDAAyD,CAAC;AAEzF,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,YAAY,EAIlB,MAAM,oBAAoB,CAAC;AA2B5B,eAAO,MAAM,OAAO,eAAgB,iBAAiB,SAAS,YAAY,KAAG,OACjC,CAAC;AAE7C;;;;GAIG;AACH,eAAO,MAAM,OAAO,SAAU,QAAQ,CAAC,OAAO,SAAS,YAAY,sCACrB,CAAC"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `Unifi.AclRule`'s wire shape — the declarable subset of `ACLRule` (`getAclRule`'s own decode
|
|
3
|
+
* target — `ACLRuleObject` is the structurally-identical page-list item type, unused here), and
|
|
4
|
+
* how a live read
|
|
5
|
+
* becomes both plan attributes and a rendered declaration. Rule ORDER is a separate resource
|
|
6
|
+
* (`acl-rule-ordering.ts`, T5) — this file is one rule's own fields only.
|
|
7
|
+
*
|
|
8
|
+
* ⚠️ `sourceFilter`/`destinationFilter` STAY `unknown`, ON THE SDK'S OWN AUTHORITY.
|
|
9
|
+
* `access_control_acl_rules.ts`'s own comment on both ("Shape varies by variant — widened by
|
|
10
|
+
* scripts/convert.ts; see README") says the OpenAPI discriminator these vary over was flattened
|
|
11
|
+
* at generation time (T10), same as `network-form.ts`'s `ipv4Configuration`. A3 (typing these
|
|
12
|
+
* per-discriminator) is scoped OUT of this PR — see the plan's family inventory — so both stay
|
|
13
|
+
* opaque JSON, compared with plain `deepEqual`, honest about not being decoded.
|
|
14
|
+
*
|
|
15
|
+
* ⚠️ KNOWN GAP UNTIL A3 (T15, red team, Minor finding 4): the vendor's own variant DTOs for these
|
|
16
|
+
* filters carry SET-LIKE arrays too (`networkIds`, `ipAddressesOrSubnets`, `portFilter`,
|
|
17
|
+
* `macAddresses` — `docs/unifi-acl-rule.md`'s own field notes). Because the filter stays opaque,
|
|
18
|
+
* `deepEqual` compares those nested arrays order-sensitively, the same false-`update` risk this
|
|
19
|
+
* file already removes for `deviceIds`/`protocolFilter` by normalizing them — but here there is
|
|
20
|
+
* no decoded field to normalize. Accepted as a known gap, not fixed, until A3 types the filter
|
|
21
|
+
* per-discriminator and can apply `sortedSet` to its own array fields.
|
|
22
|
+
*
|
|
23
|
+
* ⛔ `index` IS ATTRIBUTES-ONLY, NEVER DECLARED. `CreateAclRuleRequest`'s own field comment:
|
|
24
|
+
* "ACL rule index. This property is deprecated and has no effect. Use the dedicated ACL rule
|
|
25
|
+
* reordering endpoint." The live object's current position is `acl-rule-ordering.ts`'s concern
|
|
26
|
+
* (`ACLRuleOrdering.orderedAclRuleIds`), not this resource's declared identity — reporting it
|
|
27
|
+
* here without comparing it avoids a field that can never converge under this family's own
|
|
28
|
+
* `matches` (nothing here could ever change it) from silently pretending to be declarable.
|
|
29
|
+
*
|
|
30
|
+
* ⛔ `enforcingDeviceFilter.deviceIds` AND `protocolFilter` ARE SETS, NOT SEQUENCES — same
|
|
31
|
+
* reasoning `firewall-zone-form.ts` gives for `networkIds`: "IDs of the Switch-capable devices
|
|
32
|
+
* used to enforce the ACL rule" and "Protocols this ACL rule will be applied to" both describe
|
|
33
|
+
* membership, with no indication either list is ordered like `acl-rule-ordering.ts`'s rule-id
|
|
34
|
+
* sequence. Left alone, a console that returns either in a different order between calls would
|
|
35
|
+
* plan a spurious `update` that this read-only family's `reconcile` then refuses forever.
|
|
36
|
+
*/
|
|
37
|
+
import type * as aclRules from '@distilled.cloud/unifi-network/access_control_acl_rules';
|
|
38
|
+
/** ★ EXPORTED so `acl-rule-drift.ts` normalizes both live and declared sides identically — see
|
|
39
|
+
* `network-form.ts`'s own header for why a normalizer applied to only one side is a bug class. */
|
|
40
|
+
export declare const normalizeDeviceFilter: (value: aclRules.ACLRuleDeviceFilter | undefined) => aclRules.ACLRuleDeviceFilter | undefined;
|
|
41
|
+
export declare const normalizeProtocolFilter: (value: readonly string[] | undefined) => string[] | undefined;
|
|
42
|
+
/** ⚠️ EVERY OPTIONAL FIELD SPELLS OUT `| undefined` — `exactOptionalPropertyTypes`; see
|
|
43
|
+
* `network-form.ts`'s own header. */
|
|
44
|
+
export interface AclRuleProps {
|
|
45
|
+
siteId: string;
|
|
46
|
+
aclRuleId: string;
|
|
47
|
+
/** `ALLOW` or `BLOCK` (also accepts a future vendor value the spec did not enumerate). */
|
|
48
|
+
action: string;
|
|
49
|
+
description?: string | undefined;
|
|
50
|
+
/** Traffic destination filter — opaque, see the header. */
|
|
51
|
+
destinationFilter?: unknown;
|
|
52
|
+
enabled: boolean;
|
|
53
|
+
/** Devices enforcing this rule — compared as a SET, see the header. */
|
|
54
|
+
enforcingDeviceFilter?: aclRules.ACLRuleDeviceFilter | undefined;
|
|
55
|
+
name: string;
|
|
56
|
+
/** Traffic source filter — opaque, see the header. */
|
|
57
|
+
sourceFilter?: unknown;
|
|
58
|
+
type: string;
|
|
59
|
+
/** Protocols this rule applies to — compared as a SET, see the header. */
|
|
60
|
+
protocolFilter?: string[] | undefined;
|
|
61
|
+
networkIdFilter?: string | undefined;
|
|
62
|
+
}
|
|
63
|
+
export interface AclRuleAttributes {
|
|
64
|
+
siteId: string;
|
|
65
|
+
aclRuleId: string;
|
|
66
|
+
action: string;
|
|
67
|
+
description: string | undefined;
|
|
68
|
+
destinationFilter: unknown;
|
|
69
|
+
enabled: boolean;
|
|
70
|
+
enforcingDeviceFilter: aclRules.ACLRuleDeviceFilter | undefined;
|
|
71
|
+
/** ACL rule index (current priority position) — server-derived, never declared; see header. */
|
|
72
|
+
index: number;
|
|
73
|
+
name: string;
|
|
74
|
+
sourceFilter: unknown;
|
|
75
|
+
type: string;
|
|
76
|
+
protocolFilter: string[] | undefined;
|
|
77
|
+
networkIdFilter: string | undefined;
|
|
78
|
+
/** `metadata.origin` — server-derived, never declared; see `firewall-zone-form.ts`'s own. */
|
|
79
|
+
metadataOrigin: string;
|
|
80
|
+
}
|
|
81
|
+
export declare const attributesOf: (live: aclRules.ACLRule, props: AclRuleProps) => AclRuleAttributes;
|
|
82
|
+
/**
|
|
83
|
+
* The declaration renderer (task spec: "given one live object, return the props a declaration
|
|
84
|
+
* needs so its plan is noop"). A later import script feeds `getAclRule`'s own response straight in
|
|
85
|
+
* and writes the result as `aclRule('<id>', declareAclRule(live, siteId))` — no field is invented
|
|
86
|
+
* or defaulted beyond what `attributesOf` already reports, so `matches(attributesOf(live, props),
|
|
87
|
+
* declareAclRule(live, siteId))` is `true` by construction (`acl-rule.test.ts` proves it).
|
|
88
|
+
*/
|
|
89
|
+
export declare const declareAclRule: (live: aclRules.ACLRule, siteId: string) => AclRuleProps;
|
|
90
|
+
//# sourceMappingURL=acl-rule-form.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"acl-rule-form.d.ts","sourceRoot":"","sources":["../../src/unifi/acl-rule-form.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,OAAO,KAAK,KAAK,QAAQ,MAAM,yDAAyD,CAAC;AAIzF;mGACmG;AACnG,eAAO,MAAM,qBAAqB,UACzB,QAAQ,CAAC,mBAAmB,GAAG,SAAS,KAC9C,QAAQ,CAAC,mBAAmB,GAAG,SAM3B,CAAC;AAER,eAAO,MAAM,uBAAuB,UAC3B,SAAS,MAAM,EAAE,GAAG,SAAS,KACnC,MAAM,EAAE,GAAG,SAA2D,CAAC;AAE1E;sCACsC;AACtC,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,0FAA0F;IAC1F,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,2DAA2D;IAC3D,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,uEAAuE;IACvE,qBAAqB,CAAC,EAAE,QAAQ,CAAC,mBAAmB,GAAG,SAAS,CAAC;IACjE,IAAI,EAAE,MAAM,CAAC;IACb,sDAAsD;IACtD,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,0EAA0E;IAC1E,cAAc,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IACtC,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACtC;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,iBAAiB,EAAE,OAAO,CAAC;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,qBAAqB,EAAE,QAAQ,CAAC,mBAAmB,GAAG,SAAS,CAAC;IAChE,+FAA+F;IAC/F,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,OAAO,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IACrC,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,6FAA6F;IAC7F,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,eAAO,MAAM,YAAY,SAAU,QAAQ,CAAC,OAAO,SAAS,YAAY,KAAG,iBAezE,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,SAAU,QAAQ,CAAC,OAAO,UAAU,MAAM,KAAG,YAatE,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `Unifi.AclRuleOrdering`'s wire shape — ONE resource per site (`getAclRuleOrdering`'s own scope,
|
|
3
|
+
* `GET /v1/sites/{siteId}/acl-rules/ordering`), not per rule. Compare with `firewall-zone-form.ts`'s
|
|
4
|
+
* `networkIds`, which is a genuine SET: this file's `orderedAclRuleIds` is the opposite case.
|
|
5
|
+
*
|
|
6
|
+
* ⛔ T5 — `orderedAclRuleIds` IS A SEQUENCE, NEVER RUN THROUGH `sortedSet`. The endpoint's own name
|
|
7
|
+
* (`updateAclRuleOrdering`) and its field's own vendor comment on `ACLRule.index` ("Lower index
|
|
8
|
+
* has higher priority") both say this list's POSITION is the entire value it carries — rule
|
|
9
|
+
* priority. `firewall-zone-form.ts`'s `sortedSet`/`network-form.ts`'s three set normalizers all
|
|
10
|
+
* exist to stop the OPPOSITE mistake (treating a set as if order mattered); applying the same
|
|
11
|
+
* fix here would silently discard the one thing this resource represents. `drift.ts`'s
|
|
12
|
+
* `defaultEqual` (`deepEqual`) already compares arrays element-by-element without sorting them
|
|
13
|
+
* (its header: "sorts object KEYS but NOT ARRAY ELEMENTS") — so leaving this field un-normalized
|
|
14
|
+
* is what makes the comparison order-sensitive, not an oversight to "fix" later.
|
|
15
|
+
*
|
|
16
|
+
* ★ `makeDriftOf` (`drift.ts`), NO CUSTOM `equal` — same framework every other family's
|
|
17
|
+
* `matches`/`driftOf` share (MEDIUM-4). Its default `deepEqual` is ALREADY order-sensitive for
|
|
18
|
+
* arrays (see the paragraph above), so the absence of a custom `equal` here, unlike
|
|
19
|
+
* `firewall-zone-form.ts`'s `networkIds` entry, is itself the "never sortedSet" rule in force —
|
|
20
|
+
* not an oversight.
|
|
21
|
+
*/
|
|
22
|
+
import type * as aclRules from '@distilled.cloud/unifi-network/access_control_acl_rules';
|
|
23
|
+
export interface AclRuleOrderingProps {
|
|
24
|
+
siteId: string;
|
|
25
|
+
/** Rule IDs in priority order, highest priority first — never compared as a set (see header). */
|
|
26
|
+
orderedAclRuleIds: string[];
|
|
27
|
+
}
|
|
28
|
+
export interface AclRuleOrderingAttributes {
|
|
29
|
+
siteId: string;
|
|
30
|
+
orderedAclRuleIds: string[];
|
|
31
|
+
}
|
|
32
|
+
export declare const attributesOf: (live: aclRules.ACLRuleOrdering, props: AclRuleOrderingProps) => AclRuleOrderingAttributes;
|
|
33
|
+
/**
|
|
34
|
+
* The declaration renderer (task spec: "given one live object, return the props a declaration
|
|
35
|
+
* needs so its plan is noop"). A later import script feeds `getAclRuleOrdering`'s own response
|
|
36
|
+
* straight in and writes the result as `aclRuleOrdering('site-1', declareAclRuleOrdering(live,
|
|
37
|
+
* siteId))` — `matches(attributesOf(live, props), declareAclRuleOrdering(live, siteId))` is `true`
|
|
38
|
+
* by construction (`acl-rule-ordering.test.ts` proves it).
|
|
39
|
+
*/
|
|
40
|
+
export declare const declareAclRuleOrdering: (live: aclRules.ACLRuleOrdering, siteId: string) => AclRuleOrderingProps;
|
|
41
|
+
export declare const matches: (attributes: AclRuleOrderingAttributes, props: AclRuleOrderingProps) => boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Per-field live-vs-declared drift straight from one live read — the task's own API
|
|
44
|
+
* (`driftOf(live, props)`). Only one field exists, so this either reports nothing or the whole
|
|
45
|
+
* ordered pair, never a per-position breakdown -- a future consumer wanting "which rule moved"
|
|
46
|
+
* would need to diff the two arrays itself.
|
|
47
|
+
*/
|
|
48
|
+
export declare const driftOf: (live: aclRules.ACLRuleOrdering, props: AclRuleOrderingProps) => import("./drift.ts").FieldDrift[];
|
|
49
|
+
//# sourceMappingURL=acl-rule-ordering-form.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"acl-rule-ordering-form.d.ts","sourceRoot":"","sources":["../../src/unifi/acl-rule-ordering-form.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,KAAK,QAAQ,MAAM,yDAAyD,CAAC;AAGzF,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,iGAAiG;IACjG,iBAAiB,EAAE,MAAM,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,yBAAyB;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB,EAAE,MAAM,EAAE,CAAC;CAC7B;AAED,eAAO,MAAM,YAAY,SACjB,QAAQ,CAAC,eAAe,SACvB,oBAAoB,KAC1B,yBAGD,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,SAC3B,QAAQ,CAAC,eAAe,UACtB,MAAM,KACb,oBAGD,CAAC;AAUH,eAAO,MAAM,OAAO,eACN,yBAAyB,SAC9B,oBAAoB,KAC1B,OAAqD,CAAC;AAEzD;;;;;GAKG;AACH,eAAO,MAAM,OAAO,SAAU,QAAQ,CAAC,eAAe,SAAS,oBAAoB,sCACrC,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `Unifi.AclRuleOrdering` — the ONE ordered list of user-defined ACL rule IDs for a site
|
|
3
|
+
* (`getAclRuleOrdering`/`updateAclRuleOrdering`, `GET`/`PUT /v1/sites/{siteId}/acl-rules/ordering`),
|
|
4
|
+
* READ-ONLY (`policy.ts`). T5's per-family variant of the ordering trap `docs/unifi-api-notes.md`
|
|
5
|
+
* warns about for `Unifi.FirewallPolicyOrdering` (`firewall-policy-ordering.ts`, keyed per zone
|
|
6
|
+
* pair rather than site-wide — see its own header for why): the endpoint replaces the WHOLE list
|
|
7
|
+
* on a write, so a partial or resorted body would drop or reorder every OTHER rule too.
|
|
8
|
+
* This family never writes at all, but its `matches`/`driftOf` (`acl-rule-ordering-form.ts`) are
|
|
9
|
+
* still order-preserving, never `sortedSet`, so a future write path inherits a correct comparison
|
|
10
|
+
* rather than one that has to be fixed alongside the first `update`.
|
|
11
|
+
*
|
|
12
|
+
* ★ ONE OBJECT PER SITE, NOT PER RULE — unlike `acl-rule.ts`, there is no per-object id in the
|
|
13
|
+
* wire response at all (`ACLRuleOrdering` is just `{ orderedAclRuleIds }`); the resource's own
|
|
14
|
+
* `id` (the stack-chosen string passed to `aclRuleOrdering(id, props)`) is a label the DECLARER
|
|
15
|
+
* picks, same as `firewallZone`/`network`, not something read back from the vendor.
|
|
16
|
+
*/
|
|
17
|
+
import { Resource } from 'alchemy';
|
|
18
|
+
import * as Provider from 'alchemy/Provider';
|
|
19
|
+
import * as aclRules from '@distilled.cloud/unifi-network/access_control_acl_rules';
|
|
20
|
+
import * as Effect from 'effect/Effect';
|
|
21
|
+
import { type AclRuleOrderingAttributes, type AclRuleOrderingProps } from './acl-rule-ordering-form.ts';
|
|
22
|
+
import type { UnifiRequirements, UnifiSpec } from './resource.ts';
|
|
23
|
+
export type { AclRuleOrderingAttributes, AclRuleOrderingProps } from './acl-rule-ordering-form.ts';
|
|
24
|
+
export { declareAclRuleOrdering, driftOf } from './acl-rule-ordering-form.ts';
|
|
25
|
+
export interface UnifiAclRuleOrdering extends Resource<'Unifi.AclRuleOrdering', AclRuleOrderingProps, AclRuleOrderingAttributes, never, UnifiRequirements> {
|
|
26
|
+
}
|
|
27
|
+
export declare const UnifiAclRuleOrdering: import("alchemy").ResourceClass<UnifiAclRuleOrdering>;
|
|
28
|
+
/** `aclRuleOrdering('site-1', props)` — `adopt(true)` piped on by default (H5); see `network.ts`. */
|
|
29
|
+
export declare const aclRuleOrdering: (id: string, props: AclRuleOrderingProps) => Effect.Effect<UnifiAclRuleOrdering, never, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
30
|
+
/** ★ EXPORTED for direct testing against a fake `Credentials` layer — see `network.ts`'s own. */
|
|
31
|
+
export declare const spec: UnifiSpec<AclRuleOrderingProps, aclRules.ACLRuleOrdering, AclRuleOrderingAttributes, aclRules.GetAclRuleOrderingError>;
|
|
32
|
+
export declare const handlers: {
|
|
33
|
+
list: () => Effect.Effect<never[], never, never>;
|
|
34
|
+
read: (args: {
|
|
35
|
+
olds: AclRuleOrderingProps;
|
|
36
|
+
output: AclRuleOrderingAttributes | undefined;
|
|
37
|
+
}) => Effect.Effect<AclRuleOrderingAttributes | undefined, aclRules.UnifiNetworkOpError, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
38
|
+
diff: (args: {
|
|
39
|
+
news: import("alchemy").Input<AclRuleOrderingProps>;
|
|
40
|
+
output: AclRuleOrderingAttributes | undefined;
|
|
41
|
+
}) => Effect.Effect<{
|
|
42
|
+
readonly action: 'update';
|
|
43
|
+
} | {
|
|
44
|
+
readonly action: 'noop';
|
|
45
|
+
} | undefined, aclRules.UnifiNetworkOpError, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
46
|
+
reconcile: (args: {
|
|
47
|
+
news: AclRuleOrderingProps;
|
|
48
|
+
}) => Effect.Effect<AclRuleOrderingAttributes, import("./policy.ts").UnifiWriteRefused | aclRules.UnifiNetworkOpError, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
49
|
+
delete: (args: {
|
|
50
|
+
olds: AclRuleOrderingProps;
|
|
51
|
+
}) => Effect.Effect<never, import("./policy.ts").UnifiWriteRefused, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
52
|
+
};
|
|
53
|
+
export declare const UnifiAclRuleOrderingProvider: () => import("effect/Layer").Layer<Provider.Provider<UnifiAclRuleOrdering>, never, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
54
|
+
//# sourceMappingURL=acl-rule-ordering.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"acl-rule-ordering.d.ts","sourceRoot":"","sources":["../../src/unifi/acl-rule-ordering.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,QAAQ,MAAM,yDAAyD,CAAC;AACpF,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,EACL,KAAK,yBAAyB,EAC9B,KAAK,oBAAoB,EAG1B,MAAM,6BAA6B,CAAC;AACrC,OAAO,KAAK,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAGlE,YAAY,EAAE,yBAAyB,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnG,OAAO,EAAE,sBAAsB,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AAE9E,MAAM,WAAW,oBAAqB,SAAQ,QAAQ,CACpD,uBAAuB,EACvB,oBAAoB,EACpB,yBAAyB,EACzB,KAAK,EACL,iBAAiB,CAClB;CAAG;AAEJ,eAAO,MAAM,oBAAoB,uDAE/B,CAAC;AAEH,qGAAqG;AACrG,eAAO,MAAM,eAAe,OAAQ,MAAM,SAAS,oBAAoB,qGACpB,CAAC;AAEpD,iGAAiG;AACjG,eAAO,MAAM,IAAI,EAAE,SAAS,CAC1B,oBAAoB,EACpB,QAAQ,CAAC,eAAe,EACxB,yBAAyB,EACzB,QAAQ,CAAC,uBAAuB,CAUjC,CAAC;AAEF,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;CAAsB,CAAC;AAE5C,eAAO,MAAM,4BAA4B,0IAC0D,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `Unifi.AclRule` — one user-defined ACL rule on a UniFi Network site, READ-ONLY (`policy.ts`).
|
|
3
|
+
* `Unifi.AclRuleOrdering` (`acl-rule-ordering.ts`) is the sibling resource for rule ORDER (T5) —
|
|
4
|
+
* one per site, never this file's concern.
|
|
5
|
+
*
|
|
6
|
+
* ★ T11 GATE — see `dns-policy.ts`'s own header for the full closure-diff record: `Access Control
|
|
7
|
+
* (ACL Rules)` (7 ops, including `getAclRuleOrdering`/`updateAclRuleOrdering`) is
|
|
8
|
+
* byte-identical between 10.4.57 and 10.6.97, and unreachable from any of the 14 schemas that DID
|
|
9
|
+
* change. Full breakdown: `docs/unifi-acl-rule.md`.
|
|
10
|
+
*/
|
|
11
|
+
import { Resource } from 'alchemy';
|
|
12
|
+
import * as Provider from 'alchemy/Provider';
|
|
13
|
+
import * as aclRules from '@distilled.cloud/unifi-network/access_control_acl_rules';
|
|
14
|
+
import * as Effect from 'effect/Effect';
|
|
15
|
+
import { type AclRuleAttributes, type AclRuleProps } from './acl-rule-form.ts';
|
|
16
|
+
import type { UnifiRequirements, UnifiSpec } from './resource.ts';
|
|
17
|
+
export type { AclRuleAttributes, AclRuleProps } from './acl-rule-form.ts';
|
|
18
|
+
export { declareAclRule } from './acl-rule-form.ts';
|
|
19
|
+
export { driftOf } from './acl-rule-drift.ts';
|
|
20
|
+
export interface UnifiAclRule extends Resource<'Unifi.AclRule', AclRuleProps, AclRuleAttributes, never, UnifiRequirements> {
|
|
21
|
+
}
|
|
22
|
+
export declare const UnifiAclRule: import("alchemy").ResourceClass<UnifiAclRule>;
|
|
23
|
+
/** `aclRule('block-iot-wan', props)` — `adopt(true)` piped on by default (H5); see `network.ts`. */
|
|
24
|
+
export declare const aclRule: (id: string, props: AclRuleProps) => Effect.Effect<UnifiAclRule, never, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
25
|
+
/** ★ EXPORTED for direct testing against a fake `Credentials` layer — see `network.ts`'s own. */
|
|
26
|
+
export declare const spec: UnifiSpec<AclRuleProps, aclRules.ACLRule, AclRuleAttributes, aclRules.GetAclRuleError>;
|
|
27
|
+
export declare const handlers: {
|
|
28
|
+
list: () => Effect.Effect<never[], never, never>;
|
|
29
|
+
read: (args: {
|
|
30
|
+
olds: AclRuleProps;
|
|
31
|
+
output: AclRuleAttributes | undefined;
|
|
32
|
+
}) => Effect.Effect<AclRuleAttributes | undefined, aclRules.UnifiNetworkOpError, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
33
|
+
diff: (args: {
|
|
34
|
+
news: import("alchemy").Input<AclRuleProps>;
|
|
35
|
+
output: AclRuleAttributes | undefined;
|
|
36
|
+
}) => Effect.Effect<{
|
|
37
|
+
readonly action: 'update';
|
|
38
|
+
} | {
|
|
39
|
+
readonly action: 'noop';
|
|
40
|
+
} | undefined, aclRules.UnifiNetworkOpError, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
41
|
+
reconcile: (args: {
|
|
42
|
+
news: AclRuleProps;
|
|
43
|
+
}) => Effect.Effect<AclRuleAttributes, import("./policy.ts").UnifiWriteRefused | aclRules.UnifiNetworkOpError, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
44
|
+
delete: (args: {
|
|
45
|
+
olds: AclRuleProps;
|
|
46
|
+
}) => Effect.Effect<never, import("./policy.ts").UnifiWriteRefused, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
47
|
+
};
|
|
48
|
+
export declare const UnifiAclRuleProvider: () => import("effect/Layer").Layer<Provider.Provider<UnifiAclRule>, never, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
49
|
+
//# sourceMappingURL=acl-rule.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"acl-rule.d.ts","sourceRoot":"","sources":["../../src/unifi/acl-rule.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,QAAQ,MAAM,yDAAyD,CAAC;AACpF,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,KAAK,iBAAiB,EAAE,KAAK,YAAY,EAAgB,MAAM,oBAAoB,CAAC;AAE7F,OAAO,KAAK,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAGlE,YAAY,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAE9C,MAAM,WAAW,YAAa,SAAQ,QAAQ,CAC5C,eAAe,EACf,YAAY,EACZ,iBAAiB,EACjB,KAAK,EACL,iBAAiB,CAClB;CAAG;AAEJ,eAAO,MAAM,YAAY,+CAEvB,CAAC;AAEH,oGAAoG;AACpG,eAAO,MAAM,OAAO,OAAQ,MAAM,SAAS,YAAY,6FACZ,CAAC;AAE5C,iGAAiG;AACjG,eAAO,MAAM,IAAI,EAAE,SAAS,CAC1B,YAAY,EACZ,QAAQ,CAAC,OAAO,EAChB,iBAAiB,EACjB,QAAQ,CAAC,eAAe,CAUzB,CAAC;AAEF,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;CAAsB,CAAC;AAE5C,eAAO,MAAM,oBAAoB,kIACkD,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `Unifi.DnsPolicy`'s `matches` AND `driftOf` (B6) — both built on the ONE field list below, the
|
|
3
|
+
* same `fieldDrift`-is-the-only-comparison shape `network-drift.ts`'s own header explains (MEDIUM-4,
|
|
4
|
+
* red team, 2026-09-26): `matches(attrs, props) === (driftOf(live, props).length === 0)` is true
|
|
5
|
+
* BY CONSTRUCTION, never two hand-kept-in-sync comparisons.
|
|
6
|
+
*
|
|
7
|
+
* ★ NO CUSTOM `equal` ANYWHERE. Every field is a scalar and `drift.ts`'s `defaultEqual`
|
|
8
|
+
* (`deepEqual` with `stripNullish: true`) already gives UniFi's `null`-for-unset-optional
|
|
9
|
+
* reality the same tolerance `network-drift.ts`/`firewall-zone-form.ts` rely on — see
|
|
10
|
+
* `dns-policy-form.ts`'s own header for why no field here needs a set/order normalizer.
|
|
11
|
+
*/
|
|
12
|
+
import type * as dnsPolicies from '@distilled.cloud/unifi-network/dns_policies';
|
|
13
|
+
import { type DnsPolicyAttributes, type DnsPolicyProps } from './dns-policy-form.ts';
|
|
14
|
+
export declare const matches: (attributes: DnsPolicyAttributes, props: DnsPolicyProps) => boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Per-field live-vs-declared drift straight from one live read — the task's own API
|
|
17
|
+
* (`driftOf(live, props)`), so `homeflare-network`'s pre-import drift check never has to derive
|
|
18
|
+
* `attributesOf` itself just to call this.
|
|
19
|
+
*/
|
|
20
|
+
export declare const driftOf: (live: dnsPolicies.DNSPolicy, props: DnsPolicyProps) => import("./drift.ts").FieldDrift[];
|
|
21
|
+
//# sourceMappingURL=dns-policy-drift.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dns-policy-drift.d.ts","sourceRoot":"","sources":["../../src/unifi/dns-policy-drift.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,KAAK,WAAW,MAAM,6CAA6C,CAAC;AAEhF,OAAO,EAAE,KAAK,mBAAmB,EAAE,KAAK,cAAc,EAAgB,MAAM,sBAAsB,CAAC;AAyBnG,eAAO,MAAM,OAAO,eAAgB,mBAAmB,SAAS,cAAc,KAAG,OACrC,CAAC;AAE7C;;;;GAIG;AACH,eAAO,MAAM,OAAO,SAAU,WAAW,CAAC,SAAS,SAAS,cAAc,sCAC5B,CAAC"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `Unifi.DnsPolicy`'s wire shape — the declarable subset of `DNSPolicy`, and how a live read
|
|
3
|
+
* becomes both plan attributes and a rendered declaration.
|
|
4
|
+
*
|
|
5
|
+
* ★ ONE FLAT DTO FOR EVERY DNS RECORD `type` (`A_RECORD`/`AAAA_RECORD`/`CNAME_RECORD`/
|
|
6
|
+
* `FORWARD_DOMAIN`/`MX_RECORD`/`SRV_RECORD`/`TXT_RECORD` — the pinned spec's `DNS policy` schema
|
|
7
|
+
* DOES discriminate on `type`, via `discriminator.mapping` to 7 variant DTOs; see
|
|
8
|
+
* `docs/unifi-dns-policy.md`'s "One flat DTO" section, corrected 2026-09-26). Unlike
|
|
9
|
+
* `access_control_acl_rules.ts`'s `sourceFilter`/`destinationFilter` or `firewall.ts`'s policy
|
|
10
|
+
* filters, NONE of `dns_policies.ts`'s fields were widened to `unknown` by the converter (T10) —
|
|
11
|
+
* `scripts/convert.ts` flattens the 7 variants into one struct instead, because no two variants
|
|
12
|
+
* collide on a field name, so every optional field still decodes as a plain scalar and there is
|
|
13
|
+
* no discriminated-variant trap here to flag or defer past this PR.
|
|
14
|
+
*
|
|
15
|
+
* ⚠️ PROPS MIRROR `UpdateDnsPolicyRequest`, NOT `DNSPolicy` — same split `network-form.ts` and
|
|
16
|
+
* `firewall-zone-form.ts` both use. `id` and `metadata` are server-derived (no writable field
|
|
17
|
+
* accepts either), so they are attributes-only, reported but never compared or declared.
|
|
18
|
+
* Everything else in `DnsPolicyProps` is exactly what `updateDnsPolicy`/`createDnsPolicy` would
|
|
19
|
+
* accept, even though this family never calls either.
|
|
20
|
+
*
|
|
21
|
+
* ⛔ NO ARRAY FIELD ANYWHERE IN THIS SHAPE. Every field below is a scalar (`string`/`number`/
|
|
22
|
+
* `boolean`), so none of `network-form.ts`'s/`firewall-zone-form.ts`'s `sortedSet` normalizing
|
|
23
|
+
* is needed — `deepEqual`'s default `stripNullish` handling (`drift.ts`) is the whole story.
|
|
24
|
+
*/
|
|
25
|
+
import type * as dnsPolicies from '@distilled.cloud/unifi-network/dns_policies';
|
|
26
|
+
/**
|
|
27
|
+
* ⚠️ EVERY OPTIONAL FIELD SPELLS OUT `| undefined` ON PURPOSE (`exactOptionalPropertyTypes` —
|
|
28
|
+
* see `network-form.ts`'s own header for why `declareDnsPolicy` below needs it: it assigns a
|
|
29
|
+
* live optional field straight through, so the target type must admit an explicit `undefined`,
|
|
30
|
+
* not just omission).
|
|
31
|
+
*/
|
|
32
|
+
export interface DnsPolicyProps {
|
|
33
|
+
siteId: string;
|
|
34
|
+
dnsPolicyId: string;
|
|
35
|
+
enabled: boolean;
|
|
36
|
+
/** DNS record type: `A_RECORD`, `AAAA_RECORD`, `CNAME_RECORD`, `FORWARD_DOMAIN`, `MX_RECORD`,
|
|
37
|
+
* `SRV_RECORD` or `TXT_RECORD` (the discriminator's own mapping keys, see the header). */
|
|
38
|
+
type: string;
|
|
39
|
+
domain?: string | undefined;
|
|
40
|
+
ipv6Address?: string | undefined;
|
|
41
|
+
/** Time to live in seconds. */
|
|
42
|
+
ttlSeconds?: number | undefined;
|
|
43
|
+
ipv4Address?: string | undefined;
|
|
44
|
+
targetDomain?: string | undefined;
|
|
45
|
+
/** IP address of the DNS Server that the DNS query is forwarded to. */
|
|
46
|
+
ipAddress?: string | undefined;
|
|
47
|
+
mailServerDomain?: string | undefined;
|
|
48
|
+
/** Priority. A lower number is preferred. */
|
|
49
|
+
priority?: number | undefined;
|
|
50
|
+
port?: number | undefined;
|
|
51
|
+
/** Protocol used by the service. */
|
|
52
|
+
protocol?: string | undefined;
|
|
53
|
+
/** Domain of the server that is running the service. */
|
|
54
|
+
serverDomain?: string | undefined;
|
|
55
|
+
/** Service associated with this SRV record. */
|
|
56
|
+
service?: string | undefined;
|
|
57
|
+
/** Weight. A relative value applicable for records with the same priority. A lower number is
|
|
58
|
+
* preferred. */
|
|
59
|
+
weight?: number | undefined;
|
|
60
|
+
/** The text value associated with this TXT DNS record. Text can contain up to four
|
|
61
|
+
* 255-character strings. Lines containing commas must be enclosed in double quotes ("). */
|
|
62
|
+
text?: string | undefined;
|
|
63
|
+
}
|
|
64
|
+
export interface DnsPolicyAttributes {
|
|
65
|
+
siteId: string;
|
|
66
|
+
dnsPolicyId: string;
|
|
67
|
+
enabled: boolean;
|
|
68
|
+
type: string;
|
|
69
|
+
domain: string | undefined;
|
|
70
|
+
ipv6Address: string | undefined;
|
|
71
|
+
ttlSeconds: number | undefined;
|
|
72
|
+
ipv4Address: string | undefined;
|
|
73
|
+
targetDomain: string | undefined;
|
|
74
|
+
ipAddress: string | undefined;
|
|
75
|
+
mailServerDomain: string | undefined;
|
|
76
|
+
priority: number | undefined;
|
|
77
|
+
port: number | undefined;
|
|
78
|
+
protocol: string | undefined;
|
|
79
|
+
serverDomain: string | undefined;
|
|
80
|
+
service: string | undefined;
|
|
81
|
+
weight: number | undefined;
|
|
82
|
+
text: string | undefined;
|
|
83
|
+
/** `metadata.origin` (e.g. `USER`) — server-derived, never declared; see
|
|
84
|
+
* `firewall-zone-form.ts`'s own `metadataOrigin` for the same split. */
|
|
85
|
+
metadataOrigin: string;
|
|
86
|
+
}
|
|
87
|
+
export declare const attributesOf: (live: dnsPolicies.DNSPolicy, props: DnsPolicyProps) => DnsPolicyAttributes;
|
|
88
|
+
/**
|
|
89
|
+
* The declaration renderer (task spec: "given one live object, return the props a declaration
|
|
90
|
+
* needs so its plan is noop"). A later import script feeds `getDnsPolicy`'s own response straight
|
|
91
|
+
* in and writes the result into `alchemy.run.ts` as `dnsPolicy('<id>', declareDnsPolicy(live,
|
|
92
|
+
* siteId))` — no field is invented or defaulted here beyond what `attributesOf` already reports,
|
|
93
|
+
* so `matches(attributesOf(live, props), declareDnsPolicy(live, siteId))` is `true` by
|
|
94
|
+
* construction (`dns-policy.test.ts` proves it) for any live object this SDK can decode.
|
|
95
|
+
*/
|
|
96
|
+
export declare const declareDnsPolicy: (live: dnsPolicies.DNSPolicy, siteId: string) => DnsPolicyProps;
|
|
97
|
+
//# sourceMappingURL=dns-policy-form.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dns-policy-form.d.ts","sourceRoot":"","sources":["../../src/unifi/dns-policy-form.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,OAAO,KAAK,KAAK,WAAW,MAAM,6CAA6C,CAAC;AAEhF;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB;+FAC2F;IAC3F,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,+BAA+B;IAC/B,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,uEAAuE;IACvE,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,oCAAoC;IACpC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,wDAAwD;IACxD,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,+CAA+C;IAC/C,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B;qBACiB;IACjB,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B;gGAC4F;IAC5F,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3B;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB;6EACyE;IACzE,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,eAAO,MAAM,YAAY,SACjB,WAAW,CAAC,SAAS,SACpB,cAAc,KACpB,mBAoBD,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,SAAU,WAAW,CAAC,SAAS,UAAU,MAAM,KAAG,cAmB7E,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `Unifi.DnsPolicy` — one DNS policy on a UniFi Network site, READ-ONLY (`policy.ts`).
|
|
3
|
+
*
|
|
4
|
+
* ★ T11 GATE, CHECKED 2026-09-26, CORRECTED SAME DAY (red team, Important finding 1): `DNS
|
|
5
|
+
* Policies` is 5 operations, `Access Control (ACL Rules)` (`acl-rule.ts`) is 7 — 12 total.
|
|
6
|
+
* Diffed the pinned 10.4.57 spec against a 10.6.97 mirror (`beezly/unifi-apis`, diffing aid
|
|
7
|
+
* only, `docs/unifi-acl-rule.md` records the sha256 + mirror commit): all 12 full operation
|
|
8
|
+
* objects (parameters, request body, responses, unresolved `$ref`s included) are byte-identical
|
|
9
|
+
* across versions. ⚠️ The schema closure is 46, not 17 — a `$ref`-only walk misses every schema
|
|
10
|
+
* reachable only via a `discriminator.mapping` (both `DNS policy` and `ACL rule` discriminate on
|
|
11
|
+
* `type`); the 46-schema closure, `$ref` + `mapping` together, shares zero names with the 14
|
|
12
|
+
* schemas that DID change between the two versions (all in `Switching`, `Filtering`, or one
|
|
13
|
+
* `UniFi Devices` enum — none of it DNS- or ACL-shaped). Same reachability method
|
|
14
|
+
* `spec-version-provenance.md` (distilled package) used for Networks/FirewallZones, extended to
|
|
15
|
+
* follow `mapping` too; full breakdown in `docs/unifi-acl-rule.md`, not repeated per family.
|
|
16
|
+
*/
|
|
17
|
+
import { Resource } from 'alchemy';
|
|
18
|
+
import * as Provider from 'alchemy/Provider';
|
|
19
|
+
import * as dnsPolicies from '@distilled.cloud/unifi-network/dns_policies';
|
|
20
|
+
import * as Effect from 'effect/Effect';
|
|
21
|
+
import { type DnsPolicyAttributes, type DnsPolicyProps } from './dns-policy-form.ts';
|
|
22
|
+
import type { UnifiRequirements, UnifiSpec } from './resource.ts';
|
|
23
|
+
export type { DnsPolicyAttributes, DnsPolicyProps } from './dns-policy-form.ts';
|
|
24
|
+
export { declareDnsPolicy } from './dns-policy-form.ts';
|
|
25
|
+
export { driftOf } from './dns-policy-drift.ts';
|
|
26
|
+
export interface UnifiDnsPolicy extends Resource<'Unifi.DnsPolicy', DnsPolicyProps, DnsPolicyAttributes, never, UnifiRequirements> {
|
|
27
|
+
}
|
|
28
|
+
export declare const UnifiDnsPolicy: import("alchemy").ResourceClass<UnifiDnsPolicy>;
|
|
29
|
+
/** `dnsPolicy('lan-forwarding', props)` — `adopt(true)` piped on by default (H5); see `network.ts`. */
|
|
30
|
+
export declare const dnsPolicy: (id: string, props: DnsPolicyProps) => Effect.Effect<UnifiDnsPolicy, never, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
31
|
+
/** ★ EXPORTED for direct testing against a fake `Credentials` layer — see `network.ts`'s own. */
|
|
32
|
+
export declare const spec: UnifiSpec<DnsPolicyProps, dnsPolicies.DNSPolicy, DnsPolicyAttributes, dnsPolicies.GetDnsPolicyError>;
|
|
33
|
+
export declare const handlers: {
|
|
34
|
+
list: () => Effect.Effect<never[], never, never>;
|
|
35
|
+
read: (args: {
|
|
36
|
+
olds: DnsPolicyProps;
|
|
37
|
+
output: DnsPolicyAttributes | undefined;
|
|
38
|
+
}) => Effect.Effect<DnsPolicyAttributes | undefined, dnsPolicies.UnifiNetworkOpError, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
39
|
+
diff: (args: {
|
|
40
|
+
news: import("alchemy").Input<DnsPolicyProps>;
|
|
41
|
+
output: DnsPolicyAttributes | undefined;
|
|
42
|
+
}) => Effect.Effect<{
|
|
43
|
+
readonly action: 'update';
|
|
44
|
+
} | {
|
|
45
|
+
readonly action: 'noop';
|
|
46
|
+
} | undefined, dnsPolicies.UnifiNetworkOpError, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
47
|
+
reconcile: (args: {
|
|
48
|
+
news: DnsPolicyProps;
|
|
49
|
+
}) => Effect.Effect<DnsPolicyAttributes, import("./policy.ts").UnifiWriteRefused | dnsPolicies.UnifiNetworkOpError, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
50
|
+
delete: (args: {
|
|
51
|
+
olds: DnsPolicyProps;
|
|
52
|
+
}) => Effect.Effect<never, import("./policy.ts").UnifiWriteRefused, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
53
|
+
};
|
|
54
|
+
export declare const UnifiDnsPolicyProvider: () => import("effect/Layer").Layer<Provider.Provider<UnifiDnsPolicy>, never, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
55
|
+
//# sourceMappingURL=dns-policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dns-policy.d.ts","sourceRoot":"","sources":["../../src/unifi/dns-policy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,WAAW,MAAM,6CAA6C,CAAC;AAC3E,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,KAAK,mBAAmB,EAAE,KAAK,cAAc,EAAgB,MAAM,sBAAsB,CAAC;AAEnG,OAAO,KAAK,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAGlE,YAAY,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAChF,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAEhD,MAAM,WAAW,cAAe,SAAQ,QAAQ,CAC9C,iBAAiB,EACjB,cAAc,EACd,mBAAmB,EACnB,KAAK,EACL,iBAAiB,CAClB;CAAG;AAEJ,eAAO,MAAM,cAAc,iDAEzB,CAAC;AAEH,uGAAuG;AACvG,eAAO,MAAM,SAAS,OAAQ,MAAM,SAAS,cAAc,+FACd,CAAC;AAE9C,iGAAiG;AACjG,eAAO,MAAM,IAAI,EAAE,SAAS,CAC1B,cAAc,EACd,WAAW,CAAC,SAAS,EACrB,mBAAmB,EACnB,WAAW,CAAC,iBAAiB,CAU9B,CAAC;AAEF,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;CAAsB,CAAC;AAE5C,eAAO,MAAM,sBAAsB,oIACoD,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `Unifi.FirewallPolicy`'s `matches` AND `driftOf` (B6) — both built on the ONE field list below,
|
|
3
|
+
* the same `fieldDrift`-is-the-only-comparison shape `network-drift.ts`'s header explains (MEDIUM-4,
|
|
4
|
+
* red team, 2026-09-26): `matches(attrs, props) === (driftOf(live, props).length === 0)` is true
|
|
5
|
+
* BY CONSTRUCTION, never two hand-kept-in-sync comparisons.
|
|
6
|
+
*
|
|
7
|
+
* ⚠️ `stripNullish: true` ON EVERY FIELD BY DEFAULT (`drift.ts`'s `defaultEqual`) — same "UniFi's
|
|
8
|
+
* JSON answers `null`, a declaration omits" tolerance every other family here relies on.
|
|
9
|
+
* ⛔ `connectionStateFilter` RUNS THROUGH `firewall-policy-form.ts`'s normalizer on BOTH sides
|
|
10
|
+
* before comparing — never applied to only `live` or only `declared` (the specific gap MEDIUM-4's
|
|
11
|
+
* own mutant found in `network-drift.ts`; see its header, and `acl-rule-drift.ts`'s own repeat of
|
|
12
|
+
* this same rule for `protocolFilter`/`enforcingDeviceFilter`).
|
|
13
|
+
* ★ `action`/`destination`/`ipProtocolScope`/`schedule`/`source` compare with the plain default
|
|
14
|
+
* `equal` (whole-value `deepEqual`) — see `firewall-policy-form.ts`'s header for the accepted
|
|
15
|
+
* known gap this leaves in their own nested set-like arrays.
|
|
16
|
+
*/
|
|
17
|
+
import type * as firewall from '@distilled.cloud/unifi-network/firewall';
|
|
18
|
+
import { type FirewallPolicyAttributes, type FirewallPolicyProps } from './firewall-policy-form.ts';
|
|
19
|
+
export declare const matches: (attributes: FirewallPolicyAttributes, props: FirewallPolicyProps) => boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Per-field live-vs-declared drift straight from one live read — the task's own API
|
|
22
|
+
* (`driftOf(live, props)`), so `homeflare-network`'s pre-import drift check never has to derive
|
|
23
|
+
* `attributesOf` itself just to call this.
|
|
24
|
+
*/
|
|
25
|
+
export declare const driftOf: (live: firewall.FirewallPolicy, props: FirewallPolicyProps) => import("./drift.ts").FieldDrift[];
|
|
26
|
+
//# sourceMappingURL=firewall-policy-drift.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"firewall-policy-drift.d.ts","sourceRoot":"","sources":["../../src/unifi/firewall-policy-drift.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,KAAK,QAAQ,MAAM,yCAAyC,CAAC;AAEzE,OAAO,EACL,KAAK,wBAAwB,EAC7B,KAAK,mBAAmB,EAGzB,MAAM,2BAA2B,CAAC;AAoBnC,eAAO,MAAM,OAAO,eACN,wBAAwB,SAC7B,mBAAmB,KACzB,OAAqD,CAAC;AAEzD;;;;GAIG;AACH,eAAO,MAAM,OAAO,SAAU,QAAQ,CAAC,cAAc,SAAS,mBAAmB,sCACnC,CAAC"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `Unifi.FirewallPolicy`'s wire shape — the declarable subset of `FirewallPolicy` (`getFirewallPolicy`'s
|
|
3
|
+
* own decode target), and how a live read becomes both plan attributes and a rendered declaration.
|
|
4
|
+
* Rule ORDER is a separate resource (`firewall-policy-ordering.ts`, T5) — this file is one policy's
|
|
5
|
+
* own fields only.
|
|
6
|
+
*
|
|
7
|
+
* ★ `source`/`destination`/`ipProtocolScope`/`action`/`schedule` STAY COMPOUND, COMPARED WHOLESALE —
|
|
8
|
+
* post-A3 (`8ee11f1`, "type FirewallPolicy/ACL/TrafficMatchingList filters per discriminator"),
|
|
9
|
+
* these decode as real per-discriminator TS unions instead of `unknown`
|
|
10
|
+
* (`discriminated-filter-decode.test.ts` proves the wire path keeps every key, including one this
|
|
11
|
+
* pinned spec doesn't yet declare), so this file is honest about their real shape rather than
|
|
12
|
+
* casting to `unknown` the way `acl-rule-form.ts` still does for its own opaque filters. It does
|
|
13
|
+
* NOT follow that up with a leaf-by-leaf declarable schema for all 12 filter variants, though:
|
|
14
|
+
* that is new modelling work this PR does not attempt, so each field is compared with plain
|
|
15
|
+
* `deepEqual` (`stripNullish`) as ONE value, same proportion `acl-rule-form.ts`'s
|
|
16
|
+
* `enforcingDeviceFilter` gets (one level of structure, not exploded into scalars).
|
|
17
|
+
*
|
|
18
|
+
* ⚠️ KNOWN GAP (T15, same shape as `acl-rule-form.ts`'s own — accepted, not fixed, here either):
|
|
19
|
+
* several of the vendor's filter variants nested inside `source`/`destination`/`ipProtocolScope`
|
|
20
|
+
* are themselves SET-LIKE arrays with no documented order —
|
|
21
|
+
* `FirewallPolicyMACAddressFilter.macAddresses`, `FirewallPolicyNetworkFilter.networkIds`,
|
|
22
|
+
* `FirewallPolicyApplicationFilter.applicationIds`, `FirewallPolicyIPAddressFilter.items`,
|
|
23
|
+
* `FirewallPolicyRegionFilter.regions`, `FirewallPolicyVPNServerFilter.vpnServerIds`,
|
|
24
|
+
* `FirewallSchedule.repeatOnDays` — `deepEqual` compares every one of them order-sensitively, so a
|
|
25
|
+
* console-side reorder with no membership change would report a spurious drift this read-only
|
|
26
|
+
* family's `reconcile` then refuses forever. Not fixed here for the same reason ACL's own gap
|
|
27
|
+
* isn't: normalizing 12 filter variants' own nested arrays is a bigger, separate change, not a
|
|
28
|
+
* proportional extension of typing per-discriminator (A3) into set-aware comparison too.
|
|
29
|
+
*
|
|
30
|
+
* ⛔ `connectionStateFilter` IS THE ONE TOP-LEVEL PROPS ARRAY, AND IS A SET — "Match on firewall
|
|
31
|
+
* connection state. If null, matches all connection states" describes membership, not a sequence
|
|
32
|
+
* (unlike `firewall-policy-ordering-form.ts`'s own `beforeSystemDefined`/`afterSystemDefined`,
|
|
33
|
+
* where position IS the value). Normalized with the same `sortedSet` every other family in this
|
|
34
|
+
* directory uses for a set-shaped array (`firewall-zone-form.ts`'s `networkIds`,
|
|
35
|
+
* `acl-rule-form.ts`'s `protocolFilter`).
|
|
36
|
+
*
|
|
37
|
+
* ⛔ `index` IS ATTRIBUTES-ONLY, NEVER DECLARED. `CreateFirewallPolicyRequest` has no `index`
|
|
38
|
+
* field at all — the live object's current position among ALL policies on the site is reported,
|
|
39
|
+
* but a policy's PRIORITY relative to its own zone pair is `firewall-policy-ordering.ts`'s concern
|
|
40
|
+
* (`OrderedFirewallPolicyIDs`), same split `acl-rule-form.ts`'s own `index` documents.
|
|
41
|
+
*
|
|
42
|
+
* ⛔ `metadata.origin` IS ATTRIBUTES-ONLY, same split every other family here uses
|
|
43
|
+
* (`firewall-zone-form.ts`'s `metadataOrigin`) — `UserOrSystemDefinedOrDerivedEntityMetadata` is
|
|
44
|
+
* server-derived, no writable field accepts it.
|
|
45
|
+
*/
|
|
46
|
+
import type * as firewall from '@distilled.cloud/unifi-network/firewall';
|
|
47
|
+
/** ★ EXPORTED so `firewall-policy-drift.ts` normalizes both live and declared sides identically —
|
|
48
|
+
* see `acl-rule-form.ts`'s own header for why a normalizer applied to only one side is a bug
|
|
49
|
+
* class (MEDIUM-4). */
|
|
50
|
+
export declare const normalizeConnectionStateFilter: (value: readonly string[] | undefined) => string[] | undefined;
|
|
51
|
+
/** ⚠️ EVERY OPTIONAL FIELD SPELLS OUT `| undefined` — `exactOptionalPropertyTypes`; see
|
|
52
|
+
* `network-form.ts`'s own header. */
|
|
53
|
+
export interface FirewallPolicyProps {
|
|
54
|
+
siteId: string;
|
|
55
|
+
firewallPolicyId: string;
|
|
56
|
+
action: firewall.FirewallPolicyAction;
|
|
57
|
+
/** Connection states this policy matches — compared as a SET, see the header. */
|
|
58
|
+
connectionStateFilter?: string[] | undefined;
|
|
59
|
+
description?: string | undefined;
|
|
60
|
+
/** Traffic destination — compound, compared wholesale; see the header's known gap. */
|
|
61
|
+
destination: firewall.FirewallPolicyDestination;
|
|
62
|
+
enabled: boolean;
|
|
63
|
+
/** IP version + protocol scope — compound, compared wholesale; see the header's known gap. */
|
|
64
|
+
ipProtocolScope: firewall.FirewallPolicyIPProtocolScope;
|
|
65
|
+
ipsecFilter?: string | undefined;
|
|
66
|
+
loggingEnabled: boolean;
|
|
67
|
+
name: string;
|
|
68
|
+
/** Schedule this policy is active on — compound, compared wholesale; see the header's known gap. */
|
|
69
|
+
schedule?: firewall.FirewallSchedule | undefined;
|
|
70
|
+
/** Traffic source — compound, compared wholesale; see the header's known gap. */
|
|
71
|
+
source: firewall.FirewallPolicySource;
|
|
72
|
+
}
|
|
73
|
+
export interface FirewallPolicyAttributes {
|
|
74
|
+
siteId: string;
|
|
75
|
+
firewallPolicyId: string;
|
|
76
|
+
action: firewall.FirewallPolicyAction;
|
|
77
|
+
connectionStateFilter: string[] | undefined;
|
|
78
|
+
description: string | undefined;
|
|
79
|
+
destination: firewall.FirewallPolicyDestination;
|
|
80
|
+
enabled: boolean;
|
|
81
|
+
/** Current position among ALL policies on the site — server-derived, never declared; see header. */
|
|
82
|
+
index: number;
|
|
83
|
+
ipProtocolScope: firewall.FirewallPolicyIPProtocolScope;
|
|
84
|
+
ipsecFilter: string | undefined;
|
|
85
|
+
loggingEnabled: boolean;
|
|
86
|
+
name: string;
|
|
87
|
+
schedule: firewall.FirewallSchedule | undefined;
|
|
88
|
+
source: firewall.FirewallPolicySource;
|
|
89
|
+
/** `metadata.origin` — server-derived, never declared; see `firewall-zone-form.ts`'s own. */
|
|
90
|
+
metadataOrigin: string;
|
|
91
|
+
}
|
|
92
|
+
export declare const attributesOf: (live: firewall.FirewallPolicy, props: FirewallPolicyProps) => FirewallPolicyAttributes;
|
|
93
|
+
/**
|
|
94
|
+
* The declaration renderer (task spec: "given one live object, return the props a declaration
|
|
95
|
+
* needs so its plan is noop"). A later import script feeds `getFirewallPolicy`'s own response
|
|
96
|
+
* straight in and writes the result as `firewallPolicy('<id>', declareFirewallPolicy(live, siteId))`
|
|
97
|
+
* — no field is invented or defaulted beyond what `attributesOf` already reports, so
|
|
98
|
+
* `matches(attributesOf(live, props), declareFirewallPolicy(live, siteId))` is `true` by
|
|
99
|
+
* construction (`firewall-policy.test.ts` proves it).
|
|
100
|
+
*/
|
|
101
|
+
export declare const declareFirewallPolicy: (live: firewall.FirewallPolicy, siteId: string) => FirewallPolicyProps;
|
|
102
|
+
//# sourceMappingURL=firewall-policy-form.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"firewall-policy-form.d.ts","sourceRoot":"","sources":["../../src/unifi/firewall-policy-form.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,OAAO,KAAK,KAAK,QAAQ,MAAM,yCAAyC,CAAC;AAIzE;;wBAEwB;AACxB,eAAO,MAAM,8BAA8B,UAClC,SAAS,MAAM,EAAE,GAAG,SAAS,KACnC,MAAM,EAAE,GAAG,SAA2D,CAAC;AAE1E;sCACsC;AACtC,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,QAAQ,CAAC,oBAAoB,CAAC;IACtC,iFAAiF;IACjF,qBAAqB,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC7C,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,sFAAsF;IACtF,WAAW,EAAE,QAAQ,CAAC,yBAAyB,CAAC;IAChD,OAAO,EAAE,OAAO,CAAC;IACjB,8FAA8F;IAC9F,eAAe,EAAE,QAAQ,CAAC,6BAA6B,CAAC;IACxD,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,cAAc,EAAE,OAAO,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,oGAAoG;IACpG,QAAQ,CAAC,EAAE,QAAQ,CAAC,gBAAgB,GAAG,SAAS,CAAC;IACjD,iFAAiF;IACjF,MAAM,EAAE,QAAQ,CAAC,oBAAoB,CAAC;CACvC;AAED,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,QAAQ,CAAC,oBAAoB,CAAC;IACtC,qBAAqB,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC5C,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,WAAW,EAAE,QAAQ,CAAC,yBAAyB,CAAC;IAChD,OAAO,EAAE,OAAO,CAAC;IACjB,oGAAoG;IACpG,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,EAAE,QAAQ,CAAC,6BAA6B,CAAC;IACxD,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,cAAc,EAAE,OAAO,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,QAAQ,CAAC,gBAAgB,GAAG,SAAS,CAAC;IAChD,MAAM,EAAE,QAAQ,CAAC,oBAAoB,CAAC;IACtC,6FAA6F;IAC7F,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,eAAO,MAAM,YAAY,SACjB,QAAQ,CAAC,cAAc,SACtB,mBAAmB,KACzB,wBAgBD,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,SAC1B,QAAQ,CAAC,cAAc,UACrB,MAAM,KACb,mBAcD,CAAC"}
|