@morlay/session-rdb 0.1.9 → 0.1.10-alpha.2

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 (143) hide show
  1. package/README.md +24 -3
  2. package/dist/artifact.d.mts +118 -3
  3. package/dist/artifact.mjs +5 -3
  4. package/dist/{log-C0q5svm7.d.mts → backend-BKtJ5sO5.d.mts} +189 -291
  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 -3
  9. package/dist/deletion.mjs +2 -2
  10. package/dist/export-CfJQjQfr.mjs +123 -0
  11. package/dist/export.d.mts +1 -3
  12. package/dist/export.mjs +32 -57
  13. package/dist/import.d.mts +1 -3
  14. package/dist/import.mjs +32 -78
  15. package/dist/index-CUD2ZpTA.d.mts +71 -0
  16. package/dist/index.d.mts +20 -2
  17. package/dist/index.mjs +1562 -5
  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 -50
  23. package/dist/storage.mjs +3 -1
  24. package/dist/testing.d.mts +9 -5
  25. package/dist/testing.mjs +27 -8
  26. package/dist/usage-row-BQQM-_t6.mjs +36 -0
  27. package/dist/usage.d.mts +1 -1
  28. package/dist/usage.mjs +8 -42
  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} +125 -112
  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 -1630
  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 -272
  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-query.ts +17 -4
  74. package/src/session-store.ts +675 -0
  75. package/src/stats-fold.ts +44 -0
  76. package/src/storage-takeover/index.ts +2 -5
  77. package/src/storage-takeover/legacy-domain-migration.ts +118 -0
  78. package/src/storage-takeover/projection-cache.ts +139 -77
  79. package/src/storage-takeover/read-model.ts +189 -0
  80. package/src/storage-takeover/repository.ts +238 -425
  81. package/src/storage-takeover/storage-backend.ts +47 -149
  82. package/src/storage-takeover/types.ts +45 -14
  83. package/src/storage-takeover/workspace-documents.ts +65 -0
  84. package/src/storage.ts +4 -2
  85. package/src/testing.ts +21 -1
  86. package/src/usage.ts +11 -65
  87. package/src/version.ts +13 -0
  88. package/src/write-path.ts +286 -0
  89. package/dist/branch-DbFW3rJX.mjs +0 -391
  90. package/dist/deletion-ODZFcbZm.mjs +0 -2218
  91. package/dist/gc.d.mts +0 -6
  92. package/dist/gc.mjs +0 -49
  93. package/dist/log-DYxdjJ-l.mjs +0 -562
  94. package/dist/routes-DGBlBE_I.mjs +0 -10
  95. package/dist/sqlite-DjOnMRh2.mjs +0 -1777
  96. package/drizzle/postgres/20260908072805_v2_initial/migration.sql +0 -58
  97. package/drizzle/postgres/20260908072805_v2_initial/snapshot.json +0 -686
  98. package/drizzle/postgres/20260908072806_v3_drop_original_seq/migration.sql +0 -1
  99. package/drizzle/postgres/20260908072806_v3_drop_original_seq/snapshot.json +0 -673
  100. package/drizzle/postgres/20260910120001_v3_storage_tables/migration.sql +0 -65
  101. package/drizzle/postgres/20260910120001_v3_storage_tables/snapshot.json +0 -1183
  102. package/drizzle/postgres/20260910130001_v3_session_title_backfill/migration.sql +0 -10
  103. package/drizzle/postgres/20260910130001_v3_session_title_backfill/snapshot.json +0 -1183
  104. package/drizzle/postgres/20260918120000_v3_event_usage/migration.sql +0 -14
  105. package/drizzle/postgres/20260918120000_v3_event_usage/snapshot.json +0 -1309
  106. package/drizzle/postgres/20260921075900_v3_agent_preset/migration.sql +0 -1
  107. package/drizzle/postgres/20260922090001_v3_pinned_seq/migration.sql +0 -2
  108. package/drizzle/postgres/20260922093001_v3_last_event_at/migration.sql +0 -10
  109. package/drizzle/postgres/20260923120000_v3_usage_materialized/migration.sql +0 -48
  110. package/drizzle/postgres/20261008103001_v3_schedule_tasks/migration.sql +0 -11
  111. package/drizzle/sqlite/20260908072751_v2_initial/migration.sql +0 -53
  112. package/drizzle/sqlite/20260908072751_v2_initial/snapshot.json +0 -492
  113. package/drizzle/sqlite/20260908072752_v3_drop_original_seq/migration.sql +0 -6
  114. package/drizzle/sqlite/20260908072752_v3_drop_original_seq/snapshot.json +0 -513
  115. package/drizzle/sqlite/20260910120000_v3_storage_tables/migration.sql +0 -66
  116. package/drizzle/sqlite/20260910120000_v3_storage_tables/snapshot.json +0 -905
  117. package/drizzle/sqlite/20260910130000_v3_session_title_backfill/migration.sql +0 -13
  118. package/drizzle/sqlite/20260910130000_v3_session_title_backfill/snapshot.json +0 -905
  119. package/drizzle/sqlite/20260918120000_v3_event_usage/migration.sql +0 -14
  120. package/drizzle/sqlite/20260918120000_v3_event_usage/snapshot.json +0 -1031
  121. package/drizzle/sqlite/20260921075855_v3_agent_preset/migration.sql +0 -7
  122. package/drizzle/sqlite/20260921075855_v3_agent_preset/snapshot.json +0 -1041
  123. package/drizzle/sqlite/20260922090000_v3_pinned_seq/migration.sql +0 -4
  124. package/drizzle/sqlite/20260922093000_v3_last_event_at/migration.sql +0 -13
  125. package/drizzle/sqlite/20260923120000_v3_usage_materialized/migration.sql +0 -48
  126. package/drizzle/sqlite/20261008103000_v3_schedule_tasks/migration.sql +0 -14
  127. package/src/adapters/index.ts +0 -12
  128. package/src/adapters/to-postgres.ts +0 -93
  129. package/src/adapters/to-sqlite.ts +0 -83
  130. package/src/adapters/types.ts +0 -44
  131. package/src/drizzle/postgres-v2.ts +0 -10
  132. package/src/drizzle/postgres-v3.ts +0 -18
  133. package/src/drizzle/sqlite-v2.ts +0 -9
  134. package/src/drizzle/sqlite-v3.ts +0 -18
  135. package/src/entities/v2/index.ts +0 -20
  136. package/src/entities/v2/session-events.ts +0 -10
  137. package/src/entities/v3/schedule-tasks.ts +0 -16
  138. package/src/entities/v3/workspace-sessions.ts +0 -19
  139. package/src/entities/v3/workspace-state.ts +0 -12
  140. package/src/entities/v3/workspaces.ts +0 -14
  141. package/src/gc.ts +0 -77
  142. package/src/postgres.ts +0 -1015
  143. package/src/sqlite.ts +0 -1086
