{"_id":"@adviser/ovn-fabric","_rev":"8-dead0e9adc0a14aaa426bbb1ae15263b","name":"@adviser/ovn-fabric","dist-tags":{"latest":"0.2.1"},"versions":{"0.1.0":{"name":"@adviser/ovn-fabric","version":"0.1.0","keywords":["ovn","ovs","sdn","networking","topology","deno","cli"],"license":"Apache-2.0","_id":"@adviser/ovn-fabric@0.1.0","maintainers":[{"name":"fastandfearless","email":"meno.abels@gmail.com"}],"homepage":"https://github.com/mabels/ovn-fabric#readme","bugs":{"url":"https://github.com/mabels/ovn-fabric/issues"},"bin":{"ovn-fabric":"bin/ovn-fabric.js"},"dist":{"shasum":"467b786eb12af5bc61cf6ec6b24d5f07254d39b9","tarball":"https://registry.npmjs.org/@adviser/ovn-fabric/-/ovn-fabric-0.1.0.tgz","fileCount":11,"integrity":"sha512-jGofeMPluEVkIO24qggtrRcioA/oRv8Zu5FhZyeD0w2KktVoBNCazGSHdPw6jN+v2+ciz+AzRklCN95Dio4eZw==","signatures":[{"sig":"MEUCIQCfW1IDWshqG1ctSv20USL9ffG2GTqZkcMxI++yvbVicwIgOwsD7chWBN7uF9vtY4L1I7PwcRqp1Tqc3RTjD6kEbuY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":134615},"_npmUser":{"name":"fastandfearless","email":"meno.abels@gmail.com"},"repository":{"url":"git+https://github.com/mabels/ovn-fabric.git","type":"git"},"description":"Declarative OVN/OVS topology generator — one config, one self-installing shell script per host.","directories":{},"_nodeVersion":"22.22.2","dependencies":{"deno":"^2.9.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/ovn-fabric_0.1.0_1783346460127_0.1401801326023926","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@adviser/ovn-fabric","version":"0.1.1","keywords":["ovn","ovs","sdn","networking","topology","deno","cli"],"license":"Apache-2.0","_id":"@adviser/ovn-fabric@0.1.1","maintainers":[{"name":"fastandfearless","email":"meno.abels@gmail.com"}],"homepage":"https://github.com/mabels/ovn-fabric#readme","bugs":{"url":"https://github.com/mabels/ovn-fabric/issues"},"bin":{"ovn-fabric":"bin/ovn-fabric.js"},"dist":{"shasum":"a15839f7c23119cad2c012451408c2fbe0f0b96a","tarball":"https://registry.npmjs.org/@adviser/ovn-fabric/-/ovn-fabric-0.1.1.tgz","fileCount":11,"integrity":"sha512-Ubog2CJQiVlKI7CfFrzJ2TNeCqu2UlVPfI1MZL7qqFF74x4E8qfiNb8+jeUr3jrpYIKk2eLHA4NARTWzmMckAQ==","signatures":[{"sig":"MEQCIBgTEJp/UVR8ReevP2eR/uBoJQ7dJdigRAmI9W/+M4bPAiA4zty7kHqjtbX8eev0siX9bbTS4TSuZldPtZu17Nmm4g==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@adviser%2fovn-fabric@0.1.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":134753},"gitHead":"5132fd36ebb3db203677d5be61fc4a1e81f3ec09","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:a158b603-932d-4653-8088-bd86e495c583"}},"repository":{"url":"git+https://github.com/mabels/ovn-fabric.git","type":"git"},"_npmVersion":"11.18.0","description":"Declarative OVN/OVS topology generator — one config, one self-installing shell script per host.","directories":{},"_nodeVersion":"22.23.1","dependencies":{"deno":"^2.9.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/ovn-fabric_0.1.1_1783347264621_0.07318836333805034","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@adviser/ovn-fabric","version":"0.1.2","keywords":["ovn","ovs","sdn","networking","topology","deno","cli"],"license":"Apache-2.0","_id":"@adviser/ovn-fabric@0.1.2","maintainers":[{"name":"fastandfearless","email":"meno.abels@gmail.com"}],"homepage":"https://github.com/mabels/ovn-fabric#readme","bugs":{"url":"https://github.com/mabels/ovn-fabric/issues"},"bin":{"ovn-fabric":"bin/ovn-fabric.js"},"dist":{"shasum":"8f7c671d9df657d0a44e7c0c7aa5684db02ec179","tarball":"https://registry.npmjs.org/@adviser/ovn-fabric/-/ovn-fabric-0.1.2.tgz","fileCount":11,"integrity":"sha512-0M9C+YO1Ig7rDiGxQ3Rc8VYsSDKmmVKHXewtWX878bBQFEXvvFiD9Kasb3YPImT4ttGWhxKgvjITE3p6dXh4og==","signatures":[{"sig":"MEUCIGOcNnruDfbR9OJY8KjAU7ugavAVlKc7NvOit5YZdAvhAiEAvt27VVXLpwyoJP8RvUAIwerVH5J40ZWN4YiTihQ58TU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@adviser%2fovn-fabric@0.1.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":134753},"gitHead":"5132fd36ebb3db203677d5be61fc4a1e81f3ec09","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:a158b603-932d-4653-8088-bd86e495c583"}},"repository":{"url":"git+https://github.com/mabels/ovn-fabric.git","type":"git"},"_npmVersion":"11.18.0","description":"Declarative OVN/OVS topology generator — one config, one self-installing shell script per host.","directories":{},"_nodeVersion":"22.23.1","dependencies":{"deno":"^2.9.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/ovn-fabric_0.1.2_1783347699110_0.21347285226211832","host":"s3://npm-registry-packages-npm-production"}},"0.1.3":{"name":"@adviser/ovn-fabric","version":"0.1.3","keywords":["ovn","ovs","sdn","networking","topology","deno","cli"],"license":"Apache-2.0","_id":"@adviser/ovn-fabric@0.1.3","maintainers":[{"name":"fastandfearless","email":"meno.abels@gmail.com"}],"homepage":"https://github.com/mabels/ovn-fabric#readme","bugs":{"url":"https://github.com/mabels/ovn-fabric/issues"},"bin":{"ovn-fabric":"bin/ovn-fabric.js"},"dist":{"shasum":"a555a9142c1ad4b13f994edcd4b99feecebeaeee","tarball":"https://registry.npmjs.org/@adviser/ovn-fabric/-/ovn-fabric-0.1.3.tgz","fileCount":4,"integrity":"sha512-0h92ttRg8M9pnZ6qPdFvlbaP5PTaME1I43VoF7yVuHoDGTwQ/EgOHY2S4D+4BYQHQQzaIEF2biC5VJyD2D8jrw==","signatures":[{"sig":"MEUCIQDxYryH8zmKLn2OTZ6kdijLuQvjO9uPzDg5oiJbgxGqsgIgHJJ2h8Z3Yjt1jfDiHrXZMbfqiKDIE/o/GL7ebL3mAS0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@adviser%2fovn-fabric@0.1.3","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":20304},"gitHead":"64b82682bf7849dd6b7f02f0ca6b2ee8c9112cc9","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:a158b603-932d-4653-8088-bd86e495c583"}},"repository":{"url":"git+https://github.com/mabels/ovn-fabric.git","type":"git"},"_npmVersion":"11.18.0","description":"Declarative OVN/OVS topology generator — one config, one self-installing shell script per host.","directories":{},"_nodeVersion":"22.23.1","dependencies":{"deno":"^2.9.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/ovn-fabric_0.1.3_1783348995509_0.911067378302268","host":"s3://npm-registry-packages-npm-production"}},"0.1.4":{"name":"@adviser/ovn-fabric","version":"0.1.4","keywords":["ovn","ovs","sdn","networking","topology","deno","cli"],"license":"Apache-2.0","_id":"@adviser/ovn-fabric@0.1.4","maintainers":[{"name":"fastandfearless","email":"meno.abels@gmail.com"}],"homepage":"https://github.com/mabels/ovn-fabric#readme","bugs":{"url":"https://github.com/mabels/ovn-fabric/issues"},"bin":{"ovn-fabric":"bin/ovn-fabric.js"},"dist":{"shasum":"46723eb2f4c6c09177e465c3c531ce6af523111c","tarball":"https://registry.npmjs.org/@adviser/ovn-fabric/-/ovn-fabric-0.1.4.tgz","fileCount":4,"integrity":"sha512-BbfUbcEqZeFB93hvAHvhatWYjsWqGhPxEsW6Txze7n2nZCBgIiG7up2ekTufKyEAHHl3M9vHRhu2Y4x3jQhPYg==","signatures":[{"sig":"MEQCIEySni0xapkJh6+xCa69+dpbrk+il46g3jVLbTP6dEQJAiBRC1jdLOcwX1phxuGkiRAj2Epum01Mhhm5vjZQaudcOw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@adviser%2fovn-fabric@0.1.4","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":20478},"gitHead":"8c7d2169dbb5e575a988bf7f3c8130ed243d3711","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:a158b603-932d-4653-8088-bd86e495c583"}},"repository":{"url":"git+https://github.com/mabels/ovn-fabric.git","type":"git"},"_npmVersion":"11.18.0","description":"Declarative OVN/OVS topology generator — one config, one self-installing shell script per host.","directories":{},"_nodeVersion":"22.23.1","dependencies":{"deno":"^2.9.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/ovn-fabric_0.1.4_1783349364553_0.24594532010970593","host":"s3://npm-registry-packages-npm-production"}},"0.1.5":{"name":"@adviser/ovn-fabric","version":"0.1.5","keywords":["ovn","ovs","sdn","networking","topology","deno","cli"],"license":"Apache-2.0","_id":"@adviser/ovn-fabric@0.1.5","maintainers":[{"name":"fastandfearless","email":"meno.abels@gmail.com"}],"homepage":"https://github.com/mabels/ovn-fabric#readme","bugs":{"url":"https://github.com/mabels/ovn-fabric/issues"},"bin":{"ovn-fabric":"bin/ovn-fabric.js"},"dist":{"shasum":"3f6da5705263d9202cbae87d4d23172ea50ae4d6","tarball":"https://registry.npmjs.org/@adviser/ovn-fabric/-/ovn-fabric-0.1.5.tgz","fileCount":4,"integrity":"sha512-+BPjTFpTFVL7JU/kvvJHHgrUc9jmQmymVc2gRXoMqcksdyvJvN9unEp5MFnTBT7/EF8gtkszw98hNa/kt7ZegA==","signatures":[{"sig":"MEUCIBU7YeOFJoJ2FqUQmHKRslLMxEwYLmVpYW1u6ZhOfDrYAiEA4KFeoEj1b4V5DwqSPw7VCdchrhMcnPdYRHmgc04pz5I=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@adviser%2fovn-fabric@0.1.5","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":20478},"gitHead":"bcb5c806f05cc6ffd1795ddf9bfc85bedd3fe23f","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:a158b603-932d-4653-8088-bd86e495c583"}},"repository":{"url":"git+https://github.com/mabels/ovn-fabric.git","type":"git"},"_npmVersion":"11.18.0","description":"Declarative OVN/OVS topology generator — one config, one self-installing shell script per host.","directories":{},"_nodeVersion":"22.23.1","dependencies":{"deno":"^2.9.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/ovn-fabric_0.1.5_1783349807228_0.8063537105562044","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@adviser/ovn-fabric","version":"0.2.0","keywords":["ovn","ovs","sdn","networking","topology","deno","cli"],"license":"Apache-2.0","_id":"@adviser/ovn-fabric@0.2.0","maintainers":[{"name":"fastandfearless","email":"meno.abels@gmail.com"}],"homepage":"https://github.com/mabels/ovn-fabric#readme","bugs":{"url":"https://github.com/mabels/ovn-fabric/issues"},"bin":{"ovn-fabric":"bin/ovn-fabric.js"},"dist":{"shasum":"56d1f125df9e15b1e59ff702c17125068172c8a6","tarball":"https://registry.npmjs.org/@adviser/ovn-fabric/-/ovn-fabric-0.2.0.tgz","fileCount":4,"integrity":"sha512-2rEp5GOLGkEkPFxE9C95CI2tYzTrMMHJiKKDuTBd7g6qWqGO73pbN9aeKh6vztCLkhUXSlAY63IBWFffSazqlA==","signatures":[{"sig":"MEUCIQCZksWFsY4aC/eKUsYaI0TN1mv8y4LZQ9+s9ig0kvjd+wIgAZIKfoVAR5zUTpEJOZPcQDSMBx2bVDZA6e59R9SIjOE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@adviser%2fovn-fabric@0.2.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":20478},"gitHead":"5cd298a2d489be05c88d1645eec8dd2259dfc069","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:a158b603-932d-4653-8088-bd86e495c583"}},"repository":{"url":"git+https://github.com/mabels/ovn-fabric.git","type":"git"},"_npmVersion":"11.18.0","description":"Declarative OVN/OVS topology generator — one config, one self-installing shell script per host.","directories":{},"_nodeVersion":"22.23.1","dependencies":{"deno":"^2.9.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/ovn-fabric_0.2.0_1783350601411_0.6251292542738394","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@adviser/ovn-fabric","version":"0.2.1","description":"Declarative OVN/OVS topology generator — one config, one self-installing shell script per host.","license":"Apache-2.0","publishConfig":{"access":"public"},"bin":{"ovn-fabric":"bin/ovn-fabric.js"},"repository":{"type":"git","url":"git+https://github.com/mabels/ovn-fabric.git"},"homepage":"https://github.com/mabels/ovn-fabric#readme","bugs":{"url":"https://github.com/mabels/ovn-fabric/issues"},"keywords":["ovn","ovs","sdn","networking","topology","deno","cli"],"dependencies":{"deno":"^2.9.1"},"gitHead":"90505cd5d5296cd1e94e8f681d26f4f5f0b07a23","_id":"@adviser/ovn-fabric@0.2.1","_nodeVersion":"22.23.1","_npmVersion":"11.18.0","dist":{"integrity":"sha512-a9/4fy1/Q1FKrRpSaFldVIxYO5qU517mPoccyGE1/Yn0POEJ2zYCuc/T1QT2mWQfMyrgoNsj+efJYfvGOPYtrw==","shasum":"9b7435b0a509ca5fe8315917f8dac331b762a78a","tarball":"https://registry.npmjs.org/@adviser/ovn-fabric/-/ovn-fabric-0.2.1.tgz","fileCount":4,"unpackedSize":20589,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@adviser%2fovn-fabric@0.2.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDXPFOXlV0fIBAEr9NM/6mt7p02vOnOTxlL4OiVB+HcQAIhAO6FRyfxnUz6ysGZId+000hkzxemL0/7+oNdAzZHbu9/"}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:a158b603-932d-4653-8088-bd86e495c583"}},"directories":{},"maintainers":[{"name":"fastandfearless","email":"meno.abels@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/ovn-fabric_0.2.1_1783365202917_0.03989528816600063"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-06T14:00:59.903Z","modified":"2026-07-06T19:13:23.350Z","0.1.0":"2026-07-06T14:01:00.271Z","0.1.1":"2026-07-06T14:14:24.757Z","0.1.2":"2026-07-06T14:21:39.267Z","0.1.3":"2026-07-06T14:43:15.660Z","0.1.4":"2026-07-06T14:49:24.708Z","0.1.5":"2026-07-06T14:56:47.388Z","0.2.0":"2026-07-06T15:10:01.581Z","0.2.1":"2026-07-06T19:13:23.100Z"},"bugs":{"url":"https://github.com/mabels/ovn-fabric/issues"},"license":"Apache-2.0","homepage":"https://github.com/mabels/ovn-fabric#readme","keywords":["ovn","ovs","sdn","networking","topology","deno","cli"],"repository":{"type":"git","url":"git+https://github.com/mabels/ovn-fabric.git"},"description":"Declarative OVN/OVS topology generator — one config, one self-installing shell script per host.","maintainers":[{"name":"fastandfearless","email":"meno.abels@gmail.com"}],"readme":"# ovn-fabric\n\nA declarative OVN/OVS network topology generator. You describe a network —\nhosts, segments, uplinks, VPN tunnels — as plain TypeScript, and ovn-fabric\nemits **one self-installing shell script per host**. Copy that script to the\nhost and run it: it creates the OVS bridges/interfaces, builds the full OVN\nlogical topology (routers, switches, NAT), and installs itself as a\nboot-time systemd unit — idempotently, so re-running it (or rebooting) is\nalways safe.\n\nNo netplan, no hand-written `ovn-nbctl`/`ovs-vsctl` invocations, no\nconfiguration drift between \"what I meant to set up\" and \"what's actually\nrunning.\" The config is the single source of truth; the generated script is\na disposable, regeneratable artifact.\n\n## Install\n\n**Via npx** (no local Deno install required — the official\n[`deno`](https://www.npmjs.com/package/deno) npm package is pulled in\nautomatically as a dependency the first time you run this). Use the explicit\n`-p`/package form — npx's implicit \"guess the command from the package name\"\ndoesn't reliably resolve a scoped package name (`@adviser/ovn-fabric`)\nagainst its differently-named bin (`ovn-fabric`):\n\n```sh\nnpx -p @adviser/ovn-fabric ovn-fabric generate-ovn path/to/topology.ts > install.sh\n```\n\n**Via Deno**, if you already have it (the CLI is the `/cli` export — the bare\npackage name is the library, for use from your own `topology.ts`, see below):\n\n```sh\ndeno run -A jsr:@adviser/ovn-fabric/cli generate-ovn path/to/topology.ts > install.sh\n```\n\n**As a permanent global command**:\n\n```sh\ndeno install -g -A -n ovn-fabric jsr:@adviser/ovn-fabric/cli\n```\n\n## Quickstart\n\nCopy [`examples/minimal-topology.ts`](examples/minimal-topology.ts) as a\nstarting point. Everything you need to declare a topology comes from the one\npackage import — `defineNetwork`, every uplink/segment factory, and the\npublic types (`Host`, `Uplink`, `Segment`, `ManualUplink`, ...) all live at\nthe same `@adviser/ovn-fabric` / `jsr:@adviser/ovn-fabric` path:\n\n```ts\nimport {\n  defineNetwork,\n  segmentPhysical,\n  uplinkPhysical,\n  ManualUplink,\n} from \"jsr:@adviser/ovn-fabric\";\n\nexport const network = defineNetwork(\"minimal\", (net) => {\n  const host = net.localHost(\"this-host\");\n\n  const wan = net.uplink(\"wan\", uplinkPhysical({\n    id: \"1\",\n    name: \"eth0\",\n    nat: { ipv4: [{ kind: \"masq\" }], ipv6: [{ kind: \"masq\" }] },\n    host,\n  }));\n\n  net.segment(\"lan\", segmentPhysical({\n    id: \"10\",\n    name: \"eth1\",\n    uplink: new ManualUplink(wan),\n    gatewaySuffix: 2, // or gatewayIp/gatewayIpv6 for a literal override — see segmentPhysical's doc comment\n    slaac: false,\n    host,\n  }));\n});\n```\n\nThen:\n\n```sh\nnpx -p @adviser/ovn-fabric ovn-fabric generate topology.ts       # sanity-check what it declares\nnpx -p @adviser/ovn-fabric ovn-fabric generate-ovn topology.ts   # emit the install script(s)\n```\n\n`generate-ovn` prints one script per distinct `Host` your config declares.\nFor a multi-host config, scripts are separated by a `# ===== host: X =====`\nmarker line — never printed before the first script, since each script is\nmeant to be saved and run (or `systemctl`-exec'd) as-is, and a leading\nnon-shebang line would break that.\n\n## Model\n\n- **Host** — where a segment's or uplink's config actually gets applied\n  (`net.sshHost(name, address, user)` or `net.localHost(name)`). Every\n  segment/uplink declares its own host explicitly, so a multi-chassis\n  topology is a config change, not a redesign.\n- **Uplink** — a real (or eventually-real) path to the outside world:\n  `uplinkVlan`, `uplinkPhysical`, `uplinkDummy` (placeholder, no backing\n  interface yet), `uplinkWireguard` (a real `wg-quick`-managed tunnel).\n- **Segment** — a client-facing network (`segmentPhysical`, `segmentVlan`),\n  joined to the shared backbone and routed out through whichever uplink it\n  points at.\n- **Backdoor** — a second, dedicated transfer-link-shaped connection an\n  uplink can borrow from an *already-real* uplink's own egress. Used for\n  two distinct purposes: as a stand-in real interface while an uplink is\n  still a placeholder (`uplinkDummy`), or as pure bootstrap egress\n  alongside a real interface (e.g. a WireGuard tunnel's own handshake/\n  keepalive traffic needs a mundane path to the internet before the tunnel\n  itself is up).\n- **NAT** — per-uplink and per-segment; currently `{ kind: \"masq\" }` for\n  IPv4/IPv6 independently.\n\nSee the doc comments in `src/types.ts` for the full model — every field has\nan explanation of what it's for and why it's shaped the way it is.\n\n## Design notes worth knowing before you rely on this\n\n- Boot safety: package checks (`dpkg -s`) on the systemd/boot path are\n  `timeout`-capped and warn-only — a missing tool never blocks router\n  startup. Real `apt-get install` only ever runs in the manual/first-run\n  branch, never from `systemctl`.\n- Idempotency throughout: `--may-exist`/`--if-exists` on every\n  `ovs-vsctl`/`ovn-nbctl` call, `ip link show ... || ...` guards, `cmp -s`\n  before overwriting any file (including WireGuard confs — the tunnel only\n  bounces if the content actually changed).\n- WireGuard uplinks use `wg-quick`, not hand-rolled `wg setconf` — this\n  relies on `wg-quick`'s own fwmark + policy-routing so the tunnel's own\n  traffic keeps using whatever path already exists (see Backdoor above)\n  while everything else gets diverted into the tunnel.\n\n## Publishing (maintainers)\n\n`package.json`/`deno.json` carry a `0.0.0` placeholder version in git — there's\nnothing to bump by hand. Tag a commit `vX.Y.Z` and push it; CI derives the\nversion from that tag, patches it into both files, then publishes to npm and\nJSR via OIDC trusted publishing (see `.github/workflows/ci.yaml` and\n`scripts/patch-version.mjs`; no token secrets involved, but it does require a\none-time registry-side setup — see the comment at the top of that workflow\nfile).\n\n## License\n\nApache-2.0 — see [LICENSE](LICENSE).\n","readmeFilename":"README.md"}