@camstack/addon-export-alexa 1.2.134 → 1.2.135
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/export-alexa.addon.js +81 -480
- package/dist/export-alexa.addon.mjs +81 -480
- package/lambda-template/README.md +49 -21
- package/lambda-template/aws.js +32 -16
- package/lambda-template/broker.js +3 -3
- package/lambda-template/debug-trace.js +100 -0
- package/lambda-template/index.js +19 -8
- package/lambda-template/secrets.js +24 -21
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as crypto$1 from "node:crypto";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
|
-
//#region ../types/dist/event-category-
|
|
3
|
+
//#region ../types/dist/event-category-B_0XEcLF.mjs
|
|
4
4
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
5
5
|
EventCategory["SystemBoot"] = "system.boot";
|
|
6
6
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -501,15 +501,6 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
501
501
|
EventCategory["AgentWsDisconnected"] = "agent.ws.disconnected";
|
|
502
502
|
EventCategory["AgentBackupActivated"] = "agent.backup.activated";
|
|
503
503
|
EventCategory["OrchestrationSettingsUpdated"] = "orchestration.settings-updated";
|
|
504
|
-
/**
|
|
505
|
-
* Per-agent hwaccel preference changed (user override set, cleared, or
|
|
506
|
-
* re-probed). Observability event — decoders pull the current pref at
|
|
507
|
-
* `createSession`, so running sessions keep their current backend until
|
|
508
|
-
* they rotate naturally (camera add/remove, stream restart). Future
|
|
509
|
-
* work can wire a listener in stream-broker that force-rotates live
|
|
510
|
-
* sessions; for now this event powers logs + admin-UI toast feedback.
|
|
511
|
-
*/
|
|
512
|
-
EventCategory["PipelineAgentHwaccelChanged"] = "pipeline.agent-hwaccel-changed";
|
|
513
504
|
EventCategory["MotionAnalysis"] = "detection.motion-analysis";
|
|
514
505
|
/** All raw motion zones from CCL before minArea filter — for UI debug overlay. */
|
|
515
506
|
EventCategory["MotionZonesRaw"] = "detection.motion-zones-raw";
|
|
@@ -5380,7 +5371,7 @@ var ZodIssueCode = {
|
|
|
5380
5371
|
var ZodFirstPartyTypeKind;
|
|
5381
5372
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5382
5373
|
//#endregion
|
|
5383
|
-
//#region ../types/dist/sleep-
|
|
5374
|
+
//#region ../types/dist/sleep-BNeXenvr.mjs
|
|
5384
5375
|
/**
|
|
5385
5376
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5386
5377
|
* window to float samples (D455).
|
|
@@ -6746,32 +6737,12 @@ object({
|
|
|
6746
6737
|
audioCodec: string().optional(),
|
|
6747
6738
|
metadata: record(string(), unknown()).readonly().optional()
|
|
6748
6739
|
});
|
|
6749
|
-
var EncodedPacketSchema = object({
|
|
6750
|
-
type: _enum(["video", "audio"]),
|
|
6751
|
-
data: _instanceof(Uint8Array),
|
|
6752
|
-
pts: number(),
|
|
6753
|
-
dts: number(),
|
|
6754
|
-
keyframe: boolean(),
|
|
6755
|
-
codec: string()
|
|
6756
|
-
});
|
|
6757
|
-
var DecodedFrameSchema = object({
|
|
6758
|
-
data: _instanceof(Uint8Array),
|
|
6759
|
-
width: number(),
|
|
6760
|
-
height: number(),
|
|
6761
|
-
format: _enum([
|
|
6762
|
-
"jpeg",
|
|
6763
|
-
"rgb",
|
|
6764
|
-
"bgr",
|
|
6765
|
-
"yuv420",
|
|
6766
|
-
"gray"
|
|
6767
|
-
]),
|
|
6768
|
-
timestamp: number()
|
|
6769
|
-
});
|
|
6770
6740
|
/**
|
|
6771
6741
|
* Wire schema for `FrameHandle` — a zero-pixel, serialisable reference to a
|
|
6772
6742
|
* frame in a shared-memory ring (Phase 5 / D9). Mirrors the `FrameHandle` TS
|
|
6773
|
-
* interface in `interfaces/frame-handle.ts` field-for-field so a
|
|
6774
|
-
*
|
|
6743
|
+
* interface in `interfaces/frame-handle.ts` field-for-field so a cap method
|
|
6744
|
+
* (the runner's native-crop and pipeline-executor inputs) can carry handles
|
|
6745
|
+
* over tRPC / Moleculer.
|
|
6775
6746
|
*
|
|
6776
6747
|
* The `satisfies` assertion below pins this schema to the interface: if a
|
|
6777
6748
|
* field is added to / removed from `FrameHandle` without a matching schema
|
|
@@ -6797,50 +6768,6 @@ var FrameHandleSchema = object({
|
|
|
6797
6768
|
slotCount: number().int().positive()
|
|
6798
6769
|
});
|
|
6799
6770
|
/**
|
|
6800
|
-
* Pixel format a frame-handle subscriber can request from the broker
|
|
6801
|
-
* (Phase 5 / D9). The packed, raster subset of `FrameFormat` — the formats a
|
|
6802
|
-
* `frameSink: 'shm'` decoder session can write into a `FrameRing` slot.
|
|
6803
|
-
* `jpeg` is excluded: a variable-length stream is not a fixed-stride ring
|
|
6804
|
-
* payload, and no decoded-frame consumer requests it over the shm plane.
|
|
6805
|
-
*/
|
|
6806
|
-
var FrameHandleFormatSchema = _enum([
|
|
6807
|
-
"rgb",
|
|
6808
|
-
"bgr",
|
|
6809
|
-
"yuv420",
|
|
6810
|
-
"gray"
|
|
6811
|
-
]);
|
|
6812
|
-
/**
|
|
6813
|
-
* Input for `stream-broker.subscribeFrames` (Phase 5 / D9). A consumer asks the
|
|
6814
|
-
* broker for a `FrameHandle` stream of one `format`; the broker maintains one
|
|
6815
|
-
* shared-memory ring per `(brokerId, format)` actually requested, so a `gray`
|
|
6816
|
-
* subscriber (motion) and an `rgb` subscriber (detection) each read the format
|
|
6817
|
-
* they asked for with no broker-side conversion.
|
|
6818
|
-
*/
|
|
6819
|
-
var SubscribeFramesInputSchema = object({
|
|
6820
|
-
brokerId: string(),
|
|
6821
|
-
format: FrameHandleFormatSchema,
|
|
6822
|
-
/**
|
|
6823
|
-
* Optional reader-side cadence hint in frames per second. The broker does
|
|
6824
|
-
* NOT throttle — latest-wins ring reads drop frames implicitly for a slow
|
|
6825
|
-
* consumer. The value is echoed back in `SubscribeFramesResult.maxFps` so
|
|
6826
|
-
* the consumer can pace its own `pullFrameHandles` polling.
|
|
6827
|
-
*/
|
|
6828
|
-
maxFps: number().positive().optional(),
|
|
6829
|
-
/** Short caller-identity tag (`motion`, `detection`, …) for diagnostics. */
|
|
6830
|
-
tag: string().optional()
|
|
6831
|
-
});
|
|
6832
|
-
/**
|
|
6833
|
-
* Result of `stream-broker.subscribeFrames`. The consumer then polls
|
|
6834
|
-
* `pullFrameHandles({ subscriptionId, maxCount })` and feeds each returned
|
|
6835
|
-
* `FrameHandle` to a `FrameRingReader`.
|
|
6836
|
-
*/
|
|
6837
|
-
var SubscribeFramesResultSchema = object({
|
|
6838
|
-
/** Opaque id the consumer passes to `pullFrameHandles` / `unsubscribeFrames`. */
|
|
6839
|
-
subscriptionId: string(),
|
|
6840
|
-
/** Reader-side cadence hint (frames/s) — echoes `SubscribeFramesInput.maxFps`. */
|
|
6841
|
-
maxFps: number().nonnegative()
|
|
6842
|
-
});
|
|
6843
|
-
/**
|
|
6844
6771
|
* Wire schema for a decoded audio chunk (Phase 5 / D9). Mirrors the
|
|
6845
6772
|
* `DecodedAudioChunk` TS interface in `interfaces/stream-broker.ts`: PCM
|
|
6846
6773
|
* sample bytes plus the track parameters a consumer needs to interpret them.
|
|
@@ -6848,8 +6775,8 @@ var SubscribeFramesResultSchema = object({
|
|
|
6848
6775
|
* Audio chunks are tiny (a ~500ms AudioCodecSession window is a few KB of
|
|
6849
6776
|
* Float32 PCM), so unlike video frames they ship their bytes INLINE over
|
|
6850
6777
|
* tRPC / Moleculer — no shared-memory plane. `data` is typed `Uint8Array`
|
|
6851
|
-
* (the wire-serialisable supertype of `Buffer`)
|
|
6852
|
-
*
|
|
6778
|
+
* (the wire-serialisable supertype of `Buffer`); a `Buffer` is assignable to
|
|
6779
|
+
* it.
|
|
6853
6780
|
*/
|
|
6854
6781
|
var AudioChunkFormatSchema = _enum(AUDIO_CHUNK_FORMATS);
|
|
6855
6782
|
var DecodedAudioChunkSchema = object({
|
|
@@ -6867,11 +6794,10 @@ var DecodedAudioChunkSchema = object({
|
|
|
6867
6794
|
format: AudioChunkFormatSchema.optional()
|
|
6868
6795
|
});
|
|
6869
6796
|
/**
|
|
6870
|
-
* Input for `stream-broker.subscribeAudioChunks` (Phase 5 / D9).
|
|
6871
|
-
*
|
|
6872
|
-
*
|
|
6873
|
-
*
|
|
6874
|
-
* `pullAudioChunks`.
|
|
6797
|
+
* Input for `stream-broker.subscribeAudioChunks` (Phase 5 / D9). Audio ships
|
|
6798
|
+
* its bytes inline: a consumer asks the broker for the decoded audio-chunk
|
|
6799
|
+
* stream of one broker; the broker keeps a per-subscription bounded FIFO queue
|
|
6800
|
+
* the consumer drains via `pullAudioChunks`.
|
|
6875
6801
|
*/
|
|
6876
6802
|
var SubscribeAudioChunksInputSchema = object({
|
|
6877
6803
|
brokerId: string(),
|
|
@@ -6902,9 +6828,7 @@ var BrokerStatsSchema = object({
|
|
|
6902
6828
|
"stopped"
|
|
6903
6829
|
]),
|
|
6904
6830
|
inputFps: number(),
|
|
6905
|
-
decodeFps: number(),
|
|
6906
6831
|
encodedSubscribers: number(),
|
|
6907
|
-
decodedSubscribers: number(),
|
|
6908
6832
|
uptimeMs: number(),
|
|
6909
6833
|
bitrateKbps: number(),
|
|
6910
6834
|
idrIntervalMs: number(),
|
|
@@ -6917,14 +6841,6 @@ var BrokerStatsSchema = object({
|
|
|
6917
6841
|
preBufferMs: number(),
|
|
6918
6842
|
preBufferPackets: number(),
|
|
6919
6843
|
/**
|
|
6920
|
-
* Moleculer node id of the decoder provider currently servicing this
|
|
6921
|
-
* stream's decoded subscribers. `null` until the deferred decoder is
|
|
6922
|
-
* created (no decoded clients yet, or codec not detected). Surfaces the
|
|
6923
|
-
* runtime decoder placement so the UI can show "Decoder: <agent>" without
|
|
6924
|
-
* a separate cap call per broker.
|
|
6925
|
-
*/
|
|
6926
|
-
decoderNodeId: string().nullable(),
|
|
6927
|
-
/**
|
|
6928
6844
|
* Detected audio track parameters from the RTSP DESCRIBE / SDP. `null`
|
|
6929
6845
|
* when the stream has no audio track or the broker is in cold start.
|
|
6930
6846
|
* `supported = false` means the codec was detected but the local
|
|
@@ -10447,70 +10363,6 @@ var StorageLocationDeclarationSchema = object({
|
|
|
10447
10363
|
"backup"
|
|
10448
10364
|
]).optional()
|
|
10449
10365
|
});
|
|
10450
|
-
var DecoderStatsSchema = object({
|
|
10451
|
-
inputFps: number(),
|
|
10452
|
-
outputFps: number(),
|
|
10453
|
-
avgDecodeTimeMs: number(),
|
|
10454
|
-
droppedFrames: number(),
|
|
10455
|
-
/**
|
|
10456
|
-
* Pull-mode adaptive-fps telemetry (optional — only pull sessions run the
|
|
10457
|
-
* lag-driven controller; push sessions omit these). `lagMs` is the EWMA of
|
|
10458
|
-
* the decoder's real-time drift (rising = falling behind live); `adaptiveFps`
|
|
10459
|
-
* is the current lag-throttled emit rate (≤ `effectiveFps` ceiling).
|
|
10460
|
-
*/
|
|
10461
|
-
lagMs: number().optional(),
|
|
10462
|
-
effectiveFps: number().optional(),
|
|
10463
|
-
adaptiveFps: number().optional()
|
|
10464
|
-
});
|
|
10465
|
-
var DecoderSessionConfigSchema = object({
|
|
10466
|
-
codec: string(),
|
|
10467
|
-
maxFps: number().default(0),
|
|
10468
|
-
outputFormat: _enum([
|
|
10469
|
-
"jpeg",
|
|
10470
|
-
"rgb",
|
|
10471
|
-
"bgr",
|
|
10472
|
-
"yuv420",
|
|
10473
|
-
"gray"
|
|
10474
|
-
]).default("jpeg"),
|
|
10475
|
-
scale: number().default(1),
|
|
10476
|
-
width: number().optional(),
|
|
10477
|
-
height: number().optional(),
|
|
10478
|
-
/**
|
|
10479
|
-
* Identifier of the camera this decoder session serves. Optional
|
|
10480
|
-
* because the cap is generic (any caller could request decode), but
|
|
10481
|
-
* stream-broker passes it so decoder logs include `deviceId` for
|
|
10482
|
-
* per-camera filtering when diagnosing failures (e.g. node-av
|
|
10483
|
-
* sendPacket errors on a single hung camera).
|
|
10484
|
-
*/
|
|
10485
|
-
deviceId: number().int().nonnegative().optional(),
|
|
10486
|
-
/**
|
|
10487
|
-
* Free-form tag for log scoping. Stream-broker uses
|
|
10488
|
-
* `broker:<deviceId>/<profile>`. Decoder session logger surfaces it
|
|
10489
|
-
* on every line so `grep tag=broker:5/high` filters one camera
|
|
10490
|
-
* profile cleanly.
|
|
10491
|
-
*/
|
|
10492
|
-
tag: string().optional(),
|
|
10493
|
-
/**
|
|
10494
|
-
* Where the session delivers decoded frames (Phase 5 / D9):
|
|
10495
|
-
*
|
|
10496
|
-
* - `'callback'` (default) — the legacy pixel path: decoded frames are
|
|
10497
|
-
* buffered as `DecodedFrame`s and drained via `pullFrames`.
|
|
10498
|
-
* - `'shm'` — the shared-memory frame plane: decoded frames are written
|
|
10499
|
-
* into an OS shared-memory ring and drained as zero-pixel
|
|
10500
|
-
* `FrameHandle`s via `pullHandles`. A session is one mode or the
|
|
10501
|
-
* other — `pullFrames` returns nothing for an `'shm'` session and
|
|
10502
|
-
* `pullHandles` returns nothing for a `'callback'` session.
|
|
10503
|
-
*/
|
|
10504
|
-
frameSink: _enum(["callback", "shm"]).default("callback"),
|
|
10505
|
-
/**
|
|
10506
|
-
* Per-camera decoder DEBUG facility. When `true`, a pull-mode session emits
|
|
10507
|
-
* a throttled (~1Hz) structured `decoder debug` line (effective/adaptive fps,
|
|
10508
|
-
* real-time lag, dropped-frame delta, avg decode time, hwaccel). Mirrors the
|
|
10509
|
-
* stream-broker's `streamingDebug` gate — off by default so production logs
|
|
10510
|
-
* stay quiet and the emit path pays zero per-frame cost when disabled.
|
|
10511
|
-
*/
|
|
10512
|
-
debug: boolean().optional()
|
|
10513
|
-
});
|
|
10514
10366
|
/**
|
|
10515
10367
|
* Per-component log CHANNELS — the gate a hot path consults, and the registry
|
|
10516
10368
|
* an addon declares its channels in.
|
|
@@ -12771,13 +12623,6 @@ var BrokerRtspClientSchema = object({
|
|
|
12771
12623
|
lastRtpAt: number(),
|
|
12772
12624
|
bytesSent: number()
|
|
12773
12625
|
});
|
|
12774
|
-
var BrokerDecodedClientSchema = object({
|
|
12775
|
-
tag: string(),
|
|
12776
|
-
subscribedAt: number(),
|
|
12777
|
-
maxFps: number(),
|
|
12778
|
-
framesDelivered: number(),
|
|
12779
|
-
framesDropped: number()
|
|
12780
|
-
});
|
|
12781
12626
|
var BrokerAudioClientSchema = object({
|
|
12782
12627
|
tag: string(),
|
|
12783
12628
|
subscribedAt: number(),
|
|
@@ -12869,7 +12714,6 @@ var BrokerEncodedClientSchema = object({
|
|
|
12869
12714
|
});
|
|
12870
12715
|
var BrokerClientsSchema = object({
|
|
12871
12716
|
rtsp: array(BrokerRtspClientSchema).readonly(),
|
|
12872
|
-
decoded: array(BrokerDecodedClientSchema).readonly(),
|
|
12873
12717
|
audio: array(BrokerAudioClientSchema).readonly(),
|
|
12874
12718
|
encoded: array(BrokerEncodedClientSchema).readonly(),
|
|
12875
12719
|
pipeClients: number(),
|
|
@@ -13238,11 +13082,7 @@ method(object({
|
|
|
13238
13082
|
auth: "admin"
|
|
13239
13083
|
}), method(object({ brokerId: string() }), BrokerClientsSchema), method(object({
|
|
13240
13084
|
brokerId: string(),
|
|
13241
|
-
channel: _enum([
|
|
13242
|
-
"rtsp",
|
|
13243
|
-
"decoded",
|
|
13244
|
-
"audio"
|
|
13245
|
-
]),
|
|
13085
|
+
channel: _enum(["rtsp", "audio"]),
|
|
13246
13086
|
handle: string()
|
|
13247
13087
|
}), object({ killed: boolean() }), {
|
|
13248
13088
|
kind: "mutation",
|
|
@@ -13277,10 +13117,7 @@ method(object({
|
|
|
13277
13117
|
}), method(SubscribeAudioChunksInputSchema, SubscribeAudioChunksResultSchema, { kind: "mutation" }), method(object({
|
|
13278
13118
|
subscriptionId: string(),
|
|
13279
13119
|
maxCount: number().int().positive().default(8)
|
|
13280
|
-
}), array(DecodedAudioChunkSchema).readonly()), method(object({ subscriptionId: string() }), object({ released: boolean() }), { kind: "mutation" }), method(
|
|
13281
|
-
subscriptionId: string(),
|
|
13282
|
-
maxCount: number().int().positive().default(4)
|
|
13283
|
-
}), array(FrameHandleSchema).readonly()), method(object({ subscriptionId: string() }), object({ released: boolean() }), { kind: "mutation" }), method(object({
|
|
13120
|
+
}), array(DecodedAudioChunkSchema).readonly()), method(object({ subscriptionId: string() }), object({ released: boolean() }), { kind: "mutation" }), method(object({
|
|
13284
13121
|
brokerId: string(),
|
|
13285
13122
|
seconds: number().min(0).max(30)
|
|
13286
13123
|
}), _void(), {
|
|
@@ -14437,54 +14274,12 @@ id: union([string(), number()]) }), {
|
|
|
14437
14274
|
kind: "mutation",
|
|
14438
14275
|
auth: "admin"
|
|
14439
14276
|
});
|
|
14440
|
-
|
|
14441
|
-
* shm ring usage stats for a `frameSink: 'shm'` decoder session —
|
|
14442
|
-
* exposed via `decoder.getShmStats` so downstream consumers can
|
|
14443
|
-
* observe ring pressure (slot count, byte budget, hit/miss ratio).
|
|
14444
|
-
*/
|
|
14445
|
-
var ShmRingStatsSchema = object({
|
|
14446
|
-
sessionId: string(),
|
|
14447
|
-
slotCount: number().int(),
|
|
14448
|
-
slotByteLength: number().int(),
|
|
14449
|
-
segmentBytes: number().int(),
|
|
14450
|
-
budgetMb: number().int(),
|
|
14451
|
-
framesWritten: number().int(),
|
|
14452
|
-
getFrameHits: number().int(),
|
|
14453
|
-
getFrameMisses: number().int()
|
|
14454
|
-
});
|
|
14455
|
-
method(object({ codec: string() }), boolean()), method(_void(), object({
|
|
14277
|
+
method(_void(), object({
|
|
14456
14278
|
id: string(),
|
|
14457
14279
|
name: string(),
|
|
14458
|
-
isPullMode: boolean().optional(),
|
|
14459
|
-
priority: number().optional(),
|
|
14460
14280
|
hwaccel: string().optional(),
|
|
14461
14281
|
probedBestHwaccel: string().optional()
|
|
14462
|
-
})), method(
|
|
14463
|
-
sessionId: string(),
|
|
14464
|
-
nodeId: string()
|
|
14465
|
-
})), method(object({ sessionId: string() }), _void()), method(object({
|
|
14466
|
-
sessionId: string(),
|
|
14467
|
-
packet: EncodedPacketSchema
|
|
14468
|
-
}), _void()), method(object({
|
|
14469
|
-
sessionId: string(),
|
|
14470
|
-
url: string()
|
|
14471
|
-
}), _void()), method(object({
|
|
14472
|
-
sessionId: string(),
|
|
14473
|
-
maxCount: number().default(1),
|
|
14474
|
-
waitMs: number().optional()
|
|
14475
|
-
}), array(DecodedFrameSchema)), method(object({
|
|
14476
|
-
sessionId: string(),
|
|
14477
|
-
maxCount: number().default(1),
|
|
14478
|
-
waitMs: number().optional()
|
|
14479
|
-
}), array(FrameHandleSchema)), method(object({ handle: FrameHandleSchema }), DecodedFrameSchema.nullable()), method(object({ sessionId: string() }), ShmRingStatsSchema.nullable()), method(object({
|
|
14480
|
-
sessionId: string(),
|
|
14481
|
-
config: DecoderSessionConfigSchema.partial()
|
|
14482
|
-
}), _void()), method(object({ sessionId: string() }), DecoderStatsSchema), method(_void(), array(object({
|
|
14483
|
-
sessionId: string(),
|
|
14484
|
-
codec: string(),
|
|
14485
|
-
outputFormat: string(),
|
|
14486
|
-
createdAtMs: number()
|
|
14487
|
-
})).readonly()), method(_void(), object({ backend: string() }), {
|
|
14282
|
+
})), method(_void(), object({ backend: string() }), {
|
|
14488
14283
|
kind: "mutation",
|
|
14489
14284
|
auth: "admin"
|
|
14490
14285
|
});
|
|
@@ -21545,8 +21340,8 @@ Object.freeze(Object.fromEntries([{
|
|
|
21545
21340
|
var CLUSTER_STEP_SETTING_FIELDS = [{
|
|
21546
21341
|
stepId: "face-embedding",
|
|
21547
21342
|
key: "minLandmarkFaceSize",
|
|
21548
|
-
label: "Min face size
|
|
21549
|
-
description: "
|
|
21343
|
+
label: "Min face size to embed (detection-frame px)",
|
|
21344
|
+
description: "Faces smaller than this in the small frame the detector sees are not embedded, so they can never be recognised. Below it the face cannot be aligned reliably and a bad embedding matches everyone. Same value on every node. 0 = no limit.",
|
|
21550
21345
|
type: "slider",
|
|
21551
21346
|
min: 0,
|
|
21552
21347
|
max: 64,
|
|
@@ -23598,21 +23393,6 @@ var PipelineDefaultStepSchema = lazy(() => object({
|
|
|
23598
23393
|
group: string().optional(),
|
|
23599
23394
|
settings: record(string(), unknown()).optional()
|
|
23600
23395
|
}));
|
|
23601
|
-
var PipelineTemplateStepSchema = lazy(() => object({
|
|
23602
|
-
addonId: string(),
|
|
23603
|
-
enabled: boolean(),
|
|
23604
|
-
modelId: string(),
|
|
23605
|
-
children: array(PipelineTemplateStepSchema).readonly(),
|
|
23606
|
-
settings: record(string(), unknown()).optional()
|
|
23607
|
-
}));
|
|
23608
|
-
var PipelineTemplateSchema$1 = object({
|
|
23609
|
-
id: string(),
|
|
23610
|
-
name: string(),
|
|
23611
|
-
createdAt: string(),
|
|
23612
|
-
updatedAt: string(),
|
|
23613
|
-
engine: PipelineEngineChoiceSchema,
|
|
23614
|
-
steps: array(PipelineTemplateStepSchema).readonly()
|
|
23615
|
-
});
|
|
23616
23396
|
var PipelineModelOptionSchema = object({
|
|
23617
23397
|
id: string(),
|
|
23618
23398
|
name: string(),
|
|
@@ -23824,15 +23604,7 @@ method(_void(), array(PipelineEngineChoiceSchema)), method(_void(), PipelineEngi
|
|
|
23824
23604
|
}), method(_void(), PipelineSchemaSchema), method(_void(), array(PipelineDefaultStepSchema).readonly().nullable()), method(_void(), PipelineConfigBridge), method(_void(), ConfigUISchemaBridge), method(object({
|
|
23825
23605
|
steps: array(PipelineStepInputSchema),
|
|
23826
23606
|
deviceKey: string().optional()
|
|
23827
|
-
}), PipelineValidationResultSchema), method(_void(),
|
|
23828
|
-
name: string(),
|
|
23829
|
-
steps: array(PipelineTemplateStepSchema).readonly(),
|
|
23830
|
-
engine: PipelineEngineChoiceSchema
|
|
23831
|
-
}), PipelineTemplateSchema$1, { kind: "mutation" }), method(object({
|
|
23832
|
-
id: string(),
|
|
23833
|
-
name: string().optional(),
|
|
23834
|
-
steps: array(PipelineTemplateStepSchema).readonly().optional()
|
|
23835
|
-
}), PipelineTemplateSchema$1, { kind: "mutation" }), method(object({ id: string() }), _void(), { kind: "mutation" }), method(_void(), InferenceCapabilitiesBridge), method(object({ addonId: string() }), ModelAvailabilityListBridge), method(object({
|
|
23607
|
+
}), PipelineValidationResultSchema), method(_void(), InferenceCapabilitiesBridge), method(object({ addonId: string() }), ModelAvailabilityListBridge), method(object({
|
|
23836
23608
|
addonId: string(),
|
|
23837
23609
|
modelId: string(),
|
|
23838
23610
|
format: ModelFormatSchema$2
|
|
@@ -25242,14 +25014,15 @@ var RunnerLocalLoadSchema = object({
|
|
|
25242
25014
|
* Per-inference-device live load (multi-device C4). One entry per deviceKey
|
|
25243
25015
|
* this runner currently has attached cameras on, so the orchestrator's second
|
|
25244
25016
|
* `balance()` pass (over a node's devices) weights on real per-pool session
|
|
25245
|
-
* counts. Empty on single-device / pre-multi-device runners.
|
|
25246
|
-
* per
|
|
25017
|
+
* counts. Empty on single-device / pre-multi-device runners. There is no
|
|
25018
|
+
* per-device queue depth: the inference pool's backlog has no accessor, and
|
|
25019
|
+
* a field that always read 0 was removed rather than shown as a measurement
|
|
25020
|
+
* (D762).
|
|
25247
25021
|
*/
|
|
25248
25022
|
devices: array(object({
|
|
25249
25023
|
deviceKey: string(),
|
|
25250
25024
|
backend: string(),
|
|
25251
|
-
attachedCameras: number()
|
|
25252
|
-
queueDepthTotal: number()
|
|
25025
|
+
attachedCameras: number()
|
|
25253
25026
|
})).default([]),
|
|
25254
25027
|
/** Hardware capability flags reported by this node. */
|
|
25255
25028
|
hardware: object({
|
|
@@ -25463,14 +25236,6 @@ var CameraPipelineConfigSchema = object({
|
|
|
25463
25236
|
settings: record(string(), unknown()).readonly().optional()
|
|
25464
25237
|
}).nullable().optional()
|
|
25465
25238
|
});
|
|
25466
|
-
var PipelineTemplateSchema = object({
|
|
25467
|
-
id: string(),
|
|
25468
|
-
name: string(),
|
|
25469
|
-
description: string().optional(),
|
|
25470
|
-
config: CameraPipelineConfigSchema,
|
|
25471
|
-
createdAt: string(),
|
|
25472
|
-
updatedAt: string()
|
|
25473
|
-
});
|
|
25474
25239
|
var DeviceStepConfigSchema = object({
|
|
25475
25240
|
modelId: string().optional(),
|
|
25476
25241
|
settings: record(string(), unknown()).optional(),
|
|
@@ -25580,7 +25345,10 @@ var PipelineAssignmentSchema = object({
|
|
|
25580
25345
|
});
|
|
25581
25346
|
/**
|
|
25582
25347
|
* Per-agent load summary surfaced to the load balancer + dashboards.
|
|
25583
|
-
* Aggregated from each runner's `getLocalLoad` cap call.
|
|
25348
|
+
* Aggregated from each runner's `getLocalLoad` cap call. In the
|
|
25349
|
+
* `getAgentLoad` report, a single-device node's default-pool sessions (no
|
|
25350
|
+
* `deviceKey`) are credited to its one eligible device in `load.devices` —
|
|
25351
|
+
* the default pool IS that device (D745); the balancer's census stays raw.
|
|
25584
25352
|
*/
|
|
25585
25353
|
var AgentLoadSummarySchema = object({
|
|
25586
25354
|
nodeId: string(),
|
|
@@ -25669,26 +25437,27 @@ var CameraBrokerStatusSchema = object({
|
|
|
25669
25437
|
width: number(),
|
|
25670
25438
|
height: number(),
|
|
25671
25439
|
subscribers: number(),
|
|
25672
|
-
|
|
25673
|
-
|
|
25440
|
+
/**
|
|
25441
|
+
* Encoded packets/s the broker receives from the camera. null when the
|
|
25442
|
+
* broker's stats read failed — unknown, never 0 (a 0 here reads as a stall).
|
|
25443
|
+
* There is no output rate: decoding runs in the session decode workers, not
|
|
25444
|
+
* in the broker, so the broker's own decoded-frame rate is 0 on every live
|
|
25445
|
+
* camera and is not served (D758).
|
|
25446
|
+
*/
|
|
25447
|
+
inFps: number().nullable()
|
|
25674
25448
|
})).readonly(),
|
|
25675
25449
|
webrtcSessions: number(),
|
|
25676
25450
|
rtspRestream: boolean()
|
|
25677
25451
|
});
|
|
25678
|
-
/**
|
|
25679
|
-
|
|
25680
|
-
|
|
25681
|
-
|
|
25682
|
-
|
|
25683
|
-
|
|
25684
|
-
|
|
25685
|
-
|
|
25686
|
-
var CameraDecoderStatusSchema = object({
|
|
25687
|
-
nodeId: string(),
|
|
25688
|
-
formats: array(string()).readonly(),
|
|
25689
|
-
sessionCount: number(),
|
|
25690
|
-
shm: CameraDecoderShmSchema
|
|
25691
|
-
});
|
|
25452
|
+
/**
|
|
25453
|
+
* Decoder block — WHERE decode runs (co-located with the detection node by
|
|
25454
|
+
* construction); null when the camera has no detection node. It carries no
|
|
25455
|
+
* frame counter: the shared-memory plane whose counters it used to serve is
|
|
25456
|
+
* gone, and those fields read 0 forever. Whether frames actually flow is read
|
|
25457
|
+
* from `detection.actualFps` (frames delivered to and processed by the
|
|
25458
|
+
* detector), never from a counter nothing feeds.
|
|
25459
|
+
*/
|
|
25460
|
+
var CameraDecoderStatusSchema = object({ nodeId: string() });
|
|
25692
25461
|
/** Motion block — null when motion detection is not active for this device. */
|
|
25693
25462
|
var CameraMotionStatusSchema = object({
|
|
25694
25463
|
enabled: boolean(),
|
|
@@ -26141,25 +25910,7 @@ method(object({
|
|
|
26141
25910
|
}), method(_void(), DiskReconcileJobSchema, {
|
|
26142
25911
|
kind: "mutation",
|
|
26143
25912
|
auth: "admin"
|
|
26144
|
-
}), method(_void(), DiskReconcileJobSchema, { auth: "admin" })
|
|
26145
|
-
name: string(),
|
|
26146
|
-
description: string().optional(),
|
|
26147
|
-
config: CameraPipelineConfigSchema
|
|
26148
|
-
}), PipelineTemplateSchema, {
|
|
26149
|
-
kind: "mutation",
|
|
26150
|
-
auth: "admin"
|
|
26151
|
-
}), method(object({
|
|
26152
|
-
id: string(),
|
|
26153
|
-
name: string().optional(),
|
|
26154
|
-
description: string().optional(),
|
|
26155
|
-
config: CameraPipelineConfigSchema.optional()
|
|
26156
|
-
}), PipelineTemplateSchema, {
|
|
26157
|
-
kind: "mutation",
|
|
26158
|
-
auth: "admin"
|
|
26159
|
-
}), method(object({ id: string() }), object({ success: literal(true) }), {
|
|
26160
|
-
kind: "mutation",
|
|
26161
|
-
auth: "admin"
|
|
26162
|
-
});
|
|
25913
|
+
}), method(_void(), DiskReconcileJobSchema, { auth: "admin" });
|
|
26163
25914
|
/**
|
|
26164
25915
|
* Cap → event-kind mapping for the SENSOR / CONTROL cap families — the table
|
|
26165
25916
|
* `pipeline-analytics.listEventKinds` uses to turn a linked device's bound
|
|
@@ -28379,8 +28130,6 @@ var WebrtcStreamChoiceSchema = object({
|
|
|
28379
28130
|
]).nullable(),
|
|
28380
28131
|
/** Input FPS from the camera (null for adaptive). */
|
|
28381
28132
|
inputFps: number().nullable(),
|
|
28382
|
-
/** Decoded FPS (null for adaptive). */
|
|
28383
|
-
decodeFps: number().nullable(),
|
|
28384
28133
|
/** Bitrate in kbps (null for adaptive). */
|
|
28385
28134
|
bitrateKbps: number().nullable()
|
|
28386
28135
|
});
|
|
@@ -38515,90 +38264,18 @@ Object.freeze({
|
|
|
38515
38264
|
addonId: null,
|
|
38516
38265
|
access: "create"
|
|
38517
38266
|
},
|
|
38518
|
-
"decoder.createSession": {
|
|
38519
|
-
capName: "decoder",
|
|
38520
|
-
capScope: "system",
|
|
38521
|
-
addonId: null,
|
|
38522
|
-
access: "view"
|
|
38523
|
-
},
|
|
38524
|
-
"decoder.destroySession": {
|
|
38525
|
-
capName: "decoder",
|
|
38526
|
-
capScope: "system",
|
|
38527
|
-
addonId: null,
|
|
38528
|
-
access: "delete"
|
|
38529
|
-
},
|
|
38530
|
-
"decoder.getFrame": {
|
|
38531
|
-
capName: "decoder",
|
|
38532
|
-
capScope: "system",
|
|
38533
|
-
addonId: null,
|
|
38534
|
-
access: "view"
|
|
38535
|
-
},
|
|
38536
38267
|
"decoder.getInfo": {
|
|
38537
38268
|
capName: "decoder",
|
|
38538
38269
|
capScope: "system",
|
|
38539
38270
|
addonId: null,
|
|
38540
38271
|
access: "view"
|
|
38541
38272
|
},
|
|
38542
|
-
"decoder.getShmStats": {
|
|
38543
|
-
capName: "decoder",
|
|
38544
|
-
capScope: "system",
|
|
38545
|
-
addonId: null,
|
|
38546
|
-
access: "view"
|
|
38547
|
-
},
|
|
38548
|
-
"decoder.getStats": {
|
|
38549
|
-
capName: "decoder",
|
|
38550
|
-
capScope: "system",
|
|
38551
|
-
addonId: null,
|
|
38552
|
-
access: "view"
|
|
38553
|
-
},
|
|
38554
|
-
"decoder.listActiveSessions": {
|
|
38555
|
-
capName: "decoder",
|
|
38556
|
-
capScope: "system",
|
|
38557
|
-
addonId: null,
|
|
38558
|
-
access: "view"
|
|
38559
|
-
},
|
|
38560
|
-
"decoder.openStream": {
|
|
38561
|
-
capName: "decoder",
|
|
38562
|
-
capScope: "system",
|
|
38563
|
-
addonId: null,
|
|
38564
|
-
access: "view"
|
|
38565
|
-
},
|
|
38566
|
-
"decoder.pullFrames": {
|
|
38567
|
-
capName: "decoder",
|
|
38568
|
-
capScope: "system",
|
|
38569
|
-
addonId: null,
|
|
38570
|
-
access: "view"
|
|
38571
|
-
},
|
|
38572
|
-
"decoder.pullHandles": {
|
|
38573
|
-
capName: "decoder",
|
|
38574
|
-
capScope: "system",
|
|
38575
|
-
addonId: null,
|
|
38576
|
-
access: "view"
|
|
38577
|
-
},
|
|
38578
|
-
"decoder.pushPacket": {
|
|
38579
|
-
capName: "decoder",
|
|
38580
|
-
capScope: "system",
|
|
38581
|
-
addonId: null,
|
|
38582
|
-
access: "view"
|
|
38583
|
-
},
|
|
38584
38273
|
"decoder.reprobeHwaccel": {
|
|
38585
38274
|
capName: "decoder",
|
|
38586
38275
|
capScope: "system",
|
|
38587
38276
|
addonId: null,
|
|
38588
38277
|
access: "create"
|
|
38589
38278
|
},
|
|
38590
|
-
"decoder.supportsCodec": {
|
|
38591
|
-
capName: "decoder",
|
|
38592
|
-
capScope: "system",
|
|
38593
|
-
addonId: null,
|
|
38594
|
-
access: "view"
|
|
38595
|
-
},
|
|
38596
|
-
"decoder.updateConfig": {
|
|
38597
|
-
capName: "decoder",
|
|
38598
|
-
capScope: "system",
|
|
38599
|
-
addonId: null,
|
|
38600
|
-
access: "view"
|
|
38601
|
-
},
|
|
38602
38279
|
"detectionPipeline.applyDeviceSettingsPatch": {
|
|
38603
38280
|
capName: "detection-pipeline",
|
|
38604
38281
|
capScope: "device",
|
|
@@ -41689,12 +41366,6 @@ Object.freeze({
|
|
|
41689
41366
|
addonId: null,
|
|
41690
41367
|
access: "delete"
|
|
41691
41368
|
},
|
|
41692
|
-
"pipelineExecutor.deleteTemplate": {
|
|
41693
|
-
capName: "pipeline-executor",
|
|
41694
|
-
capScope: "system",
|
|
41695
|
-
addonId: null,
|
|
41696
|
-
access: "delete"
|
|
41697
|
-
},
|
|
41698
41369
|
"pipelineExecutor.downloadModel": {
|
|
41699
41370
|
capName: "pipeline-executor",
|
|
41700
41371
|
capScope: "system",
|
|
@@ -41833,12 +41504,6 @@ Object.freeze({
|
|
|
41833
41504
|
addonId: null,
|
|
41834
41505
|
access: "view"
|
|
41835
41506
|
},
|
|
41836
|
-
"pipelineExecutor.listTemplates": {
|
|
41837
|
-
capName: "pipeline-executor",
|
|
41838
|
-
capScope: "system",
|
|
41839
|
-
addonId: null,
|
|
41840
|
-
access: "view"
|
|
41841
|
-
},
|
|
41842
41507
|
"pipelineExecutor.rearmInferenceDevice": {
|
|
41843
41508
|
capName: "pipeline-executor",
|
|
41844
41509
|
capScope: "system",
|
|
@@ -41863,12 +41528,6 @@ Object.freeze({
|
|
|
41863
41528
|
addonId: null,
|
|
41864
41529
|
access: "create"
|
|
41865
41530
|
},
|
|
41866
|
-
"pipelineExecutor.saveTemplate": {
|
|
41867
|
-
capName: "pipeline-executor",
|
|
41868
|
-
capScope: "system",
|
|
41869
|
-
addonId: null,
|
|
41870
|
-
access: "create"
|
|
41871
|
-
},
|
|
41872
41531
|
"pipelineExecutor.setVideoPipelineSteps": {
|
|
41873
41532
|
capName: "pipeline-executor",
|
|
41874
41533
|
capScope: "system",
|
|
@@ -41887,12 +41546,6 @@ Object.freeze({
|
|
|
41887
41546
|
addonId: null,
|
|
41888
41547
|
access: "create"
|
|
41889
41548
|
},
|
|
41890
|
-
"pipelineExecutor.updateTemplate": {
|
|
41891
|
-
capName: "pipeline-executor",
|
|
41892
|
-
capScope: "system",
|
|
41893
|
-
addonId: null,
|
|
41894
|
-
access: "create"
|
|
41895
|
-
},
|
|
41896
41549
|
"pipelineExecutor.validatePipeline": {
|
|
41897
41550
|
capName: "pipeline-executor",
|
|
41898
41551
|
capScope: "system",
|
|
@@ -41923,12 +41576,6 @@ Object.freeze({
|
|
|
41923
41576
|
addonId: null,
|
|
41924
41577
|
access: "create"
|
|
41925
41578
|
},
|
|
41926
|
-
"pipelineOrchestrator.deleteTemplate": {
|
|
41927
|
-
capName: "pipeline-orchestrator",
|
|
41928
|
-
capScope: "system",
|
|
41929
|
-
addonId: null,
|
|
41930
|
-
access: "delete"
|
|
41931
|
-
},
|
|
41932
41579
|
"pipelineOrchestrator.getAgentLoad": {
|
|
41933
41580
|
capName: "pipeline-orchestrator",
|
|
41934
41581
|
capScope: "system",
|
|
@@ -42079,12 +41726,6 @@ Object.freeze({
|
|
|
42079
41726
|
addonId: null,
|
|
42080
41727
|
access: "view"
|
|
42081
41728
|
},
|
|
42082
|
-
"pipelineOrchestrator.listTemplates": {
|
|
42083
|
-
capName: "pipeline-orchestrator",
|
|
42084
|
-
capScope: "system",
|
|
42085
|
-
addonId: null,
|
|
42086
|
-
access: "view"
|
|
42087
|
-
},
|
|
42088
41729
|
"pipelineOrchestrator.pauseForStorageMigration": {
|
|
42089
41730
|
capName: "pipeline-orchestrator",
|
|
42090
41731
|
capScope: "system",
|
|
@@ -42139,12 +41780,6 @@ Object.freeze({
|
|
|
42139
41780
|
addonId: null,
|
|
42140
41781
|
access: "create"
|
|
42141
41782
|
},
|
|
42142
|
-
"pipelineOrchestrator.saveTemplate": {
|
|
42143
|
-
capName: "pipeline-orchestrator",
|
|
42144
|
-
capScope: "system",
|
|
42145
|
-
addonId: null,
|
|
42146
|
-
access: "create"
|
|
42147
|
-
},
|
|
42148
41783
|
"pipelineOrchestrator.setAgentCapabilities": {
|
|
42149
41784
|
capName: "pipeline-orchestrator",
|
|
42150
41785
|
capScope: "system",
|
|
@@ -42253,12 +41888,6 @@ Object.freeze({
|
|
|
42253
41888
|
addonId: null,
|
|
42254
41889
|
access: "create"
|
|
42255
41890
|
},
|
|
42256
|
-
"pipelineOrchestrator.updateTemplate": {
|
|
42257
|
-
capName: "pipeline-orchestrator",
|
|
42258
|
-
capScope: "system",
|
|
42259
|
-
addonId: null,
|
|
42260
|
-
access: "create"
|
|
42261
|
-
},
|
|
42262
41891
|
"pipelineRunner.attachCamera": {
|
|
42263
41892
|
capName: "pipeline-runner",
|
|
42264
41893
|
capScope: "system",
|
|
@@ -43693,12 +43322,6 @@ Object.freeze({
|
|
|
43693
43322
|
addonId: null,
|
|
43694
43323
|
access: "view"
|
|
43695
43324
|
},
|
|
43696
|
-
"streamBroker.pullFrameHandles": {
|
|
43697
|
-
capName: "stream-broker",
|
|
43698
|
-
capScope: "system",
|
|
43699
|
-
addonId: null,
|
|
43700
|
-
access: "view"
|
|
43701
|
-
},
|
|
43702
43325
|
"streamBroker.regenerateRtspToken": {
|
|
43703
43326
|
capName: "stream-broker",
|
|
43704
43327
|
capScope: "system",
|
|
@@ -43765,12 +43388,6 @@ Object.freeze({
|
|
|
43765
43388
|
addonId: null,
|
|
43766
43389
|
access: "create"
|
|
43767
43390
|
},
|
|
43768
|
-
"streamBroker.subscribeFrames": {
|
|
43769
|
-
capName: "stream-broker",
|
|
43770
|
-
capScope: "system",
|
|
43771
|
-
addonId: null,
|
|
43772
|
-
access: "create"
|
|
43773
|
-
},
|
|
43774
43391
|
"streamBroker.unassignProfile": {
|
|
43775
43392
|
capName: "stream-broker",
|
|
43776
43393
|
capScope: "system",
|
|
@@ -43783,12 +43400,6 @@ Object.freeze({
|
|
|
43783
43400
|
addonId: null,
|
|
43784
43401
|
access: "create"
|
|
43785
43402
|
},
|
|
43786
|
-
"streamBroker.unsubscribeFrames": {
|
|
43787
|
-
capName: "stream-broker",
|
|
43788
|
-
capScope: "system",
|
|
43789
|
-
addonId: null,
|
|
43790
|
-
access: "create"
|
|
43791
|
-
},
|
|
43792
43403
|
"streamCatalog.getCatalog": {
|
|
43793
43404
|
capName: "stream-catalog",
|
|
43794
43405
|
capScope: "device",
|
|
@@ -46302,11 +45913,6 @@ Object.freeze({
|
|
|
46302
45913
|
form: "single",
|
|
46303
45914
|
optional: false
|
|
46304
45915
|
}],
|
|
46305
|
-
"decoder.createSession": [{
|
|
46306
|
-
name: "deviceId",
|
|
46307
|
-
form: "single",
|
|
46308
|
-
optional: true
|
|
46309
|
-
}],
|
|
46310
45916
|
"detectionPipeline.applyDeviceSettingsPatch": [{
|
|
46311
45917
|
name: "deviceId",
|
|
46312
45918
|
form: "single",
|
|
@@ -50447,24 +50053,6 @@ var CAMERA_STREAM_CONTROLLER = {
|
|
|
50447
50053
|
audioCodecs: ["AAC"]
|
|
50448
50054
|
}]
|
|
50449
50055
|
};
|
|
50450
|
-
/**
|
|
50451
|
-
* `Alexa.EndpointHealth` — REQUIRED on a sensor endpoint (alexa-endpointhealth;
|
|
50452
|
-
* alexa-motionsensor: "Must also implement `Alexa.EndpointHealth`"), and every
|
|
50453
|
-
* camera endpoint may carry `Alexa.MotionSensor`. Declared on every camera so
|
|
50454
|
-
* Alexa can tell an offline camera from a broken one: `connectivity` comes
|
|
50455
|
-
* from the `device-status` cap in ReportState and is pushed as a ChangeReport
|
|
50456
|
-
* on `DeviceOnline` / `DeviceOffline` by the Event Gateway.
|
|
50457
|
-
*/
|
|
50458
|
-
var ENDPOINT_HEALTH = {
|
|
50459
|
-
type: "AlexaInterface",
|
|
50460
|
-
interface: "Alexa.EndpointHealth",
|
|
50461
|
-
version: "3",
|
|
50462
|
-
properties: {
|
|
50463
|
-
supported: [{ name: "connectivity" }],
|
|
50464
|
-
proactivelyReported: true,
|
|
50465
|
-
retrievable: true
|
|
50466
|
-
}
|
|
50467
|
-
};
|
|
50468
50056
|
var DOORBELL_EVENT_SOURCE = {
|
|
50469
50057
|
type: "AlexaInterface",
|
|
50470
50058
|
interface: "Alexa.DoorbellEventSource",
|
|
@@ -50627,6 +50215,27 @@ var PTZ_TILT_MODE_CONTROLLER = ptzDirectionalModeController("ptz.tilt", "Tilt",
|
|
|
50627
50215
|
label: "Down"
|
|
50628
50216
|
}
|
|
50629
50217
|
]);
|
|
50218
|
+
/** Amazon (alexa-modecontroller): "You must include a minimum of two mode
|
|
50219
|
+
* objects." One preset made the camera's whole AddOrUpdateReport fail
|
|
50220
|
+
* schema validation, and Discover dropped the camera. */
|
|
50221
|
+
var MIN_MODE_CONTROLLER_MODES = 2;
|
|
50222
|
+
/**
|
|
50223
|
+
* Preset names as distinct mode values. Two presets with the same name (the
|
|
50224
|
+
* camera allows it: `Stanza`, `Stanza`; `CamStack Home` ×3) produced two
|
|
50225
|
+
* identical modes, and Alexa rejected the capability — "Invalid capability
|
|
50226
|
+
* received." — and with it every endpoint of the camera. First wins,
|
|
50227
|
+
* case-insensitively: the SetMode handler resolves a value to the first
|
|
50228
|
+
* preset of that name, which is the one kept.
|
|
50229
|
+
*/
|
|
50230
|
+
function distinctPresetNames(names) {
|
|
50231
|
+
const seen = /* @__PURE__ */ new Set();
|
|
50232
|
+
return names.filter((name) => {
|
|
50233
|
+
const key = name.toLowerCase();
|
|
50234
|
+
if (seen.has(key)) return false;
|
|
50235
|
+
seen.add(key);
|
|
50236
|
+
return true;
|
|
50237
|
+
});
|
|
50238
|
+
}
|
|
50630
50239
|
function ptzPresetModeController(presetNames) {
|
|
50631
50240
|
return {
|
|
50632
50241
|
type: "AlexaInterface",
|
|
@@ -50666,13 +50275,13 @@ function buildParentCameraEndpoint(input) {
|
|
|
50666
50275
|
const capabilities = [
|
|
50667
50276
|
ALEXA_BASE_CAPABILITY,
|
|
50668
50277
|
CAMERA_STREAM_CONTROLLER,
|
|
50669
|
-
rtcSessionController(input.hasIntercom)
|
|
50670
|
-
ENDPOINT_HEALTH
|
|
50278
|
+
rtcSessionController(input.hasIntercom)
|
|
50671
50279
|
];
|
|
50672
50280
|
if (input.isDoorbell) capabilities.push(DOORBELL_EVENT_SOURCE);
|
|
50673
50281
|
if (input.hasMotion) capabilities.push(MOTION_SENSOR);
|
|
50674
50282
|
if (input.hasBattery) capabilities.push(BATTERY_LEVEL_SENSOR);
|
|
50675
|
-
|
|
50283
|
+
const presetNames = distinctPresetNames(input.ptzPresetNames);
|
|
50284
|
+
if (presetNames.length >= MIN_MODE_CONTROLLER_MODES) capabilities.push(ptzPresetModeController(presetNames));
|
|
50676
50285
|
if (input.hasPtz) {
|
|
50677
50286
|
capabilities.push(PTZ_PAN_MODE_CONTROLLER);
|
|
50678
50287
|
capabilities.push(PTZ_TILT_MODE_CONTROLLER);
|
|
@@ -50811,6 +50420,12 @@ function buildAlarmPanelEndpoint(input) {
|
|
|
50811
50420
|
};
|
|
50812
50421
|
}
|
|
50813
50422
|
//#endregion
|
|
50423
|
+
//#region src/handlers/ptz-preset-recallable.ts
|
|
50424
|
+
var RECALLABLE_FUNCTIONS = new Set(["home"]);
|
|
50425
|
+
function isAlexaRecallablePreset(preset) {
|
|
50426
|
+
return preset.fn === null || RECALLABLE_FUNCTIONS.has(preset.fn);
|
|
50427
|
+
}
|
|
50428
|
+
//#endregion
|
|
50814
50429
|
//#region src/handlers/discovery.ts
|
|
50815
50430
|
var discoveryPayloadSchema = DiscoveryDirectiveSchema.shape.payload;
|
|
50816
50431
|
/** Devices built at once in `handleDiscovery` — latency-bound tRPC reads, so
|
|
@@ -50998,7 +50613,7 @@ async function loadBoundDeviceInfo(device, api) {
|
|
|
50998
50613
|
};
|
|
50999
50614
|
}
|
|
51000
50615
|
async function fetchPtzPresetNames(deviceId, api) {
|
|
51001
|
-
return (await api.ptz.getPresets.query({ deviceId })).map((p) => p.name).filter((n) => n.length > 0);
|
|
50616
|
+
return (await api.ptz.getPresets.query({ deviceId })).filter(isAlexaRecallablePreset).map((p) => p.name).filter((n) => n.length > 0);
|
|
51002
50617
|
}
|
|
51003
50618
|
function classifyChildKind(deviceType, role) {
|
|
51004
50619
|
if (role === "floodlight" || role === "spotlight" || role === "nightvision") return "light";
|
|
@@ -51398,8 +51013,8 @@ async function handleSetMode(header, endpointRaw, payloadRaw, deps, _callerIdent
|
|
|
51398
51013
|
if (!mode.startsWith(PTZ_PRESET_MODE_PREFIX)) return errorEnvelope(header, "INVALID_DIRECTIVE", `mode '${mode}' is not a ptz.preset mode`);
|
|
51399
51014
|
const presetName = mode.slice(11);
|
|
51400
51015
|
if (presetName.length === 0) return errorEnvelope(header, "INVALID_DIRECTIVE", "preset name missing after prefix");
|
|
51401
|
-
const preset = (await api.ptz.getPresets.query({ deviceId: parsedId.deviceId })).find((p) => p.name === presetName);
|
|
51402
|
-
if (!preset) return errorEnvelope(header, "INVALID_DIRECTIVE", `preset '${presetName}' not
|
|
51016
|
+
const preset = (await api.ptz.getPresets.query({ deviceId: parsedId.deviceId })).find((p) => p.name === presetName && isAlexaRecallablePreset(p));
|
|
51017
|
+
if (!preset) return errorEnvelope(header, "INVALID_DIRECTIVE", `preset '${presetName}' is not a recallable preset on device ${parsedId.deviceId}`);
|
|
51403
51018
|
await api.ptz.goToPreset.mutate({
|
|
51404
51019
|
deviceId: parsedId.deviceId,
|
|
51405
51020
|
presetId: preset.id
|
|
@@ -51491,20 +51106,6 @@ async function collectCameraProperties(api, deviceId, properties, timeOfSample,
|
|
|
51491
51106
|
timeOfSample,
|
|
51492
51107
|
uncertaintyInMilliseconds: 0
|
|
51493
51108
|
});
|
|
51494
|
-
const online = boolField(await api.deviceStatus.getStatus.query({ deviceId }).catch((err) => {
|
|
51495
|
-
logger.warn("alexa report-state: deviceStatus.getStatus failed — connectivity omitted", {
|
|
51496
|
-
tags: { deviceId },
|
|
51497
|
-
meta: { error: err instanceof Error ? err.message : String(err) }
|
|
51498
|
-
});
|
|
51499
|
-
return null;
|
|
51500
|
-
}), "online");
|
|
51501
|
-
if (online !== null) properties.push({
|
|
51502
|
-
namespace: "Alexa.EndpointHealth",
|
|
51503
|
-
name: "connectivity",
|
|
51504
|
-
value: { value: online ? "OK" : "UNREACHABLE" },
|
|
51505
|
-
timeOfSample,
|
|
51506
|
-
uncertaintyInMilliseconds: 0
|
|
51507
|
-
});
|
|
51508
51109
|
const detected = boolField(await api.motion.getStatus.query({ deviceId }).catch((err) => {
|
|
51509
51110
|
logger.info("alexa report-state: motion.getStatus skipped", { meta: {
|
|
51510
51111
|
deviceId,
|
|
@@ -53461,7 +53062,7 @@ function buildAlexaOauthIntegration(publicHubUrl) {
|
|
|
53461
53062
|
* client id and SECRET, on the theory that a per-account refresh token was the
|
|
53462
53063
|
* real gate. The package is public on npm, so that secret was published with
|
|
53463
53064
|
* every version and has to be rotated. Since D753 the secret lives only in the
|
|
53464
|
-
* skill's Lambda (
|
|
53065
|
+
* skill's Lambda (SSM Parameter Store SecureString, D761); the hub gets short-lived Event Gateway
|
|
53465
53066
|
* tokens from the Lambda's broker (`broker-client.ts`) with a per-link
|
|
53466
53067
|
* credential. `scripts/check-no-client-secrets.ts` keeps it that way.
|
|
53467
53068
|
*
|
|
@@ -54492,7 +54093,7 @@ var ExportAlexaAddon = class extends BaseAddon {
|
|
|
54492
54093
|
content: [
|
|
54493
54094
|
"Public skill (default): enable the \"CamStack\" skill in the Alexa app and link your account — no Amazon developer setup is needed. A single published skill + hosted Lambda route to this hub using its public HTTPS URL (baked into every JWT).",
|
|
54494
54095
|
"The skill's Lambda keeps the Amazon credentials: this hub never holds an LWA client secret. It receives short-lived event tokens from the Lambda's token broker with a credential that is unique to this link.",
|
|
54495
|
-
"Custom skill: switch \"Alexa skill\" below to Custom, enter your skill id, and deploy the skill Lambda from this addon's lambda-template in your own AWS account (your LWA credentials go into
|
|
54096
|
+
"Custom skill: switch \"Alexa skill\" below to Custom, enter your skill id, and deploy the skill Lambda from this addon's lambda-template in your own AWS account (your LWA credentials go into SSM Parameter Store there, not here).",
|
|
54496
54097
|
"Either way this hub must be reachable from the public internet (Cloudflare Tunnel, Tailscale Funnel, …). The \"External address\" picker selects which detected endpoint the Lambda calls back on — press \"Refresh external addresses\" after setting up a new tunnel."
|
|
54497
54098
|
].join("\n")
|
|
54498
54099
|
},
|
|
@@ -54559,7 +54160,7 @@ var ExportAlexaAddon = class extends BaseAddon {
|
|
|
54559
54160
|
key: "__custom-skill-info",
|
|
54560
54161
|
label: "Your skill Lambda",
|
|
54561
54162
|
variant: "info",
|
|
54562
|
-
content: "Proactive events (doorbell, motion, battery, device-list updates) are authorised by YOUR skill Lambda: it keeps the \"Send Alexa Events\" LWA client id/secret in
|
|
54163
|
+
content: "Proactive events (doorbell, motion, battery, device-list updates) are authorised by YOUR skill Lambda: it keeps the \"Send Alexa Events\" LWA client id/secret in SSM Parameter Store and hands this hub short-lived tokens. Nothing to paste here — see the custom-skill setup guide."
|
|
54563
54164
|
}] : [{
|
|
54564
54165
|
type: "info",
|
|
54565
54166
|
key: "__public-skill-info",
|