@takodotid/circuit 0.43.0 → 1.0.0-rc.1

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 (257) hide show
  1. package/README.md +115 -37
  2. package/package.json +21 -58
  3. package/src/checks/across.ts +402 -0
  4. package/src/checks/built-in.ts +256 -0
  5. package/src/checks/device.ts +436 -0
  6. package/src/checks/index.ts +53 -0
  7. package/src/cli/advisories.ts +108 -0
  8. package/src/cli/app.ts +67 -0
  9. package/src/cli/editor-types.generated.ts +30 -0
  10. package/src/cli/editor-types.ts +69 -0
  11. package/src/cli/format.ts +124 -0
  12. package/src/cli/git-hooks.ts +79 -0
  13. package/src/cli/index.ts +348 -1170
  14. package/src/cli/migrate.ts +554 -0
  15. package/src/cli/project-commands.ts +656 -0
  16. package/src/cli/releases.ts +374 -0
  17. package/src/cli/remember.ts +339 -0
  18. package/src/cli/rename.ts +27 -33
  19. package/src/cli/secrets-password.ts +60 -0
  20. package/src/cli/secrets.ts +258 -0
  21. package/src/cli/setup.ts +300 -0
  22. package/src/cli/signing.ts +23 -0
  23. package/src/cli/text-editor.ts +268 -0
  24. package/src/cli/ui.ts +298 -0
  25. package/src/cli/version.ts +2 -0
  26. package/src/cli/versions.ts +158 -0
  27. package/src/config/address.ts +102 -0
  28. package/src/config/circuit.d.ts +30 -0
  29. package/src/config/common.ts +65 -0
  30. package/src/config/communities.ts +479 -0
  31. package/src/config/define.ts +684 -0
  32. package/src/config/device.ts +164 -0
  33. package/src/config/firewall.ts +150 -0
  34. package/src/config/index.ts +22 -0
  35. package/src/{schema → config}/interfaces.ts +121 -85
  36. package/src/config/keys.ts +434 -0
  37. package/src/config/management.ts +61 -0
  38. package/src/config/merge.ts +335 -0
  39. package/src/config/models.ts +70 -0
  40. package/src/config/monitoring.ts +64 -0
  41. package/src/config/network.ts +180 -0
  42. package/src/config/presets.ts +149 -0
  43. package/src/config/routing.ts +401 -0
  44. package/src/config/services.ts +51 -0
  45. package/src/config/switching.ts +84 -0
  46. package/src/config/system.ts +103 -0
  47. package/src/{schema → config}/time-zones.ts +1 -1
  48. package/src/core/address.ts +1 -1
  49. package/src/core/cabling.ts +8 -43
  50. package/src/core/graph.ts +40 -0
  51. package/src/{integrations → core}/registries.ts +5 -3
  52. package/src/core/secrets-file.ts +539 -0
  53. package/src/core/secrets.ts +83 -64
  54. package/src/core/topology.ts +103 -146
  55. package/src/core/utils.ts +12 -1
  56. package/src/model.ts +83 -0
  57. package/src/platforms/derive.ts +64 -37
  58. package/src/platforms/finding.ts +9 -0
  59. package/src/platforms/fortios/firewall.ts +76 -64
  60. package/src/platforms/fortios/index.ts +189 -125
  61. package/src/platforms/fortios/names.ts +51 -18
  62. package/src/platforms/fortios/plan.ts +132 -44
  63. package/src/platforms/fortios/render.ts +69 -62
  64. package/src/platforms/fortios/routing.ts +89 -58
  65. package/src/platforms/fortios/vdoms.ts +47 -16
  66. package/src/platforms/junos/TRAPS.md +2 -2
  67. package/src/platforms/junos/bgp.ts +63 -42
  68. package/src/platforms/junos/index.ts +122 -89
  69. package/src/platforms/junos/render.ts +139 -104
  70. package/src/platforms/platform.ts +10 -8
  71. package/src/platforms/raisecom-ros/TRAPS.md +1 -1
  72. package/src/platforms/raisecom-ros/index.ts +89 -70
  73. package/src/platforms/raisecom-ros/render.ts +49 -45
  74. package/src/platforms/routeros/TRAPS.md +3 -3
  75. package/src/platforms/routeros/index.ts +121 -60
  76. package/src/platforms/routeros/render.ts +214 -195
  77. package/src/platforms/vrp/TRAPS.md +1 -1
  78. package/src/platforms/vrp/index.ts +74 -50
  79. package/src/platforms/vrp/render.ts +67 -56
  80. package/src/project/project.ts +725 -0
  81. package/src/studio/app/env.d.ts +9 -0
  82. package/src/studio/app/index.html +18 -0
  83. package/src/studio/app/src/App.vue +95 -0
  84. package/src/studio/app/src/components/AddressesView.vue +38 -0
  85. package/src/studio/app/src/components/CablesView.vue +29 -0
  86. package/src/studio/app/src/components/CompareView.vue +160 -0
  87. package/src/studio/app/src/components/DataTable.vue +49 -0
  88. package/src/studio/app/src/components/DeviceView.vue +237 -0
  89. package/src/studio/app/src/components/DevicesView.vue +32 -0
  90. package/src/studio/app/src/components/Faceplate.vue +75 -0
  91. package/src/studio/app/src/components/GraphView.vue +282 -0
  92. package/src/studio/app/src/components/LineDiff.vue +24 -0
  93. package/src/studio/app/src/components/ProblemsView.vue +42 -0
  94. package/src/studio/app/src/components/SearchView.vue +72 -0
  95. package/src/studio/app/src/components/SecretsView.vue +112 -0
  96. package/src/studio/app/src/components/SessionsView.vue +35 -0
  97. package/src/studio/app/src/components/Settings.vue +95 -0
  98. package/src/studio/app/src/components/ToolsView.vue +118 -0
  99. package/src/studio/app/src/components/VlansView.vue +50 -0
  100. package/src/studio/app/src/lib/csv.ts +19 -0
  101. package/src/studio/{public/diff.js → app/src/lib/diff.ts} +40 -35
  102. package/src/studio/app/src/lib/format.ts +38 -0
  103. package/src/studio/app/src/lib/net.ts +68 -0
  104. package/src/studio/app/src/lib/secrets-crypto.ts +35 -0
  105. package/src/studio/app/src/lib/store.ts +71 -0
  106. package/src/studio/app/src/lib/tools.ts +217 -0
  107. package/src/studio/app/src/main.ts +9 -0
  108. package/src/studio/{public → app/src}/style.css +14 -4
  109. package/src/studio/app/tsconfig.json +17 -0
  110. package/src/studio/app/vite.config.ts +16 -0
  111. package/src/studio/assets.generated.ts +3 -0
  112. package/src/studio/data.ts +96 -188
  113. package/src/studio/git.ts +27 -43
  114. package/src/studio/server.ts +196 -107
  115. package/src/studio/types.ts +141 -0
  116. package/src/transport/console.ts +3 -3
  117. package/src/transport/ssh.ts +1 -1
  118. package/dist/chunks/index-3b343xva.js +0 -177
  119. package/dist/chunks/index-6wb41q67.js +0 -62
  120. package/dist/chunks/index-n7w3tg5y.js +0 -149
  121. package/dist/chunks/index-yzw86rc8.js +0 -921
  122. package/dist/chunks/new-w3zys5y4.js +0 -172
  123. package/dist/chunks/server-cxr9ynxc.js +0 -259
  124. package/dist/cli/index.js +0 -12872
  125. package/dist/helpers/index.js +0 -881
  126. package/dist/index.js +0 -28
  127. package/dist/types/core/address-space.d.ts +0 -62
  128. package/dist/types/core/address.d.ts +0 -44
  129. package/dist/types/core/cabling.d.ts +0 -41
  130. package/dist/types/core/cross-checks.d.ts +0 -28
  131. package/dist/types/core/define.d.ts +0 -79
  132. package/dist/types/core/project-files.d.ts +0 -12
  133. package/dist/types/core/schema-docs.d.ts +0 -25
  134. package/dist/types/core/secrets.d.ts +0 -62
  135. package/dist/types/core/topology.d.ts +0 -96
  136. package/dist/types/core/utils.d.ts +0 -10
  137. package/dist/types/core/validator.d.ts +0 -23
  138. package/dist/types/helpers/bgp.d.ts +0 -195
  139. package/dist/types/helpers/cables.d.ts +0 -69
  140. package/dist/types/helpers/checks.d.ts +0 -36
  141. package/dist/types/helpers/exchange.d.ts +0 -55
  142. package/dist/types/helpers/filters.d.ts +0 -51
  143. package/dist/types/helpers/index.d.ts +0 -14
  144. package/dist/types/helpers/route-server.d.ts +0 -52
  145. package/dist/types/helpers/upstreams.d.ts +0 -192
  146. package/dist/types/index.d.ts +0 -10
  147. package/dist/types/integrations/librenms.d.ts +0 -60
  148. package/dist/types/integrations/netbox.d.ts +0 -89
  149. package/dist/types/integrations/peeringdb.d.ts +0 -24
  150. package/dist/types/integrations/prometheus.d.ts +0 -24
  151. package/dist/types/integrations/registries.d.ts +0 -8
  152. package/dist/types/platforms/bgp-wait.d.ts +0 -24
  153. package/dist/types/platforms/catalog.d.ts +0 -109
  154. package/dist/types/platforms/derive.d.ts +0 -17
  155. package/dist/types/platforms/fortios/firewall.d.ts +0 -47
  156. package/dist/types/platforms/fortios/index.d.ts +0 -140
  157. package/dist/types/platforms/fortios/models.d.ts +0 -14
  158. package/dist/types/platforms/fortios/names.d.ts +0 -52
  159. package/dist/types/platforms/fortios/plan.d.ts +0 -104
  160. package/dist/types/platforms/fortios/render.d.ts +0 -77
  161. package/dist/types/platforms/fortios/routing.d.ts +0 -56
  162. package/dist/types/platforms/fortios/tree.d.ts +0 -37
  163. package/dist/types/platforms/fortios/vdoms.d.ts +0 -50
  164. package/dist/types/platforms/index.d.ts +0 -13
  165. package/dist/types/platforms/junos/bgp.d.ts +0 -44
  166. package/dist/types/platforms/junos/index.d.ts +0 -114
  167. package/dist/types/platforms/junos/models.d.ts +0 -14
  168. package/dist/types/platforms/junos/render.d.ts +0 -154
  169. package/dist/types/platforms/line-diff.d.ts +0 -67
  170. package/dist/types/platforms/platform.d.ts +0 -135
  171. package/dist/types/platforms/raisecom-ros/index.d.ts +0 -71
  172. package/dist/types/platforms/raisecom-ros/models.d.ts +0 -14
  173. package/dist/types/platforms/raisecom-ros/render.d.ts +0 -41
  174. package/dist/types/platforms/routeros/export.d.ts +0 -59
  175. package/dist/types/platforms/routeros/index.d.ts +0 -116
  176. package/dist/types/platforms/routeros/models.d.ts +0 -18
  177. package/dist/types/platforms/routeros/plan.d.ts +0 -58
  178. package/dist/types/platforms/routeros/render.d.ts +0 -250
  179. package/dist/types/platforms/vrp/index.d.ts +0 -83
  180. package/dist/types/platforms/vrp/models.d.ts +0 -12
  181. package/dist/types/platforms/vrp/render.d.ts +0 -96
  182. package/dist/types/schema/common.d.ts +0 -30
  183. package/dist/types/schema/device.d.ts +0 -126
  184. package/dist/types/schema/firewall.d.ts +0 -131
  185. package/dist/types/schema/index.d.ts +0 -8
  186. package/dist/types/schema/interfaces.d.ts +0 -205
  187. package/dist/types/schema/policy.d.ts +0 -107
  188. package/dist/types/schema/routing.d.ts +0 -161
  189. package/dist/types/schema/system.d.ts +0 -198
  190. package/dist/types/schema/time-zones.d.ts +0 -2
  191. package/dist/types/transport/console.d.ts +0 -115
  192. package/dist/types/transport/path-check.d.ts +0 -32
  193. package/dist/types/transport/ssh.d.ts +0 -27
  194. package/src/cli/graph-format.ts +0 -91
  195. package/src/cli/new.ts +0 -234
  196. package/src/core/address-space.ts +0 -320
  197. package/src/core/cross-checks.ts +0 -369
  198. package/src/core/define.ts +0 -124
  199. package/src/core/project-files.ts +0 -35
  200. package/src/core/schema-docs.ts +0 -174
  201. package/src/core/validator.ts +0 -508
  202. package/src/helpers/bgp.ts +0 -473
  203. package/src/helpers/cables.ts +0 -74
  204. package/src/helpers/checks.ts +0 -201
  205. package/src/helpers/exchange.ts +0 -123
  206. package/src/helpers/filters.ts +0 -107
  207. package/src/helpers/index.ts +0 -25
  208. package/src/helpers/route-server.ts +0 -212
  209. package/src/helpers/upstreams.ts +0 -369
  210. package/src/index.ts +0 -13
  211. package/src/integrations/librenms.ts +0 -291
  212. package/src/integrations/netbox.ts +0 -620
  213. package/src/integrations/peeringdb.ts +0 -173
  214. package/src/integrations/prometheus.ts +0 -90
  215. package/src/schema/common.ts +0 -41
  216. package/src/schema/device.ts +0 -145
  217. package/src/schema/firewall.ts +0 -140
  218. package/src/schema/index.ts +0 -8
  219. package/src/schema/policy.ts +0 -115
  220. package/src/schema/routing.ts +0 -173
  221. package/src/schema/system.ts +0 -203
  222. package/src/studio/public/app.js +0 -186
  223. package/src/studio/public/compare.js +0 -250
  224. package/src/studio/public/dom.js +0 -138
  225. package/src/studio/public/evaluate.js +0 -687
  226. package/src/studio/public/export.js +0 -130
  227. package/src/studio/public/graph.js +0 -1541
  228. package/src/studio/public/index.html +0 -83
  229. package/src/studio/public/net.js +0 -134
  230. package/src/studio/public/tables.js +0 -1289
  231. package/src/studio/public/tools.js +0 -610
  232. package/templates/colocation/checks.ts +0 -53
  233. package/templates/colocation/circuit.config.ts +0 -9
  234. package/templates/colocation/edge-01.ts +0 -133
  235. package/templates/colocation/routing.ts +0 -13
  236. package/templates/colocation/tenancy.ts +0 -76
  237. package/templates/colocation/tenants/acme.ts +0 -19
  238. package/templates/colocation/tenants/index.ts +0 -6
  239. package/templates/colocation/tor-01.ts +0 -33
  240. package/templates/edge-router/checks.ts +0 -20
  241. package/templates/edge-router/circuit.config.ts +0 -8
  242. package/templates/edge-router/edge-01.ts +0 -110
  243. package/templates/edge-router/routing.ts +0 -13
  244. package/templates/project/AGENTS.md +0 -51
  245. package/templates/project/CLAUDE.md +0 -1
  246. package/templates/project/README.md +0 -16
  247. package/templates/project/gitignore +0 -5
  248. package/templates/project/tsconfig.json +0 -13
  249. package/templates/single-site/checks.ts +0 -26
  250. package/templates/single-site/circuit.config.ts +0 -8
  251. package/templates/single-site/router.ts +0 -86
  252. package/templates/single-site/site.ts +0 -18
  253. package/templates/single-site/switch.ts +0 -34
  254. /package/src/studio/{public → app/public}/favicon.svg +0 -0
  255. /package/src/studio/{public → app/public}/special-gothic-latin-ext.woff2 +0 -0
  256. /package/src/studio/{public → app/public}/special-gothic-latin.woff2 +0 -0
  257. /package/src/studio/{public → app/public}/special-gothic-license.txt +0 -0
