iobroker.eusec 2.0.3 → 3.0.2
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/LICENSE +1 -1
- package/README.md +24 -9
- package/build/lib/eufyApiCompat.js +63 -0
- package/build/lib/eufyApiCompat.js.map +7 -0
- package/build/lib/go2rtc.js +36 -0
- package/build/lib/go2rtc.js.map +7 -0
- package/build/lib/interfaces.js.map +1 -1
- package/build/lib/log.js.map +2 -2
- package/build/lib/types.js.map +1 -1
- package/build/lib/utils.js +53 -35
- package/build/lib/utils.js.map +2 -2
- package/build/lib/video.js +55 -38
- package/build/lib/video.js.map +2 -2
- package/build/main.js +586 -238
- package/build/main.js.map +2 -2
- package/cleanupCveFix.js +1 -1
- package/io-package.json +16 -3
- package/package.json +24 -35
package/LICENSE
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c) 2025 iobroker-community-adapters <iobroker-community-adapters@gmx.de>
|
|
3
|
+
Copyright (c) 2025-2026 iobroker-community-adapters <iobroker-community-adapters@gmx.de>
|
|
4
4
|
Copyright (c) 2020-2024 bropat <patrick.broetto@gmail.com>
|
|
5
5
|
|
|
6
6
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
package/README.md
CHANGED
|
@@ -13,21 +13,21 @@
|
|
|
13
13
|
|
|
14
14
|
[](https://nodei.co/npm/iobroker.eusec/)
|
|
15
15
|
|
|
16
|
-
This is an [ioBroker](https://www.iobroker.net) adapter that uses the [eufy-security-client](https://github.com/bropat/eufy-security-client) library to
|
|
16
|
+
This is an [ioBroker](https://www.iobroker.net) adapter that uses the [eufy-security-client](https://github.com/bropat/eufy-security-client) library to communicate with Eufy devices.
|
|
17
17
|
|
|
18
18
|
**This project is not affiliated with Anker and Eufy (Eufy Security). It is a personal project that is maintained in spare time.**
|
|
19
19
|
|
|
20
20
|
## Description
|
|
21
21
|
|
|
22
|
-
This adapter allows to control [Eufy security devices](https://us.eufylife.com/collections/security) by connecting to the Eufy cloud servers and local/remote stations.
|
|
22
|
+
This adapter allows you to control [Eufy security devices](https://us.eufylife.com/collections/security) by connecting to the Eufy cloud servers and local/remote stations.
|
|
23
23
|
|
|
24
24
|
You need to provide your Cloud login credentials. The adapter connects to your cloud account and polls for all device data via HTTPS. Now a local or remote P2P connection to the Eufy stations/devices is also supported. However, a connection to the Eufy Cloud is always a prerequisite.
|
|
25
25
|
|
|
26
|
-
One Adapter instance will show all devices from one Eufy Cloud account and allows to control them.
|
|
26
|
+
One Adapter instance will show all devices from one Eufy Cloud account and allows you to control them.
|
|
27
27
|
|
|
28
28
|
## Documentation
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
Check out the documentation [here](https://iobroker-community-adapters.github.io/ioBroker.eusec/).
|
|
31
31
|
|
|
32
32
|
## Known working devices
|
|
33
33
|
|
|
@@ -37,12 +37,30 @@ Information about supported devices can be found [here](https://github.com/bropa
|
|
|
37
37
|
|
|
38
38
|
This adapter would not have been possible without the great work of Patrick Broetto (brobat) <https://github.com/bropat>, who created previous releases of this adapter.
|
|
39
39
|
|
|
40
|
+
## IMPORTANT information when upgrading to node.js 22
|
|
41
|
+
|
|
42
|
+
Adapter 2.0.3 and newer support node.js 22. Prior node.js versions require a special setup which became invalid with node.js 22. So when upgrading node.js from any version lower than 22.x.x to node.js 22, please follow these steps:
|
|
43
|
+
|
|
44
|
+
- If you have node.js < 22 and adapter < 2.0.0 installed, please update node.js first and install adapter 2.0.3 afterwards.
|
|
45
|
+
- If you have adapter >= 2.0.0 installed with any node release prior to 22, you MUST reinstall the adapter. A detailed description (in German) is available at our forum (https://forum.iobroker.net/topic/82651/test-adapter-eusec-v2-0-x)
|
|
46
|
+
|
|
40
47
|
## Changelog
|
|
41
48
|
|
|
42
49
|
<!--
|
|
43
50
|
Placeholder for the next version (at the beginning of the line):
|
|
44
51
|
### **WORK IN PROGRESS**
|
|
45
52
|
-->
|
|
53
|
+
### 3.0.2 (2026-09-02)
|
|
54
|
+
- (copilot) Adapter requires node.js >= 22 now
|
|
55
|
+
- (copilot) Adapter requires admin >= 7.7.22 now
|
|
56
|
+
- (@GermanBluefox) Refactoring
|
|
57
|
+
- (@GermanBluefox) Fixed login failing with `Get passport profile - Response code not ok` since the eufy cloud started answering successful requests with code 200 instead of 0 (see [bropat/eufy-security-client#975](https://github.com/bropat/eufy-security-client/pull/975))
|
|
58
|
+
- (typhosj) Fixed livestreaming being broken when go2rtc is configured to use an API port other than 1984, and the eufy livestream is now stopped when streaming into go2rtc fails ([#151](https://github.com/iobroker-community-adapters/ioBroker.eusec/pull/151), [#160](https://github.com/iobroker-community-adapters/ioBroker.eusec/issues/160))
|
|
59
|
+
- (typhosj) go2rtc is now supervised and restarted if it terminates unexpectedly, the livestream states are cleared when a station disconnects, and a warning is logged when a camera streams at "Auto" quality ([#152](https://github.com/iobroker-community-adapters/ioBroker.eusec/pull/152))
|
|
60
|
+
- (@GermanBluefox) The warning about the "Auto" streaming quality now also covers devices where "Auto" is not value 0 (eufyCam 3, Professional models and battery doorbells)
|
|
61
|
+
- (@GermanBluefox) Removed the obsolete CVE-2023-46809 workaround for node.js 20 from the adapter startup
|
|
62
|
+
- (@GermanBluefox) Pinned eufy-security-client to 4.1.1-1 and removed the unused packages mime and @types/ffmpeg-static
|
|
63
|
+
|
|
46
64
|
### 2.0.3 (2025-10-26)
|
|
47
65
|
- (mcm1957) Remove fix for CVE-2023-46809 for node.js 22 and newer
|
|
48
66
|
|
|
@@ -61,16 +79,13 @@ This adapter would not have been possible without the great work of Patrick Broe
|
|
|
61
79
|
|
|
62
80
|
* (bropat) Fixed issue #440
|
|
63
81
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
* (bropat) Fixed issue #436
|
|
67
|
-
* (bropat) Fixed issue #439
|
|
82
|
+
[Older changelogs can be found there](CHANGELOG_OLD.md)
|
|
68
83
|
|
|
69
84
|
## License
|
|
70
85
|
|
|
71
86
|
MIT License
|
|
72
87
|
|
|
73
|
-
Copyright (c) 2025 iobroker-community-adapters <iobroker-community-adapters@gmx.de>
|
|
88
|
+
Copyright (c) 2025-2026 iobroker-community-adapters <iobroker-community-adapters@gmx.de>
|
|
74
89
|
Copyright (c) 2020-2024 bropat <patrick.broetto@gmail.com>
|
|
75
90
|
|
|
76
91
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var eufyApiCompat_exports = {};
|
|
20
|
+
__export(eufyApiCompat_exports, {
|
|
21
|
+
applyEufyApiCompatibility: () => applyEufyApiCompatibility,
|
|
22
|
+
normalizeSuccessCode: () => normalizeSuccessCode
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(eufyApiCompat_exports);
|
|
25
|
+
var import_eufy_security_client = require("eufy-security-client");
|
|
26
|
+
const LEGACY_SUCCESS_CODE = import_eufy_security_client.ResponseErrorCode.CODE_OK;
|
|
27
|
+
const HTTP_SUCCESS_CODE = 200;
|
|
28
|
+
const normalizeSuccessCode = (data) => {
|
|
29
|
+
if (data === null || typeof data !== "object") {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
const result = data;
|
|
33
|
+
if (result.code !== HTTP_SUCCESS_CODE) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
result.code = LEGACY_SUCCESS_CODE;
|
|
37
|
+
return true;
|
|
38
|
+
};
|
|
39
|
+
let patched = false;
|
|
40
|
+
const applyEufyApiCompatibility = (log) => {
|
|
41
|
+
if (patched) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
patched = true;
|
|
45
|
+
const original = import_eufy_security_client.HTTPApi.prototype.request;
|
|
46
|
+
let reported = false;
|
|
47
|
+
import_eufy_security_client.HTTPApi.prototype.request = async function(request, withoutUrlPrefix) {
|
|
48
|
+
const response = await original.call(this, request, withoutUrlPrefix);
|
|
49
|
+
if (normalizeSuccessCode(response == null ? void 0 : response.data) && !reported) {
|
|
50
|
+
reported = true;
|
|
51
|
+
log(
|
|
52
|
+
"The Eufy API answers with the HTTP style code 200 where the legacy code 0 is expected. The adapter normalizes it - see bropat/eufy-security-client#975."
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
return response;
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
59
|
+
0 && (module.exports = {
|
|
60
|
+
applyEufyApiCompatibility,
|
|
61
|
+
normalizeSuccessCode
|
|
62
|
+
});
|
|
63
|
+
//# sourceMappingURL=eufyApiCompat.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/lib/eufyApiCompat.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Compatibility shim for the Eufy Mega/v6 backend.\n *\n * Eufy started answering with the HTTP style code 200 in the JSON body of endpoints that used to\n * return the legacy application code 0. eufy-security-client accepts only 0\n * (`ResponseErrorCode.CODE_OK`) and therefore reports perfectly valid answers as failures:\n *\n * [http] [HTTPApi.getPassportProfile] Get passport profile - Response code not ok\n * [{\"code\":200,\"msg\":\"\",\"data\":{...}}]\n *\n * The login never completes after that, and the house, station and device lists stay empty.\n *\n * Upstream carries the fix in bropat/eufy-security-client#975, but development of that library has\n * ended (bropat/eufy-security-client#965), so it will most likely never be released. 21 of the 22\n * affected comparisons read `response.data` of the public `HTTPApi.request()`, so normalizing the\n * code in that single funnel repairs all of them at once.\n *\n * The 22nd is the static `HTTPApi.getApiBaseFromCloud()`, which calls got directly and talks to a\n * different host (extend.eufylife.com). It is deliberately left untouched: a failure there aborts\n * the login with an ApiBaseLoadError long before a profile is ever requested, which is not the\n * behaviour reported in the field.\n *\n * Remove this module once the adapter depends on a library version that accepts both codes.\n */\n\nimport { HTTPApi, ResponseErrorCode } from 'eufy-security-client';\nimport type { ApiResponse, HTTPApiRequest } from 'eufy-security-client';\n\n/** Legacy application success code of the Eufy API. */\nconst LEGACY_SUCCESS_CODE = ResponseErrorCode.CODE_OK;\n\n/** HTTP style success code the Mega/v6 backend returns instead. It is not a member of ResponseErrorCode. */\nconst HTTP_SUCCESS_CODE = 200;\n\n/**\n * Rewrites the HTTP style success code of a response body to the legacy one, in place. Only the\n * code is touched - the encrypted payload in `data` is passed through untouched.\n *\n * @param data The parsed body of an Eufy API response\n * @returns true if the code was rewritten, false if the body was left as it was\n */\nexport const normalizeSuccessCode = (data: unknown): boolean => {\n if (data === null || typeof data !== 'object') {\n return false;\n }\n const result = data as { code?: unknown };\n if (result.code !== HTTP_SUCCESS_CODE) {\n return false;\n }\n result.code = LEGACY_SUCCESS_CODE;\n return true;\n};\n\nlet patched = false;\n\n/**\n * Wraps HTTPApi.request() so every response body carries a success code the library understands.\n * Must run before EufySecurity.initialize(); applying it more than once is a no-op.\n *\n * @param log Called once, on the first response that actually needed the rewrite\n */\nexport const applyEufyApiCompatibility = (log: (message: string) => void): void => {\n if (patched) {\n return;\n }\n patched = true;\n\n const original = HTTPApi.prototype.request;\n let reported = false;\n\n HTTPApi.prototype.request = async function (\n request: HTTPApiRequest,\n withoutUrlPrefix?: boolean,\n ): Promise<ApiResponse> {\n const response = await original.call(this, request, withoutUrlPrefix);\n if (normalizeSuccessCode(response?.data) && !reported) {\n reported = true;\n log(\n 'The Eufy API answers with the HTTP style code 200 where the legacy code 0 is expected. The adapter normalizes it - see bropat/eufy-security-client#975.',\n );\n }\n return response;\n };\n};\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAyBA,kCAA2C;AAI3C,MAAM,sBAAsB,8CAAkB;AAG9C,MAAM,oBAAoB;AASnB,MAAM,uBAAuB,CAAC,SAA2B;AAC5D,MAAI,SAAS,QAAQ,OAAO,SAAS,UAAU;AAC3C,WAAO;AAAA,EACX;AACA,QAAM,SAAS;AACf,MAAI,OAAO,SAAS,mBAAmB;AACnC,WAAO;AAAA,EACX;AACA,SAAO,OAAO;AACd,SAAO;AACX;AAEA,IAAI,UAAU;AAQP,MAAM,4BAA4B,CAAC,QAAyC;AAC/E,MAAI,SAAS;AACT;AAAA,EACJ;AACA,YAAU;AAEV,QAAM,WAAW,oCAAQ,UAAU;AACnC,MAAI,WAAW;AAEf,sCAAQ,UAAU,UAAU,eACxB,SACA,kBACoB;AACpB,UAAM,WAAW,MAAM,SAAS,KAAK,MAAM,SAAS,gBAAgB;AACpE,QAAI,qBAAqB,qCAAU,IAAI,KAAK,CAAC,UAAU;AACnD,iBAAW;AACX;AAAA,QACI;AAAA,MACJ;AAAA,IACJ;AACA,WAAO;AAAA,EACX;AACJ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var go2rtc_exports = {};
|
|
20
|
+
__export(go2rtc_exports, {
|
|
21
|
+
isRegularStreamEnd: () => isRegularStreamEnd,
|
|
22
|
+
streamToGo2rtcFailed: () => streamToGo2rtcFailed
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(go2rtc_exports);
|
|
25
|
+
const isRegularStreamEnd = (error) => {
|
|
26
|
+
var _a;
|
|
27
|
+
const body = (_a = error == null ? void 0 : error.response) == null ? void 0 : _a.body;
|
|
28
|
+
return typeof body === "string" && body.startsWith("EOF");
|
|
29
|
+
};
|
|
30
|
+
const streamToGo2rtcFailed = (results) => results.some((result) => result.status === "rejected" && !isRegularStreamEnd(result.reason));
|
|
31
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
32
|
+
0 && (module.exports = {
|
|
33
|
+
isRegularStreamEnd,
|
|
34
|
+
streamToGo2rtcFailed
|
|
35
|
+
});
|
|
36
|
+
//# sourceMappingURL=go2rtc.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/lib/go2rtc.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Helpers around the go2rtc stream pipelines. Deliberately free of imports so they stay testable:\n * lib/utils.ts pulls in \\@iobroker/adapter-core and main.ts, which needs a running js-controller.\n */\n\n/**\n * go2rtc answers with \"EOF\" when a stream is torn down in the regular way (livestream stopped,\n * maximum duration reached). That is not a failure and must not trigger any error handling.\n *\n * @param error The rejection reason of a stream pipeline\n * @returns true if the stream simply ended instead of breaking\n */\nexport const isRegularStreamEnd = (error: unknown): boolean => {\n const body = (error as { response?: { body?: unknown } })?.response?.body;\n return typeof body === 'string' && body.startsWith('EOF');\n};\n\n/**\n * Tells whether at least one of the stream pipelines ended in an actual failure, so callers can\n * tear the livestream down instead of leaving the camera streaming into nothing.\n *\n * @param results The settled results returned by streamToGo2rtc()\n * @returns true if at least one pipeline broke\n */\nexport const streamToGo2rtcFailed = (results: Array<PromiseSettledResult<void>>): boolean =>\n results.some(result => result.status === 'rejected' && !isRegularStreamEnd(result.reason));\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYO,MAAM,qBAAqB,CAAC,UAA4B;AAZ/D;AAaI,QAAM,QAAQ,oCAA6C,aAA7C,mBAAuD;AACrE,SAAO,OAAO,SAAS,YAAY,KAAK,WAAW,KAAK;AAC5D;AASO,MAAM,uBAAuB,CAAC,YACjC,QAAQ,KAAK,YAAU,OAAO,WAAW,cAAc,CAAC,mBAAmB,OAAO,MAAM,CAAC;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/interfaces.ts"],
|
|
4
|
-
"sourcesContent": ["
|
|
4
|
+
"sourcesContent": ["/*export interface AdapterConfig {\n username: string;\n password: string;\n pollingInterval: number;\n maxLivestreamDuration: number;\n eventDuration: number;\n verificationMethod: number;\n p2pConnectionType: string;\n acceptInvitations: boolean;\n alarmSoundDuration: number;\n go2rtc_api_port: number;\n go2rtc_rtsp_port: number;\n go2rtc_srtp_port: number;\n go2rtc_webrtc_port: number;\n go2rtc_rtsp_username: string;\n go2rtc_rtsp_password: string;\n hostname: string;\n https: boolean;\n}*/\n\nexport interface PersistentData {\n version: string;\n}\n\nexport interface IRoleMapping {\n [index: string]: string;\n}\n"],
|
|
5
5
|
"mappings": ";;;;;;;;;;;;;;AAAA;AAAA;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/build/lib/log.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/log.ts"],
|
|
4
|
-
"sourcesContent": ["import { Logger } from
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAEO,MAAM,eAAiC;AAAA,
|
|
4
|
+
"sourcesContent": ["import type { Logger } from 'ts-log';\n\nexport class ioBrokerLogger implements Logger {\n private readonly log: ioBroker.Logger;\n\n public constructor(log: ioBroker.Logger) {\n this.log = log;\n }\n\n private _getStack(): any {\n const _prepareStackTrace = Error.prepareStackTrace;\n Error.prepareStackTrace = (_, stack) => stack;\n const stack = new Error().stack?.slice(3);\n Error.prepareStackTrace = _prepareStackTrace;\n return stack;\n }\n\n private _getMessage(message?: string, hideTag = false, optionalParams?: any[]): string {\n const msg = message ? message : '';\n const stack = this._getStack();\n const typeName = stack[0].getTypeName() !== null ? stack[0].getTypeName() : '';\n const functionName = stack[0].getFunctionName() !== null ? `${stack[0].getFunctionName()}` : '';\n let tag = '';\n if (typeName !== '' && !hideTag) {\n tag = `[${typeName}`;\n if (functionName !== '') {\n tag = `${tag}.${functionName}] `;\n } else {\n tag = `${tag}] `;\n }\n }\n\n if (optionalParams && optionalParams.length > 0) {\n return `${tag}${msg} ${JSON.stringify(optionalParams)}`;\n }\n return `${tag}${msg}`;\n }\n\n public trace(message?: string, ...optionalParams: any[]): void {\n this.log.silly(this._getMessage(message, false, optionalParams));\n }\n\n public debug(message?: string, ...optionalParams: any[]): void {\n this.log.debug(this._getMessage(message, false, optionalParams));\n }\n\n public info(message?: string, ...optionalParams: any[]): void {\n this.log.info(this._getMessage(message, true, optionalParams));\n }\n\n public warn(message?: string, ...optionalParams: any[]): void {\n this.log.warn(this._getMessage(message, true, optionalParams));\n }\n\n public error(message?: string, ...optionalParams: any[]): void {\n this.log.error(this._getMessage(message, true, optionalParams));\n }\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAEO,MAAM,eAAiC;AAAA,EACzB;AAAA,EAEV,YAAY,KAAsB;AACrC,SAAK,MAAM;AAAA,EACf;AAAA,EAEQ,YAAiB;AAT7B;AAUQ,UAAM,qBAAqB,MAAM;AACjC,UAAM,oBAAoB,CAAC,GAAGA,WAAUA;AACxC,UAAM,SAAQ,SAAI,MAAM,EAAE,UAAZ,mBAAmB,MAAM;AACvC,UAAM,oBAAoB;AAC1B,WAAO;AAAA,EACX;AAAA,EAEQ,YAAY,SAAkB,UAAU,OAAO,gBAAgC;AACnF,UAAM,MAAM,UAAU,UAAU;AAChC,UAAM,QAAQ,KAAK,UAAU;AAC7B,UAAM,WAAW,MAAM,CAAC,EAAE,YAAY,MAAM,OAAO,MAAM,CAAC,EAAE,YAAY,IAAI;AAC5E,UAAM,eAAe,MAAM,CAAC,EAAE,gBAAgB,MAAM,OAAO,GAAG,MAAM,CAAC,EAAE,gBAAgB,CAAC,KAAK;AAC7F,QAAI,MAAM;AACV,QAAI,aAAa,MAAM,CAAC,SAAS;AAC7B,YAAM,IAAI,QAAQ;AAClB,UAAI,iBAAiB,IAAI;AACrB,cAAM,GAAG,GAAG,IAAI,YAAY;AAAA,MAChC,OAAO;AACH,cAAM,GAAG,GAAG;AAAA,MAChB;AAAA,IACJ;AAEA,QAAI,kBAAkB,eAAe,SAAS,GAAG;AAC7C,aAAO,GAAG,GAAG,GAAG,GAAG,IAAI,KAAK,UAAU,cAAc,CAAC;AAAA,IACzD;AACA,WAAO,GAAG,GAAG,GAAG,GAAG;AAAA,EACvB;AAAA,EAEO,MAAM,YAAqB,gBAA6B;AAC3D,SAAK,IAAI,MAAM,KAAK,YAAY,SAAS,OAAO,cAAc,CAAC;AAAA,EACnE;AAAA,EAEO,MAAM,YAAqB,gBAA6B;AAC3D,SAAK,IAAI,MAAM,KAAK,YAAY,SAAS,OAAO,cAAc,CAAC;AAAA,EACnE;AAAA,EAEO,KAAK,YAAqB,gBAA6B;AAC1D,SAAK,IAAI,KAAK,KAAK,YAAY,SAAS,MAAM,cAAc,CAAC;AAAA,EACjE;AAAA,EAEO,KAAK,YAAqB,gBAA6B;AAC1D,SAAK,IAAI,KAAK,KAAK,YAAY,SAAS,MAAM,cAAc,CAAC;AAAA,EACjE;AAAA,EAEO,MAAM,YAAqB,gBAA6B;AAC3D,SAAK,IAAI,MAAM,KAAK,YAAY,SAAS,MAAM,cAAc,CAAC;AAAA,EAClE;AACJ;",
|
|
6
6
|
"names": ["stack"]
|
|
7
7
|
}
|
package/build/lib/types.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/types.ts"],
|
|
4
|
-
"sourcesContent": ["import { PropertyName } from
|
|
4
|
+
"sourcesContent": ["import { PropertyName } from 'eufy-security-client';\n\nimport type { IRoleMapping } from './interfaces';\n\nexport const DataLocation = {\n LAST_EVENT: 'last_event',\n};\n\nexport const STREAM_FILE_NAME_EXT = '.m3u8';\nexport const IMAGE_FILE_JPEG_EXT = '.jpg';\n\nexport const RoleMapping: IRoleMapping = {\n [PropertyName.Name]: 'info.name',\n [PropertyName.StationMacAddress]: 'info.mac',\n [PropertyName.StationLANIpAddress]: 'info.ip',\n [PropertyName.DeviceState]: 'info.status',\n [PropertyName.DeviceBattery]: 'value.battery',\n [PropertyName.DeviceBatteryTemp]: 'value.temperature',\n [PropertyName.DeviceMotionDetected]: 'sensor.motion',\n [PropertyName.DevicePersonDetected]: 'sensor.motion',\n [PropertyName.DeviceRinging]: 'sensor',\n [PropertyName.DeviceCryingDetected]: 'sensor.noise',\n [PropertyName.DeviceSoundDetected]: 'sensor.noise',\n [PropertyName.DevicePetDetected]: 'sensor',\n [PropertyName.DeviceSensorOpen]: 'sensor',\n [PropertyName.DeviceBatteryLow]: 'indicator.lowbat',\n [PropertyName.DeviceLockStatus]: 'info.status',\n [PropertyName.DeviceDogLickDetected]: 'sensor',\n [PropertyName.DeviceDogPoopDetected]: 'sensor',\n [PropertyName.DeviceVehicleDetected]: 'sensor',\n [PropertyName.DeviceRadarMotionDetected]: 'sensor.motion',\n [PropertyName.DeviceStrangerPersonDetected]: 'sensor.motion',\n [PropertyName.DeviceIdentityPersonDetected]: 'sensor.motion',\n [PropertyName.DeviceChargingStatus]: 'info.status',\n};\n\nexport const DeviceStateID = {\n /*LAST_EVENT_PIC_URL: \"last_event_pic_url\",\n LAST_EVENT_PIC_HTML: \"last_event_pic_html\",\n LAST_EVENT_VIDEO_URL: \"last_event_video_url\",*/\n LIVESTREAM: 'livestream',\n START_STREAM: 'start_stream',\n STOP_STREAM: 'stop_stream',\n RTSP_STREAM_URL: 'rtsp_stream_url',\n TRIGGER_ALARM_SOUND: 'trigger_alarm_sound',\n RESET_ALARM_SOUND: 'reset_alarm_sound',\n PICTURE_URL: 'picture_url',\n PICTURE_HTML: 'picture_html',\n LIVESTREAM_RTSP: 'livestream_rtsp',\n PAN_LEFT: 'pan_left',\n PAN_RIGHT: 'pan_right',\n TILT_UP: 'tilt_up',\n TILT_DOWN: 'titl_down',\n ROTATE_360: 'rotate_360',\n SET_DEFAULT_ANGLE: 'set_default_angle',\n SET_PRIVACY_ANGLE: 'set_privacy_angle',\n CALIBRATE: 'calibrate',\n UNLOCK: 'unlock',\n OPEN_BOX: 'open_box',\n};\n\nexport const StationStateID = {\n REBOOT: 'reboot',\n CONNECTION: 'connection',\n TRIGGER_ALARM_SOUND: 'trigger_alarm_sound',\n RESET_ALARM_SOUND: 'reset_alarm_sound',\n};\n"],
|
|
5
5
|
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kCAA6B;AAItB,MAAM,eAAe;AAAA,EACxB,YAAY;AAChB;AAEO,MAAM,uBAAuB;AAC7B,MAAM,sBAAsB;AAE5B,MAAM,cAA4B;AAAA,EACrC,CAAC,yCAAa,IAAI,GAAG;AAAA,EACrB,CAAC,yCAAa,iBAAiB,GAAG;AAAA,EAClC,CAAC,yCAAa,mBAAmB,GAAG;AAAA,EACpC,CAAC,yCAAa,WAAW,GAAG;AAAA,EAC5B,CAAC,yCAAa,aAAa,GAAG;AAAA,EAC9B,CAAC,yCAAa,iBAAiB,GAAG;AAAA,EAClC,CAAC,yCAAa,oBAAoB,GAAG;AAAA,EACrC,CAAC,yCAAa,oBAAoB,GAAG;AAAA,EACrC,CAAC,yCAAa,aAAa,GAAG;AAAA,EAC9B,CAAC,yCAAa,oBAAoB,GAAG;AAAA,EACrC,CAAC,yCAAa,mBAAmB,GAAG;AAAA,EACpC,CAAC,yCAAa,iBAAiB,GAAG;AAAA,EAClC,CAAC,yCAAa,gBAAgB,GAAG;AAAA,EACjC,CAAC,yCAAa,gBAAgB,GAAG;AAAA,EACjC,CAAC,yCAAa,gBAAgB,GAAG;AAAA,EACjC,CAAC,yCAAa,qBAAqB,GAAG;AAAA,EACtC,CAAC,yCAAa,qBAAqB,GAAG;AAAA,EACtC,CAAC,yCAAa,qBAAqB,GAAG;AAAA,EACtC,CAAC,yCAAa,yBAAyB,GAAG;AAAA,EAC1C,CAAC,yCAAa,4BAA4B,GAAG;AAAA,EAC7C,CAAC,yCAAa,4BAA4B,GAAG;AAAA,EAC7C,CAAC,yCAAa,oBAAoB,GAAG;AACzC;AAEO,MAAM,gBAAgB;AAAA;AAAA;AAAA;AAAA,EAIzB,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,aAAa;AAAA,EACb,iBAAiB;AAAA,EACjB,qBAAqB;AAAA,EACrB,mBAAmB;AAAA,EACnB,aAAa;AAAA,EACb,cAAc;AAAA,EACd,iBAAiB;AAAA,EACjB,UAAU;AAAA,EACV,WAAW;AAAA,EACX,SAAS;AAAA,EACT,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,mBAAmB;AAAA,EACnB,mBAAmB;AAAA,EACnB,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,UAAU;AACd;AAEO,MAAM,iBAAiB;AAAA,EAC1B,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,qBAAqB;AAAA,EACrB,mBAAmB;AACvB;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/build/lib/utils.js
CHANGED
|
@@ -45,7 +45,7 @@ __export(utils_exports, {
|
|
|
45
45
|
});
|
|
46
46
|
module.exports = __toCommonJS(utils_exports);
|
|
47
47
|
var import_eufy_security_client = require("eufy-security-client");
|
|
48
|
-
var
|
|
48
|
+
var import_node_path = __toESM(require("node:path"));
|
|
49
49
|
var import_fs_extra = __toESM(require("fs-extra"));
|
|
50
50
|
var utils = __toESM(require("@iobroker/adapter-core"));
|
|
51
51
|
const setStateChangedAsync = async function(adapter, id, value) {
|
|
@@ -53,15 +53,17 @@ const setStateChangedAsync = async function(adapter, id, value) {
|
|
|
53
53
|
};
|
|
54
54
|
const isEmpty = function(str) {
|
|
55
55
|
if (str) {
|
|
56
|
-
if (str.length > 0)
|
|
56
|
+
if (str.length > 0) {
|
|
57
57
|
return false;
|
|
58
|
+
}
|
|
58
59
|
return true;
|
|
59
60
|
}
|
|
60
61
|
return true;
|
|
61
62
|
};
|
|
62
63
|
const getImageAsHTML = function(data, mime = "image/jpg") {
|
|
63
|
-
if (data && data.length > 0)
|
|
64
|
+
if (data && data.length > 0) {
|
|
64
65
|
return `<img src="data:${mime};base64,${data.toString("base64")}" style="width: auto ;height: 100%;" />`;
|
|
66
|
+
}
|
|
65
67
|
return "";
|
|
66
68
|
};
|
|
67
69
|
const setStateAsync = async function(adapter, state_id, common_name, value, role = "text", type = "string") {
|
|
@@ -81,17 +83,21 @@ const setStateAsync = async function(adapter, state_id, common_name, value, role
|
|
|
81
83
|
const removeFiles = function(adapter, stationSerial, folderName, device_sn) {
|
|
82
84
|
return new Promise(async (resolve, reject) => {
|
|
83
85
|
try {
|
|
84
|
-
const dir_path =
|
|
86
|
+
const dir_path = import_node_path.default.join(stationSerial, folderName);
|
|
85
87
|
if (await adapter.fileExistsAsync(adapter.namespace, dir_path)) {
|
|
86
|
-
const files = (await adapter.readDirAsync(adapter.namespace, dir_path)).filter(
|
|
88
|
+
const files = (await adapter.readDirAsync(adapter.namespace, dir_path)).filter(
|
|
89
|
+
(fn) => fn.file.startsWith(device_sn)
|
|
90
|
+
);
|
|
87
91
|
try {
|
|
88
|
-
|
|
89
|
-
|
|
92
|
+
for (const filename of files) {
|
|
93
|
+
await adapter.delFileAsync(adapter.namespace, import_node_path.default.join(dir_path, filename.file));
|
|
94
|
+
}
|
|
95
|
+
} catch {
|
|
90
96
|
}
|
|
91
97
|
}
|
|
92
98
|
resolve();
|
|
93
99
|
} catch (error) {
|
|
94
|
-
reject(error);
|
|
100
|
+
reject(new Error(`Failed to remove files: ${error}`));
|
|
95
101
|
}
|
|
96
102
|
});
|
|
97
103
|
};
|
|
@@ -114,22 +120,24 @@ const getVideoClipLength = (device) => {
|
|
|
114
120
|
if (workingMode !== void 0) {
|
|
115
121
|
switch (workingMode) {
|
|
116
122
|
case "0":
|
|
117
|
-
if (device.isCamera2Product() || device.isIndoorCamera() || device.isSoloCameras())
|
|
123
|
+
if (device.isCamera2Product() || device.isIndoorCamera() || device.isSoloCameras()) {
|
|
118
124
|
length = 20;
|
|
119
|
-
else if (device.isBatteryDoorbell() || device.isBatteryDoorbell2())
|
|
125
|
+
} else if (device.isBatteryDoorbell() || device.isBatteryDoorbell2()) {
|
|
120
126
|
length = 30;
|
|
127
|
+
}
|
|
121
128
|
break;
|
|
122
129
|
case "1":
|
|
123
130
|
break;
|
|
124
|
-
case "2":
|
|
131
|
+
case "2": {
|
|
125
132
|
const customValue = device.getRawProperty(import_eufy_security_client.CommandType.CMD_DEV_RECORD_TIMEOUT);
|
|
126
133
|
if (customValue !== void 0) {
|
|
127
134
|
try {
|
|
128
135
|
length = Number.parseInt(customValue);
|
|
129
|
-
} catch
|
|
136
|
+
} catch {
|
|
130
137
|
}
|
|
131
138
|
}
|
|
132
139
|
break;
|
|
140
|
+
}
|
|
133
141
|
case "3":
|
|
134
142
|
break;
|
|
135
143
|
}
|
|
@@ -144,48 +152,56 @@ const removeLastChar = function(text, char) {
|
|
|
144
152
|
const changeRole = async function(adapter, log, state, role) {
|
|
145
153
|
try {
|
|
146
154
|
const states = await adapter.getStatesAsync(`*.${state}`);
|
|
147
|
-
if (states)
|
|
155
|
+
if (states) {
|
|
148
156
|
Object.keys(states).forEach(async (id) => {
|
|
149
|
-
await adapter.extendObjectAsync(
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
157
|
+
await adapter.extendObjectAsync(
|
|
158
|
+
id,
|
|
159
|
+
{
|
|
160
|
+
type: "state",
|
|
161
|
+
common: {
|
|
162
|
+
role
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
{}
|
|
166
|
+
).catch();
|
|
155
167
|
});
|
|
168
|
+
}
|
|
156
169
|
} catch (error) {
|
|
157
170
|
log.error(`state: ${state} role: ${role} - Error:`, error);
|
|
158
171
|
}
|
|
159
172
|
};
|
|
160
173
|
const deleteStates = async function(adapter, property) {
|
|
161
174
|
const states = await adapter.getStatesAsync(`*.${property}`);
|
|
162
|
-
if (states)
|
|
163
|
-
Object.keys(states)
|
|
175
|
+
if (states) {
|
|
176
|
+
const ids = Object.keys(states);
|
|
177
|
+
for (const id of ids) {
|
|
164
178
|
await adapter.delObjectAsync(id).catch();
|
|
165
|
-
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
166
181
|
};
|
|
167
182
|
const handleUpdate = async function(adapter, log, oldVersion, newVersion) {
|
|
168
183
|
if (oldVersion != 0 && oldVersion <= 0.61) {
|
|
169
184
|
try {
|
|
170
185
|
const all = await adapter.getStatesAsync("T*");
|
|
171
186
|
if (all) {
|
|
172
|
-
Object.keys(all)
|
|
187
|
+
const ids = Object.keys(all);
|
|
188
|
+
for (const id of ids) {
|
|
173
189
|
await adapter.delObjectAsync(id, { recursive: false }).catch();
|
|
174
|
-
}
|
|
190
|
+
}
|
|
175
191
|
}
|
|
176
192
|
const channels = await adapter.getChannelsOfAsync();
|
|
177
193
|
if (channels) {
|
|
178
|
-
|
|
194
|
+
for (const channel of channels) {
|
|
179
195
|
if (channel.common.name !== "info") {
|
|
180
196
|
await adapter.delObjectAsync(channel._id, { recursive: false }).catch();
|
|
181
197
|
}
|
|
182
|
-
}
|
|
198
|
+
}
|
|
183
199
|
}
|
|
184
200
|
const devices = await adapter.getDevicesAsync();
|
|
185
201
|
if (devices) {
|
|
186
|
-
|
|
202
|
+
for (const device of devices) {
|
|
187
203
|
await adapter.delObjectAsync(device._id, { recursive: false }).catch();
|
|
188
|
-
}
|
|
204
|
+
}
|
|
189
205
|
}
|
|
190
206
|
} catch (error) {
|
|
191
207
|
log.error("Version 0.6.1: Error:", error);
|
|
@@ -220,32 +236,34 @@ const handleUpdate = async function(adapter, log, oldVersion, newVersion) {
|
|
|
220
236
|
if (oldVersion == 0 && newVersion == 1.3) {
|
|
221
237
|
const data_dir = utils.getAbsoluteInstanceDataDir(adapter);
|
|
222
238
|
try {
|
|
223
|
-
const file =
|
|
239
|
+
const file = import_node_path.default.join(data_dir, "adapter.json");
|
|
224
240
|
if (import_fs_extra.default.statSync(file).isFile()) {
|
|
225
241
|
const fileContent = import_fs_extra.default.readFileSync(file, "utf8");
|
|
226
242
|
await adapter.writeFileAsync(adapter.namespace, "adapter.json", fileContent);
|
|
227
243
|
}
|
|
228
|
-
} catch
|
|
244
|
+
} catch {
|
|
229
245
|
}
|
|
230
246
|
try {
|
|
231
|
-
const file =
|
|
247
|
+
const file = import_node_path.default.join(data_dir, "persistent.json");
|
|
232
248
|
if (import_fs_extra.default.statSync(file).isFile()) {
|
|
233
249
|
const fileContent = import_fs_extra.default.readFileSync(file, "utf8");
|
|
234
250
|
await adapter.writeFileAsync(adapter.namespace, "driver.json", fileContent);
|
|
235
251
|
}
|
|
236
|
-
} catch
|
|
252
|
+
} catch {
|
|
237
253
|
}
|
|
238
254
|
try {
|
|
239
255
|
import_fs_extra.default.removeSync(data_dir);
|
|
240
|
-
} catch
|
|
256
|
+
} catch {
|
|
241
257
|
}
|
|
242
|
-
adapter.log.warn(
|
|
258
|
+
adapter.log.warn(
|
|
259
|
+
"Migrated configuration files to new location (needs restart). Restart of the adapter initiated."
|
|
260
|
+
);
|
|
243
261
|
adapter.restartAdapter();
|
|
244
262
|
}
|
|
245
263
|
};
|
|
246
264
|
const convertCamelCaseToSnakeCase = function(value) {
|
|
247
265
|
return value.replace(/[A-Z]/g, (letter, index) => {
|
|
248
|
-
return index == 0 ? letter.toLowerCase() :
|
|
266
|
+
return index == 0 ? letter.toLowerCase() : `_${letter.toLowerCase()}`;
|
|
249
267
|
});
|
|
250
268
|
};
|
|
251
269
|
function getShortUrl(url, prefixUrl) {
|
package/build/lib/utils.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/utils.ts"],
|
|
4
|
-
"sourcesContent": ["import { CommandType, Device } from \"eufy-security-client\";\r\nimport path from \"path\";\r\nimport fse from \"fs-extra\";\r\nimport * as utils from \"@iobroker/adapter-core\";\r\n\r\nimport { ioBrokerLogger } from \"./log\";\r\nimport { euSec } from \"../main\";\r\n\r\n// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types\r\nexport const setStateChangedAsync = async function(adapter: ioBroker.Adapter, id: string, value: any): ioBroker.SetStateChangedPromise {\r\n return await adapter.setStateChangedAsync(id, value === undefined || value === null ? null : { val: value, ack: true }).catch();\r\n};\r\n\r\nexport const isEmpty = function(str: string | null | undefined): boolean {\r\n if (str) {\r\n if (str.length > 0)\r\n return false;\r\n return true;\r\n }\r\n return true;\r\n};\r\n\r\nexport const getImageAsHTML = function(data: Buffer, mime = \"image/jpg\"): string {\r\n if (data && data.length > 0)\r\n return `<img src=\"data:${mime};base64,${data.toString(\"base64\")}\" style=\"width: auto ;height: 100%;\" />`;\r\n return \"\";\r\n}\r\n\r\n/*export const getDataFilePath = function(adapter: ioBroker.Adapter, stationSerial: string, folderName: string, fileName: string): string {\r\n const dir_path = path.join(utils.getAbsoluteInstanceDataDir(adapter), stationSerial, folderName);\r\n if (!fse.existsSync(dir_path)) {\r\n fse.mkdirSync(dir_path, {mode: 0o775, recursive: true});\r\n }\r\n return path.join(dir_path, fileName);\r\n}*/\r\n\r\nexport const setStateAsync = async function(adapter: ioBroker.Adapter, state_id: string, common_name: string, value: string, role = \"text\", type: \"string\" | \"number\" | \"boolean\" | \"object\" | \"array\" | \"mixed\" | undefined = \"string\"): Promise<void> {\r\n await adapter.setObjectNotExistsAsync(state_id, {\r\n type: \"state\",\r\n common: {\r\n name: common_name,\r\n type: type,\r\n role: role,\r\n read: true,\r\n write: false,\r\n },\r\n native: {\r\n },\r\n });\r\n await adapter.setStateAsync(state_id, { val: value, ack: true });\r\n}\r\n\r\nexport const removeFiles = function(adapter: ioBroker.Adapter, stationSerial: string, folderName: string, device_sn: string): Promise<void> {\r\n return new Promise(async (resolve, reject) => {\r\n try {\r\n const dir_path = path.join(stationSerial, folderName);\r\n if (await adapter.fileExistsAsync(adapter.namespace, dir_path)) {\r\n const files = (await adapter.readDirAsync(adapter.namespace, dir_path)).filter(fn => fn.file.startsWith(device_sn));\r\n try {\r\n files.map(filename => adapter.delFileAsync(adapter.namespace, path.join(dir_path, filename.file)));\r\n } catch (error) {\r\n }\r\n }\r\n resolve();\r\n } catch (error) {\r\n reject(error);\r\n }\r\n });\r\n}\r\n\r\n/*export const moveFiles = function(adapter: ioBroker.Adapter, stationSerial: string, device_sn: string, srcFolderName: string, dstFolderName: string): Promise<void> {\r\n return new Promise((resolve, reject) => {\r\n try {\r\n const dirSrcPath = path.join(utils.getAbsoluteInstanceDataDir(adapter), stationSerial, srcFolderName);\r\n const dirDstPath = path.join(utils.getAbsoluteInstanceDataDir(adapter), stationSerial, dstFolderName);\r\n if (!fse.existsSync(dirDstPath)) {\r\n fse.mkdirSync(dirDstPath, {mode: 0o775, recursive: true});\r\n }\r\n if (fse.existsSync(dirSrcPath)) {\r\n const files = fse.readdirSync(dirSrcPath).filter(fn => fn.startsWith(device_sn));\r\n try {\r\n files.map(filename => fse.moveSync(path.join(dirSrcPath, filename), path.join(dirDstPath, filename)));\r\n } catch (error) {\r\n }\r\n }\r\n resolve();\r\n } catch (error) {\r\n reject(error);\r\n }\r\n });\r\n}*/\r\n\r\nexport const lowestUnusedNumber = function (sequence: number[], startingFrom: number): number {\r\n const arr = sequence.slice(0);\r\n arr.sort((a, b) => a - b);\r\n return arr.reduce((lowest, num, i) => {\r\n const seqIndex = i + startingFrom;\r\n return num !== seqIndex && seqIndex < lowest ? seqIndex : lowest\r\n }, arr.length + startingFrom);\r\n}\r\n\r\nexport const sleep = async (ms: number): Promise<void> => {\r\n return new Promise((resolve) => {\r\n setTimeout(resolve, ms);\r\n });\r\n};\r\n\r\nexport const getVideoClipLength = (device: Device): number => {\r\n let length = 60;\r\n const workingMode = device.getRawProperty(CommandType.CMD_SET_PIR_POWERMODE);\r\n if (workingMode !== undefined) {\r\n switch(workingMode) {\r\n case \"0\":\r\n if (device.isCamera2Product() || device.isIndoorCamera() || device.isSoloCameras())\r\n length = 20;\r\n else if (device.isBatteryDoorbell() || device.isBatteryDoorbell2())\r\n length = 30;\r\n break;\r\n case \"1\":\r\n // Corrisponds to 60 seconds\r\n break;\r\n case \"2\":\r\n const customValue = device.getRawProperty(CommandType.CMD_DEV_RECORD_TIMEOUT);\r\n if (customValue !== undefined) {\r\n try {\r\n length = Number.parseInt(customValue);\r\n } catch(error) {\r\n }\r\n }\r\n break;\r\n case \"3\":\r\n // Corrisponds to 60 seconds?? (this mode exists only for battery doorbells; mode: Optimal Battery Life)\r\n break;\r\n }\r\n }\r\n return length;\r\n};\r\n\r\nexport const removeLastChar = function(text: string, char: string): string {\r\n const strArr = [...text];\r\n strArr.splice(text.lastIndexOf(char), 1);\r\n return strArr.join(\"\");\r\n}\r\n\r\nexport const changeRole = async function(adapter: ioBroker.Adapter, log: ioBrokerLogger, state: string, role: string): Promise<void> {\r\n try {\r\n const states = await adapter.getStatesAsync(`*.${state}`);\r\n if (states)\r\n Object.keys(states).forEach(async id => {\r\n await adapter.extendObjectAsync(id, {\r\n type: \"state\",\r\n common: {\r\n role: role\r\n }\r\n }, {}).catch();\r\n });\r\n } catch (error) {\r\n log.error(`state: ${state} role: ${role} - Error:`, error);\r\n }\r\n};\r\n\r\nexport const deleteStates = async function(adapter: ioBroker.Adapter, property: string): Promise<void> {\r\n const states = await adapter.getStatesAsync(`*.${property}`);\r\n if (states)\r\n Object.keys(states).forEach(async id => {\r\n await adapter.delObjectAsync(id).catch();\r\n });\r\n};\r\n\r\nexport const handleUpdate = async function(adapter: euSec, log: ioBrokerLogger, oldVersion: number, newVersion: number): Promise<void> {\r\n if (oldVersion != 0 && oldVersion <= 0.61) {\r\n try {\r\n const all = await adapter.getStatesAsync(\"T*\");\r\n if (all) {\r\n Object.keys(all).forEach(async id => {\r\n await adapter.delObjectAsync(id, { recursive: false }).catch();\r\n });\r\n }\r\n const channels = await adapter.getChannelsOfAsync();\r\n if (channels) {\r\n Object.values(channels).forEach(async channel => {\r\n if (channel.common.name !== \"info\") {\r\n await adapter.delObjectAsync(channel._id, {recursive: false}).catch();\r\n }\r\n });\r\n }\r\n const devices = await adapter.getDevicesAsync();\r\n if (devices) {\r\n Object.values(devices).forEach(async device => {\r\n await adapter.delObjectAsync(device._id, {recursive: false}).catch();\r\n });\r\n }\r\n } catch (error) {\r\n log.error(\"Version 0.6.1: Error:\", error);\r\n }\r\n }\r\n if (oldVersion != 0 && oldVersion <= 0.74) {\r\n try {\r\n await adapter.setObjectAsync(\"verify_code\", {\r\n type: \"state\",\r\n common: {\r\n name: \"2FA verification code\",\r\n type: \"string\",\r\n role: \"state\",\r\n read: true,\r\n write: true,\r\n },\r\n native: {},\r\n });\r\n } catch (error) {\r\n log.error(\"Version 0.7.4: Error:\", error);\r\n }\r\n }\r\n if (oldVersion != 0 && oldVersion <= 1) {\r\n for (const state of [\"last_event_pic_url\", \"last_event_pic_html\", \"last_event_video_url\"]) {\r\n try {\r\n await deleteStates(adapter, state);\r\n } catch (error) {\r\n log.error(`Version 1.0.0 - ${state}: Error:`, error);\r\n }\r\n }\r\n }\r\n if (oldVersion == 0 && newVersion == 1.3) {\r\n const data_dir = utils.getAbsoluteInstanceDataDir(adapter);\r\n try {\r\n const file = path.join(data_dir, \"adapter.json\");\r\n if (fse.statSync(file).isFile()) {\r\n const fileContent = fse.readFileSync(file, \"utf8\");\r\n await adapter.writeFileAsync(adapter.namespace, \"adapter.json\", fileContent);\r\n }\r\n } catch (error) {\r\n //log.error(`Version 3.0.0: Error:`, error);\r\n }\r\n try {\r\n const file = path.join(data_dir, \"persistent.json\");\r\n if (fse.statSync(file).isFile()) {\r\n const fileContent = fse.readFileSync(file, \"utf8\");\r\n await adapter.writeFileAsync(adapter.namespace, \"driver.json\", fileContent);\r\n }\r\n } catch (error) {\r\n //log.error(`Version 3.0.0: Error:`, error);\r\n }\r\n try {\r\n fse.removeSync(data_dir);\r\n } catch (error) {\r\n //log.error(`Version 3.0.0: Error:`, error);\r\n }\r\n adapter.log.warn(\"Migrated configuration files to new location (needs restart). Restart of the adapter initiated.\")\r\n adapter.restartAdapter();\r\n }\r\n};\r\n\r\nexport const convertCamelCaseToSnakeCase = function (value: string): string {\r\n return value.replace(/[A-Z]/g, (letter, index) => {\r\n return index == 0 ? letter.toLowerCase() : \"_\" + letter.toLowerCase();\r\n });\r\n};\r\n\r\nexport function getShortUrl(url: URL, prefixUrl?: string): string {\r\n if (url.password) {\r\n url = new URL(url.toString()); // prevent original url mutation\r\n url.password = \"[redacted]\";\r\n }\r\n let shortUrl = url.toString();\r\n if (prefixUrl && shortUrl.startsWith(prefixUrl)) {\r\n shortUrl = shortUrl.slice(prefixUrl.length);\r\n }\r\n\r\n return shortUrl;\r\n}"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;
|
|
4
|
+
"sourcesContent": ["import type { Device } from 'eufy-security-client';\nimport { CommandType } from 'eufy-security-client';\nimport path from 'node:path';\nimport fse from 'fs-extra';\nimport * as utils from '@iobroker/adapter-core';\n\nimport type { ioBrokerLogger } from './log';\nimport type { euSec } from '../main';\n\nexport const setStateChangedAsync = async function (\n adapter: ioBroker.Adapter,\n id: string,\n value: any,\n): ioBroker.SetStateChangedPromise {\n return await adapter\n .setStateChangedAsync(id, value === undefined || value === null ? null : { val: value, ack: true })\n .catch();\n};\n\nexport const isEmpty = function (str: string | null | undefined): boolean {\n if (str) {\n if (str.length > 0) {\n return false;\n }\n return true;\n }\n return true;\n};\n\nexport const getImageAsHTML = function (data: Buffer, mime = 'image/jpg'): string {\n if (data && data.length > 0) {\n return `<img src=\"data:${mime};base64,${data.toString('base64')}\" style=\"width: auto ;height: 100%;\" />`;\n }\n return '';\n};\n\n/*export const getDataFilePath = function(adapter: ioBroker.Adapter, stationSerial: string, folderName: string, fileName: string): string {\n const dir_path = path.join(utils.getAbsoluteInstanceDataDir(adapter), stationSerial, folderName);\n if (!fse.existsSync(dir_path)) {\n fse.mkdirSync(dir_path, {mode: 0o775, recursive: true});\n }\n return path.join(dir_path, fileName);\n}*/\n\nexport const setStateAsync = async function (\n adapter: ioBroker.Adapter,\n state_id: string,\n common_name: string,\n value: string,\n role = 'text',\n type: 'string' | 'number' | 'boolean' | 'object' | 'array' | 'mixed' | undefined = 'string',\n): Promise<void> {\n await adapter.setObjectNotExistsAsync(state_id, {\n type: 'state',\n common: {\n name: common_name,\n type: type,\n role: role,\n read: true,\n write: false,\n },\n native: {},\n });\n await adapter.setStateAsync(state_id, { val: value, ack: true });\n};\n\nexport const removeFiles = function (\n adapter: ioBroker.Adapter,\n stationSerial: string,\n folderName: string,\n device_sn: string,\n): Promise<void> {\n // eslint-disable-next-line no-async-promise-executor\n return new Promise(async (resolve, reject) => {\n try {\n const dir_path = path.join(stationSerial, folderName);\n if (await adapter.fileExistsAsync(adapter.namespace, dir_path)) {\n const files = (await adapter.readDirAsync(adapter.namespace, dir_path)).filter(fn =>\n fn.file.startsWith(device_sn),\n );\n try {\n for (const filename of files) {\n await adapter.delFileAsync(adapter.namespace, path.join(dir_path, filename.file));\n }\n } catch {\n // ignore\n }\n }\n resolve();\n } catch (error) {\n reject(new Error(`Failed to remove files: ${error as Error}`));\n }\n });\n};\n\n/*export const moveFiles = function(adapter: ioBroker.Adapter, stationSerial: string, device_sn: string, srcFolderName: string, dstFolderName: string): Promise<void> {\n return new Promise((resolve, reject) => {\n try {\n const dirSrcPath = path.join(utils.getAbsoluteInstanceDataDir(adapter), stationSerial, srcFolderName);\n const dirDstPath = path.join(utils.getAbsoluteInstanceDataDir(adapter), stationSerial, dstFolderName);\n if (!fse.existsSync(dirDstPath)) {\n fse.mkdirSync(dirDstPath, {mode: 0o775, recursive: true});\n }\n if (fse.existsSync(dirSrcPath)) {\n const files = fse.readdirSync(dirSrcPath).filter(fn => fn.startsWith(device_sn));\n try {\n files.map(filename => fse.moveSync(path.join(dirSrcPath, filename), path.join(dirDstPath, filename)));\n } catch (error) {\n }\n }\n resolve();\n } catch (error) {\n reject(error);\n }\n });\n}*/\n\nexport const lowestUnusedNumber = function (sequence: number[], startingFrom: number): number {\n const arr = sequence.slice(0);\n arr.sort((a, b) => a - b);\n return arr.reduce((lowest, num, i) => {\n const seqIndex = i + startingFrom;\n return num !== seqIndex && seqIndex < lowest ? seqIndex : lowest;\n }, arr.length + startingFrom);\n};\n\nexport const sleep = async (ms: number): Promise<void> => {\n return new Promise(resolve => {\n setTimeout(resolve, ms);\n });\n};\n\nexport const getVideoClipLength = (device: Device): number => {\n let length = 60;\n const workingMode = device.getRawProperty(CommandType.CMD_SET_PIR_POWERMODE);\n if (workingMode !== undefined) {\n switch (workingMode) {\n case '0':\n if (device.isCamera2Product() || device.isIndoorCamera() || device.isSoloCameras()) {\n length = 20;\n } else if (device.isBatteryDoorbell() || device.isBatteryDoorbell2()) {\n length = 30;\n }\n break;\n case '1':\n // Corresponds to 60 seconds\n break;\n case '2': {\n const customValue = device.getRawProperty(CommandType.CMD_DEV_RECORD_TIMEOUT);\n if (customValue !== undefined) {\n try {\n length = Number.parseInt(customValue);\n } catch {\n // ignore\n }\n }\n break;\n }\n case '3':\n // Corresponds to 60 seconds?? (this mode exists only for battery doorbells; mode: Optimal Battery Life)\n break;\n }\n }\n return length;\n};\n\nexport const removeLastChar = function (text: string, char: string): string {\n const strArr = [...text];\n strArr.splice(text.lastIndexOf(char), 1);\n return strArr.join('');\n};\n\nexport const changeRole = async function (\n adapter: ioBroker.Adapter,\n log: ioBrokerLogger,\n state: string,\n role: string,\n): Promise<void> {\n try {\n const states = await adapter.getStatesAsync(`*.${state}`);\n if (states) {\n Object.keys(states).forEach(async id => {\n await adapter\n .extendObjectAsync(\n id,\n {\n type: 'state',\n common: {\n role: role,\n },\n },\n {},\n )\n .catch();\n });\n }\n } catch (error) {\n log.error(`state: ${state} role: ${role} - Error:`, error);\n }\n};\n\nexport const deleteStates = async function (adapter: ioBroker.Adapter, property: string): Promise<void> {\n const states = await adapter.getStatesAsync(`*.${property}`);\n if (states) {\n const ids = Object.keys(states);\n for (const id of ids) {\n await adapter.delObjectAsync(id).catch();\n }\n }\n};\n\nexport const handleUpdate = async function (\n adapter: euSec,\n log: ioBrokerLogger,\n oldVersion: number,\n newVersion: number,\n): Promise<void> {\n if (oldVersion != 0 && oldVersion <= 0.61) {\n try {\n const all = await adapter.getStatesAsync('T*');\n if (all) {\n const ids = Object.keys(all);\n for (const id of ids) {\n await adapter.delObjectAsync(id, { recursive: false }).catch();\n }\n }\n const channels = await adapter.getChannelsOfAsync();\n if (channels) {\n for (const channel of channels) {\n if (channel.common.name !== 'info') {\n await adapter.delObjectAsync(channel._id, { recursive: false }).catch();\n }\n }\n }\n const devices = await adapter.getDevicesAsync();\n if (devices) {\n for (const device of devices) {\n await adapter.delObjectAsync(device._id, { recursive: false }).catch();\n }\n }\n } catch (error) {\n log.error('Version 0.6.1: Error:', error);\n }\n }\n if (oldVersion != 0 && oldVersion <= 0.74) {\n try {\n await adapter.setObjectAsync('verify_code', {\n type: 'state',\n common: {\n name: '2FA verification code',\n type: 'string',\n role: 'state',\n read: true,\n write: true,\n },\n native: {},\n });\n } catch (error) {\n log.error('Version 0.7.4: Error:', error);\n }\n }\n if (oldVersion != 0 && oldVersion <= 1) {\n for (const state of ['last_event_pic_url', 'last_event_pic_html', 'last_event_video_url']) {\n try {\n await deleteStates(adapter, state);\n } catch (error) {\n log.error(`Version 1.0.0 - ${state}: Error:`, error);\n }\n }\n }\n if (oldVersion == 0 && newVersion == 1.3) {\n const data_dir = utils.getAbsoluteInstanceDataDir(adapter);\n try {\n const file = path.join(data_dir, 'adapter.json');\n if (fse.statSync(file).isFile()) {\n const fileContent = fse.readFileSync(file, 'utf8');\n await adapter.writeFileAsync(adapter.namespace, 'adapter.json', fileContent);\n }\n } catch {\n // log.error(`Version 3.0.0: Error:`, error);\n }\n try {\n const file = path.join(data_dir, 'persistent.json');\n if (fse.statSync(file).isFile()) {\n const fileContent = fse.readFileSync(file, 'utf8');\n await adapter.writeFileAsync(adapter.namespace, 'driver.json', fileContent);\n }\n } catch {\n // log.error(`Version 3.0.0: Error:`, error);\n }\n try {\n fse.removeSync(data_dir);\n } catch {\n // log.error(`Version 3.0.0: Error:`, error);\n }\n adapter.log.warn(\n 'Migrated configuration files to new location (needs restart). Restart of the adapter initiated.',\n );\n adapter.restartAdapter();\n }\n};\n\nexport const convertCamelCaseToSnakeCase = function (value: string): string {\n return value.replace(/[A-Z]/g, (letter, index) => {\n return index == 0 ? letter.toLowerCase() : `_${letter.toLowerCase()}`;\n });\n};\n\nexport function getShortUrl(url: URL, prefixUrl?: string): string {\n if (url.password) {\n url = new URL(url.toString()); // prevent original url mutation\n url.password = '[redacted]';\n }\n let shortUrl = url.toString();\n if (prefixUrl && shortUrl.startsWith(prefixUrl)) {\n shortUrl = shortUrl.slice(prefixUrl.length);\n }\n\n return shortUrl;\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,kCAA4B;AAC5B,uBAAiB;AACjB,sBAAgB;AAChB,YAAuB;AAKhB,MAAM,uBAAuB,eAChC,SACA,IACA,OAC+B;AAC/B,SAAO,MAAM,QACR,qBAAqB,IAAI,UAAU,UAAa,UAAU,OAAO,OAAO,EAAE,KAAK,OAAO,KAAK,KAAK,CAAC,EACjG,MAAM;AACf;AAEO,MAAM,UAAU,SAAU,KAAyC;AACtE,MAAI,KAAK;AACL,QAAI,IAAI,SAAS,GAAG;AAChB,aAAO;AAAA,IACX;AACA,WAAO;AAAA,EACX;AACA,SAAO;AACX;AAEO,MAAM,iBAAiB,SAAU,MAAc,OAAO,aAAqB;AAC9E,MAAI,QAAQ,KAAK,SAAS,GAAG;AACzB,WAAO,kBAAkB,IAAI,WAAW,KAAK,SAAS,QAAQ,CAAC;AAAA,EACnE;AACA,SAAO;AACX;AAUO,MAAM,gBAAgB,eACzB,SACA,UACA,aACA,OACA,OAAO,QACP,OAAmF,UACtE;AACb,QAAM,QAAQ,wBAAwB,UAAU;AAAA,IAC5C,MAAM;AAAA,IACN,QAAQ;AAAA,MACJ,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA,MAAM;AAAA,MACN,OAAO;AAAA,IACX;AAAA,IACA,QAAQ,CAAC;AAAA,EACb,CAAC;AACD,QAAM,QAAQ,cAAc,UAAU,EAAE,KAAK,OAAO,KAAK,KAAK,CAAC;AACnE;AAEO,MAAM,cAAc,SACvB,SACA,eACA,YACA,WACa;AAEb,SAAO,IAAI,QAAQ,OAAO,SAAS,WAAW;AAC1C,QAAI;AACA,YAAM,WAAW,iBAAAA,QAAK,KAAK,eAAe,UAAU;AACpD,UAAI,MAAM,QAAQ,gBAAgB,QAAQ,WAAW,QAAQ,GAAG;AAC5D,cAAM,SAAS,MAAM,QAAQ,aAAa,QAAQ,WAAW,QAAQ,GAAG;AAAA,UAAO,QAC3E,GAAG,KAAK,WAAW,SAAS;AAAA,QAChC;AACA,YAAI;AACA,qBAAW,YAAY,OAAO;AAC1B,kBAAM,QAAQ,aAAa,QAAQ,WAAW,iBAAAA,QAAK,KAAK,UAAU,SAAS,IAAI,CAAC;AAAA,UACpF;AAAA,QACJ,QAAQ;AAAA,QAER;AAAA,MACJ;AACA,cAAQ;AAAA,IACZ,SAAS,OAAO;AACZ,aAAO,IAAI,MAAM,2BAA2B,KAAc,EAAE,CAAC;AAAA,IACjE;AAAA,EACJ,CAAC;AACL;AAwBO,MAAM,qBAAqB,SAAU,UAAoB,cAA8B;AAC1F,QAAM,MAAM,SAAS,MAAM,CAAC;AAC5B,MAAI,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC;AACxB,SAAO,IAAI,OAAO,CAAC,QAAQ,KAAK,MAAM;AAClC,UAAM,WAAW,IAAI;AACrB,WAAO,QAAQ,YAAY,WAAW,SAAS,WAAW;AAAA,EAC9D,GAAG,IAAI,SAAS,YAAY;AAChC;AAEO,MAAM,QAAQ,OAAO,OAA8B;AACtD,SAAO,IAAI,QAAQ,aAAW;AAC1B,eAAW,SAAS,EAAE;AAAA,EAC1B,CAAC;AACL;AAEO,MAAM,qBAAqB,CAAC,WAA2B;AAC1D,MAAI,SAAS;AACb,QAAM,cAAc,OAAO,eAAe,wCAAY,qBAAqB;AAC3E,MAAI,gBAAgB,QAAW;AAC3B,YAAQ,aAAa;AAAA,MACjB,KAAK;AACD,YAAI,OAAO,iBAAiB,KAAK,OAAO,eAAe,KAAK,OAAO,cAAc,GAAG;AAChF,mBAAS;AAAA,QACb,WAAW,OAAO,kBAAkB,KAAK,OAAO,mBAAmB,GAAG;AAClE,mBAAS;AAAA,QACb;AACA;AAAA,MACJ,KAAK;AAED;AAAA,MACJ,KAAK,KAAK;AACN,cAAM,cAAc,OAAO,eAAe,wCAAY,sBAAsB;AAC5E,YAAI,gBAAgB,QAAW;AAC3B,cAAI;AACA,qBAAS,OAAO,SAAS,WAAW;AAAA,UACxC,QAAQ;AAAA,UAER;AAAA,QACJ;AACA;AAAA,MACJ;AAAA,MACA,KAAK;AAED;AAAA,IACR;AAAA,EACJ;AACA,SAAO;AACX;AAEO,MAAM,iBAAiB,SAAU,MAAc,MAAsB;AACxE,QAAM,SAAS,CAAC,GAAG,IAAI;AACvB,SAAO,OAAO,KAAK,YAAY,IAAI,GAAG,CAAC;AACvC,SAAO,OAAO,KAAK,EAAE;AACzB;AAEO,MAAM,aAAa,eACtB,SACA,KACA,OACA,MACa;AACb,MAAI;AACA,UAAM,SAAS,MAAM,QAAQ,eAAe,KAAK,KAAK,EAAE;AACxD,QAAI,QAAQ;AACR,aAAO,KAAK,MAAM,EAAE,QAAQ,OAAM,OAAM;AACpC,cAAM,QACD;AAAA,UACG;AAAA,UACA;AAAA,YACI,MAAM;AAAA,YACN,QAAQ;AAAA,cACJ;AAAA,YACJ;AAAA,UACJ;AAAA,UACA,CAAC;AAAA,QACL,EACC,MAAM;AAAA,MACf,CAAC;AAAA,IACL;AAAA,EACJ,SAAS,OAAO;AACZ,QAAI,MAAM,UAAU,KAAK,UAAU,IAAI,aAAa,KAAK;AAAA,EAC7D;AACJ;AAEO,MAAM,eAAe,eAAgB,SAA2B,UAAiC;AACpG,QAAM,SAAS,MAAM,QAAQ,eAAe,KAAK,QAAQ,EAAE;AAC3D,MAAI,QAAQ;AACR,UAAM,MAAM,OAAO,KAAK,MAAM;AAC9B,eAAW,MAAM,KAAK;AAClB,YAAM,QAAQ,eAAe,EAAE,EAAE,MAAM;AAAA,IAC3C;AAAA,EACJ;AACJ;AAEO,MAAM,eAAe,eACxB,SACA,KACA,YACA,YACa;AACb,MAAI,cAAc,KAAK,cAAc,MAAM;AACvC,QAAI;AACA,YAAM,MAAM,MAAM,QAAQ,eAAe,IAAI;AAC7C,UAAI,KAAK;AACL,cAAM,MAAM,OAAO,KAAK,GAAG;AAC3B,mBAAW,MAAM,KAAK;AAClB,gBAAM,QAAQ,eAAe,IAAI,EAAE,WAAW,MAAM,CAAC,EAAE,MAAM;AAAA,QACjE;AAAA,MACJ;AACA,YAAM,WAAW,MAAM,QAAQ,mBAAmB;AAClD,UAAI,UAAU;AACV,mBAAW,WAAW,UAAU;AAC5B,cAAI,QAAQ,OAAO,SAAS,QAAQ;AAChC,kBAAM,QAAQ,eAAe,QAAQ,KAAK,EAAE,WAAW,MAAM,CAAC,EAAE,MAAM;AAAA,UAC1E;AAAA,QACJ;AAAA,MACJ;AACA,YAAM,UAAU,MAAM,QAAQ,gBAAgB;AAC9C,UAAI,SAAS;AACT,mBAAW,UAAU,SAAS;AAC1B,gBAAM,QAAQ,eAAe,OAAO,KAAK,EAAE,WAAW,MAAM,CAAC,EAAE,MAAM;AAAA,QACzE;AAAA,MACJ;AAAA,IACJ,SAAS,OAAO;AACZ,UAAI,MAAM,yBAAyB,KAAK;AAAA,IAC5C;AAAA,EACJ;AACA,MAAI,cAAc,KAAK,cAAc,MAAM;AACvC,QAAI;AACA,YAAM,QAAQ,eAAe,eAAe;AAAA,QACxC,MAAM;AAAA,QACN,QAAQ;AAAA,UACJ,MAAM;AAAA,UACN,MAAM;AAAA,UACN,MAAM;AAAA,UACN,MAAM;AAAA,UACN,OAAO;AAAA,QACX;AAAA,QACA,QAAQ,CAAC;AAAA,MACb,CAAC;AAAA,IACL,SAAS,OAAO;AACZ,UAAI,MAAM,yBAAyB,KAAK;AAAA,IAC5C;AAAA,EACJ;AACA,MAAI,cAAc,KAAK,cAAc,GAAG;AACpC,eAAW,SAAS,CAAC,sBAAsB,uBAAuB,sBAAsB,GAAG;AACvF,UAAI;AACA,cAAM,aAAa,SAAS,KAAK;AAAA,MACrC,SAAS,OAAO;AACZ,YAAI,MAAM,mBAAmB,KAAK,YAAY,KAAK;AAAA,MACvD;AAAA,IACJ;AAAA,EACJ;AACA,MAAI,cAAc,KAAK,cAAc,KAAK;AACtC,UAAM,WAAW,MAAM,2BAA2B,OAAO;AACzD,QAAI;AACA,YAAM,OAAO,iBAAAA,QAAK,KAAK,UAAU,cAAc;AAC/C,UAAI,gBAAAC,QAAI,SAAS,IAAI,EAAE,OAAO,GAAG;AAC7B,cAAM,cAAc,gBAAAA,QAAI,aAAa,MAAM,MAAM;AACjD,cAAM,QAAQ,eAAe,QAAQ,WAAW,gBAAgB,WAAW;AAAA,MAC/E;AAAA,IACJ,QAAQ;AAAA,IAER;AACA,QAAI;AACA,YAAM,OAAO,iBAAAD,QAAK,KAAK,UAAU,iBAAiB;AAClD,UAAI,gBAAAC,QAAI,SAAS,IAAI,EAAE,OAAO,GAAG;AAC7B,cAAM,cAAc,gBAAAA,QAAI,aAAa,MAAM,MAAM;AACjD,cAAM,QAAQ,eAAe,QAAQ,WAAW,eAAe,WAAW;AAAA,MAC9E;AAAA,IACJ,QAAQ;AAAA,IAER;AACA,QAAI;AACA,sBAAAA,QAAI,WAAW,QAAQ;AAAA,IAC3B,QAAQ;AAAA,IAER;AACA,YAAQ,IAAI;AAAA,MACR;AAAA,IACJ;AACA,YAAQ,eAAe;AAAA,EAC3B;AACJ;AAEO,MAAM,8BAA8B,SAAU,OAAuB;AACxE,SAAO,MAAM,QAAQ,UAAU,CAAC,QAAQ,UAAU;AAC9C,WAAO,SAAS,IAAI,OAAO,YAAY,IAAI,IAAI,OAAO,YAAY,CAAC;AAAA,EACvE,CAAC;AACL;AAEO,SAAS,YAAY,KAAU,WAA4B;AAC9D,MAAI,IAAI,UAAU;AACd,UAAM,IAAI,IAAI,IAAI,SAAS,CAAC;AAC5B,QAAI,WAAW;AAAA,EACnB;AACA,MAAI,WAAW,IAAI,SAAS;AAC5B,MAAI,aAAa,SAAS,WAAW,SAAS,GAAG;AAC7C,eAAW,SAAS,MAAM,UAAU,MAAM;AAAA,EAC9C;AAEA,SAAO;AACX;",
|
|
6
6
|
"names": ["path", "fse"]
|
|
7
7
|
}
|