@whispering233/ai-editor-db 0.0.21 → 0.0.26

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 (73) hide show
  1. package/dist/connection.js +2 -2
  2. package/dist/connection.js.map +1 -1
  3. package/dist/index.js +1 -1
  4. package/dist/index.js.map +1 -1
  5. package/dist/migrations/002_event_timeline.js +1 -1
  6. package/dist/migrations/002_event_timeline.js.map +1 -1
  7. package/dist/migrations/003_timepoint.js +8 -8
  8. package/dist/migrations/003_timepoint.js.map +1 -1
  9. package/dist/migrations/004_setting_tags.js +2 -2
  10. package/dist/migrations/004_setting_tags.js.map +1 -1
  11. package/dist/migrations/005_reference.js +2 -2
  12. package/dist/migrations/005_reference.js.map +1 -1
  13. package/dist/migrations/index.d.ts +2 -2
  14. package/dist/migrations/index.d.ts.map +1 -1
  15. package/dist/migrations/index.js +7 -7
  16. package/dist/migrations/index.js.map +1 -1
  17. package/dist/queries/chat.d.ts +20 -20
  18. package/dist/queries/chat.d.ts.map +1 -1
  19. package/dist/queries/chat.js +105 -59
  20. package/dist/queries/chat.js.map +1 -1
  21. package/dist/queries/compute-state.d.ts +9 -9
  22. package/dist/queries/compute-state.d.ts.map +1 -1
  23. package/dist/queries/compute-state.js +22 -28
  24. package/dist/queries/compute-state.js.map +1 -1
  25. package/dist/queries/delta.d.ts +21 -21
  26. package/dist/queries/delta.d.ts.map +1 -1
  27. package/dist/queries/delta.js +110 -63
  28. package/dist/queries/delta.js.map +1 -1
  29. package/dist/queries/entity.d.ts +50 -46
  30. package/dist/queries/entity.d.ts.map +1 -1
  31. package/dist/queries/entity.js +226 -137
  32. package/dist/queries/entity.js.map +1 -1
  33. package/dist/queries/migration.d.ts +31 -31
  34. package/dist/queries/migration.d.ts.map +1 -1
  35. package/dist/queries/migration.js +43 -44
  36. package/dist/queries/migration.js.map +1 -1
  37. package/dist/queries/outline-ops.d.ts +22 -22
  38. package/dist/queries/outline-ops.d.ts.map +1 -1
  39. package/dist/queries/outline-ops.js +35 -42
  40. package/dist/queries/outline-ops.js.map +1 -1
  41. package/dist/queries/relation.d.ts +18 -18
  42. package/dist/queries/relation.d.ts.map +1 -1
  43. package/dist/queries/relation.js +115 -84
  44. package/dist/queries/relation.js.map +1 -1
  45. package/dist/queries/trash.d.ts +10 -10
  46. package/dist/queries/trash.d.ts.map +1 -1
  47. package/dist/queries/trash.js +75 -48
  48. package/dist/queries/trash.js.map +1 -1
  49. package/dist/query-db.d.ts +5 -0
  50. package/dist/query-db.d.ts.map +1 -0
  51. package/dist/query-db.js +22 -0
  52. package/dist/query-db.js.map +1 -0
  53. package/dist/schema.d.ts +8 -20
  54. package/dist/schema.d.ts.map +1 -1
  55. package/dist/schema.js +13 -85
  56. package/dist/schema.js.map +1 -1
  57. package/dist/storage/atomic.d.ts +8 -8
  58. package/dist/storage/atomic.d.ts.map +1 -1
  59. package/dist/storage/atomic.js +10 -11
  60. package/dist/storage/atomic.js.map +1 -1
  61. package/dist/storage/outline.d.ts +14 -14
  62. package/dist/storage/outline.d.ts.map +1 -1
  63. package/dist/storage/outline.js +17 -18
  64. package/dist/storage/outline.js.map +1 -1
  65. package/dist/storage/project.d.ts +11 -11
  66. package/dist/storage/project.d.ts.map +1 -1
  67. package/dist/storage/project.js +17 -18
  68. package/dist/storage/project.js.map +1 -1
  69. package/dist/tables.d.ts +718 -0
  70. package/dist/tables.d.ts.map +1 -0
  71. package/dist/tables.js +141 -0
  72. package/dist/tables.js.map +1 -0
  73. package/package.json +3 -2
@@ -1,41 +1,54 @@
1
1
  // @whispering233/ai-editor-db 回收站数据层(S4.1):实体列表/级联还原/物理清除 + 级联 helper(自 server 下沉)
2
2
  //
3
- // 单一事实来源:
4
- // - doc/api/endpoints.md 第 660-736 行(回收站端点契约:GET /trash、POST restore、DELETE purge)
5
- // - doc/design/decisions.md 决策 12(软删/级联还原/物理清除;2026-08 修订:软删/还原更新
6
- // updated_at;restore 级联还原全部关系不因另一端仍软删而跳过;手动删关系 = 物理删)
7
- // - doc/ui/pages/trash.md(列表字段:entities[].{ id, type, name, deleted_at },deleted_at 倒序)
8
3
  //
9
4
  // 边界(与路由层的分工):
10
- // - 本模块只提供 data.db 侧原子操作;「先 DB 后 JSON」写序(决策 16)与 outline restore 的
11
- // 祖先链 409 校验由路由层组合(S4.3 保持现状,不在本层实现)。
5
+ // - 本模块只提供 data.db 侧原子操作;「先 DB 后 JSON」写序与 outline restore 的
6
+ // 祖先链 409 校验由路由层组合(S4.3 保持现状,不在本层实现)。
12
7
  // - 「purge 仅用于回收站清理」(未软删拒绝)属路由层语义拦截,本层不校验
13
- // (与 outline purge 路由的 isSoftDeleted 拦截同构)。
8
+ // (与 outline purge 路由的 isSoftDeleted 拦截同构)。
14
9
  // - 可见性过滤(端点仍软删的关系/Delta 不可见)由查询层(relation.ts / entity.ts)负责,
15
- // restore 层不做——全部还原(决策 12 修订),端点还原后自动可见。
10
+ // restore 层不做——全部还原,端点还原后自动可见。
16
11
  //
17
12
  // 级联 helper(cascadeRestore/cascadePurge)自 server/routes/outline.ts 下沉(trash.ts 注释
18
13
  // 留痕的「S3 建模块后可下沉」项,S4.1 兑现):参数与 SQL 语义不变,仅补充单库事务包裹。
