@sentry/junior 0.9.2 → 0.9.4

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.
@@ -1,13 +1,3 @@
1
- import {
2
- discoverSkills,
3
- findSkillByName,
4
- getCapabilityProvider,
5
- listCapabilityProviders,
6
- loadSkillsByName,
7
- logCapabilityCatalogLoadedOnce,
8
- parseSkillInvocation,
9
- stripFrontmatter
10
- } from "./chunk-VM3CPAZF.js";
11
1
  import {
12
2
  SANDBOX_SKILLS_ROOT,
13
3
  SANDBOX_WORKSPACE_ROOT,
@@ -25,29 +15,33 @@ import {
25
15
  isSnapshotMissingError,
26
16
  resolveRuntimeDependencySnapshot,
27
17
  runNonInteractiveCommand,
28
- sandboxSkillDir
29
- } from "./chunk-7DAWPSTI.js";
18
+ sandboxSkillDir,
19
+ toOptionalTrimmed
20
+ } from "./chunk-FS5Y4CF2.js";
21
+ import {
22
+ discoverSkills,
23
+ findSkillByName,
24
+ getCapabilityProvider,
25
+ listCapabilityProviders,
26
+ loadSkillsByName,
27
+ logCapabilityCatalogLoadedOnce,
28
+ parseSkillInvocation,
29
+ stripFrontmatter
30
+ } from "./chunk-WM66QDLA.js";
30
31
  import {
31
32
  CredentialUnavailableError,
32
33
  createPluginBroker,
34
+ extractGenAiUsageAttributes,
33
35
  getPluginDefinition,
34
36
  getPluginMcpProviders,
35
37
  getPluginOAuthConfig,
36
38
  getPluginProviders,
37
39
  isPluginProvider,
38
- resolveAuthTokenPlaceholder
39
- } from "./chunk-ZBWWHP6Q.js";
40
- import {
41
- aboutPathCandidates,
42
- homeDir,
43
- soulPathCandidates
44
- } from "./chunk-KCLEEKYX.js";
45
- import {
46
- extractGenAiUsageAttributes,
47
40
  logError,
48
41
  logException,
49
42
  logInfo,
50
43
  logWarn,
44
+ resolveAuthTokenPlaceholder,
51
45
  resolveErrorReference,
52
46
  serializeGenAiAttribute,
53
47
  setSpanAttributes,
@@ -56,7 +50,109 @@ import {
56
50
  toOptionalString,
57
51
  withContext,
58
52
  withSpan
59
- } from "./chunk-ZW4OVKF5.js";
53
+ } from "./chunk-MY7JNCS2.js";
54
+ import {
55
+ aboutPathCandidates,
56
+ homeDir,
57
+ soulPathCandidates
58
+ } from "./chunk-KCLEEKYX.js";
59
+
60
+ // src/chat/queue/errors.ts
61
+ var DeferredThreadMessageError = class extends Error {
62
+ code = "deferred_thread_message";
63
+ reason;
64
+ constructor(reason, threadId, details) {
65
+ if (reason === "thread_locked") {
66
+ super(
67
+ `Queue message deferred because thread ${threadId} is already locked`
68
+ );
69
+ } else {
70
+ super(
71
+ `Queue message deferred for thread ${threadId} because activeTurnId=${details?.activeTurnId ?? "unknown"} is still in progress for currentTurnId=${details?.currentTurnId ?? "unknown"}`
72
+ );
73
+ }
74
+ this.name = "DeferredThreadMessageError";
75
+ this.reason = reason;
76
+ }
77
+ };
78
+ function isDeferredThreadMessageError(error, reason) {
79
+ if (!(error instanceof DeferredThreadMessageError)) {
80
+ return false;
81
+ }
82
+ if (!reason) {
83
+ return true;
84
+ }
85
+ return error.reason === reason;
86
+ }
87
+
88
+ // src/chat/queue/transport.ts
89
+ import { handleCallback, send } from "@vercel/queue";
90
+ async function sendQueueMessage(topicName, payload, options) {
91
+ const result = await send(topicName, payload, {
92
+ ...options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : {}
93
+ });
94
+ return result.messageId ?? void 0;
95
+ }
96
+ function createTransportCallbackHandler(handler, options) {
97
+ return handleCallback(
98
+ async (message, metadata) => {
99
+ await handler(message, {
100
+ messageId: metadata.messageId,
101
+ deliveryCount: metadata.deliveryCount,
102
+ topicName: metadata.topicName
103
+ });
104
+ },
105
+ options ? {
106
+ retry: options.retry ? (error, metadata) => options.retry?.(error, {
107
+ messageId: metadata.messageId,
108
+ deliveryCount: metadata.deliveryCount,
109
+ topicName: metadata.topicName
110
+ }) : void 0
111
+ } : void 0
112
+ );
113
+ }
114
+
115
+ // src/chat/queue/client.ts
116
+ var THREAD_MESSAGE_TOPIC = "junior-thread-message";
117
+ var MAX_DELIVERY_ATTEMPTS = 10;
118
+ var THREAD_LOCK_RETRY_MAX_SECONDS = 30;
119
+ var ACTIVE_TURN_RETRY_MAX_SECONDS = 300;
120
+ function getThreadMessageTopic() {
121
+ return THREAD_MESSAGE_TOPIC;
122
+ }
123
+ async function enqueueThreadMessage(payload, options) {
124
+ return await sendQueueMessage(getThreadMessageTopic(), payload, options);
125
+ }
126
+ function createQueueCallbackHandler(handler) {
127
+ return createTransportCallbackHandler(handler, {
128
+ retry: (error, metadata) => {
129
+ if (isDeferredThreadMessageError(error, "thread_locked")) {
130
+ return {
131
+ afterSeconds: Math.min(
132
+ THREAD_LOCK_RETRY_MAX_SECONDS,
133
+ Math.max(5, metadata.deliveryCount * 5)
134
+ )
135
+ };
136
+ }
137
+ if (isDeferredThreadMessageError(error, "active_turn")) {
138
+ return {
139
+ afterSeconds: Math.min(
140
+ ACTIVE_TURN_RETRY_MAX_SECONDS,
141
+ Math.max(30, metadata.deliveryCount * 30)
142
+ )
143
+ };
144
+ }
145
+ if (metadata.deliveryCount >= MAX_DELIVERY_ATTEMPTS) {
146
+ return { acknowledge: true };
147
+ }
148
+ const backoffSeconds = Math.min(
149
+ 300,
150
+ Math.max(5, metadata.deliveryCount * 5)
151
+ );
152
+ return { afterSeconds: backoffSeconds };
153
+ }
154
+ });
155
+ }
60
156
 
