@camstack/addon-provider-hikvision 1.2.49 → 1.2.51
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 +154 -19
- package/dist/addon.mjs +154 -19
- package/package.json +1 -1
package/dist/addon.js
CHANGED
|
@@ -8034,18 +8034,61 @@ var RelocateFootageInputSchema = object({
|
|
|
8034
8034
|
* `RecordingConfig.enabled` or camera wrapper bindings. */
|
|
8035
8035
|
var StorageMigrationLeaseInputSchema = object({ leaseId: string().min(1) });
|
|
8036
8036
|
var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: string().min(1) });
|
|
8037
|
+
/**
|
|
8038
|
+
* What a `relocateMedia` pass DOES. One engine, three passes — never a second
|
|
8039
|
+
* mover (the engine already walks both collections with a timestamp cursor and
|
|
8040
|
+
* already has a stamp-without-copy path).
|
|
8041
|
+
*
|
|
8042
|
+
* - `move` — the default and the historical behaviour: event-media and
|
|
8043
|
+
* retrain blobs move to `toLocationId` and their rows are
|
|
8044
|
+
* stamped. The enrolled gallery is skipped (D197).
|
|
8045
|
+
* - `seal` — ROWS ONLY, no bytes. Every row whose `locationId` is NULL is
|
|
8046
|
+
* stamped with `toLocationId`. `toLocationId` here is the id the
|
|
8047
|
+
* bytes ALREADY sit on — today's `eventMedia` default — because
|
|
8048
|
+
* a NULL row means "wherever `eventMedia` points *now*", and the
|
|
8049
|
+
* instant a repoint moves that pointer the row reads from the
|
|
8050
|
+
* new disk while its bytes are on the old one.
|
|
8051
|
+
* - `gallery` — the inverse selection of `move`: ONLY the retention-exempt
|
|
8052
|
+
* (enrolled-gallery) rows, which `move` deliberately skips.
|
|
8053
|
+
* `galleryMedia` is `cardinality: 'single'`, so this pass can
|
|
8054
|
+
* never run beside a live second location: it is stop-the-world
|
|
8055
|
+
* by construction, which is acceptable only because the gallery
|
|
8056
|
+
* is a few KB per enrolled sample.
|
|
8057
|
+
*/
|
|
8058
|
+
var MediaRelocateModeSchema = _enum([
|
|
8059
|
+
"move",
|
|
8060
|
+
"seal",
|
|
8061
|
+
"gallery"
|
|
8062
|
+
]);
|
|
8037
8063
|
var RelocateMediaInputSchema = object({
|
|
8038
8064
|
toLocationId: string(),
|
|
8039
|
-
throttleMbps: number().min(1).max(1e3).optional()
|
|
8065
|
+
throttleMbps: number().min(1).max(1e3).optional(),
|
|
8066
|
+
/** Omitted = `move`, the pre-existing behaviour. */
|
|
8067
|
+
mode: MediaRelocateModeSchema.optional()
|
|
8068
|
+
});
|
|
8069
|
+
/** How many rows still carry NO `locationId` — the population a repoint would
|
|
8070
|
+
* silently re-aim at a disk that does not hold their bytes. Zero is the only
|
|
8071
|
+
* value that permits a non-blocking `eventMedia` cutover. */
|
|
8072
|
+
var UnstampedEventMediaCountSchema = object({
|
|
8073
|
+
media: number().int().nonnegative(),
|
|
8074
|
+
retrainFrames: number().int().nonnegative(),
|
|
8075
|
+
total: number().int().nonnegative()
|
|
8040
8076
|
});
|
|
8041
8077
|
var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: string().min(1) });
|
|
8042
|
-
/** The independently selectable logical storage classes
|
|
8043
|
-
*
|
|
8044
|
-
*
|
|
8078
|
+
/** The independently selectable logical storage classes — every class
|
|
8079
|
+
* `storage.listLocationDeclarations` reports, so an operator never meets a
|
|
8080
|
+
* Zod enum error where they should meet an explanation.
|
|
8081
|
+
*
|
|
8082
|
+
* `recordings` encompasses the high and mid segment profiles; `recordingsLow`
|
|
8083
|
+
* is low segments; `eventMedia` is post-analysis blobs; `galleryMedia` is the
|
|
8084
|
+
* enrolled gallery; `backups` is the system backup archive. The last two have
|
|
8085
|
+
* their own rules — see {@link StorageMigrationFindingCodeSchema}. */
|
|
8045
8086
|
var StorageMigrationClassSchema = _enum([
|
|
8046
8087
|
"recordings",
|
|
8047
8088
|
"recordingsLow",
|
|
8048
|
-
"eventMedia"
|
|
8089
|
+
"eventMedia",
|
|
8090
|
+
"backups",
|
|
8091
|
+
"galleryMedia"
|
|
8049
8092
|
]);
|
|
8050
8093
|
/** A destination is always an existing, fully-qualified location id. The
|
|
8051
8094
|
* migration API intentionally never changes a source location's `basePath`:
|
|
@@ -8053,20 +8096,56 @@ var StorageMigrationClassSchema = _enum([
|
|
|
8053
8096
|
var StorageMigrationDestinationsSchema = object({
|
|
8054
8097
|
recordings: string().min(1).optional(),
|
|
8055
8098
|
recordingsLow: string().min(1).optional(),
|
|
8056
|
-
eventMedia: string().min(1).optional()
|
|
8099
|
+
eventMedia: string().min(1).optional(),
|
|
8100
|
+
backups: string().min(1).optional(),
|
|
8101
|
+
galleryMedia: string().min(1).optional()
|
|
8057
8102
|
}).refine((value) => Object.keys(value).length > 0, { message: "select at least one storage class" });
|
|
8103
|
+
/**
|
|
8104
|
+
* How a migration sequences the cutover against the byte move.
|
|
8105
|
+
*
|
|
8106
|
+
* - `blocking` — the historical order: pause, move every byte, repoint,
|
|
8107
|
+
* resume. Recording is stopped for the whole move. Right
|
|
8108
|
+
* for a small or a cold class, and the only legal mode for
|
|
8109
|
+
* a `cardinality: 'single'` class.
|
|
8110
|
+
* - `nonBlocking` — repoint FIRST, drain behind: seal, pause, repoint,
|
|
8111
|
+
* refresh, resume, then move the past with everything
|
|
8112
|
+
* running. The pause is three bounded instants (a detach +
|
|
8113
|
+
* attach round, a write-gate drain, a lease) instead of one
|
|
8114
|
+
* bounded by bytes. 1.09 TB at 7–14 MB/s is thirty hours of
|
|
8115
|
+
* stopped recording under `blocking`; the same move is
|
|
8116
|
+
* seconds of stopped recording under `nonBlocking`.
|
|
8117
|
+
*
|
|
8118
|
+
* The mode is on the JOB, not only on the input, because `status` is where an
|
|
8119
|
+
* operator finds out which one is running.
|
|
8120
|
+
*/
|
|
8121
|
+
var StorageMigrationModeSchema = _enum(["blocking", "nonBlocking"]);
|
|
8058
8122
|
/** Shared input for planning and starting an orchestrated storage migration. */
|
|
8059
8123
|
var StorageMigrationInputSchema = object({
|
|
8060
8124
|
destinations: StorageMigrationDestinationsSchema,
|
|
8061
|
-
throttleMbps: number().min(1).max(1e3).optional()
|
|
8125
|
+
throttleMbps: number().min(1).max(1e3).optional(),
|
|
8126
|
+
/** Omitted = `blocking`, which stays the default. */
|
|
8127
|
+
mode: StorageMigrationModeSchema.optional()
|
|
8062
8128
|
});
|
|
8063
|
-
/**
|
|
8064
|
-
*
|
|
8065
|
-
*
|
|
8129
|
+
/**
|
|
8130
|
+
* The durable coordinator state machine.
|
|
8131
|
+
*
|
|
8132
|
+
* `blocking`:
|
|
8133
|
+
* planning → pausing → moving → verifying → repointing → refreshing → resuming → done
|
|
8134
|
+
*
|
|
8135
|
+
* `nonBlocking`:
|
|
8136
|
+
* planning → sealing → pausing → repointing → refreshing → resuming → draining → verifying → done
|
|
8137
|
+
*
|
|
8138
|
+
* Same phases, different order plus two new ones — not a second mover.
|
|
8139
|
+
* `sealing` closes the `eventMedia` NULL-row hole BEFORE anything is paused;
|
|
8140
|
+
* `draining` runs the same movers UNLEASED, after every writer is back up.
|
|
8141
|
+
* `repointing` is still the only phase that changes a default location.
|
|
8142
|
+
*/
|
|
8066
8143
|
var StorageMigrationPhaseSchema = _enum([
|
|
8067
8144
|
"planning",
|
|
8145
|
+
"sealing",
|
|
8068
8146
|
"pausing",
|
|
8069
8147
|
"moving",
|
|
8148
|
+
"draining",
|
|
8070
8149
|
"verifying",
|
|
8071
8150
|
"repointing",
|
|
8072
8151
|
"refreshing",
|
|
@@ -8091,6 +8170,9 @@ var StorageMigrationMoveSchema = object({
|
|
|
8091
8170
|
var StorageMigrationJobSchema = object({
|
|
8092
8171
|
jobId: string(),
|
|
8093
8172
|
phase: StorageMigrationPhaseSchema,
|
|
8173
|
+
/** Which order this job is running. `status` is the only place an operator
|
|
8174
|
+
* can tell a seconds-long cutover from a thirty-hour one. */
|
|
8175
|
+
mode: StorageMigrationModeSchema,
|
|
8094
8176
|
destinations: StorageMigrationDestinationsSchema,
|
|
8095
8177
|
throttleMbps: number(),
|
|
8096
8178
|
moves: array(StorageMigrationMoveSchema),
|
|
@@ -8103,13 +8185,30 @@ var StorageMigrationJobSchema = object({
|
|
|
8103
8185
|
finishedAt: number().nullable(),
|
|
8104
8186
|
error: string().nullable()
|
|
8105
8187
|
});
|
|
8188
|
+
var StorageMigrationFindingSchema = object({
|
|
8189
|
+
code: _enum([
|
|
8190
|
+
"sharesDeviceWithSource",
|
|
8191
|
+
"deviceIdentityUnknown",
|
|
8192
|
+
"unstampedEventMediaRows",
|
|
8193
|
+
"blockingOnly",
|
|
8194
|
+
"noMover"
|
|
8195
|
+
]),
|
|
8196
|
+
storageClass: StorageMigrationClassSchema,
|
|
8197
|
+
/** Human-readable, already carrying the ids and counts. */
|
|
8198
|
+
message: string()
|
|
8199
|
+
});
|
|
8106
8200
|
var StorageMigrationPlanSchema = object({
|
|
8107
8201
|
destinations: StorageMigrationDestinationsSchema,
|
|
8202
|
+
/** The mode this plan was built for. A plan is only valid for its mode: the
|
|
8203
|
+
* `eventMedia` seal gate and the single-cardinality refusal both depend on
|
|
8204
|
+
* it. */
|
|
8205
|
+
mode: StorageMigrationModeSchema,
|
|
8108
8206
|
moves: array(object({
|
|
8109
8207
|
storageClass: StorageMigrationClassSchema,
|
|
8110
8208
|
fromLocationId: string(),
|
|
8111
8209
|
toLocationId: string()
|
|
8112
|
-
}))
|
|
8210
|
+
})),
|
|
8211
|
+
findings: array(StorageMigrationFindingSchema)
|
|
8113
8212
|
});
|
|
8114
8213
|
/**
|
|
8115
8214
|
* `StorageLocationType` — an addon-declared id that identifies the *kind* of
|
|
@@ -19274,7 +19373,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
19274
19373
|
}), method(RelocateMediaInputSchema, object({ jobId: string() }), {
|
|
19275
19374
|
kind: "mutation",
|
|
19276
19375
|
auth: "admin"
|
|
19277
|
-
}), method(object({}), array(RelocateJobSchema).readonly(), {
|
|
19376
|
+
}), method(object({}), UnstampedEventMediaCountSchema, { auth: "admin" }), method(object({}), array(RelocateJobSchema).readonly(), {
|
|
19278
19377
|
kind: "query",
|
|
19279
19378
|
auth: "admin"
|
|
19280
19379
|
}), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
@@ -21285,7 +21384,10 @@ method(object({
|
|
|
21285
21384
|
}), StorageLocationSchema, {
|
|
21286
21385
|
kind: "mutation",
|
|
21287
21386
|
auth: "admin"
|
|
21288
|
-
}), method(object({
|
|
21387
|
+
}), method(object({
|
|
21388
|
+
id: string(),
|
|
21389
|
+
force: boolean().optional()
|
|
21390
|
+
}), _void(), {
|
|
21289
21391
|
kind: "mutation",
|
|
21290
21392
|
auth: "admin"
|
|
21291
21393
|
}), method(object({ id: string() }), object({
|
|
@@ -25353,6 +25455,33 @@ var intercomCapability = {
|
|
|
25353
25455
|
deviceNative: true,
|
|
25354
25456
|
mode: "singleton",
|
|
25355
25457
|
deviceTypes: [DeviceType.Camera],
|
|
25458
|
+
/**
|
|
25459
|
+
* **Auth tier: `protected` on every method — deliberate, and load-bearing.**
|
|
25460
|
+
*
|
|
25461
|
+
* Talking through a camera is an OPERATE action, not a CONFIGURE one. This
|
|
25462
|
+
* cap has no configuration surface at all: all six methods open, feed and
|
|
25463
|
+
* close one live audio session against one `deviceId`. That is the same
|
|
25464
|
+
* authority as `ptz.move` or `snapshot.getSnapshot`, both `protected` — and
|
|
25465
|
+
* the opposite of `ptz.savePreset` / `snapshot.invalidateCache`, which are
|
|
25466
|
+
* `admin` because they change what the device IS.
|
|
25467
|
+
*
|
|
25468
|
+
* `protected` does not mean ungated: `protectedProcedure` runs the
|
|
25469
|
+
* `METHOD_ACCESS_MAP` scope check, and every method here is `scope: 'device'`
|
|
25470
|
+
* with `access: 'create'` and a `deviceId` in its input. So a caller needs a
|
|
25471
|
+
* grant that covers THAT camera at `create` — a `camera-viewer` (`view`
|
|
25472
|
+
* only) still cannot talk, and a grant on camera 5 cannot talk through
|
|
25473
|
+
* camera 7.
|
|
25474
|
+
*
|
|
25475
|
+
* Every method was `auth: 'admin'` from the initial commit, which made the
|
|
25476
|
+
* cap unreachable by every non-admin principal — `adminProcedure` throws
|
|
25477
|
+
* `FORBIDDEN: Admin required` BEFORE the scope check runs, so the scope
|
|
25478
|
+
* machinery generated for this cap (`METHOD_ACCESS_MAP`,
|
|
25479
|
+
* `DEVICE_SCOPED_CAPS`, `METHOD_DEVICE_SELECTORS`) was complete and dead. The
|
|
25480
|
+
* `camera-operator` scope preset has promised "PTZ control, intercom,
|
|
25481
|
+
* snapshots" since that same commit; the promise could not be kept. Recorded
|
|
25482
|
+
* as D289; `scripts/check-scope-preset-promises.ts` now fails the build if a
|
|
25483
|
+
* preset promises a cap no row of that preset can reach.
|
|
25484
|
+
*/
|
|
25356
25485
|
methods: {
|
|
25357
25486
|
/**
|
|
25358
25487
|
* Open a server-side WebRTC audio-only session. Returns an SDP
|
|
@@ -25365,7 +25494,7 @@ var intercomCapability = {
|
|
|
25365
25494
|
sdpOffer: string()
|
|
25366
25495
|
}), {
|
|
25367
25496
|
kind: "mutation",
|
|
25368
|
-
auth: "
|
|
25497
|
+
auth: "protected"
|
|
25369
25498
|
}),
|
|
25370
25499
|
handleAnswer: method(object({
|
|
25371
25500
|
deviceId: number(),
|
|
@@ -25373,7 +25502,7 @@ var intercomCapability = {
|
|
|
25373
25502
|
sdpAnswer: string()
|
|
25374
25503
|
}), _void(), {
|
|
25375
25504
|
kind: "mutation",
|
|
25376
|
-
auth: "
|
|
25505
|
+
auth: "protected"
|
|
25377
25506
|
}),
|
|
25378
25507
|
/** Close explicitly. Server also auto-closes on 30s idle. */
|
|
25379
25508
|
stopSession: method(object({
|
|
@@ -25381,7 +25510,7 @@ var intercomCapability = {
|
|
|
25381
25510
|
sessionId: string()
|
|
25382
25511
|
}), _void(), {
|
|
25383
25512
|
kind: "mutation",
|
|
25384
|
-
auth: "
|
|
25513
|
+
auth: "protected"
|
|
25385
25514
|
}),
|
|
25386
25515
|
/**
|
|
25387
25516
|
* Open a raw-PCM talk session (no WebRTC SDP plumbing). Used by
|
|
@@ -25394,7 +25523,7 @@ var intercomCapability = {
|
|
|
25394
25523
|
*/
|
|
25395
25524
|
startTalkSession: method(object({ deviceId: number() }), object({ sessionId: string() }), {
|
|
25396
25525
|
kind: "mutation",
|
|
25397
|
-
auth: "
|
|
25526
|
+
auth: "protected"
|
|
25398
25527
|
}),
|
|
25399
25528
|
/**
|
|
25400
25529
|
* Push one chunk of talk-back audio onto the active talk session.
|
|
@@ -25429,12 +25558,12 @@ var intercomCapability = {
|
|
|
25429
25558
|
sequenceNumber: number().int()
|
|
25430
25559
|
}), object({ accepted: boolean() }), {
|
|
25431
25560
|
kind: "mutation",
|
|
25432
|
-
auth: "
|
|
25561
|
+
auth: "protected"
|
|
25433
25562
|
}),
|
|
25434
25563
|
/** Close the raw-PCM talk session. Idempotent. */
|
|
25435
25564
|
endTalkSession: method(object({ deviceId: number() }), _void(), {
|
|
25436
25565
|
kind: "mutation",
|
|
25437
|
-
auth: "
|
|
25566
|
+
auth: "protected"
|
|
25438
25567
|
})
|
|
25439
25568
|
},
|
|
25440
25569
|
events: { onStatusChanged: { data: object({
|
|
@@ -35679,6 +35808,12 @@ Object.freeze({
|
|
|
35679
35808
|
addonId: null,
|
|
35680
35809
|
access: "create"
|
|
35681
35810
|
},
|
|
35811
|
+
"pipelineAnalytics.countUnstampedEventMedia": {
|
|
35812
|
+
capName: "pipeline-analytics",
|
|
35813
|
+
capScope: "device",
|
|
35814
|
+
addonId: null,
|
|
35815
|
+
access: "view"
|
|
35816
|
+
},
|
|
35682
35817
|
"pipelineAnalytics.deleteDeviceEvents": {
|
|
35683
35818
|
capName: "pipeline-analytics",
|
|
35684
35819
|
capScope: "device",
|
package/dist/addon.mjs
CHANGED
|
@@ -8035,18 +8035,61 @@ var RelocateFootageInputSchema = object({
|
|
|
8035
8035
|
* `RecordingConfig.enabled` or camera wrapper bindings. */
|
|
8036
8036
|
var StorageMigrationLeaseInputSchema = object({ leaseId: string().min(1) });
|
|
8037
8037
|
var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: string().min(1) });
|
|
8038
|
+
/**
|
|
8039
|
+
* What a `relocateMedia` pass DOES. One engine, three passes — never a second
|
|
8040
|
+
* mover (the engine already walks both collections with a timestamp cursor and
|
|
8041
|
+
* already has a stamp-without-copy path).
|
|
8042
|
+
*
|
|
8043
|
+
* - `move` — the default and the historical behaviour: event-media and
|
|
8044
|
+
* retrain blobs move to `toLocationId` and their rows are
|
|
8045
|
+
* stamped. The enrolled gallery is skipped (D197).
|
|
8046
|
+
* - `seal` — ROWS ONLY, no bytes. Every row whose `locationId` is NULL is
|
|
8047
|
+
* stamped with `toLocationId`. `toLocationId` here is the id the
|
|
8048
|
+
* bytes ALREADY sit on — today's `eventMedia` default — because
|
|
8049
|
+
* a NULL row means "wherever `eventMedia` points *now*", and the
|
|
8050
|
+
* instant a repoint moves that pointer the row reads from the
|
|
8051
|
+
* new disk while its bytes are on the old one.
|
|
8052
|
+
* - `gallery` — the inverse selection of `move`: ONLY the retention-exempt
|
|
8053
|
+
* (enrolled-gallery) rows, which `move` deliberately skips.
|
|
8054
|
+
* `galleryMedia` is `cardinality: 'single'`, so this pass can
|
|
8055
|
+
* never run beside a live second location: it is stop-the-world
|
|
8056
|
+
* by construction, which is acceptable only because the gallery
|
|
8057
|
+
* is a few KB per enrolled sample.
|
|
8058
|
+
*/
|
|
8059
|
+
var MediaRelocateModeSchema = _enum([
|
|
8060
|
+
"move",
|
|
8061
|
+
"seal",
|
|
8062
|
+
"gallery"
|
|
8063
|
+
]);
|
|
8038
8064
|
var RelocateMediaInputSchema = object({
|
|
8039
8065
|
toLocationId: string(),
|
|
8040
|
-
throttleMbps: number().min(1).max(1e3).optional()
|
|
8066
|
+
throttleMbps: number().min(1).max(1e3).optional(),
|
|
8067
|
+
/** Omitted = `move`, the pre-existing behaviour. */
|
|
8068
|
+
mode: MediaRelocateModeSchema.optional()
|
|
8069
|
+
});
|
|
8070
|
+
/** How many rows still carry NO `locationId` — the population a repoint would
|
|
8071
|
+
* silently re-aim at a disk that does not hold their bytes. Zero is the only
|
|
8072
|
+
* value that permits a non-blocking `eventMedia` cutover. */
|
|
8073
|
+
var UnstampedEventMediaCountSchema = object({
|
|
8074
|
+
media: number().int().nonnegative(),
|
|
8075
|
+
retrainFrames: number().int().nonnegative(),
|
|
8076
|
+
total: number().int().nonnegative()
|
|
8041
8077
|
});
|
|
8042
8078
|
var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: string().min(1) });
|
|
8043
|
-
/** The independently selectable logical storage classes
|
|
8044
|
-
*
|
|
8045
|
-
*
|
|
8079
|
+
/** The independently selectable logical storage classes — every class
|
|
8080
|
+
* `storage.listLocationDeclarations` reports, so an operator never meets a
|
|
8081
|
+
* Zod enum error where they should meet an explanation.
|
|
8082
|
+
*
|
|
8083
|
+
* `recordings` encompasses the high and mid segment profiles; `recordingsLow`
|
|
8084
|
+
* is low segments; `eventMedia` is post-analysis blobs; `galleryMedia` is the
|
|
8085
|
+
* enrolled gallery; `backups` is the system backup archive. The last two have
|
|
8086
|
+
* their own rules — see {@link StorageMigrationFindingCodeSchema}. */
|
|
8046
8087
|
var StorageMigrationClassSchema = _enum([
|
|
8047
8088
|
"recordings",
|
|
8048
8089
|
"recordingsLow",
|
|
8049
|
-
"eventMedia"
|
|
8090
|
+
"eventMedia",
|
|
8091
|
+
"backups",
|
|
8092
|
+
"galleryMedia"
|
|
8050
8093
|
]);
|
|
8051
8094
|
/** A destination is always an existing, fully-qualified location id. The
|
|
8052
8095
|
* migration API intentionally never changes a source location's `basePath`:
|
|
@@ -8054,20 +8097,56 @@ var StorageMigrationClassSchema = _enum([
|
|
|
8054
8097
|
var StorageMigrationDestinationsSchema = object({
|
|
8055
8098
|
recordings: string().min(1).optional(),
|
|
8056
8099
|
recordingsLow: string().min(1).optional(),
|
|
8057
|
-
eventMedia: string().min(1).optional()
|
|
8100
|
+
eventMedia: string().min(1).optional(),
|
|
8101
|
+
backups: string().min(1).optional(),
|
|
8102
|
+
galleryMedia: string().min(1).optional()
|
|
8058
8103
|
}).refine((value) => Object.keys(value).length > 0, { message: "select at least one storage class" });
|
|
8104
|
+
/**
|
|
8105
|
+
* How a migration sequences the cutover against the byte move.
|
|
8106
|
+
*
|
|
8107
|
+
* - `blocking` — the historical order: pause, move every byte, repoint,
|
|
8108
|
+
* resume. Recording is stopped for the whole move. Right
|
|
8109
|
+
* for a small or a cold class, and the only legal mode for
|
|
8110
|
+
* a `cardinality: 'single'` class.
|
|
8111
|
+
* - `nonBlocking` — repoint FIRST, drain behind: seal, pause, repoint,
|
|
8112
|
+
* refresh, resume, then move the past with everything
|
|
8113
|
+
* running. The pause is three bounded instants (a detach +
|
|
8114
|
+
* attach round, a write-gate drain, a lease) instead of one
|
|
8115
|
+
* bounded by bytes. 1.09 TB at 7–14 MB/s is thirty hours of
|
|
8116
|
+
* stopped recording under `blocking`; the same move is
|
|
8117
|
+
* seconds of stopped recording under `nonBlocking`.
|
|
8118
|
+
*
|
|
8119
|
+
* The mode is on the JOB, not only on the input, because `status` is where an
|
|
8120
|
+
* operator finds out which one is running.
|
|
8121
|
+
*/
|
|
8122
|
+
var StorageMigrationModeSchema = _enum(["blocking", "nonBlocking"]);
|
|
8059
8123
|
/** Shared input for planning and starting an orchestrated storage migration. */
|
|
8060
8124
|
var StorageMigrationInputSchema = object({
|
|
8061
8125
|
destinations: StorageMigrationDestinationsSchema,
|
|
8062
|
-
throttleMbps: number().min(1).max(1e3).optional()
|
|
8126
|
+
throttleMbps: number().min(1).max(1e3).optional(),
|
|
8127
|
+
/** Omitted = `blocking`, which stays the default. */
|
|
8128
|
+
mode: StorageMigrationModeSchema.optional()
|
|
8063
8129
|
});
|
|
8064
|
-
/**
|
|
8065
|
-
*
|
|
8066
|
-
*
|
|
8130
|
+
/**
|
|
8131
|
+
* The durable coordinator state machine.
|
|
8132
|
+
*
|
|
8133
|
+
* `blocking`:
|
|
8134
|
+
* planning → pausing → moving → verifying → repointing → refreshing → resuming → done
|
|
8135
|
+
*
|
|
8136
|
+
* `nonBlocking`:
|
|
8137
|
+
* planning → sealing → pausing → repointing → refreshing → resuming → draining → verifying → done
|
|
8138
|
+
*
|
|
8139
|
+
* Same phases, different order plus two new ones — not a second mover.
|
|
8140
|
+
* `sealing` closes the `eventMedia` NULL-row hole BEFORE anything is paused;
|
|
8141
|
+
* `draining` runs the same movers UNLEASED, after every writer is back up.
|
|
8142
|
+
* `repointing` is still the only phase that changes a default location.
|
|
8143
|
+
*/
|
|
8067
8144
|
var StorageMigrationPhaseSchema = _enum([
|
|
8068
8145
|
"planning",
|
|
8146
|
+
"sealing",
|
|
8069
8147
|
"pausing",
|
|
8070
8148
|
"moving",
|
|
8149
|
+
"draining",
|
|
8071
8150
|
"verifying",
|
|
8072
8151
|
"repointing",
|
|
8073
8152
|
"refreshing",
|
|
@@ -8092,6 +8171,9 @@ var StorageMigrationMoveSchema = object({
|
|
|
8092
8171
|
var StorageMigrationJobSchema = object({
|
|
8093
8172
|
jobId: string(),
|
|
8094
8173
|
phase: StorageMigrationPhaseSchema,
|
|
8174
|
+
/** Which order this job is running. `status` is the only place an operator
|
|
8175
|
+
* can tell a seconds-long cutover from a thirty-hour one. */
|
|
8176
|
+
mode: StorageMigrationModeSchema,
|
|
8095
8177
|
destinations: StorageMigrationDestinationsSchema,
|
|
8096
8178
|
throttleMbps: number(),
|
|
8097
8179
|
moves: array(StorageMigrationMoveSchema),
|
|
@@ -8104,13 +8186,30 @@ var StorageMigrationJobSchema = object({
|
|
|
8104
8186
|
finishedAt: number().nullable(),
|
|
8105
8187
|
error: string().nullable()
|
|
8106
8188
|
});
|
|
8189
|
+
var StorageMigrationFindingSchema = object({
|
|
8190
|
+
code: _enum([
|
|
8191
|
+
"sharesDeviceWithSource",
|
|
8192
|
+
"deviceIdentityUnknown",
|
|
8193
|
+
"unstampedEventMediaRows",
|
|
8194
|
+
"blockingOnly",
|
|
8195
|
+
"noMover"
|
|
8196
|
+
]),
|
|
8197
|
+
storageClass: StorageMigrationClassSchema,
|
|
8198
|
+
/** Human-readable, already carrying the ids and counts. */
|
|
8199
|
+
message: string()
|
|
8200
|
+
});
|
|
8107
8201
|
var StorageMigrationPlanSchema = object({
|
|
8108
8202
|
destinations: StorageMigrationDestinationsSchema,
|
|
8203
|
+
/** The mode this plan was built for. A plan is only valid for its mode: the
|
|
8204
|
+
* `eventMedia` seal gate and the single-cardinality refusal both depend on
|
|
8205
|
+
* it. */
|
|
8206
|
+
mode: StorageMigrationModeSchema,
|
|
8109
8207
|
moves: array(object({
|
|
8110
8208
|
storageClass: StorageMigrationClassSchema,
|
|
8111
8209
|
fromLocationId: string(),
|
|
8112
8210
|
toLocationId: string()
|
|
8113
|
-
}))
|
|
8211
|
+
})),
|
|
8212
|
+
findings: array(StorageMigrationFindingSchema)
|
|
8114
8213
|
});
|
|
8115
8214
|
/**
|
|
8116
8215
|
* `StorageLocationType` — an addon-declared id that identifies the *kind* of
|
|
@@ -19275,7 +19374,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
19275
19374
|
}), method(RelocateMediaInputSchema, object({ jobId: string() }), {
|
|
19276
19375
|
kind: "mutation",
|
|
19277
19376
|
auth: "admin"
|
|
19278
|
-
}), method(object({}), array(RelocateJobSchema).readonly(), {
|
|
19377
|
+
}), method(object({}), UnstampedEventMediaCountSchema, { auth: "admin" }), method(object({}), array(RelocateJobSchema).readonly(), {
|
|
19279
19378
|
kind: "query",
|
|
19280
19379
|
auth: "admin"
|
|
19281
19380
|
}), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
@@ -21286,7 +21385,10 @@ method(object({
|
|
|
21286
21385
|
}), StorageLocationSchema, {
|
|
21287
21386
|
kind: "mutation",
|
|
21288
21387
|
auth: "admin"
|
|
21289
|
-
}), method(object({
|
|
21388
|
+
}), method(object({
|
|
21389
|
+
id: string(),
|
|
21390
|
+
force: boolean().optional()
|
|
21391
|
+
}), _void(), {
|
|
21290
21392
|
kind: "mutation",
|
|
21291
21393
|
auth: "admin"
|
|
21292
21394
|
}), method(object({ id: string() }), object({
|
|
@@ -25354,6 +25456,33 @@ var intercomCapability = {
|
|
|
25354
25456
|
deviceNative: true,
|
|
25355
25457
|
mode: "singleton",
|
|
25356
25458
|
deviceTypes: [DeviceType.Camera],
|
|
25459
|
+
/**
|
|
25460
|
+
* **Auth tier: `protected` on every method — deliberate, and load-bearing.**
|
|
25461
|
+
*
|
|
25462
|
+
* Talking through a camera is an OPERATE action, not a CONFIGURE one. This
|
|
25463
|
+
* cap has no configuration surface at all: all six methods open, feed and
|
|
25464
|
+
* close one live audio session against one `deviceId`. That is the same
|
|
25465
|
+
* authority as `ptz.move` or `snapshot.getSnapshot`, both `protected` — and
|
|
25466
|
+
* the opposite of `ptz.savePreset` / `snapshot.invalidateCache`, which are
|
|
25467
|
+
* `admin` because they change what the device IS.
|
|
25468
|
+
*
|
|
25469
|
+
* `protected` does not mean ungated: `protectedProcedure` runs the
|
|
25470
|
+
* `METHOD_ACCESS_MAP` scope check, and every method here is `scope: 'device'`
|
|
25471
|
+
* with `access: 'create'` and a `deviceId` in its input. So a caller needs a
|
|
25472
|
+
* grant that covers THAT camera at `create` — a `camera-viewer` (`view`
|
|
25473
|
+
* only) still cannot talk, and a grant on camera 5 cannot talk through
|
|
25474
|
+
* camera 7.
|
|
25475
|
+
*
|
|
25476
|
+
* Every method was `auth: 'admin'` from the initial commit, which made the
|
|
25477
|
+
* cap unreachable by every non-admin principal — `adminProcedure` throws
|
|
25478
|
+
* `FORBIDDEN: Admin required` BEFORE the scope check runs, so the scope
|
|
25479
|
+
* machinery generated for this cap (`METHOD_ACCESS_MAP`,
|
|
25480
|
+
* `DEVICE_SCOPED_CAPS`, `METHOD_DEVICE_SELECTORS`) was complete and dead. The
|
|
25481
|
+
* `camera-operator` scope preset has promised "PTZ control, intercom,
|
|
25482
|
+
* snapshots" since that same commit; the promise could not be kept. Recorded
|
|
25483
|
+
* as D289; `scripts/check-scope-preset-promises.ts` now fails the build if a
|
|
25484
|
+
* preset promises a cap no row of that preset can reach.
|
|
25485
|
+
*/
|
|
25357
25486
|
methods: {
|
|
25358
25487
|
/**
|
|
25359
25488
|
* Open a server-side WebRTC audio-only session. Returns an SDP
|
|
@@ -25366,7 +25495,7 @@ var intercomCapability = {
|
|
|
25366
25495
|
sdpOffer: string()
|
|
25367
25496
|
}), {
|
|
25368
25497
|
kind: "mutation",
|
|
25369
|
-
auth: "
|
|
25498
|
+
auth: "protected"
|
|
25370
25499
|
}),
|
|
25371
25500
|
handleAnswer: method(object({
|
|
25372
25501
|
deviceId: number(),
|
|
@@ -25374,7 +25503,7 @@ var intercomCapability = {
|
|
|
25374
25503
|
sdpAnswer: string()
|
|
25375
25504
|
}), _void(), {
|
|
25376
25505
|
kind: "mutation",
|
|
25377
|
-
auth: "
|
|
25506
|
+
auth: "protected"
|
|
25378
25507
|
}),
|
|
25379
25508
|
/** Close explicitly. Server also auto-closes on 30s idle. */
|
|
25380
25509
|
stopSession: method(object({
|
|
@@ -25382,7 +25511,7 @@ var intercomCapability = {
|
|
|
25382
25511
|
sessionId: string()
|
|
25383
25512
|
}), _void(), {
|
|
25384
25513
|
kind: "mutation",
|
|
25385
|
-
auth: "
|
|
25514
|
+
auth: "protected"
|
|
25386
25515
|
}),
|
|
25387
25516
|
/**
|
|
25388
25517
|
* Open a raw-PCM talk session (no WebRTC SDP plumbing). Used by
|
|
@@ -25395,7 +25524,7 @@ var intercomCapability = {
|
|
|
25395
25524
|
*/
|
|
25396
25525
|
startTalkSession: method(object({ deviceId: number() }), object({ sessionId: string() }), {
|
|
25397
25526
|
kind: "mutation",
|
|
25398
|
-
auth: "
|
|
25527
|
+
auth: "protected"
|
|
25399
25528
|
}),
|
|
25400
25529
|
/**
|
|
25401
25530
|
* Push one chunk of talk-back audio onto the active talk session.
|
|
@@ -25430,12 +25559,12 @@ var intercomCapability = {
|
|
|
25430
25559
|
sequenceNumber: number().int()
|
|
25431
25560
|
}), object({ accepted: boolean() }), {
|
|
25432
25561
|
kind: "mutation",
|
|
25433
|
-
auth: "
|
|
25562
|
+
auth: "protected"
|
|
25434
25563
|
}),
|
|
25435
25564
|
/** Close the raw-PCM talk session. Idempotent. */
|
|
25436
25565
|
endTalkSession: method(object({ deviceId: number() }), _void(), {
|
|
25437
25566
|
kind: "mutation",
|
|
25438
|
-
auth: "
|
|
25567
|
+
auth: "protected"
|
|
25439
25568
|
})
|
|
25440
25569
|
},
|
|
25441
25570
|
events: { onStatusChanged: { data: object({
|
|
@@ -35680,6 +35809,12 @@ Object.freeze({
|
|
|
35680
35809
|
addonId: null,
|
|
35681
35810
|
access: "create"
|
|
35682
35811
|
},
|
|
35812
|
+
"pipelineAnalytics.countUnstampedEventMedia": {
|
|
35813
|
+
capName: "pipeline-analytics",
|
|
35814
|
+
capScope: "device",
|
|
35815
|
+
addonId: null,
|
|
35816
|
+
access: "view"
|
|
35817
|
+
},
|
|
35683
35818
|
"pipelineAnalytics.deleteDeviceEvents": {
|
|
35684
35819
|
capName: "pipeline-analytics",
|
|
35685
35820
|
capScope: "device",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-provider-hikvision",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.51",
|
|
4
4
|
"description": "Hikvision camera device provider addon for CamStack — ISAPI over HTTP(S) with digest auth (snapshot, alarm stream, RTSP discovery)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|