@triagepilot/db 1.1.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/LICENSE +105 -0
- package/dist/availability.d.ts +164 -0
- package/dist/availability.js +974 -0
- package/dist/database.d.ts +3 -0
- package/dist/database.js +9 -0
- package/dist/decisions.d.ts +107 -0
- package/dist/decisions.js +435 -0
- package/dist/deliveries.d.ts +30 -0
- package/dist/deliveries.js +82 -0
- package/dist/heartbeat.d.ts +11 -0
- package/dist/heartbeat.js +11 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +13 -0
- package/dist/jobs.d.ts +86 -0
- package/dist/jobs.js +641 -0
- package/dist/kysely.d.ts +202 -0
- package/dist/kysely.js +1 -0
- package/dist/migrate.d.ts +1 -0
- package/dist/migrate.js +45 -0
- package/dist/operations.d.ts +77 -0
- package/dist/operations.js +256 -0
- package/dist/outbox.d.ts +61 -0
- package/dist/outbox.js +230 -0
- package/dist/provider-connections.d.ts +34 -0
- package/dist/provider-connections.js +302 -0
- package/dist/retention.d.ts +6 -0
- package/dist/retention.js +44 -0
- package/dist/routing-recovery.d.ts +55 -0
- package/dist/routing-recovery.js +175 -0
- package/dist/workspaces.d.ts +50 -0
- package/dist/workspaces.js +43 -0
- package/migrations/0001_initial.sql +79 -0
- package/migrations/0002_selected_reviewers.sql +10 -0
- package/migrations/0003_human_review_policy.sql +10 -0
- package/migrations/0004_semantic_routing_deduplication.sql +15 -0
- package/migrations/0005_reviewer_availability.sql +58 -0
- package/migrations/0005_workspace_scope.sql +198 -0
- package/migrations/0006_decision_outbox.sql +24 -0
- package/migrations/0007_workspace_reviewer_availability.sql +192 -0
- package/migrations/0008_reviewer_mutation_intents.sql +160 -0
- package/migrations/0009_provider_connection_revocations.sql +18 -0
- package/migrations/0010_provider_connection_preemptive_revocations.sql +12 -0
- package/package.json +42 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
create table decision_outbox (
|
|
2
|
+
id uuid primary key default gen_random_uuid(),
|
|
3
|
+
workspace_id uuid not null,
|
|
4
|
+
decision_id uuid not null,
|
|
5
|
+
schema_version integer not null,
|
|
6
|
+
payload jsonb not null,
|
|
7
|
+
occurred_at timestamptz not null,
|
|
8
|
+
available_at timestamptz not null default now(),
|
|
9
|
+
published_at timestamptz,
|
|
10
|
+
attempt_count integer not null default 0,
|
|
11
|
+
last_error text,
|
|
12
|
+
constraint decision_outbox_workspace_fkey
|
|
13
|
+
foreign key (workspace_id) references workspaces(id) on delete cascade,
|
|
14
|
+
constraint decision_outbox_workspace_decision_fkey
|
|
15
|
+
foreign key (workspace_id, decision_id)
|
|
16
|
+
references routing_decisions(workspace_id, id) on delete cascade,
|
|
17
|
+
constraint decision_outbox_workspace_decision_schema_key
|
|
18
|
+
unique (workspace_id, decision_id, schema_version),
|
|
19
|
+
constraint decision_outbox_attempt_count_check check (attempt_count >= 0)
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
create index decision_outbox_claim_idx
|
|
23
|
+
on decision_outbox (available_at, occurred_at)
|
|
24
|
+
where published_at is null;
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
create table workspace_operational_settings (
|
|
2
|
+
workspace_id uuid primary key references workspaces(id) on delete cascade,
|
|
3
|
+
timezone text not null default 'UTC',
|
|
4
|
+
updated_at timestamptz not null default now()
|
|
5
|
+
);
|
|
6
|
+
|
|
7
|
+
insert into workspace_operational_settings (workspace_id, timezone, updated_at)
|
|
8
|
+
select workspaces.id, organization_settings.timezone, organization_settings.updated_at
|
|
9
|
+
from workspaces
|
|
10
|
+
cross join organization_settings
|
|
11
|
+
where organization_settings.id = true;
|
|
12
|
+
|
|
13
|
+
drop table organization_settings;
|
|
14
|
+
|
|
15
|
+
alter table reviewer_absences drop constraint reviewer_absences_no_overlap;
|
|
16
|
+
drop index reviewer_absences_active_lookup;
|
|
17
|
+
|
|
18
|
+
alter table reviewer_absences
|
|
19
|
+
add column workspace_id uuid,
|
|
20
|
+
add column provider text,
|
|
21
|
+
add column provider_connection_id uuid;
|
|
22
|
+
|
|
23
|
+
update reviewer_absences
|
|
24
|
+
set workspace_id = local_connection.workspace_id,
|
|
25
|
+
provider = local_connection.provider,
|
|
26
|
+
provider_connection_id = local_connection.id
|
|
27
|
+
from (
|
|
28
|
+
select connections.id, connections.workspace_id, connections.provider
|
|
29
|
+
from provider_connections connections
|
|
30
|
+
join workspaces on workspaces.id = connections.workspace_id
|
|
31
|
+
where workspaces.external_key = 'self-hosted'
|
|
32
|
+
and connections.status = 'active'
|
|
33
|
+
order by connections.created_at, connections.id
|
|
34
|
+
limit 1
|
|
35
|
+
) local_connection;
|
|
36
|
+
|
|
37
|
+
alter table reviewer_absences rename column reviewer_handle to external_actor_id;
|
|
38
|
+
alter table reviewer_absences drop constraint reviewer_absences_normalized_handle;
|
|
39
|
+
alter table reviewer_absences alter column workspace_id set not null;
|
|
40
|
+
alter table reviewer_absences alter column provider set not null;
|
|
41
|
+
alter table reviewer_absences alter column provider_connection_id set not null;
|
|
42
|
+
alter table reviewer_absences
|
|
43
|
+
add constraint reviewer_absences_workspace_fkey
|
|
44
|
+
foreign key (workspace_id) references workspaces(id) on delete cascade;
|
|
45
|
+
alter table reviewer_absences
|
|
46
|
+
add constraint reviewer_absences_workspace_provider_connection_fkey
|
|
47
|
+
foreign key (workspace_id, provider, provider_connection_id)
|
|
48
|
+
references provider_connections(workspace_id, provider, id) on delete cascade;
|
|
49
|
+
alter table reviewer_absences
|
|
50
|
+
add constraint reviewer_absences_scoped_id_key
|
|
51
|
+
unique (workspace_id, provider, provider_connection_id, id);
|
|
52
|
+
alter table reviewer_absences
|
|
53
|
+
add constraint reviewer_absences_no_overlap exclude using gist (
|
|
54
|
+
workspace_id with =,
|
|
55
|
+
provider with =,
|
|
56
|
+
provider_connection_id with =,
|
|
57
|
+
external_actor_id with =,
|
|
58
|
+
tstzrange(start_at, end_at, '[)') with &&
|
|
59
|
+
) where (status = 'scheduled');
|
|
60
|
+
|
|
61
|
+
create index reviewer_absences_active_lookup
|
|
62
|
+
on reviewer_absences (
|
|
63
|
+
workspace_id, provider, provider_connection_id, external_actor_id, start_at, end_at
|
|
64
|
+
)
|
|
65
|
+
where status = 'scheduled';
|
|
66
|
+
|
|
67
|
+
alter table reviewer_replacements
|
|
68
|
+
add column workspace_id uuid,
|
|
69
|
+
add column provider text,
|
|
70
|
+
add column provider_connection_id uuid,
|
|
71
|
+
add column state text not null default 'completed',
|
|
72
|
+
add column last_error text;
|
|
73
|
+
|
|
74
|
+
update reviewer_replacements replacements
|
|
75
|
+
set workspace_id = absences.workspace_id,
|
|
76
|
+
provider = absences.provider,
|
|
77
|
+
provider_connection_id = absences.provider_connection_id
|
|
78
|
+
from reviewer_absences absences
|
|
79
|
+
where absences.id = replacements.absence_id;
|
|
80
|
+
|
|
81
|
+
alter table reviewer_replacements rename column unavailable_reviewer to unavailable_actor_id;
|
|
82
|
+
alter table reviewer_replacements rename column replacement_reviewer to replacement_actor_id;
|
|
83
|
+
alter table reviewer_replacements alter column workspace_id set not null;
|
|
84
|
+
alter table reviewer_replacements alter column provider set not null;
|
|
85
|
+
alter table reviewer_replacements alter column provider_connection_id set not null;
|
|
86
|
+
alter table reviewer_replacements drop constraint reviewer_replacements_absence_id_fkey;
|
|
87
|
+
alter table reviewer_replacements drop constraint reviewer_replacements_decision_id_fkey;
|
|
88
|
+
do $$
|
|
89
|
+
declare
|
|
90
|
+
historical_source_key name;
|
|
91
|
+
begin
|
|
92
|
+
select constraint_name into historical_source_key
|
|
93
|
+
from information_schema.table_constraints
|
|
94
|
+
where table_schema = 'public'
|
|
95
|
+
and table_name = 'reviewer_replacements'
|
|
96
|
+
and constraint_type = 'UNIQUE';
|
|
97
|
+
execute format(
|
|
98
|
+
'alter table reviewer_replacements drop constraint %I',
|
|
99
|
+
historical_source_key
|
|
100
|
+
);
|
|
101
|
+
end
|
|
102
|
+
$$;
|
|
103
|
+
alter table reviewer_replacements
|
|
104
|
+
add constraint reviewer_replacements_workspace_fkey
|
|
105
|
+
foreign key (workspace_id) references workspaces(id) on delete cascade;
|
|
106
|
+
alter table reviewer_replacements
|
|
107
|
+
add constraint reviewer_replacements_workspace_provider_connection_fkey
|
|
108
|
+
foreign key (workspace_id, provider, provider_connection_id)
|
|
109
|
+
references provider_connections(workspace_id, provider, id) on delete cascade;
|
|
110
|
+
alter table reviewer_replacements
|
|
111
|
+
add constraint reviewer_replacements_scoped_absence_fkey
|
|
112
|
+
foreign key (workspace_id, provider, provider_connection_id, absence_id)
|
|
113
|
+
references reviewer_absences(workspace_id, provider, provider_connection_id, id);
|
|
114
|
+
alter table reviewer_replacements
|
|
115
|
+
add constraint reviewer_replacements_workspace_decision_fkey
|
|
116
|
+
foreign key (workspace_id, decision_id)
|
|
117
|
+
references routing_decisions(workspace_id, id) on delete cascade;
|
|
118
|
+
alter table reviewer_replacements
|
|
119
|
+
add constraint reviewer_replacements_scoped_source_key
|
|
120
|
+
unique (
|
|
121
|
+
workspace_id, provider, provider_connection_id,
|
|
122
|
+
absence_id, absence_revision, decision_id
|
|
123
|
+
);
|
|
124
|
+
alter table reviewer_replacements
|
|
125
|
+
add constraint reviewer_replacements_workspace_id_key
|
|
126
|
+
unique (workspace_id, id);
|
|
127
|
+
|
|
128
|
+
drop index reviewer_replacements_absence_history;
|
|
129
|
+
create index reviewer_replacements_absence_history
|
|
130
|
+
on reviewer_replacements (
|
|
131
|
+
workspace_id, provider, provider_connection_id, absence_id, completed_at desc, id desc
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
alter table routing_decisions add column change_request_id text;
|
|
135
|
+
|
|
136
|
+
update routing_decisions decisions
|
|
137
|
+
set change_request_id = outbox.payload ->> 'changeRequestId'
|
|
138
|
+
from decision_outbox outbox
|
|
139
|
+
where outbox.workspace_id = decisions.workspace_id
|
|
140
|
+
and outbox.decision_id = decisions.id
|
|
141
|
+
and outbox.schema_version = 1
|
|
142
|
+
and jsonb_typeof(outbox.payload -> 'changeRequestId') = 'string'
|
|
143
|
+
and length(outbox.payload ->> 'changeRequestId') > 0;
|
|
144
|
+
|
|
145
|
+
alter table decision_outbox
|
|
146
|
+
add column event_id text,
|
|
147
|
+
add column event_type text,
|
|
148
|
+
add column reviewer_replacement_id uuid;
|
|
149
|
+
|
|
150
|
+
update decision_outbox
|
|
151
|
+
set event_id = coalesce(
|
|
152
|
+
payload ->> 'eventId',
|
|
153
|
+
'decision:' || decision_id::text || ':v' || schema_version::text
|
|
154
|
+
),
|
|
155
|
+
event_type = coalesce(payload ->> 'eventType', 'routing_decision'),
|
|
156
|
+
payload = payload || jsonb_build_object(
|
|
157
|
+
'eventId', coalesce(
|
|
158
|
+
payload ->> 'eventId',
|
|
159
|
+
'decision:' || decision_id::text || ':v' || schema_version::text
|
|
160
|
+
),
|
|
161
|
+
'eventType', coalesce(payload ->> 'eventType', 'routing_decision')
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
alter table decision_outbox alter column event_id set not null;
|
|
165
|
+
alter table decision_outbox alter column event_type set not null;
|
|
166
|
+
alter table decision_outbox alter column decision_id drop not null;
|
|
167
|
+
alter table decision_outbox drop constraint decision_outbox_workspace_decision_fkey;
|
|
168
|
+
alter table decision_outbox drop constraint decision_outbox_workspace_decision_schema_key;
|
|
169
|
+
alter table decision_outbox
|
|
170
|
+
add constraint decision_outbox_workspace_decision_fkey
|
|
171
|
+
foreign key (workspace_id, decision_id)
|
|
172
|
+
references routing_decisions(workspace_id, id) on delete cascade;
|
|
173
|
+
alter table decision_outbox
|
|
174
|
+
add constraint decision_outbox_workspace_reviewer_replacement_fkey
|
|
175
|
+
foreign key (workspace_id, reviewer_replacement_id)
|
|
176
|
+
references reviewer_replacements(workspace_id, id) on delete cascade;
|
|
177
|
+
alter table decision_outbox
|
|
178
|
+
add constraint decision_outbox_exactly_one_source
|
|
179
|
+
check (num_nonnulls(decision_id, reviewer_replacement_id) = 1);
|
|
180
|
+
alter table decision_outbox
|
|
181
|
+
add constraint decision_outbox_event_type_check
|
|
182
|
+
check (event_type in ('routing_decision', 'reviewer_replacement'));
|
|
183
|
+
alter table decision_outbox
|
|
184
|
+
add constraint decision_outbox_event_source_check
|
|
185
|
+
check (
|
|
186
|
+
num_nonnulls(decision_id, reviewer_replacement_id) <> 1 or
|
|
187
|
+
(event_type = 'routing_decision' and decision_id is not null) or
|
|
188
|
+
(event_type = 'reviewer_replacement' and reviewer_replacement_id is not null)
|
|
189
|
+
);
|
|
190
|
+
alter table decision_outbox
|
|
191
|
+
add constraint decision_outbox_workspace_event_key
|
|
192
|
+
unique (workspace_id, event_id);
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
alter table repositories
|
|
2
|
+
add constraint repositories_mutation_intent_source_key
|
|
3
|
+
unique (workspace_id, provider, provider_connection_id, id, external_repository_id);
|
|
4
|
+
|
|
5
|
+
alter table routing_decisions
|
|
6
|
+
add constraint routing_decisions_mutation_intent_source_key
|
|
7
|
+
unique (workspace_id, id, repository_id);
|
|
8
|
+
|
|
9
|
+
create table reviewer_mutation_intents (
|
|
10
|
+
id uuid primary key default gen_random_uuid(),
|
|
11
|
+
workspace_id uuid not null references workspaces(id) on delete cascade,
|
|
12
|
+
provider text not null,
|
|
13
|
+
provider_connection_id uuid not null,
|
|
14
|
+
absence_id uuid not null,
|
|
15
|
+
absence_revision integer not null check (absence_revision > 0),
|
|
16
|
+
decision_id uuid not null,
|
|
17
|
+
repository_record_id uuid not null,
|
|
18
|
+
repository_id text not null check (length(btrim(repository_id)) > 0),
|
|
19
|
+
change_request_id text not null check (length(btrim(change_request_id)) > 0),
|
|
20
|
+
expected_head_revision text not null check (length(btrim(expected_head_revision)) > 0),
|
|
21
|
+
unavailable_actor_id text not null check (length(btrim(unavailable_actor_id)) > 0),
|
|
22
|
+
replacement_actor_id text not null check (length(btrim(replacement_actor_id)) > 0),
|
|
23
|
+
created_at timestamptz not null default now(),
|
|
24
|
+
constraint reviewer_mutation_intents_workspace_provider_connection_fkey
|
|
25
|
+
foreign key (workspace_id, provider, provider_connection_id)
|
|
26
|
+
references provider_connections(workspace_id, provider, id) on delete cascade,
|
|
27
|
+
constraint reviewer_mutation_intents_scoped_absence_fkey
|
|
28
|
+
foreign key (workspace_id, provider, provider_connection_id, absence_id)
|
|
29
|
+
references reviewer_absences(workspace_id, provider, provider_connection_id, id),
|
|
30
|
+
constraint reviewer_mutation_intents_workspace_decision_fkey
|
|
31
|
+
foreign key (workspace_id, decision_id, repository_record_id)
|
|
32
|
+
references routing_decisions(workspace_id, id, repository_id),
|
|
33
|
+
constraint reviewer_mutation_intents_scoped_repository_fkey
|
|
34
|
+
foreign key (workspace_id, provider, provider_connection_id, repository_record_id, repository_id)
|
|
35
|
+
references repositories(workspace_id, provider, provider_connection_id, id, external_repository_id),
|
|
36
|
+
constraint reviewer_mutation_intents_source_key
|
|
37
|
+
unique (workspace_id, provider_connection_id, absence_id, absence_revision, decision_id),
|
|
38
|
+
constraint reviewer_mutation_intents_link_key
|
|
39
|
+
unique (
|
|
40
|
+
workspace_id, provider, provider_connection_id,
|
|
41
|
+
absence_id, absence_revision, decision_id, id
|
|
42
|
+
)
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
create function validate_reviewer_mutation_intent_insert() returns trigger
|
|
46
|
+
language plpgsql as $$
|
|
47
|
+
declare
|
|
48
|
+
current_revision integer;
|
|
49
|
+
begin
|
|
50
|
+
select revision into current_revision
|
|
51
|
+
from reviewer_absences
|
|
52
|
+
where workspace_id = new.workspace_id
|
|
53
|
+
and provider = new.provider
|
|
54
|
+
and provider_connection_id = new.provider_connection_id
|
|
55
|
+
and id = new.absence_id
|
|
56
|
+
for update;
|
|
57
|
+
if current_revision is null or current_revision <> new.absence_revision then
|
|
58
|
+
raise exception 'reviewer mutation intent absence revision is not current';
|
|
59
|
+
end if;
|
|
60
|
+
return new;
|
|
61
|
+
end;
|
|
62
|
+
$$;
|
|
63
|
+
|
|
64
|
+
create trigger reviewer_mutation_intents_validate_insert
|
|
65
|
+
before insert on reviewer_mutation_intents
|
|
66
|
+
for each row execute function validate_reviewer_mutation_intent_insert();
|
|
67
|
+
|
|
68
|
+
create function reject_reviewer_mutation_intent_update() returns trigger
|
|
69
|
+
language plpgsql as $$
|
|
70
|
+
begin
|
|
71
|
+
raise exception 'reviewer mutation intents are immutable';
|
|
72
|
+
end;
|
|
73
|
+
$$;
|
|
74
|
+
|
|
75
|
+
create trigger reviewer_mutation_intents_reject_update
|
|
76
|
+
before update on reviewer_mutation_intents
|
|
77
|
+
for each row execute function reject_reviewer_mutation_intent_update();
|
|
78
|
+
|
|
79
|
+
alter table reviewer_replacements add column mutation_intent_id uuid;
|
|
80
|
+
alter table reviewer_replacements
|
|
81
|
+
add constraint reviewer_replacements_mutation_intent_fkey
|
|
82
|
+
foreign key (
|
|
83
|
+
workspace_id, provider, provider_connection_id,
|
|
84
|
+
absence_id, absence_revision, decision_id, mutation_intent_id
|
|
85
|
+
) references reviewer_mutation_intents (
|
|
86
|
+
workspace_id, provider, provider_connection_id,
|
|
87
|
+
absence_id, absence_revision, decision_id, id
|
|
88
|
+
);
|
|
89
|
+
alter table reviewer_replacements
|
|
90
|
+
add constraint reviewer_replacements_replaced_intent_check
|
|
91
|
+
check (outcome <> 'replaced' or mutation_intent_id is not null) not valid;
|
|
92
|
+
|
|
93
|
+
alter table reviewer_replacements
|
|
94
|
+
add constraint reviewer_replacements_state_outcome_check
|
|
95
|
+
check (
|
|
96
|
+
(state = 'finalizer_pending'
|
|
97
|
+
and outcome in ('replaced', 'skipped_policy_satisfied', 'no_replacement_available')
|
|
98
|
+
and last_error is null)
|
|
99
|
+
or (state = 'completed' and outcome <> 'permanent_failure' and last_error is null)
|
|
100
|
+
or (state = 'permanent_failure'
|
|
101
|
+
and last_error is not null and length(btrim(last_error)) > 0)
|
|
102
|
+
) not valid;
|
|
103
|
+
|
|
104
|
+
create function validate_reviewer_replacement_insert() returns trigger
|
|
105
|
+
language plpgsql as $$
|
|
106
|
+
begin
|
|
107
|
+
if new.outcome = 'permanent_failure' then
|
|
108
|
+
if new.state <> 'permanent_failure' or new.last_error is null or length(btrim(new.last_error)) = 0 then
|
|
109
|
+
raise exception 'permanent reviewer failure requires permanent_failure state and error';
|
|
110
|
+
end if;
|
|
111
|
+
elsif new.outcome in ('replaced', 'skipped_policy_satisfied', 'no_replacement_available') then
|
|
112
|
+
if new.state <> 'finalizer_pending' or new.last_error is not null then
|
|
113
|
+
raise exception 'mapped reviewer finalizer outcome requires finalizer_pending state';
|
|
114
|
+
end if;
|
|
115
|
+
elsif new.state <> 'completed' or new.last_error is not null then
|
|
116
|
+
raise exception 'reviewer outcome without finalizer requires completed state';
|
|
117
|
+
end if;
|
|
118
|
+
return new;
|
|
119
|
+
end;
|
|
120
|
+
$$;
|
|
121
|
+
|
|
122
|
+
create trigger reviewer_replacements_validate_insert
|
|
123
|
+
before insert on reviewer_replacements
|
|
124
|
+
for each row execute function validate_reviewer_replacement_insert();
|
|
125
|
+
|
|
126
|
+
create function validate_reviewer_replacement_update() returns trigger
|
|
127
|
+
language plpgsql as $$
|
|
128
|
+
begin
|
|
129
|
+
if (new.id, new.workspace_id, new.provider, new.provider_connection_id,
|
|
130
|
+
new.absence_id, new.absence_revision, new.decision_id,
|
|
131
|
+
new.unavailable_actor_id, new.replacement_actor_id, new.mutation_intent_id,
|
|
132
|
+
new.outcome, new.reason, new.started_at, new.completed_at)
|
|
133
|
+
is distinct from
|
|
134
|
+
(old.id, old.workspace_id, old.provider, old.provider_connection_id,
|
|
135
|
+
old.absence_id, old.absence_revision, old.decision_id,
|
|
136
|
+
old.unavailable_actor_id, old.replacement_actor_id, old.mutation_intent_id,
|
|
137
|
+
old.outcome, old.reason, old.started_at, old.completed_at) then
|
|
138
|
+
raise exception 'reviewer replacement provenance is immutable';
|
|
139
|
+
end if;
|
|
140
|
+
if old.state <> 'finalizer_pending' then
|
|
141
|
+
raise exception 'terminal reviewer replacement is immutable';
|
|
142
|
+
end if;
|
|
143
|
+
if new.state = 'completed' then
|
|
144
|
+
if new.outcome = 'permanent_failure' or new.last_error is not null then
|
|
145
|
+
raise exception 'completed reviewer replacement state is malformed';
|
|
146
|
+
end if;
|
|
147
|
+
elsif new.state = 'permanent_failure' then
|
|
148
|
+
if new.last_error is null or length(btrim(new.last_error)) = 0 then
|
|
149
|
+
raise exception 'permanent reviewer replacement state requires an error';
|
|
150
|
+
end if;
|
|
151
|
+
else
|
|
152
|
+
raise exception 'reviewer replacement may only leave finalizer_pending';
|
|
153
|
+
end if;
|
|
154
|
+
return new;
|
|
155
|
+
end;
|
|
156
|
+
$$;
|
|
157
|
+
|
|
158
|
+
create trigger reviewer_replacements_validate_update
|
|
159
|
+
before update on reviewer_replacements
|
|
160
|
+
for each row execute function validate_reviewer_replacement_update();
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
alter table provider_connections
|
|
2
|
+
add constraint provider_connections_status_check
|
|
3
|
+
check (status in ('active', 'suspended', 'revoked')) not valid;
|
|
4
|
+
|
|
5
|
+
create table provider_connection_revocations (
|
|
6
|
+
workspace_id uuid not null references workspaces(id) on delete cascade,
|
|
7
|
+
provider text not null,
|
|
8
|
+
external_connection_id text not null,
|
|
9
|
+
revoked_connection_id uuid not null,
|
|
10
|
+
revoked_at timestamptz not null,
|
|
11
|
+
cleanup_completed_at timestamptz,
|
|
12
|
+
primary key (workspace_id, provider, revoked_connection_id),
|
|
13
|
+
unique (workspace_id, provider, external_connection_id)
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
create index provider_connection_revocations_cleanup_idx
|
|
17
|
+
on provider_connection_revocations (workspace_id, revoked_at, revoked_connection_id)
|
|
18
|
+
where cleanup_completed_at is null;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
alter table provider_connection_revocations
|
|
2
|
+
add column physical_connection_id uuid;
|
|
3
|
+
|
|
4
|
+
update provider_connection_revocations
|
|
5
|
+
set physical_connection_id = revoked_connection_id;
|
|
6
|
+
|
|
7
|
+
alter table provider_connection_revocations
|
|
8
|
+
alter column revoked_connection_id set default gen_random_uuid();
|
|
9
|
+
|
|
10
|
+
create unique index provider_connection_revocations_physical_key
|
|
11
|
+
on provider_connection_revocations (workspace_id, provider, physical_connection_id)
|
|
12
|
+
where physical_connection_id is not null;
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@triagepilot/db",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"license": "FSL-1.1-Apache-2.0",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/TriagePilot/triage-pilot.git",
|
|
8
|
+
"directory": "packages/db"
|
|
9
|
+
},
|
|
10
|
+
"type": "module",
|
|
11
|
+
"files": [
|
|
12
|
+
"dist",
|
|
13
|
+
"migrations",
|
|
14
|
+
"LICENSE"
|
|
15
|
+
],
|
|
16
|
+
"main": "./dist/index.js",
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
21
|
+
"import": "./dist/index.js"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@triagepilot/contracts": "1.1.0",
|
|
26
|
+
"kysely": "^0.28.17",
|
|
27
|
+
"pg": "^8.13.1"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/pg": "^8.11.10"
|
|
31
|
+
},
|
|
32
|
+
"publishConfig": {
|
|
33
|
+
"access": "public"
|
|
34
|
+
},
|
|
35
|
+
"publishedAt": "2026-09-22T09:41:47.000Z",
|
|
36
|
+
"futureLicenseEffectiveAt": "2028-09-22T09:41:47.000Z",
|
|
37
|
+
"scripts": {
|
|
38
|
+
"build": "rm -rf dist && tsc -p tsconfig.json",
|
|
39
|
+
"check": "tsc -p tsconfig.json --noEmit",
|
|
40
|
+
"migrate": "tsx src/migrate.ts"
|
|
41
|
+
}
|
|
42
|
+
}
|