letopis 1.4.2 → 3.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 +516 -398
- package/CHANGELOG.md +739 -0
- package/LICENSE +75 -21
- package/LICENSE-COMMERCIAL.md +49 -0
- package/README.md +1312 -1190
- package/api-contract.json +381 -0
- package/dist/acl.d.ts +81 -1
- package/dist/acl.js +281 -13
- package/dist/admin.d.ts +11 -141
- package/dist/admin.js +28 -186
- package/dist/auth.d.ts +20 -5
- package/dist/auth.js +80 -21
- package/dist/cache.d.ts +8 -1
- package/dist/cache.js +30 -8
- package/dist/chain.d.ts +46 -48
- package/dist/chain.js +556 -223
- package/dist/cli.js +73 -96
- 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 +77 -13
- package/dist/errors.js +231 -30
- package/dist/index.d.ts +62 -74
- package/dist/index.js +312 -155
- package/dist/internal.d.ts +7 -0
- package/dist/jsonschema.js +18 -17
- package/dist/load.d.ts +29 -17
- package/dist/load.js +235 -190
- package/dist/log.d.ts +121 -0
- package/dist/log.js +633 -0
- package/dist/mcp.d.ts +5 -7
- package/dist/mcp.js +194 -225
- package/dist/messages/access.d.ts +90 -0
- package/dist/messages/access.js +113 -0
- package/dist/messages/api.d.ts +237 -0
- package/dist/messages/api.js +304 -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 +98 -0
- package/dist/messages/index.js +121 -0
- package/dist/messages/log.d.ts +229 -0
- package/dist/messages/log.js +102 -0
- package/dist/messages/mcp.d.ts +306 -0
- package/dist/messages/mcp.js +387 -0
- package/dist/messages/model.d.ts +256 -0
- package/dist/messages/model.js +314 -0
- package/dist/messages/query.d.ts +141 -0
- package/dist/messages/query.js +171 -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 +164 -0
- package/dist/messages/sql-core.js +198 -0
- package/dist/messages/sql-time.d.ts +86 -0
- package/dist/messages/sql-time.js +111 -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 +452 -0
- package/dist/messages/write.js +572 -0
- package/dist/model.d.ts +77 -60
- package/dist/model.js +43 -34
- 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 +1 -5
- package/dist/signals.js +1 -5
- package/dist/sql.d.ts +9 -1
- package/dist/sql.js +175 -107
- package/dist/sync.d.ts +10 -4
- package/dist/sync.js +90 -17
- package/dist/tx.d.ts +21 -2
- package/dist/tx.js +76 -13
- package/dist/typed.d.ts +252 -53
- package/dist/types.d.ts +93 -90
- package/dist/types.js +17 -14
- package/dist/up.d.ts +56 -35
- package/dist/up.js +229 -83
- package/dist/uuid.d.ts +8 -0
- package/dist/uuid.js +14 -6
- package/dist/validate.d.ts +13 -1
- package/dist/validate.js +82 -33
- package/dist/watch.d.ts +10 -16
- package/dist/watch.js +36 -77
- package/dist/write.d.ts +87 -17
- package/dist/write.js +441 -206
- package/llms.txt +48 -31
- package/package.json +13 -14
- package/sql/10-core.sql +7 -50
- package/sql/15-errors.sql +64 -10
- package/sql/20-context.sql +18 -9
- package/sql/30-validate.sql +79 -30
- package/sql/40-class.sql +41 -115
- package/sql/50-acl.sql +8 -13
- package/sql/60-write.sql +220 -676
- package/sql/70-read.sql +11 -13
- package/sql/80-auth.sql +109 -42
- package/sql/90-time.sql +108 -947
- package/sql/95-seed.system.sql +7 -14
- package/sql/99-revision.sql +6 -1
- package/sql/README.md +32 -24
- package/sql/migrate/0009-restore-rev.tenants-name.sql +10 -0
- package/sql/migrate/0010-impersonation-no-account.sql +5 -0
- package/sql/migrate/0011-key-lock.otp-enabled.sql +7 -0
- package/sql/migrate/README.md +18 -0
- package/AGENT-CHEATSHEET.en.md +0 -488
- package/MIGRATION.md +0 -190
- package/README.en.md +0 -2910
- package/dist/import.d.ts +0 -185
- package/dist/import.js +0 -820
- package/dist/project.d.ts +0 -359
- package/dist/project.js +0 -1258
- package/sql/75-history.sql +0 -436
- package/sql/88-derived.sql +0 -1236
- package/sql/migrate/0006-changed-paths.sql +0 -3
- package/sql/migrate/0007-secret-account-fk.sql +0 -12
package/dist/internal.d.ts
CHANGED
|
@@ -9,6 +9,13 @@ export interface DbInternals {
|
|
|
9
9
|
readonly allTenants: boolean;
|
|
10
10
|
/** Фасад явной транзакции db.begin(). */
|
|
11
11
|
readonly explicit: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Транзакция на администраторском пуле connect({ admin }) с сессией фасада (план 2.0, 7.9 №3): ею пишет syncModels.
|
|
14
|
+
* Только у корня подключения с опцией admin.
|
|
15
|
+
*/
|
|
16
|
+
readonly adminTx?: <T>(fn: (tx: import('./tx.js').Tx) => Promise<T>) => Promise<T>;
|
|
17
|
+
/** Логгер фасада (lib/src/log.ts): им пишут syncModels и инструменты MCP. */
|
|
18
|
+
readonly log?: import('./log.js').Log;
|
|
12
19
|
}
|
|
13
20
|
/**
|
|
14
21
|
* Пределы подключения, которых нет в опциях: реестров классов db.as() — не больше asRegistries арендаторов (план 2.0,
|
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
|
@@ -3,6 +3,14 @@ import { type Issue } from './errors.js';
|
|
|
3
3
|
import { Registry } from './registry.js';
|
|
4
4
|
type Sql = postgres.Sql<Record<string, unknown>>;
|
|
5
5
|
type Raw = Record<string, unknown>;
|
|
6
|
+
/** Ссылка на цель вне загрузки: строка, роль и допустимые классы конца. */
|
|
7
|
+
type ExtRef = {
|
|
8
|
+
line: number;
|
|
9
|
+
role: string;
|
|
10
|
+
allowed: string[];
|
|
11
|
+
};
|
|
12
|
+
/** Цели вне загрузки: id → первая ссылка с каждым набором допустимых классов (сверяется каждый набор). */
|
|
13
|
+
type ExtRefs = Map<string, ExtRef[]>;
|
|
6
14
|
export interface LoadOptions {
|
|
7
15
|
/** Повтор id в загрузке: отменить загрузку (по умолчанию), оставить первую или последнюю строку. */
|
|
8
16
|
duplicates?: 'error' | 'first' | 'last';
|
|
@@ -17,15 +25,13 @@ export interface LoadOptions {
|
|
|
17
25
|
* переносят историю объектов из другой системы.
|
|
18
26
|
*/
|
|
19
27
|
withHistory?: boolean;
|
|
20
|
-
/** В конце перепроверить загруженные строки проверкой базы. */
|
|
21
|
-
verify?: boolean;
|
|
22
28
|
/** Класс строк без $class (CLI --class). */
|
|
23
29
|
class?: string;
|
|
24
30
|
/** Арендатор строк (по умолчанию — арендатор сессии). */
|
|
25
31
|
tenant?: string;
|
|
26
32
|
/**
|
|
27
33
|
* Исполнитель записи — строка, которую журнал сохранит в поле `agent` загруженных версий рядом с автором (по умолчанию
|
|
28
|
-
* «letopis load
|
|
34
|
+
* «letopis load»).
|
|
29
35
|
*/
|
|
30
36
|
agent?: string;
|
|
31
37
|
/**
|
|
@@ -35,12 +41,28 @@ export interface LoadOptions {
|
|
|
35
41
|
*/
|
|
36
42
|
as?: string;
|
|
37
43
|
/**
|
|
38
|
-
* Первая
|
|
44
|
+
* Первая заливка: только в пустую схему (кроме строк системных классов — иначе
|
|
39
45
|
* not_empty), одной транзакцией; на время загрузки схема закрыта, индексы и триггеры сняты и
|
|
40
46
|
* перестраиваются в конце. Без commitEvery, existing (кроме 'error') и { as }.
|
|
41
47
|
*/
|
|
42
48
|
initial?: boolean;
|
|
43
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* Все опции load(): неизвестная — invalid_data с похожими (checkOptions; план 2.0, 7.10 №4). Фасад db.load() сверяет их
|
|
52
|
+
* до пула администратора (index.ts), load() — ещё раз до проверки прав.
|
|
53
|
+
*/
|
|
54
|
+
export declare const LOAD_OPTIONS: {
|
|
55
|
+
duplicates: true;
|
|
56
|
+
existing: true;
|
|
57
|
+
batch: true;
|
|
58
|
+
commitEvery: true;
|
|
59
|
+
withHistory: true;
|
|
60
|
+
class: true;
|
|
61
|
+
tenant: true;
|
|
62
|
+
agent: true;
|
|
63
|
+
as: true;
|
|
64
|
+
initial: true;
|
|
65
|
+
};
|
|
44
66
|
export interface LoadReport {
|
|
45
67
|
/** Строк во входе. */
|
|
46
68
|
rows: number;
|
|
@@ -96,14 +118,8 @@ export interface InitialTuning {
|
|
|
96
118
|
interface Pending {
|
|
97
119
|
reg: Registry;
|
|
98
120
|
tenant: string;
|
|
99
|
-
external:
|
|
100
|
-
line: number;
|
|
101
|
-
role: string;
|
|
102
|
-
allowed: string[];
|
|
103
|
-
}>;
|
|
121
|
+
external: ExtRefs;
|
|
104
122
|
owners: Map<string, number>;
|
|
105
|
-
/** verify: true — id записанных строк. */
|
|
106
|
-
verify: string[] | null;
|
|
107
123
|
}
|
|
108
124
|
/** Состояние сессии первой заливки. */
|
|
109
125
|
export interface InitialState {
|
|
@@ -115,13 +131,9 @@ export interface InitialState {
|
|
|
115
131
|
touched: Map<string, Set<string>>;
|
|
116
132
|
freeze: boolean;
|
|
117
133
|
}
|
|
118
|
-
/** Первая заливка для нескольких
|
|
134
|
+
/** Первая заливка для нескольких загрузок: загрузки идут на соединении и в транзакции сессии. */
|
|
119
135
|
export interface InitialSession {
|
|
120
|
-
/** Соединение сессии (роль владельца): свои операторы импорта — в той же транзакции. */
|
|
121
|
-
readonly sql: Sql;
|
|
122
136
|
load(input: LoadInput, opts?: LoadOptions): Promise<LoadReport>;
|
|
123
|
-
/** id уже есть в схеме: строка системного класса или объект, записанный этой сессией. */
|
|
124
|
-
taken(id: string): boolean;
|
|
125
137
|
}
|
|
126
138
|
/**
|
|
127
139
|
* Загрузить строки (§2.6). Одна транзакция (или порции commitEvery): описания классов под
|
|
@@ -132,7 +144,7 @@ export interface InitialSession {
|
|
|
132
144
|
export declare function load(env: LoadEnv, input: LoadInput, opts?: LoadOptions): Promise<LoadReport>;
|
|
133
145
|
/**
|
|
134
146
|
* Первая заливка (план 1.1, §2.3): загрузки fn — одной транзакцией в пустую схему. Блокировка таблиц до
|
|
135
|
-
* проверки; в схеме только строки системных классов
|
|
147
|
+
* проверки; в схеме только строки системных классов (иначе not_empty); они (с seq и tx
|
|
136
148
|
* журнала) и определения ограничений, индексов и триггеров из каталога (с режимом включения tgenabled:
|
|
137
149
|
* pg_get_triggerdef его не передаёт) сохраняются в памяти; внешний ключ secret.account снимается до TRUNCATE и
|
|
138
150
|
* возвращается после первичного ключа entity; TRUNCATE; триггеры, ограничения и индексы
|