@morlay/session-rdb 0.0.18 → 0.0.20

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.
Files changed (32) hide show
  1. package/dist/artifact.d.mts +1 -1
  2. package/dist/artifact.mjs +1 -1
  3. package/dist/{import-DZIAjOUr.mjs → branch-Co6xlbi0.mjs} +1 -186
  4. package/dist/import.d.mts +3 -2
  5. package/dist/import.mjs +197 -1
  6. package/dist/{index-BEKoV1Uy.d.mts → index-D55G9n4k.d.mts} +4 -3
  7. package/dist/index.d.mts +2 -2
  8. package/dist/index.mjs +94 -39
  9. package/dist/{magic-string.es-BWtG0AyA.mjs → magic-string.es-BgJoa-3K.mjs} +2 -2
  10. package/dist/{schema-Bo6Hy5gW.d.mts → schema-BkQN5GyT.d.mts} +36 -47
  11. package/dist/{sqlite-BIPdMNQb.mjs → sqlite-DYExtbLo.mjs} +27 -6
  12. package/dist/storage.d.mts +1 -1
  13. package/dist/storage.mjs +1 -1
  14. package/dist/testing.d.mts +2 -1
  15. package/dist/testing.mjs +22 -21
  16. package/drizzle/postgres/20260910120001_v3_storage_tables/snapshot.json +25 -78
  17. package/drizzle/postgres/20260910130001_v3_session_title_backfill/snapshot.json +25 -78
  18. package/drizzle/sqlite/20260910120000_v3_storage_tables/snapshot.json +25 -78
  19. package/drizzle/sqlite/20260910130000_v3_session_title_backfill/snapshot.json +25 -78
  20. package/package.json +4 -3
  21. package/src/entities/v3/workspace-state.ts +1 -1
  22. package/src/import-storages.ts +8 -3
  23. package/src/import.ts +41 -4
  24. package/src/index.ts +10 -2
  25. package/src/postgres.ts +15 -9
  26. package/src/session-query.ts +27 -0
  27. package/src/storage-takeover/index.ts +8 -8
  28. package/src/storage-takeover/projection-cache.ts +50 -24
  29. package/src/storage-takeover/repository.ts +66 -20
  30. package/src/storage-takeover/storage-backend.ts +65 -21
  31. package/src/storage-takeover/types.ts +11 -3
  32. package/src/testing.ts +3 -0
@@ -1,4 +1,4 @@
1
- import { C as EventRow, w as SessionRow } from "./schema-Bo6Hy5gW.mjs";
1
+ import { C as EventRow, w as SessionRow } from "./schema-BkQN5GyT.mjs";
2
2
  import { SESSION_IMPORT_PATH, SESSION_LOG_ARTIFACT_FILENAME, parseImportZip, parseJsonlArtifact, persistImport, registerSessionImport } from "./import.mjs";
3
3
  import { SessionStorageMetadata } from "@deepseek-ai/dsh-session-persistence";
4
4
  import { SessionEvent, SessionHeader } from "@deepseek-ai/dsh-session";
package/dist/artifact.mjs CHANGED
@@ -1,3 +1,3 @@
1
1
  import { _ as toJsonlArtifact, a as repairAssistantSettlement, c as repairRequestHeaders, d as rowToMeta, f as scanRows, g as titleOfEventData, h as syncMeteringRanges, i as renameLegacyPtcEvents, l as repairSurfaceOps, m as sessionInsertRow, n as orphanInboxSpliceSeqs, o as repairOrphanInboxSplices, p as sessionConflictRow, r as recomputeReplaceProvenance, s as repairReadView, t as findSurfaceRepairs, u as rowToEvent } from "./log-DO69NQnn.mjs";
2
- import { a as persistImport, i as parseJsonlArtifact, n as SESSION_LOG_ARTIFACT_FILENAME, o as registerSessionImport, r as parseImportZip, t as SESSION_IMPORT_PATH } from "./import-DZIAjOUr.mjs";
2
+ import { SESSION_IMPORT_PATH, SESSION_LOG_ARTIFACT_FILENAME, parseImportZip, parseJsonlArtifact, persistImport, registerSessionImport } from "./import.mjs";
3
3
  export { SESSION_IMPORT_PATH, SESSION_LOG_ARTIFACT_FILENAME, findSurfaceRepairs, orphanInboxSpliceSeqs, parseImportZip, parseJsonlArtifact, persistImport, recomputeReplaceProvenance, registerSessionImport, renameLegacyPtcEvents, repairAssistantSettlement, repairOrphanInboxSplices, repairReadView, repairRequestHeaders, repairSurfaceOps, rowToEvent, rowToMeta, scanRows, sessionConflictRow, sessionInsertRow, syncMeteringRanges, titleOfEventData, toJsonlArtifact };
