letopis 0.20.3 → 1.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.en.md +368 -0
- package/AGENT-CHEATSHEET.md +354 -0
- package/CHANGELOG.md +348 -0
- package/MIGRATION.md +190 -0
- package/README.en.md +1937 -0
- package/README.md +1493 -3466
- package/dist/acl.d.ts +26 -50
- package/dist/acl.js +22 -267
- package/dist/admin.d.ts +138 -0
- package/dist/admin.js +170 -0
- package/dist/auth.d.ts +120 -73
- package/dist/auth.js +121 -306
- package/dist/cache.d.ts +73 -0
- package/dist/cache.js +148 -0
- package/dist/chain.d.ts +124 -191
- package/dist/chain.js +369 -551
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +164 -0
- package/dist/demo/booking.d.ts +289 -0
- package/dist/demo/booking.js +159 -0
- package/dist/errors.d.ts +29 -0
- package/dist/errors.js +70 -0
- package/dist/import.d.ts +179 -0
- package/dist/import.js +792 -0
- package/dist/index.d.ts +172 -26
- package/dist/index.js +304 -178
- package/dist/jsonschema.d.ts +22 -0
- package/dist/jsonschema.js +167 -0
- package/dist/load.d.ts +76 -0
- package/dist/load.js +884 -0
- package/dist/model.d.ts +166 -0
- package/dist/model.js +224 -0
- package/dist/ops.d.ts +7 -6
- package/dist/ops.js +7 -51
- package/dist/pglite.d.ts +22 -0
- package/dist/pglite.js +45 -0
- package/dist/registry.d.ts +57 -0
- package/dist/registry.js +82 -0
- package/dist/sql.d.ts +59 -142
- package/dist/sql.js +568 -654
- package/dist/sync.d.ts +31 -0
- package/dist/sync.js +108 -0
- package/dist/tx.d.ts +129 -8
- package/dist/tx.js +300 -73
- package/dist/typed.d.ts +97 -0
- package/dist/typed.js +1 -0
- package/dist/types.d.ts +71 -250
- package/dist/types.js +27 -108
- package/dist/up.d.ts +140 -47
- package/dist/up.js +339 -267
- package/dist/uuid.d.ts +21 -6
- package/dist/uuid.js +48 -64
- package/dist/validate.d.ts +24 -0
- package/dist/validate.js +251 -0
- package/dist/watch.d.ts +62 -0
- package/dist/watch.js +168 -0
- package/dist/write.d.ts +117 -74
- package/dist/write.js +658 -720
- package/llms.txt +26 -0
- package/package.json +49 -19
- package/sql/10-core.sql +136 -0
- package/sql/15-errors.sql +60 -0
- package/sql/20-context.sql +153 -0
- package/sql/30-validate.sql +423 -0
- package/sql/40-class.sql +259 -0
- package/sql/50-acl.sql +539 -0
- package/sql/60-write.sql +1369 -0
- package/sql/70-read.sql +245 -0
- package/sql/80-auth.sql +827 -0
- package/sql/90-time.sql +957 -0
- package/sql/95-seed.system.sql +178 -0
- package/sql/99-revision.sql +3 -0
- package/sql/README.md +56 -0
- package/sql/seed.booking.sql +39 -112
- package/dist/schema.d.ts +0 -15
- package/dist/schema.js +0 -351
- package/dist/sessions.d.ts +0 -32
- package/dist/sessions.js +0 -114
- package/dist/tables.d.ts +0 -105
- package/dist/tables.js +0 -248
- package/docker/Dockerfile +0 -40
- package/docker/start.sh +0 -18
- package/scripts/check-docs.mjs +0 -375
- package/scripts/gen-api-contract.mjs +0 -226
- package/scripts/gen-types.mjs +0 -350
- package/scripts/release-notes.mjs +0 -76
- package/scripts/schema-sync.mjs +0 -185
- package/sql/ddl.sql +0 -600
- package/sql/seed.auth.sql +0 -73
package/dist/types.d.ts
CHANGED
|
@@ -1,290 +1,111 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* letopis
|
|
2
|
+
* Общие типы letopis 1.0. Файл наполняется по этапам плана (reports/PLAN-LETOPIS-1.0.md).
|
|
3
3
|
*/
|
|
4
|
-
/**
|
|
5
|
-
export
|
|
4
|
+
/** Ревизия движка в базе: штамп в lib/sql/99-revision.sql должен совпадать (этап 1). */
|
|
5
|
+
export declare const DDL_REVISION = 5;
|
|
6
|
+
/** Методы цепочки: терминалы, модификаторы, глаголы записи (этап 4), охранники снесённого API. */
|
|
7
|
+
export declare const CHAIN_METHODS: readonly ["then", "entity", "paths", "rows", "first", "ids", "count", "limit", "offset", "sort", "asOf", "withDeleted", "deep", "exact", "sum", "avg", "min", "max", "countBy", "after", "versions", "create", "update", "upsert", "set", "unset", "add", "remove", "delete", "anonymize", "reclass", "restore", "purge", "alias", "tags", "owner", "forUpdate", "cache", "rekey", "run", "execute", "account"];
|
|
8
|
+
/** Свойства корня db (и транзакции db.begin()). */
|
|
9
|
+
export declare const DB_METHODS: readonly ["as", "begin", "commit", "rollback", "lock", "batch", "watch", "close", "registry", "sql", "load", "verify", "maintain", "reset", "describe", "auth", "acl", "idOf", "refresh", "transaction", "flushSignals", "schema", "token", "tenant", "reloadSchema", "accounts", "credentials", "resources", "rules", "compact", "trimHistory", "rekeyClass", "cache"];
|
|
10
|
+
/** Свойства батча db.batch(name). */
|
|
11
|
+
export declare const BATCH_METHODS: readonly ["discard", "size"];
|
|
12
|
+
/**
|
|
13
|
+
* Зарезервированные имена: Proxy разбирает их раньше классов, поэтому класс с таким именем
|
|
14
|
+
* недостижим как шаг. Установщик подставляет список в функцию базы reserved_names(), которая
|
|
15
|
+
* отклоняет связи с такими именами; совпадение со switch Proxy проверяет check-docs.
|
|
16
|
+
*/
|
|
17
|
+
export declare const RESERVED_CLASS_NAMES: readonly string[];
|
|
18
|
+
/** Строка ответа: текущая версия (или версия журнала для asOf, versions, withDeleted). */
|
|
19
|
+
export interface Row<D = Record<string, unknown>, L = Record<string, string | string[]>> {
|
|
6
20
|
id: string;
|
|
7
21
|
class: string;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
account: string;
|
|
22
|
+
/** Номер версии — для update(patch, { rev }) (этап 4). */
|
|
23
|
+
rev: number;
|
|
24
|
+
tenant: string;
|
|
12
25
|
owner: string;
|
|
13
|
-
|
|
14
|
-
|
|
26
|
+
links: L;
|
|
27
|
+
data: D;
|
|
28
|
+
tags: string[];
|
|
29
|
+
/** Время версии (ISO, UTC, микросекунды). */
|
|
30
|
+
at: string;
|
|
31
|
+
author: string;
|
|
32
|
+
agent?: string;
|
|
33
|
+
/** Вид операции версии: create, update, delete, reclass, … */
|
|
34
|
+
op: string;
|
|
35
|
+
reason?: string;
|
|
36
|
+
/** Связь со старым или новым id при reclass и rekey. */
|
|
37
|
+
moved?: string;
|
|
38
|
+
/** Надгробие: удалённая сущность (withDeleted) или версия удаления (versions). */
|
|
15
39
|
$deleted?: true;
|
|
16
|
-
/** Глубина узла при
|
|
40
|
+
/** Глубина узла при deep() (1 — прямой потомок); в превью удаления — уровень каскада (0 — цель). */
|
|
17
41
|
$depth?: number;
|
|
42
|
+
/** Что сделал upsert (этап 4). */
|
|
43
|
+
$upsert?: 'created' | 'updated' | 'unchanged';
|
|
44
|
+
/** Превью удаления (delete() без confirm): удалится, снимется конец или помешает (restrict). */
|
|
45
|
+
$action?: 'delete' | 'unset' | 'restrict';
|
|
46
|
+
/** purge(): число версий в журнале (превью) или стёртых. */
|
|
47
|
+
$versions?: number;
|
|
48
|
+
/** purge({ confirm: true }): история стёрта. */
|
|
49
|
+
$purged?: true;
|
|
18
50
|
}
|
|
19
|
-
/**
|
|
51
|
+
/** Путь paths(): узел на каждый шаг цепочки. */
|
|
20
52
|
export type Path = Record<string, Row>;
|
|
21
|
-
/**
|
|
22
|
-
* Конец связи класса (Schema.links v2). В БД элемент text[]: JSON-объект
|
|
23
|
-
* `{"class":"Org","cardinality":1}` / `{"classes":["Service","Complex"],"cardinality":1}`
|
|
24
|
-
* (союз ролей); legacy-строка 'Org' — сахар для {classes:['Org']} (старые схемы).
|
|
25
|
-
*/
|
|
26
|
-
export interface LinkEnd {
|
|
27
|
-
/** Допустимые классы конца; ровно один из них присутствует в Entity.links. */
|
|
28
|
-
classes: string[];
|
|
29
|
-
/** Конец может отсутствовать. Default false. */
|
|
30
|
-
optional?: boolean;
|
|
31
|
-
/** ЗАРЕЗЕРВИРОВАНО (не имплементировано): 0 — безлимит, N — точное число. Default 1. */
|
|
32
|
-
cardinality?: number;
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Генерация id класса — из attributes.id:
|
|
36
|
-
* "uuid" | {type:'uuid'} → v4 (random, дефолт);
|
|
37
|
-
* {type:'uuid', generate: 7} → v7 (время в старших битах);
|
|
38
|
-
* {type:'uuid', generate: 5, from: ['Slot','Staff']} → v5: детерминированный id из значений
|
|
39
|
-
* from — имена ОБЯЗАТЕЛЬНЫХ концов Schema.links (класс или полное имя союза
|
|
40
|
-
* 'Service|Complex') и/или скалярных полей data.
|
|
41
|
-
*/
|
|
42
|
-
export interface IdGen {
|
|
43
|
-
version: 4 | 5 | 7;
|
|
44
|
-
/** Только v5: источники имени (порядок значим). */
|
|
45
|
-
from?: string[];
|
|
46
|
-
}
|
|
47
|
-
/** Класс из таблицы Schema. */
|
|
48
|
-
export interface ClassDef {
|
|
49
|
-
id: string;
|
|
50
|
-
alias: string;
|
|
51
|
-
category: 'HUB' | 'LINK';
|
|
52
|
-
ancestor: string | null;
|
|
53
|
-
ancestors: string[];
|
|
54
|
-
/** Все потомки (транзитивно) — считает триггер schema_lineage. */
|
|
55
|
-
descendants: string[];
|
|
56
|
-
/** Поля data с НАСЛЕДОВАНИЕМ по ancestor-цепочке (потомок поверх предка). */
|
|
57
|
-
attributes: Record<string, unknown>;
|
|
58
|
-
links: LinkEnd[];
|
|
59
|
-
/**
|
|
60
|
-
* true — хотя бы один конец объявлен объектом (схема v2): строгая валидация
|
|
61
|
-
* (жадный матчинг по порядку, союзы, optional, лишние связи — ошибка).
|
|
62
|
-
* false — все концы legacy-строками: старое поведение ('Entity' = полиморф, лишние молчат).
|
|
63
|
-
*/
|
|
64
|
-
strictEnds: boolean;
|
|
65
|
-
meta: Record<string, unknown>;
|
|
66
|
-
abstract: boolean;
|
|
67
|
-
order: number;
|
|
68
|
-
/** Как генерить id новой сущности (attributes.id). */
|
|
69
|
-
idGen: IdGen;
|
|
70
|
-
/** Скомпилированный fastest-validator: true | ошибки. */
|
|
71
|
-
check: (data: Record<string, unknown>) => true | {
|
|
72
|
-
field: string;
|
|
73
|
-
message?: string;
|
|
74
|
-
}[];
|
|
75
|
-
/** Тип каждого поля attributes — для SQL-кастов в фильтрах. */
|
|
76
|
-
fieldTypes: Map<string, FieldType>;
|
|
77
|
-
}
|
|
78
|
-
export type FieldType = {
|
|
79
|
-
kind: 'number';
|
|
80
|
-
} | {
|
|
81
|
-
kind: 'date';
|
|
82
|
-
} | {
|
|
83
|
-
kind: 'boolean';
|
|
84
|
-
} | {
|
|
85
|
-
kind: 'string';
|
|
86
|
-
} | {
|
|
87
|
-
kind: 'array';
|
|
88
|
-
} | {
|
|
89
|
-
kind: 'record';
|
|
90
|
-
value: FieldType;
|
|
91
|
-
} | {
|
|
92
|
-
kind: 'object';
|
|
93
|
-
props: Map<string, FieldType>;
|
|
94
|
-
} | {
|
|
95
|
-
kind: 'any';
|
|
96
|
-
};
|
|
97
|
-
/** Метка операторов фильтра (Symbol — не конфликтует с данными). */
|
|
53
|
+
/** Метка операторов фильтра (символ не пересекается с данными). */
|
|
98
54
|
export declare const OP: unique symbol;
|
|
99
55
|
export interface Op {
|
|
100
56
|
[OP]: string;
|
|
101
57
|
args: unknown[];
|
|
102
58
|
}
|
|
103
59
|
export type Scalar = string | number | boolean | null;
|
|
104
|
-
/** Значение фильтра по полю: скаляр (
|
|
60
|
+
/** Значение фильтра по полю: скаляр (равенство), список, оператор или вложенный объект. */
|
|
105
61
|
export type FieldFilter = Scalar | Scalar[] | Op | {
|
|
106
|
-
[key: string]:
|
|
62
|
+
[key: string]: FieldFilter | undefined;
|
|
63
|
+
} | {
|
|
64
|
+
id: string;
|
|
107
65
|
};
|
|
108
66
|
/**
|
|
109
|
-
* Фильтр шага:
|
|
110
|
-
*
|
|
111
|
-
* - объект: { поле data: значение (eq) | оператор | вложенный record-путь } + ключ id.
|
|
112
|
-
* Колонки tags/account/owner фильтруются модификаторами цепочки .tags()/.account()/.owner().
|
|
67
|
+
* Фильтр шага: id или список id; строка ответа (берётся её id); or(…); объект — поля data
|
|
68
|
+
* любой глубины, роли концов (`{ Org: id }`) и `id`.
|
|
113
69
|
*/
|
|
114
70
|
export type Filter = string | string[] | Op | {
|
|
71
|
+
id: string;
|
|
72
|
+
class: string;
|
|
73
|
+
} | {
|
|
115
74
|
[field: string]: FieldFilter | undefined;
|
|
116
75
|
};
|
|
117
|
-
/** Курсор keyset-пагинации: значение поля сортировки
|
|
76
|
+
/** Курсор keyset-пагинации: значение поля сортировки и id последней строки страницы. */
|
|
118
77
|
export interface Cursor {
|
|
119
|
-
v: string | number;
|
|
78
|
+
v: string | number | boolean | null;
|
|
120
79
|
id: string;
|
|
121
80
|
}
|
|
122
|
-
/**
|
|
123
|
-
* Операция записи, привязанная к шагу цепочки:
|
|
124
|
-
* .create() / .update() / .delete() / .anonymize().
|
|
125
|
-
* Терминал исполняет план (все операции + финальное чтение) одной транзакцией.
|
|
126
|
-
*/
|
|
127
|
-
export interface PlanOp {
|
|
128
|
-
kind: 'create' | 'update' | 'delete' | 'anonymize' | 'purge';
|
|
129
|
-
/** create/update: данные новой версии (deep-merge листьев). */
|
|
130
|
-
data?: Record<string, unknown>;
|
|
131
|
-
/** anonymize: string-поля под '[erased]'. */
|
|
132
|
-
fields?: string[];
|
|
133
|
-
/** delete/purge: true — выполнить; без confirm — превью (вернуть кандидатов/замыкание, БД не трогать). */
|
|
134
|
-
confirm?: boolean;
|
|
135
|
-
/** Снапшот модификаторов на момент вызова операции (limit/sort для поиска целей). */
|
|
136
|
-
mods: ChainMods;
|
|
137
|
-
}
|
|
138
|
-
/** Модификаторы выборки цепочки: .limit() / .offset() / .sort() / .asOf() / .after(). */
|
|
81
|
+
/** Модификаторы выборки цепочки. */
|
|
139
82
|
export interface ChainMods {
|
|
140
83
|
limit?: number;
|
|
141
84
|
offset?: number;
|
|
142
|
-
/** '
|
|
85
|
+
/** 'at' | 'rev' | 'id' | 'data.<путь>'. */
|
|
143
86
|
order?: string;
|
|
144
87
|
desc?: boolean;
|
|
145
|
-
/**
|
|
88
|
+
/** Срез «как было на момент T» (ISO). */
|
|
146
89
|
asOf?: string;
|
|
147
|
-
/** Keyset-пагинация от курсора (требует sort). */
|
|
148
90
|
after?: Cursor;
|
|
149
|
-
/**
|
|
150
|
-
aggFn?: 'sum' | 'avg' | 'min' | 'max' | 'countBy';
|
|
151
|
-
aggField?: string;
|
|
152
|
-
/** .withDeleted(): последний шаг включает удалённые (tombstone). Снимает ТОЛЬКО фильтр deleted; enforceAccount/enforceAcl действуют. */
|
|
91
|
+
/** Последний шаг включает удалённые. */
|
|
153
92
|
withDeleted?: boolean;
|
|
93
|
+
/** Чтение с блокировкой строк последнего шага (только в db.begin()). */
|
|
94
|
+
forUpdate?: boolean;
|
|
95
|
+
/** versions({ follow: true }): история и через смену id (reclass, rekey) по колонке moved. */
|
|
96
|
+
follow?: boolean;
|
|
97
|
+
/** Кэш результатов (§2.12): .cache() — срок по умолчанию, .cache({ ttl }) — свой, секунды. */
|
|
98
|
+
cache?: {
|
|
99
|
+
ttl?: number;
|
|
100
|
+
};
|
|
154
101
|
}
|
|
155
|
-
|
|
156
|
-
id: string;
|
|
157
|
-
categories: string[];
|
|
158
|
-
data: Record<string, unknown>;
|
|
159
|
-
meta: Record<string, unknown>;
|
|
160
|
-
avatar: string;
|
|
161
|
-
enabled: boolean;
|
|
162
|
-
created: string;
|
|
163
|
-
updated: string;
|
|
164
|
-
}
|
|
165
|
-
export interface Credential {
|
|
166
|
-
id: string;
|
|
167
|
-
account: string;
|
|
168
|
-
category: string;
|
|
169
|
-
identifier: string;
|
|
170
|
-
meta: Record<string, unknown>;
|
|
171
|
-
confirmed: boolean;
|
|
172
|
-
created: string;
|
|
173
|
-
updated: string;
|
|
174
|
-
deleted: string | null;
|
|
175
|
-
}
|
|
176
|
-
export interface Resource {
|
|
177
|
-
alias: string;
|
|
178
|
-
category: string;
|
|
179
|
-
pattern: Record<string, unknown> | null;
|
|
180
|
-
meta: Record<string, unknown> | null;
|
|
181
|
-
}
|
|
182
|
-
export interface Rule {
|
|
183
|
-
account: string;
|
|
184
|
-
resource: string;
|
|
185
|
-
permission: string;
|
|
186
|
-
weight: number | null;
|
|
187
|
-
meta: Record<string, unknown> | null;
|
|
188
|
-
enabled: boolean;
|
|
189
|
-
}
|
|
190
|
-
/** Операция над данными = категория Resource: 'READ' | 'WRITE' | 'DELETE'. */
|
|
191
|
-
export type AclOp = 'READ' | 'WRITE' | 'DELETE';
|
|
192
|
-
/** Решение ACL: победившее правило (max weight; при равенстве deny; нет правил — deny). */
|
|
193
|
-
export interface AclDecision {
|
|
194
|
-
allow: boolean;
|
|
195
|
-
/** Победившее правило (нет — deny «no matching rule»). */
|
|
196
|
-
rule?: Rule;
|
|
197
|
-
/**
|
|
198
|
-
* Остаточный шаблон строки Entity из pattern победившего allow-ресурса
|
|
199
|
-
* (ключи-колонки без class, "$account" уже подставлен) — вливается в SQL
|
|
200
|
-
* до сортировки/лимита. Отсутствует = класс целиком.
|
|
201
|
-
*/
|
|
202
|
-
filter?: Record<string, unknown>;
|
|
203
|
-
/** Из meta deny-правила: код и сообщение для ответа клиенту. */
|
|
204
|
-
code?: number;
|
|
205
|
-
message?: string;
|
|
206
|
-
}
|
|
207
|
-
/** Событие хука onQuery: один SQL-запрос цепочки (чтение или запись). */
|
|
102
|
+
/** Событие хука onQuery: один запрос цепочки. */
|
|
208
103
|
export interface QueryEvent {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
/** Классы шагов цепочки (id из Schema). */
|
|
104
|
+
mode: 'paths' | 'rows' | 'ids' | 'count' | 'versions' | 'agg';
|
|
105
|
+
/** Классы шагов цепочки. */
|
|
212
106
|
classes: string[];
|
|
213
|
-
/** Длительность, мс. */
|
|
214
107
|
ms: number;
|
|
215
|
-
/** Число строк результата. */
|
|
216
108
|
rows: number;
|
|
217
|
-
/**
|
|
109
|
+
/** ms > slowMs. */
|
|
218
110
|
slow: boolean;
|
|
219
111
|
}
|
|
220
|
-
export interface ConnectOpts {
|
|
221
|
-
/** postgres://user:pass@host:port/db */
|
|
222
|
-
dsn: string;
|
|
223
|
-
/** PG-схема с таблицами Entity/Schema (напр. 'booking'). */
|
|
224
|
-
schema: string;
|
|
225
|
-
/** Партиция данных. Default 'entity'. */
|
|
226
|
-
partition?: string;
|
|
227
|
-
/** Размер пула соединений. Default 10. */
|
|
228
|
-
max?: number;
|
|
229
|
-
/**
|
|
230
|
-
* Жёсткая изоляция арендатора: чтения фильтруются по account, записи пришпилены к нему.
|
|
231
|
-
* **Default true** (с 0.20.0). Идентичность берётся у хендла `db.as(account)`; на
|
|
232
|
-
* безличном (корневом) хендле чтение/запись при включённой изоляции — ошибка с подсказкой.
|
|
233
|
-
* Явный `.account(чужой)` на scoped-хендле — тоже ошибка.
|
|
234
|
-
* Выключать (`false`) осмысленно лишь для админских/сервисных подключений,
|
|
235
|
-
* которым нужен доступ ко всем арендаторам.
|
|
236
|
-
*/
|
|
237
|
-
enforceAccount?: boolean;
|
|
238
|
-
/**
|
|
239
|
-
* ACL по Resource/Rule: категории READ/WRITE/DELETE, pattern — шаблон строки Entity
|
|
240
|
-
* (колонки + "$account"). Каждый шаг цепочки проверяется на READ, записи — WRITE,
|
|
241
|
-
* delete — DELETE (включая классы каскада); предикат победившего правила вливается
|
|
242
|
-
* в SQL до сортировки/лимита. Субъект даёт db.as() (энфорсер компилится на scope).
|
|
243
|
-
* Deny-by-default.
|
|
244
|
-
* **Default false** — остаётся opt-in: включённый по умолчанию deny-by-default без
|
|
245
|
-
* настроенных Resource/Rule давал бы пустые выборки. Пока выключен, connect() один раз
|
|
246
|
-
* на процесс печатает предупреждение.
|
|
247
|
-
* Правила снимаются на connect и компилятся в memo-энфорсер; перечитать без
|
|
248
|
-
* реконнекта — db.reloadSchema() (пересобирает и реестр, и ACL-резолвер).
|
|
249
|
-
*/
|
|
250
|
-
enforceAcl?: boolean;
|
|
251
|
-
/** Хук на каждый запрос цепочки (метрики, лог). */
|
|
252
|
-
onQuery?: (e: QueryEvent) => void;
|
|
253
|
-
/** Порог «медленного» запроса, мс: событие получает slow: true; без onQuery — console.warn. */
|
|
254
|
-
slowMs?: number;
|
|
255
|
-
}
|
|
256
|
-
/**
|
|
257
|
-
* Имена, которые Proxy цепочки/db разбирает ДО резолва класса, поэтому класс с таким
|
|
258
|
-
* id/alias НЕДОСТИЖИМ как шаг под этим именем (`db.Клиент(c).link()` уйдёт в
|
|
259
|
-
* migration-ошибку `.link() removed`, а не в класс `link`).
|
|
260
|
-
*
|
|
261
|
-
* Источник истины — `case`-метки switch'ей в chain.ts; совпадение с этим списком
|
|
262
|
-
* проверяет scripts/check-docs.mjs. Используется как гвард: schema.define() отказывает,
|
|
263
|
-
* loadRegistry предупреждает.
|
|
264
|
-
*/
|
|
265
|
-
export declare const RESERVED_CLASS_NAMES: readonly string[];
|
|
266
|
-
/** Зарезервированные имена класса среди {id, alias}; пусто — конфликта нет. */
|
|
267
|
-
export declare function reservedNamesOf(def: {
|
|
268
|
-
id: string;
|
|
269
|
-
alias?: string;
|
|
270
|
-
}): string[];
|
|
271
|
-
/**
|
|
272
|
-
* Ревизия движка (`lib/sql/ddl.sql`), которую ожидает ЭТА версия либы.
|
|
273
|
-
*
|
|
274
|
-
* Зачем: `ddl.sql` растёт аддитивно внутри одной версии движка (в 0.19.0, например,
|
|
275
|
-
* добавились функции purge/purge_closure/purge_account). Схема, накатанная раньше, их
|
|
276
|
-
* НЕ получает — приложение обновляет пакет и падает сырым `PostgresError: function
|
|
277
|
-
* "v1.x".purge(...) does not exist` вместо внятного объяснения. `connect()` сравнивает
|
|
278
|
-
* ожидаемую ревизию с меткой в схеме (`COMMENT ON SCHEMA` — её ставит последняя строка
|
|
279
|
-
* ddl.sql) и один раз на процесс предупреждает, что и как обновить.
|
|
280
|
-
*
|
|
281
|
-
* Файл идемпотентен, поэтому аддитивные правки доезжают повторным накатом:
|
|
282
|
-
* `up({ upgrade: true })` либо `node db/apply.mjs --upgrade` — данные целы.
|
|
283
|
-
* Несовместимая правка СТРУКТУРЫ таблиц — это смена version в имени схемы (v1 → v2).
|
|
284
|
-
*
|
|
285
|
-
* Совпадение константы с маркером `-- DDL_REVISION:` в ddl.sql проверяет
|
|
286
|
-
* `scripts/check-docs.mjs` — иначе одно уедет без другого.
|
|
287
|
-
*/
|
|
288
|
-
export declare const DDL_REVISION = 1;
|
|
289
|
-
/** Метка ревизии в комментарии схемы: 'letopis ddl_revision=N' → N; иначе null. */
|
|
290
|
-
export declare function parseDdlRevision(comment: string | null | undefined): number | null;
|
package/dist/types.js
CHANGED
|
@@ -1,113 +1,32 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* letopis
|
|
2
|
+
* Общие типы letopis 1.0. Файл наполняется по этапам плана (reports/PLAN-LETOPIS-1.0.md).
|
|
3
3
|
*/
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
// FieldType - тип поля attributes для SQL-кастов (number/date/boolean/string/array/record/object/any).
|
|
23
|
-
// OP - символьная метка операторов фильтра (Symbol — не конфликтует с данными).
|
|
24
|
-
// Op - узел оператора фильтра: { [OP]: имя, args }.
|
|
25
|
-
// Scalar - скалярное значение фильтра: string | number | boolean | null.
|
|
26
|
-
// FieldFilter - значение фильтра по полю: скаляр (eq) / массив / оператор Op / вложенный record.
|
|
27
|
-
// Filter - фильтр шага: id-строка/массив, Op (or) или объект полей data.
|
|
28
|
-
// Cursor - курсор keyset-пагинации: значение поля сортировки + id последней строки.
|
|
29
|
-
// PlanOp - операция записи шага (create/update/delete/anonymize) + снапшот модификаторов.
|
|
30
|
-
// ChainMods - модификаторы выборки цепочки (limit/offset/order/desc/asOf/after + внутренняя агрегация).
|
|
31
|
-
// Account - запись аккаунта служебной таблицы auth.
|
|
32
|
-
// Credential - учётные данные аккаунта (identifier/category/confirmed/…).
|
|
33
|
-
// Resource - ресурс ACL: alias/category/pattern/meta.
|
|
34
|
-
// Rule - правило ACL: account/resource/permission/weight/enabled.
|
|
35
|
-
// AclOp - операция над данными = категория Resource: 'READ' | 'WRITE' | 'DELETE'.
|
|
36
|
-
// AclDecision - решение ACL: allow + победившее правило + остаточный filter + code/message.
|
|
37
|
-
// QueryEvent - событие хука onQuery: режим, классы, ms, rows, slow.
|
|
38
|
-
// ConnectOpts - опции connect(): dsn/schema/partition/max/enforceAccount/enforceAcl/onQuery/slowMs (account/owner — не здесь, их даёт db.as()).
|
|
39
|
-
// RESERVED_CLASS_NAMES - имена, перехватываемые Proxy до резолва класса (шаг недостижим под этим именем).
|
|
40
|
-
// reservedNamesOf - зарезервированные имена среди {id, alias} определения класса.
|
|
41
|
-
// END_MODULE_MAP
|
|
42
|
-
//
|
|
43
|
-
// START_CHANGE_SUMMARY
|
|
44
|
-
// LAST_CHANGE: [v1.3.0 - BREAKING: из ConnectOpts удалены account/owner (арендатор — свойство
|
|
45
|
-
// ВЫЗОВА: db.as(account, { owner })); 'as' добавлен в RESERVED_CLASS_NAMES → 52 имени.
|
|
46
|
-
// Ранее: 'link' убран из RESERVED_CLASS_NAMES (охранник цепочки снят, имя снова
|
|
47
|
-
// резолвится как класс); enforceAccount задокументирован как Default true]
|
|
48
|
-
// END_CHANGE_SUMMARY
|
|
49
|
-
//
|
|
50
|
-
// START_BLOCK_ENTITY_TYPES
|
|
51
|
-
// END_BLOCK_ENTITY_TYPES
|
|
52
|
-
//
|
|
53
|
-
// START_BLOCK_FILTER_TYPES
|
|
54
|
-
/** Метка операторов фильтра (Symbol — не конфликтует с данными). */
|
|
55
|
-
export const OP = Symbol('letopis.op');
|
|
56
|
-
// END_BLOCK_CONNECT_TYPES
|
|
57
|
-
// START_BLOCK_RESERVED_NAMES
|
|
58
|
-
/**
|
|
59
|
-
* Имена, которые Proxy цепочки/db разбирает ДО резолва класса, поэтому класс с таким
|
|
60
|
-
* id/alias НЕДОСТИЖИМ как шаг под этим именем (`db.Клиент(c).link()` уйдёт в
|
|
61
|
-
* migration-ошибку `.link() removed`, а не в класс `link`).
|
|
62
|
-
*
|
|
63
|
-
* Источник истины — `case`-метки switch'ей в chain.ts; совпадение с этим списком
|
|
64
|
-
* проверяет scripts/check-docs.mjs. Используется как гвард: schema.define() отказывает,
|
|
65
|
-
* loadRegistry предупреждает.
|
|
66
|
-
*/
|
|
67
|
-
export const RESERVED_CLASS_NAMES = [
|
|
68
|
-
// все три Proxy: then гасится, чтобы цепочка не выглядела thenable для await
|
|
69
|
-
'then',
|
|
70
|
-
// chain-уровень (makeChain handler)
|
|
71
|
-
'entity', 'run', 'execute', 'rows', 'first', 'ids', 'count', 'limit', 'offset', 'sort',
|
|
72
|
-
'asOf', 'withDeleted', 'deep', 'exact', 'sum', 'avg', 'min', 'max', 'countBy', 'after', 'versions',
|
|
73
|
-
'create', 'update', 'set', 'delete', 'anonymize', 'purge', 'alias', 'tags', 'account',
|
|
74
|
-
'owner',
|
|
75
|
-
// db-уровень (makeDb handler): switch …
|
|
76
|
-
'as', 'begin', 'commit', 'rollback', 'lock', 'batch', 'watch', 'close', 'reloadSchema',
|
|
77
|
-
'registry', 'sql',
|
|
78
|
-
// … и фасады, которые разбираются if'ами ДО switch (служебные таблицы, auth, acl)
|
|
79
|
-
'accounts', 'credentials', 'resources', 'rules', 'schema', 'auth', 'acl',
|
|
80
|
-
// batch-уровень (makeBatch handler)
|
|
81
|
-
'discard', 'size',
|
|
4
|
+
/** Ревизия движка в базе: штамп в lib/sql/99-revision.sql должен совпадать (этап 1). */
|
|
5
|
+
export const DDL_REVISION = 5;
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
// Методы цепочки — единственный источник зарезервированных имён (план, §2.14, этап 3, п. 10)
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
/** Методы цепочки: терминалы, модификаторы, глаголы записи (этап 4), охранники снесённого API. */
|
|
10
|
+
export const CHAIN_METHODS = [
|
|
11
|
+
'then', 'entity', 'paths', 'rows', 'first', 'ids', 'count', 'limit', 'offset', 'sort', 'asOf', 'withDeleted',
|
|
12
|
+
'deep', 'exact', 'sum', 'avg', 'min', 'max', 'countBy', 'after', 'versions', 'create', 'update', 'upsert', 'set',
|
|
13
|
+
'unset', 'add', 'remove', 'delete', 'anonymize', 'reclass', 'restore', 'purge', 'alias', 'tags', 'owner',
|
|
14
|
+
'forUpdate', 'cache', 'rekey', 'run', 'execute', 'account',
|
|
15
|
+
];
|
|
16
|
+
/** Свойства корня db (и транзакции db.begin()). */
|
|
17
|
+
export const DB_METHODS = [
|
|
18
|
+
'as', 'begin', 'commit', 'rollback', 'lock', 'batch', 'watch', 'close', 'registry', 'sql', 'load', 'verify',
|
|
19
|
+
'maintain', 'reset', 'describe', 'auth', 'acl', 'idOf', 'refresh', 'transaction', 'flushSignals', 'schema',
|
|
20
|
+
'token', 'tenant', 'reloadSchema', 'accounts', 'credentials', 'resources', 'rules', 'compact',
|
|
21
|
+
'trimHistory', 'rekeyClass', 'cache',
|
|
82
22
|
];
|
|
83
|
-
/**
|
|
84
|
-
export
|
|
85
|
-
const set = new Set(RESERVED_CLASS_NAMES);
|
|
86
|
-
return [def.id, def.alias].filter((n) => !!n && set.has(n));
|
|
87
|
-
}
|
|
88
|
-
// END_BLOCK_RESERVED_NAMES
|
|
89
|
-
// START_BLOCK_DDL_REVISION
|
|
23
|
+
/** Свойства батча db.batch(name). */
|
|
24
|
+
export const BATCH_METHODS = ['discard', 'size'];
|
|
90
25
|
/**
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
* добавились функции purge/purge_closure/purge_account). Схема, накатанная раньше, их
|
|
95
|
-
* НЕ получает — приложение обновляет пакет и падает сырым `PostgresError: function
|
|
96
|
-
* "v1.x".purge(...) does not exist` вместо внятного объяснения. `connect()` сравнивает
|
|
97
|
-
* ожидаемую ревизию с меткой в схеме (`COMMENT ON SCHEMA` — её ставит последняя строка
|
|
98
|
-
* ddl.sql) и один раз на процесс предупреждает, что и как обновить.
|
|
99
|
-
*
|
|
100
|
-
* Файл идемпотентен, поэтому аддитивные правки доезжают повторным накатом:
|
|
101
|
-
* `up({ upgrade: true })` либо `node db/apply.mjs --upgrade` — данные целы.
|
|
102
|
-
* Несовместимая правка СТРУКТУРЫ таблиц — это смена version в имени схемы (v1 → v2).
|
|
103
|
-
*
|
|
104
|
-
* Совпадение константы с маркером `-- DDL_REVISION:` в ddl.sql проверяет
|
|
105
|
-
* `scripts/check-docs.mjs` — иначе одно уедет без другого.
|
|
26
|
+
* Зарезервированные имена: Proxy разбирает их раньше классов, поэтому класс с таким именем
|
|
27
|
+
* недостижим как шаг. Установщик подставляет список в функцию базы reserved_names(), которая
|
|
28
|
+
* отклоняет связи с такими именами; совпадение со switch Proxy проверяет check-docs.
|
|
106
29
|
*/
|
|
107
|
-
export const
|
|
108
|
-
/** Метка
|
|
109
|
-
export
|
|
110
|
-
const m = /letopis ddl_revision=(\d+)/.exec(comment ?? '');
|
|
111
|
-
return m ? Number(m[1]) : null;
|
|
112
|
-
}
|
|
113
|
-
// END_BLOCK_DDL_REVISION
|
|
30
|
+
export const RESERVED_CLASS_NAMES = [...new Set([...CHAIN_METHODS, ...DB_METHODS, ...BATCH_METHODS])];
|
|
31
|
+
/** Метка операторов фильтра (символ не пересекается с данными). */
|
|
32
|
+
export const OP = Symbol.for('letopis.op');
|