letopis 1.4.1 → 2.0.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/AGENT-CHEATSHEET.md +329 -278
- package/CHANGELOG.md +558 -1
- package/README.md +606 -1037
- package/dist/acl.d.ts +78 -1
- package/dist/acl.js +264 -13
- package/dist/admin.d.ts +10 -141
- package/dist/admin.js +24 -175
- package/dist/auth.d.ts +2 -2
- package/dist/auth.js +5 -15
- package/dist/cache.d.ts +8 -1
- package/dist/cache.js +33 -10
- package/dist/chain.d.ts +19 -41
- package/dist/chain.js +169 -201
- package/dist/cli.js +51 -88
- package/dist/demo/booking.d.ts +352 -36
- package/dist/describe.d.ts +47 -0
- package/dist/describe.js +195 -0
- package/dist/errors.d.ts +59 -13
- package/dist/errors.js +190 -29
- package/dist/index.d.ts +52 -71
- package/dist/index.js +245 -130
- package/dist/internal.d.ts +12 -0
- package/dist/internal.js +5 -0
- package/dist/jsonschema.js +18 -17
- package/dist/load.d.ts +20 -12
- package/dist/load.js +225 -186
- package/dist/mcp.d.ts +5 -7
- package/dist/mcp.js +171 -215
- package/dist/messages/access.d.ts +90 -0
- package/dist/messages/access.js +113 -0
- package/dist/messages/api.d.ts +171 -0
- package/dist/messages/api.js +215 -0
- package/dist/messages/boot.d.ts +201 -0
- package/dist/messages/boot.js +256 -0
- package/dist/messages/codes.d.ts +172 -0
- package/dist/messages/codes.js +173 -0
- package/dist/messages/index.d.ts +95 -0
- package/dist/messages/index.js +118 -0
- package/dist/messages/mcp.d.ts +306 -0
- package/dist/messages/mcp.js +387 -0
- package/dist/messages/model.d.ts +233 -0
- package/dist/messages/model.js +283 -0
- package/dist/messages/query.d.ts +131 -0
- package/dist/messages/query.js +158 -0
- package/dist/messages/sql-access.d.ts +70 -0
- package/dist/messages/sql-access.js +87 -0
- package/dist/messages/sql-core.d.ts +150 -0
- package/dist/messages/sql-core.js +181 -0
- package/dist/messages/sql-time.d.ts +71 -0
- package/dist/messages/sql-time.js +88 -0
- package/dist/messages/sql-write.d.ts +246 -0
- package/dist/messages/sql-write.js +270 -0
- package/dist/messages/time.d.ts +23 -0
- package/dist/messages/time.js +29 -0
- package/dist/messages/types.d.ts +27 -0
- package/dist/messages/types.js +5 -0
- package/dist/messages/write.d.ts +405 -0
- package/dist/messages/write.js +509 -0
- package/dist/model.d.ts +73 -60
- package/dist/model.js +26 -29
- package/dist/ops.d.ts +35 -0
- package/dist/ops.js +101 -0
- package/dist/pglite.d.ts +0 -9
- package/dist/pglite.js +3 -1
- package/dist/registry.d.ts +3 -19
- package/dist/registry.js +3 -16
- package/dist/signals.d.ts +5 -9
- package/dist/signals.js +5 -9
- package/dist/sql.d.ts +13 -6
- package/dist/sql.js +176 -83
- package/dist/sync.d.ts +9 -3
- package/dist/sync.js +51 -21
- package/dist/tx.d.ts +26 -1
- package/dist/tx.js +44 -14
- package/dist/typed.d.ts +240 -45
- package/dist/types.d.ts +23 -91
- package/dist/types.js +12 -14
- package/dist/up.d.ts +53 -32
- package/dist/up.js +184 -73
- package/dist/uuid.js +5 -5
- package/dist/validate.d.ts +13 -1
- package/dist/validate.js +61 -29
- package/dist/watch.d.ts +11 -10
- package/dist/watch.js +33 -70
- package/dist/write.d.ts +9 -16
- package/dist/write.js +118 -187
- package/llms.txt +22 -25
- package/package.json +8 -11
- package/sql/10-core.sql +7 -50
- package/sql/15-errors.sql +64 -10
- package/sql/20-context.sql +7 -6
- package/sql/30-validate.sql +35 -27
- package/sql/40-class.sql +20 -114
- package/sql/50-acl.sql +8 -13
- package/sql/60-write.sql +220 -667
- package/sql/70-read.sql +20 -16
- package/sql/80-auth.sql +24 -27
- package/sql/90-time.sql +70 -859
- package/sql/95-seed.system.sql +7 -14
- package/sql/99-revision.sql +2 -1
- package/sql/README.md +32 -24
- package/sql/migrate/README.md +14 -0
- package/AGENT-CHEATSHEET.en.md +0 -485
- package/MIGRATION.md +0 -190
- package/README.en.md +0 -2859
- package/dist/import.d.ts +0 -185
- package/dist/import.js +0 -820
- package/dist/project.d.ts +0 -350
- package/dist/project.js +0 -1224
- package/sql/75-history.sql +0 -358
- package/sql/88-derived.sql +0 -1235
- package/sql/migrate/0006-changed-paths.sql +0 -3
- package/sql/migrate/0007-secret-account-fk.sql +0 -12
package/dist/internal.js
CHANGED
|
@@ -4,6 +4,11 @@
|
|
|
4
4
|
* фасад db обходит RLS, не полагаясь на то, что сообщает о себе сам вызывающий.
|
|
5
5
|
*/
|
|
6
6
|
const facades = new WeakMap();
|
|
7
|
+
/**
|
|
8
|
+
* Пределы подключения, которых нет в опциях: реестров классов db.as() — не больше asRegistries арендаторов (план 2.0,
|
|
9
|
+
* 7.4 №8). Тест меняет предел, чтобы проверить вытеснение без тысячи арендаторов.
|
|
10
|
+
*/
|
|
11
|
+
export const limits = { asRegistries: 1000 };
|
|
7
12
|
/** Запомнить фасад (зовёт makeDb для каждого фасада, который отдаёт наружу). */
|
|
8
13
|
export function registerDb(db, info) {
|
|
9
14
|
facades.set(db, info);
|
package/dist/jsonschema.js
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* группы и обратные ссылки отклоняются;
|
|
15
15
|
* - имена полей верхнего уровня, начинающиеся с `$`, отклоняются (ими загрузчик помечает служебные ключи).
|
|
16
16
|
*/
|
|
17
|
-
import {
|
|
17
|
+
import { lerr, lmsg } from './errors.js';
|
|
18
18
|
/** Подмножество, которое понимают база и валидатор. */
|
|
19
19
|
export const SUPPORTED = new Set([
|
|
20
20
|
'type', 'enum', 'const', 'minLength', 'maxLength', 'pattern', 'format', 'minimum', 'maximum',
|
|
@@ -48,7 +48,7 @@ export function translatePattern(p, where = 'pattern') {
|
|
|
48
48
|
if (c === '\\') {
|
|
49
49
|
const n = p[i + 1];
|
|
50
50
|
if (n === undefined)
|
|
51
|
-
throw bad(where, p, '
|
|
51
|
+
throw bad(where, p, 'model.pattern_trailing_backslash');
|
|
52
52
|
i++;
|
|
53
53
|
if (n === 'd')
|
|
54
54
|
out += inClass ? '0-9' : '[0-9]';
|
|
@@ -58,21 +58,21 @@ export function translatePattern(p, where = 'pattern') {
|
|
|
58
58
|
out += inClass ? SPACE_CLASS : `[${SPACE_CLASS}]`;
|
|
59
59
|
else if (n === 'D' || n === 'W' || n === 'S') {
|
|
60
60
|
if (inClass)
|
|
61
|
-
throw bad(where, p, `\\${n}
|
|
61
|
+
throw bad(where, p, 'model.pattern_escape_in_set', { escape: `\\${n}` });
|
|
62
62
|
out += n === 'D' ? '[^0-9]' : n === 'W' ? '[^A-Za-z0-9_]' : `[^${SPACE_CLASS}]`;
|
|
63
63
|
}
|
|
64
64
|
else if (n === 'b' || n === 'B')
|
|
65
|
-
throw bad(where, p, `\\${n}
|
|
65
|
+
throw bad(where, p, 'model.pattern_word_boundary', { escape: `\\${n}` });
|
|
66
66
|
else if (n === 'p' || n === 'P')
|
|
67
|
-
throw bad(where, p, '
|
|
67
|
+
throw bad(where, p, 'model.pattern_unicode_property');
|
|
68
68
|
else if (n === 'k' || /[1-9]/.test(n))
|
|
69
|
-
throw bad(where, p, '
|
|
69
|
+
throw bad(where, p, 'model.pattern_backreference');
|
|
70
70
|
else
|
|
71
71
|
out += `\\${n}`;
|
|
72
72
|
continue;
|
|
73
73
|
}
|
|
74
74
|
if (!inClass && c === '(' && p.startsWith('(?<', i) && p[i + 3] !== '=' && p[i + 3] !== '!') {
|
|
75
|
-
throw bad(where, p, '
|
|
75
|
+
throw bad(where, p, 'model.pattern_named_group');
|
|
76
76
|
}
|
|
77
77
|
if (c === '[' && !inClass)
|
|
78
78
|
inClass = true;
|
|
@@ -82,30 +82,31 @@ export function translatePattern(p, where = 'pattern') {
|
|
|
82
82
|
}
|
|
83
83
|
return out;
|
|
84
84
|
}
|
|
85
|
-
|
|
86
|
-
|
|
85
|
+
/** Шаблон несовместим с PostgreSQL (`invalid_class`): ключ каталога называет причину; where и шаблон — параметры. */
|
|
86
|
+
function bad(where, p, key, params) {
|
|
87
|
+
return lerr(key, { where, pattern: p, ...params });
|
|
87
88
|
}
|
|
88
89
|
/** Нормализует JSON Schema; бросает LetopisError('invalid_class') с названием поля и ключевого слова. */
|
|
89
90
|
export function normalizeSchema(input, opts = {}) {
|
|
90
|
-
const where = opts.where ?? '
|
|
91
|
+
const where = opts.where ?? lmsg('model.schema_default_where');
|
|
91
92
|
const defs = (input.$defs ?? input.definitions ?? {});
|
|
92
93
|
const resolve = (ref, seen) => {
|
|
93
94
|
const m = /^#\/(?:\$defs|definitions)\/(.+)$/.exec(ref);
|
|
94
95
|
if (!m)
|
|
95
|
-
throw
|
|
96
|
+
throw lerr('model.schema_ref_unsupported', { where, ref });
|
|
96
97
|
const name = decodeURIComponent(m[1].replace(/~1/g, '/').replace(/~0/g, '~'));
|
|
97
98
|
if (seen.includes(name))
|
|
98
|
-
throw
|
|
99
|
+
throw lerr('model.schema_recursive', { where, cycle: [...seen, name].join(' → ') });
|
|
99
100
|
const target = defs[name];
|
|
100
101
|
if (!target)
|
|
101
|
-
throw
|
|
102
|
+
throw lerr('model.schema_def_not_found', { where, name });
|
|
102
103
|
return node(target, [...seen, name], name);
|
|
103
104
|
};
|
|
104
105
|
const node = (s, seen, path) => {
|
|
105
106
|
if (s === true)
|
|
106
107
|
return {};
|
|
107
108
|
if (s === null || typeof s !== 'object' || Array.isArray(s)) {
|
|
108
|
-
throw
|
|
109
|
+
throw lerr('model.schema_node_not_object', { where, node: path });
|
|
109
110
|
}
|
|
110
111
|
if (typeof s.$ref === 'string') {
|
|
111
112
|
const rest = Object.keys(s).filter((k) => k !== '$ref' && !DROPPED.has(k));
|
|
@@ -127,7 +128,7 @@ export function normalizeSchema(input, opts = {}) {
|
|
|
127
128
|
out[k] = v;
|
|
128
129
|
}
|
|
129
130
|
else if (VOCABULARY.has(k)) {
|
|
130
|
-
throw
|
|
131
|
+
throw lerr('model.schema_keyword_unsupported', { where, keyword: k, node: path });
|
|
131
132
|
}
|
|
132
133
|
else {
|
|
133
134
|
meta[k] = v; // пометки .meta() Zod и прочие свободные ключи
|
|
@@ -137,7 +138,7 @@ export function normalizeSchema(input, opts = {}) {
|
|
|
137
138
|
out['x-meta'] = { ...(out['x-meta'] ?? {}), ...meta };
|
|
138
139
|
if (typeof out.format === 'string') {
|
|
139
140
|
if (!FORMATS.has(out.format))
|
|
140
|
-
throw
|
|
141
|
+
throw lerr('model.schema_format_unsupported', { where, format: out.format, node: path });
|
|
141
142
|
}
|
|
142
143
|
if (typeof out.pattern === 'string')
|
|
143
144
|
out.pattern = translatePattern(out.pattern, `${where}: ${path}`);
|
|
@@ -160,7 +161,7 @@ export function normalizeSchema(input, opts = {}) {
|
|
|
160
161
|
if (opts.topLevel && out.properties && typeof out.properties === 'object') {
|
|
161
162
|
for (const k of Object.keys(out.properties)) {
|
|
162
163
|
if (k.startsWith('$'))
|
|
163
|
-
throw
|
|
164
|
+
throw lerr('model.schema_field_dollar', { where, field: k });
|
|
164
165
|
}
|
|
165
166
|
}
|
|
166
167
|
return out;
|
package/dist/load.d.ts
CHANGED
|
@@ -17,15 +17,13 @@ export interface LoadOptions {
|
|
|
17
17
|
* переносят историю объектов из другой системы.
|
|
18
18
|
*/
|
|
19
19
|
withHistory?: boolean;
|
|
20
|
-
/** В конце перепроверить загруженные строки проверкой базы. */
|
|
21
|
-
verify?: boolean;
|
|
22
20
|
/** Класс строк без $class (CLI --class). */
|
|
23
21
|
class?: string;
|
|
24
22
|
/** Арендатор строк (по умолчанию — арендатор сессии). */
|
|
25
23
|
tenant?: string;
|
|
26
24
|
/**
|
|
27
25
|
* Исполнитель записи — строка, которую журнал сохранит в поле `agent` загруженных версий рядом с автором (по умолчанию
|
|
28
|
-
* «letopis load
|
|
26
|
+
* «letopis load»).
|
|
29
27
|
*/
|
|
30
28
|
agent?: string;
|
|
31
29
|
/**
|
|
@@ -35,12 +33,28 @@ export interface LoadOptions {
|
|
|
35
33
|
*/
|
|
36
34
|
as?: string;
|
|
37
35
|
/**
|
|
38
|
-
* Первая
|
|
36
|
+
* Первая заливка: только в пустую схему (кроме строк системных классов — иначе
|
|
39
37
|
* not_empty), одной транзакцией; на время загрузки схема закрыта, индексы и триггеры сняты и
|
|
40
38
|
* перестраиваются в конце. Без commitEvery, existing (кроме 'error') и { as }.
|
|
41
39
|
*/
|
|
42
40
|
initial?: boolean;
|
|
43
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Все опции load(): неизвестная — invalid_data с похожими (checkOptions; план 2.0, 7.10 №4). Фасад db.load() сверяет их
|
|
44
|
+
* до пула администратора (index.ts), load() — ещё раз до проверки прав.
|
|
45
|
+
*/
|
|
46
|
+
export declare const LOAD_OPTIONS: {
|
|
47
|
+
duplicates: true;
|
|
48
|
+
existing: true;
|
|
49
|
+
batch: true;
|
|
50
|
+
commitEvery: true;
|
|
51
|
+
withHistory: true;
|
|
52
|
+
class: true;
|
|
53
|
+
tenant: true;
|
|
54
|
+
agent: true;
|
|
55
|
+
as: true;
|
|
56
|
+
initial: true;
|
|
57
|
+
};
|
|
44
58
|
export interface LoadReport {
|
|
45
59
|
/** Строк во входе. */
|
|
46
60
|
rows: number;
|
|
@@ -102,8 +116,6 @@ interface Pending {
|
|
|
102
116
|
allowed: string[];
|
|
103
117
|
}>;
|
|
104
118
|
owners: Map<string, number>;
|
|
105
|
-
/** verify: true — id записанных строк. */
|
|
106
|
-
verify: string[] | null;
|
|
107
119
|
}
|
|
108
120
|
/** Состояние сессии первой заливки. */
|
|
109
121
|
export interface InitialState {
|
|
@@ -115,13 +127,9 @@ export interface InitialState {
|
|
|
115
127
|
touched: Map<string, Set<string>>;
|
|
116
128
|
freeze: boolean;
|
|
117
129
|
}
|
|
118
|
-
/** Первая заливка для нескольких
|
|
130
|
+
/** Первая заливка для нескольких загрузок: загрузки идут на соединении и в транзакции сессии. */
|
|
119
131
|
export interface InitialSession {
|
|
120
|
-
/** Соединение сессии (роль владельца): свои операторы импорта — в той же транзакции. */
|
|
121
|
-
readonly sql: Sql;
|
|
122
132
|
load(input: LoadInput, opts?: LoadOptions): Promise<LoadReport>;
|
|
123
|
-
/** id уже есть в схеме: строка системного класса или объект, записанный этой сессией. */
|
|
124
|
-
taken(id: string): boolean;
|
|
125
133
|
}
|
|
126
134
|
/**
|
|
127
135
|
* Загрузить строки (§2.6). Одна транзакция (или порции commitEvery): описания классов под
|
|
@@ -132,7 +140,7 @@ export interface InitialSession {
|
|
|
132
140
|
export declare function load(env: LoadEnv, input: LoadInput, opts?: LoadOptions): Promise<LoadReport>;
|
|
133
141
|
/**
|
|
134
142
|
* Первая заливка (план 1.1, §2.3): загрузки fn — одной транзакцией в пустую схему. Блокировка таблиц до
|
|
135
|
-
* проверки; в схеме только строки системных классов
|
|
143
|
+
* проверки; в схеме только строки системных классов (иначе not_empty); они (с seq и tx
|
|
136
144
|
* журнала) и определения ограничений, индексов и триггеров из каталога (с режимом включения tgenabled:
|
|
137
145
|
* pg_get_triggerdef его не передаёт) сохраняются в памяти; внешний ключ secret.account снимается до TRUNCATE и
|
|
138
146
|
* возвращается после первичного ключа entity; TRUNCATE; триггеры, ограничения и индексы
|