@camstack/addon-provider-amcrest 0.2.21 → 0.2.22
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 +179 -44
- package/dist/addon.mjs +179 -44
- package/package.json +1 -1
package/dist/addon.js
CHANGED
|
@@ -4,7 +4,7 @@ var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).expor
|
|
|
4
4
|
//#endregion
|
|
5
5
|
let node_crypto = require("node:crypto");
|
|
6
6
|
let node_os = require("node:os");
|
|
7
|
-
//#region ../types/dist/event-category-
|
|
7
|
+
//#region ../types/dist/event-category-XfKNtfCc.mjs
|
|
8
8
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
9
9
|
EventCategory["SystemBoot"] = "system.boot";
|
|
10
10
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -21,9 +21,10 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
21
21
|
EventCategory["SystemRestartCompleted"] = "system.restart-completed";
|
|
22
22
|
/**
|
|
23
23
|
* A newer addon or server-root package version was found by the
|
|
24
|
-
* authoritative registry check. Emitted once
|
|
25
|
-
* `(
|
|
26
|
-
*
|
|
24
|
+
* authoritative registry check. Emitted once when any observed
|
|
25
|
+
* `latestVersion` changes (or a package/node first appears behind);
|
|
26
|
+
* the payload carries the full currently-available list. Repeated
|
|
27
|
+
* polling of the same latests is silent.
|
|
27
28
|
*/
|
|
28
29
|
EventCategory["UpdateAvailable"] = "update.available";
|
|
29
30
|
/**
|
|
@@ -42,6 +43,22 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
42
43
|
EventCategory["AddonInstalled"] = "addon.installed";
|
|
43
44
|
EventCategory["AddonUninstalled"] = "addon.uninstalled";
|
|
44
45
|
EventCategory["AddonCrashed"] = "addon.crashed";
|
|
46
|
+
/**
|
|
47
|
+
* A RUNNER the D6 crash circuit-breaker gave up on — terminal.
|
|
48
|
+
*
|
|
49
|
+
* `AddonCrashed` is the routine, self-healing fact ("it crashed; it is being
|
|
50
|
+
* respawned"); this is the one that never resolves itself. Emitted exactly
|
|
51
|
+
* once per trip, by `process-service.ts`, carrying the node, the runner, the
|
|
52
|
+
* addons it hosted and the crash count that tripped the breaker.
|
|
53
|
+
*
|
|
54
|
+
* It exists because a runner marked terminally `failed` used to be SILENT:
|
|
55
|
+
* on 2026-08-18 the `recorder` runner died of three unhandled ffmpeg spawn
|
|
56
|
+
* errors, the breaker stopped respawning it (correctly), `/health` kept
|
|
57
|
+
* returning 200, and fleet-wide recording was gone for 3h15 before the
|
|
58
|
+
* operator's phone told him. The Notification Center's system-event intake
|
|
59
|
+
* consumes this category and maps it to the `addon-crash-loop` kind.
|
|
60
|
+
*/
|
|
61
|
+
EventCategory["AddonRunnerFailed"] = "addon.runner-failed";
|
|
45
62
|
EventCategory["AddonError"] = "addon.error";
|
|
46
63
|
EventCategory["AddonPageReady"] = "addon.page-ready";
|
|
47
64
|
EventCategory["AddonWidgetReady"] = "addon.widget-ready";
|
|
@@ -7541,6 +7558,10 @@ var RecordingBandSchema = object({
|
|
|
7541
7558
|
preBufferSec: number().min(0).optional(),
|
|
7542
7559
|
postBufferSec: number().min(0).optional()
|
|
7543
7560
|
});
|
|
7561
|
+
({
|
|
7562
|
+
preBufferSec: 10,
|
|
7563
|
+
postBufferSec: 30
|
|
7564
|
+
}).postBufferSec * 1e3;
|
|
7544
7565
|
/**
|
|
7545
7566
|
* Per-device retention overrides. Every field is optional; an unset or `0`
|
|
7546
7567
|
* value inherits the node-wide recorder default. Only footage-lifetime limits
|
|
@@ -7588,6 +7609,12 @@ var RecordingConfigSchema = object({
|
|
|
7588
7609
|
/** DERIVED summary of `bands`, stamped by the recorder on every save.
|
|
7589
7610
|
* Authoring it has no effect — see {@link RecordingStorageModeSchema}. */
|
|
7590
7611
|
mode: RecordingStorageModeSchema.optional(),
|
|
7612
|
+
/**
|
|
7613
|
+
* Which assigned broker slots to record. Absent / empty = {@link
|
|
7614
|
+
* DEFAULT_RECORDING_PROFILES} (`high`+`low`) intersected with the
|
|
7615
|
+
* camera's currently assigned slots — never `mid` unless the operator
|
|
7616
|
+
* picks it, and never a slot the broker has not assigned.
|
|
7617
|
+
*/
|
|
7591
7618
|
profiles: array(CamProfileSchema).optional(),
|
|
7592
7619
|
segmentSeconds: number().int().positive().optional(),
|
|
7593
7620
|
/**
|
|
@@ -7668,7 +7695,11 @@ var RelocateFootageInputSchema = object({
|
|
|
7668
7695
|
profiles: array(string()).optional(),
|
|
7669
7696
|
/** Copy throttle in MB/s (default 40) — the drain is a background chore,
|
|
7670
7697
|
* never allowed to starve live writers. */
|
|
7671
|
-
throttleMbps: number().min(1).max(1e3).optional()
|
|
7698
|
+
throttleMbps: number().min(1).max(1e3).optional(),
|
|
7699
|
+
/** Move only segments whose startMs is >= this. Absent = the whole source
|
|
7700
|
+
* pile. Used when a full drain is too expensive and the operator only
|
|
7701
|
+
* wants the recent window on the new disk. */
|
|
7702
|
+
sinceMs: number().int().optional()
|
|
7672
7703
|
});
|
|
7673
7704
|
/** Internal, lease-scoped participant operation. It is intentionally separate
|
|
7674
7705
|
* from persistent recording settings: a migration never changes
|
|
@@ -14533,6 +14564,7 @@ var NcSystemEventKindSchema = _enum([
|
|
|
14533
14564
|
"node-offline",
|
|
14534
14565
|
"node-inference-unavailable",
|
|
14535
14566
|
"detection-blind",
|
|
14567
|
+
"addon-crash-loop",
|
|
14536
14568
|
"addon-update-available",
|
|
14537
14569
|
"server-update-available",
|
|
14538
14570
|
"alarm-triggered",
|
|
@@ -14540,6 +14572,9 @@ var NcSystemEventKindSchema = _enum([
|
|
|
14540
14572
|
"alarm-disarmed",
|
|
14541
14573
|
"alarm-arming",
|
|
14542
14574
|
"alarm-arm-refused",
|
|
14575
|
+
"addon-updated",
|
|
14576
|
+
"server-updated",
|
|
14577
|
+
"export-completed",
|
|
14543
14578
|
"camera-online",
|
|
14544
14579
|
"camera-offline",
|
|
14545
14580
|
"camera-disabled",
|
|
@@ -16433,13 +16468,19 @@ var RetrainStatusSchema = _enum([
|
|
|
16433
16468
|
* "never marked" from "already trained" must read `retrainStatus`.
|
|
16434
16469
|
*
|
|
16435
16470
|
* `debug` does NOT pin; it is attention, not durability.
|
|
16471
|
+
*
|
|
16472
|
+
* `favourited` IS a BOOLEAN pin (durability bit), not a retrain lifecycle.
|
|
16473
|
+
* A favourited track is skipped by retention the same way `staging` is, but
|
|
16474
|
+
* it does not enter `none|staging|trained` and has no staging budget.
|
|
16436
16475
|
*/
|
|
16437
16476
|
var TrackFlagFields = {
|
|
16438
16477
|
/** Operator marked this track as training material — i.e. `retrainStatus` is
|
|
16439
16478
|
* `'staging'`. */
|
|
16440
16479
|
markForTrain: boolean().optional(),
|
|
16441
16480
|
/** Operator marked this track for diagnostic attention. */
|
|
16442
|
-
debug: boolean().optional()
|
|
16481
|
+
debug: boolean().optional(),
|
|
16482
|
+
/** Operator favourited this track. Pins it against pruning. */
|
|
16483
|
+
favourited: boolean().optional()
|
|
16443
16484
|
};
|
|
16444
16485
|
/**
|
|
16445
16486
|
* The lifecycle field itself, on the READ surfaces only (`Track`, `KeyEvent`).
|
|
@@ -16464,6 +16505,7 @@ var TrackFlagsSchema = object({
|
|
|
16464
16505
|
trackId: string(),
|
|
16465
16506
|
markForTrain: boolean(),
|
|
16466
16507
|
debug: boolean(),
|
|
16508
|
+
favourited: boolean(),
|
|
16467
16509
|
/** The lifecycle state the boolean was derived from. Required here (unlike on
|
|
16468
16510
|
* a track row) because this shape is only ever produced by the write body,
|
|
16469
16511
|
* which always knows it — and a surface that has just written needs to render
|
|
@@ -17096,6 +17138,12 @@ var TrackCascadeCountsSchema = object({
|
|
|
17096
17138
|
/** Per-track CLIP search vectors removed (best-effort). */
|
|
17097
17139
|
embeddings: number().int()
|
|
17098
17140
|
});
|
|
17141
|
+
/** Disk-wins reconcile: media rows whose blobs are gone, then empty tracks. */
|
|
17142
|
+
var DiskReconcileCountsSchema = object({
|
|
17143
|
+
mediaDropped: number().int(),
|
|
17144
|
+
tracks: number().int(),
|
|
17145
|
+
events: number().int()
|
|
17146
|
+
});
|
|
17099
17147
|
/** Event-store footprint for one camera. */
|
|
17100
17148
|
var EventStoreDeviceFootprintSchema = object({
|
|
17101
17149
|
deviceId: number(),
|
|
@@ -17272,6 +17320,9 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
17272
17320
|
}), method(object({ deviceId: number() }), TrackCascadeCountsSchema, {
|
|
17273
17321
|
kind: "mutation",
|
|
17274
17322
|
auth: "admin"
|
|
17323
|
+
}), method(object({ deviceId: number() }), DiskReconcileCountsSchema, {
|
|
17324
|
+
kind: "mutation",
|
|
17325
|
+
auth: "admin"
|
|
17275
17326
|
}), method(object({
|
|
17276
17327
|
deviceId: number(),
|
|
17277
17328
|
trackIds: array(string()).min(1)
|
|
@@ -18822,6 +18873,24 @@ var CameraStatusDegradationSchema = object({
|
|
|
18822
18873
|
*
|
|
18823
18874
|
* See spec: `docs/superpowers/specs/2026-06-24-camera-status-aggregator-cap.md`
|
|
18824
18875
|
*/
|
|
18876
|
+
var DiskReconcileJobSchema = object({
|
|
18877
|
+
state: _enum([
|
|
18878
|
+
"idle",
|
|
18879
|
+
"running",
|
|
18880
|
+
"done",
|
|
18881
|
+
"error"
|
|
18882
|
+
]),
|
|
18883
|
+
total: number().int().nonnegative(),
|
|
18884
|
+
completed: number().int().nonnegative(),
|
|
18885
|
+
currentDeviceId: number().int().nullable(),
|
|
18886
|
+
failed: array(number().int()).readonly(),
|
|
18887
|
+
mediaDropped: number().int().nonnegative(),
|
|
18888
|
+
tracks: number().int().nonnegative(),
|
|
18889
|
+
events: number().int().nonnegative(),
|
|
18890
|
+
startedAtMs: number().int().nullable(),
|
|
18891
|
+
finishedAtMs: number().int().nullable(),
|
|
18892
|
+
error: string().nullable()
|
|
18893
|
+
});
|
|
18825
18894
|
var CameraStatusSchema = object({
|
|
18826
18895
|
deviceId: number(),
|
|
18827
18896
|
assignment: CameraAssignmentStatusSchema,
|
|
@@ -19053,7 +19122,10 @@ method(StorageMigrationLeaseInputSchema, object({ paused: literal(true) }), {
|
|
|
19053
19122
|
}), CameraSwitchGroupSchema, {
|
|
19054
19123
|
kind: "mutation",
|
|
19055
19124
|
auth: "admin"
|
|
19056
|
-
}), method(object({ deviceId: number() }), CameraStatusSchema), method(object({ deviceIds: array(number()).optional() }), array(CameraStatusSchema).readonly()), method(_void(),
|
|
19125
|
+
}), method(object({ deviceId: number() }), CameraStatusSchema), method(object({ deviceIds: array(number()).optional() }), array(CameraStatusSchema).readonly()), method(_void(), DiskReconcileJobSchema, {
|
|
19126
|
+
kind: "mutation",
|
|
19127
|
+
auth: "admin"
|
|
19128
|
+
}), method(_void(), DiskReconcileJobSchema, { auth: "admin" }), method(_void(), array(PipelineTemplateSchema).readonly()), method(object({
|
|
19057
19129
|
name: string(),
|
|
19058
19130
|
description: string().optional(),
|
|
19059
19131
|
config: CameraPipelineConfigSchema
|
|
@@ -20230,20 +20302,6 @@ var VectorStatsResultSchema = object({
|
|
|
20230
20302
|
exact: boolean()
|
|
20231
20303
|
});
|
|
20232
20304
|
method(VectorDeclareIndexInputSchema, _void(), { kind: "mutation" }), method(VectorUpsertInputSchema, VectorUpsertResultSchema, { kind: "mutation" }), method(VectorQueryInputSchema, VectorQueryResultSchema), method(VectorGetInputSchema, VectorGetResultSchema), method(VectorDeleteInputSchema, VectorDeleteResultSchema, { kind: "mutation" }), method(VectorDeleteByFilterInputSchema, VectorDeleteResultSchema, { kind: "mutation" }), method(VectorStatsInputSchema, VectorStatsResultSchema);
|
|
20233
|
-
/**
|
|
20234
|
-
* `videoclips` — the unified, navigable-clip surface for a camera.
|
|
20235
|
-
*
|
|
20236
|
-
* A device-scoped WRAPPER cap (like `pipeline-analytics`): exactly one active
|
|
20237
|
-
* provider per device, substitutable. The DEFAULT provider (registered by
|
|
20238
|
-
* `addon-post-analysis`, `defaultActive: true`) composes the analytics event
|
|
20239
|
-
* log (markers + thumbnails) with the recorder's `getPlaybackManifest` — a clip
|
|
20240
|
-
* is a time-WINDOW over existing footage, never a separate file. A camera that
|
|
20241
|
-
* exposes NATIVE onboard clips (Reolink/Hikvision NVR) can later substitute the
|
|
20242
|
-
* wrapper provider for its device and serve its own clip catalog + URLs.
|
|
20243
|
-
*
|
|
20244
|
-
* A `Clip` is purely time-based (subtree-blind): playback resolves segments by
|
|
20245
|
-
* temporal overlap, so the API never decides `continuous` vs `events`.
|
|
20246
|
-
*/
|
|
20247
20305
|
var ClipSchema = object({
|
|
20248
20306
|
/** Opaque, provider-namespaced id. The default provider encodes the time
|
|
20249
20307
|
* window so `getClipPlayback` is self-contained (no event re-query). */
|
|
@@ -20260,8 +20318,57 @@ var ClipSchema = object({
|
|
|
20260
20318
|
startMs: number(),
|
|
20261
20319
|
endMs: number()
|
|
20262
20320
|
}),
|
|
20263
|
-
/**
|
|
20264
|
-
thumbnail
|
|
20321
|
+
/**
|
|
20322
|
+
* Lazy thumbnail URL, never inlined.
|
|
20323
|
+
*
|
|
20324
|
+
* Recording-derived clips (events-mode keep-window, and the prepared
|
|
20325
|
+
* continuous event+fragment visit) MUST use the snapshot of the **main
|
|
20326
|
+
* event of the interval** — `getEventMedia({ eventId, kind: 'snapshot' })`
|
|
20327
|
+
* of the event that owns `kind` (object > motion > audio). Do not extract
|
|
20328
|
+
* a keyframe from the recorded segments. Other providers (onboard, HKSV)
|
|
20329
|
+
* mint their own stills.
|
|
20330
|
+
*
|
|
20331
|
+
* **VOUCHED, never fabricated.** A provider emits this only for an event it
|
|
20332
|
+
* has CONFIRMED owns at least one media row (its own, or its owning track's).
|
|
20333
|
+
* Absent is meaningful — "this visit has no event still" — never "we did not
|
|
20334
|
+
* look". Stamping it from a URL template made 35% of one camera's clips point
|
|
20335
|
+
* at a 404 (device 3836, 2026-08-17: 64 of 179 clips dead, 63 of them motion).
|
|
20336
|
+
* A read that FAILS drops the claim; it never invents it.
|
|
20337
|
+
*/
|
|
20338
|
+
thumbnail: string().optional(),
|
|
20339
|
+
/**
|
|
20340
|
+
* An instant INSIDE this visit's footage, hole-safe, where a recorded still
|
|
20341
|
+
* can be decoded. Present whenever the visit came from recorded availability;
|
|
20342
|
+
* absent on a per-event padded window (there is no footage to promise).
|
|
20343
|
+
*
|
|
20344
|
+
* This is not a thumbnail and not a second byte path: it is the argument to
|
|
20345
|
+
* the recorder's existing still route. The surface — never the provider —
|
|
20346
|
+
* decides whether to use it. It is the midpoint of the visit's LONGEST
|
|
20347
|
+
* contiguous range, not of the visit: a visit spans its holes by
|
|
20348
|
+
* construction, so a naive midpoint lands in dead air.
|
|
20349
|
+
*/
|
|
20350
|
+
stillAtMs: number().optional(),
|
|
20351
|
+
/**
|
|
20352
|
+
* Analytics event ids that overlap this visit — a BOUNDED sample, newest
|
|
20353
|
+
* first within kind (object → motion → audio), capped at
|
|
20354
|
+
* {@link MAX_CLIP_EVENT_IDS}. Empty on footage-only clips.
|
|
20355
|
+
*
|
|
20356
|
+
* Bounded because it is not a payload the surface pages through: one visit on
|
|
20357
|
+
* device 615 carried 2 345 ids, and `eventIds` was 99% of a 153 KB
|
|
20358
|
+
* camera-day. Read {@link eventCount} for the true total.
|
|
20359
|
+
*/
|
|
20360
|
+
eventIds: array(string()).optional(),
|
|
20361
|
+
/** How many analytics events actually overlap this visit. Differs from
|
|
20362
|
+
* `eventIds.length` exactly when the sample was capped — so a truncated
|
|
20363
|
+
* list is never mistaken for a quiet visit. */
|
|
20364
|
+
eventCount: number().int().nonnegative().optional(),
|
|
20365
|
+
/** Intra-visit footage holes (GOP rolls, discarded segments) still shorter
|
|
20366
|
+
* than `VISIT_MERGE_GAP_MS`. Playback concatenates around them; the timeline
|
|
20367
|
+
* bar keeps showing them via `recording.getAvailability`. */
|
|
20368
|
+
holes: array(object({
|
|
20369
|
+
startMs: number(),
|
|
20370
|
+
endMs: number()
|
|
20371
|
+
})).optional()
|
|
20265
20372
|
});
|
|
20266
20373
|
var ClipPlaybackSchema = object({
|
|
20267
20374
|
/** HLS master URL through the hub data-plane (Range + token in path). */
|
|
@@ -20725,7 +20832,14 @@ var SearchResultSchema = object({
|
|
|
20725
20832
|
});
|
|
20726
20833
|
var AutoUpdateSettingsSchema = object({
|
|
20727
20834
|
channel: ChannelSchema,
|
|
20728
|
-
intervalSeconds: number()
|
|
20835
|
+
intervalSeconds: number(),
|
|
20836
|
+
/**
|
|
20837
|
+
* Cadence of the "an update exists" POLLER, in seconds. Independent of
|
|
20838
|
+
* `channel`: the poller runs while auto-apply is `off`, because being told
|
|
20839
|
+
* about a publish and installing it are different decisions. Clamped
|
|
20840
|
+
* server-side to 900 s … 604800 s; defaults to 21600 s (6 h).
|
|
20841
|
+
*/
|
|
20842
|
+
updateCheckIntervalSeconds: number()
|
|
20729
20843
|
});
|
|
20730
20844
|
var AddonAutoUpdateSchema = ChannelWithInheritSchema;
|
|
20731
20845
|
var RestartAddonResultSchema = unknown();
|
|
@@ -20866,7 +20980,9 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
|
|
|
20866
20980
|
auth: "admin"
|
|
20867
20981
|
}), method(_void(), AutoUpdateSettingsSchema, { auth: "admin" }), method(object({
|
|
20868
20982
|
channel: ChannelSchema,
|
|
20869
|
-
intervalSeconds: number().min(300).max(86400).optional()
|
|
20983
|
+
intervalSeconds: number().min(300).max(86400).optional(),
|
|
20984
|
+
/** Availability-poll cadence; see AutoUpdateSettingsSchema. */
|
|
20985
|
+
updateCheckIntervalSeconds: number().min(900).max(604800).optional()
|
|
20870
20986
|
}), unknown(), {
|
|
20871
20987
|
kind: "mutation",
|
|
20872
20988
|
auth: "admin"
|
|
@@ -26635,7 +26751,9 @@ var ExportOptionsSchema = object({
|
|
|
26635
26751
|
includeAudio: boolean(),
|
|
26636
26752
|
maxLifeMs: number().int().positive(),
|
|
26637
26753
|
deleteAfterDownload: boolean(),
|
|
26638
|
-
title: string().max(200).optional()
|
|
26754
|
+
title: string().max(200).optional(),
|
|
26755
|
+
/** Notification-output target ids to ping when this export becomes ready. */
|
|
26756
|
+
notifyTargetIds: array(string().min(1)).max(20).optional()
|
|
26639
26757
|
}).superRefine((v, ctx) => {
|
|
26640
26758
|
if (v.speed !== void 0 && v.timelapse !== void 0) ctx.addIssue({
|
|
26641
26759
|
code: ZodIssueCode.custom,
|
|
@@ -26694,10 +26812,18 @@ var ExportBytesSchema = object({
|
|
|
26694
26812
|
});
|
|
26695
26813
|
method(object({
|
|
26696
26814
|
deviceId: number(),
|
|
26697
|
-
|
|
26815
|
+
/** @deprecated Prefer `profiles`. Kept so timelapse/notifiers keep working. */
|
|
26816
|
+
profile: string().optional(),
|
|
26817
|
+
profiles: array(string()).min(1).optional(),
|
|
26698
26818
|
fromMs: number(),
|
|
26699
26819
|
toMs: number(),
|
|
26700
26820
|
options: ExportOptionsSchema
|
|
26821
|
+
}).superRefine((v, ctx) => {
|
|
26822
|
+
if ((v.profiles !== void 0 && v.profiles.length > 0 ? v.profiles : v.profile !== void 0 ? [v.profile] : []).length < 1) ctx.addIssue({
|
|
26823
|
+
code: ZodIssueCode.custom,
|
|
26824
|
+
message: "pass profiles[] (min 1) or legacy profile",
|
|
26825
|
+
path: ["profiles"]
|
|
26826
|
+
});
|
|
26701
26827
|
}), ExportRecordSchema, {
|
|
26702
26828
|
kind: "mutation",
|
|
26703
26829
|
auth: "protected"
|
|
@@ -29837,15 +29963,6 @@ var BaseDeviceProvider = class extends BaseAddon {
|
|
|
29837
29963
|
labels: ["probe not implemented"]
|
|
29838
29964
|
};
|
|
29839
29965
|
}
|
|
29840
|
-
/**
|
|
29841
|
-
* Top-level devices restored at once in {@link onRestoreDevices}.
|
|
29842
|
-
*
|
|
29843
|
-
* Four covers the fleets this ships to without turning a boot into a burst a
|
|
29844
|
-
* camera NVR answers with a refusal. A provider whose upstream is a single
|
|
29845
|
-
* session with a serial command channel (a Baichuan hub, an NVR that
|
|
29846
|
-
* serialises ISAPI) should lower it; nothing needs to raise it.
|
|
29847
|
-
*/
|
|
29848
|
-
restoreConcurrency = 4;
|
|
29849
29966
|
async restoreDevices(savedDevices) {
|
|
29850
29967
|
await this.onRestoreDevices(savedDevices);
|
|
29851
29968
|
if (savedDevices.length > 0) this.ctx.logger.info(`Restored ${savedDevices.length} ${this.providerName} device(s)`);
|
|
@@ -29900,14 +30017,7 @@ var BaseDeviceProvider = class extends BaseAddon {
|
|
|
29900
30017
|
});
|
|
29901
30018
|
}
|
|
29902
30019
|
};
|
|
29903
|
-
|
|
29904
|
-
await Promise.all(Array.from({ length: Math.min(Math.max(1, this.restoreConcurrency), topLevel.length) }, async () => {
|
|
29905
|
-
for (;;) {
|
|
29906
|
-
const saved = topLevel[nextTopLevel++];
|
|
29907
|
-
if (saved === void 0) return;
|
|
29908
|
-
await restoreOne(saved);
|
|
29909
|
-
}
|
|
29910
|
-
}));
|
|
30020
|
+
await Promise.all(topLevel.map((saved) => restoreOne(saved)));
|
|
29911
30021
|
const childRows = savedDevices.filter((s) => s.parentDeviceId !== null);
|
|
29912
30022
|
for (const saved of childRows) {
|
|
29913
30023
|
const Class = this.deviceClasses[saved.type];
|
|
@@ -33311,6 +33421,12 @@ Object.freeze({
|
|
|
33311
33421
|
addonId: null,
|
|
33312
33422
|
access: "create"
|
|
33313
33423
|
},
|
|
33424
|
+
"pipelineAnalytics.reconcileFromDisk": {
|
|
33425
|
+
capName: "pipeline-analytics",
|
|
33426
|
+
capScope: "device",
|
|
33427
|
+
addonId: null,
|
|
33428
|
+
access: "create"
|
|
33429
|
+
},
|
|
33314
33430
|
"pipelineAnalytics.refreshStorageLocationsForMigration": {
|
|
33315
33431
|
capName: "pipeline-analytics",
|
|
33316
33432
|
capScope: "device",
|
|
@@ -33713,6 +33829,12 @@ Object.freeze({
|
|
|
33713
33829
|
addonId: null,
|
|
33714
33830
|
access: "view"
|
|
33715
33831
|
},
|
|
33832
|
+
"pipelineOrchestrator.getReconcileFromDiskStatus": {
|
|
33833
|
+
capName: "pipeline-orchestrator",
|
|
33834
|
+
capScope: "system",
|
|
33835
|
+
addonId: null,
|
|
33836
|
+
access: "view"
|
|
33837
|
+
},
|
|
33716
33838
|
"pipelineOrchestrator.listAgentSettings": {
|
|
33717
33839
|
capName: "pipeline-orchestrator",
|
|
33718
33840
|
capScope: "system",
|
|
@@ -33737,6 +33859,12 @@ Object.freeze({
|
|
|
33737
33859
|
addonId: null,
|
|
33738
33860
|
access: "create"
|
|
33739
33861
|
},
|
|
33862
|
+
"pipelineOrchestrator.reconcileFromDisk": {
|
|
33863
|
+
capName: "pipeline-orchestrator",
|
|
33864
|
+
capScope: "system",
|
|
33865
|
+
addonId: null,
|
|
33866
|
+
access: "create"
|
|
33867
|
+
},
|
|
33740
33868
|
"pipelineOrchestrator.removeAgentSettings": {
|
|
33741
33869
|
capName: "pipeline-orchestrator",
|
|
33742
33870
|
capScope: "system",
|
|
@@ -36728,6 +36856,11 @@ Object.freeze({
|
|
|
36728
36856
|
form: "single",
|
|
36729
36857
|
optional: true
|
|
36730
36858
|
}],
|
|
36859
|
+
"pipelineAnalytics.reconcileFromDisk": [{
|
|
36860
|
+
name: "deviceId",
|
|
36861
|
+
form: "single",
|
|
36862
|
+
optional: false
|
|
36863
|
+
}],
|
|
36731
36864
|
"pipelineAnalytics.restageRetrainTrack": [{
|
|
36732
36865
|
name: "deviceId",
|
|
36733
36866
|
form: "single",
|
|
@@ -37793,6 +37926,8 @@ DEFAULT_NATIVE_LEASE_SETTINGS.budgetMb;
|
|
|
37793
37926
|
DEFAULT_NATIVE_LEASE_SETTINGS.activityMs;
|
|
37794
37927
|
DEFAULT_NATIVE_LEASE_SETTINGS.tileBudgetMb;
|
|
37795
37928
|
DEFAULT_NATIVE_LEASE_SETTINGS.admission;
|
|
37929
|
+
var MB = 1024 * 1024;
|
|
37930
|
+
1024 * MB, 3072 * MB;
|
|
37796
37931
|
//#endregion
|
|
37797
37932
|
//#region src/digest-auth.ts
|
|
37798
37933
|
/**
|
package/dist/addon.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import { networkInterfaces } from "node:os";
|
|
|
5
5
|
var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
|
|
6
6
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
7
7
|
//#endregion
|
|
8
|
-
//#region ../types/dist/event-category-
|
|
8
|
+
//#region ../types/dist/event-category-XfKNtfCc.mjs
|
|
9
9
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
10
10
|
EventCategory["SystemBoot"] = "system.boot";
|
|
11
11
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -22,9 +22,10 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
22
22
|
EventCategory["SystemRestartCompleted"] = "system.restart-completed";
|
|
23
23
|
/**
|
|
24
24
|
* A newer addon or server-root package version was found by the
|
|
25
|
-
* authoritative registry check. Emitted once
|
|
26
|
-
* `(
|
|
27
|
-
*
|
|
25
|
+
* authoritative registry check. Emitted once when any observed
|
|
26
|
+
* `latestVersion` changes (or a package/node first appears behind);
|
|
27
|
+
* the payload carries the full currently-available list. Repeated
|
|
28
|
+
* polling of the same latests is silent.
|
|
28
29
|
*/
|
|
29
30
|
EventCategory["UpdateAvailable"] = "update.available";
|
|
30
31
|
/**
|
|
@@ -43,6 +44,22 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
43
44
|
EventCategory["AddonInstalled"] = "addon.installed";
|
|
44
45
|
EventCategory["AddonUninstalled"] = "addon.uninstalled";
|
|
45
46
|
EventCategory["AddonCrashed"] = "addon.crashed";
|
|
47
|
+
/**
|
|
48
|
+
* A RUNNER the D6 crash circuit-breaker gave up on — terminal.
|
|
49
|
+
*
|
|
50
|
+
* `AddonCrashed` is the routine, self-healing fact ("it crashed; it is being
|
|
51
|
+
* respawned"); this is the one that never resolves itself. Emitted exactly
|
|
52
|
+
* once per trip, by `process-service.ts`, carrying the node, the runner, the
|
|
53
|
+
* addons it hosted and the crash count that tripped the breaker.
|
|
54
|
+
*
|
|
55
|
+
* It exists because a runner marked terminally `failed` used to be SILENT:
|
|
56
|
+
* on 2026-08-18 the `recorder` runner died of three unhandled ffmpeg spawn
|
|
57
|
+
* errors, the breaker stopped respawning it (correctly), `/health` kept
|
|
58
|
+
* returning 200, and fleet-wide recording was gone for 3h15 before the
|
|
59
|
+
* operator's phone told him. The Notification Center's system-event intake
|
|
60
|
+
* consumes this category and maps it to the `addon-crash-loop` kind.
|
|
61
|
+
*/
|
|
62
|
+
EventCategory["AddonRunnerFailed"] = "addon.runner-failed";
|
|
46
63
|
EventCategory["AddonError"] = "addon.error";
|
|
47
64
|
EventCategory["AddonPageReady"] = "addon.page-ready";
|
|
48
65
|
EventCategory["AddonWidgetReady"] = "addon.widget-ready";
|
|
@@ -7542,6 +7559,10 @@ var RecordingBandSchema = object({
|
|
|
7542
7559
|
preBufferSec: number().min(0).optional(),
|
|
7543
7560
|
postBufferSec: number().min(0).optional()
|
|
7544
7561
|
});
|
|
7562
|
+
({
|
|
7563
|
+
preBufferSec: 10,
|
|
7564
|
+
postBufferSec: 30
|
|
7565
|
+
}).postBufferSec * 1e3;
|
|
7545
7566
|
/**
|
|
7546
7567
|
* Per-device retention overrides. Every field is optional; an unset or `0`
|
|
7547
7568
|
* value inherits the node-wide recorder default. Only footage-lifetime limits
|
|
@@ -7589,6 +7610,12 @@ var RecordingConfigSchema = object({
|
|
|
7589
7610
|
/** DERIVED summary of `bands`, stamped by the recorder on every save.
|
|
7590
7611
|
* Authoring it has no effect — see {@link RecordingStorageModeSchema}. */
|
|
7591
7612
|
mode: RecordingStorageModeSchema.optional(),
|
|
7613
|
+
/**
|
|
7614
|
+
* Which assigned broker slots to record. Absent / empty = {@link
|
|
7615
|
+
* DEFAULT_RECORDING_PROFILES} (`high`+`low`) intersected with the
|
|
7616
|
+
* camera's currently assigned slots — never `mid` unless the operator
|
|
7617
|
+
* picks it, and never a slot the broker has not assigned.
|
|
7618
|
+
*/
|
|
7592
7619
|
profiles: array(CamProfileSchema).optional(),
|
|
7593
7620
|
segmentSeconds: number().int().positive().optional(),
|
|
7594
7621
|
/**
|
|
@@ -7669,7 +7696,11 @@ var RelocateFootageInputSchema = object({
|
|
|
7669
7696
|
profiles: array(string()).optional(),
|
|
7670
7697
|
/** Copy throttle in MB/s (default 40) — the drain is a background chore,
|
|
7671
7698
|
* never allowed to starve live writers. */
|
|
7672
|
-
throttleMbps: number().min(1).max(1e3).optional()
|
|
7699
|
+
throttleMbps: number().min(1).max(1e3).optional(),
|
|
7700
|
+
/** Move only segments whose startMs is >= this. Absent = the whole source
|
|
7701
|
+
* pile. Used when a full drain is too expensive and the operator only
|
|
7702
|
+
* wants the recent window on the new disk. */
|
|
7703
|
+
sinceMs: number().int().optional()
|
|
7673
7704
|
});
|
|
7674
7705
|
/** Internal, lease-scoped participant operation. It is intentionally separate
|
|
7675
7706
|
* from persistent recording settings: a migration never changes
|
|
@@ -14534,6 +14565,7 @@ var NcSystemEventKindSchema = _enum([
|
|
|
14534
14565
|
"node-offline",
|
|
14535
14566
|
"node-inference-unavailable",
|
|
14536
14567
|
"detection-blind",
|
|
14568
|
+
"addon-crash-loop",
|
|
14537
14569
|
"addon-update-available",
|
|
14538
14570
|
"server-update-available",
|
|
14539
14571
|
"alarm-triggered",
|
|
@@ -14541,6 +14573,9 @@ var NcSystemEventKindSchema = _enum([
|
|
|
14541
14573
|
"alarm-disarmed",
|
|
14542
14574
|
"alarm-arming",
|
|
14543
14575
|
"alarm-arm-refused",
|
|
14576
|
+
"addon-updated",
|
|
14577
|
+
"server-updated",
|
|
14578
|
+
"export-completed",
|
|
14544
14579
|
"camera-online",
|
|
14545
14580
|
"camera-offline",
|
|
14546
14581
|
"camera-disabled",
|
|
@@ -16434,13 +16469,19 @@ var RetrainStatusSchema = _enum([
|
|
|
16434
16469
|
* "never marked" from "already trained" must read `retrainStatus`.
|
|
16435
16470
|
*
|
|
16436
16471
|
* `debug` does NOT pin; it is attention, not durability.
|
|
16472
|
+
*
|
|
16473
|
+
* `favourited` IS a BOOLEAN pin (durability bit), not a retrain lifecycle.
|
|
16474
|
+
* A favourited track is skipped by retention the same way `staging` is, but
|
|
16475
|
+
* it does not enter `none|staging|trained` and has no staging budget.
|
|
16437
16476
|
*/
|
|
16438
16477
|
var TrackFlagFields = {
|
|
16439
16478
|
/** Operator marked this track as training material — i.e. `retrainStatus` is
|
|
16440
16479
|
* `'staging'`. */
|
|
16441
16480
|
markForTrain: boolean().optional(),
|
|
16442
16481
|
/** Operator marked this track for diagnostic attention. */
|
|
16443
|
-
debug: boolean().optional()
|
|
16482
|
+
debug: boolean().optional(),
|
|
16483
|
+
/** Operator favourited this track. Pins it against pruning. */
|
|
16484
|
+
favourited: boolean().optional()
|
|
16444
16485
|
};
|
|
16445
16486
|
/**
|
|
16446
16487
|
* The lifecycle field itself, on the READ surfaces only (`Track`, `KeyEvent`).
|
|
@@ -16465,6 +16506,7 @@ var TrackFlagsSchema = object({
|
|
|
16465
16506
|
trackId: string(),
|
|
16466
16507
|
markForTrain: boolean(),
|
|
16467
16508
|
debug: boolean(),
|
|
16509
|
+
favourited: boolean(),
|
|
16468
16510
|
/** The lifecycle state the boolean was derived from. Required here (unlike on
|
|
16469
16511
|
* a track row) because this shape is only ever produced by the write body,
|
|
16470
16512
|
* which always knows it — and a surface that has just written needs to render
|
|
@@ -17097,6 +17139,12 @@ var TrackCascadeCountsSchema = object({
|
|
|
17097
17139
|
/** Per-track CLIP search vectors removed (best-effort). */
|
|
17098
17140
|
embeddings: number().int()
|
|
17099
17141
|
});
|
|
17142
|
+
/** Disk-wins reconcile: media rows whose blobs are gone, then empty tracks. */
|
|
17143
|
+
var DiskReconcileCountsSchema = object({
|
|
17144
|
+
mediaDropped: number().int(),
|
|
17145
|
+
tracks: number().int(),
|
|
17146
|
+
events: number().int()
|
|
17147
|
+
});
|
|
17100
17148
|
/** Event-store footprint for one camera. */
|
|
17101
17149
|
var EventStoreDeviceFootprintSchema = object({
|
|
17102
17150
|
deviceId: number(),
|
|
@@ -17273,6 +17321,9 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
17273
17321
|
}), method(object({ deviceId: number() }), TrackCascadeCountsSchema, {
|
|
17274
17322
|
kind: "mutation",
|
|
17275
17323
|
auth: "admin"
|
|
17324
|
+
}), method(object({ deviceId: number() }), DiskReconcileCountsSchema, {
|
|
17325
|
+
kind: "mutation",
|
|
17326
|
+
auth: "admin"
|
|
17276
17327
|
}), method(object({
|
|
17277
17328
|
deviceId: number(),
|
|
17278
17329
|
trackIds: array(string()).min(1)
|
|
@@ -18823,6 +18874,24 @@ var CameraStatusDegradationSchema = object({
|
|
|
18823
18874
|
*
|
|
18824
18875
|
* See spec: `docs/superpowers/specs/2026-06-24-camera-status-aggregator-cap.md`
|
|
18825
18876
|
*/
|
|
18877
|
+
var DiskReconcileJobSchema = object({
|
|
18878
|
+
state: _enum([
|
|
18879
|
+
"idle",
|
|
18880
|
+
"running",
|
|
18881
|
+
"done",
|
|
18882
|
+
"error"
|
|
18883
|
+
]),
|
|
18884
|
+
total: number().int().nonnegative(),
|
|
18885
|
+
completed: number().int().nonnegative(),
|
|
18886
|
+
currentDeviceId: number().int().nullable(),
|
|
18887
|
+
failed: array(number().int()).readonly(),
|
|
18888
|
+
mediaDropped: number().int().nonnegative(),
|
|
18889
|
+
tracks: number().int().nonnegative(),
|
|
18890
|
+
events: number().int().nonnegative(),
|
|
18891
|
+
startedAtMs: number().int().nullable(),
|
|
18892
|
+
finishedAtMs: number().int().nullable(),
|
|
18893
|
+
error: string().nullable()
|
|
18894
|
+
});
|
|
18826
18895
|
var CameraStatusSchema = object({
|
|
18827
18896
|
deviceId: number(),
|
|
18828
18897
|
assignment: CameraAssignmentStatusSchema,
|
|
@@ -19054,7 +19123,10 @@ method(StorageMigrationLeaseInputSchema, object({ paused: literal(true) }), {
|
|
|
19054
19123
|
}), CameraSwitchGroupSchema, {
|
|
19055
19124
|
kind: "mutation",
|
|
19056
19125
|
auth: "admin"
|
|
19057
|
-
}), method(object({ deviceId: number() }), CameraStatusSchema), method(object({ deviceIds: array(number()).optional() }), array(CameraStatusSchema).readonly()), method(_void(),
|
|
19126
|
+
}), method(object({ deviceId: number() }), CameraStatusSchema), method(object({ deviceIds: array(number()).optional() }), array(CameraStatusSchema).readonly()), method(_void(), DiskReconcileJobSchema, {
|
|
19127
|
+
kind: "mutation",
|
|
19128
|
+
auth: "admin"
|
|
19129
|
+
}), method(_void(), DiskReconcileJobSchema, { auth: "admin" }), method(_void(), array(PipelineTemplateSchema).readonly()), method(object({
|
|
19058
19130
|
name: string(),
|
|
19059
19131
|
description: string().optional(),
|
|
19060
19132
|
config: CameraPipelineConfigSchema
|
|
@@ -20231,20 +20303,6 @@ var VectorStatsResultSchema = object({
|
|
|
20231
20303
|
exact: boolean()
|
|
20232
20304
|
});
|
|
20233
20305
|
method(VectorDeclareIndexInputSchema, _void(), { kind: "mutation" }), method(VectorUpsertInputSchema, VectorUpsertResultSchema, { kind: "mutation" }), method(VectorQueryInputSchema, VectorQueryResultSchema), method(VectorGetInputSchema, VectorGetResultSchema), method(VectorDeleteInputSchema, VectorDeleteResultSchema, { kind: "mutation" }), method(VectorDeleteByFilterInputSchema, VectorDeleteResultSchema, { kind: "mutation" }), method(VectorStatsInputSchema, VectorStatsResultSchema);
|
|
20234
|
-
/**
|
|
20235
|
-
* `videoclips` — the unified, navigable-clip surface for a camera.
|
|
20236
|
-
*
|
|
20237
|
-
* A device-scoped WRAPPER cap (like `pipeline-analytics`): exactly one active
|
|
20238
|
-
* provider per device, substitutable. The DEFAULT provider (registered by
|
|
20239
|
-
* `addon-post-analysis`, `defaultActive: true`) composes the analytics event
|
|
20240
|
-
* log (markers + thumbnails) with the recorder's `getPlaybackManifest` — a clip
|
|
20241
|
-
* is a time-WINDOW over existing footage, never a separate file. A camera that
|
|
20242
|
-
* exposes NATIVE onboard clips (Reolink/Hikvision NVR) can later substitute the
|
|
20243
|
-
* wrapper provider for its device and serve its own clip catalog + URLs.
|
|
20244
|
-
*
|
|
20245
|
-
* A `Clip` is purely time-based (subtree-blind): playback resolves segments by
|
|
20246
|
-
* temporal overlap, so the API never decides `continuous` vs `events`.
|
|
20247
|
-
*/
|
|
20248
20306
|
var ClipSchema = object({
|
|
20249
20307
|
/** Opaque, provider-namespaced id. The default provider encodes the time
|
|
20250
20308
|
* window so `getClipPlayback` is self-contained (no event re-query). */
|
|
@@ -20261,8 +20319,57 @@ var ClipSchema = object({
|
|
|
20261
20319
|
startMs: number(),
|
|
20262
20320
|
endMs: number()
|
|
20263
20321
|
}),
|
|
20264
|
-
/**
|
|
20265
|
-
thumbnail
|
|
20322
|
+
/**
|
|
20323
|
+
* Lazy thumbnail URL, never inlined.
|
|
20324
|
+
*
|
|
20325
|
+
* Recording-derived clips (events-mode keep-window, and the prepared
|
|
20326
|
+
* continuous event+fragment visit) MUST use the snapshot of the **main
|
|
20327
|
+
* event of the interval** — `getEventMedia({ eventId, kind: 'snapshot' })`
|
|
20328
|
+
* of the event that owns `kind` (object > motion > audio). Do not extract
|
|
20329
|
+
* a keyframe from the recorded segments. Other providers (onboard, HKSV)
|
|
20330
|
+
* mint their own stills.
|
|
20331
|
+
*
|
|
20332
|
+
* **VOUCHED, never fabricated.** A provider emits this only for an event it
|
|
20333
|
+
* has CONFIRMED owns at least one media row (its own, or its owning track's).
|
|
20334
|
+
* Absent is meaningful — "this visit has no event still" — never "we did not
|
|
20335
|
+
* look". Stamping it from a URL template made 35% of one camera's clips point
|
|
20336
|
+
* at a 404 (device 3836, 2026-08-17: 64 of 179 clips dead, 63 of them motion).
|
|
20337
|
+
* A read that FAILS drops the claim; it never invents it.
|
|
20338
|
+
*/
|
|
20339
|
+
thumbnail: string().optional(),
|
|
20340
|
+
/**
|
|
20341
|
+
* An instant INSIDE this visit's footage, hole-safe, where a recorded still
|
|
20342
|
+
* can be decoded. Present whenever the visit came from recorded availability;
|
|
20343
|
+
* absent on a per-event padded window (there is no footage to promise).
|
|
20344
|
+
*
|
|
20345
|
+
* This is not a thumbnail and not a second byte path: it is the argument to
|
|
20346
|
+
* the recorder's existing still route. The surface — never the provider —
|
|
20347
|
+
* decides whether to use it. It is the midpoint of the visit's LONGEST
|
|
20348
|
+
* contiguous range, not of the visit: a visit spans its holes by
|
|
20349
|
+
* construction, so a naive midpoint lands in dead air.
|
|
20350
|
+
*/
|
|
20351
|
+
stillAtMs: number().optional(),
|
|
20352
|
+
/**
|
|
20353
|
+
* Analytics event ids that overlap this visit — a BOUNDED sample, newest
|
|
20354
|
+
* first within kind (object → motion → audio), capped at
|
|
20355
|
+
* {@link MAX_CLIP_EVENT_IDS}. Empty on footage-only clips.
|
|
20356
|
+
*
|
|
20357
|
+
* Bounded because it is not a payload the surface pages through: one visit on
|
|
20358
|
+
* device 615 carried 2 345 ids, and `eventIds` was 99% of a 153 KB
|
|
20359
|
+
* camera-day. Read {@link eventCount} for the true total.
|
|
20360
|
+
*/
|
|
20361
|
+
eventIds: array(string()).optional(),
|
|
20362
|
+
/** How many analytics events actually overlap this visit. Differs from
|
|
20363
|
+
* `eventIds.length` exactly when the sample was capped — so a truncated
|
|
20364
|
+
* list is never mistaken for a quiet visit. */
|
|
20365
|
+
eventCount: number().int().nonnegative().optional(),
|
|
20366
|
+
/** Intra-visit footage holes (GOP rolls, discarded segments) still shorter
|
|
20367
|
+
* than `VISIT_MERGE_GAP_MS`. Playback concatenates around them; the timeline
|
|
20368
|
+
* bar keeps showing them via `recording.getAvailability`. */
|
|
20369
|
+
holes: array(object({
|
|
20370
|
+
startMs: number(),
|
|
20371
|
+
endMs: number()
|
|
20372
|
+
})).optional()
|
|
20266
20373
|
});
|
|
20267
20374
|
var ClipPlaybackSchema = object({
|
|
20268
20375
|
/** HLS master URL through the hub data-plane (Range + token in path). */
|
|
@@ -20726,7 +20833,14 @@ var SearchResultSchema = object({
|
|
|
20726
20833
|
});
|
|
20727
20834
|
var AutoUpdateSettingsSchema = object({
|
|
20728
20835
|
channel: ChannelSchema,
|
|
20729
|
-
intervalSeconds: number()
|
|
20836
|
+
intervalSeconds: number(),
|
|
20837
|
+
/**
|
|
20838
|
+
* Cadence of the "an update exists" POLLER, in seconds. Independent of
|
|
20839
|
+
* `channel`: the poller runs while auto-apply is `off`, because being told
|
|
20840
|
+
* about a publish and installing it are different decisions. Clamped
|
|
20841
|
+
* server-side to 900 s … 604800 s; defaults to 21600 s (6 h).
|
|
20842
|
+
*/
|
|
20843
|
+
updateCheckIntervalSeconds: number()
|
|
20730
20844
|
});
|
|
20731
20845
|
var AddonAutoUpdateSchema = ChannelWithInheritSchema;
|
|
20732
20846
|
var RestartAddonResultSchema = unknown();
|
|
@@ -20867,7 +20981,9 @@ method(_void(), array(AddonListItemSchema).readonly()), method(object({
|
|
|
20867
20981
|
auth: "admin"
|
|
20868
20982
|
}), method(_void(), AutoUpdateSettingsSchema, { auth: "admin" }), method(object({
|
|
20869
20983
|
channel: ChannelSchema,
|
|
20870
|
-
intervalSeconds: number().min(300).max(86400).optional()
|
|
20984
|
+
intervalSeconds: number().min(300).max(86400).optional(),
|
|
20985
|
+
/** Availability-poll cadence; see AutoUpdateSettingsSchema. */
|
|
20986
|
+
updateCheckIntervalSeconds: number().min(900).max(604800).optional()
|
|
20871
20987
|
}), unknown(), {
|
|
20872
20988
|
kind: "mutation",
|
|
20873
20989
|
auth: "admin"
|
|
@@ -26636,7 +26752,9 @@ var ExportOptionsSchema = object({
|
|
|
26636
26752
|
includeAudio: boolean(),
|
|
26637
26753
|
maxLifeMs: number().int().positive(),
|
|
26638
26754
|
deleteAfterDownload: boolean(),
|
|
26639
|
-
title: string().max(200).optional()
|
|
26755
|
+
title: string().max(200).optional(),
|
|
26756
|
+
/** Notification-output target ids to ping when this export becomes ready. */
|
|
26757
|
+
notifyTargetIds: array(string().min(1)).max(20).optional()
|
|
26640
26758
|
}).superRefine((v, ctx) => {
|
|
26641
26759
|
if (v.speed !== void 0 && v.timelapse !== void 0) ctx.addIssue({
|
|
26642
26760
|
code: ZodIssueCode.custom,
|
|
@@ -26695,10 +26813,18 @@ var ExportBytesSchema = object({
|
|
|
26695
26813
|
});
|
|
26696
26814
|
method(object({
|
|
26697
26815
|
deviceId: number(),
|
|
26698
|
-
|
|
26816
|
+
/** @deprecated Prefer `profiles`. Kept so timelapse/notifiers keep working. */
|
|
26817
|
+
profile: string().optional(),
|
|
26818
|
+
profiles: array(string()).min(1).optional(),
|
|
26699
26819
|
fromMs: number(),
|
|
26700
26820
|
toMs: number(),
|
|
26701
26821
|
options: ExportOptionsSchema
|
|
26822
|
+
}).superRefine((v, ctx) => {
|
|
26823
|
+
if ((v.profiles !== void 0 && v.profiles.length > 0 ? v.profiles : v.profile !== void 0 ? [v.profile] : []).length < 1) ctx.addIssue({
|
|
26824
|
+
code: ZodIssueCode.custom,
|
|
26825
|
+
message: "pass profiles[] (min 1) or legacy profile",
|
|
26826
|
+
path: ["profiles"]
|
|
26827
|
+
});
|
|
26702
26828
|
}), ExportRecordSchema, {
|
|
26703
26829
|
kind: "mutation",
|
|
26704
26830
|
auth: "protected"
|
|
@@ -29838,15 +29964,6 @@ var BaseDeviceProvider = class extends BaseAddon {
|
|
|
29838
29964
|
labels: ["probe not implemented"]
|
|
29839
29965
|
};
|
|
29840
29966
|
}
|
|
29841
|
-
/**
|
|
29842
|
-
* Top-level devices restored at once in {@link onRestoreDevices}.
|
|
29843
|
-
*
|
|
29844
|
-
* Four covers the fleets this ships to without turning a boot into a burst a
|
|
29845
|
-
* camera NVR answers with a refusal. A provider whose upstream is a single
|
|
29846
|
-
* session with a serial command channel (a Baichuan hub, an NVR that
|
|
29847
|
-
* serialises ISAPI) should lower it; nothing needs to raise it.
|
|
29848
|
-
*/
|
|
29849
|
-
restoreConcurrency = 4;
|
|
29850
29967
|
async restoreDevices(savedDevices) {
|
|
29851
29968
|
await this.onRestoreDevices(savedDevices);
|
|
29852
29969
|
if (savedDevices.length > 0) this.ctx.logger.info(`Restored ${savedDevices.length} ${this.providerName} device(s)`);
|
|
@@ -29901,14 +30018,7 @@ var BaseDeviceProvider = class extends BaseAddon {
|
|
|
29901
30018
|
});
|
|
29902
30019
|
}
|
|
29903
30020
|
};
|
|
29904
|
-
|
|
29905
|
-
await Promise.all(Array.from({ length: Math.min(Math.max(1, this.restoreConcurrency), topLevel.length) }, async () => {
|
|
29906
|
-
for (;;) {
|
|
29907
|
-
const saved = topLevel[nextTopLevel++];
|
|
29908
|
-
if (saved === void 0) return;
|
|
29909
|
-
await restoreOne(saved);
|
|
29910
|
-
}
|
|
29911
|
-
}));
|
|
30021
|
+
await Promise.all(topLevel.map((saved) => restoreOne(saved)));
|
|
29912
30022
|
const childRows = savedDevices.filter((s) => s.parentDeviceId !== null);
|
|
29913
30023
|
for (const saved of childRows) {
|
|
29914
30024
|
const Class = this.deviceClasses[saved.type];
|
|
@@ -33312,6 +33422,12 @@ Object.freeze({
|
|
|
33312
33422
|
addonId: null,
|
|
33313
33423
|
access: "create"
|
|
33314
33424
|
},
|
|
33425
|
+
"pipelineAnalytics.reconcileFromDisk": {
|
|
33426
|
+
capName: "pipeline-analytics",
|
|
33427
|
+
capScope: "device",
|
|
33428
|
+
addonId: null,
|
|
33429
|
+
access: "create"
|
|
33430
|
+
},
|
|
33315
33431
|
"pipelineAnalytics.refreshStorageLocationsForMigration": {
|
|
33316
33432
|
capName: "pipeline-analytics",
|
|
33317
33433
|
capScope: "device",
|
|
@@ -33714,6 +33830,12 @@ Object.freeze({
|
|
|
33714
33830
|
addonId: null,
|
|
33715
33831
|
access: "view"
|
|
33716
33832
|
},
|
|
33833
|
+
"pipelineOrchestrator.getReconcileFromDiskStatus": {
|
|
33834
|
+
capName: "pipeline-orchestrator",
|
|
33835
|
+
capScope: "system",
|
|
33836
|
+
addonId: null,
|
|
33837
|
+
access: "view"
|
|
33838
|
+
},
|
|
33717
33839
|
"pipelineOrchestrator.listAgentSettings": {
|
|
33718
33840
|
capName: "pipeline-orchestrator",
|
|
33719
33841
|
capScope: "system",
|
|
@@ -33738,6 +33860,12 @@ Object.freeze({
|
|
|
33738
33860
|
addonId: null,
|
|
33739
33861
|
access: "create"
|
|
33740
33862
|
},
|
|
33863
|
+
"pipelineOrchestrator.reconcileFromDisk": {
|
|
33864
|
+
capName: "pipeline-orchestrator",
|
|
33865
|
+
capScope: "system",
|
|
33866
|
+
addonId: null,
|
|
33867
|
+
access: "create"
|
|
33868
|
+
},
|
|
33741
33869
|
"pipelineOrchestrator.removeAgentSettings": {
|
|
33742
33870
|
capName: "pipeline-orchestrator",
|
|
33743
33871
|
capScope: "system",
|
|
@@ -36729,6 +36857,11 @@ Object.freeze({
|
|
|
36729
36857
|
form: "single",
|
|
36730
36858
|
optional: true
|
|
36731
36859
|
}],
|
|
36860
|
+
"pipelineAnalytics.reconcileFromDisk": [{
|
|
36861
|
+
name: "deviceId",
|
|
36862
|
+
form: "single",
|
|
36863
|
+
optional: false
|
|
36864
|
+
}],
|
|
36732
36865
|
"pipelineAnalytics.restageRetrainTrack": [{
|
|
36733
36866
|
name: "deviceId",
|
|
36734
36867
|
form: "single",
|
|
@@ -37794,6 +37927,8 @@ DEFAULT_NATIVE_LEASE_SETTINGS.budgetMb;
|
|
|
37794
37927
|
DEFAULT_NATIVE_LEASE_SETTINGS.activityMs;
|
|
37795
37928
|
DEFAULT_NATIVE_LEASE_SETTINGS.tileBudgetMb;
|
|
37796
37929
|
DEFAULT_NATIVE_LEASE_SETTINGS.admission;
|
|
37930
|
+
var MB = 1024 * 1024;
|
|
37931
|
+
1024 * MB, 3072 * MB;
|
|
37797
37932
|
//#endregion
|
|
37798
37933
|
//#region src/digest-auth.ts
|
|
37799
37934
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-provider-amcrest",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.22",
|
|
4
4
|
"description": "Amcrest/Dahua camera device provider addon for CamStack — Dahua CGI over HTTP(S) with digest auth (snapshot, RTSP catalog, PTZ, image/day-night config)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|