@camstack/system 1.2.357 → 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/auth/user-manager.d.ts +43 -2
- 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 +2 -2
- package/dist/builtins/autotrack/index.mjs +2 -2
- 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 +8 -8
- package/dist/builtins/composer/composer.addon.mjs +8 -8
- 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 +9 -9
- package/dist/builtins/device-manager/device-manager.addon.mjs +9 -9
- 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/admin-account-boot.d.ts +27 -0
- package/dist/builtins/local-auth/auth-schema.d.ts +3 -2
- package/dist/builtins/local-auth/local-auth.addon.js +281 -8
- package/dist/builtins/local-auth/local-auth.addon.mjs +291 -22
- package/dist/builtins/local-network/address-book.d.ts +69 -0
- package/dist/builtins/local-network/local-network.addon.d.ts +44 -32
- package/dist/builtins/local-network/local-network.addon.js +368 -55
- package/dist/builtins/local-network/local-network.addon.mjs +369 -54
- 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-BcRHQBKW.mjs → child-cap-dispatch-Dm1TRDCr.mjs} +2 -2
- package/dist/{child-cap-dispatch-wbIQJctP.js → child-cap-dispatch-t61ohDpb.js} +2 -2
- package/dist/{composition-sources-CeO0K2cl.js → composition-sources-CCU_KizO.js} +1 -1
- package/dist/{composition-sources-BBfqepyT.mjs → composition-sources-CHlfWHl6.mjs} +1 -1
- package/dist/{dist-CFVOy8VT.js → dist-W_X44h-s.js} +669 -121
- package/dist/{dist-B7WRgEZY.mjs → dist-pTfD_M-U.mjs} +628 -122
- package/dist/index.js +6 -141
- package/dist/index.mjs +4 -139
- package/dist/kernel/config-manager.d.ts +1 -1
- package/dist/kernel/config-schema.d.ts +6 -1
- package/dist/{retired-settings-keys-DKRjfz0U.mjs → retired-settings-keys-CK_ifret.mjs} +1 -1
- package/dist/{retired-settings-keys-CRlTzxaS.js → retired-settings-keys-jglEzgWR.js} +1 -1
- package/package.json +3 -3
|
@@ -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,55 +420,135 @@ 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
|
-
localHostname: ""
|
|
426
|
+
localHostname: "",
|
|
427
|
+
agentBaseUrl: "",
|
|
428
|
+
signInBaseUrl: ""
|
|
202
429
|
});
|
|
203
430
|
}
|
|
204
431
|
/**
|
|
205
|
-
* The
|
|
206
|
-
*
|
|
207
|
-
*
|
|
208
|
-
* not a hub address: the NC's signed media and buttons keep their own hub
|
|
209
|
-
* ladder when it is flagged; only viewer taps take the app form.
|
|
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
|
-
|
|
212
|
-
const
|
|
213
|
-
|
|
436
|
+
async palettes() {
|
|
437
|
+
const port = (await this.resolveAdvertisedListenPort(null)).port;
|
|
438
|
+
await this.reconcileMeshEndpoint();
|
|
439
|
+
return {
|
|
440
|
+
http: this.endpointsNow(false, false, "http", port),
|
|
441
|
+
https: this.endpointsNow(false, false, "https", port)
|
|
442
|
+
};
|
|
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
|
+
});
|
|
214
461
|
}
|
|
215
462
|
/**
|
|
216
|
-
*
|
|
217
|
-
*
|
|
218
|
-
* what the Network page lists. See `pickAppLinkHub`.
|
|
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).
|
|
219
465
|
*/
|
|
220
|
-
async
|
|
221
|
-
const
|
|
222
|
-
|
|
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
|
+
};
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
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.
|
|
498
|
+
*/
|
|
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
|
+
} });
|
|
223
521
|
}
|
|
224
522
|
async notificationEndpointSnapshot() {
|
|
225
|
-
const
|
|
523
|
+
const resolution = resolveNotificationsAddress(this.storedFlags());
|
|
524
|
+
const port = (await this.resolveAdvertisedListenPort(null)).port;
|
|
226
525
|
return {
|
|
227
|
-
baseUrl:
|
|
228
|
-
resolved:
|
|
229
|
-
appLinkHub: await this.
|
|
526
|
+
baseUrl: resolution.flagged,
|
|
527
|
+
resolved: resolution.resolved,
|
|
528
|
+
appLinkHub: pickAppLinkHub(await this.buildAdvertisedEndpoints(false, false, "https", port))
|
|
230
529
|
};
|
|
231
530
|
}
|
|
232
531
|
async snapshotViewerEndpoints() {
|
|
233
|
-
const
|
|
532
|
+
const resolution = resolveViewerAddresses(await this.buildAdvertisedEndpoints(false, false, "http", (await this.resolveAdvertisedListenPort(null)).port), this.storedFlags());
|
|
234
533
|
return {
|
|
235
|
-
baseUrls:
|
|
236
|
-
resolved:
|
|
534
|
+
baseUrls: resolution.flagged,
|
|
535
|
+
resolved: resolution.resolved
|
|
237
536
|
};
|
|
238
537
|
}
|
|
239
538
|
/**
|
|
240
|
-
* Palette shown
|
|
241
|
-
*
|
|
242
|
-
*
|
|
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.
|
|
243
543
|
*/
|
|
244
544
|
async buildAdvertisedEndpoints(includeLoopback, ipv4Only, scheme, httpsPort) {
|
|
245
|
-
const allow = this.config.allowedAddresses;
|
|
246
|
-
const interfaces = applyAllowlist(this.enumerate(), allow);
|
|
247
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);
|
|
248
552
|
const httpState = readLanHttpState();
|
|
249
553
|
return buildEndpoints(interfaces, httpsPort, includeLoopback, ipv4Only, this.publicHostname, scheme, this.meshEndpoint, {
|
|
250
554
|
enabled: this.config.httpEnabled !== false,
|
|
@@ -287,20 +591,50 @@ var LocalNetworkAddon = class extends BaseAddon {
|
|
|
287
591
|
},
|
|
288
592
|
getNotificationEndpoint: async () => this.notificationEndpointSnapshot(),
|
|
289
593
|
setNotificationEndpoint: async ({ baseUrl }) => {
|
|
290
|
-
await this.
|
|
291
|
-
this.ctx.logger.info("local-network: notification endpoint set", { meta: { baseUrl: baseUrl ?? "(auto)" } });
|
|
594
|
+
await this.setRole("notifications", baseUrl, true, false);
|
|
292
595
|
return this.notificationEndpointSnapshot();
|
|
293
596
|
},
|
|
294
597
|
getViewerEndpoints: async () => this.snapshotViewerEndpoints(),
|
|
295
598
|
setViewerEndpoints: async ({ baseUrls }) => {
|
|
296
|
-
const
|
|
297
|
-
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
|
+
}));
|
|
298
607
|
this.ctx.logger.info("local-network: viewer endpoints set", { meta: {
|
|
299
|
-
count:
|
|
300
|
-
auto:
|
|
608
|
+
count: viewer.length,
|
|
609
|
+
auto: viewer.length === 0
|
|
301
610
|
} });
|
|
302
611
|
return this.snapshotViewerEndpoints();
|
|
303
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(),
|
|
304
638
|
getAllowedAddresses: async () => ({ addresses: this.config.allowedAddresses }),
|
|
305
639
|
resetAllowlistToBestMatch: async () => {
|
|
306
640
|
const seed = autoSeedAllowlist(this.enumerate());
|
|
@@ -842,25 +1176,6 @@ function buildEndpoints(interfaces, port, includeLoopback, ipv4Only, publicHostn
|
|
|
842
1176
|
});
|
|
843
1177
|
return out.toSorted((a, b) => a.priority - b.priority);
|
|
844
1178
|
}
|
|
845
|
-
/** AUTO viewer race: LAN IPv4 + the public tunnel. Never IPv6, mesh, or loopback. */
|
|
846
|
-
function isDefaultViewerEndpoint(endpoint) {
|
|
847
|
-
if (endpoint.kind === "lan-ipv4") return true;
|
|
848
|
-
return endpoint.kind === "public" && endpoint.interfaceKind === "public";
|
|
849
|
-
}
|
|
850
|
-
/**
|
|
851
|
-
* The URLs the SDK should race for API / viewer access.
|
|
852
|
-
*
|
|
853
|
-
* Empty `viewerBaseUrls` = AUTO (IPv4 + public tunnel). A non-empty list is
|
|
854
|
-
* the operator's pin; if none of those URLs are in the current palette,
|
|
855
|
-
* fall back to AUTO rather than racing an empty set.
|
|
856
|
-
*/
|
|
857
|
-
function selectViewerEndpoints(endpoints, viewerBaseUrls) {
|
|
858
|
-
const auto = endpoints.filter(isDefaultViewerEndpoint);
|
|
859
|
-
if (viewerBaseUrls.length === 0) return auto;
|
|
860
|
-
const wanted = new Set(viewerBaseUrls);
|
|
861
|
-
const explicit = endpoints.filter((e) => wanted.has(e.baseUrl));
|
|
862
|
-
return explicit.length > 0 ? explicit : auto;
|
|
863
|
-
}
|
|
864
1179
|
/**
|
|
865
1180
|
* First-boot heuristic: which addresses should the allowlist start
|
|
866
1181
|
* with? Includes LAN + Wi-Fi IPv4 addresses + plausible IPv6:
|
|
@@ -989,4 +1304,4 @@ function readLinuxIpv6Flags() {
|
|
|
989
1304
|
}
|
|
990
1305
|
}
|
|
991
1306
|
//#endregion
|
|
992
|
-
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.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ar as BaseAddon, ir as errMsg, yr as hydrateSchema } from "../../dist-pTfD_M-U.mjs";
|
|
2
2
|
//#region src/builtins/system-config/system-config.addon.ts
|
|
3
3
|
/**
|
|
4
4
|
* Built-in `system-config` addon — Phase 4 of the settings redesign.
|
|
@@ -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_formatter = require("../../formatter-DqAKDlvN.js");
|
|
8
8
|
let node_path = require("node:path");
|
|
9
9
|
node_path = require_chunk.__toESM(node_path);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Jt as logDestinationCapability, ar as BaseAddon } from "../../dist-pTfD_M-U.mjs";
|
|
2
2
|
import { t as formatLogLine } from "../../formatter-B7qW8bPJ.mjs";
|
|
3
3
|
import * as path$1 from "node:path";
|
|
4
4
|
import path from "node:path";
|