@camstack/addon-provider-dreo 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
|
@@ -8075,18 +8075,61 @@ var RelocateFootageInputSchema = object({
|
|
|
8075
8075
|
* `RecordingConfig.enabled` or camera wrapper bindings. */
|
|
8076
8076
|
var StorageMigrationLeaseInputSchema = object({ leaseId: string().min(1) });
|
|
8077
8077
|
var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: string().min(1) });
|
|
8078
|
+
/**
|
|
8079
|
+
* What a `relocateMedia` pass DOES. One engine, three passes — never a second
|
|
8080
|
+
* mover (the engine already walks both collections with a timestamp cursor and
|
|
8081
|
+
* already has a stamp-without-copy path).
|
|
8082
|
+
*
|
|
8083
|
+
* - `move` — the default and the historical behaviour: event-media and
|
|
8084
|
+
* retrain blobs move to `toLocationId` and their rows are
|
|
8085
|
+
* stamped. The enrolled gallery is skipped (D197).
|
|
8086
|
+
* - `seal` — ROWS ONLY, no bytes. Every row whose `locationId` is NULL is
|
|
8087
|
+
* stamped with `toLocationId`. `toLocationId` here is the id the
|
|
8088
|
+
* bytes ALREADY sit on — today's `eventMedia` default — because
|
|
8089
|
+
* a NULL row means "wherever `eventMedia` points *now*", and the
|
|
8090
|
+
* instant a repoint moves that pointer the row reads from the
|
|
8091
|
+
* new disk while its bytes are on the old one.
|
|
8092
|
+
* - `gallery` — the inverse selection of `move`: ONLY the retention-exempt
|
|
8093
|
+
* (enrolled-gallery) rows, which `move` deliberately skips.
|
|
8094
|
+
* `galleryMedia` is `cardinality: 'single'`, so this pass can
|
|
8095
|
+
* never run beside a live second location: it is stop-the-world
|
|
8096
|
+
* by construction, which is acceptable only because the gallery
|
|
8097
|
+
* is a few KB per enrolled sample.
|
|
8098
|
+
*/
|
|
8099
|
+
var MediaRelocateModeSchema = _enum([
|
|
8100
|
+
"move",
|
|
8101
|
+
"seal",
|
|
8102
|
+
"gallery"
|
|
8103
|
+
]);
|
|
8078
8104
|
var RelocateMediaInputSchema = object({
|
|
8079
8105
|
toLocationId: string(),
|
|
8080
|
-
throttleMbps: number().min(1).max(1e3).optional()
|
|
8106
|
+
throttleMbps: number().min(1).max(1e3).optional(),
|
|
8107
|
+
/** Omitted = `move`, the pre-existing behaviour. */
|
|
8108
|
+
mode: MediaRelocateModeSchema.optional()
|
|
8109
|
+
});
|
|
8110
|
+
/** How many rows still carry NO `locationId` — the population a repoint would
|
|
8111
|
+
* silently re-aim at a disk that does not hold their bytes. Zero is the only
|
|
8112
|
+
* value that permits a non-blocking `eventMedia` cutover. */
|
|
8113
|
+
var UnstampedEventMediaCountSchema = object({
|
|
8114
|
+
media: number().int().nonnegative(),
|
|
8115
|
+
retrainFrames: number().int().nonnegative(),
|
|
8116
|
+
total: number().int().nonnegative()
|
|
8081
8117
|
});
|
|
8082
8118
|
var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: string().min(1) });
|
|
8083
|
-
/** The independently selectable logical storage classes
|
|
8084
|
-
*
|
|
8085
|
-
*
|
|
8119
|
+
/** The independently selectable logical storage classes — every class
|
|
8120
|
+
* `storage.listLocationDeclarations` reports, so an operator never meets a
|
|
8121
|
+
* Zod enum error where they should meet an explanation.
|
|
8122
|
+
*
|
|
8123
|
+
* `recordings` encompasses the high and mid segment profiles; `recordingsLow`
|
|
8124
|
+
* is low segments; `eventMedia` is post-analysis blobs; `galleryMedia` is the
|
|
8125
|
+
* enrolled gallery; `backups` is the system backup archive. The last two have
|
|
8126
|
+
* their own rules — see {@link StorageMigrationFindingCodeSchema}. */
|
|
8086
8127
|
var StorageMigrationClassSchema = _enum([
|
|
8087
8128
|
"recordings",
|
|
8088
8129
|
"recordingsLow",
|
|
8089
|
-
"eventMedia"
|
|
8130
|
+
"eventMedia",
|
|
8131
|
+
"backups",
|
|
8132
|
+
"galleryMedia"
|
|
8090
8133
|
]);
|
|
8091
8134
|
/** A destination is always an existing, fully-qualified location id. The
|
|
8092
8135
|
* migration API intentionally never changes a source location's `basePath`:
|
|
@@ -8094,20 +8137,56 @@ var StorageMigrationClassSchema = _enum([
|
|
|
8094
8137
|
var StorageMigrationDestinationsSchema = object({
|
|
8095
8138
|
recordings: string().min(1).optional(),
|
|
8096
8139
|
recordingsLow: string().min(1).optional(),
|
|
8097
|
-
eventMedia: string().min(1).optional()
|
|
8140
|
+
eventMedia: string().min(1).optional(),
|
|
8141
|
+
backups: string().min(1).optional(),
|
|
8142
|
+
galleryMedia: string().min(1).optional()
|
|
8098
8143
|
}).refine((value) => Object.keys(value).length > 0, { message: "select at least one storage class" });
|
|
8144
|
+
/**
|
|
8145
|
+
* How a migration sequences the cutover against the byte move.
|
|
8146
|
+
*
|
|
8147
|
+
* - `blocking` — the historical order: pause, move every byte, repoint,
|
|
8148
|
+
* resume. Recording is stopped for the whole move. Right
|
|
8149
|
+
* for a small or a cold class, and the only legal mode for
|
|
8150
|
+
* a `cardinality: 'single'` class.
|
|
8151
|
+
* - `nonBlocking` — repoint FIRST, drain behind: seal, pause, repoint,
|
|
8152
|
+
* refresh, resume, then move the past with everything
|
|
8153
|
+
* running. The pause is three bounded instants (a detach +
|
|
8154
|
+
* attach round, a write-gate drain, a lease) instead of one
|
|
8155
|
+
* bounded by bytes. 1.09 TB at 7–14 MB/s is thirty hours of
|
|
8156
|
+
* stopped recording under `blocking`; the same move is
|
|
8157
|
+
* seconds of stopped recording under `nonBlocking`.
|
|
8158
|
+
*
|
|
8159
|
+
* The mode is on the JOB, not only on the input, because `status` is where an
|
|
8160
|
+
* operator finds out which one is running.
|
|
8161
|
+
*/
|
|
8162
|
+
var StorageMigrationModeSchema = _enum(["blocking", "nonBlocking"]);
|
|
8099
8163
|
/** Shared input for planning and starting an orchestrated storage migration. */
|
|
8100
8164
|
var StorageMigrationInputSchema = object({
|
|
8101
8165
|
destinations: StorageMigrationDestinationsSchema,
|
|
8102
|
-
throttleMbps: number().min(1).max(1e3).optional()
|
|
8166
|
+
throttleMbps: number().min(1).max(1e3).optional(),
|
|
8167
|
+
/** Omitted = `blocking`, which stays the default. */
|
|
8168
|
+
mode: StorageMigrationModeSchema.optional()
|
|
8103
8169
|
});
|
|
8104
|
-
/**
|
|
8105
|
-
*
|
|
8106
|
-
*
|
|
8170
|
+
/**
|
|
8171
|
+
* The durable coordinator state machine.
|
|
8172
|
+
*
|
|
8173
|
+
* `blocking`:
|
|
8174
|
+
* planning → pausing → moving → verifying → repointing → refreshing → resuming → done
|
|
8175
|
+
*
|
|
8176
|
+
* `nonBlocking`:
|
|
8177
|
+
* planning → sealing → pausing → repointing → refreshing → resuming → draining → verifying → done
|
|
8178
|
+
*
|
|
8179
|
+
* Same phases, different order plus two new ones — not a second mover.
|
|
8180
|
+
* `sealing` closes the `eventMedia` NULL-row hole BEFORE anything is paused;
|
|
8181
|
+
* `draining` runs the same movers UNLEASED, after every writer is back up.
|
|
8182
|
+
* `repointing` is still the only phase that changes a default location.
|
|
8183
|
+
*/
|
|
8107
8184
|
var StorageMigrationPhaseSchema = _enum([
|
|
8108
8185
|
"planning",
|
|
8186
|
+
"sealing",
|
|
8109
8187
|
"pausing",
|
|
8110
8188
|
"moving",
|
|
8189
|
+
"draining",
|
|
8111
8190
|
"verifying",
|
|
8112
8191
|
"repointing",
|
|
8113
8192
|
"refreshing",
|
|
@@ -8132,6 +8211,9 @@ var StorageMigrationMoveSchema = object({
|
|
|
8132
8211
|
var StorageMigrationJobSchema = object({
|
|
8133
8212
|
jobId: string(),
|
|
8134
8213
|
phase: StorageMigrationPhaseSchema,
|
|
8214
|
+
/** Which order this job is running. `status` is the only place an operator
|
|
8215
|
+
* can tell a seconds-long cutover from a thirty-hour one. */
|
|
8216
|
+
mode: StorageMigrationModeSchema,
|
|
8135
8217
|
destinations: StorageMigrationDestinationsSchema,
|
|
8136
8218
|
throttleMbps: number(),
|
|
8137
8219
|
moves: array(StorageMigrationMoveSchema),
|
|
@@ -8144,13 +8226,30 @@ var StorageMigrationJobSchema = object({
|
|
|
8144
8226
|
finishedAt: number().nullable(),
|
|
8145
8227
|
error: string().nullable()
|
|
8146
8228
|
});
|
|
8229
|
+
var StorageMigrationFindingSchema = object({
|
|
8230
|
+
code: _enum([
|
|
8231
|
+
"sharesDeviceWithSource",
|
|
8232
|
+
"deviceIdentityUnknown",
|
|
8233
|
+
"unstampedEventMediaRows",
|
|
8234
|
+
"blockingOnly",
|
|
8235
|
+
"noMover"
|
|
8236
|
+
]),
|
|
8237
|
+
storageClass: StorageMigrationClassSchema,
|
|
8238
|
+
/** Human-readable, already carrying the ids and counts. */
|
|
8239
|
+
message: string()
|
|
8240
|
+
});
|
|
8147
8241
|
var StorageMigrationPlanSchema = object({
|
|
8148
8242
|
destinations: StorageMigrationDestinationsSchema,
|
|
8243
|
+
/** The mode this plan was built for. A plan is only valid for its mode: the
|
|
8244
|
+
* `eventMedia` seal gate and the single-cardinality refusal both depend on
|
|
8245
|
+
* it. */
|
|
8246
|
+
mode: StorageMigrationModeSchema,
|
|
8149
8247
|
moves: array(object({
|
|
8150
8248
|
storageClass: StorageMigrationClassSchema,
|
|
8151
8249
|
fromLocationId: string(),
|
|
8152
8250
|
toLocationId: string()
|
|
8153
|
-
}))
|
|
8251
|
+
})),
|
|
8252
|
+
findings: array(StorageMigrationFindingSchema)
|
|
8154
8253
|
});
|
|
8155
8254
|
/**
|
|
8156
8255
|
* `StorageLocationType` — an addon-declared id that identifies the *kind* of
|
|
@@ -19020,7 +19119,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
19020
19119
|
}), method(RelocateMediaInputSchema, object({ jobId: string() }), {
|
|
19021
19120
|
kind: "mutation",
|
|
19022
19121
|
auth: "admin"
|
|
19023
|
-
}), method(object({}), array(RelocateJobSchema).readonly(), {
|
|
19122
|
+
}), method(object({}), UnstampedEventMediaCountSchema, { auth: "admin" }), method(object({}), array(RelocateJobSchema).readonly(), {
|
|
19024
19123
|
kind: "query",
|
|
19025
19124
|
auth: "admin"
|
|
19026
19125
|
}), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
@@ -20927,7 +21026,10 @@ method(object({
|
|
|
20927
21026
|
}), StorageLocationSchema, {
|
|
20928
21027
|
kind: "mutation",
|
|
20929
21028
|
auth: "admin"
|
|
20930
|
-
}), method(object({
|
|
21029
|
+
}), method(object({
|
|
21030
|
+
id: string(),
|
|
21031
|
+
force: boolean().optional()
|
|
21032
|
+
}), _void(), {
|
|
20931
21033
|
kind: "mutation",
|
|
20932
21034
|
auth: "admin"
|
|
20933
21035
|
}), method(object({ id: string() }), object({
|
|
@@ -25003,6 +25105,33 @@ var intercomCapability = {
|
|
|
25003
25105
|
deviceNative: true,
|
|
25004
25106
|
mode: "singleton",
|
|
25005
25107
|
deviceTypes: [DeviceType.Camera],
|
|
25108
|
+
/**
|
|
25109
|
+
* **Auth tier: `protected` on every method — deliberate, and load-bearing.**
|
|
25110
|
+
*
|
|
25111
|
+
* Talking through a camera is an OPERATE action, not a CONFIGURE one. This
|
|
25112
|
+
* cap has no configuration surface at all: all six methods open, feed and
|
|
25113
|
+
* close one live audio session against one `deviceId`. That is the same
|
|
25114
|
+
* authority as `ptz.move` or `snapshot.getSnapshot`, both `protected` — and
|
|
25115
|
+
* the opposite of `ptz.savePreset` / `snapshot.invalidateCache`, which are
|
|
25116
|
+
* `admin` because they change what the device IS.
|
|
25117
|
+
*
|
|
25118
|
+
* `protected` does not mean ungated: `protectedProcedure` runs the
|
|
25119
|
+
* `METHOD_ACCESS_MAP` scope check, and every method here is `scope: 'device'`
|
|
25120
|
+
* with `access: 'create'` and a `deviceId` in its input. So a caller needs a
|
|
25121
|
+
* grant that covers THAT camera at `create` — a `camera-viewer` (`view`
|
|
25122
|
+
* only) still cannot talk, and a grant on camera 5 cannot talk through
|
|
25123
|
+
* camera 7.
|
|
25124
|
+
*
|
|
25125
|
+
* Every method was `auth: 'admin'` from the initial commit, which made the
|
|
25126
|
+
* cap unreachable by every non-admin principal — `adminProcedure` throws
|
|
25127
|
+
* `FORBIDDEN: Admin required` BEFORE the scope check runs, so the scope
|
|
25128
|
+
* machinery generated for this cap (`METHOD_ACCESS_MAP`,
|
|
25129
|
+
* `DEVICE_SCOPED_CAPS`, `METHOD_DEVICE_SELECTORS`) was complete and dead. The
|
|
25130
|
+
* `camera-operator` scope preset has promised "PTZ control, intercom,
|
|
25131
|
+
* snapshots" since that same commit; the promise could not be kept. Recorded
|
|
25132
|
+
* as D289; `scripts/check-scope-preset-promises.ts` now fails the build if a
|
|
25133
|
+
* preset promises a cap no row of that preset can reach.
|
|
25134
|
+
*/
|
|
25006
25135
|
methods: {
|
|
25007
25136
|
/**
|
|
25008
25137
|
* Open a server-side WebRTC audio-only session. Returns an SDP
|
|
@@ -25015,7 +25144,7 @@ var intercomCapability = {
|
|
|
25015
25144
|
sdpOffer: string()
|
|
25016
25145
|
}), {
|
|
25017
25146
|
kind: "mutation",
|
|
25018
|
-
auth: "
|
|
25147
|
+
auth: "protected"
|
|
25019
25148
|
}),
|
|
25020
25149
|
handleAnswer: method(object({
|
|
25021
25150
|
deviceId: number(),
|
|
@@ -25023,7 +25152,7 @@ var intercomCapability = {
|
|
|
25023
25152
|
sdpAnswer: string()
|
|
25024
25153
|
}), _void(), {
|
|
25025
25154
|
kind: "mutation",
|
|
25026
|
-
auth: "
|
|
25155
|
+
auth: "protected"
|
|
25027
25156
|
}),
|
|
25028
25157
|
/** Close explicitly. Server also auto-closes on 30s idle. */
|
|
25029
25158
|
stopSession: method(object({
|
|
@@ -25031,7 +25160,7 @@ var intercomCapability = {
|
|
|
25031
25160
|
sessionId: string()
|
|
25032
25161
|
}), _void(), {
|
|
25033
25162
|
kind: "mutation",
|
|
25034
|
-
auth: "
|
|
25163
|
+
auth: "protected"
|
|
25035
25164
|
}),
|
|
25036
25165
|
/**
|
|
25037
25166
|
* Open a raw-PCM talk session (no WebRTC SDP plumbing). Used by
|
|
@@ -25044,7 +25173,7 @@ var intercomCapability = {
|
|
|
25044
25173
|
*/
|
|
25045
25174
|
startTalkSession: method(object({ deviceId: number() }), object({ sessionId: string() }), {
|
|
25046
25175
|
kind: "mutation",
|
|
25047
|
-
auth: "
|
|
25176
|
+
auth: "protected"
|
|
25048
25177
|
}),
|
|
25049
25178
|
/**
|
|
25050
25179
|
* Push one chunk of talk-back audio onto the active talk session.
|
|
@@ -25079,12 +25208,12 @@ var intercomCapability = {
|
|
|
25079
25208
|
sequenceNumber: number().int()
|
|
25080
25209
|
}), object({ accepted: boolean() }), {
|
|
25081
25210
|
kind: "mutation",
|
|
25082
|
-
auth: "
|
|
25211
|
+
auth: "protected"
|
|
25083
25212
|
}),
|
|
25084
25213
|
/** Close the raw-PCM talk session. Idempotent. */
|
|
25085
25214
|
endTalkSession: method(object({ deviceId: number() }), _void(), {
|
|
25086
25215
|
kind: "mutation",
|
|
25087
|
-
auth: "
|
|
25216
|
+
auth: "protected"
|
|
25088
25217
|
})
|
|
25089
25218
|
},
|
|
25090
25219
|
events: { onStatusChanged: { data: object({
|
|
@@ -34765,6 +34894,12 @@ Object.freeze({
|
|
|
34765
34894
|
addonId: null,
|
|
34766
34895
|
access: "create"
|
|
34767
34896
|
},
|
|
34897
|
+
"pipelineAnalytics.countUnstampedEventMedia": {
|
|
34898
|
+
capName: "pipeline-analytics",
|
|
34899
|
+
capScope: "device",
|
|
34900
|
+
addonId: null,
|
|
34901
|
+
access: "view"
|
|
34902
|
+
},
|
|
34768
34903
|
"pipelineAnalytics.deleteDeviceEvents": {
|
|
34769
34904
|
capName: "pipeline-analytics",
|
|
34770
34905
|
capScope: "device",
|
package/dist/addon.mjs
CHANGED
|
@@ -8076,18 +8076,61 @@ var RelocateFootageInputSchema = object({
|
|
|
8076
8076
|
* `RecordingConfig.enabled` or camera wrapper bindings. */
|
|
8077
8077
|
var StorageMigrationLeaseInputSchema = object({ leaseId: string().min(1) });
|
|
8078
8078
|
var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: string().min(1) });
|
|
8079
|
+
/**
|
|
8080
|
+
* What a `relocateMedia` pass DOES. One engine, three passes — never a second
|
|
8081
|
+
* mover (the engine already walks both collections with a timestamp cursor and
|
|
8082
|
+
* already has a stamp-without-copy path).
|
|
8083
|
+
*
|
|
8084
|
+
* - `move` — the default and the historical behaviour: event-media and
|
|
8085
|
+
* retrain blobs move to `toLocationId` and their rows are
|
|
8086
|
+
* stamped. The enrolled gallery is skipped (D197).
|
|
8087
|
+
* - `seal` — ROWS ONLY, no bytes. Every row whose `locationId` is NULL is
|
|
8088
|
+
* stamped with `toLocationId`. `toLocationId` here is the id the
|
|
8089
|
+
* bytes ALREADY sit on — today's `eventMedia` default — because
|
|
8090
|
+
* a NULL row means "wherever `eventMedia` points *now*", and the
|
|
8091
|
+
* instant a repoint moves that pointer the row reads from the
|
|
8092
|
+
* new disk while its bytes are on the old one.
|
|
8093
|
+
* - `gallery` — the inverse selection of `move`: ONLY the retention-exempt
|
|
8094
|
+
* (enrolled-gallery) rows, which `move` deliberately skips.
|
|
8095
|
+
* `galleryMedia` is `cardinality: 'single'`, so this pass can
|
|
8096
|
+
* never run beside a live second location: it is stop-the-world
|
|
8097
|
+
* by construction, which is acceptable only because the gallery
|
|
8098
|
+
* is a few KB per enrolled sample.
|
|
8099
|
+
*/
|
|
8100
|
+
var MediaRelocateModeSchema = _enum([
|
|
8101
|
+
"move",
|
|
8102
|
+
"seal",
|
|
8103
|
+
"gallery"
|
|
8104
|
+
]);
|
|
8079
8105
|
var RelocateMediaInputSchema = object({
|
|
8080
8106
|
toLocationId: string(),
|
|
8081
|
-
throttleMbps: number().min(1).max(1e3).optional()
|
|
8107
|
+
throttleMbps: number().min(1).max(1e3).optional(),
|
|
8108
|
+
/** Omitted = `move`, the pre-existing behaviour. */
|
|
8109
|
+
mode: MediaRelocateModeSchema.optional()
|
|
8110
|
+
});
|
|
8111
|
+
/** How many rows still carry NO `locationId` — the population a repoint would
|
|
8112
|
+
* silently re-aim at a disk that does not hold their bytes. Zero is the only
|
|
8113
|
+
* value that permits a non-blocking `eventMedia` cutover. */
|
|
8114
|
+
var UnstampedEventMediaCountSchema = object({
|
|
8115
|
+
media: number().int().nonnegative(),
|
|
8116
|
+
retrainFrames: number().int().nonnegative(),
|
|
8117
|
+
total: number().int().nonnegative()
|
|
8082
8118
|
});
|
|
8083
8119
|
var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: string().min(1) });
|
|
8084
|
-
/** The independently selectable logical storage classes
|
|
8085
|
-
*
|
|
8086
|
-
*
|
|
8120
|
+
/** The independently selectable logical storage classes — every class
|
|
8121
|
+
* `storage.listLocationDeclarations` reports, so an operator never meets a
|
|
8122
|
+
* Zod enum error where they should meet an explanation.
|
|
8123
|
+
*
|
|
8124
|
+
* `recordings` encompasses the high and mid segment profiles; `recordingsLow`
|
|
8125
|
+
* is low segments; `eventMedia` is post-analysis blobs; `galleryMedia` is the
|
|
8126
|
+
* enrolled gallery; `backups` is the system backup archive. The last two have
|
|
8127
|
+
* their own rules — see {@link StorageMigrationFindingCodeSchema}. */
|
|
8087
8128
|
var StorageMigrationClassSchema = _enum([
|
|
8088
8129
|
"recordings",
|
|
8089
8130
|
"recordingsLow",
|
|
8090
|
-
"eventMedia"
|
|
8131
|
+
"eventMedia",
|
|
8132
|
+
"backups",
|
|
8133
|
+
"galleryMedia"
|
|
8091
8134
|
]);
|
|
8092
8135
|
/** A destination is always an existing, fully-qualified location id. The
|
|
8093
8136
|
* migration API intentionally never changes a source location's `basePath`:
|
|
@@ -8095,20 +8138,56 @@ var StorageMigrationClassSchema = _enum([
|
|
|
8095
8138
|
var StorageMigrationDestinationsSchema = object({
|
|
8096
8139
|
recordings: string().min(1).optional(),
|
|
8097
8140
|
recordingsLow: string().min(1).optional(),
|
|
8098
|
-
eventMedia: string().min(1).optional()
|
|
8141
|
+
eventMedia: string().min(1).optional(),
|
|
8142
|
+
backups: string().min(1).optional(),
|
|
8143
|
+
galleryMedia: string().min(1).optional()
|
|
8099
8144
|
}).refine((value) => Object.keys(value).length > 0, { message: "select at least one storage class" });
|
|
8145
|
+
/**
|
|
8146
|
+
* How a migration sequences the cutover against the byte move.
|
|
8147
|
+
*
|
|
8148
|
+
* - `blocking` — the historical order: pause, move every byte, repoint,
|
|
8149
|
+
* resume. Recording is stopped for the whole move. Right
|
|
8150
|
+
* for a small or a cold class, and the only legal mode for
|
|
8151
|
+
* a `cardinality: 'single'` class.
|
|
8152
|
+
* - `nonBlocking` — repoint FIRST, drain behind: seal, pause, repoint,
|
|
8153
|
+
* refresh, resume, then move the past with everything
|
|
8154
|
+
* running. The pause is three bounded instants (a detach +
|
|
8155
|
+
* attach round, a write-gate drain, a lease) instead of one
|
|
8156
|
+
* bounded by bytes. 1.09 TB at 7–14 MB/s is thirty hours of
|
|
8157
|
+
* stopped recording under `blocking`; the same move is
|
|
8158
|
+
* seconds of stopped recording under `nonBlocking`.
|
|
8159
|
+
*
|
|
8160
|
+
* The mode is on the JOB, not only on the input, because `status` is where an
|
|
8161
|
+
* operator finds out which one is running.
|
|
8162
|
+
*/
|
|
8163
|
+
var StorageMigrationModeSchema = _enum(["blocking", "nonBlocking"]);
|
|
8100
8164
|
/** Shared input for planning and starting an orchestrated storage migration. */
|
|
8101
8165
|
var StorageMigrationInputSchema = object({
|
|
8102
8166
|
destinations: StorageMigrationDestinationsSchema,
|
|
8103
|
-
throttleMbps: number().min(1).max(1e3).optional()
|
|
8167
|
+
throttleMbps: number().min(1).max(1e3).optional(),
|
|
8168
|
+
/** Omitted = `blocking`, which stays the default. */
|
|
8169
|
+
mode: StorageMigrationModeSchema.optional()
|
|
8104
8170
|
});
|
|
8105
|
-
/**
|
|
8106
|
-
*
|
|
8107
|
-
*
|
|
8171
|
+
/**
|
|
8172
|
+
* The durable coordinator state machine.
|
|
8173
|
+
*
|
|
8174
|
+
* `blocking`:
|
|
8175
|
+
* planning → pausing → moving → verifying → repointing → refreshing → resuming → done
|
|
8176
|
+
*
|
|
8177
|
+
* `nonBlocking`:
|
|
8178
|
+
* planning → sealing → pausing → repointing → refreshing → resuming → draining → verifying → done
|
|
8179
|
+
*
|
|
8180
|
+
* Same phases, different order plus two new ones — not a second mover.
|
|
8181
|
+
* `sealing` closes the `eventMedia` NULL-row hole BEFORE anything is paused;
|
|
8182
|
+
* `draining` runs the same movers UNLEASED, after every writer is back up.
|
|
8183
|
+
* `repointing` is still the only phase that changes a default location.
|
|
8184
|
+
*/
|
|
8108
8185
|
var StorageMigrationPhaseSchema = _enum([
|
|
8109
8186
|
"planning",
|
|
8187
|
+
"sealing",
|
|
8110
8188
|
"pausing",
|
|
8111
8189
|
"moving",
|
|
8190
|
+
"draining",
|
|
8112
8191
|
"verifying",
|
|
8113
8192
|
"repointing",
|
|
8114
8193
|
"refreshing",
|
|
@@ -8133,6 +8212,9 @@ var StorageMigrationMoveSchema = object({
|
|
|
8133
8212
|
var StorageMigrationJobSchema = object({
|
|
8134
8213
|
jobId: string(),
|
|
8135
8214
|
phase: StorageMigrationPhaseSchema,
|
|
8215
|
+
/** Which order this job is running. `status` is the only place an operator
|
|
8216
|
+
* can tell a seconds-long cutover from a thirty-hour one. */
|
|
8217
|
+
mode: StorageMigrationModeSchema,
|
|
8136
8218
|
destinations: StorageMigrationDestinationsSchema,
|
|
8137
8219
|
throttleMbps: number(),
|
|
8138
8220
|
moves: array(StorageMigrationMoveSchema),
|
|
@@ -8145,13 +8227,30 @@ var StorageMigrationJobSchema = object({
|
|
|
8145
8227
|
finishedAt: number().nullable(),
|
|
8146
8228
|
error: string().nullable()
|
|
8147
8229
|
});
|
|
8230
|
+
var StorageMigrationFindingSchema = object({
|
|
8231
|
+
code: _enum([
|
|
8232
|
+
"sharesDeviceWithSource",
|
|
8233
|
+
"deviceIdentityUnknown",
|
|
8234
|
+
"unstampedEventMediaRows",
|
|
8235
|
+
"blockingOnly",
|
|
8236
|
+
"noMover"
|
|
8237
|
+
]),
|
|
8238
|
+
storageClass: StorageMigrationClassSchema,
|
|
8239
|
+
/** Human-readable, already carrying the ids and counts. */
|
|
8240
|
+
message: string()
|
|
8241
|
+
});
|
|
8148
8242
|
var StorageMigrationPlanSchema = object({
|
|
8149
8243
|
destinations: StorageMigrationDestinationsSchema,
|
|
8244
|
+
/** The mode this plan was built for. A plan is only valid for its mode: the
|
|
8245
|
+
* `eventMedia` seal gate and the single-cardinality refusal both depend on
|
|
8246
|
+
* it. */
|
|
8247
|
+
mode: StorageMigrationModeSchema,
|
|
8150
8248
|
moves: array(object({
|
|
8151
8249
|
storageClass: StorageMigrationClassSchema,
|
|
8152
8250
|
fromLocationId: string(),
|
|
8153
8251
|
toLocationId: string()
|
|
8154
|
-
}))
|
|
8252
|
+
})),
|
|
8253
|
+
findings: array(StorageMigrationFindingSchema)
|
|
8155
8254
|
});
|
|
8156
8255
|
/**
|
|
8157
8256
|
* `StorageLocationType` — an addon-declared id that identifies the *kind* of
|
|
@@ -19021,7 +19120,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
19021
19120
|
}), method(RelocateMediaInputSchema, object({ jobId: string() }), {
|
|
19022
19121
|
kind: "mutation",
|
|
19023
19122
|
auth: "admin"
|
|
19024
|
-
}), method(object({}), array(RelocateJobSchema).readonly(), {
|
|
19123
|
+
}), method(object({}), UnstampedEventMediaCountSchema, { auth: "admin" }), method(object({}), array(RelocateJobSchema).readonly(), {
|
|
19025
19124
|
kind: "query",
|
|
19026
19125
|
auth: "admin"
|
|
19027
19126
|
}), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
@@ -20928,7 +21027,10 @@ method(object({
|
|
|
20928
21027
|
}), StorageLocationSchema, {
|
|
20929
21028
|
kind: "mutation",
|
|
20930
21029
|
auth: "admin"
|
|
20931
|
-
}), method(object({
|
|
21030
|
+
}), method(object({
|
|
21031
|
+
id: string(),
|
|
21032
|
+
force: boolean().optional()
|
|
21033
|
+
}), _void(), {
|
|
20932
21034
|
kind: "mutation",
|
|
20933
21035
|
auth: "admin"
|
|
20934
21036
|
}), method(object({ id: string() }), object({
|
|
@@ -25004,6 +25106,33 @@ var intercomCapability = {
|
|
|
25004
25106
|
deviceNative: true,
|
|
25005
25107
|
mode: "singleton",
|
|
25006
25108
|
deviceTypes: [DeviceType.Camera],
|
|
25109
|
+
/**
|
|
25110
|
+
* **Auth tier: `protected` on every method — deliberate, and load-bearing.**
|
|
25111
|
+
*
|
|
25112
|
+
* Talking through a camera is an OPERATE action, not a CONFIGURE one. This
|
|
25113
|
+
* cap has no configuration surface at all: all six methods open, feed and
|
|
25114
|
+
* close one live audio session against one `deviceId`. That is the same
|
|
25115
|
+
* authority as `ptz.move` or `snapshot.getSnapshot`, both `protected` — and
|
|
25116
|
+
* the opposite of `ptz.savePreset` / `snapshot.invalidateCache`, which are
|
|
25117
|
+
* `admin` because they change what the device IS.
|
|
25118
|
+
*
|
|
25119
|
+
* `protected` does not mean ungated: `protectedProcedure` runs the
|
|
25120
|
+
* `METHOD_ACCESS_MAP` scope check, and every method here is `scope: 'device'`
|
|
25121
|
+
* with `access: 'create'` and a `deviceId` in its input. So a caller needs a
|
|
25122
|
+
* grant that covers THAT camera at `create` — a `camera-viewer` (`view`
|
|
25123
|
+
* only) still cannot talk, and a grant on camera 5 cannot talk through
|
|
25124
|
+
* camera 7.
|
|
25125
|
+
*
|
|
25126
|
+
* Every method was `auth: 'admin'` from the initial commit, which made the
|
|
25127
|
+
* cap unreachable by every non-admin principal — `adminProcedure` throws
|
|
25128
|
+
* `FORBIDDEN: Admin required` BEFORE the scope check runs, so the scope
|
|
25129
|
+
* machinery generated for this cap (`METHOD_ACCESS_MAP`,
|
|
25130
|
+
* `DEVICE_SCOPED_CAPS`, `METHOD_DEVICE_SELECTORS`) was complete and dead. The
|
|
25131
|
+
* `camera-operator` scope preset has promised "PTZ control, intercom,
|
|
25132
|
+
* snapshots" since that same commit; the promise could not be kept. Recorded
|
|
25133
|
+
* as D289; `scripts/check-scope-preset-promises.ts` now fails the build if a
|
|
25134
|
+
* preset promises a cap no row of that preset can reach.
|
|
25135
|
+
*/
|
|
25007
25136
|
methods: {
|
|
25008
25137
|
/**
|
|
25009
25138
|
* Open a server-side WebRTC audio-only session. Returns an SDP
|
|
@@ -25016,7 +25145,7 @@ var intercomCapability = {
|
|
|
25016
25145
|
sdpOffer: string()
|
|
25017
25146
|
}), {
|
|
25018
25147
|
kind: "mutation",
|
|
25019
|
-
auth: "
|
|
25148
|
+
auth: "protected"
|
|
25020
25149
|
}),
|
|
25021
25150
|
handleAnswer: method(object({
|
|
25022
25151
|
deviceId: number(),
|
|
@@ -25024,7 +25153,7 @@ var intercomCapability = {
|
|
|
25024
25153
|
sdpAnswer: string()
|
|
25025
25154
|
}), _void(), {
|
|
25026
25155
|
kind: "mutation",
|
|
25027
|
-
auth: "
|
|
25156
|
+
auth: "protected"
|
|
25028
25157
|
}),
|
|
25029
25158
|
/** Close explicitly. Server also auto-closes on 30s idle. */
|
|
25030
25159
|
stopSession: method(object({
|
|
@@ -25032,7 +25161,7 @@ var intercomCapability = {
|
|
|
25032
25161
|
sessionId: string()
|
|
25033
25162
|
}), _void(), {
|
|
25034
25163
|
kind: "mutation",
|
|
25035
|
-
auth: "
|
|
25164
|
+
auth: "protected"
|
|
25036
25165
|
}),
|
|
25037
25166
|
/**
|
|
25038
25167
|
* Open a raw-PCM talk session (no WebRTC SDP plumbing). Used by
|
|
@@ -25045,7 +25174,7 @@ var intercomCapability = {
|
|
|
25045
25174
|
*/
|
|
25046
25175
|
startTalkSession: method(object({ deviceId: number() }), object({ sessionId: string() }), {
|
|
25047
25176
|
kind: "mutation",
|
|
25048
|
-
auth: "
|
|
25177
|
+
auth: "protected"
|
|
25049
25178
|
}),
|
|
25050
25179
|
/**
|
|
25051
25180
|
* Push one chunk of talk-back audio onto the active talk session.
|
|
@@ -25080,12 +25209,12 @@ var intercomCapability = {
|
|
|
25080
25209
|
sequenceNumber: number().int()
|
|
25081
25210
|
}), object({ accepted: boolean() }), {
|
|
25082
25211
|
kind: "mutation",
|
|
25083
|
-
auth: "
|
|
25212
|
+
auth: "protected"
|
|
25084
25213
|
}),
|
|
25085
25214
|
/** Close the raw-PCM talk session. Idempotent. */
|
|
25086
25215
|
endTalkSession: method(object({ deviceId: number() }), _void(), {
|
|
25087
25216
|
kind: "mutation",
|
|
25088
|
-
auth: "
|
|
25217
|
+
auth: "protected"
|
|
25089
25218
|
})
|
|
25090
25219
|
},
|
|
25091
25220
|
events: { onStatusChanged: { data: object({
|
|
@@ -34766,6 +34895,12 @@ Object.freeze({
|
|
|
34766
34895
|
addonId: null,
|
|
34767
34896
|
access: "create"
|
|
34768
34897
|
},
|
|
34898
|
+
"pipelineAnalytics.countUnstampedEventMedia": {
|
|
34899
|
+
capName: "pipeline-analytics",
|
|
34900
|
+
capScope: "device",
|
|
34901
|
+
addonId: null,
|
|
34902
|
+
access: "view"
|
|
34903
|
+
},
|
|
34769
34904
|
"pipelineAnalytics.deleteDeviceEvents": {
|
|
34770
34905
|
capName: "pipeline-analytics",
|
|
34771
34906
|
capScope: "device",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-provider-dreo",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.43",
|
|
4
4
|
"description": "Dreo smart-device (fan / air-circulator / purifier / heater / humidifier) device-provider addon for CamStack — wraps the @apocaliss92/nodedreo Dreo cloud client (REST + WebSocket)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|