@@ -0,0 +1,84 @@
1
+ // Layer 2 shared by ports: `switching.vlans`, `.stp`, `.lldp`, `.acls`.
2
+
3
+ import type { Family, Named, OneOrMore, Ordered, Prefix, Rate } from "./common";
4
+ import type { Ports, Protocol } from "./firewall";
5
+
6
+ /**
7
+ * A VLAN. Its key in `switching.vlans` is its name. `Untrusted` is whether the network turns on the check `untrusted_vlans`, which
8
+ * `untrusted` needs.
9
+ */
10
+ export type Vlan<Untrusted extends boolean = true> = {
11
+ /** The VLAN's number on the wire, 1 to 4094. Two VLANs on a device never share one. */
12
+ id: number;
13
+ /** What the VLAN is for. Dropped on a platform where a VLAN is only its number (Raisecom, FortiOS), so a device takes a VLAN whole wherever it runs. */
14
+ description?: string;
15
+ /**
16
+ * The VLAN carries traffic straight from outside: a transit, an exchange, an ISP handoff, or such a one's native VLAN. Only Circuit
17
+ * reads it, for the check `untrusted_vlans`; the device never sees it. Write it on every device that declares the VLAN. Allowed only
18
+ * when the network's `circuit()` turns on `untrusted_vlans`: an error in the editor, and `circuit validate` stops.
19
+ */
20
+ untrusted?: Untrusted extends true ? true : "allowed only when circuit.ts turns on the check untrusted_vlans";
21
+ };
22
+
23
+ /**
24
+ * Which packets an ACL rule applies to. All must be true.
25
+ *
26
+ * `vlan`, `src` and `dst` each take a list. Where the platform has no list, Circuit writes one rule per combination: the VLAN
27
+ * outermost, then `src`, then `dst`.
28
+ */
29
+ export type AclMatch<V extends string> = {
30
+ /** Only packets of this family. */
31
+ family?: Family;
32
+ /** IP protocol. */
33
+ protocol?: Protocol;
34
+ /** Source prefix, or any of several. */
35
+ src?: OneOrMore<Prefix>;
36
+ /** Destination prefix, or any of several. */
37
+ dst?: OneOrMore<Prefix>;
38
+ /** Source port, or any of several. */
39
+ src_port?: Ports;
40
+ /** Destination port, or any of several. */
41
+ dst_port?: Ports;
42
+ /** One of `switching.vlans`, or any of several: only packets in this VLAN. */
43
+ vlan?: OneOrMore<V>;
44
+ };
45
+
46
+ /**
47
+ * A stateless rule evaluated in hardware where traffic arrives, before routing, the condition first:
48
+ * `{ if: { vlan: "ix", src: "10.0.0.0/8" }, then: "drop" }`. No `if`: every packet.
49
+ */
50
+ export type AclRule<V extends string> = {
51
+ /** Shown beside the rule on the device. */
52
+ description?: string;
53
+ /** Which packets the rule applies to. Every packet when absent. */
54
+ if?: AclMatch<V>;
55
+ /** What happens to a matching packet. */
56
+ then: "accept" | "drop";
57
+ /** Accepted traffic above this rate is dropped. On RouterOS it did not limit traffic the CPU routes; see its TRAPS.md. */
58
+ rate?: Rate;
59
+ };
60
+
61
+ /** Spanning tree on every switched port. A port may override it. */
62
+ export type Stp = {
63
+ /** Which variant runs. RSTP when absent. */
64
+ mode?: "stp" | "rstp" | "mstp";
65
+ /** Bridge priority, 0 to 61440 in steps of 4096. Lower wins the root election. */
66
+ priority?: number;
67
+ };
68
+
69
+ /** Layer 2 that the ports share. `V` is the device's VLAN names, `A` its ACL names, `I` its ports and interfaces. `Untrusted` is whether the network turns on `untrusted_vlans`. */
70
+ export type Switching<V extends string, A extends string, I extends string, Untrusted extends boolean = true> = {
71
+ /** VLANs, keyed by name. A port, a LAG or a VLAN interface names one of these. */
72
+ vlans?: Named<V, Vlan<Untrusted>>;
73
+ /** Spanning tree on every switched port. A port may override it. */
74
+ stp?: Stp;
75
+ /** Advertise and learn neighbors with LLDP on every port (`true`), or only on the interfaces listed. A port may override it. */
76
+ lldp?:
77
+ | true
78
+ | {
79
+ /** Some of the device's ports and interfaces. */
80
+ interfaces: readonly I[];
81
+ };
82
+ /** Hardware ACLs, keyed by name, applied to a port with `ingress_acl`. Each is rules in order, written whole in one place: the first runs first. */
83
+ acls?: Named<A, Ordered<AclRule<NoInfer<V>>>>;
84
+ };
@@ -0,0 +1,103 @@
1
+ // The box itself: `system.timezone`, `.banner`, `.release_channel`, `.ip_stack`, `.alarms`, `.dns`, `.ntp`, `.logging`, `.hardware_offload`, `.users`, `.certificates`, `.vdoms`.
2
+
3
+ import type { IP, Named, Secret, Severity } from "./common";
4
+ import type { StaticRoute } from "./routing";
5
+ import type { TimeZone } from "./time-zones";
6
+
7
+ /** A software release track, as RouterOS names them. `long-term` changes least; `development` is the newest and least tested. */
8
+ export type ReleaseChannel = "long-term" | "stable" | "testing" | "development";
9
+
10
+ /** How bad an alarm is, most severe first, as ITU-T X.733 ranks them. */
11
+ export type AlarmSeverity = "critical" | "major" | "minor" | "warning";
12
+
13
+ /** A login on the device. */
14
+ export type User = {
15
+ /** What the user may do. */
16
+ role: "admin" | "operator" | "read-only";
17
+ /** The login password. */
18
+ password: Secret;
19
+ /** Who the account is for. */
20
+ description?: string;
21
+ /** Public keys accepted instead of the password over SSH. */
22
+ ssh_keys?: readonly string[];
23
+ };
24
+
25
+ /** A certificate the device presents or trusts. */
26
+ export type Certificate = {
27
+ /** The certificate, a PEM file (`.pem` or `.crt`): a path from the project root. Public, so it is kept in the repository. */
28
+ certificate_file: string;
29
+ /** Its private key: a PEM file through `secretFile`, or PEM base64-encoded as one line through `secret`. A certificate the device only trusts, such as a CA, has none. */
30
+ private_key?: Secret;
31
+ };
32
+
33
+ /**
34
+ * Virtual domains, on FortiOS: the device's own traffic kept apart from the traffic it routes. Everything is in `root` when absent.
35
+ *
36
+ * Multi-VDOM mode is turned on by hand, not by a plan: it moves the whole configuration into `root` and ends every session.
37
+ */
38
+ export type Vdoms<I extends string> = {
39
+ /** A VDOM for the device's own traffic: FortiGuard, NTP, DNS and logging leave from it, by its own routes, so they never follow the routed traffic's default route. Everything not listed here stays in `root`. */
40
+ management: {
41
+ /** Its name, such as `mgmt`. Not `root`. */
42
+ name: string;
43
+ /** Some of the device's ports and interfaces: the ones in it. A LAG's member ports go with the LAG. */
44
+ interfaces: readonly I[];
45
+ /** Its static routes, such as its own default route. */
46
+ static_routes?: readonly StaticRoute<I, never, never>[];
47
+ };
48
+ };
49
+
50
+ /** Device-wide settings: the box itself. `U` is the device's user names, `C` its certificate names, `I` its ports and interfaces. */
51
+ export type System<U extends string, C extends string, I extends string> = {
52
+ /** IANA zone, for example `Asia/Jakarta`. The editor suggests every name. UTC when absent. */
53
+ timezone?: TimeZone;
54
+ /** Shown at login. */
55
+ banner?: string;
56
+ /** Software release track the device updates from. `stable` when absent. */
57
+ release_channel?: ReleaseChannel;
58
+ /** Host behaviour of the IP stack. */
59
+ ip_stack?: {
60
+ /** Send ICMP redirects. Off when absent. */
61
+ icmp_redirects?: boolean;
62
+ /** Answer a TCP SYN flood with SYN cookies. Off when absent. */
63
+ syn_cookies?: boolean;
64
+ };
65
+ /** Alarms raised at another severity than the platform's own, keyed by the alarm's name as the platform spells it, such as `hwOpticalUnAuthorized` on VRP. */
66
+ alarms?: Record<
67
+ string,
68
+ {
69
+ /** The severity it is raised at. */
70
+ severity: AlarmSeverity;
71
+ }
72
+ >;
73
+ /** Resolvers the device uses. Answering others is `services.dns_server`. */
74
+ dns?: {
75
+ /** Resolvers, in order of preference. */
76
+ servers: readonly IP[];
77
+ };
78
+ /** How the device keeps time. Answering others is `services.ntp_server`. */
79
+ ntp?: {
80
+ /** Time sources, by address (alone or with its length) or name, in order of preference. */
81
+ servers: readonly string[];
82
+ };
83
+ /** Log messages kept on the device itself. Sending them to collectors is `monitoring.syslog`. */
84
+ logging?: {
85
+ /** Kept on the device's own storage, from `level` up. */
86
+ local?: {
87
+ /** The least severe message kept. */
88
+ level: Severity;
89
+ /** How many rotated files to keep. */
90
+ files?: number;
91
+ /** Lines in each file before it rotates. */
92
+ lines_per_file?: number;
93
+ };
94
+ };
95
+ /** Forward in hardware where the platform can. An interface may override it. */
96
+ hardware_offload?: boolean;
97
+ /** Logins, keyed by user name. Users not listed are removed. */
98
+ users?: Named<U, User>;
99
+ /** Certificates the device presents or trusts, keyed by name. `management.https` and `management.api_tls` name one. */
100
+ certificates?: Named<C, Certificate>;
101
+ /** Virtual domains, on FortiOS only: a management VDOM apart from the routed traffic. */
102
+ vdoms?: Vdoms<I>;
103
+ };
@@ -1,4 +1,4 @@
1
- // Generated by `bun scripts/time-zones.ts` from the time zones the runtime knows. Do not edit by hand: run the script again to update it.
1
+ // Every IANA time zone name Circuit knows, copied from Circuit 0.43 (`src/schema/time-zones.ts`, generated from the runtime).
2
2
 
