@camstack/addon-pipeline 0.1.14 → 0.1.16
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/audio-analyzer/index.js +2 -4
- package/dist/audio-analyzer/index.js.map +1 -1
- package/dist/audio-analyzer/index.mjs +2 -4
- package/dist/audio-analyzer/index.mjs.map +1 -1
- package/dist/audio-codec-nodeav/index.js +1 -1
- package/dist/audio-codec-nodeav/index.mjs +1 -1
- package/dist/decoder-nodeav/index.js +552 -18
- package/dist/decoder-nodeav/index.js.map +1 -1
- package/dist/decoder-nodeav/index.mjs +553 -19
- package/dist/decoder-nodeav/index.mjs.map +1 -1
- package/dist/detection-pipeline/index.js +2 -4
- package/dist/detection-pipeline/index.js.map +1 -1
- package/dist/detection-pipeline/index.mjs +2 -4
- package/dist/detection-pipeline/index.mjs.map +1 -1
- package/dist/{index-DKh0uEve.mjs → index-CVzLrojg.mjs} +539 -97
- package/dist/index-CVzLrojg.mjs.map +1 -0
- package/dist/{index-CFPKrb2Y.js → index-p-6GfKOg.js} +539 -97
- package/dist/index-p-6GfKOg.js.map +1 -0
- package/dist/motion-wasm/index.js +2 -4
- package/dist/motion-wasm/index.js.map +1 -1
- package/dist/motion-wasm/index.mjs +2 -4
- package/dist/motion-wasm/index.mjs.map +1 -1
- package/dist/pipeline-runner/index.js +133 -54
- package/dist/pipeline-runner/index.js.map +1 -1
- package/dist/pipeline-runner/index.mjs +133 -54
- package/dist/pipeline-runner/index.mjs.map +1 -1
- package/dist/stream-broker/@mf-types.zip +0 -0
- package/dist/stream-broker/__mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.mjs-d8PmLbO2.mjs +19 -0
- package/dist/stream-broker/__mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.mjs-B4l8Nb2y.mjs +20 -0
- package/dist/stream-broker/{__mfe_internal__addon_stream_broker_widgets__loadShare__react__loadShare__.mjs-DePVYdid.mjs → __mfe_internal__addon_stream_broker_widgets__loadShare__react__loadShare__.mjs-DAssX3h0.mjs} +4 -2
- package/dist/stream-broker/{__mfe_internal__addon_stream_broker_widgets__loadShare__react__loadShare__.mjs_commonjs-proxy-CBlCGyx5.mjs → __mfe_internal__addon_stream_broker_widgets__loadShare__react__loadShare__.mjs_commonjs-proxy-DFoJJhpt.mjs} +1 -1
- package/dist/stream-broker/{__mfe_internal__addon_stream_broker_widgets__loadShare__react_mf_2_dom__loadShare__.mjs_commonjs-proxy-DZchZKbW.mjs → __mfe_internal__addon_stream_broker_widgets__loadShare__react_mf_2_dom__loadShare__.mjs_commonjs-proxy-x7XMEeuJ.mjs} +1 -1
- package/dist/stream-broker/_stub.js +2 -2
- package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-CqeKw-Ig.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-iA_8b8fz.mjs} +6 -6
- package/dist/stream-broker/{client-BK73l2KT.mjs → client-CZXrddDR.mjs} +2990 -3217
- package/dist/stream-broker/{hostInit-DkjoXTMb.mjs → hostInit-1sVsS6_a.mjs} +12 -12
- package/dist/stream-broker/{index-BP0-1QYT.mjs → index-BCEx31Mh.mjs} +3808 -3100
- package/dist/stream-broker/{index-lmXLeXy8.mjs → index-BvV3RVTZ.mjs} +1 -1
- package/dist/stream-broker/{index-IUYKHbxX.mjs → index-C0BzaWmB.mjs} +1 -1
- package/dist/stream-broker/index-CWkKuNLr.mjs +232 -0
- package/dist/stream-broker/{index-ns1fRD30.mjs → index-CZNxa0ad.mjs} +1 -1
- package/dist/stream-broker/index-Kb4xa8FX.mjs +36403 -0
- package/dist/stream-broker/{index-BxHaCH3N.mjs → index-KtR7Pp0O.mjs} +1 -1
- package/dist/stream-broker/{index-Ss9m7Jum.mjs → index-cYW01SNH.mjs} +1 -1
- package/dist/stream-broker/index.js +802 -541
- package/dist/stream-broker/index.js.map +1 -1
- package/dist/stream-broker/index.mjs +802 -519
- package/dist/stream-broker/index.mjs.map +1 -1
- package/dist/stream-broker/{jsx-runtime-ZdY5pIZz.mjs → jsx-runtime-B_evVsXl.mjs} +1 -1
- package/dist/stream-broker/remoteEntry.js +1 -1
- package/package.json +23 -31
- package/dist/index-CFPKrb2Y.js.map +0 -1
- package/dist/index-DKh0uEve.mjs.map +0 -1
- package/dist/stream-broker/__mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.mjs-CpCK52pE.mjs +0 -19
- package/dist/stream-broker/__mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.mjs-BN3K4dM8.mjs +0 -20
- package/dist/stream-broker/index-DKercbDS.mjs +0 -20855
- package/python/__pycache__/inference_pool.cpython-313.pyc +0 -0
- package/python/postprocessors/__pycache__/__init__.cpython-312.pyc +0 -0
- package/python/postprocessors/__pycache__/__init__.cpython-313.pyc +0 -0
- package/python/postprocessors/__pycache__/_safety.cpython-313.pyc +0 -0
- package/python/postprocessors/__pycache__/arcface.cpython-312.pyc +0 -0
- package/python/postprocessors/__pycache__/arcface.cpython-313.pyc +0 -0
- package/python/postprocessors/__pycache__/ctc.cpython-312.pyc +0 -0
- package/python/postprocessors/__pycache__/ctc.cpython-313.pyc +0 -0
- package/python/postprocessors/__pycache__/saliency.cpython-312.pyc +0 -0
- package/python/postprocessors/__pycache__/saliency.cpython-313.pyc +0 -0
- package/python/postprocessors/__pycache__/scrfd.cpython-312.pyc +0 -0
- package/python/postprocessors/__pycache__/scrfd.cpython-313.pyc +0 -0
- package/python/postprocessors/__pycache__/softmax.cpython-312.pyc +0 -0
- package/python/postprocessors/__pycache__/softmax.cpython-313.pyc +0 -0
- package/python/postprocessors/__pycache__/yamnet.cpython-312.pyc +0 -0
- package/python/postprocessors/__pycache__/yamnet.cpython-313.pyc +0 -0
- package/python/postprocessors/__pycache__/yolo.cpython-312.pyc +0 -0
- package/python/postprocessors/__pycache__/yolo.cpython-313.pyc +0 -0
- package/python/postprocessors/__pycache__/yolo_seg.cpython-312.pyc +0 -0
- package/python/postprocessors/__pycache__/yolo_seg.cpython-313.pyc +0 -0
|
@@ -5068,6 +5068,7 @@ const WELL_KNOWN_TABS = [
|
|
|
5068
5068
|
{ id: "osd", label: "OSD", icon: "type", order: 18 },
|
|
5069
5069
|
{ id: "stream-broker", label: "Stream Broker", icon: "radio", order: 20 },
|
|
5070
5070
|
{ id: "streaming", label: "Streaming", icon: "video", order: 35 },
|
|
5071
|
+
{ id: "ptz", label: "PTZ", icon: "move", order: 40 },
|
|
5071
5072
|
{ id: "pipeline", label: "Detection Pipeline", icon: "cpu", order: 39 },
|
|
5072
5073
|
{ id: "zones", label: "Detection", icon: "shapes", order: 38 },
|
|
5073
5074
|
{ id: "live-stats", label: "Live Stats", icon: "activity", order: 39 },
|
|
@@ -5135,6 +5136,9 @@ function hydrateField(field, values) {
|
|
|
5135
5136
|
return { ...field, value: items };
|
|
5136
5137
|
}
|
|
5137
5138
|
const rawValue = storedValue !== void 0 ? storedValue : defaultValue !== void 0 ? defaultValue : null;
|
|
5139
|
+
if (field.type === "password") {
|
|
5140
|
+
return { ...field, value: "" };
|
|
5141
|
+
}
|
|
5138
5142
|
const value = field.type === "textarea" && field.isJson && rawValue !== null && typeof rawValue === "object" ? JSON.stringify(rawValue, null, 2) : rawValue;
|
|
5139
5143
|
const hydrated = { ...field, value };
|
|
5140
5144
|
return hydrated;
|
|
@@ -5221,7 +5225,19 @@ const DecoderSessionConfigSchema = object({
|
|
|
5221
5225
|
* on every line so `grep tag=broker:5/high` filters one camera
|
|
5222
5226
|
* profile cleanly.
|
|
5223
5227
|
*/
|
|
5224
|
-
tag: string().optional()
|
|
5228
|
+
tag: string().optional(),
|
|
5229
|
+
/**
|
|
5230
|
+
* Where the session delivers decoded frames (Phase 5 / D9):
|
|
5231
|
+
*
|
|
5232
|
+
* - `'callback'` (default) — the legacy pixel path: decoded frames are
|
|
5233
|
+
* buffered as `DecodedFrame`s and drained via `pullFrames`.
|
|
5234
|
+
* - `'shm'` — the shared-memory frame plane: decoded frames are written
|
|
5235
|
+
* into an OS shared-memory ring and drained as zero-pixel
|
|
5236
|
+
* `FrameHandle`s via `pullHandles`. A session is one mode or the
|
|
5237
|
+
* other — `pullFrames` returns nothing for an `'shm'` session and
|
|
5238
|
+
* `pullHandles` returns nothing for a `'callback'` session.
|
|
5239
|
+
*/
|
|
5240
|
+
frameSink: _enum(["callback", "shm"]).default("callback")
|
|
5225
5241
|
});
|
|
5226
5242
|
function errMsg(err) {
|
|
5227
5243
|
if (err instanceof Error) return err.message;
|
|
@@ -5987,6 +6003,53 @@ const DecodedFrameSchema = object({
|
|
|
5987
6003
|
format: _enum(["jpeg", "rgb", "bgr", "yuv420", "gray"]),
|
|
5988
6004
|
timestamp: number()
|
|
5989
6005
|
});
|
|
6006
|
+
const FrameHandleSchema = object({
|
|
6007
|
+
shmId: string(),
|
|
6008
|
+
slot: number().int().nonnegative(),
|
|
6009
|
+
seq: number().int().nonnegative(),
|
|
6010
|
+
width: number().int().positive(),
|
|
6011
|
+
height: number().int().positive(),
|
|
6012
|
+
format: _enum(["jpeg", "rgb", "bgr", "yuv420", "gray"]),
|
|
6013
|
+
pts: number(),
|
|
6014
|
+
byteLength: number().int().nonnegative(),
|
|
6015
|
+
nodeId: string(),
|
|
6016
|
+
slotCount: number().int().positive()
|
|
6017
|
+
});
|
|
6018
|
+
const FrameHandleFormatSchema = _enum(["rgb", "bgr", "yuv420", "gray"]);
|
|
6019
|
+
const SubscribeFramesInputSchema = object({
|
|
6020
|
+
brokerId: string(),
|
|
6021
|
+
format: FrameHandleFormatSchema,
|
|
6022
|
+
/**
|
|
6023
|
+
* Optional reader-side cadence hint in frames per second. The broker does
|
|
6024
|
+
* NOT throttle — latest-wins ring reads drop frames implicitly for a slow
|
|
6025
|
+
* consumer. The value is echoed back in `SubscribeFramesResult.maxFps` so
|
|
6026
|
+
* the consumer can pace its own `pullFrameHandles` polling.
|
|
6027
|
+
*/
|
|
6028
|
+
maxFps: number().positive().optional(),
|
|
6029
|
+
/** Short caller-identity tag (`motion`, `detection`, …) for diagnostics. */
|
|
6030
|
+
tag: string().optional()
|
|
6031
|
+
});
|
|
6032
|
+
const SubscribeFramesResultSchema = object({
|
|
6033
|
+
/** Opaque id the consumer passes to `pullFrameHandles` / `unsubscribeFrames`. */
|
|
6034
|
+
subscriptionId: string(),
|
|
6035
|
+
/** Reader-side cadence hint (frames/s) — echoes `SubscribeFramesInput.maxFps`. */
|
|
6036
|
+
maxFps: number().nonnegative()
|
|
6037
|
+
});
|
|
6038
|
+
const DecodedAudioChunkSchema = object({
|
|
6039
|
+
data: _instanceof(Uint8Array),
|
|
6040
|
+
sampleRate: number().int().positive(),
|
|
6041
|
+
channels: number().int().positive(),
|
|
6042
|
+
timestamp: number()
|
|
6043
|
+
});
|
|
6044
|
+
const SubscribeAudioChunksInputSchema = object({
|
|
6045
|
+
brokerId: string(),
|
|
6046
|
+
/** Short caller-identity tag (`audio-analyzer`, …) for `listClients`. */
|
|
6047
|
+
tag: string().optional()
|
|
6048
|
+
});
|
|
6049
|
+
const SubscribeAudioChunksResultSchema = object({
|
|
6050
|
+
/** Opaque id passed to `pullAudioChunks` / `unsubscribeAudioChunks`. */
|
|
6051
|
+
subscriptionId: string()
|
|
6052
|
+
});
|
|
5990
6053
|
const BrokerStatusSchema$1 = _enum(["idle", "connecting", "streaming", "error", "stopped"]);
|
|
5991
6054
|
const BrokerStatsSchema = object({
|
|
5992
6055
|
status: BrokerStatusSchema$1,
|
|
@@ -6212,9 +6275,76 @@ const streamBrokerCapability = {
|
|
|
6212
6275
|
object({ released: boolean(), refcount: number().int().nonnegative() }),
|
|
6213
6276
|
{ kind: "mutation", auth: "admin" }
|
|
6214
6277
|
),
|
|
6215
|
-
|
|
6216
|
-
|
|
6217
|
-
|
|
6278
|
+
/**
|
|
6279
|
+
* ── Decoded audio-chunk plane (Phase 5 / D9) ──────────────────────
|
|
6280
|
+
*
|
|
6281
|
+
* The serialisable replacement for the live-object `IStreamBroker.
|
|
6282
|
+
* onDecodedAudioChunk` callback path. Unlike the video frame plane,
|
|
6283
|
+
* audio chunks are tiny (a ~500ms PCM window is a few KB) so they ship
|
|
6284
|
+
* their bytes INLINE over tRPC — no shared-memory ring. A consumer:
|
|
6285
|
+
*
|
|
6286
|
+
* 1. `subscribeAudioChunks({ brokerId, tag })` — the broker registers
|
|
6287
|
+
* a per-subscription bounded FIFO queue and returns a
|
|
6288
|
+
* `subscriptionId`.
|
|
6289
|
+
* 2. polls `pullAudioChunks({ subscriptionId, maxCount })` — drains
|
|
6290
|
+
* `DecodedAudioChunk[]` in arrival order (FIFO, no latest-wins
|
|
6291
|
+
* drop: an audio gap is audible / breaks an analysis window). The
|
|
6292
|
+
* queue is generously sized; it only drops its oldest chunk if a
|
|
6293
|
+
* truly stalled consumer lets it overflow.
|
|
6294
|
+
* 3. `unsubscribeAudioChunks({ subscriptionId })` on teardown.
|
|
6295
|
+
*/
|
|
6296
|
+
subscribeAudioChunks: method(
|
|
6297
|
+
SubscribeAudioChunksInputSchema,
|
|
6298
|
+
SubscribeAudioChunksResultSchema,
|
|
6299
|
+
{ kind: "mutation" }
|
|
6300
|
+
),
|
|
6301
|
+
pullAudioChunks: method(
|
|
6302
|
+
object({
|
|
6303
|
+
subscriptionId: string(),
|
|
6304
|
+
maxCount: number().int().positive().default(8)
|
|
6305
|
+
}),
|
|
6306
|
+
array(DecodedAudioChunkSchema).readonly()
|
|
6307
|
+
),
|
|
6308
|
+
unsubscribeAudioChunks: method(
|
|
6309
|
+
object({ subscriptionId: string() }),
|
|
6310
|
+
object({ released: boolean() }),
|
|
6311
|
+
{ kind: "mutation" }
|
|
6312
|
+
),
|
|
6313
|
+
/**
|
|
6314
|
+
* ── Shared-memory frame plane (Phase 5 / D9) ──────────────────────
|
|
6315
|
+
*
|
|
6316
|
+
* The handle-based replacement for the live-object `IStreamBroker.
|
|
6317
|
+
* onDecodedFrame` callback path. A consumer:
|
|
6318
|
+
*
|
|
6319
|
+
* 1. `subscribeFrames({ brokerId, format })` — the broker spins up
|
|
6320
|
+
* (or reuses) a `frameSink: 'shm'` decoder session producing that
|
|
6321
|
+
* `format` and returns a `subscriptionId`.
|
|
6322
|
+
* 2. polls `pullFrameHandles({ subscriptionId, maxCount })` — drains
|
|
6323
|
+
* zero-pixel `FrameHandle[]`; each handle is fed to a
|
|
6324
|
+
* `FrameRingReader` that opens the named shm segment and reads the
|
|
6325
|
+
* pixels back zero-copy.
|
|
6326
|
+
* 3. `unsubscribeFrames({ subscriptionId })` on teardown.
|
|
6327
|
+
*
|
|
6328
|
+
* The broker keeps one shm ring per `(brokerId, format)` actually
|
|
6329
|
+
* requested — no broker-side `sharp` conversion. fps throttling is
|
|
6330
|
+
* implicit (latest-wins ring reads drop frames for a slow consumer).
|
|
6331
|
+
*/
|
|
6332
|
+
subscribeFrames: method(
|
|
6333
|
+
SubscribeFramesInputSchema,
|
|
6334
|
+
SubscribeFramesResultSchema,
|
|
6335
|
+
{ kind: "mutation" }
|
|
6336
|
+
),
|
|
6337
|
+
pullFrameHandles: method(
|
|
6338
|
+
object({
|
|
6339
|
+
subscriptionId: string(),
|
|
6340
|
+
maxCount: number().int().positive().default(4)
|
|
6341
|
+
}),
|
|
6342
|
+
array(FrameHandleSchema).readonly()
|
|
6343
|
+
),
|
|
6344
|
+
unsubscribeFrames: method(
|
|
6345
|
+
object({ subscriptionId: string() }),
|
|
6346
|
+
object({ released: boolean() }),
|
|
6347
|
+
{ kind: "mutation" }
|
|
6218
6348
|
),
|
|
6219
6349
|
setPreBufferDuration: method(
|
|
6220
6350
|
object({ brokerId: string(), seconds: number().min(0).max(30) }),
|
|
@@ -6270,6 +6400,8 @@ const cameraStreamsCapability = {
|
|
|
6270
6400
|
name: "camera-streams",
|
|
6271
6401
|
scope: "device",
|
|
6272
6402
|
mode: "singleton",
|
|
6403
|
+
kind: "wrapper",
|
|
6404
|
+
defaultActive: true,
|
|
6273
6405
|
deviceTypes: [DeviceType.Camera],
|
|
6274
6406
|
methods: {
|
|
6275
6407
|
getCameraStreams: method(
|
|
@@ -6535,6 +6667,8 @@ const motionDetectionCapability = {
|
|
|
6535
6667
|
name: "motion-detection",
|
|
6536
6668
|
scope: "device",
|
|
6537
6669
|
mode: "singleton",
|
|
6670
|
+
kind: "wrapper",
|
|
6671
|
+
defaultActive: true,
|
|
6538
6672
|
exposesDeviceSettings: true,
|
|
6539
6673
|
methods: {
|
|
6540
6674
|
analyze: method(
|
|
@@ -7305,6 +7439,34 @@ MotionTriggerStatusSchema.extend({
|
|
|
7305
7439
|
}) }
|
|
7306
7440
|
}
|
|
7307
7441
|
});
|
|
7442
|
+
object({
|
|
7443
|
+
enabled: boolean(),
|
|
7444
|
+
sensitivity: number(),
|
|
7445
|
+
/** Row-major active-cell grid. Length = gridWidth*gridHeight (see getOptions). */
|
|
7446
|
+
cells: array(boolean()),
|
|
7447
|
+
lastFetchedAt: number()
|
|
7448
|
+
});
|
|
7449
|
+
const MotionZoneOptionsSchema = object({
|
|
7450
|
+
gridWidth: number(),
|
|
7451
|
+
gridHeight: number(),
|
|
7452
|
+
sensitivity: object({ min: number(), max: number(), step: number() })
|
|
7453
|
+
});
|
|
7454
|
+
const MotionZonePatchSchema = object({
|
|
7455
|
+
enabled: boolean().optional(),
|
|
7456
|
+
sensitivity: number().optional(),
|
|
7457
|
+
cells: array(boolean()).optional()
|
|
7458
|
+
});
|
|
7459
|
+
({
|
|
7460
|
+
deviceTypes: [DeviceType.Camera],
|
|
7461
|
+
methods: {
|
|
7462
|
+
getOptions: method(object({ deviceId: number() }), MotionZoneOptionsSchema),
|
|
7463
|
+
setZone: method(
|
|
7464
|
+
object({ deviceId: number(), patch: MotionZonePatchSchema }),
|
|
7465
|
+
_void(),
|
|
7466
|
+
{ kind: "mutation", auth: "admin" }
|
|
7467
|
+
)
|
|
7468
|
+
}
|
|
7469
|
+
});
|
|
7308
7470
|
const AutotrackTargetTypeSchema = string().describe("Vendor target string (people/vehicle/pet); empty = camera default");
|
|
7309
7471
|
const PtzAutotrackSettingsSchema = object({
|
|
7310
7472
|
targetType: AutotrackTargetTypeSchema,
|
|
@@ -7393,6 +7555,100 @@ PtzAutotrackStatusSchema.extend({
|
|
|
7393
7555
|
}) }
|
|
7394
7556
|
}
|
|
7395
7557
|
});
|
|
7558
|
+
const StreamProfileSchema = _enum(["main", "sub", "ext"]);
|
|
7559
|
+
const StreamProfileConfigSchema = object({
|
|
7560
|
+
width: number(),
|
|
7561
|
+
height: number(),
|
|
7562
|
+
codec: _enum(["h264", "h265"]),
|
|
7563
|
+
framerate: number(),
|
|
7564
|
+
bitrate: number(),
|
|
7565
|
+
// kbps
|
|
7566
|
+
bitrateMode: _enum(["vbr", "cbr"]).optional(),
|
|
7567
|
+
encoderProfile: _enum(["high", "main", "baseline"]).optional(),
|
|
7568
|
+
gop: number().optional(),
|
|
7569
|
+
audio: boolean().optional()
|
|
7570
|
+
});
|
|
7571
|
+
object({
|
|
7572
|
+
/** Per-profile current config. A profile absent = the camera doesn't have it. */
|
|
7573
|
+
main: StreamProfileConfigSchema.optional(),
|
|
7574
|
+
sub: StreamProfileConfigSchema.optional(),
|
|
7575
|
+
ext: StreamProfileConfigSchema.optional(),
|
|
7576
|
+
lastFetchedAt: number()
|
|
7577
|
+
});
|
|
7578
|
+
const StreamProfileOptionsSchema = object({
|
|
7579
|
+
resolutions: array(object({ width: number(), height: number() })),
|
|
7580
|
+
codecs: array(_enum(["h264", "h265"])),
|
|
7581
|
+
framerates: array(number()),
|
|
7582
|
+
/** Allowed bitrate values (kbps). Empty if the camera takes a free range. */
|
|
7583
|
+
bitrates: array(number()),
|
|
7584
|
+
/** Optional [min,max] kbps when the camera accepts a continuous range. */
|
|
7585
|
+
bitrateRange: tuple([number(), number()]).optional(),
|
|
7586
|
+
supportsBitrateMode: boolean(),
|
|
7587
|
+
supportsEncoderProfile: boolean(),
|
|
7588
|
+
supportsGop: boolean(),
|
|
7589
|
+
/** Allowed GOP / keyframe-interval range, in seconds — drives the
|
|
7590
|
+
* I-frame-interval selector. Absent when the camera advertises GOP
|
|
7591
|
+
* support but no concrete range (callers then fall back to a free
|
|
7592
|
+
* numeric input). `{ min, max, step }` per the getOptions convention. */
|
|
7593
|
+
gop: object({ min: number(), max: number(), step: number() }).optional()
|
|
7594
|
+
});
|
|
7595
|
+
const StreamParamsOptionsSchema = object({
|
|
7596
|
+
main: StreamProfileOptionsSchema.optional(),
|
|
7597
|
+
sub: StreamProfileOptionsSchema.optional(),
|
|
7598
|
+
ext: StreamProfileOptionsSchema.optional()
|
|
7599
|
+
});
|
|
7600
|
+
const StreamProfilePatchSchema = object({
|
|
7601
|
+
width: number().optional(),
|
|
7602
|
+
height: number().optional(),
|
|
7603
|
+
codec: _enum(["h264", "h265"]).optional(),
|
|
7604
|
+
framerate: number().optional(),
|
|
7605
|
+
bitrate: number().optional(),
|
|
7606
|
+
bitrateMode: _enum(["vbr", "cbr"]).optional(),
|
|
7607
|
+
encoderProfile: _enum(["high", "main", "baseline"]).optional(),
|
|
7608
|
+
gop: number().optional(),
|
|
7609
|
+
audio: boolean().optional()
|
|
7610
|
+
});
|
|
7611
|
+
({
|
|
7612
|
+
deviceTypes: [DeviceType.Camera],
|
|
7613
|
+
methods: {
|
|
7614
|
+
getOptions: method(
|
|
7615
|
+
object({ deviceId: number() }),
|
|
7616
|
+
StreamParamsOptionsSchema
|
|
7617
|
+
),
|
|
7618
|
+
setProfile: method(
|
|
7619
|
+
object({
|
|
7620
|
+
deviceId: number(),
|
|
7621
|
+
profile: StreamProfileSchema,
|
|
7622
|
+
patch: StreamProfilePatchSchema
|
|
7623
|
+
}),
|
|
7624
|
+
_void(),
|
|
7625
|
+
{ kind: "mutation", auth: "admin" }
|
|
7626
|
+
),
|
|
7627
|
+
/**
|
|
7628
|
+
* Build the `ConfigUISchema` (admin-ui `ConfigFormBuilder` input
|
|
7629
|
+
* shape) for this camera's stream-encoder settings — one section per
|
|
7630
|
+
* profile (main / sub / ext) with the resolution / codec / framerate
|
|
7631
|
+
* / bitrate / bitrate-mode / encoder-profile / GOP controls the
|
|
7632
|
+
* firmware actually exposes.
|
|
7633
|
+
*
|
|
7634
|
+
* Driven by `getOptions` (camera-probed availability) + `getStatus`
|
|
7635
|
+
* (current per-profile config); each field's `default` is seeded
|
|
7636
|
+
* from the live config so the form renders the camera state in one
|
|
7637
|
+
* pass. Returns `null` when the camera exposes no configurable
|
|
7638
|
+
* stream property — the renderer then shows the unsupported message.
|
|
7639
|
+
*
|
|
7640
|
+
* Output is `z.unknown().nullable()` — the same convention every
|
|
7641
|
+
* other `ConfigUISchema`-returning cap method uses (`device-ops`,
|
|
7642
|
+
* `device-manager`); `ConfigUISchema` is a TS-only type with no
|
|
7643
|
+
* companion Zod schema, and a concrete object would collapse
|
|
7644
|
+
* unrelated AppRouter branches to `unknown` during codegen.
|
|
7645
|
+
*/
|
|
7646
|
+
getConfigSchema: method(
|
|
7647
|
+
object({ deviceId: number() }),
|
|
7648
|
+
unknown().nullable()
|
|
7649
|
+
)
|
|
7650
|
+
}
|
|
7651
|
+
});
|
|
7396
7652
|
object({
|
|
7397
7653
|
on: boolean(),
|
|
7398
7654
|
/** Ms epoch of the last state change. Useful for UI "X minutes ago". */
|
|
@@ -8330,6 +8586,83 @@ const VersionOutputSchema = object({ version: string() });
|
|
|
8330
8586
|
getVersion: method(_void(), VersionOutputSchema)
|
|
8331
8587
|
}
|
|
8332
8588
|
});
|
|
8589
|
+
const MethodAccessSchema = _enum(["view", "create", "delete"]);
|
|
8590
|
+
const AllowedProviderSchema = union([literal("*"), array(string())]);
|
|
8591
|
+
const AllowedDevicesSchema = record(string(), union([literal("*"), array(string())]));
|
|
8592
|
+
const CapScopeSchema = _enum(["device", "system"]);
|
|
8593
|
+
const TokenScopeSchema = discriminatedUnion("type", [
|
|
8594
|
+
object({
|
|
8595
|
+
type: literal("category"),
|
|
8596
|
+
target: CapScopeSchema,
|
|
8597
|
+
access: array(MethodAccessSchema).min(1)
|
|
8598
|
+
}),
|
|
8599
|
+
object({
|
|
8600
|
+
type: literal("capability"),
|
|
8601
|
+
target: string(),
|
|
8602
|
+
access: array(MethodAccessSchema).min(1)
|
|
8603
|
+
}),
|
|
8604
|
+
object({
|
|
8605
|
+
type: literal("addon"),
|
|
8606
|
+
target: string(),
|
|
8607
|
+
access: array(MethodAccessSchema).min(1)
|
|
8608
|
+
}),
|
|
8609
|
+
object({
|
|
8610
|
+
type: literal("device"),
|
|
8611
|
+
/**
|
|
8612
|
+
* One or more deviceIds (serialised as strings for wire-format
|
|
8613
|
+
* consistency with the rest of the union). Matcher accepts if
|
|
8614
|
+
* `input.deviceId` ∈ `targets`. Array shape avoids the row-explosion
|
|
8615
|
+
* of one scope-per-device when granting access to a set of cameras.
|
|
8616
|
+
*/
|
|
8617
|
+
targets: array(string()).min(1),
|
|
8618
|
+
access: array(MethodAccessSchema).min(1)
|
|
8619
|
+
})
|
|
8620
|
+
]);
|
|
8621
|
+
object({
|
|
8622
|
+
id: string(),
|
|
8623
|
+
username: string(),
|
|
8624
|
+
passwordHash: string(),
|
|
8625
|
+
/**
|
|
8626
|
+
* Admin bypass. When true, the middleware skips the scope-access
|
|
8627
|
+
* check entirely. There is no other axis of privilege; the legacy
|
|
8628
|
+
* role enum collapsed onto this boolean in v2.
|
|
8629
|
+
*/
|
|
8630
|
+
isAdmin: boolean().default(false),
|
|
8631
|
+
allowedProviders: AllowedProviderSchema,
|
|
8632
|
+
allowedDevices: AllowedDevicesSchema,
|
|
8633
|
+
/**
|
|
8634
|
+
* Scopes granted to this user. Admins bypass; their `scopes` is
|
|
8635
|
+
* ignored. Non-admins without scopes are locked out of every
|
|
8636
|
+
* protected call.
|
|
8637
|
+
*/
|
|
8638
|
+
scopes: array(TokenScopeSchema).default([]),
|
|
8639
|
+
createdAt: number(),
|
|
8640
|
+
updatedAt: number()
|
|
8641
|
+
});
|
|
8642
|
+
object({
|
|
8643
|
+
id: string(),
|
|
8644
|
+
label: string(),
|
|
8645
|
+
isAdmin: boolean().default(false),
|
|
8646
|
+
allowedProviders: AllowedProviderSchema,
|
|
8647
|
+
allowedDevices: AllowedDevicesSchema,
|
|
8648
|
+
tokenHash: string(),
|
|
8649
|
+
tokenPrefix: string(),
|
|
8650
|
+
createdAt: number(),
|
|
8651
|
+
lastUsedAt: number().optional()
|
|
8652
|
+
});
|
|
8653
|
+
object({
|
|
8654
|
+
id: string(),
|
|
8655
|
+
userId: string(),
|
|
8656
|
+
name: string(),
|
|
8657
|
+
tokenHash: string(),
|
|
8658
|
+
tokenPrefix: string(),
|
|
8659
|
+
scopes: array(TokenScopeSchema),
|
|
8660
|
+
// SQLite/JSON storage round-trips undefined → null. Use `nullish` so the
|
|
8661
|
+
// schema accepts both `null` (read from disk) and `undefined` (in-memory).
|
|
8662
|
+
expiresAt: number().nullish(),
|
|
8663
|
+
lastUsedAt: number().nullish(),
|
|
8664
|
+
createdAt: number()
|
|
8665
|
+
});
|
|
8333
8666
|
const SsoBridgeClaimsSchema = object({
|
|
8334
8667
|
userId: string(),
|
|
8335
8668
|
username: string(),
|
|
@@ -8345,7 +8678,18 @@ const SsoBridgeClaimsSchema = object({
|
|
|
8345
8678
|
* JWT WITHOUT verifying the signature — the hub re-verifies on every
|
|
8346
8679
|
* inbound call so trust still rests with the signing hub.
|
|
8347
8680
|
*/
|
|
8348
|
-
hubUrl: string().optional()
|
|
8681
|
+
hubUrl: string().optional(),
|
|
8682
|
+
/** Permission scopes baked into the token. Set by the OAuth
|
|
8683
|
+
* account-linking grant; absent on ordinary SSO-login tokens. */
|
|
8684
|
+
scopes: array(TokenScopeSchema).optional(),
|
|
8685
|
+
/** OAuth authorization-code binding — set only on `oauth-code` tokens. */
|
|
8686
|
+
redirectUri: string().optional(),
|
|
8687
|
+
integrationId: string().optional(),
|
|
8688
|
+
/** JWT ID — unique per issued code; consumed-set enforces single-use. */
|
|
8689
|
+
jti: string().optional(),
|
|
8690
|
+
/** OAuth session registry id — set on `oauth-access`/`oauth-refresh`
|
|
8691
|
+
* tokens so the verify path can check the session is not revoked. */
|
|
8692
|
+
sessionId: string().optional()
|
|
8349
8693
|
});
|
|
8350
8694
|
({
|
|
8351
8695
|
methods: {
|
|
@@ -8362,6 +8706,23 @@ const SsoBridgeClaimsSchema = object({
|
|
|
8362
8706
|
)
|
|
8363
8707
|
}
|
|
8364
8708
|
});
|
|
8709
|
+
const OauthIntegrationDescriptorSchema = object({
|
|
8710
|
+
/** Stable id used as the `integration=` query param, e.g. 'export-alexa'. */
|
|
8711
|
+
integrationId: string(),
|
|
8712
|
+
/** Human label rendered on the consent page. */
|
|
8713
|
+
displayName: string(),
|
|
8714
|
+
/** Scopes baked into every token issued for this integration. */
|
|
8715
|
+
requestedScopes: array(TokenScopeSchema),
|
|
8716
|
+
/** Allowed redirect_uri prefixes. /api/oauth2/authorize rejects any
|
|
8717
|
+
* redirect_uri that does not start with one of these. Required —
|
|
8718
|
+
* an empty list means the integration can never complete linking. */
|
|
8719
|
+
allowedRedirectPrefixes: array(string()).min(1)
|
|
8720
|
+
});
|
|
8721
|
+
({
|
|
8722
|
+
methods: {
|
|
8723
|
+
getDescriptor: method(_void(), OauthIntegrationDescriptorSchema)
|
|
8724
|
+
}
|
|
8725
|
+
});
|
|
8365
8726
|
const PasskeySummarySchema = object({
|
|
8366
8727
|
credentialId: string(),
|
|
8367
8728
|
label: string(),
|
|
@@ -8642,21 +9003,30 @@ const AddonPageDeclarationSchema = object({
|
|
|
8642
9003
|
});
|
|
8643
9004
|
const WidgetHostEnum = _enum(["device-tab", "dashboard", "integration-detail"]);
|
|
8644
9005
|
const WidgetSizeEnum = _enum(["xs", "sm", "md", "lg", "xl"]);
|
|
9006
|
+
const WidgetRemoteSchema = object({
|
|
9007
|
+
remoteName: string(),
|
|
9008
|
+
exposedModule: string(),
|
|
9009
|
+
componentKey: string().optional()
|
|
9010
|
+
});
|
|
8645
9011
|
const WidgetMetadataSchema = object({
|
|
8646
|
-
|
|
8647
|
-
|
|
9012
|
+
// ── UiContribution core (kind:'remote') ──────────────────────────
|
|
9013
|
+
/** Primary host tab — `'dashboard'`, `'device-tab'`, or a device-detail tab id. */
|
|
9014
|
+
tab: string(),
|
|
9015
|
+
/** Optional sub-tab within `tab`. */
|
|
9016
|
+
subTab: string().optional(),
|
|
8648
9017
|
/** Operator-facing label. */
|
|
8649
9018
|
label: string(),
|
|
9019
|
+
/** Ordering within `(tab, subTab)`, ascending. */
|
|
9020
|
+
order: number().optional(),
|
|
9021
|
+
/** Always `'remote'` — a widget is a Module Federation remote. */
|
|
9022
|
+
kind: literal("remote"),
|
|
9023
|
+
/** MF remote descriptor. */
|
|
9024
|
+
remote: WidgetRemoteSchema,
|
|
9025
|
+
// ── Widget-only metadata ─────────────────────────────────────────
|
|
9026
|
+
/** Stable id within the addon — kebab-case. Equals `remote.componentKey`. */
|
|
9027
|
+
stableId: string(),
|
|
8650
9028
|
description: string().optional(),
|
|
8651
9029
|
icon: string().optional(),
|
|
8652
|
-
/**
|
|
8653
|
-
* Module Federation remote name — must match the `name` field on the
|
|
8654
|
-
* widget addon's `federation()` plugin config. Used by the host's
|
|
8655
|
-
* `<WidgetRegistryProvider>` to call `loadRemote('<remoteName>/widgets')`.
|
|
8656
|
-
* Conventionally `addon_<addonid>_widgets` (snake_case; MF names
|
|
8657
|
-
* cannot contain hyphens).
|
|
8658
|
-
*/
|
|
8659
|
-
remoteName: string(),
|
|
8660
9030
|
/**
|
|
8661
9031
|
* Bundle filename inside the addon's `dist/` dir served at
|
|
8662
9032
|
* `/api/addon-widgets/<addonId>/<bundle>`. With Module Federation
|
|
@@ -8665,9 +9035,9 @@ const WidgetMetadataSchema = object({
|
|
|
8665
9035
|
* cache-buster URL without a separate filesystem stat.
|
|
8666
9036
|
*/
|
|
8667
9037
|
bundle: string(),
|
|
8668
|
-
/**
|
|
9038
|
+
/** Every host the widget supports. The picker filters on this set. */
|
|
8669
9039
|
hosts: array(WidgetHostEnum).readonly(),
|
|
8670
|
-
/** Required props the host must supply. Validated at
|
|
9040
|
+
/** Required props the host must supply. Validated at `<WidgetSlot>` mount. */
|
|
8671
9041
|
requires: object({
|
|
8672
9042
|
deviceContext: boolean().default(false),
|
|
8673
9043
|
integrationContext: boolean().default(false)
|
|
@@ -8760,6 +9130,16 @@ const DEFAULT_DECODER_HWACCEL_CONFIG = {
|
|
|
8760
9130
|
hwaccel: "auto",
|
|
8761
9131
|
probedBestHwaccel: ""
|
|
8762
9132
|
};
|
|
9133
|
+
const ShmRingStatsSchema = object({
|
|
9134
|
+
sessionId: string(),
|
|
9135
|
+
slotCount: number().int(),
|
|
9136
|
+
slotByteLength: number().int(),
|
|
9137
|
+
segmentBytes: number().int(),
|
|
9138
|
+
budgetMb: number().int(),
|
|
9139
|
+
framesWritten: number().int(),
|
|
9140
|
+
getFrameHits: number().int(),
|
|
9141
|
+
getFrameMisses: number().int()
|
|
9142
|
+
});
|
|
8763
9143
|
const decoderCapability = {
|
|
8764
9144
|
name: "decoder",
|
|
8765
9145
|
scope: "system",
|
|
@@ -8796,10 +9176,27 @@ const decoderCapability = {
|
|
|
8796
9176
|
url: string()
|
|
8797
9177
|
}), _void()),
|
|
8798
9178
|
// ── Output — polling-based frame retrieval ────────────────────
|
|
9179
|
+
// `pullFrames` drains the pixel `DecodedFrame[]` of a `frameSink:
|
|
9180
|
+
// 'callback'` session. `pullHandles` (Phase 5 / D9) drains the
|
|
9181
|
+
// zero-pixel `FrameHandle[]` of a `frameSink: 'shm'` session — the
|
|
9182
|
+
// broker hands each handle to a `FrameRingReader` that opens the
|
|
9183
|
+
// named segment and reads the pixels back zero-copy. A session is
|
|
9184
|
+
// one mode or the other; the unmatched method returns an empty
|
|
9185
|
+
// array.
|
|
8799
9186
|
pullFrames: method(object({
|
|
8800
9187
|
sessionId: string(),
|
|
8801
9188
|
maxCount: number().default(1)
|
|
8802
9189
|
}), array(DecodedFrameSchema)),
|
|
9190
|
+
pullHandles: method(object({
|
|
9191
|
+
sessionId: string(),
|
|
9192
|
+
maxCount: number().default(1)
|
|
9193
|
+
}), array(FrameHandleSchema)),
|
|
9194
|
+
// ── Frame fetch (Phase 5 / D9 downstream access) ──────────────
|
|
9195
|
+
// Read the pixels a FrameHandle refers to from this node's shm ring.
|
|
9196
|
+
// Returns null when the slot was already recycled (latest-wins).
|
|
9197
|
+
getFrame: method(object({ handle: FrameHandleSchema }), DecodedFrameSchema.nullable()),
|
|
9198
|
+
// shm ring usage stats for a session.
|
|
9199
|
+
getShmStats: method(object({ sessionId: string() }), ShmRingStatsSchema.nullable()),
|
|
8803
9200
|
// ── Control ───────────────────────────────────────────────────
|
|
8804
9201
|
updateConfig: method(object({
|
|
8805
9202
|
sessionId: string(),
|
|
@@ -8944,6 +9341,8 @@ const webrtcSessionCapability = {
|
|
|
8944
9341
|
name: "webrtc-session",
|
|
8945
9342
|
scope: "device",
|
|
8946
9343
|
mode: "singleton",
|
|
9344
|
+
kind: "wrapper",
|
|
9345
|
+
defaultActive: true,
|
|
8947
9346
|
deviceTypes: [DeviceType.Camera],
|
|
8948
9347
|
methods: {
|
|
8949
9348
|
/**
|
|
@@ -9458,6 +9857,8 @@ const audioAnalysisCapability = {
|
|
|
9458
9857
|
name: "audio-analysis",
|
|
9459
9858
|
scope: "device",
|
|
9460
9859
|
mode: "singleton",
|
|
9860
|
+
kind: "wrapper",
|
|
9861
|
+
defaultActive: true,
|
|
9461
9862
|
deviceTypes: [DeviceType.Camera],
|
|
9462
9863
|
exposesDeviceSettings: true,
|
|
9463
9864
|
methods: {
|
|
@@ -9990,8 +10391,8 @@ const DevicePersistConfigPayloadSchema = object({
|
|
|
9990
10391
|
/**
|
|
9991
10392
|
* Return the addon ids that declared a wrapper provider for `capName`.
|
|
9992
10393
|
* Backs the device-bindings UI's wrapper-picker dropdown. Entries are
|
|
9993
|
-
* sourced from `CapabilityRegistry.wrapperProviders`, populated
|
|
9994
|
-
* `
|
|
10394
|
+
* sourced from `CapabilityRegistry.wrapperProviders`, populated when
|
|
10395
|
+
* the cap definition declares `kind: 'wrapper'`.
|
|
9995
10396
|
*/
|
|
9996
10397
|
listWrappersForCap: method(
|
|
9997
10398
|
object({ capName: string() }),
|
|
@@ -10696,6 +11097,8 @@ const detectionPipelineCapability = {
|
|
|
10696
11097
|
name: "detection-pipeline",
|
|
10697
11098
|
scope: "device",
|
|
10698
11099
|
mode: "singleton",
|
|
11100
|
+
kind: "wrapper",
|
|
11101
|
+
defaultActive: true,
|
|
10699
11102
|
deviceTypes: [DeviceType.Camera],
|
|
10700
11103
|
exposesDeviceSettings: true,
|
|
10701
11104
|
methods: {}
|
|
@@ -11086,6 +11489,18 @@ const PtzMoveCommandSchema = object({
|
|
|
11086
11489
|
zoom: number().optional(),
|
|
11087
11490
|
speed: number().optional()
|
|
11088
11491
|
});
|
|
11492
|
+
PtzPositionSchema.extend({ autofocus: boolean() });
|
|
11493
|
+
const PtzOptionsSchema = object({
|
|
11494
|
+
hasPan: boolean(),
|
|
11495
|
+
hasTilt: boolean(),
|
|
11496
|
+
hasZoom: boolean(),
|
|
11497
|
+
supportsPresets: boolean(),
|
|
11498
|
+
/** Max number of named presets the camera supports, when known. */
|
|
11499
|
+
maxPresets: number().optional(),
|
|
11500
|
+
/** Whether the camera exposes a controllable autofocus toggle
|
|
11501
|
+
* (boolean `hasX` per the getOptions availability convention). */
|
|
11502
|
+
hasAutofocus: boolean()
|
|
11503
|
+
});
|
|
11089
11504
|
({
|
|
11090
11505
|
deviceTypes: [DeviceType.Camera],
|
|
11091
11506
|
methods: {
|
|
@@ -11113,6 +11528,20 @@ const PtzMoveCommandSchema = object({
|
|
|
11113
11528
|
_void(),
|
|
11114
11529
|
{ kind: "mutation" }
|
|
11115
11530
|
),
|
|
11531
|
+
savePreset: method(
|
|
11532
|
+
object({ deviceId: number(), presetId: string(), name: string() }),
|
|
11533
|
+
_void(),
|
|
11534
|
+
{ kind: "mutation", auth: "admin" }
|
|
11535
|
+
),
|
|
11536
|
+
deletePreset: method(
|
|
11537
|
+
object({ deviceId: number(), presetId: string() }),
|
|
11538
|
+
_void(),
|
|
11539
|
+
{ kind: "mutation", auth: "admin" }
|
|
11540
|
+
),
|
|
11541
|
+
getOptions: method(
|
|
11542
|
+
object({ deviceId: number() }),
|
|
11543
|
+
PtzOptionsSchema
|
|
11544
|
+
),
|
|
11116
11545
|
goHome: method(
|
|
11117
11546
|
object({ deviceId: number() }),
|
|
11118
11547
|
_void(),
|
|
@@ -11127,6 +11556,13 @@ const PtzMoveCommandSchema = object({
|
|
|
11127
11556
|
getPosition: method(
|
|
11128
11557
|
object({ deviceId: number() }),
|
|
11129
11558
|
PtzPositionSchema
|
|
11559
|
+
),
|
|
11560
|
+
/** Toggle the camera's autofocus. Only meaningful when
|
|
11561
|
+
* `getOptions().hasAutofocus` is true. */
|
|
11562
|
+
setAutofocus: method(
|
|
11563
|
+
object({ deviceId: number(), enabled: boolean() }),
|
|
11564
|
+
_void(),
|
|
11565
|
+
{ kind: "mutation" }
|
|
11130
11566
|
)
|
|
11131
11567
|
}
|
|
11132
11568
|
});
|
|
@@ -12062,83 +12498,6 @@ const MeshStatusSchema = object({
|
|
|
12062
12498
|
// tabs driven by this cap.
|
|
12063
12499
|
}
|
|
12064
12500
|
});
|
|
12065
|
-
const MethodAccessSchema = _enum(["view", "create", "delete"]);
|
|
12066
|
-
const AllowedProviderSchema = union([literal("*"), array(string())]);
|
|
12067
|
-
const AllowedDevicesSchema = record(string(), union([literal("*"), array(string())]));
|
|
12068
|
-
const CapScopeSchema = _enum(["device", "system"]);
|
|
12069
|
-
const TokenScopeSchema = discriminatedUnion("type", [
|
|
12070
|
-
object({
|
|
12071
|
-
type: literal("category"),
|
|
12072
|
-
target: CapScopeSchema,
|
|
12073
|
-
access: array(MethodAccessSchema).min(1)
|
|
12074
|
-
}),
|
|
12075
|
-
object({
|
|
12076
|
-
type: literal("capability"),
|
|
12077
|
-
target: string(),
|
|
12078
|
-
access: array(MethodAccessSchema).min(1)
|
|
12079
|
-
}),
|
|
12080
|
-
object({
|
|
12081
|
-
type: literal("addon"),
|
|
12082
|
-
target: string(),
|
|
12083
|
-
access: array(MethodAccessSchema).min(1)
|
|
12084
|
-
}),
|
|
12085
|
-
object({
|
|
12086
|
-
type: literal("device"),
|
|
12087
|
-
/**
|
|
12088
|
-
* One or more deviceIds (serialised as strings for wire-format
|
|
12089
|
-
* consistency with the rest of the union). Matcher accepts if
|
|
12090
|
-
* `input.deviceId` ∈ `targets`. Array shape avoids the row-explosion
|
|
12091
|
-
* of one scope-per-device when granting access to a set of cameras.
|
|
12092
|
-
*/
|
|
12093
|
-
targets: array(string()).min(1),
|
|
12094
|
-
access: array(MethodAccessSchema).min(1)
|
|
12095
|
-
})
|
|
12096
|
-
]);
|
|
12097
|
-
object({
|
|
12098
|
-
id: string(),
|
|
12099
|
-
username: string(),
|
|
12100
|
-
passwordHash: string(),
|
|
12101
|
-
/**
|
|
12102
|
-
* Admin bypass. When true, the middleware skips the scope-access
|
|
12103
|
-
* check entirely. There is no other axis of privilege; the legacy
|
|
12104
|
-
* role enum collapsed onto this boolean in v2.
|
|
12105
|
-
*/
|
|
12106
|
-
isAdmin: boolean().default(false),
|
|
12107
|
-
allowedProviders: AllowedProviderSchema,
|
|
12108
|
-
allowedDevices: AllowedDevicesSchema,
|
|
12109
|
-
/**
|
|
12110
|
-
* Scopes granted to this user. Admins bypass; their `scopes` is
|
|
12111
|
-
* ignored. Non-admins without scopes are locked out of every
|
|
12112
|
-
* protected call.
|
|
12113
|
-
*/
|
|
12114
|
-
scopes: array(TokenScopeSchema).default([]),
|
|
12115
|
-
createdAt: number(),
|
|
12116
|
-
updatedAt: number()
|
|
12117
|
-
});
|
|
12118
|
-
object({
|
|
12119
|
-
id: string(),
|
|
12120
|
-
label: string(),
|
|
12121
|
-
isAdmin: boolean().default(false),
|
|
12122
|
-
allowedProviders: AllowedProviderSchema,
|
|
12123
|
-
allowedDevices: AllowedDevicesSchema,
|
|
12124
|
-
tokenHash: string(),
|
|
12125
|
-
tokenPrefix: string(),
|
|
12126
|
-
createdAt: number(),
|
|
12127
|
-
lastUsedAt: number().optional()
|
|
12128
|
-
});
|
|
12129
|
-
object({
|
|
12130
|
-
id: string(),
|
|
12131
|
-
userId: string(),
|
|
12132
|
-
name: string(),
|
|
12133
|
-
tokenHash: string(),
|
|
12134
|
-
tokenPrefix: string(),
|
|
12135
|
-
scopes: array(TokenScopeSchema),
|
|
12136
|
-
// SQLite/JSON storage round-trips undefined → null. Use `nullish` so the
|
|
12137
|
-
// schema accepts both `null` (read from disk) and `undefined` (in-memory).
|
|
12138
|
-
expiresAt: number().nullish(),
|
|
12139
|
-
lastUsedAt: number().nullish(),
|
|
12140
|
-
createdAt: number()
|
|
12141
|
-
});
|
|
12142
12501
|
const UserSummarySchema = object({
|
|
12143
12502
|
id: string(),
|
|
12144
12503
|
username: string(),
|
|
@@ -12211,6 +12570,16 @@ const CreateScopedTokenResultSchema = object({
|
|
|
12211
12570
|
token: string(),
|
|
12212
12571
|
record: ScopedTokenSummarySchema
|
|
12213
12572
|
});
|
|
12573
|
+
const OauthSessionSummarySchema = object({
|
|
12574
|
+
id: string(),
|
|
12575
|
+
userId: string(),
|
|
12576
|
+
username: string(),
|
|
12577
|
+
integrationId: string(),
|
|
12578
|
+
scopes: array(TokenScopeSchema),
|
|
12579
|
+
createdAt: number(),
|
|
12580
|
+
lastUsedAt: number(),
|
|
12581
|
+
revokedAt: number().nullable()
|
|
12582
|
+
});
|
|
12214
12583
|
const TotpSetupResultSchema = object({
|
|
12215
12584
|
secret: string(),
|
|
12216
12585
|
otpauthUrl: string()
|
|
@@ -12286,6 +12655,66 @@ const TotpStatusSchema = object({
|
|
|
12286
12655
|
object({ userId: string(), code: string() }),
|
|
12287
12656
|
object({ valid: boolean() }),
|
|
12288
12657
|
{ kind: "mutation", access: "view" }
|
|
12658
|
+
),
|
|
12659
|
+
// ── OAuth account-linking grant ────────────────────────────────
|
|
12660
|
+
//
|
|
12661
|
+
// Core's /oauth2/* endpoints delegate here. Tokens are sso-bridge
|
|
12662
|
+
// JWTs (kinds oauth-code / oauth-access / oauth-refresh) and ALWAYS
|
|
12663
|
+
// carry isAdmin:false — the operator login proves hub control; the
|
|
12664
|
+
// issued token is minimal (device scope only).
|
|
12665
|
+
oauthIssueCode: method(
|
|
12666
|
+
object({
|
|
12667
|
+
integrationId: string(),
|
|
12668
|
+
userId: string(),
|
|
12669
|
+
username: string(),
|
|
12670
|
+
scopes: array(TokenScopeSchema),
|
|
12671
|
+
redirectUri: string(),
|
|
12672
|
+
hubUrl: string()
|
|
12673
|
+
}),
|
|
12674
|
+
object({ code: string() }),
|
|
12675
|
+
{ kind: "mutation", access: "create" }
|
|
12676
|
+
),
|
|
12677
|
+
oauthExchangeCode: method(
|
|
12678
|
+
object({ code: string(), redirectUri: string() }),
|
|
12679
|
+
object({
|
|
12680
|
+
accessToken: string(),
|
|
12681
|
+
refreshToken: string(),
|
|
12682
|
+
expiresIn: number()
|
|
12683
|
+
}).nullable(),
|
|
12684
|
+
{ kind: "mutation", access: "view" }
|
|
12685
|
+
),
|
|
12686
|
+
oauthRefresh: method(
|
|
12687
|
+
object({ refreshToken: string() }),
|
|
12688
|
+
object({
|
|
12689
|
+
accessToken: string(),
|
|
12690
|
+
refreshToken: string(),
|
|
12691
|
+
expiresIn: number()
|
|
12692
|
+
}).nullable(),
|
|
12693
|
+
{ kind: "mutation", access: "view" }
|
|
12694
|
+
),
|
|
12695
|
+
oauthVerifyAccessToken: method(
|
|
12696
|
+
object({ token: string() }),
|
|
12697
|
+
object({
|
|
12698
|
+
userId: string(),
|
|
12699
|
+
username: string(),
|
|
12700
|
+
scopes: array(TokenScopeSchema)
|
|
12701
|
+
}).nullable(),
|
|
12702
|
+
{ access: "view" }
|
|
12703
|
+
),
|
|
12704
|
+
// ── OAuth linked-session management (Phase D) ──────────────────
|
|
12705
|
+
//
|
|
12706
|
+
// The admin UI lists active account-linking sessions and revokes
|
|
12707
|
+
// them; revocation makes the linked integration's tokens fail
|
|
12708
|
+
// verification immediately.
|
|
12709
|
+
listOauthSessions: method(
|
|
12710
|
+
_void(),
|
|
12711
|
+
array(OauthSessionSummarySchema),
|
|
12712
|
+
{ auth: "admin" }
|
|
12713
|
+
),
|
|
12714
|
+
revokeOauthSession: method(
|
|
12715
|
+
object({ id: string() }),
|
|
12716
|
+
object({ success: boolean() }),
|
|
12717
|
+
{ kind: "mutation", auth: "admin", access: "delete" }
|
|
12289
12718
|
)
|
|
12290
12719
|
}
|
|
12291
12720
|
});
|
|
@@ -12502,6 +12931,19 @@ const RenameNodeResultSchema = object({
|
|
|
12502
12931
|
record(string(), ClusterAddonStatusEntrySchema),
|
|
12503
12932
|
{ auth: "admin" }
|
|
12504
12933
|
),
|
|
12934
|
+
getCapUsageGraph: method(
|
|
12935
|
+
object({
|
|
12936
|
+
windowSeconds: number().int().positive().max(300).default(60)
|
|
12937
|
+
}),
|
|
12938
|
+
array(object({
|
|
12939
|
+
callerAddonId: string(),
|
|
12940
|
+
providerAddonId: string(),
|
|
12941
|
+
capName: string(),
|
|
12942
|
+
callsPerMin: number(),
|
|
12943
|
+
lastCallAtMs: number()
|
|
12944
|
+
})).readonly(),
|
|
12945
|
+
{ auth: "admin" }
|
|
12946
|
+
),
|
|
12505
12947
|
/**
|
|
12506
12948
|
* Direct per-node addon listing — calls `$agent.status` on the target
|
|
12507
12949
|
* node (or returns the hub registry for `nodeId === 'hub'`) and surfaces
|
|
@@ -13825,4 +14267,4 @@ exports.pipelineRunnerCapability = pipelineRunnerCapability;
|
|
|
13825
14267
|
exports.streamBrokerCapability = streamBrokerCapability;
|
|
13826
14268
|
exports.string = string;
|
|
13827
14269
|
exports.webrtcSessionCapability = webrtcSessionCapability;
|
|
13828
|
-
//# sourceMappingURL=index-
|
|
14270
|
+
//# sourceMappingURL=index-p-6GfKOg.js.map
|