@camstack/addon-smtp-nodemailer 1.1.23 → 1.1.25

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.
@@ -36,7 +36,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
36
36
  }) : target, mod));
37
37
  var __toCommonJS = (mod) => __hasOwnProp.call(mod, "module.exports") ? mod["module.exports"] : __copyProps(__defProp({}, "__esModule", { value: true }), mod);
38
38
  //#endregion
39
- //#region ../types/dist/event-category-H4AVePnn.mjs
39
+ //#region ../types/dist/event-category-D4HJq7Mw.mjs
40
40
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
41
41
  EventCategory["SystemBoot"] = "system.boot";
42
42
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -189,6 +189,11 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
189
189
  /** Runner-sampled scrub thumbnail (~1/5 s/camera). Telemetry (D8): a lost
190
190
  * thumb is a scrub gap the recorder's keyframe backfill covers. */
191
191
  EventCategory["RecordingThumbSampled"] = "recording.thumb-sampled";
192
+ /** Export render progress (0–100). Telemetry (D8): a lost tick is a stale
193
+ * progress bar the client reconciles via `recordingExport.getExport`. */
194
+ EventCategory["RecordingExportProgress"] = "recording.export.progress";
195
+ EventCategory["RecordingExportCompleted"] = "recording.export.completed";
196
+ EventCategory["RecordingExportFailed"] = "recording.export.failed";
192
197
  EventCategory["DetectionEvent"] = "detection.event";
193
198
  EventCategory["SessionTrackNew"] = "session.track.new";
194
199
  EventCategory["SessionTrackExpired"] = "session.track.expired";
@@ -478,6 +483,25 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
478
483
  */
479
484
  EventCategory["PipelineAnalyticsStationaryChanged"] = "pipeline-analytics.stationary-changed";
