@owine/unifi-network-mcp 3.0.0 → 3.2.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.
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerClassicTools = registerClassicTools;
4
+ const responses_js_1 = require("../utils/responses.js");
5
+ const safety_js_1 = require("../utils/safety.js");
6
+ const params_js_1 = require("../utils/params.js");
7
+ const pick_js_1 = require("../utils/pick.js");
8
+ const output_schemas_js_1 = require("../utils/output-schemas.js");
9
+ const CLASSIC_IDS = "IDs are the classic controller's _id values, which differ from Integration API IDs: do not pass one to an Integration API tool, or the reverse.";
10
+ const ruleset = (rule) => (typeof rule.ruleset === "string" ? rule.ruleset : "");
11
+ // A number or a numeric string, depending on the controller version.
12
+ function ruleIndex(rule) {
13
+ const index = Number.parseFloat(String(rule.rule_index));
14
+ return Number.isNaN(index) ? Number.MAX_SAFE_INTEGER : index;
15
+ }
16
+ /** The order legacy rules are evaluated in; a rule with no usable index goes last in its ruleset. */
17
+ function byEvaluationOrder(a, b) {
18
+ return ruleset(a).localeCompare(ruleset(b)) || ruleIndex(a) - ruleIndex(b);
19
+ }
20
+ function registerClassicTools(server, client) {
21
+ const list = (collection, row, order) => {
22
+ const fields = Object.keys(row.shape);
23
+ return async ({ siteReference }) => {
24
+ try {
25
+ const { data: rows } = output_schemas_js_1.ClassicEnvelope.parse(await client.getClassic(siteReference, collection));
26
+ const data = rows.map((record) => row.strip().parse((0, pick_js_1.pick)(record, fields)));
27
+ if (order)
28
+ data.sort(order);
29
+ return (0, responses_js_1.formatSuccess)({ data, count: data.length, siteReference }, { structured: true });
30
+ }
31
+ catch (err) {
32
+ return (0, responses_js_1.formatError)(err);
33
+ }
34
+ };
35
+ };
36
+ server.registerTool("unifi_list_classic_networks", {
37
+ description: `List the site's networks from the classic controller API (rest/networkconf), whole and unpaged. Use it to resolve the classic network IDs legacy firewall rules reference; for everything else prefer unifi_list_networks. ${CLASSIC_IDS} Rows carry only the fields in the output schema; credentials are never returned.`,
38
+ inputSchema: { siteReference: (0, params_js_1.siteReference)() },
39
+ outputSchema: output_schemas_js_1.listClassicNetworksOutputSchema,
40
+ annotations: safety_js_1.READ_ONLY,
41
+ }, list("networkconf", output_schemas_js_1.ClassicNetwork));
42
+ server.registerTool("unifi_list_firewall_groups", {
43
+ description: `List the site's firewall groups (address, IPv6 address and port groups) from the classic controller API (rest/firewallgroup), whole and unpaged. Legacy firewall rules reference these by ID. ${CLASSIC_IDS}`,
44
+ inputSchema: { siteReference: (0, params_js_1.siteReference)() },
45
+ outputSchema: output_schemas_js_1.listFirewallGroupsOutputSchema,
46
+ annotations: safety_js_1.READ_ONLY,
47
+ }, list("firewallgroup", output_schemas_js_1.ClassicFirewallGroup));
48
+ server.registerTool("unifi_list_legacy_firewall_rules", {
49
+ description: `List the site's legacy firewall rules (WAN_IN, LAN_IN, GUEST_LOCAL and the other rulesets) from the classic controller API (rest/firewallrule), whole and unpaged. On a site that uses the zone-based firewall these rules may not be enforced; its rules are the policies unifi_list_firewall_policies returns. ${CLASSIC_IDS} Rules reference networks by unifi_list_classic_networks IDs and groups by unifi_list_firewall_groups IDs. Sorted by ruleset, then rule_index, the order they are evaluated in.`,
50
+ inputSchema: { siteReference: (0, params_js_1.siteReference)() },
51
+ outputSchema: output_schemas_js_1.listLegacyFirewallRulesOutputSchema,
52
+ annotations: safety_js_1.READ_ONLY,
53
+ }, list("firewallrule", output_schemas_js_1.LegacyFirewallRule, byEvaluationOrder));
54
+ }
@@ -4,9 +4,9 @@ exports.registerClientHistoryTools = registerClientHistoryTools;
4
4
  const zod_1 = require("zod");
