openzca 0.1.56 → 0.1.57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +286 -60
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -3291,6 +3291,125 @@ function inferReplyMessageThreadId(params) {
|
|
|
3291
3291
|
return void 0;
|
|
3292
3292
|
}
|
|
3293
3293
|
|
|
3294
|
+
// src/lib/adaptive-batch.ts
|
|
3295
|
+
var RETRYABLE_LOOKUP_ERROR_PATTERNS = [
|
|
3296
|
+
/retry limit/i,
|
|
3297
|
+
/\brate limit/i,
|
|
3298
|
+
/\btoo many requests?\b/i,
|
|
3299
|
+
/\btimeout\b/i,
|
|
3300
|
+
/\btimed out\b/i,
|
|
3301
|
+
/\betimedout\b/i,
|
|
3302
|
+
/\beconnreset\b/i,
|
|
3303
|
+
/\besockettimedout\b/i,
|
|
3304
|
+
/\bsocket hang up\b/i,
|
|
3305
|
+
/\btemporar(?:y|ily)\b/i
|
|
3306
|
+
];
|
|
3307
|
+
var SPLITTABLE_LOOKUP_ERROR_PATTERNS = [
|
|
3308
|
+
/\binvalid param(?:eter)?s?\b/i,
|
|
3309
|
+
/\binvalid request\b/i,
|
|
3310
|
+
/\bbad request\b/i,
|
|
3311
|
+
/tham so khong hop le/i,
|
|
3312
|
+
/tham số không hợp lệ/i
|
|
3313
|
+
];
|
|
3314
|
+
function sleep2(ms) {
|
|
3315
|
+
return new Promise((resolve) => {
|
|
3316
|
+
setTimeout(resolve, ms);
|
|
3317
|
+
});
|
|
3318
|
+
}
|
|
3319
|
+
function chunkKeys(keys, size) {
|
|
3320
|
+
const chunkSize = Math.max(1, Math.trunc(size) || 1);
|
|
3321
|
+
const chunks = [];
|
|
3322
|
+
for (let index = 0; index < keys.length; index += chunkSize) {
|
|
3323
|
+
chunks.push(keys.slice(index, index + chunkSize));
|
|
3324
|
+
}
|
|
3325
|
+
return chunks;
|
|
3326
|
+
}
|
|
3327
|
+
function toErrorText(error) {
|
|
3328
|
+
return error instanceof Error ? error.message : String(error);
|
|
3329
|
+
}
|
|
3330
|
+
function isRetryableLookupError(error) {
|
|
3331
|
+
const message = toErrorText(error);
|
|
3332
|
+
return RETRYABLE_LOOKUP_ERROR_PATTERNS.some((pattern) => pattern.test(message));
|
|
3333
|
+
}
|
|
3334
|
+
function isSplittableLookupError(error) {
|
|
3335
|
+
const message = toErrorText(error);
|
|
3336
|
+
return SPLITTABLE_LOOKUP_ERROR_PATTERNS.some((pattern) => pattern.test(message));
|
|
3337
|
+
}
|
|
3338
|
+
async function runAdaptiveBatch(keys, options) {
|
|
3339
|
+
const maxRetries = Math.max(0, options.maxRetries ?? 2);
|
|
3340
|
+
const initialDelayMs = Math.max(0, options.retryDelayMs ?? 400);
|
|
3341
|
+
const backoffMultiplier = Math.max(1, options.backoffMultiplier ?? 2);
|
|
3342
|
+
const shouldRetry = options.shouldRetry ?? isRetryableLookupError;
|
|
3343
|
+
const shouldSplit = options.shouldSplit ?? isSplittableLookupError;
|
|
3344
|
+
let attempt = 0;
|
|
3345
|
+
let delayMs = initialDelayMs;
|
|
3346
|
+
while (true) {
|
|
3347
|
+
try {
|
|
3348
|
+
return await options.fetchBatch(keys) ?? {};
|
|
3349
|
+
} catch (error) {
|
|
3350
|
+
if (keys.length > 1 && shouldSplit(error)) {
|
|
3351
|
+
throw error;
|
|
3352
|
+
}
|
|
3353
|
+
attempt += 1;
|
|
3354
|
+
if (attempt > maxRetries || !shouldRetry(error)) {
|
|
3355
|
+
throw error;
|
|
3356
|
+
}
|
|
3357
|
+
await options.onRetry?.({
|
|
3358
|
+
keys: [...keys],
|
|
3359
|
+
attempt,
|
|
3360
|
+
maxRetries,
|
|
3361
|
+
delayMs,
|
|
3362
|
+
error
|
|
3363
|
+
});
|
|
3364
|
+
if (delayMs > 0) {
|
|
3365
|
+
await sleep2(delayMs);
|
|
3366
|
+
}
|
|
3367
|
+
delayMs = Math.max(delayMs * backoffMultiplier, delayMs + 1);
|
|
3368
|
+
}
|
|
3369
|
+
}
|
|
3370
|
+
}
|
|
3371
|
+
async function fetchAdaptiveObjectBatches(keys, options) {
|
|
3372
|
+
const uniqueKeys = Array.from(new Set(keys.map((value) => value.trim()).filter(Boolean)));
|
|
3373
|
+
const pending = chunkKeys(uniqueKeys, options.initialBatchSize ?? 5);
|
|
3374
|
+
const values = /* @__PURE__ */ new Map();
|
|
3375
|
+
const errors = [];
|
|
3376
|
+
const shouldRetry = options.shouldRetry ?? isRetryableLookupError;
|
|
3377
|
+
const shouldSplit = options.shouldSplit ?? isSplittableLookupError;
|
|
3378
|
+
const continueOnItemError = options.continueOnItemError ?? true;
|
|
3379
|
+
const batchDelayMs = Math.max(0, options.batchDelayMs ?? 75);
|
|
3380
|
+
while (pending.length > 0) {
|
|
3381
|
+
const batch = pending.shift();
|
|
3382
|
+
if (!batch || batch.length === 0) {
|
|
3383
|
+
continue;
|
|
3384
|
+
}
|
|
3385
|
+
try {
|
|
3386
|
+
const result = await runAdaptiveBatch(batch, options);
|
|
3387
|
+
for (const key of batch) {
|
|
3388
|
+
const value = result[key];
|
|
3389
|
+
if (value !== void 0) {
|
|
3390
|
+
values.set(key, value);
|
|
3391
|
+
}
|
|
3392
|
+
}
|
|
3393
|
+
} catch (error) {
|
|
3394
|
+
if (batch.length > 1 && (shouldSplit(error) || shouldRetry(error))) {
|
|
3395
|
+
pending.unshift(...chunkKeys(batch, Math.ceil(batch.length / 2)));
|
|
3396
|
+
continue;
|
|
3397
|
+
}
|
|
3398
|
+
if (!continueOnItemError || batch.length > 1) {
|
|
3399
|
+
throw error;
|
|
3400
|
+
}
|
|
3401
|
+
const itemError = { key: batch[0], error };
|
|
3402
|
+
errors.push(itemError);
|
|
3403
|
+
await options.onItemError?.(itemError);
|
|
3404
|
+
continue;
|
|
3405
|
+
}
|
|
3406
|
+
if (batchDelayMs > 0 && pending.length > 0) {
|
|
3407
|
+
await sleep2(batchDelayMs);
|
|
3408
|
+
}
|
|
3409
|
+
}
|
|
3410
|
+
return { values, errors };
|
|
3411
|
+
}
|
|
3412
|
+
|
|
3294
3413
|
// src/cli.ts
|
|
3295
3414
|
var require3 = createRequire2(import.meta.url);
|
|
3296
3415
|
var { version: PKG_VERSION } = require3("../package.json");
|
|
@@ -3532,6 +3651,44 @@ function retrySendMethod(operation, command, metaBuilder) {
|
|
|
3532
3651
|
}
|
|
3533
3652
|
});
|
|
3534
3653
|
}
|
|
3654
|
+
var LOOKUP_BATCH_SIZE = 5;
|
|
3655
|
+
var LOOKUP_RETRY_COUNT = 2;
|
|
3656
|
+
var LOOKUP_RETRY_DELAY_MS = 400;
|
|
3657
|
+
var LOOKUP_BATCH_DELAY_MS = 75;
|
|
3658
|
+
async function fetchGroupInfoRecords(api, groupIds) {
|
|
3659
|
+
const { values } = await fetchAdaptiveObjectBatches(groupIds, {
|
|
3660
|
+
fetchBatch: async (keys) => {
|
|
3661
|
+
const response = await api.getGroupInfo(keys);
|
|
3662
|
+
return response.gridInfoMap ?? {};
|
|
3663
|
+
},
|
|
3664
|
+
initialBatchSize: LOOKUP_BATCH_SIZE,
|
|
3665
|
+
maxRetries: LOOKUP_RETRY_COUNT,
|
|
3666
|
+
retryDelayMs: LOOKUP_RETRY_DELAY_MS,
|
|
3667
|
+
batchDelayMs: LOOKUP_BATCH_DELAY_MS
|
|
3668
|
+
});
|
|
3669
|
+
return values;
|
|
3670
|
+
}
|
|
3671
|
+
async function fetchGroupInfoRecord(api, groupId) {
|
|
3672
|
+
const groups = await fetchGroupInfoRecords(api, [groupId]);
|
|
3673
|
+
const group2 = groups.get(groupId);
|
|
3674
|
+
if (!group2) {
|
|
3675
|
+
throw new Error(`Group not found: ${groupId}`);
|
|
3676
|
+
}
|
|
3677
|
+
return group2;
|
|
3678
|
+
}
|
|
3679
|
+
async function fetchGroupMemberProfiles(api, memberIds) {
|
|
3680
|
+
const { values } = await fetchAdaptiveObjectBatches(memberIds, {
|
|
3681
|
+
fetchBatch: async (keys) => {
|
|
3682
|
+
const response = await api.getGroupMembersInfo(keys);
|
|
3683
|
+
return response.profiles ?? {};
|
|
3684
|
+
},
|
|
3685
|
+
initialBatchSize: LOOKUP_BATCH_SIZE,
|
|
3686
|
+
maxRetries: LOOKUP_RETRY_COUNT,
|
|
3687
|
+
retryDelayMs: LOOKUP_RETRY_DELAY_MS,
|
|
3688
|
+
batchDelayMs: LOOKUP_BATCH_DELAY_MS
|
|
3689
|
+
});
|
|
3690
|
+
return values;
|
|
3691
|
+
}
|
|
3535
3692
|
function isProcessAlive(pid) {
|
|
3536
3693
|
if (!Number.isInteger(pid) || pid <= 0) return false;
|
|
3537
3694
|
try {
|
|
@@ -3737,7 +3894,7 @@ async function startListenerIpcServer(api, profile, sessionId, command) {
|
|
|
3737
3894
|
command
|
|
3738
3895
|
);
|
|
3739
3896
|
} catch (error) {
|
|
3740
|
-
fail(parsed.requestId,
|
|
3897
|
+
fail(parsed.requestId, toErrorText2(error));
|
|
3741
3898
|
writeDebugLine(
|
|
3742
3899
|
"listen.ipc.upload.error",
|
|
3743
3900
|
{
|
|
@@ -3746,7 +3903,7 @@ async function startListenerIpcServer(api, profile, sessionId, command) {
|
|
|
3746
3903
|
requestId: parsed.requestId,
|
|
3747
3904
|
threadId: parsed.threadId,
|
|
3748
3905
|
threadType: parsed.threadType,
|
|
3749
|
-
message:
|
|
3906
|
+
message: toErrorText2(error)
|
|
3750
3907
|
},
|
|
3751
3908
|
command
|
|
3752
3909
|
);
|
|
@@ -3775,7 +3932,7 @@ async function startListenerIpcServer(api, profile, sessionId, command) {
|
|
|
3775
3932
|
{
|
|
3776
3933
|
profile,
|
|
3777
3934
|
sessionId,
|
|
3778
|
-
message:
|
|
3935
|
+
message: toErrorText2(error)
|
|
3779
3936
|
},
|
|
3780
3937
|
command
|
|
3781
3938
|
);
|
|
@@ -3787,7 +3944,7 @@ async function startListenerIpcServer(api, profile, sessionId, command) {
|
|
|
3787
3944
|
{
|
|
3788
3945
|
profile,
|
|
3789
3946
|
sessionId,
|
|
3790
|
-
message:
|
|
3947
|
+
message: toErrorText2(error)
|
|
3791
3948
|
},
|
|
3792
3949
|
command
|
|
3793
3950
|
);
|
|
@@ -3976,7 +4133,7 @@ async function resolveUploadThreadType(api, profile, threadId, groupFlag, comman
|
|
|
3976
4133
|
{
|
|
3977
4134
|
profile,
|
|
3978
4135
|
threadId,
|
|
3979
|
-
message:
|
|
4136
|
+
message: toErrorText2(error)
|
|
3980
4137
|
},
|
|
3981
4138
|
command
|
|
3982
4139
|
);
|
|
@@ -4001,7 +4158,7 @@ async function resolveUploadThreadType(api, profile, threadId, groupFlag, comman
|
|
|
4001
4158
|
{
|
|
4002
4159
|
profile,
|
|
4003
4160
|
threadId,
|
|
4004
|
-
message:
|
|
4161
|
+
message: toErrorText2(error)
|
|
4005
4162
|
},
|
|
4006
4163
|
command
|
|
4007
4164
|
);
|
|
@@ -4242,8 +4399,8 @@ async function persistOutgoingMessageBestEffort(params) {
|
|
|
4242
4399
|
});
|
|
4243
4400
|
}
|
|
4244
4401
|
}
|
|
4245
|
-
async function persistGroupMembersSnapshot(profile, groupId, api) {
|
|
4246
|
-
const rows = await listGroupMemberRows(api, groupId);
|
|
4402
|
+
async function persistGroupMembersSnapshot(profile, groupId, api, groupInfo) {
|
|
4403
|
+
const rows = await listGroupMemberRows(api, groupId, groupInfo);
|
|
4247
4404
|
const snapshotAtMs = Date.now();
|
|
4248
4405
|
for (const row of rows) {
|
|
4249
4406
|
await persistContact({
|
|
@@ -4448,7 +4605,15 @@ async function prepareDbGroupTarget(params) {
|
|
|
4448
4605
|
isHidden: params.hiddenIds.has(params.groupId),
|
|
4449
4606
|
rawJson: params.rawJson
|
|
4450
4607
|
});
|
|
4451
|
-
|
|
4608
|
+
if (params.hydrateMembers === false) {
|
|
4609
|
+
return {};
|
|
4610
|
+
}
|
|
4611
|
+
try {
|
|
4612
|
+
await persistGroupMembersSnapshot(params.profile, params.groupId, params.api, params.group);
|
|
4613
|
+
return {};
|
|
4614
|
+
} catch (error) {
|
|
4615
|
+
return { memberSnapshotError: toErrorText2(error) };
|
|
4616
|
+
}
|
|
4452
4617
|
}
|
|
4453
4618
|
function resolveContactDisplayName(params) {
|
|
4454
4619
|
return params.displayName?.trim() || params.zaloName?.trim() || params.fallbackTitle?.trim() || params.userId.trim() || void 0;
|
|
@@ -4550,18 +4715,17 @@ async function hydrateUnknownLiveGroup(params) {
|
|
|
4550
4715
|
}
|
|
4551
4716
|
}
|
|
4552
4717
|
if (group2 || title) {
|
|
4553
|
-
await
|
|
4718
|
+
await prepareDbGroupTarget({
|
|
4554
4719
|
profile: params.profile,
|
|
4555
|
-
|
|
4556
|
-
|
|
4557
|
-
|
|
4720
|
+
api: params.api,
|
|
4721
|
+
groupId: params.groupId,
|
|
4722
|
+
group: group2,
|
|
4558
4723
|
title,
|
|
4559
|
-
rawJson: group2 ? JSON.stringify(group2) : void 0
|
|
4724
|
+
rawJson: group2 ? JSON.stringify(group2) : void 0,
|
|
4725
|
+
pinnedIds: /* @__PURE__ */ new Set(),
|
|
4726
|
+
hiddenIds: /* @__PURE__ */ new Set(),
|
|
4727
|
+
hydrateMembers: Boolean(group2)
|
|
4560
4728
|
});
|
|
4561
|
-
try {
|
|
4562
|
-
await persistGroupMembersSnapshot(params.profile, params.groupId, params.api);
|
|
4563
|
-
} catch {
|
|
4564
|
-
}
|
|
4565
4729
|
return;
|
|
4566
4730
|
}
|
|
4567
4731
|
if (params.fallbackTitle?.trim()) {
|
|
@@ -4631,16 +4795,23 @@ async function syncDbGroupHistoryFull(params) {
|
|
|
4631
4795
|
pagesRequested = result.pagesRequested;
|
|
4632
4796
|
listenerImportedCount = await getStoredGroupMessageCount() - beforeCount;
|
|
4633
4797
|
} catch (error) {
|
|
4634
|
-
stopReason = `fallback_window:${
|
|
4798
|
+
stopReason = `fallback_window:${toErrorText2(error)}`;
|
|
4635
4799
|
completeness = "window";
|
|
4636
4800
|
}
|
|
4637
4801
|
const fallbackCount = 200;
|
|
4638
4802
|
params.progress?.(`merging recent group API window (${fallbackCount} per group)`);
|
|
4639
4803
|
const beforeApiCount = await getStoredGroupMessageCount();
|
|
4804
|
+
const topoffErrors = [];
|
|
4640
4805
|
for (const groupId of params.targetGroupIds) {
|
|
4641
|
-
|
|
4642
|
-
|
|
4643
|
-
|
|
4806
|
+
try {
|
|
4807
|
+
const messages = await fetchRecentGroupMessagesViaApi(params.api, groupId, fallbackCount);
|
|
4808
|
+
await persistMessages(messages);
|
|
4809
|
+
params.progress?.(`group ${groupId}: fetched ${messages.length} message(s) from group history API`);
|
|
4810
|
+
} catch (error) {
|
|
4811
|
+
const message = toErrorText2(error);
|
|
4812
|
+
topoffErrors.push({ groupId, error: message });
|
|
4813
|
+
params.progress?.(`group ${groupId}: group history API skipped (${message})`);
|
|
4814
|
+
}
|
|
4644
4815
|
}
|
|
4645
4816
|
const afterCount = await getStoredGroupMessageCount();
|
|
4646
4817
|
const apiAddedCount = afterCount - beforeApiCount;
|
|
@@ -4670,7 +4841,8 @@ async function syncDbGroupHistoryFull(params) {
|
|
|
4670
4841
|
imported,
|
|
4671
4842
|
completeness,
|
|
4672
4843
|
stopReason,
|
|
4673
|
-
pagesRequested
|
|
4844
|
+
pagesRequested,
|
|
4845
|
+
topoffErrors
|
|
4674
4846
|
});
|
|
4675
4847
|
}
|
|
4676
4848
|
async function syncDbFriendDirectory(params) {
|
|
@@ -4807,25 +4979,70 @@ async function runDbSync(params) {
|
|
|
4807
4979
|
});
|
|
4808
4980
|
}
|
|
4809
4981
|
if (params.mode === "all" || params.mode === "groups") {
|
|
4810
|
-
const groups = await
|
|
4982
|
+
const groups = await api.getAllGroups();
|
|
4983
|
+
const groupIds = Object.keys(groups.gridVerMap ?? {});
|
|
4811
4984
|
const targetGroupIds = /* @__PURE__ */ new Set();
|
|
4812
4985
|
const titleById = /* @__PURE__ */ new Map();
|
|
4813
|
-
|
|
4814
|
-
|
|
4815
|
-
|
|
4816
|
-
|
|
4817
|
-
|
|
4818
|
-
|
|
4819
|
-
|
|
4820
|
-
|
|
4821
|
-
|
|
4822
|
-
|
|
4823
|
-
|
|
4824
|
-
|
|
4825
|
-
|
|
4826
|
-
|
|
4827
|
-
|
|
4828
|
-
|
|
4986
|
+
params.progress?.(`syncing group directory for ${groupIds.length} group(s)`);
|
|
4987
|
+
for (const groupId of groupIds) {
|
|
4988
|
+
let group2;
|
|
4989
|
+
let title;
|
|
4990
|
+
try {
|
|
4991
|
+
try {
|
|
4992
|
+
group2 = await fetchGroupInfoRecord(api, groupId);
|
|
4993
|
+
title = extractGroupTitle(group2);
|
|
4994
|
+
} catch (error) {
|
|
4995
|
+
const message = toErrorText2(error);
|
|
4996
|
+
params.progress?.(`group ${groupId}: metadata unavailable (${message}), continuing`);
|
|
4997
|
+
summary.syncState.push({
|
|
4998
|
+
kind: "group",
|
|
4999
|
+
groupId,
|
|
5000
|
+
status: "warning",
|
|
5001
|
+
stage: "metadata",
|
|
5002
|
+
error: message
|
|
5003
|
+
});
|
|
5004
|
+
}
|
|
5005
|
+
const { memberSnapshotError } = await prepareDbGroupTarget({
|
|
5006
|
+
profile,
|
|
5007
|
+
api,
|
|
5008
|
+
groupId,
|
|
5009
|
+
group: group2,
|
|
5010
|
+
title,
|
|
5011
|
+
rawJson: group2 ? JSON.stringify(group2) : void 0,
|
|
5012
|
+
pinnedIds,
|
|
5013
|
+
hiddenIds,
|
|
5014
|
+
hydrateMembers: Boolean(group2)
|
|
5015
|
+
});
|
|
5016
|
+
if (memberSnapshotError) {
|
|
5017
|
+
params.progress?.(`group ${groupId}: member snapshot unavailable (${memberSnapshotError}), continuing`);
|
|
5018
|
+
summary.syncState.push({
|
|
5019
|
+
kind: "group",
|
|
5020
|
+
groupId,
|
|
5021
|
+
status: "warning",
|
|
5022
|
+
stage: "members",
|
|
5023
|
+
error: memberSnapshotError
|
|
5024
|
+
});
|
|
5025
|
+
}
|
|
5026
|
+
targetGroupIds.add(groupId);
|
|
5027
|
+
titleById.set(groupId, title);
|
|
5028
|
+
} catch (error) {
|
|
5029
|
+
const message = toErrorText2(error);
|
|
5030
|
+
params.progress?.(`group ${groupId}: skipped (${message})`);
|
|
5031
|
+
await setSyncState({
|
|
5032
|
+
profile,
|
|
5033
|
+
scopeThreadId: groupId,
|
|
5034
|
+
threadType: "group",
|
|
5035
|
+
status: "error",
|
|
5036
|
+
error: message
|
|
5037
|
+
});
|
|
5038
|
+
summary.syncState.push({
|
|
5039
|
+
kind: "group",
|
|
5040
|
+
groupId,
|
|
5041
|
+
status: "error",
|
|
5042
|
+
stage: "prepare",
|
|
5043
|
+
error: message
|
|
5044
|
+
});
|
|
5045
|
+
}
|
|
4829
5046
|
}
|
|
4830
5047
|
await syncDbGroupHistoryFull({
|
|
4831
5048
|
profile,
|
|
@@ -4841,18 +5058,29 @@ async function runDbSync(params) {
|
|
|
4841
5058
|
if (!params.groupId) {
|
|
4842
5059
|
throw new Error("Missing group id for db sync group.");
|
|
4843
5060
|
}
|
|
4844
|
-
const
|
|
4845
|
-
const
|
|
4846
|
-
const
|
|
4847
|
-
await prepareDbGroupTarget({
|
|
5061
|
+
const group2 = await fetchGroupInfoRecord(api, params.groupId);
|
|
5062
|
+
const title = extractGroupTitle(group2);
|
|
5063
|
+
const { memberSnapshotError } = await prepareDbGroupTarget({
|
|
4848
5064
|
profile,
|
|
4849
5065
|
api,
|
|
4850
5066
|
groupId: params.groupId,
|
|
5067
|
+
group: group2,
|
|
4851
5068
|
title,
|
|
4852
5069
|
rawJson: group2 ? JSON.stringify(group2) : void 0,
|
|
4853
5070
|
pinnedIds,
|
|
4854
|
-
hiddenIds
|
|
5071
|
+
hiddenIds,
|
|
5072
|
+
hydrateMembers: Boolean(group2)
|
|
4855
5073
|
});
|
|
5074
|
+
if (memberSnapshotError) {
|
|
5075
|
+
params.progress?.(`group ${params.groupId}: member snapshot unavailable (${memberSnapshotError}), continuing`);
|
|
5076
|
+
summary.syncState.push({
|
|
5077
|
+
kind: "group",
|
|
5078
|
+
groupId: params.groupId,
|
|
5079
|
+
status: "warning",
|
|
5080
|
+
stage: "members",
|
|
5081
|
+
error: memberSnapshotError
|
|
5082
|
+
});
|
|
5083
|
+
}
|
|
4856
5084
|
await syncDbGroupHistoryFull({
|
|
4857
5085
|
profile,
|
|
4858
5086
|
api,
|
|
@@ -4911,8 +5139,8 @@ async function buildGroupsDetailed(api) {
|
|
|
4911
5139
|
const groups = await api.getAllGroups();
|
|
4912
5140
|
const ids = Object.keys(groups.gridVerMap ?? {});
|
|
4913
5141
|
if (ids.length === 0) return [];
|
|
4914
|
-
const info = await api
|
|
4915
|
-
return ids.map((id) => info.
|
|
5142
|
+
const info = await fetchGroupInfoRecords(api, ids);
|
|
5143
|
+
return ids.map((id) => info.get(id)).filter((item) => Boolean(item));
|
|
4916
5144
|
}
|
|
4917
5145
|
function normalizeGroupMemberId(value) {
|
|
4918
5146
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
@@ -4923,9 +5151,8 @@ function normalizeGroupMemberId(value) {
|
|
|
4923
5151
|
if (!trimmed) return "";
|
|
4924
5152
|
return trimmed.replace(/_\d+$/, "");
|
|
4925
5153
|
}
|
|
4926
|
-
async function listGroupMemberRows(api, groupId) {
|
|
4927
|
-
const
|
|
4928
|
-
const groupInfo = info.gridInfoMap[groupId];
|
|
5154
|
+
async function listGroupMemberRows(api, groupId, preloadedGroupInfo) {
|
|
5155
|
+
const groupInfo = preloadedGroupInfo ?? await fetchGroupInfoRecord(api, groupId);
|
|
4929
5156
|
if (!groupInfo) {
|
|
4930
5157
|
throw new Error(`Group not found: ${groupId}`);
|
|
4931
5158
|
}
|
|
@@ -4949,10 +5176,9 @@ async function listGroupMemberRows(api, groupId) {
|
|
|
4949
5176
|
...Array.from(currentMemberMap.keys())
|
|
4950
5177
|
])
|
|
4951
5178
|
);
|
|
4952
|
-
const
|
|
4953
|
-
const rawProfileMap = profiles.profiles;
|
|
5179
|
+
const profileLookup = ids.length > 0 ? await fetchGroupMemberProfiles(api, ids) : /* @__PURE__ */ new Map();
|
|
4954
5180
|
const profileMap = /* @__PURE__ */ new Map();
|
|
4955
|
-
for (const [key, profile] of
|
|
5181
|
+
for (const [key, profile] of profileLookup.entries()) {
|
|
4956
5182
|
if (!profile) continue;
|
|
4957
5183
|
const normalizedKey = normalizeGroupMemberId(key);
|
|
4958
5184
|
if (normalizedKey && !profileMap.has(normalizedKey)) {
|
|
@@ -5007,7 +5233,7 @@ function isListenerAlreadyStarted(error) {
|
|
|
5007
5233
|
if (!(error instanceof Error)) return false;
|
|
5008
5234
|
return /already started/i.test(error.message);
|
|
5009
5235
|
}
|
|
5010
|
-
function
|
|
5236
|
+
function toErrorText2(error) {
|
|
5011
5237
|
return error instanceof Error ? error.message : String(error);
|
|
5012
5238
|
}
|
|
5013
5239
|
var SHUTDOWN_CALLBACKS = /* @__PURE__ */ new Set();
|
|
@@ -5045,7 +5271,7 @@ async function runShutdownCallbacks(signal) {
|
|
|
5045
5271
|
"process.signal.callback_error",
|
|
5046
5272
|
{
|
|
5047
5273
|
signal,
|
|
5048
|
-
message:
|
|
5274
|
+
message: toErrorText2(error)
|
|
5049
5275
|
},
|
|
5050
5276
|
void 0
|
|
5051
5277
|
);
|
|
@@ -5128,7 +5354,7 @@ async function withUploadListener(api, command, task) {
|
|
|
5128
5354
|
writeDebugLine(
|
|
5129
5355
|
"msg.upload.listener.error",
|
|
5130
5356
|
{
|
|
5131
|
-
message:
|
|
5357
|
+
message: toErrorText2(error)
|
|
5132
5358
|
},
|
|
5133
5359
|
command
|
|
5134
5360
|
);
|
|
@@ -5170,7 +5396,7 @@ async function withUploadListener(api, command, task) {
|
|
|
5170
5396
|
finish();
|
|
5171
5397
|
};
|
|
5172
5398
|
const onConnectError = (error) => {
|
|
5173
|
-
finish(new Error(`Upload listener connection error: ${
|
|
5399
|
+
finish(new Error(`Upload listener connection error: ${toErrorText2(error)}`));
|
|
5174
5400
|
};
|
|
5175
5401
|
const onConnectClosed = (code, reason) => {
|
|
5176
5402
|
finish(
|
|
@@ -5808,7 +6034,7 @@ async function parseCredentialFile(filePath) {
|
|
|
5808
6034
|
language: parsed.language
|
|
5809
6035
|
};
|
|
5810
6036
|
}
|
|
5811
|
-
function
|
|
6037
|
+
function sleep3(ms) {
|
|
5812
6038
|
return new Promise((resolve) => {
|
|
5813
6039
|
setTimeout(resolve, ms);
|
|
5814
6040
|
});
|
|
@@ -5823,7 +6049,7 @@ async function waitForFileContent(filePath, timeoutMs) {
|
|
|
5823
6049
|
}
|
|
5824
6050
|
} catch {
|
|
5825
6051
|
}
|
|
5826
|
-
await
|
|
6052
|
+
await sleep3(150);
|
|
5827
6053
|
}
|
|
5828
6054
|
throw new Error(`Timed out waiting for QR image file: ${filePath}`);
|
|
5829
6055
|
}
|
|
@@ -9052,7 +9278,7 @@ ${replyContextText}` : replyContextText;
|
|
|
9052
9278
|
code,
|
|
9053
9279
|
reason: reason || void 0,
|
|
9054
9280
|
delayMs: keepAliveRestartDelayMs,
|
|
9055
|
-
message:
|
|
9281
|
+
message: toErrorText2(error),
|
|
9056
9282
|
sessionId
|
|
9057
9283
|
},
|
|
9058
9284
|
command
|