14
+ //
15
+ // 批次十五(15.2 试点):**全部查询经 queryDb 走 drizzle 构建器**(本卡为试点模块,
16
+ // 混合风格 4A:本模块均为单一表条件更新/删除/查询,builder 表达清晰,无 sql 模板需求)。
17
+ // 语义逐句对照旧实现(git show d510f25^:packages/db/src/queries/trash.ts):
18
+ // - deleted_at IS NOT NULL ↔ isNotNull;排序 desc(deleted_at) ↔ ORDER BY deleted_at DESC
19
+ // - (source_id = ? OR target_id = ?) ↔ or(eq,eq);IN 占位符 ↔ inArray(空集自动恒假)
20
+ // - UPDATE ... WHERE 同列多重条件 ↔ and 组合;set({ deleted_at: null }) ↔ SET deleted_at = NULL
21
+ // - 幂等语义不变:存在性检查限定 deleted_at IS NOT NULL / UPDATE 均带软删过滤
22
+ // 事务沿用 withTransaction(native db.transaction):drizzle 查询与 native 事务**连接级共享**——
23
+ // 同一连接上 builder 执行的语句在事务边界内,见 15.2 验证记录①。
24
+ import { eq, and, isNotNull, or, desc, inArray } from "drizzle-orm";
25
+ import { deltaRecords, entities, relationRecords } from "../tables.js";
19
26
  import { nowIso } from "../storage/atomic.js";
20
27
  import { withTransaction } from "../connection.js";
28
+ import { queryDb } from "../query-db.js";
21
29
  /**
22
30
  * 回收站列表(实体侧,GET /api/v1/trash):entities 表 deleted_at IS NOT NULL,
23
31
  * 按 deleted_at 倒序(回收站排序约定——ISO 字符串字典序即时间序,与 listDeletedNodes 一致)。
24
- * 常规查询默认过滤软删(决策 12),回收站 API 是访问软删对象的唯一入口。
32
+ * 常规查询默认过滤软删,回收站 API 是访问软删对象的唯一入口。
25
33
  */
26
34
  export function listDeletedEntities(db) {
27
- const rows = db
28
- .prepare("SELECT id, type, name, deleted_at FROM entities WHERE deleted_at IS NOT NULL ORDER BY deleted_at DESC")
35
+ const q = queryDb(db);
36
+ const rows = q
37
+ .select({ id: entities.id, type: entities.type, name: entities.name, deletedAt: entities.deleted_at })
38
+ .from(entities)
39
+ .where(isNotNull(entities.deleted_at))
40
+ .orderBy(desc(entities.deleted_at))
29
41
  .all();
30
- return rows.map((r) => ({ id: r.id, type: r.type, name: r.name, deletedAt: r.deleted_at }));
42
+ // drizzle 行映射:字段即 Shared 形态(snake→camel 在 select 别名处完成)
43
+ return rows.map((r) => ({ id: r.id, type: r.type, name: r.name, deletedAt: r.deletedAt }));
31
44
  }
32
45
  /**
33
- * 还原软删实体(POST /api/v1/trash/entity/:type/:id/restore,endpoints.md 第 676-692 行,决策 12 修订):
34
- * - 自身:deleted_at 置 NULL + **updated_at 刷新**(决策 12 修订:与常规编辑一致,
35
- * 保证决策 14 提案快照比对语义统一——还原后基于旧快照的提案必然 PROPOSAL_STALE)
46
+ * 还原软删实体(POST /api/v1/trash/entity/:type/:id/restore,):
47
+ * - 自身:deleted_at 置 NULL + **updated_at 刷新**(与常规编辑一致,
48
+ * 保证 提案快照比对语义统一——还原后基于旧快照的提案必然 PROPOSAL_STALE)
36
49
  * - 关联关系:relation_records(source_id = id **或** target_id = id)deleted_at 置 NULL——
37
- * **全部还原**,不因另一端仍软删而跳过(决策 12 修订:数据永不丢失;端点仍软删的
38
- * 关系由查询层可见性过滤,端点还原后自动可见)
50
+ * **全部还原**,不因另一端仍软删而跳过(数据永不丢失;端点仍软删的
51
+ * 关系由查询层可见性过滤,端点还原后自动可见)
39
52
  * - 关联 Delta:delta_records(target_id = id)同规则
40
53
  * 单库事务(withTransaction,原子性);幂等:实体不存在、类型不匹配或未软删 → 返回 null
41
54
  * 且无任何副作用(存在性检查限定 deleted_at IS NOT NULL,级联 UPDATE 均带
@@ -46,23 +59,33 @@ export function listDeletedEntities(db) {
46
59
  */
47
60
  export function restoreEntity(db, type, id) {
48
61
  return withTransaction(db, () => {
49
- const exists = db
50
- .prepare("SELECT id FROM entities WHERE id = ? AND type = ? AND deleted_at IS NOT NULL")
51
- .get(id, type);
62
+ const q = queryDb(db);
63
+ const exists = q
64
+ .select({ id: entities.id })
65
+ .from(entities)
66
+ .where(and(eq(entities.id, id), eq(entities.type, type), isNotNull(entities.deleted_at)))
67
+ .get();
52
68
  if (exists === undefined)
53
69
  return null;
54
- const rel = db
55
- .prepare(`UPDATE relation_records SET deleted_at = NULL WHERE deleted_at IS NOT NULL AND (source_id = ? OR target_id = ?)`)
56
- .run(id, id);
57
- const delta = db
58
- .prepare(`UPDATE delta_records SET deleted_at = NULL WHERE deleted_at IS NOT NULL AND target_id = ?`)
59
- .run(id);
60
- db.prepare("UPDATE entities SET deleted_at = NULL, updated_at = ? WHERE id = ?").run(nowIso(), id);
70
+ const rel = q
71
+ .update(relationRecords)
72
+ .set({ deleted_at: null })
73
+ .where(and(isNotNull(relationRecords.deleted_at), or(eq(relationRecords.source_id, id), eq(relationRecords.target_id, id))))
74
+ .run();
75
+ const delta = q
76
+ .update(deltaRecords)
77
+ .set({ deleted_at: null })
78
+ .where(and(isNotNull(deltaRecords.deleted_at), eq(deltaRecords.target_id, id)))
79
+ .run();
80
+ q.update(entities)
81
+ .set({ deleted_at: null, updated_at: nowIso() })
82
+ .where(eq(entities.id, id))
83
+ .run();
61
84
  return { restoredRelations: rel.changes, restoredDeltas: delta.changes };
62
85
  });
63
86
  }
64
87
  /**
65
- * 物理清除软删实体(DELETE /api/v1/trash/entity/:type/:id,endpoints.md 第 713-724 行):
88
+ * 物理清除软删实体(DELETE /api/v1/trash/entity/:type/:id,):
66
89
  * 不可恢复——DELETE 实体本体 + 关联 relations(source_id = id 或 target_id = id)+
67
90
  * deltas(target_id = id)。单库事务。
68
91
  * 幂等:实体不存在或类型不匹配 → 返回 null 且无副作用。
@@ -74,21 +97,18 @@ export function restoreEntity(db, type, id) {
74
97
  */
75
98
  export function purgeEntity(db, type, id) {
76
99
  return withTransaction(db, () => {
77
- const exists = db.prepare("SELECT id FROM entities WHERE id = ? AND type = ?").get(id, type);
100
+ const q = queryDb(db);
101
+ const exists = q.select({ id: entities.id }).from(entities).where(and(eq(entities.id, id), eq(entities.type, type))).get();
78
102
  if (exists === undefined)
79
103
  return null;
80
- db.prepare("DELETE FROM relation_records WHERE source_id = ? OR target_id = ?").run(id, id);
81
- db.prepare("DELETE FROM delta_records WHERE target_id = ?").run(id);
82
- db.prepare("DELETE FROM entities WHERE id = ?").run(id);
104
+ q.delete(relationRecords).where(or(eq(relationRecords.source_id, id), eq(relationRecords.target_id, id))).run();
105
+ q.delete(deltaRecords).where(eq(deltaRecords.target_id, id)).run();
106
+ q.delete(entities).where(eq(entities.id, id)).run();
83
107
  return true;
84
108
  });
85
109
  }
