@camstack/addon-provider-wyze 0.2.45 → 0.2.47

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
@@ -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
@@ -19016,7 +19115,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
19016
19115
  }), method(RelocateMediaInputSchema, object({ jobId: string() }), {
19017
19116
  kind: "mutation",
19018
19117
  auth: "admin"
19019
- }), method(object({}), array(RelocateJobSchema).readonly(), {
19118
+ }), method(object({}), UnstampedEventMediaCountSchema, { auth: "admin" }), method(object({}), array(RelocateJobSchema).readonly(), {
19020
19119
  kind: "query",
19021
19120
  auth: "admin"
19022
19121
  }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
@@ -21027,7 +21126,10 @@ method(object({
21027
21126
  }), StorageLocationSchema, {
21028
21127
  kind: "mutation",
21029
21128
  auth: "admin"
21030
- }), method(object({ id: string() }), _void(), {
21129
+ }), method(object({
21130
+ id: string(),
21131
+ force: boolean().optional()
21132
+ }), _void(), {
21031
21133
  kind: "mutation",
21032
21134
  auth: "admin"
21033
21135
  }), method(object({ id: string() }), object({
@@ -25103,6 +25205,33 @@ var intercomCapability = {
25103
25205
  deviceNative: true,
25104
25206
  mode: "singleton",
25105
25207
  deviceTypes: [DeviceType.Camera],
25208
+ /**
25209
+ * **Auth tier: `protected` on every method — deliberate, and load-bearing.**
25210
+ *
25211
+ * Talking through a camera is an OPERATE action, not a CONFIGURE one. This
25212
+ * cap has no configuration surface at all: all six methods open, feed and
25213
+ * close one live audio session against one `deviceId`. That is the same
25214
+ * authority as `ptz.move` or `snapshot.getSnapshot`, both `protected` — and
25215
+ * the opposite of `ptz.savePreset` / `snapshot.invalidateCache`, which are
25216
+ * `admin` because they change what the device IS.
25217
+ *
25218
+ * `protected` does not mean ungated: `protectedProcedure` runs the
25219
+ * `METHOD_ACCESS_MAP` scope check, and every method here is `scope: 'device'`
25220
+ * with `access: 'create'` and a `deviceId` in its input. So a caller needs a
25221
+ * grant that covers THAT camera at `create` — a `camera-viewer` (`view`
25222
+ * only) still cannot talk, and a grant on camera 5 cannot talk through
25223
+ * camera 7.
25224
+ *
25225
+ * Every method was `auth: 'admin'` from the initial commit, which made the
25226
+ * cap unreachable by every non-admin principal — `adminProcedure` throws
25227
+ * `FORBIDDEN: Admin required` BEFORE the scope check runs, so the scope
25228
+ * machinery generated for this cap (`METHOD_ACCESS_MAP`,
25229
+ * `DEVICE_SCOPED_CAPS`, `METHOD_DEVICE_SELECTORS`) was complete and dead. The
25230
+ * `camera-operator` scope preset has promised "PTZ control, intercom,
25231
+ * snapshots" since that same commit; the promise could not be kept. Recorded
25232
+ * as D289; `scripts/check-scope-preset-promises.ts` now fails the build if a
25233
+ * preset promises a cap no row of that preset can reach.
25234
+ */
25106
25235
  methods: {
25107
25236
  /**
25108
25237
  * Open a server-side WebRTC audio-only session. Returns an SDP
@@ -25115,7 +25244,7 @@ var intercomCapability = {
25115
25244
  sdpOffer: string()
25116
25245
  }), {
25117
25246
  kind: "mutation",
25118
- auth: "admin"
25247
+ auth: "protected"
25119
25248
  }),
25120
25249
  handleAnswer: method(object({
25121
25250
  deviceId: number(),
@@ -25123,7 +25252,7 @@ var intercomCapability = {
25123
25252
  sdpAnswer: string()
25124
25253
  }), _void(), {
25125
25254
  kind: "mutation",
25126
- auth: "admin"
25255
+ auth: "protected"
25127
25256
  }),
25128
25257
  /** Close explicitly. Server also auto-closes on 30s idle. */
25129
25258
  stopSession: method(object({
@@ -25131,7 +25260,7 @@ var intercomCapability = {
25131
25260
  sessionId: string()
25132
25261
  }), _void(), {
25133
25262
  kind: "mutation",
25134
- auth: "admin"
25263
+ auth: "protected"
25135
25264
  }),
25136
25265
  /**
25137
25266
  * Open a raw-PCM talk session (no WebRTC SDP plumbing). Used by
@@ -25144,7 +25273,7 @@ var intercomCapability = {
25144
25273
  */
25145
25274
  startTalkSession: method(object({ deviceId: number() }), object({ sessionId: string() }), {
25146
25275
  kind: "mutation",
25147
- auth: "admin"
25276
+ auth: "protected"
25148
25277
  }),
25149
25278
  /**
25150
25279
  * Push one chunk of talk-back audio onto the active talk session.
@@ -25179,12 +25308,12 @@ var intercomCapability = {
25179
25308
  sequenceNumber: number().int()
25180
25309
  }), object({ accepted: boolean() }), {
25181
25310
  kind: "mutation",
25182
- auth: "admin"
25311
+ auth: "protected"
25183
25312
  }),
25184
25313
  /** Close the raw-PCM talk session. Idempotent. */
25185
25314
  endTalkSession: method(object({ deviceId: number() }), _void(), {
25186
25315
  kind: "mutation",
25187
- auth: "admin"
25316
+ auth: "protected"
25188
25317
  })
25189
25318
  },
25190
25319
  events: { onStatusChanged: { data: object({
@@ -34865,6 +34994,12 @@ Object.freeze({
34865
34994
  addonId: null,
34866
34995
  access: "create"
34867
34996
  },
34997
+ "pipelineAnalytics.countUnstampedEventMedia": {
34998
+ capName: "pipeline-analytics",
34999
+ capScope: "device",
35000
+ addonId: null,
35001
+ access: "view"
35002
+ },
34868
35003
  "pipelineAnalytics.deleteDeviceEvents": {
34869
35004
  capName: "pipeline-analytics",
34870
35005
  capScope: "device",
package/dist/addon.mjs CHANGED
@@ -8050,18 +8050,61 @@ var RelocateFootageInputSchema = object({
8050
8050
  * `RecordingConfig.enabled` or camera wrapper bindings. */
8051
8051
  var StorageMigrationLeaseInputSchema = object({ leaseId: string().min(1) });
8052
8052
  var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: string().min(1) });
8053
+ /**
8054
+ * What a `relocateMedia` pass DOES. One engine, three passes — never a second
8055
+ * mover (the engine already walks both collections with a timestamp cursor and
8056
+ * already has a stamp-without-copy path).
8057
+ *
8058
+ * - `move` — the default and the historical behaviour: event-media and
8059
+ * retrain blobs move to `toLocationId` and their rows are
8060
+ * stamped. The enrolled gallery is skipped (D197).
8061
+ * - `seal` — ROWS ONLY, no bytes. Every row whose `locationId` is NULL is
8062
+ * stamped with `toLocationId`. `toLocationId` here is the id the
8063
+ * bytes ALREADY sit on — today's `eventMedia` default — because
8064
+ * a NULL row means "wherever `eventMedia` points *now*", and the
8065
+ * instant a repoint moves that pointer the row reads from the
8066
+ * new disk while its bytes are on the old one.
8067
+ * - `gallery` — the inverse selection of `move`: ONLY the retention-exempt
8068
+ * (enrolled-gallery) rows, which `move` deliberately skips.
8069
+ * `galleryMedia` is `cardinality: 'single'`, so this pass can
8070
+ * never run beside a live second location: it is stop-the-world
8071
+ * by construction, which is acceptable only because the gallery
8072
+ * is a few KB per enrolled sample.
8073
+ */
8074
+ var MediaRelocateModeSchema = _enum([
8075
+ "move",
8076
+ "seal",
8077
+ "gallery"
8078
+ ]);
8053
8079
  var RelocateMediaInputSchema = object({
8054
8080
  toLocationId: string(),
8055
- throttleMbps: number().min(1).max(1e3).optional()
8081
+ throttleMbps: number().min(1).max(1e3).optional(),
8082
+ /** Omitted = `move`, the pre-existing behaviour. */
8083
+ mode: MediaRelocateModeSchema.optional()
8084
+ });
8085
+ /** How many rows still carry NO `locationId` — the population a repoint would
8086
+ * silently re-aim at a disk that does not hold their bytes. Zero is the only
8087
+ * value that permits a non-blocking `eventMedia` cutover. */
8088
+ var UnstampedEventMediaCountSchema = object({
8089
+ media: number().int().nonnegative(),
8090
+ retrainFrames: number().int().nonnegative(),
8091
+ total: number().int().nonnegative()
8056
8092
  });
8057
8093
  var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: string().min(1) });
8058
- /** The independently selectable logical storage classes. `recordings`
8059
- * encompasses the high and mid segment profiles; `recordingsLow` is low
8060
- * segments; `eventMedia` is post-analysis blobs. */
8094
+ /** The independently selectable logical storage classes — every class
8095
+ * `storage.listLocationDeclarations` reports, so an operator never meets a
8096
+ * Zod enum error where they should meet an explanation.
8097
+ *
8098
+ * `recordings` encompasses the high and mid segment profiles; `recordingsLow`
8099
+ * is low segments; `eventMedia` is post-analysis blobs; `galleryMedia` is the
8100
+ * enrolled gallery; `backups` is the system backup archive. The last two have
8101
+ * their own rules — see {@link StorageMigrationFindingCodeSchema}. */
8061
8102
  var StorageMigrationClassSchema = _enum([
8062
8103
  "recordings",
8063
8104
  "recordingsLow",
8064
- "eventMedia"
8105
+ "eventMedia",
8106
+ "backups",
8107
+ "galleryMedia"
8065
8108
  ]);
8066
8109
  /** A destination is always an existing, fully-qualified location id. The
8067
8110
  * migration API intentionally never changes a source location's `basePath`:
@@ -8069,20 +8112,56 @@ var StorageMigrationClassSchema = _enum([
8069
8112
  var StorageMigrationDestinationsSchema = object({
8070
8113
  recordings: string().min(1).optional(),
8071
8114
  recordingsLow: string().min(1).optional(),
8072
- eventMedia: string().min(1).optional()
8115
+ eventMedia: string().min(1).optional(),
8116
+ backups: string().min(1).optional(),
8117
+ galleryMedia: string().min(1).optional()
8073
8118
  }).refine((value) => Object.keys(value).length > 0, { message: "select at least one storage class" });
8119
+ /**
8120
+ * How a migration sequences the cutover against the byte move.
8121
+ *
8122
+ * - `blocking` — the historical order: pause, move every byte, repoint,
8123
+ * resume. Recording is stopped for the whole move. Right
8124
+ * for a small or a cold class, and the only legal mode for
8125
+ * a `cardinality: 'single'` class.
8126
+ * - `nonBlocking` — repoint FIRST, drain behind: seal, pause, repoint,
8127
+ * refresh, resume, then move the past with everything
8128
+ * running. The pause is three bounded instants (a detach +
8129
+ * attach round, a write-gate drain, a lease) instead of one
8130
+ * bounded by bytes. 1.09 TB at 7–14 MB/s is thirty hours of
8131
+ * stopped recording under `blocking`; the same move is
8132
+ * seconds of stopped recording under `nonBlocking`.
8133
+ *
8134
+ * The mode is on the JOB, not only on the input, because `status` is where an
8135
+ * operator finds out which one is running.
8136
+ */
8137
+ var StorageMigrationModeSchema = _enum(["blocking", "nonBlocking"]);
8074
8138
  /** Shared input for planning and starting an orchestrated storage migration. */
8075
8139
  var StorageMigrationInputSchema = object({
8076
8140
  destinations: StorageMigrationDestinationsSchema,
8077
- throttleMbps: number().min(1).max(1e3).optional()
8141
+ throttleMbps: number().min(1).max(1e3).optional(),
8142
+ /** Omitted = `blocking`, which stays the default. */
8143
+ mode: StorageMigrationModeSchema.optional()
8078
8144
  });
8079
- /** The durable coordinator state machine. The only phase that changes default
8080
- * locations is `repointing`, after every selected mover has completed and been
8081
- * verified. */
8145
+ /**
8146
+ * The durable coordinator state machine.
8147
+ *
8148
+ * `blocking`:
8149
+ * planning → pausing → moving → verifying → repointing → refreshing → resuming → done
8150
+ *
8151
+ * `nonBlocking`:
8152
+ * planning → sealing → pausing → repointing → refreshing → resuming → draining → verifying → done
8153
+ *
8154
+ * Same phases, different order plus two new ones — not a second mover.
8155
+ * `sealing` closes the `eventMedia` NULL-row hole BEFORE anything is paused;
8156
+ * `draining` runs the same movers UNLEASED, after every writer is back up.
8157
+ * `repointing` is still the only phase that changes a default location.
8158
+ */
8082
8159
  var StorageMigrationPhaseSchema = _enum([
8083
8160
  "planning",
8161
+ "sealing",
8084
8162
  "pausing",
8085
8163
  "moving",
8164
+ "draining",
8086
8165
  "verifying",
8087
8166
  "repointing",
8088
8167
  "refreshing",
@@ -8107,6 +8186,9 @@ var StorageMigrationMoveSchema = object({
8107
8186
  var StorageMigrationJobSchema = object({
8108
8187
  jobId: string(),
8109
8188
  phase: StorageMigrationPhaseSchema,
8189
+ /** Which order this job is running. `status` is the only place an operator
8190
+ * can tell a seconds-long cutover from a thirty-hour one. */
8191
+ mode: StorageMigrationModeSchema,
8110
8192
  destinations: StorageMigrationDestinationsSchema,
8111
8193
  throttleMbps: number(),
8112
8194
  moves: array(StorageMigrationMoveSchema),
@@ -8119,13 +8201,30 @@ var StorageMigrationJobSchema = object({
8119
8201
  finishedAt: number().nullable(),
8120
8202
  error: string().nullable()
8121
8203
  });
8204
+ var StorageMigrationFindingSchema = object({
8205
+ code: _enum([
8206
+ "sharesDeviceWithSource",
8207
+ "deviceIdentityUnknown",
8208
+ "unstampedEventMediaRows",
8209
+ "blockingOnly",
8210
+ "noMover"
8211
+ ]),
8212
+ storageClass: StorageMigrationClassSchema,
8213
+ /** Human-readable, already carrying the ids and counts. */
8214
+ message: string()
8215
+ });
8122
8216
  var StorageMigrationPlanSchema = object({
8123
8217
  destinations: StorageMigrationDestinationsSchema,
8218
+ /** The mode this plan was built for. A plan is only valid for its mode: the
8219
+ * `eventMedia` seal gate and the single-cardinality refusal both depend on
8220
+ * it. */
8221
+ mode: StorageMigrationModeSchema,
8124
8222
  moves: array(object({
8125
8223
  storageClass: StorageMigrationClassSchema,
8126
8224
  fromLocationId: string(),
8127
8225
  toLocationId: string()
8128
- }))
8226
+ })),
8227
+ findings: array(StorageMigrationFindingSchema)
8129
8228
  });
8130
8229
  /**
8131
8230
  * `StorageLocationType` — an addon-declared id that identifies the *kind* of
@@ -18995,7 +19094,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
18995
19094
  }), method(RelocateMediaInputSchema, object({ jobId: string() }), {
18996
19095
  kind: "mutation",
18997
19096
  auth: "admin"
18998
- }), method(object({}), array(RelocateJobSchema).readonly(), {
19097
+ }), method(object({}), UnstampedEventMediaCountSchema, { auth: "admin" }), method(object({}), array(RelocateJobSchema).readonly(), {
18999
19098
  kind: "query",
19000
19099
  auth: "admin"
19001
19100
  }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
@@ -21006,7 +21105,10 @@ method(object({
21006
21105
  }), StorageLocationSchema, {
21007
21106
  kind: "mutation",
21008
21107
  auth: "admin"
21009
- }), method(object({ id: string() }), _void(), {
21108
+ }), method(object({
21109
+ id: string(),
21110
+ force: boolean().optional()
21111
+ }), _void(), {
21010
21112
  kind: "mutation",
21011
21113
  auth: "admin"
21012
21114
  }), method(object({ id: string() }), object({
@@ -25082,6 +25184,33 @@ var intercomCapability = {
25082
25184
  deviceNative: true,
25083
25185
  mode: "singleton",
25084
25186
  deviceTypes: [DeviceType.Camera],
25187
+ /**
25188
+ * **Auth tier: `protected` on every method — deliberate, and load-bearing.**
25189
+ *
25190
+ * Talking through a camera is an OPERATE action, not a CONFIGURE one. This
25191
+ * cap has no configuration surface at all: all six methods open, feed and
25192
+ * close one live audio session against one `deviceId`. That is the same
25193
+ * authority as `ptz.move` or `snapshot.getSnapshot`, both `protected` — and
25194
+ * the opposite of `ptz.savePreset` / `snapshot.invalidateCache`, which are
25195
+ * `admin` because they change what the device IS.
25196
+ *
25197
+ * `protected` does not mean ungated: `protectedProcedure` runs the
25198
+ * `METHOD_ACCESS_MAP` scope check, and every method here is `scope: 'device'`
25199
+ * with `access: 'create'` and a `deviceId` in its input. So a caller needs a
25200
+ * grant that covers THAT camera at `create` — a `camera-viewer` (`view`
25201
+ * only) still cannot talk, and a grant on camera 5 cannot talk through
25202
+ * camera 7.
25203
+ *
25204
+ * Every method was `auth: 'admin'` from the initial commit, which made the
25205
+ * cap unreachable by every non-admin principal — `adminProcedure` throws
25206
+ * `FORBIDDEN: Admin required` BEFORE the scope check runs, so the scope
25207
+ * machinery generated for this cap (`METHOD_ACCESS_MAP`,
25208
+ * `DEVICE_SCOPED_CAPS`, `METHOD_DEVICE_SELECTORS`) was complete and dead. The
25209
+ * `camera-operator` scope preset has promised "PTZ control, intercom,
25210
+ * snapshots" since that same commit; the promise could not be kept. Recorded
25211
+ * as D289; `scripts/check-scope-preset-promises.ts` now fails the build if a
25212
+ * preset promises a cap no row of that preset can reach.
25213
+ */
25085
25214
  methods: {
25086
25215
  /**
25087
25216
  * Open a server-side WebRTC audio-only session. Returns an SDP
@@ -25094,7 +25223,7 @@ var intercomCapability = {
25094
25223
  sdpOffer: string()
25095
25224
  }), {
25096
25225
  kind: "mutation",
25097
- auth: "admin"
25226
+ auth: "protected"
25098
25227
  }),
25099
25228
  handleAnswer: method(object({
25100
25229
  deviceId: number(),
@@ -25102,7 +25231,7 @@ var intercomCapability = {
25102
25231
  sdpAnswer: string()
25103
25232
  }), _void(), {
25104
25233
  kind: "mutation",
25105
- auth: "admin"
25234
+ auth: "protected"
25106
25235
  }),
25107
25236
  /** Close explicitly. Server also auto-closes on 30s idle. */
25108
25237
  stopSession: method(object({
@@ -25110,7 +25239,7 @@ var intercomCapability = {
25110
25239
  sessionId: string()
25111
25240
  }), _void(), {
25112
25241
  kind: "mutation",
25113
- auth: "admin"
25242
+ auth: "protected"
25114
25243
  }),
25115
25244
  /**
25116
25245
  * Open a raw-PCM talk session (no WebRTC SDP plumbing). Used by
@@ -25123,7 +25252,7 @@ var intercomCapability = {
25123
25252
  */
25124
25253
  startTalkSession: method(object({ deviceId: number() }), object({ sessionId: string() }), {
25125
25254
  kind: "mutation",
25126
- auth: "admin"
25255
+ auth: "protected"
25127
25256
  }),
25128
25257
  /**
25129
25258
  * Push one chunk of talk-back audio onto the active talk session.
@@ -25158,12 +25287,12 @@ var intercomCapability = {
25158
25287
  sequenceNumber: number().int()
25159
25288
  }), object({ accepted: boolean() }), {
25160
25289
  kind: "mutation",
25161
- auth: "admin"
25290
+ auth: "protected"
25162
25291
  }),
25163
25292
  /** Close the raw-PCM talk session. Idempotent. */
25164
25293
  endTalkSession: method(object({ deviceId: number() }), _void(), {
25165
25294
  kind: "mutation",
25166
- auth: "admin"
25295
+ auth: "protected"
25167
25296
  })
25168
25297
  },
25169
25298
  events: { onStatusChanged: { data: object({
@@ -34844,6 +34973,12 @@ Object.freeze({
34844
34973
  addonId: null,
34845
34974
  access: "create"
34846
34975
  },
34976
+ "pipelineAnalytics.countUnstampedEventMedia": {
34977
+ capName: "pipeline-analytics",
34978
+ capScope: "device",
34979
+ addonId: null,
34980
+ access: "view"
34981
+ },
34847
34982
  "pipelineAnalytics.deleteDeviceEvents": {
34848
34983
  capName: "pipeline-analytics",
34849
34984
  capScope: "device",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-wyze",
3
- "version": "0.2.45",
3
+ "version": "0.2.47",
4
4
  "description": "Wyze camera device-provider addon for CamStack — wraps the @apocaliss92/wyze-bridge-js P2P/DTLS client, feeding the stream-broker via the pull-rfc4571 lazy-publish path (a structural twin of addon-provider-reolink)",
5
5
  "keywords": [
6
6
  "camstack",