@camstack/addon-provider-velux 0.2.25 → 0.2.27

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
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- //#region ../types/dist/event-category-XfKNtfCc.mjs
2
+ //#region ../types/dist/event-category-CIa_iT6b.mjs
3
3
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
4
4
  EventCategory["SystemBoot"] = "system.boot";
5
5
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -15,6 +15,15 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
15
15
  */
16
16
  EventCategory["SystemRestartCompleted"] = "system.restart-completed";
17
17
  /**
18
+ * The hub reissued its own TLS certificate at boot (`ensureTlsCert`).
19
+ * Emitted only when the material on disk actually changed, so an
20
+ * operator who trusted the old certificate by hand is told rather than
21
+ * discovering it as a browser error. Payload `TlsCertChangedPayload`.
22
+ *
23
+ * Rule: docs/decisions/adr-0227-*.md
24
+ */
25
+ EventCategory["SystemTlsCertChanged"] = "system.tls-cert-changed";
26
+ /**
18
27
  * A newer addon or server-root package version was found by the
19
28
  * authoritative registry check. Emitted once when any observed
20
29
  * `latestVersion` changes (or a package/node first appears behind);
@@ -8011,6 +8020,15 @@ var LabelDefinitionSchema = object({
8011
8020
  description: string().optional(),
8012
8021
  icon: string().optional()
8013
8022
  });
8023
+ var ClassMapDefinitionSchema = object({
8024
+ mapping: record(string(), _enum([
8025
+ "person",
8026
+ "vehicle",
8027
+ "animal",
8028
+ "package"
8029
+ ])),
8030
+ preserveOriginal: boolean()
8031
+ });
8014
8032
  var MODEL_FORMATS = [
8015
8033
  "onnx",
8016
8034
  "coreml",
@@ -8189,7 +8207,13 @@ var ModelCatalogEntrySchema = object({
8189
8207
  * `id` stays the source of truth for resolution/download/persistence; grouping
8190
8208
  * is a presentation overlay resolved back to an `id`.
8191
8209
  */
8192
- group: ModelVariantGroupSchema.optional()
8210
+ group: ModelVariantGroupSchema.optional(),
8211
+ /**
8212
+ * Per-MODEL class map override. Absent ⇒ the step's `StepDefinition.classMap`
8213
+ * applies (Frigate / COCO public catalog). Set on a custom model whose raw
8214
+ * labels already ARE the CamStack macros (Scrypted identity map).
8215
+ */
8216
+ classMap: ClassMapDefinitionSchema.optional()
8193
8217
  });
