@sentry/junior 0.264.0 → 0.266.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.
- package/README.md +1 -1
- package/dist/{adapter-BIbMSKlG.js → adapter-eRFA_naf.js} +1 -1
- package/dist/{admin-D4d0HXax.js → admin-tILpP51p.js} +1 -1
- package/dist/{agent-runner-CvRxb09K.js → agent-runner-BtYK7bht.js} +263 -198
- package/dist/api/schema.d.ts +216 -15
- package/dist/api/schema.js +5 -5
- package/dist/api.js +109 -42
- package/dist/{app-Buc5gIWz.d.ts → app-Csbi9dW7.d.ts} +0 -4
- package/dist/app.d.ts +1 -1
- package/dist/app.js +79 -390
- package/dist/{assistant-reply-BcJj_ORj.js → assistant-reply-UyzAfZQo.js} +1 -1
- package/dist/{automation-CWX0qL8U.js → automation-BKpY9LPa.js} +31 -10
- package/dist/{briefs-BFfIE5N6.js → briefs-DgfWMU7e.js} +5 -5
- package/dist/{catalog-runtime-R53MWcMi.js → catalog-runtime-DAJjAbSx.js} +1 -1
- package/dist/cli/chat.js +15 -15
- package/dist/cli/check.js +3 -3
- package/dist/cli/init.js +4 -18
- package/dist/cli/main.js +4 -4
- package/dist/cli/plugins.js +4 -4
- package/dist/cli/snapshot-create.js +4 -4
- package/dist/cli/upgrade.js +3 -3
- package/dist/{client-DpOwh_zX.js → client-B0YZfxNy.js} +3 -8
- package/dist/{config-BxPrFVJP.js → config-C0UwYqDK.js} +100 -3
- package/dist/{connections-BnTM1nRf.js → connections-Bwu3VORi.js} +11 -10
- package/dist/{conversation-B0baEwoA.js → conversation-DF4rUcjb.js} +6 -2
- package/dist/{conversation-privacy-ueJ6i-t9.js → conversation-privacy-CY7JVjxn.js} +1 -1
- package/dist/{credential-sync-DeDkof_D.js → credential-sync-VGAMUTGp.js} +20 -20
- package/dist/{agent-hooks-D_PbluRX.js → credentialed-enF5Bf3y.js} +3316 -179
- package/dist/{executor-D3WIS4vl.js → executor-TnWbvL09.js} +10 -300
- package/dist/{history-AY8rs-FR.js → history-C84mlAwO.js} +2 -1
- package/dist/{images-5VNK_yYC.js → images-BKQqSi5W.js} +3 -3
- package/dist/instrumentation.js +41 -25
- package/dist/{job-queue-BYHonCAH.js → job-queue-DBpHmKnd.js} +53 -14
- package/dist/{logging-DNQqsQ57.js → logging-Ce0mXZ8J.js} +19 -32
- package/dist/{message-CDTJISxL.js → message-VZ3DFpGb.js} +4 -4
- package/dist/nitro.d.ts +17 -2
- package/dist/nitro.js +26 -27
- package/dist/{oauth-callback-server-Bk4rbLOs.js → oauth-callback-server-CpqWLjVY.js} +2 -2
- package/dist/{prompt-CxatQVaj.js → prompt-BcCGlmg2.js} +2 -2
- package/dist/{registry-CfdUEk4N.js → registry-1BEIPdbT.js} +1 -1
- package/dist/{resolve-BXShI336.js → resolve-BSHHkEGE.js} +7 -106
- package/dist/{result-R35jcahx.js → result-CwOpzqdh.js} +8 -8
- package/dist/{runner-IC4Drh3Y.js → runner-CEaX04kz.js} +11 -11
- package/dist/{sandbox-egress-signals-C4RIfjb8.js → sandbox-egress-signals-BwtGHwqa.js} +1 -1
- package/dist/{schema-QidbykYl.js → schema-RsaBHxRH.js} +45 -4
- package/dist/{sentry-BBUlHih9.js → sentry-MDkYAVPV.js} +3 -6
- package/dist/{service-account-DJSRo2cL.js → service-account-6wC76eBZ.js} +5 -5
- package/dist/{service-account-DifohWyX.js → service-account-Dg4lIbHm.js} +3 -3
- package/dist/{session-stop-B9RRGC-P.js → session-stop-tZOw9AJD.js} +120 -80
- package/dist/{skills-DVJmS_ZP.js → skills-DzyGN7wd.js} +2 -2
- package/dist/{spawn-DkVYGfSY.js → spawn-6rokq7l_.js} +2 -2
- package/dist/{store-BvolNnx4.js → store-DcKkzrdt.js} +3 -3
- package/dist/{store-C_mHwAnR.js → store-FALy-JQb.js} +6 -6
- package/dist/{task-queue-BcEyPhtX.js → task-queue-Bg4RS2Gy.js} +14 -19
- package/dist/{task-runner-CiQj5M_9.js → task-runner-8N5LIkSg.js} +47 -29
- package/dist/{tasks-OgXmReUv.js → tasks-DDT-J3Rf.js} +17 -2078
- package/dist/{thread-state-XFvpWXE9.js → thread-state-cprEaxgl.js} +5 -5
- package/dist/{turn-failure-response-BjBAtnVt.js → turn-failure-response-C8sMdsdX.js} +8 -8
- package/dist/{turn-lifecycle-nvKL2rul.js → turn-lifecycle-DaBVoz7h.js} +2 -2
- package/dist/{turn-session-routing-DEMxHySb.js → turn-session-routing-a9CHX-w6.js} +1 -1
- package/dist/{validation-XOFldwvE.js → validation-C2lllinq.js} +1 -1
- package/dist/{version-C9f5hdHD.js → version-oaLfxxnf.js} +1 -1
- package/dist/version.js +1 -1
- package/dist/{viewer-BuPwzOC9.js → viewer-BpE6Z3qf.js} +22 -6
- package/dist/{web-input-4t7TYLsY.js → web-input-B-bMjD1V.js} +147 -48
- package/dist/{work-C_aF6JN5.js → work-VX1SHWha.js} +52 -51
- package/dist/{worker-DR633sA-.js → worker-hook-y_Y.js} +5 -5
- package/package.json +10 -9
- package/dist/profile-ieODOp4u.js +0 -582
package/dist/app.js
CHANGED
|
@@ -1,47 +1,46 @@
|
|
|
1
|
-
import { C as automationVersionOf, Cn as
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import { C as automationVersionOf, Cn as getConfigDefaults, Q as projectConversationMessages, Y as appendConversationMessages, _n as isExperimentalFeatureEnabled, b as admitEventAutomationRun, c as withScheduledAutomationLock, fn as getThreadStopDecision, gn as getExperimentalFeatures, i as readScheduledAutomation, l as blockEventAutomation, ln as SubscribedReplyReason, n as listScheduledAutomationsForTeam, o as saveScheduledAutomationInLock, p as findMatchingEventAutomations, s as scheduledRunId, tt as settleConversationTitleWork, u as collectEventAutomationMatchKeys, vn as setExperimentalFeatures, wn as setConfigDefaults, x as eventAutomationRunLimitReason } from "./tasks-DDT-J3Rf.js";
|
|
2
|
+
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-C0UwYqDK.js";
|
|
3
|
+
import { C as withContext, M as JUNIOR_WORKSPACE_SNAPSHOT_JOB_CALLBACK_ROUTE, R as normalizeIdentityEmail, T as withSpan, f as logException, k as JUNIOR_PLUGIN_TASK_CALLBACK_ROUTE, m as logWarn, p as logInfo, r as createRequestContext, w as withLogContext, y as setSpanAttributes } from "./logging-Ce0mXZ8J.js";
|
|
4
|
+
import { n as captureMessage } from "./sentry-MDkYAVPV.js";
|
|
5
|
+
import { t as JUNIOR_VERSION } from "./version-oaLfxxnf.js";
|
|
6
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 {
|
|
7
|
+
import { P as recordGoogleSignIn, d as getConversationStore, f as getDb, h as withConversationEventLock, l as getConversationEventStore, p as getSqlExecutor, r as readActorIdentity, v as withConversationMutationLock } from "./viewer-BpE6Z3qf.js";
|
|
8
8
|
import { a as juniorAgentInvocations, d as juniorDestinations, i as juniorAgentBindings, s as juniorConversations } from "./agent-invocations-CxKldAeB.js";
|
|
9
|
-
import { a as juniorAutomationRuns, f as juniorConversationBriefs, h as juniorConversationEvents, s as juniorAutomations } from "./executor-
|
|
10
|
-
import {
|
|
11
|
-
import { n as
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import { r as getStateAdapter, s as withLock$1 } from "./adapter-BIbMSKlG.js";
|
|
9
|
+
import { a as juniorAutomationRuns, f as juniorConversationBriefs, h as juniorConversationEvents, s as juniorAutomations } from "./executor-TnWbvL09.js";
|
|
10
|
+
import { n as pluginCatalogRuntime } from "./catalog-runtime-DAJjAbSx.js";
|
|
11
|
+
import { C as requestAttachmentDeletion, H as recordSubagentEnded, J as processWorkspaceSnapshotJob, L as effectiveTaskOutcomes, M as logScheduledAutomationRunSkipped, N as scheduledAutomationRunAttributes, T as parseSlackThreadId, V as stopConversationSession, Y as ingestEvent, _ as unpublishedArtifactHeaders, g as readPublicArtifact, h as publicArtifactHeaders, n as executeAgentRun, t as createAgentRunner, v as lookupSlackUserProfile, x as collectAttachmentGarbage } from "./agent-runner-BtYK7bht.js";
|
|
12
|
+
import { An as createPluginLogger, Dn as createPluginState, Ft as collectEventMatchKeys, G as isVercelSandboxEgressRequest, Gt as bindSlackDirectCredentialSubject, Ht as takeDueTimerWatches, J as consumeSandboxEgressAuthRequiredSignal, Jn as resolveRootVisibility, Jt as verifySlackDirectCredentialSubject, K as proxyVercelSandboxEgressRequest, Kt as verifyEventAutomationCredentialSubject, St as slackExternalRefIdSchema, Ut as bindEventAutomationCredentialSubject, Wt as bindScheduledAutomationCredentialSubject, Y as consumeSandboxEgressPermissionDeniedSignal, Z as parseSandboxEgressCredentialToken, Zn as listConversationAnnotations, at as formatProviderLabel, c as getPluginRoutes, cn as runWithWorkspaceTeamId, ct as startOAuthFlow, en as getSlackClient, fn as getDashboardTaskLink, h as validatePlugins, jn as readConversationAccessFromSql, m as setPlugins, n as createUserTokenStore, nn as isDmChannel, nr as createPluginCache, p as getPlugins, pn as setDashboardConversationLinkOptions, pt as slackMention, q as clearSandboxEgressSignals, qt as verifyScheduledAutomationCredentialSubject, rr as createCache, rt as normalizeSandboxEgressTracePropagationDomains, s as getPluginApiRoutes, sn as getWorkspaceTeamId, st as resolveBaseUrl, un as getDashboardConversationLink, v as setBriefsConfig, xt as slackEntitySchema, zt as findMatchingWatches } from "./credentialed-enF5Bf3y.js";
|
|
13
|
+
import { r as getStateAdapter, s as withLock$1 } from "./adapter-eRFA_naf.js";
|
|
15
14
|
import { n as getNextRunAtMs } from "./cadence-R7Em4RjE.js";
|
|
16
|
-
import { M as annotationCard } from "./conversation-
|
|
17
|
-
import { b as listPendingAgentInvocationMailboxAppends, x as listPendingAgentInvocationResults } from "./store-
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
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-
|
|
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-
|
|
22
|
-
import { D as scheduledRunSchema } from "./automation-
|
|
23
|
-
import { n as validatePluginRegistrations, t as validatePluginEgressCredentialHooks } from "./validation-
|
|
15
|
+
import { M as annotationCard } from "./conversation-DF4rUcjb.js";
|
|
16
|
+
import { b as listPendingAgentInvocationMailboxAppends, x as listPendingAgentInvocationResults } from "./store-DcKkzrdt.js";
|
|
17
|
+
import { C as eventGuidance, N as renderTaskInput, d as getEventCatalog, f as SLACK_EVENT_NAMESPACE, g as slackChannelMessageRunsAutomation, h as slackChannelMessageReplyThreadTs, m as slackChannelMessageEvent } from "./session-stop-tZOw9AJD.js";
|
|
18
|
+
import { c as setSandboxResourceConfig, o as getSandboxResourceConfig } from "./resolve-BSHHkEGE.js";
|
|
19
|
+
import { a as getVercelConversationWorkQueue, d as getQueueProvider, 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-DBpHmKnd.js";
|
|
20
|
+
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-FALy-JQb.js";
|
|
21
|
+
import { D as scheduledRunSchema } from "./automation-BKpY9LPa.js";
|
|
22
|
+
import { n as validatePluginRegistrations, t as validatePluginEgressCredentialHooks } from "./validation-C2lllinq.js";
|
|
24
23
|
import { a as pluginRuntimeRegistrationsFromPluginSet, n as pluginCatalogConfigFromEnv, r as pluginCatalogConfigFromPluginSet, t as defineJuniorPlugins } from "./plugins-DOm9Y6qI.js";
|
|
25
|
-
import { A as THREAD_OPTOUT_ACK, C as buildSlackInboundMessage, D as normalizeIncomingSlackThreadId, E as stopSlackThread, F as renderSlackObjectCard, I as
|
|
26
|
-
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-
|
|
27
|
-
import { o as getAuthPausedConversationTurnId, t as enqueueAgentInvocationResult } from "./result-
|
|
28
|
-
import { r as enqueueAgentInvocation } from "./work-
|
|
29
|
-
import { s as coerceThreadConversationState } from "./thread-state-
|
|
30
|
-
import { o as unlinkProvider } from "./connections-
|
|
31
|
-
import { a as GET$4, i as publishAppHomeView, r as GET$5, t as receiveLocalOAuthCredential } from "./credential-sync-
|
|
32
|
-
import { a as registerVercelPluginTaskDevConsumer, n as createVercelPluginTaskCallback, s as queueCallback } from "./task-queue-
|
|
33
|
-
import { t as processConversationWork } from "./worker-
|
|
34
|
-
import { t as bindMessageAgent } from "./message-
|
|
35
|
-
import { t as bindSpawnAgent } from "./spawn-
|
|
24
|
+
import { A as THREAD_OPTOUT_ACK, C as buildSlackInboundMessage, D as normalizeIncomingSlackThreadId, E as stopSlackThread, F as renderSlackObjectCard, I as getAttachmentStorage, 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-B-bMjD1V.js";
|
|
25
|
+
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-8N5LIkSg.js";
|
|
26
|
+
import { o as getAuthPausedConversationTurnId, t as enqueueAgentInvocationResult } from "./result-CwOpzqdh.js";
|
|
27
|
+
import { r as enqueueAgentInvocation } from "./work-VX1SHWha.js";
|
|
28
|
+
import { s as coerceThreadConversationState } from "./thread-state-cprEaxgl.js";
|
|
29
|
+
import { o as unlinkProvider } from "./connections-Bwu3VORi.js";
|
|
30
|
+
import { a as GET$4, i as publishAppHomeView, r as GET$5, t as receiveLocalOAuthCredential } from "./credential-sync-VGAMUTGp.js";
|
|
31
|
+
import { a as registerVercelPluginTaskDevConsumer, n as createVercelPluginTaskCallback, s as queueCallback } from "./task-queue-Bg4RS2Gy.js";
|
|
32
|
+
import { t as processConversationWork } from "./worker-hook-y_Y.js";
|
|
33
|
+
import { t as bindMessageAgent } from "./message-VZ3DFpGb.js";
|
|
34
|
+
import { t as bindSpawnAgent } from "./spawn-6rokq7l_.js";
|
|
36
35
|
import { createRequire } from "node:module";
|
|
37
36
|
import { Hono } from "hono";
|
|
38
37
|
import { z } from "zod";
|
|
39
38
|
import { createHash, randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
|
|
40
39
|
import { and, asc, eq, inArray, isNotNull, isNull, lte, or, sql } from "drizzle-orm";
|
|
41
|
-
import { EVENT_SUMMARY_MAX_LENGTH, EVENT_TEXT_MAX_LENGTH, dispatchOptionsSchema, eventSchema, isSlackDestination, userSchema } from "@sentry/junior-plugin-api";
|
|
40
|
+
import { EVENT_SUMMARY_MAX_LENGTH, EVENT_TEXT_MAX_LENGTH, dispatchOptionsSchema, eventSchema, eventTriggerFiltersText, isSlackDestination, userSchema } from "@sentry/junior-plugin-api";
|
|
42
41
|
import { pathToFileURL } from "node:url";
|
|
43
42
|
import { setTimeout as setTimeout$1 } from "node:timers/promises";
|
|
44
|
-
import {
|
|
43
|
+
import { decodeJwt } from "jose";
|
|
45
44
|
import { ChannelImpl, ThreadImpl } from "chat";
|
|
46
45
|
import * as acp from "@agentclientprotocol/sdk";
|
|
47
46
|
import { createAuthMiddleware } from "better-auth/api";
|
|
@@ -1414,7 +1413,7 @@ async function GET$1(request, options = {}) {
|
|
|
1414
1413
|
if (!verifyRetentionRequest(request)) return new Response("Unauthorized", { status: 401 });
|
|
1415
1414
|
try {
|
|
1416
1415
|
const result = await runRetentionPurge(getSqlExecutor(), {
|
|
1417
|
-
attachmentStorage: options.attachmentStorage ??
|
|
1416
|
+
attachmentStorage: options.attachmentStorage ?? getAttachmentStorage(),
|
|
1418
1417
|
nowMs: Date.now()
|
|
1419
1418
|
});
|
|
1420
1419
|
return Response.json(result, { status: 200 });
|
|
@@ -1423,317 +1422,10 @@ async function GET$1(request, options = {}) {
|
|
|
1423
1422
|
return new Response("Retention purge failed", { status: 500 });
|
|
1424
1423
|
}
|
|
1425
1424
|
}
|
|
1426
|
-
// src/chat/sandbox/egress/oidc.ts
|
|
1427
|
-
const OIDC_DISCOVERY_CACHE_TTL_MS = 36e5;
|
|
1428
|
-
const OIDC_DISCOVERY_CACHE_MAX_ENTRIES = 8;
|
|
1429
|
-
const jwksByIssuer = /* @__PURE__ */ new Map();
|
|
1430
|
-
function buildDiscoveryUrl(issuer) {
|
|
1431
|
-
const url = new URL(issuer);
|
|
1432
|
-
if (url.protocol !== "https:" || url.hostname !== "oidc.vercel.com") throw new Error("Unexpected Vercel OIDC issuer");
|
|
1433
|
-
url.pathname = `${url.pathname.replace(/\/$/, "")}/.well-known/openid-configuration`;
|
|
1434
|
-
url.search = "";
|
|
1435
|
-
url.hash = "";
|
|
1436
|
-
return url;
|
|
1437
|
-
}
|
|
1438
|
-
function buildJwksUrl(value) {
|
|
1439
|
-
const url = new URL(value);
|
|
1440
|
-
if (url.protocol !== "https:") throw new Error("Vercel OIDC discovery jwks_uri must use HTTPS");
|
|
1441
|
-
return url;
|
|
1442
|
-
}
|
|
1443
|
-
async function getJwks(issuer) {
|
|
1444
|
-
const now = Date.now();
|
|
1445
|
-
const cached = jwksByIssuer.get(issuer);
|
|
1446
|
-
if (cached && cached.expiresAtMs > now) return cached.jwks;
|
|
1447
|
-
if (cached) jwksByIssuer.delete(issuer);
|
|
1448
|
-
const response = await fetch(buildDiscoveryUrl(issuer), { redirect: "error" });
|
|
1449
|
-
if (!response.ok) throw new Error("Unable to load Vercel OIDC discovery metadata");
|
|
1450
|
-
const config = await response.json();
|
|
1451
|
-
if (!config.jwks_uri) throw new Error("Vercel OIDC discovery metadata did not include jwks_uri");
|
|
1452
|
-
const jwks = createRemoteJWKSet(buildJwksUrl(config.jwks_uri));
|
|
1453
|
-
if (!jwksByIssuer.has(issuer) && jwksByIssuer.size >= OIDC_DISCOVERY_CACHE_MAX_ENTRIES) {
|
|
1454
|
-
const oldestIssuer = jwksByIssuer.keys().next().value;
|
|
1455
|
-
if (oldestIssuer) jwksByIssuer.delete(oldestIssuer);
|
|
1456
|
-
}
|
|
1457
|
-
jwksByIssuer.set(issuer, {
|
|
1458
|
-
jwks,
|
|
1459
|
-
expiresAtMs: now + OIDC_DISCOVERY_CACHE_TTL_MS
|
|
1460
|
-
});
|
|
1461
|
-
return jwks;
|
|
1462
|
-
}
|
|
1463
|
-
/**
|
|
1464
|
-
* Verify Vercel signed this Sandbox firewall proxy request for the active VM session.
|
|
1465
|
-
*
|
|
1466
|
-
* `currentDate` is the time for the `exp` and `nbf` checks. It defaults to
|
|
1467
|
-
* now. Evals pass the real time because they replace `Date`.
|
|
1468
|
-
*/
|
|
1469
|
-
async function verifyVercelSandboxOidcToken(token, options = {}) {
|
|
1470
|
-
const unverified = decodeJwt(token);
|
|
1471
|
-
if (typeof unverified.iss !== "string") throw new Error("Vercel OIDC token did not include an issuer");
|
|
1472
|
-
const jwks = await getJwks(unverified.iss);
|
|
1473
|
-
return (await jwtVerify(token, jwks, {
|
|
1474
|
-
issuer: unverified.iss,
|
|
1475
|
-
...options.currentDate ? { currentDate: options.currentDate } : void 0
|
|
1476
|
-
})).payload;
|
|
1477
|
-
}
|
|
1478
|
-
// src/chat/sandbox/egress/proxy.ts
|
|
1479
|
-
const OIDC_TOKEN_HEADER = "vercel-sandbox-oidc-token";
|
|
1480
|
-
const FORWARDED_HOST_HEADER = "vercel-forwarded-host";
|
|
1481
|
-
const FORWARDED_SCHEME_HEADER = "vercel-forwarded-scheme";
|
|
1482
|
-
const FORWARDED_PORT_HEADER = "vercel-forwarded-port";
|
|
1483
|
-
const FORWARDED_PATH_HEADER = "vercel-forwarded-path";
|
|
1484
|
-
function jsonError(message, status) {
|
|
1485
|
-
return Response.json({ error: message }, { status });
|
|
1486
|
-
}
|
|
1487
|
-
function egressAttributes(input) {
|
|
1488
|
-
return {
|
|
1489
|
-
...input.egressId ? { "app.sandbox.egress_id": input.egressId } : void 0,
|
|
1490
|
-
...input.provider ? { "app.provider.name": input.provider } : void 0,
|
|
1491
|
-
...input.host ? { "server.address": input.host } : void 0,
|
|
1492
|
-
...input.method ? { "http.request.method": input.method } : void 0,
|
|
1493
|
-
...input.path ? { "url.path": input.path } : void 0,
|
|
1494
|
-
...input.status ? { "http.response.status_code": input.status } : void 0
|
|
1495
|
-
};
|
|
1496
|
-
}
|
|
1497
|
-
function credentialTokenFromRequest(request) {
|
|
1498
|
-
const pathname = new URL(request.url).pathname;
|
|
1499
|
-
const prefix = `${SANDBOX_EGRESS_PROXY_PATH}/`;
|
|
1500
|
-
if (!pathname.startsWith(prefix)) return;
|
|
1501
|
-
const token = pathname.slice(prefix.length).split("/")[0];
|
|
1502
|
-
if (!token) return;
|
|
1503
|
-
try {
|
|
1504
|
-
return decodeURIComponent(token);
|
|
1505
|
-
} catch {
|
|
1506
|
-
return;
|
|
1507
|
-
}
|
|
1508
|
-
}
|
|
1509
|
-
function redactedProxyPath(pathname) {
|
|
1510
|
-
if (pathname.startsWith(`/api/internal/sandbox-egress/`)) return `${SANDBOX_EGRESS_PROXY_PATH}/<token>`;
|
|
1511
|
-
return pathname;
|
|
1512
|
-
}
|
|
1513
|
-
function routingAttributes(request, upstreamUrl) {
|
|
1514
|
-
const attributes = { "app.sandbox.egress.proxy_path": redactedProxyPath(new URL(request.url).pathname) };
|
|
1515
|
-
if (upstreamUrl) {
|
|
1516
|
-
attributes["app.sandbox.egress.upstream_path"] = upstreamUrl.pathname;
|
|
1517
|
-
const gitService = upstreamUrl.searchParams.get("service");
|
|
1518
|
-
if (upstreamUrl.hostname.toLowerCase() === "github.com" && (gitService === "git-upload-pack" || gitService === "git-receive-pack")) attributes["app.sandbox.egress.git_service"] = gitService;
|
|
1519
|
-
}
|
|
1520
|
-
return attributes;
|
|
1521
|
-
}
|
|
1522
|
-
function normalizeHost(value) {
|
|
1523
|
-
const trimmed = value.trim().toLowerCase();
|
|
1524
|
-
if (!trimmed || trimmed.includes("/") || trimmed.includes("\\") || trimmed.includes(":")) return;
|
|
1525
|
-
return trimmed.replace(/\.$/, "");
|
|
1526
|
-
}
|
|
1527
|
-
function normalizeScheme(value) {
|
|
1528
|
-
return value.trim().toLowerCase() === "https" ? "https" : void 0;
|
|
1529
|
-
}
|
|
1530
|
-
function normalizePort(value) {
|
|
1531
|
-
if (!value) return;
|
|
1532
|
-
const trimmed = value.trim();
|
|
1533
|
-
if (!/^\d{1,5}$/.test(trimmed)) return;
|
|
1534
|
-
const port = Number.parseInt(trimmed, 10);
|
|
1535
|
-
return port >= 1 && port <= 65535 ? trimmed : void 0;
|
|
1536
|
-
}
|
|
1537
|
-
function sandboxIdFromPayload(payload) {
|
|
1538
|
-
return typeof payload.sandbox_id === "string" ? payload.sandbox_id : void 0;
|
|
1539
|
-
}
|
|
1540
|
-
function normalizedForwardedPath(path) {
|
|
1541
|
-
if (!path.startsWith("/") || path.startsWith("//") || path.includes("#") || /[\r\n]/.test(path)) return {
|
|
1542
|
-
ok: false,
|
|
1543
|
-
error: "Invalid forwarded path"
|
|
1544
|
-
};
|
|
1545
|
-
try {
|
|
1546
|
-
const url = new URL(path, "https://sandbox-forwarded.local");
|
|
1547
|
-
return {
|
|
1548
|
-
ok: true,
|
|
1549
|
-
path: `${url.pathname}${url.search}`
|
|
1550
|
-
};
|
|
1551
|
-
} catch {
|
|
1552
|
-
return {
|
|
1553
|
-
ok: false,
|
|
1554
|
-
error: "Invalid forwarded path"
|
|
1555
|
-
};
|
|
1556
|
-
}
|
|
1557
|
-
}
|
|
1558
|
-
function upstreamPath(request) {
|
|
1559
|
-
const forwardedPath = request.headers.get(FORWARDED_PATH_HEADER);
|
|
1560
|
-
if (!forwardedPath?.trim()) return {
|
|
1561
|
-
ok: false,
|
|
1562
|
-
error: "Missing forwarded path"
|
|
1563
|
-
};
|
|
1564
|
-
return normalizedForwardedPath(forwardedPath.trim());
|
|
1565
|
-
}
|
|
1566
|
-
/**
|
|
1567
|
-
* Rebuild the HTTPS upstream URL from Vercel forwarding headers.
|
|
1568
|
-
*
|
|
1569
|
-
* This is the proxy's wire-format boundary for forwarded requests: host, path,
|
|
1570
|
-
* scheme, and port must normalize before the request can reach provider egress.
|
|
1571
|
-
*/
|
|
1572
|
-
function buildUpstreamUrl(request) {
|
|
1573
|
-
const forwardedHost = request.headers.get(FORWARDED_HOST_HEADER);
|
|
1574
|
-
if (!forwardedHost?.trim()) return {
|
|
1575
|
-
ok: false,
|
|
1576
|
-
error: "Missing forwarded host"
|
|
1577
|
-
};
|
|
1578
|
-
const host = normalizeHost(forwardedHost);
|
|
1579
|
-
if (!host) return {
|
|
1580
|
-
ok: false,
|
|
1581
|
-
error: "Invalid forwarded host"
|
|
1582
|
-
};
|
|
1583
|
-
const forwardedScheme = request.headers.get(FORWARDED_SCHEME_HEADER);
|
|
1584
|
-
if (!forwardedScheme?.trim()) return {
|
|
1585
|
-
ok: false,
|
|
1586
|
-
error: "Missing forwarded scheme"
|
|
1587
|
-
};
|
|
1588
|
-
const scheme = normalizeScheme(forwardedScheme);
|
|
1589
|
-
if (!scheme) return {
|
|
1590
|
-
ok: false,
|
|
1591
|
-
error: "Forwarded scheme must be https"
|
|
1592
|
-
};
|
|
1593
|
-
const forwardedPort = request.headers.get(FORWARDED_PORT_HEADER);
|
|
1594
|
-
const port = normalizePort(forwardedPort);
|
|
1595
|
-
if (forwardedPort && !port) return {
|
|
1596
|
-
ok: false,
|
|
1597
|
-
error: "Invalid forwarded port"
|
|
1598
|
-
};
|
|
1599
|
-
const path = upstreamPath(request);
|
|
1600
|
-
if (!path.ok) return {
|
|
1601
|
-
ok: false,
|
|
1602
|
-
error: path.error
|
|
1603
|
-
};
|
|
1604
|
-
try {
|
|
1605
|
-
return {
|
|
1606
|
-
ok: true,
|
|
1607
|
-
url: new URL(`${scheme}://${host}${port ? `:${port}` : ""}${path.path}`)
|
|
1608
|
-
};
|
|
1609
|
-
} catch {
|
|
1610
|
-
return {
|
|
1611
|
-
ok: false,
|
|
1612
|
-
error: "Invalid forwarded URL"
|
|
1613
|
-
};
|
|
1614
|
-
}
|
|
1615
|
-
}
|
|
1616
|
-
/**
|
|
1617
|
-
* Name the Conversation and the accountable person from the verified token.
|
|
1618
|
-
* Each proxy request is a new HTTP request with no run log context, so the
|
|
1619
|
-
* proxy binds the same fields that the run binds.
|
|
1620
|
-
*/
|
|
1621
|
-
function sandboxEgressLogContext(context) {
|
|
1622
|
-
return {
|
|
1623
|
-
...context.conversationId ? { conversationId: context.conversationId } : void 0,
|
|
1624
|
-
...credentialLogContext(context.credentials)
|
|
1625
|
-
};
|
|
1626
|
-
}
|
|
1627
|
-
/** Continue inbound trace context only after sandbox egress verification succeeds. */
|
|
1628
|
-
function continueSandboxEgressTrace(request, upstreamHost, tracePropagation, credentialContext, callback) {
|
|
1629
|
-
const sentryTrace = request.headers.get("sentry-trace") ?? void 0;
|
|
1630
|
-
const baggage = request.headers.get("baggage") ?? void 0;
|
|
1631
|
-
const logContext = sandboxEgressLogContext(credentialContext);
|
|
1632
|
-
const run = () => withSpan("sandbox.egress", "http.server", logContext, async () => {
|
|
1633
|
-
setSentryUser(logContext.userId ? { id: logContext.userId } : void 0);
|
|
1634
|
-
return await callback();
|
|
1635
|
-
}, {
|
|
1636
|
-
"http.request.method": request.method,
|
|
1637
|
-
"url.path": redactedProxyPath(new URL(request.url).pathname)
|
|
1638
|
-
});
|
|
1639
|
-
if (!shouldPropagateSandboxEgressTrace(upstreamHost, tracePropagation) || !sentryTrace && !baggage) return run();
|
|
1640
|
-
return continueTrace({
|
|
1641
|
-
sentryTrace,
|
|
1642
|
-
baggage
|
|
1643
|
-
}, run);
|
|
1644
|
-
}
|
|
1645
|
-
/**
|
|
1646
|
-
* Return whether a request carries the forwarding headers expected from Vercel.
|
|
1647
|
-
*
|
|
1648
|
-
* This is only a cheap classifier for routing into the proxy handler. Real
|
|
1649
|
-
* authentication happens in `proxySandboxEgressRequest` by verifying the OIDC
|
|
1650
|
-
* token and signed Junior credential context.
|
|
1651
|
-
*/
|
|
1652
|
-
function isSandboxEgressForwardedRequest(request) {
|
|
1653
|
-
return Boolean(request.headers.get(OIDC_TOKEN_HEADER)?.trim() && request.headers.get(FORWARDED_HOST_HEADER)?.trim() && request.headers.get(FORWARDED_SCHEME_HEADER)?.trim());
|
|
1654
|
-
}
|
|
1655
|
-
/**
|
|
1656
|
-
* Handle one forwarded sandbox egress request.
|
|
1657
|
-
*
|
|
1658
|
-
* This is the public proxy boundary: it rejects unauthenticated VM requests,
|
|
1659
|
-
* rejects forwarded URLs outside plugin-owned provider domains, rejects signed
|
|
1660
|
-
* credential contexts that do not match the active VM id, and only then asks
|
|
1661
|
-
* `execute.ts` to issue credentials and contact the upstream provider.
|
|
1662
|
-
*/
|
|
1663
|
-
async function proxySandboxEgressRequest(request, deps = {}) {
|
|
1664
|
-
const oidcToken = request.headers.get(OIDC_TOKEN_HEADER)?.trim();
|
|
1665
|
-
if (!oidcToken) return jsonError("Missing Vercel Sandbox OIDC token", 401);
|
|
1666
|
-
let oidcPayload;
|
|
1667
|
-
try {
|
|
1668
|
-
oidcPayload = await (deps.verifyOidc ?? verifyVercelSandboxOidcToken)(oidcToken);
|
|
1669
|
-
} catch (error) {
|
|
1670
|
-
logWarn("sandbox.egress.oidc_verification.failed", { "app.sandbox.oidc_error": error instanceof Error ? error.message : String(error) });
|
|
1671
|
-
return jsonError("Invalid Vercel Sandbox OIDC token", 401);
|
|
1672
|
-
}
|
|
1673
|
-
const activeEgressId = sandboxIdFromPayload(oidcPayload);
|
|
1674
|
-
if (!activeEgressId) {
|
|
1675
|
-
logWarn("sandbox.egress.oidc_session.missing", {
|
|
1676
|
-
"http.request.method": request.method,
|
|
1677
|
-
"url.path": redactedProxyPath(new URL(request.url).pathname)
|
|
1678
|
-
});
|
|
1679
|
-
return jsonError("Vercel Sandbox OIDC token did not include sandbox_id", 401);
|
|
1680
|
-
}
|
|
1681
|
-
const upstreamResult = buildUpstreamUrl(request);
|
|
1682
|
-
if (!upstreamResult.ok) {
|
|
1683
|
-
logWarn("sandbox.egress.upstream_url.invalid", {
|
|
1684
|
-
...egressAttributes({
|
|
1685
|
-
egressId: activeEgressId,
|
|
1686
|
-
method: request.method,
|
|
1687
|
-
path: redactedProxyPath(new URL(request.url).pathname),
|
|
1688
|
-
status: 400
|
|
1689
|
-
}),
|
|
1690
|
-
...routingAttributes(request)
|
|
1691
|
-
});
|
|
1692
|
-
return jsonError(upstreamResult.error, 400);
|
|
1693
|
-
}
|
|
1694
|
-
const upstreamUrl = upstreamResult.url;
|
|
1695
|
-
const provider = resolveSandboxEgressProviderForHost(upstreamUrl.hostname);
|
|
1696
|
-
if (!provider) {
|
|
1697
|
-
logWarn("sandbox.egress.provider.unresolved", {
|
|
1698
|
-
...egressAttributes({
|
|
1699
|
-
egressId: activeEgressId,
|
|
1700
|
-
host: upstreamUrl.hostname,
|
|
1701
|
-
method: request.method,
|
|
1702
|
-
path: upstreamUrl.pathname,
|
|
1703
|
-
status: 403
|
|
1704
|
-
}),
|
|
1705
|
-
...routingAttributes(request, upstreamUrl)
|
|
1706
|
-
});
|
|
1707
|
-
return jsonError("No provider owns forwarded host", 403);
|
|
1708
|
-
}
|
|
1709
|
-
const credentialContext = parseSandboxEgressCredentialToken(credentialTokenFromRequest(request));
|
|
1710
|
-
if (!credentialContext || credentialContext.egressId !== activeEgressId) {
|
|
1711
|
-
logWarn("sandbox.egress.credential_context.unauthorized", {
|
|
1712
|
-
...egressAttributes({
|
|
1713
|
-
egressId: activeEgressId,
|
|
1714
|
-
host: upstreamUrl.hostname,
|
|
1715
|
-
method: request.method,
|
|
1716
|
-
path: upstreamUrl.pathname,
|
|
1717
|
-
provider,
|
|
1718
|
-
status: 403
|
|
1719
|
-
}),
|
|
1720
|
-
...routingAttributes(request, upstreamUrl)
|
|
1721
|
-
});
|
|
1722
|
-
return jsonError("Sandbox egress credential context is not authorized", 403);
|
|
1723
|
-
}
|
|
1724
|
-
return await continueSandboxEgressTrace(request, upstreamUrl.hostname, deps.tracePropagation ?? {}, credentialContext, async () => await executeCredentialedEgressRequest({
|
|
1725
|
-
activeEgressId,
|
|
1726
|
-
credentialContext,
|
|
1727
|
-
deps,
|
|
1728
|
-
provider,
|
|
1729
|
-
request,
|
|
1730
|
-
upstreamUrl
|
|
1731
|
-
}));
|
|
1732
|
-
}
|
|
1733
1425
|
// src/handlers/sandbox-egress-proxy.ts
|
|
1734
1426
|
/** Handles Vercel Sandbox firewall egress proxy requests. */
|
|
1735
1427
|
async function ALL(request, options = {}) {
|
|
1736
|
-
return await
|
|
1428
|
+
return await proxyVercelSandboxEgressRequest(request, {
|
|
1737
1429
|
interceptHttp: options.interceptHttp,
|
|
1738
1430
|
tracePropagation: options.tracePropagation,
|
|
1739
1431
|
verifyOidc: options.verifyOidc
|
|
@@ -1741,7 +1433,7 @@ async function ALL(request, options = {}) {
|
|
|
1741
1433
|
}
|
|
1742
1434
|
/** Return whether a request should be routed through sandbox egress proxying. */
|
|
1743
1435
|
function isSandboxEgressRequest(request) {
|
|
1744
|
-
return
|
|
1436
|
+
return isVercelSandboxEgressRequest(request);
|
|
1745
1437
|
}
|
|
1746
1438
|
// src/handlers/sandbox-egress-route.ts
|
|
1747
1439
|
/**
|
|
@@ -2454,7 +2146,7 @@ function dateField(key, label, value, empty) {
|
|
|
2454
2146
|
function renderAutomationDetails(automation) {
|
|
2455
2147
|
const url = getDashboardTaskLink(automation.id);
|
|
2456
2148
|
if (!url) return void 0;
|
|
2457
|
-
const fields = [textField("status", "Status", automation.kind === "scheduled" ? automation.status : automation.
|
|
2149
|
+
const fields = [textField("status", "Status", automation.kind === "scheduled" ? automation.status : automation.trigger.problems.length === 0 ? "ready" : "unavailable"), {
|
|
2458
2150
|
...textField("description", "Instruction", automation.instruction),
|
|
2459
2151
|
format: "markdown",
|
|
2460
2152
|
long: true
|
|
@@ -2464,15 +2156,19 @@ function renderAutomationDetails(automation) {
|
|
|
2464
2156
|
long: true
|
|
2465
2157
|
}, dateField("next_run", "Next run", automation.nextRunAt, "None"));
|
|
2466
2158
|
else {
|
|
2159
|
+
const { trigger } = automation;
|
|
2467
2160
|
fields.push(textField("source", "Source", automation.source), {
|
|
2468
2161
|
...textField("resource", "Resource", automation.resource),
|
|
2469
2162
|
long: true
|
|
2470
2163
|
}, {
|
|
2471
|
-
...textField("events", "Events",
|
|
2164
|
+
...textField("events", "Events", trigger.events.join(", ")),
|
|
2165
|
+
long: true
|
|
2166
|
+
}, {
|
|
2167
|
+
...textField("filters", "Filters", trigger.filters.length > 0 ? eventTriggerFiltersText(trigger.filters) : "No filters. Runs on every selected event."),
|
|
2472
2168
|
long: true
|
|
2473
2169
|
});
|
|
2474
|
-
if (
|
|
2475
|
-
...textField("warning", "Needs attention", "Trigger unavailable.
|
|
2170
|
+
if (trigger.problems.length > 0) fields.push({
|
|
2171
|
+
...textField("warning", "Needs attention", ["Trigger unavailable.", ...trigger.problems].join(" ")),
|
|
2476
2172
|
long: true
|
|
2477
2173
|
});
|
|
2478
2174
|
}
|
|
@@ -3013,40 +2709,27 @@ async function handleSlackWebhook(args) {
|
|
|
3013
2709
|
return new Response("ok", { status: 200 });
|
|
3014
2710
|
}
|
|
3015
2711
|
// src/handlers/webhooks.ts
|
|
3016
|
-
/** Run a platform webhook with shared request
|
|
2712
|
+
/** Run a platform webhook with shared request log context and error logging. */
|
|
3017
2713
|
async function handleWebhookRequest(request, platform, run) {
|
|
3018
2714
|
const requestContext = createRequestContext(request, { platform });
|
|
3019
|
-
const requestUrl = new URL(request.url);
|
|
3020
2715
|
return await withContext(requestContext, async () => {
|
|
3021
2716
|
try {
|
|
3022
|
-
|
|
2717
|
+
const response = await run();
|
|
2718
|
+
if (response.status >= 400) {
|
|
2719
|
+
let responseBodySnippet;
|
|
3023
2720
|
try {
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
try {
|
|
3028
|
-
responseBodySnippet = (await response.clone().text()).slice(0, 300);
|
|
3029
|
-
} catch {
|
|
3030
|
-
responseBodySnippet = void 0;
|
|
3031
|
-
}
|
|
3032
|
-
logWarn("webhook.response.unsuccessful", {
|
|
3033
|
-
"http.response.status_code": response.status,
|
|
3034
|
-
"http.request.header.x_slack_signature": request.headers.get("x-slack-signature") ?? void 0,
|
|
3035
|
-
"http.request.header.x_slack_request_timestamp": request.headers.get("x-slack-request-timestamp") ?? void 0,
|
|
3036
|
-
...responseBodySnippet ? { "app.webhook.response_body": responseBodySnippet } : void 0
|
|
3037
|
-
});
|
|
3038
|
-
}
|
|
3039
|
-
setSpanAttributes({ "http.response.status_code": response.status });
|
|
3040
|
-
setSpanStatus(response.status >= 500 ? "error" : "ok");
|
|
3041
|
-
return response;
|
|
3042
|
-
} catch (error) {
|
|
3043
|
-
setSpanStatus("error");
|
|
3044
|
-
throw error;
|
|
2721
|
+
responseBodySnippet = (await response.clone().text()).slice(0, 300);
|
|
2722
|
+
} catch {
|
|
2723
|
+
responseBodySnippet = void 0;
|
|
3045
2724
|
}
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
2725
|
+
logWarn("webhook.response.unsuccessful", {
|
|
2726
|
+
"http.response.status_code": response.status,
|
|
2727
|
+
"http.request.header.x_slack_signature": request.headers.get("x-slack-signature") ?? void 0,
|
|
2728
|
+
"http.request.header.x_slack_request_timestamp": request.headers.get("x-slack-request-timestamp") ?? void 0,
|
|
2729
|
+
...responseBodySnippet ? { "app.webhook.response_body": responseBodySnippet } : void 0
|
|
2730
|
+
});
|
|
2731
|
+
}
|
|
2732
|
+
return response;
|
|
3050
2733
|
} catch (error) {
|
|
3051
2734
|
logException(error, "webhook.handler.failed");
|
|
3052
2735
|
throw error;
|
|
@@ -3073,22 +2756,29 @@ function parseConversationQueueMessage(message) {
|
|
|
3073
2756
|
function resolveConversationWorkVisibilityTimeoutSeconds(functionMaxDurationSeconds = getChatConfig().functionMaxDurationSeconds) {
|
|
3074
2757
|
return functionMaxDurationSeconds + 30;
|
|
3075
2758
|
}
|
|
3076
|
-
/**
|
|
3077
|
-
|
|
3078
|
-
|
|
2759
|
+
/**
|
|
2760
|
+
* Sentry queue attributes for the worker span. The span always sets the
|
|
2761
|
+
* messaging system and destination so the inherited Slack values do not win.
|
|
2762
|
+
*/
|
|
2763
|
+
function queueProcessAttributes(metadata, nowMs) {
|
|
3079
2764
|
return {
|
|
3080
|
-
"
|
|
3081
|
-
"
|
|
2765
|
+
"messaging.destination.name": metadata?.topicName ?? resolveConversationWorkQueueTopic(),
|
|
2766
|
+
"messaging.system": getQueueProvider().messagingSystem,
|
|
2767
|
+
...metadata && {
|
|
2768
|
+
"messaging.message.id": metadata.messageId,
|
|
2769
|
+
"messaging.message.receive.latency": nowMs - metadata.createdAt.getTime(),
|
|
2770
|
+
"messaging.message.retry.count": metadata.deliveryCount - 1
|
|
2771
|
+
}
|
|
3082
2772
|
};
|
|
3083
2773
|
}
|
|
3084
2774
|
/**
|
|
3085
|
-
* Process one
|
|
3086
|
-
* Pass the queue metadata to record queue
|
|
2775
|
+
* Process one queue payload with the generic conversation worker.
|
|
2776
|
+
* Pass the queue metadata to record time in queue and retries on the span.
|
|
3087
2777
|
*/
|
|
3088
2778
|
async function processConversationQueueMessage(message, options, metadata) {
|
|
3089
2779
|
const parsed = parseConversationQueueMessage(message);
|
|
3090
2780
|
try {
|
|
3091
|
-
return await withSpan("conversation.work.process", "
|
|
2781
|
+
return await withSpan("conversation.work.process", "queue.process", { conversationId: parsed.conversationId }, async (setSpanAttributes) => {
|
|
3092
2782
|
try {
|
|
3093
2783
|
const result = await processConversationWork(parsed, {
|
|
3094
2784
|
checkInIntervalMs: options.checkInIntervalMs,
|
|
@@ -3105,13 +2795,13 @@ async function processConversationQueueMessage(message, options, metadata) {
|
|
|
3105
2795
|
if (isConversationQueueMessageRejectedError(error)) setSpanAttributes({ "app.worker.outcome": error.reason });
|
|
3106
2796
|
throw error;
|
|
3107
2797
|
}
|
|
3108
|
-
},
|
|
2798
|
+
}, queueProcessAttributes(metadata, options.nowMs?.() ?? Date.now()));
|
|
3109
2799
|
} finally {
|
|
3110
2800
|
options.waitUntil?.(settleConversationTitleWork(parsed.conversationId));
|
|
3111
2801
|
}
|
|
3112
2802
|
}
|
|
3113
2803
|
/**
|
|
3114
|
-
* Run one queue message through the worker without a
|
|
2804
|
+
* Run one queue message through the worker without a queue push callback.
|
|
3115
2805
|
* In-process queues use this. The callback's kill switch, request deadline,
|
|
3116
2806
|
* and permanent rejection rules apply; signature checks do not.
|
|
3117
2807
|
*/
|
|
@@ -3121,9 +2811,7 @@ async function consumeConversationQueueMessage(message, options) {
|
|
|
3121
2811
|
consumerGroup: "in_process",
|
|
3122
2812
|
createdAt: new Date(nowMs),
|
|
3123
2813
|
deliveryCount: 1,
|
|
3124
|
-
expiresAt: new Date(nowMs + 3e4),
|
|
3125
2814
|
messageId: options.messageId,
|
|
3126
|
-
region: "local",
|
|
3127
2815
|
topicName: resolveConversationWorkQueueTopic(options)
|
|
3128
2816
|
});
|
|
3129
2817
|
}
|
|
@@ -3172,6 +2860,7 @@ function registerVercelConversationWorkDevConsumer(options) {
|
|
|
3172
2860
|
return conversationWorkCallback(options).registerDev();
|
|
3173
2861
|
}
|
|
3174
2862
|
// src/chat/sandbox/snapshot/job-callback.ts
|
|
2863
|
+
/** Receive queue messages for Workspace snapshot builds. */
|
|
3175
2864
|
const WORKSPACE_SNAPSHOT_JOB_DEV_CONSUMER_GROUP = "junior_workspace_snapshots_dev";
|
|
3176
2865
|
function logWorkspaceSnapshotJobRejected(reason, metadata) {
|
|
3177
2866
|
logWarn("workspace.snapshot.job.queue_message.rejected", {
|
|
@@ -3207,7 +2896,7 @@ async function publicArtifactGET(args) {
|
|
|
3207
2896
|
const artifact = await readPublicArtifact({
|
|
3208
2897
|
db: args.db ?? getSqlExecutor(),
|
|
3209
2898
|
filename: args.filename,
|
|
3210
|
-
storage: args.storage ??
|
|
2899
|
+
storage: args.storage ?? getAttachmentStorage()
|
|
3211
2900
|
});
|
|
3212
2901
|
if (!artifact) return new Response("Not Found", {
|
|
3213
2902
|
headers: unpublishedArtifactHeaders(),
|
|
@@ -5116,6 +4805,7 @@ function createBetterAuth(config) {
|
|
|
5116
4805
|
clientSecret: required(config.googleClientSecret ?? process.env.GOOGLE_CLIENT_SECRET, "GOOGLE_CLIENT_SECRET"),
|
|
5117
4806
|
hd: hostedDomain,
|
|
5118
4807
|
prompt: "select_account",
|
|
4808
|
+
disableIdTokenSignIn: true,
|
|
5119
4809
|
async getUserInfo(token) {
|
|
5120
4810
|
if (!token.idToken) return null;
|
|
5121
4811
|
const claims = readGoogleClaims(token.idToken);
|
|
@@ -5276,7 +4966,6 @@ function dashboardHostRoutePaths(dashboard, authenticatedRoutes = []) {
|
|
|
5276
4966
|
pagePath("settings"),
|
|
5277
4967
|
`${pagePath("settings")}/*`
|
|
5278
4968
|
];
|
|
5279
|
-
if (dashboard.componentGallery) pagePaths.push(pagePath("dev"), `${pagePath("dev")}/*`);
|
|
5280
4969
|
const loginPath = basePath === "/" ? "/auth/login" : `${basePath}/auth/login`;
|
|
5281
4970
|
return [
|
|
5282
4971
|
...pagePaths,
|
|
@@ -5534,7 +5223,7 @@ async function createApp(options) {
|
|
|
5534
5223
|
messageId: delivery.messageId
|
|
5535
5224
|
})) ?? getVercelConversationWorkQueue();
|
|
5536
5225
|
const pluginTaskQueue = options?.pluginTaskQueue?.(processPluginTask);
|
|
5537
|
-
const attachmentStorage =
|
|
5226
|
+
const attachmentStorage = getAttachmentStorage();
|
|
5538
5227
|
const agentRunner = createAgentRunner(executeAgentRun, {
|
|
5539
5228
|
attachmentStorage,
|
|
5540
5229
|
bindMessageAgent: (request) => bindMessageAgent(request, { queue: conversationWorkQueue }),
|