@sentry/junior 0.65.0 → 0.66.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/dist/app.d.ts +3 -0
- package/dist/app.js +3300 -1342
- package/dist/chat/agent-dispatch/heartbeat.d.ts +8 -0
- package/dist/chat/agent-dispatch/store.d.ts +2 -2
- package/dist/chat/agent-dispatch/types.d.ts +8 -22
- package/dist/chat/agent-dispatch/validation.d.ts +3 -1
- package/dist/chat/app/production.d.ts +11 -5
- package/dist/chat/capabilities/factory.d.ts +2 -1
- package/dist/chat/capabilities/router.d.ts +3 -2
- package/dist/chat/config.d.ts +5 -0
- package/dist/chat/credentials/broker.d.ts +2 -1
- package/dist/chat/credentials/context.d.ts +28 -0
- package/dist/chat/credentials/subject.d.ts +20 -0
- package/dist/chat/ingress/slack-webhook.d.ts +19 -0
- package/dist/chat/mcp/errors.d.ts +1 -1
- package/dist/chat/plugins/github-permissions.d.ts +11 -0
- package/dist/chat/plugins/types.d.ts +2 -0
- package/dist/chat/prompt.d.ts +2 -0
- package/dist/chat/respond-helpers.d.ts +4 -2
- package/dist/chat/respond.d.ts +23 -13
- package/dist/chat/runtime/processing-reaction.d.ts +1 -0
- package/dist/chat/runtime/reply-executor.d.ts +5 -0
- package/dist/chat/runtime/request-deadline.d.ts +8 -0
- package/dist/chat/runtime/slack-resume.d.ts +4 -5
- package/dist/chat/runtime/slack-runtime.d.ts +10 -0
- package/dist/chat/runtime/thread-context.d.ts +5 -2
- package/dist/chat/runtime/timeout-resume-runner.d.ts +19 -0
- package/dist/chat/runtime/turn-preparation.d.ts +1 -0
- package/dist/chat/runtime/turn.d.ts +13 -0
- package/dist/chat/sandbox/egress-policy.d.ts +1 -1
- package/dist/chat/sandbox/egress-session.d.ts +13 -12
- package/dist/chat/sandbox/sandbox.d.ts +2 -3
- package/dist/chat/services/timeout-resume.d.ts +9 -4
- package/dist/chat/services/turn-session-record.d.ts +19 -2
- package/dist/chat/slack/adapter-context.d.ts +25 -0
- package/dist/chat/slack/conversation-context.d.ts +28 -0
- package/dist/chat/state/turn-session.d.ts +1 -1
- package/dist/chat/task-execution/heartbeat.d.ts +13 -0
- package/dist/chat/task-execution/queue-signing.d.ts +12 -0
- package/dist/chat/task-execution/queue.d.ts +13 -0
- package/dist/chat/task-execution/slack-work.d.ts +32 -0
- package/dist/chat/task-execution/store.d.ts +153 -0
- package/dist/chat/task-execution/vercel-callback.d.ts +21 -0
- package/dist/chat/task-execution/vercel-queue.d.ts +16 -0
- package/dist/chat/task-execution/worker.d.ts +28 -0
- package/dist/{chunk-EDHJIYHS.js → chunk-657CJCUO.js} +218 -62
- package/dist/chunk-6YY4Q3D4.js +12 -0
- package/dist/chunk-75UZ4JLC.js +213 -0
- package/dist/{chunk-PYU2YB35.js → chunk-F57QSMOJ.js} +1 -1
- package/dist/{chunk-K3JNVV4Q.js → chunk-HRQQS63X.js} +2 -2
- package/dist/{chunk-SCQPBJAU.js → chunk-QUXPUKBH.js} +1 -7
- package/dist/{chunk-7KZXQNA6.js → chunk-X2HJLKQT.js} +368 -13
- package/dist/{chunk-OMQ5X5QH.js → chunk-ZOV3XJAH.js} +3 -2
- package/dist/cli/check.js +115 -2
- package/dist/cli/init.js +13 -1
- package/dist/cli/snapshot-warmup.js +3 -3
- package/dist/deployment.d.ts +4 -0
- package/dist/handlers/heartbeat.d.ts +5 -1
- package/dist/handlers/turn-resume.d.ts +3 -2
- package/dist/handlers/webhooks.d.ts +11 -9
- package/dist/instrumentation.js +1 -0
- package/dist/nitro.d.ts +3 -1
- package/dist/nitro.js +69 -5
- package/dist/reporting.js +13 -16
- package/dist/vercel.d.ts +1 -1
- package/dist/vercel.js +1 -1
- package/package.json +5 -4
- package/dist/chat/services/turn-continuation-response.d.ts +0 -2
- package/dist/chat/slack/turn-continuation-notice.d.ts +0 -8
- 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
|
}
|
|
@@ -1962,6 +2072,10 @@ function normalizeCredentials(data, name) {
|
|
|
1962
2072
|
`Plugin ${name} credentials.api-headers`,
|
|
1963
2073
|
{ forbiddenKeys: FORBIDDEN_API_HEADER_NAMES }
|
|
1964
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;
|
|
1965
2079
|
return {
|
|
1966
2080
|
type: "github-app",
|
|
1967
2081
|
domains,
|
|
@@ -1970,7 +2084,8 @@ function normalizeCredentials(data, name) {
|
|
|
1970
2084
|
...result.data["auth-token-placeholder"] ? { authTokenPlaceholder: result.data["auth-token-placeholder"] } : {},
|
|
1971
2085
|
appIdEnv: result.data["app-id-env"],
|
|
1972
2086
|
privateKeyEnv: result.data["private-key-env"],
|
|
1973
|
-
installationIdEnv: result.data["installation-id-env"]
|
|
2087
|
+
installationIdEnv: result.data["installation-id-env"],
|
|
2088
|
+
...systemReadPermissions ? { systemReadPermissions } : {}
|
|
1974
2089
|
};
|
|
1975
2090
|
}
|
|
1976
2091
|
function normalizeRuntimeDependencies(entries, name) {
|
|
@@ -2620,54 +2735,6 @@ function resolveGitHubApiDomain(credentials) {
|
|
|
2620
2735
|
}
|
|
2621
2736
|
return apiDomain;
|
|
2622
2737
|
}
|
|
2623
|
-
var KNOWN_SCOPES = /* @__PURE__ */ new Set([
|
|
2624
|
-
"actions",
|
|
2625
|
-
"administration",
|
|
2626
|
-
"checks",
|
|
2627
|
-
"codespaces",
|
|
2628
|
-
"contents",
|
|
2629
|
-
"deployments",
|
|
2630
|
-
"environments",
|
|
2631
|
-
"issues",
|
|
2632
|
-
"metadata",
|
|
2633
|
-
"packages",
|
|
2634
|
-
"pages",
|
|
2635
|
-
"pull_requests",
|
|
2636
|
-
"repository_hooks",
|
|
2637
|
-
"repository_projects",
|
|
2638
|
-
"secret_scanning_alerts",
|
|
2639
|
-
"secrets",
|
|
2640
|
-
"security_events",
|
|
2641
|
-
"statuses",
|
|
2642
|
-
"vulnerability_alerts",
|
|
2643
|
-
"workflows"
|
|
2644
|
-
]);
|
|
2645
|
-
function capabilitiesToPermissions(capabilities, pluginName) {
|
|
2646
|
-
const permissions = {};
|
|
2647
|
-
const prefix = `${pluginName}.`;
|
|
2648
|
-
for (const capability of capabilities) {
|
|
2649
|
-
if (!capability.startsWith(prefix)) {
|
|
2650
|
-
throw new Error(`Unsupported GitHub capability: ${capability}`);
|
|
2651
|
-
}
|
|
2652
|
-
const suffix = capability.slice(prefix.length);
|
|
2653
|
-
const lastDot = suffix.lastIndexOf(".");
|
|
2654
|
-
if (lastDot === -1) {
|
|
2655
|
-
throw new Error(`Unsupported GitHub capability: ${capability}`);
|
|
2656
|
-
}
|
|
2657
|
-
const scopeRaw = suffix.slice(0, lastDot);
|
|
2658
|
-
const level = suffix.slice(lastDot + 1);
|
|
2659
|
-
if (level !== "read" && level !== "write") {
|
|
2660
|
-
throw new Error(`Unsupported GitHub capability: ${capability}`);
|
|
2661
|
-
}
|
|
2662
|
-
const scope = scopeRaw.replace(/-/g, "_");
|
|
2663
|
-
if (!KNOWN_SCOPES.has(scope)) {
|
|
2664
|
-
throw new Error(`Unsupported GitHub capability: ${capability}`);
|
|
2665
|
-
}
|
|
2666
|
-
const existing = permissions[scope];
|
|
2667
|
-
permissions[scope] = existing === "write" || level === "write" ? "write" : "read";
|
|
2668
|
-
}
|
|
2669
|
-
return permissions;
|
|
2670
|
-
}
|
|
2671
2738
|
function createGitHubAppBroker(manifest, credentials) {
|
|
2672
2739
|
const provider = manifest.name;
|
|
2673
2740
|
const {
|
|
@@ -2694,7 +2761,23 @@ function createGitHubAppBroker(manifest, credentials) {
|
|
|
2694
2761
|
const normalizedApiDomain = apiDomain.toLowerCase();
|
|
2695
2762
|
return normalizedDomain === "github.com" || normalizedApiDomain.startsWith("api.") && normalizedDomain === normalizedApiDomain.slice("api.".length);
|
|
2696
2763
|
}
|
|
2697
|
-
const permissions = manifest.capabilities?.length ?
|
|
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
|
+
}
|
|
2698
2781
|
function createLease(params) {
|
|
2699
2782
|
return {
|
|
2700
2783
|
id: randomUUID2(),
|
|
@@ -2734,9 +2817,14 @@ function createGitHubAppBroker(manifest, credentials) {
|
|
|
2734
2817
|
return {
|
|
2735
2818
|
async issue(input) {
|
|
2736
2819
|
const installationId = resolveInstallationId();
|
|
2737
|
-
const tokenRequestBody = permissions ? { permissions } : {};
|
|
2738
2820
|
const appId = resolveAppId(appIdEnv);
|
|
2739
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 } : {};
|
|
2740
2828
|
const accessTokenResponse = await githubRequest(apiBase, `/app/installations/${installationId}/access_tokens`, {
|
|
2741
2829
|
method: "POST",
|
|
2742
2830
|
token: appJwt,
|
|
@@ -2770,6 +2858,79 @@ var CredentialUnavailableError = class extends Error {
|
|
|
2770
2858
|
}
|
|
2771
2859
|
};
|
|
2772
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
|
+
|
|
2773
2934
|
// src/chat/credentials/oauth-scope.ts
|
|
2774
2935
|
function parseScope(scope) {
|
|
2775
2936
|
if (!scope) {
|
|
@@ -2931,6 +3092,7 @@ function createOAuthBearerBroker(manifest, credentials, deps) {
|
|
|
2931
3092
|
async issue(input) {
|
|
2932
3093
|
const envToken = process.env[authTokenEnv]?.trim();
|
|
2933
3094
|
const oauth = manifest.oauth;
|
|
3095
|
+
const userSubjectId = credentialUserSubjectId(input.context);
|
|
2934
3096
|
if (!oauth) {
|
|
2935
3097
|
if (envToken) {
|
|
2936
3098
|
return buildLease(envToken, Date.now() + MAX_LEASE_MS3, input.reason);
|
|
@@ -2940,11 +3102,8 @@ function createOAuthBearerBroker(manifest, credentials, deps) {
|
|
|
2940
3102
|
`No ${provider} credentials available.`
|
|
2941
3103
|
);
|
|
2942
3104
|
}
|
|
2943
|
-
if (
|
|
2944
|
-
const stored = await deps.userTokenStore.get(
|
|
2945
|
-
input.requesterId,
|
|
2946
|
-
provider
|
|
2947
|
-
);
|
|
3105
|
+
if (userSubjectId) {
|
|
3106
|
+
const stored = await deps.userTokenStore.get(userSubjectId, provider);
|
|
2948
3107
|
if (stored) {
|
|
2949
3108
|
if (!hasRequiredOAuthScope(stored.scope, oauth.scope)) {
|
|
2950
3109
|
throw new CredentialUnavailableError(
|
|
@@ -2966,11 +3125,7 @@ function createOAuthBearerBroker(manifest, credentials, deps) {
|
|
|
2966
3125
|
`Your ${provider} connection needs to be reauthorized.`
|
|
2967
3126
|
);
|
|
2968
3127
|
}
|
|
2969
|
-
await deps.userTokenStore.set(
|
|
2970
|
-
input.requesterId,
|
|
2971
|
-
provider,
|
|
2972
|
-
refreshed
|
|
2973
|
-
);
|
|
3128
|
+
await deps.userTokenStore.set(userSubjectId, provider, refreshed);
|
|
2974
3129
|
return buildLease(
|
|
2975
3130
|
refreshed.accessToken,
|
|
2976
3131
|
getLeaseExpiry(refreshed.expiresAt),
|
|
@@ -3462,6 +3617,7 @@ export {
|
|
|
3462
3617
|
resolveAuthTokenPlaceholder,
|
|
3463
3618
|
parsePluginManifest,
|
|
3464
3619
|
CredentialUnavailableError,
|
|
3620
|
+
parseCredentialContext,
|
|
3465
3621
|
hasRequiredOAuthScope,
|
|
3466
3622
|
buildOAuthTokenRequest,
|
|
3467
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,12 +2,12 @@ import {
|
|
|
2
2
|
SANDBOX_WORKSPACE_ROOT,
|
|
3
3
|
getStateAdapter,
|
|
4
4
|
toOptionalTrimmed
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-ZOV3XJAH.js";
|
|
6
6
|
import {
|
|
7
7
|
getPluginRuntimeDependencies,
|
|
8
8
|
getPluginRuntimePostinstall,
|
|
9
9
|
withSpan
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-657CJCUO.js";
|
|
11
11
|
|
|
12
12
|
// src/chat/sandbox/runtime-dependency-snapshots.ts
|
|
13
13
|
import { createHash } from "crypto";
|
|
@@ -2,13 +2,7 @@
|
|
|
2
2
|
function juniorVercelConfig(options = {}) {
|
|
3
3
|
const buildCommand = options.buildCommand === void 0 ? "pnpm build" : options.buildCommand;
|
|
4
4
|
const config = {
|
|
5
|
-
framework: "nitro"
|
|
6
|
-
crons: [
|
|
7
|
-
{
|
|
8
|
-
path: "/api/internal/heartbeat",
|
|
9
|
-
schedule: "* * * * *"
|
|
10
|
-
}
|
|
11
|
-
]
|
|
5
|
+
framework: "nitro"
|
|
12
6
|
};
|
|
13
7
|
if (buildCommand !== null) {
|
|
14
8
|
config.buildCommand = buildCommand;
|