dsh-mobile-plugin 0.1.86 → 0.1.87
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.
|
@@ -17,10 +17,10 @@
|
|
|
17
17
|
|
|
18
18
|
const { sendJson, readJsonBody } = require('../shared/http-util');
|
|
19
19
|
const { withIdempotency, requestIdOf } = require('./idempotency.js');
|
|
20
|
-
const { canonicalDeviceKey, rememberDeletedSessionIds } = require('./session-cache.js');
|
|
20
|
+
const { canonicalDeviceKey, rememberDeletedSessionIds, deletedSessionIdsOf } = require('./session-cache.js');
|
|
21
21
|
const { invalidateSessionList } = require('./sessions.js');
|
|
22
22
|
const { unwrap } = require('./envelope.js');
|
|
23
|
-
const { deleteSessionData } = require('../session-cleanup.cjs');
|
|
23
|
+
const { deleteSessionData, sessionIdsWithoutAnyData } = require('../session-cleanup.cjs');
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
26
|
* POST /api/mobile/v1/workspace/clear-archived(token)
|
|
@@ -43,10 +43,15 @@ async function handleClearArchived(ctx, req, res) {
|
|
|
43
43
|
if (selected.length === 0) return { status: 200, body: { ok: true, deleted: 0 } };
|
|
44
44
|
const removed = await deleteSessionData(selected);
|
|
45
45
|
// 删的是列表里可见的行:手机端正开着列表,宿主那份快照可能还带着它们,先在本进程压住。
|
|
46
|
-
|
|
46
|
+
// 盘上已经没有数据的归档 id 一并压住:上一次删到一半抛错时,已删的那批没记进删除集,
|
|
47
|
+
// 宿主的进程内清单却还挂着它们 —— 不补记的话再点清理只回 0,手机上永远清不掉。
|
|
48
|
+
const already = deletedSessionIdsOf(ctx);
|
|
49
|
+
const cleared = new Set(removed);
|
|
50
|
+
for (const id of sessionIdsWithoutAnyData(selected)) if (!already.has(id)) cleared.add(id);
|
|
51
|
+
rememberDeletedSessionIds(ctx, cleared);
|
|
47
52
|
// 不立刻失效的话,最长 10 秒还能点到已删的行。
|
|
48
53
|
invalidateSessionList(ctx);
|
|
49
|
-
return { status: 200, body: { ok: true, deleted:
|
|
54
|
+
return { status: 200, body: { ok: true, deleted: cleared.size } };
|
|
50
55
|
});
|
|
51
56
|
sendJson(res, outcome.status, outcome.body);
|
|
52
57
|
}
|
package/lib/session-cleanup.cjs
CHANGED
|
@@ -186,6 +186,38 @@ async function archivedIdsWithoutLogs(archivedSessionIds) {
|
|
|
186
186
|
return [...orphans]
|
|
187
187
|
}
|
|
188
188
|
|
|
189
|
+
/**
|
|
190
|
+
* 盘上已经不剩任何会话数据的 id:目录没了,或者目录里只剩宿主锁着的 `session.lock`。
|
|
191
|
+
*
|
|
192
|
+
* 只给移动端的「清理所有已归档」补账用:更早一次删除如果删到一半抛错(2026-10-18 前
|
|
193
|
+
* Windows 的 ENOTEMPTY 就是这样),已经删掉的那批 id 没能记进本进程的删除集,而宿主的
|
|
194
|
+
* 进程内清单还挂着它们 —— 再点清理只会回 `deleted: 0`,手机上永远清不掉。
|
|
195
|
+
*
|
|
196
|
+
* 判据比 archivedIdsWithoutLogs 更宽(那个只认规范名日志),但**不许宽到把迁移中途的
|
|
197
|
+
* 临时文件当成没有数据**:目录里只要还有任何非锁文件(含子目录)就算「还在」,读不出来
|
|
198
|
+
* 也按「还在」算。
|
|
199
|
+
*/
|
|
200
|
+
function sessionIdsWithoutAnyData(sessionIds) {
|
|
201
|
+
const candidates = new Set(sessionIds)
|
|
202
|
+
const withoutData = new Set()
|
|
203
|
+
if (candidates.size === 0) return []
|
|
204
|
+
const visit = (directory) => {
|
|
205
|
+
let entries
|
|
206
|
+
try { entries = fs.readdirSync(directory, { withFileTypes: true }) } catch { return }
|
|
207
|
+
for (const entry of entries) {
|
|
208
|
+
if (!entry.isDirectory()) continue
|
|
209
|
+
const child = path.join(directory, entry.name)
|
|
210
|
+
if (!candidates.has(entry.name)) { visit(child); continue }
|
|
211
|
+
candidates.delete(entry.name)
|
|
212
|
+
let files
|
|
213
|
+
try { files = fs.readdirSync(child, { withFileTypes: true }) } catch { continue }
|
|
214
|
+
if (!files.some((file) => !file.name.endsWith('.lock'))) withoutData.add(entry.name)
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
visit(path.join(dshHome(), 'sessions'))
|
|
218
|
+
return [...candidates, ...withoutData]
|
|
219
|
+
}
|
|
220
|
+
|
|
189
221
|
async function pruneOrphanedArchivedSessions(ctx) {
|
|
190
222
|
const workspaceList = ctx && ctx.apiProxy && ctx.apiProxy.workspace ? ctx.apiProxy.workspace.list : undefined
|
|
191
223
|
if (typeof workspaceList !== 'function') return 0
|
|
@@ -308,4 +340,4 @@ function installSessionCleanup(ctx) {
|
|
|
308
340
|
registerSessionCleanupTool(ctx)
|
|
309
341
|
}
|
|
310
342
|
|
|
311
|
-
module.exports = { cleanupSessions, registerSessionCleanupTool, installSessionCleanup, deleteSessionData, forgetArchivedSessions, pruneOrphanedArchivedSessions, pruneOrphanedArchivedSessionsOnce }
|
|
343
|
+
module.exports = { cleanupSessions, registerSessionCleanupTool, installSessionCleanup, deleteSessionData, sessionIdsWithoutAnyData, forgetArchivedSessions, pruneOrphanedArchivedSessions, pruneOrphanedArchivedSessionsOnce }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-mobile-plugin",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.87",
|
|
4
4
|
"description": "Mobile API (/api/mobile/v1) and relay client for the DSH mobile app — desktop profile build (0.2.0-rc.2 compatible, peers resolved by the host)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|