@whispering233/ai-editor-db 0.0.1
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/dist/connection.d.ts +24 -0
- package/dist/connection.d.ts.map +1 -0
- package/dist/connection.js +39 -0
- package/dist/connection.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/migrations/index.d.ts +10 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +34 -0
- package/dist/migrations/index.js.map +1 -0
- package/dist/queries/atomic.d.ts +15 -0
- package/dist/queries/atomic.d.ts.map +1 -0
- package/dist/queries/atomic.js +44 -0
- package/dist/queries/atomic.js.map +1 -0
- package/dist/queries/chat.d.ts +74 -0
- package/dist/queries/chat.d.ts.map +1 -0
- package/dist/queries/chat.js +188 -0
- package/dist/queries/chat.js.map +1 -0
- package/dist/queries/compute-state.d.ts +32 -0
- package/dist/queries/compute-state.d.ts.map +1 -0
- package/dist/queries/compute-state.js +135 -0
- package/dist/queries/compute-state.js.map +1 -0
- package/dist/queries/delta.d.ts +76 -0
- package/dist/queries/delta.d.ts.map +1 -0
- package/dist/queries/delta.js +287 -0
- package/dist/queries/delta.js.map +1 -0
- package/dist/queries/entity.d.ts +110 -0
- package/dist/queries/entity.d.ts.map +1 -0
- package/dist/queries/entity.js +285 -0
- package/dist/queries/entity.js.map +1 -0
- package/dist/queries/migration.d.ts +153 -0
- package/dist/queries/migration.d.ts.map +1 -0
- package/dist/queries/migration.js +260 -0
- package/dist/queries/migration.js.map +1 -0
- package/dist/queries/outline-ops.d.ts +126 -0
- package/dist/queries/outline-ops.d.ts.map +1 -0
- package/dist/queries/outline-ops.js +346 -0
- package/dist/queries/outline-ops.js.map +1 -0
- package/dist/queries/outline.d.ts +48 -0
- package/dist/queries/outline.d.ts.map +1 -0
- package/dist/queries/outline.js +134 -0
- package/dist/queries/outline.js.map +1 -0
- package/dist/queries/project.d.ts +21 -0
- package/dist/queries/project.d.ts.map +1 -0
- package/dist/queries/project.js +43 -0
- package/dist/queries/project.js.map +1 -0
- package/dist/queries/relation.d.ts +83 -0
- package/dist/queries/relation.d.ts.map +1 -0
- package/dist/queries/relation.js +418 -0
- package/dist/queries/relation.js.map +1 -0
- package/dist/queries/trash.d.ts +65 -0
- package/dist/queries/trash.d.ts.map +1 -0
- package/dist/queries/trash.js +121 -0
- package/dist/queries/trash.js.map +1 -0
- package/dist/schema.d.ts +29 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +102 -0
- package/dist/schema.js.map +1 -0
- package/dist/storage/atomic.d.ts +32 -0
- package/dist/storage/atomic.d.ts.map +1 -0
- package/dist/storage/atomic.js +112 -0
- package/dist/storage/atomic.js.map +1 -0
- package/dist/storage/outline.d.ts +68 -0
- package/dist/storage/outline.d.ts.map +1 -0
- package/dist/storage/outline.js +154 -0
- package/dist/storage/outline.js.map +1 -0
- package/dist/storage/project.d.ts +24 -0
- package/dist/storage/project.d.ts.map +1 -0
- package/dist/storage/project.js +55 -0
- package/dist/storage/project.js.map +1 -0
- package/package.json +36 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
// @whispering233/ai-editor-db outline.json 存储模块(T2.2)
|
|
2
|
+
//
|
|
3
|
+
// 单一事实来源:doc/database/schema.md 第 123-155 行(outline.json 契约)——
|
|
4
|
+
// 严格三层(卷→章→场景,决策 19)、节点携带 updated_at 版本戳、顶层 schema_version、
|
|
5
|
+
// 软删字段 deleted/deleted_at(决策 12)。
|
|
6
|
+
// 读接口返回 shared 存储形态 OutlineFileTree(snake_case),映射到 API 形态由
|
|
7
|
+
// @whispering233/ai-editor-shared/utils 的 mapOutlineFileToTree 负责(本模块不映射)。
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
import { SCHEMA_VERSION } from "../schema.js";
|
|
10
|
+
import { readTextFileOrNull, writeJsonAtomic } from "./atomic.js";
|
|
11
|
+
/** outline.json 文件名(决策 8:项目根目录) */
|
|
12
|
+
export const OUTLINE_FILE_NAME = "outline.json";
|
|
13
|
+
/** 最小空树:文件缺失时的返回值(见 readOutlineFile 注释) */
|
|
14
|
+
const EMPTY_TREE = {
|
|
15
|
+
id: "root",
|
|
16
|
+
type: "root",
|
|
17
|
+
schema_version: SCHEMA_VERSION,
|
|
18
|
+
children: [],
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* 读取 outline.json。
|
|
22
|
+
*
|
|
23
|
+
* 缺失文件语义(本项目首次初始化即创建,决策 8):**返回最小空树**而非抛错——
|
|
24
|
+
* 调用方(server 打开项目前的探测、初始化流程)无需为「文件还不存在」分支处理;
|
|
25
|
+
* 空树的 schema_version 取当前 SCHEMA_VERSION,与初始化流程写入的一致(决策 13)。
|
|
26
|
+
* 注意:返回的是新对象,调用方修改它不会影响后续读取。
|
|
27
|
+
*
|
|
28
|
+
* JSON 损坏 / 结构不符:**抛错**,不静默重建——静默覆盖会掩盖文件损坏并可能
|
|
29
|
+
* 丢弃用户数据,由上层决定提示用户还是重建。
|
|
30
|
+
* schema_version 数值与 SCHEMA_VERSION 不一致时**不在此校验**(决策 13:以
|
|
31
|
+
* data.db 的 user_version 为准判定重建,JSON 版本仅用于结构判断,由上层流程处理)。
|
|
32
|
+
*
|
|
33
|
+
* @param dir 项目根目录
|
|
34
|
+
* @throws 文件存在但 JSON 解析失败或顶层结构不符时抛出
|
|
35
|
+
*/
|
|
36
|
+
export function readOutlineFile(dir) {
|
|
37
|
+
const raw = readTextFileOrNull(join(dir, OUTLINE_FILE_NAME));
|
|
38
|
+
if (raw === null)
|
|
39
|
+
return { ...EMPTY_TREE, children: [] };
|
|
40
|
+
const parsed = JSON.parse(raw); // JSON 损坏抛 SyntaxError,不静默吞
|
|
41
|
+
return validateOutlineFile(parsed);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* 校验 outline.json 顶层结构(读时校验,schema.md 契约):
|
|
45
|
+
* 顶层必须是 { id:"root", type:"root", schema_version:number, children:[] }。
|
|
46
|
+
* 节点级字段(title/updated_at 等)不逐一校验——文件格式演进由 schema_version
|
|
47
|
+
* 判定(决策 13),此处只拦「完全不是大纲树」的脏数据。
|
|
48
|
+
*/
|
|
49
|
+
function validateOutlineFile(parsed) {
|
|
50
|
+
if (typeof parsed !== "object" ||
|
|
51
|
+
parsed === null ||
|
|
52
|
+
parsed.id !== "root" ||
|
|
53
|
+
parsed.type !== "root" ||
|
|
54
|
+
typeof parsed.schema_version !== "number" ||
|
|
55
|
+
!Array.isArray(parsed.children)) {
|
|
56
|
+
throw new Error("outline.json 顶层结构不符契约(需 {id:\"root\", type:\"root\", schema_version, children[]})");
|
|
57
|
+
}
|
|
58
|
+
return parsed;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* 原子写 outline.json(决策 11:临时文件 + fsync + rename,见 writeJsonAtomic)。
|
|
62
|
+
* 顶层 schema_version 随 tree.schema_version 原样写入——保持与 project.json
|
|
63
|
+
* 同步写入是调用方职责(决策 13 修订:两个文件用同一版本号常量)。
|
|
64
|
+
* 节点 updated_at 版本戳(决策 19)由调用方在变更后通过 touch/update 更新,
|
|
65
|
+
* 本函数不隐式修改树。
|
|
66
|
+
*/
|
|
67
|
+
export function writeOutlineFile(dir, tree) {
|
|
68
|
+
writeJsonAtomic(join(dir, OUTLINE_FILE_NAME), tree);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* 按 id 递归查找节点(卷/章/场景,不匹配 root 自身)。
|
|
72
|
+
* @returns 找到的节点引用(修改它即修改树);未找到返回 undefined
|
|
73
|
+
*/
|
|
74
|
+
export function findOutlineNode(tree, nodeId) {
|
|
75
|
+
return findInChildren(tree.children, nodeId);
|
|
76
|
+
}
|
|
77
|
+
/** 在节点数组内递归查找(children 可选,严格三层由 shared 类型约束) */
|
|
78
|
+
function findInChildren(nodes, nodeId) {
|
|
79
|
+
for (const node of nodes) {
|
|
80
|
+
if (node.id === nodeId)
|
|
81
|
+
return node;
|
|
82
|
+
const children = nodeChildren(node);
|
|
83
|
+
if (children !== undefined) {
|
|
84
|
+
const found = findInChildren(children, nodeId);
|
|
85
|
+
if (found !== undefined)
|
|
86
|
+
return found;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return undefined;
|
|
90
|
+
}
|
|
91
|
+
/** 取节点的 children(卷→章、章→场景;场景为叶子返回 undefined) */
|
|
92
|
+
function nodeChildren(node) {
|
|
93
|
+
return node.children;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* 更新节点版本戳(决策 19:任何字段变更——含 children 重排、软删/还原——
|
|
97
|
+
* 由服务端原子写时统一更新 updated_at,支撑决策 14 提案快照比对)。
|
|
98
|
+
* 仅更新 updated_at,不改动其他字段;改 title/summary 用 updateOutlineNode。
|
|
99
|
+
*
|
|
100
|
+
* @param updatedAt ISO 8601,由调用方(应用层)传入,模块不生成时间
|
|
101
|
+
* @throws 节点不存在时抛错——静默忽略会掩盖「改了个不存在的节点」的调用方 bug
|
|
102
|
+
*/
|
|
103
|
+
export function touchOutlineNode(tree, nodeId, updatedAt) {
|
|
104
|
+
const node = findOutlineNode(tree, nodeId);
|
|
105
|
+
if (node === undefined) {
|
|
106
|
+
throw new Error(`touchOutlineNode: 大纲节点不存在 ${nodeId}`);
|
|
107
|
+
}
|
|
108
|
+
node.updated_at = updatedAt;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* 更新节点字段并统一更新 updated_at 版本戳(决策 19)。
|
|
112
|
+
* 就地修改树(返回节点引用),调用方随后 writeOutlineFile 落盘;
|
|
113
|
+
* children 重排等无法用 patch 表达的变更请用 touchOutlineNode。
|
|
114
|
+
*
|
|
115
|
+
* @param updatedAt ISO 8601,由调用方(应用层)传入,模块不生成时间
|
|
116
|
+
* @returns 更新后的节点引用
|
|
117
|
+
* @throws 节点不存在时抛错
|
|
118
|
+
*/
|
|
119
|
+
export function updateOutlineNode(tree, nodeId, patch, updatedAt) {
|
|
120
|
+
const node = findOutlineNode(tree, nodeId);
|
|
121
|
+
if (node === undefined) {
|
|
122
|
+
throw new Error(`updateOutlineNode: 大纲节点不存在 ${nodeId}`);
|
|
123
|
+
}
|
|
124
|
+
Object.assign(node, patch);
|
|
125
|
+
node.updated_at = updatedAt;
|
|
126
|
+
return node;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* 根 → 目标节点的路径 id 列表(含 root 与目标节点自身)。
|
|
130
|
+
* 供后续卡使用:章节序现推(决策 21)、computeState 树路径排序(决策 9,
|
|
131
|
+
* data-flow.md 第 50 行 getNodePathIds)。
|
|
132
|
+
*
|
|
133
|
+
* @throws 节点不存在时抛错(路径唯一是严格三层的推论,找不到即调用方 bug)
|
|
134
|
+
*/
|
|
135
|
+
export function getOutlinePathIds(tree, nodeId) {
|
|
136
|
+
const path = [tree.id];
|
|
137
|
+
if (findPath(tree.children, nodeId, path))
|
|
138
|
+
return path;
|
|
139
|
+
throw new Error(`getOutlinePathIds: 大纲节点不存在 ${nodeId}`);
|
|
140
|
+
}
|
|
141
|
+
/** 递归找路径:命中返回 true 且 path 已包含完整路径;未命中回溯 */
|
|
142
|
+
function findPath(nodes, nodeId, path) {
|
|
143
|
+
for (const node of nodes) {
|
|
144
|
+
path.push(node.id);
|
|
145
|
+
if (node.id === nodeId)
|
|
146
|
+
return true;
|
|
147
|
+
const children = nodeChildren(node);
|
|
148
|
+
if (children !== undefined && findPath(children, nodeId, path))
|
|
149
|
+
return true;
|
|
150
|
+
path.pop();
|
|
151
|
+
}
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=outline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outline.js","sourceRoot":"","sources":["../../src/storage/outline.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ProjectFileConfig } from "@whispering233/ai-editor-shared";
|
|
2
|
+
/** project.json 文件名(决策 8:项目根目录) */
|
|
3
|
+
export declare const PROJECT_FILE_NAME = "project.json";
|
|
4
|
+
/**
|
|
5
|
+
* 读取 project.json。
|
|
6
|
+
*
|
|
7
|
+
* 缺失文件语义:**返回 null**——project.json 是项目「是否已初始化」的判定文件
|
|
8
|
+
* (决策 8:首次初始化时自动创建),null 即未初始化,由上层决定创建流程;
|
|
9
|
+
* 与 readOutlineFile(缺失返回空树)语义不同:大纲空树可直接使用,项目配置
|
|
10
|
+
* 不存在则无法合成默认值(id 需生成、name 需取目录名,属初始化逻辑)。
|
|
11
|
+
*
|
|
12
|
+
* 文件存在但 JSON 损坏:**抛错**,不静默重建(同 readOutlineFile 的取舍)。
|
|
13
|
+
*
|
|
14
|
+
* @param dir 项目根目录
|
|
15
|
+
* @returns 项目配置;文件不存在返回 null
|
|
16
|
+
* @throws 文件存在但 JSON 解析失败或顶层结构不符契约时抛出
|
|
17
|
+
*/
|
|
18
|
+
export declare function readProjectFile(dir: string): ProjectFileConfig | null;
|
|
19
|
+
/**
|
|
20
|
+
* 原子写 project.json(决策 11 同款流程:临时文件 + fsync + rename,schema.md 第 186 行)。
|
|
21
|
+
* schema_version 随 config 原样写入——与 outline.json 同步写入是调用方职责(决策 13 修订)。
|
|
22
|
+
*/
|
|
23
|
+
export declare function writeProjectFile(dir: string, config: ProjectFileConfig): void;
|
|
24
|
+
//# sourceMappingURL=project.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../../src/storage/project.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAGzE,mCAAmC;AACnC,eAAO,MAAM,iBAAiB,iBAAiB,CAAC;AAEhD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI,CAIrE;AAuBD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAE7E"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// @whispering233/ai-editor-db project.json 存储模块(T2.2)
|
|
2
|
+
//
|
|
3
|
+
// 单一事实来源:doc/database/schema.md 第 157-186 行(project.json 契约)——
|
|
4
|
+
// id/name/language/prompt/schema_version/current_position/created_at/updated_at,
|
|
5
|
+
// 文件写入走决策 11 原子写同款流程(第 186 行),DeepSeek key 绝不写入本文件(决策 17)。
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
import { readTextFileOrNull, writeJsonAtomic } from "./atomic.js";
|
|
8
|
+
/** project.json 文件名(决策 8:项目根目录) */
|
|
9
|
+
export const PROJECT_FILE_NAME = "project.json";
|
|
10
|
+
/**
|
|
11
|
+
* 读取 project.json。
|
|
12
|
+
*
|
|
13
|
+
* 缺失文件语义:**返回 null**——project.json 是项目「是否已初始化」的判定文件
|
|
14
|
+
* (决策 8:首次初始化时自动创建),null 即未初始化,由上层决定创建流程;
|
|
15
|
+
* 与 readOutlineFile(缺失返回空树)语义不同:大纲空树可直接使用,项目配置
|
|
16
|
+
* 不存在则无法合成默认值(id 需生成、name 需取目录名,属初始化逻辑)。
|
|
17
|
+
*
|
|
18
|
+
* 文件存在但 JSON 损坏:**抛错**,不静默重建(同 readOutlineFile 的取舍)。
|
|
19
|
+
*
|
|
20
|
+
* @param dir 项目根目录
|
|
21
|
+
* @returns 项目配置;文件不存在返回 null
|
|
22
|
+
* @throws 文件存在但 JSON 解析失败或顶层结构不符契约时抛出
|
|
23
|
+
*/
|
|
24
|
+
export function readProjectFile(dir) {
|
|
25
|
+
const raw = readTextFileOrNull(join(dir, PROJECT_FILE_NAME));
|
|
26
|
+
if (raw === null)
|
|
27
|
+
return null;
|
|
28
|
+
return validateProjectFile(JSON.parse(raw)); // JSON 损坏抛 SyntaxError,不静默吞
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 校验 project.json 顶层结构(读时校验,与 outline.ts 的 validateOutlineFile 对称)。
|
|
32
|
+
* 必检字段(oracle 审核补):id / name / schema_version——schema_version 是 JSON
|
|
33
|
+
* 结构演进判定依据(决策 13),id/name 是初始化即写入的必填项;language/prompt/
|
|
34
|
+
* current_position/时间戳等属可缺省或后续扩展字段,不在此拦截(避免旧文件误伤)。
|
|
35
|
+
* 节点级字段不逐一校验——文件格式演进由 schema_version 判定,此处只拦
|
|
36
|
+
* 「完全不是项目配置」的脏数据。
|
|
37
|
+
*/
|
|
38
|
+
function validateProjectFile(parsed) {
|
|
39
|
+
if (typeof parsed !== "object" ||
|
|
40
|
+
parsed === null ||
|
|
41
|
+
typeof parsed.id !== "string" ||
|
|
42
|
+
typeof parsed.name !== "string" ||
|
|
43
|
+
typeof parsed.schema_version !== "number") {
|
|
44
|
+
throw new Error("project.json 顶层结构不符契约(需 {id:string, name:string, schema_version:number, ...})");
|
|
45
|
+
}
|
|
46
|
+
return parsed;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* 原子写 project.json(决策 11 同款流程:临时文件 + fsync + rename,schema.md 第 186 行)。
|
|
50
|
+
* schema_version 随 config 原样写入——与 outline.json 同步写入是调用方职责(决策 13 修订)。
|
|
51
|
+
*/
|
|
52
|
+
export function writeProjectFile(dir, config) {
|
|
53
|
+
writeJsonAtomic(join(dir, PROJECT_FILE_NAME), config);
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=project.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project.js","sourceRoot":"","sources":["../../src/storage/project.ts"],"names":[],"mappings":"AAAA,sDAAsD;AACtD,EAAE;AACF,+DAA+D;AAC/D,iFAAiF;AACjF,2DAA2D;AAE3D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAElE,mCAAmC;AACnC,MAAM,CAAC,MAAM,iBAAiB,GAAG,cAAc,CAAC;AAEhD;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,MAAM,GAAG,GAAG,kBAAkB,CAAC,IAAI,CAAC,GAAG,EAAE,iBAAiB,CAAC,CAAC,CAAC;IAC7D,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC9B,OAAO,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,4BAA4B;AAC3E,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,mBAAmB,CAAC,MAAe;IAC1C,IACE,OAAO,MAAM,KAAK,QAAQ;QAC1B,MAAM,KAAK,IAAI;QACf,OAAQ,MAAkC,CAAC,EAAE,KAAK,QAAQ;QAC1D,OAAQ,MAAkC,CAAC,IAAI,KAAK,QAAQ;QAC5D,OAAQ,MAAkC,CAAC,cAAc,KAAK,QAAQ,EACtE,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,+EAA+E,CAAC,CAAC;IACnG,CAAC;IACD,OAAO,MAA2B,CAAC;AACrC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAW,EAAE,MAAyB;IACrE,eAAe,CAAC,IAAI,CAAC,GAAG,EAAE,iBAAiB,CAAC,EAAE,MAAM,CAAC,CAAC;AACxD,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@whispering233/ai-editor-db",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "数据库层:better-sqlite3 连接 / 建表 / 查询",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"publishConfig": {
|
|
18
|
+
"access": "public"
|
|
19
|
+
},
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsc -p tsconfig.json",
|
|
22
|
+
"dev": "tsc --watch",
|
|
23
|
+
"test": "vitest run",
|
|
24
|
+
"prepack": "node ../../scripts/prepare-package-for-publish.mjs",
|
|
25
|
+
"postpack": "node ../../scripts/restore-package-json.mjs"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@whispering233/ai-editor-shared": "0.0.1",
|
|
29
|
+
"better-sqlite3": "^13.0.0",
|
|
30
|
+
"nanoid": "^5.1.0"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
34
|
+
"typescript": "^5.8.0"
|
|
35
|
+
}
|
|
36
|
+
}
|