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/sql/70-read.sql CHANGED
@@ -17,8 +17,7 @@
17
17
  --
18
18
  -- Источник — текущее состояние (entity) или журнал: версии, действовавшие на момент p_at (срез
19
19
  -- asOf), либо надгробия удалённых (p_dead, для withDeleted). Возвращается rev версии: строки
20
- -- журнала читаются по паре (id, rev) через уникальный индекс log_id_rev. Записи purge, trim и reset
21
- -- (этап 6) — не версии объекта: на момент после них объекта в срезе нет.
20
+ -- журнала читаются по паре (id, rev) через уникальный индекс log_id_rev.
22
21
 
23
22
  -- Цели концов строки: всех (p_roles is null) или только перечисленных ролей.
24
23
  create or replace function @SCHEMA@.role_ids(p_links jsonb, p_roles text[]) returns uuid[]
@@ -53,9 +52,10 @@ as $$
53
52
  where r.class = any (p_classes) and r.at <= coalesce(p_at, 'infinity'::timestamptz)) c
54
53
  cross join lateral (
55
54
  select y.* from (select x.* from @SCHEMA@.log x where x.id = c.id offset 0) y
56
- where y.class = any (p_classes) and y.at <= coalesce(p_at, 'infinity'::timestamptz)
55
+ where y.at <= coalesce(p_at, 'infinity'::timestamptz)
57
56
  order by y.rev desc limit 1) w
58
- where @SCHEMA@.link_ids(w.links) @> array[p_src]
57
+ -- класс — у последней версии на момент, а не среди версий классов шага (план 2.0, 7.1 №1)
58
+ where w.class = any (p_classes) and @SCHEMA@.link_ids(w.links) @> array[p_src]
59
59
  $$;
60
60
 
61
61
  -- id строк классов p_classes: по вложению в data (GIN entity_data), по целям концов (GIN entity_ends),
@@ -121,32 +121,36 @@ begin
121
121
  from @SCHEMA@.log l
122
122
  where l.id = any (p_ids) and l.at <= coalesce(p_at, 'infinity'::timestamptz)
123
123
  order by l.id, l.rev desc) v
124
- where v.class = any (p_classes) and (v.op = 'delete') = p_dead and v.op not in ('purge', 'trim', 'reset')
124
+ where v.class = any (p_classes) and (v.op = 'delete') = p_dead
125
125
  and (p_data is null or v.data @> p_data) and (p_ends is null or @SCHEMA@.link_ids(v.links) @> p_ends)
126
126
  and @SCHEMA@.row_visible(v.tenant, v.class, v.id, v.owner, v.tags, v.data, v.links, c_tenant, c_account, c_plan);
127
127
  elsif p_ends is not null then
128
128
  -- по целям концов — от версий, ссылавшихся на первую цель (GIN log_ends); арендатор — после пробы
129
129
  return query select v.id, v.rev from @SCHEMA@.log_refs_at(p_classes, p_ends[1], p_at) v
130
130
  where (v.tenant = any (v_tenants) or v.class = 'member')
131
- and (v.op = 'delete') = p_dead and v.op not in ('purge', 'trim', 'reset')
131
+ and (v.op = 'delete') = p_dead
132
132
  and (p_data is null or v.data @> p_data) and @SCHEMA@.link_ids(v.links) @> p_ends
133
133
  and @SCHEMA@.row_visible(v.tenant, v.class, v.id, v.owner, v.tags, v.data, v.links, c_tenant, c_account, c_plan);
134
134
  else
135
- -- арендатор id неизменен, записи purge и trim несут арендатора объекта: условие до distinct on не меняет, какая
135
+ -- арендатор id неизменен: условие до distinct on не меняет, какая
136
136
  -- версия id последняя (индекс log_class_tenant_at)
