camstack 1.2.76 → 1.2.78
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.
|
@@ -15614,7 +15614,8 @@ var OpsLogReasonSchema = external_exports.enum([
|
|
|
15614
15614
|
"quota",
|
|
15615
15615
|
"manual",
|
|
15616
15616
|
"operator",
|
|
15617
|
-
"maintenance"
|
|
15617
|
+
"maintenance",
|
|
15618
|
+
"orphaned-device"
|
|
15618
15619
|
]);
|
|
15619
15620
|
var OpsLogEntrySchema = external_exports.object({
|
|
15620
15621
|
/** Unique row id. */
|
|
@@ -20544,6 +20545,27 @@ var DevicePersistConfigPayloadSchema = external_exports.object({
|
|
|
20544
20545
|
deviceId: external_exports.number(),
|
|
20545
20546
|
data: external_exports.record(external_exports.string(), external_exports.unknown())
|
|
20546
20547
|
});
|
|
20548
|
+
var MigrateSwitchOutcomeSchema = external_exports.enum([
|
|
20549
|
+
"off",
|
|
20550
|
+
"on",
|
|
20551
|
+
"not-offered",
|
|
20552
|
+
"unreachable"
|
|
20553
|
+
]);
|
|
20554
|
+
var MigrateSwitchReportSchema = external_exports.object({
|
|
20555
|
+
deviceId: external_exports.number(),
|
|
20556
|
+
switchId: CameraSwitchIdSchema,
|
|
20557
|
+
outcome: MigrateSwitchOutcomeSchema,
|
|
20558
|
+
detail: external_exports.string().optional()
|
|
20559
|
+
});
|
|
20560
|
+
var MigrateDeviceResultSchema = external_exports.object({
|
|
20561
|
+
sourceId: external_exports.number(),
|
|
20562
|
+
targetId: external_exports.number(),
|
|
20563
|
+
switches: external_exports.array(MigrateSwitchReportSchema).readonly(),
|
|
20564
|
+
/** Switches that could NOT be turned off on the source. Empty is the only
|
|
20565
|
+
* value meaning the replaced hardware is quiet. */
|
|
20566
|
+
sourceStillLive: external_exports.array(CameraSwitchIdSchema).readonly(),
|
|
20567
|
+
swapped: external_exports.boolean()
|
|
20568
|
+
});
|
|
20547
20569
|
var deviceManagerCapability = {
|
|
20548
20570
|
name: "device-manager",
|
|
20549
20571
|
scope: "system",
|
|
@@ -20558,6 +20580,33 @@ var deviceManagerCapability = {
|
|
|
20558
20580
|
addonId: external_exports.string(),
|
|
20559
20581
|
stableId: external_exports.string()
|
|
20560
20582
|
}), external_exports.object({ id: external_exports.number() }), { kind: "mutation" }),
|
|
20583
|
+
/**
|
|
20584
|
+
* Replace a camera: the new hardware inherits the number the system knows.
|
|
20585
|
+
*
|
|
20586
|
+
* Everything general about a camera is keyed on the numeric id and nothing
|
|
20587
|
+
* else — the recording path on disk, the hour ledger, the media store, zone
|
|
20588
|
+
* ownership, and all four ecosystem exports. So a replacement moves the
|
|
20589
|
+
* NUMBER rather than the work, and the operator keeps their footage, their
|
|
20590
|
+
* rules and their integrations.
|
|
20591
|
+
*
|
|
20592
|
+
* Both cameras are switched off first, then the identities are exchanged
|
|
20593
|
+
* (children follow their parent), then the target — now answering on the
|
|
20594
|
+
* inherited number — is switched back on.
|
|
20595
|
+
*
|
|
20596
|
+
* **A switch that could not be written is REPORTED, not swallowed.** The
|
|
20597
|
+
* source is characteristically broken, and two of the eight switches write
|
|
20598
|
+
* the camera itself, so on a dead one they cannot be written at all.
|
|
20599
|
+
* `sourceStillLive` names what stayed live; empty is the only value that
|
|
20600
|
+
* means the old hardware is quiet. The migration proceeds either way —
|
|
20601
|
+
* refusing would refuse the case this exists for.
|
|
20602
|
+
*/
|
|
20603
|
+
migrateDevice: method(external_exports.object({
|
|
20604
|
+
sourceId: external_exports.number(),
|
|
20605
|
+
targetId: external_exports.number()
|
|
20606
|
+
}), MigrateDeviceResultSchema, {
|
|
20607
|
+
kind: "mutation",
|
|
20608
|
+
auth: "admin"
|
|
20609
|
+
}),
|
|
20561
20610
|
/** Register a device in the DB + in-memory registry. Called by DeviceManagerApi.register(). */
|
|
20562
20611
|
registerDevice: method(DeviceRegisterPayloadSchema, external_exports.void(), { kind: "mutation" }),
|
|
20563
20612
|
/** Remove a device from the DB + in-memory registry. Called by DeviceManagerApi.remove(). */
|
|
@@ -40655,6 +40704,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
40655
40704
|
addonId: null,
|
|
40656
40705
|
access: "view"
|
|
40657
40706
|
},
|
|
40707
|
+
"deviceManager.migrateDevice": {
|
|
40708
|
+
capName: "device-manager",
|
|
40709
|
+
capScope: "system",
|
|
40710
|
+
addonId: null,
|
|
40711
|
+
access: "create"
|
|
40712
|
+
},
|
|
40658
40713
|
"deviceManager.persistConfig": {
|
|
40659
40714
|
capName: "device-manager",
|
|
40660
40715
|
capScope: "system",
|
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
runDiscover
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-EDAEBWHA.js";
|
|
5
5
|
import "./chunk-LMMQX4CK.js";
|
|
6
6
|
|
|
7
7
|
// src/cli.ts
|
|
@@ -38,7 +38,7 @@ async function runServe(args) {
|
|
|
38
38
|
...typeof values.data === "string" ? { data: values.data } : {}
|
|
39
39
|
};
|
|
40
40
|
Object.assign(process.env, buildServeEnv(opts));
|
|
41
|
-
await import("./launcher-
|
|
41
|
+
await import("./launcher-22Q4HRAB.js");
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
// src/commands/agent.ts
|
|
@@ -83,7 +83,7 @@ async function runAgent(args) {
|
|
|
83
83
|
...typeof values.port === "string" ? { port: values.port } : {}
|
|
84
84
|
};
|
|
85
85
|
Object.assign(process.env, buildAgentEnv(opts));
|
|
86
|
-
await import("./launcher-
|
|
86
|
+
await import("./launcher-22Q4HRAB.js");
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
// src/commands/setup.ts
|
|
@@ -1130,7 +1130,7 @@ function isUnknown(_value) {
|
|
|
1130
1130
|
return true;
|
|
1131
1131
|
}
|
|
1132
1132
|
async function resolveServerInteractive(presetNamespace) {
|
|
1133
|
-
const { discoverNodes, resolveHubFromDiscovered, filterHubNodes, DEFAULT_HUB_HTTPS_PORT } = await import("./discover-
|
|
1133
|
+
const { discoverNodes, resolveHubFromDiscovered, filterHubNodes, DEFAULT_HUB_HTTPS_PORT } = await import("./discover-HIST37I5.js");
|
|
1134
1134
|
if (presetNamespace) {
|
|
1135
1135
|
const spinner4 = clack.spinner();
|
|
1136
1136
|
spinner4.start(`Discovering hub on LAN (namespace "${presetNamespace}")`);
|
|
@@ -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-BzPNEPHo.js
|
|
23637
|
+
var require_dist_BzPNEPHo = __commonJS({
|
|
23638
|
+
"../system/dist/dist-BzPNEPHo.js"(exports) {
|
|
23639
23639
|
"use strict";
|
|
23640
23640
|
var zod = require_zod();
|
|
23641
23641
|
var EventCategory = /* @__PURE__ */ (function(EventCategory2) {
|
|
@@ -25953,6 +25953,16 @@ var require_dist_DsoVfJSR = __commonJS({
|
|
|
25953
25953
|
"recording",
|
|
25954
25954
|
"notifications"
|
|
25955
25955
|
]);
|
|
25956
|
+
var CAMERA_SWITCH_ORDER = [
|
|
25957
|
+
"stream-broker",
|
|
25958
|
+
"object-detection",
|
|
25959
|
+
"privacy-mask",
|
|
25960
|
+
"device-audio",
|
|
25961
|
+
"broker-audio",
|
|
25962
|
+
"audio-analysis",
|
|
25963
|
+
"recording",
|
|
25964
|
+
"notifications"
|
|
25965
|
+
];
|
|
25956
25966
|
var CameraSwitchAuthoritySchema = zod.z.discriminatedUnion("kind", [
|
|
25957
25967
|
zod.z.object({ kind: zod.z.literal("device-disabled") }),
|
|
25958
25968
|
zod.z.object({
|
|
@@ -26102,7 +26112,8 @@ var require_dist_DsoVfJSR = __commonJS({
|
|
|
26102
26112
|
"quota",
|
|
26103
26113
|
"manual",
|
|
26104
26114
|
"operator",
|
|
26105
|
-
"maintenance"
|
|
26115
|
+
"maintenance",
|
|
26116
|
+
"orphaned-device"
|
|
26106
26117
|
]);
|
|
26107
26118
|
var OpsLogEntrySchema = zod.z.object({
|
|
26108
26119
|
/** Unique row id. */
|
|
@@ -31247,6 +31258,27 @@ var require_dist_DsoVfJSR = __commonJS({
|
|
|
31247
31258
|
deviceId: zod.z.number(),
|
|
31248
31259
|
data: zod.z.record(zod.z.string(), zod.z.unknown())
|
|
31249
31260
|
});
|
|
31261
|
+
var MigrateSwitchOutcomeSchema = zod.z.enum([
|
|
31262
|
+
"off",
|
|
31263
|
+
"on",
|
|
31264
|
+
"not-offered",
|
|
31265
|
+
"unreachable"
|
|
31266
|
+
]);
|
|
31267
|
+
var MigrateSwitchReportSchema = zod.z.object({
|
|
31268
|
+
deviceId: zod.z.number(),
|
|
31269
|
+
switchId: CameraSwitchIdSchema,
|
|
31270
|
+
outcome: MigrateSwitchOutcomeSchema,
|
|
31271
|
+
detail: zod.z.string().optional()
|
|
31272
|
+
});
|
|
31273
|
+
var MigrateDeviceResultSchema = zod.z.object({
|
|
31274
|
+
sourceId: zod.z.number(),
|
|
31275
|
+
targetId: zod.z.number(),
|
|
31276
|
+
switches: zod.z.array(MigrateSwitchReportSchema).readonly(),
|
|
31277
|
+
/** Switches that could NOT be turned off on the source. Empty is the only
|
|
31278
|
+
* value meaning the replaced hardware is quiet. */
|
|
31279
|
+
sourceStillLive: zod.z.array(CameraSwitchIdSchema).readonly(),
|
|
31280
|
+
swapped: zod.z.boolean()
|
|
31281
|
+
});
|
|
31250
31282
|
var deviceManagerCapability = {
|
|
31251
31283
|
name: "device-manager",
|
|
31252
31284
|
scope: "system",
|
|
@@ -31261,6 +31293,33 @@ var require_dist_DsoVfJSR = __commonJS({
|
|
|
31261
31293
|
addonId: zod.z.string(),
|
|
31262
31294
|
stableId: zod.z.string()
|
|
31263
31295
|
}), zod.z.object({ id: zod.z.number() }), { kind: "mutation" }),
|
|
31296
|
+
/**
|
|
31297
|
+
* Replace a camera: the new hardware inherits the number the system knows.
|
|
31298
|
+
*
|
|
31299
|
+
* Everything general about a camera is keyed on the numeric id and nothing
|
|
31300
|
+
* else — the recording path on disk, the hour ledger, the media store, zone
|
|
31301
|
+
* ownership, and all four ecosystem exports. So a replacement moves the
|
|
31302
|
+
* NUMBER rather than the work, and the operator keeps their footage, their
|
|
31303
|
+
* rules and their integrations.
|
|
31304
|
+
*
|
|
31305
|
+
* Both cameras are switched off first, then the identities are exchanged
|
|
31306
|
+
* (children follow their parent), then the target — now answering on the
|
|
31307
|
+
* inherited number — is switched back on.
|
|
31308
|
+
*
|
|
31309
|
+
* **A switch that could not be written is REPORTED, not swallowed.** The
|
|
31310
|
+
* source is characteristically broken, and two of the eight switches write
|
|
31311
|
+
* the camera itself, so on a dead one they cannot be written at all.
|
|
31312
|
+
* `sourceStillLive` names what stayed live; empty is the only value that
|
|
31313
|
+
* means the old hardware is quiet. The migration proceeds either way —
|
|
31314
|
+
* refusing would refuse the case this exists for.
|
|
31315
|
+
*/
|
|
31316
|
+
migrateDevice: method(zod.z.object({
|
|
31317
|
+
sourceId: zod.z.number(),
|
|
31318
|
+
targetId: zod.z.number()
|
|
31319
|
+
}), MigrateDeviceResultSchema, {
|
|
31320
|
+
kind: "mutation",
|
|
31321
|
+
auth: "admin"
|
|
31322
|
+
}),
|
|
31264
31323
|
/** Register a device in the DB + in-memory registry. Called by DeviceManagerApi.register(). */
|
|
31265
31324
|
registerDevice: method(DeviceRegisterPayloadSchema, zod.z.void(), { kind: "mutation" }),
|
|
31266
31325
|
/** Remove a device from the DB + in-memory registry. Called by DeviceManagerApi.remove(). */
|
|
@@ -51971,6 +52030,12 @@ var require_dist_DsoVfJSR = __commonJS({
|
|
|
51971
52030
|
addonId: null,
|
|
51972
52031
|
access: "view"
|
|
51973
52032
|
},
|
|
52033
|
+
"deviceManager.migrateDevice": {
|
|
52034
|
+
capName: "device-manager",
|
|
52035
|
+
capScope: "system",
|
|
52036
|
+
addonId: null,
|
|
52037
|
+
access: "create"
|
|
52038
|
+
},
|
|
51974
52039
|
"deviceManager.persistConfig": {
|
|
51975
52040
|
capName: "device-manager",
|
|
51976
52041
|
capScope: "system",
|
|
@@ -59055,6 +59120,12 @@ var require_dist_DsoVfJSR = __commonJS({
|
|
|
59055
59120
|
return BatteryStatusSchema;
|
|
59056
59121
|
}
|
|
59057
59122
|
});
|
|
59123
|
+
Object.defineProperty(exports, "CAMERA_SWITCH_ORDER", {
|
|
59124
|
+
enumerable: true,
|
|
59125
|
+
get: function() {
|
|
59126
|
+
return CAMERA_SWITCH_ORDER;
|
|
59127
|
+
}
|
|
59128
|
+
});
|
|
59058
59129
|
Object.defineProperty(exports, "CAP_NAMES_WITH_STATUS", {
|
|
59059
59130
|
enumerable: true,
|
|
59060
59131
|
get: function() {
|
|
@@ -59715,7 +59786,7 @@ var require_alerts_addon = __commonJS({
|
|
|
59715
59786
|
[Symbol.toStringTag]: { value: "Module" }
|
|
59716
59787
|
});
|
|
59717
59788
|
require_chunk_Cek0wNdY();
|
|
59718
|
-
var require_dist10 =
|
|
59789
|
+
var require_dist10 = require_dist_BzPNEPHo();
|
|
59719
59790
|
function selectExpired(alerts, cutoffMs) {
|
|
59720
59791
|
return alerts.filter((a) => a.createdAt < cutoffMs).sort((a, b) => a.createdAt - b.createdAt).map((a) => a.id);
|
|
59721
59792
|
}
|
|
@@ -60534,7 +60605,7 @@ var require_console_logging = __commonJS({
|
|
|
60534
60605
|
[Symbol.toStringTag]: { value: "Module" }
|
|
60535
60606
|
});
|
|
60536
60607
|
require_chunk_Cek0wNdY();
|
|
60537
|
-
var require_dist10 =
|
|
60608
|
+
var require_dist10 = require_dist_BzPNEPHo();
|
|
60538
60609
|
var require_formatter = require_formatter_DqAKDlvN();
|
|
60539
60610
|
var LEVEL_RANK = {
|
|
60540
60611
|
debug: 0,
|
|
@@ -60628,7 +60699,7 @@ var require_core_blocks_addon = __commonJS({
|
|
|
60628
60699
|
"use strict";
|
|
60629
60700
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
60630
60701
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
60631
|
-
var require_dist10 =
|
|
60702
|
+
var require_dist10 = require_dist_BzPNEPHo();
|
|
60632
60703
|
var node_crypto = __require("crypto");
|
|
60633
60704
|
var node_fs_promises = __require("fs/promises");
|
|
60634
60705
|
node_fs_promises = require_chunk.__toESM(node_fs_promises);
|
|
@@ -61525,11 +61596,11 @@ var require_core_blocks = __commonJS({
|
|
|
61525
61596
|
}
|
|
61526
61597
|
});
|
|
61527
61598
|
|
|
61528
|
-
// ../system/dist/retired-settings-keys-
|
|
61529
|
-
var
|
|
61530
|
-
"../system/dist/retired-settings-keys-
|
|
61599
|
+
// ../system/dist/retired-settings-keys-DZmeJ8ja.js
|
|
61600
|
+
var require_retired_settings_keys_DZmeJ8ja = __commonJS({
|
|
61601
|
+
"../system/dist/retired-settings-keys-DZmeJ8ja.js"(exports) {
|
|
61531
61602
|
"use strict";
|
|
61532
|
-
var require_dist10 =
|
|
61603
|
+
var require_dist10 = require_dist_BzPNEPHo();
|
|
61533
61604
|
function settingsStoreIsAuthoritativeHere(env) {
|
|
61534
61605
|
const raw = (env["CAMSTACK_ROLE"] ?? "").trim().toLowerCase();
|
|
61535
61606
|
return raw === "" || raw === "hub";
|
|
@@ -63743,8 +63814,8 @@ var require_device_manager_addon = __commonJS({
|
|
|
63743
63814
|
[Symbol.toStringTag]: { value: "Module" }
|
|
63744
63815
|
});
|
|
63745
63816
|
require_chunk_Cek0wNdY();
|
|
63746
|
-
var require_dist10 =
|
|
63747
|
-
var require_retired_settings_keys =
|
|
63817
|
+
var require_dist10 = require_dist_BzPNEPHo();
|
|
63818
|
+
var require_retired_settings_keys = require_retired_settings_keys_DZmeJ8ja();
|
|
63748
63819
|
var node_crypto = __require("crypto");
|
|
63749
63820
|
var _camstack_types_node = require_node();
|
|
63750
63821
|
var JOB_HISTORY = 20;
|
|
@@ -66226,6 +66297,62 @@ var require_device_manager_addon = __commonJS({
|
|
|
66226
66297
|
return chain;
|
|
66227
66298
|
}
|
|
66228
66299
|
};
|
|
66300
|
+
function classify(err) {
|
|
66301
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
66302
|
+
return {
|
|
66303
|
+
outcome: /does not offer|not available|unsupported/i.test(detail) ? "not-offered" : "unreachable",
|
|
66304
|
+
detail
|
|
66305
|
+
};
|
|
66306
|
+
}
|
|
66307
|
+
async function applyAll(deps, deviceId, enabled) {
|
|
66308
|
+
const out = [];
|
|
66309
|
+
for (const switchId of require_dist10.CAMERA_SWITCH_ORDER) try {
|
|
66310
|
+
await deps.setSwitch(deviceId, switchId, enabled);
|
|
66311
|
+
out.push({
|
|
66312
|
+
deviceId,
|
|
66313
|
+
switchId,
|
|
66314
|
+
outcome: enabled ? "on" : "off"
|
|
66315
|
+
});
|
|
66316
|
+
} catch (err) {
|
|
66317
|
+
const { outcome, detail } = classify(err);
|
|
66318
|
+
out.push({
|
|
66319
|
+
deviceId,
|
|
66320
|
+
switchId,
|
|
66321
|
+
outcome,
|
|
66322
|
+
detail
|
|
66323
|
+
});
|
|
66324
|
+
deps.log("camera switch refused", {
|
|
66325
|
+
deviceId,
|
|
66326
|
+
switchId,
|
|
66327
|
+
enabled,
|
|
66328
|
+
outcome,
|
|
66329
|
+
detail
|
|
66330
|
+
});
|
|
66331
|
+
}
|
|
66332
|
+
return out;
|
|
66333
|
+
}
|
|
66334
|
+
async function migrateDevice$1(deps, input) {
|
|
66335
|
+
const { sourceId, targetId } = input;
|
|
66336
|
+
if (sourceId === targetId) throw new Error(`[device-manager] migrateDevice: ${sourceId} is both source and target`);
|
|
66337
|
+
const down = [...await applyAll(deps, sourceId, false), ...await applyAll(deps, targetId, false)];
|
|
66338
|
+
const sourceStillLive = down.filter((r) => r.deviceId === sourceId && r.outcome === "unreachable").map((r) => r.switchId);
|
|
66339
|
+
await deps.swapIds(sourceId, targetId);
|
|
66340
|
+
const up = await applyAll(deps, sourceId, true);
|
|
66341
|
+
await deps.respawnRunners([sourceId, targetId]);
|
|
66342
|
+
deps.log("camera migrated", {
|
|
66343
|
+
sourceId,
|
|
66344
|
+
targetId,
|
|
66345
|
+
sourceStillLive,
|
|
66346
|
+
refusals: [...down, ...up].filter((r) => r.outcome === "unreachable").length
|
|
66347
|
+
});
|
|
66348
|
+
return {
|
|
66349
|
+
sourceId,
|
|
66350
|
+
targetId,
|
|
66351
|
+
switches: [...down, ...up],
|
|
66352
|
+
sourceStillLive,
|
|
66353
|
+
swapped: true
|
|
66354
|
+
};
|
|
66355
|
+
}
|
|
66229
66356
|
async function stampIntegrationId(metaStore, ctx, deviceId, integrationId) {
|
|
66230
66357
|
await metaStore.withMetaWriteLock(async () => {
|
|
66231
66358
|
if (!await metaStore.resolvePersistedById(deviceId)) throw new Error(`[device-manager] stampIntegrationId: unknown device id=${deviceId}`);
|
|
@@ -66268,6 +66395,42 @@ var require_device_manager_addon = __commonJS({
|
|
|
66268
66395
|
return { id };
|
|
66269
66396
|
});
|
|
66270
66397
|
}
|
|
66398
|
+
async function migrateDevice(pctx, input) {
|
|
66399
|
+
const { sourceId, targetId } = input;
|
|
66400
|
+
const ctx = pctx.host.ctx;
|
|
66401
|
+
return await pctx.metaStore.withMetaWriteLock(async () => {
|
|
66402
|
+
const tempId = await pctx.metaStore.allocateNextDeviceId();
|
|
66403
|
+
return await migrateDevice$1({
|
|
66404
|
+
setSwitch: async (deviceId, switchId, enabled) => {
|
|
66405
|
+
await ctx.api.pipelineOrchestrator.setCameraSwitch.mutate({
|
|
66406
|
+
deviceId,
|
|
66407
|
+
switchId,
|
|
66408
|
+
enabled
|
|
66409
|
+
});
|
|
66410
|
+
},
|
|
66411
|
+
swapIds: async (a, b) => {
|
|
66412
|
+
await pctx.metaStore.rows.swapIds(a, b, tempId);
|
|
66413
|
+
},
|
|
66414
|
+
respawnRunners: async (deviceIds) => {
|
|
66415
|
+
const owners = /* @__PURE__ */ new Set();
|
|
66416
|
+
for (const deviceId of deviceIds) {
|
|
66417
|
+
const addonId = pctx.metaStore.idToAddonId.get(deviceId);
|
|
66418
|
+
if (addonId !== void 0) owners.add(addonId);
|
|
66419
|
+
}
|
|
66420
|
+
for (const addonId of owners) await ctx.api.addons.restartAddon.mutate({ addonId });
|
|
66421
|
+
},
|
|
66422
|
+
log: (message, meta) => {
|
|
66423
|
+
ctx.logger.info(message, {
|
|
66424
|
+
tags: { deviceId: sourceId },
|
|
66425
|
+
meta
|
|
66426
|
+
});
|
|
66427
|
+
}
|
|
66428
|
+
}, {
|
|
66429
|
+
sourceId,
|
|
66430
|
+
targetId
|
|
66431
|
+
});
|
|
66432
|
+
});
|
|
66433
|
+
}
|
|
66271
66434
|
async function registerDevice(pctx, input) {
|
|
66272
66435
|
const { addonId, stableId, id, type, name, parentDeviceId, features, config } = input;
|
|
66273
66436
|
const featuresArr = Array.isArray(features) ? [...features] : [];
|
|
@@ -67743,6 +67906,86 @@ var require_device_manager_addon = __commonJS({
|
|
|
67743
67906
|
});
|
|
67744
67907
|
}
|
|
67745
67908
|
/** Drop the device's row. Idempotent. */
|
|
67909
|
+
/**
|
|
67910
|
+
* Exchange the ids of two devices, carrying their children with them.
|
|
67911
|
+
*
|
|
67912
|
+
* ## Why this exists as a primitive
|
|
67913
|
+
*
|
|
67914
|
+
* Replacing a camera means the new hardware has to become the device the rest
|
|
67915
|
+
* of the system already knows. Everything general about a camera is keyed on
|
|
67916
|
+
* the NUMERIC id and on nothing else — the recording path on disk is
|
|
67917
|
+
* `<deviceId>/profile/…`, the hour ledger, the media store and zone ownership
|
|
67918
|
+
* carry `deviceId` and not one `stableId` between them, and all four
|
|
67919
|
+
* ecosystem exports (Home Assistant, Alexa, HomeKit, Google) key on it too.
|
|
67920
|
+
* Moving that work is the expensive, lossy operation. Moving the NUMBER is
|
|
67921
|
+
* two rows.
|
|
67922
|
+
*
|
|
67923
|
+
* ## Children are re-pointed, not renumbered
|
|
67924
|
+
*
|
|
67925
|
+
* A child keeps its own id and follows its parent: every row whose
|
|
67926
|
+
* `parentDeviceId` was `a` now names `b`, and the reverse. Renumbering the
|
|
67927
|
+
* children as well would move THEIR general work for no reason — the
|
|
67928
|
+
* accessory's own recordings and rules are keyed on the child id, which is
|
|
67929
|
+
* not the id being inherited.
|
|
67930
|
+
*
|
|
67931
|
+
* ## There are no transactions here, so the ORDER is the safety
|
|
67932
|
+
*
|
|
67933
|
+
* The backing store is a collection API (`set` / `delete` / `updateWhere`);
|
|
67934
|
+
* there is no rollback to lean on. So the sequence is chosen to make every
|
|
67935
|
+
* crash point LOUD rather than plausible: `a` first moves to a freshly
|
|
67936
|
+
* allocated id, which the monotonic counter guarantees was never used and
|
|
67937
|
+
* will never be reused. A crash before the end therefore leaves a device
|
|
67938
|
+
* missing from its number and a stray at an unfamiliar one — visible in the
|
|
67939
|
+
* device list at a glance. What it can never leave is two rows on one number,
|
|
67940
|
+
* or a row that looks correct while its children point elsewhere.
|
|
67941
|
+
*
|
|
67942
|
+
* The caller holds {@link DeviceMetaStore.withMetaWriteLock}. This method does
|
|
67943
|
+
* not take it: taking it here would deadlock the migration that has to disable
|
|
67944
|
+
* functions on both devices in the same critical section.
|
|
67945
|
+
*/
|
|
67946
|
+
async swapIds(a, b, tempId) {
|
|
67947
|
+
if (a === b) throw new Error(`[device-manager] swapIds: ${a} and ${b} are the same device`);
|
|
67948
|
+
await this.declare();
|
|
67949
|
+
const rowA = await this.get(a);
|
|
67950
|
+
const rowB = await this.get(b);
|
|
67951
|
+
if (rowA === null) throw new Error(`[device-manager] swapIds: device ${a} does not exist`);
|
|
67952
|
+
if (rowB === null) throw new Error(`[device-manager] swapIds: device ${b} does not exist`);
|
|
67953
|
+
if (await this.get(tempId) !== null) throw new Error(`[device-manager] swapIds: temp id ${tempId} is taken`);
|
|
67954
|
+
const childrenOfA = (await this.listByParent(a)).map((r) => r.meta.id);
|
|
67955
|
+
const childrenOfB = (await this.listByParent(b)).map((r) => r.meta.id);
|
|
67956
|
+
await this.moveRow(rowA, tempId);
|
|
67957
|
+
await this.moveRow(rowB, a);
|
|
67958
|
+
await this.moveRow({
|
|
67959
|
+
...rowA,
|
|
67960
|
+
meta: {
|
|
67961
|
+
...rowA.meta,
|
|
67962
|
+
id: tempId
|
|
67963
|
+
}
|
|
67964
|
+
}, b);
|
|
67965
|
+
for (const childId of childrenOfA) await this.patch(childId, { parentDeviceId: b });
|
|
67966
|
+
for (const childId of childrenOfB) await this.patch(childId, { parentDeviceId: a });
|
|
67967
|
+
this.logger.info("device ids swapped", {
|
|
67968
|
+
tags: { deviceId: a },
|
|
67969
|
+
meta: {
|
|
67970
|
+
a,
|
|
67971
|
+
b,
|
|
67972
|
+
childrenOfA,
|
|
67973
|
+
childrenOfB
|
|
67974
|
+
}
|
|
67975
|
+
});
|
|
67976
|
+
}
|
|
67977
|
+
/** Rewrite a row under a new id and drop the old key. Not exported: the only
|
|
67978
|
+
* legitimate reason to move a row is {@link swapIds}. */
|
|
67979
|
+
async moveRow(row, toId) {
|
|
67980
|
+
await this.upsert({
|
|
67981
|
+
...row.meta,
|
|
67982
|
+
id: toId
|
|
67983
|
+
}, {
|
|
67984
|
+
registered: row.registered,
|
|
67985
|
+
metadata: row.metadata
|
|
67986
|
+
});
|
|
67987
|
+
await this.remove(row.meta.id);
|
|
67988
|
+
}
|
|
67746
67989
|
async remove(deviceId) {
|
|
67747
67990
|
await this.declare();
|
|
67748
67991
|
await this.backend.delete({
|
|
@@ -68376,6 +68619,7 @@ var require_device_manager_addon = __commonJS({
|
|
|
68376
68619
|
resolveDeviceOwnerSync: (deviceId) => resolveDeviceOwnerSync(pctx, deviceId),
|
|
68377
68620
|
resolveNativeCapOwnerSync: (capName, deviceId) => resolveNativeCapOwnerSync(pctx, capName, deviceId),
|
|
68378
68621
|
allocateDeviceId: (input) => allocateDeviceId(pctx, input),
|
|
68622
|
+
migrateDevice: (input) => migrateDevice(pctx, input),
|
|
68379
68623
|
registerDevice: (input) => registerDevice(pctx, input),
|
|
68380
68624
|
removeDevice: (input) => removeDevice(pctx, input),
|
|
68381
68625
|
persistConfig: (input) => persistConfig(pctx, input),
|
|
@@ -68606,7 +68850,7 @@ var require_hub_forwarder = __commonJS({
|
|
|
68606
68850
|
[Symbol.toStringTag]: { value: "Module" }
|
|
68607
68851
|
});
|
|
68608
68852
|
require_chunk_Cek0wNdY();
|
|
68609
|
-
var require_dist10 =
|
|
68853
|
+
var require_dist10 = require_dist_BzPNEPHo();
|
|
68610
68854
|
var require_formatter = require_formatter_DqAKDlvN();
|
|
68611
68855
|
var DEFAULT_OUTBOUND_BUFFER_SIZE = 500;
|
|
68612
68856
|
var HubForwarderDestination = class {
|
|
@@ -68743,7 +68987,7 @@ var require_liveness_monitor_addon = __commonJS({
|
|
|
68743
68987
|
"use strict";
|
|
68744
68988
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
68745
68989
|
require_chunk_Cek0wNdY();
|
|
68746
|
-
var require_dist10 =
|
|
68990
|
+
var require_dist10 = require_dist_BzPNEPHo();
|
|
68747
68991
|
var NO_DEVICES = "liveness:no-devices";
|
|
68748
68992
|
var ALL_OFFLINE = "liveness:all-devices-offline";
|
|
68749
68993
|
var NO_FOOTAGE_PREFIX = "liveness:no-footage:";
|
|
@@ -68933,7 +69177,7 @@ var require_local_auth_addon = __commonJS({
|
|
|
68933
69177
|
[Symbol.toStringTag]: { value: "Module" }
|
|
68934
69178
|
});
|
|
68935
69179
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
68936
|
-
var require_dist10 =
|
|
69180
|
+
var require_dist10 = require_dist_BzPNEPHo();
|
|
68937
69181
|
var node_crypto = __require("crypto");
|
|
68938
69182
|
node_crypto = require_chunk.__toESM(node_crypto);
|
|
68939
69183
|
var crypto$1 = __require("crypto");
|
|
@@ -76746,7 +76990,7 @@ var require_loki_logging = __commonJS({
|
|
|
76746
76990
|
[Symbol.toStringTag]: { value: "Module" }
|
|
76747
76991
|
});
|
|
76748
76992
|
require_chunk_Cek0wNdY();
|
|
76749
|
-
var require_dist10 =
|
|
76993
|
+
var require_dist10 = require_dist_BzPNEPHo();
|
|
76750
76994
|
function sanitizeLabelName(raw) {
|
|
76751
76995
|
const replaced = raw.replaceAll(/[^a-zA-Z0-9_]/g, "_");
|
|
76752
76996
|
return /^[a-zA-Z_]/.test(replaced) ? replaced : `_${replaced}`;
|
|
@@ -77311,7 +77555,7 @@ var require_native_metrics_addon = __commonJS({
|
|
|
77311
77555
|
[Symbol.toStringTag]: { value: "Module" }
|
|
77312
77556
|
});
|
|
77313
77557
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
77314
|
-
var require_dist10 =
|
|
77558
|
+
var require_dist10 = require_dist_BzPNEPHo();
|
|
77315
77559
|
var node_fs_promises = __require("fs/promises");
|
|
77316
77560
|
var node_child_process = __require("child_process");
|
|
77317
77561
|
var node_util = __require("util");
|
|
@@ -79933,7 +80177,7 @@ var require_filesystem_storage_addon = __commonJS({
|
|
|
79933
80177
|
[Symbol.toStringTag]: { value: "Module" }
|
|
79934
80178
|
});
|
|
79935
80179
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
79936
|
-
var require_dist10 =
|
|
80180
|
+
var require_dist10 = require_dist_BzPNEPHo();
|
|
79937
80181
|
var node_crypto = __require("crypto");
|
|
79938
80182
|
var node_fs_promises = __require("fs/promises");
|
|
79939
80183
|
var node_path = __require("path");
|
|
@@ -81049,8 +81293,8 @@ var require_sqlite_settings_addon = __commonJS({
|
|
|
81049
81293
|
[Symbol.toStringTag]: { value: "Module" }
|
|
81050
81294
|
});
|
|
81051
81295
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
81052
|
-
var require_dist10 =
|
|
81053
|
-
var require_retired_settings_keys =
|
|
81296
|
+
var require_dist10 = require_dist_BzPNEPHo();
|
|
81297
|
+
var require_retired_settings_keys = require_retired_settings_keys_DZmeJ8ja();
|
|
81054
81298
|
var node_crypto = __require("crypto");
|
|
81055
81299
|
var node_fs = __require("fs");
|
|
81056
81300
|
var node_module = __require("module");
|
|
@@ -83532,7 +83776,7 @@ var require_storage_orchestrator_addon = __commonJS({
|
|
|
83532
83776
|
[Symbol.toStringTag]: { value: "Module" }
|
|
83533
83777
|
});
|
|
83534
83778
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
83535
|
-
var require_dist10 =
|
|
83779
|
+
var require_dist10 = require_dist_BzPNEPHo();
|
|
83536
83780
|
var require_hub_cap_forward = require_hub_cap_forward_DmHNjbB0();
|
|
83537
83781
|
var zod = require_zod();
|
|
83538
83782
|
var node_crypto = __require("crypto");
|
|
@@ -86483,7 +86727,7 @@ var require_system_config_addon = __commonJS({
|
|
|
86483
86727
|
[Symbol.toStringTag]: { value: "Module" }
|
|
86484
86728
|
});
|
|
86485
86729
|
require_chunk_Cek0wNdY();
|
|
86486
|
-
var require_dist10 =
|
|
86730
|
+
var require_dist10 = require_dist_BzPNEPHo();
|
|
86487
86731
|
var SECTION_TITLES = {
|
|
86488
86732
|
server: "Server",
|
|
86489
86733
|
auth: "Authentication"
|
|
@@ -104544,7 +104788,7 @@ var require_winston_logging = __commonJS({
|
|
|
104544
104788
|
[Symbol.toStringTag]: { value: "Module" }
|
|
104545
104789
|
});
|
|
104546
104790
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
104547
|
-
var require_dist10 =
|
|
104791
|
+
var require_dist10 = require_dist_BzPNEPHo();
|
|
104548
104792
|
var require_formatter = require_formatter_DqAKDlvN();
|
|
104549
104793
|
var node_path = __require("path");
|
|
104550
104794
|
node_path = require_chunk.__toESM(node_path);
|
|
@@ -117044,12 +117288,12 @@ var require_dist2 = __commonJS({
|
|
|
117044
117288
|
}
|
|
117045
117289
|
});
|
|
117046
117290
|
|
|
117047
|
-
// ../system/dist/manifest-system-deps-
|
|
117048
|
-
var
|
|
117049
|
-
"../system/dist/manifest-system-deps-
|
|
117291
|
+
// ../system/dist/manifest-system-deps-B0mzJPmb.js
|
|
117292
|
+
var require_manifest_system_deps_B0mzJPmb = __commonJS({
|
|
117293
|
+
"../system/dist/manifest-system-deps-B0mzJPmb.js"(exports) {
|
|
117050
117294
|
"use strict";
|
|
117051
117295
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
117052
|
-
|
|
117296
|
+
require_dist_BzPNEPHo();
|
|
117053
117297
|
require_hub_cap_forward_DmHNjbB0();
|
|
117054
117298
|
var node_crypto = __require("crypto");
|
|
117055
117299
|
node_crypto = require_chunk.__toESM(node_crypto);
|
|
@@ -129145,7 +129389,7 @@ var require_dist3 = __commonJS({
|
|
|
129145
129389
|
"use strict";
|
|
129146
129390
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
129147
129391
|
var require_chunk = require_chunk_Cek0wNdY();
|
|
129148
|
-
var require_dist10 =
|
|
129392
|
+
var require_dist10 = require_dist_BzPNEPHo();
|
|
129149
129393
|
var require_builtins_alerts_alerts_addon = require_alerts_addon();
|
|
129150
129394
|
require_alerts();
|
|
129151
129395
|
var require_formatter = require_formatter_DqAKDlvN();
|
|
@@ -129172,7 +129416,7 @@ var require_dist3 = __commonJS({
|
|
|
129172
129416
|
var require_builtins_winston_logging_index = require_winston_logging();
|
|
129173
129417
|
var require_file_data_plane = require_file_data_plane_DO8KbxCe();
|
|
129174
129418
|
var require_tls$1 = require_tls_BxQlomxd();
|
|
129175
|
-
var require_manifest_system_deps =
|
|
129419
|
+
var require_manifest_system_deps = require_manifest_system_deps_B0mzJPmb();
|
|
129176
129420
|
var require_resource_monitor = require_resource_monitor_CdnzxBLP();
|
|
129177
129421
|
var require_custom_action_registry = require_custom_action_registry_jY0NOZK8();
|
|
129178
129422
|
var zod = require_zod();
|
|
@@ -210982,7 +211226,8 @@ var require_dist4 = __commonJS({
|
|
|
210982
211226
|
"quota",
|
|
210983
211227
|
"manual",
|
|
210984
211228
|
"operator",
|
|
210985
|
-
"maintenance"
|
|
211229
|
+
"maintenance",
|
|
211230
|
+
"orphaned-device"
|
|
210986
211231
|
]);
|
|
210987
211232
|
var OpsLogEntrySchema = zod.z.object({
|
|
210988
211233
|
/** Unique row id. */
|
|
@@ -217321,6 +217566,27 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
217321
217566
|
deviceId: zod.z.number(),
|
|
217322
217567
|
data: zod.z.record(zod.z.string(), zod.z.unknown())
|
|
217323
217568
|
});
|
|
217569
|
+
var MigrateSwitchOutcomeSchema = zod.z.enum([
|
|
217570
|
+
"off",
|
|
217571
|
+
"on",
|
|
217572
|
+
"not-offered",
|
|
217573
|
+
"unreachable"
|
|
217574
|
+
]);
|
|
217575
|
+
var MigrateSwitchReportSchema = zod.z.object({
|
|
217576
|
+
deviceId: zod.z.number(),
|
|
217577
|
+
switchId: CameraSwitchIdSchema,
|
|
217578
|
+
outcome: MigrateSwitchOutcomeSchema,
|
|
217579
|
+
detail: zod.z.string().optional()
|
|
217580
|
+
});
|
|
217581
|
+
var MigrateDeviceResultSchema = zod.z.object({
|
|
217582
|
+
sourceId: zod.z.number(),
|
|
217583
|
+
targetId: zod.z.number(),
|
|
217584
|
+
switches: zod.z.array(MigrateSwitchReportSchema).readonly(),
|
|
217585
|
+
/** Switches that could NOT be turned off on the source. Empty is the only
|
|
217586
|
+
* value meaning the replaced hardware is quiet. */
|
|
217587
|
+
sourceStillLive: zod.z.array(CameraSwitchIdSchema).readonly(),
|
|
217588
|
+
swapped: zod.z.boolean()
|
|
217589
|
+
});
|
|
217324
217590
|
var deviceManagerCapability = {
|
|
217325
217591
|
name: "device-manager",
|
|
217326
217592
|
scope: "system",
|
|
@@ -217335,6 +217601,33 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
217335
217601
|
addonId: zod.z.string(),
|
|
217336
217602
|
stableId: zod.z.string()
|
|
217337
217603
|
}), zod.z.object({ id: zod.z.number() }), { kind: "mutation" }),
|
|
217604
|
+
/**
|
|
217605
|
+
* Replace a camera: the new hardware inherits the number the system knows.
|
|
217606
|
+
*
|
|
217607
|
+
* Everything general about a camera is keyed on the numeric id and nothing
|
|
217608
|
+
* else — the recording path on disk, the hour ledger, the media store, zone
|
|
217609
|
+
* ownership, and all four ecosystem exports. So a replacement moves the
|
|
217610
|
+
* NUMBER rather than the work, and the operator keeps their footage, their
|
|
217611
|
+
* rules and their integrations.
|
|
217612
|
+
*
|
|
217613
|
+
* Both cameras are switched off first, then the identities are exchanged
|
|
217614
|
+
* (children follow their parent), then the target — now answering on the
|
|
217615
|
+
* inherited number — is switched back on.
|
|
217616
|
+
*
|
|
217617
|
+
* **A switch that could not be written is REPORTED, not swallowed.** The
|
|
217618
|
+
* source is characteristically broken, and two of the eight switches write
|
|
217619
|
+
* the camera itself, so on a dead one they cannot be written at all.
|
|
217620
|
+
* `sourceStillLive` names what stayed live; empty is the only value that
|
|
217621
|
+
* means the old hardware is quiet. The migration proceeds either way —
|
|
217622
|
+
* refusing would refuse the case this exists for.
|
|
217623
|
+
*/
|
|
217624
|
+
migrateDevice: require_sleep.method(zod.z.object({
|
|
217625
|
+
sourceId: zod.z.number(),
|
|
217626
|
+
targetId: zod.z.number()
|
|
217627
|
+
}), MigrateDeviceResultSchema, {
|
|
217628
|
+
kind: "mutation",
|
|
217629
|
+
auth: "admin"
|
|
217630
|
+
}),
|
|
217338
217631
|
/** Register a device in the DB + in-memory registry. Called by DeviceManagerApi.register(). */
|
|
217339
217632
|
registerDevice: require_sleep.method(DeviceRegisterPayloadSchema, zod.z.void(), { kind: "mutation" }),
|
|
217340
217633
|
/** Remove a device from the DB + in-memory registry. Called by DeviceManagerApi.remove(). */
|
|
@@ -241969,6 +242262,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
241969
242262
|
addonId: null,
|
|
241970
242263
|
access: "view"
|
|
241971
242264
|
},
|
|
242265
|
+
"deviceManager.migrateDevice": {
|
|
242266
|
+
capName: "device-manager",
|
|
242267
|
+
capScope: "system",
|
|
242268
|
+
addonId: null,
|
|
242269
|
+
access: "create"
|
|
242270
|
+
},
|
|
241972
242271
|
"deviceManager.persistConfig": {
|
|
241973
242272
|
capName: "device-manager",
|
|
241974
242273
|
capScope: "system",
|
|
@@ -249275,6 +249574,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
|
|
|
249275
249574
|
},
|
|
249276
249575
|
deviceManager: {
|
|
249277
249576
|
allocateDeviceId: (input) => dispatch("deviceManager", "allocateDeviceId", "mutation", input),
|
|
249577
|
+
migrateDevice: (input) => dispatch("deviceManager", "migrateDevice", "mutation", input),
|
|
249278
249578
|
registerDevice: (input) => dispatch("deviceManager", "registerDevice", "mutation", input),
|
|
249279
249579
|
removeDevice: (input) => dispatch("deviceManager", "removeDevice", "mutation", input),
|
|
249280
249580
|
persistConfig: (input) => dispatch("deviceManager", "persistConfig", "mutation", input),
|