@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.
- package/README.md +18 -3
- package/dist/artifact.d.mts +118 -2
- package/dist/artifact.mjs +5 -3
- package/dist/{log-TYgd8Xkr.d.mts → backend-BKtJ5sO5.d.mts} +183 -284
- package/dist/backend-rdb-BDCntVDy.mjs +1341 -0
- package/dist/branch-CG1PUlO6.mjs +833 -0
- package/dist/deletion-SSX7IqU8.mjs +35 -0
- package/dist/deletion.d.mts +1 -1
- package/dist/deletion.mjs +2 -2
- package/dist/export-CfJQjQfr.mjs +123 -0
- package/dist/export.d.mts +1 -1
- package/dist/export.mjs +31 -55
- package/dist/import.d.mts +1 -1
- package/dist/import.mjs +31 -76
- package/dist/index-CUD2ZpTA.d.mts +71 -0
- package/dist/index.d.mts +20 -2
- package/dist/index.mjs +1561 -4
- package/dist/open-YoyD_kah.mjs +561 -0
- package/dist/organize.d.mts +9 -0
- package/dist/organize.mjs +30 -0
- package/dist/route-DpfY0zq-.mjs +114 -0
- package/dist/storage.d.mts +41 -48
- package/dist/storage.mjs +3 -1
- package/dist/testing.d.mts +9 -1
- package/dist/testing.mjs +25 -4
- package/dist/usage-row-BQQM-_t6.mjs +36 -0
- package/dist/usage.d.mts +1 -1
- package/dist/usage.mjs +7 -40
- package/dist/write-guard-CYrY58GM.mjs +174 -0
- package/package.json +32 -36
- package/src/artifact.ts +4 -1
- package/src/backend-rdb.ts +331 -0
- package/src/backend.ts +32 -15
- package/src/{branch.ts → branch/index.ts} +109 -110
- package/src/branch/port.ts +62 -0
- package/src/branch/semantics.ts +69 -0
- package/src/db/open.ts +180 -0
- package/src/db/stats.ts +449 -0
- package/src/deletion-error.ts +17 -0
- package/src/deletion.ts +19 -72
- package/src/entities/index.ts +16 -1
- package/src/entities/v3/event-usage.ts +3 -3
- package/src/entities/v3/events.ts +3 -3
- package/src/entities/v3/index.ts +4 -16
- package/src/entities/v3/persistence-state.ts +3 -3
- package/src/entities/v3/schema-meta.ts +3 -3
- package/src/entities/v3/session-counts.ts +3 -3
- package/src/entities/v3/session-events.ts +3 -3
- package/src/entities/v3/session-projcache-rows.ts +3 -3
- package/src/entities/v3/session-usage.ts +3 -3
- package/src/entities/v3/sessions.ts +3 -3
- package/src/entities/v3/storage-records.ts +17 -0
- package/src/entities/v3/storage-units.ts +3 -3
- package/src/{schema.ts → event-shape.ts} +0 -46
- package/src/export.ts +32 -78
- package/src/handles.ts +349 -0
- package/src/http/route.ts +178 -0
- package/src/import-storages.ts +5 -2
- package/src/import.ts +63 -125
- package/src/index.ts +15 -1666
- package/src/legacy.ts +3 -1
- package/src/live-routing.ts +205 -0
- package/src/log/export.ts +84 -0
- package/src/{log.ts → log/repair.ts} +1 -268
- package/src/log/rows.ts +107 -0
- package/src/log/usage-row.ts +64 -0
- package/src/migrations.ts +196 -0
- package/src/organize.ts +38 -0
- package/src/read-path.ts +190 -0
- package/src/routes.ts +2 -1
- package/src/rows.ts +25 -77
- package/src/session-ops.ts +444 -0
- package/src/session-store.ts +675 -0
- package/src/stats-fold.ts +44 -0
- package/src/storage-takeover/index.ts +2 -5
- package/src/storage-takeover/legacy-domain-migration.ts +118 -0
- package/src/storage-takeover/projection-cache.ts +122 -71
- package/src/storage-takeover/read-model.ts +189 -0
- package/src/storage-takeover/repository.ts +236 -442
- package/src/storage-takeover/storage-backend.ts +44 -159
- package/src/storage-takeover/types.ts +45 -19
- package/src/storage-takeover/workspace-documents.ts +65 -0
- package/src/storage.ts +4 -2
- package/src/testing.ts +21 -1
- package/src/usage.ts +11 -65
- package/src/version.ts +13 -0
- package/src/write-path.ts +286 -0
- package/dist/branch-CoPCRKer.mjs +0 -401
- package/dist/deletion-CWl89TIR.mjs +0 -2249
- package/dist/gc.d.mts +0 -4
- package/dist/gc.mjs +0 -48
- package/dist/log-CcWy46VE.mjs +0 -558
- package/dist/routes-hZjTcX_R.mjs +0 -9
- package/dist/sqlite-BNRd1aqR.mjs +0 -1778
- package/drizzle/postgres/20260908072805_v2_initial/migration.sql +0 -58
- package/drizzle/postgres/20260908072805_v2_initial/snapshot.json +0 -686
- package/drizzle/postgres/20260908072806_v3_drop_original_seq/migration.sql +0 -1
- package/drizzle/postgres/20260908072806_v3_drop_original_seq/snapshot.json +0 -673
- package/drizzle/postgres/20260910120001_v3_storage_tables/migration.sql +0 -65
- package/drizzle/postgres/20260910120001_v3_storage_tables/snapshot.json +0 -1183
- package/drizzle/postgres/20260910130001_v3_session_title_backfill/migration.sql +0 -10
- package/drizzle/postgres/20260910130001_v3_session_title_backfill/snapshot.json +0 -1183
- package/drizzle/postgres/20260918120000_v3_event_usage/migration.sql +0 -14
- package/drizzle/postgres/20260918120000_v3_event_usage/snapshot.json +0 -1309
- package/drizzle/postgres/20260921075900_v3_agent_preset/migration.sql +0 -1
- package/drizzle/postgres/20260922090001_v3_pinned_seq/migration.sql +0 -2
- package/drizzle/postgres/20260922093001_v3_last_event_at/migration.sql +0 -10
- package/drizzle/postgres/20260923120000_v3_usage_materialized/migration.sql +0 -48
- package/drizzle/postgres/20261008103001_v3_schedule_tasks/migration.sql +0 -11
- package/drizzle/sqlite/20260908072751_v2_initial/migration.sql +0 -53
- package/drizzle/sqlite/20260908072751_v2_initial/snapshot.json +0 -492
- package/drizzle/sqlite/20260908072752_v3_drop_original_seq/migration.sql +0 -6
- package/drizzle/sqlite/20260908072752_v3_drop_original_seq/snapshot.json +0 -513
- package/drizzle/sqlite/20260910120000_v3_storage_tables/migration.sql +0 -66
- package/drizzle/sqlite/20260910120000_v3_storage_tables/snapshot.json +0 -905
- package/drizzle/sqlite/20260910130000_v3_session_title_backfill/migration.sql +0 -13
- package/drizzle/sqlite/20260910130000_v3_session_title_backfill/snapshot.json +0 -905
- package/drizzle/sqlite/20260918120000_v3_event_usage/migration.sql +0 -14
- package/drizzle/sqlite/20260918120000_v3_event_usage/snapshot.json +0 -1031
- package/drizzle/sqlite/20260921075855_v3_agent_preset/migration.sql +0 -7
- package/drizzle/sqlite/20260921075855_v3_agent_preset/snapshot.json +0 -1041
- package/drizzle/sqlite/20260922090000_v3_pinned_seq/migration.sql +0 -4
- package/drizzle/sqlite/20260922093000_v3_last_event_at/migration.sql +0 -13
- package/drizzle/sqlite/20260923120000_v3_usage_materialized/migration.sql +0 -48
- package/drizzle/sqlite/20261008103000_v3_schedule_tasks/migration.sql +0 -14
- package/src/adapters/index.ts +0 -12
- package/src/adapters/to-postgres.ts +0 -93
- package/src/adapters/to-sqlite.ts +0 -83
- package/src/adapters/types.ts +0 -44
- package/src/drizzle/postgres-v2.ts +0 -10
- package/src/drizzle/postgres-v3.ts +0 -18
- package/src/drizzle/sqlite-v2.ts +0 -9
- package/src/drizzle/sqlite-v3.ts +0 -18
- package/src/entities/v2/index.ts +0 -20
- package/src/entities/v2/session-events.ts +0 -10
- package/src/entities/v3/schedule-tasks.ts +0 -16
- package/src/entities/v3/workspace-sessions.ts +0 -19
- package/src/entities/v3/workspace-state.ts +0 -12
- package/src/entities/v3/workspaces.ts +0 -14
- package/src/gc.ts +0 -77
- package/src/postgres.ts +0 -1015
- package/src/sqlite.ts +0 -1096
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
|
|
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
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
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
|
}
|
package/src/entities/index.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
|
1
|
+
import { defineTable } from "@morlay/rdbkit";
|
|
2
2
|
|
|
3
3
|
// 用量日志:一条 `assistant/message` 事件一行(按事件行唯一,fork 共享行不重复);读侧维度全部物化在行上
|
|
4
4
|
// (本地日、是否被会话引用、是否被子代理会话引用),统计因此不做 `EXISTS` 判定、也不回连事件表。
|
|
5
5
|
// 取舍见 ADR-统计衍生表物化归属与汇总。
|
|
6
|
-
export const eventUsage
|
|
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
|
|
1
|
+
import { defineTable } from "@morlay/rdbkit";
|
|
2
2
|
|
|
3
|
-
export const events
|
|
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
|
+
});
|
package/src/entities/v3/index.ts
CHANGED
|
@@ -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 {
|
|
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 {
|
|
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
|
-
|
|
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
|
-
|
|
56
|
-
workspaceSessions,
|
|
57
|
-
workspaceState,
|
|
58
|
-
scheduleTasks,
|
|
46
|
+
storageRecords,
|
|
59
47
|
sessionProjcacheRows,
|
|
60
48
|
eventUsage,
|
|
61
49
|
sessionUsage,
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { defineTable } from "@morlay/rdbkit";
|
|
2
2
|
|
|
3
|
-
export const persistenceState
|
|
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
|
|
1
|
+
import { defineTable } from "@morlay/rdbkit";
|
|
2
2
|
|
|
3
|
-
export const schemaMeta
|
|
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
|
|
1
|
+
import { defineTable } from "@morlay/rdbkit";
|
|
2
2
|
|
|
3
3
|
// 会话 × 本地日的活动计数(派生统计表):轮次 / 步骤 / 用户输入 / 工具调用四列直接读,
|
|
4
4
|
// 不再存事件类型、也不在读取时折。旁路累加、可按会话重建,读侧只读;
|
|
5
5
|
// 取舍见 ADR-统计衍生表物化归属与汇总。
|
|
6
|
-
export const sessionCounts
|
|
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
|
|
1
|
+
import { defineTable } from "@morlay/rdbkit";
|
|
2
2
|
|
|
3
|
-
export const sessionEvents
|
|
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
|
|
1
|
+
import { defineTable } from "@morlay/rdbkit";
|
|
2
2
|
|
|
3
|
-
export const sessionProjcacheRows
|
|
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
|
|
1
|
+
import { defineTable } from "@morlay/rdbkit";
|
|
2
2
|
|
|
3
3
|
// 会话 × 本地日 × 模型的 token 汇总(派生统计表):**按会话的行**读它,因此保住
|
|
4
4
|
// 「fork 子会话含继承前缀」的口径(各会话行之和 ≥ 总量)而不回连事件表。
|
|
5
5
|
// 旁路累加、可按会话重建,读侧只读;取舍见 ADR-统计衍生表物化归属与汇总。
|
|
6
|
-
export const sessionUsage
|
|
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
|
|
1
|
+
import { defineTable } from "@morlay/rdbkit";
|
|
2
2
|
|
|
3
|
-
export const sessions
|
|
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
|
|
1
|
+
import { defineTable } from "@morlay/rdbkit";
|
|
2
2
|
|
|
3
|
-
export const storageUnits
|
|
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 "./
|
|
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
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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
|
}
|