@apocaliss92/nodedreame 1.12.2 → 1.12.3

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.cjs CHANGED
@@ -96,6 +96,8 @@ __export(index_exports, {
96
96
  getAliyunAuthCode: () => getAliyunAuthCode,
97
97
  getDeviceVideoProfile: () => getDeviceVideoProfile,
98
98
  getMowerCapabilities: () => getMowerCapabilities,
99
+ getTencentIdentity: () => getTencentIdentity,
100
+ getTencentP2PInfo: () => getTencentP2PInfo,
99
101
  getVacuumCapabilities: () => getVacuumCapabilities,
100
102
  getVideoAccessToken: () => getVideoAccessToken,
101
103
  getVideoFamilyId: () => getVideoFamilyId,
@@ -132,7 +134,7 @@ module.exports = __toCommonJS(index_exports);
132
134
 
133
135
  // src/support/version.ts
134
136
  var LIBRARY_NAME = "nodedreame";
135
- var LIBRARY_VERSION = "1.12.2";
137
+ var LIBRARY_VERSION = "1.12.3";
136
138
 
137
139
  // src/transport/errors.ts
138
140
  var DreameError = class extends Error {
@@ -2198,6 +2200,24 @@ var FamilyIdResponseSchema = import_zod3.z.object({
2198
2200
  msg: import_zod3.z.string().nullish(),
2199
2201
  data: import_zod3.z.object({ data: import_zod3.z.object({ familyId: import_zod3.z.string() }).passthrough() }).passthrough()
2200
2202
  }).passthrough();
2203
+ var TencentIdentityResponseSchema = import_zod3.z.object({
2204
+ code: import_zod3.z.number().optional(),
2205
+ msg: import_zod3.z.string().nullish(),
2206
+ data: import_zod3.z.object({
2207
+ data: import_zod3.z.object({
2208
+ productId: import_zod3.z.string(),
2209
+ deviceName: import_zod3.z.string(),
2210
+ deviceId: import_zod3.z.string().optional(),
2211
+ secretId: import_zod3.z.string().optional(),
2212
+ secretKey: import_zod3.z.string().optional()
2213
+ }).passthrough()
2214
+ }).passthrough()
2215
+ }).passthrough();
2216
+ var TencentP2PInfoResponseSchema = import_zod3.z.object({
2217
+ code: import_zod3.z.number().optional(),
2218
+ msg: import_zod3.z.string().nullish(),
2219
+ data: import_zod3.z.object({ data: import_zod3.z.object({ p2pInfo: import_zod3.z.string() }).passthrough() }).passthrough()
2220
+ }).passthrough();
2201
2221
  var DeviceVideoInfoSchema = import_zod3.z.object({
2202
2222
  model: import_zod3.z.string().optional(),
2203
2223
  displayName: import_zod3.z.string().optional(),
@@ -2318,6 +2338,37 @@ async function getVideoFamilyId(input) {
2318
2338
  });
2319
2339
  return FamilyIdResponseSchema.parse(raw).data.data.familyId;
2320
2340
  }
2341
+ async function getTencentIdentity(input) {
2342
+ const ctx = resolveCtx(input);
2343
+ const videoToken = input.videoToken ?? (await getVideoAccessToken({ ...input, ctx })).token;
2344
+ const raw = await httpPostJsonBody({
2345
+ ctx,
2346
+ path: `${P_THIRD_VIDEO}/tx/mgr/dev/getIdentity`,
2347
+ body: { accesstoken: videoToken, os: DEFAULT_OS, did: input.did },
2348
+ context: "tencent identity",
2349
+ ...passthrough(input)
2350
+ });
2351
+ const d = TencentIdentityResponseSchema.parse(raw).data.data;
2352
+ return {
2353
+ productId: d.productId,
2354
+ deviceName: d.deviceName,
2355
+ deviceId: d.deviceId ?? null,
2356
+ secretId: d.secretId ?? null,
2357
+ secretKey: d.secretKey ?? null
2358
+ };
2359
+ }
2360
+ async function getTencentP2PInfo(input) {
2361
+ const ctx = resolveCtx(input);
2362
+ const videoToken = input.videoToken ?? (await getVideoAccessToken({ ...input, ctx })).token;
2363
+ const raw = await httpPostJsonBody({
2364
+ ctx,
2365
+ path: `${P_THIRD_VIDEO}/tx/dev/getP2PInfo`,
2366
+ body: { accesstoken: videoToken, os: DEFAULT_OS, did: input.did },
2367
+ context: "tencent p2p info",
2368
+ ...passthrough(input)
2369
+ });
2370
+ return { p2pInfo: TencentP2PInfoResponseSchema.parse(raw).data.data.p2pInfo };
2371
+ }
2321
2372
  async function getDeviceVideoProfile(input) {
2322
2373
  const ctx = resolveCtx(input);
2323
2374
  const raw = await httpPostJsonBody({
@@ -2834,6 +2885,34 @@ var VACUUM_ACTIONS = {
2834
2885
  autoEmpty: { siid: 15, aiid: 1 }
2835
2886
  };
2836
2887
 
2888
+ // src/video/monitor/vendor.ts
2889
+ function videoVendorSwitchParams(vendor) {
2890
+ return { vendor };
2891
+ }
2892
+ function parseVideoVendorStatus(raw) {
2893
+ const text = typeof raw === "string" ? raw : typeof raw === "object" && raw !== null ? null : null;
2894
+ const source = text === null ? raw : safeJson(text);
2895
+ if (typeof source !== "object" || source === null) {
2896
+ return { vendor: null, initStatus: null };
2897
+ }
2898
+ const v = Reflect.get(source, "vendor");
2899
+ const s = Reflect.get(source, "initStatus");
2900
+ return {
2901
+ vendor: v === "ali" || v === "tx" ? v : null,
2902
+ initStatus: typeof s === "number" ? s : null
2903
+ };
2904
+ }
2905
+ function safeJson(text) {
2906
+ try {
2907
+ return JSON.parse(text);
2908
+ } catch {
2909
+ return null;
2910
+ }
2911
+ }
2912
+ function vendorSwitchSettled(status, wanted) {
2913
+ return status.vendor === wanted && status.initStatus === 1;
2914
+ }
2915
+
2837
2916
  // src/video/monitor/protocol.ts
2838
2917
  var import_node_crypto4 = require("crypto");
2839
2918
  function makeMonitorSession(accountId, now = Date.now()) {
@@ -5490,6 +5569,59 @@ var VacuumDevice = class _VacuumDevice extends BaseDevice {
5490
5569
  ...opts?.log ? { log: opts.log } : {}
5491
5570
  });
5492
5571
  }
5572
+ /**
5573
+ * What video backend this robot is on, and whether that backend's SDK is up.
5574
+ *
5575
+ * A CACHED read by default: the cloud shadow answers for a robot on its dock
5576
+ * without waking it, which is the whole point of asking before deciding how
5577
+ * to stream. Pass `{ live: true }` when the answer must be current — while a
5578
+ * switch settles, for instance.
5579
+ */
5580
+ async readVideoVendorStatus(opts) {
5581
+ const props = [{ siid: MONITOR_SIID, piid: MONITOR_PIID.VIDEO_VENDOR_STATUS }];
5582
+ const results = opts?.live === true ? await this.refreshProperties(props) : await this.refreshCachedProperties(props);
5583
+ return parseVideoVendorStatus(results[0]?.value);
5584
+ }
5585
+ /**
5586
+ * Move this robot onto a video backend, and WAIT until it is really there.
5587
+ *
5588
+ * The two backends are not interchangeable: measured on an X50 on
5589
+ * 2026-09-16, a robot on `tx` offers only Tencent's proprietary UDP P2P
5590
+ * plane (`getRtcInfo` answers 404), while the same robot on `ali` streams
5591
+ * through a plain RTMP relay this library implements end to end. So which
5592
+ * one it sits on decides whether it can be streamed at all.
5593
+ *
5594
+ * The device reports the NEW vendor before its SDK is up, which is why the
5595
+ * app polls rather than trusting the action's return — and why this resolves
5596
+ * on `initStatus === 1` and not a moment earlier. A half-switched robot
5597
+ * answers questions about a backend it cannot yet serve.
5598
+ *
5599
+ * Only meaningful on a dual-vendor device (`videoDynamicVendor`, with the
5600
+ * target in `defaultVendors`); a device that cannot move simply never
5601
+ * settles, and this reports that as a timeout rather than a silent success.
5602
+ */
5603
+ async setVideoVendor(vendor, opts) {
5604
+ const already = await this.readVideoVendorStatus({ live: true });
5605
+ if (vendorSwitchSettled(already, vendor)) {
5606
+ return already;
5607
+ }
5608
+ await this.callAction(MONITOR_SIID, MONITOR_AIID.VIDEO_VENDOR, [
5609
+ { piid: MONITOR_PIID.VIDEO_VENDOR_STATUS, value: videoVendorSwitchParams(vendor) }
5610
+ ]);
5611
+ const every = opts?.pollIntervalMs ?? 5e3;
5612
+ const deadline = Date.now() + (opts?.timeoutMs ?? every * 10);
5613
+ let last = already;
5614
+ while (Date.now() < deadline) {
5615
+ await new Promise((r) => setTimeout(r, every));
5616
+ last = await this.readVideoVendorStatus({ live: true });
5617
+ if (vendorSwitchSettled(last, vendor)) {
5618
+ return last;
5619
+ }
5620
+ }
5621
+ throw new DreameError(
5622
+ `video vendor did not settle on "${vendor}" within the timeout (last seen: vendor=${last.vendor ?? "unknown"}, initStatus=${String(last.initStatus)})`
5623
+ );
5624
+ }
5493
5625
  /** Props worth seeding on start() / polling — exported for the facade. */
5494
5626
  static DEFAULT_PROPS = [
5495
5627
  VACUUM_PROP.STATE,
@@ -8572,6 +8704,8 @@ var DreameCameraStream = class extends TypedEmitter {
8572
8704
  getAliyunAuthCode,
8573
8705
  getDeviceVideoProfile,
8574
8706
  getMowerCapabilities,
8707
+ getTencentIdentity,
8708
+ getTencentP2PInfo,
8575
8709
  getVacuumCapabilities,
8576
8710
  getVideoAccessToken,
8577
8711
  getVideoFamilyId,