package/src/deletion.ts CHANGED
@@ -1,7 +1,9 @@
1
1
  import type { Context } from "@deepseek-ai/cordis";
2
2
  import type { SessionId } from "@deepseek-ai/dsh-session";
3
- import { SessionDeletionError, type SessionPersistenceRdb } from "./index.ts";
3
+ import { SessionDeletionError } from "./deletion-error.ts";
4
+ import type { SessionPersistenceRdb } from "./session-store.ts";
4
5
  import { SESSION_DELETE_PATH } from "./routes.ts";
6
+ import { HttpError, mountJsonRoute } from "./http/route.ts";
5
7
 
6
8
  export { SESSION_DELETE_PATH };
7
9
 
@@ -12,77 +14,22 @@ const STATUS_OF_DELETION_ERROR: Record<SessionDeletionError["code"], number> = {
12
14
  };
13
15
 
14
16
  export function registerSessionDeletion(ctx: Context, persistence: SessionPersistenceRdb): void {
15
- ctx.inject(["webServer", "connection"] as const, (webCtx) => {
16
- const webServer = webCtx.webServer as unknown as {
17
- register(route: {
18
- kind: "exact";
19
- path: string;
20
- handler: (
21
- req: import("node:http").IncomingMessage,
22
- res: import("node:http").ServerResponse,
23
- ) => void | Promise<void>;
24
- }): () => void;
25
- };
26
- const connection = webCtx.get("connection") as unknown as {
27
- requestRejection(request: {
28
- headers: import("node:http").IncomingHttpHeaders;
29
- }): number | undefined;
30
- };
31
- return webCtx.effect(() =>
32
- webServer.register({
33
- kind: "exact",
34
- path: SESSION_DELETE_PATH,
35
- handler: async (req, res) => {
36
- const rejection = connection.requestRejection(req);
37
- if (rejection !== undefined) {
38
- res.writeHead(rejection);
39
- res.end(rejection === 401 ? "unauthorized" : "forbidden");
40
- return;
17
+ mountJsonRoute(ctx, {
18
+ path: SESSION_DELETE_PATH,
19
+ handle: async (body) => {
20
+ const { sessionId } = body as { sessionId?: unknown };
21
+ if (typeof sessionId !== "string" || sessionId === "") {
22
+ throw new HttpError(400, "missing sessionId field");
23
+ }
24
+ await persistence.deleteSession(sessionId as SessionId);
25
+ return { body: { deleted: sessionId } };
26
+ },
27
+ statusOfError: (error) =>
28
+ error instanceof SessionDeletionError
29
+ ? {
30
+ status: STATUS_OF_DELETION_ERROR[error.code],
31
+ body: { error: error.message, code: error.code },
41
32
  }
42
- if (req.method !== "POST") {
43
- res.writeHead(405, { "content-type": "application/json" });
44
- res.end(JSON.stringify({ error: "method not allowed" }));
45
- return;
46
- }
47
- const chunks: Buffer[] = [];
48
- for await (const chunk of req) chunks.push(chunk as Buffer);
49
- let envelope: { sessionId?: unknown };
50
- try {
51
- envelope = JSON.parse(Buffer.concat(chunks).toString("utf8")) as {
52
- sessionId?: unknown;
53
- };
54
- } catch {
55
- res.writeHead(400, { "content-type": "application/json" });
56
- res.end(JSON.stringify({ error: "request body is not JSON" }));
57
- return;
58
- }
59
- if (typeof envelope.sessionId !== "string" || envelope.sessionId === "") {
60
- res.writeHead(400, { "content-type": "application/json" });
61
- res.end(JSON.stringify({ error: "missing sessionId field" }));
62
- return;
63
- }
64
- try {
65
- await persistence.deleteSession(envelope.sessionId as SessionId);
66
- } catch (error: unknown) {
67
- if (error instanceof SessionDeletionError) {
68
- res.writeHead(STATUS_OF_DELETION_ERROR[error.code], {
69
- "content-type": "application/json",
70
- });
71
- res.end(JSON.stringify({ error: error.message, code: error.code }));
72
- return;
73
- }
74
- res.writeHead(500, { "content-type": "application/json" });
75
- res.end(
76
- JSON.stringify({
77
- error: error instanceof Error ? error.message : "session deletion failed",
78
- }),
79
- );
80
- return;
81
- }
82
- res.writeHead(200, { "content-type": "application/json" });
83
- res.end(JSON.stringify({ deleted: envelope.sessionId }));
84
- },
85
- }),
86
- );
33
+ : undefined,
87
34
  });
88
35
  }
@@ -1,2 +1,17 @@
1
+ import { defineCatalog } from "@morlay/rdbkit";
2
+ import { sqliteTableDefs } from "./v3/index.ts";
3
+
1
4
  export { sqliteTableDefs, postgresTableDefs } from "./v3/index.ts";
2
- export { sqliteTableDefsV2, postgresTableDefsV2 } from "./v2/index.ts";
5
+
6
+ /** 库结构的唯一事实来源(DDL、迁移与表句柄都从它算出来)。 */
7
+ export const catalog = defineCatalog(sqliteTableDefs);
8
+ export { storageRecords } from "./v3/storage-records.ts";
9
+ export { sessionProjcacheRows } from "./v3/session-projcache-rows.ts";
10
+ export { persistenceState } from "./v3/persistence-state.ts";
11
+ export { sessions } from "./v3/sessions.ts";
12
+ export { events } from "./v3/events.ts";
13
+ export { sessionEvents } from "./v3/session-events.ts";
14
+ export { eventUsage } from "./v3/event-usage.ts";
15
+ export { sessionUsage } from "./v3/session-usage.ts";
16
+ export { sessionCounts } from "./v3/session-counts.ts";
17
+ export { storageUnits } from "./v3/storage-units.ts";
@@ -1,9 +1,9 @@
1
- import type { TableDef } from "../../adapters/types.ts";
1
+ import { defineTable } from "@morlay/rdbkit";
2
2
 
3
3
  // 用量日志:一条 `assistant/message` 事件一行(按事件行唯一,fork 共享行不重复);读侧维度全部物化在行上
4
4
  // (本地日、是否被会话引用、是否被子代理会话引用),统计因此不做 `EXISTS` 判定、也不回连事件表。
5
5
  // 取舍见 ADR-统计衍生表物化归属与汇总。
6
- export const eventUsage: TableDef = {
6
+ export const eventUsage = defineTable({
7
7
  name: "t_event_usage",
8
8
  columns: {
9
9
  f_event_id: {
@@ -27,4 +27,4 @@ export const eventUsage: TableDef = {
27
27
  f_total_tokens: { type: "integer", notNull: true, default: 0 },
28
28
  },
29
29
  indexes: { idx_event_usage_created_at: { columns: ["f_created_at"] } },
30
- };
30
+ });
@@ -1,6 +1,6 @@
1
- import type { TableDef } from "../../adapters/types.ts";
1
+ import { defineTable } from "@morlay/rdbkit";
2
2
 
3
- export const events: TableDef = {
3
+ export const events = defineTable({
4
4
  name: "t_events",
5
5
  columns: {
6
6
  f_id: { type: "serial", primaryKey: true },
@@ -22,4 +22,4 @@ export const events: TableDef = {
22
22
  idx_events_name: { columns: ["f_name"] },
23
23
  idx_events_action_id: { columns: ["f_action_id"] },
24
24
  },
25
- };
25
+ });
@@ -4,10 +4,7 @@ import { sessions } from "./sessions.ts";
4
4
  import { events } from "./events.ts";
5
5
  import { sessionEvents } from "./session-events.ts";
6
6
  import { storageUnits } from "./storage-units.ts";
7
- import { workspaces } from "./workspaces.ts";
8
- import { workspaceSessions } from "./workspace-sessions.ts";
9
- import { workspaceState } from "./workspace-state.ts";
10
- import { scheduleTasks } from "./schedule-tasks.ts";
7
+ import { storageRecords } from "./storage-records.ts";
11
8
  import { sessionProjcacheRows } from "./session-projcache-rows.ts";
12
9
  import { eventUsage } from "./event-usage.ts";
13
10
  import { sessionUsage } from "./session-usage.ts";
@@ -19,10 +16,7 @@ export { sessions };
19
16
  export { events };
20
17
  export { sessionEvents };
21
18
  export { storageUnits };
22
- export { workspaces };
23
- export { workspaceSessions };
24
- export { workspaceState };
25
- export { scheduleTasks };
19
+ export { storageRecords };
26
20
  export { sessionProjcacheRows };
27
21
  export { eventUsage };
28
22
  export { sessionUsage };
@@ -35,10 +29,7 @@ export const sqliteTableDefs = [
35
29
  events,
36
30
  sessionEvents,
37
31
  storageUnits,
38
- workspaces,
39
- workspaceSessions,
40
- workspaceState,
41
- scheduleTasks,
32
+ storageRecords,
42
33
  sessionProjcacheRows,
43
34
  eventUsage,
44
35
  sessionUsage,
@@ -52,10 +43,7 @@ export const postgresTableDefs = [
52
43
  events,
53
44
  sessionEvents,
54
45
  storageUnits,
55
- workspaces,
56
- workspaceSessions,
57
- workspaceState,
58
- scheduleTasks,
46
+ storageRecords,
59
47
  sessionProjcacheRows,
60
48
  eventUsage,
61
49
  sessionUsage,
@@ -1,10 +1,10 @@
1
- import type { TableDef } from "../../adapters/types.ts";
1
+ import { defineTable } from "@morlay/rdbkit";
2
2
 
3
- export const persistenceState: TableDef = {
3
+ export const persistenceState = defineTable({
4
4
  name: "t_persistence_state",
5
5
  columns: {
6
6
  f_singleton: { type: "integer", primaryKey: true },
7
7
  f_store_id: { type: "text", notNull: true },
8
8
  },
9
9
  checks: { ck_persistence_state_singleton: { expression: "f_singleton = 1" } },
10
- };
10
+ });
@@ -1,9 +1,9 @@
1
- import type { TableDef } from "../../adapters/types.ts";
1
+ import { defineTable } from "@morlay/rdbkit";
2
2
 
3
- export const schemaMeta: TableDef = {
3
+ export const schemaMeta = defineTable({
4
4
  name: "t_schema_meta",
5
5
  columns: {
6
6
  f_key: { type: "text", primaryKey: true },
7
7
  f_value: { type: "text", notNull: true },
8
8
  },
9
- };
9
+ });
@@ -1,9 +1,9 @@
1
- import type { TableDef } from "../../adapters/types.ts";
1
+ import { defineTable } from "@morlay/rdbkit";
2
2
 
3
3
  // 会话 × 本地日的活动计数(派生统计表):轮次 / 步骤 / 用户输入 / 工具调用四列直接读,
4
4
  // 不再存事件类型、也不在读取时折。旁路累加、可按会话重建,读侧只读;
5
5
  // 取舍见 ADR-统计衍生表物化归属与汇总。
6
- export const sessionCounts: TableDef = {
6
+ export const sessionCounts = defineTable({
7
7
  name: "t_session_counts",
8
8
  columns: {
9
9
  f_session_id: {
@@ -18,4 +18,4 @@ export const sessionCounts: TableDef = {
18
18
  f_tool_calls: { type: "integer", notNull: true, default: 0 },
19
19
  },
20
20
  uniques: { uq_session_counts_key: { columns: ["f_session_id", "f_day"] } },
21
- };
21
+ });
@@ -1,6 +1,6 @@
1
- import type { TableDef } from "../../adapters/types.ts";
1
+ import { defineTable } from "@morlay/rdbkit";
2
2
 
3
- export const sessionEvents: TableDef = {
3
+ export const sessionEvents = defineTable({
4
4
  name: "t_session_events",
5
5
  columns: {
6
6
  f_id: { type: "serial", primaryKey: true },
@@ -22,4 +22,4 @@ export const sessionEvents: TableDef = {
22
22
  },
23
23
 
24
24
  indexes: { idx_session_events_event_id: { columns: ["f_event_id"] } },
25
- };
25
+ });
@@ -1,6 +1,6 @@
1
- import type { TableDef } from "../../adapters/types.ts";
1
+ import { defineTable } from "@morlay/rdbkit";
2
2
 
3
- export const sessionProjcacheRows: TableDef = {
3
+ export const sessionProjcacheRows = defineTable({
4
4
  name: "t_session_projcache_row",
5
5
  columns: {
6
6
  f_id: { type: "serial", primaryKey: true },
@@ -16,4 +16,4 @@ export const sessionProjcacheRows: TableDef = {
16
16
  },
17
17
  uniques: { uq_session_projcache_row_session_key: { columns: ["f_session_id", "f_key"] } },
18
18
  indexes: { idx_session_projcache_row_key: { columns: ["f_key"] } },
19
- };
19
+ });
@@ -1,9 +1,9 @@
1
- import type { TableDef } from "../../adapters/types.ts";
1
+ import { defineTable } from "@morlay/rdbkit";
2
2
 
3
3
  // 会话 × 本地日 × 模型的 token 汇总(派生统计表):**按会话的行**读它,因此保住
4
4
  // 「fork 子会话含继承前缀」的口径(各会话行之和 ≥ 总量)而不回连事件表。
5
5
  // 旁路累加、可按会话重建,读侧只读;取舍见 ADR-统计衍生表物化归属与汇总。
6
- export const sessionUsage: TableDef = {
6
+ export const sessionUsage = defineTable({
7
7
  name: "t_session_usage",
8
8
  columns: {
9
9
  f_session_id: {
@@ -24,4 +24,4 @@ export const sessionUsage: TableDef = {
24
24
  uniques: {
25
25
  uq_session_usage_key: { columns: ["f_session_id", "f_day", "f_provider", "f_model"] },
26
26
  },
27
- };
27
+ });
@@ -1,6 +1,6 @@
1
- import type { TableDef } from "../../adapters/types.ts";
1
+ import { defineTable } from "@morlay/rdbkit";
2
2
 
3
- export const sessions: TableDef = {
3
+ export const sessions = defineTable({
4
4
  name: "t_sessions",
5
5
  columns: {
6
6
  f_id: { type: "serial", primaryKey: true },
@@ -28,4 +28,4 @@ export const sessions: TableDef = {
28
28
 
29
29
  f_title_seq: { type: "integer" },
30
30
  },
31
- };
31
+ });
@@ -0,0 +1,17 @@
1
+ import { defineTable } from "@morlay/rdbkit";
2
+
3
+ // 所有 storage 域共用这一张表:(域, 表, 键) 一行,值是整份记录文档。域是行的一部分,所以新增域
4
+ // (不论它自带几张表、还是只有 global 槽)都不需要再建表——上游 `KvUnit` 的契约本来就只要求
5
+ // 「按表名读写记录 + 一个 global 单例」,行存储直接承载它。global 单例用 `f_table = ''`。
6
+ export const storageRecords = defineTable({
7
+ name: "t_storage_records",
8
+ columns: {
9
+ f_domain: { type: "text", notNull: true },
10
+ f_table: { type: "text", notNull: true },
11
+ f_key: { type: "text", notNull: true },
12
+ f_value: { type: "text", notNull: true },
13
+ },
14
+ uniques: {
15
+ uq_storage_records_domain_table_key: { columns: ["f_domain", "f_table", "f_key"] },
16
+ },
17
+ });
@@ -1,9 +1,9 @@
1
- import type { TableDef } from "../../adapters/types.ts";
1
+ import { defineTable } from "@morlay/rdbkit";
2
2
 
3
- export const storageUnits: TableDef = {
3
+ export const storageUnits = defineTable({
4
4
  name: "t_storage_units",
5
5
  columns: {
6
6
  f_name: { type: "text", primaryKey: true },
7
7
  f_version: { type: "integer", notNull: true },
8
8
  },
9
- };
9
+ });
@@ -1,50 +1,4 @@
1
1
  import type { SessionEvent } from "@deepseek-ai/dsh-session";
2
- import { toSqliteSchema } from "./adapters/index.ts";
3
- import { sqliteTableDefs } from "./entities/index.ts";
4
-
5
- export const SCHEMA_VERSION = 3;
6
-
7
- export const SESSION_PERSISTENCE_SQLITE_APPLICATION_ID = 0x44534850;
8
-
9
- export const EVENT_ENCODING = "json";
10
-
11
- const sqliteTables: Record<string, any> = toSqliteSchema(sqliteTableDefs);
12
-
13
- export const tPersistenceState = sqliteTables["t_persistence_state"]!;
14
-
15
- export const tSchemaMeta = sqliteTables["t_schema_meta"]!;
16
-
17
- export const tSessions = sqliteTables["t_sessions"]!;
18
-
19
- export const tEvents = sqliteTables["t_events"]!;
20
-
21
- export const tSessionEvents = sqliteTables["t_session_events"]!;
22
-
23
- export const tStorageUnits = sqliteTables["t_storage_units"]!;
24
-
25
- export const tWorkspaces = sqliteTables["t_workspaces"]!;
26
-
27
- export const tWorkspaceSessions = sqliteTables["t_workspace_sessions"]!;
28
-
29
- export const tWorkspaceState = sqliteTables["t_workspace_state"]!;
30
-
31
- export const tScheduleTasks = sqliteTables["t_schedule_tasks"]!;
32
-
33
- export const tSessionProjcacheRows = sqliteTables["t_session_projcache_row"]!;
34
-
35
- export const tEventUsage = sqliteTables["t_event_usage"]!;
36
-
37
- export const tSessionUsage = sqliteTables["t_session_usage"]!;
38
-
39
- export const tSessionCounts = sqliteTables["t_session_counts"]!;
40
-
41
- export type { SessionRow } from "./backend.ts";
42
-
43
- export type { EventRow } from "./backend.ts";
44
-
45
- export type JournalMode = "wal" | "delete" | "truncate" | "persist";
46
-
47
- export const DEFAULT_BUSY_TIMEOUT_MS = 5000;
48
2
 
49
3
  export type EventKind =
50
4
  | "message"
package/src/export.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  import { strToU8, zip } from "fflate";
2
2
  import type { Context } from "@deepseek-ai/cordis";
3
3
  import type { SessionId } from "@deepseek-ai/dsh-session";
4
- import type { SessionPersistenceRdb } from "./index.ts";
4
+ import type { SessionPersistenceRdb } from "./session-store.ts";
5
5
  import { SESSION_EXPORT_PATH } from "./routes.ts";
6
+ import { mountRoute } from "./http/route.ts";
6
7
 
7
8
  export { SESSION_EXPORT_PATH };
8
9
 
@@ -23,82 +24,35 @@ function zipBytes(files: Record<string, Uint8Array>): Promise<Uint8Array> {
23
24
 
24
25
  // 导出通道:直接把会话日志打成 zip 响应体,与导入通道读同一份 artifact。
25
26
  export function registerSessionExport(ctx: Context, persistence: SessionPersistenceRdb): void {
26
- ctx.inject(["webServer", "connection"] as const, (webCtx) => {
27
- const webServer = webCtx.webServer as unknown as {
28
- register(route: {
29
- kind: "exact";
30
- path: string;
31
- handler: (
32
- req: import("node:http").IncomingMessage,
33
- res: import("node:http").ServerResponse,
34
- ) => void | Promise<void>;
35
- }): () => void;
36
- };
37
- const connection = webCtx.get("connection") as unknown as {
38
- requestRejection(request: {
39
- headers: import("node:http").IncomingHttpHeaders;
40
- }): number | undefined;
41
- };
42
- return webCtx.effect(
43
- () =>
44
- webServer.register({
45
- kind: "exact",
46
- path: SESSION_EXPORT_PATH,
47
- handler: async (req, res) => {
48
- const rejection = connection.requestRejection(req);
49
- if (rejection !== undefined) {
50
- res.writeHead(rejection);
51
- res.end(rejection === 401 ? "unauthorized" : "forbidden");
52
- return;
53
- }
54
- if (req.method !== "POST") {
55
- res.writeHead(405, { "content-type": "application/json" });
56
- res.end(JSON.stringify({ error: "method not allowed" }));
57
- return;
58
- }
59
- const chunks: Buffer[] = [];
60
- for await (const chunk of req) chunks.push(chunk as Buffer);
61
- let envelope: { sessionId?: unknown };
62
- try {
63
- envelope = JSON.parse(Buffer.concat(chunks).toString("utf8")) as {
64
- sessionId?: unknown;
65
- };
66
- } catch {
67
- res.writeHead(400, { "content-type": "application/json" });
68
- res.end(JSON.stringify({ error: "request body is not JSON" }));
69
- return;
70
- }
71
- if (typeof envelope.sessionId !== "string" || envelope.sessionId === "") {
72
- res.writeHead(400, { "content-type": "application/json" });
73
- res.end(JSON.stringify({ error: "missing sessionId field" }));
74
- return;
75
- }
76
- const sessionId = envelope.sessionId;
77
- try {
78
- const raw = await persistence.readRaw(sessionId as SessionId);
79
- if (raw === undefined) {
80
- res.writeHead(404, { "content-type": "application/json" });
81
- res.end(JSON.stringify({ error: `session "${sessionId}" not found` }));
82
- return;
83
- }
84
- const zipFile = await zipBytes({ [raw.filename]: strToU8(raw.content) });
85
- res.writeHead(200, {
86
- "content-type": "application/zip",
87
- "content-length": String(zipFile.byteLength),
88
- "content-disposition": `attachment; filename="${safeFilename(sessionId)}.zip"`,
89
- });
90
- res.end(Buffer.from(zipFile));
91
- } catch (error: unknown) {
92
- res.writeHead(500, { "content-type": "application/json" });
93
- res.end(
94
- JSON.stringify({
95
- error: error instanceof Error ? error.message : "session export failed",
96
- }),
97
- );
98
- }
99
- },
100
- }),
101
- `session-rdb: ${SESSION_EXPORT_PATH} route`,
102
- );
27
+ mountRoute(ctx, SESSION_EXPORT_PATH, async (req, res) => {
28
+ const chunks: Buffer[] = [];
29
+ for await (const chunk of req) chunks.push(chunk as Buffer);
30
+ let envelope: { sessionId?: unknown };
31
+ try {
32
+ envelope = JSON.parse(Buffer.concat(chunks).toString("utf8")) as { sessionId?: unknown };
33
+ } catch {
34
+ res.writeHead(400, { "content-type": "application/json" });
35
+ res.end(JSON.stringify({ error: "request body is not JSON" }));
36
+ return;
37
+ }
38
+ if (typeof envelope.sessionId !== "string" || envelope.sessionId === "") {
39
+ res.writeHead(400, { "content-type": "application/json" });
40
+ res.end(JSON.stringify({ error: "missing sessionId field" }));
41
+ return;
42
+ }
43
+ const sessionId = envelope.sessionId;
44
+ const raw = await persistence.readRaw(sessionId as SessionId);
45
+ if (raw === undefined) {
46
+ res.writeHead(404, { "content-type": "application/json" });
47
+ res.end(JSON.stringify({ error: `session "${sessionId}" not found` }));
48
+ return;
49
+ }
50
+ const zipFile = await zipBytes({ [raw.filename]: strToU8(raw.content) });
51
+ res.writeHead(200, {
52
+ "content-type": "application/zip",
53
+ "content-length": String(zipFile.byteLength),
54
+ "content-disposition": `attachment; filename="${safeFilename(sessionId)}.zip"`,
55
+ });
56
+ res.end(Buffer.from(zipFile));
103
57
  });
104
58
  }