@camstack/addon-decoder-ffmpeg 1.1.15 → 1.1.17

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/index.js CHANGED
@@ -4,7 +4,7 @@ Object.defineProperties(exports, {
4
4
  });
5
5
  let node_crypto = require("node:crypto");
6
6
  let node_child_process = require("node:child_process");
7
- //#region ../types/dist/event-category-H4AVePnn.mjs
7
+ //#region ../types/dist/event-category-D4HJq7Mw.mjs
8
8
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
9
9
  EventCategory["SystemBoot"] = "system.boot";
10
10
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -157,6 +157,11 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
157
157
  /** Runner-sampled scrub thumbnail (~1/5 s/camera). Telemetry (D8): a lost
158
158
  * thumb is a scrub gap the recorder's keyframe backfill covers. */
159
159
  EventCategory["RecordingThumbSampled"] = "recording.thumb-sampled";
160
+ /** Export render progress (0–100). Telemetry (D8): a lost tick is a stale
161
+ * progress bar the client reconciles via `recordingExport.getExport`. */
162
+ EventCategory["RecordingExportProgress"] = "recording.export.progress";
163
+ EventCategory["RecordingExportCompleted"] = "recording.export.completed";
164
+ EventCategory["RecordingExportFailed"] = "recording.export.failed";
160
165
  EventCategory["DetectionEvent"] = "detection.event";
161
166
  EventCategory["SessionTrackNew"] = "session.track.new";
162
167
  EventCategory["SessionTrackExpired"] = "session.track.expired";
@@ -446,6 +451,25 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
446
451
  */
447
452
  EventCategory["PipelineAnalyticsStationaryChanged"] = "pipeline-analytics.stationary-changed";
