@camstack/addon-tailscale 1.2.26 → 1.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.
@@ -24,7 +24,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
24
24
  enumerable: true
25
25
  }) : target, mod));
26
26
  //#endregion
27
- const require_dist = require("../dist-CByJkMGY.js");
27
+ const require_dist = require("../dist-BrkbC1tE.js");
28
28
  let node_child_process = require("node:child_process");
29
29
  let node_util = require("node:util");
30
30
  let node_fs = require("node:fs");
@@ -1,4 +1,4 @@
1
- import { a as EventCategory, i as BaseAddon, n as networkAccessCapability, r as BOOT_RECOVERY_BACKOFF_MS, t as meshNetworkCapability } from "../dist-C8q1YCua.mjs";
1
+ import { a as EventCategory, i as BaseAddon, n as networkAccessCapability, r as BOOT_RECOVERY_BACKOFF_MS, t as meshNetworkCapability } from "../dist-CovkuhH2.mjs";
2
2
  import { execFile, spawn } from "node:child_process";
3
3
  import { promisify } from "node:util";
4
4
  import * as fs from "node:fs";
@@ -8037,6 +8037,15 @@ var LabelDefinitionSchema = object({
8037
8037
  description: string().optional(),
8038
8038
  icon: string().optional()
8039
8039
  });
