@apocaliss92/nodedreame 1.12.2 → 1.12.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -976,6 +976,81 @@ declare class VacuumCapabilityResolver implements CapabilityResolver {
976
976
  resolve(model: string): DeviceCapabilities;
977
977
  }
978
978
 
979
+ /**
980
+ * Public types for the video control-plane. The Dreamehome cloud fronts several
981
+ * camera backends ("vendors"); a device advertises which ones it supports and
982
+ * which one it is currently provisioned on. This module models only the
983
+ * control-plane (token + session negotiation); the media transport per vendor
984
+ * is built on top of it.
985
+ */
986
+ /** Camera backend a device streams through. `tx` = Tencent, `ali` = Aliyun LinkVisual. */
987
+ type VideoVendor = 'tx' | 'ali';
988
+ /** Short-lived token minted by `tx/user/accesstoken`, used by the video endpoints. */
989
+ interface VideoAccessToken {
990
+ /** Opaque bearer for the third-video service (distinct from the account token). */
991
+ readonly token: string;
992
+ /** Numeric video-service user id, as a string. */
993
+ readonly userId: string | null;
994
+ /** Epoch-ms at which {@link token} expires (converted from the cloud's epoch-seconds). */
995
+ readonly expiresAt: number;
996
+ }
997
+ /**
998
+ * A device's video profile, derived from its cloud record. Tells you whether the
999
+ * device has a camera, which vendors it supports, which one it is on now, and —
1000
+ * when on Aliyun — its LinkVisual `iotId` (the id every LinkVisual call needs).
1001
+ */
1002
+ interface DeviceVideoProfile {
1003
+ /** Dreame device id (the `did`). */
1004
+ readonly did: string;
1005
+ /** Model code, e.g. `dreame.vacuum.r2538z`. */
1006
+ readonly model: string;
1007
+ /** Human product name, e.g. `X50 Ultra Complete`. */
1008
+ readonly displayName: string | null;
1009
+ /** True when the device exposes a camera stream (`permit === "video"`). */
1010
+ readonly videoCapable: boolean;
1011
+ /** The vendor the device is currently provisioned on (`''` in the record → null). */
1012
+ readonly currentVendor: VideoVendor | null;
1013
+ /** Vendors the device can use, in cloud-declared order. */
1014
+ readonly supportedVendors: readonly VideoVendor[];
1015
+ /** True when the cloud picks the vendor dynamically at session time. */
1016
+ readonly dynamicVendor: boolean;
1017
+ /** Aliyun LinkVisual device id, when the device is on (or has been on) Aliyun. */
1018
+ readonly iotId: string | null;
1019
+ /** Whether the device is online. */
1020
+ readonly online: boolean;
1021
+ }
1022
+ /**
1023
+ * A device's TENCENT IoT triple, from `tx/mgr/dev/getIdentity`.
1024
+ *
1025
+ * Present only while the device is provisioned on the `tx` vendor. The secrets
1026
+ * are session-scoped credentials for the Tencent IoT plane — never log them.
1027
+ */
1028
+ interface TencentDeviceIdentity {
1029
+ readonly productId: string;
1030
+ readonly deviceName: string;
1031
+ /** `<productId>/<deviceName>`, as the cloud composes it. */
1032
+ readonly deviceId: string | null;
1033
+ readonly secretId: string | null;
1034
+ readonly secretKey: string | null;
1035
+ }
1036
+ /**
1037
+ * The xp2p session descriptor from `tx/dev/getP2PInfo`.
1038
+ *
1039
+ * OPAQUE by nature: measured at 35 characters on an X50 and not JSON — it is
1040
+ * the handle Tencent's proprietary xp2p SDK consumes to open the UDP P2P
1041
+ * session, not a URL anything else can dial. It is carried, never parsed.
1042
+ */
1043
+ interface TencentP2PDescriptor {
1044
+ readonly p2pInfo: string;
1045
+ }
1046
+
1047
+ /** What the device reports about its video SDK. */
1048
+ interface VideoVendorStatus {
1049
+ readonly vendor: VideoVendor | null;
1050
+ /** `1` once the SDK for {@link vendor} is up. A switch is not done until this. */
1051
+ readonly initStatus: number | null;
1052
+ }
1053
+
979
1054
  /**
980
1055
  * MIoT surface of the Dreame camera service (SIID 10001), reversed byte-exact
981
1056
  * from the r2538z (X50) React-Native plugin `Monitor` model. Every camera
@@ -2076,6 +2151,39 @@ declare class VacuumDevice extends BaseDevice<VacuumDeviceEvents> {
2076
2151
  /** Reuse an existing relay minter (e.g. a shared {@link DreameVideoSession}). */
2077
2152
  relay?: RelayMinter;
2078
2153
  }): Promise<DreameCameraController>;
2154
+ /**
2155
+ * What video backend this robot is on, and whether that backend's SDK is up.
2156
+ *
2157
+ * A CACHED read by default: the cloud shadow answers for a robot on its dock
2158
+ * without waking it, which is the whole point of asking before deciding how
2159
+ * to stream. Pass `{ live: true }` when the answer must be current — while a
2160
+ * switch settles, for instance.
2161
+ */
2162
+ readVideoVendorStatus(opts?: {
2163
+ live?: boolean;
2164
+ }): Promise<VideoVendorStatus>;
2165
+ /**
2166
+ * Move this robot onto a video backend, and WAIT until it is really there.
2167
+ *
2168
+ * The two backends are not interchangeable: measured on an X50 on
2169
+ * 2026-09-16, a robot on `tx` offers only Tencent's proprietary UDP P2P
2170
+ * plane (`getRtcInfo` answers 404), while the same robot on `ali` streams
2171
+ * through a plain RTMP relay this library implements end to end. So which
2172
+ * one it sits on decides whether it can be streamed at all.
2173
+ *
2174
+ * The device reports the NEW vendor before its SDK is up, which is why the
2175
+ * app polls rather than trusting the action's return — and why this resolves
2176
+ * on `initStatus === 1` and not a moment earlier. A half-switched robot
2177
+ * answers questions about a backend it cannot yet serve.
2178
+ *
2179
+ * Only meaningful on a dual-vendor device (`videoDynamicVendor`, with the
2180
+ * target in `defaultVendors`); a device that cannot move simply never
2181
+ * settles, and this reports that as a timeout rather than a silent success.
2182
+ */
2183
+ setVideoVendor(vendor: VideoVendor, opts?: {
2184
+ timeoutMs?: number;
2185
+ pollIntervalMs?: number;
2186
+ }): Promise<VideoVendorStatus>;
2079
2187
  /** Props worth seeding on start() / polling — exported for the facade. */
