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.
Files changed (123) hide show
  1. package/AGENT-CHEATSHEET.md +516 -398
  2. package/CHANGELOG.md +739 -0
  3. package/LICENSE +75 -21
  4. package/LICENSE-COMMERCIAL.md +49 -0
  5. package/README.md +1312 -1190
  6. package/api-contract.json +381 -0
  7. package/dist/acl.d.ts +81 -1
  8. package/dist/acl.js +281 -13
  9. package/dist/admin.d.ts +11 -141
  10. package/dist/admin.js +28 -186
  11. package/dist/auth.d.ts +20 -5
  12. package/dist/auth.js +80 -21
  13. package/dist/cache.d.ts +8 -1
  14. package/dist/cache.js +30 -8
  15. package/dist/chain.d.ts +46 -48
  16. package/dist/chain.js +556 -223
  17. package/dist/cli.js +73 -96
  18. package/dist/demo/booking.d.ts +352 -36
  19. package/dist/describe.d.ts +47 -0
  20. package/dist/describe.js +195 -0
  21. package/dist/errors.d.ts +77 -13
  22. package/dist/errors.js +231 -30
  23. package/dist/index.d.ts +62 -74
  24. package/dist/index.js +312 -155
  25. package/dist/internal.d.ts +7 -0
  26. package/dist/jsonschema.js +18 -17
  27. package/dist/load.d.ts +29 -17
  28. package/dist/load.js +235 -190
  29. package/dist/log.d.ts +121 -0
  30. package/dist/log.js +633 -0
  31. package/dist/mcp.d.ts +5 -7
  32. package/dist/mcp.js +194 -225
  33. package/dist/messages/access.d.ts +90 -0
  34. package/dist/messages/access.js +113 -0
  35. package/dist/messages/api.d.ts +237 -0
  36. package/dist/messages/api.js +304 -0
  37. package/dist/messages/boot.d.ts +201 -0
  38. package/dist/messages/boot.js +256 -0
  39. package/dist/messages/codes.d.ts +172 -0
  40. package/dist/messages/codes.js +173 -0
  41. package/dist/messages/index.d.ts +98 -0
  42. package/dist/messages/index.js +121 -0
  43. package/dist/messages/log.d.ts +229 -0
  44. package/dist/messages/log.js +102 -0
  45. package/dist/messages/mcp.d.ts +306 -0
  46. package/dist/messages/mcp.js +387 -0
  47. package/dist/messages/model.d.ts +256 -0
  48. package/dist/messages/model.js +314 -0
  49. package/dist/messages/query.d.ts +141 -0
  50. package/dist/messages/query.js +171 -0
  51. package/dist/messages/sql-access.d.ts +70 -0
  52. package/dist/messages/sql-access.js +87 -0
  53. package/dist/messages/sql-core.d.ts +164 -0
  54. package/dist/messages/sql-core.js +198 -0
  55. package/dist/messages/sql-time.d.ts +86 -0
  56. package/dist/messages/sql-time.js +111 -0
  57. package/dist/messages/sql-write.d.ts +246 -0
  58. package/dist/messages/sql-write.js +270 -0
  59. package/dist/messages/time.d.ts +23 -0
  60. package/dist/messages/time.js +29 -0
  61. package/dist/messages/types.d.ts +27 -0
  62. package/dist/messages/types.js +5 -0
  63. package/dist/messages/write.d.ts +452 -0
  64. package/dist/messages/write.js +572 -0
  65. package/dist/model.d.ts +77 -60
  66. package/dist/model.js +43 -34
  67. package/dist/ops.d.ts +35 -0
  68. package/dist/ops.js +101 -0
  69. package/dist/pglite.d.ts +0 -9
  70. package/dist/pglite.js +3 -1
  71. package/dist/registry.d.ts +3 -19
  72. package/dist/registry.js +3 -16
  73. package/dist/signals.d.ts +1 -5
  74. package/dist/signals.js +1 -5
  75. package/dist/sql.d.ts +9 -1
  76. package/dist/sql.js +175 -107
  77. package/dist/sync.d.ts +10 -4
  78. package/dist/sync.js +90 -17
  79. package/dist/tx.d.ts +21 -2
  80. package/dist/tx.js +76 -13
  81. package/dist/typed.d.ts +252 -53
  82. package/dist/types.d.ts +93 -90
  83. package/dist/types.js +17 -14
  84. package/dist/up.d.ts +56 -35
  85. package/dist/up.js +229 -83
  86. package/dist/uuid.d.ts +8 -0
  87. package/dist/uuid.js +14 -6
  88. package/dist/validate.d.ts +13 -1
  89. package/dist/validate.js +82 -33
  90. package/dist/watch.d.ts +10 -16
  91. package/dist/watch.js +36 -77
  92. package/dist/write.d.ts +87 -17
  93. package/dist/write.js +441 -206
  94. package/llms.txt +48 -31
  95. package/package.json +13 -14
  96. package/sql/10-core.sql +7 -50
  97. package/sql/15-errors.sql +64 -10
  98. package/sql/20-context.sql +18 -9
  99. package/sql/30-validate.sql +79 -30
  100. package/sql/40-class.sql +41 -115
  101. package/sql/50-acl.sql +8 -13
  102. package/sql/60-write.sql +220 -676
  103. package/sql/70-read.sql +11 -13
  104. package/sql/80-auth.sql +109 -42
  105. package/sql/90-time.sql +108 -947
  106. package/sql/95-seed.system.sql +7 -14
  107. package/sql/99-revision.sql +6 -1
  108. package/sql/README.md +32 -24
  109. package/sql/migrate/0009-restore-rev.tenants-name.sql +10 -0
  110. package/sql/migrate/0010-impersonation-no-account.sql +5 -0
  111. package/sql/migrate/0011-key-lock.otp-enabled.sql +7 -0
  112. package/sql/migrate/README.md +18 -0
  113. package/AGENT-CHEATSHEET.en.md +0 -488
  114. package/MIGRATION.md +0 -190
  115. package/README.en.md +0 -2910
  116. package/dist/import.d.ts +0 -185
  117. package/dist/import.js +0 -820
  118. package/dist/project.d.ts +0 -359
  119. package/dist/project.js +0 -1258
  120. package/sql/75-history.sql +0 -436
  121. package/sql/88-derived.sql +0 -1236
  122. package/sql/migrate/0006-changed-paths.sql +0 -3
  123. package/sql/migrate/0007-secret-account-fk.sql +0 -12
