@camstack/addon-admin-ui 0.1.39 → 0.1.46

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 (47) hide show
  1. package/dist/assets/{__mfe_internal__admin_ui_host__loadShare___mf_0_tanstack_mf_1_react_mf_2_query__loadShare__.mjs-Cv6qLu_-.js → __mfe_internal__admin_ui_host__loadShare___mf_0_tanstack_mf_1_react_mf_2_query__loadShare__.mjs-CRKSbdgN.js} +1 -1
  2. package/dist/assets/{__mfe_internal__admin_ui_host__loadShare___mf_0_tanstack_mf_1_react_mf_2_query__loadShare__.mjs_commonjs-proxy-CChEG9e0.js → __mfe_internal__admin_ui_host__loadShare___mf_0_tanstack_mf_1_react_mf_2_query__loadShare__.mjs_commonjs-proxy-BGPfTw3V.js} +1 -1
  3. package/dist/assets/{__mfe_internal__admin_ui_host__loadShare___mf_0_trpc_mf_1_react_mf_2_query__loadShare__.mjs-C1BmHlGM.js → __mfe_internal__admin_ui_host__loadShare___mf_0_trpc_mf_1_react_mf_2_query__loadShare__.mjs-jPpiOa0I.js} +1 -1
  4. package/dist/assets/{__mfe_internal__admin_ui_host__loadShare___mf_0_trpc_mf_1_react_mf_2_query__loadShare__.mjs_commonjs-proxy-Bxv_3KWz.js → __mfe_internal__admin_ui_host__loadShare___mf_0_trpc_mf_1_react_mf_2_query__loadShare__.mjs_commonjs-proxy-DYNYuSL7.js} +1 -1
  5. package/dist/assets/{__mfe_internal__admin_ui_host__loadShare__react__loadShare__.mjs-DC63qZbr.js → __mfe_internal__admin_ui_host__loadShare__react__loadShare__.mjs-ij0ODm-n.js} +1 -1
  6. package/dist/assets/{__mfe_internal__admin_ui_host__loadShare__react__loadShare__.mjs_commonjs-proxy-D2C49VyZ.js → __mfe_internal__admin_ui_host__loadShare__react__loadShare__.mjs_commonjs-proxy-C4Ko8zXp.js} +1 -1
  7. package/dist/assets/{__mfe_internal__admin_ui_host__loadShare__react_mf_2_dom__loadShare__.mjs-D3WbXy3O.js → __mfe_internal__admin_ui_host__loadShare__react_mf_2_dom__loadShare__.mjs-Cf5gSqc_.js} +1 -1
  8. package/dist/assets/{__mfe_internal__admin_ui_host__loadShare__react_mf_2_dom__loadShare__.mjs_commonjs-proxy-Csg6EbPB.js → __mfe_internal__admin_ui_host__loadShare__react_mf_2_dom__loadShare__.mjs_commonjs-proxy-CYaX3FDr.js} +1 -1
  9. package/dist/assets/{__mfe_internal__admin_ui_host__loadShare__react_mf_2_dom_mf_1_client__loadShare__.mjs-CUc0oFNo.js → __mfe_internal__admin_ui_host__loadShare__react_mf_2_dom_mf_1_client__loadShare__.mjs-rHwdrynu.js} +1 -1
  10. package/dist/assets/{__mfe_internal__admin_ui_host__loadShare__react_mf_2_dom_mf_1_client__loadShare__.mjs_commonjs-proxy-vh0hhA5d.js → __mfe_internal__admin_ui_host__loadShare__react_mf_2_dom_mf_1_client__loadShare__.mjs_commonjs-proxy-DRDS6j-Y.js} +1 -1
  11. package/dist/assets/{__mfe_internal__admin_ui_host__loadShare__react_mf_2_konva__loadShare__.mjs-CpGtTxci.js → __mfe_internal__admin_ui_host__loadShare__react_mf_2_konva__loadShare__.mjs-cUuqcEcL.js} +2 -2
  12. package/dist/assets/{__mfe_internal__admin_ui_host__loadShare__react_mf_2_konva__loadShare__.mjs_commonjs-proxy-RUDPE9aM.js → __mfe_internal__admin_ui_host__loadShare__react_mf_2_konva__loadShare__.mjs_commonjs-proxy-CzMP41OH.js} +1 -1
  13. package/dist/assets/{_virtual_mf-localSharedImportMap___mfe_internal__admin_ui_host-TUicghXo.js → _virtual_mf-localSharedImportMap___mfe_internal__admin_ui_host-DNAkeUTZ.js} +1 -1
  14. package/dist/assets/{devices-GLp7me2a.js → devices-DaqavVOg.js} +1 -1
  15. package/dist/assets/{hostInit-94fVe_XD.js → hostInit-ByQycOVJ.js} +1 -1
  16. package/dist/assets/index-B6kubsZI.js +151 -0
  17. package/dist/assets/index-BI1a6Whs.js +1 -0
  18. package/dist/assets/index-BVNg3Krt.js +1185 -0
  19. package/dist/assets/{index-TiJwCuZx.js → index-BbwPCEeT.js} +1 -1
  20. package/dist/assets/{index-D6khiudP.js → index-BpC2rqYA.js} +1 -1
  21. package/dist/assets/index-CukoHCyD.js +1 -0
  22. package/dist/assets/{index-JJ5NLHxC.js → index-Cyva9RmE.js} +1 -1
  23. package/dist/assets/index-DLnW8nGB.css +1 -0
  24. package/dist/assets/index-DNydUTOB.js +1 -0
  25. package/dist/assets/{index-CwF7Dxf8.js → index-DVLRgczW.js} +1 -1
  26. package/dist/assets/index-PXbclFuZ.js +87 -0
  27. package/dist/assets/index-QqQmcu5i.js +1 -0
  28. package/dist/assets/method-access-map-DjDdPRYC.js +1 -0
  29. package/dist/assets/{remoteEntry-JLETvOnh.js → remoteEntry-iRKuVHUX.js} +1 -1
  30. package/dist/assets/{schemas-BEt-CulV.js → schemas-BdJePqbR.js} +5 -5
  31. package/dist/assets/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__admin_ui_host__remoteEntry-_hash_-DM77_4pA.js → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__admin_ui_host__remoteEntry-_hash_-QVZxTxLo.js} +2 -2
  32. package/dist/index.html +152 -9
  33. package/dist/mf-entry-bootstrap-0.js +2 -2
  34. package/dist/server/addon.js +435 -52
  35. package/dist/server/addon.js.map +1 -1
  36. package/dist/sw.js +1 -1
  37. package/package.json +1 -1
  38. package/dist/assets/index-BM6aK9lG.js +0 -1150
  39. package/dist/assets/index-ByRJWRUP.js +0 -1
  40. package/dist/assets/index-COoei6lw.css +0 -1
  41. package/dist/assets/index-CtHpLu0L.js +0 -1
  42. package/dist/assets/index-DNY_otk4.js +0 -151
  43. package/dist/assets/index-DQFO9ZU6.js +0 -1
  44. package/dist/assets/index-WrAHDGEr.js +0 -87
  45. package/dist/assets/index-b0D9qthW.js +0 -1
  46. package/dist/assets/method-access-map-DLEhlu0x.js +0 -1
  47. package/dist/registerSW.js +0 -1
