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/typed.d.ts CHANGED
@@ -1,35 +1,171 @@
1
1
  /**
2
- * Типы цепочек по моделям (план, этап 3, п. 9): `connect({ models })` даёт типы шагов по именам и
3
- * алиасам классов, типы строк ответа и фильтров. Допустимость переходов проверяется во время
4
- * выполнения, как в 0.21. Модель описана структурно (ModelLike), чтобы основная точка входа не
5
- * зависела от Zod: модели letopis/model ей соответствуют.
2
+ * Строгие типы цепочек по моделям (план 2.0, этап 4, п. 1; типы шагов, строк и фильтров — план 1.0, этап 3, п. 9).
3
+ * `connect({ models })` — модели letopis/model — или `connect<Models>()` — объявления `letopis types` (generateTypes,
4
+ * sync.ts) — дают TypedDb без индексных сигнатур:
5
+ * - шаг от корня — только известный класс или алиас: моделей подключения и системных (встроенный набор SystemModels);
6
+ * - переходы цепочки выводятся из концов, как в resolveHop (lib/src/sql.ts): от класса C — роли его семейства (C и
7
+ * потомков) и классы, связанные с семейством C концом в любую сторону (роль, имя которой совпало с именем класса,
8
+ * во время выполнения — шаг класса, так же и здесь);
9
+ * - слоты — только роли класса C: `set(id | строка | цепочка)`, `add` и `remove` — у множественного конца, `unset` —
10
+ * у необязательного;
11
+ * - поля фильтров, `or()` и агрегатов `sum`, `avg`, `min`, `max`, `countBy` — поля класса.
12
+ * Чего типы не знают: возврат к узлу связи из пути (pivot) от класса, с которым связь не связана концом, и роль чужого
13
+ * класса шагом. Это и имена, известные только во время выполнения, — через loose(db) (index.ts): проверки во время
14
+ * выполнения те же. db.as(), db.begin(), db.batch() и entity() отдают цепочки без строгих типов (Db, Batch, Chain).
15
+ * Модель описана структурно (ModelLike), поэтому основная точка входа не зависит от Zod.
6
16
  */
7
- import type { ChainCore, StepFn } from './chain.js';
8
- import type { Cursor, Op, Path, Row, Scalar } from './types.js';
17
+ import type { ChainCore, ChainRef } from './chain.js';
18
+ import type { Cursor, Op, OP, Path, Row, Scalar } from './types.js';
9
19
  import type { IncMarker } from './write.js';
