@automagik/omni 2.260923.5 → 2.260923.7
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,58 @@
|
|
|
1
|
+
-- Slack OAuth identity uniqueness (#1235, follow-up to #1233).
|
|
2
|
+
--
|
|
3
|
+
-- The OAuth callback upserts one instance per Slack identity, but nothing in
|
|
4
|
+
-- the database enforced it: two callbacks for the same identity landing
|
|
5
|
+
-- together could both insert. These partial unique indexes make the identity
|
|
6
|
+
-- a constraint and give the upsert an ON CONFLICT target:
|
|
7
|
+
--
|
|
8
|
+
-- instances_slack_oauth_user_uq (slack_team_id, slack_user_id) for
|
|
9
|
+
-- user-mode OAuth rows
|
|
10
|
+
-- instances_slack_oauth_bot_uq (slack_team_id) for bot-mode OAuth rows
|
|
11
|
+
-- (NULL slack_user_id) — two bot installs
|
|
12
|
+
-- for one workspace are one identity
|
|
13
|
+
--
|
|
14
|
+
-- Only slack_connection_method = 'oauth' rows are covered: the
|
|
15
|
+
-- instance.connected listener also fills the identity columns of manual
|
|
16
|
+
-- pasted-token instances, which may legitimately repeat.
|
|
17
|
+
--
|
|
18
|
+
-- Duplicate-row policy: detect and refuse. A database that already holds two
|
|
19
|
+
-- OAuth rows for one identity cannot build the index, so the DO block below
|
|
20
|
+
-- fails the migration with the duplicate instance ids instead. Resolve by
|
|
21
|
+
-- deleting the extra instance(s), then restart; nothing is deduped
|
|
22
|
+
-- automatically because each row carries its own live tokens.
|
|
23
|
+
--
|
|
24
|
+
-- Hand-written following the 0043/0044/0052 precedent (additive, idempotent).
|
|
25
|
+
-- No explicit BEGIN/COMMIT — the boot migrator executes this file on a pooled
|
|
26
|
+
-- postgres-js connection, which rejects raw transaction control.
|
|
27
|
+
|
|
28
|
+
DO $$
|
|
29
|
+
DECLARE
|
|
30
|
+
duplicates text;
|
|
31
|
+
BEGIN
|
|
32
|
+
SELECT string_agg(
|
|
33
|
+
format('team %s %s: instances %s',
|
|
34
|
+
slack_team_id,
|
|
35
|
+
COALESCE('user ' || slack_user_id, '(bot)'),
|
|
36
|
+
ids),
|
|
37
|
+
'; ')
|
|
38
|
+
INTO duplicates
|
|
39
|
+
FROM (
|
|
40
|
+
SELECT slack_team_id, slack_user_id, string_agg(id::text, ', ' ORDER BY created_at) AS ids
|
|
41
|
+
FROM "instances"
|
|
42
|
+
WHERE slack_connection_method = 'oauth' AND slack_team_id IS NOT NULL
|
|
43
|
+
GROUP BY slack_team_id, slack_user_id
|
|
44
|
+
HAVING count(*) > 1
|
|
45
|
+
) d;
|
|
46
|
+
|
|
47
|
+
IF duplicates IS NOT NULL THEN
|
|
48
|
+
RAISE EXCEPTION 'Duplicate Slack OAuth instances for one identity (#1235): %. Delete the extra instance(s) and restart.', duplicates;
|
|
49
|
+
END IF;
|
|
50
|
+
END $$;
|
|
51
|
+
|
|
52
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "instances_slack_oauth_user_uq"
|
|
53
|
+
ON "instances" ("slack_team_id", "slack_user_id")
|
|
54
|
+
WHERE "slack_connection_method" = 'oauth' AND "slack_user_id" IS NOT NULL;
|
|
55
|
+
|
|
56
|
+
CREATE UNIQUE INDEX IF NOT EXISTS "instances_slack_oauth_bot_uq"
|
|
57
|
+
ON "instances" ("slack_team_id")
|
|
58
|
+
WHERE "slack_connection_method" = 'oauth' AND "slack_user_id" IS NULL;
|
|
@@ -554,6 +554,13 @@
|
|
|
554
554
|
"when": 1787800000000,
|
|
555
555
|
"tag": "0078_instances_slack_oauth_identity",
|
|
556
556
|
"breakpoints": true
|
|
557
|
+
},
|
|
558
|
+
{
|
|
559
|
+
"idx": 79,
|
|
560
|
+
"version": "7",
|
|
561
|
+
"when": 1787900000000,
|
|
562
|
+
"tag": "0079_instances_slack_identity_unique",
|
|
563
|
+
"breakpoints": true
|
|
557
564
|
}
|
|
558
565
|
]
|
|
559
566
|
}
|
package/dist/index.js
CHANGED
|
@@ -82460,6 +82460,8 @@ var init_schema2 = __esm(() => {
|
|
|
82460
82460
|
agentIdIdx: index("instances_agent_id_idx").on(table3.agentId),
|
|
82461
82461
|
metaPhoneNumberIdx: index("instances_meta_phone_number_idx").on(table3.metaPhoneNumberId),
|
|
82462
82462
|
slackIdentityIdx: index("instances_slack_identity_idx").on(table3.slackTeamId, table3.slackUserId),
|
|
82463
|
+
slackOAuthUserUq: uniqueIndex("instances_slack_oauth_user_uq").on(table3.slackTeamId, table3.slackUserId).where(sql`${table3.slackConnectionMethod} = 'oauth' AND ${table3.slackUserId} IS NOT NULL`),
|
|
82464
|
+
slackOAuthBotUq: uniqueIndex("instances_slack_oauth_bot_uq").on(table3.slackTeamId).where(sql`${table3.slackConnectionMethod} = 'oauth' AND ${table3.slackUserId} IS NULL`),
|
|
82463
82465
|
chainModeCheck: check("instances_chain_mode_check", sql`${table3.chainMode} IN ('off', 'forward', 'bidirectional')`)
|
|
82464
82466
|
}));
|
|
82465
82467
|
whatsappTemplates = pgTable("whatsapp_templates", {
|
|
@@ -137460,7 +137462,7 @@ import { fileURLToPath } from "url";
|
|
|
137460
137462
|
// package.json
|
|
137461
137463
|
var package_default = {
|
|
137462
137464
|
name: "@automagik/omni",
|
|
137463
|
-
version: "2.260923.
|
|
137465
|
+
version: "2.260923.7",
|
|
137464
137466
|
repository: {
|
|
137465
137467
|
type: "git",
|
|
137466
137468
|
url: "git+https://github.com/automagik-dev/omni.git",
|
package/dist/server/index.js
CHANGED
|
@@ -188261,6 +188261,8 @@ var init_schema2 = __esm(() => {
|
|
|
188261
188261
|
agentIdIdx: index("instances_agent_id_idx").on(table3.agentId),
|
|
188262
188262
|
metaPhoneNumberIdx: index("instances_meta_phone_number_idx").on(table3.metaPhoneNumberId),
|
|
188263
188263
|
slackIdentityIdx: index("instances_slack_identity_idx").on(table3.slackTeamId, table3.slackUserId),
|
|
188264
|
+
slackOAuthUserUq: uniqueIndex("instances_slack_oauth_user_uq").on(table3.slackTeamId, table3.slackUserId).where(sql`${table3.slackConnectionMethod} = 'oauth' AND ${table3.slackUserId} IS NOT NULL`),
|
|
188265
|
+
slackOAuthBotUq: uniqueIndex("instances_slack_oauth_bot_uq").on(table3.slackTeamId).where(sql`${table3.slackConnectionMethod} = 'oauth' AND ${table3.slackUserId} IS NULL`),
|
|
188264
188266
|
chainModeCheck: check("instances_chain_mode_check", sql`${table3.chainMode} IN ('off', 'forward', 'bidirectional')`)
|
|
188265
188267
|
}));
|
|
188266
188268
|
whatsappTemplates = pgTable("whatsapp_templates", {
|
|
@@ -266442,7 +266444,7 @@ var init_sentry_scrub = __esm(() => {
|
|
|
266442
266444
|
var require_package7 = __commonJS((exports, module) => {
|
|
266443
266445
|
module.exports = {
|
|
266444
266446
|
name: "@omni/api",
|
|
266445
|
-
version: "2.260923.
|
|
266447
|
+
version: "2.260923.7",
|
|
266446
266448
|
private: true,
|
|
266447
266449
|
type: "module",
|
|
266448
266450
|
exports: {
|
|
@@ -387615,12 +387617,39 @@ class InstanceService {
|
|
|
387615
387617
|
const [row] = await this.db.select({ tenantId: instances.tenantId }).from(instances).where(eq(instances.id, id)).limit(1);
|
|
387616
387618
|
return this.sealTenantFor(row?.tenantId ?? null);
|
|
387617
387619
|
}
|
|
387620
|
+
async findBySlackIdentity(teamId, userId) {
|
|
387621
|
+
const [row] = await this.db.select().from(instances).where(and2(eq(instances.slackConnectionMethod, "oauth"), eq(instances.slackTeamId, teamId), userId === null ? isNull2(instances.slackUserId) : eq(instances.slackUserId, userId))).limit(1);
|
|
387622
|
+
if (!row)
|
|
387623
|
+
return;
|
|
387624
|
+
rememberInstanceOwners([row]);
|
|
387625
|
+
return openInstanceCredentials(row);
|
|
387626
|
+
}
|
|
387618
387627
|
async create(data) {
|
|
387619
|
-
const
|
|
387620
|
-
const [created] = await this.db.insert(instances).values(sealInstanceCredentials(this.sealTenantFor(rowTenant), data)).returning();
|
|
387628
|
+
const created = await this.insert(data, false);
|
|
387621
387629
|
if (!created) {
|
|
387622
387630
|
throw new Error("Failed to create instance");
|
|
387623
387631
|
}
|
|
387632
|
+
return created;
|
|
387633
|
+
}
|
|
387634
|
+
async createSlackOAuth(data) {
|
|
387635
|
+
return this.insert({ ...data, slackConnectionMethod: "oauth" }, true);
|
|
387636
|
+
}
|
|
387637
|
+
async insert(data, slackIdentityConflict) {
|
|
387638
|
+
const rowTenant = data.tenantId ?? null;
|
|
387639
|
+
const query = this.db.insert(instances).values(sealInstanceCredentials(this.sealTenantFor(rowTenant), data));
|
|
387640
|
+
if (slackIdentityConflict) {
|
|
387641
|
+
query.onConflictDoNothing(data.slackUserId == null ? {
|
|
387642
|
+
target: instances.slackTeamId,
|
|
387643
|
+
where: sql`${instances.slackConnectionMethod} = 'oauth' AND ${instances.slackUserId} IS NULL`
|
|
387644
|
+
} : {
|
|
387645
|
+
target: [instances.slackTeamId, instances.slackUserId],
|
|
387646
|
+
where: sql`${instances.slackConnectionMethod} = 'oauth' AND ${instances.slackUserId} IS NOT NULL`
|
|
387647
|
+
});
|
|
387648
|
+
}
|
|
387649
|
+
const [created] = await query.returning();
|
|
387650
|
+
if (!created) {
|
|
387651
|
+
return null;
|
|
387652
|
+
}
|
|
387624
387653
|
rememberInstanceOwners([created]);
|
|
387625
387654
|
if (this.eventBus) {
|
|
387626
387655
|
await this.eventBus.publish("instance.connected", {
|
|
@@ -412858,19 +412887,8 @@ function isAllowedReturnTo(returnTo, publicOrigin) {
|
|
|
412858
412887
|
}
|
|
412859
412888
|
return url.origin === publicOrigin && url.search === "" && url.hash === "";
|
|
412860
412889
|
}
|
|
412861
|
-
function
|
|
412862
|
-
|
|
412863
|
-
return false;
|
|
412864
|
-
if (input.mode === "user")
|
|
412865
|
-
return row.slackUserId === input.userId && row.slackAuthMode === "user";
|
|
412866
|
-
return row.slackUserId == null && (row.slackAuthMode ?? "bot") === "bot";
|
|
412867
|
-
}
|
|
412868
|
-
async function findExisting(instances2, input) {
|
|
412869
|
-
const page = await instances2.list({ channel: ["slack"], limit: SLACK_LOOKUP_LIMIT });
|
|
412870
|
-
if (page.hasMore) {
|
|
412871
|
-
log127.warn("Slack OAuth identity lookup truncated; add a service finder", { limit: SLACK_LOOKUP_LIMIT });
|
|
412872
|
-
}
|
|
412873
|
-
return page.items.find((row) => matchesIdentity(row, input));
|
|
412890
|
+
function findExisting(instances2, input) {
|
|
412891
|
+
return instances2.findBySlackIdentity(input.teamId, input.mode === "user" ? input.userId : null);
|
|
412874
412892
|
}
|
|
412875
412893
|
function baseName(input) {
|
|
412876
412894
|
const team = (input.teamName ?? input.teamId).trim() || input.teamId;
|
|
@@ -412903,7 +412921,7 @@ async function createWithUniqueName(instances2, input) {
|
|
|
412903
412921
|
for (let attempt = 1;attempt <= NAME_SUFFIX_ATTEMPTS; attempt++) {
|
|
412904
412922
|
const name = attempt === 1 ? base2 : `${base2} ${attempt}`;
|
|
412905
412923
|
try {
|
|
412906
|
-
return await instances2.
|
|
412924
|
+
return await instances2.createSlackOAuth({
|
|
412907
412925
|
name,
|
|
412908
412926
|
channel: "slack",
|
|
412909
412927
|
profileName: input.mode === "user" ? input.displayName ?? null : input.teamName ?? null,
|
|
@@ -412956,8 +412974,14 @@ function resolvePlugin(registry5) {
|
|
|
412956
412974
|
async function upsertSlackOAuthInstance(deps, input) {
|
|
412957
412975
|
const plugin13 = resolvePlugin(deps.channelRegistry);
|
|
412958
412976
|
const existing = await findExisting(deps.instances, input);
|
|
412959
|
-
|
|
412960
|
-
const created =
|
|
412977
|
+
let row = existing ? null : await createWithUniqueName(deps.instances, input);
|
|
412978
|
+
const created = row !== null;
|
|
412979
|
+
if (!row) {
|
|
412980
|
+
const current = existing ?? await findExisting(deps.instances, input);
|
|
412981
|
+
if (!current)
|
|
412982
|
+
throw new Error("slack-oauth: identity conflict but no row found");
|
|
412983
|
+
row = await deps.instances.update(current.id, credentialColumns(input));
|
|
412984
|
+
}
|
|
412961
412985
|
log127.info(created ? "Slack OAuth instance created" : "Slack OAuth instance re-authorized", {
|
|
412962
412986
|
instanceId: row.id,
|
|
412963
412987
|
teamId: input.teamId,
|
|
@@ -412972,7 +412996,7 @@ async function upsertSlackOAuthInstance(deps, input) {
|
|
|
412972
412996
|
}
|
|
412973
412997
|
return { instanceId: row.id, created };
|
|
412974
412998
|
}
|
|
412975
|
-
var log127,
|
|
412999
|
+
var log127, NAME_MAX = 200, NAME_SUFFIX_ATTEMPTS = 20;
|
|
412976
413000
|
var init_slack_oauth2 = __esm(() => {
|
|
412977
413001
|
init_src4();
|
|
412978
413002
|
init_src();
|