@camstack/addon-provider-unifi 0.1.11 → 0.1.12
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 +202 -7
- package/dist/addon.mjs +202 -7
- package/package.json +1 -1
package/dist/addon.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
//#region ../types/dist/event-category-
|
|
2
|
+
//#region ../types/dist/event-category-D4HJq7Mw.mjs
|
|
3
3
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
4
4
|
EventCategory["SystemBoot"] = "system.boot";
|
|
5
5
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -152,6 +152,11 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
152
152
|
/** Runner-sampled scrub thumbnail (~1/5 s/camera). Telemetry (D8): a lost
|
|
153
153
|
* thumb is a scrub gap the recorder's keyframe backfill covers. */
|
|
154
154
|
EventCategory["RecordingThumbSampled"] = "recording.thumb-sampled";
|
|
155
|
+
/** Export render progress (0–100). Telemetry (D8): a lost tick is a stale
|
|
156
|
+
* progress bar the client reconciles via `recordingExport.getExport`. */
|
|
157
|
+
EventCategory["RecordingExportProgress"] = "recording.export.progress";
|
|
158
|
+
EventCategory["RecordingExportCompleted"] = "recording.export.completed";
|
|
159
|
+
EventCategory["RecordingExportFailed"] = "recording.export.failed";
|
|
155
160
|
EventCategory["DetectionEvent"] = "detection.event";
|
|
156
161
|
EventCategory["SessionTrackNew"] = "session.track.new";
|
|
157
162
|
EventCategory["SessionTrackExpired"] = "session.track.expired";
|
|
@@ -441,6 +446,25 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
441
446
|
*/
|
|
442
447
|
EventCategory["PipelineAnalyticsStationaryChanged"] = "pipeline-analytics.stationary-changed";
|
|
443
448
|
/**
|
|
449
|
+
* Fired by `addon-post-analysis` when a package-drop is confirmed inside
|
|
450
|
+
* a package zone — a newly-appeared stationary object of a package class
|
|
451
|
+
* that cleared the class / zone / dwell / size gates. Payload:
|
|
452
|
+
* `PipelineAnalyticsPackageDeliveredPayload` carrying `{ deviceId,
|
|
453
|
+
* entryId, className, zoneIds, keyFrameMediaKey?, bbox, timestamp }`.
|
|
454
|
+
* Telemetry (D8): the durable record is the `package-events` store row;
|
|
455
|
+
* this bus topic drives notifier rules + live UI. See
|
|
456
|
+
* docs/superpowers/specs/2026-07-17-package-zones-design.md §5.1.
|
|
457
|
+
*/
|
|
458
|
+
EventCategory["PipelineAnalyticsPackageDelivered"] = "pipeline-analytics.package-delivered";
|
|
459
|
+
/**
|
|
460
|
+
* Fired by `addon-post-analysis` when a previously-delivered package
|
|
461
|
+
* leaves its zone (the stationary entry departed — moved or swept).
|
|
462
|
+
* Payload: `PipelineAnalyticsPackagePickedUpPayload` carrying
|
|
463
|
+
* `{ deviceId, entryId, deliveredEventId, className, timestamp }`.
|
|
464
|
+
* Telemetry (D8). See package-zones-design §5.2.
|
|
465
|
+
*/
|
|
466
|
+
EventCategory["PipelineAnalyticsPackagePickedUp"] = "pipeline-analytics.package-picked-up";
|
|
467
|
+
/**
|
|
444
468
|
* Fired by `addon-post-analysis` whenever a gallery face row changes:
|
|
445
469
|
* `kind:'buffered'` a new detected face was persisted, `'assigned'` /
|
|
446
470
|
* `'unassigned'` its identity link changed, `'deleted'` the row was
|
|
@@ -5193,6 +5217,25 @@ function preprocess(fn, schema) {
|
|
|
5193
5217
|
out: schema
|
|
5194
5218
|
});
|
|
5195
5219
|
}
|
|
5220
|
+
//#endregion
|
|
5221
|
+
//#region ../../node_modules/zod/v4/classic/compat.js
|
|
5222
|
+
/** @deprecated Use the raw string literal codes instead, e.g. "invalid_type". */
|
|
5223
|
+
var ZodIssueCode = {
|
|
5224
|
+
invalid_type: "invalid_type",
|
|
5225
|
+
too_big: "too_big",
|
|
5226
|
+
too_small: "too_small",
|
|
5227
|
+
invalid_format: "invalid_format",
|
|
5228
|
+
not_multiple_of: "not_multiple_of",
|
|
5229
|
+
unrecognized_keys: "unrecognized_keys",
|
|
5230
|
+
invalid_union: "invalid_union",
|
|
5231
|
+
invalid_key: "invalid_key",
|
|
5232
|
+
invalid_element: "invalid_element",
|
|
5233
|
+
invalid_value: "invalid_value",
|
|
5234
|
+
custom: "custom"
|
|
5235
|
+
};
|
|
5236
|
+
/** @deprecated Do not use. Stub definition, only included for zod-to-json-schema compatibility. */
|
|
5237
|
+
var ZodFirstPartyTypeKind;
|
|
5238
|
+
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5196
5239
|
Object.fromEntries([
|
|
5197
5240
|
{
|
|
5198
5241
|
id: "overview",
|
|
@@ -14670,7 +14713,11 @@ array(ZoneRuleSchema).readonly();
|
|
|
14670
14713
|
* Extend the enum here when a new gating consumer comes online (audio
|
|
14671
14714
|
* gating, alert filtering, …) — no other surface needs to change.
|
|
14672
14715
|
*/
|
|
14673
|
-
var ZoneRuleStageEnum = _enum([
|
|
14716
|
+
var ZoneRuleStageEnum = _enum([
|
|
14717
|
+
"motion",
|
|
14718
|
+
"detection",
|
|
14719
|
+
"package"
|
|
14720
|
+
]);
|
|
14674
14721
|
/**
|
|
14675
14722
|
* Runtime registry: cap-property-name → cap definition. `BaseDevice`'s
|
|
14676
14723
|
* `state` getter looks up the cap definition here to construct a
|
|
@@ -14764,16 +14811,24 @@ var DEVICE_LOCAL_STATE_CAPS = {
|
|
|
14764
14811
|
})
|
|
14765
14812
|
},
|
|
14766
14813
|
/**
|
|
14767
|
-
* Runtime-state slice —
|
|
14814
|
+
* Runtime-state slice — every stage mirrored together so consumers
|
|
14768
14815
|
* see one reactive handle (`device.state.zoneRules.value`) instead
|
|
14769
|
-
* of
|
|
14770
|
-
* `{motion, detection}` shape, so subscribers always get the
|
|
14816
|
+
* of one per stage. Bulk-replace mutations on any stage write the full
|
|
14817
|
+
* `{motion, detection, package}` shape, so subscribers always get the
|
|
14771
14818
|
* complete current set. Consumers that only care about one stage
|
|
14772
14819
|
* just read the matching property.
|
|
14820
|
+
*
|
|
14821
|
+
* `package` backs the package-drop detector — a package zone is a
|
|
14822
|
+
* `ZoneRule` on the `'package'` stage referencing drawn polygons
|
|
14823
|
+
* (see docs/superpowers/specs/2026-07-17-package-zones-design.md §3.1).
|
|
14824
|
+
* The orchestrator provider that writes this stage lands in a later
|
|
14825
|
+
* slice; until then the mirror carries only `{motion, detection}` and
|
|
14826
|
+
* consumers read `package` as absent (treat as `[]`).
|
|
14773
14827
|
*/
|
|
14774
14828
|
runtimeState: object({
|
|
14775
14829
|
motion: array(ZoneRuleSchema).readonly(),
|
|
14776
|
-
detection: array(ZoneRuleSchema).readonly()
|
|
14830
|
+
detection: array(ZoneRuleSchema).readonly(),
|
|
14831
|
+
package: array(ZoneRuleSchema).readonly()
|
|
14777
14832
|
})
|
|
14778
14833
|
},
|
|
14779
14834
|
zones: zonesCapability
|
|
@@ -18735,6 +18790,7 @@ var EventKindIconSchema = _enum([
|
|
|
18735
18790
|
"smoke",
|
|
18736
18791
|
"water",
|
|
18737
18792
|
"button",
|
|
18793
|
+
"package",
|
|
18738
18794
|
"generic"
|
|
18739
18795
|
]);
|
|
18740
18796
|
var EventKindCategorySchema = _enum([
|
|
@@ -18742,7 +18798,8 @@ var EventKindCategorySchema = _enum([
|
|
|
18742
18798
|
"audio",
|
|
18743
18799
|
"detection",
|
|
18744
18800
|
"sensor",
|
|
18745
|
-
"custom"
|
|
18801
|
+
"custom",
|
|
18802
|
+
"package"
|
|
18746
18803
|
]);
|
|
18747
18804
|
var EventKindDescriptorSchema = object({
|
|
18748
18805
|
/** Stable kind id (e.g. 'motion', 'person', 'contact'). */
|
|
@@ -22405,6 +22462,108 @@ method(object({
|
|
|
22405
22462
|
auth: "admin"
|
|
22406
22463
|
});
|
|
22407
22464
|
/**
|
|
22465
|
+
* `recordingExport` cap — render a footage time range into a single downloadable
|
|
22466
|
+
* MP4 (regular / accelerated / decelerated / timelapse, ± audio), kept for a
|
|
22467
|
+
* bounded lifetime with a durable history, auto-expiry, and optional
|
|
22468
|
+
* delete-after-download.
|
|
22469
|
+
*
|
|
22470
|
+
* Like `recording` this is a `scope:'system', mode:'singleton'` cap: the
|
|
22471
|
+
* recorder self-gates so exactly ONE node (the designated `recordingNodeId`,
|
|
22472
|
+
* default `hub`) registers it. Device-scoped methods carry `deviceId` in their
|
|
22473
|
+
* input and dispatch to that single provider; the render runs on the node that
|
|
22474
|
+
* owns the footage (no cross-node segment transfer). Download rides the
|
|
22475
|
+
* framework addon data-plane. State persists in a DurableState blob (NOT
|
|
22476
|
+
* SQLite); history rows survive file deletion for audit.
|
|
22477
|
+
*/
|
|
22478
|
+
/** Playback-speed multiplier for the render (1 = realtime). */
|
|
22479
|
+
var ExportSpeedSchema = number().min(.25).max(32);
|
|
22480
|
+
/** Timelapse cadence — sample one source frame per `everyMs`, output at `outputFps`. */
|
|
22481
|
+
var ExportTimelapseSchema = object({
|
|
22482
|
+
everyMs: number().int().positive(),
|
|
22483
|
+
outputFps: number().int().min(1).max(60).optional()
|
|
22484
|
+
});
|
|
22485
|
+
/**
|
|
22486
|
+
* Render options. `speed` and `timelapse` are mutually exclusive. `includeAudio`
|
|
22487
|
+
* is honoured only for a realtime-ish speed (0.5–2×); timelapse is always
|
|
22488
|
+
* silent. `maxLifeMs` bounds how long the finished file is kept;
|
|
22489
|
+
* `deleteAfterDownload` removes it shortly after the first complete download.
|
|
22490
|
+
*/
|
|
22491
|
+
var ExportOptionsSchema = object({
|
|
22492
|
+
speed: ExportSpeedSchema.optional(),
|
|
22493
|
+
timelapse: ExportTimelapseSchema.optional(),
|
|
22494
|
+
includeAudio: boolean(),
|
|
22495
|
+
maxLifeMs: number().int().positive(),
|
|
22496
|
+
deleteAfterDownload: boolean(),
|
|
22497
|
+
title: string().max(200).optional()
|
|
22498
|
+
}).superRefine((v, ctx) => {
|
|
22499
|
+
if (v.speed !== void 0 && v.timelapse !== void 0) ctx.addIssue({
|
|
22500
|
+
code: ZodIssueCode.custom,
|
|
22501
|
+
message: "speed and timelapse are mutually exclusive",
|
|
22502
|
+
path: ["timelapse"]
|
|
22503
|
+
});
|
|
22504
|
+
});
|
|
22505
|
+
var ExportStateSchema = _enum([
|
|
22506
|
+
"queued",
|
|
22507
|
+
"rendering",
|
|
22508
|
+
"ready",
|
|
22509
|
+
"failed",
|
|
22510
|
+
"expired",
|
|
22511
|
+
"deleted"
|
|
22512
|
+
]);
|
|
22513
|
+
/** One export job / history row. */
|
|
22514
|
+
var ExportRecordSchema = object({
|
|
22515
|
+
id: string(),
|
|
22516
|
+
deviceId: number(),
|
|
22517
|
+
profile: string(),
|
|
22518
|
+
fromMs: number(),
|
|
22519
|
+
toMs: number(),
|
|
22520
|
+
options: ExportOptionsSchema,
|
|
22521
|
+
state: ExportStateSchema,
|
|
22522
|
+
/** 0–100 while rendering; null otherwise. */
|
|
22523
|
+
progressPct: number().nullable(),
|
|
22524
|
+
/** File size once ready; null before. */
|
|
22525
|
+
fileBytes: number().nullable(),
|
|
22526
|
+
expiresAt: number(),
|
|
22527
|
+
deleteAfterDownload: boolean(),
|
|
22528
|
+
/** Epoch of the first complete download; null until then. */
|
|
22529
|
+
downloadedAt: number().nullable(),
|
|
22530
|
+
createdAt: number(),
|
|
22531
|
+
/** User id/name that requested the export. */
|
|
22532
|
+
createdBy: string(),
|
|
22533
|
+
/** Failure reason when state is 'failed'; null otherwise. */
|
|
22534
|
+
error: string().nullable()
|
|
22535
|
+
});
|
|
22536
|
+
/** Candidate download URLs (LAN first, then operator extra hosts). */
|
|
22537
|
+
var ExportDownloadSchema = object({
|
|
22538
|
+
url: string(),
|
|
22539
|
+
endpoints: array(string())
|
|
22540
|
+
});
|
|
22541
|
+
method(object({
|
|
22542
|
+
deviceId: number(),
|
|
22543
|
+
profile: string(),
|
|
22544
|
+
fromMs: number(),
|
|
22545
|
+
toMs: number(),
|
|
22546
|
+
options: ExportOptionsSchema
|
|
22547
|
+
}), ExportRecordSchema, {
|
|
22548
|
+
kind: "mutation",
|
|
22549
|
+
auth: "protected"
|
|
22550
|
+
}), method(object({ deviceId: number().optional() }), array(ExportRecordSchema), {
|
|
22551
|
+
kind: "query",
|
|
22552
|
+
auth: "protected"
|
|
22553
|
+
}), method(object({ exportId: string() }), ExportRecordSchema, {
|
|
22554
|
+
kind: "query",
|
|
22555
|
+
auth: "protected"
|
|
22556
|
+
}), method(object({ exportId: string() }), ExportRecordSchema, {
|
|
22557
|
+
kind: "mutation",
|
|
22558
|
+
auth: "protected"
|
|
22559
|
+
}), method(object({ exportId: string() }), ExportRecordSchema, {
|
|
22560
|
+
kind: "mutation",
|
|
22561
|
+
auth: "protected"
|
|
22562
|
+
}), method(object({ exportId: string() }), ExportDownloadSchema, {
|
|
22563
|
+
kind: "query",
|
|
22564
|
+
auth: "protected"
|
|
22565
|
+
});
|
|
22566
|
+
/**
|
|
22408
22567
|
* One publishable camera stream as its OWNING PROVIDER describes it — the same
|
|
22409
22568
|
* payload the (legacy) push `streamBroker.publishCameraStream` carried, minus
|
|
22410
22569
|
* `deviceId`.
|
|
@@ -26328,6 +26487,42 @@ Object.freeze({
|
|
|
26328
26487
|
addonId: null,
|
|
26329
26488
|
access: "create"
|
|
26330
26489
|
},
|
|
26490
|
+
"recordingExport.cancelExport": {
|
|
26491
|
+
capName: "recordingExport",
|
|
26492
|
+
capScope: "system",
|
|
26493
|
+
addonId: null,
|
|
26494
|
+
access: "create"
|
|
26495
|
+
},
|
|
26496
|
+
"recordingExport.createExport": {
|
|
26497
|
+
capName: "recordingExport",
|
|
26498
|
+
capScope: "system",
|
|
26499
|
+
addonId: null,
|
|
26500
|
+
access: "create"
|
|
26501
|
+
},
|
|
26502
|
+
"recordingExport.deleteExport": {
|
|
26503
|
+
capName: "recordingExport",
|
|
26504
|
+
capScope: "system",
|
|
26505
|
+
addonId: null,
|
|
26506
|
+
access: "delete"
|
|
26507
|
+
},
|
|
26508
|
+
"recordingExport.getDownloadUrl": {
|
|
26509
|
+
capName: "recordingExport",
|
|
26510
|
+
capScope: "system",
|
|
26511
|
+
addonId: null,
|
|
26512
|
+
access: "view"
|
|
26513
|
+
},
|
|
26514
|
+
"recordingExport.getExport": {
|
|
26515
|
+
capName: "recordingExport",
|
|
26516
|
+
capScope: "system",
|
|
26517
|
+
addonId: null,
|
|
26518
|
+
access: "view"
|
|
26519
|
+
},
|
|
26520
|
+
"recordingExport.listExports": {
|
|
26521
|
+
capName: "recordingExport",
|
|
26522
|
+
capScope: "system",
|
|
26523
|
+
addonId: null,
|
|
26524
|
+
access: "view"
|
|
26525
|
+
},
|
|
26331
26526
|
"sceneMonitor.captureReference": {
|
|
26332
26527
|
capName: "scene-monitor",
|
|
26333
26528
|
capScope: "device",
|
package/dist/addon.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//#region ../types/dist/event-category-
|
|
1
|
+
//#region ../types/dist/event-category-D4HJq7Mw.mjs
|
|
2
2
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
3
3
|
EventCategory["SystemBoot"] = "system.boot";
|
|
4
4
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -151,6 +151,11 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
151
151
|
/** Runner-sampled scrub thumbnail (~1/5 s/camera). Telemetry (D8): a lost
|
|
152
152
|
* thumb is a scrub gap the recorder's keyframe backfill covers. */
|
|
153
153
|
EventCategory["RecordingThumbSampled"] = "recording.thumb-sampled";
|
|
154
|
+
/** Export render progress (0–100). Telemetry (D8): a lost tick is a stale
|
|
155
|
+
* progress bar the client reconciles via `recordingExport.getExport`. */
|
|
156
|
+
EventCategory["RecordingExportProgress"] = "recording.export.progress";
|
|
157
|
+
EventCategory["RecordingExportCompleted"] = "recording.export.completed";
|
|
158
|
+
EventCategory["RecordingExportFailed"] = "recording.export.failed";
|
|
154
159
|
EventCategory["DetectionEvent"] = "detection.event";
|
|
155
160
|
EventCategory["SessionTrackNew"] = "session.track.new";
|
|
156
161
|
EventCategory["SessionTrackExpired"] = "session.track.expired";
|
|
@@ -440,6 +445,25 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
440
445
|
*/
|
|
441
446
|
EventCategory["PipelineAnalyticsStationaryChanged"] = "pipeline-analytics.stationary-changed";
|
|
442
447
|
/**
|
|
448
|
+
* Fired by `addon-post-analysis` when a package-drop is confirmed inside
|
|
449
|
+
* a package zone — a newly-appeared stationary object of a package class
|
|
450
|
+
* that cleared the class / zone / dwell / size gates. Payload:
|
|
451
|
+
* `PipelineAnalyticsPackageDeliveredPayload` carrying `{ deviceId,
|
|
452
|
+
* entryId, className, zoneIds, keyFrameMediaKey?, bbox, timestamp }`.
|
|
453
|
+
* Telemetry (D8): the durable record is the `package-events` store row;
|
|
454
|
+
* this bus topic drives notifier rules + live UI. See
|
|
455
|
+
* docs/superpowers/specs/2026-07-17-package-zones-design.md §5.1.
|
|
456
|
+
*/
|
|
457
|
+
EventCategory["PipelineAnalyticsPackageDelivered"] = "pipeline-analytics.package-delivered";
|
|
458
|
+
/**
|
|
459
|
+
* Fired by `addon-post-analysis` when a previously-delivered package
|
|
460
|
+
* leaves its zone (the stationary entry departed — moved or swept).
|
|
461
|
+
* Payload: `PipelineAnalyticsPackagePickedUpPayload` carrying
|
|
462
|
+
* `{ deviceId, entryId, deliveredEventId, className, timestamp }`.
|
|
463
|
+
* Telemetry (D8). See package-zones-design §5.2.
|
|
464
|
+
*/
|
|
465
|
+
EventCategory["PipelineAnalyticsPackagePickedUp"] = "pipeline-analytics.package-picked-up";
|
|
466
|
+
/**
|
|
443
467
|
* Fired by `addon-post-analysis` whenever a gallery face row changes:
|
|
444
468
|
* `kind:'buffered'` a new detected face was persisted, `'assigned'` /
|
|
445
469
|
* `'unassigned'` its identity link changed, `'deleted'` the row was
|
|
@@ -5192,6 +5216,25 @@ function preprocess(fn, schema) {
|
|
|
5192
5216
|
out: schema
|
|
5193
5217
|
});
|
|
5194
5218
|
}
|
|
5219
|
+
//#endregion
|
|
5220
|
+
//#region ../../node_modules/zod/v4/classic/compat.js
|
|
5221
|
+
/** @deprecated Use the raw string literal codes instead, e.g. "invalid_type". */
|
|
5222
|
+
var ZodIssueCode = {
|
|
5223
|
+
invalid_type: "invalid_type",
|
|
5224
|
+
too_big: "too_big",
|
|
5225
|
+
too_small: "too_small",
|
|
5226
|
+
invalid_format: "invalid_format",
|
|
5227
|
+
not_multiple_of: "not_multiple_of",
|
|
5228
|
+
unrecognized_keys: "unrecognized_keys",
|
|
5229
|
+
invalid_union: "invalid_union",
|
|
5230
|
+
invalid_key: "invalid_key",
|
|
5231
|
+
invalid_element: "invalid_element",
|
|
5232
|
+
invalid_value: "invalid_value",
|
|
5233
|
+
custom: "custom"
|
|
5234
|
+
};
|
|
5235
|
+
/** @deprecated Do not use. Stub definition, only included for zod-to-json-schema compatibility. */
|
|
5236
|
+
var ZodFirstPartyTypeKind;
|
|
5237
|
+
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5195
5238
|
Object.fromEntries([
|
|
5196
5239
|
{
|
|
5197
5240
|
id: "overview",
|
|
@@ -14669,7 +14712,11 @@ array(ZoneRuleSchema).readonly();
|
|
|
14669
14712
|
* Extend the enum here when a new gating consumer comes online (audio
|
|
14670
14713
|
* gating, alert filtering, …) — no other surface needs to change.
|
|
14671
14714
|
*/
|
|
14672
|
-
var ZoneRuleStageEnum = _enum([
|
|
14715
|
+
var ZoneRuleStageEnum = _enum([
|
|
14716
|
+
"motion",
|
|
14717
|
+
"detection",
|
|
14718
|
+
"package"
|
|
14719
|
+
]);
|
|
14673
14720
|
/**
|
|
14674
14721
|
* Runtime registry: cap-property-name → cap definition. `BaseDevice`'s
|
|
14675
14722
|
* `state` getter looks up the cap definition here to construct a
|
|
@@ -14763,16 +14810,24 @@ var DEVICE_LOCAL_STATE_CAPS = {
|
|
|
14763
14810
|
})
|
|
14764
14811
|
},
|
|
14765
14812
|
/**
|
|
14766
|
-
* Runtime-state slice —
|
|
14813
|
+
* Runtime-state slice — every stage mirrored together so consumers
|
|
14767
14814
|
* see one reactive handle (`device.state.zoneRules.value`) instead
|
|
14768
|
-
* of
|
|
14769
|
-
* `{motion, detection}` shape, so subscribers always get the
|
|
14815
|
+
* of one per stage. Bulk-replace mutations on any stage write the full
|
|
14816
|
+
* `{motion, detection, package}` shape, so subscribers always get the
|
|
14770
14817
|
* complete current set. Consumers that only care about one stage
|
|
14771
14818
|
* just read the matching property.
|
|
14819
|
+
*
|
|
14820
|
+
* `package` backs the package-drop detector — a package zone is a
|
|
14821
|
+
* `ZoneRule` on the `'package'` stage referencing drawn polygons
|
|
14822
|
+
* (see docs/superpowers/specs/2026-07-17-package-zones-design.md §3.1).
|
|
14823
|
+
* The orchestrator provider that writes this stage lands in a later
|
|
14824
|
+
* slice; until then the mirror carries only `{motion, detection}` and
|
|
14825
|
+
* consumers read `package` as absent (treat as `[]`).
|
|
14772
14826
|
*/
|
|
14773
14827
|
runtimeState: object({
|
|
14774
14828
|
motion: array(ZoneRuleSchema).readonly(),
|
|
14775
|
-
detection: array(ZoneRuleSchema).readonly()
|
|
14829
|
+
detection: array(ZoneRuleSchema).readonly(),
|
|
14830
|
+
package: array(ZoneRuleSchema).readonly()
|
|
14776
14831
|
})
|
|
14777
14832
|
},
|
|
14778
14833
|
zones: zonesCapability
|
|
@@ -18734,6 +18789,7 @@ var EventKindIconSchema = _enum([
|
|
|
18734
18789
|
"smoke",
|
|
18735
18790
|
"water",
|
|
18736
18791
|
"button",
|
|
18792
|
+
"package",
|
|
18737
18793
|
"generic"
|
|
18738
18794
|
]);
|
|
18739
18795
|
var EventKindCategorySchema = _enum([
|
|
@@ -18741,7 +18797,8 @@ var EventKindCategorySchema = _enum([
|
|
|
18741
18797
|
"audio",
|
|
18742
18798
|
"detection",
|
|
18743
18799
|
"sensor",
|
|
18744
|
-
"custom"
|
|
18800
|
+
"custom",
|
|
18801
|
+
"package"
|
|
18745
18802
|
]);
|
|
18746
18803
|
var EventKindDescriptorSchema = object({
|
|
18747
18804
|
/** Stable kind id (e.g. 'motion', 'person', 'contact'). */
|
|
@@ -22404,6 +22461,108 @@ method(object({
|
|
|
22404
22461
|
auth: "admin"
|
|
22405
22462
|
});
|
|
22406
22463
|
/**
|
|
22464
|
+
* `recordingExport` cap — render a footage time range into a single downloadable
|
|
22465
|
+
* MP4 (regular / accelerated / decelerated / timelapse, ± audio), kept for a
|
|
22466
|
+
* bounded lifetime with a durable history, auto-expiry, and optional
|
|
22467
|
+
* delete-after-download.
|
|
22468
|
+
*
|
|
22469
|
+
* Like `recording` this is a `scope:'system', mode:'singleton'` cap: the
|
|
22470
|
+
* recorder self-gates so exactly ONE node (the designated `recordingNodeId`,
|
|
22471
|
+
* default `hub`) registers it. Device-scoped methods carry `deviceId` in their
|
|
22472
|
+
* input and dispatch to that single provider; the render runs on the node that
|
|
22473
|
+
* owns the footage (no cross-node segment transfer). Download rides the
|
|
22474
|
+
* framework addon data-plane. State persists in a DurableState blob (NOT
|
|
22475
|
+
* SQLite); history rows survive file deletion for audit.
|
|
22476
|
+
*/
|
|
22477
|
+
/** Playback-speed multiplier for the render (1 = realtime). */
|
|
22478
|
+
var ExportSpeedSchema = number().min(.25).max(32);
|
|
22479
|
+
/** Timelapse cadence — sample one source frame per `everyMs`, output at `outputFps`. */
|
|
22480
|
+
var ExportTimelapseSchema = object({
|
|
22481
|
+
everyMs: number().int().positive(),
|
|
22482
|
+
outputFps: number().int().min(1).max(60).optional()
|
|
22483
|
+
});
|
|
22484
|
+
/**
|
|
22485
|
+
* Render options. `speed` and `timelapse` are mutually exclusive. `includeAudio`
|
|
22486
|
+
* is honoured only for a realtime-ish speed (0.5–2×); timelapse is always
|
|
22487
|
+
* silent. `maxLifeMs` bounds how long the finished file is kept;
|
|
22488
|
+
* `deleteAfterDownload` removes it shortly after the first complete download.
|
|
22489
|
+
*/
|
|
22490
|
+
var ExportOptionsSchema = object({
|
|
22491
|
+
speed: ExportSpeedSchema.optional(),
|
|
22492
|
+
timelapse: ExportTimelapseSchema.optional(),
|
|
22493
|
+
includeAudio: boolean(),
|
|
22494
|
+
maxLifeMs: number().int().positive(),
|
|
22495
|
+
deleteAfterDownload: boolean(),
|
|
22496
|
+
title: string().max(200).optional()
|
|
22497
|
+
}).superRefine((v, ctx) => {
|
|
22498
|
+
if (v.speed !== void 0 && v.timelapse !== void 0) ctx.addIssue({
|
|
22499
|
+
code: ZodIssueCode.custom,
|
|
22500
|
+
message: "speed and timelapse are mutually exclusive",
|
|
22501
|
+
path: ["timelapse"]
|
|
22502
|
+
});
|
|
22503
|
+
});
|
|
22504
|
+
var ExportStateSchema = _enum([
|
|
22505
|
+
"queued",
|
|
22506
|
+
"rendering",
|
|
22507
|
+
"ready",
|
|
22508
|
+
"failed",
|
|
22509
|
+
"expired",
|
|
22510
|
+
"deleted"
|
|
22511
|
+
]);
|
|
22512
|
+
/** One export job / history row. */
|
|
22513
|
+
var ExportRecordSchema = object({
|
|
22514
|
+
id: string(),
|
|
22515
|
+
deviceId: number(),
|
|
22516
|
+
profile: string(),
|
|
22517
|
+
fromMs: number(),
|
|
22518
|
+
toMs: number(),
|
|
22519
|
+
options: ExportOptionsSchema,
|
|
22520
|
+
state: ExportStateSchema,
|
|
22521
|
+
/** 0–100 while rendering; null otherwise. */
|
|
22522
|
+
progressPct: number().nullable(),
|
|
22523
|
+
/** File size once ready; null before. */
|
|
22524
|
+
fileBytes: number().nullable(),
|
|
22525
|
+
expiresAt: number(),
|
|
22526
|
+
deleteAfterDownload: boolean(),
|
|
22527
|
+
/** Epoch of the first complete download; null until then. */
|
|
22528
|
+
downloadedAt: number().nullable(),
|
|
22529
|
+
createdAt: number(),
|
|
22530
|
+
/** User id/name that requested the export. */
|
|
22531
|
+
createdBy: string(),
|
|
22532
|
+
/** Failure reason when state is 'failed'; null otherwise. */
|
|
22533
|
+
error: string().nullable()
|
|
22534
|
+
});
|
|
22535
|
+
/** Candidate download URLs (LAN first, then operator extra hosts). */
|
|
22536
|
+
var ExportDownloadSchema = object({
|
|
22537
|
+
url: string(),
|
|
22538
|
+
endpoints: array(string())
|
|
22539
|
+
});
|
|
22540
|
+
method(object({
|
|
22541
|
+
deviceId: number(),
|
|
22542
|
+
profile: string(),
|
|
22543
|
+
fromMs: number(),
|
|
22544
|
+
toMs: number(),
|
|
22545
|
+
options: ExportOptionsSchema
|
|
22546
|
+
}), ExportRecordSchema, {
|
|
22547
|
+
kind: "mutation",
|
|
22548
|
+
auth: "protected"
|
|
22549
|
+
}), method(object({ deviceId: number().optional() }), array(ExportRecordSchema), {
|
|
22550
|
+
kind: "query",
|
|
22551
|
+
auth: "protected"
|
|
22552
|
+
}), method(object({ exportId: string() }), ExportRecordSchema, {
|
|
22553
|
+
kind: "query",
|
|
22554
|
+
auth: "protected"
|
|
22555
|
+
}), method(object({ exportId: string() }), ExportRecordSchema, {
|
|
22556
|
+
kind: "mutation",
|
|
22557
|
+
auth: "protected"
|
|
22558
|
+
}), method(object({ exportId: string() }), ExportRecordSchema, {
|
|
22559
|
+
kind: "mutation",
|
|
22560
|
+
auth: "protected"
|
|
22561
|
+
}), method(object({ exportId: string() }), ExportDownloadSchema, {
|
|
22562
|
+
kind: "query",
|
|
22563
|
+
auth: "protected"
|
|
22564
|
+
});
|
|
22565
|
+
/**
|
|
22407
22566
|
* One publishable camera stream as its OWNING PROVIDER describes it — the same
|
|
22408
22567
|
* payload the (legacy) push `streamBroker.publishCameraStream` carried, minus
|
|
22409
22568
|
* `deviceId`.
|
|
@@ -26327,6 +26486,42 @@ Object.freeze({
|
|
|
26327
26486
|
addonId: null,
|
|
26328
26487
|
access: "create"
|
|
26329
26488
|
},
|
|
26489
|
+
"recordingExport.cancelExport": {
|
|
26490
|
+
capName: "recordingExport",
|
|
26491
|
+
capScope: "system",
|
|
26492
|
+
addonId: null,
|
|
26493
|
+
access: "create"
|
|
26494
|
+
},
|
|
26495
|
+
"recordingExport.createExport": {
|
|
26496
|
+
capName: "recordingExport",
|
|
26497
|
+
capScope: "system",
|
|
26498
|
+
addonId: null,
|
|
26499
|
+
access: "create"
|
|
26500
|
+
},
|
|
26501
|
+
"recordingExport.deleteExport": {
|
|
26502
|
+
capName: "recordingExport",
|
|
26503
|
+
capScope: "system",
|
|
26504
|
+
addonId: null,
|
|
26505
|
+
access: "delete"
|
|
26506
|
+
},
|
|
26507
|
+
"recordingExport.getDownloadUrl": {
|
|
26508
|
+
capName: "recordingExport",
|
|
26509
|
+
capScope: "system",
|
|
26510
|
+
addonId: null,
|
|
26511
|
+
access: "view"
|
|
26512
|
+
},
|
|
26513
|
+
"recordingExport.getExport": {
|
|
26514
|
+
capName: "recordingExport",
|
|
26515
|
+
capScope: "system",
|
|
26516
|
+
addonId: null,
|
|
26517
|
+
access: "view"
|
|
26518
|
+
},
|
|
26519
|
+
"recordingExport.listExports": {
|
|
26520
|
+
capName: "recordingExport",
|
|
26521
|
+
capScope: "system",
|
|
26522
|
+
addonId: null,
|
|
26523
|
+
access: "view"
|
|
26524
|
+
},
|
|
26330
26525
|
"sceneMonitor.captureReference": {
|
|
26331
26526
|
capName: "scene-monitor",
|
|
26332
26527
|
capScope: "device",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-provider-unifi",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.12",
|
|
4
4
|
"description": "UniFi Network controller device-provider addon for CamStack — local-controller infra switches/APs (as containers) + network-client presence. NO cameras/Protect.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|