@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.
Files changed (3) hide show
  1. package/dist/addon.js +154 -19
  2. package/dist/addon.mjs +154 -19
  3. 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. `recordings`
9033
- * encompasses the high and mid segment profiles; `recordingsLow` is low
9034
- * segments; `eventMedia` is post-analysis blobs. */
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
- /** The durable coordinator state machine. The only phase that changes default
9054
- * locations is `repointing`, after every selected mover has completed and been
9055
- * verified. */
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({ id: string() }), _void(), {
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: "admin"
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: "admin"
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: "admin"
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: "admin"
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: "admin"
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: "admin"
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. `recordings`
9032
- * encompasses the high and mid segment profiles; `recordingsLow` is low
9033
- * segments; `eventMedia` is post-analysis blobs. */
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
- /** The durable coordinator state machine. The only phase that changes default
9053
- * locations is `repointing`, after every selected mover has completed and been
9054
- * verified. */
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({ id: string() }), _void(), {
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: "admin"
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: "admin"
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: "admin"
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: "admin"
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: "admin"
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: "admin"
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.40",
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",