@camstack/addon-post-analysis 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 (42) hide show
  1. package/dist/embedding-encoder/index.js +1 -1
  2. package/dist/embedding-encoder/index.mjs +1 -1
  3. package/dist/enrichment-engine/index.js +1 -1
  4. package/dist/enrichment-engine/index.mjs +1 -1
  5. package/dist/{index-DafwGlkQ.js → index-BFbwYH1P.js} +414 -45
  6. package/dist/index-BFbwYH1P.js.map +1 -0
  7. package/dist/{index-CIJfmsWX.mjs → index-BrTlzsrE.mjs} +414 -45
  8. package/dist/index-BrTlzsrE.mjs.map +1 -0
  9. package/dist/pipeline-analytics/@mf-types.zip +0 -0
  10. package/dist/pipeline-analytics/__mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.mjs-NjF4kxzW.mjs +19 -0
  11. package/dist/pipeline-analytics/__mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.mjs-7HAAnpQu.mjs +18 -0
  12. package/dist/pipeline-analytics/{__mfe_internal__addon_pipeline_analytics_widgets__loadShare__react__loadShare__.mjs-D-USVuHq.mjs → __mfe_internal__addon_pipeline_analytics_widgets__loadShare__react__loadShare__.mjs-BZTB2scQ.mjs} +2 -1
  13. package/dist/pipeline-analytics/{__mfe_internal__addon_pipeline_analytics_widgets__loadShare__react__loadShare__.mjs_commonjs-proxy-qQCPW8pT.mjs → __mfe_internal__addon_pipeline_analytics_widgets__loadShare__react__loadShare__.mjs_commonjs-proxy-CJO5YKGV.mjs} +1 -1
  14. package/dist/pipeline-analytics/{__mfe_internal__addon_pipeline_analytics_widgets__loadShare__react_mf_2_dom__loadShare__.mjs_commonjs-proxy-Bv9bYz9E.mjs → __mfe_internal__addon_pipeline_analytics_widgets__loadShare__react_mf_2_dom__loadShare__.mjs_commonjs-proxy-B0h0AGOH.mjs} +1 -1
  15. package/dist/pipeline-analytics/_stub.js +2 -2
  16. package/dist/pipeline-analytics/{_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-B3kCe2qM.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-kZBmgzMg.mjs} +6 -6
  17. package/dist/pipeline-analytics/{client-DHmQcIWy.mjs → client-BlxIUpgf.mjs} +2 -2
  18. package/dist/pipeline-analytics/{hostInit-CuWzic_f.mjs → hostInit-qBB1Thhi.mjs} +12 -12
  19. package/dist/pipeline-analytics/{index-CHnXxMRA.mjs → index-BoL0rgZt.mjs} +1 -1
  20. package/dist/pipeline-analytics/{index-DicaGC31.mjs → index-CR1aiZDH.mjs} +1 -1
  21. package/dist/pipeline-analytics/{index-Crs1D0Uu.mjs → index-DlhiA9R0.mjs} +1 -1
  22. package/dist/pipeline-analytics/{index-gpelkpEE.mjs → index-DtdgkNgf.mjs} +1 -1
  23. package/dist/pipeline-analytics/{index-BA65ZJOW.mjs → index-Dw6Q30NI.mjs} +2 -2
  24. package/dist/pipeline-analytics/{index-CUXiTSWS.mjs → index-Dy2V7VOm.mjs} +3775 -3279
  25. package/dist/pipeline-analytics/index-i47purqY.mjs +37880 -0
  26. package/dist/pipeline-analytics/index.js +1 -1
  27. package/dist/pipeline-analytics/index.mjs +1 -1
  28. package/dist/pipeline-analytics/{jsx-runtime-Wcfyyyt4.mjs → jsx-runtime-Dlbl3gpr.mjs} +1 -1
  29. package/dist/pipeline-analytics/remoteEntry.js +1 -1
  30. package/dist/pipeline-analytics/{schemas-ChN4Ih0h.mjs → schemas-ClCuS4qa.mjs} +151 -141
  31. package/dist/recording/index.js +2 -2
  32. package/dist/recording/index.mjs +2 -2
  33. package/dist/{recording-coordinator-BKsM_JGg.js → recording-coordinator-BoGr5moz.js} +2 -2
  34. package/dist/{recording-coordinator-BKsM_JGg.js.map → recording-coordinator-BoGr5moz.js.map} +1 -1
  35. package/dist/{recording-coordinator-Bw3N1gYu.mjs → recording-coordinator-CsYH9LqF.mjs} +2 -2
  36. package/dist/{recording-coordinator-Bw3N1gYu.mjs.map → recording-coordinator-CsYH9LqF.mjs.map} +1 -1
  37. package/package.json +1 -1
  38. package/dist/index-CIJfmsWX.mjs.map +0 -1
  39. package/dist/index-DafwGlkQ.js.map +0 -1
  40. package/dist/pipeline-analytics/__mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_types__loadShare__.mjs-d8PmLbO2.mjs +0 -19
  41. package/dist/pipeline-analytics/__mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.mjs-BcWYbuKp.mjs +0 -18
  42. package/dist/pipeline-analytics/index-gbflFMEY.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 },
