@camstack/addon-provider-rademacher 0.2.42 → 0.2.44

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 +333 -12
  2. package/dist/addon.mjs +333 -12
  3. package/package.json +1 -1
package/dist/addon.js CHANGED
@@ -9149,13 +9149,49 @@ var StorageMigrationParticipantSchema = _enum([
9149
9149
  "recorder",
9150
9150
  "analytics"
9151
9151
  ]);
9152
+ /**
9153
+ * The mover's own numbers, folded onto the coordinator's durable move record.
9154
+ *
9155
+ * The long half of a non-blocking migration is `draining`, and it is measured
9156
+ * in hours: 136 885 files at ~4 MB/s is about five of them. Before this shape
9157
+ * existed the only place those numbers appeared was a Loki line, so an operator
9158
+ * watching the Admin UI saw `phase: draining` and nothing else for a whole
9159
+ * afternoon.
9160
+ *
9161
+ * It is POLLED, never pushed. Events are telemetry and may be dropped
9162
+ * (D8/D11), and a dropped progress event is indistinguishable from a stalled
9163
+ * mover — which is the exact failure this is meant to end. The coordinator's
9164
+ * `waitForMoves` already fetches the whole {@link RelocateJob} on every tick to
9165
+ * read `state`; folding the counters costs no extra read and makes the durable
9166
+ * record say afterwards how far a move actually got.
9167
+ *
9168
+ * `filesTotal` is `null` for "no honest denominator" and is never zero-filled:
9169
+ * a windowed footage job (`sinceMs`) and a node with no ledger both genuinely
9170
+ * cannot say M, and a 0 there would render as "100 % done".
9171
+ */
9172
+ var StorageMigrationMoveProgressSchema = object({
9173
+ filesMoved: number().int().nonnegative(),
9174
+ /** The archive census — the **M** of "N of M" (D295). `null` = unknowable. */
9175
+ filesTotal: number().int().nonnegative().nullable(),
9176
+ bytesMoved: number().int().nonnegative(),
9177
+ /** The MOVER's start, not the migration's: a drain restarted after an addon
9178
+ * crash gets a new mover, and a rate computed from the migration's start
9179
+ * would silently average in the time nothing was running. */
9180
+ startedAt: number(),
9181
+ /** When the coordinator last read these numbers. Paired with `startedAt` it
9182
+ * is the only honest rate: both clocks are the hub's, so a UI never has to
9183
+ * subtract its own. */
9184
+ observedAt: number()
9185
+ });
9152
9186
  var StorageMigrationMoveSchema = object({
9153
9187
  storageClass: StorageMigrationClassSchema,
9154
9188
  fromLocationId: string(),
9155
9189
  toLocationId: string(),
9156
9190
  moverJobId: string().nullable(),
9157
9191
  state: RelocateJobStateSchema.nullable(),
9158
- error: string().nullable()
9192
+ error: string().nullable(),
9193
+ /** Last observed mover counters; `null` until the mover has been polled once. */
9194
+ progress: StorageMigrationMoveProgressSchema.nullable()
9159
9195
  });
