@sentry/junior 0.203.0 → 0.204.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 (174) hide show
  1. package/dist/agent-CMyTD4DD.js +17509 -0
  2. package/dist/agent-hooks-Bbcp9e33.js +4040 -0
  3. package/dist/agent-runner-DNb1A49M.js +678 -0
  4. package/dist/api/schema.d.ts +2728 -2639
  5. package/dist/api/schema.js +4 -169
  6. package/dist/api.d.ts +23 -17
  7. package/dist/api.js +3881 -5326
  8. package/dist/app-B1TOqBI8.d.ts +246 -0
  9. package/dist/app.d.ts +4 -520
  10. package/dist/app.js +9522 -11875
  11. package/dist/auth-pause-state-DosEalIG.js +168 -0
  12. package/dist/catalog-runtime-BReos-D4.js +7 -0
  13. package/dist/checkpoint-CNrPyRJN.js +2450 -0
  14. package/dist/cli/chat.d.ts +20 -0
  15. package/dist/cli/chat.js +229 -336
  16. package/dist/cli/check.d.ts +8 -0
  17. package/dist/cli/check.js +513 -806
  18. package/dist/cli/env.d.ts +13 -0
  19. package/dist/cli/env.js +63 -12
  20. package/dist/cli/init.d.ts +3 -0
  21. package/dist/cli/init.js +90 -159
  22. package/dist/cli/main.d.ts +6 -0
  23. package/dist/cli/main.js +43 -64
  24. package/dist/cli/plugins.d.ts +13 -0
  25. package/dist/cli/plugins.js +148 -227
  26. package/dist/cli/run.d.ts +16 -0
  27. package/dist/cli/run.js +52 -8
  28. package/dist/cli/snapshot-create.d.ts +4 -0
  29. package/dist/cli/snapshot-create.js +71 -125
  30. package/dist/cli/upgrade.d.ts +15 -0
  31. package/dist/cli/upgrade.js +232 -335
  32. package/dist/config-nGCW1OTG.js +941 -0
  33. package/dist/context-B45_WqVX.js +298 -0
  34. package/dist/conversation-privacy-B4voFRSm.js +182 -0
  35. package/dist/conversation-work-C6y3T5Hx.js +51 -0
  36. package/dist/credential-sync-kXr1hvO1.js +2660 -0
  37. package/dist/db-BeyXKJOI.d.ts +5 -0
  38. package/dist/destinations-BeBiJeEM.js +29 -0
  39. package/dist/execution-stats-DWfSihcH.js +373 -0
  40. package/dist/executor-DcMSlI5c.js +721 -0
  41. package/dist/experimental-CIXf7Uye.js +46 -0
  42. package/dist/history-ClE4toxe.d.ts +32 -0
  43. package/dist/history-CqTuSAdI.js +441 -0
  44. package/dist/instrumentation.d.ts +3 -3
  45. package/dist/instrumentation.js +130 -176
  46. package/dist/job-queue-Drn_LXlM.js +63 -0
  47. package/dist/logging-BzAk1S_s.js +1210 -0
  48. package/dist/model-profile-CZmVoGdX.js +49 -0
  49. package/dist/nitro.d.ts +31 -36
  50. package/dist/nitro.js +275 -456
  51. package/dist/oauth-callback-server-JiftokvA.js +130 -0
  52. package/dist/oauth-relay-CdCnu80W.js +62 -0
  53. package/dist/package-discovery-7a9YqLhE.js +455 -0
  54. package/dist/pending-auth-CWmSdZVg.js +185 -0
  55. package/dist/plugin-module-BKGOXca2.js +81 -0
  56. package/dist/plugins-BI9A1vKA.d.ts +95 -0
  57. package/dist/plugins-egKWjgue.js +99 -0
  58. package/dist/private-trace-result-BLvBjy_e.js +16 -0
  59. package/dist/profile-CrT5nXbw.js +861 -0
  60. package/dist/registry-DH1xUo2N.js +1419 -0
  61. package/dist/reporting-schema-DosTN__Q.js +105 -0
  62. package/dist/resolve-CZHnfxaS.js +546 -0
  63. package/dist/rolldown-runtime-B4FMCO8f.js +28 -0
  64. package/dist/runner-CZV2sC46.js +392 -0
  65. package/dist/sandbox-egress-signals-bHZfmhbd.js +46 -0
  66. package/dist/schema-Rn8-XEaN.js +1140 -0
  67. package/dist/sentry-CD3SdJl-.js +26 -0
  68. package/dist/skills-CIcDQSgM.js +316 -0
  69. package/dist/spawn-DdkUFRmq.js +29 -0
  70. package/dist/stats-DTUbAb88.js +2634 -0
  71. package/dist/store-C5qxF2ac.d.ts +208 -0
  72. package/dist/task-queue-CJIR4RF7.js +136 -0
  73. package/dist/task-runner-D-O3A-Cp.js +639 -0
  74. package/dist/thread-state-CRc9jTJS.js +431 -0
  75. package/dist/turn-execution-BkinIdJF.js +47 -0
  76. package/dist/turn-lifecycle-DQV19VTW.js +54 -0
  77. package/dist/usage-D3EbSO7w.js +296 -0
  78. package/dist/usage-schema-CKaDkH_j.js +20 -0
  79. package/dist/validation-C2CR-OX3.js +40 -0
  80. package/dist/vercel-queue-DIkVcfK4.js +167 -0
  81. package/dist/vercel.d.ts +6 -6
  82. package/dist/vercel.js +14 -6
  83. package/dist/version-CnXZ614E.d.ts +5 -0
  84. package/dist/version-DxcWdoKa.js +8 -0
  85. package/dist/version.d.ts +2 -4
  86. package/dist/version.js +2 -6
  87. package/dist/web-authorization-RMBxAR_t.js +76 -0
  88. package/dist/web-input-3EPfpf55.js +494 -0
  89. package/dist/work-fGofI7Op.js +509 -0
  90. package/dist/worker-CsOLq-mR.js +625 -0
  91. package/package.json +8 -8
  92. package/dist/agent-hooks-GB2VPTNA.js +0 -51
  93. package/dist/catalog-runtime-UBLIWD3O.js +0 -14
  94. package/dist/chunk-2LYHWMR4.js +0 -46
  95. package/dist/chunk-352OWAZH.js +0 -320
  96. package/dist/chunk-3Y47VMHV.js +0 -6
  97. package/dist/chunk-3YJSKOWF.js +0 -164
  98. package/dist/chunk-4KSSKTQ5.js +0 -229
  99. package/dist/chunk-4UO6FK4G.js +0 -64
  100. package/dist/chunk-5AHX53NQ.js +0 -717
  101. package/dist/chunk-5J3E5FWA.js +0 -700
  102. package/dist/chunk-5PDAG6O3.js +0 -206
  103. package/dist/chunk-6Y5B5PEX.js +0 -80
  104. package/dist/chunk-7GWQ5S5R.js +0 -2086
  105. package/dist/chunk-7H2VZTWN.js +0 -103
  106. package/dist/chunk-7NL7T6VU.js +0 -406
  107. package/dist/chunk-A5L27LE4.js +0 -387
  108. package/dist/chunk-ADIAWL34.js +0 -81
  109. package/dist/chunk-ASTEMBKJ.js +0 -519
  110. package/dist/chunk-CEMMLV5L.js +0 -98
  111. package/dist/chunk-CM5HNV2W.js +0 -131
  112. package/dist/chunk-CRTRBBRI.js +0 -105
  113. package/dist/chunk-DA2KGZZI.js +0 -13
  114. package/dist/chunk-DIB4GX3G.js +0 -8
  115. package/dist/chunk-DKIJ2RP5.js +0 -68
  116. package/dist/chunk-DWPN6SCH.js +0 -172
  117. package/dist/chunk-EDKUFGPL.js +0 -64
  118. package/dist/chunk-ENY6SKIU.js +0 -1228
  119. package/dist/chunk-F4MGCZOX.js +0 -2943
  120. package/dist/chunk-FA6POGLH.js +0 -70
  121. package/dist/chunk-FSUR7GTG.js +0 -20475
  122. package/dist/chunk-GKEOHJL5.js +0 -1856
  123. package/dist/chunk-GMCB6W5Y.js +0 -333
  124. package/dist/chunk-IE2VPG7O.js +0 -1135
  125. package/dist/chunk-IZ5B5IHQ.js +0 -3656
  126. package/dist/chunk-JAL3CH4G.js +0 -27
  127. package/dist/chunk-KIIEUXD3.js +0 -1764
  128. package/dist/chunk-KXU4NIL7.js +0 -692
  129. package/dist/chunk-MTM5IFCY.js +0 -1190
  130. package/dist/chunk-N7TMSOZH.js +0 -235
  131. package/dist/chunk-NCEBK6PH.js +0 -36
  132. package/dist/chunk-NHJU2ZAL.js +0 -56
  133. package/dist/chunk-P6KTRNVC.js +0 -321
  134. package/dist/chunk-PDO5BLNM.js +0 -22
  135. package/dist/chunk-PDRNLLFT.js +0 -3295
  136. package/dist/chunk-PEQXYSSE.js +0 -45
  137. package/dist/chunk-PKEX2AQX.js +0 -198
  138. package/dist/chunk-PSJCGIGO.js +0 -1163
  139. package/dist/chunk-PZUSUL55.js +0 -506
  140. package/dist/chunk-R45M4TUS.js +0 -37
  141. package/dist/chunk-RC745GGZ.js +0 -122
  142. package/dist/chunk-SP3QKZXJ.js +0 -820
  143. package/dist/chunk-TXKUKMVO.js +0 -417
  144. package/dist/chunk-UE4GPWSD.js +0 -931
  145. package/dist/chunk-UIE3R5XU.js +0 -17
  146. package/dist/chunk-UXPG6ZIN.js +0 -84
  147. package/dist/chunk-VFUK3X5B.js +0 -50
  148. package/dist/chunk-VNMJWREK.js +0 -787
  149. package/dist/chunk-VZ7CSOX2.js +0 -706
  150. package/dist/chunk-WCNQJKFT.js +0 -10
  151. package/dist/chunk-WDZR3QQM.js +0 -135
  152. package/dist/chunk-WLYVJCHV.js +0 -1433
  153. package/dist/chunk-WS7NAFTM.js +0 -1520
  154. package/dist/chunk-X6GDDWQH.js +0 -60
  155. package/dist/chunk-XPDEYNQI.js +0 -102
  156. package/dist/chunk-XRW44VGM.js +0 -58
  157. package/dist/chunk-Y2CM7HXH.js +0 -111
  158. package/dist/chunk-Y7X25LFY.js +0 -15
  159. package/dist/conversation-work-VIOQ5ZF3.js +0 -54
  160. package/dist/db-NGDJV7YH.js +0 -26
  161. package/dist/discovery-DWVDM7UK.js +0 -44
  162. package/dist/experimental-P5FZM4CU.js +0 -12
  163. package/dist/oauth-callback-server-YFY7YEGK.js +0 -243
  164. package/dist/oauth-relay-5XPVRPYB.js +0 -8
  165. package/dist/plugins-YTYJMMJF.js +0 -14
  166. package/dist/runner-ORTNSB2Q.js +0 -522
  167. package/dist/sandbox-egress-signals-FIL7EGPR.js +0 -73
  168. package/dist/sentry-MB3NL3IR.js +0 -42
  169. package/dist/skills-H376WQOH.js +0 -27
  170. package/dist/spawn-T43WHLOS.js +0 -42
  171. package/dist/task-runner-LBZWF32V.js +0 -36
  172. package/dist/validation-REJLRKI6.js +0 -17
  173. package/dist/work-3KJ3RE76.js +0 -51
  174. package/dist/worker-QFEBU72E.js +0 -24
