@camstack/addon-export-hap 1.1.25 → 1.1.26
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/export-hap.addon.js +192 -4
- package/dist/export-hap.addon.mjs +192 -4
- package/package.json +1 -1
package/dist/export-hap.addon.js
CHANGED
|
@@ -35,7 +35,7 @@ let node_fs_promises = require("node:fs/promises");
|
|
|
35
35
|
node_fs_promises = __toESM(node_fs_promises);
|
|
36
36
|
let node_dgram = require("node:dgram");
|
|
37
37
|
let node_os = require("node:os");
|
|
38
|
-
//#region ../types/dist/event-category-
|
|
38
|
+
//#region ../types/dist/event-category-D4HJq7Mw.mjs
|
|
39
39
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
40
40
|
EventCategory["SystemBoot"] = "system.boot";
|
|
41
41
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -188,6 +188,11 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
188
188
|
/** Runner-sampled scrub thumbnail (~1/5 s/camera). Telemetry (D8): a lost
|
|
189
189
|
* thumb is a scrub gap the recorder's keyframe backfill covers. */
|
|
190
190
|
EventCategory["RecordingThumbSampled"] = "recording.thumb-sampled";
|
|
191
|
+
/** Export render progress (0–100). Telemetry (D8): a lost tick is a stale
|
|
192
|
+
* progress bar the client reconciles via `recordingExport.getExport`. */
|
|
193
|
+
EventCategory["RecordingExportProgress"] = "recording.export.progress";
|
|
194
|
+
EventCategory["RecordingExportCompleted"] = "recording.export.completed";
|
|
195
|
+
EventCategory["RecordingExportFailed"] = "recording.export.failed";
|
|
191
196
|
EventCategory["DetectionEvent"] = "detection.event";
|
|
192
197
|
EventCategory["SessionTrackNew"] = "session.track.new";
|
|
193
198
|
EventCategory["SessionTrackExpired"] = "session.track.expired";
|
|
@@ -477,6 +482,25 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
477
482
|
*/
|
|
478
483
|
EventCategory["PipelineAnalyticsStationaryChanged"] = "pipeline-analytics.stationary-changed";
|
|
479
484
|
/**
|
|
485
|
+
* Fired by `addon-post-analysis` when a package-drop is confirmed inside
|
|
486
|
+
* a package zone — a newly-appeared stationary object of a package class
|
|
487
|
+
* that cleared the class / zone / dwell / size gates. Payload:
|
|
488
|
+
* `PipelineAnalyticsPackageDeliveredPayload` carrying `{ deviceId,
|
|
489
|
+
* entryId, className, zoneIds, keyFrameMediaKey?, bbox, timestamp }`.
|
|
490
|
+
* Telemetry (D8): the durable record is the `package-events` store row;
|
|
491
|
+
* this bus topic drives notifier rules + live UI. See
|
|
492
|
+
* docs/superpowers/specs/2026-07-17-package-zones-design.md §5.1.
|
|
493
|
+
*/
|
|
494
|
+
EventCategory["PipelineAnalyticsPackageDelivered"] = "pipeline-analytics.package-delivered";
|
|
495
|
+
/**
|
|
496
|
+
* Fired by `addon-post-analysis` when a previously-delivered package
|
|
497
|
+
* leaves its zone (the stationary entry departed — moved or swept).
|
|
498
|
+
* Payload: `PipelineAnalyticsPackagePickedUpPayload` carrying
|
|
499
|
+
* `{ deviceId, entryId, deliveredEventId, className, timestamp }`.
|
|
500
|
+
* Telemetry (D8). See package-zones-design §5.2.
|
|
501
|
+
*/
|
|
502
|
+
EventCategory["PipelineAnalyticsPackagePickedUp"] = "pipeline-analytics.package-picked-up";
|
|
503
|
+
/**
|
|
480
504
|
* Fired by `addon-post-analysis` whenever a gallery face row changes:
|
|
481
505
|
* `kind:'buffered'` a new detected face was persisted, `'assigned'` /
|
|
482
506
|
* `'unassigned'` its identity link changed, `'deleted'` the row was
|
|
@@ -5215,6 +5239,25 @@ function _instanceof(cls, params = {}) {
|
|
|
5215
5239
|
};
|
|
5216
5240
|
return inst;
|
|
5217
5241
|
}
|
|
5242
|
+
//#endregion
|
|
5243
|
+
//#region ../../node_modules/zod/v4/classic/compat.js
|
|
5244
|
+
/** @deprecated Use the raw string literal codes instead, e.g. "invalid_type". */
|
|
5245
|
+
var ZodIssueCode = {
|
|
5246
|
+
invalid_type: "invalid_type",
|
|
5247
|
+
too_big: "too_big",
|
|
5248
|
+
too_small: "too_small",
|
|
5249
|
+
invalid_format: "invalid_format",
|
|
5250
|
+
not_multiple_of: "not_multiple_of",
|
|
5251
|
+
unrecognized_keys: "unrecognized_keys",
|
|
5252
|
+
invalid_union: "invalid_union",
|
|
5253
|
+
invalid_key: "invalid_key",
|
|
5254
|
+
invalid_element: "invalid_element",
|
|
5255
|
+
invalid_value: "invalid_value",
|
|
5256
|
+
custom: "custom"
|
|
5257
|
+
};
|
|
5258
|
+
/** @deprecated Do not use. Stub definition, only included for zod-to-json-schema compatibility. */
|
|
5259
|
+
var ZodFirstPartyTypeKind;
|
|
5260
|
+
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5218
5261
|
Object.fromEntries([
|
|
5219
5262
|
{
|
|
5220
5263
|
id: "overview",
|
|
@@ -12624,7 +12667,11 @@ array(ZoneRuleSchema).readonly();
|
|
|
12624
12667
|
* Extend the enum here when a new gating consumer comes online (audio
|
|
12625
12668
|
* gating, alert filtering, …) — no other surface needs to change.
|
|
12626
12669
|
*/
|
|
12627
|
-
var ZoneRuleStageEnum = _enum([
|
|
12670
|
+
var ZoneRuleStageEnum = _enum([
|
|
12671
|
+
"motion",
|
|
12672
|
+
"detection",
|
|
12673
|
+
"package"
|
|
12674
|
+
]);
|
|
12628
12675
|
DeviceType.Camera, method(object({
|
|
12629
12676
|
deviceId: number(),
|
|
12630
12677
|
stage: ZoneRuleStageEnum
|
|
@@ -12637,7 +12684,8 @@ DeviceType.Camera, method(object({
|
|
|
12637
12684
|
auth: "admin"
|
|
12638
12685
|
}), object({
|
|
12639
12686
|
motion: array(ZoneRuleSchema).readonly(),
|
|
12640
|
-
detection: array(ZoneRuleSchema).readonly()
|
|
12687
|
+
detection: array(ZoneRuleSchema).readonly(),
|
|
12688
|
+
package: array(ZoneRuleSchema).readonly()
|
|
12641
12689
|
});
|
|
12642
12690
|
var ProviderStatusSchema = object({
|
|
12643
12691
|
connected: boolean(),
|
|
@@ -15845,6 +15893,7 @@ var EventKindIconSchema = _enum([
|
|
|
15845
15893
|
"smoke",
|
|
15846
15894
|
"water",
|
|
15847
15895
|
"button",
|
|
15896
|
+
"package",
|
|
15848
15897
|
"generic"
|
|
15849
15898
|
]);
|
|
15850
15899
|
var EventKindCategorySchema = _enum([
|
|
@@ -15852,7 +15901,8 @@ var EventKindCategorySchema = _enum([
|
|
|
15852
15901
|
"audio",
|
|
15853
15902
|
"detection",
|
|
15854
15903
|
"sensor",
|
|
15855
|
-
"custom"
|
|
15904
|
+
"custom",
|
|
15905
|
+
"package"
|
|
15856
15906
|
]);
|
|
15857
15907
|
var EventKindDescriptorSchema = object({
|
|
15858
15908
|
/** Stable kind id (e.g. 'motion', 'person', 'contact'). */
|
|
@@ -19498,6 +19548,108 @@ method(object({
|
|
|
19498
19548
|
auth: "admin"
|
|
19499
19549
|
});
|
|
19500
19550
|
/**
|
|
19551
|
+
* `recordingExport` cap — render a footage time range into a single downloadable
|
|
19552
|
+
* MP4 (regular / accelerated / decelerated / timelapse, ± audio), kept for a
|
|
19553
|
+
* bounded lifetime with a durable history, auto-expiry, and optional
|
|
19554
|
+
* delete-after-download.
|
|
19555
|
+
*
|
|
19556
|
+
* Like `recording` this is a `scope:'system', mode:'singleton'` cap: the
|
|
19557
|
+
* recorder self-gates so exactly ONE node (the designated `recordingNodeId`,
|
|
19558
|
+
* default `hub`) registers it. Device-scoped methods carry `deviceId` in their
|
|
19559
|
+
* input and dispatch to that single provider; the render runs on the node that
|
|
19560
|
+
* owns the footage (no cross-node segment transfer). Download rides the
|
|
19561
|
+
* framework addon data-plane. State persists in a DurableState blob (NOT
|
|
19562
|
+
* SQLite); history rows survive file deletion for audit.
|
|
19563
|
+
*/
|
|
19564
|
+
/** Playback-speed multiplier for the render (1 = realtime). */
|
|
19565
|
+
var ExportSpeedSchema = number().min(.25).max(32);
|
|
19566
|
+
/** Timelapse cadence — sample one source frame per `everyMs`, output at `outputFps`. */
|
|
19567
|
+
var ExportTimelapseSchema = object({
|
|
19568
|
+
everyMs: number().int().positive(),
|
|
19569
|
+
outputFps: number().int().min(1).max(60).optional()
|
|
19570
|
+
});
|
|
19571
|
+
/**
|
|
19572
|
+
* Render options. `speed` and `timelapse` are mutually exclusive. `includeAudio`
|
|
19573
|
+
* is honoured only for a realtime-ish speed (0.5–2×); timelapse is always
|
|
19574
|
+
* silent. `maxLifeMs` bounds how long the finished file is kept;
|
|
19575
|
+
* `deleteAfterDownload` removes it shortly after the first complete download.
|
|
19576
|
+
*/
|
|
19577
|
+
var ExportOptionsSchema = object({
|
|
19578
|
+
speed: ExportSpeedSchema.optional(),
|
|
19579
|
+
timelapse: ExportTimelapseSchema.optional(),
|
|
19580
|
+
includeAudio: boolean(),
|
|
19581
|
+
maxLifeMs: number().int().positive(),
|
|
19582
|
+
deleteAfterDownload: boolean(),
|
|
19583
|
+
title: string().max(200).optional()
|
|
19584
|
+
}).superRefine((v, ctx) => {
|
|
19585
|
+
if (v.speed !== void 0 && v.timelapse !== void 0) ctx.addIssue({
|
|
19586
|
+
code: ZodIssueCode.custom,
|
|
19587
|
+
message: "speed and timelapse are mutually exclusive",
|
|
19588
|
+
path: ["timelapse"]
|
|
19589
|
+
});
|
|
19590
|
+
});
|
|
19591
|
+
var ExportStateSchema = _enum([
|
|
19592
|
+
"queued",
|
|
19593
|
+
"rendering",
|
|
19594
|
+
"ready",
|
|
19595
|
+
"failed",
|
|
19596
|
+
"expired",
|
|
19597
|
+
"deleted"
|
|
19598
|
+
]);
|
|
19599
|
+
/** One export job / history row. */
|
|
19600
|
+
var ExportRecordSchema = object({
|
|
19601
|
+
id: string(),
|
|
19602
|
+
deviceId: number(),
|
|
19603
|
+
profile: string(),
|
|
19604
|
+
fromMs: number(),
|
|
19605
|
+
toMs: number(),
|
|
19606
|
+
options: ExportOptionsSchema,
|
|
19607
|
+
state: ExportStateSchema,
|
|
19608
|
+
/** 0–100 while rendering; null otherwise. */
|
|
19609
|
+
progressPct: number().nullable(),
|
|
19610
|
+
/** File size once ready; null before. */
|
|
19611
|
+
fileBytes: number().nullable(),
|
|
19612
|
+
expiresAt: number(),
|
|
19613
|
+
deleteAfterDownload: boolean(),
|
|
19614
|
+
/** Epoch of the first complete download; null until then. */
|
|
19615
|
+
downloadedAt: number().nullable(),
|
|
19616
|
+
createdAt: number(),
|
|
19617
|
+
/** User id/name that requested the export. */
|
|
19618
|
+
createdBy: string(),
|
|
19619
|
+
/** Failure reason when state is 'failed'; null otherwise. */
|
|
19620
|
+
error: string().nullable()
|
|
19621
|
+
});
|
|
19622
|
+
/** Candidate download URLs (LAN first, then operator extra hosts). */
|
|
19623
|
+
var ExportDownloadSchema = object({
|
|
19624
|
+
url: string(),
|
|
19625
|
+
endpoints: array(string())
|
|
19626
|
+
});
|
|
19627
|
+
method(object({
|
|
19628
|
+
deviceId: number(),
|
|
19629
|
+
profile: string(),
|
|
19630
|
+
fromMs: number(),
|
|
19631
|
+
toMs: number(),
|
|
19632
|
+
options: ExportOptionsSchema
|
|
19633
|
+
}), ExportRecordSchema, {
|
|
19634
|
+
kind: "mutation",
|
|
19635
|
+
auth: "protected"
|
|
19636
|
+
}), method(object({ deviceId: number().optional() }), array(ExportRecordSchema), {
|
|
19637
|
+
kind: "query",
|
|
19638
|
+
auth: "protected"
|
|
19639
|
+
}), method(object({ exportId: string() }), ExportRecordSchema, {
|
|
19640
|
+
kind: "query",
|
|
19641
|
+
auth: "protected"
|
|
19642
|
+
}), method(object({ exportId: string() }), ExportRecordSchema, {
|
|
19643
|
+
kind: "mutation",
|
|
19644
|
+
auth: "protected"
|
|
19645
|
+
}), method(object({ exportId: string() }), ExportRecordSchema, {
|
|
19646
|
+
kind: "mutation",
|
|
19647
|
+
auth: "protected"
|
|
19648
|
+
}), method(object({ exportId: string() }), ExportDownloadSchema, {
|
|
19649
|
+
kind: "query",
|
|
19650
|
+
auth: "protected"
|
|
19651
|
+
});
|
|
19652
|
+
/**
|
|
19501
19653
|
* One publishable camera stream as its OWNING PROVIDER describes it — the same
|
|
19502
19654
|
* payload the (legacy) push `streamBroker.publishCameraStream` carried, minus
|
|
19503
19655
|
* `deviceId`.
|
|
@@ -23421,6 +23573,42 @@ Object.freeze({
|
|
|
23421
23573
|
addonId: null,
|
|
23422
23574
|
access: "create"
|
|
23423
23575
|
},
|
|
23576
|
+
"recordingExport.cancelExport": {
|
|
23577
|
+
capName: "recordingExport",
|
|
23578
|
+
capScope: "system",
|
|
23579
|
+
addonId: null,
|
|
23580
|
+
access: "create"
|
|
23581
|
+
},
|
|
23582
|
+
"recordingExport.createExport": {
|
|
23583
|
+
capName: "recordingExport",
|
|
23584
|
+
capScope: "system",
|
|
23585
|
+
addonId: null,
|
|
23586
|
+
access: "create"
|
|
23587
|
+
},
|
|
23588
|
+
"recordingExport.deleteExport": {
|
|
23589
|
+
capName: "recordingExport",
|
|
23590
|
+
capScope: "system",
|
|
23591
|
+
addonId: null,
|
|
23592
|
+
access: "delete"
|
|
23593
|
+
},
|
|
23594
|
+
"recordingExport.getDownloadUrl": {
|
|
23595
|
+
capName: "recordingExport",
|
|
23596
|
+
capScope: "system",
|
|
23597
|
+
addonId: null,
|
|
23598
|
+
access: "view"
|
|
23599
|
+
},
|
|
23600
|
+
"recordingExport.getExport": {
|
|
23601
|
+
capName: "recordingExport",
|
|
23602
|
+
capScope: "system",
|
|
23603
|
+
addonId: null,
|
|
23604
|
+
access: "view"
|
|
23605
|
+
},
|
|
23606
|
+
"recordingExport.listExports": {
|
|
23607
|
+
capName: "recordingExport",
|
|
23608
|
+
capScope: "system",
|
|
23609
|
+
addonId: null,
|
|
23610
|
+
access: "view"
|
|
23611
|
+
},
|
|
23424
23612
|
"sceneMonitor.captureReference": {
|
|
23425
23613
|
capName: "scene-monitor",
|
|
23426
23614
|
capScope: "device",
|
|
@@ -10,7 +10,7 @@ import { networkInterfaces } from "node:os";
|
|
|
10
10
|
var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
|
|
11
11
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
12
12
|
//#endregion
|
|
13
|
-
//#region ../types/dist/event-category-
|
|
13
|
+
//#region ../types/dist/event-category-D4HJq7Mw.mjs
|
|
14
14
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
15
15
|
EventCategory["SystemBoot"] = "system.boot";
|
|
16
16
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -163,6 +163,11 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
163
163
|
/** Runner-sampled scrub thumbnail (~1/5 s/camera). Telemetry (D8): a lost
|
|
164
164
|
* thumb is a scrub gap the recorder's keyframe backfill covers. */
|
|
165
165
|
EventCategory["RecordingThumbSampled"] = "recording.thumb-sampled";
|
|
166
|
+
/** Export render progress (0–100). Telemetry (D8): a lost tick is a stale
|
|
167
|
+
* progress bar the client reconciles via `recordingExport.getExport`. */
|
|
168
|
+
EventCategory["RecordingExportProgress"] = "recording.export.progress";
|
|
169
|
+
EventCategory["RecordingExportCompleted"] = "recording.export.completed";
|
|
170
|
+
EventCategory["RecordingExportFailed"] = "recording.export.failed";
|
|
166
171
|
EventCategory["DetectionEvent"] = "detection.event";
|
|
167
172
|
EventCategory["SessionTrackNew"] = "session.track.new";
|
|
168
173
|
EventCategory["SessionTrackExpired"] = "session.track.expired";
|
|
@@ -452,6 +457,25 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
452
457
|
*/
|
|
453
458
|
EventCategory["PipelineAnalyticsStationaryChanged"] = "pipeline-analytics.stationary-changed";
|
|
454
459
|
/**
|
|
460
|
+
* Fired by `addon-post-analysis` when a package-drop is confirmed inside
|
|
461
|
+
* a package zone — a newly-appeared stationary object of a package class
|
|
462
|
+
* that cleared the class / zone / dwell / size gates. Payload:
|
|
463
|
+
* `PipelineAnalyticsPackageDeliveredPayload` carrying `{ deviceId,
|
|
464
|
+
* entryId, className, zoneIds, keyFrameMediaKey?, bbox, timestamp }`.
|
|
465
|
+
* Telemetry (D8): the durable record is the `package-events` store row;
|
|
466
|
+
* this bus topic drives notifier rules + live UI. See
|
|
467
|
+
* docs/superpowers/specs/2026-07-17-package-zones-design.md §5.1.
|
|
468
|
+
*/
|
|
469
|
+
EventCategory["PipelineAnalyticsPackageDelivered"] = "pipeline-analytics.package-delivered";
|
|
470
|
+
/**
|
|
471
|
+
* Fired by `addon-post-analysis` when a previously-delivered package
|
|
472
|
+
* leaves its zone (the stationary entry departed — moved or swept).
|
|
473
|
+
* Payload: `PipelineAnalyticsPackagePickedUpPayload` carrying
|
|
474
|
+
* `{ deviceId, entryId, deliveredEventId, className, timestamp }`.
|
|
475
|
+
* Telemetry (D8). See package-zones-design §5.2.
|
|
476
|
+
*/
|
|
477
|
+
EventCategory["PipelineAnalyticsPackagePickedUp"] = "pipeline-analytics.package-picked-up";
|
|
478
|
+
/**
|
|
455
479
|
* Fired by `addon-post-analysis` whenever a gallery face row changes:
|
|
456
480
|
* `kind:'buffered'` a new detected face was persisted, `'assigned'` /
|
|
457
481
|
* `'unassigned'` its identity link changed, `'deleted'` the row was
|
|
@@ -5190,6 +5214,25 @@ function _instanceof(cls, params = {}) {
|
|
|
5190
5214
|
};
|
|
5191
5215
|
return inst;
|
|
5192
5216
|
}
|
|
5217
|
+
//#endregion
|
|
5218
|
+
//#region ../../node_modules/zod/v4/classic/compat.js
|
|
5219
|
+
/** @deprecated Use the raw string literal codes instead, e.g. "invalid_type". */
|
|
5220
|
+
var ZodIssueCode = {
|
|
5221
|
+
invalid_type: "invalid_type",
|
|
5222
|
+
too_big: "too_big",
|
|
5223
|
+
too_small: "too_small",
|
|
5224
|
+
invalid_format: "invalid_format",
|
|
5225
|
+
not_multiple_of: "not_multiple_of",
|
|
5226
|
+
unrecognized_keys: "unrecognized_keys",
|
|
5227
|
+
invalid_union: "invalid_union",
|
|
5228
|
+
invalid_key: "invalid_key",
|
|
5229
|
+
invalid_element: "invalid_element",
|
|
5230
|
+
invalid_value: "invalid_value",
|
|
5231
|
+
custom: "custom"
|
|
5232
|
+
};
|
|
5233
|
+
/** @deprecated Do not use. Stub definition, only included for zod-to-json-schema compatibility. */
|
|
5234
|
+
var ZodFirstPartyTypeKind;
|
|
5235
|
+
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5193
5236
|
Object.fromEntries([
|
|
5194
5237
|
{
|
|
5195
5238
|
id: "overview",
|
|
@@ -12599,7 +12642,11 @@ array(ZoneRuleSchema).readonly();
|
|
|
12599
12642
|
* Extend the enum here when a new gating consumer comes online (audio
|
|
12600
12643
|
* gating, alert filtering, …) — no other surface needs to change.
|
|
12601
12644
|
*/
|
|
12602
|
-
var ZoneRuleStageEnum = _enum([
|
|
12645
|
+
var ZoneRuleStageEnum = _enum([
|
|
12646
|
+
"motion",
|
|
12647
|
+
"detection",
|
|
12648
|
+
"package"
|
|
12649
|
+
]);
|
|
12603
12650
|
DeviceType.Camera, method(object({
|
|
12604
12651
|
deviceId: number(),
|
|
12605
12652
|
stage: ZoneRuleStageEnum
|
|
@@ -12612,7 +12659,8 @@ DeviceType.Camera, method(object({
|
|
|
12612
12659
|
auth: "admin"
|
|
12613
12660
|
}), object({
|
|
12614
12661
|
motion: array(ZoneRuleSchema).readonly(),
|
|
12615
|
-
detection: array(ZoneRuleSchema).readonly()
|
|
12662
|
+
detection: array(ZoneRuleSchema).readonly(),
|
|
12663
|
+
package: array(ZoneRuleSchema).readonly()
|
|
12616
12664
|
});
|
|
12617
12665
|
var ProviderStatusSchema = object({
|
|
12618
12666
|
connected: boolean(),
|
|
@@ -15820,6 +15868,7 @@ var EventKindIconSchema = _enum([
|
|
|
15820
15868
|
"smoke",
|
|
15821
15869
|
"water",
|
|
15822
15870
|
"button",
|
|
15871
|
+
"package",
|
|
15823
15872
|
"generic"
|
|
15824
15873
|
]);
|
|
15825
15874
|
var EventKindCategorySchema = _enum([
|
|
@@ -15827,7 +15876,8 @@ var EventKindCategorySchema = _enum([
|
|
|
15827
15876
|
"audio",
|
|
15828
15877
|
"detection",
|
|
15829
15878
|
"sensor",
|
|
15830
|
-
"custom"
|
|
15879
|
+
"custom",
|
|
15880
|
+
"package"
|
|
15831
15881
|
]);
|
|
15832
15882
|
var EventKindDescriptorSchema = object({
|
|
15833
15883
|
/** Stable kind id (e.g. 'motion', 'person', 'contact'). */
|
|
@@ -19473,6 +19523,108 @@ method(object({
|
|
|
19473
19523
|
auth: "admin"
|
|
19474
19524
|
});
|
|
19475
19525
|
/**
|
|
19526
|
+
* `recordingExport` cap — render a footage time range into a single downloadable
|
|
19527
|
+
* MP4 (regular / accelerated / decelerated / timelapse, ± audio), kept for a
|
|
19528
|
+
* bounded lifetime with a durable history, auto-expiry, and optional
|
|
19529
|
+
* delete-after-download.
|
|
19530
|
+
*
|
|
19531
|
+
* Like `recording` this is a `scope:'system', mode:'singleton'` cap: the
|
|
19532
|
+
* recorder self-gates so exactly ONE node (the designated `recordingNodeId`,
|
|
19533
|
+
* default `hub`) registers it. Device-scoped methods carry `deviceId` in their
|
|
19534
|
+
* input and dispatch to that single provider; the render runs on the node that
|
|
19535
|
+
* owns the footage (no cross-node segment transfer). Download rides the
|
|
19536
|
+
* framework addon data-plane. State persists in a DurableState blob (NOT
|
|
19537
|
+
* SQLite); history rows survive file deletion for audit.
|
|
19538
|
+
*/
|
|
19539
|
+
/** Playback-speed multiplier for the render (1 = realtime). */
|
|
19540
|
+
var ExportSpeedSchema = number().min(.25).max(32);
|
|
19541
|
+
/** Timelapse cadence — sample one source frame per `everyMs`, output at `outputFps`. */
|
|
19542
|
+
var ExportTimelapseSchema = object({
|
|
19543
|
+
everyMs: number().int().positive(),
|
|
19544
|
+
outputFps: number().int().min(1).max(60).optional()
|
|
19545
|
+
});
|
|
19546
|
+
/**
|
|
19547
|
+
* Render options. `speed` and `timelapse` are mutually exclusive. `includeAudio`
|
|
19548
|
+
* is honoured only for a realtime-ish speed (0.5–2×); timelapse is always
|
|
19549
|
+
* silent. `maxLifeMs` bounds how long the finished file is kept;
|
|
19550
|
+
* `deleteAfterDownload` removes it shortly after the first complete download.
|
|
19551
|
+
*/
|
|
19552
|
+
var ExportOptionsSchema = object({
|
|
19553
|
+
speed: ExportSpeedSchema.optional(),
|
|
19554
|
+
timelapse: ExportTimelapseSchema.optional(),
|
|
19555
|
+
includeAudio: boolean(),
|
|
19556
|
+
maxLifeMs: number().int().positive(),
|
|
19557
|
+
deleteAfterDownload: boolean(),
|
|
19558
|
+
title: string().max(200).optional()
|
|
19559
|
+
}).superRefine((v, ctx) => {
|
|
19560
|
+
if (v.speed !== void 0 && v.timelapse !== void 0) ctx.addIssue({
|
|
19561
|
+
code: ZodIssueCode.custom,
|
|
19562
|
+
message: "speed and timelapse are mutually exclusive",
|
|
19563
|
+
path: ["timelapse"]
|
|
19564
|
+
});
|
|
19565
|
+
});
|
|
19566
|
+
var ExportStateSchema = _enum([
|
|
19567
|
+
"queued",
|
|
19568
|
+
"rendering",
|
|
19569
|
+
"ready",
|
|
19570
|
+
"failed",
|
|
19571
|
+
"expired",
|
|
19572
|
+
"deleted"
|
|
19573
|
+
]);
|
|
19574
|
+
/** One export job / history row. */
|
|
19575
|
+
var ExportRecordSchema = object({
|
|
19576
|
+
id: string(),
|
|
19577
|
+
deviceId: number(),
|
|
19578
|
+
profile: string(),
|
|
19579
|
+
fromMs: number(),
|
|
19580
|
+
toMs: number(),
|
|
19581
|
+
options: ExportOptionsSchema,
|
|
19582
|
+
state: ExportStateSchema,
|
|
19583
|
+
/** 0–100 while rendering; null otherwise. */
|
|
19584
|
+
progressPct: number().nullable(),
|
|
19585
|
+
/** File size once ready; null before. */
|
|
19586
|
+
fileBytes: number().nullable(),
|
|
19587
|
+
expiresAt: number(),
|
|
19588
|
+
deleteAfterDownload: boolean(),
|
|
19589
|
+
/** Epoch of the first complete download; null until then. */
|
|
19590
|
+
downloadedAt: number().nullable(),
|
|
19591
|
+
createdAt: number(),
|
|
19592
|
+
/** User id/name that requested the export. */
|
|
19593
|
+
createdBy: string(),
|
|
19594
|
+
/** Failure reason when state is 'failed'; null otherwise. */
|
|
19595
|
+
error: string().nullable()
|
|
19596
|
+
});
|
|
19597
|
+
/** Candidate download URLs (LAN first, then operator extra hosts). */
|
|
19598
|
+
var ExportDownloadSchema = object({
|
|
19599
|
+
url: string(),
|
|
19600
|
+
endpoints: array(string())
|
|
19601
|
+
});
|
|
19602
|
+
method(object({
|
|
19603
|
+
deviceId: number(),
|
|
19604
|
+
profile: string(),
|
|
19605
|
+
fromMs: number(),
|
|
19606
|
+
toMs: number(),
|
|
19607
|
+
options: ExportOptionsSchema
|
|
19608
|
+
}), ExportRecordSchema, {
|
|
19609
|
+
kind: "mutation",
|
|
19610
|
+
auth: "protected"
|
|
19611
|
+
}), method(object({ deviceId: number().optional() }), array(ExportRecordSchema), {
|
|
19612
|
+
kind: "query",
|
|
19613
|
+
auth: "protected"
|
|
19614
|
+
}), method(object({ exportId: string() }), ExportRecordSchema, {
|
|
19615
|
+
kind: "query",
|
|
19616
|
+
auth: "protected"
|
|
19617
|
+
}), method(object({ exportId: string() }), ExportRecordSchema, {
|
|
19618
|
+
kind: "mutation",
|
|
19619
|
+
auth: "protected"
|
|
19620
|
+
}), method(object({ exportId: string() }), ExportRecordSchema, {
|
|
19621
|
+
kind: "mutation",
|
|
19622
|
+
auth: "protected"
|
|
19623
|
+
}), method(object({ exportId: string() }), ExportDownloadSchema, {
|
|
19624
|
+
kind: "query",
|
|
19625
|
+
auth: "protected"
|
|
19626
|
+
});
|
|
19627
|
+
/**
|
|
19476
19628
|
* One publishable camera stream as its OWNING PROVIDER describes it — the same
|
|
19477
19629
|
* payload the (legacy) push `streamBroker.publishCameraStream` carried, minus
|
|
19478
19630
|
* `deviceId`.
|
|
@@ -23396,6 +23548,42 @@ Object.freeze({
|
|
|
23396
23548
|
addonId: null,
|
|
23397
23549
|
access: "create"
|
|
23398
23550
|
},
|
|
23551
|
+
"recordingExport.cancelExport": {
|
|
23552
|
+
capName: "recordingExport",
|
|
23553
|
+
capScope: "system",
|
|
23554
|
+
addonId: null,
|
|
23555
|
+
access: "create"
|
|
23556
|
+
},
|
|
23557
|
+
"recordingExport.createExport": {
|
|
23558
|
+
capName: "recordingExport",
|
|
23559
|
+
capScope: "system",
|
|
23560
|
+
addonId: null,
|
|
23561
|
+
access: "create"
|
|
23562
|
+
},
|
|
23563
|
+
"recordingExport.deleteExport": {
|
|
23564
|
+
capName: "recordingExport",
|
|
23565
|
+
capScope: "system",
|
|
23566
|
+
addonId: null,
|
|
23567
|
+
access: "delete"
|
|
23568
|
+
},
|
|
23569
|
+
"recordingExport.getDownloadUrl": {
|
|
23570
|
+
capName: "recordingExport",
|
|
23571
|
+
capScope: "system",
|
|
23572
|
+
addonId: null,
|
|
23573
|
+
access: "view"
|
|
23574
|
+
},
|
|
23575
|
+
"recordingExport.getExport": {
|
|
23576
|
+
capName: "recordingExport",
|
|
23577
|
+
capScope: "system",
|
|
23578
|
+
addonId: null,
|
|
23579
|
+
access: "view"
|
|
23580
|
+
},
|
|
23581
|
+
"recordingExport.listExports": {
|
|
23582
|
+
capName: "recordingExport",
|
|
23583
|
+
capScope: "system",
|
|
23584
|
+
addonId: null,
|
|
23585
|
+
access: "view"
|
|
23586
|
+
},
|
|
23399
23587
|
"sceneMonitor.captureReference": {
|
|
23400
23588
|
capName: "scene-monitor",
|
|
23401
23589
|
capScope: "device",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-export-hap",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.26",
|
|
4
4
|
"description": "HomeKit (HAP) bridge exporter for CamStack devices. Publishes a bridged accessory per exposed device — MotionSensor in this MVP; Camera/Doorbell/Switch/Light follow.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|