@camstack/addon-ai 0.4.119 → 0.4.121

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.
package/dist/addon.js CHANGED
@@ -5520,7 +5520,7 @@ function number(params) {
5520
5520
  return /* @__PURE__ */ _coercedNumber(ZodNumber, params);
5521
5521
  }
5522
5522
  //#endregion
5523
- //#region ../types/dist/sleep-vl6nBE8d.mjs
5523
+ //#region ../types/dist/sleep-Bs3xPtSh.mjs
5524
5524
  /**
5525
5525
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5526
5526
  * window to float samples (D455).
@@ -12024,6 +12024,24 @@ var GetStreamWithCodecInputSchema = object({
12024
12024
  });
12025
12025
  var RtpSourceSchema = object({
12026
12026
  url: string(),
12027
+ /**
12028
+ * The SENTRY counterpart of {@link url} — the dial that asks for the stream
12029
+ * WITHOUT asking for the camera — or `null` when this camera offers none.
12030
+ *
12031
+ * The broker answers it because the broker is the only thing that can:
12032
+ * eligibility is `sentryEligible` (a BATTERY camera that DECLARES the signals
12033
+ * cap), asked of facts only the broker holds. A consumer re-deriving it from
12034
+ * cap bindings would be a second authority, and two authorities on the same
12035
+ * question is how a composite camera ends up dialling a sleeping camera
12036
+ * because its own copy of the rule was a release behind.
12037
+ *
12038
+ * `null` is a real answer and is never a live url in disguise: a consumer
12039
+ * that silently fell back to {@link url} would perform exactly the wake this
12040
+ * field exists to prevent. Only a PASSTHROUGH acquisition can offer one — a
12041
+ * transcode hands back an egress the broker is feeding itself, which has no
12042
+ * sentry counterpart.
12043
+ */
12044
+ sentryUrl: string().nullable().optional(),
12027
12045
  videoCodec: _enum(["H264", "H265"]),
12028
12046
  audioCodec: string(),