@@ -1,9 +1,7 @@
1
1
  import { d as rowToMeta } from "./log-DO69NQnn.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import { SESSION_FORMAT_VERSION, SessionLogOffset } from "@deepseek-ai/dsh-session";
4
- import { sessionFormatCatalog } from "@deepseek-ai/dsh-session-format-catalog";
5
4
  import { SessionBranch, SessionBranchError, balanceRewindPrefix, buildTimeline } from "@morlay/session-branch";
6
- import { unzipSync } from "fflate";
7
5
  //#region src/branch.ts
8
6
  function locateTurnEnd(events, atSeq, mode = "after") {
9
7
  const ends = events.filter((event) => event.type === "turn/end").map((event) => event.seq);
@@ -278,187 +276,4 @@ var SessionBranchRdb = class extends SessionBranch {
278
276
  }
279
277
  };
280
278
  //#endregion
281
- //#region src/import.ts
282
- const SESSION_LOG_ARTIFACT_FILENAME = "session.jsonl";
283
- const SESSION_IMPORT_PATH = "/api/session.import";
284
- const MAX_IMPORT_ZIP_BYTES = 67108864;
285
- function parseJsonlArtifact(content) {
286
- const lines = content.split("\n");
287
- if (lines.length === 0 || lines[0] === "") throw new Error("imported session log is empty");
288
- let header;
289
- try {
290
- header = JSON.parse(lines[0]);
291
- } catch {
292
- throw new Error("imported session log has an unparsable header line");
293
- }
294
- let restore;
295
- try {
296
- restore = sessionFormatCatalog.createRestore(header, {
297
- recovery: "strict",
298
- validation: "transformed"
299
- });
300
- } catch (error) {
301
- throw new Error(`imported session log has an invalid header line: ${error instanceof Error ? error.message : String(error)}`);
302
- }
303
- for (let i = 1; i < lines.length; i++) {
304
- const line = lines[i];
305
- if (line === void 0 || line === "") continue;
306
- let parsed;
307
- try {
308
- parsed = JSON.parse(line);
309
- } catch {
310
- throw new Error(`imported session log has an unparsable event line at ${i}`);
311
- }
312
- try {
313
- restore.decodeRow(parsed);
314
- } catch (error) {
315
- throw new Error(`imported session log has an invalid event line at ${i}: ${error instanceof Error ? error.message : String(error)}`);
316
- }
317
- }
318
- let artifact;
319
- try {
320
- artifact = restore.finish();
321
- } catch (error) {
322
- throw new Error(`imported session log is incomplete: ${error instanceof Error ? error.message : String(error)}`);
323
- }
324
- const meta = artifact.header;
325
- const events = artifact.events;
326
- for (let i = 0; i < events.length; i++) if (events[i].seq !== i) throw new Error(`imported session log seq gap at ${i} (got ${events[i].seq}); import requires a dense log`);
327
- const inheritedEventCount = Math.min(artifact.inheritedEventCount, events.length);
328
- return {
329
- meta: {
330
- version: SESSION_FORMAT_VERSION,
331
- id: meta.id,
332
- createdAt: meta.createdAt,
333
- ...meta.cwd === void 0 ? {} : { cwd: meta.cwd },
334
- ...meta.parentSession === void 0 ? {} : { parentSession: meta.parentSession },
335
- isSeeded: meta.isSeeded,
336
- ...meta.origin === void 0 ? {} : { origin: meta.origin },
337
- ...meta.delegationDepth === void 0 ? {} : { delegationDepth: meta.delegationDepth },
338
- ...meta.agentPreset === void 0 ? {} : { agentPreset: meta.agentPreset }
339
- },
340
- inheritedEventCount: SessionLogOffset(inheritedEventCount),
341
- events
342
- };
343
- }
344
- function parseImportZip(zip) {
345
- let entries;
346
- try {
347
- entries = unzipSync(zip);
348
- } catch {
349
- throw new Error("imported zip is not a valid ZIP archive");
350
- }
351
- const artifact = entries[SESSION_LOG_ARTIFACT_FILENAME];
352
- if (artifact === void 0) throw new Error(`imported zip is missing ${SESSION_LOG_ARTIFACT_FILENAME}`);
353
- return parseJsonlArtifact(new TextDecoder().decode(artifact));
354
- }
355
- async function persistImport(persistence, branch, imported, targetId, sessions) {
356
- const id = targetId ?? `session-${randomUUID()}`;
357
- if (targetId !== void 0) {
358
- if (branch === void 0) throw new Error("sessionBranch service is unavailable");
359
- await branch.rewind(targetId, -1);
360
- const liveHandle = persistence.tracker.writerOf(targetId);
361
- if (liveHandle !== void 0) {
362
- if (imported.events.length > 0) await liveHandle.append(imported.events);
363
- } else {
364
- const handle = await persistence.open(targetId, "write");
365
- try {
366
- if (imported.events.length > 0) await handle.append(imported.events);
367
- } finally {
368
- await handle.close();
369
- }
370
- }
371
- } else {
372
- const handle = await persistence.create({
373
- ...imported.meta,
374
- id
375
- }, { inheritedEventCount: imported.inheritedEventCount });
376
- if (imported.events.length > 0) await handle.append(imported.events);
377
- await handle.close();
378
- }
379
- if (targetId !== void 0) {
380
- const live = sessions?.get(targetId);
381
- if (live !== void 0) replaceLiveSessionLog(live, imported.events);
382
- }
383
- return id;
384
- }
385
- function registerSessionImport(ctx, persistence) {
386
- ctx.inject(["webServer", "connection"], (webCtx) => {
387
- const webServer = webCtx.webServer;
388
- const connection = webCtx.get("connection");
389
- return webCtx.effect(() => webServer.register({
390
- kind: "exact",
391
- path: SESSION_IMPORT_PATH,
392
- handler: async (req, res) => {
393
- const rejection = connection.requestRejection(req);
394
- if (rejection !== void 0) {
395
- res.writeHead(rejection);
396
- res.end(rejection === 401 ? "unauthorized" : "forbidden");
397
- return;
398
- }
399
- const chunks = [];
400
- for await (const chunk of req) chunks.push(chunk);
401
- const body = Buffer.concat(chunks);
402
- let envelope;
403
- try {
404
- envelope = JSON.parse(body.toString("utf8"));
405
- } catch {
406
- res.writeHead(400, { "content-type": "application/json" });
407
- res.end(JSON.stringify({ error: "request body is not JSON" }));
408
- return;
409
- }
410
- if (typeof envelope.zip !== "string" || envelope.zip === "") {
411
- res.writeHead(400, { "content-type": "application/json" });
412
- res.end(JSON.stringify({ error: "missing zip field" }));
413
- return;
414
- }
415
- if (envelope.sessionId !== void 0 && (typeof envelope.sessionId !== "string" || envelope.sessionId === "")) {
416
- res.writeHead(400, { "content-type": "application/json" });
417
- res.end(JSON.stringify({ error: "sessionId must be a non-empty string" }));
418
- return;
419
- }
420
- let zip;
421
- try {
422
- zip = Buffer.from(envelope.zip, "base64");
423
- } catch {
424
- res.writeHead(400, { "content-type": "application/json" });
425
- res.end(JSON.stringify({ error: "zip field is not valid base64" }));
426
- return;
427
- }
428
- if (zip.byteLength > MAX_IMPORT_ZIP_BYTES) {
429
- res.writeHead(413, { "content-type": "application/json" });
430
- res.end(JSON.stringify({ error: "imported zip exceeds the size limit" }));
431
- return;
432
- }
433
- let imported;
434
- try {
435
- imported = parseImportZip(zip);
436
- } catch (error) {
437
- res.writeHead(400, { "content-type": "application/json" });
438
- res.end(JSON.stringify({ error: error instanceof Error ? error.message : "imported zip is invalid" }));
439
- return;
440
- }
441
- const targetId = typeof envelope.sessionId === "string" ? envelope.sessionId : void 0;
442
- const branch = webCtx.get("sessionBranch");
443
- try {
444
- const sessions = webCtx.get("sessions");
445
- const id = await persistImport(persistence, branch, imported, targetId, sessions);
446
- res.writeHead(200, { "content-type": "application/json" });
447
- res.end(JSON.stringify({ sessionId: id }));
448
- } catch (error) {
449
- const message = error instanceof Error ? error.message : String(error);
450
- if (targetId !== void 0 && /not found/i.test(message)) {
451
- res.writeHead(404, { "content-type": "application/json" });
452
- res.end(JSON.stringify({ error: `session "${targetId}" not found` }));
453
- return;
454
- }
455
- res.writeHead(500, { "content-type": "application/json" });
456
- res.end(JSON.stringify({ error: error instanceof Error ? error.message : "import failed" }));
457
- return;
458
- }
459
- }
460
- }), `session-rdb: ${SESSION_IMPORT_PATH} route`);
461
- });
462
- }
463
- //#endregion
464
- export { persistImport as a, SessionBranchRdbProvider as c, parseJsonlArtifact as i, locateTurnEnd as l, SESSION_LOG_ARTIFACT_FILENAME as n, registerSessionImport as o, parseImportZip as r, SessionBranchRdb as s, SESSION_IMPORT_PATH as t };
279
+ export { truncateLiveSession as a, replaceLiveSessionLog as i, SessionBranchRdbProvider as n, locateTurnEnd as r, SessionBranchRdb as t };
package/dist/import.d.mts CHANGED
@@ -1,8 +1,9 @@
1
- import { r as SessionPersistenceRdb } from "./index-BEKoV1Uy.mjs";
1
+ import { r as SessionPersistenceRdb } from "./index-D55G9n4k.mjs";
2
2
  import { SessionStorageMetadata } from "@deepseek-ai/dsh-session-persistence";