86
- /** 生成 SQL IN 占位符串(id 集来自服务端生成的 nanoid,无注入面;空集返回 "(NULL)" 恒假) */
87
- function inPlaceholders(ids) {
88
- return ids.length === 0 ? "(NULL)" : `(${ids.map(() => "?").join(",")})`;
89
- }
90
110
  /**
91
- * 级联还原子树关联的 relation/delta(决策 12 修订:全部还原,不因另一端仍软删而跳过;
111
+ * 级联还原子树关联的 relation/delta(全部还原,不因另一端仍软删而跳过;
92
112
  * 自 server/routes/outline.ts 下沉,参数与 SQL 语义不变):
93
113
  * - relations:source 或 target 命中子树任一节点 → deleted_at 置 NULL(含 plot_edge 画布连线)
94
114
  * - deltas:node_id 命中子树任一节点 → deleted_at 置 NULL(delta_records.node_id = 触发节点列)
@@ -96,26 +116,33 @@ function inPlaceholders(ids) {
96
116
  */
97
117
  export function cascadeRestore(db, subtreeIds) {
98
118
  return withTransaction(db, () => {
99
- const rel = db
100
- .prepare(`UPDATE relation_records SET deleted_at = NULL WHERE deleted_at IS NOT NULL AND
101
- (source_id IN ${inPlaceholders(subtreeIds)} OR target_id IN ${inPlaceholders(subtreeIds)})`)
102
- .run(...subtreeIds, ...subtreeIds);
103
- const delta = db
104
- .prepare(`UPDATE delta_records SET deleted_at = NULL WHERE deleted_at IS NOT NULL AND node_id IN ${inPlaceholders(subtreeIds)}`)
105
- .run(...subtreeIds);
119
+ const q = queryDb(db);
120
+ const rel = q
121
+ .update(relationRecords)
122
+ .set({ deleted_at: null })
123
+ .where(and(isNotNull(relationRecords.deleted_at), or(inArray(relationRecords.source_id, subtreeIds), inArray(relationRecords.target_id, subtreeIds))))
124
+ .run();
125
+ const delta = q
126
+ .update(deltaRecords)
127
+ .set({ deleted_at: null })
128
+ .where(and(isNotNull(deltaRecords.deleted_at), inArray(deltaRecords.node_id, subtreeIds)))
129
+ .run();
106
130
  return { relations: rel.changes, deltas: delta.changes };
107
131
  });
108
132
  }
109
133
  /**
110
- * 物理清除子树关联的 relation/delta(purge,决策 12:物理清除且不可恢复;
134
+ * 物理清除子树关联的 relation/delta(purge,物理清除且不可恢复;
111
135
  * 自 server/routes/outline.ts 下沉,参数与 SQL 语义不变):
112
136
  * - relations:source 或 target 命中子树任一节点 → 物理删除
113
137
  * - deltas:node_id 命中子树任一节点 → 物理删除
114
138
  */
115
139
  export function cascadePurge(db, subtreeIds) {
116
140
  withTransaction(db, () => {
117
- db.prepare(`DELETE FROM relation_records WHERE source_id IN ${inPlaceholders(subtreeIds)} OR target_id IN ${inPlaceholders(subtreeIds)}`).run(...subtreeIds, ...subtreeIds);
118
- db.prepare(`DELETE FROM delta_records WHERE node_id IN ${inPlaceholders(subtreeIds)}`).run(...subtreeIds);
141
+ const q = queryDb(db);
142
+ q.delete(relationRecords)
143
+ .where(or(inArray(relationRecords.source_id, subtreeIds), inArray(relationRecords.target_id, subtreeIds)))
144
+ .run();
145
+ q.delete(deltaRecords).where(inArray(deltaRecords.node_id, subtreeIds)).run();
119
146
  });
120
147
  }
121
148
  //# sourceMappingURL=trash.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"trash.js","sourceRoot":"","sources":["../../src/queries/trash.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"trash.js","sourceRoot":"","sources":["../../src/queries/trash.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import { type BetterSQLite3Database } from "drizzle-orm/better-sqlite3";
2
+ import type Database from "better-sqlite3";
3
+ /** 获取 db 的 drizzle 查询实例(同连接缓存;类型为 sync 模式 BetterSQLite3Database) */
4
+ export declare function queryDb(db: Database.Database): BetterSQLite3Database;
5
+ //# sourceMappingURL=query-db.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query-db.d.ts","sourceRoot":"","sources":["../src/query-db.ts"],"names":[],"mappings":"AAWA,OAAO,EAAW,KAAK,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACjF,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAI3C,oEAAoE;AACpE,wBAAgB,OAAO,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,qBAAqB,CAOpE"}
@@ -0,0 +1,22 @@
1
+ // @whispering233/ai-editor-db queryDb 辅助:native 连接 → drizzle 实例(批次十五 15.2)
2
+ //
3
+ // 查询模块函数签名保持 (db: Db)(native better-sqlite3 连接,调用方零改动),
4
+ // 模块内部经本辅助获取 drizzle 查询实例(builder/模板混合风格,4A)。
5
+ //
6
+ // - WeakMap 缓存:同一 native 连接只构造一次 drizzle 实例(构造本身轻量——仅包装
7
+ // client/dialect/session,无 I/O;缓存省去每函数调用的重复分配);测试并行多库互不干扰,
8
+ // 连接关闭后随 WeakMap 键自然 GC,无泄漏。
9
+ // - `$client` 可逆取回 native 连接:事务(withTransaction 保持 native db.transaction,
10
+ // 连接级共享——见 15.2 验证记录①)、PRAGMA、自建迁移管线走 native 路径。
11
+ import { drizzle } from "drizzle-orm/better-sqlite3";
12
+ const cache = new WeakMap();
13
+ /** 获取 db 的 drizzle 查询实例(同连接缓存;类型为 sync 模式 BetterSQLite3Database) */
14
+ export function queryDb(db) {
15
+ let q = cache.get(db);
16
+ if (q === undefined) {
17
+ q = drizzle(db);
18
+ cache.set(db, q);
19
+ }
20
+ return q;
21
+ }
22
+ //# sourceMappingURL=query-db.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query-db.js","sourceRoot":"","sources":["../src/query-db.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,EAAE;AACF,wDAAwD;AACxD,8CAA8C;AAC9C,EAAE;AACF,wDAAwD;AACxD,2DAA2D;AAC3D,6BAA6B;AAC7B,0EAA0E;AAC1E,iDAAiD;AAEjD,OAAO,EAAE,OAAO,EAA8B,MAAM,4BAA4B,CAAC;AAGjF,MAAM,KAAK,GAAG,IAAI,OAAO,EAA4C,CAAC;AAEtE,oEAAoE;AACpE,MAAM,UAAU,OAAO,CAAC,EAAqB;IAC3C,IAAI,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACtB,IAAI,CAAC,KAAK,SAAS,EAAE,CAAC;QACpB,CAAC,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC;QAChB,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;IACnB,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC"}
package/dist/schema.d.ts CHANGED
@@ -1,37 +1,25 @@
1
1
  import type Database from "better-sqlite3";
