camstack 1.2.83 → 1.2.84
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.
|
@@ -23633,9 +23633,9 @@ var require_zod = __commonJS({
|
|
|
23633
23633
|
}
|
|
23634
23634
|
});
|
|
23635
23635
|
|
|
23636
|
-
// ../system/dist/dist-
|
|
23637
|
-
var
|
|
23638
|
-
"../system/dist/dist-
|
|
23636
|
+
// ../system/dist/dist-TEwQZL3g.js
|
|
23637
|
+
var require_dist_TEwQZL3g = __commonJS({
|
|
23638
|
+
"../system/dist/dist-TEwQZL3g.js"(exports) {
|
|
23639
23639
|
"use strict";
|
|
23640
23640
|
var zod = require_zod();
|
|
23641
23641
|
var EventCategory = /* @__PURE__ */ (function(EventCategory2) {
|
|
@@ -28488,6 +28488,68 @@ var require_dist_C7qWwrK1 = __commonJS({
|
|
|
28488
28488
|
fileCount: zod.z.number(),
|
|
28489
28489
|
present: zod.z.boolean()
|
|
28490
28490
|
});
|
|
28491
|
+
var BackupRunStateSchema = zod.z.enum([
|
|
28492
|
+
"queued",
|
|
28493
|
+
"running",
|
|
28494
|
+
"succeeded",
|
|
28495
|
+
"failed",
|
|
28496
|
+
"cancelled"
|
|
28497
|
+
]);
|
|
28498
|
+
var BackupRunPhaseSchema = zod.z.enum([
|
|
28499
|
+
"queued",
|
|
28500
|
+
"building",
|
|
28501
|
+
"uploading",
|
|
28502
|
+
"done"
|
|
28503
|
+
]);
|
|
28504
|
+
var BackupRunSchema = zod.z.object({
|
|
28505
|
+
/** Stable run id — the handle `backup.cancel` takes. */
|
|
28506
|
+
id: zod.z.string(),
|
|
28507
|
+
state: BackupRunStateSchema,
|
|
28508
|
+
phase: BackupRunPhaseSchema,
|
|
28509
|
+
/**
|
|
28510
|
+
* Resolved destination location ids. Empty while queued (targets are
|
|
28511
|
+
* resolved when the run starts, against the then-current policies).
|
|
28512
|
+
*/
|
|
28513
|
+
destinationIds: zod.z.array(zod.z.string()).readonly(),
|
|
28514
|
+
label: zod.z.string().optional(),
|
|
28515
|
+
/** ms-epoch when the run was submitted (trigger call / schedule fire). */
|
|
28516
|
+
requestedAt: zod.z.number(),
|
|
28517
|
+
/** ms-epoch when the run left the queue and started building. */
|
|
28518
|
+
startedAt: zod.z.number().optional(),
|
|
28519
|
+
/** ms-epoch when the run reached a terminal state. */
|
|
28520
|
+
finishedAt: zod.z.number().optional(),
|
|
28521
|
+
/** Compressed bytes of the staging archive written so far. */
|
|
28522
|
+
stagedBytes: zod.z.number(),
|
|
28523
|
+
/** Final staged archive size, once the build phase completes. */
|
|
28524
|
+
archiveSizeBytes: zod.z.number().optional(),
|
|
28525
|
+
/** Bytes pushed to the destination currently uploading. */
|
|
28526
|
+
uploadedBytes: zod.z.number(),
|
|
28527
|
+
/** Destinations where the archive fully landed (uploaded + indexed). */
|
|
28528
|
+
completedDestinationIds: zod.z.array(zod.z.string()).readonly(),
|
|
28529
|
+
/** Destinations that failed during the fan-out. */
|
|
28530
|
+
failedDestinationIds: zod.z.array(zod.z.string()).readonly(),
|
|
28531
|
+
/** Failure message when `state === 'failed'`. */
|
|
28532
|
+
error: zod.z.string().optional(),
|
|
28533
|
+
/**
|
|
28534
|
+
* 1-based place in the execution queue — 1 = runs next. Present only
|
|
28535
|
+
* while `state === 'queued'`. Stamped by the orchestrator from the
|
|
28536
|
+
* queue's OWN pending order, never derived from timestamps, so the
|
|
28537
|
+
* UI cannot show an order the executor will not honour.
|
|
28538
|
+
*/
|
|
28539
|
+
queuePosition: zod.z.number().int().min(1).optional()
|
|
28540
|
+
});
|
|
28541
|
+
var BackupTriggerResultSchema = zod.z.object({
|
|
28542
|
+
/** The run this trigger mapped to — poll it via `listRuns`, stop it via `cancel`. */
|
|
28543
|
+
runId: zod.z.string(),
|
|
28544
|
+
/** True when the run waited behind an in-flight run instead of starting immediately. */
|
|
28545
|
+
queued: zod.z.boolean(),
|
|
28546
|
+
/** True when this trigger was coalesced onto an identical already-queued run. */
|
|
28547
|
+
joined: zod.z.boolean(),
|
|
28548
|
+
/** True when the run was cancelled before completing every destination. */
|
|
28549
|
+
cancelled: zod.z.boolean(),
|
|
28550
|
+
/** One entry per destination the archive landed at (partial on cancel). */
|
|
28551
|
+
entries: zod.z.array(BackupEntrySchema).readonly()
|
|
28552
|
+
});
|
|
28491
28553
|
var BackupScheduleSchema = zod.z.object({
|
|
28492
28554
|
/** Stable id. Generated by the orchestrator on first upsert if absent. */
|
|
28493
28555
|
id: zod.z.string(),
|
|
@@ -28524,6 +28586,11 @@ var require_dist_C7qWwrK1 = __commonJS({
|
|
|
28524
28586
|
* Trigger a backup. Without `destinations` the orchestrator fans
|
|
28525
28587
|
* out to every destination flagged as enabled in the routing
|
|
28526
28588
|
* config; with it, only the listed addons receive the archive.
|
|
28589
|
+
*
|
|
28590
|
+
* At most ONE backup run executes at a time — the source tree and
|
|
28591
|
+
* the staging disk are shared by every run, so a second trigger
|
|
28592
|
+
* while one is in flight is enqueued (or joined onto an identical
|
|
28593
|
+
* queued run) and the result says so. See D342.
|
|
28527
28594
|
*/
|
|
28528
28595
|
trigger: method(zod.z.object({
|
|
28529
28596
|
/** Subset of registered `backup-destination` addon ids to write to. */
|
|
@@ -28537,7 +28604,30 @@ var require_dist_C7qWwrK1 = __commonJS({
|
|
|
28537
28604
|
* retention (manual runs).
|
|
28538
28605
|
*/
|
|
28539
28606
|
retentionCount: zod.z.number().int().min(1).max(1e3).optional()
|
|
28540
|
-
}).optional(),
|
|
28607
|
+
}).optional(), BackupTriggerResultSchema, {
|
|
28608
|
+
kind: "mutation",
|
|
28609
|
+
auth: "admin"
|
|
28610
|
+
}),
|
|
28611
|
+
/**
|
|
28612
|
+
* Every run the orchestrator knows about, in EXECUTION order: the
|
|
28613
|
+
* running run first, then queued runs in the exact order they will
|
|
28614
|
+
* execute (each with `queuePosition`, 1 = next), then the bounded
|
|
28615
|
+
* finished history newest-first. Only one run executes at a time
|
|
28616
|
+
* (D342) — the queued section IS the line. Each run carries live
|
|
28617
|
+
* phase + byte counters so a runaway build is visible in seconds,
|
|
28618
|
+
* not via `du`.
|
|
28619
|
+
*/
|
|
28620
|
+
listRuns: method(zod.z.void(), zod.z.array(BackupRunSchema).readonly(), { auth: "admin" }),
|
|
28621
|
+
/**
|
|
28622
|
+
* Stop a backup run. Mirrors `storage-migration.cancel` semantics:
|
|
28623
|
+
* id in, `{ cancelled }` out — `false` when the run is unknown or
|
|
28624
|
+
* already terminal. A QUEUED run is removed before it ever starts;
|
|
28625
|
+
* the RUNNING run has its tar/upload stream actually aborted, the
|
|
28626
|
+
* half-written staging archive is deleted, and the in-flight
|
|
28627
|
+
* destination upload is aborted server-side (partial discarded).
|
|
28628
|
+
* Destinations that already completed keep their archive.
|
|
28629
|
+
*/
|
|
28630
|
+
cancel: method(zod.z.object({ runId: zod.z.string() }), zod.z.object({ cancelled: zod.z.boolean() }), {
|
|
28541
28631
|
kind: "mutation",
|
|
28542
28632
|
auth: "admin"
|
|
28543
28633
|
}),
|
|
@@ -29277,6 +29367,38 @@ var require_dist_C7qWwrK1 = __commonJS({
|
|
|
29277
29367
|
auth: "admin"
|
|
29278
29368
|
}),
|
|
29279
29369
|
/**
|
|
29370
|
+
* The HARDWARE behind a device number was replaced
|
|
29371
|
+
* (`deviceManager.migrateDevice`). Forget every piece of broker state that
|
|
29372
|
+
* described the old box, so the next catalog pull derives everything from
|
|
29373
|
+
* the camera that is actually there:
|
|
29374
|
+
*
|
|
29375
|
+
* - every `derived:*` stream definition — a derived is authored against a
|
|
29376
|
+
* specific profile layout, and against the wrong hardware its feeder
|
|
29377
|
+
* respawns forever (observed at attempt 2732 on the live hub,
|
|
29378
|
+
* 2026-09-01);
|
|
29379
|
+
* - the profile-slot assignment entry, PURGED (not unassigned — unassign
|
|
29380
|
+
* marks the slot manual, which would pin the stale choice instead of
|
|
29381
|
+
* letting `computeInitialAssignment` re-derive it);
|
|
29382
|
+
* - the probe snapshots (`<deviceId>/…` — probed codec/resolution of the
|
|
29383
|
+
* old hardware);
|
|
29384
|
+
* - the persisted RTSP token rows for the device's brokers (keyed
|
|
29385
|
+
* `<deviceId>/<camStreamId>`; the stream ids change with the hardware,
|
|
29386
|
+
* so the rows are dead URLs).
|
|
29387
|
+
*
|
|
29388
|
+
* An RPC, deliberately — an event is telemetry and may be dropped (D8),
|
|
29389
|
+
* and a dropped forget leaves a feeder respawning against a stream that
|
|
29390
|
+
* does not exist.
|
|
29391
|
+
*/
|
|
29392
|
+
forgetDeviceHardware: method(zod.z.object({ deviceId: zod.z.number().int().nonnegative() }), zod.z.object({
|
|
29393
|
+
derivedStreamsDeleted: zod.z.array(zod.z.string()).readonly(),
|
|
29394
|
+
assignmentsPurged: zod.z.boolean(),
|
|
29395
|
+
probeSnapshotsDropped: zod.z.number().int().nonnegative(),
|
|
29396
|
+
rtspTokenRowsDeleted: zod.z.number().int().nonnegative()
|
|
29397
|
+
}), {
|
|
29398
|
+
kind: "mutation",
|
|
29399
|
+
auth: "admin"
|
|
29400
|
+
}),
|
|
29401
|
+
/**
|
|
29280
29402
|
* Render a short GIF or MP4 from the broker's PRE-BUFFER around an instant.
|
|
29281
29403
|
*
|
|
29282
29404
|
* The pre-buffer is the only source that already holds the seconds BEFORE
|
|
@@ -51132,6 +51254,12 @@ var require_dist_C7qWwrK1 = __commonJS({
|
|
|
51132
51254
|
addonId: null,
|
|
51133
51255
|
access: "create"
|
|
51134
51256
|
},
|
|
51257
|
+
"backup.cancel": {
|
|
51258
|
+
capName: "backup",
|
|
51259
|
+
capScope: "system",
|
|
51260
|
+
addonId: null,
|
|
51261
|
+
access: "create"
|
|
51262
|
+
},
|
|
51135
51263
|
"backup.delete": {
|
|
51136
51264
|
capName: "backup",
|
|
51137
51265
|
capScope: "system",
|
|
@@ -51174,6 +51302,12 @@ var require_dist_C7qWwrK1 = __commonJS({
|
|
|
51174
51302
|
addonId: null,
|
|
51175
51303
|
access: "view"
|
|
51176
51304
|
},
|
|
51305
|
+
"backup.listRuns": {
|
|
51306
|
+
capName: "backup",
|
|
51307
|
+
capScope: "system",
|
|
51308
|
+
addonId: null,
|
|
51309
|
+
access: "view"
|
|
51310
|
+
},
|
|
51177
51311
|
"backup.listSchedules": {
|
|
51178
51312
|
capName: "backup",
|
|
51179
51313
|
capScope: "system",
|
|
@@ -55740,6 +55874,12 @@ var require_dist_C7qWwrK1 = __commonJS({
|
|
|
55740
55874
|
addonId: null,
|
|
55741
55875
|
access: "create"
|
|
55742
55876
|
},
|
|
55877
|
+
"streamBroker.forgetDeviceHardware": {
|
|
55878
|
+
capName: "stream-broker",
|
|
55879
|
+
capScope: "system",
|
|
55880
|
+
addonId: null,
|
|
55881
|
+
access: "delete"
|
|
55882
|
+
},
|
|
55743
55883
|
"streamBroker.getAllRtspEntries": {
|
|
55744
55884
|
capName: "stream-broker",
|
|
55745
55885
|
capScope: "system",
|
|
@@ -58198,6 +58338,11 @@ var require_dist_C7qWwrK1 = __commonJS({
|
|
|
58198
58338
|
form: "single",
|
|
58199
58339
|
optional: false
|
|
58200
58340
|
}],
|
|
58341
|
+
"streamBroker.forgetDeviceHardware": [{
|
|
58342
|
+
name: "deviceId",
|
|
58343
|
+
form: "single",
|
|
58344
|
+
optional: false
|
|
58345
|
+
}],
|
|
58201
58346
|
"streamBroker.getDeviceAudioMute": [{
|
|
58202
58347
|
name: "deviceId",
|
|
58203
58348
|
form: "single",
|
|
@@ -59854,7 +59999,7 @@ var require_alerts_addon = __commonJS({
|
|
|
59854
59999
|
[Symbol.toStringTag]: { value: "Module" }
|
|
59855
60000
|
});
|
|
59856
60001
|
require_chunk_Cek0wNdY();
|
|
59857
|
-
var require_dist10 =
|
|
60002
|
+
var require_dist10 = require_dist_TEwQZL3g();
|
|
59858
60003
|
function selectExpired(alerts, cutoffMs) {
|
|
59859
60004
|
return alerts.filter((a) => a.createdAt < cutoffMs).sort((a, b) => a.createdAt - b.createdAt).map((a) => a.id);
|
|
59860
60005
|
}
|
|
@@ -60673,7 +60818,7 @@ var require_console_logging = __commonJS({
|
|
|
60673
60818
|
[Symbol.toStringTag]: { value: "Module" }
|
|
60674
60819
|
});
|
|
60675
60820
|
require_chunk_Cek0wNdY();
|
|
60676
|
-
var require_dist10 =
|
|
60821
|
+
var require_dist10 = require_dist_TEwQZL3g();
|
|
60677
60822
|
var require_formatter = require_formatter_DqAKDlvN();
|
|
60678
60823
|
var LEVEL_RANK = {
|
|
60679
60824
|
debug: 0,
|
|
@@ -60767,7 +60912,7 @@ var require_core_blocks_addon = __commonJS({
|
|
|
60767
60912
|
"use strict";
|
|
60768
60913
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
60769
60914
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
60770
|
-
var require_dist10 =
|
|
60915
|
+
var require_dist10 = require_dist_TEwQZL3g();
|
|
60771
60916
|
var node_crypto = __require("crypto");
|
|
60772
60917
|
var node_fs_promises = __require("fs/promises");
|
|
60773
60918
|
node_fs_promises = require_chunk.__toESM(node_fs_promises);
|
|
@@ -61664,11 +61809,11 @@ var require_core_blocks = __commonJS({
|
|
|
61664
61809
|
}
|
|
61665
61810
|
});
|
|
61666
61811
|
|
|
61667
|
-
// ../system/dist/retired-settings-keys-
|
|
61668
|
-
var
|
|
61669
|
-
"../system/dist/retired-settings-keys-
|
|
61812
|
+
// ../system/dist/retired-settings-keys-DauPtbFR.js
|
|
61813
|
+
var require_retired_settings_keys_DauPtbFR = __commonJS({
|
|
61814
|
+
"../system/dist/retired-settings-keys-DauPtbFR.js"(exports) {
|
|
61670
61815
|
"use strict";
|
|
61671
|
-
var require_dist10 =
|
|
61816
|
+
var require_dist10 = require_dist_TEwQZL3g();
|
|
61672
61817
|
function settingsStoreIsAuthoritativeHere(env) {
|
|
61673
61818
|
const raw = (env["CAMSTACK_ROLE"] ?? "").trim().toLowerCase();
|
|
61674
61819
|
return raw === "" || raw === "hub";
|
|
@@ -63882,8 +64027,8 @@ var require_device_manager_addon = __commonJS({
|
|
|
63882
64027
|
[Symbol.toStringTag]: { value: "Module" }
|
|
63883
64028
|
});
|
|
63884
64029
|
require_chunk_Cek0wNdY();
|
|
63885
|
-
var require_dist10 =
|
|
63886
|
-
var require_retired_settings_keys =
|
|
64030
|
+
var require_dist10 = require_dist_TEwQZL3g();
|
|
64031
|
+
var require_retired_settings_keys = require_retired_settings_keys_DauPtbFR();
|
|
63887
64032
|
var node_crypto = __require("crypto");
|
|
63888
64033
|
var _camstack_types_node = require_node();
|
|
63889
64034
|
var JOB_HISTORY = 20;
|
|
@@ -65546,7 +65691,13 @@ var require_device_manager_addon = __commonJS({
|
|
|
65546
65691
|
if (config.mode === "auto") {
|
|
65547
65692
|
if (selfLocation !== null && selfLocation.length > 0) for (const c of candidates) {
|
|
65548
65693
|
if (c.type === require_dist10.DeviceType.Container) continue;
|
|
65549
|
-
if (c.location
|
|
65694
|
+
if (c.location !== selfLocation) continue;
|
|
65695
|
+
const parent = c.parentDeviceId !== null ? byId.get(c.parentDeviceId) : void 0;
|
|
65696
|
+
if (parent !== void 0 && parent.type === require_dist10.DeviceType.Container) {
|
|
65697
|
+
expand(parent.id);
|
|
65698
|
+
continue;
|
|
65699
|
+
}
|
|
65700
|
+
ids.add(c.id);
|
|
65550
65701
|
}
|
|
65551
65702
|
} else for (const id of config.manualIds) if (byId.has(id)) expand(id);
|
|
65552
65703
|
ids.delete(selfId);
|
|
@@ -66409,6 +66560,16 @@ var require_device_manager_addon = __commonJS({
|
|
|
66409
66560
|
const down = [...await applyAll(deps, sourceId, false), ...await applyAll(deps, targetId, false)];
|
|
66410
66561
|
const sourceStillLive = down.filter((r) => r.deviceId === sourceId && r.outcome === "unreachable").map((r) => r.switchId);
|
|
66411
66562
|
await deps.swapIds(sourceId, targetId);
|
|
66563
|
+
await deps.swapHardwareState(sourceId, targetId);
|
|
66564
|
+
for (const deviceId of [sourceId, targetId]) try {
|
|
66565
|
+
await deps.forgetStreamState(deviceId);
|
|
66566
|
+
} catch (err) {
|
|
66567
|
+
deps.log("migration: broker hardware state NOT forgotten \u2014 stale stream state survives", {
|
|
66568
|
+
deviceId,
|
|
66569
|
+
error: err instanceof Error ? err.message : String(err),
|
|
66570
|
+
remedy: "delete the device's derived streams and reassign its stream profiles, or update the stream-broker addon and re-run streamBroker.forgetDeviceHardware"
|
|
66571
|
+
});
|
|
66572
|
+
}
|
|
66412
66573
|
const up = await applyAll(deps, sourceId, true);
|
|
66413
66574
|
await deps.respawnRunners([sourceId, targetId]);
|
|
66414
66575
|
deps.log("camera migrated", {
|
|
@@ -66425,6 +66586,49 @@ var require_device_manager_addon = __commonJS({
|
|
|
66425
66586
|
swapped: true
|
|
66426
66587
|
};
|
|
66427
66588
|
}
|
|
66589
|
+
var PROFILE_MAP_CONFIG_KEY = "_profileMap";
|
|
66590
|
+
var ROLE_SCOPED_CONFIG_KEYS = new Set(DEVICE_STORE_SECTIONS.flatMap((section) => [...section.keys]));
|
|
66591
|
+
function splitConfig(config) {
|
|
66592
|
+
const hardware = {};
|
|
66593
|
+
const role = {};
|
|
66594
|
+
for (const [key, value] of Object.entries(config)) {
|
|
66595
|
+
if (key === PROFILE_MAP_CONFIG_KEY) continue;
|
|
66596
|
+
if (ROLE_SCOPED_CONFIG_KEYS.has(key)) role[key] = value;
|
|
66597
|
+
else hardware[key] = value;
|
|
66598
|
+
}
|
|
66599
|
+
return {
|
|
66600
|
+
hardware,
|
|
66601
|
+
role
|
|
66602
|
+
};
|
|
66603
|
+
}
|
|
66604
|
+
async function swapHardwareState(settings, sourceId, targetId) {
|
|
66605
|
+
const sourceConfig = await settings.readDeviceStore(sourceId);
|
|
66606
|
+
const targetConfig = await settings.readDeviceStore(targetId);
|
|
66607
|
+
const source = splitConfig(sourceConfig);
|
|
66608
|
+
const target = splitConfig(targetConfig);
|
|
66609
|
+
await settings.clearDeviceStore(sourceId);
|
|
66610
|
+
await settings.writeDeviceStore(sourceId, {
|
|
66611
|
+
...target.hardware,
|
|
66612
|
+
...source.role
|
|
66613
|
+
});
|
|
66614
|
+
await settings.clearDeviceStore(targetId);
|
|
66615
|
+
await settings.writeDeviceStore(targetId, {
|
|
66616
|
+
...source.hardware,
|
|
66617
|
+
...target.role
|
|
66618
|
+
});
|
|
66619
|
+
const sourceRuntimeState = await settings.readDeviceRuntimeState(sourceId);
|
|
66620
|
+
const targetRuntimeState = await settings.readDeviceRuntimeState(targetId);
|
|
66621
|
+
await settings.writeDeviceRuntimeState(sourceId, targetRuntimeState);
|
|
66622
|
+
await settings.writeDeviceRuntimeState(targetId, sourceRuntimeState);
|
|
66623
|
+
return {
|
|
66624
|
+
runtimeStateNowAtSource: targetRuntimeState,
|
|
66625
|
+
runtimeStateNowAtTarget: sourceRuntimeState,
|
|
66626
|
+
hardwareKeysToSource: Object.keys(target.hardware).toSorted(),
|
|
66627
|
+
hardwareKeysToTarget: Object.keys(source.hardware).toSorted(),
|
|
66628
|
+
roleKeysKeptAtSource: Object.keys(source.role).toSorted(),
|
|
66629
|
+
roleKeysKeptAtTarget: Object.keys(target.role).toSorted()
|
|
66630
|
+
};
|
|
66631
|
+
}
|
|
66428
66632
|
async function stampIntegrationId(metaStore, ctx, deviceId, integrationId) {
|
|
66429
66633
|
await metaStore.withMetaWriteLock(async () => {
|
|
66430
66634
|
if (!await metaStore.resolvePersistedById(deviceId)) throw new Error(`[device-manager] stampIntegrationId: unknown device id=${deviceId}`);
|
|
@@ -66484,13 +66688,42 @@ var require_device_manager_addon = __commonJS({
|
|
|
66484
66688
|
swapIds: async (a, b) => {
|
|
66485
66689
|
await pctx.metaStore.rows.swapIds(a, b, tempId);
|
|
66486
66690
|
},
|
|
66691
|
+
swapHardwareState: async (a, b) => {
|
|
66692
|
+
const swapped = await swapHardwareState(pctx.settings, a, b);
|
|
66693
|
+
pctx.host.seedMirror(a, pctx.host.withResetSessionProbe(swapped.runtimeStateNowAtSource));
|
|
66694
|
+
pctx.host.seedMirror(b, pctx.host.withResetSessionProbe(swapped.runtimeStateNowAtTarget));
|
|
66695
|
+
ctx.logger.info("migration: hardware-scoped device state swapped", {
|
|
66696
|
+
tags: { deviceId: a },
|
|
66697
|
+
meta: {
|
|
66698
|
+
sourceId: a,
|
|
66699
|
+
targetId: b,
|
|
66700
|
+
hardwareKeysToSource: swapped.hardwareKeysToSource,
|
|
66701
|
+
hardwareKeysToTarget: swapped.hardwareKeysToTarget,
|
|
66702
|
+
roleKeysKeptAtSource: swapped.roleKeysKeptAtSource,
|
|
66703
|
+
roleKeysKeptAtTarget: swapped.roleKeysKeptAtTarget
|
|
66704
|
+
}
|
|
66705
|
+
});
|
|
66706
|
+
},
|
|
66707
|
+
forgetStreamState: async (deviceId) => {
|
|
66708
|
+
await ctx.api.streamBroker.forgetDeviceHardware.mutate({ deviceId });
|
|
66709
|
+
},
|
|
66487
66710
|
respawnRunners: async (deviceIds) => {
|
|
66488
66711
|
const owners = /* @__PURE__ */ new Set();
|
|
66489
66712
|
for (const deviceId of deviceIds) {
|
|
66490
66713
|
const addonId = pctx.metaStore.idToAddonId.get(deviceId);
|
|
66491
66714
|
if (addonId !== void 0) owners.add(addonId);
|
|
66492
66715
|
}
|
|
66493
|
-
for (const addonId of owners)
|
|
66716
|
+
for (const addonId of owners) {
|
|
66717
|
+
const owned = [...pctx.metaStore.idToAddonId.entries()].filter(([, a]) => a === addonId).length;
|
|
66718
|
+
ctx.logger.info("migration: restarting a whole provider to flush the id maps", {
|
|
66719
|
+
tags: { deviceId: sourceId },
|
|
66720
|
+
meta: {
|
|
66721
|
+
addonId,
|
|
66722
|
+
devicesTakenDown: owned
|
|
66723
|
+
}
|
|
66724
|
+
});
|
|
66725
|
+
await ctx.api.addons.restartAddon.mutate({ addonId });
|
|
66726
|
+
}
|
|
66494
66727
|
},
|
|
66495
66728
|
log: (message, meta) => {
|
|
66496
66729
|
ctx.logger.info(message, {
|
|
@@ -68923,7 +69156,7 @@ var require_hub_forwarder = __commonJS({
|
|
|
68923
69156
|
[Symbol.toStringTag]: { value: "Module" }
|
|
68924
69157
|
});
|
|
68925
69158
|
require_chunk_Cek0wNdY();
|
|
68926
|
-
var require_dist10 =
|
|
69159
|
+
var require_dist10 = require_dist_TEwQZL3g();
|
|
68927
69160
|
var require_formatter = require_formatter_DqAKDlvN();
|
|
68928
69161
|
var DEFAULT_OUTBOUND_BUFFER_SIZE = 500;
|
|
68929
69162
|
var HubForwarderDestination = class {
|
|
@@ -69060,7 +69293,7 @@ var require_liveness_monitor_addon = __commonJS({
|
|
|
69060
69293
|
"use strict";
|
|
69061
69294
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
69062
69295
|
require_chunk_Cek0wNdY();
|
|
69063
|
-
var require_dist10 =
|
|
69296
|
+
var require_dist10 = require_dist_TEwQZL3g();
|
|
69064
69297
|
var NO_DEVICES = "liveness:no-devices";
|
|
69065
69298
|
var ALL_OFFLINE = "liveness:all-devices-offline";
|
|
69066
69299
|
var NO_FOOTAGE_PREFIX = "liveness:no-footage:";
|
|
@@ -69250,7 +69483,7 @@ var require_local_auth_addon = __commonJS({
|
|
|
69250
69483
|
[Symbol.toStringTag]: { value: "Module" }
|
|
69251
69484
|
});
|
|
69252
69485
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
69253
|
-
var require_dist10 =
|
|
69486
|
+
var require_dist10 = require_dist_TEwQZL3g();
|
|
69254
69487
|
var node_crypto = __require("crypto");
|
|
69255
69488
|
node_crypto = require_chunk.__toESM(node_crypto);
|
|
69256
69489
|
var crypto$1 = __require("crypto");
|
|
@@ -77063,7 +77296,7 @@ var require_loki_logging = __commonJS({
|
|
|
77063
77296
|
[Symbol.toStringTag]: { value: "Module" }
|
|
77064
77297
|
});
|
|
77065
77298
|
require_chunk_Cek0wNdY();
|
|
77066
|
-
var require_dist10 =
|
|
77299
|
+
var require_dist10 = require_dist_TEwQZL3g();
|
|
77067
77300
|
function sanitizeLabelName(raw) {
|
|
77068
77301
|
const replaced = raw.replaceAll(/[^a-zA-Z0-9_]/g, "_");
|
|
77069
77302
|
return /^[a-zA-Z_]/.test(replaced) ? replaced : `_${replaced}`;
|
|
@@ -77628,7 +77861,7 @@ var require_native_metrics_addon = __commonJS({
|
|
|
77628
77861
|
[Symbol.toStringTag]: { value: "Module" }
|
|
77629
77862
|
});
|
|
77630
77863
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
77631
|
-
var require_dist10 =
|
|
77864
|
+
var require_dist10 = require_dist_TEwQZL3g();
|
|
77632
77865
|
var node_fs_promises = __require("fs/promises");
|
|
77633
77866
|
var node_child_process = __require("child_process");
|
|
77634
77867
|
var node_util = __require("util");
|
|
@@ -80212,7 +80445,7 @@ var require_filesystem_storage_addon = __commonJS({
|
|
|
80212
80445
|
[Symbol.toStringTag]: { value: "Module" }
|
|
80213
80446
|
});
|
|
80214
80447
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
80215
|
-
var require_dist10 =
|
|
80448
|
+
var require_dist10 = require_dist_TEwQZL3g();
|
|
80216
80449
|
var node_crypto = __require("crypto");
|
|
80217
80450
|
var node_fs_promises = __require("fs/promises");
|
|
80218
80451
|
var node_path = __require("path");
|
|
@@ -81328,8 +81561,8 @@ var require_sqlite_settings_addon = __commonJS({
|
|
|
81328
81561
|
[Symbol.toStringTag]: { value: "Module" }
|
|
81329
81562
|
});
|
|
81330
81563
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
81331
|
-
var require_dist10 =
|
|
81332
|
-
var require_retired_settings_keys =
|
|
81564
|
+
var require_dist10 = require_dist_TEwQZL3g();
|
|
81565
|
+
var require_retired_settings_keys = require_retired_settings_keys_DauPtbFR();
|
|
81333
81566
|
var node_crypto = __require("crypto");
|
|
81334
81567
|
var node_fs = __require("fs");
|
|
81335
81568
|
var node_module = __require("module");
|
|
@@ -83819,7 +84052,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
83819
84052
|
[Symbol.toStringTag]: { value: "Module" }
|
|
83820
84053
|
});
|
|
83821
84054
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
83822
|
-
var require_dist10 =
|
|
84055
|
+
var require_dist10 = require_dist_TEwQZL3g();
|
|
83823
84056
|
var require_hub_cap_forward = require_hub_cap_forward_DmHNjbB0();
|
|
83824
84057
|
var zod = require_zod();
|
|
83825
84058
|
var node_crypto = __require("crypto");
|
|
@@ -86770,7 +87003,7 @@ var require_system_config_addon = __commonJS({
|
|
|
86770
87003
|
[Symbol.toStringTag]: { value: "Module" }
|
|
86771
87004
|
});
|
|
86772
87005
|
require_chunk_Cek0wNdY();
|
|
86773
|
-
var require_dist10 =
|
|
87006
|
+
var require_dist10 = require_dist_TEwQZL3g();
|
|
86774
87007
|
var SECTION_TITLES = {
|
|
86775
87008
|
server: "Server",
|
|
86776
87009
|
auth: "Authentication"
|
|
@@ -104831,7 +105064,7 @@ var require_winston_logging = __commonJS({
|
|
|
104831
105064
|
[Symbol.toStringTag]: { value: "Module" }
|
|
104832
105065
|
});
|
|
104833
105066
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
104834
|
-
var require_dist10 =
|
|
105067
|
+
var require_dist10 = require_dist_TEwQZL3g();
|
|
104835
105068
|
var require_formatter = require_formatter_DqAKDlvN();
|
|
104836
105069
|
var node_path = __require("path");
|
|
104837
105070
|
node_path = require_chunk.__toESM(node_path);
|
|
@@ -106774,9 +107007,9 @@ var require_event_category_BaEgqJNv = __commonJS({
|
|
|
106774
107007
|
}
|
|
106775
107008
|
});
|
|
106776
107009
|
|
|
106777
|
-
// ../types/dist/sleep-
|
|
106778
|
-
var
|
|
106779
|
-
"../types/dist/sleep-
|
|
107010
|
+
// ../types/dist/sleep-BDmIj1HV.js
|
|
107011
|
+
var require_sleep_BDmIj1HV = __commonJS({
|
|
107012
|
+
"../types/dist/sleep-BDmIj1HV.js"(exports) {
|
|
106780
107013
|
"use strict";
|
|
106781
107014
|
var require_event_category = require_event_category_BaEgqJNv();
|
|
106782
107015
|
var zod = require_zod();
|
|
@@ -109784,6 +110017,7 @@ var require_sleep_BwGJ_wL = __commonJS({
|
|
|
109784
110017
|
retractCameraStream: (input) => dispatchSystem("streamBroker", "retractCameraStream", "mutation", input),
|
|
109785
110018
|
assignProfile: (input) => dispatchSystem("streamBroker", "assignProfile", "mutation", input),
|
|
109786
110019
|
unassignProfile: (input) => dispatchSystem("streamBroker", "unassignProfile", "mutation", input),
|
|
110020
|
+
forgetDeviceHardware: (input) => dispatchSystem("streamBroker", "forgetDeviceHardware", "mutation", input),
|
|
109787
110021
|
renderPreBufferClip: (input) => dispatchSystem("streamBroker", "renderPreBufferClip", "mutation", input),
|
|
109788
110022
|
produceEventMedia: (input) => dispatchSystem("streamBroker", "produceEventMedia", "mutation", input),
|
|
109789
110023
|
restartProfile: (input) => dispatchSystem("streamBroker", "restartProfile", "mutation", input),
|
|
@@ -110448,7 +110682,7 @@ var require_addon = __commonJS({
|
|
|
110448
110682
|
"use strict";
|
|
110449
110683
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
110450
110684
|
var require_event_category = require_event_category_BaEgqJNv();
|
|
110451
|
-
var require_sleep =
|
|
110685
|
+
var require_sleep = require_sleep_BDmIj1HV();
|
|
110452
110686
|
var require_err_msg = require_err_msg_COpsHMw2();
|
|
110453
110687
|
var CAP_INPUT_DEFAULTS = Object.freeze({
|
|
110454
110688
|
"addons": { "getLogs": { "limit": 100 } },
|
|
@@ -117331,12 +117565,12 @@ var require_dist2 = __commonJS({
|
|
|
117331
117565
|
}
|
|
117332
117566
|
});
|
|
117333
117567
|
|
|
117334
|
-
// ../system/dist/manifest-system-deps-
|
|
117335
|
-
var
|
|
117336
|
-
"../system/dist/manifest-system-deps-
|
|
117568
|
+
// ../system/dist/manifest-system-deps-BVIr3MYJ.js
|
|
117569
|
+
var require_manifest_system_deps_BVIr3MYJ = __commonJS({
|
|
117570
|
+
"../system/dist/manifest-system-deps-BVIr3MYJ.js"(exports) {
|
|
117337
117571
|
"use strict";
|
|
117338
117572
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
117339
|
-
|
|
117573
|
+
require_dist_TEwQZL3g();
|
|
117340
117574
|
require_hub_cap_forward_DmHNjbB0();
|
|
117341
117575
|
var node_crypto = __require("crypto");
|
|
117342
117576
|
node_crypto = require_chunk.__toESM(node_crypto);
|
|
@@ -129403,7 +129637,7 @@ var require_dist3 = __commonJS({
|
|
|
129403
129637
|
"use strict";
|
|
129404
129638
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
129405
129639
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
129406
|
-
var require_dist10 =
|
|
129640
|
+
var require_dist10 = require_dist_TEwQZL3g();
|
|
129407
129641
|
var require_builtins_alerts_alerts_addon = require_alerts_addon();
|
|
129408
129642
|
require_alerts();
|
|
129409
129643
|
var require_formatter = require_formatter_DqAKDlvN();
|
|
@@ -129430,7 +129664,7 @@ var require_dist3 = __commonJS({
|
|
|
129430
129664
|
var require_builtins_winston_logging_index = require_winston_logging();
|
|
129431
129665
|
var require_file_data_plane = require_file_data_plane_DO8KbxCe();
|
|
129432
129666
|
var require_tls$1 = require_tls_BxQlomxd();
|
|
129433
|
-
var require_manifest_system_deps =
|
|
129667
|
+
var require_manifest_system_deps = require_manifest_system_deps_BVIr3MYJ();
|
|
129434
129668
|
var require_resource_monitor = require_resource_monitor_CdnzxBLP();
|
|
129435
129669
|
var require_custom_action_registry = require_custom_action_registry_jY0NOZK8();
|
|
129436
129670
|
var zod = require_zod();
|
|
@@ -132468,7 +132702,265 @@ var require_dist3 = __commonJS({
|
|
|
132468
132702
|
};
|
|
132469
132703
|
}
|
|
132470
132704
|
};
|
|
132705
|
+
function parseVersion(value) {
|
|
132706
|
+
const m = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/.exec(value.trim());
|
|
132707
|
+
if (!m) return null;
|
|
132708
|
+
return {
|
|
132709
|
+
major: Number(m[1]),
|
|
132710
|
+
minor: Number(m[2]),
|
|
132711
|
+
patch: Number(m[3]),
|
|
132712
|
+
prerelease: m[4] ?? null
|
|
132713
|
+
};
|
|
132714
|
+
}
|
|
132715
|
+
function compareTriple(a, b) {
|
|
132716
|
+
if (a.major !== b.major) return a.major < b.major ? -1 : 1;
|
|
132717
|
+
if (a.minor !== b.minor) return a.minor < b.minor ? -1 : 1;
|
|
132718
|
+
if (a.patch !== b.patch) return a.patch < b.patch ? -1 : 1;
|
|
132719
|
+
return 0;
|
|
132720
|
+
}
|
|
132721
|
+
function closureSatisfiesRange(range, version2) {
|
|
132722
|
+
const trimmedRange = range.trim();
|
|
132723
|
+
const v2 = parseVersion(version2);
|
|
132724
|
+
if (v2 === null) return false;
|
|
132725
|
+
if (v2.prerelease !== null) return trimmedRange === version2.trim() || trimmedRange === `=${version2.trim()}`;
|
|
132726
|
+
const exactBase = parseVersion(trimmedRange.startsWith("=") ? trimmedRange.slice(1) : trimmedRange);
|
|
132727
|
+
if (exactBase !== null) return exactBase.prerelease === null && compareTriple(v2, exactBase) === 0;
|
|
132728
|
+
const operator = trimmedRange[0];
|
|
132729
|
+
if (operator !== "^" && operator !== "~") return false;
|
|
132730
|
+
const base = parseVersion(trimmedRange.slice(1));
|
|
132731
|
+
if (base === null || base.prerelease !== null) return false;
|
|
132732
|
+
if (operator === "~") return v2.major === base.major && v2.minor === base.minor && compareTriple(v2, base) >= 0;
|
|
132733
|
+
if (base.major > 0) return v2.major === base.major && compareTriple(v2, base) >= 0;
|
|
132734
|
+
if (base.minor > 0) return v2.major === 0 && v2.minor === base.minor && compareTriple(v2, base) >= 0;
|
|
132735
|
+
return compareTriple(v2, base) === 0;
|
|
132736
|
+
}
|
|
132737
|
+
function sameCompatLine(a, b) {
|
|
132738
|
+
const pa = parseVersion(a);
|
|
132739
|
+
const pb = parseVersion(b);
|
|
132740
|
+
if (pa === null || pb === null) return false;
|
|
132741
|
+
if (pa.major !== pb.major) return false;
|
|
132742
|
+
if (pa.major === 0) return pa.minor === pb.minor;
|
|
132743
|
+
return true;
|
|
132744
|
+
}
|
|
132745
|
+
function planClosureDedupe(input) {
|
|
132746
|
+
const links = [];
|
|
132747
|
+
const keeps = [];
|
|
132748
|
+
for (const candidate of input.candidates) {
|
|
132749
|
+
if (candidate.name.startsWith("@camstack/")) {
|
|
132750
|
+
keeps.push({
|
|
132751
|
+
name: candidate.name,
|
|
132752
|
+
reason: "camstack-package"
|
|
132753
|
+
});
|
|
132754
|
+
continue;
|
|
132755
|
+
}
|
|
132756
|
+
if (input.neverLink.has(candidate.name)) {
|
|
132757
|
+
keeps.push({
|
|
132758
|
+
name: candidate.name,
|
|
132759
|
+
reason: "never-link"
|
|
132760
|
+
});
|
|
132761
|
+
continue;
|
|
132762
|
+
}
|
|
132763
|
+
const closureVersion = input.closureVersions.get(candidate.name);
|
|
132764
|
+
if (closureVersion === void 0) {
|
|
132765
|
+
keeps.push({
|
|
132766
|
+
name: candidate.name,
|
|
132767
|
+
reason: "not-in-closure"
|
|
132768
|
+
});
|
|
132769
|
+
continue;
|
|
132770
|
+
}
|
|
132771
|
+
if (closureVersion === candidate.version) {
|
|
132772
|
+
links.push({
|
|
132773
|
+
name: candidate.name,
|
|
132774
|
+
closureVersion
|
|
132775
|
+
});
|
|
132776
|
+
continue;
|
|
132777
|
+
}
|
|
132778
|
+
const ranges = input.requirements.get(candidate.name) ?? [];
|
|
132779
|
+
if (ranges.length > 0 && ranges.every((range) => closureSatisfiesRange(range, closureVersion)) && sameCompatLine(closureVersion, candidate.version)) links.push({
|
|
132780
|
+
name: candidate.name,
|
|
132781
|
+
closureVersion
|
|
132782
|
+
});
|
|
132783
|
+
else keeps.push({
|
|
132784
|
+
name: candidate.name,
|
|
132785
|
+
reason: "version-incompatible"
|
|
132786
|
+
});
|
|
132787
|
+
}
|
|
132788
|
+
return {
|
|
132789
|
+
links,
|
|
132790
|
+
keeps
|
|
132791
|
+
};
|
|
132792
|
+
}
|
|
132793
|
+
function readTreeManifest(pkgJsonPath) {
|
|
132794
|
+
let raw;
|
|
132795
|
+
try {
|
|
132796
|
+
raw = require_dist10.asJsonObject(require_dist10.parseJsonUnknown(node_fs.readFileSync(pkgJsonPath, "utf-8")));
|
|
132797
|
+
} catch {
|
|
132798
|
+
return null;
|
|
132799
|
+
}
|
|
132800
|
+
if (raw === null) return null;
|
|
132801
|
+
const ranges = /* @__PURE__ */ new Map();
|
|
132802
|
+
for (const key of [
|
|
132803
|
+
"dependencies",
|
|
132804
|
+
"optionalDependencies",
|
|
132805
|
+
"peerDependencies"
|
|
132806
|
+
]) {
|
|
132807
|
+
const deps = require_dist10.asJsonObject(raw[key]);
|
|
132808
|
+
if (deps === null) continue;
|
|
132809
|
+
for (const [name2, range] of Object.entries(deps)) if (typeof range === "string" && !ranges.has(name2)) ranges.set(name2, range);
|
|
132810
|
+
}
|
|
132811
|
+
const version2 = require_dist10.asString(raw["version"]);
|
|
132812
|
+
return {
|
|
132813
|
+
version: version2.length > 0 ? version2 : null,
|
|
132814
|
+
ranges
|
|
132815
|
+
};
|
|
132816
|
+
}
|
|
132817
|
+
function listTopLevelEntries(nodeModulesDir) {
|
|
132818
|
+
let entries;
|
|
132819
|
+
try {
|
|
132820
|
+
entries = node_fs.readdirSync(nodeModulesDir, { withFileTypes: true });
|
|
132821
|
+
} catch {
|
|
132822
|
+
return [];
|
|
132823
|
+
}
|
|
132824
|
+
const names = [];
|
|
132825
|
+
for (const entry of entries) {
|
|
132826
|
+
if (entry.name.startsWith(".")) continue;
|
|
132827
|
+
if (entry.name.startsWith("@")) {
|
|
132828
|
+
let inner;
|
|
132829
|
+
try {
|
|
132830
|
+
inner = node_fs.readdirSync(node_path.join(nodeModulesDir, entry.name), { withFileTypes: true });
|
|
132831
|
+
} catch {
|
|
132832
|
+
continue;
|
|
132833
|
+
}
|
|
132834
|
+
for (const sub of inner) if (!sub.name.startsWith(".")) names.push(`${entry.name}/${sub.name}`);
|
|
132835
|
+
} else names.push(entry.name);
|
|
132836
|
+
}
|
|
132837
|
+
return names;
|
|
132838
|
+
}
|
|
132839
|
+
function collectAddonTreeState(addonDir) {
|
|
132840
|
+
const nodeModulesDir = node_path.join(addonDir, "node_modules");
|
|
132841
|
+
const requirements = /* @__PURE__ */ new Map();
|
|
132842
|
+
const addRange = (name2, range) => {
|
|
132843
|
+
const existing = requirements.get(name2);
|
|
132844
|
+
if (existing === void 0) requirements.set(name2, [range]);
|
|
132845
|
+
else existing.push(range);
|
|
132846
|
+
};
|
|
132847
|
+
const rootManifest = readTreeManifest(node_path.join(addonDir, "package.json"));
|
|
132848
|
+
if (rootManifest !== null) for (const [name2, range] of rootManifest.ranges) addRange(name2, range);
|
|
132849
|
+
const candidates = [];
|
|
132850
|
+
const existingLinks = [];
|
|
132851
|
+
for (const name2 of listTopLevelEntries(nodeModulesDir)) {
|
|
132852
|
+
const entryDir = node_path.join(nodeModulesDir, name2);
|
|
132853
|
+
let isLink = false;
|
|
132854
|
+
try {
|
|
132855
|
+
isLink = node_fs.lstatSync(entryDir).isSymbolicLink();
|
|
132856
|
+
} catch {
|
|
132857
|
+
continue;
|
|
132858
|
+
}
|
|
132859
|
+
if (isLink) {
|
|
132860
|
+
let target = "";
|
|
132861
|
+
try {
|
|
132862
|
+
target = node_fs.readlinkSync(entryDir);
|
|
132863
|
+
} catch {
|
|
132864
|
+
}
|
|
132865
|
+
existingLinks.push({
|
|
132866
|
+
name: name2,
|
|
132867
|
+
target
|
|
132868
|
+
});
|
|
132869
|
+
}
|
|
132870
|
+
const manifest = readTreeManifest(node_path.join(entryDir, "package.json"));
|
|
132871
|
+
if (manifest === null) continue;
|
|
132872
|
+
if (!isLink && manifest.version !== null) candidates.push({
|
|
132873
|
+
name: name2,
|
|
132874
|
+
version: manifest.version
|
|
132875
|
+
});
|
|
132876
|
+
for (const [depName, range] of manifest.ranges) {
|
|
132877
|
+
if (node_fs.existsSync(node_path.join(entryDir, "node_modules", depName))) continue;
|
|
132878
|
+
addRange(depName, range);
|
|
132879
|
+
}
|
|
132880
|
+
}
|
|
132881
|
+
return {
|
|
132882
|
+
candidates,
|
|
132883
|
+
requirements,
|
|
132884
|
+
existingLinks
|
|
132885
|
+
};
|
|
132886
|
+
}
|
|
132887
|
+
function readClosureVersions(closureNodeModulesDir, names) {
|
|
132888
|
+
const versions = /* @__PURE__ */ new Map();
|
|
132889
|
+
for (const name2 of names) {
|
|
132890
|
+
const manifest = readTreeManifest(node_path.join(closureNodeModulesDir, name2, "package.json"));
|
|
132891
|
+
if (manifest !== null && manifest.version !== null) versions.set(name2, manifest.version);
|
|
132892
|
+
}
|
|
132893
|
+
return versions;
|
|
132894
|
+
}
|
|
132895
|
+
function resolveClosureNodeModulesDir(explicitDir) {
|
|
132896
|
+
const frameworkDir = explicitDir ?? process.env["CAMSTACK_FRAMEWORK_DIR"];
|
|
132897
|
+
if (frameworkDir === void 0 || frameworkDir.length === 0) return null;
|
|
132898
|
+
const nodeModulesDir = explicitDir ?? node_path.join(frameworkDir, "node_modules");
|
|
132899
|
+
return node_fs.existsSync(nodeModulesDir) ? nodeModulesDir : null;
|
|
132900
|
+
}
|
|
132901
|
+
function symlinkType() {
|
|
132902
|
+
return process.platform === "win32" ? "junction" : "dir";
|
|
132903
|
+
}
|
|
132904
|
+
function executeClosureDedupe(addonDir, closureNodeModulesDir, plan, logger) {
|
|
132905
|
+
if (plan.links.length === 0) return [];
|
|
132906
|
+
const nodeModulesDir = node_path.join(addonDir, "node_modules");
|
|
132907
|
+
const probePath = node_path.join(nodeModulesDir, ".closure-link-probe");
|
|
132908
|
+
try {
|
|
132909
|
+
node_fs.mkdirSync(nodeModulesDir, { recursive: true });
|
|
132910
|
+
node_fs.rmSync(probePath, { force: true });
|
|
132911
|
+
node_fs.symlinkSync(closureNodeModulesDir, probePath, symlinkType());
|
|
132912
|
+
node_fs.rmSync(probePath, { force: true });
|
|
132913
|
+
} catch (err) {
|
|
132914
|
+
logger.warn("closure dedupe skipped \u2014 symlinks unavailable on this volume", { meta: {
|
|
132915
|
+
addonDir,
|
|
132916
|
+
error: require_dist10.errMsg(err)
|
|
132917
|
+
} });
|
|
132918
|
+
return [];
|
|
132919
|
+
}
|
|
132920
|
+
const linked = [];
|
|
132921
|
+
for (const link of plan.links) {
|
|
132922
|
+
const target = node_path.join(closureNodeModulesDir, link.name);
|
|
132923
|
+
const manifest = readTreeManifest(node_path.join(target, "package.json"));
|
|
132924
|
+
if (manifest === null || manifest.version !== link.closureVersion) {
|
|
132925
|
+
logger.warn("closure dedupe \u2014 closure changed under the plan; keeping own copy", { meta: {
|
|
132926
|
+
name: link.name,
|
|
132927
|
+
planned: link.closureVersion,
|
|
132928
|
+
found: manifest?.version ?? null
|
|
132929
|
+
} });
|
|
132930
|
+
continue;
|
|
132931
|
+
}
|
|
132932
|
+
const entryDir = node_path.join(nodeModulesDir, link.name);
|
|
132933
|
+
try {
|
|
132934
|
+
node_fs.rmSync(entryDir, {
|
|
132935
|
+
recursive: true,
|
|
132936
|
+
force: true
|
|
132937
|
+
});
|
|
132938
|
+
node_fs.mkdirSync(node_path.dirname(entryDir), { recursive: true });
|
|
132939
|
+
node_fs.symlinkSync(target, entryDir, symlinkType());
|
|
132940
|
+
linked.push(link.name);
|
|
132941
|
+
} catch (err) {
|
|
132942
|
+
logger.warn("closure dedupe \u2014 link failed; entry removed copy may need reinstall", { meta: {
|
|
132943
|
+
name: link.name,
|
|
132944
|
+
error: require_dist10.errMsg(err)
|
|
132945
|
+
} });
|
|
132946
|
+
}
|
|
132947
|
+
}
|
|
132948
|
+
return linked;
|
|
132949
|
+
}
|
|
132950
|
+
function isClosureLinkTarget(linkTarget, closureNodeModulesDir) {
|
|
132951
|
+
if (linkTarget.length === 0) return false;
|
|
132952
|
+
const normalized = node_path.resolve(linkTarget);
|
|
132953
|
+
const root = node_path.resolve(closureNodeModulesDir);
|
|
132954
|
+
return normalized === root || normalized.startsWith(`${root}${node_path.sep}`);
|
|
132955
|
+
}
|
|
132471
132956
|
var execFileAsync = (0, node_util.promisify)(node_child_process.execFile);
|
|
132957
|
+
function readNativeDependencyNames(pkg) {
|
|
132958
|
+
if (pkg === void 0) return /* @__PURE__ */ new Set();
|
|
132959
|
+
const camstack = require_dist10.asJsonObject(pkg["camstack"]);
|
|
132960
|
+
if (camstack === null) return /* @__PURE__ */ new Set();
|
|
132961
|
+
const native = require_dist10.asJsonObject(camstack["nativeDependencies"]);
|
|
132962
|
+
return native === null ? /* @__PURE__ */ new Set() : new Set(Object.keys(native));
|
|
132963
|
+
}
|
|
132472
132964
|
function parseInstallSource(value) {
|
|
132473
132965
|
switch (value) {
|
|
132474
132966
|
case "npm":
|
|
@@ -132530,6 +133022,8 @@ var require_dist3 = __commonJS({
|
|
|
132530
133022
|
installSource;
|
|
132531
133023
|
logger;
|
|
132532
133024
|
isPackageResolvable;
|
|
133025
|
+
/** Test seam — production resolves via `CAMSTACK_FRAMEWORK_DIR`. */
|
|
133026
|
+
closureNodeModulesDir;
|
|
132533
133027
|
/**
|
|
132534
133028
|
* Central manifest of installed addons. Tracks version + source +
|
|
132535
133029
|
* timestamps + last-backup pointer per package, written atomically
|
|
@@ -132551,6 +133045,7 @@ var require_dist3 = __commonJS({
|
|
|
132551
133045
|
this.logger = logger;
|
|
132552
133046
|
this.manifest = new AddonManifest(config.addonsDir);
|
|
132553
133047
|
this.isPackageResolvable = config.isPackageResolvable;
|
|
133048
|
+
this.closureNodeModulesDir = config.closureNodeModulesDir;
|
|
132554
133049
|
if (config.installSource) this.installSource = config.installSource;
|
|
132555
133050
|
else this.installSource = "npm";
|
|
132556
133051
|
}
|
|
@@ -132738,6 +133233,140 @@ var require_dist3 = __commonJS({
|
|
|
132738
133233
|
return changes;
|
|
132739
133234
|
}
|
|
132740
133235
|
/**
|
|
133236
|
+
* Make every INSTALLED addon's runtime dependencies resolvable — doing the
|
|
133237
|
+
* least work that achieves it. Runs at boot on hub and agent, which is what
|
|
133238
|
+
* turns a restore back into a working node: a system backup archives no
|
|
133239
|
+
* node_modules (D338), so before this pass every restored non-bootstrap
|
|
133240
|
+
* addon failed its first import until someone redeployed it by hand.
|
|
133241
|
+
*
|
|
133242
|
+
* Per addon, in order:
|
|
133243
|
+
* 1. drop closure links that no longer hold (dangling, or the closure
|
|
133244
|
+
* moved to a version the addon tree's recorded ranges refuse) — those
|
|
133245
|
+
* addons get a reinstall;
|
|
133246
|
+
* 2. a declared dep that already resolves in the addon tree costs nothing;
|
|
133247
|
+
* 3. a missing declared dep the closure provides at a COMPATIBLE version
|
|
133248
|
+
* becomes a link — no npm, no network;
|
|
133249
|
+
* 4. only an addon left with a genuinely unresolvable dep gets an npm
|
|
133250
|
+
* install (then dedupe + native ensure, same tail as a fresh install).
|
|
133251
|
+
*
|
|
133252
|
+
* "Only when necessary" is the contract: an addon whose deps are all
|
|
133253
|
+
* satisfied is not touched at all. Failures are per-addon and non-fatal —
|
|
133254
|
+
* a dep that cannot be re-fetched leaves that addon exactly as broken as
|
|
133255
|
+
* it already was, but LOUDLY, and never blocks the rest of the boot.
|
|
133256
|
+
*/
|
|
133257
|
+
async ensureAddonRuntimeDeps() {
|
|
133258
|
+
const closureNodeModules = resolveClosureNodeModulesDir(this.closureNodeModulesDir);
|
|
133259
|
+
const linked = [];
|
|
133260
|
+
const reinstalled = [];
|
|
133261
|
+
const failed = [];
|
|
133262
|
+
const installedPackages = this.listInstalled();
|
|
133263
|
+
for (const pkg of installedPackages) {
|
|
133264
|
+
try {
|
|
133265
|
+
if (node_fs.lstatSync(pkg.dir).isSymbolicLink()) continue;
|
|
133266
|
+
} catch {
|
|
133267
|
+
continue;
|
|
133268
|
+
}
|
|
133269
|
+
try {
|
|
133270
|
+
const outcome = this.ensureOneAddonDeps(pkg.dir, pkg.name, closureNodeModules);
|
|
133271
|
+
for (const dep of outcome.linked) linked.push(`${pkg.name}:${dep}`);
|
|
133272
|
+
if (outcome.needsInstall) {
|
|
133273
|
+
await this.reinstallAddonDeps(pkg.dir, pkg.name);
|
|
133274
|
+
reinstalled.push(pkg.name);
|
|
133275
|
+
}
|
|
133276
|
+
} catch (err) {
|
|
133277
|
+
failed.push(pkg.name);
|
|
133278
|
+
this.logger.error(`${pkg.name} \u2014 runtime dependencies could NOT be ensured; the addon will fail to load until its deps install`, { meta: {
|
|
133279
|
+
dir: pkg.dir,
|
|
133280
|
+
error: require_dist10.errMsg(err)
|
|
133281
|
+
} });
|
|
133282
|
+
}
|
|
133283
|
+
}
|
|
133284
|
+
return {
|
|
133285
|
+
checked: installedPackages.length,
|
|
133286
|
+
linked,
|
|
133287
|
+
reinstalled,
|
|
133288
|
+
failed
|
|
133289
|
+
};
|
|
133290
|
+
}
|
|
133291
|
+
/**
|
|
133292
|
+
* One addon's dependency audit (steps 1–3 of `ensureAddonRuntimeDeps`).
|
|
133293
|
+
* Pure decision + link creation; the npm fallback is the caller's.
|
|
133294
|
+
*/
|
|
133295
|
+
ensureOneAddonDeps(addonDir, packageName, closureNodeModules) {
|
|
133296
|
+
const pkgView = readPackageJson(node_path.join(addonDir, "package.json"));
|
|
133297
|
+
const declared = pkgView === null ? null : require_dist10.asJsonObject(pkgView.raw["dependencies"]);
|
|
133298
|
+
const declaredEntries = declared === null ? [] : Object.entries(declared);
|
|
133299
|
+
const state = collectAddonTreeState(addonDir);
|
|
133300
|
+
const nodeModulesDir = node_path.join(addonDir, "node_modules");
|
|
133301
|
+
let needsInstall = false;
|
|
133302
|
+
if (closureNodeModules !== null) for (const link of state.existingLinks) {
|
|
133303
|
+
if (!isClosureLinkTarget(link.target, closureNodeModules)) continue;
|
|
133304
|
+
const linkDir = node_path.join(nodeModulesDir, link.name);
|
|
133305
|
+
const targetManifest = node_fs.existsSync(node_path.join(linkDir, "package.json"));
|
|
133306
|
+
const ranges = state.requirements.get(link.name) ?? [];
|
|
133307
|
+
let holds = targetManifest;
|
|
133308
|
+
if (holds && ranges.length > 0) {
|
|
133309
|
+
const version2 = readClosureVersions(closureNodeModules, [link.name]).get(link.name);
|
|
133310
|
+
holds = version2 !== void 0 && ranges.every((range) => closureSatisfiesRange(range, version2));
|
|
133311
|
+
}
|
|
133312
|
+
if (!holds) {
|
|
133313
|
+
this.logger.warn(`${packageName} \u2014 closure link for ${link.name} no longer holds; reinstalling this addon's deps`, { meta: { target: link.target } });
|
|
133314
|
+
node_fs.rmSync(linkDir, { force: true });
|
|
133315
|
+
needsInstall = true;
|
|
133316
|
+
}
|
|
133317
|
+
}
|
|
133318
|
+
const linked = [];
|
|
133319
|
+
for (const [depName, range] of declaredEntries) {
|
|
133320
|
+
if (typeof range !== "string") continue;
|
|
133321
|
+
if (node_fs.existsSync(node_path.join(nodeModulesDir, depName, "package.json"))) continue;
|
|
133322
|
+
const closureVersion = closureNodeModules === null ? void 0 : readClosureVersions(closureNodeModules, [depName]).get(depName);
|
|
133323
|
+
if (closureNodeModules !== null && closureVersion !== void 0 && closureSatisfiesRange(range, closureVersion)) {
|
|
133324
|
+
if (executeClosureDedupe(addonDir, closureNodeModules, {
|
|
133325
|
+
links: [{
|
|
133326
|
+
name: depName,
|
|
133327
|
+
closureVersion
|
|
133328
|
+
}],
|
|
133329
|
+
keeps: []
|
|
133330
|
+
}, this.logger).length === 1) {
|
|
133331
|
+
this.logger.info(`${packageName} \u2014 ${depName} linked from the server closure`, { meta: { closureVersion } });
|
|
133332
|
+
linked.push(depName);
|
|
133333
|
+
continue;
|
|
133334
|
+
}
|
|
133335
|
+
}
|
|
133336
|
+
needsInstall = true;
|
|
133337
|
+
}
|
|
133338
|
+
return {
|
|
133339
|
+
linked,
|
|
133340
|
+
needsInstall
|
|
133341
|
+
};
|
|
133342
|
+
}
|
|
133343
|
+
/**
|
|
133344
|
+
* npm-install an installed addon's runtime deps IN PLACE (the restore /
|
|
133345
|
+
* repair path — the tree is not yet running at boot), then the same tail
|
|
133346
|
+
* every fresh install gets: closure dedupe + native deps + prebuild ensure.
|
|
133347
|
+
* Closure links are stripped first so npm reifies against plain missing
|
|
133348
|
+
* dirs instead of symlinks it does not own.
|
|
133349
|
+
*/
|
|
133350
|
+
async reinstallAddonDeps(addonDir, packageName) {
|
|
133351
|
+
const closureNodeModules = resolveClosureNodeModulesDir(this.closureNodeModulesDir);
|
|
133352
|
+
if (closureNodeModules !== null) {
|
|
133353
|
+
const state = collectAddonTreeState(addonDir);
|
|
133354
|
+
for (const link of state.existingLinks) if (isClosureLinkTarget(link.target, closureNodeModules)) node_fs.rmSync(node_path.join(addonDir, "node_modules", link.name), { force: true });
|
|
133355
|
+
}
|
|
133356
|
+
this.logger.info(`${packageName} \u2014 reinstalling runtime dependencies`, { meta: { addonDir } });
|
|
133357
|
+
await require_manifest_system_deps.runNpm([
|
|
133358
|
+
"install",
|
|
133359
|
+
"--omit=dev",
|
|
133360
|
+
"--omit=peer",
|
|
133361
|
+
"--no-audit",
|
|
133362
|
+
"--no-fund",
|
|
133363
|
+
"--no-package-lock",
|
|
133364
|
+
...this.registry ? ["--registry", this.registry] : []
|
|
133365
|
+
], this.npmRunOptions(addonDir, 24e4));
|
|
133366
|
+
this.dedupeTreeAgainstClosure(addonDir, packageName);
|
|
133367
|
+
await this.installNativeDependencies(addonDir, packageName);
|
|
133368
|
+
}
|
|
133369
|
+
/**
|
|
132741
133370
|
* Install a single addon — on-demand installer used by AddonPackageService
|
|
132742
133371
|
* (admin UI "Install addon" / "Reinstall" buttons).
|
|
132743
133372
|
*
|
|
@@ -132845,6 +133474,7 @@ var require_dist3 = __commonJS({
|
|
|
132845
133474
|
logger: this.logger,
|
|
132846
133475
|
bundledSourceDir: sourceDir
|
|
132847
133476
|
});
|
|
133477
|
+
this.dedupeTreeAgainstClosure(targetDir, packageName);
|
|
132848
133478
|
this.logger.info(`${packageName} \u2014 copied from ${sourceDir}`);
|
|
132849
133479
|
return {
|
|
132850
133480
|
name: pkgData.name,
|
|
@@ -133149,6 +133779,40 @@ var require_dist3 = __commonJS({
|
|
|
133149
133779
|
logger: this.logger
|
|
133150
133780
|
});
|
|
133151
133781
|
}
|
|
133782
|
+
/**
|
|
133783
|
+
* Stop copying what the server closure already provides: replace each
|
|
133784
|
+
* top-level `node_modules` entry the closure serves at a COMPATIBLE version
|
|
133785
|
+
* with a symlink into the closure (see `deps/closure-dedupe.ts` for the
|
|
133786
|
+
* plan rules and the live measurements). Runs LAST in tree
|
|
133787
|
+
* materialisation — after the runtime-dep npm install AND the native-dep
|
|
133788
|
+
* steps — so no later npm invocation can fight the links.
|
|
133789
|
+
*
|
|
133790
|
+
* Non-fatal by design: dedupe is an optimisation, and its failure mode is
|
|
133791
|
+
* "the addon keeps its own copies", which is exactly today's behaviour. A
|
|
133792
|
+
* refusal on version grounds is logged loudly — that line is the answer to
|
|
133793
|
+
* "why does this addon still carry its own zod".
|
|
133794
|
+
*/
|
|
133795
|
+
dedupeTreeAgainstClosure(pkgDir, packageName) {
|
|
133796
|
+
const closureNodeModules = resolveClosureNodeModulesDir(this.closureNodeModulesDir);
|
|
133797
|
+
if (closureNodeModules === null) return;
|
|
133798
|
+
try {
|
|
133799
|
+
const state = collectAddonTreeState(pkgDir);
|
|
133800
|
+
if (state.candidates.length === 0) return;
|
|
133801
|
+
const pkgView = readPackageJson(node_path.join(pkgDir, "package.json"));
|
|
133802
|
+
const plan = planClosureDedupe({
|
|
133803
|
+
candidates: state.candidates,
|
|
133804
|
+
closureVersions: readClosureVersions(closureNodeModules, state.candidates.map((c) => c.name)),
|
|
133805
|
+
requirements: state.requirements,
|
|
133806
|
+
neverLink: readNativeDependencyNames(pkgView?.raw)
|
|
133807
|
+
});
|
|
133808
|
+
const linked = executeClosureDedupe(pkgDir, closureNodeModules, plan, this.logger);
|
|
133809
|
+
if (linked.length > 0) this.logger.info(`${packageName} \u2014 ${linked.length} node_modules entr${linked.length === 1 ? "y" : "ies"} now resolve from the server closure`, { meta: { linked } });
|
|
133810
|
+
const refused = plan.keeps.filter((k2) => k2.reason === "version-incompatible");
|
|
133811
|
+
if (refused.length > 0) this.logger.info(`${packageName} \u2014 kept own copy where the closure version is incompatible`, { meta: { kept: refused.map((k2) => k2.name) } });
|
|
133812
|
+
} catch (err) {
|
|
133813
|
+
this.logger.warn(`${packageName} \u2014 closure dedupe failed (copies kept)`, { meta: { error: require_dist10.errMsg(err) } });
|
|
133814
|
+
}
|
|
133815
|
+
}
|
|
133152
133816
|
/** Install addon from a tgz file (uploaded or downloaded) */
|
|
133153
133817
|
async installFromTgz(tgzPath) {
|
|
133154
133818
|
const stagingRoot = node_path.join(this.addonsDir, ".staging");
|
|
@@ -133174,6 +133838,7 @@ var require_dist3 = __commonJS({
|
|
|
133174
133838
|
const targetDir = node_path.join(this.addonsDir, pkgView.name);
|
|
133175
133839
|
await this.installRuntimeDependencies(pkgDir, pkgView.name);
|
|
133176
133840
|
await this.installNativeDependencies(pkgDir, pkgView.name);
|
|
133841
|
+
this.dedupeTreeAgainstClosure(pkgDir, pkgView.name);
|
|
133177
133842
|
await this.evictInstallDir(targetDir);
|
|
133178
133843
|
ensureDir(node_path.dirname(targetDir));
|
|
133179
133844
|
await node_fs.promises.rename(pkgDir, targetDir);
|
|
@@ -133306,6 +133971,7 @@ var require_dist3 = __commonJS({
|
|
|
133306
133971
|
if (!node_fs.existsSync(addonDir)) throw new Error(`Cannot update ${packageName}: install dir ${addonDir} missing`);
|
|
133307
133972
|
await this.installRuntimeDependencies(stagedPath, packageName);
|
|
133308
133973
|
await this.installNativeDependencies(stagedPath, packageName);
|
|
133974
|
+
this.dedupeTreeAgainstClosure(stagedPath, packageName);
|
|
133309
133975
|
const ts2 = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
133310
133976
|
const backupRoot = node_path.join(this.addonsDir, ".backups", packageName);
|
|
133311
133977
|
ensureDir(backupRoot);
|
|
@@ -163521,7 +164187,7 @@ globstar while`, t, d, e, u, m), this.matchOne(t.slice(d), e.slice(u), s)) retur
|
|
|
163521
164187
|
}));
|
|
163522
164188
|
var require_symlink_type2 = /* @__PURE__ */ require_chunk.__commonJSMin(((exports2, module2) => {
|
|
163523
164189
|
var fs2 = require_graceful_fs2();
|
|
163524
|
-
function
|
|
164190
|
+
function symlinkType2(srcpath, type2, callback) {
|
|
163525
164191
|
callback = typeof type2 === "function" ? type2 : callback;
|
|
163526
164192
|
type2 = typeof type2 === "function" ? false : type2;
|
|
163527
164193
|
if (type2) return callback(null, type2);
|
|
@@ -163542,7 +164208,7 @@ globstar while`, t, d, e, u, m), this.matchOne(t.slice(d), e.slice(u), s)) retur
|
|
|
163542
164208
|
return stats && stats.isDirectory() ? "dir" : "file";
|
|
163543
164209
|
}
|
|
163544
164210
|
module2.exports = {
|
|
163545
|
-
symlinkType,
|
|
164211
|
+
symlinkType: symlinkType2,
|
|
163546
164212
|
symlinkTypeSync
|
|
163547
164213
|
};
|
|
163548
164214
|
}));
|
|
@@ -163557,7 +164223,7 @@ globstar while`, t, d, e, u, m), this.matchOne(t.slice(d), e.slice(u), s)) retur
|
|
|
163557
164223
|
var symlinkPaths = _symlinkPaths.symlinkPaths;
|
|
163558
164224
|
var symlinkPathsSync = _symlinkPaths.symlinkPathsSync;
|
|
163559
164225
|
var _symlinkType = require_symlink_type2();
|
|
163560
|
-
var
|
|
164226
|
+
var symlinkType2 = _symlinkType.symlinkType;
|
|
163561
164227
|
var symlinkTypeSync = _symlinkType.symlinkTypeSync;
|
|
163562
164228
|
var pathExists = require_path_exists2().pathExists;
|
|
163563
164229
|
function createSymlink(srcpath, dstpath, type2, callback) {
|
|
@@ -163569,7 +164235,7 @@ globstar while`, t, d, e, u, m), this.matchOne(t.slice(d), e.slice(u), s)) retur
|
|
|
163569
164235
|
symlinkPaths(srcpath, dstpath, (err2, relative) => {
|
|
163570
164236
|
if (err2) return callback(err2);
|
|
163571
164237
|
srcpath = relative.toDst;
|
|
163572
|
-
|
|
164238
|
+
symlinkType2(relative.toCwd, type2, (err3, type3) => {
|
|
163573
164239
|
if (err3) return callback(err3);
|
|
163574
164240
|
const dir = path$23.dirname(dstpath);
|
|
163575
164241
|
pathExists(dir, (err4, dirExists) => {
|
|
@@ -210088,7 +210754,7 @@ var require_dist4 = __commonJS({
|
|
|
210088
210754
|
"use strict";
|
|
210089
210755
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
210090
210756
|
var require_event_category = require_event_category_BaEgqJNv();
|
|
210091
|
-
var require_sleep =
|
|
210757
|
+
var require_sleep = require_sleep_BDmIj1HV();
|
|
210092
210758
|
var require_canonical_hash = require_canonical_hash_DNV8S5ET();
|
|
210093
210759
|
var require_enums2 = require_enums();
|
|
210094
210760
|
var require_err_msg = require_err_msg_COpsHMw2();
|
|
@@ -214698,6 +215364,68 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
214698
215364
|
fileCount: zod.z.number(),
|
|
214699
215365
|
present: zod.z.boolean()
|
|
214700
215366
|
});
|
|
215367
|
+
var BackupRunStateSchema = zod.z.enum([
|
|
215368
|
+
"queued",
|
|
215369
|
+
"running",
|
|
215370
|
+
"succeeded",
|
|
215371
|
+
"failed",
|
|
215372
|
+
"cancelled"
|
|
215373
|
+
]);
|
|
215374
|
+
var BackupRunPhaseSchema = zod.z.enum([
|
|
215375
|
+
"queued",
|
|
215376
|
+
"building",
|
|
215377
|
+
"uploading",
|
|
215378
|
+
"done"
|
|
215379
|
+
]);
|
|
215380
|
+
var BackupRunSchema = zod.z.object({
|
|
215381
|
+
/** Stable run id — the handle `backup.cancel` takes. */
|
|
215382
|
+
id: zod.z.string(),
|
|
215383
|
+
state: BackupRunStateSchema,
|
|
215384
|
+
phase: BackupRunPhaseSchema,
|
|
215385
|
+
/**
|
|
215386
|
+
* Resolved destination location ids. Empty while queued (targets are
|
|
215387
|
+
* resolved when the run starts, against the then-current policies).
|
|
215388
|
+
*/
|
|
215389
|
+
destinationIds: zod.z.array(zod.z.string()).readonly(),
|
|
215390
|
+
label: zod.z.string().optional(),
|
|
215391
|
+
/** ms-epoch when the run was submitted (trigger call / schedule fire). */
|
|
215392
|
+
requestedAt: zod.z.number(),
|
|
215393
|
+
/** ms-epoch when the run left the queue and started building. */
|
|
215394
|
+
startedAt: zod.z.number().optional(),
|
|
215395
|
+
/** ms-epoch when the run reached a terminal state. */
|
|
215396
|
+
finishedAt: zod.z.number().optional(),
|
|
215397
|
+
/** Compressed bytes of the staging archive written so far. */
|
|
215398
|
+
stagedBytes: zod.z.number(),
|
|
215399
|
+
/** Final staged archive size, once the build phase completes. */
|
|
215400
|
+
archiveSizeBytes: zod.z.number().optional(),
|
|
215401
|
+
/** Bytes pushed to the destination currently uploading. */
|
|
215402
|
+
uploadedBytes: zod.z.number(),
|
|
215403
|
+
/** Destinations where the archive fully landed (uploaded + indexed). */
|
|
215404
|
+
completedDestinationIds: zod.z.array(zod.z.string()).readonly(),
|
|
215405
|
+
/** Destinations that failed during the fan-out. */
|
|
215406
|
+
failedDestinationIds: zod.z.array(zod.z.string()).readonly(),
|
|
215407
|
+
/** Failure message when `state === 'failed'`. */
|
|
215408
|
+
error: zod.z.string().optional(),
|
|
215409
|
+
/**
|
|
215410
|
+
* 1-based place in the execution queue — 1 = runs next. Present only
|
|
215411
|
+
* while `state === 'queued'`. Stamped by the orchestrator from the
|
|
215412
|
+
* queue's OWN pending order, never derived from timestamps, so the
|
|
215413
|
+
* UI cannot show an order the executor will not honour.
|
|
215414
|
+
*/
|
|
215415
|
+
queuePosition: zod.z.number().int().min(1).optional()
|
|
215416
|
+
});
|
|
215417
|
+
var BackupTriggerResultSchema = zod.z.object({
|
|
215418
|
+
/** The run this trigger mapped to — poll it via `listRuns`, stop it via `cancel`. */
|
|
215419
|
+
runId: zod.z.string(),
|
|
215420
|
+
/** True when the run waited behind an in-flight run instead of starting immediately. */
|
|
215421
|
+
queued: zod.z.boolean(),
|
|
215422
|
+
/** True when this trigger was coalesced onto an identical already-queued run. */
|
|
215423
|
+
joined: zod.z.boolean(),
|
|
215424
|
+
/** True when the run was cancelled before completing every destination. */
|
|
215425
|
+
cancelled: zod.z.boolean(),
|
|
215426
|
+
/** One entry per destination the archive landed at (partial on cancel). */
|
|
215427
|
+
entries: zod.z.array(BackupEntrySchema).readonly()
|
|
215428
|
+
});
|
|
214701
215429
|
var BackupScheduleSchema = zod.z.object({
|
|
214702
215430
|
/** Stable id. Generated by the orchestrator on first upsert if absent. */
|
|
214703
215431
|
id: zod.z.string(),
|
|
@@ -214734,6 +215462,11 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
214734
215462
|
* Trigger a backup. Without `destinations` the orchestrator fans
|
|
214735
215463
|
* out to every destination flagged as enabled in the routing
|
|
214736
215464
|
* config; with it, only the listed addons receive the archive.
|
|
215465
|
+
*
|
|
215466
|
+
* At most ONE backup run executes at a time — the source tree and
|
|
215467
|
+
* the staging disk are shared by every run, so a second trigger
|
|
215468
|
+
* while one is in flight is enqueued (or joined onto an identical
|
|
215469
|
+
* queued run) and the result says so. See D342.
|
|
214737
215470
|
*/
|
|
214738
215471
|
trigger: require_sleep.method(zod.z.object({
|
|
214739
215472
|
/** Subset of registered `backup-destination` addon ids to write to. */
|
|
@@ -214747,7 +215480,30 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
214747
215480
|
* retention (manual runs).
|
|
214748
215481
|
*/
|
|
214749
215482
|
retentionCount: zod.z.number().int().min(1).max(1e3).optional()
|
|
214750
|
-
}).optional(),
|
|
215483
|
+
}).optional(), BackupTriggerResultSchema, {
|
|
215484
|
+
kind: "mutation",
|
|
215485
|
+
auth: "admin"
|
|
215486
|
+
}),
|
|
215487
|
+
/**
|
|
215488
|
+
* Every run the orchestrator knows about, in EXECUTION order: the
|
|
215489
|
+
* running run first, then queued runs in the exact order they will
|
|
215490
|
+
* execute (each with `queuePosition`, 1 = next), then the bounded
|
|
215491
|
+
* finished history newest-first. Only one run executes at a time
|
|
215492
|
+
* (D342) — the queued section IS the line. Each run carries live
|
|
215493
|
+
* phase + byte counters so a runaway build is visible in seconds,
|
|
215494
|
+
* not via `du`.
|
|
215495
|
+
*/
|
|
215496
|
+
listRuns: require_sleep.method(zod.z.void(), zod.z.array(BackupRunSchema).readonly(), { auth: "admin" }),
|
|
215497
|
+
/**
|
|
215498
|
+
* Stop a backup run. Mirrors `storage-migration.cancel` semantics:
|
|
215499
|
+
* id in, `{ cancelled }` out — `false` when the run is unknown or
|
|
215500
|
+
* already terminal. A QUEUED run is removed before it ever starts;
|
|
215501
|
+
* the RUNNING run has its tar/upload stream actually aborted, the
|
|
215502
|
+
* half-written staging archive is deleted, and the in-flight
|
|
215503
|
+
* destination upload is aborted server-side (partial discarded).
|
|
215504
|
+
* Destinations that already completed keep their archive.
|
|
215505
|
+
*/
|
|
215506
|
+
cancel: require_sleep.method(zod.z.object({ runId: zod.z.string() }), zod.z.object({ cancelled: zod.z.boolean() }), {
|
|
214751
215507
|
kind: "mutation",
|
|
214752
215508
|
auth: "admin"
|
|
214753
215509
|
}),
|
|
@@ -215487,6 +216243,38 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
215487
216243
|
auth: "admin"
|
|
215488
216244
|
}),
|
|
215489
216245
|
/**
|
|
216246
|
+
* The HARDWARE behind a device number was replaced
|
|
216247
|
+
* (`deviceManager.migrateDevice`). Forget every piece of broker state that
|
|
216248
|
+
* described the old box, so the next catalog pull derives everything from
|
|
216249
|
+
* the camera that is actually there:
|
|
216250
|
+
*
|
|
216251
|
+
* - every `derived:*` stream definition — a derived is authored against a
|
|
216252
|
+
* specific profile layout, and against the wrong hardware its feeder
|
|
216253
|
+
* respawns forever (observed at attempt 2732 on the live hub,
|
|
216254
|
+
* 2026-09-01);
|
|
216255
|
+
* - the profile-slot assignment entry, PURGED (not unassigned — unassign
|
|
216256
|
+
* marks the slot manual, which would pin the stale choice instead of
|
|
216257
|
+
* letting `computeInitialAssignment` re-derive it);
|
|
216258
|
+
* - the probe snapshots (`<deviceId>/…` — probed codec/resolution of the
|
|
216259
|
+
* old hardware);
|
|
216260
|
+
* - the persisted RTSP token rows for the device's brokers (keyed
|
|
216261
|
+
* `<deviceId>/<camStreamId>`; the stream ids change with the hardware,
|
|
216262
|
+
* so the rows are dead URLs).
|
|
216263
|
+
*
|
|
216264
|
+
* An RPC, deliberately — an event is telemetry and may be dropped (D8),
|
|
216265
|
+
* and a dropped forget leaves a feeder respawning against a stream that
|
|
216266
|
+
* does not exist.
|
|
216267
|
+
*/
|
|
216268
|
+
forgetDeviceHardware: require_sleep.method(zod.z.object({ deviceId: zod.z.number().int().nonnegative() }), zod.z.object({
|
|
216269
|
+
derivedStreamsDeleted: zod.z.array(zod.z.string()).readonly(),
|
|
216270
|
+
assignmentsPurged: zod.z.boolean(),
|
|
216271
|
+
probeSnapshotsDropped: zod.z.number().int().nonnegative(),
|
|
216272
|
+
rtspTokenRowsDeleted: zod.z.number().int().nonnegative()
|
|
216273
|
+
}), {
|
|
216274
|
+
kind: "mutation",
|
|
216275
|
+
auth: "admin"
|
|
216276
|
+
}),
|
|
216277
|
+
/**
|
|
215490
216278
|
* Render a short GIF or MP4 from the broker's PRE-BUFFER around an instant.
|
|
215491
216279
|
*
|
|
215492
216280
|
* The pre-buffer is the only source that already holds the seconds BEFORE
|
|
@@ -241376,6 +242164,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
241376
242164
|
addonId: null,
|
|
241377
242165
|
access: "create"
|
|
241378
242166
|
},
|
|
242167
|
+
"backup.cancel": {
|
|
242168
|
+
capName: "backup",
|
|
242169
|
+
capScope: "system",
|
|
242170
|
+
addonId: null,
|
|
242171
|
+
access: "create"
|
|
242172
|
+
},
|
|
241379
242173
|
"backup.delete": {
|
|
241380
242174
|
capName: "backup",
|
|
241381
242175
|
capScope: "system",
|
|
@@ -241418,6 +242212,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
241418
242212
|
addonId: null,
|
|
241419
242213
|
access: "view"
|
|
241420
242214
|
},
|
|
242215
|
+
"backup.listRuns": {
|
|
242216
|
+
capName: "backup",
|
|
242217
|
+
capScope: "system",
|
|
242218
|
+
addonId: null,
|
|
242219
|
+
access: "view"
|
|
242220
|
+
},
|
|
241421
242221
|
"backup.listSchedules": {
|
|
241422
242222
|
capName: "backup",
|
|
241423
242223
|
capScope: "system",
|
|
@@ -245984,6 +246784,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
245984
246784
|
addonId: null,
|
|
245985
246785
|
access: "create"
|
|
245986
246786
|
},
|
|
246787
|
+
"streamBroker.forgetDeviceHardware": {
|
|
246788
|
+
capName: "stream-broker",
|
|
246789
|
+
capScope: "system",
|
|
246790
|
+
addonId: null,
|
|
246791
|
+
access: "delete"
|
|
246792
|
+
},
|
|
245987
246793
|
"streamBroker.getAllRtspEntries": {
|
|
245988
246794
|
capName: "stream-broker",
|
|
245989
246795
|
capScope: "system",
|
|
@@ -248700,6 +249506,11 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
248700
249506
|
form: "single",
|
|
248701
249507
|
optional: false
|
|
248702
249508
|
}],
|
|
249509
|
+
"streamBroker.forgetDeviceHardware": [{
|
|
249510
|
+
name: "deviceId",
|
|
249511
|
+
form: "single",
|
|
249512
|
+
optional: false
|
|
249513
|
+
}],
|
|
248703
249514
|
"streamBroker.getDeviceAudioMute": [{
|
|
248704
249515
|
name: "deviceId",
|
|
248705
249516
|
form: "single",
|
|
@@ -249071,6 +249882,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
249071
249882
|
"recordingExport.listExports",
|
|
249072
249883
|
"streamBroker.acquireEgressTranscode",
|
|
249073
249884
|
"streamBroker.assignProfile",
|
|
249885
|
+
"streamBroker.forgetDeviceHardware",
|
|
249074
249886
|
"streamBroker.getDeviceAudioMute",
|
|
249075
249887
|
"streamBroker.getStreamWithCodec",
|
|
249076
249888
|
"streamBroker.produceEventMedia",
|
|
@@ -249569,6 +250381,8 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
249569
250381
|
backup: {
|
|
249570
250382
|
listDestinations: (input) => dispatch("backup", "listDestinations", "query", input),
|
|
249571
250383
|
trigger: (input) => dispatch("backup", "trigger", "mutation", input),
|
|
250384
|
+
listRuns: (input) => dispatch("backup", "listRuns", "query", input),
|
|
250385
|
+
cancel: (input) => dispatch("backup", "cancel", "mutation", input),
|
|
249572
250386
|
list: (input) => dispatch("backup", "list", "query", input),
|
|
249573
250387
|
listLocations: (input) => dispatch("backup", "listLocations", "query", input),
|
|
249574
250388
|
getEntries: (input) => dispatch("backup", "getEntries", "query", input),
|
|
@@ -252848,6 +253662,10 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
252848
253662
|
exports.BacklightModeSchema = BacklightModeSchema;
|
|
252849
253663
|
exports.BackupDestinationInfoSchema = BackupDestinationInfoSchema;
|
|
252850
253664
|
exports.BackupEntrySchema = BackupEntrySchema;
|
|
253665
|
+
exports.BackupRunPhaseSchema = BackupRunPhaseSchema;
|
|
253666
|
+
exports.BackupRunSchema = BackupRunSchema;
|
|
253667
|
+
exports.BackupRunStateSchema = BackupRunStateSchema;
|
|
253668
|
+
exports.BackupTriggerResultSchema = BackupTriggerResultSchema;
|
|
252851
253669
|
exports.BaseAddon = require_sleep.BaseAddon;
|
|
252852
253670
|
exports.BaseDevice = BaseDevice;
|
|
252853
253671
|
exports.BaseDeviceProvider = BaseDeviceProvider;
|
|
@@ -387819,6 +388637,16 @@ var require_main2 = __commonJS({
|
|
|
387819
388637
|
installSource: resolvedSource
|
|
387820
388638
|
});
|
|
387821
388639
|
await installer.ensureRequiredPackages(system_1.AddonInstaller.AGENT_PACKAGES);
|
|
388640
|
+
if (typeof installer.ensureAddonRuntimeDeps === "function") {
|
|
388641
|
+
try {
|
|
388642
|
+
const depsResult = await installer.ensureAddonRuntimeDeps();
|
|
388643
|
+
if (depsResult.linked.length > 0 || depsResult.reinstalled.length > 0 || depsResult.failed.length > 0) {
|
|
388644
|
+
console.log(`[Agent] Addon runtime deps ensured \u2014 linked: [${depsResult.linked.join(", ")}], reinstalled: [${depsResult.reinstalled.join(", ")}], failed: [${depsResult.failed.join(", ")}] (${depsResult.checked} checked)`);
|
|
388645
|
+
}
|
|
388646
|
+
} catch (err) {
|
|
388647
|
+
console.warn(`[Agent] ensureAddonRuntimeDeps failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
388648
|
+
}
|
|
388649
|
+
}
|
|
387822
388650
|
console.log(`[Agent] Addon packages ready in ${config.addonsDir}`);
|
|
387823
388651
|
let broker = (0, system_1.createBroker)({
|
|
387824
388652
|
nodeID: config.nodeId,
|
|
@@ -427674,6 +428502,18 @@ var require_launcher = __commonJS({
|
|
|
427674
428502
|
console.warn(`[launcher] first-boot addon plan failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
427675
428503
|
}
|
|
427676
428504
|
await installer.ensureRequiredPackages(bootstrapRequired);
|
|
428505
|
+
if (typeof installer.ensureAddonRuntimeDeps === "function") {
|
|
428506
|
+
try {
|
|
428507
|
+
const depsResult = await installer.ensureAddonRuntimeDeps();
|
|
428508
|
+
if (depsResult.linked.length > 0 || depsResult.reinstalled.length > 0 || depsResult.failed.length > 0) {
|
|
428509
|
+
console.log(`[launcher] Addon runtime deps ensured \u2014 linked: [${depsResult.linked.join(", ")}], reinstalled: [${depsResult.reinstalled.join(", ")}], failed: [${depsResult.failed.join(", ")}] (${depsResult.checked} checked)`);
|
|
428510
|
+
}
|
|
428511
|
+
} catch (err) {
|
|
428512
|
+
console.warn(`[launcher] ensureAddonRuntimeDeps failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
428513
|
+
}
|
|
428514
|
+
} else {
|
|
428515
|
+
console.warn("[launcher] ensureAddonRuntimeDeps unavailable \u2014 skipping addon dep repair");
|
|
428516
|
+
}
|
|
427677
428517
|
if (typeof installer.reconcileManifest === "function") {
|
|
427678
428518
|
const reconciled = installer.reconcileManifest();
|
|
427679
428519
|
if (reconciled > 0) {
|