@camstack/system 1.2.118 → 1.2.120

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 (60) hide show
  1. package/dist/addon-runner.js +1 -1
  2. package/dist/addon-runner.mjs +1 -1
  3. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
  4. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
  5. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
  6. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
  7. package/dist/builtins/alerts/alerts.addon.js +1 -1
  8. package/dist/builtins/alerts/alerts.addon.mjs +1 -1
  9. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +1 -1
  10. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +1 -1
  11. package/dist/builtins/console-logging/index.js +1 -1
  12. package/dist/builtins/console-logging/index.mjs +1 -1
  13. package/dist/builtins/core-blocks/core-blocks.addon.js +1 -1
  14. package/dist/builtins/core-blocks/core-blocks.addon.mjs +1 -1
  15. package/dist/builtins/device-manager/device-manager.addon.js +2 -2
  16. package/dist/builtins/device-manager/device-manager.addon.mjs +2 -2
  17. package/dist/builtins/doorbell/virtual-doorbell.addon.js +1 -1
  18. package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +1 -1
  19. package/dist/builtins/hub-forwarder/index.js +1 -1
  20. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  21. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  22. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  23. package/dist/builtins/local-auth/local-auth.addon.js +1 -1
  24. package/dist/builtins/local-auth/local-auth.addon.mjs +1 -1
  25. package/dist/builtins/local-network/local-network.addon.js +1 -1
  26. package/dist/builtins/local-network/local-network.addon.mjs +1 -1
  27. package/dist/builtins/loki-logging/index.js +1 -1
  28. package/dist/builtins/loki-logging/index.mjs +1 -1
  29. package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
  30. package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
  31. package/dist/builtins/platform-probe/index.js +1 -1
  32. package/dist/builtins/platform-probe/index.mjs +1 -1
  33. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  34. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  35. package/dist/builtins/snapshot/index.js +1 -1
  36. package/dist/builtins/snapshot/index.mjs +1 -1
  37. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
  38. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
  39. package/dist/builtins/sqlite-storage/index.mjs +1 -1
  40. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +3 -2
  41. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +3 -3
  42. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
  43. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
  44. package/dist/builtins/system-config/system-config.addon.js +1 -1
  45. package/dist/builtins/system-config/system-config.addon.mjs +1 -1
  46. package/dist/builtins/winston-logging/index.js +1 -1
  47. package/dist/builtins/winston-logging/index.mjs +1 -1
  48. package/dist/{dist-C2_1HCpW.js → dist-CX9qXYC4.js} +114 -11
  49. package/dist/{dist-DCTpBXm4.mjs → dist-DNbsZxNv.mjs} +114 -11
  50. package/dist/index.js +187 -9
  51. package/dist/index.mjs +185 -11
  52. package/dist/kernel/config-manager.d.ts +8 -1
  53. package/dist/kernel/index.d.ts +3 -0
  54. package/dist/kernel/isolated-builtin-phase.d.ts +33 -0
  55. package/dist/kernel/settings-door-view.d.ts +7 -0
  56. package/dist/{manifest-python-deps-CwBbX4Ut.js → manifest-python-deps-76dZLxD0.js} +11 -3
  57. package/dist/{manifest-python-deps-SGdbr9D5.mjs → manifest-python-deps-DZSNlHjU.mjs} +12 -4
  58. package/dist/{retired-settings-keys-DHRXLMPn.js → retired-settings-keys-DlIuGG4o.js} +1 -1
  59. package/dist/{retired-settings-keys-Czd76yLZ.mjs → retired-settings-keys-Dt0-obcq.mjs} +1 -1
  60. package/package.json +6 -2
@@ -4215,6 +4215,12 @@ var ModelVariantGroupSchema = zod.z.object({
4215
4215
  */
4216
4216
  resolution: zod.z.number().int().positive().optional()
4217
4217
  });
