@camstack/addon-provider-gree 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
@@ -8042,18 +8042,61 @@ var RelocateFootageInputSchema = object({
8042
8042
  * `RecordingConfig.enabled` or camera wrapper bindings. */
8043
8043
  var StorageMigrationLeaseInputSchema = object({ leaseId: string().min(1) });
8044
8044
  var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: string().min(1) });
8045
+ /**
8046
+ * What a `relocateMedia` pass DOES. One engine, three passes — never a second
8047
+ * mover (the engine already walks both collections with a timestamp cursor and
8048
+ * already has a stamp-without-copy path).
8049
+ *
8050
+ * - `move` — the default and the historical behaviour: event-media and
8051
+ * retrain blobs move to `toLocationId` and their rows are
8052
+ * stamped. The enrolled gallery is skipped (D197).
8053
+ * - `seal` — ROWS ONLY, no bytes. Every row whose `locationId` is NULL is
8054
+ * stamped with `toLocationId`. `toLocationId` here is the id the
8055
+ * bytes ALREADY sit on — today's `eventMedia` default — because
8056
+ * a NULL row means "wherever `eventMedia` points *now*", and the
8057
+ * instant a repoint moves that pointer the row reads from the
8058
+ * new disk while its bytes are on the old one.
8059
+ * - `gallery` — the inverse selection of `move`: ONLY the retention-exempt
8060
+ * (enrolled-gallery) rows, which `move` deliberately skips.
8061
+ * `galleryMedia` is `cardinality: 'single'`, so this pass can
8062
+ * never run beside a live second location: it is stop-the-world
8063
+ * by construction, which is acceptable only because the gallery
8064
+ * is a few KB per enrolled sample.
8065
+ */
8066
+ var MediaRelocateModeSchema = _enum([
8067
+ "move",
8068
+ "seal",
8069
+ "gallery"
8070
+ ]);
8045
8071
  var RelocateMediaInputSchema = object({
8046
8072
  toLocationId: string(),
8047
- throttleMbps: number().min(1).max(1e3).optional()
8073
+ throttleMbps: number().min(1).max(1e3).optional(),
8074
+ /** Omitted = `move`, the pre-existing behaviour. */
8075
+ mode: MediaRelocateModeSchema.optional()
8076
+ });
8077
+ /** How many rows still carry NO `locationId` — the population a repoint would
8078
+ * silently re-aim at a disk that does not hold their bytes. Zero is the only
8079
+ * value that permits a non-blocking `eventMedia` cutover. */
8080
+ var UnstampedEventMediaCountSchema = object({
8081
+ media: number().int().nonnegative(),
8082
+ retrainFrames: number().int().nonnegative(),
8083
+ total: number().int().nonnegative()
8048
8084
  });
8049
8085
  var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: string().min(1) });
8050
- /** The independently selectable logical storage classes. `recordings`
8051
- * encompasses the high and mid segment profiles; `recordingsLow` is low
8052
- * segments; `eventMedia` is post-analysis blobs. */
8086
+ /** The independently selectable logical storage classes — every class
8087
+ * `storage.listLocationDeclarations` reports, so an operator never meets a
8088
+ * Zod enum error where they should meet an explanation.
8089
+ *
8090
+ * `recordings` encompasses the high and mid segment profiles; `recordingsLow`
8091
+ * is low segments; `eventMedia` is post-analysis blobs; `galleryMedia` is the
8092
+ * enrolled gallery; `backups` is the system backup archive. The last two have
8093
+ * their own rules — see {@link StorageMigrationFindingCodeSchema}. */
8053
8094
  var StorageMigrationClassSchema = _enum([
8054
8095
  "recordings",
8055
8096
  "recordingsLow",
8056
- "eventMedia"
8097
+ "eventMedia",
8098
+ "backups",
8099
+ "galleryMedia"
8057
8100
  ]);
