@sentry/junior 0.257.0 → 0.258.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 (101) hide show
  1. package/dist/{actor-BTtLaeWy.js → actor-tlxzqaRe.js} +3 -6
  2. package/dist/{admin-DgIkm6Vy.js → admin-My1SLGVO.js} +2 -3
  3. package/dist/{agent-hooks-BjtTzvru.js → agent-hooks-BJ_5mlRH.js} +69 -109
  4. package/dist/{agent-invocations-Bdu3ROfo.js → agent-invocations-Qfz7dWgU.js} +6 -12
  5. package/dist/{agent-runner-D7OboVb3.js → agent-runner-DGsFQw72.js} +261 -458
  6. package/dist/api/schema.d.ts +414 -448
  7. package/dist/api/schema.js +5 -5
  8. package/dist/api.d.ts +2 -12
  9. package/dist/api.js +94 -158
  10. package/dist/{app-BsU5QNBd.d.ts → app-PX2H1PxU.d.ts} +21 -44
  11. package/dist/app.d.ts +3 -3
  12. package/dist/app.js +204 -321
  13. package/dist/{assistant-reply-CbTPebzL.js → assistant-reply-H1M-91oF.js} +3 -5
  14. package/dist/{automation-CHdlHVZP.js → automation-DWBFBenG.js} +6 -11
  15. package/dist/{briefs-oLOldnDM.js → briefs-vYoK85rJ.js} +8 -11
  16. package/dist/{cadence-D00SCzT1.js → cadence-R7Em4RjE.js} +1 -2
  17. package/dist/{catalog-runtime-CZzhGQ7F.js → catalog-runtime-BN4DVxco.js} +3 -4
  18. package/dist/cli/chat.d.ts +2 -4
  19. package/dist/cli/chat.js +22 -24
  20. package/dist/cli/check.d.ts +1 -3
  21. package/dist/cli/check.js +4 -5
  22. package/dist/cli/env.d.ts +1 -3
  23. package/dist/cli/env.js +1 -2
  24. package/dist/cli/init.d.ts +1 -3
  25. package/dist/cli/init.js +3 -3
  26. package/dist/cli/main.d.ts +1 -3
  27. package/dist/cli/main.js +4 -5
  28. package/dist/cli/plugins.d.ts +2 -4
  29. package/dist/cli/plugins.js +7 -8
  30. package/dist/cli/run.d.ts +1 -2
  31. package/dist/cli/run.js +1 -2
  32. package/dist/cli/snapshot-create.d.ts +1 -3
  33. package/dist/cli/snapshot-create.js +4 -5
  34. package/dist/cli/upgrade.d.ts +3 -6
  35. package/dist/cli/upgrade.js +11 -17
  36. package/dist/{client-D8HnkOQX.js → client-DbyHuMFU.js} +9 -16
  37. package/dist/{config-CJRnWK9H.js → config-_WO_AjCB.js} +18 -15
  38. package/dist/{connections-ClYrKzpX.js → connections-ag_1JOhB.js} +14 -19
  39. package/dist/{conversation-CKNLYBJt.js → conversation-DjN3mlog.js} +8 -15
  40. package/dist/{conversation-privacy-C8b1nphZ.js → conversation-privacy-DHP_xnVj.js} +2 -3
  41. package/dist/{conversation-work-C6y3T5Hx.js → conversation-work-BaT_T6EB.js} +1 -2
  42. package/dist/{credential-sync-BXfohNmJ.js → credential-sync-B-CPX_ag.js} +23 -28
  43. package/dist/{db-Ca9Nt5ci.d.ts → db-BnRqQ7G5.d.ts} +1 -1
  44. package/dist/{executor-Do0THDRR.js → executor-RvG6kVe1.js} +30 -52
  45. package/dist/{experimental-CQIvMUO7.js → experimental-BNK1l1jv.js} +2 -4
  46. package/dist/{history-9pO1Zd4Y.js → history-AY8rs-FR.js} +5 -9
  47. package/dist/{history-DvqWZlYX.d.ts → history-BgI33Kie.d.ts} +12 -20
  48. package/dist/{images-BN_BiBXF.js → images-C2J_bj2g.js} +5 -6
  49. package/dist/instrumentation.d.ts +1 -3
  50. package/dist/instrumentation.js +6 -8
  51. package/dist/{job-queue-B6SV9uVa.js → job-queue-DVe37it2.js} +6 -12
  52. package/dist/{logging-CWxiIuCF.js → logging-DsHONhVm.js} +7 -12
  53. package/dist/{message-TUOdbSBW.js → message-DyitL8no.js} +5 -6
  54. package/dist/{model-profile-BwU8mqwD.js → model-profile-Bg8EoCKD.js} +2 -4
  55. package/dist/nitro.d.ts +3 -5
  56. package/dist/nitro.js +12 -17
  57. package/dist/{oauth-authorization-BA4Dt6a7.js → oauth-authorization-djQn5Nhy.js} +2 -4
  58. package/dist/{oauth-callback-server-Dj5UJODo.js → oauth-callback-server-CDby-pCn.js} +3 -4
  59. package/dist/{oauth-relay-CdCnu80W.js → oauth-relay-CTygMkNx.js} +2 -3
  60. package/dist/{package-discovery-BVvSnQBB.js → package-discovery-DJBompdd.js} +17 -21
  61. package/dist/{pending-auth-s_QFribU.js → pending-auth-D8J1uJUS.js} +37 -28
  62. package/dist/{plugin-module-CVvEUSMH.js → plugin-module-Cf5gVPWP.js} +1 -2
  63. package/dist/{plugins-CjfUP5gJ.d.ts → plugins-B11Mfkmv.d.ts} +0 -4
  64. package/dist/{plugins-egKWjgue.js → plugins-DOm9Y6qI.js} +2 -3
  65. package/dist/{private-trace-result-BLvBjy_e.js → private-trace-result-CE7_lEdq.js} +1 -2
  66. package/dist/{profile-h-72wM78.js → profile-DpYjfKke.js} +16 -28
  67. package/dist/{prompt-DyoEj9c2.js → prompt-xgpyMtg7.js} +5 -9
  68. package/dist/{queue-B5SnqRln.d.ts → queue-C37RbDVc.d.ts} +0 -2
  69. package/dist/{registry-sLTr-sV9.js → registry-Du566MtJ.js} +16 -29
  70. package/dist/{resolve-ncQPZROQ.js → resolve-ClCIgh8E.js} +7 -12
  71. package/dist/{result-C883vngT.js → result-BBbKA61B.js} +13 -17
  72. package/dist/{rolldown-runtime-B4FMCO8f.js → rolldown-runtime-nwUcYXjP.js} +1 -2
  73. package/dist/{runner-CzYImdOF.js → runner-CCuqFSqx.js} +12 -13
  74. package/dist/{sandbox-egress-signals-CZbMINHI.js → sandbox-egress-signals-DY1mbKF4.js} +2 -3
  75. package/dist/{schema-Dy69D4Ge.js → schema-DrMh3NtR.js} +15 -26
  76. package/dist/{sentry-CgWZM_kV.js → sentry-BBUlHih9.js} +2 -3
  77. package/dist/{session-stop-CQjKd4a2.js → session-stop-CIoFiwwe.js} +23 -33
  78. package/dist/{skills-C22SLruK.js → skills-DyQBLIrK.js} +9 -9
  79. package/dist/{spawn-DY9CLXDL.js → spawn-Dqfeo7XP.js} +4 -5
  80. package/dist/{store-DoewL5mG.d.ts → store-CG0VJyye.d.ts} +0 -14
  81. package/dist/{store-DXFIQy-G.js → store-DJLwq4x8.js} +13 -15
  82. package/dist/{task-queue-B17vV0La.js → task-queue-BzW4MaWU.js} +5 -7
  83. package/dist/{task-runner-DUjvzYXj.js → task-runner-D3qJh4fK.js} +22 -26
  84. package/dist/{tasks-D_WIJtvO.js → tasks-CEXKTASS.js} +62 -78
  85. package/dist/{thread-state-Ch4yuCqG.js → thread-state-W3f6kAtz.js} +13 -19
  86. package/dist/{turn-failure-response-C5nBKC4S.js → turn-failure-response-CWx7aNIh.js} +16 -22
  87. package/dist/{turn-lifecycle-CO-ylUmV.js → turn-lifecycle-C9JFst7-.js} +2 -3
  88. package/dist/{turn-session-routing-B3LWooK5.js → turn-session-routing-CUxtfpr7.js} +2 -3
  89. package/dist/{validation-CXYxaNYx.js → validation-BHRxa5G4.js} +3 -4
  90. package/dist/vercel.d.ts +1 -3
  91. package/dist/vercel.js +1 -2
  92. package/dist/{version-BcdZy2zg.js → version-C0U6rHg0.js} +3 -5
  93. package/dist/{version-CnXZ614E.d.ts → version-Cc2OFd9G.d.ts} +0 -2
  94. package/dist/version.d.ts +1 -1
  95. package/dist/version.js +1 -2
  96. package/dist/{viewer-DSZXygMU.js → viewer-CGvvRqKp.js} +26 -57
  97. package/dist/{web-input-B9Bv0_lR.js → web-input-Keb5GRWj.js} +98 -155
  98. package/dist/{web-message-id-xPI_EFSC.js → web-message-id-CJSUiksE.js} +3 -6
  99. package/dist/{work-nAfDSUFP.js → work-DRcsJ3hV.js} +14 -16
  100. package/dist/{worker-vGXZ6XFT.js → worker-Cjo-QqPq.js} +7 -8
  101. package/package.json +7 -6