@@ -6583,7 +6624,7 @@ const SpatialDetectionSchema = object({
6583
6624
  bbox: BoundingBoxSchema
6584
6625
  });
6585
6626
  const AudioChunkInputSchema = object({
6586
- data: _instanceof(Float32Array),
6627
+ data: _instanceof(Uint8Array),
6587
6628
  sampleRate: number(),
6588
6629
  channels: number(),
6589
6630
  timestamp: number(),
@@ -7254,7 +7295,23 @@ const RunnerCameraConfigSchema = object({
7254
7295
  * whenever its `zones` device-state slice changes, so the runner's
7255
7296
  * copy stays in sync. Empty array → no zone filtering.
7256
7297
  */
7257
- zones: array(ZoneSchema).readonly().default([])
7298
+ zones: array(ZoneSchema).readonly().default([]),
7299
+ /**
7300
+ * When true (default) and the camera's `motionSources` contains only
7301
+ * `'onboard'`, the runner dynamically opens the same WASM frame-diff
7302
+ * motion-frames subscription on each `MotionOnMotionChanged
7303
+ * source:'onboard'` event and tears it down after `motionCooldownMs`.
7304
+ * This causes `runMotionAnalysis` to emit `MotionZonesRaw` /
7305
+ * `MotionAnalysis` during active-motion windows without the
7306
+ * substream being held open continuously.
7307
+ *
7308
+ * Set to `false` to disable the dynamic analyzer for this camera
7309
+ * (e.g. very low-bandwidth links where the extra substream is
7310
+ * undesirable). Has no effect when `motionSources` already includes
7311
+ * `'analyzer'` — the analyzer runs continuously in that case and
7312
+ * this gate is bypassed.
7313
+ */
7314
+ onboardMotionDrivesAnalyzer: boolean().default(true)
7258
7315
  });
7259
7316
  const RunnerLocalLoadSchema = object({
7260
7317
  /** Moleculer node id of this runner instance. */
@@ -7391,22 +7448,68 @@ MotionTriggerStatusSchema.extend({
7391
7448
  }) }
7392
7449
  }
7393
7450
  });
7451
+ const MaskPointSchema = object({
7452
+ x: number(),
7453
+ y: number()
7454
+ });
7455
+ const MaskRectShapeSchema = object({
7456
+ kind: literal("rect"),
7457
+ x: number(),
7458
+ y: number(),
7459
+ width: number(),
7460
+ height: number()
7461
+ });
7462
+ const MaskPolygonShapeSchema = object({
7463
+ kind: literal("polygon"),
7464
+ points: array(MaskPointSchema)
7465
+ });
7466
+ const MaskGridShapeSchema = object({
7467
+ kind: literal("grid"),
7468
+ gridWidth: number(),
7469
+ gridHeight: number(),
7470
+ cells: array(boolean())
7471
+ });
7472
+ const MaskLineShapeSchema = object({
7473
+ kind: literal("line"),
7474
+ points: array(MaskPointSchema)
7475
+ });
7476
+ discriminatedUnion("kind", [
7477
+ MaskRectShapeSchema,
7478
+ MaskPolygonShapeSchema,
7479
+ MaskGridShapeSchema,
7480
+ MaskLineShapeSchema
7481
+ ]);
7482
+ const MaskShapeKindSchema = _enum(["rect", "polygon", "grid", "line"]);
7483
+ const MaskPolygonVerticesSchema = object({
7484
+ min: number(),
7485
+ max: number()
7486
+ });
7487
+ const MaskGridDimsSchema = object({
7488
+ width: number(),
7489
+ height: number()
7490
+ });
7491
+ const MotionZoneRegionSchema = object({
7492
+ id: number(),
7493
+ enabled: boolean(),
7494
+ shape: MaskGridShapeSchema
7495
+ });
7394
7496
  object({
7395
7497
  enabled: boolean(),
7396
7498
  sensitivity: number(),
7397
- /** Row-major active-cell grid. Length = gridWidth*gridHeight (see getOptions). */
7398
- cells: array(boolean()),
7499
+ /** Grid region(s). Today exactly one `grid` shape. */
7500
+ regions: array(MotionZoneRegionSchema),
7399
7501
  lastFetchedAt: number()
7400
7502
  });
