@camstack/types 1.2.309 → 1.2.311
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/dist/addon.js +1 -1
- package/dist/addon.mjs +1 -1
- package/dist/capabilities/hub-address.d.ts +107 -51
- package/dist/capabilities/index.d.ts +4 -4
- package/dist/capabilities/local-network.cap.d.ts +561 -58
- package/dist/capabilities/notification-rules.cap.d.ts +12 -0
- package/dist/capabilities/webrtc-session.cap.d.ts +36 -0
- package/dist/client.js +20 -4
- package/dist/client.mjs +20 -4
- package/dist/generated/addon-api.d.ts +33 -7
- package/dist/generated/method-access-map.d.ts +1 -1
- package/dist/generated/method-device-selectors.d.ts +1 -1
- package/dist/generated/system-proxy.d.ts +1 -1
- package/dist/index.js +485 -206
- package/dist/index.mjs +471 -203
- package/dist/notification/alarm-settings.d.ts +6 -3
- package/dist/{sleep-DXKLNFvA.mjs → sleep-C16NCZR2.mjs} +1 -0
- package/dist/{sleep-C3gDpn7G.js → sleep-DyF95STh.js} +1 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_sleep = require("./sleep-
|
|
2
|
+
const require_sleep = require("./sleep-DyF95STh.js");
|
|
3
3
|
const require_event_category = require("./event-category-DmS_tLsU.js");
|
|
4
4
|
const require_composition = require("./composition-BLWAivB2.js");
|
|
5
5
|
const require_err_msg = require("./err-msg-Dx2Kor0g.js");
|
|
@@ -16116,7 +16116,143 @@ var filesystemBrowseCapability = {
|
|
|
16116
16116
|
}
|
|
16117
16117
|
};
|
|
16118
16118
|
//#endregion
|
|
16119
|
+
//#region src/capabilities/viewer-link-url.ts
|
|
16120
|
+
/** The central link domain the viewer app claims (Universal Links / App Links). */
|
|
16121
|
+
var CAMSTACK_APP_LINK_ORIGIN = "https://camstack.zentik.app";
|
|
16122
|
+
/** Where the hub serves the viewer SPA. */
|
|
16123
|
+
var HUB_VIEWER_MOUNT = "/viewer/camstack";
|
|
16124
|
+
/** True when `baseUrl` names the CamStack app link rather than a hub address. */
|
|
16125
|
+
function isAppLinkBase(baseUrl) {
|
|
16126
|
+
if (baseUrl === null || baseUrl === void 0 || baseUrl === "") return false;
|
|
16127
|
+
try {
|
|
16128
|
+
return new URL(baseUrl).origin === CAMSTACK_APP_LINK_ORIGIN;
|
|
16129
|
+
} catch {
|
|
16130
|
+
return false;
|
|
16131
|
+
}
|
|
16132
|
+
}
|
|
16133
|
+
/**
|
|
16134
|
+
* The base a viewer link is built on, from the flagged notification address:
|
|
16135
|
+
* the effective address is the explicit choice, else AUTO's `resolved`. The
|
|
16136
|
+
* one reading of that answer — the NC's tap and the Network page's preview
|
|
16137
|
+
* both go through it.
|
|
16138
|
+
*/
|
|
16139
|
+
function viewerLinkBaseOf(endpoint) {
|
|
16140
|
+
const flagged = endpoint.baseUrl ?? endpoint.resolved;
|
|
16141
|
+
return isAppLinkBase(flagged) ? {
|
|
16142
|
+
form: "app",
|
|
16143
|
+
hubBaseUrl: endpoint.appLinkHub ?? null
|
|
16144
|
+
} : {
|
|
16145
|
+
form: "hub",
|
|
16146
|
+
hubBaseUrl: flagged
|
|
16147
|
+
};
|
|
16148
|
+
}
|
|
16149
|
+
/**
|
|
16150
|
+
* Reduce a base URL to the bare origin the central page accepts as `hub=`,
|
|
16151
|
+
* or `null` when it cannot be one: not http(s), carries credentials, or does
|
|
16152
|
+
* not parse. A path/query/fragment is dropped — the central page mounts the
|
|
16153
|
+
* viewer under the origin itself.
|
|
16154
|
+
*/
|
|
16155
|
+
function toAppLinkHubOrigin(baseUrl) {
|
|
16156
|
+
let parsed;
|
|
16157
|
+
try {
|
|
16158
|
+
parsed = new URL(baseUrl);
|
|
16159
|
+
} catch {
|
|
16160
|
+
return null;
|
|
16161
|
+
}
|
|
16162
|
+
if (parsed.protocol !== "https:" && parsed.protocol !== "http:") return null;
|
|
16163
|
+
if (parsed.username !== "" || parsed.password !== "") return null;
|
|
16164
|
+
if (parsed.hostname === "") return null;
|
|
16165
|
+
return parsed.origin;
|
|
16166
|
+
}
|
|
16167
|
+
/**
|
|
16168
|
+
* The hub address an app link carries as `hub=`, chosen from the hub's OWN
|
|
16169
|
+
* advertised palette so it always agrees with what the Network page lists:
|
|
16170
|
+
* the public tunnel first, then the mesh (Tailscale MagicDNS) — HTTPS only,
|
|
16171
|
+
* because the app and the hosted viewer reach it from off the LAN. `null`
|
|
16172
|
+
* when the hub advertises neither.
|
|
16173
|
+
*/
|
|
16174
|
+
function pickAppLinkHub(endpoints) {
|
|
16175
|
+
const rank = (e) => {
|
|
16176
|
+
if (e.kind !== "public" || !e.baseUrl.startsWith("https://")) return null;
|
|
16177
|
+
if (e.interfaceKind === "public") return 0;
|
|
16178
|
+
if (e.interfaceKind === "vpn") return 1;
|
|
16179
|
+
return null;
|
|
16180
|
+
};
|
|
16181
|
+
return endpoints.flatMap((e) => {
|
|
16182
|
+
const r = rank(e);
|
|
16183
|
+
const origin = toAppLinkHubOrigin(e.baseUrl);
|
|
16184
|
+
return r === null || origin === null ? [] : [{
|
|
16185
|
+
r,
|
|
16186
|
+
p: e.priority,
|
|
16187
|
+
origin
|
|
16188
|
+
}];
|
|
16189
|
+
}).toSorted((a, b) => a.r - b.r || a.p - b.p)[0]?.origin ?? null;
|
|
16190
|
+
}
|
|
16191
|
+
/** The viewer route for a destination, or null when it names nothing. */
|
|
16192
|
+
function viewerRoute(destination) {
|
|
16193
|
+
switch (destination.kind) {
|
|
16194
|
+
case "camera": {
|
|
16195
|
+
if (!Number.isInteger(destination.deviceId) || destination.deviceId <= 0) return null;
|
|
16196
|
+
const at = destination.atMs;
|
|
16197
|
+
return {
|
|
16198
|
+
path: `/camera/${String(destination.deviceId)}`,
|
|
16199
|
+
query: at !== void 0 && Number.isFinite(at) ? [["at", String(Math.trunc(at))]] : []
|
|
16200
|
+
};
|
|
16201
|
+
}
|
|
16202
|
+
case "events": return {
|
|
16203
|
+
path: "/events",
|
|
16204
|
+
query: []
|
|
16205
|
+
};
|
|
16206
|
+
case "notifications": return {
|
|
16207
|
+
path: "/notifications",
|
|
16208
|
+
query: []
|
|
16209
|
+
};
|
|
16210
|
+
}
|
|
16211
|
+
}
|
|
16212
|
+
function encodeQuery(query) {
|
|
16213
|
+
if (query.length === 0) return "";
|
|
16214
|
+
return `?${query.map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`).join("&")}`;
|
|
16215
|
+
}
|
|
16216
|
+
/**
|
|
16217
|
+
* The link for a viewer destination, or `null` when none can be minted: an
|
|
16218
|
+
* unknown destination, or the `hub` form with no reachable base (a dead link
|
|
16219
|
+
* is worse than none).
|
|
16220
|
+
*/
|
|
16221
|
+
function buildViewerLink(input) {
|
|
16222
|
+
const route = viewerRoute(input.destination);
|
|
16223
|
+
if (route === null) return null;
|
|
16224
|
+
const raw = input.base.hubBaseUrl;
|
|
16225
|
+
const base = raw === null ? "" : raw.replace(/\/+$/, "");
|
|
16226
|
+
if (input.base.form === "app") {
|
|
16227
|
+
const origin = base === "" ? null : toAppLinkHubOrigin(base);
|
|
16228
|
+
const query = origin === null ? route.query : [...route.query, ["hub", origin]];
|
|
16229
|
+
return `${CAMSTACK_APP_LINK_ORIGIN}${route.path}${encodeQuery(query)}`;
|
|
16230
|
+
}
|
|
16231
|
+
if (base === "" || isAppLinkBase(base)) return null;
|
|
16232
|
+
return `${base}${HUB_VIEWER_MOUNT}${route.path}${encodeQuery(route.query)}`;
|
|
16233
|
+
}
|
|
16234
|
+
//#endregion
|
|
16119
16235
|
//#region src/capabilities/hub-address.ts
|
|
16236
|
+
var HUB_ADDRESS_ROLES = [
|
|
16237
|
+
"appConnections",
|
|
16238
|
+
"notificationTaps",
|
|
16239
|
+
"internal",
|
|
16240
|
+
"publicEndpoint"
|
|
16241
|
+
];
|
|
16242
|
+
var SINGLE_HUB_ADDRESS_ROLES = [
|
|
16243
|
+
"notificationTaps",
|
|
16244
|
+
"internal",
|
|
16245
|
+
"publicEndpoint"
|
|
16246
|
+
];
|
|
16247
|
+
function isSingleHubAddressRole(role) {
|
|
16248
|
+
return role !== "appConnections";
|
|
16249
|
+
}
|
|
16250
|
+
var AUTOMATIC_HUB_ADDRESS_FLAGS = {
|
|
16251
|
+
appConnections: [],
|
|
16252
|
+
notificationTaps: null,
|
|
16253
|
+
internal: null,
|
|
16254
|
+
publicEndpoint: null
|
|
16255
|
+
};
|
|
16120
16256
|
var IPV4_LITERAL = /^\d{1,3}(?:\.\d{1,3}){3}$/;
|
|
16121
16257
|
function hostnameOf(baseUrl) {
|
|
16122
16258
|
try {
|
|
@@ -16126,6 +16262,9 @@ function hostnameOf(baseUrl) {
|
|
|
16126
16262
|
return null;
|
|
16127
16263
|
}
|
|
16128
16264
|
}
|
|
16265
|
+
function trimSlash(baseUrl) {
|
|
16266
|
+
return baseUrl.replace(/\/+$/, "");
|
|
16267
|
+
}
|
|
16129
16268
|
function isMesh(endpoint) {
|
|
16130
16269
|
return endpoint.kind === "public" && endpoint.interfaceKind === "vpn";
|
|
16131
16270
|
}
|
|
@@ -16140,11 +16279,11 @@ function isLanIpv4Literal(endpoint) {
|
|
|
16140
16279
|
const host = hostnameOf(endpoint.baseUrl);
|
|
16141
16280
|
return host !== null && IPV4_LITERAL.test(host);
|
|
16142
16281
|
}
|
|
16143
|
-
/** Lower = better; `null` = never this
|
|
16144
|
-
function
|
|
16145
|
-
if (endpoint.kind === "loopback" || endpoint.kind === "app-link") return null;
|
|
16282
|
+
/** Lower = better; `null` = never this role's AUTOMATIC answer. */
|
|
16283
|
+
function autoRankFor(role, endpoint) {
|
|
16284
|
+
if (endpoint.kind === "loopback" || endpoint.kind === "app-link" || endpoint.kind === "custom") return null;
|
|
16146
16285
|
if (hostnameOf(endpoint.baseUrl) === null) return null;
|
|
16147
|
-
if (
|
|
16286
|
+
if (role === "internal") {
|
|
16148
16287
|
if (isLanIpv4Literal(endpoint)) return 0;
|
|
16149
16288
|
if (isPlausibleLan(endpoint)) return 1;
|
|
16150
16289
|
if (isMesh(endpoint)) return 2;
|
|
@@ -16170,11 +16309,11 @@ function isLoopbackHost(hostname) {
|
|
|
16170
16309
|
return /^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(h);
|
|
16171
16310
|
}
|
|
16172
16311
|
/**
|
|
16173
|
-
* Validate an operator-typed
|
|
16312
|
+
* Validate an operator-typed address: an http(s) URL with a host, no
|
|
16174
16313
|
* credentials, no path, and never loopback (it would name whoever dials it).
|
|
16175
16314
|
* Answers the normalised origin (`scheme://host[:port]`).
|
|
16176
16315
|
*/
|
|
16177
|
-
function
|
|
16316
|
+
function validateCustomAddress(raw) {
|
|
16178
16317
|
const trimmed = raw.trim();
|
|
16179
16318
|
if (trimmed === "") return {
|
|
16180
16319
|
ok: false,
|
|
@@ -16214,47 +16353,130 @@ function validateHubAddressOverride(raw) {
|
|
|
16214
16353
|
baseUrl: parsed.origin
|
|
16215
16354
|
};
|
|
16216
16355
|
}
|
|
16356
|
+
/** The reason a plain-http public endpoint is refused unless accepted. */
|
|
16357
|
+
var PUBLIC_ENDPOINT_HTTP_REASON = "The public endpoint needs an https:// address: passkeys and most identity providers refuse a plain-http origin. Accept http only when sign-in and notification links never leave your own network.";
|
|
16217
16358
|
/**
|
|
16218
|
-
*
|
|
16219
|
-
* the
|
|
16220
|
-
*
|
|
16221
|
-
*
|
|
16359
|
+
* May `baseUrl` carry `role`? The address check above, plus two role rules:
|
|
16360
|
+
* the app link carries `notificationTaps` only (it is not a hub address), and
|
|
16361
|
+
* a plain-http address carries `publicEndpoint` only when the operator
|
|
16362
|
+
* explicitly accepted it (`acceptInsecureHttp`) — a LAN-only password or
|
|
16363
|
+
* magic-link sign-in works over http, a passkey or an OIDC callback does not.
|
|
16222
16364
|
*/
|
|
16223
|
-
function
|
|
16224
|
-
|
|
16225
|
-
|
|
16226
|
-
|
|
16227
|
-
|
|
16228
|
-
|
|
16229
|
-
|
|
16230
|
-
if (check.ok) return {
|
|
16231
|
-
override,
|
|
16232
|
-
resolved: check.baseUrl,
|
|
16233
|
-
source: "override"
|
|
16234
|
-
};
|
|
16235
|
-
}
|
|
16236
|
-
const auto = pickFromPalette(endpoints, audience);
|
|
16237
|
-
return {
|
|
16238
|
-
override: override === null || override === "" ? null : override,
|
|
16239
|
-
resolved: auto,
|
|
16240
|
-
source: auto === null ? "none" : "auto"
|
|
16365
|
+
function checkRoleAddress(role, baseUrl, options = {}) {
|
|
16366
|
+
if (isAppLinkBase(baseUrl)) return role === "notificationTaps" ? {
|
|
16367
|
+
ok: true,
|
|
16368
|
+
baseUrl: CAMSTACK_APP_LINK_ORIGIN
|
|
16369
|
+
} : {
|
|
16370
|
+
ok: false,
|
|
16371
|
+
reason: "The CamStack app link is not a hub address — only notification taps can use it."
|
|
16241
16372
|
};
|
|
16373
|
+
const check = validateCustomAddress(baseUrl);
|
|
16374
|
+
if (!check.ok) return check;
|
|
16375
|
+
if (role === "publicEndpoint" && check.baseUrl.startsWith("http:") && options.acceptInsecureHttp !== true) return {
|
|
16376
|
+
ok: false,
|
|
16377
|
+
reason: PUBLIC_ENDPOINT_HTTP_REASON
|
|
16378
|
+
};
|
|
16379
|
+
return check;
|
|
16380
|
+
}
|
|
16381
|
+
/** A stored flag that still validates (stored values are external data). */
|
|
16382
|
+
function validFlag(role, flag) {
|
|
16383
|
+
if (flag === null || flag === "") return null;
|
|
16384
|
+
const check = checkRoleAddress(role, flag, { acceptInsecureHttp: true });
|
|
16385
|
+
return check.ok ? check.baseUrl : null;
|
|
16242
16386
|
}
|
|
16243
|
-
function
|
|
16387
|
+
function pickAuto(endpoints, role) {
|
|
16244
16388
|
const best = endpoints.flatMap((endpoint) => {
|
|
16245
|
-
const rank =
|
|
16389
|
+
const rank = autoRankFor(role, endpoint);
|
|
16246
16390
|
return rank === null ? [] : [{
|
|
16247
16391
|
rank,
|
|
16248
16392
|
priority: endpoint.priority,
|
|
16249
16393
|
endpoint
|
|
16250
16394
|
}];
|
|
16251
16395
|
}).toSorted((a, b) => a.rank - b.rank || a.priority - b.priority)[0];
|
|
16252
|
-
return best === void 0 ? null : best.endpoint.baseUrl
|
|
16396
|
+
return best === void 0 ? null : trimSlash(best.endpoint.baseUrl);
|
|
16397
|
+
}
|
|
16398
|
+
function resolveHubRole(endpoints, role, flag) {
|
|
16399
|
+
const flagged = validFlag(role, flag);
|
|
16400
|
+
if (flagged !== null) return {
|
|
16401
|
+
flagged,
|
|
16402
|
+
resolved: flagged,
|
|
16403
|
+
source: "flagged"
|
|
16404
|
+
};
|
|
16405
|
+
const auto = pickAuto(endpoints, role);
|
|
16406
|
+
return {
|
|
16407
|
+
flagged: null,
|
|
16408
|
+
resolved: auto,
|
|
16409
|
+
source: auto === null ? "none" : "auto"
|
|
16410
|
+
};
|
|
16253
16411
|
}
|
|
16254
|
-
/**
|
|
16255
|
-
function
|
|
16256
|
-
|
|
16257
|
-
|
|
16412
|
+
/** `internal`: what agents and LAN devices download from. */
|
|
16413
|
+
function resolveInternalAddress(endpoints, flags) {
|
|
16414
|
+
return resolveHubRole(endpoints, "internal", flags.internal);
|
|
16415
|
+
}
|
|
16416
|
+
/**
|
|
16417
|
+
* `publicEndpoint`: every URL that must work off the LAN — sign-in links, OIDC
|
|
16418
|
+
* / OAuth2 callbacks, the relying party, and notification buttons,
|
|
16419
|
+
* attachments, media and admin links.
|
|
16420
|
+
*/
|
|
16421
|
+
function resolvePublicEndpoint(endpoints, flags) {
|
|
16422
|
+
return resolveHubRole(endpoints, "publicEndpoint", flags.publicEndpoint);
|
|
16423
|
+
}
|
|
16424
|
+
/** `notificationTaps`: the flagged address, else the CamStack app link (D709). */
|
|
16425
|
+
function resolveNotificationTapAddress(flags) {
|
|
16426
|
+
const flagged = validFlag("notificationTaps", flags.notificationTaps);
|
|
16427
|
+
if (flagged !== null && !isAppLinkBase(flagged)) return {
|
|
16428
|
+
flagged,
|
|
16429
|
+
resolved: flagged,
|
|
16430
|
+
source: "flagged"
|
|
16431
|
+
};
|
|
16432
|
+
return {
|
|
16433
|
+
flagged: null,
|
|
16434
|
+
resolved: CAMSTACK_APP_LINK_ORIGIN,
|
|
16435
|
+
source: "auto"
|
|
16436
|
+
};
|
|
16437
|
+
}
|
|
16438
|
+
/** AUTO app connections: LAN IPv4 + the public tunnel. Never IPv6, mesh, loopback or custom. */
|
|
16439
|
+
function isDefaultAppConnectionEndpoint(endpoint) {
|
|
16440
|
+
if (endpoint.kind === "lan-ipv4") return true;
|
|
16441
|
+
return endpoint.kind === "public" && endpoint.interfaceKind === "public";
|
|
16442
|
+
}
|
|
16443
|
+
/**
|
|
16444
|
+
* The endpoints the apps race: the flagged ones that are in `endpoints`
|
|
16445
|
+
* (which carries the custom addresses flagged `appConnections`), else AUTO. A flagged
|
|
16446
|
+
* set none of which is currently up falls back to AUTO rather than racing
|
|
16447
|
+
* nothing.
|
|
16448
|
+
*/
|
|
16449
|
+
function selectAppConnectionEndpoints(endpoints, flags) {
|
|
16450
|
+
const auto = endpoints.filter(isDefaultAppConnectionEndpoint);
|
|
16451
|
+
if (flags.appConnections.length === 0) return auto;
|
|
16452
|
+
const wanted = new Set(flags.appConnections);
|
|
16453
|
+
const explicit = endpoints.filter((e) => wanted.has(e.baseUrl));
|
|
16454
|
+
return explicit.length > 0 ? explicit : auto;
|
|
16455
|
+
}
|
|
16456
|
+
/** `appConnections`: what the apps try when connecting. */
|
|
16457
|
+
function resolveAppConnections(endpoints, flags) {
|
|
16458
|
+
const wanted = new Set(flags.appConnections);
|
|
16459
|
+
const selected = selectAppConnectionEndpoints(endpoints, flags);
|
|
16460
|
+
const usedFlags = selected.some((e) => wanted.has(e.baseUrl));
|
|
16461
|
+
return {
|
|
16462
|
+
flagged: flags.appConnections,
|
|
16463
|
+
resolved: selected.map((e) => e.baseUrl),
|
|
16464
|
+
source: selected.length === 0 ? "none" : usedFlags ? "flagged" : "auto"
|
|
16465
|
+
};
|
|
16466
|
+
}
|
|
16467
|
+
/**
|
|
16468
|
+
* Every role at once, each through its own resolver. `appPalette` is what
|
|
16469
|
+
* the apps race (it carries the custom addresses flagged `appConnections`);
|
|
16470
|
+
* `hubPalette` is the detected HTTPS palette `internal` and `publicEndpoint`
|
|
16471
|
+
* resolve over.
|
|
16472
|
+
*/
|
|
16473
|
+
function resolveHubAddressRoles(appPalette, hubPalette, flags) {
|
|
16474
|
+
return {
|
|
16475
|
+
appConnections: resolveAppConnections(appPalette, flags),
|
|
16476
|
+
notificationTaps: resolveNotificationTapAddress(flags),
|
|
16477
|
+
internal: resolveInternalAddress(hubPalette, flags),
|
|
16478
|
+
publicEndpoint: resolvePublicEndpoint(hubPalette, flags)
|
|
16479
|
+
};
|
|
16258
16480
|
}
|
|
16259
16481
|
/** The bare hostname of a base URL, or `null` when it does not parse. */
|
|
16260
16482
|
function hubAddressHostname(baseUrl) {
|
|
@@ -22058,7 +22280,13 @@ var NcAlarmModeDelaysSchema = zod.z.object({
|
|
|
22058
22280
|
* Absent = false (logged, not sent). Even when true it is not sent when that same sensor
|
|
22059
22281
|
* is the one that starts the entry delay — the entry-delay notification already names it.
|
|
22060
22282
|
*/
|
|
22061
|
-
notifySensorRewatched: zod.z.boolean().optional()
|
|
22283
|
+
notifySensorRewatched: zod.z.boolean().optional(),
|
|
22284
|
+
/**
|
|
22285
|
+
* D735: notify "ignored" when a sensor this arm bypassed really MOVED while armed (its own
|
|
22286
|
+
* change time is after the arm) and set nothing off. Absent = false (logged, not sent). A
|
|
22287
|
+
* re-sync, a recovery from `unavailable` or a duplicate is never announced, switch or not.
|
|
22288
|
+
*/
|
|
22289
|
+
notifySensorIgnored: zod.z.boolean().optional()
|
|
22062
22290
|
});
|
|
22063
22291
|
var NcAlarmModeDelaysListSchema = zod.z.array(NcAlarmModeDelaysSchema).max(8).refine(uniqueModes, { message: "modeDelays: at most one entry per arm mode" });
|
|
22064
22292
|
/**
|
|
@@ -22077,7 +22305,9 @@ var NcAlarmModeDelaysEditSchema = zod.z.object({
|
|
|
22077
22305
|
/** D706: set the switch, or `null` to clear it (back to the default, false). */
|
|
22078
22306
|
notifyDuringEntryDelay: zod.z.boolean().nullable().optional(),
|
|
22079
22307
|
/** D706: set the switch, or `null` to clear it (back to the default, false). */
|
|
22080
|
-
notifySensorRewatched: zod.z.boolean().nullable().optional()
|
|
22308
|
+
notifySensorRewatched: zod.z.boolean().nullable().optional(),
|
|
22309
|
+
/** D735: set the switch, or `null` to clear it (back to the default, false). */
|
|
22310
|
+
notifySensorIgnored: zod.z.boolean().nullable().optional()
|
|
22081
22311
|
});
|
|
22082
22312
|
var NcAlarmModeDelaysEditListSchema = zod.z.array(NcAlarmModeDelaysEditSchema).max(8).refine(uniqueModes, { message: "modeDelays: at most one edit per arm mode" });
|
|
22083
22313
|
/** One switch of the alarm table: put ONE device on, or take it off, ONE mode's list. */
|
|
@@ -32796,122 +33026,6 @@ var CLIP_PLAYBACK_OPTIONS = {
|
|
|
32796
33026
|
}
|
|
32797
33027
|
};
|
|
32798
33028
|
//#endregion
|
|
32799
|
-
//#region src/capabilities/viewer-link-url.ts
|
|
32800
|
-
/** The central link domain the viewer app claims (Universal Links / App Links). */
|
|
32801
|
-
var CAMSTACK_APP_LINK_ORIGIN = "https://camstack.zentik.app";
|
|
32802
|
-
/** Where the hub serves the viewer SPA. */
|
|
32803
|
-
var HUB_VIEWER_MOUNT = "/viewer/camstack";
|
|
32804
|
-
/** True when `baseUrl` names the CamStack app link rather than a hub address. */
|
|
32805
|
-
function isAppLinkBase(baseUrl) {
|
|
32806
|
-
if (baseUrl === null || baseUrl === void 0 || baseUrl === "") return false;
|
|
32807
|
-
try {
|
|
32808
|
-
return new URL(baseUrl).origin === CAMSTACK_APP_LINK_ORIGIN;
|
|
32809
|
-
} catch {
|
|
32810
|
-
return false;
|
|
32811
|
-
}
|
|
32812
|
-
}
|
|
32813
|
-
/**
|
|
32814
|
-
* The base a viewer link is built on, from the flagged notification address:
|
|
32815
|
-
* the effective address is the explicit choice, else AUTO's `resolved`. The
|
|
32816
|
-
* one reading of that answer — the NC's tap and the Network page's preview
|
|
32817
|
-
* both go through it.
|
|
32818
|
-
*/
|
|
32819
|
-
function viewerLinkBaseOf(endpoint) {
|
|
32820
|
-
const flagged = endpoint.baseUrl ?? endpoint.resolved;
|
|
32821
|
-
return isAppLinkBase(flagged) ? {
|
|
32822
|
-
form: "app",
|
|
32823
|
-
hubBaseUrl: endpoint.appLinkHub ?? null
|
|
32824
|
-
} : {
|
|
32825
|
-
form: "hub",
|
|
32826
|
-
hubBaseUrl: flagged
|
|
32827
|
-
};
|
|
32828
|
-
}
|
|
32829
|
-
/**
|
|
32830
|
-
* Reduce a base URL to the bare origin the central page accepts as `hub=`,
|
|
32831
|
-
* or `null` when it cannot be one: not http(s), carries credentials, or does
|
|
32832
|
-
* not parse. A path/query/fragment is dropped — the central page mounts the
|
|
32833
|
-
* viewer under the origin itself.
|
|
32834
|
-
*/
|
|
32835
|
-
function toAppLinkHubOrigin(baseUrl) {
|
|
32836
|
-
let parsed;
|
|
32837
|
-
try {
|
|
32838
|
-
parsed = new URL(baseUrl);
|
|
32839
|
-
} catch {
|
|
32840
|
-
return null;
|
|
32841
|
-
}
|
|
32842
|
-
if (parsed.protocol !== "https:" && parsed.protocol !== "http:") return null;
|
|
32843
|
-
if (parsed.username !== "" || parsed.password !== "") return null;
|
|
32844
|
-
if (parsed.hostname === "") return null;
|
|
32845
|
-
return parsed.origin;
|
|
32846
|
-
}
|
|
32847
|
-
/**
|
|
32848
|
-
* The hub address an app link carries as `hub=`, chosen from the hub's OWN
|
|
32849
|
-
* advertised palette so it always agrees with what the Network page lists:
|
|
32850
|
-
* the public tunnel first, then the mesh (Tailscale MagicDNS) — HTTPS only,
|
|
32851
|
-
* because the app and the hosted viewer reach it from off the LAN. `null`
|
|
32852
|
-
* when the hub advertises neither.
|
|
32853
|
-
*/
|
|
32854
|
-
function pickAppLinkHub(endpoints) {
|
|
32855
|
-
const rank = (e) => {
|
|
32856
|
-
if (e.kind !== "public" || !e.baseUrl.startsWith("https://")) return null;
|
|
32857
|
-
if (e.interfaceKind === "public") return 0;
|
|
32858
|
-
if (e.interfaceKind === "vpn") return 1;
|
|
32859
|
-
return null;
|
|
32860
|
-
};
|
|
32861
|
-
return endpoints.flatMap((e) => {
|
|
32862
|
-
const r = rank(e);
|
|
32863
|
-
const origin = toAppLinkHubOrigin(e.baseUrl);
|
|
32864
|
-
return r === null || origin === null ? [] : [{
|
|
32865
|
-
r,
|
|
32866
|
-
p: e.priority,
|
|
32867
|
-
origin
|
|
32868
|
-
}];
|
|
32869
|
-
}).toSorted((a, b) => a.r - b.r || a.p - b.p)[0]?.origin ?? null;
|
|
32870
|
-
}
|
|
32871
|
-
/** The viewer route for a destination, or null when it names nothing. */
|
|
32872
|
-
function viewerRoute(destination) {
|
|
32873
|
-
switch (destination.kind) {
|
|
32874
|
-
case "camera": {
|
|
32875
|
-
if (!Number.isInteger(destination.deviceId) || destination.deviceId <= 0) return null;
|
|
32876
|
-
const at = destination.atMs;
|
|
32877
|
-
return {
|
|
32878
|
-
path: `/camera/${String(destination.deviceId)}`,
|
|
32879
|
-
query: at !== void 0 && Number.isFinite(at) ? [["at", String(Math.trunc(at))]] : []
|
|
32880
|
-
};
|
|
32881
|
-
}
|
|
32882
|
-
case "events": return {
|
|
32883
|
-
path: "/events",
|
|
32884
|
-
query: []
|
|
32885
|
-
};
|
|
32886
|
-
case "notifications": return {
|
|
32887
|
-
path: "/notifications",
|
|
32888
|
-
query: []
|
|
32889
|
-
};
|
|
32890
|
-
}
|
|
32891
|
-
}
|
|
32892
|
-
function encodeQuery(query) {
|
|
32893
|
-
if (query.length === 0) return "";
|
|
32894
|
-
return `?${query.map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`).join("&")}`;
|
|
32895
|
-
}
|
|
32896
|
-
/**
|
|
32897
|
-
* The link for a viewer destination, or `null` when none can be minted: an
|
|
32898
|
-
* unknown destination, or the `hub` form with no reachable base (a dead link
|
|
32899
|
-
* is worse than none).
|
|
32900
|
-
*/
|
|
32901
|
-
function buildViewerLink(input) {
|
|
32902
|
-
const route = viewerRoute(input.destination);
|
|
32903
|
-
if (route === null) return null;
|
|
32904
|
-
const raw = input.base.hubBaseUrl;
|
|
32905
|
-
const base = raw === null ? "" : raw.replace(/\/+$/, "");
|
|
32906
|
-
if (input.base.form === "app") {
|
|
32907
|
-
const origin = base === "" ? null : toAppLinkHubOrigin(base);
|
|
32908
|
-
const query = origin === null ? route.query : [...route.query, ["hub", origin]];
|
|
32909
|
-
return `${CAMSTACK_APP_LINK_ORIGIN}${route.path}${encodeQuery(query)}`;
|
|
32910
|
-
}
|
|
32911
|
-
if (base === "" || isAppLinkBase(base)) return null;
|
|
32912
|
-
return `${base}${HUB_VIEWER_MOUNT}${route.path}${encodeQuery(route.query)}`;
|
|
32913
|
-
}
|
|
32914
|
-
//#endregion
|
|
32915
33029
|
//#region src/capabilities/webrtc-session.cap.ts
|
|
32916
33030
|
/**
|
|
32917
33031
|
* Optional client-side hints sent at session creation to help the provider
|
|
@@ -33419,6 +33533,35 @@ var webrtcSessionCapability = {
|
|
|
33419
33533
|
alive: zod.z.boolean()
|
|
33420
33534
|
})),
|
|
33421
33535
|
/**
|
|
33536
|
+
* The viewer's downlink probe, for ONE live session (D733).
|
|
33537
|
+
*
|
|
33538
|
+
* The player measures `/adaptive-probe` after the session's first decoded
|
|
33539
|
+
* frame (D635). It used to act on the reading itself, by opening a SECOND
|
|
33540
|
+
* session with `hints.downlinkMbps` — every adaptive live open became two
|
|
33541
|
+
* sessions, two ICE + DTLS handshakes and two server pipelines. It now
|
|
33542
|
+
* hands the measurement to the session it already has; the provider picks
|
|
33543
|
+
* the rung exactly as it would from an offer's hints (same viewport
|
|
33544
|
+
* ceiling) and moves the session there — in place when the negotiated
|
|
33545
|
+
* codec carries the new rendition, by the existing re-offer
|
|
33546
|
+
* (`getSessionState.pendingRenegotiation`) when it cannot.
|
|
33547
|
+
*
|
|
33548
|
+
* A MEASUREMENT, never a tier: the client does not choose. A probe only
|
|
33549
|
+
* raises the rung; lowering it stays the ladder's call on delivery.
|
|
33550
|
+
* `held` answers why nothing moved (`not-adaptive`, `pinned`,
|
|
33551
|
+
* `already-there`, `recorded`, …) — a client that gets ANY answer must not
|
|
33552
|
+
* fall back to a reconnect; only a provider that does not know the method
|
|
33553
|
+
* (an older hub) leaves the client its legacy second session.
|
|
33554
|
+
*/
|
|
33555
|
+
applyDownlinkProbe: require_sleep.method(zod.z.object({
|
|
33556
|
+
deviceId: zod.z.number().int().nonnegative(),
|
|
33557
|
+
sessionId: zod.z.string(),
|
|
33558
|
+
downlinkMbps: zod.z.number().nonnegative()
|
|
33559
|
+
}), zod.z.object({
|
|
33560
|
+
outcome: zod.z.enum(["switching", "held"]),
|
|
33561
|
+
tier: require_sleep.CamProfileSchema.nullable(),
|
|
33562
|
+
reason: zod.z.string()
|
|
33563
|
+
}), { kind: "mutation" }),
|
|
33564
|
+
/**
|
|
33422
33565
|
* The SERVER's half of the stream-debug overlay, for one live session.
|
|
33423
33566
|
*
|
|
33424
33567
|
* The client can measure its own transport (`getStats()`); it cannot see
|
|
@@ -37840,7 +37983,8 @@ var ConnectionEndpointSchema = zod.z.object({
|
|
|
37840
37983
|
"lan-ipv6",
|
|
37841
37984
|
"public",
|
|
37842
37985
|
"loopback",
|
|
37843
|
-
"app-link"
|
|
37986
|
+
"app-link",
|
|
37987
|
+
"custom"
|
|
37844
37988
|
]),
|
|
37845
37989
|
/**
|
|
37846
37990
|
* Originating-interface kind — `lan`/`wifi`/`docker`/`vpn`/`other`/
|
|
@@ -37909,7 +38053,7 @@ var GetConnectionEndpointsResultSchema = zod.z.object({
|
|
|
37909
38053
|
localPort: AdvertisedLocalPortSchema
|
|
37910
38054
|
});
|
|
37911
38055
|
/**
|
|
37912
|
-
* The address flagged for notification
|
|
38056
|
+
* The address flagged for notification taps (`notificationTaps`). `baseUrl: null` = AUTO, which
|
|
37913
38057
|
* since D709 is the CamStack app link; `resolved` reports the effective value,
|
|
37914
38058
|
* so the UI can show it either way.
|
|
37915
38059
|
*/
|
|
@@ -37943,13 +38087,12 @@ var ViewerEndpointsSchema = zod.z.object({
|
|
|
37943
38087
|
resolved: zod.z.array(zod.z.string()).readonly()
|
|
37944
38088
|
});
|
|
37945
38089
|
/**
|
|
37946
|
-
*
|
|
37947
|
-
*
|
|
38090
|
+
* DEPRECATED compatibility shape of `getHubAddresses` (D729 amendment, kept
|
|
38091
|
+
* for addons built against it): `cluster` is the `internal` role, `browser`
|
|
38092
|
+
* the `publicEndpoint` role; `override` is the flagged address.
|
|
37948
38093
|
*/
|
|
37949
38094
|
var HubAddressSnapshotSchema = zod.z.object({
|
|
37950
|
-
/** The operator's override, or null for automatic. */
|
|
37951
38095
|
override: zod.z.string().nullable(),
|
|
37952
|
-
/** The address in use, or null when nothing qualifies (never loopback). */
|
|
37953
38096
|
resolved: zod.z.string().nullable(),
|
|
37954
38097
|
source: zod.z.enum([
|
|
37955
38098
|
"override",
|
|
@@ -37958,11 +38101,63 @@ var HubAddressSnapshotSchema = zod.z.object({
|
|
|
37958
38101
|
])
|
|
37959
38102
|
});
|
|
37960
38103
|
var HubAddressesSchema = zod.z.object({
|
|
37961
|
-
/** "Hub address for agents" — agents' bundle/model pulls, LAN devices. */
|
|
37962
38104
|
cluster: HubAddressSnapshotSchema,
|
|
37963
|
-
/** "Public address for sign-in links" — e-mail links, OIDC, WebAuthn, OAuth2. */
|
|
37964
38105
|
browser: HubAddressSnapshotSchema
|
|
37965
38106
|
});
|
|
38107
|
+
/**
|
|
38108
|
+
* What an address is used for (`hub-address.ts`, D734). `appConnections` is
|
|
38109
|
+
* many-valued; `notificationTaps`, `publicEndpoint` and `internal` are carried
|
|
38110
|
+
* by at most one address.
|
|
38111
|
+
*/
|
|
38112
|
+
var HubAddressRoleSchema = zod.z.enum(HUB_ADDRESS_ROLES);
|
|
38113
|
+
var RoleSourceSchema = zod.z.enum([
|
|
38114
|
+
"flagged",
|
|
38115
|
+
"auto",
|
|
38116
|
+
"none"
|
|
38117
|
+
]);
|
|
38118
|
+
/** One single-valued role: the flagged address, the one in use, and why. */
|
|
38119
|
+
var HubAddressRoleResolutionSchema = zod.z.object({
|
|
38120
|
+
/** The address carrying the flag, or null = automatic. */
|
|
38121
|
+
flagged: zod.z.string().nullable(),
|
|
38122
|
+
/** The address in use, or null when nothing qualifies (never loopback). */
|
|
38123
|
+
resolved: zod.z.string().nullable(),
|
|
38124
|
+
source: RoleSourceSchema
|
|
38125
|
+
});
|
|
38126
|
+
var HubAppConnectionsResolutionSchema = zod.z.object({
|
|
38127
|
+
/** The addresses flagged `appConnections`, or empty = automatic. */
|
|
38128
|
+
flagged: zod.z.array(zod.z.string()).readonly(),
|
|
38129
|
+
/** What the apps race right now. */
|
|
38130
|
+
resolved: zod.z.array(zod.z.string()).readonly(),
|
|
38131
|
+
source: RoleSourceSchema
|
|
38132
|
+
});
|
|
38133
|
+
/**
|
|
38134
|
+
* One row of the Network page's Addresses table: a detected endpoint, an
|
|
38135
|
+
* operator-entered custom address, or the CamStack app link — flagged the
|
|
38136
|
+
* same way. A URL that is both detected and entered is ONE row.
|
|
38137
|
+
*/
|
|
38138
|
+
var HubAddressRowSchema = ConnectionEndpointSchema.extend({
|
|
38139
|
+
/** In the hub's detected palette right now. */
|
|
38140
|
+
detected: zod.z.boolean(),
|
|
38141
|
+
/** Entered by the operator (removable). */
|
|
38142
|
+
custom: zod.z.boolean(),
|
|
38143
|
+
/** The roles explicitly flagged on this address. */
|
|
38144
|
+
flags: zod.z.array(HubAddressRoleSchema).readonly(),
|
|
38145
|
+
/** The roles this address serves right now — flagged or automatic. */
|
|
38146
|
+
inUse: zod.z.array(HubAddressRoleSchema).readonly(),
|
|
38147
|
+
/** The roles this address may be flagged with. */
|
|
38148
|
+
eligible: zod.z.array(HubAddressRoleSchema).readonly()
|
|
38149
|
+
});
|
|
38150
|
+
var HubAddressBookSchema = zod.z.object({
|
|
38151
|
+
rows: zod.z.array(HubAddressRowSchema).readonly(),
|
|
38152
|
+
roles: zod.z.object({
|
|
38153
|
+
appConnections: HubAppConnectionsResolutionSchema,
|
|
38154
|
+
notificationTaps: HubAddressRoleResolutionSchema,
|
|
38155
|
+
internal: HubAddressRoleResolutionSchema,
|
|
38156
|
+
publicEndpoint: HubAddressRoleResolutionSchema
|
|
38157
|
+
}),
|
|
38158
|
+
/** The `hub=` an app link carries (D709), or null. */
|
|
38159
|
+
appLinkHub: zod.z.string().nullable()
|
|
38160
|
+
});
|
|
37966
38161
|
var AllowedAddressesSchema = zod.z.object({
|
|
37967
38162
|
/**
|
|
37968
38163
|
* Allowlist of interface addresses operators have explicitly opted
|
|
@@ -38053,19 +38248,18 @@ var localNetworkCapability = {
|
|
|
38053
38248
|
* tunnel always emits `https://` regardless. */
|
|
38054
38249
|
scheme: zod.z.enum(["http", "https"]).optional(),
|
|
38055
38250
|
/** Append the CamStack app link entry (`kind: 'app-link'`, D709) —
|
|
38056
|
-
* an address notification
|
|
38251
|
+
* an address notification taps can be flagged with, not a hub
|
|
38057
38252
|
* route. Default `false`: racers and rankers never see it. */
|
|
38058
38253
|
includeAppLink: zod.z.boolean().optional()
|
|
38059
38254
|
}), GetConnectionEndpointsResultSchema),
|
|
38060
38255
|
/**
|
|
38061
|
-
* The
|
|
38062
|
-
* AUTO, which is the CamStack app link (D709):
|
|
38063
|
-
* `https://camstack.zentik.app/…?hub=<appLinkHub>` and open the
|
|
38064
|
-
* hub address the palette lists can be flagged instead; then
|
|
38065
|
-
*
|
|
38066
|
-
*
|
|
38067
|
-
*
|
|
38068
|
-
* the LAN), never loopback.
|
|
38256
|
+
* The `notificationTaps` role (D734): where TAPPING a notification opens.
|
|
38257
|
+
* `baseUrl: null` means AUTO, which is the CamStack app link (D709): taps
|
|
38258
|
+
* go through `https://camstack.zentik.app/…?hub=<appLinkHub>` and open the
|
|
38259
|
+
* app. Any hub address the palette lists can be flagged instead; then a
|
|
38260
|
+
* tap opens that address. Only the tap: action buttons, attachment /
|
|
38261
|
+
* media links and admin links follow the `publicEndpoint` role
|
|
38262
|
+
* (`getAddresses().roles.publicEndpoint`), never this one.
|
|
38069
38263
|
*
|
|
38070
38264
|
* Why an explicit marker: the automatic ranking cannot know which of
|
|
38071
38265
|
* several reachable addresses the RECIPIENT can actually open. A link is
|
|
@@ -38075,46 +38269,80 @@ var localNetworkCapability = {
|
|
|
38075
38269
|
*/
|
|
38076
38270
|
getNotificationEndpoint: require_sleep.method(zod.z.void(), NotificationEndpointSchema),
|
|
38077
38271
|
/**
|
|
38078
|
-
*
|
|
38079
|
-
*
|
|
38080
|
-
*
|
|
38081
|
-
* different address after a reboot.
|
|
38272
|
+
* @deprecated Use `setAddressRole({ role: 'notificationTaps', … })`. It
|
|
38273
|
+
* writes the same `notificationTaps` flag, with the same validation. `baseUrl: null` restores automatic; an
|
|
38274
|
+
* address that is not detected becomes a custom address.
|
|
38082
38275
|
*/
|
|
38083
38276
|
setNotificationEndpoint: require_sleep.method(zod.z.object({ baseUrl: zod.z.string().nullable() }), NotificationEndpointSchema, { kind: "mutation" }),
|
|
38084
38277
|
/**
|
|
38085
|
-
* The
|
|
38086
|
-
*
|
|
38087
|
-
*
|
|
38088
|
-
*
|
|
38278
|
+
* The `appConnections` role as shipped apps read it: the flagged addresses
|
|
38279
|
+
* (detected or custom), or empty for AUTO — every LAN IPv4 address plus
|
|
38280
|
+
* the public tunnel, never IPv6, mesh, loopback or a custom address.
|
|
38281
|
+
* `resolved` is the set as it stands right now; the custom ones in it are
|
|
38282
|
+
* also in `getConnectionEndpoints`, which the apps filter by it.
|
|
38089
38283
|
*/
|
|
38090
38284
|
getViewerEndpoints: require_sleep.method(zod.z.void(), ViewerEndpointsSchema),
|
|
38091
38285
|
/**
|
|
38092
|
-
*
|
|
38093
|
-
*
|
|
38094
|
-
*
|
|
38286
|
+
* @deprecated Use `setAddressRole({ role: 'appConnections', … })`. It
|
|
38287
|
+
* replaces the same `appConnections` flags.
|
|
38288
|
+
* Empty `baseUrls` restores automatic.
|
|
38095
38289
|
*/
|
|
38096
38290
|
setViewerEndpoints: require_sleep.method(zod.z.object({ baseUrls: zod.z.array(zod.z.string()).readonly() }), ViewerEndpointsSchema, { kind: "mutation" }),
|
|
38097
38291
|
/**
|
|
38098
|
-
* The
|
|
38099
|
-
*
|
|
38100
|
-
*
|
|
38101
|
-
*
|
|
38102
|
-
*
|
|
38292
|
+
* The Network page's Addresses table and every role's answer — the ONE
|
|
38293
|
+
* reading of "which address is this hub reached at, for what": detected
|
|
38294
|
+
* endpoints and custom addresses with their role flags, and per role the
|
|
38295
|
+
* flagged address, the one in use and whether it is automatic. Agent
|
|
38296
|
+
* deliveries and LAN devices read `roles.internal`; sign-in, OAuth2 and
|
|
38297
|
+
* the notification centre's buttons / media / admin links read
|
|
38298
|
+
* `roles.publicEndpoint`; nothing ranks the palette itself. `scheme` is
|
|
38299
|
+
* the one the caller shows LAN rows in (as `getConnectionEndpoints`);
|
|
38300
|
+
* `internal` and `publicEndpoint` are always resolved over the HTTPS
|
|
38301
|
+
* palette.
|
|
38103
38302
|
*/
|
|
38104
|
-
|
|
38303
|
+
getAddresses: require_sleep.method(zod.z.object({ scheme: zod.z.enum(["http", "https"]).optional() }).optional(), HubAddressBookSchema),
|
|
38105
38304
|
/**
|
|
38106
|
-
*
|
|
38107
|
-
*
|
|
38108
|
-
*
|
|
38305
|
+
* Add a custom address. Validated: an http(s) origin with a host, no
|
|
38306
|
+
* credentials, no path, never loopback — an invalid one is refused with
|
|
38307
|
+
* the reason and nothing is stored. Adding an address that already exists
|
|
38308
|
+
* only updates its label.
|
|
38109
38309
|
*/
|
|
38110
|
-
|
|
38111
|
-
|
|
38112
|
-
|
|
38113
|
-
}),
|
|
38310
|
+
addCustomAddress: require_sleep.method(zod.z.object({
|
|
38311
|
+
baseUrl: zod.z.string(),
|
|
38312
|
+
label: zod.z.string().max(80)
|
|
38313
|
+
}), HubAddressBookSchema, {
|
|
38314
|
+
kind: "mutation",
|
|
38315
|
+
auth: "admin"
|
|
38316
|
+
}),
|
|
38317
|
+
/** Remove a custom address. Its role flags go with it (those roles turn automatic). */
|
|
38318
|
+
removeCustomAddress: require_sleep.method(zod.z.object({ baseUrl: zod.z.string() }), HubAddressBookSchema, {
|
|
38114
38319
|
kind: "mutation",
|
|
38115
38320
|
auth: "admin"
|
|
38116
38321
|
}),
|
|
38117
38322
|
/**
|
|
38323
|
+
* Flag (`enabled: true`) or unflag an address for a role. For a
|
|
38324
|
+
* single-valued role, flagging moves the flag off every other address.
|
|
38325
|
+
* `baseUrl: null` returns the role to automatic. The address must be a row
|
|
38326
|
+
* of the table (detected, custom, or the app link for `notificationTaps`);
|
|
38327
|
+
* `publicEndpoint` on a plain-http address is refused unless
|
|
38328
|
+
* `acceptInsecureHttp`, and never takes the app link.
|
|
38329
|
+
*/
|
|
38330
|
+
setAddressRole: require_sleep.method(zod.z.object({
|
|
38331
|
+
role: HubAddressRoleSchema,
|
|
38332
|
+
baseUrl: zod.z.string().nullable(),
|
|
38333
|
+
enabled: zod.z.boolean(),
|
|
38334
|
+
acceptInsecureHttp: zod.z.boolean().optional()
|
|
38335
|
+
}), HubAddressBookSchema, {
|
|
38336
|
+
kind: "mutation",
|
|
38337
|
+
auth: "admin"
|
|
38338
|
+
}),
|
|
38339
|
+
/**
|
|
38340
|
+
* @deprecated Read `getAddresses().roles.internal` / `.publicEndpoint`.
|
|
38341
|
+
* Kept so an addon built against the D729 amendment keeps resolving:
|
|
38342
|
+
* `cluster` = the `internal` role, `browser` = the `publicEndpoint` role.
|
|
38343
|
+
*/
|
|
38344
|
+
getHubAddresses: require_sleep.method(zod.z.void(), HubAddressesSchema),
|
|
38345
|
+
/**
|
|
38118
38346
|
* Read the operator's allowlist. Empty = "auto" (no filter). Used
|
|
38119
38347
|
* by the admin UI's address selector to seed its checkbox state.
|
|
38120
38348
|
*/
|
|
@@ -53757,12 +53985,24 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
53757
53985
|
addonId: null,
|
|
53758
53986
|
access: "view"
|
|
53759
53987
|
},
|
|
53988
|
+
"localNetwork.addCustomAddress": {
|
|
53989
|
+
capName: "local-network",
|
|
53990
|
+
capScope: "system",
|
|
53991
|
+
addonId: null,
|
|
53992
|
+
access: "create"
|
|
53993
|
+
},
|
|
53760
53994
|
"localNetwork.downloadCa": {
|
|
53761
53995
|
capName: "local-network",
|
|
53762
53996
|
capScope: "system",
|
|
53763
53997
|
addonId: null,
|
|
53764
53998
|
access: "view"
|
|
53765
53999
|
},
|
|
54000
|
+
"localNetwork.getAddresses": {
|
|
54001
|
+
capName: "local-network",
|
|
54002
|
+
capScope: "system",
|
|
54003
|
+
addonId: null,
|
|
54004
|
+
access: "view"
|
|
54005
|
+
},
|
|
53766
54006
|
"localNetwork.getAllowedAddresses": {
|
|
53767
54007
|
capName: "local-network",
|
|
53768
54008
|
capScope: "system",
|
|
@@ -53817,6 +54057,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
53817
54057
|
addonId: null,
|
|
53818
54058
|
access: "create"
|
|
53819
54059
|
},
|
|
54060
|
+
"localNetwork.removeCustomAddress": {
|
|
54061
|
+
capName: "local-network",
|
|
54062
|
+
capScope: "system",
|
|
54063
|
+
addonId: null,
|
|
54064
|
+
access: "delete"
|
|
54065
|
+
},
|
|
53820
54066
|
"localNetwork.resetAllowlistToBestMatch": {
|
|
53821
54067
|
capName: "local-network",
|
|
53822
54068
|
capScope: "system",
|
|
@@ -53829,13 +54075,13 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
53829
54075
|
addonId: null,
|
|
53830
54076
|
access: "create"
|
|
53831
54077
|
},
|
|
53832
|
-
"localNetwork.
|
|
54078
|
+
"localNetwork.setAddressRole": {
|
|
53833
54079
|
capName: "local-network",
|
|
53834
54080
|
capScope: "system",
|
|
53835
54081
|
addonId: null,
|
|
53836
54082
|
access: "create"
|
|
53837
54083
|
},
|
|
53838
|
-
"localNetwork.
|
|
54084
|
+
"localNetwork.setAllowedAddresses": {
|
|
53839
54085
|
capName: "local-network",
|
|
53840
54086
|
capScope: "system",
|
|
53841
54087
|
addonId: null,
|
|
@@ -58089,6 +58335,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
58089
58335
|
addonId: null,
|
|
58090
58336
|
access: "create"
|
|
58091
58337
|
},
|
|
58338
|
+
"webrtcSession.applyDownlinkProbe": {
|
|
58339
|
+
capName: "webrtc-session",
|
|
58340
|
+
capScope: "device",
|
|
58341
|
+
addonId: null,
|
|
58342
|
+
access: "create"
|
|
58343
|
+
},
|
|
58092
58344
|
"webrtcSession.closeSession": {
|
|
58093
58345
|
capName: "webrtc-session",
|
|
58094
58346
|
capScope: "device",
|
|
@@ -65363,6 +65615,11 @@ var METHOD_DEVICE_SELECTORS = Object.freeze({
|
|
|
65363
65615
|
form: "single",
|
|
65364
65616
|
optional: false
|
|
65365
65617
|
}],
|
|
65618
|
+
"webrtcSession.applyDownlinkProbe": [{
|
|
65619
|
+
name: "deviceId",
|
|
65620
|
+
form: "single",
|
|
65621
|
+
optional: false
|
|
65622
|
+
}],
|
|
65366
65623
|
"webrtcSession.closeSession": [{
|
|
65367
65624
|
name: "deviceId",
|
|
65368
65625
|
form: "single",
|
|
@@ -66403,8 +66660,11 @@ function createSystemProxy(api) {
|
|
|
66403
66660
|
setNotificationEndpoint: (input) => dispatch("localNetwork", "setNotificationEndpoint", "mutation", input),
|
|
66404
66661
|
getViewerEndpoints: (input) => dispatch("localNetwork", "getViewerEndpoints", "query", input),
|
|
66405
66662
|
setViewerEndpoints: (input) => dispatch("localNetwork", "setViewerEndpoints", "mutation", input),
|
|
66663
|
+
getAddresses: (input) => dispatch("localNetwork", "getAddresses", "query", input),
|
|
66664
|
+
addCustomAddress: (input) => dispatch("localNetwork", "addCustomAddress", "mutation", input),
|
|
66665
|
+
removeCustomAddress: (input) => dispatch("localNetwork", "removeCustomAddress", "mutation", input),
|
|
66666
|
+
setAddressRole: (input) => dispatch("localNetwork", "setAddressRole", "mutation", input),
|
|
66406
66667
|
getHubAddresses: (input) => dispatch("localNetwork", "getHubAddresses", "query", input),
|
|
66407
|
-
setHubAddress: (input) => dispatch("localNetwork", "setHubAddress", "mutation", input),
|
|
66408
66668
|
getAllowedAddresses: (input) => dispatch("localNetwork", "getAllowedAddresses", "query", input),
|
|
66409
66669
|
setAllowedAddresses: (input) => dispatch("localNetwork", "setAllowedAddresses", "mutation", input),
|
|
66410
66670
|
resetAllowlistToBestMatch: (input) => dispatch("localNetwork", "resetAllowlistToBestMatch", "mutation", input),
|
|
@@ -68657,17 +68917,23 @@ var NC_ALARM_DELAY_FIELDS = [
|
|
|
68657
68917
|
* all read this one constant.
|
|
68658
68918
|
*/
|
|
68659
68919
|
var NC_ALARM_DEFAULT_TRIGGERED_DURATION_SEC = 30;
|
|
68660
|
-
var NC_ALARM_NOTIFY_FIELDS = [
|
|
68920
|
+
var NC_ALARM_NOTIFY_FIELDS = [
|
|
68921
|
+
"notifyDuringEntryDelay",
|
|
68922
|
+
"notifySensorRewatched",
|
|
68923
|
+
"notifySensorIgnored"
|
|
68924
|
+
];
|
|
68661
68925
|
/**
|
|
68662
68926
|
* The switches `mode` runs on. There is no global value: absent is OFF (operator decision
|
|
68663
68927
|
* 2026-10-06 — the entry-delay notification is the only one by default, and "watched again"
|
|
68664
|
-
* is not sent). An answer from an older hub carries no
|
|
68928
|
+
* is not sent; 2026-10-07 — nor is "ignored", D735). An answer from an older hub carries no
|
|
68929
|
+
* switch and reads as off.
|
|
68665
68930
|
*/
|
|
68666
68931
|
function resolveModeNotifyPolicy(settings, mode) {
|
|
68667
68932
|
const entry = (settings.modeDelays ?? []).find((e) => e.mode === mode);
|
|
68668
68933
|
return {
|
|
68669
68934
|
notifyDuringEntryDelay: entry?.notifyDuringEntryDelay === true,
|
|
68670
|
-
notifySensorRewatched: entry?.notifySensorRewatched === true
|
|
68935
|
+
notifySensorRewatched: entry?.notifySensorRewatched === true,
|
|
68936
|
+
notifySensorIgnored: entry?.notifySensorIgnored === true
|
|
68671
68937
|
};
|
|
68672
68938
|
}
|
|
68673
68939
|
/**
|
|
@@ -68759,6 +69025,7 @@ function applyModeDelaysEdits(current, edits) {
|
|
|
68759
69025
|
const schedule = editedSchedule(base.schedule, edit.schedule);
|
|
68760
69026
|
const duringEntry = editedFlag(base.notifyDuringEntryDelay, edit.notifyDuringEntryDelay);
|
|
68761
69027
|
const rewatched = editedFlag(base.notifySensorRewatched, edit.notifySensorRewatched);
|
|
69028
|
+
const ignored = editedFlag(base.notifySensorIgnored, edit.notifySensorIgnored);
|
|
68762
69029
|
if (exit !== void 0) next.exitDelaySec = exit;
|
|
68763
69030
|
if (entry !== void 0) next.entryDelaySec = entry;
|
|
68764
69031
|
if (triggered !== void 0) next.triggeredDurationSec = triggered;
|
|
@@ -68766,10 +69033,11 @@ function applyModeDelaysEdits(current, edits) {
|
|
|
68766
69033
|
if (schedule !== void 0) next.schedule = schedule;
|
|
68767
69034
|
if (duringEntry !== void 0) next.notifyDuringEntryDelay = duringEntry;
|
|
68768
69035
|
if (rewatched !== void 0) next.notifySensorRewatched = rewatched;
|
|
69036
|
+
if (ignored !== void 0) next.notifySensorIgnored = ignored;
|
|
68769
69037
|
if (at >= 0) out[at] = next;
|
|
68770
69038
|
else out.push(next);
|
|
68771
69039
|
}
|
|
68772
|
-
return out.filter((e) => e.exitDelaySec !== void 0 || e.entryDelaySec !== void 0 || e.triggeredDurationSec !== void 0 || e.postTriggeredAction !== void 0 || e.schedule !== void 0 || e.notifyDuringEntryDelay !== void 0 || e.notifySensorRewatched !== void 0);
|
|
69040
|
+
return out.filter((e) => e.exitDelaySec !== void 0 || e.entryDelaySec !== void 0 || e.triggeredDurationSec !== void 0 || e.postTriggeredAction !== void 0 || e.schedule !== void 0 || e.notifyDuringEntryDelay !== void 0 || e.notifySensorRewatched !== void 0 || e.notifySensorIgnored !== void 0);
|
|
68773
69041
|
}
|
|
68774
69042
|
/**
|
|
68775
69043
|
* Put ONE device on, or take it off, ONE mode's device-id list. A no-op answers
|
|
@@ -73591,6 +73859,7 @@ exports.AUDIO_NOT_CLASSIFIED_REASONS = AUDIO_NOT_CLASSIFIED_REASONS;
|
|
|
73591
73859
|
exports.AUDIO_PRESETS = require_composition.AUDIO_PRESETS;
|
|
73592
73860
|
exports.AUDIO_SCALE_EPOCH_ISO = AUDIO_SCALE_EPOCH_ISO;
|
|
73593
73861
|
exports.AUDIO_SCALE_EPOCH_MS = AUDIO_SCALE_EPOCH_MS;
|
|
73862
|
+
exports.AUTOMATIC_HUB_ADDRESS_FLAGS = AUTOMATIC_HUB_ADDRESS_FLAGS;
|
|
73594
73863
|
exports.AccessoriesStatusSchema = AccessoriesStatusSchema;
|
|
73595
73864
|
exports.AccessoryKind = AccessoryKind;
|
|
73596
73865
|
exports.AddBrokerInputSchema = AddBrokerInputSchema;
|
|
@@ -74158,12 +74427,14 @@ exports.HAP_KEYFRAME_INTERVAL_SEC = HAP_KEYFRAME_INTERVAL_SEC;
|
|
|
74158
74427
|
exports.HF_BASE_URL = HF_BASE_URL;
|
|
74159
74428
|
exports.HF_REPO = HF_REPO;
|
|
74160
74429
|
exports.HOURS_PER_DAY = HOURS_PER_DAY;
|
|
74430
|
+
exports.HUB_ADDRESS_ROLES = HUB_ADDRESS_ROLES;
|
|
74161
74431
|
exports.HUB_VIEWER_MOUNT = HUB_VIEWER_MOUNT;
|
|
74162
74432
|
exports.HWACCEL_OPTIONS = HWACCEL_OPTIONS;
|
|
74163
74433
|
exports.HealthStatusSchema = HealthStatusSchema;
|
|
74164
74434
|
exports.HfModelResolutionSchema = HfModelResolutionSchema;
|
|
74165
74435
|
exports.HistoryPointSchema = HistoryPointSchema;
|
|
74166
74436
|
exports.HistoryResolutionEnum = HistoryResolutionEnum;
|
|
74437
|
+
exports.HubAddressRoleSchema = HubAddressRoleSchema;
|
|
74167
74438
|
exports.HumidifierStatusSchema = HumidifierStatusSchema;
|
|
74168
74439
|
exports.HumiditySensorStatusSchema = HumiditySensorStatusSchema;
|
|
74169
74440
|
exports.HvacModeSchema = HvacModeSchema;
|
|
@@ -74638,6 +74909,7 @@ exports.PIPELINE_OWNER_CAPABILITY_NAMES = PIPELINE_OWNER_CAPABILITY_NAMES;
|
|
|
74638
74909
|
exports.PRIVACY_MASK_CAP_NAME = PRIVACY_MASK_CAP_NAME;
|
|
74639
74910
|
exports.PROVIDER_KIND_CAP_NAMES = PROVIDER_KIND_CAP_NAMES;
|
|
74640
74911
|
exports.PROVIDER_PIN_FIELD = require_sleep.PROVIDER_PIN_FIELD;
|
|
74912
|
+
exports.PUBLIC_ENDPOINT_HTTP_REASON = PUBLIC_ENDPOINT_HTTP_REASON;
|
|
74641
74913
|
exports.PYTHON_SCRIPT = PYTHON_SCRIPT;
|
|
74642
74914
|
exports.PackageUpdateSchema = PackageUpdateSchema;
|
|
74643
74915
|
exports.PackageVersionInfoSchema = PackageVersionInfoSchema;
|
|
@@ -74823,6 +75095,7 @@ exports.SCOPE_PRESETS = SCOPE_PRESETS;
|
|
|
74823
75095
|
exports.SENSOR_FEATURES = SENSOR_FEATURES;
|
|
74824
75096
|
exports.SENSOR_MAP = SENSOR_MAP;
|
|
74825
75097
|
exports.SHARE_VIEW_KINDS = require_sleep.SHARE_VIEW_KINDS;
|
|
75098
|
+
exports.SINGLE_HUB_ADDRESS_ROLES = SINGLE_HUB_ADDRESS_ROLES;
|
|
74826
75099
|
exports.SOURCE_CAPS = require_composition.SOURCE_CAPS;
|
|
74827
75100
|
exports.SOURCE_CAP_ACTIVE_FIELD = require_composition.SOURCE_CAP_ACTIVE_FIELD;
|
|
74828
75101
|
exports.SOURCE_CAP_CHANGED_AT_FIELD = require_composition.SOURCE_CAP_CHANGED_AT_FIELD;
|
|
@@ -75170,6 +75443,7 @@ exports.canConvertUnit = canConvertUnit;
|
|
|
75170
75443
|
exports.canonicalEgressPlan = canonicalEgressPlan;
|
|
75171
75444
|
exports.carbonMonoxideCapability = carbonMonoxideCapability;
|
|
75172
75445
|
exports.cellsToRects = cellsToRects;
|
|
75446
|
+
exports.checkRoleAddress = checkRoleAddress;
|
|
75173
75447
|
exports.classifyBearerPrincipal = classifyBearerPrincipal;
|
|
75174
75448
|
exports.classifyStream = classifyStream;
|
|
75175
75449
|
exports.classifyStreams = classifyStreams;
|
|
@@ -75404,6 +75678,7 @@ exports.isBatteryPresenceFault = isBatteryPresenceFault;
|
|
|
75404
75678
|
exports.isClusterScopedStep = isClusterScopedStep;
|
|
75405
75679
|
exports.isCollectionArrayMethod = isCollectionArrayMethod;
|
|
75406
75680
|
exports.isDefaultAlarmProfileId = isDefaultAlarmProfileId;
|
|
75681
|
+
exports.isDefaultAppConnectionEndpoint = isDefaultAppConnectionEndpoint;
|
|
75407
75682
|
exports.isDeployableToAgent = isDeployableToAgent;
|
|
75408
75683
|
exports.isDetectionMacroClass = isDetectionMacroClass;
|
|
75409
75684
|
exports.isDeviceConfigCap = require_sleep.isDeviceConfigCap;
|
|
@@ -75433,6 +75708,7 @@ exports.isRootSuppliableStepId = isRootSuppliableStepId;
|
|
|
75433
75708
|
exports.isSameAddonId = isSameAddonId;
|
|
75434
75709
|
exports.isScheduleActive = isScheduleActive;
|
|
75435
75710
|
exports.isSecretConfigField = isSecretConfigField;
|
|
75711
|
+
exports.isSingleHubAddressRole = isSingleHubAddressRole;
|
|
75436
75712
|
exports.isSoftwareDecode = require_composition.isSoftwareDecode;
|
|
75437
75713
|
exports.isSourceCap = require_composition.isSourceCap;
|
|
75438
75714
|
exports.isStateLabelKey = isStateLabelKey;
|
|
@@ -75549,8 +75825,6 @@ exports.pickAppLinkHub = pickAppLinkHub;
|
|
|
75549
75825
|
exports.pickClusterStepModels = pickClusterStepModels;
|
|
75550
75826
|
exports.pickClusterStepSettings = pickClusterStepSettings;
|
|
75551
75827
|
exports.pickDetailCropConvention = pickDetailCropConvention;
|
|
75552
|
-
exports.pickHubBaseUrl = pickHubBaseUrl;
|
|
75553
|
-
exports.pickHubHostname = pickHubHostname;
|
|
75554
75828
|
exports.pickInvalidClusterStepModels = pickInvalidClusterStepModels;
|
|
75555
75829
|
exports.pickNativeLeaseOverride = pickNativeLeaseOverride;
|
|
75556
75830
|
exports.pickPreferredRtspEntry = pickPreferredRtspEntry;
|
|
@@ -75611,6 +75885,7 @@ exports.resetPoolBaseline = resetPoolBaseline;
|
|
|
75611
75885
|
exports.resolveAddonExecution = resolveAddonExecution;
|
|
75612
75886
|
exports.resolveAddonGroup = resolveAddonGroup;
|
|
75613
75887
|
exports.resolveAddonPlacement = resolveAddonPlacement;
|
|
75888
|
+
exports.resolveAppConnections = resolveAppConnections;
|
|
75614
75889
|
exports.resolveBucketMs = resolveBucketMs;
|
|
75615
75890
|
exports.resolveCapMount = require_sleep.resolveCapMount;
|
|
75616
75891
|
exports.resolveClipSearchMinScore = resolveClipSearchMinScore;
|
|
@@ -75624,15 +75899,18 @@ exports.resolveDeviceProfile = resolveDeviceProfile;
|
|
|
75624
75899
|
exports.resolveEgressDecodeHwAccel = resolveEgressDecodeHwAccel;
|
|
75625
75900
|
exports.resolveExportProfiles = resolveExportProfiles;
|
|
75626
75901
|
exports.resolveFormat = resolveFormat;
|
|
75627
|
-
exports.
|
|
75902
|
+
exports.resolveHubAddressRoles = resolveHubAddressRoles;
|
|
75628
75903
|
exports.resolveHydratedFieldValue = require_sleep.resolveHydratedFieldValue;
|
|
75904
|
+
exports.resolveInternalAddress = resolveInternalAddress;
|
|
75629
75905
|
exports.resolveLocationIcon = resolveLocationIcon;
|
|
75630
75906
|
exports.resolveLocationMode = resolveLocationMode;
|
|
75631
75907
|
exports.resolveMethodAuth = resolveMethodAuth;
|
|
75632
75908
|
exports.resolveModeDelays = resolveModeDelays;
|
|
75633
75909
|
exports.resolveModeNotifyPolicy = resolveModeNotifyPolicy;
|
|
75634
75910
|
exports.resolveMutate = resolveMutate;
|
|
75911
|
+
exports.resolveNotificationTapAddress = resolveNotificationTapAddress;
|
|
75635
75912
|
exports.resolvePoolMemoryPolicy = resolvePoolMemoryPolicy;
|
|
75913
|
+
exports.resolvePublicEndpoint = resolvePublicEndpoint;
|
|
75636
75914
|
exports.resolveRecordingProfiles = resolveRecordingProfiles;
|
|
75637
75915
|
exports.resolveRootSupply = resolveRootSupply;
|
|
75638
75916
|
exports.resolveRunnerId = resolveRunnerId;
|
|
@@ -75671,6 +75949,7 @@ exports.scoreRuntimes = scoreRuntimes;
|
|
|
75671
75949
|
exports.scriptRunnerCapability = scriptRunnerCapability;
|
|
75672
75950
|
exports.searchDisplayIcons = searchDisplayIcons;
|
|
75673
75951
|
exports.secureActuationFor = secureActuationFor;
|
|
75952
|
+
exports.selectAppConnectionEndpoints = selectAppConnectionEndpoints;
|
|
75674
75953
|
exports.selectAssignedProfileSlots = require_sleep.selectAssignedProfileSlots;
|
|
75675
75954
|
exports.sendTimesForEditor = sendTimesForEditor;
|
|
75676
75955
|
exports.sendTimesOfSchedule = sendTimesOfSchedule;
|
|
@@ -75763,8 +76042,8 @@ exports.userManagementCapability = userManagementCapability;
|
|
|
75763
76042
|
exports.userPasskeysCapability = userPasskeysCapability;
|
|
75764
76043
|
exports.vacuumControlCapability = vacuumControlCapability;
|
|
75765
76044
|
exports.validateComposition = validateComposition;
|
|
76045
|
+
exports.validateCustomAddress = validateCustomAddress;
|
|
75766
76046
|
exports.validateExpressionSource = require_composition.validateExpressionSource;
|
|
75767
|
-
exports.validateHubAddressOverride = validateHubAddressOverride;
|
|
75768
76047
|
exports.validateRecipeBounds = validateRecipeBounds;
|
|
75769
76048
|
exports.valveCapability = valveCapability;
|
|
75770
76049
|
exports.vectorDimFromBase64 = vectorDimFromBase64;
|