@softtynet/zca-js 2.3.3 → 2.3.4
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/README.md +63 -21
- package/dist/apis/auth/exportSession.d.ts +7 -0
- package/dist/apis/auth/exportSession.js +17 -0
- package/dist/apis/chat/getDirectMessageStatus.d.ts +14 -0
- package/dist/apis/chat/getDirectMessageStatus.js +52 -0
- package/dist/apis/chat/getSuggestedConversations.d.ts +5 -0
- package/dist/apis/chat/getSuggestedConversations.js +24 -0
- package/dist/apis/chat/updatePinConversations.d.ts +24 -0
- package/dist/apis/chat/updatePinConversations.js +40 -0
- package/dist/apis/friend/getFriendProfilesV2.d.ts +26 -0
- package/dist/apis/friend/getFriendProfilesV2.js +38 -0
- package/dist/apis/friend/getFriendsActivePCWeb.d.ts +6 -0
- package/dist/apis/friend/getFriendsActivePCWeb.js +15 -0
- package/dist/apis/friend/verifyFriend.d.ts +11 -0
- package/dist/apis/friend/verifyFriend.js +37 -0
- package/dist/apis/group/analyseGroup.d.ts +4 -0
- package/dist/apis/group/analyseGroup.js +28 -0
- package/dist/apis/group/checkQuotaCommunityMember.d.ts +6 -0
- package/dist/apis/group/checkQuotaCommunityMember.js +34 -0
- package/dist/apis/group/getE2eeGroupList.d.ts +7 -0
- package/dist/apis/group/getE2eeGroupList.js +15 -0
- package/dist/apis/group/getGroupCloudMessagePath.d.ts +19 -0
- package/dist/apis/group/getGroupCloudMessagePath.js +51 -0
- package/dist/apis/group/getMultiGroupCloudMessages.d.ts +5 -0
- package/dist/apis/group/getMultiGroupCloudMessages.js +29 -0
- package/dist/apis/media/getPersonalMedia.d.ts +8 -0
- package/dist/apis/media/getPersonalMedia.js +31 -0
- package/dist/apis/media/getPersonalMediaPreview.d.ts +3 -0
- package/dist/apis/media/getPersonalMediaPreview.js +24 -0
- package/dist/apis/media/removePersonalMedia.d.ts +9 -0
- package/dist/apis/media/removePersonalMedia.js +28 -0
- package/dist/apis.d.ts +45 -0
- package/dist/apis.js +75 -0
- package/dist/cjs/apis/auth/exportSession.cjs +22 -0
- package/dist/cjs/apis/chat/getDirectMessageStatus.cjs +58 -0
- package/dist/cjs/apis/chat/getSuggestedConversations.cjs +29 -0
- package/dist/cjs/apis/chat/updatePinConversations.cjs +45 -0
- package/dist/cjs/apis/friend/getFriendProfilesV2.cjs +43 -0
- package/dist/cjs/apis/friend/getFriendsActivePCWeb.cjs +20 -0
- package/dist/cjs/apis/friend/verifyFriend.cjs +42 -0
- package/dist/cjs/apis/group/analyseGroup.cjs +33 -0
- package/dist/cjs/apis/group/checkQuotaCommunityMember.cjs +39 -0
- package/dist/cjs/apis/group/getE2eeGroupList.cjs +20 -0
- package/dist/cjs/apis/group/getGroupChatHistory.cjs +8 -7
- package/dist/cjs/apis/group/getGroupCloudMessagePath.cjs +69 -0
- package/dist/cjs/apis/group/getGroupHistoryLegacy.cjs +7 -6
- package/dist/cjs/apis/group/getGroupMessageStatus.cjs +7 -6
- package/dist/cjs/apis/group/getMultiGroupCloudMessages.cjs +34 -0
- package/dist/cjs/apis/media/getPersonalMedia.cjs +36 -0
- package/dist/cjs/apis/media/getPersonalMediaPreview.cjs +29 -0
- package/dist/cjs/apis/media/removePersonalMedia.cjs +33 -0
- package/dist/cjs/apis.cjs +75 -0
- package/dist/cjs/constants/protocol.cjs +1 -1
- package/dist/cjs/context.cjs +20 -2
- package/dist/cjs/core/zcloud-client.cjs +1 -2
- package/dist/cjs/crypto/ws-cipher.cjs +66 -2
- package/dist/cjs/index.cjs +9 -2
- package/dist/cjs/realtime/listener.cjs +18 -6
- package/dist/cjs/update.cjs +10 -1
- package/dist/cjs/utils.cjs +21 -68
- package/dist/constants/protocol.d.ts +1 -1
- package/dist/constants/protocol.js +1 -1
- package/dist/context.d.ts +10 -0
- package/dist/context.js +20 -2
- package/dist/crypto/ws-cipher.d.ts +7 -0
- package/dist/crypto/ws-cipher.js +64 -2
- package/dist/index.d.ts +15 -0
- package/dist/realtime/listener.d.ts +1 -0
- package/dist/realtime/listener.js +18 -6
- package/dist/update.js +10 -1
- package/dist/utils.d.ts +0 -7
- package/dist/utils.js +15 -64
- package/index.d.ts +1 -1
- package/package.json +15 -5
package/dist/cjs/utils.cjs
CHANGED
|
@@ -15,8 +15,7 @@ var protocol = require('./constants/protocol.cjs');
|
|
|
15
15
|
var domains = require('./constants/domains.cjs');
|
|
16
16
|
var defaults = require('./constants/defaults.cjs');
|
|
17
17
|
var aes = require('./crypto/aes.cjs');
|
|
18
|
-
require('
|
|
19
|
-
require('json-bigint');
|
|
18
|
+
var wsCipher = require('./crypto/ws-cipher.cjs');
|
|
20
19
|
|
|
21
20
|
const isBun = typeof Bun !== "undefined";
|
|
22
21
|
function hasOwn(obj, key) {
|
|
@@ -166,8 +165,20 @@ async function request(ctx, url, options, raw = false) {
|
|
|
166
165
|
options = { ...(options || {}), headers: defaultHeaders };
|
|
167
166
|
}
|
|
168
167
|
}
|
|
168
|
+
const timeoutMs = ctx.options?.requestTimeout;
|
|
169
|
+
const defaultSignal = !options?.signal &&
|
|
170
|
+
typeof timeoutMs === "number" &&
|
|
171
|
+
timeoutMs > 0 &&
|
|
172
|
+
typeof AbortSignal !== "undefined" &&
|
|
173
|
+
typeof AbortSignal.timeout === "function"
|
|
174
|
+
? AbortSignal.timeout(timeoutMs)
|
|
175
|
+
: undefined;
|
|
176
|
+
const isAgentUndiciDispatcher = Boolean(ctx.options.agent && typeof ctx.options.agent.dispatch === "function");
|
|
177
|
+
const resolvedDispatcher = ctx.options.dispatcher ?? (isAgentUndiciDispatcher ? ctx.options.agent : undefined);
|
|
178
|
+
const resolvedAgent = ctx.options.agent && !isAgentUndiciDispatcher ? ctx.options.agent : undefined;
|
|
169
179
|
const _options = {
|
|
170
180
|
...(options ?? {}),
|
|
181
|
+
...(defaultSignal ? { signal: defaultSignal } : {}),
|
|
171
182
|
...(isBun
|
|
172
183
|
? {
|
|
173
184
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
@@ -175,8 +186,8 @@ async function request(ctx, url, options, raw = false) {
|
|
|
175
186
|
proxy: ctx.options.agent?.proxy?.href,
|
|
176
187
|
}
|
|
177
188
|
: {
|
|
178
|
-
agent:
|
|
179
|
-
dispatcher:
|
|
189
|
+
...(resolvedAgent ? { agent: resolvedAgent } : {}),
|
|
190
|
+
...(resolvedDispatcher ? { dispatcher: resolvedDispatcher } : {}),
|
|
180
191
|
}),
|
|
181
192
|
};
|
|
182
193
|
const response = await ctx.options.polyfill(url, _options);
|
|
@@ -452,67 +463,6 @@ function getFriendEventType(act) {
|
|
|
452
463
|
return FriendEvent.FriendEventType.PIN_CREATE;
|
|
453
464
|
return FriendEvent.FriendEventType.UNKNOWN;
|
|
454
465
|
}
|
|
455
|
-
const DEFAULT_BIGINT_ID_FIELDS = [
|
|
456
|
-
"owner_id",
|
|
457
|
-
"group_id",
|
|
458
|
-
"uidFrom",
|
|
459
|
-
"uidTo",
|
|
460
|
-
"uid",
|
|
461
|
-
"ownerId",
|
|
462
|
-
"destId",
|
|
463
|
-
"srcId",
|
|
464
|
-
"fromUid",
|
|
465
|
-
"threadId",
|
|
466
|
-
"globalMsgId",
|
|
467
|
-
"global_msg_id",
|
|
468
|
-
"globalDelMsgId",
|
|
469
|
-
"msgId",
|
|
470
|
-
"refMessageId",
|
|
471
|
-
"cliMsgId",
|
|
472
|
-
"client_msg_id",
|
|
473
|
-
"actionId",
|
|
474
|
-
"lastActionIdOther",
|
|
475
|
-
"lastActionId",
|
|
476
|
-
"resetLastActionId",
|
|
477
|
-
"lastId",
|
|
478
|
-
"ids",
|
|
479
|
-
"topicId",
|
|
480
|
-
"reminderId",
|
|
481
|
-
"eventId",
|
|
482
|
-
];
|
|
483
|
-
/**
|
|
484
|
-
* Tiền xử lý chuỗi JSON trước khi `JSON.parse` (tương đương `preParse(e, t)` trong `app.asar` của Zalo PC).
|
|
485
|
-
* Bọc dấu ngoặc kép quanh các trường định danh 64-bit (`owner_id`, `group_id`, hoặc các số nguyên >= 16 chữ số
|
|
486
|
-
* vượt quá `Number.MAX_SAFE_INTEGER`) để tránh mất 3 chữ số cuối của UID/MsgId do làm tròn IEEE-754.
|
|
487
|
-
*/
|
|
488
|
-
function preParseJsonIds(jsonStr, alwaysStringFields = ["owner_id", "group_id"], bigIntSafeFields = DEFAULT_BIGINT_ID_FIELDS) {
|
|
489
|
-
if (!jsonStr || typeof jsonStr !== "string")
|
|
490
|
-
return jsonStr;
|
|
491
|
-
const alwaysSet = new Set(alwaysStringFields);
|
|
492
|
-
const allFields = Array.from(new Set([...alwaysStringFields, ...bigIntSafeFields]));
|
|
493
|
-
if (allFields.length === 0)
|
|
494
|
-
return jsonStr;
|
|
495
|
-
const escapedKeys = allFields.map((k) => k.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
|
|
496
|
-
const keyValueRegex = new RegExp(`"(${escapedKeys})"(\\s*:\\s*)(\\d+|\\[\\s*\\d+(?:\\s*,\\s*\\d+)*\\s*\\])`, "g");
|
|
497
|
-
return jsonStr.replace(keyValueRegex, (fullMatch, key, sep, rawVal) => {
|
|
498
|
-
const forceString = alwaysSet.has(key);
|
|
499
|
-
if (rawVal.startsWith("[")) {
|
|
500
|
-
const inner = rawVal.slice(1, -1);
|
|
501
|
-
const parts = inner.split(",").map((part) => {
|
|
502
|
-
const trimmed = part.trim();
|
|
503
|
-
if (forceString || trimmed.length >= 16 || Number(trimmed) > Number.MAX_SAFE_INTEGER) {
|
|
504
|
-
return `"${trimmed}"`;
|
|
505
|
-
}
|
|
506
|
-
return trimmed;
|
|
507
|
-
});
|
|
508
|
-
return `"${key}"${sep}[${parts.join(",")}]`;
|
|
509
|
-
}
|
|
510
|
-
if (forceString || rawVal.length >= 16 || Number(rawVal) > Number.MAX_SAFE_INTEGER) {
|
|
511
|
-
return `"${key}"${sep}"${rawVal}"`;
|
|
512
|
-
}
|
|
513
|
-
return fullMatch;
|
|
514
|
-
});
|
|
515
|
-
}
|
|
516
466
|
async function handleZaloResponse(ctx, response, isEncrypted = true) {
|
|
517
467
|
const result = {
|
|
518
468
|
data: null,
|
|
@@ -542,7 +492,7 @@ async function handleZaloResponse(ctx, response, isEncrypted = true) {
|
|
|
542
492
|
result.data = {};
|
|
543
493
|
return result;
|
|
544
494
|
}
|
|
545
|
-
const safeJsonStr = isEncrypted ? preParseJsonIds(decodedStr) : null;
|
|
495
|
+
const safeJsonStr = isEncrypted ? wsCipher.preParseJsonIds(decodedStr) : null;
|
|
546
496
|
const decodedData = isEncrypted ? JSON.parse(safeJsonStr) : jsonData;
|
|
547
497
|
if (decodedData.error_code != 0) {
|
|
548
498
|
result.error = {
|
|
@@ -616,7 +566,11 @@ exports.decryptResp = aes.decryptResp;
|
|
|
616
566
|
exports.encodeAES = aes.encodeAES;
|
|
617
567
|
exports.encryptPin = aes.encryptPin;
|
|
618
568
|
exports.validatePin = aes.validatePin;
|
|
619
|
-
exports.DEFAULT_BIGINT_ID_FIELDS = DEFAULT_BIGINT_ID_FIELDS;
|
|
569
|
+
exports.DEFAULT_BIGINT_ID_FIELDS = wsCipher.DEFAULT_BIGINT_ID_FIELDS;
|
|
570
|
+
exports.decodeBase64ToBuffer = wsCipher.decodeBase64ToBuffer;
|
|
571
|
+
exports.decodeEventData = wsCipher.decodeEventData;
|
|
572
|
+
exports.decodeUnit8Array = wsCipher.decodeUnit8Array;
|
|
573
|
+
exports.preParseJsonIds = wsCipher.preParseJsonIds;
|
|
620
574
|
exports.apiFactory = apiFactory;
|
|
621
575
|
exports.formatTime = formatTime;
|
|
622
576
|
exports.generateZaloUUID = generateZaloUUID;
|
|
@@ -642,7 +596,6 @@ exports.isBun = isBun;
|
|
|
642
596
|
exports.logger = logger;
|
|
643
597
|
exports.makeURL = makeURL;
|
|
644
598
|
exports.normalizeHolderName = normalizeHolderName;
|
|
645
|
-
exports.preParseJsonIds = preParseJsonIds;
|
|
646
599
|
exports.removeUndefinedKeys = removeUndefinedKeys;
|
|
647
600
|
exports.request = request;
|
|
648
601
|
exports.resolveResponse = resolveResponse;
|
|
@@ -10,7 +10,7 @@ export declare const ZALO_PROTOCOL: {
|
|
|
10
10
|
readonly API_VERSION: 689;
|
|
11
11
|
readonly DEFAULT_API_VERSION: 689;
|
|
12
12
|
/** Phiên bản SDK hiện tại */
|
|
13
|
-
readonly SDK_VERSION: "2.3.
|
|
13
|
+
readonly SDK_VERSION: "2.3.4";
|
|
14
14
|
/** Mã zpw_type đặc thù dành riêng cho phân hệ Gọi Thoại & Video (binary C++ ZaloCall) */
|
|
15
15
|
readonly VOICECALL_API_TYPE: 24;
|
|
16
16
|
/** Phiên bản mã hóa ZCID (ParamDecryptor) */
|
|
@@ -10,7 +10,7 @@ export const ZALO_PROTOCOL = {
|
|
|
10
10
|
API_VERSION: 689,
|
|
11
11
|
DEFAULT_API_VERSION: 689,
|
|
12
12
|
/** Phiên bản SDK hiện tại */
|
|
13
|
-
SDK_VERSION: "2.3.
|
|
13
|
+
SDK_VERSION: "2.3.4",
|
|
14
14
|
/** Mã zpw_type đặc thù dành riêng cho phân hệ Gọi Thoại & Video (binary C++ ZaloCall) */
|
|
15
15
|
VOICECALL_API_TYPE: 24,
|
|
16
16
|
/** Phiên bản mã hóa ZCID (ParamDecryptor) */
|
package/dist/context.d.ts
CHANGED
|
@@ -154,18 +154,28 @@ export type Options = {
|
|
|
154
154
|
apiType: number;
|
|
155
155
|
apiVersion: number;
|
|
156
156
|
agent?: Agent;
|
|
157
|
+
/**
|
|
158
|
+
* Bộ điều phối kết nối (Undici `Dispatcher` / `ProxyAgent`) dành cho `globalThis.fetch` mặc định của Node.js 18+.
|
|
159
|
+
*/
|
|
160
|
+
dispatcher?: unknown;
|
|
157
161
|
/**
|
|
158
162
|
* Optional fetch implementation for polyfills in non-standard environments.
|
|
159
163
|
* If using proxy, `node-fetch` is highly recommended.
|
|
160
164
|
*/
|
|
161
165
|
polyfill: typeof fetch;
|
|
162
166
|
imageMetadataGetter?: ImageMetadataGetter;
|
|
167
|
+
/**
|
|
168
|
+
* Thời gian chờ tối đa cho mỗi HTTP request tính bằng mili-giây (mặc định: `30000`ms = 30s, đặt `0` để tắt).
|
|
169
|
+
*/
|
|
170
|
+
requestTimeout?: number;
|
|
163
171
|
};
|
|
164
172
|
declare class CallbacksMap extends Map<string, UploadCallback> {
|
|
173
|
+
private timers;
|
|
165
174
|
/**
|
|
166
175
|
* @param ttl Time to live in milliseconds. Default is 5 minutes.
|
|
167
176
|
*/
|
|
168
177
|
set(key: string, value: UploadCallback, ttl?: number): this;
|
|
178
|
+
delete(key: string): boolean;
|
|
169
179
|
}
|
|
170
180
|
export type ViewerKeyCacheEntry = {
|
|
171
181
|
viewer_key: string;
|
package/dist/context.js
CHANGED
|
@@ -1,15 +1,32 @@
|
|
|
1
1
|
import { ZALO_DEFAULTS, ZALO_PROTOCOL } from "./constants/index.js";
|
|
2
2
|
const _5_MINUTES = ZALO_DEFAULTS.UPLOAD.CALLBACK_TTL_MS;
|
|
3
3
|
class CallbacksMap extends Map {
|
|
4
|
+
timers = new Map();
|
|
4
5
|
/**
|
|
5
6
|
* @param ttl Time to live in milliseconds. Default is 5 minutes.
|
|
6
7
|
*/
|
|
7
8
|
set(key, value, ttl = _5_MINUTES) {
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
const existing = this.timers.get(key);
|
|
10
|
+
if (existing)
|
|
11
|
+
clearTimeout(existing);
|
|
12
|
+
const timer = setTimeout(() => {
|
|
13
|
+
this.timers.delete(key);
|
|
14
|
+
super.delete(key);
|
|
10
15
|
}, ttl);
|
|
16
|
+
if (typeof timer === "object" && timer !== null && "unref" in timer && typeof timer.unref === "function") {
|
|
17
|
+
timer.unref();
|
|
18
|
+
}
|
|
19
|
+
this.timers.set(key, timer);
|
|
11
20
|
return super.set(key, value);
|
|
12
21
|
}
|
|
22
|
+
delete(key) {
|
|
23
|
+
const existing = this.timers.get(key);
|
|
24
|
+
if (existing) {
|
|
25
|
+
clearTimeout(existing);
|
|
26
|
+
this.timers.delete(key);
|
|
27
|
+
}
|
|
28
|
+
return super.delete(key);
|
|
29
|
+
}
|
|
13
30
|
}
|
|
14
31
|
export const createContext = (apiType = ZALO_PROTOCOL.API_TYPE, apiVersion = ZALO_PROTOCOL.API_VERSION) => ({
|
|
15
32
|
API_TYPE: apiType,
|
|
@@ -20,6 +37,7 @@ export const createContext = (apiType = ZALO_PROTOCOL.API_TYPE, apiVersion = ZAL
|
|
|
20
37
|
checkUpdate: ZALO_DEFAULTS.OPTIONS.CHECK_UPDATE,
|
|
21
38
|
logging: ZALO_DEFAULTS.OPTIONS.LOGGING,
|
|
22
39
|
polyfill: global.fetch,
|
|
40
|
+
requestTimeout: 30000,
|
|
23
41
|
},
|
|
24
42
|
secretKey: null,
|
|
25
43
|
});
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
export declare const DEFAULT_BIGINT_ID_FIELDS: readonly ["owner_id", "group_id", "uidFrom", "uidTo", "uid", "ownerId", "destId", "srcId", "fromUid", "threadId", "globalMsgId", "global_msg_id", "globalDelMsgId", "msgId", "refMessageId", "cliMsgId", "client_msg_id", "actionId", "lastActionIdOther", "lastActionId", "resetLastActionId", "lastId", "ids", "topicId", "reminderId", "eventId"];
|
|
2
|
+
/**
|
|
3
|
+
* Tiền xử lý chuỗi JSON trước khi `JSON.parse` (tương đương `preParse(e, t)` trong `app.asar` của Zalo PC).
|
|
4
|
+
* Bọc dấu ngoặc kép quanh các trường định danh 64-bit (`owner_id`, `group_id`, hoặc các số nguyên >= 16 chữ số
|
|
5
|
+
* vượt quá `Number.MAX_SAFE_INTEGER`) để tránh mất 3 chữ số cuối của UID/MsgId do làm tròn IEEE-754.
|
|
6
|
+
*/
|
|
7
|
+
export declare function preParseJsonIds(jsonStr: string, alwaysStringFields?: readonly string[], bigIntSafeFields?: readonly string[]): string;
|
|
1
8
|
export declare function decodeBase64ToBuffer(data: string): Buffer;
|
|
2
9
|
export declare function decodeUnit8Array(data: Uint8Array): string | null;
|
|
3
10
|
export declare function decodeEventData(parsed: Record<string, unknown>, cipherKey?: string): Promise<any>;
|
package/dist/crypto/ws-cipher.js
CHANGED
|
@@ -2,6 +2,68 @@ import crypto from "node:crypto";
|
|
|
2
2
|
import pako from "pako";
|
|
3
3
|
import JSONBig from "json-bigint";
|
|
4
4
|
import { ZaloApiError } from "../Errors/index.js";
|
|
5
|
+
const jsonBigString = JSONBig({ storeAsString: true });
|
|
6
|
+
export const DEFAULT_BIGINT_ID_FIELDS = [
|
|
7
|
+
"owner_id",
|
|
8
|
+
"group_id",
|
|
9
|
+
"uidFrom",
|
|
10
|
+
"uidTo",
|
|
11
|
+
"uid",
|
|
12
|
+
"ownerId",
|
|
13
|
+
"destId",
|
|
14
|
+
"srcId",
|
|
15
|
+
"fromUid",
|
|
16
|
+
"threadId",
|
|
17
|
+
"globalMsgId",
|
|
18
|
+
"global_msg_id",
|
|
19
|
+
"globalDelMsgId",
|
|
20
|
+
"msgId",
|
|
21
|
+
"refMessageId",
|
|
22
|
+
"cliMsgId",
|
|
23
|
+
"client_msg_id",
|
|
24
|
+
"actionId",
|
|
25
|
+
"lastActionIdOther",
|
|
26
|
+
"lastActionId",
|
|
27
|
+
"resetLastActionId",
|
|
28
|
+
"lastId",
|
|
29
|
+
"ids",
|
|
30
|
+
"topicId",
|
|
31
|
+
"reminderId",
|
|
32
|
+
"eventId",
|
|
33
|
+
];
|
|
34
|
+
/**
|
|
35
|
+
* Tiền xử lý chuỗi JSON trước khi `JSON.parse` (tương đương `preParse(e, t)` trong `app.asar` của Zalo PC).
|
|
36
|
+
* Bọc dấu ngoặc kép quanh các trường định danh 64-bit (`owner_id`, `group_id`, hoặc các số nguyên >= 16 chữ số
|
|
37
|
+
* vượt quá `Number.MAX_SAFE_INTEGER`) để tránh mất 3 chữ số cuối của UID/MsgId do làm tròn IEEE-754.
|
|
38
|
+
*/
|
|
39
|
+
export function preParseJsonIds(jsonStr, alwaysStringFields = ["owner_id", "group_id"], bigIntSafeFields = DEFAULT_BIGINT_ID_FIELDS) {
|
|
40
|
+
if (!jsonStr || typeof jsonStr !== "string")
|
|
41
|
+
return jsonStr;
|
|
42
|
+
const alwaysSet = new Set(alwaysStringFields);
|
|
43
|
+
const allFields = Array.from(new Set([...alwaysStringFields, ...bigIntSafeFields]));
|
|
44
|
+
if (allFields.length === 0)
|
|
45
|
+
return jsonStr;
|
|
46
|
+
const escapedKeys = allFields.map((k) => k.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
|
|
47
|
+
const keyValueRegex = new RegExp(`"(${escapedKeys})"(\\s*:\\s*)(\\d+|\\[\\s*\\d+(?:\\s*,\\s*\\d+)*\\s*\\])`, "g");
|
|
48
|
+
return jsonStr.replace(keyValueRegex, (fullMatch, key, sep, rawVal) => {
|
|
49
|
+
const forceString = alwaysSet.has(key);
|
|
50
|
+
if (rawVal.startsWith("[")) {
|
|
51
|
+
const inner = rawVal.slice(1, -1);
|
|
52
|
+
const parts = inner.split(",").map((part) => {
|
|
53
|
+
const trimmed = part.trim();
|
|
54
|
+
if (forceString || trimmed.length >= 16 || Number(trimmed) > Number.MAX_SAFE_INTEGER) {
|
|
55
|
+
return `"${trimmed}"`;
|
|
56
|
+
}
|
|
57
|
+
return trimmed;
|
|
58
|
+
});
|
|
59
|
+
return `"${key}"${sep}[${parts.join(",")}]`;
|
|
60
|
+
}
|
|
61
|
+
if (forceString || rawVal.length >= 16 || Number(rawVal) > Number.MAX_SAFE_INTEGER) {
|
|
62
|
+
return `"${key}"${sep}"${rawVal}"`;
|
|
63
|
+
}
|
|
64
|
+
return fullMatch;
|
|
65
|
+
});
|
|
66
|
+
}
|
|
5
67
|
export function decodeBase64ToBuffer(data) {
|
|
6
68
|
return Buffer.from(data, "base64");
|
|
7
69
|
}
|
|
@@ -23,7 +85,7 @@ export async function decodeEventData(parsed, cipherKey) {
|
|
|
23
85
|
const rawData = parsed.data;
|
|
24
86
|
const encryptType = parsed.encrypt;
|
|
25
87
|
if (encryptType === 0)
|
|
26
|
-
return
|
|
88
|
+
return jsonBigString.parse(preParseJsonIds(rawData));
|
|
27
89
|
const decodedBuffer = decodeBase64ToBuffer(encryptType === 1 ? rawData : decodeURIComponent(rawData));
|
|
28
90
|
let decryptedBuffer = decodedBuffer;
|
|
29
91
|
if (encryptType !== 1) {
|
|
@@ -48,5 +110,5 @@ export async function decodeEventData(parsed, cipherKey) {
|
|
|
48
110
|
const decodedData = decodeUnit8Array(decompressedBuffer);
|
|
49
111
|
if (!decodedData)
|
|
50
112
|
return;
|
|
51
|
-
return
|
|
113
|
+
return jsonBigString.parse(preParseJsonIds(decodedData));
|
|
52
114
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -74,6 +74,21 @@ export type { GroupInfoPendingApprove, GroupInfoResponse } from "./apis/group/ge
|
|
|
74
74
|
export type { GetGroupInfoV2Options, GetGroupInfoV2Response } from "./apis/group/getGroupInfoV2.js";
|
|
75
75
|
export type { GetGroupListV3Options, GetGroupListV3Response } from "./apis/group/getGroupListV3.js";
|
|
76
76
|
export type { GetGroupMessageStatusQueryItem, GetGroupMessageStatusResponse, GroupMessageStatusMemberItem, GroupMessageStatusThreadInfo, } from "./apis/group/getGroupMessageStatus.js";
|
|
77
|
+
export type { CheckQuotaCommunityMemberResponse } from "./apis/group/checkQuotaCommunityMember.js";
|
|
78
|
+
export type { GetE2eeGroupListResponse } from "./apis/group/getE2eeGroupList.js";
|
|
79
|
+
export type { GetMultiGroupCloudMessagesResponse } from "./apis/group/getMultiGroupCloudMessages.js";
|
|
80
|
+
export type { GetGroupCloudMessagePathOptions, GetGroupCloudMessagePathResponse } from "./apis/group/getGroupCloudMessagePath.js";
|
|
81
|
+
export type { AnalyseGroupResponse } from "./apis/group/analyseGroup.js";
|
|
82
|
+
export type { DirectMessageStatusItem, GetDirectMessageStatusResponse } from "./apis/chat/getDirectMessageStatus.js";
|
|
83
|
+
export type { GetSuggestedConversationsResponse } from "./apis/chat/getSuggestedConversations.js";
|
|
84
|
+
export type { UpdatePinConversationsOptions, UpdatePinConversationsResponse } from "./apis/chat/updatePinConversations.js";
|
|
85
|
+
export type { GetFriendProfilesV2Options, GetFriendProfilesV2Response } from "./apis/friend/getFriendProfilesV2.js";
|
|
86
|
+
export type { GetFriendsActivePCWebResponse } from "./apis/friend/getFriendsActivePCWeb.js";
|
|
87
|
+
export type { VerifyFriendOptions, VerifyFriendResponse } from "./apis/friend/verifyFriend.js";
|
|
88
|
+
export type { GetPersonalMediaOptions } from "./apis/media/getPersonalMedia.js";
|
|
89
|
+
export type { GetPersonalMediaPreviewResponse } from "./apis/media/getPersonalMediaPreview.js";
|
|
90
|
+
export type { RemovePersonalMediaOptions, RemovePersonalMediaResponse } from "./apis/media/removePersonalMedia.js";
|
|
91
|
+
export type { ExportedSession } from "./apis/auth/exportSession.js";
|
|
77
92
|
export type { GetGroupInviteBoxInfoPayload, GetGroupInviteBoxInfoResponse } from "./apis/group/getGroupInviteBoxInfo.js";
|
|
78
93
|
export type { GetGroupInviteBoxListPayload, GetGroupInviteBoxListResponse } from "./apis/group/getGroupInviteBoxList.js";
|
|
79
94
|
export type { GetGroupLinkDetailResponse } from "./apis/group/getGroupLinkDetail.js";
|
|
@@ -27,6 +27,7 @@ export class Listener extends EventEmitter {
|
|
|
27
27
|
retryTimeout;
|
|
28
28
|
watchdogTimeout;
|
|
29
29
|
consecutive1006Count = 0;
|
|
30
|
+
isManualStop = false;
|
|
30
31
|
id = 0;
|
|
31
32
|
constructor(ctx, urls) {
|
|
32
33
|
super();
|
|
@@ -152,6 +153,7 @@ export class Listener extends EventEmitter {
|
|
|
152
153
|
logger(this.ctx).verbose(`Rotating endpoint to ${this.wsURL}`);
|
|
153
154
|
}
|
|
154
155
|
start({ retryOnClose = false } = {}) {
|
|
156
|
+
this.isManualStop = false;
|
|
155
157
|
if (this.retryTimeout) {
|
|
156
158
|
clearTimeout(this.retryTimeout);
|
|
157
159
|
this.retryTimeout = undefined;
|
|
@@ -175,6 +177,10 @@ export class Listener extends EventEmitter {
|
|
|
175
177
|
t: Date.now(),
|
|
176
178
|
});
|
|
177
179
|
const cookie = this.ctx.cookie.getCookieStringSync(ZALO_DOMAINS.CHAT_WEB);
|
|
180
|
+
const wsAgent = this.ctx.options.agent &&
|
|
181
|
+
typeof this.ctx.options.agent.dispatch !== "function"
|
|
182
|
+
? this.ctx.options.agent
|
|
183
|
+
: undefined;
|
|
178
184
|
const ws = new WebSocket(this.wsURL, {
|
|
179
185
|
headers: {
|
|
180
186
|
"accept-language": getBrowserLanguage(this.ctx.language),
|
|
@@ -189,7 +195,7 @@ export class Listener extends EventEmitter {
|
|
|
189
195
|
"user-agent": this.userAgent,
|
|
190
196
|
cookie,
|
|
191
197
|
},
|
|
192
|
-
agent:
|
|
198
|
+
...(wsAgent ? { agent: wsAgent } : {}),
|
|
193
199
|
});
|
|
194
200
|
this.ws = ws;
|
|
195
201
|
ws.onopen = () => {
|
|
@@ -202,7 +208,8 @@ export class Listener extends EventEmitter {
|
|
|
202
208
|
ws.onclose = (event) => {
|
|
203
209
|
this.reset();
|
|
204
210
|
this.emit("disconnected", event.code, event.reason);
|
|
205
|
-
const retry =
|
|
211
|
+
const retry = !this.isManualStop &&
|
|
212
|
+
retryOnClose &&
|
|
206
213
|
this.isRetryable(event.code) &&
|
|
207
214
|
this.canRetry(event.code);
|
|
208
215
|
if (retry && retryOnClose) {
|
|
@@ -288,19 +295,24 @@ export class Listener extends EventEmitter {
|
|
|
288
295
|
};
|
|
289
296
|
}
|
|
290
297
|
stop() {
|
|
291
|
-
|
|
298
|
+
this.isManualStop = true;
|
|
299
|
+
if (this.retryTimeout) {
|
|
292
300
|
clearTimeout(this.retryTimeout);
|
|
293
|
-
|
|
301
|
+
this.retryTimeout = undefined;
|
|
302
|
+
}
|
|
303
|
+
if (this.watchdogTimeout) {
|
|
294
304
|
clearTimeout(this.watchdogTimeout);
|
|
305
|
+
this.watchdogTimeout = undefined;
|
|
306
|
+
}
|
|
295
307
|
if (this.ws) {
|
|
296
|
-
if (this.ws.readyState !== WebSocket.CLOSED) {
|
|
308
|
+
if (this.ws.readyState !== WebSocket.CLOSED && this.ws.readyState !== WebSocket.CLOSING) {
|
|
297
309
|
this.ws.close(CloseReason.ManualClosure);
|
|
298
310
|
}
|
|
299
311
|
}
|
|
300
312
|
this.reset();
|
|
301
313
|
}
|
|
302
314
|
sendWs(payload, requireId = true) {
|
|
303
|
-
if (this.ws) {
|
|
315
|
+
if (this.ws && (this.ws.readyState === undefined || this.ws.readyState === WebSocket.OPEN)) {
|
|
304
316
|
if (requireId)
|
|
305
317
|
payload.data["req_id"] = `req_${this.id++}`;
|
|
306
318
|
const encodedData = new TextEncoder().encode(JSON.stringify(payload.data));
|
package/dist/update.js
CHANGED
|
@@ -6,6 +6,9 @@ const NPM_REGISTRY = ZALO_DOMAINS.NPM_REGISTRY;
|
|
|
6
6
|
export async function checkUpdate(ctx) {
|
|
7
7
|
if (!ctx.options.checkUpdate)
|
|
8
8
|
return;
|
|
9
|
+
const isAgentUndiciDispatcher = Boolean(ctx.options.agent && typeof ctx.options.agent.dispatch === "function");
|
|
10
|
+
const resolvedDispatcher = ctx.options.dispatcher ?? (isAgentUndiciDispatcher ? ctx.options.agent : undefined);
|
|
11
|
+
const resolvedAgent = ctx.options.agent && !isAgentUndiciDispatcher ? ctx.options.agent : undefined;
|
|
9
12
|
const _options = {
|
|
10
13
|
...(isBun
|
|
11
14
|
? {
|
|
@@ -13,7 +16,13 @@ export async function checkUpdate(ctx) {
|
|
|
13
16
|
// @ts-ignore
|
|
14
17
|
proxy: ctx.options.agent?.proxy?.href,
|
|
15
18
|
}
|
|
16
|
-
: {
|
|
19
|
+
: {
|
|
20
|
+
...(resolvedAgent ? { agent: resolvedAgent } : {}),
|
|
21
|
+
...(resolvedDispatcher ? { dispatcher: resolvedDispatcher } : {}),
|
|
22
|
+
}),
|
|
23
|
+
...(typeof AbortSignal !== "undefined" && typeof AbortSignal.timeout === "function"
|
|
24
|
+
? { signal: AbortSignal.timeout(3000) }
|
|
25
|
+
: {}),
|
|
17
26
|
};
|
|
18
27
|
const response = await ctx.options.polyfill(NPM_REGISTRY, _options).catch(() => null);
|
|
19
28
|
if (!response || !response.ok)
|
package/dist/utils.d.ts
CHANGED
|
@@ -112,13 +112,6 @@ export type ZaloResponse<T> = {
|
|
|
112
112
|
code?: number;
|
|
113
113
|
} | null;
|
|
114
114
|
};
|
|
115
|
-
export declare const DEFAULT_BIGINT_ID_FIELDS: readonly ["owner_id", "group_id", "uidFrom", "uidTo", "uid", "ownerId", "destId", "srcId", "fromUid", "threadId", "globalMsgId", "global_msg_id", "globalDelMsgId", "msgId", "refMessageId", "cliMsgId", "client_msg_id", "actionId", "lastActionIdOther", "lastActionId", "resetLastActionId", "lastId", "ids", "topicId", "reminderId", "eventId"];
|
|
116
|
-
/**
|
|
117
|
-
* Tiền xử lý chuỗi JSON trước khi `JSON.parse` (tương đương `preParse(e, t)` trong `app.asar` của Zalo PC).
|
|
118
|
-
* Bọc dấu ngoặc kép quanh các trường định danh 64-bit (`owner_id`, `group_id`, hoặc các số nguyên >= 16 chữ số
|
|
119
|
-
* vượt quá `Number.MAX_SAFE_INTEGER`) để tránh mất 3 chữ số cuối của UID/MsgId do làm tròn IEEE-754.
|
|
120
|
-
*/
|
|
121
|
-
export declare function preParseJsonIds(jsonStr: string, alwaysStringFields?: readonly string[], bigIntSafeFields?: readonly string[]): string;
|
|
122
115
|
export declare function handleZaloResponse<T = unknown>(ctx: ContextSession, response: Response, isEncrypted?: boolean): Promise<ZaloResponse<T>>;
|
|
123
116
|
export declare function resolveResponse<T = unknown>(ctx: ContextSession, res: Response, cb?: (result: ZaloResponse<unknown>) => T, isEncrypted?: boolean): Promise<T>;
|
|
124
117
|
export type FactoryUtils<T> = {
|
package/dist/utils.js
CHANGED
|
@@ -9,7 +9,7 @@ import { ZaloApiError, ZaloApiMissingImageMetadataGetter } from "./Errors/index.
|
|
|
9
9
|
import { FriendEventType } from "./models/FriendEvent.js";
|
|
10
10
|
import { GroupEventType } from "./models/GroupEvent.js";
|
|
11
11
|
import { ZALO_DEFAULTS, ZALO_DOMAINS, ZALO_PROTOCOL } from "./constants/index.js";
|
|
12
|
-
import { decodeAES, encodeAES } from "./crypto/index.js";
|
|
12
|
+
import { decodeAES, encodeAES, preParseJsonIds } from "./crypto/index.js";
|
|
13
13
|
export * from "./constants/index.js";
|
|
14
14
|
export * from "./crypto/index.js";
|
|
15
15
|
export * from "./core/index.js";
|
|
@@ -161,8 +161,20 @@ export async function request(ctx, url, options, raw = false) {
|
|
|
161
161
|
options = { ...(options || {}), headers: defaultHeaders };
|
|
162
162
|
}
|
|
163
163
|
}
|
|
164
|
+
const timeoutMs = ctx.options?.requestTimeout;
|
|
165
|
+
const defaultSignal = !options?.signal &&
|
|
166
|
+
typeof timeoutMs === "number" &&
|
|
167
|
+
timeoutMs > 0 &&
|
|
168
|
+
typeof AbortSignal !== "undefined" &&
|
|
169
|
+
typeof AbortSignal.timeout === "function"
|
|
170
|
+
? AbortSignal.timeout(timeoutMs)
|
|
171
|
+
: undefined;
|
|
172
|
+
const isAgentUndiciDispatcher = Boolean(ctx.options.agent && typeof ctx.options.agent.dispatch === "function");
|
|
173
|
+
const resolvedDispatcher = ctx.options.dispatcher ?? (isAgentUndiciDispatcher ? ctx.options.agent : undefined);
|
|
174
|
+
const resolvedAgent = ctx.options.agent && !isAgentUndiciDispatcher ? ctx.options.agent : undefined;
|
|
164
175
|
const _options = {
|
|
165
176
|
...(options ?? {}),
|
|
177
|
+
...(defaultSignal ? { signal: defaultSignal } : {}),
|
|
166
178
|
...(isBun
|
|
167
179
|
? {
|
|
168
180
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
@@ -170,8 +182,8 @@ export async function request(ctx, url, options, raw = false) {
|
|
|
170
182
|
proxy: ctx.options.agent?.proxy?.href,
|
|
171
183
|
}
|
|
172
184
|
: {
|
|
173
|
-
agent:
|
|
174
|
-
dispatcher:
|
|
185
|
+
...(resolvedAgent ? { agent: resolvedAgent } : {}),
|
|
186
|
+
...(resolvedDispatcher ? { dispatcher: resolvedDispatcher } : {}),
|
|
175
187
|
}),
|
|
176
188
|
};
|
|
177
189
|
const response = await ctx.options.polyfill(url, _options);
|
|
@@ -447,67 +459,6 @@ export function getFriendEventType(act) {
|
|
|
447
459
|
return FriendEventType.PIN_CREATE;
|
|
448
460
|
return FriendEventType.UNKNOWN;
|
|
449
461
|
}
|
|
450
|
-
export const DEFAULT_BIGINT_ID_FIELDS = [
|
|
451
|
-
"owner_id",
|
|
452
|
-
"group_id",
|
|
453
|
-
"uidFrom",
|
|
454
|
-
"uidTo",
|
|
455
|
-
"uid",
|
|
456
|
-
"ownerId",
|
|
457
|
-
"destId",
|
|
458
|
-
"srcId",
|
|
459
|
-
"fromUid",
|
|
460
|
-
"threadId",
|
|
461
|
-
"globalMsgId",
|
|
462
|
-
"global_msg_id",
|
|
463
|
-
"globalDelMsgId",
|
|
464
|
-
"msgId",
|
|
465
|
-
"refMessageId",
|
|
466
|
-
"cliMsgId",
|
|
467
|
-
"client_msg_id",
|
|
468
|
-
"actionId",
|
|
469
|
-
"lastActionIdOther",
|
|
470
|
-
"lastActionId",
|
|
471
|
-
"resetLastActionId",
|
|
472
|
-
"lastId",
|
|
473
|
-
"ids",
|
|
474
|
-
"topicId",
|
|
475
|
-
"reminderId",
|
|
476
|
-
"eventId",
|
|
477
|
-
];
|
|
478
|
-
/**
|
|
479
|
-
* Tiền xử lý chuỗi JSON trước khi `JSON.parse` (tương đương `preParse(e, t)` trong `app.asar` của Zalo PC).
|
|
480
|
-
* Bọc dấu ngoặc kép quanh các trường định danh 64-bit (`owner_id`, `group_id`, hoặc các số nguyên >= 16 chữ số
|
|
481
|
-
* vượt quá `Number.MAX_SAFE_INTEGER`) để tránh mất 3 chữ số cuối của UID/MsgId do làm tròn IEEE-754.
|
|
482
|
-
*/
|
|
483
|
-
export function preParseJsonIds(jsonStr, alwaysStringFields = ["owner_id", "group_id"], bigIntSafeFields = DEFAULT_BIGINT_ID_FIELDS) {
|
|
484
|
-
if (!jsonStr || typeof jsonStr !== "string")
|
|
485
|
-
return jsonStr;
|
|
486
|
-
const alwaysSet = new Set(alwaysStringFields);
|
|
487
|
-
const allFields = Array.from(new Set([...alwaysStringFields, ...bigIntSafeFields]));
|
|
488
|
-
if (allFields.length === 0)
|
|
489
|
-
return jsonStr;
|
|
490
|
-
const escapedKeys = allFields.map((k) => k.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
|
|
491
|
-
const keyValueRegex = new RegExp(`"(${escapedKeys})"(\\s*:\\s*)(\\d+|\\[\\s*\\d+(?:\\s*,\\s*\\d+)*\\s*\\])`, "g");
|
|
492
|
-
return jsonStr.replace(keyValueRegex, (fullMatch, key, sep, rawVal) => {
|
|
493
|
-
const forceString = alwaysSet.has(key);
|
|
494
|
-
if (rawVal.startsWith("[")) {
|
|
495
|
-
const inner = rawVal.slice(1, -1);
|
|
496
|
-
const parts = inner.split(",").map((part) => {
|
|
497
|
-
const trimmed = part.trim();
|
|
498
|
-
if (forceString || trimmed.length >= 16 || Number(trimmed) > Number.MAX_SAFE_INTEGER) {
|
|
499
|
-
return `"${trimmed}"`;
|
|
500
|
-
}
|
|
501
|
-
return trimmed;
|
|
502
|
-
});
|
|
503
|
-
return `"${key}"${sep}[${parts.join(",")}]`;
|
|
504
|
-
}
|
|
505
|
-
if (forceString || rawVal.length >= 16 || Number(rawVal) > Number.MAX_SAFE_INTEGER) {
|
|
506
|
-
return `"${key}"${sep}"${rawVal}"`;
|
|
507
|
-
}
|
|
508
|
-
return fullMatch;
|
|
509
|
-
});
|
|
510
|
-
}
|
|
511
462
|
export async function handleZaloResponse(ctx, response, isEncrypted = true) {
|
|
512
463
|
const result = {
|
|
513
464
|
data: null,
|
package/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export * from "./dist";
|
|
1
|
+
export * from "./dist/index.js";
|
|
2
2
|
export as namespace Zalo;
|
package/package.json
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@softtynet/zca-js",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.4",
|
|
4
4
|
"description": "Zalo API client library for Node.js and Bun, maintained by Softtynet.",
|
|
5
|
-
"main": "dist/index.
|
|
5
|
+
"main": "dist/cjs/index.cjs",
|
|
6
|
+
"module": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
6
8
|
"type": "module",
|
|
7
9
|
"files": [
|
|
8
10
|
"dist",
|
|
@@ -12,8 +14,9 @@
|
|
|
12
14
|
],
|
|
13
15
|
"exports": {
|
|
14
16
|
".": {
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"import": "./dist/index.js",
|
|
15
19
|
"require": "./dist/cjs/index.cjs",
|
|
16
|
-
"types": "./index.d.ts",
|
|
17
20
|
"default": "./dist/index.js"
|
|
18
21
|
}
|
|
19
22
|
},
|
|
@@ -23,8 +26,14 @@
|
|
|
23
26
|
"build:esm": "tsc",
|
|
24
27
|
"build:cjs": "rollup -c rollup.config.js",
|
|
25
28
|
"build": "npm run build:clean && npm run build:esm && npm run build:cjs",
|
|
26
|
-
"
|
|
29
|
+
"typecheck": "tsc --noEmit && tsc -p test/tsconfig.json --noEmit && tsc -p examples/tsconfig.json --noEmit && tsc -p docs/tsconfig.json --noEmit",
|
|
30
|
+
"test:verify": "npm run typecheck && npx --yes tsx test/verify_upgrades.ts",
|
|
27
31
|
"test:live": "npx --yes tsx test/verify_live.ts",
|
|
32
|
+
"docs:gen": "node scripts/generateDocs.js",
|
|
33
|
+
"docs:dev": "node scripts/generateDocs.js && vitepress dev docs",
|
|
34
|
+
"docs:build": "node scripts/generateDocs.js && vitepress build docs",
|
|
35
|
+
"docs:preview": "vitepress preview docs",
|
|
36
|
+
"docs:deploy": "node scripts/deployDocs.js",
|
|
28
37
|
"prettier": "prettier --write .",
|
|
29
38
|
"lint": "eslint .",
|
|
30
39
|
"lint:fix": "eslint . --fix",
|
|
@@ -79,7 +88,8 @@
|
|
|
79
88
|
"rimraf": "^5.0.10",
|
|
80
89
|
"rollup": "^4.24.0",
|
|
81
90
|
"typescript": "^5.5.3",
|
|
82
|
-
"typescript-eslint": "^8.41.0"
|
|
91
|
+
"typescript-eslint": "^8.41.0",
|
|
92
|
+
"vitepress": "^1.6.4"
|
|
83
93
|
},
|
|
84
94
|
"lint-staged": {
|
|
85
95
|
"*.{js,ts}": "eslint"
|