package/dist/app.js CHANGED
@@ -1,40 +1,39 @@
1
- import { At as consumeSandboxEgressPermissionDeniedSignal, B as effectiveTaskOutcomes, Ct as ingestEvent, Dt as SANDBOX_EGRESS_PROXY_PATH, E as requestAttachmentDeletion, Et as shouldPropagateSandboxEgressTrace, F as logScheduledAutomationRunSkipped, I as scheduledAutomationRunAttributes, It as resolveBaseUrl, Jt as setConfigDefaults, Lt as startOAuthFlow, Nt as deliverPrivateMessage, O as parseSlackThreadId, Ot as clearSandboxEgressSignals, Pt as formatProviderLabel, Rt as createUserTokenStore, St as processWorkspaceSnapshotJob, Tt as normalizeSandboxEgressTracePropagationDomains, U as stopConversationSession, W as recordSubagentEnded, b as unpublishedArtifactHeaders, i as executeCredentialedEgressRequest, jt as parseSandboxEgressCredentialToken, kt as consumeSandboxEgressAuthRequiredSignal, lt as listPendingAgentInvocationMailboxAppends, n as executeAgentRun, qt as getConfigDefaults, t as createAgentRunner, ut as listPendingAgentInvocationResults, v as publicArtifactHeaders, w as collectAttachmentGarbage, wt as resolveSandboxEgressProviderForHost, x as lookupSlackUserProfile, y as readPublicArtifact } from "./agent-runner-D7OboVb3.js";
2
- import { f as escapeXml } from "./client-D8HnkOQX.js";
3
- import { C as withContext, M as JUNIOR_WORKSPACE_SNAPSHOT_JOB_CALLBACK_ROUTE, R as normalizeIdentityEmail, T as withSpan, b as setSpanStatus, f as logException, k as JUNIOR_PLUGIN_TASK_CALLBACK_ROUTE, m as logWarn, p as logInfo, r as createRequestContext, v as setSentryUser, w as withLogContext, y as setSpanAttributes } from "./logging-CWxiIuCF.js";
4
- import { n as captureMessage, r as continueTrace } from "./sentry-CgWZM_kV.js";
5
- import { t as JUNIOR_VERSION } from "./version-BcdZy2zg.js";
6
- import { _ as snapshotRuntimeConfig, d as restoreRuntimeConfig, f as setBotModelConfig, g as setSlackReactionConfig, h as setRuntimeLimits, i as getChatConfig, m as setProfiles, n as botConfig, o as getSlackBotToken, p as setCrossActorMidRunMode, u as resetRuntimeConfig } from "./config-CJRnWK9H.js";
7
- import { _ as slackMessageTsSchema, d as parseSlackTeamId, f as parseSlackUserId, h as slackUserIdSchema, m as slackTeamIdSchema, o as parseActorUserId, p as slackChannelIdSchema } from "./actor-BTtLaeWy.js";
8
- import { F as recordGoogleSignIn, L as slackUserHasGoogleSignIn, M as findSlackIdentityUserId, R as upsertIdentity, d as getConversationStore, f as getDb, h as withConversationEventLock, i as readActorIdentity, l as getConversationEventStore, n as findUserByEmailFromSql, p as getSqlExecutor, v as withConversationMutationLock } from "./viewer-DSZXygMU.js";
9
- import { a as juniorAgentInvocations, d as juniorDestinations, i as juniorAgentBindings, s as juniorConversations } from "./agent-invocations-Bdu3ROfo.js";
10
- import { a as juniorAutomationRuns, f as juniorConversationBriefs, h as juniorConversationEvents, s as juniorAutomations } from "./executor-Do0THDRR.js";
11
- import { m as credentialLogContext } from "./registry-sLTr-sV9.js";
12
- import { n as pluginCatalogRuntime } from "./catalog-runtime-CZzhGQ7F.js";
13
- import { C as automationVersionOf, Kt as projectConversationMessages, P as slackMention, U as slackEntitySchema, Ut as appendConversationMessages, W as slackExternalRefIdSchema, Yt as settleConversationTitleWork, b as admitEventAutomationRun, c as withScheduledAutomationLock, i as readScheduledAutomation, j as formatSlackLink, l as blockEventAutomation, n as listScheduledAutomationsForTeam, o as saveScheduledAutomationInLock, p as findMatchingEventAutomations, s as scheduledRunId, u as collectEventAutomationMatchKeys, x as eventAutomationRunLimitReason } from "./tasks-D_WIJtvO.js";
14
- import { $ as bindSlackDirectCredentialSubject, At as resolveRootVisibility, Ht as getSlackClient, Jt as getWorkspaceTeamId, Nt as listConversationAnnotations, Q as bindScheduledAutomationCredentialSubject, U as collectEventMatchKeys, Wt as isDmChannel, X as takeDueTimerWatches, Yt as runWithWorkspaceTeamId, Z as bindEventAutomationCredentialSubject, a as getPluginRoutes, at as getDashboardConversationLink, ct as setDashboardConversationLinkOptions, d as setPlugins, et as verifyEventAutomationCredentialSubject, f as validatePlugins, ft as createPluginLogger, h as setBriefsConfig, i as getPluginApiRoutes, lt as createPluginState, nt as verifySlackDirectCredentialSubject, pt as readConversationAccessFromSql, q as findMatchingWatches, st as getDashboardTaskLink, tt as verifyScheduledAutomationCredentialSubject, u as getPlugins } from "./agent-hooks-BjtTzvru.js";
15
- import { W as annotationCard } from "./conversation-CKNLYBJt.js";
16
- import { O as withLock$1, w as getStateAdapter } from "./profile-h-72wM78.js";
17
- import { c as getThreadStopDecision } from "./pending-auth-s_QFribU.js";
18
- import { b as eventGuidance, f as slackChannelMessageEvent, k as renderTaskInput, l as getEventCatalog, m as slackChannelMessageRunsAutomation, p as slackChannelMessageReplyThreadTs, u as SLACK_EVENT_NAMESPACE } from "./session-stop-CQjKd4a2.js";
19
- import { n as getNextRunAtMs } from "./cadence-D00SCzT1.js";
20
- import { f as setSandboxResourceConfig, u as getSandboxResourceConfig } from "./resolve-ncQPZROQ.js";
21
- import { a as getVercelConversationWorkQueue, g as isConversationQueueMessageRejectedError, h as conversationQueueMessageSchema, i as verifyWorkspaceSnapshotJobMessage, o as resolveConversationWorkQueueTopic, s as verifyConversationQueueMessage, t as WORKSPACE_SNAPSHOT_JOB_QUEUE_TOPIC } from "./job-queue-B6SV9uVa.js";
22
- import { A as hasRunnableConversationWork$1, M as isInvalidConversationRecordError, O as CONVERSATION_WORK_STALE_ENQUEUE_MS, S as removeActiveConversation, _ as hasRunnableConversationWork, c as clearExpiredConversationLease, g as getConversationWorkState, h as getConversation, m as ensureConversationWake, r as appendAndEnqueueInboundMessage, v as listActiveConversationIds } from "./store-DXFIQy-G.js";
23
- import { D as scheduledRunSchema } from "./automation-CHdlHVZP.js";
24
- import { i as setExperimentalFeatures, n as getExperimentalFeatures, r as isExperimentalFeatureEnabled } from "./experimental-CQIvMUO7.js";
25
- import { n as validatePluginRegistrations, t as validatePluginEgressCredentialHooks } from "./validation-CXYxaNYx.js";
26
- import { a as pluginRuntimeRegistrationsFromPluginSet, n as pluginCatalogConfigFromEnv, r as pluginCatalogConfigFromPluginSet, t as defineJuniorPlugins } from "./plugins-egKWjgue.js";
27
- import { A as THREAD_OPTOUT_ACK, C as buildSlackInboundMessage, D as normalizeIncomingSlackThreadId, E as stopSlackThread, F as renderSlackObjectCard, I as createVercelAttachmentStorage, M as parseContent, N as runWithSlackInstallation, O as withNormalizedThreadId, P as verifySlackSignature, R as enqueueAgentDispatch, S as recordSkippedConversationMessage, T as isSlackMessageStopped, a as recordWebConversationActivity, c as createProductionSlackWebhookServices, f as createSlackWebApiStatusSender, j as startProcessingReaction, k as stopConversationTurn, l as getProductionSlackAdapter, n as conversationTurnIdForMessage, o as webActorFromEmail, s as createProductionConversationWorkOptions, t as appendAndEnqueueWebMessage, v as readViewerAutomationSummary, w as clearSlackPendingReactions, z as GET$3 } from "./web-input-B9Bv0_lR.js";
28
- import { M as recordAutomationExecution, S as existingConversationId, a as confirmDispatchMailboxAppend, b as notifyAutomationBlocked, f as getPluginDispatchProjection, m as listPendingDispatchMailboxAppends, o as createOrGetDispatch, p as isTerminalDispatchStatus, s as getDispatchConversationId, t as processPluginTask, u as getDispatchRecord, v as markDispatchFailed } from "./task-runner-DUjvzYXj.js";
29
- import { o as getAuthPausedConversationTurnId, t as enqueueAgentInvocationResult } from "./result-C883vngT.js";
30
- import { r as enqueueAgentInvocation } from "./work-nAfDSUFP.js";
31
- import { s as coerceThreadConversationState } from "./thread-state-Ch4yuCqG.js";
32
- import { o as unlinkProvider } from "./connections-ClYrKzpX.js";
33
- import { a as GET$4, i as publishAppHomeView, o as htmlCallbackResponse, r as GET$5, t as receiveLocalOAuthCredential } from "./credential-sync-BXfohNmJ.js";
34
- import { a as registerVercelPluginTaskDevConsumer, n as createVercelPluginTaskCallback, s as queueCallback } from "./task-queue-B17vV0La.js";
35
- import { t as processConversationWork } from "./worker-vGXZ6XFT.js";
36
- import { t as bindMessageAgent } from "./message-TUOdbSBW.js";
37
- import { t as bindSpawnAgent } from "./spawn-DY9CLXDL.js";
1
+ import { At as consumeSandboxEgressPermissionDeniedSignal, B as effectiveTaskOutcomes, Ct as ingestEvent, Dt as SANDBOX_EGRESS_PROXY_PATH, E as requestAttachmentDeletion, Et as shouldPropagateSandboxEgressTrace, F as logScheduledAutomationRunSkipped, Ft as resolveBaseUrl, I as scheduledAutomationRunAttributes, It as startOAuthFlow, Kt as getConfigDefaults, Lt as createUserTokenStore, Nt as formatProviderLabel, O as parseSlackThreadId, Ot as clearSandboxEgressSignals, St as processWorkspaceSnapshotJob, Tt as normalizeSandboxEgressTracePropagationDomains, U as stopConversationSession, W as recordSubagentEnded, b as unpublishedArtifactHeaders, i as executeCredentialedEgressRequest, jt as parseSandboxEgressCredentialToken, kt as consumeSandboxEgressAuthRequiredSignal, lt as listPendingAgentInvocationMailboxAppends, n as executeAgentRun, qt as setConfigDefaults, t as createAgentRunner, ut as listPendingAgentInvocationResults, v as publicArtifactHeaders, w as collectAttachmentGarbage, wt as resolveSandboxEgressProviderForHost, x as lookupSlackUserProfile, y as readPublicArtifact } from "./agent-runner-DGsFQw72.js";
2
+ import { C as withContext, M as JUNIOR_WORKSPACE_SNAPSHOT_JOB_CALLBACK_ROUTE, R as normalizeIdentityEmail, T as withSpan, b as setSpanStatus, f as logException, k as JUNIOR_PLUGIN_TASK_CALLBACK_ROUTE, m as logWarn, p as logInfo, r as createRequestContext, v as setSentryUser, w as withLogContext, y as setSpanAttributes } from "./logging-DsHONhVm.js";
3
+ import { n as captureMessage, r as continueTrace } from "./sentry-BBUlHih9.js";
4
+ import { t as JUNIOR_VERSION } from "./version-C0U6rHg0.js";
5
+ import { _ as snapshotRuntimeConfig, d as restoreRuntimeConfig, f as setBotModelConfig, g as setSlackReactionConfig, h as setRuntimeLimits, i as getChatConfig, m as setProfiles, n as botConfig, o as getSlackBotToken, p as setCrossActorMidRunMode, u as resetRuntimeConfig } from "./config-_WO_AjCB.js";
6
+ import { _ as slackMessageTsSchema, d as parseSlackTeamId, f as parseSlackUserId, h as slackUserIdSchema, m as slackTeamIdSchema, o as parseActorUserId, p as slackChannelIdSchema } from "./actor-tlxzqaRe.js";
7
+ import { N as recordGoogleSignIn, _ as withConversationMutationLock, c as getConversationEventStore, d as getDb, f as getSqlExecutor, m as withConversationEventLock, r as readActorIdentity, u as getConversationStore } from "./viewer-CGvvRqKp.js";
8
+ import { a as juniorAgentInvocations, d as juniorDestinations, i as juniorAgentBindings, s as juniorConversations } from "./agent-invocations-Qfz7dWgU.js";
9
+ import { a as juniorAutomationRuns, f as juniorConversationBriefs, h as juniorConversationEvents, s as juniorAutomations } from "./executor-RvG6kVe1.js";
10
+ import { m as credentialLogContext } from "./registry-Du566MtJ.js";
11
+ import { n as pluginCatalogRuntime } from "./catalog-runtime-BN4DVxco.js";
12
+ import { C as automationVersionOf, Kt as projectConversationMessages, P as slackMention, U as slackEntitySchema, Ut as appendConversationMessages, W as slackExternalRefIdSchema, Yt as settleConversationTitleWork, b as admitEventAutomationRun, c as withScheduledAutomationLock, i as readScheduledAutomation, l as blockEventAutomation, n as listScheduledAutomationsForTeam, o as saveScheduledAutomationInLock, p as findMatchingEventAutomations, s as scheduledRunId, u as collectEventAutomationMatchKeys, x as eventAutomationRunLimitReason } from "./tasks-CEXKTASS.js";
13
+ import { $ as bindSlackDirectCredentialSubject, At as resolveRootVisibility, Ht as getSlackClient, Jt as getWorkspaceTeamId, Nt as listConversationAnnotations, Q as bindScheduledAutomationCredentialSubject, U as collectEventMatchKeys, Wt as isDmChannel, X as takeDueTimerWatches, Yt as runWithWorkspaceTeamId, Z as bindEventAutomationCredentialSubject, a as getPluginRoutes, at as getDashboardConversationLink, ct as setDashboardConversationLinkOptions, d as setPlugins, et as verifyEventAutomationCredentialSubject, f as validatePlugins, ft as createPluginLogger, h as setBriefsConfig, i as getPluginApiRoutes, lt as createPluginState, nt as verifySlackDirectCredentialSubject, pt as readConversationAccessFromSql, q as findMatchingWatches, st as getDashboardTaskLink, tt as verifyScheduledAutomationCredentialSubject, u as getPlugins } from "./agent-hooks-BJ_5mlRH.js";
14
+ import { W as annotationCard } from "./conversation-DjN3mlog.js";
15
+ import { O as withLock$1, w as getStateAdapter } from "./profile-DpYjfKke.js";
16
+ import { l as getThreadStopDecision, o as SubscribedReplyReason } from "./pending-auth-D8J1uJUS.js";
17
+ import { b as eventGuidance, f as slackChannelMessageEvent, k as renderTaskInput, l as getEventCatalog, m as slackChannelMessageRunsAutomation, p as slackChannelMessageReplyThreadTs, u as SLACK_EVENT_NAMESPACE } from "./session-stop-CIoFiwwe.js";
18
+ import { n as getNextRunAtMs } from "./cadence-R7Em4RjE.js";
19
+ import { f as setSandboxResourceConfig, u as getSandboxResourceConfig } from "./resolve-ClCIgh8E.js";
20
+ import { a as getVercelConversationWorkQueue, g as isConversationQueueMessageRejectedError, h as conversationQueueMessageSchema, i as verifyWorkspaceSnapshotJobMessage, o as resolveConversationWorkQueueTopic, s as verifyConversationQueueMessage, t as WORKSPACE_SNAPSHOT_JOB_QUEUE_TOPIC } from "./job-queue-DVe37it2.js";
21
+ import { A as hasRunnableConversationWork$1, M as isInvalidConversationRecordError, O as CONVERSATION_WORK_STALE_ENQUEUE_MS, S as removeActiveConversation, _ as hasRunnableConversationWork, c as clearExpiredConversationLease, g as getConversationWorkState, h as getConversation, m as ensureConversationWake, r as appendAndEnqueueInboundMessage, v as listActiveConversationIds } from "./store-DJLwq4x8.js";
22
+ import { D as scheduledRunSchema } from "./automation-DWBFBenG.js";
23
+ import { i as setExperimentalFeatures, n as getExperimentalFeatures, r as isExperimentalFeatureEnabled } from "./experimental-BNK1l1jv.js";
24
+ import { n as validatePluginRegistrations, t as validatePluginEgressCredentialHooks } from "./validation-BHRxa5G4.js";
25
+ import { a as pluginRuntimeRegistrationsFromPluginSet, n as pluginCatalogConfigFromEnv, r as pluginCatalogConfigFromPluginSet, t as defineJuniorPlugins } from "./plugins-DOm9Y6qI.js";
26
+ import { A as THREAD_OPTOUT_ACK, C as buildSlackInboundMessage, D as normalizeIncomingSlackThreadId, E as stopSlackThread, F as renderSlackObjectCard, I as createVercelAttachmentStorage, M as parseContent, N as runWithSlackInstallation, O as withNormalizedThreadId, P as verifySlackSignature, R as enqueueAgentDispatch, S as recordSkippedConversationMessage, T as isSlackMessageStopped, a as recordWebConversationActivity, c as createProductionSlackWebhookServices, f as createSlackWebApiStatusSender, j as startProcessingReaction, k as stopConversationTurn, l as getProductionSlackAdapter, n as conversationTurnIdForMessage, o as webActorFromEmail, s as createProductionConversationWorkOptions, t as appendAndEnqueueWebMessage, v as readViewerAutomationSummary, w as clearSlackPendingReactions, z as GET$3 } from "./web-input-Keb5GRWj.js";
27
+ import { C as existingConversationId, N as recordAutomationExecution, c as getDispatchConversationId, d as getDispatchRecord, h as listPendingDispatchMailboxAppends, i as buildDispatchId, m as isTerminalDispatchStatus, o as confirmDispatchMailboxAppend, p as getPluginDispatchProjection, s as createOrGetDispatch, t as processPluginTask, x as notifyAutomationBlocked, y as markDispatchFailed } from "./task-runner-D3qJh4fK.js";
28
+ import { o as getAuthPausedConversationTurnId, t as enqueueAgentInvocationResult } from "./result-BBbKA61B.js";
29
+ import { r as enqueueAgentInvocation } from "./work-DRcsJ3hV.js";
30
+ import { s as coerceThreadConversationState } from "./thread-state-W3f6kAtz.js";
31
+ import { o as unlinkProvider } from "./connections-ag_1JOhB.js";
32
+ import { a as GET$4, i as publishAppHomeView, r as GET$5, t as receiveLocalOAuthCredential } from "./credential-sync-B-CPX_ag.js";
33
+ import { a as registerVercelPluginTaskDevConsumer, n as createVercelPluginTaskCallback, s as queueCallback } from "./task-queue-BzW4MaWU.js";
34
+ import { t as processConversationWork } from "./worker-Cjo-QqPq.js";
35
+ import { t as bindMessageAgent } from "./message-DyitL8no.js";
36
+ import { t as bindSpawnAgent } from "./spawn-Dqfeo7XP.js";
38
37
  import { createRequire } from "node:module";
