letopis 1.4.1 → 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.
Files changed (113) hide show
  1. package/AGENT-CHEATSHEET.md +329 -278
  2. package/CHANGELOG.md +558 -1
  3. package/README.md +606 -1037
  4. package/dist/acl.d.ts +78 -1
  5. package/dist/acl.js +264 -13
  6. package/dist/admin.d.ts +10 -141
  7. package/dist/admin.js +24 -175
  8. package/dist/auth.d.ts +2 -2
  9. package/dist/auth.js +5 -15
  10. package/dist/cache.d.ts +8 -1
  11. package/dist/cache.js +33 -10
  12. package/dist/chain.d.ts +19 -41
  13. package/dist/chain.js +169 -201
  14. package/dist/cli.js +51 -88
  15. package/dist/demo/booking.d.ts +352 -36
  16. package/dist/describe.d.ts +47 -0
  17. package/dist/describe.js +195 -0
  18. package/dist/errors.d.ts +59 -13
  19. package/dist/errors.js +190 -29
  20. package/dist/index.d.ts +52 -71
  21. package/dist/index.js +245 -130
  22. package/dist/internal.d.ts +12 -0
  23. package/dist/internal.js +5 -0
  24. package/dist/jsonschema.js +18 -17
  25. package/dist/load.d.ts +20 -12
  26. package/dist/load.js +225 -186
  27. package/dist/mcp.d.ts +5 -7
  28. package/dist/mcp.js +171 -215
  29. package/dist/messages/access.d.ts +90 -0
  30. package/dist/messages/access.js +113 -0
  31. package/dist/messages/api.d.ts +171 -0
  32. package/dist/messages/api.js +215 -0
  33. package/dist/messages/boot.d.ts +201 -0
  34. package/dist/messages/boot.js +256 -0
  35. package/dist/messages/codes.d.ts +172 -0
  36. package/dist/messages/codes.js +173 -0
  37. package/dist/messages/index.d.ts +95 -0
  38. package/dist/messages/index.js +118 -0
  39. package/dist/messages/mcp.d.ts +306 -0
  40. package/dist/messages/mcp.js +387 -0
  41. package/dist/messages/model.d.ts +233 -0
  42. package/dist/messages/model.js +283 -0
  43. package/dist/messages/query.d.ts +131 -0
  44. package/dist/messages/query.js +158 -0
  45. package/dist/messages/sql-access.d.ts +70 -0
  46. package/dist/messages/sql-access.js +87 -0
  47. package/dist/messages/sql-core.d.ts +150 -0
  48. package/dist/messages/sql-core.js +181 -0
  49. package/dist/messages/sql-time.d.ts +71 -0
  50. package/dist/messages/sql-time.js +88 -0
  51. package/dist/messages/sql-write.d.ts +246 -0
  52. package/dist/messages/sql-write.js +270 -0
  53. package/dist/messages/time.d.ts +23 -0
  54. package/dist/messages/time.js +29 -0
  55. package/dist/messages/types.d.ts +27 -0
  56. package/dist/messages/types.js +5 -0
  57. package/dist/messages/write.d.ts +405 -0
  58. package/dist/messages/write.js +509 -0
  59. package/dist/model.d.ts +73 -60
  60. package/dist/model.js +26 -29
  61. package/dist/ops.d.ts +35 -0
  62. package/dist/ops.js +101 -0
  63. package/dist/pglite.d.ts +0 -9
  64. package/dist/pglite.js +3 -1
  65. package/dist/registry.d.ts +3 -19
  66. package/dist/registry.js +3 -16
  67. package/dist/signals.d.ts +5 -9
  68. package/dist/signals.js +5 -9
  69. package/dist/sql.d.ts +13 -6
  70. package/dist/sql.js +176 -83
  71. package/dist/sync.d.ts +9 -3
  72. package/dist/sync.js +51 -21
  73. package/dist/tx.d.ts +26 -1
  74. package/dist/tx.js +44 -14
  75. package/dist/typed.d.ts +240 -45
  76. package/dist/types.d.ts +23 -91
  77. package/dist/types.js +12 -14
  78. package/dist/up.d.ts +53 -32
  79. package/dist/up.js +184 -73
  80. package/dist/uuid.js +5 -5
  81. package/dist/validate.d.ts +13 -1
  82. package/dist/validate.js +61 -29
  83. package/dist/watch.d.ts +11 -10
  84. package/dist/watch.js +33 -70
  85. package/dist/write.d.ts +9 -16
  86. package/dist/write.js +118 -187
  87. package/llms.txt +22 -25
  88. package/package.json +8 -11
  89. package/sql/10-core.sql +7 -50
  90. package/sql/15-errors.sql +64 -10
  91. package/sql/20-context.sql +7 -6
  92. package/sql/30-validate.sql +35 -27
  93. package/sql/40-class.sql +20 -114
  94. package/sql/50-acl.sql +8 -13
  95. package/sql/60-write.sql +220 -667
  96. package/sql/70-read.sql +20 -16
  97. package/sql/80-auth.sql +24 -27
  98. package/sql/90-time.sql +70 -859
  99. package/sql/95-seed.system.sql +7 -14
  100. package/sql/99-revision.sql +2 -1
  101. package/sql/README.md +32 -24
  102. package/sql/migrate/README.md +14 -0
  103. package/AGENT-CHEATSHEET.en.md +0 -485
  104. package/MIGRATION.md +0 -190
  105. package/README.en.md +0 -2859
  106. package/dist/import.d.ts +0 -185
  107. package/dist/import.js +0 -820
  108. package/dist/project.d.ts +0 -350
  109. package/dist/project.js +0 -1224
  110. package/sql/75-history.sql +0 -358
  111. package/sql/88-derived.sql +0 -1235
  112. package/sql/migrate/0006-changed-paths.sql +0 -3
  113. package/sql/migrate/0007-secret-account-fk.sql +0 -12
