@camstack/system 1.2.358 → 1.2.359
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-runner.js +1 -1
- package/dist/addon-runner.mjs +1 -1
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
- package/dist/builtins/alerts/alerts.addon.js +1 -1
- package/dist/builtins/alerts/alerts.addon.mjs +1 -1
- package/dist/builtins/autotrack/index.js +1 -1
- package/dist/builtins/autotrack/index.mjs +1 -1
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1 -1
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
- package/dist/builtins/calendars/calendars.addon.js +1 -1
- package/dist/builtins/calendars/calendars.addon.mjs +1 -1
- package/dist/builtins/camera-grid/index.js +1 -1
- package/dist/builtins/camera-grid/index.mjs +1 -1
- package/dist/builtins/composer/composer.addon.js +2 -2
- package/dist/builtins/composer/composer.addon.mjs +2 -2
- package/dist/builtins/console-logging/index.js +1 -1
- package/dist/builtins/console-logging/index.mjs +1 -1
- package/dist/builtins/core-blocks/core-blocks.addon.js +2 -2
- package/dist/builtins/core-blocks/core-blocks.addon.mjs +2 -2
- package/dist/builtins/device-manager/device-manager.addon.js +2 -2
- package/dist/builtins/device-manager/device-manager.addon.mjs +2 -2
- package/dist/builtins/hub-forwarder/index.js +1 -1
- package/dist/builtins/hub-forwarder/index.mjs +1 -1
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
- package/dist/builtins/local-auth/local-auth.addon.js +1 -1
- package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
- package/dist/builtins/local-network/address-book.d.ts +69 -0
- package/dist/builtins/local-network/local-network.addon.d.ts +38 -45
- package/dist/builtins/local-network/local-network.addon.js +359 -76
- package/dist/builtins/local-network/local-network.addon.mjs +360 -75
- package/dist/builtins/loki-logging/index.js +1 -1
- package/dist/builtins/loki-logging/index.mjs +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
- package/dist/builtins/platform-probe/index.js +1 -1
- package/dist/builtins/platform-probe/index.mjs +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
- package/dist/builtins/snapshot/index.js +1 -1
- package/dist/builtins/snapshot/index.mjs +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +0 -0
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +0 -0
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
- package/dist/builtins/system-config/system-config.addon.js +1 -1
- package/dist/builtins/system-config/system-config.addon.mjs +1 -1
- package/dist/builtins/winston-logging/index.js +1 -1
- package/dist/builtins/winston-logging/index.mjs +1 -1
- package/dist/{child-cap-dispatch-C2dFiu87.mjs → child-cap-dispatch-Dm1TRDCr.mjs} +1 -1
- package/dist/{child-cap-dispatch-BWk99kmA.js → child-cap-dispatch-t61ohDpb.js} +1 -1
- package/dist/{composition-sources-BaHPH661.js → composition-sources-CCU_KizO.js} +1 -1
- package/dist/{composition-sources-D8Hapyav.mjs → composition-sources-CHlfWHl6.mjs} +1 -1
- package/dist/{dist-DzAHit0a.js → dist-W_X44h-s.js} +386 -106
- package/dist/{dist-D3bhbMY3.mjs → dist-pTfD_M-U.mjs} +353 -103
- package/dist/index.js +2 -2
- package/dist/index.mjs +2 -2
- package/dist/{retired-settings-keys-B6AFmtlO.mjs → retired-settings-keys-CK_ifret.mjs} +1 -1
- package/dist/{retired-settings-keys-CkXoPjKy.js → retired-settings-keys-jglEzgWR.js} +1 -1
- package/package.json +1 -1
|
@@ -1,8 +1,232 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Ar as EventCategory, Ft as isAppLinkBase, Kt as localNetworkCapability, Rn as validateCustomAddress, Rt as isDefaultViewerEndpoint, Sn as resolveViewerAddresses, ar as BaseAddon, cn as pickAppLinkHub, s as CAMSTACK_APP_LINK_ORIGIN, tt as checkRoleAddress, vn as resolveHubAddressRoles, xn as resolveNotificationsAddress } from "../../dist-pTfD_M-U.mjs";
|
|
2
2
|
import { P as readLanHttpState, _ as writeExtraSans, h as readTlsMode, i as storeUploadedCertificate, j as applyLanHttp, k as DEFAULT_LAN_HTTP_PORT, m as readTlsAccessStatus, n as regenerateCertificate, p as readExtraSans, r as revertToGeneratedCertificate, t as applyCertificateToListener, u as servedHttpsLeafFingerprint, y as ensureTlsCert } from "../../tls-CJHogwTl.mjs";
|
|
3
|
+
import { z } from "zod";
|
|
3
4
|
import * as os from "node:os";
|
|
4
5
|
import { readFileSync } from "node:fs";
|
|
5
6
|
import { isIP } from "node:net";
|
|
7
|
+
//#region src/builtins/local-network/address-book.ts
|
|
8
|
+
/**
|
|
9
|
+
* The Network page's address book, as pure functions: custom addresses plus
|
|
10
|
+
* the role flags carried by detected and custom addresses alike.
|
|
11
|
+
*
|
|
12
|
+
* ## Storage
|
|
13
|
+
*
|
|
14
|
+
* The role flags keep the keys they always had, so a rolled-back hub reads
|
|
15
|
+
* them with the meaning it knew: `viewerBaseUrls` (viewer, many),
|
|
16
|
+
* `notificationBaseUrl` (notifications, D709), `agentBaseUrl` and
|
|
17
|
+
* `signInBaseUrl` (agents / sign-in, D729 amendment). A single-valued role is
|
|
18
|
+
* one URL — at most one address carries it, by construction. `''` / `[]` is
|
|
19
|
+
* automatic. The custom addresses are `customAddresses` (url + label).
|
|
20
|
+
*
|
|
21
|
+
* ## Migration in the read path
|
|
22
|
+
*
|
|
23
|
+
* Before this, a single-valued flag could name an address that was in no row:
|
|
24
|
+
* the notification links' typed custom address (D709) and the two hub-address
|
|
25
|
+
* overrides (D729 amendment) were free URLs. {@link normalizeAddressBook}
|
|
26
|
+
* turns every such flag into a custom address carrying that role, on every
|
|
27
|
+
* read; the next write persists the result. It is the same rule forever, not
|
|
28
|
+
* a one-off: a flagged detected address that disappears (a DHCP move) shows up
|
|
29
|
+
* as a custom row instead of vanishing while it still wins.
|
|
30
|
+
*/
|
|
31
|
+
var CustomAddressListSchema = z.array(z.object({
|
|
32
|
+
baseUrl: z.string(),
|
|
33
|
+
label: z.string()
|
|
34
|
+
}));
|
|
35
|
+
/** The label a flag promoted to a custom address is given. */
|
|
36
|
+
var PROMOTED_LABEL = {
|
|
37
|
+
notifications: "Notification links address",
|
|
38
|
+
agents: "Hub address for agents",
|
|
39
|
+
signIn: "Sign-in address"
|
|
40
|
+
};
|
|
41
|
+
var SINGLE_ROLES = [
|
|
42
|
+
"notifications",
|
|
43
|
+
"agents",
|
|
44
|
+
"signIn"
|
|
45
|
+
];
|
|
46
|
+
function flagOf(value) {
|
|
47
|
+
return value === "" ? null : value;
|
|
48
|
+
}
|
|
49
|
+
/** Parse the stored custom list; a malformed store reads as empty, never throws. */
|
|
50
|
+
function parseCustomAddresses(raw) {
|
|
51
|
+
const parsed = CustomAddressListSchema.safeParse(raw ?? []);
|
|
52
|
+
return parsed.success ? parsed.data : [];
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* The address book as it stands: stored custom addresses, plus every
|
|
56
|
+
* single-valued flag that names neither a detected address, a custom one nor
|
|
57
|
+
* the app link, promoted to a custom address (see the module doc).
|
|
58
|
+
*/
|
|
59
|
+
function normalizeAddressBook(stored, detectedUrls) {
|
|
60
|
+
const flags = {
|
|
61
|
+
viewer: stored.viewerBaseUrls,
|
|
62
|
+
notifications: flagOf(stored.notificationBaseUrl),
|
|
63
|
+
agents: flagOf(stored.agentBaseUrl),
|
|
64
|
+
signIn: flagOf(stored.signInBaseUrl)
|
|
65
|
+
};
|
|
66
|
+
const custom = [...parseCustomAddresses(stored.customAddresses)];
|
|
67
|
+
for (const role of SINGLE_ROLES) {
|
|
68
|
+
const url = flags[role];
|
|
69
|
+
if (url === null || isAppLinkBase(url) || detectedUrls.has(url)) continue;
|
|
70
|
+
if (custom.some((c) => c.baseUrl === url)) continue;
|
|
71
|
+
custom.push({
|
|
72
|
+
baseUrl: url,
|
|
73
|
+
label: PROMOTED_LABEL[role]
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
custom,
|
|
78
|
+
flags
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/** The stored-settings patch that persists `state`. */
|
|
82
|
+
function addressBookPatch(state) {
|
|
83
|
+
return {
|
|
84
|
+
customAddresses: state.custom,
|
|
85
|
+
viewerBaseUrls: state.flags.viewer,
|
|
86
|
+
notificationBaseUrl: state.flags.notifications ?? "",
|
|
87
|
+
agentBaseUrl: state.flags.agents ?? "",
|
|
88
|
+
signInBaseUrl: state.flags.signIn ?? ""
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function withCustomAddress(state, entry) {
|
|
92
|
+
const custom = state.custom.some((c) => c.baseUrl === entry.baseUrl) ? state.custom.map((c) => c.baseUrl === entry.baseUrl ? entry : c) : [...state.custom, entry];
|
|
93
|
+
return {
|
|
94
|
+
...state,
|
|
95
|
+
custom
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
/** Drop a custom address and every flag it carried (those roles turn automatic). */
|
|
99
|
+
function withoutCustomAddress(state, baseUrl) {
|
|
100
|
+
const clear = (flag) => flag === baseUrl ? null : flag;
|
|
101
|
+
return {
|
|
102
|
+
custom: state.custom.filter((c) => c.baseUrl !== baseUrl),
|
|
103
|
+
flags: {
|
|
104
|
+
viewer: state.flags.viewer.filter((u) => u !== baseUrl),
|
|
105
|
+
notifications: clear(state.flags.notifications),
|
|
106
|
+
agents: clear(state.flags.agents),
|
|
107
|
+
signIn: clear(state.flags.signIn)
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
/** Every role back to automatic for `role`. */
|
|
112
|
+
function withRoleAutomatic(state, role) {
|
|
113
|
+
return role === "viewer" ? {
|
|
114
|
+
...state,
|
|
115
|
+
flags: {
|
|
116
|
+
...state.flags,
|
|
117
|
+
viewer: []
|
|
118
|
+
}
|
|
119
|
+
} : {
|
|
120
|
+
...state,
|
|
121
|
+
flags: {
|
|
122
|
+
...state.flags,
|
|
123
|
+
[role]: null
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Flag or unflag `baseUrl` for `role`. A single-valued role flagged here moves
|
|
129
|
+
* off every other address (it is one URL); unflagging the address that carries
|
|
130
|
+
* it returns the role to automatic. The app link flagged for notifications IS
|
|
131
|
+
* the automatic answer, stored as automatic — one representation. `viewer`
|
|
132
|
+
* toggles inside the set; toggling while automatic starts from the automatic
|
|
133
|
+
* set (`autoViewer`) so the other addresses keep racing.
|
|
134
|
+
*/
|
|
135
|
+
function withRoleFlag(state, role, baseUrl, enabled, autoViewer) {
|
|
136
|
+
if (role === "viewer") {
|
|
137
|
+
const without = (state.flags.viewer.length === 0 ? autoViewer : state.flags.viewer).filter((u) => u !== baseUrl);
|
|
138
|
+
const viewer = enabled ? [...without, baseUrl] : without;
|
|
139
|
+
return {
|
|
140
|
+
...state,
|
|
141
|
+
flags: {
|
|
142
|
+
...state.flags,
|
|
143
|
+
viewer
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
if (role === "notifications" && isAppLinkBase(baseUrl)) return withRoleAutomatic(state, role);
|
|
148
|
+
if (enabled) return {
|
|
149
|
+
...state,
|
|
150
|
+
flags: {
|
|
151
|
+
...state.flags,
|
|
152
|
+
[role]: baseUrl
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
return state.flags[role] === baseUrl ? withRoleAutomatic(state, role) : state;
|
|
156
|
+
}
|
|
157
|
+
/** What a row may be flagged with. */
|
|
158
|
+
function eligibleRoles(endpoint) {
|
|
159
|
+
if (endpoint.kind === "loopback") return [];
|
|
160
|
+
if (endpoint.kind === "app-link") return ["notifications"];
|
|
161
|
+
return [
|
|
162
|
+
"viewer",
|
|
163
|
+
"notifications",
|
|
164
|
+
"agents",
|
|
165
|
+
"signIn"
|
|
166
|
+
];
|
|
167
|
+
}
|
|
168
|
+
/** A custom address as a palette entry (`kind: 'custom'`). */
|
|
169
|
+
function customEndpoint(entry) {
|
|
170
|
+
return {
|
|
171
|
+
label: entry.label === "" ? "Custom address" : entry.label,
|
|
172
|
+
baseUrl: entry.baseUrl,
|
|
173
|
+
kind: "custom",
|
|
174
|
+
interfaceKind: "other",
|
|
175
|
+
plausible: true,
|
|
176
|
+
plausibleReason: "",
|
|
177
|
+
priority: 200
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* The palette a client races: the detected endpoints plus the custom
|
|
182
|
+
* addresses flagged `viewer` (a detected URL is never listed twice).
|
|
183
|
+
*/
|
|
184
|
+
function withViewerCustomEndpoints(detected, state) {
|
|
185
|
+
const known = new Set(detected.map((e) => e.baseUrl));
|
|
186
|
+
const wanted = new Set(state.flags.viewer);
|
|
187
|
+
const extra = state.custom.filter((c) => wanted.has(c.baseUrl) && !known.has(c.baseUrl)).map(customEndpoint);
|
|
188
|
+
return [...detected, ...extra];
|
|
189
|
+
}
|
|
190
|
+
/** Every role's answer — the resolvers from `@camstack/types`, nothing else. */
|
|
191
|
+
function resolveRoles(state, viewerPalette, httpsPalette) {
|
|
192
|
+
return resolveHubAddressRoles(withViewerCustomEndpoints(viewerPalette, state), httpsPalette, state.flags);
|
|
193
|
+
}
|
|
194
|
+
function flagsOn(state, baseUrl) {
|
|
195
|
+
const out = [];
|
|
196
|
+
if (state.flags.viewer.includes(baseUrl)) out.push("viewer");
|
|
197
|
+
for (const role of SINGLE_ROLES) if (state.flags[role] === baseUrl) out.push(role);
|
|
198
|
+
return out;
|
|
199
|
+
}
|
|
200
|
+
function inUseOn(roles, baseUrl) {
|
|
201
|
+
const out = [];
|
|
202
|
+
if (roles.viewer.resolved.includes(baseUrl)) out.push("viewer");
|
|
203
|
+
for (const role of SINGLE_ROLES) if (roles[role].resolved === baseUrl) out.push(role);
|
|
204
|
+
return out;
|
|
205
|
+
}
|
|
206
|
+
/** The Addresses table: app link, detected rows, then custom-only rows. */
|
|
207
|
+
function buildAddressBook(state, inputs) {
|
|
208
|
+
const roles = resolveRoles(state, inputs.rowsPalette, inputs.httpsPalette);
|
|
209
|
+
const customUrls = new Set(state.custom.map((c) => c.baseUrl));
|
|
210
|
+
const detectedUrls = new Set(inputs.rowsPalette.map((e) => e.baseUrl));
|
|
211
|
+
const row = (endpoint, detected) => ({
|
|
212
|
+
...endpoint,
|
|
213
|
+
detected,
|
|
214
|
+
custom: customUrls.has(endpoint.baseUrl),
|
|
215
|
+
flags: endpoint.kind === "app-link" ? [] : flagsOn(state, endpoint.baseUrl),
|
|
216
|
+
inUse: endpoint.kind === "app-link" ? roles.notifications.resolved === "https://camstack.zentik.app" ? ["notifications"] : [] : inUseOn(roles, endpoint.baseUrl),
|
|
217
|
+
eligible: eligibleRoles(endpoint)
|
|
218
|
+
});
|
|
219
|
+
return {
|
|
220
|
+
rows: [
|
|
221
|
+
row(inputs.appLink, false),
|
|
222
|
+
...inputs.rowsPalette.map((e) => row(e, true)),
|
|
223
|
+
...state.custom.filter((c) => !detectedUrls.has(c.baseUrl)).map((c) => row(customEndpoint(c), false))
|
|
224
|
+
],
|
|
225
|
+
roles,
|
|
226
|
+
appLinkHub: inputs.appLinkHub
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
//#endregion
|
|
6
230
|
//#region src/builtins/local-network/ipv6-lan.ts
|
|
7
231
|
/**
|
|
8
232
|
* IPv6 helpers for LAN advertisement: prefix matching (privacy addresses
|
|
@@ -196,6 +420,7 @@ var LocalNetworkAddon = class extends BaseAddon {
|
|
|
196
420
|
bootSeeded: false,
|
|
197
421
|
notificationBaseUrl: "",
|
|
198
422
|
viewerBaseUrls: [],
|
|
423
|
+
customAddresses: [],
|
|
199
424
|
httpEnabled: true,
|
|
200
425
|
httpPort: DEFAULT_LAN_HTTP_PORT,
|
|
201
426
|
localHostname: "",
|
|
@@ -204,62 +429,126 @@ var LocalNetworkAddon = class extends BaseAddon {
|
|
|
204
429
|
});
|
|
205
430
|
}
|
|
206
431
|
/**
|
|
207
|
-
*
|
|
208
|
-
*
|
|
209
|
-
*
|
|
432
|
+
* The detected palettes, with the mesh reconciled once: `https` (what agents
|
|
433
|
+
* and sign-in resolve over, and the app link's `hub=`) and `http` (what the
|
|
434
|
+
* viewer race resolves over, as before).
|
|
210
435
|
*/
|
|
211
|
-
async
|
|
436
|
+
async palettes() {
|
|
212
437
|
const port = (await this.resolveAdvertisedListenPort(null)).port;
|
|
213
|
-
|
|
438
|
+
await this.reconcileMeshEndpoint();
|
|
214
439
|
return {
|
|
215
|
-
|
|
216
|
-
|
|
440
|
+
http: this.endpointsNow(false, false, "http", port),
|
|
441
|
+
https: this.endpointsNow(false, false, "https", port)
|
|
217
442
|
};
|
|
218
443
|
}
|
|
444
|
+
/** The stored address book, normalised against what is detected now. */
|
|
445
|
+
addressState(detected) {
|
|
446
|
+
return normalizeAddressBook(this.config, new Set(detected.map((e) => e.baseUrl)));
|
|
447
|
+
}
|
|
448
|
+
/** The role flags alone — they do not depend on what is detected. */
|
|
449
|
+
storedFlags() {
|
|
450
|
+
return normalizeAddressBook(this.config, /* @__PURE__ */ new Set()).flags;
|
|
451
|
+
}
|
|
452
|
+
/** `getAddresses`: the Addresses table and every role's answer. */
|
|
453
|
+
async addressBook(scheme) {
|
|
454
|
+
const { http, https } = await this.palettes();
|
|
455
|
+
return buildAddressBook(this.addressState([...http, ...https]), {
|
|
456
|
+
rowsPalette: scheme === "http" ? http : https,
|
|
457
|
+
httpsPalette: https,
|
|
458
|
+
appLink: appLinkEndpoint(),
|
|
459
|
+
appLinkHub: pickAppLinkHub(https)
|
|
460
|
+
});
|
|
461
|
+
}
|
|
219
462
|
/**
|
|
220
|
-
*
|
|
221
|
-
*
|
|
222
|
-
* 2026-10-06; before it AUTO was the tunnel, then the mesh). The app link is
|
|
223
|
-
* not a hub address: the NC's signed media and buttons keep their own hub
|
|
224
|
-
* ladder when it is flagged; only viewer taps take the app form.
|
|
463
|
+
* Apply one change to the address book and persist it, normalised (a flag
|
|
464
|
+
* naming an address in no row becomes a custom address in the same write).
|
|
225
465
|
*/
|
|
226
|
-
|
|
227
|
-
const
|
|
228
|
-
|
|
466
|
+
async changeAddressBook(change) {
|
|
467
|
+
const { http, https } = await this.palettes();
|
|
468
|
+
const detected = [...http, ...https];
|
|
469
|
+
const detectedUrls = new Set(detected.map((e) => e.baseUrl));
|
|
470
|
+
const changed = change(this.addressState(detected), {
|
|
471
|
+
detectedUrls,
|
|
472
|
+
autoViewer: [...new Set(detected.filter(isDefaultViewerEndpoint).map((e) => e.baseUrl))]
|
|
473
|
+
});
|
|
474
|
+
const after = normalizeAddressBook({
|
|
475
|
+
...addressBookPatch(changed),
|
|
476
|
+
customAddresses: changed.custom
|
|
477
|
+
}, detectedUrls);
|
|
478
|
+
await this.updateGlobalSettings(addressBookPatch(after));
|
|
479
|
+
}
|
|
480
|
+
/** The deprecated `getHubAddresses` shape, from the role resolvers. */
|
|
481
|
+
async snapshotHubAddresses() {
|
|
482
|
+
const { roles } = await this.addressBook("https");
|
|
483
|
+
const legacy = (r) => ({
|
|
484
|
+
override: r.flagged,
|
|
485
|
+
resolved: r.resolved,
|
|
486
|
+
source: r.source === "flagged" ? "override" : r.source
|
|
487
|
+
});
|
|
488
|
+
return {
|
|
489
|
+
cluster: legacy(roles.agents),
|
|
490
|
+
browser: legacy(roles.signIn)
|
|
491
|
+
};
|
|
229
492
|
}
|
|
230
493
|
/**
|
|
231
|
-
*
|
|
232
|
-
*
|
|
233
|
-
*
|
|
494
|
+
* Flag / unflag `baseUrl` for `role`, or (`baseUrl: null`) return the role
|
|
495
|
+
* to automatic. Validated: the address must be a row (detected, custom, or
|
|
496
|
+
* the app link for notifications), never loopback, and `signIn` on plain
|
|
497
|
+
* http only when accepted. A refusal stores nothing.
|
|
234
498
|
*/
|
|
235
|
-
async
|
|
236
|
-
|
|
237
|
-
|
|
499
|
+
async setRole(role, baseUrl, enabled, acceptInsecureHttp) {
|
|
500
|
+
if (baseUrl === null || baseUrl.trim() === "" && role !== "viewer") {
|
|
501
|
+
await this.changeAddressBook((state) => withRoleAutomatic(state, role));
|
|
502
|
+
this.ctx.logger.info("local-network: address role set to automatic", { meta: { role } });
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
505
|
+
let target = baseUrl.trim();
|
|
506
|
+
if (enabled) {
|
|
507
|
+
const check = checkRoleAddress(role, target, { acceptInsecureHttp });
|
|
508
|
+
if (!check.ok) throw new Error(check.reason);
|
|
509
|
+
target = check.baseUrl;
|
|
510
|
+
}
|
|
511
|
+
await this.changeAddressBook((state, ctx) => {
|
|
512
|
+
const known = isAppLinkBase(target) || ctx.detectedUrls.has(target) || state.custom.some((c) => c.baseUrl === target);
|
|
513
|
+
if (enabled && !known && role !== "notifications") throw new Error(`${target} is not in the address list — add it as a custom address first.`);
|
|
514
|
+
return withRoleFlag(state, role, target, enabled, ctx.autoViewer);
|
|
515
|
+
});
|
|
516
|
+
this.ctx.logger.info("local-network: address role set", { meta: {
|
|
517
|
+
role,
|
|
518
|
+
baseUrl: target,
|
|
519
|
+
enabled
|
|
520
|
+
} });
|
|
238
521
|
}
|
|
239
522
|
async notificationEndpointSnapshot() {
|
|
240
|
-
const
|
|
523
|
+
const resolution = resolveNotificationsAddress(this.storedFlags());
|
|
524
|
+
const port = (await this.resolveAdvertisedListenPort(null)).port;
|
|
241
525
|
return {
|
|
242
|
-
baseUrl:
|
|
243
|
-
resolved:
|
|
244
|
-
appLinkHub: await this.
|
|
526
|
+
baseUrl: resolution.flagged,
|
|
527
|
+
resolved: resolution.resolved,
|
|
528
|
+
appLinkHub: pickAppLinkHub(await this.buildAdvertisedEndpoints(false, false, "https", port))
|
|
245
529
|
};
|
|
246
530
|
}
|
|
247
531
|
async snapshotViewerEndpoints() {
|
|
248
|
-
const
|
|
532
|
+
const resolution = resolveViewerAddresses(await this.buildAdvertisedEndpoints(false, false, "http", (await this.resolveAdvertisedListenPort(null)).port), this.storedFlags());
|
|
249
533
|
return {
|
|
250
|
-
baseUrls:
|
|
251
|
-
resolved:
|
|
534
|
+
baseUrls: resolution.flagged,
|
|
535
|
+
resolved: resolution.resolved
|
|
252
536
|
};
|
|
253
537
|
}
|
|
254
538
|
/**
|
|
255
|
-
* Palette shown
|
|
256
|
-
*
|
|
257
|
-
*
|
|
539
|
+
* Palette shown to clients: LAN IPv4, stable LAN IPv6, public, mesh, and
|
|
540
|
+
* the custom addresses flagged `viewer` (`kind: 'custom'`). The viewer
|
|
541
|
+
* HTTP/WS race is a subset (`selectViewerEndpoints`) — IPv6 stays in this
|
|
542
|
+
* list because ICE/WebRTC gathers it regardless.
|
|
258
543
|
*/
|
|
259
544
|
async buildAdvertisedEndpoints(includeLoopback, ipv4Only, scheme, httpsPort) {
|
|
260
|
-
const allow = this.config.allowedAddresses;
|
|
261
|
-
const interfaces = applyAllowlist(this.enumerate(), allow);
|
|
262
545
|
await this.reconcileMeshEndpoint();
|
|
546
|
+
const detected = this.endpointsNow(includeLoopback, ipv4Only, scheme, httpsPort);
|
|
547
|
+
return withViewerCustomEndpoints(detected, this.addressState(detected));
|
|
548
|
+
}
|
|
549
|
+
/** The DETECTED palette from the cached interface/tunnel/mesh state. */
|
|
550
|
+
endpointsNow(includeLoopback, ipv4Only, scheme, httpsPort) {
|
|
551
|
+
const interfaces = applyAllowlist(this.enumerate(), this.config.allowedAddresses);
|
|
263
552
|
const httpState = readLanHttpState();
|
|
264
553
|
return buildEndpoints(interfaces, httpsPort, includeLoopback, ipv4Only, this.publicHostname, scheme, this.meshEndpoint, {
|
|
265
554
|
enabled: this.config.httpEnabled !== false,
|
|
@@ -302,35 +591,50 @@ var LocalNetworkAddon = class extends BaseAddon {
|
|
|
302
591
|
},
|
|
303
592
|
getNotificationEndpoint: async () => this.notificationEndpointSnapshot(),
|
|
304
593
|
setNotificationEndpoint: async ({ baseUrl }) => {
|
|
305
|
-
await this.
|
|
306
|
-
this.ctx.logger.info("local-network: notification endpoint set", { meta: { baseUrl: baseUrl ?? "(auto)" } });
|
|
594
|
+
await this.setRole("notifications", baseUrl, true, false);
|
|
307
595
|
return this.notificationEndpointSnapshot();
|
|
308
596
|
},
|
|
309
|
-
getHubAddresses: async () => this.snapshotHubAddresses(),
|
|
310
|
-
setHubAddress: async ({ audience, baseUrl }) => {
|
|
311
|
-
let stored = "";
|
|
312
|
-
if (baseUrl !== null && baseUrl.trim() !== "") {
|
|
313
|
-
const check = validateHubAddressOverride(baseUrl);
|
|
314
|
-
if (!check.ok) throw new Error(check.reason);
|
|
315
|
-
stored = check.baseUrl;
|
|
316
|
-
}
|
|
317
|
-
await this.updateGlobalSettings(audience === "cluster" ? { agentBaseUrl: stored } : { signInBaseUrl: stored });
|
|
318
|
-
this.ctx.logger.info("local-network: hub address override set", { meta: {
|
|
319
|
-
audience,
|
|
320
|
-
baseUrl: stored === "" ? "(auto)" : stored
|
|
321
|
-
} });
|
|
322
|
-
return this.snapshotHubAddresses();
|
|
323
|
-
},
|
|
324
597
|
getViewerEndpoints: async () => this.snapshotViewerEndpoints(),
|
|
325
598
|
setViewerEndpoints: async ({ baseUrls }) => {
|
|
326
|
-
const
|
|
327
|
-
await this.
|
|
599
|
+
const viewer = [...new Set(baseUrls.filter((u) => u.length > 0))];
|
|
600
|
+
await this.changeAddressBook((state) => ({
|
|
601
|
+
...state,
|
|
602
|
+
flags: {
|
|
603
|
+
...state.flags,
|
|
604
|
+
viewer
|
|
605
|
+
}
|
|
606
|
+
}));
|
|
328
607
|
this.ctx.logger.info("local-network: viewer endpoints set", { meta: {
|
|
329
|
-
count:
|
|
330
|
-
auto:
|
|
608
|
+
count: viewer.length,
|
|
609
|
+
auto: viewer.length === 0
|
|
331
610
|
} });
|
|
332
611
|
return this.snapshotViewerEndpoints();
|
|
333
612
|
},
|
|
613
|
+
getAddresses: async (input) => this.addressBook(input?.scheme ?? "https"),
|
|
614
|
+
addCustomAddress: async ({ baseUrl, label }) => {
|
|
615
|
+
const check = validateCustomAddress(baseUrl);
|
|
616
|
+
if (!check.ok) throw new Error(check.reason);
|
|
617
|
+
const entry = {
|
|
618
|
+
baseUrl: check.baseUrl,
|
|
619
|
+
label: label.trim()
|
|
620
|
+
};
|
|
621
|
+
await this.changeAddressBook((state) => withCustomAddress(state, entry));
|
|
622
|
+
this.ctx.logger.info("local-network: custom address added", { meta: {
|
|
623
|
+
baseUrl: entry.baseUrl,
|
|
624
|
+
label: entry.label
|
|
625
|
+
} });
|
|
626
|
+
return this.addressBook("https");
|
|
627
|
+
},
|
|
628
|
+
removeCustomAddress: async ({ baseUrl }) => {
|
|
629
|
+
await this.changeAddressBook((state) => withoutCustomAddress(state, baseUrl));
|
|
630
|
+
this.ctx.logger.info("local-network: custom address removed", { meta: { baseUrl } });
|
|
631
|
+
return this.addressBook("https");
|
|
632
|
+
},
|
|
633
|
+
setAddressRole: async ({ role, baseUrl, enabled, acceptInsecureHttp }) => {
|
|
634
|
+
await this.setRole(role, baseUrl, enabled, acceptInsecureHttp === true);
|
|
635
|
+
return this.addressBook("https");
|
|
636
|
+
},
|
|
637
|
+
getHubAddresses: async () => this.snapshotHubAddresses(),
|
|
334
638
|
getAllowedAddresses: async () => ({ addresses: this.config.allowedAddresses }),
|
|
335
639
|
resetAllowlistToBestMatch: async () => {
|
|
336
640
|
const seed = autoSeedAllowlist(this.enumerate());
|
|
@@ -872,25 +1176,6 @@ function buildEndpoints(interfaces, port, includeLoopback, ipv4Only, publicHostn
|
|
|
872
1176
|
});
|
|
873
1177
|
return out.toSorted((a, b) => a.priority - b.priority);
|
|
874
1178
|
}
|
|
875
|
-
/** AUTO viewer race: LAN IPv4 + the public tunnel. Never IPv6, mesh, or loopback. */
|
|
876
|
-
function isDefaultViewerEndpoint(endpoint) {
|
|
877
|
-
if (endpoint.kind === "lan-ipv4") return true;
|
|
878
|
-
return endpoint.kind === "public" && endpoint.interfaceKind === "public";
|
|
879
|
-
}
|
|
880
|
-
/**
|
|
881
|
-
* The URLs the SDK should race for API / viewer access.
|
|
882
|
-
*
|
|
883
|
-
* Empty `viewerBaseUrls` = AUTO (IPv4 + public tunnel). A non-empty list is
|
|
884
|
-
* the operator's pin; if none of those URLs are in the current palette,
|
|
885
|
-
* fall back to AUTO rather than racing an empty set.
|
|
886
|
-
*/
|
|
887
|
-
function selectViewerEndpoints(endpoints, viewerBaseUrls) {
|
|
888
|
-
const auto = endpoints.filter(isDefaultViewerEndpoint);
|
|
889
|
-
if (viewerBaseUrls.length === 0) return auto;
|
|
890
|
-
const wanted = new Set(viewerBaseUrls);
|
|
891
|
-
const explicit = endpoints.filter((e) => wanted.has(e.baseUrl));
|
|
892
|
-
return explicit.length > 0 ? explicit : auto;
|
|
893
|
-
}
|
|
894
1179
|
/**
|
|
895
1180
|
* First-boot heuristic: which addresses should the allowlist start
|
|
896
1181
|
* with? Includes LAN + Wi-Fi IPv4 addresses + plausible IPv6:
|
|
@@ -1019,4 +1304,4 @@ function readLinuxIpv6Flags() {
|
|
|
1019
1304
|
}
|
|
1020
1305
|
}
|
|
1021
1306
|
//#endregion
|
|
1022
|
-
export { ALLOWLIST_RECONCILE_INTERVAL_MS, LocalNetworkAddon, appLinkEndpoint, applyAllowlist, autoSeedAllowlist, buildEndpoints, classifyKind, enumerateOsInterfaces, explainNonPlausible, ipv6Prefix64Key,
|
|
1307
|
+
export { ALLOWLIST_RECONCILE_INTERVAL_MS, LocalNetworkAddon, appLinkEndpoint, applyAllowlist, autoSeedAllowlist, buildEndpoints, classifyKind, enumerateOsInterfaces, explainNonPlausible, ipv6Prefix64Key, isPlausibleAutoSeed, parseProcIfInet6, pickPreferred, prefixLen, reconcileAllowlist, resolveAdvertisedPort, shouldAdvertiseIpv6 };
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-W_X44h-s.js");
|
|
7
7
|
//#region src/builtins/loki-logging/loki-payload.ts
|
|
8
8
|
/**
|
|
9
9
|
* Loki rejects a label name that is not a valid Prometheus label
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Jt as logDestinationCapability, ar as BaseAddon } from "../../dist-pTfD_M-U.mjs";
|
|
2
2
|
//#region src/builtins/loki-logging/loki-payload.ts
|
|
3
3
|
/**
|
|
4
4
|
* Loki rejects a label name that is not a valid Prometheus label
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-W_X44h-s.js");
|
|
7
7
|
const require_proc_stat = require("../../proc-stat-DL-WUOhl.js");
|
|
8
8
|
let node_fs_promises = require("node:fs/promises");
|
|
9
9
|
let node_os = require("node:os");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Ar as EventCategory, Mt as foldSnapshotByFunction, ar as BaseAddon, en as metricsProviderCapability, hn as resolveBucketMs, hr as createEvent, ir as errMsg, pn as reducePoints } from "../../dist-pTfD_M-U.mjs";
|
|
2
2
|
import { a as parseProcStat, i as nodeProcReader, n as elapsedSecSince, o as parseProcStatusRss, r as lifetimeCpuPercent, t as commandFromCmdline } from "../../proc-stat-CbC55Kqi.mjs";
|
|
3
3
|
import { access, readFile, readdir } from "node:fs/promises";
|
|
4
4
|
import * as os from "node:os";
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-W_X44h-s.js");
|
|
7
7
|
let node_os = require("node:os");
|
|
8
8
|
node_os = require_chunk.__toESM(node_os);
|
|
9
9
|
let node_fs = require("node:fs");
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { o as __toESM } from "../../chunk-CNf5ZN-e.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { Ar as EventCategory, Ct as enumerateInferenceDevices, En as scoreRuntimes, _r as emitReadiness, ar as BaseAddon, ir as errMsg, un as platformProbeCapability } from "../../dist-pTfD_M-U.mjs";
|
|
3
3
|
import * as os from "node:os";
|
|
4
4
|
import * as fs from "node:fs";
|
|
5
5
|
import { execFile } from "node:child_process";
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-W_X44h-s.js");
|
|
7
7
|
//#region src/builtins/remote-access-orchestrator/enabled-providers-reconcile.ts
|
|
8
8
|
/**
|
|
9
9
|
* Reconcile the durable `enabledProviders` set against authoritative
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Ar as EventCategory, ar as BaseAddon } from "../../dist-pTfD_M-U.mjs";
|
|
2
2
|
//#region src/builtins/remote-access-orchestrator/enabled-providers-reconcile.ts
|
|
3
3
|
/**
|
|
4
4
|
* Reconcile the durable `enabledProviders` set against authoritative
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-W_X44h-s.js");
|
|
7
7
|
const require_snapshot_courtesy = require("../../snapshot-courtesy-D_C5-nC0.js");
|
|
8
8
|
let zod = require("zod");
|
|
9
9
|
let node_crypto = require("node:crypto");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $
|
|
1
|
+
import { $t as memoizePinnedFfmpeg, Ar as EventCategory, Fn as streamQualityLabel, Sr as nodePin, X as batteryCapability, Y as bareAddonId, _t as deriveBatteryPresence, a as BatteryStatusSchema, ar as BaseAddon, ir as errMsg, kn as snapshotCapability, rr as DeviceType, tr as DeviceFeature } from "../../dist-pTfD_M-U.mjs";
|
|
2
2
|
import { i as renderCourtesyOverlayJpeg, n as courtesyCacheKey, r as renderCourtesyJpeg } from "../../snapshot-courtesy-CyFs1M3I.mjs";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { randomUUID } from "node:crypto";
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-W_X44h-s.js");
|
|
7
7
|
let node_crypto = require("node:crypto");
|
|
8
8
|
let node_fs_promises = require("node:fs/promises");
|
|
9
9
|
let node_path = require("node:path");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Nn as storageProviderCapability, ar as BaseAddon, jt as filesystemBrowseCapability } from "../../dist-pTfD_M-U.mjs";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import { mkdir, readdir, realpath, statfs } from "node:fs/promises";
|
|
4
4
|
import * as path$1 from "node:path";
|
|
Binary file
|
|
Binary file
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-W_X44h-s.js");
|
|
7
7
|
const require_hub_cap_forward = require("../../hub-cap-forward-DmHNjbB0.js");
|
|
8
8
|
let zod = require("zod");
|
|
9
9
|
let node_crypto = require("node:crypto");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { An as storageCapability, Ar as EventCategory, B as StorageLocationTypeSchema, Cr as parseJsonObject, Dn as settingsStoreCapability, Dt as evictionPolicyOfLocation, E as LegacyStorageLocationDefaultSchema, Hn as withLocationMode, M as REDACTED_SECRET, Pt as gbToBytes, Qt as mayWriteToLocation, R as StorageCleanupJobSchema, V as StorageMigrationJobSchema, Wt as legacyModeOf, Zt as mayReadLocation, ar as BaseAddon, jn as storageMigrationCapability, nt as collectSecretConfigKeys, tn as modeMayWrite, yn as resolveLocationMode, z as StorageLocationModeSchema, zt as isLocationEnabled } from "../../dist-pTfD_M-U.mjs";
|
|
2
2
|
import { t as HUB_CAP_FWD_ACTION } from "../../hub-cap-forward-BdT320dq.mjs";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { randomUUID } from "node:crypto";
|
|
@@ -3,7 +3,7 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-W_X44h-s.js");
|
|
7
7
|
//#region src/builtins/system-config/system-config.addon.ts
|
|
8
8
|
/**
|
|
9
9
|
* Built-in `system-config` addon — Phase 4 of the settings redesign.
|