@camstack/addon-provider-petkit 0.2.41 → 0.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
@@ -9141,18 +9141,61 @@ var RelocateFootageInputSchema = object({
9141
9141
  * `RecordingConfig.enabled` or camera wrapper bindings. */
9142
9142
  var StorageMigrationLeaseInputSchema = object({ leaseId: string().min(1) });
9143
9143
  var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: string().min(1) });
9144
+ /**
9145
+ * What a `relocateMedia` pass DOES. One engine, three passes — never a second
9146
+ * mover (the engine already walks both collections with a timestamp cursor and
9147
+ * already has a stamp-without-copy path).
9148
+ *
9149
+ * - `move` — the default and the historical behaviour: event-media and
9150
+ * retrain blobs move to `toLocationId` and their rows are
9151
+ * stamped. The enrolled gallery is skipped (D197).
9152
+ * - `seal` — ROWS ONLY, no bytes. Every row whose `locationId` is NULL is
9153
+ * stamped with `toLocationId`. `toLocationId` here is the id the
9154
+ * bytes ALREADY sit on — today's `eventMedia` default — because
9155
+ * a NULL row means "wherever `eventMedia` points *now*", and the
9156
+ * instant a repoint moves that pointer the row reads from the
9157
+ * new disk while its bytes are on the old one.
9158
+ * - `gallery` — the inverse selection of `move`: ONLY the retention-exempt
9159
+ * (enrolled-gallery) rows, which `move` deliberately skips.
9160
+ * `galleryMedia` is `cardinality: 'single'`, so this pass can
9161
+ * never run beside a live second location: it is stop-the-world
9162
+ * by construction, which is acceptable only because the gallery
9163
+ * is a few KB per enrolled sample.
9164
+ */
9165
+ var MediaRelocateModeSchema = _enum([
9166
+ "move",
9167
+ "seal",
9168
+ "gallery"
9169
+ ]);
9144
9170
  var RelocateMediaInputSchema = object({
9145
9171
  toLocationId: string(),
9146
- throttleMbps: number().min(1).max(1e3).optional()
9172
+ throttleMbps: number().min(1).max(1e3).optional(),
9173
+ /** Omitted = `move`, the pre-existing behaviour. */
9174
+ mode: MediaRelocateModeSchema.optional()
9175
+ });
9176
+ /** How many rows still carry NO `locationId` — the population a repoint would
9177
+ * silently re-aim at a disk that does not hold their bytes. Zero is the only
9178
+ * value that permits a non-blocking `eventMedia` cutover. */
9179
+ var UnstampedEventMediaCountSchema = object({
9180
+ media: number().int().nonnegative(),
9181
+ retrainFrames: number().int().nonnegative(),
9182
+ total: number().int().nonnegative()
9147
9183
  });
9148
9184
  var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: string().min(1) });
9149
- /** The independently selectable logical storage classes. `recordings`
9150
- * encompasses the high and mid segment profiles; `recordingsLow` is low
9151
- * segments; `eventMedia` is post-analysis blobs. */
9185
+ /** The independently selectable logical storage classes — every class
9186
+ * `storage.listLocationDeclarations` reports, so an operator never meets a
9187
+ * Zod enum error where they should meet an explanation.
9188
+ *
9189
+ * `recordings` encompasses the high and mid segment profiles; `recordingsLow`
9190
+ * is low segments; `eventMedia` is post-analysis blobs; `galleryMedia` is the
9191
+ * enrolled gallery; `backups` is the system backup archive. The last two have
9192
+ * their own rules — see {@link StorageMigrationFindingCodeSchema}. */
9152
9193
  var StorageMigrationClassSchema = _enum([
9153
9194
  "recordings",
9154
9195
  "recordingsLow",
9155
- "eventMedia"
9196
+ "eventMedia",
9197
+ "backups",
9198
+ "galleryMedia"
9156
9199
  ]);
