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.
- package/AGENT-CHEATSHEET.md +516 -398
- package/CHANGELOG.md +739 -0
- package/LICENSE +75 -21
- package/LICENSE-COMMERCIAL.md +49 -0
- package/README.md +1312 -1190
- package/api-contract.json +381 -0
- package/dist/acl.d.ts +81 -1
- package/dist/acl.js +281 -13
- package/dist/admin.d.ts +11 -141
- package/dist/admin.js +28 -186
- package/dist/auth.d.ts +20 -5
- package/dist/auth.js +80 -21
- package/dist/cache.d.ts +8 -1
- package/dist/cache.js +30 -8
- package/dist/chain.d.ts +46 -48
- package/dist/chain.js +556 -223
- package/dist/cli.js +73 -96
- 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 +77 -13
- package/dist/errors.js +231 -30
- package/dist/index.d.ts +62 -74
- package/dist/index.js +312 -155
- package/dist/internal.d.ts +7 -0
- package/dist/jsonschema.js +18 -17
- package/dist/load.d.ts +29 -17
- package/dist/load.js +235 -190
- package/dist/log.d.ts +121 -0
- package/dist/log.js +633 -0
- package/dist/mcp.d.ts +5 -7
- package/dist/mcp.js +194 -225
- package/dist/messages/access.d.ts +90 -0
- package/dist/messages/access.js +113 -0
- package/dist/messages/api.d.ts +237 -0
- package/dist/messages/api.js +304 -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 +98 -0
- package/dist/messages/index.js +121 -0
- package/dist/messages/log.d.ts +229 -0
- package/dist/messages/log.js +102 -0
- package/dist/messages/mcp.d.ts +306 -0
- package/dist/messages/mcp.js +387 -0
- package/dist/messages/model.d.ts +256 -0
- package/dist/messages/model.js +314 -0
- package/dist/messages/query.d.ts +141 -0
- package/dist/messages/query.js +171 -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 +164 -0
- package/dist/messages/sql-core.js +198 -0
- package/dist/messages/sql-time.d.ts +86 -0
- package/dist/messages/sql-time.js +111 -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 +452 -0
- package/dist/messages/write.js +572 -0
- package/dist/model.d.ts +77 -60
- package/dist/model.js +43 -34
- 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 +9 -1
- package/dist/sql.js +175 -107
- package/dist/sync.d.ts +10 -4
- package/dist/sync.js +90 -17
- package/dist/tx.d.ts +21 -2
- package/dist/tx.js +76 -13
- package/dist/typed.d.ts +252 -53
- package/dist/types.d.ts +93 -90
- package/dist/types.js +17 -14
- package/dist/up.d.ts +56 -35
- package/dist/up.js +229 -83
- package/dist/uuid.d.ts +8 -0
- package/dist/uuid.js +14 -6
- package/dist/validate.d.ts +13 -1
- package/dist/validate.js +82 -33
- package/dist/watch.d.ts +10 -16
- package/dist/watch.js +36 -77
- package/dist/write.d.ts +87 -17
- package/dist/write.js +441 -206
- package/llms.txt +48 -31
- package/package.json +13 -14
- package/sql/10-core.sql +7 -50
- package/sql/15-errors.sql +64 -10
- package/sql/20-context.sql +18 -9
- package/sql/30-validate.sql +79 -30
- package/sql/40-class.sql +41 -115
- 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 +109 -42
- package/sql/90-time.sql +108 -947
- package/sql/95-seed.system.sql +7 -14
- package/sql/99-revision.sql +6 -1
- package/sql/README.md +32 -24
- package/sql/migrate/0009-restore-rev.tenants-name.sql +10 -0
- package/sql/migrate/0010-impersonation-no-account.sql +5 -0
- package/sql/migrate/0011-key-lock.otp-enabled.sql +7 -0
- package/sql/migrate/README.md +18 -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/dist/typed.d.ts
CHANGED
|
@@ -1,35 +1,171 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
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,
|
|
8
|
-
import type { Cursor, Op, Path, Row, Scalar } from './types.js';
|
|
9
|
-
import type { IncMarker } from './write.js';
|
|
10
|
-
/**
|
|
11
|
-
|
|
17
|
+
import type { ChainCore, ChainRef } from './chain.js';
|
|
18
|
+
import type { Cursor, Op, OP, Path, Row, Scalar } from './types.js';
|
|
19
|
+
import type { DeleteOptions, IncMarker, RestoreOptions } from './write.js';
|
|
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
|
-
|
|
21
|
-
type
|
|
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
|
|
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
|
-
/**
|
|
29
|
-
|
|
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
|
-
/**
|
|
42
|
-
|
|
43
|
-
|
|
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
|
-
|
|
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
|
-
|
|
52
|
-
|
|
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(
|
|
58
|
-
|
|
59
|
-
|
|
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,31 @@ 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>;
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}): TypedChain<C, M>;
|
|
90
|
-
reclass(cls: string, data?: Record<string, unknown>, opts?: {
|
|
91
|
-
reason?: string;
|
|
92
|
-
}): TypedChain<unknown, M>;
|
|
293
|
+
/**
|
|
294
|
+
* Без опций — превью. `{ confirm: true, expect: превью }` — удалить ровно показанное (цели сужены фильтром, id, `tags()`,
|
|
295
|
+
* `owner()` или `limit()`); `{ confirm: true }` без `expect` — `invalid_query` (`write.confirm_without_expect`);
|
|
296
|
+
* осознанно удалить текущий состав без сверки — `{ confirm: true, all: true }`.
|
|
297
|
+
*/
|
|
298
|
+
delete(opts?: DeleteOptions): TypedChain<C, M>;
|
|
93
299
|
forUpdate(): TypedChain<C, M>;
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
rekey(patch: Partial<DataOf<C>> & Partial<Record<keyof LinksOf<C>, string | {
|
|
102
|
-
id: string;
|
|
103
|
-
}>>, opts?: {
|
|
104
|
-
reason?: string;
|
|
105
|
-
}): TypedChain<C, M>;
|
|
300
|
+
/**
|
|
301
|
+
* `{ expect }` — надгробия `{ id, rev }`: восстановить ровно то, что ушло удалением; расхождение — отказ по смыслу
|
|
302
|
+
* (`write.restore_already`, `write.restore_id_taken`, `write.restore_stale`). `{ expect, partial: true }` — что можно, а
|
|
303
|
+
* остальное — строки `$action: 'skip'` с причиной `$why`. Без `expect` — `invalid_query` (`write.restore_without_expect`);
|
|
304
|
+
* осознанно вернуть все удалённые цели шага без сверки — `{ all: true }`.
|
|
305
|
+
*/
|
|
306
|
+
restore(opts: RestoreOptions): TypedChain<C, M>;
|
|
106
307
|
cache(opts?: {
|
|
107
308
|
ttl?: number;
|
|
108
309
|
}): TypedChain<C, M>;
|
|
109
|
-
} &
|
|
110
|
-
[step: string]: StepFn;
|
|
111
|
-
};
|
|
310
|
+
} & HopsOf<C, M>;
|
|
112
311
|
export {};
|
package/dist/types.d.ts
CHANGED
|
@@ -3,35 +3,41 @@
|
|
|
3
3
|
*/
|
|
4
4
|
/**
|
|
5
5
|
* Ревизия схемы, которую знает эта версия пакета, — номер версии SQL-части letopis (таблиц и функций в схеме установки).
|
|
6
|
-
* После `up()` у схемы та же ревизия (`r.revision`); схему отставшей ревизии `up()` обновляет только с
|
|
7
|
-
* а `connect()` о ней предупреждает.
|
|
6
|
+
* После `up()` у схемы та же ревизия (`r.revision`); схему отставшей ревизии 2.x `up()` обновляет только с
|
|
7
|
+
* `upgrade: true`, а `connect()` о ней предупреждает.
|
|
8
8
|
*/
|
|
9
|
-
export declare const DDL_REVISION =
|
|
9
|
+
export declare const DDL_REVISION = 11;
|
|
10
|
+
/**
|
|
11
|
+
* Префикс версии в имени схемы `v<N>.<имя>`: `up({ schema: 'salon' })` и `connect({ schema: 'salon' })` дописывают его к
|
|
12
|
+
* имени без точки — `v2.salon`.
|
|
13
|
+
*/
|
|
14
|
+
export declare const SCHEMA_VERSION = "v2";
|
|
10
15
|
/**
|
|
11
16
|
* Классы, строки которых меняют права и схему: их запись повышает счётчик прав (загрузчик), а сигнал
|
|
12
17
|
* сбрасывает весь кэш результатов и пропуска прав. Тот же список — в триггерах базы (60-write.sql).
|
|
13
18
|
*/
|
|
14
19
|
export declare const ACL_CLASS_NAMES: readonly string[];
|
|
15
20
|
/**
|
|
16
|
-
* Имена методов цепочки: модификаторы, терминалы, глаголы записи и слоты концов, а также `then
|
|
17
|
-
*
|
|
21
|
+
* Имена методов цепочки: модификаторы, терминалы, глаголы записи и слоты концов, а также `then`. После шага цепочки эти
|
|
22
|
+
* имена библиотека не ищет среди классов; все они входят в `RESERVED_CLASS_NAMES`.
|
|
18
23
|
*/
|
|
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", "
|
|
24
|
+
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
25
|
/** Свойства корня db (и транзакции db.begin()). */
|
|
21
|
-
export declare const DB_METHODS: readonly ["as", "begin", "commit", "rollback", "lock", "batch", "watch", "close", "registry", "sql", "load", "
|
|
26
|
+
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
27
|
/** Свойства батча db.batch(name). */
|
|
23
|
-
export declare const BATCH_METHODS: readonly ["discard", "size"];
|
|
28
|
+
export declare const BATCH_METHODS: readonly ["run", "discard", "size"];
|
|
24
29
|
/**
|
|
25
30
|
* Имена методов цепочки, корня `db` и батча. Там, где имя занято методом, библиотека не ищет его среди классов, и шаг с
|
|
26
|
-
* таким именем до класса не
|
|
27
|
-
*
|
|
31
|
+
* таким именем до класса не дойдёт. Хаб с таким именем отклоняют `hub()`, `syncModels` и база, связь (`link`) — база
|
|
32
|
+
* (`invalid_class`; план 2.0, этап 4, п. 2); хаб, заведённый мимо проверки базы, `up()` оставляет и называет в
|
|
33
|
+
* предупреждении.
|
|
28
34
|
*/
|
|
29
35
|
export declare const RESERVED_CLASS_NAMES: readonly string[];
|
|
30
36
|
/** Строка ответа: текущая версия (или версия журнала для asOf, versions, withDeleted). */
|
|
31
37
|
export interface Row<D = Record<string, unknown>, L = Record<string, string | string[]>> {
|
|
32
38
|
id: string;
|
|
33
39
|
class: string;
|
|
34
|
-
/** Номер версии — для update(patch, { rev })
|
|
40
|
+
/** Номер версии — для update(patch, { rev }). */
|
|
35
41
|
rev: number;
|
|
36
42
|
tenant: string;
|
|
37
43
|
owner: string;
|
|
@@ -42,23 +48,25 @@ export interface Row<D = Record<string, unknown>, L = Record<string, string | st
|
|
|
42
48
|
at: string;
|
|
43
49
|
author: string;
|
|
44
50
|
agent?: string;
|
|
45
|
-
/** Вид операции версии: create, update, delete,
|
|
51
|
+
/** Вид операции версии: create, update, delete, restore, … */
|
|
46
52
|
op: string;
|
|
47
53
|
reason?: string;
|
|
48
|
-
/** Связь со старым или новым id при reclass и rekey. */
|
|
49
|
-
moved?: string;
|
|
50
54
|
/** Надгробие: удалённая сущность (withDeleted) или версия удаления (versions). */
|
|
51
55
|
$deleted?: true;
|
|
52
56
|
/** Глубина узла при deep() (1 — прямой потомок); в превью удаления — уровень каскада (0 — цель). */
|
|
53
57
|
$depth?: number;
|
|
54
|
-
/** Что сделал upsert
|
|
58
|
+
/** Что сделал upsert. */
|
|
55
59
|
$upsert?: 'created' | 'updated' | 'unchanged';
|
|
56
|
-
/**
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
/**
|
|
61
|
+
* Превью удаления (delete() без confirm): удалится, снимется конец или помешает (restrict). В ответе
|
|
62
|
+
* `restore({ expect, partial: true })` — `skip`: цель не восстановлена, причина — `$why`.
|
|
63
|
+
*/
|
|
64
|
+
$action?: 'delete' | 'unset' | 'restrict' | 'skip';
|
|
65
|
+
/**
|
|
66
|
+
* Почему цель `restore({ expect, partial: true })` не восстановлена: `restored` — её уже восстановили, `reissued` — id
|
|
67
|
+
* занял новый объект с тем же ключом, `changed` — после показанного удаления её меняли (удалили снова и т. п.).
|
|
68
|
+
*/
|
|
69
|
+
$why?: 'restored' | 'reissued' | 'changed';
|
|
62
70
|
}
|
|
63
71
|
/** Путь paths(): узел на каждый шаг цепочки. */
|
|
64
72
|
export type Path = Record<string, Row>;
|
|
@@ -107,28 +115,21 @@ export interface ChainMods {
|
|
|
107
115
|
/** Срез «как было на момент T» (ISO). */
|
|
108
116
|
asOf?: string;
|
|
109
117
|
after?: Cursor;
|
|
110
|
-
/**
|
|
118
|
+
/**
|
|
119
|
+
* Не действует: с 2.1 `withDeleted()` — модификатор своего шага (флаг шага цепочки), а не всей выборки. Поле оставлено,
|
|
120
|
+
* чтобы тип не менялся.
|
|
121
|
+
*/
|
|
111
122
|
withDeleted?: boolean;
|
|
112
123
|
/** Чтение с блокировкой строк последнего шага (только в db.begin()). */
|
|
113
124
|
forUpdate?: boolean;
|
|
114
|
-
/** versions({ follow: true }): история и через смену id (reclass, rekey) по колонке moved. */
|
|
115
|
-
follow?: boolean;
|
|
116
125
|
/** Кэш результатов (§2.12): .cache() — срок по умолчанию, .cache({ ttl }) — свой, секунды. */
|
|
117
126
|
cache?: {
|
|
118
127
|
ttl?: number;
|
|
119
128
|
};
|
|
120
|
-
/** Параметры терминалов diff() и blame() (план 1.1, §2.1): номера версий или моменты (ISO). */
|
|
121
|
-
hist?: {
|
|
122
|
-
from?: number | string;
|
|
123
|
-
to?: number | string;
|
|
124
|
-
at?: string;
|
|
125
|
-
follow?: boolean;
|
|
126
|
-
limit?: number;
|
|
127
|
-
};
|
|
128
129
|
}
|
|
129
130
|
/** Событие хука onQuery: один запрос цепочки. */
|
|
130
131
|
export interface QueryEvent {
|
|
131
|
-
mode: 'paths' | 'rows' | 'ids' | 'count' | 'versions' | 'agg'
|
|
132
|
+
mode: 'paths' | 'rows' | 'ids' | 'count' | 'versions' | 'agg';
|
|
132
133
|
/** Классы шагов цепочки. */
|
|
133
134
|
classes: string[];
|
|
134
135
|
ms: number;
|
|
@@ -136,63 +137,65 @@ export interface QueryEvent {
|
|
|
136
137
|
/** ms > slowMs. */
|
|
137
138
|
slow: boolean;
|
|
138
139
|
}
|
|
139
|
-
/**
|
|
140
|
-
export
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
exact: boolean;
|
|
177
|
-
}
|
|
178
|
-
/** Поля версии объекта с версиями, которые их изменили (blame()). */
|
|
179
|
-
export interface BlameResult {
|
|
180
|
-
id: string;
|
|
181
|
-
class: string;
|
|
182
|
-
rev: number;
|
|
183
|
-
deleted?: true;
|
|
184
|
-
/** История просмотрена целиком и без пропусков. */
|
|
185
|
-
complete: boolean;
|
|
186
|
-
fields: BlameField[];
|
|
140
|
+
/** Порог логирования: события этого уровня и выше; `'off'` — ничего. */
|
|
141
|
+
export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'off';
|
|
142
|
+
/** Событие логирования (каталог событий — lib/src/messages/log.ts). Поля без значения в событии отсутствуют. */
|
|
143
|
+
export interface LogEvent {
|
|
144
|
+
/** Время события, ISO 8601 (UTC). */
|
|
145
|
+
ts: string;
|
|
146
|
+
level: Exclude<LogLevel, 'off'>;
|
|
147
|
+
/** Имя события: connect, read, write, delete, error, sql и др. */
|
|
148
|
+
event: string;
|
|
149
|
+
/** Операция: терминал или глагол цепочки, метод db, auth, acl, инструмент MCP. */
|
|
150
|
+
op?: string;
|
|
151
|
+
/** Длительность операции, мс (с точностью до 0,1). */
|
|
152
|
+
ms?: number;
|
|
153
|
+
/** Арендатор сессии фасада. */
|
|
154
|
+
tenant?: string;
|
|
155
|
+
/** Аккаунт фасада: аккаунт сессии или тот, от чьего имени действует db.as(). */
|
|
156
|
+
account?: string;
|
|
157
|
+
/** Метка транзакции db.begin() или db.transaction(). */
|
|
158
|
+
tx?: string;
|
|
159
|
+
/** Цепочка в читаемом виде: `Shop({"name":"A"}).Product.limit(10).rows()`; данные записи — только именами полей. */
|
|
160
|
+
chain?: string;
|
|
161
|
+
/** Строк в ответе или затронуто. */
|
|
162
|
+
rows?: number;
|
|
163
|
+
/** Код ошибки letopis (или SQLSTATE ошибки базы) — у error. */
|
|
164
|
+
code?: string;
|
|
165
|
+
/** Ключ каталога сообщений — у error и warning. */
|
|
166
|
+
key?: string;
|
|
167
|
+
/** Текст ошибки или предупреждения. */
|
|
168
|
+
msg?: string;
|
|
169
|
+
/** Подробности события; секреты замаскированы. */
|
|
170
|
+
detail?: Record<string, unknown>;
|
|
171
|
+
/** Причина ошибки (исходная ошибка базы и т. п.) — у error. */
|
|
172
|
+
cause?: {
|
|
173
|
+
name?: string;
|
|
174
|
+
message: string;
|
|
175
|
+
code?: string;
|
|
176
|
+
};
|
|
187
177
|
}
|
|
188
|
-
/**
|
|
189
|
-
export
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
178
|
+
/** Логгер-функция. */
|
|
179
|
+
export type LogFn = (event: LogEvent) => unknown;
|
|
180
|
+
/** Логгер-объект: pino, console и подобные — вызов `logger[уровень](событие, событие.event)`. */
|
|
181
|
+
export interface LogObject {
|
|
182
|
+
debug?(event: LogEvent, msg: string): unknown;
|
|
183
|
+
info?(event: LogEvent, msg: string): unknown;
|
|
184
|
+
warn?(event: LogEvent, msg: string): unknown;
|
|
185
|
+
error?(event: LogEvent, msg: string): unknown;
|
|
186
|
+
log?(event: LogEvent, msg: string): unknown;
|
|
193
187
|
}
|
|
194
|
-
/**
|
|
195
|
-
export
|
|
196
|
-
|
|
197
|
-
|
|
188
|
+
/** Логгер: функция или объект с методами уровней. */
|
|
189
|
+
export type Logger = LogFn | LogObject;
|
|
190
|
+
/** Опции логирования connect() и up(). */
|
|
191
|
+
export interface LogOptions {
|
|
192
|
+
/**
|
|
193
|
+
* Логгер: функция `(событие) => void` или объект с методами `debug`, `info`, `warn`, `error` (pino, console). Без него
|
|
194
|
+
* и с переменной окружения `LETOPIS_LOG=<уровень>` события идут JSON-строками в stderr.
|
|
195
|
+
*/
|
|
196
|
+
log?: Logger;
|
|
197
|
+
/** Порог: `'debug' | 'info' | 'warn' | 'error' | 'off'`, по умолчанию `'info'` (или уровень из `LETOPIS_LOG`). */
|
|
198
|
+
logLevel?: LogLevel;
|
|
199
|
+
/** Ещё имена полей, значения которых маскируются в событиях (пароли, токены и ключи маскируются всегда). */
|
|
200
|
+
redact?: readonly string[];
|
|
198
201
|
}
|