3
3
  /** An IANA time zone name, such as `Asia/Jakarta`, or `UTC`. */
4
4
  export type TimeZone =
@@ -1,6 +1,6 @@
1
1
  // Address arithmetic for both families. Addresses are parsed to bigint so v4 and v6 share one code path.
2
2
 
3
- import type { Family, IP, IPv4, IPv6, Prefix } from "../schema";
3
+ import type { Family, IP, IPv4, IPv6, Prefix } from "../model";
4
4
 
5
5
  /** Address helpers, for checks of your own. */
6
6
  export class Address {
@@ -1,10 +1,8 @@
1
- // The cabling as LLDP sees it, compared with what `link` says. `snapshot` saves each device's LLDP neighbors beside its config; `validate` warns where they disagree.
1
+ // The cabling as LLDP sees it, compared with what `link` says. `diff` and `apply` read a device's LLDP neighbors while they are connected, and warn where they disagree.
2
2
 
3
- import { existsSync, readFileSync, rmSync, writeFileSync } from "node:fs";
4
- import { join } from "node:path";
5
3
  import { Catalog } from "../platforms/catalog";
6
- import type { Device } from "../schema";
7
- import type { Finding } from "./define";
4
+ import type { Device } from "../model";
5
+ import type { Finding } from "../platforms/finding";
8
6
 
9
7
  /** A device one of our ports sees at the far end of its cable, over LLDP. */
10
8
  export type Neighbor = {
@@ -17,50 +15,17 @@ export type Neighbor = {
17
15
  };
18
16
 
19
17
  export class Cabling {
20
- /** The end of a state file that holds a device's LLDP neighbors, beside its config. */
21
- static readonly SUFFIX = ".lldp.json";
22
-
23
- /** The file a device's neighbors are saved in. */
24
- static path(stateDirectory: string, device: string): string {
25
- return join(stateDirectory, device + Cabling.SUFFIX);
26
- }
27
-
28
- /** Save what a device sees, sorted, so a file changes only when a neighbor does. */
29
- static save(stateDirectory: string, device: string, neighbors: readonly Neighbor[]): void {
30
- const sorted = [...neighbors].sort((a, b) => Cabling.order(a).localeCompare(Cabling.order(b)));
31
- const tidy = sorted.map(({ port, system, remote_port }) => ({ port, system, remote_port }));
32
-
33
- writeFileSync(Cabling.path(stateDirectory, device), JSON.stringify(tidy, null, 4) + "\n");
34
- }
35
-
36
- /** Forget what a device saw, when its neighbors could not be read this time. */
37
- static forget(stateDirectory: string, device: string): void {
38
- rmSync(Cabling.path(stateDirectory, device), { force: true });
39
- }
40
-
41
- /** What a device saw at its last snapshot, or undefined when its neighbors were never read. */
42
- static load(stateDirectory: string, device: string): Neighbor[] | undefined {
43
- const path = Cabling.path(stateDirectory, device);
44
- if (!existsSync(path)) return undefined;
45
-
46
- return JSON.parse(readFileSync(path, "utf8")) as Neighbor[];
47
- }
48
-
49
- private static order(neighbor: Neighbor): string {
50
- return `${neighbor.port} ${neighbor.system} ${neighbor.remote_port}`;
51
- }
52
-
53
18
  /** The device runs LLDP somewhere: on every port, on the interfaces it lists, or on a port that turns it on. */
54
19
  static runsAnywhere(device: Device): boolean {
55
- return Boolean(device.lldp) || Object.values(device.ports ?? {}).some((port) => port?.lldp === true);
20
+ return Boolean(device.switching?.lldp) || Object.values(device.interfaces?.ethernet ?? {}).some((port) => port?.lldp === true);
56
21
  }
57
22
 
58
23
  /** The port runs LLDP, by the port's own `lldp`, or else the device's. */
59
24
  static runsOn(device: Device, port: string): boolean {
60
- const own = device.ports?.[port as keyof typeof device.ports]?.lldp;
25
+ const own = device.interfaces?.ethernet?.[port]?.lldp;
61
26
  if (own !== undefined) return own;
62
27
 
63
- const lldp = device.lldp;
28
+ const lldp = device.switching?.lldp;
64
29
  return lldp === true || (typeof lldp === "object" && (lldp.interfaces as readonly string[]).includes(port));
65
30
  }
66
31
 
@@ -77,14 +42,14 @@ export class Cabling {
77
42
  if (!seen) continue;
78
43
 
79
44
  const warn = (message: string) => findings.push({ level: "warning", device: device.name, message });
80
- const linked = Object.entries(device.ports ?? {}).filter(([, port]) => port?.link);
45
+ const linked = Object.entries(device.interfaces?.ethernet ?? {}).filter(([, port]) => port?.link);
81
46
  const ports = new Set([...linked.map(([name]) => name), ...seen.map((neighbor) => neighbor.port)]);
82
47
 
83
48
  for (const port of ports) {
84
49
  if (!Cabling.runsOn(device, port)) continue;
85
50
 
86
51
  const here = seen.filter((neighbor) => neighbor.port === port);
87
- const link = device.ports?.[port as keyof typeof device.ports]?.link;
52
+ const link = device.interfaces?.ethernet?.[port]?.link;
88
53
 
89
54
  if (!link) {
90
55
  for (const neighbor of here) {
@@ -0,0 +1,40 @@
1
+ // The network as a graph: the shapes `Topology` draws, without its code, so Studio's page can share them.
2
+
3
+ /** One view of the network. Every edge belongs to one. */
4
+ export type Layer = "l1" | "l2" | "l3" | "bgp" | "ospf" | "tunnels";
5
+
6
+ /** One of our devices, a segment several of them share, or something outside the network. */
7
+ export type GraphNode = {
8
+ /** Unique among the nodes, such as `device:edge-01` or `as:64501`. */
9
+ id: string;
10
+ kind: "device" | "segment" | "outside";
11
+ /** A word or two, drawn on the node. */
12
+ label: string;
13
+ /** One fact per line, for a closer look. */
14
+ detail: string[];
15
+ };
16
+
17
+ /** A VLAN a cable carries. */
18
+ export type CarriedVlan = {
19
+ name: string;
20
+ id: number;
21
+ /** Carried without a tag: the access VLAN, or a trunk's native VLAN. */
22
+ untagged: boolean;
23
+ };
24
+
25
+ export type GraphEdge = {
26
+ layer: Layer;
27
+ /** Node ids. */
28
+ from: string;
29
+ to: string;
30
+ /** A few words, drawn on the edge. */
31
+ label: string;
32
+ /** One fact per line, for a closer look. */
33
+ detail: string[];
34
+ /** Only one end declares it: the far device does not declare the cable, session or tunnel back. */
35
+ oneSided?: true;
36
+ /** On `l2`, the VLANs the cable carries. */
37
+ vlans?: CarriedVlan[];
38
+ };
39
+
40
+ export type Graph = { nodes: GraphNode[]; edges: GraphEdge[] };
@@ -1,7 +1,9 @@
1
- // Registries the framework reads prefix sets from. PeeringDB, which it publishes to, is in ./peeringdb.ts.
1
+ // Registries Circuit reads prefix sets from.
2
2
 
3
- import type { Family } from "../schema";
4
- import type { Registry } from "../schema/policy";
3
+ import type { Family } from "../model";
4
+
5
+ /** A registry Circuit fetches prefixes from. */
6
+ export type Registry = "ripe-stat";
5
7
 
6
8
  export class Registries {
7
9
  /** The prefixes of one family a registry gives for a query. */