@sentry/junior 0.64.0 → 0.65.1

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 (70) hide show
  1. package/dist/app.d.ts +3 -0
  2. package/dist/app.js +3299 -1343
  3. package/dist/chat/agent-dispatch/heartbeat.d.ts +8 -0
  4. package/dist/chat/agent-dispatch/store.d.ts +2 -2
  5. package/dist/chat/agent-dispatch/types.d.ts +8 -22
  6. package/dist/chat/agent-dispatch/validation.d.ts +3 -1
  7. package/dist/chat/app/production.d.ts +11 -5
  8. package/dist/chat/capabilities/factory.d.ts +2 -1
  9. package/dist/chat/capabilities/router.d.ts +3 -2
  10. package/dist/chat/config.d.ts +5 -0
  11. package/dist/chat/credentials/broker.d.ts +2 -1
  12. package/dist/chat/credentials/context.d.ts +28 -0
  13. package/dist/chat/credentials/subject.d.ts +20 -0
  14. package/dist/chat/ingress/slack-webhook.d.ts +19 -0
  15. package/dist/chat/mcp/errors.d.ts +1 -1
  16. package/dist/chat/plugins/command-env.d.ts +1 -1
  17. package/dist/chat/plugins/github-permissions.d.ts +11 -0
  18. package/dist/chat/plugins/types.d.ts +3 -0
  19. package/dist/chat/prompt.d.ts +2 -0
  20. package/dist/chat/respond-helpers.d.ts +4 -2
  21. package/dist/chat/respond.d.ts +23 -13
  22. package/dist/chat/runtime/processing-reaction.d.ts +1 -0
  23. package/dist/chat/runtime/reply-executor.d.ts +5 -0
  24. package/dist/chat/runtime/request-deadline.d.ts +8 -0
  25. package/dist/chat/runtime/slack-resume.d.ts +4 -5
  26. package/dist/chat/runtime/slack-runtime.d.ts +10 -0
  27. package/dist/chat/runtime/thread-context.d.ts +5 -2
  28. package/dist/chat/runtime/timeout-resume-runner.d.ts +19 -0
  29. package/dist/chat/runtime/turn-preparation.d.ts +1 -0
  30. package/dist/chat/runtime/turn.d.ts +13 -0
  31. package/dist/chat/sandbox/egress-policy.d.ts +1 -1
  32. package/dist/chat/sandbox/egress-session.d.ts +13 -12
  33. package/dist/chat/sandbox/sandbox.d.ts +2 -3
  34. package/dist/chat/services/timeout-resume.d.ts +9 -4
  35. package/dist/chat/services/turn-session-record.d.ts +19 -2
  36. package/dist/chat/slack/adapter-context.d.ts +25 -0
  37. package/dist/chat/slack/conversation-context.d.ts +28 -0
  38. package/dist/chat/state/turn-session.d.ts +1 -1
  39. package/dist/chat/task-execution/heartbeat.d.ts +13 -0
  40. package/dist/chat/task-execution/queue-signing.d.ts +12 -0
  41. package/dist/chat/task-execution/queue.d.ts +13 -0
  42. package/dist/chat/task-execution/slack-work.d.ts +32 -0
  43. package/dist/chat/task-execution/store.d.ts +153 -0
  44. package/dist/chat/task-execution/vercel-callback.d.ts +21 -0
  45. package/dist/chat/task-execution/vercel-queue.d.ts +16 -0
  46. package/dist/chat/task-execution/worker.d.ts +28 -0
  47. package/dist/{chunk-WDPWFMCE.js → chunk-657CJCUO.js} +244 -68
  48. package/dist/chunk-6YY4Q3D4.js +12 -0
  49. package/dist/chunk-75UZ4JLC.js +213 -0
  50. package/dist/{chunk-D23WCM66.js → chunk-F57QSMOJ.js} +1 -1
  51. package/dist/{chunk-WZFQQ6SP.js → chunk-HRQQS63X.js} +2 -2
  52. package/dist/{chunk-SCQPBJAU.js → chunk-QUXPUKBH.js} +1 -7
  53. package/dist/{chunk-4CRYMG7M.js → chunk-X2HJLKQT.js} +368 -13
  54. package/dist/{chunk-IGVHCX2U.js → chunk-ZOV3XJAH.js} +3 -2
  55. package/dist/cli/check.js +115 -2
  56. package/dist/cli/init.js +13 -1
  57. package/dist/cli/snapshot-warmup.js +3 -3
  58. package/dist/deployment.d.ts +4 -0
  59. package/dist/handlers/heartbeat.d.ts +5 -1
  60. package/dist/handlers/turn-resume.d.ts +3 -2
  61. package/dist/handlers/webhooks.d.ts +11 -9
  62. package/dist/nitro.d.ts +3 -1
  63. package/dist/nitro.js +48 -4
  64. package/dist/reporting.js +13 -16
  65. package/dist/vercel.d.ts +1 -1
  66. package/dist/vercel.js +1 -1
  67. package/package.json +5 -4
  68. package/dist/chat/services/turn-continuation-response.d.ts +0 -2
  69. package/dist/chat/slack/turn-continuation-notice.d.ts +0 -8
  70. package/dist/chunk-5VDO6LSG.js +0 -104
