@morlay/session-rdb 0.1.10-alpha.0 → 0.1.10-alpha.3

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 (142) hide show
  1. package/README.md +18 -3
  2. package/dist/artifact.d.mts +118 -2
  3. package/dist/artifact.mjs +5 -3
  4. package/dist/{log-TYgd8Xkr.d.mts → backend-BKtJ5sO5.d.mts} +183 -284
  5. package/dist/backend-rdb-BDCntVDy.mjs +1341 -0
  6. package/dist/branch-CG1PUlO6.mjs +833 -0
  7. package/dist/deletion-SSX7IqU8.mjs +35 -0
  8. package/dist/deletion.d.mts +1 -1
  9. package/dist/deletion.mjs +2 -2
  10. package/dist/export-CfJQjQfr.mjs +123 -0
  11. package/dist/export.d.mts +1 -1
  12. package/dist/export.mjs +31 -55
  13. package/dist/import.d.mts +1 -1
  14. package/dist/import.mjs +31 -76
  15. package/dist/index-CUD2ZpTA.d.mts +71 -0
  16. package/dist/index.d.mts +20 -2
  17. package/dist/index.mjs +1561 -4
  18. package/dist/open-YoyD_kah.mjs +561 -0
  19. package/dist/organize.d.mts +9 -0
  20. package/dist/organize.mjs +30 -0
  21. package/dist/route-DpfY0zq-.mjs +114 -0
  22. package/dist/storage.d.mts +41 -48
  23. package/dist/storage.mjs +3 -1
  24. package/dist/testing.d.mts +9 -1
  25. package/dist/testing.mjs +25 -4
  26. package/dist/usage-row-BQQM-_t6.mjs +36 -0
  27. package/dist/usage.d.mts +1 -1
  28. package/dist/usage.mjs +7 -40
  29. package/dist/write-guard-CYrY58GM.mjs +174 -0
  30. package/package.json +32 -36
  31. package/src/artifact.ts +4 -1
  32. package/src/backend-rdb.ts +331 -0
  33. package/src/backend.ts +32 -15
  34. package/src/{branch.ts → branch/index.ts} +109 -110
  35. package/src/branch/port.ts +62 -0
  36. package/src/branch/semantics.ts +69 -0
  37. package/src/db/open.ts +180 -0
  38. package/src/db/stats.ts +449 -0
  39. package/src/deletion-error.ts +17 -0
  40. package/src/deletion.ts +19 -72
  41. package/src/entities/index.ts +16 -1
  42. package/src/entities/v3/event-usage.ts +3 -3
  43. package/src/entities/v3/events.ts +3 -3
  44. package/src/entities/v3/index.ts +4 -16
  45. package/src/entities/v3/persistence-state.ts +3 -3
  46. package/src/entities/v3/schema-meta.ts +3 -3
  47. package/src/entities/v3/session-counts.ts +3 -3
  48. package/src/entities/v3/session-events.ts +3 -3
  49. package/src/entities/v3/session-projcache-rows.ts +3 -3
  50. package/src/entities/v3/session-usage.ts +3 -3
  51. package/src/entities/v3/sessions.ts +3 -3
  52. package/src/entities/v3/storage-records.ts +17 -0
  53. package/src/entities/v3/storage-units.ts +3 -3
  54. package/src/{schema.ts → event-shape.ts} +0 -46
  55. package/src/export.ts +32 -78
  56. package/src/handles.ts +349 -0
  57. package/src/http/route.ts +178 -0
  58. package/src/import-storages.ts +5 -2
  59. package/src/import.ts +63 -125
  60. package/src/index.ts +15 -1666
  61. package/src/legacy.ts +3 -1
  62. package/src/live-routing.ts +205 -0
  63. package/src/log/export.ts +84 -0
  64. package/src/{log.ts → log/repair.ts} +1 -268
  65. package/src/log/rows.ts +107 -0
  66. package/src/log/usage-row.ts +64 -0
  67. package/src/migrations.ts +196 -0
  68. package/src/organize.ts +38 -0
  69. package/src/read-path.ts +190 -0
  70. package/src/routes.ts +2 -1
  71. package/src/rows.ts +25 -77
  72. package/src/session-ops.ts +444 -0
  73. package/src/session-store.ts +675 -0
  74. package/src/stats-fold.ts +44 -0
  75. package/src/storage-takeover/index.ts +2 -5
  76. package/src/storage-takeover/legacy-domain-migration.ts +118 -0
  77. package/src/storage-takeover/projection-cache.ts +122 -71
  78. package/src/storage-takeover/read-model.ts +189 -0
  79. package/src/storage-takeover/repository.ts +236 -442
  80. package/src/storage-takeover/storage-backend.ts +44 -159
  81. package/src/storage-takeover/types.ts +45 -19
  82. package/src/storage-takeover/workspace-documents.ts +65 -0
  83. package/src/storage.ts +4 -2
  84. package/src/testing.ts +21 -1
  85. package/src/usage.ts +11 -65
  86. package/src/version.ts +13 -0
  87. package/src/write-path.ts +286 -0
  88. package/dist/branch-CoPCRKer.mjs +0 -401
  89. package/dist/deletion-CWl89TIR.mjs +0 -2249
  90. package/dist/gc.d.mts +0 -4
  91. package/dist/gc.mjs +0 -48
  92. package/dist/log-CcWy46VE.mjs +0 -558
  93. package/dist/routes-hZjTcX_R.mjs +0 -9
  94. package/dist/sqlite-BNRd1aqR.mjs +0 -1778
  95. package/drizzle/postgres/20260908072805_v2_initial/migration.sql +0 -58
  96. package/drizzle/postgres/20260908072805_v2_initial/snapshot.json +0 -686
  97. package/drizzle/postgres/20260908072806_v3_drop_original_seq/migration.sql +0 -1
  98. package/drizzle/postgres/20260908072806_v3_drop_original_seq/snapshot.json +0 -673
  99. package/drizzle/postgres/20260910120001_v3_storage_tables/migration.sql +0 -65
  100. package/drizzle/postgres/20260910120001_v3_storage_tables/snapshot.json +0 -1183
  101. package/drizzle/postgres/20260910130001_v3_session_title_backfill/migration.sql +0 -10
  102. package/drizzle/postgres/20260910130001_v3_session_title_backfill/snapshot.json +0 -1183
  103. package/drizzle/postgres/20260918120000_v3_event_usage/migration.sql +0 -14
  104. package/drizzle/postgres/20260918120000_v3_event_usage/snapshot.json +0 -1309
  105. package/drizzle/postgres/20260921075900_v3_agent_preset/migration.sql +0 -1
  106. package/drizzle/postgres/20260922090001_v3_pinned_seq/migration.sql +0 -2
  107. package/drizzle/postgres/20260922093001_v3_last_event_at/migration.sql +0 -10
  108. package/drizzle/postgres/20260923120000_v3_usage_materialized/migration.sql +0 -48
  109. package/drizzle/postgres/20261008103001_v3_schedule_tasks/migration.sql +0 -11
  110. package/drizzle/sqlite/20260908072751_v2_initial/migration.sql +0 -53
  111. package/drizzle/sqlite/20260908072751_v2_initial/snapshot.json +0 -492
  112. package/drizzle/sqlite/20260908072752_v3_drop_original_seq/migration.sql +0 -6
  113. package/drizzle/sqlite/20260908072752_v3_drop_original_seq/snapshot.json +0 -513
  114. package/drizzle/sqlite/20260910120000_v3_storage_tables/migration.sql +0 -66
  115. package/drizzle/sqlite/20260910120000_v3_storage_tables/snapshot.json +0 -905
  116. package/drizzle/sqlite/20260910130000_v3_session_title_backfill/migration.sql +0 -13
  117. package/drizzle/sqlite/20260910130000_v3_session_title_backfill/snapshot.json +0 -905
  118. package/drizzle/sqlite/20260918120000_v3_event_usage/migration.sql +0 -14
  119. package/drizzle/sqlite/20260918120000_v3_event_usage/snapshot.json +0 -1031
  120. package/drizzle/sqlite/20260921075855_v3_agent_preset/migration.sql +0 -7
  121. package/drizzle/sqlite/20260921075855_v3_agent_preset/snapshot.json +0 -1041
  122. package/drizzle/sqlite/20260922090000_v3_pinned_seq/migration.sql +0 -4
  123. package/drizzle/sqlite/20260922093000_v3_last_event_at/migration.sql +0 -13
  124. package/drizzle/sqlite/20260923120000_v3_usage_materialized/migration.sql +0 -48
  125. package/drizzle/sqlite/20261008103000_v3_schedule_tasks/migration.sql +0 -14
  126. package/src/adapters/index.ts +0 -12
  127. package/src/adapters/to-postgres.ts +0 -93
  128. package/src/adapters/to-sqlite.ts +0 -83
  129. package/src/adapters/types.ts +0 -44
  130. package/src/drizzle/postgres-v2.ts +0 -10
  131. package/src/drizzle/postgres-v3.ts +0 -18
  132. package/src/drizzle/sqlite-v2.ts +0 -9
  133. package/src/drizzle/sqlite-v3.ts +0 -18
  134. package/src/entities/v2/index.ts +0 -20
  135. package/src/entities/v2/session-events.ts +0 -10
  136. package/src/entities/v3/schedule-tasks.ts +0 -16
  137. package/src/entities/v3/workspace-sessions.ts +0 -19
  138. package/src/entities/v3/workspace-state.ts +0 -12
  139. package/src/entities/v3/workspaces.ts +0 -14
  140. package/src/gc.ts +0 -77
  141. package/src/postgres.ts +0 -1015
  142. package/src/sqlite.ts +0 -1096