package/dist/index.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  * Этап 2: connect() — подключение под сессией, реестр классов, отложенный сигнал, db.sql.
6
6
  * Этап 3: цепочки чтения t.Класс(…).Связь().rows(); этап 4 — запись цепочками и загрузчик.
7
7
  * Этап 5: db.auth (креды, вход, сессии), db.acl, db.as(аккаунт, { tenant }) — имперсонация.
8
- * Этап 6: история (restore, purge, rekey, trimHistory), verify, maintain, reset, watch, кэш результатов.
8
+ * Этап 6: история (versions, asOf, restore), maintain, watch, кэш результатов.
9
9
  */
10
10
  import postgres from 'postgres';
11
11
  import { Registry } from './registry.js';
@@ -13,41 +13,40 @@ import { type Tx } from './tx.js';
13
13
  import { type AuthApi } from './auth.js';
14
14
  import { type AclApi } from './acl.js';
15
15
  import { type LoadInput, type LoadOptions, type LoadReport } from './load.js';
16
- import { type Batch, type Chain, type StepFn } from './chain.js';
16
+ import { type Batch, type Chain, type ChainRef, type StepFn } from './chain.js';
17
17
  import type { QueryEvent, Row } from './types.js';
18
18
  import { type CacheOptions, type CacheStats } from './cache.js';
19
19
  import { Subscription, type WatchOptions } from './watch.js';
20
- import { Projector, type ProjectorOptions } from './project.js';
21
- import { type MaintainOptions, type MaintainReport, type ModelDescription, type ResetOptions, type ResetResult, type VerifyResult } from './admin.js';
22
- import type { AnyModelLike, StepsOf } from './typed.js';
20
+ import { type MaintainReport } from './admin.js';
21
+ import type { AnyModelLike, OrOp, StepsOf } from './typed.js';
23
22
  export { DDL_REVISION } from './types.js';
24
23
  export { uuidv5, v5Name, v5Id, idOf, type KeyedClass } from './uuid.js';
25
24
  export { LetopisError, ValidationError, fromDbError, type Issue } from './errors.js';
26
- export { Registry, type AggregateInfo, type ClassInfo, type EndInfo, type LeafType } from './registry.js';
25
+ export { Registry, type ClassInfo, type EndInfo, type LeafType } from './registry.js';
27
26
  export { compileValidator, applyDefaults, type Validator } from './validate.js';
28
27
  export { syncModels, generateTypes, schemaToTs, type SyncResult } from './sync.js';
29
- export { ne, gt, gte, lt, lte, between, inList, like, ilike, starts, ends, has, hasAny, hasAll, exists, isNull, not, or, isOp } from './ops.js';
28
+ export { ne, gt, gte, lt, lte, between, inList, like, ilike, starts, ends, has, hasAny, hasAll, exists, isNull, not, isOp } from './ops.js';
29
+ /**
30
+ * Хотя бы один из фильтров: `db.Product(or({ sku: 'K-1' }, { price: lt(500) }))` — товар K-1 или дешевле 500. Ставится
31
+ * вместо всего фильтра шага, а не значением поля; условия внутри одного фильтра соединяются через «и». В шаге подключения
32
+ * с моделями (`TypedDb`) фильтры внутри — поля и роли класса шага: тип им даёт шаг (план 2.0, этап 4, п. 1). Та же
33
+ * фабрика, что в реестре операторов (ops.ts), — другой у неё только тип.
34
+ */
35
+ export declare const or: <F extends object>(...filters: NoInfer<F>[]) => OrOp<F>;
30
36
  export { cursorOf } from './sql.js';