12029
12047
  resolution: object({
@@ -27460,6 +27478,114 @@ DeviceType.Light, DeviceType.Siren, DeviceType.Switch, method(object({
27460
27478
  lastChangedAt: number$1()
27461
27479
  });
27462
27480
  /**
27481
+ * camera-grid-layout — the geometry of a COMPOSITE camera, on the camera's own
27482
+ * page.
27483
+ *
27484
+ * ## Why this is a capability and not an addon settings schema
27485
+ *
27486
+ * It was one, and it did not render. The addon declared the editor as a
27487
+ * `type: 'widget'` field inside its own `deviceSettingsSchema()`; the hub
27488
+ * returned that section correctly and `ConfigFormField` renders `type:'widget'`
27489
+ * perfectly well — and nothing ever asked camera-grid for it. The Cluster →
27490
+ * Pipeline → Device Overrides page interrogates a HAND-WRITTEN list of four
27491
+ * addons (`PIPELINE_CLUSTER_DEVICE_ADDONS`), whose own comment says an addon
27492
+ * not on it "falls off silently".
27493
+ *
27494
+ * Adding a fifth name to that list would have been the wrong fix twice over:
27495
+ * that page is per-camera DETECTION tuning, and a grid's geometry belongs
27496
+ * beside PTZ and motion zones on the camera itself — which is exactly where the
27497
+ * framework already puts a widget, when the widget is declared on a CAPABILITY.
27498
+ * `deviceConfig.ui` is the mechanism (`motion-zones`, `ptz`, `ptz-autotrack`
27499
+ * all use it): the framework emits the structural section and the widget
27500
+ * self-persists through the cap's own mutations.
27501
+ *
27502
+ * ## Why one addon may implement it
27503
+ *
27504
+ * It is a device-scoped NATIVE cap, registered by the grid camera device
27505
+ * itself. Nothing else declares a composite camera, so nothing else has a
27506
+ * layout — and the device-scoped route means the widget asks THE camera, not
27507
+ * "the camera-grid addon", which is what let the old custom-action pair be
27508
+ * reached only by a caller that already knew the addon id.
27509
+ *
27510
+ * ## The tab
27511
+ *
27512
+ * `streaming`, not a top-tab of its own. A grid's geometry IS what its stream
27513
+ * is, so the Streaming tab is where it belongs; a `grid` top-tab would need an
27514
+ * entry in `WELL_KNOWN_TAB_MAP` or the device page renders the raw id as the
27515
+ * label (measured on the robot camera, 2026-09-06 — a tab called "navigation"
27516
+ * next to "PTZ").
27517
+ */
27518
+ /** A rectangle in normalized [0,1] coordinates of whatever contains it. */
27519
+ var GridNormalizedRectSchema = object({
27520
+ x: number$1().min(0).max(1),
27521
+ y: number$1().min(0).max(1),
27522
+ width: number$1().gt(0).max(1),
27523
+ height: number$1().gt(0).max(1)
27524
+ });
27525
+ /**
27526
+ * One source camera, the part of its picture taken, and where that part lands.
27527
+ *
27528
+ * Both rectangles are NORMALIZED (D519): a source camera can change resolution
27529
+ * — a profile switch, a firmware update, a substream that comes back different
27530
+ * — and a stored PIXEL rectangle would quietly start cutting the wrong region,
27531
+ * which is the class of bug nobody files.
27532
+ */
27533
+ var GridLayoutCellSchema = object({
27534
+ deviceId: number$1().int().positive(),
27535
+ /** The part of the SOURCE taken, normalized against the source. */
27536
+ source: GridNormalizedRectSchema,
27537
+ /** Where it lands, normalized against the CANVAS. */
27538
+ cell: GridNormalizedRectSchema
27539
+ });
27540
+ /**
27541
+ * Which profiles this grid can actually compose, and why not.
27542
+ *
27543
+ * A grid's `high` composes its sources' `high` and its `low` their `low`, so a
27544
+ * profile is on offer only when EVERY source can serve it. The refusal NAMES
27545
+ * the sources, because "this grid has no low" is not a finding — "615 has no
27546
+ * low" is, and it is the one an operator can act on.
27547
+ */
27548
+ var GridProfileOfferSchema = object({
27549
+ profile: _enum([
27550
+ "high",
27551
+ "mid",
27552
+ "low"
27553
+ ]),
27554
+ offered: boolean(),
27555
+ /** Sources that cannot serve it. Empty when it is offered, or when there are no cells. */
27556
+ missingSources: array(number$1().int().positive())
27557
+ });
27558
+ var GridLayoutViewSchema = object({
27559
+ /** The persisted grid row this camera was declared from. */
27560
+ instanceId: string(),
27561
+ deviceId: number$1().int().nonnegative(),
27562
+ name: string(),
27563
+ /** The canvas the operator laid out — this grid's `high`. mid/low are scaled from it. */
27564
+ width: number$1().int(),
27565
+ height: number$1().int(),
27566
+ fps: number$1().int(),
27567
+ cells: array(GridLayoutCellSchema),
27568
+ /** What the catalog will publish, and what it refuses to. Read-only. */
27569
+ profiles: array(GridProfileOfferSchema)
27570
+ });
27571
+ var GridLayoutPatchSchema = object({
27572
+ deviceId: number$1().int().nonnegative(),
27573
+ name: string().min(1).max(160).optional(),
27574
+ width: number$1().int().min(160).max(7680).optional(),
27575
+ height: number$1().int().min(120).max(4320).optional(),
27576
+ fps: number$1().int().min(1).max(60).optional(),
27577
+ /**
27578
+ * The whole cell list at once. A per-cell patch would need an ordering the
27579
+ * editor does not have, and a half-applied layout is a picture nobody asked
27580
+ * for.
27581
+ */
27582
+ cells: array(GridLayoutCellSchema).max(16)
27583
+ });
27584
+ DeviceType.Camera, method(object({ deviceId: number$1().int().nonnegative() }), GridLayoutViewSchema.nullable(), { auth: "admin" }), method(GridLayoutPatchSchema, GridLayoutViewSchema, {
27585
+ kind: "mutation",
27586
+ auth: "admin"
27587
+ });
27588
+ /**
27463
27589
  * Motion-zones share the same MaskShape vocabulary as privacy-mask — the
27464
27590
  * on-camera motion-detection mask is a single `grid` region (a row-major
27465
27591
  * boolean cell lattice the camera's onboard VMD evaluates). Composing it as
@@ -29159,6 +29285,26 @@ var PtzHomePresetSchema = object({
29159
29285
  "none"
29160
29286
  ])
29161
29287
  });
29288
+ /**
29289
+ * The camera's own idle-return behaviour: whether it goes home by itself, and
29290
+ * after how long.
29291
+ *
29292
+ * ONE shape, not two scalars, because on the camera they are ONE fact —
29293
+ * Reolink's guard point carries `benable` and `timeout` in the same element,
29294
+ * written by the same command. Reading them apart means two round-trips that
29295
+ * can disagree.
29296
+ *
29297
+ * `enabled` and `seconds` are INDEPENDENT: a camera can hold a 68 s delay with
29298
+ * the behaviour switched off, which is exactly what the vendor app leaves when
29299
+ * you turn the guard point off without clearing it. The first version of this
29300
+ * cap reported only the delay, so that state was invisible — a camera could be
29301
+ * configured to return after 68 seconds with no way to say whether it should
29302
+ * return at all.
29303
+ */
29304
+ var PtzHomeReturnSchema = object({
29305
+ enabled: boolean(),
29306
+ seconds: number$1().int()
29307
+ });
29162
29308
  DeviceType.Camera, method(PtzMoveCommandSchema.extend({ deviceId: number$1() }), _void(), { kind: "mutation" }), method(PtzMoveCommandSchema.extend({ deviceId: number$1() }), _void(), { kind: "mutation" }), method(object({ deviceId: number$1() }), _void(), { kind: "mutation" }), method(object({ deviceId: number$1() }), array(PtzPresetSchema)), method(object({
29163
29309
  deviceId: number$1(),
29164
29310
  presetId: string()
@@ -29184,8 +29330,9 @@ DeviceType.Camera, method(PtzMoveCommandSchema.extend({ deviceId: number$1() }),
29184
29330
  }), method(object({ deviceId: number$1() }), _void(), {
29185
29331
  kind: "mutation",
29186
29332
  auth: "admin"
29187
- }), method(object({ deviceId: number$1() }), number$1().int().nullable()), method(object({
29333
+ }), method(object({ deviceId: number$1() }), PtzHomeReturnSchema.nullable()), method(object({
29188
29334
  deviceId: number$1(),
29335
+ enabled: boolean(),
29189
29336
  seconds: number$1().int().min(0).max(3600)
29190
29337
  }), _void(), {
29191
29338
  kind: "mutation",
@@ -32467,6 +32614,18 @@ Object.freeze({
32467
32614
  addonId: null,
32468
32615
  access: "view"
32469
32616
  },
32617
+ "cameraGridLayout.getLayout": {
32618
+ capName: "camera-grid-layout",
32619
+ capScope: "device",
32620
+ addonId: null,
32621
+ access: "view"
32622
+ },
32623
+ "cameraGridLayout.saveLayout": {
32624
+ capName: "camera-grid-layout",
32625
+ capScope: "device",
32626
+ addonId: null,
32627
+ access: "create"
32628
+ },
32470
32629
  "cameraStreams.getBrokerStreams": {
32471
32630
  capName: "camera-streams",
32472
32631
  capScope: "device",
@@ -36217,7 +36376,7 @@ Object.freeze({
36217
36376
  addonId: null,
36218
36377
  access: "view"
36219
36378
  },
36220
- "ptz.getHomeReturnSeconds": {
36379
+ "ptz.getHomeReturn": {
36221
36380
  capName: "ptz",
36222
36381
  capScope: "device",
36223
36382
  addonId: null,
@@ -36277,7 +36436,7 @@ Object.freeze({
36277
36436
  addonId: null,
36278
36437
  access: "create"
36279
36438
  },
36280
- "ptz.setHomeReturnSeconds": {
36439
+ "ptz.setHomeReturn": {
36281
36440
  capName: "ptz",
36282
36441
  capScope: "device",
36283
36442
  addonId: null,
@@ -38166,6 +38325,21 @@ Object.freeze({
38166
38325
  form: "single",
38167
38326
  optional: false
38168
38327
  }],
38328
+ "cameraGridLayout.getLayout": [{
38329
+ name: "deviceId",
38330
+ form: "single",
38331
+ optional: false
38332
+ }],
38333
+ "cameraGridLayout.saveLayout": [{
38334
+ name: "cells",
38335
+ form: "object-array",
38336
+ optional: false,
38337
+ itemField: "deviceId"
38338
+ }, {
38339
+ name: "deviceId",
38340
+ form: "single",
38341
+ optional: false
38342
+ }],
38169
38343
  "cameraStreams.getBrokerStreams": [{
38170
38344
  name: "deviceId",
38171
38345
  form: "single",
@@ -39466,7 +39640,7 @@ Object.freeze({
39466
39640
  form: "single",
39467
39641
  optional: false
39468
39642
  }],
39469
- "ptz.getHomeReturnSeconds": [{
39643
+ "ptz.getHomeReturn": [{
39470
39644
  name: "deviceId",
39471
39645
  form: "single",
39472
39646
  optional: false
@@ -39516,7 +39690,7 @@ Object.freeze({
39516
39690
  form: "single",
39517
39691
  optional: false
39518
39692
  }],
39519
- "ptz.setHomeReturnSeconds": [{
39693
+ "ptz.setHomeReturn": [{
39520
39694
  name: "deviceId",
39521
39695
  form: "single",
39522
39696
  optional: false
package/dist/addon.mjs CHANGED
@@ -5547,7 +5547,7 @@ function number(params) {
5547
5547
  return /* @__PURE__ */ _coercedNumber(ZodNumber, params);
5548
5548
  }
5549
5549
  //#endregion
5550
- //#region ../types/dist/sleep-vl6nBE8d.mjs
5550
+ //#region ../types/dist/sleep-Bs3xPtSh.mjs
5551
5551
  /**
5552
5552
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5553
5553
  * window to float samples (D455).
@@ -12051,6 +12051,24 @@ var GetStreamWithCodecInputSchema = object({
12051
12051
  });
12052
12052
  var RtpSourceSchema = object({
12053
12053
  url: string(),
12054
+ /**
12055
+ * The SENTRY counterpart of {@link url} — the dial that asks for the stream
12056
+ * WITHOUT asking for the camera — or `null` when this camera offers none.
12057
+ *
12058
+ * The broker answers it because the broker is the only thing that can:
12059
+ * eligibility is `sentryEligible` (a BATTERY camera that DECLARES the signals
12060
+ * cap), asked of facts only the broker holds. A consumer re-deriving it from
12061
+ * cap bindings would be a second authority, and two authorities on the same
12062
+ * question is how a composite camera ends up dialling a sleeping camera
12063
+ * because its own copy of the rule was a release behind.
12064
+ *
12065
+ * `null` is a real answer and is never a live url in disguise: a consumer
12066
+ * that silently fell back to {@link url} would perform exactly the wake this
12067
+ * field exists to prevent. Only a PASSTHROUGH acquisition can offer one — a
12068
+ * transcode hands back an egress the broker is feeding itself, which has no
12069
+ * sentry counterpart.
12070
+ */
12071
+ sentryUrl: string().nullable().optional(),
12054
12072
  videoCodec: _enum(["H264", "H265"]),
12055
12073
  audioCodec: string(),
12056
12074
  resolution: object({
@@ -27487,6 +27505,114 @@ DeviceType.Light, DeviceType.Siren, DeviceType.Switch, method(object({
27487
27505
  lastChangedAt: number$1()
27488
27506
  });
27489
27507
  /**
27508
+ * camera-grid-layout — the geometry of a COMPOSITE camera, on the camera's own
27509
+ * page.
27510
+ *
27511
+ * ## Why this is a capability and not an addon settings schema
27512
+ *
27513
+ * It was one, and it did not render. The addon declared the editor as a
27514
+ * `type: 'widget'` field inside its own `deviceSettingsSchema()`; the hub
27515
+ * returned that section correctly and `ConfigFormField` renders `type:'widget'`
27516
+ * perfectly well — and nothing ever asked camera-grid for it. The Cluster →
27517
+ * Pipeline → Device Overrides page interrogates a HAND-WRITTEN list of four
27518
+ * addons (`PIPELINE_CLUSTER_DEVICE_ADDONS`), whose own comment says an addon
27519
+ * not on it "falls off silently".
27520
+ *
27521
+ * Adding a fifth name to that list would have been the wrong fix twice over:
27522
+ * that page is per-camera DETECTION tuning, and a grid's geometry belongs
27523
+ * beside PTZ and motion zones on the camera itself — which is exactly where the
27524
+ * framework already puts a widget, when the widget is declared on a CAPABILITY.
27525
+ * `deviceConfig.ui` is the mechanism (`motion-zones`, `ptz`, `ptz-autotrack`
27526
+ * all use it): the framework emits the structural section and the widget
27527
+ * self-persists through the cap's own mutations.
27528
+ *
27529
+ * ## Why one addon may implement it
27530
+ *
27531
+ * It is a device-scoped NATIVE cap, registered by the grid camera device
27532
+ * itself. Nothing else declares a composite camera, so nothing else has a
27533
+ * layout — and the device-scoped route means the widget asks THE camera, not
27534
+ * "the camera-grid addon", which is what let the old custom-action pair be
27535
+ * reached only by a caller that already knew the addon id.
27536
+ *
27537
+ * ## The tab
27538
+ *
27539
+ * `streaming`, not a top-tab of its own. A grid's geometry IS what its stream
27540
+ * is, so the Streaming tab is where it belongs; a `grid` top-tab would need an
27541
+ * entry in `WELL_KNOWN_TAB_MAP` or the device page renders the raw id as the
27542
+ * label (measured on the robot camera, 2026-09-06 — a tab called "navigation"
27543
+ * next to "PTZ").
27544
+ */
27545
+ /** A rectangle in normalized [0,1] coordinates of whatever contains it. */
27546
+ var GridNormalizedRectSchema = object({
27547
+ x: number$1().min(0).max(1),
27548
+ y: number$1().min(0).max(1),
27549
+ width: number$1().gt(0).max(1),
27550
+ height: number$1().gt(0).max(1)
27551
+ });
27552
+ /**
27553
+ * One source camera, the part of its picture taken, and where that part lands.
27554
+ *
27555
+ * Both rectangles are NORMALIZED (D519): a source camera can change resolution
27556
+ * — a profile switch, a firmware update, a substream that comes back different
27557
+ * — and a stored PIXEL rectangle would quietly start cutting the wrong region,
27558
+ * which is the class of bug nobody files.
27559
+ */
27560
+ var GridLayoutCellSchema = object({
27561
+ deviceId: number$1().int().positive(),
27562
+ /** The part of the SOURCE taken, normalized against the source. */
27563
+ source: GridNormalizedRectSchema,
27564
+ /** Where it lands, normalized against the CANVAS. */
27565
+ cell: GridNormalizedRectSchema
27566
+ });
27567
+ /**
27568
+ * Which profiles this grid can actually compose, and why not.
27569
+ *
27570
+ * A grid's `high` composes its sources' `high` and its `low` their `low`, so a
27571
+ * profile is on offer only when EVERY source can serve it. The refusal NAMES
27572
+ * the sources, because "this grid has no low" is not a finding — "615 has no
27573
+ * low" is, and it is the one an operator can act on.
27574
+ */
27575
+ var GridProfileOfferSchema = object({
27576
+ profile: _enum([
27577
+ "high",
27578
+ "mid",
27579
+ "low"
27580
+ ]),
27581
+ offered: boolean(),
27582
+ /** Sources that cannot serve it. Empty when it is offered, or when there are no cells. */
27583
+ missingSources: array(number$1().int().positive())
27584
+ });
27585
+ var GridLayoutViewSchema = object({
27586
+ /** The persisted grid row this camera was declared from. */
27587
+ instanceId: string(),
27588
+ deviceId: number$1().int().nonnegative(),
27589
+ name: string(),
27590
+ /** The canvas the operator laid out — this grid's `high`. mid/low are scaled from it. */
27591
+ width: number$1().int(),
27592
+ height: number$1().int(),
27593
+ fps: number$1().int(),
27594
+ cells: array(GridLayoutCellSchema),
27595
+ /** What the catalog will publish, and what it refuses to. Read-only. */
27596
+ profiles: array(GridProfileOfferSchema)
27597
+ });
27598
+ var GridLayoutPatchSchema = object({
27599
+ deviceId: number$1().int().nonnegative(),
27600
+ name: string().min(1).max(160).optional(),
27601
+ width: number$1().int().min(160).max(7680).optional(),
27602
+ height: number$1().int().min(120).max(4320).optional(),
27603
+ fps: number$1().int().min(1).max(60).optional(),
27604
+ /**
27605
+ * The whole cell list at once. A per-cell patch would need an ordering the
27606
+ * editor does not have, and a half-applied layout is a picture nobody asked
27607
+ * for.
27608
+ */
27609
+ cells: array(GridLayoutCellSchema).max(16)
27610
+ });
27611
+ DeviceType.Camera, method(object({ deviceId: number$1().int().nonnegative() }), GridLayoutViewSchema.nullable(), { auth: "admin" }), method(GridLayoutPatchSchema, GridLayoutViewSchema, {
27612
+ kind: "mutation",
27613
+ auth: "admin"
27614
+ });
27615
+ /**
27490
27616
  * Motion-zones share the same MaskShape vocabulary as privacy-mask — the
27491
27617
  * on-camera motion-detection mask is a single `grid` region (a row-major
27492
27618
  * boolean cell lattice the camera's onboard VMD evaluates). Composing it as
@@ -29186,6 +29312,26 @@ var PtzHomePresetSchema = object({
29186
29312
  "none"
29187
29313
  ])
29188
29314
  });
29315
+ /**
29316
+ * The camera's own idle-return behaviour: whether it goes home by itself, and
29317
+ * after how long.
29318
+ *
29319
+ * ONE shape, not two scalars, because on the camera they are ONE fact —
29320
+ * Reolink's guard point carries `benable` and `timeout` in the same element,
29321
+ * written by the same command. Reading them apart means two round-trips that
29322
+ * can disagree.
29323
+ *
29324
+ * `enabled` and `seconds` are INDEPENDENT: a camera can hold a 68 s delay with
29325
+ * the behaviour switched off, which is exactly what the vendor app leaves when
29326
+ * you turn the guard point off without clearing it. The first version of this
29327
+ * cap reported only the delay, so that state was invisible — a camera could be
29328
+ * configured to return after 68 seconds with no way to say whether it should
29329
+ * return at all.
29330
+ */
29331
+ var PtzHomeReturnSchema = object({
29332
+ enabled: boolean(),
29333
+ seconds: number$1().int()
29334
+ });
29189
29335
  DeviceType.Camera, method(PtzMoveCommandSchema.extend({ deviceId: number$1() }), _void(), { kind: "mutation" }), method(PtzMoveCommandSchema.extend({ deviceId: number$1() }), _void(), { kind: "mutation" }), method(object({ deviceId: number$1() }), _void(), { kind: "mutation" }), method(object({ deviceId: number$1() }), array(PtzPresetSchema)), method(object({
29190
29336
  deviceId: number$1(),
29191
29337
  presetId: string()
@@ -29211,8 +29357,9 @@ DeviceType.Camera, method(PtzMoveCommandSchema.extend({ deviceId: number$1() }),
29211
29357
  }), method(object({ deviceId: number$1() }), _void(), {
29212
29358
  kind: "mutation",
29213
29359
  auth: "admin"
29214
- }), method(object({ deviceId: number$1() }), number$1().int().nullable()), method(object({
29360
+ }), method(object({ deviceId: number$1() }), PtzHomeReturnSchema.nullable()), method(object({
29215
29361
  deviceId: number$1(),
29362
+ enabled: boolean(),
29216
29363
  seconds: number$1().int().min(0).max(3600)
29217
29364
  }), _void(), {
29218
29365
  kind: "mutation",
@@ -32494,6 +32641,18 @@ Object.freeze({
32494
32641
  addonId: null,
32495
32642
  access: "view"
32496
32643
  },
32644
+ "cameraGridLayout.getLayout": {
32645
+ capName: "camera-grid-layout",
32646
+ capScope: "device",
32647
+ addonId: null,
32648
+ access: "view"
32649
+ },
32650
+ "cameraGridLayout.saveLayout": {
32651
+ capName: "camera-grid-layout",
32652
+ capScope: "device",
32653
+ addonId: null,
32654
+ access: "create"
32655
+ },
32497
32656
  "cameraStreams.getBrokerStreams": {
32498
32657
  capName: "camera-streams",
32499
32658
  capScope: "device",
@@ -36244,7 +36403,7 @@ Object.freeze({
36244
36403
  addonId: null,
36245
36404
  access: "view"
36246
36405
  },
36247
- "ptz.getHomeReturnSeconds": {
36406
+ "ptz.getHomeReturn": {
36248
36407
  capName: "ptz",
36249
36408
  capScope: "device",
36250
36409
  addonId: null,
@@ -36304,7 +36463,7 @@ Object.freeze({
36304
36463
  addonId: null,
36305
36464
  access: "create"
36306
36465
  },
36307
- "ptz.setHomeReturnSeconds": {
36466
+ "ptz.setHomeReturn": {
36308
36467
  capName: "ptz",
36309
36468
  capScope: "device",
36310
36469
  addonId: null,
@@ -38193,6 +38352,21 @@ Object.freeze({
38193
38352
  form: "single",
38194
38353
  optional: false
38195
38354
  }],
38355
+ "cameraGridLayout.getLayout": [{
38356
+ name: "deviceId",
38357
+ form: "single",
38358
+ optional: false
38359
+ }],
38360
+ "cameraGridLayout.saveLayout": [{
38361
+ name: "cells",
38362
+ form: "object-array",
38363
+ optional: false,
38364
+ itemField: "deviceId"
38365
+ }, {
38366
+ name: "deviceId",
38367
+ form: "single",
38368
+ optional: false
38369
+ }],
38196
38370
  "cameraStreams.getBrokerStreams": [{
38197
38371
  name: "deviceId",
38198
38372
  form: "single",
@@ -39493,7 +39667,7 @@ Object.freeze({
39493
39667
  form: "single",
39494
39668
  optional: false
39495
39669
  }],
39496
- "ptz.getHomeReturnSeconds": [{
39670
+ "ptz.getHomeReturn": [{
39497
39671
  name: "deviceId",
39498
39672
  form: "single",
39499
39673
  optional: false
@@ -39543,7 +39717,7 @@ Object.freeze({
39543
39717
  form: "single",
39544
39718
  optional: false
39545
39719
  }],
39546
- "ptz.setHomeReturnSeconds": [{
39720
+ "ptz.setHomeReturn": [{
39547
39721
  name: "deviceId",
39548
39722
  form: "single",
39549
39723
  optional: false
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-ai",
3
- "version": "0.4.119",
3
+ "version": "0.4.121",
4
4
  "description": "AI addon for CamStack — the `llm` collection provider (cloud, LAN, and camstack-managed local llama.cpp profiles) plus the per-node `llm-runtime` managed executor.",
5
5
  "keywords": [
6
6
  "camstack",