@@ -1363,6 +1363,11 @@ function inlineCredentialsSource(credentials) {
1363
1363
  setDefined(result, "app-id-env", credentials.appIdEnv);
1364
1364
  setDefined(result, "private-key-env", credentials.privateKeyEnv);
1365
1365
  setDefined(result, "installation-id-env", credentials.installationIdEnv);
1366
+ setDefined(
1367
+ result,
1368
+ "system-read-permissions",
1369
+ credentials.systemReadPermissions
1370
+ );
1366
1371
  }
1367
1372
  return result;
1368
1373
  }
@@ -1441,6 +1446,103 @@ function inlineManifestSource(manifest) {
1441
1446
  return result;
1442
1447
  }
1443
1448
 
1449
+ // src/chat/plugins/github-permissions.ts
1450
+ var KNOWN_GITHUB_PERMISSION_SCOPES = /* @__PURE__ */ new Set([
1451
+ "actions",
1452
+ "administration",
1453
+ "checks",
1454
+ "codespaces",
1455
+ "contents",
1456
+ "deployments",
1457
+ "environments",
1458
+ "issues",
1459
+ "metadata",
1460
+ "packages",
1461
+ "pages",
1462
+ "pull_requests",
1463
+ "repository_hooks",
1464
+ "repository_projects",
1465
+ "secret_scanning_alerts",
1466
+ "secrets",
1467
+ "security_events",
1468
+ "statuses",
1469
+ "vulnerability_alerts",
1470
+ "workflows"
1471
+ ]);
1472
+ var DEFAULT_GITHUB_SYSTEM_READ_SCOPES = /* @__PURE__ */ new Set([
1473
+ "actions",
1474
+ "checks",
1475
+ "contents",
1476
+ "issues",
1477
+ "metadata",
1478
+ "pull_requests",
1479
+ "statuses"
1480
+ ]);
1481
+ function normalizeGitHubPermissionScope(rawScope) {
1482
+ return rawScope.trim().replace(/-/g, "_");
1483
+ }
1484
+ function normalizeGitHubSystemReadPermissionScopes(scopes, context) {
1485
+ return scopes.map((rawScope) => {
1486
+ const scope = normalizeGitHubPermissionScope(rawScope);
1487
+ if (!KNOWN_GITHUB_PERMISSION_SCOPES.has(scope)) {
1488
+ throw new Error(`${context} contains unsupported scope "${rawScope}"`);
1489
+ }
1490
+ return scope;
1491
+ });
1492
+ }
1493
+ function githubCapabilitiesToPermissions(capabilities, pluginName) {
1494
+ const permissions = {};
1495
+ const prefix = `${pluginName}.`;
1496
+ for (const capability of capabilities) {
1497
+ if (!capability.startsWith(prefix)) {
1498
+ throw new Error(`Unsupported GitHub capability: ${capability}`);
1499
+ }
1500
+ const suffix = capability.slice(prefix.length);
1501
+ const lastDot = suffix.lastIndexOf(".");
1502
+ if (lastDot === -1) {
1503
+ throw new Error(`Unsupported GitHub capability: ${capability}`);
1504
+ }
1505
+ const scopeRaw = suffix.slice(0, lastDot);
1506
+ const level = suffix.slice(lastDot + 1);
1507
+ if (level !== "read" && level !== "write") {
1508
+ throw new Error(`Unsupported GitHub capability: ${capability}`);
1509
+ }
1510
+ const scope = normalizeGitHubPermissionScope(scopeRaw);
1511
+ if (!KNOWN_GITHUB_PERMISSION_SCOPES.has(scope)) {
1512
+ throw new Error(`Unsupported GitHub capability: ${capability}`);
1513
+ }
1514
+ const existing = permissions[scope];
1515
+ permissions[scope] = existing === "write" || level === "write" ? "write" : "read";
1516
+ }
1517
+ return permissions;
1518
+ }
1519
+ function githubSystemReadPermissionsFromScopes(scopes) {
1520
+ const readOnly = {
1521
+ metadata: "read"
1522
+ };
1523
+ for (const scope of normalizeGitHubSystemReadPermissionScopes(
1524
+ scopes,
1525
+ "GitHub system read permissions"
1526
+ )) {
1527
+ readOnly[scope] = "read";
1528
+ }
1529
+ return readOnly;
1530
+ }
1531
+ function githubInstallationReadPermissions(permissions, allowedScopes) {
1532
+ const readOnly = {
1533
+ metadata: "read"
1534
+ };
1535
+ for (const [scope, level] of Object.entries(permissions ?? {})) {
1536
+ if (!allowedScopes.has(scope) || !KNOWN_GITHUB_PERMISSION_SCOPES.has(scope)) {
1537
+ continue;
1538
+ }
1539
+ if (level === "read" || level === "write" || level === "admin") {
1540
+ readOnly[scope] = "read";
1541
+ }
1542
+ }
1543
+ return readOnly;
1544
+ }
1545
+
1444
1546
  // src/chat/plugins/manifest.ts