@@ -1,700 +0,0 @@
1
- import {
2
- healthReportSchema
3
- } from "./chunk-RC745GGZ.js";
4
- import {
5
- parseSlackThreadId
6
- } from "./chunk-XPDEYNQI.js";
7
- import {
8
- appendAndEnqueueExclusiveInboundMessage,
9
- appendAndEnqueueInboundMessage
10
- } from "./chunk-KIIEUXD3.js";
11
- import {
12
- buildDeterministicTurnId
13
- } from "./chunk-DA2KGZZI.js";
14
- import {
15
- normalizeSlackConversationId
16
- } from "./chunk-IZ5B5IHQ.js";
17
- import {
18
- getConversationStore,
19
- getDb
20
- } from "./chunk-GKEOHJL5.js";
21
- import {
22
- juniorConversationParticipants,
23
- juniorConversations,
24
- juniorIdentities,
25
- juniorUsers
26
- } from "./chunk-IE2VPG7O.js";
27
- import {
28
- juniorDestinations
29
- } from "./chunk-VFUK3X5B.js";
30
- import {
31
- getSlackBotToken
32
- } from "./chunk-ENY6SKIU.js";
33
- import {
34
- canExposeConversationPayload
35
- } from "./chunk-PKEX2AQX.js";
36
- import {
37
- logWarn
38
- } from "./chunk-WS7NAFTM.js";
39
-
40
- // src/handlers/health.ts
41
- function readHealthReport() {
42
- return healthReportSchema.parse({
43
- status: "ok",
44
- service: "junior",
45
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
46
- });
47
- }
48
- function GET() {
49
- return Response.json(readHealthReport());
50
- }
51
-
52
- // src/chat/attachments/vercel.ts
53
- import { del, get, put } from "@vercel/blob";
54
- function createVercelAttachmentStorage() {
55
- return {
56
- provider: "vercel-blob",
57
- async put(input) {
58
- await put(input.key, input.body, {
59
- access: "private",
60
- addRandomSuffix: false,
61
- allowOverwrite: true,
62
- contentType: input.contentType
63
- });
64
- },
65
- async get(key) {
66
- const result = await get(key, { access: "private", useCache: false });
67
- return result?.statusCode === 200 ? result.stream : null;
68
- },
69
- async delete(keys) {
70
- if (keys.length === 0) return;
71
- await del(keys);
72
- }
73
- };
74
- }
75
-
76
- // src/api/conversations/access.ts
77
- import { eq as eq2, inArray as inArray2 } from "drizzle-orm";
78
- import { alias } from "drizzle-orm/pg-core";
79
-
80
- // src/api/conversations/membership.ts
81
- import {
82
- and,
83
- eq,
84
- exists,
85
- inArray,
86
- isNotNull,
87
- notExists,
88
- or
89
- } from "drizzle-orm";
90
- function conversationHasParticipantUser(userId) {
91
- const participant = getDb().select({
92
- rootConversationId: juniorConversationParticipants.rootConversationId
93
- }).from(juniorConversationParticipants).where(
94
- and(
95
- eq(
96
- juniorConversationParticipants.rootConversationId,
97
- juniorConversations.conversationId
98
- ),
99
- eq(juniorConversationParticipants.userId, userId)
100
- )
101
- );
102
- return exists(participant);
103
- }
104
- function conversationHasParticipantEmail(email) {
105
- const participant = getDb().select({
106
- rootConversationId: juniorConversationParticipants.rootConversationId
107
- }).from(juniorConversationParticipants).innerJoin(
108
- juniorUsers,
109
- eq(juniorUsers.id, juniorConversationParticipants.userId)
110
- ).where(
111
- and(
112
- eq(
113
- juniorConversationParticipants.rootConversationId,
114
- juniorConversations.conversationId
115
- ),
116
- eq(juniorUsers.primaryEmailNormalized, email)
117
- )
118
- );
119
- return exists(participant);
120
- }
121
- function conversationArchivedForUser(userId) {
122
- const archive = getDb().select({
123
- rootConversationId: juniorConversationParticipants.rootConversationId
124
- }).from(juniorConversationParticipants).where(
125
- and(
126
- eq(
127
- juniorConversationParticipants.rootConversationId,
128
- juniorConversations.conversationId
129
- ),
130
- eq(juniorConversationParticipants.userId, userId),
131
- isNotNull(juniorConversationParticipants.archivedAt)
132
- )
133
- );
134
- return exists(archive);
135
- }
136
- function conversationNotArchivedForUser(userId) {
137
- const archive = getDb().select({
138
- rootConversationId: juniorConversationParticipants.rootConversationId
139
- }).from(juniorConversationParticipants).where(
140
- and(
141
- eq(
142
- juniorConversationParticipants.rootConversationId,
143
- juniorConversations.conversationId
144
- ),
145
- eq(juniorConversationParticipants.userId, userId),
146
- isNotNull(juniorConversationParticipants.archivedAt)
147
- )
148
- );
149
- return notExists(archive);
150
- }
151
- function conversationArchivedForEmail(email) {
152
- const archive = getDb().select({
153
- rootConversationId: juniorConversationParticipants.rootConversationId
154
- }).from(juniorConversationParticipants).innerJoin(
155
- juniorUsers,
156
- eq(juniorUsers.id, juniorConversationParticipants.userId)
157
- ).where(
158
- and(
159
- eq(
160
- juniorConversationParticipants.rootConversationId,
161
- juniorConversations.conversationId
162
- ),
163
- eq(juniorUsers.primaryEmailNormalized, email),
164
- isNotNull(juniorConversationParticipants.archivedAt)
165
- )
166
- );
167
- return exists(archive);
168
- }
169
- function conversationNotArchivedForEmail(email) {
170
- const archive = getDb().select({
171
- rootConversationId: juniorConversationParticipants.rootConversationId
172
- }).from(juniorConversationParticipants).innerJoin(
173
- juniorUsers,
174
- eq(juniorUsers.id, juniorConversationParticipants.userId)
175
- ).where(
176
- and(
177
- eq(
178
- juniorConversationParticipants.rootConversationId,
179
- juniorConversations.conversationId
180
- ),
181
- eq(juniorUsers.primaryEmailNormalized, email),
182
- isNotNull(juniorConversationParticipants.archivedAt)
183
- )
184
- );
185
- return notExists(archive);
186
- }
187
- function viewerConversationMembership(args) {
188
- if (args.actorMatch && args.participantMatch) {
189
- return or(args.actorMatch, args.participantMatch);
190
- }
191
- return args.actorMatch ?? args.participantMatch;
192
- }
193
- async function conversationArchiveTimes(db, conversationIds, subject) {
194
- if (!subject || conversationIds.length === 0) return /* @__PURE__ */ new Map();
195
- const query = db.select({
196
- archivedAt: juniorConversationParticipants.archivedAt,
197
- rootConversationId: juniorConversationParticipants.rootConversationId
198
- }).from(juniorConversationParticipants);
199
- const rows = "userId" in subject ? await query.where(
200
- and(
201
- eq(juniorConversationParticipants.userId, subject.userId),
202
- inArray(juniorConversationParticipants.rootConversationId, [
203
- ...conversationIds
204
- ]),
205
- isNotNull(juniorConversationParticipants.archivedAt)
206
- )
207
- ) : await query.innerJoin(
208
- juniorUsers,
209
- eq(juniorUsers.id, juniorConversationParticipants.userId)
210
- ).where(
211
- and(
212
- eq(juniorUsers.primaryEmailNormalized, subject.email),
213
- inArray(juniorConversationParticipants.rootConversationId, [
214
- ...conversationIds
215
- ]),
216
- isNotNull(juniorConversationParticipants.archivedAt)
217
- )
218
- );
219
- return new Map(
220
- rows.flatMap(
221
- (row) => row.archivedAt ? [[row.rootConversationId, row.archivedAt.getTime()]] : []
222
- )
223
- );
224
- }
225
- async function conversationIdsWithParticipantUser(db, conversationIds, userId) {
226
- if (conversationIds.length === 0) {
227
- return /* @__PURE__ */ new Set();
228
- }
229
- const rows = await db.select({
230
- rootConversationId: juniorConversationParticipants.rootConversationId
231
- }).from(juniorConversationParticipants).where(
232
- and(
233
- eq(juniorConversationParticipants.userId, userId),
234
- inArray(juniorConversationParticipants.rootConversationId, [
235
- ...conversationIds
236
- ])
237
- )
238
- );
239
- return new Set(rows.map((row) => row.rootConversationId));
240
- }
241
-
242
- // src/api/conversations/access.ts
243
- var rootConversation = alias(juniorConversations, "access_root_conversation");
244
- var rootDestination = alias(juniorDestinations, "access_root_destination");
245
- var rootIdentity = alias(juniorIdentities, "access_root_identity");
246
- async function readConversationAccessFromSql(db, conversationIds, viewer) {
247
- if (conversationIds.length === 0) return /* @__PURE__ */ new Map();
248
- const normalizedViewerEmail = viewer?.email.trim().toLowerCase() || void 0;
249
- const rows = await db.select({
250
- conversationId: juniorConversations.conversationId,
251
- parentConversationId: juniorConversations.parentConversationId,
252
- storedRootConversationId: juniorConversations.rootConversationId,
253
- rootConversationId: rootConversation.conversationId,
254
- rootParentConversationId: rootConversation.parentConversationId,
255
- rootRootConversationId: rootConversation.rootConversationId,
256
- visibility: rootDestination.visibility,
257
- rootEmailNormalized: rootIdentity.emailNormalized,
258
- rootEmailVerified: rootIdentity.emailVerified,
259
- rootUserId: rootIdentity.userId
260
- }).from(juniorConversations).leftJoin(
261
- rootConversation,
262
- eq2(
263
- rootConversation.conversationId,
264
- juniorConversations.rootConversationId
265
- )
266
- ).leftJoin(
267
- rootDestination,
268
- eq2(rootDestination.id, rootConversation.destinationId)
269
- ).leftJoin(
270
- rootIdentity,
271
- eq2(rootIdentity.id, rootConversation.actorIdentityId)
272
- ).where(inArray2(juniorConversations.conversationId, [...conversationIds]));
273
- const membershipConversationIds = /* @__PURE__ */ new Set();
274
- for (const row of rows) {
275
- membershipConversationIds.add(row.conversationId);
276
- if (row.storedRootConversationId) {
277
- membershipConversationIds.add(row.storedRootConversationId);
278
- }
279
- }
280
- const participantRootIds = viewer !== void 0 ? await conversationIdsWithParticipantUser(
281
- db,
282
- [...membershipConversationIds],
283
- viewer.id
284
- ) : /* @__PURE__ */ new Set();
285
- return new Map(
286
- rows.map((row) => {
287
- const hasValidRoot = row.rootConversationId !== null && row.rootConversationId === row.storedRootConversationId && row.rootRootConversationId === row.rootConversationId && row.rootParentConversationId === null && (row.parentConversationId !== null || row.storedRootConversationId === row.conversationId);
288
- const validRootConversationId = hasValidRoot ? row.rootConversationId ?? void 0 : void 0;
289
- const visibility = validRootConversationId === void 0 ? null : row.visibility;
290
- const isRootActor = validRootConversationId !== void 0 && viewer !== void 0 && (row.rootUserId === viewer.id || normalizedViewerEmail !== void 0 && row.rootEmailVerified === true && row.rootEmailNormalized === normalizedViewerEmail);
291
- const isMaterializedParticipant = participantRootIds.has(row.conversationId) || validRootConversationId !== void 0 && participantRootIds.has(validRootConversationId);
292
- const isParticipant = isRootActor || isMaterializedParticipant;
293
- const canViewPrivateContent = isParticipant || validRootConversationId !== void 0 && canExposeConversationPayload({
294
- visibility: visibility ?? void 0
295
- });
296
- return [
297
- row.conversationId,
298
- {
299
- canViewPrivateContent,
300
- isParticipant,
301
- visibility
302
- }
303
- ];
304
- })
305
- );
306
- }
307
-
308
- // src/chat/conversations/web-input.ts
309
- import { createHash } from "crypto";
310
- import { createWebSource } from "@sentry/junior-plugin-api";
311
-
312
- // src/chat/conversations/destination.ts
313
- import {
314
- localDestinationSchema
315
- } from "@sentry/junior-plugin-api";
316
- function requireLocalDestination(conversationId) {
317
- const parsed = localDestinationSchema.safeParse({
318
- platform: "local",
319
- conversationId
320
- });
321
- if (!parsed.success) {
322
- throw new Error(`Invalid local conversation id: ${conversationId}`);
323
- }
324
- return parsed.data;
325
- }
326
- function resolveConversationDestination(args) {
327
- return args.existing ?? requireLocalDestination(args.conversationId);
328
- }
329
-
330
- // src/chat/conversations/web-input.ts
331
- function normalizeEmail(email) {
332
- return email.trim().toLowerCase();
333
- }
334
- function stableHex(...parts) {
335
- return createHash("sha256").update(parts.join("\0")).digest("hex").slice(0, 24);
336
- }
337
- function createConversationId(args) {
338
- return `local:web:${stableHex(
339
- normalizeEmail(args.actorEmail),
340
- args.idempotencyKey
341
- )}`;
342
- }
343
- function webMessageId(args) {
344
- return `api-msg:${stableHex(args.conversationId, args.idempotencyKey)}`;
345
- }
346
- function conversationTurnIdForMessage(messageId) {
347
- return buildDeterministicTurnId(messageId);
348
- }
349
- function storedActorFromWeb(actor) {
350
- return {
351
- ...actor.email ? { email: normalizeEmail(actor.email) } : void 0,
352
- ...actor.fullName ? { fullName: actor.fullName } : void 0
353
- };
354
- }
355
- function webActorFromEmail(email, profile) {
356
- const normalized = normalizeEmail(email);
357
- return {
358
- platform: "web",
359
- userId: `dashboard:${stableHex(normalized)}`,
360
- email: normalized,
361
- ...profile?.fullName ? { fullName: profile.fullName } : void 0,
362
- ...profile?.userName ? { userName: profile.userName } : void 0
363
- };
364
- }
365
- function buildWebInboundMessage(args) {
366
- const text = args.message.trim();
367
- if (!text) {
368
- throw new Error("Web Message must not be empty");
369
- }
370
- if (!args.actor.email) {
371
- throw new Error("Web Actor requires a verified email");
372
- }
373
- const destination = resolveConversationDestination({
374
- conversationId: args.conversationId,
375
- existing: args.destination
376
- });
377
- const nowMs = args.nowMs ?? Date.now();
378
- return {
379
- conversationId: args.conversationId,
380
- createdAtMs: args.createdAtMs ?? nowMs,
381
- delivery: "defer",
382
- // TODO(dcramer): Remove InboundMessage.destination after workers read the
383
- // Conversation Location and no mailbox reader requires Destination.
384
- destination,
385
- inboundMessageId: args.messageId,
386
- input: {
387
- authorId: args.actor.userId,
388
- text,
389
- metadata: {
390
- authorEmail: normalizeEmail(args.actor.email),
391
- ...args.actor.fullName && { authorFullName: args.actor.fullName },
392
- authorUserId: args.actor.userId,
393
- ...args.actor.userName && { authorUserName: args.actor.userName },
394
- // TODO(dcramer): Remove api_turn after deployed mailbox readers use
395
- // Inbound message Source.kind to identify web input.
396
- kind: "api_turn",
397
- messageId: args.messageId
398
- }
399
- },
400
- receivedAtMs: nowMs,
401
- // TODO(dcramer): Replace this string after deployed mailbox readers and
402
- // writers use a complete web Source.
403
- source: "web"
404
- };
405
- }
406
- async function recordWebConversationActivity(args) {
407
- const store = args.conversationStore ?? getConversationStore();
408
- const existing = await store.get({ conversationId: args.conversationId });
409
- const destination = resolveConversationDestination({
410
- conversationId: args.conversationId,
411
- existing: existing?.destination
412
- });
413
- const isNewRoot = !existing;
414
- const visibility = args.rootVisibility === "private" ? "private" : "public";
415
- const source = isNewRoot ? createWebSource(args.conversationId, visibility) : void 0;
416
- await store.recordActivity({
417
- conversationId: args.conversationId,
418
- // TODO(dcramer): Remove the Conversation destination write after all
419
- // readers use its stored Location.
420
- destination,
421
- nowMs: args.nowMs,
422
- actor: storedActorFromWeb(args.actor),
423
- // A dashboard continuation does not replace the root Source.
424
- // TODO(dcramer): Remove the Conversation source and sessionSource writes
425
- // after every Turn stores Source and all resume readers use that Turn fact.
426
- ...isNewRoot ? { source: "web" } : void 0,
427
- ...source ? { sessionSource: source } : void 0,
428
- ...isNewRoot ? { visibility } : void 0
429
- });
430
- return destination;
431
- }
432
- async function createAndEnqueueConversation(input, options) {
433
- if (!input.actor.email) {
434
- throw new Error("Web Actor requires a verified email");
435
- }
436
- const conversationId = createConversationId({
437
- actorEmail: input.actor.email,
438
- idempotencyKey: input.idempotencyKey
439
- });
440
- return await appendAndEnqueueWebMessage(
441
- {
442
- actor: input.actor,
443
- conversationId,
444
- idempotencyKey: input.idempotencyKey,
445
- message: input.message,
446
- rootVisibility: input.visibility === "private" ? "private" : "public"
447
- },
448
- options
449
- );
450
- }
451
- async function appendAndEnqueueWebMessage(input, options) {
452
- const text = input.message.trim();
453
- if (!text) {
454
- throw new Error("Web Message must not be empty");
455
- }
456
- if (!input.actor.email) {
457
- throw new Error("Web Actor requires a verified email");
458
- }
459
- const nowMs = options.nowMs ?? Date.now();
460
- const messageId = webMessageId({
461
- conversationId: input.conversationId,
462
- idempotencyKey: input.idempotencyKey
463
- });
464
- const destination = await recordWebConversationActivity({
465
- actor: input.actor,
466
- conversationId: input.conversationId,
467
- conversationStore: options.conversationStore,
468
- nowMs,
469
- ...input.rootVisibility && { rootVisibility: input.rootVisibility }
470
- });
471
- const enqueue = options.exclusive ? appendAndEnqueueExclusiveInboundMessage : appendAndEnqueueInboundMessage;
472
- const result = await enqueue({
473
- message: buildWebInboundMessage({
474
- actor: input.actor,
475
- conversationId: input.conversationId,
476
- destination,
477
- message: text,
478
- messageId,
479
- nowMs
480
- }),
481
- conversationStore: options.conversationStore,
482
- nowMs,
483
- queue: options.queue,
484
- state: options.state
485
- });
486
- const status = result.status === "appended" ? "accepted" : result.status;
487
- return {
488
- conversationId: input.conversationId,
489
- messageId,
490
- status
491
- };
492
- }
493
-
494
- // src/chat/conversations/web-mailbox.ts
495
- import { z } from "zod";
496
- var legacyWebMailboxMetadataSchema = z.object({
497
- authorEmail: z.string().email(),
498
- authorFullName: z.string().min(1).optional(),
499
- authorUserId: z.string().min(1),
500
- authorUserName: z.string().min(1).optional(),
501
- kind: z.literal("api_turn"),
502
- messageId: z.string().min(1)
503
- }).strict();
504
-
505
- // src/chat/slack/user.ts
506
- import { z as z2 } from "zod";
507
- var slackUserInfoSchema = z2.object({
508
- ok: z2.literal(true),
509
- user: z2.object({
510
- name: z2.string().nullish(),
511
- profile: z2.object({
512
- email: z2.string().nullish(),
513
- real_name: z2.string().nullish()
514
- }).optional()
515
- })
516
- });
517
- var USER_CACHE_TTL_MS = 5 * 60 * 1e3;
518
- var userCache = /* @__PURE__ */ new Map();
519
- function userCacheKey(teamId, userId) {
520
- return `${teamId}:${userId}`;
521
- }
522
- function readFromCache(teamId, userId) {
523
- const hit = userCache.get(userCacheKey(teamId, userId));
524
- if (!hit) return null;
525
- if (hit.expiresAt < Date.now()) {
526
- userCache.delete(userCacheKey(teamId, userId));
527
- return null;
528
- }
529
- return hit.value;
530
- }
531
- function writeToCache(teamId, userId, value) {
532
- userCache.set(userCacheKey(teamId, userId), {
533
- value,
534
- expiresAt: Date.now() + USER_CACHE_TTL_MS
535
- });
536
- }
537
- async function lookupSlackUser(teamId, userId) {
538
- if (!teamId || !userId) {
539
- return null;
540
- }
541
- const cached = readFromCache(teamId, userId);
542
- if (cached) {
543
- return cached;
544
- }
545
- const token = getSlackBotToken();
546
- if (!token) {
547
- return null;
548
- }
549
- try {
550
- const response = await fetch(
551
- `https://slack.com/api/users.info?user=${encodeURIComponent(userId)}`,
552
- {
553
- headers: {
554
- authorization: `Bearer ${token}`
555
- }
556
- }
557
- );
558
- if (!response.ok) {
559
- logWarn("slack.user.lookup.failed", {
560
- "enduser.id": userId,
561
- "app.slack.team_id": teamId,
562
- "http.response.status_code": response.status
563
- });
564
- return null;
565
- }
566
- const parsed = slackUserInfoSchema.safeParse(await response.json());
567
- if (!parsed.success) {
568
- return null;
569
- }
570
- const payload = parsed.data;
571
- const userName = payload.user.name?.trim() || void 0;
572
- const fullName = payload.user.profile?.real_name?.trim() || void 0;
573
- const result = {
574
- userName,
575
- fullName,
576
- email: payload.user.profile?.email?.trim() || void 0
577
- };
578
- writeToCache(teamId, userId, result);
579
- return result;
580
- } catch (error) {
581
- logWarn("slack.user.lookup.failed", {
582
- "enduser.id": userId,
583
- "app.slack.team_id": teamId,
584
- "exception.message": error instanceof Error ? error.message : String(error)
585
- });
586
- return null;
587
- }
588
- }
589
-
590
- // src/chat/slack/conversation-context.ts
591
- function normalizeConversationName(type, channelName) {
592
- const trimmed = channelName?.trim();
593
- if (!trimmed) return void 0;
594
- if (type === "public_channel" || type === "private_channel" || type === "private_channel_or_group_dm") {
595
- return trimmed.startsWith("#") ? trimmed : `#${trimmed}`;
596
- }
597
- return trimmed;
598
- }
599
- function typeFromSlackChannelType(channelType) {
600
- if (channelType === "channel") return "public_channel";
601
- if (channelType === "group") return "private_channel";
602
- if (channelType === "mpim") return "group_dm";
603
- if (channelType === "im") return "direct_message";
604
- return void 0;
605
- }
606
- function typeFromChannelId(channelId, channelName) {
607
- const normalized = normalizeSlackConversationId(channelId);
608
- if (!normalized) return void 0;
609
- if (normalized.startsWith("C")) return "public_channel";
610
- if (normalized.startsWith("D")) return "direct_message";
611
- if (normalized.startsWith("G")) {
612
- return channelName?.trim().startsWith("mpdm-") ? "group_dm" : "private_channel_or_group_dm";
613
- }
614
- return void 0;
615
- }
616
- function toSlackEventChannelType(channelType) {
617
- if (channelType === "channel" || channelType === "group" || channelType === "mpim" || channelType === "im") {
618
- return channelType;
619
- }
620
- return void 0;
621
- }
622
- function conversationVisibilityFromSlackChannelType(channelType) {
623
- if (!channelType) return void 0;
624
- return channelType === "channel" ? "public" : "private";
625
- }
626
- function resolveSlackChannelTypeFromMessage(message) {
627
- const raw = message.raw;
628
- if (!raw || typeof raw !== "object") {
629
- return void 0;
630
- }
631
- const channelType = raw.channel_type;
632
- return typeof channelType === "string" ? toSlackEventChannelType(channelType.trim()) : void 0;
633
- }
634
- function resolveSlackConversationContext(input) {
635
- const type = typeFromSlackChannelType(input.channelType) ?? typeFromChannelId(input.channelId, input.channelName);
636
- if (!type) return void 0;
637
- const name = normalizeConversationName(type, input.channelName);
638
- const visibility = conversationVisibilityFromSlackChannelType(
639
- input.channelType
640
- );
641
- return {
642
- type,
643
- ...name ? { name } : void 0,
644
- ...visibility ? { visibility } : void 0
645
- };
646
- }
647
- function resolveSlackConversationContextFromThreadId(input) {
648
- const slackThread = parseSlackThreadId(input.threadId);
649
- const context = resolveSlackConversationContext({
650
- channelId: slackThread?.channelId,
651
- channelName: input.channelName
652
- });
653
- if (!context || !input.visibility) {
654
- return context;
655
- }
656
- return {
657
- ...context,
658
- type: input.visibility === "private" && context.type === "public_channel" ? "private_channel" : context.type,
659
- visibility: input.visibility
660
- };
661
- }
662
- function formatSlackConversationTypeLabel(type) {
663
- if (type === "public_channel") return "Public Channel";
664
- if (type === "private_channel") return "Private Channel";
665
- if (type === "group_dm") return "Group DM";
666
- if (type === "direct_message") return "Direct Message";
667
- return "Private Channel or Group DM";
668
- }
669
- function formatSlackConversationRedactedLabel(context) {
670
- if (!context) return void 0;
671
- return formatSlackConversationTypeLabel(context.type);
672
- }
673
-
674
- export {
675
- readHealthReport,
676
- GET,
677
- createVercelAttachmentStorage,
678
- legacyWebMailboxMetadataSchema,
679
- lookupSlackUser,
680
- conversationVisibilityFromSlackChannelType,
681
- resolveSlackChannelTypeFromMessage,
682
- resolveSlackConversationContext,
683
- resolveSlackConversationContextFromThreadId,
684
- formatSlackConversationRedactedLabel,
685
- resolveConversationDestination,
686
- conversationHasParticipantUser,
687
- conversationHasParticipantEmail,
688
- conversationArchivedForUser,
689
- conversationNotArchivedForUser,
690
- conversationArchivedForEmail,
691
- conversationNotArchivedForEmail,
692
- viewerConversationMembership,
693
- conversationArchiveTimes,
694
- readConversationAccessFromSql,
695
- conversationTurnIdForMessage,
696
- webActorFromEmail,
697
- recordWebConversationActivity,
698
- createAndEnqueueConversation,
699
- appendAndEnqueueWebMessage
700
- };