package/dist/chain.d.ts CHANGED
@@ -2,7 +2,9 @@ import { type ResultCache } from './cache.js';
2
2
  import type { ClassInfo, Registry } from './registry.js';
3
3
  import { type Step } from './sql.js';
4
4
  import type { Executor } from './tx.js';
5
- import type { BlameOptions, BlameResult, ChainMods, Cursor, DiffOptions, DiffResult, Filter, Path, QueryEvent, Row } from './types.js';
5
+ import { type ChainMods, type Cursor, type Filter, type Path, type QueryEvent, type Row } from './types.js';
6
+ import { type Log } from './log.js';
7
+ import { type DeleteOptions, type RestoreOptions } from './write.js';
6
8
  export interface ChainCtx {
7
9
  readonly reg: Registry;
8
10
  readonly schema: string;
@@ -10,6 +12,8 @@ export interface ChainCtx {
10
12
  readonly exec: Executor;
11
13
  /** Арендатор сессии. */
12
14
  readonly tenant: () => string | null;
15
+ /** Фасад входит по токену сессии (connect({ token }), ключ API): без арендатора сессии шаг — sessionless(). */
16
+ readonly hasToken?: () => boolean;
13
17
  /** Владелец новых строк по умолчанию (db.as(…, { owner })). */
14
18
  readonly owner?: string;
15
19
  readonly onQuery?: (e: QueryEvent) => void;
@@ -28,6 +32,8 @@ export interface ChainCtx {
28
32
  tenant?: string | null;
29
33
  };
30
34
  };
35
+ /** Логгер фасада (lib/src/log.ts): события read, write, delete, restore, кэша и error. */
36
+ readonly log?: Log;
31
37
  }
32
38
  /** План в очереди батча; steps обновляется по мере роста цепочки. */
33
39
  export interface BatchEntry {
@@ -70,16 +76,10 @@ export interface ChainCore {
70
76
  paths?: boolean;
71
77
  }): Promise<number>;
72
78
  /**
73
- * Все версии сущностей последнего шага (надгробия — $deleted), по id и номеру версии;
74
- * { follow: true } — и через смену id при reclass и rekey, по времени.
79
+ * Все версии сущностей последнего шага (надгробия — $deleted), по id и номеру версии. Шаг с явными id находит и
80
+ * удалённые объекты: `db.Класс(id).versions()` отдаёт историю удалённого.
75
81
  */