3
3
  import { Session, SessionEvent, SessionId } from "@deepseek-ai/dsh-session";
4
4
  import { Context } from "@deepseek-ai/cordis";
5
5
  //#region src/import.d.ts
6
+ /** 当前世代产物的文件名(读入侧接受任意 canonical 世代名,见 parseImportZip)。 */
6
7
  declare const SESSION_LOG_ARTIFACT_FILENAME = "session.jsonl";
7
8
  declare const SESSION_IMPORT_PATH = "/api/session.import";
8
9
  declare function parseJsonlArtifact(content: string): SessionStorageMetadata & {
@@ -17,7 +18,7 @@ declare function persistImport(persistence: SessionPersistenceRdb, branch: {
17
18
  events: SessionEvent[];
18
19
  }, targetId?: SessionId, sessions?: {
19
20
  get(id: SessionId): Session | undefined;
20
- }): Promise<SessionId>;
21
+ }, stopLoop?: (id: SessionId) => Promise<void>): Promise<SessionId>;
21
22
  declare function registerSessionImport(ctx: Context, persistence: SessionPersistenceRdb): void;
22
23
  //#endregion
23
24
  export { SESSION_IMPORT_PATH, SESSION_LOG_ARTIFACT_FILENAME, parseImportZip, parseJsonlArtifact, persistImport, registerSessionImport };
