@camstack/addon-import-alexa 0.2.24 → 0.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.
Files changed (3) hide show
  1. package/dist/addon.js +258 -17
  2. package/dist/addon.mjs +258 -17
  3. package/package.json +1 -1
package/dist/addon.js CHANGED
@@ -38,7 +38,7 @@ let node_os = require("node:os");
38
38
  let node_fs = require("node:fs");
39
39
  let node_path = require("node:path");
40
40
  node_path = __toESM(node_path);
41
- //#region ../types/dist/event-category-XfKNtfCc.mjs
41
+ //#region ../types/dist/event-category-CIa_iT6b.mjs
42
42
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
43
43
  EventCategory["SystemBoot"] = "system.boot";
44
44
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -54,6 +54,15 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
54
54
  */
55
55
  EventCategory["SystemRestartCompleted"] = "system.restart-completed";
56
56
  /**
57
+ * The hub reissued its own TLS certificate at boot (`ensureTlsCert`).
58
+ * Emitted only when the material on disk actually changed, so an
59
+ * operator who trusted the old certificate by hand is told rather than
60
+ * discovering it as a browser error. Payload `TlsCertChangedPayload`.
61
+ *
62
+ * Rule: docs/decisions/adr-0227-*.md
63
+ */
64
+ EventCategory["SystemTlsCertChanged"] = "system.tls-cert-changed";
65
+ /**
57
66
  * A newer addon or server-root package version was found by the
58
67
  * authoritative registry check. Emitted once when any observed
59
68
  * `latestVersion` changes (or a package/node first appears behind);
@@ -8169,6 +8178,15 @@ var LabelDefinitionSchema = object({
8169
8178
  description: string().optional(),
8170
8179
  icon: string().optional()
8171
8180
  });
8181
+ var ClassMapDefinitionSchema = object({
8182
+ mapping: record(string(), _enum([
8183
+ "person",
8184
+ "vehicle",
8185
+ "animal",
8186
+ "package"
8187
+ ])),
8188
+ preserveOriginal: boolean()
8189
+ });
8172
8190
  var MODEL_FORMATS = [
8173
8191
  "onnx",
8174
8192
  "coreml",
@@ -8347,7 +8365,13 @@ var ModelCatalogEntrySchema = object({
8347
8365
  * `id` stays the source of truth for resolution/download/persistence; grouping
8348
8366
  * is a presentation overlay resolved back to an `id`.
8349
8367
  */
8350
- group: ModelVariantGroupSchema.optional()
8368
+ group: ModelVariantGroupSchema.optional(),
8369
+ /**
8370
+ * Per-MODEL class map override. Absent ⇒ the step's `StepDefinition.classMap`
8371
+ * applies (Frigate / COCO public catalog). Set on a custom model whose raw
8372
+ * labels already ARE the CamStack macros (Scrypted identity map).
8373
+ */
8374
+ classMap: ClassMapDefinitionSchema.optional()
8351
8375
  });