8040
+ var ClassMapDefinitionSchema = object({
8041
+ mapping: record(string(), _enum([
8042
+ "person",
8043
+ "vehicle",
8044
+ "animal",
8045
+ "package"
8046
+ ])),
8047
+ preserveOriginal: boolean()
8048
+ });
8040
8049
  var MODEL_FORMATS = [
8041
8050
  "onnx",
8042
8051
  "coreml",
@@ -8215,7 +8224,13 @@ var ModelCatalogEntrySchema = object({
8215
8224
  * `id` stays the source of truth for resolution/download/persistence; grouping
8216
8225
  * is a presentation overlay resolved back to an `id`.
8217
8226
  */
8218
- group: ModelVariantGroupSchema.optional()
8227
+ group: ModelVariantGroupSchema.optional(),
8228
+ /**
8229
+ * Per-MODEL class map override. Absent ⇒ the step's `StepDefinition.classMap`
8230
+ * applies (Frigate / COCO public catalog). Set on a custom model whose raw
8231
+ * labels already ARE the CamStack macros (Scrypted identity map).
8232
+ */
8233
+ classMap: ClassMapDefinitionSchema.optional()
8219
8234
  });
8220
8235
  var ConvertTargetSchema = discriminatedUnion("format", [object({
8221
8236
  format: literal("openvino"),
@@ -8244,7 +8259,8 @@ var ModelConvertMetadataSchema = object({
8244
8259
  "ocr",
8245
8260
  "segmentation"
8246
8261
  ]),
8247
- faceAlignment: boolean().optional()
8262
+ faceAlignment: boolean().optional(),
8263
+ classMap: ClassMapDefinitionSchema.optional()
8248
8264
  });
8249
8265
  var ConvertResultSchema = object({
8250
8266
  entry: ModelCatalogEntrySchema,
@@ -17252,6 +17268,33 @@ var NativeCropRefSchema = object({
17252
17268
  h: number()
17253
17269
  })
17254
17270
  });
17271
+ object({
17272
+ crop: object({
17273
+ left: number(),
17274
+ top: number(),
17275
+ width: number().positive(),
17276
+ height: number().positive()
17277
+ }).optional(),
17278
+ content: object({
17279
+ width: number().int().positive(),
17280
+ height: number().int().positive()
17281
+ }),
17282
+ fit: _enum(["stretch", "contain"]),
17283
+ format: _enum([
17284
+ "rgb",
17285
+ "gray",
17286
+ "jpeg"
17287
+ ])
17288
+ });
17289
+ var FrameRefSchema = object({
17290
+ registryId: string().min(1),
17291
+ id: string().min(1),
17292
+ width: number().int().positive(),
17293
+ height: number().int().positive(),
17294
+ format: _enum(["rgb", "gray"]),
17295
+ timestamp: number(),
17296
+ capturedAt: number().optional()
17297
+ });
17255
17298
  var ModelFormatSchema$1 = _enum([
17256
17299
  "onnx",
17257
17300
  "coreml",
@@ -17496,6 +17539,12 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
17496
17539
  steps: array(PipelineStepInputSchema).min(1),
17497
17540
  frame: FrameInputSchema.optional(),
17498
17541
  /**
17542
+ * Process-local lazy frame. Valid only when caller and provider resolve
17543
+ * in the same execution-group process; split/cross-node callers use
17544
+ * `frame`/`image` inline compatibility instead.
17545
+ */
17546
+ frameRef: FrameRefSchema.optional(),
17547
+ /**
17499
17548
  * CB5 shm passthrough — a `FrameHandle` naming the same ring slot
17500
17549
  * the decoded pixels live in. One more member of the one-of
17501
17550
  * frame/frameHandle/image/imageBase64/referenceImage group.
@@ -17751,7 +17800,10 @@ var NativeCropResultSchema = object({
17751
17800
  * Which source served this crop, so a quality-sensitive consumer (the native
17752
17801
  * `keyFrame`) can reject a degraded fallback:
17753
17802
  * - `native` — cut from the decode worker's retained NATIVE surface (the
17754
- * quality path).
17803
+ * quality path). A subject-tile serve is also native-resolution and stays
17804
+ * `native` here: the public enum cannot name `tile` without a breaking cap
17805
+ * change. Runner telemetry distinguishes lease vs tile via `source` on the
17806
+ * internal crop result (`nativeHits` vs `tileHits`).
17755
17807
  * - `ram-fullframe` — the native surface MISSED but the request was full-frame,
17756
17808
  * so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
17757
17809
  * the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
@@ -18242,12 +18294,41 @@ var RunnerLocalLoadSchema = object({
18242
18294
  * legacy `OrchestratorMetricsSchema` shape so existing dashboards keep
18243
18295
  * working unchanged when they switch to reading from the runner cap.
18244
18296
  */
18297
+ var FrameLazyCountersSchema = object({
18298
+ framesDecoded: number(),
18299
+ framesAdmitted: number(),
18300
+ framesDroppedPixelFree: number(),
18301
+ viewsMaterialized: number(),
18302
+ viewsSkipped: number(),
18303
+ workerToRunnerBytes: number(),
18304
+ runnerToPoolRawBytes: number(),
18305
+ runnerToPoolJpegBytes: number(),
18306
+ onDemandFullFrameRequests: number(),
18307
+ onDemandCropRequests: number(),
18308
+ nativeHits: number(),
18309
+ nativeMisses: number(),
18310
+ tileHits: number(),
18311
+ tileMisses: number(),
18312
+ fallbackHits: number(),
18313
+ fallbackMisses: number(),
18314
+ retainedWritesAvoided: number(),
18315
+ residentRefs: number(),
18316
+ residentBytes: number(),
18317
+ releases: number(),
18318
+ evictions: number(),
18319
+ staleMisses: number()
18320
+ });
18321
+ var FrameLazyMetricsSchema = object({
18322
+ node: FrameLazyCountersSchema,
18323
+ cameras: array(FrameLazyCountersSchema.extend({ deviceId: number() }))
18324
+ });
18245
18325
  var RunnerLocalMetricsSchema = object({
18246
18326
  nodeId: string(),
18247
18327
  activeCameras: number(),
18248
18328
  throttledCameras: number(),
18249
18329
  avgInferenceTimeMs: number(),
18250
- queueDepth: number()
18330
+ queueDepth: number(),
18331
+ frameLazy: FrameLazyMetricsSchema.optional()
18251
18332
  });
18252
18333
  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({
18253
18334
  handle: FrameHandleSchema,
@@ -19547,6 +19628,9 @@ method(_void(), ProviderInfoSchema), method(object({ config: record(string(), un
19547
19628
  location: StorageLocationSchema,
19548
19629
  relativePath: string()
19549
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());
19550
19634
  /**
19551
19635
  * A live terminal session hosted by the provider addon. Output and input do
19552
19636
  * NOT flow through the capability — they use the addon data plane
@@ -19576,7 +19660,14 @@ var TerminalSessionInfoSchema = object({
19576
19660
  var TerminalProfileInfoSchema = object({
19577
19661
  profileId: string(),
19578
19662
  label: string(),
19579
- 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()
19580
19671
  });
19581
19672
  /**
19582
19673
  * A durable operator-created Terminal instance. Profiles are templates; only
@@ -19589,7 +19680,12 @@ var TerminalInstanceInfoSchema = object({
19589
19680
  profileId: string(),
19590
19681
  profileLabel: string(),
19591
19682
  name: string(),
19592
- enabled: boolean()
19683
+ enabled: boolean(),
19684
+ executable: string(),
19685
+ args: array(string()).readonly(),
19686
+ cwd: string(),
19687
+ environment: array(string()).readonly(),
19688
+ profileSettings: ProfileSettingsBagSchema
19593
19689
  });
19594
19690
  var TerminalLegacyCameraSchema = object({
19595
19691
  stableId: string(),
@@ -19619,7 +19715,23 @@ var TerminalOutputBatchSchema = object({
19619
19715
  method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }), method(_void(), array(TerminalInstanceInfoSchema).readonly(), { auth: "admin" }), method(object({
19620
19716
  targetNodeId: string().min(1),
19621
19717
  profileId: string().min(1),
19622
- 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()
19623
19735
  }), TerminalInstanceInfoSchema, {
19624
19736
  kind: "mutation",
19625
19737
  auth: "admin"
@@ -19641,7 +19753,11 @@ method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }),
19641
19753
  }), method(_void(), array(TerminalSessionInfoSchema).readonly(), { auth: "admin" }), method(object({
19642
19754
  profileId: string(),
19643
19755
  cols: number().int().positive(),
19644
- 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()
19645
19761
  }), TerminalSessionInfoSchema, {
19646
19762
  kind: "mutation",
19647
19763
  auth: "admin"
@@ -22423,10 +22539,10 @@ DeviceType.LawnMower, method(object({ deviceId: number().int().nonnegative() }),
22423
22539
  *
22424
22540
  * • The SDK (mobile / web client) consumes `getConnectionEndpoints()`
22425
22541
  * to receive an ordered list of candidate base URLs it should race
22426
- * on connect — LAN IPv4 first (lowest latency when on same network),
22427
- * then public hostname (if a tunnel is up), then IPv6. The SDK can
22428
- * race them with short timeouts and stick with the winner for the
22429
- * 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.
22430
22546
  *
22431
22547
  * Why hub-only: agents are not directly addressable by the operator's
22432
22548
  * clients — they reverse-connect to the hub. Exposing their interfaces
@@ -22581,6 +22697,17 @@ var NotificationEndpointSchema = object({
22581
22697
  /** What the ranking currently resolves to (null when nothing is reachable). */
22582
22698
  resolved: string().nullable()
22583
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
+ });
22584
22711
  var AllowedAddressesSchema = object({
22585
22712
  /**
22586
22713
  * Allowlist of interface addresses operators have explicitly opted
@@ -22589,6 +22716,20 @@ var AllowedAddressesSchema = object({
22589
22716
  * Network Addresses admin page and persisted by the addon.
22590
22717
  */
22591
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
+ });
22592
22733
  method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(object({
22593
22734
  /**
22594
22735
  * LEGACY HINT — do not send from new code. Kept optional so clients
@@ -22598,17 +22739,31 @@ method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(obje
22598
22739
  */
22599
22740
  port: number().int().min(1).max(65535).optional(),
22600
22741
  /** Include `http(s)://127.0.0.1:<port>` as the lowest-priority
22601
- * candidate. Default `true`. */
22742
+ * candidate. Default `false` — loopback is not a client route. */
22602
22743
  includeLoopback: boolean().optional(),
22603
- /** Skip IPv6 entries. Some legacy clients can't parse them.
22604
- * 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`. */
22605
22747
  ipv4Only: boolean().optional(),
22606
22748
  /** Scheme to emit for LAN/loopback URLs. Default `'http'`.
22607
22749
  * Pass `'https'` when the caller is itself loaded over HTTPS
22608
22750
  * to avoid mixed-content blocks in the browser. The public
22609
22751
  * tunnel always emits `https://` regardless. */
22610
22752
  scheme: _enum(["http", "https"]).optional()
22611
- }), 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
+ });
22612
22767
  object({
22613
22768
  /** Lifecycle state of the lock. `jammed` means the motor reported
22614
22769
  * failure to reach the target — operator intervention required. */
@@ -28432,6 +28587,12 @@ Object.freeze({
28432
28587
  addonId: null,
28433
28588
  access: "create"
28434
28589
  },
28590
+ "localNetwork.downloadCa": {
28591
+ capName: "local-network",
28592
+ capScope: "system",
28593
+ addonId: null,
28594
+ access: "view"
28595
+ },
28435
28596
  "localNetwork.getAllowedAddresses": {
28436
28597
  capName: "local-network",
28437
28598
  capScope: "system",
@@ -28456,18 +28617,42 @@ Object.freeze({
28456
28617
  addonId: null,
28457
28618
  access: "view"
28458
28619
  },
28620
+ "localNetwork.getTlsStatus": {
28621
+ capName: "local-network",
28622
+ capScope: "system",
28623
+ addonId: null,
28624
+ access: "view"
28625
+ },
28626
+ "localNetwork.getViewerEndpoints": {
28627
+ capName: "local-network",
28628
+ capScope: "system",
28629
+ addonId: null,
28630
+ access: "view"
28631
+ },
28459
28632
  "localNetwork.list": {
28460
28633
  capName: "local-network",
28461
28634
  capScope: "system",
28462
28635
  addonId: null,
28463
28636
  access: "view"
28464
28637
  },
28638
+ "localNetwork.regenerateCertificate": {
28639
+ capName: "local-network",
28640
+ capScope: "system",
28641
+ addonId: null,
28642
+ access: "create"
28643
+ },
28465
28644
  "localNetwork.resetAllowlistToBestMatch": {
28466
28645
  capName: "local-network",
28467
28646
  capScope: "system",
28468
28647
  addonId: null,
28469
28648
  access: "delete"
28470
28649
  },
28650
+ "localNetwork.revertToGeneratedCertificate": {
28651
+ capName: "local-network",
28652
+ capScope: "system",
28653
+ addonId: null,
28654
+ access: "create"
28655
+ },
28471
28656
  "localNetwork.setAllowedAddresses": {
28472
28657
  capName: "local-network",
28473
28658
  capScope: "system",
@@ -28480,6 +28665,18 @@ Object.freeze({
28480
28665
  addonId: null,
28481
28666
  access: "create"
28482
28667
  },
28668
+ "localNetwork.setViewerEndpoints": {
28669
+ capName: "local-network",
28670
+ capScope: "system",
28671
+ addonId: null,
28672
+ access: "create"
28673
+ },
28674
+ "localNetwork.uploadCertificate": {
28675
+ capName: "local-network",
28676
+ capScope: "system",
28677
+ addonId: null,
28678
+ access: "create"
28679
+ },
28483
28680
  "lockControl.lock": {
28484
28681
  capName: "lock-control",
28485
28682
  capScope: "device",
@@ -31360,6 +31557,12 @@ Object.freeze({
31360
31557
  addonId: null,
31361
31558
  access: "create"
31362
31559
  },
31560
+ "terminalSession.updateInstance": {
31561
+ capName: "terminal-session",
31562
+ capScope: "system",
31563
+ addonId: null,
31564
+ access: "create"
31565
+ },
31363
31566
  "terminalSession.writeInput": {
31364
31567
  capName: "terminal-session",
31365
31568
  capScope: "system",
@@ -33847,6 +34050,35 @@ Object.freeze(Object.fromEntries([{
33847
34050
  }]
33848
34051
  }].map((s) => [s.stepId, s.defaultModelId])));
33849
34052
  string().min(1);
34053
+ var CLUSTER_STEP_SETTING_FIELDS = [{
34054
+ stepId: "face-embedding",
34055
+ key: "minLandmarkFaceSize",
34056
+ label: "Min face size for recognition (detection px)",
34057
+ 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.",
34058
+ type: "slider",
34059
+ min: 0,
34060
+ max: 64,
34061
+ step: 2,
34062
+ default: 24
34063
+ }];
34064
+ function clusterStepSettingKey(stepId, fieldKey) {
34065
+ return `clusterStepSetting:${stepId}:${fieldKey}`;
34066
+ }
34067
+ var ClusterSettingNumberSchema = number().finite();
34068
+ function readClusterStepSettings(config) {
34069
+ const out = {};
34070
+ for (const field of CLUSTER_STEP_SETTING_FIELDS) {
34071
+ const parsed = ClusterSettingNumberSchema.safeParse(config[clusterStepSettingKey(field.stepId, field.key)]);
34072
+ const value = parsed.success ? parsed.data : field.default;
34073
+ const existing = out[field.stepId] ?? {};
34074
+ out[field.stepId] = {
34075
+ ...existing,
34076
+ [field.key]: value
34077
+ };
34078
+ }
34079
+ return out;
34080
+ }
34081
+ readClusterStepSettings({});
33850
34082
  object({
33851
34083
  /**
33852
34084
  * Fraction of the box's own size added on EACH side before cutting.
@@ -8037,6 +8037,15 @@ var LabelDefinitionSchema = object({
8037
8037
  description: string().optional(),
8038
8038
  icon: string().optional()
8039
8039
  });
8040
+ var ClassMapDefinitionSchema = object({
8041
+ mapping: record(string(), _enum([
8042
+ "person",
8043
+ "vehicle",
8044
+ "animal",
8045
+ "package"
8046
+ ])),
8047
+ preserveOriginal: boolean()
8048
+ });
8040
8049
  var MODEL_FORMATS = [
8041
8050
  "onnx",
8042
8051
  "coreml",
@@ -8215,7 +8224,13 @@ var ModelCatalogEntrySchema = object({
8215
8224
  * `id` stays the source of truth for resolution/download/persistence; grouping
8216
8225
  * is a presentation overlay resolved back to an `id`.
8217
8226
  */
8218
- group: ModelVariantGroupSchema.optional()
8227
+ group: ModelVariantGroupSchema.optional(),
8228
+ /**
8229
+ * Per-MODEL class map override. Absent ⇒ the step's `StepDefinition.classMap`
8230
+ * applies (Frigate / COCO public catalog). Set on a custom model whose raw
8231
+ * labels already ARE the CamStack macros (Scrypted identity map).
8232
+ */
8233
+ classMap: ClassMapDefinitionSchema.optional()
8219
8234
  });
8220
8235
  var ConvertTargetSchema = discriminatedUnion("format", [object({
8221
8236
  format: literal("openvino"),
@@ -8244,7 +8259,8 @@ var ModelConvertMetadataSchema = object({
8244
8259
  "ocr",
8245
8260
  "segmentation"
8246
8261
  ]),
8247
- faceAlignment: boolean().optional()
8262
+ faceAlignment: boolean().optional(),
8263
+ classMap: ClassMapDefinitionSchema.optional()
8248
8264
  });
8249
8265
  var ConvertResultSchema = object({
8250
8266
  entry: ModelCatalogEntrySchema,
@@ -17252,6 +17268,33 @@ var NativeCropRefSchema = object({
17252
17268
  h: number()
17253
17269
  })
17254
17270
  });
17271
+ object({
17272
+ crop: object({
17273
+ left: number(),
17274
+ top: number(),
17275
+ width: number().positive(),
17276
+ height: number().positive()
17277
+ }).optional(),
17278
+ content: object({
17279
+ width: number().int().positive(),
17280
+ height: number().int().positive()
17281
+ }),
17282
+ fit: _enum(["stretch", "contain"]),
17283
+ format: _enum([
17284
+ "rgb",
17285
+ "gray",
17286
+ "jpeg"
17287
+ ])
17288
+ });
17289
+ var FrameRefSchema = object({
17290
+ registryId: string().min(1),
17291
+ id: string().min(1),
17292
+ width: number().int().positive(),
17293
+ height: number().int().positive(),
17294
+ format: _enum(["rgb", "gray"]),
17295
+ timestamp: number(),
17296
+ capturedAt: number().optional()
17297
+ });
17255
17298
  var ModelFormatSchema$1 = _enum([
17256
17299
  "onnx",
17257
17300
  "coreml",
@@ -17496,6 +17539,12 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
17496
17539
  steps: array(PipelineStepInputSchema).min(1),
17497
17540
  frame: FrameInputSchema.optional(),
17498
17541
  /**
17542
+ * Process-local lazy frame. Valid only when caller and provider resolve
17543
+ * in the same execution-group process; split/cross-node callers use
17544
+ * `frame`/`image` inline compatibility instead.
17545
+ */
17546
+ frameRef: FrameRefSchema.optional(),
17547
+ /**
17499
17548
  * CB5 shm passthrough — a `FrameHandle` naming the same ring slot
17500
17549
  * the decoded pixels live in. One more member of the one-of
17501
17550
  * frame/frameHandle/image/imageBase64/referenceImage group.
@@ -17751,7 +17800,10 @@ var NativeCropResultSchema = object({
17751
17800
  * Which source served this crop, so a quality-sensitive consumer (the native
17752
17801
  * `keyFrame`) can reject a degraded fallback:
17753
17802
  * - `native` — cut from the decode worker's retained NATIVE surface (the
17754
- * quality path).
17803
+ * quality path). A subject-tile serve is also native-resolution and stays
17804
+ * `native` here: the public enum cannot name `tile` without a breaking cap
17805
+ * change. Runner telemetry distinguishes lease vs tile via `source` on the
17806
+ * internal crop result (`nativeHits` vs `tileHits`).
17755
17807
  * - `ram-fullframe` — the native surface MISSED but the request was full-frame,
17756
17808
  * so the ≤640 RAM `RetainedFrameStore` served it (honest lower-res; legit for
17757
17809
  * the blank-frame guard / 640-snapshot resolve, NOT for the clean keyFrame).
@@ -18242,12 +18294,41 @@ var RunnerLocalLoadSchema = object({
18242
18294
  * legacy `OrchestratorMetricsSchema` shape so existing dashboards keep
18243
18295
  * working unchanged when they switch to reading from the runner cap.
18244
18296
  */
18297
+ var FrameLazyCountersSchema = object({
18298
+ framesDecoded: number(),
18299
+ framesAdmitted: number(),
18300
+ framesDroppedPixelFree: number(),
18301
+ viewsMaterialized: number(),
18302
+ viewsSkipped: number(),
18303
+ workerToRunnerBytes: number(),
18304
+ runnerToPoolRawBytes: number(),
18305
+ runnerToPoolJpegBytes: number(),
18306
+ onDemandFullFrameRequests: number(),
18307
+ onDemandCropRequests: number(),
18308
+ nativeHits: number(),
18309
+ nativeMisses: number(),
18310
+ tileHits: number(),
18311
+ tileMisses: number(),
18312
+ fallbackHits: number(),
18313
+ fallbackMisses: number(),
18314
+ retainedWritesAvoided: number(),
18315
+ residentRefs: number(),
18316
+ residentBytes: number(),
18317
+ releases: number(),
18318
+ evictions: number(),
18319
+ staleMisses: number()
18320
+ });
18321
+ var FrameLazyMetricsSchema = object({
18322
+ node: FrameLazyCountersSchema,
18323
+ cameras: array(FrameLazyCountersSchema.extend({ deviceId: number() }))
18324
+ });
18245
18325
  var RunnerLocalMetricsSchema = object({
18246
18326
  nodeId: string(),
18247
18327
  activeCameras: number(),
18248
18328
  throttledCameras: number(),
18249
18329
  avgInferenceTimeMs: number(),
18250
- queueDepth: number()
18330
+ queueDepth: number(),
18331
+ frameLazy: FrameLazyMetricsSchema.optional()
18251
18332
  });
18252
18333
  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({
18253
18334
  handle: FrameHandleSchema,
@@ -19547,6 +19628,9 @@ method(_void(), ProviderInfoSchema), method(object({ config: record(string(), un
19547
19628
  location: StorageLocationSchema,
19548
19629
  relativePath: string()
19549
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());
19550
19634
  /**
19551
19635
  * A live terminal session hosted by the provider addon. Output and input do
19552
19636
  * NOT flow through the capability — they use the addon data plane
@@ -19576,7 +19660,14 @@ var TerminalSessionInfoSchema = object({
19576
19660
  var TerminalProfileInfoSchema = object({
19577
19661
  profileId: string(),
19578
19662
  label: string(),
19579
- 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()
19580
19671
  });
19581
19672
  /**
19582
19673
  * A durable operator-created Terminal instance. Profiles are templates; only
@@ -19589,7 +19680,12 @@ var TerminalInstanceInfoSchema = object({
19589
19680
  profileId: string(),
19590
19681
  profileLabel: string(),
19591
19682
  name: string(),
19592
- enabled: boolean()
19683
+ enabled: boolean(),
19684
+ executable: string(),
19685
+ args: array(string()).readonly(),
19686
+ cwd: string(),
19687
+ environment: array(string()).readonly(),
19688
+ profileSettings: ProfileSettingsBagSchema
19593
19689
  });
19594
19690
  var TerminalLegacyCameraSchema = object({
19595
19691
  stableId: string(),
@@ -19619,7 +19715,23 @@ var TerminalOutputBatchSchema = object({
19619
19715
  method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }), method(_void(), array(TerminalInstanceInfoSchema).readonly(), { auth: "admin" }), method(object({
19620
19716
  targetNodeId: string().min(1),
19621
19717
  profileId: string().min(1),
19622
- 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()
19623
19735
  }), TerminalInstanceInfoSchema, {
19624
19736
  kind: "mutation",
19625
19737
  auth: "admin"
@@ -19641,7 +19753,11 @@ method(_void(), array(TerminalProfileInfoSchema).readonly(), { auth: "admin" }),
19641
19753
  }), method(_void(), array(TerminalSessionInfoSchema).readonly(), { auth: "admin" }), method(object({
19642
19754
  profileId: string(),
19643
19755
  cols: number().int().positive(),
19644
- 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()
19645
19761
  }), TerminalSessionInfoSchema, {
19646
19762
  kind: "mutation",
19647
19763
  auth: "admin"
@@ -22423,10 +22539,10 @@ DeviceType.LawnMower, method(object({ deviceId: number().int().nonnegative() }),
22423
22539
  *
22424
22540
  * • The SDK (mobile / web client) consumes `getConnectionEndpoints()`
22425
22541
  * to receive an ordered list of candidate base URLs it should race
22426
- * on connect — LAN IPv4 first (lowest latency when on same network),
22427
- * then public hostname (if a tunnel is up), then IPv6. The SDK can
22428
- * race them with short timeouts and stick with the winner for the
22429
- * 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.
22430
22546
  *
22431
22547
  * Why hub-only: agents are not directly addressable by the operator's
22432
22548
  * clients — they reverse-connect to the hub. Exposing their interfaces
@@ -22581,6 +22697,17 @@ var NotificationEndpointSchema = object({
22581
22697
  /** What the ranking currently resolves to (null when nothing is reachable). */
22582
22698
  resolved: string().nullable()
22583
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
+ });
22584
22711
  var AllowedAddressesSchema = object({
22585
22712
  /**
22586
22713
  * Allowlist of interface addresses operators have explicitly opted
@@ -22589,6 +22716,20 @@ var AllowedAddressesSchema = object({
22589
22716
  * Network Addresses admin page and persisted by the addon.
22590
22717
  */
22591
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
+ });
22592
22733
  method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(object({
22593
22734
  /**
22594
22735
  * LEGACY HINT — do not send from new code. Kept optional so clients
@@ -22598,17 +22739,31 @@ method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(obje
22598
22739
  */
22599
22740
  port: number().int().min(1).max(65535).optional(),
22600
22741
  /** Include `http(s)://127.0.0.1:<port>` as the lowest-priority
22601
- * candidate. Default `true`. */
22742
+ * candidate. Default `false` — loopback is not a client route. */
22602
22743
  includeLoopback: boolean().optional(),
22603
- /** Skip IPv6 entries. Some legacy clients can't parse them.
22604
- * 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`. */
22605
22747
  ipv4Only: boolean().optional(),
22606
22748
  /** Scheme to emit for LAN/loopback URLs. Default `'http'`.
22607
22749
  * Pass `'https'` when the caller is itself loaded over HTTPS
22608
22750
  * to avoid mixed-content blocks in the browser. The public
22609
22751
  * tunnel always emits `https://` regardless. */
22610
22752
  scheme: _enum(["http", "https"]).optional()
22611
- }), 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
+ });
22612
22767
  object({
22613
22768
  /** Lifecycle state of the lock. `jammed` means the motor reported
22614
22769
  * failure to reach the target — operator intervention required. */
@@ -28432,6 +28587,12 @@ Object.freeze({
28432
28587
  addonId: null,
28433
28588
  access: "create"
28434
28589
  },
28590
+ "localNetwork.downloadCa": {
28591
+ capName: "local-network",
28592
+ capScope: "system",
28593
+ addonId: null,
28594
+ access: "view"
28595
+ },
28435
28596
  "localNetwork.getAllowedAddresses": {
28436
28597
  capName: "local-network",
28437
28598
  capScope: "system",
@@ -28456,18 +28617,42 @@ Object.freeze({
28456
28617
  addonId: null,
28457
28618
  access: "view"
28458
28619
  },
28620
+ "localNetwork.getTlsStatus": {
28621
+ capName: "local-network",
28622
+ capScope: "system",
28623
+ addonId: null,
28624
+ access: "view"
28625
+ },
28626
+ "localNetwork.getViewerEndpoints": {
28627
+ capName: "local-network",
28628
+ capScope: "system",
28629
+ addonId: null,
28630
+ access: "view"
28631
+ },
28459
28632
  "localNetwork.list": {
28460
28633
  capName: "local-network",
28461
28634
  capScope: "system",
28462
28635
  addonId: null,
28463
28636
  access: "view"
28464
28637
  },
28638
+ "localNetwork.regenerateCertificate": {
28639
+ capName: "local-network",
28640
+ capScope: "system",
28641
+ addonId: null,
28642
+ access: "create"
28643
+ },
28465
28644
  "localNetwork.resetAllowlistToBestMatch": {
28466
28645
  capName: "local-network",
28467
28646
  capScope: "system",
28468
28647
  addonId: null,
28469
28648
  access: "delete"
28470
28649
  },
28650
+ "localNetwork.revertToGeneratedCertificate": {
28651
+ capName: "local-network",
28652
+ capScope: "system",
28653
+ addonId: null,
28654
+ access: "create"
28655
+ },
28471
28656
  "localNetwork.setAllowedAddresses": {
28472
28657
  capName: "local-network",
28473
28658
  capScope: "system",
@@ -28480,6 +28665,18 @@ Object.freeze({
28480
28665
  addonId: null,
28481
28666
  access: "create"
28482
28667
  },
28668
+ "localNetwork.setViewerEndpoints": {
28669
+ capName: "local-network",
28670
+ capScope: "system",
28671
+ addonId: null,
28672
+ access: "create"
28673
+ },
28674
+ "localNetwork.uploadCertificate": {
28675
+ capName: "local-network",
28676
+ capScope: "system",
28677
+ addonId: null,
28678
+ access: "create"
28679
+ },
28483
28680
  "lockControl.lock": {
28484
28681
  capName: "lock-control",
28485
28682
  capScope: "device",
@@ -31360,6 +31557,12 @@ Object.freeze({
31360
31557
  addonId: null,
31361
31558
  access: "create"
31362
31559
  },
31560
+ "terminalSession.updateInstance": {
31561
+ capName: "terminal-session",
31562
+ capScope: "system",
31563
+ addonId: null,
31564
+ access: "create"
31565
+ },
31363
31566
  "terminalSession.writeInput": {
31364
31567
  capName: "terminal-session",
31365
31568
  capScope: "system",
@@ -33847,6 +34050,35 @@ Object.freeze(Object.fromEntries([{
33847
34050
  }]
33848
34051
  }].map((s) => [s.stepId, s.defaultModelId])));
33849
34052
  string().min(1);
34053
+ var CLUSTER_STEP_SETTING_FIELDS = [{
34054
+ stepId: "face-embedding",
34055
+ key: "minLandmarkFaceSize",
34056
+ label: "Min face size for recognition (detection px)",
34057
+ 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.",
34058
+ type: "slider",
34059
+ min: 0,
34060
+ max: 64,
34061
+ step: 2,
34062
+ default: 24
34063
+ }];
34064
+ function clusterStepSettingKey(stepId, fieldKey) {
34065
+ return `clusterStepSetting:${stepId}:${fieldKey}`;
34066
+ }
34067
+ var ClusterSettingNumberSchema = number().finite();
34068
+ function readClusterStepSettings(config) {
34069
+ const out = {};
34070
+ for (const field of CLUSTER_STEP_SETTING_FIELDS) {
34071
+ const parsed = ClusterSettingNumberSchema.safeParse(config[clusterStepSettingKey(field.stepId, field.key)]);
34072
+ const value = parsed.success ? parsed.data : field.default;
34073
+ const existing = out[field.stepId] ?? {};
34074
+ out[field.stepId] = {
34075
+ ...existing,
34076
+ [field.key]: value
34077
+ };
34078
+ }
34079
+ return out;
34080
+ }
34081
+ readClusterStepSettings({});
33850
34082
  object({
33851
34083
  /**
33852
34084
  * Fraction of the box's own size added on EACH side before cutting.
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
2
2
  __esModule: { value: true },
3
3
  [Symbol.toStringTag]: { value: "Module" }
4
4
  });
5
- const require_dist = require("../dist-CByJkMGY.js");
5
+ const require_dist = require("../dist-BrkbC1tE.js");
6
6
  let node_crypto = require("node:crypto");
7
7
  let node_child_process = require("node:child_process");
8
8
  //#region src/ingress/tailscale-cli.ts
@@ -1,4 +1,4 @@
1
- import { a as EventCategory, i as BaseAddon, n as networkAccessCapability } from "../dist-C8q1YCua.mjs";
1
+ import { a as EventCategory, i as BaseAddon, n as networkAccessCapability } from "../dist-CovkuhH2.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import { execFile } from "node:child_process";
4
4
  import { promisify } from "node:util";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-tailscale",
3
- "version": "1.2.26",
3
+ "version": "1.2.27",
4
4
  "description": "Tailscale bundle for CamStack — joins the host to a tailnet (client) and exposes the hub via Serve/Funnel (ingress). Multi-entry npm package shipping 2 addons under a single bundle.",
5
5
  "keywords": [
6
6
  "camstack",