package/dist/import.mjs CHANGED
@@ -1,2 +1,198 @@
1
- import { a as persistImport, i as parseJsonlArtifact, n as SESSION_LOG_ARTIFACT_FILENAME, o as registerSessionImport, r as parseImportZip, t as SESSION_IMPORT_PATH } from "./import-DZIAjOUr.mjs";
1
+ import { i as replaceLiveSessionLog } from "./branch-Co6xlbi0.mjs";
2
+ import { randomUUID } from "node:crypto";
3
+ import { SESSION_FORMAT_VERSION, SessionLogOffset } from "@deepseek-ai/dsh-session";
4
+ import { parseSessionFormatLogFilename } from "@deepseek-ai/dsh-session-format";
5
+ import { sessionFormatCatalog } from "@deepseek-ai/dsh-session-format-catalog";
6
+ import { unzipSync } from "fflate";
7
+ //#region src/import.ts
8
+ /** 当前世代产物的文件名(读入侧接受任意 canonical 世代名,见 parseImportZip)。 */
9
+ const SESSION_LOG_ARTIFACT_FILENAME = "session.jsonl";
10
+ const SESSION_IMPORT_PATH = "/api/session.import";
11
+ const MAX_IMPORT_ZIP_BYTES = 67108864;
12
+ function parseJsonlArtifact(content) {
13
+ const lines = content.split("\n");
14
+ if (lines.length === 0 || lines[0] === "") throw new Error("imported session log is empty");
15
+ let header;
16
+ try {
17
+ header = JSON.parse(lines[0]);
18
+ } catch {
19
+ throw new Error("imported session log has an unparsable header line");
20
+ }
21
+ let restore;
22
+ try {
23
+ restore = sessionFormatCatalog.createRestore(header, {
24
+ recovery: "strict",
25
+ validation: "transformed"
26
+ });
27
+ } catch (error) {
28
+ throw new Error(`imported session log has an invalid header line: ${error instanceof Error ? error.message : String(error)}`);
29
+ }
30
+ for (let i = 1; i < lines.length; i++) {
31
+ const line = lines[i];
32
+ if (line === void 0 || line === "") continue;
33
+ let parsed;
34
+ try {
35
+ parsed = JSON.parse(line);
36
+ } catch {
37
+ throw new Error(`imported session log has an unparsable event line at ${i}`);
38
+ }
39
+ try {
40
+ restore.decodeRow(parsed);
41
+ } catch (error) {
42
+ throw new Error(`imported session log has an invalid event line at ${i}: ${error instanceof Error ? error.message : String(error)}`);
43
+ }
44
+ }
45
+ let artifact;
46
+ try {
47
+ artifact = restore.finish();
48
+ } catch (error) {
49
+ throw new Error(`imported session log is incomplete: ${error instanceof Error ? error.message : String(error)}`);
50
+ }
51
+ const meta = artifact.header;
52
+ const events = artifact.events;
53
+ for (let i = 0; i < events.length; i++) if (events[i].seq !== i) throw new Error(`imported session log seq gap at ${i} (got ${events[i].seq}); import requires a dense log`);
54
+ const inheritedEventCount = Math.min(artifact.inheritedEventCount, events.length);
55
+ return {
56
+ meta: {
57
+ version: SESSION_FORMAT_VERSION,
58
+ id: meta.id,
59
+ createdAt: meta.createdAt,
60
+ ...meta.cwd === void 0 ? {} : { cwd: meta.cwd },
61
+ ...meta.parentSession === void 0 ? {} : { parentSession: meta.parentSession },
62
+ isSeeded: meta.isSeeded,
63
+ ...meta.origin === void 0 ? {} : { origin: meta.origin },
64
+ ...meta.delegationDepth === void 0 ? {} : { delegationDepth: meta.delegationDepth },
65
+ ...meta.agentPreset === void 0 ? {} : { agentPreset: meta.agentPreset }
66
+ },
67
+ inheritedEventCount: SessionLogOffset(inheritedEventCount),
68
+ events
69
+ };
70
+ }
71
+ function parseImportZip(zip) {
72
+ let entries;
73
+ try {
74
+ entries = unzipSync(zip);
75
+ } catch {
76
+ throw new Error("imported zip is not a valid ZIP archive");
77
+ }
78
+ const artifact = Object.entries(entries).find(([name]) => parseSessionFormatLogFilename(name) !== void 0);
79
+ if (artifact === void 0) throw new Error(`imported zip has no session log artifact (expected ${SESSION_LOG_ARTIFACT_FILENAME} or a canonical session.vN.jsonl)`);
80
+ return parseJsonlArtifact(new TextDecoder().decode(artifact[1]));
81
+ }
82
+ async function stopAgentLoop(ctx, sessionId) {
83
+ const agent = ctx.get("agents")?.get(sessionId);
84
+ if (agent === void 0) return;
85
+ agent.cancel?.({ kind: "user" }, { keepInbox: true });
86
+ await agent.whenIdle();
87
+ }
88
+ async function persistImport(persistence, branch, imported, targetId, sessions, stopLoop) {
89
+ const id = targetId ?? `session-${randomUUID()}`;
90
+ if (targetId !== void 0) {
91
+ if (branch === void 0) throw new Error("sessionBranch service is unavailable");
92
+ if (stopLoop !== void 0) await stopLoop(targetId);
93
+ await branch.rewind(targetId, -1);
94
+ const liveHandle = persistence.tracker.writerOf(targetId);
95
+ if (liveHandle !== void 0) {
96
+ if (imported.events.length > 0) await liveHandle.append(imported.events);
97
+ } else {
98
+ const handle = await persistence.open(targetId, "write");
99
+ try {
100
+ if (imported.events.length > 0) await handle.append(imported.events);
101
+ } finally {
102
+ await handle.close();
103
+ }
104
+ }
105
+ } else {
106
+ const handle = await persistence.create({
107
+ ...imported.meta,
108
+ id
109
+ }, { inheritedEventCount: imported.inheritedEventCount });
110
+ if (imported.events.length > 0) await handle.append(imported.events);
111
+ await handle.close();
112
+ }
113
+ if (targetId !== void 0) {
114
+ const live = sessions?.get(targetId);
115
+ if (live !== void 0) replaceLiveSessionLog(live, imported.events);
116
+ }
117
+ return id;
118
+ }
119
+ function registerSessionImport(ctx, persistence) {
120
+ ctx.inject(["webServer", "connection"], (webCtx) => {
121
+ const webServer = webCtx.webServer;
122
+ const connection = webCtx.get("connection");
123
+ return webCtx.effect(() => webServer.register({
124
+ kind: "exact",
125
+ path: SESSION_IMPORT_PATH,
126
+ handler: async (req, res) => {
127
+ const rejection = connection.requestRejection(req);
128
+ if (rejection !== void 0) {
129
+ res.writeHead(rejection);
130
+ res.end(rejection === 401 ? "unauthorized" : "forbidden");
131
+ return;
132
+ }
133
+ const chunks = [];
134
+ for await (const chunk of req) chunks.push(chunk);
135
+ const body = Buffer.concat(chunks);
136
+ let envelope;
137
+ try {
138
+ envelope = JSON.parse(body.toString("utf8"));
139
+ } catch {
140
+ res.writeHead(400, { "content-type": "application/json" });
141
+ res.end(JSON.stringify({ error: "request body is not JSON" }));
142
+ return;
143
+ }
144
+ if (typeof envelope.zip !== "string" || envelope.zip === "") {
145
+ res.writeHead(400, { "content-type": "application/json" });
146
+ res.end(JSON.stringify({ error: "missing zip field" }));
147
+ return;
148
+ }
149
+ if (envelope.sessionId !== void 0 && (typeof envelope.sessionId !== "string" || envelope.sessionId === "")) {
150
+ res.writeHead(400, { "content-type": "application/json" });
151
+ res.end(JSON.stringify({ error: "sessionId must be a non-empty string" }));
152
+ return;
153
+ }
154
+ let zip;
155
+ try {
156
+ zip = Buffer.from(envelope.zip, "base64");
157
+ } catch {
158
+ res.writeHead(400, { "content-type": "application/json" });
159
+ res.end(JSON.stringify({ error: "zip field is not valid base64" }));
160
+ return;
161
+ }
162
+ if (zip.byteLength > MAX_IMPORT_ZIP_BYTES) {
163
+ res.writeHead(413, { "content-type": "application/json" });
164
+ res.end(JSON.stringify({ error: "imported zip exceeds the size limit" }));
165
+ return;
166
+ }
167
+ let imported;
168
+ try {
169
+ imported = parseImportZip(zip);
170
+ } catch (error) {
171
+ res.writeHead(400, { "content-type": "application/json" });
172
+ res.end(JSON.stringify({ error: error instanceof Error ? error.message : "imported zip is invalid" }));
173
+ return;
174
+ }
175
+ const targetId = typeof envelope.sessionId === "string" ? envelope.sessionId : void 0;
176
+ const branch = webCtx.get("sessionBranch");
177
+ try {
178
+ const sessions = webCtx.get("sessions");
179
+ const id = await persistImport(persistence, branch, imported, targetId, sessions, (sessionId) => stopAgentLoop(webCtx, sessionId));
180
+ res.writeHead(200, { "content-type": "application/json" });
181
+ res.end(JSON.stringify({ sessionId: id }));
182
+ } catch (error) {
183
+ const message = error instanceof Error ? error.message : String(error);
184
+ if (targetId !== void 0 && /not found/i.test(message)) {
185
+ res.writeHead(404, { "content-type": "application/json" });
186
+ res.end(JSON.stringify({ error: `session "${targetId}" not found` }));
187
+ return;
188
+ }
189
+ res.writeHead(500, { "content-type": "application/json" });
190
+ res.end(JSON.stringify({ error: error instanceof Error ? error.message : "import failed" }));
191
+ return;
192
+ }
193
+ }
194
+ }), `session-rdb: ${SESSION_IMPORT_PATH} route`);
195
+ });
196
+ }
197
+ //#endregion
2
198
  export { SESSION_IMPORT_PATH, SESSION_LOG_ARTIFACT_FILENAME, parseImportZip, parseJsonlArtifact, persistImport, registerSessionImport };