61
157
  // src/chat/app/production.ts
62
158
  import { createSlackAdapter } from "@chat-adapter/slack";
@@ -846,24 +942,10 @@ var GATEWAY_PROVIDER = "vercel-ai-gateway";
846
942
  var GEN_AI_PROVIDER_NAME = GATEWAY_PROVIDER;
847
943
  var GEN_AI_OPERATION_CHAT = "chat";
848
944
  var MISSING_GATEWAY_CREDENTIALS_ERROR = "Missing AI gateway credentials (AI_GATEWAY_API_KEY or VERCEL_OIDC_TOKEN)";
849
- function toOptionalTrimmed(value) {
850
- if (!value) {
851
- return void 0;
852
- }
853
- const trimmed = value.trim();
854
- return trimmed.length > 0 ? trimmed : void 0;
855
- }
856
- function isVercelRuntime() {
857
- return process.env.VERCEL === "1" || Boolean(process.env.VERCEL_ENV) || Boolean(process.env.VERCEL_REGION);
858
- }
859
945
  function getGatewayApiKey() {
860
- const explicitApiKey = toOptionalTrimmed(getEnvApiKey("vercel-ai-gateway"));
861
- if (explicitApiKey) {
862
- return explicitApiKey;
863
- }
864
- if (!isVercelRuntime()) {
865
- return void 0;
866
- }
946
+ return toOptionalTrimmed(getEnvApiKey("vercel-ai-gateway")) ?? toOptionalTrimmed(process.env.VERCEL_OIDC_TOKEN);
947
+ }
948
+ function getPiGatewayApiKeyOverride() {
867
949
  return toOptionalTrimmed(process.env.VERCEL_OIDC_TOKEN);
868
950
  }
