camstack 1.2.82 → 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_C0IXtI_E = __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_C0IXtI_E = __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_C0IXtI_E = __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_C0IXtI_E = __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
|
|
@@ -37159,7 +37281,20 @@ var require_dist_C0IXtI_E = __commonJS({
|
|
|
37159
37281
|
projection: TrackProjectionSchema.optional(),
|
|
37160
37282
|
/** Include stationary-promoted rows (parked objects). Default false: the
|
|
37161
37283
|
* feed lists passages; parking records live on the stationary registry. */
|
|
37162
|
-
includeStationary: zod.z.boolean().optional()
|
|
37284
|
+
includeStationary: zod.z.boolean().optional(),
|
|
37285
|
+
/**
|
|
37286
|
+
* Restrict to these track classes. ABSENT or EMPTY means no filter.
|
|
37287
|
+
*
|
|
37288
|
+
* The same filter `listTracks` takes, because the timeline's class chips must
|
|
37289
|
+
* mean the same thing whether the scope is one camera or twelve. Until this
|
|
37290
|
+
* existed the scoped feed downloaded a page and narrowed it on the phone
|
|
37291
|
+
* while the single-camera path narrowed the read — one filter, two costs.
|
|
37292
|
+
*
|
|
37293
|
+
* A SUPERSET prefilter on `classes[]`, like its single-camera twin: rows
|
|
37294
|
+
* whose class list is unreadable are kept, and the client's rule stays the
|
|
37295
|
+
* exact one.
|
|
37296
|
+
*/
|
|
37297
|
+
classes: zod.z.array(zod.z.string()).optional()
|
|
37163
37298
|
});
|
|
37164
37299
|
var RecentTracksPageSchema = zod.z.object({
|
|
37165
37300
|
/** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
|
|
@@ -42290,8 +42425,22 @@ var require_dist_C0IXtI_E = __commonJS({
|
|
|
42290
42425
|
durability: "session"
|
|
42291
42426
|
};
|
|
42292
42427
|
var BatteryStatusSchema = zod.z.object({
|
|
42293
|
-
/**
|
|
42294
|
-
|
|
42428
|
+
/**
|
|
42429
|
+
* 0..100 inclusive, firmware-reported. **`null` means NOT YET KNOWN** — the
|
|
42430
|
+
* provider has registered the capability but no reading has landed.
|
|
42431
|
+
*
|
|
42432
|
+
* It is nullable because it was not, and the only value a provider could
|
|
42433
|
+
* seed with was `0`. A battery camera behind an NVR therefore announced
|
|
42434
|
+
* itself at 0% on every start and corrected itself a moment later, which is
|
|
42435
|
+
* indistinguishable from a real flat battery: it fires the low-battery alert
|
|
42436
|
+
* every time the hub restarts. Unknown is not empty (D315), and on a battery
|
|
42437
|
+
* reading the difference is an alarm.
|
|
42438
|
+
*
|
|
42439
|
+
* `vacuum-control` and `lawn-mower-control` already model it this way.
|
|
42440
|
+
* Consumers must SKIP a null rather than coerce it — `battery-band` already
|
|
42441
|
+
* declines to band a non-finite reading, which is the correct shape.
|
|
42442
|
+
*/
|
|
42443
|
+
percentage: zod.z.number().min(0).max(100).nullable(),
|
|
42295
42444
|
/**
|
|
42296
42445
|
* Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
|
|
42297
42446
|
* Reolink-specific for the Solar Panel 2 accessory (will become
|
|
@@ -50087,7 +50236,7 @@ var require_dist_C0IXtI_E = __commonJS({
|
|
|
50087
50236
|
}
|
|
50088
50237
|
function resolveContainerPrimaryChild(children, overrideEntityId) {
|
|
50089
50238
|
if (overrideEntityId !== void 0 && overrideEntityId !== null) {
|
|
50090
|
-
const picked = children.find((c) => c.entityId === overrideEntityId);
|
|
50239
|
+
const picked = children.find((c) => c.stableId === overrideEntityId) ?? children.find((c) => c.entityId !== void 0 && c.entityId === overrideEntityId);
|
|
50091
50240
|
if (picked !== void 0) return picked;
|
|
50092
50241
|
}
|
|
50093
50242
|
return [...children].toSorted((a, b) => rank(a.type) - rank(b.type))[0] ?? null;
|
|
@@ -51105,6 +51254,12 @@ var require_dist_C0IXtI_E = __commonJS({
|
|
|
51105
51254
|
addonId: null,
|
|
51106
51255
|
access: "create"
|
|
51107
51256
|
},
|
|
51257
|
+
"backup.cancel": {
|
|
51258
|
+
capName: "backup",
|
|
51259
|
+
capScope: "system",
|
|
51260
|
+
addonId: null,
|
|
51261
|
+
access: "create"
|
|
51262
|
+
},
|
|
51108
51263
|
"backup.delete": {
|
|
51109
51264
|
capName: "backup",
|
|
51110
51265
|
capScope: "system",
|
|
@@ -51147,6 +51302,12 @@ var require_dist_C0IXtI_E = __commonJS({
|
|
|
51147
51302
|
addonId: null,
|
|
51148
51303
|
access: "view"
|
|
51149
51304
|
},
|
|
51305
|
+
"backup.listRuns": {
|
|
51306
|
+
capName: "backup",
|
|
51307
|
+
capScope: "system",
|
|
51308
|
+
addonId: null,
|
|
51309
|
+
access: "view"
|
|
51310
|
+
},
|
|
51150
51311
|
"backup.listSchedules": {
|
|
51151
51312
|
capName: "backup",
|
|
51152
51313
|
capScope: "system",
|
|
@@ -55713,6 +55874,12 @@ var require_dist_C0IXtI_E = __commonJS({
|
|
|
55713
55874
|
addonId: null,
|
|
55714
55875
|
access: "create"
|
|
55715
55876
|
},
|
|
55877
|
+
"streamBroker.forgetDeviceHardware": {
|
|
55878
|
+
capName: "stream-broker",
|
|
55879
|
+
capScope: "system",
|
|
55880
|
+
addonId: null,
|
|
55881
|
+
access: "delete"
|
|
55882
|
+
},
|
|
55716
55883
|
"streamBroker.getAllRtspEntries": {
|
|
55717
55884
|
capName: "stream-broker",
|
|
55718
55885
|
capScope: "system",
|
|
@@ -58171,6 +58338,11 @@ var require_dist_C0IXtI_E = __commonJS({
|
|
|
58171
58338
|
form: "single",
|
|
58172
58339
|
optional: false
|
|
58173
58340
|
}],
|
|
58341
|
+
"streamBroker.forgetDeviceHardware": [{
|
|
58342
|
+
name: "deviceId",
|
|
58343
|
+
form: "single",
|
|
58344
|
+
optional: false
|
|
58345
|
+
}],
|
|
58174
58346
|
"streamBroker.getDeviceAudioMute": [{
|
|
58175
58347
|
name: "deviceId",
|
|
58176
58348
|
form: "single",
|
|
@@ -59827,7 +59999,7 @@ var require_alerts_addon = __commonJS({
|
|
|
59827
59999
|
[Symbol.toStringTag]: { value: "Module" }
|
|
59828
60000
|
});
|
|
59829
60001
|
require_chunk_Cek0wNdY();
|
|
59830
|
-
var require_dist10 =
|
|
60002
|
+
var require_dist10 = require_dist_TEwQZL3g();
|
|
59831
60003
|
function selectExpired(alerts, cutoffMs) {
|
|
59832
60004
|
return alerts.filter((a) => a.createdAt < cutoffMs).sort((a, b) => a.createdAt - b.createdAt).map((a) => a.id);
|
|
59833
60005
|
}
|
|
@@ -60646,7 +60818,7 @@ var require_console_logging = __commonJS({
|
|
|
60646
60818
|
[Symbol.toStringTag]: { value: "Module" }
|
|
60647
60819
|
});
|
|
60648
60820
|
require_chunk_Cek0wNdY();
|
|
60649
|
-
var require_dist10 =
|
|
60821
|
+
var require_dist10 = require_dist_TEwQZL3g();
|
|
60650
60822
|
var require_formatter = require_formatter_DqAKDlvN();
|
|
60651
60823
|
var LEVEL_RANK = {
|
|
60652
60824
|
debug: 0,
|
|
@@ -60740,7 +60912,7 @@ var require_core_blocks_addon = __commonJS({
|
|
|
60740
60912
|
"use strict";
|
|
60741
60913
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
60742
60914
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
60743
|
-
var require_dist10 =
|
|
60915
|
+
var require_dist10 = require_dist_TEwQZL3g();
|
|
60744
60916
|
var node_crypto = __require("crypto");
|
|
60745
60917
|
var node_fs_promises = __require("fs/promises");
|
|
60746
60918
|
node_fs_promises = require_chunk.__toESM(node_fs_promises);
|
|
@@ -61637,11 +61809,11 @@ var require_core_blocks = __commonJS({
|
|
|
61637
61809
|
}
|
|
61638
61810
|
});
|
|
61639
61811
|
|
|
61640
|
-
// ../system/dist/retired-settings-keys-
|
|
61641
|
-
var
|
|
61642
|
-
"../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) {
|
|
61643
61815
|
"use strict";
|
|
61644
|
-
var require_dist10 =
|
|
61816
|
+
var require_dist10 = require_dist_TEwQZL3g();
|
|
61645
61817
|
function settingsStoreIsAuthoritativeHere(env) {
|
|
61646
61818
|
const raw = (env["CAMSTACK_ROLE"] ?? "").trim().toLowerCase();
|
|
61647
61819
|
return raw === "" || raw === "hub";
|
|
@@ -63855,8 +64027,8 @@ var require_device_manager_addon = __commonJS({
|
|
|
63855
64027
|
[Symbol.toStringTag]: { value: "Module" }
|
|
63856
64028
|
});
|
|
63857
64029
|
require_chunk_Cek0wNdY();
|
|
63858
|
-
var require_dist10 =
|
|
63859
|
-
var require_retired_settings_keys =
|
|
64030
|
+
var require_dist10 = require_dist_TEwQZL3g();
|
|
64031
|
+
var require_retired_settings_keys = require_retired_settings_keys_DauPtbFR();
|
|
63860
64032
|
var node_crypto = __require("crypto");
|
|
63861
64033
|
var _camstack_types_node = require_node();
|
|
63862
64034
|
var JOB_HISTORY = 20;
|
|
@@ -65498,9 +65670,9 @@ var require_device_manager_addon = __commonJS({
|
|
|
65498
65670
|
nextVisited.add(id);
|
|
65499
65671
|
const primary = require_dist10.resolveContainerPrimaryChild((byParent.get(id) ?? []).map((c) => ({
|
|
65500
65672
|
id: c.id,
|
|
65501
|
-
|
|
65673
|
+
stableId: c.stableId,
|
|
65502
65674
|
type: c.type
|
|
65503
|
-
})),
|
|
65675
|
+
})), byId.get(id)?.primaryChildEntityId);
|
|
65504
65676
|
if (primary !== null) expandContainer(primary.id, byId, byParent, nextVisited, out);
|
|
65505
65677
|
}
|
|
65506
65678
|
function resolveLinkedDeviceIds(params) {
|
|
@@ -65519,7 +65691,13 @@ var require_device_manager_addon = __commonJS({
|
|
|
65519
65691
|
if (config.mode === "auto") {
|
|
65520
65692
|
if (selfLocation !== null && selfLocation.length > 0) for (const c of candidates) {
|
|
65521
65693
|
if (c.type === require_dist10.DeviceType.Container) continue;
|
|
65522
|
-
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);
|
|
65523
65701
|
}
|
|
65524
65702
|
} else for (const id of config.manualIds) if (byId.has(id)) expand(id);
|
|
65525
65703
|
ids.delete(selfId);
|
|
@@ -66382,6 +66560,16 @@ var require_device_manager_addon = __commonJS({
|
|
|
66382
66560
|
const down = [...await applyAll(deps, sourceId, false), ...await applyAll(deps, targetId, false)];
|
|
66383
66561
|
const sourceStillLive = down.filter((r) => r.deviceId === sourceId && r.outcome === "unreachable").map((r) => r.switchId);
|
|
66384
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
|
+
}
|
|
66385
66573
|
const up = await applyAll(deps, sourceId, true);
|
|
66386
66574
|
await deps.respawnRunners([sourceId, targetId]);
|
|
66387
66575
|
deps.log("camera migrated", {
|
|
@@ -66398,6 +66586,49 @@ var require_device_manager_addon = __commonJS({
|
|
|
66398
66586
|
swapped: true
|
|
66399
66587
|
};
|
|
66400
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
|
+
}
|
|
66401
66632
|
async function stampIntegrationId(metaStore, ctx, deviceId, integrationId) {
|
|
66402
66633
|
await metaStore.withMetaWriteLock(async () => {
|
|
66403
66634
|
if (!await metaStore.resolvePersistedById(deviceId)) throw new Error(`[device-manager] stampIntegrationId: unknown device id=${deviceId}`);
|
|
@@ -66457,13 +66688,42 @@ var require_device_manager_addon = __commonJS({
|
|
|
66457
66688
|
swapIds: async (a, b) => {
|
|
66458
66689
|
await pctx.metaStore.rows.swapIds(a, b, tempId);
|
|
66459
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
|
+
},
|
|
66460
66710
|
respawnRunners: async (deviceIds) => {
|
|
66461
66711
|
const owners = /* @__PURE__ */ new Set();
|
|
66462
66712
|
for (const deviceId of deviceIds) {
|
|
66463
66713
|
const addonId = pctx.metaStore.idToAddonId.get(deviceId);
|
|
66464
66714
|
if (addonId !== void 0) owners.add(addonId);
|
|
66465
66715
|
}
|
|
66466
|
-
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
|
+
}
|
|
66467
66727
|
},
|
|
66468
66728
|
log: (message, meta) => {
|
|
66469
66729
|
ctx.logger.info(message, {
|
|
@@ -68896,7 +69156,7 @@ var require_hub_forwarder = __commonJS({
|
|
|
68896
69156
|
[Symbol.toStringTag]: { value: "Module" }
|
|
68897
69157
|
});
|
|
68898
69158
|
require_chunk_Cek0wNdY();
|
|
68899
|
-
var require_dist10 =
|
|
69159
|
+
var require_dist10 = require_dist_TEwQZL3g();
|
|
68900
69160
|
var require_formatter = require_formatter_DqAKDlvN();
|
|
68901
69161
|
var DEFAULT_OUTBOUND_BUFFER_SIZE = 500;
|
|
68902
69162
|
var HubForwarderDestination = class {
|
|
@@ -69033,7 +69293,7 @@ var require_liveness_monitor_addon = __commonJS({
|
|
|
69033
69293
|
"use strict";
|
|
69034
69294
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
69035
69295
|
require_chunk_Cek0wNdY();
|
|
69036
|
-
var require_dist10 =
|
|
69296
|
+
var require_dist10 = require_dist_TEwQZL3g();
|
|
69037
69297
|
var NO_DEVICES = "liveness:no-devices";
|
|
69038
69298
|
var ALL_OFFLINE = "liveness:all-devices-offline";
|
|
69039
69299
|
var NO_FOOTAGE_PREFIX = "liveness:no-footage:";
|
|
@@ -69223,7 +69483,7 @@ var require_local_auth_addon = __commonJS({
|
|
|
69223
69483
|
[Symbol.toStringTag]: { value: "Module" }
|
|
69224
69484
|
});
|
|
69225
69485
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
69226
|
-
var require_dist10 =
|
|
69486
|
+
var require_dist10 = require_dist_TEwQZL3g();
|
|
69227
69487
|
var node_crypto = __require("crypto");
|
|
69228
69488
|
node_crypto = require_chunk.__toESM(node_crypto);
|
|
69229
69489
|
var crypto$1 = __require("crypto");
|
|
@@ -77036,7 +77296,7 @@ var require_loki_logging = __commonJS({
|
|
|
77036
77296
|
[Symbol.toStringTag]: { value: "Module" }
|
|
77037
77297
|
});
|
|
77038
77298
|
require_chunk_Cek0wNdY();
|
|
77039
|
-
var require_dist10 =
|
|
77299
|
+
var require_dist10 = require_dist_TEwQZL3g();
|
|
77040
77300
|
function sanitizeLabelName(raw) {
|
|
77041
77301
|
const replaced = raw.replaceAll(/[^a-zA-Z0-9_]/g, "_");
|
|
77042
77302
|
return /^[a-zA-Z_]/.test(replaced) ? replaced : `_${replaced}`;
|
|
@@ -77601,7 +77861,7 @@ var require_native_metrics_addon = __commonJS({
|
|
|
77601
77861
|
[Symbol.toStringTag]: { value: "Module" }
|
|
77602
77862
|
});
|
|
77603
77863
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
77604
|
-
var require_dist10 =
|
|
77864
|
+
var require_dist10 = require_dist_TEwQZL3g();
|
|
77605
77865
|
var node_fs_promises = __require("fs/promises");
|
|
77606
77866
|
var node_child_process = __require("child_process");
|
|
77607
77867
|
var node_util = __require("util");
|
|
@@ -80185,7 +80445,7 @@ var require_filesystem_storage_addon = __commonJS({
|
|
|
80185
80445
|
[Symbol.toStringTag]: { value: "Module" }
|
|
80186
80446
|
});
|
|
80187
80447
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
80188
|
-
var require_dist10 =
|
|
80448
|
+
var require_dist10 = require_dist_TEwQZL3g();
|
|
80189
80449
|
var node_crypto = __require("crypto");
|
|
80190
80450
|
var node_fs_promises = __require("fs/promises");
|
|
80191
80451
|
var node_path = __require("path");
|
|
@@ -81301,8 +81561,8 @@ var require_sqlite_settings_addon = __commonJS({
|
|
|
81301
81561
|
[Symbol.toStringTag]: { value: "Module" }
|
|
81302
81562
|
});
|
|
81303
81563
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
81304
|
-
var require_dist10 =
|
|
81305
|
-
var require_retired_settings_keys =
|
|
81564
|
+
var require_dist10 = require_dist_TEwQZL3g();
|
|
81565
|
+
var require_retired_settings_keys = require_retired_settings_keys_DauPtbFR();
|
|
81306
81566
|
var node_crypto = __require("crypto");
|
|
81307
81567
|
var node_fs = __require("fs");
|
|
81308
81568
|
var node_module = __require("module");
|
|
@@ -83792,7 +84052,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
83792
84052
|
[Symbol.toStringTag]: { value: "Module" }
|
|
83793
84053
|
});
|
|
83794
84054
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
83795
|
-
var require_dist10 =
|
|
84055
|
+
var require_dist10 = require_dist_TEwQZL3g();
|
|
83796
84056
|
var require_hub_cap_forward = require_hub_cap_forward_DmHNjbB0();
|
|
83797
84057
|
var zod = require_zod();
|
|
83798
84058
|
var node_crypto = __require("crypto");
|
|
@@ -86743,7 +87003,7 @@ var require_system_config_addon = __commonJS({
|
|
|
86743
87003
|
[Symbol.toStringTag]: { value: "Module" }
|
|
86744
87004
|
});
|
|
86745
87005
|
require_chunk_Cek0wNdY();
|
|
86746
|
-
var require_dist10 =
|
|
87006
|
+
var require_dist10 = require_dist_TEwQZL3g();
|
|
86747
87007
|
var SECTION_TITLES = {
|
|
86748
87008
|
server: "Server",
|
|
86749
87009
|
auth: "Authentication"
|
|
@@ -104804,7 +105064,7 @@ var require_winston_logging = __commonJS({
|
|
|
104804
105064
|
[Symbol.toStringTag]: { value: "Module" }
|
|
104805
105065
|
});
|
|
104806
105066
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
104807
|
-
var require_dist10 =
|
|
105067
|
+
var require_dist10 = require_dist_TEwQZL3g();
|
|
104808
105068
|
var require_formatter = require_formatter_DqAKDlvN();
|
|
104809
105069
|
var node_path = __require("path");
|
|
104810
105070
|
node_path = require_chunk.__toESM(node_path);
|
|
@@ -106747,9 +107007,9 @@ var require_event_category_BaEgqJNv = __commonJS({
|
|
|
106747
107007
|
}
|
|
106748
107008
|
});
|
|
106749
107009
|
|
|
106750
|
-
// ../types/dist/sleep-
|
|
106751
|
-
var
|
|
106752
|
-
"../types/dist/sleep-
|
|
107010
|
+
// ../types/dist/sleep-BDmIj1HV.js
|
|
107011
|
+
var require_sleep_BDmIj1HV = __commonJS({
|
|
107012
|
+
"../types/dist/sleep-BDmIj1HV.js"(exports) {
|
|
106753
107013
|
"use strict";
|
|
106754
107014
|
var require_event_category = require_event_category_BaEgqJNv();
|
|
106755
107015
|
var zod = require_zod();
|
|
@@ -109757,6 +110017,7 @@ var require_sleep_BwGJ_wL = __commonJS({
|
|
|
109757
110017
|
retractCameraStream: (input) => dispatchSystem("streamBroker", "retractCameraStream", "mutation", input),
|
|
109758
110018
|
assignProfile: (input) => dispatchSystem("streamBroker", "assignProfile", "mutation", input),
|
|
109759
110019
|
unassignProfile: (input) => dispatchSystem("streamBroker", "unassignProfile", "mutation", input),
|
|
110020
|
+
forgetDeviceHardware: (input) => dispatchSystem("streamBroker", "forgetDeviceHardware", "mutation", input),
|
|
109760
110021
|
renderPreBufferClip: (input) => dispatchSystem("streamBroker", "renderPreBufferClip", "mutation", input),
|
|
109761
110022
|
produceEventMedia: (input) => dispatchSystem("streamBroker", "produceEventMedia", "mutation", input),
|
|
109762
110023
|
restartProfile: (input) => dispatchSystem("streamBroker", "restartProfile", "mutation", input),
|
|
@@ -110421,7 +110682,7 @@ var require_addon = __commonJS({
|
|
|
110421
110682
|
"use strict";
|
|
110422
110683
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
110423
110684
|
var require_event_category = require_event_category_BaEgqJNv();
|
|
110424
|
-
var require_sleep =
|
|
110685
|
+
var require_sleep = require_sleep_BDmIj1HV();
|
|
110425
110686
|
var require_err_msg = require_err_msg_COpsHMw2();
|
|
110426
110687
|
var CAP_INPUT_DEFAULTS = Object.freeze({
|
|
110427
110688
|
"addons": { "getLogs": { "limit": 100 } },
|
|
@@ -117304,12 +117565,12 @@ var require_dist2 = __commonJS({
|
|
|
117304
117565
|
}
|
|
117305
117566
|
});
|
|
117306
117567
|
|
|
117307
|
-
// ../system/dist/manifest-system-deps-
|
|
117308
|
-
var
|
|
117309
|
-
"../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) {
|
|
117310
117571
|
"use strict";
|
|
117311
117572
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
117312
|
-
|
|
117573
|
+
require_dist_TEwQZL3g();
|
|
117313
117574
|
require_hub_cap_forward_DmHNjbB0();
|
|
117314
117575
|
var node_crypto = __require("crypto");
|
|
117315
117576
|
node_crypto = require_chunk.__toESM(node_crypto);
|
|
@@ -129376,7 +129637,7 @@ var require_dist3 = __commonJS({
|
|
|
129376
129637
|
"use strict";
|
|
129377
129638
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
129378
129639
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
129379
|
-
var require_dist10 =
|
|
129640
|
+
var require_dist10 = require_dist_TEwQZL3g();
|
|
129380
129641
|
var require_builtins_alerts_alerts_addon = require_alerts_addon();
|
|
129381
129642
|
require_alerts();
|
|
129382
129643
|
var require_formatter = require_formatter_DqAKDlvN();
|
|
@@ -129403,7 +129664,7 @@ var require_dist3 = __commonJS({
|
|
|
129403
129664
|
var require_builtins_winston_logging_index = require_winston_logging();
|
|
129404
129665
|
var require_file_data_plane = require_file_data_plane_DO8KbxCe();
|
|
129405
129666
|
var require_tls$1 = require_tls_BxQlomxd();
|
|
129406
|
-
var require_manifest_system_deps =
|
|
129667
|
+
var require_manifest_system_deps = require_manifest_system_deps_BVIr3MYJ();
|
|
129407
129668
|
var require_resource_monitor = require_resource_monitor_CdnzxBLP();
|
|
129408
129669
|
var require_custom_action_registry = require_custom_action_registry_jY0NOZK8();
|
|
129409
129670
|
var zod = require_zod();
|
|
@@ -132441,7 +132702,265 @@ var require_dist3 = __commonJS({
|
|
|
132441
132702
|
};
|
|
132442
132703
|
}
|
|
132443
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
|
+
}
|
|
132444
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
|
+
}
|
|
132445
132964
|
function parseInstallSource(value) {
|
|
132446
132965
|
switch (value) {
|
|
132447
132966
|
case "npm":
|
|
@@ -132503,6 +133022,8 @@ var require_dist3 = __commonJS({
|
|
|
132503
133022
|
installSource;
|
|
132504
133023
|
logger;
|
|
132505
133024
|
isPackageResolvable;
|
|
133025
|
+
/** Test seam — production resolves via `CAMSTACK_FRAMEWORK_DIR`. */
|
|
133026
|
+
closureNodeModulesDir;
|
|
132506
133027
|
/**
|
|
132507
133028
|
* Central manifest of installed addons. Tracks version + source +
|
|
132508
133029
|
* timestamps + last-backup pointer per package, written atomically
|
|
@@ -132524,6 +133045,7 @@ var require_dist3 = __commonJS({
|
|
|
132524
133045
|
this.logger = logger;
|
|
132525
133046
|
this.manifest = new AddonManifest(config.addonsDir);
|
|
132526
133047
|
this.isPackageResolvable = config.isPackageResolvable;
|
|
133048
|
+
this.closureNodeModulesDir = config.closureNodeModulesDir;
|
|
132527
133049
|
if (config.installSource) this.installSource = config.installSource;
|
|
132528
133050
|
else this.installSource = "npm";
|
|
132529
133051
|
}
|
|
@@ -132711,6 +133233,140 @@ var require_dist3 = __commonJS({
|
|
|
132711
133233
|
return changes;
|
|
132712
133234
|
}
|
|
132713
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
|
+
/**
|
|
132714
133370
|
* Install a single addon — on-demand installer used by AddonPackageService
|
|
132715
133371
|
* (admin UI "Install addon" / "Reinstall" buttons).
|
|
132716
133372
|
*
|
|
@@ -132818,6 +133474,7 @@ var require_dist3 = __commonJS({
|
|
|
132818
133474
|
logger: this.logger,
|
|
132819
133475
|
bundledSourceDir: sourceDir
|
|
132820
133476
|
});
|
|
133477
|
+
this.dedupeTreeAgainstClosure(targetDir, packageName);
|
|
132821
133478
|
this.logger.info(`${packageName} \u2014 copied from ${sourceDir}`);
|
|
132822
133479
|
return {
|
|
132823
133480
|
name: pkgData.name,
|
|
@@ -133122,6 +133779,40 @@ var require_dist3 = __commonJS({
|
|
|
133122
133779
|
logger: this.logger
|
|
133123
133780
|
});
|
|
133124
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
|
+
}
|
|
133125
133816
|
/** Install addon from a tgz file (uploaded or downloaded) */
|
|
133126
133817
|
async installFromTgz(tgzPath) {
|
|
133127
133818
|
const stagingRoot = node_path.join(this.addonsDir, ".staging");
|
|
@@ -133147,6 +133838,7 @@ var require_dist3 = __commonJS({
|
|
|
133147
133838
|
const targetDir = node_path.join(this.addonsDir, pkgView.name);
|
|
133148
133839
|
await this.installRuntimeDependencies(pkgDir, pkgView.name);
|
|
133149
133840
|
await this.installNativeDependencies(pkgDir, pkgView.name);
|
|
133841
|
+
this.dedupeTreeAgainstClosure(pkgDir, pkgView.name);
|
|
133150
133842
|
await this.evictInstallDir(targetDir);
|
|
133151
133843
|
ensureDir(node_path.dirname(targetDir));
|
|
133152
133844
|
await node_fs.promises.rename(pkgDir, targetDir);
|
|
@@ -133279,6 +133971,7 @@ var require_dist3 = __commonJS({
|
|
|
133279
133971
|
if (!node_fs.existsSync(addonDir)) throw new Error(`Cannot update ${packageName}: install dir ${addonDir} missing`);
|
|
133280
133972
|
await this.installRuntimeDependencies(stagedPath, packageName);
|
|
133281
133973
|
await this.installNativeDependencies(stagedPath, packageName);
|
|
133974
|
+
this.dedupeTreeAgainstClosure(stagedPath, packageName);
|
|
133282
133975
|
const ts2 = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
133283
133976
|
const backupRoot = node_path.join(this.addonsDir, ".backups", packageName);
|
|
133284
133977
|
ensureDir(backupRoot);
|
|
@@ -163494,7 +164187,7 @@ globstar while`, t, d, e, u, m), this.matchOne(t.slice(d), e.slice(u), s)) retur
|
|
|
163494
164187
|
}));
|
|
163495
164188
|
var require_symlink_type2 = /* @__PURE__ */ require_chunk.__commonJSMin(((exports2, module2) => {
|
|
163496
164189
|
var fs2 = require_graceful_fs2();
|
|
163497
|
-
function
|
|
164190
|
+
function symlinkType2(srcpath, type2, callback) {
|
|
163498
164191
|
callback = typeof type2 === "function" ? type2 : callback;
|
|
163499
164192
|
type2 = typeof type2 === "function" ? false : type2;
|
|
163500
164193
|
if (type2) return callback(null, type2);
|
|
@@ -163515,7 +164208,7 @@ globstar while`, t, d, e, u, m), this.matchOne(t.slice(d), e.slice(u), s)) retur
|
|
|
163515
164208
|
return stats && stats.isDirectory() ? "dir" : "file";
|
|
163516
164209
|
}
|
|
163517
164210
|
module2.exports = {
|
|
163518
|
-
symlinkType,
|
|
164211
|
+
symlinkType: symlinkType2,
|
|
163519
164212
|
symlinkTypeSync
|
|
163520
164213
|
};
|
|
163521
164214
|
}));
|
|
@@ -163530,7 +164223,7 @@ globstar while`, t, d, e, u, m), this.matchOne(t.slice(d), e.slice(u), s)) retur
|
|
|
163530
164223
|
var symlinkPaths = _symlinkPaths.symlinkPaths;
|
|
163531
164224
|
var symlinkPathsSync = _symlinkPaths.symlinkPathsSync;
|
|
163532
164225
|
var _symlinkType = require_symlink_type2();
|
|
163533
|
-
var
|
|
164226
|
+
var symlinkType2 = _symlinkType.symlinkType;
|
|
163534
164227
|
var symlinkTypeSync = _symlinkType.symlinkTypeSync;
|
|
163535
164228
|
var pathExists = require_path_exists2().pathExists;
|
|
163536
164229
|
function createSymlink(srcpath, dstpath, type2, callback) {
|
|
@@ -163542,7 +164235,7 @@ globstar while`, t, d, e, u, m), this.matchOne(t.slice(d), e.slice(u), s)) retur
|
|
|
163542
164235
|
symlinkPaths(srcpath, dstpath, (err2, relative) => {
|
|
163543
164236
|
if (err2) return callback(err2);
|
|
163544
164237
|
srcpath = relative.toDst;
|
|
163545
|
-
|
|
164238
|
+
symlinkType2(relative.toCwd, type2, (err3, type3) => {
|
|
163546
164239
|
if (err3) return callback(err3);
|
|
163547
164240
|
const dir = path$23.dirname(dstpath);
|
|
163548
164241
|
pathExists(dir, (err4, dirExists) => {
|
|
@@ -210061,7 +210754,7 @@ var require_dist4 = __commonJS({
|
|
|
210061
210754
|
"use strict";
|
|
210062
210755
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
210063
210756
|
var require_event_category = require_event_category_BaEgqJNv();
|
|
210064
|
-
var require_sleep =
|
|
210757
|
+
var require_sleep = require_sleep_BDmIj1HV();
|
|
210065
210758
|
var require_canonical_hash = require_canonical_hash_DNV8S5ET();
|
|
210066
210759
|
var require_enums2 = require_enums();
|
|
210067
210760
|
var require_err_msg = require_err_msg_COpsHMw2();
|
|
@@ -214671,6 +215364,68 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
214671
215364
|
fileCount: zod.z.number(),
|
|
214672
215365
|
present: zod.z.boolean()
|
|
214673
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
|
+
});
|
|
214674
215429
|
var BackupScheduleSchema = zod.z.object({
|
|
214675
215430
|
/** Stable id. Generated by the orchestrator on first upsert if absent. */
|
|
214676
215431
|
id: zod.z.string(),
|
|
@@ -214707,6 +215462,11 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
214707
215462
|
* Trigger a backup. Without `destinations` the orchestrator fans
|
|
214708
215463
|
* out to every destination flagged as enabled in the routing
|
|
214709
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.
|
|
214710
215470
|
*/
|
|
214711
215471
|
trigger: require_sleep.method(zod.z.object({
|
|
214712
215472
|
/** Subset of registered `backup-destination` addon ids to write to. */
|
|
@@ -214720,7 +215480,30 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
214720
215480
|
* retention (manual runs).
|
|
214721
215481
|
*/
|
|
214722
215482
|
retentionCount: zod.z.number().int().min(1).max(1e3).optional()
|
|
214723
|
-
}).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() }), {
|
|
214724
215507
|
kind: "mutation",
|
|
214725
215508
|
auth: "admin"
|
|
214726
215509
|
}),
|
|
@@ -215460,6 +216243,38 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
215460
216243
|
auth: "admin"
|
|
215461
216244
|
}),
|
|
215462
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
|
+
/**
|
|
215463
216278
|
* Render a short GIF or MP4 from the broker's PRE-BUFFER around an instant.
|
|
215464
216279
|
*
|
|
215465
216280
|
* The pre-buffer is the only source that already holds the seconds BEFORE
|
|
@@ -224265,7 +225080,20 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
224265
225080
|
projection: TrackProjectionSchema.optional(),
|
|
224266
225081
|
/** Include stationary-promoted rows (parked objects). Default false: the
|
|
224267
225082
|
* feed lists passages; parking records live on the stationary registry. */
|
|
224268
|
-
includeStationary: zod.z.boolean().optional()
|
|
225083
|
+
includeStationary: zod.z.boolean().optional(),
|
|
225084
|
+
/**
|
|
225085
|
+
* Restrict to these track classes. ABSENT or EMPTY means no filter.
|
|
225086
|
+
*
|
|
225087
|
+
* The same filter `listTracks` takes, because the timeline's class chips must
|
|
225088
|
+
* mean the same thing whether the scope is one camera or twelve. Until this
|
|
225089
|
+
* existed the scoped feed downloaded a page and narrowed it on the phone
|
|
225090
|
+
* while the single-camera path narrowed the read — one filter, two costs.
|
|
225091
|
+
*
|
|
225092
|
+
* A SUPERSET prefilter on `classes[]`, like its single-camera twin: rows
|
|
225093
|
+
* whose class list is unreadable are kept, and the client's rule stays the
|
|
225094
|
+
* exact one.
|
|
225095
|
+
*/
|
|
225096
|
+
classes: zod.z.array(zod.z.string()).optional()
|
|
224269
225097
|
});
|
|
224270
225098
|
var RecentTracksPageSchema = zod.z.object({
|
|
224271
225099
|
/** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
|
|
@@ -229563,8 +230391,22 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
229563
230391
|
durability: "session"
|
|
229564
230392
|
};
|
|
229565
230393
|
var BatteryStatusSchema = zod.z.object({
|
|
229566
|
-
/**
|
|
229567
|
-
|
|
230394
|
+
/**
|
|
230395
|
+
* 0..100 inclusive, firmware-reported. **`null` means NOT YET KNOWN** — the
|
|
230396
|
+
* provider has registered the capability but no reading has landed.
|
|
230397
|
+
*
|
|
230398
|
+
* It is nullable because it was not, and the only value a provider could
|
|
230399
|
+
* seed with was `0`. A battery camera behind an NVR therefore announced
|
|
230400
|
+
* itself at 0% on every start and corrected itself a moment later, which is
|
|
230401
|
+
* indistinguishable from a real flat battery: it fires the low-battery alert
|
|
230402
|
+
* every time the hub restarts. Unknown is not empty (D315), and on a battery
|
|
230403
|
+
* reading the difference is an alarm.
|
|
230404
|
+
*
|
|
230405
|
+
* `vacuum-control` and `lawn-mower-control` already model it this way.
|
|
230406
|
+
* Consumers must SKIP a null rather than coerce it — `battery-band` already
|
|
230407
|
+
* declines to band a non-finite reading, which is the correct shape.
|
|
230408
|
+
*/
|
|
230409
|
+
percentage: zod.z.number().min(0).max(100).nullable(),
|
|
229568
230410
|
/**
|
|
229569
230411
|
* Charging source. `'dc'` covers wall/USB adapters; `'solar'` is
|
|
229570
230412
|
* Reolink-specific for the Solar Panel 2 accessory (will become
|
|
@@ -237456,7 +238298,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
237456
238298
|
}
|
|
237457
238299
|
function resolveContainerPrimaryChild(children, overrideEntityId) {
|
|
237458
238300
|
if (overrideEntityId !== void 0 && overrideEntityId !== null) {
|
|
237459
|
-
const picked = children.find((c) => c.entityId === overrideEntityId);
|
|
238301
|
+
const picked = children.find((c) => c.stableId === overrideEntityId) ?? children.find((c) => c.entityId !== void 0 && c.entityId === overrideEntityId);
|
|
237460
238302
|
if (picked !== void 0) return picked;
|
|
237461
238303
|
}
|
|
237462
238304
|
return [...children].toSorted((a, b) => rank(a.type) - rank(b.type))[0] ?? null;
|
|
@@ -241322,6 +242164,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
241322
242164
|
addonId: null,
|
|
241323
242165
|
access: "create"
|
|
241324
242166
|
},
|
|
242167
|
+
"backup.cancel": {
|
|
242168
|
+
capName: "backup",
|
|
242169
|
+
capScope: "system",
|
|
242170
|
+
addonId: null,
|
|
242171
|
+
access: "create"
|
|
242172
|
+
},
|
|
241325
242173
|
"backup.delete": {
|
|
241326
242174
|
capName: "backup",
|
|
241327
242175
|
capScope: "system",
|
|
@@ -241364,6 +242212,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
241364
242212
|
addonId: null,
|
|
241365
242213
|
access: "view"
|
|
241366
242214
|
},
|
|
242215
|
+
"backup.listRuns": {
|
|
242216
|
+
capName: "backup",
|
|
242217
|
+
capScope: "system",
|
|
242218
|
+
addonId: null,
|
|
242219
|
+
access: "view"
|
|
242220
|
+
},
|
|
241367
242221
|
"backup.listSchedules": {
|
|
241368
242222
|
capName: "backup",
|
|
241369
242223
|
capScope: "system",
|
|
@@ -245930,6 +246784,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
245930
246784
|
addonId: null,
|
|
245931
246785
|
access: "create"
|
|
245932
246786
|
},
|
|
246787
|
+
"streamBroker.forgetDeviceHardware": {
|
|
246788
|
+
capName: "stream-broker",
|
|
246789
|
+
capScope: "system",
|
|
246790
|
+
addonId: null,
|
|
246791
|
+
access: "delete"
|
|
246792
|
+
},
|
|
245933
246793
|
"streamBroker.getAllRtspEntries": {
|
|
245934
246794
|
capName: "stream-broker",
|
|
245935
246795
|
capScope: "system",
|
|
@@ -248646,6 +249506,11 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
248646
249506
|
form: "single",
|
|
248647
249507
|
optional: false
|
|
248648
249508
|
}],
|
|
249509
|
+
"streamBroker.forgetDeviceHardware": [{
|
|
249510
|
+
name: "deviceId",
|
|
249511
|
+
form: "single",
|
|
249512
|
+
optional: false
|
|
249513
|
+
}],
|
|
248649
249514
|
"streamBroker.getDeviceAudioMute": [{
|
|
248650
249515
|
name: "deviceId",
|
|
248651
249516
|
form: "single",
|
|
@@ -249017,6 +249882,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
249017
249882
|
"recordingExport.listExports",
|
|
249018
249883
|
"streamBroker.acquireEgressTranscode",
|
|
249019
249884
|
"streamBroker.assignProfile",
|
|
249885
|
+
"streamBroker.forgetDeviceHardware",
|
|
249020
249886
|
"streamBroker.getDeviceAudioMute",
|
|
249021
249887
|
"streamBroker.getStreamWithCodec",
|
|
249022
249888
|
"streamBroker.produceEventMedia",
|
|
@@ -249515,6 +250381,8 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
249515
250381
|
backup: {
|
|
249516
250382
|
listDestinations: (input) => dispatch("backup", "listDestinations", "query", input),
|
|
249517
250383
|
trigger: (input) => dispatch("backup", "trigger", "mutation", input),
|
|
250384
|
+
listRuns: (input) => dispatch("backup", "listRuns", "query", input),
|
|
250385
|
+
cancel: (input) => dispatch("backup", "cancel", "mutation", input),
|
|
249518
250386
|
list: (input) => dispatch("backup", "list", "query", input),
|
|
249519
250387
|
listLocations: (input) => dispatch("backup", "listLocations", "query", input),
|
|
249520
250388
|
getEntries: (input) => dispatch("backup", "getEntries", "query", input),
|
|
@@ -252794,6 +253662,10 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
252794
253662
|
exports.BacklightModeSchema = BacklightModeSchema;
|
|
252795
253663
|
exports.BackupDestinationInfoSchema = BackupDestinationInfoSchema;
|
|
252796
253664
|
exports.BackupEntrySchema = BackupEntrySchema;
|
|
253665
|
+
exports.BackupRunPhaseSchema = BackupRunPhaseSchema;
|
|
253666
|
+
exports.BackupRunSchema = BackupRunSchema;
|
|
253667
|
+
exports.BackupRunStateSchema = BackupRunStateSchema;
|
|
253668
|
+
exports.BackupTriggerResultSchema = BackupTriggerResultSchema;
|
|
252797
253669
|
exports.BaseAddon = require_sleep.BaseAddon;
|
|
252798
253670
|
exports.BaseDevice = BaseDevice;
|
|
252799
253671
|
exports.BaseDeviceProvider = BaseDeviceProvider;
|
|
@@ -387765,6 +388637,16 @@ var require_main2 = __commonJS({
|
|
|
387765
388637
|
installSource: resolvedSource
|
|
387766
388638
|
});
|
|
387767
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
|
+
}
|
|
387768
388650
|
console.log(`[Agent] Addon packages ready in ${config.addonsDir}`);
|
|
387769
388651
|
let broker = (0, system_1.createBroker)({
|
|
387770
388652
|
nodeID: config.nodeId,
|
|
@@ -427620,6 +428502,18 @@ var require_launcher = __commonJS({
|
|
|
427620
428502
|
console.warn(`[launcher] first-boot addon plan failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
427621
428503
|
}
|
|
427622
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
|
+
}
|
|
427623
428517
|
if (typeof installer.reconcileManifest === "function") {
|
|
427624
428518
|
const reconciled = installer.reconcileManifest();
|
|
427625
428519
|
if (reconciled > 0) {
|