@@ -1,4 +1,4 @@
1
- import { a as JournalMode, b as WriteGuard, x as Backend } from "./schema-Bo6Hy5gW.mjs";
1
+ import { a as JournalMode, b as WriteGuard, x as Backend } from "./schema-BkQN5GyT.mjs";
2
2
  import z from "@deepseek-ai/schemastery";
3
3
  import { SessionAccess, SessionHandle, SessionHandleAppendOptions, SessionHandleFlushOptions, SessionHandleReadOptions, SessionHandleReadResult, SessionPersistence, SessionPersistenceCreateOptions, SessionPersistenceListOptions, SessionPersistenceOpenOptions, SessionPersistenceRevision, SessionPersistenceSnapshot, SessionPersistenceStatOptions } from "@deepseek-ai/dsh-session-persistence";
4
4
  import { Session, SessionEvent, SessionHeader, SessionId, SessionLogOffset } from "@deepseek-ai/dsh-session";
@@ -32,6 +32,7 @@ interface LiveAgentLike {
32
32
  clear(): void;
33
33
  };
34
34
  }
35
+ declare function truncateLiveSession(session: Session, newLength: number): void;
35
36
  declare class SessionBranchRdbProvider implements SessionBranchProvider {
36
37
  private readonly persistence;
37
38
  private readonly live;
@@ -203,7 +204,7 @@ declare class SessionPersistenceRdb extends SessionPersistence {
203
204
  flush(): Promise<void>;
204
205
  stat(id: SessionId, options?: SessionPersistenceStatOptions): Promise<SessionPersistenceSnapshot | undefined>;
205
206
  list(options?: SessionPersistenceListOptions): Promise<readonly SessionPersistenceSnapshot[]>;
206
- /** 导出 artifact(jsonl v2 文本),视图只读不落库。 */
207
+ /** 导出当前世代的 jsonl artifact,视图只读不落库。 */
207
208
  readRaw(id: SessionId, signal?: AbortSignal): Promise<{
208
209
  meta: SessionHeader;
209
210
  inheritedEventCount: number;
@@ -267,4 +268,4 @@ declare class SessionPersistenceRdb extends SessionPersistence {
267
268
  private ensureLiveHandle;
268
269
  }
269
270
  //#endregion
270
- export { SessionBranchRdb as a, SessionPersistenceRdbInternals as i, ProjectionCacheOptions as n, SessionBranchRdbProvider as o, SessionPersistenceRdb as r, locateTurnEnd as s, Config as t };
271
+ export { SessionBranchRdb as a, truncateLiveSession as c, SessionPersistenceRdbInternals as i, ProjectionCacheOptions as n, SessionBranchRdbProvider as o, SessionPersistenceRdb as r, locateTurnEnd as s, Config as t };
package/dist/index.d.mts CHANGED
@@ -1,3 +1,3 @@
1
- import { o as SCHEMA_VERSION } from "./schema-Bo6Hy5gW.mjs";
2
- import { a as SessionBranchRdb, i as SessionPersistenceRdbInternals, n as ProjectionCacheOptions, o as SessionBranchRdbProvider, r as SessionPersistenceRdb, s as locateTurnEnd, t as Config } from "./index-BEKoV1Uy.mjs";
1
+ import { o as SCHEMA_VERSION } from "./schema-BkQN5GyT.mjs";
2
+ import { a as SessionBranchRdb, i as SessionPersistenceRdbInternals, n as ProjectionCacheOptions, o as SessionBranchRdbProvider, r as SessionPersistenceRdb, s as locateTurnEnd, t as Config } from "./index-D55G9n4k.mjs";
3
3
  export { Config, ProjectionCacheOptions, SCHEMA_VERSION, SessionBranchRdb, SessionBranchRdbProvider, SessionPersistenceRdb, SessionPersistenceRdb as default, SessionPersistenceRdbInternals, locateTurnEnd };