39
38
  import { Hono } from "hono";
40
39
  import { z } from "zod";
@@ -48,7 +47,7 @@ import { ChannelImpl, ThreadImpl } from "chat";
48
47
  import * as acp from "@agentclientprotocol/sdk";
49
48
  import { createAuthMiddleware } from "better-auth/api";
50
49
  import { betterAuth } from "better-auth/minimal";
51
- //#region src/chat/events/timers.ts
50
+ // src/chat/events/timers.ts
52
51
  /** Publish a bounded batch of due timers; the mailbox owns agent execution. */
53
52
  async function runTimerWatchHeartbeat(args) {
54
53
  const errors = [];
@@ -67,8 +66,7 @@ async function runTimerWatchHeartbeat(args) {
67
66
  }
68
67
  if (errors.length) throw new AggregateError(errors, "Timer Watch delivery failed");
69
68
  }
70
- //#endregion
71
- //#region src/chat/task-execution/heartbeat.ts
69
+ // src/chat/task-execution/heartbeat.ts
72
70
  const DEFAULT_RECOVERY_LIMIT = 25;
73
71
  function heartbeatIdempotencyKey(reason, conversationId, nowMs) {
74
72
  return `heartbeat:${reason}:${conversationId}:${nowMs}`;
@@ -167,8 +165,7 @@ async function recoverConversationWork(args) {
167
165
  });
168
166
  return result;
169
167
  }
170
- //#endregion
171
- //#region src/chat/agent-dispatch/validation.ts
168
+ // src/chat/agent-dispatch/validation.ts
172
169
  function hasIssueAtPath(issues, path) {
173
170
  return issues.some((issue) => issue.path.length === path.length && issue.path.every((value, index) => value === path[index]));
174
171
  }