2080
2188
  static readonly DEFAULT_PROPS: readonly [{
2081
2189
  readonly siid: 2;
@@ -3050,50 +3158,6 @@ declare function createDumper(target: DumperDevice, options?: DumperOptions): Du
3050
3158
  */
3051
3159
  declare function createClientDumper(client: Nodreame, options?: DumperOptions): Dumper[];
3052
3160
 
3053
- /**
3054
- * Public types for the video control-plane. The Dreamehome cloud fronts several
3055
- * camera backends ("vendors"); a device advertises which ones it supports and
3056
- * which one it is currently provisioned on. This module models only the
3057
- * control-plane (token + session negotiation); the media transport per vendor
3058
- * is built on top of it.
3059
- */
3060
- /** Camera backend a device streams through. `tx` = Tencent, `ali` = Aliyun LinkVisual. */
3061
- type VideoVendor = 'tx' | 'ali';
3062
- /** Short-lived token minted by `tx/user/accesstoken`, used by the video endpoints. */
3063
- interface VideoAccessToken {
3064
- /** Opaque bearer for the third-video service (distinct from the account token). */
3065
- readonly token: string;
3066
- /** Numeric video-service user id, as a string. */
3067
- readonly userId: string | null;
3068
- /** Epoch-ms at which {@link token} expires (converted from the cloud's epoch-seconds). */
3069
- readonly expiresAt: number;
3070
- }
3071
- /**
3072
- * A device's video profile, derived from its cloud record. Tells you whether the
3073
- * device has a camera, which vendors it supports, which one it is on now, and —
3074
- * when on Aliyun — its LinkVisual `iotId` (the id every LinkVisual call needs).
3075
- */
3076
- interface DeviceVideoProfile {
3077
- /** Dreame device id (the `did`). */
3078
- readonly did: string;
3079
- /** Model code, e.g. `dreame.vacuum.r2538z`. */
3080
- readonly model: string;
3081
- /** Human product name, e.g. `X50 Ultra Complete`. */
3082
- readonly displayName: string | null;
3083
- /** True when the device exposes a camera stream (`permit === "video"`). */
3084
- readonly videoCapable: boolean;
3085
- /** The vendor the device is currently provisioned on (`''` in the record → null). */
3086
- readonly currentVendor: VideoVendor | null;
3087
- /** Vendors the device can use, in cloud-declared order. */
3088
- readonly supportedVendors: readonly VideoVendor[];
3089
- /** True when the cloud picks the vendor dynamically at session time. */
3090
- readonly dynamicVendor: boolean;
3091
- /** Aliyun LinkVisual device id, when the device is on (or has been on) Aliyun. */
3092
- readonly iotId: string | null;
3093
- /** Whether the device is online. */
3094
- readonly online: boolean;
3095
- }
3096
-
3097
3161
  /** Shared inputs for every video control-plane call. Mirrors `listDevices`. */
3098
3162
  interface VideoRequestInput {
3099
3163
  session: DreameSession;
@@ -3125,6 +3189,37 @@ declare function getAliyunAuthCode(input: VideoRequestInput): Promise<string>;
3125
3189
  declare function getVideoFamilyId(input: VideoRequestInput & {
3126
3190
  videoToken?: string;
3127
3191
  }): Promise<string>;
3192
+ /**
3193
+ * The device's TENCENT IoT triple.
3194
+ *
3195
+ * Only meaningful while the device sits on the `tx` vendor: the cloud answers
3196
+ * `设备三元组不存在` ("the triple does not exist") otherwise, which this
3197
+ * surfaces as a thrown {@link DreameError} like any other refusal — a device on
3198
+ * `ali` has no Tencent identity, and that is a statement about the device, not
3199
+ * a failure of the call.
3200
+ */
3201
+ declare function getTencentIdentity(input: VideoRequestInput & {
3202
+ did: string;
3203
+ videoToken?: string;
3204
+ }): Promise<TencentDeviceIdentity>;
3205
+ /**
3206
+ * The xp2p session descriptor for a device on the `tx` vendor.
3207
+ *
3208
+ * ## This may WAKE THE CAMERA
3209
+ *
3210
+ * It is the Tencent equivalent of asking for a stream, so it is never called
3211
+ * as part of a status read.
3212
+ *
3213
+ * The result is opaque (see {@link TencentP2PDescriptor}) and is useless
3214
+ * without an xp2p implementation: measured on an X50 on 2026-09-16, the
3215
+ * sibling `tx/dev/getRtcInfo` — the TRTC path, which WOULD be portable — answers
3216
+ * 404 for this model. So the only media plane Tencent offers this device is the
3217
+ * proprietary UDP P2P one.
3218
+ */
3219
+ declare function getTencentP2PInfo(input: VideoRequestInput & {
3220
+ did: string;
3221
+ videoToken?: string;
3222
+ }): Promise<TencentP2PDescriptor>;
3128
3223
  /**
3129
3224
  * Resolve a device's video profile (vendor, supported vendors, Aliyun iotId,
3130
3225
  * capability) from its cloud record. `did` is the Dreame device id.
@@ -3746,4 +3841,4 @@ interface ListDevicesInput {
3746
3841
  /** Enumerate the devices visible to the authenticated account (incl. shared). */
3747
3842
  declare function listDevices(input: ListDevicesInput): Promise<DreameDevice[]>;
3748
3843
 
3749
- export { AI_FEATURE_BIT, AI_FEATURE_JSON_KEY, ALIYUN_REGION_ID, AUTO_SWITCH_JSON_KEY, type AacConfig, type AiDetectionRaw, type AudioInfoEvent, type AutoSwitchKey, type AutoSwitchRaw, type AvcConfig, BaseDevice, type BaseDeviceEvents, type BatchDeviceDataFetcher, type BrokerEndpoint, type CameraStreamHandle, type CapabilityResolver, ChargingStatus, type CleanOpts, CleaningMode, type ConsumableReading, type ConsumableSpec, type CreateDeviceArgs, DRIVE_DIRECTIONS, DefaultCapabilityResolver, type DetectionBox, type DeviceCapabilities, type DeviceConnectivity, type DeviceDump, type DeviceEvent, type DeviceVideoProfile, type DreameAiFeature, DreameApiError, DreameAuthError, DreameCameraController, type DreameCameraControllerInput, DreameCameraStream, type DreameCameraStreamEvents, type DreameCameraStreamInput, type DreameCloudState, type DreameConsumableKey, type DreameDevice, DreameDeviceOfflineError, DreameError, type DreameRegion, type DreameSession, DreameTransportError, DreameVideoSession, type DreameVideoSessionInput, type DriveDirection, type DumperOptions, type FrameSource, type FrameSourceFactory, type IotSession, LIBRARY_NAME, LV_STATUS, type ListDevicesInput, LvRtmpClient, type LvRtmpClientOptions, MONITOR_AIID, MONITOR_PIID, MONITOR_SIID, MONITOR_VENDOR_TOKEN, MODEL_CAPABILITIES as MOWER_MODEL_CAPABILITIES, MOWER_TASK_SUBSTATES, type MapBoundingBox, type MapCleanedAreaOverlay, type MapColorScheme, type MapDimensions, type MapFrameType, type MapLayer, type MapLayerType, type MapLowLyingArea, type MapObstacle, type MapPath, type MapPathType, type MapPoint, type MapPose, type MapRestrictedArea, type MapRoom, type MapRoomWall, type MapRun, type MapSegment, type MapStorey, type MapVirtualWall, type MapWallsInfo, type MiotAction, MiotError, type MiotProp, MiotState, type MonitorActionCaller, type MowerAvailableMap, type MowerCapabilities, MowerCapabilityResolver, MowerChargingStatus, type MowerConsumableKey, type MowerConsumableReading, type MowerContour, MowerControlAction, type MowerControlState, MowerDevice, type MowerDeviceInput, MowerFault, type MowerFaultSeverity, type MowerHeartbeat, type MowerMap, type MowerMapBoundary, type MowerMowPath, type MowerMowingProgress, type MowerPathEntry, type MowerPoint, type MowerSpotArea, MowerStatus, type MowerTaskDescriptor, MowerTaskStatus, type MowerTaskSubState, type MowerZone, Nodreame, type NodreameDeps, type NodreameEvents, type NodreameOptions, type OaSession, type ObstacleDetection, type OssFetchInput, type OssFetcherLike, PET_SOUNDS, type PersonFollowDetection, type PetSound, type PropertyChangedEvent, type PropertyResult, type PropertyState, type PropertyWrite, type RelayMinter, type RenderMowerSvgOptions, type RenderVacuumPngOptions, type RenderWifiSignalPngOptions, type StateChangedEvent, type StatusEvent, type StreamInfo, type StreamQueryInput, SuctionLevel, TALK_AUDIO_HEADER_G711A, TaskStatus, VACUUM_ACTIONS, VACUUM_CONSUMABLES, MODEL_CAPABILITIES$1 as VACUUM_MODEL_CAPABILITIES, VACUUM_MOVE, VACUUM_SIID, type VacuumActionKey, type VacuumCapabilities, VacuumCapabilityResolver, VacuumDevice, type VacuumGetMapInput, type VacuumMap, type VideoAccessToken, type VideoAccessUnitEvent, type VideoRequestInput, type VideoVendor, WaterVolume, type WifiSignalMap, type WifiSignalMapInput, aacSampleRate, aacToAdts, avccToAnnexB, consumableSpec, createClientDumper, createDumper, createIotSession, decodeAiFeature, decodeAutoSwitch, decodeAutoSwitchAll, decodeWifiSignalMap, encodeAiFeatureWrite, encodeAutoSwitchWrite, explainNoCameraChannel, extractMowerConsumableValues, getAliyunAuthCode, getDeviceVideoProfile, getMowerCapabilities, getVacuumCapabilities, getVideoAccessToken, getVideoFamilyId, hashAccessCode, isAuthRefusedError, isDreameConsumableKey, listDevices, loginByOauth, makeMonitorSession, mowerConsumableIndex, mowerFaultSeverity, parseAacConfig, parseAvcConfig, parseConnectivity, parseMowerConsumables, parseMowerHeartbeat, parseMowingProgress, parseObstacleData, parsePersonFollow, parseRelayUrl, pcm16ToALaw, pcm16leToALaw, remoteDriveValue, renderMowerSvg, renderVacuumPng, renderWifiSignalPng, resolveCapabilities, signApiGatewayRequest, streamQuery, supportedAutoSwitchKeys, toVideoProfile };
3844
+ export { AI_FEATURE_BIT, AI_FEATURE_JSON_KEY, ALIYUN_REGION_ID, AUTO_SWITCH_JSON_KEY, type AacConfig, type AiDetectionRaw, type AudioInfoEvent, type AutoSwitchKey, type AutoSwitchRaw, type AvcConfig, BaseDevice, type BaseDeviceEvents, type BatchDeviceDataFetcher, type BrokerEndpoint, type CameraStreamHandle, type CapabilityResolver, ChargingStatus, type CleanOpts, CleaningMode, type ConsumableReading, type ConsumableSpec, type CreateDeviceArgs, DRIVE_DIRECTIONS, DefaultCapabilityResolver, type DetectionBox, type DeviceCapabilities, type DeviceConnectivity, type DeviceDump, type DeviceEvent, type DeviceVideoProfile, type DreameAiFeature, DreameApiError, DreameAuthError, DreameCameraController, type DreameCameraControllerInput, DreameCameraStream, type DreameCameraStreamEvents, type DreameCameraStreamInput, type DreameCloudState, type DreameConsumableKey, type DreameDevice, DreameDeviceOfflineError, DreameError, type DreameRegion, type DreameSession, DreameTransportError, DreameVideoSession, type DreameVideoSessionInput, type DriveDirection, type DumperOptions, type FrameSource, type FrameSourceFactory, type IotSession, LIBRARY_NAME, LV_STATUS, type ListDevicesInput, LvRtmpClient, type LvRtmpClientOptions, MONITOR_AIID, MONITOR_PIID, MONITOR_SIID, MONITOR_VENDOR_TOKEN, MODEL_CAPABILITIES as MOWER_MODEL_CAPABILITIES, MOWER_TASK_SUBSTATES, type MapBoundingBox, type MapCleanedAreaOverlay, type MapColorScheme, type MapDimensions, type MapFrameType, type MapLayer, type MapLayerType, type MapLowLyingArea, type MapObstacle, type MapPath, type MapPathType, type MapPoint, type MapPose, type MapRestrictedArea, type MapRoom, type MapRoomWall, type MapRun, type MapSegment, type MapStorey, type MapVirtualWall, type MapWallsInfo, type MiotAction, MiotError, type MiotProp, MiotState, type MonitorActionCaller, type MowerAvailableMap, type MowerCapabilities, MowerCapabilityResolver, MowerChargingStatus, type MowerConsumableKey, type MowerConsumableReading, type MowerContour, MowerControlAction, type MowerControlState, MowerDevice, type MowerDeviceInput, MowerFault, type MowerFaultSeverity, type MowerHeartbeat, type MowerMap, type MowerMapBoundary, type MowerMowPath, type MowerMowingProgress, type MowerPathEntry, type MowerPoint, type MowerSpotArea, MowerStatus, type MowerTaskDescriptor, MowerTaskStatus, type MowerTaskSubState, type MowerZone, Nodreame, type NodreameDeps, type NodreameEvents, type NodreameOptions, type OaSession, type ObstacleDetection, type OssFetchInput, type OssFetcherLike, PET_SOUNDS, type PersonFollowDetection, type PetSound, type PropertyChangedEvent, type PropertyResult, type PropertyState, type PropertyWrite, type RelayMinter, type RenderMowerSvgOptions, type RenderVacuumPngOptions, type RenderWifiSignalPngOptions, type StateChangedEvent, type StatusEvent, type StreamInfo, type StreamQueryInput, SuctionLevel, TALK_AUDIO_HEADER_G711A, TaskStatus, VACUUM_ACTIONS, VACUUM_CONSUMABLES, MODEL_CAPABILITIES$1 as VACUUM_MODEL_CAPABILITIES, VACUUM_MOVE, VACUUM_SIID, type VacuumActionKey, type VacuumCapabilities, VacuumCapabilityResolver, VacuumDevice, type VacuumGetMapInput, type VacuumMap, type VideoAccessToken, type VideoAccessUnitEvent, type VideoRequestInput, type VideoVendor, WaterVolume, type WifiSignalMap, type WifiSignalMapInput, aacSampleRate, aacToAdts, avccToAnnexB, consumableSpec, createClientDumper, createDumper, createIotSession, decodeAiFeature, decodeAutoSwitch, decodeAutoSwitchAll, decodeWifiSignalMap, encodeAiFeatureWrite, encodeAutoSwitchWrite, explainNoCameraChannel, extractMowerConsumableValues, getAliyunAuthCode, getDeviceVideoProfile, getMowerCapabilities, getTencentIdentity, getTencentP2PInfo, getVacuumCapabilities, getVideoAccessToken, getVideoFamilyId, hashAccessCode, isAuthRefusedError, isDreameConsumableKey, listDevices, loginByOauth, makeMonitorSession, mowerConsumableIndex, mowerFaultSeverity, parseAacConfig, parseAvcConfig, parseConnectivity, parseMowerConsumables, parseMowerHeartbeat, parseMowingProgress, parseObstacleData, parsePersonFollow, parseRelayUrl, pcm16ToALaw, pcm16leToALaw, remoteDriveValue, renderMowerSvg, renderVacuumPng, renderWifiSignalPng, resolveCapabilities, signApiGatewayRequest, streamQuery, supportedAutoSwitchKeys, toVideoProfile };
package/dist/index.d.ts CHANGED
@@ -976,6 +976,81 @@ declare class VacuumCapabilityResolver implements CapabilityResolver {
976
976
  resolve(model: string): DeviceCapabilities;
977
977
  }
978
978
 
979
+ /**
980
+ * Public types for the video control-plane. The Dreamehome cloud fronts several
981
+ * camera backends ("vendors"); a device advertises which ones it supports and
982
+ * which one it is currently provisioned on. This module models only the
983
+ * control-plane (token + session negotiation); the media transport per vendor
984
+ * is built on top of it.
985
+ */
986
+ /** Camera backend a device streams through. `tx` = Tencent, `ali` = Aliyun LinkVisual. */
987
+ type VideoVendor = 'tx' | 'ali';
988
+ /** Short-lived token minted by `tx/user/accesstoken`, used by the video endpoints. */
989
+ interface VideoAccessToken {
990
+ /** Opaque bearer for the third-video service (distinct from the account token). */
991
+ readonly token: string;
992
+ /** Numeric video-service user id, as a string. */
993
+ readonly userId: string | null;
994
+ /** Epoch-ms at which {@link token} expires (converted from the cloud's epoch-seconds). */
995
+ readonly expiresAt: number;
996
+ }
997
+ /**
998
+ * A device's video profile, derived from its cloud record. Tells you whether the
999
+ * device has a camera, which vendors it supports, which one it is on now, and —
1000
+ * when on Aliyun — its LinkVisual `iotId` (the id every LinkVisual call needs).
1001
+ */
1002
+ interface DeviceVideoProfile {
1003
+ /** Dreame device id (the `did`). */
1004
+ readonly did: string;
1005
+ /** Model code, e.g. `dreame.vacuum.r2538z`. */
1006
+ readonly model: string;
1007
+ /** Human product name, e.g. `X50 Ultra Complete`. */
1008
+ readonly displayName: string | null;
1009
+ /** True when the device exposes a camera stream (`permit === "video"`). */
1010
+ readonly videoCapable: boolean;
1011
+ /** The vendor the device is currently provisioned on (`''` in the record → null). */
1012
+ readonly currentVendor: VideoVendor | null;
1013
+ /** Vendors the device can use, in cloud-declared order. */
1014
+ readonly supportedVendors: readonly VideoVendor[];
1015
+ /** True when the cloud picks the vendor dynamically at session time. */
1016
+ readonly dynamicVendor: boolean;
1017
+ /** Aliyun LinkVisual device id, when the device is on (or has been on) Aliyun. */
1018
+ readonly iotId: string | null;
1019
+ /** Whether the device is online. */
1020
+ readonly online: boolean;
1021
+ }
1022
+ /**
1023
+ * A device's TENCENT IoT triple, from `tx/mgr/dev/getIdentity`.
1024
+ *
1025
+ * Present only while the device is provisioned on the `tx` vendor. The secrets
1026
+ * are session-scoped credentials for the Tencent IoT plane — never log them.
1027
+ */
1028
+ interface TencentDeviceIdentity {
1029
+ readonly productId: string;
1030
+ readonly deviceName: string;
1031
+ /** `<productId>/<deviceName>`, as the cloud composes it. */
1032
+ readonly deviceId: string | null;
1033
+ readonly secretId: string | null;
1034
+ readonly secretKey: string | null;
1035
+ }
1036
+ /**
1037
+ * The xp2p session descriptor from `tx/dev/getP2PInfo`.
1038
+ *
1039
+ * OPAQUE by nature: measured at 35 characters on an X50 and not JSON — it is
1040
+ * the handle Tencent's proprietary xp2p SDK consumes to open the UDP P2P
1041
+ * session, not a URL anything else can dial. It is carried, never parsed.
1042
+ */
1043
+ interface TencentP2PDescriptor {
1044
+ readonly p2pInfo: string;
1045
+ }
1046
+
1047
+ /** What the device reports about its video SDK. */
1048
+ interface VideoVendorStatus {
1049
+ readonly vendor: VideoVendor | null;
1050
+ /** `1` once the SDK for {@link vendor} is up. A switch is not done until this. */
1051
+ readonly initStatus: number | null;
1052
+ }
1053
+
979
1054
  /**
980
1055
  * MIoT surface of the Dreame camera service (SIID 10001), reversed byte-exact
981
1056
  * from the r2538z (X50) React-Native plugin `Monitor` model. Every camera
@@ -2076,6 +2151,39 @@ declare class VacuumDevice extends BaseDevice<VacuumDeviceEvents> {
2076
2151
  /** Reuse an existing relay minter (e.g. a shared {@link DreameVideoSession}). */
2077
2152
  relay?: RelayMinter;
2078
2153
  }): Promise<DreameCameraController>;
2154
+ /**
2155
+ * What video backend this robot is on, and whether that backend's SDK is up.
2156
+ *
2157
+ * A CACHED read by default: the cloud shadow answers for a robot on its dock
2158
+ * without waking it, which is the whole point of asking before deciding how
2159
+ * to stream. Pass `{ live: true }` when the answer must be current — while a
2160
+ * switch settles, for instance.
2161
+ */
2162
+ readVideoVendorStatus(opts?: {
2163
+ live?: boolean;
2164
+ }): Promise<VideoVendorStatus>;
2165
+ /**
2166
+ * Move this robot onto a video backend, and WAIT until it is really there.
2167
+ *
2168
+ * The two backends are not interchangeable: measured on an X50 on
2169
+ * 2026-09-16, a robot on `tx` offers only Tencent's proprietary UDP P2P
2170
+ * plane (`getRtcInfo` answers 404), while the same robot on `ali` streams
2171
+ * through a plain RTMP relay this library implements end to end. So which
2172
+ * one it sits on decides whether it can be streamed at all.
2173
+ *
2174
+ * The device reports the NEW vendor before its SDK is up, which is why the
2175
+ * app polls rather than trusting the action's return — and why this resolves
2176
+ * on `initStatus === 1` and not a moment earlier. A half-switched robot
2177
+ * answers questions about a backend it cannot yet serve.
2178
+ *
2179
+ * Only meaningful on a dual-vendor device (`videoDynamicVendor`, with the
2180
+ * target in `defaultVendors`); a device that cannot move simply never
2181
+ * settles, and this reports that as a timeout rather than a silent success.
2182
+ */
2183
+ setVideoVendor(vendor: VideoVendor, opts?: {
2184
+ timeoutMs?: number;
2185
+ pollIntervalMs?: number;
2186
+ }): Promise<VideoVendorStatus>;
2079
2187
  /** Props worth seeding on start() / polling — exported for the facade. */
2080
2188
  static readonly DEFAULT_PROPS: readonly [{
2081
2189
  readonly siid: 2;
@@ -3050,50 +3158,6 @@ declare function createDumper(target: DumperDevice, options?: DumperOptions): Du
3050
3158
  */
3051
3159
  declare function createClientDumper(client: Nodreame, options?: DumperOptions): Dumper[];
3052
3160
 
3053
- /**
3054
- * Public types for the video control-plane. The Dreamehome cloud fronts several
3055
- * camera backends ("vendors"); a device advertises which ones it supports and
3056
- * which one it is currently provisioned on. This module models only the
3057
- * control-plane (token + session negotiation); the media transport per vendor
3058
- * is built on top of it.
3059
- */
3060
- /** Camera backend a device streams through. `tx` = Tencent, `ali` = Aliyun LinkVisual. */
3061
- type VideoVendor = 'tx' | 'ali';
3062
- /** Short-lived token minted by `tx/user/accesstoken`, used by the video endpoints. */
3063
- interface VideoAccessToken {
3064
- /** Opaque bearer for the third-video service (distinct from the account token). */
3065
- readonly token: string;
3066
- /** Numeric video-service user id, as a string. */
3067
- readonly userId: string | null;
3068
- /** Epoch-ms at which {@link token} expires (converted from the cloud's epoch-seconds). */
3069
- readonly expiresAt: number;
3070
- }
3071
- /**
3072
- * A device's video profile, derived from its cloud record. Tells you whether the
3073
- * device has a camera, which vendors it supports, which one it is on now, and —
3074
- * when on Aliyun — its LinkVisual `iotId` (the id every LinkVisual call needs).
3075
- */
3076
- interface DeviceVideoProfile {
3077
- /** Dreame device id (the `did`). */
3078
- readonly did: string;
3079
- /** Model code, e.g. `dreame.vacuum.r2538z`. */
3080
- readonly model: string;
3081
- /** Human product name, e.g. `X50 Ultra Complete`. */
3082
- readonly displayName: string | null;
3083
- /** True when the device exposes a camera stream (`permit === "video"`). */
3084
- readonly videoCapable: boolean;
3085
- /** The vendor the device is currently provisioned on (`''` in the record → null). */
3086
- readonly currentVendor: VideoVendor | null;
3087
- /** Vendors the device can use, in cloud-declared order. */
3088
- readonly supportedVendors: readonly VideoVendor[];
3089
- /** True when the cloud picks the vendor dynamically at session time. */
3090
- readonly dynamicVendor: boolean;
3091
- /** Aliyun LinkVisual device id, when the device is on (or has been on) Aliyun. */
3092
- readonly iotId: string | null;
3093
- /** Whether the device is online. */
3094
- readonly online: boolean;
3095
- }
3096
-
3097
3161
  /** Shared inputs for every video control-plane call. Mirrors `listDevices`. */
3098
3162
  interface VideoRequestInput {
3099
3163
  session: DreameSession;
@@ -3125,6 +3189,37 @@ declare function getAliyunAuthCode(input: VideoRequestInput): Promise<string>;
3125
3189
  declare function getVideoFamilyId(input: VideoRequestInput & {
3126
3190
  videoToken?: string;
3127
3191
  }): Promise<string>;
3192
+ /**
3193
+ * The device's TENCENT IoT triple.
3194
+ *
3195
+ * Only meaningful while the device sits on the `tx` vendor: the cloud answers
3196
+ * `设备三元组不存在` ("the triple does not exist") otherwise, which this
3197
+ * surfaces as a thrown {@link DreameError} like any other refusal — a device on
3198
+ * `ali` has no Tencent identity, and that is a statement about the device, not
3199
+ * a failure of the call.
3200
+ */
3201
+ declare function getTencentIdentity(input: VideoRequestInput & {
3202
+ did: string;
3203
+ videoToken?: string;
3204
+ }): Promise<TencentDeviceIdentity>;
3205
+ /**
3206
+ * The xp2p session descriptor for a device on the `tx` vendor.
3207
+ *
3208
+ * ## This may WAKE THE CAMERA
3209
+ *
3210
+ * It is the Tencent equivalent of asking for a stream, so it is never called
3211
+ * as part of a status read.
3212
+ *
3213
+ * The result is opaque (see {@link TencentP2PDescriptor}) and is useless
3214
+ * without an xp2p implementation: measured on an X50 on 2026-09-16, the
3215
+ * sibling `tx/dev/getRtcInfo` — the TRTC path, which WOULD be portable — answers
3216
+ * 404 for this model. So the only media plane Tencent offers this device is the
3217
+ * proprietary UDP P2P one.
3218
+ */
3219
+ declare function getTencentP2PInfo(input: VideoRequestInput & {
3220
+ did: string;
3221
+ videoToken?: string;
3222
+ }): Promise<TencentP2PDescriptor>;
3128
3223
  /**
3129
3224
  * Resolve a device's video profile (vendor, supported vendors, Aliyun iotId,
3130
3225
  * capability) from its cloud record. `did` is the Dreame device id.
@@ -3746,4 +3841,4 @@ interface ListDevicesInput {
3746
3841
  /** Enumerate the devices visible to the authenticated account (incl. shared). */
3747
3842
  declare function listDevices(input: ListDevicesInput): Promise<DreameDevice[]>;
3748
3843
 
3749
- export { AI_FEATURE_BIT, AI_FEATURE_JSON_KEY, ALIYUN_REGION_ID, AUTO_SWITCH_JSON_KEY, type AacConfig, type AiDetectionRaw, type AudioInfoEvent, type AutoSwitchKey, type AutoSwitchRaw, type AvcConfig, BaseDevice, type BaseDeviceEvents, type BatchDeviceDataFetcher, type BrokerEndpoint, type CameraStreamHandle, type CapabilityResolver, ChargingStatus, type CleanOpts, CleaningMode, type ConsumableReading, type ConsumableSpec, type CreateDeviceArgs, DRIVE_DIRECTIONS, DefaultCapabilityResolver, type DetectionBox, type DeviceCapabilities, type DeviceConnectivity, type DeviceDump, type DeviceEvent, type DeviceVideoProfile, type DreameAiFeature, DreameApiError, DreameAuthError, DreameCameraController, type DreameCameraControllerInput, DreameCameraStream, type DreameCameraStreamEvents, type DreameCameraStreamInput, type DreameCloudState, type DreameConsumableKey, type DreameDevice, DreameDeviceOfflineError, DreameError, type DreameRegion, type DreameSession, DreameTransportError, DreameVideoSession, type DreameVideoSessionInput, type DriveDirection, type DumperOptions, type FrameSource, type FrameSourceFactory, type IotSession, LIBRARY_NAME, LV_STATUS, type ListDevicesInput, LvRtmpClient, type LvRtmpClientOptions, MONITOR_AIID, MONITOR_PIID, MONITOR_SIID, MONITOR_VENDOR_TOKEN, MODEL_CAPABILITIES as MOWER_MODEL_CAPABILITIES, MOWER_TASK_SUBSTATES, type MapBoundingBox, type MapCleanedAreaOverlay, type MapColorScheme, type MapDimensions, type MapFrameType, type MapLayer, type MapLayerType, type MapLowLyingArea, type MapObstacle, type MapPath, type MapPathType, type MapPoint, type MapPose, type MapRestrictedArea, type MapRoom, type MapRoomWall, type MapRun, type MapSegment, type MapStorey, type MapVirtualWall, type MapWallsInfo, type MiotAction, MiotError, type MiotProp, MiotState, type MonitorActionCaller, type MowerAvailableMap, type MowerCapabilities, MowerCapabilityResolver, MowerChargingStatus, type MowerConsumableKey, type MowerConsumableReading, type MowerContour, MowerControlAction, type MowerControlState, MowerDevice, type MowerDeviceInput, MowerFault, type MowerFaultSeverity, type MowerHeartbeat, type MowerMap, type MowerMapBoundary, type MowerMowPath, type MowerMowingProgress, type MowerPathEntry, type MowerPoint, type MowerSpotArea, MowerStatus, type MowerTaskDescriptor, MowerTaskStatus, type MowerTaskSubState, type MowerZone, Nodreame, type NodreameDeps, type NodreameEvents, type NodreameOptions, type OaSession, type ObstacleDetection, type OssFetchInput, type OssFetcherLike, PET_SOUNDS, type PersonFollowDetection, type PetSound, type PropertyChangedEvent, type PropertyResult, type PropertyState, type PropertyWrite, type RelayMinter, type RenderMowerSvgOptions, type RenderVacuumPngOptions, type RenderWifiSignalPngOptions, type StateChangedEvent, type StatusEvent, type StreamInfo, type StreamQueryInput, SuctionLevel, TALK_AUDIO_HEADER_G711A, TaskStatus, VACUUM_ACTIONS, VACUUM_CONSUMABLES, MODEL_CAPABILITIES$1 as VACUUM_MODEL_CAPABILITIES, VACUUM_MOVE, VACUUM_SIID, type VacuumActionKey, type VacuumCapabilities, VacuumCapabilityResolver, VacuumDevice, type VacuumGetMapInput, type VacuumMap, type VideoAccessToken, type VideoAccessUnitEvent, type VideoRequestInput, type VideoVendor, WaterVolume, type WifiSignalMap, type WifiSignalMapInput, aacSampleRate, aacToAdts, avccToAnnexB, consumableSpec, createClientDumper, createDumper, createIotSession, decodeAiFeature, decodeAutoSwitch, decodeAutoSwitchAll, decodeWifiSignalMap, encodeAiFeatureWrite, encodeAutoSwitchWrite, explainNoCameraChannel, extractMowerConsumableValues, getAliyunAuthCode, getDeviceVideoProfile, getMowerCapabilities, getVacuumCapabilities, getVideoAccessToken, getVideoFamilyId, hashAccessCode, isAuthRefusedError, isDreameConsumableKey, listDevices, loginByOauth, makeMonitorSession, mowerConsumableIndex, mowerFaultSeverity, parseAacConfig, parseAvcConfig, parseConnectivity, parseMowerConsumables, parseMowerHeartbeat, parseMowingProgress, parseObstacleData, parsePersonFollow, parseRelayUrl, pcm16ToALaw, pcm16leToALaw, remoteDriveValue, renderMowerSvg, renderVacuumPng, renderWifiSignalPng, resolveCapabilities, signApiGatewayRequest, streamQuery, supportedAutoSwitchKeys, toVideoProfile };
3844
+ export { AI_FEATURE_BIT, AI_FEATURE_JSON_KEY, ALIYUN_REGION_ID, AUTO_SWITCH_JSON_KEY, type AacConfig, type AiDetectionRaw, type AudioInfoEvent, type AutoSwitchKey, type AutoSwitchRaw, type AvcConfig, BaseDevice, type BaseDeviceEvents, type BatchDeviceDataFetcher, type BrokerEndpoint, type CameraStreamHandle, type CapabilityResolver, ChargingStatus, type CleanOpts, CleaningMode, type ConsumableReading, type ConsumableSpec, type CreateDeviceArgs, DRIVE_DIRECTIONS, DefaultCapabilityResolver, type DetectionBox, type DeviceCapabilities, type DeviceConnectivity, type DeviceDump, type DeviceEvent, type DeviceVideoProfile, type DreameAiFeature, DreameApiError, DreameAuthError, DreameCameraController, type DreameCameraControllerInput, DreameCameraStream, type DreameCameraStreamEvents, type DreameCameraStreamInput, type DreameCloudState, type DreameConsumableKey, type DreameDevice, DreameDeviceOfflineError, DreameError, type DreameRegion, type DreameSession, DreameTransportError, DreameVideoSession, type DreameVideoSessionInput, type DriveDirection, type DumperOptions, type FrameSource, type FrameSourceFactory, type IotSession, LIBRARY_NAME, LV_STATUS, type ListDevicesInput, LvRtmpClient, type LvRtmpClientOptions, MONITOR_AIID, MONITOR_PIID, MONITOR_SIID, MONITOR_VENDOR_TOKEN, MODEL_CAPABILITIES as MOWER_MODEL_CAPABILITIES, MOWER_TASK_SUBSTATES, type MapBoundingBox, type MapCleanedAreaOverlay, type MapColorScheme, type MapDimensions, type MapFrameType, type MapLayer, type MapLayerType, type MapLowLyingArea, type MapObstacle, type MapPath, type MapPathType, type MapPoint, type MapPose, type MapRestrictedArea, type MapRoom, type MapRoomWall, type MapRun, type MapSegment, type MapStorey, type MapVirtualWall, type MapWallsInfo, type MiotAction, MiotError, type MiotProp, MiotState, type MonitorActionCaller, type MowerAvailableMap, type MowerCapabilities, MowerCapabilityResolver, MowerChargingStatus, type MowerConsumableKey, type MowerConsumableReading, type MowerContour, MowerControlAction, type MowerControlState, MowerDevice, type MowerDeviceInput, MowerFault, type MowerFaultSeverity, type MowerHeartbeat, type MowerMap, type MowerMapBoundary, type MowerMowPath, type MowerMowingProgress, type MowerPathEntry, type MowerPoint, type MowerSpotArea, MowerStatus, type MowerTaskDescriptor, MowerTaskStatus, type MowerTaskSubState, type MowerZone, Nodreame, type NodreameDeps, type NodreameEvents, type NodreameOptions, type OaSession, type ObstacleDetection, type OssFetchInput, type OssFetcherLike, PET_SOUNDS, type PersonFollowDetection, type PetSound, type PropertyChangedEvent, type PropertyResult, type PropertyState, type PropertyWrite, type RelayMinter, type RenderMowerSvgOptions, type RenderVacuumPngOptions, type RenderWifiSignalPngOptions, type StateChangedEvent, type StatusEvent, type StreamInfo, type StreamQueryInput, SuctionLevel, TALK_AUDIO_HEADER_G711A, TaskStatus, VACUUM_ACTIONS, VACUUM_CONSUMABLES, MODEL_CAPABILITIES$1 as VACUUM_MODEL_CAPABILITIES, VACUUM_MOVE, VACUUM_SIID, type VacuumActionKey, type VacuumCapabilities, VacuumCapabilityResolver, VacuumDevice, type VacuumGetMapInput, type VacuumMap, type VideoAccessToken, type VideoAccessUnitEvent, type VideoRequestInput, type VideoVendor, WaterVolume, type WifiSignalMap, type WifiSignalMapInput, aacSampleRate, aacToAdts, avccToAnnexB, consumableSpec, createClientDumper, createDumper, createIotSession, decodeAiFeature, decodeAutoSwitch, decodeAutoSwitchAll, decodeWifiSignalMap, encodeAiFeatureWrite, encodeAutoSwitchWrite, explainNoCameraChannel, extractMowerConsumableValues, getAliyunAuthCode, getDeviceVideoProfile, getMowerCapabilities, getTencentIdentity, getTencentP2PInfo, getVacuumCapabilities, getVideoAccessToken, getVideoFamilyId, hashAccessCode, isAuthRefusedError, isDreameConsumableKey, listDevices, loginByOauth, makeMonitorSession, mowerConsumableIndex, mowerFaultSeverity, parseAacConfig, parseAvcConfig, parseConnectivity, parseMowerConsumables, parseMowerHeartbeat, parseMowingProgress, parseObstacleData, parsePersonFollow, parseRelayUrl, pcm16ToALaw, pcm16leToALaw, remoteDriveValue, renderMowerSvg, renderVacuumPng, renderWifiSignalPng, resolveCapabilities, signApiGatewayRequest, streamQuery, supportedAutoSwitchKeys, toVideoProfile };
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // src/support/version.ts
2
2
  var LIBRARY_NAME = "nodedreame";
3
- var LIBRARY_VERSION = "1.12.2";
3
+ var LIBRARY_VERSION = "1.12.4";
4
4
 
5
5
  // src/transport/errors.ts
6
6
  var DreameError = class extends Error {
@@ -2066,6 +2066,24 @@ var FamilyIdResponseSchema = z3.object({
2066
2066
  msg: z3.string().nullish(),
2067
2067
  data: z3.object({ data: z3.object({ familyId: z3.string() }).passthrough() }).passthrough()
2068
2068
  }).passthrough();
2069
+ var TencentIdentityResponseSchema = z3.object({
2070
+ code: z3.number().optional(),
2071
+ msg: z3.string().nullish(),
2072
+ data: z3.object({
2073
+ data: z3.object({
2074
+ productId: z3.string(),
2075
+ deviceName: z3.string(),
2076
+ deviceId: z3.string().optional(),
2077
+ secretId: z3.string().optional(),
2078
+ secretKey: z3.string().optional()
2079
+ }).passthrough()
2080
+ }).passthrough()
2081
+ }).passthrough();
2082
+ var TencentP2PInfoResponseSchema = z3.object({
2083
+ code: z3.number().optional(),
2084
+ msg: z3.string().nullish(),
2085
+ data: z3.object({ data: z3.object({ p2pInfo: z3.string() }).passthrough() }).passthrough()
2086
+ }).passthrough();
2069
2087
  var DeviceVideoInfoSchema = z3.object({
2070
2088
  model: z3.string().optional(),
2071
2089
  displayName: z3.string().optional(),
@@ -2186,6 +2204,37 @@ async function getVideoFamilyId(input) {
2186
2204
  });
2187
2205
  return FamilyIdResponseSchema.parse(raw).data.data.familyId;
2188
2206
  }
2207
+ async function getTencentIdentity(input) {
2208
+ const ctx = resolveCtx(input);
2209
+ const videoToken = input.videoToken ?? (await getVideoAccessToken({ ...input, ctx })).token;
2210
+ const raw = await httpPostJsonBody({
2211
+ ctx,
2212
+ path: `${P_THIRD_VIDEO}/tx/mgr/dev/getIdentity`,
2213
+ body: { accesstoken: videoToken, os: DEFAULT_OS, did: input.did },
2214
+ context: "tencent identity",
2215
+ ...passthrough(input)
2216
+ });
2217
+ const d = TencentIdentityResponseSchema.parse(raw).data.data;
2218
+ return {
2219
+ productId: d.productId,
2220
+ deviceName: d.deviceName,
2221
+ deviceId: d.deviceId ?? null,
2222
+ secretId: d.secretId ?? null,
2223
+ secretKey: d.secretKey ?? null
2224
+ };
2225
+ }
2226
+ async function getTencentP2PInfo(input) {
2227
+ const ctx = resolveCtx(input);
2228
+ const videoToken = input.videoToken ?? (await getVideoAccessToken({ ...input, ctx })).token;
2229
+ const raw = await httpPostJsonBody({
2230
+ ctx,
2231
+ path: `${P_THIRD_VIDEO}/tx/dev/getP2PInfo`,
2232
+ body: { accesstoken: videoToken, os: DEFAULT_OS, did: input.did },
2233
+ context: "tencent p2p info",
2234
+ ...passthrough(input)
2235
+ });
2236
+ return { p2pInfo: TencentP2PInfoResponseSchema.parse(raw).data.data.p2pInfo };
2237
+ }
2189
2238
  async function getDeviceVideoProfile(input) {
2190
2239
  const ctx = resolveCtx(input);
2191
2240
  const raw = await httpPostJsonBody({
@@ -2778,6 +2827,34 @@ function firstOutValue(res) {
2778
2827
  return Array.isArray(out) && out.length > 0 ? out[0]?.value : void 0;
2779
2828
  }
2780
2829
 
2830
+ // src/video/monitor/vendor.ts
2831
+ function videoVendorSwitchParams(vendor) {
2832
+ return { vendor };
2833
+ }
2834
+ function parseVideoVendorStatus(raw) {
2835
+ const text = typeof raw === "string" ? raw : typeof raw === "object" && raw !== null ? null : null;
2836
+ const source = text === null ? raw : safeJson(text);
2837
+ if (typeof source !== "object" || source === null) {
2838
+ return { vendor: null, initStatus: null };
2839
+ }
2840
+ const v = Reflect.get(source, "vendor");
2841
+ const s = Reflect.get(source, "initStatus");
2842
+ return {
2843
+ vendor: v === "ali" || v === "tx" ? v : null,
2844
+ initStatus: typeof s === "number" ? s : null
2845
+ };
2846
+ }
2847
+ function safeJson(text) {
2848
+ try {
2849
+ return JSON.parse(text);
2850
+ } catch {
2851
+ return null;
2852
+ }
2853
+ }
2854
+ function vendorSwitchSettled(status, wanted) {
2855
+ return status.vendor === wanted && status.initStatus === 1;
2856
+ }
2857
+
2781
2858
  // src/video/monitor/controller.ts
2782
2859
  var DEFAULT_KEEP_ALIVE_MS = 1e4;
2783
2860
  var DEFAULT_AREA = "4";
@@ -5358,6 +5435,60 @@ var VacuumDevice = class _VacuumDevice extends BaseDevice {
5358
5435
  ...opts?.log ? { log: opts.log } : {}
5359
5436
  });
5360
5437
  }
5438
+ /**
5439
+ * What video backend this robot is on, and whether that backend's SDK is up.
5440
+ *
5441
+ * A CACHED read by default: the cloud shadow answers for a robot on its dock
5442
+ * without waking it, which is the whole point of asking before deciding how
5443
+ * to stream. Pass `{ live: true }` when the answer must be current — while a
5444
+ * switch settles, for instance.
5445
+ */
5446
+ async readVideoVendorStatus(opts) {
5447
+ const props = [{ siid: MONITOR_SIID, piid: MONITOR_PIID.VIDEO_VENDOR_STATUS }];
5448
+ const results = opts?.live === true ? await this.refreshProperties(props) : await this.refreshCachedProperties(props);
5449
+ return parseVideoVendorStatus(results[0]?.value);
5450
+ }
5451
+ /**
5452
+ * Move this robot onto a video backend, and WAIT until it is really there.
5453
+ *
5454
+ * The two backends are not interchangeable: measured on an X50 on
5455
+ * 2026-09-16, a robot on `tx` offers only Tencent's proprietary UDP P2P
5456
+ * plane (`getRtcInfo` answers 404), while the same robot on `ali` streams
5457
+ * through a plain RTMP relay this library implements end to end. So which
5458
+ * one it sits on decides whether it can be streamed at all.
5459
+ *
5460
+ * The device reports the NEW vendor before its SDK is up, which is why the
5461
+ * app polls rather than trusting the action's return — and why this resolves
5462
+ * on `initStatus === 1` and not a moment earlier. A half-switched robot
5463
+ * answers questions about a backend it cannot yet serve.
5464
+ *
5465
+ * Only meaningful on a dual-vendor device (`videoDynamicVendor`, with the
5466
+ * target in `defaultVendors`); a device that cannot move simply never
5467
+ * settles, and this reports that as a timeout rather than a silent success.
5468
+ */
5469
+ async setVideoVendor(vendor, opts) {
5470
+ const already = await this.readVideoVendorStatus({ live: true });
5471
+ if (vendorSwitchSettled(already, vendor)) {
5472
+ return already;
5473
+ }
5474
+ const session = makeMonitorSession(this.currentSession().uid);
5475
+ await this.callAction(MONITOR_SIID, MONITOR_AIID.VIDEO_VENDOR, [
5476
+ buildActionInput(MONITOR_PIID.VIDEO_VENDOR_STATUS, videoVendorSwitchParams(vendor), session)
5477
+ ]);
5478
+ const every = opts?.pollIntervalMs ?? 5e3;
5479
+ const deadline = Date.now() + (opts?.timeoutMs ?? every * 10);
5480
+ let last = already;
5481
+ while (Date.now() < deadline) {
5482
+ await new Promise((r) => setTimeout(r, every));
5483
+ last = await this.readVideoVendorStatus({ live: true });
5484
+ if (vendorSwitchSettled(last, vendor)) {
5485
+ return last;
5486
+ }
5487
+ }
5488
+ throw new DreameError(
5489
+ `video vendor did not settle on "${vendor}" within the timeout (last seen: vendor=${last.vendor ?? "unknown"}, initStatus=${String(last.initStatus)})`
5490
+ );
5491
+ }
5361
5492
  /** Props worth seeding on start() / polling — exported for the facade. */
5362
5493
  static DEFAULT_PROPS = [
5363
5494
  VACUUM_PROP.STATE,
@@ -8439,6 +8570,8 @@ export {
8439
8570
  getAliyunAuthCode,
8440
8571
  getDeviceVideoProfile,
8441
8572
  getMowerCapabilities,
8573
+ getTencentIdentity,
8574
+ getTencentP2PInfo,
8442
8575
  getVacuumCapabilities,
8443
8576
  getVideoAccessToken,
8444
8577
  getVideoFamilyId,