@camstack/addon-provider-homematic 1.2.101 → 1.2.102

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
@@ -5355,7 +5355,7 @@ var ZodIssueCode = {
5355
5355
  var ZodFirstPartyTypeKind;
5356
5356
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5357
5357
  //#endregion
5358
- //#region ../types/dist/sleep-CnLyvg3w.mjs
5358
+ //#region ../types/dist/sleep-DBKu2-U5.mjs
5359
5359
  /**
5360
5360
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5361
5361
  * window to float samples (D455).
@@ -7384,7 +7384,23 @@ var EncodeProfileSchema = object({
7384
7384
  "zerolatency",
7385
7385
  "film",
7386
7386
  "animation"
7387
- ]).optional()
7387
+ ]).optional(),
7388
+ /**
7389
+ * ONE slice per access unit.
7390
+ *
7391
+ * `-tune zerolatency` turns on x264's sliced threads, and a frame then leaves
7392
+ * the encoder as five NAL slices that share one RTP timestamp and carry one
7393
+ * marker bit. A libwebrtc depacketiser sees five frame-starts and one
7394
+ * frame-end per frame: the first pictures render and the video then freezes
7395
+ * for good while the audio, on its own plane, plays on. Measured on this hub
7396
+ * 2026-09-13 against the Echo, and reduced to one slice by this flag alone.
7397
+ *
7398
+ * A NAMED field and not a raw flag, because {@link EgressEncodeSchema} omits
7399
+ * `outputArgs` on purpose: an opaque array is part of the sharing key, so two
7400
+ * consumers meaning the same thing spelled differently would stop sharing one
7401
+ * child. Absent means "whatever the encoder does" — today's behaviour.
7402
+ */
7403
+ singleSlicePerFrame: boolean().optional()
7388
7404
  }),
