@camstack/addon-provider-homematic 1.2.42 → 1.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
|
@@ -8048,18 +8048,61 @@ var RelocateFootageInputSchema = object({
|
|
|
8048
8048
|
* `RecordingConfig.enabled` or camera wrapper bindings. */
|
|
8049
8049
|
var StorageMigrationLeaseInputSchema = object({ leaseId: string().min(1) });
|
|
8050
8050
|
var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: string().min(1) });
|
|
8051
|
+
/**
|
|
8052
|
+
* What a `relocateMedia` pass DOES. One engine, three passes — never a second
|
|
8053
|
+
* mover (the engine already walks both collections with a timestamp cursor and
|
|
8054
|
+
* already has a stamp-without-copy path).
|
|
8055
|
+
*
|
|
8056
|
+
* - `move` — the default and the historical behaviour: event-media and
|
|
8057
|
+
* retrain blobs move to `toLocationId` and their rows are
|
|
8058
|
+
* stamped. The enrolled gallery is skipped (D197).
|
|
8059
|
+
* - `seal` — ROWS ONLY, no bytes. Every row whose `locationId` is NULL is
|
|
8060
|
+
* stamped with `toLocationId`. `toLocationId` here is the id the
|
|
8061
|
+
* bytes ALREADY sit on — today's `eventMedia` default — because
|
|
8062
|
+
* a NULL row means "wherever `eventMedia` points *now*", and the
|
|
8063
|
+
* instant a repoint moves that pointer the row reads from the
|
|
8064
|
+
* new disk while its bytes are on the old one.
|
|
8065
|
+
* - `gallery` — the inverse selection of `move`: ONLY the retention-exempt
|
|
8066
|
+
* (enrolled-gallery) rows, which `move` deliberately skips.
|
|
8067
|
+
* `galleryMedia` is `cardinality: 'single'`, so this pass can
|
|
8068
|
+
* never run beside a live second location: it is stop-the-world
|
|
8069
|
+
* by construction, which is acceptable only because the gallery
|
|
8070
|
+
* is a few KB per enrolled sample.
|
|
8071
|
+
*/
|
|
8072
|
+
var MediaRelocateModeSchema = _enum([
|
|
8073
|
+
"move",
|
|
8074
|
+
"seal",
|
|
8075
|
+
"gallery"
|
|
8076
|
+
]);
|
|
8051
8077
|
var RelocateMediaInputSchema = object({
|
|
8052
8078
|
toLocationId: string(),
|
|
8053
|
-
throttleMbps: number().min(1).max(1e3).optional()
|
|
8079
|
+
throttleMbps: number().min(1).max(1e3).optional(),
|
|
8080
|
+
/** Omitted = `move`, the pre-existing behaviour. */
|
|
8081
|
+
mode: MediaRelocateModeSchema.optional()
|
|
8082
|
+
});
|
|
8083
|
+
/** How many rows still carry NO `locationId` — the population a repoint would
|
|
8084
|
+
* silently re-aim at a disk that does not hold their bytes. Zero is the only
|
|
8085
|
+
* value that permits a non-blocking `eventMedia` cutover. */
|
|
8086
|
+
var UnstampedEventMediaCountSchema = object({
|
|
8087
|
+
media: number().int().nonnegative(),
|
|
8088
|
+
retrainFrames: number().int().nonnegative(),
|
|
8089
|
+
total: number().int().nonnegative()
|
|
8054
8090
|
});
|
|
8055
8091
|
var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: string().min(1) });
|
|
8056
|
-
/** The independently selectable logical storage classes
|
|
8057
|
-
*
|
|
8058
|
-
*
|
|
8092
|
+
/** The independently selectable logical storage classes — every class
|
|
8093
|
+
* `storage.listLocationDeclarations` reports, so an operator never meets a
|
|
8094
|
+
* Zod enum error where they should meet an explanation.
|
|
8095
|
+
*
|
|
8096
|
+
* `recordings` encompasses the high and mid segment profiles; `recordingsLow`
|
|
8097
|
+
* is low segments; `eventMedia` is post-analysis blobs; `galleryMedia` is the
|
|
8098
|
+
* enrolled gallery; `backups` is the system backup archive. The last two have
|
|
8099
|
+
* their own rules — see {@link StorageMigrationFindingCodeSchema}. */
|
|
8059
8100
|
var StorageMigrationClassSchema = _enum([
|
|
8060
8101
|
"recordings",
|
|
8061
8102
|
"recordingsLow",
|
|
8062
|
-
"eventMedia"
|
|
8103
|
+
"eventMedia",
|
|
8104
|
+
"backups",
|
|
8105
|
+
"galleryMedia"
|
|
8063
8106
|
]);
|
|
8064
8107
|
/** A destination is always an existing, fully-qualified location id. The
|
|
8065
8108
|
* migration API intentionally never changes a source location's `basePath`:
|
|
@@ -8067,20 +8110,56 @@ var StorageMigrationClassSchema = _enum([
|
|
|
8067
8110
|
var StorageMigrationDestinationsSchema = object({
|
|
8068
8111
|
recordings: string().min(1).optional(),
|
|
8069
8112
|
recordingsLow: string().min(1).optional(),
|
|
8070
|
-
eventMedia: string().min(1).optional()
|
|
8113
|
+
eventMedia: string().min(1).optional(),
|
|
8114
|
+
backups: string().min(1).optional(),
|
|
8115
|
+
galleryMedia: string().min(1).optional()
|
|
8071
8116
|
}).refine((value) => Object.keys(value).length > 0, { message: "select at least one storage class" });
|
|
8117
|
+
/**
|
|
8118
|
+
* How a migration sequences the cutover against the byte move.
|
|
8119
|
+
*
|
|
8120
|
+
* - `blocking` — the historical order: pause, move every byte, repoint,
|
|
8121
|
+
* resume. Recording is stopped for the whole move. Right
|
|
8122
|
+
* for a small or a cold class, and the only legal mode for
|
|
8123
|
+
* a `cardinality: 'single'` class.
|
|
8124
|
+
* - `nonBlocking` — repoint FIRST, drain behind: seal, pause, repoint,
|
|
8125
|
+
* refresh, resume, then move the past with everything
|
|
8126
|
+
* running. The pause is three bounded instants (a detach +
|
|
8127
|
+
* attach round, a write-gate drain, a lease) instead of one
|
|
8128
|
+
* bounded by bytes. 1.09 TB at 7–14 MB/s is thirty hours of
|
|
8129
|
+
* stopped recording under `blocking`; the same move is
|
|
8130
|
+
* seconds of stopped recording under `nonBlocking`.
|
|
8131
|
+
*
|
|
8132
|
+
* The mode is on the JOB, not only on the input, because `status` is where an
|
|
8133
|
+
* operator finds out which one is running.
|
|
8134
|
+
*/
|
|
8135
|
+
var StorageMigrationModeSchema = _enum(["blocking", "nonBlocking"]);
|
|
8072
8136
|
/** Shared input for planning and starting an orchestrated storage migration. */
|
|
8073
8137
|
var StorageMigrationInputSchema = object({
|
|
8074
8138
|
destinations: StorageMigrationDestinationsSchema,
|
|
8075
|
-
throttleMbps: number().min(1).max(1e3).optional()
|
|
8139
|
+
throttleMbps: number().min(1).max(1e3).optional(),
|
|
8140
|
+
/** Omitted = `blocking`, which stays the default. */
|
|
8141
|
+
mode: StorageMigrationModeSchema.optional()
|
|
8076
8142
|
});
|
|
8077
|
-
/**
|
|
8078
|
-
*
|
|
8079
|
-
*
|
|
8143
|
+
/**
|
|
8144
|
+
* The durable coordinator state machine.
|
|
8145
|
+
*
|
|
8146
|
+
* `blocking`:
|
|
8147
|
+
* planning → pausing → moving → verifying → repointing → refreshing → resuming → done
|
|
8148
|
+
*
|
|
8149
|
+
* `nonBlocking`:
|
|
8150
|
+
* planning → sealing → pausing → repointing → refreshing → resuming → draining → verifying → done
|
|
8151
|
+
*
|
|
8152
|
+
* Same phases, different order plus two new ones — not a second mover.
|
|
8153
|
+
* `sealing` closes the `eventMedia` NULL-row hole BEFORE anything is paused;
|
|
8154
|
+
* `draining` runs the same movers UNLEASED, after every writer is back up.
|
|
8155
|
+
* `repointing` is still the only phase that changes a default location.
|
|
8156
|
+
*/
|
|
8080
8157
|
var StorageMigrationPhaseSchema = _enum([
|
|
8081
8158
|
"planning",
|
|
8159
|
+
"sealing",
|
|
8082
8160
|
"pausing",
|
|
8083
8161
|
"moving",
|
|
8162
|
+
"draining",
|
|
8084
8163
|
"verifying",
|
|
8085
8164
|
"repointing",
|
|
8086
8165
|
"refreshing",
|
|
@@ -8105,6 +8184,9 @@ var StorageMigrationMoveSchema = object({
|
|
|
8105
8184
|
var StorageMigrationJobSchema = object({
|
|
8106
8185
|
jobId: string(),
|
|
8107
8186
|
phase: StorageMigrationPhaseSchema,
|
|
8187
|
+
/** Which order this job is running. `status` is the only place an operator
|
|
8188
|
+
* can tell a seconds-long cutover from a thirty-hour one. */
|
|
8189
|
+
mode: StorageMigrationModeSchema,
|
|
8108
8190
|
destinations: StorageMigrationDestinationsSchema,
|
|
8109
8191
|
throttleMbps: number(),
|
|
8110
8192
|
moves: array(StorageMigrationMoveSchema),
|
|
@@ -8117,13 +8199,30 @@ var StorageMigrationJobSchema = object({
|
|
|
8117
8199
|
finishedAt: number().nullable(),
|
|
8118
8200
|
error: string().nullable()
|
|
8119
8201
|
});
|
|
8202
|
+
var StorageMigrationFindingSchema = object({
|
|
8203
|
+
code: _enum([
|
|
8204
|
+
"sharesDeviceWithSource",
|
|
8205
|
+
"deviceIdentityUnknown",
|
|
8206
|
+
"unstampedEventMediaRows",
|
|
8207
|
+
"blockingOnly",
|
|
8208
|
+
"noMover"
|
|
8209
|
+
]),
|
|
8210
|
+
storageClass: StorageMigrationClassSchema,
|
|
8211
|
+
/** Human-readable, already carrying the ids and counts. */
|
|
8212
|
+
message: string()
|
|
8213
|
+
});
|
|
8120
8214
|
var StorageMigrationPlanSchema = object({
|
|
8121
8215
|
destinations: StorageMigrationDestinationsSchema,
|
|
8216
|
+
/** The mode this plan was built for. A plan is only valid for its mode: the
|
|
8217
|
+
* `eventMedia` seal gate and the single-cardinality refusal both depend on
|
|
8218
|
+
* it. */
|
|
8219
|
+
mode: StorageMigrationModeSchema,
|
|
8122
8220
|
moves: array(object({
|
|
8123
8221
|
storageClass: StorageMigrationClassSchema,
|
|
8124
8222
|
fromLocationId: string(),
|
|
8125
8223
|
toLocationId: string()
|
|
8126
|
-
}))
|
|
8224
|
+
})),
|
|
8225
|
+
findings: array(StorageMigrationFindingSchema)
|
|
8127
8226
|
});
|
|
8128
8227
|
/**
|
|
8129
8228
|
* `StorageLocationType` — an addon-declared id that identifies the *kind* of
|
|
@@ -19042,7 +19141,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
19042
19141
|
}), method(RelocateMediaInputSchema, object({ jobId: string() }), {
|
|
19043
19142
|
kind: "mutation",
|
|
19044
19143
|
auth: "admin"
|
|
19045
|
-
}), method(object({}), array(RelocateJobSchema).readonly(), {
|
|
19144
|
+
}), method(object({}), UnstampedEventMediaCountSchema, { auth: "admin" }), method(object({}), array(RelocateJobSchema).readonly(), {
|
|
19046
19145
|
kind: "query",
|
|
19047
19146
|
auth: "admin"
|
|
19048
19147
|
}), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
@@ -20949,7 +21048,10 @@ method(object({
|
|
|
20949
21048
|
}), StorageLocationSchema, {
|
|
20950
21049
|
kind: "mutation",
|
|
20951
21050
|
auth: "admin"
|
|
20952
|
-
}), method(object({
|
|
21051
|
+
}), method(object({
|
|
21052
|
+
id: string(),
|
|
21053
|
+
force: boolean().optional()
|
|
21054
|
+
}), _void(), {
|
|
20953
21055
|
kind: "mutation",
|
|
20954
21056
|
auth: "admin"
|
|
20955
21057
|
}), method(object({ id: string() }), object({
|
|
@@ -25017,6 +25119,33 @@ var intercomCapability = {
|
|
|
25017
25119
|
deviceNative: true,
|
|
25018
25120
|
mode: "singleton",
|
|
25019
25121
|
deviceTypes: [DeviceType.Camera],
|
|
25122
|
+
/**
|
|
25123
|
+
* **Auth tier: `protected` on every method — deliberate, and load-bearing.**
|
|
25124
|
+
*
|
|
25125
|
+
* Talking through a camera is an OPERATE action, not a CONFIGURE one. This
|
|
25126
|
+
* cap has no configuration surface at all: all six methods open, feed and
|
|
25127
|
+
* close one live audio session against one `deviceId`. That is the same
|
|
25128
|
+
* authority as `ptz.move` or `snapshot.getSnapshot`, both `protected` — and
|
|
25129
|
+
* the opposite of `ptz.savePreset` / `snapshot.invalidateCache`, which are
|
|
25130
|
+
* `admin` because they change what the device IS.
|
|
25131
|
+
*
|
|
25132
|
+
* `protected` does not mean ungated: `protectedProcedure` runs the
|
|
25133
|
+
* `METHOD_ACCESS_MAP` scope check, and every method here is `scope: 'device'`
|
|
25134
|
+
* with `access: 'create'` and a `deviceId` in its input. So a caller needs a
|
|
25135
|
+
* grant that covers THAT camera at `create` — a `camera-viewer` (`view`
|
|
25136
|
+
* only) still cannot talk, and a grant on camera 5 cannot talk through
|
|
25137
|
+
* camera 7.
|
|
25138
|
+
*
|
|
25139
|
+
* Every method was `auth: 'admin'` from the initial commit, which made the
|
|
25140
|
+
* cap unreachable by every non-admin principal — `adminProcedure` throws
|
|
25141
|
+
* `FORBIDDEN: Admin required` BEFORE the scope check runs, so the scope
|
|
25142
|
+
* machinery generated for this cap (`METHOD_ACCESS_MAP`,
|
|
25143
|
+
* `DEVICE_SCOPED_CAPS`, `METHOD_DEVICE_SELECTORS`) was complete and dead. The
|
|
25144
|
+
* `camera-operator` scope preset has promised "PTZ control, intercom,
|
|
25145
|
+
* snapshots" since that same commit; the promise could not be kept. Recorded
|
|
25146
|
+
* as D289; `scripts/check-scope-preset-promises.ts` now fails the build if a
|
|
25147
|
+
* preset promises a cap no row of that preset can reach.
|
|
25148
|
+
*/
|
|
25020
25149
|
methods: {
|
|
25021
25150
|
/**
|
|
25022
25151
|
* Open a server-side WebRTC audio-only session. Returns an SDP
|
|
@@ -25029,7 +25158,7 @@ var intercomCapability = {
|
|
|
25029
25158
|
sdpOffer: string()
|
|
25030
25159
|
}), {
|
|
25031
25160
|
kind: "mutation",
|
|
25032
|
-
auth: "
|
|
25161
|
+
auth: "protected"
|
|
25033
25162
|
}),
|
|
25034
25163
|
handleAnswer: method(object({
|
|
25035
25164
|
deviceId: number(),
|
|
@@ -25037,7 +25166,7 @@ var intercomCapability = {
|
|
|
25037
25166
|
sdpAnswer: string()
|
|
25038
25167
|
}), _void(), {
|
|
25039
25168
|
kind: "mutation",
|
|
25040
|
-
auth: "
|
|
25169
|
+
auth: "protected"
|
|
25041
25170
|
}),
|
|
25042
25171
|
/** Close explicitly. Server also auto-closes on 30s idle. */
|
|
25043
25172
|
stopSession: method(object({
|
|
@@ -25045,7 +25174,7 @@ var intercomCapability = {
|
|
|
25045
25174
|
sessionId: string()
|
|
25046
25175
|
}), _void(), {
|
|
25047
25176
|
kind: "mutation",
|
|
25048
|
-
auth: "
|
|
25177
|
+
auth: "protected"
|
|
25049
25178
|
}),
|
|
25050
25179
|
/**
|
|
25051
25180
|
* Open a raw-PCM talk session (no WebRTC SDP plumbing). Used by
|
|
@@ -25058,7 +25187,7 @@ var intercomCapability = {
|
|
|
25058
25187
|
*/
|
|
25059
25188
|
startTalkSession: method(object({ deviceId: number() }), object({ sessionId: string() }), {
|
|
25060
25189
|
kind: "mutation",
|
|
25061
|
-
auth: "
|
|
25190
|
+
auth: "protected"
|
|
25062
25191
|
}),
|
|
25063
25192
|
/**
|
|
25064
25193
|
* Push one chunk of talk-back audio onto the active talk session.
|
|
@@ -25093,12 +25222,12 @@ var intercomCapability = {
|
|
|
25093
25222
|
sequenceNumber: number().int()
|
|
25094
25223
|
}), object({ accepted: boolean() }), {
|
|
25095
25224
|
kind: "mutation",
|
|
25096
|
-
auth: "
|
|
25225
|
+
auth: "protected"
|
|
25097
25226
|
}),
|
|
25098
25227
|
/** Close the raw-PCM talk session. Idempotent. */
|
|
25099
25228
|
endTalkSession: method(object({ deviceId: number() }), _void(), {
|
|
25100
25229
|
kind: "mutation",
|
|
25101
|
-
auth: "
|
|
25230
|
+
auth: "protected"
|
|
25102
25231
|
})
|
|
25103
25232
|
},
|
|
25104
25233
|
events: { onStatusChanged: { data: object({
|
|
@@ -34779,6 +34908,12 @@ Object.freeze({
|
|
|
34779
34908
|
addonId: null,
|
|
34780
34909
|
access: "create"
|
|
34781
34910
|
},
|
|
34911
|
+
"pipelineAnalytics.countUnstampedEventMedia": {
|
|
34912
|
+
capName: "pipeline-analytics",
|
|
34913
|
+
capScope: "device",
|
|
34914
|
+
addonId: null,
|
|
34915
|
+
access: "view"
|
|
34916
|
+
},
|
|
34782
34917
|
"pipelineAnalytics.deleteDeviceEvents": {
|
|
34783
34918
|
capName: "pipeline-analytics",
|
|
34784
34919
|
capScope: "device",
|
package/dist/addon.mjs
CHANGED
|
@@ -8049,18 +8049,61 @@ var RelocateFootageInputSchema = object({
|
|
|
8049
8049
|
* `RecordingConfig.enabled` or camera wrapper bindings. */
|
|
8050
8050
|
var StorageMigrationLeaseInputSchema = object({ leaseId: string().min(1) });
|
|
8051
8051
|
var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: string().min(1) });
|
|
8052
|
+
/**
|
|
8053
|
+
* What a `relocateMedia` pass DOES. One engine, three passes — never a second
|
|
8054
|
+
* mover (the engine already walks both collections with a timestamp cursor and
|
|
8055
|
+
* already has a stamp-without-copy path).
|
|
8056
|
+
*
|
|
8057
|
+
* - `move` — the default and the historical behaviour: event-media and
|
|
8058
|
+
* retrain blobs move to `toLocationId` and their rows are
|
|
8059
|
+
* stamped. The enrolled gallery is skipped (D197).
|
|
8060
|
+
* - `seal` — ROWS ONLY, no bytes. Every row whose `locationId` is NULL is
|
|
8061
|
+
* stamped with `toLocationId`. `toLocationId` here is the id the
|
|
8062
|
+
* bytes ALREADY sit on — today's `eventMedia` default — because
|
|
8063
|
+
* a NULL row means "wherever `eventMedia` points *now*", and the
|
|
8064
|
+
* instant a repoint moves that pointer the row reads from the
|
|
8065
|
+
* new disk while its bytes are on the old one.
|
|
8066
|
+
* - `gallery` — the inverse selection of `move`: ONLY the retention-exempt
|
|
8067
|
+
* (enrolled-gallery) rows, which `move` deliberately skips.
|
|
8068
|
+
* `galleryMedia` is `cardinality: 'single'`, so this pass can
|
|
8069
|
+
* never run beside a live second location: it is stop-the-world
|
|
8070
|
+
* by construction, which is acceptable only because the gallery
|
|
8071
|
+
* is a few KB per enrolled sample.
|
|
8072
|
+
*/
|
|
8073
|
+
var MediaRelocateModeSchema = _enum([
|
|
8074
|
+
"move",
|
|
8075
|
+
"seal",
|
|
8076
|
+
"gallery"
|
|
8077
|
+
]);
|
|
8052
8078
|
var RelocateMediaInputSchema = object({
|
|
8053
8079
|
toLocationId: string(),
|
|
8054
|
-
throttleMbps: number().min(1).max(1e3).optional()
|
|
8080
|
+
throttleMbps: number().min(1).max(1e3).optional(),
|
|
8081
|
+
/** Omitted = `move`, the pre-existing behaviour. */
|
|
8082
|
+
mode: MediaRelocateModeSchema.optional()
|
|
8083
|
+
});
|
|
8084
|
+
/** How many rows still carry NO `locationId` — the population a repoint would
|
|
8085
|
+
* silently re-aim at a disk that does not hold their bytes. Zero is the only
|
|
8086
|
+
* value that permits a non-blocking `eventMedia` cutover. */
|
|
8087
|
+
var UnstampedEventMediaCountSchema = object({
|
|
8088
|
+
media: number().int().nonnegative(),
|
|
8089
|
+
retrainFrames: number().int().nonnegative(),
|
|
8090
|
+
total: number().int().nonnegative()
|
|
8055
8091
|
});
|
|
8056
8092
|
var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: string().min(1) });
|
|
8057
|
-
/** The independently selectable logical storage classes
|
|
8058
|
-
*
|
|
8059
|
-
*
|
|
8093
|
+
/** The independently selectable logical storage classes — every class
|
|
8094
|
+
* `storage.listLocationDeclarations` reports, so an operator never meets a
|
|
8095
|
+
* Zod enum error where they should meet an explanation.
|
|
8096
|
+
*
|
|
8097
|
+
* `recordings` encompasses the high and mid segment profiles; `recordingsLow`
|
|
8098
|
+
* is low segments; `eventMedia` is post-analysis blobs; `galleryMedia` is the
|
|
8099
|
+
* enrolled gallery; `backups` is the system backup archive. The last two have
|
|
8100
|
+
* their own rules — see {@link StorageMigrationFindingCodeSchema}. */
|
|
8060
8101
|
var StorageMigrationClassSchema = _enum([
|
|
8061
8102
|
"recordings",
|
|
8062
8103
|
"recordingsLow",
|
|
8063
|
-
"eventMedia"
|
|
8104
|
+
"eventMedia",
|
|
8105
|
+
"backups",
|
|
8106
|
+
"galleryMedia"
|
|
8064
8107
|
]);
|
|
8065
8108
|
/** A destination is always an existing, fully-qualified location id. The
|
|
8066
8109
|
* migration API intentionally never changes a source location's `basePath`:
|
|
@@ -8068,20 +8111,56 @@ var StorageMigrationClassSchema = _enum([
|
|
|
8068
8111
|
var StorageMigrationDestinationsSchema = object({
|
|
8069
8112
|
recordings: string().min(1).optional(),
|
|
8070
8113
|
recordingsLow: string().min(1).optional(),
|
|
8071
|
-
eventMedia: string().min(1).optional()
|
|
8114
|
+
eventMedia: string().min(1).optional(),
|
|
8115
|
+
backups: string().min(1).optional(),
|
|
8116
|
+
galleryMedia: string().min(1).optional()
|
|
8072
8117
|
}).refine((value) => Object.keys(value).length > 0, { message: "select at least one storage class" });
|
|
8118
|
+
/**
|
|
8119
|
+
* How a migration sequences the cutover against the byte move.
|
|
8120
|
+
*
|
|
8121
|
+
* - `blocking` — the historical order: pause, move every byte, repoint,
|
|
8122
|
+
* resume. Recording is stopped for the whole move. Right
|
|
8123
|
+
* for a small or a cold class, and the only legal mode for
|
|
8124
|
+
* a `cardinality: 'single'` class.
|
|
8125
|
+
* - `nonBlocking` — repoint FIRST, drain behind: seal, pause, repoint,
|
|
8126
|
+
* refresh, resume, then move the past with everything
|
|
8127
|
+
* running. The pause is three bounded instants (a detach +
|
|
8128
|
+
* attach round, a write-gate drain, a lease) instead of one
|
|
8129
|
+
* bounded by bytes. 1.09 TB at 7–14 MB/s is thirty hours of
|
|
8130
|
+
* stopped recording under `blocking`; the same move is
|
|
8131
|
+
* seconds of stopped recording under `nonBlocking`.
|
|
8132
|
+
*
|
|
8133
|
+
* The mode is on the JOB, not only on the input, because `status` is where an
|
|
8134
|
+
* operator finds out which one is running.
|
|
8135
|
+
*/
|
|
8136
|
+
var StorageMigrationModeSchema = _enum(["blocking", "nonBlocking"]);
|
|
8073
8137
|
/** Shared input for planning and starting an orchestrated storage migration. */
|
|
8074
8138
|
var StorageMigrationInputSchema = object({
|
|
8075
8139
|
destinations: StorageMigrationDestinationsSchema,
|
|
8076
|
-
throttleMbps: number().min(1).max(1e3).optional()
|
|
8140
|
+
throttleMbps: number().min(1).max(1e3).optional(),
|
|
8141
|
+
/** Omitted = `blocking`, which stays the default. */
|
|
8142
|
+
mode: StorageMigrationModeSchema.optional()
|
|
8077
8143
|
});
|
|
8078
|
-
/**
|
|
8079
|
-
*
|
|
8080
|
-
*
|
|
8144
|
+
/**
|
|
8145
|
+
* The durable coordinator state machine.
|
|
8146
|
+
*
|
|
8147
|
+
* `blocking`:
|
|
8148
|
+
* planning → pausing → moving → verifying → repointing → refreshing → resuming → done
|
|
8149
|
+
*
|
|
8150
|
+
* `nonBlocking`:
|
|
8151
|
+
* planning → sealing → pausing → repointing → refreshing → resuming → draining → verifying → done
|
|
8152
|
+
*
|
|
8153
|
+
* Same phases, different order plus two new ones — not a second mover.
|
|
8154
|
+
* `sealing` closes the `eventMedia` NULL-row hole BEFORE anything is paused;
|
|
8155
|
+
* `draining` runs the same movers UNLEASED, after every writer is back up.
|
|
8156
|
+
* `repointing` is still the only phase that changes a default location.
|
|
8157
|
+
*/
|
|
8081
8158
|
var StorageMigrationPhaseSchema = _enum([
|
|
8082
8159
|
"planning",
|
|
8160
|
+
"sealing",
|
|
8083
8161
|
"pausing",
|
|
8084
8162
|
"moving",
|
|
8163
|
+
"draining",
|
|
8085
8164
|
"verifying",
|
|
8086
8165
|
"repointing",
|
|
8087
8166
|
"refreshing",
|
|
@@ -8106,6 +8185,9 @@ var StorageMigrationMoveSchema = object({
|
|
|
8106
8185
|
var StorageMigrationJobSchema = object({
|
|
8107
8186
|
jobId: string(),
|
|
8108
8187
|
phase: StorageMigrationPhaseSchema,
|
|
8188
|
+
/** Which order this job is running. `status` is the only place an operator
|
|
8189
|
+
* can tell a seconds-long cutover from a thirty-hour one. */
|
|
8190
|
+
mode: StorageMigrationModeSchema,
|
|
8109
8191
|
destinations: StorageMigrationDestinationsSchema,
|
|
8110
8192
|
throttleMbps: number(),
|
|
8111
8193
|
moves: array(StorageMigrationMoveSchema),
|
|
@@ -8118,13 +8200,30 @@ var StorageMigrationJobSchema = object({
|
|
|
8118
8200
|
finishedAt: number().nullable(),
|
|
8119
8201
|
error: string().nullable()
|
|
8120
8202
|
});
|
|
8203
|
+
var StorageMigrationFindingSchema = object({
|
|
8204
|
+
code: _enum([
|
|
8205
|
+
"sharesDeviceWithSource",
|
|
8206
|
+
"deviceIdentityUnknown",
|
|
8207
|
+
"unstampedEventMediaRows",
|
|
8208
|
+
"blockingOnly",
|
|
8209
|
+
"noMover"
|
|
8210
|
+
]),
|
|
8211
|
+
storageClass: StorageMigrationClassSchema,
|
|
8212
|
+
/** Human-readable, already carrying the ids and counts. */
|
|
8213
|
+
message: string()
|
|
8214
|
+
});
|
|
8121
8215
|
var StorageMigrationPlanSchema = object({
|
|
8122
8216
|
destinations: StorageMigrationDestinationsSchema,
|
|
8217
|
+
/** The mode this plan was built for. A plan is only valid for its mode: the
|
|
8218
|
+
* `eventMedia` seal gate and the single-cardinality refusal both depend on
|
|
8219
|
+
* it. */
|
|
8220
|
+
mode: StorageMigrationModeSchema,
|
|
8123
8221
|
moves: array(object({
|
|
8124
8222
|
storageClass: StorageMigrationClassSchema,
|
|
8125
8223
|
fromLocationId: string(),
|
|
8126
8224
|
toLocationId: string()
|
|
8127
|
-
}))
|
|
8225
|
+
})),
|
|
8226
|
+
findings: array(StorageMigrationFindingSchema)
|
|
8128
8227
|
});
|
|
8129
8228
|
/**
|
|
8130
8229
|
* `StorageLocationType` — an addon-declared id that identifies the *kind* of
|
|
@@ -19043,7 +19142,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
19043
19142
|
}), method(RelocateMediaInputSchema, object({ jobId: string() }), {
|
|
19044
19143
|
kind: "mutation",
|
|
19045
19144
|
auth: "admin"
|
|
19046
|
-
}), method(object({}), array(RelocateJobSchema).readonly(), {
|
|
19145
|
+
}), method(object({}), UnstampedEventMediaCountSchema, { auth: "admin" }), method(object({}), array(RelocateJobSchema).readonly(), {
|
|
19047
19146
|
kind: "query",
|
|
19048
19147
|
auth: "admin"
|
|
19049
19148
|
}), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
@@ -20950,7 +21049,10 @@ method(object({
|
|
|
20950
21049
|
}), StorageLocationSchema, {
|
|
20951
21050
|
kind: "mutation",
|
|
20952
21051
|
auth: "admin"
|
|
20953
|
-
}), method(object({
|
|
21052
|
+
}), method(object({
|
|
21053
|
+
id: string(),
|
|
21054
|
+
force: boolean().optional()
|
|
21055
|
+
}), _void(), {
|
|
20954
21056
|
kind: "mutation",
|
|
20955
21057
|
auth: "admin"
|
|
20956
21058
|
}), method(object({ id: string() }), object({
|
|
@@ -25018,6 +25120,33 @@ var intercomCapability = {
|
|
|
25018
25120
|
deviceNative: true,
|
|
25019
25121
|
mode: "singleton",
|
|
25020
25122
|
deviceTypes: [DeviceType.Camera],
|
|
25123
|
+
/**
|
|
25124
|
+
* **Auth tier: `protected` on every method — deliberate, and load-bearing.**
|
|
25125
|
+
*
|
|
25126
|
+
* Talking through a camera is an OPERATE action, not a CONFIGURE one. This
|
|
25127
|
+
* cap has no configuration surface at all: all six methods open, feed and
|
|
25128
|
+
* close one live audio session against one `deviceId`. That is the same
|
|
25129
|
+
* authority as `ptz.move` or `snapshot.getSnapshot`, both `protected` — and
|
|
25130
|
+
* the opposite of `ptz.savePreset` / `snapshot.invalidateCache`, which are
|
|
25131
|
+
* `admin` because they change what the device IS.
|
|
25132
|
+
*
|
|
25133
|
+
* `protected` does not mean ungated: `protectedProcedure` runs the
|
|
25134
|
+
* `METHOD_ACCESS_MAP` scope check, and every method here is `scope: 'device'`
|
|
25135
|
+
* with `access: 'create'` and a `deviceId` in its input. So a caller needs a
|
|
25136
|
+
* grant that covers THAT camera at `create` — a `camera-viewer` (`view`
|
|
25137
|
+
* only) still cannot talk, and a grant on camera 5 cannot talk through
|
|
25138
|
+
* camera 7.
|
|
25139
|
+
*
|
|
25140
|
+
* Every method was `auth: 'admin'` from the initial commit, which made the
|
|
25141
|
+
* cap unreachable by every non-admin principal — `adminProcedure` throws
|
|
25142
|
+
* `FORBIDDEN: Admin required` BEFORE the scope check runs, so the scope
|
|
25143
|
+
* machinery generated for this cap (`METHOD_ACCESS_MAP`,
|
|
25144
|
+
* `DEVICE_SCOPED_CAPS`, `METHOD_DEVICE_SELECTORS`) was complete and dead. The
|
|
25145
|
+
* `camera-operator` scope preset has promised "PTZ control, intercom,
|
|
25146
|
+
* snapshots" since that same commit; the promise could not be kept. Recorded
|
|
25147
|
+
* as D289; `scripts/check-scope-preset-promises.ts` now fails the build if a
|
|
25148
|
+
* preset promises a cap no row of that preset can reach.
|
|
25149
|
+
*/
|
|
25021
25150
|
methods: {
|
|
25022
25151
|
/**
|
|
25023
25152
|
* Open a server-side WebRTC audio-only session. Returns an SDP
|
|
@@ -25030,7 +25159,7 @@ var intercomCapability = {
|
|
|
25030
25159
|
sdpOffer: string()
|
|
25031
25160
|
}), {
|
|
25032
25161
|
kind: "mutation",
|
|
25033
|
-
auth: "
|
|
25162
|
+
auth: "protected"
|
|
25034
25163
|
}),
|
|
25035
25164
|
handleAnswer: method(object({
|
|
25036
25165
|
deviceId: number(),
|
|
@@ -25038,7 +25167,7 @@ var intercomCapability = {
|
|
|
25038
25167
|
sdpAnswer: string()
|
|
25039
25168
|
}), _void(), {
|
|
25040
25169
|
kind: "mutation",
|
|
25041
|
-
auth: "
|
|
25170
|
+
auth: "protected"
|
|
25042
25171
|
}),
|
|
25043
25172
|
/** Close explicitly. Server also auto-closes on 30s idle. */
|
|
25044
25173
|
stopSession: method(object({
|
|
@@ -25046,7 +25175,7 @@ var intercomCapability = {
|
|
|
25046
25175
|
sessionId: string()
|
|
25047
25176
|
}), _void(), {
|
|
25048
25177
|
kind: "mutation",
|
|
25049
|
-
auth: "
|
|
25178
|
+
auth: "protected"
|
|
25050
25179
|
}),
|
|
25051
25180
|
/**
|
|
25052
25181
|
* Open a raw-PCM talk session (no WebRTC SDP plumbing). Used by
|
|
@@ -25059,7 +25188,7 @@ var intercomCapability = {
|
|
|
25059
25188
|
*/
|
|
25060
25189
|
startTalkSession: method(object({ deviceId: number() }), object({ sessionId: string() }), {
|
|
25061
25190
|
kind: "mutation",
|
|
25062
|
-
auth: "
|
|
25191
|
+
auth: "protected"
|
|
25063
25192
|
}),
|
|
25064
25193
|
/**
|
|
25065
25194
|
* Push one chunk of talk-back audio onto the active talk session.
|
|
@@ -25094,12 +25223,12 @@ var intercomCapability = {
|
|
|
25094
25223
|
sequenceNumber: number().int()
|
|
25095
25224
|
}), object({ accepted: boolean() }), {
|
|
25096
25225
|
kind: "mutation",
|
|
25097
|
-
auth: "
|
|
25226
|
+
auth: "protected"
|
|
25098
25227
|
}),
|
|
25099
25228
|
/** Close the raw-PCM talk session. Idempotent. */
|
|
25100
25229
|
endTalkSession: method(object({ deviceId: number() }), _void(), {
|
|
25101
25230
|
kind: "mutation",
|
|
25102
|
-
auth: "
|
|
25231
|
+
auth: "protected"
|
|
25103
25232
|
})
|
|
25104
25233
|
},
|
|
25105
25234
|
events: { onStatusChanged: { data: object({
|
|
@@ -34780,6 +34909,12 @@ Object.freeze({
|
|
|
34780
34909
|
addonId: null,
|
|
34781
34910
|
access: "create"
|
|
34782
34911
|
},
|
|
34912
|
+
"pipelineAnalytics.countUnstampedEventMedia": {
|
|
34913
|
+
capName: "pipeline-analytics",
|
|
34914
|
+
capScope: "device",
|
|
34915
|
+
addonId: null,
|
|
34916
|
+
access: "view"
|
|
34917
|
+
},
|
|
34783
34918
|
"pipelineAnalytics.deleteDeviceEvents": {
|
|
34784
34919
|
capName: "pipeline-analytics",
|
|
34785
34920
|
capScope: "device",
|
package/package.json
CHANGED