@qzhuli/qzhuli-cli 0.2.0 → 0.3.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +2 -1
- package/dist/cmd.js +1351 -210
- package/package.json +6 -1
- package/scripts/postinstall.mjs +226 -0
- package/skills/qzhuli-cli/SKILL.md +56 -4
package/dist/cmd.js
CHANGED
|
@@ -11133,7 +11133,7 @@ var require_protos = __commonJS({
|
|
|
11133
11133
|
|
|
11134
11134
|
// src/cmd.ts
|
|
11135
11135
|
init_cjs_shims();
|
|
11136
|
-
var
|
|
11136
|
+
var import_commander9 = require("commander");
|
|
11137
11137
|
|
|
11138
11138
|
// src/commands/auth/index.ts
|
|
11139
11139
|
init_cjs_shims();
|
|
@@ -11244,10 +11244,27 @@ var commands = {
|
|
|
11244
11244
|
desc: "Conversation operations",
|
|
11245
11245
|
listDesc: "List all conversations",
|
|
11246
11246
|
limitOption: "Max conversations to retrieve",
|
|
11247
|
+
offsetOption: "Skip first N conversations",
|
|
11247
11248
|
createDesc: "Create conversation",
|
|
11248
11249
|
createArgDesc: "User UID",
|
|
11249
11250
|
createAgentIdOption: "Agent ID",
|
|
11250
|
-
createSuccess: "Conversation created."
|
|
11251
|
+
createSuccess: "Conversation created.",
|
|
11252
|
+
profileDesc: "Get conversation details",
|
|
11253
|
+
profileArgDesc: "Conversation ID",
|
|
11254
|
+
typeOption: "Conversation type (1=private, 2=group, auto-detect if omitted)",
|
|
11255
|
+
profileSuccess: "Conversation details retrieved.",
|
|
11256
|
+
searchDesc: "Find all conversations with a user by Q\u52A9\u53F7 or UID",
|
|
11257
|
+
searchArgDesc: "Query string (default: Q\u52A9\u53F7)",
|
|
11258
|
+
searchByUid: "Search by UID",
|
|
11259
|
+
searchNotFound: "No conversations found with {name}.",
|
|
11260
|
+
searchSuccess: "Found {count} conversation(s) with {name}."
|
|
11261
|
+
},
|
|
11262
|
+
cache: {
|
|
11263
|
+
desc: "Manage local cache",
|
|
11264
|
+
syncDesc: "Sync all data to local cache",
|
|
11265
|
+
statusDesc: "Show cache status",
|
|
11266
|
+
clearDesc: "Clear cache",
|
|
11267
|
+
clearTableOption: "Clear specific cache table"
|
|
11251
11268
|
}
|
|
11252
11269
|
};
|
|
11253
11270
|
var messages = {
|
|
@@ -11374,10 +11391,27 @@ var commands2 = {
|
|
|
11374
11391
|
desc: "\u4F1A\u8BDD\u64CD\u4F5C",
|
|
11375
11392
|
listDesc: "\u5217\u51FA\u6240\u6709\u4F1A\u8BDD",
|
|
11376
11393
|
limitOption: "\u6700\u5927\u4F1A\u8BDD\u6570",
|
|
11394
|
+
offsetOption: "\u8DF3\u8FC7\u524D N \u6761\u4F1A\u8BDD",
|
|
11377
11395
|
createDesc: "\u521B\u5EFA\u4F1A\u8BDD",
|
|
11378
11396
|
createArgDesc: "\u7528\u6237UID",
|
|
11379
11397
|
createAgentIdOption: "\u52A9\u7406ID",
|
|
11380
|
-
createSuccess: "\u4F1A\u8BDD\u521B\u5EFA\u6210\u529F\u3002"
|
|
11398
|
+
createSuccess: "\u4F1A\u8BDD\u521B\u5EFA\u6210\u529F\u3002",
|
|
11399
|
+
profileDesc: "\u67E5\u8BE2\u4F1A\u8BDD\u8BE6\u60C5",
|
|
11400
|
+
profileArgDesc: "\u4F1A\u8BDDID",
|
|
11401
|
+
typeOption: "\u4F1A\u8BDD\u7C7B\u578B\uFF081=\u79C1\u804A, 2=\u7FA4\u804A\uFF0C\u4E0D\u4F20\u81EA\u52A8\u5224\u65AD\uFF09",
|
|
11402
|
+
profileSuccess: "\u5DF2\u83B7\u53D6\u4F1A\u8BDD\u8BE6\u60C5\u3002",
|
|
11403
|
+
searchDesc: "\u901A\u8FC7Q\u52A9\u53F7\u6216UID\u67E5\u627E\u4E0E\u67D0\u7528\u6237\u7684\u6240\u6709\u4F1A\u8BDD",
|
|
11404
|
+
searchArgDesc: "\u67E5\u8BE2\u5185\u5BB9\uFF08\u9ED8\u8BA4\u6309 Q\u52A9\u53F7\uFF09",
|
|
11405
|
+
searchByUid: "\u6309 UID \u641C\u7D22",
|
|
11406
|
+
searchNotFound: "\u672A\u627E\u5230\u4E0E {name} \u7684\u4F1A\u8BDD\u3002",
|
|
11407
|
+
searchSuccess: "\u627E\u5230\u4E0E {name} \u7684 {count} \u4E2A\u4F1A\u8BDD\u3002"
|
|
11408
|
+
},
|
|
11409
|
+
cache: {
|
|
11410
|
+
desc: "\u7BA1\u7406\u672C\u5730\u7F13\u5B58",
|
|
11411
|
+
syncDesc: "\u540C\u6B65\u6240\u6709\u6570\u636E\u5230\u672C\u5730\u7F13\u5B58",
|
|
11412
|
+
statusDesc: "\u663E\u793A\u7F13\u5B58\u72B6\u6001",
|
|
11413
|
+
clearDesc: "\u6E05\u9664\u7F13\u5B58",
|
|
11414
|
+
clearTableOption: "\u6E05\u9664\u6307\u5B9A\u7F13\u5B58\u8868"
|
|
11381
11415
|
}
|
|
11382
11416
|
};
|
|
11383
11417
|
var messages2 = {
|
|
@@ -11435,14 +11469,191 @@ function tf(key, values) {
|
|
|
11435
11469
|
|
|
11436
11470
|
// src/iostreams.ts
|
|
11437
11471
|
init_cjs_shims();
|
|
11472
|
+
|
|
11473
|
+
// src/internal/config/index.ts
|
|
11474
|
+
init_cjs_shims();
|
|
11475
|
+
|
|
11476
|
+
// src/internal/config/credentials.ts
|
|
11477
|
+
init_cjs_shims();
|
|
11478
|
+
var import_node_fs = require("fs");
|
|
11479
|
+
var import_node_path = require("path");
|
|
11480
|
+
function loadCredentials(configDir) {
|
|
11481
|
+
const path = (0, import_node_path.join)(configDir, "credentials.json");
|
|
11482
|
+
if (!(0, import_node_fs.existsSync)(path)) {
|
|
11483
|
+
return null;
|
|
11484
|
+
}
|
|
11485
|
+
try {
|
|
11486
|
+
const raw = (0, import_node_fs.readFileSync)(path, "utf-8");
|
|
11487
|
+
return JSON.parse(raw);
|
|
11488
|
+
} catch {
|
|
11489
|
+
console.error("[WARN] credentials.json is corrupted, skipping \u2014 please re-authenticate");
|
|
11490
|
+
return null;
|
|
11491
|
+
}
|
|
11492
|
+
}
|
|
11493
|
+
function saveCredentials(configDir, creds) {
|
|
11494
|
+
const path = (0, import_node_path.join)(configDir, "credentials.json");
|
|
11495
|
+
ensureConfigDirectory(configDir);
|
|
11496
|
+
(0, import_node_fs.writeFileSync)(path, JSON.stringify(creds, null, 2), {
|
|
11497
|
+
encoding: "utf-8",
|
|
11498
|
+
mode: 384
|
|
11499
|
+
});
|
|
11500
|
+
}
|
|
11501
|
+
function ensureConfigDirectory(configDir) {
|
|
11502
|
+
if (!(0, import_node_fs.existsSync)(configDir)) {
|
|
11503
|
+
(0, import_node_fs.mkdirSync)(configDir, { recursive: true });
|
|
11504
|
+
}
|
|
11505
|
+
}
|
|
11506
|
+
function clearCredentials(configDir) {
|
|
11507
|
+
const path = (0, import_node_path.join)(configDir, "credentials.json");
|
|
11508
|
+
if ((0, import_node_fs.existsSync)(path)) {
|
|
11509
|
+
(0, import_node_fs.rmSync)(path);
|
|
11510
|
+
}
|
|
11511
|
+
}
|
|
11512
|
+
function hasCredentials(configDir) {
|
|
11513
|
+
const creds = loadCredentials(configDir);
|
|
11514
|
+
return !!(creds?.uid && creds?.tk && creds?.token);
|
|
11515
|
+
}
|
|
11516
|
+
|
|
11517
|
+
// src/internal/config/directory.ts
|
|
11518
|
+
init_cjs_shims();
|
|
11519
|
+
var import_node_os = require("os");
|
|
11520
|
+
var import_node_path2 = require("path");
|
|
11521
|
+
var PROJECT_CONFIG_DIR = (0, import_node_path2.resolve)(process.cwd(), ".qzhuli-cli");
|
|
11522
|
+
var USER_CONFIG_DIR = (0, import_node_path2.resolve)((0, import_node_os.homedir)(), ".qzhuli-cli");
|
|
11523
|
+
function getConfigDirectory(env) {
|
|
11524
|
+
return env === "production" ? USER_CONFIG_DIR : PROJECT_CONFIG_DIR;
|
|
11525
|
+
}
|
|
11526
|
+
|
|
11527
|
+
// src/internal/config/environment.ts
|
|
11528
|
+
init_cjs_shims();
|
|
11529
|
+
var TEST_CONFIG = {
|
|
11530
|
+
name: "test",
|
|
11531
|
+
baseURL: "https://test.client.qzhuli.com",
|
|
11532
|
+
wsURL: "wss://test.im.qzhuli.com/ws"
|
|
11533
|
+
};
|
|
11534
|
+
var PRODUCTION_CONFIG = {
|
|
11535
|
+
name: "production",
|
|
11536
|
+
baseURL: "https://client.qzhuli.com",
|
|
11537
|
+
wsURL: "wss://im.qzhuli.com/ws"
|
|
11538
|
+
};
|
|
11539
|
+
var ENV_MAP = {
|
|
11540
|
+
test: TEST_CONFIG,
|
|
11541
|
+
production: PRODUCTION_CONFIG
|
|
11542
|
+
};
|
|
11543
|
+
function getEnvironmentConfig(name) {
|
|
11544
|
+
return ENV_MAP[name];
|
|
11545
|
+
}
|
|
11546
|
+
function detectEnvironment() {
|
|
11547
|
+
return false ? "test" : "production";
|
|
11548
|
+
}
|
|
11549
|
+
|
|
11550
|
+
// src/internal/config/preferences.ts
|
|
11551
|
+
init_cjs_shims();
|
|
11552
|
+
var import_node_fs2 = require("fs");
|
|
11553
|
+
var import_node_path3 = require("path");
|
|
11554
|
+
var DEFAULTS = {
|
|
11555
|
+
locale: "zh"
|
|
11556
|
+
};
|
|
11557
|
+
function loadPreferences(configDir) {
|
|
11558
|
+
const path = (0, import_node_path3.join)(configDir, "preferences.json");
|
|
11559
|
+
if (!(0, import_node_fs2.existsSync)(path)) {
|
|
11560
|
+
return { ...DEFAULTS };
|
|
11561
|
+
}
|
|
11562
|
+
try {
|
|
11563
|
+
const raw = (0, import_node_fs2.readFileSync)(path, "utf-8");
|
|
11564
|
+
const parsed = JSON.parse(raw);
|
|
11565
|
+
return { ...DEFAULTS, ...parsed };
|
|
11566
|
+
} catch {
|
|
11567
|
+
return { ...DEFAULTS };
|
|
11568
|
+
}
|
|
11569
|
+
}
|
|
11570
|
+
function savePreferences(configDir, updates) {
|
|
11571
|
+
if (isDryRun()) {
|
|
11572
|
+
return;
|
|
11573
|
+
}
|
|
11574
|
+
const current = loadPreferences(configDir);
|
|
11575
|
+
const merged = { ...current, ...updates };
|
|
11576
|
+
const path = (0, import_node_path3.join)(configDir, "preferences.json");
|
|
11577
|
+
ensureConfigDirectory2(configDir);
|
|
11578
|
+
(0, import_node_fs2.writeFileSync)(path, JSON.stringify(merged, null, 2), {
|
|
11579
|
+
encoding: "utf-8",
|
|
11580
|
+
mode: 384
|
|
11581
|
+
});
|
|
11582
|
+
}
|
|
11583
|
+
function ensureConfigDirectory2(configDir) {
|
|
11584
|
+
if (!(0, import_node_fs2.existsSync)(configDir)) {
|
|
11585
|
+
(0, import_node_fs2.mkdirSync)(configDir, { recursive: true });
|
|
11586
|
+
}
|
|
11587
|
+
}
|
|
11588
|
+
function initDefaultPreferences(configDir) {
|
|
11589
|
+
const path = (0, import_node_path3.join)(configDir, "preferences.json");
|
|
11590
|
+
if (!(0, import_node_fs2.existsSync)(path)) {
|
|
11591
|
+
ensureConfigDirectory2(configDir);
|
|
11592
|
+
(0, import_node_fs2.writeFileSync)(path, JSON.stringify(DEFAULTS, null, 2), {
|
|
11593
|
+
encoding: "utf-8",
|
|
11594
|
+
mode: 384
|
|
11595
|
+
});
|
|
11596
|
+
}
|
|
11597
|
+
}
|
|
11598
|
+
|
|
11599
|
+
// src/internal/config/index.ts
|
|
11600
|
+
function loadAppConfig(env) {
|
|
11601
|
+
const envName = env ?? detectEnvironment();
|
|
11602
|
+
const configDir = getConfigDirectory(envName);
|
|
11603
|
+
initDefaultPreferences(configDir);
|
|
11604
|
+
const envConfig = getEnvironmentConfig(envName);
|
|
11605
|
+
const prefs = loadPreferences(configDir);
|
|
11606
|
+
const creds = loadCredentials(configDir);
|
|
11607
|
+
const uid = creds?.uid || null;
|
|
11608
|
+
const tk = creds?.tk || null;
|
|
11609
|
+
const token = creds?.token || null;
|
|
11610
|
+
const cid = creds?.cid || null;
|
|
11611
|
+
return {
|
|
11612
|
+
uid,
|
|
11613
|
+
tk,
|
|
11614
|
+
token,
|
|
11615
|
+
cid,
|
|
11616
|
+
locale: prefs.locale ?? "en",
|
|
11617
|
+
debug: prefs.debug ?? false,
|
|
11618
|
+
baseURL: envConfig.baseURL,
|
|
11619
|
+
wsURL: envConfig.wsURL
|
|
11620
|
+
};
|
|
11621
|
+
}
|
|
11622
|
+
|
|
11623
|
+
// src/internal/config/logs.ts
|
|
11624
|
+
init_cjs_shims();
|
|
11625
|
+
var import_node_fs3 = require("fs");
|
|
11626
|
+
var import_node_path4 = require("path");
|
|
11627
|
+
function appendCliRunLog(configDir, entry, now = /* @__PURE__ */ new Date()) {
|
|
11628
|
+
const logDir = (0, import_node_path4.join)(configDir, "logs");
|
|
11629
|
+
(0, import_node_fs3.mkdirSync)(logDir, { recursive: true });
|
|
11630
|
+
(0, import_node_fs3.appendFileSync)(
|
|
11631
|
+
(0, import_node_path4.join)(logDir, `${formatLocalDate(now)}.log`),
|
|
11632
|
+
`${JSON.stringify(entry)}
|
|
11633
|
+
`,
|
|
11634
|
+
"utf-8"
|
|
11635
|
+
);
|
|
11636
|
+
}
|
|
11637
|
+
function formatLocalDate(value) {
|
|
11638
|
+
const year = value.getFullYear();
|
|
11639
|
+
const month = String(value.getMonth() + 1).padStart(2, "0");
|
|
11640
|
+
const day = String(value.getDate()).padStart(2, "0");
|
|
11641
|
+
return `${year}-${month}-${day}`;
|
|
11642
|
+
}
|
|
11643
|
+
|
|
11644
|
+
// src/iostreams.ts
|
|
11438
11645
|
var jqFilter = null;
|
|
11439
11646
|
var dryRun = false;
|
|
11647
|
+
var logDebug = false;
|
|
11440
11648
|
function setJqFilter(expr) {
|
|
11441
11649
|
jqFilter = expr;
|
|
11442
11650
|
}
|
|
11443
11651
|
function setDryRun(enabled) {
|
|
11444
11652
|
dryRun = enabled;
|
|
11445
11653
|
}
|
|
11654
|
+
function setLogDebug(enabled) {
|
|
11655
|
+
logDebug = enabled;
|
|
11656
|
+
}
|
|
11446
11657
|
function isDryRun() {
|
|
11447
11658
|
return dryRun;
|
|
11448
11659
|
}
|
|
@@ -11473,11 +11684,34 @@ function printStatus(status) {
|
|
|
11473
11684
|
`);
|
|
11474
11685
|
}
|
|
11475
11686
|
function handleCommand(result) {
|
|
11687
|
+
appendStatusLog(result);
|
|
11476
11688
|
printStatus(result);
|
|
11477
11689
|
if (!isDryRun() && result.status === "error") {
|
|
11478
11690
|
process.exit(1);
|
|
11479
11691
|
}
|
|
11480
11692
|
}
|
|
11693
|
+
function appendStatusLog(status) {
|
|
11694
|
+
const argv = process.argv.slice(2);
|
|
11695
|
+
try {
|
|
11696
|
+
appendCliRunLog(getConfigDirectory(detectEnvironment()), {
|
|
11697
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11698
|
+
argv,
|
|
11699
|
+
command: argv.join(" "),
|
|
11700
|
+
status: status.status,
|
|
11701
|
+
code: status.code,
|
|
11702
|
+
message: status.message,
|
|
11703
|
+
data: status.data,
|
|
11704
|
+
dryRun
|
|
11705
|
+
});
|
|
11706
|
+
} catch (error) {
|
|
11707
|
+
if (logDebug) {
|
|
11708
|
+
process.stderr.write(
|
|
11709
|
+
`[DEBUG] Failed to write CLI log: ${error instanceof Error ? error.message : String(error)}
|
|
11710
|
+
`
|
|
11711
|
+
);
|
|
11712
|
+
}
|
|
11713
|
+
}
|
|
11714
|
+
}
|
|
11481
11715
|
|
|
11482
11716
|
// src/commands/auth/login.ts
|
|
11483
11717
|
init_cjs_shims();
|
|
@@ -11914,156 +12148,6 @@ function promptRefresh(controller, onReset) {
|
|
|
11914
12148
|
});
|
|
11915
12149
|
}
|
|
11916
12150
|
|
|
11917
|
-
// src/internal/config/index.ts
|
|
11918
|
-
init_cjs_shims();
|
|
11919
|
-
|
|
11920
|
-
// src/internal/config/credentials.ts
|
|
11921
|
-
init_cjs_shims();
|
|
11922
|
-
var import_node_fs = require("fs");
|
|
11923
|
-
var import_node_path = require("path");
|
|
11924
|
-
function loadCredentials(configDir) {
|
|
11925
|
-
const path = (0, import_node_path.join)(configDir, "credentials.json");
|
|
11926
|
-
if (!(0, import_node_fs.existsSync)(path)) {
|
|
11927
|
-
return null;
|
|
11928
|
-
}
|
|
11929
|
-
try {
|
|
11930
|
-
const raw = (0, import_node_fs.readFileSync)(path, "utf-8");
|
|
11931
|
-
return JSON.parse(raw);
|
|
11932
|
-
} catch {
|
|
11933
|
-
console.error("[WARN] credentials.json is corrupted, skipping \u2014 please re-authenticate");
|
|
11934
|
-
return null;
|
|
11935
|
-
}
|
|
11936
|
-
}
|
|
11937
|
-
function saveCredentials(configDir, creds) {
|
|
11938
|
-
const path = (0, import_node_path.join)(configDir, "credentials.json");
|
|
11939
|
-
ensureConfigDirectory(configDir);
|
|
11940
|
-
(0, import_node_fs.writeFileSync)(path, JSON.stringify(creds, null, 2), {
|
|
11941
|
-
encoding: "utf-8",
|
|
11942
|
-
mode: 384
|
|
11943
|
-
});
|
|
11944
|
-
}
|
|
11945
|
-
function ensureConfigDirectory(configDir) {
|
|
11946
|
-
if (!(0, import_node_fs.existsSync)(configDir)) {
|
|
11947
|
-
(0, import_node_fs.mkdirSync)(configDir, { recursive: true });
|
|
11948
|
-
}
|
|
11949
|
-
}
|
|
11950
|
-
function clearCredentials(configDir) {
|
|
11951
|
-
const path = (0, import_node_path.join)(configDir, "credentials.json");
|
|
11952
|
-
if ((0, import_node_fs.existsSync)(path)) {
|
|
11953
|
-
(0, import_node_fs.rmSync)(path);
|
|
11954
|
-
}
|
|
11955
|
-
}
|
|
11956
|
-
function hasCredentials(configDir) {
|
|
11957
|
-
const creds = loadCredentials(configDir);
|
|
11958
|
-
return !!(creds?.uid && creds?.tk && creds?.token);
|
|
11959
|
-
}
|
|
11960
|
-
|
|
11961
|
-
// src/internal/config/directory.ts
|
|
11962
|
-
init_cjs_shims();
|
|
11963
|
-
var import_node_os = require("os");
|
|
11964
|
-
var import_node_path2 = require("path");
|
|
11965
|
-
var PROJECT_CONFIG_DIR = (0, import_node_path2.resolve)(process.cwd(), ".qzhuli-cli");
|
|
11966
|
-
var USER_CONFIG_DIR = (0, import_node_path2.resolve)((0, import_node_os.homedir)(), ".qzhuli-cli");
|
|
11967
|
-
function getConfigDirectory(env) {
|
|
11968
|
-
return env === "production" ? USER_CONFIG_DIR : PROJECT_CONFIG_DIR;
|
|
11969
|
-
}
|
|
11970
|
-
|
|
11971
|
-
// src/internal/config/environment.ts
|
|
11972
|
-
init_cjs_shims();
|
|
11973
|
-
var TEST_CONFIG = {
|
|
11974
|
-
name: "test",
|
|
11975
|
-
baseURL: "https://test.client.qzhuli.com",
|
|
11976
|
-
wsURL: "wss://test.im.qzhuli.com/ws"
|
|
11977
|
-
};
|
|
11978
|
-
var PRODUCTION_CONFIG = {
|
|
11979
|
-
name: "production",
|
|
11980
|
-
baseURL: "https://client.qzhuli.com",
|
|
11981
|
-
wsURL: "wss://im.qzhuli.com/ws"
|
|
11982
|
-
};
|
|
11983
|
-
var ENV_MAP = {
|
|
11984
|
-
test: TEST_CONFIG,
|
|
11985
|
-
production: PRODUCTION_CONFIG
|
|
11986
|
-
};
|
|
11987
|
-
function getEnvironmentConfig(name) {
|
|
11988
|
-
return ENV_MAP[name];
|
|
11989
|
-
}
|
|
11990
|
-
function detectEnvironment() {
|
|
11991
|
-
return false ? "test" : "production";
|
|
11992
|
-
}
|
|
11993
|
-
|
|
11994
|
-
// src/internal/config/preferences.ts
|
|
11995
|
-
init_cjs_shims();
|
|
11996
|
-
var import_node_fs2 = require("fs");
|
|
11997
|
-
var import_node_path3 = require("path");
|
|
11998
|
-
var DEFAULTS = {
|
|
11999
|
-
locale: "zh"
|
|
12000
|
-
};
|
|
12001
|
-
function loadPreferences(configDir) {
|
|
12002
|
-
const path = (0, import_node_path3.join)(configDir, "preferences.json");
|
|
12003
|
-
if (!(0, import_node_fs2.existsSync)(path)) {
|
|
12004
|
-
return { ...DEFAULTS };
|
|
12005
|
-
}
|
|
12006
|
-
try {
|
|
12007
|
-
const raw = (0, import_node_fs2.readFileSync)(path, "utf-8");
|
|
12008
|
-
const parsed = JSON.parse(raw);
|
|
12009
|
-
return { ...DEFAULTS, ...parsed };
|
|
12010
|
-
} catch {
|
|
12011
|
-
return { ...DEFAULTS };
|
|
12012
|
-
}
|
|
12013
|
-
}
|
|
12014
|
-
function savePreferences(configDir, updates) {
|
|
12015
|
-
if (isDryRun()) {
|
|
12016
|
-
return;
|
|
12017
|
-
}
|
|
12018
|
-
const current = loadPreferences(configDir);
|
|
12019
|
-
const merged = { ...current, ...updates };
|
|
12020
|
-
const path = (0, import_node_path3.join)(configDir, "preferences.json");
|
|
12021
|
-
ensureConfigDirectory2(configDir);
|
|
12022
|
-
(0, import_node_fs2.writeFileSync)(path, JSON.stringify(merged, null, 2), {
|
|
12023
|
-
encoding: "utf-8",
|
|
12024
|
-
mode: 384
|
|
12025
|
-
});
|
|
12026
|
-
}
|
|
12027
|
-
function ensureConfigDirectory2(configDir) {
|
|
12028
|
-
if (!(0, import_node_fs2.existsSync)(configDir)) {
|
|
12029
|
-
(0, import_node_fs2.mkdirSync)(configDir, { recursive: true });
|
|
12030
|
-
}
|
|
12031
|
-
}
|
|
12032
|
-
function initDefaultPreferences(configDir) {
|
|
12033
|
-
const path = (0, import_node_path3.join)(configDir, "preferences.json");
|
|
12034
|
-
if (!(0, import_node_fs2.existsSync)(path)) {
|
|
12035
|
-
ensureConfigDirectory2(configDir);
|
|
12036
|
-
(0, import_node_fs2.writeFileSync)(path, JSON.stringify(DEFAULTS, null, 2), {
|
|
12037
|
-
encoding: "utf-8",
|
|
12038
|
-
mode: 384
|
|
12039
|
-
});
|
|
12040
|
-
}
|
|
12041
|
-
}
|
|
12042
|
-
|
|
12043
|
-
// src/internal/config/index.ts
|
|
12044
|
-
function loadAppConfig(env) {
|
|
12045
|
-
const envName = env ?? detectEnvironment();
|
|
12046
|
-
const configDir = getConfigDirectory(envName);
|
|
12047
|
-
initDefaultPreferences(configDir);
|
|
12048
|
-
const envConfig = getEnvironmentConfig(envName);
|
|
12049
|
-
const prefs = loadPreferences(configDir);
|
|
12050
|
-
const creds = loadCredentials(configDir);
|
|
12051
|
-
const uid = creds?.uid || null;
|
|
12052
|
-
const tk = creds?.tk || null;
|
|
12053
|
-
const token = creds?.token || null;
|
|
12054
|
-
const cid = creds?.cid || null;
|
|
12055
|
-
return {
|
|
12056
|
-
uid,
|
|
12057
|
-
tk,
|
|
12058
|
-
token,
|
|
12059
|
-
cid,
|
|
12060
|
-
locale: prefs.locale ?? "en",
|
|
12061
|
-
debug: prefs.debug ?? false,
|
|
12062
|
-
baseURL: envConfig.baseURL,
|
|
12063
|
-
wsURL: envConfig.wsURL
|
|
12064
|
-
};
|
|
12065
|
-
}
|
|
12066
|
-
|
|
12067
12151
|
// src/commands/auth/login.ts
|
|
12068
12152
|
async function authLoginRun(factory, opts) {
|
|
12069
12153
|
try {
|
|
@@ -12192,10 +12276,121 @@ function NewCmdAuth(factory) {
|
|
|
12192
12276
|
return cmd;
|
|
12193
12277
|
}
|
|
12194
12278
|
|
|
12195
|
-
// src/commands/
|
|
12279
|
+
// src/commands/cache/index.ts
|
|
12196
12280
|
init_cjs_shims();
|
|
12197
12281
|
var import_commander2 = require("commander");
|
|
12198
12282
|
|
|
12283
|
+
// src/commands/cache/clear.ts
|
|
12284
|
+
init_cjs_shims();
|
|
12285
|
+
async function cacheClearRun(factory, opts) {
|
|
12286
|
+
if (opts.table) {
|
|
12287
|
+
switch (opts.table) {
|
|
12288
|
+
case "conversations":
|
|
12289
|
+
factory.repos.conversation.clear();
|
|
12290
|
+
break;
|
|
12291
|
+
case "contacts":
|
|
12292
|
+
factory.repos.contact.clear();
|
|
12293
|
+
break;
|
|
12294
|
+
case "users":
|
|
12295
|
+
factory.repos.user.clear();
|
|
12296
|
+
break;
|
|
12297
|
+
case "relations":
|
|
12298
|
+
factory.repos.relation.clear();
|
|
12299
|
+
break;
|
|
12300
|
+
case "messages":
|
|
12301
|
+
factory.repos.message.clear();
|
|
12302
|
+
break;
|
|
12303
|
+
default:
|
|
12304
|
+
return {
|
|
12305
|
+
status: "error",
|
|
12306
|
+
code: "INVALID_ARGUMENT" /* INVALID_ARGUMENT */,
|
|
12307
|
+
message: t("commands.cache.unknownTable").replace("{table}", opts.table),
|
|
12308
|
+
data: null
|
|
12309
|
+
};
|
|
12310
|
+
}
|
|
12311
|
+
} else {
|
|
12312
|
+
factory.repos.conversation.clear();
|
|
12313
|
+
factory.repos.contact.clear();
|
|
12314
|
+
factory.repos.user.clear();
|
|
12315
|
+
factory.repos.relation.clear();
|
|
12316
|
+
factory.repos.message.clear();
|
|
12317
|
+
}
|
|
12318
|
+
return {
|
|
12319
|
+
status: "success",
|
|
12320
|
+
code: "CONFIG_UPDATED" /* CONFIG_UPDATED */,
|
|
12321
|
+
message: opts.table ? t("commands.cache.clearTableSuccess").replace("{table}", opts.table) : t("commands.cache.clearSuccess"),
|
|
12322
|
+
data: null
|
|
12323
|
+
};
|
|
12324
|
+
}
|
|
12325
|
+
|
|
12326
|
+
// src/commands/cache/status.ts
|
|
12327
|
+
init_cjs_shims();
|
|
12328
|
+
async function cacheStatusRun(factory) {
|
|
12329
|
+
const [convStatus, contactStatus] = await Promise.all([
|
|
12330
|
+
factory.repos.conversation.getStatus(),
|
|
12331
|
+
factory.repos.contact.getStatus()
|
|
12332
|
+
]);
|
|
12333
|
+
return {
|
|
12334
|
+
status: "success",
|
|
12335
|
+
code: "CONFIG_RETRIEVED" /* CONFIG_RETRIEVED */,
|
|
12336
|
+
message: "Cache status:",
|
|
12337
|
+
data: {
|
|
12338
|
+
conversations: {
|
|
12339
|
+
count: convStatus.count,
|
|
12340
|
+
lastSyncAt: convStatus.lastSyncAt ? new Date(convStatus.lastSyncAt).toISOString() : "never"
|
|
12341
|
+
},
|
|
12342
|
+
contacts: {
|
|
12343
|
+
count: contactStatus.count,
|
|
12344
|
+
lastSyncAt: contactStatus.lastSyncAt ? new Date(contactStatus.lastSyncAt).toISOString() : "never"
|
|
12345
|
+
}
|
|
12346
|
+
}
|
|
12347
|
+
};
|
|
12348
|
+
}
|
|
12349
|
+
|
|
12350
|
+
// src/commands/cache/sync.ts
|
|
12351
|
+
init_cjs_shims();
|
|
12352
|
+
async function cacheSyncRun(factory) {
|
|
12353
|
+
try {
|
|
12354
|
+
await factory.repos.contact.sync();
|
|
12355
|
+
await factory.repos.conversation.sync();
|
|
12356
|
+
} catch (error) {
|
|
12357
|
+
return {
|
|
12358
|
+
status: "error",
|
|
12359
|
+
code: "INTERNAL_ERROR" /* INTERNAL_ERROR */,
|
|
12360
|
+
message: error instanceof Error ? error.message : "Cache sync failed.",
|
|
12361
|
+
data: null
|
|
12362
|
+
};
|
|
12363
|
+
}
|
|
12364
|
+
return {
|
|
12365
|
+
status: "success",
|
|
12366
|
+
code: "CONFIG_UPDATED" /* CONFIG_UPDATED */,
|
|
12367
|
+
message: t("commands.cache.syncSuccess"),
|
|
12368
|
+
data: null
|
|
12369
|
+
};
|
|
12370
|
+
}
|
|
12371
|
+
|
|
12372
|
+
// src/commands/cache/index.ts
|
|
12373
|
+
function NewCmdCache(factory) {
|
|
12374
|
+
const cmd = new import_commander2.Command("cache").description(t("commands.cache.desc"));
|
|
12375
|
+
cmd.command("sync").description(t("commands.cache.syncDesc")).action(async () => {
|
|
12376
|
+
const result = await cacheSyncRun(factory);
|
|
12377
|
+
handleCommand(result);
|
|
12378
|
+
});
|
|
12379
|
+
cmd.command("status").description(t("commands.cache.statusDesc")).action(async () => {
|
|
12380
|
+
const result = await cacheStatusRun(factory);
|
|
12381
|
+
handleCommand(result);
|
|
12382
|
+
});
|
|
12383
|
+
cmd.command("clear").description(t("commands.cache.clearDesc")).option("--table <table>", t("commands.cache.clearTableOption")).action(async (opts) => {
|
|
12384
|
+
const result = await cacheClearRun(factory, { table: opts.table });
|
|
12385
|
+
handleCommand(result);
|
|
12386
|
+
});
|
|
12387
|
+
return cmd;
|
|
12388
|
+
}
|
|
12389
|
+
|
|
12390
|
+
// src/commands/config/index.ts
|
|
12391
|
+
init_cjs_shims();
|
|
12392
|
+
var import_commander3 = require("commander");
|
|
12393
|
+
|
|
12199
12394
|
// src/commands/config/get.ts
|
|
12200
12395
|
init_cjs_shims();
|
|
12201
12396
|
function configGetRun(_factory, opts) {
|
|
@@ -12223,7 +12418,7 @@ function configGetRun(_factory, opts) {
|
|
|
12223
12418
|
|
|
12224
12419
|
// src/commands/config/index.ts
|
|
12225
12420
|
function NewCmdConfig(factory) {
|
|
12226
|
-
const cmd = new
|
|
12421
|
+
const cmd = new import_commander3.Command("config").description(t("commands.config.desc"));
|
|
12227
12422
|
cmd.option("--locale <language>", t("commands.config.localeOption")).option("--debug", t("commands.config.debugOn")).option("--no-debug", t("commands.config.debugOff")).action((opts) => {
|
|
12228
12423
|
const result = configGetRun(factory, {
|
|
12229
12424
|
locale: opts.locale,
|
|
@@ -12236,7 +12431,7 @@ function NewCmdConfig(factory) {
|
|
|
12236
12431
|
|
|
12237
12432
|
// src/commands/conversation/index.ts
|
|
12238
12433
|
init_cjs_shims();
|
|
12239
|
-
var
|
|
12434
|
+
var import_commander4 = require("commander");
|
|
12240
12435
|
|
|
12241
12436
|
// src/commands/conversation/create.ts
|
|
12242
12437
|
init_cjs_shims();
|
|
@@ -12257,28 +12452,166 @@ async function conversationCreateRun(factory, opts) {
|
|
|
12257
12452
|
data: result.data
|
|
12258
12453
|
};
|
|
12259
12454
|
}
|
|
12260
|
-
|
|
12261
|
-
// src/commands/conversation/list.ts
|
|
12262
|
-
init_cjs_shims();
|
|
12263
|
-
async function conversationListRun(factory, opts) {
|
|
12264
|
-
const result = await factory.
|
|
12265
|
-
|
|
12455
|
+
|
|
12456
|
+
// src/commands/conversation/list.ts
|
|
12457
|
+
init_cjs_shims();
|
|
12458
|
+
async function conversationListRun(factory, opts) {
|
|
12459
|
+
const result = await factory.repos.conversation.queryAll({
|
|
12460
|
+
limit: opts.limit,
|
|
12461
|
+
offset: opts.offset
|
|
12462
|
+
});
|
|
12463
|
+
if (!result.ok && result.code === "AUTH_FAILED" /* AUTH_FAILED */) {
|
|
12464
|
+
return {
|
|
12465
|
+
status: "error",
|
|
12466
|
+
code: "AUTH_FAILED" /* AUTH_FAILED */,
|
|
12467
|
+
message: t("auth.notAuthenticated"),
|
|
12468
|
+
data: null
|
|
12469
|
+
};
|
|
12470
|
+
}
|
|
12471
|
+
return {
|
|
12472
|
+
status: result.ok ? "success" : "error",
|
|
12473
|
+
code: result.ok ? "CONVERSATION_LIST" /* CONVERSATION_LIST */ : result.code,
|
|
12474
|
+
message: result.ok ? `Conversations (${result.data.length}):` : result.message,
|
|
12475
|
+
data: result.ok ? { conversations: result.data } : null
|
|
12476
|
+
};
|
|
12477
|
+
}
|
|
12478
|
+
|
|
12479
|
+
// src/commands/conversation/profile.ts
|
|
12480
|
+
init_cjs_shims();
|
|
12481
|
+
async function conversationProfileRun(factory, opts) {
|
|
12482
|
+
const result = await factory.repos.conversation.getProfile(
|
|
12483
|
+
opts.conversationId,
|
|
12484
|
+
opts.conversationType
|
|
12485
|
+
);
|
|
12486
|
+
if (!result.ok) {
|
|
12487
|
+
return {
|
|
12488
|
+
status: "error",
|
|
12489
|
+
code: result.code,
|
|
12490
|
+
message: result.code === "AUTH_FAILED" /* AUTH_FAILED */ ? t("auth.notAuthenticated") : result.message,
|
|
12491
|
+
data: null
|
|
12492
|
+
};
|
|
12493
|
+
}
|
|
12494
|
+
return {
|
|
12495
|
+
status: "success",
|
|
12496
|
+
code: "CONVERSATION_LIST" /* CONVERSATION_LIST */,
|
|
12497
|
+
message: t("commands.conversation.profileSuccess"),
|
|
12498
|
+
data: result.data
|
|
12499
|
+
};
|
|
12500
|
+
}
|
|
12501
|
+
|
|
12502
|
+
// src/commands/conversation/search.ts
|
|
12503
|
+
init_cjs_shims();
|
|
12504
|
+
function convertUser(raw) {
|
|
12505
|
+
const user = {
|
|
12506
|
+
id: raw.id,
|
|
12507
|
+
cid: raw.cid,
|
|
12508
|
+
uid: raw.uid,
|
|
12509
|
+
nickname: raw.nickname,
|
|
12510
|
+
avatar: raw.avatar,
|
|
12511
|
+
status: raw.status
|
|
12512
|
+
};
|
|
12513
|
+
if (raw.link_name) user.linkName = raw.link_name;
|
|
12514
|
+
if (raw.member_delete_time) user.memberDeleteTime = raw.member_delete_time;
|
|
12515
|
+
if (raw.agent) {
|
|
12516
|
+
const a = raw.agent;
|
|
12517
|
+
const agentVoice = a.voice ? {
|
|
12518
|
+
code: a.voice.code,
|
|
12519
|
+
...a.voice.voice_name ? { voiceName: a.voice.voice_name } : {},
|
|
12520
|
+
...a.voice.file_link ? { fileLink: a.voice.file_link } : {},
|
|
12521
|
+
...a.voice.text ? { text: a.voice.text } : {}
|
|
12522
|
+
} : void 0;
|
|
12523
|
+
user.agent = {
|
|
12524
|
+
id: a.id,
|
|
12525
|
+
title: a.title,
|
|
12526
|
+
avatar: a.avatar,
|
|
12527
|
+
packageIcon: a.package_icon,
|
|
12528
|
+
packageLevel: a.package_level,
|
|
12529
|
+
...a.background !== void 0 ? { background: a.background } : {},
|
|
12530
|
+
...a.agent_type !== void 0 ? { agentType: a.agent_type } : {},
|
|
12531
|
+
...agentVoice ? { voice: agentVoice } : {}
|
|
12532
|
+
};
|
|
12533
|
+
}
|
|
12534
|
+
return user;
|
|
12535
|
+
}
|
|
12536
|
+
function convertVisitor(raw) {
|
|
12537
|
+
return { id: raw.id, cid: raw.cid };
|
|
12538
|
+
}
|
|
12539
|
+
function profileToItem(profile) {
|
|
12540
|
+
const convData = profile.conversation;
|
|
12541
|
+
return {
|
|
12542
|
+
conversationId: convData.conversation_id,
|
|
12543
|
+
blackStatus: convData.black_status,
|
|
12544
|
+
isGroup: convData.is_group,
|
|
12545
|
+
name: convData.name,
|
|
12546
|
+
avatar: convData.avatar,
|
|
12547
|
+
sourceType: convData.source_type,
|
|
12548
|
+
classesId: convData.classes_id,
|
|
12549
|
+
classesName: convData.classes_name,
|
|
12550
|
+
teamId: convData.team_id,
|
|
12551
|
+
teamName: convData.team_name,
|
|
12552
|
+
users: profile.users.map(convertUser),
|
|
12553
|
+
visitors: profile.visitors.map(convertVisitor)
|
|
12554
|
+
};
|
|
12555
|
+
}
|
|
12556
|
+
async function conversationSearchRun(factory, opts) {
|
|
12557
|
+
const userResult = opts.byUid ? await factory.repos.user.findUserById(opts.query) : await factory.repos.user.searchUserById(opts.query);
|
|
12558
|
+
if (!userResult.ok) {
|
|
12266
12559
|
return {
|
|
12267
12560
|
status: "error",
|
|
12268
|
-
code:
|
|
12269
|
-
message: t("auth.notAuthenticated"),
|
|
12561
|
+
code: userResult.code,
|
|
12562
|
+
message: userResult.code === "AUTH_FAILED" /* AUTH_FAILED */ ? t("auth.notAuthenticated") : userResult.message,
|
|
12270
12563
|
data: null
|
|
12271
12564
|
};
|
|
12272
12565
|
}
|
|
12273
|
-
|
|
12566
|
+
if (!userResult.data) {
|
|
12567
|
+
return {
|
|
12568
|
+
status: "error",
|
|
12569
|
+
code: "USER_NOT_FOUND_NEEDS_RESOLUTION" /* USER_NOT_FOUND_NEEDS_RESOLUTION */,
|
|
12570
|
+
message: t("messages.notFound"),
|
|
12571
|
+
data: null
|
|
12572
|
+
};
|
|
12573
|
+
}
|
|
12574
|
+
const targetId = userResult.data.id;
|
|
12575
|
+
const targetUid = userResult.data.uid;
|
|
12576
|
+
const nickname = userResult.data.nickname;
|
|
12577
|
+
const profilesResult = await factory.repos.conversation.searchByUid(targetUid);
|
|
12578
|
+
if (!profilesResult.ok || profilesResult.data.length === 0) {
|
|
12579
|
+
return {
|
|
12580
|
+
status: "success",
|
|
12581
|
+
code: "NOT_FOUND" /* NOT_FOUND */,
|
|
12582
|
+
message: t("commands.conversation.searchNotFound").replace("{name}", nickname),
|
|
12583
|
+
data: null
|
|
12584
|
+
};
|
|
12585
|
+
}
|
|
12586
|
+
const results = profilesResult.data.map(profileToItem);
|
|
12587
|
+
const result = {
|
|
12588
|
+
id: targetId,
|
|
12589
|
+
uid: targetUid,
|
|
12590
|
+
nickname,
|
|
12591
|
+
conversations: results
|
|
12592
|
+
};
|
|
12593
|
+
return {
|
|
12594
|
+
status: "success",
|
|
12595
|
+
code: "CONVERSATION_LIST" /* CONVERSATION_LIST */,
|
|
12596
|
+
message: t("commands.conversation.searchSuccess").replace("{name}", nickname).replace("{count}", String(results.length)),
|
|
12597
|
+
data: result
|
|
12598
|
+
};
|
|
12274
12599
|
}
|
|
12275
12600
|
|
|
12276
12601
|
// src/commands/conversation/index.ts
|
|
12277
12602
|
function NewCmdConversation(factory) {
|
|
12278
|
-
const cmd = new
|
|
12279
|
-
cmd.command("list").description(t("commands.conversation.listDesc")).option("--limit <n>", t("commands.conversation.limitOption"), "50").action(async (options3) => {
|
|
12603
|
+
const cmd = new import_commander4.Command("conversation").description(t("commands.conversation.desc"));
|
|
12604
|
+
cmd.command("list").description(t("commands.conversation.listDesc")).option("--limit <n>", t("commands.conversation.limitOption"), "50").option("--offset <n>", t("commands.conversation.offsetOption"), "0").action(async (options3) => {
|
|
12280
12605
|
const result = await conversationListRun(factory, {
|
|
12281
|
-
limit: parseInt(options3.limit, 10)
|
|
12606
|
+
limit: parseInt(options3.limit, 10),
|
|
12607
|
+
offset: parseInt(options3.offset, 10)
|
|
12608
|
+
});
|
|
12609
|
+
handleCommand(result);
|
|
12610
|
+
});
|
|
12611
|
+
cmd.command("profile").description(t("commands.conversation.profileDesc")).argument("<id>", t("commands.conversation.profileArgDesc")).option("--type <n>", t("commands.conversation.typeOption")).action(async (id, opts) => {
|
|
12612
|
+
const result = await conversationProfileRun(factory, {
|
|
12613
|
+
conversationId: id,
|
|
12614
|
+
conversationType: opts.type ? parseInt(opts.type, 10) : void 0
|
|
12282
12615
|
});
|
|
12283
12616
|
handleCommand(result);
|
|
12284
12617
|
});
|
|
@@ -12286,17 +12619,21 @@ function NewCmdConversation(factory) {
|
|
|
12286
12619
|
const result = await conversationCreateRun(factory, { uid, agentId: opts.agentId });
|
|
12287
12620
|
handleCommand(result);
|
|
12288
12621
|
});
|
|
12622
|
+
cmd.command("search").description(t("commands.conversation.searchDesc")).argument("<query>", t("commands.conversation.searchArgDesc")).option("--uid", t("commands.conversation.searchByUid")).action(async (query, opts) => {
|
|
12623
|
+
const result = await conversationSearchRun(factory, { query, byUid: opts.uid });
|
|
12624
|
+
handleCommand(result);
|
|
12625
|
+
});
|
|
12289
12626
|
return cmd;
|
|
12290
12627
|
}
|
|
12291
12628
|
|
|
12292
12629
|
// src/commands/friend/index.ts
|
|
12293
12630
|
init_cjs_shims();
|
|
12294
|
-
var
|
|
12631
|
+
var import_commander5 = require("commander");
|
|
12295
12632
|
|
|
12296
12633
|
// src/commands/friend/list.ts
|
|
12297
12634
|
init_cjs_shims();
|
|
12298
12635
|
async function friendListRun(factory) {
|
|
12299
|
-
const result = await factory.
|
|
12636
|
+
const result = await factory.repos.contact.getLinksContacts();
|
|
12300
12637
|
if (!result.ok) {
|
|
12301
12638
|
return {
|
|
12302
12639
|
status: "error",
|
|
@@ -12326,7 +12663,7 @@ async function friendListRun(factory) {
|
|
|
12326
12663
|
// src/commands/friend/profile.ts
|
|
12327
12664
|
init_cjs_shims();
|
|
12328
12665
|
async function friendProfileRun(factory, opts) {
|
|
12329
|
-
const listResult = await factory.
|
|
12666
|
+
const listResult = await factory.repos.contact.getLinksContacts();
|
|
12330
12667
|
if (!listResult.ok) {
|
|
12331
12668
|
return {
|
|
12332
12669
|
status: "error",
|
|
@@ -12411,7 +12748,7 @@ async function friendProfileRun(factory, opts) {
|
|
|
12411
12748
|
}
|
|
12412
12749
|
};
|
|
12413
12750
|
}
|
|
12414
|
-
const profileResult = await factory.
|
|
12751
|
+
const profileResult = await factory.repos.user.getUserAgentProfile(match.uid);
|
|
12415
12752
|
if (!profileResult.ok) {
|
|
12416
12753
|
return {
|
|
12417
12754
|
status: "error",
|
|
@@ -12444,7 +12781,7 @@ async function friendProfileRun(factory, opts) {
|
|
|
12444
12781
|
|
|
12445
12782
|
// src/commands/friend/index.ts
|
|
12446
12783
|
function NewCmdFriend(factory) {
|
|
12447
|
-
const cmd = new
|
|
12784
|
+
const cmd = new import_commander5.Command("friend").description(t("commands.friend.desc"));
|
|
12448
12785
|
cmd.command("list").description(t("commands.friend.listDesc")).action(async () => {
|
|
12449
12786
|
const result = await friendListRun(factory);
|
|
12450
12787
|
handleCommand(result);
|
|
@@ -12462,7 +12799,7 @@ function NewCmdFriend(factory) {
|
|
|
12462
12799
|
|
|
12463
12800
|
// src/commands/message/index.ts
|
|
12464
12801
|
init_cjs_shims();
|
|
12465
|
-
var
|
|
12802
|
+
var import_commander6 = require("commander");
|
|
12466
12803
|
|
|
12467
12804
|
// src/commands/message/history.ts
|
|
12468
12805
|
init_cjs_shims();
|
|
@@ -12472,8 +12809,8 @@ async function messageHistoryRun(factory, opts) {
|
|
|
12472
12809
|
direction: opts.direction,
|
|
12473
12810
|
limit: opts.limit
|
|
12474
12811
|
};
|
|
12475
|
-
const result = await factory.
|
|
12476
|
-
if (result.
|
|
12812
|
+
const result = await factory.repos.message.pullMessages(opts.conversationId, pullOpts);
|
|
12813
|
+
if (!result.ok && result.code === "AUTH_FAILED" /* AUTH_FAILED */) {
|
|
12477
12814
|
return {
|
|
12478
12815
|
status: "error",
|
|
12479
12816
|
code: "AUTH_FAILED" /* AUTH_FAILED */,
|
|
@@ -12481,7 +12818,12 @@ async function messageHistoryRun(factory, opts) {
|
|
|
12481
12818
|
data: null
|
|
12482
12819
|
};
|
|
12483
12820
|
}
|
|
12484
|
-
return
|
|
12821
|
+
return {
|
|
12822
|
+
status: result.ok ? "success" : "error",
|
|
12823
|
+
code: result.ok ? "MESSAGE_HISTORY" /* MESSAGE_HISTORY */ : result.code,
|
|
12824
|
+
message: result.ok ? `Messages (${result.data.messages.length}):` : result.message,
|
|
12825
|
+
data: result.ok ? result.data : null
|
|
12826
|
+
};
|
|
12485
12827
|
}
|
|
12486
12828
|
|
|
12487
12829
|
// src/commands/message/send.ts
|
|
@@ -12505,7 +12847,7 @@ async function messageSendRun(factory, opts) {
|
|
|
12505
12847
|
|
|
12506
12848
|
// src/commands/message/index.ts
|
|
12507
12849
|
function NewCmdMessage(factory) {
|
|
12508
|
-
const cmd = new
|
|
12850
|
+
const cmd = new import_commander6.Command("message").description(t("commands.message.desc"));
|
|
12509
12851
|
cmd.command("send <conversation-id> <target-cid> <content>").description(t("commands.message.sendDesc")).action(async (conversationId, targetCid, content) => {
|
|
12510
12852
|
const result = await messageSendRun(factory, { conversationId, targetCid, content });
|
|
12511
12853
|
handleCommand(result);
|
|
@@ -12524,12 +12866,12 @@ function NewCmdMessage(factory) {
|
|
|
12524
12866
|
|
|
12525
12867
|
// src/commands/relation/index.ts
|
|
12526
12868
|
init_cjs_shims();
|
|
12527
|
-
var
|
|
12869
|
+
var import_commander7 = require("commander");
|
|
12528
12870
|
|
|
12529
12871
|
// src/commands/relation/get.ts
|
|
12530
12872
|
init_cjs_shims();
|
|
12531
12873
|
async function relationGetRun(factory, opts) {
|
|
12532
|
-
const result = await factory.
|
|
12874
|
+
const result = await factory.repos.relation.getLinkNameType(opts.friendUid);
|
|
12533
12875
|
if (!result.ok) {
|
|
12534
12876
|
return {
|
|
12535
12877
|
status: "error",
|
|
@@ -12597,7 +12939,7 @@ async function relationSetRun(factory, opts) {
|
|
|
12597
12939
|
|
|
12598
12940
|
// src/commands/relation/index.ts
|
|
12599
12941
|
function NewCmdRelation(factory) {
|
|
12600
|
-
const cmd = new
|
|
12942
|
+
const cmd = new import_commander7.Command("relation").description(t("commands.relation.desc"));
|
|
12601
12943
|
cmd.command("get <uid>").description(t("commands.relation.getDesc")).action(async (uid) => {
|
|
12602
12944
|
const result = await relationGetRun(factory, { friendUid: uid });
|
|
12603
12945
|
handleCommand(result);
|
|
@@ -12615,7 +12957,7 @@ function NewCmdRelation(factory) {
|
|
|
12615
12957
|
|
|
12616
12958
|
// src/commands/user/index.ts
|
|
12617
12959
|
init_cjs_shims();
|
|
12618
|
-
var
|
|
12960
|
+
var import_commander8 = require("commander");
|
|
12619
12961
|
|
|
12620
12962
|
// src/commands/user/add.ts
|
|
12621
12963
|
init_cjs_shims();
|
|
@@ -12670,7 +13012,7 @@ async function userAddRun(factory, opts) {
|
|
|
12670
13012
|
// src/commands/user/search.ts
|
|
12671
13013
|
init_cjs_shims();
|
|
12672
13014
|
async function userSearchRun(factory, opts) {
|
|
12673
|
-
const result = opts.byUid ? await factory.
|
|
13015
|
+
const result = opts.byUid ? await factory.repos.user.findUserById(opts.query) : await factory.repos.user.searchUserById(opts.query);
|
|
12674
13016
|
if (!result.ok) {
|
|
12675
13017
|
return {
|
|
12676
13018
|
status: "error",
|
|
@@ -12698,7 +13040,7 @@ async function userSearchRun(factory, opts) {
|
|
|
12698
13040
|
|
|
12699
13041
|
// src/commands/user/index.ts
|
|
12700
13042
|
function NewCmdUser(factory) {
|
|
12701
|
-
const cmd = new
|
|
13043
|
+
const cmd = new import_commander8.Command("user").description(t("commands.user.desc"));
|
|
12702
13044
|
cmd.command("search").description(t("commands.user.searchDesc")).argument("<query>", t("commands.user.searchArgDesc")).option("--uid", t("commands.user.searchByUid")).action(async (query, opts) => {
|
|
12703
13045
|
const result = await userSearchRun(factory, { query, byUid: opts.uid });
|
|
12704
13046
|
handleCommand(result);
|
|
@@ -12837,6 +13179,23 @@ var ApiGateway = class {
|
|
|
12837
13179
|
friend_agent_id: friendAgentId
|
|
12838
13180
|
});
|
|
12839
13181
|
}
|
|
13182
|
+
/** POST /user/get_profile_by_conversation_id — auth required */
|
|
13183
|
+
getProfileByConversationId(conversationId, conversationType) {
|
|
13184
|
+
const auth3 = this.requireAuth();
|
|
13185
|
+
if (!auth3.ok) return Promise.resolve(auth3);
|
|
13186
|
+
const params = {
|
|
13187
|
+
uid: auth3.data,
|
|
13188
|
+
conversation_id: conversationId
|
|
13189
|
+
};
|
|
13190
|
+
if (conversationType !== void 0) {
|
|
13191
|
+
params.conversation_type = conversationType;
|
|
13192
|
+
}
|
|
13193
|
+
return this.client.performRequest(
|
|
13194
|
+
"/user/get_profile_by_conversation_id",
|
|
13195
|
+
"POST",
|
|
13196
|
+
params
|
|
13197
|
+
);
|
|
13198
|
+
}
|
|
12840
13199
|
};
|
|
12841
13200
|
|
|
12842
13201
|
// src/internal/api-client.ts
|
|
@@ -13049,6 +13408,33 @@ var IMClient = class {
|
|
|
13049
13408
|
console.log("[DEBUG]", ...args);
|
|
13050
13409
|
}
|
|
13051
13410
|
}
|
|
13411
|
+
/** Convert a protobuf Long to a readable string. */
|
|
13412
|
+
longStr(v) {
|
|
13413
|
+
if (!v) return "0";
|
|
13414
|
+
if (typeof v === "object" && "low" in v && "high" in v) {
|
|
13415
|
+
return v.toString();
|
|
13416
|
+
}
|
|
13417
|
+
return String(v);
|
|
13418
|
+
}
|
|
13419
|
+
/** Map operation code to a human-readable name. */
|
|
13420
|
+
opName(code) {
|
|
13421
|
+
const map = {
|
|
13422
|
+
1: "KeepAlive",
|
|
13423
|
+
1e3: "ClientOpen",
|
|
13424
|
+
1001: "ClientClose",
|
|
13425
|
+
1003: "ConversationQuery",
|
|
13426
|
+
2e3: "ConversationMessageSend",
|
|
13427
|
+
2001: "ConversationMessagePull",
|
|
13428
|
+
2005: "ConversationMessagePush",
|
|
13429
|
+
3e3: "Ack"
|
|
13430
|
+
};
|
|
13431
|
+
return map[code] ?? `Op(${code})`;
|
|
13432
|
+
}
|
|
13433
|
+
/** Format byte size for display. */
|
|
13434
|
+
size(n) {
|
|
13435
|
+
if (n < 1024) return `${n}B`;
|
|
13436
|
+
return `${(n / 1024).toFixed(1)}KB`;
|
|
13437
|
+
}
|
|
13052
13438
|
isConnected() {
|
|
13053
13439
|
return this.connected;
|
|
13054
13440
|
}
|
|
@@ -13056,9 +13442,11 @@ var IMClient = class {
|
|
|
13056
13442
|
async connect() {
|
|
13057
13443
|
return new Promise((resolve2, reject) => {
|
|
13058
13444
|
const wsUrl = this.buildWsUrl();
|
|
13445
|
+
this.debug(`\u2192 CONNECT ${wsUrl}, cid=${this.config.cid}`);
|
|
13059
13446
|
this.ws = new import_ws.default(wsUrl);
|
|
13060
13447
|
this.ws.binaryType = "arraybuffer";
|
|
13061
13448
|
this.ws.on("open", () => {
|
|
13449
|
+
this.debug(" \u2713 Connected");
|
|
13062
13450
|
clearTimeout(timeout);
|
|
13063
13451
|
this.connected = true;
|
|
13064
13452
|
this.onEvent({ type: "connected" });
|
|
@@ -13066,13 +13454,17 @@ var IMClient = class {
|
|
|
13066
13454
|
resolve2();
|
|
13067
13455
|
});
|
|
13068
13456
|
this.ws.on("message", (data) => {
|
|
13069
|
-
|
|
13457
|
+
const buf = Buffer.isBuffer(data) ? data : Buffer.from(data);
|
|
13458
|
+
this.debug(` \u2190 ${this.size(buf.length)} received`);
|
|
13459
|
+
this.handleResponse(buf);
|
|
13070
13460
|
});
|
|
13071
|
-
this.ws.on("close", (
|
|
13461
|
+
this.ws.on("close", (code, reason) => {
|
|
13462
|
+
this.debug(` \u2717 Closed (code: ${code}, reason: ${reason.toString()})`);
|
|
13072
13463
|
this.connected = false;
|
|
13073
13464
|
this.onEvent({ type: "disconnected", reason: reason.toString() });
|
|
13074
13465
|
});
|
|
13075
13466
|
this.ws.on("error", (err) => {
|
|
13467
|
+
this.debug(` \u2717 Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
13076
13468
|
this.onEvent({ type: "error", error: err });
|
|
13077
13469
|
reject(err);
|
|
13078
13470
|
});
|
|
@@ -13085,6 +13477,7 @@ var IMClient = class {
|
|
|
13085
13477
|
/** Close the IM connection. */
|
|
13086
13478
|
close() {
|
|
13087
13479
|
if (this.ws) {
|
|
13480
|
+
this.debug(`\u2192 CLOSE`);
|
|
13088
13481
|
this.ws.close();
|
|
13089
13482
|
this.ws = null;
|
|
13090
13483
|
this.connected = false;
|
|
@@ -13124,13 +13517,21 @@ var IMClient = class {
|
|
|
13124
13517
|
const handler = (ack) => {
|
|
13125
13518
|
clearTimeout(timeout);
|
|
13126
13519
|
this.ws?.off("message", onMessage);
|
|
13520
|
+
this.debug(
|
|
13521
|
+
` \u2713 Ack, msg=${ack.messageId}, blocked=${ack.blocked}, moderated=${ack.moderated}`
|
|
13522
|
+
);
|
|
13127
13523
|
resolve2(ack);
|
|
13128
13524
|
};
|
|
13129
13525
|
const onMessage = (data2) => {
|
|
13130
13526
|
const response = this.root.IMResponse.decode(new Uint8Array(data2));
|
|
13131
|
-
|
|
13132
|
-
|
|
13527
|
+
const op = response.operation;
|
|
13528
|
+
const blobLen = response.blob?.length ?? 0;
|
|
13529
|
+
if (op === this.root.IMOperation.Ack || op === this.root.IMOperation.ConversationMessageSend) {
|
|
13530
|
+
if (blobLen > 0) {
|
|
13133
13531
|
const ack = this.root.MsgAck.decode(new Uint8Array(response.blob));
|
|
13532
|
+
this.debug(
|
|
13533
|
+
` \u2190 ${this.opName(op)} ${this.size(blobLen)}, id=${this.longStr(ack.id)}, blocked=${ack.blocked}, ackTs=${this.longStr(ack.ackTs)}`
|
|
13534
|
+
);
|
|
13134
13535
|
handler({
|
|
13135
13536
|
messageId: String(ack.id),
|
|
13136
13537
|
conversationId: ack.conversationId,
|
|
@@ -13142,14 +13543,15 @@ var IMClient = class {
|
|
|
13142
13543
|
ackTs: ack.ackTs ? Number(ack.ackTs) : 0
|
|
13143
13544
|
});
|
|
13144
13545
|
} else {
|
|
13145
|
-
this.debug(
|
|
13546
|
+
this.debug(` \u2190 ${this.opName(op)} (empty blob, ignored)`);
|
|
13146
13547
|
}
|
|
13147
13548
|
} else {
|
|
13148
|
-
this.debug(
|
|
13549
|
+
this.debug(` \u2190 ${this.opName(op)} ${this.size(blobLen)} (ignored, not ack)`);
|
|
13149
13550
|
}
|
|
13150
13551
|
};
|
|
13151
13552
|
this.ws?.on("message", onMessage);
|
|
13152
13553
|
const data = this.root.IMRequest.encode(request).finish();
|
|
13554
|
+
this.debug(`\u2192 ${this.opName(2e3)} ${this.size(data.length)} to: ${targetCid}`);
|
|
13153
13555
|
this.ws?.send(Buffer.from(data));
|
|
13154
13556
|
});
|
|
13155
13557
|
}
|
|
@@ -13180,6 +13582,7 @@ var IMClient = class {
|
|
|
13180
13582
|
clearTimeout(timeout);
|
|
13181
13583
|
this.ws?.off("message", onMessage);
|
|
13182
13584
|
if (!response.blob || response.blob.length === 0) {
|
|
13585
|
+
this.debug(` \u2190 ${this.opName(2001)} (empty, no messages)`);
|
|
13183
13586
|
resolve2({
|
|
13184
13587
|
messages: [],
|
|
13185
13588
|
finished: true,
|
|
@@ -13194,6 +13597,9 @@ var IMClient = class {
|
|
|
13194
13597
|
return;
|
|
13195
13598
|
}
|
|
13196
13599
|
const msgList = this.root.MsgList.decode(new Uint8Array(response.blob));
|
|
13600
|
+
this.debug(
|
|
13601
|
+
` \u2190 ${this.opName(2001)}, ${msgList.msgs?.length ?? 0} msgs, finished=${msgList.finished}, lastId=${this.longStr(msgList.lastId)}`
|
|
13602
|
+
);
|
|
13197
13603
|
const debug = this.debugEnabled;
|
|
13198
13604
|
const messages3 = [];
|
|
13199
13605
|
for (const msg of msgList.msgs) {
|
|
@@ -13221,6 +13627,9 @@ var IMClient = class {
|
|
|
13221
13627
|
timestamp: msg.ackTs ? Number(msg.ackTs) : msg.jetTs ? Number(msg.jetTs) : 0
|
|
13222
13628
|
};
|
|
13223
13629
|
if (debug) {
|
|
13630
|
+
this.debug(
|
|
13631
|
+
` #${pulledMsg.id} ${pulledMsg.type} ${pulledMsg.role} from ${pulledMsg.senderCid} (${pulledMsg.content.length} chars, ${pulledMsg.extraContents.length} extras)`
|
|
13632
|
+
);
|
|
13224
13633
|
if (msg.blob && msg.blob.length > 0)
|
|
13225
13634
|
pulledMsg.rawBlob = Buffer.from(msg.blob).toString("base64");
|
|
13226
13635
|
if (msg.blobExtra && msg.blobExtra.length > 0)
|
|
@@ -13228,6 +13637,7 @@ var IMClient = class {
|
|
|
13228
13637
|
}
|
|
13229
13638
|
messages3.push(pulledMsg);
|
|
13230
13639
|
}
|
|
13640
|
+
this.debug(` \u2713 ${messages3.length} messages resolved`);
|
|
13231
13641
|
resolve2({
|
|
13232
13642
|
messages: messages3,
|
|
13233
13643
|
finished: msgList.finished,
|
|
@@ -13251,13 +13661,11 @@ var IMClient = class {
|
|
|
13251
13661
|
});
|
|
13252
13662
|
}
|
|
13253
13663
|
/** Query all conversations for the user. */
|
|
13254
|
-
async queryConversations(
|
|
13664
|
+
async queryConversations() {
|
|
13255
13665
|
if (!this.ws || !this.connected) {
|
|
13256
13666
|
throw new Error("Not connected to IM server");
|
|
13257
13667
|
}
|
|
13258
|
-
const queryBlob = this.root.ConversationQueryParams.create({
|
|
13259
|
-
limit: options3?.limit ?? 0
|
|
13260
|
-
});
|
|
13668
|
+
const queryBlob = this.root.ConversationQueryParams.create({});
|
|
13261
13669
|
const request = this.root.IMRequest.create({
|
|
13262
13670
|
operation: this.root.IMOperation.ConversationQuery,
|
|
13263
13671
|
cid: this.config.cid,
|
|
@@ -13274,6 +13682,7 @@ var IMClient = class {
|
|
|
13274
13682
|
clearTimeout(timeout);
|
|
13275
13683
|
this.ws?.off("message", onMessage);
|
|
13276
13684
|
if (!response.blob || response.blob.length === 0) {
|
|
13685
|
+
this.debug(` \u2190 ${this.opName(1003)} (empty, no conversations)`);
|
|
13277
13686
|
resolve2({
|
|
13278
13687
|
conversations: [],
|
|
13279
13688
|
limit: 0,
|
|
@@ -13284,6 +13693,7 @@ var IMClient = class {
|
|
|
13284
13693
|
return;
|
|
13285
13694
|
}
|
|
13286
13695
|
const list = this.root.ConversationList.decode(new Uint8Array(response.blob));
|
|
13696
|
+
this.debug(` \u2190 ${this.opName(1003)} ${list.convs?.length ?? 0} conversations`);
|
|
13287
13697
|
const debug = this.debugEnabled;
|
|
13288
13698
|
const conversations3 = [];
|
|
13289
13699
|
for (const conv of list.convs ?? []) {
|
|
@@ -13344,13 +13754,18 @@ var IMClient = class {
|
|
|
13344
13754
|
ts: Date.now()
|
|
13345
13755
|
});
|
|
13346
13756
|
const data = this.root.IMRequest.encode(request).finish();
|
|
13757
|
+
this.debug(`\u2192 ${this.opName(1e3)} ${this.size(data.length)}, cid=${this.config.cid}`);
|
|
13347
13758
|
this.ws.send(Buffer.from(data));
|
|
13348
13759
|
}
|
|
13349
13760
|
handleResponse(data) {
|
|
13350
13761
|
try {
|
|
13351
13762
|
const response = this.root.IMResponse.decode(new Uint8Array(data));
|
|
13352
|
-
|
|
13763
|
+
const op = response.operation;
|
|
13764
|
+
if (op === this.root.IMOperation.ConversationMessagePush) {
|
|
13353
13765
|
const msgList = this.root.MsgList.decode(new Uint8Array(response.blob));
|
|
13766
|
+
this.debug(
|
|
13767
|
+
` \u2190 ${this.opName(op)}, ${msgList.msgs?.length ?? 0} msgs, conv=${msgList.convId}`
|
|
13768
|
+
);
|
|
13354
13769
|
const debug = this.debugEnabled;
|
|
13355
13770
|
for (const msg of msgList.msgs) {
|
|
13356
13771
|
const extraContents = (msg.extraContents ?? []).map((ec) => {
|
|
@@ -13377,6 +13792,9 @@ var IMClient = class {
|
|
|
13377
13792
|
timestamp: msg.ackTs ? Number(msg.ackTs) : msg.jetTs ? Number(msg.jetTs) : 0
|
|
13378
13793
|
};
|
|
13379
13794
|
if (debug) {
|
|
13795
|
+
this.debug(
|
|
13796
|
+
` #${pulledMsg.id} ${pulledMsg.type} ${pulledMsg.role} from ${pulledMsg.senderCid} (${pulledMsg.content.length} chars)`
|
|
13797
|
+
);
|
|
13380
13798
|
if (msg.blob && msg.blob.length > 0)
|
|
13381
13799
|
pulledMsg.rawBlob = Buffer.from(msg.blob).toString("base64");
|
|
13382
13800
|
if (msg.blobExtra && msg.blobExtra.length > 0)
|
|
@@ -13387,6 +13805,11 @@ var IMClient = class {
|
|
|
13387
13805
|
message: pulledMsg
|
|
13388
13806
|
});
|
|
13389
13807
|
}
|
|
13808
|
+
} else {
|
|
13809
|
+
const blobLen = response.blob?.length ?? 0;
|
|
13810
|
+
this.debug(
|
|
13811
|
+
` \u2190 ${this.opName(op)} ${this.size(blobLen)} (unhandled, no handler registered)`
|
|
13812
|
+
);
|
|
13390
13813
|
}
|
|
13391
13814
|
} catch (err) {
|
|
13392
13815
|
this.debug("handleResponse decode error:", err instanceof Error ? err.message : String(err));
|
|
@@ -13401,20 +13824,28 @@ var IMGateway = class {
|
|
|
13401
13824
|
}
|
|
13402
13825
|
config;
|
|
13403
13826
|
dryRun = false;
|
|
13827
|
+
/** Log debug output when debug mode is enabled. */
|
|
13828
|
+
debug(...args) {
|
|
13829
|
+
if (this.config.debugEnabled) {
|
|
13830
|
+
console.log("[DEBUG]", ...args);
|
|
13831
|
+
}
|
|
13832
|
+
}
|
|
13404
13833
|
setDryRun(enabled) {
|
|
13405
13834
|
this.dryRun = enabled;
|
|
13406
13835
|
}
|
|
13407
13836
|
/** Execute a function with an IM connection, ensuring connect/close lifecycle. */
|
|
13408
13837
|
async withConnection(fn) {
|
|
13838
|
+
this.debug("\u2500\u2500 new connection \u2500\u2500");
|
|
13409
13839
|
const client = new IMClient(this.config, (event) => {
|
|
13410
|
-
if (event.type === "error"
|
|
13411
|
-
|
|
13840
|
+
if (event.type === "error") {
|
|
13841
|
+
this.debug(` \u2717 IM error: ${event.error.message}`);
|
|
13412
13842
|
}
|
|
13413
13843
|
});
|
|
13414
13844
|
try {
|
|
13415
13845
|
await client.connect();
|
|
13416
13846
|
return await fn(client);
|
|
13417
13847
|
} finally {
|
|
13848
|
+
this.debug("\u2500\u2500 connection closed \u2500\u2500");
|
|
13418
13849
|
client.close();
|
|
13419
13850
|
}
|
|
13420
13851
|
}
|
|
@@ -13509,7 +13940,7 @@ var IMGateway = class {
|
|
|
13509
13940
|
};
|
|
13510
13941
|
}
|
|
13511
13942
|
try {
|
|
13512
|
-
const result = await this.withConnection((client) => client.queryConversations(
|
|
13943
|
+
const result = await this.withConnection((client) => client.queryConversations());
|
|
13513
13944
|
let conversations3 = result.conversations.map((conv) => ({
|
|
13514
13945
|
id: conv.id,
|
|
13515
13946
|
name: conv.name,
|
|
@@ -13523,13 +13954,16 @@ var IMGateway = class {
|
|
|
13523
13954
|
extraDecoded: conv.extraDecoded,
|
|
13524
13955
|
rawExtra: conv.rawExtra
|
|
13525
13956
|
}));
|
|
13957
|
+
if (options3?.offset && options3.offset > 0) {
|
|
13958
|
+
conversations3 = conversations3.slice(options3.offset);
|
|
13959
|
+
}
|
|
13526
13960
|
if (options3?.limit && options3.limit > 0) {
|
|
13527
13961
|
conversations3 = conversations3.slice(0, options3.limit);
|
|
13528
13962
|
}
|
|
13529
13963
|
return {
|
|
13530
13964
|
status: "success",
|
|
13531
13965
|
code: "CONVERSATION_LIST" /* CONVERSATION_LIST */,
|
|
13532
|
-
message: conversations3.length > 0 ?
|
|
13966
|
+
message: conversations3.length > 0 ? `Conversations (${conversations3.length}):` : "No conversations found.",
|
|
13533
13967
|
data: { conversations: conversations3 }
|
|
13534
13968
|
};
|
|
13535
13969
|
} catch (error) {
|
|
@@ -13571,25 +14005,708 @@ var IMGateway = class {
|
|
|
13571
14005
|
}
|
|
13572
14006
|
};
|
|
13573
14007
|
|
|
14008
|
+
// src/internal/repository/index.ts
|
|
14009
|
+
init_cjs_shims();
|
|
14010
|
+
|
|
14011
|
+
// src/internal/repository/contact-repository.ts
|
|
14012
|
+
init_cjs_shims();
|
|
14013
|
+
var ApiContactRepository = class {
|
|
14014
|
+
constructor(gateway) {
|
|
14015
|
+
this.gateway = gateway;
|
|
14016
|
+
}
|
|
14017
|
+
gateway;
|
|
14018
|
+
async getLinksContacts() {
|
|
14019
|
+
return this.gateway.getLinksContacts();
|
|
14020
|
+
}
|
|
14021
|
+
invalidate() {
|
|
14022
|
+
}
|
|
14023
|
+
async sync() {
|
|
14024
|
+
}
|
|
14025
|
+
clear() {
|
|
14026
|
+
}
|
|
14027
|
+
async getStatus() {
|
|
14028
|
+
return { count: 0, lastSyncAt: null };
|
|
14029
|
+
}
|
|
14030
|
+
};
|
|
14031
|
+
var SqliteContactRepository = class {
|
|
14032
|
+
db;
|
|
14033
|
+
constructor(db) {
|
|
14034
|
+
this.db = db;
|
|
14035
|
+
}
|
|
14036
|
+
async getLinksContacts() {
|
|
14037
|
+
const rows = this.db.prepare(
|
|
14038
|
+
"SELECT owner_uid, data, cached_at FROM contacts_cache ORDER BY cached_at DESC LIMIT 1"
|
|
14039
|
+
).all();
|
|
14040
|
+
if (!rows || rows.length === 0) {
|
|
14041
|
+
return fail("NOT_FOUND" /* NOT_FOUND */, "Contacts not found in cache");
|
|
14042
|
+
}
|
|
14043
|
+
return ok(JSON.parse(rows[0].data));
|
|
14044
|
+
}
|
|
14045
|
+
upsert(ownerUid, data) {
|
|
14046
|
+
this.db.prepare("INSERT INTO contacts_cache (owner_uid, data, cached_at) VALUES (?, ?, ?)").run(ownerUid, JSON.stringify(data), Date.now());
|
|
14047
|
+
}
|
|
14048
|
+
invalidate() {
|
|
14049
|
+
this.db.exec("DELETE FROM contacts_cache");
|
|
14050
|
+
}
|
|
14051
|
+
async sync() {
|
|
14052
|
+
}
|
|
14053
|
+
clear() {
|
|
14054
|
+
this.db.exec("DELETE FROM contacts_cache");
|
|
14055
|
+
this.db.exec("DELETE FROM cache_metadata WHERE key = 'last_sync_contacts'");
|
|
14056
|
+
}
|
|
14057
|
+
async getStatus() {
|
|
14058
|
+
const count = this.db.prepare("SELECT COUNT(*) as c FROM contacts_cache").get();
|
|
14059
|
+
const meta = this.db.prepare("SELECT value FROM cache_metadata WHERE key = 'last_sync_contacts'").get();
|
|
14060
|
+
return {
|
|
14061
|
+
count: count.c,
|
|
14062
|
+
lastSyncAt: meta ? parseInt(meta.value, 10) : null
|
|
14063
|
+
};
|
|
14064
|
+
}
|
|
14065
|
+
};
|
|
14066
|
+
var CachedContactRepository = class {
|
|
14067
|
+
constructor(local, remote, ttlMs = 5 * 60 * 1e3) {
|
|
14068
|
+
this.local = local;
|
|
14069
|
+
this.remote = remote;
|
|
14070
|
+
this.ttlMs = ttlMs;
|
|
14071
|
+
}
|
|
14072
|
+
local;
|
|
14073
|
+
remote;
|
|
14074
|
+
ttlMs;
|
|
14075
|
+
async getLinksContacts() {
|
|
14076
|
+
const cached = await this.local.getLinksContacts();
|
|
14077
|
+
if (cached.ok) {
|
|
14078
|
+
const status = await this.local.getStatus();
|
|
14079
|
+
if (status.lastSyncAt !== null && Date.now() - status.lastSyncAt < this.ttlMs) {
|
|
14080
|
+
return cached;
|
|
14081
|
+
}
|
|
14082
|
+
}
|
|
14083
|
+
const remote = await this.remote.getLinksContacts();
|
|
14084
|
+
if (remote.ok) {
|
|
14085
|
+
this.local.upsert("", remote.data);
|
|
14086
|
+
this.local.db.prepare("INSERT OR REPLACE INTO cache_metadata (key, value) VALUES (?, ?)").run("last_sync_contacts", String(Date.now()));
|
|
14087
|
+
}
|
|
14088
|
+
return remote;
|
|
14089
|
+
}
|
|
14090
|
+
invalidate() {
|
|
14091
|
+
this.local.invalidate();
|
|
14092
|
+
}
|
|
14093
|
+
async sync() {
|
|
14094
|
+
const result = await this.remote.getLinksContacts();
|
|
14095
|
+
if (result.ok) {
|
|
14096
|
+
this.local.upsert("", result.data);
|
|
14097
|
+
this.local.db.prepare("INSERT OR REPLACE INTO cache_metadata (key, value) VALUES (?, ?)").run("last_sync_contacts", String(Date.now()));
|
|
14098
|
+
}
|
|
14099
|
+
}
|
|
14100
|
+
clear() {
|
|
14101
|
+
this.local.clear();
|
|
14102
|
+
}
|
|
14103
|
+
async getStatus() {
|
|
14104
|
+
return this.local.getStatus();
|
|
14105
|
+
}
|
|
14106
|
+
};
|
|
14107
|
+
|
|
14108
|
+
// src/internal/repository/conversation-repository.ts
|
|
14109
|
+
init_cjs_shims();
|
|
14110
|
+
var ApiConversationRepository = class {
|
|
14111
|
+
constructor(gateway, imGateway) {
|
|
14112
|
+
this.gateway = gateway;
|
|
14113
|
+
this.imGateway = imGateway;
|
|
14114
|
+
}
|
|
14115
|
+
gateway;
|
|
14116
|
+
imGateway;
|
|
14117
|
+
async queryAll(options3) {
|
|
14118
|
+
const result = await this.imGateway.queryConversations(options3);
|
|
14119
|
+
if (result.status === "error") {
|
|
14120
|
+
return fail(result.code, result.message);
|
|
14121
|
+
}
|
|
14122
|
+
return ok(result.data?.conversations ?? []);
|
|
14123
|
+
}
|
|
14124
|
+
async getProfile(conversationId, conversationType) {
|
|
14125
|
+
return this.gateway.getProfileByConversationId(conversationId, conversationType);
|
|
14126
|
+
}
|
|
14127
|
+
async searchByUid(uid) {
|
|
14128
|
+
const listResult = await this.imGateway.queryConversations({ limit: 0, offset: 0 });
|
|
14129
|
+
if (listResult.status === "error") {
|
|
14130
|
+
return fail(listResult.code, listResult.message);
|
|
14131
|
+
}
|
|
14132
|
+
const conversations3 = listResult.data?.conversations ?? [];
|
|
14133
|
+
const results = [];
|
|
14134
|
+
for (const conv of conversations3) {
|
|
14135
|
+
const profileResult = await this.gateway.getProfileByConversationId(conv.id);
|
|
14136
|
+
if (!profileResult.ok) continue;
|
|
14137
|
+
const hasTarget = profileResult.data.users.some((u) => u.uid === uid);
|
|
14138
|
+
if (hasTarget) {
|
|
14139
|
+
results.push(profileResult.data);
|
|
14140
|
+
}
|
|
14141
|
+
}
|
|
14142
|
+
return ok(results);
|
|
14143
|
+
}
|
|
14144
|
+
invalidate(_conversationId) {
|
|
14145
|
+
}
|
|
14146
|
+
async sync() {
|
|
14147
|
+
}
|
|
14148
|
+
clear() {
|
|
14149
|
+
}
|
|
14150
|
+
async getStatus() {
|
|
14151
|
+
return { count: 0, lastSyncAt: null };
|
|
14152
|
+
}
|
|
14153
|
+
};
|
|
14154
|
+
var SqliteConversationRepository = class {
|
|
14155
|
+
db;
|
|
14156
|
+
constructor(db) {
|
|
14157
|
+
this.db = db;
|
|
14158
|
+
}
|
|
14159
|
+
queryAll(_options) {
|
|
14160
|
+
return Promise.resolve(ok([]));
|
|
14161
|
+
}
|
|
14162
|
+
getProfile(conversationId) {
|
|
14163
|
+
const row = this.db.prepare("SELECT data FROM conversation_profiles WHERE conversation_id = ?").get(conversationId);
|
|
14164
|
+
if (!row) {
|
|
14165
|
+
return Promise.resolve(
|
|
14166
|
+
fail("NOT_FOUND" /* NOT_FOUND */, "Conversation profile not found in cache")
|
|
14167
|
+
);
|
|
14168
|
+
}
|
|
14169
|
+
return Promise.resolve(ok(JSON.parse(row.data)));
|
|
14170
|
+
}
|
|
14171
|
+
searchByUid(uid) {
|
|
14172
|
+
const rows = this.db.prepare(
|
|
14173
|
+
"SELECT data FROM conversation_profiles WHERE user_ids LIKE ? OR user_ids LIKE ? OR user_ids LIKE ? OR user_ids = ?"
|
|
14174
|
+
).all(`%${uid},%`, `%,${uid},%`, `%,${uid}`, uid);
|
|
14175
|
+
const results = rows.map((r) => JSON.parse(r.data));
|
|
14176
|
+
return Promise.resolve(ok(results));
|
|
14177
|
+
}
|
|
14178
|
+
upsertProfile(conversationId, profile) {
|
|
14179
|
+
const user_ids = profile.users.map((u) => u.uid).join(",");
|
|
14180
|
+
const cached_at = Date.now();
|
|
14181
|
+
const data = JSON.stringify(profile);
|
|
14182
|
+
this.db.prepare(
|
|
14183
|
+
"INSERT INTO conversation_profiles (conversation_id, data, user_ids, cached_at) VALUES (?, ?, ?, ?) ON CONFLICT(conversation_id) DO UPDATE SET data=?, user_ids=?, cached_at=?"
|
|
14184
|
+
).run(conversationId, data, user_ids, cached_at, data, user_ids, cached_at);
|
|
14185
|
+
}
|
|
14186
|
+
invalidate(conversationId) {
|
|
14187
|
+
this.db.prepare("DELETE FROM conversation_profiles WHERE conversation_id = ?").run(conversationId);
|
|
14188
|
+
}
|
|
14189
|
+
sync() {
|
|
14190
|
+
return Promise.resolve();
|
|
14191
|
+
}
|
|
14192
|
+
clear() {
|
|
14193
|
+
this.db.exec("DELETE FROM conversation_profiles");
|
|
14194
|
+
this.db.exec("DELETE FROM cache_metadata WHERE key = 'last_sync_conversations'");
|
|
14195
|
+
}
|
|
14196
|
+
getStatus() {
|
|
14197
|
+
const count = this.db.prepare("SELECT COUNT(*) as c FROM conversation_profiles").get();
|
|
14198
|
+
const meta = this.db.prepare("SELECT value FROM cache_metadata WHERE key = 'last_sync_conversations'").get();
|
|
14199
|
+
return Promise.resolve({
|
|
14200
|
+
count: count.c,
|
|
14201
|
+
lastSyncAt: meta ? parseInt(meta.value, 10) : null
|
|
14202
|
+
});
|
|
14203
|
+
}
|
|
14204
|
+
};
|
|
14205
|
+
var CachedConversationRepository = class {
|
|
14206
|
+
constructor(local, remote) {
|
|
14207
|
+
this.local = local;
|
|
14208
|
+
this.remote = remote;
|
|
14209
|
+
}
|
|
14210
|
+
local;
|
|
14211
|
+
remote;
|
|
14212
|
+
syncInProgress = false;
|
|
14213
|
+
async queryAll(options3) {
|
|
14214
|
+
return this.remote.queryAll(options3);
|
|
14215
|
+
}
|
|
14216
|
+
async getProfile(conversationId, conversationType) {
|
|
14217
|
+
const cached = await this.local.getProfile(conversationId);
|
|
14218
|
+
if (cached.ok) return cached;
|
|
14219
|
+
const remote = await this.remote.getProfile(conversationId, conversationType);
|
|
14220
|
+
if (remote.ok) {
|
|
14221
|
+
this.local.upsertProfile(conversationId, remote.data);
|
|
14222
|
+
}
|
|
14223
|
+
return remote;
|
|
14224
|
+
}
|
|
14225
|
+
async searchByUid(uid) {
|
|
14226
|
+
const cached = await this.local.searchByUid(uid);
|
|
14227
|
+
if (cached.ok && cached.data.length > 0) return cached;
|
|
14228
|
+
await this.ensureSynced();
|
|
14229
|
+
const retry = await this.local.searchByUid(uid);
|
|
14230
|
+
return retry;
|
|
14231
|
+
}
|
|
14232
|
+
async ensureSynced() {
|
|
14233
|
+
if (this.syncInProgress) return;
|
|
14234
|
+
const status = await this.local.getStatus();
|
|
14235
|
+
const isFresh = status.lastSyncAt !== null && Date.now() - status.lastSyncAt < 5 * 60 * 1e3;
|
|
14236
|
+
if (isFresh) return;
|
|
14237
|
+
this.syncInProgress = true;
|
|
14238
|
+
try {
|
|
14239
|
+
await this.sync();
|
|
14240
|
+
} finally {
|
|
14241
|
+
this.syncInProgress = false;
|
|
14242
|
+
}
|
|
14243
|
+
}
|
|
14244
|
+
async sync() {
|
|
14245
|
+
const convResult = await this.remote.queryAll({ limit: 0, offset: 0 });
|
|
14246
|
+
if (!convResult.ok || !convResult.data) return;
|
|
14247
|
+
for (const conv of convResult.data) {
|
|
14248
|
+
const profileResult = await this.remote.getProfile(conv.id);
|
|
14249
|
+
if (profileResult.ok) {
|
|
14250
|
+
this.local.upsertProfile(conv.id, profileResult.data);
|
|
14251
|
+
}
|
|
14252
|
+
}
|
|
14253
|
+
this.local.db.prepare("INSERT OR REPLACE INTO cache_metadata (key, value) VALUES (?, ?)").run("last_sync_conversations", String(Date.now()));
|
|
14254
|
+
}
|
|
14255
|
+
invalidate(conversationId) {
|
|
14256
|
+
this.local.invalidate(conversationId);
|
|
14257
|
+
}
|
|
14258
|
+
clear() {
|
|
14259
|
+
this.local.clear();
|
|
14260
|
+
}
|
|
14261
|
+
async getStatus() {
|
|
14262
|
+
return this.local.getStatus();
|
|
14263
|
+
}
|
|
14264
|
+
};
|
|
14265
|
+
|
|
14266
|
+
// src/internal/repository/message-repository.ts
|
|
14267
|
+
init_cjs_shims();
|
|
14268
|
+
var ApiMessageRepository = class {
|
|
14269
|
+
constructor(imGateway) {
|
|
14270
|
+
this.imGateway = imGateway;
|
|
14271
|
+
}
|
|
14272
|
+
imGateway;
|
|
14273
|
+
async pullMessages(conversationId, options3) {
|
|
14274
|
+
const result = await this.imGateway.pullMessages(conversationId, options3);
|
|
14275
|
+
if (result.status === "error") {
|
|
14276
|
+
return fail(result.code, result.message);
|
|
14277
|
+
}
|
|
14278
|
+
return ok({
|
|
14279
|
+
messages: result.data?.messages ?? [],
|
|
14280
|
+
finished: result.data?.finished ?? true,
|
|
14281
|
+
lastId: result.data?.lastId ?? ""
|
|
14282
|
+
});
|
|
14283
|
+
}
|
|
14284
|
+
invalidate(_conversationId) {
|
|
14285
|
+
}
|
|
14286
|
+
async sync(_conversationId) {
|
|
14287
|
+
}
|
|
14288
|
+
clear() {
|
|
14289
|
+
}
|
|
14290
|
+
};
|
|
14291
|
+
var SqliteMessageRepository = class {
|
|
14292
|
+
db;
|
|
14293
|
+
constructor(db) {
|
|
14294
|
+
this.db = db;
|
|
14295
|
+
}
|
|
14296
|
+
async pullMessages(conversationId, options3) {
|
|
14297
|
+
const limit = options3?.limit ?? 50;
|
|
14298
|
+
const fromId = options3?.fromMessageId;
|
|
14299
|
+
let sql = "SELECT message_id, data FROM messages_cache WHERE conversation_id = ?";
|
|
14300
|
+
const params = [conversationId];
|
|
14301
|
+
if (fromId) {
|
|
14302
|
+
if (options3?.direction === "newer") {
|
|
14303
|
+
sql += " AND message_id > ?";
|
|
14304
|
+
params.push(fromId);
|
|
14305
|
+
} else {
|
|
14306
|
+
sql += " AND message_id < ?";
|
|
14307
|
+
params.push(fromId);
|
|
14308
|
+
}
|
|
14309
|
+
}
|
|
14310
|
+
sql += " ORDER BY message_id DESC LIMIT ?";
|
|
14311
|
+
params.push(limit);
|
|
14312
|
+
const rows = this.db.prepare(sql).all(...params);
|
|
14313
|
+
if (rows.length === 0) {
|
|
14314
|
+
return fail("NOT_FOUND" /* NOT_FOUND */, "Messages not found in cache");
|
|
14315
|
+
}
|
|
14316
|
+
return ok({
|
|
14317
|
+
messages: rows.map((r) => JSON.parse(r.data)),
|
|
14318
|
+
finished: rows.length < limit,
|
|
14319
|
+
lastId: rows[rows.length - 1]?.message_id ?? ""
|
|
14320
|
+
});
|
|
14321
|
+
}
|
|
14322
|
+
upsert(conversationId, messageId, data) {
|
|
14323
|
+
this.db.prepare(
|
|
14324
|
+
"INSERT INTO messages_cache (conversation_id, message_id, data, cached_at) VALUES (?, ?, ?, ?) ON CONFLICT(conversation_id, message_id) DO UPDATE SET data=?, cached_at=?"
|
|
14325
|
+
).run(
|
|
14326
|
+
conversationId,
|
|
14327
|
+
messageId,
|
|
14328
|
+
JSON.stringify(data),
|
|
14329
|
+
Date.now(),
|
|
14330
|
+
JSON.stringify(data),
|
|
14331
|
+
Date.now()
|
|
14332
|
+
);
|
|
14333
|
+
}
|
|
14334
|
+
invalidate(conversationId) {
|
|
14335
|
+
this.db.prepare("DELETE FROM messages_cache WHERE conversation_id = ?").run(conversationId);
|
|
14336
|
+
}
|
|
14337
|
+
async sync(_conversationId) {
|
|
14338
|
+
}
|
|
14339
|
+
clear() {
|
|
14340
|
+
this.db.exec("DELETE FROM messages_cache");
|
|
14341
|
+
}
|
|
14342
|
+
};
|
|
14343
|
+
var CachedMessageRepository = class {
|
|
14344
|
+
constructor(local, remote) {
|
|
14345
|
+
this.local = local;
|
|
14346
|
+
this.remote = remote;
|
|
14347
|
+
}
|
|
14348
|
+
local;
|
|
14349
|
+
remote;
|
|
14350
|
+
async pullMessages(conversationId, options3) {
|
|
14351
|
+
const cached = await this.local.pullMessages(conversationId, options3);
|
|
14352
|
+
if (cached.ok) return cached;
|
|
14353
|
+
const remote = await this.remote.pullMessages(conversationId, options3);
|
|
14354
|
+
if (remote.ok) {
|
|
14355
|
+
for (const msg of remote.data.messages) {
|
|
14356
|
+
const messageId = msg.id;
|
|
14357
|
+
if (messageId) {
|
|
14358
|
+
this.local.upsert(conversationId, messageId, msg);
|
|
14359
|
+
}
|
|
14360
|
+
}
|
|
14361
|
+
}
|
|
14362
|
+
return remote;
|
|
14363
|
+
}
|
|
14364
|
+
invalidate(conversationId) {
|
|
14365
|
+
this.local.invalidate(conversationId);
|
|
14366
|
+
}
|
|
14367
|
+
async sync(conversationId) {
|
|
14368
|
+
const result = await this.remote.pullMessages(conversationId, { limit: 100 });
|
|
14369
|
+
if (result.ok) {
|
|
14370
|
+
for (const msg of result.data.messages) {
|
|
14371
|
+
const messageId = msg.id;
|
|
14372
|
+
if (messageId) {
|
|
14373
|
+
this.local.upsert(conversationId, messageId, msg);
|
|
14374
|
+
}
|
|
14375
|
+
}
|
|
14376
|
+
}
|
|
14377
|
+
}
|
|
14378
|
+
clear() {
|
|
14379
|
+
this.local.clear();
|
|
14380
|
+
}
|
|
14381
|
+
};
|
|
14382
|
+
|
|
14383
|
+
// src/internal/repository/relation-repository.ts
|
|
14384
|
+
init_cjs_shims();
|
|
14385
|
+
var ApiRelationRepository = class {
|
|
14386
|
+
constructor(gateway) {
|
|
14387
|
+
this.gateway = gateway;
|
|
14388
|
+
}
|
|
14389
|
+
gateway;
|
|
14390
|
+
async getLinkNameType(friendUid) {
|
|
14391
|
+
return this.gateway.getLinkNameType(friendUid);
|
|
14392
|
+
}
|
|
14393
|
+
invalidate(_friendUid) {
|
|
14394
|
+
}
|
|
14395
|
+
async sync() {
|
|
14396
|
+
}
|
|
14397
|
+
clear() {
|
|
14398
|
+
}
|
|
14399
|
+
};
|
|
14400
|
+
var SqliteRelationRepository = class {
|
|
14401
|
+
db;
|
|
14402
|
+
constructor(db) {
|
|
14403
|
+
this.db = db;
|
|
14404
|
+
}
|
|
14405
|
+
async getLinkNameType(friendUid) {
|
|
14406
|
+
const row = this.db.prepare("SELECT name, type, cached_at FROM relations_cache WHERE friend_uid = ?").get(friendUid);
|
|
14407
|
+
if (!row) return fail("NOT_FOUND" /* NOT_FOUND */, "Relation not found in cache");
|
|
14408
|
+
return ok({ name: row.name, type: row.type });
|
|
14409
|
+
}
|
|
14410
|
+
upsert(friendUid, name, type) {
|
|
14411
|
+
this.db.prepare(
|
|
14412
|
+
"INSERT OR REPLACE INTO relations_cache (friend_uid, name, type, cached_at) VALUES (?, ?, ?, ?)"
|
|
14413
|
+
).run(friendUid, name, type, Date.now());
|
|
14414
|
+
}
|
|
14415
|
+
invalidate(friendUid) {
|
|
14416
|
+
this.db.prepare("DELETE FROM relations_cache WHERE friend_uid = ?").run(friendUid);
|
|
14417
|
+
}
|
|
14418
|
+
async sync() {
|
|
14419
|
+
}
|
|
14420
|
+
clear() {
|
|
14421
|
+
this.db.exec("DELETE FROM relations_cache");
|
|
14422
|
+
}
|
|
14423
|
+
};
|
|
14424
|
+
var CachedRelationRepository = class {
|
|
14425
|
+
constructor(local, remote, ttlMs = 5 * 60 * 1e3) {
|
|
14426
|
+
this.local = local;
|
|
14427
|
+
this.remote = remote;
|
|
14428
|
+
this.ttlMs = ttlMs;
|
|
14429
|
+
}
|
|
14430
|
+
local;
|
|
14431
|
+
remote;
|
|
14432
|
+
ttlMs;
|
|
14433
|
+
async getLinkNameType(friendUid) {
|
|
14434
|
+
const row = this.local.db.prepare("SELECT name, type, cached_at FROM relations_cache WHERE friend_uid = ?").get(friendUid);
|
|
14435
|
+
if (row && Date.now() - row.cached_at < this.ttlMs) {
|
|
14436
|
+
return ok({ name: row.name, type: row.type });
|
|
14437
|
+
}
|
|
14438
|
+
const remote = await this.remote.getLinkNameType(friendUid);
|
|
14439
|
+
if (remote.ok) {
|
|
14440
|
+
this.local.upsert(friendUid, remote.data.name, remote.data.type);
|
|
14441
|
+
}
|
|
14442
|
+
return remote;
|
|
14443
|
+
}
|
|
14444
|
+
invalidate(friendUid) {
|
|
14445
|
+
this.local.invalidate(friendUid);
|
|
14446
|
+
}
|
|
14447
|
+
async sync() {
|
|
14448
|
+
}
|
|
14449
|
+
clear() {
|
|
14450
|
+
this.local.clear();
|
|
14451
|
+
}
|
|
14452
|
+
};
|
|
14453
|
+
|
|
14454
|
+
// src/internal/repository/sqlite.ts
|
|
14455
|
+
init_cjs_shims();
|
|
14456
|
+
var import_node_path5 = require("path");
|
|
14457
|
+
var import_better_sqlite3 = __toESM(require("better-sqlite3"));
|
|
14458
|
+
var SCHEMA_VERSION = 1;
|
|
14459
|
+
var CREATE_TABLES = `
|
|
14460
|
+
CREATE TABLE IF NOT EXISTS conversation_profiles (
|
|
14461
|
+
conversation_id TEXT PRIMARY KEY,
|
|
14462
|
+
data TEXT NOT NULL,
|
|
14463
|
+
user_ids TEXT NOT NULL,
|
|
14464
|
+
cached_at INTEGER NOT NULL
|
|
14465
|
+
);
|
|
14466
|
+
CREATE INDEX IF NOT EXISTS idx_conv_user_ids ON conversation_profiles(user_ids);
|
|
14467
|
+
|
|
14468
|
+
CREATE TABLE IF NOT EXISTS contacts_cache (
|
|
14469
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
14470
|
+
owner_uid TEXT NOT NULL,
|
|
14471
|
+
data TEXT NOT NULL,
|
|
14472
|
+
cached_at INTEGER NOT NULL
|
|
14473
|
+
);
|
|
14474
|
+
CREATE INDEX IF NOT EXISTS idx_contacts_owner ON contacts_cache(owner_uid);
|
|
14475
|
+
|
|
14476
|
+
CREATE TABLE IF NOT EXISTS user_profiles (
|
|
14477
|
+
uid TEXT PRIMARY KEY,
|
|
14478
|
+
data TEXT NOT NULL,
|
|
14479
|
+
cached_at INTEGER NOT NULL
|
|
14480
|
+
);
|
|
14481
|
+
|
|
14482
|
+
CREATE TABLE IF NOT EXISTS relations_cache (
|
|
14483
|
+
friend_uid TEXT PRIMARY KEY,
|
|
14484
|
+
name TEXT,
|
|
14485
|
+
type INTEGER,
|
|
14486
|
+
cached_at INTEGER NOT NULL
|
|
14487
|
+
);
|
|
14488
|
+
|
|
14489
|
+
CREATE TABLE IF NOT EXISTS messages_cache (
|
|
14490
|
+
conversation_id TEXT NOT NULL,
|
|
14491
|
+
message_id TEXT NOT NULL,
|
|
14492
|
+
data TEXT NOT NULL,
|
|
14493
|
+
cached_at INTEGER NOT NULL,
|
|
14494
|
+
PRIMARY KEY (conversation_id, message_id)
|
|
14495
|
+
);
|
|
14496
|
+
CREATE INDEX IF NOT EXISTS idx_msg_conv ON messages_cache(conversation_id);
|
|
14497
|
+
|
|
14498
|
+
CREATE TABLE IF NOT EXISTS cache_metadata (
|
|
14499
|
+
key TEXT PRIMARY KEY,
|
|
14500
|
+
value TEXT
|
|
14501
|
+
);
|
|
14502
|
+
`;
|
|
14503
|
+
function resolveDbPaths(configDir, uid) {
|
|
14504
|
+
return {
|
|
14505
|
+
dbFile: (0, import_node_path5.join)(configDir, `cache-${uid}.db`)
|
|
14506
|
+
};
|
|
14507
|
+
}
|
|
14508
|
+
function openDatabase(dbPath) {
|
|
14509
|
+
const db = new import_better_sqlite3.default(dbPath);
|
|
14510
|
+
db.pragma("journal_mode = WAL");
|
|
14511
|
+
db.pragma("foreign_keys = ON");
|
|
14512
|
+
db.exec(CREATE_TABLES);
|
|
14513
|
+
ensureVersion(db);
|
|
14514
|
+
return db;
|
|
14515
|
+
}
|
|
14516
|
+
function closeDatabase(db) {
|
|
14517
|
+
db.close();
|
|
14518
|
+
}
|
|
14519
|
+
function ensureVersion(db) {
|
|
14520
|
+
const row = db.prepare("SELECT value FROM cache_metadata WHERE key = 'schema_version'").get();
|
|
14521
|
+
const current = row ? parseInt(row.value, 10) : 0;
|
|
14522
|
+
if (current < SCHEMA_VERSION) {
|
|
14523
|
+
db.prepare("INSERT OR REPLACE INTO cache_metadata (key, value) VALUES (?, ?)").run(
|
|
14524
|
+
"schema_version",
|
|
14525
|
+
String(SCHEMA_VERSION)
|
|
14526
|
+
);
|
|
14527
|
+
}
|
|
14528
|
+
}
|
|
14529
|
+
|
|
14530
|
+
// src/internal/repository/user-repository.ts
|
|
14531
|
+
init_cjs_shims();
|
|
14532
|
+
var ApiUserRepository = class {
|
|
14533
|
+
constructor(gateway) {
|
|
14534
|
+
this.gateway = gateway;
|
|
14535
|
+
}
|
|
14536
|
+
gateway;
|
|
14537
|
+
findUserById(id) {
|
|
14538
|
+
return this.gateway.findUserById(id);
|
|
14539
|
+
}
|
|
14540
|
+
searchUserById(id) {
|
|
14541
|
+
return this.gateway.searchUserById(id);
|
|
14542
|
+
}
|
|
14543
|
+
getUserAgentProfile(friendUid, agentId) {
|
|
14544
|
+
return this.gateway.getUserAgentProfile(friendUid, agentId);
|
|
14545
|
+
}
|
|
14546
|
+
invalidate(_uid) {
|
|
14547
|
+
}
|
|
14548
|
+
async sync() {
|
|
14549
|
+
}
|
|
14550
|
+
clear() {
|
|
14551
|
+
}
|
|
14552
|
+
};
|
|
14553
|
+
var SqliteUserRepository = class {
|
|
14554
|
+
db;
|
|
14555
|
+
constructor(db) {
|
|
14556
|
+
this.db = db;
|
|
14557
|
+
}
|
|
14558
|
+
async findUserById(id) {
|
|
14559
|
+
const row = this.db.prepare("SELECT data FROM user_profiles WHERE uid = ?").get(id);
|
|
14560
|
+
if (!row) return fail("NOT_FOUND" /* NOT_FOUND */, "User not found in cache");
|
|
14561
|
+
return ok(JSON.parse(row.data));
|
|
14562
|
+
}
|
|
14563
|
+
async searchUserById(id) {
|
|
14564
|
+
const row = this.db.prepare("SELECT data FROM user_profiles WHERE uid = ?").get(id);
|
|
14565
|
+
if (!row) return fail("NOT_FOUND" /* NOT_FOUND */, "User not found in cache");
|
|
14566
|
+
const data = JSON.parse(row.data);
|
|
14567
|
+
return ok({
|
|
14568
|
+
id: data.id,
|
|
14569
|
+
uid: data.uid,
|
|
14570
|
+
nickname: data.nickname,
|
|
14571
|
+
avatar: data.avatar,
|
|
14572
|
+
agent: data.agent
|
|
14573
|
+
});
|
|
14574
|
+
}
|
|
14575
|
+
async getUserAgentProfile(friendUid, _agentId) {
|
|
14576
|
+
const row = this.db.prepare("SELECT data FROM user_profiles WHERE uid = ?").get(friendUid);
|
|
14577
|
+
if (!row) return fail("NOT_FOUND" /* NOT_FOUND */, "User profile not found in cache");
|
|
14578
|
+
return ok(JSON.parse(row.data));
|
|
14579
|
+
}
|
|
14580
|
+
upsert(uid, data) {
|
|
14581
|
+
this.db.prepare("INSERT OR REPLACE INTO user_profiles (uid, data, cached_at) VALUES (?, ?, ?)").run(uid, JSON.stringify(data), Date.now());
|
|
14582
|
+
}
|
|
14583
|
+
invalidate(uid) {
|
|
14584
|
+
this.db.prepare("DELETE FROM user_profiles WHERE uid = ?").run(uid);
|
|
14585
|
+
}
|
|
14586
|
+
async sync() {
|
|
14587
|
+
}
|
|
14588
|
+
clear() {
|
|
14589
|
+
this.db.exec("DELETE FROM user_profiles");
|
|
14590
|
+
}
|
|
14591
|
+
};
|
|
14592
|
+
var CachedUserRepository = class {
|
|
14593
|
+
constructor(local, remote, ttlMs = 60 * 60 * 1e3) {
|
|
14594
|
+
this.local = local;
|
|
14595
|
+
this.remote = remote;
|
|
14596
|
+
this.ttlMs = ttlMs;
|
|
14597
|
+
}
|
|
14598
|
+
local;
|
|
14599
|
+
remote;
|
|
14600
|
+
ttlMs;
|
|
14601
|
+
async findUserById(id) {
|
|
14602
|
+
return this.fetchWithCache(
|
|
14603
|
+
id,
|
|
14604
|
+
() => this.remote.findUserById(id),
|
|
14605
|
+
(data) => this.local.upsert(id, data)
|
|
14606
|
+
);
|
|
14607
|
+
}
|
|
14608
|
+
async searchUserById(id) {
|
|
14609
|
+
return this.fetchWithCache(
|
|
14610
|
+
id,
|
|
14611
|
+
() => this.remote.searchUserById(id),
|
|
14612
|
+
(data) => {
|
|
14613
|
+
this.local.upsert(id, {
|
|
14614
|
+
id: data.id,
|
|
14615
|
+
uid: data.uid,
|
|
14616
|
+
nickname: data.nickname,
|
|
14617
|
+
avatar: data.avatar,
|
|
14618
|
+
title: "",
|
|
14619
|
+
link_type: 0,
|
|
14620
|
+
sex: 0,
|
|
14621
|
+
address: "",
|
|
14622
|
+
status: 0,
|
|
14623
|
+
agent: data.agent
|
|
14624
|
+
});
|
|
14625
|
+
}
|
|
14626
|
+
);
|
|
14627
|
+
}
|
|
14628
|
+
async getUserAgentProfile(friendUid, agentId) {
|
|
14629
|
+
return this.fetchWithCache(
|
|
14630
|
+
friendUid,
|
|
14631
|
+
() => this.remote.getUserAgentProfile(friendUid, agentId),
|
|
14632
|
+
(data) => this.local.upsert(friendUid, data)
|
|
14633
|
+
);
|
|
14634
|
+
}
|
|
14635
|
+
async fetchWithCache(uid, fetch2, store) {
|
|
14636
|
+
const row = this.local.db.prepare("SELECT data, cached_at FROM user_profiles WHERE uid = ?").get(uid);
|
|
14637
|
+
if (row && Date.now() - row.cached_at < this.ttlMs) {
|
|
14638
|
+
return ok(JSON.parse(row.data));
|
|
14639
|
+
}
|
|
14640
|
+
const remote = await fetch2();
|
|
14641
|
+
if (remote.ok) {
|
|
14642
|
+
store(remote.data);
|
|
14643
|
+
}
|
|
14644
|
+
return remote;
|
|
14645
|
+
}
|
|
14646
|
+
invalidate(uid) {
|
|
14647
|
+
this.local.invalidate(uid);
|
|
14648
|
+
}
|
|
14649
|
+
async sync() {
|
|
14650
|
+
}
|
|
14651
|
+
clear() {
|
|
14652
|
+
this.local.clear();
|
|
14653
|
+
}
|
|
14654
|
+
};
|
|
14655
|
+
|
|
14656
|
+
// src/internal/repository/index.ts
|
|
14657
|
+
function createRepositories(configDir, uid, gateway, imGateway) {
|
|
14658
|
+
const paths = resolveDbPaths(configDir, uid);
|
|
14659
|
+
const db = openDatabase(paths.dbFile);
|
|
14660
|
+
const sqliteConv = new SqliteConversationRepository(db);
|
|
14661
|
+
const sqliteContact = new SqliteContactRepository(db);
|
|
14662
|
+
const sqliteUser = new SqliteUserRepository(db);
|
|
14663
|
+
const sqliteRelation = new SqliteRelationRepository(db);
|
|
14664
|
+
const sqliteMessage = new SqliteMessageRepository(db);
|
|
14665
|
+
const apiConv = new ApiConversationRepository(gateway, imGateway);
|
|
14666
|
+
const apiContact = new ApiContactRepository(gateway);
|
|
14667
|
+
const apiUser = new ApiUserRepository(gateway);
|
|
14668
|
+
const apiRelation = new ApiRelationRepository(gateway);
|
|
14669
|
+
const apiMessage = new ApiMessageRepository(imGateway);
|
|
14670
|
+
const conversation = new CachedConversationRepository(sqliteConv, apiConv);
|
|
14671
|
+
const contact = new CachedContactRepository(sqliteContact, apiContact);
|
|
14672
|
+
const user = new CachedUserRepository(sqliteUser, apiUser);
|
|
14673
|
+
const relation = new CachedRelationRepository(sqliteRelation, apiRelation);
|
|
14674
|
+
const message = new CachedMessageRepository(sqliteMessage, apiMessage);
|
|
14675
|
+
return {
|
|
14676
|
+
conversation,
|
|
14677
|
+
contact,
|
|
14678
|
+
user,
|
|
14679
|
+
relation,
|
|
14680
|
+
message,
|
|
14681
|
+
close: () => closeDatabase(db)
|
|
14682
|
+
};
|
|
14683
|
+
}
|
|
14684
|
+
|
|
13574
14685
|
// src/factory.ts
|
|
13575
14686
|
function createFactory(config) {
|
|
13576
14687
|
const client = new APIClient(config.baseURL, config.debug);
|
|
13577
14688
|
if (config.uid && config.tk && config.token) {
|
|
13578
14689
|
client.setAuth({ uid: config.uid, tk: config.tk, token: config.token });
|
|
13579
14690
|
}
|
|
14691
|
+
const gateway = new ApiGateway(client);
|
|
14692
|
+
const imGateway = new IMGateway({
|
|
14693
|
+
wsUrl: config.wsURL,
|
|
14694
|
+
cid: config.cid,
|
|
14695
|
+
debugEnabled: config.debug
|
|
14696
|
+
});
|
|
14697
|
+
const configDir = getConfigDirectory(detectEnvironment());
|
|
14698
|
+
const repos = createRepositories(configDir, config.uid ?? "anonymous", gateway, imGateway);
|
|
13580
14699
|
return {
|
|
13581
|
-
gateway
|
|
13582
|
-
imGateway
|
|
13583
|
-
|
|
13584
|
-
|
|
13585
|
-
debugEnabled: config.debug
|
|
13586
|
-
}),
|
|
13587
|
-
config
|
|
14700
|
+
gateway,
|
|
14701
|
+
imGateway,
|
|
14702
|
+
config,
|
|
14703
|
+
repos
|
|
13588
14704
|
};
|
|
13589
14705
|
}
|
|
13590
14706
|
|
|
13591
14707
|
// src/cmd.ts
|
|
13592
|
-
var
|
|
14708
|
+
var logDebugEnabled = false;
|
|
14709
|
+
var LocalizedHelp = class extends import_commander9.Help {
|
|
13593
14710
|
/** Format an argument name with <required> or [optional] brackets. */
|
|
13594
14711
|
argDisplayName(arg) {
|
|
13595
14712
|
const name = arg.name() + (arg.variadic === true ? "..." : "");
|
|
@@ -13629,8 +14746,10 @@ async function main() {
|
|
|
13629
14746
|
const envName = detectEnvironment();
|
|
13630
14747
|
const config = loadAppConfig(envName);
|
|
13631
14748
|
setLocale(config.locale);
|
|
14749
|
+
logDebugEnabled = config.debug;
|
|
14750
|
+
setLogDebug(config.debug);
|
|
13632
14751
|
const factory = createFactory(config);
|
|
13633
|
-
const program = new
|
|
14752
|
+
const program = new import_commander9.Command();
|
|
13634
14753
|
const testModeBanner = `
|
|
13635
14754
|
\u2554\u2550\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2550\u2557
|
|
13636
14755
|
\u2551 DEVELOPMENT BUILD \u2551
|
|
@@ -13641,7 +14760,7 @@ async function main() {
|
|
|
13641
14760
|
${t("cli.banner")}` : t("cli.banner");
|
|
13642
14761
|
program.addHelpText("beforeAll", `${banner}
|
|
13643
14762
|
`);
|
|
13644
|
-
program.name("qz").version(`v${"0.
|
|
14763
|
+
program.name("qz").version(`v${"0.3.0-rc.1"}`, "-v, --version", t("options.version")).helpOption("-h, --help", t("options.help")).option("-q, --jq <expr>", t("options.jq")).option("--dry-run", t("options.dryRun"));
|
|
13645
14764
|
program.usage("<command> [subcommand] [options]");
|
|
13646
14765
|
program.hook("preAction", () => {
|
|
13647
14766
|
const opts = program.opts();
|
|
@@ -13651,6 +14770,7 @@ ${t("cli.banner")}` : t("cli.banner");
|
|
|
13651
14770
|
factory.gateway.setDryRun(dryRun2);
|
|
13652
14771
|
factory.imGateway.setDryRun(dryRun2);
|
|
13653
14772
|
});
|
|
14773
|
+
program.addCommand(NewCmdCache(factory));
|
|
13654
14774
|
program.addCommand(NewCmdAuth(factory));
|
|
13655
14775
|
program.addCommand(NewCmdConfig(factory));
|
|
13656
14776
|
program.addCommand(NewCmdUser(factory));
|
|
@@ -13667,6 +14787,27 @@ ${t("messages.helpFooter")}
|
|
|
13667
14787
|
await program.parseAsync(process.argv);
|
|
13668
14788
|
}
|
|
13669
14789
|
main().catch((err) => {
|
|
13670
|
-
|
|
14790
|
+
const envName = detectEnvironment();
|
|
14791
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
14792
|
+
try {
|
|
14793
|
+
appendCliRunLog(getConfigDirectory(envName), {
|
|
14794
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
14795
|
+
argv: process.argv.slice(2),
|
|
14796
|
+
command: process.argv.slice(2).join(" "),
|
|
14797
|
+
status: "error",
|
|
14798
|
+
code: "INTERNAL_ERROR" /* INTERNAL_ERROR */,
|
|
14799
|
+
message,
|
|
14800
|
+
data: null,
|
|
14801
|
+
dryRun: process.argv.includes("--dry-run")
|
|
14802
|
+
});
|
|
14803
|
+
} catch (logError) {
|
|
14804
|
+
if (logDebugEnabled) {
|
|
14805
|
+
process.stderr.write(
|
|
14806
|
+
`[DEBUG] Failed to write CLI log: ${logError instanceof Error ? logError.message : String(logError)}
|
|
14807
|
+
`
|
|
14808
|
+
);
|
|
14809
|
+
}
|
|
14810
|
+
}
|
|
14811
|
+
console.error(`Error: ${message}`);
|
|
13671
14812
|
process.exit(1);
|
|
13672
14813
|
});
|