@camstack/addon-provider-rtsp 1.2.41 → 1.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.
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
@@ -8095,18 +8095,61 @@ var RelocateFootageInputSchema = object({
8095
8095
  * `RecordingConfig.enabled` or camera wrapper bindings. */
8096
8096
  var StorageMigrationLeaseInputSchema = object({ leaseId: string().min(1) });
8097
8097
  var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: string().min(1) });
8098
+ /**
8099
+ * What a `relocateMedia` pass DOES. One engine, three passes — never a second
8100
+ * mover (the engine already walks both collections with a timestamp cursor and
8101
+ * already has a stamp-without-copy path).
8102
+ *
8103
+ * - `move` — the default and the historical behaviour: event-media and
8104
+ * retrain blobs move to `toLocationId` and their rows are
8105
+ * stamped. The enrolled gallery is skipped (D197).
8106
+ * - `seal` — ROWS ONLY, no bytes. Every row whose `locationId` is NULL is
8107
+ * stamped with `toLocationId`. `toLocationId` here is the id the
8108
+ * bytes ALREADY sit on — today's `eventMedia` default — because
8109
+ * a NULL row means "wherever `eventMedia` points *now*", and the
8110
+ * instant a repoint moves that pointer the row reads from the
8111
+ * new disk while its bytes are on the old one.
8112
+ * - `gallery` — the inverse selection of `move`: ONLY the retention-exempt
8113
+ * (enrolled-gallery) rows, which `move` deliberately skips.
8114
+ * `galleryMedia` is `cardinality: 'single'`, so this pass can
8115
+ * never run beside a live second location: it is stop-the-world
8116
+ * by construction, which is acceptable only because the gallery
8117
+ * is a few KB per enrolled sample.
8118
+ */
8119
+ var MediaRelocateModeSchema = _enum([
8120
+ "move",
8121
+ "seal",
8122
+ "gallery"
8123
+ ]);
8098
8124
  var RelocateMediaInputSchema = object({
8099
8125
  toLocationId: string(),
8100
- throttleMbps: number().min(1).max(1e3).optional()
8126
+ throttleMbps: number().min(1).max(1e3).optional(),
8127
+ /** Omitted = `move`, the pre-existing behaviour. */
8128
+ mode: MediaRelocateModeSchema.optional()
8129
+ });
8130
+ /** How many rows still carry NO `locationId` — the population a repoint would
8131
+ * silently re-aim at a disk that does not hold their bytes. Zero is the only
8132
+ * value that permits a non-blocking `eventMedia` cutover. */
8133
+ var UnstampedEventMediaCountSchema = object({
8134
+ media: number().int().nonnegative(),
8135
+ retrainFrames: number().int().nonnegative(),
8136
+ total: number().int().nonnegative()
8101
8137
  });
8102
8138
  var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: string().min(1) });
8103
- /** The independently selectable logical storage classes. `recordings`
8104
- * encompasses the high and mid segment profiles; `recordingsLow` is low
8105
- * segments; `eventMedia` is post-analysis blobs. */
8139
+ /** The independently selectable logical storage classes — every class
8140
+ * `storage.listLocationDeclarations` reports, so an operator never meets a
8141
+ * Zod enum error where they should meet an explanation.
8142
+ *
8143
+ * `recordings` encompasses the high and mid segment profiles; `recordingsLow`
8144
+ * is low segments; `eventMedia` is post-analysis blobs; `galleryMedia` is the
8145
+ * enrolled gallery; `backups` is the system backup archive. The last two have
8146
+ * their own rules — see {@link StorageMigrationFindingCodeSchema}. */
8106
8147
  var StorageMigrationClassSchema = _enum([
8107
8148
  "recordings",
8108
8149
  "recordingsLow",
8109
- "eventMedia"
8150
+ "eventMedia",
8151
+ "backups",
8152
+ "galleryMedia"
8110
8153
  ]);
