@sentry/junior 0.266.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.
Files changed (87) hide show
  1. package/dist/{actor-tlxzqaRe.js → actor-CP9K2Idu.js} +9 -1
  2. package/dist/{adapter-eRFA_naf.js → adapter-04AcD2SO.js} +5 -7
  3. package/dist/{admin-tILpP51p.js → admin-DIU1QyG3.js} +1 -1
  4. package/dist/{agent-invocations-CxKldAeB.js → agent-invocations-C1RNOCs8.js} +2 -0
  5. package/dist/{agent-runner-BtYK7bht.js → agent-runner-CAYfFmU7.js} +2636 -601
  6. package/dist/api/schema.d.ts +2 -5454
  7. package/dist/api/schema.js +6 -5
  8. package/dist/api.d.ts +6 -1
  9. package/dist/api.js +255 -1208
  10. package/dist/{app-Csbi9dW7.d.ts → app-z6Uuyq3j.d.ts} +23 -4
  11. package/dist/app.d.ts +2 -2
  12. package/dist/app.js +1869 -378
  13. package/dist/{automation-BKpY9LPa.js → automation-CmeFBSEh.js} +42 -14
  14. package/dist/{briefs-DgfWMU7e.js → briefs-DQbV2jNr.js} +4 -4
  15. package/dist/{catalog-runtime-DAJjAbSx.js → catalog-runtime-BD9GSpc6.js} +1 -1
  16. package/dist/cli/chat.js +15 -15
  17. package/dist/cli/check.js +3 -3
  18. package/dist/cli/init.js +0 -1
  19. package/dist/cli/main.js +3 -3
  20. package/dist/cli/plugins.js +4 -4
  21. package/dist/cli/snapshot-create.js +4 -4
  22. package/dist/cli/upgrade.d.ts +1 -1
  23. package/dist/cli/upgrade.js +3 -3
  24. package/dist/{client-B0YZfxNy.js → client-C1yDYjoS.js} +2 -2
  25. package/dist/{config-C0UwYqDK.js → config-DrTeF80T.js} +32 -10
  26. package/dist/{connections-Bwu3VORi.js → connections-D46f8vvi.js} +12 -12
  27. package/dist/{conversation-DF4rUcjb.js → conversation-DSo310Ps.js} +8 -1
  28. package/dist/{conversation-privacy-CY7JVjxn.js → conversation-privacy-CxlOCiUo.js} +1 -1
  29. package/dist/{credential-sync-VGAMUTGp.js → credential-sync-sm9fegLY.js} +29 -34
  30. package/dist/{credentialed-enF5Bf3y.js → credentialed-lukuD-cc.js} +2933 -1026
  31. package/dist/db-BU4LQD8s.d.ts +6 -0
  32. package/dist/{executor-TnWbvL09.js → executor-4vhvsMZJ.js} +83 -6
  33. package/dist/instrumentation.js +6 -2
  34. package/dist/{assistant-reply-UyzAfZQo.js → interruption-marker-CkncDT8d.js} +8 -2
  35. package/dist/{job-queue-DBpHmKnd.js → job-queue-In9QKz-I.js} +128 -3
  36. package/dist/{web-input-B-bMjD1V.js → list-BkgnXEEB.js} +1611 -817
  37. package/dist/{logging-Ce0mXZ8J.js → logging-DLSpkSSr.js} +11 -3
  38. package/dist/{message-VZ3DFpGb.js → message-BObyg59s.js} +4 -4
  39. package/dist/nitro.d.ts +1 -1
  40. package/dist/nitro.js +3 -3
  41. package/dist/{oauth-callback-server-CpqWLjVY.js → oauth-callback-server-B-WbSdoH.js} +2 -2
  42. package/dist/{prompt-BcCGlmg2.js → prompt-BW9jFsqZ.js} +1 -1
  43. package/dist/{registry-1BEIPdbT.js → registry-BgecKva0.js} +2 -2
  44. package/dist/{web-message-id-CJSUiksE.js → reporting-window-DVCD_10C.js} +1 -10
  45. package/dist/{resolve-BSHHkEGE.js → resolve-Cpa4Bu1O.js} +3 -3
  46. package/dist/{result-CwOpzqdh.js → result-D3TSmZZ8.js} +9 -9
  47. package/dist/{runner-CEaX04kz.js → runner-DS5OKhEp.js} +11 -11
  48. package/dist/{sandbox-egress-signals-BwtGHwqa.js → sandbox-egress-signals-CnDjY5rx.js} +1 -1
  49. package/dist/{schema-RsaBHxRH.js → schema-0050HFnB.js} +82 -5
  50. package/dist/schema-ZngqcOWM.d.ts +5813 -0
  51. package/dist/{service-account-6wC76eBZ.js → service-account-CKV2WTY7.js} +3 -3
  52. package/dist/{service-account-Dg4lIbHm.js → service-account-DGjnDw9y.js} +3 -3
  53. package/dist/{session-stop-tZOw9AJD.js → session-stop-Dam1EI7B.js} +527 -134
  54. package/dist/{skills-DzyGN7wd.js → skills-CfAnfImD.js} +2 -2
  55. package/dist/{spawn-6rokq7l_.js → spawn-cmq9p4Ly.js} +2 -2
  56. package/dist/{store-DcKkzrdt.js → store-C5PN02QO.js} +4 -4
  57. package/dist/{store-CG0VJyye.d.ts → store-xMuuXRE0.d.ts} +23 -9
  58. package/dist/store-zPEoJPBB.js +295 -0
  59. package/dist/{task-queue-Bg4RS2Gy.js → task-queue-_mf28dSu.js} +10 -5
  60. package/dist/{task-runner-8N5LIkSg.js → task-runner-DMI2prDO.js} +25 -14
  61. package/dist/{tasks-DDT-J3Rf.js → tasks-SB9z-VTU.js} +1551 -54
  62. package/dist/{thread-state-cprEaxgl.js → thread-state-BbbPh0Sn.js} +8 -18
  63. package/dist/{turn-failure-response-C8sMdsdX.js → turn-failure-response-BKKmnMB5.js} +11 -16
  64. package/dist/{turn-lifecycle-DaBVoz7h.js → turn-lifecycle-oP0kVeGz.js} +1 -1
  65. package/dist/{validation-C2lllinq.js → validation--JsAGLwc.js} +1 -1
  66. package/dist/{version-oaLfxxnf.js → version-jHwJp4hC.js} +1 -1
  67. package/dist/version.js +1 -1
  68. package/dist/{viewer-BpE6Z3qf.js → viewer-CpXTGlep.js} +329 -230
  69. package/dist/web-message-id-DlHNANtd.js +132 -0
  70. package/dist/{work-VX1SHWha.js → work-3N-GHY9m.js} +10 -10
  71. package/dist/{worker-hook-y_Y.js → worker-CCdbcItd.js} +30 -19
  72. package/migrations/0064_any_resource_event_triggers.sql +2 -0
  73. package/migrations/0065_user_customization.sql +1 -0
  74. package/migrations/0066_review_items.sql +53 -0
  75. package/migrations/0067_review_item_dedupe_tenant.sql +2 -0
  76. package/migrations/0068_review_item_slack_cards.sql +10 -0
  77. package/migrations/meta/0064_snapshot.json +3505 -0
  78. package/migrations/meta/0065_snapshot.json +3511 -0
  79. package/migrations/meta/0066_snapshot.json +4099 -0
  80. package/migrations/meta/0067_snapshot.json +3921 -0
  81. package/migrations/meta/0068_snapshot.json +4176 -0
  82. package/migrations/meta/_journal.json +36 -1
  83. package/package.json +19 -4
  84. package/dist/db-BnRqQ7G5.d.ts +0 -5
  85. package/dist/images-BKQqSi5W.js +0 -64
  86. package/dist/store-FALy-JQb.js +0 -1424
  87. package/dist/turn-session-routing-a9CHX-w6.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-C0UwYqDK.js";