1445
1547
  var PLUGIN_NAME_RE = /^[a-z][a-z0-9-]*$/;
1446
1548
  var SHORT_CAPABILITY_RE = /^[a-z0-9-]+(\.[a-z0-9-]+)*$/;
@@ -1580,7 +1682,10 @@ var githubAppCredentialsSchema = baseCredentialsSchema.extend({
1580
1682
  type: z.literal("github-app"),
1581
1683
  "app-id-env": envVarString,
1582
1684
  "private-key-env": envVarString,
1583
- "installation-id-env": envVarString
1685
+ "installation-id-env": envVarString,
1686
+ "system-read-permissions": nonEmptyStringArraySchema(
1687
+ "system-read-permissions"
1688
+ ).optional()
1584
1689
  });
1585
1690
  var runtimeDependencyEntrySchema = z.object({
1586
1691
  type: z.enum(["npm", "system"]),
@@ -1704,6 +1809,11 @@ function manifestConfigPatch(config) {
1704
1809
  "installation-id-env",
1705
1810
  config.credentials.installationIdEnv
1706
1811
  );
1812
+ setDefined2(
1813
+ credentials,
1814
+ "system-read-permissions",
1815
+ config.credentials.systemReadPermissions
1816
+ );
1707
1817
  result.credentials = credentials;
1708
1818
  }
1709
1819
  }
@@ -1913,6 +2023,21 @@ function assertCommandEnvDoesNotExposeHostSecretRefs(commandEnv, apiHeaders, cre
1913
2023
  }
1914
2024
  }
1915
2025
  }
