@camstack/addon-provider-amcrest 0.2.129 → 0.2.131
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 +249 -140
- package/dist/addon.mjs +249 -140
- package/package.json +1 -1
package/dist/addon.mjs
CHANGED
|
@@ -10489,6 +10489,57 @@ var ClipSearchStrictnessSchema = _enum([
|
|
|
10489
10489
|
"balanced",
|
|
10490
10490
|
"strict"
|
|
10491
10491
|
]);
|
|
10492
|
+
new Set([
|
|
10493
|
+
{
|
|
10494
|
+
id: "person",
|
|
10495
|
+
name: "Person"
|
|
10496
|
+
},
|
|
10497
|
+
{
|
|
10498
|
+
id: "vehicle",
|
|
10499
|
+
name: "Vehicle"
|
|
10500
|
+
},
|
|
10501
|
+
{
|
|
10502
|
+
id: "animal",
|
|
10503
|
+
name: "Animal"
|
|
10504
|
+
},
|
|
10505
|
+
{
|
|
10506
|
+
id: "package",
|
|
10507
|
+
name: "Package"
|
|
10508
|
+
}
|
|
10509
|
+
].map((l) => l.id));
|
|
10510
|
+
var COCO_TO_MACRO = {
|
|
10511
|
+
mapping: {
|
|
10512
|
+
person: "person",
|
|
10513
|
+
bicycle: "vehicle",
|
|
10514
|
+
car: "vehicle",
|
|
10515
|
+
motorcycle: "vehicle",
|
|
10516
|
+
airplane: "vehicle",
|
|
10517
|
+
bus: "vehicle",
|
|
10518
|
+
train: "vehicle",
|
|
10519
|
+
truck: "vehicle",
|
|
10520
|
+
boat: "vehicle",
|
|
10521
|
+
bird: "animal",
|
|
10522
|
+
cat: "animal",
|
|
10523
|
+
dog: "animal",
|
|
10524
|
+
horse: "animal",
|
|
10525
|
+
sheep: "animal",
|
|
10526
|
+
cow: "animal",
|
|
10527
|
+
elephant: "animal",
|
|
10528
|
+
bear: "animal",
|
|
10529
|
+
zebra: "animal",
|
|
10530
|
+
giraffe: "animal",
|
|
10531
|
+
suitcase: "package",
|
|
10532
|
+
backpack: "package",
|
|
10533
|
+
handbag: "package"
|
|
10534
|
+
},
|
|
10535
|
+
preserveOriginal: false
|
|
10536
|
+
};
|
|
10537
|
+
/** Steps a root detector may declare it fills. */
|
|
10538
|
+
var FILLABLE_STEP_IDS = [
|
|
10539
|
+
"animal-classifier",
|
|
10540
|
+
"vehicle-classifier",
|
|
10541
|
+
"package-detection"
|
|
10542
|
+
];
|
|
10492
10543
|
var MODEL_FORMATS = [
|
|
10493
10544
|
"onnx",
|
|
10494
10545
|
"coreml",
|
|
@@ -10558,11 +10609,11 @@ var ModelVariantGroupSchema = object({
|
|
|
10558
10609
|
/** Quantization axis. Omit ⇒ the fp32 base build. */
|
|
10559
10610
|
precision: _enum(["fp32", "int8"]).optional(),
|
|
10560
10611
|
/**
|
|
10561
|
-
*
|
|
10562
|
-
*
|
|
10563
|
-
*
|
|
10612
|
+
* Training / latency-variant axis. Omit ⇒ the standard build. `test` marks
|
|
10613
|
+
* an alternate training of the same family (Scrypted `relu_test`); chip
|
|
10614
|
+
* label is "Test".
|
|
10564
10615
|
*/
|
|
10565
|
-
optimization: _enum(["standard", "
|
|
10616
|
+
optimization: _enum(["standard", "test"]).optional(),
|
|
10566
10617
|
/**
|
|
10567
10618
|
* Input-resolution axis (square input side, px). Omit ⇒ the family's native
|
|
10568
10619
|
* resolution (640 for yolo26). Reduced-input builds (320 / 256) are a big,
|
|
@@ -10585,9 +10636,10 @@ var ModelProviderIdSchema = _enum([
|
|
|
10585
10636
|
* are per upstream. A persisted custom-model row written when this field was a
|
|
10586
10637
|
* string still parses — the string is lifted into `{ weights }`.
|
|
10587
10638
|
*
|
|
10588
|
-
* Every licence surface (the
|
|
10589
|
-
*
|
|
10590
|
-
*
|
|
10639
|
+
* Every machine licence surface (`THIRD_PARTY_MODELS.md`, the Hugging Face
|
|
10640
|
+
* model table) is GENERATED from these records by
|
|
10641
|
+
* `scripts/gen-model-licenses.ts` (D661). Operator-facing docs live in
|
|
10642
|
+
* `camstack/docs` → `/docs/detection/models`.
|
|
10591
10643
|
*/
|
|
10592
10644
|
var ModelLicenseSchema = preprocess((value) => typeof value === "string" ? { weights: value } : value, object({
|
|
10593
10645
|
/** SPDX id of the WEIGHTS' terms, a `LicenseRef-*` for non-SPDX terms, or `UNKNOWN`. */
|
|
@@ -10620,6 +10672,12 @@ var ModelLicenseSchema = preprocess((value) => typeof value === "string" ? { wei
|
|
|
10620
10672
|
/** True when the weights or their data forbid commercial use. */
|
|
10621
10673
|
nonCommercial: boolean().optional()
|
|
10622
10674
|
}));
|
|
10675
|
+
/** One `fillsClassifierEffects` entry — see `ModelCatalogEntry.fillsClassifierEffects`. */
|
|
10676
|
+
var FillsClassifierEffectSchema = object({
|
|
10677
|
+
stepId: _enum(FILLABLE_STEP_IDS),
|
|
10678
|
+
labelToEffect: record(string(), string()),
|
|
10679
|
+
uncovered: array(string()).readonly()
|
|
10680
|
+
});
|
|
10623
10681
|
var ModelCatalogEntrySchema = object({
|
|
10624
10682
|
id: string(),
|
|
10625
10683
|
name: string(),
|
|
@@ -10746,6 +10804,16 @@ var ModelCatalogEntrySchema = object({
|
|
|
10746
10804
|
*/
|
|
10747
10805
|
classMap: DetectionCatalogClassMapSchema.optional(),
|
|
10748
10806
|
/**
|
|
10807
|
+
* The pipeline steps this ROOT detector already does the work of (D715):
|
|
10808
|
+
* its labels name the effect the step exists to produce (`deer` for
|
|
10809
|
+
* `animal-classifier`, `package` for `package-detection`). Derived from the
|
|
10810
|
+
* labelmap by `deriveClassifierFills`, never hand-written; a COCO model
|
|
10811
|
+
* declares none. Whether a declaration is honoured is the step's own
|
|
10812
|
+
* `labelLink` policy (`resolveLabelLink`). `labelToEffect` values are in
|
|
10813
|
+
* `FILLABLE_STEP_VOCABULARIES` (guard `check-label-link-vocabulary`).
|
|
10814
|
+
*/
|
|
10815
|
+
fillsClassifierEffects: array(FillsClassifierEffectSchema).readonly().optional(),
|
|
10816
|
+
/**
|
|
10749
10817
|
* The model's CLIP feature-space contract (text encoder, dimension, vector
|
|
10750
10818
|
* index, token window, search floor) — see `clip-model.ts`. Present ONLY on a
|
|
10751
10819
|
* CLIP image encoder; its absence is what "not a CLIP model" means to the
|
|
@@ -14218,7 +14286,7 @@ DeviceType.Camera;
|
|
|
14218
14286
|
* This matters here more than anywhere else in the repo, because every provider
|
|
14219
14287
|
* that knows a device's host knows its PASSWORD too: `{ host, port, username,
|
|
14220
14288
|
* password }` sit in one object on Hikvision, Amcrest, Reolink and ONVIF alike,
|
|
14221
|
-
* and `http://admin:hunter2@192.168.
|
|
14289
|
+
* and `http://admin:hunter2@192.168.60.139/` is a URL a browser accepts. The
|
|
14222
14290
|
* camera's own page will ask for its own login. That is correct, and pre-
|
|
14223
14291
|
* filling it is the operator's business, not ours.
|
|
14224
14292
|
*
|
|
@@ -17503,7 +17571,7 @@ method(object({
|
|
|
17503
17571
|
timeoutMs: 6e5
|
|
17504
17572
|
});
|
|
17505
17573
|
method(object({
|
|
17506
|
-
|
|
17574
|
+
targetNodeId: string(),
|
|
17507
17575
|
modelId: string(),
|
|
17508
17576
|
format: _enum(MODEL_FORMATS),
|
|
17509
17577
|
entry: ModelCatalogEntrySchema
|
|
@@ -18069,51 +18137,6 @@ method(object({}), array(TargetKindSchema)), method(object({}), array(TargetSche
|
|
|
18069
18137
|
kind: "mutation",
|
|
18070
18138
|
auth: "admin"
|
|
18071
18139
|
});
|
|
18072
|
-
new Set([
|
|
18073
|
-
{
|
|
18074
|
-
id: "person",
|
|
18075
|
-
name: "Person"
|
|
18076
|
-
},
|
|
18077
|
-
{
|
|
18078
|
-
id: "vehicle",
|
|
18079
|
-
name: "Vehicle"
|
|
18080
|
-
},
|
|
18081
|
-
{
|
|
18082
|
-
id: "animal",
|
|
18083
|
-
name: "Animal"
|
|
18084
|
-
},
|
|
18085
|
-
{
|
|
18086
|
-
id: "package",
|
|
18087
|
-
name: "Package"
|
|
18088
|
-
}
|
|
18089
|
-
].map((l) => l.id));
|
|
18090
|
-
var COCO_TO_MACRO = {
|
|
18091
|
-
mapping: {
|
|
18092
|
-
person: "person",
|
|
18093
|
-
bicycle: "vehicle",
|
|
18094
|
-
car: "vehicle",
|
|
18095
|
-
motorcycle: "vehicle",
|
|
18096
|
-
airplane: "vehicle",
|
|
18097
|
-
bus: "vehicle",
|
|
18098
|
-
train: "vehicle",
|
|
18099
|
-
truck: "vehicle",
|
|
18100
|
-
boat: "vehicle",
|
|
18101
|
-
bird: "animal",
|
|
18102
|
-
cat: "animal",
|
|
18103
|
-
dog: "animal",
|
|
18104
|
-
horse: "animal",
|
|
18105
|
-
sheep: "animal",
|
|
18106
|
-
cow: "animal",
|
|
18107
|
-
elephant: "animal",
|
|
18108
|
-
bear: "animal",
|
|
18109
|
-
zebra: "animal",
|
|
18110
|
-
giraffe: "animal",
|
|
18111
|
-
suitcase: "package",
|
|
18112
|
-
backpack: "package",
|
|
18113
|
-
handbag: "package"
|
|
18114
|
-
},
|
|
18115
|
-
preserveOriginal: false
|
|
18116
|
-
};
|
|
18117
18140
|
var AUDIO_MACRO_LABELS = [
|
|
18118
18141
|
{
|
|
18119
18142
|
id: "speech",
|
|
@@ -18909,6 +18932,8 @@ var NcSystemEventKindSchema = _enum([
|
|
|
18909
18932
|
"stream-offline",
|
|
18910
18933
|
"node-online",
|
|
18911
18934
|
"node-offline",
|
|
18935
|
+
"node-restarting",
|
|
18936
|
+
"node-updating",
|
|
18912
18937
|
"node-inference-unavailable",
|
|
18913
18938
|
"detection-blind",
|
|
18914
18939
|
"addon-crash-loop",
|
|
@@ -20007,8 +20032,9 @@ var NcRuleSchema = NcRuleInputSchema.extend({
|
|
|
20007
20032
|
disabledTargetIds: array(string()).default([])
|
|
20008
20033
|
});
|
|
20009
20034
|
/**
|
|
20010
|
-
* The state-summary SECTIONS (D647 / D698): the D637 kind groups that
|
|
20011
|
-
* still-true state. `
|
|
20035
|
+
* The state-summary SECTIONS (D647 / D698 / D708): the D637 kind groups that
|
|
20036
|
+
* report a still-true state. `addons` is the crash-looped addons only and
|
|
20037
|
+
* `addon-updates` the addons that are behind (D708 split them). `backups-exports` and `alarm` are not sections — a completed
|
|
20012
20038
|
* job is not an open state, and the alarm stays instant.
|
|
20013
20039
|
*/
|
|
20014
20040
|
var NcStateSummarySectionIdSchema = _enum([
|
|
@@ -20020,6 +20046,7 @@ var NcStateSummarySectionIdSchema = _enum([
|
|
|
20020
20046
|
"detection-blind",
|
|
20021
20047
|
"nodes",
|
|
20022
20048
|
"addons",
|
|
20049
|
+
"addon-updates",
|
|
20023
20050
|
"updates"
|
|
20024
20051
|
]);
|
|
20025
20052
|
/** One section of a previewed state summary. `unavailable` = its state could not be read. */
|
|
@@ -20500,7 +20527,19 @@ var NcAlarmModeDelaysListSchema = array(object({
|
|
|
20500
20527
|
* When this mode may be armed. Absent / null = always allowed (same as a
|
|
20501
20528
|
* rule with no `schedule`). Evaluated with {@link isScheduleActive}.
|
|
20502
20529
|
*/
|
|
20503
|
-
schedule: NcScheduleSchema.optional()
|
|
20530
|
+
schedule: NcScheduleSchema.optional(),
|
|
20531
|
+
/**
|
|
20532
|
+
* D706: while this mode's ENTRY DELAY runs, do the alarm rules' own pushes go out (as an
|
|
20533
|
+
* intrusion naming the locations)? Absent = false — the entry-delay notification is the
|
|
20534
|
+
* only one, and the matches ride the triggered notification's mosaic (D705).
|
|
20535
|
+
*/
|
|
20536
|
+
notifyDuringEntryDelay: boolean().optional(),
|
|
20537
|
+
/**
|
|
20538
|
+
* D706: notify "watched again" when a sensor this arm bypassed closes and opens again.
|
|
20539
|
+
* Absent = false (logged, not sent). Even when true it is not sent when that same sensor
|
|
20540
|
+
* is the one that starts the entry delay — the entry-delay notification already names it.
|
|
20541
|
+
*/
|
|
20542
|
+
notifySensorRewatched: boolean().optional()
|
|
20504
20543
|
})).max(8).refine(uniqueModes, { message: "modeDelays: at most one entry per arm mode" });
|
|
20505
20544
|
var NcAlarmModeDelaysEditListSchema = array(object({
|
|
20506
20545
|
mode: AlarmArmModeSchema,
|
|
@@ -20509,7 +20548,11 @@ var NcAlarmModeDelaysEditListSchema = array(object({
|
|
|
20509
20548
|
triggeredDurationSec: NcAlarmTriggeredSecSchema.nullable().optional(),
|
|
20510
20549
|
postTriggeredAction: NcAlarmPostTriggeredActionSchema.nullable().optional(),
|
|
20511
20550
|
/** Set a schedule, or `null` to clear (mode always allowed again). */
|
|
20512
|
-
schedule: NcScheduleSchema.nullable().optional()
|
|
20551
|
+
schedule: NcScheduleSchema.nullable().optional(),
|
|
20552
|
+
/** D706: set the switch, or `null` to clear it (back to the default, false). */
|
|
20553
|
+
notifyDuringEntryDelay: boolean().nullable().optional(),
|
|
20554
|
+
/** D706: set the switch, or `null` to clear it (back to the default, false). */
|
|
20555
|
+
notifySensorRewatched: boolean().nullable().optional()
|
|
20513
20556
|
})).max(8).refine(uniqueModes, { message: "modeDelays: at most one edit per arm mode" });
|
|
20514
20557
|
/** One switch of the alarm table: put ONE device on, or take it off, ONE mode's list. */
|
|
20515
20558
|
var NcAlarmNonBlockingEditSchema = object({
|
|
@@ -21470,39 +21513,19 @@ Object.freeze(Object.fromEntries([{
|
|
|
21470
21513
|
label: "Face recognition model",
|
|
21471
21514
|
defaultModelId: "auraface-r100",
|
|
21472
21515
|
indexName: "the enrolled face gallery",
|
|
21473
|
-
options: [
|
|
21474
|
-
|
|
21475
|
-
|
|
21476
|
-
|
|
21477
|
-
},
|
|
21478
|
-
{
|
|
21479
|
-
id: "arcface-r100",
|
|
21480
|
-
label: "ArcFace (ResNet34)"
|
|
21481
|
-
},
|
|
21482
|
-
{
|
|
21483
|
-
id: "inception-resnet-v1",
|
|
21484
|
-
label: "Inception ResNet V1"
|
|
21485
|
-
}
|
|
21486
|
-
]
|
|
21516
|
+
options: [{
|
|
21517
|
+
id: "auraface-r100",
|
|
21518
|
+
label: "AuraFace R100"
|
|
21519
|
+
}]
|
|
21487
21520
|
}, {
|
|
21488
21521
|
stepId: "clip-embedding",
|
|
21489
21522
|
label: "Semantic search model",
|
|
21490
|
-
defaultModelId: "
|
|
21523
|
+
defaultModelId: "siglip2-b16-224",
|
|
21491
21524
|
indexName: "the object semantic-search index",
|
|
21492
|
-
options: [
|
|
21493
|
-
|
|
21494
|
-
|
|
21495
|
-
|
|
21496
|
-
},
|
|
21497
|
-
{
|
|
21498
|
-
id: "mobileclip-s2",
|
|
21499
|
-
label: "MobileCLIP S2"
|
|
21500
|
-
},
|
|
21501
|
-
{
|
|
21502
|
-
id: "siglip2-b16-224",
|
|
21503
|
-
label: "SigLIP2 B/16 (Apache-2.0)"
|
|
21504
|
-
}
|
|
21505
|
-
]
|
|
21525
|
+
options: [{
|
|
21526
|
+
id: "siglip2-b16-224",
|
|
21527
|
+
label: "SigLIP2 B/16 (Apache-2.0)"
|
|
21528
|
+
}]
|
|
21506
21529
|
}].map((s) => [s.stepId, s.defaultModelId])));
|
|
21507
21530
|
var CLUSTER_STEP_SETTING_FIELDS = [{
|
|
21508
21531
|
stepId: "face-embedding",
|
|
@@ -23557,7 +23580,8 @@ var PipelineModelOptionSchema = object({
|
|
|
23557
23580
|
group: ModelVariantGroupSchema.optional(),
|
|
23558
23581
|
legacy: boolean().optional(),
|
|
23559
23582
|
provider: ModelProviderIdSchema.optional(),
|
|
23560
|
-
defaultConfidence: number().optional()
|
|
23583
|
+
defaultConfidence: number().optional(),
|
|
23584
|
+
fillsClassifierEffects: array(FillsClassifierEffectSchema).readonly().optional()
|
|
23561
23585
|
});
|
|
23562
23586
|
var ConfigFieldBridge = custom();
|
|
23563
23587
|
var PipelineAddonSchemaSchema = object({
|
|
@@ -24390,6 +24414,22 @@ var MotionSourceEnum = _enum([
|
|
|
24390
24414
|
"device-activity"
|
|
24391
24415
|
]);
|
|
24392
24416
|
/**
|
|
24417
|
+
* What opened an on-motion detection SESSION: the motion source that passed the
|
|
24418
|
+
* camera's `motionSources` gate, and what raised it (the camera itself, or a
|
|
24419
|
+
* sensor the operator attached — D672). `sensorName` is the attached sensor's
|
|
24420
|
+
* device name as the orchestrator's camera-sensors resolution last read it;
|
|
24421
|
+
* absent when unknown or when the camera itself triggered.
|
|
24422
|
+
*
|
|
24423
|
+
* Carried on the session attach ONLY so the runner's `DetectionPhaseTransition`
|
|
24424
|
+
* can say what started the session (D672 rule 11, amended 2026-10-06). The
|
|
24425
|
+
* runner never decides anything on it.
|
|
24426
|
+
*/
|
|
24427
|
+
var SessionTriggerSchema = object({
|
|
24428
|
+
source: MotionSourceEnum,
|
|
24429
|
+
triggeredBy: MotionTriggeredBySchema,
|
|
24430
|
+
sensorName: string().optional()
|
|
24431
|
+
});
|
|
24432
|
+
/**
|
|
24393
24433
|
* List of motion sources active on a camera. Empty array is valid:
|
|
24394
24434
|
* "no source" — happens for battery cams without firmware motion when
|
|
24395
24435
|
* the operator hasn't opted into the SW analyzer (would hold the
|
|
@@ -24641,6 +24681,14 @@ var RunnerCameraConfigSchema = object({
|
|
|
24641
24681
|
*/
|
|
24642
24682
|
motionSources: MotionSourcesSchema.default(["analyzer"]),
|
|
24643
24683
|
/**
|
|
24684
|
+
* What opened this attach, on a SESSION attach only (see
|
|
24685
|
+
* {@link SessionTriggerSchema}). OPTIONAL with no default: absent on a
|
|
24686
|
+
* standing attach, an occupancy burst, a re-dispatch with no motion event
|
|
24687
|
+
* behind it, and every attach from an orchestrator older than the field — the
|
|
24688
|
+
* runner then names no source on the phase event.
|
|
24689
|
+
*/
|
|
24690
|
+
sessionTrigger: SessionTriggerSchema.optional(),
|
|
24691
|
+
/**
|
|
24644
24692
|
* WHICH root detector runs for this camera. The detection counterpart of
|
|
24645
24693
|
* {@link motionSources}, same shape and same discipline: a per-camera list
|
|
24646
24694
|
* of sources the system understands, vendor-agnostic, owned here.
|
|
@@ -32542,7 +32590,7 @@ var LocalInterfaceSchema = object({
|
|
|
32542
32590
|
name: string(),
|
|
32543
32591
|
family: _enum(["IPv4", "IPv6"]),
|
|
32544
32592
|
address: string(),
|
|
32545
|
-
/** CIDR shorthand (e.g. `192.168.
|
|
32593
|
+
/** CIDR shorthand (e.g. `192.168.10.10/24`). Empty when OS doesn't expose. */
|
|
32546
32594
|
cidr: string(),
|
|
32547
32595
|
/** OS netmask. Stable across calls so the SDK can hash on it. */
|
|
32548
32596
|
netmask: string(),
|
|
@@ -32596,7 +32644,8 @@ var ConnectionEndpointSchema = object({
|
|
|
32596
32644
|
"lan-ipv4",
|
|
32597
32645
|
"lan-ipv6",
|
|
32598
32646
|
"public",
|
|
32599
|
-
"loopback"
|
|
32647
|
+
"loopback",
|
|
32648
|
+
"app-link"
|
|
32600
32649
|
]),
|
|
32601
32650
|
/**
|
|
32602
32651
|
* Originating-interface kind — `lan`/`wifi`/`docker`/`vpn`/`other`/
|
|
@@ -32665,15 +32714,27 @@ var GetConnectionEndpointsResultSchema = object({
|
|
|
32665
32714
|
localPort: AdvertisedLocalPortSchema
|
|
32666
32715
|
});
|
|
32667
32716
|
/**
|
|
32668
|
-
* The
|
|
32669
|
-
*
|
|
32670
|
-
*
|
|
32717
|
+
* The address flagged for notification links. `baseUrl: null` = AUTO, which
|
|
32718
|
+
* since D709 is the CamStack app link; `resolved` reports the effective value,
|
|
32719
|
+
* so the UI can show it either way.
|
|
32671
32720
|
*/
|
|
32672
32721
|
var NotificationEndpointSchema = object({
|
|
32673
32722
|
/** The operator's explicit choice, or null for AUTO. */
|
|
32674
32723
|
baseUrl: string().nullable(),
|
|
32675
|
-
/**
|
|
32676
|
-
|
|
32724
|
+
/**
|
|
32725
|
+
* The effective flagged address: the explicit choice, else (AUTO) the
|
|
32726
|
+
* CamStack app link `https://camstack.zentik.app` (D709). A pre-D709 hub
|
|
32727
|
+
* answered the public tunnel / mesh here, or null.
|
|
32728
|
+
*/
|
|
32729
|
+
resolved: string().nullable(),
|
|
32730
|
+
/**
|
|
32731
|
+
* The hub origin an app link carries as `hub=` (D709): the hub's best
|
|
32732
|
+
* public HTTPS address — the tunnel, then the mesh (Tailscale MagicDNS) —
|
|
32733
|
+
* picked from this cap's own palette by `pickAppLinkHub`. `null` when the
|
|
32734
|
+
* hub advertises neither; the app link is then minted without `hub=`.
|
|
32735
|
+
* Absent on a pre-D709 hub.
|
|
32736
|
+
*/
|
|
32737
|
+
appLinkHub: string().nullable()
|
|
32677
32738
|
});
|
|
32678
32739
|
/**
|
|
32679
32740
|
* The URLs the SDK / viewer should race for API access. `baseUrls` empty =
|
|
@@ -32727,7 +32788,11 @@ method(_void(), ListResultSchema), method(_void(), PreferredSchema), method(obje
|
|
|
32727
32788
|
* Pass `'https'` when the caller is itself loaded over HTTPS
|
|
32728
32789
|
* to avoid mixed-content blocks in the browser. The public
|
|
32729
32790
|
* tunnel always emits `https://` regardless. */
|
|
32730
|
-
scheme: _enum(["http", "https"]).optional()
|
|
32791
|
+
scheme: _enum(["http", "https"]).optional(),
|
|
32792
|
+
/** Append the CamStack app link entry (`kind: 'app-link'`, D709) —
|
|
32793
|
+
* an address notification links can be flagged with, not a hub
|
|
32794
|
+
* route. Default `false`: racers and rankers never see it. */
|
|
32795
|
+
includeAppLink: boolean().optional()
|
|
32731
32796
|
}), GetConnectionEndpointsResultSchema), method(_void(), NotificationEndpointSchema), method(object({ baseUrl: string().nullable() }), NotificationEndpointSchema, { kind: "mutation" }), method(_void(), ViewerEndpointsSchema), method(object({ baseUrls: array(string()).readonly() }), ViewerEndpointsSchema, { kind: "mutation" }), method(_void(), AllowedAddressesSchema), method(AllowedAddressesSchema, object({ success: literal(true) }), { kind: "mutation" }), method(_void(), AllowedAddressesSchema, { kind: "mutation" }), method(_void(), TlsStatusSchema), method(object({ reason: string().optional() }), TlsStatusSchema, {
|
|
32732
32797
|
kind: "mutation",
|
|
32733
32798
|
auth: "admin"
|
|
@@ -33056,7 +33121,7 @@ var MeshPeerSchema = object({
|
|
|
33056
33121
|
tags: array(string()).readonly(),
|
|
33057
33122
|
/** True when the peer advertises itself as an exit-node candidate. */
|
|
33058
33123
|
exitNodeOption: boolean(),
|
|
33059
|
-
/** Subnet routes the peer advertises (e.g. `["192.168.
|
|
33124
|
+
/** Subnet routes the peer advertises (e.g. `["192.168.10.0/24"]`). */
|
|
33060
33125
|
advertisedRoutes: array(string()).readonly(),
|
|
33061
33126
|
/** Owner account login (e.g. `foo@example.com`). Null for tagged peers. */
|
|
33062
33127
|
userLogin: string().nullable(),
|
|
@@ -33186,7 +33251,8 @@ var MotionStatusSchema = object({
|
|
|
33186
33251
|
* writes this slice (not even a boot seed), and neither does the runner's
|
|
33187
33252
|
* phase machine: its phase is "a session is attached" for every on-motion
|
|
33188
33253
|
* session, not motion, and it now has its own `DetectionPhaseTransition`.
|
|
33189
|
-
* A provider's `isDetected`
|
|
33254
|
+
* A provider's `isDetected` and `getStatus` answer from the hub's slice
|
|
33255
|
+
* (`hubMotionNativeProvider`).
|
|
33190
33256
|
* - **Sensors** (Home Assistant binary sensors, Homematic, Matter, Alexa
|
|
33191
33257
|
* imports) — the provider pushes both edges itself, from the upstream
|
|
33192
33258
|
* system's own state change. That is the sensor's own fact.
|
|
@@ -34384,7 +34450,13 @@ var OsdStatusSchema = object({ overlays: array(object({
|
|
|
34384
34450
|
*/
|
|
34385
34451
|
availablePositions: array(OsdPositionEnum).readonly(),
|
|
34386
34452
|
/** Firmware does not allow editing the `text` field (e.g. timestamp). */
|
|
34387
|
-
readOnly: boolean().optional()
|
|
34453
|
+
readOnly: boolean().optional(),
|
|
34454
|
+
/**
|
|
34455
|
+
* Firmware text ceiling for this overlay. Absent = no known limit.
|
|
34456
|
+
* The OSD manager truncates here on every write — never stores its own
|
|
34457
|
+
* copy on the binding.
|
|
34458
|
+
*/
|
|
34459
|
+
maxCharacters: number().int().positive().optional()
|
|
34388
34460
|
})).readonly() });
|
|
34389
34461
|
var OsdOverlayPatchSchema = object({
|
|
34390
34462
|
enabled: boolean().optional(),
|
|
@@ -34481,7 +34553,9 @@ var OsdTemplateBindingSchema = object({
|
|
|
34481
34553
|
valuePath: string().min(1).max(64),
|
|
34482
34554
|
/** Convert TO this unit at render (`tryConvertUnit`). Absent = source unit. */
|
|
34483
34555
|
displayUnit: string().max(16).optional(),
|
|
34484
|
-
maxDecimals: number().int().min(0).max(4).default(1)
|
|
34556
|
+
maxDecimals: number().int().min(0).max(4).default(1),
|
|
34557
|
+
/** Raw value → display text (same shape as slot binding). Empty string hides. */
|
|
34558
|
+
valueMap: record(string(), string()).optional()
|
|
34485
34559
|
});
|
|
34486
34560
|
/**
|
|
34487
34561
|
* A named template: bindings (alias → leaf field) + a parser that
|
|
@@ -34531,18 +34605,11 @@ var OsdSlotBindingSchema = object({
|
|
|
34531
34605
|
source: OsdSourceSchema,
|
|
34532
34606
|
/** `${value}` and `${unit}` are substituted; every occurrence. */
|
|
34533
34607
|
template: string().max(96).default("${value}"),
|
|
34534
|
-
/** Truncate with an ellipsis past this length. Absent = no limit. */
|
|
34535
|
-
maxCharacters: number().int().min(4).max(64).optional(),
|
|
34536
34608
|
/**
|
|
34537
34609
|
* Decimal places for a numeric value. `0` yields an integer — the
|
|
34538
34610
|
* documented workaround for firmwares that reject `.` in overlay text.
|
|
34539
34611
|
*/
|
|
34540
34612
|
maxDecimals: number().int().min(0).max(4).default(1),
|
|
34541
|
-
/**
|
|
34542
|
-
* Appended via `${unit}` when no unit conversion produces a label.
|
|
34543
|
-
* Prefer `source.displayUnit` for converted device-state values.
|
|
34544
|
-
*/
|
|
34545
|
-
unitLabel: string().max(8).optional(),
|
|
34546
34613
|
/** Raw value → display text, e.g. `{"true":"MOTION","false":""}`. */
|
|
34547
34614
|
valueMap: record(string(), string()).optional(),
|
|
34548
34615
|
/** Time windows in which the slot is shown. Absent = always. */
|
|
@@ -34551,9 +34618,7 @@ var OsdSlotBindingSchema = object({
|
|
|
34551
34618
|
* Display gate, in the notification centre's condition vocabulary.
|
|
34552
34619
|
* Only the keys reported by `getConditionSupport` are accepted.
|
|
34553
34620
|
*/
|
|
34554
|
-
conditions: NcConditionsSchema.optional()
|
|
34555
|
-
/** Rendered when the gate is closed or the value unreadable. Empty = hide. */
|
|
34556
|
-
fallbackText: string().max(64).default("")
|
|
34621
|
+
conditions: NcConditionsSchema.optional()
|
|
34557
34622
|
});
|
|
34558
34623
|
/** One camera slot, as the operator sees it: firmware truth + our binding. */
|
|
34559
34624
|
var OsdSlotViewSchema = object({
|
|
@@ -53325,6 +53390,8 @@ new Map(Object.entries({
|
|
|
53325
53390
|
"detection-blind": "device-events",
|
|
53326
53391
|
"node-online": "system",
|
|
53327
53392
|
"node-offline": "system",
|
|
53393
|
+
"node-restarting": "system",
|
|
53394
|
+
"node-updating": "system",
|
|
53328
53395
|
"node-inference-unavailable": "system",
|
|
53329
53396
|
"addon-crash-loop": "system",
|
|
53330
53397
|
"addon-update-available": "system",
|
|
@@ -53402,18 +53469,21 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
|
|
|
53402
53469
|
kinds: [
|
|
53403
53470
|
"node-offline",
|
|
53404
53471
|
"node-online",
|
|
53472
|
+
"node-restarting",
|
|
53405
53473
|
"node-inference-unavailable"
|
|
53406
53474
|
]
|
|
53407
53475
|
},
|
|
53408
53476
|
{
|
|
53409
53477
|
id: "addons",
|
|
53410
53478
|
family: "system",
|
|
53411
|
-
label: "Addons",
|
|
53412
|
-
kinds: [
|
|
53413
|
-
|
|
53414
|
-
|
|
53415
|
-
|
|
53416
|
-
|
|
53479
|
+
label: "Addons stopped",
|
|
53480
|
+
kinds: ["addon-crash-loop"]
|
|
53481
|
+
},
|
|
53482
|
+
{
|
|
53483
|
+
id: "addon-updates",
|
|
53484
|
+
family: "system",
|
|
53485
|
+
label: "Addon updates",
|
|
53486
|
+
kinds: ["addon-update-available", "addon-updated"]
|
|
53417
53487
|
},
|
|
53418
53488
|
{
|
|
53419
53489
|
id: "updates",
|
|
@@ -53421,6 +53491,7 @@ var NC_SYSTEM_EVENT_KIND_GROUP_SPECS = [
|
|
|
53421
53491
|
label: "Server & container updates",
|
|
53422
53492
|
kinds: [
|
|
53423
53493
|
"server-update-available",
|
|
53494
|
+
"node-updating",
|
|
53424
53495
|
"server-updated",
|
|
53425
53496
|
"wrapper-update-available"
|
|
53426
53497
|
]
|
|
@@ -53568,18 +53639,21 @@ var STATE_SUMMARY_SECTION_VARS = [
|
|
|
53568
53639
|
kinds: [
|
|
53569
53640
|
"node-offline",
|
|
53570
53641
|
"node-online",
|
|
53642
|
+
"node-restarting",
|
|
53571
53643
|
"node-inference-unavailable"
|
|
53572
53644
|
]
|
|
53573
53645
|
},
|
|
53574
53646
|
{
|
|
53575
53647
|
name: "summaryAddons",
|
|
53576
|
-
label: "Summary: addons",
|
|
53577
|
-
example: "
|
|
53578
|
-
kinds: [
|
|
53579
|
-
|
|
53580
|
-
|
|
53581
|
-
|
|
53582
|
-
|
|
53648
|
+
label: "Summary: addons stopped",
|
|
53649
|
+
example: "hub — recorder stopped after repeated crashes",
|
|
53650
|
+
kinds: ["addon-crash-loop"]
|
|
53651
|
+
},
|
|
53652
|
+
{
|
|
53653
|
+
name: "summaryAddonUpdates",
|
|
53654
|
+
label: "Summary: addon updates",
|
|
53655
|
+
example: "hub:\n• @camstack/addon-recorder 1.2.3 → 1.2.4",
|
|
53656
|
+
kinds: ["addon-update-available", "addon-updated"]
|
|
53583
53657
|
},
|
|
53584
53658
|
{
|
|
53585
53659
|
name: "summaryUpdates",
|
|
@@ -53587,6 +53661,7 @@ var STATE_SUMMARY_SECTION_VARS = [
|
|
|
53587
53661
|
example: "server 1.2.377 → 1.2.378",
|
|
53588
53662
|
kinds: [
|
|
53589
53663
|
"server-update-available",
|
|
53664
|
+
"node-updating",
|
|
53590
53665
|
"server-updated",
|
|
53591
53666
|
"wrapper-update-available"
|
|
53592
53667
|
]
|
|
@@ -53663,6 +53738,7 @@ var STATE_SUMMARY_VARS = [
|
|
|
53663
53738
|
[...RULE_BODY_ONLY],
|
|
53664
53739
|
[...RULE_TEXT],
|
|
53665
53740
|
([...RULE_TEXT], [...DEVICE_EVENTS]),
|
|
53741
|
+
([...RULE_TEXT], [...COMBINED_ALARM]),
|
|
53666
53742
|
([...RULE_TEXT], [...DEVICE_EVENTS]),
|
|
53667
53743
|
([...RULE_TEXT], [...BATTERY, ...CONSUMABLE]),
|
|
53668
53744
|
([...RULE_TEXT], [...CONSUMABLE]),
|
|
@@ -53703,6 +53779,8 @@ var STATE_SUMMARY_VARS = [
|
|
|
53703
53779
|
[...RULE_TEXT],
|
|
53704
53780
|
[...RULE_TEXT],
|
|
53705
53781
|
[...RULE_TEXT],
|
|
53782
|
+
[...RULE_TEXT],
|
|
53783
|
+
[...RULE_TEXT],
|
|
53706
53784
|
...STATE_SUMMARY_VARS
|
|
53707
53785
|
];
|
|
53708
53786
|
new Set([
|
|
@@ -54039,10 +54117,9 @@ TimelapseRuleInputSchema.extend({
|
|
|
54039
54117
|
createdAt: number(),
|
|
54040
54118
|
updatedAt: number()
|
|
54041
54119
|
});
|
|
54042
|
-
async function
|
|
54043
|
-
let slice;
|
|
54120
|
+
async function readSlice(deviceState, deviceId) {
|
|
54044
54121
|
try {
|
|
54045
|
-
|
|
54122
|
+
return await deviceState.getCapSlice.query({
|
|
54046
54123
|
deviceId,
|
|
54047
54124
|
capName: "motion"
|
|
54048
54125
|
});
|
|
@@ -54050,10 +54127,44 @@ async function readHubMotionDetected(deviceState, deviceId) {
|
|
|
54050
54127
|
const reason = err instanceof Error ? err.message : String(err);
|
|
54051
54128
|
throw new Error(`motion state of device ${deviceId} is unreadable: ${reason}`, { cause: err });
|
|
54052
54129
|
}
|
|
54053
|
-
|
|
54130
|
+
}
|
|
54131
|
+
/**
|
|
54132
|
+
* The hub's `motion` slice as a `MotionStatus`, or `null` when nobody has
|
|
54133
|
+
* published it since the hub started. Throws when the hub does not answer or
|
|
54134
|
+
* the slice is malformed — never a made-up "no motion".
|
|
54135
|
+
*/
|
|
54136
|
+
async function readHubMotionStatus(deviceState, deviceId) {
|
|
54137
|
+
const slice = await readSlice(deviceState, deviceId);
|
|
54138
|
+
if (slice === null) return null;
|
|
54139
|
+
const parsed = MotionStatusSchema.safeParse(slice);
|
|
54140
|
+
if (!parsed.success) throw new Error(`motion state of device ${deviceId} is malformed on the hub: ${parsed.error.message}`);
|
|
54141
|
+
return parsed.data;
|
|
54142
|
+
}
|
|
54143
|
+
async function readHubMotionDetected(deviceState, deviceId) {
|
|
54144
|
+
const detected = (await readSlice(deviceState, deviceId))?.["detected"];
|
|
54054
54145
|
if (typeof detected !== "boolean") throw new Error(`motion state of device ${deviceId} is not published yet (unknown)`);
|
|
54055
54146
|
return detected;
|
|
54056
54147
|
}
|
|
54148
|
+
/**
|
|
54149
|
+
* The native `motion` provider of a camera whose slice the orchestrator writes
|
|
54150
|
+
* (D696): `isDetected` AND `getStatus`, both from the hub. `owner` names the
|
|
54151
|
+
* provider class in the deviceId-mismatch error.
|
|
54152
|
+
*/
|
|
54153
|
+
function hubMotionNativeProvider(deviceState, deviceId, owner) {
|
|
54154
|
+
const ownDevice = (asked) => {
|
|
54155
|
+
if (asked !== deviceId) throw new Error(`${owner}: motion deviceId mismatch, expected ${deviceId}, got ${asked}`);
|
|
54156
|
+
};
|
|
54157
|
+
return {
|
|
54158
|
+
isDetected: async ({ deviceId: asked }) => {
|
|
54159
|
+
ownDevice(asked);
|
|
54160
|
+
return readHubMotionDetected(deviceState, deviceId);
|
|
54161
|
+
},
|
|
54162
|
+
getStatus: async ({ deviceId: asked }) => {
|
|
54163
|
+
ownDevice(asked);
|
|
54164
|
+
return readHubMotionStatus(deviceState, deviceId);
|
|
54165
|
+
}
|
|
54166
|
+
};
|
|
54167
|
+
}
|
|
54057
54168
|
MotionOnMotionChangedDataSchema.omit({ triggeredBy: true });
|
|
54058
54169
|
function providerMotionEvent(source, data) {
|
|
54059
54170
|
return createEvent(EventCategory.ProviderMotion, source, data);
|
|
@@ -56427,14 +56538,12 @@ var AmcrestCamera = class AmcrestCamera extends BaseDevice {
|
|
|
56427
56538
|
}
|
|
56428
56539
|
/** Register the native `motion` cap. Its mere presence (a `kind:'native'`
|
|
56429
56540
|
* `motion` binding) is what the orchestrator reads to default a
|
|
56430
|
-
* freshly-adopted camera to `motionSources:['onboard']`. `isDetected`
|
|
56431
|
-
*
|
|
56432
|
-
*
|
|
56541
|
+
* freshly-adopted camera to `motionSources:['onboard']`. `isDetected` and
|
|
56542
|
+
* `getStatus` answer from the HUB's slice (`hubMotionNativeProvider`); an
|
|
56543
|
+
* unreadable hub fails both — never `false` for unknown (D49, D393). */
|
|
56433
56544
|
registerMotionCap() {
|
|
56434
|
-
this.ctx.
|
|
56435
|
-
|
|
56436
|
-
return readHubMotionDetected(this.ctx.api.deviceState, this.id);
|
|
56437
|
-
} });
|
|
56545
|
+
const provider = hubMotionNativeProvider(this.ctx.api.deviceState, this.id, "AmcrestCamera");
|
|
56546
|
+
this.ctx.registerNativeCap(motionCapability, provider);
|
|
56438
56547
|
this.ctx.logger.info("amcrest: motion cap registered", { tags: { deviceId: this.id } });
|
|
56439
56548
|
}
|
|
56440
56549
|
/** Reusable event-source identity for every emit on this device. */
|
|
@@ -56645,7 +56754,7 @@ var AmcrestCamera = class AmcrestCamera extends BaseDevice {
|
|
|
56645
56754
|
key: "host",
|
|
56646
56755
|
label: "Camera IP",
|
|
56647
56756
|
required: true,
|
|
56648
|
-
placeholder: "192.168.
|
|
56757
|
+
placeholder: "192.168.10.100"
|
|
56649
56758
|
},
|
|
56650
56759
|
{
|
|
56651
56760
|
type: "number",
|
|
@@ -70867,13 +70976,13 @@ function enumerateHosts(cidr) {
|
|
|
70867
70976
|
for (let d = 1; d <= 254; d += 1) out.push(`${a}.${b}.${c}.${d}`);
|
|
70868
70977
|
return out;
|
|
70869
70978
|
}
|
|
70870
|
-
/** Best-effort local /24 from the first non-internal IPv4 interface (e.g. `192.168.
|
|
70979
|
+
/** Best-effort local /24 from the first non-internal IPv4 interface (e.g. `192.168.10.0/24`). */
|
|
70871
70980
|
function detectLocalCidr() {
|
|
70872
70981
|
for (const addrs of Object.values(networkInterfaces())) for (const addr of addrs ?? []) if (addr.family === "IPv4" && !addr.internal) {
|
|
70873
70982
|
const [a, b, c] = addr.address.split(".");
|
|
70874
70983
|
return `${a}.${b}.${c}.0/24`;
|
|
70875
70984
|
}
|
|
70876
|
-
return "192.168.
|
|
70985
|
+
return "192.168.10.0/24";
|
|
70877
70986
|
}
|
|
70878
70987
|
/** Flatten a host into a flat row-key slug — must match `generateStableId`'s host fallback so a
|
|
70879
70988
|
* re-scan of a host-added camera is detected as already onboarded. */
|
|
@@ -70942,7 +71051,7 @@ function buildCreationFormSchema() {
|
|
|
70942
71051
|
key: "host",
|
|
70943
71052
|
label: "Camera IP",
|
|
70944
71053
|
required: true,
|
|
70945
|
-
placeholder: "192.168.
|
|
71054
|
+
placeholder: "192.168.10.100",
|
|
70946
71055
|
inputType: "text"
|
|
70947
71056
|
},
|
|
70948
71057
|
{
|
|
@@ -70993,14 +71102,14 @@ function buildDiscoveryParamsFormSchema() {
|
|
|
70993
71102
|
}, {
|
|
70994
71103
|
id: "scan",
|
|
70995
71104
|
title: "Scan options",
|
|
70996
|
-
description: "The credentialed CGI subnet scan is the reliable path (multicast WS-Discovery is not received on a macvlan/br0 hub). IMPORTANT: leaving the network blank scans only the HUB’s own subnet — if your cameras are on a DIFFERENT subnet than the hub, you MUST enter their CIDR here (e.g. 192.168.
|
|
71105
|
+
description: "The credentialed CGI subnet scan is the reliable path (multicast WS-Discovery is not received on a macvlan/br0 hub). IMPORTANT: leaving the network blank scans only the HUB’s own subnet — if your cameras are on a DIFFERENT subnet than the hub, you MUST enter their CIDR here (e.g. 192.168.60.0/24), otherwise the scan returns nothing.",
|
|
70997
71106
|
columns: 1,
|
|
70998
71107
|
fields: [{
|
|
70999
71108
|
type: "text",
|
|
71000
71109
|
key: "networkCidr",
|
|
71001
71110
|
label: "Network (CIDR) — required if cameras are on a different subnet than the hub",
|
|
71002
71111
|
required: false,
|
|
71003
|
-
placeholder: "192.168.
|
|
71112
|
+
placeholder: "192.168.60.0/24"
|
|
71004
71113
|
}, {
|
|
71005
71114
|
type: "number",
|
|
71006
71115
|
key: "timeoutMs",
|