@camstack/addon-smtp-nodemailer 1.2.24 → 1.2.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.
@@ -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-XfKNtfCc.mjs
39
+ //#region ../types/dist/event-category-CIa_iT6b.mjs
40
40
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
41
41
  EventCategory["SystemBoot"] = "system.boot";
42
42
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -52,6 +52,15 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
52
52
  */
53
53
  EventCategory["SystemRestartCompleted"] = "system.restart-completed";
54
54
  /**
55
+ * The hub reissued its own TLS certificate at boot (`ensureTlsCert`).
56
+ * Emitted only when the material on disk actually changed, so an
57
+ * operator who trusted the old certificate by hand is told rather than
58
+ * discovering it as a browser error. Payload `TlsCertChangedPayload`.
59
+ *
60
+ * Rule: docs/decisions/adr-0227-*.md
61
+ */
62
+ EventCategory["SystemTlsCertChanged"] = "system.tls-cert-changed";
63
+ /**
55
64
  * A newer addon or server-root package version was found by the
56
65
  * authoritative registry check. Emitted once when any observed
57
66
  * `latestVersion` changes (or a package/node first appears behind);
@@ -8032,6 +8041,15 @@ var LabelDefinitionSchema = object({
8032
8041
  description: string().optional(),
8033
8042
  icon: string().optional()
8034
8043
  });
8044
+ var ClassMapDefinitionSchema = object({
8045
+ mapping: record(string(), _enum([
8046
+ "person",
8047
+ "vehicle",
8048
+ "animal",
8049
+ "package"
8050
+ ])),
8051
+ preserveOriginal: boolean()
8052
+ });
8035
8053
  var MODEL_FORMATS = [
8036
8054
  "onnx",
8037
8055
  "coreml",
@@ -8210,7 +8228,13 @@ var ModelCatalogEntrySchema = object({
8210
8228
  * `id` stays the source of truth for resolution/download/persistence; grouping
8211
8229
  * is a presentation overlay resolved back to an `id`.
8212
8230
  */
8213
- group: ModelVariantGroupSchema.optional()
8231
+ group: ModelVariantGroupSchema.optional(),
8232
+ /**
8233
+ * Per-MODEL class map override. Absent ⇒ the step's `StepDefinition.classMap`
8234
+ * applies (Frigate / COCO public catalog). Set on a custom model whose raw
8235
+ * labels already ARE the CamStack macros (Scrypted identity map).
8236
+ */
8237
+ classMap: ClassMapDefinitionSchema.optional()
8214
8238
  });