448
453
  /**
454
+ * Fired by `addon-post-analysis` when a package-drop is confirmed inside
455
+ * a package zone — a newly-appeared stationary object of a package class
456
+ * that cleared the class / zone / dwell / size gates. Payload:
457
+ * `PipelineAnalyticsPackageDeliveredPayload` carrying `{ deviceId,
458
+ * entryId, className, zoneIds, keyFrameMediaKey?, bbox, timestamp }`.
459
+ * Telemetry (D8): the durable record is the `package-events` store row;
460
+ * this bus topic drives notifier rules + live UI. See
461
+ * docs/superpowers/specs/2026-07-17-package-zones-design.md §5.1.
462
+ */
463
+ EventCategory["PipelineAnalyticsPackageDelivered"] = "pipeline-analytics.package-delivered";
464
+ /**
465
+ * Fired by `addon-post-analysis` when a previously-delivered package
466
+ * leaves its zone (the stationary entry departed — moved or swept).
467
+ * Payload: `PipelineAnalyticsPackagePickedUpPayload` carrying
468
+ * `{ deviceId, entryId, deliveredEventId, className, timestamp }`.
469
+ * Telemetry (D8). See package-zones-design §5.2.
470
+ */
471
+ EventCategory["PipelineAnalyticsPackagePickedUp"] = "pipeline-analytics.package-picked-up";
472
+ /**
449
473
  * Fired by `addon-post-analysis` whenever a gallery face row changes:
450
474
  * `kind:'buffered'` a new detected face was persisted, `'assigned'` /
451
475
  * `'unassigned'` its identity link changed, `'deleted'` the row was
@@ -5184,6 +5208,25 @@ function _instanceof(cls, params = {}) {
5184
5208
  };
5185
5209
  return inst;
5186
5210
  }
5211
+ //#endregion
5212
+ //#region ../../node_modules/zod/v4/classic/compat.js
5213
+ /** @deprecated Use the raw string literal codes instead, e.g. "invalid_type". */
5214
+ var ZodIssueCode = {
5215
+ invalid_type: "invalid_type",
5216
+ too_big: "too_big",
5217
+ too_small: "too_small",
5218
+ invalid_format: "invalid_format",
5219
+ not_multiple_of: "not_multiple_of",
5220
+ unrecognized_keys: "unrecognized_keys",
5221
+ invalid_union: "invalid_union",
5222
+ invalid_key: "invalid_key",
5223
+ invalid_element: "invalid_element",
5224
+ invalid_value: "invalid_value",
5225
+ custom: "custom"
5226
+ };
5227
+ /** @deprecated Do not use. Stub definition, only included for zod-to-json-schema compatibility. */
5228
+ var ZodFirstPartyTypeKind;
5229
+ ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5187
5230
  Object.fromEntries([
5188
5231
  {
5189
5232
  id: "overview",
@@ -7238,6 +7281,24 @@ var RecordingRetentionSchema = object({
7238
7281
  maxSizeGb: number().min(0).optional()
7239
7282
  });
7240
7283
  /**
7284
+ * Scrub-thumbnail fidelity preset — the single per-camera selector bundling the
7285
+ * sprite tile RESOLUTION + JPEG QUALITY the recorder packs timeline-scrub
7286
+ * previews at. Five graduated steps; absent on a config = `standard` (the
7287
+ * shipped default, matching `sheet-geometry`/`sheet-composer`).
7288
+ *
7289
+ * Existing sheets are IMMUTABLE — a changed preset applies to NEW windows only.
7290
+ * Each window's index sidecar carries its own tile dims, so a camera whose
7291
+ * preset changed over time renders every historical window at the dims it was
7292
+ * written with.
7293
+ */
7294
+ var ScrubThumbnailPresetSchema = _enum([
7295
+ "minimal",
7296
+ "low",
7297
+ "standard",
7298
+ "high",
7299
+ "max"
7300
+ ]);
7301
+ /**
7241
7302
  * The full per-camera recording intent — the wire shape of a RecordingTarget.
7242
7303
  *
7243
7304
  * `mode` is the authoritative storage choice; `schedule`/`triggers`/`pre`/`post`
@@ -7274,7 +7335,14 @@ var RecordingConfigSchema = object({
7274
7335
  * derived into bands once via `migrateConfigToBands`.
7275
7336
  */
7276
7337
  bands: array(RecordingBandSchema).optional(),
7277
- retention: RecordingRetentionSchema.optional()
7338
+ retention: RecordingRetentionSchema.optional(),
7339
+ /**
7340
+ * Per-camera scrub-thumbnail fidelity preset (resolution + JPEG quality for
7341
+ * timeline-scrub sprite previews). Absent = `standard`. Applies to NEW
7342
+ * windows only — existing sheets are immutable, and each window's index
7343
+ * carries its own tile dims so mixed-preset history renders correctly.
7344
+ */
7345
+ scrubThumbnails: ScrubThumbnailPresetSchema.optional()
7278
7346
  });
7279
7347
  /**
7280
7348
  * `StorageLocationType` — an addon-declared id that identifies the *kind* of
@@ -12526,7 +12594,11 @@ array(ZoneRuleSchema).readonly();
12526
12594
  * Extend the enum here when a new gating consumer comes online (audio
12527
12595
  * gating, alert filtering, …) — no other surface needs to change.
12528
12596
  */
12529
- var ZoneRuleStageEnum = _enum(["motion", "detection"]);
12597
+ var ZoneRuleStageEnum = _enum([
12598
+ "motion",
12599
+ "detection",
12600
+ "package"
12601
+ ]);
12530
12602
  DeviceType.Camera, method(object({
12531
12603
  deviceId: number(),
12532
12604
  stage: ZoneRuleStageEnum
@@ -12539,7 +12611,8 @@ DeviceType.Camera, method(object({
12539
12611
  auth: "admin"
12540
12612
  }), object({
12541
12613
  motion: array(ZoneRuleSchema).readonly(),
12542
- detection: array(ZoneRuleSchema).readonly()
12614
+ detection: array(ZoneRuleSchema).readonly(),
12615
+ package: array(ZoneRuleSchema).readonly()
12543
12616
  });
12544
12617
  var ProviderStatusSchema = object({
12545
12618
  connected: boolean(),
@@ -15852,6 +15925,7 @@ var EventKindIconSchema = _enum([
15852
15925
  "smoke",
15853
15926
  "water",
15854
15927
  "button",
15928
+ "package",
15855
15929
  "generic"
15856
15930
  ]);
15857
15931
  var EventKindCategorySchema = _enum([
@@ -15859,7 +15933,8 @@ var EventKindCategorySchema = _enum([
15859
15933
  "audio",
15860
15934
  "detection",
15861
15935
  "sensor",
15862
- "custom"
15936
+ "custom",
15937
+ "package"
15863
15938
  ]);
15864
15939
  var EventKindDescriptorSchema = object({
15865
15940
  /** Stable kind id (e.g. 'motion', 'person', 'contact'). */
@@ -19505,6 +19580,108 @@ method(object({
19505
19580
  auth: "admin"
19506
19581
  });
19507
19582
  /**
19583
+ * `recordingExport` cap — render a footage time range into a single downloadable
19584
+ * MP4 (regular / accelerated / decelerated / timelapse, ± audio), kept for a
19585
+ * bounded lifetime with a durable history, auto-expiry, and optional
19586
+ * delete-after-download.
19587
+ *
19588
+ * Like `recording` this is a `scope:'system', mode:'singleton'` cap: the
19589
+ * recorder self-gates so exactly ONE node (the designated `recordingNodeId`,
19590
+ * default `hub`) registers it. Device-scoped methods carry `deviceId` in their
19591
+ * input and dispatch to that single provider; the render runs on the node that
19592
+ * owns the footage (no cross-node segment transfer). Download rides the
19593
+ * framework addon data-plane. State persists in a DurableState blob (NOT
19594
+ * SQLite); history rows survive file deletion for audit.
19595
+ */
19596
+ /** Playback-speed multiplier for the render (1 = realtime). */
19597
+ var ExportSpeedSchema = number().min(.25).max(32);
19598
+ /** Timelapse cadence — sample one source frame per `everyMs`, output at `outputFps`. */
19599
+ var ExportTimelapseSchema = object({
19600
+ everyMs: number().int().positive(),
19601
+ outputFps: number().int().min(1).max(60).optional()
19602
+ });
19603
+ /**
19604
+ * Render options. `speed` and `timelapse` are mutually exclusive. `includeAudio`
19605
+ * is honoured only for a realtime-ish speed (0.5–2×); timelapse is always
19606
+ * silent. `maxLifeMs` bounds how long the finished file is kept;
19607
+ * `deleteAfterDownload` removes it shortly after the first complete download.
19608
+ */
19609
+ var ExportOptionsSchema = object({
19610
+ speed: ExportSpeedSchema.optional(),
19611
+ timelapse: ExportTimelapseSchema.optional(),
19612
+ includeAudio: boolean(),
19613
+ maxLifeMs: number().int().positive(),
19614
+ deleteAfterDownload: boolean(),
19615
+ title: string().max(200).optional()
19616
+ }).superRefine((v, ctx) => {
19617
+ if (v.speed !== void 0 && v.timelapse !== void 0) ctx.addIssue({
19618
+ code: ZodIssueCode.custom,
19619
+ message: "speed and timelapse are mutually exclusive",
19620
+ path: ["timelapse"]
19621
+ });
19622
+ });
19623
+ var ExportStateSchema = _enum([
19624
+ "queued",
19625
+ "rendering",
19626
+ "ready",
19627
+ "failed",
19628
+ "expired",
19629
+ "deleted"
19630
+ ]);
19631
+ /** One export job / history row. */
19632
+ var ExportRecordSchema = object({
19633
+ id: string(),
19634
+ deviceId: number(),
19635
+ profile: string(),
19636
+ fromMs: number(),
19637
+ toMs: number(),
19638
+ options: ExportOptionsSchema,
19639
+ state: ExportStateSchema,
19640
+ /** 0–100 while rendering; null otherwise. */
19641
+ progressPct: number().nullable(),
19642
+ /** File size once ready; null before. */
19643
+ fileBytes: number().nullable(),
19644
+ expiresAt: number(),
19645
+ deleteAfterDownload: boolean(),
19646
+ /** Epoch of the first complete download; null until then. */
19647
+ downloadedAt: number().nullable(),
19648
+ createdAt: number(),
19649
+ /** User id/name that requested the export. */
19650
+ createdBy: string(),
19651
+ /** Failure reason when state is 'failed'; null otherwise. */
19652
+ error: string().nullable()
19653
+ });
19654
+ /** Candidate download URLs (LAN first, then operator extra hosts). */
19655
+ var ExportDownloadSchema = object({
19656
+ url: string(),
19657
+ endpoints: array(string())
19658
+ });
19659
+ method(object({
19660
+ deviceId: number(),
19661
+ profile: string(),
19662
+ fromMs: number(),
19663
+ toMs: number(),
19664
+ options: ExportOptionsSchema
19665
+ }), ExportRecordSchema, {
19666
+ kind: "mutation",
19667
+ auth: "protected"
19668
+ }), method(object({ deviceId: number().optional() }), array(ExportRecordSchema), {
19669
+ kind: "query",
19670
+ auth: "protected"
19671
+ }), method(object({ exportId: string() }), ExportRecordSchema, {
19672
+ kind: "query",
19673
+ auth: "protected"
19674
+ }), method(object({ exportId: string() }), ExportRecordSchema, {
19675
+ kind: "mutation",
19676
+ auth: "protected"
19677
+ }), method(object({ exportId: string() }), ExportRecordSchema, {
19678
+ kind: "mutation",
19679
+ auth: "protected"
19680
+ }), method(object({ exportId: string() }), ExportDownloadSchema, {
19681
+ kind: "query",
19682
+ auth: "protected"
19683
+ });
19684
+ /**
19508
19685
  * One publishable camera stream as its OWNING PROVIDER describes it — the same
19509
19686
  * payload the (legacy) push `streamBroker.publishCameraStream` carried, minus
19510
19687
  * `deviceId`.
@@ -23428,6 +23605,42 @@ Object.freeze({
23428
23605
  addonId: null,
23429
23606
  access: "create"
23430
23607
  },
23608
+ "recordingExport.cancelExport": {
23609
+ capName: "recordingExport",
23610
+ capScope: "system",
23611
+ addonId: null,
23612
+ access: "create"
23613
+ },
23614
+ "recordingExport.createExport": {
23615
+ capName: "recordingExport",
23616
+ capScope: "system",
23617
+ addonId: null,
23618
+ access: "create"
23619
+ },
23620
+ "recordingExport.deleteExport": {
23621
+ capName: "recordingExport",
23622
+ capScope: "system",
23623
+ addonId: null,
23624
+ access: "delete"
23625
+ },
23626
+ "recordingExport.getDownloadUrl": {
23627
+ capName: "recordingExport",
23628
+ capScope: "system",
23629
+ addonId: null,
23630
+ access: "view"
23631
+ },
23632
+ "recordingExport.getExport": {
23633
+ capName: "recordingExport",
23634
+ capScope: "system",
23635
+ addonId: null,
23636
+ access: "view"
23637
+ },
23638
+ "recordingExport.listExports": {
23639
+ capName: "recordingExport",
23640
+ capScope: "system",
23641
+ addonId: null,
23642
+ access: "view"
23643
+ },
23431
23644
  "sceneMonitor.captureReference": {
23432
23645
  capName: "scene-monitor",
23433
23646
  capScope: "device",
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import { spawn } from "node:child_process";
3
- //#region ../types/dist/event-category-H4AVePnn.mjs
3
+ //#region ../types/dist/event-category-D4HJq7Mw.mjs
4
4
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
5
5
  EventCategory["SystemBoot"] = "system.boot";
6
6
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -153,6 +153,11 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
153
153
  /** Runner-sampled scrub thumbnail (~1/5 s/camera). Telemetry (D8): a lost
154
154
  * thumb is a scrub gap the recorder's keyframe backfill covers. */
155
155
  EventCategory["RecordingThumbSampled"] = "recording.thumb-sampled";
156
+ /** Export render progress (0–100). Telemetry (D8): a lost tick is a stale
157
+ * progress bar the client reconciles via `recordingExport.getExport`. */
158
+ EventCategory["RecordingExportProgress"] = "recording.export.progress";
159
+ EventCategory["RecordingExportCompleted"] = "recording.export.completed";
160
+ EventCategory["RecordingExportFailed"] = "recording.export.failed";
156
161
  EventCategory["DetectionEvent"] = "detection.event";
157
162
  EventCategory["SessionTrackNew"] = "session.track.new";
158
163
  EventCategory["SessionTrackExpired"] = "session.track.expired";
@@ -442,6 +447,25 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
442
447
  */
443
448
  EventCategory["PipelineAnalyticsStationaryChanged"] = "pipeline-analytics.stationary-changed";
444
449
  /**
450
+ * Fired by `addon-post-analysis` when a package-drop is confirmed inside
451
+ * a package zone — a newly-appeared stationary object of a package class
452
+ * that cleared the class / zone / dwell / size gates. Payload:
453
+ * `PipelineAnalyticsPackageDeliveredPayload` carrying `{ deviceId,
454
+ * entryId, className, zoneIds, keyFrameMediaKey?, bbox, timestamp }`.
455
+ * Telemetry (D8): the durable record is the `package-events` store row;
456
+ * this bus topic drives notifier rules + live UI. See
457
+ * docs/superpowers/specs/2026-07-17-package-zones-design.md §5.1.
458
+ */
459
+ EventCategory["PipelineAnalyticsPackageDelivered"] = "pipeline-analytics.package-delivered";
460
+ /**
461
+ * Fired by `addon-post-analysis` when a previously-delivered package
462
+ * leaves its zone (the stationary entry departed — moved or swept).
463
+ * Payload: `PipelineAnalyticsPackagePickedUpPayload` carrying
464
+ * `{ deviceId, entryId, deliveredEventId, className, timestamp }`.
465
+ * Telemetry (D8). See package-zones-design §5.2.
466
+ */
467
+ EventCategory["PipelineAnalyticsPackagePickedUp"] = "pipeline-analytics.package-picked-up";
468
+ /**
445
469
  * Fired by `addon-post-analysis` whenever a gallery face row changes:
446
470
  * `kind:'buffered'` a new detected face was persisted, `'assigned'` /
447
471
  * `'unassigned'` its identity link changed, `'deleted'` the row was
@@ -5180,6 +5204,25 @@ function _instanceof(cls, params = {}) {
5180
5204
  };
5181
5205
  return inst;
5182
5206
  }
5207
+ //#endregion
5208
+ //#region ../../node_modules/zod/v4/classic/compat.js
5209
+ /** @deprecated Use the raw string literal codes instead, e.g. "invalid_type". */
5210
+ var ZodIssueCode = {
5211
+ invalid_type: "invalid_type",
5212
+ too_big: "too_big",
5213
+ too_small: "too_small",
5214
+ invalid_format: "invalid_format",
5215
+ not_multiple_of: "not_multiple_of",
5216
+ unrecognized_keys: "unrecognized_keys",
5217
+ invalid_union: "invalid_union",
5218
+ invalid_key: "invalid_key",
5219
+ invalid_element: "invalid_element",
5220
+ invalid_value: "invalid_value",
5221
+ custom: "custom"
5222
+ };
5223
+ /** @deprecated Do not use. Stub definition, only included for zod-to-json-schema compatibility. */
5224
+ var ZodFirstPartyTypeKind;
5225
+ ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5183
5226
  Object.fromEntries([
5184
5227
  {
5185
5228
  id: "overview",
@@ -7234,6 +7277,24 @@ var RecordingRetentionSchema = object({
7234
7277
  maxSizeGb: number().min(0).optional()
7235
7278
  });
7236
7279
  /**
7280
+ * Scrub-thumbnail fidelity preset — the single per-camera selector bundling the
7281
+ * sprite tile RESOLUTION + JPEG QUALITY the recorder packs timeline-scrub
7282
+ * previews at. Five graduated steps; absent on a config = `standard` (the
7283
+ * shipped default, matching `sheet-geometry`/`sheet-composer`).
7284
+ *
7285
+ * Existing sheets are IMMUTABLE — a changed preset applies to NEW windows only.
7286
+ * Each window's index sidecar carries its own tile dims, so a camera whose
7287
+ * preset changed over time renders every historical window at the dims it was
7288
+ * written with.
7289
+ */
7290
+ var ScrubThumbnailPresetSchema = _enum([
7291
+ "minimal",
7292
+ "low",
7293
+ "standard",
7294
+ "high",
7295
+ "max"
7296
+ ]);
7297
+ /**
7237
7298
  * The full per-camera recording intent — the wire shape of a RecordingTarget.
7238
7299
  *
7239
7300
  * `mode` is the authoritative storage choice; `schedule`/`triggers`/`pre`/`post`
@@ -7270,7 +7331,14 @@ var RecordingConfigSchema = object({
7270
7331
  * derived into bands once via `migrateConfigToBands`.
7271
7332
  */
7272
7333
  bands: array(RecordingBandSchema).optional(),
7273
- retention: RecordingRetentionSchema.optional()
7334
+ retention: RecordingRetentionSchema.optional(),
7335
+ /**
7336
+ * Per-camera scrub-thumbnail fidelity preset (resolution + JPEG quality for
7337
+ * timeline-scrub sprite previews). Absent = `standard`. Applies to NEW
7338
+ * windows only — existing sheets are immutable, and each window's index
7339
+ * carries its own tile dims so mixed-preset history renders correctly.
7340
+ */
7341
+ scrubThumbnails: ScrubThumbnailPresetSchema.optional()
7274
7342
  });
7275
7343
  /**
7276
7344
  * `StorageLocationType` — an addon-declared id that identifies the *kind* of
@@ -12522,7 +12590,11 @@ array(ZoneRuleSchema).readonly();
12522
12590
  * Extend the enum here when a new gating consumer comes online (audio
12523
12591
  * gating, alert filtering, …) — no other surface needs to change.
12524
12592
  */
12525
- var ZoneRuleStageEnum = _enum(["motion", "detection"]);
12593
+ var ZoneRuleStageEnum = _enum([
12594
+ "motion",
12595
+ "detection",
12596
+ "package"
12597
+ ]);
12526
12598
  DeviceType.Camera, method(object({
12527
12599
  deviceId: number(),
12528
12600
  stage: ZoneRuleStageEnum
@@ -12535,7 +12607,8 @@ DeviceType.Camera, method(object({
12535
12607
  auth: "admin"
12536
12608
  }), object({
12537
12609
  motion: array(ZoneRuleSchema).readonly(),
12538
- detection: array(ZoneRuleSchema).readonly()
12610
+ detection: array(ZoneRuleSchema).readonly(),
12611
+ package: array(ZoneRuleSchema).readonly()
12539
12612
  });
12540
12613
  var ProviderStatusSchema = object({
12541
12614
  connected: boolean(),
@@ -15848,6 +15921,7 @@ var EventKindIconSchema = _enum([
15848
15921
  "smoke",
15849
15922
  "water",
15850
15923
  "button",
15924
+ "package",
15851
15925
  "generic"
15852
15926
  ]);
15853
15927
  var EventKindCategorySchema = _enum([
@@ -15855,7 +15929,8 @@ var EventKindCategorySchema = _enum([
15855
15929
  "audio",
15856
15930
  "detection",
15857
15931
  "sensor",
15858
- "custom"
15932
+ "custom",
15933
+ "package"
15859
15934
  ]);
15860
15935
  var EventKindDescriptorSchema = object({
15861
15936
  /** Stable kind id (e.g. 'motion', 'person', 'contact'). */
@@ -19501,6 +19576,108 @@ method(object({
19501
19576
  auth: "admin"
19502
19577
  });
19503
19578
  /**
19579
+ * `recordingExport` cap — render a footage time range into a single downloadable
19580
+ * MP4 (regular / accelerated / decelerated / timelapse, ± audio), kept for a
19581
+ * bounded lifetime with a durable history, auto-expiry, and optional
19582
+ * delete-after-download.
19583
+ *
19584
+ * Like `recording` this is a `scope:'system', mode:'singleton'` cap: the
19585
+ * recorder self-gates so exactly ONE node (the designated `recordingNodeId`,
19586
+ * default `hub`) registers it. Device-scoped methods carry `deviceId` in their
19587
+ * input and dispatch to that single provider; the render runs on the node that
19588
+ * owns the footage (no cross-node segment transfer). Download rides the
19589
+ * framework addon data-plane. State persists in a DurableState blob (NOT
19590
+ * SQLite); history rows survive file deletion for audit.
19591
+ */
19592
+ /** Playback-speed multiplier for the render (1 = realtime). */
19593
+ var ExportSpeedSchema = number().min(.25).max(32);
19594
+ /** Timelapse cadence — sample one source frame per `everyMs`, output at `outputFps`. */
19595
+ var ExportTimelapseSchema = object({
19596
+ everyMs: number().int().positive(),
19597
+ outputFps: number().int().min(1).max(60).optional()
19598
+ });
19599
+ /**
19600
+ * Render options. `speed` and `timelapse` are mutually exclusive. `includeAudio`
19601
+ * is honoured only for a realtime-ish speed (0.5–2×); timelapse is always
19602
+ * silent. `maxLifeMs` bounds how long the finished file is kept;
19603
+ * `deleteAfterDownload` removes it shortly after the first complete download.
19604
+ */
19605
+ var ExportOptionsSchema = object({
19606
+ speed: ExportSpeedSchema.optional(),
19607
+ timelapse: ExportTimelapseSchema.optional(),
19608
+ includeAudio: boolean(),
19609
+ maxLifeMs: number().int().positive(),
19610
+ deleteAfterDownload: boolean(),
19611
+ title: string().max(200).optional()
19612
+ }).superRefine((v, ctx) => {
19613
+ if (v.speed !== void 0 && v.timelapse !== void 0) ctx.addIssue({
19614
+ code: ZodIssueCode.custom,
19615
+ message: "speed and timelapse are mutually exclusive",
19616
+ path: ["timelapse"]
19617
+ });
19618
+ });
19619
+ var ExportStateSchema = _enum([
19620
+ "queued",
19621
+ "rendering",
19622
+ "ready",
19623
+ "failed",
19624
+ "expired",
19625
+ "deleted"
19626
+ ]);
19627
+ /** One export job / history row. */
19628
+ var ExportRecordSchema = object({
19629
+ id: string(),
19630
+ deviceId: number(),
19631
+ profile: string(),
19632
+ fromMs: number(),
19633
+ toMs: number(),
19634
+ options: ExportOptionsSchema,
19635
+ state: ExportStateSchema,
19636
+ /** 0–100 while rendering; null otherwise. */
19637
+ progressPct: number().nullable(),
19638
+ /** File size once ready; null before. */
19639
+ fileBytes: number().nullable(),
19640
+ expiresAt: number(),
19641
+ deleteAfterDownload: boolean(),
19642
+ /** Epoch of the first complete download; null until then. */
19643
+ downloadedAt: number().nullable(),
19644
+ createdAt: number(),
19645
+ /** User id/name that requested the export. */
19646
+ createdBy: string(),
19647
+ /** Failure reason when state is 'failed'; null otherwise. */
19648
+ error: string().nullable()
19649
+ });
19650
+ /** Candidate download URLs (LAN first, then operator extra hosts). */
19651
+ var ExportDownloadSchema = object({
19652
+ url: string(),
19653
+ endpoints: array(string())
19654
+ });
19655
+ method(object({
19656
+ deviceId: number(),
19657
+ profile: string(),
19658
+ fromMs: number(),
19659
+ toMs: number(),
19660
+ options: ExportOptionsSchema
19661
+ }), ExportRecordSchema, {
19662
+ kind: "mutation",
19663
+ auth: "protected"
19664
+ }), method(object({ deviceId: number().optional() }), array(ExportRecordSchema), {
19665
+ kind: "query",
19666
+ auth: "protected"
19667
+ }), method(object({ exportId: string() }), ExportRecordSchema, {
19668
+ kind: "query",
19669
+ auth: "protected"
19670
+ }), method(object({ exportId: string() }), ExportRecordSchema, {
19671
+ kind: "mutation",
19672
+ auth: "protected"
19673
+ }), method(object({ exportId: string() }), ExportRecordSchema, {
19674
+ kind: "mutation",
19675
+ auth: "protected"
19676
+ }), method(object({ exportId: string() }), ExportDownloadSchema, {
19677
+ kind: "query",
19678
+ auth: "protected"
19679
+ });
19680
+ /**
19504
19681
  * One publishable camera stream as its OWNING PROVIDER describes it — the same
19505
19682
  * payload the (legacy) push `streamBroker.publishCameraStream` carried, minus
19506
19683
  * `deviceId`.
@@ -23424,6 +23601,42 @@ Object.freeze({
23424
23601
  addonId: null,
23425
23602
  access: "create"
23426
23603
  },
23604
+ "recordingExport.cancelExport": {
23605
+ capName: "recordingExport",
23606
+ capScope: "system",
23607
+ addonId: null,
23608
+ access: "create"
23609
+ },
23610
+ "recordingExport.createExport": {
23611
+ capName: "recordingExport",
23612
+ capScope: "system",
23613
+ addonId: null,
23614
+ access: "create"
23615
+ },
23616
+ "recordingExport.deleteExport": {
23617
+ capName: "recordingExport",
23618
+ capScope: "system",
23619
+ addonId: null,
23620
+ access: "delete"
23621
+ },
23622
+ "recordingExport.getDownloadUrl": {
23623
+ capName: "recordingExport",
23624
+ capScope: "system",
23625
+ addonId: null,
23626
+ access: "view"
23627
+ },
23628
+ "recordingExport.getExport": {
23629
+ capName: "recordingExport",
23630
+ capScope: "system",
23631
+ addonId: null,
23632
+ access: "view"
23633
+ },
23634
+ "recordingExport.listExports": {
23635
+ capName: "recordingExport",
23636
+ capScope: "system",
23637
+ addonId: null,
23638
+ access: "view"
23639
+ },
23427
23640
  "sceneMonitor.captureReference": {
23428
23641
  capName: "scene-monitor",
23429
23642
  capScope: "device",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-decoder-ffmpeg",
3
- "version": "1.1.15",
3
+ "version": "1.1.17",
4
4
  "description": "Standalone ffmpeg-subprocess decoder fallback addon for CamStack",
5
5
  "keywords": [
6
6
  "camstack",