@sentry/junior 0.267.0 → 0.268.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/dist/{actor-DZSokpwj.js → actor-CP9K2Idu.js} +2 -1
- package/dist/{adapter-BybMEezj.js → adapter-04AcD2SO.js} +4 -6
- package/dist/{admin-DOs1_EiW.js → admin-DIU1QyG3.js} +1 -1
- package/dist/{agent-invocations-CxKldAeB.js → agent-invocations-C1RNOCs8.js} +2 -0
- package/dist/{agent-runner-DgNATN4D.js → agent-runner-CAYfFmU7.js} +4409 -3020
- package/dist/api/schema.d.ts +2 -5629
- package/dist/api/schema.js +4 -4
- package/dist/api.d.ts +1 -1
- package/dist/api.js +154 -32
- package/dist/{app-DAB3fzyp.d.ts → app-z6Uuyq3j.d.ts} +3 -2
- package/dist/app.d.ts +1 -1
- package/dist/app.js +332 -98
- package/dist/{briefs-CWKjka7v.js → briefs-DQbV2jNr.js} +2 -2
- package/dist/{catalog-runtime-cMlAI5LY.js → catalog-runtime-BD9GSpc6.js} +1 -1
- package/dist/cli/chat.js +15 -15
- package/dist/cli/check.js +3 -3
- package/dist/cli/main.js +3 -3
- package/dist/cli/plugins.js +4 -4
- package/dist/cli/snapshot-create.js +4 -4
- package/dist/cli/upgrade.d.ts +1 -1
- package/dist/cli/upgrade.js +3 -3
- package/dist/{client-BjgbMawj.js → client-C1yDYjoS.js} +2 -2
- package/dist/{config-CdB6yJj5.js → config-DrTeF80T.js} +2 -2
- package/dist/{connections-RE_65jzK.js → connections-D46f8vvi.js} +10 -11
- package/dist/{conversation-privacy-BzgJC5k0.js → conversation-privacy-CxlOCiUo.js} +1 -1
- package/dist/{credential-sync-DhEGEpgq.js → credential-sync-sm9fegLY.js} +29 -34
- package/dist/{credentialed-CIGwoLU2.js → credentialed-lukuD-cc.js} +39 -13
- package/dist/db-BU4LQD8s.d.ts +6 -0
- package/dist/{executor-VYrx_K4w.js → executor-4vhvsMZJ.js} +78 -4
- package/dist/instrumentation.js +2 -2
- package/dist/{assistant-reply-CT7VcXQe.js → interruption-marker-CkncDT8d.js} +8 -2
- package/dist/{job-queue-C0BZSa7r.js → job-queue-In9QKz-I.js} +2 -2
- package/dist/{list-1XQP-o6K.js → list-BkgnXEEB.js} +298 -807
- package/dist/{logging-DuZ1A4ab.js → logging-DLSpkSSr.js} +1 -1
- package/dist/{message-NKSbbnA6.js → message-BObyg59s.js} +4 -4
- package/dist/nitro.d.ts +1 -1
- package/dist/nitro.js +3 -3
- package/dist/{oauth-callback-server-qAHLPtml.js → oauth-callback-server-B-WbSdoH.js} +2 -2
- package/dist/{registry-FQutO926.js → registry-BgecKva0.js} +2 -2
- package/dist/{web-message-id-CJSUiksE.js → reporting-window-DVCD_10C.js} +1 -10
- package/dist/{resolve-Bk4yeuHy.js → resolve-Cpa4Bu1O.js} +3 -3
- package/dist/{result-B9e9ATOU.js → result-D3TSmZZ8.js} +8 -8
- package/dist/{runner-C3S2ObH-.js → runner-DS5OKhEp.js} +10 -10
- package/dist/{sandbox-egress-signals-DqpGzzMB.js → sandbox-egress-signals-CnDjY5rx.js} +1 -1
- package/dist/{schema-X7Fj4fv1.js → schema-0050HFnB.js} +80 -4
- package/dist/schema-ZngqcOWM.d.ts +5813 -0
- package/dist/{service-account-Do30HUNv.js → service-account-CKV2WTY7.js} +3 -3
- package/dist/{service-account-BQasl-qq.js → service-account-DGjnDw9y.js} +3 -3
- package/dist/{session-stop-DkOjt46_.js → session-stop-Dam1EI7B.js} +494 -18
- package/dist/{skills-CQHrwfOa.js → skills-CfAnfImD.js} +2 -2
- package/dist/{spawn-BHuqN14f.js → spawn-cmq9p4Ly.js} +2 -2
- package/dist/{store-6EetVP-m.js → store-C5PN02QO.js} +4 -4
- package/dist/{store-B8CABbmR.d.ts → store-xMuuXRE0.d.ts} +13 -7
- package/dist/{store-DvNZIsCr.js → store-zPEoJPBB.js} +3 -3
- package/dist/{task-queue-B0DLgd2P.js → task-queue-_mf28dSu.js} +3 -3
- package/dist/{task-runner-B-PD_JOj.js → task-runner-DMI2prDO.js} +11 -12
- package/dist/{tasks-0ilmuCux.js → tasks-SB9z-VTU.js} +124 -21
- package/dist/{thread-state-DRmdJ2QN.js → thread-state-BbbPh0Sn.js} +8 -18
- package/dist/{turn-failure-response-G11cs2gE.js → turn-failure-response-BKKmnMB5.js} +10 -15
- package/dist/{turn-lifecycle-OzLIwvi1.js → turn-lifecycle-oP0kVeGz.js} +1 -1
- package/dist/{validation-CxEmt1id.js → validation--JsAGLwc.js} +1 -1
- package/dist/{version-Bapedn4A.js → version-jHwJp4hC.js} +1 -1
- package/dist/version.js +1 -1
- package/dist/{viewer-DrN3oC2X.js → viewer-CpXTGlep.js} +323 -235
- package/dist/{user-input-request-BDFBdF8r.js → web-message-id-DlHNANtd.js} +17 -1
- package/dist/{work-DUQoNcqP.js → work-3N-GHY9m.js} +10 -10
- package/dist/{worker-D1l4Ugk0.js → worker-CCdbcItd.js} +6 -6
- package/migrations/0065_user_customization.sql +1 -0
- package/migrations/0066_review_items.sql +53 -0
- package/migrations/0067_review_item_dedupe_tenant.sql +2 -0
- package/migrations/0068_review_item_slack_cards.sql +10 -0
- package/migrations/meta/0065_snapshot.json +3511 -0
- package/migrations/meta/0066_snapshot.json +4099 -0
- package/migrations/meta/0067_snapshot.json +3921 -0
- package/migrations/meta/0068_snapshot.json +4176 -0
- package/migrations/meta/_journal.json +29 -1
- package/package.json +5 -5
- package/dist/db-Bg-zC3r5.d.ts +0 -5
- package/dist/images-CecjXAAz.js +0 -64
- package/dist/turn-session-routing-Dyut9l7Y.js +0 -76
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-nwUcYXjP.js";
|
|
2
|
-
import { i as getChatConfig } from "./config-
|
|
3
|
-
import { L as GOOGLE_IDENTITY_PROVIDER, z as normalizeIdentityEmail } from "./logging-
|
|
4
|
-
import {
|
|
5
|
-
import { c as juniorIdentities, d as juniorDestinations, l as juniorUsers, o as conversationReadColumns, s as juniorConversations } from "./agent-invocations-
|
|
6
|
-
import { _ as
|
|
2
|
+
import { i as getChatConfig } from "./config-DrTeF80T.js";
|
|
3
|
+
import { L as GOOGLE_IDENTITY_PROVIDER, z as normalizeIdentityEmail } from "./logging-DLSpkSSr.js";
|
|
4
|
+
import { a as isSlackUserId, d as parseSlackChannelReferenceId, f as parseSlackTeamId, s as parseActorUserId } from "./actor-CP9K2Idu.js";
|
|
5
|
+
import { c as juniorIdentities, d as juniorDestinations, l as juniorUsers, o as conversationReadColumns, s as juniorConversations } from "./agent-invocations-C1RNOCs8.js";
|
|
6
|
+
import { _ as CONVERSATION_METRICS, h as juniorConversationBindings, m as juniorConversationParticipants, t as createJuniorSqlExecutor, v as juniorConversationMetrics, x as juniorConversationAnnotations, y as juniorConversationEvents } from "./executor-4vhvsMZJ.js";
|
|
7
7
|
import { c as newConversationEventSchema, h as usageSchema, l as encodeHistoryPayload, o as decodeStoredConversationEvent, r as conversationEventDataSchema, s as historyReplacementSchema } from "./history-C84mlAwO.js";
|
|
8
8
|
import { randomUUID } from "node:crypto";
|
|
9
9
|
import { and, asc, desc, eq, gt, gte, inArray, isNull, lt, lte, ne, or, sql } from "drizzle-orm";
|
|
@@ -37,161 +37,6 @@ function sameDestination(left, right) {
|
|
|
37
37
|
if (left.platform === "slack" && right.platform === "slack") return left.teamId === right.teamId && left.channelId === right.channelId;
|
|
38
38
|
return false;
|
|
39
39
|
}
|
|
40
|
-
// src/chat/identities/sql.ts
|
|
41
|
-
function dateFromMs$1(ms) {
|
|
42
|
-
return new Date(ms);
|
|
43
|
-
}
|
|
44
|
-
function tenantId$1(value) {
|
|
45
|
-
return value ?? "";
|
|
46
|
-
}
|
|
47
|
-
async function upsertUser(executor, args) {
|
|
48
|
-
const id = (await executor.db().insert(juniorUsers).values({
|
|
49
|
-
id: randomUUID(),
|
|
50
|
-
primaryEmail: args.email,
|
|
51
|
-
primaryEmailNormalized: args.emailNormalized,
|
|
52
|
-
displayName: args.displayName ?? null,
|
|
53
|
-
createdAt: dateFromMs$1(args.nowMs),
|
|
54
|
-
updatedAt: dateFromMs$1(args.nowMs)
|
|
55
|
-
}).onConflictDoUpdate({
|
|
56
|
-
target: juniorUsers.primaryEmailNormalized,
|
|
57
|
-
set: {
|
|
58
|
-
displayName: sql`coalesce(${juniorUsers.displayName}, excluded.display_name)`,
|
|
59
|
-
updatedAt: sql`excluded.updated_at`
|
|
60
|
-
}
|
|
61
|
-
}).returning({ id: juniorUsers.id }))[0]?.id;
|
|
62
|
-
if (!id) throw new Error("User identity upsert returned no row");
|
|
63
|
-
return id;
|
|
64
|
-
}
|
|
65
|
-
async function existingIdentity(executor, identity) {
|
|
66
|
-
return (await executor.db().select().from(juniorIdentities).where(and(eq(juniorIdentities.provider, identity.provider), eq(juniorIdentities.providerTenantId, tenantId$1(identity.providerTenantId)), eq(juniorIdentities.providerSubjectId, identity.providerSubjectId))))[0];
|
|
67
|
-
}
|
|
68
|
-
async function upsertIdentityRecord(executor, identity, linkedUserId, nowMs) {
|
|
69
|
-
const emailNormalized = normalizeIdentityEmail(identity.email);
|
|
70
|
-
const email = emailNormalized ? identity.email?.trim() || emailNormalized : void 0;
|
|
71
|
-
const existing = await existingIdentity(executor, identity);
|
|
72
|
-
const userEmailNormalized = existing?.emailVerified && existing.emailNormalized ? existing.emailNormalized : identity.emailVerified ? emailNormalized : void 0;
|
|
73
|
-
const userEmail = existing?.emailVerified && existing.email ? existing.email : email ?? userEmailNormalized;
|
|
74
|
-
const verifiedUserId = identity.kind === "user" && userEmailNormalized ? await upsertUser(executor, {
|
|
75
|
-
email: userEmail ?? userEmailNormalized,
|
|
76
|
-
emailNormalized: userEmailNormalized,
|
|
77
|
-
nowMs,
|
|
78
|
-
...existing?.displayName || identity.displayName ? { displayName: existing?.displayName ?? identity.displayName } : void 0
|
|
79
|
-
}) : void 0;
|
|
80
|
-
if (existing?.userId && verifiedUserId && existing.userId !== verifiedUserId) throw new Error("Identity verified email conflicts with linked user");
|
|
81
|
-
if (linkedUserId && verifiedUserId && linkedUserId !== verifiedUserId) throw new Error("Linked identity conflicts with verified email user");
|
|
82
|
-
if (existing?.userId && linkedUserId && existing.userId !== linkedUserId) throw new Error("Identity conflicts with linked user");
|
|
83
|
-
const userId = existing?.userId ?? linkedUserId ?? verifiedUserId;
|
|
84
|
-
const row = (await executor.db().insert(juniorIdentities).values({
|
|
85
|
-
id: randomUUID(),
|
|
86
|
-
userId: userId ?? null,
|
|
87
|
-
kind: identity.kind,
|
|
88
|
-
provider: identity.provider,
|
|
89
|
-
providerTenantId: tenantId$1(identity.providerTenantId),
|
|
90
|
-
providerSubjectId: identity.providerSubjectId,
|
|
91
|
-
displayName: identity.displayName ?? null,
|
|
92
|
-
handle: identity.handle ?? null,
|
|
93
|
-
email: email ?? null,
|
|
94
|
-
emailNormalized: emailNormalized ?? null,
|
|
95
|
-
emailVerified: Boolean(identity.emailVerified && emailNormalized),
|
|
96
|
-
avatarUrl: null,
|
|
97
|
-
metadata: identity.metadata ?? null,
|
|
98
|
-
createdAt: dateFromMs$1(nowMs),
|
|
99
|
-
updatedAt: dateFromMs$1(nowMs)
|
|
100
|
-
}).onConflictDoUpdate({
|
|
101
|
-
target: [
|
|
102
|
-
juniorIdentities.provider,
|
|
103
|
-
juniorIdentities.providerTenantId,
|
|
104
|
-
juniorIdentities.providerSubjectId
|
|
105
|
-
],
|
|
106
|
-
set: {
|
|
107
|
-
kind: sql`excluded.kind`,
|
|
108
|
-
userId: sql`coalesce(${juniorIdentities.userId}, excluded.user_id)`,
|
|
109
|
-
displayName: linkedUserId ? sql`coalesce(excluded.display_name, ${juniorIdentities.displayName})` : sql`coalesce(${juniorIdentities.displayName}, excluded.display_name)`,
|
|
110
|
-
handle: linkedUserId ? sql`coalesce(excluded.handle, ${juniorIdentities.handle})` : sql`coalesce(${juniorIdentities.handle}, excluded.handle)`,
|
|
111
|
-
email: sql`case when ${juniorIdentities.emailVerified} then coalesce(${juniorIdentities.email}, excluded.email) when excluded.email_verified then excluded.email else coalesce(${juniorIdentities.email}, excluded.email) end`,
|
|
112
|
-
emailNormalized: sql`case when ${juniorIdentities.emailVerified} then coalesce(${juniorIdentities.emailNormalized}, excluded.email_normalized) when excluded.email_verified then excluded.email_normalized else coalesce(${juniorIdentities.emailNormalized}, excluded.email_normalized) end`,
|
|
113
|
-
emailVerified: sql`${juniorIdentities.emailVerified} OR excluded.email_verified`,
|
|
114
|
-
avatarUrl: sql`coalesce(${juniorIdentities.avatarUrl}, excluded.avatar_url)`,
|
|
115
|
-
metadata: sql`coalesce(${juniorIdentities.metadata}, excluded.metadata_json)`,
|
|
116
|
-
updatedAt: sql`excluded.updated_at`
|
|
117
|
-
},
|
|
118
|
-
...linkedUserId ? { setWhere: sql`${juniorIdentities.userId} IS NULL OR ${juniorIdentities.userId} = excluded.user_id` } : void 0
|
|
119
|
-
}).returning({
|
|
120
|
-
id: juniorIdentities.id,
|
|
121
|
-
userId: juniorIdentities.userId
|
|
122
|
-
}))[0];
|
|
123
|
-
if (!row) {
|
|
124
|
-
if (linkedUserId) throw new Error("Identity conflicts with linked user");
|
|
125
|
-
throw new Error("Identity upsert returned no row");
|
|
126
|
-
}
|
|
127
|
-
return {
|
|
128
|
-
id: row.id,
|
|
129
|
-
...row.userId ? { userId: row.userId } : void 0
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
/** Read the saved timezone for one user. */
|
|
133
|
-
async function readUserTimezone(db, userId) {
|
|
134
|
-
return (await db.select({ timezone: juniorUsers.timezone }).from(juniorUsers).where(eq(juniorUsers.id, userId)).limit(1))[0]?.timezone ?? void 0;
|
|
135
|
-
}
|
|
136
|
-
/** Save the IANA timezone for one user. */
|
|
137
|
-
async function saveUserTimezone(db, userId, timezone, nowMs) {
|
|
138
|
-
await db.update(juniorUsers).set({
|
|
139
|
-
timezone,
|
|
140
|
-
updatedAt: dateFromMs$1(nowMs)
|
|
141
|
-
}).where(and(eq(juniorUsers.id, userId), sql`${juniorUsers.timezone} is distinct from ${timezone}`));
|
|
142
|
-
}
|
|
143
|
-
/** Persist one provider identity observation and link verified emails to users. */
|
|
144
|
-
async function upsertIdentity(executor, identity, nowMs = Date.now()) {
|
|
145
|
-
return await upsertIdentityRecord(executor, identity, void 0, nowMs);
|
|
146
|
-
}
|
|
147
|
-
/**
|
|
148
|
-
* Persist one provider identity after a trusted account-linking flow.
|
|
149
|
-
* Callers must use provider-verified account data, such as GitHub's authenticated
|
|
150
|
-
* user response, never identity claims inferred from content such as Git commits.
|
|
151
|
-
*/
|
|
152
|
-
async function upsertLinkedIdentity(executor, userId, identity, nowMs = Date.now()) {
|
|
153
|
-
return await upsertIdentityRecord(executor, identity, userId, nowMs);
|
|
154
|
-
}
|
|
155
|
-
/**
|
|
156
|
-
* Find the one user whose primary email is in a provider-verified email list.
|
|
157
|
-
* Return undefined when no user or more than one user matches.
|
|
158
|
-
*/
|
|
159
|
-
async function findUserByVerifiedEmails(executor, emails) {
|
|
160
|
-
const normalized = new Set(emails.map((email) => normalizeIdentityEmail(email) ?? ""));
|
|
161
|
-
normalized.delete("");
|
|
162
|
-
if (normalized.size === 0) return void 0;
|
|
163
|
-
const rows = await executor.db().select({
|
|
164
|
-
email: juniorUsers.primaryEmail,
|
|
165
|
-
userId: juniorUsers.id
|
|
166
|
-
}).from(juniorUsers).where(inArray(juniorUsers.primaryEmailNormalized, Array.from(normalized))).limit(2);
|
|
167
|
-
return rows.length === 1 ? rows[0] : void 0;
|
|
168
|
-
}
|
|
169
|
-
/** Remove one exact provider identity owned by a workspace Slack user. */
|
|
170
|
-
async function deleteProviderIdentityForSlackUser(executor, slackTeamId, slackUserId, provider, providerSubjectId) {
|
|
171
|
-
const userId = (await executor.db().select({ userId: juniorIdentities.userId }).from(juniorIdentities).where(and(eq(juniorIdentities.kind, "user"), eq(juniorIdentities.provider, "slack"), eq(juniorIdentities.providerTenantId, slackTeamId), eq(juniorIdentities.providerSubjectId, slackUserId))).limit(1))[0]?.userId;
|
|
172
|
-
if (!userId) return;
|
|
173
|
-
await deleteProviderIdentityForUser(executor, userId, provider, providerSubjectId);
|
|
174
|
-
}
|
|
175
|
-
/** Remove one exact provider identity owned by a user. */
|
|
176
|
-
async function deleteProviderIdentityForUser(executor, userId, provider, providerSubjectId) {
|
|
177
|
-
await executor.db().delete(juniorIdentities).where(and(eq(juniorIdentities.userId, userId), eq(juniorIdentities.provider, provider), eq(juniorIdentities.providerTenantId, ""), eq(juniorIdentities.providerSubjectId, providerSubjectId)));
|
|
178
|
-
}
|
|
179
|
-
/**
|
|
180
|
-
* Save one Google sign-in. Link the Google identity to the user of its
|
|
181
|
-
* verified email, and set its sign-in time.
|
|
182
|
-
*/
|
|
183
|
-
async function recordGoogleSignIn(executor, account, nowMs = Date.now()) {
|
|
184
|
-
const stored = await upsertIdentity(executor, {
|
|
185
|
-
kind: "user",
|
|
186
|
-
provider: GOOGLE_IDENTITY_PROVIDER,
|
|
187
|
-
providerSubjectId: account.subject,
|
|
188
|
-
email: account.email,
|
|
189
|
-
emailVerified: true,
|
|
190
|
-
displayName: account.displayName
|
|
191
|
-
}, nowMs);
|
|
192
|
-
await executor.db().update(juniorIdentities).set({ signedInAt: dateFromMs$1(nowMs) }).where(eq(juniorIdentities.id, stored.id));
|
|
193
|
-
return stored;
|
|
194
|
-
}
|
|
195
40
|
// src/chat/conversations/sql/participants.ts
|
|
196
41
|
/** Resolve the root conversation id that owns personal-feed membership. */
|
|
197
42
|
async function resolveRootConversationId(executor, conversationId) {
|
|
@@ -339,6 +184,38 @@ function conversationMetricValues(args) {
|
|
|
339
184
|
cost_usd: agentTurnCostUsd(usage)
|
|
340
185
|
};
|
|
341
186
|
}
|
|
187
|
+
/**
|
|
188
|
+
* Read one Run's stored totals from its metric rows.
|
|
189
|
+
*
|
|
190
|
+
* Returns undefined when the Run has no rows. Cost keeps only its total.
|
|
191
|
+
*/
|
|
192
|
+
async function readConversationRunMetrics(executor, args) {
|
|
193
|
+
const rows = await executor.db().select({
|
|
194
|
+
metric: juniorConversationMetrics.metric,
|
|
195
|
+
value: juniorConversationMetrics.value
|
|
196
|
+
}).from(juniorConversationMetrics).where(and(eq(juniorConversationMetrics.conversationId, args.conversationId), eq(juniorConversationMetrics.runId, args.runId)));
|
|
197
|
+
const values = new Map(rows.map((row) => [row.metric, row.value]));
|
|
198
|
+
const durationMs = values.get("duration_ms");
|
|
199
|
+
if (durationMs === void 0) return void 0;
|
|
200
|
+
const components = {
|
|
201
|
+
inputTokens: values.get("input_tokens"),
|
|
202
|
+
outputTokens: values.get("output_tokens"),
|
|
203
|
+
cachedInputTokens: values.get("cached_input_tokens"),
|
|
204
|
+
cacheCreationTokens: values.get("cache_creation_tokens")
|
|
205
|
+
};
|
|
206
|
+
const hasComponents = Object.values(components).some((value) => value !== void 0);
|
|
207
|
+
const costUsd = values.get("cost_usd");
|
|
208
|
+
const usage = Object.fromEntries(Object.entries({
|
|
209
|
+
...components,
|
|
210
|
+
reasoningTokens: values.get("reasoning_tokens"),
|
|
211
|
+
totalTokens: hasComponents ? void 0 : values.get("total_tokens"),
|
|
212
|
+
cost: costUsd === void 0 ? void 0 : { total: costUsd }
|
|
213
|
+
}).filter(([, value]) => value !== void 0));
|
|
214
|
+
return {
|
|
215
|
+
durationMs,
|
|
216
|
+
...Object.keys(usage).length > 0 ? { usage } : void 0
|
|
217
|
+
};
|
|
218
|
+
}
|
|
342
219
|
/** Replace one Run's metric rows and refresh its Conversation totals. */
|
|
343
220
|
async function replaceConversationMetrics(executor, args) {
|
|
344
221
|
const [current] = await executor.db().select({ updatedAt: juniorConversationMetrics.updatedAt }).from(juniorConversationMetrics).where(and(eq(juniorConversationMetrics.conversationId, args.conversationId), eq(juniorConversationMetrics.runId, args.runId))).limit(1);
|
|
@@ -448,44 +325,260 @@ async function bindProviderConversation(executor, args) {
|
|
|
448
325
|
createdAt: /* @__PURE__ */ new Date()
|
|
449
326
|
}).onConflictDoNothing().returning({ conversationId: juniorConversationBindings.conversationId }))[0]?.conversationId ?? await getConversationIdByProviderConversation(executor, args)) !== args.conversationId) throw new Error("Provider conversation is already bound to another conversation");
|
|
450
327
|
}
|
|
328
|
+
// src/chat/identities/sql.ts
|
|
329
|
+
function dateFromMs$1(ms) {
|
|
330
|
+
return new Date(ms);
|
|
331
|
+
}
|
|
332
|
+
function tenantId$1(value) {
|
|
333
|
+
return value ?? "";
|
|
334
|
+
}
|
|
335
|
+
async function upsertUser(executor, args) {
|
|
336
|
+
const id = (await executor.db().insert(juniorUsers).values({
|
|
337
|
+
id: randomUUID(),
|
|
338
|
+
primaryEmail: args.email,
|
|
339
|
+
primaryEmailNormalized: args.emailNormalized,
|
|
340
|
+
displayName: args.displayName ?? null,
|
|
341
|
+
createdAt: dateFromMs$1(args.nowMs),
|
|
342
|
+
updatedAt: dateFromMs$1(args.nowMs)
|
|
343
|
+
}).onConflictDoUpdate({
|
|
344
|
+
target: juniorUsers.primaryEmailNormalized,
|
|
345
|
+
set: {
|
|
346
|
+
displayName: sql`coalesce(${juniorUsers.displayName}, excluded.display_name)`,
|
|
347
|
+
updatedAt: sql`excluded.updated_at`
|
|
348
|
+
}
|
|
349
|
+
}).returning({ id: juniorUsers.id }))[0]?.id;
|
|
350
|
+
if (!id) throw new Error("User identity upsert returned no row");
|
|
351
|
+
return id;
|
|
352
|
+
}
|
|
353
|
+
async function existingIdentity(executor, identity) {
|
|
354
|
+
return (await executor.db().select().from(juniorIdentities).where(and(eq(juniorIdentities.provider, identity.provider), eq(juniorIdentities.providerTenantId, tenantId$1(identity.providerTenantId)), eq(juniorIdentities.providerSubjectId, identity.providerSubjectId))))[0];
|
|
355
|
+
}
|
|
356
|
+
async function upsertIdentityRecord(executor, identity, linkedUserId, nowMs) {
|
|
357
|
+
const emailNormalized = normalizeIdentityEmail(identity.email);
|
|
358
|
+
const email = emailNormalized ? identity.email?.trim() || emailNormalized : void 0;
|
|
359
|
+
const existing = await existingIdentity(executor, identity);
|
|
360
|
+
const userEmailNormalized = existing?.emailVerified && existing.emailNormalized ? existing.emailNormalized : identity.emailVerified ? emailNormalized : void 0;
|
|
361
|
+
const userEmail = existing?.emailVerified && existing.email ? existing.email : email ?? userEmailNormalized;
|
|
362
|
+
const verifiedUserId = identity.kind === "user" && userEmailNormalized ? await upsertUser(executor, {
|
|
363
|
+
email: userEmail ?? userEmailNormalized,
|
|
364
|
+
emailNormalized: userEmailNormalized,
|
|
365
|
+
nowMs,
|
|
366
|
+
...existing?.displayName || identity.displayName ? { displayName: existing?.displayName ?? identity.displayName } : void 0
|
|
367
|
+
}) : void 0;
|
|
368
|
+
if (existing?.userId && verifiedUserId && existing.userId !== verifiedUserId) throw new Error("Identity verified email conflicts with linked user");
|
|
369
|
+
if (linkedUserId && verifiedUserId && linkedUserId !== verifiedUserId) throw new Error("Linked identity conflicts with verified email user");
|
|
370
|
+
if (existing?.userId && linkedUserId && existing.userId !== linkedUserId) throw new Error("Identity conflicts with linked user");
|
|
371
|
+
const userId = existing?.userId ?? linkedUserId ?? verifiedUserId;
|
|
372
|
+
const row = (await executor.db().insert(juniorIdentities).values({
|
|
373
|
+
id: randomUUID(),
|
|
374
|
+
userId: userId ?? null,
|
|
375
|
+
kind: identity.kind,
|
|
376
|
+
provider: identity.provider,
|
|
377
|
+
providerTenantId: tenantId$1(identity.providerTenantId),
|
|
378
|
+
providerSubjectId: identity.providerSubjectId,
|
|
379
|
+
displayName: identity.displayName ?? null,
|
|
380
|
+
handle: identity.handle ?? null,
|
|
381
|
+
email: email ?? null,
|
|
382
|
+
emailNormalized: emailNormalized ?? null,
|
|
383
|
+
emailVerified: Boolean(identity.emailVerified && emailNormalized),
|
|
384
|
+
avatarUrl: null,
|
|
385
|
+
metadata: identity.metadata ?? null,
|
|
386
|
+
createdAt: dateFromMs$1(nowMs),
|
|
387
|
+
updatedAt: dateFromMs$1(nowMs)
|
|
388
|
+
}).onConflictDoUpdate({
|
|
389
|
+
target: [
|
|
390
|
+
juniorIdentities.provider,
|
|
391
|
+
juniorIdentities.providerTenantId,
|
|
392
|
+
juniorIdentities.providerSubjectId
|
|
393
|
+
],
|
|
394
|
+
set: {
|
|
395
|
+
kind: sql`excluded.kind`,
|
|
396
|
+
userId: sql`coalesce(${juniorIdentities.userId}, excluded.user_id)`,
|
|
397
|
+
displayName: linkedUserId ? sql`coalesce(excluded.display_name, ${juniorIdentities.displayName})` : sql`coalesce(${juniorIdentities.displayName}, excluded.display_name)`,
|
|
398
|
+
handle: linkedUserId ? sql`coalesce(excluded.handle, ${juniorIdentities.handle})` : sql`coalesce(${juniorIdentities.handle}, excluded.handle)`,
|
|
399
|
+
email: sql`case when ${juniorIdentities.emailVerified} then coalesce(${juniorIdentities.email}, excluded.email) when excluded.email_verified then excluded.email else coalesce(${juniorIdentities.email}, excluded.email) end`,
|
|
400
|
+
emailNormalized: sql`case when ${juniorIdentities.emailVerified} then coalesce(${juniorIdentities.emailNormalized}, excluded.email_normalized) when excluded.email_verified then excluded.email_normalized else coalesce(${juniorIdentities.emailNormalized}, excluded.email_normalized) end`,
|
|
401
|
+
emailVerified: sql`${juniorIdentities.emailVerified} OR excluded.email_verified`,
|
|
402
|
+
avatarUrl: sql`coalesce(${juniorIdentities.avatarUrl}, excluded.avatar_url)`,
|
|
403
|
+
metadata: sql`coalesce(${juniorIdentities.metadata}, excluded.metadata_json)`,
|
|
404
|
+
updatedAt: sql`excluded.updated_at`
|
|
405
|
+
},
|
|
406
|
+
...linkedUserId ? { setWhere: sql`${juniorIdentities.userId} IS NULL OR ${juniorIdentities.userId} = excluded.user_id` } : void 0
|
|
407
|
+
}).returning({
|
|
408
|
+
id: juniorIdentities.id,
|
|
409
|
+
userId: juniorIdentities.userId
|
|
410
|
+
}))[0];
|
|
411
|
+
if (!row) {
|
|
412
|
+
if (linkedUserId) throw new Error("Identity conflicts with linked user");
|
|
413
|
+
throw new Error("Identity upsert returned no row");
|
|
414
|
+
}
|
|
415
|
+
return {
|
|
416
|
+
id: row.id,
|
|
417
|
+
...row.userId ? { userId: row.userId } : void 0
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
/** Read the saved timezone for one user. */
|
|
421
|
+
async function readUserTimezone(db, userId) {
|
|
422
|
+
return (await db.select({ timezone: juniorUsers.timezone }).from(juniorUsers).where(eq(juniorUsers.id, userId)).limit(1))[0]?.timezone ?? void 0;
|
|
423
|
+
}
|
|
424
|
+
/** Save the IANA timezone for one user. */
|
|
425
|
+
async function saveUserTimezone(db, userId, timezone, nowMs) {
|
|
426
|
+
await db.update(juniorUsers).set({
|
|
427
|
+
timezone,
|
|
428
|
+
updatedAt: dateFromMs$1(nowMs)
|
|
429
|
+
}).where(and(eq(juniorUsers.id, userId), sql`${juniorUsers.timezone} is distinct from ${timezone}`));
|
|
430
|
+
}
|
|
431
|
+
/** Persist one provider identity observation and link verified emails to users. */
|
|
432
|
+
async function upsertIdentity(executor, identity, nowMs = Date.now()) {
|
|
433
|
+
return await upsertIdentityRecord(executor, identity, void 0, nowMs);
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* Persist one provider identity after a trusted account-linking flow.
|
|
437
|
+
* Callers must use provider-verified account data, such as GitHub's authenticated
|
|
438
|
+
* user response, never identity claims inferred from content such as Git commits.
|
|
439
|
+
*/
|
|
440
|
+
async function upsertLinkedIdentity(executor, userId, identity, nowMs = Date.now()) {
|
|
441
|
+
return await upsertIdentityRecord(executor, identity, userId, nowMs);
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* Find the one user whose primary email is in a provider-verified email list.
|
|
445
|
+
* Return undefined when no user or more than one user matches.
|
|
446
|
+
*/
|
|
447
|
+
async function findUserByVerifiedEmails(executor, emails) {
|
|
448
|
+
const normalized = new Set(emails.map((email) => normalizeIdentityEmail(email) ?? ""));
|
|
449
|
+
normalized.delete("");
|
|
450
|
+
if (normalized.size === 0) return void 0;
|
|
451
|
+
const rows = await executor.db().select({
|
|
452
|
+
email: juniorUsers.primaryEmail,
|
|
453
|
+
userId: juniorUsers.id
|
|
454
|
+
}).from(juniorUsers).where(inArray(juniorUsers.primaryEmailNormalized, Array.from(normalized))).limit(2);
|
|
455
|
+
return rows.length === 1 ? rows[0] : void 0;
|
|
456
|
+
}
|
|
457
|
+
/** Remove one exact provider identity owned by a workspace Slack user. */
|
|
458
|
+
async function deleteProviderIdentityForSlackUser(executor, slackTeamId, slackUserId, provider, providerSubjectId) {
|
|
459
|
+
const userId = (await executor.db().select({ userId: juniorIdentities.userId }).from(juniorIdentities).where(and(eq(juniorIdentities.kind, "user"), eq(juniorIdentities.provider, "slack"), eq(juniorIdentities.providerTenantId, slackTeamId), eq(juniorIdentities.providerSubjectId, slackUserId))).limit(1))[0]?.userId;
|
|
460
|
+
if (!userId) return;
|
|
461
|
+
await deleteProviderIdentityForUser(executor, userId, provider, providerSubjectId);
|
|
462
|
+
}
|
|
463
|
+
/** Remove one exact provider identity owned by a user. */
|
|
464
|
+
async function deleteProviderIdentityForUser(executor, userId, provider, providerSubjectId) {
|
|
465
|
+
await executor.db().delete(juniorIdentities).where(and(eq(juniorIdentities.userId, userId), eq(juniorIdentities.provider, provider), eq(juniorIdentities.providerTenantId, ""), eq(juniorIdentities.providerSubjectId, providerSubjectId)));
|
|
466
|
+
}
|
|
467
|
+
/**
|
|
468
|
+
* Save one Google sign-in. Link the Google identity to the user of its
|
|
469
|
+
* verified email, and set its sign-in time.
|
|
470
|
+
*/
|
|
471
|
+
async function recordGoogleSignIn(executor, account, nowMs = Date.now()) {
|
|
472
|
+
const stored = await upsertIdentity(executor, {
|
|
473
|
+
kind: "user",
|
|
474
|
+
provider: GOOGLE_IDENTITY_PROVIDER,
|
|
475
|
+
providerSubjectId: account.subject,
|
|
476
|
+
email: account.email,
|
|
477
|
+
emailVerified: true,
|
|
478
|
+
displayName: account.displayName
|
|
479
|
+
}, nowMs);
|
|
480
|
+
await executor.db().update(juniorIdentities).set({ signedInAt: dateFromMs$1(nowMs) }).where(eq(juniorIdentities.id, stored.id));
|
|
481
|
+
return stored;
|
|
482
|
+
}
|
|
483
|
+
// src/chat/identities/actor.ts
|
|
484
|
+
/**
|
|
485
|
+
* Resolve runtime Actors to the Identity rows that Junior stores for them.
|
|
486
|
+
*
|
|
487
|
+
* The Conversation store, OAuth, the viewer, and message events use this
|
|
488
|
+
* module, so they agree on one Identity per person. The key for each Actor
|
|
489
|
+
* stays private here, so it can change without changing callers.
|
|
490
|
+
*/
|
|
491
|
+
/** The one Identity for work that Junior does on its own. */
|
|
492
|
+
const SYSTEM_IDENTITY = {
|
|
493
|
+
kind: "system",
|
|
494
|
+
provider: "junior",
|
|
495
|
+
providerSubjectId: "system",
|
|
496
|
+
displayName: "System"
|
|
497
|
+
};
|
|
498
|
+
/**
|
|
499
|
+
* Return the Identity key for one Actor.
|
|
500
|
+
*
|
|
501
|
+
* Every SystemActor uses the one system Identity. `SystemActor.name` is
|
|
502
|
+
* provenance, not part of the key. A LocalActor uses the system Identity too,
|
|
503
|
+
* because the local runner has no per-person user id.
|
|
504
|
+
*/
|
|
505
|
+
function identityKey(actor) {
|
|
506
|
+
switch (actor.platform) {
|
|
507
|
+
case "slack": return {
|
|
508
|
+
kind: "user",
|
|
509
|
+
provider: "slack",
|
|
510
|
+
providerTenantId: actor.teamId,
|
|
511
|
+
providerSubjectId: actor.userId,
|
|
512
|
+
...actor.fullName ? { displayName: actor.fullName } : void 0,
|
|
513
|
+
...actor.userName ? { handle: actor.userName } : void 0,
|
|
514
|
+
...actor.email ? {
|
|
515
|
+
email: actor.email,
|
|
516
|
+
emailVerified: true
|
|
517
|
+
} : void 0,
|
|
518
|
+
metadata: { platform: "slack" }
|
|
519
|
+
};
|
|
520
|
+
case "web": {
|
|
521
|
+
const email = normalizeIdentityEmail(actor.email);
|
|
522
|
+
if (!email) return;
|
|
523
|
+
return {
|
|
524
|
+
kind: "user",
|
|
525
|
+
provider: "junior",
|
|
526
|
+
providerSubjectId: email,
|
|
527
|
+
email,
|
|
528
|
+
emailVerified: true,
|
|
529
|
+
...actor.fullName ? { displayName: actor.fullName } : void 0,
|
|
530
|
+
metadata: { platform: "web" }
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
case "local":
|
|
534
|
+
case "system": return SYSTEM_IDENTITY;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
/**
|
|
538
|
+
* Save the Identity for one Actor and return its id.
|
|
539
|
+
* Return undefined only for a web Actor without a verified email.
|
|
540
|
+
*/
|
|
541
|
+
async function resolveActorIdentityId(executor, actor, nowMs = Date.now()) {
|
|
542
|
+
const key = identityKey(actor);
|
|
543
|
+
return key ? (await upsertIdentity(executor, key, nowMs)).id : void 0;
|
|
544
|
+
}
|
|
545
|
+
/** Find the stored Identity id for one Actor without writing. */
|
|
546
|
+
async function findActorIdentityId(db, actor) {
|
|
547
|
+
const key = identityKey(actor);
|
|
548
|
+
if (!key) return;
|
|
549
|
+
return (await db.select({ id: juniorIdentities.id }).from(juniorIdentities).where(and(eq(juniorIdentities.provider, key.provider), eq(juniorIdentities.providerTenantId, key.providerTenantId ?? ""), eq(juniorIdentities.providerSubjectId, key.providerSubjectId))).limit(1))[0]?.id;
|
|
550
|
+
}
|
|
451
551
|
// src/chat/conversations/sql/actor-identity.ts
|
|
452
|
-
/**
|
|
453
|
-
|
|
552
|
+
/**
|
|
553
|
+
* Convert an Actor in the stored Conversation shape to a runtime Actor.
|
|
554
|
+
*
|
|
555
|
+
* TODO(dcramer): Remove after Conversations store the Identity id instead of
|
|
556
|
+
* StoredSlackActor.
|
|
557
|
+
*/
|
|
558
|
+
function actorFromStoredActor(actor) {
|
|
454
559
|
if (actor?.slackUserId) return {
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
...actor.slackUserName ? {
|
|
461
|
-
...actor.email ? {
|
|
462
|
-
email: actor.email,
|
|
463
|
-
emailVerified: true
|
|
464
|
-
} : void 0,
|
|
465
|
-
metadata: { platform: "slack" }
|
|
560
|
+
...actor.email ? { email: actor.email } : void 0,
|
|
561
|
+
...actor.fullName ? { fullName: actor.fullName } : void 0,
|
|
562
|
+
platform: "slack",
|
|
563
|
+
teamId: actor.teamId ?? "",
|
|
564
|
+
userId: actor.slackUserId,
|
|
565
|
+
...actor.slackUserName ? { userName: actor.slackUserName } : void 0
|
|
466
566
|
};
|
|
467
|
-
|
|
468
|
-
if (!email) return;
|
|
567
|
+
if (!actor?.email) return;
|
|
469
568
|
return {
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
email
|
|
474
|
-
emailVerified: true,
|
|
475
|
-
...actor?.fullName ? { displayName: actor.fullName } : void 0,
|
|
476
|
-
metadata: { platform: "web" }
|
|
569
|
+
email: actor.email,
|
|
570
|
+
...actor.fullName ? { fullName: actor.fullName } : void 0,
|
|
571
|
+
platform: "web",
|
|
572
|
+
userId: actor.email
|
|
477
573
|
};
|
|
478
574
|
}
|
|
479
575
|
/**
|
|
480
|
-
* Build the
|
|
481
|
-
*
|
|
482
|
-
*
|
|
576
|
+
* Build the legacy system Identity for a Conversation that has no Actor.
|
|
577
|
+
*
|
|
578
|
+
* TODO(dcramer): Remove after every ingress supplies its Actor. These rows use
|
|
579
|
+
* one subject per Source (`scheduler`, `local-cli`, `event`). An Actor
|
|
580
|
+
* uses the one system Identity instead, so the backfill must merge them.
|
|
483
581
|
*/
|
|
484
|
-
function identityFromRuntimeActor(actor) {
|
|
485
|
-
if (actor.platform === "slack") return identityFromActor(toStoredSlackActor(actor));
|
|
486
|
-
if (actor.platform === "web") return identityFromActor(actor.email ? { email: actor.email } : void 0);
|
|
487
|
-
}
|
|
488
|
-
/** Build a system identity when a conversation has no user actor. */
|
|
489
582
|
function systemIdentityFromSource(source) {
|
|
490
583
|
if (source === "scheduler") return {
|
|
491
584
|
kind: "system",
|
|
@@ -506,9 +599,15 @@ function systemIdentityFromSource(source) {
|
|
|
506
599
|
displayName: "Event"
|
|
507
600
|
};
|
|
508
601
|
}
|
|
509
|
-
/**
|
|
510
|
-
|
|
511
|
-
|
|
602
|
+
/**
|
|
603
|
+
* Save the Identity of a Conversation's actor and return its id. Use the
|
|
604
|
+
* legacy source system Identity when the Conversation has no actor.
|
|
605
|
+
*/
|
|
606
|
+
async function resolveConversationActorIdentityId(executor, conversation) {
|
|
607
|
+
const actor = actorFromStoredActor(conversation.actor);
|
|
608
|
+
if (actor) return await resolveActorIdentityId(executor, actor, conversation.updatedAtMs);
|
|
609
|
+
const fallback = systemIdentityFromSource(conversation.source);
|
|
610
|
+
return fallback ? (await upsertIdentity(executor, fallback, conversation.updatedAtMs)).id : void 0;
|
|
512
611
|
}
|
|
513
612
|
/**
|
|
514
613
|
* Reconstruct a stored actor with the linked user name and identity-scoped
|
|
@@ -780,6 +879,9 @@ var SqlStore = class {
|
|
|
780
879
|
if (!row) return;
|
|
781
880
|
return conversationFromRow(row);
|
|
782
881
|
}
|
|
882
|
+
async getRunMetrics(args) {
|
|
883
|
+
return await readConversationRunMetrics(this.executor, args);
|
|
884
|
+
}
|
|
783
885
|
async recordActivity(args) {
|
|
784
886
|
const nowMs = args.nowMs ?? now();
|
|
785
887
|
const activityAtMs = args.activityAtMs ?? nowMs;
|
|
@@ -824,7 +926,12 @@ var SqlStore = class {
|
|
|
824
926
|
const existing = existingRow ? conversationFromRow(existingRow) : void 0;
|
|
825
927
|
if (!existing && !args.destination) return;
|
|
826
928
|
const incomingExecutionAt = args.execution.updatedAtMs ?? args.updatedAtMs;
|
|
827
|
-
const
|
|
929
|
+
const existingExecutionAt = existing?.execution.updatedAtMs ?? existing?.updatedAtMs ?? 0;
|
|
930
|
+
const latestMetricRunId = existing?.executionMetrics?.runId;
|
|
931
|
+
const incomingIsFresh = !(args.metrics !== null && args.execution.runId !== void 0 && latestMetricRunId !== void 0 && latestMetricRunId !== args.execution.runId && (args.execution.status === "idle" || args.execution.status === "failed") && await readConversationRunMetrics(this.executor, {
|
|
932
|
+
conversationId: args.conversationId,
|
|
933
|
+
runId: args.execution.runId
|
|
934
|
+
}) !== void 0) && incomingExecutionAt >= existingExecutionAt;
|
|
828
935
|
const execution = incomingIsFresh ? args.execution : existing?.execution ?? args.execution;
|
|
829
936
|
const actor = mergeActor(existing?.actor, args.actor);
|
|
830
937
|
const source = existing?.source ?? args.source;
|
|
@@ -924,8 +1031,7 @@ var SqlStore = class {
|
|
|
924
1031
|
location: conversation.location,
|
|
925
1032
|
sessionSource: conversation.sessionSource
|
|
926
1033
|
});
|
|
927
|
-
const
|
|
928
|
-
const actorIdentity = actorIdentityObservation ? await upsertIdentity(this.executor, actorIdentityObservation, conversation.updatedAtMs) : void 0;
|
|
1034
|
+
const actorIdentityId = await resolveConversationActorIdentityId(this.executor, conversation);
|
|
929
1035
|
const rootConversationId = conversation.parentConversationId ? sql`(
|
|
930
1036
|
select parent.root_conversation_id
|
|
931
1037
|
from junior_conversations parent
|
|
@@ -939,7 +1045,7 @@ var SqlStore = class {
|
|
|
939
1045
|
location: location ?? null,
|
|
940
1046
|
destinationId: destinationId ?? null,
|
|
941
1047
|
destination: null,
|
|
942
|
-
actorIdentityId:
|
|
1048
|
+
actorIdentityId: actorIdentityId ?? null,
|
|
943
1049
|
creatorIdentityId: null,
|
|
944
1050
|
credentialSubjectIdentityId: null,
|
|
945
1051
|
actor: null,
|
|
@@ -1061,7 +1167,6 @@ async function ensureConversationRow(executor, conversationId, atMs, options = {
|
|
|
1061
1167
|
});
|
|
1062
1168
|
}
|
|
1063
1169
|
// src/chat/conversations/sql/event-actor.ts
|
|
1064
|
-
const SLACK_USER_ID_PATTERN = /^[UW][A-Z0-9]{5,}$/;
|
|
1065
1170
|
function isRecord(value) {
|
|
1066
1171
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
1067
1172
|
}
|
|
@@ -1130,36 +1235,28 @@ async function resolveEventActorIdentityId(executor, args) {
|
|
|
1130
1235
|
if (author.isBot === true) return;
|
|
1131
1236
|
const userId = parseActorUserId(author.userId);
|
|
1132
1237
|
if (!userId) return;
|
|
1133
|
-
if (
|
|
1238
|
+
if (isSlackUserId(userId)) {
|
|
1134
1239
|
const tenantId = await loadConversationSlackTenantId(executor, args.conversationId);
|
|
1135
|
-
|
|
1136
|
-
kind: "user",
|
|
1137
|
-
provider: "slack",
|
|
1138
|
-
providerSubjectId: userId,
|
|
1139
|
-
...tenantId ? { providerTenantId: tenantId } : void 0,
|
|
1140
|
-
...author.fullName ? { displayName: author.fullName } : void 0,
|
|
1141
|
-
...author.userName ? { handle: author.userName } : void 0,
|
|
1142
|
-
...author.email ? {
|
|
1143
|
-
email: author.email,
|
|
1144
|
-
emailVerified: true
|
|
1145
|
-
} : void 0
|
|
1146
|
-
};
|
|
1147
|
-
if (tenantId) return (await upsertIdentity(executor, observation, args.nowMs)).id;
|
|
1148
|
-
return await findIdentityIdByProviderSubject(executor, {
|
|
1240
|
+
if (!tenantId) return await findIdentityIdByProviderSubject(executor, {
|
|
1149
1241
|
provider: "slack",
|
|
1150
1242
|
providerSubjectId: userId
|
|
1151
|
-
})
|
|
1243
|
+
});
|
|
1244
|
+
return await resolveActorIdentityId(executor, {
|
|
1245
|
+
platform: "slack",
|
|
1246
|
+
teamId: tenantId,
|
|
1247
|
+
userId,
|
|
1248
|
+
...author.email ? { email: author.email } : void 0,
|
|
1249
|
+
...author.fullName ? { fullName: author.fullName } : void 0,
|
|
1250
|
+
...author.userName ? { userName: author.userName } : void 0
|
|
1251
|
+
}, args.nowMs);
|
|
1152
1252
|
}
|
|
1153
|
-
const email = typeof author.email === "string" && author.email.includes("@") ? author.email
|
|
1154
|
-
if (email) return
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
providerSubjectId: email,
|
|
1253
|
+
const email = typeof author.email === "string" && author.email.includes("@") ? author.email : userId.includes("@") ? userId : void 0;
|
|
1254
|
+
if (email) return await resolveActorIdentityId(executor, {
|
|
1255
|
+
platform: "web",
|
|
1256
|
+
userId,
|
|
1158
1257
|
email,
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
metadata: { platform: "web" }
|
|
1162
|
-
}, args.nowMs)).id;
|
|
1258
|
+
...author.fullName ? { fullName: author.fullName } : void 0
|
|
1259
|
+
}, args.nowMs);
|
|
1163
1260
|
if (userId.startsWith("dashboard:")) return findJuniorIdentityIdByDashboardAuthorId(executor, userId);
|
|
1164
1261
|
return findJuniorIdentityIdByEmail(executor, userId);
|
|
1165
1262
|
}
|
|
@@ -1641,17 +1738,8 @@ async function listAdminUsersFromSql(db) {
|
|
|
1641
1738
|
}
|
|
1642
1739
|
/** Resolve the stored identity and linked user for one runtime actor. */
|
|
1643
1740
|
async function readActorIdentityFromSql(db, actor) {
|
|
1644
|
-
const
|
|
1645
|
-
|
|
1646
|
-
const row = (await db.select({
|
|
1647
|
-
identity: juniorIdentities,
|
|
1648
|
-
user: juniorUsers
|
|
1649
|
-
}).from(juniorIdentities).leftJoin(juniorUsers, eq(juniorUsers.id, juniorIdentities.userId)).where(and(eq(juniorIdentities.kind, "user"), eq(juniorIdentities.provider, key.provider), eq(juniorIdentities.providerTenantId, key.providerTenantId ?? ""), eq(juniorIdentities.providerSubjectId, key.providerSubjectId))).limit(1))[0];
|
|
1650
|
-
if (!row) return void 0;
|
|
1651
|
-
return {
|
|
1652
|
-
identity: identityFromRow(row.identity),
|
|
1653
|
-
...row.user ? { user: await readUserById(db, row.user) } : void 0
|
|
1654
|
-
};
|
|
1741
|
+
const identityId = await findActorIdentityId(db, actor);
|
|
1742
|
+
return identityId ? await readIdentityByIdFromSql(db, identityId) : void 0;
|
|
1655
1743
|
}
|
|
1656
1744
|
/** Resolve the stored identity and linked user for one runtime actor. */
|
|
1657
1745
|
async function readActorIdentity(actor) {
|
|
@@ -1673,4 +1761,4 @@ async function readIdentityByIdFromSql(db, identityId) {
|
|
|
1673
1761
|
async function readIdentityById(identityId) {
|
|
1674
1762
|
return await readIdentityByIdFromSql(getDb(), identityId);
|
|
1675
1763
|
}
|
|
1676
|
-
export {
|
|
1764
|
+
export { upsertLinkedIdentity as A, parseDestination as B, resolveActorIdentityId as C, readUserTimezone as D, findUserByVerifiedEmails as E, agentTurnTotalTokens as F, sameDestination as H, agentTurnUsageSchema as I, hasAgentTurnUsage as L, parseSessionSource as M, addAgentTurnUsage as N, recordGoogleSignIn as O, agentTurnCostUsd as P, resolveRootConversationId as R, startLocationThread as S, deleteProviderIdentityForUser as T, requireSlackDestination as V, withConversationEventLock as _, readIdentityById as a, withConversationMutationLock as b, updateViewerDisplayName as c, getConversationEventStore as d, getConversationMessageSearchStore as f, createSqlConversationEventStore as g, getSqlExecutor as h, readActorIdentity as i, bindProviderConversation as j, saveUserTimezone as k, closeDb as l, getDb as m, findUserByEmailFromSql as n, resolveViewerUser as o, getConversationStore as p, listAdminUsersFromSql as r, setUserAdminFromSql as s, findUserByEmail as t, db_exports as u, loadConversationSlackTenantIds as v, deleteProviderIdentityForSlackUser as w, locationFromRow as x, createSqlStore as y, createSlackDestination as z };
|