137
+ -- кандидаты — по классу (индекс log_class_tenant_at), последняя версия id на момент — любого класса, и класс
138
+ -- проверяется у неё (план 2.0, 7.1 №1)
137
139
  return query select v.id, v.rev from (
138
- select distinct on (l.id) l.id, l.rev, l.op, l.class, l.tenant, l.owner, l.tags, l.data, l.links
139
- from @SCHEMA@.log l
140
- where l.class = any (p_classes) and l.tenant = any (v_tenants) and l.at <= coalesce(p_at, 'infinity'::timestamptz)
141
- order by l.id, l.rev desc) v
142
- where (v.op = 'delete') = p_dead and v.op not in ('purge', 'trim', 'reset')
140
+ select distinct l.id from @SCHEMA@.log l
141
+ where l.class = any (p_classes) and l.tenant = any (v_tenants) and l.at <= coalesce(p_at, 'infinity'::timestamptz)) c
142
+ cross join lateral (
143
+ select y.id, y.rev, y.op, y.class, y.tenant, y.owner, y.tags, y.data, y.links
144
+ from @SCHEMA@.log y where y.id = c.id and y.at <= coalesce(p_at, 'infinity'::timestamptz)
145
+ order by y.rev desc limit 1) v
146
+ where v.class = any (p_classes) and (v.op = 'delete') = p_dead
143
147
  and (p_data is null or v.data @> p_data) and (p_ends is null or @SCHEMA@.link_ids(v.links) @> p_ends)
144
148
  and @SCHEMA@.row_visible(v.tenant, v.class, v.id, v.owner, v.tags, v.data, v.links, c_tenant, c_account, c_plan);
145
149
  -- свои членства в других арендаторах: версии, ссылавшиеся на аккаунт (GIN log_ends)
146
150
  if v_member then
147
151
  return query select v.id, v.rev from @SCHEMA@.log_refs_at(array['member'], c_account, p_at) v
148
152
  where not (v.tenant = any (v_tenants))
149
- and (v.op = 'delete') = p_dead and v.op not in ('purge', 'trim', 'reset')
153
+ and (v.op = 'delete') = p_dead
150
154
  and (p_data is null or v.data @> p_data) and (p_ends is null or @SCHEMA@.link_ids(v.links) @> p_ends)
151
155
  and @SCHEMA@.row_visible(v.tenant, v.class, v.id, v.owner, v.tags, v.data, v.links, c_tenant, c_account, c_plan);
152
156
  end if;
@@ -187,7 +191,7 @@ begin
187
191
  return query select s.src, v.id, v.rev
188
192
  from (select distinct u.x as src from unnest(p_src) u(x)) s
189
193
  cross join lateral @SCHEMA@.log_refs_at(p_classes, s.src, p_at) v
190
- where (v.op = 'delete') = p_dead and v.op not in ('purge', 'trim', 'reset')
194
+ where (v.op = 'delete') = p_dead
191
195
  and (p_data is null or v.data @> p_data) and (p_ends is null or @SCHEMA@.link_ids(v.links) @> p_ends)
192
196
  and (p_roles is null or @SCHEMA@.role_has(v.links, p_roles, s.src))
193
197
  and @SCHEMA@.row_visible(v.tenant, v.class, v.id, v.owner, v.tags, v.data, v.links, c_tenant, c_account, c_plan);
@@ -237,14 +241,14 @@ begin
237
241
  select s.src, v.id, v.rev, 1, array[s.src, v.id]
238
242
  from (select distinct u.x as src from unnest(p_src) u(x)) s
239
243
  cross join lateral @SCHEMA@.log_refs_at(p_classes, s.src, p_at) v
240
- where v.op not in ('delete', 'purge', 'trim', 'reset')
244
+ where v.op <> 'delete'
241
245
  and (p_roles is null or @SCHEMA@.role_has(v.links, p_roles, s.src))
242
246
  and @SCHEMA@.row_visible(v.tenant, v.class, v.id, v.owner, v.tags, v.data, v.links, c_tenant, c_account, c_plan)
243
247
  union all
244
248
  select d.src, v.id, v.rev, d.depth + 1, d.seen || v.id
