@camstack/addon-matter-broker 0.2.142 → 0.2.144
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 +114 -67
- package/dist/addon.mjs +114 -67
- package/package.json +1 -1
package/dist/addon.js
CHANGED
|
@@ -13,7 +13,7 @@ let node_stream_promises = require("node:stream/promises");
|
|
|
13
13
|
let node_net = require("node:net");
|
|
14
14
|
let node_dgram = require("node:dgram");
|
|
15
15
|
node_dgram = require_esm.__toESM(node_dgram, 1);
|
|
16
|
-
//#region ../types/dist/event-category-
|
|
16
|
+
//#region ../types/dist/event-category-BfJwUd2S.mjs
|
|
17
17
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
18
18
|
EventCategory["SystemBoot"] = "system.boot";
|
|
19
19
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -330,6 +330,15 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
330
330
|
*/
|
|
331
331
|
EventCategory["PipelineDetectionBlind"] = "pipeline.detection-blind";
|
|
332
332
|
/**
|
|
333
|
+
* A camera's motion source has fired constantly with no subject for an hour
|
|
334
|
+
* (motion duty or session count over the bar, zero detections) — it is not
|
|
335
|
+
* blind, its motion zones or sensitivity want tuning (D907). Paired with
|
|
336
|
+
* {@link PipelineMotionCalm}.
|
|
337
|
+
*/
|
|
338
|
+
EventCategory["PipelineMotionNoisy"] = "pipeline.motion-noisy";
|
|
339
|
+
/** The recovery edge of {@link PipelineMotionNoisy}: the motion fell back, or a detection arrived. */
|
|
340
|
+
EventCategory["PipelineMotionCalm"] = "pipeline.motion-calm";
|
|
341
|
+
/**
|
|
333
342
|
* Per-camera pipeline config was mutated by the orchestrator
|
|
334
343
|
* (3-level settings change via `setAgentAddonDefaults` /
|
|
335
344
|
* `setCameraStepToggle` / `setCameraPipelineForAgent` or a
|
|
@@ -5569,7 +5578,7 @@ var ZodIssueCode = {
|
|
|
5569
5578
|
var ZodFirstPartyTypeKind;
|
|
5570
5579
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5571
5580
|
//#endregion
|
|
5572
|
-
//#region ../types/dist/sleep-
|
|
5581
|
+
//#region ../types/dist/sleep-DJFUfKvA.mjs
|
|
5573
5582
|
/**
|
|
5574
5583
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5575
5584
|
* window to float samples (D455).
|
|
@@ -8168,7 +8177,7 @@ var EntryDescriptorSchema = object({
|
|
|
8168
8177
|
/** JSON Schema of the entry body; `secret: true` marks a password field. */
|
|
8169
8178
|
fields: record(string$2(), unknown())
|
|
8170
8179
|
}).strict();
|
|
8171
|
-
/** What crosses the wire
|
|
8180
|
+
/** What crosses the wire from an addon: JSON only, no Zod. An unknown key is refused. */
|
|
8172
8181
|
var RecordKindDeclarationSchema = object({
|
|
8173
8182
|
database: _enum(RECORD_DATABASES).default("settings"),
|
|
8174
8183
|
class: _enum(RECORD_CLASSES),
|
|
@@ -8187,14 +8196,6 @@ var RecordKindDeclarationSchema = object({
|
|
|
8187
8196
|
secretPaths: array(string$2().min(1)).default([]),
|
|
8188
8197
|
/** The id key of each array that carries a secret (`{ headers: 'name' }`). */
|
|
8189
8198
|
secretArrayKeys: record(string$2(), string$2()).default({}),
|
|
8190
|
-
/**
|
|
8191
|
-
* RETIRED (D900): the legacy table a kind adopted from during the records
|
|
8192
|
-
* migration. Nothing declares it any more and nothing reads it; the schema
|
|
8193
|
-
* still ACCEPTS it because the catalog rows the migration wrote carry it
|
|
8194
|
-
* (an orphaned kind is never redeclared) and an addon built before the
|
|
8195
|
-
* removal still sends it. Never set it.
|
|
8196
|
-
*/
|
|
8197
|
-
adoptsFrom: string$2().min(1).optional(),
|
|
8198
8199
|
/** Kinds that must agree through `transact` sit in one file under one family name. */
|
|
8199
8200
|
transactFamily: string$2().min(1).optional(),
|
|
8200
8201
|
entry: EntryDescriptorSchema.optional()
|
|
@@ -12990,17 +12991,6 @@ object({
|
|
|
12990
12991
|
createdAt: number(),
|
|
12991
12992
|
updatedAt: number()
|
|
12992
12993
|
});
|
|
12993
|
-
object({
|
|
12994
|
-
id: string$2(),
|
|
12995
|
-
label: string$2(),
|
|
12996
|
-
isAdmin: boolean().default(false),
|
|
12997
|
-
allowedProviders: AllowedProviderSchema,
|
|
12998
|
-
allowedDevices: AllowedDevicesSchema,
|
|
12999
|
-
tokenHash: string$2(),
|
|
13000
|
-
tokenPrefix: string$2(),
|
|
13001
|
-
createdAt: number(),
|
|
13002
|
-
lastUsedAt: number().optional()
|
|
13003
|
-
});
|
|
13004
12994
|
object({
|
|
13005
12995
|
id: string$2(),
|
|
13006
12996
|
userId: string$2(),
|
|
@@ -17031,16 +17021,36 @@ var RecordKindStateSchema = _enum([
|
|
|
17031
17021
|
var DeclareKindResultSchema = object({
|
|
17032
17022
|
kindId: number().int(),
|
|
17033
17023
|
state: RecordKindStateSchema,
|
|
17034
|
-
createdIndexes: array(string$2())
|
|
17035
|
-
/**
|
|
17036
|
-
* RETIRED (D900): always `null`. It carried the records-migration boot guard;
|
|
17037
|
-
* it stays on the wire, null, because an addon built before the removal reads
|
|
17038
|
-
* an ABSENT field as "adoption pending" and refuses to start.
|
|
17039
|
-
*/
|
|
17040
|
-
adoptionPending: _null()
|
|
17024
|
+
createdIndexes: array(string$2())
|
|
17041
17025
|
});
|
|
17042
17026
|
/** Keychain refs a write released (the old marker is gone from the row): the owner deletes the values. */
|
|
17043
17027
|
var SecretRefsList = array(string$2());
|
|
17028
|
+
/**
|
|
17029
|
+
* One op of a `transact`: the single-row writes, each on a kind of the caller.
|
|
17030
|
+
* All ops of one call share ONE database file and ONE `transactFamily`.
|
|
17031
|
+
*/
|
|
17032
|
+
var RecordTransactOpSchema = discriminatedUnion("op", [
|
|
17033
|
+
object({
|
|
17034
|
+
op: literal("put"),
|
|
17035
|
+
kind: RecordKindNameSchema,
|
|
17036
|
+
record: RecordInputSchema,
|
|
17037
|
+
ifRev: number().int().min(0).optional()
|
|
17038
|
+
}),
|
|
17039
|
+
object({
|
|
17040
|
+
op: literal("patch"),
|
|
17041
|
+
kind: RecordKindNameSchema,
|
|
17042
|
+
id: RecordIdSchema,
|
|
17043
|
+
data: RecordBodySchema,
|
|
17044
|
+
at: number().int().nullable().optional(),
|
|
17045
|
+
expiresAt: number().int().nullable().optional(),
|
|
17046
|
+
ifRev: number().int().min(1).optional()
|
|
17047
|
+
}),
|
|
17048
|
+
object({
|
|
17049
|
+
op: literal("delete"),
|
|
17050
|
+
kind: RecordKindNameSchema,
|
|
17051
|
+
id: RecordIdSchema
|
|
17052
|
+
})
|
|
17053
|
+
]);
|
|
17044
17054
|
var RecordSecretRefsSchema = record(string$2(), record(string$2(), string$2()));
|
|
17045
17055
|
method(object({ kinds: record(RecordKindNameSchema, RecordKindDeclarationSchema) }), object({ kinds: record(string$2(), DeclareKindResultSchema) }), {
|
|
17046
17056
|
kind: "mutation",
|
|
@@ -17147,6 +17157,16 @@ method(object({ kinds: record(RecordKindNameSchema, RecordKindDeclarationSchema)
|
|
|
17147
17157
|
}), {
|
|
17148
17158
|
kind: "mutation",
|
|
17149
17159
|
auth: "admin"
|
|
17160
|
+
}), method(object({ ops: array(RecordTransactOpSchema).min(1).max(RECORD_BATCH_MAX) }), object({
|
|
17161
|
+
results: array(object({
|
|
17162
|
+
rev: number().int().nullable(),
|
|
17163
|
+
deleted: boolean()
|
|
17164
|
+
})),
|
|
17165
|
+
releasedRefs: SecretRefsList,
|
|
17166
|
+
secretRefs: SecretRefsList
|
|
17167
|
+
}), {
|
|
17168
|
+
kind: "mutation",
|
|
17169
|
+
auth: "admin"
|
|
17150
17170
|
}), method(object({
|
|
17151
17171
|
deviceId: number().int(),
|
|
17152
17172
|
kinds: array(RecordKindNameSchema).optional()
|
|
@@ -42758,9 +42778,13 @@ var NcSystemEventKindSchema = _enum([
|
|
|
42758
42778
|
"node-updating",
|
|
42759
42779
|
"node-inference-unavailable",
|
|
42760
42780
|
"detection-blind",
|
|
42781
|
+
"motion-noisy",
|
|
42782
|
+
"motion-calm",
|
|
42761
42783
|
"recording-stalled",
|
|
42762
42784
|
"recording-healthy",
|
|
42763
42785
|
"recording-degraded",
|
|
42786
|
+
"device-attention-required",
|
|
42787
|
+
"device-attention-resolved",
|
|
42764
42788
|
"storage-location-low",
|
|
42765
42789
|
"storage-location-critical",
|
|
42766
42790
|
"storage-location-ok",
|
|
@@ -48321,7 +48345,6 @@ var RecommendationReasonSchema = discriminatedUnion("kind", [
|
|
|
48321
48345
|
modelId: string$2()
|
|
48322
48346
|
}),
|
|
48323
48347
|
object({ kind: literal("cpu-device") }),
|
|
48324
|
-
object({ kind: literal("coral-untouched") }),
|
|
48325
48348
|
object({ kind: literal("device-disabled") }),
|
|
48326
48349
|
object({ kind: literal("device-unavailable") }),
|
|
48327
48350
|
object({ kind: literal("node-offline") }),
|
|
@@ -48419,11 +48442,6 @@ var AutoTuneWarningSchema = discriminatedUnion("kind", [
|
|
|
48419
48442
|
kind: literal("detector-store-unreadable"),
|
|
48420
48443
|
error: string$2()
|
|
48421
48444
|
}),
|
|
48422
|
-
object({
|
|
48423
|
-
kind: literal("coral-enabled"),
|
|
48424
|
-
nodeId: string$2(),
|
|
48425
|
-
deviceKey: string$2()
|
|
48426
|
-
}),
|
|
48427
48445
|
object({
|
|
48428
48446
|
kind: literal("custom-pin-kept"),
|
|
48429
48447
|
nodeId: string$2(),
|
|
@@ -56101,6 +56119,16 @@ var DishwasherStatusSchema = object({
|
|
|
56101
56119
|
powerState: string$2().nullable(),
|
|
56102
56120
|
saltLevel: DishwasherConsumableLevelSchema.nullable(),
|
|
56103
56121
|
rinseAidLevel: DishwasherConsumableLevelSchema.nullable(),
|
|
56122
|
+
/**
|
|
56123
|
+
* True while the appliance asks for its filter to be cleaned (smart-filter, filter-system or
|
|
56124
|
+
* combined care-and-filter reminder raised); false when every such reminder reads clear; null
|
|
56125
|
+
* when none is reported. A cleared reminder is not an unknown one.
|
|
56126
|
+
*/
|
|
56127
|
+
filterCleaningDue: boolean().nullable(),
|
|
56128
|
+
/** True while the machine-care (descaling / cleaning-program) reminder is raised; false when clear; null when not reported. */
|
|
56129
|
+
machineCareDue: boolean().nullable(),
|
|
56130
|
+
/** Program runs left before the machine-care reminder is due; null when the appliance does not say. */
|
|
56131
|
+
machineCareRemainingRuns: number().int().nonnegative().nullable(),
|
|
56104
56132
|
/** Option states: null when the appliance does not expose the option or has not said. */
|
|
56105
56133
|
halfLoad: boolean().nullable(),
|
|
56106
56134
|
hygienePlus: boolean().nullable(),
|
|
@@ -64751,16 +64779,6 @@ var UpdateUserInputSchema = object({
|
|
|
64751
64779
|
allowedDevices: record(string$2(), union([array(string$2()), literal("*")])).optional(),
|
|
64752
64780
|
scopes: array(TokenScopeSchema).optional()
|
|
64753
64781
|
});
|
|
64754
|
-
var ApiKeySummarySchema = object({
|
|
64755
|
-
id: string$2(),
|
|
64756
|
-
label: string$2(),
|
|
64757
|
-
isAdmin: boolean().default(false),
|
|
64758
|
-
allowedProviders: union([array(string$2()), literal("*")]).optional(),
|
|
64759
|
-
allowedDevices: record(string$2(), union([array(string$2()), literal("*")])).optional(),
|
|
64760
|
-
tokenPrefix: string$2(),
|
|
64761
|
-
createdAt: number(),
|
|
64762
|
-
lastUsedAt: number().optional()
|
|
64763
|
-
});
|
|
64764
64782
|
var OauthSessionSummarySchema = object({
|
|
64765
64783
|
id: string$2(),
|
|
64766
64784
|
userId: string$2(),
|
|
@@ -64782,8 +64800,7 @@ var TotpStatusSchema = object({
|
|
|
64782
64800
|
confirmedAt: number().nullable()
|
|
64783
64801
|
});
|
|
64784
64802
|
/**
|
|
64785
|
-
* user-management — singleton capability for user accounts
|
|
64786
|
-
* legacy API-key rows.
|
|
64803
|
+
* user-management — singleton capability for user accounts.
|
|
64787
64804
|
*
|
|
64788
64805
|
* v2 model: every method gated by `auth: 'admin'`. Admin-only delegation
|
|
64789
64806
|
* — the subset check on `setUserScopes` is moot
|
|
@@ -64839,10 +64856,6 @@ method(_void(), array(UserSummarySchema), { auth: "admin" }), method(CreateUserI
|
|
|
64839
64856
|
}), UserSummarySchema.extend({ passwordHash: string$2() }).nullable(), {
|
|
64840
64857
|
kind: "mutation",
|
|
64841
64858
|
access: "view"
|
|
64842
|
-
}), method(_void(), array(ApiKeySummarySchema), { auth: "admin" }), method(object({ id: string$2() }), object({ success: literal(true) }), {
|
|
64843
|
-
kind: "mutation",
|
|
64844
|
-
auth: "admin",
|
|
64845
|
-
access: "delete"
|
|
64846
64859
|
}), method(object({ userId: string$2() }), TotpSetupResultSchema, {
|
|
64847
64860
|
kind: "mutation",
|
|
64848
64861
|
auth: "admin",
|
|
@@ -74298,6 +74311,12 @@ Object.freeze({
|
|
|
74298
74311
|
addonId: null,
|
|
74299
74312
|
access: "view"
|
|
74300
74313
|
},
|
|
74314
|
+
"records.transact": {
|
|
74315
|
+
capName: "records",
|
|
74316
|
+
capScope: "system",
|
|
74317
|
+
addonId: null,
|
|
74318
|
+
access: "create"
|
|
74319
|
+
},
|
|
74301
74320
|
"sceneMonitor.captureReference": {
|
|
74302
74321
|
capName: "scene-monitor",
|
|
74303
74322
|
capScope: "device",
|
|
@@ -75630,12 +75649,6 @@ Object.freeze({
|
|
|
75630
75649
|
addonId: null,
|
|
75631
75650
|
access: "view"
|
|
75632
75651
|
},
|
|
75633
|
-
"userManagement.listApiKeys": {
|
|
75634
|
-
capName: "user-management",
|
|
75635
|
-
capScope: "system",
|
|
75636
|
-
addonId: null,
|
|
75637
|
-
access: "view"
|
|
75638
|
-
},
|
|
75639
75652
|
"userManagement.listExternalIdentities": {
|
|
75640
75653
|
capName: "user-management",
|
|
75641
75654
|
capScope: "system",
|
|
@@ -75690,12 +75703,6 @@ Object.freeze({
|
|
|
75690
75703
|
addonId: null,
|
|
75691
75704
|
access: "create"
|
|
75692
75705
|
},
|
|
75693
|
-
"userManagement.revokeApiKey": {
|
|
75694
|
-
capName: "user-management",
|
|
75695
|
-
capScope: "system",
|
|
75696
|
-
addonId: null,
|
|
75697
|
-
access: "delete"
|
|
75698
|
-
},
|
|
75699
75706
|
"userManagement.revokeOauthSession": {
|
|
75700
75707
|
capName: "user-management",
|
|
75701
75708
|
capScope: "system",
|
|
@@ -79060,9 +79067,13 @@ new Map(Object.entries({
|
|
|
79060
79067
|
"stream-online": "device-events",
|
|
79061
79068
|
"stream-offline": "device-events",
|
|
79062
79069
|
"detection-blind": "device-events",
|
|
79070
|
+
"motion-noisy": "device-events",
|
|
79071
|
+
"motion-calm": "device-events",
|
|
79063
79072
|
"recording-stalled": "device-events",
|
|
79064
79073
|
"recording-healthy": "device-events",
|
|
79065
79074
|
"recording-degraded": "device-events",
|
|
79075
|
+
"device-attention-required": "device-events",
|
|
79076
|
+
"device-attention-resolved": "device-events",
|
|
79066
79077
|
"node-online": "system",
|
|
79067
79078
|
"node-offline": "system",
|
|
79068
79079
|
"node-restarting": "system",
|
|
@@ -79145,6 +79156,12 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
|
|
|
79145
79156
|
label: "Detecting nothing",
|
|
79146
79157
|
kinds: ["detection-blind"]
|
|
79147
79158
|
},
|
|
79159
|
+
{
|
|
79160
|
+
id: "motion-noise",
|
|
79161
|
+
family: "device-events",
|
|
79162
|
+
label: "Motion without a subject",
|
|
79163
|
+
kinds: ["motion-noisy", "motion-calm"]
|
|
79164
|
+
},
|
|
79148
79165
|
{
|
|
79149
79166
|
id: "recording",
|
|
79150
79167
|
family: "device-events",
|
|
@@ -79155,6 +79172,12 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
|
|
|
79155
79172
|
"recording-degraded"
|
|
79156
79173
|
]
|
|
79157
79174
|
},
|
|
79175
|
+
{
|
|
79176
|
+
id: "device-attention",
|
|
79177
|
+
family: "device-events",
|
|
79178
|
+
label: "Needs attention",
|
|
79179
|
+
kinds: ["device-attention-required", "device-attention-resolved"]
|
|
79180
|
+
},
|
|
79158
79181
|
{
|
|
79159
79182
|
id: "nodes",
|
|
79160
79183
|
family: "system",
|
|
@@ -79294,6 +79317,7 @@ var ALERT_EPISODE = [
|
|
|
79294
79317
|
"alert-error",
|
|
79295
79318
|
"alert-critical-resolved"
|
|
79296
79319
|
];
|
|
79320
|
+
var DEVICE_ATTENTION = ["device-attention-required", "device-attention-resolved"];
|
|
79297
79321
|
var UPDATES = [
|
|
79298
79322
|
"addon-update-available",
|
|
79299
79323
|
"server-update-available",
|
|
@@ -79323,9 +79347,12 @@ var DEVICE_EVENTS = [
|
|
|
79323
79347
|
"stream-online",
|
|
79324
79348
|
"stream-offline",
|
|
79325
79349
|
"detection-blind",
|
|
79350
|
+
"motion-noisy",
|
|
79351
|
+
"motion-calm",
|
|
79326
79352
|
"recording-stalled",
|
|
79327
79353
|
"recording-healthy",
|
|
79328
79354
|
"recording-degraded",
|
|
79355
|
+
...DEVICE_ATTENTION,
|
|
79329
79356
|
...ALARM
|
|
79330
79357
|
];
|
|
79331
79358
|
/** Every kind a summary may speak about — the two summarisable families. */
|
|
@@ -79493,7 +79520,9 @@ var STATE_SUMMARY_VARS = [
|
|
|
79493
79520
|
[...RULE_TEXT],
|
|
79494
79521
|
[...RULE_TEXT],
|
|
79495
79522
|
[...RULE_TEXT],
|
|
79496
|
-
|
|
79523
|
+
[...RULE_TEXT],
|
|
79524
|
+
[...RULE_TEXT],
|
|
79525
|
+
([...RULE_TEXT], [...DEVICE_ATTENTION, ...ALERT_EPISODE]),
|
|
79497
79526
|
[...RULE_TEXT],
|
|
79498
79527
|
[...RULE_TEXT],
|
|
79499
79528
|
[...RULE_TEXT],
|
|
@@ -79515,11 +79544,11 @@ var STATE_SUMMARY_VARS = [
|
|
|
79515
79544
|
[...RULE_TEXT],
|
|
79516
79545
|
[...RULE_TEXT],
|
|
79517
79546
|
[...RULE_TEXT],
|
|
79547
|
+
([...RULE_TEXT], [...DEVICE_ATTENTION, ...ALERT_EPISODE]),
|
|
79518
79548
|
([...RULE_TEXT], [...ALERT_EPISODE]),
|
|
79549
|
+
([...RULE_TEXT], [...DEVICE_ATTENTION, ...ALERT_EPISODE]),
|
|
79519
79550
|
([...RULE_TEXT], [...ALERT_EPISODE]),
|
|
79520
|
-
([...RULE_TEXT], [...ALERT_EPISODE]),
|
|
79521
|
-
([...RULE_TEXT], [...ALERT_EPISODE]),
|
|
79522
|
-
([...RULE_TEXT], [...ALERT_EPISODE]),
|
|
79551
|
+
([...RULE_TEXT], [...DEVICE_ATTENTION, ...ALERT_EPISODE]),
|
|
79523
79552
|
[...RULE_TEXT],
|
|
79524
79553
|
[...RULE_TEXT],
|
|
79525
79554
|
[...RULE_TEXT],
|
|
@@ -79595,6 +79624,15 @@ new Map([
|
|
|
79595
79624
|
snapshotLabel: "Tanks low or full now",
|
|
79596
79625
|
snapshotSection: "tanks"
|
|
79597
79626
|
},
|
|
79627
|
+
{
|
|
79628
|
+
id: "motion-noise",
|
|
79629
|
+
family: "device-events",
|
|
79630
|
+
label: "Motion without a subject (constant / calm again)",
|
|
79631
|
+
bad: ["motion-noisy"],
|
|
79632
|
+
recovery: ["motion-calm"],
|
|
79633
|
+
snapshotLabel: "Cameras with constant motion now",
|
|
79634
|
+
snapshotSection: null
|
|
79635
|
+
},
|
|
79598
79636
|
{
|
|
79599
79637
|
id: "recording-health",
|
|
79600
79638
|
family: "device-events",
|
|
@@ -79604,6 +79642,15 @@ new Map([
|
|
|
79604
79642
|
snapshotLabel: "Recordings stalled now",
|
|
79605
79643
|
snapshotSection: null
|
|
79606
79644
|
},
|
|
79645
|
+
{
|
|
79646
|
+
id: "device-attention",
|
|
79647
|
+
family: "device-events",
|
|
79648
|
+
label: "Device needs attention (raised / resolved)",
|
|
79649
|
+
bad: ["device-attention-required"],
|
|
79650
|
+
recovery: ["device-attention-resolved"],
|
|
79651
|
+
snapshotLabel: "Devices needing attention now",
|
|
79652
|
+
snapshotSection: null
|
|
79653
|
+
},
|
|
79607
79654
|
{
|
|
79608
79655
|
id: "node-connectivity",
|
|
79609
79656
|
family: "system",
|
package/dist/addon.mjs
CHANGED
|
@@ -11,7 +11,7 @@ import { networkInterfaces, tmpdir, uptime } from "node:os";
|
|
|
11
11
|
import { finished } from "node:stream/promises";
|
|
12
12
|
import { createConnection, createServer as createServer$2 } from "node:net";
|
|
13
13
|
import * as dgram from "node:dgram";
|
|
14
|
-
//#region ../types/dist/event-category-
|
|
14
|
+
//#region ../types/dist/event-category-BfJwUd2S.mjs
|
|
15
15
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
16
16
|
EventCategory["SystemBoot"] = "system.boot";
|
|
17
17
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -328,6 +328,15 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
328
328
|
*/
|
|
329
329
|
EventCategory["PipelineDetectionBlind"] = "pipeline.detection-blind";
|
|
330
330
|
/**
|
|
331
|
+
* A camera's motion source has fired constantly with no subject for an hour
|
|
332
|
+
* (motion duty or session count over the bar, zero detections) — it is not
|
|
333
|
+
* blind, its motion zones or sensitivity want tuning (D907). Paired with
|
|
334
|
+
* {@link PipelineMotionCalm}.
|
|
335
|
+
*/
|
|
336
|
+
EventCategory["PipelineMotionNoisy"] = "pipeline.motion-noisy";
|
|
337
|
+
/** The recovery edge of {@link PipelineMotionNoisy}: the motion fell back, or a detection arrived. */
|
|
338
|
+
EventCategory["PipelineMotionCalm"] = "pipeline.motion-calm";
|
|
339
|
+
/**
|
|
331
340
|
* Per-camera pipeline config was mutated by the orchestrator
|
|
332
341
|
* (3-level settings change via `setAgentAddonDefaults` /
|
|
333
342
|
* `setCameraStepToggle` / `setCameraPipelineForAgent` or a
|
|
@@ -5567,7 +5576,7 @@ var ZodIssueCode = {
|
|
|
5567
5576
|
var ZodFirstPartyTypeKind;
|
|
5568
5577
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5569
5578
|
//#endregion
|
|
5570
|
-
//#region ../types/dist/sleep-
|
|
5579
|
+
//#region ../types/dist/sleep-DJFUfKvA.mjs
|
|
5571
5580
|
/**
|
|
5572
5581
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5573
5582
|
* window to float samples (D455).
|
|
@@ -8166,7 +8175,7 @@ var EntryDescriptorSchema = object({
|
|
|
8166
8175
|
/** JSON Schema of the entry body; `secret: true` marks a password field. */
|
|
8167
8176
|
fields: record(string$2(), unknown())
|
|
8168
8177
|
}).strict();
|
|
8169
|
-
/** What crosses the wire
|
|
8178
|
+
/** What crosses the wire from an addon: JSON only, no Zod. An unknown key is refused. */
|
|
8170
8179
|
var RecordKindDeclarationSchema = object({
|
|
8171
8180
|
database: _enum(RECORD_DATABASES).default("settings"),
|
|
8172
8181
|
class: _enum(RECORD_CLASSES),
|
|
@@ -8185,14 +8194,6 @@ var RecordKindDeclarationSchema = object({
|
|
|
8185
8194
|
secretPaths: array(string$2().min(1)).default([]),
|
|
8186
8195
|
/** The id key of each array that carries a secret (`{ headers: 'name' }`). */
|
|
8187
8196
|
secretArrayKeys: record(string$2(), string$2()).default({}),
|
|
8188
|
-
/**
|
|
8189
|
-
* RETIRED (D900): the legacy table a kind adopted from during the records
|
|
8190
|
-
* migration. Nothing declares it any more and nothing reads it; the schema
|
|
8191
|
-
* still ACCEPTS it because the catalog rows the migration wrote carry it
|
|
8192
|
-
* (an orphaned kind is never redeclared) and an addon built before the
|
|
8193
|
-
* removal still sends it. Never set it.
|
|
8194
|
-
*/
|
|
8195
|
-
adoptsFrom: string$2().min(1).optional(),
|
|
8196
8197
|
/** Kinds that must agree through `transact` sit in one file under one family name. */
|
|
8197
8198
|
transactFamily: string$2().min(1).optional(),
|
|
8198
8199
|
entry: EntryDescriptorSchema.optional()
|
|
@@ -12988,17 +12989,6 @@ object({
|
|
|
12988
12989
|
createdAt: number(),
|
|
12989
12990
|
updatedAt: number()
|
|
12990
12991
|
});
|
|
12991
|
-
object({
|
|
12992
|
-
id: string$2(),
|
|
12993
|
-
label: string$2(),
|
|
12994
|
-
isAdmin: boolean().default(false),
|
|
12995
|
-
allowedProviders: AllowedProviderSchema,
|
|
12996
|
-
allowedDevices: AllowedDevicesSchema,
|
|
12997
|
-
tokenHash: string$2(),
|
|
12998
|
-
tokenPrefix: string$2(),
|
|
12999
|
-
createdAt: number(),
|
|
13000
|
-
lastUsedAt: number().optional()
|
|
13001
|
-
});
|
|
13002
12992
|
object({
|
|
13003
12993
|
id: string$2(),
|
|
13004
12994
|
userId: string$2(),
|
|
@@ -17029,16 +17019,36 @@ var RecordKindStateSchema = _enum([
|
|
|
17029
17019
|
var DeclareKindResultSchema = object({
|
|
17030
17020
|
kindId: number().int(),
|
|
17031
17021
|
state: RecordKindStateSchema,
|
|
17032
|
-
createdIndexes: array(string$2())
|
|
17033
|
-
/**
|
|
17034
|
-
* RETIRED (D900): always `null`. It carried the records-migration boot guard;
|
|
17035
|
-
* it stays on the wire, null, because an addon built before the removal reads
|
|
17036
|
-
* an ABSENT field as "adoption pending" and refuses to start.
|
|
17037
|
-
*/
|
|
17038
|
-
adoptionPending: _null()
|
|
17022
|
+
createdIndexes: array(string$2())
|
|
17039
17023
|
});
|
|
17040
17024
|
/** Keychain refs a write released (the old marker is gone from the row): the owner deletes the values. */
|
|
17041
17025
|
var SecretRefsList = array(string$2());
|
|
17026
|
+
/**
|
|
17027
|
+
* One op of a `transact`: the single-row writes, each on a kind of the caller.
|
|
17028
|
+
* All ops of one call share ONE database file and ONE `transactFamily`.
|
|
17029
|
+
*/
|
|
17030
|
+
var RecordTransactOpSchema = discriminatedUnion("op", [
|
|
17031
|
+
object({
|
|
17032
|
+
op: literal("put"),
|
|
17033
|
+
kind: RecordKindNameSchema,
|
|
17034
|
+
record: RecordInputSchema,
|
|
17035
|
+
ifRev: number().int().min(0).optional()
|
|
17036
|
+
}),
|
|
17037
|
+
object({
|
|
17038
|
+
op: literal("patch"),
|
|
17039
|
+
kind: RecordKindNameSchema,
|
|
17040
|
+
id: RecordIdSchema,
|
|
17041
|
+
data: RecordBodySchema,
|
|
17042
|
+
at: number().int().nullable().optional(),
|
|
17043
|
+
expiresAt: number().int().nullable().optional(),
|
|
17044
|
+
ifRev: number().int().min(1).optional()
|
|
17045
|
+
}),
|
|
17046
|
+
object({
|
|
17047
|
+
op: literal("delete"),
|
|
17048
|
+
kind: RecordKindNameSchema,
|
|
17049
|
+
id: RecordIdSchema
|
|
17050
|
+
})
|
|
17051
|
+
]);
|
|
17042
17052
|
var RecordSecretRefsSchema = record(string$2(), record(string$2(), string$2()));
|
|
17043
17053
|
method(object({ kinds: record(RecordKindNameSchema, RecordKindDeclarationSchema) }), object({ kinds: record(string$2(), DeclareKindResultSchema) }), {
|
|
17044
17054
|
kind: "mutation",
|
|
@@ -17145,6 +17155,16 @@ method(object({ kinds: record(RecordKindNameSchema, RecordKindDeclarationSchema)
|
|
|
17145
17155
|
}), {
|
|
17146
17156
|
kind: "mutation",
|
|
17147
17157
|
auth: "admin"
|
|
17158
|
+
}), method(object({ ops: array(RecordTransactOpSchema).min(1).max(RECORD_BATCH_MAX) }), object({
|
|
17159
|
+
results: array(object({
|
|
17160
|
+
rev: number().int().nullable(),
|
|
17161
|
+
deleted: boolean()
|
|
17162
|
+
})),
|
|
17163
|
+
releasedRefs: SecretRefsList,
|
|
17164
|
+
secretRefs: SecretRefsList
|
|
17165
|
+
}), {
|
|
17166
|
+
kind: "mutation",
|
|
17167
|
+
auth: "admin"
|
|
17148
17168
|
}), method(object({
|
|
17149
17169
|
deviceId: number().int(),
|
|
17150
17170
|
kinds: array(RecordKindNameSchema).optional()
|
|
@@ -42756,9 +42776,13 @@ var NcSystemEventKindSchema = _enum([
|
|
|
42756
42776
|
"node-updating",
|
|
42757
42777
|
"node-inference-unavailable",
|
|
42758
42778
|
"detection-blind",
|
|
42779
|
+
"motion-noisy",
|
|
42780
|
+
"motion-calm",
|
|
42759
42781
|
"recording-stalled",
|
|
42760
42782
|
"recording-healthy",
|
|
42761
42783
|
"recording-degraded",
|
|
42784
|
+
"device-attention-required",
|
|
42785
|
+
"device-attention-resolved",
|
|
42762
42786
|
"storage-location-low",
|
|
42763
42787
|
"storage-location-critical",
|
|
42764
42788
|
"storage-location-ok",
|
|
@@ -48319,7 +48343,6 @@ var RecommendationReasonSchema = discriminatedUnion("kind", [
|
|
|
48319
48343
|
modelId: string$2()
|
|
48320
48344
|
}),
|
|
48321
48345
|
object({ kind: literal("cpu-device") }),
|
|
48322
|
-
object({ kind: literal("coral-untouched") }),
|
|
48323
48346
|
object({ kind: literal("device-disabled") }),
|
|
48324
48347
|
object({ kind: literal("device-unavailable") }),
|
|
48325
48348
|
object({ kind: literal("node-offline") }),
|
|
@@ -48417,11 +48440,6 @@ var AutoTuneWarningSchema = discriminatedUnion("kind", [
|
|
|
48417
48440
|
kind: literal("detector-store-unreadable"),
|
|
48418
48441
|
error: string$2()
|
|
48419
48442
|
}),
|
|
48420
|
-
object({
|
|
48421
|
-
kind: literal("coral-enabled"),
|
|
48422
|
-
nodeId: string$2(),
|
|
48423
|
-
deviceKey: string$2()
|
|
48424
|
-
}),
|
|
48425
48443
|
object({
|
|
48426
48444
|
kind: literal("custom-pin-kept"),
|
|
48427
48445
|
nodeId: string$2(),
|
|
@@ -56099,6 +56117,16 @@ var DishwasherStatusSchema = object({
|
|
|
56099
56117
|
powerState: string$2().nullable(),
|
|
56100
56118
|
saltLevel: DishwasherConsumableLevelSchema.nullable(),
|
|
56101
56119
|
rinseAidLevel: DishwasherConsumableLevelSchema.nullable(),
|
|
56120
|
+
/**
|
|
56121
|
+
* True while the appliance asks for its filter to be cleaned (smart-filter, filter-system or
|
|
56122
|
+
* combined care-and-filter reminder raised); false when every such reminder reads clear; null
|
|
56123
|
+
* when none is reported. A cleared reminder is not an unknown one.
|
|
56124
|
+
*/
|
|
56125
|
+
filterCleaningDue: boolean().nullable(),
|
|
56126
|
+
/** True while the machine-care (descaling / cleaning-program) reminder is raised; false when clear; null when not reported. */
|
|
56127
|
+
machineCareDue: boolean().nullable(),
|
|
56128
|
+
/** Program runs left before the machine-care reminder is due; null when the appliance does not say. */
|
|
56129
|
+
machineCareRemainingRuns: number().int().nonnegative().nullable(),
|
|
56102
56130
|
/** Option states: null when the appliance does not expose the option or has not said. */
|
|
56103
56131
|
halfLoad: boolean().nullable(),
|
|
56104
56132
|
hygienePlus: boolean().nullable(),
|
|
@@ -64749,16 +64777,6 @@ var UpdateUserInputSchema = object({
|
|
|
64749
64777
|
allowedDevices: record(string$2(), union([array(string$2()), literal("*")])).optional(),
|
|
64750
64778
|
scopes: array(TokenScopeSchema).optional()
|
|
64751
64779
|
});
|
|
64752
|
-
var ApiKeySummarySchema = object({
|
|
64753
|
-
id: string$2(),
|
|
64754
|
-
label: string$2(),
|
|
64755
|
-
isAdmin: boolean().default(false),
|
|
64756
|
-
allowedProviders: union([array(string$2()), literal("*")]).optional(),
|
|
64757
|
-
allowedDevices: record(string$2(), union([array(string$2()), literal("*")])).optional(),
|
|
64758
|
-
tokenPrefix: string$2(),
|
|
64759
|
-
createdAt: number(),
|
|
64760
|
-
lastUsedAt: number().optional()
|
|
64761
|
-
});
|
|
64762
64780
|
var OauthSessionSummarySchema = object({
|
|
64763
64781
|
id: string$2(),
|
|
64764
64782
|
userId: string$2(),
|
|
@@ -64780,8 +64798,7 @@ var TotpStatusSchema = object({
|
|
|
64780
64798
|
confirmedAt: number().nullable()
|
|
64781
64799
|
});
|
|
64782
64800
|
/**
|
|
64783
|
-
* user-management — singleton capability for user accounts
|
|
64784
|
-
* legacy API-key rows.
|
|
64801
|
+
* user-management — singleton capability for user accounts.
|
|
64785
64802
|
*
|
|
64786
64803
|
* v2 model: every method gated by `auth: 'admin'`. Admin-only delegation
|
|
64787
64804
|
* — the subset check on `setUserScopes` is moot
|
|
@@ -64837,10 +64854,6 @@ method(_void(), array(UserSummarySchema), { auth: "admin" }), method(CreateUserI
|
|
|
64837
64854
|
}), UserSummarySchema.extend({ passwordHash: string$2() }).nullable(), {
|
|
64838
64855
|
kind: "mutation",
|
|
64839
64856
|
access: "view"
|
|
64840
|
-
}), method(_void(), array(ApiKeySummarySchema), { auth: "admin" }), method(object({ id: string$2() }), object({ success: literal(true) }), {
|
|
64841
|
-
kind: "mutation",
|
|
64842
|
-
auth: "admin",
|
|
64843
|
-
access: "delete"
|
|
64844
64857
|
}), method(object({ userId: string$2() }), TotpSetupResultSchema, {
|
|
64845
64858
|
kind: "mutation",
|
|
64846
64859
|
auth: "admin",
|
|
@@ -74296,6 +74309,12 @@ Object.freeze({
|
|
|
74296
74309
|
addonId: null,
|
|
74297
74310
|
access: "view"
|
|
74298
74311
|
},
|
|
74312
|
+
"records.transact": {
|
|
74313
|
+
capName: "records",
|
|
74314
|
+
capScope: "system",
|
|
74315
|
+
addonId: null,
|
|
74316
|
+
access: "create"
|
|
74317
|
+
},
|
|
74299
74318
|
"sceneMonitor.captureReference": {
|
|
74300
74319
|
capName: "scene-monitor",
|
|
74301
74320
|
capScope: "device",
|
|
@@ -75628,12 +75647,6 @@ Object.freeze({
|
|
|
75628
75647
|
addonId: null,
|
|
75629
75648
|
access: "view"
|
|
75630
75649
|
},
|
|
75631
|
-
"userManagement.listApiKeys": {
|
|
75632
|
-
capName: "user-management",
|
|
75633
|
-
capScope: "system",
|
|
75634
|
-
addonId: null,
|
|
75635
|
-
access: "view"
|
|
75636
|
-
},
|
|
75637
75650
|
"userManagement.listExternalIdentities": {
|
|
75638
75651
|
capName: "user-management",
|
|
75639
75652
|
capScope: "system",
|
|
@@ -75688,12 +75701,6 @@ Object.freeze({
|
|
|
75688
75701
|
addonId: null,
|
|
75689
75702
|
access: "create"
|
|
75690
75703
|
},
|
|
75691
|
-
"userManagement.revokeApiKey": {
|
|
75692
|
-
capName: "user-management",
|
|
75693
|
-
capScope: "system",
|
|
75694
|
-
addonId: null,
|
|
75695
|
-
access: "delete"
|
|
75696
|
-
},
|
|
75697
75704
|
"userManagement.revokeOauthSession": {
|
|
75698
75705
|
capName: "user-management",
|
|
75699
75706
|
capScope: "system",
|
|
@@ -79058,9 +79065,13 @@ new Map(Object.entries({
|
|
|
79058
79065
|
"stream-online": "device-events",
|
|
79059
79066
|
"stream-offline": "device-events",
|
|
79060
79067
|
"detection-blind": "device-events",
|
|
79068
|
+
"motion-noisy": "device-events",
|
|
79069
|
+
"motion-calm": "device-events",
|
|
79061
79070
|
"recording-stalled": "device-events",
|
|
79062
79071
|
"recording-healthy": "device-events",
|
|
79063
79072
|
"recording-degraded": "device-events",
|
|
79073
|
+
"device-attention-required": "device-events",
|
|
79074
|
+
"device-attention-resolved": "device-events",
|
|
79064
79075
|
"node-online": "system",
|
|
79065
79076
|
"node-offline": "system",
|
|
79066
79077
|
"node-restarting": "system",
|
|
@@ -79143,6 +79154,12 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
|
|
|
79143
79154
|
label: "Detecting nothing",
|
|
79144
79155
|
kinds: ["detection-blind"]
|
|
79145
79156
|
},
|
|
79157
|
+
{
|
|
79158
|
+
id: "motion-noise",
|
|
79159
|
+
family: "device-events",
|
|
79160
|
+
label: "Motion without a subject",
|
|
79161
|
+
kinds: ["motion-noisy", "motion-calm"]
|
|
79162
|
+
},
|
|
79146
79163
|
{
|
|
79147
79164
|
id: "recording",
|
|
79148
79165
|
family: "device-events",
|
|
@@ -79153,6 +79170,12 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
|
|
|
79153
79170
|
"recording-degraded"
|
|
79154
79171
|
]
|
|
79155
79172
|
},
|
|
79173
|
+
{
|
|
79174
|
+
id: "device-attention",
|
|
79175
|
+
family: "device-events",
|
|
79176
|
+
label: "Needs attention",
|
|
79177
|
+
kinds: ["device-attention-required", "device-attention-resolved"]
|
|
79178
|
+
},
|
|
79156
79179
|
{
|
|
79157
79180
|
id: "nodes",
|
|
79158
79181
|
family: "system",
|
|
@@ -79292,6 +79315,7 @@ var ALERT_EPISODE = [
|
|
|
79292
79315
|
"alert-error",
|
|
79293
79316
|
"alert-critical-resolved"
|
|
79294
79317
|
];
|
|
79318
|
+
var DEVICE_ATTENTION = ["device-attention-required", "device-attention-resolved"];
|
|
79295
79319
|
var UPDATES = [
|
|
79296
79320
|
"addon-update-available",
|
|
79297
79321
|
"server-update-available",
|
|
@@ -79321,9 +79345,12 @@ var DEVICE_EVENTS = [
|
|
|
79321
79345
|
"stream-online",
|
|
79322
79346
|
"stream-offline",
|
|
79323
79347
|
"detection-blind",
|
|
79348
|
+
"motion-noisy",
|
|
79349
|
+
"motion-calm",
|
|
79324
79350
|
"recording-stalled",
|
|
79325
79351
|
"recording-healthy",
|
|
79326
79352
|
"recording-degraded",
|
|
79353
|
+
...DEVICE_ATTENTION,
|
|
79327
79354
|
...ALARM
|
|
79328
79355
|
];
|
|
79329
79356
|
/** Every kind a summary may speak about — the two summarisable families. */
|
|
@@ -79491,7 +79518,9 @@ var STATE_SUMMARY_VARS = [
|
|
|
79491
79518
|
[...RULE_TEXT],
|
|
79492
79519
|
[...RULE_TEXT],
|
|
79493
79520
|
[...RULE_TEXT],
|
|
79494
|
-
|
|
79521
|
+
[...RULE_TEXT],
|
|
79522
|
+
[...RULE_TEXT],
|
|
79523
|
+
([...RULE_TEXT], [...DEVICE_ATTENTION, ...ALERT_EPISODE]),
|
|
79495
79524
|
[...RULE_TEXT],
|
|
79496
79525
|
[...RULE_TEXT],
|
|
79497
79526
|
[...RULE_TEXT],
|
|
@@ -79513,11 +79542,11 @@ var STATE_SUMMARY_VARS = [
|
|
|
79513
79542
|
[...RULE_TEXT],
|
|
79514
79543
|
[...RULE_TEXT],
|
|
79515
79544
|
[...RULE_TEXT],
|
|
79545
|
+
([...RULE_TEXT], [...DEVICE_ATTENTION, ...ALERT_EPISODE]),
|
|
79516
79546
|
([...RULE_TEXT], [...ALERT_EPISODE]),
|
|
79547
|
+
([...RULE_TEXT], [...DEVICE_ATTENTION, ...ALERT_EPISODE]),
|
|
79517
79548
|
([...RULE_TEXT], [...ALERT_EPISODE]),
|
|
79518
|
-
([...RULE_TEXT], [...ALERT_EPISODE]),
|
|
79519
|
-
([...RULE_TEXT], [...ALERT_EPISODE]),
|
|
79520
|
-
([...RULE_TEXT], [...ALERT_EPISODE]),
|
|
79549
|
+
([...RULE_TEXT], [...DEVICE_ATTENTION, ...ALERT_EPISODE]),
|
|
79521
79550
|
[...RULE_TEXT],
|
|
79522
79551
|
[...RULE_TEXT],
|
|
79523
79552
|
[...RULE_TEXT],
|
|
@@ -79593,6 +79622,15 @@ new Map([
|
|
|
79593
79622
|
snapshotLabel: "Tanks low or full now",
|
|
79594
79623
|
snapshotSection: "tanks"
|
|
79595
79624
|
},
|
|
79625
|
+
{
|
|
79626
|
+
id: "motion-noise",
|
|
79627
|
+
family: "device-events",
|
|
79628
|
+
label: "Motion without a subject (constant / calm again)",
|
|
79629
|
+
bad: ["motion-noisy"],
|
|
79630
|
+
recovery: ["motion-calm"],
|
|
79631
|
+
snapshotLabel: "Cameras with constant motion now",
|
|
79632
|
+
snapshotSection: null
|
|
79633
|
+
},
|
|
79596
79634
|
{
|
|
79597
79635
|
id: "recording-health",
|
|
79598
79636
|
family: "device-events",
|
|
@@ -79602,6 +79640,15 @@ new Map([
|
|
|
79602
79640
|
snapshotLabel: "Recordings stalled now",
|
|
79603
79641
|
snapshotSection: null
|
|
79604
79642
|
},
|
|
79643
|
+
{
|
|
79644
|
+
id: "device-attention",
|
|
79645
|
+
family: "device-events",
|
|
79646
|
+
label: "Device needs attention (raised / resolved)",
|
|
79647
|
+
bad: ["device-attention-required"],
|
|
79648
|
+
recovery: ["device-attention-resolved"],
|
|
79649
|
+
snapshotLabel: "Devices needing attention now",
|
|
79650
|
+
snapshotSection: null
|
|
79651
|
+
},
|
|
79605
79652
|
{
|
|
79606
79653
|
id: "node-connectivity",
|
|
79607
79654
|
family: "system",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-matter-broker",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.144",
|
|
4
4
|
"description": "Matter broker addon for CamStack — owns a Matter fabric (commissioning + the long-lived controller) via the matter.js controller and brokers commissioned Matter nodes into CamStack",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|