letopis 1.4.2 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/AGENT-CHEATSHEET.md +516 -398
  2. package/CHANGELOG.md +739 -0
  3. package/LICENSE +75 -21
  4. package/LICENSE-COMMERCIAL.md +49 -0
  5. package/README.md +1312 -1190
  6. package/api-contract.json +381 -0
  7. package/dist/acl.d.ts +81 -1
  8. package/dist/acl.js +281 -13
  9. package/dist/admin.d.ts +11 -141
  10. package/dist/admin.js +28 -186
  11. package/dist/auth.d.ts +20 -5
  12. package/dist/auth.js +80 -21
  13. package/dist/cache.d.ts +8 -1
  14. package/dist/cache.js +30 -8
  15. package/dist/chain.d.ts +46 -48
  16. package/dist/chain.js +556 -223
  17. package/dist/cli.js +73 -96
  18. package/dist/demo/booking.d.ts +352 -36
  19. package/dist/describe.d.ts +47 -0
  20. package/dist/describe.js +195 -0
  21. package/dist/errors.d.ts +77 -13
  22. package/dist/errors.js +231 -30
  23. package/dist/index.d.ts +62 -74
  24. package/dist/index.js +312 -155
  25. package/dist/internal.d.ts +7 -0
  26. package/dist/jsonschema.js +18 -17
  27. package/dist/load.d.ts +29 -17
  28. package/dist/load.js +235 -190
  29. package/dist/log.d.ts +121 -0
  30. package/dist/log.js +633 -0
  31. package/dist/mcp.d.ts +5 -7
  32. package/dist/mcp.js +194 -225
  33. package/dist/messages/access.d.ts +90 -0
  34. package/dist/messages/access.js +113 -0
  35. package/dist/messages/api.d.ts +237 -0
  36. package/dist/messages/api.js +304 -0
  37. package/dist/messages/boot.d.ts +201 -0
  38. package/dist/messages/boot.js +256 -0
  39. package/dist/messages/codes.d.ts +172 -0
  40. package/dist/messages/codes.js +173 -0
  41. package/dist/messages/index.d.ts +98 -0
  42. package/dist/messages/index.js +121 -0
  43. package/dist/messages/log.d.ts +229 -0
  44. package/dist/messages/log.js +102 -0
  45. package/dist/messages/mcp.d.ts +306 -0
  46. package/dist/messages/mcp.js +387 -0
  47. package/dist/messages/model.d.ts +256 -0
  48. package/dist/messages/model.js +314 -0
  49. package/dist/messages/query.d.ts +141 -0
  50. package/dist/messages/query.js +171 -0
  51. package/dist/messages/sql-access.d.ts +70 -0
  52. package/dist/messages/sql-access.js +87 -0
  53. package/dist/messages/sql-core.d.ts +164 -0
  54. package/dist/messages/sql-core.js +198 -0
  55. package/dist/messages/sql-time.d.ts +86 -0
  56. package/dist/messages/sql-time.js +111 -0
  57. package/dist/messages/sql-write.d.ts +246 -0
  58. package/dist/messages/sql-write.js +270 -0
  59. package/dist/messages/time.d.ts +23 -0
  60. package/dist/messages/time.js +29 -0
  61. package/dist/messages/types.d.ts +27 -0
  62. package/dist/messages/types.js +5 -0
  63. package/dist/messages/write.d.ts +452 -0
  64. package/dist/messages/write.js +572 -0
  65. package/dist/model.d.ts +77 -60
  66. package/dist/model.js +43 -34
  67. package/dist/ops.d.ts +35 -0
  68. package/dist/ops.js +101 -0
  69. package/dist/pglite.d.ts +0 -9
  70. package/dist/pglite.js +3 -1
  71. package/dist/registry.d.ts +3 -19
  72. package/dist/registry.js +3 -16
  73. package/dist/signals.d.ts +1 -5
  74. package/dist/signals.js +1 -5
  75. package/dist/sql.d.ts +9 -1
  76. package/dist/sql.js +175 -107
  77. package/dist/sync.d.ts +10 -4
  78. package/dist/sync.js +90 -17
  79. package/dist/tx.d.ts +21 -2
  80. package/dist/tx.js +76 -13
  81. package/dist/typed.d.ts +252 -53
  82. package/dist/types.d.ts +93 -90
  83. package/dist/types.js +17 -14
  84. package/dist/up.d.ts +56 -35
  85. package/dist/up.js +229 -83
  86. package/dist/uuid.d.ts +8 -0
  87. package/dist/uuid.js +14 -6
  88. package/dist/validate.d.ts +13 -1
  89. package/dist/validate.js +82 -33
  90. package/dist/watch.d.ts +10 -16
  91. package/dist/watch.js +36 -77
  92. package/dist/write.d.ts +87 -17
  93. package/dist/write.js +441 -206
  94. package/llms.txt +48 -31
  95. package/package.json +13 -14
  96. package/sql/10-core.sql +7 -50
  97. package/sql/15-errors.sql +64 -10
  98. package/sql/20-context.sql +18 -9
  99. package/sql/30-validate.sql +79 -30
  100. package/sql/40-class.sql +41 -115
  101. package/sql/50-acl.sql +8 -13
  102. package/sql/60-write.sql +220 -676
  103. package/sql/70-read.sql +11 -13
  104. package/sql/80-auth.sql +109 -42
  105. package/sql/90-time.sql +108 -947
  106. package/sql/95-seed.system.sql +7 -14
  107. package/sql/99-revision.sql +6 -1
  108. package/sql/README.md +32 -24
  109. package/sql/migrate/0009-restore-rev.tenants-name.sql +10 -0
  110. package/sql/migrate/0010-impersonation-no-account.sql +5 -0
  111. package/sql/migrate/0011-key-lock.otp-enabled.sql +7 -0
  112. package/sql/migrate/README.md +18 -0
  113. package/AGENT-CHEATSHEET.en.md +0 -488
  114. package/MIGRATION.md +0 -190
  115. package/README.en.md +0 -2910
  116. package/dist/import.d.ts +0 -185
  117. package/dist/import.js +0 -820
  118. package/dist/project.d.ts +0 -359
  119. package/dist/project.js +0 -1258
  120. package/sql/75-history.sql +0 -436
  121. package/sql/88-derived.sql +0 -1236
  122. package/sql/migrate/0006-changed-paths.sql +0 -3
  123. package/sql/migrate/0007-secret-account-fk.sql +0 -12