7389
7405
  audio: union([literal("passthrough"), object({
7390
7406
  codec: _enum([
@@ -7434,7 +7450,7 @@ var BASE_LIVE_EGRESS_PROFILE = {
7434
7450
  audio: "passthrough"
7435
7451
  };
7436
7452
  ({ ...BASE_LIVE_EGRESS_PROFILE }), { ...BASE_LIVE_EGRESS_PROFILE.video };
7437
- ({ ...BASE_LIVE_EGRESS_PROFILE });
7453
+ ({ ...BASE_LIVE_EGRESS_PROFILE }), { ...BASE_LIVE_EGRESS_PROFILE.video };
7438
7454
  /**
7439
7455
  * Deep wiring healthcheck — snapshot of active reachability probes across
7440
7456
  * every declared capability + widget of every installed plugin, on every
@@ -20205,13 +20221,109 @@ var SummariesQueryInput = object({
20205
20221
  deviceIds: array(number()).min(1),
20206
20222
  since: number().optional(),
20207
20223
  until: number().optional(),
20208
- limit: number().int().min(1).max(200).default(50)
20224
+ limit: number().int().min(1).max(200).default(50),
20225
+ /** The same member-wise filter {@link listRecentSummaries} takes — one
20226
+ * meaning of "dog" on every summary surface. */
20227
+ classes: array(string().min(1).max(60)).max(40).optional()
20209
20228
  });
20210
- var SummariesPageSchema = object({ summaries: array(SummarySchema).readonly() });
20211
20229
  var SummaryDetailSchema = object({
20212
20230
  summary: SummarySchema,
20213
- /** Member track ids, in absorption order. */
20214
- trackIds: array(string()).readonly()
20231
+ /** Members in absorption order, oldest join first. */
20232
+ members: array(object({
20233
+ trackId: string(),
20234
+ /**
20235
+ * The track's class at the time it JOINED, or `null` when it was unresolved
20236
+ * and the track no longer exists to fill it.
20237
+ *
20238
+ * The join, not the latest opinion: class voting can re-decide a track's
20239
+ * class afterwards, and a group's composition is the history of who came
20240
+ * together. A consumer counts these to badge a thumbnail — "two people and a
20241
+ * dog" — rather than being handed a second, denormalised tally that would
20242
+ * drift from the members it claims to describe.
20243
+ */
20244
+ className: string().nullable(),
20245
+ /** `primary` is the one member that carries the group's identity. */
20246
+ role: _enum([
20247
+ "primary",
20248
+ "sibling",
20249
+ "child"
20250
+ ]).nullable(),
20251
+ joinedAt: number(),
20252
+ /** Tier 1 — the sub-class (`dog`, `van`), resolved from the member's track
20253
+ * at read time. Absent when nothing resolved, never an empty string. */
20254
+ label: string().optional(),
20255
+ /** Tier 2 — the instance: a person's name, a plate. Absent when the pipeline
20256
+ * recognised nobody, and absent for a member whose track has been pruned —
20257
+ * a thumbnail that names the wrong person is worse than one naming nobody. */
20258
+ subLabel: string().optional()
20259
+ })).readonly()
20260
+ });
20261
+ /**
20262
+ * What a LIST of groups carries: the envelope plus what it is MADE OF.
20263
+ *
20264
+ * Coarse on purpose — the operator's rule is "only the rough data on the list,
20265
+ * we extend when we notice we need more". Enough to draw the card ("two people
20266
+ * and a dog") and no more. The MEMBERS, their names and the per-member links
20267
+ * are on {@link getSummary}: shipping every member of every group so a client
20268
+ * can count them turns a page of two hundred groups into a thousand records to
20269
+ * draw two hundred badges.
20270
+ */
20271
+ var SummaryListItemSchema = object({
20272
+ summary: SummarySchema,
20273
+ /** Class counts, most numerous first; `className: null` is a member whose
20274
+ * class never resolved, counted so the counts add up to `memberCount`. */
20275
+ classes: array(object({
20276
+ className: string().nullable(),
20277
+ count: number().int().positive()
20278
+ })).readonly()
20279
+ });
20280
+ var SummariesPageSchema = object({ summaries: array(SummaryListItemSchema).readonly() });
20281
+ /**
20282
+ * The paged feed, deliberately the SAME shape as {@link RecentTracksQueryInput}.
20283
+ *
20284
+ * The reel on the cameras page and the Events gallery both ride a cursor, so a
20285
+ * summaries feed that could only answer "the last N for these cameras"
20286
+ * (`listSummaries`) would make groups available in the timeline and nowhere
20287
+ * else. Two feeds with different ordering contracts would be two ideas of what
20288
+ * "newest" means, on one screen.
20289
+ */
20290
+ var RecentSummariesQueryInput = object({
20291
+ /** Devices to merge. An empty array yields an empty page. */
20292
+ deviceIds: array(number()),
20293
+ /** Window lower bound on `lastActiveAt` (inclusive). */
20294
+ since: number().optional(),
20295
+ /** Window upper bound on `lastActiveAt` (inclusive). */
20296
+ until: number().optional(),
20297
+ limit: number().int().min(1).max(500).default(100),
20298
+ /** Opaque continuation cursor from a previous page's `nextCursor`. */
20299
+ cursor: string().optional(),
20300
+ /**
20301
+ * Restrict to these classes — THE SAME FIELD `listRecentTracks` takes, and
20302
+ * deliberately the same name: the events filter tree emits one list of ticked
20303
+ * taxonomy nodes, and a summaries feed that called it something else would
20304
+ * make the operator's one filter component produce two shapes.
20305
+ *
20306
+ * A question about the MEMBERS: a group matches when ANY of them does. "Show
20307
+ * me the arrivals with a dog" has to return the group of four people who had
20308
+ * one with them; a filter on the group's own fields could only ever answer
20309
+ * about its primary.
20310
+ *
20311
+ * Matched against all THREE tiers of a member — the class (`animal`), the
20312
+ * sub-class (`dog`) and the instance (a name, a plate) — because which tier a
20313
+ * ticked node lives on is the taxonomy's business, not the caller's. `dog` is
20314
+ * an event kind in the tree and a tier-1 label on an `animal` track; a filter
20315
+ * that read only the class would answer "animal" and never "dog".
20316
+ *
20317
+ * ABSENT or EMPTY means no filter — absent is not a selection of none.
20318
+ */
20319
+ classes: array(string().min(1).max(60)).max(40).optional()
20320
+ });
20321
+ var RecentSummariesPageSchema = object({
20322
+ /** Ordered by (`lastActiveAt` DESC, id DESC). Same light item as
20323
+ * {@link listSummaries} — one list shape, so a card renders the same
20324
+ * whichever feed drew it. */
20325
+ summaries: array(SummaryListItemSchema).readonly(),
20326
+ nextCursor: string().nullable()
20215
20327
  });
20216
20328
  var RecentTracksPageSchema = object({
20217
20329
  /** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
@@ -20625,7 +20737,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
20625
20737
  classes: array(string()).optional(),
20626
20738
  /** See {@link ExcludeSourcesDoc}. */
20627
20739
  excludeSources: array(TrackSourceSchema).optional()
20628
- }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(SummariesQueryInput, SummariesPageSchema), method(object({ id: string() }), SummaryDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
20740
+ }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(SummariesQueryInput, SummariesPageSchema), method(RecentSummariesQueryInput, RecentSummariesPageSchema), method(object({ id: string() }), SummaryDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
20629
20741
  kind: "mutation",
20630
20742
  auth: "admin"
20631
20743
  }), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(object({ deviceId: number() }), array(EventKindDescriptorSchema).readonly()), method(object({ deviceIds: array(number()).min(1).max(200) }), array(EventKindsForDeviceSchema).readonly()), method(object({
@@ -32378,7 +32490,29 @@ var LoggingSettingsPatchSchema = object({
32378
32490
  * disarmed the channels it did not mention would make the Levels page and
32379
32491
  * the Diagnostics page fight over the same value.
32380
32492
  */
32381
- channels: array(LogChannelWindowPatchSchema).readonly().optional()
32493
+ channels: array(LogChannelWindowPatchSchema).readonly().optional(),
32494
+ /**
32495
+ * How many days the analytics OPS LOG is kept — the audit trail of what
32496
+ * retention actually deleted.
32497
+ *
32498
+ * It lives HERE, on the logging document, and not on the analytics addon's
32499
+ * settings form, on the operator's instruction: every other log-ish window in
32500
+ * this system is configured through this one document, and a retention audit
32501
+ * configured somewhere else is a second place to look when the question is
32502
+ * "what happened to my data".
32503
+ *
32504
+ * That placement has a cost worth stating: this document ships in the
32505
+ * framework closure, so this knob needs a published `@camstack/server` while
32506
+ * the four windows beside it (D485) reach a node on `camstack deploy`.
32507
+ *
32508
+ * `retention-model.ts` argued this one must NOT follow a device window,
32509
+ * because the audit trail is the history of the SWEEP and not of the camera.
32510
+ * That argument stands and is untouched — what changes is that 30 days stops
32511
+ * being a constant nobody can reach. `0` keeps it forever. The floor is 1 day
32512
+ * rather than 0-as-delete: an audit log truncated to nothing is precisely the
32513
+ * state in which the next 9.5 GiB leak cannot be explained.
32514
+ */
32515
+ opsLogRetentionDays: number().int().min(0).max(3650).optional()
32382
32516
  });
32383
32517
  /**
32384
32518
  * Which LAYER of the hierarchy is addressed. Absent = the cluster layer.
@@ -32451,6 +32585,14 @@ var LoggingSettingsStateSchema = object({
32451
32585
  channels: array(LogChannelDescriptorSchema).readonly(),
32452
32586
  /** The channels ARMED right now, each with its deadline. */
32453
32587
  activeChannels: array(LogChannelWindowStateSchema).readonly(),
32588
+ /**
32589
+ * The ops-log window in days, as it is in force. `0` = kept forever.
32590
+ *
32591
+ * Reported rather than left to the caller's memory of what it wrote: this is
32592
+ * the value the analytics sweep will actually use, and an operator asking how
32593
+ * long their audit trail lives should not have to infer it from a default.
32594
+ */
32595
+ opsLogRetentionDays: number().int().min(0),
32454
32596
  persisted: boolean()
32455
32597
  });
32456
32598
  method(_void(), FeatureManifestSchema), method(_void(), HealthStatusSchema), method(_void(), FeatureManifestSchema), method(_void(), array(NetworkAddressSchema).readonly()), method(_void(), unknown().nullable(), { auth: "admin" }), method(record(string(), unknown()), _null(), {
@@ -38451,6 +38593,12 @@ Object.freeze({
38451
38593
  addonId: null,
38452
38594
  access: "view"
38453
38595
  },
38596
+ "pipelineAnalytics.listRecentSummaries": {
38597
+ capName: "pipeline-analytics",
38598
+ capScope: "device",
38599
+ addonId: null,
38600
+ access: "view"
38601
+ },
38454
38602
  "pipelineAnalytics.listRecentTracks": {
38455
38603
  capName: "pipeline-analytics",
38456
38604
  capScope: "device",
@@ -42278,6 +42426,11 @@ Object.freeze({
42278
42426
  form: "single",
42279
42427
  optional: true
42280
42428
  }],
42429
+ "pipelineAnalytics.listRecentSummaries": [{
42430
+ name: "deviceIds",
42431
+ form: "array",
42432
+ optional: false
42433
+ }],
42281
42434
  "pipelineAnalytics.listRecentTracks": [{
42282
42435
  name: "deviceIds",
42283
42436
  form: "array",
package/dist/addon.mjs CHANGED
@@ -5356,7 +5356,7 @@ var ZodIssueCode = {
5356
5356
  var ZodFirstPartyTypeKind;
5357
5357
  ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
5358
5358
  //#endregion
5359
- //#region ../types/dist/sleep-CnLyvg3w.mjs
5359
+ //#region ../types/dist/sleep-DBKu2-U5.mjs
5360
5360
  /**
5361
5361
  * The audio chunk plane's byte format, and the ONE expansion from a coded
5362
5362
  * window to float samples (D455).
@@ -7385,7 +7385,23 @@ var EncodeProfileSchema = object({
7385
7385
  "zerolatency",
7386
7386
  "film",
7387
7387
  "animation"
7388
- ]).optional()
7388
+ ]).optional(),
7389
+ /**
7390
+ * ONE slice per access unit.
7391
+ *
7392
+ * `-tune zerolatency` turns on x264's sliced threads, and a frame then leaves
7393
+ * the encoder as five NAL slices that share one RTP timestamp and carry one
7394
+ * marker bit. A libwebrtc depacketiser sees five frame-starts and one
7395
+ * frame-end per frame: the first pictures render and the video then freezes
7396
+ * for good while the audio, on its own plane, plays on. Measured on this hub
7397
+ * 2026-09-13 against the Echo, and reduced to one slice by this flag alone.
7398
+ *
7399
+ * A NAMED field and not a raw flag, because {@link EgressEncodeSchema} omits
7400
+ * `outputArgs` on purpose: an opaque array is part of the sharing key, so two
7401
+ * consumers meaning the same thing spelled differently would stop sharing one
7402
+ * child. Absent means "whatever the encoder does" — today's behaviour.
7403
+ */
7404
+ singleSlicePerFrame: boolean().optional()
7389
7405
  }),
7390
7406
  audio: union([literal("passthrough"), object({
7391
7407
  codec: _enum([
@@ -7435,7 +7451,7 @@ var BASE_LIVE_EGRESS_PROFILE = {
7435
7451
  audio: "passthrough"
7436
7452
  };
7437
7453
  ({ ...BASE_LIVE_EGRESS_PROFILE }), { ...BASE_LIVE_EGRESS_PROFILE.video };
7438
- ({ ...BASE_LIVE_EGRESS_PROFILE });
7454
+ ({ ...BASE_LIVE_EGRESS_PROFILE }), { ...BASE_LIVE_EGRESS_PROFILE.video };
7439
7455
  /**
7440
7456
  * Deep wiring healthcheck — snapshot of active reachability probes across
7441
7457
  * every declared capability + widget of every installed plugin, on every
@@ -20206,13 +20222,109 @@ var SummariesQueryInput = object({
20206
20222
  deviceIds: array(number()).min(1),
20207
20223
  since: number().optional(),
20208
20224
  until: number().optional(),
20209
- limit: number().int().min(1).max(200).default(50)
20225
+ limit: number().int().min(1).max(200).default(50),
20226
+ /** The same member-wise filter {@link listRecentSummaries} takes — one
20227
+ * meaning of "dog" on every summary surface. */
20228
+ classes: array(string().min(1).max(60)).max(40).optional()
20210
20229
  });
20211
- var SummariesPageSchema = object({ summaries: array(SummarySchema).readonly() });
20212
20230
  var SummaryDetailSchema = object({
20213
20231
  summary: SummarySchema,
20214
- /** Member track ids, in absorption order. */
20215
- trackIds: array(string()).readonly()
20232
+ /** Members in absorption order, oldest join first. */
20233
+ members: array(object({
20234
+ trackId: string(),
20235
+ /**
20236
+ * The track's class at the time it JOINED, or `null` when it was unresolved
20237
+ * and the track no longer exists to fill it.
20238
+ *
20239
+ * The join, not the latest opinion: class voting can re-decide a track's
20240
+ * class afterwards, and a group's composition is the history of who came
20241
+ * together. A consumer counts these to badge a thumbnail — "two people and a
20242
+ * dog" — rather than being handed a second, denormalised tally that would
20243
+ * drift from the members it claims to describe.
20244
+ */
20245
+ className: string().nullable(),
20246
+ /** `primary` is the one member that carries the group's identity. */
20247
+ role: _enum([
20248
+ "primary",
20249
+ "sibling",
20250
+ "child"
20251
+ ]).nullable(),
20252
+ joinedAt: number(),
20253
+ /** Tier 1 — the sub-class (`dog`, `van`), resolved from the member's track
20254
+ * at read time. Absent when nothing resolved, never an empty string. */
20255
+ label: string().optional(),
20256
+ /** Tier 2 — the instance: a person's name, a plate. Absent when the pipeline
20257
+ * recognised nobody, and absent for a member whose track has been pruned —
20258
+ * a thumbnail that names the wrong person is worse than one naming nobody. */
20259
+ subLabel: string().optional()
20260
+ })).readonly()
20261
+ });
20262
+ /**
20263
+ * What a LIST of groups carries: the envelope plus what it is MADE OF.
20264
+ *
20265
+ * Coarse on purpose — the operator's rule is "only the rough data on the list,
20266
+ * we extend when we notice we need more". Enough to draw the card ("two people
20267
+ * and a dog") and no more. The MEMBERS, their names and the per-member links
20268
+ * are on {@link getSummary}: shipping every member of every group so a client
20269
+ * can count them turns a page of two hundred groups into a thousand records to
20270
+ * draw two hundred badges.
20271
+ */
20272
+ var SummaryListItemSchema = object({
20273
+ summary: SummarySchema,
20274
+ /** Class counts, most numerous first; `className: null` is a member whose
20275
+ * class never resolved, counted so the counts add up to `memberCount`. */
20276
+ classes: array(object({
20277
+ className: string().nullable(),
20278
+ count: number().int().positive()
20279
+ })).readonly()
20280
+ });
20281
+ var SummariesPageSchema = object({ summaries: array(SummaryListItemSchema).readonly() });
20282
+ /**
20283
+ * The paged feed, deliberately the SAME shape as {@link RecentTracksQueryInput}.
20284
+ *
20285
+ * The reel on the cameras page and the Events gallery both ride a cursor, so a
20286
+ * summaries feed that could only answer "the last N for these cameras"
20287
+ * (`listSummaries`) would make groups available in the timeline and nowhere
20288
+ * else. Two feeds with different ordering contracts would be two ideas of what
20289
+ * "newest" means, on one screen.
20290
+ */
20291
+ var RecentSummariesQueryInput = object({
20292
+ /** Devices to merge. An empty array yields an empty page. */
20293
+ deviceIds: array(number()),
20294
+ /** Window lower bound on `lastActiveAt` (inclusive). */
20295
+ since: number().optional(),
20296
+ /** Window upper bound on `lastActiveAt` (inclusive). */
20297
+ until: number().optional(),
20298
+ limit: number().int().min(1).max(500).default(100),
20299
+ /** Opaque continuation cursor from a previous page's `nextCursor`. */
20300
+ cursor: string().optional(),
20301
+ /**
20302
+ * Restrict to these classes — THE SAME FIELD `listRecentTracks` takes, and
20303
+ * deliberately the same name: the events filter tree emits one list of ticked
20304
+ * taxonomy nodes, and a summaries feed that called it something else would
20305
+ * make the operator's one filter component produce two shapes.
20306
+ *
20307
+ * A question about the MEMBERS: a group matches when ANY of them does. "Show
20308
+ * me the arrivals with a dog" has to return the group of four people who had
20309
+ * one with them; a filter on the group's own fields could only ever answer
20310
+ * about its primary.
20311
+ *
20312
+ * Matched against all THREE tiers of a member — the class (`animal`), the
20313
+ * sub-class (`dog`) and the instance (a name, a plate) — because which tier a
20314
+ * ticked node lives on is the taxonomy's business, not the caller's. `dog` is
20315
+ * an event kind in the tree and a tier-1 label on an `animal` track; a filter
20316
+ * that read only the class would answer "animal" and never "dog".
20317
+ *
20318
+ * ABSENT or EMPTY means no filter — absent is not a selection of none.
20319
+ */
20320
+ classes: array(string().min(1).max(60)).max(40).optional()
20321
+ });
20322
+ var RecentSummariesPageSchema = object({
20323
+ /** Ordered by (`lastActiveAt` DESC, id DESC). Same light item as
20324
+ * {@link listSummaries} — one list shape, so a card renders the same
20325
+ * whichever feed drew it. */
20326
+ summaries: array(SummaryListItemSchema).readonly(),
20327
+ nextCursor: string().nullable()
20216
20328
  });
20217
20329
  var RecentTracksPageSchema = object({
20218
20330
  /** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
@@ -20626,7 +20738,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
20626
20738
  classes: array(string()).optional(),
20627
20739
  /** See {@link ExcludeSourcesDoc}. */
20628
20740
  excludeSources: array(TrackSourceSchema).optional()
20629
- }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(SummariesQueryInput, SummariesPageSchema), method(object({ id: string() }), SummaryDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
20741
+ }), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(SummariesQueryInput, SummariesPageSchema), method(RecentSummariesQueryInput, RecentSummariesPageSchema), method(object({ id: string() }), SummaryDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
20630
20742
  kind: "mutation",
20631
20743
  auth: "admin"
20632
20744
  }), method(DeviceEventQueryInput, array(MotionEventSchema).readonly()), method(ObjectEventQueryInput, array(ObjectEventSchema).readonly()), method(DeviceEventQueryInput, array(AudioEventSchema).readonly()), method(object({ deviceId: number() }), array(EventKindDescriptorSchema).readonly()), method(object({ deviceIds: array(number()).min(1).max(200) }), array(EventKindsForDeviceSchema).readonly()), method(object({
@@ -32379,7 +32491,29 @@ var LoggingSettingsPatchSchema = object({
32379
32491
  * disarmed the channels it did not mention would make the Levels page and
32380
32492
  * the Diagnostics page fight over the same value.
32381
32493
  */
32382
- channels: array(LogChannelWindowPatchSchema).readonly().optional()
32494
+ channels: array(LogChannelWindowPatchSchema).readonly().optional(),
32495
+ /**
32496
+ * How many days the analytics OPS LOG is kept — the audit trail of what
32497
+ * retention actually deleted.
32498
+ *
32499
+ * It lives HERE, on the logging document, and not on the analytics addon's
32500
+ * settings form, on the operator's instruction: every other log-ish window in
32501
+ * this system is configured through this one document, and a retention audit
32502
+ * configured somewhere else is a second place to look when the question is
32503
+ * "what happened to my data".
32504
+ *
32505
+ * That placement has a cost worth stating: this document ships in the
32506
+ * framework closure, so this knob needs a published `@camstack/server` while
32507
+ * the four windows beside it (D485) reach a node on `camstack deploy`.
32508
+ *
32509
+ * `retention-model.ts` argued this one must NOT follow a device window,
32510
+ * because the audit trail is the history of the SWEEP and not of the camera.
32511
+ * That argument stands and is untouched — what changes is that 30 days stops
32512
+ * being a constant nobody can reach. `0` keeps it forever. The floor is 1 day
32513
+ * rather than 0-as-delete: an audit log truncated to nothing is precisely the
32514
+ * state in which the next 9.5 GiB leak cannot be explained.
32515
+ */
32516
+ opsLogRetentionDays: number().int().min(0).max(3650).optional()
32383
32517
  });
32384
32518
  /**
32385
32519
  * Which LAYER of the hierarchy is addressed. Absent = the cluster layer.
@@ -32452,6 +32586,14 @@ var LoggingSettingsStateSchema = object({
32452
32586
  channels: array(LogChannelDescriptorSchema).readonly(),
32453
32587
  /** The channels ARMED right now, each with its deadline. */
32454
32588
  activeChannels: array(LogChannelWindowStateSchema).readonly(),
32589
+ /**
32590
+ * The ops-log window in days, as it is in force. `0` = kept forever.
32591
+ *
32592
+ * Reported rather than left to the caller's memory of what it wrote: this is
32593
+ * the value the analytics sweep will actually use, and an operator asking how
32594
+ * long their audit trail lives should not have to infer it from a default.
32595
+ */
32596
+ opsLogRetentionDays: number().int().min(0),
32455
32597
  persisted: boolean()
32456
32598
  });
32457
32599
  method(_void(), FeatureManifestSchema), method(_void(), HealthStatusSchema), method(_void(), FeatureManifestSchema), method(_void(), array(NetworkAddressSchema).readonly()), method(_void(), unknown().nullable(), { auth: "admin" }), method(record(string(), unknown()), _null(), {
@@ -38452,6 +38594,12 @@ Object.freeze({
38452
38594
  addonId: null,
38453
38595
  access: "view"
38454
38596
  },
38597
+ "pipelineAnalytics.listRecentSummaries": {
38598
+ capName: "pipeline-analytics",
38599
+ capScope: "device",
38600
+ addonId: null,
38601
+ access: "view"
38602
+ },
38455
38603
  "pipelineAnalytics.listRecentTracks": {
38456
38604
  capName: "pipeline-analytics",
38457
38605
  capScope: "device",
@@ -42279,6 +42427,11 @@ Object.freeze({
42279
42427
  form: "single",
42280
42428
  optional: true
42281
42429
  }],
42430
+ "pipelineAnalytics.listRecentSummaries": [{
42431
+ name: "deviceIds",
42432
+ form: "array",
42433
+ optional: false
42434
+ }],
42282
42435
  "pipelineAnalytics.listRecentTracks": [{
42283
42436
  name: "deviceIds",
42284
42437
  form: "array",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-homematic",
3
- "version": "1.2.101",
3
+ "version": "1.2.102",
4
4
  "description": "Homematic / HomematicIP (CCU3 / RaspberryMatic) device-provider addon for CamStack — wraps the nodehomematic library",
5
5
  "keywords": [
6
6
  "camstack",