7401
7503
  const MotionZoneOptionsSchema = object({
7402
- gridWidth: number(),
7403
- gridHeight: number(),
7504
+ maxRegions: number(),
7505
+ supportedShapes: array(MaskShapeKindSchema),
7506
+ grid: MaskGridDimsSchema,
7404
7507
  sensitivity: object({ min: number(), max: number(), step: number() })
7405
7508
  });
7406
7509
  const MotionZonePatchSchema = object({
7407
7510
  enabled: boolean().optional(),
7408
7511
  sensitivity: number().optional(),
7409
- cells: array(boolean()).optional()
7512
+ regions: array(MotionZoneRegionSchema).optional()
7410
7513
  });
7411
7514
  ({
7412
7515
  deviceTypes: [DeviceType.Camera],
@@ -7419,6 +7522,102 @@ const MotionZonePatchSchema = object({
7419
7522
  )
7420
7523
  }
7421
7524
  });
7525
+ const NativeObjectClassEnum = _enum([
7526
+ "person",
7527
+ "vehicle",
7528
+ "animal",
7529
+ "face",
7530
+ "package",
7531
+ "other"
7532
+ ]);
7533
+ const NativeDetectionSchema = object({
7534
+ class: NativeObjectClassEnum,
7535
+ timestamp: number(),
7536
+ /** Firmware-provided confidence [0..1]. Reolink pushes don't carry it → undefined. */
7537
+ confidence: number().min(0).max(1).optional()
7538
+ });
7539
+ const NativeObjectDetectionStatusSchema = object({
7540
+ /**
7541
+ * Last observed instance per class. Missing entries mean the class
7542
+ * is supported but nothing has been seen since the provider started.
7543
+ *
7544
+ * MUST be a partial record: providers seed an empty `{}` on cold-start
7545
+ * and write one class at a time as detections arrive. In Zod 4
7546
+ * `z.record(enum, …)` is EXHAUSTIVE (requires every enum key), so a
7547
+ * partial write throws "expected object, received undefined" for every
7548
+ * unseen class. `z.partialRecord` keeps the enum-key narrowing while
7549
+ * allowing the sparse shape the providers actually write.
7550
+ */
7551
+ lastByClass: partialRecord(NativeObjectClassEnum, NativeDetectionSchema.nullable()),
7552
+ /** Classes the firmware is capable of detecting — enumerated at device register. */
7553
+ supportedClasses: array(NativeObjectClassEnum).readonly(),
7554
+ /**
7555
+ * Whether forwarding of onboard AI detections is enabled for this device.
7556
+ * Default true (on cold-start) — detections flow unconditionally before
7557
+ * the toggle is saved, so defaulting true preserves existing behaviour.
7558
+ */
7559
+ enabled: boolean()
7560
+ });
7561
+ NativeObjectDetectionStatusSchema.extend({
7562
+ /** Required by createRuntimeStateBridge — epoch ms of last refresh. */
7563
+ lastFetchedAt: number()
7564
+ });
7565
+ ({
7566
+ deviceTypes: [DeviceType.Camera],
7567
+ methods: {
7568
+ setEnabled: method(
7569
+ object({ deviceId: number(), enabled: boolean() }),
7570
+ _void(),
7571
+ { kind: "mutation", auth: "admin" }
7572
+ )
7573
+ },
7574
+ events: {
7575
+ onDetected: { data: object({
7576
+ deviceId: number(),
7577
+ detection: NativeDetectionSchema
7578
+ }) }
7579
+ }
7580
+ });
7581
+ const PrivacyMaskShapeSchema = discriminatedUnion("kind", [
7582
+ MaskRectShapeSchema,
7583
+ MaskPolygonShapeSchema
7584
+ ]);
7585
+ const PrivacyMaskRegionSchema = object({
7586
+ /** Slot id, 0-based. Stable across read/write. */
7587
+ id: number(),
7588
+ /** Whether this zone is active (blanked out by the camera). */
7589
+ enabled: boolean(),
7590
+ shape: PrivacyMaskShapeSchema
7591
+ });
7592
+ object({
7593
+ enabled: boolean(),
7594
+ /** Active zones (normalized 0..1). Length ≤ maxRegions. */
7595
+ regions: array(PrivacyMaskRegionSchema),
7596
+ lastFetchedAt: number()
7597
+ });
7598
+ const PrivacyMaskOptionsSchema = object({
7599
+ /** Maximum number of supported zones. */
7600
+ maxRegions: number(),
7601
+ /** Shape kinds this camera accepts — Reolink: ['rect']; Hikvision: ['rect','polygon']. */
7602
+ supportedShapes: array(MaskShapeKindSchema),
7603
+ /** Polygon vertex bounds when 'polygon' is supported (Hikvision: {min:4,max:4}). */
7604
+ polygonVertices: MaskPolygonVerticesSchema.optional()
7605
+ });
7606
+ const PrivacyMaskPatchSchema = object({
7607
+ enabled: boolean().optional(),
7608
+ regions: array(PrivacyMaskRegionSchema).optional()
7609
+ });
7610
+ ({
7611
+ deviceTypes: [DeviceType.Camera],
7612
+ methods: {
7613
+ getOptions: method(object({ deviceId: number() }), PrivacyMaskOptionsSchema),
7614
+ setMask: method(
7615
+ object({ deviceId: number(), patch: PrivacyMaskPatchSchema }),
7616
+ _void(),
7617
+ { kind: "mutation", auth: "admin" }
7618
+ )
7619
+ }
7620
+ });
7422
7621
  const AutotrackTargetTypeSchema = string().describe("Vendor target string (people/vehicle/pet); empty = camera default");
