@takodotid/circuit 0.23.0 → 0.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,9 +10,9 @@ Documentation: [circuit.tako.id](https://circuit.tako.id)
10
10
  ## What it does
11
11
 
12
12
  - **One file per device.** VLANs, ports, addresses, routing, firewall, users and services, written in TypeScript. Your editor checks every name you refer to as you type.
13
- - **The same words for every vendor.** MikroTik RouterOS 7, Huawei VRP and Raisecom ROS each get their own commands. What a device cannot do is an error before anything is sent.
13
+ - **The same words for every vendor.** MikroTik RouterOS 7, Huawei VRP, Raisecom ROS and Juniper Junos each get their own commands. What a device cannot do is an error before anything is sent.
14
14
  - **The file is the whole truth.** A port, user or service the file does not mention is removed or turned off, so nothing set by hand lingers.
15
- - **See every change first.** `diff` shows it offline, `apply` plans it against the live device, and nothing is sent without `--confirm`. On RouterOS, a change undoes itself if Circuit cannot log in again afterwards.
15
+ - **See every change first.** `diff` shows it offline, `apply` plans it against the live device, and nothing is sent without `--confirm`. On RouterOS and Junos, a change undoes itself if Circuit cannot log in again afterwards.
16
16
  - **History in git.** Each device's last snapshot is kept in `.circuit/state/`, so the repository's history is the network's history.
17
17
  - **Rules of your own.** Checks run on every change, and presets give ready-made filters, BGP policies and checks.
18
18
  - **Secrets stay out of the repository.** They come from `.env` or 1Password, and never appear in a plan or a snapshot.
@@ -25,6 +25,15 @@ Documentation: [circuit.tako.id](https://circuit.tako.id)
25
25
  <img src="docs/public/screenshots/studio-light.png" alt="Studio's VLAN graph with devices that differ from their snapshots marked by orange dashed borders, beside the layer details and legend.">
26
26
  </picture>
27
27
 
28
+ ## Circuit Academy
29
+
30
+ New to networking? [Circuit Academy](https://circuit.tako.id/academy/) teaches it from the very start, in lessons you try in the browser rather than only read: packets, addresses, switches and routers first, then VLANs, DHCP, NAT and firewalls written down in Circuit, up to BGP and an edge router of your own. A certification is coming.
31
+
32
+ <picture>
33
+ <source media="(prefers-color-scheme: dark)" srcset="docs/public/screenshots/academy-dark.png">
34
+ <img src="docs/public/screenshots/academy-light.png" alt="A Circuit Academy lesson on switches: a frame from a laptop to a printer has just been flooded out of every port, and the switch has learned which port the laptop is behind.">
35
+ </picture>
36
+
28
37
  ## Start
29
38
 
30
39
  You need [Node.js](https://nodejs.org) 20.12 or newer, or [Bun](https://bun.sh). Then:
@@ -35,7 +44,7 @@ npx @takodotid/circuit new # or: pnpm dlx @takodotid/circuit new, bunx @t
35
44
 
36
45
  It asks which kind of network you have, creates a project with example devices, and installs Circuit. [Getting started](https://circuit.tako.id/guide/getting-started) walks through the first run.
37
46
 
38
- Circuit supports MikroTik RouterOS 7, Huawei VRP and Raisecom ROS. Releases are on the [releases page](https://github.com/takodotid/circuit/releases), on npm and on GitHub Packages.
47
+ Circuit supports MikroTik RouterOS 7, Huawei VRP, Raisecom ROS and Juniper Junos. Releases are on the [releases page](https://github.com/takodotid/circuit/releases), on npm and on GitHub Packages.
39
48
 
40
49
  ## Working on Circuit
41
50
 
@@ -12,8 +12,16 @@ import {
12
12
  host2
13
13
  } from "./index-v8zgr7wm.js";
14
14
 
15
- // src/adapters/devices/raisecom-ros/models.ts
15
+ // src/adapters/devices/junos/models.ts
16
16
  var models = {
17
+ "QFX5100-48S-6Q": {
18
+ ports: { "40g": 6, "10g": 48, "1g": 2 },
19
+ spelling: { "40g": "et-0/0/{n+47}", "10g": "xe-0/0/{n-1}", "1g": "em{n-1}" }
20
+ }
21
+ };
22
+
23
+ // src/adapters/devices/raisecom-ros/models.ts
24
+ var models2 = {
17
25
  "RAX721-C-6C48": {
18
26
  ports: { "100g": 6, "25g": 24, "10g": 24 },
19
27
  spelling: { "100g": "hundredgige 1/1/{n}", "25g": "twenty-fivegige 1/2/{n}", "10g": "tengigabitethernet 1/3/{n}" }
@@ -21,7 +29,7 @@ var models = {
21
29
  };
22
30
 
23
31
  // src/adapters/devices/routeros/models.ts
24
- var models2 = {
32
+ var models3 = {
25
33
  "CCR2216-1G-12XS-2XQ": {
26
34
  ports: { "100g": 2, "25g": 12, "1g": 1 },
27
35
  spelling: { "100g": "qsfp28-{n}-1", "25g": "sfp28-{n}", "1g": "ether{n}" }
@@ -29,12 +37,12 @@ var models2 = {
29
37
  };
30
38
 
31
39
  // src/adapters/devices/vrp/models.ts
32
- var models3 = {
40
+ var models4 = {
33
41
  "CE6855-48S6Q-HI": { ports: { "10g": 48, "40g": 6 }, spelling: { "10g": "10GE1/0/{n}", "40g": "40GE1/0/{n}" } }
34
42
  };
35
43
 
36
44
  // src/adapters/devices/catalog.ts
37
- var catalog = { routeros: models2, vrp: models3, "raisecom-ros": models };
45
+ var catalog = { routeros: models3, vrp: models4, "raisecom-ros": models2, junos: models };
38
46
  function portsOf(platform, model) {
39
47
  const spec = catalog[platform]?.[model];
40
48
  if (!spec)
@@ -47,7 +55,7 @@ function spell(platform, model, port) {
47
55
  const template = parts && spec?.spelling[parts[1]];
48
56
  if (!template)
49
57
  throw new Error(`${model} has no port ${port}`);
50
- return template.replace("{n}", parts[2]);
58
+ return template.replace(/\{n([+-]\d+)?\}/, (_, shift) => String(Number(parts[2]) + Number(shift ?? 0)));
51
59
  }
52
60
 
53
61
  // src/core/graph.ts
@@ -92,7 +100,7 @@ function holdersOf(devices) {
92
100
  if (!isCidr2(address))
93
101
  return [];
94
102
  const peer = typeof entry === "string" ? undefined : entry.peer;
95
- return [{ device, name, address, peer, vrrp: settings.vrrp ?? [] }];
103
+ return [{ device, name, address, peer, vrrp: settings.vrrp ?? [], vrf: settings.vrf }];
96
104
  })));
97
105
  }
98
106
  function describeDevice(device) {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  packageRoot
3
- } from "./index-n4zpd25n.js";
3
+ } from "./index-wm9ypkjq.js";
4
4
 
5
5
  // src/studio/server.ts
6
6
  import { execFile as execFile2, spawn } from "node:child_process";