245
249
  from d
246
250
  cross join lateral @SCHEMA@.log_refs_at(p_classes, d.id, p_at) v
247
- where d.depth < p_max and not (v.id = any (d.seen)) and v.op not in ('delete', 'purge', 'trim', 'reset')
251
+ where d.depth < p_max and not (v.id = any (d.seen)) and v.op <> 'delete'
248
252
  and (p_roles is null or @SCHEMA@.role_has(v.links, p_roles, d.id))
249
253
  and @SCHEMA@.row_visible(v.tenant, v.class, v.id, v.owner, v.tags, v.data, v.links, c_tenant, c_account, c_plan))
250
254
  select distinct on (d.src, d.id) d.src, d.id, d.rev, d.depth from d order by d.src, d.id, d.depth;
package/sql/80-auth.sql CHANGED
@@ -17,7 +17,7 @@ return interval '10 minutes';
17
17
 
18
18
  create or replace function @SCHEMA@.auth_kind_ok(p_kind text) returns boolean
19
19
  language sql immutable parallel safe
20
- return p_kind ~ '^[A-Z][A-Z0-9_]{1,31}$' and p_kind not in ('SESSION', 'APIKEY', 'KEYSECRET', 'OTP', 'TOTP', 'KEY', 'PROJECTOR', 'LOCK');
20
+ return p_kind ~ '^[A-Z][A-Z0-9_]{1,31}$' and p_kind not in ('SESSION', 'APIKEY', 'KEYSECRET', 'OTP', 'TOTP', 'KEY', 'LOCK');
21
21
 
22
22
  -- Действующая сессия обязательна (иначе no_session).
23
23
  create or replace function @SCHEMA@.auth_session_required(p_account uuid) returns void
@@ -25,7 +25,7 @@ language plpgsql immutable
25
25
  as $$
26
26
  begin
27
27
  if p_account is null then
28
- perform @SCHEMA@.lt_fail('no_session', 'нет действующей сессии');
28
+ perform @SCHEMA@.lt_fail('sql-access.no_session');
29
29
  end if;
30
30
  end $$;
31
31
 
@@ -42,7 +42,7 @@ declare
42
42
  begin
43
43
  select * into c from @SCHEMA@.ctx();
44
44
  if c.account is null then
45
- perform @SCHEMA@.lt_fail('no_session', 'нет действующей сессии');
45
+ perform @SCHEMA@.lt_fail('sql-access.no_session');
46
46
  end if;
47
47
  if c.account = p_account and c.service is null then
48
48
  select (s.meta->>'login_at')::timestamptz, coalesce(s.meta->'methods', '[]'::jsonb) into login_at, methods
@@ -57,12 +57,12 @@ begin
57
57
  end if;
58
58
  end if;
59
59
  if not coalesce((@SCHEMA@.acl_api_for(c.tenant, c.categories, c.roles, 'auth.credential', true)->>'allow')::boolean, false) then
60
- perform @SCHEMA@.lt_fail('acl_denied', 'привязка отклонена: нужен недавний вход или право auth.credential');
60
+ perform @SCHEMA@.lt_fail('sql-access.bind_denied');
61
61
  end if;
62
62
  -- креды System, сервисов и системных администраторов выдаёт только системный администратор: иначе
63
63
  -- сервис привязал бы себе вход под ними (ревью этапа 5)
64
64
  if not @SCHEMA@.auth_target_ok(p_account) and not @SCHEMA@.auth_is_sysadmin() then
65
- perform @SCHEMA@.lt_fail('acl_denied', 'привязка отклонена: нужен недавний вход или право auth.credential');
65
+ perform @SCHEMA@.lt_fail('sql-access.bind_denied');
66
66
  end if;
67
67
  end $$;
68
68
 
@@ -77,7 +77,7 @@ declare
77
77
  begin
78
78
  select * into c from @SCHEMA@.ctx();
79
79
  if p_account is distinct from c.account and not @SCHEMA@.auth_target_ok(p_account) and not @SCHEMA@.auth_is_sysadmin() then
