@ray-js/lock-sdk 1.0.3 → 1.1.0-beta.1

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 (63) hide show
  1. package/lib/api/index.d.ts +25 -0
  2. package/lib/api/index.js +59 -3
  3. package/lib/api/linkage.js +7 -7
  4. package/lib/api/lock.d.ts +1 -0
  5. package/lib/api/lock.js +26 -15
  6. package/lib/api/log.d.ts +6 -1
  7. package/lib/api/log.js +6 -6
  8. package/lib/api/request.d.ts +6 -0
  9. package/lib/api/request.js +57 -0
  10. package/lib/api/setting.d.ts +1 -1
  11. package/lib/api/setting.js +3 -3
  12. package/lib/api/temp.d.ts +45 -1
  13. package/lib/api/temp.js +52 -15
  14. package/lib/api/user.d.ts +21 -0
  15. package/lib/api/user.js +26 -7
  16. package/lib/api/video.js +2 -2
  17. package/lib/capability.d.ts +4 -0
  18. package/lib/capability.js +95 -0
  19. package/lib/config/dp-code/index.d.ts +10 -1
  20. package/lib/config/dp-code/index.js +12 -3
  21. package/lib/config/dp-map/normal.d.ts +2 -3
  22. package/lib/config/dp-map/normal.js +2 -9
  23. package/lib/config/dp-map/unlock-method-big.d.ts +3 -7
  24. package/lib/config/dp-map/unlock-method-big.js +30 -1
  25. package/lib/config/dp-map/unlock-method.d.ts +489 -0
  26. package/lib/config/dp-map/unlock-method.js +55 -1
  27. package/lib/config/index.d.ts +7 -1
  28. package/lib/config/index.js +18 -1
  29. package/lib/index.d.ts +6 -2
  30. package/lib/index.js +8 -3
  31. package/lib/interface.d.ts +39 -1
  32. package/lib/log.js +3 -0
  33. package/lib/media.d.ts +6 -1
  34. package/lib/media.js +24 -6
  35. package/lib/offline-dps.d.ts +9 -0
  36. package/lib/offline-dps.js +84 -0
  37. package/lib/open.d.ts +9 -0
  38. package/lib/open.js +90 -11
  39. package/lib/other.d.ts +16 -2
  40. package/lib/other.js +188 -31
  41. package/lib/sleep.d.ts +3 -3
  42. package/lib/sleep.js +40 -25
  43. package/lib/state.js +116 -57
  44. package/lib/sync/offline-dps.d.ts +1 -0
  45. package/lib/sync/offline-dps.js +34 -0
  46. package/lib/sync/remote-serect-key.js +19 -23
  47. package/lib/sync/t0.js +2 -2
  48. package/lib/sync/unlock-method.d.ts +2 -0
  49. package/lib/sync/unlock-method.js +42 -0
  50. package/lib/sync/user.d.ts +2 -0
  51. package/lib/sync/user.js +76 -0
  52. package/lib/temporary.d.ts +93 -0
  53. package/lib/temporary.js +171 -1
  54. package/lib/unlock-method.js +43 -13
  55. package/lib/user.d.ts +2 -1
  56. package/lib/user.js +54 -1
  57. package/lib/utils/device.d.ts +7 -0
  58. package/lib/utils/device.js +39 -0
  59. package/lib/utils/errors.js +4 -0
  60. package/lib/utils/index.js +6 -6
  61. package/lib/utils/ipc.d.ts +11 -0
  62. package/lib/utils/ipc.js +26 -0
  63. package/package.json +2 -2