2
2
  /**
3
- * data.db 当前 schema 版本(决策 13;SCHEMA_VERSION = 2 起由增量迁移驱动,E5)。
4
- * v1 → v2(决策 26 时间轴):entities 表 type CHECK 扩为 5 种(含 event)+ 新增
3
+ * data.db 当前 schema 版本(SCHEMA_VERSION = 2 起由增量迁移驱动)。
4
+ * v1 → v2( 时间轴):entities 表 type CHECK 扩为 5 种(含 event)+ 新增
5
5
  * sort_order 列——旧 v1 库经 migrations/002_event_timeline.ts 迁移,新库直接建 v2 结构。
6
- * v2 → v3(G2 时间标签点实体化,决策 26 修订):entities 表 type CHECK 扩为 6 种
6
+ * v2 → v3(G2 时间标签点实体化):entities 表 type CHECK 扩为 6 种
7
7
  * (含 timepoint)+ 旧 event.data.time_label 由 migrations/003_timepoint.ts 迁移为
8
8
  * timepoint 实体 + occurs_at 挂载关系(从 event.data 移除 time_label)。
9
- * v3 → v4(决策 31 K2 修订,2026-08):**无 DDL**——仅 entities.data JSON 数据迁移
9
+ * v3 → v4( K2 修订,2026-08):**无 DDL**——仅 entities.data JSON 数据迁移
10
10
  * (setting 的旧 rules 分类值复制到 data.tags 并移除 rules,migrations/004_setting_tags.ts)。
11
11
  */
12
12
  export declare const SCHEMA_VERSION = 5;
13
13
  /**
14
- * 四张业务表 + 索引的建表 SQL(幂等:CREATE TABLE/INDEX IF NOT EXISTS)。
15
- *
16
- * - entities 实体(character/setting/location/hook/event/timepoint),type 受 CHECK 约束,data 存 JSON,
17
- * sort_order 为时间轴线性序(决策 26 + G2 修订:event 与 timepoint 各类型内线性,
18
- * 其余类型 NULL),软删列 deleted_at(决策 12)
19
- * - relation_records 通用关系表(含 plot_edge 剧情连线、occurs_in 事件锚定,决策 26),
20
- * 3 个部分索引 WHERE deleted_at IS NULL(决策 12 修订)
21
- * - delta_records 属性变更记录("order" 列引号保留——ORDER 是 SQLite 关键字)
22
- * - chat_messages 对话历史(决策 18),含 project_id/tool_call_id,会话索引 (session_id, created_at)
23
- */
24
- export declare const CREATE_TABLES_SQL = "\n-- entities\uFF1A\u5B9E\u4F53\u8868\uFF08\u4EBA\u7269/\u8BBE\u5B9A/\u5730\u70B9/\u4F0F\u7B14/\u65F6\u95F4\u8F74\u4E8B\u4EF6/\u65F6\u95F4\u6807\u7B7E\u70B9\uFF09\nCREATE TABLE IF NOT EXISTS entities (\n id TEXT PRIMARY KEY,\n type TEXT NOT NULL CHECK(type IN ('character', 'setting', 'location', 'hook', 'event', 'timepoint', 'reference')),\n name TEXT NOT NULL,\n data TEXT NOT NULL DEFAULT '{}', -- JSON: \u5404\u7C7B\u578B\u7684\u4E13\u5C5E\u5B57\u6BB5\n sort_order INTEGER, -- \u65F6\u95F4\u8F74\u7EBF\u6027\u5E8F\uFF08\u51B3\u7B56 26 + G2 \u4FEE\u8BA2\uFF09\uFF1Aevent \u4E0E timepoint \u5404\u7C7B\u578B\u5185\u7EBF\u6027\uFF08\u5404\u81EA 0..n-1\uFF09\uFF0C\u5176\u4F59\u7C7B\u578B\u6052\u4E3A NULL\n created_at TEXT NOT NULL, -- ISO 8601\uFF0C\u5E94\u7528\u5C42\u5199\u5165\n updated_at TEXT NOT NULL, -- ISO 8601\uFF0C\u5E94\u7528\u5C42\u5199\u5165\uFF08\u63D0\u6848\u5FEB\u7167\u6BD4\u5BF9\uFF0C\u51B3\u7B56 14\uFF09\n deleted_at TEXT -- \u8F6F\u5220\u6807\u8BB0\uFF08\u51B3\u7B56 12\uFF09\uFF0CNULL \u8868\u793A\u672A\u5220\u9664\uFF1B\u975E NULL \u65F6\u8BE5\u5B9E\u4F53\u8FDB\u5165\u56DE\u6536\u7AD9\uFF0C\u672C\u4F53\u4FDD\u7559\u53EF\u8FD8\u539F\n);\n\n-- relation_records\uFF1A\u901A\u7528\u5173\u7CFB\u8868\nCREATE TABLE IF NOT EXISTS relation_records (\n id TEXT PRIMARY KEY,\n source_type TEXT NOT NULL, -- \u7AEF\u70B9\u7C7B\u578B\uFF1A\u5B9E\u4F53 'character'|'setting'|'location'|'hook'|'event'\uFF0C\u5927\u7EB2\u8282\u70B9 'outline_node'\n source_id TEXT NOT NULL,\n target_type TEXT NOT NULL,\n target_id TEXT NOT NULL,\n relation_type TEXT NOT NULL,\n metadata TEXT, -- JSON \u6269\u5C55\u5143\u6570\u636E\n created_at TEXT NOT NULL, -- ISO 8601\uFF0C\u5E94\u7528\u5C42\u5199\u5165\n updated_at TEXT NOT NULL, -- ISO 8601\uFF0C\u5E94\u7528\u5C42\u5199\u5165\uFF08\u63D0\u6848\u5FEB\u7167\u6BD4\u5BF9\uFF0C\u51B3\u7B56 14\uFF1B\u8F6F\u5220/\u8FD8\u539F\u4EA6\u66F4\u65B0\uFF0C\u51B3\u7B56 12 \u4FEE\u8BA2\uFF09\n deleted_at TEXT -- \u7EA7\u8054\u8F6F\u5220\u6807\u8BB0\uFF08\u51B3\u7B56 12\uFF09\uFF1A\u4EC5\u5B9E\u4F53/\u8282\u70B9\u7EA7\u8054\u5220\u9664\u65F6\u5199\u5165\uFF1B\n -- \u624B\u52A8\u5220\u9664\u5173\u7CFB = \u7269\u7406\u5220\uFF08\u4E0D\u7F6E deleted_at\uFF0C\u4E0D\u8FDB\u5165\u56DE\u6536\u7AD9\uFF09\n);\n\n-- \u7D22\u5F15\uFF08\u51B3\u7B56 12 \u4FEE\u8BA2\u8865\uFF09\uFF1Ak \u8DF3\u904D\u5386\u4E0E\u9AD8\u9891\u5173\u7CFB\u67E5\u8BE2\uFF08\u90E8\u5206\u7D22\u5F15\uFF0C\u4EC5\u8986\u76D6\u672A\u8F6F\u5220\u884C\uFF09\nCREATE INDEX IF NOT EXISTS idx_relation_source ON relation_records(source_id) WHERE deleted_at IS NULL;\nCREATE INDEX IF NOT EXISTS idx_relation_target ON relation_records(target_id) WHERE deleted_at IS NULL;\nCREATE INDEX IF NOT EXISTS idx_relation_type ON relation_records(relation_type) WHERE deleted_at IS NULL;\n\n-- delta_records\uFF1A\u5C5E\u6027\u53D8\u66F4\u8868\nCREATE TABLE IF NOT EXISTS delta_records (\n id TEXT PRIMARY KEY,\n node_id TEXT NOT NULL, -- \u89E6\u53D1\u53D8\u66F4\u7684\u5927\u7EB2\u8282\u70B9\n target_type TEXT NOT NULL,\n target_id TEXT NOT NULL,\n changes TEXT NOT NULL, -- JSON: [{field, op, from?, to?, value?}]\n description TEXT NOT NULL, -- \u4EBA\u7C7B\u53EF\u8BFB\u63CF\u8FF0\n \"order\" INTEGER NOT NULL DEFAULT 0, -- \u540C\u4E00\u8282\u70B9\u5185\u591A\u4E2A Delta \u7684\u6392\u5E8F\uFF08\u5168\u5C40\u5355\u8C03\u9012\u589E\uFF0C\u670D\u52A1\u7AEF\u751F\u6210\uFF09\n created_at TEXT NOT NULL, -- ISO 8601\uFF0C\u5E94\u7528\u5C42\u5199\u5165\n updated_at TEXT NOT NULL, -- ISO 8601\uFF0C\u5E94\u7528\u5C42\u5199\u5165\uFF08\u63D0\u6848\u5FEB\u7167\u6BD4\u5BF9\uFF0C\u51B3\u7B56 14\uFF09\n deleted_at TEXT -- \u7EA7\u8054\u8F6F\u5220\u6807\u8BB0\uFF08\u51B3\u7B56 12\uFF09\uFF1A\u4EC5\u5B9E\u4F53/\u8282\u70B9\u7EA7\u8054\u5220\u9664\u65F6\u5199\u5165\u3002\n -- \u53EF\u89C1\u6027\u8054\u52A8\u89E6\u53D1\u8282\u70B9\u4E0E\u76EE\u6807\u5B9E\u4F53\uFF08\u51B3\u7B56 12 \u4FEE\u8BA2\uFF09\uFF1A\u4EFB\u4E00\u7AEF\u8F6F\u5220\u5373\u4E0D\u53EF\u89C1\n);\n\n-- chat_messages\uFF1A\u5BF9\u8BDD\u5386\u53F2\u8868\uFF08\u51B3\u7B56 18\uFF0C\u4E0E data.db \u540C\u5E93\uFF09\nCREATE TABLE IF NOT EXISTS chat_messages (\n id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL,\n project_id TEXT NOT NULL, -- \u4F1A\u8BDD\u6309\u9879\u76EE\u9694\u79BB\uFF08\u51B3\u7B56 18 \u4FEE\u8BA2\uFF09\n role TEXT NOT NULL CHECK(role IN ('user','assistant','tool')),\n content TEXT,\n tool_calls TEXT, -- JSON: \u52A9\u624B\u6D88\u606F\u7684\u5DE5\u5177\u8C03\u7528\u6570\u7EC4\n tool_call_id TEXT, -- tool \u6D88\u606F\u5173\u8054\u7684 assistant \u5DE5\u5177\u8C03\u7528 id\uFF08\u51B3\u7B56 18 \u4FEE\u8BA2\uFF09\n created_at TEXT NOT NULL -- ISO 8601\uFF0C\u5E94\u7528\u5C42\u5199\u5165\n);\n\nCREATE INDEX IF NOT EXISTS idx_chat_session ON chat_messages(session_id, created_at);\n";
25
- /**
26
- * 建表:执行全部 DDL(CREATE TABLE/INDEX IF NOT EXISTS),幂等,可重复调用。
14
+ * 建表:执行全部 DDL(CREATE TABLE/INDEX IF NOT EXISTS,定义于 tables.ts),幂等,可重复调用。
27
15
  * 打开数据库后由 connection.openDatabase 自动调用。
28
16
  */