76
- versions(opts?: {
77
- follow?: boolean;
78
- }): Promise<Row[]>;
79
- /** Что изменилось между двумя версиями или моментами (по умолчанию — предыдущая версия → последняя), план 1.1. */
80
- diff(opts?: DiffOptions): Promise<DiffResult[]>;
81
- /** Кто, когда и почему последним изменил каждое поле версии (по умолчанию текущей), план 1.1. */
82
- blame(opts?: BlameOptions): Promise<BlameResult[]>;
82
+ versions(): Promise<Row[]>;
83
83
  /**
84
84
  * Сумма поля `'data.<путь>'` по объектам последнего шага: значения приводятся к числу, складывает база. `limit()` и
85
85
  * `offset()` на итог не влияют; нет ни одного значения — `null`.
@@ -123,12 +123,13 @@ export interface ChainCore {
123
123
  * Постраничный вывод по курсору: ответ начинается строго после строки, на которой кончилась прошлая страница, в
124
124
  * порядке `sort()` (без `sort()` — ошибка `invalid_query`). Курсор этой строки даёт `cursorOf(строка, поле)` с тем же
125
125
  * полем, что в `sort()`. Листает `rows()`, `ids()`, `versions()` и `paths()` (курсор пути — `cursorOf(путь, поле)`);
126
- * `count()`, агрегаты, `diff()` и `blame()` курсор не учитывают.
126
+ * перед `count()` и агрегатами (`sum`, `avg`, `min`, `max`, `countBy`) — `invalid_query`: они считают по всем объектам.
127
127
  */
128
128
  after(cursor: Cursor): Chain;
129
129
  /**
130
- * Последний шаг находит и удалённые объекты. Удалённый объект приходит надгробием — своей последней версией, версией
131
- * удаления, — с `$deleted: true`.
130
+ * Шаг, после которого стоит, находит и удалённые объекты — модификатор своего шага, как `exact()`:
131
+ * `db.Member(id).withDeleted().Loan().withDeleted()` — удалённые выдачи удалённого участника. Удалённый объект приходит
132
+ * надгробием — своей последней версией, версией удаления, — с `$deleted: true`.
132
133
  */
133
134
  withDeleted(): Chain;
134
135
  /** Дети любой глубины на переходе к тому же классу; $depth в строке. */