3
- import { I as GOOGLE_IDENTITY_PROVIDER, R as normalizeIdentityEmail } from "./logging-Ce0mXZ8J.js";
4
- import { d as parseSlackTeamId, o as parseActorUserId, u as parseSlackChannelReferenceId } from "./actor-tlxzqaRe.js";
5
- import { c as juniorIdentities, d as juniorDestinations, l as juniorUsers, o as conversationReadColumns, s as juniorConversations } from "./agent-invocations-CxKldAeB.js";
6
- import { _ as juniorConversationAnnotations, d as juniorConversationBindings, h as juniorConversationEvents, m as juniorConversationMetrics, p as CONVERSATION_METRICS, t as createJuniorSqlExecutor, u as juniorConversationParticipants } from "./executor-TnWbvL09.js";
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,35 +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
- /** Build a durable identity observation from a stored conversation actor. */
453
- function identityFromActor(actor) {
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
- kind: "user",
456
- provider: "slack",
457
- providerTenantId: actor.teamId,
458
- providerSubjectId: actor.slackUserId,
459
- ...actor.fullName ? { displayName: actor.fullName } : void 0,
460
- ...actor.slackUserName ? { handle: actor.slackUserName } : void 0,
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
- const email = actor?.email?.trim().toLowerCase();
468
- if (!email) return;
567
+ if (!actor?.email) return;
469
568
  return {
470
- kind: "user",
471
- provider: "junior",
472
- providerSubjectId: email,
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
- /** Build a system identity when a conversation has no user actor. */
575
+ /**
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.
581
+ */
480
582
  function systemIdentityFromSource(source) {
481
583
  if (source === "scheduler") return {
482
584
  kind: "system",
@@ -497,9 +599,15 @@ function systemIdentityFromSource(source) {
497
599
  displayName: "Event"
498
600
  };
499
601
  }
500
- /** Prefer the user actor identity, else a source-derived system identity. */
501
- function actorIdentityForConversation(conversation) {
502
- return identityFromActor(conversation.actor) ?? systemIdentityFromSource(conversation.source);
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;
503
611
  }
504
612
  /**
505
613
  * Reconstruct a stored actor with the linked user name and identity-scoped
@@ -771,6 +879,9 @@ var SqlStore = class {
771
879
  if (!row) return;
772
880
  return conversationFromRow(row);
773
881
  }
882
+ async getRunMetrics(args) {
883
+ return await readConversationRunMetrics(this.executor, args);
884
+ }
774
885
  async recordActivity(args) {
775
886
  const nowMs = args.nowMs ?? now();
776
887
  const activityAtMs = args.activityAtMs ?? nowMs;
@@ -815,8 +926,15 @@ var SqlStore = class {
815
926
  const existing = existingRow ? conversationFromRow(existingRow) : void 0;
816
927
  if (!existing && !args.destination) return;
817
928
  const incomingExecutionAt = args.execution.updatedAtMs ?? args.updatedAtMs;
818
- const incomingIsFresh = incomingExecutionAt >= (existing?.execution.updatedAtMs ?? existing?.updatedAtMs ?? 0);
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;
819
935
  const execution = incomingIsFresh ? args.execution : existing?.execution ?? args.execution;
936
+ const actor = mergeActor(existing?.actor, args.actor);
937
+ const source = existing?.source ?? args.source;
820
938
  await this.upsertConversation({ conversation: {
821
939
  schemaVersion: 1,
822
940
  conversationId: args.conversationId,
@@ -827,8 +945,8 @@ var SqlStore = class {
827
945
  ...existing?.location ? { location: existing.location } : void 0,
828
946
  ...args.channelName ? { channelName: args.channelName } : void 0,
829
947
  ...args.destination ? { destination: args.destination } : void 0,
830
- ...args.actor ? { actor: args.actor } : void 0,
831
- ...args.source ? { source: args.source } : void 0,
948
+ ...actor ? { actor } : void 0,
949
+ ...source ? { source } : void 0,
832
950
  ...args.title ? { title: args.title } : void 0,
833
951
  ...args.visibility ? { visibility: args.visibility } : void 0,
834
952
  execution
@@ -913,8 +1031,7 @@ var SqlStore = class {
913
1031
  location: conversation.location,
914
1032
  sessionSource: conversation.sessionSource
915
1033
  });
916
- const actorIdentityObservation = actorIdentityForConversation(conversation);
917
- const actorIdentity = actorIdentityObservation ? await upsertIdentity(this.executor, actorIdentityObservation, conversation.updatedAtMs) : void 0;
1034
+ const actorIdentityId = await resolveConversationActorIdentityId(this.executor, conversation);
918
1035
  const rootConversationId = conversation.parentConversationId ? sql`(
919
1036
  select parent.root_conversation_id
920
1037
  from junior_conversations parent
@@ -928,7 +1045,7 @@ var SqlStore = class {
928
1045
  location: location ?? null,
929
1046
  destinationId: destinationId ?? null,
930
1047
  destination: null,
931
- actorIdentityId: actorIdentity?.id ?? null,
1048
+ actorIdentityId: actorIdentityId ?? null,
932
1049
  creatorIdentityId: null,
933
1050
  credentialSubjectIdentityId: null,
934
1051
  actor: null,
@@ -1050,7 +1167,6 @@ async function ensureConversationRow(executor, conversationId, atMs, options = {
1050
1167
  });
1051
1168
  }
1052
1169
  // src/chat/conversations/sql/event-actor.ts
1053
- const SLACK_USER_ID_PATTERN = /^[UW][A-Z0-9]{5,}$/;
1054
1170
  function isRecord(value) {
1055
1171
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
1056
1172
  }
@@ -1119,36 +1235,28 @@ async function resolveEventActorIdentityId(executor, args) {
1119
1235
  if (author.isBot === true) return;
1120
1236
  const userId = parseActorUserId(author.userId);
1121
1237
  if (!userId) return;
1122
- if (SLACK_USER_ID_PATTERN.test(userId)) {
1238
+ if (isSlackUserId(userId)) {
1123
1239
  const tenantId = await loadConversationSlackTenantId(executor, args.conversationId);
1124
- const observation = {
1125
- kind: "user",
1126
- provider: "slack",
1127
- providerSubjectId: userId,
1128
- ...tenantId ? { providerTenantId: tenantId } : void 0,
1129
- ...author.fullName ? { displayName: author.fullName } : void 0,
1130
- ...author.userName ? { handle: author.userName } : void 0,
1131
- ...author.email ? {
1132
- email: author.email,
1133
- emailVerified: true
1134
- } : void 0
1135
- };
1136
- if (tenantId) return (await upsertIdentity(executor, observation, args.nowMs)).id;
1137
- return await findIdentityIdByProviderSubject(executor, {
1240
+ if (!tenantId) return await findIdentityIdByProviderSubject(executor, {
1138
1241
  provider: "slack",
1139
1242
  providerSubjectId: userId
1140
- }) ?? void 0;
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);
1141
1252
  }
1142
- const email = typeof author.email === "string" && author.email.includes("@") ? author.email.trim().toLowerCase() : userId.includes("@") ? userId.trim().toLowerCase() : void 0;
1143
- if (email) return (await upsertIdentity(executor, {
1144
- kind: "user",
1145
- provider: "junior",
1146
- 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,
1147
1257
  email,
1148
- emailVerified: true,
1149
- ...author.fullName ? { displayName: author.fullName } : void 0,
1150
- metadata: { platform: "web" }
1151
- }, args.nowMs)).id;
1258
+ ...author.fullName ? { fullName: author.fullName } : void 0
1259
+ }, args.nowMs);
1152
1260
  if (userId.startsWith("dashboard:")) return findJuniorIdentityIdByDashboardAuthorId(executor, userId);
1153
1261
  return findJuniorIdentityIdByEmail(executor, userId);
1154
1262
  }
@@ -1630,17 +1738,8 @@ async function listAdminUsersFromSql(db) {
1630
1738
  }
1631
1739
  /** Resolve the stored identity and linked user for one runtime actor. */
1632
1740
  async function readActorIdentityFromSql(db, actor) {
1633
- if (actor.platform === "system") return void 0;
1634
- const providerTenantId = actor.platform === "slack" ? actor.teamId : "";
1635
- const row = (await db.select({
1636
- identity: juniorIdentities,
1637
- user: juniorUsers
1638
- }).from(juniorIdentities).leftJoin(juniorUsers, eq(juniorUsers.id, juniorIdentities.userId)).where(and(eq(juniorIdentities.kind, "user"), eq(juniorIdentities.provider, actor.platform), eq(juniorIdentities.providerTenantId, providerTenantId), eq(juniorIdentities.providerSubjectId, actor.userId))).limit(1))[0];
1639
- if (!row) return void 0;
1640
- return {
1641
- identity: identityFromRow(row.identity),
1642
- ...row.user ? { user: await readUserById(db, row.user) } : void 0
1643
- };
1741
+ const identityId = await findActorIdentityId(db, actor);
1742
+ return identityId ? await readIdentityByIdFromSql(db, identityId) : void 0;
1644
1743
  }
1645
1744
  /** Resolve the stored identity and linked user for one runtime actor. */
1646
1745
  async function readActorIdentity(actor) {
@@ -1662,4 +1761,4 @@ async function readIdentityByIdFromSql(db, identityId) {
1662
1761
  async function readIdentityById(identityId) {
1663
1762
  return await readIdentityByIdFromSql(getDb(), identityId);
1664
1763
  }
1665
- export { deleteProviderIdentityForSlackUser as A, requireSlackDestination as B, parseSessionSource as C, agentTurnUsageSchema as D, agentTurnTotalTokens as E, saveUserTimezone as F, upsertIdentity as I, upsertLinkedIdentity as L, findUserByVerifiedEmails as M, readUserTimezone as N, hasAgentTurnUsage as O, recordGoogleSignIn as P, createSlackDestination as R, bindProviderConversation as S, agentTurnCostUsd as T, sameDestination as V, createSqlStore as _, resolveViewerUser as a, startLocationThread as b, db_exports as c, getConversationStore as d, getDb as f, loadConversationSlackTenantIds as g, withConversationEventLock as h, readIdentityById as i, deleteProviderIdentityForUser as j, resolveRootConversationId as k, getConversationEventStore as l, createSqlConversationEventStore as m, listAdminUsersFromSql as n, setUserAdminFromSql as o, getSqlExecutor as p, readActorIdentity as r, updateViewerDisplayName as s, findUserByEmail as t, getConversationMessageSearchStore as u, withConversationMutationLock as v, addAgentTurnUsage as w, identityFromActor as x, locationFromRow as y, parseDestination as z };
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 };