@@ -4780,6 +4780,16 @@ function record(keyType, valueType, params) {
4780
4780
  ...normalizeParams(params)
4781
4781
  });
4782
4782
  }
4783
+ function partialRecord(keyType, valueType, params) {
4784
+ const k = clone(keyType);
4785
+ k._zod.values = void 0;
4786
+ return new ZodRecord({
4787
+ type: "record",
4788
+ keyType: k,
4789
+ valueType,
4790
+ ...normalizeParams(params)
4791
+ });
4792
+ }
4783
4793
  const ZodEnum = /* @__PURE__ */ $constructor("ZodEnum", (inst, def) => {
4784
4794
  $ZodEnum.init(inst, def);
4785
4795
  ZodType.init(inst, def);
@@ -5056,6 +5066,37 @@ function _instanceof(cls, params = {}) {
5056
5066
  };
5057
5067
  return inst;
5058
5068
  }
5069
+ const wiringProbeKindSchema = _enum(["singleton", "device", "widget"]);
5070
+ const wiringProbeResultSchema = object({
5071
+ capName: string(),
5072
+ kind: wiringProbeKindSchema,
5073
+ deviceId: number().optional(),
5074
+ reachable: boolean(),
5075
+ latencyMs: number(),
5076
+ error: string().optional()
5077
+ });
5078
+ const wiringAddonHealthSchema = object({
5079
+ addonId: string(),
5080
+ caps: array(wiringProbeResultSchema).readonly(),
5081
+ widgets: array(wiringProbeResultSchema).readonly()
5082
+ });
5083
+ const wiringNodeHealthSchema = object({
5084
+ nodeId: string(),
5085
+ addons: array(wiringAddonHealthSchema).readonly()
5086
+ });
5087
+ object({
5088
+ /** True only when every probed target is reachable. */
5089
+ ok: boolean(),
5090
+ /** True when at least one target is unreachable. */
5091
+ degraded: boolean(),
5092
+ checkedAt: string(),
5093
+ nodes: array(wiringNodeHealthSchema).readonly(),
5094
+ summary: object({
5095
+ total: number(),
5096
+ reachable: number(),
5097
+ unreachable: number()
5098
+ })
5099
+ });
5059
5100
  const MODEL_FORMATS = ["onnx", "coreml", "openvino", "tflite", "pt"];
5060
5101
  const WELL_KNOWN_TABS = [
5061
5102
  { id: "overview", label: "Overview", icon: "layout-dashboard", order: -10 },
@@ -6575,7 +6616,7 @@ const SpatialDetectionSchema = object({
6575
6616
  bbox: BoundingBoxSchema
6576
6617
  });
6577
6618
  const AudioChunkInputSchema = object({
6578
- data: _instanceof(Float32Array),
6619
+ data: _instanceof(Uint8Array),
6579
6620
  sampleRate: number(),
6580
6621
  channels: number(),
6581
6622
  timestamp: number(),
@@ -7246,7 +7287,23 @@ const RunnerCameraConfigSchema = object({
7246
7287
  * whenever its `zones` device-state slice changes, so the runner's
7247
7288
  * copy stays in sync. Empty array → no zone filtering.
7248
7289
  */
7249
- zones: array(ZoneSchema).readonly().default([])
7290
+ zones: array(ZoneSchema).readonly().default([]),
7291
+ /**
7292
+ * When true (default) and the camera's `motionSources` contains only
7293
+ * `'onboard'`, the runner dynamically opens the same WASM frame-diff
7294
+ * motion-frames subscription on each `MotionOnMotionChanged
7295
+ * source:'onboard'` event and tears it down after `motionCooldownMs`.
7296
+ * This causes `runMotionAnalysis` to emit `MotionZonesRaw` /
7297
+ * `MotionAnalysis` during active-motion windows without the
7298
+ * substream being held open continuously.
7299
+ *
7300
+ * Set to `false` to disable the dynamic analyzer for this camera
7301
+ * (e.g. very low-bandwidth links where the extra substream is
7302
+ * undesirable). Has no effect when `motionSources` already includes
7303
+ * `'analyzer'` — the analyzer runs continuously in that case and
7304
+ * this gate is bypassed.
7305
+ */
7306
+ onboardMotionDrivesAnalyzer: boolean().default(true)
7250
7307
  });
7251
7308
  const RunnerLocalLoadSchema = object({
7252
7309
  /** Moleculer node id of this runner instance. */
@@ -7383,22 +7440,68 @@ MotionTriggerStatusSchema.extend({
7383
7440
  }) }
7384
7441
  }
7385
7442
  });
7443
+ const MaskPointSchema = object({
7444
+ x: number(),
7445
+ y: number()
7446
+ });
7447
+ const MaskRectShapeSchema = object({
7448
+ kind: literal("rect"),
7449
+ x: number(),
7450
+ y: number(),
7451
+ width: number(),
7452
+ height: number()
7453
+ });
7454
+ const MaskPolygonShapeSchema = object({
7455
+ kind: literal("polygon"),
7456
+ points: array(MaskPointSchema)
7457
+ });
7458
+ const MaskGridShapeSchema = object({
7459
+ kind: literal("grid"),
7460
+ gridWidth: number(),
7461
+ gridHeight: number(),
7462
+ cells: array(boolean())
7463
+ });
7464
+ const MaskLineShapeSchema = object({
7465
+ kind: literal("line"),
7466
+ points: array(MaskPointSchema)
7467
+ });
7468
+ discriminatedUnion("kind", [
7469
+ MaskRectShapeSchema,
7470
+ MaskPolygonShapeSchema,
7471
+ MaskGridShapeSchema,
7472
+ MaskLineShapeSchema
7473
+ ]);
7474
+ const MaskShapeKindSchema = _enum(["rect", "polygon", "grid", "line"]);
7475
+ const MaskPolygonVerticesSchema = object({
7476
+ min: number(),
7477
+ max: number()
7478
+ });
7479
+ const MaskGridDimsSchema = object({
7480
+ width: number(),
7481
+ height: number()
7482
+ });
7483
+ const MotionZoneRegionSchema = object({
7484
+ id: number(),
7485
+ enabled: boolean(),
7486
+ shape: MaskGridShapeSchema
7487
+ });
7386
7488
  object({
7387
7489
  enabled: boolean(),
7388
7490
  sensitivity: number(),
7389
- /** Row-major active-cell grid. Length = gridWidth*gridHeight (see getOptions). */
7390
- cells: array(boolean()),
7491
+ /** Grid region(s). Today exactly one `grid` shape. */
7492
+ regions: array(MotionZoneRegionSchema),
7391
7493
  lastFetchedAt: number()
7392
7494
  });
7393
7495
  const MotionZoneOptionsSchema = object({
7394
- gridWidth: number(),
7395
- gridHeight: number(),
7496
+ maxRegions: number(),
7497
+ supportedShapes: array(MaskShapeKindSchema),
7498
+ grid: MaskGridDimsSchema,
7396
7499
  sensitivity: object({ min: number(), max: number(), step: number() })
7397
7500
  });
7398
7501
  const MotionZonePatchSchema = object({
7399
7502
  enabled: boolean().optional(),
7400
7503
  sensitivity: number().optional(),
7401
- cells: array(boolean()).optional()
7504
+ regions: array(MotionZoneRegionSchema).optional()
7402
7505
  });
7403
7506
  ({
7404
7507
  deviceTypes: [DeviceType.Camera],
@@ -7411,6 +7514,102 @@ const MotionZonePatchSchema = object({
7411
7514
  )
7412
7515
  }
7413
7516
  });
7517
+ const NativeObjectClassEnum = _enum([
7518
+ "person",
7519
+ "vehicle",
7520
+ "animal",
7521
+ "face",
7522
+ "package",
7523
+ "other"
7524
+ ]);
7525
+ const NativeDetectionSchema = object({
7526
+ class: NativeObjectClassEnum,
7527
+ timestamp: number(),
7528
+ /** Firmware-provided confidence [0..1]. Reolink pushes don't carry it → undefined. */
7529
+ confidence: number().min(0).max(1).optional()
7530
+ });
7531
+ const NativeObjectDetectionStatusSchema = object({
7532
+ /**
7533
+ * Last observed instance per class. Missing entries mean the class
7534
+ * is supported but nothing has been seen since the provider started.
7535
+ *
7536
+ * MUST be a partial record: providers seed an empty `{}` on cold-start
7537
+ * and write one class at a time as detections arrive. In Zod 4
7538
+ * `z.record(enum, …)` is EXHAUSTIVE (requires every enum key), so a
7539
+ * partial write throws "expected object, received undefined" for every
7540
+ * unseen class. `z.partialRecord` keeps the enum-key narrowing while
7541
+ * allowing the sparse shape the providers actually write.
7542
+ */
7543
+ lastByClass: partialRecord(NativeObjectClassEnum, NativeDetectionSchema.nullable()),
7544
+ /** Classes the firmware is capable of detecting — enumerated at device register. */
7545
+ supportedClasses: array(NativeObjectClassEnum).readonly(),
7546
+ /**
7547
+ * Whether forwarding of onboard AI detections is enabled for this device.
7548
+ * Default true (on cold-start) — detections flow unconditionally before
7549
+ * the toggle is saved, so defaulting true preserves existing behaviour.
7550
+ */
7551
+ enabled: boolean()
7552
+ });
7553
+ NativeObjectDetectionStatusSchema.extend({
7554
+ /** Required by createRuntimeStateBridge — epoch ms of last refresh. */
7555
+ lastFetchedAt: number()
7556
+ });
7557
+ ({
7558
+ deviceTypes: [DeviceType.Camera],
7559
+ methods: {
7560
+ setEnabled: method(
7561
+ object({ deviceId: number(), enabled: boolean() }),
7562
+ _void(),
7563
+ { kind: "mutation", auth: "admin" }
7564
+ )
7565
+ },
7566
+ events: {
7567
+ onDetected: { data: object({
7568
+ deviceId: number(),
7569
+ detection: NativeDetectionSchema
7570
+ }) }
7571
+ }
7572
+ });
7573
+ const PrivacyMaskShapeSchema = discriminatedUnion("kind", [
7574
+ MaskRectShapeSchema,
7575
+ MaskPolygonShapeSchema
7576
+ ]);
7577
+ const PrivacyMaskRegionSchema = object({
7578
+ /** Slot id, 0-based. Stable across read/write. */
7579
+ id: number(),
7580
+ /** Whether this zone is active (blanked out by the camera). */
7581
+ enabled: boolean(),
7582
+ shape: PrivacyMaskShapeSchema
7583
+ });
7584
+ object({
7585
+ enabled: boolean(),
7586
+ /** Active zones (normalized 0..1). Length ≤ maxRegions. */
7587
+ regions: array(PrivacyMaskRegionSchema),
7588
+ lastFetchedAt: number()
7589
+ });
7590
+ const PrivacyMaskOptionsSchema = object({
7591
+ /** Maximum number of supported zones. */
7592
+ maxRegions: number(),
7593
+ /** Shape kinds this camera accepts — Reolink: ['rect']; Hikvision: ['rect','polygon']. */
7594
+ supportedShapes: array(MaskShapeKindSchema),
7595
+ /** Polygon vertex bounds when 'polygon' is supported (Hikvision: {min:4,max:4}). */
7596
+ polygonVertices: MaskPolygonVerticesSchema.optional()
7597
+ });
7598
+ const PrivacyMaskPatchSchema = object({
7599
+ enabled: boolean().optional(),
7600
+ regions: array(PrivacyMaskRegionSchema).optional()
7601
+ });
7602
+ ({
7603
+ deviceTypes: [DeviceType.Camera],
7604
+ methods: {
7605
+ getOptions: method(object({ deviceId: number() }), PrivacyMaskOptionsSchema),
7606
+ setMask: method(
7607
+ object({ deviceId: number(), patch: PrivacyMaskPatchSchema }),
7608
+ _void(),
7609
+ { kind: "mutation", auth: "admin" }
7610
+ )
7611
+ }
7612
+ });
7414
7613
  const AutotrackTargetTypeSchema = string().describe("Vendor target string (people/vehicle/pet); empty = camera default");
7415
7614
  const PtzAutotrackSettingsSchema = object({
7416
7615
  targetType: AutotrackTargetTypeSchema,
@@ -7929,7 +8128,8 @@ const SettingsUpdateResultSchema = object({
7929
8128
  object({
7930
8129
  addonId: string(),
7931
8130
  nodeId: string().optional(),
7932
- overlay: record(string(), unknown()).optional()
8131
+ overlay: record(string(), unknown()).optional(),
8132
+ cap: string().optional()
7933
8133
  }),
7934
8134
  SettingsSchemaWithValuesSchema.nullable()
7935
8135
  ),
@@ -8664,7 +8864,14 @@ const OauthIntegrationDescriptorSchema = object({
8664
8864
  /** Allowed redirect_uri prefixes. /api/oauth2/authorize rejects any
8665
8865
  * redirect_uri that does not start with one of these. Required —
8666
8866
  * an empty list means the integration can never complete linking. */
8667
- allowedRedirectPrefixes: array(string()).min(1)
8867
+ allowedRedirectPrefixes: array(string()).min(1),
8868
+ /** Optional public origin (no trailing slash) that this integration's
8869
+ * issued codes/tokens should carry as the `hubUrl` claim — typically the
8870
+ * operator-selected external-access endpoint resolved by the addon. When
8871
+ * present, /api/oauth2/authorize bakes THIS into the code instead of the
8872
+ * hub-global `publicHubUrl()`, so a forked exporter addon (which can't set
8873
+ * the hub's env) drives the claim that its cloud Lambda routes back on. */
8874
+ hubUrl: string().optional()
8668
8875
  });
8669
8876
  ({
8670
8877
  methods: {
@@ -9278,7 +9485,20 @@ const WebrtcStreamChoiceSchema = object({
9278
9485
  object({
9279
9486
  deviceId: number().int().nonnegative(),
9280
9487
  target: WebrtcStreamTargetSchema,
9281
- hints: webrtcClientHintsSchema.optional()
9488
+ hints: webrtcClientHintsSchema.optional(),
9489
+ /**
9490
+ * SERVER-INJECTED — NOT a client hint. The hub layer that holds
9491
+ * the tRPC request context (and therefore the client IP) sets
9492
+ * this to `true` when the viewer's source IP is non-LAN
9493
+ * (4G/CGNAT/internet). The broker then forces TURN-relay-only
9494
+ * ICE for the session so a CGNAT client (which can only offer a
9495
+ * relay candidate) gets a clean relay↔relay media path instead
9496
+ * of werift nominating a dead host/hairpin-srflx pair. LAN
9497
+ * clients leave this absent/false and keep the low-latency
9498
+ * direct (host/srflx) path. Clients MUST NOT send this — the
9499
+ * server overwrites it from the request context.
9500
+ */
9501
+ relayOnly: boolean().optional()
9282
9502
  }),
9283
9503
  object({ sessionId: string(), sdpOffer: string() }),
9284
9504
  { kind: "mutation" }
@@ -9301,7 +9521,22 @@ const WebrtcStreamChoiceSchema = object({
9301
9521
  deviceId: number().int().nonnegative(),
9302
9522
  target: WebrtcStreamTargetSchema.optional(),
9303
9523
  sdpOffer: string(),
9304
- sessionId: string().optional()
9524
+ sessionId: string().optional(),
9525
+ /**
9526
+ * Force TURN-relay-only ICE for this session. Two kinds of caller
9527
+ * set it:
9528
+ * - A cloud peer like Alexa's RTCSessionController (reachable
9529
+ * only via TURN, never our host/srflx behind NAT) passes
9530
+ * `true` from its own trusted addon context.
9531
+ * - The hub injects it for browser client-offer viewers from the
9532
+ * request's source IP (non-LAN ⇒ true), exactly as it does for
9533
+ * `createSession`.
9534
+ * A LAN/Tailscale browser doing client-offer passthrough leaves it
9535
+ * absent/false so a direct host pair carries full native quality.
9536
+ * Untrusted browser clients MUST NOT send it — the hub overwrites
9537
+ * it from the request context.
9538
+ */
9539
+ relayOnly: boolean().optional()
9305
9540
  }),
9306
9541
  object({ sessionId: string(), sdpAnswer: string() }),
9307
9542
  { kind: "mutation" }
@@ -9315,6 +9550,46 @@ const WebrtcStreamChoiceSchema = object({
9315
9550
  _void(),
9316
9551
  { kind: "mutation" }
9317
9552
  ),
9553
+ /**
9554
+ * Trickle ICE — add a remote (client) ICE candidate to a live session.
9555
+ * Lets the client send its SDP offer/answer IMMEDIATELY (before ICE
9556
+ * gathering finishes) and deliver candidates as they arrive, so the
9557
+ * connection establishes in ~0s instead of waiting for full gathering.
9558
+ * The dual of `getIceCandidates`. Mirrors Scrypted's signaling.
9559
+ */
9560
+ addIceCandidate: method(
9561
+ object({
9562
+ deviceId: number().int().nonnegative(),
9563
+ sessionId: string(),
9564
+ candidate: string(),
9565
+ sdpMid: string().nullable().optional(),
9566
+ sdpMLineIndex: number().int().nullable().optional()
9567
+ }),
9568
+ _void(),
9569
+ { kind: "mutation" }
9570
+ ),
9571
+ /**
9572
+ * Trickle ICE — poll the server's gathered ICE candidates for a session.
9573
+ * The server answers immediately (no gathering wait) and the client polls
9574
+ * this to receive host/srflx/relay candidates as werift gathers them,
9575
+ * adding each to its PeerConnection. Returns all candidates gathered so
9576
+ * far; the client dedupes. `done` flips true once gathering completes.
9577
+ */
9578
+ getIceCandidates: method(
9579
+ object({
9580
+ deviceId: number().int().nonnegative(),
9581
+ sessionId: string()
9582
+ }),
9583
+ object({
9584
+ candidates: array(object({
9585
+ candidate: string(),
9586
+ sdpMid: string().nullable(),
9587
+ sdpMLineIndex: number().int().nullable()
9588
+ })),
9589
+ done: boolean()
9590
+ }),
9591
+ { kind: "query" }
9592
+ ),
9318
9593
  closeSession: method(
9319
9594
  object({
9320
9595
  deviceId: number().int().nonnegative(),
@@ -10986,6 +11261,9 @@ const UpdateConfigInput = object({
10986
11261
  ({
10987
11262
  deviceTypes: [DeviceType.Camera]
10988
11263
  });
11264
+ ({
11265
+ deviceTypes: [DeviceType.Camera]
11266
+ });
10989
11267
  const TrackStateSchema = _enum(["new", "entered", "left", "moving", "idle"]);
10990
11268
  const EventKindSchema = _enum(["motion", "object", "audio"]);
10991
11269
  const TrackPositionSchema = object({
@@ -11813,36 +12091,28 @@ const IntercomStatusSchema = object({
11813
12091
  }) }
11814
12092
  }
11815
12093
  });
11816
- const NativeObjectClassEnum = _enum([
11817
- "person",
11818
- "vehicle",
11819
- "animal",
11820
- "face",
11821
- "package",
11822
- "other"
11823
- ]);
11824
- const NativeDetectionSchema = object({
11825
- class: NativeObjectClassEnum,
11826
- timestamp: number(),
11827
- /** Firmware-provided confidence [0..1]. Reolink pushes don't carry it → undefined. */
11828
- confidence: number().min(0).max(1).optional()
11829
- });
11830
- object({
11831
- /**
11832
- * Last observed instance per class. Undefined entries mean the class
11833
- * is supported but nothing has been seen since the provider started.
11834
- */
11835
- lastByClass: record(NativeObjectClassEnum, NativeDetectionSchema.nullable()),
11836
- /** Classes the firmware is capable of detecting — enumerated at device register. */
11837
- supportedClasses: array(NativeObjectClassEnum).readonly()
12094
+ const CamStreamDescriptorSchema = object({
12095
+ camStreamId: string().min(1),
12096
+ kind: CamStreamKindSchema,
12097
+ url: string().optional(),
12098
+ codec: string().optional(),
12099
+ resolution: CamStreamResolutionSchema.optional(),
12100
+ fps: number().positive().optional(),
12101
+ label: string().optional(),
12102
+ /** Device-level features (e.g. `battery-operated`) — drives broker policy. */
12103
+ deviceFeatures: array(string()).optional(),
12104
+ /** Eligible for automatic profile assignment. Absent = `true`. */
12105
+ autoEligible: boolean().optional(),
12106
+ /** Transport-specific opaque metadata (e.g. rfc4571 SDP). */
12107
+ metadata: record(string(), unknown()).optional()
11838
12108
  });
11839
12109
  ({
11840
12110
  deviceTypes: [DeviceType.Camera],
11841
- events: {
11842
- onDetected: { data: object({
11843
- deviceId: number(),
11844
- detection: NativeDetectionSchema
11845
- }) }
12111
+ methods: {
12112
+ getCatalog: method(
12113
+ object({ deviceId: number().int().nonnegative() }),
12114
+ array(CamStreamDescriptorSchema).readonly()
12115
+ )
11846
12116
  }
11847
12117
  });
11848
12118
  const ModelFormatSchema = _enum(MODEL_FORMATS);
@@ -12710,6 +12980,18 @@ const TopologyProcessSchema = object({
12710
12980
  services: array(TopologyServiceSchema).readonly(),
12711
12981
  groupId: string().optional()
12712
12982
  });
12983
+ const TopologyCategoryAddonSchema = object({
12984
+ id: string(),
12985
+ status: string(),
12986
+ cpuPercent: number(),
12987
+ memoryRss: number()
12988
+ });
12989
+ const TopologyCategorySchema = object({
12990
+ category: string(),
12991
+ total: number(),
12992
+ healthy: number(),
12993
+ addons: array(TopologyCategoryAddonSchema).readonly()
12994
+ });
12713
12995
  const TopologyNodeSchema = object({
12714
12996
  id: string(),
12715
12997
  name: string(),
@@ -12734,7 +13016,15 @@ const TopologyNodeSchema = object({
12734
13016
  status: string()
12735
13017
  })
12736
13018
  ).readonly(),
12737
- processes: array(TopologyProcessSchema).readonly()
13019
+ processes: array(TopologyProcessSchema).readonly(),
13020
+ categories: array(TopologyCategorySchema).readonly()
13021
+ });
13022
+ const CapUsageEdgeSchema = object({
13023
+ callerAddonId: string(),
13024
+ providerAddonId: string(),
13025
+ capName: string(),
13026
+ callsPerMin: number(),
13027
+ lastCallAtMs: number()
12738
13028
  });
12739
13029
  const ClusterAddonNodeDeploymentSchema = object({
12740
13030
  nodeId: string(),
@@ -12818,13 +13108,7 @@ const RenameNodeResultSchema = object({
12818
13108
  object({
12819
13109
  windowSeconds: number().int().positive().max(300).default(60)
12820
13110
  }),
12821
- array(object({
12822
- callerAddonId: string(),
12823
- providerAddonId: string(),
12824
- capName: string(),
12825
- callsPerMin: number(),
12826
- lastCallAtMs: number()
12827
- })).readonly(),
13111
+ array(CapUsageEdgeSchema).readonly(),
12828
13112
  { auth: "admin" }
12829
13113
  ),
12830
13114
  /**
@@ -13036,7 +13320,8 @@ const PackageUpdateSchema = object({
13036
13320
  currentVersion: string(),
13037
13321
  latestVersion: string(),
13038
13322
  category: _enum(["addon", "core"]),
13039
- requiresRestart: boolean()
13323
+ requiresRestart: boolean(),
13324
+ isSystem: boolean()
13040
13325
  });
13041
13326
  const PackageVersionInfoSchema = object({
13042
13327
  version: string(),
@@ -13069,6 +13354,42 @@ const UpdateFrameworkPackageResultSchema = object({
13069
13354
  /** Ms-epoch the server scheduled its self-restart. */
13070
13355
  restartingAt: number()
13071
13356
  });
13357
+ const BulkUpdateItemStatusSchema = _enum([
13358
+ "queued",
13359
+ "updating",
13360
+ "done",
13361
+ "done-pending-restart",
13362
+ "failed"
13363
+ ]);
13364
+ const BulkUpdateItemSchema = object({
13365
+ name: string(),
13366
+ isSystem: boolean(),
13367
+ fromVersion: string(),
13368
+ toVersion: string(),
13369
+ status: BulkUpdateItemStatusSchema,
13370
+ error: string().optional(),
13371
+ startedAtMs: number().optional(),
13372
+ completedAtMs: number().optional()
13373
+ });
13374
+ const BulkUpdatePhaseSchema = _enum([
13375
+ "regular",
13376
+ "system",
13377
+ "restarting",
13378
+ "finalizing"
13379
+ ]);
13380
+ const BulkUpdateStateSchema = object({
13381
+ id: string(),
13382
+ nodeId: string(),
13383
+ startedAtMs: number(),
13384
+ completedAtMs: number().optional(),
13385
+ total: number(),
13386
+ completed: number(),
13387
+ failed: number(),
13388
+ current: string().nullable(),
13389
+ phase: BulkUpdatePhaseSchema,
13390
+ cancelled: boolean(),
13391
+ items: array(BulkUpdateItemSchema).readonly()
13392
+ });
13072
13393
  const FrameworkPackageStatusSchema = object({
13073
13394
  packageName: string(),
13074
13395
  currentVersion: string(),
@@ -13206,7 +13527,7 @@ const CustomActionInputSchema = object({
13206
13527
  getLastRestart: method(
13207
13528
  _void(),
13208
13529
  object({
13209
- kind: _enum(["framework-update", "manual", "system"]),
13530
+ kind: _enum(["framework-update", "manual", "system", "framework-bulk-update"]),
13210
13531
  packageName: string().optional(),
13211
13532
  fromVersion: string().optional(),
13212
13533
  toVersion: string().optional(),
@@ -13296,11 +13617,70 @@ const CustomActionInputSchema = object({
13296
13617
  updateFrameworkPackage: method(
13297
13618
  object({
13298
13619
  packageName: string().min(1),
13299
- version: string().optional()
13620
+ version: string().optional(),
13621
+ deferRestart: boolean().optional()
13300
13622
  }),
13301
13623
  UpdateFrameworkPackageResultSchema,
13302
13624
  { kind: "mutation", auth: "admin" }
13303
13625
  ),
13626
+ /**
13627
+ * Kicks off a server-side bulk update operation and returns the bulk
13628
+ * id immediately. The operation runs asynchronously; observe progress
13629
+ * via the `AddonsBulkUpdateProgress` event or `getBulkUpdateState`.
13630
+ * Items with `isSystem: true` use `deferRestart` — the hub restarts
13631
+ * ONCE at the end of the system phase, after all system packages are
13632
+ * installed.
13633
+ *
13634
+ * `items[].version` is REQUIRED — callers must pass the resolved
13635
+ * version from `listUpdates`. There is no `'latest'` default here
13636
+ * (unlike `updatePackage`) to guarantee deterministic bulk rolls.
13637
+ */
13638
+ startBulkUpdate: method(
13639
+ object({
13640
+ nodeId: string(),
13641
+ items: array(object({
13642
+ name: string(),
13643
+ version: string(),
13644
+ isSystem: boolean()
13645
+ })).readonly()
13646
+ }),
13647
+ object({ id: string() }),
13648
+ { kind: "mutation", auth: "admin" }
13649
+ ),
13650
+ /**
13651
+ * Returns the current state of a bulk update by id.
13652
+ * Returns `null` if the id is unknown or has been auto-cleaned
13653
+ * (5 minutes after `completedAt` the record is evicted from memory).
13654
+ */
13655
+ getBulkUpdateState: method(
13656
+ object({ id: string() }),
13657
+ BulkUpdateStateSchema.nullable(),
13658
+ { auth: "admin" }
13659
+ ),
13660
+ /**
13661
+ * Cancels an in-flight bulk update. The update loop exits after the
13662
+ * currently-processing item completes — cancellation is not
13663
+ * instantaneous. Has no effect once the `restarting` phase has been
13664
+ * entered (the hub is already shutting down at that point).
13665
+ * Returns `{ cancelled: false }` if the id is unknown, the operation
13666
+ * has already completed, or the `restarting` phase is active.
13667
+ */
13668
+ cancelBulkUpdate: method(
13669
+ object({ id: string() }),
13670
+ object({ cancelled: boolean() }),
13671
+ { kind: "mutation", auth: "admin" }
13672
+ ),
13673
+ /**
13674
+ * Lists all currently active (non-completed) bulk updates.
13675
+ * If `nodeId` is provided, filters to only bulk updates targeting
13676
+ * that node. Useful for restoring an in-progress banner on a fresh
13677
+ * page load when the UI reconnects mid-operation.
13678
+ */
13679
+ listActiveBulkUpdates: method(
13680
+ object({ nodeId: string().optional() }),
13681
+ array(BulkUpdateStateSchema).readonly(),
13682
+ { auth: "admin" }
13683
+ ),
13304
13684
  getVersions: method(
13305
13685
  object({ name: string() }),
13306
13686
  array(PackageVersionInfoSchema).readonly()
@@ -13428,6 +13808,7 @@ var EventCategory = /* @__PURE__ */ ((EventCategory2) => {
13428
13808
  EventCategory2["StreamBrokerOnCamStreamDemand"] = "stream-broker.onCamStreamDemand";
13429
13809
  EventCategory2["StreamBrokerOnCamStreamIdle"] = "stream-broker.onCamStreamIdle";
13430
13810
  EventCategory2["StreamBrokerOnRequestStreamSourceRefresh"] = "stream-broker.onRequestStreamSourceRefresh";
13811
+ EventCategory2["StreamParamsChanged"] = "stream-params.changed";
13431
13812
  EventCategory2["DeviceStateChanged"] = "device.state-changed";
13432
13813
  EventCategory2["BatteryOnStatusChanged"] = "battery.onStatusChanged";
13433
13814
  EventCategory2["DoorbellOnPressed"] = "doorbell.onPressed";
@@ -13475,6 +13856,7 @@ var EventCategory = /* @__PURE__ */ ((EventCategory2) => {
13475
13856
  EventCategory2["NetworkTunnelStarted"] = "network.tunnel.started";
13476
13857
  EventCategory2["NetworkTunnelStopped"] = "network.tunnel.stopped";
13477
13858
  EventCategory2["LocalNetworkChanged"] = "network.local.changed";
13859
+ EventCategory2["MeshNetworkChanged"] = "network.mesh.changed";
13478
13860
  EventCategory2["BackupCompleted"] = "backup.completed";
13479
13861
  EventCategory2["BackupRestored"] = "backup.restored";
13480
13862
  EventCategory2["NotificationDispatched"] = "notification.dispatched";
@@ -13485,6 +13867,7 @@ var EventCategory = /* @__PURE__ */ ((EventCategory2) => {
13485
13867
  EventCategory2["DeviceAwake"] = "device.awake";
13486
13868
  EventCategory2["DeviceSleeping"] = "device.sleeping";
13487
13869
  EventCategory2["RetentionCleanup"] = "retention.cleanup";
13870
+ EventCategory2["AddonsBulkUpdateProgress"] = "addons.bulk-update-progress";
13488
13871
  return EventCategory2;
13489
13872
  })(EventCategory || {});
13490
13873
  function createEvent(category, source, data) {
@@ -13634,7 +14017,7 @@ class BaseAddon {
13634
14017
  }
13635
14018
  // ── Settings schemas (override to provide UI) ─────────────────────────
13636
14019
  /** Override to provide global-level settings UI schema. */
13637
- globalSettingsSchema() {
14020
+ globalSettingsSchema(_cap) {
13638
14021
  return null;
13639
14022
  }
13640
14023
  /** Override to provide device-level settings UI schema. */
@@ -13648,8 +14031,8 @@ class BaseAddon {
13648
14031
  // blob and every addon used exactly one of them; the distinction was
13649
14032
  // never semantically load-bearing. `global` won because it was the
13650
14033
  // widely-used one and the name reads naturally (per-node addon config).
13651
- async getGlobalSettings(overlay) {
13652
- const schema = this.globalSettingsSchema();
14034
+ async getGlobalSettings(overlay, cap) {
14035
+ const schema = this.globalSettingsSchema(cap);
13653
14036
  if (!schema) return { sections: [] };
13654
14037
  const raw = await this._ctx?.settings?.readAddonStore() ?? {};
13655
14038
  return hydrateSchema(schema, overlay ? { ...raw, ...overlay } : raw);