8352
8376
  var ConvertTargetSchema = discriminatedUnion("format", [object({
8353
8377
  format: literal("openvino"),
@@ -8376,7 +8400,8 @@ var ModelConvertMetadataSchema = object({
8376
8400
  "ocr",
8377
8401
  "segmentation"
8378
8402
  ]),
8379
- faceAlignment: boolean().optional()
8403
+ faceAlignment: boolean().optional(),
8404
+ classMap: ClassMapDefinitionSchema.optional()
8380
8405
  });
8381
8406
  var ConvertResultSchema = object({
8382
8407
  entry: ModelCatalogEntrySchema,
@@ -17754,6 +17779,33 @@ var NativeCropRefSchema = object({
17754
17779
  h: number()
17755
17780
  })
17756
17781
  });
17782
+ object({
17783
+ crop: object({
17784
+ left: number(),
17785
+ top: number(),
17786
+ width: number().positive(),
17787
+ height: number().positive()
17788
+ }).optional(),
17789
+ content: object({
17790
+ width: number().int().positive(),
17791
+ height: number().int().positive()
17792
+ }),
17793
+ fit: _enum(["stretch", "contain"]),
17794
+ format: _enum([
17795
+ "rgb",
17796
+ "gray",
17797
+ "jpeg"
17798
+ ])
17799
+ });
17800
+ var FrameRefSchema = object({
17801
+ registryId: string().min(1),
17802
+ id: string().min(1),
17803
+ width: number().int().positive(),
17804
+ height: number().int().positive(),
17805
+ format: _enum(["rgb", "gray"]),
17806
+ timestamp: number(),
17807
+ capturedAt: number().optional()
17808
+ });
17757
17809
  var ModelFormatSchema$1 = _enum([
17758
17810
  "onnx",
17759
17811
  "coreml",
@@ -17998,6 +18050,12 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
17998
18050
  steps: array(PipelineStepInputSchema).min(1),
17999
18051
  frame: FrameInputSchema.optional(),
18000
18052
  /**
18053
+ * Process-local lazy frame. Valid only when caller and provider resolve
18054
+ * in the same execution-group process; split/cross-node callers use
18055
+ * `frame`/`image` inline compatibility instead.
18056
+ */
18057
+ frameRef: FrameRefSchema.optional(),
18058
+ /**
18001
18059
  * CB5 shm passthrough — a `FrameHandle` naming the same ring slot
18002
18060
  * the decoded pixels live in. One more member of the one-of
18003
18061
  * frame/frameHandle/image/imageBase64/referenceImage group.
@@ -18293,7 +18351,10 @@ var NativeCropResultSchema = object({
18293
18351
  * Which source served this crop, so a quality-sensitive consumer (the native
18294
18352
  * `keyFrame`) can reject a degraded fallback:
18295
18353
  * - `native` — cut from the decode worker's retained NATIVE surface (the
18296
- * quality path).
18354
+ * quality path). A subject-tile serve is also native-resolution and stays
18355
+ * `native` here: the public enum cannot name `tile` without a breaking cap
18356
+ * change. Runner telemetry distinguishes lease vs tile via `source` on the
18357
+ * internal crop result (`nativeHits` vs `tileHits`).
18297
18358
  * - `ram-fullframe` — the native surface MISSED but the request was full-frame,
18298
18359
  * so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
18299
18360
  * the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
@@ -18784,12 +18845,41 @@ var RunnerLocalLoadSchema = object({
18784
18845
  * legacy `OrchestratorMetricsSchema` shape so existing dashboards keep
18785
18846
  * working unchanged when they switch to reading from the runner cap.
18786
18847
  */
18848
+ var FrameLazyCountersSchema = object({
18849
+ framesDecoded: number(),
18850
+ framesAdmitted: number(),
18851
+ framesDroppedPixelFree: number(),
18852
+ viewsMaterialized: number(),
18853
+ viewsSkipped: number(),
18854
+ workerToRunnerBytes: number(),
18855
+ runnerToPoolRawBytes: number(),
18856
+ runnerToPoolJpegBytes: number(),
18857
+ onDemandFullFrameRequests: number(),
18858
+ onDemandCropRequests: number(),
18859
+ nativeHits: number(),
18860
+ nativeMisses: number(),
18861
+ tileHits: number(),
18862
+ tileMisses: number(),
18863
+ fallbackHits: number(),
18864
+ fallbackMisses: number(),
18865
+ retainedWritesAvoided: number(),
18866
+ residentRefs: number(),
18867
+ residentBytes: number(),
18868
+ releases: number(),
18869
+ evictions: number(),
18870
+ staleMisses: number()
18871
+ });
18872
+ var FrameLazyMetricsSchema = object({
18873
+ node: FrameLazyCountersSchema,
18874
+ cameras: array(FrameLazyCountersSchema.extend({ deviceId: number() }))
18875
+ });
18787
18876
  var RunnerLocalMetricsSchema = object({
18788
18877
  nodeId: string(),
18789
18878
  activeCameras: number(),
18790
18879
  throttledCameras: number(),
18791
18880
  avgInferenceTimeMs: number(),
18792
- queueDepth: number()
18881
+ queueDepth: number(),
18882
+ frameLazy: FrameLazyMetricsSchema.optional()
18793
18883
  });
18794
18884
  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({
18795
18885
  handle: FrameHandleSchema,
@@ -20089,6 +20179,9 @@ method(_void(), ProviderInfoSchema), method(object({ config: record(string(), un
20089
20179
  location: StorageLocationSchema,
20090
20180
  relativePath: string()
20091
20181
  }), _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" });
20182
+ /** Profile-exported FormBuilder schema. Shape is ConfigUISchema at the UI. */
20183
+ var ProfileSettingsSchemaBridge = unknown().nullable();
20184
+ var ProfileSettingsBagSchema = record(string(), unknown());
20092
20185
  /**
20093
20186
  * A live terminal session hosted by the provider addon. Output and input do
20094
20187
  * NOT flow through the capability — they use the addon data plane
@@ -20118,7 +20211,14 @@ var TerminalSessionInfoSchema = object({
20118
20211
  var TerminalProfileInfoSchema = object({
20119
20212
  profileId: string(),
20120
20213
  label: string(),
20121
- description: string().optional()
20214
+ description: string().optional(),
20215
+ /** Spawn defaults the instance form copies on create. */
20216
+ executable: string().optional(),
20217
+ args: array(string()).readonly().optional(),
20218
+ cwd: string().optional(),
20219
+ environment: array(string()).readonly().optional(),
20220
+ /** ConfigUISchema for instance knobs, or null when the profile has none. */
20221
+ settingsSchema: ProfileSettingsSchemaBridge.optional()
20122
20222
  });
20123
20223
  /**
20124
20224
  * A durable operator-created Terminal instance. Profiles are templates; only
@@ -20131,7 +20231,12 @@ var TerminalInstanceInfoSchema = object({
20131
20231
  profileId: string(),
20132
20232
  profileLabel: string(),
20133
20233
  name: string(),
20134
- enabled: boolean()
20234
+ enabled: boolean(),
20235
+ executable: string(),
20236
+ args: array(string()).readonly(),
20237
+ cwd: string(),
20238
+ environment: array(string()).readonly(),
20239
+ profileSettings: ProfileSettingsBagSchema
20135
20240
  });
20136
20241
  var TerminalLegacyCameraSchema = object({
20137
20242
  stableId: string(),
@@ -20161,7 +20266,23 @@ var TerminalOutputBatchSchema = object({
20161
20266
  method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }), method(_void(), array(TerminalInstanceInfoSchema).readonly(), { auth: "admin" }), method(object({
20162
20267
  targetNodeId: string().min(1),
20163
20268
  profileId: string().min(1),
20164
- name: string().trim().min(1).max(160).optional()
20269
+ name: string().trim().min(1).max(160).optional(),
20270
+ executable: string().max(1024).optional(),
20271
+ args: array(string().max(2048)).max(64).optional(),
20272
+ cwd: string().max(1024).optional(),
20273
+ environment: array(string().max(4096)).max(64).optional(),
20274
+ profileSettings: ProfileSettingsBagSchema.optional()
20275
+ }), TerminalInstanceInfoSchema, {
20276
+ kind: "mutation",
20277
+ auth: "admin"
20278
+ }), method(object({
20279
+ instanceId: string().min(1),
20280
+ name: string().trim().min(1).max(160).optional(),
20281
+ executable: string().max(1024).optional(),
20282
+ args: array(string().max(2048)).max(64).optional(),
20283
+ cwd: string().max(1024).optional(),
20284
+ environment: array(string().max(4096)).max(64).optional(),
20285
+ profileSettings: ProfileSettingsBagSchema.optional()
20165
20286
  }), TerminalInstanceInfoSchema, {
20166
20287
  kind: "mutation",
20167
20288
  auth: "admin"
@@ -20183,7 +20304,11 @@ method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }),
20183
20304
  }), method(_void(), array(TerminalSessionInfoSchema).readonly(), { auth: "admin" }), method(object({
20184
20305
  profileId: string(),
20185
20306
  cols: number().int().positive(),
20186
- rows: number().int().positive()
20307
+ rows: number().int().positive(),
20308
+ executable: string().max(1024).optional(),
20309
+ args: array(string().max(2048)).max(64).optional(),
20310
+ cwd: string().max(1024).optional(),
20311
+ environment: array(string().max(4096)).max(64).optional()
20187
20312
  }), TerminalSessionInfoSchema, {
20188
20313
  kind: "mutation",
20189
20314
  auth: "admin"
@@ -24075,10 +24200,10 @@ var lawnMowerControlCapability = {
24075
24200
  *
24076
24201
  * • The SDK (mobile / web client) consumes `getConnectionEndpoints()`
24077
24202
  * to receive an ordered list of candidate base URLs it should race
24078
- * on connect — LAN IPv4 first (lowest latency when on same network),
24079
- * then public hostname (if a tunnel is up), then IPv6. The SDK can
24080
- * race them with short timeouts and stick with the winner for the
24081
- * session.
24203
+ * on connect — LAN IPv4 and stable LAN IPv6 first (lowest latency
24204
+ * when on the same network), then public hostname (if a tunnel is
24205
+ * up). The SDK can race them with short timeouts and stick with the
24206
+ * winner for the session.
24082
24207
  *
24083
24208
  * Why hub-only: agents are not directly addressable by the operator's
24084
24209
  * clients — they reverse-connect to the hub. Exposing their interfaces
@@ -24233,6 +24358,17 @@ var NotificationEndpointSchema = object({
24233
24358
  /** What the ranking currently resolves to (null when nothing is reachable). */
24234
24359
  resolved: string().nullable()
24235
24360
  });
24361
+ /**
24362
+ * The URLs the SDK / viewer should race for API access. `baseUrls` empty =
24363
+ * AUTO (every LAN IPv4 + the public tunnel). `resolved` is what that choice
24364
+ * currently expands to, so the UI can show the effective set either way.
24365
+ */
24366
+ var ViewerEndpointsSchema = object({
24367
+ /** The operator's explicit race set, or empty for AUTO. */
24368
+ baseUrls: array(string()).readonly(),
24369
+ /** What the ranking currently resolves to (may be empty if nothing is up). */
24370
+ resolved: array(string()).readonly()
24371
+ });
24236
24372
  var AllowedAddressesSchema = object({
24237
24373
  /**
24238
24374
  * Allowlist of interface addresses operators have explicitly opted
@@ -24241,6 +24377,20 @@ var AllowedAddressesSchema = object({
24241
24377
  * Network Addresses admin page and persisted by the addon.
24242
24378
  */
24243
24379
  addresses: array(string()).readonly() });
24380
+ var TlsStatusSchema = object({
24381
+ mode: _enum([
24382
+ "generated",
24383
+ "uploaded",
24384
+ "disabled"
24385
+ ]),
24386
+ leafFingerprintSha256: string().nullable(),
24387
+ caFingerprintSha256: string().nullable(),
24388
+ validTo: string().nullable(),
24389
+ sans: array(string()),
24390
+ caCertPem: string().nullable(),
24391
+ reissueError: string().nullable(),
24392
+ restartRequired: boolean()
24393
+ });
24244
24394
  method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(object({
24245
24395
  /**
24246
24396
  * LEGACY HINT — do not send from new code. Kept optional so clients
@@ -24250,17 +24400,31 @@ method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(obje
24250
24400
  */
24251
24401
  port: number().int().min(1).max(65535).optional(),
24252
24402
  /** Include `http(s)://127.0.0.1:<port>` as the lowest-priority
24253
- * candidate. Default `true`. */
24403
+ * candidate. Default `false` — loopback is not a client route. */
24254
24404
  includeLoopback: boolean().optional(),
24255
- /** Skip IPv6 entries. Some legacy clients can't parse them.
24256
- * Default `false`. */
24405
+ /** Skip IPv6 entries. Default `false` the palette includes stable
24406
+ * LAN IPv6 (ICE/WebRTC uses dual-stack regardless). Pass `true` to
24407
+ * hide them. The viewer HTTP/WS race is `getViewerEndpoints`. */
24257
24408
  ipv4Only: boolean().optional(),
24258
24409
  /** Scheme to emit for LAN/loopback URLs. Default `'http'`.
24259
24410
  * Pass `'https'` when the caller is itself loaded over HTTPS
24260
24411
  * to avoid mixed-content blocks in the browser. The public
24261
24412
  * tunnel always emits `https://` regardless. */
24262
24413
  scheme: _enum(["http", "https"]).optional()
24263
- }), 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" });
24414
+ }), 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, {
24415
+ kind: "mutation",
24416
+ auth: "admin"
24417
+ }), method(object({
24418
+ certPem: string().min(1),
24419
+ keyPem: string().min(1),
24420
+ caPem: string().optional()
24421
+ }), TlsStatusSchema, {
24422
+ kind: "mutation",
24423
+ auth: "admin"
24424
+ }), method(_void(), object({ pem: string() })), method(_void(), TlsStatusSchema, {
24425
+ kind: "mutation",
24426
+ auth: "admin"
24427
+ });
24264
24428
  var LockControlStatusSchema = object({
24265
24429
  /** Lifecycle state of the lock. `jammed` means the motor reported
24266
24430
  * failure to reach the target — operator intervention required. */
@@ -32287,6 +32451,12 @@ Object.freeze({
32287
32451
  addonId: null,
32288
32452
  access: "create"
32289
32453
  },
32454
+ "localNetwork.downloadCa": {
32455
+ capName: "local-network",
32456
+ capScope: "system",
32457
+ addonId: null,
32458
+ access: "view"
32459
+ },
32290
32460
  "localNetwork.getAllowedAddresses": {
32291
32461
  capName: "local-network",
32292
32462
  capScope: "system",
@@ -32311,18 +32481,42 @@ Object.freeze({
32311
32481
  addonId: null,
32312
32482
  access: "view"
32313
32483
  },
32484
+ "localNetwork.getTlsStatus": {
32485
+ capName: "local-network",
32486
+ capScope: "system",
32487
+ addonId: null,
32488
+ access: "view"
32489
+ },
32490
+ "localNetwork.getViewerEndpoints": {
32491
+ capName: "local-network",
32492
+ capScope: "system",
32493
+ addonId: null,
32494
+ access: "view"
32495
+ },
32314
32496
  "localNetwork.list": {
32315
32497
  capName: "local-network",
32316
32498
  capScope: "system",
32317
32499
  addonId: null,
32318
32500
  access: "view"
32319
32501
  },
32502
+ "localNetwork.regenerateCertificate": {
32503
+ capName: "local-network",
32504
+ capScope: "system",
32505
+ addonId: null,
32506
+ access: "create"
32507
+ },
32320
32508
  "localNetwork.resetAllowlistToBestMatch": {
32321
32509
  capName: "local-network",
32322
32510
  capScope: "system",
32323
32511
  addonId: null,
32324
32512
  access: "delete"
32325
32513
  },
32514
+ "localNetwork.revertToGeneratedCertificate": {
32515
+ capName: "local-network",
32516
+ capScope: "system",
32517
+ addonId: null,
32518
+ access: "create"
32519
+ },
32326
32520
  "localNetwork.setAllowedAddresses": {
32327
32521
  capName: "local-network",
32328
32522
  capScope: "system",
@@ -32335,6 +32529,18 @@ Object.freeze({
32335
32529
  addonId: null,
32336
32530
  access: "create"
32337
32531
  },
32532
+ "localNetwork.setViewerEndpoints": {
32533
+ capName: "local-network",
32534
+ capScope: "system",
32535
+ addonId: null,
32536
+ access: "create"
32537
+ },
32538
+ "localNetwork.uploadCertificate": {
32539
+ capName: "local-network",
32540
+ capScope: "system",
32541
+ addonId: null,
32542
+ access: "create"
32543
+ },
32338
32544
  "lockControl.lock": {
32339
32545
  capName: "lock-control",
32340
32546
  capScope: "device",
@@ -35215,6 +35421,12 @@ Object.freeze({
35215
35421
  addonId: null,
35216
35422
  access: "create"
35217
35423
  },
35424
+ "terminalSession.updateInstance": {
35425
+ capName: "terminal-session",
35426
+ capScope: "system",
35427
+ addonId: null,
35428
+ access: "create"
35429
+ },
35218
35430
  "terminalSession.writeInput": {
35219
35431
  capName: "terminal-session",
35220
35432
  capScope: "system",
@@ -37702,6 +37914,35 @@ Object.freeze(Object.fromEntries([{
37702
37914
  }]
37703
37915
  }].map((s) => [s.stepId, s.defaultModelId])));
37704
37916
  string().min(1);
37917
+ var CLUSTER_STEP_SETTING_FIELDS = [{
37918
+ stepId: "face-embedding",
37919
+ key: "minLandmarkFaceSize",
37920
+ label: "Min face size for recognition (detection px)",
37921
+ 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.",
37922
+ type: "slider",
37923
+ min: 0,
37924
+ max: 64,
37925
+ step: 2,
37926
+ default: 24
37927
+ }];
37928
+ function clusterStepSettingKey(stepId, fieldKey) {
37929
+ return `clusterStepSetting:${stepId}:${fieldKey}`;
37930
+ }
37931
+ var ClusterSettingNumberSchema = number().finite();
37932
+ function readClusterStepSettings(config) {
37933
+ const out = {};
37934
+ for (const field of CLUSTER_STEP_SETTING_FIELDS) {
37935
+ const parsed = ClusterSettingNumberSchema.safeParse(config[clusterStepSettingKey(field.stepId, field.key)]);
37936
+ const value = parsed.success ? parsed.data : field.default;
37937
+ const existing = out[field.stepId] ?? {};
37938
+ out[field.stepId] = {
37939
+ ...existing,
37940
+ [field.key]: value
37941
+ };
37942
+ }
37943
+ return out;
37944
+ }
37945
+ readClusterStepSettings({});
37705
37946
  object({
37706
37947
  /**
37707
37948
  * Fraction of the box's own size added on EACH side before cutting.
package/dist/addon.mjs CHANGED
@@ -38,7 +38,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
38
38
  var __toCommonJS = (mod) => __hasOwnProp.call(mod, "module.exports") ? mod["module.exports"] : __copyProps(__defProp({}, "__esModule", { value: true }), mod);
39
39
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
40
40
  //#endregion
41
- //#region ../types/dist/event-category-XfKNtfCc.mjs
41
+ //#region ../types/dist/event-category-CIa_iT6b.mjs
42
42
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
43
43
  EventCategory["SystemBoot"] = "system.boot";
44
44
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -54,6 +54,15 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
54
54
  */
55
55
  EventCategory["SystemRestartCompleted"] = "system.restart-completed";
56
56
  /**
57
+ * The hub reissued its own TLS certificate at boot (`ensureTlsCert`).
58
+ * Emitted only when the material on disk actually changed, so an
59
+ * operator who trusted the old certificate by hand is told rather than
60
+ * discovering it as a browser error. Payload `TlsCertChangedPayload`.
61
+ *
62
+ * Rule: docs/decisions/adr-0227-*.md
63
+ */
64
+ EventCategory["SystemTlsCertChanged"] = "system.tls-cert-changed";
65
+ /**
57
66
  * A newer addon or server-root package version was found by the
58
67
  * authoritative registry check. Emitted once when any observed
59
68
  * `latestVersion` changes (or a package/node first appears behind);
@@ -8169,6 +8178,15 @@ var LabelDefinitionSchema = object({
8169
8178
  description: string().optional(),
8170
8179
  icon: string().optional()
8171
8180
  });
8181
+ var ClassMapDefinitionSchema = object({
8182
+ mapping: record(string(), _enum([
8183
+ "person",
8184
+ "vehicle",
8185
+ "animal",
8186
+ "package"
8187
+ ])),
8188
+ preserveOriginal: boolean()
8189
+ });
8172
8190
  var MODEL_FORMATS = [
8173
8191
  "onnx",
8174
8192
  "coreml",
@@ -8347,7 +8365,13 @@ var ModelCatalogEntrySchema = object({
8347
8365
  * `id` stays the source of truth for resolution/download/persistence; grouping
8348
8366
  * is a presentation overlay resolved back to an `id`.
8349
8367
  */
8350
- group: ModelVariantGroupSchema.optional()
8368
+ group: ModelVariantGroupSchema.optional(),
8369
+ /**
8370
+ * Per-MODEL class map override. Absent ⇒ the step's `StepDefinition.classMap`
8371
+ * applies (Frigate / COCO public catalog). Set on a custom model whose raw
8372
+ * labels already ARE the CamStack macros (Scrypted identity map).
8373
+ */
8374
+ classMap: ClassMapDefinitionSchema.optional()
8351
8375
  });
8352
8376
  var ConvertTargetSchema = discriminatedUnion("format", [object({
8353
8377
  format: literal("openvino"),
@@ -8376,7 +8400,8 @@ var ModelConvertMetadataSchema = object({
8376
8400
  "ocr",
8377
8401
  "segmentation"
8378
8402
  ]),
8379
- faceAlignment: boolean().optional()
8403
+ faceAlignment: boolean().optional(),
8404
+ classMap: ClassMapDefinitionSchema.optional()
8380
8405
  });
8381
8406
  var ConvertResultSchema = object({
8382
8407
  entry: ModelCatalogEntrySchema,
@@ -17754,6 +17779,33 @@ var NativeCropRefSchema = object({
17754
17779
  h: number()
17755
17780
  })
17756
17781
  });
17782
+ object({
17783
+ crop: object({
17784
+ left: number(),
17785
+ top: number(),
17786
+ width: number().positive(),
17787
+ height: number().positive()
17788
+ }).optional(),
17789
+ content: object({
17790
+ width: number().int().positive(),
17791
+ height: number().int().positive()
17792
+ }),
17793
+ fit: _enum(["stretch", "contain"]),
17794
+ format: _enum([
17795
+ "rgb",
17796
+ "gray",
17797
+ "jpeg"
17798
+ ])
17799
+ });
17800
+ var FrameRefSchema = object({
17801
+ registryId: string().min(1),
17802
+ id: string().min(1),
17803
+ width: number().int().positive(),
17804
+ height: number().int().positive(),
17805
+ format: _enum(["rgb", "gray"]),
17806
+ timestamp: number(),
17807
+ capturedAt: number().optional()
17808
+ });
17757
17809
  var ModelFormatSchema$1 = _enum([
17758
17810
  "onnx",
17759
17811
  "coreml",
@@ -17998,6 +18050,12 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
17998
18050
  steps: array(PipelineStepInputSchema).min(1),
17999
18051
  frame: FrameInputSchema.optional(),
18000
18052
  /**
18053
+ * Process-local lazy frame. Valid only when caller and provider resolve
18054
+ * in the same execution-group process; split/cross-node callers use
18055
+ * `frame`/`image` inline compatibility instead.
18056
+ */
18057
+ frameRef: FrameRefSchema.optional(),
18058
+ /**
18001
18059
  * CB5 shm passthrough — a `FrameHandle` naming the same ring slot
18002
18060
  * the decoded pixels live in. One more member of the one-of
18003
18061
  * frame/frameHandle/image/imageBase64/referenceImage group.
@@ -18293,7 +18351,10 @@ var NativeCropResultSchema = object({
18293
18351
  * Which source served this crop, so a quality-sensitive consumer (the native
18294
18352
  * `keyFrame`) can reject a degraded fallback:
18295
18353
  * - `native` — cut from the decode worker's retained NATIVE surface (the
18296
- * quality path).
18354
+ * quality path). A subject-tile serve is also native-resolution and stays
18355
+ * `native` here: the public enum cannot name `tile` without a breaking cap
18356
+ * change. Runner telemetry distinguishes lease vs tile via `source` on the
18357
+ * internal crop result (`nativeHits` vs `tileHits`).
18297
18358
  * - `ram-fullframe` — the native surface MISSED but the request was full-frame,
18298
18359
  * so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
18299
18360
  * the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
@@ -18784,12 +18845,41 @@ var RunnerLocalLoadSchema = object({
18784
18845
  * legacy `OrchestratorMetricsSchema` shape so existing dashboards keep
18785
18846
  * working unchanged when they switch to reading from the runner cap.
18786
18847
  */
18848
+ var FrameLazyCountersSchema = object({
18849
+ framesDecoded: number(),
18850
+ framesAdmitted: number(),
18851
+ framesDroppedPixelFree: number(),
18852
+ viewsMaterialized: number(),
18853
+ viewsSkipped: number(),
18854
+ workerToRunnerBytes: number(),
18855
+ runnerToPoolRawBytes: number(),
18856
+ runnerToPoolJpegBytes: number(),
18857
+ onDemandFullFrameRequests: number(),
18858
+ onDemandCropRequests: number(),
18859
+ nativeHits: number(),
18860
+ nativeMisses: number(),
18861
+ tileHits: number(),
18862
+ tileMisses: number(),
18863
+ fallbackHits: number(),
18864
+ fallbackMisses: number(),
18865
+ retainedWritesAvoided: number(),
18866
+ residentRefs: number(),
18867
+ residentBytes: number(),
18868
+ releases: number(),
18869
+ evictions: number(),
18870
+ staleMisses: number()
18871
+ });
18872
+ var FrameLazyMetricsSchema = object({
18873
+ node: FrameLazyCountersSchema,
18874
+ cameras: array(FrameLazyCountersSchema.extend({ deviceId: number() }))
18875
+ });
18787
18876
  var RunnerLocalMetricsSchema = object({
18788
18877
  nodeId: string(),
18789
18878
  activeCameras: number(),
18790
18879
  throttledCameras: number(),
18791
18880
  avgInferenceTimeMs: number(),
18792
- queueDepth: number()
18881
+ queueDepth: number(),
18882
+ frameLazy: FrameLazyMetricsSchema.optional()
18793
18883
  });
18794
18884
  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({
18795
18885
  handle: FrameHandleSchema,
@@ -20089,6 +20179,9 @@ method(_void(), ProviderInfoSchema), method(object({ config: record(string(), un
20089
20179
  location: StorageLocationSchema,
20090
20180
  relativePath: string()
20091
20181
  }), _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" });
20182
+ /** Profile-exported FormBuilder schema. Shape is ConfigUISchema at the UI. */
20183
+ var ProfileSettingsSchemaBridge = unknown().nullable();
20184
+ var ProfileSettingsBagSchema = record(string(), unknown());
20092
20185
  /**
20093
20186
  * A live terminal session hosted by the provider addon. Output and input do
20094
20187
  * NOT flow through the capability — they use the addon data plane
@@ -20118,7 +20211,14 @@ var TerminalSessionInfoSchema = object({
20118
20211
  var TerminalProfileInfoSchema = object({
20119
20212
  profileId: string(),
20120
20213
  label: string(),
20121
- description: string().optional()
20214
+ description: string().optional(),
20215
+ /** Spawn defaults the instance form copies on create. */
20216
+ executable: string().optional(),
20217
+ args: array(string()).readonly().optional(),
20218
+ cwd: string().optional(),
20219
+ environment: array(string()).readonly().optional(),
20220
+ /** ConfigUISchema for instance knobs, or null when the profile has none. */
20221
+ settingsSchema: ProfileSettingsSchemaBridge.optional()
20122
20222
  });
20123
20223
  /**
20124
20224
  * A durable operator-created Terminal instance. Profiles are templates; only
@@ -20131,7 +20231,12 @@ var TerminalInstanceInfoSchema = object({
20131
20231
  profileId: string(),
20132
20232
  profileLabel: string(),
20133
20233
  name: string(),
20134
- enabled: boolean()
20234
+ enabled: boolean(),
20235
+ executable: string(),
20236
+ args: array(string()).readonly(),
20237
+ cwd: string(),
20238
+ environment: array(string()).readonly(),
20239
+ profileSettings: ProfileSettingsBagSchema
20135
20240
  });
20136
20241
  var TerminalLegacyCameraSchema = object({
20137
20242
  stableId: string(),
@@ -20161,7 +20266,23 @@ var TerminalOutputBatchSchema = object({
20161
20266
  method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }), method(_void(), array(TerminalInstanceInfoSchema).readonly(), { auth: "admin" }), method(object({
20162
20267
  targetNodeId: string().min(1),
20163
20268
  profileId: string().min(1),
20164
- name: string().trim().min(1).max(160).optional()
20269
+ name: string().trim().min(1).max(160).optional(),
20270
+ executable: string().max(1024).optional(),
20271
+ args: array(string().max(2048)).max(64).optional(),
20272
+ cwd: string().max(1024).optional(),
20273
+ environment: array(string().max(4096)).max(64).optional(),
20274
+ profileSettings: ProfileSettingsBagSchema.optional()
20275
+ }), TerminalInstanceInfoSchema, {
20276
+ kind: "mutation",
20277
+ auth: "admin"
20278
+ }), method(object({
20279
+ instanceId: string().min(1),
20280
+ name: string().trim().min(1).max(160).optional(),
20281
+ executable: string().max(1024).optional(),
20282
+ args: array(string().max(2048)).max(64).optional(),
20283
+ cwd: string().max(1024).optional(),
20284
+ environment: array(string().max(4096)).max(64).optional(),
20285
+ profileSettings: ProfileSettingsBagSchema.optional()
20165
20286
  }), TerminalInstanceInfoSchema, {
20166
20287
  kind: "mutation",
20167
20288
  auth: "admin"
@@ -20183,7 +20304,11 @@ method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }),
20183
20304
  }), method(_void(), array(TerminalSessionInfoSchema).readonly(), { auth: "admin" }), method(object({
20184
20305
  profileId: string(),
20185
20306
  cols: number().int().positive(),
20186
- rows: number().int().positive()
20307
+ rows: number().int().positive(),
20308
+ executable: string().max(1024).optional(),
20309
+ args: array(string().max(2048)).max(64).optional(),
20310
+ cwd: string().max(1024).optional(),
20311
+ environment: array(string().max(4096)).max(64).optional()
20187
20312
  }), TerminalSessionInfoSchema, {
20188
20313
  kind: "mutation",
20189
20314
  auth: "admin"
@@ -24075,10 +24200,10 @@ var lawnMowerControlCapability = {
24075
24200
  *
24076
24201
  * • The SDK (mobile / web client) consumes `getConnectionEndpoints()`
24077
24202
  * to receive an ordered list of candidate base URLs it should race
24078
- * on connect — LAN IPv4 first (lowest latency when on same network),
24079
- * then public hostname (if a tunnel is up), then IPv6. The SDK can
24080
- * race them with short timeouts and stick with the winner for the
24081
- * session.
24203
+ * on connect — LAN IPv4 and stable LAN IPv6 first (lowest latency
24204
+ * when on the same network), then public hostname (if a tunnel is
24205
+ * up). The SDK can race them with short timeouts and stick with the
24206
+ * winner for the session.
24082
24207
  *
24083
24208
  * Why hub-only: agents are not directly addressable by the operator's
24084
24209
  * clients — they reverse-connect to the hub. Exposing their interfaces
@@ -24233,6 +24358,17 @@ var NotificationEndpointSchema = object({
24233
24358
  /** What the ranking currently resolves to (null when nothing is reachable). */
24234
24359
  resolved: string().nullable()
24235
24360
  });
24361
+ /**
24362
+ * The URLs the SDK / viewer should race for API access. `baseUrls` empty =
24363
+ * AUTO (every LAN IPv4 + the public tunnel). `resolved` is what that choice
24364
+ * currently expands to, so the UI can show the effective set either way.
24365
+ */
24366
+ var ViewerEndpointsSchema = object({
24367
+ /** The operator's explicit race set, or empty for AUTO. */
24368
+ baseUrls: array(string()).readonly(),
24369
+ /** What the ranking currently resolves to (may be empty if nothing is up). */
24370
+ resolved: array(string()).readonly()
24371
+ });
24236
24372
  var AllowedAddressesSchema = object({
24237
24373
  /**
24238
24374
  * Allowlist of interface addresses operators have explicitly opted
@@ -24241,6 +24377,20 @@ var AllowedAddressesSchema = object({
24241
24377
  * Network Addresses admin page and persisted by the addon.
24242
24378
  */
24243
24379
  addresses: array(string()).readonly() });
24380
+ var TlsStatusSchema = object({
24381
+ mode: _enum([
24382
+ "generated",
24383
+ "uploaded",
24384
+ "disabled"
24385
+ ]),
24386
+ leafFingerprintSha256: string().nullable(),
24387
+ caFingerprintSha256: string().nullable(),
24388
+ validTo: string().nullable(),
24389
+ sans: array(string()),
24390
+ caCertPem: string().nullable(),
24391
+ reissueError: string().nullable(),
24392
+ restartRequired: boolean()
24393
+ });
24244
24394
  method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(object({
24245
24395
  /**
24246
24396
  * LEGACY HINT — do not send from new code. Kept optional so clients
@@ -24250,17 +24400,31 @@ method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(obje
24250
24400
  */
24251
24401
  port: number().int().min(1).max(65535).optional(),
24252
24402
  /** Include `http(s)://127.0.0.1:<port>` as the lowest-priority
24253
- * candidate. Default `true`. */
24403
+ * candidate. Default `false` — loopback is not a client route. */
24254
24404
  includeLoopback: boolean().optional(),
24255
- /** Skip IPv6 entries. Some legacy clients can't parse them.
24256
- * Default `false`. */
24405
+ /** Skip IPv6 entries. Default `false` the palette includes stable
24406
+ * LAN IPv6 (ICE/WebRTC uses dual-stack regardless). Pass `true` to
24407
+ * hide them. The viewer HTTP/WS race is `getViewerEndpoints`. */
24257
24408
  ipv4Only: boolean().optional(),
24258
24409
  /** Scheme to emit for LAN/loopback URLs. Default `'http'`.
24259
24410
  * Pass `'https'` when the caller is itself loaded over HTTPS
24260
24411
  * to avoid mixed-content blocks in the browser. The public
24261
24412
  * tunnel always emits `https://` regardless. */
24262
24413
  scheme: _enum(["http", "https"]).optional()
24263
- }), 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" });
24414
+ }), 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, {
24415
+ kind: "mutation",
24416
+ auth: "admin"
24417
+ }), method(object({
24418
+ certPem: string().min(1),
24419
+ keyPem: string().min(1),
24420
+ caPem: string().optional()
24421
+ }), TlsStatusSchema, {
24422
+ kind: "mutation",
24423
+ auth: "admin"
24424
+ }), method(_void(), object({ pem: string() })), method(_void(), TlsStatusSchema, {
24425
+ kind: "mutation",
24426
+ auth: "admin"
24427
+ });
24264
24428
  var LockControlStatusSchema = object({
24265
24429
  /** Lifecycle state of the lock. `jammed` means the motor reported
24266
24430
  * failure to reach the target — operator intervention required. */
@@ -32287,6 +32451,12 @@ Object.freeze({
32287
32451
  addonId: null,
32288
32452
  access: "create"
32289
32453
  },
32454
+ "localNetwork.downloadCa": {
32455
+ capName: "local-network",
32456
+ capScope: "system",
32457
+ addonId: null,
32458
+ access: "view"
32459
+ },
32290
32460
  "localNetwork.getAllowedAddresses": {
32291
32461
  capName: "local-network",
32292
32462
  capScope: "system",
@@ -32311,18 +32481,42 @@ Object.freeze({
32311
32481
  addonId: null,
32312
32482
  access: "view"
32313
32483
  },
32484
+ "localNetwork.getTlsStatus": {
32485
+ capName: "local-network",
32486
+ capScope: "system",
32487
+ addonId: null,
32488
+ access: "view"
32489
+ },
32490
+ "localNetwork.getViewerEndpoints": {
32491
+ capName: "local-network",
32492
+ capScope: "system",
32493
+ addonId: null,
32494
+ access: "view"
32495
+ },
32314
32496
  "localNetwork.list": {
32315
32497
  capName: "local-network",
32316
32498
  capScope: "system",
32317
32499
  addonId: null,
32318
32500
  access: "view"
32319
32501
  },
32502
+ "localNetwork.regenerateCertificate": {
32503
+ capName: "local-network",
32504
+ capScope: "system",
32505
+ addonId: null,
32506
+ access: "create"
32507
+ },
32320
32508
  "localNetwork.resetAllowlistToBestMatch": {
32321
32509
  capName: "local-network",
32322
32510
  capScope: "system",
32323
32511
  addonId: null,
32324
32512
  access: "delete"
32325
32513
  },
32514
+ "localNetwork.revertToGeneratedCertificate": {
32515
+ capName: "local-network",
32516
+ capScope: "system",
32517
+ addonId: null,
32518
+ access: "create"
32519
+ },
32326
32520
  "localNetwork.setAllowedAddresses": {
32327
32521
  capName: "local-network",
32328
32522
  capScope: "system",
@@ -32335,6 +32529,18 @@ Object.freeze({
32335
32529
  addonId: null,
32336
32530
  access: "create"
32337
32531
  },
32532
+ "localNetwork.setViewerEndpoints": {
32533
+ capName: "local-network",
32534
+ capScope: "system",
32535
+ addonId: null,
32536
+ access: "create"
32537
+ },
32538
+ "localNetwork.uploadCertificate": {
32539
+ capName: "local-network",
32540
+ capScope: "system",
32541
+ addonId: null,
32542
+ access: "create"
32543
+ },
32338
32544
  "lockControl.lock": {
32339
32545
  capName: "lock-control",
32340
32546
  capScope: "device",
@@ -35215,6 +35421,12 @@ Object.freeze({
35215
35421
  addonId: null,
35216
35422
  access: "create"
35217
35423
  },
35424
+ "terminalSession.updateInstance": {
35425
+ capName: "terminal-session",
35426
+ capScope: "system",
35427
+ addonId: null,
35428
+ access: "create"
35429
+ },
35218
35430
  "terminalSession.writeInput": {
35219
35431
  capName: "terminal-session",
35220
35432
  capScope: "system",
@@ -37702,6 +37914,35 @@ Object.freeze(Object.fromEntries([{
37702
37914
  }]
37703
37915
  }].map((s) => [s.stepId, s.defaultModelId])));
37704
37916
  string().min(1);
37917
+ var CLUSTER_STEP_SETTING_FIELDS = [{
37918
+ stepId: "face-embedding",
37919
+ key: "minLandmarkFaceSize",
37920
+ label: "Min face size for recognition (detection px)",
37921
+ 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.",
37922
+ type: "slider",
37923
+ min: 0,
37924
+ max: 64,
37925
+ step: 2,
37926
+ default: 24
37927
+ }];
37928
+ function clusterStepSettingKey(stepId, fieldKey) {
37929
+ return `clusterStepSetting:${stepId}:${fieldKey}`;
37930
+ }
37931
+ var ClusterSettingNumberSchema = number().finite();
37932
+ function readClusterStepSettings(config) {
37933
+ const out = {};
37934
+ for (const field of CLUSTER_STEP_SETTING_FIELDS) {
37935
+ const parsed = ClusterSettingNumberSchema.safeParse(config[clusterStepSettingKey(field.stepId, field.key)]);
37936
+ const value = parsed.success ? parsed.data : field.default;
37937
+ const existing = out[field.stepId] ?? {};
37938
+ out[field.stepId] = {
37939
+ ...existing,
37940
+ [field.key]: value
37941
+ };
37942
+ }
37943
+ return out;
37944
+ }
37945
+ readClusterStepSettings({});
37705
37946
  object({
37706
37947
  /**
37707
37948
  * 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-import-alexa",
3
- "version": "0.2.24",
3
+ "version": "0.2.26",
4
4
  "description": "Alexa device-import provider for CamStack — imports the smart-home devices in a user's Alexa account via the unofficial alexa-remote2 cookie/token client (the inverse of the Alexa exporter)",
5
5
  "keywords": [
6
6
  "camstack",