480
485
  /**
486
+ * Fired by `addon-post-analysis` when a package-drop is confirmed inside
487
+ * a package zone — a newly-appeared stationary object of a package class
488
+ * that cleared the class / zone / dwell / size gates. Payload:
489
+ * `PipelineAnalyticsPackageDeliveredPayload` carrying `{ deviceId,
490
+ * entryId, className, zoneIds, keyFrameMediaKey?, bbox, timestamp }`.
491
+ * Telemetry (D8): the durable record is the `package-events` store row;
492
+ * this bus topic drives notifier rules + live UI. See
493
+ * docs/superpowers/specs/2026-07-17-package-zones-design.md §5.1.
494
+ */
495
+ EventCategory["PipelineAnalyticsPackageDelivered"] = "pipeline-analytics.package-delivered";
496
+ /**
497
+ * Fired by `addon-post-analysis` when a previously-delivered package
498
+ * leaves its zone (the stationary entry departed — moved or swept).
499
+ * Payload: `PipelineAnalyticsPackagePickedUpPayload` carrying
500
+ * `{ deviceId, entryId, deliveredEventId, className, timestamp }`.
501
+ * Telemetry (D8). See package-zones-design §5.2.
502
+ */
503
+ EventCategory["PipelineAnalyticsPackagePickedUp"] = "pipeline-analytics.package-picked-up";
504
+ /**
481
505
  * Fired by `addon-post-analysis` whenever a gallery face row changes:
482
506
  * `kind:'buffered'` a new detected face was persisted, `'assigned'` /
483
507
  * `'unassigned'` its identity link changed, `'deleted'` the row was
@@ -5216,6 +5240,25 @@ function _instanceof(cls, params = {}) {
5216
5240
  };
5217
5241
  return inst;
5218
5242
  }
5243
+ //#endregion
5244
+ //#region ../../node_modules/zod/v4/classic/compat.js
5245
+ /** @deprecated Use the raw string literal codes instead, e.g. "invalid_type". */
5246
+ var ZodIssueCode = {
5247
+ invalid_type: "invalid_type",
5248
+ too_big: "too_big",
5249
+ too_small: "too_small",
5250
+ invalid_format: "invalid_format",
5251
+ not_multiple_of: "not_multiple_of",
5252
+ unrecognized_keys: "unrecognized_keys",
5253
+ invalid_union: "invalid_union",
5254
+ invalid_key: "invalid_key",
5255
+ invalid_element: "invalid_element",
5256
+ invalid_value: "invalid_value",
5257
+ custom: "custom"
5258
+ };
5259
+ /** @deprecated Do not use. Stub definition, only included for zod-to-json-schema compatibility. */
5260
+ var ZodFirstPartyTypeKind;
5261
+ ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5219
5262
  Object.fromEntries([
5220
5263
  {
5221
5264
  id: "overview",
@@ -7258,6 +7301,24 @@ var RecordingRetentionSchema = object({
7258
7301
  maxSizeGb: number().min(0).optional()
7259
7302
  });
7260
7303
  /**
7304
+ * Scrub-thumbnail fidelity preset — the single per-camera selector bundling the
7305
+ * sprite tile RESOLUTION + JPEG QUALITY the recorder packs timeline-scrub
7306
+ * previews at. Five graduated steps; absent on a config = `standard` (the
7307
+ * shipped default, matching `sheet-geometry`/`sheet-composer`).
7308
+ *
7309
+ * Existing sheets are IMMUTABLE — a changed preset applies to NEW windows only.
7310
+ * Each window's index sidecar carries its own tile dims, so a camera whose
7311
+ * preset changed over time renders every historical window at the dims it was
7312
+ * written with.
7313
+ */
7314
+ var ScrubThumbnailPresetSchema = _enum([
7315
+ "minimal",
7316
+ "low",
7317
+ "standard",
7318
+ "high",
7319
+ "max"
7320
+ ]);
7321
+ /**
7261
7322
  * The full per-camera recording intent — the wire shape of a RecordingTarget.
7262
7323
  *
7263
7324
  * `mode` is the authoritative storage choice; `schedule`/`triggers`/`pre`/`post`
@@ -7294,7 +7355,14 @@ var RecordingConfigSchema = object({
7294
7355
  * derived into bands once via `migrateConfigToBands`.
7295
7356
  */
7296
7357
  bands: array(RecordingBandSchema).optional(),
7297
- retention: RecordingRetentionSchema.optional()
7358
+ retention: RecordingRetentionSchema.optional(),
7359
+ /**
7360
+ * Per-camera scrub-thumbnail fidelity preset (resolution + JPEG quality for
7361
+ * timeline-scrub sprite previews). Absent = `standard`. Applies to NEW
7362
+ * windows only — existing sheets are immutable, and each window's index
7363
+ * carries its own tile dims so mixed-preset history renders correctly.
7364
+ */
7365
+ scrubThumbnails: ScrubThumbnailPresetSchema.optional()
7298
7366
  });
7299
7367
  /**
7300
7368
  * `StorageLocationType` — an addon-declared id that identifies the *kind* of
@@ -12546,7 +12614,11 @@ array(ZoneRuleSchema).readonly();
12546
12614
  * Extend the enum here when a new gating consumer comes online (audio
12547
12615
  * gating, alert filtering, …) — no other surface needs to change.
12548
12616
  */
12549
- var ZoneRuleStageEnum = _enum(["motion", "detection"]);
12617
+ var ZoneRuleStageEnum = _enum([
12618
+ "motion",
12619
+ "detection",
12620
+ "package"
12621
+ ]);
12550
12622
  DeviceType.Camera, method(object({
12551
12623
  deviceId: number(),
12552
12624
  stage: ZoneRuleStageEnum
@@ -12559,7 +12631,8 @@ DeviceType.Camera, method(object({
12559
12631
  auth: "admin"
12560
12632
  }), object({
12561
12633
  motion: array(ZoneRuleSchema).readonly(),
12562
- detection: array(ZoneRuleSchema).readonly()
12634
+ detection: array(ZoneRuleSchema).readonly(),
12635
+ package: array(ZoneRuleSchema).readonly()
12563
12636
  });
12564
12637
  var ProviderStatusSchema = object({
12565
12638
  connected: boolean(),
@@ -15742,6 +15815,7 @@ var EventKindIconSchema = _enum([
15742
15815
  "smoke",
15743
15816
  "water",
15744
15817
  "button",
15818
+ "package",
15745
15819
  "generic"
15746
15820
  ]);
15747
15821
  var EventKindCategorySchema = _enum([
@@ -15749,7 +15823,8 @@ var EventKindCategorySchema = _enum([
15749
15823
  "audio",
15750
15824
  "detection",
15751
15825
  "sensor",
15752
- "custom"
15826
+ "custom",
15827
+ "package"
15753
15828
  ]);
15754
15829
  var EventKindDescriptorSchema = object({
15755
15830
  /** Stable kind id (e.g. 'motion', 'person', 'contact'). */
@@ -19408,6 +19483,108 @@ method(object({
19408
19483
  auth: "admin"
19409
19484
  });
19410
19485
  /**
19486
+ * `recordingExport` cap — render a footage time range into a single downloadable
19487
+ * MP4 (regular / accelerated / decelerated / timelapse, ± audio), kept for a
19488
+ * bounded lifetime with a durable history, auto-expiry, and optional
19489
+ * delete-after-download.
19490
+ *
19491
+ * Like `recording` this is a `scope:'system', mode:'singleton'` cap: the
19492
+ * recorder self-gates so exactly ONE node (the designated `recordingNodeId`,
19493
+ * default `hub`) registers it. Device-scoped methods carry `deviceId` in their
19494
+ * input and dispatch to that single provider; the render runs on the node that
19495
+ * owns the footage (no cross-node segment transfer). Download rides the
19496
+ * framework addon data-plane. State persists in a DurableState blob (NOT
19497
+ * SQLite); history rows survive file deletion for audit.
19498
+ */
19499
+ /** Playback-speed multiplier for the render (1 = realtime). */
19500
+ var ExportSpeedSchema = number().min(.25).max(32);
19501
+ /** Timelapse cadence — sample one source frame per `everyMs`, output at `outputFps`. */
19502
+ var ExportTimelapseSchema = object({
19503
+ everyMs: number().int().positive(),
19504
+ outputFps: number().int().min(1).max(60).optional()
19505
+ });
19506
+ /**
19507
+ * Render options. `speed` and `timelapse` are mutually exclusive. `includeAudio`
19508
+ * is honoured only for a realtime-ish speed (0.5–2×); timelapse is always
19509
+ * silent. `maxLifeMs` bounds how long the finished file is kept;
19510
+ * `deleteAfterDownload` removes it shortly after the first complete download.
19511
+ */
19512
+ var ExportOptionsSchema = object({
19513
+ speed: ExportSpeedSchema.optional(),
19514
+ timelapse: ExportTimelapseSchema.optional(),
19515
+ includeAudio: boolean(),
19516
+ maxLifeMs: number().int().positive(),
19517
+ deleteAfterDownload: boolean(),
19518
+ title: string().max(200).optional()
19519
+ }).superRefine((v, ctx) => {
19520
+ if (v.speed !== void 0 && v.timelapse !== void 0) ctx.addIssue({
19521
+ code: ZodIssueCode.custom,
19522
+ message: "speed and timelapse are mutually exclusive",
19523
+ path: ["timelapse"]
19524
+ });
19525
+ });
19526
+ var ExportStateSchema = _enum([
19527
+ "queued",
19528
+ "rendering",
19529
+ "ready",
19530
+ "failed",
19531
+ "expired",
19532
+ "deleted"
19533
+ ]);
19534
+ /** One export job / history row. */
19535
+ var ExportRecordSchema = object({
19536
+ id: string(),
19537
+ deviceId: number(),
19538
+ profile: string(),
19539
+ fromMs: number(),
19540
+ toMs: number(),
19541
+ options: ExportOptionsSchema,
19542
+ state: ExportStateSchema,
19543
+ /** 0–100 while rendering; null otherwise. */
19544
+ progressPct: number().nullable(),
19545
+ /** File size once ready; null before. */
19546
+ fileBytes: number().nullable(),
19547
+ expiresAt: number(),
19548
+ deleteAfterDownload: boolean(),
19549
+ /** Epoch of the first complete download; null until then. */
19550
+ downloadedAt: number().nullable(),
19551
+ createdAt: number(),
19552
+ /** User id/name that requested the export. */
19553
+ createdBy: string(),
19554
+ /** Failure reason when state is 'failed'; null otherwise. */
19555
+ error: string().nullable()
19556
+ });
19557
+ /** Candidate download URLs (LAN first, then operator extra hosts). */
19558
+ var ExportDownloadSchema = object({
19559
+ url: string(),
19560
+ endpoints: array(string())
19561
+ });
19562
+ method(object({
19563
+ deviceId: number(),
19564
+ profile: string(),
19565
+ fromMs: number(),
19566
+ toMs: number(),
19567
+ options: ExportOptionsSchema
19568
+ }), ExportRecordSchema, {
19569
+ kind: "mutation",
19570
+ auth: "protected"
19571
+ }), method(object({ deviceId: number().optional() }), array(ExportRecordSchema), {
19572
+ kind: "query",
19573
+ auth: "protected"
19574
+ }), method(object({ exportId: string() }), ExportRecordSchema, {
19575
+ kind: "query",
19576
+ auth: "protected"
19577
+ }), method(object({ exportId: string() }), ExportRecordSchema, {
19578
+ kind: "mutation",
19579
+ auth: "protected"
19580
+ }), method(object({ exportId: string() }), ExportRecordSchema, {
19581
+ kind: "mutation",
19582
+ auth: "protected"
19583
+ }), method(object({ exportId: string() }), ExportDownloadSchema, {
19584
+ kind: "query",
19585
+ auth: "protected"
19586
+ });
19587
+ /**
19411
19588
  * One publishable camera stream as its OWNING PROVIDER describes it — the same
19412
19589
  * payload the (legacy) push `streamBroker.publishCameraStream` carried, minus
19413
19590
  * `deviceId`.
@@ -23331,6 +23508,42 @@ Object.freeze({
23331
23508
  addonId: null,
23332
23509
  access: "create"
23333
23510
  },
23511
+ "recordingExport.cancelExport": {
23512
+ capName: "recordingExport",
23513
+ capScope: "system",
23514
+ addonId: null,
23515
+ access: "create"
23516
+ },
23517
+ "recordingExport.createExport": {
23518
+ capName: "recordingExport",
23519
+ capScope: "system",
23520
+ addonId: null,
23521
+ access: "create"
23522
+ },
23523
+ "recordingExport.deleteExport": {
23524
+ capName: "recordingExport",
23525
+ capScope: "system",
23526
+ addonId: null,
23527
+ access: "delete"
23528
+ },
23529
+ "recordingExport.getDownloadUrl": {
23530
+ capName: "recordingExport",
23531
+ capScope: "system",
23532
+ addonId: null,
23533
+ access: "view"
23534
+ },
23535
+ "recordingExport.getExport": {
23536
+ capName: "recordingExport",
23537
+ capScope: "system",
23538
+ addonId: null,
23539
+ access: "view"
23540
+ },
23541
+ "recordingExport.listExports": {
23542
+ capName: "recordingExport",
23543
+ capScope: "system",
23544
+ addonId: null,
23545
+ access: "view"
23546
+ },
23334
23547
  "sceneMonitor.captureReference": {
23335
23548
  capName: "scene-monitor",
23336
23549
  capScope: "device",
@@ -34,7 +34,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
34
34
  var __toCommonJS = (mod) => __hasOwnProp.call(mod, "module.exports") ? mod["module.exports"] : __copyProps(__defProp({}, "__esModule", { value: true }), mod);
35
35
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
36
36
  //#endregion
37
- //#region ../types/dist/event-category-H4AVePnn.mjs
37
+ //#region ../types/dist/event-category-D4HJq7Mw.mjs
38
38
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
39
39
  EventCategory["SystemBoot"] = "system.boot";
40
40
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -187,6 +187,11 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
187
187
  /** Runner-sampled scrub thumbnail (~1/5 s/camera). Telemetry (D8): a lost
188
188
  * thumb is a scrub gap the recorder's keyframe backfill covers. */
189
189
  EventCategory["RecordingThumbSampled"] = "recording.thumb-sampled";
190
+ /** Export render progress (0–100). Telemetry (D8): a lost tick is a stale
191
+ * progress bar the client reconciles via `recordingExport.getExport`. */
192
+ EventCategory["RecordingExportProgress"] = "recording.export.progress";
193
+ EventCategory["RecordingExportCompleted"] = "recording.export.completed";
194
+ EventCategory["RecordingExportFailed"] = "recording.export.failed";
190
195
  EventCategory["DetectionEvent"] = "detection.event";
191
196
  EventCategory["SessionTrackNew"] = "session.track.new";
192
197
  EventCategory["SessionTrackExpired"] = "session.track.expired";
@@ -476,6 +481,25 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
476
481
  */
477
482
  EventCategory["PipelineAnalyticsStationaryChanged"] = "pipeline-analytics.stationary-changed";
478
483
  /**
484
+ * Fired by `addon-post-analysis` when a package-drop is confirmed inside
485
+ * a package zone — a newly-appeared stationary object of a package class
486
+ * that cleared the class / zone / dwell / size gates. Payload:
487
+ * `PipelineAnalyticsPackageDeliveredPayload` carrying `{ deviceId,
488
+ * entryId, className, zoneIds, keyFrameMediaKey?, bbox, timestamp }`.
489
+ * Telemetry (D8): the durable record is the `package-events` store row;
490
+ * this bus topic drives notifier rules + live UI. See
491
+ * docs/superpowers/specs/2026-07-17-package-zones-design.md §5.1.
492
+ */
493
+ EventCategory["PipelineAnalyticsPackageDelivered"] = "pipeline-analytics.package-delivered";
494
+ /**
495
+ * Fired by `addon-post-analysis` when a previously-delivered package
496
+ * leaves its zone (the stationary entry departed — moved or swept).
497
+ * Payload: `PipelineAnalyticsPackagePickedUpPayload` carrying
498
+ * `{ deviceId, entryId, deliveredEventId, className, timestamp }`.
499
+ * Telemetry (D8). See package-zones-design §5.2.
500
+ */
501
+ EventCategory["PipelineAnalyticsPackagePickedUp"] = "pipeline-analytics.package-picked-up";
502
+ /**
479
503
  * Fired by `addon-post-analysis` whenever a gallery face row changes:
480
504
  * `kind:'buffered'` a new detected face was persisted, `'assigned'` /
481
505
  * `'unassigned'` its identity link changed, `'deleted'` the row was
@@ -5214,6 +5238,25 @@ function _instanceof(cls, params = {}) {
5214
5238
  };
5215
5239
  return inst;
5216
5240
  }
5241
+ //#endregion
5242
+ //#region ../../node_modules/zod/v4/classic/compat.js
5243
+ /** @deprecated Use the raw string literal codes instead, e.g. "invalid_type". */
5244
+ var ZodIssueCode = {
5245
+ invalid_type: "invalid_type",
5246
+ too_big: "too_big",
5247
+ too_small: "too_small",
5248
+ invalid_format: "invalid_format",
5249
+ not_multiple_of: "not_multiple_of",
5250
+ unrecognized_keys: "unrecognized_keys",
5251
+ invalid_union: "invalid_union",
5252
+ invalid_key: "invalid_key",
5253
+ invalid_element: "invalid_element",
5254
+ invalid_value: "invalid_value",
5255
+ custom: "custom"
5256
+ };
5257
+ /** @deprecated Do not use. Stub definition, only included for zod-to-json-schema compatibility. */
5258
+ var ZodFirstPartyTypeKind;
5259
+ ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5217
5260
  Object.fromEntries([
5218
5261
  {
5219
5262
  id: "overview",
@@ -7256,6 +7299,24 @@ var RecordingRetentionSchema = object({
7256
7299
  maxSizeGb: number().min(0).optional()
7257
7300
  });
7258
7301
  /**
7302
+ * Scrub-thumbnail fidelity preset — the single per-camera selector bundling the
7303
+ * sprite tile RESOLUTION + JPEG QUALITY the recorder packs timeline-scrub
7304
+ * previews at. Five graduated steps; absent on a config = `standard` (the
7305
+ * shipped default, matching `sheet-geometry`/`sheet-composer`).
7306
+ *
7307
+ * Existing sheets are IMMUTABLE — a changed preset applies to NEW windows only.
7308
+ * Each window's index sidecar carries its own tile dims, so a camera whose
7309
+ * preset changed over time renders every historical window at the dims it was
7310
+ * written with.
7311
+ */
7312
+ var ScrubThumbnailPresetSchema = _enum([
7313
+ "minimal",
7314
+ "low",
7315
+ "standard",
7316
+ "high",
7317
+ "max"
7318
+ ]);
7319
+ /**
7259
7320
  * The full per-camera recording intent — the wire shape of a RecordingTarget.
7260
7321
  *
7261
7322
  * `mode` is the authoritative storage choice; `schedule`/`triggers`/`pre`/`post`
@@ -7292,7 +7353,14 @@ var RecordingConfigSchema = object({
7292
7353
  * derived into bands once via `migrateConfigToBands`.
7293
7354
  */
7294
7355
  bands: array(RecordingBandSchema).optional(),
7295
- retention: RecordingRetentionSchema.optional()
7356
+ retention: RecordingRetentionSchema.optional(),
7357
+ /**
7358
+ * Per-camera scrub-thumbnail fidelity preset (resolution + JPEG quality for
7359
+ * timeline-scrub sprite previews). Absent = `standard`. Applies to NEW
7360
+ * windows only — existing sheets are immutable, and each window's index
7361
+ * carries its own tile dims so mixed-preset history renders correctly.
7362
+ */
7363
+ scrubThumbnails: ScrubThumbnailPresetSchema.optional()
7296
7364
  });
7297
7365
  /**
7298
7366
  * `StorageLocationType` — an addon-declared id that identifies the *kind* of
@@ -12544,7 +12612,11 @@ array(ZoneRuleSchema).readonly();
12544
12612
  * Extend the enum here when a new gating consumer comes online (audio
12545
12613
  * gating, alert filtering, …) — no other surface needs to change.
12546
12614
  */
12547
- var ZoneRuleStageEnum = _enum(["motion", "detection"]);
12615
+ var ZoneRuleStageEnum = _enum([
12616
+ "motion",
12617
+ "detection",
12618
+ "package"
12619
+ ]);
12548
12620
  DeviceType.Camera, method(object({
12549
12621
  deviceId: number(),
12550
12622
  stage: ZoneRuleStageEnum
@@ -12557,7 +12629,8 @@ DeviceType.Camera, method(object({
12557
12629
  auth: "admin"
12558
12630
  }), object({
12559
12631
  motion: array(ZoneRuleSchema).readonly(),
12560
- detection: array(ZoneRuleSchema).readonly()
12632
+ detection: array(ZoneRuleSchema).readonly(),
12633
+ package: array(ZoneRuleSchema).readonly()
12561
12634
  });
12562
12635
  var ProviderStatusSchema = object({
12563
12636
  connected: boolean(),
@@ -15740,6 +15813,7 @@ var EventKindIconSchema = _enum([
15740
15813
  "smoke",
15741
15814
  "water",
15742
15815
  "button",
15816
+ "package",
15743
15817
  "generic"
15744
15818
  ]);
15745
15819
  var EventKindCategorySchema = _enum([
@@ -15747,7 +15821,8 @@ var EventKindCategorySchema = _enum([
15747
15821
  "audio",
15748
15822
  "detection",
15749
15823
  "sensor",
15750
- "custom"
15824
+ "custom",
15825
+ "package"
15751
15826
  ]);
15752
15827
  var EventKindDescriptorSchema = object({
15753
15828
  /** Stable kind id (e.g. 'motion', 'person', 'contact'). */
@@ -19406,6 +19481,108 @@ method(object({
19406
19481
  auth: "admin"
19407
19482
  });
19408
19483
  /**
19484
+ * `recordingExport` cap — render a footage time range into a single downloadable
19485
+ * MP4 (regular / accelerated / decelerated / timelapse, ± audio), kept for a
19486
+ * bounded lifetime with a durable history, auto-expiry, and optional
19487
+ * delete-after-download.
19488
+ *
19489
+ * Like `recording` this is a `scope:'system', mode:'singleton'` cap: the
19490
+ * recorder self-gates so exactly ONE node (the designated `recordingNodeId`,
19491
+ * default `hub`) registers it. Device-scoped methods carry `deviceId` in their
19492
+ * input and dispatch to that single provider; the render runs on the node that
19493
+ * owns the footage (no cross-node segment transfer). Download rides the
19494
+ * framework addon data-plane. State persists in a DurableState blob (NOT
19495
+ * SQLite); history rows survive file deletion for audit.
19496
+ */
19497
+ /** Playback-speed multiplier for the render (1 = realtime). */
19498
+ var ExportSpeedSchema = number().min(.25).max(32);
19499
+ /** Timelapse cadence — sample one source frame per `everyMs`, output at `outputFps`. */
19500
+ var ExportTimelapseSchema = object({
19501
+ everyMs: number().int().positive(),
19502
+ outputFps: number().int().min(1).max(60).optional()
19503
+ });
19504
+ /**
19505
+ * Render options. `speed` and `timelapse` are mutually exclusive. `includeAudio`
19506
+ * is honoured only for a realtime-ish speed (0.5–2×); timelapse is always
19507
+ * silent. `maxLifeMs` bounds how long the finished file is kept;
19508
+ * `deleteAfterDownload` removes it shortly after the first complete download.
19509
+ */
19510
+ var ExportOptionsSchema = object({
19511
+ speed: ExportSpeedSchema.optional(),
19512
+ timelapse: ExportTimelapseSchema.optional(),
19513
+ includeAudio: boolean(),
19514
+ maxLifeMs: number().int().positive(),
19515
+ deleteAfterDownload: boolean(),
19516
+ title: string().max(200).optional()
19517
+ }).superRefine((v, ctx) => {
19518
+ if (v.speed !== void 0 && v.timelapse !== void 0) ctx.addIssue({
19519
+ code: ZodIssueCode.custom,
19520
+ message: "speed and timelapse are mutually exclusive",
19521
+ path: ["timelapse"]
19522
+ });
19523
+ });
19524
+ var ExportStateSchema = _enum([
19525
+ "queued",
19526
+ "rendering",
19527
+ "ready",
19528
+ "failed",
19529
+ "expired",
19530
+ "deleted"
19531
+ ]);
19532
+ /** One export job / history row. */
19533
+ var ExportRecordSchema = object({
19534
+ id: string(),
19535
+ deviceId: number(),
19536
+ profile: string(),
19537
+ fromMs: number(),
19538
+ toMs: number(),
19539
+ options: ExportOptionsSchema,
19540
+ state: ExportStateSchema,
19541
+ /** 0–100 while rendering; null otherwise. */
19542
+ progressPct: number().nullable(),
19543
+ /** File size once ready; null before. */
19544
+ fileBytes: number().nullable(),
19545
+ expiresAt: number(),
19546
+ deleteAfterDownload: boolean(),
19547
+ /** Epoch of the first complete download; null until then. */
19548
+ downloadedAt: number().nullable(),
19549
+ createdAt: number(),
19550
+ /** User id/name that requested the export. */
19551
+ createdBy: string(),
19552
+ /** Failure reason when state is 'failed'; null otherwise. */
19553
+ error: string().nullable()
19554
+ });
19555
+ /** Candidate download URLs (LAN first, then operator extra hosts). */
19556
+ var ExportDownloadSchema = object({
19557
+ url: string(),
19558
+ endpoints: array(string())
19559
+ });
19560
+ method(object({
19561
+ deviceId: number(),
19562
+ profile: string(),
19563
+ fromMs: number(),
19564
+ toMs: number(),
19565
+ options: ExportOptionsSchema
19566
+ }), ExportRecordSchema, {
19567
+ kind: "mutation",
19568
+ auth: "protected"
19569
+ }), method(object({ deviceId: number().optional() }), array(ExportRecordSchema), {
19570
+ kind: "query",
19571
+ auth: "protected"
19572
+ }), method(object({ exportId: string() }), ExportRecordSchema, {
19573
+ kind: "query",
19574
+ auth: "protected"
19575
+ }), method(object({ exportId: string() }), ExportRecordSchema, {
19576
+ kind: "mutation",
19577
+ auth: "protected"
19578
+ }), method(object({ exportId: string() }), ExportRecordSchema, {
19579
+ kind: "mutation",
19580
+ auth: "protected"
19581
+ }), method(object({ exportId: string() }), ExportDownloadSchema, {
19582
+ kind: "query",
19583
+ auth: "protected"
19584
+ });
19585
+ /**
19409
19586
  * One publishable camera stream as its OWNING PROVIDER describes it — the same
19410
19587
  * payload the (legacy) push `streamBroker.publishCameraStream` carried, minus
19411
19588
  * `deviceId`.
@@ -23329,6 +23506,42 @@ Object.freeze({
23329
23506
  addonId: null,
23330
23507
  access: "create"
23331
23508
  },
23509
+ "recordingExport.cancelExport": {
23510
+ capName: "recordingExport",
23511
+ capScope: "system",
23512
+ addonId: null,
23513
+ access: "create"
23514
+ },
23515
+ "recordingExport.createExport": {
23516
+ capName: "recordingExport",
23517
+ capScope: "system",
23518
+ addonId: null,
23519
+ access: "create"
23520
+ },
23521
+ "recordingExport.deleteExport": {
23522
+ capName: "recordingExport",
23523
+ capScope: "system",
23524
+ addonId: null,
23525
+ access: "delete"
23526
+ },
23527
+ "recordingExport.getDownloadUrl": {
23528
+ capName: "recordingExport",
23529
+ capScope: "system",
23530
+ addonId: null,
23531
+ access: "view"
23532
+ },
23533
+ "recordingExport.getExport": {
23534
+ capName: "recordingExport",
23535
+ capScope: "system",
23536
+ addonId: null,
23537
+ access: "view"
23538
+ },
23539
+ "recordingExport.listExports": {
23540
+ capName: "recordingExport",
23541
+ capScope: "system",
23542
+ addonId: null,
23543
+ access: "view"
23544
+ },
23332
23545
  "sceneMonitor.captureReference": {
23333
23546
  capName: "scene-monitor",
23334
23547
  capScope: "device",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-smtp-nodemailer",
3
- "version": "1.1.23",
3
+ "version": "1.1.25",
4
4
  "description": "SMTP email provider addon for CamStack — wraps `nodemailer` and registers a `smtp-provider` cap collection entry. Used by magic-link login + notifier addons.",
5
5
  "keywords": [
6
6
  "camstack",