9157
9200
  /** A destination is always an existing, fully-qualified location id. The
9158
9201
  * migration API intentionally never changes a source location's `basePath`:
@@ -9160,20 +9203,56 @@ var StorageMigrationClassSchema = _enum([
9160
9203
  var StorageMigrationDestinationsSchema = object({
9161
9204
  recordings: string().min(1).optional(),
9162
9205
  recordingsLow: string().min(1).optional(),
9163
- eventMedia: string().min(1).optional()
9206
+ eventMedia: string().min(1).optional(),
9207
+ backups: string().min(1).optional(),
9208
+ galleryMedia: string().min(1).optional()
9164
9209
  }).refine((value) => Object.keys(value).length > 0, { message: "select at least one storage class" });
9210
+ /**
9211
+ * How a migration sequences the cutover against the byte move.
9212
+ *
9213
+ * - `blocking` — the historical order: pause, move every byte, repoint,
9214
+ * resume. Recording is stopped for the whole move. Right
9215
+ * for a small or a cold class, and the only legal mode for
9216
+ * a `cardinality: 'single'` class.
9217
+ * - `nonBlocking` — repoint FIRST, drain behind: seal, pause, repoint,
9218
+ * refresh, resume, then move the past with everything
9219
+ * running. The pause is three bounded instants (a detach +
9220
+ * attach round, a write-gate drain, a lease) instead of one
9221
+ * bounded by bytes. 1.09 TB at 7–14 MB/s is thirty hours of
9222
+ * stopped recording under `blocking`; the same move is
9223
+ * seconds of stopped recording under `nonBlocking`.
9224
+ *
9225
+ * The mode is on the JOB, not only on the input, because `status` is where an
9226
+ * operator finds out which one is running.
9227
+ */
9228
+ var StorageMigrationModeSchema = _enum(["blocking", "nonBlocking"]);
9165
9229
  /** Shared input for planning and starting an orchestrated storage migration. */
9166
9230
  var StorageMigrationInputSchema = object({
9167
9231
  destinations: StorageMigrationDestinationsSchema,
9168
- throttleMbps: number().min(1).max(1e3).optional()
9232
+ throttleMbps: number().min(1).max(1e3).optional(),
9233
+ /** Omitted = `blocking`, which stays the default. */
9234
+ mode: StorageMigrationModeSchema.optional()
9169
9235
  });