8194
8218
  var ConvertTargetSchema = discriminatedUnion("format", [object({
8195
8219
  format: literal("openvino"),
@@ -8218,7 +8242,8 @@ var ModelConvertMetadataSchema = object({
8218
8242
  "ocr",
8219
8243
  "segmentation"
8220
8244
  ]),
8221
- faceAlignment: boolean().optional()
8245
+ faceAlignment: boolean().optional(),
8246
+ classMap: ClassMapDefinitionSchema.optional()
8222
8247
  });
8223
8248
  var ConvertResultSchema = object({
8224
8249
  entry: ModelCatalogEntrySchema,
@@ -17511,6 +17536,33 @@ var NativeCropRefSchema = object({
17511
17536
  h: number()
17512
17537
  })
17513
17538
  });
17539
+ object({
17540
+ crop: object({
17541
+ left: number(),
17542
+ top: number(),
17543
+ width: number().positive(),
17544
+ height: number().positive()
17545
+ }).optional(),
17546
+ content: object({
17547
+ width: number().int().positive(),
17548
+ height: number().int().positive()
17549
+ }),
17550
+ fit: _enum(["stretch", "contain"]),
17551
+ format: _enum([
17552
+ "rgb",
17553
+ "gray",
17554
+ "jpeg"
17555
+ ])
17556
+ });
17557
+ var FrameRefSchema = object({
17558
+ registryId: string().min(1),
17559
+ id: string().min(1),
17560
+ width: number().int().positive(),
17561
+ height: number().int().positive(),
17562
+ format: _enum(["rgb", "gray"]),
17563
+ timestamp: number(),
17564
+ capturedAt: number().optional()
17565
+ });
17514
17566
  var ModelFormatSchema$1 = _enum([
17515
17567
  "onnx",
17516
17568
  "coreml",
@@ -17755,6 +17807,12 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
17755
17807
  steps: array(PipelineStepInputSchema).min(1),
17756
17808
  frame: FrameInputSchema.optional(),
17757
17809
  /**
17810
+ * Process-local lazy frame. Valid only when caller and provider resolve
17811
+ * in the same execution-group process; split/cross-node callers use
17812
+ * `frame`/`image` inline compatibility instead.
17813
+ */
17814
+ frameRef: FrameRefSchema.optional(),
17815
+ /**
17758
17816
  * CB5 shm passthrough — a `FrameHandle` naming the same ring slot
17759
17817
  * the decoded pixels live in. One more member of the one-of
17760
17818
  * frame/frameHandle/image/imageBase64/referenceImage group.
@@ -18050,7 +18108,10 @@ var NativeCropResultSchema = object({
18050
18108
  * Which source served this crop, so a quality-sensitive consumer (the native
18051
18109
  * `keyFrame`) can reject a degraded fallback:
18052
18110
  * - `native` — cut from the decode worker's retained NATIVE surface (the
18053
- * quality path).
18111
+ * quality path). A subject-tile serve is also native-resolution and stays
18112
+ * `native` here: the public enum cannot name `tile` without a breaking cap
18113
+ * change. Runner telemetry distinguishes lease vs tile via `source` on the
18114
+ * internal crop result (`nativeHits` vs `tileHits`).
18054
18115
  * - `ram-fullframe` — the native surface MISSED but the request was full-frame,
18055
18116
  * so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
18056
18117
  * the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
@@ -18541,12 +18602,41 @@ var RunnerLocalLoadSchema = object({
18541
18602
  * legacy `OrchestratorMetricsSchema` shape so existing dashboards keep
18542
18603
  * working unchanged when they switch to reading from the runner cap.
18543
18604
  */
18605
+ var FrameLazyCountersSchema = object({
18606
+ framesDecoded: number(),
18607
+ framesAdmitted: number(),
18608
+ framesDroppedPixelFree: number(),
18609
+ viewsMaterialized: number(),
18610
+ viewsSkipped: number(),
18611
+ workerToRunnerBytes: number(),
18612
+ runnerToPoolRawBytes: number(),
18613
+ runnerToPoolJpegBytes: number(),
18614
+ onDemandFullFrameRequests: number(),
18615
+ onDemandCropRequests: number(),
18616
+ nativeHits: number(),
18617
+ nativeMisses: number(),
18618
+ tileHits: number(),
18619
+ tileMisses: number(),
18620
+ fallbackHits: number(),
18621
+ fallbackMisses: number(),
18622
+ retainedWritesAvoided: number(),
18623
+ residentRefs: number(),
18624
+ residentBytes: number(),
18625
+ releases: number(),
18626
+ evictions: number(),
18627
+ staleMisses: number()
18628
+ });
18629
+ var FrameLazyMetricsSchema = object({
18630
+ node: FrameLazyCountersSchema,
18631
+ cameras: array(FrameLazyCountersSchema.extend({ deviceId: number() }))
18632
+ });
18544
18633
  var RunnerLocalMetricsSchema = object({
18545
18634
  nodeId: string(),
18546
18635
  activeCameras: number(),
18547
18636
  throttledCameras: number(),
18548
18637
  avgInferenceTimeMs: number(),
18549
- queueDepth: number()
18638
+ queueDepth: number(),
18639
+ frameLazy: FrameLazyMetricsSchema.optional()
18550
18640
  });
18551
18641
  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({
18552
18642
  handle: FrameHandleSchema,
@@ -19846,6 +19936,9 @@ method(_void(), ProviderInfoSchema), method(object({ config: record(string(), un
19846
19936
  location: StorageLocationSchema,
19847
19937
  relativePath: string()
19848
19938
  }), _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" });
19939
+ /** Profile-exported FormBuilder schema. Shape is ConfigUISchema at the UI. */
19940
+ var ProfileSettingsSchemaBridge = unknown().nullable();
19941
+ var ProfileSettingsBagSchema = record(string(), unknown());
19849
19942
  /**
19850
19943
  * A live terminal session hosted by the provider addon. Output and input do
19851
19944
  * NOT flow through the capability — they use the addon data plane
@@ -19875,7 +19968,14 @@ var TerminalSessionInfoSchema = object({
19875
19968
  var TerminalProfileInfoSchema = object({
19876
19969
  profileId: string(),
19877
19970
  label: string(),
19878
- description: string().optional()
19971
+ description: string().optional(),
19972
+ /** Spawn defaults the instance form copies on create. */
19973
+ executable: string().optional(),
19974
+ args: array(string()).readonly().optional(),
19975
+ cwd: string().optional(),
19976
+ environment: array(string()).readonly().optional(),
19977
+ /** ConfigUISchema for instance knobs, or null when the profile has none. */
19978
+ settingsSchema: ProfileSettingsSchemaBridge.optional()
19879
19979
  });
19880
19980
  /**
19881
19981
  * A durable operator-created Terminal instance. Profiles are templates; only
@@ -19888,7 +19988,12 @@ var TerminalInstanceInfoSchema = object({
19888
19988
  profileId: string(),
19889
19989
  profileLabel: string(),
19890
19990
  name: string(),
19891
- enabled: boolean()
19991
+ enabled: boolean(),
19992
+ executable: string(),
19993
+ args: array(string()).readonly(),
19994
+ cwd: string(),
19995
+ environment: array(string()).readonly(),
19996
+ profileSettings: ProfileSettingsBagSchema
19892
19997
  });
19893
19998
  var TerminalLegacyCameraSchema = object({
19894
19999
  stableId: string(),
@@ -19918,7 +20023,23 @@ var TerminalOutputBatchSchema = object({
19918
20023
  method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }), method(_void(), array(TerminalInstanceInfoSchema).readonly(), { auth: "admin" }), method(object({
19919
20024
  targetNodeId: string().min(1),
19920
20025
  profileId: string().min(1),
19921
- name: string().trim().min(1).max(160).optional()
20026
+ name: string().trim().min(1).max(160).optional(),
20027
+ executable: string().max(1024).optional(),
20028
+ args: array(string().max(2048)).max(64).optional(),
20029
+ cwd: string().max(1024).optional(),
20030
+ environment: array(string().max(4096)).max(64).optional(),
20031
+ profileSettings: ProfileSettingsBagSchema.optional()
20032
+ }), TerminalInstanceInfoSchema, {
20033
+ kind: "mutation",
20034
+ auth: "admin"
20035
+ }), method(object({
20036
+ instanceId: string().min(1),
20037
+ name: string().trim().min(1).max(160).optional(),
20038
+ executable: string().max(1024).optional(),
20039
+ args: array(string().max(2048)).max(64).optional(),
20040
+ cwd: string().max(1024).optional(),
20041
+ environment: array(string().max(4096)).max(64).optional(),
20042
+ profileSettings: ProfileSettingsBagSchema.optional()
19922
20043
  }), TerminalInstanceInfoSchema, {
19923
20044
  kind: "mutation",
19924
20045
  auth: "admin"
@@ -19940,7 +20061,11 @@ method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }),
19940
20061
  }), method(_void(), array(TerminalSessionInfoSchema).readonly(), { auth: "admin" }), method(object({
19941
20062
  profileId: string(),
19942
20063
  cols: number().int().positive(),
19943
- rows: number().int().positive()
20064
+ rows: number().int().positive(),
20065
+ executable: string().max(1024).optional(),
20066
+ args: array(string().max(2048)).max(64).optional(),
20067
+ cwd: string().max(1024).optional(),
20068
+ environment: array(string().max(4096)).max(64).optional()
19944
20069
  }), TerminalSessionInfoSchema, {
19945
20070
  kind: "mutation",
19946
20071
  auth: "admin"
@@ -23815,10 +23940,10 @@ var lawnMowerControlCapability = {
23815
23940
  *
23816
23941
  * • The SDK (mobile / web client) consumes `getConnectionEndpoints()`
23817
23942
  * to receive an ordered list of candidate base URLs it should race
23818
- * on connect — LAN IPv4 first (lowest latency when on same network),
23819
- * then public hostname (if a tunnel is up), then IPv6. The SDK can
23820
- * race them with short timeouts and stick with the winner for the
23821
- * session.
23943
+ * on connect — LAN IPv4 and stable LAN IPv6 first (lowest latency
23944
+ * when on the same network), then public hostname (if a tunnel is
23945
+ * up). The SDK can race them with short timeouts and stick with the
23946
+ * winner for the session.
23822
23947
  *
23823
23948
  * Why hub-only: agents are not directly addressable by the operator's
23824
23949
  * clients — they reverse-connect to the hub. Exposing their interfaces
@@ -23973,6 +24098,17 @@ var NotificationEndpointSchema = object({
23973
24098
  /** What the ranking currently resolves to (null when nothing is reachable). */
23974
24099
  resolved: string().nullable()
23975
24100
  });
24101
+ /**
24102
+ * The URLs the SDK / viewer should race for API access. `baseUrls` empty =
24103
+ * AUTO (every LAN IPv4 + the public tunnel). `resolved` is what that choice
24104
+ * currently expands to, so the UI can show the effective set either way.
24105
+ */
24106
+ var ViewerEndpointsSchema = object({
24107
+ /** The operator's explicit race set, or empty for AUTO. */
24108
+ baseUrls: array(string()).readonly(),
24109
+ /** What the ranking currently resolves to (may be empty if nothing is up). */
24110
+ resolved: array(string()).readonly()
24111
+ });
23976
24112
  var AllowedAddressesSchema = object({
23977
24113
  /**
23978
24114
  * Allowlist of interface addresses operators have explicitly opted
@@ -23981,6 +24117,20 @@ var AllowedAddressesSchema = object({
23981
24117
  * Network Addresses admin page and persisted by the addon.
23982
24118
  */
23983
24119
  addresses: array(string()).readonly() });
24120
+ var TlsStatusSchema = object({
24121
+ mode: _enum([
24122
+ "generated",
24123
+ "uploaded",
24124
+ "disabled"
24125
+ ]),
24126
+ leafFingerprintSha256: string().nullable(),
24127
+ caFingerprintSha256: string().nullable(),
24128
+ validTo: string().nullable(),
24129
+ sans: array(string()),
24130
+ caCertPem: string().nullable(),
24131
+ reissueError: string().nullable(),
24132
+ restartRequired: boolean()
24133
+ });
23984
24134
  method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(object({
23985
24135
  /**
23986
24136
  * LEGACY HINT — do not send from new code. Kept optional so clients
@@ -23990,17 +24140,31 @@ method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(obje
23990
24140
  */
23991
24141
  port: number().int().min(1).max(65535).optional(),
23992
24142
  /** Include `http(s)://127.0.0.1:<port>` as the lowest-priority
23993
- * candidate. Default `true`. */
24143
+ * candidate. Default `false` — loopback is not a client route. */
23994
24144
  includeLoopback: boolean().optional(),
23995
- /** Skip IPv6 entries. Some legacy clients can't parse them.
23996
- * Default `false`. */
24145
+ /** Skip IPv6 entries. Default `false` the palette includes stable
24146
+ * LAN IPv6 (ICE/WebRTC uses dual-stack regardless). Pass `true` to
24147
+ * hide them. The viewer HTTP/WS race is `getViewerEndpoints`. */
23997
24148
  ipv4Only: boolean().optional(),
23998
24149
  /** Scheme to emit for LAN/loopback URLs. Default `'http'`.
23999
24150
  * Pass `'https'` when the caller is itself loaded over HTTPS
24000
24151
  * to avoid mixed-content blocks in the browser. The public
24001
24152
  * tunnel always emits `https://` regardless. */
24002
24153
  scheme: _enum(["http", "https"]).optional()
24003
- }), 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" });
24154
+ }), 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, {
24155
+ kind: "mutation",
24156
+ auth: "admin"
24157
+ }), method(object({
24158
+ certPem: string().min(1),
24159
+ keyPem: string().min(1),
24160
+ caPem: string().optional()
24161
+ }), TlsStatusSchema, {
24162
+ kind: "mutation",
24163
+ auth: "admin"
24164
+ }), method(_void(), object({ pem: string() })), method(_void(), TlsStatusSchema, {
24165
+ kind: "mutation",
24166
+ auth: "admin"
24167
+ });
24004
24168
  var LockControlStatusSchema = object({
24005
24169
  /** Lifecycle state of the lock. `jammed` means the motor reported
24006
24170
  * failure to reach the target — operator intervention required. */
@@ -32027,6 +32191,12 @@ Object.freeze({
32027
32191
  addonId: null,
32028
32192
  access: "create"
32029
32193
  },
32194
+ "localNetwork.downloadCa": {
32195
+ capName: "local-network",
32196
+ capScope: "system",
32197
+ addonId: null,
32198
+ access: "view"
32199
+ },
32030
32200
  "localNetwork.getAllowedAddresses": {
32031
32201
  capName: "local-network",
32032
32202
  capScope: "system",
@@ -32051,18 +32221,42 @@ Object.freeze({
32051
32221
  addonId: null,
32052
32222
  access: "view"
32053
32223
  },
32224
+ "localNetwork.getTlsStatus": {
32225
+ capName: "local-network",
32226
+ capScope: "system",
32227
+ addonId: null,
32228
+ access: "view"
32229
+ },
32230
+ "localNetwork.getViewerEndpoints": {
32231
+ capName: "local-network",
32232
+ capScope: "system",
32233
+ addonId: null,
32234
+ access: "view"
32235
+ },
32054
32236
  "localNetwork.list": {
32055
32237
  capName: "local-network",
32056
32238
  capScope: "system",
32057
32239
  addonId: null,
32058
32240
  access: "view"
32059
32241
  },
32242
+ "localNetwork.regenerateCertificate": {
32243
+ capName: "local-network",
32244
+ capScope: "system",
32245
+ addonId: null,
32246
+ access: "create"
32247
+ },
32060
32248
  "localNetwork.resetAllowlistToBestMatch": {
32061
32249
  capName: "local-network",
32062
32250
  capScope: "system",
32063
32251
  addonId: null,
32064
32252
  access: "delete"
32065
32253
  },
32254
+ "localNetwork.revertToGeneratedCertificate": {
32255
+ capName: "local-network",
32256
+ capScope: "system",
32257
+ addonId: null,
32258
+ access: "create"
32259
+ },
32066
32260
  "localNetwork.setAllowedAddresses": {
32067
32261
  capName: "local-network",
32068
32262
  capScope: "system",
@@ -32075,6 +32269,18 @@ Object.freeze({
32075
32269
  addonId: null,
32076
32270
  access: "create"
32077
32271
  },
32272
+ "localNetwork.setViewerEndpoints": {
32273
+ capName: "local-network",
32274
+ capScope: "system",
32275
+ addonId: null,
32276
+ access: "create"
32277
+ },
32278
+ "localNetwork.uploadCertificate": {
32279
+ capName: "local-network",
32280
+ capScope: "system",
32281
+ addonId: null,
32282
+ access: "create"
32283
+ },
32078
32284
  "lockControl.lock": {
32079
32285
  capName: "lock-control",
32080
32286
  capScope: "device",
@@ -34955,6 +35161,12 @@ Object.freeze({
34955
35161
  addonId: null,
34956
35162
  access: "create"
34957
35163
  },
35164
+ "terminalSession.updateInstance": {
35165
+ capName: "terminal-session",
35166
+ capScope: "system",
35167
+ addonId: null,
35168
+ access: "create"
35169
+ },
34958
35170
  "terminalSession.writeInput": {
34959
35171
  capName: "terminal-session",
34960
35172
  capScope: "system",
@@ -37442,6 +37654,35 @@ Object.freeze(Object.fromEntries([{
37442
37654
  }]
37443
37655
  }].map((s) => [s.stepId, s.defaultModelId])));
37444
37656
  string().min(1);
37657
+ var CLUSTER_STEP_SETTING_FIELDS = [{
37658
+ stepId: "face-embedding",
37659
+ key: "minLandmarkFaceSize",
37660
+ label: "Min face size for recognition (detection px)",
37661
+ 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.",
37662
+ type: "slider",
37663
+ min: 0,
37664
+ max: 64,
37665
+ step: 2,
37666
+ default: 24
37667
+ }];
37668
+ function clusterStepSettingKey(stepId, fieldKey) {
37669
+ return `clusterStepSetting:${stepId}:${fieldKey}`;
37670
+ }
37671
+ var ClusterSettingNumberSchema = number().finite();
37672
+ function readClusterStepSettings(config) {
37673
+ const out = {};
37674
+ for (const field of CLUSTER_STEP_SETTING_FIELDS) {
37675
+ const parsed = ClusterSettingNumberSchema.safeParse(config[clusterStepSettingKey(field.stepId, field.key)]);
37676
+ const value = parsed.success ? parsed.data : field.default;
37677
+ const existing = out[field.stepId] ?? {};
37678
+ out[field.stepId] = {
37679
+ ...existing,
37680
+ [field.key]: value
37681
+ };
37682
+ }
37683
+ return out;
37684
+ }
37685
+ readClusterStepSettings({});
37445
37686
  object({
37446
37687
  /**
37447
37688
  * Fraction of the box's own size added on EACH side before cutting.
package/dist/addon.mjs CHANGED
@@ -1,4 +1,4 @@
1
- //#region ../types/dist/event-category-XfKNtfCc.mjs
1
+ //#region ../types/dist/event-category-CIa_iT6b.mjs
2
2
  var EventCategory = /* @__PURE__ */ function(EventCategory) {
3
3
  EventCategory["SystemBoot"] = "system.boot";
4
4
  EventCategory["SystemAddonsReady"] = "system.addons-ready";
@@ -14,6 +14,15 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
14
14
  */
15
15
  EventCategory["SystemRestartCompleted"] = "system.restart-completed";
16
16
  /**
17
+ * The hub reissued its own TLS certificate at boot (`ensureTlsCert`).
18
+ * Emitted only when the material on disk actually changed, so an
19
+ * operator who trusted the old certificate by hand is told rather than
20
+ * discovering it as a browser error. Payload `TlsCertChangedPayload`.
21
+ *
22
+ * Rule: docs/decisions/adr-0227-*.md
23
+ */
24
+ EventCategory["SystemTlsCertChanged"] = "system.tls-cert-changed";
25
+ /**
17
26
  * A newer addon or server-root package version was found by the
18
27
  * authoritative registry check. Emitted once when any observed
19
28
  * `latestVersion` changes (or a package/node first appears behind);
@@ -8010,6 +8019,15 @@ var LabelDefinitionSchema = object({
8010
8019
  description: string().optional(),
8011
8020
  icon: string().optional()
8012
8021
  });
8022
+ var ClassMapDefinitionSchema = object({
8023
+ mapping: record(string(), _enum([
8024
+ "person",
8025
+ "vehicle",
8026
+ "animal",
8027
+ "package"
8028
+ ])),
8029
+ preserveOriginal: boolean()
8030
+ });
8013
8031
  var MODEL_FORMATS = [
8014
8032
  "onnx",
8015
8033
  "coreml",
@@ -8188,7 +8206,13 @@ var ModelCatalogEntrySchema = object({
8188
8206
  * `id` stays the source of truth for resolution/download/persistence; grouping
8189
8207
  * is a presentation overlay resolved back to an `id`.
8190
8208
  */
8191
- group: ModelVariantGroupSchema.optional()
8209
+ group: ModelVariantGroupSchema.optional(),
8210
+ /**
8211
+ * Per-MODEL class map override. Absent ⇒ the step's `StepDefinition.classMap`
8212
+ * applies (Frigate / COCO public catalog). Set on a custom model whose raw
8213
+ * labels already ARE the CamStack macros (Scrypted identity map).
8214
+ */
8215
+ classMap: ClassMapDefinitionSchema.optional()
8192
8216
  });
8193
8217
  var ConvertTargetSchema = discriminatedUnion("format", [object({
8194
8218
  format: literal("openvino"),
@@ -8217,7 +8241,8 @@ var ModelConvertMetadataSchema = object({
8217
8241
  "ocr",
8218
8242
  "segmentation"
8219
8243
  ]),
8220
- faceAlignment: boolean().optional()
8244
+ faceAlignment: boolean().optional(),
8245
+ classMap: ClassMapDefinitionSchema.optional()
8221
8246
  });
8222
8247
  var ConvertResultSchema = object({
8223
8248
  entry: ModelCatalogEntrySchema,
@@ -17510,6 +17535,33 @@ var NativeCropRefSchema = object({
17510
17535
  h: number()
17511
17536
  })
17512
17537
  });
17538
+ object({
17539
+ crop: object({
17540
+ left: number(),
17541
+ top: number(),
17542
+ width: number().positive(),
17543
+ height: number().positive()
17544
+ }).optional(),
17545
+ content: object({
17546
+ width: number().int().positive(),
17547
+ height: number().int().positive()
17548
+ }),
17549
+ fit: _enum(["stretch", "contain"]),
17550
+ format: _enum([
17551
+ "rgb",
17552
+ "gray",
17553
+ "jpeg"
17554
+ ])
17555
+ });
17556
+ var FrameRefSchema = object({
17557
+ registryId: string().min(1),
17558
+ id: string().min(1),
17559
+ width: number().int().positive(),
17560
+ height: number().int().positive(),
17561
+ format: _enum(["rgb", "gray"]),
17562
+ timestamp: number(),
17563
+ capturedAt: number().optional()
17564
+ });
17513
17565
  var ModelFormatSchema$1 = _enum([
17514
17566
  "onnx",
17515
17567
  "coreml",
@@ -17754,6 +17806,12 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
17754
17806
  steps: array(PipelineStepInputSchema).min(1),
17755
17807
  frame: FrameInputSchema.optional(),
17756
17808
  /**
17809
+ * Process-local lazy frame. Valid only when caller and provider resolve
17810
+ * in the same execution-group process; split/cross-node callers use
17811
+ * `frame`/`image` inline compatibility instead.
17812
+ */
17813
+ frameRef: FrameRefSchema.optional(),
17814
+ /**
17757
17815
  * CB5 shm passthrough — a `FrameHandle` naming the same ring slot
17758
17816
  * the decoded pixels live in. One more member of the one-of
17759
17817
  * frame/frameHandle/image/imageBase64/referenceImage group.
@@ -18049,7 +18107,10 @@ var NativeCropResultSchema = object({
18049
18107
  * Which source served this crop, so a quality-sensitive consumer (the native
18050
18108
  * `keyFrame`) can reject a degraded fallback:
18051
18109
  * - `native` — cut from the decode worker's retained NATIVE surface (the
18052
- * quality path).
18110
+ * quality path). A subject-tile serve is also native-resolution and stays
18111
+ * `native` here: the public enum cannot name `tile` without a breaking cap
18112
+ * change. Runner telemetry distinguishes lease vs tile via `source` on the
18113
+ * internal crop result (`nativeHits` vs `tileHits`).
18053
18114
  * - `ram-fullframe` — the native surface MISSED but the request was full-frame,
18054
18115
  * so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
18055
18116
  * the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
@@ -18540,12 +18601,41 @@ var RunnerLocalLoadSchema = object({
18540
18601
  * legacy `OrchestratorMetricsSchema` shape so existing dashboards keep
18541
18602
  * working unchanged when they switch to reading from the runner cap.
18542
18603
  */
18604
+ var FrameLazyCountersSchema = object({
18605
+ framesDecoded: number(),
18606
+ framesAdmitted: number(),
18607
+ framesDroppedPixelFree: number(),
18608
+ viewsMaterialized: number(),
18609
+ viewsSkipped: number(),
18610
+ workerToRunnerBytes: number(),
18611
+ runnerToPoolRawBytes: number(),
18612
+ runnerToPoolJpegBytes: number(),
18613
+ onDemandFullFrameRequests: number(),
18614
+ onDemandCropRequests: number(),
18615
+ nativeHits: number(),
18616
+ nativeMisses: number(),
18617
+ tileHits: number(),
18618
+ tileMisses: number(),
18619
+ fallbackHits: number(),
18620
+ fallbackMisses: number(),
18621
+ retainedWritesAvoided: number(),
18622
+ residentRefs: number(),
18623
+ residentBytes: number(),
18624
+ releases: number(),
18625
+ evictions: number(),
18626
+ staleMisses: number()
18627
+ });
18628
+ var FrameLazyMetricsSchema = object({
18629
+ node: FrameLazyCountersSchema,
18630
+ cameras: array(FrameLazyCountersSchema.extend({ deviceId: number() }))
18631
+ });
18543
18632
  var RunnerLocalMetricsSchema = object({
18544
18633
  nodeId: string(),
18545
18634
  activeCameras: number(),
18546
18635
  throttledCameras: number(),
18547
18636
  avgInferenceTimeMs: number(),
18548
- queueDepth: number()
18637
+ queueDepth: number(),
18638
+ frameLazy: FrameLazyMetricsSchema.optional()
18549
18639
  });
18550
18640
  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({
18551
18641
  handle: FrameHandleSchema,
@@ -19845,6 +19935,9 @@ method(_void(), ProviderInfoSchema), method(object({ config: record(string(), un
19845
19935
  location: StorageLocationSchema,
19846
19936
  relativePath: string()
19847
19937
  }), _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" });
19938
+ /** Profile-exported FormBuilder schema. Shape is ConfigUISchema at the UI. */
19939
+ var ProfileSettingsSchemaBridge = unknown().nullable();
19940
+ var ProfileSettingsBagSchema = record(string(), unknown());
19848
19941
  /**
19849
19942
  * A live terminal session hosted by the provider addon. Output and input do
19850
19943
  * NOT flow through the capability — they use the addon data plane
@@ -19874,7 +19967,14 @@ var TerminalSessionInfoSchema = object({
19874
19967
  var TerminalProfileInfoSchema = object({
19875
19968
  profileId: string(),
19876
19969
  label: string(),
19877
- description: string().optional()
19970
+ description: string().optional(),
19971
+ /** Spawn defaults the instance form copies on create. */
19972
+ executable: string().optional(),
19973
+ args: array(string()).readonly().optional(),
19974
+ cwd: string().optional(),
19975
+ environment: array(string()).readonly().optional(),
19976
+ /** ConfigUISchema for instance knobs, or null when the profile has none. */
19977
+ settingsSchema: ProfileSettingsSchemaBridge.optional()
19878
19978
  });
19879
19979
  /**
19880
19980
  * A durable operator-created Terminal instance. Profiles are templates; only
@@ -19887,7 +19987,12 @@ var TerminalInstanceInfoSchema = object({
19887
19987
  profileId: string(),
19888
19988
  profileLabel: string(),
19889
19989
  name: string(),
19890
- enabled: boolean()
19990
+ enabled: boolean(),
19991
+ executable: string(),
19992
+ args: array(string()).readonly(),
19993
+ cwd: string(),
19994
+ environment: array(string()).readonly(),
19995
+ profileSettings: ProfileSettingsBagSchema
19891
19996
  });
19892
19997
  var TerminalLegacyCameraSchema = object({
19893
19998
  stableId: string(),
@@ -19917,7 +20022,23 @@ var TerminalOutputBatchSchema = object({
19917
20022
  method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }), method(_void(), array(TerminalInstanceInfoSchema).readonly(), { auth: "admin" }), method(object({
19918
20023
  targetNodeId: string().min(1),
19919
20024
  profileId: string().min(1),
19920
- name: string().trim().min(1).max(160).optional()
20025
+ name: string().trim().min(1).max(160).optional(),
20026
+ executable: string().max(1024).optional(),
20027
+ args: array(string().max(2048)).max(64).optional(),
20028
+ cwd: string().max(1024).optional(),
20029
+ environment: array(string().max(4096)).max(64).optional(),
20030
+ profileSettings: ProfileSettingsBagSchema.optional()
20031
+ }), TerminalInstanceInfoSchema, {
20032
+ kind: "mutation",
20033
+ auth: "admin"
20034
+ }), method(object({
20035
+ instanceId: string().min(1),
20036
+ name: string().trim().min(1).max(160).optional(),
20037
+ executable: string().max(1024).optional(),
20038
+ args: array(string().max(2048)).max(64).optional(),
20039
+ cwd: string().max(1024).optional(),
20040
+ environment: array(string().max(4096)).max(64).optional(),
20041
+ profileSettings: ProfileSettingsBagSchema.optional()
19921
20042
  }), TerminalInstanceInfoSchema, {
19922
20043
  kind: "mutation",
19923
20044
  auth: "admin"
@@ -19939,7 +20060,11 @@ method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }),
19939
20060
  }), method(_void(), array(TerminalSessionInfoSchema).readonly(), { auth: "admin" }), method(object({
19940
20061
  profileId: string(),
19941
20062
  cols: number().int().positive(),
19942
- rows: number().int().positive()
20063
+ rows: number().int().positive(),
20064
+ executable: string().max(1024).optional(),
20065
+ args: array(string().max(2048)).max(64).optional(),
20066
+ cwd: string().max(1024).optional(),
20067
+ environment: array(string().max(4096)).max(64).optional()
19943
20068
  }), TerminalSessionInfoSchema, {
19944
20069
  kind: "mutation",
19945
20070
  auth: "admin"
@@ -23814,10 +23939,10 @@ var lawnMowerControlCapability = {
23814
23939
  *
23815
23940
  * • The SDK (mobile / web client) consumes `getConnectionEndpoints()`
23816
23941
  * to receive an ordered list of candidate base URLs it should race
23817
- * on connect — LAN IPv4 first (lowest latency when on same network),
23818
- * then public hostname (if a tunnel is up), then IPv6. The SDK can
23819
- * race them with short timeouts and stick with the winner for the
23820
- * session.
23942
+ * on connect — LAN IPv4 and stable LAN IPv6 first (lowest latency
23943
+ * when on the same network), then public hostname (if a tunnel is
23944
+ * up). The SDK can race them with short timeouts and stick with the
23945
+ * winner for the session.
23821
23946
  *
23822
23947
  * Why hub-only: agents are not directly addressable by the operator's
23823
23948
  * clients — they reverse-connect to the hub. Exposing their interfaces
@@ -23972,6 +24097,17 @@ var NotificationEndpointSchema = object({
23972
24097
  /** What the ranking currently resolves to (null when nothing is reachable). */
23973
24098
  resolved: string().nullable()
23974
24099
  });
24100
+ /**
24101
+ * The URLs the SDK / viewer should race for API access. `baseUrls` empty =
24102
+ * AUTO (every LAN IPv4 + the public tunnel). `resolved` is what that choice
24103
+ * currently expands to, so the UI can show the effective set either way.
24104
+ */
24105
+ var ViewerEndpointsSchema = object({
24106
+ /** The operator's explicit race set, or empty for AUTO. */
24107
+ baseUrls: array(string()).readonly(),
24108
+ /** What the ranking currently resolves to (may be empty if nothing is up). */
24109
+ resolved: array(string()).readonly()
24110
+ });
23975
24111
  var AllowedAddressesSchema = object({
23976
24112
  /**
23977
24113
  * Allowlist of interface addresses operators have explicitly opted
@@ -23980,6 +24116,20 @@ var AllowedAddressesSchema = object({
23980
24116
  * Network Addresses admin page and persisted by the addon.
23981
24117
  */
23982
24118
  addresses: array(string()).readonly() });
24119
+ var TlsStatusSchema = object({
24120
+ mode: _enum([
24121
+ "generated",
24122
+ "uploaded",
24123
+ "disabled"
24124
+ ]),
24125
+ leafFingerprintSha256: string().nullable(),
24126
+ caFingerprintSha256: string().nullable(),
24127
+ validTo: string().nullable(),
24128
+ sans: array(string()),
24129
+ caCertPem: string().nullable(),
24130
+ reissueError: string().nullable(),
24131
+ restartRequired: boolean()
24132
+ });
23983
24133
  method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(object({
23984
24134
  /**
23985
24135
  * LEGACY HINT — do not send from new code. Kept optional so clients
@@ -23989,17 +24139,31 @@ method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(obje
23989
24139
  */
23990
24140
  port: number().int().min(1).max(65535).optional(),
23991
24141
  /** Include `http(s)://127.0.0.1:<port>` as the lowest-priority
23992
- * candidate. Default `true`. */
24142
+ * candidate. Default `false` — loopback is not a client route. */
23993
24143
  includeLoopback: boolean().optional(),
23994
- /** Skip IPv6 entries. Some legacy clients can't parse them.
23995
- * Default `false`. */
24144
+ /** Skip IPv6 entries. Default `false` the palette includes stable
24145
+ * LAN IPv6 (ICE/WebRTC uses dual-stack regardless). Pass `true` to
24146
+ * hide them. The viewer HTTP/WS race is `getViewerEndpoints`. */
23996
24147
  ipv4Only: boolean().optional(),
23997
24148
  /** Scheme to emit for LAN/loopback URLs. Default `'http'`.
23998
24149
  * Pass `'https'` when the caller is itself loaded over HTTPS
23999
24150
  * to avoid mixed-content blocks in the browser. The public
24000
24151
  * tunnel always emits `https://` regardless. */
24001
24152
  scheme: _enum(["http", "https"]).optional()
24002
- }), 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" });
24153
+ }), 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, {
24154
+ kind: "mutation",
24155
+ auth: "admin"
24156
+ }), method(object({
24157
+ certPem: string().min(1),
24158
+ keyPem: string().min(1),
24159
+ caPem: string().optional()
24160
+ }), TlsStatusSchema, {
24161
+ kind: "mutation",
24162
+ auth: "admin"
24163
+ }), method(_void(), object({ pem: string() })), method(_void(), TlsStatusSchema, {
24164
+ kind: "mutation",
24165
+ auth: "admin"
24166
+ });
24003
24167
  var LockControlStatusSchema = object({
24004
24168
  /** Lifecycle state of the lock. `jammed` means the motor reported
24005
24169
  * failure to reach the target — operator intervention required. */
@@ -32026,6 +32190,12 @@ Object.freeze({
32026
32190
  addonId: null,
32027
32191
  access: "create"
32028
32192
  },
32193
+ "localNetwork.downloadCa": {
32194
+ capName: "local-network",
32195
+ capScope: "system",
32196
+ addonId: null,
32197
+ access: "view"
32198
+ },
32029
32199
  "localNetwork.getAllowedAddresses": {
32030
32200
  capName: "local-network",
32031
32201
  capScope: "system",
@@ -32050,18 +32220,42 @@ Object.freeze({
32050
32220
  addonId: null,
32051
32221
  access: "view"
32052
32222
  },
32223
+ "localNetwork.getTlsStatus": {
32224
+ capName: "local-network",
32225
+ capScope: "system",
32226
+ addonId: null,
32227
+ access: "view"
32228
+ },
32229
+ "localNetwork.getViewerEndpoints": {
32230
+ capName: "local-network",
32231
+ capScope: "system",
32232
+ addonId: null,
32233
+ access: "view"
32234
+ },
32053
32235
  "localNetwork.list": {
32054
32236
  capName: "local-network",
32055
32237
  capScope: "system",
32056
32238
  addonId: null,
32057
32239
  access: "view"
32058
32240
  },
32241
+ "localNetwork.regenerateCertificate": {
32242
+ capName: "local-network",
32243
+ capScope: "system",
32244
+ addonId: null,
32245
+ access: "create"
32246
+ },
32059
32247
  "localNetwork.resetAllowlistToBestMatch": {
32060
32248
  capName: "local-network",
32061
32249
  capScope: "system",
32062
32250
  addonId: null,
32063
32251
  access: "delete"
32064
32252
  },
32253
+ "localNetwork.revertToGeneratedCertificate": {
32254
+ capName: "local-network",
32255
+ capScope: "system",
32256
+ addonId: null,
32257
+ access: "create"
32258
+ },
32065
32259
  "localNetwork.setAllowedAddresses": {
32066
32260
  capName: "local-network",
32067
32261
  capScope: "system",
@@ -32074,6 +32268,18 @@ Object.freeze({
32074
32268
  addonId: null,
32075
32269
  access: "create"
32076
32270
  },
32271
+ "localNetwork.setViewerEndpoints": {
32272
+ capName: "local-network",
32273
+ capScope: "system",
32274
+ addonId: null,
32275
+ access: "create"
32276
+ },
32277
+ "localNetwork.uploadCertificate": {
32278
+ capName: "local-network",
32279
+ capScope: "system",
32280
+ addonId: null,
32281
+ access: "create"
32282
+ },
32077
32283
  "lockControl.lock": {
32078
32284
  capName: "lock-control",
32079
32285
  capScope: "device",
@@ -34954,6 +35160,12 @@ Object.freeze({
34954
35160
  addonId: null,
34955
35161
  access: "create"
34956
35162
  },
35163
+ "terminalSession.updateInstance": {
35164
+ capName: "terminal-session",
35165
+ capScope: "system",
35166
+ addonId: null,
35167
+ access: "create"
35168
+ },
34957
35169
  "terminalSession.writeInput": {
34958
35170
  capName: "terminal-session",
34959
35171
  capScope: "system",
@@ -37441,6 +37653,35 @@ Object.freeze(Object.fromEntries([{
37441
37653
  }]
37442
37654
  }].map((s) => [s.stepId, s.defaultModelId])));
37443
37655
  string().min(1);
37656
+ var CLUSTER_STEP_SETTING_FIELDS = [{
37657
+ stepId: "face-embedding",
37658
+ key: "minLandmarkFaceSize",
37659
+ label: "Min face size for recognition (detection px)",
37660
+ 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.",
37661
+ type: "slider",
37662
+ min: 0,
37663
+ max: 64,
37664
+ step: 2,
37665
+ default: 24
37666
+ }];
37667
+ function clusterStepSettingKey(stepId, fieldKey) {
37668
+ return `clusterStepSetting:${stepId}:${fieldKey}`;
37669
+ }
37670
+ var ClusterSettingNumberSchema = number().finite();
37671
+ function readClusterStepSettings(config) {
37672
+ const out = {};
37673
+ for (const field of CLUSTER_STEP_SETTING_FIELDS) {
37674
+ const parsed = ClusterSettingNumberSchema.safeParse(config[clusterStepSettingKey(field.stepId, field.key)]);
37675
+ const value = parsed.success ? parsed.data : field.default;
37676
+ const existing = out[field.stepId] ?? {};
37677
+ out[field.stepId] = {
37678
+ ...existing,
37679
+ [field.key]: value
37680
+ };
37681
+ }
37682
+ return out;
37683
+ }
37684
+ readClusterStepSettings({});
37444
37685
  object({
37445
37686
  /**
37446
37687
  * 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-provider-velux",
3
- "version": "0.2.25",
3
+ "version": "0.2.27",
4
4
  "description": "Velux KLF-200 device-provider addon for CamStack — local-gateway window + shutter covers (positional, no tilt)",
5
5
  "keywords": [
6
6
  "camstack",