@morlay/session-rdb 0.0.15 → 0.0.16-alpha.0

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 (65) hide show
  1. package/README.md +11 -13
  2. package/dist/artifact.d.mts +6 -16
  3. package/dist/artifact.mjs +3 -3
  4. package/dist/{import-DFed8DBt.mjs → import-CKrzjXVB.mjs} +73 -83
  5. package/dist/import.d.mts +2 -3
  6. package/dist/import.mjs +2 -2
  7. package/dist/index-CgGDHQSK.d.mts +225 -0
  8. package/dist/index.d.mts +3 -3
  9. package/dist/index.mjs +694 -169
  10. package/dist/log-DTJsxMud.mjs +314 -0
  11. package/dist/{schema-CFXZURX7.d.mts → schema-COK7-wRV.d.mts} +3 -15
  12. package/dist/sqlite-DCy4VTD8.mjs +698 -0
  13. package/dist/storage.d.mts +2 -7
  14. package/dist/storage.mjs +2 -3
  15. package/dist/testing.d.mts +30 -1
  16. package/dist/testing.mjs +676 -1991
  17. package/drizzle/postgres/20260908072805_v2_initial/migration.sql +58 -0
  18. package/drizzle/postgres/20260908072805_v2_initial/snapshot.json +686 -0
  19. package/drizzle/postgres/20260908072806_v3_drop_original_seq/migration.sql +1 -0
  20. package/drizzle/postgres/20260908072806_v3_drop_original_seq/snapshot.json +673 -0
  21. package/drizzle/sqlite/20260908072751_v2_initial/migration.sql +53 -0
  22. package/drizzle/sqlite/20260908072751_v2_initial/snapshot.json +492 -0
  23. package/drizzle/sqlite/20260908072752_v3_drop_original_seq/migration.sql +6 -0
  24. package/drizzle/sqlite/20260908072752_v3_drop_original_seq/snapshot.json +513 -0
  25. package/package.json +17 -12
  26. package/src/adapters/index.ts +10 -2
  27. package/src/adapters/to-postgres.ts +19 -15
  28. package/src/adapters/to-sqlite.ts +20 -14
  29. package/src/{entities → adapters}/types.ts +7 -8
  30. package/src/backend.ts +0 -7
  31. package/src/branch.ts +29 -110
  32. package/src/drizzle/postgres-v2.ts +11 -0
  33. package/src/drizzle/postgres-v3.ts +11 -0
  34. package/src/drizzle/sqlite-v2.ts +10 -0
  35. package/src/drizzle/sqlite-v3.ts +11 -0
  36. package/src/entities/index.ts +2 -30
  37. package/src/entities/v2/index.ts +20 -0
  38. package/src/entities/v2/session-events.ts +11 -0
  39. package/src/entities/v3/events.ts +27 -0
  40. package/src/entities/v3/index.ts +27 -0
  41. package/src/entities/v3/persistence-state.ts +10 -0
  42. package/src/entities/v3/schema-meta.ts +9 -0
  43. package/src/entities/v3/session-events.ts +26 -0
  44. package/src/entities/v3/sessions.ts +20 -0
  45. package/src/import.ts +65 -57
  46. package/src/index.ts +868 -223
  47. package/src/invariant.ts +0 -2
  48. package/src/legacy.ts +67 -0
  49. package/src/log.ts +41 -87
  50. package/src/postgres.ts +75 -93
  51. package/src/schema.ts +3 -14
  52. package/src/sqlite.ts +59 -46
  53. package/src/testing/contract.ts +460 -375
  54. package/src/testing/coordinator-contract.ts +108 -1374
  55. package/src/testing.ts +1 -6
  56. package/dist/index-uUvn6gYp.d.mts +0 -111
  57. package/dist/schema-vwzwEXNE.mjs +0 -878
  58. package/dist/sqlite-CG_Qcx5C.mjs +0 -356
  59. package/src/adapters/ddl.ts +0 -77
  60. package/src/entities/events.ts +0 -27
  61. package/src/entities/persistence-state.ts +0 -10
  62. package/src/entities/schema-meta.ts +0 -9
  63. package/src/entities/session-events.ts +0 -29
  64. package/src/entities/sessions.ts +0 -20
  65. package/src/migrate.ts +0 -137
@@ -10,24 +10,26 @@ import {
10
10
  type AnySQLiteTable,
11
11
  type SQLiteColumnBuilder,
12
12
  } from "drizzle-orm/sqlite-core";
