@camstack/addon-smtp-nodemailer 1.2.47 → 1.2.48
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/smtp.addon.js +218 -4
- package/dist/smtp.addon.mjs +218 -4
- package/package.json +1 -1
package/dist/smtp.addon.js
CHANGED
|
@@ -8039,6 +8039,20 @@ var RelocateJobSchema = object({
|
|
|
8039
8039
|
* in its row, not in its name, so `MediaRelocateEngine` never reconciles one.
|
|
8040
8040
|
*/
|
|
8041
8041
|
rowsReconciled: number().int().nonnegative().optional(),
|
|
8042
|
+
/**
|
|
8043
|
+
* Rows this run FORGOT because the file they name is not on disk.
|
|
8044
|
+
*
|
|
8045
|
+
* The mover derived the path from the row's own fields and `stat`ed it; an
|
|
8046
|
+
* ENOENT there is a per-path confirmation that the segment is gone (D296),
|
|
8047
|
+
* and the durable row is dropped through the same channel eviction uses. It
|
|
8048
|
+
* is reported for the same reason `rowsReconciled` is: this is a durable
|
|
8049
|
+
* mutation nobody asked for, and a migration that quietly erases hour rows is
|
|
8050
|
+
* the same failure as one that quietly skips them (D295).
|
|
8051
|
+
*
|
|
8052
|
+
* The production drain of 2026-08-30 would have reported 11 074 here — the
|
|
8053
|
+
* ledger claimed 5.65 GB of footage that no longer existed.
|
|
8054
|
+
*/
|
|
8055
|
+
rowsForgotten: number().int().nonnegative().optional(),
|
|
8042
8056
|
startedAt: number(),
|
|
8043
8057
|
finishedAt: number().nullable(),
|
|
8044
8058
|
error: string().nullable()
|
|
@@ -8402,6 +8416,91 @@ var RelocateResidueSchema = object({
|
|
|
8402
8416
|
segments: number().int().nonnegative(),
|
|
8403
8417
|
bytes: number().int().nonnegative()
|
|
8404
8418
|
}).nullable();
|
|
8419
|
+
/**
|
|
8420
|
+
* Ask one location whether its durable hour rows describe the disk — the walk
|
|
8421
|
+
* (D319).
|
|
8422
|
+
*
|
|
8423
|
+
* `apply` DEFAULTS TO FALSE and that default is the product: the operator's
|
|
8424
|
+
* missing tool is the question, and the dry run is how they sanity-check the
|
|
8425
|
+
* destructive run before authorising it.
|
|
8426
|
+
*/
|
|
8427
|
+
var LedgerWalkInputSchema = object({
|
|
8428
|
+
locationId: string().min(1),
|
|
8429
|
+
/** Forget the confirmed-absent rows, rather than only counting them. */
|
|
8430
|
+
apply: boolean().optional(),
|
|
8431
|
+
/** Narrow to one camera. */
|
|
8432
|
+
deviceId: number().int().positive().optional(),
|
|
8433
|
+
/** Narrow to these recording profiles; empty/absent = every profile. */
|
|
8434
|
+
profiles: array(string().min(1)).optional()
|
|
8435
|
+
});
|
|
8436
|
+
/** Why a whole walk did nothing. Every one leaves the ledger untouched. */
|
|
8437
|
+
var LedgerWalkRefusalSchema = _enum([
|
|
8438
|
+
"location-unknown",
|
|
8439
|
+
"source-writable",
|
|
8440
|
+
"no-ledger",
|
|
8441
|
+
"archive-unreadable",
|
|
8442
|
+
"anchor-absent",
|
|
8443
|
+
"anchor-unreadable",
|
|
8444
|
+
"anchor-moved"
|
|
8445
|
+
]);
|
|
8446
|
+
_enum([
|
|
8447
|
+
"live-tail",
|
|
8448
|
+
"listing-error",
|
|
8449
|
+
"path-mismatch",
|
|
8450
|
+
"durable-refused"
|
|
8451
|
+
]);
|
|
8452
|
+
/** Every skip reason, always present, always a number — so a reason that never
|
|
8453
|
+
* fired reports as zero rather than absent and the report shape is constant
|
|
8454
|
+
* between passes. Spelled out rather than `z.record` for exactly that. */
|
|
8455
|
+
var LedgerWalkSkipCountsSchema = object({
|
|
8456
|
+
"live-tail": number().int().nonnegative(),
|
|
8457
|
+
"listing-error": number().int().nonnegative(),
|
|
8458
|
+
"path-mismatch": number().int().nonnegative(),
|
|
8459
|
+
"durable-refused": number().int().nonnegative()
|
|
8460
|
+
});
|
|
8461
|
+
/** One camera's share of a walk, so a report names cameras and not rows. */
|
|
8462
|
+
var LedgerWalkDeviceReportSchema = object({
|
|
8463
|
+
deviceId: number().int(),
|
|
8464
|
+
hoursWalked: number().int().nonnegative(),
|
|
8465
|
+
hoursMissing: number().int().nonnegative(),
|
|
8466
|
+
ghostSegments: number().int().nonnegative(),
|
|
8467
|
+
ghostBytes: number().int().nonnegative(),
|
|
8468
|
+
forgottenSegments: number().int().nonnegative(),
|
|
8469
|
+
orphanFiles: number().int().nonnegative()
|
|
8470
|
+
});
|
|
8471
|
+
/**
|
|
8472
|
+
* What one walk claimed, listed, found and (only when armed) forgot.
|
|
8473
|
+
*
|
|
8474
|
+
* `archiveSegments` is the **M** and `segmentsClaimed` the **N** (D295), so a
|
|
8475
|
+
* walk that saw a fraction of the location is visible in its own report rather
|
|
8476
|
+
* than in the absence of one.
|
|
8477
|
+
*/
|
|
8478
|
+
var LedgerWalkReportSchema = object({
|
|
8479
|
+
locationId: string(),
|
|
8480
|
+
applied: boolean(),
|
|
8481
|
+
refused: LedgerWalkRefusalSchema.nullable(),
|
|
8482
|
+
archiveSegments: number().int().nonnegative().nullable(),
|
|
8483
|
+
archiveBytes: number().int().nonnegative().nullable(),
|
|
8484
|
+
hoursClaimed: number().int().nonnegative(),
|
|
8485
|
+
hoursWalked: number().int().nonnegative(),
|
|
8486
|
+
hoursMissing: number().int().nonnegative(),
|
|
8487
|
+
/** `readdir` calls issued — the cost, stated in the unit that is paid. */
|
|
8488
|
+
listings: number().int().nonnegative(),
|
|
8489
|
+
segmentsClaimed: number().int().nonnegative(),
|
|
8490
|
+
ghostSegments: number().int().nonnegative(),
|
|
8491
|
+
ghostBytes: number().int().nonnegative(),
|
|
8492
|
+
ghostHoursWhole: number().int().nonnegative(),
|
|
8493
|
+
forgottenSegments: number().int().nonnegative(),
|
|
8494
|
+
forgottenBytes: number().int().nonnegative(),
|
|
8495
|
+
/** Files under a claimed hour that no durable row names. Never deleted. */
|
|
8496
|
+
orphanFiles: number().int().nonnegative(),
|
|
8497
|
+
orphanSample: array(string()).readonly(),
|
|
8498
|
+
hoursSkipped: number().int().nonnegative(),
|
|
8499
|
+
skippedByReason: LedgerWalkSkipCountsSchema,
|
|
8500
|
+
/** The walk stopped at its per-pass hour bound with claims unwalked. */
|
|
8501
|
+
bounded: boolean(),
|
|
8502
|
+
byDevice: array(LedgerWalkDeviceReportSchema).readonly()
|
|
8503
|
+
});
|
|
8405
8504
|
/** How many rows a media pass would still act on against a given target — the
|
|
8406
8505
|
* media lane's denominator AND its residue, from ONE derivation so the two can
|
|
8407
8506
|
* never disagree. `null` = the count could not be taken. */
|
|
@@ -18675,13 +18774,15 @@ var ListGroupsPageSchema = object({
|
|
|
18675
18774
|
groups: array(AnalyticsGroupRecordSchema).readonly(),
|
|
18676
18775
|
nextCursor: string().nullable()
|
|
18677
18776
|
});
|
|
18777
|
+
var KEY_EVENTS_DEFAULT_LIMIT = 50;
|
|
18778
|
+
var KEY_EVENTS_MAX_LIMIT = 200;
|
|
18678
18779
|
var KeyEventQueryInput = object({
|
|
18679
18780
|
deviceId: number(),
|
|
18680
18781
|
/** Window lower bound (track firstSeen ≥ since). */
|
|
18681
18782
|
since: number(),
|
|
18682
18783
|
/** Window upper bound (track firstSeen ≤ until). */
|
|
18683
18784
|
until: number(),
|
|
18684
|
-
limit: number().int().min(1).max(
|
|
18785
|
+
limit: number().int().min(1).max(KEY_EVENTS_MAX_LIMIT).default(KEY_EVENTS_DEFAULT_LIMIT),
|
|
18685
18786
|
/** Drop tracks scoring below this importance. */
|
|
18686
18787
|
minImportance: number().min(0).max(1).optional(),
|
|
18687
18788
|
/** Restrict to a single class (e.g. 'person'). */
|
|
@@ -18703,6 +18804,32 @@ var KeyEventSchema = object({
|
|
|
18703
18804
|
...TrackFlagFields,
|
|
18704
18805
|
...TrackRetrainFields
|
|
18705
18806
|
});
|
|
18807
|
+
/** `getKeyEvents`' window and filters, asked of a SET of cameras at once. */
|
|
18808
|
+
var KeyEventBatchQueryInput = object({
|
|
18809
|
+
deviceIds: array(number()).min(1).max(200),
|
|
18810
|
+
since: number(),
|
|
18811
|
+
until: number(),
|
|
18812
|
+
/** Applied PER CAMERA, exactly as `getKeyEvents.limit` is — never a total
|
|
18813
|
+
* across the set, which would let a busy camera starve a quiet one of its
|
|
18814
|
+
* rows and change what the merged feed contains. */
|
|
18815
|
+
limit: number().int().min(1).max(KEY_EVENTS_MAX_LIMIT).default(KEY_EVENTS_DEFAULT_LIMIT),
|
|
18816
|
+
minImportance: number().min(0).max(1).optional(),
|
|
18817
|
+
classFilter: string().optional()
|
|
18818
|
+
});
|
|
18819
|
+
/**
|
|
18820
|
+
* One camera's key events in a batch answer.
|
|
18821
|
+
*
|
|
18822
|
+
* The row exists for every requested id. `getKeyEvents` degrades to `[]` on
|
|
18823
|
+
* error rather than throwing, so a camera whose store read failed and one with
|
|
18824
|
+
* no events in the window were ALREADY indistinguishable per camera — the
|
|
18825
|
+
* batch does not make that worse, and the row keeps the deviceId the single
|
|
18826
|
+
* method's output never carried (the caller used to stamp it from the fan-out
|
|
18827
|
+
* key, which only worked because there was one query per camera).
|
|
18828
|
+
*/
|
|
18829
|
+
var KeyEventsForDeviceSchema = object({
|
|
18830
|
+
deviceId: number(),
|
|
18831
|
+
events: array(KeyEventSchema).readonly()
|
|
18832
|
+
});
|
|
18706
18833
|
object({
|
|
18707
18834
|
trackId: string(),
|
|
18708
18835
|
className: string(),
|
|
@@ -18972,7 +19099,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
18972
19099
|
until: number().optional(),
|
|
18973
19100
|
kinds: array(string()).optional(),
|
|
18974
19101
|
limit: number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT)
|
|
18975
|
-
}), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
|
|
19102
|
+
}), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(KeyEventBatchQueryInput, array(KeyEventsForDeviceSchema).readonly()), method(object({
|
|
18976
19103
|
deviceId: number(),
|
|
18977
19104
|
since: number(),
|
|
18978
19105
|
until: number(),
|
|
@@ -26637,6 +26764,9 @@ method(object({
|
|
|
26637
26764
|
}), method(RelocateResidueInputSchema, RelocateResidueSchema, {
|
|
26638
26765
|
kind: "query",
|
|
26639
26766
|
auth: "admin"
|
|
26767
|
+
}), method(LedgerWalkInputSchema, LedgerWalkReportSchema, {
|
|
26768
|
+
kind: "mutation",
|
|
26769
|
+
auth: "admin"
|
|
26640
26770
|
}), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
26641
26771
|
kind: "mutation",
|
|
26642
26772
|
auth: "admin"
|
|
@@ -27028,7 +27158,26 @@ var SceneMonitorStatusSchema = object({
|
|
|
27028
27158
|
monitors: array(SceneMonitorSchema),
|
|
27029
27159
|
lastFetchedAt: number()
|
|
27030
27160
|
});
|
|
27031
|
-
|
|
27161
|
+
/**
|
|
27162
|
+
* One camera's row in a `listScenesBatch` answer.
|
|
27163
|
+
*
|
|
27164
|
+
* `status` is NULLABLE and the nullability is the whole point. `scene-monitor`
|
|
27165
|
+
* is a `defaultActive` wrapper, so every camera is asked; a camera whose
|
|
27166
|
+
* provider is absent (pipeline-analytics not deployed, the post-processing node
|
|
27167
|
+
* down) cannot answer, and that is not the same fact as a camera with no scenes
|
|
27168
|
+
* configured. Fanned out per camera the difference was visible — one query
|
|
27169
|
+
* errored while the others resolved — and a batch that returned only the rows
|
|
27170
|
+
* it managed would have destroyed it, silently, by making an unreachable camera
|
|
27171
|
+
* indistinguishable from one that answered `monitors: []`.
|
|
27172
|
+
*
|
|
27173
|
+
* So: EVERY requested deviceId gets a row. `status: null` means "this camera
|
|
27174
|
+
* could not be read"; `status.monitors: []` means "read, and it has none".
|
|
27175
|
+
*/
|
|
27176
|
+
var SceneMonitorStatusForDeviceSchema = object({
|
|
27177
|
+
deviceId: number(),
|
|
27178
|
+
status: SceneMonitorStatusSchema.nullable()
|
|
27179
|
+
});
|
|
27180
|
+
DeviceType.Camera, method(object({ deviceId: number() }), SceneMonitorStatusSchema), method(object({ deviceIds: array(number()).min(1).max(200) }), array(SceneMonitorStatusForDeviceSchema).readonly()), method(object({
|
|
27032
27181
|
deviceId: number(),
|
|
27033
27182
|
label: string(),
|
|
27034
27183
|
roi: MaskRectShapeSchema,
|
|
@@ -28352,6 +28501,27 @@ var CameraOccupancySnapshotSchema = object({
|
|
|
28352
28501
|
stationaryObjects: array(StationaryObjectSchema).readonly().optional()
|
|
28353
28502
|
});
|
|
28354
28503
|
/**
|
|
28504
|
+
* One camera's row in a `getCurrentSnapshotBatch` answer.
|
|
28505
|
+
*
|
|
28506
|
+
* THREE outcomes, and the single-camera method could only express two of them
|
|
28507
|
+
* because `snapshot: null` was already spoken for:
|
|
28508
|
+
*
|
|
28509
|
+
* - `read: 'read'`, `snapshot` present — the live occupancy reading.
|
|
28510
|
+
* - `read: 'read'`, `snapshot: null` — read, and this camera has no reading
|
|
28511
|
+
* yet: no frame since boot, and no parked-object registry to hydrate from.
|
|
28512
|
+
* - `read: 'unreadable'` — the owner could not answer for this
|
|
28513
|
+
* camera. `snapshot` is null, and it does NOT mean "nothing parked here".
|
|
28514
|
+
*
|
|
28515
|
+
* Collapsing the last two is the failure this field exists to prevent: a
|
|
28516
|
+
* hydration that threw would otherwise render as an empty Stationary section,
|
|
28517
|
+
* which is a definite claim about a camera nobody could read.
|
|
28518
|
+
*/
|
|
28519
|
+
var CameraOccupancySnapshotForDeviceSchema = object({
|
|
28520
|
+
deviceId: number(),
|
|
28521
|
+
read: _enum(["read", "unreadable"]),
|
|
28522
|
+
snapshot: CameraOccupancySnapshotSchema.nullable()
|
|
28523
|
+
});
|
|
28524
|
+
/**
|
|
28355
28525
|
* Time-series resolution. The history methods return one bucket per
|
|
28356
28526
|
* step over the requested range. Smaller resolutions cost more
|
|
28357
28527
|
* memory + bandwidth; bound to discrete steps so caller cannot ask
|
|
@@ -28375,7 +28545,7 @@ var HistoryPointSchema = object({
|
|
|
28375
28545
|
/** Object count averaged over the bucket (rounded to nearest integer). */
|
|
28376
28546
|
count: number().int().nonnegative()
|
|
28377
28547
|
});
|
|
28378
|
-
DeviceType.Camera, method(object({ deviceId: number() }), CameraOccupancySnapshotSchema.nullable()), method(object({
|
|
28548
|
+
DeviceType.Camera, method(object({ deviceId: number() }), CameraOccupancySnapshotSchema.nullable()), method(object({ deviceIds: array(number()).min(1).max(200) }), array(CameraOccupancySnapshotForDeviceSchema).readonly()), method(object({
|
|
28379
28549
|
deviceId: number(),
|
|
28380
28550
|
zoneId: string(),
|
|
28381
28551
|
className: string().optional()
|
|
@@ -31680,6 +31850,12 @@ Object.freeze({
|
|
|
31680
31850
|
addonId: null,
|
|
31681
31851
|
access: "view"
|
|
31682
31852
|
},
|
|
31853
|
+
"pipelineAnalytics.getKeyEventsBatch": {
|
|
31854
|
+
capName: "pipeline-analytics",
|
|
31855
|
+
capScope: "device",
|
|
31856
|
+
addonId: null,
|
|
31857
|
+
access: "view"
|
|
31858
|
+
},
|
|
31683
31859
|
"pipelineAnalytics.getMotionEvents": {
|
|
31684
31860
|
capName: "pipeline-analytics",
|
|
31685
31861
|
capScope: "device",
|
|
@@ -32856,6 +33032,12 @@ Object.freeze({
|
|
|
32856
33032
|
addonId: null,
|
|
32857
33033
|
access: "view"
|
|
32858
33034
|
},
|
|
33035
|
+
"recording.reconcileLedgerAgainstDisk": {
|
|
33036
|
+
capName: "recording",
|
|
33037
|
+
capScope: "system",
|
|
33038
|
+
addonId: null,
|
|
33039
|
+
access: "create"
|
|
33040
|
+
},
|
|
32859
33041
|
"recording.refreshStorageLocationsForMigration": {
|
|
32860
33042
|
capName: "recording",
|
|
32861
33043
|
capScope: "system",
|
|
@@ -32982,6 +33164,12 @@ Object.freeze({
|
|
|
32982
33164
|
addonId: null,
|
|
32983
33165
|
access: "view"
|
|
32984
33166
|
},
|
|
33167
|
+
"sceneMonitor.listScenesBatch": {
|
|
33168
|
+
capName: "scene-monitor",
|
|
33169
|
+
capScope: "device",
|
|
33170
|
+
addonId: null,
|
|
33171
|
+
access: "view"
|
|
33172
|
+
},
|
|
32985
33173
|
"sceneMonitor.recheckNow": {
|
|
32986
33174
|
capName: "scene-monitor",
|
|
32987
33175
|
capScope: "device",
|
|
@@ -34338,6 +34526,12 @@ Object.freeze({
|
|
|
34338
34526
|
addonId: null,
|
|
34339
34527
|
access: "view"
|
|
34340
34528
|
},
|
|
34529
|
+
"zoneAnalytics.getCurrentSnapshotBatch": {
|
|
34530
|
+
capName: "zone-analytics",
|
|
34531
|
+
capScope: "device",
|
|
34532
|
+
addonId: null,
|
|
34533
|
+
access: "view"
|
|
34534
|
+
},
|
|
34341
34535
|
"zoneAnalytics.getUnzonedHistory": {
|
|
34342
34536
|
capName: "zone-analytics",
|
|
34343
34537
|
capScope: "device",
|
|
@@ -35342,6 +35536,11 @@ Object.freeze({
|
|
|
35342
35536
|
form: "single",
|
|
35343
35537
|
optional: false
|
|
35344
35538
|
}],
|
|
35539
|
+
"pipelineAnalytics.getKeyEventsBatch": [{
|
|
35540
|
+
name: "deviceIds",
|
|
35541
|
+
form: "array",
|
|
35542
|
+
optional: false
|
|
35543
|
+
}],
|
|
35345
35544
|
"pipelineAnalytics.getMotionEvents": [{
|
|
35346
35545
|
name: "deviceId",
|
|
35347
35546
|
form: "single",
|
|
@@ -35782,6 +35981,11 @@ Object.freeze({
|
|
|
35782
35981
|
form: "single",
|
|
35783
35982
|
optional: false
|
|
35784
35983
|
}],
|
|
35984
|
+
"recording.reconcileLedgerAgainstDisk": [{
|
|
35985
|
+
name: "deviceId",
|
|
35986
|
+
form: "single",
|
|
35987
|
+
optional: true
|
|
35988
|
+
}],
|
|
35785
35989
|
"recording.relocateFootage": [{
|
|
35786
35990
|
name: "deviceId",
|
|
35787
35991
|
form: "single",
|
|
@@ -35847,6 +36051,11 @@ Object.freeze({
|
|
|
35847
36051
|
form: "single",
|
|
35848
36052
|
optional: false
|
|
35849
36053
|
}],
|
|
36054
|
+
"sceneMonitor.listScenesBatch": [{
|
|
36055
|
+
name: "deviceIds",
|
|
36056
|
+
form: "array",
|
|
36057
|
+
optional: false
|
|
36058
|
+
}],
|
|
35850
36059
|
"sceneMonitor.recheckNow": [{
|
|
35851
36060
|
name: "deviceId",
|
|
35852
36061
|
form: "single",
|
|
@@ -36108,6 +36317,11 @@ Object.freeze({
|
|
|
36108
36317
|
form: "single",
|
|
36109
36318
|
optional: false
|
|
36110
36319
|
}],
|
|
36320
|
+
"zoneAnalytics.getCurrentSnapshotBatch": [{
|
|
36321
|
+
name: "deviceIds",
|
|
36322
|
+
form: "array",
|
|
36323
|
+
optional: false
|
|
36324
|
+
}],
|
|
36111
36325
|
"zoneAnalytics.getUnzonedHistory": [{
|
|
36112
36326
|
name: "deviceId",
|
|
36113
36327
|
form: "single",
|
package/dist/smtp.addon.mjs
CHANGED
|
@@ -8037,6 +8037,20 @@ var RelocateJobSchema = object({
|
|
|
8037
8037
|
* in its row, not in its name, so `MediaRelocateEngine` never reconciles one.
|
|
8038
8038
|
*/
|
|
8039
8039
|
rowsReconciled: number().int().nonnegative().optional(),
|
|
8040
|
+
/**
|
|
8041
|
+
* Rows this run FORGOT because the file they name is not on disk.
|
|
8042
|
+
*
|
|
8043
|
+
* The mover derived the path from the row's own fields and `stat`ed it; an
|
|
8044
|
+
* ENOENT there is a per-path confirmation that the segment is gone (D296),
|
|
8045
|
+
* and the durable row is dropped through the same channel eviction uses. It
|
|
8046
|
+
* is reported for the same reason `rowsReconciled` is: this is a durable
|
|
8047
|
+
* mutation nobody asked for, and a migration that quietly erases hour rows is
|
|
8048
|
+
* the same failure as one that quietly skips them (D295).
|
|
8049
|
+
*
|
|
8050
|
+
* The production drain of 2026-08-30 would have reported 11 074 here — the
|
|
8051
|
+
* ledger claimed 5.65 GB of footage that no longer existed.
|
|
8052
|
+
*/
|
|
8053
|
+
rowsForgotten: number().int().nonnegative().optional(),
|
|
8040
8054
|
startedAt: number(),
|
|
8041
8055
|
finishedAt: number().nullable(),
|
|
8042
8056
|
error: string().nullable()
|
|
@@ -8400,6 +8414,91 @@ var RelocateResidueSchema = object({
|
|
|
8400
8414
|
segments: number().int().nonnegative(),
|
|
8401
8415
|
bytes: number().int().nonnegative()
|
|
8402
8416
|
}).nullable();
|
|
8417
|
+
/**
|
|
8418
|
+
* Ask one location whether its durable hour rows describe the disk — the walk
|
|
8419
|
+
* (D319).
|
|
8420
|
+
*
|
|
8421
|
+
* `apply` DEFAULTS TO FALSE and that default is the product: the operator's
|
|
8422
|
+
* missing tool is the question, and the dry run is how they sanity-check the
|
|
8423
|
+
* destructive run before authorising it.
|
|
8424
|
+
*/
|
|
8425
|
+
var LedgerWalkInputSchema = object({
|
|
8426
|
+
locationId: string().min(1),
|
|
8427
|
+
/** Forget the confirmed-absent rows, rather than only counting them. */
|
|
8428
|
+
apply: boolean().optional(),
|
|
8429
|
+
/** Narrow to one camera. */
|
|
8430
|
+
deviceId: number().int().positive().optional(),
|
|
8431
|
+
/** Narrow to these recording profiles; empty/absent = every profile. */
|
|
8432
|
+
profiles: array(string().min(1)).optional()
|
|
8433
|
+
});
|
|
8434
|
+
/** Why a whole walk did nothing. Every one leaves the ledger untouched. */
|
|
8435
|
+
var LedgerWalkRefusalSchema = _enum([
|
|
8436
|
+
"location-unknown",
|
|
8437
|
+
"source-writable",
|
|
8438
|
+
"no-ledger",
|
|
8439
|
+
"archive-unreadable",
|
|
8440
|
+
"anchor-absent",
|
|
8441
|
+
"anchor-unreadable",
|
|
8442
|
+
"anchor-moved"
|
|
8443
|
+
]);
|
|
8444
|
+
_enum([
|
|
8445
|
+
"live-tail",
|
|
8446
|
+
"listing-error",
|
|
8447
|
+
"path-mismatch",
|
|
8448
|
+
"durable-refused"
|
|
8449
|
+
]);
|
|
8450
|
+
/** Every skip reason, always present, always a number — so a reason that never
|
|
8451
|
+
* fired reports as zero rather than absent and the report shape is constant
|
|
8452
|
+
* between passes. Spelled out rather than `z.record` for exactly that. */
|
|
8453
|
+
var LedgerWalkSkipCountsSchema = object({
|
|
8454
|
+
"live-tail": number().int().nonnegative(),
|
|
8455
|
+
"listing-error": number().int().nonnegative(),
|
|
8456
|
+
"path-mismatch": number().int().nonnegative(),
|
|
8457
|
+
"durable-refused": number().int().nonnegative()
|
|
8458
|
+
});
|
|
8459
|
+
/** One camera's share of a walk, so a report names cameras and not rows. */
|
|
8460
|
+
var LedgerWalkDeviceReportSchema = object({
|
|
8461
|
+
deviceId: number().int(),
|
|
8462
|
+
hoursWalked: number().int().nonnegative(),
|
|
8463
|
+
hoursMissing: number().int().nonnegative(),
|
|
8464
|
+
ghostSegments: number().int().nonnegative(),
|
|
8465
|
+
ghostBytes: number().int().nonnegative(),
|
|
8466
|
+
forgottenSegments: number().int().nonnegative(),
|
|
8467
|
+
orphanFiles: number().int().nonnegative()
|
|
8468
|
+
});
|
|
8469
|
+
/**
|
|
8470
|
+
* What one walk claimed, listed, found and (only when armed) forgot.
|
|
8471
|
+
*
|
|
8472
|
+
* `archiveSegments` is the **M** and `segmentsClaimed` the **N** (D295), so a
|
|
8473
|
+
* walk that saw a fraction of the location is visible in its own report rather
|
|
8474
|
+
* than in the absence of one.
|
|
8475
|
+
*/
|
|
8476
|
+
var LedgerWalkReportSchema = object({
|
|
8477
|
+
locationId: string(),
|
|
8478
|
+
applied: boolean(),
|
|
8479
|
+
refused: LedgerWalkRefusalSchema.nullable(),
|
|
8480
|
+
archiveSegments: number().int().nonnegative().nullable(),
|
|
8481
|
+
archiveBytes: number().int().nonnegative().nullable(),
|
|
8482
|
+
hoursClaimed: number().int().nonnegative(),
|
|
8483
|
+
hoursWalked: number().int().nonnegative(),
|
|
8484
|
+
hoursMissing: number().int().nonnegative(),
|
|
8485
|
+
/** `readdir` calls issued — the cost, stated in the unit that is paid. */
|
|
8486
|
+
listings: number().int().nonnegative(),
|
|
8487
|
+
segmentsClaimed: number().int().nonnegative(),
|
|
8488
|
+
ghostSegments: number().int().nonnegative(),
|
|
8489
|
+
ghostBytes: number().int().nonnegative(),
|
|
8490
|
+
ghostHoursWhole: number().int().nonnegative(),
|
|
8491
|
+
forgottenSegments: number().int().nonnegative(),
|
|
8492
|
+
forgottenBytes: number().int().nonnegative(),
|
|
8493
|
+
/** Files under a claimed hour that no durable row names. Never deleted. */
|
|
8494
|
+
orphanFiles: number().int().nonnegative(),
|
|
8495
|
+
orphanSample: array(string()).readonly(),
|
|
8496
|
+
hoursSkipped: number().int().nonnegative(),
|
|
8497
|
+
skippedByReason: LedgerWalkSkipCountsSchema,
|
|
8498
|
+
/** The walk stopped at its per-pass hour bound with claims unwalked. */
|
|
8499
|
+
bounded: boolean(),
|
|
8500
|
+
byDevice: array(LedgerWalkDeviceReportSchema).readonly()
|
|
8501
|
+
});
|
|
8403
8502
|
/** How many rows a media pass would still act on against a given target — the
|
|
8404
8503
|
* media lane's denominator AND its residue, from ONE derivation so the two can
|
|
8405
8504
|
* never disagree. `null` = the count could not be taken. */
|
|
@@ -18673,13 +18772,15 @@ var ListGroupsPageSchema = object({
|
|
|
18673
18772
|
groups: array(AnalyticsGroupRecordSchema).readonly(),
|
|
18674
18773
|
nextCursor: string().nullable()
|
|
18675
18774
|
});
|
|
18775
|
+
var KEY_EVENTS_DEFAULT_LIMIT = 50;
|
|
18776
|
+
var KEY_EVENTS_MAX_LIMIT = 200;
|
|
18676
18777
|
var KeyEventQueryInput = object({
|
|
18677
18778
|
deviceId: number(),
|
|
18678
18779
|
/** Window lower bound (track firstSeen ≥ since). */
|
|
18679
18780
|
since: number(),
|
|
18680
18781
|
/** Window upper bound (track firstSeen ≤ until). */
|
|
18681
18782
|
until: number(),
|
|
18682
|
-
limit: number().int().min(1).max(
|
|
18783
|
+
limit: number().int().min(1).max(KEY_EVENTS_MAX_LIMIT).default(KEY_EVENTS_DEFAULT_LIMIT),
|
|
18683
18784
|
/** Drop tracks scoring below this importance. */
|
|
18684
18785
|
minImportance: number().min(0).max(1).optional(),
|
|
18685
18786
|
/** Restrict to a single class (e.g. 'person'). */
|
|
@@ -18701,6 +18802,32 @@ var KeyEventSchema = object({
|
|
|
18701
18802
|
...TrackFlagFields,
|
|
18702
18803
|
...TrackRetrainFields
|
|
18703
18804
|
});
|
|
18805
|
+
/** `getKeyEvents`' window and filters, asked of a SET of cameras at once. */
|
|
18806
|
+
var KeyEventBatchQueryInput = object({
|
|
18807
|
+
deviceIds: array(number()).min(1).max(200),
|
|
18808
|
+
since: number(),
|
|
18809
|
+
until: number(),
|
|
18810
|
+
/** Applied PER CAMERA, exactly as `getKeyEvents.limit` is — never a total
|
|
18811
|
+
* across the set, which would let a busy camera starve a quiet one of its
|
|
18812
|
+
* rows and change what the merged feed contains. */
|
|
18813
|
+
limit: number().int().min(1).max(KEY_EVENTS_MAX_LIMIT).default(KEY_EVENTS_DEFAULT_LIMIT),
|
|
18814
|
+
minImportance: number().min(0).max(1).optional(),
|
|
18815
|
+
classFilter: string().optional()
|
|
18816
|
+
});
|
|
18817
|
+
/**
|
|
18818
|
+
* One camera's key events in a batch answer.
|
|
18819
|
+
*
|
|
18820
|
+
* The row exists for every requested id. `getKeyEvents` degrades to `[]` on
|
|
18821
|
+
* error rather than throwing, so a camera whose store read failed and one with
|
|
18822
|
+
* no events in the window were ALREADY indistinguishable per camera — the
|
|
18823
|
+
* batch does not make that worse, and the row keeps the deviceId the single
|
|
18824
|
+
* method's output never carried (the caller used to stamp it from the fan-out
|
|
18825
|
+
* key, which only worked because there was one query per camera).
|
|
18826
|
+
*/
|
|
18827
|
+
var KeyEventsForDeviceSchema = object({
|
|
18828
|
+
deviceId: number(),
|
|
18829
|
+
events: array(KeyEventSchema).readonly()
|
|
18830
|
+
});
|
|
18704
18831
|
object({
|
|
18705
18832
|
trackId: string(),
|
|
18706
18833
|
className: string(),
|
|
@@ -18970,7 +19097,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
18970
19097
|
until: number().optional(),
|
|
18971
19098
|
kinds: array(string()).optional(),
|
|
18972
19099
|
limit: number().int().min(1).max(MAX_EVENT_QUERY_LIMIT).default(DEFAULT_EVENT_QUERY_LIMIT)
|
|
18973
|
-
}), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(object({
|
|
19100
|
+
}), array(SensorEventSchema).readonly()), method(KeyEventQueryInput, array(KeyEventSchema).readonly()), method(KeyEventBatchQueryInput, array(KeyEventsForDeviceSchema).readonly()), method(object({
|
|
18974
19101
|
deviceId: number(),
|
|
18975
19102
|
since: number(),
|
|
18976
19103
|
until: number(),
|
|
@@ -26635,6 +26762,9 @@ method(object({
|
|
|
26635
26762
|
}), method(RelocateResidueInputSchema, RelocateResidueSchema, {
|
|
26636
26763
|
kind: "query",
|
|
26637
26764
|
auth: "admin"
|
|
26765
|
+
}), method(LedgerWalkInputSchema, LedgerWalkReportSchema, {
|
|
26766
|
+
kind: "mutation",
|
|
26767
|
+
auth: "admin"
|
|
26638
26768
|
}), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
26639
26769
|
kind: "mutation",
|
|
26640
26770
|
auth: "admin"
|
|
@@ -27026,7 +27156,26 @@ var SceneMonitorStatusSchema = object({
|
|
|
27026
27156
|
monitors: array(SceneMonitorSchema),
|
|
27027
27157
|
lastFetchedAt: number()
|
|
27028
27158
|
});
|
|
27029
|
-
|
|
27159
|
+
/**
|
|
27160
|
+
* One camera's row in a `listScenesBatch` answer.
|
|
27161
|
+
*
|
|
27162
|
+
* `status` is NULLABLE and the nullability is the whole point. `scene-monitor`
|
|
27163
|
+
* is a `defaultActive` wrapper, so every camera is asked; a camera whose
|
|
27164
|
+
* provider is absent (pipeline-analytics not deployed, the post-processing node
|
|
27165
|
+
* down) cannot answer, and that is not the same fact as a camera with no scenes
|
|
27166
|
+
* configured. Fanned out per camera the difference was visible — one query
|
|
27167
|
+
* errored while the others resolved — and a batch that returned only the rows
|
|
27168
|
+
* it managed would have destroyed it, silently, by making an unreachable camera
|
|
27169
|
+
* indistinguishable from one that answered `monitors: []`.
|
|
27170
|
+
*
|
|
27171
|
+
* So: EVERY requested deviceId gets a row. `status: null` means "this camera
|
|
27172
|
+
* could not be read"; `status.monitors: []` means "read, and it has none".
|
|
27173
|
+
*/
|
|
27174
|
+
var SceneMonitorStatusForDeviceSchema = object({
|
|
27175
|
+
deviceId: number(),
|
|
27176
|
+
status: SceneMonitorStatusSchema.nullable()
|
|
27177
|
+
});
|
|
27178
|
+
DeviceType.Camera, method(object({ deviceId: number() }), SceneMonitorStatusSchema), method(object({ deviceIds: array(number()).min(1).max(200) }), array(SceneMonitorStatusForDeviceSchema).readonly()), method(object({
|
|
27030
27179
|
deviceId: number(),
|
|
27031
27180
|
label: string(),
|
|
27032
27181
|
roi: MaskRectShapeSchema,
|
|
@@ -28350,6 +28499,27 @@ var CameraOccupancySnapshotSchema = object({
|
|
|
28350
28499
|
stationaryObjects: array(StationaryObjectSchema).readonly().optional()
|
|
28351
28500
|
});
|
|
28352
28501
|
/**
|
|
28502
|
+
* One camera's row in a `getCurrentSnapshotBatch` answer.
|
|
28503
|
+
*
|
|
28504
|
+
* THREE outcomes, and the single-camera method could only express two of them
|
|
28505
|
+
* because `snapshot: null` was already spoken for:
|
|
28506
|
+
*
|
|
28507
|
+
* - `read: 'read'`, `snapshot` present — the live occupancy reading.
|
|
28508
|
+
* - `read: 'read'`, `snapshot: null` — read, and this camera has no reading
|
|
28509
|
+
* yet: no frame since boot, and no parked-object registry to hydrate from.
|
|
28510
|
+
* - `read: 'unreadable'` — the owner could not answer for this
|
|
28511
|
+
* camera. `snapshot` is null, and it does NOT mean "nothing parked here".
|
|
28512
|
+
*
|
|
28513
|
+
* Collapsing the last two is the failure this field exists to prevent: a
|
|
28514
|
+
* hydration that threw would otherwise render as an empty Stationary section,
|
|
28515
|
+
* which is a definite claim about a camera nobody could read.
|
|
28516
|
+
*/
|
|
28517
|
+
var CameraOccupancySnapshotForDeviceSchema = object({
|
|
28518
|
+
deviceId: number(),
|
|
28519
|
+
read: _enum(["read", "unreadable"]),
|
|
28520
|
+
snapshot: CameraOccupancySnapshotSchema.nullable()
|
|
28521
|
+
});
|
|
28522
|
+
/**
|
|
28353
28523
|
* Time-series resolution. The history methods return one bucket per
|
|
28354
28524
|
* step over the requested range. Smaller resolutions cost more
|
|
28355
28525
|
* memory + bandwidth; bound to discrete steps so caller cannot ask
|
|
@@ -28373,7 +28543,7 @@ var HistoryPointSchema = object({
|
|
|
28373
28543
|
/** Object count averaged over the bucket (rounded to nearest integer). */
|
|
28374
28544
|
count: number().int().nonnegative()
|
|
28375
28545
|
});
|
|
28376
|
-
DeviceType.Camera, method(object({ deviceId: number() }), CameraOccupancySnapshotSchema.nullable()), method(object({
|
|
28546
|
+
DeviceType.Camera, method(object({ deviceId: number() }), CameraOccupancySnapshotSchema.nullable()), method(object({ deviceIds: array(number()).min(1).max(200) }), array(CameraOccupancySnapshotForDeviceSchema).readonly()), method(object({
|
|
28377
28547
|
deviceId: number(),
|
|
28378
28548
|
zoneId: string(),
|
|
28379
28549
|
className: string().optional()
|
|
@@ -31678,6 +31848,12 @@ Object.freeze({
|
|
|
31678
31848
|
addonId: null,
|
|
31679
31849
|
access: "view"
|
|
31680
31850
|
},
|
|
31851
|
+
"pipelineAnalytics.getKeyEventsBatch": {
|
|
31852
|
+
capName: "pipeline-analytics",
|
|
31853
|
+
capScope: "device",
|
|
31854
|
+
addonId: null,
|
|
31855
|
+
access: "view"
|
|
31856
|
+
},
|
|
31681
31857
|
"pipelineAnalytics.getMotionEvents": {
|
|
31682
31858
|
capName: "pipeline-analytics",
|
|
31683
31859
|
capScope: "device",
|
|
@@ -32854,6 +33030,12 @@ Object.freeze({
|
|
|
32854
33030
|
addonId: null,
|
|
32855
33031
|
access: "view"
|
|
32856
33032
|
},
|
|
33033
|
+
"recording.reconcileLedgerAgainstDisk": {
|
|
33034
|
+
capName: "recording",
|
|
33035
|
+
capScope: "system",
|
|
33036
|
+
addonId: null,
|
|
33037
|
+
access: "create"
|
|
33038
|
+
},
|
|
32857
33039
|
"recording.refreshStorageLocationsForMigration": {
|
|
32858
33040
|
capName: "recording",
|
|
32859
33041
|
capScope: "system",
|
|
@@ -32980,6 +33162,12 @@ Object.freeze({
|
|
|
32980
33162
|
addonId: null,
|
|
32981
33163
|
access: "view"
|
|
32982
33164
|
},
|
|
33165
|
+
"sceneMonitor.listScenesBatch": {
|
|
33166
|
+
capName: "scene-monitor",
|
|
33167
|
+
capScope: "device",
|
|
33168
|
+
addonId: null,
|
|
33169
|
+
access: "view"
|
|
33170
|
+
},
|
|
32983
33171
|
"sceneMonitor.recheckNow": {
|
|
32984
33172
|
capName: "scene-monitor",
|
|
32985
33173
|
capScope: "device",
|
|
@@ -34336,6 +34524,12 @@ Object.freeze({
|
|
|
34336
34524
|
addonId: null,
|
|
34337
34525
|
access: "view"
|
|
34338
34526
|
},
|
|
34527
|
+
"zoneAnalytics.getCurrentSnapshotBatch": {
|
|
34528
|
+
capName: "zone-analytics",
|
|
34529
|
+
capScope: "device",
|
|
34530
|
+
addonId: null,
|
|
34531
|
+
access: "view"
|
|
34532
|
+
},
|
|
34339
34533
|
"zoneAnalytics.getUnzonedHistory": {
|
|
34340
34534
|
capName: "zone-analytics",
|
|
34341
34535
|
capScope: "device",
|
|
@@ -35340,6 +35534,11 @@ Object.freeze({
|
|
|
35340
35534
|
form: "single",
|
|
35341
35535
|
optional: false
|
|
35342
35536
|
}],
|
|
35537
|
+
"pipelineAnalytics.getKeyEventsBatch": [{
|
|
35538
|
+
name: "deviceIds",
|
|
35539
|
+
form: "array",
|
|
35540
|
+
optional: false
|
|
35541
|
+
}],
|
|
35343
35542
|
"pipelineAnalytics.getMotionEvents": [{
|
|
35344
35543
|
name: "deviceId",
|
|
35345
35544
|
form: "single",
|
|
@@ -35780,6 +35979,11 @@ Object.freeze({
|
|
|
35780
35979
|
form: "single",
|
|
35781
35980
|
optional: false
|
|
35782
35981
|
}],
|
|
35982
|
+
"recording.reconcileLedgerAgainstDisk": [{
|
|
35983
|
+
name: "deviceId",
|
|
35984
|
+
form: "single",
|
|
35985
|
+
optional: true
|
|
35986
|
+
}],
|
|
35783
35987
|
"recording.relocateFootage": [{
|
|
35784
35988
|
name: "deviceId",
|
|
35785
35989
|
form: "single",
|
|
@@ -35845,6 +36049,11 @@ Object.freeze({
|
|
|
35845
36049
|
form: "single",
|
|
35846
36050
|
optional: false
|
|
35847
36051
|
}],
|
|
36052
|
+
"sceneMonitor.listScenesBatch": [{
|
|
36053
|
+
name: "deviceIds",
|
|
36054
|
+
form: "array",
|
|
36055
|
+
optional: false
|
|
36056
|
+
}],
|
|
35848
36057
|
"sceneMonitor.recheckNow": [{
|
|
35849
36058
|
name: "deviceId",
|
|
35850
36059
|
form: "single",
|
|
@@ -36106,6 +36315,11 @@ Object.freeze({
|
|
|
36106
36315
|
form: "single",
|
|
36107
36316
|
optional: false
|
|
36108
36317
|
}],
|
|
36318
|
+
"zoneAnalytics.getCurrentSnapshotBatch": [{
|
|
36319
|
+
name: "deviceIds",
|
|
36320
|
+
form: "array",
|
|
36321
|
+
optional: false
|
|
36322
|
+
}],
|
|
36109
36323
|
"zoneAnalytics.getUnzonedHistory": [{
|
|
36110
36324
|
name: "deviceId",
|
|
36111
36325
|
form: "single",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-smtp-nodemailer",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.48",
|
|
4
4
|
"description": "SMTP email provider addon for CamStack — wraps `nodemailer` and registers a `smtp-provider` cap collection entry. Used by magic-link login + notifier addons.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|