@coffeerunhobby/mcp-ha-connect 2.2.1 → 2.3.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.
- package/.env.example +1 -1
- package/README.md +11 -2
- package/dist/omadaClient/client.d.ts +6 -1
- package/dist/omadaClient/client.js +12 -1
- package/dist/omadaClient/client.js.map +1 -1
- package/dist/omadaClient/diagnose.d.ts +68 -0
- package/dist/omadaClient/diagnose.js +164 -0
- package/dist/omadaClient/diagnose.js.map +1 -0
- package/dist/omadaClient/index.d.ts +6 -0
- package/dist/omadaClient/index.js +15 -0
- package/dist/omadaClient/index.js.map +1 -1
- package/dist/omadaClient/macGroups.d.ts +58 -0
- package/dist/omadaClient/macGroups.js +124 -0
- package/dist/omadaClient/macGroups.js.map +1 -0
- package/dist/tools/infra/actions.d.ts +1 -1
- package/dist/tools/infra/actions.js +1 -1
- package/dist/tools/omada/index.js +6 -0
- package/dist/tools/omada/index.js.map +1 -1
- package/dist/tools/omada/macGroups.d.ts +19 -0
- package/dist/tools/omada/macGroups.js +77 -0
- package/dist/tools/omada/macGroups.js.map +1 -0
- package/dist/tools/omada/namespace.js +8 -0
- package/dist/tools/omada/namespace.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +5 -1
- package/.codex/review-rules.md +0 -16
- package/.dockerignore +0 -8
- package/.gitattributes +0 -30
- package/.github/workflows/ci.yml +0 -193
- package/AGENTS.md +0 -389
- package/Dockerfile +0 -50
- package/docker-compose.yml +0 -23
- package/docs/CHANGELOG.md +0 -341
- package/docs/COVERAGE.md +0 -219
- package/docs/QUICK_START.md +0 -240
- package/eslint.config.js +0 -33
- package/n8n/ai-agent-safety-monitor.json +0 -355
- package/openapi.json +0 -1259
- package/scripts/check-version-sync.mjs +0 -69
- package/scripts/generate-jwt.ts +0 -121
- package/src/config.ts +0 -440
- package/src/haClient/automations.ts +0 -261
- package/src/haClient/calendars.ts +0 -94
- package/src/haClient/config.ts +0 -52
- package/src/haClient/devices.ts +0 -653
- package/src/haClient/entities.ts +0 -128
- package/src/haClient/events.ts +0 -689
- package/src/haClient/history.ts +0 -73
- package/src/haClient/index.ts +0 -336
- package/src/haClient/request.ts +0 -142
- package/src/haClient/services.ts +0 -45
- package/src/haClient/states.ts +0 -60
- package/src/haClient/updates.ts +0 -58
- package/src/haClient/wsCommand.ts +0 -44
- package/src/index.ts +0 -164
- package/src/localAI/index.ts +0 -88
- package/src/localAI/prompts.ts +0 -50
- package/src/localAI/providers/base.ts +0 -120
- package/src/localAI/providers/ollama.ts +0 -78
- package/src/localAI/providers/openai.ts +0 -86
- package/src/localAI/types.ts +0 -67
- package/src/omadaClient/auth.ts +0 -178
- package/src/omadaClient/client.ts +0 -337
- package/src/omadaClient/device.ts +0 -118
- package/src/omadaClient/index.ts +0 -310
- package/src/omadaClient/network.ts +0 -284
- package/src/omadaClient/request.ts +0 -365
- package/src/omadaClient/security.ts +0 -51
- package/src/omadaClient/site.ts +0 -344
- package/src/ownerQuestions/service.ts +0 -536
- package/src/permissions/index.ts +0 -143
- package/src/resources/index.ts +0 -213
- package/src/server/auth.ts +0 -175
- package/src/server/chatFace.ts +0 -789
- package/src/server/chatSlice.ts +0 -57
- package/src/server/common.ts +0 -170
- package/src/server/eventSubscription.ts +0 -343
- package/src/server/http.ts +0 -626
- package/src/server/instructions.ts +0 -97
- package/src/server/rateLimiter.ts +0 -227
- package/src/server/stdio.ts +0 -41
- package/src/server/stream.ts +0 -205
- package/src/tools/ai/analyzeSensors.ts +0 -33
- package/src/tools/ai/index.ts +0 -20
- package/src/tools/common.ts +0 -442
- package/src/tools/homeassistant/askOwner.ts +0 -133
- package/src/tools/homeassistant/automationControls.ts +0 -66
- package/src/tools/homeassistant/calendar.ts +0 -97
- package/src/tools/homeassistant/callService.ts +0 -25
- package/src/tools/homeassistant/controlClimate.ts +0 -68
- package/src/tools/homeassistant/controlCover.ts +0 -48
- package/src/tools/homeassistant/controlFan.ts +0 -44
- package/src/tools/homeassistant/controlLight.ts +0 -38
- package/src/tools/homeassistant/controlMediaPlayer.ts +0 -50
- package/src/tools/homeassistant/createAutomation.ts +0 -35
- package/src/tools/homeassistant/deleteAutomation.ts +0 -24
- package/src/tools/homeassistant/entityAction.ts +0 -35
- package/src/tools/homeassistant/entityGuard.ts +0 -28
- package/src/tools/homeassistant/getAllSensors.ts +0 -46
- package/src/tools/homeassistant/getAutomationTrace.ts +0 -30
- package/src/tools/homeassistant/getDomainSummary.ts +0 -29
- package/src/tools/homeassistant/getEntitiesByDomain.ts +0 -56
- package/src/tools/homeassistant/getHistory.ts +0 -24
- package/src/tools/homeassistant/getState.ts +0 -24
- package/src/tools/homeassistant/getStates.ts +0 -46
- package/src/tools/homeassistant/getVersion.ts +0 -21
- package/src/tools/homeassistant/index.ts +0 -121
- package/src/tools/homeassistant/listAutomations.ts +0 -35
- package/src/tools/homeassistant/listEntities.ts +0 -44
- package/src/tools/homeassistant/listPersons.ts +0 -46
- package/src/tools/homeassistant/sceneAndScript.ts +0 -53
- package/src/tools/homeassistant/searchEntities.ts +0 -58
- package/src/tools/homeassistant/sendNotification.ts +0 -179
- package/src/tools/homeassistant/systemTools.ts +0 -52
- package/src/tools/homeassistant/triggerAutomation.ts +0 -24
- package/src/tools/index.ts +0 -78
- package/src/tools/infra/actions.ts +0 -95
- package/src/tools/infra/index.ts +0 -138
- package/src/tools/omada/blockClient.ts +0 -28
- package/src/tools/omada/cyclePoePort.ts +0 -32
- package/src/tools/omada/deleteClient.ts +0 -27
- package/src/tools/omada/disableClientRateLimit.ts +0 -23
- package/src/tools/omada/getClient.ts +0 -14
- package/src/tools/omada/getDevice.ts +0 -14
- package/src/tools/omada/getFirewallSetting.ts +0 -14
- package/src/tools/omada/getInternetInfo.ts +0 -14
- package/src/tools/omada/getLanNetworkList.ts +0 -14
- package/src/tools/omada/getLanProfileList.ts +0 -14
- package/src/tools/omada/getPortForwardingStatus.ts +0 -26
- package/src/tools/omada/getRateLimitProfiles.ts +0 -14
- package/src/tools/omada/getSiteNtpStatus.ts +0 -14
- package/src/tools/omada/getSsidDetail.ts +0 -22
- package/src/tools/omada/getSsidList.ts +0 -21
- package/src/tools/omada/getSwitchStackDetail.ts +0 -14
- package/src/tools/omada/getThreatList.ts +0 -42
- package/src/tools/omada/getWlanGroupList.ts +0 -14
- package/src/tools/omada/graph.ts +0 -187
- package/src/tools/omada/index.ts +0 -153
- package/src/tools/omada/listBlockedClients.ts +0 -17
- package/src/tools/omada/listClients.ts +0 -14
- package/src/tools/omada/listClientsActivity.ts +0 -25
- package/src/tools/omada/listClientsPastConnections.ts +0 -44
- package/src/tools/omada/listDevices.ts +0 -14
- package/src/tools/omada/listDevicesStats.ts +0 -41
- package/src/tools/omada/listMostActiveClients.ts +0 -14
- package/src/tools/omada/listSites.ts +0 -18
- package/src/tools/omada/namespace.ts +0 -1164
- package/src/tools/omada/searchDevices.ts +0 -20
- package/src/tools/omada/setClientRateLimit.ts +0 -26
- package/src/tools/omada/setClientRateLimitProfile.ts +0 -25
- package/src/tools/omada/setSiteNtpServers.ts +0 -36
- package/src/tools/omada/setSsidEnabled.ts +0 -38
- package/src/tools/omada/unblockClient.ts +0 -26
- package/src/tools/types.ts +0 -11
- package/src/tools/utils/pagination-schema.ts +0 -27
- package/src/types/ai/index.ts +0 -11
- package/src/types/ai/types.ts +0 -67
- package/src/types/homeassistant/automations.ts +0 -43
- package/src/types/homeassistant/calendars.ts +0 -26
- package/src/types/homeassistant/config.ts +0 -14
- package/src/types/homeassistant/entities.ts +0 -14
- package/src/types/homeassistant/errors.ts +0 -33
- package/src/types/homeassistant/haConfig.ts +0 -7
- package/src/types/homeassistant/history.ts +0 -13
- package/src/types/homeassistant/index.ts +0 -46
- package/src/types/homeassistant/request.ts +0 -6
- package/src/types/homeassistant/serviceCall.ts +0 -18
- package/src/types/homeassistant/states.ts +0 -58
- package/src/types/homeassistant/updates.ts +0 -28
- package/src/types/index.ts +0 -12
- package/src/types/omada/activeClientInfo.ts +0 -17
- package/src/types/omada/clientActivity.ts +0 -32
- package/src/types/omada/clientBlockStatus.ts +0 -11
- package/src/types/omada/clientPastConnection.ts +0 -82
- package/src/types/omada/index.ts +0 -14
- package/src/types/omada/omadaApiResponse.ts +0 -5
- package/src/types/omada/omadaClientInfo.ts +0 -11
- package/src/types/omada/omadaDeviceInfo.ts +0 -11
- package/src/types/omada/omadaDeviceStats.ts +0 -31
- package/src/types/omada/omadaSiteSummary.ts +0 -5
- package/src/types/omada/oswStackDetail.ts +0 -11
- package/src/types/omada/paginatedResult.ts +0 -6
- package/src/types/omada/rateLimitProfile.ts +0 -58
- package/src/types/omada/threatInfo.ts +0 -38
- package/src/types/omada/tokenResult.ts +0 -6
- package/src/types.ts +0 -2
- package/src/utils/config-validations.ts +0 -68
- package/src/utils/jwt.ts +0 -112
- package/src/utils/logger.ts +0 -121
- package/src/utils/plainText.ts +0 -48
- package/src/utils/redact.ts +0 -59
- package/src/utils/sanitizeError.ts +0 -18
- package/src/utils/tlsDispatcher.ts +0 -69
- package/src/version.ts +0 -5
- package/tests/bdd/automation-creation.spec.ts +0 -214
- package/tests/bdd/automation-management.spec.ts +0 -267
- package/tests/bdd/calendar.spec.ts +0 -190
- package/tests/bdd/configuration.spec.ts +0 -283
- package/tests/bdd/device-control.spec.ts +0 -344
- package/tests/bdd/entity-listing.spec.ts +0 -208
- package/tests/bdd/entity-search.spec.ts +0 -183
- package/tests/bdd/history-retrieval.spec.ts +0 -195
- package/tests/bdd/notifications.spec.ts +0 -238
- package/tests/bdd/service-calls.spec.ts +0 -144
- package/tests/bdd/state-retrieval.spec.ts +0 -204
- package/tests/bench/hotpaths.bench.ts +0 -68
- package/tests/config.test.ts +0 -355
- package/tests/features/automation-creation.feature +0 -36
- package/tests/features/automation-management.feature +0 -54
- package/tests/features/calendar.feature +0 -37
- package/tests/features/configuration.feature +0 -70
- package/tests/features/device-control.feature +0 -100
- package/tests/features/entity-listing.feature +0 -51
- package/tests/features/entity-search.feature +0 -44
- package/tests/features/history-retrieval.feature +0 -38
- package/tests/features/notifications.feature +0 -37
- package/tests/features/service-calls.feature +0 -35
- package/tests/features/state-retrieval.feature +0 -37
- package/tests/fixtures/openapi-default-slice.json +0 -290
- package/tests/haClient/automationTrace.test.ts +0 -59
- package/tests/haClient/automations.test.ts +0 -149
- package/tests/haClient/config.test.ts +0 -117
- package/tests/haClient/entities.test.ts +0 -188
- package/tests/haClient/events.test.ts +0 -455
- package/tests/haClient/eventsTls.test.ts +0 -52
- package/tests/haClient/history.test.ts +0 -228
- package/tests/haClient/index.test.ts +0 -243
- package/tests/haClient/request.test.ts +0 -217
- package/tests/haClient/services.test.ts +0 -120
- package/tests/haClient/states.test.ts +0 -119
- package/tests/haClient/updates.test.ts +0 -193
- package/tests/index.test.ts +0 -160
- package/tests/integration/homeassistant.test.ts +0 -144
- package/tests/integration/omada.test.ts +0 -167
- package/tests/integration/server.test.ts +0 -151
- package/tests/localAI/index.test.ts +0 -177
- package/tests/localAI/ollama.test.ts +0 -187
- package/tests/localAI/openai.test.ts +0 -257
- package/tests/omadaClient/actions.test.ts +0 -161
- package/tests/omadaClient/clientBlocks.test.ts +0 -170
- package/tests/omadaClient/ntp.test.ts +0 -381
- package/tests/omadaClient/site.test.ts +0 -37
- package/tests/ownerQuestions/service.test.ts +0 -499
- package/tests/ownerQuestions/tools.test.ts +0 -186
- package/tests/permissions/index.test.ts +0 -217
- package/tests/resources/index.test.ts +0 -288
- package/tests/scripts/generateJwt.test.ts +0 -44
- package/tests/security/accessControl.test.ts +0 -223
- package/tests/security/authentication.test.ts +0 -117
- package/tests/security/configuration.test.ts +0 -170
- package/tests/security/cryptoTransport.test.ts +0 -172
- package/tests/security/dependencies.test.ts +0 -152
- package/tests/security/injection.test.ts +0 -117
- package/tests/security/insecureDesign.test.ts +0 -121
- package/tests/security/logging.test.ts +0 -131
- package/tests/security/resourceConsumption.test.ts +0 -142
- package/tests/server/auth.test.ts +0 -249
- package/tests/server/chatFace.test.ts +0 -320
- package/tests/server/common.test.ts +0 -84
- package/tests/server/http.test.ts +0 -561
- package/tests/server/instructions.test.ts +0 -152
- package/tests/server/memoizeJsonSchema.test.ts +0 -71
- package/tests/server/stdio.test.ts +0 -99
- package/tests/server/stream.test.ts +0 -285
- package/tests/server/toolVisibility.http.test.ts +0 -111
- package/tests/server/toolVisibility.test.ts +0 -129
- package/tests/tools/ai/analyzeSensors.test.ts +0 -227
- package/tests/tools/common.test.ts +0 -123
- package/tests/tools/homeassistant/handlers.test.ts +0 -872
- package/tests/tools/infra/invokeAction.test.ts +0 -280
- package/tests/tools/omada/graph.test.ts +0 -385
- package/tests/tools/omada/handlers.test.ts +0 -897
- package/tests/tools/omada/namespace.test.ts +0 -483
- package/tests/tools/registry.test.ts +0 -168
- package/tests/utils/config-validations.test.ts +0 -352
- package/tests/utils/jwt.test.ts +0 -115
- package/tests/utils/logger.test.ts +0 -327
- package/tests/utils/redact.test.ts +0 -105
- package/tsconfig.json +0 -24
- package/vitest.config.ts +0 -38
|
@@ -1,1164 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Omada resource-graph namespace.
|
|
3
|
-
*
|
|
4
|
-
* Instead of registering one MCP tool per Omada endpoint (which explodes the
|
|
5
|
-
* tool-schema budget for small models), graph mode exposes a single discoverable
|
|
6
|
-
* namespace via `omada_browse` (navigate) + `omada_read` (fetch). This manifest is
|
|
7
|
-
* the source of truth mapping graph paths → fetch logic + per-path RBAC.
|
|
8
|
-
*
|
|
9
|
-
* Design (see the "resource graph with lazy expansion" discussion):
|
|
10
|
-
* - `browse` returns resource *types/metadata*, never instances — no enumeration,
|
|
11
|
-
* no controller calls, zero payload explosion.
|
|
12
|
-
* - `read` is where data is fetched: single leaves, collections (optionally a
|
|
13
|
-
* single member via `id`), or paginated logs (single page via page/pageSize).
|
|
14
|
-
* - Authorization is per-path: each node declares the Permission bit it needs.
|
|
15
|
-
* Most nodes are QUERY; the security subtree (`/security/threats`) requires
|
|
16
|
-
* ADMIN, demonstrating that sensitive subtrees can require a higher bit without
|
|
17
|
-
* touching the tools.
|
|
18
|
-
*
|
|
19
|
-
* `graph` mode is a complete superset of `eager` reads: every eager read getter
|
|
20
|
-
* has a corresponding graph node here, including the ADMIN-gated IDS/IPS
|
|
21
|
-
* threat-management log (`/security/threats`), which maps its mandatory epoch
|
|
22
|
-
* time-window onto the required `params.startTime`/`params.endTime` validated by
|
|
23
|
-
* `omada_read` before any controller call.
|
|
24
|
-
*/
|
|
25
|
-
|
|
26
|
-
import type { OmadaClient } from '../../omadaClient/index.js';
|
|
27
|
-
import { Permission } from '../../permissions/index.js';
|
|
28
|
-
|
|
29
|
-
/** Arguments passed from `omada_read` to a node's fetch function. */
|
|
30
|
-
export interface ReadArgs {
|
|
31
|
-
siteId?: string;
|
|
32
|
-
/** Look up a single member of a collection by id/MAC. */
|
|
33
|
-
id?: string;
|
|
34
|
-
/** Path parameters some resources require (e.g. gatewayMac, apMac, deviceMac). */
|
|
35
|
-
params?: Record<string, string>;
|
|
36
|
-
page?: number;
|
|
37
|
-
pageSize?: number;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/** A declared parameter for a resource (surfaced by browse, validated by read). */
|
|
41
|
-
export interface ResourceParam {
|
|
42
|
-
name: string;
|
|
43
|
-
required: boolean;
|
|
44
|
-
description: string;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export type ResourceKind = 'container' | 'collection' | 'leaf';
|
|
48
|
-
|
|
49
|
-
export interface ResourceNode {
|
|
50
|
-
/** Graph path, e.g. '/gateway/wan'. Always normalized (leading slash, no trailing). */
|
|
51
|
-
path: string;
|
|
52
|
-
kind: ResourceKind;
|
|
53
|
-
/** Permission bit required to browse-to / read this node. */
|
|
54
|
-
permission: number;
|
|
55
|
-
description: string;
|
|
56
|
-
estimatedSize?: 'small' | 'medium' | 'large';
|
|
57
|
-
paginated?: boolean;
|
|
58
|
-
defaultPageSize?: number;
|
|
59
|
-
params?: ResourceParam[];
|
|
60
|
-
/** Undefined for pure containers (browse-only — no data of their own). */
|
|
61
|
-
fetch?: (client: OmadaClient, args: ReadArgs) => Promise<unknown>;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const Q = Permission.QUERY;
|
|
65
|
-
const A = Permission.ADMIN;
|
|
66
|
-
|
|
67
|
-
const HOUR_MS = 60 * 60 * 1000;
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Resolve an epoch-MILLISECONDS time window for the event/alert log endpoints
|
|
71
|
-
* (`/sites/{siteId}/logs/{events,alerts}`), which require `filters.timeStart` and
|
|
72
|
-
* `filters.timeEnd`. Explicit `params.startTime`/`params.endTime` win; otherwise
|
|
73
|
-
* default to the last 7 days so a bare `omada_read('/events')` "just works".
|
|
74
|
-
* Exported for unit testing (inject `now` to keep tests deterministic).
|
|
75
|
-
*/
|
|
76
|
-
export function resolveLogWindowMs(
|
|
77
|
-
params: Record<string, string> | undefined,
|
|
78
|
-
now = Date.now()
|
|
79
|
-
): { timeStart: number; timeEnd: number } {
|
|
80
|
-
const timeEnd = params?.endTime ? Number(params.endTime) : now;
|
|
81
|
-
const timeStart = params?.startTime ? Number(params.startTime) : timeEnd - 7 * 24 * HOUR_MS;
|
|
82
|
-
return { timeStart, timeEnd };
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Resolve an epoch-SECONDS time window for the dashboard top-usage endpoints
|
|
87
|
-
* (`top-device-cpu-usage` / `top-device-memory-usage`), which require `start` and
|
|
88
|
-
* `end`. Explicit `params.startTime`/`params.endTime` (seconds) win; otherwise
|
|
89
|
-
* default to the last 24 hours. Exported for unit testing.
|
|
90
|
-
*/
|
|
91
|
-
export function resolveUsageWindowSec(
|
|
92
|
-
params: Record<string, string> | undefined,
|
|
93
|
-
now = Date.now()
|
|
94
|
-
): { start: number; end: number } {
|
|
95
|
-
const end = params?.endTime ? Number(params.endTime) : Math.floor(now / 1000);
|
|
96
|
-
const start = params?.startTime ? Number(params.startTime) : end - 24 * 60 * 60;
|
|
97
|
-
return { start, end };
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Build the optional query filters for the audit-log endpoints from caller params.
|
|
102
|
-
* `startTime`/`endTime` are epoch MILLISECONDS, forwarded as the controller's
|
|
103
|
-
* `filters.startTime`/`filters.endTime`; `searchKey` is fuzzy text. Absent params
|
|
104
|
-
* are omitted so a bare read returns the most recent page unfiltered. Exported for
|
|
105
|
-
* unit testing.
|
|
106
|
-
*/
|
|
107
|
-
export function auditFilters(params: Record<string, string> | undefined): Record<string, unknown> {
|
|
108
|
-
const query: Record<string, unknown> = {};
|
|
109
|
-
if (params?.startTime !== undefined) {
|
|
110
|
-
query['filters.startTime'] = Number(params.startTime);
|
|
111
|
-
}
|
|
112
|
-
if (params?.endTime !== undefined) {
|
|
113
|
-
query['filters.endTime'] = Number(params.endTime);
|
|
114
|
-
}
|
|
115
|
-
if (params?.searchKey) {
|
|
116
|
-
query.searchKey = params.searchKey;
|
|
117
|
-
}
|
|
118
|
-
return query;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* The Omada resource graph. Containers have no `fetch` (browse-only); collections
|
|
123
|
-
* and leaves fetch data. Existing client methods back the well-trodden reads;
|
|
124
|
-
* the generic `client.readResource(...)` backs newly-added endpoints with zero
|
|
125
|
-
* new client code.
|
|
126
|
-
*/
|
|
127
|
-
export const OMADA_RESOURCES: ResourceNode[] = [
|
|
128
|
-
{
|
|
129
|
-
path: '/',
|
|
130
|
-
kind: 'container',
|
|
131
|
-
permission: Q,
|
|
132
|
-
description: 'Root of the Omada network resource graph. Browse children to discover resources.',
|
|
133
|
-
},
|
|
134
|
-
|
|
135
|
-
// ---- Sites -------------------------------------------------------------
|
|
136
|
-
{
|
|
137
|
-
path: '/sites',
|
|
138
|
-
kind: 'collection',
|
|
139
|
-
permission: Q,
|
|
140
|
-
estimatedSize: 'small',
|
|
141
|
-
description: 'All sites on the controller. Most resources are scoped to a site via the optional siteId argument.',
|
|
142
|
-
fetch: (c) => c.listSites(),
|
|
143
|
-
},
|
|
144
|
-
|
|
145
|
-
// ---- Devices (infrastructure) -----------------------------------------
|
|
146
|
-
{
|
|
147
|
-
path: '/devices',
|
|
148
|
-
kind: 'collection',
|
|
149
|
-
permission: Q,
|
|
150
|
-
estimatedSize: 'medium',
|
|
151
|
-
description: 'Network infrastructure (APs, switches, gateways). Pass id=<MAC> to look up a single device.',
|
|
152
|
-
params: [{ name: 'id', required: false, description: 'Device MAC to fetch a single device' }],
|
|
153
|
-
fetch: (c, a) => (a.id ? c.getDevice(a.id, a.siteId) : c.listDevices(a.siteId)),
|
|
154
|
-
},
|
|
155
|
-
{
|
|
156
|
-
path: '/devices/pending',
|
|
157
|
-
kind: 'collection',
|
|
158
|
-
permission: Q,
|
|
159
|
-
paginated: true,
|
|
160
|
-
defaultPageSize: 50,
|
|
161
|
-
estimatedSize: 'small',
|
|
162
|
-
description: 'Devices discovered but not yet adopted into the site (paginated). Use page/pageSize.',
|
|
163
|
-
fetch: (c, a) =>
|
|
164
|
-
c.readResource({
|
|
165
|
-
pathTemplate: '/sites/{siteId}/grid/devices/pending',
|
|
166
|
-
siteId: a.siteId,
|
|
167
|
-
paginated: true,
|
|
168
|
-
page: a.page,
|
|
169
|
-
pageSize: a.pageSize,
|
|
170
|
-
}),
|
|
171
|
-
},
|
|
172
|
-
{
|
|
173
|
-
path: '/devices/stats',
|
|
174
|
-
kind: 'collection',
|
|
175
|
-
permission: Q,
|
|
176
|
-
paginated: true,
|
|
177
|
-
defaultPageSize: 50,
|
|
178
|
-
estimatedSize: 'medium',
|
|
179
|
-
description: 'Per-device statistics (CPU, memory, traffic). Paginated — use page/pageSize.',
|
|
180
|
-
fetch: (c, a) => c.listDevicesStats({ page: a.page ?? 1, pageSize: a.pageSize ?? 50 }),
|
|
181
|
-
},
|
|
182
|
-
{
|
|
183
|
-
path: '/devices/stack',
|
|
184
|
-
kind: 'leaf',
|
|
185
|
-
permission: Q,
|
|
186
|
-
estimatedSize: 'small',
|
|
187
|
-
description: 'Switch-stack detail. Requires stackId.',
|
|
188
|
-
params: [{ name: 'stackId', required: true, description: 'Switch stack identifier' }],
|
|
189
|
-
fetch: (c, a) => c.getSwitchStackDetail(a.params?.stackId ?? '', a.siteId),
|
|
190
|
-
},
|
|
191
|
-
{
|
|
192
|
-
path: '/devices/search',
|
|
193
|
-
kind: 'collection',
|
|
194
|
-
permission: Q,
|
|
195
|
-
estimatedSize: 'small',
|
|
196
|
-
description: 'Search infrastructure devices across all sites by name/MAC/model. Requires searchKey.',
|
|
197
|
-
params: [{ name: 'searchKey', required: true, description: 'Text to match against device name, MAC, or model' }],
|
|
198
|
-
fetch: (c, a) => c.searchDevices(a.params?.searchKey ?? ''),
|
|
199
|
-
},
|
|
200
|
-
|
|
201
|
-
// ---- Cable test (switch port diagnostics) -----------------------------
|
|
202
|
-
{
|
|
203
|
-
path: '/devices/cable-test',
|
|
204
|
-
kind: 'container',
|
|
205
|
-
permission: Q,
|
|
206
|
-
description: 'Switch-port cable diagnostics. Children require a switchMac (find via /devices).',
|
|
207
|
-
},
|
|
208
|
-
{
|
|
209
|
-
path: '/devices/cable-test/ports',
|
|
210
|
-
kind: 'collection',
|
|
211
|
-
permission: Q,
|
|
212
|
-
estimatedSize: 'small',
|
|
213
|
-
description: 'Ports available for cable testing on a switch. Requires switchMac.',
|
|
214
|
-
params: [{ name: 'switchMac', required: true, description: 'Switch MAC address' }],
|
|
215
|
-
fetch: (c, a) =>
|
|
216
|
-
c.readResource({
|
|
217
|
-
pathTemplate: '/sites/{siteId}/cable-test/switches/{switchMac}/ports',
|
|
218
|
-
siteId: a.siteId,
|
|
219
|
-
pathParams: { switchMac: a.params?.switchMac ?? '' },
|
|
220
|
-
}),
|
|
221
|
-
},
|
|
222
|
-
{
|
|
223
|
-
path: '/devices/cable-test/results',
|
|
224
|
-
kind: 'leaf',
|
|
225
|
-
permission: Q,
|
|
226
|
-
estimatedSize: 'small',
|
|
227
|
-
description: 'Full cable-test results (pair status, length, fault distance) for a switch. Requires switchMac.',
|
|
228
|
-
params: [{ name: 'switchMac', required: true, description: 'Switch MAC address' }],
|
|
229
|
-
fetch: (c, a) =>
|
|
230
|
-
c.readResource({
|
|
231
|
-
pathTemplate: '/sites/{siteId}/cable-test/switches/{switchMac}/full-results',
|
|
232
|
-
siteId: a.siteId,
|
|
233
|
-
pathParams: { switchMac: a.params?.switchMac ?? '' },
|
|
234
|
-
}),
|
|
235
|
-
},
|
|
236
|
-
{
|
|
237
|
-
path: '/devices/cable-test/logs',
|
|
238
|
-
kind: 'collection',
|
|
239
|
-
permission: Q,
|
|
240
|
-
estimatedSize: 'small',
|
|
241
|
-
description: 'Cable-test run history for a switch. Requires switchMac.',
|
|
242
|
-
params: [{ name: 'switchMac', required: true, description: 'Switch MAC address' }],
|
|
243
|
-
fetch: (c, a) =>
|
|
244
|
-
c.readResource({
|
|
245
|
-
pathTemplate: '/sites/{siteId}/cable-test/switches/{switchMac}/logs',
|
|
246
|
-
siteId: a.siteId,
|
|
247
|
-
pathParams: { switchMac: a.params?.switchMac ?? '' },
|
|
248
|
-
}),
|
|
249
|
-
},
|
|
250
|
-
{
|
|
251
|
-
path: '/devices/poe',
|
|
252
|
-
kind: 'collection',
|
|
253
|
-
permission: Q,
|
|
254
|
-
paginated: true,
|
|
255
|
-
defaultPageSize: 50,
|
|
256
|
-
estimatedSize: 'small',
|
|
257
|
-
description: 'Per-port PoE status across switches (which ports deliver power, to what, and how much). Paginated.',
|
|
258
|
-
fetch: (c, a) =>
|
|
259
|
-
c.readResource({
|
|
260
|
-
pathTemplate: '/sites/{siteId}/switches/ports/poe-info',
|
|
261
|
-
siteId: a.siteId,
|
|
262
|
-
paginated: true,
|
|
263
|
-
page: a.page,
|
|
264
|
-
pageSize: a.pageSize,
|
|
265
|
-
}),
|
|
266
|
-
},
|
|
267
|
-
{
|
|
268
|
-
path: '/devices/lldp',
|
|
269
|
-
kind: 'collection',
|
|
270
|
-
permission: Q,
|
|
271
|
-
estimatedSize: 'small',
|
|
272
|
-
description: 'Site-wide LLDP neighbor information (physical link/topology discovery between devices).',
|
|
273
|
-
fetch: (c, a) => c.readResource({ pathTemplate: '/sites/{siteId}/lldp', siteId: a.siteId }),
|
|
274
|
-
},
|
|
275
|
-
|
|
276
|
-
// ---- Clients (connected users) ----------------------------------------
|
|
277
|
-
{
|
|
278
|
-
path: '/clients',
|
|
279
|
-
kind: 'collection',
|
|
280
|
-
permission: Q,
|
|
281
|
-
estimatedSize: 'large',
|
|
282
|
-
description: 'Connected clients (phones, laptops, IoT). Pass id=<MAC> to look up a single client.',
|
|
283
|
-
params: [{ name: 'id', required: false, description: 'Client MAC to fetch a single client' }],
|
|
284
|
-
fetch: (c, a) => (a.id ? c.getClient(a.id, a.siteId) : c.listClients(a.siteId)),
|
|
285
|
-
},
|
|
286
|
-
{
|
|
287
|
-
path: '/clients/active',
|
|
288
|
-
kind: 'collection',
|
|
289
|
-
permission: Q,
|
|
290
|
-
estimatedSize: 'small',
|
|
291
|
-
description: 'Most active clients by traffic.',
|
|
292
|
-
fetch: (c, a) => c.listMostActiveClients(a.siteId),
|
|
293
|
-
},
|
|
294
|
-
{
|
|
295
|
-
path: '/clients/known',
|
|
296
|
-
kind: 'collection',
|
|
297
|
-
permission: Q,
|
|
298
|
-
paginated: true,
|
|
299
|
-
defaultPageSize: 50,
|
|
300
|
-
estimatedSize: 'medium',
|
|
301
|
-
description:
|
|
302
|
-
'Clients the controller remembers, online and offline, with their block state (paginated; use page/pageSize). ' +
|
|
303
|
-
'Blocked clients have block=true; the controller cannot filter by it, so check every page.',
|
|
304
|
-
fetch: (c, a) =>
|
|
305
|
-
c.readResource({
|
|
306
|
-
pathTemplate: '/sites/{siteId}/insight/clients',
|
|
307
|
-
siteId: a.siteId,
|
|
308
|
-
paginated: true,
|
|
309
|
-
page: a.page,
|
|
310
|
-
pageSize: a.pageSize,
|
|
311
|
-
}),
|
|
312
|
-
},
|
|
313
|
-
{
|
|
314
|
-
path: '/clients/activity',
|
|
315
|
-
kind: 'collection',
|
|
316
|
-
permission: Q,
|
|
317
|
-
estimatedSize: 'medium',
|
|
318
|
-
description: 'Per-client activity (traffic over time). Optional time window via params.start/params.end (epoch seconds).',
|
|
319
|
-
params: [
|
|
320
|
-
{ name: 'start', required: false, description: 'Start timestamp, epoch seconds' },
|
|
321
|
-
{ name: 'end', required: false, description: 'End timestamp, epoch seconds' },
|
|
322
|
-
],
|
|
323
|
-
fetch: (c, a) =>
|
|
324
|
-
c.listClientsActivity({
|
|
325
|
-
siteId: a.siteId,
|
|
326
|
-
start: a.params?.start !== undefined ? Number(a.params.start) : undefined,
|
|
327
|
-
end: a.params?.end !== undefined ? Number(a.params.end) : undefined,
|
|
328
|
-
}),
|
|
329
|
-
},
|
|
330
|
-
{
|
|
331
|
-
path: '/clients/past-connections',
|
|
332
|
-
kind: 'collection',
|
|
333
|
-
permission: Q,
|
|
334
|
-
paginated: true,
|
|
335
|
-
defaultPageSize: 50,
|
|
336
|
-
estimatedSize: 'large',
|
|
337
|
-
description: 'Historical client connections (paginated). Use page/pageSize.',
|
|
338
|
-
fetch: (c, a) => c.listClientsPastConnections({ siteId: a.siteId, page: a.page ?? 1, pageSize: a.pageSize ?? 50 }),
|
|
339
|
-
},
|
|
340
|
-
|
|
341
|
-
// ---- Gateway -----------------------------------------------------------
|
|
342
|
-
{ path: '/gateway', kind: 'container', permission: Q, description: 'Gateway/router status and connectivity.' },
|
|
343
|
-
{
|
|
344
|
-
path: '/gateway/wan',
|
|
345
|
-
kind: 'leaf',
|
|
346
|
-
permission: Q,
|
|
347
|
-
estimatedSize: 'small',
|
|
348
|
-
description: 'WAN port status for a gateway: WAN IP, DNS, uptime, link speed, TX/RX. Requires gatewayMac (find via /devices).',
|
|
349
|
-
params: [{ name: 'gatewayMac', required: true, description: 'Gateway MAC address' }],
|
|
350
|
-
fetch: (c, a) =>
|
|
351
|
-
c.readResource({
|
|
352
|
-
pathTemplate: '/sites/{siteId}/gateways/{gatewayMac}/wan-status',
|
|
353
|
-
siteId: a.siteId,
|
|
354
|
-
pathParams: { gatewayMac: a.params?.gatewayMac ?? '' },
|
|
355
|
-
}),
|
|
356
|
-
},
|
|
357
|
-
{
|
|
358
|
-
path: '/gateway/health',
|
|
359
|
-
kind: 'leaf',
|
|
360
|
-
permission: Q,
|
|
361
|
-
estimatedSize: 'small',
|
|
362
|
-
description: 'Detailed per-WAN health for a gateway. Requires gatewayMac (find via /devices).',
|
|
363
|
-
params: [{ name: 'gatewayMac', required: true, description: 'Gateway MAC address' }],
|
|
364
|
-
fetch: (c, a) =>
|
|
365
|
-
c.readResource({
|
|
366
|
-
pathTemplate: '/sites/{siteId}/health/gateways/{gatewayMac}/wans/details',
|
|
367
|
-
siteId: a.siteId,
|
|
368
|
-
pathParams: { gatewayMac: a.params?.gatewayMac ?? '' },
|
|
369
|
-
}),
|
|
370
|
-
},
|
|
371
|
-
|
|
372
|
-
// ---- Network config ----------------------------------------------------
|
|
373
|
-
{ path: '/network', kind: 'container', permission: Q, description: 'Network configuration: internet, LANs, WLAN groups, firewall.' },
|
|
374
|
-
{
|
|
375
|
-
path: '/network/internet',
|
|
376
|
-
kind: 'leaf',
|
|
377
|
-
permission: Q,
|
|
378
|
-
estimatedSize: 'small',
|
|
379
|
-
description: 'Internet/WAN connection information for the site.',
|
|
380
|
-
fetch: (c, a) => c.getInternetInfo(a.siteId),
|
|
381
|
-
},
|
|
382
|
-
{
|
|
383
|
-
path: '/network/ntp',
|
|
384
|
-
kind: 'leaf',
|
|
385
|
-
permission: Q,
|
|
386
|
-
estimatedSize: 'small',
|
|
387
|
-
description: 'NTP (network time) server configuration and status for the site.',
|
|
388
|
-
fetch: (c, a) => c.getSiteNtpStatus(a.siteId),
|
|
389
|
-
},
|
|
390
|
-
{
|
|
391
|
-
path: '/network/lan-networks',
|
|
392
|
-
kind: 'collection',
|
|
393
|
-
permission: Q,
|
|
394
|
-
estimatedSize: 'small',
|
|
395
|
-
description: 'Configured LAN networks / VLANs.',
|
|
396
|
-
fetch: (c, a) => c.getLanNetworkList(a.siteId),
|
|
397
|
-
},
|
|
398
|
-
{
|
|
399
|
-
path: '/network/lan-profiles',
|
|
400
|
-
kind: 'collection',
|
|
401
|
-
permission: Q,
|
|
402
|
-
estimatedSize: 'small',
|
|
403
|
-
description: 'LAN profiles.',
|
|
404
|
-
fetch: (c, a) => c.getLanProfileList(a.siteId),
|
|
405
|
-
},
|
|
406
|
-
{
|
|
407
|
-
path: '/network/wlan-groups',
|
|
408
|
-
kind: 'collection',
|
|
409
|
-
permission: Q,
|
|
410
|
-
estimatedSize: 'small',
|
|
411
|
-
description: 'WLAN groups.',
|
|
412
|
-
fetch: (c, a) => c.getWlanGroupList(a.siteId),
|
|
413
|
-
},
|
|
414
|
-
{
|
|
415
|
-
path: '/network/firewall',
|
|
416
|
-
kind: 'leaf',
|
|
417
|
-
permission: Q,
|
|
418
|
-
estimatedSize: 'small',
|
|
419
|
-
description: 'Gateway firewall settings for the site.',
|
|
420
|
-
fetch: (c, a) => c.getFirewallSetting(a.siteId),
|
|
421
|
-
},
|
|
422
|
-
{
|
|
423
|
-
path: '/network/port-forwarding',
|
|
424
|
-
kind: 'collection',
|
|
425
|
-
permission: Q,
|
|
426
|
-
paginated: true,
|
|
427
|
-
defaultPageSize: 10,
|
|
428
|
-
estimatedSize: 'small',
|
|
429
|
-
description: "Port-forwarding status (paginated). params.type is 'User' (default) or 'UPnP'.",
|
|
430
|
-
params: [{ name: 'type', required: false, description: "'User' (default) or 'UPnP'" }],
|
|
431
|
-
fetch: (c, a) =>
|
|
432
|
-
c.getPortForwardingStatus(a.params?.type === 'UPnP' ? 'UPnP' : 'User', a.siteId, a.page ?? 1, a.pageSize ?? 10),
|
|
433
|
-
},
|
|
434
|
-
{
|
|
435
|
-
path: '/network/port-forwarding/rules',
|
|
436
|
-
kind: 'collection',
|
|
437
|
-
permission: Q,
|
|
438
|
-
paginated: true,
|
|
439
|
-
defaultPageSize: 50,
|
|
440
|
-
estimatedSize: 'small',
|
|
441
|
-
description: 'Configured NAT port-forwarding rules (the full rule list, not just status). Paginated — use page/pageSize.',
|
|
442
|
-
fetch: (c, a) =>
|
|
443
|
-
c.readResource({
|
|
444
|
-
pathTemplate: '/sites/{siteId}/nat/port-forwardings',
|
|
445
|
-
siteId: a.siteId,
|
|
446
|
-
paginated: true,
|
|
447
|
-
page: a.page,
|
|
448
|
-
pageSize: a.pageSize,
|
|
449
|
-
}),
|
|
450
|
-
},
|
|
451
|
-
{
|
|
452
|
-
path: '/network/dhcp-leases',
|
|
453
|
-
kind: 'collection',
|
|
454
|
-
permission: Q,
|
|
455
|
-
paginated: true,
|
|
456
|
-
defaultPageSize: 50,
|
|
457
|
-
estimatedSize: 'medium',
|
|
458
|
-
description: 'Active DHCP leases across all DHCP servers on the site (paginated). Use page/pageSize. See /network/dhcp-reservations for static reservations.',
|
|
459
|
-
fetch: (c, a) =>
|
|
460
|
-
c.readResource({
|
|
461
|
-
pathTemplate: '/sites/{siteId}/setting/service/dhcp/user-list',
|
|
462
|
-
siteId: a.siteId,
|
|
463
|
-
paginated: true,
|
|
464
|
-
page: a.page,
|
|
465
|
-
pageSize: a.pageSize,
|
|
466
|
-
}),
|
|
467
|
-
},
|
|
468
|
-
{
|
|
469
|
-
path: '/network/load-balance',
|
|
470
|
-
kind: 'leaf',
|
|
471
|
-
permission: Q,
|
|
472
|
-
estimatedSize: 'small',
|
|
473
|
-
description: 'Multi-WAN load-balance status for the gateway (which WANs are up / in the balancing pool).',
|
|
474
|
-
fetch: (c, a) => c.readResource({ pathTemplate: '/sites/{siteId}/internet/load-balance/status', siteId: a.siteId }),
|
|
475
|
-
},
|
|
476
|
-
{
|
|
477
|
-
path: '/network/dhcp-reservations',
|
|
478
|
-
kind: 'collection',
|
|
479
|
-
permission: Q,
|
|
480
|
-
paginated: true,
|
|
481
|
-
defaultPageSize: 50,
|
|
482
|
-
estimatedSize: 'small',
|
|
483
|
-
description: 'Static DHCP reservations (each maps a client MAC to a fixed IP). Paginated. See /network/dhcp-leases for active leases.',
|
|
484
|
-
fetch: (c, a) =>
|
|
485
|
-
c.readResource({
|
|
486
|
-
pathTemplate: '/sites/{siteId}/setting/service/dhcp',
|
|
487
|
-
siteId: a.siteId,
|
|
488
|
-
paginated: true,
|
|
489
|
-
page: a.page,
|
|
490
|
-
pageSize: a.pageSize,
|
|
491
|
-
}),
|
|
492
|
-
},
|
|
493
|
-
{
|
|
494
|
-
path: '/network/static-routes',
|
|
495
|
-
kind: 'collection',
|
|
496
|
-
permission: Q,
|
|
497
|
-
paginated: true,
|
|
498
|
-
defaultPageSize: 50,
|
|
499
|
-
estimatedSize: 'small',
|
|
500
|
-
description: 'Configured static routes for the gateway (destination → next-hop). Paginated.',
|
|
501
|
-
fetch: (c, a) =>
|
|
502
|
-
c.readResource({
|
|
503
|
-
pathTemplate: '/sites/{siteId}/routing/static-routings',
|
|
504
|
-
siteId: a.siteId,
|
|
505
|
-
paginated: true,
|
|
506
|
-
page: a.page,
|
|
507
|
-
pageSize: a.pageSize,
|
|
508
|
-
}),
|
|
509
|
-
},
|
|
510
|
-
{
|
|
511
|
-
path: '/network/ip-mac-binding',
|
|
512
|
-
kind: 'collection',
|
|
513
|
-
permission: Q,
|
|
514
|
-
paginated: true,
|
|
515
|
-
defaultPageSize: 50,
|
|
516
|
-
estimatedSize: 'small',
|
|
517
|
-
description: 'IP↔MAC binding entries (ARP-spoofing protection: which MACs are pinned to which IPs). Paginated.',
|
|
518
|
-
fetch: (c, a) =>
|
|
519
|
-
c.readResource({
|
|
520
|
-
pathTemplate: '/sites/{siteId}/ip-mac-binds',
|
|
521
|
-
siteId: a.siteId,
|
|
522
|
-
paginated: true,
|
|
523
|
-
page: a.page,
|
|
524
|
-
pageSize: a.pageSize,
|
|
525
|
-
}),
|
|
526
|
-
},
|
|
527
|
-
{
|
|
528
|
-
path: '/network/attack-defense',
|
|
529
|
-
kind: 'leaf',
|
|
530
|
-
permission: Q,
|
|
531
|
-
estimatedSize: 'small',
|
|
532
|
-
description: 'Gateway attack-defense settings (flood/scan/spoof protection toggles and thresholds).',
|
|
533
|
-
fetch: (c, a) => c.readResource({ pathTemplate: '/sites/{siteId}/attack-defense', siteId: a.siteId }),
|
|
534
|
-
},
|
|
535
|
-
|
|
536
|
-
// ---- Access-control lists (read-only policy visibility) ---------------
|
|
537
|
-
{ path: '/network/acls', kind: 'container', permission: Q, description: 'Access-control lists by enforcement point (gateway, switch, EAP/AP).' },
|
|
538
|
-
{
|
|
539
|
-
path: '/network/acls/gateway',
|
|
540
|
-
kind: 'collection',
|
|
541
|
-
permission: Q,
|
|
542
|
-
paginated: true,
|
|
543
|
-
defaultPageSize: 50,
|
|
544
|
-
estimatedSize: 'small',
|
|
545
|
-
description: 'Gateway ACL rules (osg-acls). Paginated.',
|
|
546
|
-
fetch: (c, a) =>
|
|
547
|
-
c.readResource({ pathTemplate: '/sites/{siteId}/acls/osg-acls', siteId: a.siteId, paginated: true, page: a.page, pageSize: a.pageSize }),
|
|
548
|
-
},
|
|
549
|
-
{
|
|
550
|
-
path: '/network/acls/switch',
|
|
551
|
-
kind: 'collection',
|
|
552
|
-
permission: Q,
|
|
553
|
-
paginated: true,
|
|
554
|
-
defaultPageSize: 50,
|
|
555
|
-
estimatedSize: 'small',
|
|
556
|
-
description: 'Switch ACL rules (osw-acls). Paginated.',
|
|
557
|
-
fetch: (c, a) =>
|
|
558
|
-
c.readResource({ pathTemplate: '/sites/{siteId}/acls/osw-acls', siteId: a.siteId, paginated: true, page: a.page, pageSize: a.pageSize }),
|
|
559
|
-
},
|
|
560
|
-
{
|
|
561
|
-
path: '/network/acls/eap',
|
|
562
|
-
kind: 'collection',
|
|
563
|
-
permission: Q,
|
|
564
|
-
paginated: true,
|
|
565
|
-
defaultPageSize: 50,
|
|
566
|
-
estimatedSize: 'small',
|
|
567
|
-
description: 'EAP/AP ACL rules (eap-acls). Paginated.',
|
|
568
|
-
fetch: (c, a) =>
|
|
569
|
-
c.readResource({ pathTemplate: '/sites/{siteId}/acls/eap-acls', siteId: a.siteId, paginated: true, page: a.page, pageSize: a.pageSize }),
|
|
570
|
-
},
|
|
571
|
-
|
|
572
|
-
// ---- URL filtering (content controls) ---------------------------------
|
|
573
|
-
{ path: '/network/url-filters', kind: 'container', permission: Q, description: 'URL-filtering rules (content/parental controls) by enforcement point.' },
|
|
574
|
-
{
|
|
575
|
-
path: '/network/url-filters/gateway',
|
|
576
|
-
kind: 'collection',
|
|
577
|
-
permission: Q,
|
|
578
|
-
paginated: true,
|
|
579
|
-
defaultPageSize: 50,
|
|
580
|
-
estimatedSize: 'small',
|
|
581
|
-
description: 'Gateway URL-filter rules. Paginated.',
|
|
582
|
-
fetch: (c, a) =>
|
|
583
|
-
c.readResource({ pathTemplate: '/sites/{siteId}/url-filters/gateway', siteId: a.siteId, paginated: true, page: a.page, pageSize: a.pageSize }),
|
|
584
|
-
},
|
|
585
|
-
{
|
|
586
|
-
path: '/network/url-filters/eap',
|
|
587
|
-
kind: 'collection',
|
|
588
|
-
permission: Q,
|
|
589
|
-
paginated: true,
|
|
590
|
-
defaultPageSize: 50,
|
|
591
|
-
estimatedSize: 'small',
|
|
592
|
-
description: 'EAP/AP URL-filter rules. Paginated.',
|
|
593
|
-
fetch: (c, a) =>
|
|
594
|
-
c.readResource({ pathTemplate: '/sites/{siteId}/url-filters/eap', siteId: a.siteId, paginated: true, page: a.page, pageSize: a.pageSize }),
|
|
595
|
-
},
|
|
596
|
-
|
|
597
|
-
// ---- MAC filtering -----------------------------------------------------
|
|
598
|
-
{ path: '/network/mac-filters', kind: 'container', permission: Q, description: 'Wireless MAC allow/deny filtering lists.' },
|
|
599
|
-
{
|
|
600
|
-
path: '/network/mac-filters/allow',
|
|
601
|
-
kind: 'collection',
|
|
602
|
-
permission: Q,
|
|
603
|
-
paginated: true,
|
|
604
|
-
defaultPageSize: 50,
|
|
605
|
-
estimatedSize: 'small',
|
|
606
|
-
description: 'MAC addresses on the allow list. Paginated.',
|
|
607
|
-
fetch: (c, a) =>
|
|
608
|
-
c.readResource({ pathTemplate: '/sites/{siteId}/mac-filters/allow', siteId: a.siteId, paginated: true, page: a.page, pageSize: a.pageSize }),
|
|
609
|
-
},
|
|
610
|
-
{
|
|
611
|
-
path: '/network/mac-filters/deny',
|
|
612
|
-
kind: 'collection',
|
|
613
|
-
permission: Q,
|
|
614
|
-
paginated: true,
|
|
615
|
-
defaultPageSize: 50,
|
|
616
|
-
estimatedSize: 'small',
|
|
617
|
-
description: 'MAC addresses on the deny list. Paginated.',
|
|
618
|
-
fetch: (c, a) =>
|
|
619
|
-
c.readResource({ pathTemplate: '/sites/{siteId}/mac-filters/deny', siteId: a.siteId, paginated: true, page: a.page, pageSize: a.pageSize }),
|
|
620
|
-
},
|
|
621
|
-
{
|
|
622
|
-
path: '/network/rate-limit-profiles',
|
|
623
|
-
kind: 'collection',
|
|
624
|
-
permission: Q,
|
|
625
|
-
estimatedSize: 'small',
|
|
626
|
-
description: 'Configured client rate-limit profiles (input for the rate-limit write tools).',
|
|
627
|
-
fetch: (c, a) => c.getRateLimitProfiles(a.siteId),
|
|
628
|
-
},
|
|
629
|
-
|
|
630
|
-
// ---- WiFi / wireless security -----------------------------------------
|
|
631
|
-
{ path: '/wifi', kind: 'container', permission: Q, description: 'Wireless: SSIDs, speed tests, rogue-AP and intrusion detection.' },
|
|
632
|
-
{
|
|
633
|
-
path: '/wifi/speedtest',
|
|
634
|
-
kind: 'leaf',
|
|
635
|
-
permission: Q,
|
|
636
|
-
estimatedSize: 'small',
|
|
637
|
-
description: 'Latest speed-test result for an access point. Requires apMac (find via /devices).',
|
|
638
|
-
params: [{ name: 'apMac', required: true, description: 'Access point MAC address' }],
|
|
639
|
-
fetch: (c, a) =>
|
|
640
|
-
c.readResource({
|
|
641
|
-
pathTemplate: '/sites/{siteId}/aps/{apMac}/speed-test-result',
|
|
642
|
-
siteId: a.siteId,
|
|
643
|
-
pathParams: { apMac: a.params?.apMac ?? '' },
|
|
644
|
-
}),
|
|
645
|
-
},
|
|
646
|
-
{
|
|
647
|
-
path: '/wifi/rogue',
|
|
648
|
-
kind: 'collection',
|
|
649
|
-
permission: Q,
|
|
650
|
-
paginated: true,
|
|
651
|
-
defaultPageSize: 50,
|
|
652
|
-
estimatedSize: 'small',
|
|
653
|
-
description: 'Rogue access points detected near the site (paginated). Use page/pageSize.',
|
|
654
|
-
fetch: (c, a) =>
|
|
655
|
-
c.readResource({
|
|
656
|
-
pathTemplate: '/sites/{siteId}/insight/rogueaps',
|
|
657
|
-
siteId: a.siteId,
|
|
658
|
-
paginated: true,
|
|
659
|
-
page: a.page,
|
|
660
|
-
pageSize: a.pageSize,
|
|
661
|
-
}),
|
|
662
|
-
},
|
|
663
|
-
{
|
|
664
|
-
path: '/wifi/wids',
|
|
665
|
-
kind: 'collection',
|
|
666
|
-
permission: Q,
|
|
667
|
-
paginated: true,
|
|
668
|
-
defaultPageSize: 50,
|
|
669
|
-
estimatedSize: 'small',
|
|
670
|
-
description:
|
|
671
|
-
'Wireless Intrusion Detection System (WIDS) entries (paginated). Use page/pageSize. ' +
|
|
672
|
-
'Note: the controller restricts this endpoint to Omada Pro controllers/sites; on a ' +
|
|
673
|
-
'standard controller it returns a "Pro only" message rather than data.',
|
|
674
|
-
fetch: (c, a) =>
|
|
675
|
-
c.readResource({
|
|
676
|
-
pathTemplate: '/sites/{siteId}/insight/wids',
|
|
677
|
-
siteId: a.siteId,
|
|
678
|
-
paginated: true,
|
|
679
|
-
page: a.page,
|
|
680
|
-
pageSize: a.pageSize,
|
|
681
|
-
}),
|
|
682
|
-
},
|
|
683
|
-
{
|
|
684
|
-
path: '/wifi/ssids',
|
|
685
|
-
kind: 'collection',
|
|
686
|
-
permission: Q,
|
|
687
|
-
estimatedSize: 'small',
|
|
688
|
-
description: 'SSIDs in a WLAN group. Requires wlanId; pass params.ssidId too to fetch a single SSID detail.',
|
|
689
|
-
params: [
|
|
690
|
-
{ name: 'wlanId', required: true, description: 'WLAN group id (find via /network/wlan-groups)' },
|
|
691
|
-
{ name: 'ssidId', required: false, description: 'SSID id — when set, returns that SSID detail instead of the list' },
|
|
692
|
-
],
|
|
693
|
-
fetch: (c, a) =>
|
|
694
|
-
a.params?.ssidId
|
|
695
|
-
? c.getSsidDetail(a.params.wlanId ?? '', a.params.ssidId, a.siteId)
|
|
696
|
-
: c.getSsidList(a.params?.wlanId ?? '', a.siteId),
|
|
697
|
-
},
|
|
698
|
-
{
|
|
699
|
-
path: '/wifi/band-steering',
|
|
700
|
-
kind: 'leaf',
|
|
701
|
-
permission: Q,
|
|
702
|
-
estimatedSize: 'small',
|
|
703
|
-
description: 'Band-steering settings for the site (steering clients between 2.4/5/6 GHz radios).',
|
|
704
|
-
fetch: (c, a) => c.readResource({ pathTemplate: '/sites/{siteId}/band-steering', siteId: a.siteId }),
|
|
705
|
-
},
|
|
706
|
-
|
|
707
|
-
// ---- Events / alerts (paginated) --------------------------------------
|
|
708
|
-
{
|
|
709
|
-
path: '/events',
|
|
710
|
-
kind: 'collection',
|
|
711
|
-
permission: Q,
|
|
712
|
-
paginated: true,
|
|
713
|
-
defaultPageSize: 50,
|
|
714
|
-
estimatedSize: 'large',
|
|
715
|
-
description:
|
|
716
|
-
'Site event log (paginated). Use page/pageSize. The controller requires a time window: by default this ' +
|
|
717
|
-
'returns the last 7 days. Override with params.startTime / params.endTime (epoch MILLISECONDS, e.g. ' +
|
|
718
|
-
'1679297710438). Optional params.module filters by source module.',
|
|
719
|
-
params: [
|
|
720
|
-
{ name: 'startTime', required: false, description: 'Window start, epoch ms (default: 7 days ago)' },
|
|
721
|
-
{ name: 'endTime', required: false, description: 'Window end, epoch ms (default: now)' },
|
|
722
|
-
{ name: 'module', required: false, description: 'Filter by module (e.g. "Device", "Client", "User")' },
|
|
723
|
-
],
|
|
724
|
-
fetch: (c, a) => {
|
|
725
|
-
const { timeStart, timeEnd } = resolveLogWindowMs(a.params);
|
|
726
|
-
const query: Record<string, unknown> = { 'filters.timeStart': timeStart, 'filters.timeEnd': timeEnd };
|
|
727
|
-
if (a.params?.module) {
|
|
728
|
-
query['filters.module'] = a.params.module;
|
|
729
|
-
}
|
|
730
|
-
return c.readResource({ pathTemplate: '/sites/{siteId}/logs/events', siteId: a.siteId, paginated: true, page: a.page, pageSize: a.pageSize, query });
|
|
731
|
-
},
|
|
732
|
-
},
|
|
733
|
-
{
|
|
734
|
-
path: '/events/alerts',
|
|
735
|
-
kind: 'collection',
|
|
736
|
-
permission: Q,
|
|
737
|
-
paginated: true,
|
|
738
|
-
defaultPageSize: 50,
|
|
739
|
-
estimatedSize: 'large',
|
|
740
|
-
description:
|
|
741
|
-
'Site alert log (paginated). Use page/pageSize. The controller requires a time window: by default this ' +
|
|
742
|
-
'returns the last 7 days. Override with params.startTime / params.endTime (epoch MILLISECONDS). Optional ' +
|
|
743
|
-
'params.module filters by source module; params.resolved ("true"/"false") filters by resolution state.',
|
|
744
|
-
params: [
|
|
745
|
-
{ name: 'startTime', required: false, description: 'Window start, epoch ms (default: 7 days ago)' },
|
|
746
|
-
{ name: 'endTime', required: false, description: 'Window end, epoch ms (default: now)' },
|
|
747
|
-
{ name: 'module', required: false, description: 'Filter by module (e.g. "Device", "Client", "User")' },
|
|
748
|
-
{ name: 'resolved', required: false, description: '"true" or "false" to filter by resolution state' },
|
|
749
|
-
],
|
|
750
|
-
fetch: (c, a) => {
|
|
751
|
-
const { timeStart, timeEnd } = resolveLogWindowMs(a.params);
|
|
752
|
-
const query: Record<string, unknown> = { 'filters.timeStart': timeStart, 'filters.timeEnd': timeEnd };
|
|
753
|
-
if (a.params?.module) {
|
|
754
|
-
query['filters.module'] = a.params.module;
|
|
755
|
-
}
|
|
756
|
-
if (a.params?.resolved === 'true' || a.params?.resolved === 'false') {
|
|
757
|
-
query['filters.resolved'] = a.params.resolved;
|
|
758
|
-
}
|
|
759
|
-
return c.readResource({ pathTemplate: '/sites/{siteId}/logs/alerts', siteId: a.siteId, paginated: true, page: a.page, pageSize: a.pageSize, query });
|
|
760
|
-
},
|
|
761
|
-
},
|
|
762
|
-
|
|
763
|
-
// ---- Dashboard ---------------------------------------------------------
|
|
764
|
-
{
|
|
765
|
-
path: '/dashboard',
|
|
766
|
-
kind: 'leaf',
|
|
767
|
-
permission: Q,
|
|
768
|
-
estimatedSize: 'medium',
|
|
769
|
-
description: 'Site dashboard overview diagram (topology + summary).',
|
|
770
|
-
fetch: (c, a) => c.readResource({ pathTemplate: '/sites/{siteId}/dashboard/overview-diagram', siteId: a.siteId }),
|
|
771
|
-
},
|
|
772
|
-
{
|
|
773
|
-
path: '/dashboard/cpu',
|
|
774
|
-
kind: 'collection',
|
|
775
|
-
permission: Q,
|
|
776
|
-
estimatedSize: 'small',
|
|
777
|
-
description:
|
|
778
|
-
'Devices with the highest CPU usage over a time window (default: last 24h). Override with params.startTime / ' +
|
|
779
|
-
'params.endTime (epoch SECONDS, e.g. 1682000000).',
|
|
780
|
-
params: [
|
|
781
|
-
{ name: 'startTime', required: false, description: 'Window start, epoch seconds (default: 24h ago)' },
|
|
782
|
-
{ name: 'endTime', required: false, description: 'Window end, epoch seconds (default: now)' },
|
|
783
|
-
],
|
|
784
|
-
fetch: (c, a) =>
|
|
785
|
-
c.readResource({ pathTemplate: '/sites/{siteId}/dashboard/top-device-cpu-usage', siteId: a.siteId, query: resolveUsageWindowSec(a.params) }),
|
|
786
|
-
},
|
|
787
|
-
{
|
|
788
|
-
path: '/dashboard/memory',
|
|
789
|
-
kind: 'collection',
|
|
790
|
-
permission: Q,
|
|
791
|
-
estimatedSize: 'small',
|
|
792
|
-
description:
|
|
793
|
-
'Devices with the highest memory usage over a time window (default: last 24h). Override with params.startTime / ' +
|
|
794
|
-
'params.endTime (epoch SECONDS, e.g. 1682000000).',
|
|
795
|
-
params: [
|
|
796
|
-
{ name: 'startTime', required: false, description: 'Window start, epoch seconds (default: 24h ago)' },
|
|
797
|
-
{ name: 'endTime', required: false, description: 'Window end, epoch seconds (default: now)' },
|
|
798
|
-
],
|
|
799
|
-
fetch: (c, a) =>
|
|
800
|
-
c.readResource({ pathTemplate: '/sites/{siteId}/dashboard/top-device-memory-usage', siteId: a.siteId, query: resolveUsageWindowSec(a.params) }),
|
|
801
|
-
},
|
|
802
|
-
{
|
|
803
|
-
path: '/dashboard/client-distribution',
|
|
804
|
-
kind: 'leaf',
|
|
805
|
-
permission: Q,
|
|
806
|
-
estimatedSize: 'small',
|
|
807
|
-
description: 'Breakdown of connected clients by category (wired/wireless, band, SSID). No time window required.',
|
|
808
|
-
fetch: (c, a) => c.readResource({ pathTemplate: '/sites/{siteId}/dashboard/client-distribution', siteId: a.siteId }),
|
|
809
|
-
},
|
|
810
|
-
{
|
|
811
|
-
path: '/dashboard/traffic-distribution',
|
|
812
|
-
kind: 'leaf',
|
|
813
|
-
permission: Q,
|
|
814
|
-
estimatedSize: 'small',
|
|
815
|
-
description:
|
|
816
|
-
'Traffic distribution across the site over a time window (default: last 24h). Override with params.startTime / ' +
|
|
817
|
-
'params.endTime (epoch SECONDS).',
|
|
818
|
-
params: [
|
|
819
|
-
{ name: 'startTime', required: false, description: 'Window start, epoch seconds (default: 24h ago)' },
|
|
820
|
-
{ name: 'endTime', required: false, description: 'Window end, epoch seconds (default: now)' },
|
|
821
|
-
],
|
|
822
|
-
fetch: (c, a) =>
|
|
823
|
-
c.readResource({ pathTemplate: '/sites/{siteId}/dashboard/traffic-distribution', siteId: a.siteId, query: resolveUsageWindowSec(a.params) }),
|
|
824
|
-
},
|
|
825
|
-
{
|
|
826
|
-
path: '/dashboard/traffic-activities',
|
|
827
|
-
kind: 'leaf',
|
|
828
|
-
permission: Q,
|
|
829
|
-
estimatedSize: 'medium',
|
|
830
|
-
description:
|
|
831
|
-
'Traffic activity over time (a time-series for charting) for the site (default window: last 24h). Override with ' +
|
|
832
|
-
'params.startTime / params.endTime (epoch SECONDS).',
|
|
833
|
-
params: [
|
|
834
|
-
{ name: 'startTime', required: false, description: 'Window start, epoch seconds (default: 24h ago)' },
|
|
835
|
-
{ name: 'endTime', required: false, description: 'Window end, epoch seconds (default: now)' },
|
|
836
|
-
],
|
|
837
|
-
fetch: (c, a) =>
|
|
838
|
-
c.readResource({ pathTemplate: '/sites/{siteId}/dashboard/traffic-activities', siteId: a.siteId, query: resolveUsageWindowSec(a.params) }),
|
|
839
|
-
},
|
|
840
|
-
|
|
841
|
-
// ---- Firmware ----------------------------------------------------------
|
|
842
|
-
{
|
|
843
|
-
path: '/firmware',
|
|
844
|
-
kind: 'leaf',
|
|
845
|
-
permission: Q,
|
|
846
|
-
estimatedSize: 'small',
|
|
847
|
-
description: 'Latest available firmware info for a device. Requires deviceMac (find via /devices).',
|
|
848
|
-
params: [{ name: 'deviceMac', required: true, description: 'Device MAC address' }],
|
|
849
|
-
fetch: (c, a) =>
|
|
850
|
-
c.readResource({
|
|
851
|
-
pathTemplate: '/sites/{siteId}/devices/{deviceMac}/latest-firmware-info',
|
|
852
|
-
siteId: a.siteId,
|
|
853
|
-
pathParams: { deviceMac: a.params?.deviceMac ?? '' },
|
|
854
|
-
}),
|
|
855
|
-
},
|
|
856
|
-
{
|
|
857
|
-
path: '/firmware/critical',
|
|
858
|
-
kind: 'leaf',
|
|
859
|
-
permission: Q,
|
|
860
|
-
estimatedSize: 'small',
|
|
861
|
-
description: 'Controller-wide overview of critical firmware upgrades (not site-scoped).',
|
|
862
|
-
fetch: (c) => c.readResource({ pathTemplate: '/upgrade/overview/critical', siteScoped: false }),
|
|
863
|
-
},
|
|
864
|
-
|
|
865
|
-
// ---- VPN (status & tunnels) -------------------------------------------
|
|
866
|
-
{
|
|
867
|
-
path: '/vpn',
|
|
868
|
-
kind: 'container',
|
|
869
|
-
permission: Q,
|
|
870
|
-
description: 'VPN status: site-to-site, client-to-site, WireGuard, and IPsec tunnel stats.',
|
|
871
|
-
},
|
|
872
|
-
{
|
|
873
|
-
path: '/vpn/site-to-site',
|
|
874
|
-
kind: 'collection',
|
|
875
|
-
permission: Q,
|
|
876
|
-
estimatedSize: 'small',
|
|
877
|
-
description: 'Site-to-site VPN tunnels. Pass id=<vpnId> to fetch a single tunnel.',
|
|
878
|
-
params: [{ name: 'id', required: false, description: 'VPN id to fetch a single site-to-site tunnel' }],
|
|
879
|
-
fetch: (c, a) =>
|
|
880
|
-
a.id
|
|
881
|
-
? c.readResource({
|
|
882
|
-
pathTemplate: '/sites/{siteId}/vpn/site-to-site-vpns/{vpnId}',
|
|
883
|
-
siteId: a.siteId,
|
|
884
|
-
pathParams: { vpnId: a.id },
|
|
885
|
-
})
|
|
886
|
-
: c.readResource({ pathTemplate: '/sites/{siteId}/vpn/site-to-site-vpns', siteId: a.siteId }),
|
|
887
|
-
},
|
|
888
|
-
{
|
|
889
|
-
path: '/vpn/client-to-site',
|
|
890
|
-
kind: 'container',
|
|
891
|
-
permission: Q,
|
|
892
|
-
description: 'Client-to-site (remote-access) VPN: configured servers and connected clients.',
|
|
893
|
-
},
|
|
894
|
-
{
|
|
895
|
-
path: '/vpn/client-to-site/servers',
|
|
896
|
-
kind: 'collection',
|
|
897
|
-
permission: Q,
|
|
898
|
-
estimatedSize: 'small',
|
|
899
|
-
description: 'Configured client-to-site VPN servers (L2TP/OpenVPN/etc.).',
|
|
900
|
-
fetch: (c, a) =>
|
|
901
|
-
c.readResource({ pathTemplate: '/sites/{siteId}/vpn/client-to-site-vpn-servers', siteId: a.siteId }),
|
|
902
|
-
},
|
|
903
|
-
{
|
|
904
|
-
path: '/vpn/client-to-site/clients',
|
|
905
|
-
kind: 'collection',
|
|
906
|
-
permission: Q,
|
|
907
|
-
estimatedSize: 'small',
|
|
908
|
-
description: 'Currently connected client-to-site (remote-access) VPN clients.',
|
|
909
|
-
fetch: (c, a) =>
|
|
910
|
-
c.readResource({ pathTemplate: '/sites/{siteId}/vpn/client-to-site-vpn-clients', siteId: a.siteId }),
|
|
911
|
-
},
|
|
912
|
-
{
|
|
913
|
-
path: '/vpn/wireguard',
|
|
914
|
-
kind: 'collection',
|
|
915
|
-
permission: Q,
|
|
916
|
-
estimatedSize: 'small',
|
|
917
|
-
description: 'Configured WireGuard VPN interfaces on the gateway.',
|
|
918
|
-
fetch: (c, a) => c.readResource({ pathTemplate: '/sites/{siteId}/vpn/wireguards', siteId: a.siteId }),
|
|
919
|
-
},
|
|
920
|
-
{
|
|
921
|
-
path: '/vpn/ipsec-stats',
|
|
922
|
-
kind: 'collection',
|
|
923
|
-
permission: Q,
|
|
924
|
-
paginated: true,
|
|
925
|
-
defaultPageSize: 50,
|
|
926
|
-
estimatedSize: 'small',
|
|
927
|
-
description: 'IPsec VPN tunnel statistics (paginated — use page/pageSize).',
|
|
928
|
-
fetch: (c, a) =>
|
|
929
|
-
c.readResource({
|
|
930
|
-
pathTemplate: '/sites/{siteId}/setting/vpn/stats/ipsec',
|
|
931
|
-
siteId: a.siteId,
|
|
932
|
-
paginated: true,
|
|
933
|
-
page: a.page,
|
|
934
|
-
pageSize: a.pageSize,
|
|
935
|
-
}),
|
|
936
|
-
},
|
|
937
|
-
|
|
938
|
-
// ---- Profiles (reusable network profiles) -----------------------------
|
|
939
|
-
{
|
|
940
|
-
path: '/profiles',
|
|
941
|
-
kind: 'container',
|
|
942
|
-
permission: Q,
|
|
943
|
-
description: 'Reusable network profiles: per-device Wi-Fi keys (PPSK) and time-range schedules.',
|
|
944
|
-
},
|
|
945
|
-
{
|
|
946
|
-
path: '/profiles/ppsk',
|
|
947
|
-
kind: 'collection',
|
|
948
|
-
permission: Q,
|
|
949
|
-
estimatedSize: 'small',
|
|
950
|
-
description:
|
|
951
|
-
'PPSK (Private Pre-Shared Key) profiles — unique per-user/per-device Wi-Fi passwords on a shared SSID. ' +
|
|
952
|
-
'REQUIRES params.type: 0 = PPSK without RADIUS, 1 = PPSK with RADIUS.',
|
|
953
|
-
params: [{ name: 'type', required: true, description: '0 = PPSK without RADIUS, 1 = PPSK with RADIUS' }],
|
|
954
|
-
fetch: (c, a) =>
|
|
955
|
-
c.readResource({
|
|
956
|
-
pathTemplate: '/sites/{siteId}/ppsk-profiles',
|
|
957
|
-
siteId: a.siteId,
|
|
958
|
-
query: { type: Number(a.params?.type) },
|
|
959
|
-
}),
|
|
960
|
-
},
|
|
961
|
-
{
|
|
962
|
-
path: '/profiles/time-range',
|
|
963
|
-
kind: 'collection',
|
|
964
|
-
permission: Q,
|
|
965
|
-
estimatedSize: 'small',
|
|
966
|
-
description: 'Time-range profiles — reusable schedules referenced by ACLs, Wi-Fi, and PoE rules.',
|
|
967
|
-
fetch: (c, a) => c.readResource({ pathTemplate: '/sites/{siteId}/time-range-profiles', siteId: a.siteId }),
|
|
968
|
-
},
|
|
969
|
-
|
|
970
|
-
// ---- Schedules (PoE / port / firmware-upgrade) ------------------------
|
|
971
|
-
{
|
|
972
|
-
path: '/schedules',
|
|
973
|
-
kind: 'container',
|
|
974
|
-
permission: Q,
|
|
975
|
-
description:
|
|
976
|
-
'Device schedules: PoE power, switch-port on/off, and firmware-upgrade windows. ' +
|
|
977
|
-
'(Reboot schedules are site-template-scoped enterprise config and are intentionally not exposed here.)',
|
|
978
|
-
},
|
|
979
|
-
{
|
|
980
|
-
path: '/schedules/poe',
|
|
981
|
-
kind: 'collection',
|
|
982
|
-
permission: Q,
|
|
983
|
-
estimatedSize: 'small',
|
|
984
|
-
description: 'PoE schedules — when switch ports deliver power to PoE devices.',
|
|
985
|
-
fetch: (c, a) => c.readResource({ pathTemplate: '/sites/{siteId}/poe-schedules', siteId: a.siteId }),
|
|
986
|
-
},
|
|
987
|
-
{
|
|
988
|
-
path: '/schedules/port',
|
|
989
|
-
kind: 'collection',
|
|
990
|
-
permission: Q,
|
|
991
|
-
estimatedSize: 'small',
|
|
992
|
-
description: 'Port schedules — when switch ports are administratively up/down.',
|
|
993
|
-
fetch: (c, a) => c.readResource({ pathTemplate: '/sites/{siteId}/port-schedules', siteId: a.siteId }),
|
|
994
|
-
},
|
|
995
|
-
{
|
|
996
|
-
path: '/schedules/upgrade',
|
|
997
|
-
kind: 'collection',
|
|
998
|
-
permission: Q,
|
|
999
|
-
estimatedSize: 'small',
|
|
1000
|
-
description: 'Firmware-upgrade schedules — planned maintenance windows for device upgrades.',
|
|
1001
|
-
fetch: (c, a) => c.readResource({ pathTemplate: '/sites/{siteId}/upgrade-schedules', siteId: a.siteId }),
|
|
1002
|
-
},
|
|
1003
|
-
|
|
1004
|
-
// ---- Backup (controller/site backup status) ---------------------------
|
|
1005
|
-
{
|
|
1006
|
-
path: '/backup',
|
|
1007
|
-
kind: 'container',
|
|
1008
|
-
permission: Q,
|
|
1009
|
-
description: 'Site backup status: available backup files and the most recent backup result.',
|
|
1010
|
-
},
|
|
1011
|
-
{
|
|
1012
|
-
path: '/backup/files',
|
|
1013
|
-
kind: 'collection',
|
|
1014
|
-
permission: Q,
|
|
1015
|
-
estimatedSize: 'small',
|
|
1016
|
-
description: 'List of available site backup files.',
|
|
1017
|
-
fetch: (c, a) => c.readResource({ pathTemplate: '/sites/{siteId}/maintenance/backup/files', siteId: a.siteId }),
|
|
1018
|
-
},
|
|
1019
|
-
{
|
|
1020
|
-
path: '/backup/result',
|
|
1021
|
-
kind: 'leaf',
|
|
1022
|
-
permission: Q,
|
|
1023
|
-
estimatedSize: 'small',
|
|
1024
|
-
description: 'Result of the most recent site backup operation.',
|
|
1025
|
-
fetch: (c, a) => c.readResource({ pathTemplate: '/sites/{siteId}/backup/result', siteId: a.siteId }),
|
|
1026
|
-
},
|
|
1027
|
-
|
|
1028
|
-
// ---- Audit logs (administrative operation history) — ADMIN only -------
|
|
1029
|
-
{
|
|
1030
|
-
path: '/audit',
|
|
1031
|
-
kind: 'container',
|
|
1032
|
-
permission: A,
|
|
1033
|
-
description:
|
|
1034
|
-
'Administrative audit logs — who did what on the controller. ADMIN only (reveals full admin activity).',
|
|
1035
|
-
},
|
|
1036
|
-
{
|
|
1037
|
-
path: '/audit/site',
|
|
1038
|
-
kind: 'collection',
|
|
1039
|
-
permission: A,
|
|
1040
|
-
paginated: true,
|
|
1041
|
-
defaultPageSize: 10,
|
|
1042
|
-
estimatedSize: 'large',
|
|
1043
|
-
description:
|
|
1044
|
-
'Site-scoped administrative audit log (paginated, ADMIN). Optional params: startTime/endTime ' +
|
|
1045
|
-
'(epoch MILLISECONDS) to bound the window, and searchKey (fuzzy text).',
|
|
1046
|
-
params: [
|
|
1047
|
-
{ name: 'startTime', required: false, description: 'Window start, epoch milliseconds' },
|
|
1048
|
-
{ name: 'endTime', required: false, description: 'Window end, epoch milliseconds' },
|
|
1049
|
-
{ name: 'searchKey', required: false, description: 'Fuzzy search on the log text' },
|
|
1050
|
-
],
|
|
1051
|
-
fetch: (c, a) =>
|
|
1052
|
-
c.readResource({
|
|
1053
|
-
pathTemplate: '/sites/{siteId}/audit-logs',
|
|
1054
|
-
siteId: a.siteId,
|
|
1055
|
-
paginated: true,
|
|
1056
|
-
page: a.page,
|
|
1057
|
-
pageSize: a.pageSize,
|
|
1058
|
-
query: auditFilters(a.params),
|
|
1059
|
-
}),
|
|
1060
|
-
},
|
|
1061
|
-
{
|
|
1062
|
-
path: '/audit/global',
|
|
1063
|
-
kind: 'collection',
|
|
1064
|
-
permission: A,
|
|
1065
|
-
paginated: true,
|
|
1066
|
-
defaultPageSize: 10,
|
|
1067
|
-
estimatedSize: 'large',
|
|
1068
|
-
description:
|
|
1069
|
-
'Controller-wide administrative audit log across all sites (paginated, ADMIN). Optional params: ' +
|
|
1070
|
-
'startTime/endTime (epoch MILLISECONDS) and searchKey (fuzzy text).',
|
|
1071
|
-
params: [
|
|
1072
|
-
{ name: 'startTime', required: false, description: 'Window start, epoch milliseconds' },
|
|
1073
|
-
{ name: 'endTime', required: false, description: 'Window end, epoch milliseconds' },
|
|
1074
|
-
{ name: 'searchKey', required: false, description: 'Fuzzy search on the log text' },
|
|
1075
|
-
],
|
|
1076
|
-
fetch: (c, a) =>
|
|
1077
|
-
c.readResource({
|
|
1078
|
-
pathTemplate: '/audit-logs',
|
|
1079
|
-
siteScoped: false,
|
|
1080
|
-
paginated: true,
|
|
1081
|
-
page: a.page,
|
|
1082
|
-
pageSize: a.pageSize,
|
|
1083
|
-
query: auditFilters(a.params),
|
|
1084
|
-
}),
|
|
1085
|
-
},
|
|
1086
|
-
|
|
1087
|
-
// ---- Security (IDS/IPS) — ADMIN only -----------------------------------
|
|
1088
|
-
{
|
|
1089
|
-
path: '/security',
|
|
1090
|
-
kind: 'container',
|
|
1091
|
-
permission: A,
|
|
1092
|
-
description: 'Security: IDS/IPS threat-management log. ADMIN only.',
|
|
1093
|
-
},
|
|
1094
|
-
{
|
|
1095
|
-
path: '/security/threats',
|
|
1096
|
-
kind: 'collection',
|
|
1097
|
-
permission: A,
|
|
1098
|
-
paginated: true,
|
|
1099
|
-
defaultPageSize: 10,
|
|
1100
|
-
estimatedSize: 'large',
|
|
1101
|
-
description:
|
|
1102
|
-
'IDS/IPS threat-management log (paginated, ADMIN). REQUIRES a time window: params.startTime and params.endTime ' +
|
|
1103
|
-
'(epoch SECONDS, e.g. 1682000000). Optional params: archived ("true"/"false", default false), severity ' +
|
|
1104
|
-
'(0=Critical,1=Major,2=Concerning,3=Minor), sortTime ("asc"/"desc"), searchKey (fuzzy text), siteList ' +
|
|
1105
|
-
'(comma-separated site IDs; default all sites).',
|
|
1106
|
-
params: [
|
|
1107
|
-
{ name: 'startTime', required: true, description: 'Window start, epoch seconds (e.g. 1682000000)' },
|
|
1108
|
-
{ name: 'endTime', required: true, description: 'Window end, epoch seconds (e.g. 1682003600)' },
|
|
1109
|
-
{ name: 'archived', required: false, description: '"true" or "false" (default false)' },
|
|
1110
|
-
{ name: 'severity', required: false, description: '0=Critical, 1=Major, 2=Concerning, 3=Minor' },
|
|
1111
|
-
{ name: 'sortTime', required: false, description: 'Sort by time: "asc" or "desc"' },
|
|
1112
|
-
{ name: 'searchKey', required: false, description: 'Fuzzy search on description/classification' },
|
|
1113
|
-
{ name: 'siteList', required: false, description: 'Comma-separated site IDs (default: all sites)' },
|
|
1114
|
-
],
|
|
1115
|
-
fetch: (c, a) =>
|
|
1116
|
-
c.getThreatList({
|
|
1117
|
-
siteList: a.params?.siteList,
|
|
1118
|
-
archived: a.params?.archived === 'true',
|
|
1119
|
-
page: a.page ?? 1,
|
|
1120
|
-
pageSize: a.pageSize ?? 10,
|
|
1121
|
-
startTime: Number(a.params?.startTime),
|
|
1122
|
-
endTime: Number(a.params?.endTime),
|
|
1123
|
-
severity: a.params?.severity !== undefined ? Number(a.params.severity) : undefined,
|
|
1124
|
-
sortTime: a.params?.sortTime === 'asc' ? 'asc' : a.params?.sortTime === 'desc' ? 'desc' : undefined,
|
|
1125
|
-
searchKey: a.params?.searchKey,
|
|
1126
|
-
}),
|
|
1127
|
-
},
|
|
1128
|
-
];
|
|
1129
|
-
|
|
1130
|
-
const byPath = new Map<string, ResourceNode>(OMADA_RESOURCES.map((n) => [n.path, n]));
|
|
1131
|
-
|
|
1132
|
-
/** Normalize a user-supplied path: leading slash, no trailing slash, '/' for root. */
|
|
1133
|
-
export function normalizePath(path: string): string {
|
|
1134
|
-
if (!path || path === '/') {
|
|
1135
|
-
return '/';
|
|
1136
|
-
}
|
|
1137
|
-
let p = path.trim();
|
|
1138
|
-
if (!p.startsWith('/')) {
|
|
1139
|
-
p = `/${p}`;
|
|
1140
|
-
}
|
|
1141
|
-
if (p.length > 1 && p.endsWith('/')) {
|
|
1142
|
-
p = p.slice(0, -1);
|
|
1143
|
-
}
|
|
1144
|
-
return p;
|
|
1145
|
-
}
|
|
1146
|
-
|
|
1147
|
-
/** The immediate parent path, or null for the root. */
|
|
1148
|
-
function parentPath(path: string): string | null {
|
|
1149
|
-
if (path === '/') {
|
|
1150
|
-
return null;
|
|
1151
|
-
}
|
|
1152
|
-
const idx = path.lastIndexOf('/');
|
|
1153
|
-
return idx <= 0 ? '/' : path.slice(0, idx);
|
|
1154
|
-
}
|
|
1155
|
-
|
|
1156
|
-
export function getResourceNode(path: string): ResourceNode | undefined {
|
|
1157
|
-
return byPath.get(normalizePath(path));
|
|
1158
|
-
}
|
|
1159
|
-
|
|
1160
|
-
/** Direct children (one segment deeper) of the given path. */
|
|
1161
|
-
export function childrenOf(path: string): ResourceNode[] {
|
|
1162
|
-
const norm = normalizePath(path);
|
|
1163
|
-
return OMADA_RESOURCES.filter((n) => parentPath(n.path) === norm);
|
|
1164
|
-
}
|