@@ -0,0 +1,34 @@
1
+ import { clearOfflineDpData } from "../api";
2
+ import { getOfflineDps } from "../offline-dps";
3
+ import config from "../config";
4
+ import { isUseNearChannel } from "../utils";
5
+ import { publishDpsOnly } from "../utils/publishDps";
6
+ export const syncOfflineDps = async () => {
7
+ if (config.supportOfflineDps) {
8
+ const useNear = isUseNearChannel();
9
+ if (useNear) {
10
+ const offlineDps = await getOfflineDps();
11
+ try {
12
+ if (Object.keys(offlineDps).length) {
13
+ const hasTask = Object.keys(offlineDps).some((code) => offlineDps[code].pushStatus === false);
14
+ if (hasTask) {
15
+ try {
16
+ await clearOfflineDpData(config.devInfo.devId);
17
+ }
18
+ catch (error) {
19
+ return;
20
+ }
21
+ const dpData = Object.keys(offlineDps).reduce((acc, code) => {
22
+ acc[code] = offlineDps[code].value;
23
+ return acc;
24
+ }, {});
25
+ publishDpsOnly(dpData);
26
+ }
27
+ }
28
+ }
29
+ catch (error) {
30
+ console.warn(error);
31
+ }
32
+ }
33
+ }
34
+ };
@@ -8,36 +8,32 @@ import { decrypt } from "../utils/device";
8
8
  import { publishDpsOnly } from "../utils/publishDps";
9
9
  import dpUtils from "@ray-js/tuya-dp-transform";
10
10
  import { reportSetKey as reportSetKeyMap, setKey as setKeyMap, } from "../config/dp-map/open";
