@camstack/addon-provider-tuya 0.2.100 → 0.2.101
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 +162 -9
- package/dist/addon.mjs +162 -9
- package/package.json +1 -1
package/dist/addon.js
CHANGED
|
@@ -6166,7 +6166,7 @@ var ZodIssueCode = {
|
|
|
6166
6166
|
var ZodFirstPartyTypeKind;
|
|
6167
6167
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
6168
6168
|
//#endregion
|
|
6169
|
-
//#region ../types/dist/sleep-
|
|
6169
|
+
//#region ../types/dist/sleep-DBKu2-U5.mjs
|
|
6170
6170
|
/**
|
|
6171
6171
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
6172
6172
|
* window to float samples (D455).
|
|
@@ -8195,7 +8195,23 @@ var EncodeProfileSchema = object({
|
|
|
8195
8195
|
"zerolatency",
|
|
8196
8196
|
"film",
|
|
8197
8197
|
"animation"
|
|
8198
|
-
]).optional()
|
|
8198
|
+
]).optional(),
|
|
8199
|
+
/**
|
|
8200
|
+
* ONE slice per access unit.
|
|
8201
|
+
*
|
|
8202
|
+
* `-tune zerolatency` turns on x264's sliced threads, and a frame then leaves
|
|
8203
|
+
* the encoder as five NAL slices that share one RTP timestamp and carry one
|
|
8204
|
+
* marker bit. A libwebrtc depacketiser sees five frame-starts and one
|
|
8205
|
+
* frame-end per frame: the first pictures render and the video then freezes
|
|
8206
|
+
* for good while the audio, on its own plane, plays on. Measured on this hub
|
|
8207
|
+
* 2026-09-13 against the Echo, and reduced to one slice by this flag alone.
|
|
8208
|
+
*
|
|
8209
|
+
* A NAMED field and not a raw flag, because {@link EgressEncodeSchema} omits
|
|
8210
|
+
* `outputArgs` on purpose: an opaque array is part of the sharing key, so two
|
|
8211
|
+
* consumers meaning the same thing spelled differently would stop sharing one
|
|
8212
|
+
* child. Absent means "whatever the encoder does" — today's behaviour.
|
|
8213
|
+
*/
|
|
8214
|
+
singleSlicePerFrame: boolean().optional()
|
|
8199
8215
|
}),
|
|
8200
8216
|
audio: union([literal("passthrough"), object({
|
|
8201
8217
|
codec: _enum([
|
|
@@ -8245,7 +8261,7 @@ var BASE_LIVE_EGRESS_PROFILE = {
|
|
|
8245
8261
|
audio: "passthrough"
|
|
8246
8262
|
};
|
|
8247
8263
|
({ ...BASE_LIVE_EGRESS_PROFILE }), { ...BASE_LIVE_EGRESS_PROFILE.video };
|
|
8248
|
-
({ ...BASE_LIVE_EGRESS_PROFILE });
|
|
8264
|
+
({ ...BASE_LIVE_EGRESS_PROFILE }), { ...BASE_LIVE_EGRESS_PROFILE.video };
|
|
8249
8265
|
/**
|
|
8250
8266
|
* Deep wiring healthcheck — snapshot of active reachability probes across
|
|
8251
8267
|
* every declared capability + widget of every installed plugin, on every
|
|
@@ -20967,13 +20983,109 @@ var SummariesQueryInput = object({
|
|
|
20967
20983
|
deviceIds: array(number()).min(1),
|
|
20968
20984
|
since: number().optional(),
|
|
20969
20985
|
until: number().optional(),
|
|
20970
|
-
limit: number().int().min(1).max(200).default(50)
|
|
20986
|
+
limit: number().int().min(1).max(200).default(50),
|
|
20987
|
+
/** The same member-wise filter {@link listRecentSummaries} takes — one
|
|
20988
|
+
* meaning of "dog" on every summary surface. */
|
|
20989
|
+
classes: array(string().min(1).max(60)).max(40).optional()
|
|
20971
20990
|
});
|
|
20972
|
-
var SummariesPageSchema = object({ summaries: array(SummarySchema).readonly() });
|
|
20973
20991
|
var SummaryDetailSchema = object({
|
|
20974
20992
|
summary: SummarySchema,
|
|
20975
|
-
/**
|
|
20976
|
-
|
|
20993
|
+
/** Members in absorption order, oldest join first. */
|
|
20994
|
+
members: array(object({
|
|
20995
|
+
trackId: string(),
|
|
20996
|
+
/**
|
|
20997
|
+
* The track's class at the time it JOINED, or `null` when it was unresolved
|
|
20998
|
+
* and the track no longer exists to fill it.
|
|
20999
|
+
*
|
|
21000
|
+
* The join, not the latest opinion: class voting can re-decide a track's
|
|
21001
|
+
* class afterwards, and a group's composition is the history of who came
|
|
21002
|
+
* together. A consumer counts these to badge a thumbnail — "two people and a
|
|
21003
|
+
* dog" — rather than being handed a second, denormalised tally that would
|
|
21004
|
+
* drift from the members it claims to describe.
|
|
21005
|
+
*/
|
|
21006
|
+
className: string().nullable(),
|
|
21007
|
+
/** `primary` is the one member that carries the group's identity. */
|
|
21008
|
+
role: _enum([
|
|
21009
|
+
"primary",
|
|
21010
|
+
"sibling",
|
|
21011
|
+
"child"
|
|
21012
|
+
]).nullable(),
|
|
21013
|
+
joinedAt: number(),
|
|
21014
|
+
/** Tier 1 — the sub-class (`dog`, `van`), resolved from the member's track
|
|
21015
|
+
* at read time. Absent when nothing resolved, never an empty string. */
|
|
21016
|
+
label: string().optional(),
|
|
21017
|
+
/** Tier 2 — the instance: a person's name, a plate. Absent when the pipeline
|
|
21018
|
+
* recognised nobody, and absent for a member whose track has been pruned —
|
|
21019
|
+
* a thumbnail that names the wrong person is worse than one naming nobody. */
|
|
21020
|
+
subLabel: string().optional()
|
|
21021
|
+
})).readonly()
|
|
21022
|
+
});
|
|
21023
|
+
/**
|
|
21024
|
+
* What a LIST of groups carries: the envelope plus what it is MADE OF.
|
|
21025
|
+
*
|
|
21026
|
+
* Coarse on purpose — the operator's rule is "only the rough data on the list,
|
|
21027
|
+
* we extend when we notice we need more". Enough to draw the card ("two people
|
|
21028
|
+
* and a dog") and no more. The MEMBERS, their names and the per-member links
|
|
21029
|
+
* are on {@link getSummary}: shipping every member of every group so a client
|
|
21030
|
+
* can count them turns a page of two hundred groups into a thousand records to
|
|
21031
|
+
* draw two hundred badges.
|
|
21032
|
+
*/
|
|
21033
|
+
var SummaryListItemSchema = object({
|
|
21034
|
+
summary: SummarySchema,
|
|
21035
|
+
/** Class counts, most numerous first; `className: null` is a member whose
|
|
21036
|
+
* class never resolved, counted so the counts add up to `memberCount`. */
|
|
21037
|
+
classes: array(object({
|
|
21038
|
+
className: string().nullable(),
|
|
21039
|
+
count: number().int().positive()
|
|
21040
|
+
})).readonly()
|
|
21041
|
+
});
|
|
21042
|
+
var SummariesPageSchema = object({ summaries: array(SummaryListItemSchema).readonly() });
|
|
21043
|
+
/**
|
|
21044
|
+
* The paged feed, deliberately the SAME shape as {@link RecentTracksQueryInput}.
|
|
21045
|
+
*
|
|
21046
|
+
* The reel on the cameras page and the Events gallery both ride a cursor, so a
|
|
21047
|
+
* summaries feed that could only answer "the last N for these cameras"
|
|
21048
|
+
* (`listSummaries`) would make groups available in the timeline and nowhere
|
|
21049
|
+
* else. Two feeds with different ordering contracts would be two ideas of what
|
|
21050
|
+
* "newest" means, on one screen.
|
|
21051
|
+
*/
|
|
21052
|
+
var RecentSummariesQueryInput = object({
|
|
21053
|
+
/** Devices to merge. An empty array yields an empty page. */
|
|
21054
|
+
deviceIds: array(number()),
|
|
21055
|
+
/** Window lower bound on `lastActiveAt` (inclusive). */
|
|
21056
|
+
since: number().optional(),
|
|
21057
|
+
/** Window upper bound on `lastActiveAt` (inclusive). */
|
|
21058
|
+
until: number().optional(),
|
|
21059
|
+
limit: number().int().min(1).max(500).default(100),
|
|
21060
|
+
/** Opaque continuation cursor from a previous page's `nextCursor`. */
|
|
21061
|
+
cursor: string().optional(),
|
|
21062
|
+
/**
|
|
21063
|
+
* Restrict to these classes — THE SAME FIELD `listRecentTracks` takes, and
|
|
21064
|
+
* deliberately the same name: the events filter tree emits one list of ticked
|
|
21065
|
+
* taxonomy nodes, and a summaries feed that called it something else would
|
|
21066
|
+
* make the operator's one filter component produce two shapes.
|
|
21067
|
+
*
|
|
21068
|
+
* A question about the MEMBERS: a group matches when ANY of them does. "Show
|
|
21069
|
+
* me the arrivals with a dog" has to return the group of four people who had
|
|
21070
|
+
* one with them; a filter on the group's own fields could only ever answer
|
|
21071
|
+
* about its primary.
|
|
21072
|
+
*
|
|
21073
|
+
* Matched against all THREE tiers of a member — the class (`animal`), the
|
|
21074
|
+
* sub-class (`dog`) and the instance (a name, a plate) — because which tier a
|
|
21075
|
+
* ticked node lives on is the taxonomy's business, not the caller's. `dog` is
|
|
21076
|
+
* an event kind in the tree and a tier-1 label on an `animal` track; a filter
|
|
21077
|
+
* that read only the class would answer "animal" and never "dog".
|
|
21078
|
+
*
|
|
21079
|
+
* ABSENT or EMPTY means no filter — absent is not a selection of none.
|
|
21080
|
+
*/
|
|
21081
|
+
classes: array(string().min(1).max(60)).max(40).optional()
|
|
21082
|
+
});
|
|
21083
|
+
var RecentSummariesPageSchema = object({
|
|
21084
|
+
/** Ordered by (`lastActiveAt` DESC, id DESC). Same light item as
|
|
21085
|
+
* {@link listSummaries} — one list shape, so a card renders the same
|
|
21086
|
+
* whichever feed drew it. */
|
|
21087
|
+
summaries: array(SummaryListItemSchema).readonly(),
|
|
21088
|
+
nextCursor: string().nullable()
|
|
20977
21089
|
});
|
|
20978
21090
|
var RecentTracksPageSchema = object({
|
|
20979
21091
|
/** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
|
|
@@ -21387,7 +21499,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
21387
21499
|
classes: array(string()).optional(),
|
|
21388
21500
|
/** See {@link ExcludeSourcesDoc}. */
|
|
21389
21501
|
excludeSources: array(TrackSourceSchema).optional()
|
|
21390
|
-
}), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(SummariesQueryInput, SummariesPageSchema), method(object({ id: string() }), SummaryDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
|
|
21502
|
+
}), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(SummariesQueryInput, SummariesPageSchema), method(RecentSummariesQueryInput, RecentSummariesPageSchema), method(object({ id: string() }), SummaryDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
|
|
21391
21503
|
kind: "mutation",
|
|
21392
21504
|
auth: "admin"
|
|
21393
21505
|
}), 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({
|
|
@@ -33148,7 +33260,29 @@ var LoggingSettingsPatchSchema = object({
|
|
|
33148
33260
|
* disarmed the channels it did not mention would make the Levels page and
|
|
33149
33261
|
* the Diagnostics page fight over the same value.
|
|
33150
33262
|
*/
|
|
33151
|
-
channels: array(LogChannelWindowPatchSchema).readonly().optional()
|
|
33263
|
+
channels: array(LogChannelWindowPatchSchema).readonly().optional(),
|
|
33264
|
+
/**
|
|
33265
|
+
* How many days the analytics OPS LOG is kept — the audit trail of what
|
|
33266
|
+
* retention actually deleted.
|
|
33267
|
+
*
|
|
33268
|
+
* It lives HERE, on the logging document, and not on the analytics addon's
|
|
33269
|
+
* settings form, on the operator's instruction: every other log-ish window in
|
|
33270
|
+
* this system is configured through this one document, and a retention audit
|
|
33271
|
+
* configured somewhere else is a second place to look when the question is
|
|
33272
|
+
* "what happened to my data".
|
|
33273
|
+
*
|
|
33274
|
+
* That placement has a cost worth stating: this document ships in the
|
|
33275
|
+
* framework closure, so this knob needs a published `@camstack/server` while
|
|
33276
|
+
* the four windows beside it (D485) reach a node on `camstack deploy`.
|
|
33277
|
+
*
|
|
33278
|
+
* `retention-model.ts` argued this one must NOT follow a device window,
|
|
33279
|
+
* because the audit trail is the history of the SWEEP and not of the camera.
|
|
33280
|
+
* That argument stands and is untouched — what changes is that 30 days stops
|
|
33281
|
+
* being a constant nobody can reach. `0` keeps it forever. The floor is 1 day
|
|
33282
|
+
* rather than 0-as-delete: an audit log truncated to nothing is precisely the
|
|
33283
|
+
* state in which the next 9.5 GiB leak cannot be explained.
|
|
33284
|
+
*/
|
|
33285
|
+
opsLogRetentionDays: number().int().min(0).max(3650).optional()
|
|
33152
33286
|
});
|
|
33153
33287
|
/**
|
|
33154
33288
|
* Which LAYER of the hierarchy is addressed. Absent = the cluster layer.
|
|
@@ -33221,6 +33355,14 @@ var LoggingSettingsStateSchema = object({
|
|
|
33221
33355
|
channels: array(LogChannelDescriptorSchema).readonly(),
|
|
33222
33356
|
/** The channels ARMED right now, each with its deadline. */
|
|
33223
33357
|
activeChannels: array(LogChannelWindowStateSchema).readonly(),
|
|
33358
|
+
/**
|
|
33359
|
+
* The ops-log window in days, as it is in force. `0` = kept forever.
|
|
33360
|
+
*
|
|
33361
|
+
* Reported rather than left to the caller's memory of what it wrote: this is
|
|
33362
|
+
* the value the analytics sweep will actually use, and an operator asking how
|
|
33363
|
+
* long their audit trail lives should not have to infer it from a default.
|
|
33364
|
+
*/
|
|
33365
|
+
opsLogRetentionDays: number().int().min(0),
|
|
33224
33366
|
persisted: boolean()
|
|
33225
33367
|
});
|
|
33226
33368
|
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(), {
|
|
@@ -39221,6 +39363,12 @@ Object.freeze({
|
|
|
39221
39363
|
addonId: null,
|
|
39222
39364
|
access: "view"
|
|
39223
39365
|
},
|
|
39366
|
+
"pipelineAnalytics.listRecentSummaries": {
|
|
39367
|
+
capName: "pipeline-analytics",
|
|
39368
|
+
capScope: "device",
|
|
39369
|
+
addonId: null,
|
|
39370
|
+
access: "view"
|
|
39371
|
+
},
|
|
39224
39372
|
"pipelineAnalytics.listRecentTracks": {
|
|
39225
39373
|
capName: "pipeline-analytics",
|
|
39226
39374
|
capScope: "device",
|
|
@@ -43048,6 +43196,11 @@ Object.freeze({
|
|
|
43048
43196
|
form: "single",
|
|
43049
43197
|
optional: true
|
|
43050
43198
|
}],
|
|
43199
|
+
"pipelineAnalytics.listRecentSummaries": [{
|
|
43200
|
+
name: "deviceIds",
|
|
43201
|
+
form: "array",
|
|
43202
|
+
optional: false
|
|
43203
|
+
}],
|
|
43051
43204
|
"pipelineAnalytics.listRecentTracks": [{
|
|
43052
43205
|
name: "deviceIds",
|
|
43053
43206
|
form: "array",
|
package/dist/addon.mjs
CHANGED
|
@@ -6165,7 +6165,7 @@ var ZodIssueCode = {
|
|
|
6165
6165
|
var ZodFirstPartyTypeKind;
|
|
6166
6166
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
6167
6167
|
//#endregion
|
|
6168
|
-
//#region ../types/dist/sleep-
|
|
6168
|
+
//#region ../types/dist/sleep-DBKu2-U5.mjs
|
|
6169
6169
|
/**
|
|
6170
6170
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
6171
6171
|
* window to float samples (D455).
|
|
@@ -8194,7 +8194,23 @@ var EncodeProfileSchema = object({
|
|
|
8194
8194
|
"zerolatency",
|
|
8195
8195
|
"film",
|
|
8196
8196
|
"animation"
|
|
8197
|
-
]).optional()
|
|
8197
|
+
]).optional(),
|
|
8198
|
+
/**
|
|
8199
|
+
* ONE slice per access unit.
|
|
8200
|
+
*
|
|
8201
|
+
* `-tune zerolatency` turns on x264's sliced threads, and a frame then leaves
|
|
8202
|
+
* the encoder as five NAL slices that share one RTP timestamp and carry one
|
|
8203
|
+
* marker bit. A libwebrtc depacketiser sees five frame-starts and one
|
|
8204
|
+
* frame-end per frame: the first pictures render and the video then freezes
|
|
8205
|
+
* for good while the audio, on its own plane, plays on. Measured on this hub
|
|
8206
|
+
* 2026-09-13 against the Echo, and reduced to one slice by this flag alone.
|
|
8207
|
+
*
|
|
8208
|
+
* A NAMED field and not a raw flag, because {@link EgressEncodeSchema} omits
|
|
8209
|
+
* `outputArgs` on purpose: an opaque array is part of the sharing key, so two
|
|
8210
|
+
* consumers meaning the same thing spelled differently would stop sharing one
|
|
8211
|
+
* child. Absent means "whatever the encoder does" — today's behaviour.
|
|
8212
|
+
*/
|
|
8213
|
+
singleSlicePerFrame: boolean().optional()
|
|
8198
8214
|
}),
|
|
8199
8215
|
audio: union([literal("passthrough"), object({
|
|
8200
8216
|
codec: _enum([
|
|
@@ -8244,7 +8260,7 @@ var BASE_LIVE_EGRESS_PROFILE = {
|
|
|
8244
8260
|
audio: "passthrough"
|
|
8245
8261
|
};
|
|
8246
8262
|
({ ...BASE_LIVE_EGRESS_PROFILE }), { ...BASE_LIVE_EGRESS_PROFILE.video };
|
|
8247
|
-
({ ...BASE_LIVE_EGRESS_PROFILE });
|
|
8263
|
+
({ ...BASE_LIVE_EGRESS_PROFILE }), { ...BASE_LIVE_EGRESS_PROFILE.video };
|
|
8248
8264
|
/**
|
|
8249
8265
|
* Deep wiring healthcheck — snapshot of active reachability probes across
|
|
8250
8266
|
* every declared capability + widget of every installed plugin, on every
|
|
@@ -20966,13 +20982,109 @@ var SummariesQueryInput = object({
|
|
|
20966
20982
|
deviceIds: array(number()).min(1),
|
|
20967
20983
|
since: number().optional(),
|
|
20968
20984
|
until: number().optional(),
|
|
20969
|
-
limit: number().int().min(1).max(200).default(50)
|
|
20985
|
+
limit: number().int().min(1).max(200).default(50),
|
|
20986
|
+
/** The same member-wise filter {@link listRecentSummaries} takes — one
|
|
20987
|
+
* meaning of "dog" on every summary surface. */
|
|
20988
|
+
classes: array(string().min(1).max(60)).max(40).optional()
|
|
20970
20989
|
});
|
|
20971
|
-
var SummariesPageSchema = object({ summaries: array(SummarySchema).readonly() });
|
|
20972
20990
|
var SummaryDetailSchema = object({
|
|
20973
20991
|
summary: SummarySchema,
|
|
20974
|
-
/**
|
|
20975
|
-
|
|
20992
|
+
/** Members in absorption order, oldest join first. */
|
|
20993
|
+
members: array(object({
|
|
20994
|
+
trackId: string(),
|
|
20995
|
+
/**
|
|
20996
|
+
* The track's class at the time it JOINED, or `null` when it was unresolved
|
|
20997
|
+
* and the track no longer exists to fill it.
|
|
20998
|
+
*
|
|
20999
|
+
* The join, not the latest opinion: class voting can re-decide a track's
|
|
21000
|
+
* class afterwards, and a group's composition is the history of who came
|
|
21001
|
+
* together. A consumer counts these to badge a thumbnail — "two people and a
|
|
21002
|
+
* dog" — rather than being handed a second, denormalised tally that would
|
|
21003
|
+
* drift from the members it claims to describe.
|
|
21004
|
+
*/
|
|
21005
|
+
className: string().nullable(),
|
|
21006
|
+
/** `primary` is the one member that carries the group's identity. */
|
|
21007
|
+
role: _enum([
|
|
21008
|
+
"primary",
|
|
21009
|
+
"sibling",
|
|
21010
|
+
"child"
|
|
21011
|
+
]).nullable(),
|
|
21012
|
+
joinedAt: number(),
|
|
21013
|
+
/** Tier 1 — the sub-class (`dog`, `van`), resolved from the member's track
|
|
21014
|
+
* at read time. Absent when nothing resolved, never an empty string. */
|
|
21015
|
+
label: string().optional(),
|
|
21016
|
+
/** Tier 2 — the instance: a person's name, a plate. Absent when the pipeline
|
|
21017
|
+
* recognised nobody, and absent for a member whose track has been pruned —
|
|
21018
|
+
* a thumbnail that names the wrong person is worse than one naming nobody. */
|
|
21019
|
+
subLabel: string().optional()
|
|
21020
|
+
})).readonly()
|
|
21021
|
+
});
|
|
21022
|
+
/**
|
|
21023
|
+
* What a LIST of groups carries: the envelope plus what it is MADE OF.
|
|
21024
|
+
*
|
|
21025
|
+
* Coarse on purpose — the operator's rule is "only the rough data on the list,
|
|
21026
|
+
* we extend when we notice we need more". Enough to draw the card ("two people
|
|
21027
|
+
* and a dog") and no more. The MEMBERS, their names and the per-member links
|
|
21028
|
+
* are on {@link getSummary}: shipping every member of every group so a client
|
|
21029
|
+
* can count them turns a page of two hundred groups into a thousand records to
|
|
21030
|
+
* draw two hundred badges.
|
|
21031
|
+
*/
|
|
21032
|
+
var SummaryListItemSchema = object({
|
|
21033
|
+
summary: SummarySchema,
|
|
21034
|
+
/** Class counts, most numerous first; `className: null` is a member whose
|
|
21035
|
+
* class never resolved, counted so the counts add up to `memberCount`. */
|
|
21036
|
+
classes: array(object({
|
|
21037
|
+
className: string().nullable(),
|
|
21038
|
+
count: number().int().positive()
|
|
21039
|
+
})).readonly()
|
|
21040
|
+
});
|
|
21041
|
+
var SummariesPageSchema = object({ summaries: array(SummaryListItemSchema).readonly() });
|
|
21042
|
+
/**
|
|
21043
|
+
* The paged feed, deliberately the SAME shape as {@link RecentTracksQueryInput}.
|
|
21044
|
+
*
|
|
21045
|
+
* The reel on the cameras page and the Events gallery both ride a cursor, so a
|
|
21046
|
+
* summaries feed that could only answer "the last N for these cameras"
|
|
21047
|
+
* (`listSummaries`) would make groups available in the timeline and nowhere
|
|
21048
|
+
* else. Two feeds with different ordering contracts would be two ideas of what
|
|
21049
|
+
* "newest" means, on one screen.
|
|
21050
|
+
*/
|
|
21051
|
+
var RecentSummariesQueryInput = object({
|
|
21052
|
+
/** Devices to merge. An empty array yields an empty page. */
|
|
21053
|
+
deviceIds: array(number()),
|
|
21054
|
+
/** Window lower bound on `lastActiveAt` (inclusive). */
|
|
21055
|
+
since: number().optional(),
|
|
21056
|
+
/** Window upper bound on `lastActiveAt` (inclusive). */
|
|
21057
|
+
until: number().optional(),
|
|
21058
|
+
limit: number().int().min(1).max(500).default(100),
|
|
21059
|
+
/** Opaque continuation cursor from a previous page's `nextCursor`. */
|
|
21060
|
+
cursor: string().optional(),
|
|
21061
|
+
/**
|
|
21062
|
+
* Restrict to these classes — THE SAME FIELD `listRecentTracks` takes, and
|
|
21063
|
+
* deliberately the same name: the events filter tree emits one list of ticked
|
|
21064
|
+
* taxonomy nodes, and a summaries feed that called it something else would
|
|
21065
|
+
* make the operator's one filter component produce two shapes.
|
|
21066
|
+
*
|
|
21067
|
+
* A question about the MEMBERS: a group matches when ANY of them does. "Show
|
|
21068
|
+
* me the arrivals with a dog" has to return the group of four people who had
|
|
21069
|
+
* one with them; a filter on the group's own fields could only ever answer
|
|
21070
|
+
* about its primary.
|
|
21071
|
+
*
|
|
21072
|
+
* Matched against all THREE tiers of a member — the class (`animal`), the
|
|
21073
|
+
* sub-class (`dog`) and the instance (a name, a plate) — because which tier a
|
|
21074
|
+
* ticked node lives on is the taxonomy's business, not the caller's. `dog` is
|
|
21075
|
+
* an event kind in the tree and a tier-1 label on an `animal` track; a filter
|
|
21076
|
+
* that read only the class would answer "animal" and never "dog".
|
|
21077
|
+
*
|
|
21078
|
+
* ABSENT or EMPTY means no filter — absent is not a selection of none.
|
|
21079
|
+
*/
|
|
21080
|
+
classes: array(string().min(1).max(60)).max(40).optional()
|
|
21081
|
+
});
|
|
21082
|
+
var RecentSummariesPageSchema = object({
|
|
21083
|
+
/** Ordered by (`lastActiveAt` DESC, id DESC). Same light item as
|
|
21084
|
+
* {@link listSummaries} — one list shape, so a card renders the same
|
|
21085
|
+
* whichever feed drew it. */
|
|
21086
|
+
summaries: array(SummaryListItemSchema).readonly(),
|
|
21087
|
+
nextCursor: string().nullable()
|
|
20976
21088
|
});
|
|
20977
21089
|
var RecentTracksPageSchema = object({
|
|
20978
21090
|
/** Merged page, ordered by (`lastSeen` DESC, `trackId` DESC). */
|
|
@@ -21386,7 +21498,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
21386
21498
|
classes: array(string()).optional(),
|
|
21387
21499
|
/** See {@link ExcludeSourcesDoc}. */
|
|
21388
21500
|
excludeSources: array(TrackSourceSchema).optional()
|
|
21389
|
-
}), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(SummariesQueryInput, SummariesPageSchema), method(object({ id: string() }), SummaryDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
|
|
21501
|
+
}), array(TrackSchema).readonly()), method(RecentTracksQueryInput, RecentTracksPageSchema), method(SummariesQueryInput, SummariesPageSchema), method(RecentSummariesQueryInput, RecentSummariesPageSchema), method(object({ id: string() }), SummaryDetailSchema.nullable()), method(object({ deviceId: number() }), _void(), {
|
|
21390
21502
|
kind: "mutation",
|
|
21391
21503
|
auth: "admin"
|
|
21392
21504
|
}), 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({
|
|
@@ -33147,7 +33259,29 @@ var LoggingSettingsPatchSchema = object({
|
|
|
33147
33259
|
* disarmed the channels it did not mention would make the Levels page and
|
|
33148
33260
|
* the Diagnostics page fight over the same value.
|
|
33149
33261
|
*/
|
|
33150
|
-
channels: array(LogChannelWindowPatchSchema).readonly().optional()
|
|
33262
|
+
channels: array(LogChannelWindowPatchSchema).readonly().optional(),
|
|
33263
|
+
/**
|
|
33264
|
+
* How many days the analytics OPS LOG is kept — the audit trail of what
|
|
33265
|
+
* retention actually deleted.
|
|
33266
|
+
*
|
|
33267
|
+
* It lives HERE, on the logging document, and not on the analytics addon's
|
|
33268
|
+
* settings form, on the operator's instruction: every other log-ish window in
|
|
33269
|
+
* this system is configured through this one document, and a retention audit
|
|
33270
|
+
* configured somewhere else is a second place to look when the question is
|
|
33271
|
+
* "what happened to my data".
|
|
33272
|
+
*
|
|
33273
|
+
* That placement has a cost worth stating: this document ships in the
|
|
33274
|
+
* framework closure, so this knob needs a published `@camstack/server` while
|
|
33275
|
+
* the four windows beside it (D485) reach a node on `camstack deploy`.
|
|
33276
|
+
*
|
|
33277
|
+
* `retention-model.ts` argued this one must NOT follow a device window,
|
|
33278
|
+
* because the audit trail is the history of the SWEEP and not of the camera.
|
|
33279
|
+
* That argument stands and is untouched — what changes is that 30 days stops
|
|
33280
|
+
* being a constant nobody can reach. `0` keeps it forever. The floor is 1 day
|
|
33281
|
+
* rather than 0-as-delete: an audit log truncated to nothing is precisely the
|
|
33282
|
+
* state in which the next 9.5 GiB leak cannot be explained.
|
|
33283
|
+
*/
|
|
33284
|
+
opsLogRetentionDays: number().int().min(0).max(3650).optional()
|
|
33151
33285
|
});
|
|
33152
33286
|
/**
|
|
33153
33287
|
* Which LAYER of the hierarchy is addressed. Absent = the cluster layer.
|
|
@@ -33220,6 +33354,14 @@ var LoggingSettingsStateSchema = object({
|
|
|
33220
33354
|
channels: array(LogChannelDescriptorSchema).readonly(),
|
|
33221
33355
|
/** The channels ARMED right now, each with its deadline. */
|
|
33222
33356
|
activeChannels: array(LogChannelWindowStateSchema).readonly(),
|
|
33357
|
+
/**
|
|
33358
|
+
* The ops-log window in days, as it is in force. `0` = kept forever.
|
|
33359
|
+
*
|
|
33360
|
+
* Reported rather than left to the caller's memory of what it wrote: this is
|
|
33361
|
+
* the value the analytics sweep will actually use, and an operator asking how
|
|
33362
|
+
* long their audit trail lives should not have to infer it from a default.
|
|
33363
|
+
*/
|
|
33364
|
+
opsLogRetentionDays: number().int().min(0),
|
|
33223
33365
|
persisted: boolean()
|
|
33224
33366
|
});
|
|
33225
33367
|
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(), {
|
|
@@ -39220,6 +39362,12 @@ Object.freeze({
|
|
|
39220
39362
|
addonId: null,
|
|
39221
39363
|
access: "view"
|
|
39222
39364
|
},
|
|
39365
|
+
"pipelineAnalytics.listRecentSummaries": {
|
|
39366
|
+
capName: "pipeline-analytics",
|
|
39367
|
+
capScope: "device",
|
|
39368
|
+
addonId: null,
|
|
39369
|
+
access: "view"
|
|
39370
|
+
},
|
|
39223
39371
|
"pipelineAnalytics.listRecentTracks": {
|
|
39224
39372
|
capName: "pipeline-analytics",
|
|
39225
39373
|
capScope: "device",
|
|
@@ -43047,6 +43195,11 @@ Object.freeze({
|
|
|
43047
43195
|
form: "single",
|
|
43048
43196
|
optional: true
|
|
43049
43197
|
}],
|
|
43198
|
+
"pipelineAnalytics.listRecentSummaries": [{
|
|
43199
|
+
name: "deviceIds",
|
|
43200
|
+
form: "array",
|
|
43201
|
+
optional: false
|
|
43202
|
+
}],
|
|
43050
43203
|
"pipelineAnalytics.listRecentTracks": [{
|
|
43051
43204
|
name: "deviceIds",
|
|
43052
43205
|
form: "array",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-provider-tuya",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.101",
|
|
4
4
|
"description": "Tuya / Smart Life device-provider addon for CamStack — account-onboarded (Tuya IoT cloud fetch of device localKeys) + LOCAL DP control via the @apocaliss92/nodetuya encrypted-LAN client, exposing switch / water-heater-family kettle entities",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|