@@ -0,0 +1,270 @@
1
+ export const sqlWrite = {
2
+ // 60-write.sql, lock_row(), family_lock(): внутренняя ошибка (SQLSTATE XX000) — строки-замка нет и после вставки или
3
+ // блокировка её не нашла; name — имя строки-замка
4
+ 'sql-write.lock_row_not_created': {
5
+ code: 'internal',
6
+ ru: 'строка-замок {name} не создана',
7
+ },
8
+ 'sql-write.lock_row_not_found': {
9
+ code: 'internal',
10
+ ru: 'строка-замок {name} не найдена',
11
+ },
12
+ // 60-write.sql, триггеры вставки и правки, move_row: данные не проходят описание класса; detail.issues — нарушения
13
+ 'sql-write.invalid_data': {
14
+ code: 'invalid_data',
15
+ ru: 'данные не проходят описание класса {cls}',
16
+ },
17
+ // links_shape(): разбор концов строки (триггеры вставки и правки; check_links — restore)
18
+ 'sql-write.links_not_object': {
19
+ code: 'invalid_data',
20
+ ru: 'links — не объект',
21
+ },
22
+ 'sql-write.end_undeclared': {
23
+ code: 'undeclared_end',
24
+ ru: 'конец {end} не объявлен в классе {cls}',
25
+ },
26
+ 'sql-write.end_not_list': {
27
+ code: 'invalid_data',
28
+ ru: 'конец {end} — список id',
29
+ },
30
+ 'sql-write.end_not_uuid': {
31
+ code: 'invalid_data',
32
+ ru: 'конец {end}: значение не uuid',
33
+ },
34
+ 'sql-write.end_target_repeated': {
35
+ code: 'invalid_data',
36
+ ru: 'конец {end}: цель повторяется',
37
+ },
38
+ 'sql-write.end_too_few': {
39
+ code: 'invalid_data',
40
+ ru: 'у конца {end} слишком мало целей',
41
+ },
42
+ 'sql-write.end_too_many': {
43
+ code: 'invalid_data',
44
+ ru: 'у конца {end} слишком много целей',
45
+ },
46
+ 'sql-write.end_required': {
47
+ code: 'invalid_data',
48
+ ru: 'обязательный конец {end} не задан',
49
+ },
50
+ // check_links(), триггеры после вставки и правки (targets_bad): цель конца не найдена
51
+ 'sql-write.end_target_missing': {
52
+ code: 'target_not_found',
53
+ ru: 'цель конца {end} не найдена',
54
+ },
55
+ // family_conflicts(): чем строка семейства не проходит новое описание — поле problem в detail.rows отказа
56
+ // tightening_conflict (ужесточение класса); у строки ещё key и params — fromDbError их убирает
57
+ 'sql-write.problem_abstract': {
58
+ code: 'tightening_conflict',
59
+ ru: 'класс абстрактный',
60
+ },
61
+ // issues — нарушения текстом JSON без key и params; в params строки — сами нарушения с ключами (массив)
62
+ 'sql-write.problem_data': {
63
+ code: 'tightening_conflict',
64
+ ru: 'данные: {issues}',
65
+ },
66
+ 'sql-write.problem_key': {
67
+ code: 'tightening_conflict',
68
+ ru: 'id не соответствует ключу класса',
69
+ },
70
+ // ссылающаяся строка видна актору — её роль и id; не видна — ни роли, ни id
71
+ 'sql-write.problem_ref': {
72
+ code: 'tightening_conflict',
73
+ ru: 'на строку ссылается роль {role} строки {id}, которая не принимает класс',
74
+ },
75
+ 'sql-write.problem_ref_hidden': {
76
+ code: 'tightening_conflict',
77
+ ru: 'на строку ссылается строка, которой актор не видит, и она не принимает класс',
78
+ },
79
+ // class_rows_admit(): нет права без условий на все строки класса {target} (сам класс {cls} или его потомок); что
80
+ // меняется — p_what: reparent, history, tighten; иной p_what — прежний готовый текст {what}
81
+ 'sql-write.reparent_needs_all': {
82
+ code: 'acl_denied',
83
+ ru: 'класс {cls} меняет предков или алиас: нужно право {op} на все строки класса {target}',
84
+ },
85
+ 'sql-write.history_needs_all': {
86
+ code: 'acl_denied',
87
+ ru: 'класс {cls} включает или выключает журнал (history): нужно право {op} на все строки класса {target}',
88
+ },
89
+ 'sql-write.tighten_needs_all': {
90
+ code: 'acl_denied',
91
+ ru: 'ужесточение класса {cls}: нужно право {op} на все строки класса {target}',
92
+ },
93
+ 'sql-write.change_needs_all': {
94
+ code: 'acl_denied',
95
+ ru: '{what}: нужно право {op} на все строки класса {target}',
96
+ },
97
+ // class_admit(): проверки строки Class сверх метасхемы
98
+ 'sql-write.system_name_reserved': {
99
+ code: 'invalid_class',
100
+ ru: 'имя {name} зарезервировано за системным классом',
101
+ },
102
+ 'sql-write.system_flag': {
103
+ code: 'invalid_class',
104
+ ru: 'признак system задаёт только установка',
105
+ },
106
+ 'sql-write.system_name_taken': {
107
+ code: 'invalid_class',
108
+ ru: 'имя {name} занято системным классом',
109
+ },
110
+ 'sql-write.link_name_reserved': {
111
+ code: 'invalid_class',
112
+ ru: 'имя связи {name} совпадает с методом цепочки',
113
+ },
114
+ // хаб с зарезервированным именем (план 2.0, этап 4, п. 2; 7.10 №3): прежние такие хабы up() оставляет и называет в
115
+ // предупреждении (boot.reserved_hubs), но описание их строки Class база больше не пишет
116
+ 'sql-write.hub_name_reserved': {
117
+ code: 'invalid_class',
118
+ ru: 'имя хаба {name} совпадает с методом цепочки',
119
+ },
120
+ 'sql-write.alias_taken': {
121
+ code: 'invalid_class',
122
+ ru: 'алиас {alias} класса {cls} совпадает с именем или алиасом другого класса',
123
+ },
124
+ 'sql-write.name_is_alias': {
125
+ code: 'invalid_class',
126
+ ru: 'имя класса {cls} совпадает с алиасом другого класса',
127
+ },
128
+ 'sql-write.alias_orphan_history': {
129
+ code: 'invalid_class',
130
+ ru: 'удалённые потомки класса {cls} хранят историю строк: алиас не меняется',
131
+ },
132
+ 'sql-write.end_other_class': {
133
+ code: 'invalid_class',
134
+ ru: 'конец {end} в классе {cls} ведёт на другой класс',
135
+ },
136
+ // триггеры вставки и правки
137
+ 'sql-write.no_session': {
138
+ code: 'no_session',
139
+ ru: 'нет действующей сессии',
140
+ },
141
+ 'sql-write.foreign_tenant': {
142
+ code: 'tenant_denied',
143
+ ru: 'запись в чужого арендатора',
144
+ },
145
+ 'sql-write.account_tenant': {
146
+ code: 'tenant_denied',
147
+ ru: 'аккаунты лежат в арендаторе System',
148
+ },
149
+ 'sql-write.class_not_found': {
150
+ code: 'invalid_class',
151
+ ru: 'класс {cls} не найден',
152
+ },
153
+ // класс удалили, пока писатель ждал блокировку семейства
154
+ 'sql-write.class_deleted': {
155
+ code: 'invalid_class',
156
+ ru: 'класс {cls} удалён',
157
+ },
158
+ 'sql-write.class_abstract': {
159
+ code: 'invalid_class',
160
+ ru: 'класс {cls} абстрактный',
161
+ },
162
+ 'sql-write.member_tenant': {
163
+ code: 'invalid_data',
164
+ ru: 'конец Tenant членства — арендатор строки',
165
+ },
166
+ 'sql-write.id_from_db': {
167
+ code: 'id_from_db',
168
+ ru: 'id класса без ключа {cls} выдаёт база',
169
+ },
170
+ // detail.expected — id от ключа
171
+ 'sql-write.id_mismatch': {
172
+ code: 'id_mismatch',
173
+ ru: 'id не равен v5 от ключа класса {cls}',
174
+ },
175
+ 'sql-write.history_recreate': {
176
+ code: 'invalid_class',
177
+ ru: 'журнал хранит историю строк класса {cls} или его удалённых потомков: создать его можно только заново и с прежними parent, alias и history',
178
+ },
179
+ 'sql-write.owner_not_found': {
180
+ code: 'target_not_found',
181
+ ru: 'владелец строки не найден',
182
+ },
183
+ 'sql-write.immutable_columns': {
184
+ code: 'immutable_key',
185
+ ru: 'id, арендатора, владельца и время создания менять нельзя',
186
+ },
187
+ // класс строки неизменен (план 2.0, редакция 2): смены класса нет
188
+ 'sql-write.class_immutable': {
189
+ code: 'immutable_key',
190
+ ru: 'класс строки {cls} неизменен: объект другого класса — новый объект',
191
+ },
192
+ 'sql-write.key_changed': {
193
+ code: 'immutable_key',
194
+ ru: 'ключевое поле класса {cls} менять нельзя: id изменился бы',
195
+ },
196
+ // class_evolve(): detail — видимые нарушающие строки и число остальных (visible_detail)
197
+ 'sql-write.tightening_mismatch': {
198
+ code: 'tightening_conflict',
199
+ ru: 'новому описанию класса {cls} не соответствуют строки',
200
+ },
201
+ // триггеры удаления
202
+ 'sql-write.delete_isolation': {
203
+ code: 'isolation_level',
204
+ ru: 'удаление разрешено только в read committed',
205
+ },
206
+ 'sql-write.system_account_delete': {
207
+ code: 'acl_denied',
208
+ ru: 'аккаунт System не удаляется: ему принадлежат служебные строки установки',
209
+ },
210
+ 'sql-write.recreated_in_statement': {
211
+ code: 'recreated_in_statement',
212
+ ru: 'id удалён и создан заново одним оператором',
213
+ },
214
+ 'sql-write.class_not_empty': {
215
+ code: 'invalid_class',
216
+ ru: 'у класса {cls} есть строки или потомки',
217
+ },
218
+ 'sql-write.class_has_history': {
219
+ code: 'invalid_class',
220
+ ru: 'у класса {cls} есть история строк в журнале: класс с историей строк не удаляется',
221
+ },
222
+ // каскад и снятие конца: класс отказавшей строки — только если актор её видит (visible_class)
223
+ 'sql-write.cascade_delete_denied': {
224
+ code: 'acl_denied',
225
+ ru: 'нет права DELETE на класс {cls} в каскаде удаления',
226
+ },
227
+ 'sql-write.cascade_delete_denied_hidden': {
228
+ code: 'acl_denied',
229
+ ru: 'нет права DELETE на строки в каскаде удаления',
230
+ },
231
+ 'sql-write.unset_write_denied': {
232
+ code: 'acl_denied',
233
+ ru: 'нет права WRITE на класс {cls}: снятие конца при удалении',
234
+ },
235
+ 'sql-write.unset_write_denied_hidden': {
236
+ code: 'acl_denied',
237
+ ru: 'нет права WRITE на ссылающуюся строку: снятие конца при удалении',
238
+ },
239
+ // detail — видимые актору мешающие строки и число остальных (visible_detail)
240
+ 'sql-write.delete_restricted': {
241
+ code: 'delete_restricted',
242
+ ru: 'на удаляемые строки ссылаются другие строки (onDelete: restrict)',
243
+ },
244
+ // links_patch() и inc() исполняет приложение: raise с lt_text(), в detail — key и params
245
+ 'sql-write.links_patch_op': {
246
+ code: 'invalid_data',
247
+ ru: 'links_patch: неизвестная операция {op}',
248
+ },
249
+ // inc(): нарушение — и в detail.issues[0].message
250
+ 'sql-write.inc_args': {
251
+ code: 'invalid_data',
252
+ ru: 'inc: нужны путь и величина',
253
+ },
254
+ 'sql-write.inc_path_missing': {
255
+ code: 'invalid_data',
256
+ ru: 'inc: путь {path} идёт через отсутствующий объект',
257
+ },
258
+ 'sql-write.inc_path_not_object': {
259
+ code: 'invalid_data',
260
+ ru: 'inc: путь {path} идёт не через объект',
261
+ },
262
+ 'sql-write.inc_no_field': {
263
+ code: 'invalid_data',
264
+ ru: 'inc: поля {path} нет — задайте start',
265
+ },
266
+ 'sql-write.inc_not_number': {
267
+ code: 'invalid_data',
268
+ ru: 'inc: в поле {path} не число',
269
+ },
270
+ };
@@ -0,0 +1,23 @@
1
+ export declare const time: {
2
+ 'time.maintain_in_tx': {
3
+ code: "invalid_query";
4
+ ru: string;
5
+ };
6
+ 'time.signal_queue': {
7
+ code: "invalid_query";
8
+ ru: string;
9
+ };
10
+ 'time.bad_interval': {
11
+ code: "invalid_data";
12
+ ru: string;
13
+ hint: string;
14
+ };
15
+ 'time.maintain_failed': {
16
+ code: "invalid_query";
17
+ ru: string;
18
+ };
19
+ 'time.watch_cursor': {
20
+ code: "invalid_query";
21
+ ru: string;
22
+ };
23
+ };
@@ -0,0 +1,29 @@
1
+ export const time = {
2
+ // admin.ts, maintain(): внутри db.begin()
3
+ 'time.maintain_in_tx': {
4
+ code: 'invalid_query',
5
+ ru: 'maintain() идёт своей транзакцией, не внутри db.begin()',
6
+ },
7
+ // admin.ts, queueWarning: очередь сигналов PostgreSQL заполнена больше чем наполовину — предупреждение maintain();
8
+ // pct — проценты целым числом; код записи не печатается
9
+ 'time.signal_queue': {
10
+ code: 'invalid_query',
11
+ ru: 'очередь сигналов PostgreSQL заполнена на {pct} % — проверьте зависших слушателей',
12
+ },
13
+ // admin.ts, parseInterval: интервал connect({ maintain }); value — как передан (строка — в кавычках)
14
+ 'time.bad_interval': {
15
+ code: 'invalid_data',
16
+ ru: "интервал {value}: число мс или строка '30s', '15m', '1h', '1d' — от 1 мс до 2³¹−1 мс (около 24 суток)",
17
+ hint: "задать интервал числом миллисекунд или строкой вида '30s', '15m', '1h', '1d'",
18
+ },
19
+ // admin.ts, scheduleMaintain: запуск maintain() по расписанию упал — предупреждение (lwarn); message — текст его ошибки
20
+ 'time.maintain_failed': {
21
+ code: 'invalid_query',
22
+ ru: 'maintain по расписанию: {message}',
23
+ },
24
+ // watch.ts, decode: курсор watch({ from }) не разбирается; cursor — как передан
25
+ 'time.watch_cursor': {
26
+ code: 'invalid_query',
27
+ ru: 'watch: курсор {cursor} — ожидается курсор события',
28
+ },
29
+ };
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Каталог сообщений letopis (план 2.0, этап 3, п. 3) — типы записей. Как перевести место на ключ и вызывать — шапка
3
+ * index.ts.
4
+ */
5
+ /**
6
+ * Коды ошибок letopis: каталог базы (SQLSTATE LT001–LT018, `error_catalog()` в lib/sql/15-errors.sql, `LT_NAMES` в
7
+ * errors.ts) и коды самой библиотеки. Новый код — сюда, в codes.ts (заголовок и подсказка) и в раздел «Ошибки» README
8
+ * (с якорем `<a id="код"></a>`). `internal` — внутренняя ошибка базы: SQLSTATE XX000 с ключом каталога в DETAIL
9
+ * (`lt_raise('XX000', ключ, …)`, fromDbError).
10
+ */
11
+ export type ErrorCode = 'no_session' | 'target_not_found' | 'invalid_data' | 'undeclared_end' | 'tenant_denied' | 'acl_denied' | 'id_mismatch' | 'id_from_db' | 'immutable_key' | 'invalid_class' | 'tightening_conflict' | 'isolation_level' | 'recreated_in_statement' | 'delete_restricted' | 'not_deleted' | 'exists' | 'duplicate' | 'deleted' | 'conflict' | 'rev_ambiguous' | 'tx_required' | 'lock_unsupported' | 'commit_unknown' | 'tx_rolled_back' | 'no_key' | 'no_path' | 'invalid_query' | 'admin_required' | 'not_empty' | 'class_not_loadable' | 'bypass_rls' | 'user_session_required' | 'confirmation_required' | 'internal';
12
+ /**
13
+ * Запись каталога: код ошибки, шаблон текста (`ru`), `{имя}` в шаблоне — параметр. `hint` — своя подсказка «что делать»;
14
+ * без неё ошибка берёт подсказку своего кода из codes.ts. Поля — в этом порядке: code, ru, hint.
15
+ */
16
+ export interface Msg {
17
+ code: ErrorCode;
18
+ ru: string;
19
+ hint?: string;
20
+ }
21
+ /**
22
+ * Параметры шаблона: `{имя}` → значение, напечатанное как в шаблонной строке JS (`${x}`). `similar` (массив похожих
23
+ * имён) дописывает к тексту «— похожие: …» сам `lerr`.
24
+ */
25
+ export type Params = Readonly<Record<string, unknown>>;
26
+ /** Раздел каталога: ключи только вида `<раздел>.<snake_case>` — чужой префикс не пропустит проверка типов. */
27
+ export type Section<P extends string> = Record<`${P}.${string}`, Msg>;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Каталог сообщений letopis (план 2.0, этап 3, п. 3) — типы записей. Как перевести место на ключ и вызывать — шапка
3
+ * index.ts.
4
+ */
5
+ export {};