11
- import { ProductCommunicationType } from "../constant";
12
11
  const syncRemoteSerectKey = async (force) => {
13
12
  const useNear = isUseNearChannel();
14
13
  if (useNear) {
15
14
  try {
16
- const isSupportBle = config.communication.includes(ProductCommunicationType.BLUETOOTH);
17
- if (config.communication.length > 1 && isSupportBle) {
18
- if (!force) {
19
- const keyValue = getDpValue(dpCodes.remoteNoPdSetkey);
20
- if (keyValue) {
21
- const keyData = dpUtils.parse(getDpValue(dpCodes.remoteNoPdSetkey), reportSetKeyMap);
22
- if (keyData.status === 0) {
23
- return;
24
- }
15
+ if (!force) {
16
+ const keyValue = getDpValue(dpCodes.remoteNoPdSetkey);
17
+ if (keyValue) {
18
+ const keyData = dpUtils.parse(getDpValue(dpCodes.remoteNoPdSetkey), reportSetKeyMap);
19
+ if (keyData.status === 0) {
20
+ return;
25
21
  }
26
22
  }
27
- const { lockUserId, userId } = await getCurrentUser();
28
- const { password, invalidTime, effectiveTime } = await checkRemoteKey(config.devInfo.devId);
29
- const pw = await decrypt(config.devInfo.devId, password);
30
- publishDpsOnly({
31
- [dpCodes.remoteNoPdSetkey]: dpUtils.format({
32
- valid: true,
33
- memberId: lockUserId !== 0 ? lockUserId : userId,
34
- startTime: effectiveTime,
35
- endTime: invalidTime,
36
- validNum: 100,
37
- key: stringToBytes(pw),
38
- }, setKeyMap),
39
- });
40
23
  }
24
+ const { lockUserId, userId } = await getCurrentUser();
25
+ const { password, invalidTime, effectiveTime } = await checkRemoteKey(config.devInfo.devId);
26
+ const pw = await decrypt(config.devInfo.devId, password);
27
+ publishDpsOnly({
28
+ [dpCodes.remoteNoPdSetkey]: dpUtils.format({
29
+ valid: true,
30
+ memberId: lockUserId !== 0 ? lockUserId : userId,
31
+ startTime: effectiveTime,
32
+ endTime: invalidTime,
33
+ validNum: 100,
34
+ key: stringToBytes(pw),
35
+ }, setKeyMap),
36
+ });
41
37
  }
42
38
  catch (e) {
43
39
  console.warn(e);
package/lib/sync/t0.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { getActiveTime } from "../api";
2
- import config from "../config";
2
+ import config, { hasCapability } from "../config";
3
3
  import dpCodes from "../config/dp-code";
4
4
  import { ProductCommunicationType } from "../constant";
5
5
  import { isUseNearChannel } from "../utils";
@@ -9,7 +9,7 @@ const isNeedSync = () => {
9
9
  const near = isUseNearChannel();
10
10
  return (near ||
11
11
  (config.devInfo.isOnline &&
12
- config.communication.includes(ProductCommunicationType.THREAD)));
12
+ hasCapability(ProductCommunicationType.THREAD)));
13
13
  };
14
14
  const syncT0 = async () => {
15
15
  if (hasSysncT0) {
@@ -0,0 +1,2 @@
1
+ export declare const syncUnlockMethod: () => Promise<void>;
2
+ export declare const autoSyncUnlockMethod: () => Promise<void>;
@@ -0,0 +1,42 @@
1
+ import { fetchSyncUnlockMethodInfo } from "../api/lock";
2
+ import config from "../config";
3
+ import dpCodes from "../config/dp-code";
4
+ import { getCurrentUser } from "../state";
5
+ import { publishDps } from "../utils/publishDps";
6
+ import dpUtils from "@ray-js/tuya-dp-transform";
7
+ import { reportSync as reportSyncMap } from "../config/dp-map/unlock-method";
8
+ import { reportSync as reportSyncBigMap } from "../config/dp-map/unlock-method-big";
9
+ let syncUnlockMethodFirst = true;
10
+ export const syncUnlockMethod = async () => {
11
+ syncUnlockMethodFirst = false;
12
+ const { allOpenDps = "" } = await getCurrentUser();
13
+ const { ins = "", distributed = false } = await fetchSyncUnlockMethodInfo({
14
+ devId: config.devInfo.devId,
15
+ dpIds: allOpenDps.split(","),
16
+ });
17
+ if (ins && distributed) {
18
+ const dpCode = config.supportBigData
19
+ ? dpCodes.synchMethodW
20
+ : dpCodes.synchMethod;
21
+ await publishDps({ [dpCode]: ins }, {
22
+ checkReport: (dpData) => {
23
+ if (typeof dpData[dpCode] !== "undefined") {
24
+ const result = dpUtils.parse(dpData[dpCode], config.supportBigData ? reportSyncBigMap : reportSyncMap);
25
+ if (result.stage === 1) {
26
+ return true;
27
+ }
28
+ }
29
+ return false;
30
+ },
31
+ });
32
+ }
33
+ };
34
+ export const autoSyncUnlockMethod = async () => {
35
+ try {
36
+ if (syncUnlockMethodFirst) {
37
+ await syncUnlockMethod();
38
+ }
39
+ }
40
+ catch (e) {
41
+ }
42
+ };
@@ -0,0 +1,2 @@
1
+ declare const syncDeleteUsers: () => Promise<void>;
2
+ export default syncDeleteUsers;
@@ -0,0 +1,76 @@
1
+ import { getDeviceStatus } from "../state";
2
+ import { ProductCommunicationType } from "../constant";
3
+ import config, { hasCapability } from "../config";
4
+ import { getUsersSyncLockData, removeUser } from "../api/user";
5
+ import dpCodes from "../config/dp-code";
6
+ import dpUtils from "@ray-js/tuya-dp-transform";
7
+ import { remove as removeBigMap, reportRemove as reportRemoveBigMap, } from "../config/dp-map/unlock-method-big";
8
+ import { remove as removeMap, reportRemove as reportRemoveMap, } from "../config/dp-map/unlock-method";
9
+ import { publishDps } from "../utils/publishDps";
10
+ const deleteUser = async (data) => {
11
+ const { admin, lockUserId, userId } = data;
12
+ const dpCode = config.supportBigData
13
+ ? dpCodes.unlockMethodDelW
14
+ : dpCodes.unlockMethodDel;
15
+ const dpData = {
16
+ type: 0,
17
+ stage: 0,
18
+ admin: !!admin,
19
+ memberId: lockUserId,
20
+ unlockId: config.supportBigData ? 0xffff : 0xff,
21
+ category: 0,
22
+ };
23
+ await publishDps({
24
+ [dpCode]: dpUtils.format(dpData, (config.supportBigData ? removeBigMap : removeMap)),
25
+ }, {
26
+ checkReport: (dps) => {
27
+ if (dps[dpCode]) {
28
+ const dpValue = dpUtils.parse(dps[dpCode], (config.supportBigData
29
+ ? reportRemoveBigMap
30
+ : reportRemoveMap));
31
+ if (dpValue.type === 0 &&
32
+ dpValue.status == 255 &&
33
+ dpValue.memberId === lockUserId) {
34
+ return true;
35
+ }
36
+ }
37
+ return false;
38
+ },
39
+ });
40
+ await removeUser(config.devInfo.devId, userId);
41
+ };
42
+ let isSyncDone = false;
43
+ const syncDeleteUsers = async () => {
44
+ const deviceStatus = getDeviceStatus();
45
+ if (deviceStatus.isWifiActive) {
46
+ return;
47
+ }
48
+ const hasThread = hasCapability(ProductCommunicationType.THREAD);
49
+ if (hasThread &&
50
+ (deviceStatus.onlineType === "local" || deviceStatus.onlineType === "cloud")) {
51
+ return;
52
+ }
53
+ if (isSyncDone)
54
+ return;
55
+ if (deviceStatus.type === "online" && deviceStatus.onlineType === "ble") {
56
+ isSyncDone = true;
57
+ let count = 0;
58
+ const handleSync = async () => {
59
+ try {
60
+ const { removedUser = [] } = await getUsersSyncLockData(config.devInfo.devId);
61
+ await Promise.all(removedUser.map((item) => deleteUser(item).catch(() => { })));
62
+ isSyncDone = false;
63
+ }
64
+ catch (e) {
65
+ if (e?.innerError?.errorCode === "DEVICE_KEY_NOT_FOUND" && count < 3) {
66
+ count++;
67
+ setTimeout(async () => {
68
+ await handleSync();
69
+ }, 2000);
70
+ }
71
+ }
72
+ };
73
+ handleSync();
74
+ }
75
+ };
76
+ export default syncDeleteUsers;
@@ -74,4 +74,97 @@ interface RenameParams {
74
74
  name: string;
75
75
  }
76
76
  export declare const renameTemp: (params: RenameParams) => Promise<void>;
77
+ interface CreateOnlineUnlimitedParams {
78
+ password: string;
79
+ name: string;
80
+ effective: EffectiveConfig;
81
+ phone?: string;
82
+ countryCode?: string;
83
+ }
84
+ export declare const saveTempOnlineUnlimited: (params: CreateOnlineUnlimitedParams) => Promise<{
85
+ type: string;
86
+ name: string;
87
+ pwdId: string;
88
+ effectiveConfig: EffectiveConfig;
89
+ }>;
90
+ interface CreateOfflineParams {
91
+ name: string;
92
+ effective: EffectiveConfig;
93
+ isOnce: boolean;
94
+ }
95
+ export type OfflineTempType = "once" | "multiple";
96
+ export interface OfflineTempResult {
97
+ type: OfflineTempType;
98
+ name: string;
99
+ password: string;
100
+ unlockBindingId: string;
101
+ pwdId: string;
102
+ effectiveConfig: EffectiveConfig;
103
+ }
104
+ export declare const createTempOffline: (params: CreateOfflineParams) => Promise<{
105
+ type: string;
106
+ name: string;
107
+ password: string;
108
+ unlockBindingId: string;
109
+ pwdId: string;
110
+ effectiveConfig: {
111
+ effectiveDate: number;
112
+ expiredDate: number;
113
+ };
114
+ }>;
115
+ export declare const removeTempOnlineUnlimited: (id: string) => Promise<void>;
116
+ export interface OnlinePasswordItem {
117
+ effective: number;
118
+ unlockBindingId: string;
119
+ effectiveTime: number;
120
+ invalidTime: number;
121
+ name: string;
122
+ phase: number;
123
+ scheduleDetails: EffectiveConfig;
124
+ status: "effective" | "synchronizing" | "expired" | "disabled" | "invalid";
125
+ }
126
+ export declare const getTempOnlineUnlimitedList: () => Promise<{
127
+ status: string;
128
+ effectiveConfig: EffectiveConfig;
129
+ effective: number;
130
+ unlockBindingId: string;
131
+ effectiveTime: number;
132
+ failReason: number;
133
+ invalidTime: number;
134
+ name: string;
135
+ phase: number;
136
+ scheduleDetails: {
137
+ allDay: boolean;
138
+ effectiveTime: number;
139
+ invalidTime: number;
140
+ timeZoneId: string;
141
+ workingDay: number;
142
+ }[];
143
+ opModeType: number;
144
+ opModeSubType: number;
145
+ sn: number;
146
+ opModeInfo?: {
147
+ hasClearPwd?: boolean;
148
+ revokedPwdName?: string;
149
+ revokedPwdEffectiveTime?: number;
150
+ revokedPwdInvalidTime?: number;
151
+ };
152
+ }[]>;
153
+ export interface OfflinePasswordItem {
154
+ email: string;
155
+ gmtExpired: number;
156
+ gmtStart: number;
157
+ hasClearPwd: boolean;
158
+ mobile: string;
159
+ pwd: string;
160
+ pwdId: string;
161
+ pwdName: string;
162
+ pwdTypeCode: "once" | "multiple" | "clear_one" | "clear_all";
163
+ revokedPwdName: string;
164
+ status: number;
165
+ timeZoneId: string;
166
+ }
167
+ export type OfflinePasswordType = "once" | "multiple" | "clear_one" | "clear_all";
168
+ export declare const getTempOfflineEffectiveList: (pwdTypeCode: OfflinePasswordType) => Promise<import("./api/temp").EffectivePasswrodItem[]>;
169
+ export declare const getTempOfflineInvalidList: (pwdTypeCode: OfflinePasswordType) => Promise<import("./api/temp").EffectivePasswrodItem[]>;
77
170
  export {};
package/lib/temporary.js CHANGED
@@ -1,4 +1,4 @@
1
- import { clearInvalidTempList, createOfflinePassword, createTemporaryPassword, deleteTempPassword, fetchEffectiveList, fetchInvalidList, getDynamicPassword, reNameOffline, reNameTemporary, revokeOfflinePassword, updateTemporaryPassword, validateTempPwd, } from "./api/temp";
1
+ import { clearInvalidTempList, createOfflinePassword, createTemporaryPassword, deleteTempPassword, fetchEffectiveList, fetchInvalidList, getDynamicPassword, reNameOffline, reNameTemporary, revokeOfflinePassword, updateTemporaryPassword, validateTempPwd, createOnlineUnlimited, removeTempOnlineUnlimitedAPI, getTempOnlineUnlimitedListAPI, getTempOfflineListAPI, createOfflineOnceAPI, } from "./api/temp";
2
2
  import config from "./config";
3
3
  import { formatWeek, isUseNearChannel, parallelOnly, parseOfflinePassword, parseWeek, validateEffectiveConfig, } from "./utils";
4
4
  import { LoopTypes } from "./utils/constant";
@@ -511,3 +511,173 @@ export const renameTemp = async (params) => {
511
511
  handleError(e);
512
512
  }
513
513
  };
514
+ export const saveTempOnlineUnlimited = async (params) => {
515
+ const { password, name, effective, phone, countryCode } = params;
516
+ if (!PASSWORD_REGEX.test(password)) {
517
+ throw getError(1030);
518
+ }
519
+ if (name && name.length > 20) {
520
+ throw getError(1031);
521
+ }
522
+ validateEffectiveConfig(effective);
523
+ const { effectiveTime = 0, expiredTime = 1439 } = effective;
524
+ const aesPwd = await encrypt(config.devInfo.devId, password);
525
+ const loopType = effective?.repeat
526
+ ?
527
+ LoopTypes[effective?.repeat?.toUpperCase()]
528
+ : LoopTypes.NONE;
529
+ const schedule = [
530
+ {
531
+ allDay: loopType === LoopTypes.NONE,
532
+ effectiveTime,
533
+ invalidTime: expiredTime,
534
+ workingDay: formatWeek(effective?.weeks ?? [0]),
535
+ },
536
+ ];
537
+ try {
538
+ const res = await createOnlineUnlimited({
539
+ devId: config.devInfo.devId,
540
+ effectiveTime: effective.effectiveDate,
541
+ invalidTime: effective.expiredDate,
542
+ name: name,
543
+ password: aesPwd,
544
+ schedule,
545
+ availTime: 0,
546
+ phone,
547
+ countryCode,
548
+ });
549
+ return {
550
+ type: "custom",
551
+ name: res.name,
552
+ pwdId: res.pwdId,
553
+ effectiveConfig: effective,
554
+ };
555
+ }
556
+ catch (error) {
557
+ throw handleError(error);
558
+ }
559
+ };
560
+ export const createTempOffline = async (params) => {
561
+ const { name, effective, isOnce } = params;
562
+ if (isOnce) {
563
+ const res = await createOfflineOnceAPI({
564
+ devId: config.devInfo.devId,
565
+ pwdType: "1",
566
+ gmtStart: "0",
567
+ gmtExpired: "0",
568
+ });
569
+ return {
570
+ type: "once",
571
+ name: res.pwdName,
572
+ password: parseOfflinePassword(res.pwd),
573
+ unlockBindingId: res.unlockBindingId,
574
+ pwdId: res.pwdId,
575
+ effectiveConfig: {
576
+ effectiveDate: Number(res.gmtStart),
577
+ expiredDate: Number(res.gmtExpired),
578
+ },
579
+ };
580
+ }
581
+ else {
582
+ if (name && name.length > 20) {
583
+ throw getError(1031);
584
+ }
585
+ if (effective.effectiveDate >= effective.expiredDate) {
586
+ throw getError(1010);
587
+ }
588
+ const res = await createOfflineOnceAPI({
589
+ devId: config.devInfo.devId,
590
+ pwdType: "0",
591
+ gmtStart: effective.effectiveDate.toString(),
592
+ gmtExpired: effective.expiredDate.toString(),
593
+ });
594
+ return {
595
+ type: "multiple",
596
+ name: res.pwdName,
597
+ password: parseOfflinePassword(res.pwd),
598
+ unlockBindingId: res.unlockBindingId,
599
+ pwdId: res.pwdId,
600
+ effectiveConfig: {
601
+ effectiveDate: Number(res.gmtStart),
602
+ expiredDate: Number(res.gmtExpired),
603
+ },
604
+ };
605
+ }
606
+ };
607
+ export const removeTempOnlineUnlimited = async (id) => {
608
+ try {
609
+ await removeTempOnlineUnlimitedAPI({
610
+ devId: config.devInfo.devId,
611
+ id,
612
+ });
613
+ }
614
+ catch (error) {
615
+ throw handleError(error);
616
+ }
617
+ };
618
+ const onLinePasswordStatusMap = {
619
+ 1: "effective",
620
+ 2: "synchronizing",
621
+ 3: "expired",
622
+ 4: "disabled",
623
+ 5: "invalid",
624
+ };
625
+ export const getTempOnlineUnlimitedList = async () => {
626
+ try {
627
+ const pswList = await getTempOnlineUnlimitedListAPI(config.devInfo.devId);
628
+ const newPswList = pswList?.map((item) => {
629
+ const status = onLinePasswordStatusMap[item.effective];
630
+ const effectiveConfig = {
631
+ effectiveDate: item.effectiveTime,
632
+ expiredDate: item.invalidTime,
633
+ };
634
+ if (item.scheduleDetails?.length) {
635
+ const scheduleDetail = item.scheduleDetails[0];
636
+ effectiveConfig.repeat =
637
+ scheduleDetail.allDay === false ? "week" : "none";
638
+ if (effectiveConfig.repeat === "week") {
639
+ effectiveConfig.weeks = parseWeek(scheduleDetail.workingDay);
640
+ effectiveConfig.effectiveTime = scheduleDetail.effectiveTime;
641
+ effectiveConfig.expiredTime = scheduleDetail.invalidTime;
642
+ }
643
+ }
644
+ return { ...item, status, effectiveConfig };
645
+ });
646
+ return newPswList;
647
+ }
648
+ catch (error) {
649
+ throw handleError(error);
650
+ }
651
+ };
652
+ const offlinePasswordTypeMap = {
653
+ once: "1",
654
+ multiple: "0",
655
+ clear_one: "8",
656
+ clear_all: "9",
657
+ };
658
+ export const getTempOfflineEffectiveList = async (pwdTypeCode) => {
659
+ try {
660
+ const offLineValidPswList = await getTempOfflineListAPI({
661
+ devId: config.devInfo.devId,
662
+ pwdType: offlinePasswordTypeMap[pwdTypeCode],
663
+ status: "1",
664
+ });
665
+ return offLineValidPswList;
666
+ }
667
+ catch (error) {
668
+ throw handleError(error);
669
+ }
670
+ };
671
+ export const getTempOfflineInvalidList = async (pwdTypeCode) => {
672
+ try {
673
+ const offLineFailurePswList = await getTempOfflineListAPI({
674
+ devId: config.devInfo.devId,
675
+ pwdType: offlinePasswordTypeMap[pwdTypeCode],
676
+ status: "0",
677
+ });
678
+ return offLineFailurePswList;
679
+ }
680
+ catch (error) {
681
+ throw handleError(error);
682
+ }
683
+ };
@@ -13,6 +13,7 @@ import { encrypt } from "./utils/device";
13
13
  import emitter from "./utils/event";
14
14
  import { DPCHANGE, UNLOCK_METHOD_EVENT } from "./utils/constant";
15
15
  import { sendPhoneVerifyCode } from "./api";
16
+ import { getUserInfo } from "./user";
16
17
  const getAddUnlockError = (status) => {
17
18
  if (status >= 0 && status <= 10) {
18
19
  return getError(1015 + status);
@@ -261,19 +262,48 @@ const handleAddReport = async (dps) => {
261
262
  clearMonitoringAddReport();
262
263
  try {
263
264
  await sleep(300);
264
- const res = await createUnlockMethod({
265
- devId: config.devInfo.devId,
266
- userId: addUnlockMethodData.userId,
267
- unlockId: `${addUnlockMethodData.unlockDpId}-${result.unlockId}`,
268
- unlockName: "",
269
- unlockAttr: 0,
270
- });
271
- eventData = {
272
- stage: "success",
273
- type,
274
- id: res.opModeId,
275
- name: res.unlockName,
276
- };
265
+ let isAddEnabled = true;
266
+ if (!config.supportMultipleFace && type === "face") {
267
+ const user = await getUserInfo({
268
+ userId: addUnlockMethodData.userId,
269
+ });
270
+ const faceData = user.unlockDetails.find((item) => item.type === "face" && item.unlockList.length > 0);
271
+ if (faceData) {
272
+ const originUnlockId = faceData.unlockList[0].unlockId;
273
+ if (originUnlockId !== result.unlockId) {
274
+ eventData = {
275
+ stage: "fail",
276
+ type,
277
+ lockUserId: result.memberId,
278
+ error: getError(1061),
279
+ };
280
+ }
281
+ else {
282
+ eventData = {
283
+ stage: "success",
284
+ type,
285
+ id: faceData.unlockList[0].id,
286
+ name: faceData.unlockList[0].unlockName,
287
+ };
288
+ }
289
+ isAddEnabled = false;
290
+ }
291
+ }
292
+ if (isAddEnabled) {
293
+ const res = await createUnlockMethod({
294
+ devId: config.devInfo.devId,
295
+ userId: addUnlockMethodData.userId,
296
+ unlockId: `${addUnlockMethodData.unlockDpId}-${result.unlockId}`,
297
+ unlockName: "",
298
+ unlockAttr: 0,
299
+ });
300
+ eventData = {
301
+ stage: "success",
302
+ type,
303
+ id: res.opModeId,
304
+ name: res.unlockName,
305
+ };
306
+ }
277
307
  }
278
308
  catch {
279
309
  eventData = {
package/lib/user.d.ts CHANGED
@@ -10,7 +10,6 @@ export declare const getUsers: (params?: getUsersParams) => Promise<{
10
10
  }>;
11
11
  interface getUserInfoParams {
12
12
  userId: string;
13
- nickName: string;
14
13
  }
15
14
  export declare const getUserInfo: (params: getUserInfoParams) => Promise<UserInfo>;
16
15
  interface updateUserLimitTimeParams {
@@ -21,6 +20,8 @@ interface updateUserLimitTimeParams {
21
20
  offlineUnlock?: boolean;
22
21
  }
23
22
  export declare const updateUserLimitTime: (params: updateUserLimitTimeParams) => Promise<boolean>;
23
+ export declare const openAddFamilyUser: () => Promise<unknown>;
24
+ export declare const openFamilyUserDetail: (userId: string) => Promise<undefined>;
24
25
  interface AddUserParams {
25
26
  name: string;
26
27
  }
package/lib/user.js CHANGED
@@ -9,6 +9,7 @@ import { getError } from "./utils/errors";
9
9
  import { updateUserTimeSchedule, addNormalUser, removeNormalUser, } from "./api/user";
10
10
  import { validConfigDpMap } from "./config/dp-map/common";
11
11
  import { formatTimestampToMilliseconds, formatWeek, isAdmin, parseWeek, unlockMethodConfigs, validateEffectiveConfig, } from "./utils";
12
+ import { getCurrentHomeInfo, isSupportShortLink } from "./utils/device";
12
13
  import { LoopTypes } from "./utils/constant";
13
14
  import { getCurrentUser } from "./state";
14
15
  const concactUserList = (list, result) => {
@@ -94,8 +95,12 @@ export const getUsers = async (params) => {
94
95
  };
95
96
  };
96
97
  export const getUserInfo = async (params) => {
98
+ const user = await getUserDetail({
99
+ devId: config.devInfo.devId,
100
+ userId: params.userId,
101
+ });
97
102
  const data = await getUsers({
98
- keyword: params.nickName,
103
+ keyword: user.nickName,
99
104
  });
100
105
  const res = data.list.find((item) => item.userId === params.userId);
101
106
  if (res) {
@@ -199,6 +204,54 @@ export const updateUserLimitTime = async (params) => {
199
204
  }
200
205
  return true;
201
206
  };
207
+ export const openAddFamilyUser = async () => {
208
+ const homeInfo = await getCurrentHomeInfo();
209
+ let link = await isSupportShortLink("tysh_family_add_member_rn");
210
+ if (!link) {
211
+ link = await isSupportShortLink("thingsh_family_add_member_rn");
212
+ }
213
+ if (link) {
214
+ const url = `tuyaSmart://${link}?homeId=${homeInfo.homeId}`;
215
+ return new Promise((resolve, reject) => {
216
+ ty.router({
217
+ url: url,
218
+ success: (d) => {
219
+ resolve(true);
220
+ },
221
+ fail: (e) => {
222
+ reject(e);
223
+ },
224
+ });
225
+ });
226
+ }
227
+ return Promise.reject(getError(1013));
228
+ };
229
+ const userTypeMap = {
230
+ "10": 1,
231
+ "20": 0,
232
+ "40": -1,
233
+ "50": 2,
234
+ };
235
+ export const openFamilyUserDetail = async (userId) => {
236
+ const { homeId } = await getCurrentHomeInfo();
237
+ const { userType: currentUserType } = await getCurrentUser();
238
+ const role = userTypeMap[currentUserType];
239
+ let link = await isSupportShortLink("member_info");
240
+ if (link) {
241
+ const url = `tuyaSmart://member_info?homeId=${homeId}&memberId=${userId}&role=${role}`;
242
+ ty.router({
243
+ url: url,
244
+ success: (d) => {
245
+ console.log("openFamilyUserDetail success");
246
+ },
247
+ fail: (e) => {
248
+ console.log("openFamilyUserDetail fail", e);
249
+ },
250
+ });
251
+ return;
252
+ }
253
+ return Promise.reject(getError(1013));
254
+ };
202
255
  export const addUser = async (params) => {
203
256
  if (!config.supportBigData) {
204
257
  throw getError(1060);