13
- import { toProperty, type ColumnDef, type TableDef } from "../entities/types.ts";
13
+ import { toProperty, type ColumnDef, type TableDef } from "./types.ts";
14
14
 
15
15
  type TableRegistry = Record<string, AnySQLiteTable>;
16
16
 
17
- function buildColumn(c: ColumnDef, tables: TableRegistry): SQLiteColumnBuilder {
17
+ function buildColumn(name: string, c: ColumnDef, tables: TableRegistry): SQLiteColumnBuilder {
18
18
  // 具体 builder 类型与基类在方法层面不兼容(泛型逆变),构建阶段用宽松
19
19
  // 类型合并,返回时收窄为基类;查询类型安全由手写行接口兜底。
20
20
  let col: any;
21
21
  switch (c.type) {
22
- case "text":
23
- col = text(c.name);
22
+ case "text": {
23
+ const built = text(name);
24
+ col = c.primaryKey ? built.primaryKey() : built;
24
25
  break;
26
+ }
25
27
  case "serial":
26
- col = integer(c.name).primaryKey({ autoIncrement: true });
28
+ col = integer(name).primaryKey({ autoIncrement: true });
27
29
  break;
28
30
  case "integer":
29
31
  case "bigint": {
30
- const built = integer(c.name);
32
+ const built = integer(name);
31
33
  col = c.primaryKey ? built.primaryKey() : built;
32
34
  break;
33
35
  }
@@ -49,20 +51,24 @@ export function toSqliteSchema(defs: readonly TableDef[]): Record<string, AnySQL
49
51
  const tables: TableRegistry = {};
50
52
  for (const def of defs) {
51
53
  const columns: Record<string, SQLiteColumnBuilder> = {};
52
- for (const c of def.columns) columns[toProperty(c.name)] = buildColumn(c, tables);
54
+ for (const [name, c] of Object.entries(def.columns)) {
55
+ columns[toProperty(name)] = buildColumn(name, c, tables);
56
+ }
53
57
  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
+ ...Object.entries(def.checks ?? {}).map(([name, c]) =>
59
+ sqliteCheck(name, sql.raw(c.expression)),
60
+ ),
61
+ ...Object.entries(def.uniques ?? {}).map(([name, u]) =>
62
+ unique(name).on(
63
+ ...(u.columns.map((n) => self[toProperty(n)] as AnySQLiteColumn) as [
58
64
  AnySQLiteColumn,
59
65
  ...AnySQLiteColumn[],
60
66
  ]),
61
67
  ),
62
68
  ),
63
- ...(def.indexes ?? []).map((i) =>
64
- index(i.name).on(
65
- ...(i.columns.map((name) => self[toProperty(name)] as AnySQLiteColumn) as [
69
+ ...Object.entries(def.indexes ?? {}).map(([name, i]) =>
70
+ index(name).on(
71
+ ...(i.columns.map((n) => self[toProperty(n)] as AnySQLiteColumn) as [
66
72
  AnySQLiteColumn,
67
73
  ...AnySQLiteColumn[],
68
74
  ]),
@@ -1,9 +1,10 @@
1
+ /** drizzle util 层:方言无关的表结构描述(entities 与 adapters 共用)。 */
2
+
1
3
  export type ColumnTypeName = "serial" | "integer" | "bigint" | "text";
2
4
 
3
5
  export type DeleteAction = "cascade" | "set null" | "restrict" | "no action";
4
6
 
5
7
  export interface ColumnDef {
6
- name: string;
7
8
  type: ColumnTypeName;
8
9
  notNull?: boolean;
9
10
 
@@ -21,26 +22,24 @@ export interface ColumnDef {
21
22
  }
22
23
 
23
24
  export interface CheckDef {
24
- name: string;
25
25
  expression: string;
26
26
  }
27
27
 
28
28
  export interface UniqueDef {
29
- name?: string;
30
29
  columns: string[];
31
30
  }
32
31
 
33
32
  export interface IndexDef {
34
- name: string;
35
33
  columns: string[];
36
34
  }
37
35
 
36
+ /** 表结构描述:columns / checks / uniques / indexes 以 Record 键为名,天然唯一。 */
38
37
  export interface TableDef {
39
38
  name: string;
40
- columns: ColumnDef[];
41
- checks?: CheckDef[];
42
- uniques?: UniqueDef[];
43
- indexes?: IndexDef[];
39
+ columns: Record<string, ColumnDef>;
40
+ checks?: Record<string, CheckDef>;
41
+ uniques?: Record<string, UniqueDef>;
42
+ indexes?: Record<string, IndexDef>;
44
43
  }
45
44
 
46
45
  export function toProperty(name: string): string {
package/src/backend.ts CHANGED
@@ -37,8 +37,6 @@ export interface EventRow {
37
37
 
38
38
  fSequence: number;
39
39
 
40
- fOriginalSeq: number;
41
-
42
40
  fType: string;
43
41
 
44
42
  fKind: string;
@@ -72,7 +70,6 @@ export interface BackendTx {
72
70
  fSessionId: SessionId;
73
71
  fEventId: string;
74
72
  fSequence: number;
75
- fOriginalSeq: number;
76
73
  fSurfaceOp: string | null;
77
74
  }>,
78
75
  ): Promise<void>;
@@ -87,8 +84,6 @@ export interface BackendTx {
87
84
  id: SessionId,
88
85
  sequence: number,
89
86
  ): Promise<{ fEventId: string; fSequence: number } | undefined>;
90
-
91
- getLastBridge(id: SessionId): Promise<{ fEventId: string; fSequence: number } | undefined>;
92
87
  }
93
88
 
94
89
  export interface Backend {
@@ -100,8 +95,6 @@ export interface Backend {
100
95
 
101
96
  getSession(id: SessionId): Promise<SessionRow | undefined>;
102
97
 
103
- getSeqMapRows(id: SessionId): Promise<Array<{ fSequence: number; fOriginalSeq: number }>>;
104
-
105
98
  getEventRows(id: SessionId, fromSequence?: number): Promise<EventRow[]>;
106
99
 
107
100
  listSessions(): Promise<SessionRow[]>;
package/src/branch.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  SESSION_FORMAT_VERSION,
3
+ SessionLogOffset,
3
4
  type Session,
4
5
  type SessionEvent,
5
6
  type SessionHeader,
@@ -19,7 +20,6 @@ import {
19
20
  import { randomUUID } from "node:crypto";
20
21
  import type { SessionPersistenceRdb } from "./index.ts";
21
22
  import { rowToMeta } from "./log.ts";
22
- import { isPersistedEvent } from "./schema.ts";
23
23
 
24
24
  export function locateTurnEnd(
25
25
  events: readonly SessionEvent[],
@@ -66,12 +66,6 @@ export interface LiveSessionHooks {
66
66
  getAgent(id: SessionId): LiveAgentLike | undefined;
67
67
 
68
68
  flush(session: Session): Promise<boolean>;
69
-
70
- setCoordinatorCursor(id: SessionId, cursor: number): void;
71
-
72
- setCoordinatorState(id: SessionId, cursor: number, meta: SessionHeader): void;
73
-
74
- setCoordinatorSeedLength(id: SessionId, seedLength: number): void;
75
69
  }
76
70
 
77
71
  export interface LiveAgentLike {
@@ -155,9 +149,6 @@ export class SessionBranchRdbProvider implements SessionBranchProvider {
155
149
  getSession: () => undefined,
156
150
  getAgent: () => undefined,
157
151
  flush: async () => true,
158
- setCoordinatorCursor: () => {},
159
- setCoordinatorState: () => {},
160
- setCoordinatorSeedLength: () => {},
161
152
  },
162
153
  ) {}
163
154
 
@@ -176,7 +167,7 @@ export class SessionBranchRdbProvider implements SessionBranchProvider {
176
167
  id: SessionId,
177
168
  signal?: AbortSignal,
178
169
  ): Promise<{ meta: SessionHeader; events: readonly SessionEvent[] }> {
179
- const stored = await this.persistence.loadStored(id, signal);
170
+ const stored = await this.persistence.readLog(id, {}, signal);
180
171
  if (stored === undefined)
181
172
  throw new SessionBranchError(`session "${id}" not found`, "SESSION_NOT_FOUND");
182
173
  return { meta: stored.meta, events: stored.events };
@@ -189,7 +180,9 @@ export class SessionBranchRdbProvider implements SessionBranchProvider {
189
180
  ): Promise<SessionId> {
190
181
  signal?.throwIfAborted();
191
182
  const { atSeq, anchorMode = "after", seedSuffix = [], childSessionId, meta = {} } = options;
192
- const source = await this.persistence.inspect(sourceId, signal);
183
+ const source = await this.persistence.readLog(sourceId, {}, signal);
184
+ if (source === undefined)
185
+ throw new SessionBranchError(`session "${sourceId}" not found`, "SESSION_NOT_FOUND");
193
186
  const boundary = locateTurnEnd(source.events, atSeq, anchorMode);
194
187
  const prefix = source.events.slice(0, boundary + 1);
195
188
  const childId = childSessionId ?? mintSessionId();
@@ -213,20 +206,26 @@ export class SessionBranchRdbProvider implements SessionBranchProvider {
213
206
  ...(meta.delegationDepth !== undefined ? { delegationDepth: meta.delegationDepth } : {}),
214
207
  };
215
208
  const seed = [...renumber(prefix, 0), ...renumber(seedSuffix, prefix.length)];
216
- // 事件行复用:前缀事件(上游 seq → 源会话已存在事件行 id)注册到写路径,
209
+ // 事件行复用:前缀事件(稠密 seq → 源会话已存在事件行 id)注册到写路径,
217
210
  // appendBatch 消费时复用事件行、不复制。seedSuffix 的 manualTurn 事件是
218
211
  // 新事件(无源行),不注册。
219
212
  const internals = this.persistence.internals();
220
213
  const sourceRows = await internals.backend.getEventRows(sourceId);
221
- const sourceEventIds = new Map(sourceRows.map((row) => [row.fOriginalSeq, row.fEventId]));
214
+ const sourceEventIds = new Map(sourceRows.map((row) => [row.fSequence, row.fEventId]));
222
215
  const reuse = new Map<number, string>();
223
216
  for (const event of prefix) {
224
217
  const eventId = sourceEventIds.get(event.seq);
225
218
  if (eventId !== undefined) reuse.set(event.seq, eventId);
226
219
  }
227
220
  internals.registerReuseEventIds(childId, reuse);
228
- await this.persistence.create(childMeta, prefix.length);
229
- if (seed.length > 0) await this.persistence.append(childId, seed);
221
+ const handle = await this.persistence.create(childMeta, {
222
+ inheritedEventCount: SessionLogOffset(prefix.length),
223
+ });
224
+ try {
225
+ if (seed.length > 0) await handle.append(seed);
226
+ } finally {
227
+ await handle.close();
228
+ }
230
229
  return childId;
231
230
  }
232
231
 
@@ -245,11 +244,12 @@ export class SessionBranchRdbProvider implements SessionBranchProvider {
245
244
  const live = this.live.getSession(id);
246
245
  // live 会话先落盘 write-behind 缓冲,保证后续读取与后端事务同视图。
247
246
  if (live !== undefined) await this.live.flush(live);
248
- // 边界校验用原始事件(loadStored,不补 closers)——inspect 会给未闭合
247
+ // 边界校验用原始事件(readLog,不补 closers)——inspect 会给未闭合
249
248
  // log 补合成 closers,把 user/message 边界掩盖成 turn/end,丢失 exclusive
250
249
  // 语义。
251
250
  const raw = live === undefined ? await this.readRawEvents(id, signal) : undefined;
252
- const inspection = live === undefined ? undefined : await this.persistence.inspect(id, signal);
251
+ const inspection =
252
+ live === undefined ? undefined : await this.persistence.internals().inspect(id, signal);
253
253
  const events = live === undefined ? raw!.events : inspection!.events;
254
254
  const meta = live === undefined ? raw!.meta : inspection!.meta;
255
255
  const boundaryEvent = events[toBoundary];
@@ -273,12 +273,9 @@ export class SessionBranchRdbProvider implements SessionBranchProvider {
273
273
  const keepLength = balanceRewindPrefix(events.slice(0, rawKeepLength)).length;
274
274
 
275
275
  const internals = this.persistence.internals();
276
- // live 视图是上游 seq(含被过滤的 delta),RDB head 是稠密 seq——live
277
- // 边界须换算为前缀中 persisted 事件数 - 1;cold 视图本身已是稠密 seq
278
- const denseBoundary =
279
- live === undefined
280
- ? keepLength - 1
281
- : events.slice(0, keepLength).filter(isPersistedEvent).length - 1;
276
+ // 原样存储(无过滤):live 视图与 RDB head 同空间(上游 seq),
277
+ // 边界即保留前缀长度 - 1。
278
+ const denseBoundary = keepLength - 1;
282
279
  const newSeedLength = await internals.backend.transaction(async (tx) => {
283
280
  signal?.throwIfAborted();
284
281
  const head = await tx.getHead(id);
@@ -308,17 +305,12 @@ export class SessionBranchRdbProvider implements SessionBranchProvider {
308
305
  await tx.bumpRevision(id);
309
306
  return shrunk;
310
307
  });
311
- // 同步 coordinator 的 storage.inheritedEventCount——DB 已收缩而内存不
312
- // 收缩的话,下一次 append 的 upsert 会把旧值覆盖回去。
313
- if (newSeedLength !== null) {
314
- this.live.setCoordinatorSeedLength(id, newSeedLength);
315
- }
316
308
 
317
309
  // 更新确认 head(下一次 append 的并发校验基准),与 appendBatch 同语义。
318
310
  internals.writeGuard.confirmHead(id, denseBoundary);
319
311
 
320
312
  if (live !== undefined) {
321
- // live 分支:截断内存 log 并重置派生缓存;同步 coordinator cursor 与
313
+ // live 分支:截断内存 log 并重置派生缓存;同步 handle cursor 与
322
314
  // agent 轮次游标。不调用 load——live 时 load 会先 flush 把旧内存写回,
323
315
  // 撤销本次截断。
324
316
  truncateLiveSession(live, keepLength);
@@ -331,14 +323,12 @@ export class SessionBranchRdbProvider implements SessionBranchProvider {
331
323
  const phase = (agent as unknown as { phase?: { lastTurn?: number } }).phase;
332
324
  if (phase !== undefined) phase.lastTurn = lastTurn;
333
325
  }
334
- this.live.setCoordinatorCursor(id, keepLength);
335
- } else {
336
- // cold 分支:user/message 边界直接同步 ownerless states 条目(load 会
337
- // closers 撤销截断语义);turn/end 边界经 load 重新 adopt。
338
- if (boundaryEvent?.type === "user/message") {
339
- this.live.setCoordinatorState(id, keepLength, meta);
340
- } else {
341
- await this.persistence.load(id);
326
+ // DB 已截断:同步 live write handle 的 cursor 与继承前缀,使下一次
327
+ // append 从截断后的位置续接。handle cursor 是**上游空间**(live 内存
328
+ // log 截断后的长度,与 drainBuffered 的过滤/contiguity 校验同空间)。
329
+ const handle = this.persistence.tracker.writerOf(id);
330
+ if (handle !== undefined) {
331
+ handle.resetAfterRewind(keepLength, newSeedLength === null ? undefined : newSeedLength);
342
332
  }
343
333
  }
344
334
 
@@ -385,57 +375,6 @@ export class SessionBranchRdb extends SessionBranch {
385
375
  return agents?.get(id);
386
376
  },
387
377
  flush: (session) => this.ctx.sessions.flush(session),
388
- setCoordinatorCursor: (id, cursor) => {
389
- // states 是私有 Map;保留条目(owner 不能丢),仅对齐 cursor 到新尾部。
390
- const persistence = this.ctx.sessionPersistence as unknown as {
391
- coordinator?: {
392
- states?: Map<SessionId, { cursor: number } | undefined>;
393
- };
394
- };
395
- const state = persistence.coordinator?.states?.get(id);
396
- if (state !== undefined) state.cursor = cursor;
397
- },
398
- setCoordinatorState: (id, cursor, meta) => {
399
- // states 条目可能不存在(会话从未被 adopt);存在则仅对齐 cursor,
400
- // 不存在则创建 ownerless 条目,使下一次 append 走标准路径而非 adopt
401
- // (adopt 会经 prepareCore 补 closers 撤销截断)。
402
- const persistence = this.ctx.sessionPersistence as unknown as {
403
- coordinator?: {
404
- states?: Map<
405
- SessionId,
406
- { cursor: number; meta: SessionHeader; materialized: boolean } | undefined
407
- >;
408
- };
409
- };
410
- const states = persistence.coordinator?.states;
411
- if (states === undefined) return;
412
- const state = states.get(id);
413
- if (state !== undefined) {
414
- state.cursor = cursor;
415
- } else {
416
- states.set(id, { meta, cursor, materialized: true });
417
- }
418
- },
419
- setCoordinatorSeedLength: (id, seedLength) => {
420
- // 收缩 storage.inheritedEventCount,与 DB 事务内的收缩保持一致——
421
- // 不同步的话下一次 append 的 upsert 会把旧值覆盖回去。storage 对象
422
- // 可能被冻结,整体替换 state.storage 而非改字段。
423
- const persistence = this.ctx.sessionPersistence as unknown as {
424
- coordinator?: {
425
- states?: Map<
426
- SessionId,
427
- | {
428
- storage?: { meta: SessionHeader; inheritedEventCount: number };
429
- }
430
- | undefined
431
- >;
432
- };
433
- };
434
- const state = persistence.coordinator?.states?.get(id);
435
- if (state?.storage !== undefined && state.storage.inheritedEventCount > seedLength) {
436
- state.storage = { ...state.storage, inheritedEventCount: seedLength };
437
- }
438
- },
439
378
  },
440
379
  );
441
380
 
@@ -471,26 +410,6 @@ export class SessionBranchRdb extends SessionBranch {
471
410
  return this.provider.rewind(id, toBoundary, signal);
472
411
  }
473
412
 
474
- syncLiveCursor(sessionId: SessionId): void {
475
- const live = this.ctx.sessions.get(sessionId);
476
- if (live === undefined) return;
477
- const persistence = this.ctx.sessionPersistence as unknown as {
478
- coordinator?: {
479
- states?: Map<SessionId, { cursor: number } | undefined>;
480
- };
481
- };
482
- const state = persistence.coordinator?.states?.get(sessionId);
483
- if (state === undefined) return;
484
- let cursor = state.cursor;
485
- // ignorable 是下游信封扩展(上游 SessionEvent 无此字段),结构化读取。
486
- while (
487
- (live.snapshotEvents()[cursor] as (SessionEvent & { ignorable?: unknown }) | undefined)
488
- ?.ignorable === true
489
- )
490
- cursor += 1;
491
- state.cursor = cursor;
492
- }
493
-
494
413
  async timeline(sessionId: SessionId, signal?: AbortSignal) {
495
414
  const persistence = this.ctx.sessionPersistence as SessionPersistenceRdb;
496
415
  const snapshots = await persistence.listSnapshots(signal);
@@ -499,7 +418,7 @@ export class SessionBranchRdb extends SessionBranch {
499
418
  const readOwnEvents = async (id: SessionId, fromSeq: number, s?: AbortSignal) => {
500
419
  const live = this.ctx.sessions.get(id);
501
420
  if (live !== undefined) return live.snapshotEvents().slice(fromSeq);
502
- return (await persistence.readFrom(id, fromSeq, s)).events;
421
+ return (await persistence.internals().readFrom(id, fromSeq, s)).events;
503
422
  };
504
423
  return buildTimeline(snapshots, readOwnEvents, sessionId, signal);
505
424
  }
@@ -0,0 +1,11 @@
1
+ // drizzle-kit 入口:v2 快照(PG,具名导出表对象)。
2
+ import { toPostgresSchema } from "../adapters/to-postgres.ts";
3
+ import { postgresTableDefsV2 } from "../entities/v2/index.ts";
4
+
5
+ const tables = toPostgresSchema(postgresTableDefsV2);
6
+
7
+ export const tPersistenceState = tables["t_persistence_state"]!;
8
+ export const tSchemaMeta = tables["t_schema_meta"]!;
9
+ export const tSessions = tables["t_sessions"]!;
10
+ export const tEvents = tables["t_events"]!;
11
+ export const tSessionEvents = tables["t_session_events"]!;
@@ -0,0 +1,11 @@
1
+ // drizzle-kit 入口:v3 快照(PG,具名导出表对象)。
2
+ import { toPostgresSchema } from "../adapters/to-postgres.ts";
3
+ import { postgresTableDefs } from "../entities/v3/index.ts";
4
+
5
+ const tables = toPostgresSchema(postgresTableDefs);
6
+
7
+ export const tPersistenceState = tables["t_persistence_state"]!;
8
+ export const tSchemaMeta = tables["t_schema_meta"]!;
9
+ export const tSessions = tables["t_sessions"]!;
10
+ export const tEvents = tables["t_events"]!;
11
+ export const tSessionEvents = tables["t_session_events"]!;
@@ -0,0 +1,10 @@
1
+ // drizzle-kit 入口:v2 快照(具名导出表对象,供 generate 生成 v2 baseline)。
2
+ import { toSqliteSchema } from "../adapters/to-sqlite.ts";
3
+ import { sqliteTableDefsV2 } from "../entities/v2/index.ts";
4
+
5
+ const tables = toSqliteSchema(sqliteTableDefsV2);
6
+
7
+ export const tPersistenceState = tables["t_persistence_state"]!;
8
+ export const tSessions = tables["t_sessions"]!;
9
+ export const tEvents = tables["t_events"]!;
10
+ export const tSessionEvents = tables["t_session_events"]!;
@@ -0,0 +1,11 @@
1
+ // drizzle-kit 入口:v3 快照(具名导出表对象,供 generate 生成 v3 diff)。
2
+ import { toSqliteSchema } from "../adapters/to-sqlite.ts";
3
+ import { sqliteTableDefs } from "../entities/v3/index.ts";
4
+
5
+ const tables = toSqliteSchema(sqliteTableDefs);
6
+
7
+ export const tPersistenceState = tables["t_persistence_state"]!;
8
+ export const tSchemaMeta = tables["t_schema_meta"]!;
9
+ export const tSessions = tables["t_sessions"]!;
10
+ export const tEvents = tables["t_events"]!;
11
+ export const tSessionEvents = tables["t_session_events"]!;
@@ -1,30 +1,2 @@
1
- import { persistenceState } from "./persistence-state.ts";
2
- import { schemaMeta } from "./schema-meta.ts";
3
- import { sessions } from "./sessions.ts";
4
- import { events } from "./events.ts";
5
- import { sessionEvents } from "./session-events.ts";
6
-
7
- export { persistenceState };
8
- export { schemaMeta };
9
- export { sessions };
10
- export { events };
11
- export { sessionEvents };
12
- export type {
13
- ColumnDef,
14
- TableDef,
15
- CheckDef,
16
- UniqueDef,
17
- IndexDef,
18
- ColumnTypeName,
19
- DeleteAction,
20
- } from "./types.ts";
21
-
22
- export const sqliteTableDefs = [persistenceState, sessions, events, sessionEvents] as const;
23
-
24
- export const postgresTableDefs = [
25
- persistenceState,
26
- schemaMeta,
27
- sessions,
28
- events,
29
- sessionEvents,
30
- ] as const;
1
+ export { sqliteTableDefs, postgresTableDefs } from "./v3/index.ts";
2
+ export { sqliteTableDefsV2, postgresTableDefsV2 } from "./v2/index.ts";
@@ -0,0 +1,20 @@
1
+ import { persistenceState } from "../v3/persistence-state.ts";
2
+ import { schemaMeta } from "../v3/schema-meta.ts";
3
+ import { sessions } from "../v3/sessions.ts";
4
+ import { events } from "../v3/events.ts";
5
+ import { sessionEvents } from "./session-events.ts";
6
+
7
+ export { persistenceState };
8
+ export { schemaMeta };
9
+ export { sessions };
10
+ export { events };
11
+ export { sessionEvents };
12
+
13
+ export const sqliteTableDefsV2 = [persistenceState, sessions, events, sessionEvents] as const;
14
+ export const postgresTableDefsV2 = [
15
+ persistenceState,
16
+ schemaMeta,
17
+ sessions,
18
+ events,
19
+ sessionEvents,
20
+ ] as const;
@@ -0,0 +1,11 @@
1
+ import type { TableDef } from "../../adapters/types.ts";
2
+ import { sessionEvents as v3SessionEvents } from "../v3/session-events.ts";
3
+
4
+ /** v2 派生:v3 规格 + f_original_seq 列(原样存储前记录上游 seq 的遗留列)。 */
5
+ export const sessionEvents: TableDef = {
6
+ ...v3SessionEvents,
7
+ columns: {
8
+ ...v3SessionEvents.columns,
9
+ f_original_seq: { type: "integer", notNull: true },
10
+ },
11
+ };
@@ -0,0 +1,27 @@
1
+ import type { TableDef } from "../../adapters/types.ts";
2
+
3
+ export const events: TableDef = {
4
+ name: "t_events",
5
+ columns: {
6
+ f_id: { type: "serial", primaryKey: true },
7
+ f_event_id: { type: "text", notNull: true, unique: true },
8
+ f_parent_id: { type: "text", notNull: true, default: "" },
9
+ f_type: { type: "text", notNull: true, default: "" },
10
+ f_kind: { type: "text", notNull: true, default: "" },
11
+ f_role: { type: "text", notNull: true, default: "" },
12
+ f_name: { type: "text", notNull: true, default: "" },
13
+ f_action_id: { type: "text", notNull: true, default: "" },
14
+ f_encoding: { type: "text", notNull: true, default: "" },
15
+ f_data: { type: "text", notNull: true },
16
+ f_created_at: { type: "bigint", notNull: true, default: 0 },
17
+ },
18
+ // 查询经 f_event_id(列级 UNIQUE 唯一索引)与 t_session_events 复合索引
19
+ // (按 session 过滤后回表);f_parent_id 仅写路径构造;维度列索引为
20
+ // 审计/UI 过滤预留。
21
+ indexes: {
22
+ idx_events_kind: { columns: ["f_kind"] },
23
+ idx_events_role: { columns: ["f_role"] },
24
+ idx_events_name: { columns: ["f_name"] },
25
+ idx_events_action_id: { columns: ["f_action_id"] },
26
+ },
27
+ };
@@ -0,0 +1,27 @@
1
+ import { persistenceState } from "./persistence-state.ts";
2
+ import { schemaMeta } from "./schema-meta.ts";
3
+ import { sessions } from "./sessions.ts";
4
+ import { events } from "./events.ts";
5
+ import { sessionEvents } from "./session-events.ts";
6
+
7
+ export { persistenceState };
8
+ export { schemaMeta };
9
+ export { sessions };
10
+ export { events };
11
+ export { sessionEvents };
12
+
13
+ export const sqliteTableDefs = [
14
+ persistenceState,
15
+ schemaMeta,
16
+ sessions,
17
+ events,
18
+ sessionEvents,
19
+ ] as const;
20
+
21
+ export const postgresTableDefs = [
22
+ persistenceState,
23
+ schemaMeta,
24
+ sessions,
25
+ events,
26
+ sessionEvents,
27
+ ] as const;
@@ -0,0 +1,10 @@
1
+ import type { TableDef } from "../../adapters/types.ts";
2
+
3
+ export const persistenceState: TableDef = {
4
+ name: "t_persistence_state",
5
+ columns: {
6
+ f_singleton: { type: "integer", primaryKey: true },
7
+ f_store_id: { type: "text", notNull: true },
8
+ },
9
+ checks: { ck_persistence_state_singleton: { expression: "f_singleton = 1" } },
10
+ };
@@ -0,0 +1,9 @@
1
+ import type { TableDef } from "../../adapters/types.ts";
2
+
3
+ export const schemaMeta: TableDef = {
4
+ name: "t_schema_meta",
5
+ columns: {
6
+ f_key: { type: "text", primaryKey: true },
7
+ f_value: { type: "text", notNull: true },
8
+ },
9
+ };
@@ -0,0 +1,26 @@
1
+ import type { TableDef } from "../../adapters/types.ts";
2
+
3
+ export const sessionEvents: TableDef = {
4
+ name: "t_session_events",
5
+ columns: {
6
+ f_id: { type: "serial", primaryKey: true },
7
+ f_session_id: {
8
+ type: "text",
9
+ notNull: true,
10
+ references: { table: "t_sessions", column: "f_session_id", onDelete: "cascade" },
11
+ },
12
+ f_event_id: {
13
+ type: "text",
14
+ notNull: true,
15
+ references: { table: "t_events", column: "f_event_id", onDelete: "cascade" },
16
+ },
17
+ f_sequence: { type: "integer", notNull: true },
18
+ f_surface_op: { type: "text" },
19
+ },
20
+ uniques: {
21
+ uq_session_events_session_sequence: { columns: ["f_session_id", "f_sequence"] },
22
+ },
23
+ // UNIQUE(f_session_id, f_sequence) 自动建唯一索引(按 session 过滤 + seq
24
+ // 范围/排序/取尾);f_event_id 索引覆盖反向查找(孤儿事件行清理)。
25
+ indexes: { idx_session_events_event_id: { columns: ["f_event_id"] } },
26
+ };
@@ -0,0 +1,20 @@
1
+ import type { TableDef } from "../../adapters/types.ts";
2
+
3
+ export const sessions: TableDef = {
4
+ name: "t_sessions",
5
+ columns: {
6
+ f_id: { type: "serial", primaryKey: true },
7
+ f_session_id: { type: "text", notNull: true, unique: true },
8
+ f_head_event_id: { type: "text", notNull: true, default: "" },
9
+ f_head_sequence: { type: "integer", notNull: true, default: -1 },
10
+ f_version: { type: "integer", notNull: true },
11
+ f_created_at: { type: "bigint", notNull: true },
12
+ f_cwd: { type: "text" },
13
+ f_parent_session: { type: "text" },
14
+ f_seed_length: { type: "integer" },
15
+ f_origin: { type: "text" },
16
+ f_delegation_depth: { type: "integer" },
17
+ f_incarnation: { type: "text", notNull: true },
18
+ f_revision: { type: "integer", notNull: true },
19
+ },
20
+ };