@camstack/types 1.2.106 → 1.2.108
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/addon.js +1 -1
- package/dist/addon.mjs +1 -1
- package/dist/capabilities/addon-pages-source.cap.d.ts +10 -0
- package/dist/capabilities/addon-widgets-source.cap.d.ts +12 -0
- package/dist/capabilities/admin-ui.cap.d.ts +9 -0
- package/dist/capabilities/custom-model-registry.cap.d.ts +9 -0
- package/dist/capabilities/data-store-provider.cap.d.ts +17 -0
- package/dist/capabilities/embedding-encoder.cap.d.ts +7 -0
- package/dist/capabilities/llm-runtime.cap.d.ts +13 -0
- package/dist/capabilities/oauth-integration.cap.d.ts +9 -0
- package/dist/capabilities/sso-bridge.cap.d.ts +14 -0
- package/dist/capabilities/storage-evictable.cap.d.ts +7 -0
- package/dist/capabilities/storage-provider.cap.d.ts +15 -0
- package/dist/capabilities/user-passkeys.cap.d.ts +18 -0
- package/dist/capabilities/vector-store.cap.d.ts +8 -0
- package/dist/capabilities/viewer-ui.cap.d.ts +15 -0
- package/dist/index.js +283 -60
- package/dist/index.mjs +283 -60
- package/dist/{sleep-BLxqGLY0.mjs → sleep-DCBRhx0s.mjs} +28 -4
- package/dist/{sleep-CUuoW-kk.js → sleep-OOwhyQIx.js} +28 -4
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as EventCategory } from "./event-category-CIa_iT6b.mjs";
|
|
2
|
-
import { $ as DecodedFrameSchema, A as event, B as ReadinessRegistry, C as DeviceFeature, Ct as isEvent, D as DEFAULT_RUNTIME_STATE_DURABILITY, Dt as collectHydratedFieldValues, E as adminUiCapability, Et as collectHydratedFieldEntries, F as systemMethod, G as BrokerStatsSchema, H as emitDownForOwnedCaps, I as CAP_NODE_PIN_CONTEXT_KEY, J as CamProfileSchema, K as BrokerStatusSchema, L as nodePin, M as isDeviceConfigCap, N as method, O as DEVICE_SETTINGS_CONTRIBUTION_METHODS, Ot as hydrateSchema, P as resolveCapMount, Q as DecodedAudioChunkSchema, R as readNodePin, S as ChargingStatus, St as emitReadiness, T as DeviceType, Tt as WELL_KNOWN_TAB_MAP, U as readinessKey, V as ReadinessTimeoutError, W as scopeKey, X as CamStreamResolutionSchema, Y as CamStreamKindSchema, Z as CameraStreamSchema, _ as createMirrorSource, _t as DisposerChain, a as asJsonObject, at as ProfileSlotStatusSchema, b as deviceOpsCapability, bt as createDurableState, c as parseJsonArray, ct as SubscribeAudioChunksInputSchema, d as BOOT_RECOVERY_BACKOFF_MS, dt as SubscribeFramesResultSchema, et as EncodedPacketSchema, f as DEVICE_SCOPED_CAPS, ft as makeProfileBrokerId, g as createLazyTrpcSource, gt as DATAPLANE_SECRET_HEADER, h as createEventBusSliceSource, ht as selectAssignedProfileSlots, i as asJsonArray, it as ProfileSlotSchema, j as expandCapMethods, k as DEVICE_STATUS_METHOD, kt as resolveHydratedFieldValue, l as parseJsonObject, lt as SubscribeAudioChunksResultSchema, m as createDeviceProxy, mt as parseProfileBrokerId, n as sleepCancellable, nt as FrameHandleSchema, o as asNumber, ot as StreamSourceEntrySchema, p as isDeviceScopedCap, pt as makeSourceBrokerId, q as CAM_PROFILE_ORDER, r as asBoolean, rt as ProfileRtspEntrySchema, s as asString, st as StreamSourceSchema, t as sleep, tt as FrameHandleFormatSchema, u as parseJsonUnknown, ut as SubscribeFramesInputSchema, v as createSliceHandle, vt as BaseAddon, w as DeviceRole, wt as WELL_KNOWN_TABS, x as viewerUiCapability, xt as createEvent, y as RawStateResultSchema, yt as normalizeAddonInitResult, z as toNodeId } from "./sleep-
|
|
2
|
+
import { $ as DecodedFrameSchema, A as event, B as ReadinessRegistry, C as DeviceFeature, Ct as isEvent, D as DEFAULT_RUNTIME_STATE_DURABILITY, Dt as collectHydratedFieldValues, E as adminUiCapability, Et as collectHydratedFieldEntries, F as systemMethod, G as BrokerStatsSchema, H as emitDownForOwnedCaps, I as CAP_NODE_PIN_CONTEXT_KEY, J as CamProfileSchema, K as BrokerStatusSchema, L as nodePin, M as isDeviceConfigCap, N as method, O as DEVICE_SETTINGS_CONTRIBUTION_METHODS, Ot as hydrateSchema, P as resolveCapMount, Q as DecodedAudioChunkSchema, R as readNodePin, S as ChargingStatus, St as emitReadiness, T as DeviceType, Tt as WELL_KNOWN_TAB_MAP, U as readinessKey, V as ReadinessTimeoutError, W as scopeKey, X as CamStreamResolutionSchema, Y as CamStreamKindSchema, Z as CameraStreamSchema, _ as createMirrorSource, _t as DisposerChain, a as asJsonObject, at as ProfileSlotStatusSchema, b as deviceOpsCapability, bt as createDurableState, c as parseJsonArray, ct as SubscribeAudioChunksInputSchema, d as BOOT_RECOVERY_BACKOFF_MS, dt as SubscribeFramesResultSchema, et as EncodedPacketSchema, f as DEVICE_SCOPED_CAPS, ft as makeProfileBrokerId, g as createLazyTrpcSource, gt as DATAPLANE_SECRET_HEADER, h as createEventBusSliceSource, ht as selectAssignedProfileSlots, i as asJsonArray, it as ProfileSlotSchema, j as expandCapMethods, k as DEVICE_STATUS_METHOD, kt as resolveHydratedFieldValue, l as parseJsonObject, lt as SubscribeAudioChunksResultSchema, m as createDeviceProxy, mt as parseProfileBrokerId, n as sleepCancellable, nt as FrameHandleSchema, o as asNumber, ot as StreamSourceEntrySchema, p as isDeviceScopedCap, pt as makeSourceBrokerId, q as CAM_PROFILE_ORDER, r as asBoolean, rt as ProfileRtspEntrySchema, s as asString, st as StreamSourceSchema, t as sleep, tt as FrameHandleFormatSchema, u as parseJsonUnknown, ut as SubscribeFramesInputSchema, v as createSliceHandle, vt as BaseAddon, w as DeviceRole, wt as WELL_KNOWN_TABS, x as viewerUiCapability, xt as createEvent, y as RawStateResultSchema, yt as normalizeAddonInitResult, z as toNodeId } from "./sleep-DCBRhx0s.mjs";
|
|
3
3
|
import { a as buildAudioArgs, c as buildVideoArgs, d as logBannerArgs, f as pickVideoEncoder, i as audioPlanFromEncodeProfile, l as invocationFromEncodeProfile, n as Fmp4BoxSplitter, o as buildFfmpegArgs, r as AUDIO_PRESETS, s as buildInputArgs, t as canonicalHash, u as isSoftwareDecode } from "./canonical-hash-rO1sRmEK.mjs";
|
|
4
4
|
import { EventSourceType } from "./enums.mjs";
|
|
5
5
|
import { t as errMsg } from "./err-msg-IQTHeDzc.mjs";
|
|
@@ -4348,7 +4348,18 @@ var addonPagesSourceCapability = {
|
|
|
4348
4348
|
scope: "system",
|
|
4349
4349
|
mode: "collection",
|
|
4350
4350
|
internal: true,
|
|
4351
|
-
methods: {
|
|
4351
|
+
methods: {
|
|
4352
|
+
/**
|
|
4353
|
+
* `internal: true` did not gate the mount (see the 2026-08-26 note on
|
|
4354
|
+
* `data-store-provider`) — this was reachable on the AppRouter by ANY
|
|
4355
|
+
* authenticated session at the default `auth: 'protected'`. The only
|
|
4356
|
+
* consumer, the `addon-pages-aggregator` builtin, reads it via
|
|
4357
|
+
* `ctx.capabilities.getCollection('addon-pages-source')` — LOCAL-PROCESS
|
|
4358
|
+
* only, never tRPC (per `ctx.capabilities` seeing only the local
|
|
4359
|
+
* process). The public, enriched listing admin-ui actually consumes is
|
|
4360
|
+
* the separate `addon-pages` cap, unaffected by this change.
|
|
4361
|
+
*/
|
|
4362
|
+
listPages: method(z.void(), z.array(AddonPageDeclarationSchema).readonly(), { auth: "admin" }) }
|
|
4352
4363
|
};
|
|
4353
4364
|
//#endregion
|
|
4354
4365
|
//#region src/capabilities/addon-routes.cap.ts
|
|
@@ -4651,7 +4662,20 @@ var addonWidgetsSourceCapability = {
|
|
|
4651
4662
|
scope: "system",
|
|
4652
4663
|
mode: "collection",
|
|
4653
4664
|
internal: true,
|
|
4654
|
-
methods: {
|
|
4665
|
+
methods: {
|
|
4666
|
+
/**
|
|
4667
|
+
* `internal: true` did not gate the mount (see the 2026-08-26 note on
|
|
4668
|
+
* `data-store-provider`) — this was reachable on the AppRouter by ANY
|
|
4669
|
+
* authenticated session at the default `auth: 'protected'`. The only
|
|
4670
|
+
* consumer, the `addon-widgets-aggregator` builtin, reads it via
|
|
4671
|
+
* `ctx.capabilities.getCollection('addon-widgets-source')` — LOCAL-PROCESS
|
|
4672
|
+
* only, never tRPC. The public, enriched listing admin-ui actually
|
|
4673
|
+
* consumes is the separate `addon-widgets` cap (`listWidgets` there is
|
|
4674
|
+
* gated separately, and a `preAuth: true` widget is surfaced through the
|
|
4675
|
+
* PUBLIC `auth.listLoginMethods` contribution channel instead) —
|
|
4676
|
+
* neither is affected by this change.
|
|
4677
|
+
*/
|
|
4678
|
+
listWidgets: method(z.void(), z.array(WidgetMetadataSchema).readonly(), { auth: "admin" }) }
|
|
4655
4679
|
};
|
|
4656
4680
|
//#endregion
|
|
4657
4681
|
//#region src/capabilities/addon-widgets.cap.ts
|
|
@@ -7100,7 +7124,17 @@ var customModelRegistryCapability = {
|
|
|
7100
7124
|
scope: "system",
|
|
7101
7125
|
mode: "collection",
|
|
7102
7126
|
internal: true,
|
|
7103
|
-
methods: {
|
|
7127
|
+
methods: {
|
|
7128
|
+
/**
|
|
7129
|
+
* `internal: true` did not gate the mount (see the 2026-08-26 note on
|
|
7130
|
+
* `data-store-provider`) — this was reachable on the AppRouter by ANY
|
|
7131
|
+
* authenticated session at the default `auth: 'protected'`. The only
|
|
7132
|
+
* consumer, the detection-pipeline's model resolution
|
|
7133
|
+
* (`addon-pipeline/src/detection-pipeline/provider.ts`), calls
|
|
7134
|
+
* `ctx.api.customModelRegistry.listModels.query()` — UDS/Moleculer,
|
|
7135
|
+
* never tRPC — so `auth: 'admin'` costs it nothing.
|
|
7136
|
+
*/
|
|
7137
|
+
listModels: method(z.void(), z.array(CustomModelDescriptorSchema).readonly(), { auth: "admin" }) }
|
|
7104
7138
|
};
|
|
7105
7139
|
//#endregion
|
|
7106
7140
|
//#region src/capabilities/settings-store.cap.ts
|
|
@@ -7373,6 +7407,23 @@ var EngineInfoSchema = z.object({
|
|
|
7373
7407
|
* go through `settings-store`; they never see this cap, and an engine
|
|
7374
7408
|
* never sees a caller.
|
|
7375
7409
|
*
|
|
7410
|
+
* ⚠ **`internal: true` DOES NOT gate the mount, and until 2026-08-26 this
|
|
7411
|
+
* comment claimed otherwise.** `resolveCapMount` never reads the field, so this
|
|
7412
|
+
* cap was live on the AppRouter with every method at the default
|
|
7413
|
+
* `auth: 'protected'` — i.e. readable by ANY authenticated session, admin or
|
|
7414
|
+
* not. Verified against the live hub: `dataStoreProvider.query` returned raw
|
|
7415
|
+
* settings rows including a provider credential, bypassing the secret redaction
|
|
7416
|
+
* that `deviceManager.listAll` and friends go through.
|
|
7417
|
+
*
|
|
7418
|
+
* Every method is now `auth: 'admin'` EXPLICITLY, including the five reads —
|
|
7419
|
+
* they had no options object at all, which is exactly how they kept the
|
|
7420
|
+
* permissive default while the mutations looked deliberate. The explicit
|
|
7421
|
+
* annotation is the fix that works today; making `internal` mean something at
|
|
7422
|
+
* mount time is the systemic one, and it is not free: 22 caps declare it, only
|
|
7423
|
+
* 4 are `mount: 'skip'`, and forcing admin on all of them would change the auth
|
|
7424
|
+
* of surfaces the viewer and admin-ui call as non-admin users. That decision is
|
|
7425
|
+
* the operator's, not a side effect of this file.
|
|
7426
|
+
*
|
|
7376
7427
|
* Design notes:
|
|
7377
7428
|
* - **Stateless dispatch.** Every method carries its own
|
|
7378
7429
|
* `namespace` + `collection`, so an engine keeps no per-caller state
|
|
@@ -7394,20 +7445,23 @@ var dataStoreProviderCapability = {
|
|
|
7394
7445
|
internal: true,
|
|
7395
7446
|
methods: {
|
|
7396
7447
|
/** Self-description — how the orchestrator picks a registrant. */
|
|
7397
|
-
getEngineInfo: method(z.void(), EngineInfoSchema),
|
|
7448
|
+
getEngineInfo: method(z.void(), EngineInfoSchema, { auth: "admin" }),
|
|
7398
7449
|
/** Get a single value by key from a collection. */
|
|
7399
7450
|
get: method(z.object({
|
|
7400
7451
|
namespace: z.string().optional(),
|
|
7401
7452
|
collection: z.string(),
|
|
7402
7453
|
key: z.string()
|
|
7403
|
-
}), z.unknown()),
|
|
7454
|
+
}), z.unknown(), { auth: "admin" }),
|
|
7404
7455
|
/** Set a value by key in a collection (upsert). */
|
|
7405
7456
|
set: method(z.object({
|
|
7406
7457
|
namespace: z.string().optional(),
|
|
7407
7458
|
collection: z.string(),
|
|
7408
7459
|
key: z.string(),
|
|
7409
7460
|
value: z.unknown()
|
|
7410
|
-
}), z.void(), {
|
|
7461
|
+
}), z.void(), {
|
|
7462
|
+
kind: "mutation",
|
|
7463
|
+
auth: "admin"
|
|
7464
|
+
}),
|
|
7411
7465
|
/** Get all entries matching an optional filter. */
|
|
7412
7466
|
query: method(z.object({
|
|
7413
7467
|
namespace: z.string().optional(),
|
|
@@ -7416,52 +7470,80 @@ var dataStoreProviderCapability = {
|
|
|
7416
7470
|
/**
|
|
7417
7471
|
* SQL-level column projection — MUST mirror `settings-store.query`.
|
|
7418
7472
|
*
|
|
7419
|
-
*
|
|
7420
|
-
*
|
|
7421
|
-
*
|
|
7422
|
-
*
|
|
7423
|
-
*
|
|
7473
|
+
* ⚠ An earlier version of this comment blamed Zod stripping, and that
|
|
7474
|
+
* was wrong — corrected 2026-08-26 after the hop map
|
|
7475
|
+
* (`docs/design/2026-08-26-mappa-hop-argomenti.md`) traced the path.
|
|
7476
|
+
* There is **no Zod parse at all** between the door and the engine: the
|
|
7477
|
+
* dispatcher forwards the payload verbatim and UDS carries it whole. A
|
|
7478
|
+
* field declared here reaches `SqliteSettingsBackend` either way.
|
|
7479
|
+
*
|
|
7480
|
+
* What actually lost `columns` was the THIRD declaration of this shape:
|
|
7481
|
+
* `SettingsQueryInput` in `interfaces/storage.ts`, a hand-written TS
|
|
7482
|
+
* interface the engine destructures from. The field existed on both
|
|
7483
|
+
* schemas and the engine still never read it, because nothing checks a
|
|
7484
|
+
* registered provider against `InferProvider<cap>` —
|
|
7485
|
+
* `ProviderRegistration.provider` is typed `object`.
|
|
7486
|
+
*
|
|
7487
|
+
* It is declared here anyway, and must stay in step with
|
|
7488
|
+
* `settings-store.query`: a caller reading only the cap definitions has
|
|
7489
|
+
* to be able to see that this call carries a projection.
|
|
7490
|
+
* `data-door-schema-parity.spec.ts` keeps the two aligned.
|
|
7424
7491
|
*/
|
|
7425
7492
|
columns: z.array(z.string()).readonly().optional()
|
|
7426
|
-
}), z.array(SettingsRecordSchema).readonly()),
|
|
7493
|
+
}), z.array(SettingsRecordSchema).readonly(), { auth: "admin" }),
|
|
7427
7494
|
/** Insert a new record. */
|
|
7428
7495
|
insert: method(z.object({
|
|
7429
7496
|
namespace: z.string().optional(),
|
|
7430
7497
|
collection: z.string(),
|
|
7431
7498
|
record: SettingsRecordSchema
|
|
7432
|
-
}), z.void(), {
|
|
7499
|
+
}), z.void(), {
|
|
7500
|
+
kind: "mutation",
|
|
7501
|
+
auth: "admin"
|
|
7502
|
+
}),
|
|
7433
7503
|
/** Update an existing record by ID. */
|
|
7434
7504
|
update: method(z.object({
|
|
7435
7505
|
namespace: z.string().optional(),
|
|
7436
7506
|
collection: z.string(),
|
|
7437
7507
|
id: z.string(),
|
|
7438
7508
|
data: z.record(z.string(), z.unknown())
|
|
7439
|
-
}), z.void(), {
|
|
7509
|
+
}), z.void(), {
|
|
7510
|
+
kind: "mutation",
|
|
7511
|
+
auth: "admin"
|
|
7512
|
+
}),
|
|
7440
7513
|
/** Delete a record by key/ID. */
|
|
7441
7514
|
delete: method(z.object({
|
|
7442
7515
|
namespace: z.string().optional(),
|
|
7443
7516
|
collection: z.string(),
|
|
7444
7517
|
key: z.string()
|
|
7445
|
-
}), z.void(), {
|
|
7518
|
+
}), z.void(), {
|
|
7519
|
+
kind: "mutation",
|
|
7520
|
+
auth: "admin"
|
|
7521
|
+
}),
|
|
7446
7522
|
/** Delete every record matching `filter`, in one statement. */
|
|
7447
7523
|
deleteWhere: method(z.object({
|
|
7448
7524
|
namespace: z.string().optional(),
|
|
7449
7525
|
collection: z.string(),
|
|
7450
7526
|
filter: MutationFilterSchema
|
|
7451
|
-
}), z.object({ deleted: z.number().int() }), {
|
|
7527
|
+
}), z.object({ deleted: z.number().int() }), {
|
|
7528
|
+
kind: "mutation",
|
|
7529
|
+
auth: "admin"
|
|
7530
|
+
}),
|
|
7452
7531
|
/** Apply `data` to every record matching `filter`, in one statement. */
|
|
7453
7532
|
updateWhere: method(z.object({
|
|
7454
7533
|
namespace: z.string().optional(),
|
|
7455
7534
|
collection: z.string(),
|
|
7456
7535
|
filter: MutationFilterSchema,
|
|
7457
7536
|
data: z.record(z.string(), z.unknown())
|
|
7458
|
-
}), z.object({ updated: z.number().int() }), {
|
|
7537
|
+
}), z.object({ updated: z.number().int() }), {
|
|
7538
|
+
kind: "mutation",
|
|
7539
|
+
auth: "admin"
|
|
7540
|
+
}),
|
|
7459
7541
|
/** Count entries in a collection, optionally filtered. */
|
|
7460
7542
|
count: method(z.object({
|
|
7461
7543
|
namespace: z.string().optional(),
|
|
7462
7544
|
collection: z.string(),
|
|
7463
7545
|
filter: QueryFilterSchema.optional()
|
|
7464
|
-
}), z.number()),
|
|
7546
|
+
}), z.number(), { auth: "admin" }),
|
|
7465
7547
|
/** Grouped counts per ((field-origin)/bucketSize) bucket, filtered. */
|
|
7466
7548
|
histogram: method(z.object({
|
|
7467
7549
|
namespace: z.string().optional(),
|
|
@@ -7473,19 +7555,22 @@ var dataStoreProviderCapability = {
|
|
|
7473
7555
|
}), z.array(z.object({
|
|
7474
7556
|
bucket: z.number().int(),
|
|
7475
7557
|
count: z.number().int()
|
|
7476
|
-
})).readonly()),
|
|
7558
|
+
})).readonly(), { auth: "admin" }),
|
|
7477
7559
|
/** Check if a collection is empty. */
|
|
7478
7560
|
isEmpty: method(z.object({
|
|
7479
7561
|
namespace: z.string().optional(),
|
|
7480
7562
|
collection: z.string()
|
|
7481
|
-
}), z.boolean()),
|
|
7563
|
+
}), z.boolean(), { auth: "admin" }),
|
|
7482
7564
|
/** Declare a typed (SQL-backed) collection with columns + indexes. */
|
|
7483
7565
|
declareCollection: method(z.object({
|
|
7484
7566
|
namespace: z.string().optional(),
|
|
7485
7567
|
collection: z.string(),
|
|
7486
7568
|
columns: z.array(CollectionColumnSchema).readonly(),
|
|
7487
7569
|
indexes: z.array(CollectionIndexSchema).readonly().optional()
|
|
7488
|
-
}), z.void(), {
|
|
7570
|
+
}), z.void(), {
|
|
7571
|
+
kind: "mutation",
|
|
7572
|
+
auth: "admin"
|
|
7573
|
+
})
|
|
7489
7574
|
}
|
|
7490
7575
|
};
|
|
7491
7576
|
//#endregion
|
|
@@ -9470,13 +9555,20 @@ var embeddingEncoderCapability = {
|
|
|
9470
9555
|
mode: "collection",
|
|
9471
9556
|
internal: true,
|
|
9472
9557
|
methods: {
|
|
9558
|
+
/**
|
|
9559
|
+
* `internal: true` did not gate the mount (see the 2026-08-26 note on
|
|
9560
|
+
* `data-store-provider`) — every method below was reachable on the
|
|
9561
|
+
* AppRouter by ANY authenticated session at the default
|
|
9562
|
+
* `auth: 'protected'`. Consumers reach the encoder via `ctx.api` from
|
|
9563
|
+
* `addon-post-analysis`, never tRPC.
|
|
9564
|
+
*/
|
|
9473
9565
|
encode: method(z.object({
|
|
9474
9566
|
crop: z.instanceof(Uint8Array),
|
|
9475
9567
|
width: z.number(),
|
|
9476
9568
|
height: z.number()
|
|
9477
|
-
}), EmbeddingResultSchema),
|
|
9478
|
-
encodeText: method(z.object({ text: z.string() }), EmbeddingResultSchema),
|
|
9479
|
-
getInfo: method(z.void(), EmbeddingInfoSchema)
|
|
9569
|
+
}), EmbeddingResultSchema, { auth: "admin" }),
|
|
9570
|
+
encodeText: method(z.object({ text: z.string() }), EmbeddingResultSchema, { auth: "admin" }),
|
|
9571
|
+
getInfo: method(z.void(), EmbeddingInfoSchema, { auth: "admin" })
|
|
9480
9572
|
}
|
|
9481
9573
|
};
|
|
9482
9574
|
//#endregion
|
|
@@ -9817,7 +9909,23 @@ var llmRuntimeCapability = {
|
|
|
9817
9909
|
mode: "singleton",
|
|
9818
9910
|
internal: true,
|
|
9819
9911
|
methods: {
|
|
9820
|
-
|
|
9912
|
+
/**
|
|
9913
|
+
* `complete`, `status`, `listLocalModels` and `getDiskUsage` had NO
|
|
9914
|
+
* `auth` override — `internal: true` did not gate the mount (see the
|
|
9915
|
+
* 2026-08-26 note on `data-store-provider`), so they were reachable on
|
|
9916
|
+
* the AppRouter by ANY authenticated session at the default
|
|
9917
|
+
* `auth: 'protected'`, inconsistent with the rest of this cap (already
|
|
9918
|
+
* `auth: 'admin'`) and with this file's own docblock: "the operator
|
|
9919
|
+
* reaches this only through the `llm` cap's methods." The sole caller,
|
|
9920
|
+
* `addon-ai`'s `runtime-client.ts`, reaches every method here via
|
|
9921
|
+
* `ctx.api` + `nodePin` — never tRPC — so `auth: 'admin'` costs it
|
|
9922
|
+
* nothing; the public `llm` cap (which end users and non-admin sessions
|
|
9923
|
+
* legitimately call for chat/generation) is untouched.
|
|
9924
|
+
*/
|
|
9925
|
+
complete: method(LlmRuntimeCompleteInputSchema, LlmGenerateResultSchema, {
|
|
9926
|
+
kind: "mutation",
|
|
9927
|
+
auth: "admin"
|
|
9928
|
+
}),
|
|
9821
9929
|
ensureStarted: method(z.object({ runtime: ManagedRuntimeConfigSchema }), LlmRuntimeStatusSchema, {
|
|
9822
9930
|
kind: "mutation",
|
|
9823
9931
|
auth: "admin"
|
|
@@ -9826,7 +9934,7 @@ var llmRuntimeCapability = {
|
|
|
9826
9934
|
kind: "mutation",
|
|
9827
9935
|
auth: "admin"
|
|
9828
9936
|
}),
|
|
9829
|
-
status: method(z.object({}), LlmRuntimeStatusSchema),
|
|
9937
|
+
status: method(z.object({}), LlmRuntimeStatusSchema, { auth: "admin" }),
|
|
9830
9938
|
installModel: method(z.object({ model: ManagedModelRefSchema }), z.void(), {
|
|
9831
9939
|
kind: "mutation",
|
|
9832
9940
|
auth: "admin"
|
|
@@ -9835,8 +9943,8 @@ var llmRuntimeCapability = {
|
|
|
9835
9943
|
kind: "mutation",
|
|
9836
9944
|
auth: "admin"
|
|
9837
9945
|
}),
|
|
9838
|
-
listLocalModels: method(z.object({}), z.array(LlmNodeModelSchema)),
|
|
9839
|
-
getDiskUsage: method(z.object({}), LlmRuntimeDiskUsageSchema)
|
|
9946
|
+
listLocalModels: method(z.object({}), z.array(LlmNodeModelSchema), { auth: "admin" }),
|
|
9947
|
+
getDiskUsage: method(z.object({}), LlmRuntimeDiskUsageSchema, { auth: "admin" })
|
|
9840
9948
|
}
|
|
9841
9949
|
};
|
|
9842
9950
|
//#endregion
|
|
@@ -14614,7 +14722,17 @@ var oauthIntegrationCapability = {
|
|
|
14614
14722
|
scope: "system",
|
|
14615
14723
|
mode: "collection",
|
|
14616
14724
|
internal: true,
|
|
14617
|
-
methods: {
|
|
14725
|
+
methods: {
|
|
14726
|
+
/**
|
|
14727
|
+
* `internal: true` did not gate the mount (see the 2026-08-26 note on
|
|
14728
|
+
* `data-store-provider`) — `getDescriptor` was reachable on the AppRouter
|
|
14729
|
+
* by ANY authenticated session at the default `auth: 'protected'`. The
|
|
14730
|
+
* real caller is `/api/oauth2/authorize` and `/api/oauth2/integrations`
|
|
14731
|
+
* (`oauth2-routes.ts`), which resolve the provider directly off the
|
|
14732
|
+
* capability registry — never through tRPC. `auth: 'admin'` closes the
|
|
14733
|
+
* tRPC surface without touching that path.
|
|
14734
|
+
*/
|
|
14735
|
+
getDescriptor: method(z.void(), OauthIntegrationDescriptorSchema, { auth: "admin" }) }
|
|
14618
14736
|
};
|
|
14619
14737
|
//#endregion
|
|
14620
14738
|
//#region src/capabilities/pipeline-analytics.cap.ts
|
|
@@ -19627,6 +19745,20 @@ var ssoBridgeCapability = {
|
|
|
19627
19745
|
mode: "singleton",
|
|
19628
19746
|
internal: true,
|
|
19629
19747
|
methods: {
|
|
19748
|
+
/**
|
|
19749
|
+
* `internal: true` did not gate the mount (see the 2026-08-26 note on
|
|
19750
|
+
* `data-store-provider`) — `signBridgeToken` was reachable on the
|
|
19751
|
+
* AppRouter by ANY authenticated session at the default
|
|
19752
|
+
* `auth: 'protected'`. The claims (including `isAdmin`) are CALLER-
|
|
19753
|
+
* SUPPLIED: an unprivileged session could have minted its own
|
|
19754
|
+
* `isAdmin: true` bridge token and redeemed it at
|
|
19755
|
+
* `/api/auth/sso/finish` to become admin — a full privilege escalation
|
|
19756
|
+
* through the exact surface this cap exists to close (see the module
|
|
19757
|
+
* docblock). Every real caller (`oauth-grants.ts`, `main.ts`
|
|
19758
|
+
* registration, the OIDC/magic-link addons) reaches this through
|
|
19759
|
+
* `ctx.api` / the in-process registry — never through tRPC — so
|
|
19760
|
+
* `auth: 'admin'` costs those callers nothing.
|
|
19761
|
+
*/
|
|
19630
19762
|
signBridgeToken: method(z.object({
|
|
19631
19763
|
claims: SsoBridgeClaimsSchema,
|
|
19632
19764
|
/**
|
|
@@ -19639,8 +19771,8 @@ var ssoBridgeCapability = {
|
|
|
19639
19771
|
* linking rather than produce an eternal token.
|
|
19640
19772
|
*/
|
|
19641
19773
|
ttlSec: z.union([z.number().int().positive(), z.literal("never")]).optional()
|
|
19642
|
-
}), z.object({ token: z.string() })),
|
|
19643
|
-
verifyBridgeToken: method(z.object({ token: z.string() }), SsoBridgeClaimsSchema.nullable())
|
|
19774
|
+
}), z.object({ token: z.string() }), { auth: "admin" }),
|
|
19775
|
+
verifyBridgeToken: method(z.object({ token: z.string() }), SsoBridgeClaimsSchema.nullable(), { auth: "admin" })
|
|
19644
19776
|
}
|
|
19645
19777
|
};
|
|
19646
19778
|
//#endregion
|
|
@@ -19793,8 +19925,15 @@ var storageEvictableCapability = {
|
|
|
19793
19925
|
mode: "collection",
|
|
19794
19926
|
internal: true,
|
|
19795
19927
|
methods: {
|
|
19928
|
+
/**
|
|
19929
|
+
* `internal: true` did not gate the mount (see the 2026-08-26 note on
|
|
19930
|
+
* `data-store-provider`) — this was reachable on the AppRouter by ANY
|
|
19931
|
+
* authenticated session at the default `auth: 'protected'`. The only
|
|
19932
|
+
* consumer is the orchestrator's `StoragePressureManager`, which calls
|
|
19933
|
+
* `ctx.api` — never tRPC — so `auth: 'admin'` costs it nothing.
|
|
19934
|
+
*/
|
|
19796
19935
|
/** Bytes this provider holds on the given location — drives proportional fan-out. */
|
|
19797
|
-
getEvictableUsage: method(z.object({ locationId: z.string() }), EvictableUsageSchema),
|
|
19936
|
+
getEvictableUsage: method(z.object({ locationId: z.string() }), EvictableUsageSchema, { auth: "admin" }),
|
|
19798
19937
|
/**
|
|
19799
19938
|
* Free approximately `targetBytes` of this provider's OWN least-valuable
|
|
19800
19939
|
* data on the location (oldest footage, expired clips, …). Returns what it
|
|
@@ -19803,7 +19942,10 @@ var storageEvictableCapability = {
|
|
|
19803
19942
|
evict: method(z.object({
|
|
19804
19943
|
locationId: z.string(),
|
|
19805
19944
|
targetBytes: z.number().int().positive()
|
|
19806
|
-
}), EvictResultSchema, {
|
|
19945
|
+
}), EvictResultSchema, {
|
|
19946
|
+
kind: "mutation",
|
|
19947
|
+
auth: "admin"
|
|
19948
|
+
})
|
|
19807
19949
|
}
|
|
19808
19950
|
};
|
|
19809
19951
|
//#endregion
|
|
@@ -19910,43 +20052,82 @@ var storageProviderCapability = {
|
|
|
19910
20052
|
mode: "collection",
|
|
19911
20053
|
internal: true,
|
|
19912
20054
|
methods: {
|
|
20055
|
+
/**
|
|
20056
|
+
* Every method below except `testLocation` had NO `auth` override —
|
|
20057
|
+
* `internal: true` did not gate the mount (see the 2026-08-26 note on
|
|
20058
|
+
* `data-store-provider`), so this was reachable on the AppRouter by ANY
|
|
20059
|
+
* authenticated session at the default `auth: 'protected'`: arbitrary
|
|
20060
|
+
* read/write/delete/list against any storage location the operator has
|
|
20061
|
+
* configured, keyed only by a caller-supplied `location` + `relativePath`
|
|
20062
|
+
* — the same "public consumers never see this cap" claim that was false
|
|
20063
|
+
* for `data-store-provider`, here gating raw file I/O instead of raw
|
|
20064
|
+
* settings rows. The only legitimate caller,
|
|
20065
|
+
* `addon-registry.service.ts`'s `activeStorageProvider`, calls the
|
|
20066
|
+
* provider object directly (in-process) — never tRPC — so `auth: 'admin'`
|
|
20067
|
+
* on every method costs it nothing. Public consumers already go through
|
|
20068
|
+
* the separate `storage` singleton cap.
|
|
20069
|
+
*/
|
|
19913
20070
|
/** Self-description for the "Add location" wizard. */
|
|
19914
|
-
getProviderInfo: method(z.void(), ProviderInfoSchema),
|
|
20071
|
+
getProviderInfo: method(z.void(), ProviderInfoSchema, { auth: "admin" }),
|
|
19915
20072
|
/** Validate config + probe connectivity. Called on add and on edit. */
|
|
19916
20073
|
testLocation: method(z.object({ config: z.record(z.string(), z.unknown()) }), TestLocationResultSchema, { auth: "admin" }),
|
|
19917
20074
|
resolve: method(z.object({
|
|
19918
20075
|
location: StorageLocationSchema,
|
|
19919
20076
|
relativePath: z.string()
|
|
19920
|
-
}), z.string()),
|
|
20077
|
+
}), z.string(), { auth: "admin" }),
|
|
19921
20078
|
write: method(z.object({
|
|
19922
20079
|
location: StorageLocationSchema,
|
|
19923
20080
|
relativePath: z.string(),
|
|
19924
20081
|
data: z.instanceof(Uint8Array)
|
|
19925
|
-
}), z.void(), {
|
|
20082
|
+
}), z.void(), {
|
|
20083
|
+
kind: "mutation",
|
|
20084
|
+
auth: "admin"
|
|
20085
|
+
}),
|
|
19926
20086
|
read: method(z.object({
|
|
19927
20087
|
location: StorageLocationSchema,
|
|
19928
20088
|
relativePath: z.string()
|
|
19929
|
-
}), z.instanceof(Uint8Array)),
|
|
20089
|
+
}), z.instanceof(Uint8Array), { auth: "admin" }),
|
|
19930
20090
|
exists: method(z.object({
|
|
19931
20091
|
location: StorageLocationSchema,
|
|
19932
20092
|
relativePath: z.string()
|
|
19933
|
-
}), z.boolean()),
|
|
20093
|
+
}), z.boolean(), { auth: "admin" }),
|
|
19934
20094
|
list: method(z.object({
|
|
19935
20095
|
location: StorageLocationSchema,
|
|
19936
20096
|
prefix: z.string().optional()
|
|
19937
|
-
}), z.array(z.string()).readonly()),
|
|
20097
|
+
}), z.array(z.string()).readonly(), { auth: "admin" }),
|
|
19938
20098
|
delete: method(z.object({
|
|
19939
20099
|
location: StorageLocationSchema,
|
|
19940
20100
|
relativePath: z.string()
|
|
19941
|
-
}), z.void(), {
|
|
19942
|
-
|
|
19943
|
-
|
|
19944
|
-
|
|
19945
|
-
|
|
19946
|
-
|
|
19947
|
-
|
|
19948
|
-
|
|
19949
|
-
|
|
20101
|
+
}), z.void(), {
|
|
20102
|
+
kind: "mutation",
|
|
20103
|
+
auth: "admin"
|
|
20104
|
+
}),
|
|
20105
|
+
getAvailableSpace: method(z.object({ location: StorageLocationSchema }), z.number().nullable(), { auth: "admin" }),
|
|
20106
|
+
beginUpload: method(BeginUploadInputSchema, BeginUploadResultSchema, {
|
|
20107
|
+
kind: "mutation",
|
|
20108
|
+
auth: "admin"
|
|
20109
|
+
}),
|
|
20110
|
+
writeChunk: method(WriteChunkInputSchema, z.void(), {
|
|
20111
|
+
kind: "mutation",
|
|
20112
|
+
auth: "admin"
|
|
20113
|
+
}),
|
|
20114
|
+
finalizeUpload: method(FinalizeUploadInputSchema, z.void(), {
|
|
20115
|
+
kind: "mutation",
|
|
20116
|
+
auth: "admin"
|
|
20117
|
+
}),
|
|
20118
|
+
abortUpload: method(AbortUploadInputSchema, z.void(), {
|
|
20119
|
+
kind: "mutation",
|
|
20120
|
+
auth: "admin"
|
|
20121
|
+
}),
|
|
20122
|
+
beginDownload: method(BeginDownloadInputSchema, BeginDownloadResultSchema, {
|
|
20123
|
+
kind: "mutation",
|
|
20124
|
+
auth: "admin"
|
|
20125
|
+
}),
|
|
20126
|
+
readChunk: method(ReadChunkInputSchema, z.instanceof(Uint8Array), { auth: "admin" }),
|
|
20127
|
+
endDownload: method(EndDownloadInputSchema, z.void(), {
|
|
20128
|
+
kind: "mutation",
|
|
20129
|
+
auth: "admin"
|
|
20130
|
+
})
|
|
19950
20131
|
}
|
|
19951
20132
|
};
|
|
19952
20133
|
//#endregion
|
|
@@ -20285,9 +20466,28 @@ var userPasskeysCapability = {
|
|
|
20285
20466
|
auth: "admin",
|
|
20286
20467
|
access: "create"
|
|
20287
20468
|
}),
|
|
20469
|
+
/**
|
|
20470
|
+
* The four methods below had NO `auth` override — `internal: true` did
|
|
20471
|
+
* not gate the mount (see the 2026-08-26 note on `data-store-provider`),
|
|
20472
|
+
* so they were reachable on the AppRouter at the default
|
|
20473
|
+
* `auth: 'protected'` (any authenticated session), inconsistent with
|
|
20474
|
+
* every other method on this cap (all already `auth: 'admin'`).
|
|
20475
|
+
*
|
|
20476
|
+
* ⚠ Checked before gating: these are also the PRE-AUTH login-ceremony
|
|
20477
|
+
* methods, so admin-gating them here must not break login for an
|
|
20478
|
+
* unauthenticated principal. It doesn't — the real login path is the
|
|
20479
|
+
* PUBLIC `auth.beginAuthentication` / `auth.finishAuthentication` /
|
|
20480
|
+
* `auth.beginDiscoverableAuthentication` / `auth.finishDiscoverableAuthentication`
|
|
20481
|
+
* procedures in `server/backend/src/api/core/auth.router.ts`, which call
|
|
20482
|
+
* `provider.beginAuthentication(...)` etc. directly against the
|
|
20483
|
+
* capability-registry-resolved provider — never through this cap's own
|
|
20484
|
+
* tRPC route. `auth: 'admin'` here only closes a redundant, unused
|
|
20485
|
+
* second entry point onto the same ceremony.
|
|
20486
|
+
*/
|
|
20288
20487
|
beginAuthentication: method(z.object({ userId: z.string().optional() }), z.object({ optionsJSON: z.record(z.string(), z.unknown()) }), {
|
|
20289
20488
|
kind: "mutation",
|
|
20290
|
-
access: "view"
|
|
20489
|
+
access: "view",
|
|
20490
|
+
auth: "admin"
|
|
20291
20491
|
}),
|
|
20292
20492
|
finishAuthentication: method(z.object({
|
|
20293
20493
|
/** Required — the user the assertion belongs to (verified). */
|
|
@@ -20296,11 +20496,13 @@ var userPasskeysCapability = {
|
|
|
20296
20496
|
response: z.record(z.string(), z.unknown())
|
|
20297
20497
|
}), z.object({ verified: z.boolean() }), {
|
|
20298
20498
|
kind: "mutation",
|
|
20299
|
-
access: "view"
|
|
20499
|
+
access: "view",
|
|
20500
|
+
auth: "admin"
|
|
20300
20501
|
}),
|
|
20301
20502
|
beginDiscoverableAuthentication: method(z.object({}), z.object({ optionsJSON: z.record(z.string(), z.unknown()) }), {
|
|
20302
20503
|
kind: "mutation",
|
|
20303
|
-
access: "view"
|
|
20504
|
+
access: "view",
|
|
20505
|
+
auth: "admin"
|
|
20304
20506
|
}),
|
|
20305
20507
|
finishDiscoverableAuthentication: method(z.object({
|
|
20306
20508
|
/** AuthenticationResponseJSON from the browser. */
|
|
@@ -20309,7 +20511,8 @@ response: z.record(z.string(), z.unknown()) }), z.object({
|
|
|
20309
20511
|
userId: z.string().nullable()
|
|
20310
20512
|
}), {
|
|
20311
20513
|
kind: "mutation",
|
|
20312
|
-
access: "view"
|
|
20514
|
+
access: "view",
|
|
20515
|
+
auth: "admin"
|
|
20313
20516
|
}),
|
|
20314
20517
|
listPasskeys: method(z.object({ userId: z.string() }), z.array(PasskeySummarySchema), { auth: "admin" }),
|
|
20315
20518
|
removePasskey: method(z.object({
|
|
@@ -20489,6 +20692,14 @@ var VectorStatsResultSchema = z.object({
|
|
|
20489
20692
|
/** False when the backend ranks approximately. */
|
|
20490
20693
|
exact: z.boolean()
|
|
20491
20694
|
});
|
|
20695
|
+
/**
|
|
20696
|
+
* `internal: true` did not gate the mount (see the 2026-08-26 note on
|
|
20697
|
+
* `data-store-provider`) — every method below was reachable on the AppRouter
|
|
20698
|
+
* by ANY authenticated session at the default `auth: 'protected'`. The only
|
|
20699
|
+
* consumers (`addon-post-analysis`'s embedding stores) reach this cap via
|
|
20700
|
+
* `ctx.api` — UDS/Moleculer, never tRPC — so `auth: 'admin'` on every method
|
|
20701
|
+
* costs them nothing. No client (viewer or admin-ui) calls `vectorStore.*`.
|
|
20702
|
+
*/
|
|
20492
20703
|
var vectorStoreCapability = {
|
|
20493
20704
|
name: "vector-store",
|
|
20494
20705
|
scope: "system",
|
|
@@ -20496,14 +20707,26 @@ var vectorStoreCapability = {
|
|
|
20496
20707
|
internal: true,
|
|
20497
20708
|
methods: {
|
|
20498
20709
|
/** Idempotent. Re-declaring with a different `dim` is an error, not a wipe. */
|
|
20499
|
-
declareIndex: method(VectorDeclareIndexInputSchema, z.void(), {
|
|
20500
|
-
|
|
20501
|
-
|
|
20710
|
+
declareIndex: method(VectorDeclareIndexInputSchema, z.void(), {
|
|
20711
|
+
kind: "mutation",
|
|
20712
|
+
auth: "admin"
|
|
20713
|
+
}),
|
|
20714
|
+
upsert: method(VectorUpsertInputSchema, VectorUpsertResultSchema, {
|
|
20715
|
+
kind: "mutation",
|
|
20716
|
+
auth: "admin"
|
|
20717
|
+
}),
|
|
20718
|
+
query: method(VectorQueryInputSchema, VectorQueryResultSchema, { auth: "admin" }),
|
|
20502
20719
|
/** Metadata by id, no vectors — see {@link VectorGetResultSchema}. */
|
|
20503
|
-
getByIds: method(VectorGetInputSchema, VectorGetResultSchema),
|
|
20504
|
-
deleteByIds: method(VectorDeleteInputSchema, VectorDeleteResultSchema, {
|
|
20505
|
-
|
|
20506
|
-
|
|
20720
|
+
getByIds: method(VectorGetInputSchema, VectorGetResultSchema, { auth: "admin" }),
|
|
20721
|
+
deleteByIds: method(VectorDeleteInputSchema, VectorDeleteResultSchema, {
|
|
20722
|
+
kind: "mutation",
|
|
20723
|
+
auth: "admin"
|
|
20724
|
+
}),
|
|
20725
|
+
deleteByFilter: method(VectorDeleteByFilterInputSchema, VectorDeleteResultSchema, {
|
|
20726
|
+
kind: "mutation",
|
|
20727
|
+
auth: "admin"
|
|
20728
|
+
}),
|
|
20729
|
+
stats: method(VectorStatsInputSchema, VectorStatsResultSchema, { auth: "admin" })
|
|
20507
20730
|
}
|
|
20508
20731
|
};
|
|
20509
20732
|
//#endregion
|
|
@@ -2171,8 +2171,17 @@ var adminUiCapability = {
|
|
|
2171
2171
|
mode: "singleton",
|
|
2172
2172
|
internal: true,
|
|
2173
2173
|
methods: {
|
|
2174
|
-
|
|
2175
|
-
|
|
2174
|
+
/**
|
|
2175
|
+
* `internal: true` did not gate the mount (see the 2026-08-26 note on
|
|
2176
|
+
* `data-store-provider`) — both methods were reachable on the AppRouter
|
|
2177
|
+
* by ANY authenticated session at the default `auth: 'protected'`, and
|
|
2178
|
+
* `getStaticDir` leaks a hub filesystem path. The only caller is
|
|
2179
|
+
* `main.ts`'s static-file bootstrap, via `capRegistry.getSingletonForNode`
|
|
2180
|
+
* — never tRPC — so `auth: 'admin'` costs it nothing. The actual admin-ui
|
|
2181
|
+
* SPA assets are served as plain static files, unaffected by this gate.
|
|
2182
|
+
*/
|
|
2183
|
+
getStaticDir: method(z.void(), StaticDirOutputSchema$1, { auth: "admin" }),
|
|
2184
|
+
getVersion: method(z.void(), VersionOutputSchema$1, { auth: "admin" })
|
|
2176
2185
|
}
|
|
2177
2186
|
};
|
|
2178
2187
|
//#endregion
|
|
@@ -2518,8 +2527,23 @@ var viewerUiCapability = {
|
|
|
2518
2527
|
mode: "singleton",
|
|
2519
2528
|
internal: true,
|
|
2520
2529
|
methods: {
|
|
2521
|
-
|
|
2522
|
-
|
|
2530
|
+
/**
|
|
2531
|
+
* `internal: true` did not gate the mount (see the 2026-08-26 note on
|
|
2532
|
+
* `data-store-provider`) — both methods were reachable on the AppRouter
|
|
2533
|
+
* by ANY authenticated session at the default `auth: 'protected'`, and
|
|
2534
|
+
* `getStaticDir` leaks a hub filesystem path.
|
|
2535
|
+
*
|
|
2536
|
+
* ⚠ Checked before gating: the VIEWER app IS used by a non-admin user
|
|
2537
|
+
* (`roberta`), but it never calls `viewerUi.*` over tRPC. The static SPA
|
|
2538
|
+
* it loads is served by the plain `GET /viewer/*` Fastify route in
|
|
2539
|
+
* `main.ts`, which reads `staticDir`/`indexPath` from a module-level
|
|
2540
|
+
* cache populated ONCE at boot via `capRegistry.getSingletonForNode`
|
|
2541
|
+
* (in-process, not tRPC) — the cap's tRPC procedure is never on that
|
|
2542
|
+
* request path. `auth: 'admin'` here does not block a single viewer
|
|
2543
|
+
* user from loading the app.
|
|
2544
|
+
*/
|
|
2545
|
+
getStaticDir: method(z.void(), StaticDirOutputSchema, { auth: "admin" }),
|
|
2546
|
+
getVersion: method(z.void(), VersionOutputSchema, { auth: "admin" })
|
|
2523
2547
|
}
|
|
2524
2548
|
};
|
|
2525
2549
|
//#endregion
|