8058
8101
  /** A destination is always an existing, fully-qualified location id. The
8059
8102
  * migration API intentionally never changes a source location's `basePath`:
@@ -8061,20 +8104,56 @@ var StorageMigrationClassSchema = _enum([
8061
8104
  var StorageMigrationDestinationsSchema = object({
8062
8105
  recordings: string().min(1).optional(),
8063
8106
  recordingsLow: string().min(1).optional(),
8064
- eventMedia: string().min(1).optional()
8107
+ eventMedia: string().min(1).optional(),
8108
+ backups: string().min(1).optional(),
8109
+ galleryMedia: string().min(1).optional()
8065
8110
  }).refine((value) => Object.keys(value).length > 0, { message: "select at least one storage class" });
8111
+ /**
8112
+ * How a migration sequences the cutover against the byte move.
8113
+ *
8114
+ * - `blocking` — the historical order: pause, move every byte, repoint,
8115
+ * resume. Recording is stopped for the whole move. Right
8116
+ * for a small or a cold class, and the only legal mode for
8117
+ * a `cardinality: 'single'` class.
8118
+ * - `nonBlocking` — repoint FIRST, drain behind: seal, pause, repoint,
8119
+ * refresh, resume, then move the past with everything
8120
+ * running. The pause is three bounded instants (a detach +
8121
+ * attach round, a write-gate drain, a lease) instead of one
8122
+ * bounded by bytes. 1.09 TB at 7–14 MB/s is thirty hours of
8123
+ * stopped recording under `blocking`; the same move is
8124
+ * seconds of stopped recording under `nonBlocking`.
8125
+ *
8126
+ * The mode is on the JOB, not only on the input, because `status` is where an
8127
+ * operator finds out which one is running.
8128
+ */
8129
+ var StorageMigrationModeSchema = _enum(["blocking", "nonBlocking"]);
8066
8130
  /** Shared input for planning and starting an orchestrated storage migration. */
8067
8131
  var StorageMigrationInputSchema = object({
8068
8132
  destinations: StorageMigrationDestinationsSchema,
8069
- throttleMbps: number().min(1).max(1e3).optional()
8133
+ throttleMbps: number().min(1).max(1e3).optional(),
8134
+ /** Omitted = `blocking`, which stays the default. */
8135
+ mode: StorageMigrationModeSchema.optional()
8070
8136
  });
