@camstack/addon-provider-rademacher 0.2.40 → 0.2.42
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
|
@@ -9024,18 +9024,61 @@ var RelocateFootageInputSchema = object({
|
|
|
9024
9024
|
* `RecordingConfig.enabled` or camera wrapper bindings. */
|
|
9025
9025
|
var StorageMigrationLeaseInputSchema = object({ leaseId: string().min(1) });
|
|
9026
9026
|
var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: string().min(1) });
|
|
9027
|
+
/**
|
|
9028
|
+
* What a `relocateMedia` pass DOES. One engine, three passes — never a second
|
|
9029
|
+
* mover (the engine already walks both collections with a timestamp cursor and
|
|
9030
|
+
* already has a stamp-without-copy path).
|
|
9031
|
+
*
|
|
9032
|
+
* - `move` — the default and the historical behaviour: event-media and
|
|
9033
|
+
* retrain blobs move to `toLocationId` and their rows are
|
|
9034
|
+
* stamped. The enrolled gallery is skipped (D197).
|
|
9035
|
+
* - `seal` — ROWS ONLY, no bytes. Every row whose `locationId` is NULL is
|
|
9036
|
+
* stamped with `toLocationId`. `toLocationId` here is the id the
|
|
9037
|
+
* bytes ALREADY sit on — today's `eventMedia` default — because
|
|
9038
|
+
* a NULL row means "wherever `eventMedia` points *now*", and the
|
|
9039
|
+
* instant a repoint moves that pointer the row reads from the
|
|
9040
|
+
* new disk while its bytes are on the old one.
|
|
9041
|
+
* - `gallery` — the inverse selection of `move`: ONLY the retention-exempt
|
|
9042
|
+
* (enrolled-gallery) rows, which `move` deliberately skips.
|
|
9043
|
+
* `galleryMedia` is `cardinality: 'single'`, so this pass can
|
|
9044
|
+
* never run beside a live second location: it is stop-the-world
|
|
9045
|
+
* by construction, which is acceptable only because the gallery
|
|
9046
|
+
* is a few KB per enrolled sample.
|
|
9047
|
+
*/
|
|
9048
|
+
var MediaRelocateModeSchema = _enum([
|
|
9049
|
+
"move",
|
|
9050
|
+
"seal",
|
|
9051
|
+
"gallery"
|
|
9052
|
+
]);
|
|
9027
9053
|
var RelocateMediaInputSchema = object({
|
|
9028
9054
|
toLocationId: string(),
|
|
9029
|
-
throttleMbps: number().min(1).max(1e3).optional()
|
|
9055
|
+
throttleMbps: number().min(1).max(1e3).optional(),
|
|
9056
|
+
/** Omitted = `move`, the pre-existing behaviour. */
|
|
9057
|
+
mode: MediaRelocateModeSchema.optional()
|
|
9058
|
+
});
|
|
9059
|
+
/** How many rows still carry NO `locationId` — the population a repoint would
|
|
9060
|
+
* silently re-aim at a disk that does not hold their bytes. Zero is the only
|
|
9061
|
+
* value that permits a non-blocking `eventMedia` cutover. */
|
|
9062
|
+
var UnstampedEventMediaCountSchema = object({
|
|
9063
|
+
media: number().int().nonnegative(),
|
|
9064
|
+
retrainFrames: number().int().nonnegative(),
|
|
9065
|
+
total: number().int().nonnegative()
|
|
9030
9066
|
});
|
|
9031
9067
|
var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: string().min(1) });
|
|
9032
|
-
/** The independently selectable logical storage classes
|
|
9033
|
-
*
|
|
9034
|
-
*
|
|
9068
|
+
/** The independently selectable logical storage classes — every class
|
|
9069
|
+
* `storage.listLocationDeclarations` reports, so an operator never meets a
|
|
9070
|
+
* Zod enum error where they should meet an explanation.
|
|
9071
|
+
*
|
|
9072
|
+
* `recordings` encompasses the high and mid segment profiles; `recordingsLow`
|
|
9073
|
+
* is low segments; `eventMedia` is post-analysis blobs; `galleryMedia` is the
|
|
9074
|
+
* enrolled gallery; `backups` is the system backup archive. The last two have
|
|
9075
|
+
* their own rules — see {@link StorageMigrationFindingCodeSchema}. */
|
|
9035
9076
|
var StorageMigrationClassSchema = _enum([
|
|
9036
9077
|
"recordings",
|
|
9037
9078
|
"recordingsLow",
|
|
9038
|
-
"eventMedia"
|
|
9079
|
+
"eventMedia",
|
|
9080
|
+
"backups",
|
|
9081
|
+
"galleryMedia"
|
|
9039
9082
|
]);
|
|
9040
9083
|
/** A destination is always an existing, fully-qualified location id. The
|
|
9041
9084
|
* migration API intentionally never changes a source location's `basePath`:
|
|
@@ -9043,20 +9086,56 @@ var StorageMigrationClassSchema = _enum([
|
|
|
9043
9086
|
var StorageMigrationDestinationsSchema = object({
|
|
9044
9087
|
recordings: string().min(1).optional(),
|
|
9045
9088
|
recordingsLow: string().min(1).optional(),
|
|
9046
|
-
eventMedia: string().min(1).optional()
|
|
9089
|
+
eventMedia: string().min(1).optional(),
|
|
9090
|
+
backups: string().min(1).optional(),
|
|
9091
|
+
galleryMedia: string().min(1).optional()
|
|
9047
9092
|
}).refine((value) => Object.keys(value).length > 0, { message: "select at least one storage class" });
|
|
9093
|
+
/**
|
|
9094
|
+
* How a migration sequences the cutover against the byte move.
|
|
9095
|
+
*
|
|
9096
|
+
* - `blocking` — the historical order: pause, move every byte, repoint,
|
|
9097
|
+
* resume. Recording is stopped for the whole move. Right
|
|
9098
|
+
* for a small or a cold class, and the only legal mode for
|
|
9099
|
+
* a `cardinality: 'single'` class.
|
|
9100
|
+
* - `nonBlocking` — repoint FIRST, drain behind: seal, pause, repoint,
|
|
9101
|
+
* refresh, resume, then move the past with everything
|
|
9102
|
+
* running. The pause is three bounded instants (a detach +
|
|
9103
|
+
* attach round, a write-gate drain, a lease) instead of one
|
|
9104
|
+
* bounded by bytes. 1.09 TB at 7–14 MB/s is thirty hours of
|
|
9105
|
+
* stopped recording under `blocking`; the same move is
|
|
9106
|
+
* seconds of stopped recording under `nonBlocking`.
|
|
9107
|
+
*
|
|
9108
|
+
* The mode is on the JOB, not only on the input, because `status` is where an
|
|
9109
|
+
* operator finds out which one is running.
|
|
9110
|
+
*/
|
|
9111
|
+
var StorageMigrationModeSchema = _enum(["blocking", "nonBlocking"]);
|
|
9048
9112
|
/** Shared input for planning and starting an orchestrated storage migration. */
|
|
9049
9113
|
var StorageMigrationInputSchema = object({
|
|
9050
9114
|
destinations: StorageMigrationDestinationsSchema,
|
|
9051
|
-
throttleMbps: number().min(1).max(1e3).optional()
|
|
9115
|
+
throttleMbps: number().min(1).max(1e3).optional(),
|
|
9116
|
+
/** Omitted = `blocking`, which stays the default. */
|
|
9117
|
+
mode: StorageMigrationModeSchema.optional()
|
|
9052
9118
|
});
|
|
9053
|
-
/**
|
|
9054
|
-
*
|
|
9055
|
-
*
|
|
9119
|
+
/**
|
|
9120
|
+
* The durable coordinator state machine.
|
|
9121
|
+
*
|
|
9122
|
+
* `blocking`:
|
|
9123
|
+
* planning → pausing → moving → verifying → repointing → refreshing → resuming → done
|
|
9124
|
+
*
|
|
9125
|
+
* `nonBlocking`:
|
|
9126
|
+
* planning → sealing → pausing → repointing → refreshing → resuming → draining → verifying → done
|
|
9127
|
+
*
|
|
9128
|
+
* Same phases, different order plus two new ones — not a second mover.
|
|
9129
|
+
* `sealing` closes the `eventMedia` NULL-row hole BEFORE anything is paused;
|
|
9130
|
+
* `draining` runs the same movers UNLEASED, after every writer is back up.
|
|
9131
|
+
* `repointing` is still the only phase that changes a default location.
|
|
9132
|
+
*/
|
|
9056
9133
|
var StorageMigrationPhaseSchema = _enum([
|
|
9057
9134
|
"planning",
|
|
9135
|
+
"sealing",
|
|
9058
9136
|
"pausing",
|
|
9059
9137
|
"moving",
|
|
9138
|
+
"draining",
|
|
9060
9139
|
"verifying",
|
|
9061
9140
|
"repointing",
|
|
9062
9141
|
"refreshing",
|
|
@@ -9081,6 +9160,9 @@ var StorageMigrationMoveSchema = object({
|
|
|
9081
9160
|
var StorageMigrationJobSchema = object({
|
|
9082
9161
|
jobId: string(),
|
|
9083
9162
|
phase: StorageMigrationPhaseSchema,
|
|
9163
|
+
/** Which order this job is running. `status` is the only place an operator
|
|
9164
|
+
* can tell a seconds-long cutover from a thirty-hour one. */
|
|
9165
|
+
mode: StorageMigrationModeSchema,
|
|
9084
9166
|
destinations: StorageMigrationDestinationsSchema,
|
|
9085
9167
|
throttleMbps: number(),
|
|
9086
9168
|
moves: array(StorageMigrationMoveSchema),
|
|
@@ -9093,13 +9175,30 @@ var StorageMigrationJobSchema = object({
|
|
|
9093
9175
|
finishedAt: number().nullable(),
|
|
9094
9176
|
error: string().nullable()
|
|
9095
9177
|
});
|
|
9178
|
+
var StorageMigrationFindingSchema = object({
|
|
9179
|
+
code: _enum([
|
|
9180
|
+
"sharesDeviceWithSource",
|
|
9181
|
+
"deviceIdentityUnknown",
|
|
9182
|
+
"unstampedEventMediaRows",
|
|
9183
|
+
"blockingOnly",
|
|
9184
|
+
"noMover"
|
|
9185
|
+
]),
|
|
9186
|
+
storageClass: StorageMigrationClassSchema,
|
|
9187
|
+
/** Human-readable, already carrying the ids and counts. */
|
|
9188
|
+
message: string()
|
|
9189
|
+
});
|
|
9096
9190
|
var StorageMigrationPlanSchema = object({
|
|
9097
9191
|
destinations: StorageMigrationDestinationsSchema,
|
|
9192
|
+
/** The mode this plan was built for. A plan is only valid for its mode: the
|
|
9193
|
+
* `eventMedia` seal gate and the single-cardinality refusal both depend on
|
|
9194
|
+
* it. */
|
|
9195
|
+
mode: StorageMigrationModeSchema,
|
|
9098
9196
|
moves: array(object({
|
|
9099
9197
|
storageClass: StorageMigrationClassSchema,
|
|
9100
9198
|
fromLocationId: string(),
|
|
9101
9199
|
toLocationId: string()
|
|
9102
|
-
}))
|
|
9200
|
+
})),
|
|
9201
|
+
findings: array(StorageMigrationFindingSchema)
|
|
9103
9202
|
});
|
|
9104
9203
|
/**
|
|
9105
9204
|
* `StorageLocationType` — an addon-declared id that identifies the *kind* of
|
|
@@ -19952,7 +20051,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
19952
20051
|
}), method(RelocateMediaInputSchema, object({ jobId: string() }), {
|
|
19953
20052
|
kind: "mutation",
|
|
19954
20053
|
auth: "admin"
|
|
19955
|
-
}), method(object({}), array(RelocateJobSchema).readonly(), {
|
|
20054
|
+
}), method(object({}), UnstampedEventMediaCountSchema, { auth: "admin" }), method(object({}), array(RelocateJobSchema).readonly(), {
|
|
19956
20055
|
kind: "query",
|
|
19957
20056
|
auth: "admin"
|
|
19958
20057
|
}), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
@@ -21859,7 +21958,10 @@ method(object({
|
|
|
21859
21958
|
}), StorageLocationSchema, {
|
|
21860
21959
|
kind: "mutation",
|
|
21861
21960
|
auth: "admin"
|
|
21862
|
-
}), method(object({
|
|
21961
|
+
}), method(object({
|
|
21962
|
+
id: string(),
|
|
21963
|
+
force: boolean().optional()
|
|
21964
|
+
}), _void(), {
|
|
21863
21965
|
kind: "mutation",
|
|
21864
21966
|
auth: "admin"
|
|
21865
21967
|
}), method(object({ id: string() }), object({
|
|
@@ -25927,6 +26029,33 @@ var intercomCapability = {
|
|
|
25927
26029
|
deviceNative: true,
|
|
25928
26030
|
mode: "singleton",
|
|
25929
26031
|
deviceTypes: [DeviceType.Camera],
|
|
26032
|
+
/**
|
|
26033
|
+
* **Auth tier: `protected` on every method — deliberate, and load-bearing.**
|
|
26034
|
+
*
|
|
26035
|
+
* Talking through a camera is an OPERATE action, not a CONFIGURE one. This
|
|
26036
|
+
* cap has no configuration surface at all: all six methods open, feed and
|
|
26037
|
+
* close one live audio session against one `deviceId`. That is the same
|
|
26038
|
+
* authority as `ptz.move` or `snapshot.getSnapshot`, both `protected` — and
|
|
26039
|
+
* the opposite of `ptz.savePreset` / `snapshot.invalidateCache`, which are
|
|
26040
|
+
* `admin` because they change what the device IS.
|
|
26041
|
+
*
|
|
26042
|
+
* `protected` does not mean ungated: `protectedProcedure` runs the
|
|
26043
|
+
* `METHOD_ACCESS_MAP` scope check, and every method here is `scope: 'device'`
|
|
26044
|
+
* with `access: 'create'` and a `deviceId` in its input. So a caller needs a
|
|
26045
|
+
* grant that covers THAT camera at `create` — a `camera-viewer` (`view`
|
|
26046
|
+
* only) still cannot talk, and a grant on camera 5 cannot talk through
|
|
26047
|
+
* camera 7.
|
|
26048
|
+
*
|
|
26049
|
+
* Every method was `auth: 'admin'` from the initial commit, which made the
|
|
26050
|
+
* cap unreachable by every non-admin principal — `adminProcedure` throws
|
|
26051
|
+
* `FORBIDDEN: Admin required` BEFORE the scope check runs, so the scope
|
|
26052
|
+
* machinery generated for this cap (`METHOD_ACCESS_MAP`,
|
|
26053
|
+
* `DEVICE_SCOPED_CAPS`, `METHOD_DEVICE_SELECTORS`) was complete and dead. The
|
|
26054
|
+
* `camera-operator` scope preset has promised "PTZ control, intercom,
|
|
26055
|
+
* snapshots" since that same commit; the promise could not be kept. Recorded
|
|
26056
|
+
* as D289; `scripts/check-scope-preset-promises.ts` now fails the build if a
|
|
26057
|
+
* preset promises a cap no row of that preset can reach.
|
|
26058
|
+
*/
|
|
25930
26059
|
methods: {
|
|
25931
26060
|
/**
|
|
25932
26061
|
* Open a server-side WebRTC audio-only session. Returns an SDP
|
|
@@ -25939,7 +26068,7 @@ var intercomCapability = {
|
|
|
25939
26068
|
sdpOffer: string()
|
|
25940
26069
|
}), {
|
|
25941
26070
|
kind: "mutation",
|
|
25942
|
-
auth: "
|
|
26071
|
+
auth: "protected"
|
|
25943
26072
|
}),
|
|
25944
26073
|
handleAnswer: method(object({
|
|
25945
26074
|
deviceId: number(),
|
|
@@ -25947,7 +26076,7 @@ var intercomCapability = {
|
|
|
25947
26076
|
sdpAnswer: string()
|
|
25948
26077
|
}), _void(), {
|
|
25949
26078
|
kind: "mutation",
|
|
25950
|
-
auth: "
|
|
26079
|
+
auth: "protected"
|
|
25951
26080
|
}),
|
|
25952
26081
|
/** Close explicitly. Server also auto-closes on 30s idle. */
|
|
25953
26082
|
stopSession: method(object({
|
|
@@ -25955,7 +26084,7 @@ var intercomCapability = {
|
|
|
25955
26084
|
sessionId: string()
|
|
25956
26085
|
}), _void(), {
|
|
25957
26086
|
kind: "mutation",
|
|
25958
|
-
auth: "
|
|
26087
|
+
auth: "protected"
|
|
25959
26088
|
}),
|
|
25960
26089
|
/**
|
|
25961
26090
|
* Open a raw-PCM talk session (no WebRTC SDP plumbing). Used by
|
|
@@ -25968,7 +26097,7 @@ var intercomCapability = {
|
|
|
25968
26097
|
*/
|
|
25969
26098
|
startTalkSession: method(object({ deviceId: number() }), object({ sessionId: string() }), {
|
|
25970
26099
|
kind: "mutation",
|
|
25971
|
-
auth: "
|
|
26100
|
+
auth: "protected"
|
|
25972
26101
|
}),
|
|
25973
26102
|
/**
|
|
25974
26103
|
* Push one chunk of talk-back audio onto the active talk session.
|
|
@@ -26003,12 +26132,12 @@ var intercomCapability = {
|
|
|
26003
26132
|
sequenceNumber: number().int()
|
|
26004
26133
|
}), object({ accepted: boolean() }), {
|
|
26005
26134
|
kind: "mutation",
|
|
26006
|
-
auth: "
|
|
26135
|
+
auth: "protected"
|
|
26007
26136
|
}),
|
|
26008
26137
|
/** Close the raw-PCM talk session. Idempotent. */
|
|
26009
26138
|
endTalkSession: method(object({ deviceId: number() }), _void(), {
|
|
26010
26139
|
kind: "mutation",
|
|
26011
|
-
auth: "
|
|
26140
|
+
auth: "protected"
|
|
26012
26141
|
})
|
|
26013
26142
|
},
|
|
26014
26143
|
events: { onStatusChanged: { data: object({
|
|
@@ -35689,6 +35818,12 @@ Object.freeze({
|
|
|
35689
35818
|
addonId: null,
|
|
35690
35819
|
access: "create"
|
|
35691
35820
|
},
|
|
35821
|
+
"pipelineAnalytics.countUnstampedEventMedia": {
|
|
35822
|
+
capName: "pipeline-analytics",
|
|
35823
|
+
capScope: "device",
|
|
35824
|
+
addonId: null,
|
|
35825
|
+
access: "view"
|
|
35826
|
+
},
|
|
35692
35827
|
"pipelineAnalytics.deleteDeviceEvents": {
|
|
35693
35828
|
capName: "pipeline-analytics",
|
|
35694
35829
|
capScope: "device",
|
package/dist/addon.mjs
CHANGED
|
@@ -9023,18 +9023,61 @@ var RelocateFootageInputSchema = object({
|
|
|
9023
9023
|
* `RecordingConfig.enabled` or camera wrapper bindings. */
|
|
9024
9024
|
var StorageMigrationLeaseInputSchema = object({ leaseId: string().min(1) });
|
|
9025
9025
|
var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: string().min(1) });
|
|
9026
|
+
/**
|
|
9027
|
+
* What a `relocateMedia` pass DOES. One engine, three passes — never a second
|
|
9028
|
+
* mover (the engine already walks both collections with a timestamp cursor and
|
|
9029
|
+
* already has a stamp-without-copy path).
|
|
9030
|
+
*
|
|
9031
|
+
* - `move` — the default and the historical behaviour: event-media and
|
|
9032
|
+
* retrain blobs move to `toLocationId` and their rows are
|
|
9033
|
+
* stamped. The enrolled gallery is skipped (D197).
|
|
9034
|
+
* - `seal` — ROWS ONLY, no bytes. Every row whose `locationId` is NULL is
|
|
9035
|
+
* stamped with `toLocationId`. `toLocationId` here is the id the
|
|
9036
|
+
* bytes ALREADY sit on — today's `eventMedia` default — because
|
|
9037
|
+
* a NULL row means "wherever `eventMedia` points *now*", and the
|
|
9038
|
+
* instant a repoint moves that pointer the row reads from the
|
|
9039
|
+
* new disk while its bytes are on the old one.
|
|
9040
|
+
* - `gallery` — the inverse selection of `move`: ONLY the retention-exempt
|
|
9041
|
+
* (enrolled-gallery) rows, which `move` deliberately skips.
|
|
9042
|
+
* `galleryMedia` is `cardinality: 'single'`, so this pass can
|
|
9043
|
+
* never run beside a live second location: it is stop-the-world
|
|
9044
|
+
* by construction, which is acceptable only because the gallery
|
|
9045
|
+
* is a few KB per enrolled sample.
|
|
9046
|
+
*/
|
|
9047
|
+
var MediaRelocateModeSchema = _enum([
|
|
9048
|
+
"move",
|
|
9049
|
+
"seal",
|
|
9050
|
+
"gallery"
|
|
9051
|
+
]);
|
|
9026
9052
|
var RelocateMediaInputSchema = object({
|
|
9027
9053
|
toLocationId: string(),
|
|
9028
|
-
throttleMbps: number().min(1).max(1e3).optional()
|
|
9054
|
+
throttleMbps: number().min(1).max(1e3).optional(),
|
|
9055
|
+
/** Omitted = `move`, the pre-existing behaviour. */
|
|
9056
|
+
mode: MediaRelocateModeSchema.optional()
|
|
9057
|
+
});
|
|
9058
|
+
/** How many rows still carry NO `locationId` — the population a repoint would
|
|
9059
|
+
* silently re-aim at a disk that does not hold their bytes. Zero is the only
|
|
9060
|
+
* value that permits a non-blocking `eventMedia` cutover. */
|
|
9061
|
+
var UnstampedEventMediaCountSchema = object({
|
|
9062
|
+
media: number().int().nonnegative(),
|
|
9063
|
+
retrainFrames: number().int().nonnegative(),
|
|
9064
|
+
total: number().int().nonnegative()
|
|
9029
9065
|
});
|
|
9030
9066
|
var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: string().min(1) });
|
|
9031
|
-
/** The independently selectable logical storage classes
|
|
9032
|
-
*
|
|
9033
|
-
*
|
|
9067
|
+
/** The independently selectable logical storage classes — every class
|
|
9068
|
+
* `storage.listLocationDeclarations` reports, so an operator never meets a
|
|
9069
|
+
* Zod enum error where they should meet an explanation.
|
|
9070
|
+
*
|
|
9071
|
+
* `recordings` encompasses the high and mid segment profiles; `recordingsLow`
|
|
9072
|
+
* is low segments; `eventMedia` is post-analysis blobs; `galleryMedia` is the
|
|
9073
|
+
* enrolled gallery; `backups` is the system backup archive. The last two have
|
|
9074
|
+
* their own rules — see {@link StorageMigrationFindingCodeSchema}. */
|
|
9034
9075
|
var StorageMigrationClassSchema = _enum([
|
|
9035
9076
|
"recordings",
|
|
9036
9077
|
"recordingsLow",
|
|
9037
|
-
"eventMedia"
|
|
9078
|
+
"eventMedia",
|
|
9079
|
+
"backups",
|
|
9080
|
+
"galleryMedia"
|
|
9038
9081
|
]);
|
|
9039
9082
|
/** A destination is always an existing, fully-qualified location id. The
|
|
9040
9083
|
* migration API intentionally never changes a source location's `basePath`:
|
|
@@ -9042,20 +9085,56 @@ var StorageMigrationClassSchema = _enum([
|
|
|
9042
9085
|
var StorageMigrationDestinationsSchema = object({
|
|
9043
9086
|
recordings: string().min(1).optional(),
|
|
9044
9087
|
recordingsLow: string().min(1).optional(),
|
|
9045
|
-
eventMedia: string().min(1).optional()
|
|
9088
|
+
eventMedia: string().min(1).optional(),
|
|
9089
|
+
backups: string().min(1).optional(),
|
|
9090
|
+
galleryMedia: string().min(1).optional()
|
|
9046
9091
|
}).refine((value) => Object.keys(value).length > 0, { message: "select at least one storage class" });
|
|
9092
|
+
/**
|
|
9093
|
+
* How a migration sequences the cutover against the byte move.
|
|
9094
|
+
*
|
|
9095
|
+
* - `blocking` — the historical order: pause, move every byte, repoint,
|
|
9096
|
+
* resume. Recording is stopped for the whole move. Right
|
|
9097
|
+
* for a small or a cold class, and the only legal mode for
|
|
9098
|
+
* a `cardinality: 'single'` class.
|
|
9099
|
+
* - `nonBlocking` — repoint FIRST, drain behind: seal, pause, repoint,
|
|
9100
|
+
* refresh, resume, then move the past with everything
|
|
9101
|
+
* running. The pause is three bounded instants (a detach +
|
|
9102
|
+
* attach round, a write-gate drain, a lease) instead of one
|
|
9103
|
+
* bounded by bytes. 1.09 TB at 7–14 MB/s is thirty hours of
|
|
9104
|
+
* stopped recording under `blocking`; the same move is
|
|
9105
|
+
* seconds of stopped recording under `nonBlocking`.
|
|
9106
|
+
*
|
|
9107
|
+
* The mode is on the JOB, not only on the input, because `status` is where an
|
|
9108
|
+
* operator finds out which one is running.
|
|
9109
|
+
*/
|
|
9110
|
+
var StorageMigrationModeSchema = _enum(["blocking", "nonBlocking"]);
|
|
9047
9111
|
/** Shared input for planning and starting an orchestrated storage migration. */
|
|
9048
9112
|
var StorageMigrationInputSchema = object({
|
|
9049
9113
|
destinations: StorageMigrationDestinationsSchema,
|
|
9050
|
-
throttleMbps: number().min(1).max(1e3).optional()
|
|
9114
|
+
throttleMbps: number().min(1).max(1e3).optional(),
|
|
9115
|
+
/** Omitted = `blocking`, which stays the default. */
|
|
9116
|
+
mode: StorageMigrationModeSchema.optional()
|
|
9051
9117
|
});
|
|
9052
|
-
/**
|
|
9053
|
-
*
|
|
9054
|
-
*
|
|
9118
|
+
/**
|
|
9119
|
+
* The durable coordinator state machine.
|
|
9120
|
+
*
|
|
9121
|
+
* `blocking`:
|
|
9122
|
+
* planning → pausing → moving → verifying → repointing → refreshing → resuming → done
|
|
9123
|
+
*
|
|
9124
|
+
* `nonBlocking`:
|
|
9125
|
+
* planning → sealing → pausing → repointing → refreshing → resuming → draining → verifying → done
|
|
9126
|
+
*
|
|
9127
|
+
* Same phases, different order plus two new ones — not a second mover.
|
|
9128
|
+
* `sealing` closes the `eventMedia` NULL-row hole BEFORE anything is paused;
|
|
9129
|
+
* `draining` runs the same movers UNLEASED, after every writer is back up.
|
|
9130
|
+
* `repointing` is still the only phase that changes a default location.
|
|
9131
|
+
*/
|
|
9055
9132
|
var StorageMigrationPhaseSchema = _enum([
|
|
9056
9133
|
"planning",
|
|
9134
|
+
"sealing",
|
|
9057
9135
|
"pausing",
|
|
9058
9136
|
"moving",
|
|
9137
|
+
"draining",
|
|
9059
9138
|
"verifying",
|
|
9060
9139
|
"repointing",
|
|
9061
9140
|
"refreshing",
|
|
@@ -9080,6 +9159,9 @@ var StorageMigrationMoveSchema = object({
|
|
|
9080
9159
|
var StorageMigrationJobSchema = object({
|
|
9081
9160
|
jobId: string(),
|
|
9082
9161
|
phase: StorageMigrationPhaseSchema,
|
|
9162
|
+
/** Which order this job is running. `status` is the only place an operator
|
|
9163
|
+
* can tell a seconds-long cutover from a thirty-hour one. */
|
|
9164
|
+
mode: StorageMigrationModeSchema,
|
|
9083
9165
|
destinations: StorageMigrationDestinationsSchema,
|
|
9084
9166
|
throttleMbps: number(),
|
|
9085
9167
|
moves: array(StorageMigrationMoveSchema),
|
|
@@ -9092,13 +9174,30 @@ var StorageMigrationJobSchema = object({
|
|
|
9092
9174
|
finishedAt: number().nullable(),
|
|
9093
9175
|
error: string().nullable()
|
|
9094
9176
|
});
|
|
9177
|
+
var StorageMigrationFindingSchema = object({
|
|
9178
|
+
code: _enum([
|
|
9179
|
+
"sharesDeviceWithSource",
|
|
9180
|
+
"deviceIdentityUnknown",
|
|
9181
|
+
"unstampedEventMediaRows",
|
|
9182
|
+
"blockingOnly",
|
|
9183
|
+
"noMover"
|
|
9184
|
+
]),
|
|
9185
|
+
storageClass: StorageMigrationClassSchema,
|
|
9186
|
+
/** Human-readable, already carrying the ids and counts. */
|
|
9187
|
+
message: string()
|
|
9188
|
+
});
|
|
9095
9189
|
var StorageMigrationPlanSchema = object({
|
|
9096
9190
|
destinations: StorageMigrationDestinationsSchema,
|
|
9191
|
+
/** The mode this plan was built for. A plan is only valid for its mode: the
|
|
9192
|
+
* `eventMedia` seal gate and the single-cardinality refusal both depend on
|
|
9193
|
+
* it. */
|
|
9194
|
+
mode: StorageMigrationModeSchema,
|
|
9097
9195
|
moves: array(object({
|
|
9098
9196
|
storageClass: StorageMigrationClassSchema,
|
|
9099
9197
|
fromLocationId: string(),
|
|
9100
9198
|
toLocationId: string()
|
|
9101
|
-
}))
|
|
9199
|
+
})),
|
|
9200
|
+
findings: array(StorageMigrationFindingSchema)
|
|
9102
9201
|
});
|
|
9103
9202
|
/**
|
|
9104
9203
|
* `StorageLocationType` — an addon-declared id that identifies the *kind* of
|
|
@@ -19951,7 +20050,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
|
|
|
19951
20050
|
}), method(RelocateMediaInputSchema, object({ jobId: string() }), {
|
|
19952
20051
|
kind: "mutation",
|
|
19953
20052
|
auth: "admin"
|
|
19954
|
-
}), method(object({}), array(RelocateJobSchema).readonly(), {
|
|
20053
|
+
}), method(object({}), UnstampedEventMediaCountSchema, { auth: "admin" }), method(object({}), array(RelocateJobSchema).readonly(), {
|
|
19955
20054
|
kind: "query",
|
|
19956
20055
|
auth: "admin"
|
|
19957
20056
|
}), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
@@ -21858,7 +21957,10 @@ method(object({
|
|
|
21858
21957
|
}), StorageLocationSchema, {
|
|
21859
21958
|
kind: "mutation",
|
|
21860
21959
|
auth: "admin"
|
|
21861
|
-
}), method(object({
|
|
21960
|
+
}), method(object({
|
|
21961
|
+
id: string(),
|
|
21962
|
+
force: boolean().optional()
|
|
21963
|
+
}), _void(), {
|
|
21862
21964
|
kind: "mutation",
|
|
21863
21965
|
auth: "admin"
|
|
21864
21966
|
}), method(object({ id: string() }), object({
|
|
@@ -25926,6 +26028,33 @@ var intercomCapability = {
|
|
|
25926
26028
|
deviceNative: true,
|
|
25927
26029
|
mode: "singleton",
|
|
25928
26030
|
deviceTypes: [DeviceType.Camera],
|
|
26031
|
+
/**
|
|
26032
|
+
* **Auth tier: `protected` on every method — deliberate, and load-bearing.**
|
|
26033
|
+
*
|
|
26034
|
+
* Talking through a camera is an OPERATE action, not a CONFIGURE one. This
|
|
26035
|
+
* cap has no configuration surface at all: all six methods open, feed and
|
|
26036
|
+
* close one live audio session against one `deviceId`. That is the same
|
|
26037
|
+
* authority as `ptz.move` or `snapshot.getSnapshot`, both `protected` — and
|
|
26038
|
+
* the opposite of `ptz.savePreset` / `snapshot.invalidateCache`, which are
|
|
26039
|
+
* `admin` because they change what the device IS.
|
|
26040
|
+
*
|
|
26041
|
+
* `protected` does not mean ungated: `protectedProcedure` runs the
|
|
26042
|
+
* `METHOD_ACCESS_MAP` scope check, and every method here is `scope: 'device'`
|
|
26043
|
+
* with `access: 'create'` and a `deviceId` in its input. So a caller needs a
|
|
26044
|
+
* grant that covers THAT camera at `create` — a `camera-viewer` (`view`
|
|
26045
|
+
* only) still cannot talk, and a grant on camera 5 cannot talk through
|
|
26046
|
+
* camera 7.
|
|
26047
|
+
*
|
|
26048
|
+
* Every method was `auth: 'admin'` from the initial commit, which made the
|
|
26049
|
+
* cap unreachable by every non-admin principal — `adminProcedure` throws
|
|
26050
|
+
* `FORBIDDEN: Admin required` BEFORE the scope check runs, so the scope
|
|
26051
|
+
* machinery generated for this cap (`METHOD_ACCESS_MAP`,
|
|
26052
|
+
* `DEVICE_SCOPED_CAPS`, `METHOD_DEVICE_SELECTORS`) was complete and dead. The
|
|
26053
|
+
* `camera-operator` scope preset has promised "PTZ control, intercom,
|
|
26054
|
+
* snapshots" since that same commit; the promise could not be kept. Recorded
|
|
26055
|
+
* as D289; `scripts/check-scope-preset-promises.ts` now fails the build if a
|
|
26056
|
+
* preset promises a cap no row of that preset can reach.
|
|
26057
|
+
*/
|
|
25929
26058
|
methods: {
|
|
25930
26059
|
/**
|
|
25931
26060
|
* Open a server-side WebRTC audio-only session. Returns an SDP
|
|
@@ -25938,7 +26067,7 @@ var intercomCapability = {
|
|
|
25938
26067
|
sdpOffer: string()
|
|
25939
26068
|
}), {
|
|
25940
26069
|
kind: "mutation",
|
|
25941
|
-
auth: "
|
|
26070
|
+
auth: "protected"
|
|
25942
26071
|
}),
|
|
25943
26072
|
handleAnswer: method(object({
|
|
25944
26073
|
deviceId: number(),
|
|
@@ -25946,7 +26075,7 @@ var intercomCapability = {
|
|
|
25946
26075
|
sdpAnswer: string()
|
|
25947
26076
|
}), _void(), {
|
|
25948
26077
|
kind: "mutation",
|
|
25949
|
-
auth: "
|
|
26078
|
+
auth: "protected"
|
|
25950
26079
|
}),
|
|
25951
26080
|
/** Close explicitly. Server also auto-closes on 30s idle. */
|
|
25952
26081
|
stopSession: method(object({
|
|
@@ -25954,7 +26083,7 @@ var intercomCapability = {
|
|
|
25954
26083
|
sessionId: string()
|
|
25955
26084
|
}), _void(), {
|
|
25956
26085
|
kind: "mutation",
|
|
25957
|
-
auth: "
|
|
26086
|
+
auth: "protected"
|
|
25958
26087
|
}),
|
|
25959
26088
|
/**
|
|
25960
26089
|
* Open a raw-PCM talk session (no WebRTC SDP plumbing). Used by
|
|
@@ -25967,7 +26096,7 @@ var intercomCapability = {
|
|
|
25967
26096
|
*/
|
|
25968
26097
|
startTalkSession: method(object({ deviceId: number() }), object({ sessionId: string() }), {
|
|
25969
26098
|
kind: "mutation",
|
|
25970
|
-
auth: "
|
|
26099
|
+
auth: "protected"
|
|
25971
26100
|
}),
|
|
25972
26101
|
/**
|
|
25973
26102
|
* Push one chunk of talk-back audio onto the active talk session.
|
|
@@ -26002,12 +26131,12 @@ var intercomCapability = {
|
|
|
26002
26131
|
sequenceNumber: number().int()
|
|
26003
26132
|
}), object({ accepted: boolean() }), {
|
|
26004
26133
|
kind: "mutation",
|
|
26005
|
-
auth: "
|
|
26134
|
+
auth: "protected"
|
|
26006
26135
|
}),
|
|
26007
26136
|
/** Close the raw-PCM talk session. Idempotent. */
|
|
26008
26137
|
endTalkSession: method(object({ deviceId: number() }), _void(), {
|
|
26009
26138
|
kind: "mutation",
|
|
26010
|
-
auth: "
|
|
26139
|
+
auth: "protected"
|
|
26011
26140
|
})
|
|
26012
26141
|
},
|
|
26013
26142
|
events: { onStatusChanged: { data: object({
|
|
@@ -35688,6 +35817,12 @@ Object.freeze({
|
|
|
35688
35817
|
addonId: null,
|
|
35689
35818
|
access: "create"
|
|
35690
35819
|
},
|
|
35820
|
+
"pipelineAnalytics.countUnstampedEventMedia": {
|
|
35821
|
+
capName: "pipeline-analytics",
|
|
35822
|
+
capScope: "device",
|
|
35823
|
+
addonId: null,
|
|
35824
|
+
access: "view"
|
|
35825
|
+
},
|
|
35691
35826
|
"pipelineAnalytics.deleteDeviceEvents": {
|
|
35692
35827
|
capName: "pipeline-analytics",
|
|
35693
35828
|
capScope: "device",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/addon-provider-rademacher",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.42",
|
|
4
4
|
"description": "Rademacher HomePilot device-provider addon for CamStack — wraps the @apocaliss92/noderademacher local-hub client (roller shutters over the cover cap)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|