8215
8239
  var ConvertTargetSchema = discriminatedUnion("format", [object({
8216
8240
  format: literal("openvino"),
@@ -8239,7 +8263,8 @@ var ModelConvertMetadataSchema = object({
8239
8263
  "ocr",
8240
8264
  "segmentation"
8241
8265
  ]),
8242
- faceAlignment: boolean().optional()
8266
+ faceAlignment: boolean().optional(),
8267
+ classMap: ClassMapDefinitionSchema.optional()
8243
8268
  });
8244
8269
  var ConvertResultSchema = object({
8245
8270
  entry: ModelCatalogEntrySchema,
@@ -17230,6 +17255,33 @@ var NativeCropRefSchema = object({
17230
17255
  h: number()
17231
17256
  })
17232
17257
  });
17258
+ object({
17259
+ crop: object({
17260
+ left: number(),
17261
+ top: number(),
17262
+ width: number().positive(),
17263
+ height: number().positive()
17264
+ }).optional(),
17265
+ content: object({
17266
+ width: number().int().positive(),
17267
+ height: number().int().positive()
17268
+ }),
17269
+ fit: _enum(["stretch", "contain"]),
17270
+ format: _enum([
17271
+ "rgb",
17272
+ "gray",
17273
+ "jpeg"
17274
+ ])
17275
+ });
17276
+ var FrameRefSchema = object({
17277
+ registryId: string().min(1),
17278
+ id: string().min(1),
17279
+ width: number().int().positive(),
17280
+ height: number().int().positive(),
17281
+ format: _enum(["rgb", "gray"]),
17282
+ timestamp: number(),
17283
+ capturedAt: number().optional()
17284
+ });
17233
17285
  var ModelFormatSchema$1 = _enum([
17234
17286
  "onnx",
17235
17287
  "coreml",
@@ -17474,6 +17526,12 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
17474
17526
  steps: array(PipelineStepInputSchema).min(1),
17475
17527
  frame: FrameInputSchema.optional(),
17476
17528
  /**
17529
+ * Process-local lazy frame. Valid only when caller and provider resolve
17530
+ * in the same execution-group process; split/cross-node callers use
17531
+ * `frame`/`image` inline compatibility instead.
17532
+ */
17533
+ frameRef: FrameRefSchema.optional(),
17534
+ /**
17477
17535
  * CB5 shm passthrough — a `FrameHandle` naming the same ring slot
17478
17536
  * the decoded pixels live in. One more member of the one-of
17479
17537
  * frame/frameHandle/image/imageBase64/referenceImage group.
@@ -17729,7 +17787,10 @@ var NativeCropResultSchema = object({
17729
17787
  * Which source served this crop, so a quality-sensitive consumer (the native
17730
17788
  * `keyFrame`) can reject a degraded fallback:
17731
17789
  * - `native` — cut from the decode worker's retained NATIVE surface (the
17732
- * quality path).
17790
+ * quality path). A subject-tile serve is also native-resolution and stays
17791
+ * `native` here: the public enum cannot name `tile` without a breaking cap
17792
+ * change. Runner telemetry distinguishes lease vs tile via `source` on the
17793
+ * internal crop result (`nativeHits` vs `tileHits`).
17733
17794
  * - `ram-fullframe` — the native surface MISSED but the request was full-frame,
17734
17795
  * so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
17735
17796
  * the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
@@ -18220,12 +18281,41 @@ var RunnerLocalLoadSchema = object({
18220
18281
  * legacy `OrchestratorMetricsSchema` shape so existing dashboards keep
18221
18282
  * working unchanged when they switch to reading from the runner cap.
18222
18283
  */
18284
+ var FrameLazyCountersSchema = object({
18285
+ framesDecoded: number(),
18286
+ framesAdmitted: number(),
18287
+ framesDroppedPixelFree: number(),
18288
+ viewsMaterialized: number(),
18289
+ viewsSkipped: number(),
18290
+ workerToRunnerBytes: number(),
18291
+ runnerToPoolRawBytes: number(),
18292
+ runnerToPoolJpegBytes: number(),
18293
+ onDemandFullFrameRequests: number(),
18294
+ onDemandCropRequests: number(),
18295
+ nativeHits: number(),
18296
+ nativeMisses: number(),
18297
+ tileHits: number(),
18298
+ tileMisses: number(),
18299
+ fallbackHits: number(),
18300
+ fallbackMisses: number(),
18301
+ retainedWritesAvoided: number(),
18302
+ residentRefs: number(),
18303
+ residentBytes: number(),
18304
+ releases: number(),
18305
+ evictions: number(),
18306
+ staleMisses: number()
18307
+ });
18308
+ var FrameLazyMetricsSchema = object({
18309
+ node: FrameLazyCountersSchema,
18310
+ cameras: array(FrameLazyCountersSchema.extend({ deviceId: number() }))
18311
+ });
18223
18312
  var RunnerLocalMetricsSchema = object({
18224
18313
  nodeId: string(),
18225
18314
  activeCameras: number(),
18226
18315
  throttledCameras: number(),
18227
18316
  avgInferenceTimeMs: number(),
18228
- queueDepth: number()
18317
+ queueDepth: number(),
18318
+ frameLazy: FrameLazyMetricsSchema.optional()
18229
18319
  });
18230
18320
  method(RunnerCameraConfigSchema, object({ success: literal(true) }), { kind: "mutation" }), method(object({ deviceId: number() }), object({ success: literal(true) }), { kind: "mutation" }), method(ReportMotionInputSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), RunnerLocalLoadSchema), method(_void(), RunnerLocalMetricsSchema), method(object({ deviceId: number() }), CameraMetricsSchema.nullable()), method(_void(), array(CameraMetricsWithDeviceIdSchema).readonly()), method(_void(), array(number()).readonly()), method(object({
18231
18321
  handle: FrameHandleSchema,
@@ -19538,6 +19628,9 @@ method(_void(), ProviderInfoSchema), method(object({ config: record(string(), un
19538
19628
  location: StorageLocationSchema,
19539
19629
  relativePath: string()
19540
19630
  }), _void(), { kind: "mutation" }), method(object({ location: StorageLocationSchema }), number().nullable()), method(BeginUploadInputSchema, BeginUploadResultSchema, { kind: "mutation" }), method(WriteChunkInputSchema, _void(), { kind: "mutation" }), method(FinalizeUploadInputSchema, _void(), { kind: "mutation" }), method(AbortUploadInputSchema, _void(), { kind: "mutation" }), method(BeginDownloadInputSchema, BeginDownloadResultSchema, { kind: "mutation" }), method(ReadChunkInputSchema, _instanceof(Uint8Array)), method(EndDownloadInputSchema, _void(), { kind: "mutation" });
19631
+ /** Profile-exported FormBuilder schema. Shape is ConfigUISchema at the UI. */
19632
+ var ProfileSettingsSchemaBridge = unknown().nullable();
19633
+ var ProfileSettingsBagSchema = record(string(), unknown());
19541
19634
  /**
19542
19635
  * A live terminal session hosted by the provider addon. Output and input do
19543
19636
  * NOT flow through the capability — they use the addon data plane
@@ -19567,7 +19660,14 @@ var TerminalSessionInfoSchema = object({
19567
19660
  var TerminalProfileInfoSchema = object({
19568
19661
  profileId: string(),
19569
19662
  label: string(),
19570
- description: string().optional()
19663
+ description: string().optional(),
19664
+ /** Spawn defaults the instance form copies on create. */
19665
+ executable: string().optional(),
19666
+ args: array(string()).readonly().optional(),
19667
+ cwd: string().optional(),
19668
+ environment: array(string()).readonly().optional(),
19669
+ /** ConfigUISchema for instance knobs, or null when the profile has none. */
19670
+ settingsSchema: ProfileSettingsSchemaBridge.optional()
19571
19671
  });
19572
19672
  /**
19573
19673
  * A durable operator-created Terminal instance. Profiles are templates; only
@@ -19580,7 +19680,12 @@ var TerminalInstanceInfoSchema = object({
19580
19680
  profileId: string(),
19581
19681
  profileLabel: string(),
19582
19682
  name: string(),
19583
- enabled: boolean()
19683
+ enabled: boolean(),
19684
+ executable: string(),
19685
+ args: array(string()).readonly(),
19686
+ cwd: string(),
19687
+ environment: array(string()).readonly(),
19688
+ profileSettings: ProfileSettingsBagSchema
19584
19689
  });
19585
19690
  var TerminalLegacyCameraSchema = object({
19586
19691
  stableId: string(),
@@ -19610,7 +19715,23 @@ var TerminalOutputBatchSchema = object({
19610
19715
  method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }), method(_void(), array(TerminalInstanceInfoSchema).readonly(), { auth: "admin" }), method(object({
19611
19716
  targetNodeId: string().min(1),
19612
19717
  profileId: string().min(1),
19613
- name: string().trim().min(1).max(160).optional()
19718
+ name: string().trim().min(1).max(160).optional(),
19719
+ executable: string().max(1024).optional(),
19720
+ args: array(string().max(2048)).max(64).optional(),
19721
+ cwd: string().max(1024).optional(),
19722
+ environment: array(string().max(4096)).max(64).optional(),
19723
+ profileSettings: ProfileSettingsBagSchema.optional()
19724
+ }), TerminalInstanceInfoSchema, {
19725
+ kind: "mutation",
19726
+ auth: "admin"
19727
+ }), method(object({
19728
+ instanceId: string().min(1),
19729
+ name: string().trim().min(1).max(160).optional(),
19730
+ executable: string().max(1024).optional(),
19731
+ args: array(string().max(2048)).max(64).optional(),
19732
+ cwd: string().max(1024).optional(),
19733
+ environment: array(string().max(4096)).max(64).optional(),
19734
+ profileSettings: ProfileSettingsBagSchema.optional()
19614
19735
  }), TerminalInstanceInfoSchema, {
19615
19736
  kind: "mutation",
19616
19737
  auth: "admin"
@@ -19632,7 +19753,11 @@ method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }),
19632
19753
  }), method(_void(), array(TerminalSessionInfoSchema).readonly(), { auth: "admin" }), method(object({
19633
19754
  profileId: string(),
19634
19755
  cols: number().int().positive(),
19635
- rows: number().int().positive()
19756
+ rows: number().int().positive(),
19757
+ executable: string().max(1024).optional(),
19758
+ args: array(string().max(2048)).max(64).optional(),
19759
+ cwd: string().max(1024).optional(),
19760
+ environment: array(string().max(4096)).max(64).optional()
19636
19761
  }), TerminalSessionInfoSchema, {
19637
19762
  kind: "mutation",
19638
19763
  auth: "admin"
@@ -22414,10 +22539,10 @@ DeviceType.LawnMower, method(object({ deviceId: number().int().nonnegative() }),
22414
22539
  *
22415
22540
  * • The SDK (mobile / web client) consumes `getConnectionEndpoints()`
22416
22541
  * to receive an ordered list of candidate base URLs it should race
22417
- * on connect — LAN IPv4 first (lowest latency when on same network),
22418
- * then public hostname (if a tunnel is up), then IPv6. The SDK can
22419
- * race them with short timeouts and stick with the winner for the
22420
- * session.
22542
+ * on connect — LAN IPv4 and stable LAN IPv6 first (lowest latency
22543
+ * when on the same network), then public hostname (if a tunnel is
22544
+ * up). The SDK can race them with short timeouts and stick with the
22545
+ * winner for the session.
22421
22546
  *
22422
22547
  * Why hub-only: agents are not directly addressable by the operator's
22423
22548
  * clients — they reverse-connect to the hub. Exposing their interfaces
@@ -22572,6 +22697,17 @@ var NotificationEndpointSchema = object({
22572
22697
  /** What the ranking currently resolves to (null when nothing is reachable). */
22573
22698
  resolved: string().nullable()
22574
22699
  });
22700
+ /**
22701
+ * The URLs the SDK / viewer should race for API access. `baseUrls` empty =
22702
+ * AUTO (every LAN IPv4 + the public tunnel). `resolved` is what that choice
22703
+ * currently expands to, so the UI can show the effective set either way.
22704
+ */
22705
+ var ViewerEndpointsSchema = object({
22706
+ /** The operator's explicit race set, or empty for AUTO. */
22707
+ baseUrls: array(string()).readonly(),
22708
+ /** What the ranking currently resolves to (may be empty if nothing is up). */
22709
+ resolved: array(string()).readonly()
22710
+ });
22575
22711
  var AllowedAddressesSchema = object({
22576
22712
  /**
22577
22713
  * Allowlist of interface addresses operators have explicitly opted
@@ -22580,6 +22716,20 @@ var AllowedAddressesSchema = object({
22580
22716
  * Network Addresses admin page and persisted by the addon.
22581
22717
  */
22582
22718
  addresses: array(string()).readonly() });
22719
+ var TlsStatusSchema = object({
22720
+ mode: _enum([
22721
+ "generated",
22722
+ "uploaded",
22723
+ "disabled"
22724
+ ]),
22725
+ leafFingerprintSha256: string().nullable(),
22726
+ caFingerprintSha256: string().nullable(),
22727
+ validTo: string().nullable(),
22728
+ sans: array(string()),
22729
+ caCertPem: string().nullable(),
22730
+ reissueError: string().nullable(),
22731
+ restartRequired: boolean()
22732
+ });
22583
22733
  method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(object({
22584
22734
  /**
22585
22735
  * LEGACY HINT — do not send from new code. Kept optional so clients
@@ -22589,17 +22739,31 @@ method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(obje
22589
22739
  */
22590
22740
  port: number().int().min(1).max(65535).optional(),
22591
22741
  /** Include `http(s)://127.0.0.1:<port>` as the lowest-priority
22592
- * candidate. Default `true`. */
22742
+ * candidate. Default `false` — loopback is not a client route. */
22593
22743
  includeLoopback: boolean().optional(),
22594
- /** Skip IPv6 entries. Some legacy clients can't parse them.
22595
- * Default `false`. */
22744
+ /** Skip IPv6 entries. Default `false` the palette includes stable
22745
+ * LAN IPv6 (ICE/WebRTC uses dual-stack regardless). Pass `true` to
22746
+ * hide them. The viewer HTTP/WS race is `getViewerEndpoints`. */
22596
22747
  ipv4Only: boolean().optional(),
22597
22748
  /** Scheme to emit for LAN/loopback URLs. Default `'http'`.
22598
22749
  * Pass `'https'` when the caller is itself loaded over HTTPS
22599
22750
  * to avoid mixed-content blocks in the browser. The public
22600
22751
  * tunnel always emits `https://` regardless. */
22601
22752
  scheme: _enum(["http", "https"]).optional()
22602
- }), GetConnectionEndpointsResultSchema), method(_void(), NotificationEndpointSchema), method(object({ baseUrl: string().nullable() }), NotificationEndpointSchema, { kind: "mutation" }), method(_void(), AllowedAddressesSchema), method(AllowedAddressesSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), AllowedAddressesSchema, { kind: "mutation" });
22753
+ }), GetConnectionEndpointsResultSchema), method(_void(), NotificationEndpointSchema), method(object({ baseUrl: string().nullable() }), NotificationEndpointSchema, { kind: "mutation" }), method(_void(), ViewerEndpointsSchema), method(object({ baseUrls: array(string()).readonly() }), ViewerEndpointsSchema, { kind: "mutation" }), method(_void(), AllowedAddressesSchema), method(AllowedAddressesSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), AllowedAddressesSchema, { kind: "mutation" }), method(_void(), TlsStatusSchema), method(object({ reason: string().optional() }), TlsStatusSchema, {
22754
+ kind: "mutation",
22755
+ auth: "admin"
22756
+ }), method(object({
22757
+ certPem: string().min(1),
22758
+ keyPem: string().min(1),
22759
+ caPem: string().optional()
22760
+ }), TlsStatusSchema, {
22761
+ kind: "mutation",
22762
+ auth: "admin"
22763
+ }), method(_void(), object({ pem: string() })), method(_void(), TlsStatusSchema, {
22764
+ kind: "mutation",
22765
+ auth: "admin"
22766
+ });
22603
22767
  object({
22604
22768
  /** Lifecycle state of the lock. `jammed` means the motor reported
22605
22769
  * failure to reach the target — operator intervention required. */
@@ -28362,6 +28526,12 @@ Object.freeze({
28362
28526
  addonId: null,
28363
28527
  access: "create"
28364
28528
  },
28529
+ "localNetwork.downloadCa": {
28530
+ capName: "local-network",
28531
+ capScope: "system",
28532
+ addonId: null,
28533
+ access: "view"
28534
+ },
28365
28535
  "localNetwork.getAllowedAddresses": {
28366
28536
  capName: "local-network",
28367
28537
  capScope: "system",
@@ -28386,18 +28556,42 @@ Object.freeze({
28386
28556
  addonId: null,
28387
28557
  access: "view"
28388
28558
  },
28559
+ "localNetwork.getTlsStatus": {
28560
+ capName: "local-network",
28561
+ capScope: "system",
28562
+ addonId: null,
28563
+ access: "view"
28564
+ },
28565
+ "localNetwork.getViewerEndpoints": {
28566
+ capName: "local-network",
28567
+ capScope: "system",
28568
+ addonId: null,
28569
+ access: "view"
28570
+ },
28389
28571
  "localNetwork.list": {
28390
28572
  capName: "local-network",
28391
28573
  capScope: "system",
28392
28574
  addonId: null,
28393
28575
  access: "view"
28394
28576
  },
28577
+ "localNetwork.regenerateCertificate": {
28578
+ capName: "local-network",
28579
+ capScope: "system",
28580
+ addonId: null,
28581
+ access: "create"
28582
+ },
28395
28583
  "localNetwork.resetAllowlistToBestMatch": {
28396
28584
  capName: "local-network",
28397
28585
  capScope: "system",
28398
28586
  addonId: null,
28399
28587
  access: "delete"
28400
28588
  },
28589
+ "localNetwork.revertToGeneratedCertificate": {
28590
+ capName: "local-network",
28591
+ capScope: "system",
28592
+ addonId: null,
28593
+ access: "create"
28594
+ },
28401
28595
  "localNetwork.setAllowedAddresses": {
28402
28596
  capName: "local-network",
28403
28597
  capScope: "system",
@@ -28410,6 +28604,18 @@ Object.freeze({
28410
28604
  addonId: null,
28411
28605
  access: "create"
28412
28606
  },
28607
+ "localNetwork.setViewerEndpoints": {
28608
+ capName: "local-network",
28609
+ capScope: "system",
28610
+ addonId: null,
28611
+ access: "create"
28612
+ },
28613
+ "localNetwork.uploadCertificate": {
28614
+ capName: "local-network",
28615
+ capScope: "system",
28616
+ addonId: null,
28617
+ access: "create"
28618
+ },
28413
28619
  "lockControl.lock": {
28414
28620
  capName: "lock-control",
28415
28621
  capScope: "device",
@@ -31290,6 +31496,12 @@ Object.freeze({
31290
31496
  addonId: null,
31291
31497
  access: "create"
31292
31498
  },
31499
+ "terminalSession.updateInstance": {
31500
+ capName: "terminal-session",
31501
+ capScope: "system",
31502
+ addonId: null,
31503
+ access: "create"
31504
+ },
31293
31505
  "terminalSession.writeInput": {
31294
31506
  capName: "terminal-session",
31295
31507
  capScope: "system",
@@ -33777,6 +33989,35 @@ Object.freeze(Object.fromEntries([{
33777
33989
  }]
33778
33990
  }].map((s) => [s.stepId, s.defaultModelId])));
33779
33991
  string().min(1);
33992
+ var CLUSTER_STEP_SETTING_FIELDS = [{
33993
+ stepId: "face-embedding",
33994
+ key: "minLandmarkFaceSize",
33995
+ label: "Min face size for recognition (detection px)",
33996
+ description: "Refuse to embed a face smaller than this IN THE DETECTION FRAME. Applies to every node — the enrolled gallery is one index, and two admission floors would fill it from two policies. 0 disables the gate.",
33997
+ type: "slider",
33998
+ min: 0,
33999
+ max: 64,
34000
+ step: 2,
34001
+ default: 24
34002
+ }];
34003
+ function clusterStepSettingKey(stepId, fieldKey) {
34004
+ return `clusterStepSetting:${stepId}:${fieldKey}`;
34005
+ }
34006
+ var ClusterSettingNumberSchema = number().finite();
34007
+ function readClusterStepSettings(config) {
34008
+ const out = {};
34009
+ for (const field of CLUSTER_STEP_SETTING_FIELDS) {
34010
+ const parsed = ClusterSettingNumberSchema.safeParse(config[clusterStepSettingKey(field.stepId, field.key)]);
34011
+ const value = parsed.success ? parsed.data : field.default;
34012
+ const existing = out[field.stepId] ?? {};
34013
+ out[field.stepId] = {
34014
+ ...existing,
34015
+ [field.key]: value
34016
+ };
34017
+ }
34018
+ return out;
34019
+ }
34020
+ readClusterStepSettings({});
33780
34021
  object({
33781
34022
  /**
33782
34023
  * Fraction of the box's own size added on EACH side before cutting.
@@ -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-XfKNtfCc.mjs
37
+ //#region ../types/dist/event-category-CIa_iT6b.mjs
38
38
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
39
39
  EventCategory["SystemBoot"] = "system.boot";
40
40
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -50,6 +50,15 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
50
50
  */
51
51
  EventCategory["SystemRestartCompleted"] = "system.restart-completed";
52
52
  /**
53
+ * The hub reissued its own TLS certificate at boot (`ensureTlsCert`).
54
+ * Emitted only when the material on disk actually changed, so an
55
+ * operator who trusted the old certificate by hand is told rather than
56
+ * discovering it as a browser error. Payload `TlsCertChangedPayload`.
57
+ *
58
+ * Rule: docs/decisions/adr-0227-*.md
59
+ */
60
+ EventCategory["SystemTlsCertChanged"] = "system.tls-cert-changed";
61
+ /**
53
62
  * A newer addon or server-root package version was found by the
54
63
  * authoritative registry check. Emitted once when any observed
55
64
  * `latestVersion` changes (or a package/node first appears behind);
@@ -8030,6 +8039,15 @@ var LabelDefinitionSchema = object({
8030
8039
  description: string().optional(),
8031
8040
  icon: string().optional()
8032
8041
  });
8042
+ var ClassMapDefinitionSchema = object({
8043
+ mapping: record(string(), _enum([
8044
+ "person",
8045
+ "vehicle",
8046
+ "animal",
8047
+ "package"
8048
+ ])),
8049
+ preserveOriginal: boolean()
8050
+ });
8033
8051
  var MODEL_FORMATS = [
8034
8052
  "onnx",
8035
8053
  "coreml",
@@ -8208,7 +8226,13 @@ var ModelCatalogEntrySchema = object({
8208
8226
  * `id` stays the source of truth for resolution/download/persistence; grouping
8209
8227
  * is a presentation overlay resolved back to an `id`.
8210
8228
  */
8211
- group: ModelVariantGroupSchema.optional()
8229
+ group: ModelVariantGroupSchema.optional(),
8230
+ /**
8231
+ * Per-MODEL class map override. Absent ⇒ the step's `StepDefinition.classMap`
8232
+ * applies (Frigate / COCO public catalog). Set on a custom model whose raw
8233
+ * labels already ARE the CamStack macros (Scrypted identity map).
8234
+ */
8235
+ classMap: ClassMapDefinitionSchema.optional()
8212
8236
  });
8213
8237
  var ConvertTargetSchema = discriminatedUnion("format", [object({
8214
8238
  format: literal("openvino"),
@@ -8237,7 +8261,8 @@ var ModelConvertMetadataSchema = object({
8237
8261
  "ocr",
8238
8262
  "segmentation"
8239
8263
  ]),
8240
- faceAlignment: boolean().optional()
8264
+ faceAlignment: boolean().optional(),
8265
+ classMap: ClassMapDefinitionSchema.optional()
8241
8266
  });
8242
8267
  var ConvertResultSchema = object({
8243
8268
  entry: ModelCatalogEntrySchema,
@@ -17228,6 +17253,33 @@ var NativeCropRefSchema = object({
17228
17253
  h: number()
17229
17254
  })
17230
17255
  });
17256
+ object({
17257
+ crop: object({
17258
+ left: number(),
17259
+ top: number(),
17260
+ width: number().positive(),
17261
+ height: number().positive()
17262
+ }).optional(),
17263
+ content: object({
17264
+ width: number().int().positive(),
17265
+ height: number().int().positive()
17266
+ }),
17267
+ fit: _enum(["stretch", "contain"]),
17268
+ format: _enum([
17269
+ "rgb",
17270
+ "gray",
17271
+ "jpeg"
17272
+ ])
17273
+ });
17274
+ var FrameRefSchema = object({
17275
+ registryId: string().min(1),
17276
+ id: string().min(1),
17277
+ width: number().int().positive(),
17278
+ height: number().int().positive(),
17279
+ format: _enum(["rgb", "gray"]),
17280
+ timestamp: number(),
17281
+ capturedAt: number().optional()
17282
+ });
17231
17283
  var ModelFormatSchema$1 = _enum([
17232
17284
  "onnx",
17233
17285
  "coreml",
@@ -17472,6 +17524,12 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
17472
17524
  steps: array(PipelineStepInputSchema).min(1),
17473
17525
  frame: FrameInputSchema.optional(),
17474
17526
  /**
17527
+ * Process-local lazy frame. Valid only when caller and provider resolve
17528
+ * in the same execution-group process; split/cross-node callers use
17529
+ * `frame`/`image` inline compatibility instead.
17530
+ */
17531
+ frameRef: FrameRefSchema.optional(),
17532
+ /**
17475
17533
  * CB5 shm passthrough — a `FrameHandle` naming the same ring slot
17476
17534
  * the decoded pixels live in. One more member of the one-of
17477
17535
  * frame/frameHandle/image/imageBase64/referenceImage group.
@@ -17727,7 +17785,10 @@ var NativeCropResultSchema = object({
17727
17785
  * Which source served this crop, so a quality-sensitive consumer (the native
17728
17786
  * `keyFrame`) can reject a degraded fallback:
17729
17787
  * - `native` — cut from the decode worker's retained NATIVE surface (the
17730
- * quality path).
17788
+ * quality path). A subject-tile serve is also native-resolution and stays
17789
+ * `native` here: the public enum cannot name `tile` without a breaking cap
17790
+ * change. Runner telemetry distinguishes lease vs tile via `source` on the
17791
+ * internal crop result (`nativeHits` vs `tileHits`).
17731
17792
  * - `ram-fullframe` — the native surface MISSED but the request was full-frame,
17732
17793
  * so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
17733
17794
  * the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
@@ -18218,12 +18279,41 @@ var RunnerLocalLoadSchema = object({
18218
18279
  * legacy `OrchestratorMetricsSchema` shape so existing dashboards keep
18219
18280
  * working unchanged when they switch to reading from the runner cap.
18220
18281
  */
18282
+ var FrameLazyCountersSchema = object({
18283
+ framesDecoded: number(),
18284
+ framesAdmitted: number(),
18285
+ framesDroppedPixelFree: number(),
18286
+ viewsMaterialized: number(),
18287
+ viewsSkipped: number(),
18288
+ workerToRunnerBytes: number(),
18289
+ runnerToPoolRawBytes: number(),
18290
+ runnerToPoolJpegBytes: number(),
18291
+ onDemandFullFrameRequests: number(),
18292
+ onDemandCropRequests: number(),
18293
+ nativeHits: number(),
18294
+ nativeMisses: number(),
18295
+ tileHits: number(),
18296
+ tileMisses: number(),
18297
+ fallbackHits: number(),
18298
+ fallbackMisses: number(),
18299
+ retainedWritesAvoided: number(),
18300
+ residentRefs: number(),
18301
+ residentBytes: number(),
18302
+ releases: number(),
18303
+ evictions: number(),
18304
+ staleMisses: number()
18305
+ });
18306
+ var FrameLazyMetricsSchema = object({
18307
+ node: FrameLazyCountersSchema,
18308
+ cameras: array(FrameLazyCountersSchema.extend({ deviceId: number() }))
18309
+ });
18221
18310
  var RunnerLocalMetricsSchema = object({
18222
18311
  nodeId: string(),
18223
18312
  activeCameras: number(),
18224
18313
  throttledCameras: number(),
18225
18314
  avgInferenceTimeMs: number(),
18226
- queueDepth: number()
18315
+ queueDepth: number(),
18316
+ frameLazy: FrameLazyMetricsSchema.optional()
18227
18317
  });
18228
18318
  method(RunnerCameraConfigSchema, object({ success: literal(true) }), { kind: "mutation" }), method(object({ deviceId: number() }), object({ success: literal(true) }), { kind: "mutation" }), method(ReportMotionInputSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), RunnerLocalLoadSchema), method(_void(), RunnerLocalMetricsSchema), method(object({ deviceId: number() }), CameraMetricsSchema.nullable()), method(_void(), array(CameraMetricsWithDeviceIdSchema).readonly()), method(_void(), array(number()).readonly()), method(object({
18229
18319
  handle: FrameHandleSchema,
@@ -19536,6 +19626,9 @@ method(_void(), ProviderInfoSchema), method(object({ config: record(string(), un
19536
19626
  location: StorageLocationSchema,
19537
19627
  relativePath: string()
19538
19628
  }), _void(), { kind: "mutation" }), method(object({ location: StorageLocationSchema }), number().nullable()), method(BeginUploadInputSchema, BeginUploadResultSchema, { kind: "mutation" }), method(WriteChunkInputSchema, _void(), { kind: "mutation" }), method(FinalizeUploadInputSchema, _void(), { kind: "mutation" }), method(AbortUploadInputSchema, _void(), { kind: "mutation" }), method(BeginDownloadInputSchema, BeginDownloadResultSchema, { kind: "mutation" }), method(ReadChunkInputSchema, _instanceof(Uint8Array)), method(EndDownloadInputSchema, _void(), { kind: "mutation" });
19629
+ /** Profile-exported FormBuilder schema. Shape is ConfigUISchema at the UI. */
19630
+ var ProfileSettingsSchemaBridge = unknown().nullable();
19631
+ var ProfileSettingsBagSchema = record(string(), unknown());
19539
19632
  /**
19540
19633
  * A live terminal session hosted by the provider addon. Output and input do
19541
19634
  * NOT flow through the capability — they use the addon data plane
@@ -19565,7 +19658,14 @@ var TerminalSessionInfoSchema = object({
19565
19658
  var TerminalProfileInfoSchema = object({
19566
19659
  profileId: string(),
19567
19660
  label: string(),
19568
- description: string().optional()
19661
+ description: string().optional(),
19662
+ /** Spawn defaults the instance form copies on create. */
19663
+ executable: string().optional(),
19664
+ args: array(string()).readonly().optional(),
19665
+ cwd: string().optional(),
19666
+ environment: array(string()).readonly().optional(),
19667
+ /** ConfigUISchema for instance knobs, or null when the profile has none. */
19668
+ settingsSchema: ProfileSettingsSchemaBridge.optional()
19569
19669
  });
19570
19670
  /**
19571
19671
  * A durable operator-created Terminal instance. Profiles are templates; only
@@ -19578,7 +19678,12 @@ var TerminalInstanceInfoSchema = object({
19578
19678
  profileId: string(),
19579
19679
  profileLabel: string(),
19580
19680
  name: string(),
19581
- enabled: boolean()
19681
+ enabled: boolean(),
19682
+ executable: string(),
19683
+ args: array(string()).readonly(),
19684
+ cwd: string(),
19685
+ environment: array(string()).readonly(),
19686
+ profileSettings: ProfileSettingsBagSchema
19582
19687
  });
19583
19688
  var TerminalLegacyCameraSchema = object({
19584
19689
  stableId: string(),
@@ -19608,7 +19713,23 @@ var TerminalOutputBatchSchema = object({
19608
19713
  method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }), method(_void(), array(TerminalInstanceInfoSchema).readonly(), { auth: "admin" }), method(object({
19609
19714
  targetNodeId: string().min(1),
19610
19715
  profileId: string().min(1),
19611
- name: string().trim().min(1).max(160).optional()
19716
+ name: string().trim().min(1).max(160).optional(),
19717
+ executable: string().max(1024).optional(),
19718
+ args: array(string().max(2048)).max(64).optional(),
19719
+ cwd: string().max(1024).optional(),
19720
+ environment: array(string().max(4096)).max(64).optional(),
19721
+ profileSettings: ProfileSettingsBagSchema.optional()
19722
+ }), TerminalInstanceInfoSchema, {
19723
+ kind: "mutation",
19724
+ auth: "admin"
19725
+ }), method(object({
19726
+ instanceId: string().min(1),
19727
+ name: string().trim().min(1).max(160).optional(),
19728
+ executable: string().max(1024).optional(),
19729
+ args: array(string().max(2048)).max(64).optional(),
19730
+ cwd: string().max(1024).optional(),
19731
+ environment: array(string().max(4096)).max(64).optional(),
19732
+ profileSettings: ProfileSettingsBagSchema.optional()
19612
19733
  }), TerminalInstanceInfoSchema, {
19613
19734
  kind: "mutation",
19614
19735
  auth: "admin"
@@ -19630,7 +19751,11 @@ method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }),
19630
19751
  }), method(_void(), array(TerminalSessionInfoSchema).readonly(), { auth: "admin" }), method(object({
19631
19752
  profileId: string(),
19632
19753
  cols: number().int().positive(),
19633
- rows: number().int().positive()
19754
+ rows: number().int().positive(),
19755
+ executable: string().max(1024).optional(),
19756
+ args: array(string().max(2048)).max(64).optional(),
19757
+ cwd: string().max(1024).optional(),
19758
+ environment: array(string().max(4096)).max(64).optional()
19634
19759
  }), TerminalSessionInfoSchema, {
19635
19760
  kind: "mutation",
19636
19761
  auth: "admin"
@@ -22412,10 +22537,10 @@ DeviceType.LawnMower, method(object({ deviceId: number().int().nonnegative() }),
22412
22537
  *
22413
22538
  * • The SDK (mobile / web client) consumes `getConnectionEndpoints()`
22414
22539
  * to receive an ordered list of candidate base URLs it should race
22415
- * on connect — LAN IPv4 first (lowest latency when on same network),
22416
- * then public hostname (if a tunnel is up), then IPv6. The SDK can
22417
- * race them with short timeouts and stick with the winner for the
22418
- * session.
22540
+ * on connect — LAN IPv4 and stable LAN IPv6 first (lowest latency
22541
+ * when on the same network), then public hostname (if a tunnel is
22542
+ * up). The SDK can race them with short timeouts and stick with the
22543
+ * winner for the session.
22419
22544
  *
22420
22545
  * Why hub-only: agents are not directly addressable by the operator's
22421
22546
  * clients — they reverse-connect to the hub. Exposing their interfaces
@@ -22570,6 +22695,17 @@ var NotificationEndpointSchema = object({
22570
22695
  /** What the ranking currently resolves to (null when nothing is reachable). */
22571
22696
  resolved: string().nullable()
22572
22697
  });
22698
+ /**
22699
+ * The URLs the SDK / viewer should race for API access. `baseUrls` empty =
22700
+ * AUTO (every LAN IPv4 + the public tunnel). `resolved` is what that choice
22701
+ * currently expands to, so the UI can show the effective set either way.
22702
+ */
22703
+ var ViewerEndpointsSchema = object({
22704
+ /** The operator's explicit race set, or empty for AUTO. */
22705
+ baseUrls: array(string()).readonly(),
22706
+ /** What the ranking currently resolves to (may be empty if nothing is up). */
22707
+ resolved: array(string()).readonly()
22708
+ });
22573
22709
  var AllowedAddressesSchema = object({
22574
22710
  /**
22575
22711
  * Allowlist of interface addresses operators have explicitly opted
@@ -22578,6 +22714,20 @@ var AllowedAddressesSchema = object({
22578
22714
  * Network Addresses admin page and persisted by the addon.
22579
22715
  */
22580
22716
  addresses: array(string()).readonly() });
22717
+ var TlsStatusSchema = object({
22718
+ mode: _enum([
22719
+ "generated",
22720
+ "uploaded",
22721
+ "disabled"
22722
+ ]),
22723
+ leafFingerprintSha256: string().nullable(),
22724
+ caFingerprintSha256: string().nullable(),
22725
+ validTo: string().nullable(),
22726
+ sans: array(string()),
22727
+ caCertPem: string().nullable(),
22728
+ reissueError: string().nullable(),
22729
+ restartRequired: boolean()
22730
+ });
22581
22731
  method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(object({
22582
22732
  /**
22583
22733
  * LEGACY HINT — do not send from new code. Kept optional so clients
@@ -22587,17 +22737,31 @@ method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(obje
22587
22737
  */
22588
22738
  port: number().int().min(1).max(65535).optional(),
22589
22739
  /** Include `http(s)://127.0.0.1:<port>` as the lowest-priority
22590
- * candidate. Default `true`. */
22740
+ * candidate. Default `false` — loopback is not a client route. */
22591
22741
  includeLoopback: boolean().optional(),
22592
- /** Skip IPv6 entries. Some legacy clients can't parse them.
22593
- * Default `false`. */
22742
+ /** Skip IPv6 entries. Default `false` the palette includes stable
22743
+ * LAN IPv6 (ICE/WebRTC uses dual-stack regardless). Pass `true` to
22744
+ * hide them. The viewer HTTP/WS race is `getViewerEndpoints`. */
22594
22745
  ipv4Only: boolean().optional(),
22595
22746
  /** Scheme to emit for LAN/loopback URLs. Default `'http'`.
22596
22747
  * Pass `'https'` when the caller is itself loaded over HTTPS
22597
22748
  * to avoid mixed-content blocks in the browser. The public
22598
22749
  * tunnel always emits `https://` regardless. */
22599
22750
  scheme: _enum(["http", "https"]).optional()
22600
- }), GetConnectionEndpointsResultSchema), method(_void(), NotificationEndpointSchema), method(object({ baseUrl: string().nullable() }), NotificationEndpointSchema, { kind: "mutation" }), method(_void(), AllowedAddressesSchema), method(AllowedAddressesSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), AllowedAddressesSchema, { kind: "mutation" });
22751
+ }), GetConnectionEndpointsResultSchema), method(_void(), NotificationEndpointSchema), method(object({ baseUrl: string().nullable() }), NotificationEndpointSchema, { kind: "mutation" }), method(_void(), ViewerEndpointsSchema), method(object({ baseUrls: array(string()).readonly() }), ViewerEndpointsSchema, { kind: "mutation" }), method(_void(), AllowedAddressesSchema), method(AllowedAddressesSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), AllowedAddressesSchema, { kind: "mutation" }), method(_void(), TlsStatusSchema), method(object({ reason: string().optional() }), TlsStatusSchema, {
22752
+ kind: "mutation",
22753
+ auth: "admin"
22754
+ }), method(object({
22755
+ certPem: string().min(1),
22756
+ keyPem: string().min(1),
22757
+ caPem: string().optional()
22758
+ }), TlsStatusSchema, {
22759
+ kind: "mutation",
22760
+ auth: "admin"
22761
+ }), method(_void(), object({ pem: string() })), method(_void(), TlsStatusSchema, {
22762
+ kind: "mutation",
22763
+ auth: "admin"
22764
+ });
22601
22765
  object({
22602
22766
  /** Lifecycle state of the lock. `jammed` means the motor reported
22603
22767
  * failure to reach the target — operator intervention required. */
@@ -28360,6 +28524,12 @@ Object.freeze({
28360
28524
  addonId: null,
28361
28525
  access: "create"
28362
28526
  },
28527
+ "localNetwork.downloadCa": {
28528
+ capName: "local-network",
28529
+ capScope: "system",
28530
+ addonId: null,
28531
+ access: "view"
28532
+ },
28363
28533
  "localNetwork.getAllowedAddresses": {
28364
28534
  capName: "local-network",
28365
28535
  capScope: "system",
@@ -28384,18 +28554,42 @@ Object.freeze({
28384
28554
  addonId: null,
28385
28555
  access: "view"
28386
28556
  },
28557
+ "localNetwork.getTlsStatus": {
28558
+ capName: "local-network",
28559
+ capScope: "system",
28560
+ addonId: null,
28561
+ access: "view"
28562
+ },
28563
+ "localNetwork.getViewerEndpoints": {
28564
+ capName: "local-network",
28565
+ capScope: "system",
28566
+ addonId: null,
28567
+ access: "view"
28568
+ },
28387
28569
  "localNetwork.list": {
28388
28570
  capName: "local-network",
28389
28571
  capScope: "system",
28390
28572
  addonId: null,
28391
28573
  access: "view"
28392
28574
  },
28575
+ "localNetwork.regenerateCertificate": {
28576
+ capName: "local-network",
28577
+ capScope: "system",
28578
+ addonId: null,
28579
+ access: "create"
28580
+ },
28393
28581
  "localNetwork.resetAllowlistToBestMatch": {
28394
28582
  capName: "local-network",
28395
28583
  capScope: "system",
28396
28584
  addonId: null,
28397
28585
  access: "delete"
28398
28586
  },
28587
+ "localNetwork.revertToGeneratedCertificate": {
28588
+ capName: "local-network",
28589
+ capScope: "system",
28590
+ addonId: null,
28591
+ access: "create"
28592
+ },
28399
28593
  "localNetwork.setAllowedAddresses": {
28400
28594
  capName: "local-network",
28401
28595
  capScope: "system",
@@ -28408,6 +28602,18 @@ Object.freeze({
28408
28602
  addonId: null,
28409
28603
  access: "create"
28410
28604
  },
28605
+ "localNetwork.setViewerEndpoints": {
28606
+ capName: "local-network",
28607
+ capScope: "system",
28608
+ addonId: null,
28609
+ access: "create"
28610
+ },
28611
+ "localNetwork.uploadCertificate": {
28612
+ capName: "local-network",
28613
+ capScope: "system",
28614
+ addonId: null,
28615
+ access: "create"
28616
+ },
28411
28617
  "lockControl.lock": {
28412
28618
  capName: "lock-control",
28413
28619
  capScope: "device",
@@ -31288,6 +31494,12 @@ Object.freeze({
31288
31494
  addonId: null,
31289
31495
  access: "create"
31290
31496
  },
31497
+ "terminalSession.updateInstance": {
31498
+ capName: "terminal-session",
31499
+ capScope: "system",
31500
+ addonId: null,
31501
+ access: "create"
31502
+ },
31291
31503
  "terminalSession.writeInput": {
31292
31504
  capName: "terminal-session",
31293
31505
  capScope: "system",
@@ -33775,6 +33987,35 @@ Object.freeze(Object.fromEntries([{
33775
33987
  }]
33776
33988
  }].map((s) => [s.stepId, s.defaultModelId])));
33777
33989
  string().min(1);
33990
+ var CLUSTER_STEP_SETTING_FIELDS = [{
33991
+ stepId: "face-embedding",
33992
+ key: "minLandmarkFaceSize",
33993
+ label: "Min face size for recognition (detection px)",
33994
+ description: "Refuse to embed a face smaller than this IN THE DETECTION FRAME. Applies to every node — the enrolled gallery is one index, and two admission floors would fill it from two policies. 0 disables the gate.",
33995
+ type: "slider",
33996
+ min: 0,
33997
+ max: 64,
33998
+ step: 2,
33999
+ default: 24
34000
+ }];
34001
+ function clusterStepSettingKey(stepId, fieldKey) {
34002
+ return `clusterStepSetting:${stepId}:${fieldKey}`;
34003
+ }
34004
+ var ClusterSettingNumberSchema = number().finite();
34005
+ function readClusterStepSettings(config) {
34006
+ const out = {};
34007
+ for (const field of CLUSTER_STEP_SETTING_FIELDS) {
34008
+ const parsed = ClusterSettingNumberSchema.safeParse(config[clusterStepSettingKey(field.stepId, field.key)]);
34009
+ const value = parsed.success ? parsed.data : field.default;
34010
+ const existing = out[field.stepId] ?? {};
34011
+ out[field.stepId] = {
34012
+ ...existing,
34013
+ [field.key]: value
34014
+ };
34015
+ }
34016
+ return out;
34017
+ }
34018
+ readClusterStepSettings({});
33778
34019
  object({
33779
34020
  /**
33780
34021
  * Fraction of the box's own size added on EACH side before cutting.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-smtp-nodemailer",
3
- "version": "1.2.24",
3
+ "version": "1.2.26",
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",