camstack 1.2.39 → 1.2.41

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.
@@ -14522,7 +14522,7 @@ function date4(params) {
14522
14522
  // ../../node_modules/zod/v4/classic/external.js
14523
14523
  config(en_default());
14524
14524
 
14525
- // ../types/dist/sleep-B8EIZt4h.mjs
14525
+ // ../types/dist/sleep-BLxqGLY0.mjs
14526
14526
  var WELL_KNOWN_TABS = [
14527
14527
  {
14528
14528
  id: "overview",
@@ -15989,6 +15989,13 @@ var ModelVariantGroupSchema = external_exports.object({
15989
15989
  */
15990
15990
  resolution: external_exports.number().int().positive().optional()
15991
15991
  });
15992
+ var MODEL_PROVIDER_IDS = [
15993
+ "camstack",
15994
+ "frigate",
15995
+ "scrypted",
15996
+ "custom"
15997
+ ];
15998
+ var ModelProviderIdSchema = external_exports.enum(MODEL_PROVIDER_IDS);
15992
15999
  var ModelCatalogEntrySchema = external_exports.object({
15993
16000
  id: external_exports.string(),
15994
16001
  name: external_exports.string(),
@@ -16086,6 +16093,12 @@ var ModelCatalogEntrySchema = external_exports.object({
16086
16093
  */
16087
16094
  group: ModelVariantGroupSchema.optional(),
16088
16095
  /**
16096
+ * Catalog source for the pipeline stepper's provider-first picker. Absent on
16097
+ * built-in CamStack entries (treated as `camstack`) and on registry rows
16098
+ * persisted before this field existed (`inferModelProvider` fills those).
16099
+ */
16100
+ provider: ModelProviderIdSchema.optional(),
16101
+ /**
16089
16102
  * Per-MODEL class map override. Absent ⇒ the step's `StepDefinition.classMap`
16090
16103
  * applies (Frigate / COCO public catalog). Set on a custom model whose raw
16091
16104
  * labels already ARE the CamStack macros (Scrypted identity map).
@@ -19859,6 +19872,21 @@ var LinkedDeviceSchema = external_exports.object({
19859
19872
  features: external_exports.array(external_exports.string()),
19860
19873
  producesTrackedEvents: external_exports.boolean().optional()
19861
19874
  });
19875
+ var LinkedDevicesForDeviceSchema = external_exports.object({
19876
+ deviceId: external_exports.number(),
19877
+ mode: LinkedDevicesModeSchema,
19878
+ devices: external_exports.array(LinkedDeviceSchema)
19879
+ });
19880
+ var DeviceBindingsForDeviceSchema = external_exports.object({
19881
+ deviceId: external_exports.number(),
19882
+ entries: external_exports.array(external_exports.object({
19883
+ capName: external_exports.string(),
19884
+ kind: external_exports.enum(["native", "wrapped"]),
19885
+ providerAddonId: external_exports.string(),
19886
+ providerNodeId: external_exports.string(),
19887
+ nativeAddonId: external_exports.string()
19888
+ }))
19889
+ });
19862
19890
  var SavedDeviceRowSchema = external_exports.object({
19863
19891
  /** Numeric id reserved at allocateDeviceId time. */
19864
19892
  id: external_exports.number(),
@@ -20216,7 +20244,21 @@ var deviceManagerCapability = {
20216
20244
  projection: external_exports.enum(["full", "slim"]).optional(),
20217
20245
  /** Return only camera devices. Filtering server-side instead of
20218
20246
  * shipping 293 rows to find 12. */
20219
- isCamera: external_exports.boolean().optional()
20247
+ isCamera: external_exports.boolean().optional(),
20248
+ /**
20249
+ * Return only these device ids. For the caller that already KNOWS the
20250
+ * handful it wants and needs a field the id-bearing answer does not
20251
+ * carry — the viewer's linked-devices panel joins `type` and `online`
20252
+ * onto ~8 linked ids and, unfiltered, dragged the fleet across to do
20253
+ * it: 433 KB slim / 958 KB full for 967 devices, on a query that
20254
+ * refetches on the reconcile interval, on a phone.
20255
+ *
20256
+ * Safe to send at a hub that predates it: Zod STRIPS unknown input
20257
+ * keys rather than rejecting them (verified against the live hub
20258
+ * 2026-08-25 — 967 rows came back), so an old hub answers exactly what
20259
+ * it answers today and the caller filters as it already does.
20260
+ */
20261
+ deviceIds: external_exports.array(external_exports.number()).optional()
20220
20262
  }), external_exports.array(DeviceInfoSchema)),
20221
20263
  /** Get a single device by numeric deviceId. */
20222
20264
  getDevice: method(external_exports.object({ deviceId: external_exports.number() }), DeviceInfoSchema.nullable()),
@@ -20235,6 +20277,23 @@ var deviceManagerCapability = {
20235
20277
  mode: LinkedDevicesModeSchema,
20236
20278
  devices: external_exports.array(LinkedDeviceSchema)
20237
20279
  })),
20280
+ /**
20281
+ * `getLinkedDevices` for MANY cameras, in one call.
20282
+ *
20283
+ * Not a convenience wrapper — a cost fix. Resolving one camera's linked set
20284
+ * needs the whole fleet as candidates (children ∪ same-location), so the
20285
+ * single-device path runs a full `listAll` per call. Asked per camera that
20286
+ * is N full-fleet sweeps of device-manager's event loop, and they do not
20287
+ * overlap: measured on the live hub 2026-08-25, 30 concurrent
20288
+ * `getLinkedDevices` took 4110 ms wall (median 4060 ms each) to return
20289
+ * 7260 bytes in total. The batch takes ONE sweep and one settings read per
20290
+ * camera.
20291
+ *
20292
+ * A device id that resolves to nothing still gets a row (`devices: []`) —
20293
+ * a caller that asked for thirty and got twenty-eight cannot tell which two
20294
+ * are missing, or that any are.
20295
+ */
20296
+ getLinkedDevicesBatch: method(external_exports.object({ deviceIds: external_exports.array(external_exports.number()) }), external_exports.array(LinkedDevicesForDeviceSchema)),
20238
20297
  /** Get stream sources for a camera device. */
20239
20298
  getStreamSources: method(external_exports.object({ deviceId: external_exports.number() }), external_exports.array(StreamSourceEntrySchema$1)),
20240
20299
  /** Get config entries (key + value + description) for a device. */
@@ -20292,16 +20351,22 @@ var deviceManagerCapability = {
20292
20351
  * currently-active provider (native or wrapper) + the underlying native
20293
20352
  * addon id, so consumers can decide routing without re-running discovery.
20294
20353
  */
20295
- getBindings: method(external_exports.object({ deviceId: external_exports.number() }), external_exports.object({
20296
- deviceId: external_exports.number(),
20297
- entries: external_exports.array(external_exports.object({
20298
- capName: external_exports.string(),
20299
- kind: external_exports.enum(["native", "wrapped"]),
20300
- providerAddonId: external_exports.string(),
20301
- providerNodeId: external_exports.string(),
20302
- nativeAddonId: external_exports.string()
20303
- }))
20304
- })),
20354
+ getBindings: method(external_exports.object({ deviceId: external_exports.number() }), DeviceBindingsForDeviceSchema),
20355
+ /**
20356
+ * `getBindings` for a NAMED set of devices, in one call.
20357
+ *
20358
+ * Between `getBindings` (one device) and `getAllBindings` (all 988) there
20359
+ * was nothing, so a caller that needs seventy-five either pays
20360
+ * seventy-five round-trips or drags the whole fleet across. Measured on
20361
+ * the live hub 2026-08-25: 75 concurrent `getBindings` = 1211 ms / 118 KB,
20362
+ * `getAllBindings({})` = 511 ms / 679 KB. Neither is the right answer to
20363
+ * "these seventy-five".
20364
+ *
20365
+ * Same resolver, same routing rules, same per-device shape as
20366
+ * `getBindings`; ids are deduped and a device with no bindings answers
20367
+ * `entries: []` rather than dropping out.
20368
+ */
20369
+ getBindingsBatch: method(external_exports.object({ deviceIds: external_exports.array(external_exports.number()) }), external_exports.array(DeviceBindingsForDeviceSchema)),
20305
20370
  /**
20306
20371
  * Return the binding map for every device known to the hub. Used by
20307
20372
  * `SystemManager` warm-boot: a single round-trip resolves the
@@ -20310,16 +20375,7 @@ var deviceManagerCapability = {
20310
20375
  * device add/remove) — clients invalidate via the
20311
20376
  * `capability.binding-changed` event.
20312
20377
  */
20313
- getAllBindings: method(external_exports.object({}), external_exports.array(external_exports.object({
20314
- deviceId: external_exports.number(),
20315
- entries: external_exports.array(external_exports.object({
20316
- capName: external_exports.string(),
20317
- kind: external_exports.enum(["native", "wrapped"]),
20318
- providerAddonId: external_exports.string(),
20319
- providerNodeId: external_exports.string(),
20320
- nativeAddonId: external_exports.string()
20321
- }))
20322
- }))),
20378
+ getAllBindings: method(external_exports.object({}), external_exports.array(DeviceBindingsForDeviceSchema)),
20323
20379
  /**
20324
20380
  * Activate (or deactivate) a wrapper addon for a (device, cap) pair.
20325
20381
  * Persists the binding via ctx.settings. active=false clears the wrapper
@@ -22757,14 +22813,22 @@ var NcOccupancyConditionSchema = external_exports.object({
22757
22813
  sustainSeconds: external_exports.number().int().min(0).max(3600).default(15)
22758
22814
  });
22759
22815
  var NcAudioConditionSchema = external_exports.object({
22760
- /** LABEL MODE: audio macro labels. Present ⇒ fires on the first labelled frame. */
22816
+ /** LABEL MODE: audio macro labels. Present ⇒ count-in-window confirm. */
22761
22817
  labels: external_exports.array(external_exports.string().min(1)).min(1).optional(),
22762
22818
  /** LEVEL MODE: floor in dBFS (negative-going, `0` = full scale). */
22763
22819
  dbThreshold: external_exports.number().min(-96).max(0).optional(),
22764
22820
  /** LEVEL MODE ONLY: percentage of the window's samples that must be hits (1–100). */
22765
22821
  hitPercent: external_exports.number().int().min(1).max(100).default(60),
22766
22822
  /** LEVEL MODE ONLY: length of the sampling window in seconds. */
22767
- samplingSeconds: external_exports.number().int().min(1).max(300).default(10)
22823
+ samplingSeconds: external_exports.number().int().min(1).max(300).default(10),
22824
+ /**
22825
+ * LABEL MODE: how many labelled frames must land inside
22826
+ * {@link NcAudioConditionSchema.shape.confirmWindowSec} before dispatch.
22827
+ * Absent ⇒ 2 (the matcher default). `1` is first-frame fire.
22828
+ */
22829
+ confirmHits: external_exports.number().int().min(1).max(20).optional(),
22830
+ /** LABEL MODE: the window those frames must share, in seconds. Absent ⇒ 5. */
22831
+ confirmWindowSec: external_exports.number().int().min(1).max(60).optional()
22768
22832
  });
22769
22833
  var NcCrossingSchema = external_exports.enum([
22770
22834
  "enter",
@@ -24582,6 +24646,46 @@ var RecentTracksPageSchema = external_exports.object({
24582
24646
  /** Cursor for the next page, or null when this page is the last. */
24583
24647
  nextCursor: external_exports.string().nullable()
24584
24648
  });
24649
+ var LIST_GROUPS_DEFAULT_LIMIT = 40;
24650
+ var LIST_GROUPS_MAX_LIMIT = 100;
24651
+ var AnalyticsGroupRecordSchema = external_exports.object({
24652
+ id: external_exports.string(),
24653
+ deviceId: external_exports.number().int(),
24654
+ openedAt: external_exports.number().int(),
24655
+ closedAt: external_exports.number().int(),
24656
+ timestamp: external_exports.number().int(),
24657
+ memberCount: external_exports.number().int(),
24658
+ memberTrackIds: external_exports.array(external_exports.string()).readonly(),
24659
+ className: external_exports.string(),
24660
+ classes: external_exports.array(external_exports.string()).readonly(),
24661
+ /** Relative event-media path, or null when the group has no picture yet. */
24662
+ mediaUrl: external_exports.string().nullable(),
24663
+ singleton: external_exports.boolean()
24664
+ });
24665
+ var AnalyticsGroupMemberSchema = external_exports.object({
24666
+ trackId: external_exports.string(),
24667
+ deviceId: external_exports.number().int(),
24668
+ className: external_exports.string(),
24669
+ firstSeen: external_exports.number().int(),
24670
+ lastSeen: external_exports.number().int(),
24671
+ mediaUrl: external_exports.string().nullable()
24672
+ });
24673
+ var AnalyticsGroupDetailSchema = AnalyticsGroupRecordSchema.extend({ members: external_exports.array(AnalyticsGroupMemberSchema).readonly() });
24674
+ var ListGroupsQueryInput = external_exports.object({
24675
+ /** Devices to merge. An empty array yields `{ groups: [], nextCursor: null }`. */
24676
+ deviceIds: external_exports.array(external_exports.number()),
24677
+ /** Window lower bound on `closedAt` (inclusive). */
24678
+ since: external_exports.number().optional(),
24679
+ /** Window upper bound on `openedAt` (inclusive). */
24680
+ until: external_exports.number().optional(),
24681
+ limit: external_exports.number().int().min(1).max(LIST_GROUPS_MAX_LIMIT).default(LIST_GROUPS_DEFAULT_LIMIT),
24682
+ /** Opaque continuation cursor from a previous page's `nextCursor`. */
24683
+ cursor: external_exports.string().optional()
24684
+ });
24685
+ var ListGroupsPageSchema = external_exports.object({
24686
+ groups: external_exports.array(AnalyticsGroupRecordSchema).readonly(),
24687
+ nextCursor: external_exports.string().nullable()
24688
+ });
24585
24689
  var KeyEventQueryInput = external_exports.object({
24586
24690
  deviceId: external_exports.number(),
24587
24691
  /** Window lower bound (track firstSeen ≥ since). */
@@ -24657,7 +24761,9 @@ var TrackCascadeCountsSchema = external_exports.object({
24657
24761
  /** Unassigned plate reads removed (best-effort; plate leg deferred to plate-intelligence). */
24658
24762
  plates: external_exports.number().int(),
24659
24763
  /** Per-track CLIP search vectors removed (best-effort). */
24660
- embeddings: external_exports.number().int()
24764
+ embeddings: external_exports.number().int(),
24765
+ /** Group membership + group rows removed with their last member (best-effort). */
24766
+ groups: external_exports.number().int()
24661
24767
  });
24662
24768
  var DiskReconcileCountsSchema = external_exports.object({
24663
24769
  mediaDropped: external_exports.number().int(),
@@ -24799,6 +24905,16 @@ var pipelineAnalyticsCapability = {
24799
24905
  * are not included (same contract as `listTracks`).
24800
24906
  */
24801
24907
  listRecentTracks: method(RecentTracksQueryInput, RecentTracksPageSchema),
24908
+ /**
24909
+ * Batched co-moving group listing — the Groups feed. Same merge/cursor
24910
+ * contract as {@link listRecentTracks}. A group is a sealed partition of
24911
+ * one session; `getGroup` is the detail with members.
24912
+ */
24913
+ listGroups: method(ListGroupsQueryInput, ListGroupsPageSchema),
24914
+ getGroup: method(external_exports.object({
24915
+ deviceId: external_exports.number(),
24916
+ groupId: external_exports.string().min(1)
24917
+ }), AnalyticsGroupDetailSchema.nullable()),
24802
24918
  clearTracks: method(external_exports.object({ deviceId: external_exports.number() }), external_exports.void(), {
24803
24919
  kind: "mutation",
24804
24920
  auth: "admin"
@@ -25480,7 +25596,8 @@ var PipelineModelOptionSchema = external_exports.object({
25480
25596
  sizeMB: external_exports.number()
25481
25597
  })),
25482
25598
  group: ModelVariantGroupSchema.optional(),
25483
- legacy: external_exports.boolean().optional()
25599
+ legacy: external_exports.boolean().optional(),
25600
+ provider: ModelProviderIdSchema.optional()
25484
25601
  });
25485
25602
  var ConfigFieldBridge = external_exports.custom();
25486
25603
  var PipelineAddonSchemaSchema = external_exports.object({
@@ -33934,7 +34051,12 @@ var PlateInfoSchema = external_exports.object({
33934
34051
  plateBbox: BoundingBoxSchema.optional(),
33935
34052
  /** keyFrame parity: MediaStore key of the track's native-resolution key frame. */
33936
34053
  keyFrameMediaKey: external_exports.string().optional(),
33937
- base64: external_exports.string().optional()
34054
+ base64: external_exports.string().optional(),
34055
+ /**
34056
+ * Same crop as a data-plane URL. `getPlateByTrack` returns this and
34057
+ * never inlines JPEG; `listPlates` still inlines for the admin-ui.
34058
+ */
34059
+ cropUrl: external_exports.string().optional()
33938
34060
  });
33939
34061
  var MediaFileLiteSchema = external_exports.object({
33940
34062
  key: external_exports.string(),
@@ -38133,6 +38255,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
38133
38255
  addonId: null,
38134
38256
  access: "view"
38135
38257
  },
38258
+ "deviceManager.getBindingsBatch": {
38259
+ capName: "device-manager",
38260
+ capScope: "system",
38261
+ addonId: null,
38262
+ access: "view"
38263
+ },
38136
38264
  "deviceManager.getChildren": {
38137
38265
  capName: "device-manager",
38138
38266
  capScope: "system",
@@ -38193,6 +38321,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
38193
38321
  addonId: null,
38194
38322
  access: "view"
38195
38323
  },
38324
+ "deviceManager.getLinkedDevicesBatch": {
38325
+ capName: "device-manager",
38326
+ capScope: "system",
38327
+ addonId: null,
38328
+ access: "view"
38329
+ },
38196
38330
  "deviceManager.getRoleDisplayDefaults": {
38197
38331
  capName: "device-manager",
38198
38332
  capScope: "system",
@@ -39963,6 +40097,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
39963
40097
  addonId: null,
39964
40098
  access: "view"
39965
40099
  },
40100
+ "pipelineAnalytics.getGroup": {
40101
+ capName: "pipeline-analytics",
40102
+ capScope: "device",
40103
+ addonId: null,
40104
+ access: "view"
40105
+ },
39966
40106
  "pipelineAnalytics.getKeyEvents": {
39967
40107
  capName: "pipeline-analytics",
39968
40108
  capScope: "device",
@@ -40047,6 +40187,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
40047
40187
  addonId: null,
40048
40188
  access: "view"
40049
40189
  },
40190
+ "pipelineAnalytics.listGroups": {
40191
+ capName: "pipeline-analytics",
40192
+ capScope: "device",
40193
+ addonId: null,
40194
+ access: "view"
40195
+ },
40050
40196
  "pipelineAnalytics.listOpsLog": {
40051
40197
  capName: "pipeline-analytics",
40052
40198
  capScope: "device",
@@ -42828,6 +42974,11 @@ var METHOD_DEVICE_SELECTORS = Object.freeze({
42828
42974
  form: "single",
42829
42975
  optional: false
42830
42976
  }],
42977
+ "deviceManager.getBindingsBatch": [{
42978
+ name: "deviceIds",
42979
+ form: "array",
42980
+ optional: false
42981
+ }],
42831
42982
  "deviceManager.getChildren": [{
42832
42983
  name: "parentDeviceId",
42833
42984
  form: "single",
@@ -42873,6 +43024,11 @@ var METHOD_DEVICE_SELECTORS = Object.freeze({
42873
43024
  form: "single",
42874
43025
  optional: false
42875
43026
  }],
43027
+ "deviceManager.getLinkedDevicesBatch": [{
43028
+ name: "deviceIds",
43029
+ form: "array",
43030
+ optional: false
43031
+ }],
42876
43032
  "deviceManager.getSettingsSchema": [{
42877
43033
  name: "deviceId",
42878
43034
  form: "single",
@@ -42893,6 +43049,11 @@ var METHOD_DEVICE_SELECTORS = Object.freeze({
42893
43049
  form: "single",
42894
43050
  optional: false
42895
43051
  }],
43052
+ "deviceManager.listAll": [{
43053
+ name: "deviceIds",
43054
+ form: "array",
43055
+ optional: true
43056
+ }],
42896
43057
  "deviceManager.loadConfig": [{
42897
43058
  name: "deviceId",
42898
43059
  form: "single",
@@ -43466,6 +43627,11 @@ var METHOD_DEVICE_SELECTORS = Object.freeze({
43466
43627
  form: "single",
43467
43628
  optional: false
43468
43629
  }],
43630
+ "pipelineAnalytics.getGroup": [{
43631
+ name: "deviceId",
43632
+ form: "single",
43633
+ optional: false
43634
+ }],
43469
43635
  "pipelineAnalytics.getKeyEvents": [{
43470
43636
  name: "deviceId",
43471
43637
  form: "single",
@@ -43521,6 +43687,11 @@ var METHOD_DEVICE_SELECTORS = Object.freeze({
43521
43687
  form: "array",
43522
43688
  optional: false
43523
43689
  }],
43690
+ "pipelineAnalytics.listGroups": [{
43691
+ name: "deviceIds",
43692
+ form: "array",
43693
+ optional: false
43694
+ }],
43524
43695
  "pipelineAnalytics.listOpsLog": [{
43525
43696
  name: "deviceId",
43526
43697
  form: "single",
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runDiscover
4
- } from "./chunk-VGIPYXDI.js";
4
+ } from "./chunk-WSQAFZ7F.js";
5
5
  import "./chunk-LMMQX4CK.js";
6
6
 
7
7
  // src/cli.ts
@@ -38,7 +38,7 @@ async function runServe(args) {
38
38
  ...typeof values.data === "string" ? { data: values.data } : {}
39
39
  };
40
40
  Object.assign(process.env, buildServeEnv(opts));
41
- await import("./launcher-ZGFW4X34.js");
41
+ await import("./launcher-V3PF4DU6.js");
42
42
  }
43
43
 
44
44
  // src/commands/agent.ts
@@ -83,7 +83,7 @@ async function runAgent(args) {
83
83
  ...typeof values.port === "string" ? { port: values.port } : {}
84
84
  };
85
85
  Object.assign(process.env, buildAgentEnv(opts));
86
- await import("./launcher-ZGFW4X34.js");
86
+ await import("./launcher-V3PF4DU6.js");
87
87
  }
88
88
 
89
89
  // src/commands/setup.ts
@@ -1130,7 +1130,7 @@ function isUnknown(_value) {
1130
1130
  return true;
1131
1131
  }
1132
1132
  async function resolveServerInteractive(presetNamespace) {
1133
- const { discoverNodes, resolveHubFromDiscovered, filterHubNodes, DEFAULT_HUB_HTTPS_PORT } = await import("./discover-PWDC46ET.js");
1133
+ const { discoverNodes, resolveHubFromDiscovered, filterHubNodes, DEFAULT_HUB_HTTPS_PORT } = await import("./discover-S6SLEJRU.js");
1134
1134
  if (presetNamespace) {
1135
1135
  const spinner4 = clack.spinner();
1136
1136
  spinner4.start(`Discovering hub on LAN (namespace "${presetNamespace}")`);
@@ -5,7 +5,7 @@ import {
5
5
  filterHubNodes,
6
6
  resolveHubFromDiscovered,
7
7
  runDiscover
8
- } from "./chunk-VGIPYXDI.js";
8
+ } from "./chunk-WSQAFZ7F.js";
9
9
  import "./chunk-LMMQX4CK.js";
10
10
  export {
11
11
  DEFAULT_HUB_HTTPS_PORT,