@lobu/cli 6.0.1 → 6.1.1
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/README.md +20 -27
- package/dist/bundled-skills/lobu/SKILL.md +11 -11
- package/dist/commands/_lib/apply/apply-cmd.d.ts +2 -0
- package/dist/commands/_lib/apply/apply-cmd.d.ts.map +1 -1
- package/dist/commands/_lib/apply/apply-cmd.js +26 -0
- package/dist/commands/_lib/apply/apply-cmd.js.map +1 -1
- package/dist/commands/_lib/apply/client.d.ts +1 -1
- package/dist/commands/_lib/apply/client.d.ts.map +1 -1
- package/dist/commands/_lib/apply/desired-state.js +4 -4
- package/dist/commands/_lib/apply/desired-state.js.map +1 -1
- package/dist/commands/agent.d.ts +7 -0
- package/dist/commands/agent.d.ts.map +1 -1
- package/dist/commands/agent.js +65 -1
- package/dist/commands/agent.js.map +1 -1
- package/dist/commands/chat.d.ts +12 -9
- package/dist/commands/chat.d.ts.map +1 -1
- package/dist/commands/chat.js +117 -56
- package/dist/commands/chat.js.map +1 -1
- package/dist/commands/dev.d.ts +15 -7
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +79 -44
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/doctor.d.ts +1 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +136 -0
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/eval.d.ts +8 -0
- package/dist/commands/eval.d.ts.map +1 -1
- package/dist/commands/eval.js +56 -1
- package/dist/commands/eval.js.map +1 -1
- package/dist/commands/init.d.ts +20 -5
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +332 -183
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/link.d.ts +11 -0
- package/dist/commands/link.d.ts.map +1 -0
- package/dist/commands/link.js +28 -0
- package/dist/commands/link.js.map +1 -0
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +14 -2
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/memory/_lib/browser-auth-cmd.d.ts.map +1 -1
- package/dist/commands/memory/_lib/browser-auth-cmd.js +3 -3
- package/dist/commands/memory/_lib/browser-auth-cmd.js.map +1 -1
- package/dist/commands/memory/_lib/mcp.d.ts +2 -2
- package/dist/commands/memory/_lib/mcp.d.ts.map +1 -1
- package/dist/commands/memory/_lib/mcp.js +24 -12
- package/dist/commands/memory/_lib/mcp.js.map +1 -1
- package/dist/commands/memory/_lib/openclaw-auth.d.ts +1 -0
- package/dist/commands/memory/_lib/openclaw-auth.d.ts.map +1 -1
- package/dist/commands/memory/_lib/openclaw-auth.js +14 -3
- package/dist/commands/memory/_lib/openclaw-auth.js.map +1 -1
- package/dist/commands/memory/_lib/openclaw-cmd.js +1 -1
- package/dist/commands/memory/_lib/openclaw-cmd.js.map +1 -1
- package/dist/commands/memory/_lib/schema.d.ts +1 -1
- package/dist/commands/memory/_lib/schema.js +1 -1
- package/dist/commands/memory/_lib/seed-cmd.d.ts.map +1 -1
- package/dist/commands/memory/_lib/seed-cmd.js +5 -6
- package/dist/commands/memory/_lib/seed-cmd.js.map +1 -1
- package/dist/commands/memory/run.d.ts.map +1 -1
- package/dist/commands/memory/run.js +2 -2
- package/dist/commands/memory/run.js.map +1 -1
- package/dist/commands/platforms/platform-prompts.d.ts +0 -1
- package/dist/commands/platforms/platform-prompts.d.ts.map +1 -1
- package/dist/commands/platforms/platform-prompts.js +54 -8
- package/dist/commands/platforms/platform-prompts.js.map +1 -1
- package/dist/commands/telemetry.d.ts +10 -0
- package/dist/commands/telemetry.d.ts.map +1 -0
- package/dist/commands/telemetry.js +68 -0
- package/dist/commands/telemetry.js.map +1 -0
- package/dist/commands/whoami.d.ts.map +1 -1
- package/dist/commands/whoami.js +1 -1
- package/dist/commands/whoami.js.map +1 -1
- package/dist/connectors/README.md +534 -0
- package/dist/connectors/__tests__/browser-scraper-utils.test.ts +186 -0
- package/dist/connectors/browser-scraper-utils.ts +214 -0
- package/dist/connectors/capterra.ts +273 -0
- package/dist/connectors/g2.ts +286 -0
- package/dist/connectors/github.ts +1553 -0
- package/dist/connectors/glassdoor.ts +291 -0
- package/dist/connectors/gmaps.ts +197 -0
- package/dist/connectors/google_calendar.ts +631 -0
- package/dist/connectors/google_gmail.ts +751 -0
- package/dist/connectors/google_photos.ts +776 -0
- package/dist/connectors/google_play.ts +342 -0
- package/dist/connectors/hackernews.ts +471 -0
- package/dist/connectors/index.ts +23 -0
- package/dist/connectors/ios_appstore.ts +226 -0
- package/dist/connectors/linkedin.ts +471 -0
- package/dist/connectors/microsoft_outlook.ts +410 -0
- package/dist/connectors/producthunt.ts +471 -0
- package/dist/connectors/reddit.ts +600 -0
- package/dist/connectors/rss.ts +448 -0
- package/dist/connectors/spotify.ts +590 -0
- package/dist/connectors/trustpilot.ts +199 -0
- package/dist/connectors/website.ts +629 -0
- package/dist/connectors/whatsapp.ts +1073 -0
- package/dist/connectors/x.ts +526 -0
- package/dist/connectors/youtube.ts +666 -0
- package/dist/db/migrations/00000000000000_baseline.sql +4867 -0
- package/dist/db/migrations/20260405193000_add_mcp_sessions.sql +33 -0
- package/dist/db/migrations/20260408120000_remove_system_connectors.sql +48 -0
- package/dist/db/migrations/20260408120001_optional_compiled_code.sql +6 -0
- package/dist/db/migrations/20260409110000_add_active_watcher_run_index.sql +9 -0
- package/dist/db/migrations/20260409130000_connector_default_config.sql +5 -0
- package/dist/db/migrations/20260410120000_add_agent_secrets.sql +25 -0
- package/dist/db/migrations/20260413170000_add_watcher_group_id.sql +67 -0
- package/dist/db/migrations/20260416120000_add_entity_wa_jid_index.sql +14 -0
- package/dist/db/migrations/20260417100000_add_entity_identities.sql +77 -0
- package/dist/db/migrations/20260418100000_add_auth_runs.sql +83 -0
- package/dist/db/migrations/20260418110000_add_runs_created_by_user.sql +18 -0
- package/dist/db/migrations/20260419120000_add_event_identity_indexes.sql +56 -0
- package/dist/db/migrations/20260420120000_extend_reserved_org_slugs.sql +56 -0
- package/dist/db/migrations/20260424030000_add_watcher_run_correlation.sql +52 -0
- package/dist/db/migrations/20260424130000_relax_events_client_id_fk.sql +47 -0
- package/dist/db/migrations/20260425100000_normalize_watcher_feedback.sql +91 -0
- package/dist/db/migrations/20260425120000_add_run_diagnostics.sql +20 -0
- package/dist/db/migrations/20260425130000_add_repair_agent_plumbing.sql +46 -0
- package/dist/db/migrations/20260426120000_entities_entity_type_fk.sql +101 -0
- package/dist/db/migrations/20260426130000_db_integrity_cleanup.sql +104 -0
- package/dist/db/migrations/20260426130001_db_integrity_cleanup_concurrent.sql +187 -0
- package/dist/db/migrations/20260427133000_events_created_by_nullable.sql +74 -0
- package/dist/db/migrations/20260427140000_identity_engine_indexes.sql +140 -0
- package/dist/db/migrations/20260427150000_drop_events_source_id.sql +177 -0
- package/dist/db/migrations/20260427160000_drop_dead_schema.sql +76 -0
- package/dist/db/migrations/20260427170000_market_founder_to_member.sql +364 -0
- package/dist/db/migrations/20260428040000_cascade_events_watchers_org_fk.sql +66 -0
- package/dist/db/migrations/20260428050000_add_runs_approved_input.sql +9 -0
- package/dist/db/migrations/20260429010000_auth_profile_tenant_scoped_fk.sql +79 -0
- package/dist/db/migrations/20260429060000_extend_runs_for_lobu_queue.sql +108 -0
- package/dist/db/migrations/20260429120000_agent_changed_notify.sql +97 -0
- package/dist/db/migrations/20260429120100_user_auth_profiles_and_model_prefs.sql +36 -0
- package/dist/db/migrations/20260429120200_fix_notify_old_keys.sql +130 -0
- package/dist/db/migrations/20260429130000_oauth_states_cli_sessions_rate_limits.sql +83 -0
- package/dist/db/migrations/20260429140000_phase8_grants_chat_connections_mcp_sessions.sql +84 -0
- package/dist/db/migrations/20260429140100_runs_priority_expires_at_retry_delay.sql +44 -0
- package/dist/db/migrations/20260429180000_drop_invalidatable_cache_triggers.sql +25 -0
- package/dist/db/migrations/20260430005614_agents_apply_fields.sql +21 -0
- package/dist/db/migrations/20260430022231_fix_connection_config_encryption.sql +69 -0
- package/dist/db/migrations/20260430151215_add_task_run_type.sql +77 -0
- package/dist/db/migrations/20260501000000_drop_cli_sessions.sql +27 -0
- package/dist/db/migrations/20260501133000_lobu_memory_mcp_id.sql +117 -0
- package/dist/db/migrations/20260502000000_drop_chat_connections.sql +60 -0
- package/dist/db/migrations/20260503000000_agent_secrets_org_scope.sql +56 -0
- package/dist/db/migrations/20260504000000_flatten_agents_drop_sandbox_model.sql +48 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +147 -23
- package/dist/index.js.map +1 -1
- package/dist/internal/api-client.d.ts +4 -8
- package/dist/internal/api-client.d.ts.map +1 -1
- package/dist/internal/api-client.js +1 -1
- package/dist/internal/api-client.js.map +1 -1
- package/dist/internal/context.js +2 -2
- package/dist/internal/context.js.map +1 -1
- package/dist/internal/credentials.d.ts.map +1 -1
- package/dist/internal/credentials.js +6 -1
- package/dist/internal/credentials.js.map +1 -1
- package/dist/internal/index.d.ts +2 -3
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +2 -2
- package/dist/internal/index.js.map +1 -1
- package/dist/internal/oauth.d.ts +6 -5
- package/dist/internal/oauth.d.ts.map +1 -1
- package/dist/internal/oauth.js +2 -2
- package/dist/internal/project-link.d.ts +10 -0
- package/dist/internal/project-link.d.ts.map +1 -0
- package/dist/internal/project-link.js +48 -0
- package/dist/internal/project-link.js.map +1 -0
- package/dist/providers.json +2 -2
- package/dist/server.bundle.mjs +3090 -4321
- package/dist/start-local.bundle.mjs +71481 -0
- package/dist/templates/README.md.tmpl +10 -11
- package/package.json +14 -12
- package/dist/__tests__/chat.integration.test.d.ts +0 -2
- package/dist/__tests__/chat.integration.test.d.ts.map +0 -1
- package/dist/__tests__/chat.integration.test.js +0 -337
- package/dist/__tests__/chat.integration.test.js.map +0 -1
- package/dist/__tests__/dev.test.d.ts +0 -2
- package/dist/__tests__/dev.test.d.ts.map +0 -1
- package/dist/__tests__/dev.test.js +0 -25
- package/dist/__tests__/dev.test.js.map +0 -1
- package/dist/__tests__/init-memory.test.d.ts +0 -2
- package/dist/__tests__/init-memory.test.d.ts.map +0 -1
- package/dist/__tests__/init-memory.test.js +0 -45
- package/dist/__tests__/init-memory.test.js.map +0 -1
- package/dist/__tests__/token.test.d.ts +0 -2
- package/dist/__tests__/token.test.d.ts.map +0 -1
- package/dist/__tests__/token.test.js +0 -52
- package/dist/__tests__/token.test.js.map +0 -1
- package/dist/commands/_lib/apply/__tests__/client.test.d.ts +0 -2
- package/dist/commands/_lib/apply/__tests__/client.test.d.ts.map +0 -1
- package/dist/commands/_lib/apply/__tests__/client.test.js +0 -23
- package/dist/commands/_lib/apply/__tests__/client.test.js.map +0 -1
- package/dist/commands/_lib/apply/__tests__/desired-state.test.d.ts +0 -2
- package/dist/commands/_lib/apply/__tests__/desired-state.test.d.ts.map +0 -1
- package/dist/commands/_lib/apply/__tests__/desired-state.test.js +0 -140
- package/dist/commands/_lib/apply/__tests__/desired-state.test.js.map +0 -1
- package/dist/commands/_lib/apply/__tests__/diff.test.d.ts +0 -2
- package/dist/commands/_lib/apply/__tests__/diff.test.d.ts.map +0 -1
- package/dist/commands/_lib/apply/__tests__/diff.test.js +0 -378
- package/dist/commands/_lib/apply/__tests__/diff.test.js.map +0 -1
- package/dist/commands/apply.d.ts +0 -3
- package/dist/commands/apply.d.ts.map +0 -1
- package/dist/commands/apply.js +0 -5
- package/dist/commands/apply.js.map +0 -1
- package/dist/commands/memory/_lib/openclaw-auth.test.d.ts +0 -2
- package/dist/commands/memory/_lib/openclaw-auth.test.d.ts.map +0 -1
- package/dist/commands/memory/_lib/openclaw-auth.test.js +0 -9
- package/dist/commands/memory/_lib/openclaw-auth.test.js.map +0 -1
- package/dist/internal/__tests__/api-client.test.d.ts +0 -2
- package/dist/internal/__tests__/api-client.test.d.ts.map +0 -1
- package/dist/internal/__tests__/api-client.test.js +0 -95
- package/dist/internal/__tests__/api-client.test.js.map +0 -1
- package/dist/internal/__tests__/context.test.d.ts +0 -2
- package/dist/internal/__tests__/context.test.d.ts.map +0 -1
- package/dist/internal/__tests__/context.test.js +0 -77
- package/dist/internal/__tests__/context.test.js.map +0 -1
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
-- migrate:up
|
|
2
|
+
|
|
3
|
+
CREATE TABLE public.mcp_sessions (
|
|
4
|
+
session_id text PRIMARY KEY,
|
|
5
|
+
user_id text,
|
|
6
|
+
client_id text,
|
|
7
|
+
organization_id text,
|
|
8
|
+
member_role text,
|
|
9
|
+
requested_agent_id text,
|
|
10
|
+
is_authenticated boolean DEFAULT false NOT NULL,
|
|
11
|
+
scoped_to_org boolean DEFAULT false NOT NULL,
|
|
12
|
+
last_accessed_at timestamp with time zone DEFAULT now() NOT NULL,
|
|
13
|
+
expires_at timestamp with time zone NOT NULL
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
CREATE INDEX mcp_sessions_client_id_idx ON public.mcp_sessions USING btree (client_id);
|
|
17
|
+
CREATE INDEX mcp_sessions_expires_at_idx ON public.mcp_sessions USING btree (expires_at);
|
|
18
|
+
CREATE INDEX mcp_sessions_user_id_idx ON public.mcp_sessions USING btree (user_id);
|
|
19
|
+
|
|
20
|
+
ALTER TABLE ONLY public.mcp_sessions
|
|
21
|
+
ADD CONSTRAINT mcp_sessions_client_id_fkey FOREIGN KEY (client_id) REFERENCES public.oauth_clients(id) ON DELETE CASCADE;
|
|
22
|
+
|
|
23
|
+
ALTER TABLE ONLY public.mcp_sessions
|
|
24
|
+
ADD CONSTRAINT mcp_sessions_organization_id_fkey FOREIGN KEY (organization_id) REFERENCES public.organization(id) ON DELETE CASCADE;
|
|
25
|
+
|
|
26
|
+
ALTER TABLE ONLY public.mcp_sessions
|
|
27
|
+
ADD CONSTRAINT mcp_sessions_user_id_fkey FOREIGN KEY (user_id) REFERENCES public."user"(id) ON DELETE CASCADE;
|
|
28
|
+
|
|
29
|
+
COMMENT ON TABLE public.mcp_sessions IS 'Persisted MCP streamable HTTP sessions for restart and cross-replica recovery';
|
|
30
|
+
|
|
31
|
+
-- migrate:down
|
|
32
|
+
|
|
33
|
+
DROP TABLE IF EXISTS public.mcp_sessions;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
-- migrate:up
|
|
2
|
+
|
|
3
|
+
-- Migrate system connector definitions to org-scoped.
|
|
4
|
+
-- For every org, copy each active system connector definition that
|
|
5
|
+
-- the org doesn't already have (regardless of whether connections exist).
|
|
6
|
+
|
|
7
|
+
INSERT INTO connector_definitions (
|
|
8
|
+
organization_id, key, name, description, version,
|
|
9
|
+
auth_schema, feeds_schema, actions_schema, options_schema,
|
|
10
|
+
mcp_config, openapi_config, favicon_domain, status, login_enabled
|
|
11
|
+
)
|
|
12
|
+
SELECT
|
|
13
|
+
o.id,
|
|
14
|
+
cd.key,
|
|
15
|
+
cd.name,
|
|
16
|
+
cd.description,
|
|
17
|
+
cd.version,
|
|
18
|
+
cd.auth_schema,
|
|
19
|
+
cd.feeds_schema,
|
|
20
|
+
cd.actions_schema,
|
|
21
|
+
cd.options_schema,
|
|
22
|
+
cd.mcp_config,
|
|
23
|
+
cd.openapi_config,
|
|
24
|
+
cd.favicon_domain,
|
|
25
|
+
cd.status,
|
|
26
|
+
cd.login_enabled
|
|
27
|
+
FROM connector_definitions cd
|
|
28
|
+
CROSS JOIN "organization" o
|
|
29
|
+
WHERE cd.organization_id IS NULL
|
|
30
|
+
AND cd.status = 'active'
|
|
31
|
+
AND NOT EXISTS (
|
|
32
|
+
SELECT 1
|
|
33
|
+
FROM connector_definitions existing
|
|
34
|
+
WHERE existing.organization_id = o.id
|
|
35
|
+
AND existing.key = cd.key
|
|
36
|
+
AND existing.status = 'active'
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
-- Archive all system-level connector definitions
|
|
40
|
+
UPDATE connector_definitions
|
|
41
|
+
SET status = 'archived', updated_at = NOW()
|
|
42
|
+
WHERE organization_id IS NULL
|
|
43
|
+
AND status = 'active';
|
|
44
|
+
|
|
45
|
+
-- Drop orphaned index that only covered system-level (org IS NULL) definitions
|
|
46
|
+
DROP INDEX IF EXISTS idx_connector_defs_system_key;
|
|
47
|
+
|
|
48
|
+
-- migrate:down
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
-- migrate:up
|
|
2
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_runs_active_watcher_per_watcher
|
|
3
|
+
ON runs (watcher_id)
|
|
4
|
+
WHERE run_type = 'watcher'
|
|
5
|
+
AND watcher_id IS NOT NULL
|
|
6
|
+
AND status IN ('pending', 'claimed', 'running');
|
|
7
|
+
|
|
8
|
+
-- migrate:down
|
|
9
|
+
DROP INDEX IF EXISTS idx_runs_active_watcher_per_watcher;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
-- migrate:up
|
|
2
|
+
|
|
3
|
+
CREATE TABLE public.agent_secrets (
|
|
4
|
+
name text PRIMARY KEY,
|
|
5
|
+
ciphertext text NOT NULL,
|
|
6
|
+
expires_at timestamp with time zone,
|
|
7
|
+
created_at timestamp with time zone DEFAULT now() NOT NULL,
|
|
8
|
+
updated_at timestamp with time zone DEFAULT now() NOT NULL
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
-- text_pattern_ops index enables efficient prefix scans used by list(prefix)
|
|
12
|
+
-- to support cascade deletes (deleteSecretsByPrefix in @lobu/gateway).
|
|
13
|
+
CREATE INDEX agent_secrets_name_prefix_idx
|
|
14
|
+
ON public.agent_secrets USING btree (name text_pattern_ops);
|
|
15
|
+
|
|
16
|
+
CREATE INDEX agent_secrets_expires_at_idx
|
|
17
|
+
ON public.agent_secrets USING btree (expires_at)
|
|
18
|
+
WHERE expires_at IS NOT NULL;
|
|
19
|
+
|
|
20
|
+
COMMENT ON TABLE public.agent_secrets IS
|
|
21
|
+
'Encrypted secret values referenced via secret:// refs. Backs the PostgresSecretStore implementation of @lobu/gateway WritableSecretStore.';
|
|
22
|
+
|
|
23
|
+
-- migrate:down
|
|
24
|
+
|
|
25
|
+
DROP TABLE IF EXISTS public.agent_secrets;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
-- migrate:up
|
|
2
|
+
|
|
3
|
+
ALTER TABLE public.watchers
|
|
4
|
+
ADD COLUMN IF NOT EXISTS source_watcher_id integer,
|
|
5
|
+
ADD COLUMN IF NOT EXISTS watcher_group_id integer;
|
|
6
|
+
|
|
7
|
+
-- Backfill source watcher links from cloned watcher versions.
|
|
8
|
+
WITH derived_source AS (
|
|
9
|
+
SELECT DISTINCT ON (w.id)
|
|
10
|
+
w.id AS watcher_id,
|
|
11
|
+
source_versions.watcher_id AS source_watcher_id
|
|
12
|
+
FROM public.watchers w
|
|
13
|
+
JOIN public.watcher_versions wv ON wv.watcher_id = w.id
|
|
14
|
+
JOIN public.watcher_versions source_versions
|
|
15
|
+
ON source_versions.id = substring(wv.change_notes FROM 'Created from version ([0-9]+)')::integer
|
|
16
|
+
WHERE wv.change_notes ~ 'Created from version [0-9]+'
|
|
17
|
+
ORDER BY w.id, wv.version ASC, wv.id ASC
|
|
18
|
+
)
|
|
19
|
+
UPDATE public.watchers w
|
|
20
|
+
SET source_watcher_id = ds.source_watcher_id
|
|
21
|
+
FROM derived_source ds
|
|
22
|
+
WHERE w.id = ds.watcher_id
|
|
23
|
+
AND w.source_watcher_id IS NULL;
|
|
24
|
+
|
|
25
|
+
-- Build stable watcher group ids by walking source watcher ancestry to the root.
|
|
26
|
+
WITH RECURSIVE roots AS (
|
|
27
|
+
SELECT w.id AS watcher_id, w.source_watcher_id, w.id AS root_id
|
|
28
|
+
FROM public.watchers w
|
|
29
|
+
WHERE w.source_watcher_id IS NULL
|
|
30
|
+
|
|
31
|
+
UNION ALL
|
|
32
|
+
|
|
33
|
+
SELECT child.id AS watcher_id, child.source_watcher_id, roots.root_id
|
|
34
|
+
FROM public.watchers child
|
|
35
|
+
JOIN roots ON child.source_watcher_id = roots.watcher_id
|
|
36
|
+
)
|
|
37
|
+
UPDATE public.watchers w
|
|
38
|
+
SET watcher_group_id = roots.root_id
|
|
39
|
+
FROM roots
|
|
40
|
+
WHERE w.id = roots.watcher_id;
|
|
41
|
+
|
|
42
|
+
-- Fallback for any rows that did not match the recursive backfill.
|
|
43
|
+
UPDATE public.watchers
|
|
44
|
+
SET watcher_group_id = id
|
|
45
|
+
WHERE watcher_group_id IS NULL;
|
|
46
|
+
|
|
47
|
+
-- `watchers.current_version_id` has a DEFERRABLE FK. The backfill updates above queue
|
|
48
|
+
-- deferred trigger events, and PostgreSQL refuses ALTER TABLE while those are pending.
|
|
49
|
+
SET CONSTRAINTS ALL IMMEDIATE;
|
|
50
|
+
|
|
51
|
+
ALTER TABLE public.watchers
|
|
52
|
+
ALTER COLUMN watcher_group_id SET NOT NULL;
|
|
53
|
+
|
|
54
|
+
CREATE INDEX IF NOT EXISTS idx_watchers_watcher_group_id
|
|
55
|
+
ON public.watchers USING btree (watcher_group_id);
|
|
56
|
+
|
|
57
|
+
CREATE INDEX IF NOT EXISTS idx_watchers_org_group
|
|
58
|
+
ON public.watchers USING btree (organization_id, watcher_group_id);
|
|
59
|
+
|
|
60
|
+
-- migrate:down
|
|
61
|
+
|
|
62
|
+
DROP INDEX IF EXISTS idx_watchers_org_group;
|
|
63
|
+
DROP INDEX IF EXISTS idx_watchers_watcher_group_id;
|
|
64
|
+
|
|
65
|
+
ALTER TABLE public.watchers
|
|
66
|
+
DROP COLUMN IF EXISTS watcher_group_id,
|
|
67
|
+
DROP COLUMN IF EXISTS source_watcher_id;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
-- migrate:up
|
|
2
|
+
|
|
3
|
+
-- Speeds up the event↔entity join declared by the WhatsApp connector's
|
|
4
|
+
-- early entityLinks rule: events JOIN entities ON
|
|
5
|
+
-- entities.metadata->>'wa_jid' = events.metadata->>'chat_jid'.
|
|
6
|
+
-- Superseded by the entity_identities table (2026-04-17 migration) which
|
|
7
|
+
-- drops this index; this file is kept so dbmate's history is preserved.
|
|
8
|
+
CREATE INDEX IF NOT EXISTS idx_entities_wa_jid
|
|
9
|
+
ON public.entities (entity_type, (metadata->>'wa_jid'))
|
|
10
|
+
WHERE metadata ? 'wa_jid' AND deleted_at IS NULL;
|
|
11
|
+
|
|
12
|
+
-- migrate:down
|
|
13
|
+
|
|
14
|
+
DROP INDEX IF EXISTS public.idx_entities_wa_jid;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
-- migrate:up
|
|
2
|
+
|
|
3
|
+
-- Normalized identifier store. One row per (organization_id, namespace, identifier).
|
|
4
|
+
-- Replaces the earlier scheme of storing identifiers inside entities.metadata JSONB
|
|
5
|
+
-- arrays. The UNIQUE constraint is the foundation of the whole design:
|
|
6
|
+
-- * creation races collapse on the UNIQUE (one batch wins, the other links)
|
|
7
|
+
-- * cross-entity contamination is constraint-blocked
|
|
8
|
+
-- * accrete is just INSERT ... ON CONFLICT DO NOTHING
|
|
9
|
+
-- * lookup is a plain BTREE seek (no GIN-on-jsonb)
|
|
10
|
+
CREATE TABLE public.entity_identities (
|
|
11
|
+
id bigserial PRIMARY KEY,
|
|
12
|
+
organization_id text NOT NULL REFERENCES public.organization(id) ON DELETE CASCADE,
|
|
13
|
+
entity_id bigint NOT NULL REFERENCES public.entities(id) ON DELETE CASCADE,
|
|
14
|
+
namespace text NOT NULL,
|
|
15
|
+
identifier text NOT NULL,
|
|
16
|
+
source_connector text,
|
|
17
|
+
created_at timestamp with time zone DEFAULT now() NOT NULL,
|
|
18
|
+
updated_at timestamp with time zone DEFAULT now() NOT NULL,
|
|
19
|
+
deleted_at timestamp with time zone
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
-- Relaxed uniqueness: only live rows are constrained, so soft-delete + re-claim
|
|
23
|
+
-- is a supported repair path (mis-attribution recovery).
|
|
24
|
+
CREATE UNIQUE INDEX idx_entity_identities_live_unique
|
|
25
|
+
ON public.entity_identities (organization_id, namespace, identifier)
|
|
26
|
+
WHERE deleted_at IS NULL;
|
|
27
|
+
|
|
28
|
+
-- Primary ingestion lookup path: "does anyone in this org own this identifier?"
|
|
29
|
+
CREATE INDEX idx_entity_identities_lookup
|
|
30
|
+
ON public.entity_identities (organization_id, namespace, identifier)
|
|
31
|
+
WHERE deleted_at IS NULL;
|
|
32
|
+
|
|
33
|
+
-- Reverse lookup: "what identifiers does this entity have?"
|
|
34
|
+
CREATE INDEX idx_entity_identities_by_entity
|
|
35
|
+
ON public.entity_identities (entity_id)
|
|
36
|
+
WHERE deleted_at IS NULL;
|
|
37
|
+
|
|
38
|
+
COMMENT ON TABLE public.entity_identities IS
|
|
39
|
+
'Normalized identifier claims per entity. See docs/identity-linking.md for the full pattern.';
|
|
40
|
+
COMMENT ON COLUMN public.entity_identities.namespace IS
|
|
41
|
+
'Identifier kind. Standard values: phone, email, wa_jid, slack_user_id, github_login, auth_user_id, google_contact_id. Custom namespaces allowed but connectors sharing a namespace must agree on its format.';
|
|
42
|
+
COMMENT ON COLUMN public.entity_identities.identifier IS
|
|
43
|
+
'Normalized identifier value (E.164 digits for phone, lowercase for email, etc.). Normalizers in @lobu/connector-sdk own the canonical form.';
|
|
44
|
+
COMMENT ON COLUMN public.entity_identities.source_connector IS
|
|
45
|
+
'Who claimed this identifier: "connector:whatsapp", "manual", or null when seeded by migration.';
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
-- Per-install override surface. A JSONB keyed by entityType; shallow-merged
|
|
49
|
+
-- onto the connector's declared entityLinks at rule-resolve time. Lets an
|
|
50
|
+
-- org retarget, disable rules, flip autoCreate, or mask specific identities
|
|
51
|
+
-- without forking the connector. Null column = use connector defaults verbatim.
|
|
52
|
+
ALTER TABLE public.connector_definitions
|
|
53
|
+
ADD COLUMN IF NOT EXISTS entity_link_overrides jsonb;
|
|
54
|
+
|
|
55
|
+
COMMENT ON COLUMN public.connector_definitions.entity_link_overrides IS
|
|
56
|
+
'Per-install override of connector entityLinks rules. See resolveEntityLinkRules() for merge semantics.';
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
-- The old scalar-JSONB index was built for a shape (entities.metadata->>wa_jid)
|
|
60
|
+
-- we no longer use — identifiers now live in entity_identities. Drop to avoid
|
|
61
|
+
-- carrying an unused index and a misleading comment on future reads.
|
|
62
|
+
DROP INDEX IF EXISTS public.idx_entities_wa_jid;
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
-- migrate:down
|
|
66
|
+
|
|
67
|
+
DROP INDEX IF EXISTS public.idx_entity_identities_by_entity;
|
|
68
|
+
DROP INDEX IF EXISTS public.idx_entity_identities_lookup;
|
|
69
|
+
DROP INDEX IF EXISTS public.idx_entity_identities_live_unique;
|
|
70
|
+
DROP TABLE IF EXISTS public.entity_identities;
|
|
71
|
+
|
|
72
|
+
ALTER TABLE public.connector_definitions
|
|
73
|
+
DROP COLUMN IF EXISTS entity_link_overrides;
|
|
74
|
+
|
|
75
|
+
CREATE INDEX IF NOT EXISTS idx_entities_wa_jid
|
|
76
|
+
ON public.entities (entity_type, (metadata->>'wa_jid'))
|
|
77
|
+
WHERE metadata ? 'wa_jid' AND deleted_at IS NULL;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
-- migrate:up
|
|
2
|
+
|
|
3
|
+
-- Adds the 'auth' run lifecycle: workers run interactive connector.authenticate()
|
|
4
|
+
-- flows (WhatsApp QR, OAuth redirect, credential prompt) and stream artifacts
|
|
5
|
+
-- back to the UI via runs.checkpoint. The UI signals back (OAuth callback,
|
|
6
|
+
-- form submit, cancel) via runs.auth_signal.
|
|
7
|
+
|
|
8
|
+
ALTER TABLE public.runs DROP CONSTRAINT IF EXISTS runs_run_type_check;
|
|
9
|
+
ALTER TABLE public.runs ADD CONSTRAINT runs_run_type_check CHECK (
|
|
10
|
+
run_type = ANY (ARRAY[
|
|
11
|
+
'sync'::text,
|
|
12
|
+
'action'::text,
|
|
13
|
+
'code'::text,
|
|
14
|
+
'insight'::text,
|
|
15
|
+
'watcher'::text,
|
|
16
|
+
'embed_backfill'::text,
|
|
17
|
+
'auth'::text
|
|
18
|
+
])
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
-- Target auth profile for 'auth' runs (null for other run types).
|
|
22
|
+
ALTER TABLE public.runs ADD COLUMN IF NOT EXISTS auth_profile_id bigint
|
|
23
|
+
REFERENCES public.auth_profiles(id) ON DELETE CASCADE;
|
|
24
|
+
|
|
25
|
+
-- Reverse channel: UI → connector. The connector pauses on ctx.awaitSignal(name)
|
|
26
|
+
-- and polls this column; the API writes here when the UI posts a signal.
|
|
27
|
+
ALTER TABLE public.runs ADD COLUMN IF NOT EXISTS auth_signal jsonb;
|
|
28
|
+
|
|
29
|
+
-- One active auth run per auth profile at a time.
|
|
30
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_runs_active_auth_per_profile
|
|
31
|
+
ON public.runs (auth_profile_id)
|
|
32
|
+
WHERE run_type = 'auth'
|
|
33
|
+
AND auth_profile_id IS NOT NULL
|
|
34
|
+
AND status = ANY (ARRAY['pending'::text, 'claimed'::text, 'running'::text]);
|
|
35
|
+
|
|
36
|
+
-- 'interactive' profile kind: credentials produced by a connector.authenticate()
|
|
37
|
+
-- run. Examples: WhatsApp Baileys session, connector-managed OAuth.
|
|
38
|
+
ALTER TABLE public.auth_profiles DROP CONSTRAINT IF EXISTS auth_profiles_profile_kind_check;
|
|
39
|
+
ALTER TABLE public.auth_profiles ADD CONSTRAINT auth_profiles_profile_kind_check CHECK (
|
|
40
|
+
profile_kind = ANY (ARRAY[
|
|
41
|
+
'env'::text,
|
|
42
|
+
'oauth_app'::text,
|
|
43
|
+
'oauth_account'::text,
|
|
44
|
+
'browser_session'::text,
|
|
45
|
+
'interactive'::text
|
|
46
|
+
])
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
-- Structured display metadata produced by connector.authenticate() — account_id,
|
|
50
|
+
-- display_name, paired_at, expires_at, etc. Surfaced in UI next to the connection.
|
|
51
|
+
ALTER TABLE public.auth_profiles ADD COLUMN IF NOT EXISTS metadata jsonb DEFAULT '{}'::jsonb NOT NULL;
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
-- migrate:down
|
|
55
|
+
|
|
56
|
+
ALTER TABLE public.auth_profiles DROP COLUMN IF EXISTS metadata;
|
|
57
|
+
|
|
58
|
+
ALTER TABLE public.auth_profiles DROP CONSTRAINT IF EXISTS auth_profiles_profile_kind_check;
|
|
59
|
+
ALTER TABLE public.auth_profiles ADD CONSTRAINT auth_profiles_profile_kind_check CHECK (
|
|
60
|
+
profile_kind = ANY (ARRAY[
|
|
61
|
+
'env'::text,
|
|
62
|
+
'oauth_app'::text,
|
|
63
|
+
'oauth_account'::text,
|
|
64
|
+
'browser_session'::text
|
|
65
|
+
])
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
DROP INDEX IF EXISTS public.idx_runs_active_auth_per_profile;
|
|
69
|
+
|
|
70
|
+
ALTER TABLE public.runs DROP COLUMN IF EXISTS auth_signal;
|
|
71
|
+
ALTER TABLE public.runs DROP COLUMN IF EXISTS auth_profile_id;
|
|
72
|
+
|
|
73
|
+
ALTER TABLE public.runs DROP CONSTRAINT IF EXISTS runs_run_type_check;
|
|
74
|
+
ALTER TABLE public.runs ADD CONSTRAINT runs_run_type_check CHECK (
|
|
75
|
+
run_type = ANY (ARRAY[
|
|
76
|
+
'sync'::text,
|
|
77
|
+
'action'::text,
|
|
78
|
+
'code'::text,
|
|
79
|
+
'insight'::text,
|
|
80
|
+
'watcher'::text,
|
|
81
|
+
'embed_backfill'::text
|
|
82
|
+
])
|
|
83
|
+
);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
-- migrate:up
|
|
2
|
+
|
|
3
|
+
-- Track which user initiated an interactive auth run so that only that user
|
|
4
|
+
-- can view the QR / credential artifact. Sensitive artifacts (WhatsApp QR,
|
|
5
|
+
-- OTP codes, OAuth consent URLs) must never be viewable by other org members.
|
|
6
|
+
|
|
7
|
+
ALTER TABLE public.runs ADD COLUMN IF NOT EXISTS created_by_user_id text
|
|
8
|
+
REFERENCES public."user"(id) ON DELETE SET NULL;
|
|
9
|
+
|
|
10
|
+
CREATE INDEX IF NOT EXISTS idx_runs_created_by_user
|
|
11
|
+
ON public.runs (created_by_user_id)
|
|
12
|
+
WHERE created_by_user_id IS NOT NULL;
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
-- migrate:down
|
|
16
|
+
|
|
17
|
+
DROP INDEX IF EXISTS public.idx_runs_created_by_user;
|
|
18
|
+
ALTER TABLE public.runs DROP COLUMN IF EXISTS created_by_user_id;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
-- migrate:up
|
|
2
|
+
|
|
3
|
+
-- Read-time JOIN support for the entity_identities graph.
|
|
4
|
+
--
|
|
5
|
+
-- applyEntityLinks (src/utils/entity-link-upsert.ts) stamps normalized
|
|
6
|
+
-- identifiers into events.metadata under the namespace key (metadata.email,
|
|
7
|
+
-- metadata.wa_jid, metadata.phone, …). Entity-scoped content queries then
|
|
8
|
+
-- JOIN:
|
|
9
|
+
--
|
|
10
|
+
-- events f
|
|
11
|
+
-- EXISTS (SELECT 1 FROM entity_identities ei
|
|
12
|
+
-- WHERE ei.entity_id = $X
|
|
13
|
+
-- AND ei.deleted_at IS NULL
|
|
14
|
+
-- AND f.metadata ? ei.namespace
|
|
15
|
+
-- AND f.metadata->>ei.namespace = ei.identifier)
|
|
16
|
+
--
|
|
17
|
+
-- Without these indexes, the plan degenerates into a seq scan of events for
|
|
18
|
+
-- every entity-scoped content listing. One partial BTREE per namespace in use
|
|
19
|
+
-- keeps the JOIN on an index.
|
|
20
|
+
CREATE INDEX IF NOT EXISTS idx_events_metadata_email
|
|
21
|
+
ON public.events ((metadata->>'email'))
|
|
22
|
+
WHERE metadata ? 'email';
|
|
23
|
+
|
|
24
|
+
CREATE INDEX IF NOT EXISTS idx_events_metadata_wa_jid
|
|
25
|
+
ON public.events ((metadata->>'wa_jid'))
|
|
26
|
+
WHERE metadata ? 'wa_jid';
|
|
27
|
+
|
|
28
|
+
CREATE INDEX IF NOT EXISTS idx_events_metadata_phone
|
|
29
|
+
ON public.events ((metadata->>'phone'))
|
|
30
|
+
WHERE metadata ? 'phone';
|
|
31
|
+
|
|
32
|
+
CREATE INDEX IF NOT EXISTS idx_events_metadata_slack_user_id
|
|
33
|
+
ON public.events ((metadata->>'slack_user_id'))
|
|
34
|
+
WHERE metadata ? 'slack_user_id';
|
|
35
|
+
|
|
36
|
+
CREATE INDEX IF NOT EXISTS idx_events_metadata_github_login
|
|
37
|
+
ON public.events ((metadata->>'github_login'))
|
|
38
|
+
WHERE metadata ? 'github_login';
|
|
39
|
+
|
|
40
|
+
CREATE INDEX IF NOT EXISTS idx_events_metadata_auth_user_id
|
|
41
|
+
ON public.events ((metadata->>'auth_user_id'))
|
|
42
|
+
WHERE metadata ? 'auth_user_id';
|
|
43
|
+
|
|
44
|
+
CREATE INDEX IF NOT EXISTS idx_events_metadata_google_contact_id
|
|
45
|
+
ON public.events ((metadata->>'google_contact_id'))
|
|
46
|
+
WHERE metadata ? 'google_contact_id';
|
|
47
|
+
|
|
48
|
+
-- migrate:down
|
|
49
|
+
|
|
50
|
+
DROP INDEX IF EXISTS public.idx_events_metadata_google_contact_id;
|
|
51
|
+
DROP INDEX IF EXISTS public.idx_events_metadata_auth_user_id;
|
|
52
|
+
DROP INDEX IF EXISTS public.idx_events_metadata_github_login;
|
|
53
|
+
DROP INDEX IF EXISTS public.idx_events_metadata_slack_user_id;
|
|
54
|
+
DROP INDEX IF EXISTS public.idx_events_metadata_phone;
|
|
55
|
+
DROP INDEX IF EXISTS public.idx_events_metadata_wa_jid;
|
|
56
|
+
DROP INDEX IF EXISTS public.idx_events_metadata_email;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
-- migrate:up
|
|
2
|
+
|
|
3
|
+
-- Extend reserved org slugs to cover infrastructure subdomains.
|
|
4
|
+
-- RESERVED_SUBDOMAINS in packages/server/src/index.ts already
|
|
5
|
+
-- treats www/mcp/static/cdn/... as non-org at the routing layer; this
|
|
6
|
+
-- mirrors it at the DB layer so those names can never be claimed.
|
|
7
|
+
--
|
|
8
|
+
-- `app` is intentionally NOT reserved — `app.lobu.ai` hosts the auth
|
|
9
|
+
-- org itself, whose DB row uses slug='app'.
|
|
10
|
+
|
|
11
|
+
ALTER TABLE public.organization DROP CONSTRAINT IF EXISTS org_slug_not_reserved;
|
|
12
|
+
|
|
13
|
+
ALTER TABLE public.organization ADD CONSTRAINT org_slug_not_reserved CHECK (
|
|
14
|
+
slug <> ALL (ARRAY[
|
|
15
|
+
'settings',
|
|
16
|
+
'auth',
|
|
17
|
+
'api',
|
|
18
|
+
'templates',
|
|
19
|
+
'help',
|
|
20
|
+
'account',
|
|
21
|
+
'admin',
|
|
22
|
+
'health',
|
|
23
|
+
'login',
|
|
24
|
+
'logout',
|
|
25
|
+
'signup',
|
|
26
|
+
'register',
|
|
27
|
+
'www',
|
|
28
|
+
'mcp',
|
|
29
|
+
'static',
|
|
30
|
+
'assets',
|
|
31
|
+
'cdn',
|
|
32
|
+
'docs',
|
|
33
|
+
'mail'
|
|
34
|
+
]::text[])
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
-- migrate:down
|
|
38
|
+
|
|
39
|
+
ALTER TABLE public.organization DROP CONSTRAINT IF EXISTS org_slug_not_reserved;
|
|
40
|
+
|
|
41
|
+
ALTER TABLE public.organization ADD CONSTRAINT org_slug_not_reserved CHECK (
|
|
42
|
+
slug <> ALL (ARRAY[
|
|
43
|
+
'settings',
|
|
44
|
+
'auth',
|
|
45
|
+
'api',
|
|
46
|
+
'templates',
|
|
47
|
+
'help',
|
|
48
|
+
'account',
|
|
49
|
+
'admin',
|
|
50
|
+
'health',
|
|
51
|
+
'login',
|
|
52
|
+
'logout',
|
|
53
|
+
'signup',
|
|
54
|
+
'register'
|
|
55
|
+
]::text[])
|
|
56
|
+
);
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
-- migrate:up
|
|
2
|
+
|
|
3
|
+
-- Durable correlation between a dispatched watcher run and the agent message
|
|
4
|
+
-- that executes it, and between a completed watcher window and the run that
|
|
5
|
+
-- produced it. Replaces payload-based matching in reconcileWatcherRuns.
|
|
6
|
+
|
|
7
|
+
ALTER TABLE public.runs
|
|
8
|
+
ADD COLUMN IF NOT EXISTS dispatched_message_id text;
|
|
9
|
+
|
|
10
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_runs_dispatched_message_id
|
|
11
|
+
ON public.runs (dispatched_message_id)
|
|
12
|
+
WHERE dispatched_message_id IS NOT NULL;
|
|
13
|
+
|
|
14
|
+
ALTER TABLE public.watcher_windows
|
|
15
|
+
ADD COLUMN IF NOT EXISTS run_id bigint
|
|
16
|
+
REFERENCES public.runs(id) ON DELETE SET NULL;
|
|
17
|
+
|
|
18
|
+
-- Rollout backfill: older windows already stored watcher_run_id in run_metadata,
|
|
19
|
+
-- but pre-migration rows have NULL run_id. Populate the durable FK before the
|
|
20
|
+
-- new reconciler/reset path runs so successful pre-deploy executions are not
|
|
21
|
+
-- re-dispatched on first tick.
|
|
22
|
+
WITH correlated_windows AS (
|
|
23
|
+
SELECT ww.id,
|
|
24
|
+
(btrim(ww.run_metadata->>'watcher_run_id'))::bigint AS correlated_run_id
|
|
25
|
+
FROM public.watcher_windows ww
|
|
26
|
+
WHERE ww.run_id IS NULL
|
|
27
|
+
AND ww.run_metadata ? 'watcher_run_id'
|
|
28
|
+
AND jsonb_typeof(ww.run_metadata->'watcher_run_id') IN ('number', 'string')
|
|
29
|
+
AND btrim(ww.run_metadata->>'watcher_run_id') ~ '^[0-9]+$'
|
|
30
|
+
)
|
|
31
|
+
UPDATE public.watcher_windows ww
|
|
32
|
+
SET run_id = cw.correlated_run_id
|
|
33
|
+
FROM correlated_windows cw
|
|
34
|
+
WHERE ww.id = cw.id
|
|
35
|
+
AND EXISTS (
|
|
36
|
+
SELECT 1
|
|
37
|
+
FROM public.runs r
|
|
38
|
+
WHERE r.id = cw.correlated_run_id
|
|
39
|
+
AND r.run_type = 'watcher'
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
CREATE INDEX IF NOT EXISTS idx_watcher_windows_run_id
|
|
43
|
+
ON public.watcher_windows (run_id)
|
|
44
|
+
WHERE run_id IS NOT NULL;
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
-- migrate:down
|
|
48
|
+
|
|
49
|
+
DROP INDEX IF EXISTS public.idx_watcher_windows_run_id;
|
|
50
|
+
ALTER TABLE public.watcher_windows DROP COLUMN IF EXISTS run_id;
|
|
51
|
+
DROP INDEX IF EXISTS public.idx_runs_dispatched_message_id;
|
|
52
|
+
ALTER TABLE public.runs DROP COLUMN IF EXISTS dispatched_message_id;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
-- migrate:up
|
|
2
|
+
|
|
3
|
+
-- The events table tags each row with the OAuth client that produced it via
|
|
4
|
+
-- `events.client_id -> oauth_clients.id`. The original FK had no ON DELETE
|
|
5
|
+
-- behaviour, so when an oauth_client row was removed (manual cleanup, e2e
|
|
6
|
+
-- teardown, expired registration) any in-flight token still issuing inserts
|
|
7
|
+
-- failed with `events_client_id_fkey` violations (Sentry: LOBU-34).
|
|
8
|
+
--
|
|
9
|
+
-- Match the relaxation already applied to other event-side FKs
|
|
10
|
+
-- (connection_id, feed_id, run_id) and let stale client references reset
|
|
11
|
+
-- to NULL instead of breaking inserts.
|
|
12
|
+
--
|
|
13
|
+
-- Add and validate the replacement constraint before the quick final swap so
|
|
14
|
+
-- existing traffic stays protected and the ACCESS EXCLUSIVE window is short.
|
|
15
|
+
|
|
16
|
+
ALTER TABLE public.events
|
|
17
|
+
ADD CONSTRAINT events_client_id_fkey_v2
|
|
18
|
+
FOREIGN KEY (client_id)
|
|
19
|
+
REFERENCES public.oauth_clients(id)
|
|
20
|
+
ON DELETE SET NULL
|
|
21
|
+
NOT VALID;
|
|
22
|
+
|
|
23
|
+
ALTER TABLE public.events
|
|
24
|
+
VALIDATE CONSTRAINT events_client_id_fkey_v2;
|
|
25
|
+
|
|
26
|
+
ALTER TABLE public.events
|
|
27
|
+
DROP CONSTRAINT IF EXISTS events_client_id_fkey;
|
|
28
|
+
|
|
29
|
+
ALTER TABLE public.events
|
|
30
|
+
RENAME CONSTRAINT events_client_id_fkey_v2 TO events_client_id_fkey;
|
|
31
|
+
|
|
32
|
+
-- migrate:down
|
|
33
|
+
|
|
34
|
+
ALTER TABLE public.events
|
|
35
|
+
ADD CONSTRAINT events_client_id_fkey_v2
|
|
36
|
+
FOREIGN KEY (client_id)
|
|
37
|
+
REFERENCES public.oauth_clients(id)
|
|
38
|
+
NOT VALID;
|
|
39
|
+
|
|
40
|
+
ALTER TABLE public.events
|
|
41
|
+
VALIDATE CONSTRAINT events_client_id_fkey_v2;
|
|
42
|
+
|
|
43
|
+
ALTER TABLE public.events
|
|
44
|
+
DROP CONSTRAINT IF EXISTS events_client_id_fkey;
|
|
45
|
+
|
|
46
|
+
ALTER TABLE public.events
|
|
47
|
+
RENAME CONSTRAINT events_client_id_fkey_v2 TO events_client_id_fkey;
|