80
- perform @SCHEMA@.lt_fail('acl_denied', 'креды и сессии этого аккаунта меняет только он сам или системный администратор');
80
+ perform @SCHEMA@.lt_fail('sql-access.self_or_sysadmin');
81
81
  end if;
82
82
  end $$;
83
83
 
@@ -203,7 +203,7 @@ begin
203
203
  perform @SCHEMA@.auth_session_required(c.account);
204
204
  perform @SCHEMA@.acl_require('auth.session');
205
205
  if not @SCHEMA@.auth_target_ok(p_account) then
206
- perform @SCHEMA@.lt_fail('acl_denied', 'сессии для этого аккаунта не выпускаются');
206
+ perform @SCHEMA@.lt_fail('sql-access.no_sessions_for_account');
207
207
  end if;
208
208
  return @SCHEMA@.new_session(p_account, p_ttl, jsonb_build_object('methods', to_jsonb(p_methods), 'service', c.account));
209
209
  end $$;
@@ -248,14 +248,14 @@ begin
248
248
  p_confirmed := null;
249
249
  end if;
250
250
  if not @SCHEMA@.auth_kind_ok(p_kind) or coalesce(p_ident, '') = '' or p_hash !~ '^scrypt\$' then
251
- perform @SCHEMA@.lt_fail('invalid_data', 'пароль: вид, идентификатор и хэш scrypt$… обязательны');
251
+ perform @SCHEMA@.lt_fail('sql-access.password_args');
252
252
  end if;
253
253
  select s.id, s.account into cur from @SCHEMA@.secret s
254
254
  where s.kind = p_kind and s.deleted_at is null
255
255
  and casefold(s.ident) collate pg_unicode_fast = casefold(p_ident) collate pg_unicode_fast
256
256
  for update;
257
257
  if cur.id is not null and cur.account <> p_account then
258
- perform @SCHEMA@.lt_fail('acl_denied', 'привязка отклонена: нужен недавний вход или право auth.credential');
258
+ perform @SCHEMA@.lt_fail('sql-access.bind_denied');
259
259
  end if;
260
260
  if cur.id is not null then
261
261
  update @SCHEMA@.secret s
@@ -270,7 +270,7 @@ begin
270
270
  values (p_account, p_kind, p_ident, convert_to(p_hash, 'UTF8'), jsonb_build_object('confirmed', coalesce(p_confirmed, false)))
271
271
  returning id into cid;
272
272
  exception when unique_violation then
273
- perform @SCHEMA@.lt_fail('acl_denied', 'привязка отклонена: нужен недавний вход или право auth.credential');
273
+ perform @SCHEMA@.lt_fail('sql-access.bind_denied');
274
274
  end;
275
275
  end if;
276
276
  return cid;
@@ -308,7 +308,7 @@ begin
308
308
  null; -- совпал префикс: новый ключ
309
309
  end;
310
310
  end loop;
311
- perform @SCHEMA@.lt_raise('40001', 'conflict', 'не удалось выпустить ключ с уникальным префиксом');
311
+ perform @SCHEMA@.lt_raise('40001','sql-access.apikey_prefix_conflict', '{}'::jsonb);
312
312
  end $$;
313
313
 