31
37
  export { inc, isInc, type IncMarker, type WriteRow } from './write.js';
32
38
  export { totpCode, hashPassword, verifyHash, type AuthApi, type LoginResult, type Credential, type SessionInfo } from './auth.js';
33
- export type { AclApi, AclDecision, AclDataDecision, AclOp } from './acl.js';
39
+ export type { AclApi, AclDecision, AclDataDecision, AclOp, AclRule, AclRuleSpec, AclTarget } from './acl.js';
34
40
  export type { LoadOptions, LoadReport, LoadIssue, LoadInput } from './load.js';
35
- export type { Chain, ChainCore, StepFn, BatchEntry } from './chain.js';
36
- export type { ModelLike, AnyModelLike, RowOf, FilterOf, FieldFilterOf, TypedChain, StepsOf, PatchOf } from './typed.js';
41
+ export type { Chain, ChainCore, ChainRef, StepFn, BatchEntry } from './chain.js';
42
+ export type { ModelLike, AnyModelLike, RowOf, FilterOf, FieldFilterOf, TypedChain, StepsOf, PatchOf, OrOp, SystemModels } from './typed.js';
37
43
  export type { Row, Path, Filter, FieldFilter, Cursor, ChainMods, QueryEvent, Op, Scalar } from './types.js';
38
- export type { DiffChange, DiffResult, DiffOptions, BlameField, BlameResult, BlameOptions } from './types.js';
39
44
  export type { CacheOptions, CacheStats } from './cache.js';
40
45
  export type { SignalMode } from './signals.js';
41
46
  export type { WatchOptions, WatchEvent, Subscription } from './watch.js';
42
- export type { Projector, ProjectorOptions, ProjectorChange, ProjectorOut, ProjectorRow, ProjectorReport, ProjectorStatus, ProjectorFailure } from './project.js';
43
- export type { VerifyResult, VerifyIssue, MaintainOptions, MaintainReport, ResetOptions, ResetResult, ModelDescription } from './admin.js';
44
- export { describeText } from './admin.js';
45
- export { up, createTenant, type UpOptions, type UpResult, type HistoryPolicy, type TenantOptions, type TenantResult } from './up.js';
47
+ export type { MaintainReport } from './admin.js';
48
+ export { up, createTenant, type UpOptions, type UpResult, type TenantOptions, type TenantResult, type LoginOptions } from './up.js';
46
49
  export { RESERVED_CLASS_NAMES, CHAIN_METHODS, DB_METHODS } from './types.js';
