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,98 @@
1
+ /**
2
+ * Каталог сообщений letopis (план 2.0, этап 3, п. 3): ключ → код ошибки, шаблон текста и, если нужно, своя подсказка
3
+ * «что делать». Здесь разделы сливаются в MESSAGES (префикс ключа — имя раздела, ключи не повторяются), а render()
4
+ * подставляет параметры; ошибки и тексты строит errors.ts — lerr, lmsg, lwarn.
5
+ *
6
+ * Как перевести место на ключ каталога — инструкция исполнителям (образцы: записи разделов api, query, access, sql-core, sql-write,
7
+ * sql-time и места, которые их бросают).
8
+ *
9
+ * 1. Раздел — по файлу, где брошена ошибка:
10
+ * api — index, chain, typed, errors, internal; write — write, tx, load; query — sql, ops;
11
+ * time — watch, admin, cache, signals; access — auth, acl; model — model, registry, sync, cli, validate,
12
+ * jsonschema, uuid; boot — up, pglite; mcp — mcp, describe; log — log (и тексты логирования из index, tx);
13
+ * sql-core — sql/10, 15, 20, 30, 40; sql-write — sql/60; sql-access — sql/50, 80;
14
+ * sql-time — sql/70, 90, 95, 99 и sql/migrate.
15
+ * codes.ts — запись на каждый код: заголовок и подсказка. Новый код — ещё ErrorCode (types.ts), для кода базы —
16
+ * LT_NAMES (errors.ts) и error_catalog(), и строка таблицы «Ошибки» README с якорем `<a id="код"></a>`.
17
+ * 2. Ключ — `<раздел>.<snake_case>`: что случилось, а не где (api.unknown_step, query.sort_field). Одно место — один
18
+ * ключ; одинаковый текст в разных разделах — разные ключи (api.validation_failed и sql-write.invalid_data).
19
+ * 3. Запись — { code, ru, hint? }, поля в этом порядке:
20
+ * code — код, с которым место бросало ошибку: код не меняется (коды сверяет check:semver);
21
+ * ru — прежний текст буква в букву, без префикса «letopis: <код>: »; подстановка ${x} → параметр {имя};
22
+ * hint — только если подсказка кода из codes.ts к месту не подходит (образцы: api.connect_schema, sql-time.last_owner).
23
+ * Параметр печатается как `${x}` в шаблонной строке, поэтому прежний текст не меняется; лучше скаляры (строка,
24
+ * число). Похожие имена — params.similar (массив из similar() в errors.ts): «— похожие: a, b» lerr допишет сам, в
25
+ * шаблон их не пишут.
26
+ * Текст с двумя формами (род, число) — две записи или параметр без грамматики, а не склейка слов в коде.
27
+ * 4. Вызов в TS:
28
+ * throw lerr('api.unknown_step', { name, similar: similar(name, names) });
29
+ * throw lerr('access.switch_not_root');
30
+ * throw lerr('<раздел>.<ключ>', { cls }, { detail: { id }, cause: e }); // detail и cause — как раньше
31
+ * Текст не для ошибки (сообщение нарушения, описание) — lmsg(ключ, параметры); предупреждение — lwarn(ключ,
32
+ * параметры, { once }). Подкласс и помощник вида fail(текст) переходят на ключ так же (образец — ValidationError в
33
+ * errors.ts). Старый конструктор new LetopisError(код, текст) из переведённого места уходит целиком.
34
+ * 5. Вызов в SQL — перегрузка lt_fail(p_key text, p_params jsonb default '{}', p_detail jsonb default null)
35
+ * (lib/sql/15-errors.sql): код ошибки — из записи, текст база собирает из шаблона ru (его видит и сырой SQL), в
36
+ * DETAIL — поля p_detail и ещё key, params; их fromDbError переносит в поля ошибки (key, params):
37
+ * perform @SCHEMA@.lt_fail('sql-core.no_membership');
38
+ * perform @SCHEMA@.lt_fail('sql-write.invalid_data', jsonb_build_object('cls', NEW.class), jsonb_build_object('issues', bad));
39
+ * Параметры — jsonb_build_object со скалярами (список — array_to_string); без параметров — один аргумент, а не null
40
+ * (литерал без типа выбрал бы прежнюю lt_fail(имя, текст)). detail ошибки — прежний: без p_detail — {}, а место, где
41
+ * был raise без detail, — p_detail => 'null' (detail нет). Свой SQLSTATE не из каталога — lt_raise(p_code, p_key,
42
+ * p_params, p_detail). В функциях, которые исполняет приложение (inc, links_patch: lt_fail ему не выдан), — raise
43
+ * как прежде (errcode — SQLSTATE кода, message — префикс «letopis: <код>: » и текст), только текст — lt_text(ключ,
44
+ * параметры) (она выдана приложению), а detail — jsonb_build_object('key', ключ, 'params', параметры)::text; без
45
+ * своих полей — ещё 'nodetail', true (detail нет, как у raise без detail).
46
+ * Разделы sql-* установщик кладёт в базу при каждом up() (@MESSAGES@): новой ревизии и миграции не нужно.
47
+ * 6. Готовый файл — убрать из PENDING_LITERALS в lib/scripts/check-docs.mjs (проверка «в LetopisError, fail и lt_fail не
48
+ * осталось литеральных текстов»). Затем cd lib && npm run typecheck, npm run check:docs, npm run api:contract и тесты
49
+ * модуля по одному файлу: тест, который сверял русский текст, остаётся зелёным без правки.
50
+ * 7. Особые места. Разделы каталога контракт API читает регэкспами: код — из поля code: в кавычках, текст ошибки — из
51
+ * строки с префиксом letopis и двоеточием; в комментариях их в таком виде не пишут. up.ts и pglite.ts бросают обычный Error('letopis.up: ' + lmsg(…)) — подходящего кода нет. Сообщения нарушений
52
+ * (issues[].message: validate.ts, 30-validate.sql) — lmsg и lt_text с кодом invalid_data. Описания инструментов MCP и
53
+ * instructions — строки в mcp.ts рядом со схемами, тексты ответов — раздел mcp.
54
+ */
55
+ import { access } from './access.js';
56
+ import { api } from './api.js';
57
+ import { boot } from './boot.js';
58
+ import { codes } from './codes.js';
59
+ import { log } from './log.js';
60
+ import { mcp } from './mcp.js';
61
+ import { model } from './model.js';
62
+ import { query } from './query.js';
63
+ import { sqlAccess } from './sql-access.js';
64
+ import { sqlCore } from './sql-core.js';
65
+ import { sqlTime } from './sql-time.js';
66
+ import { sqlWrite } from './sql-write.js';
67
+ import { time } from './time.js';
68
+ import { write } from './write.js';
69
+ import type { ErrorCode, Msg, Params } from './types.js';
70
+ export type { ErrorCode, Msg, Params, Section } from './types.js';
71
+ /** Каталог событий логирования (не сообщения об ошибках — в MESSAGES не входит). */
72
+ export { LOG_EVENTS, type LogEventInfo, type LogEventLevel, type LogEventName } from './log.js';
73
+ /** Разделы, которые установщик кладёт в базу (message_catalog() в lib/sql/15-errors.sql). */
74
+ export declare const SQL_SECTIONS: readonly ["sql-core", "sql-write", "sql-access", "sql-time"];
75
+ type All = typeof codes & typeof api & typeof write & typeof query & typeof time & typeof access & typeof model & typeof boot & typeof mcp & typeof log & typeof sqlCore & typeof sqlWrite & typeof sqlAccess & typeof sqlTime;
76
+ /** Ключ каталога: опечатку в lerr('…') ловит проверка типов. */
77
+ export type MsgKey = keyof All;
78
+ /** Все записи каталога по ключу. */
79
+ export declare const MESSAGES: Readonly<Record<MsgKey, Msg>>;
80
+ /** Запись по ключу из любого источника (DETAIL базы, вызов из JS); нет такой — undefined. */
81
+ export declare function msgOf(key: string): Msg | undefined;
82
+ /** Подпись кода: заголовок и подсказка «что делать» (codes.ts). */
83
+ export declare function codeOf(code: string): (Msg & {
84
+ hint: string;
85
+ }) | undefined;
86
+ /** Суффикс похожих имён (params.similar) — его дописывает lerr. */
87
+ export declare const SIMILAR = " \u2014 \u043F\u043E\u0445\u043E\u0436\u0438\u0435: {similar}";
88
+ /**
89
+ * Шаблон с параметрами: `{имя}` → значение, напечатанное как в шаблонной строке JS (`${x}`), поэтому перенос текста
90
+ * `…${x}…` в шаблон `…{x}…` его не меняет. `{имя}` без такого параметра остаётся как есть; так же — lt_text() в базе
91
+ * (там null — пусто, как у format('%s')).
92
+ */
93
+ export declare function render(template: string, params?: Params): string;
94
+ /** Разделы sql-* для базы: ключ → имя ошибки и русский шаблон (установщик подставляет в @MESSAGES@). */
95
+ export declare function sqlCatalog(): Record<string, {
96
+ name: ErrorCode;
97
+ ru: string;
98
+ }>;
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Каталог сообщений letopis (план 2.0, этап 3, п. 3): ключ → код ошибки, шаблон текста и, если нужно, своя подсказка
3
+ * «что делать». Здесь разделы сливаются в MESSAGES (префикс ключа — имя раздела, ключи не повторяются), а render()
4
+ * подставляет параметры; ошибки и тексты строит errors.ts — lerr, lmsg, lwarn.
5
+ *
6
+ * Как перевести место на ключ каталога — инструкция исполнителям (образцы: записи разделов api, query, access, sql-core, sql-write,
7
+ * sql-time и места, которые их бросают).
8
+ *
9
+ * 1. Раздел — по файлу, где брошена ошибка:
10
+ * api — index, chain, typed, errors, internal; write — write, tx, load; query — sql, ops;
11
+ * time — watch, admin, cache, signals; access — auth, acl; model — model, registry, sync, cli, validate,
12
+ * jsonschema, uuid; boot — up, pglite; mcp — mcp, describe; log — log (и тексты логирования из index, tx);
13
+ * sql-core — sql/10, 15, 20, 30, 40; sql-write — sql/60; sql-access — sql/50, 80;
14
+ * sql-time — sql/70, 90, 95, 99 и sql/migrate.
15
+ * codes.ts — запись на каждый код: заголовок и подсказка. Новый код — ещё ErrorCode (types.ts), для кода базы —
16
+ * LT_NAMES (errors.ts) и error_catalog(), и строка таблицы «Ошибки» README с якорем `<a id="код"></a>`.
17
+ * 2. Ключ — `<раздел>.<snake_case>`: что случилось, а не где (api.unknown_step, query.sort_field). Одно место — один
18
+ * ключ; одинаковый текст в разных разделах — разные ключи (api.validation_failed и sql-write.invalid_data).
19
+ * 3. Запись — { code, ru, hint? }, поля в этом порядке:
20
+ * code — код, с которым место бросало ошибку: код не меняется (коды сверяет check:semver);
21
+ * ru — прежний текст буква в букву, без префикса «letopis: <код>: »; подстановка ${x} → параметр {имя};
22
+ * hint — только если подсказка кода из codes.ts к месту не подходит (образцы: api.connect_schema, sql-time.last_owner).
23
+ * Параметр печатается как `${x}` в шаблонной строке, поэтому прежний текст не меняется; лучше скаляры (строка,
24
+ * число). Похожие имена — params.similar (массив из similar() в errors.ts): «— похожие: a, b» lerr допишет сам, в
25
+ * шаблон их не пишут.
26
+ * Текст с двумя формами (род, число) — две записи или параметр без грамматики, а не склейка слов в коде.
27
+ * 4. Вызов в TS:
28
+ * throw lerr('api.unknown_step', { name, similar: similar(name, names) });
29
+ * throw lerr('access.switch_not_root');
30
+ * throw lerr('<раздел>.<ключ>', { cls }, { detail: { id }, cause: e }); // detail и cause — как раньше
31
+ * Текст не для ошибки (сообщение нарушения, описание) — lmsg(ключ, параметры); предупреждение — lwarn(ключ,
32
+ * параметры, { once }). Подкласс и помощник вида fail(текст) переходят на ключ так же (образец — ValidationError в
33
+ * errors.ts). Старый конструктор new LetopisError(код, текст) из переведённого места уходит целиком.
34
+ * 5. Вызов в SQL — перегрузка lt_fail(p_key text, p_params jsonb default '{}', p_detail jsonb default null)
35
+ * (lib/sql/15-errors.sql): код ошибки — из записи, текст база собирает из шаблона ru (его видит и сырой SQL), в
36
+ * DETAIL — поля p_detail и ещё key, params; их fromDbError переносит в поля ошибки (key, params):
37
+ * perform @SCHEMA@.lt_fail('sql-core.no_membership');
38
+ * perform @SCHEMA@.lt_fail('sql-write.invalid_data', jsonb_build_object('cls', NEW.class), jsonb_build_object('issues', bad));
39
+ * Параметры — jsonb_build_object со скалярами (список — array_to_string); без параметров — один аргумент, а не null
40
+ * (литерал без типа выбрал бы прежнюю lt_fail(имя, текст)). detail ошибки — прежний: без p_detail — {}, а место, где
41
+ * был raise без detail, — p_detail => 'null' (detail нет). Свой SQLSTATE не из каталога — lt_raise(p_code, p_key,
42
+ * p_params, p_detail). В функциях, которые исполняет приложение (inc, links_patch: lt_fail ему не выдан), — raise
43
+ * как прежде (errcode — SQLSTATE кода, message — префикс «letopis: <код>: » и текст), только текст — lt_text(ключ,
44
+ * параметры) (она выдана приложению), а detail — jsonb_build_object('key', ключ, 'params', параметры)::text; без
45
+ * своих полей — ещё 'nodetail', true (detail нет, как у raise без detail).
46
+ * Разделы sql-* установщик кладёт в базу при каждом up() (@MESSAGES@): новой ревизии и миграции не нужно.
47
+ * 6. Готовый файл — убрать из PENDING_LITERALS в lib/scripts/check-docs.mjs (проверка «в LetopisError, fail и lt_fail не
48
+ * осталось литеральных текстов»). Затем cd lib && npm run typecheck, npm run check:docs, npm run api:contract и тесты
49
+ * модуля по одному файлу: тест, который сверял русский текст, остаётся зелёным без правки.
50
+ * 7. Особые места. Разделы каталога контракт API читает регэкспами: код — из поля code: в кавычках, текст ошибки — из
51
+ * строки с префиксом letopis и двоеточием; в комментариях их в таком виде не пишут. up.ts и pglite.ts бросают обычный Error('letopis.up: ' + lmsg(…)) — подходящего кода нет. Сообщения нарушений
52
+ * (issues[].message: validate.ts, 30-validate.sql) — lmsg и lt_text с кодом invalid_data. Описания инструментов MCP и
53
+ * instructions — строки в mcp.ts рядом со схемами, тексты ответов — раздел mcp.
54
+ */
55
+ import { access } from './access.js';
56
+ import { api } from './api.js';
57
+ import { boot } from './boot.js';
58
+ import { codes } from './codes.js';
59
+ import { log } from './log.js';
60
+ import { mcp } from './mcp.js';
61
+ import { model } from './model.js';
62
+ import { query } from './query.js';
63
+ import { sqlAccess } from './sql-access.js';
64
+ import { sqlCore } from './sql-core.js';
65
+ import { sqlTime } from './sql-time.js';
66
+ import { sqlWrite } from './sql-write.js';
67
+ import { time } from './time.js';
68
+ import { write } from './write.js';
69
+ /** Каталог событий логирования (не сообщения об ошибках — в MESSAGES не входит). */
70
+ export { LOG_EVENTS } from './log.js';
71
+ /** Разделы каталога: имя — префикс ключа и имя файла. */
72
+ const SECTIONS = {
73
+ codes, api, write, query, time, access, model, boot, mcp, log,
74
+ 'sql-core': sqlCore, 'sql-write': sqlWrite, 'sql-access': sqlAccess, 'sql-time': sqlTime,
75
+ };
76
+ /** Разделы, которые установщик кладёт в базу (message_catalog() в lib/sql/15-errors.sql). */
77
+ export const SQL_SECTIONS = ['sql-core', 'sql-write', 'sql-access', 'sql-time'];
78
+ function merge(sections) {
79
+ const out = {};
80
+ for (const [name, section] of Object.entries(sections)) {
81
+ for (const [key, m] of Object.entries(section)) {
82
+ if (!key.startsWith(`${name}.`))
83
+ throw new Error(`letopis: ключ каталога ${key} — не из раздела ${name}`);
84
+ if (Object.hasOwn(out, key))
85
+ throw new Error(`letopis: ключ каталога ${key} повторяется`);
86
+ out[key] = m;
87
+ }
88
+ }
89
+ return out;
90
+ }
91
+ /** Все записи каталога по ключу. */
92
+ export const MESSAGES = merge(SECTIONS);
93
+ /** Запись по ключу из любого источника (DETAIL базы, вызов из JS); нет такой — undefined. */
94
+ export function msgOf(key) {
95
+ return Object.hasOwn(MESSAGES, key) ? MESSAGES[key] : undefined;
96
+ }
97
+ /** Подпись кода: заголовок и подсказка «что делать» (codes.ts). */
98
+ export function codeOf(code) {
99
+ return msgOf(`codes.${code}`);
100
+ }
101
+ /** Суффикс похожих имён (params.similar) — его дописывает lerr. */
102
+ export const SIMILAR = ' — похожие: {similar}';
103
+ /**
104
+ * Шаблон с параметрами: `{имя}` → значение, напечатанное как в шаблонной строке JS (`${x}`), поэтому перенос текста
105
+ * `…${x}…` в шаблон `…{x}…` его не меняет. `{имя}` без такого параметра остаётся как есть; так же — lt_text() в базе
106
+ * (там null — пусто, как у format('%s')).
107
+ */
108
+ export function render(template, params) {
109
+ if (!params)
110
+ return template;
111
+ return template.replace(/\{([A-Za-z_][A-Za-z0-9_]*)\}/g, (m, k) => (Object.hasOwn(params, k) ? String(params[k]) : m));
112
+ }
113
+ /** Разделы sql-* для базы: ключ → имя ошибки и русский шаблон (установщик подставляет в @MESSAGES@). */
114
+ export function sqlCatalog() {
115
+ const out = {};
116
+ for (const s of SQL_SECTIONS) {
117
+ for (const [key, m] of Object.entries(SECTIONS[s]))
118
+ out[key] = { name: m.code, ru: m.ru };
119
+ }
120
+ return out;
121
+ }
@@ -0,0 +1,229 @@
1
+ export declare const log: {
2
+ 'log.bad_level': {
3
+ code: "invalid_data";
4
+ ru: string;
5
+ hint: string;
6
+ };
7
+ 'log.bad_logger': {
8
+ code: "invalid_data";
9
+ ru: string;
10
+ hint: string;
11
+ };
12
+ 'log.bad_redact': {
13
+ code: "invalid_data";
14
+ ru: string;
15
+ hint: string;
16
+ };
17
+ 'log.db_error': {
18
+ code: "internal";
19
+ ru: string;
20
+ };
21
+ 'log.logger_failed': {
22
+ code: "internal";
23
+ ru: string;
24
+ };
25
+ 'log.notify_failed': {
26
+ code: "internal";
27
+ ru: string;
28
+ };
29
+ 'log.renew_failed': {
30
+ code: "no_session";
31
+ ru: string;
32
+ };
33
+ };
34
+ /** Уровень события. */
35
+ export type LogEventLevel = 'debug' | 'info' | 'warn' | 'error';
36
+ /** Запись каталога событий: уровень по умолчанию и что значит событие. */
37
+ export interface LogEventInfo {
38
+ level: LogEventLevel;
39
+ ru: string;
40
+ }
41
+ /**
42
+ * Каталог событий логирования. Имена основных событий зафиксированы спецификацией 3.0 (connect, close, up, migrate,
43
+ * sync, read, cache.hit, cache.miss, write, delete.preview, delete, restore, tx.*, auth.login, auth.logout, auth.revoke,
44
+ * auth.switch, watch.start, watch.stop, signal, maintain, warning, error, sql); остальные — дополнительные.
45
+ */
46
+ export declare const LOG_EVENTS: {
47
+ readonly connect: {
48
+ readonly level: "info";
49
+ readonly ru: "connect() готов: схема, режим сигналов, кэш, способ входа";
50
+ };
51
+ readonly close: {
52
+ readonly level: "info";
53
+ readonly ru: "db.close(): пул, подписки и таймеры закрыты";
54
+ };
55
+ readonly 'registry.refresh': {
56
+ readonly level: "debug";
57
+ readonly ru: "реестр классов перечитан";
58
+ };
59
+ readonly 'session.renew': {
60
+ readonly level: "info";
61
+ readonly ru: "сессия по ключу сервиса истекла — ключ обменян на новую";
62
+ };
63
+ readonly up: {
64
+ readonly level: "info";
65
+ readonly ru: "up() завершён: схема поставлена, обновлена или накатана повторно";
66
+ };
67
+ readonly 'up.step': {
68
+ readonly level: "info";
69
+ readonly ru: "шаг up(): то, что без логгера печатается в консоль";
70
+ };
71
+ readonly migrate: {
72
+ readonly level: "info";
73
+ readonly ru: "up() обновил ревизию схемы миграциями";
74
+ };
75
+ readonly 'tenant.create': {
76
+ readonly level: "info";
77
+ readonly ru: "арендатор (и его первый пользователь) заведён или найден";
78
+ };
79
+ readonly sync: {
80
+ readonly level: "info";
81
+ readonly ru: "syncModels(): классы созданы, изменены или сверены (сухой прогон)";
82
+ };
83
+ readonly read: {
84
+ readonly level: "debug";
85
+ readonly ru: "терминал чтения цепочки: rows, first, ids, count, paths, versions, агрегаты";
86
+ };
87
+ readonly 'cache.hit': {
88
+ readonly level: "debug";
89
+ readonly ru: "ответ взят из кэша результатов";
90
+ };
91
+ readonly 'cache.miss': {
92
+ readonly level: "debug";
93
+ readonly ru: "ответа нет в кэше результатов — запрос к базе";
94
+ };
95
+ readonly raw: {
96
+ readonly level: "debug";
97
+ readonly ru: "сырой SQL db.sql";
98
+ };
99
+ readonly write: {
100
+ readonly level: "info";
101
+ readonly ru: "запись цепочкой (create, update, upsert, слоты) или батч";
102
+ };
103
+ readonly 'delete.preview': {
104
+ readonly level: "debug";
105
+ readonly ru: "превью удаления: delete() без confirm, ничего не удалено";
106
+ };
107
+ readonly delete: {
108
+ readonly level: "info";
109
+ readonly ru: "удаление выполнено: состав каскада, сверка с expect";
110
+ };
111
+ readonly restore: {
112
+ readonly level: "info";
113
+ readonly ru: "восстановление выполнено: восстановленные и пропущенные цели";
114
+ };
115
+ readonly load: {
116
+ readonly level: "info";
117
+ readonly ru: "db.load(): массовая загрузка завершена";
118
+ };
119
+ readonly lock: {
120
+ readonly level: "debug";
121
+ readonly ru: "db.lock(): advisory-блокировка в транзакции";
122
+ };
123
+ readonly 'tx.begin': {
124
+ readonly level: "debug";
125
+ readonly ru: "открыта транзакция: db.begin() или db.transaction()";
126
+ };
127
+ readonly 'tx.commit': {
128
+ readonly level: "debug";
129
+ readonly ru: "транзакция зафиксирована; с записью (db.begin()) и у db.transaction() — уровень info и detail.writes: доказательство фиксации событий с тем же tx";
130
+ };
131
+ readonly 'tx.rollback': {
132
+ readonly level: "info";
133
+ readonly ru: "транзакция откачена: явно или из-за ошибки";
134
+ };
135
+ readonly 'tx.retry': {
136
+ readonly level: "warn";
137
+ readonly ru: "повтор операции после конфликта (взаимная блокировка, сериализация, журнал)";
138
+ };
139
+ readonly 'auth.login': {
140
+ readonly level: "info";
141
+ readonly ru: "успешный вход: пароль, ключ, код, привязка";
142
+ };
143
+ readonly 'auth.fail': {
144
+ readonly level: "warn";
145
+ readonly ru: "неудачный вход или неверный второй фактор";
146
+ };
147
+ readonly 'auth.logout': {
148
+ readonly level: "info";
149
+ readonly ru: "выход: гашение текущей сессии";
150
+ };
151
+ readonly 'auth.revoke': {
152
+ readonly level: "info";
153
+ readonly ru: "отзыв: сессии по токену, все сессии аккаунта или кред";
154
+ };
155
+ readonly 'auth.switch': {
156
+ readonly level: "info";
157
+ readonly ru: "auth.switch(): сменён рабочий арендатор сессии";
158
+ };
159
+ readonly 'auth.as': {
160
+ readonly level: "debug";
161
+ readonly ru: "db.as(): фасад от имени другого аккаунта или арендатора";
162
+ };
163
+ readonly 'auth.session': {
164
+ readonly level: "info";
165
+ readonly ru: "сервис выпустил сессию пользователю (sessionFor)";
166
+ };
167
+ readonly 'auth.credential': {
168
+ readonly level: "info";
169
+ readonly ru: "кред заведён или изменён: пароль, ключ, TOTP, код, привязка, флаги";
170
+ };
171
+ readonly 'auth.call': {
172
+ readonly level: "debug";
173
+ readonly ru: "прочие вызовы db.auth: сведения о сессии, кредах, арендаторах";
174
+ };
175
+ readonly 'account.purge': {
176
+ readonly level: "info";
177
+ readonly ru: "аккаунт удалён с данными своего арендатора";
178
+ };
179
+ readonly 'acl.change': {
180
+ readonly level: "info";
181
+ readonly ru: "права изменены: grant, deny, revoke, roles";
182
+ };
183
+ readonly 'acl.check': {
184
+ readonly level: "debug";
185
+ readonly ru: "проверка или список прав";
186
+ };
187
+ readonly 'watch.start': {
188
+ readonly level: "info";
189
+ readonly ru: "подписка watch() открыта";
190
+ };
191
+ readonly 'watch.fetch': {
192
+ readonly level: "debug";
193
+ readonly ru: "подписка прочитала пачку событий журнала";
194
+ };
195
+ readonly 'watch.stop': {
196
+ readonly level: "info";
197
+ readonly ru: "подписка закрыта";
198
+ };
199
+ readonly signal: {
200
+ readonly level: "debug";
201
+ readonly ru: "получен сигнал базы (NOTIFY) или слушатель переподключился";
202
+ };
203
+ readonly 'signal.send': {
204
+ readonly level: "debug";
205
+ readonly ru: "отправлены накопленные сигналы записи";
206
+ };
207
+ readonly maintain: {
208
+ readonly level: "info";
209
+ readonly ru: "maintain(): обслуживание выполнено или пропущено";
210
+ };
211
+ readonly 'mcp.call': {
212
+ readonly level: "info";
213
+ readonly ru: "вызов инструмента MCP";
214
+ };
215
+ readonly warning: {
216
+ readonly level: "warn";
217
+ readonly ru: "предупреждение letopis";
218
+ };
219
+ readonly error: {
220
+ readonly level: "error";
221
+ readonly ru: "ошибка операции letopis: код, ключ каталога, подробности, причина; штатный отказ (exists, conflict, target_not_found, нарушения данных и т. п.) — уровень warn; у ошибки PostgreSQL — только SQLSTATE и имена объектов схемы";
222
+ };
223
+ readonly sql: {
224
+ readonly level: "debug";
225
+ readonly ru: "SQL-запрос: текст без значений параметров, время, число строк";
226
+ };
227
+ };
228
+ /** Имя события логирования. */
229
+ export type LogEventName = keyof typeof LOG_EVENTS;
@@ -0,0 +1,102 @@
1
+ export const log = {
2
+ // log.ts, makeLog: logLevel не из списка; value — как передан (строка — в кавычках)
3
+ 'log.bad_level': {
4
+ code: 'invalid_data',
5
+ ru: "logLevel {value}: ожидается 'debug', 'info', 'warn', 'error' или 'off'",
6
+ hint: "передать logLevel одной из строк 'debug', 'info', 'warn', 'error', 'off' (по умолчанию 'info')",
7
+ },
8
+ // log.ts, makeLog: log — не функция и не объект с методами уровней
9
+ 'log.bad_logger': {
10
+ code: 'invalid_data',
11
+ ru: 'log: ожидается функция (событие) => void или объект с методами debug, info, warn, error (pino, console)',
12
+ hint: 'передать в log функцию или объект логгера (pino, console)',
13
+ },
14
+ // log.ts, makeLog: redact — не массив строк
15
+ 'log.bad_redact': {
16
+ code: 'invalid_data',
17
+ ru: 'redact: ожидается массив имён полей (строк)',
18
+ hint: "передать redact списком имён полей, например ['email', 'phone']",
19
+ },
20
+ // log.ts, errorFields и causeOf: ошибка PostgreSQL в событии — только SQLSTATE и имена объектов схемы; её текст,
21
+ // DETAIL, WHERE и HINT могут нести значения параметров и данных и в журнал не идут (полный текст — у самой ошибки)
22
+ 'log.db_error': {
23
+ code: 'internal',
24
+ ru: 'ошибка PostgreSQL {sqlstate} (текст, DETAIL, WHERE и HINT базы в журнал не пишутся — они у самой ошибки)',
25
+ },
26
+ // log.ts, deliver: исключение в логгере приложения — один раз на процесс в stderr; операция не прерывается
27
+ 'log.logger_failed': {
28
+ code: 'internal',
29
+ ru: 'логгер бросил исключение на событии {event}: {message} — событие пропущено, операции это не мешает',
30
+ },
31
+ // index.ts, Notifier: отправка сигналов не удалась — предупреждение (warning); повтор — следующим интервалом
32
+ 'log.notify_failed': {
33
+ code: 'internal',
34
+ ru: 'сигналы не отправлены: {message} — повтор следующим интервалом',
35
+ },
36
+ // index.ts, ctx.renew: обмен ключа сервиса на новую сессию не удался — предупреждение (warning)
37
+ 'log.renew_failed': {
38
+ code: 'no_session',
39
+ ru: 'сессия по ключу сервиса истекла, а обмен ключа на новую не удался',
40
+ },
41
+ };
42
+ /**
43
+ * Каталог событий логирования. Имена основных событий зафиксированы спецификацией 3.0 (connect, close, up, migrate,
44
+ * sync, read, cache.hit, cache.miss, write, delete.preview, delete, restore, tx.*, auth.login, auth.logout, auth.revoke,
45
+ * auth.switch, watch.start, watch.stop, signal, maintain, warning, error, sql); остальные — дополнительные.
46
+ */
47
+ export const LOG_EVENTS = {
48
+ // подключение
49
+ 'connect': { level: 'info', ru: 'connect() готов: схема, режим сигналов, кэш, способ входа' },
50
+ 'close': { level: 'info', ru: 'db.close(): пул, подписки и таймеры закрыты' },
51
+ 'registry.refresh': { level: 'debug', ru: 'реестр классов перечитан' },
52
+ 'session.renew': { level: 'info', ru: 'сессия по ключу сервиса истекла — ключ обменян на новую' },
53
+ // установка
54
+ 'up': { level: 'info', ru: 'up() завершён: схема поставлена, обновлена или накатана повторно' },
55
+ 'up.step': { level: 'info', ru: 'шаг up(): то, что без логгера печатается в консоль' },
56
+ 'migrate': { level: 'info', ru: 'up() обновил ревизию схемы миграциями' },
57
+ 'tenant.create': { level: 'info', ru: 'арендатор (и его первый пользователь) заведён или найден' },
58
+ 'sync': { level: 'info', ru: 'syncModels(): классы созданы, изменены или сверены (сухой прогон)' },
59
+ // чтение
60
+ 'read': { level: 'debug', ru: 'терминал чтения цепочки: rows, first, ids, count, paths, versions, агрегаты' },
61
+ 'cache.hit': { level: 'debug', ru: 'ответ взят из кэша результатов' },
62
+ 'cache.miss': { level: 'debug', ru: 'ответа нет в кэше результатов — запрос к базе' },
63
+ 'raw': { level: 'debug', ru: 'сырой SQL db.sql' },
64
+ // запись
65
+ 'write': { level: 'info', ru: 'запись цепочкой (create, update, upsert, слоты) или батч' },
66
+ 'delete.preview': { level: 'debug', ru: 'превью удаления: delete() без confirm, ничего не удалено' },
67
+ 'delete': { level: 'info', ru: 'удаление выполнено: состав каскада, сверка с expect' },
68
+ 'restore': { level: 'info', ru: 'восстановление выполнено: восстановленные и пропущенные цели' },
69
+ 'load': { level: 'info', ru: 'db.load(): массовая загрузка завершена' },
70
+ 'lock': { level: 'debug', ru: 'db.lock(): advisory-блокировка в транзакции' },
71
+ // транзакции
72
+ 'tx.begin': { level: 'debug', ru: 'открыта транзакция: db.begin() или db.transaction()' },
73
+ 'tx.commit': { level: 'debug', ru: 'транзакция зафиксирована; с записью (db.begin()) и у db.transaction() — уровень info и detail.writes: доказательство фиксации событий с тем же tx' },
74
+ 'tx.rollback': { level: 'info', ru: 'транзакция откачена: явно или из-за ошибки' },
75
+ 'tx.retry': { level: 'warn', ru: 'повтор операции после конфликта (взаимная блокировка, сериализация, журнал)' },
76
+ // вход и права
77
+ 'auth.login': { level: 'info', ru: 'успешный вход: пароль, ключ, код, привязка' },
78
+ 'auth.fail': { level: 'warn', ru: 'неудачный вход или неверный второй фактор' },
79
+ 'auth.logout': { level: 'info', ru: 'выход: гашение текущей сессии' },
80
+ 'auth.revoke': { level: 'info', ru: 'отзыв: сессии по токену, все сессии аккаунта или кред' },
81
+ 'auth.switch': { level: 'info', ru: 'auth.switch(): сменён рабочий арендатор сессии' },
82
+ 'auth.as': { level: 'debug', ru: 'db.as(): фасад от имени другого аккаунта или арендатора' },
83
+ 'auth.session': { level: 'info', ru: 'сервис выпустил сессию пользователю (sessionFor)' },
84
+ 'auth.credential': { level: 'info', ru: 'кред заведён или изменён: пароль, ключ, TOTP, код, привязка, флаги' },
85
+ 'auth.call': { level: 'debug', ru: 'прочие вызовы db.auth: сведения о сессии, кредах, арендаторах' },
86
+ 'account.purge': { level: 'info', ru: 'аккаунт удалён с данными своего арендатора' },
87
+ 'acl.change': { level: 'info', ru: 'права изменены: grant, deny, revoke, roles' },
88
+ 'acl.check': { level: 'debug', ru: 'проверка или список прав' },
89
+ // время
90
+ 'watch.start': { level: 'info', ru: 'подписка watch() открыта' },
91
+ 'watch.fetch': { level: 'debug', ru: 'подписка прочитала пачку событий журнала' },
92
+ 'watch.stop': { level: 'info', ru: 'подписка закрыта' },
93
+ 'signal': { level: 'debug', ru: 'получен сигнал базы (NOTIFY) или слушатель переподключился' },
94
+ 'signal.send': { level: 'debug', ru: 'отправлены накопленные сигналы записи' },
95
+ 'maintain': { level: 'info', ru: 'maintain(): обслуживание выполнено или пропущено' },
96
+ // MCP
97
+ 'mcp.call': { level: 'info', ru: 'вызов инструмента MCP' },
98
+ // общее
99
+ 'warning': { level: 'warn', ru: 'предупреждение letopis' },
100
+ 'error': { level: 'error', ru: 'ошибка операции letopis: код, ключ каталога, подробности, причина; штатный отказ (exists, conflict, target_not_found, нарушения данных и т. п.) — уровень warn; у ошибки PostgreSQL — только SQLSTATE и имена объектов схемы' },
101
+ 'sql': { level: 'debug', ru: 'SQL-запрос: текст без значений параметров, время, число строк' },
102
+ };