@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 +135 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +140 -45
- package/dist/index.d.ts +140 -45
- package/dist/index.js +133 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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.
|
|
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,
|