@@ -218,8 +215,7 @@ async function verifyDispatchCredentialSubjectAccess(options, plugin) {
218
215
  subject: options.credentialSubject
219
216
  }))) throw new Error("Dispatch credentialSubject is not valid for this action");
220
217
  }
221
- //#endregion
222
- //#region src/chat/agent-dispatch/context.ts
218
+ // src/chat/agent-dispatch/context.ts
223
219
  const MAX_DISPATCHES_PER_HEARTBEAT = 25;
224
220
  function bindDispatchCredentialSubject(options, plugin) {
225
221
  const { credentialSubject, ...baseOptions } = options;
@@ -307,7 +303,11 @@ async function dispatchEventAutomation(args) {
307
303
  ...unboundOptions,
308
304
  ...outcomes !== void 0 ? { outcomes } : void 0,
309
305
  ...boundSubject ? { credentialSubject: boundSubject } : void 0,
310
- source: { kind: "event_automation" }
306
+ source: {
307
+ kind: "event_automation",
308
+ automationId: args.automationId,
309
+ automationRunId: buildDispatchId(plugin, unboundOptions.idempotencyKey)
310
+ }
311
311
  };
312
312
  return await dispatch({
313
313
  conversationWorkQueue: args.conversationWorkQueue,
@@ -330,7 +330,11 @@ async function dispatchScheduledAutomation(args) {
330
330
  ...unboundOptions,
331
331
  ...outcomes !== void 0 ? { outcomes } : void 0,
332
332
  ...boundSubject ? { credentialSubject: boundSubject } : void 0,
333
- source: { kind: "scheduled_automation" }
333
+ source: {
334
+ kind: "scheduled_automation",
335
+ automationId: args.automationId,
336
+ automationRunId: unboundOptions.idempotencyKey
337
+ }
334
338
  };
335
339
  return await dispatch({
336
340
  conversationWorkQueue: args.conversationWorkQueue,
@@ -346,8 +350,7 @@ async function getScheduledAutomationDispatch(id) {
346
350
  id
347
351
  });
348
352
  }
349
- //#endregion
350
- //#region src/chat/event-automations/runs.ts
353
+ // src/chat/event-automations/runs.ts
351
354
  /**
352
355
  * Record a dispatched event automation run with the Automation version it ran,
353
356
  * and link its Conversation when it exists. The dispatch can finish before
@@ -386,8 +389,7 @@ async function settleEventAutomationRuns(db, nowMs) {
386
389
  });
387
390
  }
388
391
  }
389
- //#endregion
390
- //#region src/chat/automations/reply-attribution.ts
392
+ // src/chat/automations/reply-attribution.ts
391
393
  /** Name the Automation in the footer of the replies that its runs post. */
392
394
  function automationReplyAttribution(title) {
393
395
  const detail = (title ?? "").replace(/\s+/g, " ").trim().slice(0, 128).trim();
@@ -396,8 +398,7 @@ function automationReplyAttribution(title) {
396
398
  detail
397
399
  } : { label: "Automation" };
398
400
  }
399
- //#endregion
400
- //#region src/chat/scheduled-automations/runs.ts
401
+ // src/chat/scheduled-automations/runs.ts
401
402
  const PENDING_CLAIM_STALE_MS = 6e4;
402
403
  const MISSED_RUN_MAX_AGE_MS = 864e5;
403
404
  const INCOMPLETE_RUN_STATUSES = ["pending", "running"];
@@ -722,8 +723,7 @@ async function advanceScheduledAutomationAfterRun(db, args) {
722
723
  return args.status === "blocked";
723
724
  });
724
725
  }
725
- //#endregion
726
- //#region src/chat/scheduled-automations/heartbeat.ts
726
+ // src/chat/scheduled-automations/heartbeat.ts
727
727
  const SCHEDULED_AUTOMATION_HEARTBEAT_LIMIT = 10;
728
728
  function singleLineMetadataValue(value) {
729
729
  return value.replace(/[\r\n]+/g, " ").replace(/\s+/g, " ").trim();
@@ -954,6 +954,7 @@ async function runScheduledAutomationHeartbeat(args) {
954
954
  let dispatch;
955
955
  try {
956
956
  dispatch = await dispatchScheduledAutomation({
957
+ automationId: task.id,
957
958
  conversationWorkQueue: args.conversationWorkQueue,
958
959
  nowMs: args.nowMs,
959
960
  options: {
@@ -997,8 +998,7 @@ async function runScheduledAutomationHeartbeat(args) {
997
998
  }
998
999
  return dispatchCount;
999
1000
  }
1000
- //#endregion
1001
- //#region src/chat/agent-dispatch/heartbeat.ts
1001
+ // src/chat/agent-dispatch/heartbeat.ts
1002
1002
  const DEFAULT_PLUGIN_LIMIT = 25;
1003
1003
  const PLUGIN_HEARTBEAT_TIMEOUT_MS = 25e3;
1004
1004
  const DISPATCH_MAILBOX_APPEND_LIMIT = 100;
@@ -1132,8 +1132,7 @@ async function runHeartbeat(args) {
1132
1132
  nowMs: args.nowMs
1133
1133
  });
1134
1134
  }
1135
- //#endregion
1136
- //#region src/handlers/heartbeat.ts
1135
+ // src/handlers/heartbeat.ts
1137
1136
  function getHeartbeatSecret() {
1138
1137
  return process.env.JUNIOR_SCHEDULER_SECRET?.trim() || process.env.CRON_SECRET?.trim();
1139
1138
  }
@@ -1158,8 +1157,7 @@ async function GET$2(request, waitUntil, options = {}) {
1158
1157
  }));
1159
1158
  return new Response("Accepted", { status: 202 });
1160
1159
  }
1161
- //#endregion
1162
- //#region src/chat/conversations/sql/purge.ts
1160
+ // src/chat/conversations/sql/purge.ts
1163
1161
  /** Discover a root and its current descendants via `parent_conversation_id`. */
1164
1162
  async function discoverConversationTree(executor, root) {
1165
1163
  const all = /* @__PURE__ */ new Map([[root.conversationId, root]]);
@@ -1318,8 +1316,7 @@ async function purgeConversationTree(executor, args) {
1318
1316
  });
1319
1317
  });
1320
1318
  }
1321
- //#endregion
1322
- //#region src/chat/conversations/retention.ts
1319
+ // src/chat/conversations/retention.ts
1323
1320
  /**
1324
1321
  * Content retention policy and the bounded purge job.
1325
1322
  *
@@ -1395,8 +1392,7 @@ async function runRetentionPurge(executor, args) {
1395
1392
  attachments: attachmentResult.deleted
1396
1393
  };
1397
1394
  }
1398
- //#endregion
1399
- //#region src/handlers/retention.ts
1395
+ // src/handlers/retention.ts
1400
1396
  function getRetentionSecret() {
1401
1397
  return process.env.JUNIOR_SCHEDULER_SECRET?.trim() || process.env.CRON_SECRET?.trim();
1402
1398
  }
@@ -1427,8 +1423,7 @@ async function GET$1(request, options = {}) {
1427
1423
  return new Response("Retention purge failed", { status: 500 });
1428
1424
  }
1429
1425
  }
1430
- //#endregion
1431
- //#region src/chat/sandbox/egress/oidc.ts
1426
+ // src/chat/sandbox/egress/oidc.ts
1432
1427
  const OIDC_DISCOVERY_CACHE_TTL_MS = 36e5;
1433
1428
  const OIDC_DISCOVERY_CACHE_MAX_ENTRIES = 8;
1434
1429
  const jwksByIssuer = /* @__PURE__ */ new Map();
@@ -1480,8 +1475,7 @@ async function verifyVercelSandboxOidcToken(token, options = {}) {
1480
1475
  ...options.currentDate ? { currentDate: options.currentDate } : void 0
1481
1476
  })).payload;
1482
1477
  }
1483
- //#endregion
1484
- //#region src/chat/sandbox/egress/proxy.ts
1478
+ // src/chat/sandbox/egress/proxy.ts
1485
1479
  const OIDC_TOKEN_HEADER = "vercel-sandbox-oidc-token";
1486
1480
  const FORWARDED_HOST_HEADER = "vercel-forwarded-host";
1487
1481
  const FORWARDED_SCHEME_HEADER = "vercel-forwarded-scheme";
@@ -1736,8 +1730,7 @@ async function proxySandboxEgressRequest(request, deps = {}) {
1736
1730
  upstreamUrl
1737
1731
  }));
1738
1732
  }
1739
- //#endregion
1740
- //#region src/handlers/sandbox-egress-proxy.ts
1733
+ // src/handlers/sandbox-egress-proxy.ts
1741
1734
  /** Handles Vercel Sandbox firewall egress proxy requests. */
