@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.
Files changed (279) hide show
  1. package/README.md +10 -8
  2. package/dist/caddy/index.js.map +2 -2
  3. package/dist/ceph/auth-entity.d.ts +34 -0
  4. package/dist/ceph/auth-entity.d.ts.map +1 -0
  5. package/dist/ceph/ceph-argv-config.d.ts +10 -0
  6. package/dist/ceph/ceph-argv-config.d.ts.map +1 -0
  7. package/dist/ceph/ceph-argv.d.ts +19 -0
  8. package/dist/ceph/ceph-argv.d.ts.map +1 -0
  9. package/dist/ceph/ceph-auth-form.d.ts +54 -0
  10. package/dist/ceph/ceph-auth-form.d.ts.map +1 -0
  11. package/dist/ceph/ceph-auth-parse.d.ts +56 -0
  12. package/dist/ceph/ceph-auth-parse.d.ts.map +1 -0
  13. package/dist/ceph/ceph-auth-reconcile.d.ts +35 -0
  14. package/dist/ceph/ceph-auth-reconcile.d.ts.map +1 -0
  15. package/dist/ceph/ceph-config-options.d.ts +23 -0
  16. package/dist/ceph/ceph-config-options.d.ts.map +1 -0
  17. package/dist/ceph/ceph-key-leak-assert.d.ts +25 -0
  18. package/dist/ceph/ceph-key-leak-assert.d.ts.map +1 -0
  19. package/dist/ceph/ceph-transport.d.ts +37 -0
  20. package/dist/ceph/ceph-transport.d.ts.map +1 -0
  21. package/dist/ceph/fake-ceph-dial.d.ts +35 -0
  22. package/dist/ceph/fake-ceph-dial.d.ts.map +1 -0
  23. package/dist/ceph/index.d.ts +13 -0
  24. package/dist/ceph/index.d.ts.map +1 -0
  25. package/dist/ceph/index.js +1610 -0
  26. package/dist/ceph/index.js.map +38 -0
  27. package/dist/index.d.ts +1 -0
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/launchd/fake-runner.d.ts.map +1 -1
  30. package/dist/launchd/index.d.ts +1 -1
  31. package/dist/launchd/index.d.ts.map +1 -1
  32. package/dist/launchd/index.js +7 -1
  33. package/dist/launchd/index.js.map +5 -5
  34. package/dist/launchd/local-runner.d.ts.map +1 -1
  35. package/dist/launchd/runner.d.ts +21 -0
  36. package/dist/launchd/runner.d.ts.map +1 -1
  37. package/dist/launchd/sudo-runner.d.ts.map +1 -1
  38. package/dist/linux/directory-lifecycle.d.ts.map +1 -1
  39. package/dist/linux/fake-linux-host.d.ts.map +1 -1
  40. package/dist/linux/index.d.ts +1 -1
  41. package/dist/linux/index.d.ts.map +1 -1
  42. package/dist/linux/index.js +16 -4
  43. package/dist/linux/index.js.map +7 -7
  44. package/dist/linux/ssh-runner.d.ts.map +1 -1
  45. package/dist/linux/sudo-runner.d.ts.map +1 -1
  46. package/dist/opnsense/alias-form.d.ts +14 -1
  47. package/dist/opnsense/alias-form.d.ts.map +1 -1
  48. package/dist/opnsense/alias.d.ts +1 -1
  49. package/dist/opnsense/alias.d.ts.map +1 -1
  50. package/dist/opnsense/group-form.d.ts +8 -2
  51. package/dist/opnsense/group-form.d.ts.map +1 -1
  52. package/dist/opnsense/group.d.ts +1 -1
  53. package/dist/opnsense/group.d.ts.map +1 -1
  54. package/dist/opnsense/index.js +15 -7
  55. package/dist/opnsense/index.js.map +7 -7
  56. package/dist/opnsense/wire.d.ts +42 -12
  57. package/dist/opnsense/wire.d.ts.map +1 -1
  58. package/dist/proxmox/index.js +62 -39
  59. package/dist/proxmox/index.js.map +8 -7
  60. package/dist/proxmox/qemu-volume.d.ts +12 -2
  61. package/dist/proxmox/qemu-volume.d.ts.map +1 -1
  62. package/dist/proxmox/storage-form.d.ts +28 -3
  63. package/dist/proxmox/storage-form.d.ts.map +1 -1
  64. package/dist/proxmox/storage-plugin-options.d.ts +2 -0
  65. package/dist/proxmox/storage-plugin-options.d.ts.map +1 -0
  66. package/dist/proxmox/storage-wire.d.ts +28 -1
  67. package/dist/proxmox/storage-wire.d.ts.map +1 -1
  68. package/dist/proxmox/storage.d.ts +6 -1
  69. package/dist/proxmox/storage.d.ts.map +1 -1
  70. package/dist/release/index.d.ts +1 -1
  71. package/dist/release/index.d.ts.map +1 -1
  72. package/dist/release/index.js.map +2 -2
  73. package/dist/talos/credentials-write.d.ts +46 -0
  74. package/dist/talos/credentials-write.d.ts.map +1 -0
  75. package/dist/talos/credentials.d.ts +51 -9
  76. package/dist/talos/credentials.d.ts.map +1 -1
  77. package/dist/talos/fake-process.d.ts +56 -0
  78. package/dist/talos/fake-process.d.ts.map +1 -0
  79. package/dist/talos/index.d.ts +19 -4
  80. package/dist/talos/index.d.ts.map +1 -1
  81. package/dist/talos/index.js +357 -173
  82. package/dist/talos/index.js.map +16 -10
  83. package/dist/talos/kubeconfig-attrs.d.ts +4 -0
  84. package/dist/talos/kubeconfig-attrs.d.ts.map +1 -0
  85. package/dist/talos/kubeconfig.d.ts +41 -23
  86. package/dist/talos/kubeconfig.d.ts.map +1 -1
  87. package/dist/talos/machine-config-fixtures.d.ts +60 -0
  88. package/dist/talos/machine-config-fixtures.d.ts.map +1 -0
  89. package/dist/talos/machine-config-poll.d.ts +43 -0
  90. package/dist/talos/machine-config-poll.d.ts.map +1 -0
  91. package/dist/talos/machine-config-read.d.ts +49 -0
  92. package/dist/talos/machine-config-read.d.ts.map +1 -0
  93. package/dist/talos/resource.d.ts +18 -0
  94. package/dist/talos/resource.d.ts.map +1 -1
  95. package/dist/talos/talos-bootstrap-etcd.d.ts +38 -0
  96. package/dist/talos/talos-bootstrap-etcd.d.ts.map +1 -0
  97. package/dist/talos/talos-bootstrap.d.ts +87 -0
  98. package/dist/talos/talos-bootstrap.d.ts.map +1 -1
  99. package/dist/talos/talos-cluster-health.d.ts +43 -1
  100. package/dist/talos/talos-cluster-health.d.ts.map +1 -1
  101. package/dist/talos/talos-errors.d.ts +68 -0
  102. package/dist/talos/talos-errors.d.ts.map +1 -0
  103. package/dist/talos/talos-machine-config.d.ts +51 -15
  104. package/dist/talos/talos-machine-config.d.ts.map +1 -1
  105. package/dist/talos/talosctl.d.ts +7 -0
  106. package/dist/talos/talosctl.d.ts.map +1 -1
  107. package/dist/talos/values.d.ts +23 -3
  108. package/dist/talos/values.d.ts.map +1 -1
  109. package/dist/unifi/acl-rule-drift.d.ts +22 -0
  110. package/dist/unifi/acl-rule-drift.d.ts.map +1 -0
  111. package/dist/unifi/acl-rule-form.d.ts +90 -0
  112. package/dist/unifi/acl-rule-form.d.ts.map +1 -0
  113. package/dist/unifi/acl-rule-ordering-form.d.ts +49 -0
  114. package/dist/unifi/acl-rule-ordering-form.d.ts.map +1 -0
  115. package/dist/unifi/acl-rule-ordering.d.ts +54 -0
  116. package/dist/unifi/acl-rule-ordering.d.ts.map +1 -0
  117. package/dist/unifi/acl-rule.d.ts +49 -0
  118. package/dist/unifi/acl-rule.d.ts.map +1 -0
  119. package/dist/unifi/dns-policy-drift.d.ts +21 -0
  120. package/dist/unifi/dns-policy-drift.d.ts.map +1 -0
  121. package/dist/unifi/dns-policy-form.d.ts +97 -0
  122. package/dist/unifi/dns-policy-form.d.ts.map +1 -0
  123. package/dist/unifi/dns-policy.d.ts +55 -0
  124. package/dist/unifi/dns-policy.d.ts.map +1 -0
  125. package/dist/unifi/firewall-policy-drift.d.ts +26 -0
  126. package/dist/unifi/firewall-policy-drift.d.ts.map +1 -0
  127. package/dist/unifi/firewall-policy-form.d.ts +102 -0
  128. package/dist/unifi/firewall-policy-form.d.ts.map +1 -0
  129. package/dist/unifi/firewall-policy-ordering-form.d.ts +66 -0
  130. package/dist/unifi/firewall-policy-ordering-form.d.ts.map +1 -0
  131. package/dist/unifi/firewall-policy-ordering.d.ts +57 -0
  132. package/dist/unifi/firewall-policy-ordering.d.ts.map +1 -0
  133. package/dist/unifi/firewall-policy.d.ts +57 -0
  134. package/dist/unifi/firewall-policy.d.ts.map +1 -0
  135. package/dist/unifi/index.d.ts +7 -0
  136. package/dist/unifi/index.d.ts.map +1 -1
  137. package/dist/unifi/index.js +588 -3
  138. package/dist/unifi/index.js.map +24 -4
  139. package/dist/unifi/paginate.d.ts +0 -12
  140. package/dist/unifi/paginate.d.ts.map +1 -1
  141. package/dist/unifi/providers.d.ts +1 -1
  142. package/dist/unifi/providers.d.ts.map +1 -1
  143. package/dist/unifi/scan-source.d.ts +11 -0
  144. package/dist/unifi/scan-source.d.ts.map +1 -0
  145. package/dist/unifi/traffic-matching-list-drift.d.ts +22 -0
  146. package/dist/unifi/traffic-matching-list-drift.d.ts.map +1 -0
  147. package/dist/unifi/traffic-matching-list-form.d.ts +56 -0
  148. package/dist/unifi/traffic-matching-list-form.d.ts.map +1 -0
  149. package/dist/unifi/traffic-matching-list.d.ts +51 -0
  150. package/dist/unifi/traffic-matching-list.d.ts.map +1 -0
  151. package/dist/unifi/wifi-broadcast-drift.d.ts +22 -0
  152. package/dist/unifi/wifi-broadcast-drift.d.ts.map +1 -0
  153. package/dist/unifi/wifi-broadcast-form.d.ts +127 -0
  154. package/dist/unifi/wifi-broadcast-form.d.ts.map +1 -0
  155. package/dist/unifi/wifi-broadcast.d.ts +73 -0
  156. package/dist/unifi/wifi-broadcast.d.ts.map +1 -0
  157. package/docs/distilled-interim.md +7 -0
  158. package/docs/launchd.md +5 -3
  159. package/docs/provider-standard.md +5 -1
  160. package/docs/talos-argocd-dogfood.md +160 -0
  161. package/docs/unifi-acl-rule.md +122 -0
  162. package/docs/unifi-dns-policy.md +75 -0
  163. package/docs/unifi-firewall-policy.md +109 -0
  164. package/docs/unifi-traffic-matching-list.md +82 -0
  165. package/docs/unifi-wifi.md +120 -0
  166. package/docs/unifi.md +10 -5
  167. package/package.json +7 -3
  168. package/src/ceph/auth-entity.ts +74 -0
  169. package/src/ceph/ceph-argv-config.ts +78 -0
  170. package/src/ceph/ceph-argv.test.ts +226 -0
  171. package/src/ceph/ceph-argv.ts +189 -0
  172. package/src/ceph/ceph-auth-form.test.ts +103 -0
  173. package/src/ceph/ceph-auth-form.ts +107 -0
  174. package/src/ceph/ceph-auth-parse.test.ts +155 -0
  175. package/src/ceph/ceph-auth-parse.ts +121 -0
  176. package/src/ceph/ceph-auth-reconcile-secrecy.test.ts +82 -0
  177. package/src/ceph/ceph-auth-reconcile.test.ts +233 -0
  178. package/src/ceph/ceph-auth-reconcile.ts +119 -0
  179. package/src/ceph/ceph-config-options.test.ts +44 -0
  180. package/src/ceph/ceph-config-options.ts +36 -0
  181. package/src/ceph/ceph-key-leak-assert.ts +35 -0
  182. package/src/ceph/ceph-no-output-logging.test.ts +52 -0
  183. package/src/ceph/ceph-transport.test.ts +125 -0
  184. package/src/ceph/ceph-transport.ts +117 -0
  185. package/src/ceph/fake-ceph-dial.ts +55 -0
  186. package/src/ceph/index.ts +12 -0
  187. package/src/index.ts +1 -0
  188. package/src/launchd/fake-runner.ts +2 -0
  189. package/src/launchd/index.ts +8 -1
  190. package/src/launchd/local-runner.ts +16 -1
  191. package/src/launchd/runner.ts +22 -0
  192. package/src/launchd/sudo-runner.ts +3 -0
  193. package/src/linux/directory-lifecycle.ts +18 -3
  194. package/src/linux/directory-sudo.test.ts +59 -0
  195. package/src/linux/directory.test.ts +34 -8
  196. package/src/linux/fake-linux-host.ts +2 -0
  197. package/src/linux/index.ts +1 -0
  198. package/src/linux/ssh-runner.ts +4 -0
  199. package/src/linux/sudo-runner.ts +3 -0
  200. package/src/opnsense/alias-form.test.ts +24 -12
  201. package/src/opnsense/alias-form.ts +20 -7
  202. package/src/opnsense/alias.test.ts +13 -6
  203. package/src/opnsense/alias.ts +16 -10
  204. package/src/opnsense/group-form.test.ts +12 -8
  205. package/src/opnsense/group-form.ts +13 -4
  206. package/src/opnsense/group.test.ts +18 -7
  207. package/src/opnsense/group.ts +10 -3
  208. package/src/opnsense/wire.ts +57 -12
  209. package/src/proxmox/qemu-volume.test.ts +153 -4
  210. package/src/proxmox/qemu-volume.ts +71 -14
  211. package/src/proxmox/storage-form.ts +48 -8
  212. package/src/proxmox/storage-plugin-options.ts +45 -0
  213. package/src/proxmox/storage-update.test.ts +183 -0
  214. package/src/proxmox/storage-wire.ts +54 -7
  215. package/src/proxmox/storage.ts +18 -6
  216. package/src/release/index.ts +1 -0
  217. package/src/talos/credentials-write.test.ts +81 -0
  218. package/src/talos/credentials-write.ts +95 -0
  219. package/src/talos/credentials.test.ts +157 -0
  220. package/src/talos/credentials.ts +160 -90
  221. package/src/talos/fake-process.ts +94 -0
  222. package/src/talos/index.ts +39 -4
  223. package/src/talos/kubeconfig-attrs.ts +55 -0
  224. package/src/talos/kubeconfig.test.ts +256 -0
  225. package/src/talos/kubeconfig.ts +170 -90
  226. package/src/talos/machine-config-fixtures.ts +86 -0
  227. package/src/talos/machine-config-poll.test.ts +57 -0
  228. package/src/talos/machine-config-poll.ts +82 -0
  229. package/src/talos/machine-config-read.ts +118 -0
  230. package/src/talos/resource.ts +19 -0
  231. package/src/talos/secrets-gate.test.ts +63 -0
  232. package/src/talos/talos-bootstrap-etcd.ts +71 -0
  233. package/src/talos/talos-bootstrap.test.ts +218 -0
  234. package/src/talos/talos-bootstrap.ts +151 -45
  235. package/src/talos/talos-cluster-health.test.ts +143 -0
  236. package/src/talos/talos-cluster-health.ts +91 -28
  237. package/src/talos/talos-errors.ts +85 -0
  238. package/src/talos/talos-machine-config.test.ts +189 -0
  239. package/src/talos/talos-machine-config.ts +102 -88
  240. package/src/talos/talosctl.ts +8 -0
  241. package/src/talos/values.test.ts +34 -6
  242. package/src/talos/values.ts +41 -7
  243. package/src/unifi/acl-rule-drift.ts +57 -0
  244. package/src/unifi/acl-rule-form.ts +135 -0
  245. package/src/unifi/acl-rule-ordering-form.ts +79 -0
  246. package/src/unifi/acl-rule-ordering.test.ts +141 -0
  247. package/src/unifi/acl-rule-ordering.ts +70 -0
  248. package/src/unifi/acl-rule.test.ts +183 -0
  249. package/src/unifi/acl-rule.ts +61 -0
  250. package/src/unifi/discriminated-filter-decode.test.ts +134 -0
  251. package/src/unifi/dns-policy-drift.ts +48 -0
  252. package/src/unifi/dns-policy-form.ts +142 -0
  253. package/src/unifi/dns-policy.test.ts +154 -0
  254. package/src/unifi/dns-policy.ts +67 -0
  255. package/src/unifi/firewall-policy-drift.test.ts +151 -0
  256. package/src/unifi/firewall-policy-drift.ts +55 -0
  257. package/src/unifi/firewall-policy-filter-roundtrip.test.ts +143 -0
  258. package/src/unifi/firewall-policy-form.ts +146 -0
  259. package/src/unifi/firewall-policy-ordering-form.ts +111 -0
  260. package/src/unifi/firewall-policy-ordering.test.ts +185 -0
  261. package/src/unifi/firewall-policy-ordering.ts +87 -0
  262. package/src/unifi/firewall-policy.test.ts +183 -0
  263. package/src/unifi/firewall-policy.ts +73 -0
  264. package/src/unifi/index.ts +63 -0
  265. package/src/unifi/paginate.test.ts +24 -0
  266. package/src/unifi/paginate.ts +15 -3
  267. package/src/unifi/providers.ts +19 -1
  268. package/src/unifi/scan-source.ts +64 -0
  269. package/src/unifi/traffic-matching-list-drift.ts +40 -0
  270. package/src/unifi/traffic-matching-list-form.ts +77 -0
  271. package/src/unifi/traffic-matching-list.test.ts +202 -0
  272. package/src/unifi/traffic-matching-list.ts +78 -0
  273. package/src/unifi/wifi-broadcast-details-call.test.ts +92 -0
  274. package/src/unifi/wifi-broadcast-drift.ts +69 -0
  275. package/src/unifi/wifi-broadcast-form.ts +211 -0
  276. package/src/unifi/wifi-broadcast-secrets.test.ts +145 -0
  277. package/src/unifi/wifi-broadcast.test.ts +155 -0
  278. package/src/unifi/wifi-broadcast.ts +90 -0
  279. 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"}