package/src/import.ts CHANGED
@@ -6,10 +6,11 @@ import { parseSessionFormatLogFilename } from "@deepseek-ai/dsh-session-format";
6
6
  import type { SessionStorageMetadata } from "@deepseek-ai/dsh-session-persistence";
7
7
  import { balanceRewindPrefix } from "@morlay/session-branch";
8
8
  import { unzip } from "fflate";
9
- import { replaceLiveSessionLog } from "./branch.ts";
9
+ import { replaceLiveSessionLog } from "./branch/index.ts";
10
10
  import { restoreCatalog } from "./legacy.ts";
11
- import type { SessionPersistenceRdb } from "./index.ts";
11
+ import type { SessionPersistenceRdb } from "./session-store.ts";
12
12
  import { SESSION_IMPORT_PATH } from "./routes.ts";
13
+ import { HttpError, mountJsonRoute } from "./http/route.ts";
13
14
 
14
15
  export const SESSION_LOG_ARTIFACT_FILENAME = "session.jsonl";
15
16
 
@@ -210,128 +211,65 @@ export async function persistImport(
210
211
  }
211
212
 
212
213
  export function registerSessionImport(ctx: Context, persistence: SessionPersistenceRdb): void {
213
- ctx.inject(["webServer", "connection"] as const, (webCtx) => {
214
- const webServer = webCtx.webServer as unknown as {
215
- register(route: {
216
- kind: "exact";
217
- path: string;
218
- handler: (
219
- req: import("node:http").IncomingMessage,
220
- res: import("node:http").ServerResponse,
221
- ) => void | Promise<void>;
222
- }): () => void;
223
- };
224
- const connection = webCtx.get("connection") as unknown as {
225
- requestRejection(request: {
226
- headers: import("node:http").IncomingHttpHeaders;
227
- }): number | undefined;
228
- };
229
- return webCtx.effect(
230
- () =>
231
- webServer.register({
232
- kind: "exact",
233
- path: SESSION_IMPORT_PATH,
234
- handler: async (req, res) => {
235
- const rejection = connection.requestRejection(req);
236
- if (rejection !== undefined) {
237
- res.writeHead(rejection);
238
- res.end(rejection === 401 ? "unauthorized" : "forbidden");
239
- return;
240
- }
241
- const chunks: Buffer[] = [];
242
- for await (const chunk of req) chunks.push(chunk as Buffer);
243
- const body = Buffer.concat(chunks);
244
- let envelope: { zip?: unknown; sessionId?: unknown };
245
- try {
246
- envelope = JSON.parse(body.toString("utf8")) as {
247
- zip?: unknown;
248
- sessionId?: unknown;
249
- };
250
- } catch {
251
- res.writeHead(400, { "content-type": "application/json" });
252
- res.end(JSON.stringify({ error: "request body is not JSON" }));
253
- return;
254
- }
255
- if (typeof envelope.zip !== "string" || envelope.zip === "") {
256
- res.writeHead(400, { "content-type": "application/json" });
257
- res.end(JSON.stringify({ error: "missing zip field" }));
258
- return;
259
- }
260
- if (
261
- envelope.sessionId !== undefined &&
262
- (typeof envelope.sessionId !== "string" || envelope.sessionId === "")
263
- ) {
264
- res.writeHead(400, { "content-type": "application/json" });
265
- res.end(JSON.stringify({ error: "sessionId must be a non-empty string" }));
266
- return;
267
- }
268
- let zip: Uint8Array;
269
- try {
270
- zip = Buffer.from(envelope.zip, "base64");
271
- } catch {
272
- res.writeHead(400, { "content-type": "application/json" });
273
- res.end(JSON.stringify({ error: "zip field is not valid base64" }));
274
- return;
275
- }
276
- if (zip.byteLength > MAX_IMPORT_ZIP_BYTES) {
277
- res.writeHead(413, { "content-type": "application/json" });
278
- res.end(JSON.stringify({ error: "imported zip exceeds the size limit" }));
279
- return;
280
- }
281
- let imported: SessionStorageMetadata & { events: SessionEvent[] };
282
- try {
283
- imported = await parseImportZip(zip);
284
- } catch (error: unknown) {
285
- res.writeHead(400, { "content-type": "application/json" });
286
- res.end(
287
- JSON.stringify({
288
- error: error instanceof Error ? error.message : "imported zip is invalid",
289
- }),
290
- );
291
- return;
292
- }
293
- const targetId =
294
- typeof envelope.sessionId === "string"
295
- ? (envelope.sessionId as SessionId)
296
- : undefined;
297
- const branch = webCtx.get("sessionBranch") as unknown as
298
- | {
299
- rewind(id: SessionId, toBoundary: number): Promise<unknown>;
300
- resetLiveDerivedState?(session: Session): void;
301
- }
302
- | undefined;
303
- try {
304
- const sessions = webCtx.get("sessions") as
305
- | { get(id: SessionId): Session | undefined }
306
- | undefined;
307
- const id = await persistImport(
308
- persistence,
309
- branch,
310
- imported,
311
- targetId,
312
- sessions,
313
- (sessionId) => stopAgentLoop(webCtx, sessionId),
314
- );
315
- res.writeHead(200, { "content-type": "application/json" });
316
- res.end(JSON.stringify({ sessionId: id }));
317
- } catch (error: unknown) {
318
- const message = error instanceof Error ? error.message : String(error);
319
- if (targetId !== undefined && /not found/i.test(message)) {
320
- res.writeHead(404, { "content-type": "application/json" });
321
- res.end(JSON.stringify({ error: `session "${targetId}" not found` }));
322
- return;
323
- }
324
- res.writeHead(500, { "content-type": "application/json" });
325
- res.end(
326
- JSON.stringify({
327
- error: error instanceof Error ? error.message : "import failed",
328
- }),
329
- );
330
- return;
331
- }
332
- },
333
- }),
334
- `session-rdb: ${SESSION_IMPORT_PATH} route`,
335
- );
214
+ mountJsonRoute(ctx, {
215
+ path: SESSION_IMPORT_PATH,
216
+ handle: async (body, webCtx) => {
217
+ const envelope = body as { zip?: unknown; sessionId?: unknown };
218
+ if (typeof envelope.zip !== "string" || envelope.zip === "") {
219
+ throw new HttpError(400, "missing zip field");
220
+ }
221
+ if (
222
+ envelope.sessionId !== undefined &&
223
+ (typeof envelope.sessionId !== "string" || envelope.sessionId === "")
224
+ ) {
225
+ throw new HttpError(400, "sessionId must be a non-empty string");
226
+ }
227
+ let zip: Uint8Array;
228
+ try {
229
+ zip = Buffer.from(envelope.zip, "base64");
230
+ } catch {
231
+ throw new HttpError(400, "zip field is not valid base64");
232
+ }
233
+ if (zip.byteLength > MAX_IMPORT_ZIP_BYTES) {
234
+ throw new HttpError(413, "imported zip exceeds the size limit");
235
+ }
236
+ let imported: SessionStorageMetadata & { events: SessionEvent[] };
237
+ try {
238
+ imported = await parseImportZip(zip);
239
+ } catch (error: unknown) {
240
+ throw new HttpError(
241
+ 400,
242
+ error instanceof Error ? error.message : "imported zip is invalid",
243
+ );
244
+ }
245
+ const targetId =
246
+ typeof envelope.sessionId === "string" ? (envelope.sessionId as SessionId) : undefined;
247
+ const branch = webCtx.get("sessionBranch") as unknown as
248
+ | {
249
+ rewind(id: SessionId, toBoundary: number): Promise<unknown>;
250
+ resetLiveDerivedState?(session: Session): void;
251
+ }
252
+ | undefined;
253
+ const sessions = webCtx.get("sessions") as
254
+ | { get(id: SessionId): Session | undefined }
255
+ | undefined;
256
+ try {
257
+ const id = await persistImport(
258
+ persistence,
259
+ branch,
260
+ imported,
261
+ targetId,
262
+ sessions,
263
+ (sessionId) => stopAgentLoop(webCtx, sessionId),
264
+ );
265
+ return { body: { sessionId: id } };
266
+ } catch (error: unknown) {
267
+ const message = error instanceof Error ? error.message : String(error);
268
+ if (targetId !== undefined && /not found/i.test(message)) {
269
+ throw new HttpError(404, `session "${targetId}" not found`);
270
+ }
271
+ throw error;
272
+ }
273
+ },
336
274
  });
337
275
  }