@camstack/addon-pipeline 0.1.18 → 0.1.19

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.
Files changed (52) hide show
  1. package/dist/audio-analyzer/index.js +8 -3
  2. package/dist/audio-analyzer/index.js.map +1 -1
  3. package/dist/audio-analyzer/index.mjs +8 -3
  4. package/dist/audio-analyzer/index.mjs.map +1 -1
  5. package/dist/audio-codec-nodeav/index.js +1 -1
  6. package/dist/audio-codec-nodeav/index.mjs +1 -1
  7. package/dist/decoder-nodeav/index.js +1 -1
  8. package/dist/decoder-nodeav/index.mjs +1 -1
  9. package/dist/detection-pipeline/index.js +23 -20
  10. package/dist/detection-pipeline/index.js.map +1 -1
  11. package/dist/detection-pipeline/index.mjs +23 -20
  12. package/dist/detection-pipeline/index.mjs.map +1 -1
  13. package/dist/{index-DLHaHm6u.js → index-BbPPvoCx.js} +414 -45
  14. package/dist/index-BbPPvoCx.js.map +1 -0
  15. package/dist/{index-asZs8U_s.mjs → index-Bmlkm0Fd.mjs} +414 -45
  16. package/dist/index-Bmlkm0Fd.mjs.map +1 -0
  17. package/dist/motion-wasm/index.js +1 -1
  18. package/dist/motion-wasm/index.mjs +1 -1
  19. package/dist/pipeline-runner/index.js +132 -14
  20. package/dist/pipeline-runner/index.js.map +1 -1
  21. package/dist/pipeline-runner/index.mjs +133 -15
  22. package/dist/pipeline-runner/index.mjs.map +1 -1
  23. package/dist/stream-broker/@mf-types.zip +0 -0
  24. package/dist/stream-broker/__mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.mjs-NjF4kxzW.mjs +19 -0
  25. package/dist/stream-broker/__mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.mjs-BAv_5ISf.mjs +20 -0
  26. package/dist/stream-broker/{__mfe_internal__addon_stream_broker_widgets__loadShare__react__loadShare__.mjs-DAssX3h0.mjs → __mfe_internal__addon_stream_broker_widgets__loadShare__react__loadShare__.mjs-BsB2G7oY.mjs} +2 -1
  27. package/dist/stream-broker/{__mfe_internal__addon_stream_broker_widgets__loadShare__react__loadShare__.mjs_commonjs-proxy-DFoJJhpt.mjs → __mfe_internal__addon_stream_broker_widgets__loadShare__react__loadShare__.mjs_commonjs-proxy-xrRiPUpA.mjs} +1 -1
  28. package/dist/stream-broker/{__mfe_internal__addon_stream_broker_widgets__loadShare__react_mf_2_dom__loadShare__.mjs_commonjs-proxy-x7XMEeuJ.mjs → __mfe_internal__addon_stream_broker_widgets__loadShare__react_mf_2_dom__loadShare__.mjs_commonjs-proxy-C0E2yCzO.mjs} +1 -1
  29. package/dist/stream-broker/_stub.js +2 -2
  30. package/dist/stream-broker/{_virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-3TxRVJ5L.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_stream_broker_widgets-CupRlwqG.mjs} +6 -6
  31. package/dist/stream-broker/{client-CZXrddDR.mjs → client-NPZqorv9.mjs} +2 -2
  32. package/dist/stream-broker/{hostInit-De6APW25.mjs → hostInit-Bh4w7o5_.mjs} +12 -12
  33. package/dist/stream-broker/{index-C0BzaWmB.mjs → index-2Qp8vT3w.mjs} +1 -1
  34. package/dist/stream-broker/{index-CZNxa0ad.mjs → index-BBcZvb5t.mjs} +1 -1
  35. package/dist/stream-broker/index-CIJue-4t.mjs +37880 -0
  36. package/dist/stream-broker/{index-BvV3RVTZ.mjs → index-Cc6QBqMk.mjs} +2 -2
  37. package/dist/stream-broker/{index-cYW01SNH.mjs → index-D_1p2K9B.mjs} +1 -1
  38. package/dist/stream-broker/{index-CUXiTSWS.mjs → index-Dy2V7VOm.mjs} +3775 -3279
  39. package/dist/stream-broker/{index-KtR7Pp0O.mjs → index-mX3Kgiv1.mjs} +1 -1
  40. package/dist/stream-broker/index.js +1565 -280
  41. package/dist/stream-broker/index.js.map +1 -1
  42. package/dist/stream-broker/index.mjs +1567 -281
  43. package/dist/stream-broker/index.mjs.map +1 -1
  44. package/dist/stream-broker/{jsx-runtime-B_evVsXl.mjs → jsx-runtime-lb0mH5st.mjs} +1 -1
  45. package/dist/stream-broker/remoteEntry.js +1 -1
  46. package/dist/stream-broker/{schemas-ChN4Ih0h.mjs → schemas-ClCuS4qa.mjs} +151 -141
  47. package/package.json +1 -1
  48. package/dist/index-DLHaHm6u.js.map +0 -1
  49. package/dist/index-asZs8U_s.mjs.map +0 -1
  50. package/dist/stream-broker/__mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.mjs-d8PmLbO2.mjs +0 -19
  51. package/dist/stream-broker/__mfe_internal__addon_stream_broker_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.mjs-B4l8Nb2y.mjs +0 -20
  52. package/dist/stream-broker/index-Kb4xa8FX.mjs +0 -36403
