chatlab-cli 0.21.0 → 0.21.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/dist/{chunk-3DIWXYMJ.mjs → chunk-4GI2UPCS.mjs} +2 -2
- package/dist/{chunk-EIRLEPXP.mjs → chunk-7HQWGLX6.mjs} +6 -1
- package/dist/{chunk-EIRLEPXP.mjs.map → chunk-7HQWGLX6.mjs.map} +1 -1
- package/dist/{chunk-EWCSGYVT.mjs → chunk-AIR7EAF4.mjs} +2 -2
- package/dist/{chunk-FBTHZU55.mjs → chunk-LI4X52E7.mjs} +190 -29
- package/dist/chunk-LI4X52E7.mjs.map +1 -0
- package/dist/{chunk-XUHPCRVT.mjs → chunk-OQVKZTVD.mjs} +2 -2
- package/dist/{chunk-NB4BIAYM.mjs → chunk-OZWXLRJL.mjs} +9 -9
- package/dist/cli.mjs +2 -2
- package/dist/{http-QVYJ5HER.mjs → http-DHQI4G5J.mjs} +6 -6
- package/dist/{import-AJKL6JPR.mjs → import-CQWGIMZQ.mjs} +4 -4
- package/dist/index.mjs +6 -6
- package/dist/{mcp-FRF3YAN5.mjs → mcp-7Q3FEI3Z.mjs} +3 -3
- package/dist/{src-KOIGBZJX.mjs → src-QBT5SYW5.mjs} +2 -2
- package/dist/{stream-import-URGOCXUH.mjs → stream-import-VG7RP6KJ.mjs} +3 -3
- package/dist-web/assets/{DebugToolsPanel-dUV6pVqD.css → DebugToolsPanel-CoBtqb--.css} +1 -1
- package/dist-web/assets/DebugToolsPanel.vue_vue_type_script_setup_true_lang-CpFGhsl5.js +147 -0
- package/dist-web/assets/{MessageExportModal-BAf68-wB.js → MessageExportModal-DTgxz1eQ.js} +1 -1
- package/dist-web/assets/electron-H65bUnhW.js +1 -0
- package/dist-web/assets/{fetch-Ayp337Ng.js → fetch-C2vUkdnA.js} +1 -1
- package/dist-web/assets/fetch-CTZXLLcn.js +1 -0
- package/dist-web/assets/index-B8867dX7.css +1 -0
- package/dist-web/assets/{index-CmU6x-uJ.css → index-BE64tUWq.css} +1 -1
- package/dist-web/assets/{index-Bd5r2oFG.js → index-C4B0hv6C.js} +3 -3
- package/dist-web/assets/index-CbQMfheg.css +1 -0
- package/dist-web/assets/index-DUXf21MT.js +173 -0
- package/dist-web/assets/index-DZiH2cC1.js +7 -0
- package/dist-web/assets/index-DeG0EHOT.js +24 -0
- package/dist-web/assets/index-DuhN8jAf.js +2 -0
- package/dist-web/assets/{web-C5yfcwjn.js → web-DImo6Kjz.js} +1 -1
- package/dist-web/index.html +2 -2
- package/package.json +1 -7
- package/dist/chunk-FBTHZU55.mjs.map +0 -1
- package/dist-web/assets/DebugToolsPanel.vue_vue_type_script_setup_true_lang-DFN1Co1H.js +0 -155
- package/dist-web/assets/electron-BHjOx6B6.js +0 -1
- package/dist-web/assets/fetch-BWtpQwBZ.js +0 -1
- package/dist-web/assets/index-BfZM-q0T.js +0 -7
- package/dist-web/assets/index-CLGv8Den.css +0 -1
- package/dist-web/assets/index-CLYHD_f4.js +0 -2
- package/dist-web/assets/index-CaTRpNBK.js +0 -16
- package/dist-web/assets/index-CzR1sElx.css +0 -1
- package/dist-web/assets/index-Ksa--o23.js +0 -173
- /package/dist/{chunk-3DIWXYMJ.mjs.map → chunk-4GI2UPCS.mjs.map} +0 -0
- /package/dist/{chunk-EWCSGYVT.mjs.map → chunk-AIR7EAF4.mjs.map} +0 -0
- /package/dist/{chunk-XUHPCRVT.mjs.map → chunk-OQVKZTVD.mjs.map} +0 -0
- /package/dist/{chunk-NB4BIAYM.mjs.map → chunk-OZWXLRJL.mjs.map} +0 -0
- /package/dist/{http-QVYJ5HER.mjs.map → http-DHQI4G5J.mjs.map} +0 -0
- /package/dist/{import-AJKL6JPR.mjs.map → import-CQWGIMZQ.mjs.map} +0 -0
- /package/dist/{mcp-FRF3YAN5.mjs.map → mcp-7Q3FEI3Z.mjs.map} +0 -0
- /package/dist/{src-KOIGBZJX.mjs.map → src-QBT5SYW5.mjs.map} +0 -0
- /package/dist/{stream-import-URGOCXUH.mjs.map → stream-import-VG7RP6KJ.mjs.map} +0 -0
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
incrementalImport,
|
|
14
14
|
openBetterSqliteDatabase,
|
|
15
15
|
streamingImport
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-7HQWGLX6.mjs";
|
|
17
17
|
|
|
18
18
|
// src/import/stream-import.ts
|
|
19
19
|
import * as fs from "fs";
|
|
@@ -141,4 +141,4 @@ export {
|
|
|
141
141
|
analyzeIncrementalImport2 as analyzeIncrementalImport,
|
|
142
142
|
analyzeNewImport2 as analyzeNewImport
|
|
143
143
|
};
|
|
144
|
-
//# sourceMappingURL=chunk-
|
|
144
|
+
//# sourceMappingURL=chunk-AIR7EAF4.mjs.map
|
|
@@ -7,17 +7,17 @@ const __dirname = __pathDirname(__filename);
|
|
|
7
7
|
import {
|
|
8
8
|
importData,
|
|
9
9
|
parseFile
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-OQVKZTVD.mjs";
|
|
11
11
|
import {
|
|
12
12
|
analyzeIncrementalImport,
|
|
13
13
|
analyzeNewImport,
|
|
14
14
|
incrementalImport,
|
|
15
15
|
streamImport
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-AIR7EAF4.mjs";
|
|
17
17
|
import {
|
|
18
18
|
AGENT_TOOL_REGISTRY,
|
|
19
19
|
CoreDataProvider
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-4GI2UPCS.mjs";
|
|
21
21
|
import {
|
|
22
22
|
getVersion
|
|
23
23
|
} from "./chunk-2AIOU3PW.mjs";
|
|
@@ -114,7 +114,7 @@ import {
|
|
|
114
114
|
verifyCliDataPath,
|
|
115
115
|
writeAuthProfile,
|
|
116
116
|
writeConfigField
|
|
117
|
-
} from "./chunk-
|
|
117
|
+
} from "./chunk-7HQWGLX6.mjs";
|
|
118
118
|
|
|
119
119
|
// src/http/index.ts
|
|
120
120
|
import * as fs14 from "fs";
|
|
@@ -849,6 +849,11 @@ function registerSessionIndexRoutes(server2, adapter) {
|
|
|
849
849
|
const sessionCount = session_index_service_exports.generateIndex(adapter, request.params.id, gapThreshold);
|
|
850
850
|
return { sessionCount };
|
|
851
851
|
});
|
|
852
|
+
server2.post("/_web/sessions/:id/generate-incremental-index", async (request) => {
|
|
853
|
+
const gapThreshold = request.body?.gapThreshold ?? 1800;
|
|
854
|
+
const sessionCount = session_index_service_exports.generateIncrementalIndex(adapter, request.params.id, gapThreshold);
|
|
855
|
+
return { sessionCount };
|
|
856
|
+
});
|
|
852
857
|
server2.post("/_web/sessions/:id/clear-index", async (request) => {
|
|
853
858
|
session_index_service_exports.clearIndex(adapter, request.params.id);
|
|
854
859
|
return { success: true };
|
|
@@ -1472,7 +1477,7 @@ function registerMergeRoutes(server2, dbManager2, mergeCache) {
|
|
|
1472
1477
|
const merged = buildMergedOutput(dataSources, outputName);
|
|
1473
1478
|
let sessionId;
|
|
1474
1479
|
if (andImport) {
|
|
1475
|
-
const { streamImport: serverStreamImport } = await import("./stream-import-
|
|
1480
|
+
const { streamImport: serverStreamImport } = await import("./stream-import-VG7RP6KJ.mjs");
|
|
1476
1481
|
const jsonData = JSON.stringify(merged.chatLabData);
|
|
1477
1482
|
const tmpDir = fs5.mkdtempSync(path5.join(os2.tmpdir(), "chatlab-merged-"));
|
|
1478
1483
|
const tmpPath = path5.join(tmpDir, `${outputName}.json`);
|
|
@@ -1525,7 +1530,7 @@ function registerMergeRoutes(server2, dbManager2, mergeCache) {
|
|
|
1525
1530
|
const db = ensureDb2(dbManager2, sid);
|
|
1526
1531
|
const exported = exportSessionToJson(db);
|
|
1527
1532
|
const { db: tempDb, tempDbPath } = mergeCache.createTempDatabase(exported.meta.name);
|
|
1528
|
-
const { TempDbWriter } = await import("./src-
|
|
1533
|
+
const { TempDbWriter } = await import("./src-QBT5SYW5.mjs");
|
|
1529
1534
|
const writer = new TempDbWriter(tempDb);
|
|
1530
1535
|
writer.writeMeta({
|
|
1531
1536
|
name: exported.meta.name,
|
|
@@ -2713,12 +2718,12 @@ var DataSourceManager = class {
|
|
|
2713
2718
|
removeSession(sourceId, sessionId) {
|
|
2714
2719
|
const sources = this.loadAll();
|
|
2715
2720
|
const ds = sources.find((s) => s.id === sourceId);
|
|
2716
|
-
if (!ds) return
|
|
2717
|
-
const
|
|
2721
|
+
if (!ds) return null;
|
|
2722
|
+
const removed = ds.sessions.find((s) => s.id === sessionId);
|
|
2723
|
+
if (!removed) return null;
|
|
2718
2724
|
ds.sessions = ds.sessions.filter((s) => s.id !== sessionId);
|
|
2719
|
-
if (ds.sessions.length === before) return false;
|
|
2720
2725
|
this.saveAll(sources);
|
|
2721
|
-
return
|
|
2726
|
+
return removed;
|
|
2722
2727
|
}
|
|
2723
2728
|
updateSession(sourceId, sessionId, updates) {
|
|
2724
2729
|
const sources = this.loadAll();
|
|
@@ -2766,14 +2771,13 @@ function parseRemoteSessionsResponse(body) {
|
|
|
2766
2771
|
// ../../packages/sync/src/pull-engine.ts
|
|
2767
2772
|
import * as fs12 from "fs";
|
|
2768
2773
|
import * as crypto3 from "crypto";
|
|
2769
|
-
var MAX_PAGES_PER_PULL =
|
|
2774
|
+
var MAX_PAGES_PER_PULL = 5e3;
|
|
2770
2775
|
var PULL_OVERLAP_SECONDS = 60;
|
|
2771
2776
|
function buildPullUrl(baseUrl, remoteSessionId, params) {
|
|
2772
2777
|
const base = `${baseUrl}/sessions/${remoteSessionId}/messages`;
|
|
2773
2778
|
const qs = ["format=chatlab"];
|
|
2774
2779
|
if (params.since !== void 0 && params.since > 0) qs.push(`since=${params.since}`);
|
|
2775
2780
|
if (params.offset !== void 0 && params.offset > 0) qs.push(`offset=${params.offset}`);
|
|
2776
|
-
if (params.end !== void 0 && params.end > 0) qs.push(`end=${params.end}`);
|
|
2777
2781
|
if (params.limit !== void 0 && params.limit > 0) qs.push(`limit=${params.limit}`);
|
|
2778
2782
|
return base + "?" + qs.join("&");
|
|
2779
2783
|
}
|
|
@@ -2815,6 +2819,29 @@ function parseSyncFromFile(filePath) {
|
|
|
2815
2819
|
return null;
|
|
2816
2820
|
}
|
|
2817
2821
|
}
|
|
2822
|
+
function fileContainsMessages(filePath) {
|
|
2823
|
+
try {
|
|
2824
|
+
if (filePath.endsWith(".jsonl")) {
|
|
2825
|
+
const content = fs12.readFileSync(filePath, "utf-8");
|
|
2826
|
+
for (const line of content.split("\n")) {
|
|
2827
|
+
const trimmed = line.trim();
|
|
2828
|
+
if (!trimmed) continue;
|
|
2829
|
+
try {
|
|
2830
|
+
const obj = JSON.parse(trimmed);
|
|
2831
|
+
if (obj._type === "message") return true;
|
|
2832
|
+
} catch {
|
|
2833
|
+
continue;
|
|
2834
|
+
}
|
|
2835
|
+
}
|
|
2836
|
+
return false;
|
|
2837
|
+
}
|
|
2838
|
+
const raw = fs12.readFileSync(filePath, "utf-8");
|
|
2839
|
+
const parsed = JSON.parse(raw);
|
|
2840
|
+
return Array.isArray(parsed.messages) && parsed.messages.length > 0;
|
|
2841
|
+
} catch {
|
|
2842
|
+
return false;
|
|
2843
|
+
}
|
|
2844
|
+
}
|
|
2818
2845
|
function cleanupTempFile(filePath) {
|
|
2819
2846
|
try {
|
|
2820
2847
|
if (fs12.existsSync(filePath)) fs12.unlinkSync(filePath);
|
|
@@ -2829,6 +2856,7 @@ var PullEngine = class {
|
|
|
2829
2856
|
logger;
|
|
2830
2857
|
isImporting;
|
|
2831
2858
|
pullingSourceIds = /* @__PURE__ */ new Set();
|
|
2859
|
+
progressMap = /* @__PURE__ */ new Map();
|
|
2832
2860
|
constructor(options) {
|
|
2833
2861
|
this.fetcher = options.fetcher;
|
|
2834
2862
|
this.importer = options.importer;
|
|
@@ -2837,6 +2865,9 @@ var PullEngine = class {
|
|
|
2837
2865
|
this.logger = options.logger ?? NOOP_LOGGER;
|
|
2838
2866
|
this.isImporting = options.isImporting ?? (() => false);
|
|
2839
2867
|
}
|
|
2868
|
+
getProgress() {
|
|
2869
|
+
return Array.from(this.progressMap.values());
|
|
2870
|
+
}
|
|
2840
2871
|
async importTempFile(baseUrl, sess, tempFile) {
|
|
2841
2872
|
let targetId = sess.targetSessionId;
|
|
2842
2873
|
if (!targetId) {
|
|
@@ -2850,6 +2881,11 @@ var PullEngine = class {
|
|
|
2850
2881
|
return this.importer.importFile(tempFile, targetId || void 0, externalId);
|
|
2851
2882
|
}
|
|
2852
2883
|
async executePullSession(sourceId, ds, sess) {
|
|
2884
|
+
const currentDs = this.dsManager.get(sourceId);
|
|
2885
|
+
if (!currentDs || !currentDs.sessions.some((s) => s.id === sess.id)) {
|
|
2886
|
+
this.logger.info(`[Pull] Skipping "${sess.name}": session no longer exists`);
|
|
2887
|
+
return { success: true, newMessageCount: 0 };
|
|
2888
|
+
}
|
|
2853
2889
|
if (this.isImporting()) {
|
|
2854
2890
|
this.logger.info(`[Pull] Skipping "${sess.name}": import in progress`);
|
|
2855
2891
|
return { success: false, newMessageCount: 0, error: "Import in progress" };
|
|
@@ -2857,34 +2893,114 @@ var PullEngine = class {
|
|
|
2857
2893
|
this.logger.info(`[Pull] Pulling "${sess.name}" from ${ds.baseUrl}`);
|
|
2858
2894
|
let totalNewMessages = 0;
|
|
2859
2895
|
let since = sess.lastPullAt;
|
|
2860
|
-
let offset = 0;
|
|
2861
|
-
let end;
|
|
2862
2896
|
let pageCount = 0;
|
|
2863
2897
|
let resyncAttempted = false;
|
|
2898
|
+
this.progressMap.set(sess.id, { sessionId: sess.id, sessionName: sess.name, current: 0, pages: 0, done: false });
|
|
2864
2899
|
try {
|
|
2865
2900
|
while (pageCount < MAX_PAGES_PER_PULL) {
|
|
2866
2901
|
pageCount++;
|
|
2867
2902
|
const tempFile = await this.fetcher.fetchToTempFile(ds.baseUrl, sess.remoteSessionId, ds.token, {
|
|
2868
2903
|
since,
|
|
2869
|
-
offset,
|
|
2870
|
-
end,
|
|
2871
2904
|
limit: ds.pullLimit
|
|
2872
2905
|
});
|
|
2873
2906
|
try {
|
|
2874
2907
|
const stat = fs12.statSync(tempFile);
|
|
2875
2908
|
this.logger.info(`[Pull] "${sess.name}" page ${pageCount}: fetched ${stat.size} bytes`);
|
|
2909
|
+
const sync0 = parseSyncFromFile(tempFile);
|
|
2910
|
+
if (stat.size < 1024) {
|
|
2911
|
+
if (!fileContainsMessages(tempFile) && sync0?.hasMore === false) {
|
|
2912
|
+
cleanupTempFile(tempFile);
|
|
2913
|
+
const retryDelays = [2e3, 3e3, 5e3];
|
|
2914
|
+
let retrySuccess = false;
|
|
2915
|
+
let retryHasMore = false;
|
|
2916
|
+
for (let ri = 0; ri < retryDelays.length; ri++) {
|
|
2917
|
+
this.logger.info(
|
|
2918
|
+
`[Pull] "${sess.name}" page ${pageCount} got empty response, retry ${ri + 1}/${retryDelays.length} after ${retryDelays[ri]}ms`
|
|
2919
|
+
);
|
|
2920
|
+
await new Promise((r) => setTimeout(r, retryDelays[ri]));
|
|
2921
|
+
const retryFile = await this.fetcher.fetchToTempFile(ds.baseUrl, sess.remoteSessionId, ds.token, {
|
|
2922
|
+
since,
|
|
2923
|
+
limit: ds.pullLimit
|
|
2924
|
+
});
|
|
2925
|
+
const retryStat = fs12.statSync(retryFile);
|
|
2926
|
+
this.logger.info(`[Pull] "${sess.name}" retry ${ri + 1}: fetched ${retryStat.size} bytes`);
|
|
2927
|
+
const retrySync = parseSyncFromFile(retryFile);
|
|
2928
|
+
if (retryStat.size < 1024 && !fileContainsMessages(retryFile) && retrySync?.hasMore === false) {
|
|
2929
|
+
cleanupTempFile(retryFile);
|
|
2930
|
+
continue;
|
|
2931
|
+
}
|
|
2932
|
+
const retryResult = await this.importTempFile(ds.baseUrl, sess, retryFile);
|
|
2933
|
+
cleanupTempFile(retryFile);
|
|
2934
|
+
if (retryResult.needFullResync && !resyncAttempted) {
|
|
2935
|
+
resyncAttempted = true;
|
|
2936
|
+
this.logger.info(`[Pull] Resetting since=0 for "${sess.name}" full resync`);
|
|
2937
|
+
since = 0;
|
|
2938
|
+
pageCount = 0;
|
|
2939
|
+
sess.targetSessionId = "";
|
|
2940
|
+
sess.lastPullAt = 0;
|
|
2941
|
+
this.dsManager.updateSession(sourceId, sess.id, { targetSessionId: "", lastPullAt: 0 });
|
|
2942
|
+
retrySuccess = true;
|
|
2943
|
+
retryHasMore = true;
|
|
2944
|
+
break;
|
|
2945
|
+
}
|
|
2946
|
+
if (retryResult.needFullResync) {
|
|
2947
|
+
const errMsg = "Full resync failed";
|
|
2948
|
+
this.logger.error(`[Pull] Full resync already attempted for "${sess.name}", aborting`);
|
|
2949
|
+
this.dsManager.updateSession(sourceId, sess.id, {
|
|
2950
|
+
lastPullAt: Math.floor(Date.now() / 1e3),
|
|
2951
|
+
lastStatus: "error",
|
|
2952
|
+
lastError: errMsg
|
|
2953
|
+
});
|
|
2954
|
+
this.notifier.onPullResult(sourceId, sess.id, "error", errMsg);
|
|
2955
|
+
this.markProgressDone(sess.id);
|
|
2956
|
+
return { success: false, newMessageCount: 0, error: errMsg };
|
|
2957
|
+
}
|
|
2958
|
+
if (!retryResult.success) {
|
|
2959
|
+
const errMsg = retryResult.error || "Import failed";
|
|
2960
|
+
this.dsManager.updateSession(sourceId, sess.id, {
|
|
2961
|
+
lastPullAt: Math.floor(Date.now() / 1e3),
|
|
2962
|
+
lastStatus: "error",
|
|
2963
|
+
lastError: errMsg
|
|
2964
|
+
});
|
|
2965
|
+
this.notifier.onPullResult(sourceId, sess.id, "error", errMsg);
|
|
2966
|
+
this.markProgressDone(sess.id);
|
|
2967
|
+
return { success: false, newMessageCount: 0, error: errMsg };
|
|
2968
|
+
}
|
|
2969
|
+
if (retryResult.success && retryResult.sessionId && !sess.targetSessionId) {
|
|
2970
|
+
sess.targetSessionId = retryResult.sessionId;
|
|
2971
|
+
this.dsManager.updateSession(sourceId, sess.id, { targetSessionId: retryResult.sessionId });
|
|
2972
|
+
}
|
|
2973
|
+
totalNewMessages += retryResult.newMessageCount;
|
|
2974
|
+
this.progressMap.set(sess.id, {
|
|
2975
|
+
sessionId: sess.id,
|
|
2976
|
+
sessionName: sess.name,
|
|
2977
|
+
current: totalNewMessages,
|
|
2978
|
+
pages: pageCount,
|
|
2979
|
+
done: false
|
|
2980
|
+
});
|
|
2981
|
+
if (retrySync?.hasMore && retrySync.nextSince !== void 0) {
|
|
2982
|
+
since = retrySync.nextSince;
|
|
2983
|
+
}
|
|
2984
|
+
retryHasMore = !!retrySync?.hasMore;
|
|
2985
|
+
retrySuccess = true;
|
|
2986
|
+
break;
|
|
2987
|
+
}
|
|
2988
|
+
if (!retrySuccess) break;
|
|
2989
|
+
if (!retryHasMore) break;
|
|
2990
|
+
continue;
|
|
2991
|
+
}
|
|
2992
|
+
}
|
|
2876
2993
|
if (stat.size === 0) {
|
|
2877
2994
|
cleanupTempFile(tempFile);
|
|
2878
2995
|
break;
|
|
2879
2996
|
}
|
|
2880
|
-
const sync =
|
|
2997
|
+
const sync = sync0;
|
|
2881
2998
|
const result = await this.importTempFile(ds.baseUrl, sess, tempFile);
|
|
2882
2999
|
cleanupTempFile(tempFile);
|
|
2883
3000
|
if (result.needFullResync && !resyncAttempted) {
|
|
2884
3001
|
resyncAttempted = true;
|
|
2885
3002
|
this.logger.info(`[Pull] Resetting since=0 for "${sess.name}" full resync`);
|
|
2886
3003
|
since = 0;
|
|
2887
|
-
offset = 0;
|
|
2888
3004
|
pageCount = 0;
|
|
2889
3005
|
sess.targetSessionId = "";
|
|
2890
3006
|
sess.lastPullAt = 0;
|
|
@@ -2900,6 +3016,7 @@ var PullEngine = class {
|
|
|
2900
3016
|
lastError: errMsg
|
|
2901
3017
|
});
|
|
2902
3018
|
this.notifier.onPullResult(sourceId, sess.id, "error", errMsg);
|
|
3019
|
+
this.markProgressDone(sess.id);
|
|
2903
3020
|
return { success: false, newMessageCount: 0, error: errMsg };
|
|
2904
3021
|
}
|
|
2905
3022
|
if (!result.success) {
|
|
@@ -2910,6 +3027,7 @@ var PullEngine = class {
|
|
|
2910
3027
|
lastError: errMsg
|
|
2911
3028
|
});
|
|
2912
3029
|
this.notifier.onPullResult(sourceId, sess.id, "error", errMsg);
|
|
3030
|
+
this.markProgressDone(sess.id);
|
|
2913
3031
|
return { success: false, newMessageCount: 0, error: errMsg };
|
|
2914
3032
|
}
|
|
2915
3033
|
if (!sess.targetSessionId && result.sessionId) {
|
|
@@ -2917,11 +3035,15 @@ var PullEngine = class {
|
|
|
2917
3035
|
this.dsManager.updateSession(sourceId, sess.id, { targetSessionId: result.sessionId });
|
|
2918
3036
|
}
|
|
2919
3037
|
totalNewMessages += result.newMessageCount;
|
|
3038
|
+
this.progressMap.set(sess.id, {
|
|
3039
|
+
sessionId: sess.id,
|
|
3040
|
+
sessionName: sess.name,
|
|
3041
|
+
current: totalNewMessages,
|
|
3042
|
+
pages: pageCount,
|
|
3043
|
+
done: false
|
|
3044
|
+
});
|
|
2920
3045
|
if (!sync || !sync.hasMore) break;
|
|
2921
3046
|
if (sync.nextSince !== void 0) since = sync.nextSince;
|
|
2922
|
-
if (sync.nextOffset !== void 0) offset = sync.nextOffset;
|
|
2923
|
-
else offset = 0;
|
|
2924
|
-
if (sync.watermark !== void 0 && !end) end = sync.watermark;
|
|
2925
3047
|
} catch (importErr) {
|
|
2926
3048
|
cleanupTempFile(tempFile);
|
|
2927
3049
|
throw importErr;
|
|
@@ -2938,6 +3060,7 @@ var PullEngine = class {
|
|
|
2938
3060
|
});
|
|
2939
3061
|
if (totalNewMessages > 0) this.notifier.onSessionListChanged();
|
|
2940
3062
|
this.notifier.onPullResult(sourceId, sess.id, "success", `+${totalNewMessages} messages`);
|
|
3063
|
+
this.markProgressDone(sess.id);
|
|
2941
3064
|
return { success: true, newMessageCount: totalNewMessages };
|
|
2942
3065
|
} catch (error) {
|
|
2943
3066
|
const errMsg = error.message || "Pull failed";
|
|
@@ -2948,9 +3071,17 @@ var PullEngine = class {
|
|
|
2948
3071
|
lastError: errMsg
|
|
2949
3072
|
});
|
|
2950
3073
|
this.notifier.onPullResult(sourceId, sess.id, "error", errMsg);
|
|
3074
|
+
this.markProgressDone(sess.id);
|
|
2951
3075
|
return { success: false, newMessageCount: 0, error: errMsg };
|
|
2952
3076
|
}
|
|
2953
3077
|
}
|
|
3078
|
+
markProgressDone(sessionId) {
|
|
3079
|
+
const p = this.progressMap.get(sessionId);
|
|
3080
|
+
if (p) {
|
|
3081
|
+
p.done = true;
|
|
3082
|
+
setTimeout(() => this.progressMap.delete(sessionId), 5e3);
|
|
3083
|
+
}
|
|
3084
|
+
}
|
|
2954
3085
|
async pullAllSessions(ds) {
|
|
2955
3086
|
if (this.pullingSourceIds.has(ds.id)) {
|
|
2956
3087
|
this.logger.info(`[Pull] Skipping pullAllSessions for "${ds.baseUrl}": pull already in progress`);
|
|
@@ -3077,7 +3208,7 @@ var NodeFetcher = class {
|
|
|
3077
3208
|
async fetchToTempFile(baseUrl, remoteSessionId, token, params) {
|
|
3078
3209
|
const url = buildPullUrl(baseUrl, remoteSessionId, params);
|
|
3079
3210
|
const headers = {
|
|
3080
|
-
Accept: "application/json
|
|
3211
|
+
Accept: "application/json"
|
|
3081
3212
|
};
|
|
3082
3213
|
if (token) headers["Authorization"] = `Bearer ${token}`;
|
|
3083
3214
|
const response = await fetch(url, { headers, signal: AbortSignal.timeout(12e4) });
|
|
@@ -3109,7 +3240,28 @@ var DirectImporter = class {
|
|
|
3109
3240
|
}
|
|
3110
3241
|
sessionExists(sessionId) {
|
|
3111
3242
|
const dbPath = this.dbManager.getDbPath(sessionId);
|
|
3112
|
-
|
|
3243
|
+
if (!fs13.existsSync(dbPath)) return false;
|
|
3244
|
+
try {
|
|
3245
|
+
const db = openBetterSqliteDatabase(dbPath, { readonly: true, nativeBinding: this.nativeBinding });
|
|
3246
|
+
const row = db.prepare("SELECT COUNT(*) as cnt FROM sqlite_master WHERE type='table' AND name='message'").get();
|
|
3247
|
+
db.close();
|
|
3248
|
+
if (row.cnt === 0) {
|
|
3249
|
+
this.logger.warn(`[DirectImporter] DB file exists but has no message table: ${sessionId}, removing`);
|
|
3250
|
+
try {
|
|
3251
|
+
fs13.unlinkSync(dbPath);
|
|
3252
|
+
} catch {
|
|
3253
|
+
}
|
|
3254
|
+
return false;
|
|
3255
|
+
}
|
|
3256
|
+
return true;
|
|
3257
|
+
} catch {
|
|
3258
|
+
this.logger.warn(`[DirectImporter] Cannot validate DB file: ${sessionId}, removing`);
|
|
3259
|
+
try {
|
|
3260
|
+
fs13.unlinkSync(dbPath);
|
|
3261
|
+
} catch {
|
|
3262
|
+
}
|
|
3263
|
+
return false;
|
|
3264
|
+
}
|
|
3113
3265
|
}
|
|
3114
3266
|
async importFile(tempFile, targetSessionId, externalId) {
|
|
3115
3267
|
if (targetSessionId && this.sessionExists(targetSessionId)) {
|
|
@@ -3139,7 +3291,7 @@ var DirectImporter = class {
|
|
|
3139
3291
|
sessionId
|
|
3140
3292
|
};
|
|
3141
3293
|
}
|
|
3142
|
-
if (result.error?.includes("not found") || result.error?.includes("session_not_found")) {
|
|
3294
|
+
if (result.error?.includes("not found") || result.error?.includes("session_not_found") || result.error?.includes("no such table")) {
|
|
3143
3295
|
return { success: false, newMessageCount: 0, sessionId, needFullResync: true };
|
|
3144
3296
|
}
|
|
3145
3297
|
return { success: false, newMessageCount: 0, sessionId, error: result.error };
|
|
@@ -3177,7 +3329,7 @@ var NoopNotifier = class {
|
|
|
3177
3329
|
|
|
3178
3330
|
// src/sync/routes.ts
|
|
3179
3331
|
function registerAutomationRoutes(server2, ctx) {
|
|
3180
|
-
const { dsManager: dsManager2, pullEngine: pullEngine2, serverInfo } = ctx;
|
|
3332
|
+
const { dsManager: dsManager2, pullEngine: pullEngine2, dbManager: dbManager2, serverInfo } = ctx;
|
|
3181
3333
|
server2.get("/_web/automation/config", async () => {
|
|
3182
3334
|
return {
|
|
3183
3335
|
enabled: true,
|
|
@@ -3219,9 +3371,15 @@ function registerAutomationRoutes(server2, ctx) {
|
|
|
3219
3371
|
return added;
|
|
3220
3372
|
});
|
|
3221
3373
|
server2.delete("/_web/automation/data-sources/:id/sessions/:sessId", async (request, reply) => {
|
|
3222
|
-
const
|
|
3223
|
-
if (!
|
|
3374
|
+
const removed = dsManager2.removeSession(request.params.id, request.params.sessId);
|
|
3375
|
+
if (!removed) return reply.code(404).send({ error: "Session not found" });
|
|
3224
3376
|
reloadTimer(request.params.id);
|
|
3377
|
+
if (request.query.deleteData === "true" && removed.targetSessionId) {
|
|
3378
|
+
dbManager2.close(removed.targetSessionId);
|
|
3379
|
+
const dbPath = dbManager2.getDbPath(removed.targetSessionId);
|
|
3380
|
+
const fs15 = await import("fs");
|
|
3381
|
+
if (fs15.existsSync(dbPath)) fs15.unlinkSync(dbPath);
|
|
3382
|
+
}
|
|
3225
3383
|
return { success: true };
|
|
3226
3384
|
});
|
|
3227
3385
|
server2.post(
|
|
@@ -3233,6 +3391,9 @@ function registerAutomationRoutes(server2, ctx) {
|
|
|
3233
3391
|
server2.post("/_web/automation/data-sources/:id/pull-all", async (request) => {
|
|
3234
3392
|
return pullEngine2.triggerPullAll(request.params.id);
|
|
3235
3393
|
});
|
|
3394
|
+
server2.get("/_web/automation/sync-progress", async () => {
|
|
3395
|
+
return pullEngine2.getProgress();
|
|
3396
|
+
});
|
|
3236
3397
|
server2.get("/_web/automation/remote-sessions", async (request, reply) => {
|
|
3237
3398
|
const { baseUrl, token, keyword, limit, cursor } = request.query;
|
|
3238
3399
|
if (!baseUrl) return reply.code(400).send({ error: "baseUrl is required" });
|
|
@@ -3276,7 +3437,7 @@ function initSync(server2, dbManager2, pathProvider, serverInfo) {
|
|
|
3276
3437
|
dsManager,
|
|
3277
3438
|
logger: syncLogger
|
|
3278
3439
|
});
|
|
3279
|
-
registerAutomationRoutes(server2, { dsManager, pullEngine, serverInfo });
|
|
3440
|
+
registerAutomationRoutes(server2, { dsManager, pullEngine, dbManager: dbManager2, serverInfo });
|
|
3280
3441
|
initScheduler({
|
|
3281
3442
|
dsManager,
|
|
3282
3443
|
pullEngine,
|
|
@@ -3397,4 +3558,4 @@ export {
|
|
|
3397
3558
|
startHttpServer,
|
|
3398
3559
|
stopHttpServer
|
|
3399
3560
|
};
|
|
3400
|
-
//# sourceMappingURL=chunk-
|
|
3561
|
+
//# sourceMappingURL=chunk-LI4X52E7.mjs.map
|