869
951
  function extractText(message) {
@@ -930,18 +1012,7 @@ function parseJsonCandidate(text) {
930
1012
  }
931
1013
  }
932
1014
  function resolveGatewayModel(modelId) {
933
- let models;
934
- try {
935
- models = getModels(GATEWAY_PROVIDER);
936
- } catch (error) {
937
- const message = error instanceof Error ? error.message : String(error);
938
- if (message.includes('missing "key" field')) {
939
- throw new Error(
940
- "Invalid AI gateway credentials: Vercel API did not return a key. Set AI_GATEWAY_API_KEY, or ensure VERCEL_OIDC_TOKEN is valid in a Vercel runtime."
941
- );
942
- }
943
- throw error;
944
- }
1015
+ const models = getModels(GATEWAY_PROVIDER);
945
1016
  const matched = models.find((model) => model.id === modelId);
946
1017
  if (!matched) {
947
1018
  throw new Error(`Unknown AI Gateway model id: ${modelId}`);
@@ -950,18 +1021,15 @@ function resolveGatewayModel(modelId) {
950
1021
  }
951
1022
  async function completeText(params) {
952
1023
  const startedAt = Date.now();
953
- if (!getGatewayApiKey()) {
954
- throw new Error(MISSING_GATEWAY_CREDENTIALS_ERROR);
955
- }
956
1024
  const model = resolveGatewayModel(params.modelId);
957
- const apiKey = getGatewayApiKey();
1025
+ const apiKey = getPiGatewayApiKeyOverride();
958
1026
  const requestMessagesAttribute = serializeGenAiAttribute(params.messages);
959
1027
  const startAttributes = {
960
1028
  "gen_ai.provider.name": GEN_AI_PROVIDER_NAME,
961
1029
  "gen_ai.operation.name": GEN_AI_OPERATION_CHAT,
962
1030
  "gen_ai.request.model": params.modelId,
963
1031
  ...requestMessagesAttribute ? { "gen_ai.input.messages": requestMessagesAttribute } : {},
964
- "app.ai.auth_mode": apiKey ? "api_key" : "ambient"
1032
+ "app.ai.auth_mode": apiKey ? "oidc" : "api_key"
965
1033
  };
966
1034
  setSpanAttributes(startAttributes);
967
1035
  const message = await completeSimple(
@@ -4507,11 +4575,9 @@ function createImageGenerateTool(hooks, deps = {}) {
4507
4575
  }),
4508
4576
  execute: async ({ prompt }) => {
4509
4577
  const fetchImpl = deps.fetch ?? fetch;
4510
- const apiKey = process.env.AI_GATEWAY_API_KEY ?? process.env.VERCEL_OIDC_TOKEN;
4578
+ const apiKey = getGatewayApiKey();
4511
4579
  if (!apiKey) {
4512
- throw new Error(
4513
- "Missing AI gateway credentials (AI_GATEWAY_API_KEY or VERCEL_OIDC_TOKEN)"
4514
- );
4580
+ throw new Error(MISSING_GATEWAY_CREDENTIALS_ERROR);
4515
4581
  }
4516
4582
  const model = process.env.AI_IMAGE_MODEL ?? DEFAULT_IMAGE_MODEL;
4517
4583
  const enrichedPrompt = await enrichImagePrompt(prompt);
@@ -6306,7 +6372,7 @@ function formatSearchFailure(error) {
6306
6372
  }
6307
6373
  function isNonRetryableSearchFailure(message) {
6308
6374
  const normalized = message.toLowerCase();
6309
- return normalized.includes("missing ai gateway credentials");
6375
+ return normalized.includes("missing ai gateway credentials") || normalized.includes("authentication failed");
6310
6376
  }
6311
6377
  function isTimeoutSearchFailure(message) {
6312
6378
  return /timed out/i.test(message);
@@ -6331,14 +6397,8 @@ function createWebSearchTool() {
6331
6397
  execute: async ({ query, max_results }) => {
6332
6398
  const maxResults = max_results ?? 3;
6333
6399
  try {
6334
- const apiKey = getGatewayApiKey();
6335
- if (!apiKey) {
6336
- throw new Error(
6337
- "Missing AI gateway credentials (AI_GATEWAY_API_KEY or VERCEL_OIDC_TOKEN)"
6338
- );
6339
- }
6340
6400
  const model = process.env.AI_WEB_SEARCH_MODEL ?? process.env.AI_FAST_MODEL ?? process.env.AI_MODEL ?? DEFAULT_SEARCH_MODEL;
6341
- const provider = createGatewayProvider({ apiKey });
6401
+ const provider = createGatewayProvider();
6342
6402
  const response = await withTimeout(
6343
6403
  (async () => {
6344
6404
  try {
@@ -9165,24 +9225,6 @@ async function generateAssistantReply(messageText, context = {}) {
9165
9225
  userInput,
9166
9226
  context.conversationContext
9167
9227
  );
9168
- if (!getGatewayApiKey()) {
9169
- const providerError = "Missing AI gateway credentials (AI_GATEWAY_API_KEY or VERCEL_OIDC_TOKEN)";
9170
- return {
9171
- text: `Error: ${providerError}`,
9172
- sandboxId: sandboxExecutor.getSandboxId(),
9173
- sandboxDependencyProfileHash: sandboxExecutor.getDependencyProfileHash(),
9174
- diagnostics: {
9175
- outcome: "provider_error",
9176
- modelId: botConfig.modelId,
9177
- assistantMessageCount: 0,
9178
- toolCalls: [],
9179
- toolResultCount: 0,
9180
- toolErrorCount: 0,
9181
- usedPrimaryText: false,
9182
- errorMessage: providerError
9183
- }
9184
- };
9185
- }
9186
9228
  timeoutResumeMessages = [];
9187
9229
  pendingMcpAuthorizationPause = void 0;
9188
9230
  const generatedFiles = [];
@@ -9387,7 +9429,7 @@ async function generateAssistantReply(messageText, context = {}) {
9387
9429
  }
9388
9430
  );
9389
9431
  agent = new Agent({
9390
- getApiKey: () => getGatewayApiKey(),
9432
+ getApiKey: () => getPiGatewayApiKeyOverride(),
9391
9433
  initialState: {
9392
9434
  systemPrompt: baseInstructions,
9393
9435
  model: resolveGatewayModel(botConfig.modelId),
@@ -11468,103 +11510,6 @@ import {
11468
11510
  Chat
11469
11511
  } from "chat";
11470
11512
 
11471
- // src/chat/queue/errors.ts
11472
- var DeferredThreadMessageError = class extends Error {
11473
- code = "deferred_thread_message";
11474
- reason;
11475
- constructor(reason, threadId, details) {
11476
- if (reason === "thread_locked") {
11477
- super(
11478
- `Queue message deferred because thread ${threadId} is already locked`
11479
- );
11480
- } else {
11481
- super(
11482
- `Queue message deferred for thread ${threadId} because activeTurnId=${details?.activeTurnId ?? "unknown"} is still in progress for currentTurnId=${details?.currentTurnId ?? "unknown"}`
11483
- );
11484
- }
11485
- this.name = "DeferredThreadMessageError";
11486
- this.reason = reason;
11487
- }
11488
- };
11489
- function isDeferredThreadMessageError(error, reason) {
11490
- if (!(error instanceof DeferredThreadMessageError)) {
11491
- return false;
11492
- }
11493
- if (!reason) {
11494
- return true;
11495
- }
11496
- return error.reason === reason;
11497
- }
11498
-
11499
- // src/chat/queue/transport.ts
11500
- import { handleCallback, send } from "@vercel/queue";
11501
- async function sendQueueMessage(topicName, payload, options) {
11502
- const result = await send(topicName, payload, {
11503
- ...options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : {}
11504
- });
11505
- return result.messageId ?? void 0;
11506
- }
11507
- function createTransportCallbackHandler(handler, options) {
11508
- return handleCallback(
11509
- async (message, metadata) => {
11510
- await handler(message, {
11511
- messageId: metadata.messageId,
11512
- deliveryCount: metadata.deliveryCount,
11513
- topicName: metadata.topicName
11514
- });
11515
- },
11516
- options ? {
11517
- retry: options.retry ? (error, metadata) => options.retry?.(error, {
11518
- messageId: metadata.messageId,
11519
- deliveryCount: metadata.deliveryCount,
11520
- topicName: metadata.topicName
11521
- }) : void 0
11522
- } : void 0
11523
- );
11524
- }
11525
-
11526
- // src/chat/queue/client.ts
11527
- var THREAD_MESSAGE_TOPIC = "junior-thread-message";
11528
- var MAX_DELIVERY_ATTEMPTS = 10;
11529
- var THREAD_LOCK_RETRY_MAX_SECONDS = 30;
11530
- var ACTIVE_TURN_RETRY_MAX_SECONDS = 300;
11531
- function getThreadMessageTopic() {
11532
- return THREAD_MESSAGE_TOPIC;
11533
- }
11534
- async function enqueueThreadMessage(payload, options) {
11535
- return await sendQueueMessage(getThreadMessageTopic(), payload, options);
11536
- }
11537
- function createQueueCallbackHandler(handler) {
11538
- return createTransportCallbackHandler(handler, {
11539
- retry: (error, metadata) => {
11540
- if (isDeferredThreadMessageError(error, "thread_locked")) {
11541
- return {
11542
- afterSeconds: Math.min(
11543
- THREAD_LOCK_RETRY_MAX_SECONDS,
11544
- Math.max(5, metadata.deliveryCount * 5)
11545
- )
11546
- };
11547
- }
11548
- if (isDeferredThreadMessageError(error, "active_turn")) {
11549
- return {
11550
- afterSeconds: Math.min(
11551
- ACTIVE_TURN_RETRY_MAX_SECONDS,
11552
- Math.max(30, metadata.deliveryCount * 30)
11553
- )
11554
- };
11555
- }
11556
- if (metadata.deliveryCount >= MAX_DELIVERY_ATTEMPTS) {
11557
- return { acknowledge: true };
11558
- }
11559
- const backoffSeconds = Math.min(
11560
- 300,
11561
- Math.max(5, metadata.deliveryCount * 5)
11562
- );
11563
- return { afterSeconds: backoffSeconds };
11564
- }
11565
- });
11566
- }
11567
-
11568
11513
  // src/chat/state/queue-ingress-store.ts
11569
11514
  var QUEUE_INGRESS_DEDUP_PREFIX = "junior:queue_ingress";
11570
11515
  function queueIngressDedupKey(rawKey) {
@@ -12298,112 +12243,132 @@ async function handleSlashCommand(event) {
12298
12243
  }
12299
12244
 
12300
12245
  // src/chat/app/production.ts
12301
- var bot = new JuniorChat({
12302
- userName: botConfig.userName,
12303
- adapters: {
12304
- slack: (() => {
12305
- const signingSecret = getSlackSigningSecret();
12306
- const botToken = getSlackBotToken();
12307
- const clientId = getSlackClientId();
12308
- const clientSecret = getSlackClientSecret();
12309
- if (!signingSecret) {
12310
- throw new Error("SLACK_SIGNING_SECRET is required");
12311
- }
12312
- return createSlackAdapter({
12313
- signingSecret,
12314
- ...botToken ? { botToken } : {},
12315
- ...clientId ? { clientId } : {},
12316
- ...clientSecret ? { clientSecret } : {}
12317
- });
12318
- })()
12319
- },
12320
- state: getStateAdapter()
12321
- });
12322
- var registerSingleton = bot.registerSingleton;
12323
- if (typeof registerSingleton === "function") {
12324
- registerSingleton.call(bot);
12325
- }
12326
- function getSlackAdapter() {
12327
- return bot.getAdapter("slack");
12328
- }
12329
- var slackRuntime = createSlackRuntime({
12330
- getSlackAdapter
12331
- });
12332
- bot.onNewMention(slackRuntime.handleNewMention);
12333
- bot.onSubscribedMessage(slackRuntime.handleSubscribedMessage);
12334
- bot.onAssistantThreadStarted(
12335
- (event) => slackRuntime.handleAssistantThreadStarted(event)
12336
- );
12337
- bot.onAssistantContextChanged(
12338
- (event) => slackRuntime.handleAssistantContextChanged(event)
12339
- );
12340
- bot.onSlashCommand(
12341
- "/jr",
12342
- (event) => withSpan(
12343
- "chat.slash_command",
12344
- "chat.slash_command",
12345
- { slackUserId: event.user.userId },
12346
- async () => {
12347
- try {
12348
- await handleSlashCommand(event);
12349
- } catch (error) {
12350
- logException(error, "slash_command_failed", {
12351
- slackUserId: event.user.userId
12352
- });
12353
- throw error;
12354
- }
12355
- }
12356
- )
12357
- );
12358
- bot.onAppHomeOpened(
12359
- (event) => withSpan(
12360
- "chat.app_home_opened",
12361
- "chat.app_home_opened",
12362
- { slackUserId: event.userId },
12363
- async () => {
12364
- try {
12365
- await publishAppHomeView(
12366
- getSlackClient(),
12367
- event.userId,
12368
- createUserTokenStore()
12369
- );
12370
- } catch (error) {
12371
- logException(error, "app_home_opened_failed", {
12372
- slackUserId: event.userId
12246
+ var productionBot;
12247
+ var productionSlackRuntime;
12248
+ function createProductionBot() {
12249
+ return new JuniorChat({
12250
+ userName: botConfig.userName,
12251
+ adapters: {
12252
+ slack: (() => {
12253
+ const signingSecret = getSlackSigningSecret();
12254
+ const botToken = getSlackBotToken();
12255
+ const clientId = getSlackClientId();
12256
+ const clientSecret = getSlackClientSecret();
12257
+ if (!signingSecret) {
12258
+ throw new Error("SLACK_SIGNING_SECRET is required");
12259
+ }
12260
+ return createSlackAdapter({
12261
+ signingSecret,
12262
+ ...botToken ? { botToken } : {},
12263
+ ...clientId ? { clientId } : {},
12264
+ ...clientSecret ? { clientSecret } : {}
12373
12265
  });
12266
+ })()
12267
+ },
12268
+ state: getStateAdapter()
12269
+ });
12270
+ }
12271
+ function registerProductionHandlers(bot, slackRuntime) {
12272
+ bot.onNewMention(slackRuntime.handleNewMention);
12273
+ bot.onSubscribedMessage(slackRuntime.handleSubscribedMessage);
12274
+ bot.onAssistantThreadStarted(
12275
+ (event) => slackRuntime.handleAssistantThreadStarted(event)
12276
+ );
12277
+ bot.onAssistantContextChanged(
12278
+ (event) => slackRuntime.handleAssistantContextChanged(event)
12279
+ );
12280
+ bot.onSlashCommand(
12281
+ "/jr",
12282
+ (event) => withSpan(
12283
+ "chat.slash_command",
12284
+ "chat.slash_command",
12285
+ { slackUserId: event.user.userId },
12286
+ async () => {
12287
+ try {
12288
+ await handleSlashCommand(event);
12289
+ } catch (error) {
12290
+ logException(error, "slash_command_failed", {
12291
+ slackUserId: event.user.userId
12292
+ });
12293
+ throw error;
12294
+ }
12374
12295
  }
12375
- }
12376
- )
12377
- );
12378
- bot.onAction("app_home_disconnect", async (event) => {
12379
- const provider = event.value;
12380
- if (!provider) return;
12381
- const userId = event.user.userId;
12382
- await withSpan(
12383
- "chat.app_home_disconnect",
12384
- "chat.app_home_disconnect",
12385
- { slackUserId: userId },
12386
- async () => {
12387
- try {
12388
- await unlinkProvider(userId, provider, createUserTokenStore());
12389
- await publishAppHomeView(
12390
- getSlackClient(),
12391
- userId,
12392
- createUserTokenStore()
12393
- );
12394
- } catch (error) {
12395
- logException(
12396
- error,
12397
- "app_home_disconnect_failed",
12398
- { slackUserId: userId },
12399
- {
12400
- "app.credential.provider": provider
12401
- }
12402
- );
12296
+ )
12297
+ );
12298
+ bot.onAppHomeOpened(
12299
+ (event) => withSpan(
12300
+ "chat.app_home_opened",
12301
+ "chat.app_home_opened",
12302
+ { slackUserId: event.userId },
12303
+ async () => {
12304
+ try {
12305
+ await publishAppHomeView(
12306
+ getSlackClient(),
12307
+ event.userId,
12308
+ createUserTokenStore()
12309
+ );
12310
+ } catch (error) {
12311
+ logException(error, "app_home_opened_failed", {
12312
+ slackUserId: event.userId
12313
+ });
12314
+ }
12403
12315
  }
12404
- }
12316
+ )
12405
12317
  );
12406
- });
12318
+ bot.onAction("app_home_disconnect", async (event) => {
12319
+ const provider = event.value;
12320
+ if (!provider) return;
12321
+ const userId = event.user.userId;
12322
+ await withSpan(
12323
+ "chat.app_home_disconnect",
12324
+ "chat.app_home_disconnect",
12325
+ { slackUserId: userId },
12326
+ async () => {
12327
+ try {
12328
+ await unlinkProvider(userId, provider, createUserTokenStore());
12329
+ await publishAppHomeView(
12330
+ getSlackClient(),
12331
+ userId,
12332
+ createUserTokenStore()
12333
+ );
12334
+ } catch (error) {
12335
+ logException(
12336
+ error,
12337
+ "app_home_disconnect_failed",
12338
+ { slackUserId: userId },
12339
+ {
12340
+ "app.credential.provider": provider
12341
+ }
12342
+ );
12343
+ }
12344
+ }
12345
+ );
12346
+ });
12347
+ }
12348
+ function initializeProductionApp() {
12349
+ if (productionBot && productionSlackRuntime) {
12350
+ return;
12351
+ }
12352
+ const bot = createProductionBot();
12353
+ const registerSingleton = bot.registerSingleton;
12354
+ if (typeof registerSingleton === "function") {
12355
+ registerSingleton.call(bot);
12356
+ }
12357
+ const slackRuntime = createSlackRuntime({
12358
+ getSlackAdapter: () => bot.getAdapter("slack")
12359
+ });
12360
+ registerProductionHandlers(bot, slackRuntime);
12361
+ productionBot = bot;
12362
+ productionSlackRuntime = slackRuntime;
12363
+ }
12364
+ function getProductionBot() {
12365
+ initializeProductionApp();
12366
+ return productionBot;
12367
+ }
12368
+ function getProductionSlackRuntime() {
12369
+ initializeProductionApp();
12370
+ return productionSlackRuntime;
12371
+ }
12407
12372
 
12408
12373
  export {
12409
12374
  coerceThreadConversationState,
@@ -12435,10 +12400,9 @@ export {
12435
12400
  resolveReplyDelivery,
12436
12401
  generateAssistantReply,
12437
12402
  publishAppHomeView,
12438
- createNormalizingStream,
12439
12403
  DeferredThreadMessageError,
12440
12404
  getThreadMessageTopic,
12441
12405
  createQueueCallbackHandler,
12442
- bot,
12443
- slackRuntime
12406
+ getProductionBot,
12407
+ getProductionSlackRuntime
12444
12408
  };