29
17
  export declare function createTables(db: Database.Database): void;
30
- /** 读取 data.db schema 版本(决策 13:以 PRAGMA user_version 为准判定是否重建) */
18
+ /** 读取 data.db schema 版本(以 PRAGMA user_version 为准判定是否重建) */
31
19
  export declare function getUserVersion(db: Database.Database): number;
32
20
  /**
33
- * 写入 data.db schema 版本(决策 13)。
34
- * 首次初始化时写入 SCHEMA_VERSION,与 outline.json / project.json 顶层 schema_version 同步(决策 8)。
21
+ * 写入 data.db schema 版本。
22
+ * 首次初始化时写入 SCHEMA_VERSION,与 outline.json / project.json 顶层 schema_version 同步。
35
23
  * 入参必须是整数(user_version 为 SQLite 整数 PRAGMA),非整数直接抛错,杜绝模板拼接的注入面。
36
24
  */
37
25
  export declare function setUserVersion(db: Database.Database, version: number): void;
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAE3C;;;;;;;;;GASG;AACH,eAAO,MAAM,cAAc,IAAI,CAAC;AAEhC;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iBAAiB,4nKA6D7B,CAAC;AAEF;;;GAGG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAExD;AAED,iEAAiE;AACjE,wBAAgB,cAAc,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,MAAM,CAE5D;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAK3E"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAG3C;;;;;;;;;GASG;AACH,eAAO,MAAM,cAAc,IAAI,CAAC;AAEhC;;;GAGG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAExD;AAED,2DAA2D;AAC3D,wBAAgB,cAAc,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,MAAM,CAE5D;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAK3E"}
package/dist/schema.js CHANGED
@@ -1,106 +1,34 @@
1
- // @whispering233/ai-editor-db 建表 SQL 与 schema 版本管理(T2.1)
1
+ // @whispering233/ai-editor-db schema 版本管理与建表入口(T2.1)
2
2
  //
3
- // 单一事实来源:doc/database/schema.md——列名/类型/CHECK/索引逐字对照,勿在此处自行改动结构。
4
- // 时间约定(schema.md 第 16 行):所有时间列统一 ISO 8601 字符串、由应用层写入,
3
+ // 建表 DDL 常量已迁至 tables.ts(双份声明 + 对齐断言),本文件只保留版本工具。
4
+ // 时间约定():所有时间列统一 ISO 8601 字符串、由应用层写入,
5
5
  // 不使用 SQLite 内置 datetime('now')——回收站按 deleted_at 排序需跨 SQLite 与 outline.json 统一格式。