8071
- /** The durable coordinator state machine. The only phase that changes default
8072
- * locations is `repointing`, after every selected mover has completed and been
8073
- * verified. */
8137
+ /**
8138
+ * The durable coordinator state machine.
8139
+ *
8140
+ * `blocking`:
8141
+ * planning → pausing → moving → verifying → repointing → refreshing → resuming → done
8142
+ *
8143
+ * `nonBlocking`:
8144
+ * planning → sealing → pausing → repointing → refreshing → resuming → draining → verifying → done
8145
+ *
8146
+ * Same phases, different order plus two new ones — not a second mover.
8147
+ * `sealing` closes the `eventMedia` NULL-row hole BEFORE anything is paused;
8148
+ * `draining` runs the same movers UNLEASED, after every writer is back up.
8149
+ * `repointing` is still the only phase that changes a default location.
8150
+ */
8074
8151
  var StorageMigrationPhaseSchema = _enum([
8075
8152
  "planning",
8153
+ "sealing",
8076
8154
  "pausing",
8077
8155
  "moving",
8156
+ "draining",
8078
8157
  "verifying",
8079
8158
  "repointing",
8080
8159
  "refreshing",
@@ -8099,6 +8178,9 @@ var StorageMigrationMoveSchema = object({
8099
8178
  var StorageMigrationJobSchema = object({
8100
8179
  jobId: string(),
8101
8180
  phase: StorageMigrationPhaseSchema,
8181
+ /** Which order this job is running. `status` is the only place an operator
8182
+ * can tell a seconds-long cutover from a thirty-hour one. */
8183
+ mode: StorageMigrationModeSchema,
8102
8184
  destinations: StorageMigrationDestinationsSchema,
8103
8185
  throttleMbps: number(),
8104
8186
  moves: array(StorageMigrationMoveSchema),
@@ -8111,13 +8193,30 @@ var StorageMigrationJobSchema = object({
8111
8193
  finishedAt: number().nullable(),
8112
8194
  error: string().nullable()
8113
8195
  });
8196
+ var StorageMigrationFindingSchema = object({
8197
+ code: _enum([
8198
+ "sharesDeviceWithSource",
8199
+ "deviceIdentityUnknown",
8200
+ "unstampedEventMediaRows",
8201
+ "blockingOnly",
8202
+ "noMover"
8203
+ ]),
8204
+ storageClass: StorageMigrationClassSchema,
8205
+ /** Human-readable, already carrying the ids and counts. */
8206
+ message: string()
8207
+ });
8114
8208
  var StorageMigrationPlanSchema = object({
8115
8209
  destinations: StorageMigrationDestinationsSchema,
8210
+ /** The mode this plan was built for. A plan is only valid for its mode: the
8211
+ * `eventMedia` seal gate and the single-cardinality refusal both depend on
8212
+ * it. */
8213
+ mode: StorageMigrationModeSchema,
8116
8214
  moves: array(object({
8117
8215
  storageClass: StorageMigrationClassSchema,
8118
8216
  fromLocationId: string(),
8119
8217
  toLocationId: string()
8120
- }))
8218
+ })),
8219
+ findings: array(StorageMigrationFindingSchema)
8121
8220
  });
8122
8221
  /**
8123
8222
  * `StorageLocationType` — an addon-declared id that identifies the *kind* of
@@ -18970,7 +19069,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
18970
19069
  }), method(RelocateMediaInputSchema, object({ jobId: string() }), {
18971
19070
  kind: "mutation",
18972
19071
  auth: "admin"
18973
- }), method(object({}), array(RelocateJobSchema).readonly(), {
19072
+ }), method(object({}), UnstampedEventMediaCountSchema, { auth: "admin" }), method(object({}), array(RelocateJobSchema).readonly(), {
18974
19073
  kind: "query",
18975
19074
  auth: "admin"
18976
19075
  }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
@@ -20877,7 +20976,10 @@ method(object({
20877
20976
  }), StorageLocationSchema, {
20878
20977
  kind: "mutation",
20879
20978
  auth: "admin"
20880
- }), method(object({ id: string() }), _void(), {
20979
+ }), method(object({
20980
+ id: string(),
20981
+ force: boolean().optional()
20982
+ }), _void(), {
20881
20983
  kind: "mutation",
20882
20984
  auth: "admin"
20883
20985
  }), method(object({ id: string() }), object({
@@ -24945,6 +25047,33 @@ var intercomCapability = {
24945
25047
  deviceNative: true,
24946
25048
  mode: "singleton",
24947
25049
  deviceTypes: [DeviceType.Camera],
25050
+ /**
25051
+ * **Auth tier: `protected` on every method — deliberate, and load-bearing.**
25052
+ *
25053
+ * Talking through a camera is an OPERATE action, not a CONFIGURE one. This
25054
+ * cap has no configuration surface at all: all six methods open, feed and
25055
+ * close one live audio session against one `deviceId`. That is the same
25056
+ * authority as `ptz.move` or `snapshot.getSnapshot`, both `protected` — and
25057
+ * the opposite of `ptz.savePreset` / `snapshot.invalidateCache`, which are
25058
+ * `admin` because they change what the device IS.
25059
+ *
25060
+ * `protected` does not mean ungated: `protectedProcedure` runs the
25061
+ * `METHOD_ACCESS_MAP` scope check, and every method here is `scope: 'device'`
25062
+ * with `access: 'create'` and a `deviceId` in its input. So a caller needs a
25063
+ * grant that covers THAT camera at `create` — a `camera-viewer` (`view`
25064
+ * only) still cannot talk, and a grant on camera 5 cannot talk through
25065
+ * camera 7.
25066
+ *
25067
+ * Every method was `auth: 'admin'` from the initial commit, which made the
25068
+ * cap unreachable by every non-admin principal — `adminProcedure` throws
25069
+ * `FORBIDDEN: Admin required` BEFORE the scope check runs, so the scope
25070
+ * machinery generated for this cap (`METHOD_ACCESS_MAP`,
25071
+ * `DEVICE_SCOPED_CAPS`, `METHOD_DEVICE_SELECTORS`) was complete and dead. The
25072
+ * `camera-operator` scope preset has promised "PTZ control, intercom,
25073
+ * snapshots" since that same commit; the promise could not be kept. Recorded
25074
+ * as D289; `scripts/check-scope-preset-promises.ts` now fails the build if a
25075
+ * preset promises a cap no row of that preset can reach.
25076
+ */
24948
25077
  methods: {
24949
25078
  /**
24950
25079
  * Open a server-side WebRTC audio-only session. Returns an SDP
@@ -24957,7 +25086,7 @@ var intercomCapability = {
24957
25086
  sdpOffer: string()
24958
25087
  }), {
24959
25088
  kind: "mutation",
24960
- auth: "admin"
25089
+ auth: "protected"
24961
25090
  }),
24962
25091
  handleAnswer: method(object({
24963
25092
  deviceId: number(),
@@ -24965,7 +25094,7 @@ var intercomCapability = {
24965
25094
  sdpAnswer: string()
24966
25095
  }), _void(), {
24967
25096
  kind: "mutation",
24968
- auth: "admin"
25097
+ auth: "protected"
24969
25098
  }),
24970
25099
  /** Close explicitly. Server also auto-closes on 30s idle. */
24971
25100
  stopSession: method(object({
@@ -24973,7 +25102,7 @@ var intercomCapability = {
24973
25102
  sessionId: string()
24974
25103
  }), _void(), {
24975
25104
  kind: "mutation",
24976
- auth: "admin"
25105
+ auth: "protected"
24977
25106
  }),
24978
25107
  /**
24979
25108
  * Open a raw-PCM talk session (no WebRTC SDP plumbing). Used by
@@ -24986,7 +25115,7 @@ var intercomCapability = {
24986
25115
  */
24987
25116
  startTalkSession: method(object({ deviceId: number() }), object({ sessionId: string() }), {
24988
25117
  kind: "mutation",
24989
- auth: "admin"
25118
+ auth: "protected"
24990
25119
  }),
24991
25120
  /**
24992
25121
  * Push one chunk of talk-back audio onto the active talk session.
@@ -25021,12 +25150,12 @@ var intercomCapability = {
25021
25150
  sequenceNumber: number().int()
25022
25151
  }), object({ accepted: boolean() }), {
25023
25152
  kind: "mutation",
25024
- auth: "admin"
25153
+ auth: "protected"
25025
25154
  }),
25026
25155
  /** Close the raw-PCM talk session. Idempotent. */
25027
25156
  endTalkSession: method(object({ deviceId: number() }), _void(), {
25028
25157
  kind: "mutation",
25029
- auth: "admin"
25158
+ auth: "protected"
25030
25159
  })
25031
25160
  },
25032
25161
  events: { onStatusChanged: { data: object({
@@ -34707,6 +34836,12 @@ Object.freeze({
34707
34836
  addonId: null,
34708
34837
  access: "create"
34709
34838
  },
34839
+ "pipelineAnalytics.countUnstampedEventMedia": {
34840
+ capName: "pipeline-analytics",
34841
+ capScope: "device",
34842
+ addonId: null,
34843
+ access: "view"
34844
+ },
34710
34845
  "pipelineAnalytics.deleteDeviceEvents": {
34711
34846
  capName: "pipeline-analytics",
34712
34847
  capScope: "device",
package/dist/addon.mjs CHANGED
@@ -8041,18 +8041,61 @@ var RelocateFootageInputSchema = object({
8041
8041
  * `RecordingConfig.enabled` or camera wrapper bindings. */
8042
8042
  var StorageMigrationLeaseInputSchema = object({ leaseId: string().min(1) });
8043
8043
  var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: string().min(1) });
8044
+ /**
8045
+ * What a `relocateMedia` pass DOES. One engine, three passes — never a second
8046
+ * mover (the engine already walks both collections with a timestamp cursor and
8047
+ * already has a stamp-without-copy path).
8048
+ *
8049
+ * - `move` — the default and the historical behaviour: event-media and
8050
+ * retrain blobs move to `toLocationId` and their rows are
8051
+ * stamped. The enrolled gallery is skipped (D197).
8052
+ * - `seal` — ROWS ONLY, no bytes. Every row whose `locationId` is NULL is
8053
+ * stamped with `toLocationId`. `toLocationId` here is the id the
8054
+ * bytes ALREADY sit on — today's `eventMedia` default — because
8055
+ * a NULL row means "wherever `eventMedia` points *now*", and the
8056
+ * instant a repoint moves that pointer the row reads from the
8057
+ * new disk while its bytes are on the old one.
8058
+ * - `gallery` — the inverse selection of `move`: ONLY the retention-exempt
8059
+ * (enrolled-gallery) rows, which `move` deliberately skips.
8060
+ * `galleryMedia` is `cardinality: 'single'`, so this pass can
8061
+ * never run beside a live second location: it is stop-the-world
8062
+ * by construction, which is acceptable only because the gallery
8063
+ * is a few KB per enrolled sample.
8064
+ */
8065
+ var MediaRelocateModeSchema = _enum([
8066
+ "move",
8067
+ "seal",
8068
+ "gallery"
8069
+ ]);
8044
8070
  var RelocateMediaInputSchema = object({
8045
8071
  toLocationId: string(),
8046
- throttleMbps: number().min(1).max(1e3).optional()
8072
+ throttleMbps: number().min(1).max(1e3).optional(),
8073
+ /** Omitted = `move`, the pre-existing behaviour. */
8074
+ mode: MediaRelocateModeSchema.optional()
8075
+ });
8076
+ /** How many rows still carry NO `locationId` — the population a repoint would
8077
+ * silently re-aim at a disk that does not hold their bytes. Zero is the only
8078
+ * value that permits a non-blocking `eventMedia` cutover. */
8079
+ var UnstampedEventMediaCountSchema = object({
8080
+ media: number().int().nonnegative(),
8081
+ retrainFrames: number().int().nonnegative(),
8082
+ total: number().int().nonnegative()
8047
8083
  });
8048
8084
  var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: string().min(1) });
8049
- /** The independently selectable logical storage classes. `recordings`
8050
- * encompasses the high and mid segment profiles; `recordingsLow` is low
8051
- * segments; `eventMedia` is post-analysis blobs. */
8085
+ /** The independently selectable logical storage classes — every class
8086
+ * `storage.listLocationDeclarations` reports, so an operator never meets a
8087
+ * Zod enum error where they should meet an explanation.
8088
+ *
8089
+ * `recordings` encompasses the high and mid segment profiles; `recordingsLow`
8090
+ * is low segments; `eventMedia` is post-analysis blobs; `galleryMedia` is the
8091
+ * enrolled gallery; `backups` is the system backup archive. The last two have
8092
+ * their own rules — see {@link StorageMigrationFindingCodeSchema}. */
8052
8093
  var StorageMigrationClassSchema = _enum([
8053
8094
  "recordings",
8054
8095
  "recordingsLow",
8055
- "eventMedia"
8096
+ "eventMedia",
8097
+ "backups",
8098
+ "galleryMedia"
8056
8099
  ]);
8057
8100
  /** A destination is always an existing, fully-qualified location id. The
8058
8101
  * migration API intentionally never changes a source location's `basePath`:
@@ -8060,20 +8103,56 @@ var StorageMigrationClassSchema = _enum([
8060
8103
  var StorageMigrationDestinationsSchema = object({
8061
8104
  recordings: string().min(1).optional(),
8062
8105
  recordingsLow: string().min(1).optional(),
8063
- eventMedia: string().min(1).optional()
8106
+ eventMedia: string().min(1).optional(),
8107
+ backups: string().min(1).optional(),
8108
+ galleryMedia: string().min(1).optional()
8064
8109
  }).refine((value) => Object.keys(value).length > 0, { message: "select at least one storage class" });
8110
+ /**
8111
+ * How a migration sequences the cutover against the byte move.
8112
+ *
8113
+ * - `blocking` — the historical order: pause, move every byte, repoint,
8114
+ * resume. Recording is stopped for the whole move. Right
8115
+ * for a small or a cold class, and the only legal mode for
8116
+ * a `cardinality: 'single'` class.
8117
+ * - `nonBlocking` — repoint FIRST, drain behind: seal, pause, repoint,
8118
+ * refresh, resume, then move the past with everything
8119
+ * running. The pause is three bounded instants (a detach +
8120
+ * attach round, a write-gate drain, a lease) instead of one
8121
+ * bounded by bytes. 1.09 TB at 7–14 MB/s is thirty hours of
8122
+ * stopped recording under `blocking`; the same move is
8123
+ * seconds of stopped recording under `nonBlocking`.
8124
+ *
8125
+ * The mode is on the JOB, not only on the input, because `status` is where an
8126
+ * operator finds out which one is running.
8127
+ */
8128
+ var StorageMigrationModeSchema = _enum(["blocking", "nonBlocking"]);
8065
8129
  /** Shared input for planning and starting an orchestrated storage migration. */
8066
8130
  var StorageMigrationInputSchema = object({
8067
8131
  destinations: StorageMigrationDestinationsSchema,
8068
- throttleMbps: number().min(1).max(1e3).optional()
8132
+ throttleMbps: number().min(1).max(1e3).optional(),
8133
+ /** Omitted = `blocking`, which stays the default. */
8134
+ mode: StorageMigrationModeSchema.optional()
8069
8135
  });
8070
- /** The durable coordinator state machine. The only phase that changes default
8071
- * locations is `repointing`, after every selected mover has completed and been
8072
- * verified. */
8136
+ /**
8137
+ * The durable coordinator state machine.
8138
+ *
8139
+ * `blocking`:
8140
+ * planning → pausing → moving → verifying → repointing → refreshing → resuming → done
8141
+ *
8142
+ * `nonBlocking`:
8143
+ * planning → sealing → pausing → repointing → refreshing → resuming → draining → verifying → done
8144
+ *
8145
+ * Same phases, different order plus two new ones — not a second mover.
8146
+ * `sealing` closes the `eventMedia` NULL-row hole BEFORE anything is paused;
8147
+ * `draining` runs the same movers UNLEASED, after every writer is back up.
8148
+ * `repointing` is still the only phase that changes a default location.
8149
+ */
8073
8150
  var StorageMigrationPhaseSchema = _enum([
8074
8151
  "planning",
8152
+ "sealing",
8075
8153
  "pausing",
8076
8154
  "moving",
8155
+ "draining",
8077
8156
  "verifying",
8078
8157
  "repointing",
8079
8158
  "refreshing",
@@ -8098,6 +8177,9 @@ var StorageMigrationMoveSchema = object({
8098
8177
  var StorageMigrationJobSchema = object({
8099
8178
  jobId: string(),
8100
8179
  phase: StorageMigrationPhaseSchema,
8180
+ /** Which order this job is running. `status` is the only place an operator
8181
+ * can tell a seconds-long cutover from a thirty-hour one. */
8182
+ mode: StorageMigrationModeSchema,
8101
8183
  destinations: StorageMigrationDestinationsSchema,
8102
8184
  throttleMbps: number(),
8103
8185
  moves: array(StorageMigrationMoveSchema),
@@ -8110,13 +8192,30 @@ var StorageMigrationJobSchema = object({
8110
8192
  finishedAt: number().nullable(),
8111
8193
  error: string().nullable()
8112
8194
  });
8195
+ var StorageMigrationFindingSchema = object({
8196
+ code: _enum([
8197
+ "sharesDeviceWithSource",
8198
+ "deviceIdentityUnknown",
8199
+ "unstampedEventMediaRows",
8200
+ "blockingOnly",
8201
+ "noMover"
8202
+ ]),
8203
+ storageClass: StorageMigrationClassSchema,
8204
+ /** Human-readable, already carrying the ids and counts. */
8205
+ message: string()
8206
+ });
8113
8207
  var StorageMigrationPlanSchema = object({
8114
8208
  destinations: StorageMigrationDestinationsSchema,
8209
+ /** The mode this plan was built for. A plan is only valid for its mode: the
8210
+ * `eventMedia` seal gate and the single-cardinality refusal both depend on
8211
+ * it. */
8212
+ mode: StorageMigrationModeSchema,
8115
8213
  moves: array(object({
8116
8214
  storageClass: StorageMigrationClassSchema,
8117
8215
  fromLocationId: string(),
8118
8216
  toLocationId: string()
8119
- }))
8217
+ })),
8218
+ findings: array(StorageMigrationFindingSchema)
8120
8219
  });
8121
8220
  /**
8122
8221
  * `StorageLocationType` — an addon-declared id that identifies the *kind* of
@@ -18969,7 +19068,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
18969
19068
  }), method(RelocateMediaInputSchema, object({ jobId: string() }), {
18970
19069
  kind: "mutation",
18971
19070
  auth: "admin"
18972
- }), method(object({}), array(RelocateJobSchema).readonly(), {
19071
+ }), method(object({}), UnstampedEventMediaCountSchema, { auth: "admin" }), method(object({}), array(RelocateJobSchema).readonly(), {
18973
19072
  kind: "query",
18974
19073
  auth: "admin"
18975
19074
  }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
@@ -20876,7 +20975,10 @@ method(object({
20876
20975
  }), StorageLocationSchema, {
20877
20976
  kind: "mutation",
20878
20977
  auth: "admin"
20879
- }), method(object({ id: string() }), _void(), {
20978
+ }), method(object({
20979
+ id: string(),
20980
+ force: boolean().optional()
20981
+ }), _void(), {
20880
20982
  kind: "mutation",
20881
20983
  auth: "admin"
20882
20984
  }), method(object({ id: string() }), object({
@@ -24944,6 +25046,33 @@ var intercomCapability = {
24944
25046
  deviceNative: true,
24945
25047
  mode: "singleton",
24946
25048
  deviceTypes: [DeviceType.Camera],
25049
+ /**
25050
+ * **Auth tier: `protected` on every method — deliberate, and load-bearing.**
25051
+ *
25052
+ * Talking through a camera is an OPERATE action, not a CONFIGURE one. This
25053
+ * cap has no configuration surface at all: all six methods open, feed and
25054
+ * close one live audio session against one `deviceId`. That is the same
25055
+ * authority as `ptz.move` or `snapshot.getSnapshot`, both `protected` — and
25056
+ * the opposite of `ptz.savePreset` / `snapshot.invalidateCache`, which are
25057
+ * `admin` because they change what the device IS.
25058
+ *
25059
+ * `protected` does not mean ungated: `protectedProcedure` runs the
25060
+ * `METHOD_ACCESS_MAP` scope check, and every method here is `scope: 'device'`
25061
+ * with `access: 'create'` and a `deviceId` in its input. So a caller needs a
25062
+ * grant that covers THAT camera at `create` — a `camera-viewer` (`view`
25063
+ * only) still cannot talk, and a grant on camera 5 cannot talk through
25064
+ * camera 7.
25065
+ *
25066
+ * Every method was `auth: 'admin'` from the initial commit, which made the
25067
+ * cap unreachable by every non-admin principal — `adminProcedure` throws
25068
+ * `FORBIDDEN: Admin required` BEFORE the scope check runs, so the scope
25069
+ * machinery generated for this cap (`METHOD_ACCESS_MAP`,
25070
+ * `DEVICE_SCOPED_CAPS`, `METHOD_DEVICE_SELECTORS`) was complete and dead. The
25071
+ * `camera-operator` scope preset has promised "PTZ control, intercom,
25072
+ * snapshots" since that same commit; the promise could not be kept. Recorded
25073
+ * as D289; `scripts/check-scope-preset-promises.ts` now fails the build if a
25074
+ * preset promises a cap no row of that preset can reach.
25075
+ */
24947
25076
  methods: {
24948
25077
  /**
24949
25078
  * Open a server-side WebRTC audio-only session. Returns an SDP
@@ -24956,7 +25085,7 @@ var intercomCapability = {
24956
25085
  sdpOffer: string()
24957
25086
  }), {
24958
25087
  kind: "mutation",
24959
- auth: "admin"
25088
+ auth: "protected"
24960
25089
  }),
24961
25090
  handleAnswer: method(object({
24962
25091
  deviceId: number(),
@@ -24964,7 +25093,7 @@ var intercomCapability = {
24964
25093
  sdpAnswer: string()
24965
25094
  }), _void(), {
24966
25095
  kind: "mutation",
24967
- auth: "admin"
25096
+ auth: "protected"
24968
25097
  }),
24969
25098
  /** Close explicitly. Server also auto-closes on 30s idle. */
24970
25099
  stopSession: method(object({
@@ -24972,7 +25101,7 @@ var intercomCapability = {
24972
25101
  sessionId: string()
24973
25102
  }), _void(), {
24974
25103
  kind: "mutation",
24975
- auth: "admin"
25104
+ auth: "protected"
24976
25105
  }),
24977
25106
  /**
24978
25107
  * Open a raw-PCM talk session (no WebRTC SDP plumbing). Used by
@@ -24985,7 +25114,7 @@ var intercomCapability = {
24985
25114
  */
24986
25115
  startTalkSession: method(object({ deviceId: number() }), object({ sessionId: string() }), {
24987
25116
  kind: "mutation",
24988
- auth: "admin"
25117
+ auth: "protected"
24989
25118
  }),
24990
25119
  /**
24991
25120
  * Push one chunk of talk-back audio onto the active talk session.
@@ -25020,12 +25149,12 @@ var intercomCapability = {
25020
25149
  sequenceNumber: number().int()
25021
25150
  }), object({ accepted: boolean() }), {
25022
25151
  kind: "mutation",
25023
- auth: "admin"
25152
+ auth: "protected"
25024
25153
  }),
25025
25154
  /** Close the raw-PCM talk session. Idempotent. */
25026
25155
  endTalkSession: method(object({ deviceId: number() }), _void(), {
25027
25156
  kind: "mutation",
25028
- auth: "admin"
25157
+ auth: "protected"
25029
25158
  })
25030
25159
  },
25031
25160
  events: { onStatusChanged: { data: object({
@@ -34706,6 +34835,12 @@ Object.freeze({
34706
34835
  addonId: null,
34707
34836
  access: "create"
34708
34837
  },
34838
+ "pipelineAnalytics.countUnstampedEventMedia": {
34839
+ capName: "pipeline-analytics",
34840
+ capScope: "device",
34841
+ addonId: null,
34842
+ access: "view"
34843
+ },
34709
34844
  "pipelineAnalytics.deleteDeviceEvents": {
34710
34845
  capName: "pipeline-analytics",
34711
34846
  capScope: "device",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-gree",
3
- "version": "0.2.40",
3
+ "version": "0.2.42",
4
4
  "description": "Gree air-conditioner device-provider addon for CamStack — wraps the @apocaliss92/nodegree local-UDP client (LAN discovery + AES control), exposing climate-control and fan-control",
5
5
  "keywords": [
6
6
  "camstack",