@camstack/addon-osd-manager 0.1.21 → 0.1.22
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.
- package/dist/{MotionZonesSettings-C1tuU9vA.mjs → MotionZonesSettings-DhYwaRz3.mjs} +2 -2
- package/dist/{PrivacyMaskSettings-BfYwmnx-.mjs → PrivacyMaskSettings-BquvldBM.mjs} +4 -4
- package/dist/{SceneMonitorEditor-Fui6aPeX.mjs → SceneMonitorEditor-wK0ulSnf.mjs} +3 -3
- package/dist/_stub.js +10 -10
- package/dist/{_virtual_mf-localSharedImportMap___mfe_internal__addon_osd_manager_page-CUYUIYix.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_osd_manager_page-CG-BhZBB.mjs} +4 -4
- package/dist/_virtual_mf___mfe_internal__addon_osd_manager_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-6_-m0FOQ.mjs +26 -0
- package/dist/{hostInit-wPjKQ8mT.mjs → hostInit-8p7aKRSc.mjs} +3 -3
- package/dist/index.js +465 -100
- package/dist/index.mjs +465 -100
- package/dist/{player-overlays-B_C4YyEi.mjs → player-overlays-CS4sZzYZ.mjs} +1 -1
- package/dist/remoteEntry.js +1 -1
- package/dist/{responsive-BzwsIYSh.mjs → responsive-VdLah82L.mjs} +1 -1
- package/dist/{square-X_zDrz0l.mjs → square-a4rMgWr9.mjs} +1 -1
- package/dist/{trash-2-BldQMEFN.mjs → trash-2-BCaHwGDI.mjs} +1 -1
- package/dist/{use-device-snapshot-Bxo1wH26.mjs → use-device-snapshot-CTWHDX3F.mjs} +1 -1
- package/dist/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_osd_manager_page__remoteEntry_js-DZH4YPzH.mjs → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_osd_manager_page__remoteEntry_js-BdfKcHRf.mjs} +1 -1
- package/package.json +1 -1
- package/dist/_virtual_mf___mfe_internal__addon_osd_manager_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-BhABwRxy.mjs +0 -26
package/dist/index.js
CHANGED
|
@@ -6633,7 +6633,7 @@ function method(input, output, options) {
|
|
|
6633
6633
|
input,
|
|
6634
6634
|
output,
|
|
6635
6635
|
kind: options?.kind ?? "query",
|
|
6636
|
-
auth: options
|
|
6636
|
+
...options?.auth !== void 0 ? { auth: options.auth } : {},
|
|
6637
6637
|
...options?.access !== void 0 ? { access: options.access } : {},
|
|
6638
6638
|
...options?.caller !== void 0 ? { caller: options.caller } : {},
|
|
6639
6639
|
timeoutMs: options?.timeoutMs
|
|
@@ -6663,8 +6663,17 @@ var adminUiCapability = {
|
|
|
6663
6663
|
mode: "singleton",
|
|
6664
6664
|
internal: true,
|
|
6665
6665
|
methods: {
|
|
6666
|
-
|
|
6667
|
-
|
|
6666
|
+
/**
|
|
6667
|
+
* `internal: true` did not gate the mount (see the 2026-08-26 note on
|
|
6668
|
+
* `data-store-provider`) — both methods were reachable on the AppRouter
|
|
6669
|
+
* by ANY authenticated session at the default `auth: 'protected'`, and
|
|
6670
|
+
* `getStaticDir` leaks a hub filesystem path. The only caller is
|
|
6671
|
+
* `main.ts`'s static-file bootstrap, via `capRegistry.getSingletonForNode`
|
|
6672
|
+
* — never tRPC — so `auth: 'admin'` costs it nothing. The actual admin-ui
|
|
6673
|
+
* SPA assets are served as plain static files, unaffected by this gate.
|
|
6674
|
+
*/
|
|
6675
|
+
getStaticDir: method(_void(), StaticDirOutputSchema$1, { auth: "admin" }),
|
|
6676
|
+
getVersion: method(_void(), VersionOutputSchema$1, { auth: "admin" })
|
|
6668
6677
|
}
|
|
6669
6678
|
};
|
|
6670
6679
|
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
@@ -7000,8 +7009,23 @@ var viewerUiCapability = {
|
|
|
7000
7009
|
mode: "singleton",
|
|
7001
7010
|
internal: true,
|
|
7002
7011
|
methods: {
|
|
7003
|
-
|
|
7004
|
-
|
|
7012
|
+
/**
|
|
7013
|
+
* `internal: true` did not gate the mount (see the 2026-08-26 note on
|
|
7014
|
+
* `data-store-provider`) — both methods were reachable on the AppRouter
|
|
7015
|
+
* by ANY authenticated session at the default `auth: 'protected'`, and
|
|
7016
|
+
* `getStaticDir` leaks a hub filesystem path.
|
|
7017
|
+
*
|
|
7018
|
+
* ⚠ Checked before gating: the VIEWER app IS used by a non-admin user
|
|
7019
|
+
* (`roberta`), but it never calls `viewerUi.*` over tRPC. The static SPA
|
|
7020
|
+
* it loads is served by the plain `GET /viewer/*` Fastify route in
|
|
7021
|
+
* `main.ts`, which reads `staticDir`/`indexPath` from a module-level
|
|
7022
|
+
* cache populated ONCE at boot via `capRegistry.getSingletonForNode`
|
|
7023
|
+
* (in-process, not tRPC) — the cap's tRPC procedure is never on that
|
|
7024
|
+
* request path. `auth: 'admin'` here does not block a single viewer
|
|
7025
|
+
* user from loading the app.
|
|
7026
|
+
*/
|
|
7027
|
+
getStaticDir: method(_void(), StaticDirOutputSchema, { auth: "admin" }),
|
|
7028
|
+
getVersion: method(_void(), VersionOutputSchema, { auth: "admin" })
|
|
7005
7029
|
}
|
|
7006
7030
|
};
|
|
7007
7031
|
/**
|
|
@@ -7676,24 +7700,6 @@ var RecordingRetentionSchema = object({
|
|
|
7676
7700
|
maxSizeGb: number().min(0).optional()
|
|
7677
7701
|
});
|
|
7678
7702
|
/**
|
|
7679
|
-
* Scrub-thumbnail fidelity preset — the single per-camera selector bundling the
|
|
7680
|
-
* sprite tile RESOLUTION + JPEG QUALITY the recorder packs timeline-scrub
|
|
7681
|
-
* previews at. Five graduated steps; absent on a config = `standard` (the
|
|
7682
|
-
* shipped default, matching `sheet-geometry`/`sheet-composer`).
|
|
7683
|
-
*
|
|
7684
|
-
* Existing sheets are IMMUTABLE — a changed preset applies to NEW windows only.
|
|
7685
|
-
* Each window's index sidecar carries its own tile dims, so a camera whose
|
|
7686
|
-
* preset changed over time renders every historical window at the dims it was
|
|
7687
|
-
* written with.
|
|
7688
|
-
*/
|
|
7689
|
-
var ScrubThumbnailPresetSchema = _enum([
|
|
7690
|
-
"minimal",
|
|
7691
|
-
"low",
|
|
7692
|
-
"standard",
|
|
7693
|
-
"high",
|
|
7694
|
-
"max"
|
|
7695
|
-
]);
|
|
7696
|
-
/**
|
|
7697
7703
|
* The full per-camera recording intent — the wire shape of a RecordingTarget.
|
|
7698
7704
|
*
|
|
7699
7705
|
* `bands` is the ONLY authored recording intent: what to record, when, and on
|
|
@@ -7701,7 +7707,11 @@ var ScrubThumbnailPresetSchema = _enum([
|
|
|
7701
7707
|
* other field is a storage knob (profiles, segment length, retention, scrub).
|
|
7702
7708
|
*
|
|
7703
7709
|
* STRICT on purpose: the legacy authoring surface (`schedule`/`schedules`/
|
|
7704
|
-
* `triggers`/`preBufferSec`/`postBufferSec`/`rules`) was retired 2026-07-30
|
|
7710
|
+
* `triggers`/`preBufferSec`/`postBufferSec`/`rules`) was retired 2026-07-30,
|
|
7711
|
+
* and `scrubThumbnails` — a five-step fidelity knob for a sprite tier that was
|
|
7712
|
+
* deleted on 2026-07-24 and had ZERO consumers in the recorder — on 2026-08-25
|
|
7713
|
+
* (D62: a switch that writes a store nobody reads is worse than no switch).
|
|
7714
|
+
* Stored rows keep loading: the READ schema is `.strip()` (config-store.ts).
|
|
7705
7715
|
* A stale caller must fail loudly — silently stripping its legacy intent would
|
|
7706
7716
|
* persist a band-less config, i.e. silently stop recording the camera.
|
|
7707
7717
|
*/
|
|
@@ -7724,14 +7734,7 @@ var RecordingConfigSchema = object({
|
|
|
7724
7734
|
* "off" is the absence of a covering band, never a band value.
|
|
7725
7735
|
*/
|
|
7726
7736
|
bands: array(RecordingBandSchema).default([]),
|
|
7727
|
-
retention: RecordingRetentionSchema.optional()
|
|
7728
|
-
/**
|
|
7729
|
-
* Per-camera scrub-thumbnail fidelity preset (resolution + JPEG quality for
|
|
7730
|
-
* timeline-scrub sprite previews). Absent = `standard`. Applies to NEW
|
|
7731
|
-
* windows only — existing sheets are immutable, and each window's index
|
|
7732
|
-
* carries its own tile dims so mixed-preset history renders correctly.
|
|
7733
|
-
*/
|
|
7734
|
-
scrubThumbnails: ScrubThumbnailPresetSchema.optional()
|
|
7737
|
+
retention: RecordingRetentionSchema.optional()
|
|
7735
7738
|
}).strict();
|
|
7736
7739
|
/**
|
|
7737
7740
|
* Entity-relocation job state (storage entity-routing spec, Phase 4).
|
|
@@ -7807,10 +7810,11 @@ var RelocateFootageInputSchema = object({
|
|
|
7807
7810
|
* `RecordingConfig.enabled` or camera wrapper bindings. */
|
|
7808
7811
|
var StorageMigrationLeaseInputSchema = object({ leaseId: string().min(1) });
|
|
7809
7812
|
var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: string().min(1) });
|
|
7810
|
-
var
|
|
7813
|
+
var RelocateMediaInputSchema = object({
|
|
7811
7814
|
toLocationId: string(),
|
|
7812
7815
|
throttleMbps: number().min(1).max(1e3).optional()
|
|
7813
|
-
})
|
|
7816
|
+
});
|
|
7817
|
+
var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: string().min(1) });
|
|
7814
7818
|
/** The independently selectable logical storage classes. `recordings`
|
|
7815
7819
|
* encompasses the high and mid segment profiles; `recordingsLow` is low
|
|
7816
7820
|
* segments; `eventMedia` is post-analysis blobs. */
|
|
@@ -8105,7 +8109,26 @@ var LabelDefinitionSchema = object({
|
|
|
8105
8109
|
description: string().optional(),
|
|
8106
8110
|
icon: string().optional()
|
|
8107
8111
|
});
|
|
8108
|
-
|
|
8112
|
+
/**
|
|
8113
|
+
* Wire schema for a per-model CATALOG classMap override
|
|
8114
|
+
* (`ModelCatalogEntry.classMap` / `ModelConvertMetadata.classMap`) —
|
|
8115
|
+
* restricted to {@link CLASS_MAP_MACRO_TARGETS}, the only macros the
|
|
8116
|
+
* detection pipeline executor actually routes.
|
|
8117
|
+
*
|
|
8118
|
+
* This is deliberately a DIFFERENT, narrower shape than the general-purpose
|
|
8119
|
+
* `ClassMapDefinition` interface above (e.g. `IDetectionAddon.getClassMap()`
|
|
8120
|
+
* and the audio `YAMNET_TO_MACRO` catalog both use macro targets outside this
|
|
8121
|
+
* enum) — the two used to share the name `ClassMapDefinition`/
|
|
8122
|
+
* `ClassMapDefinitionSchema`, which made the schema-type-twin guard
|
|
8123
|
+
* (`scripts/check-schema-type-twins.ts`) flag them as a duplicated shape. They
|
|
8124
|
+
* are not: it is two different concepts colliding on a name. Keep this type
|
|
8125
|
+
* under its own name rather than reusing `ClassMapDefinition` — reusing it
|
|
8126
|
+
* would either narrow every `ClassMapDefinition` consumer to the four
|
|
8127
|
+
* detection macros (breaking `YAMNET_TO_MACRO`) or drop the validation this
|
|
8128
|
+
* schema exists for (see the "rejects a classMap whose target is not a
|
|
8129
|
+
* detection macro" test in `model-catalog-schema.test.ts`).
|
|
8130
|
+
*/
|
|
8131
|
+
var DetectionCatalogClassMapSchema = object({
|
|
8109
8132
|
mapping: record(string(), _enum([
|
|
8110
8133
|
"person",
|
|
8111
8134
|
"vehicle",
|
|
@@ -8310,7 +8333,7 @@ var ModelCatalogEntrySchema = object({
|
|
|
8310
8333
|
* applies (Frigate / COCO public catalog). Set on a custom model whose raw
|
|
8311
8334
|
* labels already ARE the CamStack macros (Scrypted identity map).
|
|
8312
8335
|
*/
|
|
8313
|
-
classMap:
|
|
8336
|
+
classMap: DetectionCatalogClassMapSchema.optional()
|
|
8314
8337
|
});
|
|
8315
8338
|
var ConvertTargetSchema = discriminatedUnion("format", [object({
|
|
8316
8339
|
format: literal("openvino"),
|
|
@@ -8340,7 +8363,7 @@ var ModelConvertMetadataSchema = object({
|
|
|
8340
8363
|
"segmentation"
|
|
8341
8364
|
]),
|
|
8342
8365
|
faceAlignment: boolean().optional(),
|
|
8343
|
-
classMap:
|
|
8366
|
+
classMap: DetectionCatalogClassMapSchema.optional()
|
|
8344
8367
|
});
|
|
8345
8368
|
var ConvertResultSchema = object({
|
|
8346
8369
|
entry: ModelCatalogEntrySchema,
|
|
@@ -9213,7 +9236,18 @@ var addonPagesSourceCapability = {
|
|
|
9213
9236
|
scope: "system",
|
|
9214
9237
|
mode: "collection",
|
|
9215
9238
|
internal: true,
|
|
9216
|
-
methods: {
|
|
9239
|
+
methods: {
|
|
9240
|
+
/**
|
|
9241
|
+
* `internal: true` did not gate the mount (see the 2026-08-26 note on
|
|
9242
|
+
* `data-store-provider`) — this was reachable on the AppRouter by ANY
|
|
9243
|
+
* authenticated session at the default `auth: 'protected'`. The only
|
|
9244
|
+
* consumer, the `addon-pages-aggregator` builtin, reads it via
|
|
9245
|
+
* `ctx.capabilities.getCollection('addon-pages-source')` — LOCAL-PROCESS
|
|
9246
|
+
* only, never tRPC (per `ctx.capabilities` seeing only the local
|
|
9247
|
+
* process). The public, enriched listing admin-ui actually consumes is
|
|
9248
|
+
* the separate `addon-pages` cap, unaffected by this change.
|
|
9249
|
+
*/
|
|
9250
|
+
listPages: method(_void(), array(AddonPageDeclarationSchema).readonly(), { auth: "admin" }) }
|
|
9217
9251
|
};
|
|
9218
9252
|
var AddonHttpRouteSchema = object({
|
|
9219
9253
|
method: _enum([
|
|
@@ -9510,7 +9544,20 @@ var addonWidgetsSourceCapability = {
|
|
|
9510
9544
|
scope: "system",
|
|
9511
9545
|
mode: "collection",
|
|
9512
9546
|
internal: true,
|
|
9513
|
-
methods: {
|
|
9547
|
+
methods: {
|
|
9548
|
+
/**
|
|
9549
|
+
* `internal: true` did not gate the mount (see the 2026-08-26 note on
|
|
9550
|
+
* `data-store-provider`) — this was reachable on the AppRouter by ANY
|
|
9551
|
+
* authenticated session at the default `auth: 'protected'`. The only
|
|
9552
|
+
* consumer, the `addon-widgets-aggregator` builtin, reads it via
|
|
9553
|
+
* `ctx.capabilities.getCollection('addon-widgets-source')` — LOCAL-PROCESS
|
|
9554
|
+
* only, never tRPC. The public, enriched listing admin-ui actually
|
|
9555
|
+
* consumes is the separate `addon-widgets` cap (`listWidgets` there is
|
|
9556
|
+
* gated separately, and a `preAuth: true` widget is surfaced through the
|
|
9557
|
+
* PUBLIC `auth.listLoginMethods` contribution channel instead) —
|
|
9558
|
+
* neither is affected by this change.
|
|
9559
|
+
*/
|
|
9560
|
+
listWidgets: method(_void(), array(WidgetMetadataSchema).readonly(), { auth: "admin" }) }
|
|
9514
9561
|
};
|
|
9515
9562
|
/**
|
|
9516
9563
|
* `addon-widgets` — system-scoped singleton aggregator cap. Public-facing
|
|
@@ -11674,7 +11721,17 @@ var customModelRegistryCapability = {
|
|
|
11674
11721
|
scope: "system",
|
|
11675
11722
|
mode: "collection",
|
|
11676
11723
|
internal: true,
|
|
11677
|
-
methods: {
|
|
11724
|
+
methods: {
|
|
11725
|
+
/**
|
|
11726
|
+
* `internal: true` did not gate the mount (see the 2026-08-26 note on
|
|
11727
|
+
* `data-store-provider`) — this was reachable on the AppRouter by ANY
|
|
11728
|
+
* authenticated session at the default `auth: 'protected'`. The only
|
|
11729
|
+
* consumer, the detection-pipeline's model resolution
|
|
11730
|
+
* (`addon-pipeline/src/detection-pipeline/provider.ts`), calls
|
|
11731
|
+
* `ctx.api.customModelRegistry.listModels.query()` — UDS/Moleculer,
|
|
11732
|
+
* never tRPC — so `auth: 'admin'` costs it nothing.
|
|
11733
|
+
*/
|
|
11734
|
+
listModels: method(_void(), array(CustomModelDescriptorSchema).readonly(), { auth: "admin" }) }
|
|
11678
11735
|
};
|
|
11679
11736
|
/**
|
|
11680
11737
|
* Query filter for settings-store collections.
|
|
@@ -11798,11 +11855,26 @@ var settingsStoreCapability = {
|
|
|
11798
11855
|
key: string(),
|
|
11799
11856
|
value: unknown()
|
|
11800
11857
|
}), _void(), { kind: "mutation" }),
|
|
11801
|
-
/**
|
|
11858
|
+
/**
|
|
11859
|
+
* Rows matching a filter.
|
|
11860
|
+
*
|
|
11861
|
+
* `columns` is a SQL-level projection: the engine SELECTs only those
|
|
11862
|
+
* columns (plus the primary key) instead of the whole row. It is the only
|
|
11863
|
+
* way to stop paying disk for a column that is discarded — a heavy JSON
|
|
11864
|
+
* column dominates the row, and dropping it in JS after the read pays every
|
|
11865
|
+
* byte first. Measured on the live `pipeline-analytics:tracks` table: a
|
|
11866
|
+
* 501-row page is 4.6 MB whole and 0.11 MB projected, same index, same
|
|
11867
|
+
* plan.
|
|
11868
|
+
*
|
|
11869
|
+
* The engine REFUSES a column it cannot serve rather than omitting it —
|
|
11870
|
+
* see `SettingsQueryInput.columns` for why a projection may not be
|
|
11871
|
+
* forgiving the way a predicate is.
|
|
11872
|
+
*/
|
|
11802
11873
|
query: method(object({
|
|
11803
11874
|
namespace: string().optional(),
|
|
11804
11875
|
collection: string(),
|
|
11805
|
-
filter: QueryFilterSchema.optional()
|
|
11876
|
+
filter: QueryFilterSchema.optional(),
|
|
11877
|
+
columns: array(string()).readonly().optional()
|
|
11806
11878
|
}), array(SettingsRecordSchema).readonly()),
|
|
11807
11879
|
/** Insert a new record. */
|
|
11808
11880
|
insert: method(object({
|
|
@@ -11928,6 +12000,23 @@ var EngineInfoSchema = object({
|
|
|
11928
12000
|
* go through `settings-store`; they never see this cap, and an engine
|
|
11929
12001
|
* never sees a caller.
|
|
11930
12002
|
*
|
|
12003
|
+
* ⚠ **`internal: true` DOES NOT gate the mount, and until 2026-08-26 this
|
|
12004
|
+
* comment claimed otherwise.** `resolveCapMount` never reads the field, so this
|
|
12005
|
+
* cap was live on the AppRouter with every method at the default
|
|
12006
|
+
* `auth: 'protected'` — i.e. readable by ANY authenticated session, admin or
|
|
12007
|
+
* not. Verified against the live hub: `dataStoreProvider.query` returned raw
|
|
12008
|
+
* settings rows including a provider credential, bypassing the secret redaction
|
|
12009
|
+
* that `deviceManager.listAll` and friends go through.
|
|
12010
|
+
*
|
|
12011
|
+
* Every method is now `auth: 'admin'` EXPLICITLY, including the five reads —
|
|
12012
|
+
* they had no options object at all, which is exactly how they kept the
|
|
12013
|
+
* permissive default while the mutations looked deliberate. The explicit
|
|
12014
|
+
* annotation is the fix that works today; making `internal` mean something at
|
|
12015
|
+
* mount time is the systemic one, and it is not free: 22 caps declare it, only
|
|
12016
|
+
* 4 are `mount: 'skip'`, and forcing admin on all of them would change the auth
|
|
12017
|
+
* of surfaces the viewer and admin-ui call as non-admin users. That decision is
|
|
12018
|
+
* the operator's, not a side effect of this file.
|
|
12019
|
+
*
|
|
11931
12020
|
* Design notes:
|
|
11932
12021
|
* - **Stateless dispatch.** Every method carries its own
|
|
11933
12022
|
* `namespace` + `collection`, so an engine keeps no per-caller state
|
|
@@ -11949,64 +12038,105 @@ var dataStoreProviderCapability = {
|
|
|
11949
12038
|
internal: true,
|
|
11950
12039
|
methods: {
|
|
11951
12040
|
/** Self-description — how the orchestrator picks a registrant. */
|
|
11952
|
-
getEngineInfo: method(_void(), EngineInfoSchema),
|
|
12041
|
+
getEngineInfo: method(_void(), EngineInfoSchema, { auth: "admin" }),
|
|
11953
12042
|
/** Get a single value by key from a collection. */
|
|
11954
12043
|
get: method(object({
|
|
11955
12044
|
namespace: string().optional(),
|
|
11956
12045
|
collection: string(),
|
|
11957
12046
|
key: string()
|
|
11958
|
-
}), unknown()),
|
|
12047
|
+
}), unknown(), { auth: "admin" }),
|
|
11959
12048
|
/** Set a value by key in a collection (upsert). */
|
|
11960
12049
|
set: method(object({
|
|
11961
12050
|
namespace: string().optional(),
|
|
11962
12051
|
collection: string(),
|
|
11963
12052
|
key: string(),
|
|
11964
12053
|
value: unknown()
|
|
11965
|
-
}), _void(), {
|
|
12054
|
+
}), _void(), {
|
|
12055
|
+
kind: "mutation",
|
|
12056
|
+
auth: "admin"
|
|
12057
|
+
}),
|
|
11966
12058
|
/** Get all entries matching an optional filter. */
|
|
11967
12059
|
query: method(object({
|
|
11968
12060
|
namespace: string().optional(),
|
|
11969
12061
|
collection: string(),
|
|
11970
|
-
filter: QueryFilterSchema.optional()
|
|
11971
|
-
|
|
12062
|
+
filter: QueryFilterSchema.optional(),
|
|
12063
|
+
/**
|
|
12064
|
+
* SQL-level column projection — MUST mirror `settings-store.query`.
|
|
12065
|
+
*
|
|
12066
|
+
* ⚠ An earlier version of this comment blamed Zod stripping, and that
|
|
12067
|
+
* was wrong — corrected 2026-08-26 after the hop map
|
|
12068
|
+
* (`docs/design/2026-08-26-mappa-hop-argomenti.md`) traced the path.
|
|
12069
|
+
* There is **no Zod parse at all** between the door and the engine: the
|
|
12070
|
+
* dispatcher forwards the payload verbatim and UDS carries it whole. A
|
|
12071
|
+
* field declared here reaches `SqliteSettingsBackend` either way.
|
|
12072
|
+
*
|
|
12073
|
+
* What actually lost `columns` was the THIRD declaration of this shape:
|
|
12074
|
+
* `SettingsQueryInput` in `interfaces/storage.ts`, a hand-written TS
|
|
12075
|
+
* interface the engine destructures from. The field existed on both
|
|
12076
|
+
* schemas and the engine still never read it, because nothing checks a
|
|
12077
|
+
* registered provider against `InferProvider<cap>` —
|
|
12078
|
+
* `ProviderRegistration.provider` is typed `object`.
|
|
12079
|
+
*
|
|
12080
|
+
* It is declared here anyway, and must stay in step with
|
|
12081
|
+
* `settings-store.query`: a caller reading only the cap definitions has
|
|
12082
|
+
* to be able to see that this call carries a projection.
|
|
12083
|
+
* `data-door-schema-parity.spec.ts` keeps the two aligned.
|
|
12084
|
+
*/
|
|
12085
|
+
columns: array(string()).readonly().optional()
|
|
12086
|
+
}), array(SettingsRecordSchema).readonly(), { auth: "admin" }),
|
|
11972
12087
|
/** Insert a new record. */
|
|
11973
12088
|
insert: method(object({
|
|
11974
12089
|
namespace: string().optional(),
|
|
11975
12090
|
collection: string(),
|
|
11976
12091
|
record: SettingsRecordSchema
|
|
11977
|
-
}), _void(), {
|
|
12092
|
+
}), _void(), {
|
|
12093
|
+
kind: "mutation",
|
|
12094
|
+
auth: "admin"
|
|
12095
|
+
}),
|
|
11978
12096
|
/** Update an existing record by ID. */
|
|
11979
12097
|
update: method(object({
|
|
11980
12098
|
namespace: string().optional(),
|
|
11981
12099
|
collection: string(),
|
|
11982
12100
|
id: string(),
|
|
11983
12101
|
data: record(string(), unknown())
|
|
11984
|
-
}), _void(), {
|
|
12102
|
+
}), _void(), {
|
|
12103
|
+
kind: "mutation",
|
|
12104
|
+
auth: "admin"
|
|
12105
|
+
}),
|
|
11985
12106
|
/** Delete a record by key/ID. */
|
|
11986
12107
|
delete: method(object({
|
|
11987
12108
|
namespace: string().optional(),
|
|
11988
12109
|
collection: string(),
|
|
11989
12110
|
key: string()
|
|
11990
|
-
}), _void(), {
|
|
12111
|
+
}), _void(), {
|
|
12112
|
+
kind: "mutation",
|
|
12113
|
+
auth: "admin"
|
|
12114
|
+
}),
|
|
11991
12115
|
/** Delete every record matching `filter`, in one statement. */
|
|
11992
12116
|
deleteWhere: method(object({
|
|
11993
12117
|
namespace: string().optional(),
|
|
11994
12118
|
collection: string(),
|
|
11995
12119
|
filter: MutationFilterSchema
|
|
11996
|
-
}), object({ deleted: number().int() }), {
|
|
12120
|
+
}), object({ deleted: number().int() }), {
|
|
12121
|
+
kind: "mutation",
|
|
12122
|
+
auth: "admin"
|
|
12123
|
+
}),
|
|
11997
12124
|
/** Apply `data` to every record matching `filter`, in one statement. */
|
|
11998
12125
|
updateWhere: method(object({
|
|
11999
12126
|
namespace: string().optional(),
|
|
12000
12127
|
collection: string(),
|
|
12001
12128
|
filter: MutationFilterSchema,
|
|
12002
12129
|
data: record(string(), unknown())
|
|
12003
|
-
}), object({ updated: number().int() }), {
|
|
12130
|
+
}), object({ updated: number().int() }), {
|
|
12131
|
+
kind: "mutation",
|
|
12132
|
+
auth: "admin"
|
|
12133
|
+
}),
|
|
12004
12134
|
/** Count entries in a collection, optionally filtered. */
|
|
12005
12135
|
count: method(object({
|
|
12006
12136
|
namespace: string().optional(),
|
|
12007
12137
|
collection: string(),
|
|
12008
12138
|
filter: QueryFilterSchema.optional()
|
|
12009
|
-
}), number()),
|
|
12139
|
+
}), number(), { auth: "admin" }),
|
|
12010
12140
|
/** Grouped counts per ((field-origin)/bucketSize) bucket, filtered. */
|
|
12011
12141
|
histogram: method(object({
|
|
12012
12142
|
namespace: string().optional(),
|
|
@@ -12018,19 +12148,22 @@ var dataStoreProviderCapability = {
|
|
|
12018
12148
|
}), array(object({
|
|
12019
12149
|
bucket: number().int(),
|
|
12020
12150
|
count: number().int()
|
|
12021
|
-
})).readonly()),
|
|
12151
|
+
})).readonly(), { auth: "admin" }),
|
|
12022
12152
|
/** Check if a collection is empty. */
|
|
12023
12153
|
isEmpty: method(object({
|
|
12024
12154
|
namespace: string().optional(),
|
|
12025
12155
|
collection: string()
|
|
12026
|
-
}), boolean()),
|
|
12156
|
+
}), boolean(), { auth: "admin" }),
|
|
12027
12157
|
/** Declare a typed (SQL-backed) collection with columns + indexes. */
|
|
12028
12158
|
declareCollection: method(object({
|
|
12029
12159
|
namespace: string().optional(),
|
|
12030
12160
|
collection: string(),
|
|
12031
12161
|
columns: array(CollectionColumnSchema).readonly(),
|
|
12032
12162
|
indexes: array(CollectionIndexSchema).readonly().optional()
|
|
12033
|
-
}), _void(), {
|
|
12163
|
+
}), _void(), {
|
|
12164
|
+
kind: "mutation",
|
|
12165
|
+
auth: "admin"
|
|
12166
|
+
})
|
|
12034
12167
|
}
|
|
12035
12168
|
};
|
|
12036
12169
|
/**
|
|
@@ -13830,13 +13963,20 @@ var embeddingEncoderCapability = {
|
|
|
13830
13963
|
mode: "collection",
|
|
13831
13964
|
internal: true,
|
|
13832
13965
|
methods: {
|
|
13966
|
+
/**
|
|
13967
|
+
* `internal: true` did not gate the mount (see the 2026-08-26 note on
|
|
13968
|
+
* `data-store-provider`) — every method below was reachable on the
|
|
13969
|
+
* AppRouter by ANY authenticated session at the default
|
|
13970
|
+
* `auth: 'protected'`. Consumers reach the encoder via `ctx.api` from
|
|
13971
|
+
* `addon-post-analysis`, never tRPC.
|
|
13972
|
+
*/
|
|
13833
13973
|
encode: method(object({
|
|
13834
13974
|
crop: _instanceof(Uint8Array),
|
|
13835
13975
|
width: number(),
|
|
13836
13976
|
height: number()
|
|
13837
|
-
}), EmbeddingResultSchema),
|
|
13838
|
-
encodeText: method(object({ text: string() }), EmbeddingResultSchema),
|
|
13839
|
-
getInfo: method(_void(), EmbeddingInfoSchema)
|
|
13977
|
+
}), EmbeddingResultSchema, { auth: "admin" }),
|
|
13978
|
+
encodeText: method(object({ text: string() }), EmbeddingResultSchema, { auth: "admin" }),
|
|
13979
|
+
getInfo: method(_void(), EmbeddingInfoSchema, { auth: "admin" })
|
|
13840
13980
|
}
|
|
13841
13981
|
};
|
|
13842
13982
|
/**
|
|
@@ -14145,12 +14285,28 @@ var llmRuntimeCapability = {
|
|
|
14145
14285
|
mode: "singleton",
|
|
14146
14286
|
internal: true,
|
|
14147
14287
|
methods: {
|
|
14288
|
+
/**
|
|
14289
|
+
* `complete`, `status`, `listLocalModels` and `getDiskUsage` had NO
|
|
14290
|
+
* `auth` override — `internal: true` did not gate the mount (see the
|
|
14291
|
+
* 2026-08-26 note on `data-store-provider`), so they were reachable on
|
|
14292
|
+
* the AppRouter by ANY authenticated session at the default
|
|
14293
|
+
* `auth: 'protected'`, inconsistent with the rest of this cap (already
|
|
14294
|
+
* `auth: 'admin'`) and with this file's own docblock: "the operator
|
|
14295
|
+
* reaches this only through the `llm` cap's methods." The sole caller,
|
|
14296
|
+
* `addon-ai`'s `runtime-client.ts`, reaches every method here via
|
|
14297
|
+
* `ctx.api` + `nodePin` — never tRPC — so `auth: 'admin'` costs it
|
|
14298
|
+
* nothing; the public `llm` cap (which end users and non-admin sessions
|
|
14299
|
+
* legitimately call for chat/generation) is untouched.
|
|
14300
|
+
*/
|
|
14148
14301
|
complete: method(LlmGenerateBaseInputSchema.extend({
|
|
14149
14302
|
images: array(LlmImageSchema).optional(),
|
|
14150
14303
|
runtime: ManagedRuntimeConfigSchema,
|
|
14151
14304
|
/** The managed profile's timeout, threaded by the hub provider. */
|
|
14152
14305
|
timeoutMs: number().int().positive().optional()
|
|
14153
|
-
}), LlmGenerateResultSchema, {
|
|
14306
|
+
}), LlmGenerateResultSchema, {
|
|
14307
|
+
kind: "mutation",
|
|
14308
|
+
auth: "admin"
|
|
14309
|
+
}),
|
|
14154
14310
|
ensureStarted: method(object({ runtime: ManagedRuntimeConfigSchema }), LlmRuntimeStatusSchema, {
|
|
14155
14311
|
kind: "mutation",
|
|
14156
14312
|
auth: "admin"
|
|
@@ -14159,7 +14315,7 @@ var llmRuntimeCapability = {
|
|
|
14159
14315
|
kind: "mutation",
|
|
14160
14316
|
auth: "admin"
|
|
14161
14317
|
}),
|
|
14162
|
-
status: method(object({}), LlmRuntimeStatusSchema),
|
|
14318
|
+
status: method(object({}), LlmRuntimeStatusSchema, { auth: "admin" }),
|
|
14163
14319
|
installModel: method(object({ model: ManagedModelRefSchema }), _void(), {
|
|
14164
14320
|
kind: "mutation",
|
|
14165
14321
|
auth: "admin"
|
|
@@ -14168,8 +14324,8 @@ var llmRuntimeCapability = {
|
|
|
14168
14324
|
kind: "mutation",
|
|
14169
14325
|
auth: "admin"
|
|
14170
14326
|
}),
|
|
14171
|
-
listLocalModels: method(object({}), array(LlmNodeModelSchema)),
|
|
14172
|
-
getDiskUsage: method(object({}), LlmRuntimeDiskUsageSchema)
|
|
14327
|
+
listLocalModels: method(object({}), array(LlmNodeModelSchema), { auth: "admin" }),
|
|
14328
|
+
getDiskUsage: method(object({}), LlmRuntimeDiskUsageSchema, { auth: "admin" })
|
|
14173
14329
|
}
|
|
14174
14330
|
};
|
|
14175
14331
|
/**
|
|
@@ -18435,7 +18591,17 @@ var oauthIntegrationCapability = {
|
|
|
18435
18591
|
scope: "system",
|
|
18436
18592
|
mode: "collection",
|
|
18437
18593
|
internal: true,
|
|
18438
|
-
methods: {
|
|
18594
|
+
methods: {
|
|
18595
|
+
/**
|
|
18596
|
+
* `internal: true` did not gate the mount (see the 2026-08-26 note on
|
|
18597
|
+
* `data-store-provider`) — `getDescriptor` was reachable on the AppRouter
|
|
18598
|
+
* by ANY authenticated session at the default `auth: 'protected'`. The
|
|
18599
|
+
* real caller is `/api/oauth2/authorize` and `/api/oauth2/integrations`
|
|
18600
|
+
* (`oauth2-routes.ts`), which resolve the provider directly off the
|
|
18601
|
+
* capability registry — never through tRPC. `auth: 'admin'` closes the
|
|
18602
|
+
* tRPC surface without touching that path.
|
|
18603
|
+
*/
|
|
18604
|
+
getDescriptor: method(_void(), OauthIntegrationDescriptorSchema, { auth: "admin" }) }
|
|
18439
18605
|
};
|
|
18440
18606
|
/**
|
|
18441
18607
|
* pipeline-analytics — device-scoped wrapper cap. Refines raw
|
|
@@ -19834,6 +20000,29 @@ var pipelineAnalyticsCapability = {
|
|
|
19834
20000
|
kind: "mutation",
|
|
19835
20001
|
auth: "admin"
|
|
19836
20002
|
}),
|
|
20003
|
+
/**
|
|
20004
|
+
* Moves event media between locations — the OPERATOR's mover, without the
|
|
20005
|
+
* coordinator's lease. Twin of `recording.relocateFootage`: the same
|
|
20006
|
+
* engine the lease-gated coordinated migration uses
|
|
20007
|
+
* (`startStorageMigrationMove`), armable in the background and WITHOUT
|
|
20008
|
+
* pausing anything. Exists because `eventMedia` was the only storage
|
|
20009
|
+
* class whose only move path went through the recorder's global pause.
|
|
20010
|
+
*/
|
|
20011
|
+
relocateMedia: method(RelocateMediaInputSchema, object({ jobId: string() }), {
|
|
20012
|
+
kind: "mutation",
|
|
20013
|
+
auth: "admin"
|
|
20014
|
+
}),
|
|
20015
|
+
/** Every relocate job this addon knows about, newest first (in RAM: the
|
|
20016
|
+
* move is resumable, so a lost list costs nothing but the display). */
|
|
20017
|
+
listRelocateMediaJobs: method(object({}), array(RelocateJobSchema).readonly(), {
|
|
20018
|
+
kind: "query",
|
|
20019
|
+
auth: "admin"
|
|
20020
|
+
}),
|
|
20021
|
+
/** Cancel a running or queued relocate job. */
|
|
20022
|
+
cancelRelocateMedia: method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
20023
|
+
kind: "mutation",
|
|
20024
|
+
auth: "admin"
|
|
20025
|
+
}),
|
|
19837
20026
|
listOpsLog: method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
|
|
19838
20027
|
kind: "query",
|
|
19839
20028
|
auth: "admin"
|
|
@@ -20193,6 +20382,11 @@ object({
|
|
|
20193
20382
|
"jpeg"
|
|
20194
20383
|
])
|
|
20195
20384
|
});
|
|
20385
|
+
/**
|
|
20386
|
+
* Process-local frame identity. It is serializable so it can ride an in-process
|
|
20387
|
+
* capability call, but `registryId` deliberately prevents resolution in any
|
|
20388
|
+
* other process or execution group.
|
|
20389
|
+
*/
|
|
20196
20390
|
var FrameRefSchema = object({
|
|
20197
20391
|
registryId: string().min(1),
|
|
20198
20392
|
id: string().min(1),
|
|
@@ -23146,6 +23340,20 @@ var ssoBridgeCapability = {
|
|
|
23146
23340
|
mode: "singleton",
|
|
23147
23341
|
internal: true,
|
|
23148
23342
|
methods: {
|
|
23343
|
+
/**
|
|
23344
|
+
* `internal: true` did not gate the mount (see the 2026-08-26 note on
|
|
23345
|
+
* `data-store-provider`) — `signBridgeToken` was reachable on the
|
|
23346
|
+
* AppRouter by ANY authenticated session at the default
|
|
23347
|
+
* `auth: 'protected'`. The claims (including `isAdmin`) are CALLER-
|
|
23348
|
+
* SUPPLIED: an unprivileged session could have minted its own
|
|
23349
|
+
* `isAdmin: true` bridge token and redeemed it at
|
|
23350
|
+
* `/api/auth/sso/finish` to become admin — a full privilege escalation
|
|
23351
|
+
* through the exact surface this cap exists to close (see the module
|
|
23352
|
+
* docblock). Every real caller (`oauth-grants.ts`, `main.ts`
|
|
23353
|
+
* registration, the OIDC/magic-link addons) reaches this through
|
|
23354
|
+
* `ctx.api` / the in-process registry — never through tRPC — so
|
|
23355
|
+
* `auth: 'admin'` costs those callers nothing.
|
|
23356
|
+
*/
|
|
23149
23357
|
signBridgeToken: method(object({
|
|
23150
23358
|
claims: SsoBridgeClaimsSchema,
|
|
23151
23359
|
/**
|
|
@@ -23158,8 +23366,8 @@ var ssoBridgeCapability = {
|
|
|
23158
23366
|
* linking rather than produce an eternal token.
|
|
23159
23367
|
*/
|
|
23160
23368
|
ttlSec: union([number().int().positive(), literal("never")]).optional()
|
|
23161
|
-
}), object({ token: string() })),
|
|
23162
|
-
verifyBridgeToken: method(object({ token: string() }), SsoBridgeClaimsSchema.nullable())
|
|
23369
|
+
}), object({ token: string() }), { auth: "admin" }),
|
|
23370
|
+
verifyBridgeToken: method(object({ token: string() }), SsoBridgeClaimsSchema.nullable(), { auth: "admin" })
|
|
23163
23371
|
}
|
|
23164
23372
|
};
|
|
23165
23373
|
var ProviderListEntrySchema = discriminatedUnion("shouldSaveDiskSpace", [object({
|
|
@@ -23308,8 +23516,15 @@ var storageEvictableCapability = {
|
|
|
23308
23516
|
mode: "collection",
|
|
23309
23517
|
internal: true,
|
|
23310
23518
|
methods: {
|
|
23519
|
+
/**
|
|
23520
|
+
* `internal: true` did not gate the mount (see the 2026-08-26 note on
|
|
23521
|
+
* `data-store-provider`) — this was reachable on the AppRouter by ANY
|
|
23522
|
+
* authenticated session at the default `auth: 'protected'`. The only
|
|
23523
|
+
* consumer is the orchestrator's `StoragePressureManager`, which calls
|
|
23524
|
+
* `ctx.api` — never tRPC — so `auth: 'admin'` costs it nothing.
|
|
23525
|
+
*/
|
|
23311
23526
|
/** Bytes this provider holds on the given location — drives proportional fan-out. */
|
|
23312
|
-
getEvictableUsage: method(object({ locationId: string() }), EvictableUsageSchema),
|
|
23527
|
+
getEvictableUsage: method(object({ locationId: string() }), EvictableUsageSchema, { auth: "admin" }),
|
|
23313
23528
|
/**
|
|
23314
23529
|
* Free approximately `targetBytes` of this provider's OWN least-valuable
|
|
23315
23530
|
* data on the location (oldest footage, expired clips, …). Returns what it
|
|
@@ -23318,7 +23533,10 @@ var storageEvictableCapability = {
|
|
|
23318
23533
|
evict: method(object({
|
|
23319
23534
|
locationId: string(),
|
|
23320
23535
|
targetBytes: number().int().positive()
|
|
23321
|
-
}), EvictResultSchema, {
|
|
23536
|
+
}), EvictResultSchema, {
|
|
23537
|
+
kind: "mutation",
|
|
23538
|
+
auth: "admin"
|
|
23539
|
+
})
|
|
23322
23540
|
}
|
|
23323
23541
|
};
|
|
23324
23542
|
/**
|
|
@@ -23421,43 +23639,82 @@ var storageProviderCapability = {
|
|
|
23421
23639
|
mode: "collection",
|
|
23422
23640
|
internal: true,
|
|
23423
23641
|
methods: {
|
|
23642
|
+
/**
|
|
23643
|
+
* Every method below except `testLocation` had NO `auth` override —
|
|
23644
|
+
* `internal: true` did not gate the mount (see the 2026-08-26 note on
|
|
23645
|
+
* `data-store-provider`), so this was reachable on the AppRouter by ANY
|
|
23646
|
+
* authenticated session at the default `auth: 'protected'`: arbitrary
|
|
23647
|
+
* read/write/delete/list against any storage location the operator has
|
|
23648
|
+
* configured, keyed only by a caller-supplied `location` + `relativePath`
|
|
23649
|
+
* — the same "public consumers never see this cap" claim that was false
|
|
23650
|
+
* for `data-store-provider`, here gating raw file I/O instead of raw
|
|
23651
|
+
* settings rows. The only legitimate caller,
|
|
23652
|
+
* `addon-registry.service.ts`'s `activeStorageProvider`, calls the
|
|
23653
|
+
* provider object directly (in-process) — never tRPC — so `auth: 'admin'`
|
|
23654
|
+
* on every method costs it nothing. Public consumers already go through
|
|
23655
|
+
* the separate `storage` singleton cap.
|
|
23656
|
+
*/
|
|
23424
23657
|
/** Self-description for the "Add location" wizard. */
|
|
23425
|
-
getProviderInfo: method(_void(), ProviderInfoSchema),
|
|
23658
|
+
getProviderInfo: method(_void(), ProviderInfoSchema, { auth: "admin" }),
|
|
23426
23659
|
/** Validate config + probe connectivity. Called on add and on edit. */
|
|
23427
23660
|
testLocation: method(object({ config: record(string(), unknown()) }), TestLocationResultSchema, { auth: "admin" }),
|
|
23428
23661
|
resolve: method(object({
|
|
23429
23662
|
location: StorageLocationSchema,
|
|
23430
23663
|
relativePath: string()
|
|
23431
|
-
}), string()),
|
|
23664
|
+
}), string(), { auth: "admin" }),
|
|
23432
23665
|
write: method(object({
|
|
23433
23666
|
location: StorageLocationSchema,
|
|
23434
23667
|
relativePath: string(),
|
|
23435
23668
|
data: _instanceof(Uint8Array)
|
|
23436
|
-
}), _void(), {
|
|
23669
|
+
}), _void(), {
|
|
23670
|
+
kind: "mutation",
|
|
23671
|
+
auth: "admin"
|
|
23672
|
+
}),
|
|
23437
23673
|
read: method(object({
|
|
23438
23674
|
location: StorageLocationSchema,
|
|
23439
23675
|
relativePath: string()
|
|
23440
|
-
}), _instanceof(Uint8Array)),
|
|
23676
|
+
}), _instanceof(Uint8Array), { auth: "admin" }),
|
|
23441
23677
|
exists: method(object({
|
|
23442
23678
|
location: StorageLocationSchema,
|
|
23443
23679
|
relativePath: string()
|
|
23444
|
-
}), boolean()),
|
|
23680
|
+
}), boolean(), { auth: "admin" }),
|
|
23445
23681
|
list: method(object({
|
|
23446
23682
|
location: StorageLocationSchema,
|
|
23447
23683
|
prefix: string().optional()
|
|
23448
|
-
}), array(string()).readonly()),
|
|
23684
|
+
}), array(string()).readonly(), { auth: "admin" }),
|
|
23449
23685
|
delete: method(object({
|
|
23450
23686
|
location: StorageLocationSchema,
|
|
23451
23687
|
relativePath: string()
|
|
23452
|
-
}), _void(), {
|
|
23453
|
-
|
|
23454
|
-
|
|
23455
|
-
|
|
23456
|
-
|
|
23457
|
-
|
|
23458
|
-
|
|
23459
|
-
|
|
23460
|
-
|
|
23688
|
+
}), _void(), {
|
|
23689
|
+
kind: "mutation",
|
|
23690
|
+
auth: "admin"
|
|
23691
|
+
}),
|
|
23692
|
+
getAvailableSpace: method(object({ location: StorageLocationSchema }), number().nullable(), { auth: "admin" }),
|
|
23693
|
+
beginUpload: method(BeginUploadInputSchema, BeginUploadResultSchema, {
|
|
23694
|
+
kind: "mutation",
|
|
23695
|
+
auth: "admin"
|
|
23696
|
+
}),
|
|
23697
|
+
writeChunk: method(WriteChunkInputSchema, _void(), {
|
|
23698
|
+
kind: "mutation",
|
|
23699
|
+
auth: "admin"
|
|
23700
|
+
}),
|
|
23701
|
+
finalizeUpload: method(FinalizeUploadInputSchema, _void(), {
|
|
23702
|
+
kind: "mutation",
|
|
23703
|
+
auth: "admin"
|
|
23704
|
+
}),
|
|
23705
|
+
abortUpload: method(AbortUploadInputSchema, _void(), {
|
|
23706
|
+
kind: "mutation",
|
|
23707
|
+
auth: "admin"
|
|
23708
|
+
}),
|
|
23709
|
+
beginDownload: method(BeginDownloadInputSchema, BeginDownloadResultSchema, {
|
|
23710
|
+
kind: "mutation",
|
|
23711
|
+
auth: "admin"
|
|
23712
|
+
}),
|
|
23713
|
+
readChunk: method(ReadChunkInputSchema, _instanceof(Uint8Array), { auth: "admin" }),
|
|
23714
|
+
endDownload: method(EndDownloadInputSchema, _void(), {
|
|
23715
|
+
kind: "mutation",
|
|
23716
|
+
auth: "admin"
|
|
23717
|
+
})
|
|
23461
23718
|
}
|
|
23462
23719
|
};
|
|
23463
23720
|
/** Profile-exported FormBuilder schema. Shape is ConfigUISchema at the UI. */
|
|
@@ -23790,9 +24047,28 @@ var userPasskeysCapability = {
|
|
|
23790
24047
|
auth: "admin",
|
|
23791
24048
|
access: "create"
|
|
23792
24049
|
}),
|
|
24050
|
+
/**
|
|
24051
|
+
* The four methods below had NO `auth` override — `internal: true` did
|
|
24052
|
+
* not gate the mount (see the 2026-08-26 note on `data-store-provider`),
|
|
24053
|
+
* so they were reachable on the AppRouter at the default
|
|
24054
|
+
* `auth: 'protected'` (any authenticated session), inconsistent with
|
|
24055
|
+
* every other method on this cap (all already `auth: 'admin'`).
|
|
24056
|
+
*
|
|
24057
|
+
* ⚠ Checked before gating: these are also the PRE-AUTH login-ceremony
|
|
24058
|
+
* methods, so admin-gating them here must not break login for an
|
|
24059
|
+
* unauthenticated principal. It doesn't — the real login path is the
|
|
24060
|
+
* PUBLIC `auth.beginAuthentication` / `auth.finishAuthentication` /
|
|
24061
|
+
* `auth.beginDiscoverableAuthentication` / `auth.finishDiscoverableAuthentication`
|
|
24062
|
+
* procedures in `server/backend/src/api/core/auth.router.ts`, which call
|
|
24063
|
+
* `provider.beginAuthentication(...)` etc. directly against the
|
|
24064
|
+
* capability-registry-resolved provider — never through this cap's own
|
|
24065
|
+
* tRPC route. `auth: 'admin'` here only closes a redundant, unused
|
|
24066
|
+
* second entry point onto the same ceremony.
|
|
24067
|
+
*/
|
|
23793
24068
|
beginAuthentication: method(object({ userId: string().optional() }), object({ optionsJSON: record(string(), unknown()) }), {
|
|
23794
24069
|
kind: "mutation",
|
|
23795
|
-
access: "view"
|
|
24070
|
+
access: "view",
|
|
24071
|
+
auth: "admin"
|
|
23796
24072
|
}),
|
|
23797
24073
|
finishAuthentication: method(object({
|
|
23798
24074
|
/** Required — the user the assertion belongs to (verified). */
|
|
@@ -23801,11 +24077,13 @@ var userPasskeysCapability = {
|
|
|
23801
24077
|
response: record(string(), unknown())
|
|
23802
24078
|
}), object({ verified: boolean() }), {
|
|
23803
24079
|
kind: "mutation",
|
|
23804
|
-
access: "view"
|
|
24080
|
+
access: "view",
|
|
24081
|
+
auth: "admin"
|
|
23805
24082
|
}),
|
|
23806
24083
|
beginDiscoverableAuthentication: method(object({}), object({ optionsJSON: record(string(), unknown()) }), {
|
|
23807
24084
|
kind: "mutation",
|
|
23808
|
-
access: "view"
|
|
24085
|
+
access: "view",
|
|
24086
|
+
auth: "admin"
|
|
23809
24087
|
}),
|
|
23810
24088
|
finishDiscoverableAuthentication: method(object({
|
|
23811
24089
|
/** AuthenticationResponseJSON from the browser. */
|
|
@@ -23814,7 +24092,8 @@ response: record(string(), unknown()) }), object({
|
|
|
23814
24092
|
userId: string().nullable()
|
|
23815
24093
|
}), {
|
|
23816
24094
|
kind: "mutation",
|
|
23817
|
-
access: "view"
|
|
24095
|
+
access: "view",
|
|
24096
|
+
auth: "admin"
|
|
23818
24097
|
}),
|
|
23819
24098
|
listPasskeys: method(object({ userId: string() }), array(PasskeySummarySchema), { auth: "admin" }),
|
|
23820
24099
|
removePasskey: method(object({
|
|
@@ -23992,6 +24271,14 @@ var VectorStatsResultSchema = object({
|
|
|
23992
24271
|
/** False when the backend ranks approximately. */
|
|
23993
24272
|
exact: boolean()
|
|
23994
24273
|
});
|
|
24274
|
+
/**
|
|
24275
|
+
* `internal: true` did not gate the mount (see the 2026-08-26 note on
|
|
24276
|
+
* `data-store-provider`) — every method below was reachable on the AppRouter
|
|
24277
|
+
* by ANY authenticated session at the default `auth: 'protected'`. The only
|
|
24278
|
+
* consumers (`addon-post-analysis`'s embedding stores) reach this cap via
|
|
24279
|
+
* `ctx.api` — UDS/Moleculer, never tRPC — so `auth: 'admin'` on every method
|
|
24280
|
+
* costs them nothing. No client (viewer or admin-ui) calls `vectorStore.*`.
|
|
24281
|
+
*/
|
|
23995
24282
|
var vectorStoreCapability = {
|
|
23996
24283
|
name: "vector-store",
|
|
23997
24284
|
scope: "system",
|
|
@@ -23999,14 +24286,26 @@ var vectorStoreCapability = {
|
|
|
23999
24286
|
internal: true,
|
|
24000
24287
|
methods: {
|
|
24001
24288
|
/** Idempotent. Re-declaring with a different `dim` is an error, not a wipe. */
|
|
24002
|
-
declareIndex: method(VectorDeclareIndexInputSchema, _void(), {
|
|
24003
|
-
|
|
24004
|
-
|
|
24289
|
+
declareIndex: method(VectorDeclareIndexInputSchema, _void(), {
|
|
24290
|
+
kind: "mutation",
|
|
24291
|
+
auth: "admin"
|
|
24292
|
+
}),
|
|
24293
|
+
upsert: method(VectorUpsertInputSchema, VectorUpsertResultSchema, {
|
|
24294
|
+
kind: "mutation",
|
|
24295
|
+
auth: "admin"
|
|
24296
|
+
}),
|
|
24297
|
+
query: method(VectorQueryInputSchema, VectorQueryResultSchema, { auth: "admin" }),
|
|
24005
24298
|
/** Metadata by id, no vectors — see {@link VectorGetResultSchema}. */
|
|
24006
|
-
getByIds: method(VectorGetInputSchema, VectorGetResultSchema),
|
|
24007
|
-
deleteByIds: method(VectorDeleteInputSchema, VectorDeleteResultSchema, {
|
|
24008
|
-
|
|
24009
|
-
|
|
24299
|
+
getByIds: method(VectorGetInputSchema, VectorGetResultSchema, { auth: "admin" }),
|
|
24300
|
+
deleteByIds: method(VectorDeleteInputSchema, VectorDeleteResultSchema, {
|
|
24301
|
+
kind: "mutation",
|
|
24302
|
+
auth: "admin"
|
|
24303
|
+
}),
|
|
24304
|
+
deleteByFilter: method(VectorDeleteByFilterInputSchema, VectorDeleteResultSchema, {
|
|
24305
|
+
kind: "mutation",
|
|
24306
|
+
auth: "admin"
|
|
24307
|
+
}),
|
|
24308
|
+
stats: method(VectorStatsInputSchema, VectorStatsResultSchema, { auth: "admin" })
|
|
24010
24309
|
}
|
|
24011
24310
|
};
|
|
24012
24311
|
var ClipSchema = object({
|
|
@@ -26855,7 +27154,27 @@ var faceGalleryCapability = {
|
|
|
26855
27154
|
scope: "system",
|
|
26856
27155
|
mode: "singleton",
|
|
26857
27156
|
methods: {
|
|
26858
|
-
listIdentities: method(
|
|
27157
|
+
listIdentities: method(object({
|
|
27158
|
+
/**
|
|
27159
|
+
* Inline {@link IdentitySchema.coverBase64} on every row.
|
|
27160
|
+
*
|
|
27161
|
+
* Default `false`, the same inversion `listRecentFaces` and
|
|
27162
|
+
* `listPlates` took on 2026-08-25 (see `include-crops-default.ts` for
|
|
27163
|
+
* why the burden belongs on the caller that WANTS the bytes). Measured
|
|
27164
|
+
* on the live hub the same day: four identities cost 40,979 B with the
|
|
27165
|
+
* covers inline, ~10 KB of base64 per row, on a query this UI mounts
|
|
27166
|
+
* four times and the viewer holds at `staleTime: 30_000`.
|
|
27167
|
+
*
|
|
27168
|
+
* Nothing loses its avatar: `coverMediaKey` is already on every row and
|
|
27169
|
+
* the `event-media` plane serves that key `immutable` with an ETag.
|
|
27170
|
+
*
|
|
27171
|
+
* **This is an INPUT field, so it does not reach the addon until the
|
|
27172
|
+
* next train** — the hub router validates cap inputs against its own
|
|
27173
|
+
* compiled Zod and strips a key it does not know. Until then the
|
|
27174
|
+
* provider sees `undefined`, which resolves to `false`: the cheap shape
|
|
27175
|
+
* is what ships, and the opt-in becomes reachable when the train lands.
|
|
27176
|
+
*/
|
|
27177
|
+
includeCrops: boolean().optional() }).optional(), array(IdentitySchema).readonly()),
|
|
26859
27178
|
createIdentity: method(object({ name: string().min(1) }), IdentitySchema, {
|
|
26860
27179
|
kind: "mutation",
|
|
26861
27180
|
auth: "admin"
|
|
@@ -30108,8 +30427,10 @@ var PlateInfoSchema = object({
|
|
|
30108
30427
|
keyFrameMediaKey: string().optional(),
|
|
30109
30428
|
base64: string().optional(),
|
|
30110
30429
|
/**
|
|
30111
|
-
* Same crop as a data-plane URL
|
|
30112
|
-
* never inlines JPEG; `listPlates`
|
|
30430
|
+
* Same crop as a data-plane URL, always present when the plate has a stored
|
|
30431
|
+
* crop. `getPlateByTrack` returns this and never inlines JPEG; `listPlates`
|
|
30432
|
+
* and `searchPlates` inline the crop only when their `includeCrops` input is
|
|
30433
|
+
* left at its `true` default.
|
|
30113
30434
|
*/
|
|
30114
30435
|
cropUrl: string().optional()
|
|
30115
30436
|
});
|
|
@@ -30142,7 +30463,25 @@ var plateGalleryCapability = {
|
|
|
30142
30463
|
methods: {
|
|
30143
30464
|
listPlates: method(object({
|
|
30144
30465
|
deviceId: number().int().optional(),
|
|
30145
|
-
limit: number().int().positive().optional()
|
|
30466
|
+
limit: number().int().positive().optional(),
|
|
30467
|
+
/**
|
|
30468
|
+
* Inline the base64 crop on every row. Default `true` — the existing
|
|
30469
|
+
* behaviour, kept so no caller breaks.
|
|
30470
|
+
*
|
|
30471
|
+
* Set `false` once the caller renders {@link PlateInfo.cropUrl}.
|
|
30472
|
+
* Measured on the live hub at the 500 rows the Plates view asks for:
|
|
30473
|
+
* 879,403 B and 27.7 s with the crops inline, against a few KiB of
|
|
30474
|
+
* metadata without them — and the browser then caches the images.
|
|
30475
|
+
*
|
|
30476
|
+
* This is the plate twin of `faceGallery.listRecentFaces`'s option;
|
|
30477
|
+
* plates were the one gallery list left without it.
|
|
30478
|
+
*
|
|
30479
|
+
* **This is an INPUT field, so it does not reach the addon until the
|
|
30480
|
+
* next train.** The hub router validates cap inputs against its own
|
|
30481
|
+
* compiled Zod and strips a key it does not know. Until the train
|
|
30482
|
+
* ships, sending `false` is harmless and keeps the crops inline.
|
|
30483
|
+
*/
|
|
30484
|
+
includeCrops: boolean().optional()
|
|
30146
30485
|
}).optional(), array(PlateInfoSchema).readonly()),
|
|
30147
30486
|
getPlateByTrack: method(object({
|
|
30148
30487
|
deviceId: number().int(),
|
|
@@ -30153,7 +30492,9 @@ var plateGalleryCapability = {
|
|
|
30153
30492
|
searchPlates: method(object({
|
|
30154
30493
|
text: string().min(1),
|
|
30155
30494
|
maxDistance: number().int().min(0).optional(),
|
|
30156
|
-
limit: number().int().positive().optional()
|
|
30495
|
+
limit: number().int().positive().optional(),
|
|
30496
|
+
/** See `listPlates.includeCrops`. Default `true`. */
|
|
30497
|
+
includeCrops: boolean().optional()
|
|
30157
30498
|
}), array(PlateInfoSchema).readonly()),
|
|
30158
30499
|
/** Suggest groups of near-identical reads (same physical plate) for review/merge. */
|
|
30159
30500
|
suggestPlateClusters: method(object({
|
|
@@ -30173,7 +30514,13 @@ var plateGalleryCapability = {
|
|
|
30173
30514
|
kind: "mutation",
|
|
30174
30515
|
auth: "admin"
|
|
30175
30516
|
}),
|
|
30176
|
-
listVehicles: method(
|
|
30517
|
+
listVehicles: method(object({
|
|
30518
|
+
/** Inline {@link VehicleSchema.coverBase64} on every row. Default
|
|
30519
|
+
* `false` — the vehicle twin of `faceGallery.listIdentities`'s
|
|
30520
|
+
* option; `coverMediaKey` + the `event-media` plane carry the picture.
|
|
30521
|
+
* INPUT field: stripped by the hub router until the train ships, which
|
|
30522
|
+
* resolves to `false` and is exactly the intended default. */
|
|
30523
|
+
includeCrops: boolean().optional() }).optional(), array(VehicleSchema).readonly()),
|
|
30177
30524
|
createVehicle: method(object({ name: string().min(1) }), VehicleSchema, {
|
|
30178
30525
|
kind: "mutation",
|
|
30179
30526
|
auth: "admin"
|
|
@@ -36917,6 +37264,12 @@ Object.freeze({
|
|
|
36917
37264
|
addonId: null,
|
|
36918
37265
|
access: "create"
|
|
36919
37266
|
},
|
|
37267
|
+
"pipelineAnalytics.cancelRelocateMedia": {
|
|
37268
|
+
capName: "pipeline-analytics",
|
|
37269
|
+
capScope: "device",
|
|
37270
|
+
addonId: null,
|
|
37271
|
+
access: "create"
|
|
37272
|
+
},
|
|
36920
37273
|
"pipelineAnalytics.cancelStorageMigrationMove": {
|
|
36921
37274
|
capName: "pipeline-analytics",
|
|
36922
37275
|
capScope: "device",
|
|
@@ -37091,6 +37444,12 @@ Object.freeze({
|
|
|
37091
37444
|
addonId: null,
|
|
37092
37445
|
access: "view"
|
|
37093
37446
|
},
|
|
37447
|
+
"pipelineAnalytics.listRelocateMediaJobs": {
|
|
37448
|
+
capName: "pipeline-analytics",
|
|
37449
|
+
capScope: "device",
|
|
37450
|
+
addonId: null,
|
|
37451
|
+
access: "view"
|
|
37452
|
+
},
|
|
37094
37453
|
"pipelineAnalytics.listRetrainAnnotations": {
|
|
37095
37454
|
capName: "pipeline-analytics",
|
|
37096
37455
|
capScope: "device",
|
|
@@ -37169,6 +37528,12 @@ Object.freeze({
|
|
|
37169
37528
|
addonId: null,
|
|
37170
37529
|
access: "create"
|
|
37171
37530
|
},
|
|
37531
|
+
"pipelineAnalytics.relocateMedia": {
|
|
37532
|
+
capName: "pipeline-analytics",
|
|
37533
|
+
capScope: "device",
|
|
37534
|
+
addonId: null,
|
|
37535
|
+
access: "create"
|
|
37536
|
+
},
|
|
37172
37537
|
"pipelineAnalytics.restageRetrainTrack": {
|
|
37173
37538
|
capName: "pipeline-analytics",
|
|
37174
37539
|
capScope: "device",
|