@mega-yfue/eufy-sdk 0.6.0-beta.42 → 0.6.0-beta.43
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.js +107 -49
- package/dist/index.js.map +3 -3
- package/dist/model/capabilities/thing-description.d.ts +3 -5
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -16388,19 +16388,19 @@ function buildKeyedActuatePayload(id, devicePublicKeyHex, userName, rnd) {
|
|
|
16388
16388
|
payload: sealInnerPayload(inner, aesKeyHex, id.deviceSn)
|
|
16389
16389
|
};
|
|
16390
16390
|
}
|
|
16391
|
-
function keyedPayloadReportCode(
|
|
16392
|
-
if (
|
|
16391
|
+
function keyedPayloadReportCode(json2, engage) {
|
|
16392
|
+
if (json2?.cmd !== CommandType.P2P_QUERY_STATUS_IN_LOCK)
|
|
16393
16393
|
return void 0;
|
|
16394
|
-
const payload =
|
|
16394
|
+
const payload = json2.payload;
|
|
16395
16395
|
const slState = engage ? "4" : "3";
|
|
16396
16396
|
if (payload?.slState !== slState)
|
|
16397
16397
|
return void 0;
|
|
16398
16398
|
return typeof payload?.code === "number" ? payload.code : void 0;
|
|
16399
16399
|
}
|
|
16400
|
-
function keyedPayloadSeqMark(
|
|
16401
|
-
if (
|
|
16400
|
+
function keyedPayloadSeqMark(json2) {
|
|
16401
|
+
if (json2?.cmd !== CommandType.CMD_DOORLOCK_P2P_SEQ)
|
|
16402
16402
|
return void 0;
|
|
16403
|
-
const seq =
|
|
16403
|
+
const seq = json2.payload?.seq_num;
|
|
16404
16404
|
return typeof seq === "number" && Number.isFinite(seq) ? seq : void 0;
|
|
16405
16405
|
}
|
|
16406
16406
|
|
|
@@ -17696,8 +17696,8 @@ var P2PSession = class _P2PSession extends EventEmitter2 {
|
|
|
17696
17696
|
* `channel`. This is the form the eufy app uses for control commands (confirmed by live capture:
|
|
17697
17697
|
* floodlight = `{"commandType":1400,"data":{...}}`). Returns `false` if no level-2 key.
|
|
17698
17698
|
*/
|
|
17699
|
-
sendRawLevel2(
|
|
17700
|
-
return this.sendRawLevel2Bytes(Buffer.from(
|
|
17699
|
+
sendRawLevel2(json2, channel, outerCmd = CMD_SET_PAYLOAD) {
|
|
17700
|
+
return this.sendRawLevel2Bytes(Buffer.from(json2, "utf-8"), channel, outerCmd);
|
|
17701
17701
|
}
|
|
17702
17702
|
/**
|
|
17703
17703
|
* Like {@link sendRawLevel2} but the plaintext is a raw byte buffer, not a UTF-8 string. Some
|
|
@@ -17805,13 +17805,13 @@ var P2PSession = class _P2PSession extends EventEmitter2 {
|
|
|
17805
17805
|
body.writeUInt32LE(channel >>> 0, 0);
|
|
17806
17806
|
return this.sendRawLevel2Bytes(body, channel, start ? CMD_START_TALKBACK : CMD_STOP_TALKBACK, 8);
|
|
17807
17807
|
}
|
|
17808
|
-
const
|
|
17808
|
+
const json2 = JSON.stringify({
|
|
17809
17809
|
commandType: start ? CMD_START_SPEAK : CMD_END_SPEAK,
|
|
17810
17810
|
data: { transaction: String(Date.now()) }
|
|
17811
17811
|
});
|
|
17812
17812
|
if (this.level2Key)
|
|
17813
|
-
return this.sendRawLevel2(
|
|
17814
|
-
this.sendStringPayloadCommand(CMD_CONTROL_PAYLOAD,
|
|
17813
|
+
return this.sendRawLevel2(json2, channel, CMD_CONTROL_PAYLOAD);
|
|
17814
|
+
this.sendStringPayloadCommand(CMD_CONTROL_PAYLOAD, json2, channel);
|
|
17815
17815
|
return true;
|
|
17816
17816
|
}
|
|
17817
17817
|
/**
|
|
@@ -23736,17 +23736,17 @@ var P2PCommandRouter = class _P2PCommandRouter {
|
|
|
23736
23736
|
session.off("data", onData);
|
|
23737
23737
|
};
|
|
23738
23738
|
session.on("data", onData);
|
|
23739
|
-
const
|
|
23739
|
+
const json2 = JSON.stringify({ commandType: param, data });
|
|
23740
23740
|
this.sendBySessionLevel(sn, {
|
|
23741
23741
|
l1: ({ session: s, channel: ch }) => {
|
|
23742
|
-
s.sendStringPayloadCommand(P2P_ENVELOPE.CONTROL_PAYLOAD,
|
|
23742
|
+
s.sendStringPayloadCommand(P2P_ENVELOPE.CONTROL_PAYLOAD, json2, ch);
|
|
23743
23743
|
return Promise.resolve();
|
|
23744
23744
|
},
|
|
23745
23745
|
l2: async ({ session: s, channel: ch, parentSn }) => {
|
|
23746
23746
|
if (!await s.awaitLevel2Key(LEVEL2_GRACE_MS, "call")) {
|
|
23747
23747
|
throw new StationKeyUnavailableError(parentSn);
|
|
23748
23748
|
}
|
|
23749
|
-
s.sendRawLevel2(
|
|
23749
|
+
s.sendRawLevel2(json2, ch, P2P_ENVELOPE.CONTROL_PAYLOAD);
|
|
23750
23750
|
}
|
|
23751
23751
|
}).catch((e) => {
|
|
23752
23752
|
cleanup();
|
|
@@ -24432,17 +24432,17 @@ var P2PCommandRouter = class _P2PCommandRouter {
|
|
|
24432
24432
|
* the session to connect + (for HomeBase) the level-2 key.
|
|
24433
24433
|
*/
|
|
24434
24434
|
async routeControl(sn, outerCmd, inner) {
|
|
24435
|
-
const
|
|
24435
|
+
const json2 = JSON.stringify(inner);
|
|
24436
24436
|
await this.sendBySessionLevel(sn, {
|
|
24437
24437
|
l1: ({ session, channel }) => {
|
|
24438
|
-
session.sendStringPayloadCommand(outerCmd,
|
|
24438
|
+
session.sendStringPayloadCommand(outerCmd, json2, channel);
|
|
24439
24439
|
return Promise.resolve();
|
|
24440
24440
|
},
|
|
24441
24441
|
l2: async ({ session, channel }) => {
|
|
24442
24442
|
if (!await session.awaitLevel2Key(LEVEL2_GRACE_MS, "call")) {
|
|
24443
24443
|
throw new Error(`level-2 key not ready for ${sn} \u2014 cannot route HomeBase command`);
|
|
24444
24444
|
}
|
|
24445
|
-
session.sendRawLevel2(
|
|
24445
|
+
session.sendRawLevel2(json2, channel, outerCmd);
|
|
24446
24446
|
}
|
|
24447
24447
|
});
|
|
24448
24448
|
}
|
|
@@ -25058,7 +25058,7 @@ var PtcsFramer = class {
|
|
|
25058
25058
|
// dist/transport/rtc/scall-sdp.js
|
|
25059
25059
|
var HUB_SDP_MID = "2";
|
|
25060
25060
|
var ANKER_MAX_MESSAGE_SIZE = 262144;
|
|
25061
|
-
function scallJsonToSdp(
|
|
25061
|
+
function scallJsonToSdp(json2, now2 = Date.now) {
|
|
25062
25062
|
let sdp = "";
|
|
25063
25063
|
sdp += "v=0\r\n";
|
|
25064
25064
|
sdp += `o=- ${Math.floor(now2())} 1 IN IP4 127.0.0.1\r
|
|
@@ -25073,42 +25073,42 @@ function scallJsonToSdp(json, now2 = Date.now) {
|
|
|
25073
25073
|
sdp += `a=mid:${HUB_SDP_MID}\r
|
|
25074
25074
|
`;
|
|
25075
25075
|
sdp += "a=ice-options:trickle\r\n";
|
|
25076
|
-
if (
|
|
25077
|
-
sdp += `a=ice-ufrag:${
|
|
25076
|
+
if (json2.ice?.ufrag)
|
|
25077
|
+
sdp += `a=ice-ufrag:${json2.ice.ufrag}\r
|
|
25078
25078
|
`;
|
|
25079
|
-
if (
|
|
25080
|
-
sdp += `a=ice-pwd:${
|
|
25079
|
+
if (json2.ice?.pwd)
|
|
25080
|
+
sdp += `a=ice-pwd:${json2.ice.pwd}\r
|
|
25081
25081
|
`;
|
|
25082
|
-
if (
|
|
25083
|
-
const fp =
|
|
25084
|
-
sdp += `a=fingerprint:${
|
|
25082
|
+
if (json2.ice?.fingerprint) {
|
|
25083
|
+
const fp = json2.ice.fingerprint.replace(/(.{2})(?=.)/g, "$1:");
|
|
25084
|
+
sdp += `a=fingerprint:${json2.ice.fingerprint_type ?? "sha-256"} ${fp}\r
|
|
25085
25085
|
`;
|
|
25086
25086
|
}
|
|
25087
|
-
sdp += `a=setup:${
|
|
25087
|
+
sdp += `a=setup:${json2.setup ?? "actpass"}\r
|
|
25088
25088
|
`;
|
|
25089
25089
|
sdp += "a=sctp-port:5000\r\n";
|
|
25090
25090
|
sdp += `a=max-message-size:${ANKER_MAX_MESSAGE_SIZE}\r
|
|
25091
25091
|
`;
|
|
25092
|
-
for (const c of
|
|
25092
|
+
for (const c of json2.candidate ?? [])
|
|
25093
25093
|
sdp += `a=candidate:${c}\r
|
|
25094
25094
|
`;
|
|
25095
25095
|
return sdp;
|
|
25096
25096
|
}
|
|
25097
25097
|
function sdpToScallJson(sdp) {
|
|
25098
|
-
const
|
|
25098
|
+
const json2 = { ice: { ufrag: "", pwd: "", fingerprint: "" } };
|
|
25099
25099
|
const setup = sdp.match(/a=setup:([^\r\n]+)/)?.[1];
|
|
25100
25100
|
if (setup && setup !== "actpass")
|
|
25101
|
-
|
|
25101
|
+
json2.setup = setup;
|
|
25102
25102
|
const ufrag = sdp.match(/a=ice-ufrag:([^\r\n]+)/)?.[1];
|
|
25103
25103
|
if (ufrag)
|
|
25104
|
-
|
|
25104
|
+
json2.ice.ufrag = ufrag;
|
|
25105
25105
|
const pwd = sdp.match(/a=ice-pwd:([^\r\n]+)/)?.[1];
|
|
25106
25106
|
if (pwd)
|
|
25107
|
-
|
|
25107
|
+
json2.ice.pwd = pwd;
|
|
25108
25108
|
const fp = sdp.match(/a=fingerprint:([^\s]+)\s+([^\r\n]+)/);
|
|
25109
25109
|
if (fp?.[2]) {
|
|
25110
|
-
|
|
25111
|
-
|
|
25110
|
+
json2.ice.fingerprint_type = fp[1];
|
|
25111
|
+
json2.ice.fingerprint = fp[2].replace(/:/g, "");
|
|
25112
25112
|
}
|
|
25113
25113
|
const candidates = [];
|
|
25114
25114
|
for (const line of sdp.split(/\r\n|\r|\n/)) {
|
|
@@ -25117,8 +25117,8 @@ function sdpToScallJson(sdp) {
|
|
|
25117
25117
|
candidates.push(m[1]);
|
|
25118
25118
|
}
|
|
25119
25119
|
if (candidates.length)
|
|
25120
|
-
|
|
25121
|
-
return
|
|
25120
|
+
json2.candidate = candidates;
|
|
25121
|
+
return json2;
|
|
25122
25122
|
}
|
|
25123
25123
|
function iceCandidateType(candidate) {
|
|
25124
25124
|
return candidate.match(/typ (\w+)/)?.[1] ?? "unknown";
|
|
@@ -27630,10 +27630,10 @@ function deriveBodyKey(requestId, ecode) {
|
|
|
27630
27630
|
const hex = createHmac5("sha256", requestId).update(msg, "utf-8").digest("hex");
|
|
27631
27631
|
return Buffer.from(hex.slice(0, 16), "ascii");
|
|
27632
27632
|
}
|
|
27633
|
-
function encryptBody2(key,
|
|
27633
|
+
function encryptBody2(key, json2) {
|
|
27634
27634
|
const nonce = randomBytes6(12);
|
|
27635
27635
|
const cipher = createCipheriv7("aes-128-gcm", key, nonce);
|
|
27636
|
-
const ciphertext = Buffer.concat([cipher.update(Buffer.from(
|
|
27636
|
+
const ciphertext = Buffer.concat([cipher.update(Buffer.from(json2, "utf-8")), cipher.final()]);
|
|
27637
27637
|
return Buffer.concat([nonce, ciphertext, cipher.getAuthTag()]).toString("base64");
|
|
27638
27638
|
}
|
|
27639
27639
|
function decryptReply(key, resultB64) {
|
|
@@ -28822,11 +28822,11 @@ var PushClient = class _PushClient extends EventEmitter13 {
|
|
|
28822
28822
|
const data = {};
|
|
28823
28823
|
for (const kv of object?.appData ?? []) {
|
|
28824
28824
|
if (kv.key === "payload") {
|
|
28825
|
-
const
|
|
28825
|
+
const json2 = readNullTerminated(Buffer.from(kv.value, "base64"));
|
|
28826
28826
|
try {
|
|
28827
|
-
data.payload = JSON.parse(
|
|
28827
|
+
data.payload = JSON.parse(json2);
|
|
28828
28828
|
} catch {
|
|
28829
|
-
data.payload =
|
|
28829
|
+
data.payload = json2;
|
|
28830
28830
|
}
|
|
28831
28831
|
} else {
|
|
28832
28832
|
data[kv.key] = kv.value;
|
|
@@ -29340,7 +29340,71 @@ function cameraInfo(facts, qualifier, value) {
|
|
|
29340
29340
|
return typeof spec.value === "string" && spec.value === reported;
|
|
29341
29341
|
if (qualifier === "RE")
|
|
29342
29342
|
return typeof spec.regex === "string" && re(spec.regex, reported);
|
|
29343
|
-
|
|
29343
|
+
if (qualifier !== "json_match" || !spec.json_match || typeof spec.json_match !== "object")
|
|
29344
|
+
return false;
|
|
29345
|
+
const target = json(reported);
|
|
29346
|
+
return !!target && typeof target === "object" && !Array.isArray(target) && jsonMatch(target, spec.json_match);
|
|
29347
|
+
}
|
|
29348
|
+
var content = (v) => v === null || v === void 0 || typeof v === "object" ? void 0 : String(v);
|
|
29349
|
+
var json = (text2) => {
|
|
29350
|
+
try {
|
|
29351
|
+
return JSON.parse(text2);
|
|
29352
|
+
} catch {
|
|
29353
|
+
return void 0;
|
|
29354
|
+
}
|
|
29355
|
+
};
|
|
29356
|
+
var asInt = (v, fallback) => {
|
|
29357
|
+
const n = Number.parseInt(String(v), 10);
|
|
29358
|
+
return Number.isNaN(n) ? fallback : n;
|
|
29359
|
+
};
|
|
29360
|
+
var ASSOCIATED = {
|
|
29361
|
+
/** `true` once `APP_CMD_SET_SILENT_OTA_SWITCH` (6287) is reported. */
|
|
29362
|
+
is_support_silent_ota_switch: (p) => p[6287] === void 0 ? void 0 : "true",
|
|
29363
|
+
/** `APP_CMD_HB3_AI_Empowerment` (1299): its JSON value, else the value as an integer (0 when none). */
|
|
29364
|
+
ai_empower: (p) => {
|
|
29365
|
+
const v = p[1299];
|
|
29366
|
+
if (v === void 0)
|
|
29367
|
+
return void 0;
|
|
29368
|
+
const parsed = json(v);
|
|
29369
|
+
if (parsed === void 0)
|
|
29370
|
+
return String(asInt(v, 0));
|
|
29371
|
+
return content(parsed) ?? JSON.stringify(parsed);
|
|
29372
|
+
},
|
|
29373
|
+
/** `APP_CMD_GET_POWER_SUPPLY_MODE` (6445): its JSON `power_source`, else `source`, as an integer; 1 when empty. */
|
|
29374
|
+
device_power_supply_mode: (p) => {
|
|
29375
|
+
const v = p[6445];
|
|
29376
|
+
if (v === void 0)
|
|
29377
|
+
return void 0;
|
|
29378
|
+
if (v === "")
|
|
29379
|
+
return "1";
|
|
29380
|
+
const parsed = json(v);
|
|
29381
|
+
return parsed === void 0 ? void 0 : String(asInt(parsed?.power_source ?? parsed?.source, 1));
|
|
29382
|
+
}
|
|
29383
|
+
};
|
|
29384
|
+
function jsonMatch(target, match) {
|
|
29385
|
+
const checks = [];
|
|
29386
|
+
const keys = (k) => Array.isArray(match[k]) ? match[k].map(content).filter((x) => x !== void 0) : [];
|
|
29387
|
+
const pairs = (k) => match[k] && typeof match[k] === "object" ? Object.entries(match[k]).map(([key, v]) => [key, content(v)]) : [];
|
|
29388
|
+
for (const k of keys("contains_key"))
|
|
29389
|
+
checks.push(Object.hasOwn(target, k));
|
|
29390
|
+
for (const k of keys("not_contains_key"))
|
|
29391
|
+
checks.push(!Object.hasOwn(target, k));
|
|
29392
|
+
const valued = (k, test) => {
|
|
29393
|
+
for (const [key, expected] of pairs(k)) {
|
|
29394
|
+
const actual = content(target[key]);
|
|
29395
|
+
checks.push(expected !== void 0 && actual !== void 0 && test(actual, expected));
|
|
29396
|
+
}
|
|
29397
|
+
};
|
|
29398
|
+
valued("value_equals", (a, e) => a === e);
|
|
29399
|
+
valued("value_not_equals", (a, e) => a !== e);
|
|
29400
|
+
valued("value_regex", (a, e) => {
|
|
29401
|
+
try {
|
|
29402
|
+
return new RegExp(e).test(a);
|
|
29403
|
+
} catch {
|
|
29404
|
+
return false;
|
|
29405
|
+
}
|
|
29406
|
+
});
|
|
29407
|
+
return match.mode === "any" ? checks.some(Boolean) : checks.every(Boolean);
|
|
29344
29408
|
}
|
|
29345
29409
|
function condition(c, facts) {
|
|
29346
29410
|
const station = facts.stationSerial ?? facts.serial ?? "";
|
|
@@ -29358,15 +29422,10 @@ function condition(c, facts) {
|
|
|
29358
29422
|
return re(c.value, facts.serial ?? "");
|
|
29359
29423
|
case "user_country":
|
|
29360
29424
|
return re(c.value, facts.country ?? "");
|
|
29361
|
-
case "user_domain":
|
|
29362
|
-
return re(c.value, "");
|
|
29363
29425
|
case "sdk_version":
|
|
29364
29426
|
return version(APP_SDK_VERSION, c.qualifier, c.value);
|
|
29365
29427
|
case "associated_field":
|
|
29366
|
-
|
|
29367
|
-
return compare("", c.qualifier, c.value);
|
|
29368
|
-
case "user_permission":
|
|
29369
|
-
return c.qualifier === "in";
|
|
29428
|
+
return compare(ASSOCIATED[c.propId ?? ""]?.(facts.params ?? {}) ?? "", c.qualifier, c.value);
|
|
29370
29429
|
case "camera_info":
|
|
29371
29430
|
return cameraInfo(facts, c.qualifier, c.value);
|
|
29372
29431
|
default:
|
|
@@ -29399,7 +29458,7 @@ function resolveThing(td, facts) {
|
|
|
29399
29458
|
const p = td.properties[chosen];
|
|
29400
29459
|
if (!p || !conditionsPass(p.availableConditions, facts))
|
|
29401
29460
|
continue;
|
|
29402
|
-
properties[base] =
|
|
29461
|
+
properties[base] = p;
|
|
29403
29462
|
}
|
|
29404
29463
|
const available = (entries) => {
|
|
29405
29464
|
const out = /* @__PURE__ */ Object.create(null);
|
|
@@ -29450,7 +29509,6 @@ function property(p) {
|
|
|
29450
29509
|
...num2(specs.step) !== void 0 ? { step: num2(specs.step) } : {},
|
|
29451
29510
|
...optStr(specs.unit) !== void 0 ? { unit: str3(specs.unit) } : {},
|
|
29452
29511
|
readConditions: conditions(p.read_conditions),
|
|
29453
|
-
writeConditions: conditions(p.write_conditions),
|
|
29454
29512
|
availableConditions: conditions(p.available_conditions)
|
|
29455
29513
|
};
|
|
29456
29514
|
}
|