6
+ import { CREATE_TABLES_SQL } from "./tables.js";
6
7
  /**
7
- * data.db 当前 schema 版本(决策 13;SCHEMA_VERSION = 2 起由增量迁移驱动,E5)。
8
- * v1 → v2(决策 26 时间轴):entities 表 type CHECK 扩为 5 种(含 event)+ 新增
8
+ * data.db 当前 schema 版本(SCHEMA_VERSION = 2 起由增量迁移驱动)。
9
+ * v1 → v2( 时间轴):entities 表 type CHECK 扩为 5 种(含 event)+ 新增
9
10
  * sort_order 列——旧 v1 库经 migrations/002_event_timeline.ts 迁移,新库直接建 v2 结构。
10
- * v2 → v3(G2 时间标签点实体化,决策 26 修订):entities 表 type CHECK 扩为 6 种
11
+ * v2 → v3(G2 时间标签点实体化):entities 表 type CHECK 扩为 6 种
11
12
  * (含 timepoint)+ 旧 event.data.time_label 由 migrations/003_timepoint.ts 迁移为
12
13
  * timepoint 实体 + occurs_at 挂载关系(从 event.data 移除 time_label)。
13
- * v3 → v4(决策 31 K2 修订,2026-08):**无 DDL**——仅 entities.data JSON 数据迁移
14
+ * v3 → v4( K2 修订,2026-08):**无 DDL**——仅 entities.data JSON 数据迁移
14
15
  * (setting 的旧 rules 分类值复制到 data.tags 并移除 rules,migrations/004_setting_tags.ts)。
15
16
  */
16
- export const SCHEMA_VERSION = 5; // 决策 36:+reference(005_reference.ts 四步换表)
17
+ export const SCHEMA_VERSION = 5; // +reference(005_reference.ts 四步换表)
17
18
  /**
18
- * 四张业务表 + 索引的建表 SQL(幂等:CREATE TABLE/INDEX IF NOT EXISTS)。
19
- *
20
- * - entities 实体(character/setting/location/hook/event/timepoint),type 受 CHECK 约束,data 存 JSON,
21
- * sort_order 为时间轴线性序(决策 26 + G2 修订:event 与 timepoint 各类型内线性,
22
- * 其余类型 NULL),软删列 deleted_at(决策 12)
23
- * - relation_records 通用关系表(含 plot_edge 剧情连线、occurs_in 事件锚定,决策 26),
24
- * 3 个部分索引 WHERE deleted_at IS NULL(决策 12 修订)
25
- * - delta_records 属性变更记录("order" 列引号保留——ORDER 是 SQLite 关键字)
26
- * - chat_messages 对话历史(决策 18),含 project_id/tool_call_id,会话索引 (session_id, created_at)
27
- */
28
- export const CREATE_TABLES_SQL = `
29
- -- entities:实体表(人物/设定/地点/伏笔/时间轴事件/时间标签点)
30
- CREATE TABLE IF NOT EXISTS entities (
31
- id TEXT PRIMARY KEY,
32
- type TEXT NOT NULL CHECK(type IN ('character', 'setting', 'location', 'hook', 'event', 'timepoint', 'reference')),
33
- name TEXT NOT NULL,
34
- data TEXT NOT NULL DEFAULT '{}', -- JSON: 各类型的专属字段
35
- sort_order INTEGER, -- 时间轴线性序(决策 26 + G2 修订):event 与 timepoint 各类型内线性(各自 0..n-1),其余类型恒为 NULL
36
- created_at TEXT NOT NULL, -- ISO 8601,应用层写入
37
- updated_at TEXT NOT NULL, -- ISO 8601,应用层写入(提案快照比对,决策 14)
38
- deleted_at TEXT -- 软删标记(决策 12),NULL 表示未删除;非 NULL 时该实体进入回收站,本体保留可还原
39
- );
40
-
41
- -- relation_records:通用关系表
42
- CREATE TABLE IF NOT EXISTS relation_records (
43
- id TEXT PRIMARY KEY,
44
- source_type TEXT NOT NULL, -- 端点类型:实体 'character'|'setting'|'location'|'hook'|'event',大纲节点 'outline_node'
45
- source_id TEXT NOT NULL,
46
- target_type TEXT NOT NULL,
47
- target_id TEXT NOT NULL,
48
- relation_type TEXT NOT NULL,
49
- metadata TEXT, -- JSON 扩展元数据
50
- created_at TEXT NOT NULL, -- ISO 8601,应用层写入
51
- updated_at TEXT NOT NULL, -- ISO 8601,应用层写入(提案快照比对,决策 14;软删/还原亦更新,决策 12 修订)
52
- deleted_at TEXT -- 级联软删标记(决策 12):仅实体/节点级联删除时写入;
53
- -- 手动删除关系 = 物理删(不置 deleted_at,不进入回收站)
54
- );
55
-
56
- -- 索引(决策 12 修订补):k 跳遍历与高频关系查询(部分索引,仅覆盖未软删行)
57
- CREATE INDEX IF NOT EXISTS idx_relation_source ON relation_records(source_id) WHERE deleted_at IS NULL;
58
- CREATE INDEX IF NOT EXISTS idx_relation_target ON relation_records(target_id) WHERE deleted_at IS NULL;
59
- CREATE INDEX IF NOT EXISTS idx_relation_type ON relation_records(relation_type) WHERE deleted_at IS NULL;
60
-
61
- -- delta_records:属性变更表
62
- CREATE TABLE IF NOT EXISTS delta_records (
63
- id TEXT PRIMARY KEY,
64
- node_id TEXT NOT NULL, -- 触发变更的大纲节点
65
- target_type TEXT NOT NULL,
66
- target_id TEXT NOT NULL,
67
- changes TEXT NOT NULL, -- JSON: [{field, op, from?, to?, value?}]
68
- description TEXT NOT NULL, -- 人类可读描述
69
- "order" INTEGER NOT NULL DEFAULT 0, -- 同一节点内多个 Delta 的排序(全局单调递增,服务端生成)
70
- created_at TEXT NOT NULL, -- ISO 8601,应用层写入
71
- updated_at TEXT NOT NULL, -- ISO 8601,应用层写入(提案快照比对,决策 14)
72
- deleted_at TEXT -- 级联软删标记(决策 12):仅实体/节点级联删除时写入。
73
- -- 可见性联动触发节点与目标实体(决策 12 修订):任一端软删即不可见
74
- );
75
-
76
- -- chat_messages:对话历史表(决策 18,与 data.db 同库)
77
- CREATE TABLE IF NOT EXISTS chat_messages (
78
- id TEXT PRIMARY KEY,
79
- session_id TEXT NOT NULL,
80
- project_id TEXT NOT NULL, -- 会话按项目隔离(决策 18 修订)
81
- role TEXT NOT NULL CHECK(role IN ('user','assistant','tool')),
82
- content TEXT,
83
- tool_calls TEXT, -- JSON: 助手消息的工具调用数组
84
- tool_call_id TEXT, -- tool 消息关联的 assistant 工具调用 id(决策 18 修订)
85
- created_at TEXT NOT NULL -- ISO 8601,应用层写入
86
- );
87
-
88
- CREATE INDEX IF NOT EXISTS idx_chat_session ON chat_messages(session_id, created_at);
89
- `;
90
- /**
91
- * 建表:执行全部 DDL(CREATE TABLE/INDEX IF NOT EXISTS),幂等,可重复调用。
19
+ * 建表:执行全部 DDL(CREATE TABLE/INDEX IF NOT EXISTS,定义于 tables.ts),幂等,可重复调用。
92
20
  * 打开数据库后由 connection.openDatabase 自动调用。
93
21
  */
