@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.mjs
CHANGED
|
@@ -6629,7 +6629,7 @@ function method(input, output, options) {
|
|
|
6629
6629
|
input,
|
|
6630
6630
|
output,
|
|
6631
6631
|
kind: options?.kind ?? "query",
|
|
6632
|
-
auth: options
|
|
6632
|
+
...options?.auth !== void 0 ? { auth: options.auth } : {},
|
|
6633
6633
|
...options?.access !== void 0 ? { access: options.access } : {},
|
|
6634
6634
|
...options?.caller !== void 0 ? { caller: options.caller } : {},
|
|
6635
6635
|
timeoutMs: options?.timeoutMs
|
|
@@ -6659,8 +6659,17 @@ var adminUiCapability = {
|
|
|
6659
6659
|
mode: "singleton",
|
|
6660
6660
|
internal: true,
|
|
6661
6661
|
methods: {
|
|
6662
|
-
|
|
6663
|
-
|
|
6662
|
+
/**
|
|
6663
|
+
* `internal: true` did not gate the mount (see the 2026-08-26 note on
|
|
6664
|
+
* `data-store-provider`) — both methods were reachable on the AppRouter
|
|
6665
|
+
* by ANY authenticated session at the default `auth: 'protected'`, and
|
|
6666
|
+
* `getStaticDir` leaks a hub filesystem path. The only caller is
|
|
6667
|
+
* `main.ts`'s static-file bootstrap, via `capRegistry.getSingletonForNode`
|
|
6668
|
+
* — never tRPC — so `auth: 'admin'` costs it nothing. The actual admin-ui
|
|
6669
|
+
* SPA assets are served as plain static files, unaffected by this gate.
|
|
6670
|
+
*/
|
|
6671
|
+
getStaticDir: method(_void(), StaticDirOutputSchema$1, { auth: "admin" }),
|
|
6672
|
+
getVersion: method(_void(), VersionOutputSchema$1, { auth: "admin" })
|
|
6664
6673
|
}
|
|
6665
6674
|
};
|
|
6666
6675
|
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
@@ -6996,8 +7005,23 @@ var viewerUiCapability = {
|
|
|
6996
7005
|
mode: "singleton",
|
|
6997
7006
|
internal: true,
|
|
6998
7007
|
methods: {
|
|
6999
|
-
|
|
7000
|
-
|
|
7008
|
+
/**
|
|
7009
|
+
* `internal: true` did not gate the mount (see the 2026-08-26 note on
|
|
7010
|
+
* `data-store-provider`) — both methods were reachable on the AppRouter
|
|
7011
|
+
* by ANY authenticated session at the default `auth: 'protected'`, and
|
|
7012
|
+
* `getStaticDir` leaks a hub filesystem path.
|
|
7013
|
+
*
|
|
7014
|
+
* ⚠ Checked before gating: the VIEWER app IS used by a non-admin user
|
|
7015
|
+
* (`roberta`), but it never calls `viewerUi.*` over tRPC. The static SPA
|
|
7016
|
+
* it loads is served by the plain `GET /viewer/*` Fastify route in
|
|
7017
|
+
* `main.ts`, which reads `staticDir`/`indexPath` from a module-level
|
|
7018
|
+
* cache populated ONCE at boot via `capRegistry.getSingletonForNode`
|
|
7019
|
+
* (in-process, not tRPC) — the cap's tRPC procedure is never on that
|
|
7020
|
+
* request path. `auth: 'admin'` here does not block a single viewer
|
|
7021
|
+
* user from loading the app.
|
|
7022
|
+
*/
|
|
7023
|
+
getStaticDir: method(_void(), StaticDirOutputSchema, { auth: "admin" }),
|
|
7024
|
+
getVersion: method(_void(), VersionOutputSchema, { auth: "admin" })
|
|
7001
7025
|
}
|
|
7002
7026
|
};
|
|
7003
7027
|
/**
|
|
@@ -7672,24 +7696,6 @@ var RecordingRetentionSchema = object({
|
|
|
7672
7696
|
maxSizeGb: number().min(0).optional()
|
|
7673
7697
|
});
|
|
7674
7698
|
/**
|
|
7675
|
-
* Scrub-thumbnail fidelity preset — the single per-camera selector bundling the
|
|
7676
|
-
* sprite tile RESOLUTION + JPEG QUALITY the recorder packs timeline-scrub
|
|
7677
|
-
* previews at. Five graduated steps; absent on a config = `standard` (the
|
|
7678
|
-
* shipped default, matching `sheet-geometry`/`sheet-composer`).
|
|
7679
|
-
*
|
|
7680
|
-
* Existing sheets are IMMUTABLE — a changed preset applies to NEW windows only.
|
|
7681
|
-
* Each window's index sidecar carries its own tile dims, so a camera whose
|
|
7682
|
-
* preset changed over time renders every historical window at the dims it was
|
|
7683
|
-
* written with.
|
|
7684
|
-
*/
|
|
7685
|
-
var ScrubThumbnailPresetSchema = _enum([
|
|
7686
|
-
"minimal",
|
|
7687
|
-
"low",
|
|
7688
|
-
"standard",
|
|
7689
|
-
"high",
|
|
7690
|
-
"max"
|
|
7691
|
-
]);
|
|
7692
|
-
/**
|
|
7693
7699
|
* The full per-camera recording intent — the wire shape of a RecordingTarget.
|
|
7694
7700
|
*
|
|
7695
7701
|
* `bands` is the ONLY authored recording intent: what to record, when, and on
|
|
@@ -7697,7 +7703,11 @@ var ScrubThumbnailPresetSchema = _enum([
|
|
|
7697
7703
|
* other field is a storage knob (profiles, segment length, retention, scrub).
|
|
7698
7704
|
*
|
|
7699
7705
|
* STRICT on purpose: the legacy authoring surface (`schedule`/`schedules`/
|
|
7700
|
-
* `triggers`/`preBufferSec`/`postBufferSec`/`rules`) was retired 2026-07-30
|
|
7706
|
+
* `triggers`/`preBufferSec`/`postBufferSec`/`rules`) was retired 2026-07-30,
|
|
7707
|
+
* and `scrubThumbnails` — a five-step fidelity knob for a sprite tier that was
|
|
7708
|
+
* deleted on 2026-07-24 and had ZERO consumers in the recorder — on 2026-08-25
|
|
7709
|
+
* (D62: a switch that writes a store nobody reads is worse than no switch).
|
|
7710
|
+
* Stored rows keep loading: the READ schema is `.strip()` (config-store.ts).
|
|
7701
7711
|
* A stale caller must fail loudly — silently stripping its legacy intent would
|
|
7702
7712
|
* persist a band-less config, i.e. silently stop recording the camera.
|
|
7703
7713
|
*/
|
|
@@ -7720,14 +7730,7 @@ var RecordingConfigSchema = object({
|
|
|
7720
7730
|
* "off" is the absence of a covering band, never a band value.
|
|
7721
7731
|
*/
|
|
7722
7732
|
bands: array(RecordingBandSchema).default([]),
|
|
7723
|
-
retention: RecordingRetentionSchema.optional()
|
|
7724
|
-
/**
|
|
7725
|
-
* Per-camera scrub-thumbnail fidelity preset (resolution + JPEG quality for
|
|
7726
|
-
* timeline-scrub sprite previews). Absent = `standard`. Applies to NEW
|
|
7727
|
-
* windows only — existing sheets are immutable, and each window's index
|
|
7728
|
-
* carries its own tile dims so mixed-preset history renders correctly.
|
|
7729
|
-
*/
|
|
7730
|
-
scrubThumbnails: ScrubThumbnailPresetSchema.optional()
|
|
7733
|
+
retention: RecordingRetentionSchema.optional()
|
|
7731
7734
|
}).strict();
|
|
7732
7735
|
/**
|
|
7733
7736
|
* Entity-relocation job state (storage entity-routing spec, Phase 4).
|
|
@@ -7803,10 +7806,11 @@ var RelocateFootageInputSchema = object({
|
|
|
7803
7806
|
* `RecordingConfig.enabled` or camera wrapper bindings. */
|
|
7804
7807
|
var StorageMigrationLeaseInputSchema = object({ leaseId: string().min(1) });
|
|
7805
7808
|
var StorageMigrationFootageMoveInputSchema = RelocateFootageInputSchema.extend({ leaseId: string().min(1) });
|
|
7806
|
-
var
|
|
7809
|
+
var RelocateMediaInputSchema = object({
|
|
7807
7810
|
toLocationId: string(),
|
|
7808
7811
|
throttleMbps: number().min(1).max(1e3).optional()
|
|
7809
|
-
})
|
|
7812
|
+
});
|
|
7813
|
+
var StorageMigrationMediaMoveInputSchema = RelocateMediaInputSchema.extend({ leaseId: string().min(1) });
|
|
7810
7814
|
/** The independently selectable logical storage classes. `recordings`
|
|
7811
7815
|
* encompasses the high and mid segment profiles; `recordingsLow` is low
|
|
7812
7816
|
* segments; `eventMedia` is post-analysis blobs. */
|
|
@@ -8101,7 +8105,26 @@ var LabelDefinitionSchema = object({
|
|
|
8101
8105
|
description: string().optional(),
|
|
8102
8106
|
icon: string().optional()
|
|
8103
8107
|
});
|
|
8104
|
-
|
|
8108
|
+
/**
|
|
8109
|
+
* Wire schema for a per-model CATALOG classMap override
|
|
8110
|
+
* (`ModelCatalogEntry.classMap` / `ModelConvertMetadata.classMap`) —
|
|
8111
|
+
* restricted to {@link CLASS_MAP_MACRO_TARGETS}, the only macros the
|
|
8112
|
+
* detection pipeline executor actually routes.
|
|
8113
|
+
*
|
|
8114
|
+
* This is deliberately a DIFFERENT, narrower shape than the general-purpose
|
|
8115
|
+
* `ClassMapDefinition` interface above (e.g. `IDetectionAddon.getClassMap()`
|
|
8116
|
+
* and the audio `YAMNET_TO_MACRO` catalog both use macro targets outside this
|
|
8117
|
+
* enum) — the two used to share the name `ClassMapDefinition`/
|
|
8118
|
+
* `ClassMapDefinitionSchema`, which made the schema-type-twin guard
|
|
8119
|
+
* (`scripts/check-schema-type-twins.ts`) flag them as a duplicated shape. They
|
|
8120
|
+
* are not: it is two different concepts colliding on a name. Keep this type
|
|
8121
|
+
* under its own name rather than reusing `ClassMapDefinition` — reusing it
|
|
8122
|
+
* would either narrow every `ClassMapDefinition` consumer to the four
|
|
8123
|
+
* detection macros (breaking `YAMNET_TO_MACRO`) or drop the validation this
|
|
8124
|
+
* schema exists for (see the "rejects a classMap whose target is not a
|
|
8125
|
+
* detection macro" test in `model-catalog-schema.test.ts`).
|
|
8126
|
+
*/
|
|
8127
|
+
var DetectionCatalogClassMapSchema = object({
|
|
8105
8128
|
mapping: record(string(), _enum([
|
|
8106
8129
|
"person",
|
|
8107
8130
|
"vehicle",
|
|
@@ -8306,7 +8329,7 @@ var ModelCatalogEntrySchema = object({
|
|
|
8306
8329
|
* applies (Frigate / COCO public catalog). Set on a custom model whose raw
|
|
8307
8330
|
* labels already ARE the CamStack macros (Scrypted identity map).
|
|
8308
8331
|
*/
|
|
8309
|
-
classMap:
|
|
8332
|
+
classMap: DetectionCatalogClassMapSchema.optional()
|
|
8310
8333
|
});
|
|
8311
8334
|
var ConvertTargetSchema = discriminatedUnion("format", [object({
|
|
8312
8335
|
format: literal("openvino"),
|
|
@@ -8336,7 +8359,7 @@ var ModelConvertMetadataSchema = object({
|
|
|
8336
8359
|
"segmentation"
|
|
8337
8360
|
]),
|
|
8338
8361
|
faceAlignment: boolean().optional(),
|
|
8339
|
-
classMap:
|
|
8362
|
+
classMap: DetectionCatalogClassMapSchema.optional()
|
|
8340
8363
|
});
|
|
8341
8364
|
var ConvertResultSchema = object({
|
|
8342
8365
|
entry: ModelCatalogEntrySchema,
|
|
@@ -9209,7 +9232,18 @@ var addonPagesSourceCapability = {
|
|
|
9209
9232
|
scope: "system",
|
|
9210
9233
|
mode: "collection",
|
|
9211
9234
|
internal: true,
|
|
9212
|
-
methods: {
|
|
9235
|
+
methods: {
|
|
9236
|
+
/**
|
|
9237
|
+
* `internal: true` did not gate the mount (see the 2026-08-26 note on
|
|
9238
|
+
* `data-store-provider`) — this was reachable on the AppRouter by ANY
|
|
9239
|
+
* authenticated session at the default `auth: 'protected'`. The only
|
|
9240
|
+
* consumer, the `addon-pages-aggregator` builtin, reads it via
|
|
9241
|
+
* `ctx.capabilities.getCollection('addon-pages-source')` — LOCAL-PROCESS
|
|
9242
|
+
* only, never tRPC (per `ctx.capabilities` seeing only the local
|
|
9243
|
+
* process). The public, enriched listing admin-ui actually consumes is
|
|
9244
|
+
* the separate `addon-pages` cap, unaffected by this change.
|
|
9245
|
+
*/
|
|
9246
|
+
listPages: method(_void(), array(AddonPageDeclarationSchema).readonly(), { auth: "admin" }) }
|
|
9213
9247
|
};
|
|
9214
9248
|
var AddonHttpRouteSchema = object({
|
|
9215
9249
|
method: _enum([
|
|
@@ -9506,7 +9540,20 @@ var addonWidgetsSourceCapability = {
|
|
|
9506
9540
|
scope: "system",
|
|
9507
9541
|
mode: "collection",
|
|
9508
9542
|
internal: true,
|
|
9509
|
-
methods: {
|
|
9543
|
+
methods: {
|
|
9544
|
+
/**
|
|
9545
|
+
* `internal: true` did not gate the mount (see the 2026-08-26 note on
|
|
9546
|
+
* `data-store-provider`) — this was reachable on the AppRouter by ANY
|
|
9547
|
+
* authenticated session at the default `auth: 'protected'`. The only
|
|
9548
|
+
* consumer, the `addon-widgets-aggregator` builtin, reads it via
|
|
9549
|
+
* `ctx.capabilities.getCollection('addon-widgets-source')` — LOCAL-PROCESS
|
|
9550
|
+
* only, never tRPC. The public, enriched listing admin-ui actually
|
|
9551
|
+
* consumes is the separate `addon-widgets` cap (`listWidgets` there is
|
|
9552
|
+
* gated separately, and a `preAuth: true` widget is surfaced through the
|
|
9553
|
+
* PUBLIC `auth.listLoginMethods` contribution channel instead) —
|
|
9554
|
+
* neither is affected by this change.
|
|
9555
|
+
*/
|
|
9556
|
+
listWidgets: method(_void(), array(WidgetMetadataSchema).readonly(), { auth: "admin" }) }
|
|
9510
9557
|
};
|
|
9511
9558
|
/**
|
|
9512
9559
|
* `addon-widgets` — system-scoped singleton aggregator cap. Public-facing
|
|
@@ -11670,7 +11717,17 @@ var customModelRegistryCapability = {
|
|
|
11670
11717
|
scope: "system",
|
|
11671
11718
|
mode: "collection",
|
|
11672
11719
|
internal: true,
|
|
11673
|
-
methods: {
|
|
11720
|
+
methods: {
|
|
11721
|
+
/**
|
|
11722
|
+
* `internal: true` did not gate the mount (see the 2026-08-26 note on
|
|
11723
|
+
* `data-store-provider`) — this was reachable on the AppRouter by ANY
|
|
11724
|
+
* authenticated session at the default `auth: 'protected'`. The only
|
|
11725
|
+
* consumer, the detection-pipeline's model resolution
|
|
11726
|
+
* (`addon-pipeline/src/detection-pipeline/provider.ts`), calls
|
|
11727
|
+
* `ctx.api.customModelRegistry.listModels.query()` — UDS/Moleculer,
|
|
11728
|
+
* never tRPC — so `auth: 'admin'` costs it nothing.
|
|
11729
|
+
*/
|
|
11730
|
+
listModels: method(_void(), array(CustomModelDescriptorSchema).readonly(), { auth: "admin" }) }
|
|
11674
11731
|
};
|
|
11675
11732
|
/**
|
|
11676
11733
|
* Query filter for settings-store collections.
|
|
@@ -11794,11 +11851,26 @@ var settingsStoreCapability = {
|
|
|
11794
11851
|
key: string(),
|
|
11795
11852
|
value: unknown()
|
|
11796
11853
|
}), _void(), { kind: "mutation" }),
|
|
11797
|
-
/**
|
|
11854
|
+
/**
|
|
11855
|
+
* Rows matching a filter.
|
|
11856
|
+
*
|
|
11857
|
+
* `columns` is a SQL-level projection: the engine SELECTs only those
|
|
11858
|
+
* columns (plus the primary key) instead of the whole row. It is the only
|
|
11859
|
+
* way to stop paying disk for a column that is discarded — a heavy JSON
|
|
11860
|
+
* column dominates the row, and dropping it in JS after the read pays every
|
|
11861
|
+
* byte first. Measured on the live `pipeline-analytics:tracks` table: a
|
|
11862
|
+
* 501-row page is 4.6 MB whole and 0.11 MB projected, same index, same
|
|
11863
|
+
* plan.
|
|
11864
|
+
*
|
|
11865
|
+
* The engine REFUSES a column it cannot serve rather than omitting it —
|
|
11866
|
+
* see `SettingsQueryInput.columns` for why a projection may not be
|
|
11867
|
+
* forgiving the way a predicate is.
|
|
11868
|
+
*/
|
|
11798
11869
|
query: method(object({
|
|
11799
11870
|
namespace: string().optional(),
|
|
11800
11871
|
collection: string(),
|
|
11801
|
-
filter: QueryFilterSchema.optional()
|
|
11872
|
+
filter: QueryFilterSchema.optional(),
|
|
11873
|
+
columns: array(string()).readonly().optional()
|
|
11802
11874
|
}), array(SettingsRecordSchema).readonly()),
|
|
11803
11875
|
/** Insert a new record. */
|
|
11804
11876
|
insert: method(object({
|
|
@@ -11924,6 +11996,23 @@ var EngineInfoSchema = object({
|
|
|
11924
11996
|
* go through `settings-store`; they never see this cap, and an engine
|
|
11925
11997
|
* never sees a caller.
|
|
11926
11998
|
*
|
|
11999
|
+
* ⚠ **`internal: true` DOES NOT gate the mount, and until 2026-08-26 this
|
|
12000
|
+
* comment claimed otherwise.** `resolveCapMount` never reads the field, so this
|
|
12001
|
+
* cap was live on the AppRouter with every method at the default
|
|
12002
|
+
* `auth: 'protected'` — i.e. readable by ANY authenticated session, admin or
|
|
12003
|
+
* not. Verified against the live hub: `dataStoreProvider.query` returned raw
|
|
12004
|
+
* settings rows including a provider credential, bypassing the secret redaction
|
|
12005
|
+
* that `deviceManager.listAll` and friends go through.
|
|
12006
|
+
*
|
|
12007
|
+
* Every method is now `auth: 'admin'` EXPLICITLY, including the five reads —
|
|
12008
|
+
* they had no options object at all, which is exactly how they kept the
|
|
12009
|
+
* permissive default while the mutations looked deliberate. The explicit
|
|
12010
|
+
* annotation is the fix that works today; making `internal` mean something at
|
|
12011
|
+
* mount time is the systemic one, and it is not free: 22 caps declare it, only
|
|
12012
|
+
* 4 are `mount: 'skip'`, and forcing admin on all of them would change the auth
|
|
12013
|
+
* of surfaces the viewer and admin-ui call as non-admin users. That decision is
|
|
12014
|
+
* the operator's, not a side effect of this file.
|
|
12015
|
+
*
|
|
11927
12016
|
* Design notes:
|
|
11928
12017
|
* - **Stateless dispatch.** Every method carries its own
|
|
11929
12018
|
* `namespace` + `collection`, so an engine keeps no per-caller state
|
|
@@ -11945,64 +12034,105 @@ var dataStoreProviderCapability = {
|
|
|
11945
12034
|
internal: true,
|
|
11946
12035
|
methods: {
|
|
11947
12036
|
/** Self-description — how the orchestrator picks a registrant. */
|
|
11948
|
-
getEngineInfo: method(_void(), EngineInfoSchema),
|
|
12037
|
+
getEngineInfo: method(_void(), EngineInfoSchema, { auth: "admin" }),
|
|
11949
12038
|
/** Get a single value by key from a collection. */
|
|
11950
12039
|
get: method(object({
|
|
11951
12040
|
namespace: string().optional(),
|
|
11952
12041
|
collection: string(),
|
|
11953
12042
|
key: string()
|
|
11954
|
-
}), unknown()),
|
|
12043
|
+
}), unknown(), { auth: "admin" }),
|
|
11955
12044
|
/** Set a value by key in a collection (upsert). */
|
|
11956
12045
|
set: method(object({
|
|
11957
12046
|
namespace: string().optional(),
|
|
11958
12047
|
collection: string(),
|
|
11959
12048
|
key: string(),
|
|
11960
12049
|
value: unknown()
|
|
11961
|
-
}), _void(), {
|
|
12050
|
+
}), _void(), {
|
|
12051
|
+
kind: "mutation",
|
|
12052
|
+
auth: "admin"
|
|
12053
|
+
}),
|
|
11962
12054
|
/** Get all entries matching an optional filter. */
|
|
11963
12055
|
query: method(object({
|
|
11964
12056
|
namespace: string().optional(),
|
|
11965
12057
|
collection: string(),
|
|
11966
|
-
filter: QueryFilterSchema.optional()
|
|
11967
|
-
|
|
12058
|
+
filter: QueryFilterSchema.optional(),
|
|
12059
|
+
/**
|
|
12060
|
+
* SQL-level column projection — MUST mirror `settings-store.query`.
|
|
12061
|
+
*
|
|
12062
|
+
* ⚠ An earlier version of this comment blamed Zod stripping, and that
|
|
12063
|
+
* was wrong — corrected 2026-08-26 after the hop map
|
|
12064
|
+
* (`docs/design/2026-08-26-mappa-hop-argomenti.md`) traced the path.
|
|
12065
|
+
* There is **no Zod parse at all** between the door and the engine: the
|
|
12066
|
+
* dispatcher forwards the payload verbatim and UDS carries it whole. A
|
|
12067
|
+
* field declared here reaches `SqliteSettingsBackend` either way.
|
|
12068
|
+
*
|
|
12069
|
+
* What actually lost `columns` was the THIRD declaration of this shape:
|
|
12070
|
+
* `SettingsQueryInput` in `interfaces/storage.ts`, a hand-written TS
|
|
12071
|
+
* interface the engine destructures from. The field existed on both
|
|
12072
|
+
* schemas and the engine still never read it, because nothing checks a
|
|
12073
|
+
* registered provider against `InferProvider<cap>` —
|
|
12074
|
+
* `ProviderRegistration.provider` is typed `object`.
|
|
12075
|
+
*
|
|
12076
|
+
* It is declared here anyway, and must stay in step with
|
|
12077
|
+
* `settings-store.query`: a caller reading only the cap definitions has
|
|
12078
|
+
* to be able to see that this call carries a projection.
|
|
12079
|
+
* `data-door-schema-parity.spec.ts` keeps the two aligned.
|
|
12080
|
+
*/
|
|
12081
|
+
columns: array(string()).readonly().optional()
|
|
12082
|
+
}), array(SettingsRecordSchema).readonly(), { auth: "admin" }),
|
|
11968
12083
|
/** Insert a new record. */
|
|
11969
12084
|
insert: method(object({
|
|
11970
12085
|
namespace: string().optional(),
|
|
11971
12086
|
collection: string(),
|
|
11972
12087
|
record: SettingsRecordSchema
|
|
11973
|
-
}), _void(), {
|
|
12088
|
+
}), _void(), {
|
|
12089
|
+
kind: "mutation",
|
|
12090
|
+
auth: "admin"
|
|
12091
|
+
}),
|
|
11974
12092
|
/** Update an existing record by ID. */
|
|
11975
12093
|
update: method(object({
|
|
11976
12094
|
namespace: string().optional(),
|
|
11977
12095
|
collection: string(),
|
|
11978
12096
|
id: string(),
|
|
11979
12097
|
data: record(string(), unknown())
|
|
11980
|
-
}), _void(), {
|
|
12098
|
+
}), _void(), {
|
|
12099
|
+
kind: "mutation",
|
|
12100
|
+
auth: "admin"
|
|
12101
|
+
}),
|
|
11981
12102
|
/** Delete a record by key/ID. */
|
|
11982
12103
|
delete: method(object({
|
|
11983
12104
|
namespace: string().optional(),
|
|
11984
12105
|
collection: string(),
|
|
11985
12106
|
key: string()
|
|
11986
|
-
}), _void(), {
|
|
12107
|
+
}), _void(), {
|
|
12108
|
+
kind: "mutation",
|
|
12109
|
+
auth: "admin"
|
|
12110
|
+
}),
|
|
11987
12111
|
/** Delete every record matching `filter`, in one statement. */
|
|
11988
12112
|
deleteWhere: method(object({
|
|
11989
12113
|
namespace: string().optional(),
|
|
11990
12114
|
collection: string(),
|
|
11991
12115
|
filter: MutationFilterSchema
|
|
11992
|
-
}), object({ deleted: number().int() }), {
|
|
12116
|
+
}), object({ deleted: number().int() }), {
|
|
12117
|
+
kind: "mutation",
|
|
12118
|
+
auth: "admin"
|
|
12119
|
+
}),
|
|
11993
12120
|
/** Apply `data` to every record matching `filter`, in one statement. */
|
|
11994
12121
|
updateWhere: method(object({
|
|
11995
12122
|
namespace: string().optional(),
|
|
11996
12123
|
collection: string(),
|
|
11997
12124
|
filter: MutationFilterSchema,
|
|
11998
12125
|
data: record(string(), unknown())
|
|
11999
|
-
}), object({ updated: number().int() }), {
|
|
12126
|
+
}), object({ updated: number().int() }), {
|
|
12127
|
+
kind: "mutation",
|
|
12128
|
+
auth: "admin"
|
|
12129
|
+
}),
|
|
12000
12130
|
/** Count entries in a collection, optionally filtered. */
|
|
12001
12131
|
count: method(object({
|
|
12002
12132
|
namespace: string().optional(),
|
|
12003
12133
|
collection: string(),
|
|
12004
12134
|
filter: QueryFilterSchema.optional()
|
|
12005
|
-
}), number()),
|
|
12135
|
+
}), number(), { auth: "admin" }),
|
|
12006
12136
|
/** Grouped counts per ((field-origin)/bucketSize) bucket, filtered. */
|
|
12007
12137
|
histogram: method(object({
|
|
12008
12138
|
namespace: string().optional(),
|
|
@@ -12014,19 +12144,22 @@ var dataStoreProviderCapability = {
|
|
|
12014
12144
|
}), array(object({
|
|
12015
12145
|
bucket: number().int(),
|
|
12016
12146
|
count: number().int()
|
|
12017
|
-
})).readonly()),
|
|
12147
|
+
})).readonly(), { auth: "admin" }),
|
|
12018
12148
|
/** Check if a collection is empty. */
|
|
12019
12149
|
isEmpty: method(object({
|
|
12020
12150
|
namespace: string().optional(),
|
|
12021
12151
|
collection: string()
|
|
12022
|
-
}), boolean()),
|
|
12152
|
+
}), boolean(), { auth: "admin" }),
|
|
12023
12153
|
/** Declare a typed (SQL-backed) collection with columns + indexes. */
|
|
12024
12154
|
declareCollection: method(object({
|
|
12025
12155
|
namespace: string().optional(),
|
|
12026
12156
|
collection: string(),
|
|
12027
12157
|
columns: array(CollectionColumnSchema).readonly(),
|
|
12028
12158
|
indexes: array(CollectionIndexSchema).readonly().optional()
|
|
12029
|
-
}), _void(), {
|
|
12159
|
+
}), _void(), {
|
|
12160
|
+
kind: "mutation",
|
|
12161
|
+
auth: "admin"
|
|
12162
|
+
})
|
|
12030
12163
|
}
|
|
12031
12164
|
};
|
|
12032
12165
|
/**
|
|
@@ -13826,13 +13959,20 @@ var embeddingEncoderCapability = {
|
|
|
13826
13959
|
mode: "collection",
|
|
13827
13960
|
internal: true,
|
|
13828
13961
|
methods: {
|
|
13962
|
+
/**
|
|
13963
|
+
* `internal: true` did not gate the mount (see the 2026-08-26 note on
|
|
13964
|
+
* `data-store-provider`) — every method below was reachable on the
|
|
13965
|
+
* AppRouter by ANY authenticated session at the default
|
|
13966
|
+
* `auth: 'protected'`. Consumers reach the encoder via `ctx.api` from
|
|
13967
|
+
* `addon-post-analysis`, never tRPC.
|
|
13968
|
+
*/
|
|
13829
13969
|
encode: method(object({
|
|
13830
13970
|
crop: _instanceof(Uint8Array),
|
|
13831
13971
|
width: number(),
|
|
13832
13972
|
height: number()
|
|
13833
|
-
}), EmbeddingResultSchema),
|
|
13834
|
-
encodeText: method(object({ text: string() }), EmbeddingResultSchema),
|
|
13835
|
-
getInfo: method(_void(), EmbeddingInfoSchema)
|
|
13973
|
+
}), EmbeddingResultSchema, { auth: "admin" }),
|
|
13974
|
+
encodeText: method(object({ text: string() }), EmbeddingResultSchema, { auth: "admin" }),
|
|
13975
|
+
getInfo: method(_void(), EmbeddingInfoSchema, { auth: "admin" })
|
|
13836
13976
|
}
|
|
13837
13977
|
};
|
|
13838
13978
|
/**
|
|
@@ -14141,12 +14281,28 @@ var llmRuntimeCapability = {
|
|
|
14141
14281
|
mode: "singleton",
|
|
14142
14282
|
internal: true,
|
|
14143
14283
|
methods: {
|
|
14284
|
+
/**
|
|
14285
|
+
* `complete`, `status`, `listLocalModels` and `getDiskUsage` had NO
|
|
14286
|
+
* `auth` override — `internal: true` did not gate the mount (see the
|
|
14287
|
+
* 2026-08-26 note on `data-store-provider`), so they were reachable on
|
|
14288
|
+
* the AppRouter by ANY authenticated session at the default
|
|
14289
|
+
* `auth: 'protected'`, inconsistent with the rest of this cap (already
|
|
14290
|
+
* `auth: 'admin'`) and with this file's own docblock: "the operator
|
|
14291
|
+
* reaches this only through the `llm` cap's methods." The sole caller,
|
|
14292
|
+
* `addon-ai`'s `runtime-client.ts`, reaches every method here via
|
|
14293
|
+
* `ctx.api` + `nodePin` — never tRPC — so `auth: 'admin'` costs it
|
|
14294
|
+
* nothing; the public `llm` cap (which end users and non-admin sessions
|
|
14295
|
+
* legitimately call for chat/generation) is untouched.
|
|
14296
|
+
*/
|
|
14144
14297
|
complete: method(LlmGenerateBaseInputSchema.extend({
|
|
14145
14298
|
images: array(LlmImageSchema).optional(),
|
|
14146
14299
|
runtime: ManagedRuntimeConfigSchema,
|
|
14147
14300
|
/** The managed profile's timeout, threaded by the hub provider. */
|
|
14148
14301
|
timeoutMs: number().int().positive().optional()
|
|
14149
|
-
}), LlmGenerateResultSchema, {
|
|
14302
|
+
}), LlmGenerateResultSchema, {
|
|
14303
|
+
kind: "mutation",
|
|
14304
|
+
auth: "admin"
|
|
14305
|
+
}),
|
|
14150
14306
|
ensureStarted: method(object({ runtime: ManagedRuntimeConfigSchema }), LlmRuntimeStatusSchema, {
|
|
14151
14307
|
kind: "mutation",
|
|
14152
14308
|
auth: "admin"
|
|
@@ -14155,7 +14311,7 @@ var llmRuntimeCapability = {
|
|
|
14155
14311
|
kind: "mutation",
|
|
14156
14312
|
auth: "admin"
|
|
14157
14313
|
}),
|
|
14158
|
-
status: method(object({}), LlmRuntimeStatusSchema),
|
|
14314
|
+
status: method(object({}), LlmRuntimeStatusSchema, { auth: "admin" }),
|
|
14159
14315
|
installModel: method(object({ model: ManagedModelRefSchema }), _void(), {
|
|
14160
14316
|
kind: "mutation",
|
|
14161
14317
|
auth: "admin"
|
|
@@ -14164,8 +14320,8 @@ var llmRuntimeCapability = {
|
|
|
14164
14320
|
kind: "mutation",
|
|
14165
14321
|
auth: "admin"
|
|
14166
14322
|
}),
|
|
14167
|
-
listLocalModels: method(object({}), array(LlmNodeModelSchema)),
|
|
14168
|
-
getDiskUsage: method(object({}), LlmRuntimeDiskUsageSchema)
|
|
14323
|
+
listLocalModels: method(object({}), array(LlmNodeModelSchema), { auth: "admin" }),
|
|
14324
|
+
getDiskUsage: method(object({}), LlmRuntimeDiskUsageSchema, { auth: "admin" })
|
|
14169
14325
|
}
|
|
14170
14326
|
};
|
|
14171
14327
|
/**
|
|
@@ -18431,7 +18587,17 @@ var oauthIntegrationCapability = {
|
|
|
18431
18587
|
scope: "system",
|
|
18432
18588
|
mode: "collection",
|
|
18433
18589
|
internal: true,
|
|
18434
|
-
methods: {
|
|
18590
|
+
methods: {
|
|
18591
|
+
/**
|
|
18592
|
+
* `internal: true` did not gate the mount (see the 2026-08-26 note on
|
|
18593
|
+
* `data-store-provider`) — `getDescriptor` was reachable on the AppRouter
|
|
18594
|
+
* by ANY authenticated session at the default `auth: 'protected'`. The
|
|
18595
|
+
* real caller is `/api/oauth2/authorize` and `/api/oauth2/integrations`
|
|
18596
|
+
* (`oauth2-routes.ts`), which resolve the provider directly off the
|
|
18597
|
+
* capability registry — never through tRPC. `auth: 'admin'` closes the
|
|
18598
|
+
* tRPC surface without touching that path.
|
|
18599
|
+
*/
|
|
18600
|
+
getDescriptor: method(_void(), OauthIntegrationDescriptorSchema, { auth: "admin" }) }
|
|
18435
18601
|
};
|
|
18436
18602
|
/**
|
|
18437
18603
|
* pipeline-analytics — device-scoped wrapper cap. Refines raw
|
|
@@ -19830,6 +19996,29 @@ var pipelineAnalyticsCapability = {
|
|
|
19830
19996
|
kind: "mutation",
|
|
19831
19997
|
auth: "admin"
|
|
19832
19998
|
}),
|
|
19999
|
+
/**
|
|
20000
|
+
* Moves event media between locations — the OPERATOR's mover, without the
|
|
20001
|
+
* coordinator's lease. Twin of `recording.relocateFootage`: the same
|
|
20002
|
+
* engine the lease-gated coordinated migration uses
|
|
20003
|
+
* (`startStorageMigrationMove`), armable in the background and WITHOUT
|
|
20004
|
+
* pausing anything. Exists because `eventMedia` was the only storage
|
|
20005
|
+
* class whose only move path went through the recorder's global pause.
|
|
20006
|
+
*/
|
|
20007
|
+
relocateMedia: method(RelocateMediaInputSchema, object({ jobId: string() }), {
|
|
20008
|
+
kind: "mutation",
|
|
20009
|
+
auth: "admin"
|
|
20010
|
+
}),
|
|
20011
|
+
/** Every relocate job this addon knows about, newest first (in RAM: the
|
|
20012
|
+
* move is resumable, so a lost list costs nothing but the display). */
|
|
20013
|
+
listRelocateMediaJobs: method(object({}), array(RelocateJobSchema).readonly(), {
|
|
20014
|
+
kind: "query",
|
|
20015
|
+
auth: "admin"
|
|
20016
|
+
}),
|
|
20017
|
+
/** Cancel a running or queued relocate job. */
|
|
20018
|
+
cancelRelocateMedia: method(object({ jobId: string() }), object({ cancelled: boolean() }), {
|
|
20019
|
+
kind: "mutation",
|
|
20020
|
+
auth: "admin"
|
|
20021
|
+
}),
|
|
19833
20022
|
listOpsLog: method(OpsLogQueryInputSchema, array(OpsLogEntrySchema).readonly(), {
|
|
19834
20023
|
kind: "query",
|
|
19835
20024
|
auth: "admin"
|
|
@@ -20189,6 +20378,11 @@ object({
|
|
|
20189
20378
|
"jpeg"
|
|
20190
20379
|
])
|
|
20191
20380
|
});
|
|
20381
|
+
/**
|
|
20382
|
+
* Process-local frame identity. It is serializable so it can ride an in-process
|
|
20383
|
+
* capability call, but `registryId` deliberately prevents resolution in any
|
|
20384
|
+
* other process or execution group.
|
|
20385
|
+
*/
|
|
20192
20386
|
var FrameRefSchema = object({
|
|
20193
20387
|
registryId: string().min(1),
|
|
20194
20388
|
id: string().min(1),
|
|
@@ -23142,6 +23336,20 @@ var ssoBridgeCapability = {
|
|
|
23142
23336
|
mode: "singleton",
|
|
23143
23337
|
internal: true,
|
|
23144
23338
|
methods: {
|
|
23339
|
+
/**
|
|
23340
|
+
* `internal: true` did not gate the mount (see the 2026-08-26 note on
|
|
23341
|
+
* `data-store-provider`) — `signBridgeToken` was reachable on the
|
|
23342
|
+
* AppRouter by ANY authenticated session at the default
|
|
23343
|
+
* `auth: 'protected'`. The claims (including `isAdmin`) are CALLER-
|
|
23344
|
+
* SUPPLIED: an unprivileged session could have minted its own
|
|
23345
|
+
* `isAdmin: true` bridge token and redeemed it at
|
|
23346
|
+
* `/api/auth/sso/finish` to become admin — a full privilege escalation
|
|
23347
|
+
* through the exact surface this cap exists to close (see the module
|
|
23348
|
+
* docblock). Every real caller (`oauth-grants.ts`, `main.ts`
|
|
23349
|
+
* registration, the OIDC/magic-link addons) reaches this through
|
|
23350
|
+
* `ctx.api` / the in-process registry — never through tRPC — so
|
|
23351
|
+
* `auth: 'admin'` costs those callers nothing.
|
|
23352
|
+
*/
|
|
23145
23353
|
signBridgeToken: method(object({
|
|
23146
23354
|
claims: SsoBridgeClaimsSchema,
|
|
23147
23355
|
/**
|
|
@@ -23154,8 +23362,8 @@ var ssoBridgeCapability = {
|
|
|
23154
23362
|
* linking rather than produce an eternal token.
|
|
23155
23363
|
*/
|
|
23156
23364
|
ttlSec: union([number().int().positive(), literal("never")]).optional()
|
|
23157
|
-
}), object({ token: string() })),
|
|
23158
|
-
verifyBridgeToken: method(object({ token: string() }), SsoBridgeClaimsSchema.nullable())
|
|
23365
|
+
}), object({ token: string() }), { auth: "admin" }),
|
|
23366
|
+
verifyBridgeToken: method(object({ token: string() }), SsoBridgeClaimsSchema.nullable(), { auth: "admin" })
|
|
23159
23367
|
}
|
|
23160
23368
|
};
|
|
23161
23369
|
var ProviderListEntrySchema = discriminatedUnion("shouldSaveDiskSpace", [object({
|
|
@@ -23304,8 +23512,15 @@ var storageEvictableCapability = {
|
|
|
23304
23512
|
mode: "collection",
|
|
23305
23513
|
internal: true,
|
|
23306
23514
|
methods: {
|
|
23515
|
+
/**
|
|
23516
|
+
* `internal: true` did not gate the mount (see the 2026-08-26 note on
|
|
23517
|
+
* `data-store-provider`) — this was reachable on the AppRouter by ANY
|
|
23518
|
+
* authenticated session at the default `auth: 'protected'`. The only
|
|
23519
|
+
* consumer is the orchestrator's `StoragePressureManager`, which calls
|
|
23520
|
+
* `ctx.api` — never tRPC — so `auth: 'admin'` costs it nothing.
|
|
23521
|
+
*/
|
|
23307
23522
|
/** Bytes this provider holds on the given location — drives proportional fan-out. */
|
|
23308
|
-
getEvictableUsage: method(object({ locationId: string() }), EvictableUsageSchema),
|
|
23523
|
+
getEvictableUsage: method(object({ locationId: string() }), EvictableUsageSchema, { auth: "admin" }),
|
|
23309
23524
|
/**
|
|
23310
23525
|
* Free approximately `targetBytes` of this provider's OWN least-valuable
|
|
23311
23526
|
* data on the location (oldest footage, expired clips, …). Returns what it
|
|
@@ -23314,7 +23529,10 @@ var storageEvictableCapability = {
|
|
|
23314
23529
|
evict: method(object({
|
|
23315
23530
|
locationId: string(),
|
|
23316
23531
|
targetBytes: number().int().positive()
|
|
23317
|
-
}), EvictResultSchema, {
|
|
23532
|
+
}), EvictResultSchema, {
|
|
23533
|
+
kind: "mutation",
|
|
23534
|
+
auth: "admin"
|
|
23535
|
+
})
|
|
23318
23536
|
}
|
|
23319
23537
|
};
|
|
23320
23538
|
/**
|
|
@@ -23417,43 +23635,82 @@ var storageProviderCapability = {
|
|
|
23417
23635
|
mode: "collection",
|
|
23418
23636
|
internal: true,
|
|
23419
23637
|
methods: {
|
|
23638
|
+
/**
|
|
23639
|
+
* Every method below except `testLocation` had NO `auth` override —
|
|
23640
|
+
* `internal: true` did not gate the mount (see the 2026-08-26 note on
|
|
23641
|
+
* `data-store-provider`), so this was reachable on the AppRouter by ANY
|
|
23642
|
+
* authenticated session at the default `auth: 'protected'`: arbitrary
|
|
23643
|
+
* read/write/delete/list against any storage location the operator has
|
|
23644
|
+
* configured, keyed only by a caller-supplied `location` + `relativePath`
|
|
23645
|
+
* — the same "public consumers never see this cap" claim that was false
|
|
23646
|
+
* for `data-store-provider`, here gating raw file I/O instead of raw
|
|
23647
|
+
* settings rows. The only legitimate caller,
|
|
23648
|
+
* `addon-registry.service.ts`'s `activeStorageProvider`, calls the
|
|
23649
|
+
* provider object directly (in-process) — never tRPC — so `auth: 'admin'`
|
|
23650
|
+
* on every method costs it nothing. Public consumers already go through
|
|
23651
|
+
* the separate `storage` singleton cap.
|
|
23652
|
+
*/
|
|
23420
23653
|
/** Self-description for the "Add location" wizard. */
|
|
23421
|
-
getProviderInfo: method(_void(), ProviderInfoSchema),
|
|
23654
|
+
getProviderInfo: method(_void(), ProviderInfoSchema, { auth: "admin" }),
|
|
23422
23655
|
/** Validate config + probe connectivity. Called on add and on edit. */
|
|
23423
23656
|
testLocation: method(object({ config: record(string(), unknown()) }), TestLocationResultSchema, { auth: "admin" }),
|
|
23424
23657
|
resolve: method(object({
|
|
23425
23658
|
location: StorageLocationSchema,
|
|
23426
23659
|
relativePath: string()
|
|
23427
|
-
}), string()),
|
|
23660
|
+
}), string(), { auth: "admin" }),
|
|
23428
23661
|
write: method(object({
|
|
23429
23662
|
location: StorageLocationSchema,
|
|
23430
23663
|
relativePath: string(),
|
|
23431
23664
|
data: _instanceof(Uint8Array)
|
|
23432
|
-
}), _void(), {
|
|
23665
|
+
}), _void(), {
|
|
23666
|
+
kind: "mutation",
|
|
23667
|
+
auth: "admin"
|
|
23668
|
+
}),
|
|
23433
23669
|
read: method(object({
|
|
23434
23670
|
location: StorageLocationSchema,
|
|
23435
23671
|
relativePath: string()
|
|
23436
|
-
}), _instanceof(Uint8Array)),
|
|
23672
|
+
}), _instanceof(Uint8Array), { auth: "admin" }),
|
|
23437
23673
|
exists: method(object({
|
|
23438
23674
|
location: StorageLocationSchema,
|
|
23439
23675
|
relativePath: string()
|
|
23440
|
-
}), boolean()),
|
|
23676
|
+
}), boolean(), { auth: "admin" }),
|
|
23441
23677
|
list: method(object({
|
|
23442
23678
|
location: StorageLocationSchema,
|
|
23443
23679
|
prefix: string().optional()
|
|
23444
|
-
}), array(string()).readonly()),
|
|
23680
|
+
}), array(string()).readonly(), { auth: "admin" }),
|
|
23445
23681
|
delete: method(object({
|
|
23446
23682
|
location: StorageLocationSchema,
|
|
23447
23683
|
relativePath: string()
|
|
23448
|
-
}), _void(), {
|
|
23449
|
-
|
|
23450
|
-
|
|
23451
|
-
|
|
23452
|
-
|
|
23453
|
-
|
|
23454
|
-
|
|
23455
|
-
|
|
23456
|
-
|
|
23684
|
+
}), _void(), {
|
|
23685
|
+
kind: "mutation",
|
|
23686
|
+
auth: "admin"
|
|
23687
|
+
}),
|
|
23688
|
+
getAvailableSpace: method(object({ location: StorageLocationSchema }), number().nullable(), { auth: "admin" }),
|
|
23689
|
+
beginUpload: method(BeginUploadInputSchema, BeginUploadResultSchema, {
|
|
23690
|
+
kind: "mutation",
|
|
23691
|
+
auth: "admin"
|
|
23692
|
+
}),
|
|
23693
|
+
writeChunk: method(WriteChunkInputSchema, _void(), {
|
|
23694
|
+
kind: "mutation",
|
|
23695
|
+
auth: "admin"
|
|
23696
|
+
}),
|
|
23697
|
+
finalizeUpload: method(FinalizeUploadInputSchema, _void(), {
|
|
23698
|
+
kind: "mutation",
|
|
23699
|
+
auth: "admin"
|
|
23700
|
+
}),
|
|
23701
|
+
abortUpload: method(AbortUploadInputSchema, _void(), {
|
|
23702
|
+
kind: "mutation",
|
|
23703
|
+
auth: "admin"
|
|
23704
|
+
}),
|
|
23705
|
+
beginDownload: method(BeginDownloadInputSchema, BeginDownloadResultSchema, {
|
|
23706
|
+
kind: "mutation",
|
|
23707
|
+
auth: "admin"
|
|
23708
|
+
}),
|
|
23709
|
+
readChunk: method(ReadChunkInputSchema, _instanceof(Uint8Array), { auth: "admin" }),
|
|
23710
|
+
endDownload: method(EndDownloadInputSchema, _void(), {
|
|
23711
|
+
kind: "mutation",
|
|
23712
|
+
auth: "admin"
|
|
23713
|
+
})
|
|
23457
23714
|
}
|
|
23458
23715
|
};
|
|
23459
23716
|
/** Profile-exported FormBuilder schema. Shape is ConfigUISchema at the UI. */
|
|
@@ -23786,9 +24043,28 @@ var userPasskeysCapability = {
|
|
|
23786
24043
|
auth: "admin",
|
|
23787
24044
|
access: "create"
|
|
23788
24045
|
}),
|
|
24046
|
+
/**
|
|
24047
|
+
* The four methods below had NO `auth` override — `internal: true` did
|
|
24048
|
+
* not gate the mount (see the 2026-08-26 note on `data-store-provider`),
|
|
24049
|
+
* so they were reachable on the AppRouter at the default
|
|
24050
|
+
* `auth: 'protected'` (any authenticated session), inconsistent with
|
|
24051
|
+
* every other method on this cap (all already `auth: 'admin'`).
|
|
24052
|
+
*
|
|
24053
|
+
* ⚠ Checked before gating: these are also the PRE-AUTH login-ceremony
|
|
24054
|
+
* methods, so admin-gating them here must not break login for an
|
|
24055
|
+
* unauthenticated principal. It doesn't — the real login path is the
|
|
24056
|
+
* PUBLIC `auth.beginAuthentication` / `auth.finishAuthentication` /
|
|
24057
|
+
* `auth.beginDiscoverableAuthentication` / `auth.finishDiscoverableAuthentication`
|
|
24058
|
+
* procedures in `server/backend/src/api/core/auth.router.ts`, which call
|
|
24059
|
+
* `provider.beginAuthentication(...)` etc. directly against the
|
|
24060
|
+
* capability-registry-resolved provider — never through this cap's own
|
|
24061
|
+
* tRPC route. `auth: 'admin'` here only closes a redundant, unused
|
|
24062
|
+
* second entry point onto the same ceremony.
|
|
24063
|
+
*/
|
|
23789
24064
|
beginAuthentication: method(object({ userId: string().optional() }), object({ optionsJSON: record(string(), unknown()) }), {
|
|
23790
24065
|
kind: "mutation",
|
|
23791
|
-
access: "view"
|
|
24066
|
+
access: "view",
|
|
24067
|
+
auth: "admin"
|
|
23792
24068
|
}),
|
|
23793
24069
|
finishAuthentication: method(object({
|
|
23794
24070
|
/** Required — the user the assertion belongs to (verified). */
|
|
@@ -23797,11 +24073,13 @@ var userPasskeysCapability = {
|
|
|
23797
24073
|
response: record(string(), unknown())
|
|
23798
24074
|
}), object({ verified: boolean() }), {
|
|
23799
24075
|
kind: "mutation",
|
|
23800
|
-
access: "view"
|
|
24076
|
+
access: "view",
|
|
24077
|
+
auth: "admin"
|
|
23801
24078
|
}),
|
|
23802
24079
|
beginDiscoverableAuthentication: method(object({}), object({ optionsJSON: record(string(), unknown()) }), {
|
|
23803
24080
|
kind: "mutation",
|
|
23804
|
-
access: "view"
|
|
24081
|
+
access: "view",
|
|
24082
|
+
auth: "admin"
|
|
23805
24083
|
}),
|
|
23806
24084
|
finishDiscoverableAuthentication: method(object({
|
|
23807
24085
|
/** AuthenticationResponseJSON from the browser. */
|
|
@@ -23810,7 +24088,8 @@ response: record(string(), unknown()) }), object({
|
|
|
23810
24088
|
userId: string().nullable()
|
|
23811
24089
|
}), {
|
|
23812
24090
|
kind: "mutation",
|
|
23813
|
-
access: "view"
|
|
24091
|
+
access: "view",
|
|
24092
|
+
auth: "admin"
|
|
23814
24093
|
}),
|
|
23815
24094
|
listPasskeys: method(object({ userId: string() }), array(PasskeySummarySchema), { auth: "admin" }),
|
|
23816
24095
|
removePasskey: method(object({
|
|
@@ -23988,6 +24267,14 @@ var VectorStatsResultSchema = object({
|
|
|
23988
24267
|
/** False when the backend ranks approximately. */
|
|
23989
24268
|
exact: boolean()
|
|
23990
24269
|
});
|
|
24270
|
+
/**
|
|
24271
|
+
* `internal: true` did not gate the mount (see the 2026-08-26 note on
|
|
24272
|
+
* `data-store-provider`) — every method below was reachable on the AppRouter
|
|
24273
|
+
* by ANY authenticated session at the default `auth: 'protected'`. The only
|
|
24274
|
+
* consumers (`addon-post-analysis`'s embedding stores) reach this cap via
|
|
24275
|
+
* `ctx.api` — UDS/Moleculer, never tRPC — so `auth: 'admin'` on every method
|
|
24276
|
+
* costs them nothing. No client (viewer or admin-ui) calls `vectorStore.*`.
|
|
24277
|
+
*/
|
|
23991
24278
|
var vectorStoreCapability = {
|
|
23992
24279
|
name: "vector-store",
|
|
23993
24280
|
scope: "system",
|
|
@@ -23995,14 +24282,26 @@ var vectorStoreCapability = {
|
|
|
23995
24282
|
internal: true,
|
|
23996
24283
|
methods: {
|
|
23997
24284
|
/** Idempotent. Re-declaring with a different `dim` is an error, not a wipe. */
|
|
23998
|
-
declareIndex: method(VectorDeclareIndexInputSchema, _void(), {
|
|
23999
|
-
|
|
24000
|
-
|
|
24285
|
+
declareIndex: method(VectorDeclareIndexInputSchema, _void(), {
|
|
24286
|
+
kind: "mutation",
|
|
24287
|
+
auth: "admin"
|
|
24288
|
+
}),
|
|
24289
|
+
upsert: method(VectorUpsertInputSchema, VectorUpsertResultSchema, {
|
|
24290
|
+
kind: "mutation",
|
|
24291
|
+
auth: "admin"
|
|
24292
|
+
}),
|
|
24293
|
+
query: method(VectorQueryInputSchema, VectorQueryResultSchema, { auth: "admin" }),
|
|
24001
24294
|
/** Metadata by id, no vectors — see {@link VectorGetResultSchema}. */
|
|
24002
|
-
getByIds: method(VectorGetInputSchema, VectorGetResultSchema),
|
|
24003
|
-
deleteByIds: method(VectorDeleteInputSchema, VectorDeleteResultSchema, {
|
|
24004
|
-
|
|
24005
|
-
|
|
24295
|
+
getByIds: method(VectorGetInputSchema, VectorGetResultSchema, { auth: "admin" }),
|
|
24296
|
+
deleteByIds: method(VectorDeleteInputSchema, VectorDeleteResultSchema, {
|
|
24297
|
+
kind: "mutation",
|
|
24298
|
+
auth: "admin"
|
|
24299
|
+
}),
|
|
24300
|
+
deleteByFilter: method(VectorDeleteByFilterInputSchema, VectorDeleteResultSchema, {
|
|
24301
|
+
kind: "mutation",
|
|
24302
|
+
auth: "admin"
|
|
24303
|
+
}),
|
|
24304
|
+
stats: method(VectorStatsInputSchema, VectorStatsResultSchema, { auth: "admin" })
|
|
24006
24305
|
}
|
|
24007
24306
|
};
|
|
24008
24307
|
var ClipSchema = object({
|
|
@@ -26851,7 +27150,27 @@ var faceGalleryCapability = {
|
|
|
26851
27150
|
scope: "system",
|
|
26852
27151
|
mode: "singleton",
|
|
26853
27152
|
methods: {
|
|
26854
|
-
listIdentities: method(
|
|
27153
|
+
listIdentities: method(object({
|
|
27154
|
+
/**
|
|
27155
|
+
* Inline {@link IdentitySchema.coverBase64} on every row.
|
|
27156
|
+
*
|
|
27157
|
+
* Default `false`, the same inversion `listRecentFaces` and
|
|
27158
|
+
* `listPlates` took on 2026-08-25 (see `include-crops-default.ts` for
|
|
27159
|
+
* why the burden belongs on the caller that WANTS the bytes). Measured
|
|
27160
|
+
* on the live hub the same day: four identities cost 40,979 B with the
|
|
27161
|
+
* covers inline, ~10 KB of base64 per row, on a query this UI mounts
|
|
27162
|
+
* four times and the viewer holds at `staleTime: 30_000`.
|
|
27163
|
+
*
|
|
27164
|
+
* Nothing loses its avatar: `coverMediaKey` is already on every row and
|
|
27165
|
+
* the `event-media` plane serves that key `immutable` with an ETag.
|
|
27166
|
+
*
|
|
27167
|
+
* **This is an INPUT field, so it does not reach the addon until the
|
|
27168
|
+
* next train** — the hub router validates cap inputs against its own
|
|
27169
|
+
* compiled Zod and strips a key it does not know. Until then the
|
|
27170
|
+
* provider sees `undefined`, which resolves to `false`: the cheap shape
|
|
27171
|
+
* is what ships, and the opt-in becomes reachable when the train lands.
|
|
27172
|
+
*/
|
|
27173
|
+
includeCrops: boolean().optional() }).optional(), array(IdentitySchema).readonly()),
|
|
26855
27174
|
createIdentity: method(object({ name: string().min(1) }), IdentitySchema, {
|
|
26856
27175
|
kind: "mutation",
|
|
26857
27176
|
auth: "admin"
|
|
@@ -30104,8 +30423,10 @@ var PlateInfoSchema = object({
|
|
|
30104
30423
|
keyFrameMediaKey: string().optional(),
|
|
30105
30424
|
base64: string().optional(),
|
|
30106
30425
|
/**
|
|
30107
|
-
* Same crop as a data-plane URL
|
|
30108
|
-
* never inlines JPEG; `listPlates`
|
|
30426
|
+
* Same crop as a data-plane URL, always present when the plate has a stored
|
|
30427
|
+
* crop. `getPlateByTrack` returns this and never inlines JPEG; `listPlates`
|
|
30428
|
+
* and `searchPlates` inline the crop only when their `includeCrops` input is
|
|
30429
|
+
* left at its `true` default.
|
|
30109
30430
|
*/
|
|
30110
30431
|
cropUrl: string().optional()
|
|
30111
30432
|
});
|
|
@@ -30138,7 +30459,25 @@ var plateGalleryCapability = {
|
|
|
30138
30459
|
methods: {
|
|
30139
30460
|
listPlates: method(object({
|
|
30140
30461
|
deviceId: number().int().optional(),
|
|
30141
|
-
limit: number().int().positive().optional()
|
|
30462
|
+
limit: number().int().positive().optional(),
|
|
30463
|
+
/**
|
|
30464
|
+
* Inline the base64 crop on every row. Default `true` — the existing
|
|
30465
|
+
* behaviour, kept so no caller breaks.
|
|
30466
|
+
*
|
|
30467
|
+
* Set `false` once the caller renders {@link PlateInfo.cropUrl}.
|
|
30468
|
+
* Measured on the live hub at the 500 rows the Plates view asks for:
|
|
30469
|
+
* 879,403 B and 27.7 s with the crops inline, against a few KiB of
|
|
30470
|
+
* metadata without them — and the browser then caches the images.
|
|
30471
|
+
*
|
|
30472
|
+
* This is the plate twin of `faceGallery.listRecentFaces`'s option;
|
|
30473
|
+
* plates were the one gallery list left without it.
|
|
30474
|
+
*
|
|
30475
|
+
* **This is an INPUT field, so it does not reach the addon until the
|
|
30476
|
+
* next train.** The hub router validates cap inputs against its own
|
|
30477
|
+
* compiled Zod and strips a key it does not know. Until the train
|
|
30478
|
+
* ships, sending `false` is harmless and keeps the crops inline.
|
|
30479
|
+
*/
|
|
30480
|
+
includeCrops: boolean().optional()
|
|
30142
30481
|
}).optional(), array(PlateInfoSchema).readonly()),
|
|
30143
30482
|
getPlateByTrack: method(object({
|
|
30144
30483
|
deviceId: number().int(),
|
|
@@ -30149,7 +30488,9 @@ var plateGalleryCapability = {
|
|
|
30149
30488
|
searchPlates: method(object({
|
|
30150
30489
|
text: string().min(1),
|
|
30151
30490
|
maxDistance: number().int().min(0).optional(),
|
|
30152
|
-
limit: number().int().positive().optional()
|
|
30491
|
+
limit: number().int().positive().optional(),
|
|
30492
|
+
/** See `listPlates.includeCrops`. Default `true`. */
|
|
30493
|
+
includeCrops: boolean().optional()
|
|
30153
30494
|
}), array(PlateInfoSchema).readonly()),
|
|
30154
30495
|
/** Suggest groups of near-identical reads (same physical plate) for review/merge. */
|
|
30155
30496
|
suggestPlateClusters: method(object({
|
|
@@ -30169,7 +30510,13 @@ var plateGalleryCapability = {
|
|
|
30169
30510
|
kind: "mutation",
|
|
30170
30511
|
auth: "admin"
|
|
30171
30512
|
}),
|
|
30172
|
-
listVehicles: method(
|
|
30513
|
+
listVehicles: method(object({
|
|
30514
|
+
/** Inline {@link VehicleSchema.coverBase64} on every row. Default
|
|
30515
|
+
* `false` — the vehicle twin of `faceGallery.listIdentities`'s
|
|
30516
|
+
* option; `coverMediaKey` + the `event-media` plane carry the picture.
|
|
30517
|
+
* INPUT field: stripped by the hub router until the train ships, which
|
|
30518
|
+
* resolves to `false` and is exactly the intended default. */
|
|
30519
|
+
includeCrops: boolean().optional() }).optional(), array(VehicleSchema).readonly()),
|
|
30173
30520
|
createVehicle: method(object({ name: string().min(1) }), VehicleSchema, {
|
|
30174
30521
|
kind: "mutation",
|
|
30175
30522
|
auth: "admin"
|
|
@@ -36913,6 +37260,12 @@ Object.freeze({
|
|
|
36913
37260
|
addonId: null,
|
|
36914
37261
|
access: "create"
|
|
36915
37262
|
},
|
|
37263
|
+
"pipelineAnalytics.cancelRelocateMedia": {
|
|
37264
|
+
capName: "pipeline-analytics",
|
|
37265
|
+
capScope: "device",
|
|
37266
|
+
addonId: null,
|
|
37267
|
+
access: "create"
|
|
37268
|
+
},
|
|
36916
37269
|
"pipelineAnalytics.cancelStorageMigrationMove": {
|
|
36917
37270
|
capName: "pipeline-analytics",
|
|
36918
37271
|
capScope: "device",
|
|
@@ -37087,6 +37440,12 @@ Object.freeze({
|
|
|
37087
37440
|
addonId: null,
|
|
37088
37441
|
access: "view"
|
|
37089
37442
|
},
|
|
37443
|
+
"pipelineAnalytics.listRelocateMediaJobs": {
|
|
37444
|
+
capName: "pipeline-analytics",
|
|
37445
|
+
capScope: "device",
|
|
37446
|
+
addonId: null,
|
|
37447
|
+
access: "view"
|
|
37448
|
+
},
|
|
37090
37449
|
"pipelineAnalytics.listRetrainAnnotations": {
|
|
37091
37450
|
capName: "pipeline-analytics",
|
|
37092
37451
|
capScope: "device",
|
|
@@ -37165,6 +37524,12 @@ Object.freeze({
|
|
|
37165
37524
|
addonId: null,
|
|
37166
37525
|
access: "create"
|
|
37167
37526
|
},
|
|
37527
|
+
"pipelineAnalytics.relocateMedia": {
|
|
37528
|
+
capName: "pipeline-analytics",
|
|
37529
|
+
capScope: "device",
|
|
37530
|
+
addonId: null,
|
|
37531
|
+
access: "create"
|
|
37532
|
+
},
|
|
37168
37533
|
"pipelineAnalytics.restageRetrainTrack": {
|
|
37169
37534
|
capName: "pipeline-analytics",
|
|
37170
37535
|
capScope: "device",
|