10
- /** То, что цепочкам нужно от модели: имя, алиас и выведенные типы данных и концов. */
11
- export interface ModelLike<N extends string = string, D = unknown, L = unknown, A extends string = string> {
20
+ /**
21
+ * То, что цепочкам нужно от модели: имя, алиас и типы для вывода — данные строки, концы строки, концы класса (роль →
22
+ * `{ targets: имена классов целей; many; required }`) и имена класса и его предков. Модели letopis/model и объявления
23
+ * `letopis types` ему соответствуют.
24
+ */
25
+ export interface ModelLike<N extends string = string, D = unknown, L = unknown, A extends string = string, E = unknown, P extends string = never> {
12
26
  readonly name: N;
13
27
  readonly alias?: A;
14
28
  readonly __types?: {
15
29
  data: D;
16
30
  links: L;
31
+ ends?: E;
32
+ ancestors?: P;
17
33
  };
18
34
  }
19
- export type AnyModelLike = ModelLike<string, any, any, any>;
20
- type DataOf<C> = C extends ModelLike<string, infer D, unknown, string> ? (D extends Record<string, unknown> ? D : Record<string, unknown>) : Record<string, unknown>;
21
- type LinksOf<C> = C extends ModelLike<string, unknown, infer L, string> ? (L extends Record<string, unknown> ? L : Record<string, string>) : Record<string, string>;
35
+ export type AnyModelLike = ModelLike<string, any, any, any, any, any>;
36
+ /** Обязательный одиночный конец на класс T (системные классы). */
37
+ type One<T extends string> = {
38
+ targets: T;
39
+ many: false;
40
+ required: true;
41
+ };
42
+ type NoKeys = Record<never, never>;
43
+ /**
44
+ * Встроенный набор моделей системных классов (lib/sql/95-seed.system.sql): шаги Class, Account, member, Resource, rule
45
+ * есть у любого TypedDb. Модель с тем же именем в `models` (например, из `letopis types --system`) — вместо встроенной.
46
+ */
47
+ export type SystemModels = readonly [
48
+ ModelLike<'Class', {
49
+ name: string;
50
+ }, NoKeys, never, NoKeys>,
51
+ ModelLike<'Account', {
52
+ name: string;
53
+ enabled?: boolean;
54
+ categories?: string[];
55
+ }, NoKeys, never, NoKeys>,
56
+ ModelLike<'member', {
57
+ roles?: string[];
58
+ }, {
59
+ User: string;
60
+ Tenant: string;
61
+ }, never, {
62
+ User: One<'Account'>;
63
+ Tenant: One<'Account'>;
64
+ }>,
65
+ ModelLike<'Resource', {
66
+ alias: string;
67
+ category: 'ACCOUNT' | 'API' | 'READ' | 'WRITE' | 'DELETE';
68
+ pattern?: {
69
+ categories?: string;
70
+ roles?: string;
71
+ endpoint?: string;
72
+ class?: string;
73
+ };
74
+ description?: string;
75
+ }, NoKeys, never, NoKeys>,
76
+ ModelLike<'rule', {
77
+ permission: 'allow' | 'deny';
78
+ weight?: number;
79
+ enabled?: boolean;
80
+ code?: number;
81
+ message?: string;
82
+ description?: string;
83
+ }, {
84
+ Group: string;
85
+ Object: string;
86
+ }, never, {
87
+ Group: One<'Resource'>;
88
+ Object: One<'Resource'>;
89
+ }>
90
+ ];
91
+ type NameOf<K> = K extends {
92
+ readonly name: infer N extends string;
93
+ } ? N : never;
94
+ /** Алиас модели; нет алиаса (или он не литерал) — never. */
95
+ type AliasOf<K> = K extends {
96
+ readonly alias?: infer A;
97
+ } ? (A extends string ? (string extends A ? never : A) : never) : never;
98
+ /** Имена, которыми модель вызывается шагом: имя и алиас. */
99
+ type StepNames<K> = NameOf<K> | AliasOf<K>;
100
+ type TypesOf<K> = K extends {
101
+ readonly __types?: infer T;
102
+ } ? NonNullable<T> : NoKeys;
103
+ /** Данные строки класса C (интерфейсы `letopis types` — тоже: индексная сигнатура не требуется). */
104
+ type DataOf<C> = C extends unknown ? (TypesOf<C> extends {
105
+ data: infer D;
106
+ } ? (D extends object ? D : Record<string, unknown>) : Record<string, unknown>) : never;
107
+ type LinksOf<C> = C extends unknown ? (TypesOf<C> extends {
108
+ links: infer L;
109
+ } ? (L extends object ? L : Record<string, string>) : Record<string, string>) : never;
110
+ /** Концы класса C: роль → { targets, many, required }; модель без них — без концов. */
111
+ type EndsOf<C> = C extends unknown ? (TypesOf<C> extends {
112
+ ends?: infer E;
113
+ } ? EndsOrNone<NonNullable<E>> : NoKeys) : never;
114
+ type EndsOrNone<E> = [E] extends [object] ? E : NoKeys;
115
+ /** Имя класса и его предков (ancestors реестра). */
116
+ type AncestorsOf<K> = K extends unknown ? NameOf<K> | (TypesOf<K> extends {
117
+ ancestors?: infer P;
118
+ } ? Extract<P, string> : never) : never;
119
+ type EndTargets<S> = S extends {
120
+ targets: infer T;
121
+ } ? Extract<T, string> : never;
122
+ /** Классы целей всех концов модели. */
123
+ type TargetsOf<K> = K extends unknown ? {
124
+ [R in keyof EndsOf<K>]: EndTargets<EndsOf<K>[R]>;
125
+ }[keyof EndsOf<K>] : never;
126
+ /** Роли модели. */
127
+ type RolesOf<K> = K extends unknown ? Extract<keyof EndsOf<K>, string> : never;
128
+ /** Модели подключения и встроенные системные (своя модель системного класса — вместо встроенной). */
129
+ type AllOf<M extends readonly AnyModelLike[]> = M[number] | Exclude<SystemModels[number], {
130
+ readonly name: NameOf<M[number]>;
131
+ }>;
132
+ /** Семейство класса C: сам класс и потомки (reg.family). */
133
+ type FamilyOf<C, All> = C extends unknown ? C | DescendantsOf<NameOf<C>, All> : never;
134
+ type DescendantsOf<N, All> = All extends unknown ? (N extends AncestorsOf<All> ? All : never) : never;
135
+ type FamTargets<C, All> = TargetsOf<FamilyOf<C, All>>;
136
+ type FamAncestors<C, All> = AncestorsOf<FamilyOf<C, All>>;
137
+ /**
138
+ * Связаны ли классы C и X концом: роль семейства C принимает класс семейства X (вперёд) или роль семейства X — класс
139
+ * семейства C (назад); конец принимает класс и его потомков (accepts).
140
+ */
141
+ type Linked<C, X, All> = [FamTargets<C, All> & FamAncestors<X, All>] extends [never] ? ([FamTargets<X, All> & FamAncestors<C, All>] extends [never] ? false : true) : true;
142
+ /** Классы, в которые ведёт шаг от C. */
143
+ type HopClasses<C, All> = HopClassesOf<C, All, All>;
144
+ type HopClassesOf<C, X, All> = X extends unknown ? (Linked<C, X, All> extends true ? X : never) : never;
145
+ /** Модель по имени или алиасу шага. */
146
+ type ByStepName<P, U> = U extends unknown ? (P extends StepNames<U> ? U : never) : never;
147
+ /** Классы целей роли R: имя роли однозначно во всей схеме (проверяет база). */
148
+ type RoleTargets<R, All> = All extends unknown ? (R extends RolesOf<All> ? EndTargets<EndsOf<All>[R & keyof EndsOf<All>]> : never) : never;
149
+ /** Модели классов T; класса нет среди моделей — только имя (строки без типов данных). */
150
+ type ModelsNamed<T, All> = (All extends unknown ? (NameOf<All> extends T ? All : never) : never) | BareOf<Exclude<T, NameOf<All>>>;
151
+ type BareOf<T> = T extends string ? {
152
+ readonly name: T;
153
+ } : never;
154
+ /**
155
+ * Анонимный тип объекта вместо интерфейса: у интерфейса (`<Класс>Data` из `letopis types`) нет неявной индексной
156
+ * сигнатуры, и без этого его строка не подошла бы туда, где ждут `Row` (`entity()`, `cursorOf()`).
157
+ */
158
+ type Plain<T> = {
159
+ [K in keyof T]: T[K];
160
+ };
22
161
  /** Строка ответа класса C. */
23
- export type RowOf<C> = Row<DataOf<C>, LinksOf<C>>;
162
+ export type RowOf<C> = C extends unknown ? Row<Plain<DataOf<C>>, Plain<LinksOf<C>>> : never;
24
163
  /** Фильтр по значению поля: равенство, оператор, вложенный объект любой глубины. */
25
164
  export type FieldFilterOf<T> = Op | (T extends readonly unknown[] ? T : T extends Record<string, unknown> ? {
26
165
  [P in keyof T]?: FieldFilterOf<T[P]>;
27
166
  } : T extends Scalar ? T | null : never);
28
- /** Фильтр шага класса C: id, список id, строка ответа, or(…) или объект полей и ролей. */
29
- export type FilterOf<C> = string | string[] | Op | {
30
- id: string;
31
- class: string;
32
- } | ({
167
+ /** Фильтр-объект класса C: поля данных, роли концов и id. */
168
+ type ObjectFilterOf<C> = C extends unknown ? {
33
169
  [P in keyof DataOf<C>]?: FieldFilterOf<DataOf<C>[P]>;
34
170
  } & {
35
171
  [R in keyof LinksOf<C>]?: string | {
@@ -37,26 +173,98 @@ export type FilterOf<C> = string | string[] | Op | {
37
173
  } | null;
38
174
  } & {
39
175
  id?: string | string[];
40
- });
41
- /** Шаги по именам и алиасам моделей M. */
42
- export type StepsOf<M extends readonly AnyModelLike[]> = {
43
- [K in M[number] as K['name']]: (filter?: FilterOf<K>) => TypedChain<K, M>;
176
+ } : never;
177
+ /**
178
+ * Результат `or(…)` (index.ts): оператор `or` и фильтры, которыми он типизирован; `F` — только для типов. В шаге класса C
179
+ * фильтры внутри `or()` — фильтры-объекты класса C.
180
+ */
181
+ export type OrOp<F = Record<string, unknown>> = Op & {
182
+ readonly [K in typeof OP]: 'or';
44
183
  } & {
45
- [K in M[number] as K extends ModelLike<string, unknown, unknown, infer A> ? (string extends A ? never : A) : never]: (filter?: FilterOf<K>) => TypedChain<K, M>;
184
+ readonly __filters?: F;
46
185
  };
186
+ /** Фильтр шага класса C: id, список id, строка ответа, or(…) из фильтров класса или объект полей и ролей. */
187
+ export type FilterOf<C> = string | string[] | {
188
+ id: string;
189
+ class: string;
190
+ } | OrOp<ObjectFilterOf<C>> | ObjectFilterOf<C>;
47
191
  /** Патч update: поля любой глубины необязательны; inc() — только у числовых полей (§2.5). */
48
192
  export type PatchOf<T> = {
49
193
  [P in keyof T]?: T[P] extends number | undefined ? T[P] | IncMarker : T[P] extends readonly unknown[] | undefined ? T[P] : T[P] extends Record<string, unknown> | undefined ? PatchOf<NonNullable<T[P]>> : T[P];
50
194
  };
51
- type Retyped = 'paths' | 'rows' | 'first' | 'versions' | 'limit' | 'offset' | 'sort' | 'asOf' | 'after' | 'withDeleted' | 'deep' | 'exact' | 'alias' | 'tags' | 'owner' | 'create' | 'update' | 'upsert' | 'delete' | 'anonymize' | 'reclass' | 'forUpdate' | 'restore' | 'purge' | 'rekey' | 'cache';
52
- /** Цепочка с текущим классом C: терминалы отдают RowOf<C>, шаги — по моделям M; роли и прочие классы — без типов. */
195
+ /** Счётчик глубины путей полей. */
196
+ type Depth = [never, 0, 1, 2, 3, 4, 5];
197
+ /** Пути полей данных через точку — без элементов массивов. */
198
+ type FieldPaths<T, D extends number = 6> = [D] extends [never] ? never : T extends readonly unknown[] ? never : T extends object ? {
199
+ [K in keyof T & string]-?: K | `${K}.${FieldPaths<NonNullable<T[K]>, Depth[D]>}`;
200
+ }[keyof T & string] : never;
201
+ /** Пути числовых полей (и полей без типа). */
202
+ type NumberPaths<T, D extends number = 6> = [D] extends [never] ? never : T extends readonly unknown[] ? never : T extends object ? {
203
+ [K in keyof T & string]-?: (unknown extends T[K] ? K : NonNullable<T[K]> extends number ? K : never) | `${K}.${NumberPaths<NonNullable<T[K]>, Depth[D]>}`;
204
+ }[keyof T & string] : never;
205
+ /** Поле агрегата класса C: `'data.<путь>'`. */
206
+ type DataField<C> = `data.${FieldPaths<DataOf<C>>}`;
207
+ /** Числовое поле агрегата класса C (sum, avg). */
208
+ type NumberField<C> = `data.${NumberPaths<DataOf<C>>}`;
209
+ /** Шаг класса C: фильтр класса и цепочка с ним. */
210
+ type StepFnOf<C, M extends readonly AnyModelLike[]> = (filter?: FilterOf<C>) => TypedChain<C, M>;
211
+ /** Шаги корня: имена и алиасы моделей подключения и системных классов. */
212
+ export type StepsOf<M extends readonly AnyModelLike[]> = {
213
+ [K in AllOf<M> as NameOf<K>]: StepFnOf<K, M>;
214
+ } & {
215
+ [K in AllOf<M> as AliasOf<K>]: StepFnOf<K, M>;
216
+ };
217
+ /** Значение слота одиночного конца: id, строка ответа или цепочка. */
218
+ type SlotOne = string | {
219
+ readonly id: string;
220
+ } | ChainRef;
221
+ /** Значение слота множественного конца: ещё и список id или строк. */
222
+ type SlotMany = SlotOne | readonly (string | {
223
+ readonly id: string;
224
+ })[];
225
+ /** Слоты роли с концом S записываемой строки класса C. */
226
+ type SlotFns<S, C, M extends readonly AnyModelLike[]> = {
227
+ set(value: S extends {
228
+ many: true;
229
+ } ? SlotMany : SlotOne): TypedChain<C, M>;
230
+ } & (S extends {
231
+ many: false;
232
+ } ? unknown : {
233
+ add(value: SlotMany): TypedChain<C, M>;
234
+ remove(value: SlotMany): TypedChain<C, M>;
235
+ }) & (S extends {
236
+ required: true;
237
+ } ? unknown : {
238
+ unset(): TypedChain<C, M>;
239
+ });
240
+ /** Шаг от C по имени P: класс или алиас, связанный с C, или роль семейства C (имя роли, совпавшее с классом, — шаг класса). */
241
+ type HopStep<C, P, M extends readonly AnyModelLike[], All> = P extends StepNames<All> ? ([ByStepName<P, HopClasses<C, All>>] extends [never] ? unknown : StepFnOf<ByStepName<P, HopClasses<C, All>>, M>) : P extends RolesOf<FamilyOf<C, All>> ? StepFnOf<ModelsNamed<RoleTargets<P, All>, All>, M> : unknown;
242
+ /** Слоты имени P: только роль самого класса C. */
243
+ type HopSlots<C, P, M extends readonly AnyModelLike[]> = P extends keyof EndsOf<C> ? SlotFns<EndsOf<C>[P], C, M> : unknown;
244
+ /** Свойства-шаги цепочки класса C. */
245
+ type HopsOf<C, M extends readonly AnyModelLike[], All = AllOf<M>> = {
246
+ [P in StepNames<HopClasses<C, All>> | Exclude<RolesOf<FamilyOf<C, All>>, StepNames<All>> | Extract<keyof EndsOf<C>, string>]: HopStep<C, P, M, All> & HopSlots<C, P, M>;
247
+ };
248
+ type Retyped = 'paths' | 'rows' | 'first' | 'versions' | 'limit' | 'offset' | 'sort' | 'asOf' | 'after' | 'withDeleted' | 'deep' | 'exact' | 'alias' | 'tags' | 'owner' | 'create' | 'update' | 'upsert' | 'delete' | 'forUpdate' | 'restore' | 'cache' | 'sum' | 'avg' | 'min' | 'max' | 'countBy';
249
+ /**
250
+ * Цепочка с текущим классом C (у шага-роли с несколькими целями — их союз): терминалы отдают RowOf<C>, шаги — переходы
251
+ * из концов, слоты — роли C, агрегаты — поля C.
252
+ */
53
253
  export type TypedChain<C, M extends readonly AnyModelLike[]> = Omit<ChainCore, Retyped> & {
54
254
  paths(): Promise<Path[]>;
55
255
  rows(): Promise<RowOf<C>[]>;
56
256
  first(): Promise<RowOf<C> | null>;
57
- versions(opts?: {
58
- follow?: boolean;
59
- }): Promise<RowOf<C>[]>;
257
+ versions(): Promise<RowOf<C>[]>;
258
+ /** Сумма числового поля `'data.<путь>'` класса; нет ни одного значения — `null`. */
259
+ sum(field: NumberField<C>): Promise<number | null>;
260
+ /** Среднее числового поля `'data.<путь>'` класса; нет ни одного значения — `null`. */
261
+ avg(field: NumberField<C>): Promise<number | null>;
262
+ /** Наименьшее значение поля `'data.<путь>'` класса. */
263
+ min(field: DataField<C>): Promise<unknown>;
264
+ /** Наибольшее значение поля `'data.<путь>'` класса. */
265
+ max(field: DataField<C>): Promise<unknown>;
266
+ /** Сколько объектов с каждым значением поля `'data.<путь>'` класса. */
267
+ countBy(field: DataField<C>): Promise<Record<string, number>>;
60
268
  limit(n: number): TypedChain<C, M>;
61
269
  offset(n: number): TypedChain<C, M>;
62
270
  sort(field: 'at' | 'rev' | 'id' | `data.${string}`, dir?: 'asc' | 'desc' | boolean): TypedChain<C, M>;
@@ -73,40 +281,27 @@ export type TypedChain<C, M extends readonly AnyModelLike[]> = Omit<ChainCore, R
73
281
  create(data: Partial<DataOf<C>>, opts?: {
74
282
  reason?: string;
75
283
  }): TypedChain<C, M>;
284
+ /** Без фильтра, id, `tags()`, `owner()` и `limit()` у шагов — `invalid_query`; правка всех строк — `{ all: true }`. */
76
285
  update(patch?: PatchOf<DataOf<C>>, opts?: {
77
286
  rev?: number;
287
+ all?: boolean;
78
288
  reason?: string;
79
289
  }): TypedChain<C, M>;
80
290
  upsert(data: Partial<DataOf<C>>, opts?: {
81
291
  reason?: string;
82
292
  }): TypedChain<C, M>;
293
+ /** С `{ confirm: true }` без фильтра, id, `tags()`, `owner()` и `limit()` у шагов — `invalid_query`; всех — `{ all: true }`. */
83
294
  delete(opts?: {
84
295
  confirm?: boolean;
296
+ all?: boolean;
85
297
  reason?: string;
86
298
  }): TypedChain<C, M>;
87
- anonymize(fields: (keyof DataOf<C> & string)[], opts?: {
88
- reason?: string;
89
- }): TypedChain<C, M>;
90
- reclass(cls: string, data?: Record<string, unknown>, opts?: {
91
- reason?: string;
92
- }): TypedChain<unknown, M>;
93
299
  forUpdate(): TypedChain<C, M>;
94
300
  restore(opts?: {
95
301
  reason?: string;
96
302
  }): TypedChain<C, M>;
97
- purge(opts?: {
98
- confirm?: boolean;
99
- reason?: string;
100
- }): TypedChain<C, M>;
101
- rekey(patch: Partial<DataOf<C>> & Partial<Record<keyof LinksOf<C>, string | {
102
- id: string;
103
- }>>, opts?: {
104
- reason?: string;
105
- }): TypedChain<C, M>;
106
303
  cache(opts?: {
107
304
  ttl?: number;
108
305
  }): TypedChain<C, M>;
109
- } & StepsOf<M> & {
110
- [step: string]: StepFn;
111
- };
306
+ } & HopsOf<C, M>;
112
307
  export {};
package/dist/types.d.ts CHANGED
@@ -3,35 +3,36 @@
3
3
  */
4
4
  /**
5
5
  * Ревизия схемы, которую знает эта версия пакета, — номер версии SQL-части letopis (таблиц и функций в схеме установки).
6
- * После `up()` у схемы та же ревизия (`r.revision`); схему отставшей ревизии `up()` обновляет только с `upgrade: true`,
7
- * а `connect()` о ней предупреждает.
6
+ * После `up()` у схемы та же ревизия (`r.revision`); схему отставшей ревизии 2.x `up()` обновляет только с
7
+ * `upgrade: true`, а `connect()` о ней предупреждает.
8
8
  */
9
- export declare const DDL_REVISION = 7;
9
+ export declare const DDL_REVISION = 8;
10
10
  /**
11
11
  * Классы, строки которых меняют права и схему: их запись повышает счётчик прав (загрузчик), а сигнал
12
12
  * сбрасывает весь кэш результатов и пропуска прав. Тот же список — в триггерах базы (60-write.sql).
13
13
  */
14
14
  export declare const ACL_CLASS_NAMES: readonly string[];
15
15
  /**
16
- * Имена методов цепочки: модификаторы, терминалы, глаголы записи и слоты концов, а также `then` и снятые методы прежних
17
- * версий. После шага цепочки эти имена библиотека не ищет среди классов; все они входят в `RESERVED_CLASS_NAMES`.
16
+ * Имена методов цепочки: модификаторы, терминалы, глаголы записи и слоты концов, а также `then`. После шага цепочки эти
17
+ * имена библиотека не ищет среди классов; все они входят в `RESERVED_CLASS_NAMES`.
18
18
  */
19
- 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", "diff", "blame"];
19
+ 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", "restore", "alias", "tags", "owner", "forUpdate", "cache"];
20
20
  /** Свойства корня db (и транзакции db.begin()). */
21
- 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", "projector", "rebuildAggregates"];
21
+ export declare const DB_METHODS: readonly ["as", "begin", "commit", "rollback", "lock", "batch", "watch", "close", "registry", "sql", "load", "maintain", "auth", "acl", "idOf", "refresh", "transaction", "flushSignals", "schema", "token", "tenant", "cache"];
22
22
  /** Свойства батча db.batch(name). */
23
- export declare const BATCH_METHODS: readonly ["discard", "size"];
23
+ export declare const BATCH_METHODS: readonly ["run", "discard", "size"];
24
24
  /**
25
25
  * Имена методов цепочки, корня `db` и батча. Там, где имя занято методом, библиотека не ищет его среди классов, и шаг с
26
- * таким именем до класса не дойдёт; класс-связь (`link`) с таким именем база не создаст (`invalid_class`). Не давайте
27
- * классам эти имена.
26
+ * таким именем до класса не дойдёт. Хаб с таким именем отклоняют `hub()`, `syncModels` и база, связь (`link`) — база
27
+ * (`invalid_class`; план 2.0, этап 4, п. 2); хаб, заведённый мимо проверки базы, `up()` оставляет и называет в
28
+ * предупреждении.
28
29
  */
29
30
  export declare const RESERVED_CLASS_NAMES: readonly string[];
30
31
  /** Строка ответа: текущая версия (или версия журнала для asOf, versions, withDeleted). */
31
32
  export interface Row<D = Record<string, unknown>, L = Record<string, string | string[]>> {
32
33
  id: string;
33
34
  class: string;
34
- /** Номер версии — для update(patch, { rev }) (этап 4). */
35
+ /** Номер версии — для update(patch, { rev }). */
35
36
  rev: number;
36
37
  tenant: string;
37
38
  owner: string;
@@ -42,23 +43,17 @@ export interface Row<D = Record<string, unknown>, L = Record<string, string | st
42
43
  at: string;
43
44
  author: string;
44
45
  agent?: string;
45
- /** Вид операции версии: create, update, delete, reclass, … */
46
+ /** Вид операции версии: create, update, delete, restore, … */
46
47
  op: string;
47
48
  reason?: string;
48
- /** Связь со старым или новым id при reclass и rekey. */
49
- moved?: string;
50
49
  /** Надгробие: удалённая сущность (withDeleted) или версия удаления (versions). */
51
50
  $deleted?: true;
52
51
  /** Глубина узла при deep() (1 — прямой потомок); в превью удаления — уровень каскада (0 — цель). */
53
52
  $depth?: number;
54
- /** Что сделал upsert (этап 4). */
53
+ /** Что сделал upsert. */
55
54
  $upsert?: 'created' | 'updated' | 'unchanged';
56
55
  /** Превью удаления (delete() без confirm): удалится, снимется конец или помешает (restrict). */
57
56
  $action?: 'delete' | 'unset' | 'restrict';
58
- /** purge(): число версий в журнале (превью) или стёртых. */
59
- $versions?: number;
60
- /** purge({ confirm: true }): история стёрта. */
61
- $purged?: true;
62
57
  }
63
58
  /** Путь paths(): узел на каждый шаг цепочки. */
64
59
  export type Path = Record<string, Row>;
@@ -85,10 +80,17 @@ export type Filter = string | string[] | Op | {
85
80
  } | {
86
81
  [field: string]: FieldFilter | undefined;
87
82
  };
88
- /** Курсор постраничного вывода для `after()`: значение поля сортировки и id последней строки страницы. */
83
+ /**
84
+ * Курсор постраничного вывода для `after()`: значение поля сортировки и id последней строки страницы. Равные по полю
85
+ * строки разводят `rev` (версии в `versions()`) и `path` (id всех узлов пути в `paths()`); `cursorOf` заполняет их сам.
86
+ */
89
87
  export interface Cursor {
90
88
  v: string | number | boolean | null;
91
89
  id: string;
90
+ /** Номер версии строки: в `versions()` отделяет версии одного объекта с равным полем сортировки. */
91
+ rev?: number;
92
+ /** Узлы пути из `paths()`: ключ узла → id; отделяет пути с общим последним узлом. */
93
+ path?: Record<string, string>;
92
94
  }
93
95
  /** Модификаторы выборки цепочки. */
94
96
  export interface ChainMods {
@@ -104,24 +106,14 @@ export interface ChainMods {
104
106
  withDeleted?: boolean;
105
107
  /** Чтение с блокировкой строк последнего шага (только в db.begin()). */
106
108
  forUpdate?: boolean;
107
- /** versions({ follow: true }): история и через смену id (reclass, rekey) по колонке moved. */
108
- follow?: boolean;
109
109
  /** Кэш результатов (§2.12): .cache() — срок по умолчанию, .cache({ ttl }) — свой, секунды. */
110
110
  cache?: {
111
111
  ttl?: number;
112
112
  };
113
- /** Параметры терминалов diff() и blame() (план 1.1, §2.1): номера версий или моменты (ISO). */
114
- hist?: {
115
- from?: number | string;
116
- to?: number | string;
117
- at?: string;
118
- follow?: boolean;
119
- limit?: number;
120
- };
121
113
  }
122
114
  /** Событие хука onQuery: один запрос цепочки. */
123
115
  export interface QueryEvent {
124
- mode: 'paths' | 'rows' | 'ids' | 'count' | 'versions' | 'agg' | 'diff' | 'blame';
116
+ mode: 'paths' | 'rows' | 'ids' | 'count' | 'versions' | 'agg';
125
117
  /** Классы шагов цепочки. */
126
118
  classes: string[];
127
119
  ms: number;
@@ -129,63 +121,3 @@ export interface QueryEvent {
129
121
  /** ms > slowMs. */
130
122
  slow: boolean;
131
123
  }
132
- /** Изменение пути: added — не было, removed — не стало, changed — другое значение. */
133
- export interface DiffChange {
134
- /** Путь: первый сегмент — раздел строки (data, links, tags, owner, class). */
135
- path: string[];
136
- kind: 'added' | 'removed' | 'changed';
137
- before?: unknown;
138
- after?: unknown;
139
- }
140
- /** Различия объекта между двумя версиями (diff()). */
141
- export interface DiffResult {
142
- id: string;
143
- class: string | null;
144
- from: {
145
- rev: number;
146
- at: string;
147
- id?: string;
148
- } | null;
149
- to: {
150
- rev: number;
151
- at: string;
152
- id?: string;
153
- deleted?: true;
154
- } | null;
155
- changes: DiffChange[];
156
- }
157
- /** Кто и почему последним изменил лист версии (blame()). */
158
- export interface BlameField {
159
- path: string[];
160
- rev: number;
161
- at: string;
162
- author: string;
163
- agent?: string;
164
- op: string;
165
- reason?: string;
166
- /** Другой id (история прошла через смену id при reclass или rekey). */
167
- id?: string;
168
- /** false — до найденной версии история неполная: изменение могло быть раньше. */
169
- exact: boolean;
170
- }
171
- /** Поля версии объекта с версиями, которые их изменили (blame()). */
172
- export interface BlameResult {
173
- id: string;
174
- class: string;
175
- rev: number;
176
- deleted?: true;
177
- /** История просмотрена целиком и без пропусков. */
178
- complete: boolean;
179
- fields: BlameField[];
180
- }
181
- /** diff(): «до» и «после» — номер версии или момент (ISO-строка, Date); follow — через смену id. */
182
- export interface DiffOptions {
183
- from?: number | string | Date;
184
- to?: number | string | Date;
185
- follow?: boolean;
186
- }
187
- /** blame(): версия на момент at (по умолчанию текущая); limit — сколько версий просматривать (1000). */
188
- export interface BlameOptions {
189
- at?: string | Date;
190
- limit?: number;
191
- }
package/dist/types.js CHANGED
@@ -3,10 +3,10 @@
3
3
  */
4
4
  /**
5
5
  * Ревизия схемы, которую знает эта версия пакета, — номер версии SQL-части letopis (таблиц и функций в схеме установки).
6
- * После `up()` у схемы та же ревизия (`r.revision`); схему отставшей ревизии `up()` обновляет только с `upgrade: true`,
7
- * а `connect()` о ней предупреждает.
6
+ * После `up()` у схемы та же ревизия (`r.revision`); схему отставшей ревизии 2.x `up()` обновляет только с
7
+ * `upgrade: true`, а `connect()` о ней предупреждает.
8
8
  */
9
- export const DDL_REVISION = 7;
9
+ export const DDL_REVISION = 8;
10
10
  /**
11
11
  * Классы, строки которых меняют права и схему: их запись повышает счётчик прав (загрузчик), а сигнал
12
12
  * сбрасывает весь кэш результатов и пропуска прав. Тот же список — в триггерах базы (60-write.sql).
@@ -16,28 +16,26 @@ export const ACL_CLASS_NAMES = ['rule', 'Resource', 'member', 'Account', 'Class'
16
16
  // Методы цепочки — единственный источник зарезервированных имён (план, §2.14, этап 3, п. 10)
17
17
  // ---------------------------------------------------------------------------
18
18
  /**
19
- * Имена методов цепочки: модификаторы, терминалы, глаголы записи и слоты концов, а также `then` и снятые методы прежних
20
- * версий. После шага цепочки эти имена библиотека не ищет среди классов; все они входят в `RESERVED_CLASS_NAMES`.
19
+ * Имена методов цепочки: модификаторы, терминалы, глаголы записи и слоты концов, а также `then`. После шага цепочки эти
20
+ * имена библиотека не ищет среди классов; все они входят в `RESERVED_CLASS_NAMES`.
21
21
  */
22
22
  export const CHAIN_METHODS = [
23
23
  'then', 'entity', 'paths', 'rows', 'first', 'ids', 'count', 'limit', 'offset', 'sort', 'asOf', 'withDeleted',
24
24
  'deep', 'exact', 'sum', 'avg', 'min', 'max', 'countBy', 'after', 'versions', 'create', 'update', 'upsert', 'set',
25
- 'unset', 'add', 'remove', 'delete', 'anonymize', 'reclass', 'restore', 'purge', 'alias', 'tags', 'owner',
26
- 'forUpdate', 'cache', 'rekey', 'run', 'execute', 'account', 'diff', 'blame',
25
+ 'unset', 'add', 'remove', 'delete', 'restore', 'alias', 'tags', 'owner', 'forUpdate', 'cache',
27
26
  ];
28
27
  /** Свойства корня db (и транзакции db.begin()). */
29
28
  export const DB_METHODS = [
30
- 'as', 'begin', 'commit', 'rollback', 'lock', 'batch', 'watch', 'close', 'registry', 'sql', 'load', 'verify',
31
- 'maintain', 'reset', 'describe', 'auth', 'acl', 'idOf', 'refresh', 'transaction', 'flushSignals', 'schema',
32
- 'token', 'tenant', 'reloadSchema', 'accounts', 'credentials', 'resources', 'rules', 'compact',
33
- 'trimHistory', 'rekeyClass', 'cache', 'projector', 'rebuildAggregates',
29
+ 'as', 'begin', 'commit', 'rollback', 'lock', 'batch', 'watch', 'close', 'registry', 'sql', 'load',
30
+ 'maintain', 'auth', 'acl', 'idOf', 'refresh', 'transaction', 'flushSignals', 'schema', 'token', 'tenant', 'cache',
34
31
  ];
35
32
  /** Свойства батча db.batch(name). */
36
- export const BATCH_METHODS = ['discard', 'size'];
33
+ export const BATCH_METHODS = ['run', 'discard', 'size'];
37
34
  /**
38
35
  * Имена методов цепочки, корня `db` и батча. Там, где имя занято методом, библиотека не ищет его среди классов, и шаг с
39
- * таким именем до класса не дойдёт; класс-связь (`link`) с таким именем база не создаст (`invalid_class`). Не давайте
40
- * классам эти имена.
36
+ * таким именем до класса не дойдёт. Хаб с таким именем отклоняют `hub()`, `syncModels` и база, связь (`link`) — база
37
+ * (`invalid_class`; план 2.0, этап 4, п. 2); хаб, заведённый мимо проверки базы, `up()` оставляет и называет в
38
+ * предупреждении.
41
39
  */
42
40
  export const RESERVED_CLASS_NAMES = [...new Set([...CHAIN_METHODS, ...DB_METHODS, ...BATCH_METHODS])];
43
41
  /** Метка операторов фильтра (символ не пересекается с данными). */