@camstack/addon-provider-reolink 1.2.13 → 1.2.14
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 +346 -73
- package/dist/addon.mjs +346 -73
- package/package.json +3 -2
package/dist/addon.js
CHANGED
|
@@ -7413,35 +7413,22 @@ function findTimezone(id) {
|
|
|
7413
7413
|
*/
|
|
7414
7414
|
var RecordingWeekdaySchema = number().int().min(0).max(6);
|
|
7415
7415
|
var HHMM = /^([01]\d|2[0-3]):[0-5]\d$/;
|
|
7416
|
-
var RecordingScheduleSchema = discriminatedUnion("kind", [object({ kind: literal("always") }), object({
|
|
7417
|
-
kind: literal("timeOfDay"),
|
|
7418
|
-
start: string().regex(HHMM),
|
|
7419
|
-
end: string().regex(HHMM),
|
|
7420
|
-
/** Restrict to these weekdays; omit = every day. */
|
|
7421
|
-
days: array(RecordingWeekdaySchema).optional()
|
|
7422
|
-
})]);
|
|
7423
|
-
var RecordingModeSchema = _enum([
|
|
7424
|
-
"continuous",
|
|
7425
|
-
"onMotion",
|
|
7426
|
-
"onAudioThreshold"
|
|
7427
|
-
]);
|
|
7428
7416
|
/**
|
|
7429
|
-
*
|
|
7430
|
-
*
|
|
7431
|
-
* - `off` —
|
|
7432
|
-
* - `events` —
|
|
7433
|
-
*
|
|
7434
|
-
* - `continuous` — record 24/7 within the schedule.
|
|
7417
|
+
* DERIVED per-camera storage summary — the single field cheap consumers read
|
|
7418
|
+
* (the viewer's status dot, the camera list) instead of walking `bands`:
|
|
7419
|
+
* - `off` — no band covers the camera (or it is disabled).
|
|
7420
|
+
* - `events` — every band records around triggers only.
|
|
7421
|
+
* - `continuous` — at least one band records continuously.
|
|
7435
7422
|
*
|
|
7436
|
-
*
|
|
7437
|
-
*
|
|
7423
|
+
* NEVER authored: the recorder stamps it from the authoritative `bands` on
|
|
7424
|
+
* every save (`activeModeForConfig`). Writing it has no effect.
|
|
7438
7425
|
*/
|
|
7439
7426
|
var RecordingStorageModeSchema = _enum([
|
|
7440
7427
|
"off",
|
|
7441
7428
|
"events",
|
|
7442
7429
|
"continuous"
|
|
7443
7430
|
]);
|
|
7444
|
-
/** Which detectors trigger an `events`-mode
|
|
7431
|
+
/** Which detectors trigger an `events`-mode band. */
|
|
7445
7432
|
var RecordingTriggersSchema = object({
|
|
7446
7433
|
motion: boolean().optional(),
|
|
7447
7434
|
audioThresholdDbfs: number().optional()
|
|
@@ -7477,18 +7464,6 @@ var RecordingBandSchema = object({
|
|
|
7477
7464
|
preBufferSec: number().min(0).optional(),
|
|
7478
7465
|
postBufferSec: number().min(0).optional()
|
|
7479
7466
|
});
|
|
7480
|
-
var RecordingRuleSchema = object({
|
|
7481
|
-
schedule: RecordingScheduleSchema,
|
|
7482
|
-
mode: RecordingModeSchema,
|
|
7483
|
-
/** Seconds of footage to retain BEFORE a trigger (applied at keep/discard). */
|
|
7484
|
-
preBufferSec: number().min(0).default(0),
|
|
7485
|
-
/** Keep recording until this many seconds after the last trigger. */
|
|
7486
|
-
postBufferSec: number().min(0).default(0),
|
|
7487
|
-
/** Each new trigger restarts the post-buffer window. */
|
|
7488
|
-
resetTimeoutOnNewEvent: boolean().default(true),
|
|
7489
|
-
/** onAudioThreshold only — dBFS level that counts as a trigger. */
|
|
7490
|
-
thresholdDbfs: number().optional()
|
|
7491
|
-
});
|
|
7492
7467
|
/**
|
|
7493
7468
|
* Per-device retention overrides. Every field is optional; an unset or `0`
|
|
7494
7469
|
* value inherits the node-wide recorder default. Only footage-lifetime limits
|
|
@@ -7522,40 +7497,28 @@ var ScrubThumbnailPresetSchema = _enum([
|
|
|
7522
7497
|
/**
|
|
7523
7498
|
* The full per-camera recording intent — the wire shape of a RecordingTarget.
|
|
7524
7499
|
*
|
|
7525
|
-
* `
|
|
7526
|
-
*
|
|
7527
|
-
*
|
|
7528
|
-
*
|
|
7500
|
+
* `bands` is the ONLY authored recording intent: what to record, when, and on
|
|
7501
|
+
* which trigger. `mode` is a derived summary the recorder stamps on save; every
|
|
7502
|
+
* other field is a storage knob (profiles, segment length, retention, scrub).
|
|
7503
|
+
*
|
|
7504
|
+
* STRICT on purpose: the legacy authoring surface (`schedule`/`schedules`/
|
|
7505
|
+
* `triggers`/`preBufferSec`/`postBufferSec`/`rules`) was retired 2026-07-30.
|
|
7506
|
+
* A stale caller must fail loudly — silently stripping its legacy intent would
|
|
7507
|
+
* persist a band-less config, i.e. silently stop recording the camera.
|
|
7529
7508
|
*/
|
|
7530
7509
|
var RecordingConfigSchema = object({
|
|
7531
7510
|
enabled: boolean(),
|
|
7532
|
-
/**
|
|
7533
|
-
*
|
|
7511
|
+
/** DERIVED summary of `bands`, stamped by the recorder on every save.
|
|
7512
|
+
* Authoring it has no effect — see {@link RecordingStorageModeSchema}. */
|
|
7534
7513
|
mode: RecordingStorageModeSchema.optional(),
|
|
7535
7514
|
profiles: array(CamProfileSchema).optional(),
|
|
7536
7515
|
segmentSeconds: number().int().positive().optional(),
|
|
7537
|
-
/** Shared recording time-bands for `events` & `continuous` — record only when
|
|
7538
|
-
* the wall-clock falls inside one of these windows. Omit or empty = always.
|
|
7539
|
-
* `continuous` compiles to one rule per band; `events` to band × trigger. */
|
|
7540
|
-
schedules: array(RecordingScheduleSchema).optional(),
|
|
7541
|
-
/** Legacy single-band predecessor of `schedules`. Read-compat only — it is
|
|
7542
|
-
* normalized into `schedules` on read and never written going forward. (Not
|
|
7543
|
-
* tagged `@deprecated`: the normalization paths must read it cast-free.) */
|
|
7544
|
-
schedule: RecordingScheduleSchema.optional(),
|
|
7545
|
-
/** `events`-mode only — which detectors trigger a recording. */
|
|
7546
|
-
triggers: RecordingTriggersSchema.optional(),
|
|
7547
|
-
/** `events`-mode only — seconds retained before / after a trigger. */
|
|
7548
|
-
preBufferSec: number().min(0).optional(),
|
|
7549
|
-
postBufferSec: number().min(0).optional(),
|
|
7550
|
-
/** DEPRECATED authoring input; retained for migration/transition. */
|
|
7551
|
-
rules: array(RecordingRuleSchema).optional(),
|
|
7552
7516
|
/**
|
|
7553
|
-
* AUTHORITATIVE mode-per-band recording model
|
|
7554
|
-
*
|
|
7555
|
-
*
|
|
7556
|
-
* derived into bands once via `migrateConfigToBands`.
|
|
7517
|
+
* AUTHORITATIVE mode-per-band recording model — the single source of truth
|
|
7518
|
+
* the recorder's band engine consumes. An empty array = record nothing;
|
|
7519
|
+
* "off" is the absence of a covering band, never a band value.
|
|
7557
7520
|
*/
|
|
7558
|
-
bands: array(RecordingBandSchema).
|
|
7521
|
+
bands: array(RecordingBandSchema).default([]),
|
|
7559
7522
|
retention: RecordingRetentionSchema.optional(),
|
|
7560
7523
|
/**
|
|
7561
7524
|
* Per-camera scrub-thumbnail fidelity preset (resolution + JPEG quality for
|
|
@@ -7563,8 +7526,15 @@ var RecordingConfigSchema = object({
|
|
|
7563
7526
|
* windows only — existing sheets are immutable, and each window's index
|
|
7564
7527
|
* carries its own tile dims so mixed-preset history renders correctly.
|
|
7565
7528
|
*/
|
|
7566
|
-
scrubThumbnails: ScrubThumbnailPresetSchema.optional()
|
|
7567
|
-
|
|
7529
|
+
scrubThumbnails: ScrubThumbnailPresetSchema.optional(),
|
|
7530
|
+
/**
|
|
7531
|
+
* OPT-IN thumbnail-strip generation for this camera: every keyframe of the
|
|
7532
|
+
* low recording saved as a JPEG (the fast-drag scrub depth), a derived
|
|
7533
|
+
* cache that eviction reclaims with the footage. Absent/false = no strips
|
|
7534
|
+
* are written and scrub reads exact keyframes at every velocity.
|
|
7535
|
+
*/
|
|
7536
|
+
stripsEnabled: boolean().optional()
|
|
7537
|
+
}).strict();
|
|
7568
7538
|
/**
|
|
7569
7539
|
* Ops-log — the durable, append-only operations audit shared by the
|
|
7570
7540
|
* recordings and events management surfaces.
|
|
@@ -7583,7 +7553,8 @@ var OpsLogOpSchema = _enum([
|
|
|
7583
7553
|
"prune",
|
|
7584
7554
|
"manual-delete",
|
|
7585
7555
|
"rescan",
|
|
7586
|
-
"retention-run"
|
|
7556
|
+
"retention-run",
|
|
7557
|
+
"relocate"
|
|
7587
7558
|
]);
|
|
7588
7559
|
/** Why the operation ran. */
|
|
7589
7560
|
var OpsLogReasonSchema = _enum([
|
|
@@ -7622,6 +7593,55 @@ var OpsLogQueryInputSchema = object({
|
|
|
7622
7593
|
limit: number().int().min(1).max(1e3).optional()
|
|
7623
7594
|
});
|
|
7624
7595
|
/**
|
|
7596
|
+
* Entity-relocation job state (storage entity-routing spec, Phase 4).
|
|
7597
|
+
*
|
|
7598
|
+
* One shape shared by the recorder's `relocateFootage` (segments + strips) and
|
|
7599
|
+
* pipeline-analytics' `relocateMedia` (event media blobs) so the admin Data
|
|
7600
|
+
* page renders both movers with one component. Jobs are in-RAM (a restart
|
|
7601
|
+
* forgets them — re-running is safe by construction: copy-if-absent, delete
|
|
7602
|
+
* after verify) and each completed/failed run also lands one durable ops-log
|
|
7603
|
+
* row on the owning addon's surface.
|
|
7604
|
+
*/
|
|
7605
|
+
var RelocateJobStateSchema = _enum([
|
|
7606
|
+
"running",
|
|
7607
|
+
"done",
|
|
7608
|
+
"failed",
|
|
7609
|
+
"cancelled"
|
|
7610
|
+
]);
|
|
7611
|
+
var RelocateJobSchema = object({
|
|
7612
|
+
jobId: string(),
|
|
7613
|
+
state: RelocateJobStateSchema,
|
|
7614
|
+
/** Source location — for media relocation this is informational ('*': rows
|
|
7615
|
+
* move from wherever they are to the target). */
|
|
7616
|
+
fromLocationId: string(),
|
|
7617
|
+
toLocationId: string(),
|
|
7618
|
+
/** Scoped device, or null = every device. */
|
|
7619
|
+
deviceId: number().nullable(),
|
|
7620
|
+
/** What the job moves (owner-addon specific: segments/strips or media). */
|
|
7621
|
+
entities: array(string()),
|
|
7622
|
+
filesMoved: number().int(),
|
|
7623
|
+
bytesMoved: number().int(),
|
|
7624
|
+
/** Total files discovered up front; null while (or when) unknown. */
|
|
7625
|
+
filesTotal: number().int().nullable(),
|
|
7626
|
+
startedAt: number(),
|
|
7627
|
+
finishedAt: number().nullable(),
|
|
7628
|
+
error: string().nullable()
|
|
7629
|
+
});
|
|
7630
|
+
var RelocateFootageInputSchema = object({
|
|
7631
|
+
deviceId: number().optional(),
|
|
7632
|
+
fromLocationId: string(),
|
|
7633
|
+
toLocationId: string(),
|
|
7634
|
+
entities: array(_enum(["segments", "strips"])).optional(),
|
|
7635
|
+
/** Copy throttle in MB/s (default 40) — the drain is a background chore,
|
|
7636
|
+
* never allowed to starve live writers. */
|
|
7637
|
+
throttleMbps: number().min(1).max(1e3).optional()
|
|
7638
|
+
});
|
|
7639
|
+
var RelocateMediaInputSchema = object({
|
|
7640
|
+
deviceId: number().optional(),
|
|
7641
|
+
toLocationId: string(),
|
|
7642
|
+
throttleMbps: number().min(1).max(1e3).optional()
|
|
7643
|
+
});
|
|
7644
|
+
/**
|
|
7625
7645
|
* `StorageLocationType` — an addon-declared id that identifies the *kind* of
|
|
7626
7646
|
* storage a location serves. Defined here (not in `capabilities/storage.cap.ts`)
|
|
7627
7647
|
* so the persisted record schema and the consumer-facing cap can both consume it
|
|
@@ -7671,6 +7691,13 @@ var StorageLocationSchema = object({
|
|
|
7671
7691
|
nodeId: string().optional(),
|
|
7672
7692
|
isDefault: boolean().default(false),
|
|
7673
7693
|
isSystem: boolean().default(false),
|
|
7694
|
+
/** COMPUTED at read time by the orchestrator (statfs of the backing volume
|
|
7695
|
+
* for node-local locations it can reach) — never persisted, absent when the
|
|
7696
|
+
* volume is remote/unreachable. The single capacity truth every UI reads. */
|
|
7697
|
+
capacity: object({
|
|
7698
|
+
totalBytes: number(),
|
|
7699
|
+
availableBytes: number()
|
|
7700
|
+
}).nullable().optional(),
|
|
7674
7701
|
createdAt: number(),
|
|
7675
7702
|
updatedAt: number()
|
|
7676
7703
|
});
|
|
@@ -8438,7 +8465,8 @@ var NcTaxonomyEntrySchema = object({
|
|
|
8438
8465
|
/** Macro/category parent for grouping ('car' → 'vehicle'); null for a top. */
|
|
8439
8466
|
parentKind: string().nullable()
|
|
8440
8467
|
});
|
|
8441
|
-
|
|
8468
|
+
/** The complete NC picker taxonomy — three grouped buckets. */
|
|
8469
|
+
var NcTaxonomySchema = object({
|
|
8442
8470
|
videoClasses: array(NcTaxonomyEntrySchema),
|
|
8443
8471
|
audioKinds: array(NcTaxonomyEntrySchema),
|
|
8444
8472
|
labels: array(NcTaxonomyEntrySchema)
|
|
@@ -9380,6 +9408,7 @@ function createRuntimeStateBridge(params) {
|
|
|
9380
9408
|
getStatus
|
|
9381
9409
|
};
|
|
9382
9410
|
}
|
|
9411
|
+
new Set(["devices", "classes"]);
|
|
9383
9412
|
/**
|
|
9384
9413
|
* Shared geometry vocabulary for on-frame shape caps — privacy-mask,
|
|
9385
9414
|
* motion-zones, and the detection zones/lines editor all speak this one
|
|
@@ -9696,12 +9725,60 @@ var NcRuleTargetSchema = object({
|
|
|
9696
9725
|
* - `keyFrame` — the clean scene frame (no subject box).
|
|
9697
9726
|
* - `none` — no attachment.
|
|
9698
9727
|
*/
|
|
9699
|
-
|
|
9700
|
-
|
|
9701
|
-
|
|
9702
|
-
|
|
9703
|
-
|
|
9704
|
-
|
|
9728
|
+
/**
|
|
9729
|
+
* WHAT THE PICTURE SHOWS — chosen explicitly, because the implicit ladders
|
|
9730
|
+
* conflate it with the selection strategy and betray the request: asking for
|
|
9731
|
+
* the clean scene frame on an object-event owner used to start at
|
|
9732
|
+
* `fullFrameBoxed`, i.e. the annotated frame (2026-07-30).
|
|
9733
|
+
* - `cropped` — the subject, tight. What "who is at the door" wants.
|
|
9734
|
+
* - `full` — the clean scene, no annotation. What "what is going on" wants.
|
|
9735
|
+
* - `boxed` — the scene WITH the detection boxes drawn, for verifying what
|
|
9736
|
+
* the pipeline actually saw.
|
|
9737
|
+
*/
|
|
9738
|
+
var NcMediaFrameSchema = _enum([
|
|
9739
|
+
"cropped",
|
|
9740
|
+
"full",
|
|
9741
|
+
"boxed"
|
|
9742
|
+
]);
|
|
9743
|
+
var NcMediaPolicySchema = object({
|
|
9744
|
+
attach: _enum([
|
|
9745
|
+
"best",
|
|
9746
|
+
"best-matching",
|
|
9747
|
+
"keyFrame",
|
|
9748
|
+
"none"
|
|
9749
|
+
]).default("best"),
|
|
9750
|
+
/** What the still shows. Absent = `cropped` (the historical `best` shape). */
|
|
9751
|
+
frame: NcMediaFrameSchema.optional(),
|
|
9752
|
+
/** Crop the attached still to the rule's condition-zone bbox (padded) —
|
|
9753
|
+
* "show me the ZONE", not the whole scene or the subject crop. */
|
|
9754
|
+
zoneCrop: boolean().optional(),
|
|
9755
|
+
/**
|
|
9756
|
+
* Also attach a short GIF cut from the stream broker's clip ring around the
|
|
9757
|
+
* event — NOT from the recording, so the camera does not have to be
|
|
9758
|
+
* recording, and the window sits AROUND the moment instead of a segment
|
|
9759
|
+
* behind it. Fail-closed: a window the ring does not cover contributes no
|
|
9760
|
+
* gif, never a failed notification.
|
|
9761
|
+
*/
|
|
9762
|
+
gif: boolean().optional(),
|
|
9763
|
+
/**
|
|
9764
|
+
* Also attach a short MP4 CLIP of the same cut. Same source and the same
|
|
9765
|
+
* fail-closed rule as `gif`. Prefer it where the backend takes video
|
|
9766
|
+
* (telegram, discord, zentik, webhook); backends that do not are handled by
|
|
9767
|
+
* the degrade engine, which drops the video and keeps the still.
|
|
9768
|
+
*/
|
|
9769
|
+
clip: boolean().optional(),
|
|
9770
|
+
/** Seconds of footage BEFORE / AFTER the event instant. Defaults 3 / 7. */
|
|
9771
|
+
clipPreRollSec: number().int().min(0).max(30).optional(),
|
|
9772
|
+
clipPostRollSec: number().int().min(0).max(30).optional(),
|
|
9773
|
+
/**
|
|
9774
|
+
* Which stream profile the footage is cut from. Absent = the CHEAPEST
|
|
9775
|
+
* assigned profile: a notification is watched on a phone, so the 4K
|
|
9776
|
+
* rendition would burn CPU to produce a file the client downscales anyway.
|
|
9777
|
+
* A profile that is not assigned falls back to the cheapest, and the render
|
|
9778
|
+
* reports which one actually ran.
|
|
9779
|
+
*/
|
|
9780
|
+
profile: CamProfileSchema.optional()
|
|
9781
|
+
});
|
|
9705
9782
|
/** Throttle — cooldown survives restarts (rebuilt from the outbox on boot). */
|
|
9706
9783
|
var NcThrottleSchema = object({
|
|
9707
9784
|
cooldownSec: number().int().min(0).max(86400).default(60),
|
|
@@ -9715,7 +9792,19 @@ var NcRuleInputSchema = object({
|
|
|
9715
9792
|
delivery: NcDeliverySchema,
|
|
9716
9793
|
conditions: NcConditionsSchema.default({}),
|
|
9717
9794
|
schedule: NcScheduleSchema.optional(),
|
|
9718
|
-
|
|
9795
|
+
/** May be empty when `targetUsers` addresses at least one user — the
|
|
9796
|
+
* "at least one addressee" invariant is enforced by the provider, because
|
|
9797
|
+
* a cross-field refine here would break `NcRulePatchSchema.partial()`. */
|
|
9798
|
+
targets: array(NcRuleTargetSchema),
|
|
9799
|
+
/**
|
|
9800
|
+
* USERS this rule addresses in addition to `targets` (Phase 4). At fire
|
|
9801
|
+
* time each user fans out to the personal targets they own
|
|
9802
|
+
* (`config.ownerUserId`), filtered by that user's `allowedDevices` for the
|
|
9803
|
+
* firing camera — a user is never notified about a device they cannot open.
|
|
9804
|
+
* Per-user opt-outs (`disabledTargetIds`) still apply to the fanned-out
|
|
9805
|
+
* targets.
|
|
9806
|
+
*/
|
|
9807
|
+
targetUsers: array(string()).optional(),
|
|
9719
9808
|
media: NcMediaPolicySchema.default({ attach: "best" }),
|
|
9720
9809
|
throttle: NcThrottleSchema.default({
|
|
9721
9810
|
cooldownSec: 60,
|
|
@@ -9928,7 +10017,10 @@ method(object({}), object({ rules: array(NcRuleSchema) }), { auth: "admin" }), m
|
|
|
9928
10017
|
}), object({ results: array(NcTestResultSchema) }), {
|
|
9929
10018
|
kind: "mutation",
|
|
9930
10019
|
auth: "admin"
|
|
9931
|
-
}), method(object({}), object({
|
|
10020
|
+
}), method(object({}), object({
|
|
10021
|
+
catalog: array(NcConditionDescriptorSchema),
|
|
10022
|
+
taxonomy: NcTaxonomySchema.optional()
|
|
10023
|
+
})), method(object({ filter: NcHistoryFilterSchema.default({ limit: 100 }) }), object({ entries: array(NcHistoryEntrySchema) }), { auth: "admin" });
|
|
9932
10024
|
/**
|
|
9933
10025
|
* TimelapseRule — the STANDALONE scheduled timelapse producer's rule model.
|
|
9934
10026
|
*
|
|
@@ -10937,6 +11029,28 @@ method(object({
|
|
|
10937
11029
|
}), object({ success: literal(true) }), {
|
|
10938
11030
|
kind: "mutation",
|
|
10939
11031
|
auth: "admin"
|
|
11032
|
+
}), method(object({
|
|
11033
|
+
deviceId: number(),
|
|
11034
|
+
/** Absent = the LOWEST assigned profile — a notification attachment is
|
|
11035
|
+
* watched on a phone, and the cheap rendition is the right default. */
|
|
11036
|
+
profile: CamProfileSchema.optional(),
|
|
11037
|
+
aroundMs: number(),
|
|
11038
|
+
preRollSec: number().min(0).max(20).default(3),
|
|
11039
|
+
postRollSec: number().min(0).max(20).default(5),
|
|
11040
|
+
format: _enum(["gif", "mp4"]).default("gif"),
|
|
11041
|
+
maxWidth: number().int().min(120).max(1920).default(480),
|
|
11042
|
+
/** GIF only — MP4 keeps the source cadence. */
|
|
11043
|
+
fps: number().int().min(1).max(15).default(5)
|
|
11044
|
+
}), object({
|
|
11045
|
+
base64: string(),
|
|
11046
|
+
mime: string(),
|
|
11047
|
+
bytes: number().int(),
|
|
11048
|
+
/** The profile actually rendered (what the default resolved to). */
|
|
11049
|
+
profile: CamProfileSchema,
|
|
11050
|
+
durationMs: number()
|
|
11051
|
+
}), {
|
|
11052
|
+
kind: "mutation",
|
|
11053
|
+
auth: "admin"
|
|
10940
11054
|
}), method(_void(), array(CameraStreamSchema).readonly()), method(_void(), array(ProfileSlotSchema).readonly()), method(object({ brokerId: string() }), BrokerStatsSchema), method(object({ brokerId: string() }), object({
|
|
10941
11055
|
probed: boolean(),
|
|
10942
11056
|
summary: string()
|
|
@@ -19942,6 +20056,36 @@ var TargetKindSchema = object({
|
|
|
19942
20056
|
icon: string(),
|
|
19943
20057
|
/** Stamped by each provider so the concat-fanned catalog stays routable. */
|
|
19944
20058
|
addonId: string(),
|
|
20059
|
+
/**
|
|
20060
|
+
* URL of the kind's bundled BRAND icon, served by the providing addon over
|
|
20061
|
+
* its own `addon-routes` surface (`/addon/<addonId>/icons/<kind>`). Absent
|
|
20062
|
+
* when the addon bundles no icon for that kind — the client then falls back
|
|
20063
|
+
* to a neutral glyph rather than rendering the raw `icon` NAME as text.
|
|
20064
|
+
*
|
|
20065
|
+
* Root-relative on purpose: it resolves against whatever origin serves a web
|
|
20066
|
+
* client, and a native client joins it onto its own hub base.
|
|
20067
|
+
*
|
|
20068
|
+
* DECLARED here deliberately. It used to travel as an undeclared passthrough
|
|
20069
|
+
* field that survived only because the runtime cap-router forwards provider
|
|
20070
|
+
* output verbatim — so every consumer had to re-declare it by hand to stop
|
|
20071
|
+
* its own Zod parse from stripping it, and the whole arrangement would have
|
|
20072
|
+
* broken silently the moment output validation was tightened anywhere.
|
|
20073
|
+
*/
|
|
20074
|
+
iconUrl: string().optional(),
|
|
20075
|
+
/**
|
|
20076
|
+
* Media type of {@link iconUrl} (`image/svg+xml`, `image/png`, …).
|
|
20077
|
+
*
|
|
20078
|
+
* The server knows this and therefore says it, because the client cannot
|
|
20079
|
+
* safely guess: a React-Native client renders SVG and raster through two
|
|
20080
|
+
* DIFFERENT components (`react-native-svg` vs `expo-image` — expo-image does
|
|
20081
|
+
* not decode SVG on iOS/Android), so without this it silently fell back to a
|
|
20082
|
+
* placeholder glyph for every vector icon while the web build looked fine.
|
|
20083
|
+
*
|
|
20084
|
+
* Absent when {@link iconUrl} is absent, or for a legacy provider that has
|
|
20085
|
+
* not been updated — a client that cannot determine the type should prefer
|
|
20086
|
+
* its raster path, which is the safe default for an unknown image.
|
|
20087
|
+
*/
|
|
20088
|
+
iconMediaType: string().optional(),
|
|
19945
20089
|
configSchema: ConfigSchemaPassthrough,
|
|
19946
20090
|
supportsDiscovery: boolean(),
|
|
19947
20091
|
caps: TargetKindCapsSchema
|
|
@@ -20673,6 +20817,15 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
20673
20817
|
}), method(object({ deviceId: number() }), EventPruneCountsSchema, {
|
|
20674
20818
|
kind: "mutation",
|
|
20675
20819
|
auth: "admin"
|
|
20820
|
+
}), method(RelocateMediaInputSchema, object({ jobId: string() }), {
|
|
20821
|
+
kind: "mutation",
|
|
20822
|
+
auth: "admin"
|
|
20823
|
+
}), method(object({}), array(RelocateJobSchema).readonly(), {
|
|
20824
|
+
kind: "query",
|
|
20825
|
+
auth: "admin"
|
|
20826
|
+
}), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
20827
|
+
kind: "mutation",
|
|
20828
|
+
auth: "admin"
|
|
20676
20829
|
}), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
|
|
20677
20830
|
kind: "query",
|
|
20678
20831
|
auth: "admin"
|
|
@@ -23254,6 +23407,17 @@ var GetConnectionEndpointsResultSchema = object({ endpoints: array(object({
|
|
|
23254
23407
|
*/
|
|
23255
23408
|
priority: number()
|
|
23256
23409
|
})).readonly() });
|
|
23410
|
+
/**
|
|
23411
|
+
* The chosen outbound endpoint for notification artifacts. `baseUrl: null` =
|
|
23412
|
+
* AUTO (resolved from the candidate ranking at send time); `resolved` reports
|
|
23413
|
+
* what AUTO currently picks, so the UI can show the effective value either way.
|
|
23414
|
+
*/
|
|
23415
|
+
var NotificationEndpointSchema = object({
|
|
23416
|
+
/** The operator's explicit choice, or null for AUTO. */
|
|
23417
|
+
baseUrl: string().nullable(),
|
|
23418
|
+
/** What the ranking currently resolves to (null when nothing is reachable). */
|
|
23419
|
+
resolved: string().nullable()
|
|
23420
|
+
});
|
|
23257
23421
|
var AllowedAddressesSchema = object({
|
|
23258
23422
|
/**
|
|
23259
23423
|
* Allowlist of interface addresses operators have explicitly opted
|
|
@@ -23276,7 +23440,7 @@ method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(obje
|
|
|
23276
23440
|
* to avoid mixed-content blocks in the browser. The public
|
|
23277
23441
|
* tunnel always emits `https://` regardless. */
|
|
23278
23442
|
scheme: _enum(["http", "https"]).optional()
|
|
23279
|
-
}), GetConnectionEndpointsResultSchema), method(_void(), AllowedAddressesSchema), method(AllowedAddressesSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), AllowedAddressesSchema, { kind: "mutation" });
|
|
23443
|
+
}), GetConnectionEndpointsResultSchema), method(_void(), NotificationEndpointSchema), method(object({ baseUrl: string().nullable() }), NotificationEndpointSchema, { kind: "mutation" }), method(_void(), AllowedAddressesSchema), method(AllowedAddressesSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), AllowedAddressesSchema, { kind: "mutation" });
|
|
23280
23444
|
/**
|
|
23281
23445
|
* mesh-network — collection cap for mesh-VPN providers.
|
|
23282
23446
|
*
|
|
@@ -24142,7 +24306,12 @@ var RecordingDeviceUsageSchema = object({
|
|
|
24142
24306
|
var RecordingLocationUsageSchema = object({
|
|
24143
24307
|
/** StorageLocation id; null for the legacy/degraded single-root fallback. */
|
|
24144
24308
|
locationId: string().nullable(),
|
|
24145
|
-
/**
|
|
24309
|
+
/** Every location id sharing this row's PHYSICAL volume (aliases). One row
|
|
24310
|
+
* is emitted per physical disk (2026-07-29): two locations on one root
|
|
24311
|
+
* previously rendered as two identical "disks" with a nonsensical used
|
|
24312
|
+
* split — hydrate attribution across aliases is arbitrary by nature. */
|
|
24313
|
+
locationIds: array(string()).optional(),
|
|
24314
|
+
/** Bytes of recordings stored on this PHYSICAL volume (all aliases). */
|
|
24146
24315
|
usedBytes: number(),
|
|
24147
24316
|
/** Free bytes on the location's volume; null when capacity is unknown (remote). */
|
|
24148
24317
|
availableBytes: number().nullable(),
|
|
@@ -24254,6 +24423,44 @@ method(object({
|
|
|
24254
24423
|
}), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
|
|
24255
24424
|
kind: "query",
|
|
24256
24425
|
auth: "admin"
|
|
24426
|
+
}), method(object({
|
|
24427
|
+
deviceId: number(),
|
|
24428
|
+
aroundMs: number(),
|
|
24429
|
+
preRollSec: number().min(0).max(30).default(2),
|
|
24430
|
+
postRollSec: number().min(0).max(30).default(5),
|
|
24431
|
+
maxWidth: number().int().min(120).max(1280).default(480),
|
|
24432
|
+
fps: number().int().min(1).max(15).default(5)
|
|
24433
|
+
}), object({
|
|
24434
|
+
gifBase64: string(),
|
|
24435
|
+
fromMs: number(),
|
|
24436
|
+
toMs: number()
|
|
24437
|
+
}), {
|
|
24438
|
+
kind: "mutation",
|
|
24439
|
+
auth: "admin"
|
|
24440
|
+
}), method(object({
|
|
24441
|
+
deviceId: number(),
|
|
24442
|
+
aroundMs: number(),
|
|
24443
|
+
preRollSec: number().min(0).max(30).default(3),
|
|
24444
|
+
postRollSec: number().min(0).max(30).default(7),
|
|
24445
|
+
maxWidth: number().int().min(160).max(1920).default(640)
|
|
24446
|
+
}), object({
|
|
24447
|
+
clipBase64: string(),
|
|
24448
|
+
mime: string(),
|
|
24449
|
+
fromMs: number(),
|
|
24450
|
+
toMs: number(),
|
|
24451
|
+
bytes: number().int()
|
|
24452
|
+
}), {
|
|
24453
|
+
kind: "mutation",
|
|
24454
|
+
auth: "admin"
|
|
24455
|
+
}), method(RelocateFootageInputSchema, object({ jobId: string() }), {
|
|
24456
|
+
kind: "mutation",
|
|
24457
|
+
auth: "admin"
|
|
24458
|
+
}), method(object({}), array(RelocateJobSchema).readonly(), {
|
|
24459
|
+
kind: "query",
|
|
24460
|
+
auth: "admin"
|
|
24461
|
+
}), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
24462
|
+
kind: "mutation",
|
|
24463
|
+
auth: "admin"
|
|
24257
24464
|
});
|
|
24258
24465
|
/**
|
|
24259
24466
|
* `recordingExport` cap — render a footage time range into a single downloadable
|
|
@@ -26950,6 +27157,12 @@ Object.freeze({
|
|
|
26950
27157
|
addonId: null,
|
|
26951
27158
|
access: "view"
|
|
26952
27159
|
},
|
|
27160
|
+
"localNetwork.getNotificationEndpoint": {
|
|
27161
|
+
capName: "local-network",
|
|
27162
|
+
capScope: "system",
|
|
27163
|
+
addonId: null,
|
|
27164
|
+
access: "view"
|
|
27165
|
+
},
|
|
26953
27166
|
"localNetwork.getPreferred": {
|
|
26954
27167
|
capName: "local-network",
|
|
26955
27168
|
capScope: "system",
|
|
@@ -26974,6 +27187,12 @@ Object.freeze({
|
|
|
26974
27187
|
addonId: null,
|
|
26975
27188
|
access: "create"
|
|
26976
27189
|
},
|
|
27190
|
+
"localNetwork.setNotificationEndpoint": {
|
|
27191
|
+
capName: "local-network",
|
|
27192
|
+
capScope: "system",
|
|
27193
|
+
addonId: null,
|
|
27194
|
+
access: "create"
|
|
27195
|
+
},
|
|
26977
27196
|
"lockControl.lock": {
|
|
26978
27197
|
capName: "lock-control",
|
|
26979
27198
|
capScope: "device",
|
|
@@ -27616,6 +27835,12 @@ Object.freeze({
|
|
|
27616
27835
|
addonId: null,
|
|
27617
27836
|
access: "create"
|
|
27618
27837
|
},
|
|
27838
|
+
"pipelineAnalytics.cancelMediaRelocate": {
|
|
27839
|
+
capName: "pipeline-analytics",
|
|
27840
|
+
capScope: "device",
|
|
27841
|
+
addonId: null,
|
|
27842
|
+
access: "create"
|
|
27843
|
+
},
|
|
27619
27844
|
"pipelineAnalytics.clearTracks": {
|
|
27620
27845
|
capName: "pipeline-analytics",
|
|
27621
27846
|
capScope: "device",
|
|
@@ -27670,6 +27895,12 @@ Object.freeze({
|
|
|
27670
27895
|
addonId: null,
|
|
27671
27896
|
access: "view"
|
|
27672
27897
|
},
|
|
27898
|
+
"pipelineAnalytics.getMediaRelocateStatus": {
|
|
27899
|
+
capName: "pipeline-analytics",
|
|
27900
|
+
capScope: "device",
|
|
27901
|
+
addonId: null,
|
|
27902
|
+
access: "view"
|
|
27903
|
+
},
|
|
27673
27904
|
"pipelineAnalytics.getMotionEvents": {
|
|
27674
27905
|
capName: "pipeline-analytics",
|
|
27675
27906
|
capScope: "device",
|
|
@@ -27742,6 +27973,12 @@ Object.freeze({
|
|
|
27742
27973
|
addonId: null,
|
|
27743
27974
|
access: "create"
|
|
27744
27975
|
},
|
|
27976
|
+
"pipelineAnalytics.relocateMedia": {
|
|
27977
|
+
capName: "pipeline-analytics",
|
|
27978
|
+
capScope: "device",
|
|
27979
|
+
addonId: null,
|
|
27980
|
+
access: "create"
|
|
27981
|
+
},
|
|
27745
27982
|
"pipelineAnalytics.searchObjectEvents": {
|
|
27746
27983
|
capName: "pipeline-analytics",
|
|
27747
27984
|
capScope: "device",
|
|
@@ -28504,6 +28741,12 @@ Object.freeze({
|
|
|
28504
28741
|
addonId: null,
|
|
28505
28742
|
access: "create"
|
|
28506
28743
|
},
|
|
28744
|
+
"recording.cancelRelocate": {
|
|
28745
|
+
capName: "recording",
|
|
28746
|
+
capScope: "system",
|
|
28747
|
+
addonId: null,
|
|
28748
|
+
access: "create"
|
|
28749
|
+
},
|
|
28507
28750
|
"recording.deleteFootprint": {
|
|
28508
28751
|
capName: "recording",
|
|
28509
28752
|
capScope: "system",
|
|
@@ -28534,6 +28777,12 @@ Object.freeze({
|
|
|
28534
28777
|
addonId: null,
|
|
28535
28778
|
access: "view"
|
|
28536
28779
|
},
|
|
28780
|
+
"recording.getRelocateStatus": {
|
|
28781
|
+
capName: "recording",
|
|
28782
|
+
capScope: "system",
|
|
28783
|
+
addonId: null,
|
|
28784
|
+
access: "view"
|
|
28785
|
+
},
|
|
28537
28786
|
"recording.getStorageUsage": {
|
|
28538
28787
|
capName: "recording",
|
|
28539
28788
|
capScope: "system",
|
|
@@ -28564,6 +28813,24 @@ Object.freeze({
|
|
|
28564
28813
|
addonId: null,
|
|
28565
28814
|
access: "view"
|
|
28566
28815
|
},
|
|
28816
|
+
"recording.relocateFootage": {
|
|
28817
|
+
capName: "recording",
|
|
28818
|
+
capScope: "system",
|
|
28819
|
+
addonId: null,
|
|
28820
|
+
access: "create"
|
|
28821
|
+
},
|
|
28822
|
+
"recording.renderClip": {
|
|
28823
|
+
capName: "recording",
|
|
28824
|
+
capScope: "system",
|
|
28825
|
+
addonId: null,
|
|
28826
|
+
access: "create"
|
|
28827
|
+
},
|
|
28828
|
+
"recording.renderGif": {
|
|
28829
|
+
capName: "recording",
|
|
28830
|
+
capScope: "system",
|
|
28831
|
+
addonId: null,
|
|
28832
|
+
access: "create"
|
|
28833
|
+
},
|
|
28567
28834
|
"recording.rescanStorage": {
|
|
28568
28835
|
capName: "recording",
|
|
28569
28836
|
capScope: "system",
|
|
@@ -29158,6 +29425,12 @@ Object.freeze({
|
|
|
29158
29425
|
addonId: null,
|
|
29159
29426
|
access: "create"
|
|
29160
29427
|
},
|
|
29428
|
+
"streamBroker.renderPreBufferClip": {
|
|
29429
|
+
capName: "stream-broker",
|
|
29430
|
+
capScope: "system",
|
|
29431
|
+
addonId: null,
|
|
29432
|
+
access: "create"
|
|
29433
|
+
},
|
|
29161
29434
|
"streamBroker.restartProfile": {
|
|
29162
29435
|
capName: "stream-broker",
|
|
29163
29436
|
capScope: "system",
|
package/dist/addon.mjs
CHANGED
|
@@ -7408,35 +7408,22 @@ function findTimezone(id) {
|
|
|
7408
7408
|
*/
|
|
7409
7409
|
var RecordingWeekdaySchema = number().int().min(0).max(6);
|
|
7410
7410
|
var HHMM = /^([01]\d|2[0-3]):[0-5]\d$/;
|
|
7411
|
-
var RecordingScheduleSchema = discriminatedUnion("kind", [object({ kind: literal("always") }), object({
|
|
7412
|
-
kind: literal("timeOfDay"),
|
|
7413
|
-
start: string().regex(HHMM),
|
|
7414
|
-
end: string().regex(HHMM),
|
|
7415
|
-
/** Restrict to these weekdays; omit = every day. */
|
|
7416
|
-
days: array(RecordingWeekdaySchema).optional()
|
|
7417
|
-
})]);
|
|
7418
|
-
var RecordingModeSchema = _enum([
|
|
7419
|
-
"continuous",
|
|
7420
|
-
"onMotion",
|
|
7421
|
-
"onAudioThreshold"
|
|
7422
|
-
]);
|
|
7423
7411
|
/**
|
|
7424
|
-
*
|
|
7425
|
-
*
|
|
7426
|
-
* - `off` —
|
|
7427
|
-
* - `events` —
|
|
7428
|
-
*
|
|
7429
|
-
* - `continuous` — record 24/7 within the schedule.
|
|
7412
|
+
* DERIVED per-camera storage summary — the single field cheap consumers read
|
|
7413
|
+
* (the viewer's status dot, the camera list) instead of walking `bands`:
|
|
7414
|
+
* - `off` — no band covers the camera (or it is disabled).
|
|
7415
|
+
* - `events` — every band records around triggers only.
|
|
7416
|
+
* - `continuous` — at least one band records continuously.
|
|
7430
7417
|
*
|
|
7431
|
-
*
|
|
7432
|
-
*
|
|
7418
|
+
* NEVER authored: the recorder stamps it from the authoritative `bands` on
|
|
7419
|
+
* every save (`activeModeForConfig`). Writing it has no effect.
|
|
7433
7420
|
*/
|
|
7434
7421
|
var RecordingStorageModeSchema = _enum([
|
|
7435
7422
|
"off",
|
|
7436
7423
|
"events",
|
|
7437
7424
|
"continuous"
|
|
7438
7425
|
]);
|
|
7439
|
-
/** Which detectors trigger an `events`-mode
|
|
7426
|
+
/** Which detectors trigger an `events`-mode band. */
|
|
7440
7427
|
var RecordingTriggersSchema = object({
|
|
7441
7428
|
motion: boolean().optional(),
|
|
7442
7429
|
audioThresholdDbfs: number().optional()
|
|
@@ -7472,18 +7459,6 @@ var RecordingBandSchema = object({
|
|
|
7472
7459
|
preBufferSec: number().min(0).optional(),
|
|
7473
7460
|
postBufferSec: number().min(0).optional()
|
|
7474
7461
|
});
|
|
7475
|
-
var RecordingRuleSchema = object({
|
|
7476
|
-
schedule: RecordingScheduleSchema,
|
|
7477
|
-
mode: RecordingModeSchema,
|
|
7478
|
-
/** Seconds of footage to retain BEFORE a trigger (applied at keep/discard). */
|
|
7479
|
-
preBufferSec: number().min(0).default(0),
|
|
7480
|
-
/** Keep recording until this many seconds after the last trigger. */
|
|
7481
|
-
postBufferSec: number().min(0).default(0),
|
|
7482
|
-
/** Each new trigger restarts the post-buffer window. */
|
|
7483
|
-
resetTimeoutOnNewEvent: boolean().default(true),
|
|
7484
|
-
/** onAudioThreshold only — dBFS level that counts as a trigger. */
|
|
7485
|
-
thresholdDbfs: number().optional()
|
|
7486
|
-
});
|
|
7487
7462
|
/**
|
|
7488
7463
|
* Per-device retention overrides. Every field is optional; an unset or `0`
|
|
7489
7464
|
* value inherits the node-wide recorder default. Only footage-lifetime limits
|
|
@@ -7517,40 +7492,28 @@ var ScrubThumbnailPresetSchema = _enum([
|
|
|
7517
7492
|
/**
|
|
7518
7493
|
* The full per-camera recording intent — the wire shape of a RecordingTarget.
|
|
7519
7494
|
*
|
|
7520
|
-
* `
|
|
7521
|
-
*
|
|
7522
|
-
*
|
|
7523
|
-
*
|
|
7495
|
+
* `bands` is the ONLY authored recording intent: what to record, when, and on
|
|
7496
|
+
* which trigger. `mode` is a derived summary the recorder stamps on save; every
|
|
7497
|
+
* other field is a storage knob (profiles, segment length, retention, scrub).
|
|
7498
|
+
*
|
|
7499
|
+
* STRICT on purpose: the legacy authoring surface (`schedule`/`schedules`/
|
|
7500
|
+
* `triggers`/`preBufferSec`/`postBufferSec`/`rules`) was retired 2026-07-30.
|
|
7501
|
+
* A stale caller must fail loudly — silently stripping its legacy intent would
|
|
7502
|
+
* persist a band-less config, i.e. silently stop recording the camera.
|
|
7524
7503
|
*/
|
|
7525
7504
|
var RecordingConfigSchema = object({
|
|
7526
7505
|
enabled: boolean(),
|
|
7527
|
-
/**
|
|
7528
|
-
*
|
|
7506
|
+
/** DERIVED summary of `bands`, stamped by the recorder on every save.
|
|
7507
|
+
* Authoring it has no effect — see {@link RecordingStorageModeSchema}. */
|
|
7529
7508
|
mode: RecordingStorageModeSchema.optional(),
|
|
7530
7509
|
profiles: array(CamProfileSchema).optional(),
|
|
7531
7510
|
segmentSeconds: number().int().positive().optional(),
|
|
7532
|
-
/** Shared recording time-bands for `events` & `continuous` — record only when
|
|
7533
|
-
* the wall-clock falls inside one of these windows. Omit or empty = always.
|
|
7534
|
-
* `continuous` compiles to one rule per band; `events` to band × trigger. */
|
|
7535
|
-
schedules: array(RecordingScheduleSchema).optional(),
|
|
7536
|
-
/** Legacy single-band predecessor of `schedules`. Read-compat only — it is
|
|
7537
|
-
* normalized into `schedules` on read and never written going forward. (Not
|
|
7538
|
-
* tagged `@deprecated`: the normalization paths must read it cast-free.) */
|
|
7539
|
-
schedule: RecordingScheduleSchema.optional(),
|
|
7540
|
-
/** `events`-mode only — which detectors trigger a recording. */
|
|
7541
|
-
triggers: RecordingTriggersSchema.optional(),
|
|
7542
|
-
/** `events`-mode only — seconds retained before / after a trigger. */
|
|
7543
|
-
preBufferSec: number().min(0).optional(),
|
|
7544
|
-
postBufferSec: number().min(0).optional(),
|
|
7545
|
-
/** DEPRECATED authoring input; retained for migration/transition. */
|
|
7546
|
-
rules: array(RecordingRuleSchema).optional(),
|
|
7547
7511
|
/**
|
|
7548
|
-
* AUTHORITATIVE mode-per-band recording model
|
|
7549
|
-
*
|
|
7550
|
-
*
|
|
7551
|
-
* derived into bands once via `migrateConfigToBands`.
|
|
7512
|
+
* AUTHORITATIVE mode-per-band recording model — the single source of truth
|
|
7513
|
+
* the recorder's band engine consumes. An empty array = record nothing;
|
|
7514
|
+
* "off" is the absence of a covering band, never a band value.
|
|
7552
7515
|
*/
|
|
7553
|
-
bands: array(RecordingBandSchema).
|
|
7516
|
+
bands: array(RecordingBandSchema).default([]),
|
|
7554
7517
|
retention: RecordingRetentionSchema.optional(),
|
|
7555
7518
|
/**
|
|
7556
7519
|
* Per-camera scrub-thumbnail fidelity preset (resolution + JPEG quality for
|
|
@@ -7558,8 +7521,15 @@ var RecordingConfigSchema = object({
|
|
|
7558
7521
|
* windows only — existing sheets are immutable, and each window's index
|
|
7559
7522
|
* carries its own tile dims so mixed-preset history renders correctly.
|
|
7560
7523
|
*/
|
|
7561
|
-
scrubThumbnails: ScrubThumbnailPresetSchema.optional()
|
|
7562
|
-
|
|
7524
|
+
scrubThumbnails: ScrubThumbnailPresetSchema.optional(),
|
|
7525
|
+
/**
|
|
7526
|
+
* OPT-IN thumbnail-strip generation for this camera: every keyframe of the
|
|
7527
|
+
* low recording saved as a JPEG (the fast-drag scrub depth), a derived
|
|
7528
|
+
* cache that eviction reclaims with the footage. Absent/false = no strips
|
|
7529
|
+
* are written and scrub reads exact keyframes at every velocity.
|
|
7530
|
+
*/
|
|
7531
|
+
stripsEnabled: boolean().optional()
|
|
7532
|
+
}).strict();
|
|
7563
7533
|
/**
|
|
7564
7534
|
* Ops-log — the durable, append-only operations audit shared by the
|
|
7565
7535
|
* recordings and events management surfaces.
|
|
@@ -7578,7 +7548,8 @@ var OpsLogOpSchema = _enum([
|
|
|
7578
7548
|
"prune",
|
|
7579
7549
|
"manual-delete",
|
|
7580
7550
|
"rescan",
|
|
7581
|
-
"retention-run"
|
|
7551
|
+
"retention-run",
|
|
7552
|
+
"relocate"
|
|
7582
7553
|
]);
|
|
7583
7554
|
/** Why the operation ran. */
|
|
7584
7555
|
var OpsLogReasonSchema = _enum([
|
|
@@ -7617,6 +7588,55 @@ var OpsLogQueryInputSchema = object({
|
|
|
7617
7588
|
limit: number().int().min(1).max(1e3).optional()
|
|
7618
7589
|
});
|
|
7619
7590
|
/**
|
|
7591
|
+
* Entity-relocation job state (storage entity-routing spec, Phase 4).
|
|
7592
|
+
*
|
|
7593
|
+
* One shape shared by the recorder's `relocateFootage` (segments + strips) and
|
|
7594
|
+
* pipeline-analytics' `relocateMedia` (event media blobs) so the admin Data
|
|
7595
|
+
* page renders both movers with one component. Jobs are in-RAM (a restart
|
|
7596
|
+
* forgets them — re-running is safe by construction: copy-if-absent, delete
|
|
7597
|
+
* after verify) and each completed/failed run also lands one durable ops-log
|
|
7598
|
+
* row on the owning addon's surface.
|
|
7599
|
+
*/
|
|
7600
|
+
var RelocateJobStateSchema = _enum([
|
|
7601
|
+
"running",
|
|
7602
|
+
"done",
|
|
7603
|
+
"failed",
|
|
7604
|
+
"cancelled"
|
|
7605
|
+
]);
|
|
7606
|
+
var RelocateJobSchema = object({
|
|
7607
|
+
jobId: string(),
|
|
7608
|
+
state: RelocateJobStateSchema,
|
|
7609
|
+
/** Source location — for media relocation this is informational ('*': rows
|
|
7610
|
+
* move from wherever they are to the target). */
|
|
7611
|
+
fromLocationId: string(),
|
|
7612
|
+
toLocationId: string(),
|
|
7613
|
+
/** Scoped device, or null = every device. */
|
|
7614
|
+
deviceId: number().nullable(),
|
|
7615
|
+
/** What the job moves (owner-addon specific: segments/strips or media). */
|
|
7616
|
+
entities: array(string()),
|
|
7617
|
+
filesMoved: number().int(),
|
|
7618
|
+
bytesMoved: number().int(),
|
|
7619
|
+
/** Total files discovered up front; null while (or when) unknown. */
|
|
7620
|
+
filesTotal: number().int().nullable(),
|
|
7621
|
+
startedAt: number(),
|
|
7622
|
+
finishedAt: number().nullable(),
|
|
7623
|
+
error: string().nullable()
|
|
7624
|
+
});
|
|
7625
|
+
var RelocateFootageInputSchema = object({
|
|
7626
|
+
deviceId: number().optional(),
|
|
7627
|
+
fromLocationId: string(),
|
|
7628
|
+
toLocationId: string(),
|
|
7629
|
+
entities: array(_enum(["segments", "strips"])).optional(),
|
|
7630
|
+
/** Copy throttle in MB/s (default 40) — the drain is a background chore,
|
|
7631
|
+
* never allowed to starve live writers. */
|
|
7632
|
+
throttleMbps: number().min(1).max(1e3).optional()
|
|
7633
|
+
});
|
|
7634
|
+
var RelocateMediaInputSchema = object({
|
|
7635
|
+
deviceId: number().optional(),
|
|
7636
|
+
toLocationId: string(),
|
|
7637
|
+
throttleMbps: number().min(1).max(1e3).optional()
|
|
7638
|
+
});
|
|
7639
|
+
/**
|
|
7620
7640
|
* `StorageLocationType` — an addon-declared id that identifies the *kind* of
|
|
7621
7641
|
* storage a location serves. Defined here (not in `capabilities/storage.cap.ts`)
|
|
7622
7642
|
* so the persisted record schema and the consumer-facing cap can both consume it
|
|
@@ -7666,6 +7686,13 @@ var StorageLocationSchema = object({
|
|
|
7666
7686
|
nodeId: string().optional(),
|
|
7667
7687
|
isDefault: boolean().default(false),
|
|
7668
7688
|
isSystem: boolean().default(false),
|
|
7689
|
+
/** COMPUTED at read time by the orchestrator (statfs of the backing volume
|
|
7690
|
+
* for node-local locations it can reach) — never persisted, absent when the
|
|
7691
|
+
* volume is remote/unreachable. The single capacity truth every UI reads. */
|
|
7692
|
+
capacity: object({
|
|
7693
|
+
totalBytes: number(),
|
|
7694
|
+
availableBytes: number()
|
|
7695
|
+
}).nullable().optional(),
|
|
7669
7696
|
createdAt: number(),
|
|
7670
7697
|
updatedAt: number()
|
|
7671
7698
|
});
|
|
@@ -8433,7 +8460,8 @@ var NcTaxonomyEntrySchema = object({
|
|
|
8433
8460
|
/** Macro/category parent for grouping ('car' → 'vehicle'); null for a top. */
|
|
8434
8461
|
parentKind: string().nullable()
|
|
8435
8462
|
});
|
|
8436
|
-
|
|
8463
|
+
/** The complete NC picker taxonomy — three grouped buckets. */
|
|
8464
|
+
var NcTaxonomySchema = object({
|
|
8437
8465
|
videoClasses: array(NcTaxonomyEntrySchema),
|
|
8438
8466
|
audioKinds: array(NcTaxonomyEntrySchema),
|
|
8439
8467
|
labels: array(NcTaxonomyEntrySchema)
|
|
@@ -9375,6 +9403,7 @@ function createRuntimeStateBridge(params) {
|
|
|
9375
9403
|
getStatus
|
|
9376
9404
|
};
|
|
9377
9405
|
}
|
|
9406
|
+
new Set(["devices", "classes"]);
|
|
9378
9407
|
/**
|
|
9379
9408
|
* Shared geometry vocabulary for on-frame shape caps — privacy-mask,
|
|
9380
9409
|
* motion-zones, and the detection zones/lines editor all speak this one
|
|
@@ -9691,12 +9720,60 @@ var NcRuleTargetSchema = object({
|
|
|
9691
9720
|
* - `keyFrame` — the clean scene frame (no subject box).
|
|
9692
9721
|
* - `none` — no attachment.
|
|
9693
9722
|
*/
|
|
9694
|
-
|
|
9695
|
-
|
|
9696
|
-
|
|
9697
|
-
|
|
9698
|
-
|
|
9699
|
-
|
|
9723
|
+
/**
|
|
9724
|
+
* WHAT THE PICTURE SHOWS — chosen explicitly, because the implicit ladders
|
|
9725
|
+
* conflate it with the selection strategy and betray the request: asking for
|
|
9726
|
+
* the clean scene frame on an object-event owner used to start at
|
|
9727
|
+
* `fullFrameBoxed`, i.e. the annotated frame (2026-07-30).
|
|
9728
|
+
* - `cropped` — the subject, tight. What "who is at the door" wants.
|
|
9729
|
+
* - `full` — the clean scene, no annotation. What "what is going on" wants.
|
|
9730
|
+
* - `boxed` — the scene WITH the detection boxes drawn, for verifying what
|
|
9731
|
+
* the pipeline actually saw.
|
|
9732
|
+
*/
|
|
9733
|
+
var NcMediaFrameSchema = _enum([
|
|
9734
|
+
"cropped",
|
|
9735
|
+
"full",
|
|
9736
|
+
"boxed"
|
|
9737
|
+
]);
|
|
9738
|
+
var NcMediaPolicySchema = object({
|
|
9739
|
+
attach: _enum([
|
|
9740
|
+
"best",
|
|
9741
|
+
"best-matching",
|
|
9742
|
+
"keyFrame",
|
|
9743
|
+
"none"
|
|
9744
|
+
]).default("best"),
|
|
9745
|
+
/** What the still shows. Absent = `cropped` (the historical `best` shape). */
|
|
9746
|
+
frame: NcMediaFrameSchema.optional(),
|
|
9747
|
+
/** Crop the attached still to the rule's condition-zone bbox (padded) —
|
|
9748
|
+
* "show me the ZONE", not the whole scene or the subject crop. */
|
|
9749
|
+
zoneCrop: boolean().optional(),
|
|
9750
|
+
/**
|
|
9751
|
+
* Also attach a short GIF cut from the stream broker's clip ring around the
|
|
9752
|
+
* event — NOT from the recording, so the camera does not have to be
|
|
9753
|
+
* recording, and the window sits AROUND the moment instead of a segment
|
|
9754
|
+
* behind it. Fail-closed: a window the ring does not cover contributes no
|
|
9755
|
+
* gif, never a failed notification.
|
|
9756
|
+
*/
|
|
9757
|
+
gif: boolean().optional(),
|
|
9758
|
+
/**
|
|
9759
|
+
* Also attach a short MP4 CLIP of the same cut. Same source and the same
|
|
9760
|
+
* fail-closed rule as `gif`. Prefer it where the backend takes video
|
|
9761
|
+
* (telegram, discord, zentik, webhook); backends that do not are handled by
|
|
9762
|
+
* the degrade engine, which drops the video and keeps the still.
|
|
9763
|
+
*/
|
|
9764
|
+
clip: boolean().optional(),
|
|
9765
|
+
/** Seconds of footage BEFORE / AFTER the event instant. Defaults 3 / 7. */
|
|
9766
|
+
clipPreRollSec: number().int().min(0).max(30).optional(),
|
|
9767
|
+
clipPostRollSec: number().int().min(0).max(30).optional(),
|
|
9768
|
+
/**
|
|
9769
|
+
* Which stream profile the footage is cut from. Absent = the CHEAPEST
|
|
9770
|
+
* assigned profile: a notification is watched on a phone, so the 4K
|
|
9771
|
+
* rendition would burn CPU to produce a file the client downscales anyway.
|
|
9772
|
+
* A profile that is not assigned falls back to the cheapest, and the render
|
|
9773
|
+
* reports which one actually ran.
|
|
9774
|
+
*/
|
|
9775
|
+
profile: CamProfileSchema.optional()
|
|
9776
|
+
});
|
|
9700
9777
|
/** Throttle — cooldown survives restarts (rebuilt from the outbox on boot). */
|
|
9701
9778
|
var NcThrottleSchema = object({
|
|
9702
9779
|
cooldownSec: number().int().min(0).max(86400).default(60),
|
|
@@ -9710,7 +9787,19 @@ var NcRuleInputSchema = object({
|
|
|
9710
9787
|
delivery: NcDeliverySchema,
|
|
9711
9788
|
conditions: NcConditionsSchema.default({}),
|
|
9712
9789
|
schedule: NcScheduleSchema.optional(),
|
|
9713
|
-
|
|
9790
|
+
/** May be empty when `targetUsers` addresses at least one user — the
|
|
9791
|
+
* "at least one addressee" invariant is enforced by the provider, because
|
|
9792
|
+
* a cross-field refine here would break `NcRulePatchSchema.partial()`. */
|
|
9793
|
+
targets: array(NcRuleTargetSchema),
|
|
9794
|
+
/**
|
|
9795
|
+
* USERS this rule addresses in addition to `targets` (Phase 4). At fire
|
|
9796
|
+
* time each user fans out to the personal targets they own
|
|
9797
|
+
* (`config.ownerUserId`), filtered by that user's `allowedDevices` for the
|
|
9798
|
+
* firing camera — a user is never notified about a device they cannot open.
|
|
9799
|
+
* Per-user opt-outs (`disabledTargetIds`) still apply to the fanned-out
|
|
9800
|
+
* targets.
|
|
9801
|
+
*/
|
|
9802
|
+
targetUsers: array(string()).optional(),
|
|
9714
9803
|
media: NcMediaPolicySchema.default({ attach: "best" }),
|
|
9715
9804
|
throttle: NcThrottleSchema.default({
|
|
9716
9805
|
cooldownSec: 60,
|
|
@@ -9923,7 +10012,10 @@ method(object({}), object({ rules: array(NcRuleSchema) }), { auth: "admin" }), m
|
|
|
9923
10012
|
}), object({ results: array(NcTestResultSchema) }), {
|
|
9924
10013
|
kind: "mutation",
|
|
9925
10014
|
auth: "admin"
|
|
9926
|
-
}), method(object({}), object({
|
|
10015
|
+
}), method(object({}), object({
|
|
10016
|
+
catalog: array(NcConditionDescriptorSchema),
|
|
10017
|
+
taxonomy: NcTaxonomySchema.optional()
|
|
10018
|
+
})), method(object({ filter: NcHistoryFilterSchema.default({ limit: 100 }) }), object({ entries: array(NcHistoryEntrySchema) }), { auth: "admin" });
|
|
9927
10019
|
/**
|
|
9928
10020
|
* TimelapseRule — the STANDALONE scheduled timelapse producer's rule model.
|
|
9929
10021
|
*
|
|
@@ -10932,6 +11024,28 @@ method(object({
|
|
|
10932
11024
|
}), object({ success: literal(true) }), {
|
|
10933
11025
|
kind: "mutation",
|
|
10934
11026
|
auth: "admin"
|
|
11027
|
+
}), method(object({
|
|
11028
|
+
deviceId: number(),
|
|
11029
|
+
/** Absent = the LOWEST assigned profile — a notification attachment is
|
|
11030
|
+
* watched on a phone, and the cheap rendition is the right default. */
|
|
11031
|
+
profile: CamProfileSchema.optional(),
|
|
11032
|
+
aroundMs: number(),
|
|
11033
|
+
preRollSec: number().min(0).max(20).default(3),
|
|
11034
|
+
postRollSec: number().min(0).max(20).default(5),
|
|
11035
|
+
format: _enum(["gif", "mp4"]).default("gif"),
|
|
11036
|
+
maxWidth: number().int().min(120).max(1920).default(480),
|
|
11037
|
+
/** GIF only — MP4 keeps the source cadence. */
|
|
11038
|
+
fps: number().int().min(1).max(15).default(5)
|
|
11039
|
+
}), object({
|
|
11040
|
+
base64: string(),
|
|
11041
|
+
mime: string(),
|
|
11042
|
+
bytes: number().int(),
|
|
11043
|
+
/** The profile actually rendered (what the default resolved to). */
|
|
11044
|
+
profile: CamProfileSchema,
|
|
11045
|
+
durationMs: number()
|
|
11046
|
+
}), {
|
|
11047
|
+
kind: "mutation",
|
|
11048
|
+
auth: "admin"
|
|
10935
11049
|
}), method(_void(), array(CameraStreamSchema).readonly()), method(_void(), array(ProfileSlotSchema).readonly()), method(object({ brokerId: string() }), BrokerStatsSchema), method(object({ brokerId: string() }), object({
|
|
10936
11050
|
probed: boolean(),
|
|
10937
11051
|
summary: string()
|
|
@@ -19937,6 +20051,36 @@ var TargetKindSchema = object({
|
|
|
19937
20051
|
icon: string(),
|
|
19938
20052
|
/** Stamped by each provider so the concat-fanned catalog stays routable. */
|
|
19939
20053
|
addonId: string(),
|
|
20054
|
+
/**
|
|
20055
|
+
* URL of the kind's bundled BRAND icon, served by the providing addon over
|
|
20056
|
+
* its own `addon-routes` surface (`/addon/<addonId>/icons/<kind>`). Absent
|
|
20057
|
+
* when the addon bundles no icon for that kind — the client then falls back
|
|
20058
|
+
* to a neutral glyph rather than rendering the raw `icon` NAME as text.
|
|
20059
|
+
*
|
|
20060
|
+
* Root-relative on purpose: it resolves against whatever origin serves a web
|
|
20061
|
+
* client, and a native client joins it onto its own hub base.
|
|
20062
|
+
*
|
|
20063
|
+
* DECLARED here deliberately. It used to travel as an undeclared passthrough
|
|
20064
|
+
* field that survived only because the runtime cap-router forwards provider
|
|
20065
|
+
* output verbatim — so every consumer had to re-declare it by hand to stop
|
|
20066
|
+
* its own Zod parse from stripping it, and the whole arrangement would have
|
|
20067
|
+
* broken silently the moment output validation was tightened anywhere.
|
|
20068
|
+
*/
|
|
20069
|
+
iconUrl: string().optional(),
|
|
20070
|
+
/**
|
|
20071
|
+
* Media type of {@link iconUrl} (`image/svg+xml`, `image/png`, …).
|
|
20072
|
+
*
|
|
20073
|
+
* The server knows this and therefore says it, because the client cannot
|
|
20074
|
+
* safely guess: a React-Native client renders SVG and raster through two
|
|
20075
|
+
* DIFFERENT components (`react-native-svg` vs `expo-image` — expo-image does
|
|
20076
|
+
* not decode SVG on iOS/Android), so without this it silently fell back to a
|
|
20077
|
+
* placeholder glyph for every vector icon while the web build looked fine.
|
|
20078
|
+
*
|
|
20079
|
+
* Absent when {@link iconUrl} is absent, or for a legacy provider that has
|
|
20080
|
+
* not been updated — a client that cannot determine the type should prefer
|
|
20081
|
+
* its raster path, which is the safe default for an unknown image.
|
|
20082
|
+
*/
|
|
20083
|
+
iconMediaType: string().optional(),
|
|
19940
20084
|
configSchema: ConfigSchemaPassthrough,
|
|
19941
20085
|
supportsDiscovery: boolean(),
|
|
19942
20086
|
caps: TargetKindCapsSchema
|
|
@@ -20668,6 +20812,15 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
20668
20812
|
}), method(object({ deviceId: number() }), EventPruneCountsSchema, {
|
|
20669
20813
|
kind: "mutation",
|
|
20670
20814
|
auth: "admin"
|
|
20815
|
+
}), method(RelocateMediaInputSchema, object({ jobId: string() }), {
|
|
20816
|
+
kind: "mutation",
|
|
20817
|
+
auth: "admin"
|
|
20818
|
+
}), method(object({}), array(RelocateJobSchema).readonly(), {
|
|
20819
|
+
kind: "query",
|
|
20820
|
+
auth: "admin"
|
|
20821
|
+
}), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
20822
|
+
kind: "mutation",
|
|
20823
|
+
auth: "admin"
|
|
20671
20824
|
}), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
|
|
20672
20825
|
kind: "query",
|
|
20673
20826
|
auth: "admin"
|
|
@@ -23249,6 +23402,17 @@ var GetConnectionEndpointsResultSchema = object({ endpoints: array(object({
|
|
|
23249
23402
|
*/
|
|
23250
23403
|
priority: number()
|
|
23251
23404
|
})).readonly() });
|
|
23405
|
+
/**
|
|
23406
|
+
* The chosen outbound endpoint for notification artifacts. `baseUrl: null` =
|
|
23407
|
+
* AUTO (resolved from the candidate ranking at send time); `resolved` reports
|
|
23408
|
+
* what AUTO currently picks, so the UI can show the effective value either way.
|
|
23409
|
+
*/
|
|
23410
|
+
var NotificationEndpointSchema = object({
|
|
23411
|
+
/** The operator's explicit choice, or null for AUTO. */
|
|
23412
|
+
baseUrl: string().nullable(),
|
|
23413
|
+
/** What the ranking currently resolves to (null when nothing is reachable). */
|
|
23414
|
+
resolved: string().nullable()
|
|
23415
|
+
});
|
|
23252
23416
|
var AllowedAddressesSchema = object({
|
|
23253
23417
|
/**
|
|
23254
23418
|
* Allowlist of interface addresses operators have explicitly opted
|
|
@@ -23271,7 +23435,7 @@ method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(obje
|
|
|
23271
23435
|
* to avoid mixed-content blocks in the browser. The public
|
|
23272
23436
|
* tunnel always emits `https://` regardless. */
|
|
23273
23437
|
scheme: _enum(["http", "https"]).optional()
|
|
23274
|
-
}), GetConnectionEndpointsResultSchema), method(_void(), AllowedAddressesSchema), method(AllowedAddressesSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), AllowedAddressesSchema, { kind: "mutation" });
|
|
23438
|
+
}), GetConnectionEndpointsResultSchema), method(_void(), NotificationEndpointSchema), method(object({ baseUrl: string().nullable() }), NotificationEndpointSchema, { kind: "mutation" }), method(_void(), AllowedAddressesSchema), method(AllowedAddressesSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), AllowedAddressesSchema, { kind: "mutation" });
|
|
23275
23439
|
/**
|
|
23276
23440
|
* mesh-network — collection cap for mesh-VPN providers.
|
|
23277
23441
|
*
|
|
@@ -24137,7 +24301,12 @@ var RecordingDeviceUsageSchema = object({
|
|
|
24137
24301
|
var RecordingLocationUsageSchema = object({
|
|
24138
24302
|
/** StorageLocation id; null for the legacy/degraded single-root fallback. */
|
|
24139
24303
|
locationId: string().nullable(),
|
|
24140
|
-
/**
|
|
24304
|
+
/** Every location id sharing this row's PHYSICAL volume (aliases). One row
|
|
24305
|
+
* is emitted per physical disk (2026-07-29): two locations on one root
|
|
24306
|
+
* previously rendered as two identical "disks" with a nonsensical used
|
|
24307
|
+
* split — hydrate attribution across aliases is arbitrary by nature. */
|
|
24308
|
+
locationIds: array(string()).optional(),
|
|
24309
|
+
/** Bytes of recordings stored on this PHYSICAL volume (all aliases). */
|
|
24141
24310
|
usedBytes: number(),
|
|
24142
24311
|
/** Free bytes on the location's volume; null when capacity is unknown (remote). */
|
|
24143
24312
|
availableBytes: number().nullable(),
|
|
@@ -24249,6 +24418,44 @@ method(object({
|
|
|
24249
24418
|
}), method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
|
|
24250
24419
|
kind: "query",
|
|
24251
24420
|
auth: "admin"
|
|
24421
|
+
}), method(object({
|
|
24422
|
+
deviceId: number(),
|
|
24423
|
+
aroundMs: number(),
|
|
24424
|
+
preRollSec: number().min(0).max(30).default(2),
|
|
24425
|
+
postRollSec: number().min(0).max(30).default(5),
|
|
24426
|
+
maxWidth: number().int().min(120).max(1280).default(480),
|
|
24427
|
+
fps: number().int().min(1).max(15).default(5)
|
|
24428
|
+
}), object({
|
|
24429
|
+
gifBase64: string(),
|
|
24430
|
+
fromMs: number(),
|
|
24431
|
+
toMs: number()
|
|
24432
|
+
}), {
|
|
24433
|
+
kind: "mutation",
|
|
24434
|
+
auth: "admin"
|
|
24435
|
+
}), method(object({
|
|
24436
|
+
deviceId: number(),
|
|
24437
|
+
aroundMs: number(),
|
|
24438
|
+
preRollSec: number().min(0).max(30).default(3),
|
|
24439
|
+
postRollSec: number().min(0).max(30).default(7),
|
|
24440
|
+
maxWidth: number().int().min(160).max(1920).default(640)
|
|
24441
|
+
}), object({
|
|
24442
|
+
clipBase64: string(),
|
|
24443
|
+
mime: string(),
|
|
24444
|
+
fromMs: number(),
|
|
24445
|
+
toMs: number(),
|
|
24446
|
+
bytes: number().int()
|
|
24447
|
+
}), {
|
|
24448
|
+
kind: "mutation",
|
|
24449
|
+
auth: "admin"
|
|
24450
|
+
}), method(RelocateFootageInputSchema, object({ jobId: string() }), {
|
|
24451
|
+
kind: "mutation",
|
|
24452
|
+
auth: "admin"
|
|
24453
|
+
}), method(object({}), array(RelocateJobSchema).readonly(), {
|
|
24454
|
+
kind: "query",
|
|
24455
|
+
auth: "admin"
|
|
24456
|
+
}), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
24457
|
+
kind: "mutation",
|
|
24458
|
+
auth: "admin"
|
|
24252
24459
|
});
|
|
24253
24460
|
/**
|
|
24254
24461
|
* `recordingExport` cap — render a footage time range into a single downloadable
|
|
@@ -26945,6 +27152,12 @@ Object.freeze({
|
|
|
26945
27152
|
addonId: null,
|
|
26946
27153
|
access: "view"
|
|
26947
27154
|
},
|
|
27155
|
+
"localNetwork.getNotificationEndpoint": {
|
|
27156
|
+
capName: "local-network",
|
|
27157
|
+
capScope: "system",
|
|
27158
|
+
addonId: null,
|
|
27159
|
+
access: "view"
|
|
27160
|
+
},
|
|
26948
27161
|
"localNetwork.getPreferred": {
|
|
26949
27162
|
capName: "local-network",
|
|
26950
27163
|
capScope: "system",
|
|
@@ -26969,6 +27182,12 @@ Object.freeze({
|
|
|
26969
27182
|
addonId: null,
|
|
26970
27183
|
access: "create"
|
|
26971
27184
|
},
|
|
27185
|
+
"localNetwork.setNotificationEndpoint": {
|
|
27186
|
+
capName: "local-network",
|
|
27187
|
+
capScope: "system",
|
|
27188
|
+
addonId: null,
|
|
27189
|
+
access: "create"
|
|
27190
|
+
},
|
|
26972
27191
|
"lockControl.lock": {
|
|
26973
27192
|
capName: "lock-control",
|
|
26974
27193
|
capScope: "device",
|
|
@@ -27611,6 +27830,12 @@ Object.freeze({
|
|
|
27611
27830
|
addonId: null,
|
|
27612
27831
|
access: "create"
|
|
27613
27832
|
},
|
|
27833
|
+
"pipelineAnalytics.cancelMediaRelocate": {
|
|
27834
|
+
capName: "pipeline-analytics",
|
|
27835
|
+
capScope: "device",
|
|
27836
|
+
addonId: null,
|
|
27837
|
+
access: "create"
|
|
27838
|
+
},
|
|
27614
27839
|
"pipelineAnalytics.clearTracks": {
|
|
27615
27840
|
capName: "pipeline-analytics",
|
|
27616
27841
|
capScope: "device",
|
|
@@ -27665,6 +27890,12 @@ Object.freeze({
|
|
|
27665
27890
|
addonId: null,
|
|
27666
27891
|
access: "view"
|
|
27667
27892
|
},
|
|
27893
|
+
"pipelineAnalytics.getMediaRelocateStatus": {
|
|
27894
|
+
capName: "pipeline-analytics",
|
|
27895
|
+
capScope: "device",
|
|
27896
|
+
addonId: null,
|
|
27897
|
+
access: "view"
|
|
27898
|
+
},
|
|
27668
27899
|
"pipelineAnalytics.getMotionEvents": {
|
|
27669
27900
|
capName: "pipeline-analytics",
|
|
27670
27901
|
capScope: "device",
|
|
@@ -27737,6 +27968,12 @@ Object.freeze({
|
|
|
27737
27968
|
addonId: null,
|
|
27738
27969
|
access: "create"
|
|
27739
27970
|
},
|
|
27971
|
+
"pipelineAnalytics.relocateMedia": {
|
|
27972
|
+
capName: "pipeline-analytics",
|
|
27973
|
+
capScope: "device",
|
|
27974
|
+
addonId: null,
|
|
27975
|
+
access: "create"
|
|
27976
|
+
},
|
|
27740
27977
|
"pipelineAnalytics.searchObjectEvents": {
|
|
27741
27978
|
capName: "pipeline-analytics",
|
|
27742
27979
|
capScope: "device",
|
|
@@ -28499,6 +28736,12 @@ Object.freeze({
|
|
|
28499
28736
|
addonId: null,
|
|
28500
28737
|
access: "create"
|
|
28501
28738
|
},
|
|
28739
|
+
"recording.cancelRelocate": {
|
|
28740
|
+
capName: "recording",
|
|
28741
|
+
capScope: "system",
|
|
28742
|
+
addonId: null,
|
|
28743
|
+
access: "create"
|
|
28744
|
+
},
|
|
28502
28745
|
"recording.deleteFootprint": {
|
|
28503
28746
|
capName: "recording",
|
|
28504
28747
|
capScope: "system",
|
|
@@ -28529,6 +28772,12 @@ Object.freeze({
|
|
|
28529
28772
|
addonId: null,
|
|
28530
28773
|
access: "view"
|
|
28531
28774
|
},
|
|
28775
|
+
"recording.getRelocateStatus": {
|
|
28776
|
+
capName: "recording",
|
|
28777
|
+
capScope: "system",
|
|
28778
|
+
addonId: null,
|
|
28779
|
+
access: "view"
|
|
28780
|
+
},
|
|
28532
28781
|
"recording.getStorageUsage": {
|
|
28533
28782
|
capName: "recording",
|
|
28534
28783
|
capScope: "system",
|
|
@@ -28559,6 +28808,24 @@ Object.freeze({
|
|
|
28559
28808
|
addonId: null,
|
|
28560
28809
|
access: "view"
|
|
28561
28810
|
},
|
|
28811
|
+
"recording.relocateFootage": {
|
|
28812
|
+
capName: "recording",
|
|
28813
|
+
capScope: "system",
|
|
28814
|
+
addonId: null,
|
|
28815
|
+
access: "create"
|
|
28816
|
+
},
|
|
28817
|
+
"recording.renderClip": {
|
|
28818
|
+
capName: "recording",
|
|
28819
|
+
capScope: "system",
|
|
28820
|
+
addonId: null,
|
|
28821
|
+
access: "create"
|
|
28822
|
+
},
|
|
28823
|
+
"recording.renderGif": {
|
|
28824
|
+
capName: "recording",
|
|
28825
|
+
capScope: "system",
|
|
28826
|
+
addonId: null,
|
|
28827
|
+
access: "create"
|
|
28828
|
+
},
|
|
28562
28829
|
"recording.rescanStorage": {
|
|
28563
28830
|
capName: "recording",
|
|
28564
28831
|
capScope: "system",
|
|
@@ -29153,6 +29420,12 @@ Object.freeze({
|
|
|
29153
29420
|
addonId: null,
|
|
29154
29421
|
access: "create"
|
|
29155
29422
|
},
|
|
29423
|
+
"streamBroker.renderPreBufferClip": {
|
|
29424
|
+
capName: "stream-broker",
|
|
29425
|
+
capScope: "system",
|
|
29426
|
+
addonId: null,
|
|
29427
|
+
access: "create"
|
|
29428
|
+
},
|
|
29156
29429
|
"streamBroker.restartProfile": {
|
|
29157
29430
|
capName: "stream-broker",
|
|
29158
29431
|
capScope: "system",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-provider-reolink",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.14",
|
|
4
4
|
"description": "Reolink camera device provider addon for CamStack — native Baichuan protocol",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|
|
@@ -63,7 +63,8 @@
|
|
|
63
63
|
}
|
|
64
64
|
],
|
|
65
65
|
"runtimeDependencies": [
|
|
66
|
-
"@apocaliss92/nodelink-js"
|
|
66
|
+
"@apocaliss92/nodelink-js",
|
|
67
|
+
"werift"
|
|
67
68
|
]
|
|
68
69
|
},
|
|
69
70
|
"files": [
|