1742
1735
  async function ALL(request, options = {}) {
1743
1736
  return await proxySandboxEgressRequest(request, {
@@ -1750,8 +1743,7 @@ async function ALL(request, options = {}) {
1750
1743
  function isSandboxEgressRequest(request) {
1751
1744
  return isSandboxEgressForwardedRequest(request);
1752
1745
  }
1753
- //#endregion
1754
- //#region src/handlers/sandbox-egress-route.ts
1746
+ // src/handlers/sandbox-egress-route.ts
1755
1747
  /**
1756
1748
  * Route authenticated sandbox egress proxy traffic before ordinary app routes.
1757
1749
  */
@@ -1759,8 +1751,7 @@ async function handleSandboxEgressRoute(request, tracePropagationDomains, next)
1759
1751
  if (isSandboxEgressRequest(request)) return await ALL(request, { tracePropagation: { domains: tracePropagationDomains } });
1760
1752
  await next();
1761
1753
  }
1762
- //#endregion
1763
- //#region src/handlers/sandbox-egress-signals.ts
1754
+ // src/handlers/sandbox-egress-signals.ts
1764
1755
  const SANDBOX_EGRESS_TOKEN_HEADER = "x-junior-sandbox-egress-token";
1765
1756
  function isLoopbackDevelopmentRequest(request) {
1766
1757
  const hostname = new URL(request.url).hostname;
@@ -1785,8 +1776,7 @@ async function GET(request) {
1785
1776
  ...permissionDenied ? { permission_denied: permissionDenied } : void 0
1786
1777
  });
1787
1778
  }
1788
- //#endregion
1789
- //#region src/chat/slack/annotation-details.ts
1779
+ // src/chat/slack/annotation-details.ts
1790
1780
  const eventSchema$1 = z.object({
1791
1781
  trigger_id: z.string().min(1),
1792
1782
  user: z.string().min(1),
@@ -1864,8 +1854,7 @@ async function presentSlackAnnotationDetails(event, teamId) {
1864
1854
  metadata: slackEntitySchema.parse(entity)
1865
1855
  });
1866
1856
  }
1867
- //#endregion
1868
- //#region src/chat/ingress/slack-payload.ts
1857
+ // src/chat/ingress/slack-payload.ts
1869
1858
  const eventTimestampSchema = slackMessageTsSchema.refine((value) => Number.isFinite((/* @__PURE__ */ new Date(Number(value) * 1e3)).getTime()));
1870
1859
  const slackSlashCommandSchema = z.object({
1871
1860
  channel_id: z.string().trim().pipe(slackChannelIdSchema),
@@ -1962,8 +1951,7 @@ const slackInteractivePayloadSchema = z.object({
1962
1951
  team_id: z.string().optional()
1963
1952
  }).optional()
1964
1953
  });
1965
- //#endregion
1966
- //#region src/chat/ingress/slash-command.ts
1954
+ // src/chat/ingress/slash-command.ts
1967
1955
  async function postEphemeral(event, text) {
1968
1956
  await event.channel.postEphemeral(event.userId, text, { fallbackToDM: false });
1969
1957
  }
@@ -2024,8 +2012,7 @@ async function handleSlashCommand(event) {
2024
2012
  if (subcommand === "link") await handleLink(event, normalized);
2025
2013
  else await handleUnlink(event, normalized);
2026
2014
  }
2027
- //#endregion
2028
- //#region src/chat/ingress/slack-form.ts
2015
+ // src/chat/ingress/slack-form.ts
2029
2016
  function parseJson$1(body) {
2030
2017
  try {
2031
2018
  return JSON.parse(body);
@@ -2130,8 +2117,7 @@ async function handleSlackForm(args) {
2130
2117
  })));
2131
2118
  return new Response("", { status: 200 });
2132
2119
  }
2133
- //#endregion
2134
- //#region src/chat/ingress/bot-mention.ts
2120
+ // src/chat/ingress/bot-mention.ts
2135
2121
  /**
2136
2122
  * Detect Slack bot @mentions that should activate Junior.
2137
2123
  *
@@ -2208,8 +2194,7 @@ function textMentionsBot(text, botUserId) {
2208
2194
  const id = escapeRegExp(botUserId);
2209
2195
  return new RegExp(`<@${id}(?:\\|[^>]+)?>`).test(outside);
2210
2196
  }
2211
- //#endregion
2212
- //#region src/chat/event-automations/ingest.ts
2197
+ // src/chat/event-automations/ingest.ts
2213
2198
  /**
2214
2199
  * Owns event matching and durable event-automation dispatch.
2215
2200
  *
@@ -2266,7 +2251,8 @@ async function ingestEventAutomations(input, options) {
2266
2251
  },
2267
2252
  extra: {
2268
2253
  "app.event.event_type": event.eventType,
2269
- "app.event_automation.max_runs_per_hour": botConfig.maxEventAutomationRunsPerHour,
2254
+ "app.event_automation.max_runs": botConfig.maxEventAutomationRuns,
2255
+ "app.event_automation.run_window_ms": botConfig.eventAutomationRunWindowMs,
2270
2256
  "app.event_automation.resource_type": task.trigger.resourceType,
2271
2257
  "app.task.id": task.id
2272
2258
  }
@@ -2292,6 +2278,7 @@ async function ingestEventAutomations(input, options) {
2292
2278
  taskId: task.id
2293
2279
  } : void 0;
2294
2280
  const dispatch = await dispatchEventAutomation({
2281
+ automationId: task.id,
2295
2282
  conversationWorkQueue: options.queue,
2296
2283
  nowMs,
2297
2284
  options: {
@@ -2317,8 +2304,7 @@ async function ingestEventAutomations(input, options) {
2317
2304
  if (errors.length > 0) throw new AggregateError(errors, "Failed to dispatch one or more event automations");
2318
2305
  return { dispatched };
2319
2306
  }
2320
- //#endregion
2321
- //#region src/chat/ingress/workspace-membership.ts
2307
+ // src/chat/ingress/workspace-membership.ts
2322
2308
  const MEMBER_TTL_MS = 3e5;
2323
2309
  const NON_MEMBER_TTL_MS = 3e4;
2324
2310
  const authorTeamSchema = z.object({
@@ -2364,13 +2350,14 @@ async function isSlackWorkspaceMember(raw, state) {
2364
2350
  if (!result.acquired) throw new Error("Could not acquire Slack membership lookup lock");
2365
2351
  return result.value;
2366
2352
  }
2367
- //#endregion
2368
- //#region src/chat/sign-in/allowlist.ts
2369
- /** Google accounts that may sign in. The dashboard uses the same list. */
2353
+ // src/chat/sign-in/allowlist.ts
2370
2354
  /**
2371
- * Read a list env var the same way as the dashboard: a JSON string array or
2372
- * comma-separated values.
2355
+ * Domains that may use Junior. Slack authors must have a Slack profile email
2356
+ * on one of them, and dashboard Google sign-ins must come from a Google
2357
+ * Workspace account whose `hd` claim is one of them. Slack and the dashboard
2358
+ * share one list.
2373
2359
  */
