@camstack/addon-provider-petkit 0.2.41 → 0.2.43
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
|
@@ -9141,18 +9141,61 @@ var RelocateFootageInputSchema = object({
|
|
|
9141
9141
|
* `RecordingConfig.enabled` or camera wrapper bindings. */
|
|
9142
9142
|
var StorageMigrationLeaseInputSchema = object({ leaseId: string().min(1) });
|
|
9143
9143
|
var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: string().min(1) });
|
|
9144
|
+
/**
|
|
9145
|
+
* What a `relocateMedia` pass DOES. One engine, three passes — never a second
|
|
9146
|
+
* mover (the engine already walks both collections with a timestamp cursor and
|
|
9147
|
+
* already has a stamp-without-copy path).
|
|
9148
|
+
*
|
|
9149
|
+
* - `move` — the default and the historical behaviour: event-media and
|
|
9150
|
+
* retrain blobs move to `toLocationId` and their rows are
|
|
9151
|
+
* stamped. The enrolled gallery is skipped (D197).
|
|
9152
|
+
* - `seal` — ROWS ONLY, no bytes. Every row whose `locationId` is NULL is
|
|
9153
|
+
* stamped with `toLocationId`. `toLocationId` here is the id the
|
|
9154
|
+
* bytes ALREADY sit on — today's `eventMedia` default — because
|
|
9155
|
+
* a NULL row means "wherever `eventMedia` points *now*", and the
|
|
9156
|
+
* instant a repoint moves that pointer the row reads from the
|
|
9157
|
+
* new disk while its bytes are on the old one.
|
|
9158
|
+
* - `gallery` — the inverse selection of `move`: ONLY the retention-exempt
|
|
9159
|
+
* (enrolled-gallery) rows, which `move` deliberately skips.
|
|
9160
|
+
* `galleryMedia` is `cardinality: 'single'`, so this pass can
|
|
9161
|
+
* never run beside a live second location: it is stop-the-world
|
|
9162
|
+
* by construction, which is acceptable only because the gallery
|
|
9163
|
+
* is a few KB per enrolled sample.
|
|
9164
|
+
*/
|
|
9165
|
+
var MediaRelocateModeSchema = _enum([
|
|
9166
|
+
"move",
|
|
9167
|
+
"seal",
|
|
9168
|
+
"gallery"
|
|
9169
|
+
]);
|
|
9144
9170
|
var RelocateMediaInputSchema = object({
|
|
9145
9171
|
toLocationId: string(),
|
|
9146
|
-
throttleMbps: number().min(1).max(1e3).optional()
|
|
9172
|
+
throttleMbps: number().min(1).max(1e3).optional(),
|
|
9173
|
+
/** Omitted = `move`, the pre-existing behaviour. */
|
|
9174
|
+
mode: MediaRelocateModeSchema.optional()
|
|
9175
|
+
});
|
|
9176
|
+
/** How many rows still carry NO `locationId` — the population a repoint would
|
|
9177
|
+
* silently re-aim at a disk that does not hold their bytes. Zero is the only
|
|
9178
|
+
* value that permits a non-blocking `eventMedia` cutover. */
|
|
9179
|
+
var UnstampedEventMediaCountSchema = object({
|
|
9180
|
+
media: number().int().nonnegative(),
|
|
9181
|
+
retrainFrames: number().int().nonnegative(),
|
|
9182
|
+
total: number().int().nonnegative()
|
|
9147
9183
|
});
|
|
9148
9184
|
var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: string().min(1) });
|
|
9149
|
-
/** The independently selectable logical storage classes
|
|
9150
|
-
*
|
|
9151
|
-
*
|
|
9185
|
+
/** The independently selectable logical storage classes — every class
|
|
9186
|
+
* `storage.listLocationDeclarations` reports, so an operator never meets a
|
|
9187
|
+
* Zod enum error where they should meet an explanation.
|
|
9188
|
+
*
|
|
9189
|
+
* `recordings` encompasses the high and mid segment profiles; `recordingsLow`
|
|
9190
|
+
* is low segments; `eventMedia` is post-analysis blobs; `galleryMedia` is the
|
|
9191
|
+
* enrolled gallery; `backups` is the system backup archive. The last two have
|
|
9192
|
+
* their own rules — see {@link StorageMigrationFindingCodeSchema}. */
|
|
9152
9193
|
var StorageMigrationClassSchema = _enum([
|
|
9153
9194
|
"recordings",
|
|
9154
9195
|
"recordingsLow",
|
|
9155
|
-
"eventMedia"
|
|
9196
|
+
"eventMedia",
|
|
9197
|
+
"backups",
|
|
9198
|
+
"galleryMedia"
|
|
9156
9199
|
]);
|
|
9157
9200
|
/** A destination is always an existing, fully-qualified location id. The
|
|
9158
9201
|
* migration API intentionally never changes a source location's `basePath`:
|
|
@@ -9160,20 +9203,56 @@ var StorageMigrationClassSchema = _enum([
|
|
|
9160
9203
|
var StorageMigrationDestinationsSchema = object({
|
|
9161
9204
|
recordings: string().min(1).optional(),
|
|
9162
9205
|
recordingsLow: string().min(1).optional(),
|
|
9163
|
-
eventMedia: string().min(1).optional()
|
|
9206
|
+
eventMedia: string().min(1).optional(),
|
|
9207
|
+
backups: string().min(1).optional(),
|
|
9208
|
+
galleryMedia: string().min(1).optional()
|
|
9164
9209
|
}).refine((value) => Object.keys(value).length > 0, { message: "select at least one storage class" });
|
|
9210
|
+
/**
|
|
9211
|
+
* How a migration sequences the cutover against the byte move.
|
|
9212
|
+
*
|
|
9213
|
+
* - `blocking` — the historical order: pause, move every byte, repoint,
|
|
9214
|
+
* resume. Recording is stopped for the whole move. Right
|
|
9215
|
+
* for a small or a cold class, and the only legal mode for
|
|
9216
|
+
* a `cardinality: 'single'` class.
|
|
9217
|
+
* - `nonBlocking` — repoint FIRST, drain behind: seal, pause, repoint,
|
|
9218
|
+
* refresh, resume, then move the past with everything
|
|
9219
|
+
* running. The pause is three bounded instants (a detach +
|
|
9220
|
+
* attach round, a write-gate drain, a lease) instead of one
|
|
9221
|
+
* bounded by bytes. 1.09 TB at 7–14 MB/s is thirty hours of
|
|
9222
|
+
* stopped recording under `blocking`; the same move is
|
|
9223
|
+
* seconds of stopped recording under `nonBlocking`.
|
|
9224
|
+
*
|
|
9225
|
+
* The mode is on the JOB, not only on the input, because `status` is where an
|
|
9226
|
+
* operator finds out which one is running.
|
|
9227
|
+
*/
|
|
9228
|
+
var StorageMigrationModeSchema = _enum(["blocking", "nonBlocking"]);
|
|
9165
9229
|
/** Shared input for planning and starting an orchestrated storage migration. */
|
|
9166
9230
|
var StorageMigrationInputSchema = object({
|
|
9167
9231
|
destinations: StorageMigrationDestinationsSchema,
|
|
9168
|
-
throttleMbps: number().min(1).max(1e3).optional()
|
|
9232
|
+
throttleMbps: number().min(1).max(1e3).optional(),
|
|
9233
|
+
/** Omitted = `blocking`, which stays the default. */
|
|
9234
|
+
mode: StorageMigrationModeSchema.optional()
|
|
9169
9235
|
});
|
|
9170
|
-
/**
|
|
9171
|
-
*
|
|
9172
|
-
*
|
|
9236
|
+
/**
|
|
9237
|
+
* The durable coordinator state machine.
|
|
9238
|
+
*
|
|
9239
|
+
* `blocking`:
|
|
9240
|
+
* planning → pausing → moving → verifying → repointing → refreshing → resuming → done
|
|
9241
|
+
*
|
|
9242
|
+
* `nonBlocking`:
|
|
9243
|
+
* planning → sealing → pausing → repointing → refreshing → resuming → draining → verifying → done
|
|
9244
|
+
*
|
|
9245
|
+
* Same phases, different order plus two new ones — not a second mover.
|
|
9246
|
+
* `sealing` closes the `eventMedia` NULL-row hole BEFORE anything is paused;
|
|
9247
|
+
* `draining` runs the same movers UNLEASED, after every writer is back up.
|
|
9248
|
+
* `repointing` is still the only phase that changes a default location.
|
|
9249
|
+
*/
|
|
9173
9250
|
var StorageMigrationPhaseSchema = _enum([
|
|
9174
9251
|
"planning",
|
|
9252
|
+
"sealing",
|
|
9175
9253
|
"pausing",
|
|
9176
9254
|
"moving",
|
|
9255
|
+
"draining",
|
|
9177
9256
|
"verifying",
|
|
9178
9257
|
"repointing",
|
|
9179
9258
|
"refreshing",
|
|
@@ -9198,6 +9277,9 @@ var StorageMigrationMoveSchema = object({
|
|
|
9198
9277
|
var StorageMigrationJobSchema = object({
|
|
9199
9278
|
jobId: string(),
|
|
9200
9279
|
phase: StorageMigrationPhaseSchema,
|
|
9280
|
+
/** Which order this job is running. `status` is the only place an operator
|
|
9281
|
+
* can tell a seconds-long cutover from a thirty-hour one. */
|
|
9282
|
+
mode: StorageMigrationModeSchema,
|
|
9201
9283
|
destinations: StorageMigrationDestinationsSchema,
|
|
9202
9284
|
throttleMbps: number(),
|
|
9203
9285
|
moves: array(StorageMigrationMoveSchema),
|
|
@@ -9210,13 +9292,30 @@ var StorageMigrationJobSchema = object({
|
|
|
9210
9292
|
finishedAt: number().nullable(),
|
|
9211
9293
|
error: string().nullable()
|
|
9212
9294
|
});
|
|
9295
|
+
var StorageMigrationFindingSchema = object({
|
|
9296
|
+
code: _enum([
|
|
9297
|
+
"sharesDeviceWithSource",
|
|
9298
|
+
"deviceIdentityUnknown",
|
|
9299
|
+
"unstampedEventMediaRows",
|
|
9300
|
+
"blockingOnly",
|
|
9301
|
+
"noMover"
|
|
9302
|
+
]),
|
|
9303
|
+
storageClass: StorageMigrationClassSchema,
|
|
9304
|
+
/** Human-readable, already carrying the ids and counts. */
|
|
9305
|
+
message: string()
|
|
9306
|
+
});
|
|
9213
9307
|
var StorageMigrationPlanSchema = object({
|
|
9214
9308
|
destinations: StorageMigrationDestinationsSchema,
|
|
9309
|
+
/** The mode this plan was built for. A plan is only valid for its mode: the
|
|
9310
|
+
* `eventMedia` seal gate and the single-cardinality refusal both depend on
|
|
9311
|
+
* it. */
|
|
9312
|
+
mode: StorageMigrationModeSchema,
|
|
9215
9313
|
moves: array(object({
|
|
9216
9314
|
storageClass: StorageMigrationClassSchema,
|
|
9217
9315
|
fromLocationId: string(),
|
|
9218
9316
|
toLocationId: string()
|
|
9219
|
-
}))
|
|
9317
|
+
})),
|
|
9318
|
+
findings: array(StorageMigrationFindingSchema)
|
|
9220
9319
|
});
|
|
9221
9320
|
/**
|
|
9222
9321
|
* `StorageLocationType` — an addon-declared id that identifies the *kind* of
|
|
@@ -20086,7 +20185,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
20086
20185
|
}), method(RelocateMediaInputSchema, object({ jobId: string() }), {
|
|
20087
20186
|
kind: "mutation",
|
|
20088
20187
|
auth: "admin"
|
|
20089
|
-
}), method(object({}), array(RelocateJobSchema).readonly(), {
|
|
20188
|
+
}), method(object({}), UnstampedEventMediaCountSchema, { auth: "admin" }), method(object({}), array(RelocateJobSchema).readonly(), {
|
|
20090
20189
|
kind: "query",
|
|
20091
20190
|
auth: "admin"
|
|
20092
20191
|
}), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
@@ -21993,7 +22092,10 @@ method(object({
|
|
|
21993
22092
|
}), StorageLocationSchema, {
|
|
21994
22093
|
kind: "mutation",
|
|
21995
22094
|
auth: "admin"
|
|
21996
|
-
}), method(object({
|
|
22095
|
+
}), method(object({
|
|
22096
|
+
id: string(),
|
|
22097
|
+
force: boolean().optional()
|
|
22098
|
+
}), _void(), {
|
|
21997
22099
|
kind: "mutation",
|
|
21998
22100
|
auth: "admin"
|
|
21999
22101
|
}), method(object({ id: string() }), object({
|
|
@@ -26069,6 +26171,33 @@ var intercomCapability = {
|
|
|
26069
26171
|
deviceNative: true,
|
|
26070
26172
|
mode: "singleton",
|
|
26071
26173
|
deviceTypes: [DeviceType.Camera],
|
|
26174
|
+
/**
|
|
26175
|
+
* **Auth tier: `protected` on every method — deliberate, and load-bearing.**
|
|
26176
|
+
*
|
|
26177
|
+
* Talking through a camera is an OPERATE action, not a CONFIGURE one. This
|
|
26178
|
+
* cap has no configuration surface at all: all six methods open, feed and
|
|
26179
|
+
* close one live audio session against one `deviceId`. That is the same
|
|
26180
|
+
* authority as `ptz.move` or `snapshot.getSnapshot`, both `protected` — and
|
|
26181
|
+
* the opposite of `ptz.savePreset` / `snapshot.invalidateCache`, which are
|
|
26182
|
+
* `admin` because they change what the device IS.
|
|
26183
|
+
*
|
|
26184
|
+
* `protected` does not mean ungated: `protectedProcedure` runs the
|
|
26185
|
+
* `METHOD_ACCESS_MAP` scope check, and every method here is `scope: 'device'`
|
|
26186
|
+
* with `access: 'create'` and a `deviceId` in its input. So a caller needs a
|
|
26187
|
+
* grant that covers THAT camera at `create` — a `camera-viewer` (`view`
|
|
26188
|
+
* only) still cannot talk, and a grant on camera 5 cannot talk through
|
|
26189
|
+
* camera 7.
|
|
26190
|
+
*
|
|
26191
|
+
* Every method was `auth: 'admin'` from the initial commit, which made the
|
|
26192
|
+
* cap unreachable by every non-admin principal — `adminProcedure` throws
|
|
26193
|
+
* `FORBIDDEN: Admin required` BEFORE the scope check runs, so the scope
|
|
26194
|
+
* machinery generated for this cap (`METHOD_ACCESS_MAP`,
|
|
26195
|
+
* `DEVICE_SCOPED_CAPS`, `METHOD_DEVICE_SELECTORS`) was complete and dead. The
|
|
26196
|
+
* `camera-operator` scope preset has promised "PTZ control, intercom,
|
|
26197
|
+
* snapshots" since that same commit; the promise could not be kept. Recorded
|
|
26198
|
+
* as D289; `scripts/check-scope-preset-promises.ts` now fails the build if a
|
|
26199
|
+
* preset promises a cap no row of that preset can reach.
|
|
26200
|
+
*/
|
|
26072
26201
|
methods: {
|
|
26073
26202
|
/**
|
|
26074
26203
|
* Open a server-side WebRTC audio-only session. Returns an SDP
|
|
@@ -26081,7 +26210,7 @@ var intercomCapability = {
|
|
|
26081
26210
|
sdpOffer: string()
|
|
26082
26211
|
}), {
|
|
26083
26212
|
kind: "mutation",
|
|
26084
|
-
auth: "
|
|
26213
|
+
auth: "protected"
|
|
26085
26214
|
}),
|
|
26086
26215
|
handleAnswer: method(object({
|
|
26087
26216
|
deviceId: number(),
|
|
@@ -26089,7 +26218,7 @@ var intercomCapability = {
|
|
|
26089
26218
|
sdpAnswer: string()
|
|
26090
26219
|
}), _void(), {
|
|
26091
26220
|
kind: "mutation",
|
|
26092
|
-
auth: "
|
|
26221
|
+
auth: "protected"
|
|
26093
26222
|
}),
|
|
26094
26223
|
/** Close explicitly. Server also auto-closes on 30s idle. */
|
|
26095
26224
|
stopSession: method(object({
|
|
@@ -26097,7 +26226,7 @@ var intercomCapability = {
|
|
|
26097
26226
|
sessionId: string()
|
|
26098
26227
|
}), _void(), {
|
|
26099
26228
|
kind: "mutation",
|
|
26100
|
-
auth: "
|
|
26229
|
+
auth: "protected"
|
|
26101
26230
|
}),
|
|
26102
26231
|
/**
|
|
26103
26232
|
* Open a raw-PCM talk session (no WebRTC SDP plumbing). Used by
|
|
@@ -26110,7 +26239,7 @@ var intercomCapability = {
|
|
|
26110
26239
|
*/
|
|
26111
26240
|
startTalkSession: method(object({ deviceId: number() }), object({ sessionId: string() }), {
|
|
26112
26241
|
kind: "mutation",
|
|
26113
|
-
auth: "
|
|
26242
|
+
auth: "protected"
|
|
26114
26243
|
}),
|
|
26115
26244
|
/**
|
|
26116
26245
|
* Push one chunk of talk-back audio onto the active talk session.
|
|
@@ -26145,12 +26274,12 @@ var intercomCapability = {
|
|
|
26145
26274
|
sequenceNumber: number().int()
|
|
26146
26275
|
}), object({ accepted: boolean() }), {
|
|
26147
26276
|
kind: "mutation",
|
|
26148
|
-
auth: "
|
|
26277
|
+
auth: "protected"
|
|
26149
26278
|
}),
|
|
26150
26279
|
/** Close the raw-PCM talk session. Idempotent. */
|
|
26151
26280
|
endTalkSession: method(object({ deviceId: number() }), _void(), {
|
|
26152
26281
|
kind: "mutation",
|
|
26153
|
-
auth: "
|
|
26282
|
+
auth: "protected"
|
|
26154
26283
|
})
|
|
26155
26284
|
},
|
|
26156
26285
|
events: { onStatusChanged: { data: object({
|
|
@@ -35831,6 +35960,12 @@ Object.freeze({
|
|
|
35831
35960
|
addonId: null,
|
|
35832
35961
|
access: "create"
|
|
35833
35962
|
},
|
|
35963
|
+
"pipelineAnalytics.countUnstampedEventMedia": {
|
|
35964
|
+
capName: "pipeline-analytics",
|
|
35965
|
+
capScope: "device",
|
|
35966
|
+
addonId: null,
|
|
35967
|
+
access: "view"
|
|
35968
|
+
},
|
|
35834
35969
|
"pipelineAnalytics.deleteDeviceEvents": {
|
|
35835
35970
|
capName: "pipeline-analytics",
|
|
35836
35971
|
capScope: "device",
|
package/dist/addon.mjs
CHANGED
|
@@ -9140,18 +9140,61 @@ var RelocateFootageInputSchema = object({
|
|
|
9140
9140
|
* `RecordingConfig.enabled` or camera wrapper bindings. */
|
|
9141
9141
|
var StorageMigrationLeaseInputSchema = object({ leaseId: string().min(1) });
|
|
9142
9142
|
var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: string().min(1) });
|
|
9143
|
+
/**
|
|
9144
|
+
* What a `relocateMedia` pass DOES. One engine, three passes — never a second
|
|
9145
|
+
* mover (the engine already walks both collections with a timestamp cursor and
|
|
9146
|
+
* already has a stamp-without-copy path).
|
|
9147
|
+
*
|
|
9148
|
+
* - `move` — the default and the historical behaviour: event-media and
|
|
9149
|
+
* retrain blobs move to `toLocationId` and their rows are
|
|
9150
|
+
* stamped. The enrolled gallery is skipped (D197).
|
|
9151
|
+
* - `seal` — ROWS ONLY, no bytes. Every row whose `locationId` is NULL is
|
|
9152
|
+
* stamped with `toLocationId`. `toLocationId` here is the id the
|
|
9153
|
+
* bytes ALREADY sit on — today's `eventMedia` default — because
|
|
9154
|
+
* a NULL row means "wherever `eventMedia` points *now*", and the
|
|
9155
|
+
* instant a repoint moves that pointer the row reads from the
|
|
9156
|
+
* new disk while its bytes are on the old one.
|
|
9157
|
+
* - `gallery` — the inverse selection of `move`: ONLY the retention-exempt
|
|
9158
|
+
* (enrolled-gallery) rows, which `move` deliberately skips.
|
|
9159
|
+
* `galleryMedia` is `cardinality: 'single'`, so this pass can
|
|
9160
|
+
* never run beside a live second location: it is stop-the-world
|
|
9161
|
+
* by construction, which is acceptable only because the gallery
|
|
9162
|
+
* is a few KB per enrolled sample.
|
|
9163
|
+
*/
|
|
9164
|
+
var MediaRelocateModeSchema = _enum([
|
|
9165
|
+
"move",
|
|
9166
|
+
"seal",
|
|
9167
|
+
"gallery"
|
|
9168
|
+
]);
|
|
9143
9169
|
var RelocateMediaInputSchema = object({
|
|
9144
9170
|
toLocationId: string(),
|
|
9145
|
-
throttleMbps: number().min(1).max(1e3).optional()
|
|
9171
|
+
throttleMbps: number().min(1).max(1e3).optional(),
|
|
9172
|
+
/** Omitted = `move`, the pre-existing behaviour. */
|
|
9173
|
+
mode: MediaRelocateModeSchema.optional()
|
|
9174
|
+
});
|
|
9175
|
+
/** How many rows still carry NO `locationId` — the population a repoint would
|
|
9176
|
+
* silently re-aim at a disk that does not hold their bytes. Zero is the only
|
|
9177
|
+
* value that permits a non-blocking `eventMedia` cutover. */
|
|
9178
|
+
var UnstampedEventMediaCountSchema = object({
|
|
9179
|
+
media: number().int().nonnegative(),
|
|
9180
|
+
retrainFrames: number().int().nonnegative(),
|
|
9181
|
+
total: number().int().nonnegative()
|
|
9146
9182
|
});
|
|
9147
9183
|
var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: string().min(1) });
|
|
9148
|
-
/** The independently selectable logical storage classes
|
|
9149
|
-
*
|
|
9150
|
-
*
|
|
9184
|
+
/** The independently selectable logical storage classes — every class
|
|
9185
|
+
* `storage.listLocationDeclarations` reports, so an operator never meets a
|
|
9186
|
+
* Zod enum error where they should meet an explanation.
|
|
9187
|
+
*
|
|
9188
|
+
* `recordings` encompasses the high and mid segment profiles; `recordingsLow`
|
|
9189
|
+
* is low segments; `eventMedia` is post-analysis blobs; `galleryMedia` is the
|
|
9190
|
+
* enrolled gallery; `backups` is the system backup archive. The last two have
|
|
9191
|
+
* their own rules — see {@link StorageMigrationFindingCodeSchema}. */
|
|
9151
9192
|
var StorageMigrationClassSchema = _enum([
|
|
9152
9193
|
"recordings",
|
|
9153
9194
|
"recordingsLow",
|
|
9154
|
-
"eventMedia"
|
|
9195
|
+
"eventMedia",
|
|
9196
|
+
"backups",
|
|
9197
|
+
"galleryMedia"
|
|
9155
9198
|
]);
|
|
9156
9199
|
/** A destination is always an existing, fully-qualified location id. The
|
|
9157
9200
|
* migration API intentionally never changes a source location's `basePath`:
|
|
@@ -9159,20 +9202,56 @@ var StorageMigrationClassSchema = _enum([
|
|
|
9159
9202
|
var StorageMigrationDestinationsSchema = object({
|
|
9160
9203
|
recordings: string().min(1).optional(),
|
|
9161
9204
|
recordingsLow: string().min(1).optional(),
|
|
9162
|
-
eventMedia: string().min(1).optional()
|
|
9205
|
+
eventMedia: string().min(1).optional(),
|
|
9206
|
+
backups: string().min(1).optional(),
|
|
9207
|
+
galleryMedia: string().min(1).optional()
|
|
9163
9208
|
}).refine((value) => Object.keys(value).length > 0, { message: "select at least one storage class" });
|
|
9209
|
+
/**
|
|
9210
|
+
* How a migration sequences the cutover against the byte move.
|
|
9211
|
+
*
|
|
9212
|
+
* - `blocking` — the historical order: pause, move every byte, repoint,
|
|
9213
|
+
* resume. Recording is stopped for the whole move. Right
|
|
9214
|
+
* for a small or a cold class, and the only legal mode for
|
|
9215
|
+
* a `cardinality: 'single'` class.
|
|
9216
|
+
* - `nonBlocking` — repoint FIRST, drain behind: seal, pause, repoint,
|
|
9217
|
+
* refresh, resume, then move the past with everything
|
|
9218
|
+
* running. The pause is three bounded instants (a detach +
|
|
9219
|
+
* attach round, a write-gate drain, a lease) instead of one
|
|
9220
|
+
* bounded by bytes. 1.09 TB at 7–14 MB/s is thirty hours of
|
|
9221
|
+
* stopped recording under `blocking`; the same move is
|
|
9222
|
+
* seconds of stopped recording under `nonBlocking`.
|
|
9223
|
+
*
|
|
9224
|
+
* The mode is on the JOB, not only on the input, because `status` is where an
|
|
9225
|
+
* operator finds out which one is running.
|
|
9226
|
+
*/
|
|
9227
|
+
var StorageMigrationModeSchema = _enum(["blocking", "nonBlocking"]);
|
|
9164
9228
|
/** Shared input for planning and starting an orchestrated storage migration. */
|
|
9165
9229
|
var StorageMigrationInputSchema = object({
|
|
9166
9230
|
destinations: StorageMigrationDestinationsSchema,
|
|
9167
|
-
throttleMbps: number().min(1).max(1e3).optional()
|
|
9231
|
+
throttleMbps: number().min(1).max(1e3).optional(),
|
|
9232
|
+
/** Omitted = `blocking`, which stays the default. */
|
|
9233
|
+
mode: StorageMigrationModeSchema.optional()
|
|
9168
9234
|
});
|
|
9169
|
-
/**
|
|
9170
|
-
*
|
|
9171
|
-
*
|
|
9235
|
+
/**
|
|
9236
|
+
* The durable coordinator state machine.
|
|
9237
|
+
*
|
|
9238
|
+
* `blocking`:
|
|
9239
|
+
* planning → pausing → moving → verifying → repointing → refreshing → resuming → done
|
|
9240
|
+
*
|
|
9241
|
+
* `nonBlocking`:
|
|
9242
|
+
* planning → sealing → pausing → repointing → refreshing → resuming → draining → verifying → done
|
|
9243
|
+
*
|
|
9244
|
+
* Same phases, different order plus two new ones — not a second mover.
|
|
9245
|
+
* `sealing` closes the `eventMedia` NULL-row hole BEFORE anything is paused;
|
|
9246
|
+
* `draining` runs the same movers UNLEASED, after every writer is back up.
|
|
9247
|
+
* `repointing` is still the only phase that changes a default location.
|
|
9248
|
+
*/
|
|
9172
9249
|
var StorageMigrationPhaseSchema = _enum([
|
|
9173
9250
|
"planning",
|
|
9251
|
+
"sealing",
|
|
9174
9252
|
"pausing",
|
|
9175
9253
|
"moving",
|
|
9254
|
+
"draining",
|
|
9176
9255
|
"verifying",
|
|
9177
9256
|
"repointing",
|
|
9178
9257
|
"refreshing",
|
|
@@ -9197,6 +9276,9 @@ var StorageMigrationMoveSchema = object({
|
|
|
9197
9276
|
var StorageMigrationJobSchema = object({
|
|
9198
9277
|
jobId: string(),
|
|
9199
9278
|
phase: StorageMigrationPhaseSchema,
|
|
9279
|
+
/** Which order this job is running. `status` is the only place an operator
|
|
9280
|
+
* can tell a seconds-long cutover from a thirty-hour one. */
|
|
9281
|
+
mode: StorageMigrationModeSchema,
|
|
9200
9282
|
destinations: StorageMigrationDestinationsSchema,
|
|
9201
9283
|
throttleMbps: number(),
|
|
9202
9284
|
moves: array(StorageMigrationMoveSchema),
|
|
@@ -9209,13 +9291,30 @@ var StorageMigrationJobSchema = object({
|
|
|
9209
9291
|
finishedAt: number().nullable(),
|
|
9210
9292
|
error: string().nullable()
|
|
9211
9293
|
});
|
|
9294
|
+
var StorageMigrationFindingSchema = object({
|
|
9295
|
+
code: _enum([
|
|
9296
|
+
"sharesDeviceWithSource",
|
|
9297
|
+
"deviceIdentityUnknown",
|
|
9298
|
+
"unstampedEventMediaRows",
|
|
9299
|
+
"blockingOnly",
|
|
9300
|
+
"noMover"
|
|
9301
|
+
]),
|
|
9302
|
+
storageClass: StorageMigrationClassSchema,
|
|
9303
|
+
/** Human-readable, already carrying the ids and counts. */
|
|
9304
|
+
message: string()
|
|
9305
|
+
});
|
|
9212
9306
|
var StorageMigrationPlanSchema = object({
|
|
9213
9307
|
destinations: StorageMigrationDestinationsSchema,
|
|
9308
|
+
/** The mode this plan was built for. A plan is only valid for its mode: the
|
|
9309
|
+
* `eventMedia` seal gate and the single-cardinality refusal both depend on
|
|
9310
|
+
* it. */
|
|
9311
|
+
mode: StorageMigrationModeSchema,
|
|
9214
9312
|
moves: array(object({
|
|
9215
9313
|
storageClass: StorageMigrationClassSchema,
|
|
9216
9314
|
fromLocationId: string(),
|
|
9217
9315
|
toLocationId: string()
|
|
9218
|
-
}))
|
|
9316
|
+
})),
|
|
9317
|
+
findings: array(StorageMigrationFindingSchema)
|
|
9219
9318
|
});
|
|
9220
9319
|
/**
|
|
9221
9320
|
* `StorageLocationType` — an addon-declared id that identifies the *kind* of
|
|
@@ -20085,7 +20184,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
20085
20184
|
}), method(RelocateMediaInputSchema, object({ jobId: string() }), {
|
|
20086
20185
|
kind: "mutation",
|
|
20087
20186
|
auth: "admin"
|
|
20088
|
-
}), method(object({}), array(RelocateJobSchema).readonly(), {
|
|
20187
|
+
}), method(object({}), UnstampedEventMediaCountSchema, { auth: "admin" }), method(object({}), array(RelocateJobSchema).readonly(), {
|
|
20089
20188
|
kind: "query",
|
|
20090
20189
|
auth: "admin"
|
|
20091
20190
|
}), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
@@ -21992,7 +22091,10 @@ method(object({
|
|
|
21992
22091
|
}), StorageLocationSchema, {
|
|
21993
22092
|
kind: "mutation",
|
|
21994
22093
|
auth: "admin"
|
|
21995
|
-
}), method(object({
|
|
22094
|
+
}), method(object({
|
|
22095
|
+
id: string(),
|
|
22096
|
+
force: boolean().optional()
|
|
22097
|
+
}), _void(), {
|
|
21996
22098
|
kind: "mutation",
|
|
21997
22099
|
auth: "admin"
|
|
21998
22100
|
}), method(object({ id: string() }), object({
|
|
@@ -26068,6 +26170,33 @@ var intercomCapability = {
|
|
|
26068
26170
|
deviceNative: true,
|
|
26069
26171
|
mode: "singleton",
|
|
26070
26172
|
deviceTypes: [DeviceType.Camera],
|
|
26173
|
+
/**
|
|
26174
|
+
* **Auth tier: `protected` on every method — deliberate, and load-bearing.**
|
|
26175
|
+
*
|
|
26176
|
+
* Talking through a camera is an OPERATE action, not a CONFIGURE one. This
|
|
26177
|
+
* cap has no configuration surface at all: all six methods open, feed and
|
|
26178
|
+
* close one live audio session against one `deviceId`. That is the same
|
|
26179
|
+
* authority as `ptz.move` or `snapshot.getSnapshot`, both `protected` — and
|
|
26180
|
+
* the opposite of `ptz.savePreset` / `snapshot.invalidateCache`, which are
|
|
26181
|
+
* `admin` because they change what the device IS.
|
|
26182
|
+
*
|
|
26183
|
+
* `protected` does not mean ungated: `protectedProcedure` runs the
|
|
26184
|
+
* `METHOD_ACCESS_MAP` scope check, and every method here is `scope: 'device'`
|
|
26185
|
+
* with `access: 'create'` and a `deviceId` in its input. So a caller needs a
|
|
26186
|
+
* grant that covers THAT camera at `create` — a `camera-viewer` (`view`
|
|
26187
|
+
* only) still cannot talk, and a grant on camera 5 cannot talk through
|
|
26188
|
+
* camera 7.
|
|
26189
|
+
*
|
|
26190
|
+
* Every method was `auth: 'admin'` from the initial commit, which made the
|
|
26191
|
+
* cap unreachable by every non-admin principal — `adminProcedure` throws
|
|
26192
|
+
* `FORBIDDEN: Admin required` BEFORE the scope check runs, so the scope
|
|
26193
|
+
* machinery generated for this cap (`METHOD_ACCESS_MAP`,
|
|
26194
|
+
* `DEVICE_SCOPED_CAPS`, `METHOD_DEVICE_SELECTORS`) was complete and dead. The
|
|
26195
|
+
* `camera-operator` scope preset has promised "PTZ control, intercom,
|
|
26196
|
+
* snapshots" since that same commit; the promise could not be kept. Recorded
|
|
26197
|
+
* as D289; `scripts/check-scope-preset-promises.ts` now fails the build if a
|
|
26198
|
+
* preset promises a cap no row of that preset can reach.
|
|
26199
|
+
*/
|
|
26071
26200
|
methods: {
|
|
26072
26201
|
/**
|
|
26073
26202
|
* Open a server-side WebRTC audio-only session. Returns an SDP
|
|
@@ -26080,7 +26209,7 @@ var intercomCapability = {
|
|
|
26080
26209
|
sdpOffer: string()
|
|
26081
26210
|
}), {
|
|
26082
26211
|
kind: "mutation",
|
|
26083
|
-
auth: "
|
|
26212
|
+
auth: "protected"
|
|
26084
26213
|
}),
|
|
26085
26214
|
handleAnswer: method(object({
|
|
26086
26215
|
deviceId: number(),
|
|
@@ -26088,7 +26217,7 @@ var intercomCapability = {
|
|
|
26088
26217
|
sdpAnswer: string()
|
|
26089
26218
|
}), _void(), {
|
|
26090
26219
|
kind: "mutation",
|
|
26091
|
-
auth: "
|
|
26220
|
+
auth: "protected"
|
|
26092
26221
|
}),
|
|
26093
26222
|
/** Close explicitly. Server also auto-closes on 30s idle. */
|
|
26094
26223
|
stopSession: method(object({
|
|
@@ -26096,7 +26225,7 @@ var intercomCapability = {
|
|
|
26096
26225
|
sessionId: string()
|
|
26097
26226
|
}), _void(), {
|
|
26098
26227
|
kind: "mutation",
|
|
26099
|
-
auth: "
|
|
26228
|
+
auth: "protected"
|
|
26100
26229
|
}),
|
|
26101
26230
|
/**
|
|
26102
26231
|
* Open a raw-PCM talk session (no WebRTC SDP plumbing). Used by
|
|
@@ -26109,7 +26238,7 @@ var intercomCapability = {
|
|
|
26109
26238
|
*/
|
|
26110
26239
|
startTalkSession: method(object({ deviceId: number() }), object({ sessionId: string() }), {
|
|
26111
26240
|
kind: "mutation",
|
|
26112
|
-
auth: "
|
|
26241
|
+
auth: "protected"
|
|
26113
26242
|
}),
|
|
26114
26243
|
/**
|
|
26115
26244
|
* Push one chunk of talk-back audio onto the active talk session.
|
|
@@ -26144,12 +26273,12 @@ var intercomCapability = {
|
|
|
26144
26273
|
sequenceNumber: number().int()
|
|
26145
26274
|
}), object({ accepted: boolean() }), {
|
|
26146
26275
|
kind: "mutation",
|
|
26147
|
-
auth: "
|
|
26276
|
+
auth: "protected"
|
|
26148
26277
|
}),
|
|
26149
26278
|
/** Close the raw-PCM talk session. Idempotent. */
|
|
26150
26279
|
endTalkSession: method(object({ deviceId: number() }), _void(), {
|
|
26151
26280
|
kind: "mutation",
|
|
26152
|
-
auth: "
|
|
26281
|
+
auth: "protected"
|
|
26153
26282
|
})
|
|
26154
26283
|
},
|
|
26155
26284
|
events: { onStatusChanged: { data: object({
|
|
@@ -35830,6 +35959,12 @@ Object.freeze({
|
|
|
35830
35959
|
addonId: null,
|
|
35831
35960
|
access: "create"
|
|
35832
35961
|
},
|
|
35962
|
+
"pipelineAnalytics.countUnstampedEventMedia": {
|
|
35963
|
+
capName: "pipeline-analytics",
|
|
35964
|
+
capScope: "device",
|
|
35965
|
+
addonId: null,
|
|
35966
|
+
access: "view"
|
|
35967
|
+
},
|
|
35833
35968
|
"pipelineAnalytics.deleteDeviceEvents": {
|
|
35834
35969
|
capName: "pipeline-analytics",
|
|
35835
35970
|
capScope: "device",
|
package/package.json
CHANGED