@camstack/addon-provider-amcrest 0.2.42 → 0.2.44
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
|
@@ -8032,18 +8032,61 @@ var RelocateFootageInputSchema = object({
|
|
|
8032
8032
|
* `RecordingConfig.enabled` or camera wrapper bindings. */
|
|
8033
8033
|
var StorageMigrationLeaseInputSchema = object({ leaseId: string().min(1) });
|
|
8034
8034
|
var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: string().min(1) });
|
|
8035
|
+
/**
|
|
8036
|
+
* What a `relocateMedia` pass DOES. One engine, three passes — never a second
|
|
8037
|
+
* mover (the engine already walks both collections with a timestamp cursor and
|
|
8038
|
+
* already has a stamp-without-copy path).
|
|
8039
|
+
*
|
|
8040
|
+
* - `move` — the default and the historical behaviour: event-media and
|
|
8041
|
+
* retrain blobs move to `toLocationId` and their rows are
|
|
8042
|
+
* stamped. The enrolled gallery is skipped (D197).
|
|
8043
|
+
* - `seal` — ROWS ONLY, no bytes. Every row whose `locationId` is NULL is
|
|
8044
|
+
* stamped with `toLocationId`. `toLocationId` here is the id the
|
|
8045
|
+
* bytes ALREADY sit on — today's `eventMedia` default — because
|
|
8046
|
+
* a NULL row means "wherever `eventMedia` points *now*", and the
|
|
8047
|
+
* instant a repoint moves that pointer the row reads from the
|
|
8048
|
+
* new disk while its bytes are on the old one.
|
|
8049
|
+
* - `gallery` — the inverse selection of `move`: ONLY the retention-exempt
|
|
8050
|
+
* (enrolled-gallery) rows, which `move` deliberately skips.
|
|
8051
|
+
* `galleryMedia` is `cardinality: 'single'`, so this pass can
|
|
8052
|
+
* never run beside a live second location: it is stop-the-world
|
|
8053
|
+
* by construction, which is acceptable only because the gallery
|
|
8054
|
+
* is a few KB per enrolled sample.
|
|
8055
|
+
*/
|
|
8056
|
+
var MediaRelocateModeSchema = _enum([
|
|
8057
|
+
"move",
|
|
8058
|
+
"seal",
|
|
8059
|
+
"gallery"
|
|
8060
|
+
]);
|
|
8035
8061
|
var RelocateMediaInputSchema = object({
|
|
8036
8062
|
toLocationId: string(),
|
|
8037
|
-
throttleMbps: number().min(1).max(1e3).optional()
|
|
8063
|
+
throttleMbps: number().min(1).max(1e3).optional(),
|
|
8064
|
+
/** Omitted = `move`, the pre-existing behaviour. */
|
|
8065
|
+
mode: MediaRelocateModeSchema.optional()
|
|
8066
|
+
});
|
|
8067
|
+
/** How many rows still carry NO `locationId` — the population a repoint would
|
|
8068
|
+
* silently re-aim at a disk that does not hold their bytes. Zero is the only
|
|
8069
|
+
* value that permits a non-blocking `eventMedia` cutover. */
|
|
8070
|
+
var UnstampedEventMediaCountSchema = object({
|
|
8071
|
+
media: number().int().nonnegative(),
|
|
8072
|
+
retrainFrames: number().int().nonnegative(),
|
|
8073
|
+
total: number().int().nonnegative()
|
|
8038
8074
|
});
|
|
8039
8075
|
var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: string().min(1) });
|
|
8040
|
-
/** The independently selectable logical storage classes
|
|
8041
|
-
*
|
|
8042
|
-
*
|
|
8076
|
+
/** The independently selectable logical storage classes — every class
|
|
8077
|
+
* `storage.listLocationDeclarations` reports, so an operator never meets a
|
|
8078
|
+
* Zod enum error where they should meet an explanation.
|
|
8079
|
+
*
|
|
8080
|
+
* `recordings` encompasses the high and mid segment profiles; `recordingsLow`
|
|
8081
|
+
* is low segments; `eventMedia` is post-analysis blobs; `galleryMedia` is the
|
|
8082
|
+
* enrolled gallery; `backups` is the system backup archive. The last two have
|
|
8083
|
+
* their own rules — see {@link StorageMigrationFindingCodeSchema}. */
|
|
8043
8084
|
var StorageMigrationClassSchema = _enum([
|
|
8044
8085
|
"recordings",
|
|
8045
8086
|
"recordingsLow",
|
|
8046
|
-
"eventMedia"
|
|
8087
|
+
"eventMedia",
|
|
8088
|
+
"backups",
|
|
8089
|
+
"galleryMedia"
|
|
8047
8090
|
]);
|
|
8048
8091
|
/** A destination is always an existing, fully-qualified location id. The
|
|
8049
8092
|
* migration API intentionally never changes a source location's `basePath`:
|
|
@@ -8051,20 +8094,56 @@ var StorageMigrationClassSchema = _enum([
|
|
|
8051
8094
|
var StorageMigrationDestinationsSchema = object({
|
|
8052
8095
|
recordings: string().min(1).optional(),
|
|
8053
8096
|
recordingsLow: string().min(1).optional(),
|
|
8054
|
-
eventMedia: string().min(1).optional()
|
|
8097
|
+
eventMedia: string().min(1).optional(),
|
|
8098
|
+
backups: string().min(1).optional(),
|
|
8099
|
+
galleryMedia: string().min(1).optional()
|
|
8055
8100
|
}).refine((value) => Object.keys(value).length > 0, { message: "select at least one storage class" });
|
|
8101
|
+
/**
|
|
8102
|
+
* How a migration sequences the cutover against the byte move.
|
|
8103
|
+
*
|
|
8104
|
+
* - `blocking` — the historical order: pause, move every byte, repoint,
|
|
8105
|
+
* resume. Recording is stopped for the whole move. Right
|
|
8106
|
+
* for a small or a cold class, and the only legal mode for
|
|
8107
|
+
* a `cardinality: 'single'` class.
|
|
8108
|
+
* - `nonBlocking` — repoint FIRST, drain behind: seal, pause, repoint,
|
|
8109
|
+
* refresh, resume, then move the past with everything
|
|
8110
|
+
* running. The pause is three bounded instants (a detach +
|
|
8111
|
+
* attach round, a write-gate drain, a lease) instead of one
|
|
8112
|
+
* bounded by bytes. 1.09 TB at 7–14 MB/s is thirty hours of
|
|
8113
|
+
* stopped recording under `blocking`; the same move is
|
|
8114
|
+
* seconds of stopped recording under `nonBlocking`.
|
|
8115
|
+
*
|
|
8116
|
+
* The mode is on the JOB, not only on the input, because `status` is where an
|
|
8117
|
+
* operator finds out which one is running.
|
|
8118
|
+
*/
|
|
8119
|
+
var StorageMigrationModeSchema = _enum(["blocking", "nonBlocking"]);
|
|
8056
8120
|
/** Shared input for planning and starting an orchestrated storage migration. */
|
|
8057
8121
|
var StorageMigrationInputSchema = object({
|
|
8058
8122
|
destinations: StorageMigrationDestinationsSchema,
|
|
8059
|
-
throttleMbps: number().min(1).max(1e3).optional()
|
|
8123
|
+
throttleMbps: number().min(1).max(1e3).optional(),
|
|
8124
|
+
/** Omitted = `blocking`, which stays the default. */
|
|
8125
|
+
mode: StorageMigrationModeSchema.optional()
|
|
8060
8126
|
});
|
|
8061
|
-
/**
|
|
8062
|
-
*
|
|
8063
|
-
*
|
|
8127
|
+
/**
|
|
8128
|
+
* The durable coordinator state machine.
|
|
8129
|
+
*
|
|
8130
|
+
* `blocking`:
|
|
8131
|
+
* planning → pausing → moving → verifying → repointing → refreshing → resuming → done
|
|
8132
|
+
*
|
|
8133
|
+
* `nonBlocking`:
|
|
8134
|
+
* planning → sealing → pausing → repointing → refreshing → resuming → draining → verifying → done
|
|
8135
|
+
*
|
|
8136
|
+
* Same phases, different order plus two new ones — not a second mover.
|
|
8137
|
+
* `sealing` closes the `eventMedia` NULL-row hole BEFORE anything is paused;
|
|
8138
|
+
* `draining` runs the same movers UNLEASED, after every writer is back up.
|
|
8139
|
+
* `repointing` is still the only phase that changes a default location.
|
|
8140
|
+
*/
|
|
8064
8141
|
var StorageMigrationPhaseSchema = _enum([
|
|
8065
8142
|
"planning",
|
|
8143
|
+
"sealing",
|
|
8066
8144
|
"pausing",
|
|
8067
8145
|
"moving",
|
|
8146
|
+
"draining",
|
|
8068
8147
|
"verifying",
|
|
8069
8148
|
"repointing",
|
|
8070
8149
|
"refreshing",
|
|
@@ -8089,6 +8168,9 @@ var StorageMigrationMoveSchema = object({
|
|
|
8089
8168
|
var StorageMigrationJobSchema = object({
|
|
8090
8169
|
jobId: string(),
|
|
8091
8170
|
phase: StorageMigrationPhaseSchema,
|
|
8171
|
+
/** Which order this job is running. `status` is the only place an operator
|
|
8172
|
+
* can tell a seconds-long cutover from a thirty-hour one. */
|
|
8173
|
+
mode: StorageMigrationModeSchema,
|
|
8092
8174
|
destinations: StorageMigrationDestinationsSchema,
|
|
8093
8175
|
throttleMbps: number(),
|
|
8094
8176
|
moves: array(StorageMigrationMoveSchema),
|
|
@@ -8101,13 +8183,30 @@ var StorageMigrationJobSchema = object({
|
|
|
8101
8183
|
finishedAt: number().nullable(),
|
|
8102
8184
|
error: string().nullable()
|
|
8103
8185
|
});
|
|
8186
|
+
var StorageMigrationFindingSchema = object({
|
|
8187
|
+
code: _enum([
|
|
8188
|
+
"sharesDeviceWithSource",
|
|
8189
|
+
"deviceIdentityUnknown",
|
|
8190
|
+
"unstampedEventMediaRows",
|
|
8191
|
+
"blockingOnly",
|
|
8192
|
+
"noMover"
|
|
8193
|
+
]),
|
|
8194
|
+
storageClass: StorageMigrationClassSchema,
|
|
8195
|
+
/** Human-readable, already carrying the ids and counts. */
|
|
8196
|
+
message: string()
|
|
8197
|
+
});
|
|
8104
8198
|
var StorageMigrationPlanSchema = object({
|
|
8105
8199
|
destinations: StorageMigrationDestinationsSchema,
|
|
8200
|
+
/** The mode this plan was built for. A plan is only valid for its mode: the
|
|
8201
|
+
* `eventMedia` seal gate and the single-cardinality refusal both depend on
|
|
8202
|
+
* it. */
|
|
8203
|
+
mode: StorageMigrationModeSchema,
|
|
8106
8204
|
moves: array(object({
|
|
8107
8205
|
storageClass: StorageMigrationClassSchema,
|
|
8108
8206
|
fromLocationId: string(),
|
|
8109
8207
|
toLocationId: string()
|
|
8110
|
-
}))
|
|
8208
|
+
})),
|
|
8209
|
+
findings: array(StorageMigrationFindingSchema)
|
|
8111
8210
|
});
|
|
8112
8211
|
/**
|
|
8113
8212
|
* `StorageLocationType` — an addon-declared id that identifies the *kind* of
|
|
@@ -18960,7 +19059,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
18960
19059
|
}), method(RelocateMediaInputSchema, object({ jobId: string() }), {
|
|
18961
19060
|
kind: "mutation",
|
|
18962
19061
|
auth: "admin"
|
|
18963
|
-
}), method(object({}), array(RelocateJobSchema).readonly(), {
|
|
19062
|
+
}), method(object({}), UnstampedEventMediaCountSchema, { auth: "admin" }), method(object({}), array(RelocateJobSchema).readonly(), {
|
|
18964
19063
|
kind: "query",
|
|
18965
19064
|
auth: "admin"
|
|
18966
19065
|
}), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
@@ -20971,7 +21070,10 @@ method(object({
|
|
|
20971
21070
|
}), StorageLocationSchema, {
|
|
20972
21071
|
kind: "mutation",
|
|
20973
21072
|
auth: "admin"
|
|
20974
|
-
}), method(object({
|
|
21073
|
+
}), method(object({
|
|
21074
|
+
id: string(),
|
|
21075
|
+
force: boolean().optional()
|
|
21076
|
+
}), _void(), {
|
|
20975
21077
|
kind: "mutation",
|
|
20976
21078
|
auth: "admin"
|
|
20977
21079
|
}), method(object({ id: string() }), object({
|
|
@@ -25039,6 +25141,33 @@ var intercomCapability = {
|
|
|
25039
25141
|
deviceNative: true,
|
|
25040
25142
|
mode: "singleton",
|
|
25041
25143
|
deviceTypes: [DeviceType.Camera],
|
|
25144
|
+
/**
|
|
25145
|
+
* **Auth tier: `protected` on every method — deliberate, and load-bearing.**
|
|
25146
|
+
*
|
|
25147
|
+
* Talking through a camera is an OPERATE action, not a CONFIGURE one. This
|
|
25148
|
+
* cap has no configuration surface at all: all six methods open, feed and
|
|
25149
|
+
* close one live audio session against one `deviceId`. That is the same
|
|
25150
|
+
* authority as `ptz.move` or `snapshot.getSnapshot`, both `protected` — and
|
|
25151
|
+
* the opposite of `ptz.savePreset` / `snapshot.invalidateCache`, which are
|
|
25152
|
+
* `admin` because they change what the device IS.
|
|
25153
|
+
*
|
|
25154
|
+
* `protected` does not mean ungated: `protectedProcedure` runs the
|
|
25155
|
+
* `METHOD_ACCESS_MAP` scope check, and every method here is `scope: 'device'`
|
|
25156
|
+
* with `access: 'create'` and a `deviceId` in its input. So a caller needs a
|
|
25157
|
+
* grant that covers THAT camera at `create` — a `camera-viewer` (`view`
|
|
25158
|
+
* only) still cannot talk, and a grant on camera 5 cannot talk through
|
|
25159
|
+
* camera 7.
|
|
25160
|
+
*
|
|
25161
|
+
* Every method was `auth: 'admin'` from the initial commit, which made the
|
|
25162
|
+
* cap unreachable by every non-admin principal — `adminProcedure` throws
|
|
25163
|
+
* `FORBIDDEN: Admin required` BEFORE the scope check runs, so the scope
|
|
25164
|
+
* machinery generated for this cap (`METHOD_ACCESS_MAP`,
|
|
25165
|
+
* `DEVICE_SCOPED_CAPS`, `METHOD_DEVICE_SELECTORS`) was complete and dead. The
|
|
25166
|
+
* `camera-operator` scope preset has promised "PTZ control, intercom,
|
|
25167
|
+
* snapshots" since that same commit; the promise could not be kept. Recorded
|
|
25168
|
+
* as D289; `scripts/check-scope-preset-promises.ts` now fails the build if a
|
|
25169
|
+
* preset promises a cap no row of that preset can reach.
|
|
25170
|
+
*/
|
|
25042
25171
|
methods: {
|
|
25043
25172
|
/**
|
|
25044
25173
|
* Open a server-side WebRTC audio-only session. Returns an SDP
|
|
@@ -25051,7 +25180,7 @@ var intercomCapability = {
|
|
|
25051
25180
|
sdpOffer: string()
|
|
25052
25181
|
}), {
|
|
25053
25182
|
kind: "mutation",
|
|
25054
|
-
auth: "
|
|
25183
|
+
auth: "protected"
|
|
25055
25184
|
}),
|
|
25056
25185
|
handleAnswer: method(object({
|
|
25057
25186
|
deviceId: number(),
|
|
@@ -25059,7 +25188,7 @@ var intercomCapability = {
|
|
|
25059
25188
|
sdpAnswer: string()
|
|
25060
25189
|
}), _void(), {
|
|
25061
25190
|
kind: "mutation",
|
|
25062
|
-
auth: "
|
|
25191
|
+
auth: "protected"
|
|
25063
25192
|
}),
|
|
25064
25193
|
/** Close explicitly. Server also auto-closes on 30s idle. */
|
|
25065
25194
|
stopSession: method(object({
|
|
@@ -25067,7 +25196,7 @@ var intercomCapability = {
|
|
|
25067
25196
|
sessionId: string()
|
|
25068
25197
|
}), _void(), {
|
|
25069
25198
|
kind: "mutation",
|
|
25070
|
-
auth: "
|
|
25199
|
+
auth: "protected"
|
|
25071
25200
|
}),
|
|
25072
25201
|
/**
|
|
25073
25202
|
* Open a raw-PCM talk session (no WebRTC SDP plumbing). Used by
|
|
@@ -25080,7 +25209,7 @@ var intercomCapability = {
|
|
|
25080
25209
|
*/
|
|
25081
25210
|
startTalkSession: method(object({ deviceId: number() }), object({ sessionId: string() }), {
|
|
25082
25211
|
kind: "mutation",
|
|
25083
|
-
auth: "
|
|
25212
|
+
auth: "protected"
|
|
25084
25213
|
}),
|
|
25085
25214
|
/**
|
|
25086
25215
|
* Push one chunk of talk-back audio onto the active talk session.
|
|
@@ -25115,12 +25244,12 @@ var intercomCapability = {
|
|
|
25115
25244
|
sequenceNumber: number().int()
|
|
25116
25245
|
}), object({ accepted: boolean() }), {
|
|
25117
25246
|
kind: "mutation",
|
|
25118
|
-
auth: "
|
|
25247
|
+
auth: "protected"
|
|
25119
25248
|
}),
|
|
25120
25249
|
/** Close the raw-PCM talk session. Idempotent. */
|
|
25121
25250
|
endTalkSession: method(object({ deviceId: number() }), _void(), {
|
|
25122
25251
|
kind: "mutation",
|
|
25123
|
-
auth: "
|
|
25252
|
+
auth: "protected"
|
|
25124
25253
|
})
|
|
25125
25254
|
},
|
|
25126
25255
|
events: { onStatusChanged: { data: object({
|
|
@@ -35293,6 +35422,12 @@ Object.freeze({
|
|
|
35293
35422
|
addonId: null,
|
|
35294
35423
|
access: "create"
|
|
35295
35424
|
},
|
|
35425
|
+
"pipelineAnalytics.countUnstampedEventMedia": {
|
|
35426
|
+
capName: "pipeline-analytics",
|
|
35427
|
+
capScope: "device",
|
|
35428
|
+
addonId: null,
|
|
35429
|
+
access: "view"
|
|
35430
|
+
},
|
|
35296
35431
|
"pipelineAnalytics.deleteDeviceEvents": {
|
|
35297
35432
|
capName: "pipeline-analytics",
|
|
35298
35433
|
capScope: "device",
|
package/dist/addon.mjs
CHANGED
|
@@ -8033,18 +8033,61 @@ var RelocateFootageInputSchema = object({
|
|
|
8033
8033
|
* `RecordingConfig.enabled` or camera wrapper bindings. */
|
|
8034
8034
|
var StorageMigrationLeaseInputSchema = object({ leaseId: string().min(1) });
|
|
8035
8035
|
var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: string().min(1) });
|
|
8036
|
+
/**
|
|
8037
|
+
* What a `relocateMedia` pass DOES. One engine, three passes — never a second
|
|
8038
|
+
* mover (the engine already walks both collections with a timestamp cursor and
|
|
8039
|
+
* already has a stamp-without-copy path).
|
|
8040
|
+
*
|
|
8041
|
+
* - `move` — the default and the historical behaviour: event-media and
|
|
8042
|
+
* retrain blobs move to `toLocationId` and their rows are
|
|
8043
|
+
* stamped. The enrolled gallery is skipped (D197).
|
|
8044
|
+
* - `seal` — ROWS ONLY, no bytes. Every row whose `locationId` is NULL is
|
|
8045
|
+
* stamped with `toLocationId`. `toLocationId` here is the id the
|
|
8046
|
+
* bytes ALREADY sit on — today's `eventMedia` default — because
|
|
8047
|
+
* a NULL row means "wherever `eventMedia` points *now*", and the
|
|
8048
|
+
* instant a repoint moves that pointer the row reads from the
|
|
8049
|
+
* new disk while its bytes are on the old one.
|
|
8050
|
+
* - `gallery` — the inverse selection of `move`: ONLY the retention-exempt
|
|
8051
|
+
* (enrolled-gallery) rows, which `move` deliberately skips.
|
|
8052
|
+
* `galleryMedia` is `cardinality: 'single'`, so this pass can
|
|
8053
|
+
* never run beside a live second location: it is stop-the-world
|
|
8054
|
+
* by construction, which is acceptable only because the gallery
|
|
8055
|
+
* is a few KB per enrolled sample.
|
|
8056
|
+
*/
|
|
8057
|
+
var MediaRelocateModeSchema = _enum([
|
|
8058
|
+
"move",
|
|
8059
|
+
"seal",
|
|
8060
|
+
"gallery"
|
|
8061
|
+
]);
|
|
8036
8062
|
var RelocateMediaInputSchema = object({
|
|
8037
8063
|
toLocationId: string(),
|
|
8038
|
-
throttleMbps: number().min(1).max(1e3).optional()
|
|
8064
|
+
throttleMbps: number().min(1).max(1e3).optional(),
|
|
8065
|
+
/** Omitted = `move`, the pre-existing behaviour. */
|
|
8066
|
+
mode: MediaRelocateModeSchema.optional()
|
|
8067
|
+
});
|
|
8068
|
+
/** How many rows still carry NO `locationId` — the population a repoint would
|
|
8069
|
+
* silently re-aim at a disk that does not hold their bytes. Zero is the only
|
|
8070
|
+
* value that permits a non-blocking `eventMedia` cutover. */
|
|
8071
|
+
var UnstampedEventMediaCountSchema = object({
|
|
8072
|
+
media: number().int().nonnegative(),
|
|
8073
|
+
retrainFrames: number().int().nonnegative(),
|
|
8074
|
+
total: number().int().nonnegative()
|
|
8039
8075
|
});
|
|
8040
8076
|
var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: string().min(1) });
|
|
8041
|
-
/** The independently selectable logical storage classes
|
|
8042
|
-
*
|
|
8043
|
-
*
|
|
8077
|
+
/** The independently selectable logical storage classes — every class
|
|
8078
|
+
* `storage.listLocationDeclarations` reports, so an operator never meets a
|
|
8079
|
+
* Zod enum error where they should meet an explanation.
|
|
8080
|
+
*
|
|
8081
|
+
* `recordings` encompasses the high and mid segment profiles; `recordingsLow`
|
|
8082
|
+
* is low segments; `eventMedia` is post-analysis blobs; `galleryMedia` is the
|
|
8083
|
+
* enrolled gallery; `backups` is the system backup archive. The last two have
|
|
8084
|
+
* their own rules — see {@link StorageMigrationFindingCodeSchema}. */
|
|
8044
8085
|
var StorageMigrationClassSchema = _enum([
|
|
8045
8086
|
"recordings",
|
|
8046
8087
|
"recordingsLow",
|
|
8047
|
-
"eventMedia"
|
|
8088
|
+
"eventMedia",
|
|
8089
|
+
"backups",
|
|
8090
|
+
"galleryMedia"
|
|
8048
8091
|
]);
|
|
8049
8092
|
/** A destination is always an existing, fully-qualified location id. The
|
|
8050
8093
|
* migration API intentionally never changes a source location's `basePath`:
|
|
@@ -8052,20 +8095,56 @@ var StorageMigrationClassSchema = _enum([
|
|
|
8052
8095
|
var StorageMigrationDestinationsSchema = object({
|
|
8053
8096
|
recordings: string().min(1).optional(),
|
|
8054
8097
|
recordingsLow: string().min(1).optional(),
|
|
8055
|
-
eventMedia: string().min(1).optional()
|
|
8098
|
+
eventMedia: string().min(1).optional(),
|
|
8099
|
+
backups: string().min(1).optional(),
|
|
8100
|
+
galleryMedia: string().min(1).optional()
|
|
8056
8101
|
}).refine((value) => Object.keys(value).length > 0, { message: "select at least one storage class" });
|
|
8102
|
+
/**
|
|
8103
|
+
* How a migration sequences the cutover against the byte move.
|
|
8104
|
+
*
|
|
8105
|
+
* - `blocking` — the historical order: pause, move every byte, repoint,
|
|
8106
|
+
* resume. Recording is stopped for the whole move. Right
|
|
8107
|
+
* for a small or a cold class, and the only legal mode for
|
|
8108
|
+
* a `cardinality: 'single'` class.
|
|
8109
|
+
* - `nonBlocking` — repoint FIRST, drain behind: seal, pause, repoint,
|
|
8110
|
+
* refresh, resume, then move the past with everything
|
|
8111
|
+
* running. The pause is three bounded instants (a detach +
|
|
8112
|
+
* attach round, a write-gate drain, a lease) instead of one
|
|
8113
|
+
* bounded by bytes. 1.09 TB at 7–14 MB/s is thirty hours of
|
|
8114
|
+
* stopped recording under `blocking`; the same move is
|
|
8115
|
+
* seconds of stopped recording under `nonBlocking`.
|
|
8116
|
+
*
|
|
8117
|
+
* The mode is on the JOB, not only on the input, because `status` is where an
|
|
8118
|
+
* operator finds out which one is running.
|
|
8119
|
+
*/
|
|
8120
|
+
var StorageMigrationModeSchema = _enum(["blocking", "nonBlocking"]);
|
|
8057
8121
|
/** Shared input for planning and starting an orchestrated storage migration. */
|
|
8058
8122
|
var StorageMigrationInputSchema = object({
|
|
8059
8123
|
destinations: StorageMigrationDestinationsSchema,
|
|
8060
|
-
throttleMbps: number().min(1).max(1e3).optional()
|
|
8124
|
+
throttleMbps: number().min(1).max(1e3).optional(),
|
|
8125
|
+
/** Omitted = `blocking`, which stays the default. */
|
|
8126
|
+
mode: StorageMigrationModeSchema.optional()
|
|
8061
8127
|
});
|
|
8062
|
-
/**
|
|
8063
|
-
*
|
|
8064
|
-
*
|
|
8128
|
+
/**
|
|
8129
|
+
* The durable coordinator state machine.
|
|
8130
|
+
*
|
|
8131
|
+
* `blocking`:
|
|
8132
|
+
* planning → pausing → moving → verifying → repointing → refreshing → resuming → done
|
|
8133
|
+
*
|
|
8134
|
+
* `nonBlocking`:
|
|
8135
|
+
* planning → sealing → pausing → repointing → refreshing → resuming → draining → verifying → done
|
|
8136
|
+
*
|
|
8137
|
+
* Same phases, different order plus two new ones — not a second mover.
|
|
8138
|
+
* `sealing` closes the `eventMedia` NULL-row hole BEFORE anything is paused;
|
|
8139
|
+
* `draining` runs the same movers UNLEASED, after every writer is back up.
|
|
8140
|
+
* `repointing` is still the only phase that changes a default location.
|
|
8141
|
+
*/
|
|
8065
8142
|
var StorageMigrationPhaseSchema = _enum([
|
|
8066
8143
|
"planning",
|
|
8144
|
+
"sealing",
|
|
8067
8145
|
"pausing",
|
|
8068
8146
|
"moving",
|
|
8147
|
+
"draining",
|
|
8069
8148
|
"verifying",
|
|
8070
8149
|
"repointing",
|
|
8071
8150
|
"refreshing",
|
|
@@ -8090,6 +8169,9 @@ var StorageMigrationMoveSchema = object({
|
|
|
8090
8169
|
var StorageMigrationJobSchema = object({
|
|
8091
8170
|
jobId: string(),
|
|
8092
8171
|
phase: StorageMigrationPhaseSchema,
|
|
8172
|
+
/** Which order this job is running. `status` is the only place an operator
|
|
8173
|
+
* can tell a seconds-long cutover from a thirty-hour one. */
|
|
8174
|
+
mode: StorageMigrationModeSchema,
|
|
8093
8175
|
destinations: StorageMigrationDestinationsSchema,
|
|
8094
8176
|
throttleMbps: number(),
|
|
8095
8177
|
moves: array(StorageMigrationMoveSchema),
|
|
@@ -8102,13 +8184,30 @@ var StorageMigrationJobSchema = object({
|
|
|
8102
8184
|
finishedAt: number().nullable(),
|
|
8103
8185
|
error: string().nullable()
|
|
8104
8186
|
});
|
|
8187
|
+
var StorageMigrationFindingSchema = object({
|
|
8188
|
+
code: _enum([
|
|
8189
|
+
"sharesDeviceWithSource",
|
|
8190
|
+
"deviceIdentityUnknown",
|
|
8191
|
+
"unstampedEventMediaRows",
|
|
8192
|
+
"blockingOnly",
|
|
8193
|
+
"noMover"
|
|
8194
|
+
]),
|
|
8195
|
+
storageClass: StorageMigrationClassSchema,
|
|
8196
|
+
/** Human-readable, already carrying the ids and counts. */
|
|
8197
|
+
message: string()
|
|
8198
|
+
});
|
|
8105
8199
|
var StorageMigrationPlanSchema = object({
|
|
8106
8200
|
destinations: StorageMigrationDestinationsSchema,
|
|
8201
|
+
/** The mode this plan was built for. A plan is only valid for its mode: the
|
|
8202
|
+
* `eventMedia` seal gate and the single-cardinality refusal both depend on
|
|
8203
|
+
* it. */
|
|
8204
|
+
mode: StorageMigrationModeSchema,
|
|
8107
8205
|
moves: array(object({
|
|
8108
8206
|
storageClass: StorageMigrationClassSchema,
|
|
8109
8207
|
fromLocationId: string(),
|
|
8110
8208
|
toLocationId: string()
|
|
8111
|
-
}))
|
|
8209
|
+
})),
|
|
8210
|
+
findings: array(StorageMigrationFindingSchema)
|
|
8112
8211
|
});
|
|
8113
8212
|
/**
|
|
8114
8213
|
* `StorageLocationType` — an addon-declared id that identifies the *kind* of
|
|
@@ -18961,7 +19060,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
18961
19060
|
}), method(RelocateMediaInputSchema, object({ jobId: string() }), {
|
|
18962
19061
|
kind: "mutation",
|
|
18963
19062
|
auth: "admin"
|
|
18964
|
-
}), method(object({}), array(RelocateJobSchema).readonly(), {
|
|
19063
|
+
}), method(object({}), UnstampedEventMediaCountSchema, { auth: "admin" }), method(object({}), array(RelocateJobSchema).readonly(), {
|
|
18965
19064
|
kind: "query",
|
|
18966
19065
|
auth: "admin"
|
|
18967
19066
|
}), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
@@ -20972,7 +21071,10 @@ method(object({
|
|
|
20972
21071
|
}), StorageLocationSchema, {
|
|
20973
21072
|
kind: "mutation",
|
|
20974
21073
|
auth: "admin"
|
|
20975
|
-
}), method(object({
|
|
21074
|
+
}), method(object({
|
|
21075
|
+
id: string(),
|
|
21076
|
+
force: boolean().optional()
|
|
21077
|
+
}), _void(), {
|
|
20976
21078
|
kind: "mutation",
|
|
20977
21079
|
auth: "admin"
|
|
20978
21080
|
}), method(object({ id: string() }), object({
|
|
@@ -25040,6 +25142,33 @@ var intercomCapability = {
|
|
|
25040
25142
|
deviceNative: true,
|
|
25041
25143
|
mode: "singleton",
|
|
25042
25144
|
deviceTypes: [DeviceType.Camera],
|
|
25145
|
+
/**
|
|
25146
|
+
* **Auth tier: `protected` on every method — deliberate, and load-bearing.**
|
|
25147
|
+
*
|
|
25148
|
+
* Talking through a camera is an OPERATE action, not a CONFIGURE one. This
|
|
25149
|
+
* cap has no configuration surface at all: all six methods open, feed and
|
|
25150
|
+
* close one live audio session against one `deviceId`. That is the same
|
|
25151
|
+
* authority as `ptz.move` or `snapshot.getSnapshot`, both `protected` — and
|
|
25152
|
+
* the opposite of `ptz.savePreset` / `snapshot.invalidateCache`, which are
|
|
25153
|
+
* `admin` because they change what the device IS.
|
|
25154
|
+
*
|
|
25155
|
+
* `protected` does not mean ungated: `protectedProcedure` runs the
|
|
25156
|
+
* `METHOD_ACCESS_MAP` scope check, and every method here is `scope: 'device'`
|
|
25157
|
+
* with `access: 'create'` and a `deviceId` in its input. So a caller needs a
|
|
25158
|
+
* grant that covers THAT camera at `create` — a `camera-viewer` (`view`
|
|
25159
|
+
* only) still cannot talk, and a grant on camera 5 cannot talk through
|
|
25160
|
+
* camera 7.
|
|
25161
|
+
*
|
|
25162
|
+
* Every method was `auth: 'admin'` from the initial commit, which made the
|
|
25163
|
+
* cap unreachable by every non-admin principal — `adminProcedure` throws
|
|
25164
|
+
* `FORBIDDEN: Admin required` BEFORE the scope check runs, so the scope
|
|
25165
|
+
* machinery generated for this cap (`METHOD_ACCESS_MAP`,
|
|
25166
|
+
* `DEVICE_SCOPED_CAPS`, `METHOD_DEVICE_SELECTORS`) was complete and dead. The
|
|
25167
|
+
* `camera-operator` scope preset has promised "PTZ control, intercom,
|
|
25168
|
+
* snapshots" since that same commit; the promise could not be kept. Recorded
|
|
25169
|
+
* as D289; `scripts/check-scope-preset-promises.ts` now fails the build if a
|
|
25170
|
+
* preset promises a cap no row of that preset can reach.
|
|
25171
|
+
*/
|
|
25043
25172
|
methods: {
|
|
25044
25173
|
/**
|
|
25045
25174
|
* Open a server-side WebRTC audio-only session. Returns an SDP
|
|
@@ -25052,7 +25181,7 @@ var intercomCapability = {
|
|
|
25052
25181
|
sdpOffer: string()
|
|
25053
25182
|
}), {
|
|
25054
25183
|
kind: "mutation",
|
|
25055
|
-
auth: "
|
|
25184
|
+
auth: "protected"
|
|
25056
25185
|
}),
|
|
25057
25186
|
handleAnswer: method(object({
|
|
25058
25187
|
deviceId: number(),
|
|
@@ -25060,7 +25189,7 @@ var intercomCapability = {
|
|
|
25060
25189
|
sdpAnswer: string()
|
|
25061
25190
|
}), _void(), {
|
|
25062
25191
|
kind: "mutation",
|
|
25063
|
-
auth: "
|
|
25192
|
+
auth: "protected"
|
|
25064
25193
|
}),
|
|
25065
25194
|
/** Close explicitly. Server also auto-closes on 30s idle. */
|
|
25066
25195
|
stopSession: method(object({
|
|
@@ -25068,7 +25197,7 @@ var intercomCapability = {
|
|
|
25068
25197
|
sessionId: string()
|
|
25069
25198
|
}), _void(), {
|
|
25070
25199
|
kind: "mutation",
|
|
25071
|
-
auth: "
|
|
25200
|
+
auth: "protected"
|
|
25072
25201
|
}),
|
|
25073
25202
|
/**
|
|
25074
25203
|
* Open a raw-PCM talk session (no WebRTC SDP plumbing). Used by
|
|
@@ -25081,7 +25210,7 @@ var intercomCapability = {
|
|
|
25081
25210
|
*/
|
|
25082
25211
|
startTalkSession: method(object({ deviceId: number() }), object({ sessionId: string() }), {
|
|
25083
25212
|
kind: "mutation",
|
|
25084
|
-
auth: "
|
|
25213
|
+
auth: "protected"
|
|
25085
25214
|
}),
|
|
25086
25215
|
/**
|
|
25087
25216
|
* Push one chunk of talk-back audio onto the active talk session.
|
|
@@ -25116,12 +25245,12 @@ var intercomCapability = {
|
|
|
25116
25245
|
sequenceNumber: number().int()
|
|
25117
25246
|
}), object({ accepted: boolean() }), {
|
|
25118
25247
|
kind: "mutation",
|
|
25119
|
-
auth: "
|
|
25248
|
+
auth: "protected"
|
|
25120
25249
|
}),
|
|
25121
25250
|
/** Close the raw-PCM talk session. Idempotent. */
|
|
25122
25251
|
endTalkSession: method(object({ deviceId: number() }), _void(), {
|
|
25123
25252
|
kind: "mutation",
|
|
25124
|
-
auth: "
|
|
25253
|
+
auth: "protected"
|
|
25125
25254
|
})
|
|
25126
25255
|
},
|
|
25127
25256
|
events: { onStatusChanged: { data: object({
|
|
@@ -35294,6 +35423,12 @@ Object.freeze({
|
|
|
35294
35423
|
addonId: null,
|
|
35295
35424
|
access: "create"
|
|
35296
35425
|
},
|
|
35426
|
+
"pipelineAnalytics.countUnstampedEventMedia": {
|
|
35427
|
+
capName: "pipeline-analytics",
|
|
35428
|
+
capScope: "device",
|
|
35429
|
+
addonId: null,
|
|
35430
|
+
access: "view"
|
|
35431
|
+
},
|
|
35297
35432
|
"pipelineAnalytics.deleteDeviceEvents": {
|
|
35298
35433
|
capName: "pipeline-analytics",
|
|
35299
35434
|
capScope: "device",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-provider-amcrest",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.44",
|
|
4
4
|
"description": "Amcrest/Dahua camera device provider addon for CamStack — Dahua CGI over HTTP(S) with digest auth (snapshot, RTSP catalog, PTZ, image/day-night config)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|