@sentry/junior 0.67.3 → 0.69.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 (66) hide show
  1. package/dist/app.js +1465 -814
  2. package/dist/build/virtual-config.d.ts +2 -2
  3. package/dist/chat/agent-dispatch/heartbeat.d.ts +2 -2
  4. package/dist/chat/agent-dispatch/store.d.ts +4 -1
  5. package/dist/chat/agent-dispatch/types.d.ts +2 -4
  6. package/dist/chat/agent-dispatch/validation.d.ts +3 -2
  7. package/dist/chat/credentials/context.d.ts +49 -24
  8. package/dist/chat/credentials/user-token-store.d.ts +6 -0
  9. package/dist/chat/destination.d.ts +12 -0
  10. package/dist/chat/ingress/message-router.d.ts +1 -1
  11. package/dist/chat/mcp/auth-store.d.ts +2 -0
  12. package/dist/chat/mcp/oauth.d.ts +2 -0
  13. package/dist/chat/oauth-flow.d.ts +7 -0
  14. package/dist/chat/plugins/agent-hooks.d.ts +9 -9
  15. package/dist/chat/plugins/auth/auth-token-placeholder.d.ts +2 -2
  16. package/dist/chat/plugins/auth/oauth-request.d.ts +3 -1
  17. package/dist/chat/plugins/credential-hooks.d.ts +34 -0
  18. package/dist/chat/plugins/logging.d.ts +1 -1
  19. package/dist/chat/plugins/state.d.ts +1 -1
  20. package/dist/chat/plugins/types.d.ts +19 -23
  21. package/dist/chat/respond.d.ts +2 -0
  22. package/dist/chat/runtime/reply-executor.d.ts +3 -1
  23. package/dist/chat/runtime/slack-runtime.d.ts +8 -3
  24. package/dist/chat/sandbox/egress-credentials.d.ts +33 -0
  25. package/dist/chat/sandbox/egress-schemas.d.ts +105 -0
  26. package/dist/chat/sandbox/egress-session.d.ts +17 -17
  27. package/dist/chat/sandbox/sandbox.d.ts +3 -0
  28. package/dist/chat/sandbox/session.d.ts +1 -0
  29. package/dist/chat/services/mcp-auth-orchestration.d.ts +2 -0
  30. package/dist/chat/services/pending-auth.d.ts +2 -0
  31. package/dist/chat/services/plugin-auth-orchestration.d.ts +2 -0
  32. package/dist/chat/services/provider-retry.d.ts +13 -4
  33. package/dist/chat/services/timeout-resume.d.ts +2 -0
  34. package/dist/chat/services/turn-session-record.d.ts +6 -0
  35. package/dist/chat/slack/attachment-fetchers.d.ts +11 -0
  36. package/dist/chat/slack/footer.d.ts +2 -7
  37. package/dist/chat/state/conversation.d.ts +1 -0
  38. package/dist/chat/state/turn-session.d.ts +4 -0
  39. package/dist/chat/task-execution/queue.d.ts +2 -0
  40. package/dist/chat/task-execution/store.d.ts +5 -0
  41. package/dist/chat/task-execution/vercel-callback.d.ts +4 -0
  42. package/dist/chat/task-execution/vercel-queue.d.ts +2 -0
  43. package/dist/chat/task-execution/worker.d.ts +4 -2
  44. package/dist/chat/tools/slack/context.d.ts +3 -0
  45. package/dist/chat/tools/types.d.ts +21 -2
  46. package/dist/chunk-76YMBKW7.js +326 -0
  47. package/dist/{chunk-PIVOJIUD.js → chunk-B5HKWWQB.js} +9 -5
  48. package/dist/chunk-BBXYXOJW.js +1858 -0
  49. package/dist/{chunk-V47RLIO2.js → chunk-GT67ZWZQ.js} +4 -4
  50. package/dist/{chunk-75UZ4JLC.js → chunk-IGLNC5H6.js} +21 -9
  51. package/dist/{chunk-EBVQXCD2.js → chunk-JS4HURDT.js} +362 -280
  52. package/dist/{chunk-UQQSW7QB.js → chunk-N3MORKTH.js} +74 -331
  53. package/dist/chunk-R62YWUNO.js +264 -0
  54. package/dist/{chunk-OIIXZOOC.js → chunk-UXG6TU2U.js} +311 -2015
  55. package/dist/cli/check.js +4 -4
  56. package/dist/cli/snapshot-warmup.js +5 -4
  57. package/dist/nitro.d.ts +1 -1
  58. package/dist/nitro.js +21 -19
  59. package/dist/plugins.d.ts +2 -2
  60. package/dist/reporting.d.ts +2 -2
  61. package/dist/reporting.js +13 -11
  62. package/package.json +6 -4
  63. package/dist/chat/plugins/auth/github-app-broker.d.ts +0 -4
  64. package/dist/chat/plugins/github-permissions.d.ts +0 -11
  65. package/dist/chat/queue/thread-message-dispatcher.d.ts +0 -33
  66. package/dist/chunk-KVZL5NZS.js +0 -519