314
314
  -- Вход по ключу API для db.auth.verifyApiKey: { account, token } или null (login_apikey — для
@@ -390,13 +390,13 @@ declare
390
390
  begin
391
391
  perform @SCHEMA@.acl_require('auth.otp');
392
392
  if p_kind !~ '^OTP(_[A-Z0-9]{1,27})?$' or coalesce(p_ident, '') = '' or p_digits not between 4 and 10 then
393
- perform @SCHEMA@.lt_fail('invalid_data', 'код: вид OTP или OTP_<имя>, идентификатор, 4–10 знаков');
393
+ perform @SCHEMA@.lt_fail('sql-access.otp_args');
394
394
  end if;
395
395
  if not @SCHEMA@.auth_enabled(p_account) then
396
- perform @SCHEMA@.lt_fail('target_not_found', 'аккаунт не найден');
396
+ perform @SCHEMA@.lt_fail('sql-access.account_not_found');
397
397
  end if;
398
398
  if not @SCHEMA@.auth_target_ok(p_account) and not @SCHEMA@.auth_is_sysadmin() then
399
- perform @SCHEMA@.lt_fail('acl_denied', 'коды входа для System, сервисов и системных администраторов выпускает только системный администратор');
399
+ perform @SCHEMA@.lt_fail('sql-access.otp_sysadmin_only');
400
400
  end if;
401
401
  code := lpad((('x' || encode(@PGCRYPTO@.gen_random_bytes(7), 'hex'))::bit(56)::bigint % (10::bigint ^ p_digits)::bigint)::text, p_digits, '0');
402
402
  update @SCHEMA@.secret s set deleted_at = clock_timestamp()
@@ -564,7 +564,7 @@ begin
564
564
  p_confirmed := false;
565
565
  end if;
566
566
  if not @SCHEMA@.auth_kind_ok(p_kind) or p_kind = 'PASSWORD' or coalesce(p_ident, '') = '' then
567
- perform @SCHEMA@.lt_fail('invalid_data', 'identity: вид (TELEGRAM, GOOGLE, …) и идентификатор обязательны');
567
+ perform @SCHEMA@.lt_fail('sql-access.identity_args');
568
568
  end if;
569
569
  begin
570
570
  insert into @SCHEMA@.secret (account, kind, ident, meta)
@@ -572,7 +572,7 @@ begin
572
572
  || jsonb_build_object('confirmed', coalesce(p_confirmed, false)))
573
573
  returning id into cid;
574
574
  exception when unique_violation then
575
- perform @SCHEMA@.lt_fail('acl_denied', 'привязка отклонена: нужен недавний вход или право auth.credential');
575
+ perform @SCHEMA@.lt_fail('sql-access.bind_denied');
576
576
  end;
577
577
  return cid;
578
578
  end $$;
@@ -617,7 +617,7 @@ begin
617
617
  coalesce((s.meta->>'confirmed')::boolean, false), coalesce((s.meta->>'enabled')::boolean, true),
618
618
  s.meta - 'confirmed' - 'enabled' - 'attempts' - 'last_step', s.created_at, s.expires_at
619
619
  from @SCHEMA@.secret s
620
- where s.account = p_account and s.kind not in ('SESSION', 'KEY', 'PROJECTOR', 'LOCK') and s.deleted_at is null
620
+ where s.account = p_account and s.kind not in ('SESSION', 'KEY', 'LOCK') and s.deleted_at is null
621
621
  and (s.expires_at is null or s.expires_at > clock_timestamp())
622
622
  order by s.created_at, s.id;
623
623
  end $$;
@@ -639,7 +639,7 @@ begin
639
639
  perform @SCHEMA@.auth_session_required(c.account);
640
640
  select s.account, s.kind,
641
641
  (s.expires_at is null or s.expires_at > clock_timestamp()) and coalesce((s.meta->>'enabled')::boolean, true) as live
642
- into cr from @SCHEMA@.secret s where s.id = p_id and s.kind not in ('SESSION', 'KEY', 'PROJECTOR', 'LOCK') and s.deleted_at is null;
642
+ into cr from @SCHEMA@.secret s where s.id = p_id and s.kind not in ('SESSION', 'KEY', 'LOCK') and s.deleted_at is null;
643
643
  if cr.account is null then
644
644
  return false;
645
645
  end if;
@@ -655,7 +655,7 @@ begin
655
655
  if not exists (select 1 from @SCHEMA@.secret s
656
656
  where s.account = cr.account and s.kind in ('APIKEY', 'KEYSECRET') and s.deleted_at is null and s.id <> p_id
657
657
  and (s.expires_at is null or s.expires_at > clock_timestamp()) and coalesce((s.meta->>'enabled')::boolean, true)) then
