@camstack/addon-pipeline 0.1.17 → 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-p-6GfKOg.js → index-BbPPvoCx.js} +469 -57
  14. package/dist/index-BbPPvoCx.js.map +1 -0
  15. package/dist/{index-CVzLrojg.mjs → index-Bmlkm0Fd.mjs} +469 -57
  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-Sx8tgpFZ.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-D0jPgChu.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-BCEx31Mh.mjs → index-Dy2V7VOm.mjs} +3808 -3277
  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-CVzLrojg.mjs.map +0 -1
  49. package/dist/index-p-6GfKOg.js.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
@@ -4779,6 +4779,16 @@ function record(keyType, valueType, params) {
4779
4779
  ...normalizeParams(params)
4780
4780
  });
4781
4781
  }
4782
+ function partialRecord(keyType, valueType, params) {
4783
+ const k = clone(keyType);
4784
+ k._zod.values = void 0;
4785
+ return new ZodRecord({
4786
+ type: "record",
4787
+ keyType: k,
4788
+ valueType,
4789
+ ...normalizeParams(params)
4790
+ });
4791
+ }
4782
4792
  const ZodEnum = /* @__PURE__ */ $constructor("ZodEnum", (inst, def) => {
4783
4793
  $ZodEnum.init(inst, def);
4784
4794
  ZodType.init(inst, def);
@@ -5055,6 +5065,37 @@ function _instanceof(cls, params = {}) {
5055
5065
  };
5056
5066
  return inst;
5057
5067
  }
5068
+ const wiringProbeKindSchema = _enum(["singleton", "device", "widget"]);
5069
+ const wiringProbeResultSchema = object({
5070
+ capName: string(),
5071
+ kind: wiringProbeKindSchema,
5072
+ deviceId: number().optional(),
5073
+ reachable: boolean(),
5074
+ latencyMs: number(),
5075
+ error: string().optional()
5076
+ });
5077
+ const wiringAddonHealthSchema = object({
5078
+ addonId: string(),
5079
+ caps: array(wiringProbeResultSchema).readonly(),
5080
+ widgets: array(wiringProbeResultSchema).readonly()
5081
+ });
5082
+ const wiringNodeHealthSchema = object({
5083
+ nodeId: string(),
5084
+ addons: array(wiringAddonHealthSchema).readonly()
5085
+ });
5086
+ object({
5087
+ /** True only when every probed target is reachable. */
5088
+ ok: boolean(),
5089
+ /** True when at least one target is unreachable. */
5090
+ degraded: boolean(),
5091
+ checkedAt: string(),
5092
+ nodes: array(wiringNodeHealthSchema).readonly(),
5093
+ summary: object({
5094
+ total: number(),
5095
+ reachable: number(),
5096
+ unreachable: number()
5097
+ })
5098
+ });
5058
5099
  const MODEL_FORMATS = ["onnx", "coreml", "openvino", "tflite", "pt"];
5059
5100
  const WELL_KNOWN_TABS = [
5060
5101
  { id: "overview", label: "Overview", icon: "layout-dashboard", order: -10 },
@@ -6619,7 +6660,7 @@ const SpatialDetectionSchema = object({
6619
6660
  bbox: BoundingBoxSchema
6620
6661
  });
6621
6662
  const AudioChunkInputSchema = object({
6622
- data: _instanceof(Float32Array),
6663
+ data: _instanceof(Uint8Array),
6623
6664
  sampleRate: number(),
6624
6665
  channels: number(),
6625
6666
  timestamp: number(),
@@ -7299,7 +7340,23 @@ const RunnerCameraConfigSchema = object({
7299
7340
  * whenever its `zones` device-state slice changes, so the runner's
7300
7341
  * copy stays in sync. Empty array → no zone filtering.
7301
7342
  */
7302
- zones: array(ZoneSchema).readonly().default([])
7343
+ zones: array(ZoneSchema).readonly().default([]),
7344
+ /**
7345
+ * When true (default) and the camera's `motionSources` contains only
7346
+ * `'onboard'`, the runner dynamically opens the same WASM frame-diff
7347
+ * motion-frames subscription on each `MotionOnMotionChanged
7348
+ * source:'onboard'` event and tears it down after `motionCooldownMs`.
7349
+ * This causes `runMotionAnalysis` to emit `MotionZonesRaw` /
7350
+ * `MotionAnalysis` during active-motion windows without the
7351
+ * substream being held open continuously.
7352
+ *
7353
+ * Set to `false` to disable the dynamic analyzer for this camera
7354
+ * (e.g. very low-bandwidth links where the extra substream is
7355
+ * undesirable). Has no effect when `motionSources` already includes
7356
+ * `'analyzer'` — the analyzer runs continuously in that case and
7357
+ * this gate is bypassed.
7358
+ */
7359
+ onboardMotionDrivesAnalyzer: boolean().default(true)
7303
7360
  });
7304
7361
  const RunnerLocalLoadSchema = object({
7305
7362
  /** Moleculer node id of this runner instance. */
@@ -7439,22 +7496,68 @@ MotionTriggerStatusSchema.extend({
7439
7496
  }) }
7440
7497
  }
7441
7498
  });
7499
+ const MaskPointSchema = object({
7500
+ x: number(),
7501
+ y: number()
7502
+ });
7503
+ const MaskRectShapeSchema = object({
7504
+ kind: literal("rect"),
7505
+ x: number(),
7506
+ y: number(),
7507
+ width: number(),
7508
+ height: number()
7509
+ });
7510
+ const MaskPolygonShapeSchema = object({
7511
+ kind: literal("polygon"),
7512
+ points: array(MaskPointSchema)
7513
+ });
7514
+ const MaskGridShapeSchema = object({
7515
+ kind: literal("grid"),
7516
+ gridWidth: number(),
7517
+ gridHeight: number(),
7518
+ cells: array(boolean())
7519
+ });
7520
+ const MaskLineShapeSchema = object({
7521
+ kind: literal("line"),
7522
+ points: array(MaskPointSchema)
7523
+ });
7524
+ discriminatedUnion("kind", [
7525
+ MaskRectShapeSchema,
7526
+ MaskPolygonShapeSchema,
7527
+ MaskGridShapeSchema,
7528
+ MaskLineShapeSchema
7529
+ ]);
7530
+ const MaskShapeKindSchema = _enum(["rect", "polygon", "grid", "line"]);
7531
+ const MaskPolygonVerticesSchema = object({
7532
+ min: number(),
7533
+ max: number()
7534
+ });
7535
+ const MaskGridDimsSchema = object({
7536
+ width: number(),
7537
+ height: number()
7538
+ });
7539
+ const MotionZoneRegionSchema = object({
7540
+ id: number(),
7541
+ enabled: boolean(),
7542
+ shape: MaskGridShapeSchema
7543
+ });
7442
7544
  object({
7443
7545
  enabled: boolean(),
7444
7546
  sensitivity: number(),
7445
- /** Row-major active-cell grid. Length = gridWidth*gridHeight (see getOptions). */
7446
- cells: array(boolean()),
7547
+ /** Grid region(s). Today exactly one `grid` shape. */
7548
+ regions: array(MotionZoneRegionSchema),
7447
7549
  lastFetchedAt: number()
7448
7550
  });
7449
7551
  const MotionZoneOptionsSchema = object({
7450
- gridWidth: number(),
7451
- gridHeight: number(),
7552
+ maxRegions: number(),
7553
+ supportedShapes: array(MaskShapeKindSchema),
7554
+ grid: MaskGridDimsSchema,
7452
7555
  sensitivity: object({ min: number(), max: number(), step: number() })
7453
7556
  });
7454
7557
  const MotionZonePatchSchema = object({
7455
7558
  enabled: boolean().optional(),
7456
7559
  sensitivity: number().optional(),
7457
- cells: array(boolean()).optional()
7560
+ regions: array(MotionZoneRegionSchema).optional()
7458
7561
  });
7459
7562
  ({
7460
7563
  deviceTypes: [DeviceType.Camera],
@@ -7467,6 +7570,102 @@ const MotionZonePatchSchema = object({
7467
7570
  )
7468
7571
  }
7469
7572
  });
7573
+ const NativeObjectClassEnum = _enum([
7574
+ "person",
7575
+ "vehicle",
7576
+ "animal",
7577
+ "face",
7578
+ "package",
7579
+ "other"
7580
+ ]);
7581
+ const NativeDetectionSchema = object({
7582
+ class: NativeObjectClassEnum,
7583
+ timestamp: number(),
7584
+ /** Firmware-provided confidence [0..1]. Reolink pushes don't carry it → undefined. */
7585
+ confidence: number().min(0).max(1).optional()
7586
+ });
7587
+ const NativeObjectDetectionStatusSchema = object({
7588
+ /**
7589
+ * Last observed instance per class. Missing entries mean the class
7590
+ * is supported but nothing has been seen since the provider started.
7591
+ *
7592
+ * MUST be a partial record: providers seed an empty `{}` on cold-start
7593
+ * and write one class at a time as detections arrive. In Zod 4
7594
+ * `z.record(enum, …)` is EXHAUSTIVE (requires every enum key), so a
7595
+ * partial write throws "expected object, received undefined" for every
7596
+ * unseen class. `z.partialRecord` keeps the enum-key narrowing while
7597
+ * allowing the sparse shape the providers actually write.
7598
+ */
7599
+ lastByClass: partialRecord(NativeObjectClassEnum, NativeDetectionSchema.nullable()),
7600
+ /** Classes the firmware is capable of detecting — enumerated at device register. */
7601
+ supportedClasses: array(NativeObjectClassEnum).readonly(),
7602
+ /**
7603
+ * Whether forwarding of onboard AI detections is enabled for this device.
7604
+ * Default true (on cold-start) — detections flow unconditionally before
7605
+ * the toggle is saved, so defaulting true preserves existing behaviour.
7606
+ */
7607
+ enabled: boolean()
7608
+ });
7609
+ NativeObjectDetectionStatusSchema.extend({
7610
+ /** Required by createRuntimeStateBridge — epoch ms of last refresh. */
7611
+ lastFetchedAt: number()
7612
+ });
7613
+ ({
7614
+ deviceTypes: [DeviceType.Camera],
7615
+ methods: {
7616
+ setEnabled: method(
7617
+ object({ deviceId: number(), enabled: boolean() }),
7618
+ _void(),
7619
+ { kind: "mutation", auth: "admin" }
7620
+ )
7621
+ },
7622
+ events: {
7623
+ onDetected: { data: object({
7624
+ deviceId: number(),
7625
+ detection: NativeDetectionSchema
7626
+ }) }
7627
+ }
7628
+ });
7629
+ const PrivacyMaskShapeSchema = discriminatedUnion("kind", [
7630
+ MaskRectShapeSchema,
7631
+ MaskPolygonShapeSchema
7632
+ ]);
7633
+ const PrivacyMaskRegionSchema = object({
7634
+ /** Slot id, 0-based. Stable across read/write. */
7635
+ id: number(),
7636
+ /** Whether this zone is active (blanked out by the camera). */
7637
+ enabled: boolean(),
7638
+ shape: PrivacyMaskShapeSchema
7639
+ });
7640
+ object({
7641
+ enabled: boolean(),
7642
+ /** Active zones (normalized 0..1). Length ≤ maxRegions. */
7643
+ regions: array(PrivacyMaskRegionSchema),
7644
+ lastFetchedAt: number()
7645
+ });
7646
+ const PrivacyMaskOptionsSchema = object({
7647
+ /** Maximum number of supported zones. */
7648
+ maxRegions: number(),
7649
+ /** Shape kinds this camera accepts — Reolink: ['rect']; Hikvision: ['rect','polygon']. */
7650
+ supportedShapes: array(MaskShapeKindSchema),
7651
+ /** Polygon vertex bounds when 'polygon' is supported (Hikvision: {min:4,max:4}). */
7652
+ polygonVertices: MaskPolygonVerticesSchema.optional()
7653
+ });
7654
+ const PrivacyMaskPatchSchema = object({
7655
+ enabled: boolean().optional(),
7656
+ regions: array(PrivacyMaskRegionSchema).optional()
7657
+ });
7658
+ ({
7659
+ deviceTypes: [DeviceType.Camera],
7660
+ methods: {
7661
+ getOptions: method(object({ deviceId: number() }), PrivacyMaskOptionsSchema),
7662
+ setMask: method(
7663
+ object({ deviceId: number(), patch: PrivacyMaskPatchSchema }),
7664
+ _void(),
7665
+ { kind: "mutation", auth: "admin" }
7666
+ )
7667
+ }
7668
+ });
7470
7669
  const AutotrackTargetTypeSchema = string().describe("Vendor target string (people/vehicle/pet); empty = camera default");
7471
7670
  const PtzAutotrackSettingsSchema = object({
7472
7671
  targetType: AutotrackTargetTypeSchema,
@@ -7985,7 +8184,8 @@ const SettingsUpdateResultSchema = object({
7985
8184
  object({
7986
8185
  addonId: string(),
7987
8186
  nodeId: string().optional(),
7988
- overlay: record(string(), unknown()).optional()
8187
+ overlay: record(string(), unknown()).optional(),
8188
+ cap: string().optional()
7989
8189
  }),
7990
8190
  SettingsSchemaWithValuesSchema.nullable()
7991
8191
  ),
@@ -8716,7 +8916,14 @@ const OauthIntegrationDescriptorSchema = object({
8716
8916
  /** Allowed redirect_uri prefixes. /api/oauth2/authorize rejects any
8717
8917
  * redirect_uri that does not start with one of these. Required —
8718
8918
  * an empty list means the integration can never complete linking. */
8719
- allowedRedirectPrefixes: array(string()).min(1)
8919
+ allowedRedirectPrefixes: array(string()).min(1),
8920
+ /** Optional public origin (no trailing slash) that this integration's
8921
+ * issued codes/tokens should carry as the `hubUrl` claim — typically the
8922
+ * operator-selected external-access endpoint resolved by the addon. When
8923
+ * present, /api/oauth2/authorize bakes THIS into the code instead of the
8924
+ * hub-global `publicHubUrl()`, so a forked exporter addon (which can't set
8925
+ * the hub's env) drives the claim that its cloud Lambda routes back on. */
8926
+ hubUrl: string().optional()
8720
8927
  });
8721
8928
  ({
8722
8929
  methods: {
@@ -9366,7 +9573,20 @@ const webrtcSessionCapability = {
9366
9573
  object({
9367
9574
  deviceId: number().int().nonnegative(),
9368
9575
  target: WebrtcStreamTargetSchema,
9369
- hints: webrtcClientHintsSchema.optional()
9576
+ hints: webrtcClientHintsSchema.optional(),
9577
+ /**
9578
+ * SERVER-INJECTED — NOT a client hint. The hub layer that holds
9579
+ * the tRPC request context (and therefore the client IP) sets
9580
+ * this to `true` when the viewer's source IP is non-LAN
9581
+ * (4G/CGNAT/internet). The broker then forces TURN-relay-only
9582
+ * ICE for the session so a CGNAT client (which can only offer a
9583
+ * relay candidate) gets a clean relay↔relay media path instead
9584
+ * of werift nominating a dead host/hairpin-srflx pair. LAN
9585
+ * clients leave this absent/false and keep the low-latency
9586
+ * direct (host/srflx) path. Clients MUST NOT send this — the
9587
+ * server overwrites it from the request context.
9588
+ */
9589
+ relayOnly: boolean().optional()
9370
9590
  }),
9371
9591
  object({ sessionId: string(), sdpOffer: string() }),
9372
9592
  { kind: "mutation" }
@@ -9389,7 +9609,22 @@ const webrtcSessionCapability = {
9389
9609
  deviceId: number().int().nonnegative(),
9390
9610
  target: WebrtcStreamTargetSchema.optional(),
9391
9611
  sdpOffer: string(),
9392
- sessionId: string().optional()
9612
+ sessionId: string().optional(),
9613
+ /**
9614
+ * Force TURN-relay-only ICE for this session. Two kinds of caller
9615
+ * set it:
9616
+ * - A cloud peer like Alexa's RTCSessionController (reachable
9617
+ * only via TURN, never our host/srflx behind NAT) passes
9618
+ * `true` from its own trusted addon context.
9619
+ * - The hub injects it for browser client-offer viewers from the
9620
+ * request's source IP (non-LAN ⇒ true), exactly as it does for
9621
+ * `createSession`.
9622
+ * A LAN/Tailscale browser doing client-offer passthrough leaves it
9623
+ * absent/false so a direct host pair carries full native quality.
9624
+ * Untrusted browser clients MUST NOT send it — the hub overwrites
9625
+ * it from the request context.
9626
+ */
9627
+ relayOnly: boolean().optional()
9393
9628
  }),
9394
9629
  object({ sessionId: string(), sdpAnswer: string() }),
9395
9630
  { kind: "mutation" }
@@ -9403,6 +9638,46 @@ const webrtcSessionCapability = {
9403
9638
  _void(),
9404
9639
  { kind: "mutation" }
9405
9640
  ),
9641
+ /**
9642
+ * Trickle ICE — add a remote (client) ICE candidate to a live session.
9643
+ * Lets the client send its SDP offer/answer IMMEDIATELY (before ICE
9644
+ * gathering finishes) and deliver candidates as they arrive, so the
9645
+ * connection establishes in ~0s instead of waiting for full gathering.
9646
+ * The dual of `getIceCandidates`. Mirrors Scrypted's signaling.
9647
+ */
9648
+ addIceCandidate: method(
9649
+ object({
9650
+ deviceId: number().int().nonnegative(),
9651
+ sessionId: string(),
9652
+ candidate: string(),
9653
+ sdpMid: string().nullable().optional(),
9654
+ sdpMLineIndex: number().int().nullable().optional()
9655
+ }),
9656
+ _void(),
9657
+ { kind: "mutation" }
9658
+ ),
9659
+ /**
9660
+ * Trickle ICE — poll the server's gathered ICE candidates for a session.
9661
+ * The server answers immediately (no gathering wait) and the client polls
9662
+ * this to receive host/srflx/relay candidates as werift gathers them,
9663
+ * adding each to its PeerConnection. Returns all candidates gathered so
9664
+ * far; the client dedupes. `done` flips true once gathering completes.
9665
+ */
9666
+ getIceCandidates: method(
9667
+ object({
9668
+ deviceId: number().int().nonnegative(),
9669
+ sessionId: string()
9670
+ }),
9671
+ object({
9672
+ candidates: array(object({
9673
+ candidate: string(),
9674
+ sdpMid: string().nullable(),
9675
+ sdpMLineIndex: number().int().nullable()
9676
+ })),
9677
+ done: boolean()
9678
+ }),
9679
+ { kind: "query" }
9680
+ ),
9406
9681
  closeSession: method(
9407
9682
  object({
9408
9683
  deviceId: number().int().nonnegative(),
@@ -11103,6 +11378,9 @@ const detectionPipelineCapability = {
11103
11378
  exposesDeviceSettings: true,
11104
11379
  methods: {}
11105
11380
  };
11381
+ ({
11382
+ deviceTypes: [DeviceType.Camera]
11383
+ });
11106
11384
  const TrackStateSchema = _enum(["new", "entered", "left", "moving", "idle"]);
11107
11385
  const EventKindSchema = _enum(["motion", "object", "audio"]);
11108
11386
  const TrackPositionSchema = object({
@@ -11930,36 +12208,28 @@ const IntercomStatusSchema = object({
11930
12208
  }) }
11931
12209
  }
11932
12210
  });
11933
- const NativeObjectClassEnum = _enum([
11934
- "person",
11935
- "vehicle",
11936
- "animal",
11937
- "face",
11938
- "package",
11939
- "other"
11940
- ]);
11941
- const NativeDetectionSchema = object({
11942
- class: NativeObjectClassEnum,
11943
- timestamp: number(),
11944
- /** Firmware-provided confidence [0..1]. Reolink pushes don't carry it → undefined. */
11945
- confidence: number().min(0).max(1).optional()
11946
- });
11947
- object({
11948
- /**
11949
- * Last observed instance per class. Undefined entries mean the class
11950
- * is supported but nothing has been seen since the provider started.
11951
- */
11952
- lastByClass: record(NativeObjectClassEnum, NativeDetectionSchema.nullable()),
11953
- /** Classes the firmware is capable of detecting — enumerated at device register. */
11954
- supportedClasses: array(NativeObjectClassEnum).readonly()
12211
+ const CamStreamDescriptorSchema = object({
12212
+ camStreamId: string().min(1),
12213
+ kind: CamStreamKindSchema,
12214
+ url: string().optional(),
12215
+ codec: string().optional(),
12216
+ resolution: CamStreamResolutionSchema.optional(),
12217
+ fps: number().positive().optional(),
12218
+ label: string().optional(),
12219
+ /** Device-level features (e.g. `battery-operated`) — drives broker policy. */
12220
+ deviceFeatures: array(string()).optional(),
12221
+ /** Eligible for automatic profile assignment. Absent = `true`. */
12222
+ autoEligible: boolean().optional(),
12223
+ /** Transport-specific opaque metadata (e.g. rfc4571 SDP). */
12224
+ metadata: record(string(), unknown()).optional()
11955
12225
  });
11956
12226
  ({
11957
12227
  deviceTypes: [DeviceType.Camera],
11958
- events: {
11959
- onDetected: { data: object({
11960
- deviceId: number(),
11961
- detection: NativeDetectionSchema
11962
- }) }
12228
+ methods: {
12229
+ getCatalog: method(
12230
+ object({ deviceId: number().int().nonnegative() }),
12231
+ array(CamStreamDescriptorSchema).readonly()
12232
+ )
11963
12233
  }
11964
12234
  });
11965
12235
  const ModelFormatSchema = _enum(MODEL_FORMATS);
@@ -12827,6 +13097,18 @@ const TopologyProcessSchema = object({
12827
13097
  services: array(TopologyServiceSchema).readonly(),
12828
13098
  groupId: string().optional()
12829
13099
  });
13100
+ const TopologyCategoryAddonSchema = object({
13101
+ id: string(),
13102
+ status: string(),
13103
+ cpuPercent: number(),
13104
+ memoryRss: number()
13105
+ });
13106
+ const TopologyCategorySchema = object({
13107
+ category: string(),
13108
+ total: number(),
13109
+ healthy: number(),
13110
+ addons: array(TopologyCategoryAddonSchema).readonly()
13111
+ });
12830
13112
  const TopologyNodeSchema = object({
12831
13113
  id: string(),
12832
13114
  name: string(),
@@ -12851,7 +13133,15 @@ const TopologyNodeSchema = object({
12851
13133
  status: string()
12852
13134
  })
12853
13135
  ).readonly(),
12854
- processes: array(TopologyProcessSchema).readonly()
13136
+ processes: array(TopologyProcessSchema).readonly(),
13137
+ categories: array(TopologyCategorySchema).readonly()
13138
+ });
13139
+ const CapUsageEdgeSchema = object({
13140
+ callerAddonId: string(),
13141
+ providerAddonId: string(),
13142
+ capName: string(),
13143
+ callsPerMin: number(),
13144
+ lastCallAtMs: number()
12855
13145
  });
12856
13146
  const ClusterAddonNodeDeploymentSchema = object({
12857
13147
  nodeId: string(),
@@ -12935,13 +13225,7 @@ const RenameNodeResultSchema = object({
12935
13225
  object({
12936
13226
  windowSeconds: number().int().positive().max(300).default(60)
12937
13227
  }),
12938
- array(object({
12939
- callerAddonId: string(),
12940
- providerAddonId: string(),
12941
- capName: string(),
12942
- callsPerMin: number(),
12943
- lastCallAtMs: number()
12944
- })).readonly(),
13228
+ array(CapUsageEdgeSchema).readonly(),
12945
13229
  { auth: "admin" }
12946
13230
  ),
12947
13231
  /**
@@ -13153,7 +13437,8 @@ const PackageUpdateSchema = object({
13153
13437
  currentVersion: string(),
13154
13438
  latestVersion: string(),
13155
13439
  category: _enum(["addon", "core"]),
13156
- requiresRestart: boolean()
13440
+ requiresRestart: boolean(),
13441
+ isSystem: boolean()
13157
13442
  });
13158
13443
  const PackageVersionInfoSchema = object({
13159
13444
  version: string(),
@@ -13186,6 +13471,42 @@ const UpdateFrameworkPackageResultSchema = object({
13186
13471
  /** Ms-epoch the server scheduled its self-restart. */
13187
13472
  restartingAt: number()
13188
13473
  });
13474
+ const BulkUpdateItemStatusSchema = _enum([
13475
+ "queued",
13476
+ "updating",
13477
+ "done",
13478
+ "done-pending-restart",
13479
+ "failed"
13480
+ ]);
13481
+ const BulkUpdateItemSchema = object({
13482
+ name: string(),
13483
+ isSystem: boolean(),
13484
+ fromVersion: string(),
13485
+ toVersion: string(),
13486
+ status: BulkUpdateItemStatusSchema,
13487
+ error: string().optional(),
13488
+ startedAtMs: number().optional(),
13489
+ completedAtMs: number().optional()
13490
+ });
13491
+ const BulkUpdatePhaseSchema = _enum([
13492
+ "regular",
13493
+ "system",
13494
+ "restarting",
13495
+ "finalizing"
13496
+ ]);
13497
+ const BulkUpdateStateSchema = object({
13498
+ id: string(),
13499
+ nodeId: string(),
13500
+ startedAtMs: number(),
13501
+ completedAtMs: number().optional(),
13502
+ total: number(),
13503
+ completed: number(),
13504
+ failed: number(),
13505
+ current: string().nullable(),
13506
+ phase: BulkUpdatePhaseSchema,
13507
+ cancelled: boolean(),
13508
+ items: array(BulkUpdateItemSchema).readonly()
13509
+ });
13189
13510
  const FrameworkPackageStatusSchema = object({
13190
13511
  packageName: string(),
13191
13512
  currentVersion: string(),
@@ -13323,7 +13644,7 @@ const CustomActionInputSchema = object({
13323
13644
  getLastRestart: method(
13324
13645
  _void(),
13325
13646
  object({
13326
- kind: _enum(["framework-update", "manual", "system"]),
13647
+ kind: _enum(["framework-update", "manual", "system", "framework-bulk-update"]),
13327
13648
  packageName: string().optional(),
13328
13649
  fromVersion: string().optional(),
13329
13650
  toVersion: string().optional(),
@@ -13413,11 +13734,70 @@ const CustomActionInputSchema = object({
13413
13734
  updateFrameworkPackage: method(
13414
13735
  object({
13415
13736
  packageName: string().min(1),
13416
- version: string().optional()
13737
+ version: string().optional(),
13738
+ deferRestart: boolean().optional()
13417
13739
  }),
13418
13740
  UpdateFrameworkPackageResultSchema,
13419
13741
  { kind: "mutation", auth: "admin" }
13420
13742
  ),
13743
+ /**
13744
+ * Kicks off a server-side bulk update operation and returns the bulk
13745
+ * id immediately. The operation runs asynchronously; observe progress
13746
+ * via the `AddonsBulkUpdateProgress` event or `getBulkUpdateState`.
13747
+ * Items with `isSystem: true` use `deferRestart` — the hub restarts
13748
+ * ONCE at the end of the system phase, after all system packages are
13749
+ * installed.
13750
+ *
13751
+ * `items[].version` is REQUIRED — callers must pass the resolved
13752
+ * version from `listUpdates`. There is no `'latest'` default here
13753
+ * (unlike `updatePackage`) to guarantee deterministic bulk rolls.
13754
+ */
13755
+ startBulkUpdate: method(
13756
+ object({
13757
+ nodeId: string(),
13758
+ items: array(object({
13759
+ name: string(),
13760
+ version: string(),
13761
+ isSystem: boolean()
13762
+ })).readonly()
13763
+ }),
13764
+ object({ id: string() }),
13765
+ { kind: "mutation", auth: "admin" }
13766
+ ),
13767
+ /**
13768
+ * Returns the current state of a bulk update by id.
13769
+ * Returns `null` if the id is unknown or has been auto-cleaned
13770
+ * (5 minutes after `completedAt` the record is evicted from memory).
13771
+ */
13772
+ getBulkUpdateState: method(
13773
+ object({ id: string() }),
13774
+ BulkUpdateStateSchema.nullable(),
13775
+ { auth: "admin" }
13776
+ ),
13777
+ /**
13778
+ * Cancels an in-flight bulk update. The update loop exits after the
13779
+ * currently-processing item completes — cancellation is not
13780
+ * instantaneous. Has no effect once the `restarting` phase has been
13781
+ * entered (the hub is already shutting down at that point).
13782
+ * Returns `{ cancelled: false }` if the id is unknown, the operation
13783
+ * has already completed, or the `restarting` phase is active.
13784
+ */
13785
+ cancelBulkUpdate: method(
13786
+ object({ id: string() }),
13787
+ object({ cancelled: boolean() }),
13788
+ { kind: "mutation", auth: "admin" }
13789
+ ),
13790
+ /**
13791
+ * Lists all currently active (non-completed) bulk updates.
13792
+ * If `nodeId` is provided, filters to only bulk updates targeting
13793
+ * that node. Useful for restoring an in-progress banner on a fresh
13794
+ * page load when the UI reconnects mid-operation.
13795
+ */
13796
+ listActiveBulkUpdates: method(
13797
+ object({ nodeId: string().optional() }),
13798
+ array(BulkUpdateStateSchema).readonly(),
13799
+ { auth: "admin" }
13800
+ ),
13421
13801
  getVersions: method(
13422
13802
  object({ name: string() }),
13423
13803
  array(PackageVersionInfoSchema).readonly()
@@ -13545,6 +13925,7 @@ var EventCategory = /* @__PURE__ */ ((EventCategory2) => {
13545
13925
  EventCategory2["StreamBrokerOnCamStreamDemand"] = "stream-broker.onCamStreamDemand";
13546
13926
  EventCategory2["StreamBrokerOnCamStreamIdle"] = "stream-broker.onCamStreamIdle";
13547
13927
  EventCategory2["StreamBrokerOnRequestStreamSourceRefresh"] = "stream-broker.onRequestStreamSourceRefresh";
13928
+ EventCategory2["StreamParamsChanged"] = "stream-params.changed";
13548
13929
  EventCategory2["DeviceStateChanged"] = "device.state-changed";
13549
13930
  EventCategory2["BatteryOnStatusChanged"] = "battery.onStatusChanged";
13550
13931
  EventCategory2["DoorbellOnPressed"] = "doorbell.onPressed";
@@ -13592,6 +13973,7 @@ var EventCategory = /* @__PURE__ */ ((EventCategory2) => {
13592
13973
  EventCategory2["NetworkTunnelStarted"] = "network.tunnel.started";
13593
13974
  EventCategory2["NetworkTunnelStopped"] = "network.tunnel.stopped";
13594
13975
  EventCategory2["LocalNetworkChanged"] = "network.local.changed";
13976
+ EventCategory2["MeshNetworkChanged"] = "network.mesh.changed";
13595
13977
  EventCategory2["BackupCompleted"] = "backup.completed";
13596
13978
  EventCategory2["BackupRestored"] = "backup.restored";
13597
13979
  EventCategory2["NotificationDispatched"] = "notification.dispatched";
@@ -13602,6 +13984,7 @@ var EventCategory = /* @__PURE__ */ ((EventCategory2) => {
13602
13984
  EventCategory2["DeviceAwake"] = "device.awake";
13603
13985
  EventCategory2["DeviceSleeping"] = "device.sleeping";
13604
13986
  EventCategory2["RetentionCleanup"] = "retention.cleanup";
13987
+ EventCategory2["AddonsBulkUpdateProgress"] = "addons.bulk-update-progress";
13605
13988
  return EventCategory2;
13606
13989
  })(EventCategory || {});
13607
13990
  function createEvent(category, source, data) {
@@ -13751,7 +14134,7 @@ class BaseAddon {
13751
14134
  }
13752
14135
  // ── Settings schemas (override to provide UI) ─────────────────────────
13753
14136
  /** Override to provide global-level settings UI schema. */
13754
- globalSettingsSchema() {
14137
+ globalSettingsSchema(_cap) {
13755
14138
  return null;
13756
14139
  }
13757
14140
  /** Override to provide device-level settings UI schema. */
@@ -13765,8 +14148,8 @@ class BaseAddon {
13765
14148
  // blob and every addon used exactly one of them; the distinction was
13766
14149
  // never semantically load-bearing. `global` won because it was the
13767
14150
  // widely-used one and the name reads naturally (per-node addon config).
13768
- async getGlobalSettings(overlay) {
13769
- const schema = this.globalSettingsSchema();
14151
+ async getGlobalSettings(overlay, cap) {
14152
+ const schema = this.globalSettingsSchema(cap);
13770
14153
  if (!schema) return { sections: [] };
13771
14154
  const raw = await this._ctx?.settings?.readAddonStore() ?? {};
13772
14155
  return hydrateSchema(schema, overlay ? { ...raw, ...overlay } : raw);
@@ -14177,13 +14560,42 @@ function customAction(input, output, options) {
14177
14560
  scope: options?.scope ?? { kind: "system" }
14178
14561
  };
14179
14562
  }
14563
+ const CREDENTIAL_PARAM_PATTERNS = [
14564
+ /^user$/i,
14565
+ /^usr$/i,
14566
+ /^username$/i,
14567
+ /^password$/i,
14568
+ /^pwd$/i,
14569
+ /^pass$/i,
14570
+ /^passwd$/i,
14571
+ /^secret$/i,
14572
+ /^token$/i,
14573
+ /^auth$/i,
14574
+ /^auth[_-]?token$/i,
14575
+ /^bearer$/i,
14576
+ /^api[_-]?key$/i,
14577
+ /^access[_-]?token$/i,
14578
+ /^refresh[_-]?token$/i
14579
+ ];
14580
+ function isCredentialParam(name) {
14581
+ return CREDENTIAL_PARAM_PATTERNS.some((re) => re.test(name));
14582
+ }
14180
14583
  function maskUrlCredentials(rawUrl) {
14181
14584
  try {
14182
14585
  const u = new URL(rawUrl);
14183
- if (!u.username && !u.password) return rawUrl;
14184
- u.username = "";
14185
- u.password = "";
14186
- return u.toString();
14586
+ let touched = false;
14587
+ if (u.username || u.password) {
14588
+ u.username = "";
14589
+ u.password = "";
14590
+ touched = true;
14591
+ }
14592
+ for (const key of [...u.searchParams.keys()]) {
14593
+ if (isCredentialParam(key)) {
14594
+ u.searchParams.set(key, "***");
14595
+ touched = true;
14596
+ }
14597
+ }
14598
+ return touched ? u.toString() : rawUrl;
14187
14599
  } catch {
14188
14600
  return rawUrl;
14189
14601
  }
@@ -14267,4 +14679,4 @@ exports.pipelineRunnerCapability = pipelineRunnerCapability;
14267
14679
  exports.streamBrokerCapability = streamBrokerCapability;
14268
14680
  exports.string = string;
14269
14681
  exports.webrtcSessionCapability = webrtcSessionCapability;
14270
- //# sourceMappingURL=index-p-6GfKOg.js.map
14682
+ //# sourceMappingURL=index-BbPPvoCx.js.map