@@ -4778,6 +4778,16 @@ function record(keyType, valueType, params) {
4778
4778
  ...normalizeParams(params)
4779
4779
  });
4780
4780
  }
4781
+ function partialRecord(keyType, valueType, params) {
4782
+ const k = clone(keyType);
4783
+ k._zod.values = void 0;
4784
+ return new ZodRecord({
4785
+ type: "record",
4786
+ keyType: k,
4787
+ valueType,
4788
+ ...normalizeParams(params)
4789
+ });
4790
+ }
4781
4791
  const ZodEnum = /* @__PURE__ */ $constructor("ZodEnum", (inst, def) => {
4782
4792
  $ZodEnum.init(inst, def);
4783
4793
  ZodType.init(inst, def);
@@ -5054,6 +5064,37 @@ function _instanceof(cls, params = {}) {
5054
5064
  };
5055
5065
  return inst;
5056
5066
  }
5067
+ const wiringProbeKindSchema = _enum(["singleton", "device", "widget"]);
5068
+ const wiringProbeResultSchema = object({
5069
+ capName: string(),
5070
+ kind: wiringProbeKindSchema,
5071
+ deviceId: number().optional(),
5072
+ reachable: boolean(),
5073
+ latencyMs: number(),
5074
+ error: string().optional()
5075
+ });
5076
+ const wiringAddonHealthSchema = object({
5077
+ addonId: string(),
5078
+ caps: array(wiringProbeResultSchema).readonly(),
5079
+ widgets: array(wiringProbeResultSchema).readonly()
5080
+ });
5081
+ const wiringNodeHealthSchema = object({
5082
+ nodeId: string(),
5083
+ addons: array(wiringAddonHealthSchema).readonly()
5084
+ });
5085
+ object({
5086
+ /** True only when every probed target is reachable. */
5087
+ ok: boolean(),
5088
+ /** True when at least one target is unreachable. */
5089
+ degraded: boolean(),
5090
+ checkedAt: string(),
5091
+ nodes: array(wiringNodeHealthSchema).readonly(),
5092
+ summary: object({
5093
+ total: number(),
5094
+ reachable: number(),
5095
+ unreachable: number()
5096
+ })
5097
+ });
5057
5098
  const MODEL_FORMATS = ["onnx", "coreml", "openvino", "tflite", "pt"];
5058
5099
  const WELL_KNOWN_TABS = [
5059
5100
  { id: "overview", label: "Overview", icon: "layout-dashboard", order: -10 },
@@ -6618,7 +6659,7 @@ const SpatialDetectionSchema = object({
6618
6659
  bbox: BoundingBoxSchema
6619
6660
  });
6620
6661
  const AudioChunkInputSchema = object({
6621
- data: _instanceof(Float32Array),
6662
+ data: _instanceof(Uint8Array),
6622
6663
  sampleRate: number(),
6623
6664
  channels: number(),
6624
6665
  timestamp: number(),
@@ -7298,7 +7339,23 @@ const RunnerCameraConfigSchema = object({
7298
7339
  * whenever its `zones` device-state slice changes, so the runner's
7299
7340
  * copy stays in sync. Empty array → no zone filtering.
7300
7341
  */
7301
- zones: array(ZoneSchema).readonly().default([])
7342
+ zones: array(ZoneSchema).readonly().default([]),
7343
+ /**
7344
+ * When true (default) and the camera's `motionSources` contains only
7345
+ * `'onboard'`, the runner dynamically opens the same WASM frame-diff
7346
+ * motion-frames subscription on each `MotionOnMotionChanged
7347
+ * source:'onboard'` event and tears it down after `motionCooldownMs`.
7348
+ * This causes `runMotionAnalysis` to emit `MotionZonesRaw` /
7349
+ * `MotionAnalysis` during active-motion windows without the
7350
+ * substream being held open continuously.
7351
+ *
7352
+ * Set to `false` to disable the dynamic analyzer for this camera
7353
+ * (e.g. very low-bandwidth links where the extra substream is
7354
+ * undesirable). Has no effect when `motionSources` already includes
7355
+ * `'analyzer'` — the analyzer runs continuously in that case and
7356
+ * this gate is bypassed.
7357
+ */
7358
+ onboardMotionDrivesAnalyzer: boolean().default(true)
7302
7359
  });
7303
7360
  const RunnerLocalLoadSchema = object({
7304
7361
  /** Moleculer node id of this runner instance. */
@@ -7438,22 +7495,68 @@ MotionTriggerStatusSchema.extend({
7438
7495
  }) }
7439
7496
  }
7440
7497
  });
7498
+ const MaskPointSchema = object({
7499
+ x: number(),
7500
+ y: number()
7501
+ });
7502
+ const MaskRectShapeSchema = object({
7503
+ kind: literal("rect"),
7504
+ x: number(),
7505
+ y: number(),
7506
+ width: number(),
7507
+ height: number()
7508
+ });
7509
+ const MaskPolygonShapeSchema = object({
7510
+ kind: literal("polygon"),
7511
+ points: array(MaskPointSchema)
7512
+ });
7513
+ const MaskGridShapeSchema = object({
7514
+ kind: literal("grid"),
7515
+ gridWidth: number(),
7516
+ gridHeight: number(),
7517
+ cells: array(boolean())
7518
+ });
7519
+ const MaskLineShapeSchema = object({
7520
+ kind: literal("line"),
7521
+ points: array(MaskPointSchema)
7522
+ });
7523
+ discriminatedUnion("kind", [
7524
+ MaskRectShapeSchema,
7525
+ MaskPolygonShapeSchema,
7526
+ MaskGridShapeSchema,
7527
+ MaskLineShapeSchema
7528
+ ]);
7529
+ const MaskShapeKindSchema = _enum(["rect", "polygon", "grid", "line"]);
7530
+ const MaskPolygonVerticesSchema = object({
7531
+ min: number(),
7532
+ max: number()
7533
+ });
7534
+ const MaskGridDimsSchema = object({
7535
+ width: number(),
7536
+ height: number()
7537
+ });
7538
+ const MotionZoneRegionSchema = object({
7539
+ id: number(),
7540
+ enabled: boolean(),
7541
+ shape: MaskGridShapeSchema
7542
+ });
7441
7543
  object({
7442
7544
  enabled: boolean(),
7443
7545
  sensitivity: number(),
7444
- /** Row-major active-cell grid. Length = gridWidth*gridHeight (see getOptions). */
7445
- cells: array(boolean()),
7546
+ /** Grid region(s). Today exactly one `grid` shape. */
7547
+ regions: array(MotionZoneRegionSchema),
7446
7548
  lastFetchedAt: number()
7447
7549
  });
7448
7550
  const MotionZoneOptionsSchema = object({
7449
- gridWidth: number(),
7450
- gridHeight: number(),
7551
+ maxRegions: number(),
7552
+ supportedShapes: array(MaskShapeKindSchema),
7553
+ grid: MaskGridDimsSchema,
7451
7554
  sensitivity: object({ min: number(), max: number(), step: number() })
7452
7555
  });
7453
7556
  const MotionZonePatchSchema = object({
7454
7557
  enabled: boolean().optional(),
7455
7558
  sensitivity: number().optional(),
7456
- cells: array(boolean()).optional()
7559
+ regions: array(MotionZoneRegionSchema).optional()
7457
7560
  });
7458
7561
  ({
7459
7562
  deviceTypes: [DeviceType.Camera],
@@ -7466,6 +7569,102 @@ const MotionZonePatchSchema = object({
7466
7569
  )
7467
7570
  }
7468
7571
  });
7572
+ const NativeObjectClassEnum = _enum([
7573
+ "person",
7574
+ "vehicle",
7575
+ "animal",
7576
+ "face",
7577
+ "package",
7578
+ "other"
7579
+ ]);
7580
+ const NativeDetectionSchema = object({
7581
+ class: NativeObjectClassEnum,
7582
+ timestamp: number(),
7583
+ /** Firmware-provided confidence [0..1]. Reolink pushes don't carry it → undefined. */
7584
+ confidence: number().min(0).max(1).optional()
7585
+ });
7586
+ const NativeObjectDetectionStatusSchema = object({
7587
+ /**
7588
+ * Last observed instance per class. Missing entries mean the class
7589
+ * is supported but nothing has been seen since the provider started.
7590
+ *
7591
+ * MUST be a partial record: providers seed an empty `{}` on cold-start
7592
+ * and write one class at a time as detections arrive. In Zod 4
7593
+ * `z.record(enum, …)` is EXHAUSTIVE (requires every enum key), so a
7594
+ * partial write throws "expected object, received undefined" for every
7595
+ * unseen class. `z.partialRecord` keeps the enum-key narrowing while
7596
+ * allowing the sparse shape the providers actually write.
7597
+ */
7598
+ lastByClass: partialRecord(NativeObjectClassEnum, NativeDetectionSchema.nullable()),
7599
+ /** Classes the firmware is capable of detecting — enumerated at device register. */
7600
+ supportedClasses: array(NativeObjectClassEnum).readonly(),
7601
+ /**
7602
+ * Whether forwarding of onboard AI detections is enabled for this device.
7603
+ * Default true (on cold-start) — detections flow unconditionally before
7604
+ * the toggle is saved, so defaulting true preserves existing behaviour.
7605
+ */
7606
+ enabled: boolean()
7607
+ });
7608
+ NativeObjectDetectionStatusSchema.extend({
7609
+ /** Required by createRuntimeStateBridge — epoch ms of last refresh. */
7610
+ lastFetchedAt: number()
7611
+ });
7612
+ ({
7613
+ deviceTypes: [DeviceType.Camera],
7614
+ methods: {
7615
+ setEnabled: method(
7616
+ object({ deviceId: number(), enabled: boolean() }),
7617
+ _void(),
7618
+ { kind: "mutation", auth: "admin" }
7619
+ )
7620
+ },
7621
+ events: {
7622
+ onDetected: { data: object({
7623
+ deviceId: number(),
7624
+ detection: NativeDetectionSchema
7625
+ }) }
7626
+ }
7627
+ });
7628
+ const PrivacyMaskShapeSchema = discriminatedUnion("kind", [
7629
+ MaskRectShapeSchema,
7630
+ MaskPolygonShapeSchema
7631
+ ]);
7632
+ const PrivacyMaskRegionSchema = object({
7633
+ /** Slot id, 0-based. Stable across read/write. */
7634
+ id: number(),
7635
+ /** Whether this zone is active (blanked out by the camera). */
7636
+ enabled: boolean(),
7637
+ shape: PrivacyMaskShapeSchema
7638
+ });
7639
+ object({
7640
+ enabled: boolean(),
7641
+ /** Active zones (normalized 0..1). Length ≤ maxRegions. */
7642
+ regions: array(PrivacyMaskRegionSchema),
7643
+ lastFetchedAt: number()
7644
+ });
7645
+ const PrivacyMaskOptionsSchema = object({
7646
+ /** Maximum number of supported zones. */
7647
+ maxRegions: number(),
7648
+ /** Shape kinds this camera accepts — Reolink: ['rect']; Hikvision: ['rect','polygon']. */
7649
+ supportedShapes: array(MaskShapeKindSchema),
7650
+ /** Polygon vertex bounds when 'polygon' is supported (Hikvision: {min:4,max:4}). */
7651
+ polygonVertices: MaskPolygonVerticesSchema.optional()
7652
+ });
7653
+ const PrivacyMaskPatchSchema = object({
7654
+ enabled: boolean().optional(),
7655
+ regions: array(PrivacyMaskRegionSchema).optional()
7656
+ });
7657
+ ({
7658
+ deviceTypes: [DeviceType.Camera],
7659
+ methods: {
7660
+ getOptions: method(object({ deviceId: number() }), PrivacyMaskOptionsSchema),
7661
+ setMask: method(
7662
+ object({ deviceId: number(), patch: PrivacyMaskPatchSchema }),
7663
+ _void(),
7664
+ { kind: "mutation", auth: "admin" }
7665
+ )
7666
+ }
7667
+ });
7469
7668
  const AutotrackTargetTypeSchema = string().describe("Vendor target string (people/vehicle/pet); empty = camera default");
7470
7669
  const PtzAutotrackSettingsSchema = object({
7471
7670
  targetType: AutotrackTargetTypeSchema,
@@ -7984,7 +8183,8 @@ const SettingsUpdateResultSchema = object({
7984
8183
  object({
7985
8184
  addonId: string(),
7986
8185
  nodeId: string().optional(),
7987
- overlay: record(string(), unknown()).optional()
8186
+ overlay: record(string(), unknown()).optional(),
8187
+ cap: string().optional()
7988
8188
  }),
7989
8189
  SettingsSchemaWithValuesSchema.nullable()
7990
8190
  ),
@@ -8715,7 +8915,14 @@ const OauthIntegrationDescriptorSchema = object({
8715
8915
  /** Allowed redirect_uri prefixes. /api/oauth2/authorize rejects any
8716
8916
  * redirect_uri that does not start with one of these. Required —
8717
8917
  * an empty list means the integration can never complete linking. */
8718
- allowedRedirectPrefixes: array(string()).min(1)
8918
+ allowedRedirectPrefixes: array(string()).min(1),
8919
+ /** Optional public origin (no trailing slash) that this integration's
8920
+ * issued codes/tokens should carry as the `hubUrl` claim — typically the
8921
+ * operator-selected external-access endpoint resolved by the addon. When
8922
+ * present, /api/oauth2/authorize bakes THIS into the code instead of the
8923
+ * hub-global `publicHubUrl()`, so a forked exporter addon (which can't set
8924
+ * the hub's env) drives the claim that its cloud Lambda routes back on. */
8925
+ hubUrl: string().optional()
8719
8926
  });
8720
8927
  ({
8721
8928
  methods: {
@@ -9365,7 +9572,20 @@ const webrtcSessionCapability = {
9365
9572
  object({
9366
9573
  deviceId: number().int().nonnegative(),
9367
9574
  target: WebrtcStreamTargetSchema,
9368
- hints: webrtcClientHintsSchema.optional()
9575
+ hints: webrtcClientHintsSchema.optional(),
9576
+ /**
9577
+ * SERVER-INJECTED — NOT a client hint. The hub layer that holds
9578
+ * the tRPC request context (and therefore the client IP) sets
9579
+ * this to `true` when the viewer's source IP is non-LAN
9580
+ * (4G/CGNAT/internet). The broker then forces TURN-relay-only
9581
+ * ICE for the session so a CGNAT client (which can only offer a
9582
+ * relay candidate) gets a clean relay↔relay media path instead
9583
+ * of werift nominating a dead host/hairpin-srflx pair. LAN
9584
+ * clients leave this absent/false and keep the low-latency
9585
+ * direct (host/srflx) path. Clients MUST NOT send this — the
9586
+ * server overwrites it from the request context.
9587
+ */
9588
+ relayOnly: boolean().optional()
9369
9589
  }),
9370
9590
  object({ sessionId: string(), sdpOffer: string() }),
9371
9591
  { kind: "mutation" }
@@ -9388,7 +9608,22 @@ const webrtcSessionCapability = {
9388
9608
  deviceId: number().int().nonnegative(),
9389
9609
  target: WebrtcStreamTargetSchema.optional(),
9390
9610
  sdpOffer: string(),
9391
- sessionId: string().optional()
9611
+ sessionId: string().optional(),
9612
+ /**
9613
+ * Force TURN-relay-only ICE for this session. Two kinds of caller
9614
+ * set it:
9615
+ * - A cloud peer like Alexa's RTCSessionController (reachable
9616
+ * only via TURN, never our host/srflx behind NAT) passes
9617
+ * `true` from its own trusted addon context.
9618
+ * - The hub injects it for browser client-offer viewers from the
9619
+ * request's source IP (non-LAN ⇒ true), exactly as it does for
9620
+ * `createSession`.
9621
+ * A LAN/Tailscale browser doing client-offer passthrough leaves it
9622
+ * absent/false so a direct host pair carries full native quality.
9623
+ * Untrusted browser clients MUST NOT send it — the hub overwrites
9624
+ * it from the request context.
9625
+ */
9626
+ relayOnly: boolean().optional()
9392
9627
  }),
9393
9628
  object({ sessionId: string(), sdpAnswer: string() }),
9394
9629
  { kind: "mutation" }
@@ -9402,6 +9637,46 @@ const webrtcSessionCapability = {
9402
9637
  _void(),
9403
9638
  { kind: "mutation" }
9404
9639
  ),
9640
+ /**
9641
+ * Trickle ICE — add a remote (client) ICE candidate to a live session.
9642
+ * Lets the client send its SDP offer/answer IMMEDIATELY (before ICE
9643
+ * gathering finishes) and deliver candidates as they arrive, so the
9644
+ * connection establishes in ~0s instead of waiting for full gathering.
9645
+ * The dual of `getIceCandidates`. Mirrors Scrypted's signaling.
9646
+ */
9647
+ addIceCandidate: method(
9648
+ object({
9649
+ deviceId: number().int().nonnegative(),
9650
+ sessionId: string(),
9651
+ candidate: string(),
9652
+ sdpMid: string().nullable().optional(),
9653
+ sdpMLineIndex: number().int().nullable().optional()
9654
+ }),
9655
+ _void(),
9656
+ { kind: "mutation" }
9657
+ ),
9658
+ /**
9659
+ * Trickle ICE — poll the server's gathered ICE candidates for a session.
9660
+ * The server answers immediately (no gathering wait) and the client polls
9661
+ * this to receive host/srflx/relay candidates as werift gathers them,
9662
+ * adding each to its PeerConnection. Returns all candidates gathered so
9663
+ * far; the client dedupes. `done` flips true once gathering completes.
9664
+ */
9665
+ getIceCandidates: method(
9666
+ object({
9667
+ deviceId: number().int().nonnegative(),
9668
+ sessionId: string()
9669
+ }),
9670
+ object({
9671
+ candidates: array(object({
9672
+ candidate: string(),
9673
+ sdpMid: string().nullable(),
9674
+ sdpMLineIndex: number().int().nullable()
9675
+ })),
9676
+ done: boolean()
9677
+ }),
9678
+ { kind: "query" }
9679
+ ),
9405
9680
  closeSession: method(
9406
9681
  object({
9407
9682
  deviceId: number().int().nonnegative(),
@@ -11102,6 +11377,9 @@ const detectionPipelineCapability = {
11102
11377
  exposesDeviceSettings: true,
11103
11378
  methods: {}
11104
11379
  };
11380
+ ({
11381
+ deviceTypes: [DeviceType.Camera]
11382
+ });
11105
11383
  const TrackStateSchema = _enum(["new", "entered", "left", "moving", "idle"]);
11106
11384
  const EventKindSchema = _enum(["motion", "object", "audio"]);
11107
11385
  const TrackPositionSchema = object({
@@ -11929,36 +12207,28 @@ const IntercomStatusSchema = object({
11929
12207
  }) }
11930
12208
  }
11931
12209
  });
11932
- const NativeObjectClassEnum = _enum([
11933
- "person",
11934
- "vehicle",
11935
- "animal",
11936
- "face",
11937
- "package",
11938
- "other"
11939
- ]);
11940
- const NativeDetectionSchema = object({
11941
- class: NativeObjectClassEnum,
11942
- timestamp: number(),
11943
- /** Firmware-provided confidence [0..1]. Reolink pushes don't carry it → undefined. */
11944
- confidence: number().min(0).max(1).optional()
11945
- });
11946
- object({
11947
- /**
11948
- * Last observed instance per class. Undefined entries mean the class
11949
- * is supported but nothing has been seen since the provider started.
11950
- */
11951
- lastByClass: record(NativeObjectClassEnum, NativeDetectionSchema.nullable()),
11952
- /** Classes the firmware is capable of detecting — enumerated at device register. */
11953
- supportedClasses: array(NativeObjectClassEnum).readonly()
12210
+ const CamStreamDescriptorSchema = object({
12211
+ camStreamId: string().min(1),
12212
+ kind: CamStreamKindSchema,
12213
+ url: string().optional(),
12214
+ codec: string().optional(),
12215
+ resolution: CamStreamResolutionSchema.optional(),
12216
+ fps: number().positive().optional(),
12217
+ label: string().optional(),
12218
+ /** Device-level features (e.g. `battery-operated`) — drives broker policy. */
12219
+ deviceFeatures: array(string()).optional(),
12220
+ /** Eligible for automatic profile assignment. Absent = `true`. */
12221
+ autoEligible: boolean().optional(),
12222
+ /** Transport-specific opaque metadata (e.g. rfc4571 SDP). */
12223
+ metadata: record(string(), unknown()).optional()
11954
12224
  });
11955
12225
  ({
11956
12226
  deviceTypes: [DeviceType.Camera],
11957
- events: {
11958
- onDetected: { data: object({
11959
- deviceId: number(),
11960
- detection: NativeDetectionSchema
11961
- }) }
12227
+ methods: {
12228
+ getCatalog: method(
12229
+ object({ deviceId: number().int().nonnegative() }),
12230
+ array(CamStreamDescriptorSchema).readonly()
12231
+ )
11962
12232
  }
11963
12233
  });
11964
12234
  const ModelFormatSchema = _enum(MODEL_FORMATS);
@@ -13166,7 +13436,8 @@ const PackageUpdateSchema = object({
13166
13436
  currentVersion: string(),
13167
13437
  latestVersion: string(),
13168
13438
  category: _enum(["addon", "core"]),
13169
- requiresRestart: boolean()
13439
+ requiresRestart: boolean(),
13440
+ isSystem: boolean()
13170
13441
  });
13171
13442
  const PackageVersionInfoSchema = object({
13172
13443
  version: string(),
@@ -13199,6 +13470,42 @@ const UpdateFrameworkPackageResultSchema = object({
13199
13470
  /** Ms-epoch the server scheduled its self-restart. */
13200
13471
  restartingAt: number()
13201
13472
  });
13473
+ const BulkUpdateItemStatusSchema = _enum([
13474
+ "queued",
13475
+ "updating",
13476
+ "done",
13477
+ "done-pending-restart",
13478
+ "failed"
13479
+ ]);
13480
+ const BulkUpdateItemSchema = object({
13481
+ name: string(),
13482
+ isSystem: boolean(),
13483
+ fromVersion: string(),
13484
+ toVersion: string(),
13485
+ status: BulkUpdateItemStatusSchema,
13486
+ error: string().optional(),
13487
+ startedAtMs: number().optional(),
13488
+ completedAtMs: number().optional()
13489
+ });
13490
+ const BulkUpdatePhaseSchema = _enum([
13491
+ "regular",
13492
+ "system",
13493
+ "restarting",
13494
+ "finalizing"
13495
+ ]);
13496
+ const BulkUpdateStateSchema = object({
13497
+ id: string(),
13498
+ nodeId: string(),
13499
+ startedAtMs: number(),
13500
+ completedAtMs: number().optional(),
13501
+ total: number(),
13502
+ completed: number(),
13503
+ failed: number(),
13504
+ current: string().nullable(),
13505
+ phase: BulkUpdatePhaseSchema,
13506
+ cancelled: boolean(),
13507
+ items: array(BulkUpdateItemSchema).readonly()
13508
+ });
13202
13509
  const FrameworkPackageStatusSchema = object({
13203
13510
  packageName: string(),
13204
13511
  currentVersion: string(),
@@ -13336,7 +13643,7 @@ const CustomActionInputSchema = object({
13336
13643
  getLastRestart: method(
13337
13644
  _void(),
13338
13645
  object({
13339
- kind: _enum(["framework-update", "manual", "system"]),
13646
+ kind: _enum(["framework-update", "manual", "system", "framework-bulk-update"]),
13340
13647
  packageName: string().optional(),
13341
13648
  fromVersion: string().optional(),
13342
13649
  toVersion: string().optional(),
@@ -13426,11 +13733,70 @@ const CustomActionInputSchema = object({
13426
13733
  updateFrameworkPackage: method(
13427
13734
  object({
13428
13735
  packageName: string().min(1),
13429
- version: string().optional()
13736
+ version: string().optional(),
13737
+ deferRestart: boolean().optional()
13430
13738
  }),
13431
13739
  UpdateFrameworkPackageResultSchema,
13432
13740
  { kind: "mutation", auth: "admin" }
13433
13741
  ),
13742
+ /**
13743
+ * Kicks off a server-side bulk update operation and returns the bulk
13744
+ * id immediately. The operation runs asynchronously; observe progress
13745
+ * via the `AddonsBulkUpdateProgress` event or `getBulkUpdateState`.
13746
+ * Items with `isSystem: true` use `deferRestart` — the hub restarts
13747
+ * ONCE at the end of the system phase, after all system packages are
13748
+ * installed.
13749
+ *
13750
+ * `items[].version` is REQUIRED — callers must pass the resolved
13751
+ * version from `listUpdates`. There is no `'latest'` default here
13752
+ * (unlike `updatePackage`) to guarantee deterministic bulk rolls.
13753
+ */
13754
+ startBulkUpdate: method(
13755
+ object({
13756
+ nodeId: string(),
13757
+ items: array(object({
13758
+ name: string(),
13759
+ version: string(),
13760
+ isSystem: boolean()
13761
+ })).readonly()
13762
+ }),
13763
+ object({ id: string() }),
13764
+ { kind: "mutation", auth: "admin" }
13765
+ ),
13766
+ /**
13767
+ * Returns the current state of a bulk update by id.
13768
+ * Returns `null` if the id is unknown or has been auto-cleaned
13769
+ * (5 minutes after `completedAt` the record is evicted from memory).
13770
+ */
13771
+ getBulkUpdateState: method(
13772
+ object({ id: string() }),
13773
+ BulkUpdateStateSchema.nullable(),
13774
+ { auth: "admin" }
13775
+ ),
13776
+ /**
13777
+ * Cancels an in-flight bulk update. The update loop exits after the
13778
+ * currently-processing item completes — cancellation is not
13779
+ * instantaneous. Has no effect once the `restarting` phase has been
13780
+ * entered (the hub is already shutting down at that point).
13781
+ * Returns `{ cancelled: false }` if the id is unknown, the operation
13782
+ * has already completed, or the `restarting` phase is active.
13783
+ */
13784
+ cancelBulkUpdate: method(
13785
+ object({ id: string() }),
13786
+ object({ cancelled: boolean() }),
13787
+ { kind: "mutation", auth: "admin" }
13788
+ ),
13789
+ /**
13790
+ * Lists all currently active (non-completed) bulk updates.
13791
+ * If `nodeId` is provided, filters to only bulk updates targeting
13792
+ * that node. Useful for restoring an in-progress banner on a fresh
13793
+ * page load when the UI reconnects mid-operation.
13794
+ */
13795
+ listActiveBulkUpdates: method(
13796
+ object({ nodeId: string().optional() }),
13797
+ array(BulkUpdateStateSchema).readonly(),
13798
+ { auth: "admin" }
13799
+ ),
13434
13800
  getVersions: method(
13435
13801
  object({ name: string() }),
13436
13802
  array(PackageVersionInfoSchema).readonly()
@@ -13558,6 +13924,7 @@ var EventCategory = /* @__PURE__ */ ((EventCategory2) => {
13558
13924
  EventCategory2["StreamBrokerOnCamStreamDemand"] = "stream-broker.onCamStreamDemand";
13559
13925
  EventCategory2["StreamBrokerOnCamStreamIdle"] = "stream-broker.onCamStreamIdle";
13560
13926
  EventCategory2["StreamBrokerOnRequestStreamSourceRefresh"] = "stream-broker.onRequestStreamSourceRefresh";
13927
+ EventCategory2["StreamParamsChanged"] = "stream-params.changed";
13561
13928
  EventCategory2["DeviceStateChanged"] = "device.state-changed";
13562
13929
  EventCategory2["BatteryOnStatusChanged"] = "battery.onStatusChanged";
13563
13930
  EventCategory2["DoorbellOnPressed"] = "doorbell.onPressed";
@@ -13605,6 +13972,7 @@ var EventCategory = /* @__PURE__ */ ((EventCategory2) => {
13605
13972
  EventCategory2["NetworkTunnelStarted"] = "network.tunnel.started";
13606
13973
  EventCategory2["NetworkTunnelStopped"] = "network.tunnel.stopped";
13607
13974
  EventCategory2["LocalNetworkChanged"] = "network.local.changed";
13975
+ EventCategory2["MeshNetworkChanged"] = "network.mesh.changed";
13608
13976
  EventCategory2["BackupCompleted"] = "backup.completed";
13609
13977
  EventCategory2["BackupRestored"] = "backup.restored";
13610
13978
  EventCategory2["NotificationDispatched"] = "notification.dispatched";
@@ -13615,6 +13983,7 @@ var EventCategory = /* @__PURE__ */ ((EventCategory2) => {
13615
13983
  EventCategory2["DeviceAwake"] = "device.awake";
13616
13984
  EventCategory2["DeviceSleeping"] = "device.sleeping";
13617
13985
  EventCategory2["RetentionCleanup"] = "retention.cleanup";
13986
+ EventCategory2["AddonsBulkUpdateProgress"] = "addons.bulk-update-progress";
13618
13987
  return EventCategory2;
13619
13988
  })(EventCategory || {});
13620
13989
  function createEvent(category, source, data) {
@@ -13764,7 +14133,7 @@ class BaseAddon {
13764
14133
  }
13765
14134
  // ── Settings schemas (override to provide UI) ─────────────────────────
13766
14135
  /** Override to provide global-level settings UI schema. */
13767
- globalSettingsSchema() {
14136
+ globalSettingsSchema(_cap) {
13768
14137
  return null;
13769
14138
  }
13770
14139
  /** Override to provide device-level settings UI schema. */
@@ -13778,8 +14147,8 @@ class BaseAddon {
13778
14147
  // blob and every addon used exactly one of them; the distinction was
13779
14148
  // never semantically load-bearing. `global` won because it was the
13780
14149
  // widely-used one and the name reads naturally (per-node addon config).
13781
- async getGlobalSettings(overlay) {
13782
- const schema = this.globalSettingsSchema();
14150
+ async getGlobalSettings(overlay, cap) {
14151
+ const schema = this.globalSettingsSchema(cap);
13783
14152
  if (!schema) return { sections: [] };
13784
14153
  const raw = await this._ctx?.settings?.readAddonStore() ?? {};
13785
14154
  return hydrateSchema(schema, overlay ? { ...raw, ...overlay } : raw);
@@ -14311,4 +14680,4 @@ export {
14311
14680
  DEFAULT_AUDIO_ANALYZER_CONFIG as y,
14312
14681
  AUDIO_BACKEND_CHOICES as z
14313
14682
  };
14314
- //# sourceMappingURL=index-asZs8U_s.mjs.map
14683
+ //# sourceMappingURL=index-Bmlkm0Fd.mjs.map