9160
9196
  var StorageMigrationJobSchema = object({
9161
9197
  jobId: string(),
@@ -9201,6 +9237,98 @@ var StorageMigrationPlanSchema = object({
9201
9237
  findings: array(StorageMigrationFindingSchema)
9202
9238
  });
9203
9239
  /**
9240
+ * A mover as it exists RIGHT NOW, whether or not a migration job owns it.
9241
+ *
9242
+ * The coordinator's job record is the state of record for a migration, and its
9243
+ * moves carry {@link StorageMigrationMoveProgress}. But the movers are usable
9244
+ * standalone — `recording.relocateFootage` and `pipelineAnalytics.relocateMedia`
9245
+ * are both operator-callable, and on 2026-08-29 a five-hour drain was armed that
9246
+ * way because no supported UI path existed. A mover armed like that has no job
9247
+ * to fold progress into, so it has to be readable on its own or it is invisible.
9248
+ *
9249
+ * `migrationJobId` is what tells the two apart: `null` means nothing here
9250
+ * orchestrated it.
9251
+ */
9252
+ var StorageMigrationMoverSchema = object({
9253
+ lane: _enum(["footage", "media"]),
9254
+ job: RelocateJobSchema,
9255
+ /** The coordinator job that armed this mover, or `null` for a mover armed
9256
+ * directly against the owning addon. */
9257
+ migrationJobId: string().nullable(),
9258
+ /** When the hub read these counters. Stamped here so a rate is `bytesMoved`
9259
+ * over (`observedAt` − `job.startedAt`) with BOTH ends on the hub's clock —
9260
+ * a browser subtracting its own `Date.now()` from a server `startedAt` is a
9261
+ * rate made of two different clocks. */
9262
+ observedAt: number()
9263
+ });
9264
+ /**
9265
+ * What a SOURCE still holds for one storage class — the number that makes a
9266
+ * "drain remaining" action honest rather than hopeful.
9267
+ *
9268
+ * It comes from the archive (`SegmentHourLedger.census` for footage, the media
9269
+ * engine's own selection count for media), never from the resident index: a
9270
+ * drain sized off `RecordingIndex` is what reported `done` over 80.3 GB it had
9271
+ * never been told about (D295).
9272
+ *
9273
+ * `items`/`bytes` are `null` for "the archive could not be asked", which is
9274
+ * deliberately NOT zero: a drain is still offered for an unknown residue,
9275
+ * because refusing on an unanswerable read would hide exactly the case an
9276
+ * operator needs to act on.
9277
+ */
9278
+ var StorageMigrationResidueSchema = object({
9279
+ storageClass: StorageMigrationClassSchema,
9280
+ /** The location still holding the data. `'*'` for the media lane, whose rows
9281
+ * move from wherever they are rather than from one named source. */
9282
+ fromLocationId: string(),
9283
+ /** Where a drain would move it — the class's CURRENT default. */
9284
+ toLocationId: string(),
9285
+ /** Segments (footage lane) or rows (media lane) still on the source. */
9286
+ items: number().int().nonnegative().nullable(),
9287
+ /** Bytes on the source; `null` when the lane counts rows rather than bytes. */
9288
+ bytes: number().int().nonnegative().nullable()
9289
+ });
9290
+ /**
9291
+ * Run the DRAIN half and nothing else.
9292
+ *
9293
+ * A migration that reached `done` has already repointed, so `start` correctly
9294
+ * refuses its destination ("already the default") — there is nothing left to
9295
+ * repoint. But the drain can fail, be cancelled, be interrupted by a restart,
9296
+ * or finish against a work list that was a tenth of the archive (D295), and
9297
+ * before this there was no supported way to run only that half: the only way
9298
+ * through was calling `recording.relocateFootage` by hand over admin tRPC.
9299
+ *
9300
+ * `drain` NEVER calls `setDefaultLocations`. That is what keeps `start`'s
9301
+ * refusal meaningful: the two verbs are disjoint, so nothing here can silently
9302
+ * re-repoint a class that is already migrated.
9303
+ */
9304
+ var StorageMigrationDrainInputSchema = object({
9305
+ /** The classes to drain. Each must appear in `storageMigration.residue`, so
9306
+ * a class whose source is already empty is refused rather than started. */
9307
+ classes: array(StorageMigrationClassSchema).min(1),
9308
+ throttleMbps: number().min(1).max(1e3).optional()
9309
+ });
9310
+ /** What a footage source still holds, asked of the durable hour ledger. */
9311
+ var RelocateResidueInputSchema = object({
9312
+ fromLocationId: string().min(1),
9313
+ /** Narrow to one logical class; omit for every profile on the location. */
9314
+ footageClass: RelocateFootageClassSchema.optional()
9315
+ });
9316
+ /** `null` = the archive could not answer (no ledger on this node, or the
9317
+ * aggregate failed). Never conflated with an empty source. */
9318
+ var RelocateResidueSchema = object({
9319
+ segments: number().int().nonnegative(),
9320
+ bytes: number().int().nonnegative()
9321
+ }).nullable();
9322
+ /** How many rows a media pass would still act on against a given target — the
9323
+ * media lane's denominator AND its residue, from ONE derivation so the two can
9324
+ * never disagree. `null` = the count could not be taken. */
9325
+ var RelocatableMediaCountSchema = object({ rows: number().int().nonnegative() }).nullable();
9326
+ var RelocatableMediaCountInputSchema = object({
9327
+ toLocationId: string().min(1),
9328
+ /** Omitted = `move`. */
9329
+ mode: MediaRelocateModeSchema.optional()
9330
+ });
9331
+ /**
9204
9332
  * `StorageLocationType` — an addon-declared id that identifies the *kind* of
9205
9333
  * storage a location serves. Defined here (not in `capabilities/storage.cap.ts`)
9206
9334
  * so the persisted record schema and the consumer-facing cap can both consume it
@@ -9304,6 +9432,32 @@ var StorageLocationRefSchema = union([StorageLocationTypeSchema, string().regex(
9304
9432
  * two addons declaring the same `id` must agree on `cardinality` (validated
9305
9433
  * at kernel aggregation time, not here).
9306
9434
  */
9435
+ /**
9436
+ * `StorageAccess` — how the service that DECLARED a storage-location kind
9437
+ * actually reaches the bytes. It is the constraint that decides which
9438
+ * `storage-provider`s may back a location of that kind.
9439
+ *
9440
+ * - `'local-path'` — the service asks `storage.resolve` for a path string and
9441
+ * then does its own `node:fs` I/O on it (the recorder's segment writer, the
9442
+ * post-analysis media roots). Only a provider that serves a genuine local
9443
+ * filesystem (`getProviderInfo().nodeLocal === true`) can satisfy that: a
9444
+ * remote provider's `resolve` returns a path on the REMOTE host, and
9445
+ * `fs.readdir` of it on this node either fails or — far worse — succeeds
9446
+ * against a same-named local directory that is something else entirely.
9447
+ *
9448
+ * - `'cap-mediated'` — every byte travels through the `storage` cap
9449
+ * (`read`/`write`, or `beginUpload`/`writeChunk`/`finalizeUpload`). The
9450
+ * service never sees a path, so any provider can back it. `backups` is the
9451
+ * one kind that qualifies today.
9452
+ *
9453
+ * Before this existed, `recordings` was unreachable by SFTP/S3/WebDAV only as
9454
+ * an EMERGENT property of how the recorder happened to be written. Nothing
9455
+ * refused the configuration; the first write simply went somewhere wrong, and
9456
+ * a recording write that goes wrong surfaces as a silent black window rather
9457
+ * than an error (the read path does not `stat`). This turns that accident into
9458
+ * a declared, enforced, testable refusal.
9459
+ */
9460
+ var StorageAccessSchema = _enum(["local-path", "cap-mediated"]);
9307
9461
  var StorageLocationDeclarationSchema = object({
9308
9462
  /**
9309
9463
  * Global location identifier, e.g. `recordings` or `recordingsLow`.
@@ -9323,6 +9477,19 @@ var StorageLocationDeclarationSchema = object({
9323
9477
  */
9324
9478
  cardinality: _enum(["single", "multi"]),
9325
9479
  /**
9480
+ * HOW the declaring service reaches the bytes — and therefore WHICH
9481
+ * providers may back a location of this kind. See {@link StorageAccessSchema}
9482
+ * and {@link STORAGE_ACCESS_FALLBACK}.
9483
+ *
9484
+ * Absent means `'local-path'`. That default is FAIL-CLOSED on purpose: it
9485
+ * can only over-restrict (refuse a remote provider for a kind that might
9486
+ * have coped) and never under-restrict. Declaring `'cap-mediated'` is the
9487
+ * permissive direction and is therefore never inferred — a repo guard
9488
+ * (`scripts/check-storage-access-declarations.ts`) refuses to let it be
9489
+ * reached by omission.
9490
+ */
9491
+ access: StorageAccessSchema.optional(),
9492
+ /**
9326
9493
  * When set, the default instance for this location inherits its resolved
9327
9494
  * root from the named location's default instance. Useful for derivative
9328
9495
  * slots (e.g. `recordingsLow` → `recordings`) so operators only need to
@@ -19190,8 +19357,10 @@ var TrackSchema = object({
19190
19357
  lastSeen: number(),
19191
19358
  /** Frame-rate position history (subject to maxPositionHistory cap). */
19192
19359
  positions: array(TrackPositionSchema).readonly(),
19193
- /** Periodic snapshots at snapshotIntervalMs cadence (subject to
19194
- * saveThumbnails policy). */
19360
+ /** Periodic snapshots at snapshotIntervalMs cadence DEBUG media, produced
19361
+ * only while `MediaSettings.debugMediaEnabled` is on for the camera (D299;
19362
+ * the retired `saveThumbnails` used to gate this and the rolling
19363
+ * `lastFrame` together). Empty is the healthy default, not a capture gap. */
19195
19364
  snapshots: array(TrackSnapshotSchema).readonly(),
19196
19365
  /** Deduplicated zones the track has entered at least once. Zone IDS. */
19197
19366
  zonesVisited: array(string()).readonly(),
@@ -20051,7 +20220,10 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
20051
20220
  }), method(RelocateMediaInputSchema, object({ jobId: string() }), {
20052
20221
  kind: "mutation",
20053
20222
  auth: "admin"
20054
- }), method(object({}), UnstampedEventMediaCountSchema, { auth: "admin" }), method(object({}), array(RelocateJobSchema).readonly(), {
20223
+ }), method(object({}), UnstampedEventMediaCountSchema, { auth: "admin" }), method(RelocatableMediaCountInputSchema, RelocatableMediaCountSchema, {
20224
+ kind: "query",
20225
+ auth: "admin"
20226
+ }), method(object({}), array(RelocateJobSchema).readonly(), {
20055
20227
  kind: "query",
20056
20228
  auth: "admin"
20057
20229
  }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
@@ -22010,6 +22182,9 @@ method(StorageMigrationInputSchema, StorageMigrationPlanSchema, { auth: "admin"
22010
22182
  }), method(object({ jobId: string().optional() }), StorageMigrationJobSchema.nullable(), { auth: "admin" }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
22011
22183
  kind: "mutation",
22012
22184
  auth: "admin"
22185
+ }), method(object({}), array(StorageMigrationMoverSchema).readonly(), { auth: "admin" }), method(object({}), array(StorageMigrationResidueSchema).readonly(), { auth: "admin" }), method(StorageMigrationDrainInputSchema, object({ jobId: string() }), {
22186
+ kind: "mutation",
22187
+ auth: "admin"
22013
22188
  });
22014
22189
  var ProviderInfoSchema = discriminatedUnion("shouldSaveDiskSpace", [object({
22015
22190
  providerId: string().min(1),
@@ -22408,12 +22583,38 @@ response: record(string(), unknown()) }), object({
22408
22583
  *
22409
22584
  * ## Why this is a capability and not a helper
22410
22585
  *
22411
- * Six stores in `addon-post-analysis` already hold vectors object CLIP, face,
22412
- * plate, vehicle, identity, and the event store's derivativesand every one of
22413
- * them keeps its vectors in a `JSON` settings-store column and ranks them by
22414
- * brute-force cosine in JS. Measured on the live hub that costs ~11.7 KB per row
22415
- * (512 floats as TEXT, `JSON.parse`d on every search) and made semantic search
22416
- * load 5,000 rows before ranking anything.
22586
+ * This capability was introduced with the claim that SIX stores in
22587
+ * `addon-post-analysis` held vectors in a `JSON` settings-store columnobject
22588
+ * CLIP, face, plate, vehicle, identity, and the event store's derivatives. That
22589
+ * claim was never true, and leaving it here made five stores look like pending
22590
+ * work when three of them have no vector at all. Counted column by column on
22591
+ * 2026-08-30, exactly THREE ever held one:
22592
+ *
22593
+ * - `object-clip` — 512-dim CLIP image embedding, migrated 2026-08-06.
22594
+ * - `faces.embedding` — 512-dim ArcFace face embedding, migrated 2026-08-30.
22595
+ * - `identity-samples.embedding` — the same ArcFace vector for an ENROLLED
22596
+ * face, migrated 2026-08-30 into its OWN index (see below).
22597
+ *
22598
+ * `plates` and `vehicle-samples` store a plate STRING and a score; `vehicles`
22599
+ * and `identities` store a name; the event store stores no derivative vector.
22600
+ * They are not migration candidates and never were.
22601
+ *
22602
+ * Measured on the live hub the JSON encoding cost ~11.7 KB per row (512 floats
22603
+ * as TEXT, `JSON.parse`d on every search) and made semantic search load 5,000
22604
+ * rows before ranking anything.
22605
+ *
22606
+ * ## One index per COMPARISON, never per encoder
22607
+ *
22608
+ * `faces` and `identity-samples` hold the same 512 ArcFace dims from the same
22609
+ * model, and they still get two indexes. An index is a set of things that are
22610
+ * ranked against each other and that live and die together, and these two are
22611
+ * neither: a `faces` row is TRACK-OWNED and cascades away with its track under
22612
+ * a per-camera capacity cap, an `identity-samples` row is retention-EXEMPT
22613
+ * forever and is the gallery every recognition ranks against. One index would
22614
+ * mean every gallery load and every reconcile carried a filter whose failure
22615
+ * mode is either ranking a candidate against itself or reclaiming an enrolled
22616
+ * person's only sample. The dimension they share is not a reason to share an
22617
+ * index; the question they answer is, and it differs.
22417
22618
  *
22418
22619
  * The fix is not a faster loop, it is a different backend — and the backend
22419
22620
  * should be replaceable without touching six callers. So: a singleton
@@ -22518,7 +22719,20 @@ var VectorQueryResultSchema = object({
22518
22719
  */
22519
22720
  scanned: number(),
22520
22721
  /** True when the backend could not consider every row that passed the filter. */
22521
- truncated: boolean()
22722
+ truncated: boolean(),
22723
+ /**
22724
+ * The `topK` the backend actually ran with.
22725
+ *
22726
+ * Every backend has a ceiling — sqlite-vec's is 4,096 — and a caller asking
22727
+ * past it used to learn nothing but a boolean, from a WARN in the provider's
22728
+ * own log rather than in its answer. That is how an audit asking for 20,000
22729
+ * consumed 4,096 and reported `examined: 4096` as if it had walked the index,
22730
+ * for weeks. `truncated` says THAT the answer was short; this says BY HOW
22731
+ * MUCH, in the return value, where the caller cannot fail to see it.
22732
+ *
22733
+ * Equals the requested `topK` whenever nothing was lowered.
22734
+ */
22735
+ effectiveTopK: number().int().positive()
22522
22736
  });
22523
22737
  var VectorDeleteInputSchema = object({
22524
22738
  index: string(),
@@ -22547,6 +22761,68 @@ var VectorGetResultSchema = object({ items: array(object({
22547
22761
  id: string(),
22548
22762
  metadata: VectorMetadataSchema
22549
22763
  })) });
22764
+ /**
22765
+ * Ids to read back WITH their vectors.
22766
+ *
22767
+ * The sibling of {@link VectorGetResultSchema}, and deliberately a separate
22768
+ * method rather than a flag on it: `getByIds` promises no vectors and its one
22769
+ * caller depends on that promise. This one promises the opposite.
22770
+ *
22771
+ * It exists because a store cannot put its vectors here otherwise. An ArcFace
22772
+ * gallery is ranked IN PROCESS, per detection, against every enrolled sample —
22773
+ * a per-face cross-process KNN would be a network round trip inside the
22774
+ * recognition loop. So the gallery is loaded once and held in RAM, and loading
22775
+ * it requires the index to hand the floats back. Without this method the only
22776
+ * way to keep a readable vector is a JSON column, which is the thing this
22777
+ * capability exists to delete.
22778
+ *
22779
+ * BOUNDED BY THE CALLER: ids are named, never "everything". Enumerating an
22780
+ * index is {@link VectorScanInputSchema}'s job, and it returns no vectors.
22781
+ */
22782
+ var VectorFetchInputSchema = object({
22783
+ index: string(),
22784
+ ids: array(string())
22785
+ });
22786
+ var VectorFetchResultSchema = object({ items: array(object({
22787
+ id: string(),
22788
+ /** base64 Float32LE — the same wire form `upsert` accepts. */
22789
+ vector: string(),
22790
+ metadata: VectorMetadataSchema
22791
+ })) });
22792
+ /**
22793
+ * ENUMERATE an index: one page of rows in a stable order, no ranking.
22794
+ *
22795
+ * A reconcile does not want the nearest rows, it wants ALL of them, and asking
22796
+ * a KNN for "all" is the wrong question twice over. It hits the backend's `k`
22797
+ * ceiling — 4,096 on sqlite-vec against a 22,128-row index — and it needs a
22798
+ * probe vector it does not have, so the audit passed a ZERO vector whose cosine
22799
+ * distance to every row is degenerate. `examined: 4096` then read as "we
22800
+ * looked" for as long as anyone cared to read it.
22801
+ *
22802
+ * This is the primitive that question actually needs: a bounded page, ordered
22803
+ * by the backend's own row order, costing no distance computation at all.
22804
+ * Vectors are NOT returned — an enumeration that shipped 2 KB per row would be
22805
+ * the full-table read this capability was built to stop.
22806
+ */
22807
+ var VectorScanInputSchema = object({
22808
+ index: string(),
22809
+ /** Opaque resume point. `0` starts at the top; pass back `nextCursor`. */
22810
+ cursor: number().int().nonnegative().default(0),
22811
+ limit: number().int().positive()
22812
+ });
22813
+ var VectorScanResultSchema = object({
22814
+ items: array(object({
22815
+ id: string(),
22816
+ metadata: VectorMetadataSchema
22817
+ })),
22818
+ /**
22819
+ * Where the next page starts, or `null` when the walk reached the end.
22820
+ *
22821
+ * `null` is the ONLY end-of-index signal. A caller must not infer the end
22822
+ * from a short page: a backend is free to return fewer rows than asked.
22823
+ */
22824
+ nextCursor: number().int().nonnegative().nullable()
22825
+ });
22550
22826
  var VectorStatsInputSchema = object({ index: string() });
22551
22827
  var VectorStatsResultSchema = object({
22552
22828
  /** Provider id, so an operator can tell brute force from an ANN index. */
@@ -22565,7 +22841,7 @@ method(VectorDeclareIndexInputSchema, _void(), {
22565
22841
  }), method(VectorUpsertInputSchema, VectorUpsertResultSchema, {
22566
22842
  kind: "mutation",
22567
22843
  auth: "admin"
22568
- }), method(VectorQueryInputSchema, VectorQueryResultSchema, { auth: "admin" }), method(VectorGetInputSchema, VectorGetResultSchema, { auth: "admin" }), method(VectorDeleteInputSchema, VectorDeleteResultSchema, {
22844
+ }), method(VectorQueryInputSchema, VectorQueryResultSchema, { auth: "admin" }), method(VectorGetInputSchema, VectorGetResultSchema, { auth: "admin" }), method(VectorFetchInputSchema, VectorFetchResultSchema, { auth: "admin" }), method(VectorScanInputSchema, VectorScanResultSchema, { auth: "admin" }), method(VectorDeleteInputSchema, VectorDeleteResultSchema, {
22569
22845
  kind: "mutation",
22570
22846
  auth: "admin"
22571
22847
  }), method(VectorDeleteByFilterInputSchema, VectorDeleteResultSchema, {
@@ -29184,6 +29460,9 @@ method(object({
29184
29460
  }), method(object({}), array(RelocateJobSchema).readonly(), {
29185
29461
  kind: "query",
29186
29462
  auth: "admin"
29463
+ }), method(RelocateResidueInputSchema, RelocateResidueSchema, {
29464
+ kind: "query",
29465
+ auth: "admin"
29187
29466
  }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
29188
29467
  kind: "mutation",
29189
29468
  auth: "admin"
@@ -35818,6 +36097,12 @@ Object.freeze({
35818
36097
  addonId: null,
35819
36098
  access: "create"
35820
36099
  },
36100
+ "pipelineAnalytics.countRelocatableMedia": {
36101
+ capName: "pipeline-analytics",
36102
+ capScope: "device",
36103
+ addonId: null,
36104
+ access: "view"
36105
+ },
35821
36106
  "pipelineAnalytics.countUnstampedEventMedia": {
35822
36107
  capName: "pipeline-analytics",
35823
36108
  capScope: "device",
@@ -36982,6 +37267,12 @@ Object.freeze({
36982
37267
  addonId: null,
36983
37268
  access: "view"
36984
37269
  },
37270
+ "recording.getRelocateResidue": {
37271
+ capName: "recording",
37272
+ capScope: "system",
37273
+ addonId: null,
37274
+ access: "view"
37275
+ },
36985
37276
  "recording.getStorageMigrationMoveStatus": {
36986
37277
  capName: "recording",
36987
37278
  capScope: "system",
@@ -37528,12 +37819,30 @@ Object.freeze({
37528
37819
  addonId: null,
37529
37820
  access: "create"
37530
37821
  },
37822
+ "storageMigration.drain": {
37823
+ capName: "storage-migration",
37824
+ capScope: "system",
37825
+ addonId: null,
37826
+ access: "create"
37827
+ },
37828
+ "storageMigration.movers": {
37829
+ capName: "storage-migration",
37830
+ capScope: "system",
37831
+ addonId: null,
37832
+ access: "view"
37833
+ },
37531
37834
  "storageMigration.plan": {
37532
37835
  capName: "storage-migration",
37533
37836
  capScope: "system",
37534
37837
  addonId: null,
37535
37838
  access: "view"
37536
37839
  },
37840
+ "storageMigration.residue": {
37841
+ capName: "storage-migration",
37842
+ capScope: "system",
37843
+ addonId: null,
37844
+ access: "view"
37845
+ },
37537
37846
  "storageMigration.start": {
37538
37847
  capName: "storage-migration",
37539
37848
  capScope: "system",
@@ -38368,6 +38677,12 @@ Object.freeze({
38368
38677
  addonId: null,
38369
38678
  access: "delete"
38370
38679
  },
38680
+ "vectorStore.fetchByIds": {
38681
+ capName: "vector-store",
38682
+ capScope: "system",
38683
+ addonId: null,
38684
+ access: "view"
38685
+ },
38371
38686
  "vectorStore.getByIds": {
38372
38687
  capName: "vector-store",
38373
38688
  capScope: "system",
@@ -38380,6 +38695,12 @@ Object.freeze({
38380
38695
  addonId: null,
38381
38696
  access: "view"
38382
38697
  },
38698
+ "vectorStore.scan": {
38699
+ capName: "vector-store",
38700
+ capScope: "system",
38701
+ addonId: null,
38702
+ access: "view"
38703
+ },
38383
38704
  "vectorStore.stats": {
38384
38705
  capName: "vector-store",
38385
38706
  capScope: "system",
package/dist/addon.mjs CHANGED
@@ -9148,13 +9148,49 @@ var StorageMigrationParticipantSchema = _enum([
9148
9148
  "recorder",
9149
9149
  "analytics"
9150
9150
  ]);
9151
+ /**
9152
+ * The mover's own numbers, folded onto the coordinator's durable move record.
9153
+ *
9154
+ * The long half of a non-blocking migration is `draining`, and it is measured
9155
+ * in hours: 136 885 files at ~4 MB/s is about five of them. Before this shape
9156
+ * existed the only place those numbers appeared was a Loki line, so an operator
9157
+ * watching the Admin UI saw `phase: draining` and nothing else for a whole
9158
+ * afternoon.
9159
+ *
9160
+ * It is POLLED, never pushed. Events are telemetry and may be dropped
9161
+ * (D8/D11), and a dropped progress event is indistinguishable from a stalled
9162
+ * mover — which is the exact failure this is meant to end. The coordinator's
9163
+ * `waitForMoves` already fetches the whole {@link RelocateJob} on every tick to
9164
+ * read `state`; folding the counters costs no extra read and makes the durable
9165
+ * record say afterwards how far a move actually got.
9166
+ *
9167
+ * `filesTotal` is `null` for "no honest denominator" and is never zero-filled:
9168
+ * a windowed footage job (`sinceMs`) and a node with no ledger both genuinely
9169
+ * cannot say M, and a 0 there would render as "100 % done".
9170
+ */
9171
+ var StorageMigrationMoveProgressSchema = object({
9172
+ filesMoved: number().int().nonnegative(),
9173
+ /** The archive census — the **M** of "N of M" (D295). `null` = unknowable. */
9174
+ filesTotal: number().int().nonnegative().nullable(),
9175
+ bytesMoved: number().int().nonnegative(),
9176
+ /** The MOVER's start, not the migration's: a drain restarted after an addon
9177
+ * crash gets a new mover, and a rate computed from the migration's start
9178
+ * would silently average in the time nothing was running. */
9179
+ startedAt: number(),
9180
+ /** When the coordinator last read these numbers. Paired with `startedAt` it
9181
+ * is the only honest rate: both clocks are the hub's, so a UI never has to
9182
+ * subtract its own. */
9183
+ observedAt: number()
9184
+ });
9151
9185
  var StorageMigrationMoveSchema = object({
9152
9186
  storageClass: StorageMigrationClassSchema,
9153
9187
  fromLocationId: string(),
9154
9188
  toLocationId: string(),
9155
9189
  moverJobId: string().nullable(),
9156
9190
  state: RelocateJobStateSchema.nullable(),
9157
- error: string().nullable()
9191
+ error: string().nullable(),
9192
+ /** Last observed mover counters; `null` until the mover has been polled once. */
9193
+ progress: StorageMigrationMoveProgressSchema.nullable()
9158
9194
  });
9159
9195
  var StorageMigrationJobSchema = object({
9160
9196
  jobId: string(),
@@ -9200,6 +9236,98 @@ var StorageMigrationPlanSchema = object({
9200
9236
  findings: array(StorageMigrationFindingSchema)
9201
9237
  });
9202
9238
  /**
9239
+ * A mover as it exists RIGHT NOW, whether or not a migration job owns it.
9240
+ *
9241
+ * The coordinator's job record is the state of record for a migration, and its
9242
+ * moves carry {@link StorageMigrationMoveProgress}. But the movers are usable
9243
+ * standalone — `recording.relocateFootage` and `pipelineAnalytics.relocateMedia`
9244
+ * are both operator-callable, and on 2026-08-29 a five-hour drain was armed that
9245
+ * way because no supported UI path existed. A mover armed like that has no job
9246
+ * to fold progress into, so it has to be readable on its own or it is invisible.
9247
+ *
9248
+ * `migrationJobId` is what tells the two apart: `null` means nothing here
9249
+ * orchestrated it.
9250
+ */
9251
+ var StorageMigrationMoverSchema = object({
9252
+ lane: _enum(["footage", "media"]),
9253
+ job: RelocateJobSchema,
9254
+ /** The coordinator job that armed this mover, or `null` for a mover armed
9255
+ * directly against the owning addon. */
9256
+ migrationJobId: string().nullable(),
9257
+ /** When the hub read these counters. Stamped here so a rate is `bytesMoved`
9258
+ * over (`observedAt` − `job.startedAt`) with BOTH ends on the hub's clock —
9259
+ * a browser subtracting its own `Date.now()` from a server `startedAt` is a
9260
+ * rate made of two different clocks. */
9261
+ observedAt: number()
9262
+ });
9263
+ /**
9264
+ * What a SOURCE still holds for one storage class — the number that makes a
9265
+ * "drain remaining" action honest rather than hopeful.
9266
+ *
9267
+ * It comes from the archive (`SegmentHourLedger.census` for footage, the media
9268
+ * engine's own selection count for media), never from the resident index: a
9269
+ * drain sized off `RecordingIndex` is what reported `done` over 80.3 GB it had
9270
+ * never been told about (D295).
9271
+ *
9272
+ * `items`/`bytes` are `null` for "the archive could not be asked", which is
9273
+ * deliberately NOT zero: a drain is still offered for an unknown residue,
9274
+ * because refusing on an unanswerable read would hide exactly the case an
9275
+ * operator needs to act on.
9276
+ */
9277
+ var StorageMigrationResidueSchema = object({
9278
+ storageClass: StorageMigrationClassSchema,
9279
+ /** The location still holding the data. `'*'` for the media lane, whose rows
9280
+ * move from wherever they are rather than from one named source. */
9281
+ fromLocationId: string(),
9282
+ /** Where a drain would move it — the class's CURRENT default. */
9283
+ toLocationId: string(),
9284
+ /** Segments (footage lane) or rows (media lane) still on the source. */
9285
+ items: number().int().nonnegative().nullable(),
9286
+ /** Bytes on the source; `null` when the lane counts rows rather than bytes. */
9287
+ bytes: number().int().nonnegative().nullable()
9288
+ });
9289
+ /**
9290
+ * Run the DRAIN half and nothing else.
9291
+ *
9292
+ * A migration that reached `done` has already repointed, so `start` correctly
9293
+ * refuses its destination ("already the default") — there is nothing left to
9294
+ * repoint. But the drain can fail, be cancelled, be interrupted by a restart,
9295
+ * or finish against a work list that was a tenth of the archive (D295), and
9296
+ * before this there was no supported way to run only that half: the only way
9297
+ * through was calling `recording.relocateFootage` by hand over admin tRPC.
9298
+ *
9299
+ * `drain` NEVER calls `setDefaultLocations`. That is what keeps `start`'s
9300
+ * refusal meaningful: the two verbs are disjoint, so nothing here can silently
9301
+ * re-repoint a class that is already migrated.
9302
+ */
9303
+ var StorageMigrationDrainInputSchema = object({
9304
+ /** The classes to drain. Each must appear in `storageMigration.residue`, so
9305
+ * a class whose source is already empty is refused rather than started. */
9306
+ classes: array(StorageMigrationClassSchema).min(1),
9307
+ throttleMbps: number().min(1).max(1e3).optional()
9308
+ });
9309
+ /** What a footage source still holds, asked of the durable hour ledger. */
9310
+ var RelocateResidueInputSchema = object({
9311
+ fromLocationId: string().min(1),
9312
+ /** Narrow to one logical class; omit for every profile on the location. */
9313
+ footageClass: RelocateFootageClassSchema.optional()
9314
+ });
9315
+ /** `null` = the archive could not answer (no ledger on this node, or the
9316
+ * aggregate failed). Never conflated with an empty source. */
9317
+ var RelocateResidueSchema = object({
9318
+ segments: number().int().nonnegative(),
9319
+ bytes: number().int().nonnegative()
9320
+ }).nullable();
9321
+ /** How many rows a media pass would still act on against a given target — the
9322
+ * media lane's denominator AND its residue, from ONE derivation so the two can
9323
+ * never disagree. `null` = the count could not be taken. */
9324
+ var RelocatableMediaCountSchema = object({ rows: number().int().nonnegative() }).nullable();
9325
+ var RelocatableMediaCountInputSchema = object({
9326
+ toLocationId: string().min(1),
9327
+ /** Omitted = `move`. */
9328
+ mode: MediaRelocateModeSchema.optional()
9329
+ });
9330
+ /**
9203
9331
  * `StorageLocationType` — an addon-declared id that identifies the *kind* of
9204
9332
  * storage a location serves. Defined here (not in `capabilities/storage.cap.ts`)
9205
9333
  * so the persisted record schema and the consumer-facing cap can both consume it
@@ -9303,6 +9431,32 @@ var StorageLocationRefSchema = union([StorageLocationTypeSchema, string().regex(
9303
9431
  * two addons declaring the same `id` must agree on `cardinality` (validated
9304
9432
  * at kernel aggregation time, not here).
9305
9433
  */
9434
+ /**
9435
+ * `StorageAccess` — how the service that DECLARED a storage-location kind
9436
+ * actually reaches the bytes. It is the constraint that decides which
9437
+ * `storage-provider`s may back a location of that kind.
9438
+ *
9439
+ * - `'local-path'` — the service asks `storage.resolve` for a path string and
9440
+ * then does its own `node:fs` I/O on it (the recorder's segment writer, the
9441
+ * post-analysis media roots). Only a provider that serves a genuine local
9442
+ * filesystem (`getProviderInfo().nodeLocal === true`) can satisfy that: a
9443
+ * remote provider's `resolve` returns a path on the REMOTE host, and
9444
+ * `fs.readdir` of it on this node either fails or — far worse — succeeds
9445
+ * against a same-named local directory that is something else entirely.
9446
+ *
9447
+ * - `'cap-mediated'` — every byte travels through the `storage` cap
9448
+ * (`read`/`write`, or `beginUpload`/`writeChunk`/`finalizeUpload`). The
9449
+ * service never sees a path, so any provider can back it. `backups` is the
9450
+ * one kind that qualifies today.
9451
+ *
9452
+ * Before this existed, `recordings` was unreachable by SFTP/S3/WebDAV only as
9453
+ * an EMERGENT property of how the recorder happened to be written. Nothing
9454
+ * refused the configuration; the first write simply went somewhere wrong, and
9455
+ * a recording write that goes wrong surfaces as a silent black window rather
9456
+ * than an error (the read path does not `stat`). This turns that accident into
9457
+ * a declared, enforced, testable refusal.
9458
+ */
9459
+ var StorageAccessSchema = _enum(["local-path", "cap-mediated"]);
9306
9460
  var StorageLocationDeclarationSchema = object({
9307
9461
  /**
9308
9462
  * Global location identifier, e.g. `recordings` or `recordingsLow`.
@@ -9322,6 +9476,19 @@ var StorageLocationDeclarationSchema = object({
9322
9476
  */
9323
9477
  cardinality: _enum(["single", "multi"]),
9324
9478
  /**
9479
+ * HOW the declaring service reaches the bytes — and therefore WHICH
9480
+ * providers may back a location of this kind. See {@link StorageAccessSchema}
9481
+ * and {@link STORAGE_ACCESS_FALLBACK}.
9482
+ *
9483
+ * Absent means `'local-path'`. That default is FAIL-CLOSED on purpose: it
9484
+ * can only over-restrict (refuse a remote provider for a kind that might
9485
+ * have coped) and never under-restrict. Declaring `'cap-mediated'` is the
9486
+ * permissive direction and is therefore never inferred — a repo guard
9487
+ * (`scripts/check-storage-access-declarations.ts`) refuses to let it be
9488
+ * reached by omission.
9489
+ */
9490
+ access: StorageAccessSchema.optional(),
9491
+ /**
9325
9492
  * When set, the default instance for this location inherits its resolved
9326
9493
  * root from the named location's default instance. Useful for derivative
9327
9494
  * slots (e.g. `recordingsLow` → `recordings`) so operators only need to
@@ -19189,8 +19356,10 @@ var TrackSchema = object({
19189
19356
  lastSeen: number(),
19190
19357
  /** Frame-rate position history (subject to maxPositionHistory cap). */
19191
19358
  positions: array(TrackPositionSchema).readonly(),
19192
- /** Periodic snapshots at snapshotIntervalMs cadence (subject to
19193
- * saveThumbnails policy). */
19359
+ /** Periodic snapshots at snapshotIntervalMs cadence DEBUG media, produced
19360
+ * only while `MediaSettings.debugMediaEnabled` is on for the camera (D299;
19361
+ * the retired `saveThumbnails` used to gate this and the rolling
19362
+ * `lastFrame` together). Empty is the healthy default, not a capture gap. */
19194
19363
  snapshots: array(TrackSnapshotSchema).readonly(),
19195
19364
  /** Deduplicated zones the track has entered at least once. Zone IDS. */
19196
19365
  zonesVisited: array(string()).readonly(),
@@ -20050,7 +20219,10 @@ DeviceType.Camera, method(object({ deviceId: number() }), array(TrackSchema).rea
20050
20219
  }), method(RelocateMediaInputSchema, object({ jobId: string() }), {
20051
20220
  kind: "mutation",
20052
20221
  auth: "admin"
20053
- }), method(object({}), UnstampedEventMediaCountSchema, { auth: "admin" }), method(object({}), array(RelocateJobSchema).readonly(), {
20222
+ }), method(object({}), UnstampedEventMediaCountSchema, { auth: "admin" }), method(RelocatableMediaCountInputSchema, RelocatableMediaCountSchema, {
20223
+ kind: "query",
20224
+ auth: "admin"
20225
+ }), method(object({}), array(RelocateJobSchema).readonly(), {
20054
20226
  kind: "query",
20055
20227
  auth: "admin"
20056
20228
  }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
@@ -22009,6 +22181,9 @@ method(StorageMigrationInputSchema, StorageMigrationPlanSchema, { auth: "admin"
22009
22181
  }), method(object({ jobId: string().optional() }), StorageMigrationJobSchema.nullable(), { auth: "admin" }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
22010
22182
  kind: "mutation",
22011
22183
  auth: "admin"
22184
+ }), method(object({}), array(StorageMigrationMoverSchema).readonly(), { auth: "admin" }), method(object({}), array(StorageMigrationResidueSchema).readonly(), { auth: "admin" }), method(StorageMigrationDrainInputSchema, object({ jobId: string() }), {
22185
+ kind: "mutation",
22186
+ auth: "admin"
22012
22187
  });
22013
22188
  var ProviderInfoSchema = discriminatedUnion("shouldSaveDiskSpace", [object({
22014
22189
  providerId: string().min(1),
@@ -22407,12 +22582,38 @@ response: record(string(), unknown()) }), object({
22407
22582
  *
22408
22583
  * ## Why this is a capability and not a helper
22409
22584
  *
22410
- * Six stores in `addon-post-analysis` already hold vectors object CLIP, face,
22411
- * plate, vehicle, identity, and the event store's derivativesand every one of
22412
- * them keeps its vectors in a `JSON` settings-store column and ranks them by
22413
- * brute-force cosine in JS. Measured on the live hub that costs ~11.7 KB per row
22414
- * (512 floats as TEXT, `JSON.parse`d on every search) and made semantic search
22415
- * load 5,000 rows before ranking anything.
22585
+ * This capability was introduced with the claim that SIX stores in
22586
+ * `addon-post-analysis` held vectors in a `JSON` settings-store columnobject
22587
+ * CLIP, face, plate, vehicle, identity, and the event store's derivatives. That
22588
+ * claim was never true, and leaving it here made five stores look like pending
22589
+ * work when three of them have no vector at all. Counted column by column on
22590
+ * 2026-08-30, exactly THREE ever held one:
22591
+ *
22592
+ * - `object-clip` — 512-dim CLIP image embedding, migrated 2026-08-06.
22593
+ * - `faces.embedding` — 512-dim ArcFace face embedding, migrated 2026-08-30.
22594
+ * - `identity-samples.embedding` — the same ArcFace vector for an ENROLLED
22595
+ * face, migrated 2026-08-30 into its OWN index (see below).
22596
+ *
22597
+ * `plates` and `vehicle-samples` store a plate STRING and a score; `vehicles`
22598
+ * and `identities` store a name; the event store stores no derivative vector.
22599
+ * They are not migration candidates and never were.
22600
+ *
22601
+ * Measured on the live hub the JSON encoding cost ~11.7 KB per row (512 floats
22602
+ * as TEXT, `JSON.parse`d on every search) and made semantic search load 5,000
22603
+ * rows before ranking anything.
22604
+ *
22605
+ * ## One index per COMPARISON, never per encoder
22606
+ *
22607
+ * `faces` and `identity-samples` hold the same 512 ArcFace dims from the same
22608
+ * model, and they still get two indexes. An index is a set of things that are
22609
+ * ranked against each other and that live and die together, and these two are
22610
+ * neither: a `faces` row is TRACK-OWNED and cascades away with its track under
22611
+ * a per-camera capacity cap, an `identity-samples` row is retention-EXEMPT
22612
+ * forever and is the gallery every recognition ranks against. One index would
22613
+ * mean every gallery load and every reconcile carried a filter whose failure
22614
+ * mode is either ranking a candidate against itself or reclaiming an enrolled
22615
+ * person's only sample. The dimension they share is not a reason to share an
22616
+ * index; the question they answer is, and it differs.
22416
22617
  *
22417
22618
  * The fix is not a faster loop, it is a different backend — and the backend
22418
22619
  * should be replaceable without touching six callers. So: a singleton
@@ -22517,7 +22718,20 @@ var VectorQueryResultSchema = object({
22517
22718
  */
22518
22719
  scanned: number(),
22519
22720
  /** True when the backend could not consider every row that passed the filter. */
22520
- truncated: boolean()
22721
+ truncated: boolean(),
22722
+ /**
22723
+ * The `topK` the backend actually ran with.
22724
+ *
22725
+ * Every backend has a ceiling — sqlite-vec's is 4,096 — and a caller asking
22726
+ * past it used to learn nothing but a boolean, from a WARN in the provider's
22727
+ * own log rather than in its answer. That is how an audit asking for 20,000
22728
+ * consumed 4,096 and reported `examined: 4096` as if it had walked the index,
22729
+ * for weeks. `truncated` says THAT the answer was short; this says BY HOW
22730
+ * MUCH, in the return value, where the caller cannot fail to see it.
22731
+ *
22732
+ * Equals the requested `topK` whenever nothing was lowered.
22733
+ */
22734
+ effectiveTopK: number().int().positive()
22521
22735
  });
22522
22736
  var VectorDeleteInputSchema = object({
22523
22737
  index: string(),
@@ -22546,6 +22760,68 @@ var VectorGetResultSchema = object({ items: array(object({
22546
22760
  id: string(),
22547
22761
  metadata: VectorMetadataSchema
22548
22762
  })) });
22763
+ /**
22764
+ * Ids to read back WITH their vectors.
22765
+ *
22766
+ * The sibling of {@link VectorGetResultSchema}, and deliberately a separate
22767
+ * method rather than a flag on it: `getByIds` promises no vectors and its one
22768
+ * caller depends on that promise. This one promises the opposite.
22769
+ *
22770
+ * It exists because a store cannot put its vectors here otherwise. An ArcFace
22771
+ * gallery is ranked IN PROCESS, per detection, against every enrolled sample —
22772
+ * a per-face cross-process KNN would be a network round trip inside the
22773
+ * recognition loop. So the gallery is loaded once and held in RAM, and loading
22774
+ * it requires the index to hand the floats back. Without this method the only
22775
+ * way to keep a readable vector is a JSON column, which is the thing this
22776
+ * capability exists to delete.
22777
+ *
22778
+ * BOUNDED BY THE CALLER: ids are named, never "everything". Enumerating an
22779
+ * index is {@link VectorScanInputSchema}'s job, and it returns no vectors.
22780
+ */
22781
+ var VectorFetchInputSchema = object({
22782
+ index: string(),
22783
+ ids: array(string())
22784
+ });
22785
+ var VectorFetchResultSchema = object({ items: array(object({
22786
+ id: string(),
22787
+ /** base64 Float32LE — the same wire form `upsert` accepts. */
22788
+ vector: string(),
22789
+ metadata: VectorMetadataSchema
22790
+ })) });
22791
+ /**
22792
+ * ENUMERATE an index: one page of rows in a stable order, no ranking.
22793
+ *
22794
+ * A reconcile does not want the nearest rows, it wants ALL of them, and asking
22795
+ * a KNN for "all" is the wrong question twice over. It hits the backend's `k`
22796
+ * ceiling — 4,096 on sqlite-vec against a 22,128-row index — and it needs a
22797
+ * probe vector it does not have, so the audit passed a ZERO vector whose cosine
22798
+ * distance to every row is degenerate. `examined: 4096` then read as "we
22799
+ * looked" for as long as anyone cared to read it.
22800
+ *
22801
+ * This is the primitive that question actually needs: a bounded page, ordered
22802
+ * by the backend's own row order, costing no distance computation at all.
22803
+ * Vectors are NOT returned — an enumeration that shipped 2 KB per row would be
22804
+ * the full-table read this capability was built to stop.
22805
+ */
22806
+ var VectorScanInputSchema = object({
22807
+ index: string(),
22808
+ /** Opaque resume point. `0` starts at the top; pass back `nextCursor`. */
22809
+ cursor: number().int().nonnegative().default(0),
22810
+ limit: number().int().positive()
22811
+ });
22812
+ var VectorScanResultSchema = object({
22813
+ items: array(object({
22814
+ id: string(),
22815
+ metadata: VectorMetadataSchema
22816
+ })),
22817
+ /**
22818
+ * Where the next page starts, or `null` when the walk reached the end.
22819
+ *
22820
+ * `null` is the ONLY end-of-index signal. A caller must not infer the end
22821
+ * from a short page: a backend is free to return fewer rows than asked.
22822
+ */
22823
+ nextCursor: number().int().nonnegative().nullable()
22824
+ });
22549
22825
  var VectorStatsInputSchema = object({ index: string() });
22550
22826
  var VectorStatsResultSchema = object({
22551
22827
  /** Provider id, so an operator can tell brute force from an ANN index. */
@@ -22564,7 +22840,7 @@ method(VectorDeclareIndexInputSchema, _void(), {
22564
22840
  }), method(VectorUpsertInputSchema, VectorUpsertResultSchema, {
22565
22841
  kind: "mutation",
22566
22842
  auth: "admin"
22567
- }), method(VectorQueryInputSchema, VectorQueryResultSchema, { auth: "admin" }), method(VectorGetInputSchema, VectorGetResultSchema, { auth: "admin" }), method(VectorDeleteInputSchema, VectorDeleteResultSchema, {
22843
+ }), method(VectorQueryInputSchema, VectorQueryResultSchema, { auth: "admin" }), method(VectorGetInputSchema, VectorGetResultSchema, { auth: "admin" }), method(VectorFetchInputSchema, VectorFetchResultSchema, { auth: "admin" }), method(VectorScanInputSchema, VectorScanResultSchema, { auth: "admin" }), method(VectorDeleteInputSchema, VectorDeleteResultSchema, {
22568
22844
  kind: "mutation",
22569
22845
  auth: "admin"
22570
22846
  }), method(VectorDeleteByFilterInputSchema, VectorDeleteResultSchema, {
@@ -29183,6 +29459,9 @@ method(object({
29183
29459
  }), method(object({}), array(RelocateJobSchema).readonly(), {
29184
29460
  kind: "query",
29185
29461
  auth: "admin"
29462
+ }), method(RelocateResidueInputSchema, RelocateResidueSchema, {
29463
+ kind: "query",
29464
+ auth: "admin"
29186
29465
  }), method(object({ jobId: string() }), object({ cancelled: boolean() }), {
29187
29466
  kind: "mutation",
29188
29467
  auth: "admin"
@@ -35817,6 +36096,12 @@ Object.freeze({
35817
36096
  addonId: null,
35818
36097
  access: "create"
35819
36098
  },
36099
+ "pipelineAnalytics.countRelocatableMedia": {
36100
+ capName: "pipeline-analytics",
36101
+ capScope: "device",
36102
+ addonId: null,
36103
+ access: "view"
36104
+ },
35820
36105
  "pipelineAnalytics.countUnstampedEventMedia": {
35821
36106
  capName: "pipeline-analytics",
35822
36107
  capScope: "device",
@@ -36981,6 +37266,12 @@ Object.freeze({
36981
37266
  addonId: null,
36982
37267
  access: "view"
36983
37268
  },
37269
+ "recording.getRelocateResidue": {
37270
+ capName: "recording",
37271
+ capScope: "system",
37272
+ addonId: null,
37273
+ access: "view"
37274
+ },
36984
37275
  "recording.getStorageMigrationMoveStatus": {
36985
37276
  capName: "recording",
36986
37277
  capScope: "system",
@@ -37527,12 +37818,30 @@ Object.freeze({
37527
37818
  addonId: null,
37528
37819
  access: "create"
37529
37820
  },
37821
+ "storageMigration.drain": {
37822
+ capName: "storage-migration",
37823
+ capScope: "system",
37824
+ addonId: null,
37825
+ access: "create"
37826
+ },
37827
+ "storageMigration.movers": {
37828
+ capName: "storage-migration",
37829
+ capScope: "system",
37830
+ addonId: null,
37831
+ access: "view"
37832
+ },
37530
37833
  "storageMigration.plan": {
37531
37834
  capName: "storage-migration",
37532
37835
  capScope: "system",
37533
37836
  addonId: null,
37534
37837
  access: "view"
37535
37838
  },
37839
+ "storageMigration.residue": {
37840
+ capName: "storage-migration",
37841
+ capScope: "system",
37842
+ addonId: null,
37843
+ access: "view"
37844
+ },
37536
37845
  "storageMigration.start": {
37537
37846
  capName: "storage-migration",
37538
37847
  capScope: "system",
@@ -38367,6 +38676,12 @@ Object.freeze({
38367
38676
  addonId: null,
38368
38677
  access: "delete"
38369
38678
  },
38679
+ "vectorStore.fetchByIds": {
38680
+ capName: "vector-store",
38681
+ capScope: "system",
38682
+ addonId: null,
38683
+ access: "view"
38684
+ },
38370
38685
  "vectorStore.getByIds": {
38371
38686
  capName: "vector-store",
38372
38687
  capScope: "system",
@@ -38379,6 +38694,12 @@ Object.freeze({
38379
38694
  addonId: null,
38380
38695
  access: "view"
38381
38696
  },
38697
+ "vectorStore.scan": {
38698
+ capName: "vector-store",
38699
+ capScope: "system",
38700
+ addonId: null,
38701
+ access: "view"
38702
+ },
38382
38703
  "vectorStore.stats": {
38383
38704
  capName: "vector-store",
38384
38705
  capScope: "system",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camstack/addon-provider-rademacher",
3
- "version": "0.2.42",
3
+ "version": "0.2.44",
4
4
  "description": "Rademacher HomePilot device-provider addon for CamStack — wraps the @apocaliss92/noderademacher local-hub client (roller shutters over the cover cap)",
5
5
  "keywords": [
6
6
  "camstack",