camstack 1.2.63 → 1.2.66

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.
@@ -23633,9 +23633,9 @@ var require_zod = __commonJS({
23633
23633
  }
23634
23634
  });
23635
23635
 
23636
- // ../system/dist/dist-CDgIzo82.js
23637
- var require_dist_CDgIzo82 = __commonJS({
23638
- "../system/dist/dist-CDgIzo82.js"(exports) {
23636
+ // ../system/dist/dist-CcvXUhHK.js
23637
+ var require_dist_CcvXUhHK = __commonJS({
23638
+ "../system/dist/dist-CcvXUhHK.js"(exports) {
23639
23639
  "use strict";
23640
23640
  var zod = require_zod();
23641
23641
  var EventCategory = /* @__PURE__ */ (function(EventCategory2) {
@@ -25997,6 +25997,40 @@ var require_dist_CDgIzo82 = __commonJS({
25997
25997
  /** Unix ms when the group was composed server-side. */
25998
25998
  fetchedAt: zod.z.number()
25999
25999
  });
26000
+ var REDACTED_SECRET = "__camstack_redacted__";
26001
+ function collectSecretConfigKeys(schema) {
26002
+ const keys = /* @__PURE__ */ new Set();
26003
+ for (const section of sectionsOf(schema)) for (const field of fieldsOf(section)) walkField(field, keys);
26004
+ return keys;
26005
+ }
26006
+ function isRecord$2(value) {
26007
+ return typeof value === "object" && value !== null && !Array.isArray(value);
26008
+ }
26009
+ function sectionsOf(schema) {
26010
+ if (!isRecord$2(schema)) return [];
26011
+ const sections = schema["sections"];
26012
+ return Array.isArray(sections) ? sections : [];
26013
+ }
26014
+ function fieldsOf(node) {
26015
+ if (!isRecord$2(node)) return [];
26016
+ const fields = node["fields"];
26017
+ return Array.isArray(fields) ? fields : [];
26018
+ }
26019
+ function walkField(field, out) {
26020
+ if (!isRecord$2(field)) return;
26021
+ const type = field["type"];
26022
+ const key = field["key"];
26023
+ if ((type === "password" || field["secret"] === true) && typeof key === "string" && key.length > 0) out.add(key);
26024
+ if (type === "group") {
26025
+ for (const child of fieldsOf(field)) walkField(child, out);
26026
+ return;
26027
+ }
26028
+ if (type === "sub-tabs") {
26029
+ const tabs = field["tabs"];
26030
+ if (!Array.isArray(tabs)) return;
26031
+ for (const tab of tabs) for (const child of fieldsOf(tab)) walkField(child, out);
26032
+ }
26033
+ }
26000
26034
  var STREAM_QUALITY_LABELS = {
26001
26035
  high: "High",
26002
26036
  mid: "Mid",
@@ -26225,6 +26259,21 @@ var require_dist_CDgIzo82 = __commonJS({
26225
26259
  bytesMoved: zod.z.number().int(),
26226
26260
  /** Total files discovered up front; null while (or when) unknown. */
26227
26261
  filesTotal: zod.z.number().int().nullable(),
26262
+ /**
26263
+ * Rows this run CORRECTED while moving them — a durable mutation the move
26264
+ * made that nobody asked for, so it is reported where the operator reads the
26265
+ * job rather than only in a log line.
26266
+ *
26267
+ * A footage segment records its byte count in its own NAME, and the durable
26268
+ * hour row derives its aggregates from those names. A file that does not
26269
+ * match its name therefore makes the ledger's sums — and with them quota and
26270
+ * pressure eviction — wrong by the difference, and only a rename can fix it.
26271
+ * On 2026-08-30 one such row also stalled a 110 749-file drain permanently.
26272
+ *
26273
+ * Absent on lanes where the question has no meaning: a media blob's size is
26274
+ * in its row, not in its name, so `MediaRelocateEngine` never reconciles one.
26275
+ */
26276
+ rowsReconciled: zod.z.number().int().nonnegative().optional(),
26228
26277
  startedAt: zod.z.number(),
26229
26278
  finishedAt: zod.z.number().nullable(),
26230
26279
  error: zod.z.string().nullable()
@@ -26267,11 +26316,18 @@ var require_dist_CDgIzo82 = __commonJS({
26267
26316
  /** Omitted = `move`, the pre-existing behaviour. */
26268
26317
  mode: MediaRelocateModeSchema.optional()
26269
26318
  });
26270
- var UnstampedEventMediaCountSchema = zod.z.object({
26271
- media: zod.z.number().int().nonnegative(),
26272
- retrainFrames: zod.z.number().int().nonnegative(),
26273
- total: zod.z.number().int().nonnegative()
26319
+ var UnstampedRowsSchema = zod.z.object({
26320
+ present: zod.z.boolean(),
26321
+ rows: zod.z.number().int().nonnegative().nullable()
26274
26322
  });
26323
+ var UnstampedEventMediaCountSchema = zod.z.object({
26324
+ media: UnstampedRowsSchema,
26325
+ retrainFrames: UnstampedRowsSchema,
26326
+ /** True when EITHER collection holds one. The refusal reads this. */
26327
+ anyPresent: zod.z.boolean(),
26328
+ /** Sum across both, or `null` when either lane could not be counted. */
26329
+ total: zod.z.number().int().nonnegative().nullable()
26330
+ }).nullable();
26275
26331
  var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: zod.z.string().min(1) });
26276
26332
  var StorageMigrationClassSchema = zod.z.enum([
26277
26333
  "recordings",
@@ -26313,13 +26369,33 @@ var require_dist_CDgIzo82 = __commonJS({
26313
26369
  "recorder",
26314
26370
  "analytics"
26315
26371
  ]);
26372
+ var StorageMigrationMoveProgressSchema = zod.z.object({
26373
+ filesMoved: zod.z.number().int().nonnegative(),
26374
+ /** The archive census — the **M** of "N of M" (D295). `null` = unknowable. */
26375
+ filesTotal: zod.z.number().int().nonnegative().nullable(),
26376
+ bytesMoved: zod.z.number().int().nonnegative(),
26377
+ /** Rows the mover corrected while moving them — see `RelocateJob`. Absent on
26378
+ * a lane that cannot reconcile. A migration that silently rewrote durable
26379
+ * rows would be the same failure as one that silently skipped them. */
26380
+ rowsReconciled: zod.z.number().int().nonnegative().optional(),
26381
+ /** The MOVER's start, not the migration's: a drain restarted after an addon
26382
+ * crash gets a new mover, and a rate computed from the migration's start
26383
+ * would silently average in the time nothing was running. */
26384
+ startedAt: zod.z.number(),
26385
+ /** When the coordinator last read these numbers. Paired with `startedAt` it
26386
+ * is the only honest rate: both clocks are the hub's, so a UI never has to
26387
+ * subtract its own. */
26388
+ observedAt: zod.z.number()
26389
+ });
26316
26390
  var StorageMigrationMoveSchema = zod.z.object({
26317
26391
  storageClass: StorageMigrationClassSchema,
26318
26392
  fromLocationId: zod.z.string(),
26319
26393
  toLocationId: zod.z.string(),
26320
26394
  moverJobId: zod.z.string().nullable(),
26321
26395
  state: RelocateJobStateSchema.nullable(),
26322
- error: zod.z.string().nullable()
26396
+ error: zod.z.string().nullable(),
26397
+ /** Last observed mover counters; `null` until the mover has been polled once. */
26398
+ progress: StorageMigrationMoveProgressSchema.nullable()
26323
26399
  });
26324
26400
  var StorageMigrationJobSchema = zod.z.object({
26325
26401
  jobId: zod.z.string(),
@@ -26365,6 +26441,52 @@ var require_dist_CDgIzo82 = __commonJS({
26365
26441
  })),
26366
26442
  findings: zod.z.array(StorageMigrationFindingSchema)
26367
26443
  });
26444
+ var StorageMigrationLaneSchema = zod.z.enum(["footage", "media"]);
26445
+ var StorageMigrationMoverSchema = zod.z.object({
26446
+ lane: StorageMigrationLaneSchema,
26447
+ job: RelocateJobSchema,
26448
+ /** The coordinator job that armed this mover, or `null` for a mover armed
26449
+ * directly against the owning addon. */
26450
+ migrationJobId: zod.z.string().nullable(),
26451
+ /** When the hub read these counters. Stamped here so a rate is `bytesMoved`
26452
+ * over (`observedAt` − `job.startedAt`) with BOTH ends on the hub's clock —
26453
+ * a browser subtracting its own `Date.now()` from a server `startedAt` is a
26454
+ * rate made of two different clocks. */
26455
+ observedAt: zod.z.number()
26456
+ });
26457
+ var StorageMigrationResidueSchema = zod.z.object({
26458
+ storageClass: StorageMigrationClassSchema,
26459
+ /** The location still holding the data. `'*'` for the media lane, whose rows
26460
+ * move from wherever they are rather than from one named source. */
26461
+ fromLocationId: zod.z.string(),
26462
+ /** Where a drain would move it — the class's CURRENT default. */
26463
+ toLocationId: zod.z.string(),
26464
+ /** Segments (footage lane) or rows (media lane) still on the source. */
26465
+ items: zod.z.number().int().nonnegative().nullable(),
26466
+ /** Bytes on the source; `null` when the lane counts rows rather than bytes. */
26467
+ bytes: zod.z.number().int().nonnegative().nullable()
26468
+ });
26469
+ var StorageMigrationDrainInputSchema = zod.z.object({
26470
+ /** The classes to drain. Each must appear in `storageMigration.residue`, so
26471
+ * a class whose source is already empty is refused rather than started. */
26472
+ classes: zod.z.array(StorageMigrationClassSchema).min(1),
26473
+ throttleMbps: zod.z.number().min(1).max(1e3).optional()
26474
+ });
26475
+ var RelocateResidueInputSchema = zod.z.object({
26476
+ fromLocationId: zod.z.string().min(1),
26477
+ /** Narrow to one logical class; omit for every profile on the location. */
26478
+ footageClass: RelocateFootageClassSchema.optional()
26479
+ });
26480
+ var RelocateResidueSchema = zod.z.object({
26481
+ segments: zod.z.number().int().nonnegative(),
26482
+ bytes: zod.z.number().int().nonnegative()
26483
+ }).nullable();
26484
+ var RelocatableMediaCountSchema = zod.z.object({ rows: zod.z.number().int().nonnegative() }).nullable();
26485
+ var RelocatableMediaCountInputSchema = zod.z.object({
26486
+ toLocationId: zod.z.string().min(1),
26487
+ /** Omitted = `move`. */
26488
+ mode: MediaRelocateModeSchema.optional()
26489
+ });
26368
26490
  var StorageLocationTypeSchema = zod.z.string().regex(/^[a-z][a-zA-Z0-9-]*$/);
26369
26491
  var StorageLocationSchema = zod.z.object({
26370
26492
  id: zod.z.string().regex(/^[a-z][a-zA-Z0-9-]*:[a-zA-Z0-9-]+$/),
@@ -26408,6 +26530,8 @@ var require_dist_CDgIzo82 = __commonJS({
26408
26530
  updatedAt: zod.z.number()
26409
26531
  });
26410
26532
  var StorageLocationRefSchema = zod.z.union([StorageLocationTypeSchema, zod.z.string().regex(/^[a-z][a-zA-Z0-9-]*:[a-zA-Z0-9-]+$/)]);
26533
+ var StorageAccessSchema = zod.z.enum(["local-path", "cap-mediated"]);
26534
+ var STORAGE_ACCESS_FALLBACK = "local-path";
26411
26535
  var StorageLocationDeclarationSchema = zod.z.object({
26412
26536
  /**
26413
26537
  * Global location identifier, e.g. `recordings` or `recordingsLow`.
@@ -26427,6 +26551,19 @@ var require_dist_CDgIzo82 = __commonJS({
26427
26551
  */
26428
26552
  cardinality: zod.z.enum(["single", "multi"]),
26429
26553
  /**
26554
+ * HOW the declaring service reaches the bytes — and therefore WHICH
26555
+ * providers may back a location of this kind. See {@link StorageAccessSchema}
26556
+ * and {@link STORAGE_ACCESS_FALLBACK}.
26557
+ *
26558
+ * Absent means `'local-path'`. That default is FAIL-CLOSED on purpose: it
26559
+ * can only over-restrict (refuse a remote provider for a kind that might
26560
+ * have coped) and never under-restrict. Declaring `'cap-mediated'` is the
26561
+ * permissive direction and is therefore never inferred — a repo guard
26562
+ * (`scripts/check-storage-access-declarations.ts`) refuses to let it be
26563
+ * reached by omission.
26564
+ */
26565
+ access: StorageAccessSchema.optional(),
26566
+ /**
26430
26567
  * When set, the default instance for this location inherits its resolved
26431
26568
  * root from the named location's default instance. Useful for derivative
26432
26569
  * slots (e.g. `recordingsLow` → `recordings`) so operators only need to
@@ -31396,6 +31533,15 @@ var require_dist_CDgIzo82 = __commonJS({
31396
31533
  * calls are sync. Bindings change rarely (only on wrapper toggle or
31397
31534
  * device add/remove) — clients invalidate via the
31398
31535
  * `capability.binding-changed` event.
31536
+ *
31537
+ * "A single round-trip" describes the CLIENT's side and used not to
31538
+ * describe the server's: until 2026-08-30 the resolver read the persisted
31539
+ * wrapper activations once per device, so answering this cost one
31540
+ * settings-door RPC per device — 1 020 on the live 1 019-device hub, and
31541
+ * it did not return in 240 s against `SystemMirror.init`'s 15 s budget.
31542
+ * The server side is now two reads for the whole fleet. Anything PERIODIC
31543
+ * still belongs on `getBindings` / `getBindingsBatch` (D12); this remains
31544
+ * a warm seed.
31399
31545
  */
31400
31546
  getAllBindings: method(zod.z.object({}), zod.z.array(DeviceBindingsForDeviceSchema)),
31401
31547
  /**
@@ -36385,8 +36531,10 @@ var require_dist_CDgIzo82 = __commonJS({
36385
36531
  lastSeen: zod.z.number(),
36386
36532
  /** Frame-rate position history (subject to maxPositionHistory cap). */
36387
36533
  positions: zod.z.array(TrackPositionSchema).readonly(),
36388
- /** Periodic snapshots at snapshotIntervalMs cadence (subject to
36389
- * saveThumbnails policy). */
36534
+ /** Periodic snapshots at snapshotIntervalMs cadence DEBUG media, produced
36535
+ * only while `MediaSettings.debugMediaEnabled` is on for the camera (D299;
36536
+ * the retired `saveThumbnails` used to gate this and the rolling
36537
+ * `lastFrame` together). Empty is the healthy default, not a capture gap. */
36390
36538
  snapshots: zod.z.array(TrackSnapshotSchema).readonly(),
36391
36539
  /** Deduplicated zones the track has entered at least once. Zone IDS. */
36392
36540
  zonesVisited: zod.z.array(zod.z.string()).readonly(),
@@ -37367,8 +37515,34 @@ var require_dist_CDgIzo82 = __commonJS({
37367
37515
  * happens to stamp it. This count is what the migration planner's
37368
37516
  * non-blocking gate reads; `relocateMedia({ mode: 'seal' })` is what drives
37369
37517
  * it to zero.
37518
+ *
37519
+ * TWO indexed statements per collection, not a walk. It used to page the
37520
+ * whole collection at 200 rows per RPC ordered by an unindexed column, so
37521
+ * on the live hub — 1 254 576 rows — it hit the 60 s RPC deadline every
37522
+ * time it was called, and the migration it gates could never start. The
37523
+ * cheap question (`present`: is there at least one) is asked first and
37524
+ * separately from the expensive one (`rows`), because only the first has
37525
+ * to be answerable for the gate to do its job.
37526
+ *
37527
+ * **`null` is "not measurable", never zero** — at either level. An
37528
+ * unreadable collection must not read as a sealed one.
37370
37529
  */
37371
37530
  countUnstampedEventMedia: method(zod.z.object({}), UnstampedEventMediaCountSchema, { auth: "admin" }),
37531
+ /**
37532
+ * How many rows a pass would STILL act on against `toLocationId`.
37533
+ *
37534
+ * One derivation, two consumers: it is the media lane's denominator (the
37535
+ * **M** the footage lane gets from the ledger census — D295) and it is the
37536
+ * residue behind "drain remaining". Deriving them separately is how "N of M"
37537
+ * ends up comparing two different populations.
37538
+ *
37539
+ * `null` means the count could not be taken; it is never zero-filled,
37540
+ * because a zero here reads as "nothing left to move".
37541
+ */
37542
+ countRelocatableMedia: method(RelocatableMediaCountInputSchema, RelocatableMediaCountSchema, {
37543
+ kind: "query",
37544
+ auth: "admin"
37545
+ }),
37372
37546
  /** Every relocate job this addon knows about, newest first (in RAM: the
37373
37547
  * move is resumable, so a lost list costs nothing but the display). */
37374
37548
  listRelocateMediaJobs: method(zod.z.object({}), zod.z.array(RelocateJobSchema).readonly(), {
@@ -39909,6 +40083,35 @@ var require_dist_CDgIzo82 = __commonJS({
39909
40083
  cancel: method(zod.z.object({ jobId: zod.z.string() }), zod.z.object({ cancelled: zod.z.boolean() }), {
39910
40084
  kind: "mutation",
39911
40085
  auth: "admin"
40086
+ }),
40087
+ /**
40088
+ * Every mover running RIGHT NOW, in both lanes, with its counters.
40089
+ *
40090
+ * `status` covers a migration's own moves — the coordinator folds their
40091
+ * progress onto the durable job record it is already polling. This covers
40092
+ * the other case, and it is not hypothetical: a drain armed straight against
40093
+ * `recording.relocateFootage` (the only path that existed before
40094
+ * {@link drain}) has no job to fold into and would otherwise be invisible.
40095
+ */
40096
+ movers: method(zod.z.object({}), zod.z.array(StorageMigrationMoverSchema).readonly(), { auth: "admin" }),
40097
+ /**
40098
+ * What each class's SOURCE still holds, from the archive — never from the
40099
+ * resident index (D295). Only classes with something left (or something
40100
+ * unknown) are listed, so an empty list means there is nothing to drain and
40101
+ * the UI has no honest button to offer.
40102
+ */
40103
+ residue: method(zod.z.object({}), zod.z.array(StorageMigrationResidueSchema).readonly(), { auth: "admin" }),
40104
+ /**
40105
+ * Run the drain half alone, on a class whose default has ALREADY moved.
40106
+ *
40107
+ * It never repoints anything, which is what lets `start` keep refusing a
40108
+ * destination that is already the default: the two verbs cannot be confused
40109
+ * for one another, and no operator can re-repoint a migrated class through
40110
+ * this door.
40111
+ */
40112
+ drain: method(StorageMigrationDrainInputSchema, zod.z.object({ jobId: zod.z.string() }), {
40113
+ kind: "mutation",
40114
+ auth: "admin"
39912
40115
  })
39913
40116
  }
39914
40117
  };
@@ -40418,7 +40621,20 @@ var require_dist_CDgIzo82 = __commonJS({
40418
40621
  */
40419
40622
  scanned: zod.z.number(),
40420
40623
  /** True when the backend could not consider every row that passed the filter. */
40421
- truncated: zod.z.boolean()
40624
+ truncated: zod.z.boolean(),
40625
+ /**
40626
+ * The `topK` the backend actually ran with.
40627
+ *
40628
+ * Every backend has a ceiling — sqlite-vec's is 4,096 — and a caller asking
40629
+ * past it used to learn nothing but a boolean, from a WARN in the provider's
40630
+ * own log rather than in its answer. That is how an audit asking for 20,000
40631
+ * consumed 4,096 and reported `examined: 4096` as if it had walked the index,
40632
+ * for weeks. `truncated` says THAT the answer was short; this says BY HOW
40633
+ * MUCH, in the return value, where the caller cannot fail to see it.
40634
+ *
40635
+ * Equals the requested `topK` whenever nothing was lowered.
40636
+ */
40637
+ effectiveTopK: zod.z.number().int().positive()
40422
40638
  });
40423
40639
  var VectorDeleteInputSchema = zod.z.object({
40424
40640
  index: zod.z.string(),
@@ -40437,6 +40653,35 @@ var require_dist_CDgIzo82 = __commonJS({
40437
40653
  id: zod.z.string(),
40438
40654
  metadata: VectorMetadataSchema
40439
40655
  })) });
40656
+ var VectorFetchInputSchema = zod.z.object({
40657
+ index: zod.z.string(),
40658
+ ids: zod.z.array(zod.z.string())
40659
+ });
40660
+ var VectorFetchResultSchema = zod.z.object({ items: zod.z.array(zod.z.object({
40661
+ id: zod.z.string(),
40662
+ /** base64 Float32LE — the same wire form `upsert` accepts. */
40663
+ vector: zod.z.string(),
40664
+ metadata: VectorMetadataSchema
40665
+ })) });
40666
+ var VectorScanInputSchema = zod.z.object({
40667
+ index: zod.z.string(),
40668
+ /** Opaque resume point. `0` starts at the top; pass back `nextCursor`. */
40669
+ cursor: zod.z.number().int().nonnegative().default(0),
40670
+ limit: zod.z.number().int().positive()
40671
+ });
40672
+ var VectorScanResultSchema = zod.z.object({
40673
+ items: zod.z.array(zod.z.object({
40674
+ id: zod.z.string(),
40675
+ metadata: VectorMetadataSchema
40676
+ })),
40677
+ /**
40678
+ * Where the next page starts, or `null` when the walk reached the end.
40679
+ *
40680
+ * `null` is the ONLY end-of-index signal. A caller must not infer the end
40681
+ * from a short page: a backend is free to return fewer rows than asked.
40682
+ */
40683
+ nextCursor: zod.z.number().int().nonnegative().nullable()
40684
+ });
40440
40685
  var VectorStatsInputSchema = zod.z.object({ index: zod.z.string() });
40441
40686
  var VectorStatsResultSchema = zod.z.object({
40442
40687
  /** Provider id, so an operator can tell brute force from an ANN index. */
@@ -40467,6 +40712,10 @@ var require_dist_CDgIzo82 = __commonJS({
40467
40712
  query: method(VectorQueryInputSchema, VectorQueryResultSchema, { auth: "admin" }),
40468
40713
  /** Metadata by id, no vectors — see {@link VectorGetResultSchema}. */
40469
40714
  getByIds: method(VectorGetInputSchema, VectorGetResultSchema, { auth: "admin" }),
40715
+ /** Metadata AND vectors, by named id — see {@link VectorFetchInputSchema}. */
40716
+ fetchByIds: method(VectorFetchInputSchema, VectorFetchResultSchema, { auth: "admin" }),
40717
+ /** One page of the whole index, unranked — see {@link VectorScanInputSchema}. */
40718
+ scan: method(VectorScanInputSchema, VectorScanResultSchema, { auth: "admin" }),
40470
40719
  deleteByIds: method(VectorDeleteInputSchema, VectorDeleteResultSchema, {
40471
40720
  kind: "mutation",
40472
40721
  auth: "admin"
@@ -46928,6 +47177,20 @@ var require_dist_CDgIzo82 = __commonJS({
46928
47177
  kind: "query",
46929
47178
  auth: "admin"
46930
47179
  }),
47180
+ /**
47181
+ * What a location STILL holds, asked of the durable hour ledger.
47182
+ *
47183
+ * The number behind "drain remaining": segments and bytes that would still
47184
+ * have to move off `fromLocationId`. It is a ledger aggregate — the archive
47185
+ * — because the resident index is not the archive (D295), and a drain sized
47186
+ * off the index is exactly what reported `done` over 80.3 GB on 2026-08-29.
47187
+ * `null` means the archive could not be asked (no ledger on this node, or
47188
+ * the aggregate failed) and is never conflated with an empty source.
47189
+ */
47190
+ getRelocateResidue: method(RelocateResidueInputSchema, RelocateResidueSchema, {
47191
+ kind: "query",
47192
+ auth: "admin"
47193
+ }),
46931
47194
  /** Cancel a running or queued relocate job. A queued job never runs. */
46932
47195
  cancelRelocateJob: method(zod.z.object({ jobId: zod.z.string() }), zod.z.object({ cancelled: zod.z.boolean() }), {
46933
47196
  kind: "mutation",
@@ -52932,6 +53195,12 @@ var require_dist_CDgIzo82 = __commonJS({
52932
53195
  addonId: null,
52933
53196
  access: "create"
52934
53197
  },
53198
+ "pipelineAnalytics.countRelocatableMedia": {
53199
+ capName: "pipeline-analytics",
53200
+ capScope: "device",
53201
+ addonId: null,
53202
+ access: "view"
53203
+ },
52935
53204
  "pipelineAnalytics.countUnstampedEventMedia": {
52936
53205
  capName: "pipeline-analytics",
52937
53206
  capScope: "device",
@@ -54096,6 +54365,12 @@ var require_dist_CDgIzo82 = __commonJS({
54096
54365
  addonId: null,
54097
54366
  access: "view"
54098
54367
  },
54368
+ "recording.getRelocateResidue": {
54369
+ capName: "recording",
54370
+ capScope: "system",
54371
+ addonId: null,
54372
+ access: "view"
54373
+ },
54099
54374
  "recording.getStorageMigrationMoveStatus": {
54100
54375
  capName: "recording",
54101
54376
  capScope: "system",
@@ -54642,12 +54917,30 @@ var require_dist_CDgIzo82 = __commonJS({
54642
54917
  addonId: null,
54643
54918
  access: "create"
54644
54919
  },
54920
+ "storageMigration.drain": {
54921
+ capName: "storage-migration",
54922
+ capScope: "system",
54923
+ addonId: null,
54924
+ access: "create"
54925
+ },
54926
+ "storageMigration.movers": {
54927
+ capName: "storage-migration",
54928
+ capScope: "system",
54929
+ addonId: null,
54930
+ access: "view"
54931
+ },
54645
54932
  "storageMigration.plan": {
54646
54933
  capName: "storage-migration",
54647
54934
  capScope: "system",
54648
54935
  addonId: null,
54649
54936
  access: "view"
54650
54937
  },
54938
+ "storageMigration.residue": {
54939
+ capName: "storage-migration",
54940
+ capScope: "system",
54941
+ addonId: null,
54942
+ access: "view"
54943
+ },
54651
54944
  "storageMigration.start": {
54652
54945
  capName: "storage-migration",
54653
54946
  capScope: "system",
@@ -55482,6 +55775,12 @@ var require_dist_CDgIzo82 = __commonJS({
55482
55775
  addonId: null,
55483
55776
  access: "delete"
55484
55777
  },
55778
+ "vectorStore.fetchByIds": {
55779
+ capName: "vector-store",
55780
+ capScope: "system",
55781
+ addonId: null,
55782
+ access: "view"
55783
+ },
55485
55784
  "vectorStore.getByIds": {
55486
55785
  capName: "vector-store",
55487
55786
  capScope: "system",
@@ -55494,6 +55793,12 @@ var require_dist_CDgIzo82 = __commonJS({
55494
55793
  addonId: null,
55495
55794
  access: "view"
55496
55795
  },
55796
+ "vectorStore.scan": {
55797
+ capName: "vector-store",
55798
+ capScope: "system",
55799
+ addonId: null,
55800
+ access: "view"
55801
+ },
55497
55802
  "vectorStore.stats": {
55498
55803
  capName: "vector-store",
55499
55804
  capScope: "system",
@@ -58249,6 +58554,12 @@ var require_dist_CDgIzo82 = __commonJS({
58249
58554
  return METHOD_ACCESS_MAP;
58250
58555
  }
58251
58556
  });
58557
+ Object.defineProperty(exports, "REDACTED_SECRET", {
58558
+ enumerable: true,
58559
+ get: function() {
58560
+ return REDACTED_SECRET;
58561
+ }
58562
+ });
58252
58563
  Object.defineProperty(exports, "RUNTIME_DEFAULTS", {
58253
58564
  enumerable: true,
58254
58565
  get: function() {
@@ -58279,6 +58590,12 @@ var require_dist_CDgIzo82 = __commonJS({
58279
58590
  return SOURCE_DEVICE_TYPES;
58280
58591
  }
58281
58592
  });
58593
+ Object.defineProperty(exports, "STORAGE_ACCESS_FALLBACK", {
58594
+ enumerable: true,
58595
+ get: function() {
58596
+ return STORAGE_ACCESS_FALLBACK;
58597
+ }
58598
+ });
58282
58599
  Object.defineProperty(exports, "STREAM_PROFILE_META", {
58283
58600
  enumerable: true,
58284
58601
  get: function() {
@@ -58387,6 +58704,12 @@ var require_dist_CDgIzo82 = __commonJS({
58387
58704
  return buildStreamParamsConfigSchema;
58388
58705
  }
58389
58706
  });
58707
+ Object.defineProperty(exports, "collectSecretConfigKeys", {
58708
+ enumerable: true,
58709
+ get: function() {
58710
+ return collectSecretConfigKeys;
58711
+ }
58712
+ });
58390
58713
  Object.defineProperty(exports, "coreBlockAddonId", {
58391
58714
  enumerable: true,
58392
58715
  get: function() {
@@ -58789,7 +59112,7 @@ var require_alerts_addon = __commonJS({
58789
59112
  [Symbol.toStringTag]: { value: "Module" }
58790
59113
  });
58791
59114
  require_chunk_Cek0wNdY();
58792
- var require_dist10 = require_dist_CDgIzo82();
59115
+ var require_dist10 = require_dist_CcvXUhHK();
58793
59116
  function selectExpired(alerts, cutoffMs) {
58794
59117
  return alerts.filter((a) => a.createdAt < cutoffMs).sort((a, b) => a.createdAt - b.createdAt).map((a) => a.id);
58795
59118
  }
@@ -59608,7 +59931,7 @@ var require_console_logging = __commonJS({
59608
59931
  [Symbol.toStringTag]: { value: "Module" }
59609
59932
  });
59610
59933
  require_chunk_Cek0wNdY();
59611
- var require_dist10 = require_dist_CDgIzo82();
59934
+ var require_dist10 = require_dist_CcvXUhHK();
59612
59935
  var require_formatter = require_formatter_DqAKDlvN();
59613
59936
  var LEVEL_RANK = {
59614
59937
  debug: 0,
@@ -59702,7 +60025,7 @@ var require_core_blocks_addon = __commonJS({
59702
60025
  "use strict";
59703
60026
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
59704
60027
  var require_chunk = require_chunk_Cek0wNdY();
59705
- var require_dist10 = require_dist_CDgIzo82();
60028
+ var require_dist10 = require_dist_CcvXUhHK();
59706
60029
  var node_crypto = __require("crypto");
59707
60030
  var node_fs_promises = __require("fs/promises");
59708
60031
  node_fs_promises = require_chunk.__toESM(node_fs_promises);
@@ -60599,11 +60922,11 @@ var require_core_blocks = __commonJS({
60599
60922
  }
60600
60923
  });
60601
60924
 
60602
- // ../system/dist/retired-settings-keys-BfAzWvPC.js
60603
- var require_retired_settings_keys_BfAzWvPC = __commonJS({
60604
- "../system/dist/retired-settings-keys-BfAzWvPC.js"(exports) {
60925
+ // ../system/dist/retired-settings-keys-DXZ2xe7C.js
60926
+ var require_retired_settings_keys_DXZ2xe7C = __commonJS({
60927
+ "../system/dist/retired-settings-keys-DXZ2xe7C.js"(exports) {
60605
60928
  "use strict";
60606
- var require_dist10 = require_dist_CDgIzo82();
60929
+ var require_dist10 = require_dist_CcvXUhHK();
60607
60930
  function settingsStoreIsAuthoritativeHere(env) {
60608
60931
  const raw = (env["CAMSTACK_ROLE"] ?? "").trim().toLowerCase();
60609
60932
  return raw === "" || raw === "hub";
@@ -62817,8 +63140,8 @@ var require_device_manager_addon = __commonJS({
62817
63140
  [Symbol.toStringTag]: { value: "Module" }
62818
63141
  });
62819
63142
  require_chunk_Cek0wNdY();
62820
- var require_dist10 = require_dist_CDgIzo82();
62821
- var require_retired_settings_keys = require_retired_settings_keys_BfAzWvPC();
63143
+ var require_dist10 = require_dist_CcvXUhHK();
63144
+ var require_retired_settings_keys = require_retired_settings_keys_DXZ2xe7C();
62822
63145
  var node_crypto = __require("crypto");
62823
63146
  var _camstack_types_node = require_node();
62824
63147
  var JOB_HISTORY = 20;
@@ -63281,10 +63604,17 @@ var require_device_manager_addon = __commonJS({
63281
63604
  const live = deps.ctx.kernel?.deviceRegistry?.getById(deviceId)?.type;
63282
63605
  return typeof live === "string" && live.length > 0 ? live : void 0;
63283
63606
  }
63284
- async function resolveDevicePresence(deps, row, deviceId) {
63607
+ async function resolveDevicePresence(deps, row, deviceId, ledgerNonEmpty) {
63285
63608
  if (deps.ctx.kernel?.deviceRegistry?.getById(deviceId)) return "present";
63286
63609
  if (row !== null) return "present";
63287
- return await deps.rows.count() > 0 ? "absent" : "unknown";
63610
+ return await ledgerNonEmpty() ? "absent" : "unknown";
63611
+ }
63612
+ function onceLedgerNonEmpty(deps) {
63613
+ let pending = null;
63614
+ return () => {
63615
+ if (pending === null) pending = deps.rows.count().then((n) => n > 0);
63616
+ return pending;
63617
+ };
63288
63618
  }
63289
63619
  function capAppliesToDeviceType(def, deviceType) {
63290
63620
  if (deviceType === void 0) return true;
@@ -63293,14 +63623,17 @@ var require_device_manager_addon = __commonJS({
63293
63623
  return declared.some((t) => t === deviceType);
63294
63624
  }
63295
63625
  async function getBindings(deps, input) {
63296
- const row = await deps.rows.get(input.deviceId);
63297
- return resolveBindingsForDevice(deps, input.deviceId, row);
63626
+ const [row, store] = await Promise.all([deps.rows.get(input.deviceId), readBindingsStore(deps)]);
63627
+ return resolveBindingsForDevice(deps, input.deviceId, row, {
63628
+ store,
63629
+ ledgerNonEmpty: onceLedgerNonEmpty(deps)
63630
+ });
63298
63631
  }
63299
- async function resolveBindingsForDevice(deps, deviceId, row) {
63632
+ async function resolveBindingsForDevice(deps, deviceId, row, pass) {
63300
63633
  const storeKey = String(deviceId);
63301
- const perDevice = (await readBindingsStore(deps)).deviceBindings[storeKey] ?? {};
63634
+ const perDevice = pass.store.deviceBindings[storeKey] ?? {};
63302
63635
  const deviceType = resolveDeviceType(deps, row, deviceId);
63303
- const presence = await resolveDevicePresence(deps, row, deviceId);
63636
+ const presence = await resolveDevicePresence(deps, row, deviceId, pass.ledgerNonEmpty);
63304
63637
  const entries = [];
63305
63638
  const seenCaps = /* @__PURE__ */ new Set();
63306
63639
  const resolveRemote = (capName) => deps.remoteNativeCaps.get(deviceId)?.get(capName) ?? resolveRemoteNativeCapFromRegistry(deps, capName, deviceId);
@@ -63400,13 +63733,17 @@ var require_device_manager_addon = __commonJS({
63400
63733
  }
63401
63734
  async function getBindingsBatch(deps, input) {
63402
63735
  const ids = [...new Set(input.deviceIds)];
63403
- const rows = await deps.rows.getMany(ids);
63736
+ const [rows, store] = await Promise.all([deps.rows.getMany(ids), readBindingsStore(deps)]);
63737
+ const pass = {
63738
+ store,
63739
+ ledgerNonEmpty: onceLedgerNonEmpty(deps)
63740
+ };
63404
63741
  const out = [];
63405
- for (const deviceId of ids) out.push(await resolveBindingsForDevice(deps, deviceId, rows.get(deviceId) ?? null));
63742
+ for (const deviceId of ids) out.push(await resolveBindingsForDevice(deps, deviceId, rows.get(deviceId) ?? null, pass));
63406
63743
  return out;
63407
63744
  }
63408
63745
  async function getAllBindings(deps) {
63409
- const fleet = await deps.rows.listAll();
63746
+ const [fleet, store] = await Promise.all([deps.rows.listAll(), readBindingsStore(deps)]);
63410
63747
  const rowById = /* @__PURE__ */ new Map();
63411
63748
  const ids = /* @__PURE__ */ new Set();
63412
63749
  for (const row of fleet) {
@@ -63419,8 +63756,12 @@ var require_device_manager_addon = __commonJS({
63419
63756
  deps.ctx.logger.warn("getAllBindings found no devices \u2014 warm boot will see nothing", { meta: { hasRegistry: deps.ctx.kernel?.deviceRegistry !== void 0 } });
63420
63757
  return [];
63421
63758
  }
63759
+ const pass = {
63760
+ store,
63761
+ ledgerNonEmpty: onceLedgerNonEmpty(deps)
63762
+ };
63422
63763
  const out = [];
63423
- for (const deviceId of [...ids].sort((a, b) => a - b)) out.push(await resolveBindingsForDevice(deps, deviceId, rowById.get(deviceId) ?? null));
63764
+ for (const deviceId of [...ids].sort((a, b) => a - b)) out.push(await resolveBindingsForDevice(deps, deviceId, rowById.get(deviceId) ?? null, pass));
63424
63765
  return out;
63425
63766
  }
63426
63767
  async function lookupPersistedStableId(deps, deviceId) {
@@ -63980,7 +64321,12 @@ var require_device_manager_addon = __commonJS({
63980
64321
  ...sourceInfoGetDevice !== void 0 ? { sourceInfo: sourceInfoGetDevice } : {}
63981
64322
  };
63982
64323
  }
63983
- async function projectChildren(pctx, parentDeviceId, ownerAddonId, childRows, liveChildren) {
64324
+ function persistedChildIds(childRows, liveChildren) {
64325
+ const live = /* @__PURE__ */ new Set();
64326
+ for (const device of liveChildren) live.add(device.id);
64327
+ return childRows.filter((row) => !live.has(row.meta.id)).map((row) => row.meta.id);
64328
+ }
64329
+ function projectChildren(pctx, parentDeviceId, ownerAddonId, childRows, liveChildren, configs) {
63984
64330
  const results = [];
63985
64331
  const seen = /* @__PURE__ */ new Set();
63986
64332
  const rowById = /* @__PURE__ */ new Map();
@@ -63996,9 +64342,9 @@ var require_device_manager_addon = __commonJS({
63996
64342
  const childStableId = m.stableId;
63997
64343
  const key = String(m.id);
63998
64344
  if (seen.has(key)) continue;
63999
- const persistedConfig = await pctx.settings.readDeviceStore(m.id);
64345
+ const persistedConfig = configs.get(m.id) ?? {};
64000
64346
  const metadata = row.metadata;
64001
- const sourceInfoChild = buildSourceInfoFromConfig(persistedConfig ?? {}, childStableId, ownerAddonId);
64347
+ const sourceInfoChild = buildSourceInfoFromConfig(persistedConfig, childStableId, ownerAddonId);
64002
64348
  results.push({
64003
64349
  id: m.id,
64004
64350
  stableId: childStableId,
@@ -64013,7 +64359,7 @@ var require_device_manager_addon = __commonJS({
64013
64359
  probed: pctx.host.resolveDeviceProbed(m.id),
64014
64360
  features: persistedFeatures(m.features),
64015
64361
  isCamera: false,
64016
- config: persistedConfig ?? {},
64362
+ config: persistedConfig,
64017
64363
  metadata,
64018
64364
  ...m.integrationId !== void 0 ? { integrationId: m.integrationId } : {},
64019
64365
  ...m.linkDeviceId !== void 0 ? { linkDeviceId: m.linkDeviceId } : {},
@@ -64040,7 +64386,8 @@ var require_device_manager_addon = __commonJS({
64040
64386
  }
64041
64387
  const childRows = await pctx.metaStore.rows.listByParent(parentDeviceId);
64042
64388
  const liveChildren = pctx.registry?.getChildren(parentDeviceId) ?? [];
64043
- return [...await projectChildren(pctx, parentDeviceId, ownerAddonId, childRows, liveChildren)];
64389
+ const configs = await readDeviceConfigs(pctx, persistedChildIds(childRows, liveChildren));
64390
+ return [...projectChildren(pctx, parentDeviceId, ownerAddonId, childRows, liveChildren, configs)];
64044
64391
  }
64045
64392
  async function getChildrenBatch(pctx, input) {
64046
64393
  const parentIds = [...new Set(input.parentDeviceIds)];
@@ -64068,11 +64415,14 @@ var require_device_manager_addon = __commonJS({
64068
64415
  if (bucket === void 0) liveByParent.set(parentId, [device]);
64069
64416
  else bucket.push(device);
64070
64417
  }
64418
+ const configIds = [];
64419
+ for (const parentId of owners.keys()) configIds.push(...persistedChildIds(rowsByParent.get(parentId) ?? [], liveByParent.get(parentId) ?? []));
64420
+ const configs = await readDeviceConfigs(pctx, configIds);
64071
64421
  for (const [parentId, ownerAddonId] of owners) {
64072
64422
  const childRows = rowsByParent.get(parentId) ?? [];
64073
64423
  const liveChildren = liveByParent.get(parentId) ?? [];
64074
64424
  if (childRows.length === 0 && liveChildren.length === 0) continue;
64075
- const projected = await projectChildren(pctx, parentId, ownerAddonId, childRows, liveChildren);
64425
+ const projected = projectChildren(pctx, parentId, ownerAddonId, childRows, liveChildren, configs);
64076
64426
  if (projected.length > 0) out[String(parentId)] = [...projected];
64077
64427
  }
64078
64428
  return out;
@@ -65114,18 +65464,20 @@ var require_device_manager_addon = __commonJS({
65114
65464
  }
65115
65465
  async function setWrapperActive(deps, input) {
65116
65466
  const storeKey = String(input.deviceId);
65117
- const store = await readBindingsStore(deps.bindingsDeps);
65118
- const perDevice = { ...store.deviceBindings[storeKey] };
65119
- if (input.active) perDevice[input.capName] = { wrapperAddonId: input.wrapperAddonId };
65120
- else perDevice[input.capName] = { wrapperAddonId: null };
65121
- const nextDeviceBindings = Object.keys(perDevice).length > 0 ? {
65122
- ...store.deviceBindings,
65123
- [storeKey]: perDevice
65124
- } : (() => {
65125
- const { [storeKey]: _drop, ...rest } = store.deviceBindings;
65126
- return rest;
65127
- })();
65128
- await writeBindingsStore(deps.bindingsDeps, { deviceBindings: nextDeviceBindings });
65467
+ await deps.bindingsDeps.withAddonStoreWriteLock(async () => {
65468
+ const store = await readBindingsStore(deps.bindingsDeps);
65469
+ const perDevice = { ...store.deviceBindings[storeKey] };
65470
+ if (input.active) perDevice[input.capName] = { wrapperAddonId: input.wrapperAddonId };
65471
+ else perDevice[input.capName] = { wrapperAddonId: null };
65472
+ const nextDeviceBindings = Object.keys(perDevice).length > 0 ? {
65473
+ ...store.deviceBindings,
65474
+ [storeKey]: perDevice
65475
+ } : (() => {
65476
+ const { [storeKey]: _drop, ...rest } = store.deviceBindings;
65477
+ return rest;
65478
+ })();
65479
+ await writeBindingsStore(deps.bindingsDeps, { deviceBindings: nextDeviceBindings });
65480
+ });
65129
65481
  deps.ctx.eventBus.emit({
65130
65482
  id: (0, node_crypto.randomUUID)(),
65131
65483
  timestamp: /* @__PURE__ */ new Date(),
@@ -65404,12 +65756,13 @@ var require_device_manager_addon = __commonJS({
65404
65756
  });
65405
65757
  await pctx.settings.clearDeviceStore(deviceId);
65406
65758
  await pctx.settings.clearDeviceRuntimeState(deviceId);
65407
- const bindingsStore = await readBindingsStore(pctx.bindingsDeps);
65408
65759
  const bindingKey = String(deviceId);
65409
- if (bindingsStore.deviceBindings[bindingKey]) {
65760
+ await pctx.bindingsDeps.withAddonStoreWriteLock(async () => {
65761
+ const bindingsStore = await readBindingsStore(pctx.bindingsDeps);
65762
+ if (!bindingsStore.deviceBindings[bindingKey]) return;
65410
65763
  const { [bindingKey]: _removedBindings, ...restBindings } = bindingsStore.deviceBindings;
65411
65764
  await writeBindingsStore(pctx.bindingsDeps, { deviceBindings: restBindings });
65412
- }
65765
+ });
65413
65766
  pctx.host.remoteNativeCaps.delete(deviceId);
65414
65767
  pctx.host.capabilityRegistry?.unregisterAllNativeForDevice(deviceId);
65415
65768
  pctx.metaStore.idToAddonId.delete(deviceId);
@@ -65751,7 +66104,9 @@ var require_device_manager_addon = __commonJS({
65751
66104
  ...def,
65752
66105
  unit: require_dist10.normalizeUnit(def.unit) ?? def.unit
65753
66106
  } : def]));
65754
- await pctx.settings.writeAddonStore({ roleDisplayDefaults: normalized });
66107
+ await pctx.bindingsDeps.withAddonStoreWriteLock(async () => {
66108
+ await pctx.settings.writeAddonStore({ roleDisplayDefaults: normalized });
66109
+ });
65755
66110
  }
65756
66111
  async function applyInitialMeta(pctx, input) {
65757
66112
  const { deviceId, name, location, type, integrationId, linkDeviceId, role } = input;
@@ -65894,16 +66249,21 @@ var require_device_manager_addon = __commonJS({
65894
66249
  async function addLocation(pctx, input) {
65895
66250
  const trimmed = input.name.trim();
65896
66251
  if (trimmed.length === 0) throw new Error("[device-manager] addLocation: name must be non-empty");
65897
- const current = (await pctx.metaStore.readStore()).locations ?? [];
65898
- if (current.some((l) => l.toLowerCase() === trimmed.toLowerCase())) return;
65899
- await pctx.settings.writeAddonStore({ locations: [...current, trimmed] });
66252
+ await pctx.bindingsDeps.withAddonStoreWriteLock(async () => {
66253
+ const current = (await pctx.metaStore.readStore()).locations ?? [];
66254
+ if (current.some((l) => l.toLowerCase() === trimmed.toLowerCase())) return;
66255
+ await pctx.settings.writeAddonStore({ locations: [...current, trimmed] });
66256
+ });
65900
66257
  }
65901
66258
  async function removeLocation(pctx, input) {
65902
66259
  const trimmed = input.name.trim();
65903
66260
  if (trimmed.length === 0) return;
65904
- const current = (await pctx.metaStore.readStore()).locations ?? [];
65905
- const remaining = current.filter((l) => l.toLowerCase() !== trimmed.toLowerCase());
65906
- if (remaining.length !== current.length) await pctx.settings.writeAddonStore({ locations: remaining });
66261
+ await pctx.bindingsDeps.withAddonStoreWriteLock(async () => {
66262
+ const current = (await pctx.metaStore.readStore()).locations ?? [];
66263
+ const remaining = current.filter((l) => l.toLowerCase() !== trimmed.toLowerCase());
66264
+ if (remaining.length === current.length) return;
66265
+ await pctx.settings.writeAddonStore({ locations: remaining });
66266
+ });
65907
66267
  if (input.cascade !== true) return;
65908
66268
  const cleared = await pctx.metaStore.withMetaWriteLock(async () => {
65909
66269
  const out = [];
@@ -65944,23 +66304,40 @@ var require_device_manager_addon = __commonJS({
65944
66304
  function isRoleDisplayDefaults(value) {
65945
66305
  return value !== null && typeof value === "object" && !Array.isArray(value);
65946
66306
  }
66307
+ function createWriteLock() {
66308
+ let chain = Promise.resolve();
66309
+ return async (fn) => {
66310
+ const previous = chain;
66311
+ let release = () => {
66312
+ };
66313
+ chain = new Promise((resolve) => {
66314
+ release = resolve;
66315
+ });
66316
+ try {
66317
+ await previous.catch(() => {
66318
+ });
66319
+ return await fn();
66320
+ } finally {
66321
+ release();
66322
+ }
66323
+ };
66324
+ }
65947
66325
  var DeviceMetaStore = class {
65948
66326
  settings;
65949
66327
  registry;
65950
66328
  rows;
66329
+ withAddonStoreWriteLock;
65951
66330
  /** Synchronous ownership cache, keyed by NUMERIC deviceId → owning addonId.
65952
66331
  * The persisted row store is authoritative but reads are async; hub-side
65953
66332
  * callers (e.g. `CapabilityRegistry.getNativeProvider` fallback) need
65954
66333
  * ownership without awaiting. Kept in sync with every register/remove and
65955
66334
  * warmed from persistence on boot. */
65956
66335
  idToAddonId = /* @__PURE__ */ new Map();
65957
- /** Serialises every read-modify-write of a device row through one promise
65958
- * chain (see `withMetaWriteLock`). Per-instance state. */
65959
- metaWriteChain = Promise.resolve();
65960
- constructor(settings, registry, rows) {
66336
+ constructor(settings, registry, rows, withAddonStoreWriteLock = createWriteLock()) {
65961
66337
  this.settings = settings;
65962
66338
  this.registry = registry;
65963
66339
  this.rows = rows;
66340
+ this.withAddonStoreWriteLock = withAddonStoreWriteLock;
65964
66341
  }
65965
66342
  /** The read currently in flight, or null. Never a settled value — see
65966
66343
  * {@link readStore}. */
@@ -65991,22 +66368,7 @@ var require_device_manager_addon = __commonJS({
65991
66368
  this.inFlightRead = read;
65992
66369
  return read;
65993
66370
  };
65994
- withMetaWriteLock = async (fn) => {
65995
- const previous = this.metaWriteChain;
65996
- let release = () => {
65997
- };
65998
- const next = new Promise((resolve) => {
65999
- release = resolve;
66000
- });
66001
- this.metaWriteChain = next;
66002
- try {
66003
- await previous.catch(() => {
66004
- });
66005
- return await fn();
66006
- } finally {
66007
- release();
66008
- }
66009
- };
66371
+ withMetaWriteLock = createWriteLock();
66010
66372
  /** The whole persisted row for one device, or `null`. */
66011
66373
  getRow = async (deviceId) => this.rows.get(deviceId);
66012
66374
  /**
@@ -66040,11 +66402,24 @@ var require_device_manager_addon = __commonJS({
66040
66402
  ids.delete(parentId);
66041
66403
  return [...ids];
66042
66404
  };
66043
- allocateNextDeviceId = async () => {
66405
+ /**
66406
+ * Mint the next numeric device id.
66407
+ *
66408
+ * A read-modify-write of `nextDeviceId`, and it must hold the addon-store
66409
+ * lock for the whole of it. Serialising the WRITES is not enough and never
66410
+ * was: two callers that both read `N` both write `N + 1` and both return
66411
+ * `N`, so two devices receive the same id. (`writeAddonStore` is itself
66412
+ * read-modify-write over the addon's whole key range, so an unlocked bump
66413
+ * can also be reverted wholesale by a concurrent `setWrapperActive`.)
66414
+ *
66415
+ * Callers hold {@link withMetaWriteLock} — this is the one nesting, and it
66416
+ * only ever goes meta ⊃ addon-store.
66417
+ */
66418
+ allocateNextDeviceId = async () => this.withAddonStoreWriteLock(async () => {
66044
66419
  const current = (await this.readStore()).nextDeviceId ?? 1;
66045
66420
  await this.settings.writeAddonStore({ nextDeviceId: current + 1 });
66046
66421
  return current;
66047
- };
66422
+ });
66048
66423
  };
66049
66424
  var CENSUS_STACK_FRAMES = 3;
66050
66425
  function siteFromStack(stack) {
@@ -67238,6 +67613,17 @@ var require_device_manager_addon = __commonJS({
67238
67613
  * it through {@link bindingsDeps} or the `ProviderContext`.
67239
67614
  */
67240
67615
  deviceRows = null;
67616
+ /**
67617
+ * The ONE lock ordering every read-modify-write of this addon's
67618
+ * `addon-settings` key range (`deviceBindings`, `locations`, `nextDeviceId`,
67619
+ * `roleDisplayDefaults`).
67620
+ *
67621
+ * It lives on the addon rather than on `DeviceMetaStore` because the writers
67622
+ * do not all go through that class — `setWrapperActive` and `removeDevice`'s
67623
+ * bindings purge reach the store through `BindingsDeps` — and two locks over
67624
+ * one key range is the same defect one level up. Handed to both.
67625
+ */
67626
+ addonStoreWriteLock = createWriteLock();
67241
67627
  /** Build the dependency context the extracted binding resolvers consume. */
67242
67628
  get bindingsDeps() {
67243
67629
  const rows = this.deviceRows;
@@ -67246,7 +67632,8 @@ var require_device_manager_addon = __commonJS({
67246
67632
  ctx: this.ctx,
67247
67633
  capabilityRegistry: this.capabilityRegistry,
67248
67634
  remoteNativeCaps: this.remoteNativeCaps,
67249
- rows
67635
+ rows,
67636
+ withAddonStoreWriteLock: this.addonStoreWriteLock
67250
67637
  };
67251
67638
  }
67252
67639
  async getBindings(input) {
@@ -67315,7 +67702,7 @@ var require_device_manager_addon = __commonJS({
67315
67702
  } catch (err) {
67316
67703
  this.ctx.logger.warn("retired-row purge failed", { meta: { error: require_dist10.errMsg(err) } });
67317
67704
  }
67318
- const metaStore = new DeviceMetaStore(settings, registry, deviceRows);
67705
+ const metaStore = new DeviceMetaStore(settings, registry, deviceRows, this.addonStoreWriteLock);
67319
67706
  this.stateMirrorImpl = new DeviceStateMirror(this.ctx);
67320
67707
  const stateMirror = this.stateMirrorImpl;
67321
67708
  const resolvePersistedById = metaStore.resolvePersistedById;
@@ -67567,7 +67954,7 @@ var require_hub_forwarder = __commonJS({
67567
67954
  [Symbol.toStringTag]: { value: "Module" }
67568
67955
  });
67569
67956
  require_chunk_Cek0wNdY();
67570
- var require_dist10 = require_dist_CDgIzo82();
67957
+ var require_dist10 = require_dist_CcvXUhHK();
67571
67958
  var require_formatter = require_formatter_DqAKDlvN();
67572
67959
  var DEFAULT_OUTBOUND_BUFFER_SIZE = 500;
67573
67960
  var HubForwarderDestination = class {
@@ -67704,7 +68091,7 @@ var require_liveness_monitor_addon = __commonJS({
67704
68091
  "use strict";
67705
68092
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
67706
68093
  require_chunk_Cek0wNdY();
67707
- var require_dist10 = require_dist_CDgIzo82();
68094
+ var require_dist10 = require_dist_CcvXUhHK();
67708
68095
  var NO_DEVICES = "liveness:no-devices";
67709
68096
  var ALL_OFFLINE = "liveness:all-devices-offline";
67710
68097
  var NO_FOOTAGE_PREFIX = "liveness:no-footage:";
@@ -67894,7 +68281,7 @@ var require_local_auth_addon = __commonJS({
67894
68281
  [Symbol.toStringTag]: { value: "Module" }
67895
68282
  });
67896
68283
  var require_chunk = require_chunk_Cek0wNdY();
67897
- var require_dist10 = require_dist_CDgIzo82();
68284
+ var require_dist10 = require_dist_CcvXUhHK();
67898
68285
  var node_crypto = __require("crypto");
67899
68286
  node_crypto = require_chunk.__toESM(node_crypto);
67900
68287
  var crypto$1 = __require("crypto");
@@ -75707,7 +76094,7 @@ var require_loki_logging = __commonJS({
75707
76094
  [Symbol.toStringTag]: { value: "Module" }
75708
76095
  });
75709
76096
  require_chunk_Cek0wNdY();
75710
- var require_dist10 = require_dist_CDgIzo82();
76097
+ var require_dist10 = require_dist_CcvXUhHK();
75711
76098
  function sanitizeLabelName(raw) {
75712
76099
  const replaced = raw.replaceAll(/[^a-zA-Z0-9_]/g, "_");
75713
76100
  return /^[a-zA-Z_]/.test(replaced) ? replaced : `_${replaced}`;
@@ -76272,7 +76659,7 @@ var require_native_metrics_addon = __commonJS({
76272
76659
  [Symbol.toStringTag]: { value: "Module" }
76273
76660
  });
76274
76661
  var require_chunk = require_chunk_Cek0wNdY();
76275
- var require_dist10 = require_dist_CDgIzo82();
76662
+ var require_dist10 = require_dist_CcvXUhHK();
76276
76663
  var node_fs_promises = __require("fs/promises");
76277
76664
  var node_child_process = __require("child_process");
76278
76665
  var node_util = __require("util");
@@ -78894,7 +79281,7 @@ var require_filesystem_storage_addon = __commonJS({
78894
79281
  [Symbol.toStringTag]: { value: "Module" }
78895
79282
  });
78896
79283
  var require_chunk = require_chunk_Cek0wNdY();
78897
- var require_dist10 = require_dist_CDgIzo82();
79284
+ var require_dist10 = require_dist_CcvXUhHK();
78898
79285
  var node_crypto = __require("crypto");
78899
79286
  var node_fs_promises = __require("fs/promises");
78900
79287
  var node_path = __require("path");
@@ -80010,8 +80397,8 @@ var require_sqlite_settings_addon = __commonJS({
80010
80397
  [Symbol.toStringTag]: { value: "Module" }
80011
80398
  });
80012
80399
  var require_chunk = require_chunk_Cek0wNdY();
80013
- var require_dist10 = require_dist_CDgIzo82();
80014
- var require_retired_settings_keys = require_retired_settings_keys_BfAzWvPC();
80400
+ var require_dist10 = require_dist_CcvXUhHK();
80401
+ var require_retired_settings_keys = require_retired_settings_keys_DXZ2xe7C();
80015
80402
  var node_crypto = __require("crypto");
80016
80403
  var node_fs = __require("fs");
80017
80404
  var node_module = __require("module");
@@ -80342,11 +80729,16 @@ var require_sqlite_settings_addon = __commonJS({
80342
80729
  const resolve = (field) => {
80343
80730
  const expr = fieldExprFor(field, shape);
80344
80731
  if (expr === null && mode === "mutate") throw new UnsafeFilterError(`filter refers to "${field}", which this collection cannot express \u2014 refusing to run a bulk mutation with a dropped predicate`);
80732
+ if (expr === null && mode === "measure") throw new UnsafeFilterError(`filter refers to "${field}", which this collection cannot express \u2014 refusing to answer with a number counted over a different question`);
80345
80733
  return expr;
80346
80734
  };
80347
80735
  for (const [field, value] of Object.entries(filter?.where ?? {})) {
80348
80736
  const expr = resolve(field);
80349
80737
  if (expr === null) continue;
80738
+ if (value === null) {
80739
+ clauses.push(`${expr} IS NULL`);
80740
+ continue;
80741
+ }
80350
80742
  clauses.push(`${expr} = ?`);
80351
80743
  params.push(serialize2(value));
80352
80744
  }
@@ -80369,6 +80761,10 @@ var require_sqlite_settings_addon = __commonJS({
80369
80761
  for (const [field, value] of Object.entries(filter?.whereNot ?? {})) {
80370
80762
  const expr = resolve(field);
80371
80763
  if (expr === null) continue;
80764
+ if (value === null) {
80765
+ clauses.push(`${expr} IS NOT NULL`);
80766
+ continue;
80767
+ }
80372
80768
  clauses.push(`(${expr} IS NULL OR ${expr} != ?)`);
80373
80769
  params.push(serialize2(value));
80374
80770
  }
@@ -80881,13 +81277,17 @@ var require_sqlite_settings_addon = __commonJS({
80881
81277
  * (visibility, kind, device, time window, expiry) — so `total` counted rows
80882
81278
  * the page could never show, including other users'.
80883
81279
  *
80884
- * `select` mode, deliberately: `count` must be forgiving in exactly the way
80885
- * `query` is, or the two disagree again for a new reason.
81280
+ * `measure` mode. `count` compiles the same predicates `query` does — the
81281
+ * two must never disagree about WHICH rows they are talking about — but it
81282
+ * refuses a predicate it cannot express rather than skipping it. `query`
81283
+ * hands back rows and a caller can see the filter did not bite; a count
81284
+ * hands back a number, and the whole collection and the intended subset are
81285
+ * the same shape.
80886
81286
  */
80887
81287
  async count({ namespace, collection, filter }) {
80888
81288
  const scoped = this.scopedName(namespace, collection);
80889
81289
  const decl = this.requireDeclared(scoped);
80890
- const { whereSql, params } = compileFilter$1(filter, this.shapeOf(decl), "select", (v) => this.serializeColumnValue(v));
81290
+ const { whereSql, params } = compileFilter$1(filter, this.shapeOf(decl), "measure", (v) => this.serializeColumnValue(v));
80891
81291
  const sql = `SELECT COUNT(*) AS cnt FROM "${scoped}"${whereSql}`;
80892
81292
  return this.measured({
80893
81293
  op: "count",
@@ -80905,8 +81305,10 @@ var require_sqlite_settings_addon = __commonJS({
80905
81305
  * projection — an unresolvable field THROWS rather than being dropped, because
80906
81306
  * a missing aggregate comes back as a number that looks real.
80907
81307
  *
80908
- * `select` mode on the filter, so this agrees with `query` and `count` about
80909
- * which rows it is talking about.
81308
+ * `measure` mode on the filter, so this agrees with `query` and `count`
81309
+ * about which rows it is talking about — and, since 2026-08-30, refuses an
81310
+ * unresolvable PREDICATE for the same reason it already refused an
81311
+ * unresolvable FIELD. Both come back as a number that looks real.
80910
81312
  */
80911
81313
  async aggregate({ namespace, collection, fields, filter }) {
80912
81314
  const scoped = this.scopedName(namespace, collection);
@@ -80918,7 +81320,7 @@ var require_sqlite_settings_addon = __commonJS({
80918
81320
  if (col === null) throw new UnsafeFilterError(`aggregate cannot read "${f.field}" on "${scoped}" \u2014 it is not a column of this collection, and answering without it would return a number that looks real`);
80919
81321
  selects.push(`${f.op.toUpperCase()}(${col}) AS "a${i}"`);
80920
81322
  });
80921
- const { whereSql, params } = compileFilter$1(filter, shape, "select", (v) => this.serializeColumnValue(v));
81323
+ const { whereSql, params } = compileFilter$1(filter, shape, "measure", (v) => this.serializeColumnValue(v));
80922
81324
  const sql = `SELECT ${selects.join(", ")} FROM "${scoped}"${whereSql}`;
80923
81325
  const row = this.measured({
80924
81326
  op: "aggregate",
@@ -80942,7 +81344,7 @@ var require_sqlite_settings_addon = __commonJS({
80942
81344
  const shape = this.shapeOf(decl);
80943
81345
  const col = fieldExprFor(field, shape);
80944
81346
  if (col === null) return [];
80945
- const { whereSql: where, params } = compileFilter$1(filter, shape, "select", (v) => this.serializeColumnValue(v));
81347
+ const { whereSql: where, params } = compileFilter$1(filter, shape, "measure", (v) => this.serializeColumnValue(v));
80946
81348
  const sql = `SELECT ${`CAST((${col} - ?) / ? AS INTEGER)`} AS bucket, COUNT(*) AS count FROM "${scoped}"${where} GROUP BY bucket ORDER BY bucket`;
80947
81349
  return this.measured({
80948
81350
  op: "histogram",
@@ -81223,8 +81625,10 @@ var require_sqlite_settings_addon = __commonJS({
81223
81625
  * connection whose `sqlite_stat1` visibility and temp schema match.
81224
81626
  *
81225
81627
  * `EXPLAIN QUERY PLAN` prepares and plans; it does not execute the statement,
81226
- * so it costs no page reads of its own. It is still called only from the
81227
- * slow-call path, once per shape per window.
81628
+ * so it costs no page reads of its own. In production it is called only from
81629
+ * the slow-call path, once per shape per window; it is public so a guard can
81630
+ * assert that a declared index is the one the planner actually picks — "we
81631
+ * added an index" and "the query uses it" are different claims.
81228
81632
  *
81229
81633
  * Never throws. A plan that cannot be taken (a statement the engine will no
81230
81634
  * longer prepare, a closed handle mid-shutdown) is a missing ANSWER, not a
@@ -81773,7 +82177,88 @@ var require_sqlite_settings_addon = __commonJS({
81773
82177
  return {
81774
82178
  matches,
81775
82179
  scanned: rows.length,
81776
- truncated: k < params.topK && rows.length >= k
82180
+ truncated: k < params.topK && rows.length >= k,
82181
+ effectiveTopK: k
82182
+ };
82183
+ }
82184
+ /**
82185
+ * Ids read back WITH their vectors.
82186
+ *
82187
+ * `vec0` returns a vector column as the packed Float32 blob it stores, which
82188
+ * is byte-for-byte what `upsert` was given — so the round trip is a base64
82189
+ * encode and nothing else. No re-normalisation, no float re-ordering: a
82190
+ * gallery loaded through here ranks identically to one loaded from the JSON
82191
+ * column it replaced.
82192
+ */
82193
+ async fetchByIds(index, ids) {
82194
+ this.specOf(index);
82195
+ if (ids.length === 0) return [];
82196
+ const placeholders = ids.map(() => "?").join(",");
82197
+ const rows = this.measured({
82198
+ op: "vectorFetch",
82199
+ collection: tableFor(index)
82200
+ }, () => this.db.prepare(`SELECT id, embedding, deviceId, timestamp, className, modelId, extra
82201
+ FROM ${tableFor(index)} WHERE id IN (${placeholders})`).all(...ids));
82202
+ const out = [];
82203
+ for (const raw of rows) {
82204
+ if (typeof raw !== "object" || raw === null) continue;
82205
+ const row = raw;
82206
+ const id = asText(row["id"]);
82207
+ if (id === null) continue;
82208
+ const blob = row["embedding"];
82209
+ if (!Buffer.isBuffer(blob)) {
82210
+ this.logger.warn("sqlite-vec: row has no readable vector \u2014 skipped", { meta: {
82211
+ index,
82212
+ id
82213
+ } });
82214
+ continue;
82215
+ }
82216
+ out.push({
82217
+ id,
82218
+ vector: blob.toString("base64"),
82219
+ metadata: rebuild(row)
82220
+ });
82221
+ }
82222
+ return out;
82223
+ }
82224
+ /**
82225
+ * One page of the whole index, unranked.
82226
+ *
82227
+ * `LIMIT ? OFFSET ?` over the `vec0` table with NO `MATCH` clause: a plain
82228
+ * scan, so the extension's KNN `k` ceiling ({@link VEC_KNN_MAX_K}) does not
82229
+ * apply and no distance is computed at all. Ordered by `id` so a cursor means
82230
+ * the same thing across calls — `rowid` order is not stable under the
82231
+ * DELETE-then-INSERT upsert this class performs.
82232
+ *
82233
+ * The cursor is an OFFSET, so rows deleted behind the walk shift the window.
82234
+ * That is acceptable and deliberate for the one caller: a reconcile that
82235
+ * misses a row this pass sees it next pass, and the alternative — a keyset
82236
+ * cursor on a virtual table whose ordering the extension owns — buys nothing
82237
+ * for a walk that is idempotent by construction.
82238
+ */
82239
+ async scan(index, cursor, limit) {
82240
+ this.specOf(index);
82241
+ const offset = Math.max(0, Math.floor(cursor));
82242
+ const take = Math.max(1, Math.floor(limit));
82243
+ const rows = this.measured({
82244
+ op: "vectorScan",
82245
+ collection: tableFor(index)
82246
+ }, () => this.db.prepare(`SELECT id, deviceId, timestamp, className, modelId, extra
82247
+ FROM ${tableFor(index)} ORDER BY id LIMIT ? OFFSET ?`).all(BigInt(take), BigInt(offset)));
82248
+ const items = [];
82249
+ for (const raw of rows) {
82250
+ if (typeof raw !== "object" || raw === null) continue;
82251
+ const row = raw;
82252
+ const id = asText(row["id"]);
82253
+ if (id === null) continue;
82254
+ items.push({
82255
+ id,
82256
+ metadata: rebuild(row)
82257
+ });
82258
+ }
82259
+ return {
82260
+ items,
82261
+ nextCursor: rows.length < take ? null : offset + rows.length
81777
82262
  };
81778
82263
  }
81779
82264
  async getByIds(index, ids) {
@@ -82111,6 +82596,8 @@ var require_sqlite_settings_addon = __commonJS({
82111
82596
  ...input.filter !== void 0 ? { filter: input.filter } : {}
82112
82597
  }),
82113
82598
  getByIds: async (input) => ({ items: await vectorIndex.getByIds(input.index, input.ids) }),
82599
+ fetchByIds: async (input) => ({ items: await vectorIndex.fetchByIds(input.index, input.ids) }),
82600
+ scan: async (input) => vectorIndex.scan(input.index, input.cursor, input.limit),
82114
82601
  deleteByIds: async (input) => ({ deleted: await vectorIndex.deleteByIds(input.index, input.ids) }),
82115
82602
  deleteByFilter: async (input) => ({ deleted: await vectorIndex.deleteByFilter(input.index, input.filter) }),
82116
82603
  stats: async (input) => vectorIndex.stats(input.index)
@@ -82290,7 +82777,7 @@ var require_storage_orchestrator_addon = __commonJS({
82290
82777
  [Symbol.toStringTag]: { value: "Module" }
82291
82778
  });
82292
82779
  var require_chunk = require_chunk_Cek0wNdY();
82293
- var require_dist10 = require_dist_CDgIzo82();
82780
+ var require_dist10 = require_dist_CcvXUhHK();
82294
82781
  var node_crypto = __require("crypto");
82295
82782
  var node_fs_promises = __require("fs/promises");
82296
82783
  node_fs_promises = require_chunk.__toESM(node_fs_promises);
@@ -82496,6 +82983,10 @@ var require_storage_orchestrator_addon = __commonJS({
82496
82983
  "recorder",
82497
82984
  "pipeline"
82498
82985
  ];
82986
+ function describeUnstamped(lane) {
82987
+ if (!lane.present) return "0";
82988
+ return lane.rows === null ? "an unknown number of" : lane.rows.toString();
82989
+ }
82499
82990
  var StorageMigrationCoordinator = class {
82500
82991
  deps;
82501
82992
  active = null;
@@ -82526,7 +83017,8 @@ var require_storage_orchestrator_addon = __commonJS({
82526
83017
  toLocationId: target.id,
82527
83018
  moverJobId: null,
82528
83019
  state: null,
82529
- error: null
83020
+ error: null,
83021
+ progress: null
82530
83022
  });
82531
83023
  if (BLOCKING_ONLY_CLASSES.includes(storageClass)) findings.push({
82532
83024
  code: "blockingOnly",
@@ -82538,12 +83030,21 @@ var require_storage_orchestrator_addon = __commonJS({
82538
83030
  if (moves.length === 0) throw new Error("select at least one storage class");
82539
83031
  if (moves.some((move) => move.storageClass === "eventMedia")) {
82540
83032
  const unstamped = await this.deps.participants.analytics.countUnstamped();
82541
- if (unstamped.total > 0) {
82542
- if (mode === "nonBlocking") throw new Error(`${unstamped.total.toString()} event-media row(s) still carry no locationId (${unstamped.media.toString()} media, ${unstamped.retrainFrames.toString()} retrain frames). A non-blocking cutover would silently orphan them. Run the seal first: pipelineAnalytics.relocateMedia({ mode: "seal", toLocationId: "${this.deps.locations.getDefaultLocation("eventMedia")?.id ?? "eventMedia"}" }).`);
83033
+ if (unstamped === null) {
83034
+ if (mode === "nonBlocking") throw new Error("could not determine whether any event-media row still carries no locationId. A non-blocking cutover repoints the default and would silently orphan every such row, so an unmeasured collection is refused exactly like a non-empty one. Retry, or run the blocking mode, which stamps rows as it moves them.");
83035
+ findings.push({
83036
+ code: "unstampedEventMediaRows",
83037
+ storageClass: "eventMedia",
83038
+ message: "the count of event-media rows carrying no locationId could not be taken \u2014 treat it as unknown, not as zero. This blocking migration stamps them as it moves them, so it is safe regardless; a non-blocking one would be refused."
83039
+ });
83040
+ } else if (unstamped.anyPresent) {
83041
+ const scale = unstamped.total === null ? "an unknown number of" : unstamped.total.toString();
83042
+ const perLane = `${describeUnstamped(unstamped.media)} media, ${describeUnstamped(unstamped.retrainFrames)} retrain frames`;
83043
+ if (mode === "nonBlocking") throw new Error(`${scale} event-media row(s) still carry no locationId (${perLane}). A non-blocking cutover would silently orphan them. Run the seal first: pipelineAnalytics.relocateMedia({ mode: "seal", toLocationId: "${this.deps.locations.getDefaultLocation("eventMedia")?.id ?? "eventMedia"}" }).`);
82543
83044
  findings.push({
82544
83045
  code: "unstampedEventMediaRows",
82545
83046
  storageClass: "eventMedia",
82546
- message: `${unstamped.total.toString()} event-media row(s) carry no locationId. This blocking migration stamps them as it moves them, but a non-blocking one would be refused until a seal pass drives the count to zero.`
83047
+ message: `${scale} event-media row(s) carry no locationId (${perLane}). This blocking migration stamps them as it moves them, but a non-blocking one would be refused until a seal pass drives the count to zero.`
82547
83048
  });
82548
83049
  }
82549
83050
  }
@@ -82624,7 +83125,8 @@ var require_storage_orchestrator_addon = __commonJS({
82624
83125
  ...move,
82625
83126
  moverJobId: null,
82626
83127
  state: null,
82627
- error: null
83128
+ error: null,
83129
+ progress: null
82628
83130
  })),
82629
83131
  pauseLeaseId: null,
82630
83132
  pausedParticipants: [],
@@ -82658,6 +83160,178 @@ var require_storage_orchestrator_addon = __commonJS({
82658
83160
  await Promise.all(job.moves.filter((move) => move.moverJobId !== null).map((move) => this.cancelMove(move)));
82659
83161
  return true;
82660
83162
  }
83163
+ /**
83164
+ * Every mover running right now, in both lanes — including the ones no
83165
+ * migration armed.
83166
+ *
83167
+ * `status` already carries a migration's own progress (the coordinator folds
83168
+ * it onto each move from the poll it is already doing). This exists for the
83169
+ * other half: `recording.relocateFootage` and `pipelineAnalytics.relocateMedia`
83170
+ * are operator-callable, and until {@link drain} existed that was the only way
83171
+ * to run a drain at all. Such a mover has no job to fold into, so without this
83172
+ * read a five-hour operation is invisible in the UI.
83173
+ *
83174
+ * `migrationJobId` is best-effort by construction: the coordinator keeps ONE
83175
+ * durable job, so a mover armed by an older, since-overwritten migration
83176
+ * reports `null`. That is the honest answer — nothing here can still claim it.
83177
+ */
83178
+ async movers() {
83179
+ const job = await this.status();
83180
+ const owned = /* @__PURE__ */ new Map();
83181
+ for (const move of job?.moves ?? []) if (move.moverJobId !== null) owned.set(move.moverJobId, job?.jobId ?? "");
83182
+ const [footage, media] = await Promise.all([this.deps.participants.recorder.listMovers(), this.deps.participants.analytics.listMovers()]);
83183
+ const observedAt = this.deps.now();
83184
+ const label = (lane, jobs) => jobs.map((mover) => ({
83185
+ lane,
83186
+ job: mover,
83187
+ migrationJobId: owned.get(mover.jobId) ?? null,
83188
+ observedAt
83189
+ }));
83190
+ return [...label("footage", footage), ...label("media", media)];
83191
+ }
83192
+ /**
83193
+ * What every class's source STILL holds — the census behind a "drain
83194
+ * remaining" action.
83195
+ *
83196
+ * A class appears here only when something is (or might be) left on a
83197
+ * location that is not its default. An empty result therefore means exactly
83198
+ * "there is nothing to drain", which is what lets the UI offer the action
83199
+ * only when it is true, and what lets {@link drain} refuse rather than start
83200
+ * a job that would move nothing and report `done` — the failure mode D295
83201
+ * exists to end.
83202
+ *
83203
+ * `items: null` is "the archive could not be asked" and is still listed. A
83204
+ * residue nobody could measure is the case an operator most needs to see;
83205
+ * dropping it because the read failed would be the quiet success again.
83206
+ */
83207
+ async residue() {
83208
+ const out = [];
83209
+ for (const storageClass of STORAGE_CLASSES) {
83210
+ if (!MOVER_CLASSES.includes(storageClass)) continue;
83211
+ const target = this.deps.locations.getDefaultLocation(storageClass);
83212
+ if (!target) continue;
83213
+ if (laneOf(storageClass) === "media") {
83214
+ const count = await unanswerable(this.deps.participants.analytics.residue({
83215
+ toLocationId: target.id,
83216
+ mode: storageClass === "galleryMedia" ? "gallery" : "move"
83217
+ }));
83218
+ if (count !== null && count.rows === 0) continue;
83219
+ out.push({
83220
+ storageClass,
83221
+ fromLocationId: "*",
83222
+ toLocationId: target.id,
83223
+ items: count?.rows ?? null,
83224
+ bytes: null
83225
+ });
83226
+ continue;
83227
+ }
83228
+ for (const source of this.deps.locations.listLocations({ type: storageClass })) {
83229
+ if (source.id === target.id) continue;
83230
+ const census = await unanswerable(this.deps.participants.recorder.residue({
83231
+ fromLocationId: source.id,
83232
+ footageClass: storageClass === "recordingsLow" ? "recordingsLow" : "recordings"
83233
+ }));
83234
+ if (census !== null && census.segments === 0) continue;
83235
+ out.push({
83236
+ storageClass,
83237
+ fromLocationId: source.id,
83238
+ toLocationId: target.id,
83239
+ items: census?.segments ?? null,
83240
+ bytes: census?.bytes ?? null
83241
+ });
83242
+ }
83243
+ }
83244
+ return out;
83245
+ }
83246
+ /**
83247
+ * Run the DRAIN half alone, against classes whose default has already moved.
83248
+ *
83249
+ * ## Why this is a second verb rather than a looser `start`
83250
+ *
83251
+ * `start` refuses a destination that is already the class's default
83252
+ * (`"recordingsLow:ssd" is already the "recordingsLow" default`). That refusal
83253
+ * is correct and it is load-bearing: there is genuinely nothing left to
83254
+ * repoint, and an operator must never be able to re-repoint a migrated class
83255
+ * by accident. Making `start` idempotent — "an already-repointed class
83256
+ * proceeds straight to draining" — would delete that protection AND make the
83257
+ * verb mean two different things depending on state, so the confirmation an
83258
+ * operator reads ("pauses the writers…") would be a lie half the time.
83259
+ *
83260
+ * `drain` instead cannot repoint AT ALL: it never touches
83261
+ * `setDefaultLocations`, and its job starts in `draining` with `repointed`
83262
+ * already true, so the `repointing` / `refreshing` / `resuming` blocks of
83263
+ * {@link run} are behind it and unreachable. The two verbs are disjoint, and
83264
+ * `start`'s refusal keeps meaning exactly what it meant.
83265
+ *
83266
+ * ## Why it re-derives the work instead of resuming the old job
83267
+ *
83268
+ * The finished job is the audit of what happened; re-opening it destroys
83269
+ * that. And a drain is needed in cases where no migration job ever existed
83270
+ * (a mover armed by hand, footage stranded on a location an operator added
83271
+ * and then un-defaulted). One job = one operation, and the work list comes
83272
+ * from {@link residue} — the archive — not from what a previous job believed.
83273
+ */
83274
+ async drain(input) {
83275
+ if (this.startReserved) throw new Error("storage migration is already active");
83276
+ this.startReserved = true;
83277
+ try {
83278
+ const existing = await this.status();
83279
+ if (existing && isTerminal(existing) && existing.pausedParticipants.length > 0) {
83280
+ await this.releaseAfterTerminal(existing);
83281
+ await this.persist(existing);
83282
+ if (existing.pausedParticipants.length > 0) throw new Error(`storage migration ${existing.jobId} still holds maintenance leases`);
83283
+ }
83284
+ if (existing && !isTerminal(existing)) throw new Error(`storage migration is already active (${existing.jobId})`);
83285
+ for (const storageClass of input.classes) {
83286
+ if (MOVER_CLASSES.includes(storageClass)) continue;
83287
+ throw new Error(`No mover owns "${storageClass}" \u2014 there is nothing that can drain it. Move it by hand.`);
83288
+ }
83289
+ const residue = await this.residue();
83290
+ const moves = [];
83291
+ const destinations = {};
83292
+ for (const storageClass of input.classes) {
83293
+ const remaining = residue.filter((entry) => entry.storageClass === storageClass);
83294
+ if (remaining.length === 0) throw new Error(`"${storageClass}" has nothing left outside its default location \u2014 there is nothing to drain. To CHANGE where it writes, use storageMigration.start with a new destination.`);
83295
+ for (const entry of remaining) {
83296
+ if (this.deps.locations.getLocationById(entry.toLocationId)?.enabled === false) throw new Error(`The "${storageClass}" drain destination "${entry.toLocationId}" is DISABLED \u2014 a disabled location takes no writes, and a drain is the largest write there is. Enable it on the Storage screen, or make an enabled location the "${storageClass}" default first.`);
83297
+ moves.push({
83298
+ storageClass,
83299
+ fromLocationId: entry.fromLocationId,
83300
+ toLocationId: entry.toLocationId,
83301
+ moverJobId: null,
83302
+ state: null,
83303
+ error: null,
83304
+ progress: null
83305
+ });
83306
+ destinations[storageClass] = entry.toLocationId;
83307
+ }
83308
+ }
83309
+ const now = this.deps.now();
83310
+ const job = {
83311
+ jobId: this.deps.newId(),
83312
+ phase: "draining",
83313
+ mode: "nonBlocking",
83314
+ destinations,
83315
+ throttleMbps: input.throttleMbps ?? 40,
83316
+ moves,
83317
+ pauseLeaseId: null,
83318
+ pausedParticipants: [],
83319
+ repointed: true,
83320
+ cancelRequested: false,
83321
+ startedAt: now,
83322
+ updatedAt: now,
83323
+ finishedAt: null,
83324
+ error: null
83325
+ };
83326
+ await this.persist(job);
83327
+ this.active = job;
83328
+ this.runPromise = this.run(job);
83329
+ this.runPromise;
83330
+ return job.jobId;
83331
+ } finally {
83332
+ this.startReserved = false;
83333
+ }
83334
+ }
82661
83335
  /** Boot recovery resumes a durable unfinished state. A missing in-memory
82662
83336
  * child mover is recreated from the same copy-if-absent input. */
82663
83337
  async recover() {
@@ -82867,6 +83541,14 @@ var require_storage_orchestrator_addon = __commonJS({
82867
83541
  }
82868
83542
  move.state = status.state;
82869
83543
  move.error = status.error;
83544
+ move.progress = {
83545
+ filesMoved: status.filesMoved,
83546
+ filesTotal: status.filesTotal,
83547
+ bytesMoved: status.bytesMoved,
83548
+ ...status.rowsReconciled === void 0 ? {} : { rowsReconciled: status.rowsReconciled },
83549
+ startedAt: status.startedAt,
83550
+ observedAt: this.deps.now()
83551
+ };
82870
83552
  if (status.state === "failed") throw new Error(move.error ?? `${move.storageClass} move failed`);
82871
83553
  if (status.state === "cancelled") {
82872
83554
  job.cancelRequested = true;
@@ -82886,9 +83568,10 @@ var require_storage_orchestrator_addon = __commonJS({
82886
83568
  *
82887
83569
  * The gate is the RE-COUNT, not the seal job's terminal state: a seal that
82888
83570
  * failed some rows still finishes, and "finished" is not "there are none
82889
- * left". A non-zero count here fails the job while nothing has been paused
83571
+ * left". A remaining row here fails the job while nothing has been paused
82890
83572
  * and nothing has been repointed, which is the cheapest possible place to
82891
- * discover it.
83573
+ * discover it. So does a re-count that could not be TAKEN: the gate opens on
83574
+ * a measured absence, and only on that.
82892
83575
  *
82893
83576
  * The seal's own mover job id is deliberately NOT durable. It is idempotent
82894
83577
  * and cheap, so a coordinator restart mid-seal simply re-runs the whole
@@ -82898,7 +83581,8 @@ var require_storage_orchestrator_addon = __commonJS({
82898
83581
  async sealEventMedia(job) {
82899
83582
  const move = job.moves.find((candidate) => candidate.storageClass === "eventMedia");
82900
83583
  if (move === void 0) return;
82901
- if ((await this.deps.participants.analytics.countUnstamped()).total > 0) {
83584
+ const before = await this.deps.participants.analytics.countUnstamped();
83585
+ if (before === null || before.anyPresent) {
82902
83586
  const started = await this.deps.participants.analytics.startDrain({
82903
83587
  toLocationId: move.fromLocationId,
82904
83588
  mode: "seal"
@@ -82907,7 +83591,8 @@ var require_storage_orchestrator_addon = __commonJS({
82907
83591
  if (job.cancelRequested) return;
82908
83592
  }
82909
83593
  const after = await this.deps.participants.analytics.countUnstamped();
82910
- if (after.total > 0) throw new Error(`event-media seal left ${after.total.toString()} row(s) without a locationId (${after.media.toString()} media, ${after.retrainFrames.toString()} retrain frames). A non-blocking cutover would silently orphan them; nothing has been paused or repointed.`);
83594
+ if (after === null) throw new Error("event-media seal ran, but whether any row still carries no locationId could not be measured afterwards. Unknown is not zero; nothing has been paused or repointed.");
83595
+ if (after.anyPresent) throw new Error(`event-media seal left ${after.total === null ? "an unknown number of" : after.total.toString()} row(s) without a locationId (${describeUnstamped(after.media)} media, ${describeUnstamped(after.retrainFrames)} retrain frames). A non-blocking cutover would silently orphan them; nothing has been paused or repointed.`);
82911
83596
  }
82912
83597
  async waitForSeal(job, moverJobId) {
82913
83598
  const sleep = this.deps.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
@@ -82986,6 +83671,13 @@ var require_storage_orchestrator_addon = __commonJS({
82986
83671
  await this.deps.state.set(job);
82987
83672
  }
82988
83673
  };
83674
+ async function unanswerable(read) {
83675
+ try {
83676
+ return await read;
83677
+ } catch {
83678
+ return null;
83679
+ }
83680
+ }
82989
83681
  function requireLease(job) {
82990
83682
  if (job.pauseLeaseId === null) throw new Error("storage migration has no maintenance lease");
82991
83683
  return job.pauseLeaseId;
@@ -83006,6 +83698,9 @@ var require_storage_orchestrator_addon = __commonJS({
83006
83698
  const existing = map.get(declaration.id);
83007
83699
  if (existing !== void 0) {
83008
83700
  if (existing.cardinality !== declaration.cardinality) throw new Error(`Storage location cardinality conflict for id "${declaration.id}": "${existing.cardinality}" (first declarer) vs "${declaration.cardinality}" (later declarer). All addons declaring the same storage location id must agree on cardinality.`);
83701
+ const existingAccess = existing.access ?? "local-path";
83702
+ const declaredAccess = declaration.access ?? "local-path";
83703
+ if (existingAccess !== declaredAccess) throw new Error(`Storage location access conflict for id "${declaration.id}": "${existingAccess}" (first declarer) vs "${declaredAccess}" (later declarer). All addons declaring the same storage location id must agree on access \u2014 a later declaration must never widen what an earlier one restricted.`);
83009
83704
  continue;
83010
83705
  }
83011
83706
  map.set(declaration.id, declaration);
@@ -83021,11 +83716,23 @@ var require_storage_orchestrator_addon = __commonJS({
83021
83716
  cardinalityOf(id) {
83022
83717
  return map.get(id)?.cardinality ?? null;
83023
83718
  },
83719
+ accessOf(id) {
83720
+ const declaration = map.get(id);
83721
+ if (declaration === void 0) return null;
83722
+ return declaration.access ?? "local-path";
83723
+ },
83024
83724
  list() {
83025
83725
  return frozen;
83026
83726
  }
83027
83727
  };
83028
83728
  }
83729
+ function resolveRefusalFor(location, locality) {
83730
+ if (locality !== false) return null;
83731
+ return `storage.resolve is a request for a path this node can open with node:fs, and location "${location.id}" is served by the remote provider "${location.providerId}" (nodeLocal: false) \u2014 the path it would return exists on the remote host, not here. Read and write this location through the storage cap (read/write, or beginUpload/writeChunk/finalizeUpload) instead.`;
83732
+ }
83733
+ function canProbeOccupancyLocally(locality) {
83734
+ return locality === true;
83735
+ }
83029
83736
  function resolveEngine(getEngines) {
83030
83737
  const engines = getEngines();
83031
83738
  if (engines.length === 0) throw new Error("settings-store: no data-store-provider engine is registered \u2014 the data door has nothing behind it");
@@ -83053,6 +83760,47 @@ var require_storage_orchestrator_addon = __commonJS({
83053
83760
  declareCollection: async (input) => (await engine()).declareCollection(input)
83054
83761
  };
83055
83762
  }
83763
+ var EMPTY_SECRET_KEYS = /* @__PURE__ */ new Set();
83764
+ function secretKeysOfProviderInfo(info) {
83765
+ return require_dist10.collectSecretConfigKeys(info.configSchema);
83766
+ }
83767
+ function redactLocationConfig(config, secretKeys) {
83768
+ if (secretKeys.size === 0) return config;
83769
+ let touched = false;
83770
+ const out = {};
83771
+ for (const [key, value] of Object.entries(config)) {
83772
+ if (secretKeys.has(key) && value !== void 0 && value !== null && value !== "") {
83773
+ out[key] = require_dist10.REDACTED_SECRET;
83774
+ touched = true;
83775
+ continue;
83776
+ }
83777
+ out[key] = value;
83778
+ }
83779
+ return touched ? out : config;
83780
+ }
83781
+ function redactLocation(location, secretKeys) {
83782
+ const config = redactLocationConfig(location.config, secretKeys);
83783
+ if (config === location.config) return location;
83784
+ return {
83785
+ ...location,
83786
+ config
83787
+ };
83788
+ }
83789
+ function restoreRedactedSecrets(incoming, stored, secretKeys) {
83790
+ if (secretKeys.size === 0) return incoming;
83791
+ let touched = false;
83792
+ const out = {};
83793
+ for (const [key, value] of Object.entries(incoming)) {
83794
+ if (value !== "__camstack_redacted__" || !secretKeys.has(key)) {
83795
+ out[key] = value;
83796
+ continue;
83797
+ }
83798
+ touched = true;
83799
+ const previous = stored?.[key];
83800
+ if (previous !== void 0) out[key] = previous;
83801
+ }
83802
+ return touched ? out : incoming;
83803
+ }
83056
83804
  async function collectProviderInfos(providers, onError) {
83057
83805
  const out = [];
83058
83806
  for (const [index, p] of providers.entries()) try {
@@ -83193,6 +83941,34 @@ var require_storage_orchestrator_addon = __commonJS({
83193
83941
  backfilled: backfill.length,
83194
83942
  total: this.locations.size
83195
83943
  } });
83944
+ this.reportDisabledDefaults();
83945
+ }
83946
+ /**
83947
+ * Shout about a persisted row that is BOTH the type default and disabled.
83948
+ *
83949
+ * `upsertLocation` cannot produce this (`resolveEnabled` force-enables a
83950
+ * default) and neither can `setDefaultLocations` — but hydrate writes rows
83951
+ * straight into the map without either, so a hand-edited store, a partial
83952
+ * migration or a row written by another build can. It matters because every
83953
+ * bare-type ref resolves through {@link getDefaultLocation}: on such a row
83954
+ * `storage.write({ location: 'eventMedia' })` and the migration coordinator's
83955
+ * drain destination both point at a disk the operator turned off. That is the
83956
+ * one thing this model must never do silently.
83957
+ *
83958
+ * Reported, never repaired: flipping an operator's flag back on at boot would
83959
+ * be the system overruling the switch instead of obeying it. The coordinator
83960
+ * refuses the drain (`storage-migration-coordinator.drain`); the bare-ref read
83961
+ * path is deliberately left working, because narrowing a READ is a worse bug
83962
+ * than the one this line reports.
83963
+ */
83964
+ reportDisabledDefaults() {
83965
+ for (const loc of this.locations.values()) {
83966
+ if (!loc.isDefault || loc.enabled !== false) continue;
83967
+ this.logger.error("storage-orchestrator: the type DEFAULT is disabled \u2014 every bare-type ref for this type resolves to a location the operator turned off. Enable it, or make another location the default.", { meta: {
83968
+ id: loc.id,
83969
+ type: loc.type
83970
+ } });
83971
+ }
83196
83972
  }
83197
83973
  /**
83198
83974
  * Inject the declaration-driven cardinality source. Called once by the
@@ -83264,6 +84040,7 @@ var require_storage_orchestrator_addon = __commonJS({
83264
84040
  loaded: this.locations.size,
83265
84041
  isSystemUpgraded: upgraded
83266
84042
  } });
84043
+ this.reportDisabledDefaults();
83267
84044
  }
83268
84045
  /**
83269
84046
  * Boot backfill (SP1): stamp `nodeId` on every persisted node-local
@@ -83374,6 +84151,66 @@ var require_storage_orchestrator_addon = __commonJS({
83374
84151
  * implicitly-demoted siblings are persisted before the in-memory map
83375
84152
  * mutation returns. Persistence errors propagate to the caller.
83376
84153
  */
84154
+ /**
84155
+ * Refuse a `(location kind, provider)` pair the kind cannot use.
84156
+ *
84157
+ * The rule, in one line: a `'local-path'` kind requires a provider whose
84158
+ * `getProviderInfo().nodeLocal` is `true`.
84159
+ *
84160
+ * `nodeLocal` is the honest name for "this provider's `resolve` returns a
84161
+ * path on the filesystem of the node that resolved it". The
84162
+ * `storage-provider` cap's own discriminated union already forces every
84163
+ * provider to declare it, and all four remote providers declare `false`, so
84164
+ * no new cap surface is needed to ask the question.
84165
+ *
84166
+ * Three-valued on purpose. Only a POSITIVE `false` refuses:
84167
+ * - `true` → node-local, always fine.
84168
+ * - `false` → the provider is known and known to be remote. REFUSE.
84169
+ * - `undefined` → the provider has not registered yet (early boot, an addon
84170
+ * still loading). That is "unknown", not "remote", and a read that could
84171
+ * not be made must never destroy work (D49) — the system seed runs
84172
+ * through this path before any provider registers. Allowed, and logged,
84173
+ * so the allowance is never silent.
84174
+ *
84175
+ * The DECLARATION side is read the same way. A kind the registry does not
84176
+ * know is `local-path` (fail-closed: an unknown kind is not a permissive
84177
+ * one), but NO REGISTRY AT ALL is a different statement — nothing has been
84178
+ * loaded, so nothing can be concluded about any kind. The addon injects the
84179
+ * registry inside `onInitialize`, before the `storage` cap is mounted, so
84180
+ * there is no window in which an operator upsert sees this branch; a service
84181
+ * constructed without one is the in-memory/early-boot path.
84182
+ */
84183
+ refuseIncompatibleProvider(input) {
84184
+ const registry = this.registry;
84185
+ if (registry === null) {
84186
+ this.logger.debug("storage-orchestrator: no location declarations loaded \u2014 access constraint not evaluated", { meta: {
84187
+ id: input.id,
84188
+ type: input.type,
84189
+ providerId: input.providerId
84190
+ } });
84191
+ return;
84192
+ }
84193
+ const access = registry.accessOf(input.type) ?? "local-path";
84194
+ if (access !== "local-path") return;
84195
+ const nodeLocal = this.nodeLocalResolver?.(input.providerId);
84196
+ if (nodeLocal === true) return;
84197
+ if (nodeLocal === void 0) {
84198
+ this.logger.debug("storage-orchestrator: provider not yet classified \u2014 allowing a local-path upsert", { meta: {
84199
+ id: input.id,
84200
+ type: input.type,
84201
+ providerId: input.providerId,
84202
+ access
84203
+ } });
84204
+ return;
84205
+ }
84206
+ this.logger.warn("storage-orchestrator: REFUSED a remote provider for a local-path kind", { meta: {
84207
+ id: input.id,
84208
+ type: input.type,
84209
+ providerId: input.providerId,
84210
+ access
84211
+ } });
84212
+ throw new Error(`Storage kind "${input.type}" is declared access "local-path": the service that owns it reads and writes its bytes with node:fs on the path "storage.resolve" returns, so it can only be backed by a node-local provider. Provider "${input.providerId}" is remote (nodeLocal: false) and its resolved paths do not exist on this node. Refusing location "${input.id}".`);
84213
+ }
83377
84214
  upsertLocation(input) {
83378
84215
  const now = Date.now();
83379
84216
  const existing = this.locations.get(input.id);
@@ -83383,6 +84220,7 @@ var require_storage_orchestrator_addon = __commonJS({
83383
84220
  if (already) throw new Error(`Storage type "${input.type}" is single \u2014 only one location allowed (existing: "${already.id}"). Edit it instead of adding a new one.`);
83384
84221
  }
83385
84222
  }
84223
+ this.refuseIncompatibleProvider(input);
83386
84224
  if (this.nodeLocalResolver?.(input.providerId) === true && !input.nodeId) input = {
83387
84225
  ...input,
83388
84226
  nodeId: "hub"
@@ -83853,6 +84691,19 @@ var require_storage_orchestrator_addon = __commonJS({
83853
84691
  */
83854
84692
  nodeLocalByProvider = /* @__PURE__ */ new Map();
83855
84693
  /**
84694
+ * Cached `providerId → secret config keys`, derived from each provider's own
84695
+ * `configSchema` in the SAME refresh as `nodeLocalByProvider` — one
84696
+ * `getProviderInfo()` round trip answers both questions.
84697
+ *
84698
+ * An absent providerId yields an EMPTY set, which redacts nothing. That is
84699
+ * the one direction this cache can be wrong in, so it is worth saying why it
84700
+ * is acceptable: the entry is populated at the same moment the provider
84701
+ * becomes resolvable at all, so a location whose provider is unknown here
84702
+ * cannot be dispatched to either — there is no window in which a credential
84703
+ * is readable through a provider the orchestrator can otherwise use.
84704
+ */
84705
+ secretKeysByProvider = /* @__PURE__ */ new Map();
84706
+ /**
83856
84707
  * Disposers run on `onShutdown` — currently the eventBus subscription
83857
84708
  * for `capability:provider-registered` events used by the lazy seed
83858
84709
  * fallback. Stored separately from the `BaseAddon` disposer chain so
@@ -83887,13 +84738,24 @@ var require_storage_orchestrator_addon = __commonJS({
83887
84738
  listLocations: async ({ type }) => {
83888
84739
  const rows = type !== void 0 ? service.listLocations({ type }) : service.listLocations();
83889
84740
  return Promise.all(rows.map(async (loc) => ({
83890
- ...loc,
84741
+ ...this.redacted(loc),
83891
84742
  capacity: await this.localCapacityOf(loc)
83892
84743
  })));
83893
84744
  },
83894
- getDefaultLocation: async ({ type }) => service.getDefaultLocation(type),
84745
+ getDefaultLocation: async ({ type }) => {
84746
+ const loc = service.getDefaultLocation(type);
84747
+ return loc === null ? null : this.redacted(loc);
84748
+ },
83895
84749
  listLocationDeclarations: async () => service.listDeclarations(),
83896
- upsertLocation: async (input) => service.upsertLocation(input),
84750
+ upsertLocation: async (input) => {
84751
+ const stored = service.getLocationById(input.id);
84752
+ const config = restoreRedactedSecrets(input.config, stored?.config, this.secretKeysFor(input.providerId));
84753
+ const saved = service.upsertLocation(config === input.config ? input : {
84754
+ ...input,
84755
+ config
84756
+ });
84757
+ return this.redacted(saved);
84758
+ },
83897
84759
  deleteLocation: async ({ id, force }) => {
83898
84760
  await service.deleteLocation(id, { force: force === true });
83899
84761
  },
@@ -83938,6 +84800,7 @@ var require_storage_orchestrator_addon = __commonJS({
83938
84800
  },
83939
84801
  resolve: async ({ location, relativePath }) => {
83940
84802
  const loc = service.resolveRef(location);
84803
+ this.refuseRemoteResolve(loc);
83941
84804
  return (await service.getProviderFor(loc)).resolve({
83942
84805
  location: loc,
83943
84806
  relativePath
@@ -84060,6 +84923,8 @@ var require_storage_orchestrator_addon = __commonJS({
84060
84923
  startMove: (input) => this.ctx.api.recording.startStorageMigrationMove.mutate(input),
84061
84924
  startDrain: (input) => this.ctx.api.recording.relocateFootage.mutate(input),
84062
84925
  getMove: (jobId) => this.ctx.api.recording.getStorageMigrationMoveStatus.query({ jobId }),
84926
+ listMovers: () => this.ctx.api.recording.listRelocateJobs.query({}),
84927
+ residue: (input) => this.ctx.api.recording.getRelocateResidue.query(input),
84063
84928
  cancelMove: async (jobId) => (await this.ctx.api.recording.cancelStorageMigrationMove.mutate({ jobId })).cancelled,
84064
84929
  refresh: async (leaseId) => {
84065
84930
  await this.ctx.api.recording.refreshStorageLocationsForMigration.mutate({ leaseId });
@@ -84076,6 +84941,8 @@ var require_storage_orchestrator_addon = __commonJS({
84076
84941
  startDrain: (input) => this.ctx.api.pipelineAnalytics.relocateMedia.mutate(input),
84077
84942
  countUnstamped: () => this.ctx.api.pipelineAnalytics.countUnstampedEventMedia.query({}),
84078
84943
  getMove: (jobId) => this.ctx.api.pipelineAnalytics.getStorageMigrationMoveStatus.query({ jobId }),
84944
+ listMovers: () => this.ctx.api.pipelineAnalytics.listRelocateMediaJobs.query({}),
84945
+ residue: (input) => this.ctx.api.pipelineAnalytics.countRelocatableMedia.query(input),
84079
84946
  cancelMove: async (jobId) => (await this.ctx.api.pipelineAnalytics.cancelStorageMigrationMove.mutate({ jobId })).cancelled,
84080
84947
  refresh: async (leaseId) => {
84081
84948
  await this.ctx.api.pipelineAnalytics.refreshStorageLocationsForMigration.mutate({ leaseId });
@@ -84091,7 +84958,10 @@ var require_storage_orchestrator_addon = __commonJS({
84091
84958
  plan: (input) => migration.plan(input),
84092
84959
  start: async (input) => ({ jobId: await migration.start(input) }),
84093
84960
  status: ({ jobId }) => migration.status(jobId),
84094
- cancel: async ({ jobId }) => ({ cancelled: await migration.cancel(jobId) })
84961
+ cancel: async ({ jobId }) => ({ cancelled: await migration.cancel(jobId) }),
84962
+ movers: () => migration.movers(),
84963
+ residue: () => migration.residue(),
84964
+ drain: async (input) => ({ jobId: await migration.drain(input) })
84095
84965
  };
84096
84966
  await this.seedFromDeclarations();
84097
84967
  const eventBus = this.ctx.eventBus;
@@ -84236,6 +85106,34 @@ var require_storage_orchestrator_addon = __commonJS({
84236
85106
  }
84237
85107
  return out;
84238
85108
  }
85109
+ /** Declared secret config keys for a provider; empty when unknown. */
85110
+ secretKeysFor(providerId) {
85111
+ return this.secretKeysByProvider.get(providerId) ?? EMPTY_SECRET_KEYS;
85112
+ }
85113
+ /** A location with its provider's declared secrets replaced by the sentinel. */
85114
+ redacted(location) {
85115
+ return redactLocation(location, this.secretKeysFor(location.providerId));
85116
+ }
85117
+ /**
85118
+ * Is this location backed by a provider that serves a genuine local
85119
+ * filesystem? `true` / `false` / `undefined` — see
85120
+ * `StorageOrchestratorService.refuseIncompatibleProvider` for why the
85121
+ * unknown case is kept distinct rather than folded into either answer.
85122
+ */
85123
+ providerIsNodeLocal(location) {
85124
+ return this.nodeLocalByProvider.get(location.providerId);
85125
+ }
85126
+ /** See the call site in the `resolve` dispatch, and `access-guards.ts`. */
85127
+ refuseRemoteResolve(location) {
85128
+ const refusal = resolveRefusalFor(location, this.providerIsNodeLocal(location));
85129
+ if (refusal === null) return;
85130
+ this.ctx.logger.warn("storage-orchestrator: REFUSED resolve() on a remote-backed location", { meta: {
85131
+ id: location.id,
85132
+ type: location.type,
85133
+ providerId: location.providerId
85134
+ } });
85135
+ throw new Error(refusal);
85136
+ }
84239
85137
  /** statfs capacity of a location's basePath, walking up to the nearest
84240
85138
  * existing ancestor. Null for remote-node locations or unstattable paths. */
84241
85139
  async localCapacityOf(loc) {
@@ -84323,6 +85221,13 @@ var require_storage_orchestrator_addon = __commonJS({
84323
85221
  * errno — `EACCES`, `EIO`, a stale NFS handle — is `unknown` and refuses.
84324
85222
  */
84325
85223
  async locationOccupancy(location) {
85224
+ if (!canProbeOccupancyLocally(this.providerIsNodeLocal(location))) {
85225
+ this.ctx.logger.debug("storage-orchestrator: occupancy unknown \u2014 location is not backed by a local filesystem", { meta: {
85226
+ id: location.id,
85227
+ providerId: location.providerId
85228
+ } });
85229
+ return "unknown";
85230
+ }
84326
85231
  if ((location.nodeId === void 0 || location.nodeId === "" ? HUB_NODE_ID : location.nodeId) !== (this.service?.getLocalNodeId() ?? HUB_NODE_ID)) return "unknown";
84327
85232
  const basePath = this.locationBasePath(location.id);
84328
85233
  if (basePath === null) return "unknown";
@@ -84405,7 +85310,10 @@ var require_storage_orchestrator_addon = __commonJS({
84405
85310
  error: err instanceof Error ? err.message : String(err)
84406
85311
  } });
84407
85312
  });
84408
- for (const info of infos) this.nodeLocalByProvider.set(info.providerId, info.nodeLocal);
85313
+ for (const info of infos) {
85314
+ this.nodeLocalByProvider.set(info.providerId, info.nodeLocal);
85315
+ this.secretKeysByProvider.set(info.providerId, secretKeysOfProviderInfo(info));
85316
+ }
84409
85317
  }
84410
85318
  };
84411
85319
  exports.SqliteLocationStore = SqliteLocationStore;
@@ -84444,7 +85352,7 @@ var require_system_config_addon = __commonJS({
84444
85352
  [Symbol.toStringTag]: { value: "Module" }
84445
85353
  });
84446
85354
  require_chunk_Cek0wNdY();
84447
- var require_dist10 = require_dist_CDgIzo82();
85355
+ var require_dist10 = require_dist_CcvXUhHK();
84448
85356
  var SECTION_TITLES = {
84449
85357
  server: "Server",
84450
85358
  auth: "Authentication"
@@ -102505,7 +103413,7 @@ var require_winston_logging = __commonJS({
102505
103413
  [Symbol.toStringTag]: { value: "Module" }
102506
103414
  });
102507
103415
  var require_chunk = require_chunk_Cek0wNdY();
102508
- var require_dist10 = require_dist_CDgIzo82();
103416
+ var require_dist10 = require_dist_CcvXUhHK();
102509
103417
  var require_formatter = require_formatter_DqAKDlvN();
102510
103418
  var node_path = __require("path");
102511
103419
  node_path = require_chunk.__toESM(node_path);
@@ -104448,9 +105356,9 @@ var require_event_category_BaEgqJNv = __commonJS({
104448
105356
  }
104449
105357
  });
104450
105358
 
104451
- // ../types/dist/sleep-CJrvRDlD.js
104452
- var require_sleep_CJrvRDlD = __commonJS({
104453
- "../types/dist/sleep-CJrvRDlD.js"(exports) {
105359
+ // ../types/dist/sleep-CWWLTM6W.js
105360
+ var require_sleep_CWWLTM6W = __commonJS({
105361
+ "../types/dist/sleep-CWWLTM6W.js"(exports) {
104454
105362
  "use strict";
104455
105363
  var require_event_category = require_event_category_BaEgqJNv();
104456
105364
  var zod = require_zod();
@@ -107151,6 +108059,7 @@ var require_sleep_CJrvRDlD = __commonJS({
107151
108059
  cancelStorageMigrationMove: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "cancelStorageMigrationMove", "mutation", input),
107152
108060
  relocateMedia: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "relocateMedia", "mutation", input),
107153
108061
  countUnstampedEventMedia: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "countUnstampedEventMedia", "query", input),
108062
+ countRelocatableMedia: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "countRelocatableMedia", "query", input),
107154
108063
  listRelocateMediaJobs: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "listRelocateMediaJobs", "query", input),
107155
108064
  cancelRelocateMedia: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "cancelRelocateMedia", "mutation", input),
107156
108065
  listOpsLog: (input) => dispatch("pipeline-analytics", "pipelineAnalytics", "listOpsLog", "query", input),
@@ -108115,7 +109024,7 @@ var require_addon = __commonJS({
108115
109024
  "use strict";
108116
109025
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
108117
109026
  var require_event_category = require_event_category_BaEgqJNv();
108118
- var require_sleep = require_sleep_CJrvRDlD();
109027
+ var require_sleep = require_sleep_CWWLTM6W();
108119
109028
  var require_err_msg = require_err_msg_COpsHMw2();
108120
109029
  var CAP_INPUT_DEFAULTS = Object.freeze({
108121
109030
  "addons": { "getLogs": { "limit": 100 } },
@@ -108335,7 +109244,10 @@ var require_addon = __commonJS({
108335
109244
  "createApiKey": { "isAdmin": false },
108336
109245
  "createUser": { "isAdmin": false }
108337
109246
  },
108338
- "vector-store": { "declareIndex": { "metric": "cosine" } },
109247
+ "vector-store": {
109248
+ "declareIndex": { "metric": "cosine" },
109249
+ "scan": { "cursor": 0 }
109250
+ },
108339
109251
  "zones": {
108340
109252
  "addZone": { "zone": { "__nested__": {
108341
109253
  "kind": "polygon",
@@ -114994,12 +115906,12 @@ var require_dist2 = __commonJS({
114994
115906
  }
114995
115907
  });
114996
115908
 
114997
- // ../system/dist/manifest-python-deps-DVODn-qc.js
114998
- var require_manifest_python_deps_DVODn_qc = __commonJS({
114999
- "../system/dist/manifest-python-deps-DVODn-qc.js"(exports) {
115909
+ // ../system/dist/manifest-system-deps-oJMkWSX-.js
115910
+ var require_manifest_system_deps_oJMkWSX = __commonJS({
115911
+ "../system/dist/manifest-system-deps-oJMkWSX-.js"(exports) {
115000
115912
  "use strict";
115001
115913
  var require_chunk = require_chunk_Cek0wNdY();
115002
- require_dist_CDgIzo82();
115914
+ require_dist_CcvXUhHK();
115003
115915
  var node_crypto = __require("crypto");
115004
115916
  node_crypto = require_chunk.__toESM(node_crypto);
115005
115917
  var _camstack_types_node = require_node();
@@ -115702,14 +116614,14 @@ var require_manifest_python_deps_DVODn_qc = __commonJS({
115702
116614
  dispose
115703
116615
  };
115704
116616
  }
115705
- var execFileAsync$1 = (0, node_util.promisify)(node_child_process.execFile);
116617
+ var execFileAsync$2 = (0, node_util.promisify)(node_child_process.execFile);
115706
116618
  var DEFAULT_REGISTRY = "https://registry.npmjs.org";
115707
116619
  function bootstrappedCliPath(cacheDir) {
115708
116620
  return node_path.join(cacheDir, "package", "bin", "npm-cli.js");
115709
116621
  }
115710
116622
  async function defaultProbeSystemNpm() {
115711
116623
  try {
115712
- await execFileAsync$1("npm", ["--version"], { timeout: 15e3 });
116624
+ await execFileAsync$2("npm", ["--version"], { timeout: 15e3 });
115713
116625
  return true;
115714
116626
  } catch {
115715
116627
  return false;
@@ -115727,7 +116639,7 @@ var require_manifest_python_deps_DVODn_qc = __commonJS({
115727
116639
  await node_fs.promises.writeFile(destTgz, bytes);
115728
116640
  }
115729
116641
  async function defaultExtractTarball(tgzPath, destDir) {
115730
- await execFileAsync$1("tar", [
116642
+ await execFileAsync$2("tar", [
115731
116643
  "-xzf",
115732
116644
  tgzPath,
115733
116645
  "-C",
@@ -115755,7 +116667,7 @@ var require_manifest_python_deps_DVODn_qc = __commonJS({
115755
116667
  registry: options.registry,
115756
116668
  logger: options.logger
115757
116669
  });
115758
- return execFileAsync$1(invocation.command, [...invocation.argsPrefix, ...args], {
116670
+ return execFileAsync$2(invocation.command, [...invocation.argsPrefix, ...args], {
115759
116671
  ...options.cwd !== void 0 ? { cwd: options.cwd } : {},
115760
116672
  timeout: options.timeout ?? 3e5
115761
116673
  });
@@ -115813,7 +116725,7 @@ var require_manifest_python_deps_DVODn_qc = __commonJS({
115813
116725
  const namedAddon = Object.values(mod).find(isAddonConstructor);
115814
116726
  if (namedAddon) return namedAddon;
115815
116727
  }
115816
- var execFileAsync = (0, node_util.promisify)(node_child_process.execFile);
116728
+ var execFileAsync$1 = (0, node_util.promisify)(node_child_process.execFile);
115817
116729
  function defaultNpmCacheDir() {
115818
116730
  return node_path.join(node_os.tmpdir(), "camstack-npm-bootstrap");
115819
116731
  }
@@ -116041,7 +116953,7 @@ var require_manifest_python_deps_DVODn_qc = __commonJS({
116041
116953
  return;
116042
116954
  }
116043
116955
  logger.warn("@electron/rebuild not available \u2014 falling back to npx", { meta: { addonDir } });
116044
- await execFileAsync("npx", [
116956
+ await execFileAsync$1("npx", [
116045
116957
  "--yes",
116046
116958
  "electron-rebuild",
116047
116959
  "-m",
@@ -117244,11 +118156,11 @@ var require_manifest_python_deps_DVODn_qc = __commonJS({
117244
118156
  });
117245
118157
  }
117246
118158
  };
117247
- const PROBE_TIMEOUT_MS = 3e4;
118159
+ const PROBE_TIMEOUT_MS2 = 3e4;
117248
118160
  const runProbe = async () => {
117249
118161
  if (typeof lifecycleHost.onProbe !== "function") return;
117250
118162
  try {
117251
- await Promise.race([lifecycleHost.onProbe(), new Promise((_, reject) => setTimeout(() => reject(/* @__PURE__ */ new Error(`onProbe timeout after ${PROBE_TIMEOUT_MS}ms`)), PROBE_TIMEOUT_MS))]);
118163
+ await Promise.race([lifecycleHost.onProbe(), new Promise((_, reject) => setTimeout(() => reject(/* @__PURE__ */ new Error(`onProbe timeout after ${PROBE_TIMEOUT_MS2}ms`)), PROBE_TIMEOUT_MS2))]);
117252
118164
  } catch (err) {
117253
118165
  opts.logger.warn("device.onProbe() threw or timed out \u2014 continuing with stale flags (slice subscription will reconcile if probe lands later)", {
117254
118166
  tags: {
@@ -119107,6 +120019,174 @@ var require_manifest_python_deps_DVODn_qc = __commonJS({
119107
120019
  createClient: (nodeId) => new UdsLocalTransportClient(localEndpointPath(nodeId))
119108
120020
  };
119109
120021
  }
120022
+ var DEFAULT_RETENTION_SECONDS = 300;
120023
+ var DEFAULT_MAX_TRIPLES = 4e3;
120024
+ var PARENT_ROUTED_PROVIDER_ADDON_ID = "(unresolved: parent-routed)";
120025
+ var CapUsageRegistry = class {
120026
+ retentionSeconds;
120027
+ maxTriples;
120028
+ map = /* @__PURE__ */ new Map();
120029
+ triples = 0;
120030
+ droppedTriples = 0;
120031
+ constructor(opts) {
120032
+ this.retentionSeconds = Math.max(1, opts?.retentionSeconds ?? DEFAULT_RETENTION_SECONDS);
120033
+ this.maxTriples = Math.max(1, opts?.maxTriples ?? DEFAULT_MAX_TRIPLES);
120034
+ }
120035
+ /**
120036
+ * Record one observed cap call.
120037
+ *
120038
+ * On the hot path: this runs once per cross-process cap call on hub-main's
120039
+ * event loop, which is the cluster's only queue (D181). Three Map lookups, an
120040
+ * integer increment, and — only when the wall clock has moved on — a bounded
120041
+ * clear. No allocation once a triple exists, and it NEVER throws into the
120042
+ * call it observes.
120043
+ */
120044
+ recordCall(rec) {
120045
+ try {
120046
+ if (rec.callerAddonId === "" || rec.providerAddonId === "" || rec.capName === "") return;
120047
+ if (!Number.isFinite(rec.atMs) || rec.atMs < 0) return;
120048
+ const window2 = this.windowFor(rec);
120049
+ if (window2 === null) return;
120050
+ const sec = Math.floor(rec.atMs / 1e3);
120051
+ if (window2.lastCallAtMs !== 0) {
120052
+ const lastSec = Math.floor(window2.lastCallAtMs / 1e3);
120053
+ const advanced = Math.min(sec - lastSec, this.retentionSeconds);
120054
+ for (let k = 1; k <= advanced; k++) window2.buckets[(lastSec + k) % this.retentionSeconds] = 0;
120055
+ }
120056
+ const idx = sec % this.retentionSeconds;
120057
+ window2.buckets[idx] = (window2.buckets[idx] ?? 0) + 1;
120058
+ if (rec.atMs > window2.lastCallAtMs) window2.lastCallAtMs = rec.atMs;
120059
+ } catch {
120060
+ }
120061
+ }
120062
+ getGraph(opts) {
120063
+ const windowSeconds = Math.max(1, Math.min(opts.windowSeconds, this.retentionSeconds));
120064
+ const minMs = opts.nowMs - windowSeconds * 1e3;
120065
+ const nowSec = Math.floor(opts.nowMs / 1e3);
120066
+ const out = [];
120067
+ for (const [caller, byProvider] of this.map) for (const [provider, byCap] of byProvider) for (const [capName, window2] of byCap) {
120068
+ if (window2.lastCallAtMs < minMs) continue;
120069
+ const count = this.sumWindow(window2, nowSec, windowSeconds);
120070
+ if (count === 0) continue;
120071
+ const callsPerMin = count / windowSeconds * 60;
120072
+ out.push({
120073
+ callerAddonId: caller,
120074
+ providerAddonId: provider,
120075
+ capName,
120076
+ callsPerMin,
120077
+ lastCallAtMs: window2.lastCallAtMs
120078
+ });
120079
+ }
120080
+ return out;
120081
+ }
120082
+ /** See {@link CapUsageStats}. Cheap — three counters, no scan. */
120083
+ getStats() {
120084
+ return {
120085
+ triples: this.triples,
120086
+ maxTriples: this.maxTriples,
120087
+ droppedTriples: this.droppedTriples
120088
+ };
120089
+ }
120090
+ /** Test / diagnostic helper — drops all recorded calls. */
120091
+ clear() {
120092
+ this.map.clear();
120093
+ this.triples = 0;
120094
+ this.droppedTriples = 0;
120095
+ }
120096
+ /**
120097
+ * Sum the buckets covering `(nowSec - windowSeconds, nowSec]`.
120098
+ *
120099
+ * The scan starts at `lastSec`, never at `nowSec`. `recordCall` clears the
120100
+ * buckets the ring has advanced OVER, which by definition stops at the last
120101
+ * write: the buckets for the seconds since then still hold whatever the
120102
+ * previous pass left in them, and reading `nowSec` down would count it. A
120103
+ * triple that went quiet for a couple of minutes and then made one call would
120104
+ * report the burst it made five minutes earlier.
120105
+ *
120106
+ * No lower bound is needed beyond the window itself: every bucket at or below
120107
+ * `lastSec - retention` was cleared by the advance that reached `lastSec`, so
120108
+ * it reads zero anyway. The loop is bounded by `windowSeconds ≤ retention`.
120109
+ */
120110
+ sumWindow(window2, nowSec, windowSeconds) {
120111
+ const lastSec = Math.floor(window2.lastCallAtMs / 1e3);
120112
+ const from = Math.min(nowSec, lastSec);
120113
+ const floorSec = nowSec - windowSeconds;
120114
+ let count = 0;
120115
+ for (let s = from; s > floorSec; s--) count += window2.buckets[s % this.retentionSeconds] ?? 0;
120116
+ return count;
120117
+ }
120118
+ /**
120119
+ * The ring for this triple, creating it if the ceiling allows. `null` means
120120
+ * the observation is dropped — counted, never silent (see
120121
+ * {@link CapUsageStats.droppedTriples}).
120122
+ */
120123
+ windowFor(rec) {
120124
+ let byProvider = this.map.get(rec.callerAddonId);
120125
+ if (!byProvider) {
120126
+ byProvider = /* @__PURE__ */ new Map();
120127
+ this.map.set(rec.callerAddonId, byProvider);
120128
+ }
120129
+ let byCap = byProvider.get(rec.providerAddonId);
120130
+ if (!byCap) {
120131
+ byCap = /* @__PURE__ */ new Map();
120132
+ byProvider.set(rec.providerAddonId, byCap);
120133
+ }
120134
+ const existing = byCap.get(rec.capName);
120135
+ if (existing) return existing;
120136
+ if (this.triples >= this.maxTriples) {
120137
+ this.reclaimExpired(rec.atMs);
120138
+ if (this.triples >= this.maxTriples) {
120139
+ this.droppedTriples++;
120140
+ return null;
120141
+ }
120142
+ byProvider = this.map.get(rec.callerAddonId);
120143
+ if (!byProvider) {
120144
+ byProvider = /* @__PURE__ */ new Map();
120145
+ this.map.set(rec.callerAddonId, byProvider);
120146
+ }
120147
+ byCap = byProvider.get(rec.providerAddonId);
120148
+ if (!byCap) {
120149
+ byCap = /* @__PURE__ */ new Map();
120150
+ byProvider.set(rec.providerAddonId, byCap);
120151
+ }
120152
+ }
120153
+ const created = {
120154
+ buckets: new Uint32Array(this.retentionSeconds),
120155
+ lastCallAtMs: 0
120156
+ };
120157
+ byCap.set(rec.capName, created);
120158
+ this.triples++;
120159
+ return created;
120160
+ }
120161
+ /**
120162
+ * Drop every triple whose whole ring has aged out — its last call is older
120163
+ * than the retention window, so it can contribute to no query. O(triples),
120164
+ * and only reachable when the ceiling is full, so it is amortised away by the
120165
+ * admissions it enables.
120166
+ */
120167
+ reclaimExpired(nowMs) {
120168
+ const cutoff = nowMs - this.retentionSeconds * 1e3;
120169
+ for (const [caller, byProvider] of this.map) {
120170
+ for (const [provider, byCap] of byProvider) {
120171
+ for (const [capName, window2] of byCap) {
120172
+ if (window2.lastCallAtMs >= cutoff) continue;
120173
+ byCap.delete(capName);
120174
+ this.triples--;
120175
+ }
120176
+ if (byCap.size === 0) byProvider.delete(provider);
120177
+ }
120178
+ if (byProvider.size === 0) this.map.delete(caller);
120179
+ }
120180
+ }
120181
+ };
120182
+ var singleton = null;
120183
+ function getCapUsageRegistry() {
120184
+ if (!singleton) singleton = new CapUsageRegistry();
120185
+ return singleton;
120186
+ }
120187
+ function __resetCapUsageRegistryForTests() {
120188
+ singleton = null;
120189
+ }
119110
120190
  function createSharedBusState(retainRecent = false) {
119111
120191
  return {
119112
120192
  handlers: /* @__PURE__ */ new Map(),
@@ -119653,6 +120733,8 @@ var require_manifest_python_deps_DVODn_qc = __commonJS({
119653
120733
  isAddonPinnedCall;
119654
120734
  /** See {@link LocalChildRegistryOptions.capTimeoutMs}. */
119655
120735
  capTimeoutMs;
120736
+ /** See {@link LocalChildRegistryOptions.capUsageObserver}. */
120737
+ capUsageObserver;
119656
120738
  /** Tracks capNames already logged as UDS-routed; one INFO line per capName per process. */
119657
120739
  egressRoutedCaps = /* @__PURE__ */ new Set();
119658
120740
  /** Active event fan-out mode, read once from `CAMSTACK_UDS_EVENT_FANOUT`. */
@@ -119684,6 +120766,7 @@ var require_manifest_python_deps_DVODn_qc = __commonJS({
119684
120766
  this.isAggregatedCollectionMethod = opts.isAggregatedCollectionMethod;
119685
120767
  this.isAddonPinnedCall = opts.isAddonPinnedCall;
119686
120768
  this.capTimeoutMs = opts.capTimeoutMs;
120769
+ this.capUsageObserver = opts.capUsageObserver;
119687
120770
  } else {
119688
120771
  this.server = serverOrOptions;
119689
120772
  this.onUnownedCall = onUnownedCallArg;
@@ -119850,6 +120933,30 @@ var require_manifest_python_deps_DVODn_qc = __commonJS({
119850
120933
  }
119851
120934
  return candidates[0];
119852
120935
  }
120936
+ /**
120937
+ * Publish one cap-usage observation, if a sink is wired.
120938
+ *
120939
+ * Cost discipline — this is on the hot path (D181: hub-main's event loop is
120940
+ * the cluster's only queue): no sink means one undefined check; with a sink
120941
+ * it is one object literal and one `Date.now()`, and the sink itself is O(1).
120942
+ * Wrapped so a broken observer can never fail the call it observes — the
120943
+ * registry swallows too, and BOTH matter: this catch also covers a sink that
120944
+ * is not the registry.
120945
+ */
120946
+ recordCapUsage(callerChildId, providerChildId, capName, methodName) {
120947
+ const sink = this.capUsageObserver;
120948
+ if (sink === void 0 || callerChildId === null) return;
120949
+ try {
120950
+ sink({
120951
+ callerAddonId: callerChildId,
120952
+ providerAddonId: providerChildId ?? "(unresolved: parent-routed)",
120953
+ capName,
120954
+ methodName,
120955
+ atMs: Date.now()
120956
+ });
120957
+ } catch {
120958
+ }
120959
+ }
119853
120960
  /** First child whose cap manifest contains a descriptor matching `predicate`. */
119854
120961
  findChildId(predicate) {
119855
120962
  for (const entry of this.children.values()) if (entry.caps.some(predicate)) return entry.childId;
@@ -120119,7 +121226,9 @@ var require_manifest_python_deps_DVODn_qc = __commonJS({
120119
121226
  const pinTargetsThisNode = pinnedNodeId !== void 0 && this.ownNodeId !== void 0 && pinnedNodeId === this.ownNodeId;
120120
121227
  const aggregated = pinnedNodeId === void 0 && this.isAggregatedCollectionMethod?.(out.capName, out.method) === true;
120121
121228
  const addonPinned = pinnedNodeId === void 0 && this.isAddonPinnedCall?.(out.capName, out.method, out.args) === true;
120122
- if ((!(out.native === true) && !aggregated && !addonPinned && (pinnedNodeId === void 0 || pinTargetsThisNode) ? this.resolveChildId(out.capName, out.deviceId) : null) !== null) {
121229
+ const target = !(out.native === true) && !aggregated && !addonPinned && (pinnedNodeId === void 0 || pinTargetsThisNode) ? this.resolveChildId(out.capName, out.deviceId) : null;
121230
+ this.recordCapUsage(childId, target, out.capName, out.method);
121231
+ if (target !== null) {
120123
121232
  if (!this.egressRoutedCaps.has(out.capName)) {
120124
121233
  this.egressRoutedCaps.add(out.capName);
120125
121234
  this.logger?.info("routed child egress over UDS", { capName: out.capName });
@@ -120976,77 +122085,6 @@ var require_manifest_python_deps_DVODn_qc = __commonJS({
120976
122085
  }
120977
122086
  return links;
120978
122087
  }
120979
- var CapUsageRegistry = class {
120980
- retentionSeconds;
120981
- map = /* @__PURE__ */ new Map();
120982
- constructor(opts) {
120983
- this.retentionSeconds = Math.max(1, opts?.retentionSeconds ?? 300);
120984
- }
120985
- recordCall(rec) {
120986
- try {
120987
- if (rec.callerAddonId === "" || rec.providerAddonId === "" || rec.capName === "") return;
120988
- if (!Number.isFinite(rec.atMs) || rec.atMs < 0) return;
120989
- let byProvider = this.map.get(rec.callerAddonId);
120990
- if (!byProvider) {
120991
- byProvider = /* @__PURE__ */ new Map();
120992
- this.map.set(rec.callerAddonId, byProvider);
120993
- }
120994
- let byCap = byProvider.get(rec.providerAddonId);
120995
- if (!byCap) {
120996
- byCap = /* @__PURE__ */ new Map();
120997
- byProvider.set(rec.providerAddonId, byCap);
120998
- }
120999
- let window2 = byCap.get(rec.capName);
121000
- if (!window2) {
121001
- window2 = {
121002
- buckets: Array.from({ length: this.retentionSeconds }, () => 0),
121003
- lastCallAtMs: 0
121004
- };
121005
- byCap.set(rec.capName, window2);
121006
- }
121007
- const bucketIdx = Math.floor(rec.atMs / 1e3) % this.retentionSeconds;
121008
- window2.buckets[bucketIdx] = (window2.buckets[bucketIdx] ?? 0) + 1;
121009
- if (rec.atMs > window2.lastCallAtMs) window2.lastCallAtMs = rec.atMs;
121010
- } catch {
121011
- }
121012
- }
121013
- getGraph(opts) {
121014
- const windowSeconds = Math.max(1, Math.min(opts.windowSeconds, this.retentionSeconds));
121015
- const minMs = opts.nowMs - windowSeconds * 1e3;
121016
- const out = [];
121017
- for (const [caller, byProvider] of this.map) for (const [provider, byCap] of byProvider) for (const [capName, window2] of byCap) {
121018
- if (window2.lastCallAtMs < minMs) continue;
121019
- const nowBucket = Math.floor(opts.nowMs / 1e3);
121020
- let count = 0;
121021
- for (let i = 0; i < windowSeconds; i++) {
121022
- const b = (nowBucket - i + this.retentionSeconds * 1e6) % this.retentionSeconds;
121023
- count += window2.buckets[b] ?? 0;
121024
- }
121025
- if (count === 0) continue;
121026
- const callsPerMin = count / windowSeconds * 60;
121027
- out.push({
121028
- callerAddonId: caller,
121029
- providerAddonId: provider,
121030
- capName,
121031
- callsPerMin,
121032
- lastCallAtMs: window2.lastCallAtMs
121033
- });
121034
- }
121035
- return out;
121036
- }
121037
- /** Test / diagnostic helper — drops all recorded calls. */
121038
- clear() {
121039
- this.map.clear();
121040
- }
121041
- };
121042
- var singleton = null;
121043
- function getCapUsageRegistry() {
121044
- if (!singleton) singleton = new CapUsageRegistry();
121045
- return singleton;
121046
- }
121047
- function __resetCapUsageRegistryForTests() {
121048
- singleton = null;
121049
- }
121050
122088
  function safeExistsSync(path) {
121051
122089
  try {
121052
122090
  return node_fs.existsSync(path);
@@ -122158,6 +123196,156 @@ var require_manifest_python_deps_DVODn_qc = __commonJS({
122158
123196
  }
122159
123197
  await deps.installPythonRequirements(reqAbs);
122160
123198
  }
123199
+ var execFileAsync = (0, node_util.promisify)(node_child_process.execFile);
123200
+ var INSTALL_TIMEOUT_MS = 300 * 1e3;
123201
+ var PROBE_TIMEOUT_MS = 1e4;
123202
+ async function installManifestSystemDeps(declaration, logger, options = {}) {
123203
+ const deps = declaration.systemDependencies;
123204
+ if (!deps || deps.length === 0) return;
123205
+ const hasBinary = options.hasBinary ?? defaultHasBinary;
123206
+ const detectManager = options.detectManager ?? defaultDetectManager;
123207
+ const run = options.run ?? defaultRun;
123208
+ const platform = options.platform ?? process.platform;
123209
+ for (const dep of deps) try {
123210
+ await satisfyOne(dep, declaration.id, {
123211
+ hasBinary,
123212
+ detectManager,
123213
+ run,
123214
+ platform
123215
+ }, logger);
123216
+ } catch (err) {
123217
+ logger.warn("system dependency step failed", { meta: {
123218
+ addonId: declaration.id,
123219
+ binary: dep.binary,
123220
+ error: err instanceof Error ? err.message : String(err)
123221
+ } });
123222
+ }
123223
+ }
123224
+ async function satisfyOne(dep, addonId, rt, logger) {
123225
+ if (await rt.hasBinary(dep.binary)) {
123226
+ logger.debug("system dependency already present", { meta: {
123227
+ addonId,
123228
+ binary: dep.binary
123229
+ } });
123230
+ return;
123231
+ }
123232
+ const manager = await rt.detectManager();
123233
+ if (manager === null) {
123234
+ logger.warn("system dependency missing and no supported package manager on this host", { meta: {
123235
+ addonId,
123236
+ binary: dep.binary,
123237
+ platform: rt.platform,
123238
+ ...dep.reason !== void 0 ? { reason: dep.reason } : {}
123239
+ } });
123240
+ return;
123241
+ }
123242
+ const packageName = dep.packages[manager];
123243
+ if (packageName === void 0 || packageName.length === 0) {
123244
+ logger.warn("system dependency missing and the addon declares no package for this manager", { meta: {
123245
+ addonId,
123246
+ binary: dep.binary,
123247
+ manager,
123248
+ ...dep.reason !== void 0 ? { reason: dep.reason } : {}
123249
+ } });
123250
+ return;
123251
+ }
123252
+ const plan = planFor(manager, packageName);
123253
+ logger.info("installing system dependency", { meta: {
123254
+ addonId,
123255
+ binary: dep.binary,
123256
+ manager,
123257
+ package: packageName
123258
+ } });
123259
+ try {
123260
+ for (const [command, args] of plan.steps) await rt.run(command, args);
123261
+ } catch (err) {
123262
+ logger.warn("system dependency install failed \u2014 the addon loads, its capability must refuse", { meta: {
123263
+ addonId,
123264
+ binary: dep.binary,
123265
+ manager,
123266
+ package: packageName,
123267
+ error: err instanceof Error ? err.message : String(err),
123268
+ ...dep.reason !== void 0 ? { reason: dep.reason } : {}
123269
+ } });
123270
+ return;
123271
+ }
123272
+ if (!await rt.hasBinary(dep.binary)) {
123273
+ logger.warn("system dependency installed but the binary still does not resolve", { meta: {
123274
+ addonId,
123275
+ binary: dep.binary,
123276
+ manager,
123277
+ package: packageName
123278
+ } });
123279
+ return;
123280
+ }
123281
+ logger.info("system dependency installed", { meta: {
123282
+ addonId,
123283
+ binary: dep.binary,
123284
+ manager,
123285
+ package: packageName
123286
+ } });
123287
+ }
123288
+ function planFor(manager, packageName) {
123289
+ switch (manager) {
123290
+ case "apt":
123291
+ return {
123292
+ manager,
123293
+ steps: [["apt-get", ["update"]], ["apt-get", [
123294
+ "install",
123295
+ "-y",
123296
+ "--no-install-recommends",
123297
+ packageName
123298
+ ]]]
123299
+ };
123300
+ case "apk":
123301
+ return {
123302
+ manager,
123303
+ steps: [["apk", [
123304
+ "add",
123305
+ "--no-cache",
123306
+ packageName
123307
+ ]]]
123308
+ };
123309
+ case "dnf":
123310
+ return {
123311
+ manager,
123312
+ steps: [["dnf", [
123313
+ "install",
123314
+ "-y",
123315
+ packageName
123316
+ ]]]
123317
+ };
123318
+ case "brew":
123319
+ return {
123320
+ manager,
123321
+ steps: [["brew", ["install", packageName]]]
123322
+ };
123323
+ }
123324
+ }
123325
+ async function defaultHasBinary(binary) {
123326
+ try {
123327
+ await execFileAsync("command", ["-v", binary], {
123328
+ timeout: PROBE_TIMEOUT_MS,
123329
+ shell: process.platform === "win32" ? false : "/bin/sh"
123330
+ });
123331
+ return true;
123332
+ } catch {
123333
+ return false;
123334
+ }
123335
+ }
123336
+ async function defaultDetectManager() {
123337
+ const candidates = node_os.platform() === "darwin" ? ["brew"] : [
123338
+ "apt",
123339
+ "apk",
123340
+ "dnf",
123341
+ "brew"
123342
+ ];
123343
+ for (const candidate of candidates) if (await defaultHasBinary(candidate === "apt" ? "apt-get" : candidate)) return candidate;
123344
+ return null;
123345
+ }
123346
+ async function defaultRun(command, args) {
123347
+ await execFileAsync(command, [...args], { timeout: INSTALL_TIMEOUT_MS });
123348
+ }
122161
123349
  Object.defineProperty(exports, "AGENT_CAP_FWD_ACTION", {
122162
123350
  enumerable: true,
122163
123351
  get: function() {
@@ -122332,6 +123520,12 @@ var require_manifest_python_deps_DVODn_qc = __commonJS({
122332
123520
  return NATIVE_PROVIDER_SERVICE_INFIX;
122333
123521
  }
122334
123522
  });
123523
+ Object.defineProperty(exports, "PARENT_ROUTED_PROVIDER_ADDON_ID", {
123524
+ enumerable: true,
123525
+ get: function() {
123526
+ return PARENT_ROUTED_PROVIDER_ADDON_ID;
123527
+ }
123528
+ });
122335
123529
  Object.defineProperty(exports, "RSS_BUDGET_REANNOUNCE_MIN_MS", {
122336
123530
  enumerable: true,
122337
123531
  get: function() {
@@ -122752,6 +123946,12 @@ var require_manifest_python_deps_DVODn_qc = __commonJS({
122752
123946
  return installManifestPythonDeps;
122753
123947
  }
122754
123948
  });
123949
+ Object.defineProperty(exports, "installManifestSystemDeps", {
123950
+ enumerable: true,
123951
+ get: function() {
123952
+ return installManifestSystemDeps;
123953
+ }
123954
+ });
122755
123955
  Object.defineProperty(exports, "ipcParentLink", {
122756
123956
  enumerable: true,
122757
123957
  get: function() {
@@ -126740,7 +127940,7 @@ var require_dist3 = __commonJS({
126740
127940
  "use strict";
126741
127941
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
126742
127942
  var require_chunk = require_chunk_Cek0wNdY();
126743
- var require_dist10 = require_dist_CDgIzo82();
127943
+ var require_dist10 = require_dist_CcvXUhHK();
126744
127944
  var require_builtins_alerts_alerts_addon = require_alerts_addon();
126745
127945
  require_alerts();
126746
127946
  var require_formatter = require_formatter_DqAKDlvN();
@@ -126766,7 +127966,7 @@ var require_dist3 = __commonJS({
126766
127966
  var require_builtins_winston_logging_index = require_winston_logging();
126767
127967
  var require_file_data_plane = require_file_data_plane_DO8KbxCe();
126768
127968
  var require_tls$1 = require_tls_BxQlomxd();
126769
- var require_manifest_python_deps = require_manifest_python_deps_DVODn_qc();
127969
+ var require_manifest_system_deps = require_manifest_system_deps_oJMkWSX();
126770
127970
  var require_resource_monitor = require_resource_monitor_CdnzxBLP();
126771
127971
  var require_custom_action_registry = require_custom_action_registry_jY0NOZK8();
126772
127972
  var zod = require_zod();
@@ -129235,7 +130435,7 @@ var require_dist3 = __commonJS({
129235
130435
  if (!node_fs.existsSync(entryPath)) throw new Error(`Entry not found: ${entryPath}`);
129236
130436
  const modUnknown = await importAddonModuleFresh(entryPath);
129237
130437
  const mod = isRecord$2(modUnknown) ? modUnknown : {};
129238
- const AddonClass = require_manifest_python_deps.resolveAddonClass(mod);
130438
+ const AddonClass = require_manifest_system_deps.resolveAddonClass(mod);
129239
130439
  if (!AddonClass) throw new Error(`No addon class in ${entryPath}`);
129240
130440
  this.addons.set(declaration.id, {
129241
130441
  declaration,
@@ -129251,7 +130451,7 @@ var require_dist3 = __commonJS({
129251
130451
  async loadFromPath(addonId, modulePath, packageName, declaration, packageVersion = "0.0.0") {
129252
130452
  const modUnknown = await importAddonModuleFresh(modulePath);
129253
130453
  const mod = isRecord$2(modUnknown) ? modUnknown : {};
129254
- const AddonClass = require_manifest_python_deps.resolveAddonClass(mod);
130454
+ const AddonClass = require_manifest_system_deps.resolveAddonClass(mod);
129255
130455
  if (!AddonClass) throw new Error(`Module ${modulePath} has no default export`);
129256
130456
  this.addons.set(addonId, {
129257
130457
  module: mod,
@@ -130154,7 +131354,7 @@ var require_dist3 = __commonJS({
130154
131354
  await node_fs.promises.writeFile(node_path.join(targetDir, "package.json"), JSON.stringify(stripBundledDeps(pkgData), null, 2));
130155
131355
  await copyDirRecursive(distDir, node_path.join(targetDir, "dist"));
130156
131356
  await copyExtraFileDirs(pkgData, sourceDir, targetDir);
130157
- require_manifest_python_deps.copyBundledNativeModules(sourceDir, targetDir, this.logger);
131357
+ require_manifest_system_deps.copyBundledNativeModules(sourceDir, targetDir, this.logger);
130158
131358
  await node_fs.promises.writeFile(node_path.join(targetDir, ".install-source"), "local");
130159
131359
  const localPkgVersion = require_dist10.asString(pkgData.version, "0.0.0");
130160
131360
  this.manifest.upsert(packageName, {
@@ -130163,7 +131363,7 @@ var require_dist3 = __commonJS({
130163
131363
  });
130164
131364
  const strippedDeps = stripBundledDeps(pkgData);
130165
131365
  if (strippedDeps["dependencies"] && typeof strippedDeps["dependencies"] === "object" && Object.keys(strippedDeps["dependencies"]).length > 0) try {
130166
- await require_manifest_python_deps.runNpm([
131366
+ await require_manifest_system_deps.runNpm([
130167
131367
  "install",
130168
131368
  "--omit=dev",
130169
131369
  "--ignore-scripts=false"
@@ -130172,7 +131372,7 @@ var require_dist3 = __commonJS({
130172
131372
  this.logger.warn(`${packageName} \u2014 npm install failed (continuing)`, { meta: { error: require_dist10.errMsg(err) } });
130173
131373
  }
130174
131374
  try {
130175
- await require_manifest_python_deps.installManifestNativeDeps(targetDir, pkgData, this.logger, this.registry, this.npmCacheDir);
131375
+ await require_manifest_system_deps.installManifestNativeDeps(targetDir, pkgData, this.logger, this.registry, this.npmCacheDir);
130176
131376
  } catch (err) {
130177
131377
  this.logger.warn(`${packageName} \u2014 native deps install failed (continuing)`, { meta: { error: require_dist10.errMsg(err) } });
130178
131378
  }
@@ -130208,7 +131408,7 @@ var require_dist3 = __commonJS({
130208
131408
  tmpDir
130209
131409
  ];
130210
131410
  if (this.registry) args.push("--registry", this.registry);
130211
- const { stdout } = await require_manifest_python_deps.runNpm(args, this.npmRunOptions(tmpDir, 12e4));
131411
+ const { stdout } = await require_manifest_system_deps.runNpm(args, this.npmRunOptions(tmpDir, 12e4));
130212
131412
  const tgzFiles = node_fs.readdirSync(tmpDir).filter((f) => f.endsWith(".tgz"));
130213
131413
  if (tgzFiles.length === 0) throw new Error(`npm pack produced no tgz. stdout: ${stdout.trim()}`);
130214
131414
  return node_path.join(tmpDir, tgzFiles[0]);
@@ -130412,7 +131612,7 @@ var require_dist3 = __commonJS({
130412
131612
  dependencies: depNames
130413
131613
  } });
130414
131614
  try {
130415
- await require_manifest_python_deps.runNpm([
131615
+ await require_manifest_system_deps.runNpm([
130416
131616
  "install",
130417
131617
  "--omit=dev",
130418
131618
  "--omit=peer",
@@ -130472,7 +131672,7 @@ var require_dist3 = __commonJS({
130472
131672
  return;
130473
131673
  }
130474
131674
  try {
130475
- await require_manifest_python_deps.installManifestNativeDeps(pkgDir, pkgView.raw, this.logger, this.registry, this.npmCacheDir);
131675
+ await require_manifest_system_deps.installManifestNativeDeps(pkgDir, pkgView.raw, this.logger, this.registry, this.npmCacheDir);
130476
131676
  } catch (nativeErr) {
130477
131677
  this.logger.error(`${packageName} \u2014 native dependency install FAILED; install ABORTED (a swapped-in copy would fail every load at the binding)`, { meta: {
130478
131678
  pkgDir,
@@ -131016,7 +132216,7 @@ var require_dist3 = __commonJS({
131016
132216
  if (!(!node_fs.existsSync(distDir) || this.isDistIncomplete(pkgData, sourceDir))) return;
131017
132217
  this.logger.info(`${packageName} \u2014 building (dist/ missing or incomplete)`);
131018
132218
  try {
131019
- await require_manifest_python_deps.runNpm(["run", "build"], this.npmRunOptions(sourceDir, 18e4));
132219
+ await require_manifest_system_deps.runNpm(["run", "build"], this.npmRunOptions(sourceDir, 18e4));
131020
132220
  } catch (err) {
131021
132221
  const msg = require_dist10.errMsg(err);
131022
132222
  this.logger.warn(`${packageName} auto-build failed`, { meta: { error: msg } });
@@ -205618,7 +206818,7 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
205618
206818
  function createCoreCapService(options) {
205619
206819
  const actions = {};
205620
206820
  for (const { actionName, invoke } of options.actions) actions[actionName] = { handler: async (ctx) => {
205621
- const raw = require_manifest_python_deps.deserializeTypedArrays(ctx.params);
206821
+ const raw = require_manifest_system_deps.deserializeTypedArrays(ctx.params);
205622
206822
  return invoke(raw !== null && typeof raw === "object" && Object.keys(raw).length === 0 ? void 0 : raw, readOrigin(ctx));
205623
206823
  } };
205624
206824
  return {
@@ -206399,7 +207599,7 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
206399
207599
  }
206400
207600
  function emitRunnerEvent(category, sourceId, data) {
206401
207601
  if (!capturedBroker) return;
206402
- require_manifest_python_deps.getBrokerEventBus(capturedBroker).emit(require_dist10.createEvent(category, {
207602
+ require_manifest_system_deps.getBrokerEventBus(capturedBroker).emit(require_dist10.createEvent(category, {
206403
207603
  type: "core",
206404
207604
  id: sourceId,
206405
207605
  nodeId: parentNodeId
@@ -206423,8 +207623,8 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
206423
207623
  ...applyRunnerNativeAllocator(process.env),
206424
207624
  ...env
206425
207625
  };
206426
- if (rssBudgetMb === void 0) delete childEnv[require_manifest_python_deps.RUNNER_RSS_BUDGET_ENV];
206427
- else childEnv[require_manifest_python_deps.RUNNER_RSS_BUDGET_ENV] = String(rssBudgetMb);
207626
+ if (rssBudgetMb === void 0) delete childEnv[require_manifest_system_deps.RUNNER_RSS_BUDGET_ENV];
207627
+ else childEnv[require_manifest_system_deps.RUNNER_RSS_BUDGET_ENV] = String(rssBudgetMb);
206428
207628
  const heapFlags = runnerHeapFlags(addons);
206429
207629
  capturedBroker?.logger.info(`[${runnerId}] heap profile: ${heavy ? "heavy" : "light"} flags=[${heapFlags.join(" ")}] arenas=${childEnv["MALLOC_ARENA_MAX"] ?? "glibc-default"} vips=${childEnv["VIPS_CONCURRENCY"] ?? "sharp-default"}`);
206430
207630
  const child = spawnFn(process.execPath, [...heapFlags, runnerPath], {
@@ -207157,12 +208357,12 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
207157
208357
  return finalJob;
207158
208358
  }
207159
208359
  };
207160
- exports.AGENT_CAP_FWD_ACTION = require_manifest_python_deps.AGENT_CAP_FWD_ACTION;
207161
- exports.AGENT_CAP_FWD_SERVICE = require_manifest_python_deps.AGENT_CAP_FWD_SERVICE;
208360
+ exports.AGENT_CAP_FWD_ACTION = require_manifest_system_deps.AGENT_CAP_FWD_ACTION;
208361
+ exports.AGENT_CAP_FWD_SERVICE = require_manifest_system_deps.AGENT_CAP_FWD_SERVICE;
207162
208362
  exports.AGENT_READINESS_SERVICE_NAME = AGENT_READINESS_SERVICE_NAME;
207163
208363
  exports.ALL_CAPABILITY_DEFINITIONS = require_dist10.ALL_CAPABILITY_DEFINITIONS;
207164
208364
  exports.AddonApiFactory = AddonApiFactory;
207165
- exports.AddonDepsManager = require_manifest_python_deps.AddonDepsManager;
208365
+ exports.AddonDepsManager = require_manifest_system_deps.AddonDepsManager;
207166
208366
  exports.AddonEngineManager = AddonEngineManager;
207167
208367
  exports.AddonHealthMonitor = AddonHealthMonitor;
207168
208368
  exports.AddonInstaller = AddonInstaller;
@@ -207177,19 +208377,19 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
207177
208377
  exports.CLUSTER_SECRET_MISMATCH_TYPE = CLUSTER_SECRET_MISMATCH_TYPE;
207178
208378
  exports.CLUSTER_SECRET_REJECTED_EXIT_CODE = CLUSTER_SECRET_REJECTED_EXIT_CODE;
207179
208379
  exports.CORE_CAP_SERVICE_NAME = CORE_CAP_SERVICE_NAME;
207180
- exports.CapRouteError = require_manifest_python_deps.CapRouteError;
207181
- exports.CapRouteResolver = require_manifest_python_deps.CapRouteResolver;
207182
- exports.CapUsageRegistry = require_manifest_python_deps.CapUsageRegistry;
207183
- exports.CapabilityHandle = require_manifest_python_deps.CapabilityHandle;
208380
+ exports.CapRouteError = require_manifest_system_deps.CapRouteError;
208381
+ exports.CapRouteResolver = require_manifest_system_deps.CapRouteResolver;
208382
+ exports.CapUsageRegistry = require_manifest_system_deps.CapUsageRegistry;
208383
+ exports.CapabilityHandle = require_manifest_system_deps.CapabilityHandle;
207184
208384
  exports.CapabilityRegistry = CapabilityRegistry;
207185
- exports.CapabilityUnavailableError = require_manifest_python_deps.CapabilityUnavailableError;
208385
+ exports.CapabilityUnavailableError = require_manifest_system_deps.CapabilityUnavailableError;
207186
208386
  exports.ConfigManager = ConfigManager;
207187
208387
  exports.ConfigStore = require_builtins_sqlite_storage_index.ConfigStore$1;
207188
208388
  exports.ConsoleDestination = require_builtins_console_logging_index.ConsoleDestination$1;
207189
208389
  exports.ConsoleLoggingAddon = require_builtins_console_logging_index.ConsoleLoggingAddon$1;
207190
208390
  exports.CoreBlocksAddon = require_builtins_core_blocks_core_blocks_addon.CoreBlocksAddon;
207191
208391
  exports.CustomActionRegistry = require_custom_action_registry.CustomActionRegistry;
207192
- exports.DECISIVE_HEAP_SPACES = require_manifest_python_deps.DECISIVE_HEAP_SPACES;
208392
+ exports.DECISIVE_HEAP_SPACES = require_manifest_system_deps.DECISIVE_HEAP_SPACES;
207193
208393
  exports.DEFAULT_DATA_PATH = DEFAULT_DATA_PATH;
207194
208394
  exports.DEFAULT_LAN_HTTP_PORT = require_tls$1.DEFAULT_LAN_HTTP_PORT;
207195
208395
  exports.DEFAULT_LOG_LEVEL = DEFAULT_LOG_LEVEL;
@@ -207197,33 +208397,33 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
207197
208397
  exports.DEVICE_STATUS_METHOD = require_dist10.DEVICE_STATUS_METHOD;
207198
208398
  exports.DataPlaneRegistry = DataPlaneRegistry;
207199
208399
  exports.DeviceManagerAddon = require_builtins_device_manager_device_manager_addon.DeviceManagerAddon;
207200
- exports.DeviceRegistry = require_manifest_python_deps.DeviceRegistry;
208400
+ exports.DeviceRegistry = require_manifest_system_deps.DeviceRegistry;
207201
208401
  exports.DeviceStore = require_builtins_sqlite_storage_index.DeviceStore$1;
207202
- exports.EMPTY_SOCKET_DIRECTION = require_manifest_python_deps.EMPTY_SOCKET_DIRECTION;
207203
- exports.EMPTY_SOCKET_PLANE_BASELINE = require_manifest_python_deps.EMPTY_SOCKET_PLANE_BASELINE;
207204
- exports.EVENT_PLANE_TOP_N = require_manifest_python_deps.EVENT_PLANE_TOP_N;
207205
- exports.EVENT_TOPIC_PREFIX = require_manifest_python_deps.EVENT_TOPIC_PREFIX;
208402
+ exports.EMPTY_SOCKET_DIRECTION = require_manifest_system_deps.EMPTY_SOCKET_DIRECTION;
208403
+ exports.EMPTY_SOCKET_PLANE_BASELINE = require_manifest_system_deps.EMPTY_SOCKET_PLANE_BASELINE;
208404
+ exports.EVENT_PLANE_TOP_N = require_manifest_system_deps.EVENT_PLANE_TOP_N;
208405
+ exports.EVENT_TOPIC_PREFIX = require_manifest_system_deps.EVENT_TOPIC_PREFIX;
207206
208406
  exports.EngineManagerResolver = EngineManagerResolver;
207207
208407
  exports.EventBus = EventBus;
207208
208408
  exports.FeatureManager = FeatureManager;
207209
208409
  exports.FilesystemStorageAddon = require_builtins_sqlite_storage_filesystem_storage_addon.FilesystemStorageAddon;
207210
208410
  exports.FilesystemStorageProvider = require_builtins_sqlite_storage_filesystem_storage_addon.FilesystemStorageProvider;
207211
- exports.FrameDecoder = require_manifest_python_deps.FrameDecoder;
208411
+ exports.FrameDecoder = require_manifest_system_deps.FrameDecoder;
207212
208412
  exports.FsStorageBackend = FsStorageBackend;
207213
208413
  exports.HEALTH_MONITOR_GRACE_PERIOD_MS = HEALTH_MONITOR_GRACE_PERIOD_MS;
207214
208414
  exports.HEALTH_MONITOR_RETRY_INTERVALS_MS = HEALTH_MONITOR_RETRY_INTERVALS_MS;
207215
208415
  exports.HEALTH_MONITOR_TICK_MS = HEALTH_MONITOR_TICK_MS;
207216
- exports.HEAP_RECLAIM_MIN_INTERVAL_MS = require_manifest_python_deps.HEAP_RECLAIM_MIN_INTERVAL_MS;
207217
- exports.HEAP_RECLAIM_STEADY_STATE_INTERVAL_MS = require_manifest_python_deps.HEAP_RECLAIM_STEADY_STATE_INTERVAL_MS;
207218
- exports.HEAP_RECLAIM_TRIGGER_MB = require_manifest_python_deps.HEAP_RECLAIM_TRIGGER_MB;
207219
- exports.HEAP_SPACE_REPORT_MIN_MB = require_manifest_python_deps.HEAP_SPACE_REPORT_MIN_MB;
207220
- exports.HEAP_WATCH_INTERVAL_MS = require_manifest_python_deps.HEAP_WATCH_INTERVAL_MS;
207221
- exports.HEAP_WATCH_WARN_RATIO = require_manifest_python_deps.HEAP_WATCH_WARN_RATIO;
207222
- exports.HUB_CAP_FWD_ACTION = require_manifest_python_deps.HUB_CAP_FWD_ACTION;
207223
- exports.HUB_CAP_FWD_SERVICE = require_manifest_python_deps.HUB_CAP_FWD_SERVICE;
207224
- exports.HUB_MAIN_HEAP_WATCH_LABEL = require_manifest_python_deps.HUB_MAIN_HEAP_WATCH_LABEL;
207225
- exports.HUB_MAIN_RSS_BUDGET_MB = require_manifest_python_deps.HUB_MAIN_RSS_BUDGET_MB;
207226
- exports.HUB_RSS_BUDGET_ENV = require_manifest_python_deps.HUB_RSS_BUDGET_ENV;
208416
+ exports.HEAP_RECLAIM_MIN_INTERVAL_MS = require_manifest_system_deps.HEAP_RECLAIM_MIN_INTERVAL_MS;
208417
+ exports.HEAP_RECLAIM_STEADY_STATE_INTERVAL_MS = require_manifest_system_deps.HEAP_RECLAIM_STEADY_STATE_INTERVAL_MS;
208418
+ exports.HEAP_RECLAIM_TRIGGER_MB = require_manifest_system_deps.HEAP_RECLAIM_TRIGGER_MB;
208419
+ exports.HEAP_SPACE_REPORT_MIN_MB = require_manifest_system_deps.HEAP_SPACE_REPORT_MIN_MB;
208420
+ exports.HEAP_WATCH_INTERVAL_MS = require_manifest_system_deps.HEAP_WATCH_INTERVAL_MS;
208421
+ exports.HEAP_WATCH_WARN_RATIO = require_manifest_system_deps.HEAP_WATCH_WARN_RATIO;
208422
+ exports.HUB_CAP_FWD_ACTION = require_manifest_system_deps.HUB_CAP_FWD_ACTION;
208423
+ exports.HUB_CAP_FWD_SERVICE = require_manifest_system_deps.HUB_CAP_FWD_SERVICE;
208424
+ exports.HUB_MAIN_HEAP_WATCH_LABEL = require_manifest_system_deps.HUB_MAIN_HEAP_WATCH_LABEL;
208425
+ exports.HUB_MAIN_RSS_BUDGET_MB = require_manifest_system_deps.HUB_MAIN_RSS_BUDGET_MB;
208426
+ exports.HUB_RSS_BUDGET_ENV = require_manifest_system_deps.HUB_RSS_BUDGET_ENV;
207227
208427
  exports.HubForwarderAddon = require_builtins_hub_forwarder_index.HubForwarderAddon$1;
207228
208428
  exports.HubForwarderDestination = require_builtins_hub_forwarder_index.HubForwarderDestination$1;
207229
208429
  exports.HubLogForwarder = HubLogForwarder;
@@ -207236,8 +208436,8 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
207236
208436
  exports.LifecycleStateMachine = LifecycleStateMachine;
207237
208437
  exports.LivenessMonitorAddon = require_builtins_liveness_monitor_liveness_monitor_addon.LivenessMonitorAddon;
207238
208438
  exports.LocalAuthAddon = require_builtins_local_auth_local_auth_addon.LocalAuthAddon;
207239
- exports.LocalChildClient = require_manifest_python_deps.LocalChildClient;
207240
- exports.LocalChildRegistry = require_manifest_python_deps.LocalChildRegistry;
208439
+ exports.LocalChildClient = require_manifest_system_deps.LocalChildClient;
208440
+ exports.LocalChildRegistry = require_manifest_system_deps.LocalChildRegistry;
207241
208441
  exports.LogManager = LogManager;
207242
208442
  exports.LogRingBuffer = LogRingBuffer;
207243
208443
  exports.LoggingGate = LoggingGate;
@@ -207246,12 +208446,13 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
207246
208446
  exports.MAX_LEAF_VALIDITY_DAYS = require_tls$1.MAX_LEAF_VALIDITY_DAYS;
207247
208447
  exports.METHOD_ACCESS_MAP = require_dist10.METHOD_ACCESS_MAP;
207248
208448
  exports.ModelDownloadService = require_file_data_plane.ModelDownloadService;
207249
- exports.NATIVE_PROVIDER_SERVICE_INFIX = require_manifest_python_deps.NATIVE_PROVIDER_SERVICE_INFIX;
208449
+ exports.NATIVE_PROVIDER_SERVICE_INFIX = require_manifest_system_deps.NATIVE_PROVIDER_SERVICE_INFIX;
207250
208450
  exports.NATIVE_SCAN_DEPTH = NATIVE_SCAN_DEPTH;
207251
208451
  exports.NativeMetricsAddon = require_builtins_native_metrics_native_metrics_addon.default;
207252
208452
  exports.NativeMetricsProvider = require_builtins_native_metrics_native_metrics_addon.NativeMetricsProvider;
207253
208453
  exports.NetworkQualityTracker = NetworkQualityTracker;
207254
208454
  exports.NotificationService = NotificationService;
208455
+ exports.PARENT_ROUTED_PROVIDER_ADDON_ID = require_manifest_system_deps.PARENT_ROUTED_PROVIDER_ADDON_ID;
207255
208456
  Object.defineProperty(exports, "PYTHON_VERSION", {
207256
208457
  enumerable: true,
207257
208458
  get: function() {
@@ -207263,21 +208464,21 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
207263
208464
  exports.PythonEnvManager = PythonEnvManager;
207264
208465
  exports.QUARANTINE_DIRNAME = QUARANTINE_DIRNAME;
207265
208466
  exports.RESTART_MARKER_FILE = RESTART_MARKER_FILE;
207266
- exports.RSS_BUDGET_REANNOUNCE_MIN_MS = require_manifest_python_deps.RSS_BUDGET_REANNOUNCE_MIN_MS;
207267
- exports.RSS_BUDGET_RELEASE_RATIO = require_manifest_python_deps.RSS_BUDGET_RELEASE_RATIO;
207268
- exports.RUNNER_HEAP_SNAPSHOT_ENV = require_manifest_python_deps.RUNNER_HEAP_SNAPSHOT_ENV;
207269
- exports.RUNNER_HEAP_WATCH_INTERVAL_MS = require_manifest_python_deps.RUNNER_HEAP_WATCH_INTERVAL_MS;
207270
- exports.RUNNER_RSS_BUDGET_ENV = require_manifest_python_deps.RUNNER_RSS_BUDGET_ENV;
208467
+ exports.RSS_BUDGET_REANNOUNCE_MIN_MS = require_manifest_system_deps.RSS_BUDGET_REANNOUNCE_MIN_MS;
208468
+ exports.RSS_BUDGET_RELEASE_RATIO = require_manifest_system_deps.RSS_BUDGET_RELEASE_RATIO;
208469
+ exports.RUNNER_HEAP_SNAPSHOT_ENV = require_manifest_system_deps.RUNNER_HEAP_SNAPSHOT_ENV;
208470
+ exports.RUNNER_HEAP_WATCH_INTERVAL_MS = require_manifest_system_deps.RUNNER_HEAP_WATCH_INTERVAL_MS;
208471
+ exports.RUNNER_RSS_BUDGET_ENV = require_manifest_system_deps.RUNNER_RSS_BUDGET_ENV;
207271
208472
  exports.RUNTIME_DEFAULTS = require_dist10.RUNTIME_DEFAULTS;
207272
208473
  exports.ReadinessRegistry = require_dist10.ReadinessRegistry;
207273
208474
  exports.ReadinessTimeoutError = require_dist10.ReadinessTimeoutError;
207274
208475
  exports.ReplEngine = ReplEngine;
207275
208476
  exports.RingBuffer = RingBuffer;
207276
208477
  exports.SERVER_AUTH_OID = require_tls$1.SERVER_AUTH_OID;
207277
- exports.SOCKET_PLANE_TOP_N = require_manifest_python_deps.SOCKET_PLANE_TOP_N;
208478
+ exports.SOCKET_PLANE_TOP_N = require_manifest_system_deps.SOCKET_PLANE_TOP_N;
207278
208479
  exports.ScopedLogger = ScopedLogger;
207279
208480
  exports.ScopedTokenManager = require_builtins_local_auth_local_auth_addon.ScopedTokenManager;
207280
- exports.SocketChannel = require_manifest_python_deps.SocketChannel;
208481
+ exports.SocketChannel = require_manifest_system_deps.SocketChannel;
207281
208482
  exports.SqliteSettingsAddon = require_builtins_sqlite_storage_sqlite_settings_addon.SqliteSettingsAddon;
207282
208483
  exports.SqliteSettingsBackend = require_builtins_sqlite_storage_sqlite_settings_addon.SqliteSettingsBackend;
207283
208484
  exports.StagingArea = StagingArea;
@@ -207289,23 +208490,23 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
207289
208490
  exports.SystemEventBus = SystemEventBus;
207290
208491
  exports.TRADITIONAL_NATIVE_PACKAGES = TRADITIONAL_NATIVE_PACKAGES;
207291
208492
  exports.ToastService = ToastService;
207292
- exports.UDS_NO_ROUTE_PREFIX = require_manifest_python_deps.UDS_NO_ROUTE_PREFIX;
207293
- exports.UdsLocalTransportClient = require_manifest_python_deps.UdsLocalTransportClient;
207294
- exports.UdsLocalTransportServer = require_manifest_python_deps.UdsLocalTransportServer;
208493
+ exports.UDS_NO_ROUTE_PREFIX = require_manifest_system_deps.UDS_NO_ROUTE_PREFIX;
208494
+ exports.UdsLocalTransportClient = require_manifest_system_deps.UdsLocalTransportClient;
208495
+ exports.UdsLocalTransportServer = require_manifest_system_deps.UdsLocalTransportServer;
207295
208496
  exports.UserManager = require_builtins_local_auth_local_auth_addon.UserManager;
207296
208497
  exports.WinstonDestination = require_builtins_winston_logging_index.WinstonDestination$1;
207297
208498
  exports.WinstonLoggingAddon = require_builtins_winston_logging_index.WinstonLoggingAddon$1;
207298
- exports.ZERO_LOOP_DELAY = require_manifest_python_deps.ZERO_LOOP_DELAY;
207299
- exports.__resetCapUsageRegistryForTests = require_manifest_python_deps.__resetCapUsageRegistryForTests;
208499
+ exports.ZERO_LOOP_DELAY = require_manifest_system_deps.ZERO_LOOP_DELAY;
208500
+ exports.__resetCapUsageRegistryForTests = require_manifest_system_deps.__resetCapUsageRegistryForTests;
207300
208501
  exports.__resetLoggingGateForTests = __resetLoggingGateForTests;
207301
- exports.adaptBrokerToCluster = require_manifest_python_deps.adaptBrokerToCluster;
208502
+ exports.adaptBrokerToCluster = require_manifest_system_deps.adaptBrokerToCluster;
207302
208503
  exports.addonSettingsCapability = require_dist10.addonSettingsCapability;
207303
208504
  exports.allFamiliesListenHost = require_tls$1.allFamiliesListenHost;
207304
208505
  exports.applyLanHttp = require_tls$1.applyLanHttp;
207305
208506
  exports.bindPendingLanHttp = require_tls$1.bindPendingLanHttp;
207306
208507
  exports.bootstrapSchema = bootstrapSchema;
207307
- exports.brokerCallForCap = require_manifest_python_deps.brokerCallForCap;
207308
- exports.brokerTransportLink = require_manifest_python_deps.brokerTransportLink;
208508
+ exports.brokerCallForCap = require_manifest_system_deps.brokerCallForCap;
208509
+ exports.brokerTransportLink = require_manifest_system_deps.brokerTransportLink;
207309
208510
  Object.defineProperty(exports, "buildBinaryPath", {
207310
208511
  enumerable: true,
207311
208512
  get: function() {
@@ -207313,70 +208514,70 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
207313
208514
  }
207314
208515
  });
207315
208516
  exports.buildCapRouters = buildCapRouters;
207316
- exports.buildHeapSample = require_manifest_python_deps.buildHeapSample;
207317
- exports.buildLinkChain = require_manifest_python_deps.buildLinkChain;
207318
- exports.buildNativeCapProxy = require_manifest_python_deps.buildNativeCapProxy;
208517
+ exports.buildHeapSample = require_manifest_system_deps.buildHeapSample;
208518
+ exports.buildLinkChain = require_manifest_system_deps.buildLinkChain;
208519
+ exports.buildNativeCapProxy = require_manifest_system_deps.buildNativeCapProxy;
207319
208520
  exports.buildNodeManifest = buildNodeManifest;
207320
208521
  exports.buildStorageLocationRegistry = require_builtins_storage_orchestrator_storage_orchestrator_addon.buildStorageLocationRegistry;
207321
- exports.buildUdsNativeCapProxy = require_manifest_python_deps.buildUdsNativeCapProxy;
208522
+ exports.buildUdsNativeCapProxy = require_manifest_system_deps.buildUdsNativeCapProxy;
207322
208523
  exports.builderMountedCapNames = builderMountedCapNames;
207323
208524
  exports.callRegisterNodeWithRetry = callRegisterNodeWithRetry;
207324
- exports.callWithServiceDiscovery = require_manifest_python_deps.callWithServiceDiscovery;
208525
+ exports.callWithServiceDiscovery = require_manifest_system_deps.callWithServiceDiscovery;
207325
208526
  exports.canServeDataPlane = canServeDataPlane;
207326
- exports.capActionName = require_manifest_python_deps.capActionName;
207327
- exports.capActionSuffix = require_manifest_python_deps.capActionSuffix;
207328
- exports.capBareAction = require_manifest_python_deps.capBareAction;
207329
- exports.capServiceName = require_manifest_python_deps.capServiceName;
208527
+ exports.capActionName = require_manifest_system_deps.capActionName;
208528
+ exports.capActionSuffix = require_manifest_system_deps.capActionSuffix;
208529
+ exports.capBareAction = require_manifest_system_deps.capBareAction;
208530
+ exports.capServiceName = require_manifest_system_deps.capServiceName;
207330
208531
  exports.classifyAddonDir = classifyAddonDir;
207331
- exports.classifyCapRoute = require_manifest_python_deps.classifyCapRoute;
208532
+ exports.classifyCapRoute = require_manifest_system_deps.classifyCapRoute;
207332
208533
  exports.clearPendingRestart = clearPendingRestart;
207333
208534
  exports.closeLanHttp = require_tls$1.closeLanHttp;
207334
- exports.clusterEventTopic = require_manifest_python_deps.clusterEventTopic;
208535
+ exports.clusterEventTopic = require_manifest_system_deps.clusterEventTopic;
207335
208536
  exports.clusterSecretMatches = clusterSecretMatches;
207336
208537
  exports.collectCertIdentity = require_tls$1.collectCertIdentity;
207337
208538
  exports.collectModelFiles = require_file_data_plane.collectModelFiles;
207338
208539
  exports.contentTypeFor = require_file_data_plane.contentTypeFor;
207339
208540
  exports.copyDirRecursive = copyDirRecursive;
207340
208541
  exports.copyExtraFileDirs = copyExtraFileDirs;
207341
- exports.createAddonContext = require_manifest_python_deps.createAddonContext;
207342
- exports.createAddonDataPlaneFacility = require_manifest_python_deps.createAddonDataPlaneFacility;
207343
- exports.createAddonService = require_manifest_python_deps.createAddonService;
208542
+ exports.createAddonContext = require_manifest_system_deps.createAddonContext;
208543
+ exports.createAddonDataPlaneFacility = require_manifest_system_deps.createAddonDataPlaneFacility;
208544
+ exports.createAddonService = require_manifest_system_deps.createAddonService;
207344
208545
  exports.createAuthenticatedFileServer = require_file_data_plane.createAuthenticatedFileServer;
207345
208546
  exports.createBroker = createBroker2;
207346
- exports.createBrokerDeviceManagerApi = require_manifest_python_deps.createBrokerDeviceManagerApi;
208547
+ exports.createBrokerDeviceManagerApi = require_manifest_system_deps.createBrokerDeviceManagerApi;
207347
208548
  exports.createCoreCapService = createCoreCapService;
207348
- exports.createDeferredHeapWatchSink = require_manifest_python_deps.createDeferredHeapWatchSink;
208549
+ exports.createDeferredHeapWatchSink = require_manifest_system_deps.createDeferredHeapWatchSink;
207349
208550
  exports.createDoorSettingsView = createDoorSettingsView;
207350
- exports.createEventPlaneMeter = require_manifest_python_deps.createEventPlaneMeter;
207351
- exports.createEventPlaneReader = require_manifest_python_deps.createEventPlaneReader;
208551
+ exports.createEventPlaneMeter = require_manifest_system_deps.createEventPlaneMeter;
208552
+ exports.createEventPlaneReader = require_manifest_system_deps.createEventPlaneReader;
207352
208553
  exports.createFileDataPlaneHandler = require_file_data_plane.createFileDataPlaneHandler;
207353
- exports.createHubCapForwardService = require_manifest_python_deps.createHubCapForwardService;
208554
+ exports.createHubCapForwardService = require_manifest_system_deps.createHubCapForwardService;
207354
208555
  exports.createHubService = createHubService;
207355
- exports.createKernelHwAccel = require_manifest_python_deps.createKernelHwAccel;
207356
- exports.createLocalTransport = require_manifest_python_deps.createLocalTransport;
207357
- exports.createLoopDelayMeter = require_manifest_python_deps.createLoopDelayMeter;
207358
- exports.createParentUnownedCallHandler = require_manifest_python_deps.createParentUnownedCallHandler;
208556
+ exports.createKernelHwAccel = require_manifest_system_deps.createKernelHwAccel;
208557
+ exports.createLocalTransport = require_manifest_system_deps.createLocalTransport;
208558
+ exports.createLoopDelayMeter = require_manifest_system_deps.createLoopDelayMeter;
208559
+ exports.createParentUnownedCallHandler = require_manifest_system_deps.createParentUnownedCallHandler;
207359
208560
  exports.createProcessService = createProcessService;
207360
208561
  exports.createReadinessService = createReadinessService;
207361
208562
  exports.createReadinessServiceForRegistry = createReadinessServiceForRegistry;
207362
208563
  exports.createScopedProcessManager = createScopedProcessManager;
207363
- exports.createSocketDirectionCounters = require_manifest_python_deps.createSocketDirectionCounters;
207364
- exports.createSocketPlaneMeter = require_manifest_python_deps.createSocketPlaneMeter;
207365
- exports.createSocketPlaneReader = require_manifest_python_deps.createSocketPlaneReader;
208564
+ exports.createSocketDirectionCounters = require_manifest_system_deps.createSocketDirectionCounters;
208565
+ exports.createSocketPlaneMeter = require_manifest_system_deps.createSocketPlaneMeter;
208566
+ exports.createSocketPlaneReader = require_manifest_system_deps.createSocketPlaneReader;
207366
208567
  exports.createStreamProbeBrokerService = createStreamProbeBrokerService;
207367
- exports.createUdsAddonContext = require_manifest_python_deps.createUdsAddonContext;
207368
- exports.createUdsEventBridge = require_manifest_python_deps.createUdsEventBridge;
207369
- exports.createUdsEventBus = require_manifest_python_deps.createUdsEventBus;
207370
- exports.createUdsLogger = require_manifest_python_deps.createUdsLogger;
207371
- exports.createUdsLoggerWithControl = require_manifest_python_deps.createUdsLoggerWithControl;
207372
- exports.createV8Reclaimer = require_manifest_python_deps.createV8Reclaimer;
208568
+ exports.createUdsAddonContext = require_manifest_system_deps.createUdsAddonContext;
208569
+ exports.createUdsEventBridge = require_manifest_system_deps.createUdsEventBridge;
208570
+ exports.createUdsEventBus = require_manifest_system_deps.createUdsEventBus;
208571
+ exports.createUdsLogger = require_manifest_system_deps.createUdsLogger;
208572
+ exports.createUdsLoggerWithControl = require_manifest_system_deps.createUdsLoggerWithControl;
208573
+ exports.createV8Reclaimer = require_manifest_system_deps.createV8Reclaimer;
207373
208574
  exports.deleteModelFromDisk = require_file_data_plane.deleteModelFromDisk;
207374
208575
  exports.deriveAgentListenPort = deriveAgentListenPort;
207375
208576
  exports.describeProviderKindDrift = describeProviderKindDrift;
207376
- exports.describeRss = require_manifest_python_deps.describeRss;
208577
+ exports.describeRss = require_manifest_system_deps.describeRss;
207377
208578
  exports.detectWorkspacePackagesDir = detectWorkspacePackagesDir;
207378
- exports.diffEventPlane = require_manifest_python_deps.diffEventPlane;
207379
- exports.diffSocketPlane = require_manifest_python_deps.diffSocketPlane;
208579
+ exports.diffEventPlane = require_manifest_system_deps.diffEventPlane;
208580
+ exports.diffSocketPlane = require_manifest_system_deps.diffSocketPlane;
207380
208581
  Object.defineProperty(exports, "downloadBinary", {
207381
208582
  enumerable: true,
207382
208583
  get: function() {
@@ -207386,8 +208587,8 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
207386
208587
  exports.downloadFile = require_file_data_plane.downloadFile;
207387
208588
  exports.downloadModel = require_file_data_plane.downloadModel;
207388
208589
  exports.emitDownForOwnedCaps = require_dist10.emitDownForOwnedCaps;
207389
- exports.emitHeapDiagnosticReport = require_manifest_python_deps.emitHeapDiagnosticReport;
207390
- exports.encodeFrame = require_manifest_python_deps.encodeFrame;
208590
+ exports.emitHeapDiagnosticReport = require_manifest_system_deps.emitHeapDiagnosticReport;
208591
+ exports.encodeFrame = require_manifest_system_deps.encodeFrame;
207391
208592
  exports.ensureAddonNativePrebuilds = ensureAddonNativePrebuilds;
207392
208593
  Object.defineProperty(exports, "ensureBinary", {
207393
208594
  enumerable: true,
@@ -207421,12 +208622,12 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
207421
208622
  return _camstack_types_node.findInPath;
207422
208623
  }
207423
208624
  });
207424
- exports.formatEventPlane = require_manifest_python_deps.formatEventPlane;
207425
- exports.formatHeapSpaces = require_manifest_python_deps.formatHeapSpaces;
208625
+ exports.formatEventPlane = require_manifest_system_deps.formatEventPlane;
208626
+ exports.formatHeapSpaces = require_manifest_system_deps.formatHeapSpaces;
207426
208627
  exports.formatLogLine = require_formatter.formatLogLine;
207427
- exports.formatSocketPlane = require_manifest_python_deps.formatSocketPlane;
207428
- exports.getBrokerEventBus = require_manifest_python_deps.getBrokerEventBus;
207429
- exports.getCapUsageRegistry = require_manifest_python_deps.getCapUsageRegistry;
208628
+ exports.formatSocketPlane = require_manifest_system_deps.formatSocketPlane;
208629
+ exports.getBrokerEventBus = require_manifest_system_deps.getBrokerEventBus;
208630
+ exports.getCapUsageRegistry = require_manifest_system_deps.getCapUsageRegistry;
207430
208631
  Object.defineProperty(exports, "getFfmpegDownloadUrl", {
207431
208632
  enumerable: true,
207432
208633
  get: function() {
@@ -207435,9 +208636,9 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
207435
208636
  });
207436
208637
  exports.getLoggingGate = getLoggingGate;
207437
208638
  exports.getModelFilePath = require_file_data_plane.getModelFilePath;
207438
- exports.getMoleculerEventStats = require_manifest_python_deps.getMoleculerEventStats;
207439
- exports.getOrInitReadinessRegistry = require_manifest_python_deps.getOrInitReadinessRegistry;
207440
- exports.getOrInitReadinessRegistryForClient = require_manifest_python_deps.getOrInitReadinessRegistryForClient;
208639
+ exports.getMoleculerEventStats = require_manifest_system_deps.getMoleculerEventStats;
208640
+ exports.getOrInitReadinessRegistry = require_manifest_system_deps.getOrInitReadinessRegistry;
208641
+ exports.getOrInitReadinessRegistryForClient = require_manifest_system_deps.getOrInitReadinessRegistryForClient;
207441
208642
  exports.getPidStats = require_resource_monitor.getPidStats;
207442
208643
  Object.defineProperty(exports, "getPlatformInfo", {
207443
208644
  enumerable: true,
@@ -207453,14 +208654,15 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
207453
208654
  });
207454
208655
  exports.getRestartMarkerPath = getRestartMarkerPath;
207455
208656
  exports.getSinglePidStats = require_resource_monitor.getSinglePidStats;
207456
- exports.getWorkerDeviceRegistry = require_manifest_python_deps.getWorkerDeviceRegistry;
208657
+ exports.getWorkerDeviceRegistry = require_manifest_system_deps.getWorkerDeviceRegistry;
207457
208658
  exports.hasDotNode = hasDotNode;
207458
208659
  exports.hashClusterSecret = hashClusterSecret;
207459
- exports.heapSnapshotAuthorised = require_manifest_python_deps.heapSnapshotAuthorised;
207460
- exports.heapSpaceField = require_manifest_python_deps.heapSpaceField;
207461
- exports.hubMainRssBudget = require_manifest_python_deps.hubMainRssBudget;
207462
- exports.installManifestNativeDeps = require_manifest_python_deps.installManifestNativeDeps;
207463
- exports.installManifestPythonDeps = require_manifest_python_deps.installManifestPythonDeps;
208660
+ exports.heapSnapshotAuthorised = require_manifest_system_deps.heapSnapshotAuthorised;
208661
+ exports.heapSpaceField = require_manifest_system_deps.heapSpaceField;
208662
+ exports.hubMainRssBudget = require_manifest_system_deps.hubMainRssBudget;
208663
+ exports.installManifestNativeDeps = require_manifest_system_deps.installManifestNativeDeps;
208664
+ exports.installManifestPythonDeps = require_manifest_system_deps.installManifestPythonDeps;
208665
+ exports.installManifestSystemDeps = require_manifest_system_deps.installManifestSystemDeps;
207464
208666
  exports.installPackageFromNpm = installPackageFromNpm;
207465
208667
  Object.defineProperty(exports, "installPythonPackages", {
207466
208668
  enumerable: true,
@@ -207474,7 +208676,7 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
207474
208676
  return _camstack_types_node.installPythonRequirements;
207475
208677
  }
207476
208678
  });
207477
- exports.ipcParentLink = require_manifest_python_deps.ipcParentLink;
208679
+ exports.ipcParentLink = require_manifest_system_deps.ipcParentLink;
207478
208680
  exports.isAddonDeploySource = isAddonDeploySource;
207479
208681
  exports.isArrayOutputSchema = require_dist10.isArrayOutputSchema;
207480
208682
  exports.isClusterSecretMismatchError = isClusterSecretMismatchError;
@@ -207484,55 +208686,55 @@ globstar while`, t, d, e, f, m), this.matchOne(t.slice(d), e.slice(f), s)) retur
207484
208686
  exports.isSourceNewer = isSourceNewer;
207485
208687
  exports.isolatedBuiltinPhase = isolatedBuiltinPhase;
207486
208688
  exports.loadTlsCert = require_tls$1.loadTlsCert;
207487
- exports.localEndpointPath = require_manifest_python_deps.localEndpointPath;
207488
- exports.localProviderLink = require_manifest_python_deps.localProviderLink;
207489
- exports.mountNativeCapService = require_manifest_python_deps.mountNativeCapService;
207490
- exports.nextRssBudgetState = require_manifest_python_deps.nextRssBudgetState;
207491
- exports.parseCapAction = require_manifest_python_deps.parseCapAction;
208689
+ exports.localEndpointPath = require_manifest_system_deps.localEndpointPath;
208690
+ exports.localProviderLink = require_manifest_system_deps.localProviderLink;
208691
+ exports.mountNativeCapService = require_manifest_system_deps.mountNativeCapService;
208692
+ exports.nextRssBudgetState = require_manifest_system_deps.nextRssBudgetState;
208693
+ exports.parseCapAction = require_manifest_system_deps.parseCapAction;
207492
208694
  exports.parseRangeHeader = require_file_data_plane.parseRangeHeader;
207493
- exports.parseRssBudgetMb = require_manifest_python_deps.parseRssBudgetMb;
208695
+ exports.parseRssBudgetMb = require_manifest_system_deps.parseRssBudgetMb;
207494
208696
  exports.parseTokenizedUrl = require_file_data_plane.parseTokenizedUrl;
207495
208697
  exports.partitionIsolatedBuiltinIds = partitionIsolatedBuiltinIds;
207496
208698
  exports.proxyToUpstream = proxyToUpstream;
207497
208699
  exports.quarantineAddonResidue = quarantineAddonResidue;
207498
208700
  exports.readExtraSans = require_tls$1.readExtraSans;
207499
- exports.readHeapSpaces = require_manifest_python_deps.readHeapSpaces;
208701
+ exports.readHeapSpaces = require_manifest_system_deps.readHeapSpaces;
207500
208702
  exports.readLanHttpState = require_tls$1.readLanHttpState;
207501
- exports.readMoleculerFanoutMode = require_manifest_python_deps.readMoleculerFanoutMode;
208703
+ exports.readMoleculerFanoutMode = require_manifest_system_deps.readMoleculerFanoutMode;
207502
208704
  exports.readPendingRestart = readPendingRestart;
207503
208705
  exports.readTlsAccessStatus = require_tls$1.readTlsAccessStatus;
207504
208706
  exports.readTlsMode = require_tls$1.readTlsMode;
207505
208707
  exports.readinessKey = require_dist10.readinessKey;
207506
- exports.reclaimIntervalMs = require_manifest_python_deps.reclaimIntervalMs;
207507
- exports.recordSocketFrame = require_manifest_python_deps.recordSocketFrame;
207508
- exports.registerEventBusService = require_manifest_python_deps.registerEventBusService;
208708
+ exports.reclaimIntervalMs = require_manifest_system_deps.reclaimIntervalMs;
208709
+ exports.recordSocketFrame = require_manifest_system_deps.recordSocketFrame;
208710
+ exports.registerEventBusService = require_manifest_system_deps.registerEventBusService;
207509
208711
  exports.registerLanHttpHandler = require_tls$1.registerLanHttpHandler;
207510
208712
  exports.reissueTlsLeaf = require_tls$1.reissueTlsLeaf;
207511
208713
  exports.resolveFilePath = require_file_data_plane.resolveFilePath;
207512
- exports.resolveHwAccel = require_manifest_python_deps.resolveHwAccel;
207513
- exports.resolveNpmInvocation = require_manifest_python_deps.resolveNpmInvocation;
208714
+ exports.resolveHwAccel = require_manifest_system_deps.resolveHwAccel;
208715
+ exports.resolveNpmInvocation = require_manifest_system_deps.resolveNpmInvocation;
207514
208716
  exports.runHubAddonBoot = runHubAddonBoot;
207515
- exports.runNpm = require_manifest_python_deps.runNpm;
207516
- exports.sampleSocketDirection = require_manifest_python_deps.sampleSocketDirection;
208717
+ exports.runNpm = require_manifest_system_deps.runNpm;
208718
+ exports.sampleSocketDirection = require_manifest_system_deps.sampleSocketDirection;
207517
208719
  exports.scheduleSelfRestart = scheduleSelfRestart;
207518
208720
  exports.scopeKey = require_dist10.scopeKey;
207519
208721
  exports.scopesAllowAddon = require_dist10.scopesAllowAddon;
207520
208722
  exports.scopesAllowDeviceCap = require_dist10.scopesAllowDeviceCap;
207521
208723
  exports.selectAddonResidue = selectAddonResidue;
207522
- exports.selectReportedSpaces = require_manifest_python_deps.selectReportedSpaces;
207523
- exports.serializeTypedArrays = require_manifest_python_deps.serializeTypedArrays;
207524
- exports.setHubConnected = require_manifest_python_deps.setHubConnected;
207525
- exports.setNodeEventInterest = require_manifest_python_deps.setNodeEventInterest;
207526
- exports.shouldReclaim = require_manifest_python_deps.shouldReclaim;
207527
- exports.socketDirectionBytes = require_manifest_python_deps.socketDirectionBytes;
207528
- exports.socketDirectionMessages = require_manifest_python_deps.socketDirectionMessages;
207529
- exports.startHeapWatch = require_manifest_python_deps.startHeapWatch;
207530
- exports.startRunnerHeapWatch = require_manifest_python_deps.startRunnerHeapWatch;
207531
- exports.strandedMb = require_manifest_python_deps.strandedMb;
208724
+ exports.selectReportedSpaces = require_manifest_system_deps.selectReportedSpaces;
208725
+ exports.serializeTypedArrays = require_manifest_system_deps.serializeTypedArrays;
208726
+ exports.setHubConnected = require_manifest_system_deps.setHubConnected;
208727
+ exports.setNodeEventInterest = require_manifest_system_deps.setNodeEventInterest;
208728
+ exports.shouldReclaim = require_manifest_system_deps.shouldReclaim;
208729
+ exports.socketDirectionBytes = require_manifest_system_deps.socketDirectionBytes;
208730
+ exports.socketDirectionMessages = require_manifest_system_deps.socketDirectionMessages;
208731
+ exports.startHeapWatch = require_manifest_system_deps.startHeapWatch;
208732
+ exports.startRunnerHeapWatch = require_manifest_system_deps.startRunnerHeapWatch;
208733
+ exports.strandedMb = require_manifest_system_deps.strandedMb;
207532
208734
  exports.stripCamstackDeps = stripCamstackDeps;
207533
- exports.subscribePassthrough = require_manifest_python_deps.subscribePassthrough;
207534
- exports.udsChildLogToWorkerEntry = require_manifest_python_deps.udsChildLogToWorkerEntry;
207535
- exports.validateProviderRegistrations = require_manifest_python_deps.validateProviderRegistrations;
208735
+ exports.subscribePassthrough = require_manifest_system_deps.subscribePassthrough;
208736
+ exports.udsChildLogToWorkerEntry = require_manifest_system_deps.udsChildLogToWorkerEntry;
208737
+ exports.validateProviderRegistrations = require_manifest_system_deps.validateProviderRegistrations;
207536
208738
  exports.validateUploadedTls = require_tls$1.validateUploadedTls;
207537
208739
  exports.waitUntilReady = waitUntilReady;
207538
208740
  exports.writeExtraSans = require_tls$1.writeExtraSans;
@@ -207567,7 +208769,7 @@ var require_dist4 = __commonJS({
207567
208769
  "use strict";
207568
208770
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
207569
208771
  var require_event_category = require_event_category_BaEgqJNv();
207570
- var require_sleep = require_sleep_CJrvRDlD();
208772
+ var require_sleep = require_sleep_CWWLTM6W();
207571
208773
  var require_canonical_hash = require_canonical_hash_DNV8S5ET();
207572
208774
  var require_enums2 = require_enums();
207573
208775
  var require_err_msg = require_err_msg_COpsHMw2();
@@ -208277,6 +209479,48 @@ var require_dist4 = __commonJS({
208277
209479
  unreadable
208278
209480
  };
208279
209481
  }
209482
+ var REDACTED_SECRET = "__camstack_redacted__";
209483
+ function isSecretConfigField(field) {
209484
+ if (field.type === "password") return true;
209485
+ return "secret" in field && field.secret === true;
209486
+ }
209487
+ function collectSecretConfigKeys(schema) {
209488
+ const keys = /* @__PURE__ */ new Set();
209489
+ for (const section of sectionsOf(schema)) for (const field of fieldsOf(section)) walkField(field, keys);
209490
+ return keys;
209491
+ }
209492
+ function schemaDeclaresAnyField(schema) {
209493
+ for (const section of sectionsOf(schema)) if (fieldsOf(section).length > 0) return true;
209494
+ return false;
209495
+ }
209496
+ function isRecord$2(value) {
209497
+ return typeof value === "object" && value !== null && !Array.isArray(value);
209498
+ }
209499
+ function sectionsOf(schema) {
209500
+ if (!isRecord$2(schema)) return [];
209501
+ const sections = schema["sections"];
209502
+ return Array.isArray(sections) ? sections : [];
209503
+ }
209504
+ function fieldsOf(node) {
209505
+ if (!isRecord$2(node)) return [];
209506
+ const fields = node["fields"];
209507
+ return Array.isArray(fields) ? fields : [];
209508
+ }
209509
+ function walkField(field, out) {
209510
+ if (!isRecord$2(field)) return;
209511
+ const type = field["type"];
209512
+ const key = field["key"];
209513
+ if ((type === "password" || field["secret"] === true) && typeof key === "string" && key.length > 0) out.add(key);
209514
+ if (type === "group") {
209515
+ for (const child of fieldsOf(field)) walkField(child, out);
209516
+ return;
209517
+ }
209518
+ if (type === "sub-tabs") {
209519
+ const tabs = field["tabs"];
209520
+ if (!Array.isArray(tabs)) return;
209521
+ for (const tab of tabs) for (const child of fieldsOf(tab)) walkField(child, out);
209522
+ }
209523
+ }
208280
209524
  var STREAM_QUALITY_LABELS = {
208281
209525
  high: "High",
208282
209526
  mid: "Mid",
@@ -208857,6 +210101,21 @@ var require_dist4 = __commonJS({
208857
210101
  bytesMoved: zod.z.number().int(),
208858
210102
  /** Total files discovered up front; null while (or when) unknown. */
208859
210103
  filesTotal: zod.z.number().int().nullable(),
210104
+ /**
210105
+ * Rows this run CORRECTED while moving them — a durable mutation the move
210106
+ * made that nobody asked for, so it is reported where the operator reads the
210107
+ * job rather than only in a log line.
210108
+ *
210109
+ * A footage segment records its byte count in its own NAME, and the durable
210110
+ * hour row derives its aggregates from those names. A file that does not
210111
+ * match its name therefore makes the ledger's sums — and with them quota and
210112
+ * pressure eviction — wrong by the difference, and only a rename can fix it.
210113
+ * On 2026-08-30 one such row also stalled a 110 749-file drain permanently.
210114
+ *
210115
+ * Absent on lanes where the question has no meaning: a media blob's size is
210116
+ * in its row, not in its name, so `MediaRelocateEngine` never reconciles one.
210117
+ */
210118
+ rowsReconciled: zod.z.number().int().nonnegative().optional(),
208860
210119
  startedAt: zod.z.number(),
208861
210120
  finishedAt: zod.z.number().nullable(),
208862
210121
  error: zod.z.string().nullable()
@@ -208899,11 +210158,18 @@ var require_dist4 = __commonJS({
208899
210158
  /** Omitted = `move`, the pre-existing behaviour. */
208900
210159
  mode: MediaRelocateModeSchema.optional()
208901
210160
  });
208902
- var UnstampedEventMediaCountSchema = zod.z.object({
208903
- media: zod.z.number().int().nonnegative(),
208904
- retrainFrames: zod.z.number().int().nonnegative(),
208905
- total: zod.z.number().int().nonnegative()
210161
+ var UnstampedRowsSchema = zod.z.object({
210162
+ present: zod.z.boolean(),
210163
+ rows: zod.z.number().int().nonnegative().nullable()
208906
210164
  });
210165
+ var UnstampedEventMediaCountSchema = zod.z.object({
210166
+ media: UnstampedRowsSchema,
210167
+ retrainFrames: UnstampedRowsSchema,
210168
+ /** True when EITHER collection holds one. The refusal reads this. */
210169
+ anyPresent: zod.z.boolean(),
210170
+ /** Sum across both, or `null` when either lane could not be counted. */
210171
+ total: zod.z.number().int().nonnegative().nullable()
210172
+ }).nullable();
208907
210173
  var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: zod.z.string().min(1) });
208908
210174
  var StorageMigrationClassSchema = zod.z.enum([
208909
210175
  "recordings",
@@ -208945,13 +210211,33 @@ var require_dist4 = __commonJS({
208945
210211
  "recorder",
208946
210212
  "analytics"
208947
210213
  ]);
210214
+ var StorageMigrationMoveProgressSchema = zod.z.object({
210215
+ filesMoved: zod.z.number().int().nonnegative(),
210216
+ /** The archive census — the **M** of "N of M" (D295). `null` = unknowable. */
210217
+ filesTotal: zod.z.number().int().nonnegative().nullable(),
210218
+ bytesMoved: zod.z.number().int().nonnegative(),
210219
+ /** Rows the mover corrected while moving them — see `RelocateJob`. Absent on
210220
+ * a lane that cannot reconcile. A migration that silently rewrote durable
210221
+ * rows would be the same failure as one that silently skipped them. */
210222
+ rowsReconciled: zod.z.number().int().nonnegative().optional(),
210223
+ /** The MOVER's start, not the migration's: a drain restarted after an addon
210224
+ * crash gets a new mover, and a rate computed from the migration's start
210225
+ * would silently average in the time nothing was running. */
210226
+ startedAt: zod.z.number(),
210227
+ /** When the coordinator last read these numbers. Paired with `startedAt` it
210228
+ * is the only honest rate: both clocks are the hub's, so a UI never has to
210229
+ * subtract its own. */
210230
+ observedAt: zod.z.number()
210231
+ });
208948
210232
  var StorageMigrationMoveSchema = zod.z.object({
208949
210233
  storageClass: StorageMigrationClassSchema,
208950
210234
  fromLocationId: zod.z.string(),
208951
210235
  toLocationId: zod.z.string(),
208952
210236
  moverJobId: zod.z.string().nullable(),
208953
210237
  state: RelocateJobStateSchema.nullable(),
208954
- error: zod.z.string().nullable()
210238
+ error: zod.z.string().nullable(),
210239
+ /** Last observed mover counters; `null` until the mover has been polled once. */
210240
+ progress: StorageMigrationMoveProgressSchema.nullable()
208955
210241
  });
208956
210242
  var StorageMigrationJobSchema = zod.z.object({
208957
210243
  jobId: zod.z.string(),
@@ -208997,6 +210283,52 @@ var require_dist4 = __commonJS({
208997
210283
  })),
208998
210284
  findings: zod.z.array(StorageMigrationFindingSchema)
208999
210285
  });
210286
+ var StorageMigrationLaneSchema = zod.z.enum(["footage", "media"]);
210287
+ var StorageMigrationMoverSchema = zod.z.object({
210288
+ lane: StorageMigrationLaneSchema,
210289
+ job: RelocateJobSchema,
210290
+ /** The coordinator job that armed this mover, or `null` for a mover armed
210291
+ * directly against the owning addon. */
210292
+ migrationJobId: zod.z.string().nullable(),
210293
+ /** When the hub read these counters. Stamped here so a rate is `bytesMoved`
210294
+ * over (`observedAt` − `job.startedAt`) with BOTH ends on the hub's clock —
210295
+ * a browser subtracting its own `Date.now()` from a server `startedAt` is a
210296
+ * rate made of two different clocks. */
210297
+ observedAt: zod.z.number()
210298
+ });
210299
+ var StorageMigrationResidueSchema = zod.z.object({
210300
+ storageClass: StorageMigrationClassSchema,
210301
+ /** The location still holding the data. `'*'` for the media lane, whose rows
210302
+ * move from wherever they are rather than from one named source. */
210303
+ fromLocationId: zod.z.string(),
210304
+ /** Where a drain would move it — the class's CURRENT default. */
210305
+ toLocationId: zod.z.string(),
210306
+ /** Segments (footage lane) or rows (media lane) still on the source. */
210307
+ items: zod.z.number().int().nonnegative().nullable(),
210308
+ /** Bytes on the source; `null` when the lane counts rows rather than bytes. */
210309
+ bytes: zod.z.number().int().nonnegative().nullable()
210310
+ });
210311
+ var StorageMigrationDrainInputSchema = zod.z.object({
210312
+ /** The classes to drain. Each must appear in `storageMigration.residue`, so
210313
+ * a class whose source is already empty is refused rather than started. */
210314
+ classes: zod.z.array(StorageMigrationClassSchema).min(1),
210315
+ throttleMbps: zod.z.number().min(1).max(1e3).optional()
210316
+ });
210317
+ var RelocateResidueInputSchema = zod.z.object({
210318
+ fromLocationId: zod.z.string().min(1),
210319
+ /** Narrow to one logical class; omit for every profile on the location. */
210320
+ footageClass: RelocateFootageClassSchema.optional()
210321
+ });
210322
+ var RelocateResidueSchema = zod.z.object({
210323
+ segments: zod.z.number().int().nonnegative(),
210324
+ bytes: zod.z.number().int().nonnegative()
210325
+ }).nullable();
210326
+ var RelocatableMediaCountSchema = zod.z.object({ rows: zod.z.number().int().nonnegative() }).nullable();
210327
+ var RelocatableMediaCountInputSchema = zod.z.object({
210328
+ toLocationId: zod.z.string().min(1),
210329
+ /** Omitted = `move`. */
210330
+ mode: MediaRelocateModeSchema.optional()
210331
+ });
209000
210332
  var SUB_DETECTION_TYPES = ["face", "plate"];
209001
210333
  var RECOGNITION_TYPES = [
209002
210334
  "face",
@@ -209047,6 +210379,8 @@ var require_dist4 = __commonJS({
209047
210379
  updatedAt: zod.z.number()
209048
210380
  });
209049
210381
  var StorageLocationRefSchema = zod.z.union([StorageLocationTypeSchema, zod.z.string().regex(/^[a-z][a-zA-Z0-9-]*:[a-zA-Z0-9-]+$/)]);
210382
+ var StorageAccessSchema = zod.z.enum(["local-path", "cap-mediated"]);
210383
+ var STORAGE_ACCESS_FALLBACK = "local-path";
209050
210384
  var StorageLocationDeclarationSchema = zod.z.object({
209051
210385
  /**
209052
210386
  * Global location identifier, e.g. `recordings` or `recordingsLow`.
@@ -209066,6 +210400,19 @@ var require_dist4 = __commonJS({
209066
210400
  */
209067
210401
  cardinality: zod.z.enum(["single", "multi"]),
209068
210402
  /**
210403
+ * HOW the declaring service reaches the bytes — and therefore WHICH
210404
+ * providers may back a location of this kind. See {@link StorageAccessSchema}
210405
+ * and {@link STORAGE_ACCESS_FALLBACK}.
210406
+ *
210407
+ * Absent means `'local-path'`. That default is FAIL-CLOSED on purpose: it
210408
+ * can only over-restrict (refuse a remote provider for a kind that might
210409
+ * have coped) and never under-restrict. Declaring `'cap-mediated'` is the
210410
+ * permissive direction and is therefore never inferred — a repo guard
210411
+ * (`scripts/check-storage-access-declarations.ts`) refuses to let it be
210412
+ * reached by omission.
210413
+ */
210414
+ access: StorageAccessSchema.optional(),
210415
+ /**
209069
210416
  * When set, the default instance for this location inherits its resolved
209070
210417
  * root from the named location's default instance. Useful for derivative
209071
210418
  * slots (e.g. `recordingsLow` → `recordings`) so operators only need to
@@ -215197,6 +216544,15 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
215197
216544
  * calls are sync. Bindings change rarely (only on wrapper toggle or
215198
216545
  * device add/remove) — clients invalidate via the
215199
216546
  * `capability.binding-changed` event.
216547
+ *
216548
+ * "A single round-trip" describes the CLIENT's side and used not to
216549
+ * describe the server's: until 2026-08-30 the resolver read the persisted
216550
+ * wrapper activations once per device, so answering this cost one
216551
+ * settings-door RPC per device — 1 020 on the live 1 019-device hub, and
216552
+ * it did not return in 240 s against `SystemMirror.init`'s 15 s budget.
216553
+ * The server side is now two reads for the whole fleet. Anything PERIODIC
216554
+ * still belongs on `getBindings` / `getBindingsBatch` (D12); this remains
216555
+ * a warm seed.
215200
216556
  */
215201
216557
  getAllBindings: require_sleep.method(zod.z.object({}), zod.z.array(DeviceBindingsForDeviceSchema)),
215202
216558
  /**
@@ -220998,8 +222354,10 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
220998
222354
  lastSeen: zod.z.number(),
220999
222355
  /** Frame-rate position history (subject to maxPositionHistory cap). */
221000
222356
  positions: zod.z.array(TrackPositionSchema).readonly(),
221001
- /** Periodic snapshots at snapshotIntervalMs cadence (subject to
221002
- * saveThumbnails policy). */
222357
+ /** Periodic snapshots at snapshotIntervalMs cadence DEBUG media, produced
222358
+ * only while `MediaSettings.debugMediaEnabled` is on for the camera (D299;
222359
+ * the retired `saveThumbnails` used to gate this and the rolling
222360
+ * `lastFrame` together). Empty is the healthy default, not a capture gap. */
221003
222361
  snapshots: zod.z.array(TrackSnapshotSchema).readonly(),
221004
222362
  /** Deduplicated zones the track has entered at least once. Zone IDS. */
221005
222363
  zonesVisited: zod.z.array(zod.z.string()).readonly(),
@@ -221980,8 +223338,34 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
221980
223338
  * happens to stamp it. This count is what the migration planner's
221981
223339
  * non-blocking gate reads; `relocateMedia({ mode: 'seal' })` is what drives
221982
223340
  * it to zero.
223341
+ *
223342
+ * TWO indexed statements per collection, not a walk. It used to page the
223343
+ * whole collection at 200 rows per RPC ordered by an unindexed column, so
223344
+ * on the live hub — 1 254 576 rows — it hit the 60 s RPC deadline every
223345
+ * time it was called, and the migration it gates could never start. The
223346
+ * cheap question (`present`: is there at least one) is asked first and
223347
+ * separately from the expensive one (`rows`), because only the first has
223348
+ * to be answerable for the gate to do its job.
223349
+ *
223350
+ * **`null` is "not measurable", never zero** — at either level. An
223351
+ * unreadable collection must not read as a sealed one.
221983
223352
  */
221984
223353
  countUnstampedEventMedia: require_sleep.method(zod.z.object({}), UnstampedEventMediaCountSchema, { auth: "admin" }),
223354
+ /**
223355
+ * How many rows a pass would STILL act on against `toLocationId`.
223356
+ *
223357
+ * One derivation, two consumers: it is the media lane's denominator (the
223358
+ * **M** the footage lane gets from the ledger census — D295) and it is the
223359
+ * residue behind "drain remaining". Deriving them separately is how "N of M"
223360
+ * ends up comparing two different populations.
223361
+ *
223362
+ * `null` means the count could not be taken; it is never zero-filled,
223363
+ * because a zero here reads as "nothing left to move".
223364
+ */
223365
+ countRelocatableMedia: require_sleep.method(RelocatableMediaCountInputSchema, RelocatableMediaCountSchema, {
223366
+ kind: "query",
223367
+ auth: "admin"
223368
+ }),
221985
223369
  /** Every relocate job this addon knows about, newest first (in RAM: the
221986
223370
  * move is resumable, so a lost list costs nothing but the display). */
221987
223371
  listRelocateMediaJobs: require_sleep.method(zod.z.object({}), zod.z.array(RelocateJobSchema).readonly(), {
@@ -224686,6 +226070,35 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
224686
226070
  cancel: require_sleep.method(zod.z.object({ jobId: zod.z.string() }), zod.z.object({ cancelled: zod.z.boolean() }), {
224687
226071
  kind: "mutation",
224688
226072
  auth: "admin"
226073
+ }),
226074
+ /**
226075
+ * Every mover running RIGHT NOW, in both lanes, with its counters.
226076
+ *
226077
+ * `status` covers a migration's own moves — the coordinator folds their
226078
+ * progress onto the durable job record it is already polling. This covers
226079
+ * the other case, and it is not hypothetical: a drain armed straight against
226080
+ * `recording.relocateFootage` (the only path that existed before
226081
+ * {@link drain}) has no job to fold into and would otherwise be invisible.
226082
+ */
226083
+ movers: require_sleep.method(zod.z.object({}), zod.z.array(StorageMigrationMoverSchema).readonly(), { auth: "admin" }),
226084
+ /**
226085
+ * What each class's SOURCE still holds, from the archive — never from the
226086
+ * resident index (D295). Only classes with something left (or something
226087
+ * unknown) are listed, so an empty list means there is nothing to drain and
226088
+ * the UI has no honest button to offer.
226089
+ */
226090
+ residue: require_sleep.method(zod.z.object({}), zod.z.array(StorageMigrationResidueSchema).readonly(), { auth: "admin" }),
226091
+ /**
226092
+ * Run the drain half alone, on a class whose default has ALREADY moved.
226093
+ *
226094
+ * It never repoints anything, which is what lets `start` keep refusing a
226095
+ * destination that is already the default: the two verbs cannot be confused
226096
+ * for one another, and no operator can re-repoint a migrated class through
226097
+ * this door.
226098
+ */
226099
+ drain: require_sleep.method(StorageMigrationDrainInputSchema, zod.z.object({ jobId: zod.z.string() }), {
226100
+ kind: "mutation",
226101
+ auth: "admin"
224689
226102
  })
224690
226103
  }
224691
226104
  };
@@ -225195,7 +226608,20 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
225195
226608
  */
225196
226609
  scanned: zod.z.number(),
225197
226610
  /** True when the backend could not consider every row that passed the filter. */
225198
- truncated: zod.z.boolean()
226611
+ truncated: zod.z.boolean(),
226612
+ /**
226613
+ * The `topK` the backend actually ran with.
226614
+ *
226615
+ * Every backend has a ceiling — sqlite-vec's is 4,096 — and a caller asking
226616
+ * past it used to learn nothing but a boolean, from a WARN in the provider's
226617
+ * own log rather than in its answer. That is how an audit asking for 20,000
226618
+ * consumed 4,096 and reported `examined: 4096` as if it had walked the index,
226619
+ * for weeks. `truncated` says THAT the answer was short; this says BY HOW
226620
+ * MUCH, in the return value, where the caller cannot fail to see it.
226621
+ *
226622
+ * Equals the requested `topK` whenever nothing was lowered.
226623
+ */
226624
+ effectiveTopK: zod.z.number().int().positive()
225199
226625
  });
225200
226626
  var VectorDeleteInputSchema = zod.z.object({
225201
226627
  index: zod.z.string(),
@@ -225214,6 +226640,35 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
225214
226640
  id: zod.z.string(),
225215
226641
  metadata: VectorMetadataSchema
225216
226642
  })) });
226643
+ var VectorFetchInputSchema = zod.z.object({
226644
+ index: zod.z.string(),
226645
+ ids: zod.z.array(zod.z.string())
226646
+ });
226647
+ var VectorFetchResultSchema = zod.z.object({ items: zod.z.array(zod.z.object({
226648
+ id: zod.z.string(),
226649
+ /** base64 Float32LE — the same wire form `upsert` accepts. */
226650
+ vector: zod.z.string(),
226651
+ metadata: VectorMetadataSchema
226652
+ })) });
226653
+ var VectorScanInputSchema = zod.z.object({
226654
+ index: zod.z.string(),
226655
+ /** Opaque resume point. `0` starts at the top; pass back `nextCursor`. */
226656
+ cursor: zod.z.number().int().nonnegative().default(0),
226657
+ limit: zod.z.number().int().positive()
226658
+ });
226659
+ var VectorScanResultSchema = zod.z.object({
226660
+ items: zod.z.array(zod.z.object({
226661
+ id: zod.z.string(),
226662
+ metadata: VectorMetadataSchema
226663
+ })),
226664
+ /**
226665
+ * Where the next page starts, or `null` when the walk reached the end.
226666
+ *
226667
+ * `null` is the ONLY end-of-index signal. A caller must not infer the end
226668
+ * from a short page: a backend is free to return fewer rows than asked.
226669
+ */
226670
+ nextCursor: zod.z.number().int().nonnegative().nullable()
226671
+ });
225217
226672
  var VectorStatsInputSchema = zod.z.object({ index: zod.z.string() });
225218
226673
  var VectorStatsResultSchema = zod.z.object({
225219
226674
  /** Provider id, so an operator can tell brute force from an ANN index. */
@@ -225244,6 +226699,10 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
225244
226699
  query: require_sleep.method(VectorQueryInputSchema, VectorQueryResultSchema, { auth: "admin" }),
225245
226700
  /** Metadata by id, no vectors — see {@link VectorGetResultSchema}. */
225246
226701
  getByIds: require_sleep.method(VectorGetInputSchema, VectorGetResultSchema, { auth: "admin" }),
226702
+ /** Metadata AND vectors, by named id — see {@link VectorFetchInputSchema}. */
226703
+ fetchByIds: require_sleep.method(VectorFetchInputSchema, VectorFetchResultSchema, { auth: "admin" }),
226704
+ /** One page of the whole index, unranked — see {@link VectorScanInputSchema}. */
226705
+ scan: require_sleep.method(VectorScanInputSchema, VectorScanResultSchema, { auth: "admin" }),
225247
226706
  deleteByIds: require_sleep.method(VectorDeleteInputSchema, VectorDeleteResultSchema, {
225248
226707
  kind: "mutation",
225249
226708
  auth: "admin"
@@ -231714,6 +233173,20 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
231714
233173
  kind: "query",
231715
233174
  auth: "admin"
231716
233175
  }),
233176
+ /**
233177
+ * What a location STILL holds, asked of the durable hour ledger.
233178
+ *
233179
+ * The number behind "drain remaining": segments and bytes that would still
233180
+ * have to move off `fromLocationId`. It is a ledger aggregate — the archive
233181
+ * — because the resident index is not the archive (D295), and a drain sized
233182
+ * off the index is exactly what reported `done` over 80.3 GB on 2026-08-29.
233183
+ * `null` means the archive could not be asked (no ledger on this node, or
233184
+ * the aggregate failed) and is never conflated with an empty source.
233185
+ */
233186
+ getRelocateResidue: require_sleep.method(RelocateResidueInputSchema, RelocateResidueSchema, {
233187
+ kind: "query",
233188
+ auth: "admin"
233189
+ }),
231717
233190
  /** Cancel a running or queued relocate job. A queued job never runs. */
231718
233191
  cancelRelocateJob: require_sleep.method(zod.z.object({ jobId: zod.z.string() }), zod.z.object({ cancelled: zod.z.boolean() }), {
231719
233192
  kind: "mutation",
@@ -240654,6 +242127,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
240654
242127
  addonId: null,
240655
242128
  access: "create"
240656
242129
  },
242130
+ "pipelineAnalytics.countRelocatableMedia": {
242131
+ capName: "pipeline-analytics",
242132
+ capScope: "device",
242133
+ addonId: null,
242134
+ access: "view"
242135
+ },
240657
242136
  "pipelineAnalytics.countUnstampedEventMedia": {
240658
242137
  capName: "pipeline-analytics",
240659
242138
  capScope: "device",
@@ -241818,6 +243297,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
241818
243297
  addonId: null,
241819
243298
  access: "view"
241820
243299
  },
243300
+ "recording.getRelocateResidue": {
243301
+ capName: "recording",
243302
+ capScope: "system",
243303
+ addonId: null,
243304
+ access: "view"
243305
+ },
241821
243306
  "recording.getStorageMigrationMoveStatus": {
241822
243307
  capName: "recording",
241823
243308
  capScope: "system",
@@ -242364,12 +243849,30 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
242364
243849
  addonId: null,
242365
243850
  access: "create"
242366
243851
  },
243852
+ "storageMigration.drain": {
243853
+ capName: "storage-migration",
243854
+ capScope: "system",
243855
+ addonId: null,
243856
+ access: "create"
243857
+ },
243858
+ "storageMigration.movers": {
243859
+ capName: "storage-migration",
243860
+ capScope: "system",
243861
+ addonId: null,
243862
+ access: "view"
243863
+ },
242367
243864
  "storageMigration.plan": {
242368
243865
  capName: "storage-migration",
242369
243866
  capScope: "system",
242370
243867
  addonId: null,
242371
243868
  access: "view"
242372
243869
  },
243870
+ "storageMigration.residue": {
243871
+ capName: "storage-migration",
243872
+ capScope: "system",
243873
+ addonId: null,
243874
+ access: "view"
243875
+ },
242373
243876
  "storageMigration.start": {
242374
243877
  capName: "storage-migration",
242375
243878
  capScope: "system",
@@ -243204,6 +244707,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
243204
244707
  addonId: null,
243205
244708
  access: "delete"
243206
244709
  },
244710
+ "vectorStore.fetchByIds": {
244711
+ capName: "vector-store",
244712
+ capScope: "system",
244713
+ addonId: null,
244714
+ access: "view"
244715
+ },
243207
244716
  "vectorStore.getByIds": {
243208
244717
  capName: "vector-store",
243209
244718
  capScope: "system",
@@ -243216,6 +244725,12 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
243216
244725
  addonId: null,
243217
244726
  access: "view"
243218
244727
  },
244728
+ "vectorStore.scan": {
244729
+ capName: "vector-store",
244730
+ capScope: "system",
244731
+ addonId: null,
244732
+ access: "view"
244733
+ },
243219
244734
  "vectorStore.stats": {
243220
244735
  capName: "vector-store",
243221
244736
  capScope: "system",
@@ -246390,6 +247905,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
246390
247905
  cancelStorageMigrationMove: (input) => dispatch("recording", "cancelStorageMigrationMove", "mutation", input),
246391
247906
  relocateFootage: (input) => dispatch("recording", "relocateFootage", "mutation", input),
246392
247907
  listRelocateJobs: (input) => dispatch("recording", "listRelocateJobs", "query", input),
247908
+ getRelocateResidue: (input) => dispatch("recording", "getRelocateResidue", "query", input),
246393
247909
  cancelRelocateJob: (input) => dispatch("recording", "cancelRelocateJob", "mutation", input),
246394
247910
  planStorageRebalance: (input) => dispatch("recording", "planStorageRebalance", "query", input),
246395
247911
  startStorageRebalance: (input) => dispatch("recording", "startStorageRebalance", "mutation", input)
@@ -246453,7 +247969,10 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
246453
247969
  plan: (input) => dispatch("storageMigration", "plan", "query", input),
246454
247970
  start: (input) => dispatch("storageMigration", "start", "mutation", input),
246455
247971
  status: (input) => dispatch("storageMigration", "status", "query", input),
246456
- cancel: (input) => dispatch("storageMigration", "cancel", "mutation", input)
247972
+ cancel: (input) => dispatch("storageMigration", "cancel", "mutation", input),
247973
+ movers: (input) => dispatch("storageMigration", "movers", "query", input),
247974
+ residue: (input) => dispatch("storageMigration", "residue", "query", input),
247975
+ drain: (input) => dispatch("storageMigration", "drain", "mutation", input)
246457
247976
  },
246458
247977
  streamBroker: {
246459
247978
  fetchEventMedia: (input) => dispatch("streamBroker", "fetchEventMedia", "mutation", input),
@@ -249907,6 +251426,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
249907
251426
  exports.REACHABILITY_PROBE_TIMEOUT_MS = REACHABILITY_PROBE_TIMEOUT_MS;
249908
251427
  exports.RECOGNITION_TYPES = RECOGNITION_TYPES;
249909
251428
  exports.RECORDING_EXPORT_MAX_READ_BYTES = RECORDING_EXPORT_MAX_READ_BYTES;
251429
+ exports.REDACTED_SECRET = REDACTED_SECRET;
249910
251430
  exports.RESERVED_BINDING_NAMES = RESERVED_BINDING_NAMES;
249911
251431
  exports.RESTORED_CAP_NAMES = RESTORED_CAP_NAMES;
249912
251432
  exports.ROOT_BUCKET_KEY = ROOT_BUCKET_KEY;
@@ -249945,11 +251465,15 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
249945
251465
  exports.RecordingTriggersSchema = RecordingTriggersSchema;
249946
251466
  exports.RecordingWeekdaySchema = RecordingWeekdaySchema;
249947
251467
  exports.RedirectLoginMethodSchema = RedirectLoginMethodSchema;
251468
+ exports.RelocatableMediaCountInputSchema = RelocatableMediaCountInputSchema;
251469
+ exports.RelocatableMediaCountSchema = RelocatableMediaCountSchema;
249948
251470
  exports.RelocateFootageClassSchema = RelocateFootageClassSchema;
249949
251471
  exports.RelocateFootageInputSchema = RelocateFootageInputSchema;
249950
251472
  exports.RelocateJobSchema = RelocateJobSchema;
249951
251473
  exports.RelocateJobStateSchema = RelocateJobStateSchema;
249952
251474
  exports.RelocateMediaInputSchema = RelocateMediaInputSchema;
251475
+ exports.RelocateResidueInputSchema = RelocateResidueInputSchema;
251476
+ exports.RelocateResidueSchema = RelocateResidueSchema;
249953
251477
  exports.RenderedAsSchema = RenderedAsSchema;
249954
251478
  exports.ReportMotionInputSchema = ReportMotionInputSchema;
249955
251479
  exports.ReportedFailureContributionSchema = ReportedFailureContributionSchema;
@@ -250000,6 +251524,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
250000
251524
  exports.SOURCE_CAP_CHANGED_AT_FIELD = SOURCE_CAP_CHANGED_AT_FIELD;
250001
251525
  exports.SOURCE_DEVICE_TYPES = SOURCE_DEVICE_TYPES;
250002
251526
  exports.SOURCE_INFO_METADATA_KEY = SOURCE_INFO_METADATA_KEY;
251527
+ exports.STORAGE_ACCESS_FALLBACK = STORAGE_ACCESS_FALLBACK;
250003
251528
  exports.STREAM_PROFILE_META = STREAM_PROFILE_META;
250004
251529
  exports.STREAM_QUALITY_LABELS = STREAM_QUALITY_LABELS;
250005
251530
  exports.SUB_DETECTION_TYPES = SUB_DETECTION_TYPES;
@@ -250049,6 +251574,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
250049
251574
  exports.StartEmbeddedInputSchema = StartEmbeddedInputSchema;
250050
251575
  exports.StationaryObjectSchema = StationaryObjectSchema;
250051
251576
  exports.StorageAbortUploadInputSchema = AbortUploadInputSchema;
251577
+ exports.StorageAccessSchema = StorageAccessSchema;
250052
251578
  exports.StorageBeginDownloadInputSchema = BeginDownloadInputSchema;
250053
251579
  exports.StorageBeginDownloadResultSchema = BeginDownloadResultSchema;
250054
251580
  exports.StorageBeginUploadInputSchema = BeginUploadInputSchema;
@@ -250061,18 +251587,23 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
250061
251587
  exports.StorageLocationTypeSchema = StorageLocationTypeSchema;
250062
251588
  exports.StorageMigrationClassSchema = StorageMigrationClassSchema;
250063
251589
  exports.StorageMigrationDestinationsSchema = StorageMigrationDestinationsSchema;
251590
+ exports.StorageMigrationDrainInputSchema = StorageMigrationDrainInputSchema;
250064
251591
  exports.StorageMigrationFindingCodeSchema = StorageMigrationFindingCodeSchema;
250065
251592
  exports.StorageMigrationFindingSchema = StorageMigrationFindingSchema;
250066
251593
  exports.StorageMigrationFootageMoveInputSchema = StorageMigrationFootageMoveInputSchema;
250067
251594
  exports.StorageMigrationInputSchema = StorageMigrationInputSchema;
250068
251595
  exports.StorageMigrationJobSchema = StorageMigrationJobSchema;
251596
+ exports.StorageMigrationLaneSchema = StorageMigrationLaneSchema;
250069
251597
  exports.StorageMigrationLeaseInputSchema = StorageMigrationLeaseInputSchema;
250070
251598
  exports.StorageMigrationMediaMoveInputSchema = StorageMigrationMediaMoveInputSchema;
250071
251599
  exports.StorageMigrationModeSchema = StorageMigrationModeSchema;
251600
+ exports.StorageMigrationMoveProgressSchema = StorageMigrationMoveProgressSchema;
250072
251601
  exports.StorageMigrationMoveSchema = StorageMigrationMoveSchema;
251602
+ exports.StorageMigrationMoverSchema = StorageMigrationMoverSchema;
250073
251603
  exports.StorageMigrationParticipantSchema = StorageMigrationParticipantSchema;
250074
251604
  exports.StorageMigrationPhaseSchema = StorageMigrationPhaseSchema;
250075
251605
  exports.StorageMigrationPlanSchema = StorageMigrationPlanSchema;
251606
+ exports.StorageMigrationResidueSchema = StorageMigrationResidueSchema;
250076
251607
  exports.StorageProviderInfoSchema = ProviderInfoSchema;
250077
251608
  exports.StorageReadChunkInputSchema = ReadChunkInputSchema;
250078
251609
  exports.StorageTestLocationResultSchema = TestLocationResultSchema;
@@ -250145,6 +251676,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
250145
251676
  exports.UnifiedBrokerInfoSchema = BrokerInfoSchema$1;
250146
251677
  exports.UnitConversionError = UnitConversionError;
250147
251678
  exports.UnstampedEventMediaCountSchema = UnstampedEventMediaCountSchema;
251679
+ exports.UnstampedRowsSchema = UnstampedRowsSchema;
250148
251680
  exports.UpdateIntegrationInputSchema = UpdateIntegrationInputSchema;
250149
251681
  exports.UpdateStatusSchema = UpdateStatusSchema;
250150
251682
  exports.UpdateUserInputSchema = UpdateUserInputSchema;
@@ -250266,6 +251798,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
250266
251798
  exports.clusterStepSettingKey = clusterStepSettingKey;
250267
251799
  exports.collectHydratedFieldEntries = require_sleep.collectHydratedFieldEntries;
250268
251800
  exports.collectHydratedFieldValues = require_sleep.collectHydratedFieldValues;
251801
+ exports.collectSecretConfigKeys = collectSecretConfigKeys;
250269
251802
  exports.colorCapability = colorCapability;
250270
251803
  exports.colorForKind = colorForKind;
250271
251804
  exports.commitWatchdogRestart = commitWatchdogRestart;
@@ -250406,6 +251939,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
250406
251939
  exports.isRestoredCap = isRestoredCap;
250407
251940
  exports.isSameAddonId = isSameAddonId;
250408
251941
  exports.isScheduleActive = isScheduleActive;
251942
+ exports.isSecretConfigField = isSecretConfigField;
250409
251943
  exports.isSoftwareDecode = require_canonical_hash.isSoftwareDecode;
250410
251944
  exports.isSourceCap = isSourceCap;
250411
251945
  exports.isSystemDelivery = isSystemDelivery;
@@ -250553,6 +252087,7 @@ ${recipe.triggers.map((t, i) => emitTrigger(t, i)).join("\n\n")}
250553
252087
  exports.runtimeDevices = runtimeDevices;
250554
252088
  exports.runtimeStatePolicyFor = runtimeStatePolicyFor;
250555
252089
  exports.sceneMonitorCapability = sceneMonitorCapability;
252090
+ exports.schemaDeclaresAnyField = schemaDeclaresAnyField;
250556
252091
  exports.scopeInherits = scopeInherits;
250557
252092
  exports.scopeKey = require_sleep.scopeKey;
250558
252093
  exports.scopesAllowAddon = scopesAllowAddon;
@@ -384452,6 +385987,14 @@ var require_main2 = __commonJS({
384452
385987
  // cap). A pin to ANOTHER node still bypasses the sibling → onUnownedCall.
384453
385988
  ownNodeId: agentNodeId,
384454
385989
  onUnownedCall
385990
+ // NO `capUsageObserver` here, deliberately. `getCapUsageRegistry()` is a
385991
+ // per-process singleton and the reader (`nodes.getCapUsageGraph`) runs on
385992
+ // hub-main; recording in the agent would produce a map nobody ever reads,
385993
+ // which is exactly the shape that made this graph return `[]` for
385994
+ // months. An agent's addon traffic is a KNOWN blind spot of the graph —
385995
+ // see `LocalChildRegistryOptions.capUsageObserver`. Closing it needs the
385996
+ // caller identity to survive `$hub-cap-fwd`'s envelope, which today it
385997
+ // does not.
384455
385998
  });
384456
385999
  await agentUdsRegistry.start();
384457
386000
  agentUdsRegistry.onChildRegistered((child) => {
@@ -409262,8 +410805,30 @@ var require_cap_providers = __commonJS({
409262
410805
  }
409263
410806
  return result;
409264
410807
  },
410808
+ /**
410809
+ * Observed caller → provider → cap edges over the last `windowSeconds`.
410810
+ *
410811
+ * **Read the blind spots before drawing a conclusion.** This reads
410812
+ * hub-main's `CapUsageRegistry`, written by the hub's `LocalChildRegistry`
410813
+ * on every `cap-call-out` a hub-local forked addon sends. It therefore does
410814
+ * NOT contain: hub-main → hub-main in-process calls (one shared `ctx.api`
410815
+ * client, no per-caller identity), a runner's own co-located calls, or any
410816
+ * traffic originating on an agent. An edge missing here means "not seen on
410817
+ * this plane", never "did not happen" — the full list is on
410818
+ * `LocalChildRegistryOptions.capUsageObserver`.
410819
+ */
409265
410820
  getCapUsageGraph: async (input) => {
409266
410821
  const reg = (0, system_1.getCapUsageRegistry)();
410822
+ const stats = reg.getStats();
410823
+ if (stats.droppedTriples > 0) {
410824
+ logger?.warn("cap-usage graph is truncated \u2014 the triple ceiling was reached", {
410825
+ meta: {
410826
+ triples: stats.triples,
410827
+ maxTriples: stats.maxTriples,
410828
+ droppedTriples: stats.droppedTriples
410829
+ }
410830
+ });
410831
+ }
409267
410832
  return reg.getGraph({ windowSeconds: input.windowSeconds, nowMs: Date.now() });
409268
410833
  },
409269
410834
  setProcessLogLevel: async (input) => {
@@ -420288,6 +421853,14 @@ var require_moleculer_service = __commonJS({
420288
421853
  // below, so a method that survives 16 minutes across nodes survives it
420289
421854
  // across a socket too — and one that hangs is cut off on both.
420290
421855
  capTimeoutMs: (capName, method) => this.capabilityService.getRegistry()?.getDefinition(capName)?.methods?.[method]?.timeoutMs,
421856
+ // Feed the cap-usage graph from the one place that sees a forked
421857
+ // addon's outbound `ctx.api` traffic AND runs in the process that reads
421858
+ // it back (`nodes.getCapUsageGraph` → `cap-providers.ts`). The
421859
+ // runner-side observer in `addon-context-factory.ts` writes to the
421860
+ // RUNNER's own module singleton, which hub-main never sees — which is
421861
+ // why the graph answered `[]` on a hub running 64 addons. Blind spots
421862
+ // that remain are listed on `LocalChildRegistryOptions.capUsageObserver`.
421863
+ capUsageObserver: (obs) => (0, system_1.getCapUsageRegistry)().recordCall(obs),
420291
421864
  logger: {
420292
421865
  info: (msg, meta) => logger.info(msg, meta !== null && meta !== void 0 ? { meta } : void 0)
420293
421866
  },