9170
- /** The durable coordinator state machine. The only phase that changes default
9171
- * locations is `repointing`, after every selected mover has completed and been
9172
- * verified. */
9236
+ /**
9237
+ * The durable coordinator state machine.
9238
+ *
9239
+ * `blocking`:
9240
+ * planning → pausing → moving → verifying → repointing → refreshing → resuming → done
9241
+ *
9242
+ * `nonBlocking`:
9243
+ * planning → sealing → pausing → repointing → refreshing → resuming → draining → verifying → done
9244
+ *
9245
+ * Same phases, different order plus two new ones — not a second mover.
9246
+ * `sealing` closes the `eventMedia` NULL-row hole BEFORE anything is paused;
9247
+ * `draining` runs the same movers UNLEASED, after every writer is back up.
9248
+ * `repointing` is still the only phase that changes a default location.
9249
+ */
9173
9250
  var StorageMigrationPhaseSchema = _enum([
9174
9251
  "planning",
9252
+ "sealing",
9175
9253
  "pausing",
9176
9254
  "moving",
9255
+ "draining",
9177
9256
  "verifying",
9178
9257
  "repointing",
9179
9258
  "refreshing",
@@ -9198,6 +9277,9 @@ var StorageMigrationMoveSchema = object({
9198
9277
  var StorageMigrationJobSchema = object({
9199
9278
  jobId: string(),
9200
9279
  phase: StorageMigrationPhaseSchema,
9280
+ /** Which order this job is running. `status` is the only place an operator
9281
+ * can tell a seconds-long cutover from a thirty-hour one. */
9282
+ mode: StorageMigrationModeSchema,
9201
9283
  destinations: StorageMigrationDestinationsSchema,
9202
9284
  throttleMbps: number(),
9203
9285
  moves: array(StorageMigrationMoveSchema),
@@ -9210,13 +9292,30 @@ var StorageMigrationJobSchema = object({
9210
9292
  finishedAt: number().nullable(),
9211
9293
  error: string().nullable()
9212
9294
  });
9295
+ var StorageMigrationFindingSchema = object({
9296
+ code: _enum([
9297
+ "sharesDeviceWithSource",
9298
+ "deviceIdentityUnknown",
9299
+ "unstampedEventMediaRows",
9300
+ "blockingOnly",
9301
+ "noMover"
9302
+ ]),
9303
+ storageClass: StorageMigrationClassSchema,
9304
+ /** Human-readable, already carrying the ids and counts. */
9305
+ message: string()
9306
+ });
9213
9307
  var StorageMigrationPlanSchema = object({
9214
9308
  destinations: StorageMigrationDestinationsSchema,
9309
+ /** The mode this plan was built for. A plan is only valid for its mode: the
9310
+ * `eventMedia` seal gate and the single-cardinality refusal both depend on
9311
+ * it. */
9312
+ mode: StorageMigrationModeSchema,
9215
9313
  moves: array(object({
9216
9314
  storageClass: StorageMigrationClassSchema,
9217
9315
  fromLocationId: string(),
9218
9316
  toLocationId: string()
9219
- }))
9317
+ })),
9318
+ findings: array(StorageMigrationFindingSchema)
9220
9319
  });
9221
9320
  /**
9222
9321
  * `StorageLocationType` — an addon-declared id that identifies the *kind* of
@@ -20086,7 +20185,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
20086
20185
  }), method(RelocateMediaInputSchema, object({ jobId: string() }), {
20087
20186
  kind: "mutation",
20088
20187
  auth: "admin"
20089
- }), method(object({}), array(RelocateJobSchema).readonly(), {
20188
+ }), method(object({}), UnstampedEventMediaCountSchema, { auth: "admin" }), method(object({}), array(RelocateJobSchema).readonly(), {
20090
20189
  kind: "query",
20091
20190
  auth: "admin"
20092
20191
  }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
@@ -21993,7 +22092,10 @@ method(object({
21993
22092
  }), StorageLocationSchema, {
21994
22093
  kind: "mutation",
21995
22094
  auth: "admin"
21996
- }), method(object({ id: string() }), _void(), {
22095
+ }), method(object({
22096
+ id: string(),
22097
+ force: boolean().optional()
22098
+ }), _void(), {
21997
22099
  kind: "mutation",
21998
22100
  auth: "admin"
21999
22101
  }), method(object({ id: string() }), object({
@@ -26069,6 +26171,33 @@ var intercomCapability = {
26069
26171
  deviceNative: true,
26070
26172
  mode: "singleton",
26071
26173
  deviceTypes: [DeviceType.Camera],
26174
+ /**
26175
+ * **Auth tier: `protected` on every method — deliberate, and load-bearing.**
26176
+ *
26177
+ * Talking through a camera is an OPERATE action, not a CONFIGURE one. This
26178
+ * cap has no configuration surface at all: all six methods open, feed and
26179
+ * close one live audio session against one `deviceId`. That is the same
26180
+ * authority as `ptz.move` or `snapshot.getSnapshot`, both `protected` — and
26181
+ * the opposite of `ptz.savePreset` / `snapshot.invalidateCache`, which are
26182
+ * `admin` because they change what the device IS.
26183
+ *
26184
+ * `protected` does not mean ungated: `protectedProcedure` runs the
26185
+ * `METHOD_ACCESS_MAP` scope check, and every method here is `scope: 'device'`
26186
+ * with `access: 'create'` and a `deviceId` in its input. So a caller needs a
26187
+ * grant that covers THAT camera at `create` — a `camera-viewer` (`view`
26188
+ * only) still cannot talk, and a grant on camera 5 cannot talk through
26189
+ * camera 7.
26190
+ *
26191
+ * Every method was `auth: 'admin'` from the initial commit, which made the
26192
+ * cap unreachable by every non-admin principal — `adminProcedure` throws
26193
+ * `FORBIDDEN: Admin required` BEFORE the scope check runs, so the scope
26194
+ * machinery generated for this cap (`METHOD_ACCESS_MAP`,
26195
+ * `DEVICE_SCOPED_CAPS`, `METHOD_DEVICE_SELECTORS`) was complete and dead. The
26196
+ * `camera-operator` scope preset has promised "PTZ control, intercom,
26197
+ * snapshots" since that same commit; the promise could not be kept. Recorded
26198
+ * as D289; `scripts/check-scope-preset-promises.ts` now fails the build if a
26199
+ * preset promises a cap no row of that preset can reach.
26200
+ */
26072
26201
  methods: {
26073
26202
  /**
26074
26203
  * Open a server-side WebRTC audio-only session. Returns an SDP
@@ -26081,7 +26210,7 @@ var intercomCapability = {
26081
26210
  sdpOffer: string()
26082
26211
  }), {
26083
26212
  kind: "mutation",
26084
- auth: "admin"
26213
+ auth: "protected"
26085
26214
  }),
26086
26215
  handleAnswer: method(object({
26087
26216
  deviceId: number(),
@@ -26089,7 +26218,7 @@ var intercomCapability = {
26089
26218
  sdpAnswer: string()
26090
26219
  }), _void(), {
26091
26220
  kind: "mutation",
26092
- auth: "admin"
26221
+ auth: "protected"
26093
26222
  }),
26094
26223
  /** Close explicitly. Server also auto-closes on 30s idle. */
26095
26224
  stopSession: method(object({
@@ -26097,7 +26226,7 @@ var intercomCapability = {
26097
26226
  sessionId: string()
26098
26227
  }), _void(), {
26099
26228
  kind: "mutation",
26100
- auth: "admin"
26229
+ auth: "protected"
26101
26230
  }),
26102
26231
  /**
26103
26232
  * Open a raw-PCM talk session (no WebRTC SDP plumbing). Used by
@@ -26110,7 +26239,7 @@ var intercomCapability = {
26110
26239
  */
26111
26240
  startTalkSession: method(object({ deviceId: number() }), object({ sessionId: string() }), {
26112
26241
  kind: "mutation",
26113
- auth: "admin"
26242
+ auth: "protected"
26114
26243
  }),
26115
26244
  /**
26116
26245
  * Push one chunk of talk-back audio onto the active talk session.
@@ -26145,12 +26274,12 @@ var intercomCapability = {
26145
26274
  sequenceNumber: number().int()
26146
26275
  }), object({ accepted: boolean() }), {
26147
26276
  kind: "mutation",
26148
- auth: "admin"
26277
+ auth: "protected"
26149
26278
  }),
26150
26279
  /** Close the raw-PCM talk session. Idempotent. */
26151
26280
  endTalkSession: method(object({ deviceId: number() }), _void(), {
26152
26281
  kind: "mutation",
26153
- auth: "admin"
26282
+ auth: "protected"
26154
26283
  })
26155
26284
  },
26156
26285
  events: { onStatusChanged: { data: object({
@@ -35831,6 +35960,12 @@ Object.freeze({
35831
35960
  addonId: null,
35832
35961
  access: "create"
35833
35962
  },
35963
+ "pipelineAnalytics.countUnstampedEventMedia": {
35964
+ capName: "pipeline-analytics",
35965
+ capScope: "device",
35966
+ addonId: null,
35967
+ access: "view"
35968
+ },
35834
35969
  "pipelineAnalytics.deleteDeviceEvents": {
35835
35970
  capName: "pipeline-analytics",
35836
35971
  capScope: "device",
package/dist/addon.mjs CHANGED
@@ -9140,18 +9140,61 @@ var RelocateFootageInputSchema = object({
9140
9140
  * `RecordingConfig.enabled` or camera wrapper bindings. */
9141
9141
  var StorageMigrationLeaseInputSchema = object({ leaseId: string().min(1) });
9142
9142
  var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: string().min(1) });
9143
+ /**
9144
+ * What a `relocateMedia` pass DOES. One engine, three passes — never a second
9145
+ * mover (the engine already walks both collections with a timestamp cursor and
9146
+ * already has a stamp-without-copy path).
9147
+ *
9148
+ * - `move` — the default and the historical behaviour: event-media and
9149
+ * retrain blobs move to `toLocationId` and their rows are
9150
+ * stamped. The enrolled gallery is skipped (D197).
9151
+ * - `seal` — ROWS ONLY, no bytes. Every row whose `locationId` is NULL is
9152
+ * stamped with `toLocationId`. `toLocationId` here is the id the
9153
+ * bytes ALREADY sit on — today's `eventMedia` default — because
9154
+ * a NULL row means "wherever `eventMedia` points *now*", and the
9155
+ * instant a repoint moves that pointer the row reads from the
9156
+ * new disk while its bytes are on the old one.
9157
+ * - `gallery` — the inverse selection of `move`: ONLY the retention-exempt
9158
+ * (enrolled-gallery) rows, which `move` deliberately skips.
9159
+ * `galleryMedia` is `cardinality: 'single'`, so this pass can
9160
+ * never run beside a live second location: it is stop-the-world
9161
+ * by construction, which is acceptable only because the gallery
9162
+ * is a few KB per enrolled sample.
9163
+ */
9164
+ var MediaRelocateModeSchema = _enum([
9165
+ "move",
9166
+ "seal",
9167
+ "gallery"
9168
+ ]);
9143
9169
  var RelocateMediaInputSchema = object({
9144
9170
  toLocationId: string(),
9145
- throttleMbps: number().min(1).max(1e3).optional()
9171
+ throttleMbps: number().min(1).max(1e3).optional(),
9172
+ /** Omitted = `move`, the pre-existing behaviour. */
9173
+ mode: MediaRelocateModeSchema.optional()
9174
+ });
9175
+ /** How many rows still carry NO `locationId` — the population a repoint would
9176
+ * silently re-aim at a disk that does not hold their bytes. Zero is the only
9177
+ * value that permits a non-blocking `eventMedia` cutover. */
9178
+ var UnstampedEventMediaCountSchema = object({
9179
+ media: number().int().nonnegative(),
9180
+ retrainFrames: number().int().nonnegative(),
9181
+ total: number().int().nonnegative()
9146
9182
  });
9147
9183
  var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: string().min(1) });
9148
- /** The independently selectable logical storage classes. `recordings`
9149
- * encompasses the high and mid segment profiles; `recordingsLow` is low
9150
- * segments; `eventMedia` is post-analysis blobs. */
9184
+ /** The independently selectable logical storage classes — every class
9185
+ * `storage.listLocationDeclarations` reports, so an operator never meets a
9186
+ * Zod enum error where they should meet an explanation.
9187
+ *
9188
+ * `recordings` encompasses the high and mid segment profiles; `recordingsLow`
9189
+ * is low segments; `eventMedia` is post-analysis blobs; `galleryMedia` is the
9190
+ * enrolled gallery; `backups` is the system backup archive. The last two have
9191
+ * their own rules — see {@link StorageMigrationFindingCodeSchema}. */
9151
9192
  var StorageMigrationClassSchema = _enum([
9152
9193
  "recordings",
9153
9194
  "recordingsLow",
9154
- "eventMedia"
9195
+ "eventMedia",
9196
+ "backups",
9197
+ "galleryMedia"
9155
9198
  ]);
9156
9199
  /** A destination is always an existing, fully-qualified location id. The
9157
9200
  * migration API intentionally never changes a source location's `basePath`:
@@ -9159,20 +9202,56 @@ var StorageMigrationClassSchema = _enum([
9159
9202
  var StorageMigrationDestinationsSchema = object({
9160
9203
  recordings: string().min(1).optional(),
9161
9204
  recordingsLow: string().min(1).optional(),
9162
- eventMedia: string().min(1).optional()
9205
+ eventMedia: string().min(1).optional(),
9206
+ backups: string().min(1).optional(),
9207
+ galleryMedia: string().min(1).optional()
9163
9208
  }).refine((value) => Object.keys(value).length > 0, { message: "select at least one storage class" });
9209
+ /**
9210
+ * How a migration sequences the cutover against the byte move.
9211
+ *
9212
+ * - `blocking` — the historical order: pause, move every byte, repoint,
9213
+ * resume. Recording is stopped for the whole move. Right
9214
+ * for a small or a cold class, and the only legal mode for
9215
+ * a `cardinality: 'single'` class.
9216
+ * - `nonBlocking` — repoint FIRST, drain behind: seal, pause, repoint,
9217
+ * refresh, resume, then move the past with everything
9218
+ * running. The pause is three bounded instants (a detach +
9219
+ * attach round, a write-gate drain, a lease) instead of one
9220
+ * bounded by bytes. 1.09 TB at 7–14 MB/s is thirty hours of
9221
+ * stopped recording under `blocking`; the same move is
9222
+ * seconds of stopped recording under `nonBlocking`.
9223
+ *
9224
+ * The mode is on the JOB, not only on the input, because `status` is where an
9225
+ * operator finds out which one is running.
9226
+ */
9227
+ var StorageMigrationModeSchema = _enum(["blocking", "nonBlocking"]);
9164
9228
  /** Shared input for planning and starting an orchestrated storage migration. */
9165
9229
  var StorageMigrationInputSchema = object({
9166
9230
  destinations: StorageMigrationDestinationsSchema,
9167
- throttleMbps: number().min(1).max(1e3).optional()
9231
+ throttleMbps: number().min(1).max(1e3).optional(),
9232
+ /** Omitted = `blocking`, which stays the default. */
9233
+ mode: StorageMigrationModeSchema.optional()
9168
9234
  });
9169
- /** The durable coordinator state machine. The only phase that changes default
9170
- * locations is `repointing`, after every selected mover has completed and been
9171
- * verified. */
9235
+ /**
9236
+ * The durable coordinator state machine.
9237
+ *
9238
+ * `blocking`:
9239
+ * planning → pausing → moving → verifying → repointing → refreshing → resuming → done
9240
+ *
9241
+ * `nonBlocking`:
9242
+ * planning → sealing → pausing → repointing → refreshing → resuming → draining → verifying → done
9243
+ *
9244
+ * Same phases, different order plus two new ones — not a second mover.
9245
+ * `sealing` closes the `eventMedia` NULL-row hole BEFORE anything is paused;
9246
+ * `draining` runs the same movers UNLEASED, after every writer is back up.
9247
+ * `repointing` is still the only phase that changes a default location.
9248
+ */
9172
9249
  var StorageMigrationPhaseSchema = _enum([
9173
9250
  "planning",
9251
+ "sealing",
9174
9252
  "pausing",
9175
9253
  "moving",
9254
+ "draining",
9176
9255
  "verifying",
9177
9256
  "repointing",
9178
9257
  "refreshing",
@@ -9197,6 +9276,9 @@ var StorageMigrationMoveSchema = object({
9197
9276
  var StorageMigrationJobSchema = object({
9198
9277
  jobId: string(),
9199
9278
  phase: StorageMigrationPhaseSchema,
9279
+ /** Which order this job is running. `status` is the only place an operator
9280
+ * can tell a seconds-long cutover from a thirty-hour one. */
9281
+ mode: StorageMigrationModeSchema,
9200
9282
  destinations: StorageMigrationDestinationsSchema,
9201
9283
  throttleMbps: number(),
9202
9284
  moves: array(StorageMigrationMoveSchema),
@@ -9209,13 +9291,30 @@ var StorageMigrationJobSchema = object({
9209
9291
  finishedAt: number().nullable(),
9210
9292
  error: string().nullable()
9211
9293
  });
9294
+ var StorageMigrationFindingSchema = object({
9295
+ code: _enum([
9296
+ "sharesDeviceWithSource",
9297
+ "deviceIdentityUnknown",
9298
+ "unstampedEventMediaRows",
9299
+ "blockingOnly",
9300
+ "noMover"
9301
+ ]),
9302
+ storageClass: StorageMigrationClassSchema,
9303
+ /** Human-readable, already carrying the ids and counts. */
9304
+ message: string()
9305
+ });
9212
9306
  var StorageMigrationPlanSchema = object({
9213
9307
  destinations: StorageMigrationDestinationsSchema,
9308
+ /** The mode this plan was built for. A plan is only valid for its mode: the
9309
+ * `eventMedia` seal gate and the single-cardinality refusal both depend on
9310
+ * it. */
9311
+ mode: StorageMigrationModeSchema,
9214
9312
  moves: array(object({
9215
9313
  storageClass: StorageMigrationClassSchema,
9216
9314
  fromLocationId: string(),
9217
9315
  toLocationId: string()
9218
- }))
9316
+ })),
9317
+ findings: array(StorageMigrationFindingSchema)
9219
9318
  });
9220
9319
  /**
9221
9320
  * `StorageLocationType` — an addon-declared id that identifies the *kind* of
@@ -20085,7 +20184,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
20085
20184
  }), method(RelocateMediaInputSchema, object({ jobId: string() }), {
20086
20185
  kind: "mutation",
20087
20186
  auth: "admin"
20088
- }), method(object({}), array(RelocateJobSchema).readonly(), {
20187
+ }), method(object({}), UnstampedEventMediaCountSchema, { auth: "admin" }), method(object({}), array(RelocateJobSchema).readonly(), {
20089
20188
  kind: "query",
20090
20189
  auth: "admin"
20091
20190
  }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
@@ -21992,7 +22091,10 @@ method(object({
21992
22091
  }), StorageLocationSchema, {
21993
22092
  kind: "mutation",
21994
22093
  auth: "admin"
21995
- }), method(object({ id: string() }), _void(), {
22094
+ }), method(object({
22095
+ id: string(),
22096
+ force: boolean().optional()
22097
+ }), _void(), {
21996
22098
  kind: "mutation",
21997
22099
  auth: "admin"
21998
22100
  }), method(object({ id: string() }), object({
@@ -26068,6 +26170,33 @@ var intercomCapability = {
26068
26170
  deviceNative: true,
26069
26171
  mode: "singleton",
26070
26172
  deviceTypes: [DeviceType.Camera],
26173
+ /**
26174
+ * **Auth tier: `protected` on every method — deliberate, and load-bearing.**
26175
+ *
26176
+ * Talking through a camera is an OPERATE action, not a CONFIGURE one. This
26177
+ * cap has no configuration surface at all: all six methods open, feed and
26178
+ * close one live audio session against one `deviceId`. That is the same
26179
+ * authority as `ptz.move` or `snapshot.getSnapshot`, both `protected` — and
26180
+ * the opposite of `ptz.savePreset` / `snapshot.invalidateCache`, which are
26181
+ * `admin` because they change what the device IS.
26182
+ *
26183
+ * `protected` does not mean ungated: `protectedProcedure` runs the
26184
+ * `METHOD_ACCESS_MAP` scope check, and every method here is `scope: 'device'`
26185
+ * with `access: 'create'` and a `deviceId` in its input. So a caller needs a
26186
+ * grant that covers THAT camera at `create` — a `camera-viewer` (`view`
26187
+ * only) still cannot talk, and a grant on camera 5 cannot talk through
26188
+ * camera 7.
26189
+ *
26190
+ * Every method was `auth: 'admin'` from the initial commit, which made the
26191
+ * cap unreachable by every non-admin principal — `adminProcedure` throws
26192
+ * `FORBIDDEN: Admin required` BEFORE the scope check runs, so the scope
26193
+ * machinery generated for this cap (`METHOD_ACCESS_MAP`,
26194
+ * `DEVICE_SCOPED_CAPS`, `METHOD_DEVICE_SELECTORS`) was complete and dead. The
26195
+ * `camera-operator` scope preset has promised "PTZ control, intercom,
26196
+ * snapshots" since that same commit; the promise could not be kept. Recorded
26197
+ * as D289; `scripts/check-scope-preset-promises.ts` now fails the build if a
26198
+ * preset promises a cap no row of that preset can reach.
26199
+ */
26071
26200
  methods: {
26072
26201
  /**
26073
26202
  * Open a server-side WebRTC audio-only session. Returns an SDP
@@ -26080,7 +26209,7 @@ var intercomCapability = {
26080
26209
  sdpOffer: string()
26081
26210
  }), {
26082
26211
  kind: "mutation",
26083
- auth: "admin"
26212
+ auth: "protected"
26084
26213
  }),
26085
26214
  handleAnswer: method(object({
26086
26215
  deviceId: number(),
@@ -26088,7 +26217,7 @@ var intercomCapability = {
26088
26217
  sdpAnswer: string()
26089
26218
  }), _void(), {
26090
26219
  kind: "mutation",
26091
- auth: "admin"
26220
+ auth: "protected"
26092
26221
  }),
26093
26222
  /** Close explicitly. Server also auto-closes on 30s idle. */
26094
26223
  stopSession: method(object({
@@ -26096,7 +26225,7 @@ var intercomCapability = {
26096
26225
  sessionId: string()
26097
26226
  }), _void(), {
26098
26227
  kind: "mutation",
26099
- auth: "admin"
26228
+ auth: "protected"
26100
26229
  }),
26101
26230
  /**
26102
26231
  * Open a raw-PCM talk session (no WebRTC SDP plumbing). Used by
@@ -26109,7 +26238,7 @@ var intercomCapability = {
26109
26238
  */
26110
26239
  startTalkSession: method(object({ deviceId: number() }), object({ sessionId: string() }), {
26111
26240
  kind: "mutation",
26112
- auth: "admin"
26241
+ auth: "protected"
26113
26242
  }),
26114
26243
  /**
26115
26244
  * Push one chunk of talk-back audio onto the active talk session.
@@ -26144,12 +26273,12 @@ var intercomCapability = {
26144
26273
  sequenceNumber: number().int()
26145
26274
  }), object({ accepted: boolean() }), {
26146
26275
  kind: "mutation",
26147
- auth: "admin"
26276
+ auth: "protected"
26148
26277
  }),
26149
26278
  /** Close the raw-PCM talk session. Idempotent. */
26150
26279
  endTalkSession: method(object({ deviceId: number() }), _void(), {
26151
26280
  kind: "mutation",
26152
- auth: "admin"
26281
+ auth: "protected"
26153
26282
  })
26154
26283
  },
26155
26284
  events: { onStatusChanged: { data: object({
@@ -35830,6 +35959,12 @@ Object.freeze({
35830
35959
  addonId: null,
35831
35960
  access: "create"
35832
35961
  },
35962
+ "pipelineAnalytics.countUnstampedEventMedia": {
35963
+ capName: "pipeline-analytics",
35964
+ capScope: "device",
35965
+ addonId: null,
35966
+ access: "view"
35967
+ },
35833
35968
  "pipelineAnalytics.deleteDeviceEvents": {
35834
35969
  capName: "pipeline-analytics",
35835
35970
  capScope: "device",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-petkit",
3
- "version": "0.2.41",
3
+ "version": "0.2.43",
4
4
  "description": "PetKit smart-feeder device-provider addon for CamStack — wraps the @apocaliss92/nodepetkit PetKit cloud client",
5
5
  "keywords": [
6
6
  "camstack",