@tickernelz/paperclip-pro-db 2026.1002.8 → 2026.1004.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.
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=chat-openwa-migration.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-openwa-migration.test.d.ts","sourceRoot":"","sources":["../src/chat-openwa-migration.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,126 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import postgres from "postgres";
3
+ import { describe, expect, it } from "vitest";
4
+ import { EMBEDDED_POSTGRES_TEST_TIMEOUT_MS, getEmbeddedPostgresTestSupport, startEmbeddedPostgresTestDatabase, } from "./test-embedded-postgres.js";
5
+ const support = await getEmbeddedPostgresTestSupport();
6
+ const describeDatabase = support.supported ? describe : describe.skip;
7
+ const NEW_TABLES = [
8
+ "chat_audit_entries",
9
+ "chat_endpoint_owners",
10
+ "chat_outbound_messages",
11
+ "chat_owner_approval_bubbles",
12
+ "chat_owner_approval_requests",
13
+ "chat_owner_grants",
14
+ "chat_scheduled_wakes",
15
+ "chat_sender_rules",
16
+ ];
17
+ describeDatabase("OpenWA chat migration", () => {
18
+ it("adds the OpenWA schema with tenant-scoped keys and enforced constraints", async () => {
19
+ const database = await startEmbeddedPostgresTestDatabase("paperclip-chat-openwa-");
20
+ const sql = postgres(database.connectionString, { max: 1, onnotice: () => { } });
21
+ try {
22
+ const columns = await sql `
23
+ SELECT table_name, column_name, data_type, is_nullable, column_default
24
+ FROM information_schema.columns
25
+ WHERE table_schema = 'public'
26
+ AND (table_name, column_name) IN (
27
+ ('chat_endpoints', 'policy'), ('chat_endpoints', 'policy_revision'), ('chat_endpoints', 'inflight_mode'),
28
+ ('chat_endpoint_resources', 'settings'), ('chat_external_principals', 'alternate_external_ids'),
29
+ ('chat_deliveries', 'trigger_class'), ('chat_deliveries', 'principal_role'), ('chat_deliveries', 'answer_state'))
30
+ ORDER BY table_name, column_name`;
31
+ expect(columns.map((row) => [row.table_name, row.column_name, row.data_type, row.is_nullable, row.column_default])).toEqual([
32
+ ["chat_deliveries", "answer_state", "text", "YES", null],
33
+ ["chat_deliveries", "principal_role", "text", "YES", null],
34
+ ["chat_deliveries", "trigger_class", "text", "YES", null],
35
+ ["chat_endpoint_resources", "settings", "jsonb", "NO", "'{}'::jsonb"],
36
+ ["chat_endpoints", "inflight_mode", "text", "NO", "'queue'::text"],
37
+ ["chat_endpoints", "policy", "jsonb", "NO", "'{}'::jsonb"],
38
+ ["chat_endpoints", "policy_revision", "integer", "NO", "0"],
39
+ ["chat_external_principals", "alternate_external_ids", "ARRAY", "NO", "'{}'::text[]"],
40
+ ]);
41
+ const tenantKeys = await sql `
42
+ SELECT conrelid::regclass::text AS table_name, pg_get_constraintdef(oid) AS definition
43
+ FROM pg_constraint
44
+ WHERE contype = 'f' AND conrelid::regclass::text = ANY(${NEW_TABLES})
45
+ AND pg_get_constraintdef(oid) LIKE 'FOREIGN KEY (company_id, endpoint_id) REFERENCES chat_endpoints(company_id, id)%'`;
46
+ expect(tenantKeys.map((row) => row.table_name).sort()).toEqual(NEW_TABLES);
47
+ expect(tenantKeys.every((row) => row.definition.endsWith("ON DELETE CASCADE"))).toBe(true);
48
+ const companyKeys = await sql `
49
+ SELECT conrelid::regclass::text AS table_name
50
+ FROM pg_constraint
51
+ WHERE contype = 'f' AND conrelid::regclass::text = ANY(${NEW_TABLES})
52
+ AND pg_get_constraintdef(oid) = 'FOREIGN KEY (company_id) REFERENCES companies(id) ON DELETE CASCADE'`;
53
+ expect(companyKeys.map((row) => row.table_name).sort()).toEqual(NEW_TABLES);
54
+ const make = async () => {
55
+ const ids = Object.fromEntries(["company", "agent", "application", "connection", "endpoint", "principal", "link"].map((key) => [key, randomUUID()]));
56
+ await sql `INSERT INTO companies (id,name,issue_prefix) VALUES (${ids.company},'OpenWA fixture',${ids.company})`;
57
+ await sql `INSERT INTO agents (id,company_id,name) VALUES (${ids.agent},${ids.company},'Agent')`;
58
+ await sql `INSERT INTO tool_applications (id,company_id,name,type) VALUES (${ids.application},${ids.company},'Fixture','mcp_http')`;
59
+ await sql `INSERT INTO tool_connections (id,company_id,application_id,uid,name,transport) VALUES (${ids.connection},${ids.company},${ids.application},${randomUUID()},'Fixture','rest_api')`;
60
+ await sql `INSERT INTO chat_endpoints (id,company_id,connection_id,provider,public_id,assigned_agent_id,status,provider_account_id,bot_external_id,inflight_mode)
61
+ VALUES (${ids.endpoint},${ids.company},${ids.connection},'openwa',${randomUUID()},${ids.agent},'active',${`http://gw#${ids.endpoint}`},${`+62${ids.endpoint.replace(/\D/g, "").slice(0, 10)}`},'steer')`;
62
+ await sql `INSERT INTO chat_external_principals (id,company_id,provider,provider_account_id,external_id,alternate_external_ids) VALUES (${ids.principal},${ids.company},'openwa','acct','628000@c.us',${sql.array(["1234@lid"])})`;
63
+ await sql `INSERT INTO chat_identity_links (id,company_id,endpoint_id,principal_id,status) VALUES (${ids.link},${ids.company},${ids.endpoint},${ids.principal},'linked')`;
64
+ return ids;
65
+ };
66
+ const own = await make();
67
+ const foreign = await make();
68
+ const [endpoint] = await sql `SELECT policy, policy_revision, inflight_mode FROM chat_endpoints WHERE id = ${own.endpoint}`;
69
+ expect(endpoint).toEqual({ policy: {}, policy_revision: 0, inflight_mode: "steer" });
70
+ await expect(sql `UPDATE chat_endpoints SET inflight_mode = 'drop' WHERE id = ${own.endpoint}`).rejects.toMatchObject({ code: "23514" });
71
+ await expect(sql `UPDATE chat_endpoints SET policy_revision = -1 WHERE id = ${own.endpoint}`).rejects.toMatchObject({ code: "23514" });
72
+ await expect(sql `UPDATE chat_endpoints SET provider = 'whatsapp' WHERE id = ${own.endpoint}`).rejects.toMatchObject({ code: "23514" });
73
+ const [ownEndpoint] = await sql `SELECT provider_account_id, bot_external_id FROM chat_endpoints WHERE id = ${own.endpoint}`;
74
+ await expect(sql `UPDATE chat_endpoints SET provider_account_id = ${ownEndpoint.provider_account_id} WHERE id = ${foreign.endpoint}`).rejects.toMatchObject({ code: "23505", constraint_name: "chat_endpoints_openwa_account_uq" });
75
+ await expect(sql `UPDATE chat_endpoints SET bot_external_id = ${ownEndpoint.bot_external_id} WHERE id = ${foreign.endpoint}`).rejects.toMatchObject({ code: "23505", constraint_name: "chat_endpoints_openwa_number_uq" });
76
+ await sql `UPDATE chat_endpoints SET status = 'archived' WHERE id = ${foreign.endpoint}`;
77
+ await sql `UPDATE chat_endpoints SET provider_account_id = ${ownEndpoint.provider_account_id}, bot_external_id = ${ownEndpoint.bot_external_id} WHERE id = ${foreign.endpoint}`;
78
+ await expect(sql `INSERT INTO chat_deliveries (company_id,endpoint_id,provider_event_id,deduplication_key,event_kind,normalized_event,trigger_class) VALUES (${own.company},${own.endpoint},'E0','E0','message','{}','vip')`).rejects.toMatchObject({ code: "23514" });
79
+ await sql `INSERT INTO chat_deliveries (company_id,endpoint_id,provider_event_id,deduplication_key,event_kind,normalized_event,trigger_class,principal_role,answer_state)
80
+ VALUES (${own.company},${own.endpoint},'E1','E1','message','{}','other','outside_allowlist','pending')`;
81
+ await expect(sql `INSERT INTO chat_endpoint_owners (company_id,endpoint_id,identity_link_id) VALUES (${own.company},${own.endpoint},${foreign.link})`).rejects.toMatchObject({ code: "23503" });
82
+ const [owner] = await sql `INSERT INTO chat_endpoint_owners (company_id,endpoint_id,identity_link_id) VALUES (${own.company},${own.endpoint},${own.link}) RETURNING id`;
83
+ await expect(sql `INSERT INTO chat_endpoint_owners (company_id,endpoint_id,identity_link_id) VALUES (${own.company},${own.endpoint},${own.link})`).rejects.toMatchObject({ code: "23505" });
84
+ await sql `INSERT INTO chat_sender_rules (company_id,endpoint_id,list,e164) VALUES (${own.company},${own.endpoint},'allow','+628123456789')`;
85
+ await expect(sql `INSERT INTO chat_sender_rules (company_id,endpoint_id,list,e164) VALUES (${own.company},${own.endpoint},'allow','+628123456789')`).rejects.toMatchObject({ code: "23505" });
86
+ await expect(sql `INSERT INTO chat_sender_rules (company_id,endpoint_id,list,e164) VALUES (${own.company},${own.endpoint},'deny','08123456789')`).rejects.toMatchObject({ code: "23514" });
87
+ const fireAt = new Date(Date.now() + 120_000);
88
+ await sql `INSERT INTO chat_scheduled_wakes (company_id,endpoint_id,chat_key,kind,fire_at) VALUES (${own.company},${own.endpoint},'g1','owner_absent',${fireAt})`;
89
+ await expect(sql `INSERT INTO chat_scheduled_wakes (company_id,endpoint_id,chat_key,kind,fire_at) VALUES (${own.company},${own.endpoint},'g1','owner_absent',${fireAt})`).rejects.toMatchObject({ code: "23505", constraint_name: "chat_scheduled_wakes_pending_absent_uq" });
90
+ await sql `UPDATE chat_scheduled_wakes SET state = 'fired' WHERE endpoint_id = ${own.endpoint}`;
91
+ await sql `INSERT INTO chat_scheduled_wakes (company_id,endpoint_id,chat_key,kind,fire_at) VALUES (${own.company},${own.endpoint},'g1','owner_absent',${fireAt})`;
92
+ await expect(sql `INSERT INTO chat_owner_approval_requests (company_id,endpoint_id,origin_chat_key,categories,scope,summary,proposed_action) VALUES (${own.company},${own.endpoint},'g1',${sql.array([])}::text[],'one_action','s','p')`).rejects.toMatchObject({ code: "23514" });
93
+ await expect(sql `INSERT INTO chat_owner_approval_requests (company_id,endpoint_id,origin_chat_key,categories,scope,summary,proposed_action) VALUES (${own.company},${own.endpoint},'g1',${sql.array(["root_shell"])}::text[],'one_action','s','p')`).rejects.toMatchObject({ code: "23514" });
94
+ await expect(sql `INSERT INTO chat_owner_approval_requests (company_id,endpoint_id,origin_chat_key,requested_by_principal_id,categories,scope,summary,proposed_action) VALUES (${own.company},${own.endpoint},'g1',${foreign.principal},${sql.array(["create_task"])}::text[],'one_action','s','p')`).rejects.toMatchObject({ code: "23503" });
95
+ const [request] = await sql `INSERT INTO chat_owner_approval_requests (company_id,endpoint_id,origin_chat_key,requested_by_principal_id,categories,scope,summary,proposed_action)
96
+ VALUES (${own.company},${own.endpoint},'g1',${own.principal},${sql.array(["create_task", "reply_outside_allowlist"])}::text[],'requester','s','p') RETURNING id, status, reminder_count`;
97
+ expect(request).toMatchObject({ status: "pending", reminder_count: 0 });
98
+ const [outbound] = await sql `INSERT INTO chat_outbound_messages (company_id,endpoint_id,chat_key,source,provider_message_id,state,body_hash,client_nonce)
99
+ VALUES (${own.company},${own.endpoint},'owner-dm','approval','wamid-1','sent','h','n1') RETURNING id`;
100
+ await expect(sql `INSERT INTO chat_outbound_messages (company_id,endpoint_id,chat_key,source,provider_message_id,body_hash,client_nonce) VALUES (${own.company},${own.endpoint},'g1','tool','wamid-1','h','n2')`).rejects.toMatchObject({ code: "23505", constraint_name: "chat_outbound_messages_provider_message_uq" });
101
+ await sql `INSERT INTO chat_outbound_messages (company_id,endpoint_id,chat_key,source,body_hash,client_nonce) VALUES (${own.company},${own.endpoint},'g1','tool','h','n3'), (${own.company},${own.endpoint},'g1','tool','h','n4')`;
102
+ await expect(sql `INSERT INTO chat_outbound_messages (company_id,endpoint_id,chat_key,source,state,body_hash,client_nonce) VALUES (${own.company},${own.endpoint},'g1','tool','delivered','h','n5')`).rejects.toMatchObject({ code: "23514" });
103
+ await sql `INSERT INTO chat_owner_approval_bubbles (company_id,endpoint_id,request_id,owner_id,outbound_message_id) VALUES (${own.company},${own.endpoint},${request.id},${owner.id},${outbound.id})`;
104
+ await expect(sql `INSERT INTO chat_owner_approval_bubbles (company_id,endpoint_id,request_id,owner_id,outbound_message_id) VALUES (${own.company},${own.endpoint},${request.id},${owner.id},${outbound.id})`).rejects.toMatchObject({ code: "23505" });
105
+ const expiresAt = new Date(Date.now() + 86_400_000);
106
+ await sql `INSERT INTO chat_owner_grants (company_id,endpoint_id,request_id,origin_chat_key,requester_principal_id,category,scope,approved_via,expires_at)
107
+ VALUES (${own.company},${own.endpoint},${request.id},'g1',${own.principal},'create_task','requester','whatsapp',${expiresAt})`;
108
+ await expect(sql `INSERT INTO chat_owner_grants (company_id,endpoint_id,request_id,origin_chat_key,category,scope,approved_via,expires_at) VALUES (${own.company},${own.endpoint},${request.id},'g1','create_task','forever','whatsapp',${expiresAt})`).rejects.toMatchObject({ code: "23514" });
109
+ await expect(sql `INSERT INTO chat_owner_grants (company_id,endpoint_id,request_id,origin_chat_key,category,scope,approved_via,expires_at) VALUES (${foreign.company},${foreign.endpoint},${request.id},'g1','create_task','one_action','paperclip',${expiresAt})`).rejects.toMatchObject({ code: "23503" });
110
+ await sql `INSERT INTO chat_audit_entries (company_id,endpoint_id,chat_key,kind,actor_kind,content,content_purge_at) VALUES (${own.company},${own.endpoint},'g1','trigger_admitted','chat_principal','{"text":"hi"}',now() + interval '90 days')`;
111
+ await expect(sql `INSERT INTO chat_audit_entries (company_id,endpoint_id,kind,actor_kind) VALUES (${own.company},${own.endpoint},'anything','system')`).rejects.toMatchObject({ code: "23514" });
112
+ await sql `DELETE FROM chat_identity_links WHERE id = ${own.link}`;
113
+ expect(await sql `SELECT id FROM chat_endpoint_owners WHERE endpoint_id = ${own.endpoint}`).toHaveLength(0);
114
+ expect(await sql `SELECT id FROM chat_owner_approval_bubbles WHERE endpoint_id = ${own.endpoint}`).toHaveLength(0);
115
+ await sql `DELETE FROM chat_endpoints WHERE id = ${own.endpoint}`;
116
+ for (const table of NEW_TABLES) {
117
+ expect(await sql.unsafe(`SELECT id FROM "${table}" WHERE company_id = $1`, [own.company]), table).toHaveLength(0);
118
+ }
119
+ }
120
+ finally {
121
+ await sql.end();
122
+ await database.cleanup();
123
+ }
124
+ }, EMBEDDED_POSTGRES_TEST_TIMEOUT_MS);
125
+ });
126
+ //# sourceMappingURL=chat-openwa-migration.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-openwa-migration.test.js","sourceRoot":"","sources":["../src/chat-openwa-migration.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,215 @@
1
+ CREATE TABLE "chat_audit_entries" (
2
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
3
+ "company_id" uuid NOT NULL,
4
+ "endpoint_id" uuid NOT NULL,
5
+ "conversation_id" uuid,
6
+ "chat_key" text,
7
+ "kind" text NOT NULL,
8
+ "actor_kind" text NOT NULL,
9
+ "actor_ref" text,
10
+ "run_id" uuid,
11
+ "metadata" jsonb DEFAULT '{}'::jsonb NOT NULL,
12
+ "content" jsonb,
13
+ "content_purge_at" timestamp with time zone,
14
+ "occurred_at" timestamp with time zone DEFAULT now() NOT NULL,
15
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
16
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL,
17
+ CONSTRAINT "chat_audit_entries_kind_check" CHECK ("chat_audit_entries"."kind" in ('trigger_admitted', 'trigger_filtered', 'message_sent', 'publication_suppressed', 'tool_called', 'approval_requested', 'approval_reminded', 'approval_resolved', 'approval_cancelled', 'config_changed', 'group_added', 'group_left', 'session_health')),
18
+ CONSTRAINT "chat_audit_entries_actor_kind_check" CHECK ("chat_audit_entries"."actor_kind" in ('user', 'agent', 'chat_principal', 'system'))
19
+ );
20
+ --> statement-breakpoint
21
+ CREATE TABLE "chat_endpoint_owners" (
22
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
23
+ "company_id" uuid NOT NULL,
24
+ "endpoint_id" uuid NOT NULL,
25
+ "identity_link_id" uuid NOT NULL,
26
+ "added_by_user_id" text,
27
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
28
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL,
29
+ CONSTRAINT "chat_endpoint_owners_company_id_uq" UNIQUE("company_id","id")
30
+ );
31
+ --> statement-breakpoint
32
+ CREATE TABLE "chat_outbound_messages" (
33
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
34
+ "company_id" uuid NOT NULL,
35
+ "endpoint_id" uuid NOT NULL,
36
+ "chat_key" text NOT NULL,
37
+ "source" text NOT NULL,
38
+ "run_id" uuid,
39
+ "provider_message_id" text,
40
+ "state" text DEFAULT 'pending' NOT NULL,
41
+ "body_hash" text NOT NULL,
42
+ "client_nonce" text NOT NULL,
43
+ "sent_at" timestamp with time zone,
44
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
45
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL,
46
+ CONSTRAINT "chat_outbound_messages_company_id_uq" UNIQUE("company_id","id"),
47
+ CONSTRAINT "chat_outbound_messages_source_check" CHECK ("chat_outbound_messages"."source" in ('tool', 'publication', 'approval')),
48
+ CONSTRAINT "chat_outbound_messages_state_check" CHECK ("chat_outbound_messages"."state" in ('pending', 'sent', 'uncertain', 'failed'))
49
+ );
50
+ --> statement-breakpoint
51
+ CREATE TABLE "chat_owner_approval_bubbles" (
52
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
53
+ "company_id" uuid NOT NULL,
54
+ "endpoint_id" uuid NOT NULL,
55
+ "request_id" uuid NOT NULL,
56
+ "owner_id" uuid NOT NULL,
57
+ "outbound_message_id" uuid NOT NULL,
58
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
59
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL
60
+ );
61
+ --> statement-breakpoint
62
+ CREATE TABLE "chat_owner_approval_requests" (
63
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
64
+ "company_id" uuid NOT NULL,
65
+ "endpoint_id" uuid NOT NULL,
66
+ "origin_chat_key" text NOT NULL,
67
+ "origin_conversation_id" uuid,
68
+ "interaction_id" uuid,
69
+ "requested_by_principal_id" uuid,
70
+ "requested_in_run_id" uuid,
71
+ "categories" text[] NOT NULL,
72
+ "scope" text NOT NULL,
73
+ "summary" text NOT NULL,
74
+ "proposed_action" text NOT NULL,
75
+ "status" text DEFAULT 'pending' NOT NULL,
76
+ "reminder_count" integer DEFAULT 0 NOT NULL,
77
+ "resolved_via" text,
78
+ "resolved_by_user_id" text,
79
+ "owner_text" text,
80
+ "agent_conditions" text,
81
+ "resolved_at" timestamp with time zone,
82
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
83
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL,
84
+ CONSTRAINT "chat_owner_approval_requests_company_id_uq" UNIQUE("company_id","id"),
85
+ CONSTRAINT "chat_owner_approval_requests_categories_check" CHECK (cardinality("chat_owner_approval_requests"."categories") > 0 and "chat_owner_approval_requests"."categories" <@ array['create_task', 'external_tools', 'cross_chat_send', 'wa_admin', 'gateway_admin', 'reply_outside_allowlist', 'reply']::text[]),
86
+ CONSTRAINT "chat_owner_approval_requests_scope_check" CHECK ("chat_owner_approval_requests"."scope" in ('one_action', 'requester')),
87
+ CONSTRAINT "chat_owner_approval_requests_status_check" CHECK ("chat_owner_approval_requests"."status" in ('pending', 'approved', 'rejected', 'cancelled')),
88
+ CONSTRAINT "chat_owner_approval_requests_resolved_via_check" CHECK ("chat_owner_approval_requests"."resolved_via" is null or "chat_owner_approval_requests"."resolved_via" in ('whatsapp', 'paperclip')),
89
+ CONSTRAINT "chat_owner_approval_requests_reminder_count_check" CHECK ("chat_owner_approval_requests"."reminder_count" >= 0)
90
+ );
91
+ --> statement-breakpoint
92
+ CREATE TABLE "chat_owner_grants" (
93
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
94
+ "company_id" uuid NOT NULL,
95
+ "endpoint_id" uuid NOT NULL,
96
+ "request_id" uuid NOT NULL,
97
+ "origin_chat_key" text NOT NULL,
98
+ "requester_principal_id" uuid,
99
+ "category" text NOT NULL,
100
+ "scope" text NOT NULL,
101
+ "status" text DEFAULT 'live' NOT NULL,
102
+ "approved_by_user_id" text,
103
+ "approved_via" text NOT NULL,
104
+ "expires_at" timestamp with time zone NOT NULL,
105
+ "consumed_at" timestamp with time zone,
106
+ "consumed_by_run_id" uuid,
107
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
108
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL,
109
+ CONSTRAINT "chat_owner_grants_category_check" CHECK ("chat_owner_grants"."category" in ('create_task', 'external_tools', 'cross_chat_send', 'wa_admin', 'gateway_admin', 'reply_outside_allowlist', 'reply')),
110
+ CONSTRAINT "chat_owner_grants_scope_check" CHECK ("chat_owner_grants"."scope" in ('one_action', 'requester')),
111
+ CONSTRAINT "chat_owner_grants_status_check" CHECK ("chat_owner_grants"."status" in ('live', 'consumed', 'revoked', 'expired')),
112
+ CONSTRAINT "chat_owner_grants_approved_via_check" CHECK ("chat_owner_grants"."approved_via" in ('whatsapp', 'paperclip'))
113
+ );
114
+ --> statement-breakpoint
115
+ CREATE TABLE "chat_scheduled_wakes" (
116
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
117
+ "company_id" uuid NOT NULL,
118
+ "endpoint_id" uuid NOT NULL,
119
+ "chat_key" text NOT NULL,
120
+ "kind" text NOT NULL,
121
+ "fire_at" timestamp with time zone NOT NULL,
122
+ "state" text DEFAULT 'pending' NOT NULL,
123
+ "related_id" uuid,
124
+ "payload" jsonb DEFAULT '{}'::jsonb NOT NULL,
125
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
126
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL,
127
+ CONSTRAINT "chat_scheduled_wakes_kind_check" CHECK ("chat_scheduled_wakes"."kind" in ('owner_absent', 'approval_reminder')),
128
+ CONSTRAINT "chat_scheduled_wakes_state_check" CHECK ("chat_scheduled_wakes"."state" in ('pending', 'fired', 'cancelled'))
129
+ );
130
+ --> statement-breakpoint
131
+ CREATE TABLE "chat_sender_rules" (
132
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
133
+ "company_id" uuid NOT NULL,
134
+ "endpoint_id" uuid NOT NULL,
135
+ "list" text NOT NULL,
136
+ "e164" text NOT NULL,
137
+ "label" text,
138
+ "created_by_user_id" text,
139
+ "created_by_principal_id" uuid,
140
+ "created_at" timestamp with time zone DEFAULT now() NOT NULL,
141
+ "updated_at" timestamp with time zone DEFAULT now() NOT NULL,
142
+ CONSTRAINT "chat_sender_rules_list_check" CHECK ("chat_sender_rules"."list" in ('allow', 'deny')),
143
+ CONSTRAINT "chat_sender_rules_e164_check" CHECK ("chat_sender_rules"."e164" ~ '^[+][1-9][0-9]{6,14}$')
144
+ );
145
+ --> statement-breakpoint
146
+ ALTER TABLE "chat_endpoints" DROP CONSTRAINT IF EXISTS "chat_endpoints_provider_check";--> statement-breakpoint
147
+ ALTER TABLE "chat_external_principals" DROP CONSTRAINT IF EXISTS "chat_external_principals_provider_check";--> statement-breakpoint
148
+ ALTER TABLE "chat_deliveries" ADD COLUMN "trigger_class" text;--> statement-breakpoint
149
+ ALTER TABLE "chat_deliveries" ADD COLUMN "principal_role" text;--> statement-breakpoint
150
+ ALTER TABLE "chat_deliveries" ADD COLUMN "answer_state" text;--> statement-breakpoint
151
+ ALTER TABLE "chat_endpoint_resources" ADD COLUMN "settings" jsonb DEFAULT '{}'::jsonb NOT NULL;--> statement-breakpoint
152
+ ALTER TABLE "chat_endpoints" ADD COLUMN "policy" jsonb DEFAULT '{}'::jsonb NOT NULL;--> statement-breakpoint
153
+ ALTER TABLE "chat_endpoints" ADD COLUMN "policy_revision" integer DEFAULT 0 NOT NULL;--> statement-breakpoint
154
+ ALTER TABLE "chat_endpoints" ADD COLUMN "inflight_mode" text DEFAULT 'queue' NOT NULL;--> statement-breakpoint
155
+ ALTER TABLE "chat_external_principals" ADD COLUMN "alternate_external_ids" text[] DEFAULT '{}'::text[] NOT NULL;--> statement-breakpoint
156
+ ALTER TABLE "chat_identity_links" ADD CONSTRAINT "chat_identity_links_company_id_uq" UNIQUE("company_id","id");--> statement-breakpoint
157
+ ALTER TABLE "chat_audit_entries" ADD CONSTRAINT "chat_audit_entries_company_id_companies_id_fk" FOREIGN KEY ("company_id") REFERENCES "public"."companies"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
158
+ ALTER TABLE "chat_audit_entries" ADD CONSTRAINT "chat_audit_entries_conversation_id_chat_conversations_id_fk" FOREIGN KEY ("conversation_id") REFERENCES "public"."chat_conversations"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
159
+ ALTER TABLE "chat_audit_entries" ADD CONSTRAINT "chat_audit_entries_run_id_heartbeat_runs_id_fk" FOREIGN KEY ("run_id") REFERENCES "public"."heartbeat_runs"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
160
+ ALTER TABLE "chat_audit_entries" ADD CONSTRAINT "chat_audit_entries_company_endpoint_fk" FOREIGN KEY ("company_id","endpoint_id") REFERENCES "public"."chat_endpoints"("company_id","id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
161
+ ALTER TABLE "chat_audit_entries" ADD CONSTRAINT "chat_audit_entries_company_conversation_fk" FOREIGN KEY ("company_id","conversation_id") REFERENCES "public"."chat_conversations"("company_id","id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
162
+ ALTER TABLE "chat_endpoint_owners" ADD CONSTRAINT "chat_endpoint_owners_company_id_companies_id_fk" FOREIGN KEY ("company_id") REFERENCES "public"."companies"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
163
+ ALTER TABLE "chat_endpoint_owners" ADD CONSTRAINT "chat_endpoint_owners_company_endpoint_fk" FOREIGN KEY ("company_id","endpoint_id") REFERENCES "public"."chat_endpoints"("company_id","id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
164
+ ALTER TABLE "chat_endpoint_owners" ADD CONSTRAINT "chat_endpoint_owners_company_identity_link_fk" FOREIGN KEY ("company_id","identity_link_id") REFERENCES "public"."chat_identity_links"("company_id","id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
165
+ ALTER TABLE "chat_outbound_messages" ADD CONSTRAINT "chat_outbound_messages_company_id_companies_id_fk" FOREIGN KEY ("company_id") REFERENCES "public"."companies"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
166
+ ALTER TABLE "chat_outbound_messages" ADD CONSTRAINT "chat_outbound_messages_run_id_heartbeat_runs_id_fk" FOREIGN KEY ("run_id") REFERENCES "public"."heartbeat_runs"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
167
+ ALTER TABLE "chat_outbound_messages" ADD CONSTRAINT "chat_outbound_messages_company_endpoint_fk" FOREIGN KEY ("company_id","endpoint_id") REFERENCES "public"."chat_endpoints"("company_id","id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
168
+ ALTER TABLE "chat_owner_approval_bubbles" ADD CONSTRAINT "chat_owner_approval_bubbles_company_id_companies_id_fk" FOREIGN KEY ("company_id") REFERENCES "public"."companies"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
169
+ ALTER TABLE "chat_owner_approval_bubbles" ADD CONSTRAINT "chat_owner_approval_bubbles_company_endpoint_fk" FOREIGN KEY ("company_id","endpoint_id") REFERENCES "public"."chat_endpoints"("company_id","id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
170
+ ALTER TABLE "chat_owner_approval_bubbles" ADD CONSTRAINT "chat_owner_approval_bubbles_company_request_fk" FOREIGN KEY ("company_id","request_id") REFERENCES "public"."chat_owner_approval_requests"("company_id","id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
171
+ ALTER TABLE "chat_owner_approval_bubbles" ADD CONSTRAINT "chat_owner_approval_bubbles_company_owner_fk" FOREIGN KEY ("company_id","owner_id") REFERENCES "public"."chat_endpoint_owners"("company_id","id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
172
+ ALTER TABLE "chat_owner_approval_bubbles" ADD CONSTRAINT "chat_owner_approval_bubbles_company_outbound_fk" FOREIGN KEY ("company_id","outbound_message_id") REFERENCES "public"."chat_outbound_messages"("company_id","id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
173
+ ALTER TABLE "chat_owner_approval_requests" ADD CONSTRAINT "chat_owner_approval_requests_company_id_companies_id_fk" FOREIGN KEY ("company_id") REFERENCES "public"."companies"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
174
+ ALTER TABLE "chat_owner_approval_requests" ADD CONSTRAINT "chat_owner_approval_requests_origin_conversation_id_chat_conversations_id_fk" FOREIGN KEY ("origin_conversation_id") REFERENCES "public"."chat_conversations"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
175
+ ALTER TABLE "chat_owner_approval_requests" ADD CONSTRAINT "chat_owner_approval_requests_interaction_id_issue_thread_interactions_id_fk" FOREIGN KEY ("interaction_id") REFERENCES "public"."issue_thread_interactions"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
176
+ ALTER TABLE "chat_owner_approval_requests" ADD CONSTRAINT "chat_owner_approval_requests_requested_by_principal_id_chat_external_principals_id_fk" FOREIGN KEY ("requested_by_principal_id") REFERENCES "public"."chat_external_principals"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
177
+ ALTER TABLE "chat_owner_approval_requests" ADD CONSTRAINT "chat_owner_approval_requests_requested_in_run_id_heartbeat_runs_id_fk" FOREIGN KEY ("requested_in_run_id") REFERENCES "public"."heartbeat_runs"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
178
+ ALTER TABLE "chat_owner_approval_requests" ADD CONSTRAINT "chat_owner_approval_requests_company_endpoint_fk" FOREIGN KEY ("company_id","endpoint_id") REFERENCES "public"."chat_endpoints"("company_id","id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
179
+ ALTER TABLE "chat_owner_approval_requests" ADD CONSTRAINT "chat_owner_approval_requests_company_conversation_fk" FOREIGN KEY ("company_id","origin_conversation_id") REFERENCES "public"."chat_conversations"("company_id","id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
180
+ ALTER TABLE "chat_owner_approval_requests" ADD CONSTRAINT "chat_owner_approval_requests_company_principal_fk" FOREIGN KEY ("company_id","requested_by_principal_id") REFERENCES "public"."chat_external_principals"("company_id","id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
181
+ ALTER TABLE "chat_owner_grants" ADD CONSTRAINT "chat_owner_grants_company_id_companies_id_fk" FOREIGN KEY ("company_id") REFERENCES "public"."companies"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
182
+ ALTER TABLE "chat_owner_grants" ADD CONSTRAINT "chat_owner_grants_requester_principal_id_chat_external_principals_id_fk" FOREIGN KEY ("requester_principal_id") REFERENCES "public"."chat_external_principals"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
183
+ ALTER TABLE "chat_owner_grants" ADD CONSTRAINT "chat_owner_grants_consumed_by_run_id_heartbeat_runs_id_fk" FOREIGN KEY ("consumed_by_run_id") REFERENCES "public"."heartbeat_runs"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
184
+ ALTER TABLE "chat_owner_grants" ADD CONSTRAINT "chat_owner_grants_company_endpoint_fk" FOREIGN KEY ("company_id","endpoint_id") REFERENCES "public"."chat_endpoints"("company_id","id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
185
+ ALTER TABLE "chat_owner_grants" ADD CONSTRAINT "chat_owner_grants_company_request_fk" FOREIGN KEY ("company_id","request_id") REFERENCES "public"."chat_owner_approval_requests"("company_id","id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
186
+ ALTER TABLE "chat_owner_grants" ADD CONSTRAINT "chat_owner_grants_company_principal_fk" FOREIGN KEY ("company_id","requester_principal_id") REFERENCES "public"."chat_external_principals"("company_id","id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
187
+ ALTER TABLE "chat_scheduled_wakes" ADD CONSTRAINT "chat_scheduled_wakes_company_id_companies_id_fk" FOREIGN KEY ("company_id") REFERENCES "public"."companies"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
188
+ ALTER TABLE "chat_scheduled_wakes" ADD CONSTRAINT "chat_scheduled_wakes_company_endpoint_fk" FOREIGN KEY ("company_id","endpoint_id") REFERENCES "public"."chat_endpoints"("company_id","id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
189
+ ALTER TABLE "chat_sender_rules" ADD CONSTRAINT "chat_sender_rules_company_id_companies_id_fk" FOREIGN KEY ("company_id") REFERENCES "public"."companies"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
190
+ ALTER TABLE "chat_sender_rules" ADD CONSTRAINT "chat_sender_rules_created_by_principal_id_chat_external_principals_id_fk" FOREIGN KEY ("created_by_principal_id") REFERENCES "public"."chat_external_principals"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
191
+ ALTER TABLE "chat_sender_rules" ADD CONSTRAINT "chat_sender_rules_company_endpoint_fk" FOREIGN KEY ("company_id","endpoint_id") REFERENCES "public"."chat_endpoints"("company_id","id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
192
+ ALTER TABLE "chat_sender_rules" ADD CONSTRAINT "chat_sender_rules_company_principal_fk" FOREIGN KEY ("company_id","created_by_principal_id") REFERENCES "public"."chat_external_principals"("company_id","id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
193
+ CREATE INDEX "chat_audit_entries_endpoint_occurred_idx" ON "chat_audit_entries" USING btree ("endpoint_id","occurred_at" DESC NULLS LAST);--> statement-breakpoint
194
+ CREATE INDEX "chat_audit_entries_content_purge_idx" ON "chat_audit_entries" USING btree ("content_purge_at") WHERE "chat_audit_entries"."content" is not null;--> statement-breakpoint
195
+ CREATE UNIQUE INDEX "chat_endpoint_owners_link_uq" ON "chat_endpoint_owners" USING btree ("endpoint_id","identity_link_id");--> statement-breakpoint
196
+ CREATE UNIQUE INDEX "chat_outbound_messages_provider_message_uq" ON "chat_outbound_messages" USING btree ("endpoint_id","provider_message_id") WHERE "chat_outbound_messages"."provider_message_id" is not null;--> statement-breakpoint
197
+ CREATE INDEX "chat_outbound_messages_chat_state_idx" ON "chat_outbound_messages" USING btree ("endpoint_id","chat_key","state");--> statement-breakpoint
198
+ CREATE INDEX "chat_outbound_messages_sent_at_idx" ON "chat_outbound_messages" USING btree ("endpoint_id","sent_at");--> statement-breakpoint
199
+ CREATE UNIQUE INDEX "chat_owner_approval_bubbles_outbound_uq" ON "chat_owner_approval_bubbles" USING btree ("endpoint_id","outbound_message_id");--> statement-breakpoint
200
+ CREATE INDEX "chat_owner_approval_bubbles_request_idx" ON "chat_owner_approval_bubbles" USING btree ("request_id");--> statement-breakpoint
201
+ CREATE INDEX "chat_owner_approval_requests_status_idx" ON "chat_owner_approval_requests" USING btree ("endpoint_id","status");--> statement-breakpoint
202
+ CREATE INDEX "chat_owner_grants_lookup_idx" ON "chat_owner_grants" USING btree ("endpoint_id","origin_chat_key","requester_principal_id","status");--> statement-breakpoint
203
+ CREATE INDEX "chat_owner_grants_request_idx" ON "chat_owner_grants" USING btree ("request_id");--> statement-breakpoint
204
+ CREATE INDEX "chat_scheduled_wakes_pending_fire_idx" ON "chat_scheduled_wakes" USING btree ("fire_at") WHERE "chat_scheduled_wakes"."state" = 'pending';--> statement-breakpoint
205
+ CREATE UNIQUE INDEX "chat_scheduled_wakes_pending_absent_uq" ON "chat_scheduled_wakes" USING btree ("endpoint_id","chat_key") WHERE "chat_scheduled_wakes"."kind" = 'owner_absent' and "chat_scheduled_wakes"."state" = 'pending';--> statement-breakpoint
206
+ CREATE UNIQUE INDEX "chat_sender_rules_entry_uq" ON "chat_sender_rules" USING btree ("endpoint_id","list","e164");--> statement-breakpoint
207
+ CREATE UNIQUE INDEX "chat_endpoints_openwa_account_uq" ON "chat_endpoints" USING btree ("provider_account_id") WHERE "chat_endpoints"."provider" = 'openwa' and "chat_endpoints"."status" <> 'archived' and "chat_endpoints"."provider_account_id" is not null;--> statement-breakpoint
208
+ CREATE UNIQUE INDEX "chat_endpoints_openwa_number_uq" ON "chat_endpoints" USING btree ("bot_external_id") WHERE "chat_endpoints"."provider" = 'openwa' and "chat_endpoints"."status" <> 'archived' and "chat_endpoints"."bot_external_id" is not null;--> statement-breakpoint
209
+ ALTER TABLE "chat_deliveries" ADD CONSTRAINT "chat_deliveries_trigger_class_check" CHECK ("chat_deliveries"."trigger_class" is null or "chat_deliveries"."trigger_class" in ('owner', 'other', 'grant'));--> statement-breakpoint
210
+ ALTER TABLE "chat_deliveries" ADD CONSTRAINT "chat_deliveries_principal_role_check" CHECK ("chat_deliveries"."principal_role" is null or "chat_deliveries"."principal_role" in ('owner', 'allowed', 'outside_allowlist', 'denylisted'));--> statement-breakpoint
211
+ ALTER TABLE "chat_deliveries" ADD CONSTRAINT "chat_deliveries_answer_state_check" CHECK ("chat_deliveries"."answer_state" is null or "chat_deliveries"."answer_state" in ('pending', 'answered', 'silenced', 'handed_off'));--> statement-breakpoint
212
+ ALTER TABLE "chat_endpoints" ADD CONSTRAINT "chat_endpoints_inflight_mode_check" CHECK ("chat_endpoints"."inflight_mode" in ('steer', 'queue'));--> statement-breakpoint
213
+ ALTER TABLE "chat_endpoints" ADD CONSTRAINT "chat_endpoints_policy_revision_check" CHECK ("chat_endpoints"."policy_revision" >= 0);--> statement-breakpoint
214
+ ALTER TABLE "chat_endpoints" ADD CONSTRAINT "chat_endpoints_provider_check" CHECK ("chat_endpoints"."provider" in ('slack', 'github', 'discord', 'microsoft-teams', 'telegram', 'agentmail', 'imessage-photon', 'openwa'));--> statement-breakpoint
215
+ ALTER TABLE "chat_external_principals" ADD CONSTRAINT "chat_external_principals_provider_check" CHECK ("chat_external_principals"."provider" in ('slack', 'github', 'discord', 'microsoft-teams', 'telegram', 'agentmail', 'imessage-photon', 'openwa'));
@@ -0,0 +1 @@
1
+ CREATE INDEX "chat_deliveries_pending_answer_idx" ON "chat_deliveries" USING btree ("endpoint_id","conversation_id","received_at") WHERE "chat_deliveries"."answer_state" = 'pending';
@@ -1996,6 +1996,20 @@
1996
1996
  "when": 1790925936339,
1997
1997
  "tag": "0286_cheerful_toro",
1998
1998
  "breakpoints": true
1999
+ },
2000
+ {
2001
+ "idx": 287,
2002
+ "version": "7",
2003
+ "when": 1791015680568,
2004
+ "tag": "0287_slimy_smasher",
2005
+ "breakpoints": true
2006
+ },
2007
+ {
2008
+ "idx": 288,
2009
+ "version": "7",
2010
+ "when": 1791038261567,
2011
+ "tag": "0288_exotic_daimon_hellstrom",
2012
+ "breakpoints": true
1999
2013
  }
2000
2014
  ]
2001
2015
  }
@@ -110,14 +110,14 @@ export declare const agentApiKeys: import("drizzle-orm/pg-core").PgTableWithColu
110
110
  dataType: "json";
111
111
  columnType: "PgJsonb";
112
112
  data: {
113
- kind: "standard";
114
- } | {
115
113
  kind: "task_bridge";
116
114
  projectId?: string | null | undefined;
117
115
  projectIds?: string[] | undefined;
118
116
  parentIssueId?: string | null | undefined;
119
117
  parentIssueIds?: string[] | undefined;
120
118
  allowedAssigneeAgentIds?: string[] | undefined;
119
+ } | {
120
+ kind: "standard";
121
121
  } | {
122
122
  kind: "skill_test";
123
123
  issueId: string;
@@ -134,14 +134,14 @@ export declare const agentApiKeys: import("drizzle-orm/pg-core").PgTableWithColu
134
134
  generated: undefined;
135
135
  }, {}, {
136
136
  $type: {
137
- kind: "standard";
138
- } | {
139
137
  kind: "task_bridge";
140
138
  projectId?: string | null | undefined;
141
139
  projectIds?: string[] | undefined;
142
140
  parentIssueId?: string | null | undefined;
143
141
  parentIssueIds?: string[] | undefined;
144
142
  allowedAssigneeAgentIds?: string[] | undefined;
143
+ } | {
144
+ kind: "standard";
145
145
  } | {
146
146
  kind: "skill_test";
147
147
  issueId: string;