skill-bill 0.1.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.
- package/dist/cli/cmd_read.d.ts +3 -0
- package/dist/cli/cmd_read.d.ts.map +1 -0
- package/dist/cli/cmd_read.js +530 -0
- package/dist/cli/cmd_read.js.map +1 -0
- package/dist/fetch/db.d.ts +55 -0
- package/dist/fetch/db.d.ts.map +1 -0
- package/dist/fetch/db.js +255 -0
- package/dist/fetch/db.js.map +1 -0
- package/dist/fetch/errors.d.ts +13 -0
- package/dist/fetch/errors.d.ts.map +1 -0
- package/dist/fetch/errors.js +18 -0
- package/dist/fetch/errors.js.map +1 -0
- package/dist/fetch/index.d.ts +5 -0
- package/dist/fetch/index.d.ts.map +1 -0
- package/dist/fetch/index.js +4 -0
- package/dist/fetch/index.js.map +1 -0
- package/dist/fetch/paths.d.ts +8 -0
- package/dist/fetch/paths.d.ts.map +1 -0
- package/dist/fetch/paths.js +36 -0
- package/dist/fetch/paths.js.map +1 -0
- package/dist/help/index.d.ts +2 -0
- package/dist/help/index.d.ts.map +1 -0
- package/dist/help/index.js +2 -0
- package/dist/help/index.js.map +1 -0
- package/dist/help/lookup.d.ts +11 -0
- package/dist/help/lookup.d.ts.map +1 -0
- package/dist/help/lookup.js +53 -0
- package/dist/help/lookup.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/policy/accounts.d.ts +13 -0
- package/dist/policy/accounts.d.ts.map +1 -0
- package/dist/policy/accounts.js +31 -0
- package/dist/policy/accounts.js.map +1 -0
- package/dist/policy/analysis.d.ts +12 -0
- package/dist/policy/analysis.d.ts.map +1 -0
- package/dist/policy/analysis.js +39 -0
- package/dist/policy/analysis.js.map +1 -0
- package/dist/policy/category.d.ts +31 -0
- package/dist/policy/category.d.ts.map +1 -0
- package/dist/policy/category.js +115 -0
- package/dist/policy/category.js.map +1 -0
- package/dist/policy/goals.d.ts +15 -0
- package/dist/policy/goals.d.ts.map +1 -0
- package/dist/policy/goals.js +33 -0
- package/dist/policy/goals.js.map +1 -0
- package/dist/policy/index.d.ts +13 -0
- package/dist/policy/index.d.ts.map +1 -0
- package/dist/policy/index.js +7 -0
- package/dist/policy/index.js.map +1 -0
- package/dist/policy/record.d.ts +15 -0
- package/dist/policy/record.d.ts.map +1 -0
- package/dist/policy/record.js +62 -0
- package/dist/policy/record.js.map +1 -0
- package/dist/policy/wakewords.d.ts +14 -0
- package/dist/policy/wakewords.d.ts.map +1 -0
- package/dist/policy/wakewords.js +121 -0
- package/dist/policy/wakewords.js.map +1 -0
- package/dist/render/envelope.d.ts +6 -0
- package/dist/render/envelope.d.ts.map +1 -0
- package/dist/render/envelope.js +56 -0
- package/dist/render/envelope.js.map +1 -0
- package/dist/render/errors.d.ts +5 -0
- package/dist/render/errors.d.ts.map +1 -0
- package/dist/render/errors.js +9 -0
- package/dist/render/errors.js.map +1 -0
- package/dist/render/html.d.ts +13 -0
- package/dist/render/html.d.ts.map +1 -0
- package/dist/render/html.js +60 -0
- package/dist/render/html.js.map +1 -0
- package/dist/render/index.d.ts +8 -0
- package/dist/render/index.d.ts.map +1 -0
- package/dist/render/index.js +6 -0
- package/dist/render/index.js.map +1 -0
- package/dist/render/templates.d.ts +5 -0
- package/dist/render/templates.d.ts.map +1 -0
- package/dist/render/templates.js +58 -0
- package/dist/render/templates.js.map +1 -0
- package/dist/render/views.d.ts +86 -0
- package/dist/render/views.d.ts.map +1 -0
- package/dist/render/views.js +127 -0
- package/dist/render/views.js.map +1 -0
- package/package.json +32 -0
- package/templates/account_query.html +16 -0
- package/templates/account_write.html +16 -0
- package/templates/analysis_compare.html +16 -0
- package/templates/analysis_overview.html +16 -0
- package/templates/analysis_trend.html +16 -0
- package/templates/goal_query.html +16 -0
- package/templates/goal_write.html +16 -0
- package/templates/help.html +16 -0
- package/templates/link_submit.html +16 -0
- package/templates/record_add.html +16 -0
- package/templates/record_detail.html +16 -0
- package/templates/record_range.html +16 -0
- package/templates/record_search.html +16 -0
- package/templates/record_today.html +16 -0
- package/templates/record_update.html +16 -0
- package/templates/setup_run.html +16 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { DatabaseSync } from 'node:sqlite';
|
|
2
|
+
export interface BillRow {
|
|
3
|
+
id: number;
|
|
4
|
+
category: string;
|
|
5
|
+
time: string;
|
|
6
|
+
amount: number;
|
|
7
|
+
account: string;
|
|
8
|
+
ledger: string;
|
|
9
|
+
currency: string;
|
|
10
|
+
note: string;
|
|
11
|
+
created_at: string;
|
|
12
|
+
deleted_at: string | null;
|
|
13
|
+
}
|
|
14
|
+
export interface BillDb {
|
|
15
|
+
db: DatabaseSync;
|
|
16
|
+
path: string;
|
|
17
|
+
initialized: boolean;
|
|
18
|
+
}
|
|
19
|
+
export declare function openBillDb(dbPath: string): BillDb;
|
|
20
|
+
export declare function closeBillDb(handle: BillDb): void;
|
|
21
|
+
export declare function fetchAll(h: BillDb, opts?: {
|
|
22
|
+
fromTime?: string;
|
|
23
|
+
toTime?: string;
|
|
24
|
+
category?: string;
|
|
25
|
+
account?: string;
|
|
26
|
+
ledger?: string;
|
|
27
|
+
includeDeleted?: boolean;
|
|
28
|
+
}): BillRow[];
|
|
29
|
+
export declare function listToday(h: BillDb, date: string): BillRow[];
|
|
30
|
+
export declare function listRange(h: BillDb, start: string, end: string): BillRow[];
|
|
31
|
+
export declare function getById(h: BillDb, id: number): BillRow;
|
|
32
|
+
export declare function searchKeyword(h: BillDb, keyword: string): BillRow[];
|
|
33
|
+
export declare function tagMatch(note: string, tag: string): boolean;
|
|
34
|
+
export declare function listByTag(h: BillDb, tag: string): BillRow[];
|
|
35
|
+
export declare function addBill(h: BillDb, input: {
|
|
36
|
+
category: string;
|
|
37
|
+
amount: number;
|
|
38
|
+
time: string;
|
|
39
|
+
account: string;
|
|
40
|
+
ledger: string;
|
|
41
|
+
currency: string;
|
|
42
|
+
note: string;
|
|
43
|
+
}): BillRow;
|
|
44
|
+
export declare function updateBill(h: BillDb, id: number, patch: Partial<BillRow>): BillRow;
|
|
45
|
+
export declare function undoBill(h: BillDb, id: number): BillRow;
|
|
46
|
+
export declare function restoreBill(h: BillDb, id: number): BillRow;
|
|
47
|
+
export interface BillGoals {
|
|
48
|
+
budgets: Record<string, unknown>[];
|
|
49
|
+
savings: Record<string, unknown>[];
|
|
50
|
+
accounts: Record<string, unknown>[];
|
|
51
|
+
[k: string]: unknown;
|
|
52
|
+
}
|
|
53
|
+
export declare function loadGoals(path: string): BillGoals;
|
|
54
|
+
export declare function saveGoals(path: string, data: BillGoals): void;
|
|
55
|
+
//# sourceMappingURL=db.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/fetch/db.ts"],"names":[],"mappings":"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"}
|
package/dist/fetch/db.js
ADDED
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
// 取数层·文件 DB(老家 scripts/db.py 对应):node:sqlite 单 bills 表 10 列 + goals.json 原子读写。
|
|
2
|
+
// 缺失/损坏大声失败,不返空。转账双笔 #转账不入收支由调用方过滤。
|
|
3
|
+
import { DatabaseSync } from 'node:sqlite';
|
|
4
|
+
import { readFileSync, writeFileSync, renameSync } from 'node:fs';
|
|
5
|
+
import { BillFetchError } from './errors.js';
|
|
6
|
+
const BILLS_DDL = `CREATE TABLE IF NOT EXISTS bills (
|
|
7
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
8
|
+
category TEXT NOT NULL,
|
|
9
|
+
time TEXT NOT NULL,
|
|
10
|
+
amount REAL NOT NULL,
|
|
11
|
+
account TEXT DEFAULT '',
|
|
12
|
+
ledger TEXT DEFAULT '生活',
|
|
13
|
+
currency TEXT DEFAULT '人民币',
|
|
14
|
+
note TEXT DEFAULT '',
|
|
15
|
+
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
16
|
+
deleted_at TEXT DEFAULT NULL
|
|
17
|
+
)`;
|
|
18
|
+
function tableColumns(db, table) {
|
|
19
|
+
try {
|
|
20
|
+
const rows = db.prepare(`PRAGMA table_info(${table})`).all();
|
|
21
|
+
return rows.map((r) => r.name);
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return [];
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
// 打开 DB:建 bills 表(幂等)+ 索引 + 老库 deleted_at 补列;失败 throw。
|
|
28
|
+
export function openBillDb(dbPath) {
|
|
29
|
+
if (typeof dbPath !== 'string' || dbPath.length === 0) {
|
|
30
|
+
throw new BillFetchError('BILL_DB_MISSING', '记账 DB 路径未指定');
|
|
31
|
+
}
|
|
32
|
+
let db;
|
|
33
|
+
try {
|
|
34
|
+
db = new DatabaseSync(dbPath);
|
|
35
|
+
}
|
|
36
|
+
catch (e) {
|
|
37
|
+
throw new BillFetchError('BILL_DB_UNREADABLE', '记账 DB 打不开:' + dbPath, { cause: e });
|
|
38
|
+
}
|
|
39
|
+
let initialized = false;
|
|
40
|
+
try {
|
|
41
|
+
db.exec('PRAGMA journal_mode=WAL');
|
|
42
|
+
db.exec('PRAGMA busy_timeout=5000');
|
|
43
|
+
const before = tableColumns(db, 'bills');
|
|
44
|
+
if (!before.length)
|
|
45
|
+
initialized = true;
|
|
46
|
+
db.exec(BILLS_DDL);
|
|
47
|
+
db.exec('CREATE INDEX IF NOT EXISTS idx_bills_time ON bills(time)');
|
|
48
|
+
db.exec('CREATE INDEX IF NOT EXISTS idx_bills_category ON bills(category)');
|
|
49
|
+
const cols = tableColumns(db, 'bills');
|
|
50
|
+
if (!cols.includes('deleted_at'))
|
|
51
|
+
db.exec('ALTER TABLE bills ADD COLUMN deleted_at TEXT DEFAULT NULL');
|
|
52
|
+
}
|
|
53
|
+
catch (e) {
|
|
54
|
+
try {
|
|
55
|
+
db.close();
|
|
56
|
+
}
|
|
57
|
+
catch { /* ignore */ }
|
|
58
|
+
throw new BillFetchError('BILL_DB_UNREADABLE', '记账 DB 初始化失败:' + dbPath, { cause: e });
|
|
59
|
+
}
|
|
60
|
+
return { db, path: dbPath, initialized };
|
|
61
|
+
}
|
|
62
|
+
export function closeBillDb(handle) {
|
|
63
|
+
try {
|
|
64
|
+
handle.db.close();
|
|
65
|
+
}
|
|
66
|
+
catch { /* ignore */ }
|
|
67
|
+
}
|
|
68
|
+
function toRow(r) {
|
|
69
|
+
return {
|
|
70
|
+
id: r.id, category: String(r.category ?? ''), time: String(r.time ?? ''),
|
|
71
|
+
amount: Number(r.amount ?? 0), account: String(r.account ?? ''), ledger: String(r.ledger ?? '生活'),
|
|
72
|
+
currency: String(r.currency ?? '人民币'), note: String(r.note ?? ''),
|
|
73
|
+
created_at: String(r.created_at ?? ''), deleted_at: r.deleted_at ?? null,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
function all(h, sql, params = []) {
|
|
77
|
+
try {
|
|
78
|
+
const stmt = h.db.prepare(sql);
|
|
79
|
+
const rows = stmt.all(...params);
|
|
80
|
+
return rows.map(toRow);
|
|
81
|
+
}
|
|
82
|
+
catch (e) {
|
|
83
|
+
throw new BillFetchError('BILL_DB_UNREADABLE', '记账查询失败', { cause: e });
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// 通用查询:默认排除软删(includeDeleted 仅恢复/导出场景);空结果返 [] 仅表示真实无记录。
|
|
87
|
+
export function fetchAll(h, opts = {}) {
|
|
88
|
+
const conds = ['1=1'];
|
|
89
|
+
const params = [];
|
|
90
|
+
if (!opts.includeDeleted)
|
|
91
|
+
conds.push("deleted_at IS NULL");
|
|
92
|
+
if (opts.fromTime) {
|
|
93
|
+
conds.push('time >= ?');
|
|
94
|
+
params.push(opts.fromTime);
|
|
95
|
+
}
|
|
96
|
+
if (opts.toTime) {
|
|
97
|
+
conds.push('time <= ?');
|
|
98
|
+
params.push(opts.toTime);
|
|
99
|
+
}
|
|
100
|
+
if (opts.category) {
|
|
101
|
+
conds.push('category = ? OR category LIKE ?');
|
|
102
|
+
params.push(opts.category, opts.category + '/%');
|
|
103
|
+
}
|
|
104
|
+
if (opts.account) {
|
|
105
|
+
conds.push('account = ?');
|
|
106
|
+
params.push(opts.account);
|
|
107
|
+
}
|
|
108
|
+
if (opts.ledger) {
|
|
109
|
+
conds.push('ledger = ?');
|
|
110
|
+
params.push(opts.ledger);
|
|
111
|
+
}
|
|
112
|
+
return all(h, `SELECT * FROM bills WHERE ${conds.join(' AND ')} ORDER BY time ASC, id ASC`, params);
|
|
113
|
+
}
|
|
114
|
+
export function listToday(h, date) {
|
|
115
|
+
return fetchAll(h, { fromTime: date + ' 00:00:00', toTime: date + ' 23:59:59' });
|
|
116
|
+
}
|
|
117
|
+
export function listRange(h, start, end) {
|
|
118
|
+
return fetchAll(h, { fromTime: start + ' 00:00:00', toTime: end + ' 23:59:59' });
|
|
119
|
+
}
|
|
120
|
+
export function getById(h, id) {
|
|
121
|
+
const rows = all(h, 'SELECT * FROM bills WHERE id = ? AND deleted_at IS NULL', [id]);
|
|
122
|
+
if (!rows.length)
|
|
123
|
+
throw new BillFetchError('BILL_RECORD_NOT_FOUND', '无此账单:' + id);
|
|
124
|
+
return rows[0];
|
|
125
|
+
}
|
|
126
|
+
// CJK 搜索:备注+分类子串(空白切 token,每 token 须命中);空查询 throw 不返全量。
|
|
127
|
+
export function searchKeyword(h, keyword) {
|
|
128
|
+
if (typeof keyword !== 'string' || keyword.trim().length === 0) {
|
|
129
|
+
throw new BillFetchError('BILL_BAD_QUERY', '搜索须给关键词(空查询不返全量)');
|
|
130
|
+
}
|
|
131
|
+
const tokens = keyword.trim().toLowerCase().split(/\s+/);
|
|
132
|
+
return fetchAll(h).filter((r) => {
|
|
133
|
+
const hay = (r.note + '\n' + r.category).toLowerCase();
|
|
134
|
+
return tokens.every((t) => hay.includes(t));
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
function isSep(c) { if (c === "")
|
|
138
|
+
return true; const code = c.charCodeAt(0); if (code <= 32)
|
|
139
|
+
return true; return ".,?!;:|/()[]{}、,。?!;:()「」『」".includes(c); }
|
|
140
|
+
const TAG_SEP_UNUSED2 = '[\\s,,、。??!!;;::·|/()()\[\]{}「」『』]';
|
|
141
|
+
// #tag 精确匹配(按空白/标点切 token 整词比对,#旅行计划不命中 #旅行)。
|
|
142
|
+
export function tagMatch(note, tag) {
|
|
143
|
+
if (!note || !tag)
|
|
144
|
+
return false;
|
|
145
|
+
const key = String.fromCharCode(35) + tag;
|
|
146
|
+
let at = note.indexOf(key);
|
|
147
|
+
while (at >= 0) {
|
|
148
|
+
const prev = at === 0 ? " " : note.charAt(at - 1);
|
|
149
|
+
const next = note.charAt(at + key.length);
|
|
150
|
+
if (isSep(prev) && isSep(next))
|
|
151
|
+
return true;
|
|
152
|
+
at = note.indexOf(key, at + 1);
|
|
153
|
+
}
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
export function listByTag(h, tag) {
|
|
157
|
+
if (typeof tag !== 'string' || tag.trim().length === 0) {
|
|
158
|
+
throw new BillFetchError('BILL_BAD_QUERY', '查标签须给 tag');
|
|
159
|
+
}
|
|
160
|
+
return fetchAll(h).filter((r) => tagMatch(r.note, tag.trim()));
|
|
161
|
+
}
|
|
162
|
+
// 写入:7 字段直写;返回行由读回确认;失败 throw 不谎报回执。
|
|
163
|
+
export function addBill(h, input) {
|
|
164
|
+
try {
|
|
165
|
+
const r = h.db.prepare('INSERT INTO bills (category, time, amount, account, ledger, currency, note) VALUES (?, ?, ?, ?, ?, ?, ?)').get(input.category, input.time, input.amount, input.account, input.ledger, input.currency, input.note);
|
|
166
|
+
void r;
|
|
167
|
+
const idRow = h.db.prepare('SELECT last_insert_rowid() AS id').get();
|
|
168
|
+
return getById(h, idRow.id);
|
|
169
|
+
}
|
|
170
|
+
catch (e) {
|
|
171
|
+
if (e instanceof BillFetchError)
|
|
172
|
+
throw e;
|
|
173
|
+
throw new BillFetchError('BILL_DB_UNREADABLE', '账单写盘失败', { cause: e });
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
// 修改:只合已知 7 字段;对不上 throw。
|
|
177
|
+
export function updateBill(h, id, patch) {
|
|
178
|
+
getById(h, id);
|
|
179
|
+
const allowed = ['category', 'time', 'amount', 'account', 'ledger', 'currency', 'note'];
|
|
180
|
+
const sets = [];
|
|
181
|
+
const params = [];
|
|
182
|
+
for (const k of allowed) {
|
|
183
|
+
if (patch[k] !== undefined) {
|
|
184
|
+
sets.push(`${k} = ?`);
|
|
185
|
+
params.push(patch[k]);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if (!sets.length)
|
|
189
|
+
throw new BillFetchError('BILL_BAD_QUERY', 'update 至少改一个字段');
|
|
190
|
+
try {
|
|
191
|
+
h.db.prepare(`UPDATE bills SET ${sets.join(', ')} WHERE id = ?`).run(...[...params, id]);
|
|
192
|
+
}
|
|
193
|
+
catch (e) {
|
|
194
|
+
throw new BillFetchError('BILL_DB_UNREADABLE', '账单更新失败:' + id, { cause: e });
|
|
195
|
+
}
|
|
196
|
+
return getById(h, id);
|
|
197
|
+
}
|
|
198
|
+
// 撤销=软删(deleted_at 置 now);恢复=deleted_at 置 NULL;G7 软删契约。
|
|
199
|
+
export function undoBill(h, id) {
|
|
200
|
+
getById(h, id);
|
|
201
|
+
const now = new Date().toISOString().slice(0, 19).replace('T', ' ');
|
|
202
|
+
try {
|
|
203
|
+
h.db.prepare('UPDATE bills SET deleted_at = ? WHERE id = ?').run(now, id);
|
|
204
|
+
}
|
|
205
|
+
catch (e) {
|
|
206
|
+
throw new BillFetchError('BILL_DB_UNREADABLE', '账单撤销失败:' + id, { cause: e });
|
|
207
|
+
}
|
|
208
|
+
const rows = all(h, 'SELECT * FROM bills WHERE id = ?', [id]);
|
|
209
|
+
return rows[0];
|
|
210
|
+
}
|
|
211
|
+
export function restoreBill(h, id) {
|
|
212
|
+
const rows = all(h, 'SELECT * FROM bills WHERE id = ?', [id]);
|
|
213
|
+
if (!rows.length)
|
|
214
|
+
throw new BillFetchError('BILL_RECORD_NOT_FOUND', '无此账单:' + id);
|
|
215
|
+
try {
|
|
216
|
+
h.db.prepare('UPDATE bills SET deleted_at = NULL WHERE id = ?').run(id);
|
|
217
|
+
}
|
|
218
|
+
catch (e) {
|
|
219
|
+
throw new BillFetchError('BILL_DB_UNREADABLE', '账单恢复失败:' + id, { cause: e });
|
|
220
|
+
}
|
|
221
|
+
return getById(h, id);
|
|
222
|
+
}
|
|
223
|
+
export function loadGoals(path) {
|
|
224
|
+
try {
|
|
225
|
+
const raw = readFileSync(path, 'utf8');
|
|
226
|
+
const j = JSON.parse(raw);
|
|
227
|
+
if (typeof j !== 'object' || j === null || Array.isArray(j)) {
|
|
228
|
+
throw new BillFetchError('BILL_GOALS_CORRUPT', 'goals.json 非对象:' + path);
|
|
229
|
+
}
|
|
230
|
+
for (const k of ['budgets', 'savings', 'accounts']) {
|
|
231
|
+
if (j[k] !== undefined && !Array.isArray(j[k])) {
|
|
232
|
+
throw new BillFetchError('BILL_GOALS_CORRUPT', 'goals.json 顶层键须为数组:' + k);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return { budgets: [], savings: [], accounts: [], ...j };
|
|
236
|
+
}
|
|
237
|
+
catch (e) {
|
|
238
|
+
if (e.code === 'ENOENT')
|
|
239
|
+
return { budgets: [], savings: [], accounts: [] };
|
|
240
|
+
if (e instanceof BillFetchError)
|
|
241
|
+
throw e;
|
|
242
|
+
throw new BillFetchError('BILL_GOALS_CORRUPT', 'goals.json 解析失败:' + path, { cause: e });
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
export function saveGoals(path, data) {
|
|
246
|
+
try {
|
|
247
|
+
const tmp = path + '.tmp';
|
|
248
|
+
writeFileSync(tmp, JSON.stringify(data, null, 2), 'utf8');
|
|
249
|
+
renameSync(tmp, path);
|
|
250
|
+
}
|
|
251
|
+
catch (e) {
|
|
252
|
+
throw new BillFetchError('BILL_DB_UNREADABLE', 'goals.json 写盘失败:' + path, { cause: e });
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
//# sourceMappingURL=db.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db.js","sourceRoot":"","sources":["../../src/fetch/db.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,oCAAoC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAiB7C,MAAM,SAAS,GAAG;;;;;;;;;;;EAWhB,CAAC;AAEH,SAAS,YAAY,CAAC,EAAgB,EAAE,KAAa;IACnD,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC,qBAAqB,KAAK,GAAG,CAAC,CAAC,GAAG,EAAwB,CAAC;QACnF,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACjC,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO,EAAE,CAAC;IAAC,CAAC;AACxB,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,UAAU,CAAC,MAAc;IACvC,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtD,MAAM,IAAI,cAAc,CAAC,iBAAiB,EAAE,aAAa,CAAC,CAAC;IAC7D,CAAC;IACD,IAAI,EAAgB,CAAC;IACrB,IAAI,CAAC;QAAC,EAAE,GAAG,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC;IAAC,CAAC;IACtC,OAAO,CAAC,EAAE,CAAC;QAAC,MAAM,IAAI,cAAc,CAAC,oBAAoB,EAAE,YAAY,GAAG,MAAM,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;IAAC,CAAC;IAClG,IAAI,WAAW,GAAG,KAAK,CAAC;IACxB,IAAI,CAAC;QACH,EAAE,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;QACnC,EAAE,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;QACpC,MAAM,MAAM,GAAG,YAAY,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QACzC,IAAI,CAAC,MAAM,CAAC,MAAM;YAAE,WAAW,GAAG,IAAI,CAAC;QACvC,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACnB,EAAE,CAAC,IAAI,CAAC,0DAA0D,CAAC,CAAC;QACpE,EAAE,CAAC,IAAI,CAAC,kEAAkE,CAAC,CAAC;QAC5E,MAAM,IAAI,GAAG,YAAY,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QACvC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC;YAAE,EAAE,CAAC,IAAI,CAAC,2DAA2D,CAAC,CAAC;IACzG,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,CAAC;YAAC,EAAE,CAAC,KAAK,EAAE,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;QAC1C,MAAM,IAAI,cAAc,CAAC,oBAAoB,EAAE,cAAc,GAAG,MAAM,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;IACxF,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,MAAc;IACxC,IAAI,CAAC;QAAC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;AACnD,CAAC;AAED,SAAS,KAAK,CAAC,CAA0B;IACvC,OAAO;QACL,EAAE,EAAE,CAAC,CAAC,EAAY,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;QAClF,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,IAAI,IAAI,CAAC;QACjG,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,IAAI,KAAK,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;QACjE,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,UAAU,IAAI,EAAE,CAAC,EAAE,UAAU,EAAG,CAAC,CAAC,UAA4B,IAAI,IAAI;KAC5F,CAAC;AACJ,CAAC;AAED,SAAS,GAAG,CAAC,CAAS,EAAE,GAAW,EAAE,SAAoB,EAAE;IACzD,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAqE,CAAC;QACnG,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,GAAI,MAAkB,CAAC,CAAC;QAC9C,OAAO,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACzB,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,IAAI,cAAc,CAAC,oBAAoB,EAAE,QAAQ,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;IACzE,CAAC;AACH,CAAC;AAED,yDAAyD;AACzD,MAAM,UAAU,QAAQ,CAAC,CAAS,EAAE,OAA+H,EAAE;IACnK,MAAM,KAAK,GAAG,CAAC,KAAK,CAAC,CAAC;IACtB,MAAM,MAAM,GAAc,EAAE,CAAC;IAC7B,IAAI,CAAC,IAAI,CAAC,cAAc;QAAE,KAAK,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;IAC3D,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAAC,CAAC;IAC3E,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAAC,CAAC;IACvE,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAAC,KAAK,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;QAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;IAAC,CAAC;IACvH,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAAC,CAAC;IAC3E,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAAC,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAAC,CAAC;IACxE,OAAO,GAAG,CAAC,CAAC,EAAE,6BAA6B,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,4BAA4B,EAAE,MAAM,CAAC,CAAC;AACtG,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,CAAS,EAAE,IAAY;IAC/C,OAAO,QAAQ,CAAC,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,GAAG,WAAW,EAAE,MAAM,EAAE,IAAI,GAAG,WAAW,EAAE,CAAC,CAAC;AACnF,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,CAAS,EAAE,KAAa,EAAE,GAAW;IAC7D,OAAO,QAAQ,CAAC,CAAC,EAAE,EAAE,QAAQ,EAAE,KAAK,GAAG,WAAW,EAAE,MAAM,EAAE,GAAG,GAAG,WAAW,EAAE,CAAC,CAAC;AACnF,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,CAAS,EAAE,EAAU;IAC3C,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,EAAE,yDAAyD,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IACrF,IAAI,CAAC,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,cAAc,CAAC,uBAAuB,EAAE,OAAO,GAAG,EAAE,CAAC,CAAC;IAClF,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC;AACjB,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,aAAa,CAAC,CAAS,EAAE,OAAe;IACtD,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/D,MAAM,IAAI,cAAc,CAAC,gBAAgB,EAAE,kBAAkB,CAAC,CAAC;IACjE,CAAC;IACD,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACzD,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;QAC9B,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;QACvD,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,KAAK,CAAC,CAAS,IAAa,IAAI,CAAC,KAAK,EAAE;IAAE,OAAO,IAAI,CAAC,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,IAAI,EAAE;IAAE,OAAO,IAAI,CAAC,CAAC,OAAO,6BAA6B,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9K,MAAM,eAAe,GAAG,oCAAoC,CAAC;AAE7D,8CAA8C;AAC9C,MAAM,UAAU,QAAQ,CAAC,IAAY,EAAE,GAAW;IAChD,IAAI,CAAC,IAAI,IAAI,CAAC,GAAG;QAAE,OAAO,KAAK,CAAC;IAChC,MAAM,GAAG,GAAG,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC;IAC1C,IAAI,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC3B,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC;QACf,MAAM,IAAI,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;QAClD,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC;QAC1C,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QAC5C,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC;IACjC,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,CAAS,EAAE,GAAW;IAC9C,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvD,MAAM,IAAI,cAAc,CAAC,gBAAgB,EAAE,WAAW,CAAC,CAAC;IAC1D,CAAC;IACD,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;AACjE,CAAC;AAED,qCAAqC;AACrC,MAAM,UAAU,OAAO,CAAC,CAAS,EAAE,KAA0H;IAC3J,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,0GAA0G,CAAC,CAAC,GAAG,CACpI,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,CAC5D,CAAC;QACxC,KAAK,CAAC,CAAC;QACP,MAAM,KAAK,GAAG,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,kCAAkC,CAAC,CAAC,GAAG,EAAoB,CAAC;QACvF,OAAO,OAAO,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,CAAC,YAAY,cAAc;YAAE,MAAM,CAAC,CAAC;QACzC,MAAM,IAAI,cAAc,CAAC,oBAAoB,EAAE,QAAQ,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;IACzE,CAAC;AACH,CAAC;AAED,0BAA0B;AAC1B,MAAM,UAAU,UAAU,CAAC,CAAS,EAAE,EAAU,EAAE,KAAuB;IACvE,OAAO,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACf,MAAM,OAAO,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,CAAU,CAAC;IACjG,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,MAAM,MAAM,GAAc,EAAE,CAAC;IAC7B,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,IAAK,KAAiC,CAAC,CAAC,CAAC,KAAK,SAAS,EAAE,CAAC;YAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAAC,MAAM,CAAC,IAAI,CAAE,KAAiC,CAAC,CAAC,CAAC,CAAC,CAAC;QAAC,CAAC;IACzI,CAAC;IACD,IAAI,CAAC,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,cAAc,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,CAAC;IAC/E,IAAI,CAAC;QACH,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,oBAAoB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,GAAG,CAAC,GAAI,CAAC,GAAG,MAAM,EAAE,EAAE,CAAa,CAAC,CAAC;IACxG,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,IAAI,cAAc,CAAC,oBAAoB,EAAE,SAAS,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;IAC/E,CAAC;IACD,OAAO,OAAO,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACxB,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,QAAQ,CAAC,CAAS,EAAE,EAAU;IAC5C,OAAO,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACf,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACpE,IAAI,CAAC;QAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,8CAA8C,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IAAC,CAAC;IAClF,OAAO,CAAC,EAAE,CAAC;QAAC,MAAM,IAAI,cAAc,CAAC,oBAAoB,EAAE,SAAS,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;IAAC,CAAC;IAC3F,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,EAAE,kCAAkC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAC9D,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,CAAS,EAAE,EAAU;IAC/C,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,EAAE,kCAAkC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAC9D,IAAI,CAAC,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,cAAc,CAAC,uBAAuB,EAAE,OAAO,GAAG,EAAE,CAAC,CAAC;IAClF,IAAI,CAAC;QAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,iDAAiD,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAAC,CAAC;IAChF,OAAO,CAAC,EAAE,CAAC;QAAC,MAAM,IAAI,cAAc,CAAC,oBAAoB,EAAE,SAAS,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;IAAC,CAAC;IAC3F,OAAO,OAAO,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACxB,CAAC;AAKD,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACvC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAA4B,CAAC;QACrD,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5D,MAAM,IAAI,cAAc,CAAC,oBAAoB,EAAE,iBAAiB,GAAG,IAAI,CAAC,CAAC;QAC3E,CAAC;QACD,KAAK,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,EAAE,UAAU,CAAC,EAAE,CAAC;YACnD,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC/C,MAAM,IAAI,cAAc,CAAC,oBAAoB,EAAE,qBAAqB,GAAG,CAAC,CAAC,CAAC;YAC5E,CAAC;QACH,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,GAAG,CAAC,EAAe,CAAC;IACvE,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAK,CAAuB,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;QAClG,IAAI,CAAC,YAAY,cAAc;YAAE,MAAM,CAAC,CAAC;QACzC,MAAM,IAAI,cAAc,CAAC,oBAAoB,EAAE,kBAAkB,GAAG,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;IAC1F,CAAC;AACH,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,IAAe;IACrD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,MAAM,CAAC;QAC1B,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;QAC1D,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACxB,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,IAAI,cAAc,CAAC,oBAAoB,EAAE,kBAAkB,GAAG,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;IAC1F,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare class BillFetchError extends Error {
|
|
2
|
+
readonly code: 'BILL_DB_MISSING' | 'BILL_DB_UNREADABLE' | 'BILL_RECORD_CORRUPT' | 'BILL_RECORD_NOT_FOUND' | 'BILL_BAD_QUERY' | 'BILL_EMPTY_RANGE' | 'BILL_GOALS_CORRUPT' | 'BILL_ACCOUNT_CORRUPT';
|
|
3
|
+
constructor(code: BillFetchError['code'], message: string, options?: {
|
|
4
|
+
cause?: unknown;
|
|
5
|
+
});
|
|
6
|
+
}
|
|
7
|
+
export declare class BillPolicyError extends Error {
|
|
8
|
+
readonly code: 'POLICY_NO_MATCH' | 'POLICY_MISSING_SLOT' | 'POLICY_BAD_CATEGORY' | 'POLICY_BAD_AMOUNT' | 'POLICY_BAD_TIME' | 'POLICY_BAD_INPUT' | 'POLICY_CONFLICT';
|
|
9
|
+
constructor(code: BillPolicyError['code'], message: string, options?: {
|
|
10
|
+
cause?: unknown;
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/fetch/errors.ts"],"names":[],"mappings":"AACA,qBAAa,cAAe,SAAQ,KAAK;IACvC,QAAQ,CAAC,IAAI,EACT,iBAAiB,GAAG,oBAAoB,GAAG,qBAAqB,GAChE,uBAAuB,GAAG,gBAAgB,GAAG,kBAAkB,GAC/D,oBAAoB,GAAG,sBAAsB,CAAC;gBACtC,IAAI,EAAE,cAAc,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAKzF;AAED,qBAAa,eAAgB,SAAQ,KAAK;IACxC,QAAQ,CAAC,IAAI,EACT,iBAAiB,GAAG,qBAAqB,GAAG,qBAAqB,GACjE,mBAAmB,GAAG,iBAAiB,GAAG,kBAAkB,GAAG,iBAAiB,CAAC;gBACzE,IAAI,EAAE,eAAe,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAK1F"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// 取数/口径错误:坏输入与缺失一律 throw,永不返空数组冒充正常。
|
|
2
|
+
export class BillFetchError extends Error {
|
|
3
|
+
code;
|
|
4
|
+
constructor(code, message, options) {
|
|
5
|
+
super(message, options);
|
|
6
|
+
this.name = 'BillFetchError';
|
|
7
|
+
this.code = code;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export class BillPolicyError extends Error {
|
|
11
|
+
code;
|
|
12
|
+
constructor(code, message, options) {
|
|
13
|
+
super(message, options);
|
|
14
|
+
this.name = 'BillPolicyError';
|
|
15
|
+
this.code = code;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/fetch/errors.ts"],"names":[],"mappings":"AAAA,qCAAqC;AACrC,MAAM,OAAO,cAAe,SAAQ,KAAK;IAC9B,IAAI,CAGqC;IAClD,YAAY,IAA4B,EAAE,OAAe,EAAE,OAA6B;QACtF,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;QAC7B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAED,MAAM,OAAO,eAAgB,SAAQ,KAAK;IAC/B,IAAI,CAEwE;IACrF,YAAY,IAA6B,EAAE,OAAe,EAAE,OAA6B;QACvF,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;QAC9B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { BillFetchError, BillPolicyError } from './errors.js';
|
|
2
|
+
export { DB_FILENAME, GOALS_FILENAME, resolveDbDir, resolveDbPath, resolveGoalsPath, assertWritablePath } from './paths.js';
|
|
3
|
+
export { openBillDb, closeBillDb, fetchAll, listToday, listRange, getById, searchKeyword, tagMatch, listByTag, addBill, updateBill, undoBill, restoreBill, loadGoals, saveGoals } from './db.js';
|
|
4
|
+
export type { BillRow, BillDb, BillGoals } from './db.js';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/fetch/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,YAAY,EAAE,aAAa,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAC5H,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,WAAW,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACjM,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { BillFetchError, BillPolicyError } from './errors.js';
|
|
2
|
+
export { DB_FILENAME, GOALS_FILENAME, resolveDbDir, resolveDbPath, resolveGoalsPath, assertWritablePath } from './paths.js';
|
|
3
|
+
export { openBillDb, closeBillDb, fetchAll, listToday, listRange, getById, searchKeyword, tagMatch, listByTag, addBill, updateBill, undoBill, restoreBill, loadGoals, saveGoals } from './db.js';
|
|
4
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/fetch/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,YAAY,EAAE,aAAa,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAC5H,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,WAAW,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const DB_FILENAME = "biscuit_accountant.db";
|
|
2
|
+
export declare const GOALS_FILENAME = "goals.json";
|
|
3
|
+
export declare function resolveDbDir(): string;
|
|
4
|
+
export declare function resolveDbPath(filename?: string, dir?: string): string;
|
|
5
|
+
export declare function resolveGoalsPath(dir?: string): string;
|
|
6
|
+
/** 测试隔离守卫:非 tmp 路径写库须 BILL_FORCE_PROD=1(卡路里哨兵语义的饼干版)。 */
|
|
7
|
+
export declare function assertWritablePath(dbPath: string): void;
|
|
8
|
+
//# sourceMappingURL=paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/fetch/paths.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,WAAW,0BAA0B,CAAC;AACnD,eAAO,MAAM,cAAc,eAAe,CAAC;AAE3C,wBAAgB,YAAY,IAAI,MAAM,CASrC;AAED,wBAAgB,aAAa,CAAC,QAAQ,SAAc,EAAE,GAAG,SAAiB,GAAG,MAAM,CAGlF;AAED,wBAAgB,gBAAgB,CAAC,GAAG,SAAiB,GAAG,MAAM,CAG7D;AAED,yDAAyD;AACzD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAYvD"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// DB 路径解析与隔离守卫:SKILLS_DB_PATH 必设,无默认值(铁律缺失阻断)。
|
|
2
|
+
// 老家 db.py _fallback_db_dir(D:/.db)TS 线有意不继承:拒绝隐式写生产。
|
|
3
|
+
import { mkdirSync } from 'node:fs';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
5
|
+
import { join, resolve } from 'node:path';
|
|
6
|
+
export const DB_FILENAME = 'biscuit_accountant.db';
|
|
7
|
+
export const GOALS_FILENAME = 'goals.json';
|
|
8
|
+
export function resolveDbDir() {
|
|
9
|
+
const env = process.env.SKILLS_DB_PATH;
|
|
10
|
+
if (!env) {
|
|
11
|
+
throw new Error('[skill-bill] SKILLS_DB_PATH 未设置:拒绝隐式落盘。' +
|
|
12
|
+
'生产请设置 SKILLS_DB_PATH;测试请传显式 tmp 路径。');
|
|
13
|
+
}
|
|
14
|
+
return env;
|
|
15
|
+
}
|
|
16
|
+
export function resolveDbPath(filename = DB_FILENAME, dir = resolveDbDir()) {
|
|
17
|
+
mkdirSync(dir, { recursive: true });
|
|
18
|
+
return join(dir, filename);
|
|
19
|
+
}
|
|
20
|
+
export function resolveGoalsPath(dir = resolveDbDir()) {
|
|
21
|
+
mkdirSync(dir, { recursive: true });
|
|
22
|
+
return join(dir, GOALS_FILENAME);
|
|
23
|
+
}
|
|
24
|
+
/** 测试隔离守卫:非 tmp 路径写库须 BILL_FORCE_PROD=1(卡路里哨兵语义的饼干版)。 */
|
|
25
|
+
export function assertWritablePath(dbPath) {
|
|
26
|
+
const forceProd = process.env.BILL_FORCE_PROD === '1';
|
|
27
|
+
const underTmp = resolve(dbPath).startsWith(resolve(tmpdir()));
|
|
28
|
+
if (!underTmp && !forceProd) {
|
|
29
|
+
throw new Error('[skill-bill] 拒绝写入非 tmp 路径 ' + dbPath + ':测试隔离守卫。' +
|
|
30
|
+
'如确需生产写,请设置 BILL_FORCE_PROD=1(opt-in 可见)。');
|
|
31
|
+
}
|
|
32
|
+
if (!underTmp && forceProd) {
|
|
33
|
+
console.error('[skill-bill] BILL_FORCE_PROD=1: 写入 ' + dbPath);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/fetch/paths.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAC/C,sDAAsD;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE1C,MAAM,CAAC,MAAM,WAAW,GAAG,uBAAuB,CAAC;AACnD,MAAM,CAAC,MAAM,cAAc,GAAG,YAAY,CAAC;AAE3C,MAAM,UAAU,YAAY;IAC1B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IACvC,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CACb,yCAAyC;YACvC,qCAAqC,CACxC,CAAC;IACJ,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,QAAQ,GAAG,WAAW,EAAE,GAAG,GAAG,YAAY,EAAE;IACxE,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACpC,OAAO,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,GAAG,GAAG,YAAY,EAAE;IACnD,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACpC,OAAO,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;AACnC,CAAC;AAED,yDAAyD;AACzD,MAAM,UAAU,kBAAkB,CAAC,MAAc;IAC/C,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,KAAK,GAAG,CAAC;IACtD,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAC/D,IAAI,CAAC,QAAQ,IAAI,CAAC,SAAS,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CACb,4BAA4B,GAAG,MAAM,GAAG,UAAU;YAChD,0CAA0C,CAC7C,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,QAAQ,IAAI,SAAS,EAAE,CAAC;QAC3B,OAAO,CAAC,KAAK,CAAC,qCAAqC,GAAG,MAAM,CAAC,CAAC;IAChE,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/help/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,KAAK,OAAO,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/help/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,UAAU,EAAgB,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type BillKey } from '../policy/index.js';
|
|
2
|
+
export interface HelpHit {
|
|
3
|
+
phrase: string;
|
|
4
|
+
key: BillKey;
|
|
5
|
+
shape: string;
|
|
6
|
+
cli: string;
|
|
7
|
+
desc: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function buildHelpLookup(): HelpHit[];
|
|
10
|
+
export declare function lookupWake(hits: HelpHit[], word: string): HelpHit[];
|
|
11
|
+
//# sourceMappingURL=lookup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lookup.d.ts","sourceRoot":"","sources":["../../src/help/lookup.ts"],"names":[],"mappings":"AACA,OAAO,EAAc,KAAK,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAG9D,MAAM,WAAW,OAAO;IAAG,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;CAAE;AAqCpG,wBAAgB,eAAe,IAAI,OAAO,EAAE,CAQ3C;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,EAAE,CAEnE"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// HELP 速查:WAKE_TABLE 唯一上游;短语→key/cli/一句话。构建期注入 SKILL.md(scripts/build-help.mjs)。
|
|
2
|
+
import { WAKE_TABLE } from '../policy/index.js';
|
|
3
|
+
import { BILL_KEY_SHAPES } from '../render/index.js';
|
|
4
|
+
function exampleParams(key, e) {
|
|
5
|
+
const p = { ...(e.preset || {}) };
|
|
6
|
+
// B2:record.add 示例须可直跑——补最小槽位 category/amount/note(kind preset 仅路由提示,校验忽略未知键)。
|
|
7
|
+
if (key === 'bill.record.add') {
|
|
8
|
+
if (p.category === undefined)
|
|
9
|
+
p.category = '餐饮';
|
|
10
|
+
if (p.amount === undefined)
|
|
11
|
+
p.amount = -35;
|
|
12
|
+
if (p.note === undefined)
|
|
13
|
+
p.note = '午饭';
|
|
14
|
+
}
|
|
15
|
+
for (const n of e.needs || []) {
|
|
16
|
+
if (p[n] === undefined)
|
|
17
|
+
p[n] = n === 'id' ? 1 : n === 'date' ? '2026-09-06' : n === 'start' || n === 'end' ? '2026-09-01' : n === 'month' ? '2026-09' : n === 'amount' ? 35 : n === 'q' ? '午饭' : n === 'tag' ? '旅行' : n === 'category' ? '餐饮' : n === 'account' ? '支付宝' : n === 'ledger' ? '生活' : n === 'name' ? '招行卡' : n === 'from' ? '支付宝' : n === 'to' ? '招行卡' : n === 'file' ? 'bills.csv' : '<值>';
|
|
18
|
+
}
|
|
19
|
+
const keys = Object.keys(p);
|
|
20
|
+
return keys.length ? ' --params \'' + JSON.stringify(p) + '\'' : '';
|
|
21
|
+
}
|
|
22
|
+
const DESCS = {
|
|
23
|
+
'bill.record.add': '记一笔(须 category+amount,note 可选;含借贷/分期/退款/报销,拍账单图片识别以外置为准)',
|
|
24
|
+
'bill.record.update': '改/撤销(软删)/恢复(须 id)',
|
|
25
|
+
'bill.record.today': '查今天/昨天/某天/最近/查账单',
|
|
26
|
+
'bill.record.range': '查周/月/区间/分类/账户/账本',
|
|
27
|
+
'bill.record.search': '搜备注/查标签/查欠款/查待报销/查分期',
|
|
28
|
+
'bill.record.detail': '看单条详情(须 id)',
|
|
29
|
+
'bill.analysis.overview': '看月度/年度/总览/周报/分类/账户/账本/结构/统计',
|
|
30
|
+
'bill.analysis.compare': '看对比/双区间/同比/分类对比',
|
|
31
|
+
'bill.analysis.trend': '看趋势/大额/高频/分布/活跃/洞察/异常/借贷/报销/分期/退款',
|
|
32
|
+
'bill.goal.write': '设定预算/目标(覆盖须 --force)',
|
|
33
|
+
'bill.goal.query': '看预算执行/目标进度',
|
|
34
|
+
'bill.account.write': '新增/改账户/转账(双笔 #转账)',
|
|
35
|
+
'bill.account.query': '看账户汇总(余额实算)',
|
|
36
|
+
'bill.link.submit': '买东西/吃饭联动(主操作复用记账,跨技能仅复制 prompt)',
|
|
37
|
+
'bill.setup.run': '初始化/备份/恢复/导入(列映射 dry-run 先行)',
|
|
38
|
+
'bill.help.lookup': '能力速查 HELP 现找',
|
|
39
|
+
};
|
|
40
|
+
// 全量速查表(77 短语:72 功能 + 4 HELP + 1 补齐)。
|
|
41
|
+
export function buildHelpLookup() {
|
|
42
|
+
return WAKE_TABLE.map((e) => ({
|
|
43
|
+
phrase: e.phrase,
|
|
44
|
+
key: e.key,
|
|
45
|
+
shape: BILL_KEY_SHAPES[e.key] || '??',
|
|
46
|
+
cli: 'bill-cmd-read ' + e.key + exampleParams(e.key, e),
|
|
47
|
+
desc: DESCS[e.key] || '',
|
|
48
|
+
}));
|
|
49
|
+
}
|
|
50
|
+
export function lookupWake(hits, word) {
|
|
51
|
+
return hits.filter((h) => word.includes(h.phrase));
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=lookup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lookup.js","sourceRoot":"","sources":["../../src/help/lookup.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,OAAO,EAAE,UAAU,EAAgB,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAIrD,SAAS,aAAa,CAAC,GAAY,EAAE,CAAyD;IAC5F,MAAM,CAAC,GAA4B,EAAE,GAAG,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE,CAAC;IAC3D,+EAA+E;IAC/E,IAAI,GAAG,KAAK,iBAAiB,EAAE,CAAC;QAC9B,IAAI,CAAC,CAAC,QAAQ,KAAK,SAAS;YAAE,CAAC,CAAC,QAAQ,GAAG,IAAI,CAAC;QAChD,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS;YAAE,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3C,IAAI,CAAC,CAAC,IAAI,KAAK,SAAS;YAAE,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC;IAC1C,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,EAAE,CAAC;QAC9B,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,SAAS;YAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,KAAK,OAAO,IAAI,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC;IAC1Y,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC5B,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,cAAc,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;AACtE,CAAC;AAED,MAAM,KAAK,GAA2B;IACpC,iBAAiB,EAAE,0DAA0D;IAC7E,oBAAoB,EAAE,mBAAmB;IACzC,mBAAmB,EAAE,kBAAkB;IACvC,mBAAmB,EAAE,kBAAkB;IACvC,oBAAoB,EAAE,sBAAsB;IAC5C,oBAAoB,EAAE,aAAa;IACnC,wBAAwB,EAAE,6BAA6B;IACvD,uBAAuB,EAAE,iBAAiB;IAC1C,qBAAqB,EAAE,mCAAmC;IAC1D,iBAAiB,EAAE,sBAAsB;IACzC,iBAAiB,EAAE,YAAY;IAC/B,oBAAoB,EAAE,mBAAmB;IACzC,oBAAoB,EAAE,aAAa;IACnC,kBAAkB,EAAE,iCAAiC;IACrD,gBAAgB,EAAE,8BAA8B;IAChD,kBAAkB,EAAE,cAAc;CACnC,CAAC;AAEF,sCAAsC;AACtC,MAAM,UAAU,eAAe;IAC7B,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC5B,MAAM,EAAE,CAAC,CAAC,MAAM;QAChB,GAAG,EAAE,CAAC,CAAC,GAAG;QACV,KAAK,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,IAAI;QACrC,GAAG,EAAE,gBAAgB,GAAG,CAAC,CAAC,GAAG,GAAG,aAAa,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;QACvD,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE;KACzB,CAAC,CAAC,CAAC;AACN,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAe,EAAE,IAAY;IACtD,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AACrD,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type AccountOp = 'add' | 'update' | 'transfer' | 'summary';
|
|
2
|
+
export declare const TRANSFER_OUT_CATEGORY = "\u8F6C\u8D26/\u8F6C\u51FA";
|
|
3
|
+
export declare const TRANSFER_IN_CATEGORY = "\u8F6C\u8D26/\u8F6C\u5165";
|
|
4
|
+
export declare const TRANSFER_LEDGER = "\u8F6C\u8D26";
|
|
5
|
+
export declare function parseAccountOp(params: Record<string, unknown>): AccountOp;
|
|
6
|
+
export declare function needName(params: Record<string, unknown>, field?: string): string;
|
|
7
|
+
export declare function validateTransfer(params: Record<string, unknown>): {
|
|
8
|
+
amount: number;
|
|
9
|
+
from: string;
|
|
10
|
+
to: string;
|
|
11
|
+
time: string | null;
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=accounts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"accounts.d.ts","sourceRoot":"","sources":["../../src/policy/accounts.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAC;AAElE,eAAO,MAAM,qBAAqB,8BAAU,CAAC;AAC7C,eAAO,MAAM,oBAAoB,8BAAU,CAAC;AAC5C,eAAO,MAAM,eAAe,iBAAO,CAAC;AAEpC,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAIzE;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,SAAS,GAAG,MAAM,CAIhF;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAUnI"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// 口径层·账户 params 校验(老家 account/cli.py 对应:add/update/transfer/summary)。
|
|
2
|
+
// 转账 = 两笔 #转账(转出支出 + 转入收入),分类 转账/转出 | 转账/转入,账本 转账,不入收支统计由 views 过滤。
|
|
3
|
+
import { BillPolicyError } from '../fetch/errors.js';
|
|
4
|
+
export const TRANSFER_OUT_CATEGORY = '转账/转出';
|
|
5
|
+
export const TRANSFER_IN_CATEGORY = '转账/转入';
|
|
6
|
+
export const TRANSFER_LEDGER = '转账';
|
|
7
|
+
export function parseAccountOp(params) {
|
|
8
|
+
const op = params.op === undefined ? 'summary' : params.op;
|
|
9
|
+
if (op === 'add' || op === 'update' || op === 'transfer' || op === 'summary')
|
|
10
|
+
return op;
|
|
11
|
+
throw new BillPolicyError('POLICY_BAD_INPUT', 'op 非法(期望 add/update/transfer/summary):' + JSON.stringify(op));
|
|
12
|
+
}
|
|
13
|
+
export function needName(params, field = 'name') {
|
|
14
|
+
const v = params[field];
|
|
15
|
+
if (typeof v !== 'string' || !v.trim())
|
|
16
|
+
throw new BillPolicyError('POLICY_MISSING_SLOT', '缺槽位 ' + field);
|
|
17
|
+
return v.trim();
|
|
18
|
+
}
|
|
19
|
+
export function validateTransfer(params) {
|
|
20
|
+
const n = typeof params.amount === 'string' ? Number(params.amount.trim()) : params.amount;
|
|
21
|
+
if (typeof n !== 'number' || !Number.isFinite(n) || n <= 0) {
|
|
22
|
+
throw new BillPolicyError('POLICY_BAD_INPUT', 'transfer amount 须为正数:' + JSON.stringify(params.amount));
|
|
23
|
+
}
|
|
24
|
+
const from = needName(params, 'from');
|
|
25
|
+
const to = needName(params, 'to');
|
|
26
|
+
if (from === to)
|
|
27
|
+
throw new BillPolicyError('POLICY_BAD_INPUT', 'transfer from/to 不得相同');
|
|
28
|
+
const time = params.time === undefined || params.time === null || params.time === '' ? null : String(params.time);
|
|
29
|
+
return { amount: Math.round(n * 100) / 100, from, to, time };
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=accounts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"accounts.js","sourceRoot":"","sources":["../../src/policy/accounts.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,oEAAoE;AACpE,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAIrD,MAAM,CAAC,MAAM,qBAAqB,GAAG,OAAO,CAAC;AAC7C,MAAM,CAAC,MAAM,oBAAoB,GAAG,OAAO,CAAC;AAC5C,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,CAAC;AAEpC,MAAM,UAAU,cAAc,CAAC,MAA+B;IAC5D,MAAM,EAAE,GAAG,MAAM,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;IAC3D,IAAI,EAAE,KAAK,KAAK,IAAI,EAAE,KAAK,QAAQ,IAAI,EAAE,KAAK,UAAU,IAAI,EAAE,KAAK,SAAS;QAAE,OAAO,EAAE,CAAC;IACxF,MAAM,IAAI,eAAe,CAAC,kBAAkB,EAAE,wCAAwC,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC;AAC/G,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,MAA+B,EAAE,KAAK,GAAG,MAAM;IACtE,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IACxB,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE;QAAE,MAAM,IAAI,eAAe,CAAC,qBAAqB,EAAE,MAAM,GAAG,KAAK,CAAC,CAAC;IACzG,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,MAA+B;IAC9D,MAAM,CAAC,GAAG,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAE,MAAM,CAAC,MAAiB,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC;IACvG,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3D,MAAM,IAAI,eAAe,CAAC,kBAAkB,EAAE,uBAAuB,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;IACzG,CAAC;IACD,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,MAAM,EAAE,GAAG,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAClC,IAAI,IAAI,KAAK,EAAE;QAAE,MAAM,IAAI,eAAe,CAAC,kBAAkB,EAAE,uBAAuB,CAAC,CAAC;IACxF,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,KAAK,SAAS,IAAI,MAAM,CAAC,IAAI,KAAK,IAAI,IAAI,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAClH,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;AAC/D,CAAC"}
|