2026
+ function assertCommandEnvHostRefsAreExplicitlyExposed(commandEnv, envVars, pluginName) {
2027
+ if (!commandEnv) {
2028
+ return;
2029
+ }
2030
+ for (const [key, value] of Object.entries(commandEnv)) {
2031
+ for (const name of envReferences(value)) {
2032
+ const declaration = envVars[name];
2033
+ if (declaration && declaration.default === void 0 && declaration.exposeToCommandEnv !== true) {
2034
+ throw new Error(
2035
+ `Plugin ${pluginName} command-env.${key} references env var ${name}, but env-vars.${name} must set expose-to-command-env: true before host env can be exposed to sandbox`
2036
+ );
2037
+ }
2038
+ }
2039
+ }
2040
+ }
1916
2041
  function normalizeCredentials(data, name) {
1917
2042
  const schema = data.type === "oauth-bearer" ? oauthBearerCredentialsSchema : data.type === "github-app" ? githubAppCredentialsSchema : void 0;
1918
2043
  if (!schema) {
@@ -1947,6 +2072,10 @@ function normalizeCredentials(data, name) {
1947
2072
  `Plugin ${name} credentials.api-headers`,
1948
2073
  { forbiddenKeys: FORBIDDEN_API_HEADER_NAMES }
1949
2074
  ) : void 0;
2075
+ const systemReadPermissions = result.data["system-read-permissions"] ? normalizeGitHubSystemReadPermissionScopes(
2076
+ result.data["system-read-permissions"],
2077
+ `Plugin ${name} credentials.system-read-permissions`
2078
+ ) : void 0;
1950
2079
  return {
1951
2080
  type: "github-app",
1952
2081
  domains,
@@ -1955,7 +2084,8 @@ function normalizeCredentials(data, name) {
1955
2084
  ...result.data["auth-token-placeholder"] ? { authTokenPlaceholder: result.data["auth-token-placeholder"] } : {},
1956
2085
  appIdEnv: result.data["app-id-env"],
1957
2086
  privateKeyEnv: result.data["private-key-env"],
1958
- installationIdEnv: result.data["installation-id-env"]
2087
+ installationIdEnv: result.data["installation-id-env"],
2088
+ ...systemReadPermissions ? { systemReadPermissions } : {}
1959
2089
  };
1960
2090
  }
1961
2091
  function normalizeRuntimeDependencies(entries, name) {
@@ -2087,7 +2217,9 @@ function normalizeRuntimePostinstall(commands, name) {
2087
2217
  var envVarDeclarationSchema = z.preprocess(
2088
2218
  (value) => value === null || value === void 0 ? {} : value,
2089
2219
  z.object({
2090
- default: z.string().optional()
2220
+ default: z.string().optional(),
2221
+ "expose-to-command-env": z.boolean().optional(),
2222
+ exposeToCommandEnv: z.boolean().optional()
2091
2223
  }).strict()
2092
2224
  );
2093
2225
  function normalizeEnvVars(data, pluginName) {
@@ -2109,6 +2241,9 @@ function normalizeEnvVars(data, pluginName) {
2109
2241
  if (parsed.data.default !== void 0) {
2110
2242
  decl.default = parsed.data.default;
2111
2243
  }
2244
+ if (parsed.data["expose-to-command-env"] === true || parsed.data.exposeToCommandEnv === true) {
2245
+ decl.exposeToCommandEnv = true;
2246
+ }
2112
2247
  normalized[name] = decl;
2113
2248
  }
2114
2249
  return normalized;
@@ -2267,11 +2402,6 @@ function parseManifestSource(parsedSource, dir, config) {
2267
2402
  envVars
2268
2403
  ) : void 0;
2269
2404
  const credentials = data.credentials ? normalizeCredentials(data.credentials, data.name) : void 0;
2270
- if (commandEnv && !credentials && !apiHeaders) {
2271
- throw new Error(
2272
- `Plugin ${data.name} command-env requires credentials or api-headers`
2273
- );
2274
- }
2275
2405
  const runtimeDependencies = data["runtime-dependencies"] ? normalizeRuntimeDependencies(data["runtime-dependencies"], data.name) : void 0;
2276
2406
  const runtimePostinstall = data["runtime-postinstall"] ? normalizeRuntimePostinstall(data["runtime-postinstall"], data.name) : void 0;
2277
2407
  const mcp = data.mcp ? normalizeMcp(data.mcp, envVars, data.name) : void 0;
@@ -2334,6 +2464,11 @@ function parseManifestSource(parsedSource, dir, config) {
2334
2464
  manifest.oauth,
2335
2465
  data.name
2336
2466
  );
2467
+ assertCommandEnvHostRefsAreExplicitlyExposed(
2468
+ data["command-env"],
2469
+ envVars,
2470
+ data.name
2471
+ );
2337
2472
  if (data.target) {
2338
2473
  const result = targetSourceSchema.safeParse(data.target);
2339
2474
  if (!result.success) {
@@ -2600,54 +2735,6 @@ function resolveGitHubApiDomain(credentials) {
2600
2735
  }
2601
2736
  return apiDomain;
2602
2737
  }
2603
- var KNOWN_SCOPES = /* @__PURE__ */ new Set([
2604
- "actions",
2605
- "administration",
2606
- "checks",
2607
- "codespaces",
2608
- "contents",
2609
- "deployments",
2610
- "environments",
2611
- "issues",
2612
- "metadata",
2613
- "packages",
2614
- "pages",
2615
- "pull_requests",
2616
- "repository_hooks",
2617
- "repository_projects",
2618
- "secret_scanning_alerts",
2619
- "secrets",
2620
- "security_events",
2621
- "statuses",
2622
- "vulnerability_alerts",
2623
- "workflows"
2624
- ]);
2625
- function capabilitiesToPermissions(capabilities, pluginName) {
2626
- const permissions = {};
2627
- const prefix = `${pluginName}.`;
2628
- for (const capability of capabilities) {
2629
- if (!capability.startsWith(prefix)) {
2630
- throw new Error(`Unsupported GitHub capability: ${capability}`);
2631
- }
2632
- const suffix = capability.slice(prefix.length);
2633
- const lastDot = suffix.lastIndexOf(".");
2634
- if (lastDot === -1) {
2635
- throw new Error(`Unsupported GitHub capability: ${capability}`);
2636
- }
2637
- const scopeRaw = suffix.slice(0, lastDot);
2638
- const level = suffix.slice(lastDot + 1);
2639
- if (level !== "read" && level !== "write") {
2640
- throw new Error(`Unsupported GitHub capability: ${capability}`);
2641
- }
2642
- const scope = scopeRaw.replace(/-/g, "_");
2643
- if (!KNOWN_SCOPES.has(scope)) {
2644
- throw new Error(`Unsupported GitHub capability: ${capability}`);
2645
- }
2646
- const existing = permissions[scope];
2647
- permissions[scope] = existing === "write" || level === "write" ? "write" : "read";
2648
- }
2649
- return permissions;
2650
- }
2651
2738
  function createGitHubAppBroker(manifest, credentials) {
2652
2739
  const provider = manifest.name;
2653
2740
  const {
@@ -2674,7 +2761,23 @@ function createGitHubAppBroker(manifest, credentials) {
2674
2761
  const normalizedApiDomain = apiDomain.toLowerCase();
2675
2762
  return normalizedDomain === "github.com" || normalizedApiDomain.startsWith("api.") && normalizedDomain === normalizedApiDomain.slice("api.".length);
2676
2763
  }
2677
- const permissions = manifest.capabilities?.length ? capabilitiesToPermissions(manifest.capabilities, provider) : void 0;
2764
+ const permissions = manifest.capabilities?.length ? githubCapabilitiesToPermissions(manifest.capabilities, provider) : void 0;
2765
+ const systemReadPermissions = credentials.systemReadPermissions?.length ? githubSystemReadPermissionsFromScopes(credentials.systemReadPermissions) : void 0;
2766
+ async function resolveTokenPermissions(params) {
2767
+ if (!params.systemActor) {
2768
+ return permissions;
2769
+ }
2770
+ if (systemReadPermissions) {
2771
+ return systemReadPermissions;
2772
+ }
2773
+ const installation = await githubRequest(apiBase, `/app/installations/${params.installationId}`, {
2774
+ token: params.appJwt
2775
+ });
2776
+ return githubInstallationReadPermissions(
2777
+ installation.permissions,
2778
+ DEFAULT_GITHUB_SYSTEM_READ_SCOPES
2779
+ );
2780
+ }
2678
2781
  function createLease(params) {
2679
2782
  return {
2680
2783
  id: randomUUID2(),
@@ -2714,9 +2817,14 @@ function createGitHubAppBroker(manifest, credentials) {
2714
2817
  return {
2715
2818
  async issue(input) {
2716
2819
  const installationId = resolveInstallationId();
2717
- const tokenRequestBody = permissions ? { permissions } : {};
2718
2820
  const appId = resolveAppId(appIdEnv);
2719
2821
  const appJwt = createAppJwt(appId, privateKeyEnv);
2822
+ const tokenPermissions = await resolveTokenPermissions({
2823
+ appJwt,
2824
+ installationId,
2825
+ systemActor: input.context.actor.type === "system"
2826
+ });
2827
+ const tokenRequestBody = tokenPermissions ? { permissions: tokenPermissions } : {};
2720
2828
  const accessTokenResponse = await githubRequest(apiBase, `/app/installations/${installationId}/access_tokens`, {
2721
2829
  method: "POST",
2722
2830
  token: appJwt,
@@ -2750,6 +2858,79 @@ var CredentialUnavailableError = class extends Error {
2750
2858
  }
2751
2859
  };
2752
2860
 
2861
+ // src/chat/credentials/context.ts
2862
+ function credentialUserSubjectId(context) {
2863
+ if (context.actor.type === "user") {
2864
+ return context.actor.userId;
2865
+ }
2866
+ return context.subject?.userId;
2867
+ }
2868
+ function parseCredentialContext(value) {
2869
+ if (!value || typeof value !== "object") {
2870
+ return void 0;
2871
+ }
2872
+ const record = value;
2873
+ const actor = parseActor(record.actor);
2874
+ if (!actor) {
2875
+ return void 0;
2876
+ }
2877
+ if (actor.type === "user") {
2878
+ if ("subject" in record && record.subject !== void 0) {
2879
+ return void 0;
2880
+ }
2881
+ return { actor };
2882
+ }
2883
+ if (!("subject" in record) || record.subject === void 0) {
2884
+ return { actor };
2885
+ }
2886
+ const subject = parseSubject(record.subject);
2887
+ if (!subject) {
2888
+ return void 0;
2889
+ }
2890
+ return {
2891
+ actor,
2892
+ subject
2893
+ };
2894
+ }
2895
+ function parseActor(value) {
2896
+ if (value && typeof value === "object") {
2897
+ const record = value;
2898
+ if (record.type === "user" && typeof record.userId === "string" && record.userId) {
2899
+ return { type: "user", userId: record.userId };
2900
+ }
2901
+ if (record.type === "system" && typeof record.id === "string" && record.id) {
2902
+ return { type: "system", id: record.id };
2903
+ }
2904
+ }
2905
+ return void 0;
2906
+ }
2907
+ function parseSubject(value) {
2908
+ if (value && typeof value === "object") {
2909
+ const record = value;
2910
+ if (record.type === "user" && typeof record.userId === "string" && record.userId && record.allowedWhen === "private-direct-conversation") {
2911
+ if (!record.binding || typeof record.binding !== "object") {
2912
+ return void 0;
2913
+ }
2914
+ const binding = record.binding;
2915
+ if (binding.type !== "slack-direct-conversation" || typeof binding.teamId !== "string" || !binding.teamId || typeof binding.channelId !== "string" || !binding.channelId || typeof binding.signature !== "string" || !binding.signature) {
2916
+ return void 0;
2917
+ }
2918
+ return {
2919
+ type: "user",
2920
+ userId: record.userId,
2921
+ allowedWhen: "private-direct-conversation",
2922
+ binding: {
2923
+ type: "slack-direct-conversation",
2924
+ teamId: binding.teamId,
2925
+ channelId: binding.channelId,
2926
+ signature: binding.signature
2927
+ }
2928
+ };
2929
+ }
2930
+ }
2931
+ return void 0;
2932
+ }
2933
+
2753
2934
  // src/chat/credentials/oauth-scope.ts
2754
2935
  function parseScope(scope) {
2755
2936
  if (!scope) {
@@ -2911,6 +3092,7 @@ function createOAuthBearerBroker(manifest, credentials, deps) {
2911
3092
  async issue(input) {
2912
3093
  const envToken = process.env[authTokenEnv]?.trim();
2913
3094
  const oauth = manifest.oauth;
3095
+ const userSubjectId = credentialUserSubjectId(input.context);
2914
3096
  if (!oauth) {
2915
3097
  if (envToken) {
2916
3098
  return buildLease(envToken, Date.now() + MAX_LEASE_MS3, input.reason);
@@ -2920,11 +3102,8 @@ function createOAuthBearerBroker(manifest, credentials, deps) {
2920
3102
  `No ${provider} credentials available.`
2921
3103
  );
2922
3104
  }
2923
- if (input.requesterId) {
2924
- const stored = await deps.userTokenStore.get(
2925
- input.requesterId,
2926
- provider
2927
- );
3105
+ if (userSubjectId) {
3106
+ const stored = await deps.userTokenStore.get(userSubjectId, provider);
2928
3107
  if (stored) {
2929
3108
  if (!hasRequiredOAuthScope(stored.scope, oauth.scope)) {
2930
3109
  throw new CredentialUnavailableError(
@@ -2946,11 +3125,7 @@ function createOAuthBearerBroker(manifest, credentials, deps) {
2946
3125
  `Your ${provider} connection needs to be reauthorized.`
2947
3126
  );
2948
3127
  }
2949
- await deps.userTokenStore.set(
2950
- input.requesterId,
2951
- provider,
2952
- refreshed
2953
- );
3128
+ await deps.userTokenStore.set(userSubjectId, provider, refreshed);
2954
3129
  return buildLease(
2955
3130
  refreshed.accessToken,
2956
3131
  getLeaseExpiry(refreshed.expiresAt),
@@ -3442,6 +3617,7 @@ export {
3442
3617
  resolveAuthTokenPlaceholder,
3443
3618
  parsePluginManifest,
3444
3619
  CredentialUnavailableError,
3620
+ parseCredentialContext,
3445
3621
  hasRequiredOAuthScope,
3446
3622
  buildOAuthTokenRequest,
3447
3623
  parseOAuthTokenResponse,
@@ -0,0 +1,12 @@
1
+ // src/deployment.ts
2
+ var JUNIOR_HEARTBEAT_ROUTE = "/api/internal/heartbeat";
3
+ var JUNIOR_HEARTBEAT_CRON_SCHEDULE = "* * * * *";
4
+ var JUNIOR_CONVERSATION_WORK_CALLBACK_ROUTE = "/api/internal/agent/continue";
5
+ var LEGACY_JUNIOR_CONVERSATION_WORK_FUNCTION = "api/internal/agent/continue.ts";
6
+
7
+ export {
8
+ JUNIOR_HEARTBEAT_ROUTE,
9
+ JUNIOR_HEARTBEAT_CRON_SCHEDULE,
10
+ JUNIOR_CONVERSATION_WORK_CALLBACK_ROUTE,
11
+ LEGACY_JUNIOR_CONVERSATION_WORK_FUNCTION
12
+ };
@@ -0,0 +1,213 @@
1
+ // src/plugins.ts
2
+ function cloneManifests(manifests) {
3
+ return manifests ? structuredClone(manifests) : void 0;
4
+ }
5
+ function cloneInlineManifests(registrations) {
6
+ const inlineManifests = registrations.flatMap(
7
+ (plugin) => plugin.manifest ? [
8
+ {
9
+ manifest: {
10
+ ...structuredClone(plugin.manifest),
11
+ capabilities: plugin.manifest.capabilities?.map(
12
+ (capability) => capability.includes(".") ? capability : `${plugin.manifest.name}.${capability}`
13
+ ) ?? [],
14
+ configKeys: plugin.manifest.configKeys?.map(
15
+ (key) => key.includes(".") ? key : `${plugin.manifest.name}.${key}`
16
+ ) ?? [],
17
+ ...plugin.manifest.target ? {
18
+ target: {
19
+ ...plugin.manifest.target,
20
+ configKey: plugin.manifest.target.configKey.includes(".") ? plugin.manifest.target.configKey : `${plugin.manifest.name}.${plugin.manifest.target.configKey}`
21
+ }
22
+ } : {}
23
+ },
24
+ ...plugin.packageName ? { packageName: plugin.packageName } : {}
25
+ }
26
+ ] : []
27
+ );
28
+ return inlineManifests.length > 0 ? inlineManifests : void 0;
29
+ }
30
+ function assertUniquePluginNames(registrations) {
31
+ const seen = /* @__PURE__ */ new Set();
32
+ for (const plugin of registrations) {
33
+ if (seen.has(plugin.name)) {
34
+ throw new Error(`Duplicate plugin registration name "${plugin.name}"`);
35
+ }
36
+ seen.add(plugin.name);
37
+ }
38
+ }
39
+ function assertUniquePackageNames(packageNames) {
40
+ const seen = /* @__PURE__ */ new Set();
41
+ for (const packageName of packageNames) {
42
+ if (seen.has(packageName)) {
43
+ throw new Error(`Duplicate plugin package name "${packageName}"`);
44
+ }
45
+ seen.add(packageName);
46
+ }
47
+ }
48
+ function normalizePluginInput(input) {
49
+ if (typeof input === "string") {
50
+ return { packageName: input };
51
+ }
52
+ return { registration: input };
53
+ }
54
+ function defineJuniorPlugins(inputs, options = {}) {
55
+ const normalized = inputs.map(normalizePluginInput);
56
+ const packageNames = normalized.flatMap(
57
+ (input) => input.packageName ? [input.packageName] : []
58
+ );
59
+ const registrations = normalized.flatMap(
60
+ (input) => input.registration ? [input.registration] : []
61
+ );
62
+ assertUniquePackageNames(packageNames);
63
+ assertUniquePluginNames(registrations);
64
+ const manifests = cloneManifests(options.manifests);
65
+ return {
66
+ packageNames,
67
+ registrations: registrations.map((plugin) => ({ ...plugin })),
68
+ ...manifests ? { manifests } : {}
69
+ };
70
+ }
71
+ function pluginCatalogConfigFromPluginSet(pluginSet) {
72
+ if (!pluginSet) {
73
+ return void 0;
74
+ }
75
+ const packages = [
76
+ .../* @__PURE__ */ new Set([
77
+ ...pluginSet.packageNames,
78
+ ...pluginSet.registrations.flatMap(
79
+ (plugin) => plugin.packageName ? [plugin.packageName] : []
80
+ )
81
+ ])
82
+ ];
83
+ const manifests = cloneManifests(pluginSet.manifests);
84
+ const inlineManifests = cloneInlineManifests(pluginSet.registrations);
85
+ if (packages.length === 0 && !manifests && !inlineManifests) {
86
+ return void 0;
87
+ }
88
+ return {
89
+ ...inlineManifests ? { inlineManifests } : {},
90
+ ...packages.length > 0 ? { packages } : {},
91
+ ...manifests ? { manifests } : {}
92
+ };
93
+ }
94
+ function trustedPluginRegistrationsFromPluginSet(pluginSet) {
95
+ return pluginSet?.registrations.filter(
96
+ (plugin) => plugin.hooks || plugin.legacyStatePrefixes
97
+ ) ?? [];
98
+ }
99
+
100
+ // src/chat/task-execution/vercel-queue.ts
101
+ import { QueueClient } from "@vercel/queue";
102
+
103
+ // src/chat/task-execution/queue-signing.ts
104
+ import { createHmac, timingSafeEqual } from "crypto";
105
+ var CONVERSATION_WORK_QUEUE_SIGNATURE_CONTEXT = "junior.conversation_work_queue.v1";
106
+ var CONVERSATION_WORK_QUEUE_SIGNATURE_VERSION = "v1";
107
+ var CONVERSATION_WORK_QUEUE_SIGNATURE_MAX_SKEW_MS = 60 * 60 * 1e3;
108
+ function getConversationWorkQueueSecret() {
109
+ return process.env.JUNIOR_SECRET?.trim() || void 0;
110
+ }
111
+ function buildSignedPayload(message, signedAtMs) {
112
+ return [
113
+ CONVERSATION_WORK_QUEUE_SIGNATURE_CONTEXT,
114
+ signedAtMs,
115
+ message.conversationId
116
+ ].join(":");
117
+ }
118
+ function signPayload(message, signedAtMs, secret) {
119
+ return createHmac("sha256", secret).update(buildSignedPayload(message, signedAtMs)).digest("hex");
120
+ }
121
+ function timingSafeMatch(expected, actual) {
122
+ const expectedBuffer = Buffer.from(expected);
123
+ const actualBuffer = Buffer.from(actual);
124
+ if (expectedBuffer.length !== actualBuffer.length) {
125
+ return false;
126
+ }
127
+ return timingSafeEqual(expectedBuffer, actualBuffer);
128
+ }
129
+ function parseSignedConversationQueueMessage(value) {
130
+ if (!value || typeof value !== "object") {
131
+ return void 0;
132
+ }
133
+ const record = value;
134
+ if (typeof record.conversationId !== "string" || !record.conversationId.trim() || record.signatureVersion !== CONVERSATION_WORK_QUEUE_SIGNATURE_VERSION || typeof record.signedAtMs !== "number" || !Number.isFinite(record.signedAtMs) || typeof record.signature !== "string" || !record.signature.trim()) {
135
+ return void 0;
136
+ }
137
+ return {
138
+ conversationId: record.conversationId,
139
+ signature: record.signature,
140
+ signatureVersion: CONVERSATION_WORK_QUEUE_SIGNATURE_VERSION,
141
+ signedAtMs: record.signedAtMs
142
+ };
143
+ }
144
+ function signConversationQueueMessage(message, nowMs = Date.now()) {
145
+ const secret = getConversationWorkQueueSecret();
146
+ if (!secret) {
147
+ throw new Error(
148
+ "Cannot sign conversation queue message without JUNIOR_SECRET"
149
+ );
150
+ }
151
+ return {
152
+ ...message,
153
+ signedAtMs: nowMs,
154
+ signatureVersion: CONVERSATION_WORK_QUEUE_SIGNATURE_VERSION,
155
+ signature: signPayload(message, nowMs, secret)
156
+ };
157
+ }
158
+ function verifySignedConversationQueueMessage(value, nowMs = Date.now()) {
159
+ const message = parseSignedConversationQueueMessage(value);
160
+ const secret = getConversationWorkQueueSecret();
161
+ if (!message || !secret || !Number.isFinite(nowMs) || Math.abs(nowMs - message.signedAtMs) > CONVERSATION_WORK_QUEUE_SIGNATURE_MAX_SKEW_MS) {
162
+ return void 0;
163
+ }
164
+ const expected = signPayload(message, message.signedAtMs, secret);
165
+ if (!timingSafeMatch(expected, message.signature)) {
166
+ return void 0;
167
+ }
168
+ return { conversationId: message.conversationId };
169
+ }
170
+
171
+ // src/chat/task-execution/vercel-queue.ts
172
+ var DEFAULT_CONVERSATION_WORK_QUEUE_TOPIC = "junior_conversation_work";
173
+ var defaultQueue;
174
+ function getTopic(options) {
175
+ return options.topic || process.env.JUNIOR_CONVERSATION_WORK_QUEUE_TOPIC?.trim() || DEFAULT_CONVERSATION_WORK_QUEUE_TOPIC;
176
+ }
177
+ function toDelaySeconds(options) {
178
+ if (!options?.delayMs || options.delayMs <= 0) {
179
+ return void 0;
180
+ }
181
+ return Math.ceil(options.delayMs / 1e3);
182
+ }
183
+ function createVercelConversationWorkQueue(options = {}) {
184
+ const topic = getTopic(options);
185
+ const client = options.client ?? new QueueClient();
186
+ return {
187
+ async send(message, sendOptions) {
188
+ const result = await client.send(
189
+ topic,
190
+ signConversationQueueMessage(message),
191
+ {
192
+ idempotencyKey: sendOptions?.idempotencyKey,
193
+ delaySeconds: toDelaySeconds(sendOptions),
194
+ retentionSeconds: options.retentionSeconds
195
+ }
196
+ );
197
+ return result.messageId ? { messageId: result.messageId } : {};
198
+ }
199
+ };
200
+ }
201
+ function getVercelConversationWorkQueue() {
202
+ defaultQueue ??= createVercelConversationWorkQueue();
203
+ return defaultQueue;
204
+ }
205
+
206
+ export {
207
+ defineJuniorPlugins,
208
+ pluginCatalogConfigFromPluginSet,
209
+ trustedPluginRegistrationsFromPluginSet,
210
+ verifySignedConversationQueueMessage,
211
+ DEFAULT_CONVERSATION_WORK_QUEUE_TOPIC,
212
+ getVercelConversationWorkQueue
213
+ };
@@ -2,7 +2,7 @@ import {
2
2
  getPluginForSkillPath,
3
3
  getPluginSkillRoots,
4
4
  logWarn
5
- } from "./chunk-WDPWFMCE.js";
5
+ } from "./chunk-657CJCUO.js";
6
6
  import {
7
7
  skillRoots
8
8
  } from "./chunk-KVZL5NZS.js";
@@ -2,12 +2,12 @@ import {
2
2
  SANDBOX_WORKSPACE_ROOT,
3
3
  getStateAdapter,
4
4
  toOptionalTrimmed
5
- } from "./chunk-IGVHCX2U.js";
5
+ } from "./chunk-ZOV3XJAH.js";
6
6
  import {
7
7
  getPluginRuntimeDependencies,
8
8
  getPluginRuntimePostinstall,
9
9
  withSpan
10
- } from "./chunk-WDPWFMCE.js";
10
+ } from "./chunk-657CJCUO.js";
11
11
 
12
12
  // src/chat/sandbox/runtime-dependency-snapshots.ts
13
13
  import { createHash } from "crypto";