47
- /** Снесено в 1.0.0: id v7 больше не выдаются (§2.3). */
48
- export declare function uuidv7(): never;
49
- /** Снесено в 1.0.0: пространство имён v5 — id арендатора. Любое использование значения — ошибка. */
50
- export declare const LETOPIS_NS: string;
51
50
  export interface ConnectOptions {
52
51
  /** Строка подключения; либо готовый пул postgres.js в `sql`. */
53
52
  dsn?: string;
@@ -58,13 +57,25 @@ export interface ConnectOptions {
58
57
  token?: string;
59
58
  apiKey?: string;
60
59
  service?: string;
61
- /** Продлевать сессию раз в минуту работы (по умолчанию да, §2.9). */
60
+ /**
61
+ * Продлевать сессию раз в минуту работы (по умолчанию да, §2.9); после простоя дольше минуты — до операции: истёкшая
62
+ * сессия тогда даёт `no_session`, а не анонимное чтение с пустым ответом, а подключение по `apiKey` обменивает ключ
63
+ * заново. `false` — без продления и без этой проверки.
64
+ */
62
65
  refreshSession?: boolean;
63
66
  /** Разрешить роль, которая обходит RLS (суперпользователь, `BYPASSRLS`, член роли-владельца), — администраторское подключение (§2.9). */
64
67
  allowBypassRls?: boolean;
68
+ /**
69
+ * Один процесс малого приложения (план 2.0, этап 3): строка подключения администратора (или пул postgres.js). Второй
70
+ * пул — не больше двух соединений — открывается при первой надобности и служит только администраторским вызовам корня
71
+ * подключения: `load`, `maintain` и `syncModels`, с той же сессией.
72
+ * Цепочки и `db.sql` идут через пул приложения (`dsn`) под RLS. Роль строки — суперпользователь или роль с `SET` на
73
+ * роль-владельца, иначе `admin_required`. Пароль администратора в процессе приложения — только для малых приложений.
74
+ */
75
+ admin?: string | postgres.Sql;
65
76
  /** Имя роли-владельца (по умолчанию `letopis_owner`). */
66
77
  owner?: string;
67
- /** Интервал отправки отложенного сигнала, мс (по умолчанию 100; решение 9 точки А). */
78
+ /** Интервал отправки отложенного сигнала, мс (по умолчанию 100). */
68
79
  notifyIntervalMs?: number;
69
80
  /** Размер пула, если подключение создаёт сам `connect()`. */
70
81
  max?: number;
@@ -87,7 +98,7 @@ export interface ConnectOptions {
87
98
  * Запускать `maintain()` по расписанию: интервал — число миллисекунд или строка вроде `'15m'`, `'1h'`, от 1 мс до
88
99
  * 2³¹−1 мс (около 24 суток); иначе `connect()` отказывает с `invalid_data`, не открывая соединений. Если обслуживание в
89
100
  * этот момент уже ведёт другой процесс или ещё идёт прошлый запуск, запуск пропускается. `close()` ждёт, пока идущий
90
- * запуск доделает текущую пачку.
101
+ * запуск закончится.
91
102
  */
92
103
  maintain?: string | number;
93
104
  }
@@ -119,37 +130,10 @@ export interface DbCore {
119
130
  /** Отправить накопленные сигналы сейчас. */
120
131
  flushSignals(): Promise<void>;
121
132
  /**
122
- * Проверяет целостность журнала всей установки: сходится ли хэш каждой версии с хэшем предыдущей и текущая строка
123
- * объекта — с его последней версией; с `{ data: true }` проверяет ещё каждую строку. Якорь в ответе — один хэш текущих
124
- * версий всех объектов: храните его вне базы, тогда заметна и подмена самых свежих версий. Нужно право `letopis.verify`
125
- * (по умолчанию оно у системного администратора) или администраторское подключение.
126
- */
127
- verify(opts?: {
128
- data?: boolean;
129
- }): Promise<VerifyResult>;
130
- /** Обслуживание: истёкшие сессии и коды, прореживание журнала по политике хранения, очередь сигналов. */
131
- maintain(opts?: MaintainOptions): Promise<MaintainReport>;
132
- /**
133
- * Сбрасывает тестовую установку: сессии, данные одного арендатора или всё — смотря по `level`. Работает, только если
134
- * установка поставлена с `up({ allowReset: true })`, у вызывающего есть право `letopis.reset` (или подключение
135
- * администраторское), а `confirm` совпадает с именем схемы.
136
- */
137
- reset(opts: ResetOptions): Promise<ResetResult>;
138
- /**
139
- * Стирает версии, сделанные раньше момента `before`; текущая версия остаётся всегда. Вместо стёртого начала истории
140
- * остаётся служебная запись `trim` со временем появления объекта.
141
- */
142
- trimHistory(target: string | string[] | Row | Row[], before: string | Date): Promise<number>;
143
- /**
144
- * Меняет ключ класса. Объекты его семейства (сам класс и потомки), у которых по новому ключу выходит другой id,
145
- * переезжают на новый id, а ссылки на них переводятся.
133
+ * Обслуживание: истёкшие и погашенные сессии, одноразовые коды, строки-замки удалённых классов, очередь сигналов. Нужно
134
+ * право `letopis.maintain` (по умолчанию оно у системного администратора) или администраторское подключение.
146
135
  */
147
- rekeyClass(cls: string, key: string[]): Promise<number>;
148
- /**
149
- * Описание модели для программ и языковых моделей: классы арендатора сессии и общие классы System с полями, ключом,
150
- * ссылками и метаданными `meta`. `describeText(db.describe())` превращает его в текст.
151
- */
152
- describe(): ModelDescription;
136
+ maintain(): Promise<MaintainReport>;
153
137
  /** Подписка по курсору: `for await (const ev of db.watch({ from })) …`; `sub.cursor` — откуда продолжить. */
154
138
  watch(opts?: WatchOptions): Subscription;
155
139
  /** Кэш результатов подключения. */
@@ -158,7 +142,7 @@ export interface DbCore {
158
142
  stats(): CacheStats;
159
143
  };
160
144
  /** Начать путь с готового узла: `db.entity(row | цепочка)`. */
161
- entity(x: Chain | Row): Chain;
145
+ entity(x: ChainRef | Row): Chain;
162
146
  /**
163
147
  * Подключение на том же пуле от имени другого аккаунта: запросы идут с его правами и в его арендаторе. Журнал
164
148
  * записывает автором версий этот аккаунт, а исполнителем (`agent`) — аккаунт сессии, например сервис. Нужно право
@@ -170,8 +154,7 @@ export interface DbCore {
170
154
  owner?: string;
171
155
  tenant?: string;
172
156
  }): Promise<Db>;
173
- /** Явная транзакция `read committed`: те же цепочки, `commit()`, `rollback()`, `lock()`, `forUpdate()`. */
174
- /** Явная транзакция; `reason` — причина изменения для всех операций блока (план 1.1). */
157
+ /** Явная транзакция `read committed`: те же цепочки, `commit()`, `rollback()`, `lock()`, `forUpdate()`; `reason` — причина изменения для всех операций блока. */
175
158
  begin(opts?: {
176
159
  reason?: string;
177
160
  }): Promise<DbTx>;
@@ -182,18 +165,6 @@ export interface DbCore {
182
165
  * от имени пользователя (опция `as`). Работает только на администраторском подключении, иначе `admin_required`.
183
166
  */
184
167
  load(input: LoadInput, opts?: LoadOptions): Promise<LoadReport>;
185
- /**
186
- * Проектор из журнала (план 1.1, §2.4): строит строки производных классов (`derivedBy: имя`) из изменений
187
- * классов `from`; `run()` — догнать журнал и следовать за ним, `rebuild()` — перестроить с текущего состояния.
188
- * Только на администраторском подключении (иначе `admin_required`).
189
- */
190
- projector(name: string, opts: ProjectorOptions): Projector;
191
- /**
192
- * Ремонт агрегатов в базе (план 1.1, §2.4): поля класса (с потомками) во всех арендаторах — заново из живых строк
193
- * источников, под исключительными блокировками; версия — только у исправленных. Возвращает их число. Только на
194
- * администраторском подключении (иначе `admin_required`).
195
- */
196
- rebuildAggregates(cls: string): Promise<number>;
197
168
  /**
198
169
  * Именованная очередь планов фасада: `batch.Класс(…).create(…)`; `batch.run()` — одной транзакцией. У корня,
199
170
  * у каждого `db.as()` и у каждой `db.begin()` очереди свои: план исполняется от имени фасада, который его поставил.
@@ -215,12 +186,22 @@ export type Db = DbCore & {
215
186
  };
216
187
  /** Явная транзакция `db.begin()`: тот же API; ошибка любого запроса её ломает (§2.5). */
217
188
  export type DbTx = Db;
218
- /** Подключение с типами шагов, строк и фильтров по моделям: `connect({ models })`. */
219
- export type TypedDb<M extends readonly AnyModelLike[]> = DbCore & StepsOf<M> & {
220
- [className: string]: StepFn;
221
- };
189
+ /**
190
+ * Подключение со строгими типами по моделям: `connect({ models })` или `connect<Models>()` с объявлениями
191
+ * `letopis types`. Шаг — только известный класс или алиас (модели и системные классы), переходы — по концам, слоты — роли
192
+ * класса; имена, известные только во время выполнения, — `loose(db)` (план 2.0, этап 4, п. 1). Модели без литеральных
193
+ * имён (`AnyModel[]` вместо списка `as const`) строгим типам не помогут — тогда это `Db`.
194
+ */
195
+ export type TypedDb<M extends readonly AnyModelLike[]> = string extends M[number]['name'] ? Db : DbCore & StepsOf<M>;
222
196
  export type { Batch };
197
+ /**
198
+ * То же подключение без строгих типов: шагом может быть любое имя, в том числе известное только во время выполнения, —
199
+ * `loose(db)[имя]()`. Объект тот же: проверки во время выполнения (неизвестное имя или поле, переход, слот) не меняются.
200
+ */
201
+ export declare function loose(db: DbCore): Db;
223
202
  export declare function connect<const M extends readonly AnyModelLike[]>(opts: ConnectOptions & {
224
203
  models: M;
225
204
  }): Promise<TypedDb<M>>;
226
205
  export declare function connect(opts: ConnectOptions): Promise<Db>;
206
+ /** Строгие типы без моделей Zod — из объявлений `letopis types`: `connect<Models>({ … })`. */
207
+ export declare function connect<M extends readonly AnyModelLike[]>(opts: ConnectOptions): Promise<TypedDb<M>>;