5
5
  const responses_js_1 = require("../utils/responses.js");
6
6
  const safety_js_1 = require("../utils/safety.js");
7
+ const params_js_1 = require("../utils/params.js");
7
8
  const output_schemas_js_1 = require("../utils/output-schemas.js");
8
- const siteReference = zod_1.z.string().regex(/^[A-Za-z0-9_-]{1,64}$/)
9
- .describe("Site internalReference from unifi_list_sites (often default), not the Integration API UUID");
9
+ const siteReference = (0, params_js_1.siteReference)();
10
10
  function registerClientHistoryTools(server, client) {
11
11
  server.registerTool("unifi_list_client_history", {
12
12
  description: `List historical/offline client inventory using the controller v2 API. Returns OFFLINE clients only — currently connected clients are excluded, so merge with unifi_list_clients for a full inventory. Includes names, MACs, first_seen and last_seen epoch seconds when available. This is inventory, not session history; use unifi_list_client_sessions for past connections. Requires controller history API-key support; errors never mean zero activity. Retention depends on the controller. Returns the most recently seen clients first, up to limit, with totalCount; truncated: true means less recently seen clients were left out, so raise limit (narrowing withinHours drops those same clients). Rows carry only ${Object.keys(output_schemas_js_1.HistoryClient.shape).join(", ")}.`,
@@ -42,7 +42,7 @@ function registerDeviceTools(server, client, readOnly = false) {
42
42
  }
43
43
  });
44
44
  server.registerTool("unifi_get_device", {
45
- description: "Get full configuration for a device. Returns (in addition to list fields): adoptedAt, provisionedAt, configurationId, uplink.deviceId (absent on the ISP modem), features (object keyed by capability: switching {lags[]} / accessPoint {}), interfaces.ports[] for switches, gateways and modems ({idx, state, connector, maxSpeedMbps, speedMbps (may be omitted on DOWN ports), poe:{standard, type, enabled, state} on PoE ports only}), interfaces.radios[] for APs ({wlanStandard, frequencyGHz, channelWidthMHz, channel}). Some devices (e.g. 5G modems) return empty features/interfaces objects. NOTE: in the LIST endpoint, features/interfaces are capability-tag string arrays instead. Use for: switch port layout/PoE state, AP radio config, uplink topology. For live throughput/CPU/memory, use unifi_get_device_statistics.",
45
+ description: "Get full configuration for a device. Returns (in addition to list fields): adoptedAt, provisionedAt, configurationId, uplink.deviceId (absent on the ISP modem), features (object keyed by capability: switching {lags[]} / accessPoint {}), interfaces.ports[] for switches, gateways and modems ({idx, state, connector, maxSpeedMbps, speedMbps (may be omitted on DOWN ports), poe:{standard, type, enabled, state} on PoE ports only}), interfaces.radios[] for APs ({wlanStandard, frequencyGHz, txPowerMode (e.g. MEDIUM; 11.1.47 and later), channelWidthMHz, channel}). Some devices (e.g. 5G modems) return empty features/interfaces objects. NOTE: in the LIST endpoint, features/interfaces are capability-tag string arrays instead. Use for: switch port layout/PoE state, AP radio config, uplink topology. For live throughput/CPU/memory, use unifi_get_device_statistics.",
46
46
  inputSchema: {
47
47
  siteId: (0, params_js_1.resourceId)().describe("Site ID"),
48
48
  deviceId: (0, params_js_1.resourceId)().describe("Device ID"),
@@ -0,0 +1,3 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { NetworkClient } from "../client.js";
3
+ export declare function registerExposureTools(server: McpServer, client: NetworkClient): void;
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerExposureTools = registerExposureTools;
4
+ const responses_js_1 = require("../utils/responses.js");
5
+ const safety_js_1 = require("../utils/safety.js");
6
+ const params_js_1 = require("../utils/params.js");
7
+ const pick_js_1 = require("../utils/pick.js");
8
+ const output_schemas_js_1 = require("../utils/output-schemas.js");
9
+ const isRow = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
10
+ const flag = (value) => (typeof value === "boolean" ? value : null);
11
+ const text = (value) => (typeof value === "string" ? value : null);
12
+ const FORWARD_FIELDS = Object.keys(output_schemas_js_1.PortForward.shape);
13
+ const DESTINATION_FIELDS = Object.keys(output_schemas_js_1.PortForwardDestination.shape);
14
+ /** The site's settings sections by key. Only the caller's picked fields leave this module. */
15
+ async function settingSections(client, site) {
16
+ const { data } = output_schemas_js_1.ClassicEnvelope.parse(await client.getClassicSettings(site));
17
+ return new Map(data.flatMap((section) => (typeof section.key === "string" ? [[section.key, section]] : [])));
18
+ }
19
+ const SETTINGS = "from the classic controller API (get/setting)";
20
+ function registerExposureTools(server, client) {
21
+ server.registerTool("unifi_list_port_forwards", {
22
+ description: `List the site's port forwards from the classic controller API (rest/portforward), whole and unpaged: each one exposes a LAN host to the internet on the WAN interface pfwd_interface. enabled: false rules forward nothing; enabledCount counts the rest. Unless src_limiting_enabled restricts it to src_firewall_group_id, the forward is open to the whole internet: src is then "any" or absent (Network 11.0.94 omits it). fwd and fwd_port are the LAN target. IDs are the classic controller's _id values.`,
23
+ inputSchema: { siteReference: (0, params_js_1.siteReference)() },
24
+ outputSchema: output_schemas_js_1.listPortForwardsOutputSchema,
25
+ annotations: safety_js_1.READ_ONLY,
26
+ }, async ({ siteReference }) => {
27
+ try {
28
+ const { data: rows } = output_schemas_js_1.ClassicEnvelope.parse(await client.getClassic(siteReference, "portforward"));
29
+ const data = rows.map((record) => {
30
+ const row = (0, pick_js_1.pick)(record, FORWARD_FIELDS);
31
+ if (Array.isArray(row.destination_ips)) {
32
+ row.destination_ips = row.destination_ips.map((entry) => (isRow(entry) ? (0, pick_js_1.pick)(entry, DESTINATION_FIELDS) : entry));
33
+ }
34
+ return output_schemas_js_1.PortForward.strip().parse(row);
35
+ });
36
+ const enabledCount = data.filter((row) => row.enabled !== false).length;
37
+ return (0, responses_js_1.formatSuccess)({ data, count: data.length, enabledCount, siteReference }, { structured: true });
38
+ }
39
+ catch (err) {
40
+ return (0, responses_js_1.formatError)(err);
41
+ }
42
+ });
43
+ server.registerTool("unifi_get_upnp_status", {
44
+ description: `Read whether UPnP and NAT-PMP are on for the site's gateway, ${SETTINGS}: the dedicated upnp section where the controller has one, otherwise the gateway (usg) section's upnp_* fields. With UPnP on, LAN devices open WAN ports themselves, without a port forward. upnp_nat_pmp_enabled is the stored setting, which does nothing while UPnP is off; detail says which applies. status: unavailable means no UPnP setting was found on this controller version; it does not mean UPnP is off.`,
45
+ inputSchema: { siteReference: (0, params_js_1.siteReference)() },
46
+ outputSchema: output_schemas_js_1.getUpnpStatusOutputSchema,
47
+ annotations: safety_js_1.READ_ONLY,
48
+ }, async ({ siteReference }) => {
49
+ try {
50
+ const sections = await settingSections(client, siteReference);
51
+ for (const source of ["upnp", "usg"]) {
52
+ const section = sections.get(source);
53
+ if (!section)
54
+ continue;
55
+ // Network 11.0.94 (zone-based) has no upnp section: its usg section holds
56
+ // the upnp_* fields. A upnp section, where there is one, may drop the prefix.
57
+ const field = (name) => section[`upnp_${name}`] ?? (source === "upnp" ? section[name] : undefined);
58
+ const enabled = flag(field("enabled"));
59
+ if (enabled === null)
60
+ continue;
61
+ const natPmp = flag(field("nat_pmp_enabled"));
62
+ const detail = enabled
63
+ ? `UPnP is on: LAN devices can open ports on the WAN without a port forward.${natPmp ? " NAT-PMP is on too." : ""}`
64
+ : natPmp
65
+ ? "UPnP is off. NAT-PMP is stored as on, but that flag does nothing while UPnP is off; it applies again if UPnP is turned on."
66
+ : "UPnP is off, so NAT-PMP is not served either.";
67
+ return (0, responses_js_1.formatSuccess)({
68
+ siteReference, status: "available", source,
69
+ upnp_enabled: enabled,
70
+ upnp_nat_pmp_enabled: natPmp,
71
+ upnp_secure_mode: flag(field("secure_mode")),
72
+ upnp_wan_interface: text(field("wan_interface")),
73
+ detail,
74
+ }, { structured: true });
75
+ }
76
+ return (0, responses_js_1.formatSuccess)({
77
+ siteReference, status: "unavailable", source: null,
78
+ upnp_enabled: null, upnp_nat_pmp_enabled: null, upnp_secure_mode: null, upnp_wan_interface: null,
79
+ detail: "No UPnP setting was found in the site's settings (neither a upnp section nor upnp_enabled in the usg section). This controller version may keep it elsewhere; check the gateway's UPnP setting in the console. This is not a result that UPnP is off.",
80
+ }, { structured: true });
81
+ }
82
+ catch (err) {
83
+ return (0, responses_js_1.formatError)(err);
84
+ }
85
+ });
86
+ server.registerTool("unifi_get_device_ssh_settings", {
87
+ description: `Read the site's device SSH settings (Device SSH Authentication for adopted UniFi devices) ${SETTINGS} mgmt section: whether SSH is on, whether it accepts passwords, whether it listens on every interface (x_ssh_bind_wildcard), and how many SSH keys are installed. Credentials and keys are never returned. Console (UniFi OS) SSH is a separate UniFi OS setting this API does not expose. Which networks reach the console's web UI and SSH is set by firewall rules and policies, and from the internet by Remote Access and port forwards (unifi_list_port_forwards). status: unavailable means the controller's settings had no such fields.`,
88
+ inputSchema: { siteReference: (0, params_js_1.siteReference)() },
89
+ outputSchema: output_schemas_js_1.getDeviceSshSettingsOutputSchema,
90
+ annotations: safety_js_1.READ_ONLY,
91
+ }, async ({ siteReference }) => {
92
+ try {
93
+ const mgmt = (await settingSections(client, siteReference)).get("mgmt");
94
+ const sshEnabled = flag(mgmt?.x_ssh_enabled);
95
+ if (!mgmt || sshEnabled === null) {
96
+ return (0, responses_js_1.formatSuccess)({
97
+ siteReference, status: "unavailable",
98
+ x_ssh_enabled: null, x_ssh_auth_password_enabled: null, x_ssh_bind_wildcard: null, sshKeyCount: null,
99
+ detail: "The site's settings have no device SSH setting (mgmt.x_ssh_enabled) on this controller version. This is not a result that SSH is off.",
100
+ }, { structured: true });
101
+ }
102
+ const passwords = flag(mgmt.x_ssh_auth_password_enabled);
103
+ return (0, responses_js_1.formatSuccess)({
104
+ siteReference, status: "available",
105
+ x_ssh_enabled: sshEnabled,
106
+ x_ssh_auth_password_enabled: passwords,
107
+ x_ssh_bind_wildcard: flag(mgmt.x_ssh_bind_wildcard),
108
+ sshKeyCount: Array.isArray(mgmt.x_ssh_keys) ? mgmt.x_ssh_keys.length : null,
109
+ detail: sshEnabled
110
+ ? `Device SSH is on${passwords === false ? " with key authentication only" : passwords ? ", and accepts passwords" : ""}. It is reachable from wherever the firewall lets traffic to the devices through.`
111
+ : "Device SSH is off.",
112
+ }, { structured: true });
113
+ }
114
+ catch (err) {
115
+ return (0, responses_js_1.formatError)(err);
116
+ }
117
+ });
118
+ }
@@ -497,14 +497,14 @@ function registerFirewallTools(server, client, readOnly = false, wan = wan_expos
497
497
  const path = `/sites/${siteId}/firewall/policies/ordering${query}`;
498
498
  const body = { orderedFirewallPolicyIds };
499
499
  const current = (0, full_put_js_1.asObject)(await client.get(path), "the current firewall policy ordering");
500
- const opens = await (0, safety_js_1.reorderOpens)(evaluationOrder(current.orderedFirewallPolicyIds), evaluationOrder(orderedFirewallPolicyIds), async (id) => {
501
- // The system-defined policies are not listed, so their actions are
502
- // unknown: moving anything across them counts both ways.
503
- if (id === SYSTEM_DEFINED)
504
- return { letsThrough: true, blocks: true };
505
- const policy = (0, full_put_js_1.asObject)(await client.get(`/sites/${siteId}/firewall/policies/${id}`), "a firewall policy");
506
- const active = policy.enabled !== false;
507
- return { letsThrough: active && letsThrough(policy), blocks: active && !letsThrough(policy) };
500
+ const opens = await (0, safety_js_1.reorderOpens)(evaluationOrder(current.orderedFirewallPolicyIds), evaluationOrder(orderedFirewallPolicyIds), async () => {
501
+ const effects = await (0, safety_js_1.listedEffects)(client, `/sites/${siteId}/firewall/policies`, (policy) => {
502
+ const active = policy.enabled !== false;
503
+ return { letsThrough: active && letsThrough(policy), blocks: active && !letsThrough(policy) };
504
+ });
505
+ // The system-defined policies are not in the ordering by ID, so their
506
+ // actions are unknown: moving anything across them counts both ways.
507
+ return effects.set(SYSTEM_DEFINED, { letsThrough: true, blocks: true });
508
508
  });
509
509
  const opening = opens ? "This moves a firewall policy that lets traffic through ahead of one that blocks it" : undefined;
510
510
  const guard = (0, safety_js_1.requireConfirmationIf)(opening, confirm, dryRun);
@@ -11,6 +11,8 @@ const sites_js_1 = require("./sites.js");
11
11
  const devices_js_1 = require("./devices.js");
12
12
  const clients_js_1 = require("./clients.js");
13
13
  const client_history_js_1 = require("./client-history.js");
14
+ const classic_js_1 = require("./classic.js");
15
+ const exposure_js_1 = require("./exposure.js");
14
16
  const networks_js_1 = require("./networks.js");
15
17
  const wifi_js_1 = require("./wifi.js");
16
18
  const hotspot_js_1 = require("./hotspot.js");
@@ -28,6 +30,8 @@ function registerAllTools(server, client, readOnly = false, options = {}) {
28
30
  (0, devices_js_1.registerDeviceTools)(server, client, readOnly);
29
31
  (0, clients_js_1.registerClientTools)(server, client, readOnly);
30
32
  (0, client_history_js_1.registerClientHistoryTools)(server, client);
33
+ (0, classic_js_1.registerClassicTools)(server, client);
34
+ (0, exposure_js_1.registerExposureTools)(server, client);
31
35
  (0, networks_js_1.registerNetworkTools)(server, client, readOnly, wan);
32
36
  (0, wifi_js_1.registerWifiTools)(server, client, readOnly);
33
37
  (0, hotspot_js_1.registerHotspotTools)(server, client, readOnly);
@@ -82,7 +86,7 @@ function instrumentTools(server, { writeTools, writeLog }) {
82
86
  // Words in tool names that read wrongly in plain sentence case.
83
87
  const TITLE_WORDS = {
84
88
  acl: "ACL", dns: "DNS", dpi: "DPI", vpn: "VPN", radius: "RADIUS",
85
- wifi: "WiFi", wan: "WAN", wans: "WANs", lag: "LAG", lags: "LAGs", mc: "MC",
89
+ wifi: "WiFi", wan: "WAN", wans: "WANs", lag: "LAG", lags: "LAGs", mc: "MC", upnp: "UPnP", ssh: "SSH",
86
90
  };
87
91
  /** "unifi_list_mc_lag_domains" → "List MC-LAG domains". */
88
92
  function toolTitle(name) {
@@ -0,0 +1,4 @@
1
+ import { z } from "zod";
2
+ import type { NetworkClient } from "../client.js";
3
+ /** Every item of a paged Integration API list, read page by page. */
4
+ export declare function listAll<T extends z.ZodType>(client: NetworkClient, path: string, item: T): Promise<z.infer<T>[]>;
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.listAll = listAll;
4
+ const zod_1 = require("zod");
5
+ const PAGE_LIMIT = 200;
6
+ const MAX_PAGES = 50;
7
+ /** Every item of a paged Integration API list, read page by page. */
8
+ async function listAll(client, path, item) {
9
+ const page = zod_1.z.object({ data: zod_1.z.array(item), totalCount: zod_1.z.number().optional() }).loose();
10
+ const items = [];
11
+ for (let pages = 0; pages < MAX_PAGES; pages++) {
12
+ const { data, totalCount } = page.parse(await client.get(`${path}?offset=${items.length}&limit=${PAGE_LIMIT}`));
13
+ items.push(...data);
14
+ // Without a totalCount, only an empty page shows the list has ended: a
15
+ // controller may cap pages below PAGE_LIMIT, so a short page proves nothing.
16
+ if (data.length === 0 || (totalCount !== undefined && items.length >= totalCount))
17
+ return items;
18
+ }
19
+ // A list that does not end cannot be checked, which must not pass.
20
+ throw new Error(`the list did not end after ${MAX_PAGES} pages`);
21
+ }
@@ -482,6 +482,7 @@ export declare const getDeviceOutputSchema: {
482
482
  radios: z.ZodOptional<z.ZodArray<z.ZodObject<{
483
483
  wlanStandard: z.ZodOptional<z.ZodString>;
484
484
  frequencyGHz: z.ZodOptional<z.ZodNumber>;
485
+ txPowerMode: z.ZodOptional<z.ZodString>;
485
486
  channelWidthMHz: z.ZodOptional<z.ZodNumber>;
486
487
  channel: z.ZodOptional<z.ZodNumber>;
487
488
  }, z.core.$loose>>>;
@@ -753,3 +754,218 @@ export declare const listClientSessionsOutputSchema: {
753
754
  readonly end: z.ZodNumber;
754
755
  readonly coverage: z.ZodString;
755
756
  };
757
+ export declare const ClassicNetwork: z.ZodObject<{
758
+ _id: z.ZodString;
759
+ name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
760
+ purpose: z.ZodOptional<z.ZodNullable<z.ZodString>>;
761
+ vlan: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
762
+ vlan_enabled: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
763
+ ip_subnet: z.ZodOptional<z.ZodNullable<z.ZodString>>;
764
+ networkgroup: z.ZodOptional<z.ZodNullable<z.ZodString>>;
765
+ enabled: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
766
+ dhcpd_enabled: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
767
+ dhcpd_start: z.ZodOptional<z.ZodNullable<z.ZodString>>;
768
+ dhcpd_stop: z.ZodOptional<z.ZodNullable<z.ZodString>>;
769
+ domain_name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
770
+ igmp_snooping: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
771
+ mdns_enabled: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
772
+ network_isolation_enabled: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
773
+ internet_access_enabled: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
774
+ firewall_zone_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
775
+ is_nat: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
776
+ ipv6_interface_type: z.ZodOptional<z.ZodNullable<z.ZodString>>;
777
+ setting_preference: z.ZodOptional<z.ZodNullable<z.ZodString>>;
778
+ }, z.core.$loose>;
779
+ export declare const ClassicFirewallGroup: z.ZodObject<{
780
+ _id: z.ZodString;
781
+ name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
782
+ group_type: z.ZodOptional<z.ZodNullable<z.ZodString>>;
783
+ group_members: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString>>>;
784
+ }, z.core.$loose>;
785
+ export declare const LegacyFirewallRule: z.ZodObject<{
786
+ _id: z.ZodString;
787
+ name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
788
+ enabled: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
789
+ ruleset: z.ZodOptional<z.ZodNullable<z.ZodString>>;
790
+ rule_index: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
791
+ action: z.ZodOptional<z.ZodNullable<z.ZodString>>;
792
+ protocol: z.ZodOptional<z.ZodNullable<z.ZodString>>;
793
+ protocol_v6: z.ZodOptional<z.ZodNullable<z.ZodString>>;
794
+ protocol_match_excepted: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
795
+ icmp_typename: z.ZodOptional<z.ZodNullable<z.ZodString>>;
796
+ icmpv6_typename: z.ZodOptional<z.ZodNullable<z.ZodString>>;
797
+ logging: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
798
+ state_established: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
799
+ state_related: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
800
+ state_new: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
801
+ state_invalid: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
802
+ src_firewallgroup_ids: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString>>>;
803
+ src_networkconf_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
804
+ src_networkconf_type: z.ZodOptional<z.ZodNullable<z.ZodString>>;
805
+ src_address: z.ZodOptional<z.ZodNullable<z.ZodString>>;
806
+ src_address_ipv6: z.ZodOptional<z.ZodNullable<z.ZodString>>;
807
+ src_mac_address: z.ZodOptional<z.ZodNullable<z.ZodString>>;
808
+ src_port: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
809
+ dst_firewallgroup_ids: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString>>>;
810
+ dst_networkconf_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
811
+ dst_networkconf_type: z.ZodOptional<z.ZodNullable<z.ZodString>>;
812
+ dst_address: z.ZodOptional<z.ZodNullable<z.ZodString>>;
813
+ dst_address_ipv6: z.ZodOptional<z.ZodNullable<z.ZodString>>;
814
+ dst_port: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
815
+ ipsec: z.ZodOptional<z.ZodNullable<z.ZodString>>;
816
+ setting_preference: z.ZodOptional<z.ZodNullable<z.ZodString>>;
817
+ }, z.core.$loose>;
818
+ /** Envelope of a classic REST collection; rows stay unknown until the allowlist is applied. */
819
+ export declare const ClassicEnvelope: z.ZodObject<{
820
+ meta: z.ZodObject<{
821
+ rc: z.ZodLiteral<"ok">;
822
+ }, z.core.$loose>;
823
+ data: z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
824
+ }, z.core.$strip>;
825
+ export declare const listClassicNetworksOutputSchema: {
826
+ readonly data: z.ZodArray<z.ZodObject<{
827
+ _id: z.ZodString;
828
+ name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
829
+ purpose: z.ZodOptional<z.ZodNullable<z.ZodString>>;
830
+ vlan: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
831
+ vlan_enabled: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
832
+ ip_subnet: z.ZodOptional<z.ZodNullable<z.ZodString>>;
833
+ networkgroup: z.ZodOptional<z.ZodNullable<z.ZodString>>;
834
+ enabled: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
835
+ dhcpd_enabled: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
836
+ dhcpd_start: z.ZodOptional<z.ZodNullable<z.ZodString>>;
837
+ dhcpd_stop: z.ZodOptional<z.ZodNullable<z.ZodString>>;
838
+ domain_name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
839
+ igmp_snooping: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
840
+ mdns_enabled: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
841
+ network_isolation_enabled: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
842
+ internet_access_enabled: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
843
+ firewall_zone_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
844
+ is_nat: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
845
+ ipv6_interface_type: z.ZodOptional<z.ZodNullable<z.ZodString>>;
846
+ setting_preference: z.ZodOptional<z.ZodNullable<z.ZodString>>;
847
+ }, z.core.$loose>>;
848
+ readonly count: z.ZodNumber;
849
+ readonly siteReference: z.ZodString;
850
+ };
851
+ export declare const listFirewallGroupsOutputSchema: {
852
+ readonly data: z.ZodArray<z.ZodObject<{
853
+ _id: z.ZodString;
854
+ name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
855
+ group_type: z.ZodOptional<z.ZodNullable<z.ZodString>>;
856
+ group_members: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString>>>;
857
+ }, z.core.$loose>>;
858
+ readonly count: z.ZodNumber;
859
+ readonly siteReference: z.ZodString;
860
+ };
861
+ export declare const listLegacyFirewallRulesOutputSchema: {
862
+ readonly data: z.ZodArray<z.ZodObject<{
863
+ _id: z.ZodString;
864
+ name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
865
+ enabled: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
866
+ ruleset: z.ZodOptional<z.ZodNullable<z.ZodString>>;
867
+ rule_index: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
868
+ action: z.ZodOptional<z.ZodNullable<z.ZodString>>;
869
+ protocol: z.ZodOptional<z.ZodNullable<z.ZodString>>;
870
+ protocol_v6: z.ZodOptional<z.ZodNullable<z.ZodString>>;
871
+ protocol_match_excepted: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
872
+ icmp_typename: z.ZodOptional<z.ZodNullable<z.ZodString>>;
873
+ icmpv6_typename: z.ZodOptional<z.ZodNullable<z.ZodString>>;
874
+ logging: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
875
+ state_established: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
876
+ state_related: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
877
+ state_new: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
878
+ state_invalid: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
879
+ src_firewallgroup_ids: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString>>>;
880
+ src_networkconf_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
881
+ src_networkconf_type: z.ZodOptional<z.ZodNullable<z.ZodString>>;
882
+ src_address: z.ZodOptional<z.ZodNullable<z.ZodString>>;
883
+ src_address_ipv6: z.ZodOptional<z.ZodNullable<z.ZodString>>;
884
+ src_mac_address: z.ZodOptional<z.ZodNullable<z.ZodString>>;
885
+ src_port: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
886
+ dst_firewallgroup_ids: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString>>>;
887
+ dst_networkconf_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
888
+ dst_networkconf_type: z.ZodOptional<z.ZodNullable<z.ZodString>>;
889
+ dst_address: z.ZodOptional<z.ZodNullable<z.ZodString>>;
890
+ dst_address_ipv6: z.ZodOptional<z.ZodNullable<z.ZodString>>;
891
+ dst_port: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
892
+ ipsec: z.ZodOptional<z.ZodNullable<z.ZodString>>;
893
+ setting_preference: z.ZodOptional<z.ZodNullable<z.ZodString>>;
894
+ }, z.core.$loose>>;
895
+ readonly count: z.ZodNumber;
896
+ readonly siteReference: z.ZodString;
897
+ };
898
+ export declare const PortForwardDestination: z.ZodObject<{
899
+ destination_ip: z.ZodOptional<z.ZodNullable<z.ZodString>>;
900
+ interface: z.ZodOptional<z.ZodNullable<z.ZodString>>;
901
+ }, z.core.$loose>;
902
+ export declare const PortForward: z.ZodObject<{
903
+ _id: z.ZodString;
904
+ name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
905
+ enabled: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
906
+ pfwd_interface: z.ZodOptional<z.ZodNullable<z.ZodString>>;
907
+ destination_ip: z.ZodOptional<z.ZodNullable<z.ZodString>>;
908
+ destination_ips: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodObject<{
909
+ destination_ip: z.ZodOptional<z.ZodNullable<z.ZodString>>;
910
+ interface: z.ZodOptional<z.ZodNullable<z.ZodString>>;
911
+ }, z.core.$loose>>>>;
912
+ src: z.ZodOptional<z.ZodNullable<z.ZodString>>;
913
+ src_limiting_enabled: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
914
+ src_limiting_type: z.ZodOptional<z.ZodNullable<z.ZodString>>;
915
+ src_firewall_group_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
916
+ dst_port: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
917
+ fwd: z.ZodOptional<z.ZodNullable<z.ZodString>>;
918
+ fwd_port: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
919
+ proto: z.ZodOptional<z.ZodNullable<z.ZodString>>;
920
+ log: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
921
+ }, z.core.$loose>;
922
+ export declare const listPortForwardsOutputSchema: {
923
+ readonly data: z.ZodArray<z.ZodObject<{
924
+ _id: z.ZodString;
925
+ name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
926
+ enabled: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
927
+ pfwd_interface: z.ZodOptional<z.ZodNullable<z.ZodString>>;
928
+ destination_ip: z.ZodOptional<z.ZodNullable<z.ZodString>>;
929
+ destination_ips: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodObject<{
930
+ destination_ip: z.ZodOptional<z.ZodNullable<z.ZodString>>;
931
+ interface: z.ZodOptional<z.ZodNullable<z.ZodString>>;
932
+ }, z.core.$loose>>>>;
933
+ src: z.ZodOptional<z.ZodNullable<z.ZodString>>;
934
+ src_limiting_enabled: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
935
+ src_limiting_type: z.ZodOptional<z.ZodNullable<z.ZodString>>;
936
+ src_firewall_group_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
937
+ dst_port: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
938
+ fwd: z.ZodOptional<z.ZodNullable<z.ZodString>>;
939
+ fwd_port: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
940
+ proto: z.ZodOptional<z.ZodNullable<z.ZodString>>;
941
+ log: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
942
+ }, z.core.$loose>>;
943
+ readonly count: z.ZodNumber;
944
+ readonly enabledCount: z.ZodNumber;
945
+ readonly siteReference: z.ZodString;
946
+ };
947
+ export declare const getUpnpStatusOutputSchema: {
948
+ readonly siteReference: z.ZodString;
949
+ readonly status: z.ZodEnum<{
950
+ available: "available";
951
+ unavailable: "unavailable";
952
+ }>;
953
+ readonly source: z.ZodNullable<z.ZodString>;
954
+ readonly upnp_enabled: z.ZodNullable<z.ZodBoolean>;
955
+ readonly upnp_nat_pmp_enabled: z.ZodNullable<z.ZodBoolean>;
956
+ readonly upnp_secure_mode: z.ZodNullable<z.ZodBoolean>;
957
+ readonly upnp_wan_interface: z.ZodNullable<z.ZodString>;
958
+ readonly detail: z.ZodString;
959
+ };
960
+ export declare const getDeviceSshSettingsOutputSchema: {
961
+ readonly siteReference: z.ZodString;
962
+ readonly status: z.ZodEnum<{
963
+ available: "available";
964
+ unavailable: "unavailable";
965
+ }>;
966
+ readonly x_ssh_enabled: z.ZodNullable<z.ZodBoolean>;
967
+ readonly x_ssh_auth_password_enabled: z.ZodNullable<z.ZodBoolean>;
968
+ readonly x_ssh_bind_wildcard: z.ZodNullable<z.ZodBoolean>;
969
+ readonly sshKeyCount: z.ZodNullable<z.ZodNumber>;
970
+ readonly detail: z.ZodString;
971
+ };