7423
7622
  const PtzAutotrackSettingsSchema = object({
7424
7623
  targetType: AutotrackTargetTypeSchema,
@@ -7948,7 +8147,8 @@ const SettingsUpdateResultSchema = object({
7948
8147
  object({
7949
8148
  addonId: string(),
7950
8149
  nodeId: string().optional(),
7951
- overlay: record(string(), unknown()).optional()
8150
+ overlay: record(string(), unknown()).optional(),
8151
+ cap: string().optional()
7952
8152
  }),
7953
8153
  SettingsSchemaWithValuesSchema.nullable()
7954
8154
  ),
@@ -8679,7 +8879,14 @@ const OauthIntegrationDescriptorSchema = object({
8679
8879
  /** Allowed redirect_uri prefixes. /api/oauth2/authorize rejects any
8680
8880
  * redirect_uri that does not start with one of these. Required —
8681
8881
  * an empty list means the integration can never complete linking. */
8682
- allowedRedirectPrefixes: array(string()).min(1)
8882
+ allowedRedirectPrefixes: array(string()).min(1),
8883
+ /** Optional public origin (no trailing slash) that this integration's
8884
+ * issued codes/tokens should carry as the `hubUrl` claim — typically the
8885
+ * operator-selected external-access endpoint resolved by the addon. When
8886
+ * present, /api/oauth2/authorize bakes THIS into the code instead of the
8887
+ * hub-global `publicHubUrl()`, so a forked exporter addon (which can't set
8888
+ * the hub's env) drives the claim that its cloud Lambda routes back on. */
8889
+ hubUrl: string().optional()
8683
8890
  });
8684
8891
  ({
8685
8892
  methods: {
@@ -9297,7 +9504,20 @@ const WebrtcStreamChoiceSchema = object({
9297
9504
  object({
9298
9505
  deviceId: number().int().nonnegative(),
9299
9506
  target: WebrtcStreamTargetSchema,
9300
- hints: webrtcClientHintsSchema.optional()
9507
+ hints: webrtcClientHintsSchema.optional(),
9508
+ /**
9509
+ * SERVER-INJECTED — NOT a client hint. The hub layer that holds
9510
+ * the tRPC request context (and therefore the client IP) sets
9511
+ * this to `true` when the viewer's source IP is non-LAN
9512
+ * (4G/CGNAT/internet). The broker then forces TURN-relay-only
9513
+ * ICE for the session so a CGNAT client (which can only offer a
9514
+ * relay candidate) gets a clean relay↔relay media path instead
9515
+ * of werift nominating a dead host/hairpin-srflx pair. LAN
9516
+ * clients leave this absent/false and keep the low-latency
9517
+ * direct (host/srflx) path. Clients MUST NOT send this — the
9518
+ * server overwrites it from the request context.
9519
+ */
9520
+ relayOnly: boolean().optional()
9301
9521
  }),
9302
9522
  object({ sessionId: string(), sdpOffer: string() }),
9303
9523
  { kind: "mutation" }
@@ -9320,7 +9540,22 @@ const WebrtcStreamChoiceSchema = object({
9320
9540
  deviceId: number().int().nonnegative(),
9321
9541
  target: WebrtcStreamTargetSchema.optional(),
9322
9542
  sdpOffer: string(),
9323
- sessionId: string().optional()
9543
+ sessionId: string().optional(),
9544
+ /**
9545
+ * Force TURN-relay-only ICE for this session. Two kinds of caller
9546
+ * set it:
9547
+ * - A cloud peer like Alexa's RTCSessionController (reachable
9548
+ * only via TURN, never our host/srflx behind NAT) passes
9549
+ * `true` from its own trusted addon context.
9550
+ * - The hub injects it for browser client-offer viewers from the
9551
+ * request's source IP (non-LAN ⇒ true), exactly as it does for
9552
+ * `createSession`.
9553
+ * A LAN/Tailscale browser doing client-offer passthrough leaves it
9554
+ * absent/false so a direct host pair carries full native quality.
9555
+ * Untrusted browser clients MUST NOT send it — the hub overwrites
9556
+ * it from the request context.
9557
+ */
9558
+ relayOnly: boolean().optional()
9324
9559
  }),
9325
9560
  object({ sessionId: string(), sdpAnswer: string() }),
9326
9561
  { kind: "mutation" }
@@ -9334,6 +9569,46 @@ const WebrtcStreamChoiceSchema = object({
9334
9569
  _void(),
9335
9570
  { kind: "mutation" }
9336
9571
  ),
9572
+ /**
9573
+ * Trickle ICE — add a remote (client) ICE candidate to a live session.
9574
+ * Lets the client send its SDP offer/answer IMMEDIATELY (before ICE
9575
+ * gathering finishes) and deliver candidates as they arrive, so the
9576
+ * connection establishes in ~0s instead of waiting for full gathering.
9577
+ * The dual of `getIceCandidates`. Mirrors Scrypted's signaling.
9578
+ */
9579
+ addIceCandidate: method(
9580
+ object({
9581
+ deviceId: number().int().nonnegative(),
9582
+ sessionId: string(),
9583
+ candidate: string(),
9584
+ sdpMid: string().nullable().optional(),
9585
+ sdpMLineIndex: number().int().nullable().optional()
9586
+ }),
9587
+ _void(),
9588
+ { kind: "mutation" }
9589
+ ),
9590
+ /**
9591
+ * Trickle ICE — poll the server's gathered ICE candidates for a session.
9592
+ * The server answers immediately (no gathering wait) and the client polls
9593
+ * this to receive host/srflx/relay candidates as werift gathers them,
9594
+ * adding each to its PeerConnection. Returns all candidates gathered so
9595
+ * far; the client dedupes. `done` flips true once gathering completes.
9596
+ */
9597
+ getIceCandidates: method(
9598
+ object({
9599
+ deviceId: number().int().nonnegative(),
9600
+ sessionId: string()
9601
+ }),
9602
+ object({
9603
+ candidates: array(object({
9604
+ candidate: string(),
9605
+ sdpMid: string().nullable(),
9606
+ sdpMLineIndex: number().int().nullable()
9607
+ })),
9608
+ done: boolean()
9609
+ }),
9610
+ { kind: "query" }
9611
+ ),
9337
9612
  closeSession: method(
9338
9613
  object({
9339
9614
  deviceId: number().int().nonnegative(),
@@ -11012,6 +11287,9 @@ const recordingEngineCapability = {
11012
11287
  ({
11013
11288
  deviceTypes: [DeviceType.Camera]
11014
11289
  });
11290
+ ({
11291
+ deviceTypes: [DeviceType.Camera]
11292
+ });
11015
11293
  const TrackStateSchema = _enum(["new", "entered", "left", "moving", "idle"]);
11016
11294
  const EventKindSchema = _enum(["motion", "object", "audio"]);
11017
11295
  const TrackPositionSchema = object({
@@ -11845,36 +12123,28 @@ const IntercomStatusSchema = object({
11845
12123
  }) }
11846
12124
  }
11847
12125
  });
11848
- const NativeObjectClassEnum = _enum([
11849
- "person",
11850
- "vehicle",
11851
- "animal",
11852
- "face",
11853
- "package",
11854
- "other"
11855
- ]);
11856
- const NativeDetectionSchema = object({
11857
- class: NativeObjectClassEnum,
11858
- timestamp: number(),
11859
- /** Firmware-provided confidence [0..1]. Reolink pushes don't carry it → undefined. */
11860
- confidence: number().min(0).max(1).optional()
11861
- });
11862
- object({
11863
- /**
11864
- * Last observed instance per class. Undefined entries mean the class
11865
- * is supported but nothing has been seen since the provider started.
11866
- */
11867
- lastByClass: record(NativeObjectClassEnum, NativeDetectionSchema.nullable()),
11868
- /** Classes the firmware is capable of detecting — enumerated at device register. */
11869
- supportedClasses: array(NativeObjectClassEnum).readonly()
12126
+ const CamStreamDescriptorSchema = object({
12127
+ camStreamId: string().min(1),
12128
+ kind: CamStreamKindSchema,
12129
+ url: string().optional(),
12130
+ codec: string().optional(),
12131
+ resolution: CamStreamResolutionSchema.optional(),
12132
+ fps: number().positive().optional(),
12133
+ label: string().optional(),
12134
+ /** Device-level features (e.g. `battery-operated`) — drives broker policy. */
12135
+ deviceFeatures: array(string()).optional(),
12136
+ /** Eligible for automatic profile assignment. Absent = `true`. */
12137
+ autoEligible: boolean().optional(),
12138
+ /** Transport-specific opaque metadata (e.g. rfc4571 SDP). */
12139
+ metadata: record(string(), unknown()).optional()
11870
12140
  });
11871
12141
  ({
11872
12142
  deviceTypes: [DeviceType.Camera],
11873
- events: {
11874
- onDetected: { data: object({
11875
- deviceId: number(),
11876
- detection: NativeDetectionSchema
11877
- }) }
12143
+ methods: {
12144
+ getCatalog: method(
12145
+ object({ deviceId: number().int().nonnegative() }),
12146
+ array(CamStreamDescriptorSchema).readonly()
12147
+ )
11878
12148
  }
11879
12149
  });
11880
12150
  const ModelFormatSchema = _enum(MODEL_FORMATS);
@@ -13082,7 +13352,8 @@ const PackageUpdateSchema = object({
13082
13352
  currentVersion: string(),
13083
13353
  latestVersion: string(),
13084
13354
  category: _enum(["addon", "core"]),
13085
- requiresRestart: boolean()
13355
+ requiresRestart: boolean(),
13356
+ isSystem: boolean()
13086
13357
  });
13087
13358
  const PackageVersionInfoSchema = object({
13088
13359
  version: string(),
@@ -13115,6 +13386,42 @@ const UpdateFrameworkPackageResultSchema = object({
13115
13386
  /** Ms-epoch the server scheduled its self-restart. */
13116
13387
  restartingAt: number()
13117
13388
  });
13389
+ const BulkUpdateItemStatusSchema = _enum([
13390
+ "queued",
13391
+ "updating",
13392
+ "done",
13393
+ "done-pending-restart",
13394
+ "failed"
13395
+ ]);
13396
+ const BulkUpdateItemSchema = object({
13397
+ name: string(),
13398
+ isSystem: boolean(),
13399
+ fromVersion: string(),
13400
+ toVersion: string(),
13401
+ status: BulkUpdateItemStatusSchema,
13402
+ error: string().optional(),
13403
+ startedAtMs: number().optional(),
13404
+ completedAtMs: number().optional()
13405
+ });
13406
+ const BulkUpdatePhaseSchema = _enum([
13407
+ "regular",
13408
+ "system",
13409
+ "restarting",
13410
+ "finalizing"
13411
+ ]);
13412
+ const BulkUpdateStateSchema = object({
13413
+ id: string(),
13414
+ nodeId: string(),
13415
+ startedAtMs: number(),
13416
+ completedAtMs: number().optional(),
13417
+ total: number(),
13418
+ completed: number(),
13419
+ failed: number(),
13420
+ current: string().nullable(),
13421
+ phase: BulkUpdatePhaseSchema,
13422
+ cancelled: boolean(),
13423
+ items: array(BulkUpdateItemSchema).readonly()
13424
+ });
13118
13425
  const FrameworkPackageStatusSchema = object({
13119
13426
  packageName: string(),
13120
13427
  currentVersion: string(),
@@ -13252,7 +13559,7 @@ const CustomActionInputSchema = object({
13252
13559
  getLastRestart: method(
13253
13560
  _void(),
13254
13561
  object({
13255
- kind: _enum(["framework-update", "manual", "system"]),
13562
+ kind: _enum(["framework-update", "manual", "system", "framework-bulk-update"]),
13256
13563
  packageName: string().optional(),
13257
13564
  fromVersion: string().optional(),
13258
13565
  toVersion: string().optional(),
@@ -13342,11 +13649,70 @@ const CustomActionInputSchema = object({
13342
13649
  updateFrameworkPackage: method(
13343
13650
  object({
13344
13651
  packageName: string().min(1),
13345
- version: string().optional()
13652
+ version: string().optional(),
13653
+ deferRestart: boolean().optional()
13346
13654
  }),
13347
13655
  UpdateFrameworkPackageResultSchema,
13348
13656
  { kind: "mutation", auth: "admin" }
13349
13657
  ),
13658
+ /**
13659
+ * Kicks off a server-side bulk update operation and returns the bulk
13660
+ * id immediately. The operation runs asynchronously; observe progress
13661
+ * via the `AddonsBulkUpdateProgress` event or `getBulkUpdateState`.
13662
+ * Items with `isSystem: true` use `deferRestart` — the hub restarts
13663
+ * ONCE at the end of the system phase, after all system packages are
13664
+ * installed.
13665
+ *
13666
+ * `items[].version` is REQUIRED — callers must pass the resolved
13667
+ * version from `listUpdates`. There is no `'latest'` default here
13668
+ * (unlike `updatePackage`) to guarantee deterministic bulk rolls.
13669
+ */
13670
+ startBulkUpdate: method(
13671
+ object({
13672
+ nodeId: string(),
13673
+ items: array(object({
13674
+ name: string(),
13675
+ version: string(),
13676
+ isSystem: boolean()
13677
+ })).readonly()
13678
+ }),
13679
+ object({ id: string() }),
13680
+ { kind: "mutation", auth: "admin" }
13681
+ ),
13682
+ /**
13683
+ * Returns the current state of a bulk update by id.
13684
+ * Returns `null` if the id is unknown or has been auto-cleaned
13685
+ * (5 minutes after `completedAt` the record is evicted from memory).
13686
+ */
13687
+ getBulkUpdateState: method(
13688
+ object({ id: string() }),
13689
+ BulkUpdateStateSchema.nullable(),
13690
+ { auth: "admin" }
13691
+ ),
13692
+ /**
13693
+ * Cancels an in-flight bulk update. The update loop exits after the
13694
+ * currently-processing item completes — cancellation is not
13695
+ * instantaneous. Has no effect once the `restarting` phase has been
13696
+ * entered (the hub is already shutting down at that point).
13697
+ * Returns `{ cancelled: false }` if the id is unknown, the operation
13698
+ * has already completed, or the `restarting` phase is active.
13699
+ */
13700
+ cancelBulkUpdate: method(
13701
+ object({ id: string() }),
13702
+ object({ cancelled: boolean() }),
13703
+ { kind: "mutation", auth: "admin" }
13704
+ ),
13705
+ /**
13706
+ * Lists all currently active (non-completed) bulk updates.
13707
+ * If `nodeId` is provided, filters to only bulk updates targeting
13708
+ * that node. Useful for restoring an in-progress banner on a fresh
13709
+ * page load when the UI reconnects mid-operation.
13710
+ */
13711
+ listActiveBulkUpdates: method(
13712
+ object({ nodeId: string().optional() }),
13713
+ array(BulkUpdateStateSchema).readonly(),
13714
+ { auth: "admin" }
13715
+ ),
13350
13716
  getVersions: method(
13351
13717
  object({ name: string() }),
13352
13718
  array(PackageVersionInfoSchema).readonly()
@@ -13474,6 +13840,7 @@ var EventCategory = /* @__PURE__ */ ((EventCategory2) => {
13474
13840
  EventCategory2["StreamBrokerOnCamStreamDemand"] = "stream-broker.onCamStreamDemand";
13475
13841
  EventCategory2["StreamBrokerOnCamStreamIdle"] = "stream-broker.onCamStreamIdle";
13476
13842
  EventCategory2["StreamBrokerOnRequestStreamSourceRefresh"] = "stream-broker.onRequestStreamSourceRefresh";
13843
+ EventCategory2["StreamParamsChanged"] = "stream-params.changed";
13477
13844
  EventCategory2["DeviceStateChanged"] = "device.state-changed";
13478
13845
  EventCategory2["BatteryOnStatusChanged"] = "battery.onStatusChanged";
13479
13846
  EventCategory2["DoorbellOnPressed"] = "doorbell.onPressed";
@@ -13521,6 +13888,7 @@ var EventCategory = /* @__PURE__ */ ((EventCategory2) => {
13521
13888
  EventCategory2["NetworkTunnelStarted"] = "network.tunnel.started";
13522
13889
  EventCategory2["NetworkTunnelStopped"] = "network.tunnel.stopped";
13523
13890
  EventCategory2["LocalNetworkChanged"] = "network.local.changed";
13891
+ EventCategory2["MeshNetworkChanged"] = "network.mesh.changed";
13524
13892
  EventCategory2["BackupCompleted"] = "backup.completed";
13525
13893
  EventCategory2["BackupRestored"] = "backup.restored";
13526
13894
  EventCategory2["NotificationDispatched"] = "notification.dispatched";
@@ -13531,6 +13899,7 @@ var EventCategory = /* @__PURE__ */ ((EventCategory2) => {
13531
13899
  EventCategory2["DeviceAwake"] = "device.awake";
13532
13900
  EventCategory2["DeviceSleeping"] = "device.sleeping";
13533
13901
  EventCategory2["RetentionCleanup"] = "retention.cleanup";
13902
+ EventCategory2["AddonsBulkUpdateProgress"] = "addons.bulk-update-progress";
13534
13903
  return EventCategory2;
13535
13904
  })(EventCategory || {});
13536
13905
  function createEvent(category, source, data) {
@@ -13680,7 +14049,7 @@ class BaseAddon {
13680
14049
  }
13681
14050
  // ── Settings schemas (override to provide UI) ─────────────────────────
13682
14051
  /** Override to provide global-level settings UI schema. */
13683
- globalSettingsSchema() {
14052
+ globalSettingsSchema(_cap) {
13684
14053
  return null;
13685
14054
  }
13686
14055
  /** Override to provide device-level settings UI schema. */
@@ -13694,8 +14063,8 @@ class BaseAddon {
13694
14063
  // blob and every addon used exactly one of them; the distinction was
13695
14064
  // never semantically load-bearing. `global` won because it was the
13696
14065
  // widely-used one and the name reads naturally (per-node addon config).
13697
- async getGlobalSettings(overlay) {
13698
- const schema = this.globalSettingsSchema();
14066
+ async getGlobalSettings(overlay, cap) {
14067
+ const schema = this.globalSettingsSchema(cap);
13699
14068
  if (!schema) return { sections: [] };
13700
14069
  const raw = await this._ctx?.settings?.readAddonStore() ?? {};
13701
14070
  return hydrateSchema(schema, overlay ? { ...raw, ...overlay } : raw);
@@ -13972,4 +14341,4 @@ export {
13972
14341
  tuple as t,
13973
14342
  zoneAnalyticsCapability as z
13974
14343
  };
13975
- //# sourceMappingURL=index-CIJfmsWX.mjs.map
14344
+ //# sourceMappingURL=index-BrTlzsrE.mjs.map