@@ -161,14 +162,19 @@ export interface ChainCore {
161
162
  * же цепочка (та же переменная) второй раз в одном пути шагов не добавляет, а возвращает к своему последнему шагу:
162
163
  * следующий шаг пойдёт от него.
163
164
  */
164
- entity(x: Chain | Row): Chain;
165
+ entity(x: ChainRef | Row): Chain;
165
166
  /** Создать объект: концы — из пути и слотов; занятый ключ — ошибка exists с id. */
166
167
  create(data?: Record<string, unknown>, opts?: {
167
168
  reason?: string;
168
169
  }): Chain;
169
- /** Новая версия каждой цели шага: слияние патча в базе; inc(n) — приращение; { rev } — с проверкой версии. */
170
+ /**
171
+ * Новая версия каждой цели шага: слияние патча в базе; inc(n) — приращение; { rev } — с проверкой версии. Цели сужают
172
+ * фильтр, id, `tags()`, `owner()` или `limit()` хотя бы у одного шага, иначе `invalid_query`; правка всех строк —
173
+ * `{ all: true }`.
174
+ */
170
175
  update(patch?: Record<string, unknown>, opts?: {
171
176
  rev?: number;
177
+ all?: boolean;
172
178
  reason?: string;
173
179
  }): Chain;
174
180
  /** Создать или заменить целиком (класс с ключом); строка ответа несёт $upsert. */
@@ -178,42 +184,27 @@ export interface ChainCore {
178
184
  /**
179
185
  * Удаляет цели шага; строки, которые на них ссылаются, база удаляет вместе с ними, отвязывает или не даёт удалить цель —
180
186
  * как задано в `onDelete` их ссылок. Без `{ confirm: true }` — предпросмотр удаления: ничего не удаляется, терминал
181
- * вернёт все строки, которых оно коснулось бы, у каждой `$action` — что с ней будет.
182
- */
183
- delete(opts?: {
184
- confirm?: boolean;
185
- reason?: string;
186
- }): Chain;
187
- /** Затереть строковые поля ('[erased]') и пометить тегом anonymized. */
188
- anonymize(fields: string[], opts?: {
189
- reason?: string;
190
- }): Chain;
191
- /** Сменить класс: у класса с ключом — новый id и перевод ссылок. */
192
- reclass(cls: string, data?: Record<string, unknown>, opts?: {
193
- reason?: string;
194
- }): Chain;
187
+ * вернёт все строки, которых оно коснулось бы, у каждой `$action` — что с ней будет. `{ confirm: true, expect: превью }`
188
+ * удаляет ровно показанное: в транзакции удаления превью строится заново и сравнивается с `expect` по `id`, `rev` и
189
+ * `$action`; расхождение — `conflict` (ничего не удалено, новое превью — `err.detail.preview`); цели сужают фильтр, id,
190
+ * `tags()`, `owner()` или `limit()` хотя бы у одного шага, иначе `invalid_query`. `{ confirm: true }` без `expect` —
191
+ * `invalid_query` (`write.confirm_without_expect`); осознанно удалить текущий состав целей без сверки (и без фильтра —
192
+ * все строки) — `{ confirm: true, all: true }`.
193
+ */
194
+ delete(opts?: DeleteOptions): Chain;
195
195
  /** Чтение с блокировкой строк последнего шага до конца db.begin() (rows, first, ids). */
196
196
  forUpdate(): Chain;
197
- /** Восстановить удалённые объекты шага: последний снимок новой версией (id прежний). */
198
- restore(opts?: {
199
- reason?: string;
200
- }): Chain;
201
- /**
202
- * Стирает историю удалённых объектов шага: все их версии в журнале, от каждого остаётся одна запись `purge`. Удалённые
203
- * объекты шаг находит сам, без `withDeleted()`. Без `{ confirm: true }` — предпросмотр: ничего не стирается, терминал
204
- * вернёт надгробия с `$versions` — сколько версий сотрётся.
205
- */
206
- purge(opts?: {
207
- confirm?: boolean;
208
- reason?: string;
209
- }): Chain;
210
197
  /**
211
- * Новое значение ключа объектов шага. id вычисляется из ключа, поэтому объект получает новый id: ссылки других строк
212
- * на него переводятся на новый id, а журнал связывает старый id с новым.
198
+ * Восстановить удалённые объекты шага: последний снимок новой версией (id прежний). `{ expect }` — надгробия `{ id, rev }`
199
+ * из ответа `delete()` или `withDeleted()`: восстанавливаются только цели из `expect`, и только если последняя версия
200
+ * каждой — та же; иначе ничего не восстановлено: уже восстановлена — `not_deleted` (`write.restore_already`), id занял
201
+ * новый объект — `not_deleted` (`write.restore_id_taken`), прочее (удалена снова, менялась) — `conflict`
202
+ * (`write.restore_stale`); причины по целям — `err.detail.stale`. `{ expect, partial: true }` — восстановить то, что
203
+ * можно: остальные цели приходят строками `{ …строка, $action: 'skip', $why }`. Без `expect` — `invalid_query`
204
+ * (`write.restore_without_expect`), и для явных id; осознанно вернуть все удалённые цели шага без сверки —
205
+ * `{ all: true }`.
213
206
  */
214
- rekey(patch: Record<string, unknown>, opts?: {
215
- reason?: string;
216
- }): Chain;
207
+ restore(opts: RestoreOptions): Chain;
217
208
  /** Кэш результатов (§2.12): ответ хранится в памяти процесса ttl секунд (по умолчанию 60). */
218
209
  cache(opts?: {
219
210
  ttl?: number;
@@ -234,6 +225,8 @@ export type StepFn = ((filter?: Filter) => Chain) & {
234
225
  export type Chain = ChainCore & {
235
226
  [className: string]: StepFn;
236
227
  };
228
+ /** Любая цепочка — с типами по моделям (`TypedChain`) или без них (`Chain`): аргумент `entity()` и значение слота. */
229
+ export type ChainRef = Pick<ChainCore, 'ids'>;
237
230
  /** Внутренний канал: план чужой ленивой цепочки (entity()). */
238
231
  export declare const PLAN: unique symbol;
239
232
  /** entity-идентичность: переменная-цепочка → nodeKey её узла в этом пути. */
@@ -243,6 +236,11 @@ export declare function lookupStep(reg: Registry, name: string): {
243
236
  cls: ClassInfo;
244
237
  role?: string;
245
238
  } | undefined;
239
+ /**
240
+ * Цепочка в читаемом виде: `Shop({"name":"A"}).Product.limit(10).rows()`. Фильтры — значениями (поля-секреты — '***'),
241
+ * данные записи — только именами полей.
242
+ */
243
+ export declare function chainText(log: Log, steps: readonly Step[], mods?: ChainMods, term?: string, args?: readonly unknown[]): string;
246
244
  export declare function makeChain(ctx: ChainCtx, steps: Step[], mods: ChainMods, nodes?: NodeMap): Chain;
247
245
  /**
248
246
  * Батч: очередь планов; каждый вызов класса — своя ссылка на очередь (свой план). run() исполняет очередь
@@ -253,5 +251,5 @@ export declare function makeBatch(ctx: ChainCtx, queue: BatchEntry[]): Batch;
253
251
  /** Старт пути от корня db: класс, алиас или роль. */
254
252
  export declare function startStep(ctx: ChainCtx, name: string): StepFn;
255
253
  /** Старт пути с готового узла: db.entity(row | цепочка). */
256
- export declare function startEntity(ctx: ChainCtx, x: Chain | Row): Chain;
254
+ export declare function startEntity(ctx: ChainCtx, x: ChainRef | Row): Chain;
257
255
  export {};