4218
+ var ModelProviderIdSchema = zod.z.enum([
4219
+ "camstack",
4220
+ "frigate",
4221
+ "scrypted",
4222
+ "custom"
4223
+ ]);
4218
4224
  var ModelCatalogEntrySchema = zod.z.object({
4219
4225
  id: zod.z.string(),
4220
4226
  name: zod.z.string(),
@@ -4312,6 +4318,12 @@ var ModelCatalogEntrySchema = zod.z.object({
4312
4318
  */
4313
4319
  group: ModelVariantGroupSchema.optional(),
4314
4320
  /**
4321
+ * Catalog source for the pipeline stepper's provider-first picker. Absent on
4322
+ * built-in CamStack entries (treated as `camstack`) and on registry rows
4323
+ * persisted before this field existed (`inferModelProvider` fills those).
4324
+ */
4325
+ provider: ModelProviderIdSchema.optional(),
4326
+ /**
4315
4327
  * Per-MODEL class map override. Absent ⇒ the step's `StepDefinition.classMap`
4316
4328
  * applies (Frigate / COCO public catalog). Set on a custom model whose raw
4317
4329
  * labels already ARE the CamStack macros (Scrypted identity map).
@@ -12572,12 +12584,15 @@ var NcOccupancyConditionSchema = zod.z.object({
12572
12584
  * there is no second switch that can disagree with the first and every rule
12573
12585
  * authored before the decision migrates for free (`audioModeOf`):
12574
12586
  *
12575
- * - **LABEL mode — `labels` present.** The rule fires on the FIRST frame the
12576
- * classifier labels with one of them. No window, no percentage:
12577
- * `hitPercent` and `samplingSeconds` are ignored, and the rule's own
12578
- * `throttle` cooldown is the only brake. The per-label confidence floor is
12579
- * the analyzer's (`classificationMinScore`, per device) a label only
12580
- * reaches this condition if the classifier was already confident enough.
12587
+ * - **LABEL mode — `labels` present.** The rule fires when `confirmHits`
12588
+ * labelled frames land inside `confirmWindowSec` (default 2 in 5 s).
12589
+ * `hitPercent` and `samplingSeconds` are still ignored a percentage of
12590
+ * frames is the wrong question for a classifier that labels 1–3 frames
12591
+ * per episode. The count window is the brake that drops a single-frame
12592
+ * false positive; the rule's own `throttle` cooldown is the other. The
12593
+ * per-label confidence floor is the analyzer's (`classificationMinScore`,
12594
+ * per device) — a label only reaches this condition if the classifier was
12595
+ * already confident enough. `confirmHits: 1` restores first-frame fire.
12581
12596
  * - **LEVEL mode — `dbThreshold` present, no labels.** The sampling window IS
12582
12597
  * the condition: at least `hitPercent`% of the samples over
12583
12598
  * `samplingSeconds` must be at or above `dbThreshold` dBFS (see
@@ -12604,14 +12619,22 @@ var NcOccupancyConditionSchema = zod.z.object({
12604
12619
  * an operator who typed `dog` mean the same thing.
12605
12620
  */
12606
12621
  var NcAudioConditionSchema = zod.z.object({
12607
- /** LABEL MODE: audio macro labels. Present ⇒ fires on the first labelled frame. */
12622
+ /** LABEL MODE: audio macro labels. Present ⇒ count-in-window confirm. */
12608
12623
  labels: zod.z.array(zod.z.string().min(1)).min(1).optional(),
12609
12624
  /** LEVEL MODE: floor in dBFS (negative-going, `0` = full scale). */
12610
12625
  dbThreshold: zod.z.number().min(-96).max(0).optional(),
12611
12626
  /** LEVEL MODE ONLY: percentage of the window's samples that must be hits (1–100). */
12612
12627
  hitPercent: zod.z.number().int().min(1).max(100).default(60),
12613
12628
  /** LEVEL MODE ONLY: length of the sampling window in seconds. */
12614
- samplingSeconds: zod.z.number().int().min(1).max(300).default(10)
12629
+ samplingSeconds: zod.z.number().int().min(1).max(300).default(10),
12630
+ /**
12631
+ * LABEL MODE: how many labelled frames must land inside
12632
+ * {@link NcAudioConditionSchema.shape.confirmWindowSec} before dispatch.
12633
+ * Absent ⇒ 2 (the matcher default). `1` is first-frame fire.
12634
+ */
12635
+ confirmHits: zod.z.number().int().min(1).max(20).optional(),
12636
+ /** LABEL MODE: the window those frames must share, in seconds. Absent ⇒ 5. */
12637
+ confirmWindowSec: zod.z.number().int().min(1).max(60).optional()
12615
12638
  });
12616
12639
  /**
12617
12640
  * Which zone-crossing DIRECTION a rule accepts (`ObjectEvent.zoneCrossing`).
@@ -15101,6 +15124,46 @@ var RecentTracksPageSchema = zod.z.object({
15101
15124
  /** Cursor for the next page, or null when this page is the last. */
15102
15125
  nextCursor: zod.z.string().nullable()
15103
15126
  });
15127
+ var LIST_GROUPS_DEFAULT_LIMIT = 40;
15128
+ var LIST_GROUPS_MAX_LIMIT = 100;
15129
+ var AnalyticsGroupRecordSchema = zod.z.object({
15130
+ id: zod.z.string(),
15131
+ deviceId: zod.z.number().int(),
15132
+ openedAt: zod.z.number().int(),
15133
+ closedAt: zod.z.number().int(),
15134
+ timestamp: zod.z.number().int(),
15135
+ memberCount: zod.z.number().int(),
15136
+ memberTrackIds: zod.z.array(zod.z.string()).readonly(),
15137
+ className: zod.z.string(),
15138
+ classes: zod.z.array(zod.z.string()).readonly(),
15139
+ /** Relative event-media path, or null when the group has no picture yet. */
15140
+ mediaUrl: zod.z.string().nullable(),
15141
+ singleton: zod.z.boolean()
15142
+ });
15143
+ var AnalyticsGroupMemberSchema = zod.z.object({
15144
+ trackId: zod.z.string(),
15145
+ deviceId: zod.z.number().int(),
15146
+ className: zod.z.string(),
15147
+ firstSeen: zod.z.number().int(),
15148
+ lastSeen: zod.z.number().int(),
15149
+ mediaUrl: zod.z.string().nullable()
15150
+ });
15151
+ var AnalyticsGroupDetailSchema = AnalyticsGroupRecordSchema.extend({ members: zod.z.array(AnalyticsGroupMemberSchema).readonly() });
15152
+ var ListGroupsQueryInput = zod.z.object({
15153
+ /** Devices to merge. An empty array yields `{ groups: [], nextCursor: null }`. */
15154
+ deviceIds: zod.z.array(zod.z.number()),
15155
+ /** Window lower bound on `closedAt` (inclusive). */
15156
+ since: zod.z.number().optional(),
15157
+ /** Window upper bound on `openedAt` (inclusive). */
15158
+ until: zod.z.number().optional(),
15159
+ limit: zod.z.number().int().min(1).max(LIST_GROUPS_MAX_LIMIT).default(LIST_GROUPS_DEFAULT_LIMIT),
15160
+ /** Opaque continuation cursor from a previous page's `nextCursor`. */
15161
+ cursor: zod.z.string().optional()
15162
+ });
15163
+ var ListGroupsPageSchema = zod.z.object({
15164
+ groups: zod.z.array(AnalyticsGroupRecordSchema).readonly(),
15165
+ nextCursor: zod.z.string().nullable()
15166
+ });
15104
15167
  var KeyEventQueryInput = zod.z.object({
15105
15168
  deviceId: zod.z.number(),
15106
15169
  /** Window lower bound (track firstSeen ≥ since). */
@@ -15176,7 +15239,9 @@ var TrackCascadeCountsSchema = zod.z.object({
15176
15239
  /** Unassigned plate reads removed (best-effort; plate leg deferred to plate-intelligence). */
15177
15240
  plates: zod.z.number().int(),
15178
15241
  /** Per-track CLIP search vectors removed (best-effort). */
15179
- embeddings: zod.z.number().int()
15242
+ embeddings: zod.z.number().int(),
15243
+ /** Group membership + group rows removed with their last member (best-effort). */
15244
+ groups: zod.z.number().int()
15180
15245
  });
15181
15246
  /** Disk-wins reconcile: media rows whose blobs are gone, then empty tracks. */
15182
15247
  var DiskReconcileCountsSchema = zod.z.object({
@@ -15348,6 +15413,16 @@ var pipelineAnalyticsCapability = {
15348
15413
  * are not included (same contract as `listTracks`).
15349
15414
  */
15350
15415
  listRecentTracks: method(RecentTracksQueryInput, RecentTracksPageSchema),
15416
+ /**
15417
+ * Batched co-moving group listing — the Groups feed. Same merge/cursor
15418
+ * contract as {@link listRecentTracks}. A group is a sealed partition of
15419
+ * one session; `getGroup` is the detail with members.
15420
+ */
15421
+ listGroups: method(ListGroupsQueryInput, ListGroupsPageSchema),
15422
+ getGroup: method(zod.z.object({
15423
+ deviceId: zod.z.number(),
15424
+ groupId: zod.z.string().min(1)
15425
+ }), AnalyticsGroupDetailSchema.nullable()),
15351
15426
  clearTracks: method(zod.z.object({ deviceId: zod.z.number() }), zod.z.void(), {
15352
15427
  kind: "mutation",
15353
15428
  auth: "admin"
@@ -16034,7 +16109,8 @@ var PipelineModelOptionSchema = zod.z.object({
16034
16109
  sizeMB: zod.z.number()
16035
16110
  })),
16036
16111
  group: ModelVariantGroupSchema.optional(),
16037
- legacy: zod.z.boolean().optional()
16112
+ legacy: zod.z.boolean().optional(),
16113
+ provider: ModelProviderIdSchema.optional()
16038
16114
  });
16039
16115
  var ConfigFieldBridge = zod.z.custom();
16040
16116
  var PipelineAddonSchemaSchema = zod.z.object({
@@ -26001,7 +26077,12 @@ var PlateInfoSchema = zod.z.object({
26001
26077
  plateBbox: BoundingBoxSchema.optional(),
26002
26078
  /** keyFrame parity: MediaStore key of the track's native-resolution key frame. */
26003
26079
  keyFrameMediaKey: zod.z.string().optional(),
26004
- base64: zod.z.string().optional()
26080
+ base64: zod.z.string().optional(),
26081
+ /**
26082
+ * Same crop as a data-plane URL. `getPlateByTrack` returns this and
26083
+ * never inlines JPEG; `listPlates` still inlines for the admin-ui.
26084
+ */
26085
+ cropUrl: zod.z.string().optional()
26005
26086
  });
26006
26087
  var MediaFileLiteSchema = zod.z.object({
26007
26088
  key: zod.z.string(),
@@ -33549,6 +33630,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
33549
33630
  addonId: null,
33550
33631
  access: "view"
33551
33632
  },
33633
+ "pipelineAnalytics.getGroup": {
33634
+ capName: "pipeline-analytics",
33635
+ capScope: "device",
33636
+ addonId: null,
33637
+ access: "view"
33638
+ },
33552
33639
  "pipelineAnalytics.getKeyEvents": {
33553
33640
  capName: "pipeline-analytics",
33554
33641
  capScope: "device",
@@ -33633,6 +33720,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
33633
33720
  addonId: null,
33634
33721
  access: "view"
33635
33722
  },
33723
+ "pipelineAnalytics.listGroups": {
33724
+ capName: "pipeline-analytics",
33725
+ capScope: "device",
33726
+ addonId: null,
33727
+ access: "view"
33728
+ },
33636
33729
  "pipelineAnalytics.listOpsLog": {
33637
33730
  capName: "pipeline-analytics",
33638
33731
  capScope: "device",
@@ -37052,6 +37145,11 @@ Object.freeze({
37052
37145
  form: "single",
37053
37146
  optional: false
37054
37147
  }],
37148
+ "pipelineAnalytics.getGroup": [{
37149
+ name: "deviceId",
37150
+ form: "single",
37151
+ optional: false
37152
+ }],
37055
37153
  "pipelineAnalytics.getKeyEvents": [{
37056
37154
  name: "deviceId",
37057
37155
  form: "single",
@@ -37107,6 +37205,11 @@ Object.freeze({
37107
37205
  form: "array",
37108
37206
  optional: false
37109
37207
  }],
37208
+ "pipelineAnalytics.listGroups": [{
37209
+ name: "deviceIds",
37210
+ form: "array",
37211
+ optional: false
37212
+ }],
37110
37213
  "pipelineAnalytics.listOpsLog": [{
37111
37214
  name: "deviceId",
37112
37215
  form: "single",
@@ -4215,6 +4215,12 @@ var ModelVariantGroupSchema = z.object({
4215
4215
  */
4216
4216
  resolution: z.number().int().positive().optional()
4217
4217
  });
4218
+ var ModelProviderIdSchema = z.enum([
4219
+ "camstack",
4220
+ "frigate",
4221
+ "scrypted",
4222
+ "custom"
4223
+ ]);
4218
4224
  var ModelCatalogEntrySchema = z.object({
4219
4225
  id: z.string(),
4220
4226
  name: z.string(),
@@ -4312,6 +4318,12 @@ var ModelCatalogEntrySchema = z.object({
4312
4318
  */
4313
4319
  group: ModelVariantGroupSchema.optional(),
4314
4320
  /**
4321
+ * Catalog source for the pipeline stepper's provider-first picker. Absent on
4322
+ * built-in CamStack entries (treated as `camstack`) and on registry rows
4323
+ * persisted before this field existed (`inferModelProvider` fills those).
4324
+ */
4325
+ provider: ModelProviderIdSchema.optional(),
4326
+ /**
4315
4327
  * Per-MODEL class map override. Absent ⇒ the step's `StepDefinition.classMap`
4316
4328
  * applies (Frigate / COCO public catalog). Set on a custom model whose raw
4317
4329
  * labels already ARE the CamStack macros (Scrypted identity map).
@@ -12572,12 +12584,15 @@ var NcOccupancyConditionSchema = z.object({
12572
12584
  * there is no second switch that can disagree with the first and every rule
12573
12585
  * authored before the decision migrates for free (`audioModeOf`):
12574
12586
  *
12575
- * - **LABEL mode — `labels` present.** The rule fires on the FIRST frame the
12576
- * classifier labels with one of them. No window, no percentage:
12577
- * `hitPercent` and `samplingSeconds` are ignored, and the rule's own
12578
- * `throttle` cooldown is the only brake. The per-label confidence floor is
12579
- * the analyzer's (`classificationMinScore`, per device) a label only
12580
- * reaches this condition if the classifier was already confident enough.
12587
+ * - **LABEL mode — `labels` present.** The rule fires when `confirmHits`
12588
+ * labelled frames land inside `confirmWindowSec` (default 2 in 5 s).
12589
+ * `hitPercent` and `samplingSeconds` are still ignored a percentage of
12590
+ * frames is the wrong question for a classifier that labels 1–3 frames
12591
+ * per episode. The count window is the brake that drops a single-frame
12592
+ * false positive; the rule's own `throttle` cooldown is the other. The
12593
+ * per-label confidence floor is the analyzer's (`classificationMinScore`,
12594
+ * per device) — a label only reaches this condition if the classifier was
12595
+ * already confident enough. `confirmHits: 1` restores first-frame fire.
12581
12596
  * - **LEVEL mode — `dbThreshold` present, no labels.** The sampling window IS
12582
12597
  * the condition: at least `hitPercent`% of the samples over
12583
12598
  * `samplingSeconds` must be at or above `dbThreshold` dBFS (see
@@ -12604,14 +12619,22 @@ var NcOccupancyConditionSchema = z.object({
12604
12619
  * an operator who typed `dog` mean the same thing.
12605
12620
  */
12606
12621
  var NcAudioConditionSchema = z.object({
12607
- /** LABEL MODE: audio macro labels. Present ⇒ fires on the first labelled frame. */
12622
+ /** LABEL MODE: audio macro labels. Present ⇒ count-in-window confirm. */
12608
12623
  labels: z.array(z.string().min(1)).min(1).optional(),
12609
12624
  /** LEVEL MODE: floor in dBFS (negative-going, `0` = full scale). */
12610
12625
  dbThreshold: z.number().min(-96).max(0).optional(),
12611
12626
  /** LEVEL MODE ONLY: percentage of the window's samples that must be hits (1–100). */
12612
12627
  hitPercent: z.number().int().min(1).max(100).default(60),
12613
12628
  /** LEVEL MODE ONLY: length of the sampling window in seconds. */
12614
- samplingSeconds: z.number().int().min(1).max(300).default(10)
12629
+ samplingSeconds: z.number().int().min(1).max(300).default(10),
12630
+ /**
12631
+ * LABEL MODE: how many labelled frames must land inside
12632
+ * {@link NcAudioConditionSchema.shape.confirmWindowSec} before dispatch.
12633
+ * Absent ⇒ 2 (the matcher default). `1` is first-frame fire.
12634
+ */
12635
+ confirmHits: z.number().int().min(1).max(20).optional(),
12636
+ /** LABEL MODE: the window those frames must share, in seconds. Absent ⇒ 5. */
12637
+ confirmWindowSec: z.number().int().min(1).max(60).optional()
12615
12638
  });
12616
12639
  /**
12617
12640
  * Which zone-crossing DIRECTION a rule accepts (`ObjectEvent.zoneCrossing`).
@@ -15101,6 +15124,46 @@ var RecentTracksPageSchema = z.object({
15101
15124
  /** Cursor for the next page, or null when this page is the last. */
15102
15125
  nextCursor: z.string().nullable()
15103
15126
  });
15127
+ var LIST_GROUPS_DEFAULT_LIMIT = 40;
15128
+ var LIST_GROUPS_MAX_LIMIT = 100;
15129
+ var AnalyticsGroupRecordSchema = z.object({
15130
+ id: z.string(),
15131
+ deviceId: z.number().int(),
15132
+ openedAt: z.number().int(),
15133
+ closedAt: z.number().int(),
15134
+ timestamp: z.number().int(),
15135
+ memberCount: z.number().int(),
15136
+ memberTrackIds: z.array(z.string()).readonly(),
15137
+ className: z.string(),
15138
+ classes: z.array(z.string()).readonly(),
15139
+ /** Relative event-media path, or null when the group has no picture yet. */
15140
+ mediaUrl: z.string().nullable(),
15141
+ singleton: z.boolean()
15142
+ });
15143
+ var AnalyticsGroupMemberSchema = z.object({
15144
+ trackId: z.string(),
15145
+ deviceId: z.number().int(),
15146
+ className: z.string(),
15147
+ firstSeen: z.number().int(),
15148
+ lastSeen: z.number().int(),
15149
+ mediaUrl: z.string().nullable()
15150
+ });
15151
+ var AnalyticsGroupDetailSchema = AnalyticsGroupRecordSchema.extend({ members: z.array(AnalyticsGroupMemberSchema).readonly() });
15152
+ var ListGroupsQueryInput = z.object({
15153
+ /** Devices to merge. An empty array yields `{ groups: [], nextCursor: null }`. */
15154
+ deviceIds: z.array(z.number()),
15155
+ /** Window lower bound on `closedAt` (inclusive). */
15156
+ since: z.number().optional(),
15157
+ /** Window upper bound on `openedAt` (inclusive). */
15158
+ until: z.number().optional(),
15159
+ limit: z.number().int().min(1).max(LIST_GROUPS_MAX_LIMIT).default(LIST_GROUPS_DEFAULT_LIMIT),
15160
+ /** Opaque continuation cursor from a previous page's `nextCursor`. */
15161
+ cursor: z.string().optional()
15162
+ });
15163
+ var ListGroupsPageSchema = z.object({
15164
+ groups: z.array(AnalyticsGroupRecordSchema).readonly(),
15165
+ nextCursor: z.string().nullable()
15166
+ });
15104
15167
  var KeyEventQueryInput = z.object({
15105
15168
  deviceId: z.number(),
15106
15169
  /** Window lower bound (track firstSeen ≥ since). */
@@ -15176,7 +15239,9 @@ var TrackCascadeCountsSchema = z.object({
15176
15239
  /** Unassigned plate reads removed (best-effort; plate leg deferred to plate-intelligence). */
15177
15240
  plates: z.number().int(),
15178
15241
  /** Per-track CLIP search vectors removed (best-effort). */
15179
- embeddings: z.number().int()
15242
+ embeddings: z.number().int(),
15243
+ /** Group membership + group rows removed with their last member (best-effort). */
15244
+ groups: z.number().int()
15180
15245
  });
15181
15246
  /** Disk-wins reconcile: media rows whose blobs are gone, then empty tracks. */
15182
15247
  var DiskReconcileCountsSchema = z.object({
@@ -15348,6 +15413,16 @@ var pipelineAnalyticsCapability = {
15348
15413
  * are not included (same contract as `listTracks`).
15349
15414
  */
15350
15415
  listRecentTracks: method(RecentTracksQueryInput, RecentTracksPageSchema),
15416
+ /**
15417
+ * Batched co-moving group listing — the Groups feed. Same merge/cursor
15418
+ * contract as {@link listRecentTracks}. A group is a sealed partition of
15419
+ * one session; `getGroup` is the detail with members.
15420
+ */
15421
+ listGroups: method(ListGroupsQueryInput, ListGroupsPageSchema),
15422
+ getGroup: method(z.object({
15423
+ deviceId: z.number(),
15424
+ groupId: z.string().min(1)
15425
+ }), AnalyticsGroupDetailSchema.nullable()),
15351
15426
  clearTracks: method(z.object({ deviceId: z.number() }), z.void(), {
15352
15427
  kind: "mutation",
15353
15428
  auth: "admin"
@@ -16034,7 +16109,8 @@ var PipelineModelOptionSchema = z.object({
16034
16109
  sizeMB: z.number()
16035
16110
  })),
16036
16111
  group: ModelVariantGroupSchema.optional(),
16037
- legacy: z.boolean().optional()
16112
+ legacy: z.boolean().optional(),
16113
+ provider: ModelProviderIdSchema.optional()
16038
16114
  });
16039
16115
  var ConfigFieldBridge = z.custom();
16040
16116
  var PipelineAddonSchemaSchema = z.object({
@@ -26001,7 +26077,12 @@ var PlateInfoSchema = z.object({
26001
26077
  plateBbox: BoundingBoxSchema.optional(),
26002
26078
  /** keyFrame parity: MediaStore key of the track's native-resolution key frame. */
26003
26079
  keyFrameMediaKey: z.string().optional(),
26004
- base64: z.string().optional()
26080
+ base64: z.string().optional(),
26081
+ /**
26082
+ * Same crop as a data-plane URL. `getPlateByTrack` returns this and
26083
+ * never inlines JPEG; `listPlates` still inlines for the admin-ui.
26084
+ */
26085
+ cropUrl: z.string().optional()
26005
26086
  });
26006
26087
  var MediaFileLiteSchema = z.object({
26007
26088
  key: z.string(),
@@ -33549,6 +33630,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
33549
33630
  addonId: null,
33550
33631
  access: "view"
33551
33632
  },
33633
+ "pipelineAnalytics.getGroup": {
33634
+ capName: "pipeline-analytics",
33635
+ capScope: "device",
33636
+ addonId: null,
33637
+ access: "view"
33638
+ },
33552
33639
  "pipelineAnalytics.getKeyEvents": {
33553
33640
  capName: "pipeline-analytics",
33554
33641
  capScope: "device",
@@ -33633,6 +33720,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
33633
33720
  addonId: null,
33634
33721
  access: "view"
33635
33722
  },
33723
+ "pipelineAnalytics.listGroups": {
33724
+ capName: "pipeline-analytics",
33725
+ capScope: "device",
33726
+ addonId: null,
33727
+ access: "view"
33728
+ },
33636
33729
  "pipelineAnalytics.listOpsLog": {
33637
33730
  capName: "pipeline-analytics",
33638
33731
  capScope: "device",
@@ -37052,6 +37145,11 @@ Object.freeze({
37052
37145
  form: "single",
37053
37146
  optional: false
37054
37147
  }],
37148
+ "pipelineAnalytics.getGroup": [{
37149
+ name: "deviceId",
37150
+ form: "single",
37151
+ optional: false
37152
+ }],
37055
37153
  "pipelineAnalytics.getKeyEvents": [{
37056
37154
  name: "deviceId",
37057
37155
  form: "single",
@@ -37107,6 +37205,11 @@ Object.freeze({
37107
37205
  form: "array",
37108
37206
  optional: false
37109
37207
  }],
37208
+ "pipelineAnalytics.listGroups": [{
37209
+ name: "deviceIds",
37210
+ form: "array",
37211
+ optional: false
37212
+ }],
37110
37213
  "pipelineAnalytics.listOpsLog": [{
37111
37214
  name: "deviceId",
37112
37215
  form: "single",