@@ -0,0 +1,326 @@
1
+ import {
2
+ getSlackBotToken
3
+ } from "./chunk-JS4HURDT.js";
4
+ import {
5
+ logWarn
6
+ } from "./chunk-BBXYXOJW.js";
7
+
8
+ // src/chat/slack/client.ts
9
+ import { WebClient } from "@slack/web-api";
10
+ var SlackActionError = class extends Error {
11
+ code;
12
+ apiError;
13
+ needed;
14
+ provided;
15
+ statusCode;
16
+ requestId;
17
+ errorData;
18
+ retryAfterSeconds;
19
+ detail;
20
+ detailLine;
21
+ detailRule;
22
+ constructor(message, code, options = {}) {
23
+ super(message);
24
+ this.name = "SlackActionError";
25
+ this.code = code;
26
+ this.apiError = options.apiError;
27
+ this.needed = options.needed;
28
+ this.provided = options.provided;
29
+ this.statusCode = options.statusCode;
30
+ this.requestId = options.requestId;
31
+ this.errorData = options.errorData;
32
+ this.retryAfterSeconds = options.retryAfterSeconds;
33
+ this.detail = options.detail;
34
+ this.detailLine = options.detailLine;
35
+ this.detailRule = options.detailRule;
36
+ }
37
+ };
38
+ function serializeSlackErrorData(data) {
39
+ if (!data || typeof data !== "object") {
40
+ return void 0;
41
+ }
42
+ const filtered = Object.fromEntries(
43
+ Object.entries(data).filter(
44
+ ([key]) => key !== "error"
45
+ )
46
+ );
47
+ if (Object.keys(filtered).length === 0) {
48
+ return void 0;
49
+ }
50
+ try {
51
+ const serialized = JSON.stringify(filtered);
52
+ return serialized.length <= 600 ? serialized : `${serialized.slice(0, 597)}...`;
53
+ } catch {
54
+ return void 0;
55
+ }
56
+ }
57
+ function getHeaderString(headers, name) {
58
+ if (!headers || typeof headers !== "object") {
59
+ return void 0;
60
+ }
61
+ const key = name.toLowerCase();
62
+ const entries = headers;
63
+ for (const [entryKey, value] of Object.entries(entries)) {
64
+ if (entryKey.toLowerCase() !== key) continue;
65
+ if (typeof value === "string") return value;
66
+ if (Array.isArray(value)) {
67
+ const first = value.find((entry) => typeof entry === "string");
68
+ return typeof first === "string" ? first : void 0;
69
+ }
70
+ }
71
+ return void 0;
72
+ }
73
+ function parseSlackCanvasDetail(detail) {
74
+ if (typeof detail !== "string") {
75
+ return {};
76
+ }
77
+ const trimmed = detail.trim();
78
+ if (!trimmed) {
79
+ return {};
80
+ }
81
+ const parsed = {
82
+ detail: trimmed
83
+ };
84
+ const lineMatch = trimmed.match(/line\s+(\d+):/i);
85
+ if (lineMatch) {
86
+ const line = Number.parseInt(lineMatch[1] ?? "", 10);
87
+ if (Number.isFinite(line)) {
88
+ parsed.detailLine = line;
89
+ }
90
+ }
91
+ if (/unsupported heading depth/i.test(trimmed)) {
92
+ parsed.detailRule = "unsupported_heading_depth";
93
+ }
94
+ return parsed;
95
+ }
96
+ var client = null;
97
+ function normalizeSlackConversationId(channelId) {
98
+ if (!channelId) return void 0;
99
+ const trimmed = channelId.trim();
100
+ if (!trimmed) return void 0;
101
+ if (!trimmed.startsWith("slack:")) {
102
+ return trimmed;
103
+ }
104
+ const parts = trimmed.split(":");
105
+ return parts[1]?.trim() || void 0;
106
+ }
107
+ function getClient() {
108
+ if (client) return client;
109
+ const token = getSlackBotToken();
110
+ if (!token) {
111
+ throw new SlackActionError(
112
+ "SLACK_BOT_TOKEN (or SLACK_BOT_USER_TOKEN) is required for Slack canvas/list actions in this service",
113
+ "missing_token"
114
+ );
115
+ }
116
+ client = new WebClient(token);
117
+ return client;
118
+ }
119
+ function mapSlackError(error) {
120
+ if (error instanceof SlackActionError) {
121
+ return error;
122
+ }
123
+ const candidate = error;
124
+ const apiError = candidate.data?.error;
125
+ const message = candidate.message ?? "Slack action failed";
126
+ const baseOptions = {
127
+ apiError,
128
+ statusCode: candidate.statusCode,
129
+ requestId: getHeaderString(candidate.headers, "x-slack-req-id"),
130
+ errorData: serializeSlackErrorData(candidate.data),
131
+ ...parseSlackCanvasDetail(candidate.data?.detail)
132
+ };
133
+ if (apiError === "missing_scope") {
134
+ return new SlackActionError(message, "missing_scope", {
135
+ ...baseOptions,
136
+ needed: candidate.data?.needed,
137
+ provided: candidate.data?.provided
138
+ });
139
+ }
140
+ if (apiError === "not_in_channel") {
141
+ return new SlackActionError(message, "not_in_channel", baseOptions);
142
+ }
143
+ if (apiError === "already_reacted") {
144
+ return new SlackActionError(message, "already_reacted", baseOptions);
145
+ }
146
+ if (apiError === "no_reaction") {
147
+ return new SlackActionError(message, "no_reaction", baseOptions);
148
+ }
149
+ if (apiError === "invalid_arguments") {
150
+ return new SlackActionError(message, "invalid_arguments", baseOptions);
151
+ }
152
+ if (apiError === "invalid_cursor") {
153
+ return new SlackActionError(message, "invalid_arguments", baseOptions);
154
+ }
155
+ if (apiError === "invalid_name") {
156
+ return new SlackActionError(message, "invalid_arguments", baseOptions);
157
+ }
158
+ if (apiError === "not_found" || apiError === "channel_not_found" || apiError === "message_not_found") {
159
+ return new SlackActionError(message, "not_found", baseOptions);
160
+ }
161
+ if (apiError === "feature_not_enabled" || apiError === "not_allowed_token_type") {
162
+ return new SlackActionError(message, "feature_unavailable", baseOptions);
163
+ }
164
+ if (apiError === "canvas_creation_failed") {
165
+ return new SlackActionError(message, "canvas_creation_failed", baseOptions);
166
+ }
167
+ if (apiError === "canvas_editing_failed") {
168
+ return new SlackActionError(message, "canvas_editing_failed", baseOptions);
169
+ }
170
+ if (candidate.code === "slack_webapi_rate_limited_error" || candidate.statusCode === 429) {
171
+ return new SlackActionError(message, "rate_limited", {
172
+ ...baseOptions,
173
+ retryAfterSeconds: candidate.retryAfter
174
+ });
175
+ }
176
+ return new SlackActionError(message, "internal_error", baseOptions);
177
+ }
178
+ function sleep(ms) {
179
+ return new Promise((resolve) => setTimeout(resolve, ms));
180
+ }
181
+ async function withSlackRetries(task, maxAttempts = 3, context = {}) {
182
+ let attempt = 0;
183
+ while (attempt < maxAttempts) {
184
+ attempt += 1;
185
+ try {
186
+ return await task();
187
+ } catch (error) {
188
+ const mapped = mapSlackError(error);
189
+ const isRetryable = mapped.code === "rate_limited";
190
+ const baseLogAttributes = {
191
+ "app.slack.action": context.action ?? "unknown",
192
+ "app.slack.error_code": mapped.code,
193
+ ...mapped.apiError ? { "app.slack.api_error": mapped.apiError } : {},
194
+ ...mapped.detail ? { "app.slack.detail": mapped.detail } : {},
195
+ ...mapped.detailLine !== void 0 ? { "app.slack.detail_line": mapped.detailLine } : {},
196
+ ...mapped.detailRule ? { "app.slack.detail_rule": mapped.detailRule } : {},
197
+ ...mapped.requestId ? { "app.slack.request_id": mapped.requestId } : {},
198
+ ...mapped.statusCode !== void 0 ? { "http.response.status_code": mapped.statusCode } : {},
199
+ ...context.attributes ?? {}
200
+ };
201
+ if (!isRetryable || attempt >= maxAttempts) {
202
+ logWarn(
203
+ "slack_action_failed",
204
+ {},
205
+ {
206
+ ...baseLogAttributes,
207
+ ...mapped.errorData ? { "app.slack.error_data": mapped.errorData } : {}
208
+ },
209
+ "Slack action failed"
210
+ );
211
+ throw mapped;
212
+ }
213
+ logWarn(
214
+ "slack_action_retrying",
215
+ {},
216
+ {
217
+ ...baseLogAttributes,
218
+ "app.slack.retry_attempt": attempt
219
+ },
220
+ "Retrying Slack action after transient failure"
221
+ );
222
+ const retryAfterMs = mapped.code === "rate_limited" && mapped.retryAfterSeconds && mapped.retryAfterSeconds > 0 ? mapped.retryAfterSeconds * 1e3 : void 0;
223
+ const backoffMs = Math.min(2e3, 250 * 2 ** (attempt - 1));
224
+ await sleep(retryAfterMs ?? backoffMs);
225
+ }
226
+ }
227
+ throw new SlackActionError(
228
+ "Slack action exhausted retries",
229
+ "internal_error"
230
+ );
231
+ }
232
+ function getSlackClient() {
233
+ return getClient();
234
+ }
235
+ function isDmChannel(channelId) {
236
+ const normalized = normalizeSlackConversationId(channelId);
237
+ return Boolean(normalized && normalized.startsWith("D"));
238
+ }
239
+ function isConversationScopedChannel(channelId) {
240
+ const normalized = normalizeSlackConversationId(channelId);
241
+ if (!normalized) return false;
242
+ return normalized.startsWith("C") || normalized.startsWith("G") || normalized.startsWith("D");
243
+ }
244
+ function isConversationChannel(channelId) {
245
+ const normalized = normalizeSlackConversationId(channelId);
246
+ if (!normalized) return false;
247
+ return normalized.startsWith("C") || normalized.startsWith("G");
248
+ }
249
+ async function getFilePermalink(fileId) {
250
+ const client2 = getClient();
251
+ const response = await withSlackRetries(
252
+ () => client2.files.info({
253
+ file: fileId
254
+ })
255
+ );
256
+ return response.file?.permalink;
257
+ }
258
+ async function downloadPrivateSlackFile(url) {
259
+ const token = getSlackBotToken();
260
+ if (!token) {
261
+ throw new SlackActionError(
262
+ "SLACK_BOT_TOKEN (or SLACK_BOT_USER_TOKEN) is required for Slack file downloads in this service",
263
+ "missing_token"
264
+ );
265
+ }
266
+ const response = await fetch(url, {
267
+ headers: {
268
+ Authorization: `Bearer ${token}`
269
+ }
270
+ });
271
+ if (!response.ok) {
272
+ throw new Error(`Slack file download failed: ${response.status}`);
273
+ }
274
+ return Buffer.from(await response.arrayBuffer());
275
+ }
276
+
277
+ // src/chat/destination.ts
278
+ import { destinationSchema } from "@sentry/junior-plugin-api";
279
+
280
+ // src/chat/slack/ids.ts
281
+ function isSlackTeamId(value) {
282
+ return /^T[A-Z0-9]+$/.test(value);
283
+ }
284
+ function isSlackConversationId(value) {
285
+ return /^(C|G|D)[A-Z0-9]+$/.test(value);
286
+ }
287
+
288
+ // src/chat/destination.ts
289
+ function createSlackDestination(input) {
290
+ const channelId = normalizeSlackConversationId(input.channelId);
291
+ const teamId = input.teamId?.trim();
292
+ if (!channelId || !teamId) {
293
+ return void 0;
294
+ }
295
+ if (!isSlackConversationId(channelId) || !isSlackTeamId(teamId)) {
296
+ return void 0;
297
+ }
298
+ return { platform: "slack", teamId, channelId };
299
+ }
300
+ function parseDestination(value) {
301
+ const parsed = destinationSchema.safeParse(value);
302
+ return parsed.success ? parsed.data : void 0;
303
+ }
304
+ function sameDestination(left, right) {
305
+ return left.platform === right.platform && left.teamId === right.teamId && left.channelId === right.channelId;
306
+ }
307
+ function destinationKey(destination) {
308
+ return `slack:${destination.teamId}:${destination.channelId}`;
309
+ }
310
+
311
+ export {
312
+ SlackActionError,
313
+ getHeaderString,
314
+ normalizeSlackConversationId,
315
+ withSlackRetries,
316
+ getSlackClient,
317
+ isDmChannel,
318
+ isConversationScopedChannel,
319
+ isConversationChannel,
320
+ getFilePermalink,
321
+ downloadPrivateSlackFile,
322
+ createSlackDestination,
323
+ parseDestination,
324
+ sameDestination,
325
+ destinationKey
326
+ };
@@ -1,13 +1,17 @@
1
1
  import {
2
2
  SANDBOX_WORKSPACE_ROOT,
3
- getStateAdapter,
4
- toOptionalTrimmed
5
- } from "./chunk-EBVQXCD2.js";
3
+ getStateAdapter
4
+ } from "./chunk-R62YWUNO.js";
6
5
  import {
7
6
  getPluginRuntimeDependencies,
8
- getPluginRuntimePostinstall,
7
+ getPluginRuntimePostinstall
8
+ } from "./chunk-UXG6TU2U.js";
9
+ import {
10
+ toOptionalTrimmed
11
+ } from "./chunk-JS4HURDT.js";
12
+ import {
9
13
  withSpan
10
- } from "./chunk-OIIXZOOC.js";
14
+ } from "./chunk-BBXYXOJW.js";
11
15
 
12
16
  // src/chat/sandbox/runtime-dependency-snapshots.ts
13
17
  import { createHash } from "crypto";