2360
+ /** Read a list env var: a JSON string array or comma-separated values. */
2374
2361
  function readEnvList(name) {
2375
2362
  const value = process.env[name]?.trim();
2376
2363
  if (!value) return void 0;
@@ -2386,150 +2373,50 @@ function readEnvList(name) {
2386
2373
  return list.data;
2387
2374
  }
2388
2375
  /**
2389
- * Resolve the sign-in allowlist. Use the same values as the dashboard: its
2390
- * options when set, else its environment variables.
2376
+ * Resolve the allowed domains: the `createApp` option when set, else
2377
+ * `JUNIOR_ALLOWED_DOMAINS`. An empty list allows every domain.
2391
2378
  */
2392
- function resolveSignInAllowlist(options = {}) {
2393
- const list = (values, name) => (values ?? readEnvList(name) ?? []).map((value) => value.trim().toLowerCase()).filter(Boolean);
2394
- return {
2395
- domains: list(options.allowedGoogleDomains, "JUNIOR_DASHBOARD_GOOGLE_DOMAINS"),
2396
- emails: list(options.allowedEmails, "JUNIOR_DASHBOARD_ALLOWED_EMAILS")
2397
- };
2379
+ function resolveAllowedDomains(allowedDomains) {
2380
+ return [...new Set((allowedDomains ?? readEnvList("JUNIOR_ALLOWED_DOMAINS") ?? []).map((value) => value.trim().toLowerCase()).filter(Boolean))];
2398
2381
  }
2399
- /** Return whether a normalized Google email is on the allowlist. */
2400
- function isSignInAllowed(email, allowlist) {
2401
- const domain = email.slice(email.lastIndexOf("@") + 1);
2402
- return allowlist.emails.includes(email) || allowlist.domains.includes(domain);
2403
- }
2404
- //#endregion
2405
- //#region src/chat/sign-in/slack.ts
2406
2382
  /**
2407
- * Slack sign-in through the shared Google sign-in session.
2408
- *
2409
- * Slack sends a person here when they have no recent Google sign-in. The page
2410
- * uses the browser session that the dashboard also uses. When the person has
2411
- * no session, or an old one, it starts a Google sign-in and comes back here.
2412
- * The sign-in counts only when its Google email belongs to the user of the
2413
- * Slack identity that got the link.
2383
+ * Fail startup on the removed Google-specific names. Ignoring them would
2384
+ * leave the list empty, which lets every Slack workspace member in.
2414
2385
  */
2415
- const SLACK_SIGN_IN_PATH = "/api/sign-in/slack";
2416
- const SIGN_IN_STATE_TTL_MS = 6e5;
2417
- const signInStateSchema = z.object({
2418
- redirected: z.boolean(),
2419
- slackTeamId: z.string().min(1),
2420
- slackUserId: z.string().min(1)
2421
- });
2422
- function stateKey(state) {
2423
- return `sign-in:v2:${state}`;
2424
- }
2425
- function page(title, message, status) {
2426
- return htmlCallbackResponse(escapeXml(title), escapeXml(message), status);
2427
- }
2428
- /** Store one Slack sign-in request and return its link. */
2429
- async function createSlackSignInUrl(args) {
2430
- const state = randomBytes(24).toString("base64url");
2431
- await args.state.set(stateKey(state), {
2432
- redirected: false,
2433
- slackTeamId: args.slackTeamId,
2434
- slackUserId: args.slackUserId
2435
- }, SIGN_IN_STATE_TTL_MS);
2436
- const url = new URL(SLACK_SIGN_IN_PATH, args.baseURL);
2437
- url.searchParams.set("state", state);
2438
- return url.toString();
2439
- }
2386
+ function assertNoLegacyAllowedDomains(dashboardOptionKeys) {
2387
+ if (dashboardOptionKeys.includes("allowedGoogleDomains")) throw new Error("dashboard.allowedGoogleDomains was removed; set createApp({ allowedDomains }) instead");
2388
+ if (process.env.JUNIOR_DASHBOARD_GOOGLE_DOMAINS?.trim()) throw new Error("JUNIOR_DASHBOARD_GOOGLE_DOMAINS was removed; set JUNIOR_ALLOWED_DOMAINS instead");
2389
+ }
2390
+ /** Return whether a verified domain may use Junior. An empty list allows all. */
2391
+ function isAllowedDomain(domain, allowedDomains) {
2392
+ if (allowedDomains.length === 0) return true;
2393
+ return Boolean(domain && allowedDomains.includes(domain.toLowerCase()));
2394
+ }
2395
+ // src/chat/ingress/slack-allowed-domain.ts
2396
+ const ALLOWED_TTL_MS = 3e5;
2397
+ const NOT_ALLOWED_TTL_MS = 3e4;
2440
2398
  /**
2441
- * Finish a Slack sign-in when the browser has a recent Google sign-in for the
2442
- * user of the Slack identity. Otherwise start one Google sign-in.
2399
+ * Return whether a Slack author may start a Turn. With allowed domains, the
2400
+ * email of the author's Slack profile must be on one of them. Slack verifies
2401
+ * that email, so Junior trusts it. Without allowed domains, every author may.
2443
2402
  */
2444
- async function handleSlackSignIn(args) {
2445
- const token = new URL(args.request.url).searchParams.get("state");
2446
- const parsed = token ? signInStateSchema.safeParse(await args.state.get(stateKey(token))) : void 0;
2447
- if (!token || !parsed?.success) return page("Sign-in link expired", `Mention ${botConfig.userName} in Slack again to get a new link.`, 400);
2448
- const stored = parsed.data;
2449
- const session = await args.auth.getSession(args.request);
2450
- const email = session?.user.emailVerified ? normalizeIdentityEmail(session.user.email) : void 0;
2451
- let failure;
2452
- if (email && !isSignInAllowed(email, args.allowlist)) failure = page("Account not allowed", `${email} cannot use ${botConfig.userName}. Sign in with your work account.`, 403);
2453
- else if (email) {
2454
- const executor = getSqlExecutor();
2455
- const userId = await findSlackIdentityUserId(executor, stored.slackTeamId, stored.slackUserId);
2456
- const user = await findUserByEmailFromSql(executor.db(), email);
2457
- if (!userId || user?.id !== userId) failure = page("Slack account does not match", `Your Slack email is not ${email}. Sign in with the account that matches your Slack email.`, 403);
2458
- else if (await slackUserHasGoogleSignIn(executor, {
2459
- signedInSince: new Date(Date.now() - args.signIn.maxAgeMs),
2460
- slackTeamId: stored.slackTeamId,
2461
- slackUserId: stored.slackUserId
2462
- })) {
2463
- await args.state.delete(stateKey(token));
2464
- return page("You are signed in", "Return to Slack and send your message again.", 200);
2465
- }
2466
- }
2467
- if (stored.redirected) return failure ?? page("Sign-in failed", "Google sign-in did not finish. Sign in with your work account.", 400);
2468
- await args.state.set(stateKey(token), {
2469
- ...stored,
2470
- redirected: true
2471
- }, SIGN_IN_STATE_TTL_MS);
2472
- const returnUrl = new URL(SLACK_SIGN_IN_PATH, args.signIn.baseURL);
2473
- returnUrl.searchParams.set("state", token);
2474
- return await args.auth.signInWithGoogle(args.request, returnUrl.toString(), returnUrl.toString());
2475
- }
2476
- //#endregion
2477
- //#region src/chat/ingress/slack-sign-in.ts
2478
- /** Require a recent Google sign-in before a Slack user can start a Turn. */
2479
- /**
2480
- * Return whether this Slack user may start work.
2481
- *
2482
- * The user of the Slack identity must have signed in with Google, in Slack or
2483
- * in the dashboard, within `signIn.maxAgeMs`. When it has not, save the Slack
2484
- * identity with the email from the Slack profile, so the sign-in page can match
2485
- * it, and check again. Then send the user a private sign-in link and drop the
2486
- * message.
2487
- */
2488
- async function hasSlackSignIn(args) {
2489
- if (!args.signIn) return true;
2490
- const teamId = args.installation.teamId;
2491
- const channelId = args.event.channel;
2492
- const userId = parseSlackUserId(args.event.user);
2493
- if (!teamId || !channelId || !userId) return false;
2494
- const executor = getSqlExecutor();
2495
- const signedInSince = new Date(Date.now() - args.signIn.maxAgeMs);
2496
- const hasSignIn = () => slackUserHasGoogleSignIn(executor, {
2497
- signedInSince,
2498
- slackTeamId: teamId,
2499
- slackUserId: userId
2500
- });
2501
- if (await hasSignIn()) return true;
2403
+ async function isSlackAuthorDomainAllowed(args) {
2404
+ if (args.allowedDomains.length === 0) return true;
2405
+ const userId = parseSlackUserId(args.user);
2406
+ if (!args.teamId || !userId) return false;
2407
+ const key = `slack:allowed-domain:${args.teamId}:${userId}`;
2408
+ const cached = await args.state.get(key);
2409
+ if (typeof cached === "boolean") return cached;
2502
2410
  const profile = await lookupSlackUserProfile(userId);
2503
- await upsertIdentity(executor, {
2504
- kind: "user",
2505
- provider: "slack",
2506
- providerTenantId: teamId,
2507
- providerSubjectId: userId,
2508
- ...profile.real_name ? { displayName: profile.real_name } : void 0,
2509
- ...profile.name ? { handle: profile.name } : void 0,
2510
- ...profile.email ? {
2511
- email: profile.email,
2512
- emailVerified: true
2513
- } : void 0,
2514
- metadata: { platform: "slack" }
2515
- });
2516
- if (await hasSignIn()) return true;
2517
- const link = await createSlackSignInUrl({
2518
- baseURL: args.signIn.baseURL,
2519
- slackTeamId: teamId,
2520
- slackUserId: userId,
2521
- state: args.state
2522
- });
2523
- await deliverPrivateMessage({
2524
- channelId,
2525
- ...args.event.thread_ts ? { threadTs: args.event.thread_ts } : void 0,
2526
- userId,
2527
- text: `${formatSlackLink(link, `Sign in to use ${botConfig.userName}`)}. Sign in with your work Google account, then send your message again.`
2528
- });
2529
- return false;
2530
- }
2531
- //#endregion
2532
- //#region src/chat/ingress/slack-message-telemetry.ts
2411
+ const email = profile.email?.toLowerCase();
2412
+ const separator = email?.lastIndexOf("@") ?? -1;
2413
+ const domain = separator > 0 ? email?.slice(separator + 1) : void 0;
2414
+ const allowed = profile.id === userId && isAllowedDomain(domain, args.allowedDomains);
2415
+ if (!allowed) logWarn("slack.allowed_domain.rejected", { "app.reason": email ? "domain_not_allowed" : "missing_email" });
2416
+ await args.state.set(key, allowed, allowed ? ALLOWED_TTL_MS : NOT_ALLOWED_TTL_MS);
2417
+ return allowed;
2418
+ }
2419
+ // src/chat/ingress/slack-message-telemetry.ts
2533
2420
  function field(value, pattern) {
2534
2421
  if (value === void 0) return "missing";
2535
2422
  return typeof value === "string" && value.length <= 64 && pattern.test(value) ? value : "invalid";
@@ -2553,8 +2440,7 @@ function slackMessageAttributes(body) {
2553
2440
  "app.slack.is_ext_shared_channel": typeof body.is_ext_shared_channel === "boolean" ? body.is_ext_shared_channel : body.is_ext_shared_channel === void 0 ? "missing" : "invalid"
2554
2441
  };
2555
2442
  }
2556
- //#endregion
2557
- //#region src/chat/slack/automation-details.ts
2443
+ // src/chat/slack/automation-details.ts
2558
2444
  function textField(key, label, value) {
2559
2445
  return {
2560
2446
  key,
@@ -2655,8 +2541,7 @@ async function presentSlackAutomationDetails(event, teamId) {
2655
2541
  metadata: slackEntitySchema.parse(entity)
2656
2542
  });
2657
2543
  }
2658
- //#endregion
2659
- //#region src/chat/ingress/slack-webhook.ts
2544
+ // src/chat/ingress/slack-webhook.ts
2660
2545
  function slackEventLogContext(event) {
2661
2546
  const channelId = event?.channel?.trim() || void 0;
2662
2547
  const threadTs = event?.thread_ts?.trim() || event?.ts?.trim() || void 0;
@@ -2850,7 +2735,7 @@ async function handleSlackThreadStop(args) {
2850
2735
  recordSkippedConversationMessage({
2851
2736
  conversation,
2852
2737
  message: args.message,
2853
- skippedReason: `thread_opt_out:${args.stopReason}`,
2738
+ skippedReason: `${SubscribedReplyReason.ThreadOptOut}:${args.stopReason}`,
2854
2739
  text: content.text
2855
2740
  });
2856
2741
  await appendConversationMessages(getConversationEventStore(), {
@@ -2951,14 +2836,19 @@ async function routeParsedMessage(args) {
2951
2836
  });
2952
2837
  return;
2953
2838
  }
2954
- if (route === "mention" && !await hasSlackSignIn(args)) return;
2839
+ if (route === "mention" && !await isSlackAuthorDomainAllowed({
2840
+ allowedDomains: args.allowedDomains,
2841
+ state: args.state,
2842
+ teamId: args.installation.teamId,
2843
+ user: args.event.user
2844
+ })) return;
2955
2845
  if (isSubscribed && !isExperimentalFeatureEnabled("passive-routing")) {
2956
2846
  const content = parseContent(message);
2957
2847
  const conversation = coerceThreadConversationState(void 0);
2958
2848
  recordSkippedConversationMessage({
2959
2849
  conversation,
2960
2850
  message,
2961
- skippedReason: `passive_disabled:passive-routing`,
2851
+ skippedReason: `${SubscribedReplyReason.PassiveDisabled}:passive-routing`,
2962
2852
  text: content.text
2963
2853
  });
2964
2854
  await appendConversationMessages(getConversationEventStore(), {
@@ -3068,7 +2958,7 @@ async function handleSlackEvent(args) {
3068
2958
  conversationStore: args.services.conversationStore,
3069
2959
  queue: args.services.queue,
3070
2960
  receivedAtMs,
3071
- signIn: args.services.signIn,
2961
+ allowedDomains: args.services.allowedDomains ?? [],
3072
2962
  state
3073
2963
  }), {
3074
2964
  keepAlive: true,
@@ -3126,8 +3016,7 @@ async function handleSlackWebhook(args) {
3126
3016
  }
3127
3017
  return new Response("ok", { status: 200 });
3128
3018
  }
3129
- //#endregion
3130
- //#region src/handlers/webhooks.ts
3019
+ // src/handlers/webhooks.ts
3131
3020
  /** Run a platform webhook with shared request tracing and error logging. */
3132
3021
  async function handleWebhookRequest(request, platform, run) {
3133
3022
  const requestContext = createRequestContext(request, { platform });
@@ -3168,8 +3057,7 @@ async function handleWebhookRequest(request, platform, run) {
3168
3057
  }
3169
3058
  });
3170
3059
  }
3171
- //#endregion
3172
- //#region src/handlers/slack-webhook.ts
3060
+ // src/handlers/slack-webhook.ts
3173
3061
  /** Handle the production Slack webhook route. */
3174
3062
  async function POST(request, waitUntil, services) {
3175
3063
  return handleWebhookRequest(request, "slack", () => handleSlackWebhook({
@@ -3267,8 +3155,7 @@ function createVercelConversationWorkCallback(options) {
3267
3155
  function registerVercelConversationWorkDevConsumer(options) {
3268
3156
  return conversationWorkCallback(options).registerDev();
3269
3157
  }
3270
- //#endregion
3271
- //#region src/chat/sandbox/snapshot/job-callback.ts
3158
+ // src/chat/sandbox/snapshot/job-callback.ts
3272
3159
  const WORKSPACE_SNAPSHOT_JOB_DEV_CONSUMER_GROUP = "junior_workspace_snapshots_dev";
3273
3160
  function logWorkspaceSnapshotJobRejected(reason, metadata) {
3274
3161
  logWarn("workspace.snapshot.job.queue_message.rejected", {
@@ -3297,8 +3184,7 @@ function createVercelWorkspaceSnapshotJobCallback() {
3297
3184
  function registerVercelWorkspaceSnapshotJobDevConsumer() {
3298
3185
  return workspaceSnapshotJobCallback().registerDev();
3299
3186
  }
3300
- //#endregion
3301
- //#region src/handlers/artifacts.ts
3187
+ // src/handlers/artifacts.ts
3302
3188
  /** Serve one content-addressed public artifact without authentication. */
3303
3189
  async function publicArtifactGET(args) {
3304
3190
  try {
@@ -3317,8 +3203,7 @@ async function publicArtifactGET(args) {
3317
3203
  return new Response("Internal Server Error", { status: 500 });
3318
3204
  }
3319
3205
  }
3320
- //#endregion
3321
- //#region src/chat/events/workspace.ts
3206
+ // src/chat/events/workspace.ts
3322
3207
  /**
3323
3208
  * Resolve the single-bot Slack team id for event-automation indexing and
3324
3209
  * Event people mentions.
@@ -3342,8 +3227,7 @@ function createEventTeamIdResolver() {
3342
3227
  return await pending;
3343
3228
  };
3344
3229
  }
3345
- //#endregion
3346
- //#region src/chat/events/app-publisher.ts
3230
+ // src/chat/events/app-publisher.ts
3347
3231
  /** Build the core event publisher used by plugin routes. */
3348
3232
  function createEventAppPublisher(args) {
3349
3233
  const resolveEventAutomationTeamId = createEventTeamIdResolver();
@@ -3391,8 +3275,7 @@ function createEventAppPublisher(args) {
3391
3275
  }
3392
3276
  };
3393
3277
  }
3394
- //#endregion
3395
- //#region src/api/acp/conversations.ts
3278
+ // src/api/acp/conversations.ts
3396
3279
  const EVENT_PAGE_SIZE = 50;
3397
3280
  function actorFromUser(user) {
3398
3281
  return webActorFromEmail(user.email, user.displayName ? { fullName: user.displayName } : void 0);
@@ -3528,8 +3411,7 @@ function createAcpConversations(options) {
3528
3411
  }
3529
3412
  };
3530
3413
  }
3531
- //#endregion
3532
- //#region src/api/acp/state.ts
3414
+ // src/api/acp/state.ts
3533
3415
  const MUTATION_LOCK_TTL_MS = 1e4;
3534
3416
  /** Run one ACP state mutation while its shared lock remains owned. */
3535
3417
  async function withLock(state, key, run, options = {}) {
@@ -3558,8 +3440,7 @@ async function withLock(state, key, run, options = {}) {
3558
3440
  async function fenceLock(state, lock, ttlMs = MUTATION_LOCK_TTL_MS) {
3559
3441
  if (!await state.extendLock(lock, ttlMs)) throw new Error(`ACP lock ownership was lost before write for ${lock.threadId}`);
3560
3442
  }
3561
- //#endregion
3562
- //#region src/api/acp/schema.ts
3443
+ // src/api/acp/schema.ts
3563
3444
  /** Validate the ACP wire messages that Junior supports. */
3564
3445
  const ACP_SESSION_ID_PATTERN = /^local:acp:[a-f0-9]{32}$/;
3565
3446
  const metaSchema = z.record(z.string(), z.unknown()).nullable();
@@ -3655,8 +3536,7 @@ const cancelParamsSchema = z.object({
3655
3536
  _meta: metaSchema.optional(),
3656
3537
  sessionId: acpSessionIdSchema
3657
3538
  }).strict();
3658
- //#endregion
3659
- //#region src/api/acp/sleep.ts
3539
+ // src/api/acp/sleep.ts
3660
3540
  /** Wait for a duration and reject when the ACP request stops. */
3661
3541
  function sleep(ms, signal) {
3662
3542
  return new Promise((resolve, reject) => {
@@ -3675,8 +3555,7 @@ function sleep(ms, signal) {
3675
3555
  signal.addEventListener("abort", onAbort, { once: true });
3676
3556
  });
3677
3557
  }
3678
- //#endregion
3679
- //#region src/api/acp/transport.ts
3558
+ // src/api/acp/transport.ts
3680
3559
  /**
3681
3560
  * Short-lived ACP transport state.
3682
3561
  *
@@ -4247,8 +4126,7 @@ function createSseBody(args) {
4247
4126
  }
4248
4127
  });
4249
4128
  }
4250
- //#endregion
4251
- //#region src/api/acp/auth.ts
4129
+ // src/api/acp/auth.ts
4252
4130
  /** Own ACP browser authorization records and connection binding. */
4253
4131
  const ACP_AUTHORIZATION_TTL_MS = 6e5;
4254
4132
  const ACP_CONNECTION_COOKIE = "junior_acp_connection";
@@ -4587,8 +4465,7 @@ async function expireAcpAuthorization(args) {
4587
4465
  if (!result.acquired) return false;
4588
4466
  return result.value;
4589
4467
  }
4590
- //#endregion
4591
- //#region src/api/acp/route.ts
4468
+ // src/api/acp/route.ts
4592
4469
  /**
4593
4470
  * Own the remote ACP v1 Streamable HTTP edge.
4594
4471
  *
@@ -5026,8 +4903,7 @@ function createAcpHttpHandler(options) {
5026
4903
  }
5027
4904
  };
5028
4905
  }
5029
- //#endregion
5030
- //#region src/api/acp/authorization-page.ts
4906
+ // src/api/acp/authorization-page.ts
5031
4907
  const ACP_AUTHORIZATION_PATH = "/_junior/acp/auth/:transactionId";
5032
4908
  const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
5033
4909
  function escapeHtml(value) {
@@ -5151,17 +5027,39 @@ async function handleAcpAuthorizationPage(args) {
5151
5027
  });
5152
5028
  return renderResult(args.agentName, result);
5153
5029
  }
5154
- //#endregion
5155
- //#region src/chat/sign-in/auth.ts
5030
+ // src/chat/sign-in/auth.ts
5156
5031
  /**
5157
- * Google sign-in session shared by the dashboard and Slack.
5032
+ * Google sign-in session for the dashboard.
5158
5033
  *
5159
5034
  * Better Auth runs the Google OAuth flow and keeps the browser session in an
5160
- * encrypted cookie. Each sign-in also saves the native Google identity with its
5161
- * sign-in time, so Slack can check a recent sign-in without the browser.
5035
+ * encrypted cookie. With allowed domains, only Google Workspace accounts on
5036
+ * those domains can sign in. Each sign-in also saves the native Google
5037
+ * identity.
5162
5038
  */
5163
5039
  const DEFAULT_AUTH_PATH = "/api/auth";
5164
5040
  const DEFAULT_SESSION_MAX_AGE_SECONDS = 28800;
5041
+ const googleClaimsSchema = z.object({
5042
+ sub: z.string().min(1),
5043
+ email: z.string().optional(),
5044
+ email_verified: z.boolean().optional(),
5045
+ hd: z.string().optional(),
5046
+ name: z.string().optional(),
5047
+ picture: z.string().optional()
5048
+ });
5049
+ /**
5050
+ * Read Google ID token claims. Returns undefined for a malformed token, so
5051
+ * Better Auth redirects with `unable_to_get_user_info` instead of a 500.
5052
+ */
5053
+ function readGoogleClaims(idToken) {
5054
+ let payload;
5055
+ try {
5056
+ payload = decodeJwt(idToken);
5057
+ } catch {
5058
+ return;
5059
+ }
5060
+ const parsed = googleClaimsSchema.safeParse(payload);
5061
+ return parsed.success ? parsed.data : void 0;
5062
+ }
5165
5063
  function trimSlashes(value, leading) {
5166
5064
  let start = 0;
5167
5065
  let end = value.length;
@@ -5173,14 +5071,12 @@ function withHttps(host) {
5173
5071
  return /^https?:\/\//.test(host) ? host : `https://${host}`;
5174
5072
  }
5175
5073
  /** Resolve sign-in settings from dashboard options and environment. */
5176
- function resolveSignInAuthConfig(agentName, options = {}) {
5177
- const authPath = `/${trimSlashes(options.authPath?.trim() || DEFAULT_AUTH_PATH, true)}`;
5178
- const baseURL = trimSlashes(withHttps(options.baseURL?.trim() || resolveBaseUrl() || "http://localhost:3000"), false);
5074
+ function resolveSignInAuthConfig(agentName, allowedDomains, options = {}) {
5179
5075
  return {
5180
5076
  agentName,
5181
- allowlist: resolveSignInAllowlist(options),
5182
- authPath,
5183
- baseURL,
5077
+ allowedDomains,
5078
+ authPath: `/${trimSlashes(options.authPath?.trim() || DEFAULT_AUTH_PATH, true)}`,
5079
+ baseURL: trimSlashes(withHttps(options.baseURL?.trim() || resolveBaseUrl() || "http://localhost:3000"), false),
5184
5080
  sessionMaxAgeSeconds: options.sessionMaxAgeSeconds,
5185
5081
  trustedOrigins: options.trustedOrigins ?? readEnvList("JUNIOR_DASHBOARD_TRUSTED_ORIGINS") ?? []
5186
5082
  };
@@ -5192,8 +5088,8 @@ function required(value, name) {
5192
5088
  function createBetterAuth(config) {
5193
5089
  const secret = required(config.secret ?? process.env.BETTER_AUTH_SECRET ?? process.env.JUNIOR_SECRET, "JUNIOR_SECRET or BETTER_AUTH_SECRET");
5194
5090
  const sessionMaxAgeSeconds = config.sessionMaxAgeSeconds ?? DEFAULT_SESSION_MAX_AGE_SECONDS;
5195
- const { domains, emails } = config.allowlist;
5196
- const hostedDomain = domains.length === 1 && emails.length === 0 ? domains[0] : void 0;
5091
+ const { allowedDomains } = config;
5092
+ const hostedDomain = allowedDomains.length === 0 ? void 0 : allowedDomains.length === 1 ? allowedDomains[0] : "*";
5197
5093
  return betterAuth({
5198
5094
  appName: config.agentName,
5199
5095
  baseURL: config.baseURL,
@@ -5205,12 +5101,20 @@ function createBetterAuth(config) {
5205
5101
  clientSecret: required(config.googleClientSecret ?? process.env.GOOGLE_CLIENT_SECRET, "GOOGLE_CLIENT_SECRET"),
5206
5102
  hd: hostedDomain,
5207
5103
  prompt: "select_account",
5208
- mapProfileToUser(profile) {
5104
+ async getUserInfo(token) {
5105
+ if (!token.idToken) return null;
5106
+ const claims = readGoogleClaims(token.idToken);
5107
+ if (!claims) return null;
5108
+ if (!isAllowedDomain(claims.hd, allowedDomains)) return null;
5209
5109
  return {
5210
- email: profile.email,
5211
- emailVerified: profile.email_verified,
5212
- image: profile.picture,
5213
- name: profile.name
5110
+ user: {
5111
+ id: claims.sub,
5112
+ email: claims.email,
5113
+ emailVerified: claims.email_verified === true,
5114
+ image: claims.picture,
5115
+ name: claims.name
5116
+ },
5117
+ data: claims
5214
5118
  };
5215
5119
  }
5216
5120
  } },
@@ -5233,7 +5137,7 @@ function createBetterAuth(config) {
5233
5137
  const created = ctx.context.newSession;
5234
5138
  if (!created || !ctx.path.startsWith("/callback/")) return;
5235
5139
  const email = normalizeIdentityEmail(created.user.email);
5236
- if (!created.user.emailVerified || !email || !isSignInAllowed(email, config.allowlist)) return;
5140
+ if (!created.user.emailVerified || !email) return;
5237
5141
  const google = (await ctx.context.internalAdapter.findAccounts(created.user.id)).find((account) => account.providerId === "google");
5238
5142
  if (!google) throw new Error("Google sign-in has no Google account");
5239
5143
  await recordGoogleSignIn(getSqlExecutor(), {
@@ -5245,8 +5149,8 @@ function createBetterAuth(config) {
5245
5149
  });
5246
5150
  }
5247
5151
  /**
5248
- * Create the shared Google sign-in session. Better Auth starts on first use,
5249
- * so apps that never sign in need no Google credentials.
5152
+ * Create the Google sign-in session. Better Auth starts on first use, so apps
5153
+ * that never sign in need no Google credentials.
5250
5154
  */
5251
5155
  function createSignInAuth(config) {
5252
5156
  let auth;
@@ -5284,14 +5188,14 @@ function createSignInAuth(config) {
5284
5188
  }
5285
5189
  };
5286
5190
  }
5287
- //#endregion
5288
- //#region src/dashboard-routes.ts
5191
+ // src/dashboard-routes.ts
5289
5192
  const DASHBOARD_PACKAGE_NAME = "@sentry/junior-dashboard";
5290
5193
  /** Mount the dashboard app on the dashboard-owned host paths. */
5291
5194
  async function createDashboardRouteRegistrations(args) {
5292
5195
  if (!args.dashboard || args.dashboard.disabled) return [];
5293
5196
  const createDashboardApp = args.createDashboardApp ?? await loadDashboardAppFactory();
5294
5197
  return dashboardRouteRegistrations({
5198
+ allowedDomains: args.allowedDomains,
5295
5199
  auth: args.auth,
5296
5200
  authenticatedRoutes: args.authenticatedRoutes,
5297
5201
  conversationWorkQueue: args.conversationWorkQueue,
@@ -5415,7 +5319,7 @@ function routePatternMatchesConcretePath(pattern, concretePath) {
5415
5319
  const patternSegments = routeSegments(pattern);
5416
5320
  const pathSegments = routeSegments(concretePath);
5417
5321
  for (let index = 0; index < patternSegments.length; index += 1) {
5418
- const segment = patternSegments[index];
5322
+ const segment = patternSegments[index] ?? "";
5419
5323
  if (segment === "**" || segment === "*") return true;
5420
5324
  const value = pathSegments[index];
5421
5325
  if (!value || !routeSegmentMatches(segment, value)) return false;
@@ -5441,6 +5345,7 @@ function dashboardRouteRegistrations(args) {
5441
5345
  const dashboardOptions = {
5442
5346
  ...args.dashboard,
5443
5347
  agentName: botConfig.userName,
5348
+ allowedDomains: args.allowedDomains,
5444
5349
  ...args.auth ? { auth: args.auth } : void 0,
5445
5350
  authenticatedRoutes: args.authenticatedRoutes,
5446
5351
  conversationWorkQueue: args.conversationWorkQueue,
@@ -5460,8 +5365,7 @@ function validateDashboardRouteOwnership(args) {
5460
5365
  if (!args.dashboard || args.dashboard.disabled) return;
5461
5366
  for (const route of args.routes) if (dashboardOwnedRoutePath(route.path, args.dashboard, args.authenticatedRoutes)) throw new Error(`Plugin "${route.pluginName}" route "${route.path}" conflicts with core dashboard routes`);
5462
5367
  }
5463
- //#endregion
5464
- //#region src/app.ts
5368
+ // src/app.ts
5465
5369
  /** Resolve the public deployment URL used by ACP browser authorization. */
5466
5370
  function resolveAcpBaseURL(dashboard) {
5467
5371
  const configured = dashboard?.baseURL?.trim() || process.env.JUNIOR_BASE_URL?.trim();
@@ -5579,7 +5483,7 @@ async function createApp(options) {
5579
5483
  }) });
5580
5484
  let sandboxEgressTracePropagationDomains = [];
5581
5485
  let signInConfig;
5582
- let slackSignIn;
5486
+ let allowedDomains = [];
5583
5487
  try {
5584
5488
  sandboxEgressTracePropagationDomains = normalizeSandboxEgressTracePropagationDomains(options?.sandbox?.egressTracePropagationDomains);
5585
5489
  setSandboxResourceConfig(options?.sandbox);
@@ -5592,18 +5496,10 @@ async function createApp(options) {
5592
5496
  setRuntimeLimits(options?.limits);
5593
5497
  setSlackReactionConfig(options?.slack ?? {});
5594
5498
  if (options?.slack?.crossActorMidRunMode) setCrossActorMidRunMode(options.slack.crossActorMidRunMode);
5595
- const dashboardMounted = Boolean(dashboard && !dashboard.disabled);
5596
- if (isExperimentalFeatureEnabled("slack-sign-in") || dashboardMounted) signInConfig = resolveSignInAuthConfig(botConfig.userName, dashboard);
5597
- if (signInConfig && isExperimentalFeatureEnabled("slack-sign-in")) {
5598
- const { allowlist } = signInConfig;
5599
- if (!allowlist.domains.length && !allowlist.emails.length) throw new Error("experimental.slack-sign-in requires allowed Google domains or emails");
5600
- const maxAgeDays = options?.slack?.signInMaxAgeDays ?? 7;
5601
- if (!(maxAgeDays > 0)) throw new Error("slack.signInMaxAgeDays must be greater than 0");
5602
- slackSignIn = {
5603
- baseURL: signInConfig.baseURL,
5604
- maxAgeMs: maxAgeDays * 24 * 60 * 60 * 1e3
5605
- };
5606
- }
5499
+ assertNoLegacyAllowedDomains(Object.keys(dashboard ?? {}));
5500
+ allowedDomains = resolveAllowedDomains(options?.allowedDomains);
5501
+ if (allowedDomains.length === 0) logWarn("app.allowed_domains.unset", { "app.reason": "allowedDomains is empty, so any Slack workspace member can use Junior" });
5502
+ if (dashboard && !dashboard.disabled) signInConfig = resolveSignInAuthConfig(botConfig.userName, allowedDomains, dashboard);
5607
5503
  if (shouldValidatePluginCatalog) {
5608
5504
  pluginCatalogRuntime.getSignature();
5609
5505
  validatePluginRegistrations(configuredPlugins?.registrations ?? []);
@@ -5697,7 +5593,7 @@ async function createApp(options) {
5697
5593
  queue: conversationWorkQueue,
5698
5594
  services: runtimeServiceOverrides
5699
5595
  }),
5700
- ...slackSignIn ? { signIn: slackSignIn } : void 0
5596
+ allowedDomains
5701
5597
  };
5702
5598
  const app = new Hono();
5703
5599
  app.onError((err, c) => {
@@ -5714,6 +5610,7 @@ async function createApp(options) {
5714
5610
  ], "/api/acp", (c) => getAcpRuntime().handleRequest(c.req.raw));
5715
5611
  mountRoutes(app, pluginRoutes);
5716
5612
  mountRoutes(app, await createDashboardRouteRegistrations({
5613
+ allowedDomains,
5717
5614
  auth: signInAuth,
5718
5615
  authenticatedRoutes,
5719
5616
  conversationWorkQueue,
@@ -5736,19 +5633,6 @@ async function createApp(options) {
5736
5633
  app.get("/api/oauth/callback/:provider", (c) => {
5737
5634
  return GET$5(c.req.raw, c.req.param("provider"), waitUntil, { conversationWorkQueue });
5738
5635
  });
5739
- if (signInAuth && signInConfig && slackSignIn) {
5740
- const auth = signInAuth;
5741
- if (!dashboard || dashboard.disabled) app.on(["GET", "POST"], `${signInConfig.authPath}/*`, (c) => auth.handler(c.req.raw));
5742
- const { allowlist } = signInConfig;
5743
- const signIn = slackSignIn;
5744
- app.get(SLACK_SIGN_IN_PATH, (c) => handleSlackSignIn({
5745
- allowlist,
5746
- auth,
5747
- signIn,
5748
- request: c.req.raw,
5749
- state: getStateAdapter()
5750
- }));
5751
- }
5752
5636
  app.get("/api/internal/sandbox-egress/signals", (c) => {
5753
5637
  return GET(c.req.raw);
5754
5638
  });
@@ -5792,5 +5676,4 @@ async function createApp(options) {
5792
5676
  });
5793
5677
  return app;
5794
5678
  }
5795
- //#endregion
5796
5679
  export { JUNIOR_VERSION, createApp, defineJuniorPlugins };