8111
8154
  /** A destination is always an existing, fully-qualified location id. The
8112
8155
  * migration API intentionally never changes a source location's `basePath`:
@@ -8114,20 +8157,56 @@ var StorageMigrationClassSchema = _enum([
8114
8157
  var StorageMigrationDestinationsSchema = object({
8115
8158
  recordings: string().min(1).optional(),
8116
8159
  recordingsLow: string().min(1).optional(),
8117
- eventMedia: string().min(1).optional()
8160
+ eventMedia: string().min(1).optional(),
8161
+ backups: string().min(1).optional(),
8162
+ galleryMedia: string().min(1).optional()
8118
8163
  }).refine((value) => Object.keys(value).length > 0, { message: "select at least one storage class" });
8164
+ /**
8165
+ * How a migration sequences the cutover against the byte move.
8166
+ *
8167
+ * - `blocking` — the historical order: pause, move every byte, repoint,
8168
+ * resume. Recording is stopped for the whole move. Right
8169
+ * for a small or a cold class, and the only legal mode for
8170
+ * a `cardinality: 'single'` class.
8171
+ * - `nonBlocking` — repoint FIRST, drain behind: seal, pause, repoint,
8172
+ * refresh, resume, then move the past with everything
8173
+ * running. The pause is three bounded instants (a detach +
8174
+ * attach round, a write-gate drain, a lease) instead of one
8175
+ * bounded by bytes. 1.09 TB at 7–14 MB/s is thirty hours of
8176
+ * stopped recording under `blocking`; the same move is
8177
+ * seconds of stopped recording under `nonBlocking`.
8178
+ *
8179
+ * The mode is on the JOB, not only on the input, because `status` is where an
8180
+ * operator finds out which one is running.
8181
+ */
8182
+ var StorageMigrationModeSchema = _enum(["blocking", "nonBlocking"]);
8119
8183
  /** Shared input for planning and starting an orchestrated storage migration. */
8120
8184
  var StorageMigrationInputSchema = object({
8121
8185
  destinations: StorageMigrationDestinationsSchema,
8122
- throttleMbps: number().min(1).max(1e3).optional()
8186
+ throttleMbps: number().min(1).max(1e3).optional(),
8187
+ /** Omitted = `blocking`, which stays the default. */
8188
+ mode: StorageMigrationModeSchema.optional()
8123
8189
  });
