letopis 1.4.2 → 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 -281
- package/CHANGELOG.md +418 -0
- package/README.md +572 -1053
- 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 -184
- package/dist/auth.d.ts +2 -2
- package/dist/auth.js +5 -15
- package/dist/cache.d.ts +8 -1
- package/dist/cache.js +30 -8
- package/dist/chain.d.ts +18 -41
- package/dist/chain.js +165 -203
- package/dist/cli.js +45 -90
- 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 -70
- package/dist/index.js +189 -122
- package/dist/internal.d.ts +5 -0
- package/dist/jsonschema.js +18 -17
- package/dist/load.d.ts +20 -12
- package/dist/load.js +207 -181
- package/dist/mcp.d.ts +5 -7
- package/dist/mcp.js +168 -214
- 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 +20 -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 +1 -5
- package/dist/signals.js +1 -5
- package/dist/sql.d.ts +7 -1
- package/dist/sql.js +101 -85
- package/dist/sync.d.ts +9 -3
- package/dist/sync.js +40 -17
- package/dist/tx.d.ts +11 -1
- package/dist/tx.js +32 -11
- package/dist/typed.d.ts +240 -45
- package/dist/types.d.ts +15 -90
- package/dist/types.js +12 -14
- package/dist/up.d.ts +53 -32
- package/dist/up.js +180 -74
- package/dist/uuid.js +5 -5
- package/dist/validate.d.ts +13 -1
- package/dist/validate.js +61 -29
- package/dist/watch.d.ts +5 -16
- package/dist/watch.js +23 -77
- package/dist/write.d.ts +9 -16
- package/dist/write.js +102 -185
- package/llms.txt +22 -25
- package/package.json +2 -9
- 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 -676
- package/sql/70-read.sql +11 -13
- package/sql/80-auth.sql +23 -27
- package/sql/90-time.sql +77 -944
- 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 -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/sql/95-seed.system.sql
CHANGED
|
@@ -21,8 +21,6 @@ begin
|
|
|
21
21
|
if p_class = 'Class' then
|
|
22
22
|
select c.data, c.validator into d, vld from @SCHEMA@.class_prepare(d, p_tenant) c;
|
|
23
23
|
end if;
|
|
24
|
-
-- журнал раньше строки: агрегатные поля новой цели триггер после вставки досчитывает в ту же версию — и в entity,
|
|
25
|
-
-- и в уже записанную версию журнала (план 1.1, §2.4)
|
|
26
24
|
insert into @SCHEMA@.log (id, rev, class, tenant, owner, links, data, tags, at, author, op)
|
|
27
25
|
values (p_id, 1, p_class, p_tenant, p_tenant, coalesce(p_links, '{}'), d, '{}', now_ts, '@SYSTEM@', 'create');
|
|
28
26
|
insert into @SCHEMA@.entity (id, rev, class, tenant, owner, links, data, at, created_at, author, op, validator)
|
|
@@ -30,10 +28,6 @@ begin
|
|
|
30
28
|
if p_class in ('rule', 'Resource', 'member', 'Account', 'Class') then
|
|
31
29
|
perform @SCHEMA@.acl_bump();
|
|
32
30
|
end if;
|
|
33
|
-
-- новая цель агрегатов: метки её источников — заново
|
|
34
|
-
if p_class = 'Class' and d->'resolved' ? 'aggregate' then
|
|
35
|
-
perform @SCHEMA@.agg_mark(p_tenant, @SCHEMA@.agg_of(d->'resolved'));
|
|
36
|
-
end if;
|
|
37
31
|
return p_id;
|
|
38
32
|
end $$;
|
|
39
33
|
alter function @SCHEMA@.sys_create(uuid, text, uuid, jsonb, jsonb) owner to @OWNER@;
|
|
@@ -58,10 +52,10 @@ alter function @SCHEMA@.sys_resource(uuid, text, text, jsonb) owner to @OWNER@;
|
|
|
58
52
|
alter function @SCHEMA@.sys_rule(uuid, uuid, uuid, text, int, jsonb) owner to @OWNER@;
|
|
59
53
|
revoke all on function @SCHEMA@.sys_resource(uuid, text, text, jsonb), @SCHEMA@.sys_rule(uuid, uuid, uuid, text, int, jsonb) from public;
|
|
60
54
|
|
|
61
|
-
-- Системный сид целиком (
|
|
55
|
+
-- Системный сид целиком (установка, этап 6): ключ подписи и счётчик прав, System,
|
|
62
56
|
-- системные классы, общие группы и системные права (этап 5, п. 8). Роль admin — роль членства в
|
|
63
57
|
-- System: системные администраторы работают в арендаторе System. Права auth.* — сервису
|
|
64
|
-
-- (имперсонация, выпуск сессий, креды), letopis.* (
|
|
58
|
+
-- (имперсонация, выпуск сессий, креды), letopis.* (maintain) — только системному
|
|
65
59
|
-- администратору. Повторный вызов ничего не меняет.
|
|
66
60
|
create or replace function @SCHEMA@.seed_system() returns void
|
|
67
61
|
language plpgsql volatile
|
|
@@ -78,16 +72,15 @@ declare
|
|
|
78
72
|
o_signals uuid;
|
|
79
73
|
op text;
|
|
80
74
|
begin
|
|
81
|
-
-- аккаунт System — раньше строки ключа: служебные строки secret (KEY, LOCK
|
|
75
|
+
-- аккаунт System — раньше строки ключа: служебные строки secret (KEY, LOCK) принадлежат ему, а внешний
|
|
82
76
|
-- ключ secret.account (ревизия 7) требует строку аккаунта в entity. Счётчик прав sys_create повышает, только когда
|
|
83
|
-
-- строка ключа уже есть, — на свежей установке
|
|
77
|
+
-- строка ключа уже есть, — на свежей установке ей неоткуда взяться, и начальный v — 0
|
|
84
78
|
perform @SCHEMA@.sys_create('@SYSTEM@'::uuid, 'Account', '@SYSTEM@'::uuid, '{}',
|
|
85
79
|
'{"name": "System", "categories": ["System"], "enabled": true}');
|
|
86
80
|
|
|
87
81
|
-- Ключ подписи пропуска прав и счётчик изменений прав (50-acl.sql: acl_token, acl_bump); от ключа же
|
|
88
82
|
-- выводится ключ сигналов. Режим сигналов (up({ signals })) хранится в meta этой строки: установщик
|
|
89
|
-
-- читает его перед накатом, поэтому повторный up() без опции режим не
|
|
90
|
-
-- его заново из константы установки.
|
|
83
|
+
-- читает его перед накатом, поэтому повторный up() без опции режим не меняет.
|
|
91
84
|
insert into @SCHEMA@.secret as k (id, account, kind, material, meta)
|
|
92
85
|
values ('@SYSTEM@'::uuid, '@SYSTEM@'::uuid, 'KEY', @PGCRYPTO@.gen_random_bytes(32), '{"v": 0, "signals": "@SIGNALS@"}')
|
|
93
86
|
on conflict (id) do update set meta = k.meta || '{"signals": "@SIGNALS@"}'
|
|
@@ -148,8 +141,8 @@ begin
|
|
|
148
141
|
foreach op in array array['READ', 'WRITE', 'DELETE'] loop
|
|
149
142
|
perform @SCHEMA@.sys_rule(sys, g_admin, @SCHEMA@.sys_resource(sys, 'all:' || op, op, null), 'allow', 100);
|
|
150
143
|
end loop;
|
|
151
|
-
-- строки-замки (60-write.sql: lock_row) семейств всех
|
|
152
|
-
-- обслуживания — заранее: первое обращение под нагрузкой их не вставляет
|
|
144
|
+
-- строки-замки (60-write.sql: lock_row) семейств всех классов — системных, из сидов (sys_create их не заводит) и
|
|
145
|
+
-- арендаторов — и обслуживания — заранее: первое обращение под нагрузкой их не вставляет
|
|
153
146
|
perform @SCHEMA@.family_rows(c.tenant, c.data) from @SCHEMA@.entity c where c.class = 'Class';
|
|
154
147
|
perform @SCHEMA@.lock_row('@SCHEMA_NAME@:maintain');
|
|
155
148
|
end $$;
|
package/sql/99-revision.sql
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
-- letopis 1.0 — штамп ревизии движка (план, §2.2, этап 1, п. 11): последний оператор наката.
|
|
2
2
|
-- Номер совпадает с DDL_REVISION в lib/src/types.ts (проверяет check-docs). С 1.4 в штампе ещё версия пакета и хэш
|
|
3
3
|
-- файлов ядра (engine, sql): connect() предупреждает, если функции схемы ставила другая версия движка той же ревизии.
|
|
4
|
-
|
|
4
|
+
-- Ревизия 8 — первая у 2.0 (план 2.0, редакция 2): схему ниже неё (letopis 1.x) up() и connect() отклоняют.
|
|
5
|
+
comment on schema @SCHEMA@ is 'letopis ddl_revision=8 engine=@ENGINE_VERSION@ sql=@ENGINE_SQL@';
|
package/sql/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
# SQL ядра letopis
|
|
1
|
+
# SQL ядра letopis 2.0
|
|
2
2
|
|
|
3
3
|
Файлы накатываются установщиком (`lib/src/up.ts`, функция `install`) по возрастанию номера; каждый можно применить повторно.
|
|
4
|
-
Спецификация — `reports/PLAN-LETOPIS-1.0.md
|
|
4
|
+
Спецификация — `reports/PLAN-LETOPIS-1.0.md` (§2 и этап 1) и `reports/PLAN-LETOPIS-2.0.md`.
|
|
5
5
|
|
|
6
6
|
## Подстановки при накате
|
|
7
7
|
|
|
@@ -10,27 +10,39 @@
|
|
|
10
10
|
| `@SCHEMA@` | имя схемы в кавычках, например `"v2.salon"` |
|
|
11
11
|
| `@SCHEMA_NAME@` | имя схемы как строковый литерал без кавычек идентификатора, например `v2.salon` |
|
|
12
12
|
| `@OWNER@` | роль-владелец, по умолчанию `letopis_owner` |
|
|
13
|
+
| `@OWNER_NAME@` | имя роли-владельца строковым литералом без кавычек идентификатора, например `letopis_owner` (условия триггеров, `pg_has_role`) |
|
|
13
14
|
| `@APP@` | роль приложения, по умолчанию `letopis_app` |
|
|
14
15
|
| `@PGCRYPTO@` | схема, где установлен pgcrypto (`pg_extension.extnamespace`) |
|
|
15
|
-
| `@SYSTEM@` | id системного арендатора System: `2eba6d0a-1edd-4bb6-a85a-a703dab49035`
|
|
16
|
-
| `@
|
|
17
|
-
| `@
|
|
18
|
-
| `@
|
|
19
|
-
| `@SIGNALS@` | режим сигналов `class`, `tenant`, `opaque` или `none` (план 1.1, §2.2): опция `up({ signals })`, иначе сохранённый в `meta.signals` строки ключа `secret`, иначе `class` — константа установки |
|
|
16
|
+
| `@SYSTEM@` | id системного арендатора System: `2eba6d0a-1edd-4bb6-a85a-a703dab49035` |
|
|
17
|
+
| `@RESERVED_NAMES@` | методы цепочки, корня `db` и батча — `RESERVED_CLASS_NAMES` из `lib/src/types.ts`, литералами через запятую |
|
|
18
|
+
| `@MESSAGES@` | каталог сообщений базы — разделы `sql-*` каталога `lib/src/messages` (план 2.0, этап 3, п. 3): литерал JSON «ключ → `{ name, ru }`» для `message_catalog()` в `15-errors.sql` |
|
|
19
|
+
| `@SIGNALS@` | режим сигналов `class`, `tenant`, `opaque` или `none`: опция `up({ signals })`, иначе сохранённый в `meta.signals` строки ключа `secret`, иначе `class` — константа установки |
|
|
20
20
|
| `@ENGINE_VERSION@` | версия пакета (`lib/package.json`) — штамп движка в комментарии схемы (`99-revision.sql`) |
|
|
21
|
-
| `@ENGINE_SQL@` | 16 знаков sha256 исходного текста файлов `NN-*.sql` до подстановок (переводы строк — LF)
|
|
21
|
+
| `@ENGINE_SQL@` | 16 знаков sha256 исходного текста файлов `NN-*.sql` до подстановок (переводы строк — LF) и разделов `sql-*` каталога сообщений: `connect()` сверяет его с файлами своего пакета |
|
|
22
22
|
|
|
23
|
-
## Колонки
|
|
23
|
+
## Колонки версии
|
|
24
24
|
|
|
25
|
-
Одинаковы в `entity` и `log` (§2.2): `id`, `rev`, `class`, `tenant`, `owner`, `links`, `data`, `tags`, `at` (время
|
|
26
|
-
`author`, `agent`, `op`, `reason
|
|
27
|
-
`
|
|
25
|
+
Одинаковы в `entity` и `log` (§2.2): `id`, `rev`, `class`, `cv`, `tenant`, `owner`, `links`, `data`, `tags`, `at` (время
|
|
26
|
+
версии), `author`, `agent`, `op`, `reason`. У `entity` ещё `ends` (генерируемая: все цели концов),
|
|
27
|
+
`created_at` и `validator` (у строк `Class`), у `log` — `seq` и `tx` (курсор подписки).
|
|
28
28
|
|
|
29
29
|
## Коды ошибок
|
|
30
30
|
|
|
31
31
|
Собственный класс SQLSTATE `LT`; текст — `letopis: <имя>: <сообщение>`, детали — JSON в `DETAIL`.
|
|
32
32
|
Источник истины — функция `error_catalog()` в `15-errors.sql`.
|
|
33
33
|
|
|
34
|
+
Тексты — по ключам каталога сообщений (план 2.0, этап 3, п. 3): `lt_fail(ключ, параметры jsonb, detail jsonb)` берёт имя
|
|
35
|
+
ошибки и русский шаблон из `message_catalog()` (`{имя}` — параметр, подставляет `lt_text()`), а в `DETAIL` кладёт поля
|
|
36
|
+
`detail` и ещё `key`, `params` — библиотека переносит их в `err.key` и `err.params`; текст тот же, что видит сырой SQL.
|
|
37
|
+
`LetopisError.detail`: без `detail` — `{}`; с `p_detail => 'null'` в `DETAIL` — признак `nodetail`, и у ошибки `detail` нет.
|
|
38
|
+
Свой SQLSTATE — `lt_raise(код, ключ, параметры, detail)`. Функции, которые исполняет приложение (`inc`, `links_patch`),
|
|
39
|
+
бросают `raise` сами: текст — `lt_text(ключ, параметры)`, она и `message_catalog()` выданы приложению; `DETAIL` без своих
|
|
40
|
+
полей — с `'nodetail', true`. Все места бросают ошибки по ключам: перегрузки `lt_fail(имя, текст, detail)` и
|
|
41
|
+
`lt_raise(код, имя, текст, detail)` — сам механизм, вне `15-errors.sql` их не зовут (`lt_raise` с текстом — единственный
|
|
42
|
+
`raise`). Внутренняя ошибка — `lt_raise('XX000', ключ, …)` с кодом `internal`; строки отказа ужесточения и нарушения данных несут `key` и `params`, а
|
|
43
|
+
текст `problem` и `message` собирает `lt_text`. Литеральный текст в `raise` и в `problem` ловит `check:docs`
|
|
44
|
+
(`literals`).
|
|
45
|
+
|
|
34
46
|
| Код | Имя | Когда |
|
|
35
47
|
|---|---|---|
|
|
36
48
|
| LT001 | `no_session` | нет действующей сессии |
|
|
@@ -41,22 +53,18 @@
|
|
|
41
53
|
| LT006 | `acl_denied` | отказ по правилам доступа |
|
|
42
54
|
| LT007 | `id_mismatch` | id не равен v5 от ключа; в деталях `expected` |
|
|
43
55
|
| LT008 | `id_from_db` | id класса без ключа выдаёт база |
|
|
44
|
-
| LT009 | `immutable_key` | ключевое поле, id, арендатор, владелец менять нельзя |
|
|
56
|
+
| LT009 | `immutable_key` | ключевое поле, класс, id, арендатор, владелец менять нельзя |
|
|
45
57
|
| LT010 | `invalid_class` | описание класса отклонено, класс не найден или абстрактный |
|
|
46
|
-
| LT011 | `use_reclass` | класс с ключом меняется функцией `reclass()` |
|
|
47
|
-
| LT012 | `reclass_denied` | роли ссылающихся строк не принимают новый класс; в деталях `rows`, `others` |
|
|
48
58
|
| LT013 | `tightening_conflict` | ужесточению мешают строки; в деталях `rows`, `others` |
|
|
49
|
-
| LT014 | `isolation_level` | удаление
|
|
59
|
+
| LT014 | `isolation_level` | удаление — только в `read committed` |
|
|
50
60
|
| LT015 | `recreated_in_statement` | id удалён и создан заново одним оператором |
|
|
51
|
-
| LT016 | `cursor_expired` | курсор подписки старше яруса `all` (этап 6) |
|
|
52
61
|
| LT017 | `delete_restricted` | удалению мешают ссылающиеся строки (`onDelete: restrict`); в деталях `rows`, `others` |
|
|
53
|
-
| LT018 | `not_deleted` | `restore`
|
|
54
|
-
| LT019 | `reset_disabled` | флаг `allowReset` установки выключен: `reset` и `maintain(now)` недоступны (этап 6) |
|
|
55
|
-
| LT020 | `confirm_mismatch` | подтверждение сброса не совпадает с именем схемы (этап 6) |
|
|
56
|
-
| LT021 | `derived_class` | строки производного класса (`derivedBy`) пишет и удаляет только его проектор; на них не ссылаются концы (план 1.1, §2.4) |
|
|
57
|
-
| LT022 | `aggregate_field` | агрегатное поле (`aggregate`) считает база: приложение и сырой SQL его не передают и не меняют (план 1.1, §2.4) |
|
|
58
|
-
| LT023 | `projector_pending` | `purge` удалённого объекта, чьё надгробие ещё не прочёл проектор его класса (ревью безопасности №3, №5), или `trim_history`, чью первую оставшуюся версию он ещё не прочёл (хвост ревью №3) |
|
|
62
|
+
| LT018 | `not_deleted` | `restore` — только для удалённых объектов |
|
|
59
63
|
|
|
60
64
|
## Порядок файлов
|
|
61
65
|
|
|
62
|
-
`10-core` → `15-errors` → `20-context` → `30-validate` → `40-class` → `50-acl` → `60-write` → `70-read` → `
|
|
66
|
+
`10-core` → `15-errors` → `20-context` → `30-validate` → `40-class` → `50-acl` → `60-write` → `70-read` → `80-auth` → `90-time` → `95-seed.system` → `99-revision`. Миграции между ревизиями — `migrate/NNNN-*.sql` (номер — ревизия, к которой ведёт; правило — `migrate/README.md`), их применяет `up({ upgrade: true })` до повторного наката. У 2.0 (ревизия 8) миграций нет.
|
|
67
|
+
|
|
68
|
+
Файлы описывают только нынешнюю ревизию: `drop … if exists` в них — лишь там, где без него не пройдёт повторный накат
|
|
69
|
+
той же ревизии (политики RLS в `50-acl.sql`: у `create policy` нет `or replace`). Смена сигнатуры функции в пределах
|
|
70
|
+
ревизии — `drop function if exists` прежней в том же файле, иначе повторный накат оставит лишнюю перегрузку.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Миграции схемы letopis 2.x
|
|
2
|
+
|
|
3
|
+
`up({ upgrade: true })` применяет файлы этого каталога к схеме отставшей ревизии 2.x: в транзакции наката, под
|
|
4
|
+
блокировкой схемы и от роли владельца, до повторного наката файлов ядра (`lib/src/up.ts`: `install`, `migrationFiles`).
|
|
5
|
+
|
|
6
|
+
- Имя — `NNNN-описание.sql`: четыре цифры — номер ревизии, к которой ведёт миграция, затем дефис и строчные латинские
|
|
7
|
+
буквы, цифры, точки и дефисы (`^\d{4}-[a-z0-9.-]+\.sql$`). Файлы с другим именем, как этот, установщик пропускает.
|
|
8
|
+
- Номер миграции — новая ревизия движка: тот же номер — `DDL_REVISION` в `lib/src/types.ts` и `ddl_revision` в
|
|
9
|
+
`lib/sql/99-revision.sql` (их сверяет `npm run check:docs`).
|
|
10
|
+
- Применяются миграции с номером выше ревизии схемы и не выше `DDL_REVISION`, по возрастанию номера. Подстановки — как
|
|
11
|
+
у файлов ядра (`@SCHEMA@`, `@OWNER@` и другие — таблица в `lib/sql/README.md`).
|
|
12
|
+
- В миграцию идёт только то, чего не догонит повторный накат: колонка или ограничение существующей таблицы, перенос
|
|
13
|
+
данных. Функции, индексы, триггеры и политики ставят файлы ядра.
|
|
14
|
+
- У 2.0 (ревизия 8) миграций нет.
|