94
22
  export function createTables(db) {
95
23
  db.exec(CREATE_TABLES_SQL);
96
24
  }
97
- /** 读取 data.db schema 版本(决策 13:以 PRAGMA user_version 为准判定是否重建) */
25
+ /** 读取 data.db schema 版本(以 PRAGMA user_version 为准判定是否重建) */
98
26
  export function getUserVersion(db) {
99
27
  return db.pragma("user_version", { simple: true });
100
28
  }
101
29
  /**
102
- * 写入 data.db schema 版本(决策 13)。
103
- * 首次初始化时写入 SCHEMA_VERSION,与 outline.json / project.json 顶层 schema_version 同步(决策 8)。
30
+ * 写入 data.db schema 版本。
31
+ * 首次初始化时写入 SCHEMA_VERSION,与 outline.json / project.json 顶层 schema_version 同步。
104
32
  * 入参必须是整数(user_version 为 SQLite 整数 PRAGMA),非整数直接抛错,杜绝模板拼接的注入面。
105
33
  */
106
34
  export function setUserVersion(db, version) {
@@ -1 +1 @@
1
- {"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA,yDAAyD;AACzD,EAAE;AACF,gEAAgE;AAChE,sDAAsD;AACtD,kFAAkF;AAIlF;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC,CAAC,0CAA0C;AAE3E;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6DhC,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,EAAqB;IAChD,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;AAC7B,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,cAAc,CAAC,EAAqB;IAClD,OAAO,EAAE,CAAC,MAAM,CAAC,cAAc,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAW,CAAC;AAC/D,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,EAAqB,EAAE,OAAe;IACnE,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,oCAAoC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACzE,CAAC;IACD,EAAE,CAAC,MAAM,CAAC,kBAAkB,OAAO,EAAE,CAAC,CAAC;AACzC,CAAC"}
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA,qDAAqD;AACrD,EAAE;AACF,kDAAkD;AAClD,sCAAsC;AACtC,kFAAkF;AAGlF,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC,CAAC,oCAAoC;AAErE;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,EAAqB;IAChD,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;AAC7B,CAAC;AAED,2DAA2D;AAC3D,MAAM,UAAU,cAAc,CAAC,EAAqB;IAClD,OAAO,EAAE,CAAC,MAAM,CAAC,cAAc,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAW,CAAC;AAC/D,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,EAAqB,EAAE,OAAe;IACnE,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,oCAAoC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACzE,CAAC;IACD,EAAE,CAAC,MAAM,CAAC,kBAAkB,OAAO,EAAE,CAAC,CAAC;AACzC,CAAC"}
@@ -2,25 +2,25 @@
2
2
  * 当前时间 ISO 8601(UTC)。
3
3
  *
4
4
  * 仅作为「应用层写时间」的便捷辅助供调用方(server 层)使用——时间戳由应用层
5
- * 写入数据文件(schema.md 第 16 行约定),本模块的 outline/project 读写接口
5
+ * 写入数据文件(约定),本模块的 outline/project 读写接口
6
6
  * 一律不隐式生成时间,由调用方显式传入。
7
7
  */
8
8
  export declare function nowIso(): string;
9
9
  /**
10
- * JSON 文件原子写(决策 11):
10
+ * JSON 文件原子写:
11
11
  *
12
12
  * 1. 序列化为 JSON(2 空格缩进 + 尾部换行),写同目录临时文件 `.${basename}.tmp`
13
13
  * 2. `fsync` 临时文件——文件数据落盘,崩溃时不会留下半截内容
14
14
  * 3. `rename` 覆盖目标文件——POSIX 上同目录 rename 是原子的,
15
- * 任意时刻磁盘上要么是旧文件、要么是新文件,崩溃/断电不会损坏原文件
15
+ * 任意时刻磁盘上要么是旧文件、要么是新文件,崩溃/断电不会损坏原文件
16
16
  * 4. `fsync` 目录——保证 rename 的目录项也落盘(平台不支持时静默忽略)
17
17
  *
18
18
  * 失败处理取舍:
19
19
  * - rename 成功即代表临时文件已不存在(rename 即移动),无需「成功后清理」;
20
20
  * - 失败时**保留临时文件**作为排查现场(内容即失败时写入的数据),不主动清理,
21
- * 下次写入会先清理残留再以独占方式重建;
21
+ * 下次写入会先清理残留再以独占方式重建;
22
22
  * - 写前清理上次崩溃残留的临时文件(unlink,ENOENT 忽略),并用 `wx` 独占创建,
23
- * 杜绝并发进程互相覆盖临时文件。
23
+ * 杜绝并发进程互相覆盖临时文件。
24
24
  *
25
25
  * @param filePath 目标文件绝对路径(父目录必须存在)
26
26
  * @param data 任意可 JSON 序列化的数据
@@ -28,9 +28,9 @@ export declare function nowIso(): string;
28
28
  */
29
29
  export declare function writeJsonAtomic(filePath: string, data: unknown): void;
30
30
  /**
31
- * 文本文件原子写(决策 11 同款流程:临时文件 + fsync + rename,schema.md 第 186 行)。
32
- * 与 writeJsonAtomic 的区别:内容为**原始文本**(不 JSON 序列化)——AGENTS.md 等
33
- * 非 JSON 数据文件用(决策 41:项目规则文件写入走原子写,防崩溃/断电损坏)。
31
+ * 文本文件原子写( 同款流程:临时文件 + fsync + rename,)。
32
+ * 与 writeJsonAtomic 的区别:内容为**原始文本**(不 JSON 序列化)—— 等
33
+ * 非 JSON 数据文件用(项目规则文件写入走原子写,防崩溃/断电损坏)。
34
34
  *
35
35
  * @param filePath 目标文件绝对路径(父目录必须存在)
36
36
  * @param content 文本内容(原样写入,不追加换行)
@@ -1 +1 @@
1
- {"version":3,"file":"atomic.d.ts","sourceRoot":"","sources":["../../src/storage/atomic.ts"],"names":[],"mappings":"AAUA;;;;;;GAMG;AACH,wBAAgB,MAAM,IAAI,MAAM,CAE/B;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CA+BrE;AA0BD;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CA8BvE;AAED,wCAAwC;AACxC,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOlE"}
1
+ {"version":3,"file":"atomic.d.ts","sourceRoot":"","sources":["../../src/storage/atomic.ts"],"names":[],"mappings":"AASA;;;;;;GAMG;AACH,wBAAgB,MAAM,IAAI,MAAM,CAE/B;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CA+BrE;AA0BD;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CA8BvE;AAED,wCAAwC;AACxC,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOlE"}
@@ -1,36 +1,35 @@
1
1
  // @whispering233/ai-editor-db JSON 原子写核心(T2.2)
2
2
  //
3
- // 单一事实来源:doc/design/decisions.md 决策 11(outline.json 原子写)——
4
3
  // 「写临时文件 → fsync → rename 覆盖」,禁止直接 writeFileSync 覆盖原文件;
5
- // schema.md 第 186 行:project.json 同款流程。
6
- // 时间约定(schema.md 第 16 行):所有时间由应用层写入(ISO 8601),模块内不生成时间。
4
+ // :project.json 同款流程。
5
+ // 时间约定():所有时间由应用层写入(ISO 8601),模块内不生成时间。
7
6
  import { closeSync, fsyncSync, openSync, readFileSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
8
7
  import { basename, dirname, join } from "node:path";
9
8
  /**
10
9
  * 当前时间 ISO 8601(UTC)。
11
10
  *
12
11
  * 仅作为「应用层写时间」的便捷辅助供调用方(server 层)使用——时间戳由应用层
13
- * 写入数据文件(schema.md 第 16 行约定),本模块的 outline/project 读写接口
12
+ * 写入数据文件(约定),本模块的 outline/project 读写接口
14
13
  * 一律不隐式生成时间,由调用方显式传入。
15
14
  */
16
15
  export function nowIso() {
17
16
  return new Date().toISOString();
18
17
  }
19
18
  /**
20
- * JSON 文件原子写(决策 11):
19
+ * JSON 文件原子写:
21
20
  *
22
21
  * 1. 序列化为 JSON(2 空格缩进 + 尾部换行),写同目录临时文件 `.${basename}.tmp`
23
22
  * 2. `fsync` 临时文件——文件数据落盘,崩溃时不会留下半截内容
24
23
  * 3. `rename` 覆盖目标文件——POSIX 上同目录 rename 是原子的,
25
- * 任意时刻磁盘上要么是旧文件、要么是新文件,崩溃/断电不会损坏原文件
24
+ * 任意时刻磁盘上要么是旧文件、要么是新文件,崩溃/断电不会损坏原文件
26
25
  * 4. `fsync` 目录——保证 rename 的目录项也落盘(平台不支持时静默忽略)
27
26
  *
28
27
  * 失败处理取舍:
29
28
  * - rename 成功即代表临时文件已不存在(rename 即移动),无需「成功后清理」;
30
29
  * - 失败时**保留临时文件**作为排查现场(内容即失败时写入的数据),不主动清理,
31
- * 下次写入会先清理残留再以独占方式重建;
30
+ * 下次写入会先清理残留再以独占方式重建;
32
31
  * - 写前清理上次崩溃残留的临时文件(unlink,ENOENT 忽略),并用 `wx` 独占创建,
33
- * 杜绝并发进程互相覆盖临时文件。
32
+ * 杜绝并发进程互相覆盖临时文件。
34
33
  *
35
34
  * @param filePath 目标文件绝对路径(父目录必须存在)
36
35
  * @param data 任意可 JSON 序列化的数据
@@ -99,9 +98,9 @@ function fsyncDir(dir) {
99
98
  }
100
99
  }
101
100
  /**
102
- * 文本文件原子写(决策 11 同款流程:临时文件 + fsync + rename,schema.md 第 186 行)。
103
- * 与 writeJsonAtomic 的区别:内容为**原始文本**(不 JSON 序列化)——AGENTS.md 等
104
- * 非 JSON 数据文件用(决策 41:项目规则文件写入走原子写,防崩溃/断电损坏)。
101
+ * 文本文件原子写( 同款流程:临时文件 + fsync + rename,)。
102
+ * 与 writeJsonAtomic 的区别:内容为**原始文本**(不 JSON 序列化)—— 等
103
+ * 非 JSON 数据文件用(项目规则文件写入走原子写,防崩溃/断电损坏)。
105
104
  *
106
105
  * @param filePath 目标文件绝对路径(父目录必须存在)
107
106
  * @param content 文本内容(原样写入,不追加换行)
@@ -1 +1 @@
1
- {"version":3,"file":"atomic.js","sourceRoot":"","sources":["../../src/storage/atomic.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"atomic.js","sourceRoot":"","sources":["../../src/storage/atomic.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAC/C,EAAE;AACF,wDAAwD;AACxD,sBAAsB;AACtB,wCAAwC;AAExC,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC9G,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEpD;;;;;;GAMG;AACH,MAAM,UAAU,MAAM;IACpB,OAAO,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AAClC,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,eAAe,CAAC,QAAgB,EAAE,IAAa;IAC7D,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC9B,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACxD,IAAI,EAAsB,CAAC;IAC3B,IAAI,CAAC;QACN,oCAAoC;QACjC,IAAI,CAAC;YACH,UAAU,CAAC,OAAO,CAAC,CAAC;QACtB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ;gBAAE,MAAM,GAAG,CAAC;QAClE,CAAC;QACD,MAAM,OAAO,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC;QACxD,yCAAyC;QACtC,EAAE,GAAG,QAAQ,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;QACpC,aAAa,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QAC3B,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,kBAAkB;QACjC,SAAS,CAAC,EAAE,CAAC,CAAC;QACd,EAAE,GAAG,SAAS,CAAC;QACf,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,OAAO;QACtC,QAAQ,CAAC,GAAG,CAAC,CAAC;IAChB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QAChB,0CAA0C;QACvC,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;YACrB,IAAI,CAAC;gBACH,SAAS,CAAC,EAAE,CAAC,CAAC;YAChB,CAAC;YAAC,MAAM,CAAC;gBACd,gBAAgB;YACX,CAAC;QACH,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,SAAS,QAAQ,CAAC,GAAW;IAC3B,IAAI,GAAuB,CAAC;IAC5B,IAAI,CAAC;QACH,GAAG,GAAG,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACzB,SAAS,CAAC,GAAG,CAAC,CAAC;IACjB,CAAC;IAAC,MAAM,CAAC;QACV,oBAAoB;IACnB,CAAC;YAAS,CAAC;QACT,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YACtB,IAAI,CAAC;gBACH,SAAS,CAAC,GAAG,CAAC,CAAC;YACjB,CAAC;YAAC,MAAM,CAAC;gBACd,KAAK;YACA,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,eAAe,CAAC,QAAgB,EAAE,OAAe;IAC/D,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC9B,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACxD,IAAI,EAAsB,CAAC;IAC3B,IAAI,CAAC;QACN,oCAAoC;QACjC,IAAI,CAAC;YACH,UAAU,CAAC,OAAO,CAAC,CAAC;QACtB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ;gBAAE,MAAM,GAAG,CAAC;QAClE,CAAC;QACJ,yCAAyC;QACtC,EAAE,GAAG,QAAQ,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;QACpC,aAAa,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QAC3B,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,kBAAkB;QACjC,SAAS,CAAC,EAAE,CAAC,CAAC;QACd,EAAE,GAAG,SAAS,CAAC;QACf,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,OAAO;QACtC,QAAQ,CAAC,GAAG,CAAC,CAAC;IAChB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QAChB,0CAA0C;QACvC,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;YACrB,IAAI,CAAC;gBACH,SAAS,CAAC,EAAE,CAAC,CAAC;YAChB,CAAC;YAAC,MAAM,CAAC;gBACd,gBAAgB;YACX,CAAC;QACH,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED,wCAAwC;AACxC,MAAM,UAAU,kBAAkB,CAAC,QAAgB;IACjD,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACxC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC;QAClE,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC"}