8124
- /** The durable coordinator state machine. The only phase that changes default
8125
- * locations is `repointing`, after every selected mover has completed and been
8126
- * verified. */
8190
+ /**
8191
+ * The durable coordinator state machine.
8192
+ *
8193
+ * `blocking`:
8194
+ * planning → pausing → moving → verifying → repointing → refreshing → resuming → done
8195
+ *
8196
+ * `nonBlocking`:
8197
+ * planning → sealing → pausing → repointing → refreshing → resuming → draining → verifying → done
8198
+ *
8199
+ * Same phases, different order plus two new ones — not a second mover.
8200
+ * `sealing` closes the `eventMedia` NULL-row hole BEFORE anything is paused;
8201
+ * `draining` runs the same movers UNLEASED, after every writer is back up.
8202
+ * `repointing` is still the only phase that changes a default location.
8203
+ */
8127
8204
  var StorageMigrationPhaseSchema = _enum([
8128
8205
  "planning",
8206
+ "sealing",
8129
8207
  "pausing",
8130
8208
  "moving",
8209
+ "draining",
8131
8210
  "verifying",
8132
8211
  "repointing",
8133
8212
  "refreshing",
@@ -8152,6 +8231,9 @@ var StorageMigrationMoveSchema = object({
8152
8231
  var StorageMigrationJobSchema = object({
8153
8232
  jobId: string(),
8154
8233
  phase: StorageMigrationPhaseSchema,
8234
+ /** Which order this job is running. `status` is the only place an operator
8235
+ * can tell a seconds-long cutover from a thirty-hour one. */
8236
+ mode: StorageMigrationModeSchema,
8155
8237
  destinations: StorageMigrationDestinationsSchema,
8156
8238
  throttleMbps: number(),
8157
8239
  moves: array(StorageMigrationMoveSchema),
@@ -8164,13 +8246,30 @@ var StorageMigrationJobSchema = object({
8164
8246
  finishedAt: number().nullable(),
8165
8247
  error: string().nullable()
8166
8248
  });
8249
+ var StorageMigrationFindingSchema = object({
8250
+ code: _enum([
8251
+ "sharesDeviceWithSource",
8252
+ "deviceIdentityUnknown",
8253
+ "unstampedEventMediaRows",
8254
+ "blockingOnly",
8255
+ "noMover"
8256
+ ]),
8257
+ storageClass: StorageMigrationClassSchema,
8258
+ /** Human-readable, already carrying the ids and counts. */
8259
+ message: string()
8260
+ });
8167
8261
  var StorageMigrationPlanSchema = object({
8168
8262
  destinations: StorageMigrationDestinationsSchema,
8263
+ /** The mode this plan was built for. A plan is only valid for its mode: the
8264
+ * `eventMedia` seal gate and the single-cardinality refusal both depend on
8265
+ * it. */
8266
+ mode: StorageMigrationModeSchema,
8169
8267
  moves: array(object({
8170
8268
  storageClass: StorageMigrationClassSchema,
8171
8269
  fromLocationId: string(),
8172
8270
  toLocationId: string()
8173
- }))
8271
+ })),
8272
+ findings: array(StorageMigrationFindingSchema)
8174
8273
  });
8175
8274
  /**
8176
8275
  * `StorageLocationType` — an addon-declared id that identifies the *kind* of
@@ -19023,7 +19122,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
19023
19122
  }), method(RelocateMediaInputSchema, object({ jobId: string() }), {
19024
19123
  kind: "mutation",
19025
19124
  auth: "admin"
19026
- }), method(object({}), array(RelocateJobSchema).readonly(), {
19125
+ }), method(object({}), UnstampedEventMediaCountSchema, { auth: "admin" }), method(object({}), array(RelocateJobSchema).readonly(), {
19027
19126
  kind: "query",
19028
19127
  auth: "admin"
19029
19128
  }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
@@ -21034,7 +21133,10 @@ method(object({
21034
21133
  }), StorageLocationSchema, {
21035
21134
  kind: "mutation",
21036
21135
  auth: "admin"
21037
- }), method(object({ id: string() }), _void(), {
21136
+ }), method(object({
21137
+ id: string(),
21138
+ force: boolean().optional()
21139
+ }), _void(), {
21038
21140
  kind: "mutation",
21039
21141
  auth: "admin"
21040
21142
  }), method(object({ id: string() }), object({
@@ -25110,6 +25212,33 @@ var intercomCapability = {
25110
25212
  deviceNative: true,
25111
25213
  mode: "singleton",
25112
25214
  deviceTypes: [DeviceType.Camera],
25215
+ /**
25216
+ * **Auth tier: `protected` on every method — deliberate, and load-bearing.**
25217
+ *
25218
+ * Talking through a camera is an OPERATE action, not a CONFIGURE one. This
25219
+ * cap has no configuration surface at all: all six methods open, feed and
25220
+ * close one live audio session against one `deviceId`. That is the same
25221
+ * authority as `ptz.move` or `snapshot.getSnapshot`, both `protected` — and
25222
+ * the opposite of `ptz.savePreset` / `snapshot.invalidateCache`, which are
25223
+ * `admin` because they change what the device IS.
25224
+ *
25225
+ * `protected` does not mean ungated: `protectedProcedure` runs the
25226
+ * `METHOD_ACCESS_MAP` scope check, and every method here is `scope: 'device'`
25227
+ * with `access: 'create'` and a `deviceId` in its input. So a caller needs a
25228
+ * grant that covers THAT camera at `create` — a `camera-viewer` (`view`
25229
+ * only) still cannot talk, and a grant on camera 5 cannot talk through
25230
+ * camera 7.
25231
+ *
25232
+ * Every method was `auth: 'admin'` from the initial commit, which made the
25233
+ * cap unreachable by every non-admin principal — `adminProcedure` throws
25234
+ * `FORBIDDEN: Admin required` BEFORE the scope check runs, so the scope
25235
+ * machinery generated for this cap (`METHOD_ACCESS_MAP`,
25236
+ * `DEVICE_SCOPED_CAPS`, `METHOD_DEVICE_SELECTORS`) was complete and dead. The
25237
+ * `camera-operator` scope preset has promised "PTZ control, intercom,
25238
+ * snapshots" since that same commit; the promise could not be kept. Recorded
25239
+ * as D289; `scripts/check-scope-preset-promises.ts` now fails the build if a
25240
+ * preset promises a cap no row of that preset can reach.
25241
+ */
25113
25242
  methods: {
25114
25243
  /**
25115
25244
  * Open a server-side WebRTC audio-only session. Returns an SDP
@@ -25122,7 +25251,7 @@ var intercomCapability = {
25122
25251
  sdpOffer: string()
25123
25252
  }), {
25124
25253
  kind: "mutation",
25125
- auth: "admin"
25254
+ auth: "protected"
25126
25255
  }),
25127
25256
  handleAnswer: method(object({
25128
25257
  deviceId: number(),
@@ -25130,7 +25259,7 @@ var intercomCapability = {
25130
25259
  sdpAnswer: string()
25131
25260
  }), _void(), {
25132
25261
  kind: "mutation",
25133
- auth: "admin"
25262
+ auth: "protected"
25134
25263
  }),
25135
25264
  /** Close explicitly. Server also auto-closes on 30s idle. */
25136
25265
  stopSession: method(object({
@@ -25138,7 +25267,7 @@ var intercomCapability = {
25138
25267
  sessionId: string()
25139
25268
  }), _void(), {
25140
25269
  kind: "mutation",
25141
- auth: "admin"
25270
+ auth: "protected"
25142
25271
  }),
25143
25272
  /**
25144
25273
  * Open a raw-PCM talk session (no WebRTC SDP plumbing). Used by
@@ -25151,7 +25280,7 @@ var intercomCapability = {
25151
25280
  */
25152
25281
  startTalkSession: method(object({ deviceId: number() }), object({ sessionId: string() }), {
25153
25282
  kind: "mutation",
25154
- auth: "admin"
25283
+ auth: "protected"
25155
25284
  }),
25156
25285
  /**
25157
25286
  * Push one chunk of talk-back audio onto the active talk session.
@@ -25186,12 +25315,12 @@ var intercomCapability = {
25186
25315
  sequenceNumber: number().int()
25187
25316
  }), object({ accepted: boolean() }), {
25188
25317
  kind: "mutation",
25189
- auth: "admin"
25318
+ auth: "protected"
25190
25319
  }),
25191
25320
  /** Close the raw-PCM talk session. Idempotent. */
25192
25321
  endTalkSession: method(object({ deviceId: number() }), _void(), {
25193
25322
  kind: "mutation",
25194
- auth: "admin"
25323
+ auth: "protected"
25195
25324
  })
25196
25325
  },
25197
25326
  events: { onStatusChanged: { data: object({
@@ -34938,6 +35067,12 @@ Object.freeze({
34938
35067
  addonId: null,
34939
35068
  access: "create"
34940
35069
  },
35070
+ "pipelineAnalytics.countUnstampedEventMedia": {
35071
+ capName: "pipeline-analytics",
35072
+ capScope: "device",
35073
+ addonId: null,
35074
+ access: "view"
35075
+ },
34941
35076
  "pipelineAnalytics.deleteDeviceEvents": {
34942
35077
  capName: "pipeline-analytics",
34943
35078
  capScope: "device",
package/dist/addon.mjs CHANGED
@@ -8071,18 +8071,61 @@ var RelocateFootageInputSchema = object({
8071
8071
  * `RecordingConfig.enabled` or camera wrapper bindings. */
8072
8072
  var StorageMigrationLeaseInputSchema = object({ leaseId: string().min(1) });
8073
8073
  var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: string().min(1) });
8074
+ /**
8075
+ * What a `relocateMedia` pass DOES. One engine, three passes — never a second
8076
+ * mover (the engine already walks both collections with a timestamp cursor and
8077
+ * already has a stamp-without-copy path).
8078
+ *
8079
+ * - `move` — the default and the historical behaviour: event-media and
8080
+ * retrain blobs move to `toLocationId` and their rows are
8081
+ * stamped. The enrolled gallery is skipped (D197).
8082
+ * - `seal` — ROWS ONLY, no bytes. Every row whose `locationId` is NULL is
8083
+ * stamped with `toLocationId`. `toLocationId` here is the id the
8084
+ * bytes ALREADY sit on — today's `eventMedia` default — because
8085
+ * a NULL row means "wherever `eventMedia` points *now*", and the
8086
+ * instant a repoint moves that pointer the row reads from the
8087
+ * new disk while its bytes are on the old one.
8088
+ * - `gallery` — the inverse selection of `move`: ONLY the retention-exempt
8089
+ * (enrolled-gallery) rows, which `move` deliberately skips.
8090
+ * `galleryMedia` is `cardinality: 'single'`, so this pass can
8091
+ * never run beside a live second location: it is stop-the-world
8092
+ * by construction, which is acceptable only because the gallery
8093
+ * is a few KB per enrolled sample.
8094
+ */
8095
+ var MediaRelocateModeSchema = _enum([
8096
+ "move",
8097
+ "seal",
8098
+ "gallery"
8099
+ ]);
8074
8100
  var RelocateMediaInputSchema = object({
8075
8101
  toLocationId: string(),
8076
- throttleMbps: number().min(1).max(1e3).optional()
8102
+ throttleMbps: number().min(1).max(1e3).optional(),
8103
+ /** Omitted = `move`, the pre-existing behaviour. */
8104
+ mode: MediaRelocateModeSchema.optional()
8105
+ });
8106
+ /** How many rows still carry NO `locationId` — the population a repoint would
8107
+ * silently re-aim at a disk that does not hold their bytes. Zero is the only
8108
+ * value that permits a non-blocking `eventMedia` cutover. */
8109
+ var UnstampedEventMediaCountSchema = object({
8110
+ media: number().int().nonnegative(),
8111
+ retrainFrames: number().int().nonnegative(),
8112
+ total: number().int().nonnegative()
8077
8113
  });
8078
8114
  var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: string().min(1) });
8079
- /** The independently selectable logical storage classes. `recordings`
8080
- * encompasses the high and mid segment profiles; `recordingsLow` is low
8081
- * segments; `eventMedia` is post-analysis blobs. */
8115
+ /** The independently selectable logical storage classes — every class
8116
+ * `storage.listLocationDeclarations` reports, so an operator never meets a
8117
+ * Zod enum error where they should meet an explanation.
8118
+ *
8119
+ * `recordings` encompasses the high and mid segment profiles; `recordingsLow`
8120
+ * is low segments; `eventMedia` is post-analysis blobs; `galleryMedia` is the
8121
+ * enrolled gallery; `backups` is the system backup archive. The last two have
8122
+ * their own rules — see {@link StorageMigrationFindingCodeSchema}. */
8082
8123
  var StorageMigrationClassSchema = _enum([
8083
8124
  "recordings",
8084
8125
  "recordingsLow",
8085
- "eventMedia"
8126
+ "eventMedia",
8127
+ "backups",
8128
+ "galleryMedia"
8086
8129
  ]);
8087
8130
  /** A destination is always an existing, fully-qualified location id. The
8088
8131
  * migration API intentionally never changes a source location's `basePath`:
@@ -8090,20 +8133,56 @@ var StorageMigrationClassSchema = _enum([
8090
8133
  var StorageMigrationDestinationsSchema = object({
8091
8134
  recordings: string().min(1).optional(),
8092
8135
  recordingsLow: string().min(1).optional(),
8093
- eventMedia: string().min(1).optional()
8136
+ eventMedia: string().min(1).optional(),
8137
+ backups: string().min(1).optional(),
8138
+ galleryMedia: string().min(1).optional()
8094
8139
  }).refine((value) => Object.keys(value).length > 0, { message: "select at least one storage class" });
8140
+ /**
8141
+ * How a migration sequences the cutover against the byte move.
8142
+ *
8143
+ * - `blocking` — the historical order: pause, move every byte, repoint,
8144
+ * resume. Recording is stopped for the whole move. Right
8145
+ * for a small or a cold class, and the only legal mode for
8146
+ * a `cardinality: 'single'` class.
8147
+ * - `nonBlocking` — repoint FIRST, drain behind: seal, pause, repoint,
8148
+ * refresh, resume, then move the past with everything
8149
+ * running. The pause is three bounded instants (a detach +
8150
+ * attach round, a write-gate drain, a lease) instead of one
8151
+ * bounded by bytes. 1.09 TB at 7–14 MB/s is thirty hours of
8152
+ * stopped recording under `blocking`; the same move is
8153
+ * seconds of stopped recording under `nonBlocking`.
8154
+ *
8155
+ * The mode is on the JOB, not only on the input, because `status` is where an
8156
+ * operator finds out which one is running.
8157
+ */
8158
+ var StorageMigrationModeSchema = _enum(["blocking", "nonBlocking"]);
8095
8159
  /** Shared input for planning and starting an orchestrated storage migration. */
8096
8160
  var StorageMigrationInputSchema = object({
8097
8161
  destinations: StorageMigrationDestinationsSchema,
8098
- throttleMbps: number().min(1).max(1e3).optional()
8162
+ throttleMbps: number().min(1).max(1e3).optional(),
8163
+ /** Omitted = `blocking`, which stays the default. */
8164
+ mode: StorageMigrationModeSchema.optional()
8099
8165
  });
8100
- /** The durable coordinator state machine. The only phase that changes default
8101
- * locations is `repointing`, after every selected mover has completed and been
8102
- * verified. */
8166
+ /**
8167
+ * The durable coordinator state machine.
8168
+ *
8169
+ * `blocking`:
8170
+ * planning → pausing → moving → verifying → repointing → refreshing → resuming → done
8171
+ *
8172
+ * `nonBlocking`:
8173
+ * planning → sealing → pausing → repointing → refreshing → resuming → draining → verifying → done
8174
+ *
8175
+ * Same phases, different order plus two new ones — not a second mover.
8176
+ * `sealing` closes the `eventMedia` NULL-row hole BEFORE anything is paused;
8177
+ * `draining` runs the same movers UNLEASED, after every writer is back up.
8178
+ * `repointing` is still the only phase that changes a default location.
8179
+ */
8103
8180
  var StorageMigrationPhaseSchema = _enum([
8104
8181
  "planning",
8182
+ "sealing",
8105
8183
  "pausing",
8106
8184
  "moving",
8185
+ "draining",
8107
8186
  "verifying",
8108
8187
  "repointing",
8109
8188
  "refreshing",
@@ -8128,6 +8207,9 @@ var StorageMigrationMoveSchema = object({
8128
8207
  var StorageMigrationJobSchema = object({
8129
8208
  jobId: string(),
8130
8209
  phase: StorageMigrationPhaseSchema,
8210
+ /** Which order this job is running. `status` is the only place an operator
8211
+ * can tell a seconds-long cutover from a thirty-hour one. */
8212
+ mode: StorageMigrationModeSchema,
8131
8213
  destinations: StorageMigrationDestinationsSchema,
8132
8214
  throttleMbps: number(),
8133
8215
  moves: array(StorageMigrationMoveSchema),
@@ -8140,13 +8222,30 @@ var StorageMigrationJobSchema = object({
8140
8222
  finishedAt: number().nullable(),
8141
8223
  error: string().nullable()
8142
8224
  });
8225
+ var StorageMigrationFindingSchema = object({
8226
+ code: _enum([
8227
+ "sharesDeviceWithSource",
8228
+ "deviceIdentityUnknown",
8229
+ "unstampedEventMediaRows",
8230
+ "blockingOnly",
8231
+ "noMover"
8232
+ ]),
8233
+ storageClass: StorageMigrationClassSchema,
8234
+ /** Human-readable, already carrying the ids and counts. */
8235
+ message: string()
8236
+ });
8143
8237
  var StorageMigrationPlanSchema = object({
8144
8238
  destinations: StorageMigrationDestinationsSchema,
8239
+ /** The mode this plan was built for. A plan is only valid for its mode: the
8240
+ * `eventMedia` seal gate and the single-cardinality refusal both depend on
8241
+ * it. */
8242
+ mode: StorageMigrationModeSchema,
8145
8243
  moves: array(object({
8146
8244
  storageClass: StorageMigrationClassSchema,
8147
8245
  fromLocationId: string(),
8148
8246
  toLocationId: string()
8149
- }))
8247
+ })),
8248
+ findings: array(StorageMigrationFindingSchema)
8150
8249
  });
8151
8250
  /**
8152
8251
  * `StorageLocationType` — an addon-declared id that identifies the *kind* of
@@ -18999,7 +19098,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
18999
19098
  }), method(RelocateMediaInputSchema, object({ jobId: string() }), {
19000
19099
  kind: "mutation",
19001
19100
  auth: "admin"
19002
- }), method(object({}), array(RelocateJobSchema).readonly(), {
19101
+ }), method(object({}), UnstampedEventMediaCountSchema, { auth: "admin" }), method(object({}), array(RelocateJobSchema).readonly(), {
19003
19102
  kind: "query",
19004
19103
  auth: "admin"
19005
19104
  }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
@@ -21010,7 +21109,10 @@ method(object({
21010
21109
  }), StorageLocationSchema, {
21011
21110
  kind: "mutation",
21012
21111
  auth: "admin"
21013
- }), method(object({ id: string() }), _void(), {
21112
+ }), method(object({
21113
+ id: string(),
21114
+ force: boolean().optional()
21115
+ }), _void(), {
21014
21116
  kind: "mutation",
21015
21117
  auth: "admin"
21016
21118
  }), method(object({ id: string() }), object({
@@ -25086,6 +25188,33 @@ var intercomCapability = {
25086
25188
  deviceNative: true,
25087
25189
  mode: "singleton",
25088
25190
  deviceTypes: [DeviceType.Camera],
25191
+ /**
25192
+ * **Auth tier: `protected` on every method — deliberate, and load-bearing.**
25193
+ *
25194
+ * Talking through a camera is an OPERATE action, not a CONFIGURE one. This
25195
+ * cap has no configuration surface at all: all six methods open, feed and
25196
+ * close one live audio session against one `deviceId`. That is the same
25197
+ * authority as `ptz.move` or `snapshot.getSnapshot`, both `protected` — and
25198
+ * the opposite of `ptz.savePreset` / `snapshot.invalidateCache`, which are
25199
+ * `admin` because they change what the device IS.
25200
+ *
25201
+ * `protected` does not mean ungated: `protectedProcedure` runs the
25202
+ * `METHOD_ACCESS_MAP` scope check, and every method here is `scope: 'device'`
25203
+ * with `access: 'create'` and a `deviceId` in its input. So a caller needs a
25204
+ * grant that covers THAT camera at `create` — a `camera-viewer` (`view`
25205
+ * only) still cannot talk, and a grant on camera 5 cannot talk through
25206
+ * camera 7.
25207
+ *
25208
+ * Every method was `auth: 'admin'` from the initial commit, which made the
25209
+ * cap unreachable by every non-admin principal — `adminProcedure` throws
25210
+ * `FORBIDDEN: Admin required` BEFORE the scope check runs, so the scope
25211
+ * machinery generated for this cap (`METHOD_ACCESS_MAP`,
25212
+ * `DEVICE_SCOPED_CAPS`, `METHOD_DEVICE_SELECTORS`) was complete and dead. The
25213
+ * `camera-operator` scope preset has promised "PTZ control, intercom,
25214
+ * snapshots" since that same commit; the promise could not be kept. Recorded
25215
+ * as D289; `scripts/check-scope-preset-promises.ts` now fails the build if a
25216
+ * preset promises a cap no row of that preset can reach.
25217
+ */
25089
25218
  methods: {
25090
25219
  /**
25091
25220
  * Open a server-side WebRTC audio-only session. Returns an SDP
@@ -25098,7 +25227,7 @@ var intercomCapability = {
25098
25227
  sdpOffer: string()
25099
25228
  }), {
25100
25229
  kind: "mutation",
25101
- auth: "admin"
25230
+ auth: "protected"
25102
25231
  }),
25103
25232
  handleAnswer: method(object({
25104
25233
  deviceId: number(),
@@ -25106,7 +25235,7 @@ var intercomCapability = {
25106
25235
  sdpAnswer: string()
25107
25236
  }), _void(), {
25108
25237
  kind: "mutation",
25109
- auth: "admin"
25238
+ auth: "protected"
25110
25239
  }),
25111
25240
  /** Close explicitly. Server also auto-closes on 30s idle. */
25112
25241
  stopSession: method(object({
@@ -25114,7 +25243,7 @@ var intercomCapability = {
25114
25243
  sessionId: string()
25115
25244
  }), _void(), {
25116
25245
  kind: "mutation",
25117
- auth: "admin"
25246
+ auth: "protected"
25118
25247
  }),
25119
25248
  /**
25120
25249
  * Open a raw-PCM talk session (no WebRTC SDP plumbing). Used by
@@ -25127,7 +25256,7 @@ var intercomCapability = {
25127
25256
  */
25128
25257
  startTalkSession: method(object({ deviceId: number() }), object({ sessionId: string() }), {
25129
25258
  kind: "mutation",
25130
- auth: "admin"
25259
+ auth: "protected"
25131
25260
  }),
25132
25261
  /**
25133
25262
  * Push one chunk of talk-back audio onto the active talk session.
@@ -25162,12 +25291,12 @@ var intercomCapability = {
25162
25291
  sequenceNumber: number().int()
25163
25292
  }), object({ accepted: boolean() }), {
25164
25293
  kind: "mutation",
25165
- auth: "admin"
25294
+ auth: "protected"
25166
25295
  }),
25167
25296
  /** Close the raw-PCM talk session. Idempotent. */
25168
25297
  endTalkSession: method(object({ deviceId: number() }), _void(), {
25169
25298
  kind: "mutation",
25170
- auth: "admin"
25299
+ auth: "protected"
25171
25300
  })
25172
25301
  },
25173
25302
  events: { onStatusChanged: { data: object({
@@ -34914,6 +35043,12 @@ Object.freeze({
34914
35043
  addonId: null,
34915
35044
  access: "create"
34916
35045
  },
35046
+ "pipelineAnalytics.countUnstampedEventMedia": {
35047
+ capName: "pipeline-analytics",
35048
+ capScope: "device",
35049
+ addonId: null,
35050
+ access: "view"
35051
+ },
34917
35052
  "pipelineAnalytics.deleteDeviceEvents": {
34918
35053
  capName: "pipeline-analytics",
34919
35054
  capScope: "device",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-rtsp",
3
- "version": "1.2.41",
3
+ "version": "1.2.43",
4
4
  "description": "Generic RTSP camera device provider addon for CamStack",
5
5
  "keywords": [
6
6
  "camstack",