@morlay/session-rdb 0.0.10 → 0.0.12
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 +0 -16
- package/dist/index.d.mts +203 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +2030 -0
- package/dist/index.mjs.map +1 -0
- package/dist/invariant.d.mts +8 -0
- package/dist/invariant.d.mts.map +1 -0
- package/dist/invariant.mjs +10 -0
- package/dist/invariant.mjs.map +1 -0
- package/package.json +22 -21
- package/src/adapters/ddl.ts +77 -0
- package/src/adapters/index.ts +4 -0
- package/src/adapters/to-postgres.ts +91 -0
- package/src/adapters/to-sqlite.ts +79 -0
- package/src/backend.ts +112 -0
- package/src/branch.ts +508 -0
- package/src/entities/events.ts +27 -0
- package/src/entities/index.ts +30 -0
- package/src/entities/persistence-state.ts +10 -0
- package/src/entities/schema-meta.ts +9 -0
- package/src/entities/session-events.ts +29 -0
- package/src/entities/sessions.ts +20 -0
- package/src/entities/types.ts +48 -0
- package/src/import.ts +270 -0
- package/src/index.ts +543 -0
- package/src/invariant.ts +15 -0
- package/src/log.ts +370 -0
- package/src/migrate.ts +137 -0
- package/src/postgres.ts +369 -0
- package/src/schema.ts +234 -0
- package/src/sqlite.ts +412 -0
- package/src/write-guard.ts +27 -0
- package/lib/index.d.mts +0 -558
- package/lib/index.d.mts.map +0 -1
- package/lib/index.mjs +0 -2175
- package/lib/index.mjs.map +0 -1
- package/lib/invariant.d.mts +0 -15
- package/lib/invariant.d.mts.map +0 -1
- package/lib/invariant.mjs +0 -21
- package/lib/invariant.mjs.map +0 -1
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { sql } from "drizzle-orm";
|
|
2
|
+
import {
|
|
3
|
+
bigint,
|
|
4
|
+
check as pgCheck,
|
|
5
|
+
index,
|
|
6
|
+
integer,
|
|
7
|
+
pgSchema,
|
|
8
|
+
pgTable,
|
|
9
|
+
serial,
|
|
10
|
+
text,
|
|
11
|
+
unique,
|
|
12
|
+
type AnyPgColumn,
|
|
13
|
+
type AnyPgColumnBuilder,
|
|
14
|
+
type AnyPgTable,
|
|
15
|
+
} from "drizzle-orm/pg-core";
|
|
16
|
+
import { toProperty, type ColumnDef, type TableDef } from "../entities/types.ts";
|
|
17
|
+
|
|
18
|
+
type TableRegistry = Record<string, AnyPgTable>;
|
|
19
|
+
|
|
20
|
+
function buildColumn(c: ColumnDef, tables: TableRegistry): AnyPgColumnBuilder {
|
|
21
|
+
// 具体 builder 类型与 AnyPgColumnBuilder 在方法层面不兼容,构建阶段用宽松类型。
|
|
22
|
+
let col: any;
|
|
23
|
+
switch (c.type) {
|
|
24
|
+
case "text":
|
|
25
|
+
col = text(c.name);
|
|
26
|
+
break;
|
|
27
|
+
case "serial":
|
|
28
|
+
col = serial(c.name).primaryKey();
|
|
29
|
+
break;
|
|
30
|
+
case "integer": {
|
|
31
|
+
const built = integer(c.name);
|
|
32
|
+
col = c.primaryKey ? built.primaryKey() : built;
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
case "bigint": {
|
|
36
|
+
const built = bigint(c.name, { mode: "number" });
|
|
37
|
+
col = c.primaryKey ? built.primaryKey() : built;
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (c.notNull) col = col.notNull();
|
|
42
|
+
if (c.default !== undefined) col = col.default(c.default);
|
|
43
|
+
if (c.unique) col = col.unique();
|
|
44
|
+
if (c.references) {
|
|
45
|
+
const { table, column, onDelete } = c.references;
|
|
46
|
+
col = col.references(
|
|
47
|
+
() => (tables[table] as unknown as Record<string, AnyPgColumn>)[toProperty(column)],
|
|
48
|
+
{ onDelete },
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
return col;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function toPostgresSchema(
|
|
55
|
+
defs: readonly TableDef[],
|
|
56
|
+
schemaName = "public",
|
|
57
|
+
): Record<string, AnyPgTable> {
|
|
58
|
+
const tables: TableRegistry = {};
|
|
59
|
+
// `pgSchema(name).table` 使表对象携带 schema 限定(查询/DDL 显式引用,
|
|
60
|
+
// 不依赖 search_path);public 与无 schema 行为一致。
|
|
61
|
+
const table = schemaName === "public" ? pgTable : pgSchema(schemaName).table;
|
|
62
|
+
for (const def of defs) {
|
|
63
|
+
const columns: Record<string, AnyPgColumnBuilder> = {};
|
|
64
|
+
for (const c of def.columns) columns[toProperty(c.name)] = buildColumn(c, tables);
|
|
65
|
+
const extra = (self: Record<string, unknown>) => [
|
|
66
|
+
...(def.checks ?? []).map((c) => pgCheck(c.name, sql.raw(c.expression))),
|
|
67
|
+
...(def.uniques ?? []).map((u) =>
|
|
68
|
+
unique(u.name).on(
|
|
69
|
+
...(u.columns.map((name) => self[toProperty(name)] as AnyPgColumn) as [
|
|
70
|
+
AnyPgColumn,
|
|
71
|
+
...AnyPgColumn[],
|
|
72
|
+
]),
|
|
73
|
+
),
|
|
74
|
+
),
|
|
75
|
+
...(def.indexes ?? []).map((i) =>
|
|
76
|
+
index(i.name).on(
|
|
77
|
+
...(i.columns.map((name) => self[toProperty(name)] as AnyPgColumn) as [
|
|
78
|
+
AnyPgColumn,
|
|
79
|
+
...AnyPgColumn[],
|
|
80
|
+
]),
|
|
81
|
+
),
|
|
82
|
+
),
|
|
83
|
+
];
|
|
84
|
+
tables[def.name] = (table as typeof pgTable)(
|
|
85
|
+
def.name,
|
|
86
|
+
columns as Record<string, AnyPgColumnBuilder>,
|
|
87
|
+
extra as never,
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
return tables;
|
|
91
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { sql } from "drizzle-orm";
|
|
2
|
+
import {
|
|
3
|
+
check as sqliteCheck,
|
|
4
|
+
index,
|
|
5
|
+
integer,
|
|
6
|
+
sqliteTable,
|
|
7
|
+
text,
|
|
8
|
+
unique,
|
|
9
|
+
type AnySQLiteColumn,
|
|
10
|
+
type AnySQLiteTable,
|
|
11
|
+
type SQLiteColumnBuilder,
|
|
12
|
+
} from "drizzle-orm/sqlite-core";
|
|
13
|
+
import { toProperty, type ColumnDef, type TableDef } from "../entities/types.ts";
|
|
14
|
+
|
|
15
|
+
type TableRegistry = Record<string, AnySQLiteTable>;
|
|
16
|
+
|
|
17
|
+
function buildColumn(c: ColumnDef, tables: TableRegistry): SQLiteColumnBuilder {
|
|
18
|
+
// 具体 builder 类型与基类在方法层面不兼容(泛型逆变),构建阶段用宽松
|
|
19
|
+
// 类型合并,返回时收窄为基类;查询类型安全由手写行接口兜底。
|
|
20
|
+
let col: any;
|
|
21
|
+
switch (c.type) {
|
|
22
|
+
case "text":
|
|
23
|
+
col = text(c.name);
|
|
24
|
+
break;
|
|
25
|
+
case "serial":
|
|
26
|
+
col = integer(c.name).primaryKey({ autoIncrement: true });
|
|
27
|
+
break;
|
|
28
|
+
case "integer":
|
|
29
|
+
case "bigint": {
|
|
30
|
+
const built = integer(c.name);
|
|
31
|
+
col = c.primaryKey ? built.primaryKey() : built;
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (c.notNull) col = col.notNull();
|
|
36
|
+
if (c.default !== undefined) col = col.default(c.default);
|
|
37
|
+
if (c.unique) col = col.unique();
|
|
38
|
+
if (c.references) {
|
|
39
|
+
const { table, column, onDelete } = c.references;
|
|
40
|
+
col = col.references(
|
|
41
|
+
() => (tables[table] as unknown as Record<string, AnySQLiteColumn>)[toProperty(column)],
|
|
42
|
+
{ onDelete },
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
return col as SQLiteColumnBuilder;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function toSqliteSchema(defs: readonly TableDef[]): Record<string, AnySQLiteTable> {
|
|
49
|
+
const tables: TableRegistry = {};
|
|
50
|
+
for (const def of defs) {
|
|
51
|
+
const columns: Record<string, SQLiteColumnBuilder> = {};
|
|
52
|
+
for (const c of def.columns) columns[toProperty(c.name)] = buildColumn(c, tables);
|
|
53
|
+
const extra = (self: Record<string, unknown>) => [
|
|
54
|
+
...(def.checks ?? []).map((c) => sqliteCheck(c.name, sql.raw(c.expression))),
|
|
55
|
+
...(def.uniques ?? []).map((u) =>
|
|
56
|
+
unique(u.name).on(
|
|
57
|
+
...(u.columns.map((name) => self[toProperty(name)] as AnySQLiteColumn) as [
|
|
58
|
+
AnySQLiteColumn,
|
|
59
|
+
...AnySQLiteColumn[],
|
|
60
|
+
]),
|
|
61
|
+
),
|
|
62
|
+
),
|
|
63
|
+
...(def.indexes ?? []).map((i) =>
|
|
64
|
+
index(i.name).on(
|
|
65
|
+
...(i.columns.map((name) => self[toProperty(name)] as AnySQLiteColumn) as [
|
|
66
|
+
AnySQLiteColumn,
|
|
67
|
+
...AnySQLiteColumn[],
|
|
68
|
+
]),
|
|
69
|
+
),
|
|
70
|
+
),
|
|
71
|
+
];
|
|
72
|
+
tables[def.name] = sqliteTable(
|
|
73
|
+
def.name,
|
|
74
|
+
columns as Record<string, SQLiteColumnBuilder>,
|
|
75
|
+
extra as never,
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
return tables;
|
|
79
|
+
}
|
package/src/backend.ts
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import type { SessionId } from "@deepseek-ai/dsh-session";
|
|
2
|
+
import type { SessionStorageMetadata } from "@deepseek-ai/dsh-session-persistence";
|
|
3
|
+
|
|
4
|
+
export interface SessionRow {
|
|
5
|
+
fSessionId: string;
|
|
6
|
+
|
|
7
|
+
fHeadEventId: string;
|
|
8
|
+
fHeadSequence: number;
|
|
9
|
+
fVersion: number;
|
|
10
|
+
fCreatedAt: number;
|
|
11
|
+
fCwd: string | null;
|
|
12
|
+
fParentSession: string | null;
|
|
13
|
+
fSeedLength: number | null;
|
|
14
|
+
fOrigin: string | null;
|
|
15
|
+
fDelegationDepth: number | null;
|
|
16
|
+
|
|
17
|
+
fIncarnation: string;
|
|
18
|
+
|
|
19
|
+
fRevision: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface EventInsert {
|
|
23
|
+
fEventId: string;
|
|
24
|
+
fParentId: string;
|
|
25
|
+
fType: string;
|
|
26
|
+
fKind: string;
|
|
27
|
+
fRole: string;
|
|
28
|
+
fName: string;
|
|
29
|
+
fActionId: string;
|
|
30
|
+
fEncoding: string;
|
|
31
|
+
fData: string;
|
|
32
|
+
fCreatedAt: number;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface EventRow {
|
|
36
|
+
fEventId: string;
|
|
37
|
+
|
|
38
|
+
fSequence: number;
|
|
39
|
+
|
|
40
|
+
fOriginalSeq: number;
|
|
41
|
+
|
|
42
|
+
fType: string;
|
|
43
|
+
|
|
44
|
+
fKind: string;
|
|
45
|
+
|
|
46
|
+
fRole: string;
|
|
47
|
+
|
|
48
|
+
fName: string;
|
|
49
|
+
|
|
50
|
+
fActionId: string;
|
|
51
|
+
|
|
52
|
+
fCreatedAt: number;
|
|
53
|
+
|
|
54
|
+
fData: string;
|
|
55
|
+
|
|
56
|
+
fSurfaceOp: string | null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface BackendTx {
|
|
60
|
+
upsertSession(storage: SessionStorageMetadata, incarnation: string): Promise<void>;
|
|
61
|
+
|
|
62
|
+
getHead(id: SessionId): Promise<Pick<SessionRow, "fHeadEventId" | "fHeadSequence">>;
|
|
63
|
+
|
|
64
|
+
getSeedLength(id: SessionId): Promise<number | null>;
|
|
65
|
+
|
|
66
|
+
updateSeedLength(id: SessionId, seedLength: number): Promise<void>;
|
|
67
|
+
|
|
68
|
+
insertEvents(events: EventInsert[]): Promise<void>;
|
|
69
|
+
|
|
70
|
+
insertBridges(
|
|
71
|
+
rows: Array<{
|
|
72
|
+
fSessionId: SessionId;
|
|
73
|
+
fEventId: string;
|
|
74
|
+
fSequence: number;
|
|
75
|
+
fOriginalSeq: number;
|
|
76
|
+
fSurfaceOp: string | null;
|
|
77
|
+
}>,
|
|
78
|
+
): Promise<void>;
|
|
79
|
+
|
|
80
|
+
updateHead(id: SessionId, headEventId: string, headSequence: number): Promise<void>;
|
|
81
|
+
|
|
82
|
+
bumpRevision(id: SessionId): Promise<void>;
|
|
83
|
+
|
|
84
|
+
deleteBridgeTail(id: SessionId, fromSequence: number): Promise<void>;
|
|
85
|
+
|
|
86
|
+
getPrevBridge(
|
|
87
|
+
id: SessionId,
|
|
88
|
+
sequence: number,
|
|
89
|
+
): Promise<{ fEventId: string; fSequence: number } | undefined>;
|
|
90
|
+
|
|
91
|
+
getLastBridge(id: SessionId): Promise<{ fEventId: string; fSequence: number } | undefined>;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export interface Backend {
|
|
95
|
+
readonly kind: "sqlite" | "postgres";
|
|
96
|
+
|
|
97
|
+
readonly storeIdentity: string;
|
|
98
|
+
|
|
99
|
+
open(): Promise<void>;
|
|
100
|
+
|
|
101
|
+
getSession(id: SessionId): Promise<SessionRow | undefined>;
|
|
102
|
+
|
|
103
|
+
getSeqMapRows(id: SessionId): Promise<Array<{ fSequence: number; fOriginalSeq: number }>>;
|
|
104
|
+
|
|
105
|
+
getEventRows(id: SessionId, fromSequence?: number): Promise<EventRow[]>;
|
|
106
|
+
|
|
107
|
+
listSessions(): Promise<SessionRow[]>;
|
|
108
|
+
|
|
109
|
+
transaction<T>(fn: (tx: BackendTx) => Promise<T>): Promise<T>;
|
|
110
|
+
|
|
111
|
+
close(): Promise<void>;
|
|
112
|
+
}
|