@camstack/addon-advanced-notifier 0.1.31 → 0.1.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/addon.js +413 -44
- package/dist/addon.js.map +1 -1
- package/dist/addon.mjs +413 -44
- package/dist/addon.mjs.map +1 -1
- package/package.json +1 -1
package/dist/addon.mjs
CHANGED
|
@@ -4779,6 +4779,16 @@ function record(keyType, valueType, params) {
|
|
|
4779
4779
|
...normalizeParams(params)
|
|
4780
4780
|
});
|
|
4781
4781
|
}
|
|
4782
|
+
function partialRecord(keyType, valueType, params) {
|
|
4783
|
+
const k = clone(keyType);
|
|
4784
|
+
k._zod.values = void 0;
|
|
4785
|
+
return new ZodRecord({
|
|
4786
|
+
type: "record",
|
|
4787
|
+
keyType: k,
|
|
4788
|
+
valueType,
|
|
4789
|
+
...normalizeParams(params)
|
|
4790
|
+
});
|
|
4791
|
+
}
|
|
4782
4792
|
const ZodEnum = /* @__PURE__ */ $constructor("ZodEnum", (inst, def) => {
|
|
4783
4793
|
$ZodEnum.init(inst, def);
|
|
4784
4794
|
ZodType.init(inst, def);
|
|
@@ -5055,6 +5065,37 @@ function _instanceof(cls, params = {}) {
|
|
|
5055
5065
|
};
|
|
5056
5066
|
return inst;
|
|
5057
5067
|
}
|
|
5068
|
+
const wiringProbeKindSchema = _enum(["singleton", "device", "widget"]);
|
|
5069
|
+
const wiringProbeResultSchema = object({
|
|
5070
|
+
capName: string(),
|
|
5071
|
+
kind: wiringProbeKindSchema,
|
|
5072
|
+
deviceId: number().optional(),
|
|
5073
|
+
reachable: boolean(),
|
|
5074
|
+
latencyMs: number(),
|
|
5075
|
+
error: string().optional()
|
|
5076
|
+
});
|
|
5077
|
+
const wiringAddonHealthSchema = object({
|
|
5078
|
+
addonId: string(),
|
|
5079
|
+
caps: array(wiringProbeResultSchema).readonly(),
|
|
5080
|
+
widgets: array(wiringProbeResultSchema).readonly()
|
|
5081
|
+
});
|
|
5082
|
+
const wiringNodeHealthSchema = object({
|
|
5083
|
+
nodeId: string(),
|
|
5084
|
+
addons: array(wiringAddonHealthSchema).readonly()
|
|
5085
|
+
});
|
|
5086
|
+
object({
|
|
5087
|
+
/** True only when every probed target is reachable. */
|
|
5088
|
+
ok: boolean(),
|
|
5089
|
+
/** True when at least one target is unreachable. */
|
|
5090
|
+
degraded: boolean(),
|
|
5091
|
+
checkedAt: string(),
|
|
5092
|
+
nodes: array(wiringNodeHealthSchema).readonly(),
|
|
5093
|
+
summary: object({
|
|
5094
|
+
total: number(),
|
|
5095
|
+
reachable: number(),
|
|
5096
|
+
unreachable: number()
|
|
5097
|
+
})
|
|
5098
|
+
});
|
|
5058
5099
|
const MODEL_FORMATS = ["onnx", "coreml", "openvino", "tflite", "pt"];
|
|
5059
5100
|
const WELL_KNOWN_TABS = [
|
|
5060
5101
|
{ id: "overview", label: "Overview", icon: "layout-dashboard", order: -10 },
|
|
@@ -6574,7 +6615,7 @@ const SpatialDetectionSchema = object({
|
|
|
6574
6615
|
bbox: BoundingBoxSchema
|
|
6575
6616
|
});
|
|
6576
6617
|
const AudioChunkInputSchema = object({
|
|
6577
|
-
data: _instanceof(
|
|
6618
|
+
data: _instanceof(Uint8Array),
|
|
6578
6619
|
sampleRate: number(),
|
|
6579
6620
|
channels: number(),
|
|
6580
6621
|
timestamp: number(),
|
|
@@ -7245,7 +7286,23 @@ const RunnerCameraConfigSchema = object({
|
|
|
7245
7286
|
* whenever its `zones` device-state slice changes, so the runner's
|
|
7246
7287
|
* copy stays in sync. Empty array → no zone filtering.
|
|
7247
7288
|
*/
|
|
7248
|
-
zones: array(ZoneSchema).readonly().default([])
|
|
7289
|
+
zones: array(ZoneSchema).readonly().default([]),
|
|
7290
|
+
/**
|
|
7291
|
+
* When true (default) and the camera's `motionSources` contains only
|
|
7292
|
+
* `'onboard'`, the runner dynamically opens the same WASM frame-diff
|
|
7293
|
+
* motion-frames subscription on each `MotionOnMotionChanged
|
|
7294
|
+
* source:'onboard'` event and tears it down after `motionCooldownMs`.
|
|
7295
|
+
* This causes `runMotionAnalysis` to emit `MotionZonesRaw` /
|
|
7296
|
+
* `MotionAnalysis` during active-motion windows without the
|
|
7297
|
+
* substream being held open continuously.
|
|
7298
|
+
*
|
|
7299
|
+
* Set to `false` to disable the dynamic analyzer for this camera
|
|
7300
|
+
* (e.g. very low-bandwidth links where the extra substream is
|
|
7301
|
+
* undesirable). Has no effect when `motionSources` already includes
|
|
7302
|
+
* `'analyzer'` — the analyzer runs continuously in that case and
|
|
7303
|
+
* this gate is bypassed.
|
|
7304
|
+
*/
|
|
7305
|
+
onboardMotionDrivesAnalyzer: boolean().default(true)
|
|
7249
7306
|
});
|
|
7250
7307
|
const RunnerLocalLoadSchema = object({
|
|
7251
7308
|
/** Moleculer node id of this runner instance. */
|
|
@@ -7382,22 +7439,68 @@ MotionTriggerStatusSchema.extend({
|
|
|
7382
7439
|
}) }
|
|
7383
7440
|
}
|
|
7384
7441
|
});
|
|
7442
|
+
const MaskPointSchema = object({
|
|
7443
|
+
x: number(),
|
|
7444
|
+
y: number()
|
|
7445
|
+
});
|
|
7446
|
+
const MaskRectShapeSchema = object({
|
|
7447
|
+
kind: literal("rect"),
|
|
7448
|
+
x: number(),
|
|
7449
|
+
y: number(),
|
|
7450
|
+
width: number(),
|
|
7451
|
+
height: number()
|
|
7452
|
+
});
|
|
7453
|
+
const MaskPolygonShapeSchema = object({
|
|
7454
|
+
kind: literal("polygon"),
|
|
7455
|
+
points: array(MaskPointSchema)
|
|
7456
|
+
});
|
|
7457
|
+
const MaskGridShapeSchema = object({
|
|
7458
|
+
kind: literal("grid"),
|
|
7459
|
+
gridWidth: number(),
|
|
7460
|
+
gridHeight: number(),
|
|
7461
|
+
cells: array(boolean())
|
|
7462
|
+
});
|
|
7463
|
+
const MaskLineShapeSchema = object({
|
|
7464
|
+
kind: literal("line"),
|
|
7465
|
+
points: array(MaskPointSchema)
|
|
7466
|
+
});
|
|
7467
|
+
discriminatedUnion("kind", [
|
|
7468
|
+
MaskRectShapeSchema,
|
|
7469
|
+
MaskPolygonShapeSchema,
|
|
7470
|
+
MaskGridShapeSchema,
|
|
7471
|
+
MaskLineShapeSchema
|
|
7472
|
+
]);
|
|
7473
|
+
const MaskShapeKindSchema = _enum(["rect", "polygon", "grid", "line"]);
|
|
7474
|
+
const MaskPolygonVerticesSchema = object({
|
|
7475
|
+
min: number(),
|
|
7476
|
+
max: number()
|
|
7477
|
+
});
|
|
7478
|
+
const MaskGridDimsSchema = object({
|
|
7479
|
+
width: number(),
|
|
7480
|
+
height: number()
|
|
7481
|
+
});
|
|
7482
|
+
const MotionZoneRegionSchema = object({
|
|
7483
|
+
id: number(),
|
|
7484
|
+
enabled: boolean(),
|
|
7485
|
+
shape: MaskGridShapeSchema
|
|
7486
|
+
});
|
|
7385
7487
|
object({
|
|
7386
7488
|
enabled: boolean(),
|
|
7387
7489
|
sensitivity: number(),
|
|
7388
|
-
/**
|
|
7389
|
-
|
|
7490
|
+
/** Grid region(s). Today exactly one `grid` shape. */
|
|
7491
|
+
regions: array(MotionZoneRegionSchema),
|
|
7390
7492
|
lastFetchedAt: number()
|
|
7391
7493
|
});
|
|
7392
7494
|
const MotionZoneOptionsSchema = object({
|
|
7393
|
-
|
|
7394
|
-
|
|
7495
|
+
maxRegions: number(),
|
|
7496
|
+
supportedShapes: array(MaskShapeKindSchema),
|
|
7497
|
+
grid: MaskGridDimsSchema,
|
|
7395
7498
|
sensitivity: object({ min: number(), max: number(), step: number() })
|
|
7396
7499
|
});
|
|
7397
7500
|
const MotionZonePatchSchema = object({
|
|
7398
7501
|
enabled: boolean().optional(),
|
|
7399
7502
|
sensitivity: number().optional(),
|
|
7400
|
-
|
|
7503
|
+
regions: array(MotionZoneRegionSchema).optional()
|
|
7401
7504
|
});
|
|
7402
7505
|
({
|
|
7403
7506
|
deviceTypes: [DeviceType.Camera],
|
|
@@ -7410,6 +7513,102 @@ const MotionZonePatchSchema = object({
|
|
|
7410
7513
|
)
|
|
7411
7514
|
}
|
|
7412
7515
|
});
|
|
7516
|
+
const NativeObjectClassEnum = _enum([
|
|
7517
|
+
"person",
|
|
7518
|
+
"vehicle",
|
|
7519
|
+
"animal",
|
|
7520
|
+
"face",
|
|
7521
|
+
"package",
|
|
7522
|
+
"other"
|
|
7523
|
+
]);
|
|
7524
|
+
const NativeDetectionSchema = object({
|
|
7525
|
+
class: NativeObjectClassEnum,
|
|
7526
|
+
timestamp: number(),
|
|
7527
|
+
/** Firmware-provided confidence [0..1]. Reolink pushes don't carry it → undefined. */
|
|
7528
|
+
confidence: number().min(0).max(1).optional()
|
|
7529
|
+
});
|
|
7530
|
+
const NativeObjectDetectionStatusSchema = object({
|
|
7531
|
+
/**
|
|
7532
|
+
* Last observed instance per class. Missing entries mean the class
|
|
7533
|
+
* is supported but nothing has been seen since the provider started.
|
|
7534
|
+
*
|
|
7535
|
+
* MUST be a partial record: providers seed an empty `{}` on cold-start
|
|
7536
|
+
* and write one class at a time as detections arrive. In Zod 4
|
|
7537
|
+
* `z.record(enum, …)` is EXHAUSTIVE (requires every enum key), so a
|
|
7538
|
+
* partial write throws "expected object, received undefined" for every
|
|
7539
|
+
* unseen class. `z.partialRecord` keeps the enum-key narrowing while
|
|
7540
|
+
* allowing the sparse shape the providers actually write.
|
|
7541
|
+
*/
|
|
7542
|
+
lastByClass: partialRecord(NativeObjectClassEnum, NativeDetectionSchema.nullable()),
|
|
7543
|
+
/** Classes the firmware is capable of detecting — enumerated at device register. */
|
|
7544
|
+
supportedClasses: array(NativeObjectClassEnum).readonly(),
|
|
7545
|
+
/**
|
|
7546
|
+
* Whether forwarding of onboard AI detections is enabled for this device.
|
|
7547
|
+
* Default true (on cold-start) — detections flow unconditionally before
|
|
7548
|
+
* the toggle is saved, so defaulting true preserves existing behaviour.
|
|
7549
|
+
*/
|
|
7550
|
+
enabled: boolean()
|
|
7551
|
+
});
|
|
7552
|
+
NativeObjectDetectionStatusSchema.extend({
|
|
7553
|
+
/** Required by createRuntimeStateBridge — epoch ms of last refresh. */
|
|
7554
|
+
lastFetchedAt: number()
|
|
7555
|
+
});
|
|
7556
|
+
({
|
|
7557
|
+
deviceTypes: [DeviceType.Camera],
|
|
7558
|
+
methods: {
|
|
7559
|
+
setEnabled: method(
|
|
7560
|
+
object({ deviceId: number(), enabled: boolean() }),
|
|
7561
|
+
_void(),
|
|
7562
|
+
{ kind: "mutation", auth: "admin" }
|
|
7563
|
+
)
|
|
7564
|
+
},
|
|
7565
|
+
events: {
|
|
7566
|
+
onDetected: { data: object({
|
|
7567
|
+
deviceId: number(),
|
|
7568
|
+
detection: NativeDetectionSchema
|
|
7569
|
+
}) }
|
|
7570
|
+
}
|
|
7571
|
+
});
|
|
7572
|
+
const PrivacyMaskShapeSchema = discriminatedUnion("kind", [
|
|
7573
|
+
MaskRectShapeSchema,
|
|
7574
|
+
MaskPolygonShapeSchema
|
|
7575
|
+
]);
|
|
7576
|
+
const PrivacyMaskRegionSchema = object({
|
|
7577
|
+
/** Slot id, 0-based. Stable across read/write. */
|
|
7578
|
+
id: number(),
|
|
7579
|
+
/** Whether this zone is active (blanked out by the camera). */
|
|
7580
|
+
enabled: boolean(),
|
|
7581
|
+
shape: PrivacyMaskShapeSchema
|
|
7582
|
+
});
|
|
7583
|
+
object({
|
|
7584
|
+
enabled: boolean(),
|
|
7585
|
+
/** Active zones (normalized 0..1). Length ≤ maxRegions. */
|
|
7586
|
+
regions: array(PrivacyMaskRegionSchema),
|
|
7587
|
+
lastFetchedAt: number()
|
|
7588
|
+
});
|
|
7589
|
+
const PrivacyMaskOptionsSchema = object({
|
|
7590
|
+
/** Maximum number of supported zones. */
|
|
7591
|
+
maxRegions: number(),
|
|
7592
|
+
/** Shape kinds this camera accepts — Reolink: ['rect']; Hikvision: ['rect','polygon']. */
|
|
7593
|
+
supportedShapes: array(MaskShapeKindSchema),
|
|
7594
|
+
/** Polygon vertex bounds when 'polygon' is supported (Hikvision: {min:4,max:4}). */
|
|
7595
|
+
polygonVertices: MaskPolygonVerticesSchema.optional()
|
|
7596
|
+
});
|
|
7597
|
+
const PrivacyMaskPatchSchema = object({
|
|
7598
|
+
enabled: boolean().optional(),
|
|
7599
|
+
regions: array(PrivacyMaskRegionSchema).optional()
|
|
7600
|
+
});
|
|
7601
|
+
({
|
|
7602
|
+
deviceTypes: [DeviceType.Camera],
|
|
7603
|
+
methods: {
|
|
7604
|
+
getOptions: method(object({ deviceId: number() }), PrivacyMaskOptionsSchema),
|
|
7605
|
+
setMask: method(
|
|
7606
|
+
object({ deviceId: number(), patch: PrivacyMaskPatchSchema }),
|
|
7607
|
+
_void(),
|
|
7608
|
+
{ kind: "mutation", auth: "admin" }
|
|
7609
|
+
)
|
|
7610
|
+
}
|
|
7611
|
+
});
|
|
7413
7612
|
const AutotrackTargetTypeSchema = string().describe("Vendor target string (people/vehicle/pet); empty = camera default");
|
|
7414
7613
|
const PtzAutotrackSettingsSchema = object({
|
|
7415
7614
|
targetType: AutotrackTargetTypeSchema,
|
|
@@ -7928,7 +8127,8 @@ const SettingsUpdateResultSchema = object({
|
|
|
7928
8127
|
object({
|
|
7929
8128
|
addonId: string(),
|
|
7930
8129
|
nodeId: string().optional(),
|
|
7931
|
-
overlay: record(string(), unknown()).optional()
|
|
8130
|
+
overlay: record(string(), unknown()).optional(),
|
|
8131
|
+
cap: string().optional()
|
|
7932
8132
|
}),
|
|
7933
8133
|
SettingsSchemaWithValuesSchema.nullable()
|
|
7934
8134
|
),
|
|
@@ -8659,7 +8859,14 @@ const OauthIntegrationDescriptorSchema = object({
|
|
|
8659
8859
|
/** Allowed redirect_uri prefixes. /api/oauth2/authorize rejects any
|
|
8660
8860
|
* redirect_uri that does not start with one of these. Required —
|
|
8661
8861
|
* an empty list means the integration can never complete linking. */
|
|
8662
|
-
allowedRedirectPrefixes: array(string()).min(1)
|
|
8862
|
+
allowedRedirectPrefixes: array(string()).min(1),
|
|
8863
|
+
/** Optional public origin (no trailing slash) that this integration's
|
|
8864
|
+
* issued codes/tokens should carry as the `hubUrl` claim — typically the
|
|
8865
|
+
* operator-selected external-access endpoint resolved by the addon. When
|
|
8866
|
+
* present, /api/oauth2/authorize bakes THIS into the code instead of the
|
|
8867
|
+
* hub-global `publicHubUrl()`, so a forked exporter addon (which can't set
|
|
8868
|
+
* the hub's env) drives the claim that its cloud Lambda routes back on. */
|
|
8869
|
+
hubUrl: string().optional()
|
|
8663
8870
|
});
|
|
8664
8871
|
({
|
|
8665
8872
|
methods: {
|
|
@@ -9273,7 +9480,20 @@ const WebrtcStreamChoiceSchema = object({
|
|
|
9273
9480
|
object({
|
|
9274
9481
|
deviceId: number().int().nonnegative(),
|
|
9275
9482
|
target: WebrtcStreamTargetSchema,
|
|
9276
|
-
hints: webrtcClientHintsSchema.optional()
|
|
9483
|
+
hints: webrtcClientHintsSchema.optional(),
|
|
9484
|
+
/**
|
|
9485
|
+
* SERVER-INJECTED — NOT a client hint. The hub layer that holds
|
|
9486
|
+
* the tRPC request context (and therefore the client IP) sets
|
|
9487
|
+
* this to `true` when the viewer's source IP is non-LAN
|
|
9488
|
+
* (4G/CGNAT/internet). The broker then forces TURN-relay-only
|
|
9489
|
+
* ICE for the session so a CGNAT client (which can only offer a
|
|
9490
|
+
* relay candidate) gets a clean relay↔relay media path instead
|
|
9491
|
+
* of werift nominating a dead host/hairpin-srflx pair. LAN
|
|
9492
|
+
* clients leave this absent/false and keep the low-latency
|
|
9493
|
+
* direct (host/srflx) path. Clients MUST NOT send this — the
|
|
9494
|
+
* server overwrites it from the request context.
|
|
9495
|
+
*/
|
|
9496
|
+
relayOnly: boolean().optional()
|
|
9277
9497
|
}),
|
|
9278
9498
|
object({ sessionId: string(), sdpOffer: string() }),
|
|
9279
9499
|
{ kind: "mutation" }
|
|
@@ -9296,7 +9516,22 @@ const WebrtcStreamChoiceSchema = object({
|
|
|
9296
9516
|
deviceId: number().int().nonnegative(),
|
|
9297
9517
|
target: WebrtcStreamTargetSchema.optional(),
|
|
9298
9518
|
sdpOffer: string(),
|
|
9299
|
-
sessionId: string().optional()
|
|
9519
|
+
sessionId: string().optional(),
|
|
9520
|
+
/**
|
|
9521
|
+
* Force TURN-relay-only ICE for this session. Two kinds of caller
|
|
9522
|
+
* set it:
|
|
9523
|
+
* - A cloud peer like Alexa's RTCSessionController (reachable
|
|
9524
|
+
* only via TURN, never our host/srflx behind NAT) passes
|
|
9525
|
+
* `true` from its own trusted addon context.
|
|
9526
|
+
* - The hub injects it for browser client-offer viewers from the
|
|
9527
|
+
* request's source IP (non-LAN ⇒ true), exactly as it does for
|
|
9528
|
+
* `createSession`.
|
|
9529
|
+
* A LAN/Tailscale browser doing client-offer passthrough leaves it
|
|
9530
|
+
* absent/false so a direct host pair carries full native quality.
|
|
9531
|
+
* Untrusted browser clients MUST NOT send it — the hub overwrites
|
|
9532
|
+
* it from the request context.
|
|
9533
|
+
*/
|
|
9534
|
+
relayOnly: boolean().optional()
|
|
9300
9535
|
}),
|
|
9301
9536
|
object({ sessionId: string(), sdpAnswer: string() }),
|
|
9302
9537
|
{ kind: "mutation" }
|
|
@@ -9310,6 +9545,46 @@ const WebrtcStreamChoiceSchema = object({
|
|
|
9310
9545
|
_void(),
|
|
9311
9546
|
{ kind: "mutation" }
|
|
9312
9547
|
),
|
|
9548
|
+
/**
|
|
9549
|
+
* Trickle ICE — add a remote (client) ICE candidate to a live session.
|
|
9550
|
+
* Lets the client send its SDP offer/answer IMMEDIATELY (before ICE
|
|
9551
|
+
* gathering finishes) and deliver candidates as they arrive, so the
|
|
9552
|
+
* connection establishes in ~0s instead of waiting for full gathering.
|
|
9553
|
+
* The dual of `getIceCandidates`. Mirrors Scrypted's signaling.
|
|
9554
|
+
*/
|
|
9555
|
+
addIceCandidate: method(
|
|
9556
|
+
object({
|
|
9557
|
+
deviceId: number().int().nonnegative(),
|
|
9558
|
+
sessionId: string(),
|
|
9559
|
+
candidate: string(),
|
|
9560
|
+
sdpMid: string().nullable().optional(),
|
|
9561
|
+
sdpMLineIndex: number().int().nullable().optional()
|
|
9562
|
+
}),
|
|
9563
|
+
_void(),
|
|
9564
|
+
{ kind: "mutation" }
|
|
9565
|
+
),
|
|
9566
|
+
/**
|
|
9567
|
+
* Trickle ICE — poll the server's gathered ICE candidates for a session.
|
|
9568
|
+
* The server answers immediately (no gathering wait) and the client polls
|
|
9569
|
+
* this to receive host/srflx/relay candidates as werift gathers them,
|
|
9570
|
+
* adding each to its PeerConnection. Returns all candidates gathered so
|
|
9571
|
+
* far; the client dedupes. `done` flips true once gathering completes.
|
|
9572
|
+
*/
|
|
9573
|
+
getIceCandidates: method(
|
|
9574
|
+
object({
|
|
9575
|
+
deviceId: number().int().nonnegative(),
|
|
9576
|
+
sessionId: string()
|
|
9577
|
+
}),
|
|
9578
|
+
object({
|
|
9579
|
+
candidates: array(object({
|
|
9580
|
+
candidate: string(),
|
|
9581
|
+
sdpMid: string().nullable(),
|
|
9582
|
+
sdpMLineIndex: number().int().nullable()
|
|
9583
|
+
})),
|
|
9584
|
+
done: boolean()
|
|
9585
|
+
}),
|
|
9586
|
+
{ kind: "query" }
|
|
9587
|
+
),
|
|
9313
9588
|
closeSession: method(
|
|
9314
9589
|
object({
|
|
9315
9590
|
deviceId: number().int().nonnegative(),
|
|
@@ -10988,6 +11263,9 @@ const UpdateConfigInput = object({
|
|
|
10988
11263
|
({
|
|
10989
11264
|
deviceTypes: [DeviceType.Camera]
|
|
10990
11265
|
});
|
|
11266
|
+
({
|
|
11267
|
+
deviceTypes: [DeviceType.Camera]
|
|
11268
|
+
});
|
|
10991
11269
|
const TrackStateSchema = _enum(["new", "entered", "left", "moving", "idle"]);
|
|
10992
11270
|
const EventKindSchema = _enum(["motion", "object", "audio"]);
|
|
10993
11271
|
const TrackPositionSchema = object({
|
|
@@ -11815,36 +12093,28 @@ const IntercomStatusSchema = object({
|
|
|
11815
12093
|
}) }
|
|
11816
12094
|
}
|
|
11817
12095
|
});
|
|
11818
|
-
const
|
|
11819
|
-
|
|
11820
|
-
|
|
11821
|
-
|
|
11822
|
-
|
|
11823
|
-
|
|
11824
|
-
|
|
11825
|
-
|
|
11826
|
-
|
|
11827
|
-
|
|
11828
|
-
|
|
11829
|
-
|
|
11830
|
-
|
|
11831
|
-
|
|
11832
|
-
object({
|
|
11833
|
-
/**
|
|
11834
|
-
* Last observed instance per class. Undefined entries mean the class
|
|
11835
|
-
* is supported but nothing has been seen since the provider started.
|
|
11836
|
-
*/
|
|
11837
|
-
lastByClass: record(NativeObjectClassEnum, NativeDetectionSchema.nullable()),
|
|
11838
|
-
/** Classes the firmware is capable of detecting — enumerated at device register. */
|
|
11839
|
-
supportedClasses: array(NativeObjectClassEnum).readonly()
|
|
12096
|
+
const CamStreamDescriptorSchema = object({
|
|
12097
|
+
camStreamId: string().min(1),
|
|
12098
|
+
kind: CamStreamKindSchema,
|
|
12099
|
+
url: string().optional(),
|
|
12100
|
+
codec: string().optional(),
|
|
12101
|
+
resolution: CamStreamResolutionSchema.optional(),
|
|
12102
|
+
fps: number().positive().optional(),
|
|
12103
|
+
label: string().optional(),
|
|
12104
|
+
/** Device-level features (e.g. `battery-operated`) — drives broker policy. */
|
|
12105
|
+
deviceFeatures: array(string()).optional(),
|
|
12106
|
+
/** Eligible for automatic profile assignment. Absent = `true`. */
|
|
12107
|
+
autoEligible: boolean().optional(),
|
|
12108
|
+
/** Transport-specific opaque metadata (e.g. rfc4571 SDP). */
|
|
12109
|
+
metadata: record(string(), unknown()).optional()
|
|
11840
12110
|
});
|
|
11841
12111
|
({
|
|
11842
12112
|
deviceTypes: [DeviceType.Camera],
|
|
11843
|
-
|
|
11844
|
-
|
|
11845
|
-
deviceId: number(),
|
|
11846
|
-
|
|
11847
|
-
|
|
12113
|
+
methods: {
|
|
12114
|
+
getCatalog: method(
|
|
12115
|
+
object({ deviceId: number().int().nonnegative() }),
|
|
12116
|
+
array(CamStreamDescriptorSchema).readonly()
|
|
12117
|
+
)
|
|
11848
12118
|
}
|
|
11849
12119
|
});
|
|
11850
12120
|
const ModelFormatSchema = _enum(MODEL_FORMATS);
|
|
@@ -13052,7 +13322,8 @@ const PackageUpdateSchema = object({
|
|
|
13052
13322
|
currentVersion: string(),
|
|
13053
13323
|
latestVersion: string(),
|
|
13054
13324
|
category: _enum(["addon", "core"]),
|
|
13055
|
-
requiresRestart: boolean()
|
|
13325
|
+
requiresRestart: boolean(),
|
|
13326
|
+
isSystem: boolean()
|
|
13056
13327
|
});
|
|
13057
13328
|
const PackageVersionInfoSchema = object({
|
|
13058
13329
|
version: string(),
|
|
@@ -13085,6 +13356,42 @@ const UpdateFrameworkPackageResultSchema = object({
|
|
|
13085
13356
|
/** Ms-epoch the server scheduled its self-restart. */
|
|
13086
13357
|
restartingAt: number()
|
|
13087
13358
|
});
|
|
13359
|
+
const BulkUpdateItemStatusSchema = _enum([
|
|
13360
|
+
"queued",
|
|
13361
|
+
"updating",
|
|
13362
|
+
"done",
|
|
13363
|
+
"done-pending-restart",
|
|
13364
|
+
"failed"
|
|
13365
|
+
]);
|
|
13366
|
+
const BulkUpdateItemSchema = object({
|
|
13367
|
+
name: string(),
|
|
13368
|
+
isSystem: boolean(),
|
|
13369
|
+
fromVersion: string(),
|
|
13370
|
+
toVersion: string(),
|
|
13371
|
+
status: BulkUpdateItemStatusSchema,
|
|
13372
|
+
error: string().optional(),
|
|
13373
|
+
startedAtMs: number().optional(),
|
|
13374
|
+
completedAtMs: number().optional()
|
|
13375
|
+
});
|
|
13376
|
+
const BulkUpdatePhaseSchema = _enum([
|
|
13377
|
+
"regular",
|
|
13378
|
+
"system",
|
|
13379
|
+
"restarting",
|
|
13380
|
+
"finalizing"
|
|
13381
|
+
]);
|
|
13382
|
+
const BulkUpdateStateSchema = object({
|
|
13383
|
+
id: string(),
|
|
13384
|
+
nodeId: string(),
|
|
13385
|
+
startedAtMs: number(),
|
|
13386
|
+
completedAtMs: number().optional(),
|
|
13387
|
+
total: number(),
|
|
13388
|
+
completed: number(),
|
|
13389
|
+
failed: number(),
|
|
13390
|
+
current: string().nullable(),
|
|
13391
|
+
phase: BulkUpdatePhaseSchema,
|
|
13392
|
+
cancelled: boolean(),
|
|
13393
|
+
items: array(BulkUpdateItemSchema).readonly()
|
|
13394
|
+
});
|
|
13088
13395
|
const FrameworkPackageStatusSchema = object({
|
|
13089
13396
|
packageName: string(),
|
|
13090
13397
|
currentVersion: string(),
|
|
@@ -13222,7 +13529,7 @@ const CustomActionInputSchema = object({
|
|
|
13222
13529
|
getLastRestart: method(
|
|
13223
13530
|
_void(),
|
|
13224
13531
|
object({
|
|
13225
|
-
kind: _enum(["framework-update", "manual", "system"]),
|
|
13532
|
+
kind: _enum(["framework-update", "manual", "system", "framework-bulk-update"]),
|
|
13226
13533
|
packageName: string().optional(),
|
|
13227
13534
|
fromVersion: string().optional(),
|
|
13228
13535
|
toVersion: string().optional(),
|
|
@@ -13312,11 +13619,70 @@ const CustomActionInputSchema = object({
|
|
|
13312
13619
|
updateFrameworkPackage: method(
|
|
13313
13620
|
object({
|
|
13314
13621
|
packageName: string().min(1),
|
|
13315
|
-
version: string().optional()
|
|
13622
|
+
version: string().optional(),
|
|
13623
|
+
deferRestart: boolean().optional()
|
|
13316
13624
|
}),
|
|
13317
13625
|
UpdateFrameworkPackageResultSchema,
|
|
13318
13626
|
{ kind: "mutation", auth: "admin" }
|
|
13319
13627
|
),
|
|
13628
|
+
/**
|
|
13629
|
+
* Kicks off a server-side bulk update operation and returns the bulk
|
|
13630
|
+
* id immediately. The operation runs asynchronously; observe progress
|
|
13631
|
+
* via the `AddonsBulkUpdateProgress` event or `getBulkUpdateState`.
|
|
13632
|
+
* Items with `isSystem: true` use `deferRestart` — the hub restarts
|
|
13633
|
+
* ONCE at the end of the system phase, after all system packages are
|
|
13634
|
+
* installed.
|
|
13635
|
+
*
|
|
13636
|
+
* `items[].version` is REQUIRED — callers must pass the resolved
|
|
13637
|
+
* version from `listUpdates`. There is no `'latest'` default here
|
|
13638
|
+
* (unlike `updatePackage`) to guarantee deterministic bulk rolls.
|
|
13639
|
+
*/
|
|
13640
|
+
startBulkUpdate: method(
|
|
13641
|
+
object({
|
|
13642
|
+
nodeId: string(),
|
|
13643
|
+
items: array(object({
|
|
13644
|
+
name: string(),
|
|
13645
|
+
version: string(),
|
|
13646
|
+
isSystem: boolean()
|
|
13647
|
+
})).readonly()
|
|
13648
|
+
}),
|
|
13649
|
+
object({ id: string() }),
|
|
13650
|
+
{ kind: "mutation", auth: "admin" }
|
|
13651
|
+
),
|
|
13652
|
+
/**
|
|
13653
|
+
* Returns the current state of a bulk update by id.
|
|
13654
|
+
* Returns `null` if the id is unknown or has been auto-cleaned
|
|
13655
|
+
* (5 minutes after `completedAt` the record is evicted from memory).
|
|
13656
|
+
*/
|
|
13657
|
+
getBulkUpdateState: method(
|
|
13658
|
+
object({ id: string() }),
|
|
13659
|
+
BulkUpdateStateSchema.nullable(),
|
|
13660
|
+
{ auth: "admin" }
|
|
13661
|
+
),
|
|
13662
|
+
/**
|
|
13663
|
+
* Cancels an in-flight bulk update. The update loop exits after the
|
|
13664
|
+
* currently-processing item completes — cancellation is not
|
|
13665
|
+
* instantaneous. Has no effect once the `restarting` phase has been
|
|
13666
|
+
* entered (the hub is already shutting down at that point).
|
|
13667
|
+
* Returns `{ cancelled: false }` if the id is unknown, the operation
|
|
13668
|
+
* has already completed, or the `restarting` phase is active.
|
|
13669
|
+
*/
|
|
13670
|
+
cancelBulkUpdate: method(
|
|
13671
|
+
object({ id: string() }),
|
|
13672
|
+
object({ cancelled: boolean() }),
|
|
13673
|
+
{ kind: "mutation", auth: "admin" }
|
|
13674
|
+
),
|
|
13675
|
+
/**
|
|
13676
|
+
* Lists all currently active (non-completed) bulk updates.
|
|
13677
|
+
* If `nodeId` is provided, filters to only bulk updates targeting
|
|
13678
|
+
* that node. Useful for restoring an in-progress banner on a fresh
|
|
13679
|
+
* page load when the UI reconnects mid-operation.
|
|
13680
|
+
*/
|
|
13681
|
+
listActiveBulkUpdates: method(
|
|
13682
|
+
object({ nodeId: string().optional() }),
|
|
13683
|
+
array(BulkUpdateStateSchema).readonly(),
|
|
13684
|
+
{ auth: "admin" }
|
|
13685
|
+
),
|
|
13320
13686
|
getVersions: method(
|
|
13321
13687
|
object({ name: string() }),
|
|
13322
13688
|
array(PackageVersionInfoSchema).readonly()
|
|
@@ -13444,6 +13810,7 @@ var EventCategory = /* @__PURE__ */ ((EventCategory2) => {
|
|
|
13444
13810
|
EventCategory2["StreamBrokerOnCamStreamDemand"] = "stream-broker.onCamStreamDemand";
|
|
13445
13811
|
EventCategory2["StreamBrokerOnCamStreamIdle"] = "stream-broker.onCamStreamIdle";
|
|
13446
13812
|
EventCategory2["StreamBrokerOnRequestStreamSourceRefresh"] = "stream-broker.onRequestStreamSourceRefresh";
|
|
13813
|
+
EventCategory2["StreamParamsChanged"] = "stream-params.changed";
|
|
13447
13814
|
EventCategory2["DeviceStateChanged"] = "device.state-changed";
|
|
13448
13815
|
EventCategory2["BatteryOnStatusChanged"] = "battery.onStatusChanged";
|
|
13449
13816
|
EventCategory2["DoorbellOnPressed"] = "doorbell.onPressed";
|
|
@@ -13491,6 +13858,7 @@ var EventCategory = /* @__PURE__ */ ((EventCategory2) => {
|
|
|
13491
13858
|
EventCategory2["NetworkTunnelStarted"] = "network.tunnel.started";
|
|
13492
13859
|
EventCategory2["NetworkTunnelStopped"] = "network.tunnel.stopped";
|
|
13493
13860
|
EventCategory2["LocalNetworkChanged"] = "network.local.changed";
|
|
13861
|
+
EventCategory2["MeshNetworkChanged"] = "network.mesh.changed";
|
|
13494
13862
|
EventCategory2["BackupCompleted"] = "backup.completed";
|
|
13495
13863
|
EventCategory2["BackupRestored"] = "backup.restored";
|
|
13496
13864
|
EventCategory2["NotificationDispatched"] = "notification.dispatched";
|
|
@@ -13501,6 +13869,7 @@ var EventCategory = /* @__PURE__ */ ((EventCategory2) => {
|
|
|
13501
13869
|
EventCategory2["DeviceAwake"] = "device.awake";
|
|
13502
13870
|
EventCategory2["DeviceSleeping"] = "device.sleeping";
|
|
13503
13871
|
EventCategory2["RetentionCleanup"] = "retention.cleanup";
|
|
13872
|
+
EventCategory2["AddonsBulkUpdateProgress"] = "addons.bulk-update-progress";
|
|
13504
13873
|
return EventCategory2;
|
|
13505
13874
|
})(EventCategory || {});
|
|
13506
13875
|
function createEvent(category, source, data) {
|
|
@@ -13650,7 +14019,7 @@ class BaseAddon {
|
|
|
13650
14019
|
}
|
|
13651
14020
|
// ── Settings schemas (override to provide UI) ─────────────────────────
|
|
13652
14021
|
/** Override to provide global-level settings UI schema. */
|
|
13653
|
-
globalSettingsSchema() {
|
|
14022
|
+
globalSettingsSchema(_cap) {
|
|
13654
14023
|
return null;
|
|
13655
14024
|
}
|
|
13656
14025
|
/** Override to provide device-level settings UI schema. */
|
|
@@ -13664,8 +14033,8 @@ class BaseAddon {
|
|
|
13664
14033
|
// blob and every addon used exactly one of them; the distinction was
|
|
13665
14034
|
// never semantically load-bearing. `global` won because it was the
|
|
13666
14035
|
// widely-used one and the name reads naturally (per-node addon config).
|
|
13667
|
-
async getGlobalSettings(overlay) {
|
|
13668
|
-
const schema = this.globalSettingsSchema();
|
|
14036
|
+
async getGlobalSettings(overlay, cap) {
|
|
14037
|
+
const schema = this.globalSettingsSchema(cap);
|
|
13669
14038
|
if (!schema) return { sections: [] };
|
|
13670
14039
|
const raw = await this._ctx?.settings?.readAddonStore() ?? {};
|
|
13671
14040
|
return hydrateSchema(schema, overlay ? { ...raw, ...overlay } : raw);
|