letopis 1.1.0 → 1.3.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.en.md +113 -16
- package/AGENT-CHEATSHEET.md +106 -14
- package/CHANGELOG.md +702 -0
- package/README.en.md +798 -74
- package/README.md +756 -68
- package/dist/admin.d.ts +20 -4
- package/dist/admin.js +33 -9
- package/dist/cli.js +53 -4
- package/dist/errors.js +4 -2
- package/dist/index.d.ts +16 -2
- package/dist/index.js +94 -23
- package/dist/internal.d.ts +16 -0
- package/dist/internal.js +14 -0
- package/dist/load.js +42 -11
- package/dist/mcp.d.ts +28 -0
- package/dist/mcp.js +810 -0
- package/dist/model.d.ts +34 -0
- package/dist/model.js +17 -0
- package/dist/project.d.ts +318 -0
- package/dist/project.js +1142 -0
- package/dist/registry.d.ts +17 -0
- package/dist/registry.js +13 -0
- package/dist/sql.js +9 -5
- package/dist/sync.js +11 -2
- package/dist/types.d.ts +1 -1
- package/dist/types.js +1 -1
- package/dist/uuid.js +19 -8
- package/dist/watch.d.ts +12 -0
- package/dist/watch.js +48 -4
- package/dist/write.d.ts +1 -1
- package/dist/write.js +25 -5
- package/llms.txt +6 -2
- package/package.json +13 -2
- package/sql/10-core.sql +8 -2
- package/sql/15-errors.sql +4 -1
- package/sql/40-class.sql +57 -2
- package/sql/60-write.sql +629 -56
- package/sql/70-read.sql +33 -8
- package/sql/80-auth.sql +4 -4
- package/sql/88-derived.sql +1154 -0
- package/sql/90-time.sql +154 -13
- package/sql/95-seed.system.sql +12 -2
- package/sql/README.md +4 -1
package/sql/70-read.sql
CHANGED
|
@@ -40,7 +40,7 @@ return exists (select 1 from unnest(p_roles) r(role) where (p_links -> r.role) @
|
|
|
40
40
|
-- не позже p_at; p_at null — последняя вообще), которые ссылаются на p_src: кандидаты — версии,
|
|
41
41
|
-- ссылавшиеся на p_src (GIN log_ends), затем последняя версия каждого кандидата (log_id_rev); ссылку
|
|
42
42
|
-- проверяет она. Класс и время кандидатов — после пробы (offset 0): иначе планировщик объединяет пробу
|
|
43
|
-
-- с
|
|
43
|
+
-- с log_class_tenant_at и читает весь класс в индексе. Без прав: вызывают только функции владельца find_*,
|
|
44
44
|
-- видимость — на них.
|
|
45
45
|
create or replace function @SCHEMA@.log_refs_at(p_classes text[], p_src uuid, p_at timestamptz)
|
|
46
46
|
returns setof @SCHEMA@.log
|
|
@@ -60,6 +60,10 @@ $$;
|
|
|
60
60
|
|
|
61
61
|
-- id строк классов p_classes: по вложению в data (GIN entity_data), по целям концов (GIN entity_ends),
|
|
62
62
|
-- по списку id (первичный ключ) или по классу (entity_class_tenant).
|
|
63
|
+
-- Арендатор строки — явным условием (доработки после точки Б): row_visible пропускает только строки арендатора
|
|
64
|
+
-- сессии и System и свои членства (member) в других арендаторах, поэтому поиск сразу берёт строки этих двух
|
|
65
|
+
-- арендаторов, а свои членства — отдельным запросом по концу User; иначе цена поиска росла с данными других
|
|
66
|
+
-- арендаторов с теми же именами классов. По списку id условие ничего не даёт — там первичный ключ.
|
|
63
67
|
create or replace function @SCHEMA@.find_ids(p_classes text[], p_data jsonb, p_ends uuid[], p_ids uuid[],
|
|
64
68
|
p_at timestamptz default null, p_dead boolean default false)
|
|
65
69
|
returns table (id uuid, rev int)
|
|
@@ -72,6 +76,8 @@ declare
|
|
|
72
76
|
c_tenant uuid := (a->>'tenant')::uuid;
|
|
73
77
|
c_account uuid := (a->>'account')::uuid;
|
|
74
78
|
c_plan jsonb := a->'plan';
|
|
79
|
+
v_tenants uuid[] := array[(a->>'tenant')::uuid, '@SYSTEM@'::uuid];
|
|
80
|
+
v_member boolean := 'member' = any (p_classes);
|
|
75
81
|
begin
|
|
76
82
|
if c_account is null then
|
|
77
83
|
return;
|
|
@@ -83,21 +89,29 @@ begin
|
|
|
83
89
|
where e.id = any (p_ids) and e.class = any (p_classes)
|
|
84
90
|
and (p_data is null or e.data @> p_data) and (p_ends is null or e.ends @> p_ends)
|
|
85
91
|
and @SCHEMA@.row_visible(e.tenant, e.class, e.id, e.owner, e.tags, e.data, e.links, c_tenant, c_account, c_plan);
|
|
92
|
+
return;
|
|
86
93
|
elsif p_data is not null and p_ends is not null then
|
|
87
94
|
return query select e.id, e.rev from @SCHEMA@.entity e
|
|
88
|
-
where e.class = any (p_classes) and e.data @> p_data and e.ends @> p_ends
|
|
95
|
+
where e.class = any (p_classes) and e.tenant = any (v_tenants) and e.data @> p_data and e.ends @> p_ends
|
|
89
96
|
and @SCHEMA@.row_visible(e.tenant, e.class, e.id, e.owner, e.tags, e.data, e.links, c_tenant, c_account, c_plan);
|
|
90
97
|
elsif p_data is not null then
|
|
91
98
|
return query select e.id, e.rev from @SCHEMA@.entity e
|
|
92
|
-
where e.class = any (p_classes) and e.data @> p_data
|
|
99
|
+
where e.class = any (p_classes) and e.tenant = any (v_tenants) and e.data @> p_data
|
|
93
100
|
and @SCHEMA@.row_visible(e.tenant, e.class, e.id, e.owner, e.tags, e.data, e.links, c_tenant, c_account, c_plan);
|
|
94
101
|
elsif p_ends is not null then
|
|
95
102
|
return query select e.id, e.rev from @SCHEMA@.entity e
|
|
96
|
-
where e.class = any (p_classes) and e.ends @> p_ends
|
|
103
|
+
where e.class = any (p_classes) and e.tenant = any (v_tenants) and e.ends @> p_ends
|
|
97
104
|
and @SCHEMA@.row_visible(e.tenant, e.class, e.id, e.owner, e.tags, e.data, e.links, c_tenant, c_account, c_plan);
|
|
98
105
|
else
|
|
99
106
|
return query select e.id, e.rev from @SCHEMA@.entity e
|
|
100
|
-
where e.class = any (p_classes)
|
|
107
|
+
where e.class = any (p_classes) and e.tenant = any (v_tenants)
|
|
108
|
+
and @SCHEMA@.row_visible(e.tenant, e.class, e.id, e.owner, e.tags, e.data, e.links, c_tenant, c_account, c_plan);
|
|
109
|
+
end if;
|
|
110
|
+
-- свои членства в других арендаторах: по концу User (GIN entity_ends)
|
|
111
|
+
if v_member then
|
|
112
|
+
return query select e.id, e.rev from @SCHEMA@.entity e
|
|
113
|
+
where e.class = 'member' and e.ends @> array[c_account] and not (e.tenant = any (v_tenants))
|
|
114
|
+
and (p_data is null or e.data @> p_data) and (p_ends is null or e.ends @> p_ends)
|
|
101
115
|
and @SCHEMA@.row_visible(e.tenant, e.class, e.id, e.owner, e.tags, e.data, e.links, c_tenant, c_account, c_plan);
|
|
102
116
|
end if;
|
|
103
117
|
elsif p_ids is not null then
|
|
@@ -111,20 +125,31 @@ begin
|
|
|
111
125
|
and (p_data is null or v.data @> p_data) and (p_ends is null or @SCHEMA@.link_ids(v.links) @> p_ends)
|
|
112
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);
|
|
113
127
|
elsif p_ends is not null then
|
|
114
|
-
-- по целям концов — от версий, ссылавшихся на первую цель (GIN log_ends)
|
|
128
|
+
-- по целям концов — от версий, ссылавшихся на первую цель (GIN log_ends); арендатор — после пробы
|
|
115
129
|
return query select v.id, v.rev from @SCHEMA@.log_refs_at(p_classes, p_ends[1], p_at) v
|
|
116
|
-
where (v.
|
|
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')
|
|
117
132
|
and (p_data is null or v.data @> p_data) and @SCHEMA@.link_ids(v.links) @> p_ends
|
|
118
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);
|
|
119
134
|
else
|
|
135
|
+
-- арендатор id неизменен, записи purge и trim несут арендатора объекта: условие до distinct on не меняет, какая
|
|
136
|
+
-- версия id последняя (индекс log_class_tenant_at)
|
|
120
137
|
return query select v.id, v.rev from (
|
|
121
138
|
select distinct on (l.id) l.id, l.rev, l.op, l.class, l.tenant, l.owner, l.tags, l.data, l.links
|
|
122
139
|
from @SCHEMA@.log l
|
|
123
|
-
where l.class = any (p_classes) and l.at <= coalesce(p_at, 'infinity'::timestamptz)
|
|
140
|
+
where l.class = any (p_classes) and l.tenant = any (v_tenants) and l.at <= coalesce(p_at, 'infinity'::timestamptz)
|
|
124
141
|
order by l.id, l.rev desc) v
|
|
125
142
|
where (v.op = 'delete') = p_dead and v.op not in ('purge', 'trim', 'reset')
|
|
126
143
|
and (p_data is null or v.data @> p_data) and (p_ends is null or @SCHEMA@.link_ids(v.links) @> p_ends)
|
|
127
144
|
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
|
+
-- свои членства в других арендаторах: версии, ссылавшиеся на аккаунт (GIN log_ends)
|
|
146
|
+
if v_member then
|
|
147
|
+
return query select v.id, v.rev from @SCHEMA@.log_refs_at(array['member'], c_account, p_at) v
|
|
148
|
+
where not (v.tenant = any (v_tenants))
|
|
149
|
+
and (v.op = 'delete') = p_dead and v.op not in ('purge', 'trim', 'reset')
|
|
150
|
+
and (p_data is null or v.data @> p_data) and (p_ends is null or @SCHEMA@.link_ids(v.links) @> p_ends)
|
|
151
|
+
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
|
+
end if;
|
|
128
153
|
end if;
|
|
129
154
|
end $$;
|
|
130
155
|
|
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');
|
|
20
|
+
return p_kind ~ '^[A-Z][A-Z0-9_]{1,31}$' and p_kind not in ('SESSION', 'APIKEY', 'KEYSECRET', 'OTP', 'TOTP', 'KEY', 'PROJECTOR', 'LOCK');
|
|
21
21
|
|
|
22
22
|
-- Действующая сессия обязательна (иначе no_session).
|
|
23
23
|
create or replace function @SCHEMA@.auth_session_required(p_account uuid) returns void
|
|
@@ -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') and s.deleted_at is null
|
|
620
|
+
where s.account = p_account and s.kind not in ('SESSION', 'KEY', 'PROJECTOR', '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') 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', 'PROJECTOR', 'LOCK') and s.deleted_at is null;
|
|
643
643
|
if cr.account is null then
|
|
644
644
|
return false;
|
|
645
645
|
end if;
|
|
@@ -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') 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', 'PROJECTOR', 'LOCK') and s.deleted_at is null;
|
|
683
683
|
if acc is null then
|
|
684
684
|
return false;
|
|
685
685
|
end if;
|