658
- perform @SCHEMA@.lt_fail('acl_denied', 'последний действующий ключ сервиса не отзывается: сначала выпустите новый');
658
+ perform @SCHEMA@.lt_fail('sql-access.last_service_key');
659
659
  end if;
660
660
  end if;
661
661
  update @SCHEMA@.secret s set deleted_at = clock_timestamp() where s.id = p_id and s.deleted_at is null;
@@ -679,7 +679,7 @@ declare
679
679
  acc uuid;
680
680
  begin
681
681
  perform @SCHEMA@.acl_require('auth.credential');
682
- select s.account into acc from @SCHEMA@.secret s where s.id = p_id and s.kind not in ('SESSION', 'KEY', 'PROJECTOR', 'LOCK') and s.deleted_at is null;
682
+ select s.account into acc from @SCHEMA@.secret s where s.id = p_id and s.kind not in ('SESSION', 'KEY', 'LOCK') and s.deleted_at is null;
683
683
  if acc is null then
684
684
  return false;
685
685
  end if;
@@ -755,20 +755,21 @@ declare
755
755
  s record;
756
756
  begin
757
757
  if nullif(current_setting('letopis.account', true), '') is not null then
758
- perform @SCHEMA@.lt_fail('invalid_query', 'auth.switch — для собственной сессии, не при имперсонации');
758
+ -- код из каталога базы (invalid_query в нём нет — lt_fail дал бы LT000 и сырую ошибку; план 2.0, 7.5 №3)
759
+ perform @SCHEMA@.lt_fail('sql-access.switch_impersonating');
759
760
  end if;
760
761
  select x.id, x.account into s from @SCHEMA@.secret x
761
762
  where x.kind = 'SESSION' and x.deleted_at is null and x.material = sha256(convert_to(coalesce(tok, ''), 'UTF8'))
762
763
  and (x.expires_at is null or x.expires_at > clock_timestamp())
763
764
  for update;
764
765
  if s.id is null or not @SCHEMA@.auth_enabled(s.account) then
765
- perform @SCHEMA@.lt_fail('no_session', 'нет действующей сессии');
766
+ perform @SCHEMA@.lt_fail('sql-access.no_session');
766
767
  end if;
767
768
  if p_tenant <> s.account and not (
768
769
  exists (select 1 from @SCHEMA@.entity x
769
770
  where x.id = @SCHEMA@.v5_id(p_tenant, 'member', array[s.account::text, p_tenant::text]) and x.class = 'member' and x.tenant = p_tenant)
770
771
  and @SCHEMA@.auth_enabled(p_tenant)) then
771
- perform @SCHEMA@.lt_fail('tenant_denied', 'нет членства в арендаторе');
772
+ perform @SCHEMA@.lt_fail('sql-access.no_membership');
772
773
  end if;
773
774
  update @SCHEMA@.secret x
774
775
  set meta = case when p_tenant = s.account then x.meta - 'tenant' else x.meta || jsonb_build_object('tenant', p_tenant) end
@@ -849,10 +850,6 @@ begin
849
850
  execute format('revoke all on function @SCHEMA@.%s from public', f);
850
851
  end loop;
851
852
  end $$;
852
- -- до этапа 5 выпуск сессии сервисом принимал два аргумента; ранние сигнатуры OTP этапа 5
853
- drop function if exists @SCHEMA@.issue_session(uuid, interval);
854
- drop function if exists @SCHEMA@.auth_issue_otp(uuid, text, text, interval, int);
855
- drop function if exists @SCHEMA@.login_otp(text, text, text, int);
856
853
  grant execute on function
857
854
  @SCHEMA@.issue_session(uuid, interval, text[]), @SCHEMA@.auth_password_get(text, text),
858
855
  @SCHEMA@.auth_set_password(uuid, text, text, text, boolean, boolean), @SCHEMA@.auth_issue_apikey(uuid, text, interval),