letopis 1.0.0 → 1.0.1
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/CHANGELOG.md +24 -0
- package/README.en.md +2 -1
- package/README.md +2 -2
- package/dist/cli.js +16 -2
- package/package.json +1 -1
- package/sql/60-write.sql +4 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,30 @@
|
|
|
2
2
|
|
|
3
3
|
Формат: [Keep a Changelog](https://keepachangelog.com/), версии — semver.
|
|
4
4
|
|
|
5
|
+
## [1.0.1] — 2026-10-09
|
|
6
|
+
|
|
7
|
+
Исправления, найденные сразу после выпуска 1.0.0.
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
- Команда `letopis` на Linux и macOS: запуск через `npx`, `node_modules/.bin` или скрипты `package.json` молча
|
|
11
|
+
завершался с кодом 0, ничего не сделав. Там `node_modules/.bin/letopis` — симлинк, а защита запуска сравнивала
|
|
12
|
+
путь симлинка (`process.argv[1]`) с реальным путём файла (`import.meta.url`). Теперь сравниваются реальные пути.
|
|
13
|
+
Прямой запуск `node node_modules/letopis/dist/cli.js` и Windows дефекта не имели.
|
|
14
|
+
- Эволюция классов: правка условий `anyOf` и `oneOf` в описании класса считалась безопасной, и строки семейства не
|
|
15
|
+
перепроверялись. Строка, не проходящая новое условие, оставалась в базе, а её следующая правка падала с
|
|
16
|
+
`invalid_data`. Теперь любая правка `anyOf` и `oneOf` — ужесточение: строки проверяются под исключительной
|
|
17
|
+
блокировкой семейства, мешающие перечисляет `tightening_conflict` (`class_change_safe`). Строки, оставшиеся после
|
|
18
|
+
такой правки в 1.0.0, находит `db.verify({ data: true })`.
|
|
19
|
+
- Выпуск: проверка опубликованного пакета (`check-package.mjs --registry`) повторяет установку, пока свежая версия не
|
|
20
|
+
появится в метаданных реестра для установки (до 5 минут). На 1.0.0 этот шаг `release.yml` упал ложно: `npm view`
|
|
21
|
+
уже видел версию, а `npm install` ещё нет. Сам пакет 1.0.0 исправен: та же проверка прошла после появления версии.
|
|
22
|
+
|
|
23
|
+
### Tests
|
|
24
|
+
- `load`: CLI запускается через симлинк, как из `node_modules/.bin` на Linux и macOS.
|
|
25
|
+
- `engine-class`: правка `anyOf` и `oneOf` при мешающей строке — `tightening_conflict`, при подходящих строках —
|
|
26
|
+
принимается.
|
|
27
|
+
- Проверка пакета запускает установленную команду `letopis --help` через `npm exec` — в CI это симлинк на Linux.
|
|
28
|
+
|
|
5
29
|
## [1.0.0] — 2026-10-09
|
|
6
30
|
|
|
7
31
|
letopis 1.0 — новая реализация хранилища по плану `reports/PLAN-LETOPIS-1.0.md` (редакция 8), основанному на
|
package/README.en.md
CHANGED
|
@@ -477,7 +477,8 @@ name of the class for a chain step, for example a name in another language.
|
|
|
477
477
|
`syncModels(db, models)` without `apply` is a dry run; with `{ apply: true }` it applies the changes. The result is
|
|
478
478
|
`{ applied, created, updated, unchanged, skipped, lost }`; `skipped` lists System classes, which only the installation
|
|
479
479
|
changes. `syncModels` touches only the classes passed to it and deletes nothing. Safe changes (a new optional field or
|
|
480
|
-
end, metadata, an alias) are applied at once.
|
|
480
|
+
end, metadata, an alias) are applied at once. Anything else, including any change to the `anyOf` and `oneOf` conditions, is a
|
|
481
|
+
tightening: it checks all rows of the family; if some rows conflict with it, you get
|
|
481
482
|
`tightening_conflict` with a list. Classes are written to the session tenant, and other tenants do not see them.
|
|
482
483
|
Classes shared by everyone are in System: the installation seed or the import puts them there.
|
|
483
484
|
|
package/README.md
CHANGED
|
@@ -467,8 +467,8 @@ id из email подбирается перебором и остаётся в
|
|
|
467
467
|
`syncModels(db, модели)` без `apply` — сухой прогон, с `{ apply: true }` — применение. Результат:
|
|
468
468
|
`{ applied, created, updated, unchanged, skipped, lost }`; в `skipped` — классы System, их меняет только установка.
|
|
469
469
|
`syncModels` трогает только переданные классы и ничего не удаляет. Безопасные изменения — новое необязательное поле или
|
|
470
|
-
конец, метаданные, алиас — применяются сразу.
|
|
471
|
-
приходит `tightening_conflict` со списком. Классы пишутся в арендатора сессии, и другие арендаторы их не видят.
|
|
470
|
+
конец, метаданные, алиас — применяются сразу. Всё остальное, в том числе любая правка условий `anyOf` и `oneOf`, —
|
|
471
|
+
ужесточение: оно проверяет все строки семейства, и если им мешают строки, приходит `tightening_conflict` со списком. Классы пишутся в арендатора сессии, и другие арендаторы их не видят.
|
|
472
472
|
Классы, общие для всех, лежат в System: их ставит сид установки или импорт.
|
|
473
473
|
|
|
474
474
|
То же из командной строки:
|
package/dist/cli.js
CHANGED
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import { parseArgs } from 'node:util';
|
|
17
17
|
import { readFile, writeFile } from 'node:fs/promises';
|
|
18
|
-
import {
|
|
18
|
+
import { realpathSync } from 'node:fs';
|
|
19
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
19
20
|
import { resolve } from 'node:path';
|
|
20
21
|
import { connect, describeText } from './index.js';
|
|
21
22
|
import { syncModels, generateTypes } from './sync.js';
|
|
@@ -153,7 +154,20 @@ export async function main(argv) {
|
|
|
153
154
|
await db.close();
|
|
154
155
|
}
|
|
155
156
|
}
|
|
156
|
-
|
|
157
|
+
// Запущен ли файл как программа. Сравниваются реальные пути: на Linux и macOS `node_modules/.bin/letopis`
|
|
158
|
+
// (npx, скрипты package.json) — симлинк, `process.argv[1]` указывает на него, а `import.meta.url` — на сам файл.
|
|
159
|
+
function isMain() {
|
|
160
|
+
const arg = process.argv[1];
|
|
161
|
+
if (!arg)
|
|
162
|
+
return false;
|
|
163
|
+
try {
|
|
164
|
+
return realpathSync(arg) === realpathSync(fileURLToPath(import.meta.url));
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if (isMain()) {
|
|
157
171
|
main(process.argv.slice(2)).then((code) => process.exit(code), (e) => {
|
|
158
172
|
console.error(e.message);
|
|
159
173
|
const rows = e.detail?.rows;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "letopis",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Letopis (летопись): versioned entity store on PostgreSQL 18 — integrity, history, tenants and access control enforced by the database itself, dot-notation chains on top",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"postgres",
|
package/sql/60-write.sql
CHANGED
|
@@ -383,13 +383,16 @@ begin
|
|
|
383
383
|
end $$;
|
|
384
384
|
|
|
385
385
|
-- Безопасно ли изменение описания класса (этап 1, п. 10): новые необязательные поля и концы,
|
|
386
|
-
-- метаданные, алиас, политика истории, кэш. Всё остальное — ужесточение с проверкой
|
|
386
|
+
-- метаданные, алиас, политика истории, кэш. Всё остальное — ужесточение с проверкой строк, в том числе
|
|
387
|
+
-- любая правка условий anyOf и oneOf (1.0.1: прежде они не сравнивались, и строки не перепроверялись).
|
|
387
388
|
create or replace function @SCHEMA@.class_change_safe(o jsonb, n jsonb) returns boolean
|
|
388
389
|
language sql immutable
|
|
389
390
|
return
|
|
390
391
|
o->'key' = n->'key'
|
|
391
392
|
and o->'ancestors' = n->'ancestors'
|
|
392
393
|
and (o->'abstract' = n->'abstract' or n->>'abstract' = 'false')
|
|
394
|
+
and o->'schema'->'anyOf' is not distinct from n->'schema'->'anyOf'
|
|
395
|
+
and o->'schema'->'oneOf' is not distinct from n->'schema'->'oneOf'
|
|
393
396
|
and coalesce(o->'schema'->'required', '[]'::jsonb) @> coalesce(n->'schema'->'required', '[]'::jsonb)
|
|
394
397
|
and not exists (select 1 from jsonb_each(coalesce(o->'schema'->'properties', '{}'::jsonb)) p
|
|
395
398
|
where n->'schema'->'properties'->p.key is distinct from p.value)
|