@standardagents/builder 0.37.8 → 0.38.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.
- package/dist/built-in-routes.js +1246 -518
- package/dist/built-in-routes.js.map +1 -1
- package/dist/client/{ApiKeysView-L85eJb6G.js → ApiKeysView-AH5i-H6j.js} +1 -1
- package/dist/client/CenteredContentView-DaBp0K-A.js +1 -0
- package/dist/client/{CompositionView-BGp0EJCk.js → CompositionView-yY1Q4M23.js} +1 -1
- package/dist/client/{ConfirmDialog.vue_vue_type_script_setup_true_lang-DgwqZrLV.js → ConfirmDialog.vue_vue_type_script_setup_true_lang-Bwo5CJzF.js} +1 -1
- package/dist/client/{CopyButton.vue_vue_type_script_setup_true_lang-B8cGgU2J.js → CopyButton.vue_vue_type_script_setup_true_lang-D0WYwWyA.js} +1 -1
- package/dist/client/{DataTable.vue_vue_type_script_setup_true_lang-CRBXym9D.js → DataTable.vue_vue_type_script_setup_true_lang-1wwPn2aY.js} +1 -1
- package/dist/client/{JsonViewer-DkHnIfq3.js → JsonViewer-Bi8Zdmir.js} +1 -1
- package/dist/client/LoginView-BIKahEU6.js +1 -0
- package/dist/client/{MarketplaceView-DEnujUBs.js → MarketplaceView-DPDPVH68.js} +1 -1
- package/dist/client/{Modal.vue_vue_type_script_setup_true_lang-keKEwm3K.js → Modal.vue_vue_type_script_setup_true_lang-D1_rfOsy.js} +1 -1
- package/dist/client/{ModelModal.vue_vue_type_script_setup_true_lang-t1n0bbJe.js → ModelModal.vue_vue_type_script_setup_true_lang-DSLeOdxr.js} +1 -1
- package/dist/client/{ModelsView-BkCLr8sp.js → ModelsView-Q2WXu1Gw.js} +1 -1
- package/dist/client/{PromptEditView-BjCfsJQE.js → PromptEditView-BzA-3n1w.js} +1 -1
- package/dist/client/{PromptModal-nxu_LIv6.js → PromptModal-CJWh_cru.js} +1 -1
- package/dist/client/{PromptsView-1yXGCmEZ.js → PromptsView-BezNl-Et.js} +1 -1
- package/dist/client/{ProvidersView-DxF6gafk.js → ProvidersView-BuzSKxuT.js} +1 -1
- package/dist/client/ThreadInspectorPane.vue_vue_type_script_setup_true_lang-DOxNp_3C.js +22 -0
- package/dist/client/{ThreadsView-CBup_w8u.js → ThreadsView-DPCpZA4J.js} +1 -1
- package/dist/client/{ToolsView-B30TfXU9.js → ToolsView-DMjFMAhH.js} +1 -1
- package/dist/client/{UiCodeBlock.vue_vue_type_script_setup_true_lang-BdyzSxZZ.js → UiCodeBlock.vue_vue_type_script_setup_true_lang-7FgZmkfs.js} +1 -1
- package/dist/client/{UsersView-kE7Xr4f3.js → UsersView-B7jXLNQs.js} +1 -1
- package/dist/client/{VariablesView-yYuynG0M.js → VariablesView-CF7x0G8g.js} +1 -1
- package/dist/client/assets/{ThreadInspectorPane-BRGO_P0_.css → ThreadInspectorPane-CZMdV0Tb.css} +1 -1
- package/dist/client/assets/{index-B-69GGhJ.css → index-DAABRRAA.css} +1 -1
- package/dist/client/{check-YKi1o6p6.js → check-CD2lvcVi.js} +1 -1
- package/dist/client/{chevron-right-T0zzq_GX.js → chevron-right-bWZrmJ5a.js} +1 -1
- package/dist/client/{copy-C_gUGAj1.js → copy-B7nifl6a.js} +1 -1
- package/dist/client/{formkit-CE26dtFp.js → formkit-DJxUzqRQ.js} +1 -1
- package/dist/client/index-eGECJFYe.js +6 -0
- package/dist/client/index.html +6 -6
- package/dist/client/{package-B70IFSDB.js → package-Dyv7fTIQ.js} +1 -1
- package/dist/client/{plus-BN9IHYdt.js → plus-XkSslfF4.js} +1 -1
- package/dist/client/{syntax-D-ZcovVx.js → syntax-D68HCEYm.js} +1 -1
- package/dist/client/{timeAgo-G1ovbWPH.js → timeAgo-DRBdu9ed.js} +1 -1
- package/dist/client/{useActionFeedback-7pfPjKMi.js → useActionFeedback-FN4t6ezB.js} +1 -1
- package/dist/client/{vendor-TPZjEwCU.js → vendor-c_uwtQ-S.js} +13 -13
- package/dist/client/{vue-CZ-ORfS3.js → vue-BuvSxRmI.js} +1 -1
- package/dist/{index-Lfan8QMN.d.ts → index-CF-lgN47.d.ts} +83 -12
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1155 -360
- package/dist/index.js.map +1 -1
- package/dist/plugin.js +131 -72
- package/dist/plugin.js.map +1 -1
- package/dist/runtime.d.ts +69 -11
- package/dist/runtime.js +1018 -280
- package/dist/runtime.js.map +1 -1
- package/dist/test.d.ts +1 -1
- package/package.json +7 -6
- package/dist/client/CenteredContentView-D9jkWoLc.js +0 -1
- package/dist/client/LoginView-BXD9Odc-.js +0 -1
- package/dist/client/ThreadInspectorPane.vue_vue_type_script_setup_true_lang-CjwWJ3uw.js +0 -22
- package/dist/client/index-AUGwDdSH.js +0 -6
package/dist/plugin.js
CHANGED
|
@@ -689,6 +689,27 @@ declare module 'virtual:@standardagents/builder' {
|
|
|
689
689
|
validateSession(tokenHash: string): Promise<{ user_id: string; expires_at: number } | null>;
|
|
690
690
|
cleanupSessions(): Promise<number>;
|
|
691
691
|
deleteSession(tokenHash: string): Promise<void>;
|
|
692
|
+
createSuperAdminSession(params: {
|
|
693
|
+
token_hash: string;
|
|
694
|
+
expires_at: number;
|
|
695
|
+
}): Promise<void>;
|
|
696
|
+
validateSuperAdminSession(tokenHash: string): Promise<boolean>;
|
|
697
|
+
deleteSuperAdminSession(tokenHash: string): Promise<void>;
|
|
698
|
+
createWebSocketTicket(params: {
|
|
699
|
+
ticket_hash: string;
|
|
700
|
+
pathname: string;
|
|
701
|
+
auth_json: string;
|
|
702
|
+
expires_at: number;
|
|
703
|
+
}): Promise<void>;
|
|
704
|
+
consumeWebSocketTicket(params: {
|
|
705
|
+
ticket_hash: string;
|
|
706
|
+
pathname: string;
|
|
707
|
+
}): Promise<string | null>;
|
|
708
|
+
consumeAuthRateLimit(params: {
|
|
709
|
+
key: string;
|
|
710
|
+
limit: number;
|
|
711
|
+
window_seconds: number;
|
|
712
|
+
}): Promise<{ allowed: boolean; retry_after: number; remaining: number }>;
|
|
692
713
|
|
|
693
714
|
// API key methods
|
|
694
715
|
createApiKey(params: {
|
|
@@ -1289,6 +1310,7 @@ function resolveLocalBootstrapCookie(projectRoot, routePath, cookieHeader) {
|
|
|
1289
1310
|
if (hasSessionCookie(cookieHeader)) return null;
|
|
1290
1311
|
return findLocalBootstrapSession(projectRoot)?.session.session_cookie ?? null;
|
|
1291
1312
|
}
|
|
1313
|
+
var SESSION_COOKIE_NAME = "agtuser_session";
|
|
1292
1314
|
|
|
1293
1315
|
// src/sdk/generators/generateModelFile.ts
|
|
1294
1316
|
function generateModelFile(data, options) {
|
|
@@ -1355,7 +1377,7 @@ function generateModelFile(data, options) {
|
|
|
1355
1377
|
return lines.join("\n");
|
|
1356
1378
|
}
|
|
1357
1379
|
function escapeString(str) {
|
|
1358
|
-
return str.replace(
|
|
1380
|
+
return str.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
1359
1381
|
}
|
|
1360
1382
|
|
|
1361
1383
|
// src/sdk/generators/jsonSchemaToZod.ts
|
|
@@ -1886,7 +1908,7 @@ function formatSideConfig(config) {
|
|
|
1886
1908
|
return parts.join("\n");
|
|
1887
1909
|
}
|
|
1888
1910
|
function escapeString3(str) {
|
|
1889
|
-
return str.replace(
|
|
1911
|
+
return str.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
1890
1912
|
}
|
|
1891
1913
|
function formatSessionBinding(binding) {
|
|
1892
1914
|
if (typeof binding === "string") {
|
|
@@ -6695,7 +6717,7 @@ function isProviderIconRoute(routePath) {
|
|
|
6695
6717
|
return /^\/api\/providers\/[^/]+\/icon$/.test(routePath);
|
|
6696
6718
|
}
|
|
6697
6719
|
function isHostedInstance(env) {
|
|
6698
|
-
const value = env
|
|
6720
|
+
const value = env && typeof env === "object" ? Reflect.get(env, "STANDARD_AGENTS_HOSTED") : void 0;
|
|
6699
6721
|
if (typeof value === "string") {
|
|
6700
6722
|
const normalized = value.trim().toLowerCase();
|
|
6701
6723
|
return normalized !== "" && normalized !== "0" && normalized !== "false";
|
|
@@ -6713,6 +6735,7 @@ function isTrustedLocalDevelopmentRequest(request, env) {
|
|
|
6713
6735
|
return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1" || hostname.endsWith(".localhost") || hostname.endsWith(".orb.local");
|
|
6714
6736
|
}
|
|
6715
6737
|
function isAdminOnlyApiRoute(routePath, method = "GET") {
|
|
6738
|
+
if (routePath === "/api/hooks") return true;
|
|
6716
6739
|
if (routePath === "/api/skills" || routePath.startsWith("/api/skills/")) return true;
|
|
6717
6740
|
if (routePath === "/api/pack" || routePath.startsWith("/api/pack/")) return true;
|
|
6718
6741
|
if (routePath === "/api/unpack" || routePath.startsWith("/api/unpack/")) return true;
|
|
@@ -6731,6 +6754,9 @@ function isAdminOnlyApiRoute(routePath, method = "GET") {
|
|
|
6731
6754
|
}
|
|
6732
6755
|
|
|
6733
6756
|
// src/plugin/dev-middleware.ts
|
|
6757
|
+
function isEncryptedSocket(socket) {
|
|
6758
|
+
return "encrypted" in socket && socket.encrypted === true;
|
|
6759
|
+
}
|
|
6734
6760
|
function readRawRequestBody(req) {
|
|
6735
6761
|
return new Promise((resolve3, reject) => {
|
|
6736
6762
|
const chunks = [];
|
|
@@ -6755,6 +6781,36 @@ function resolveContainedFile(baseDir, requestPath) {
|
|
|
6755
6781
|
return null;
|
|
6756
6782
|
}
|
|
6757
6783
|
}
|
|
6784
|
+
function firstHeader(value) {
|
|
6785
|
+
return Array.isArray(value) ? value[0] : value;
|
|
6786
|
+
}
|
|
6787
|
+
function isSameOriginDevRequest(req) {
|
|
6788
|
+
const fetchSite = firstHeader(req.headers["sec-fetch-site"])?.trim().toLowerCase();
|
|
6789
|
+
if (fetchSite && fetchSite !== "same-origin" && fetchSite !== "none") {
|
|
6790
|
+
return false;
|
|
6791
|
+
}
|
|
6792
|
+
const origin = firstHeader(req.headers.origin)?.trim();
|
|
6793
|
+
if (!origin) return true;
|
|
6794
|
+
if (origin === "null") return false;
|
|
6795
|
+
try {
|
|
6796
|
+
const forwardedProtocol = firstHeader(req.headers["x-forwarded-proto"])?.split(",")[0]?.trim().toLowerCase();
|
|
6797
|
+
const protocol = forwardedProtocol === "https" || forwardedProtocol === "http" ? forwardedProtocol : isEncryptedSocket(req.socket) ? "https" : "http";
|
|
6798
|
+
const requestOrigin = new URL(`${protocol}://${String(req.headers.host || "").trim()}`).origin;
|
|
6799
|
+
return new URL(origin).origin === requestOrigin;
|
|
6800
|
+
} catch {
|
|
6801
|
+
return false;
|
|
6802
|
+
}
|
|
6803
|
+
}
|
|
6804
|
+
function hasDevAuthoringCredential(req) {
|
|
6805
|
+
const cookie = firstHeader(req.headers.cookie) || "";
|
|
6806
|
+
const hasSession = cookie.split(";").some((part) => {
|
|
6807
|
+
const separator = part.indexOf("=");
|
|
6808
|
+
return separator !== -1 && part.slice(0, separator).trim() === SESSION_COOKIE_NAME && part.slice(separator + 1).trim() !== "";
|
|
6809
|
+
});
|
|
6810
|
+
if (hasSession) return true;
|
|
6811
|
+
const authorization = firstHeader(req.headers.authorization)?.trim() || "";
|
|
6812
|
+
return /^Bearer\s+\S+$/.test(authorization);
|
|
6813
|
+
}
|
|
6758
6814
|
function injectUiConfigIntoHtml(htmlContent) {
|
|
6759
6815
|
const configScript = `<script>window.__AGENTBUILDER_CONFIG__ = { devMode: true };</script>`;
|
|
6760
6816
|
return htmlContent.replace(/\/agents\//g, "/").replace("</head>", `${configScript}</head>`);
|
|
@@ -6809,11 +6865,21 @@ function createDevMiddleware(server, context) {
|
|
|
6809
6865
|
);
|
|
6810
6866
|
} catch {
|
|
6811
6867
|
}
|
|
6812
|
-
if (isAdminOnlyApiRoute(routePath, method)
|
|
6813
|
-
|
|
6814
|
-
|
|
6815
|
-
|
|
6816
|
-
|
|
6868
|
+
if (isAdminOnlyApiRoute(routePath, method)) {
|
|
6869
|
+
if (!trustedLocalHost || !isSameOriginDevRequest(req)) {
|
|
6870
|
+
res.statusCode = 403;
|
|
6871
|
+
res.setHeader("Content-Type", "application/json");
|
|
6872
|
+
res.setHeader("Cache-Control", "no-store");
|
|
6873
|
+
res.end(JSON.stringify({ error: "Authoring APIs require a same-origin local request" }));
|
|
6874
|
+
return;
|
|
6875
|
+
}
|
|
6876
|
+
if (!hasDevAuthoringCredential(req)) {
|
|
6877
|
+
res.statusCode = 401;
|
|
6878
|
+
res.setHeader("Content-Type", "application/json");
|
|
6879
|
+
res.setHeader("Cache-Control", "no-store");
|
|
6880
|
+
res.end(JSON.stringify({ error: "Authoring APIs require an authenticated local session" }));
|
|
6881
|
+
return;
|
|
6882
|
+
}
|
|
6817
6883
|
}
|
|
6818
6884
|
if (await handleConfigApiRequest({
|
|
6819
6885
|
req,
|
|
@@ -7462,14 +7528,21 @@ import { prompts, promptNames } from "virtual:@standardagents-prompts";
|
|
|
7462
7528
|
import { agents, agentNames } from "virtual:@standardagents-agents";
|
|
7463
7529
|
import { registry } from "virtual:@standardagents-registry";
|
|
7464
7530
|
import {
|
|
7531
|
+
authenticate,
|
|
7465
7532
|
requireAuth,
|
|
7466
7533
|
createThreadEndpointHandler,
|
|
7467
7534
|
canAccessThread,
|
|
7535
|
+
endpointCallerFromAuth,
|
|
7468
7536
|
isHostedInstance,
|
|
7537
|
+
isTrustedLocalDevelopmentRequest,
|
|
7538
|
+
isSameOriginBrowserRequest,
|
|
7469
7539
|
isPublicApiRoute,
|
|
7470
7540
|
isAdminOnlyApiRoute,
|
|
7541
|
+
applyRuntimeCors,
|
|
7542
|
+
runtimeCorsHeaders,
|
|
7543
|
+
runtimePreflightResponse,
|
|
7471
7544
|
} from "@standardagents/builder/runtime";
|
|
7472
|
-
import { isThreadEndpoint } from "@standardagents/spec";
|
|
7545
|
+
import { isThreadEndpoint, getEndpointAccess } from "@standardagents/spec";
|
|
7473
7546
|
|
|
7474
7547
|
function platformEndpoint(env) {
|
|
7475
7548
|
const configured =
|
|
@@ -7524,71 +7597,34 @@ function isHtmlNavigationRequest(request) {
|
|
|
7524
7597
|
return (accept === '' || accept === '*/*') && isUiNavigationPath(pathname);
|
|
7525
7598
|
}
|
|
7526
7599
|
|
|
7527
|
-
// CORS headers for API responses
|
|
7528
|
-
const CORS_HEADERS = {
|
|
7529
|
-
"Access-Control-Allow-Origin": "*",
|
|
7530
|
-
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
|
|
7531
|
-
"Access-Control-Allow-Headers": "Content-Type, Authorization, X-Requested-With",
|
|
7532
|
-
"Access-Control-Max-Age": "86400",
|
|
7533
|
-
};
|
|
7534
|
-
|
|
7535
7600
|
// Helper to create headers with CORS
|
|
7536
|
-
function corsHeaders(contentType) {
|
|
7601
|
+
function corsHeaders(contentType, request, env) {
|
|
7537
7602
|
return {
|
|
7538
7603
|
"Content-Type": contentType,
|
|
7539
|
-
...
|
|
7604
|
+
...runtimeCorsHeaders(request, env),
|
|
7540
7605
|
};
|
|
7541
7606
|
}
|
|
7542
7607
|
|
|
7543
|
-
// Helper to add CORS headers to any Response without touching the body
|
|
7544
|
-
function addCorsHeaders(response) {
|
|
7545
|
-
// Skip WebSocket upgrade responses - they can't be wrapped
|
|
7546
|
-
if (response.status === 101) {
|
|
7547
|
-
return response;
|
|
7548
|
-
}
|
|
7549
|
-
|
|
7550
|
-
// Skip if already has CORS headers
|
|
7551
|
-
if (response.headers.has("Access-Control-Allow-Origin")) {
|
|
7552
|
-
return response;
|
|
7553
|
-
}
|
|
7554
|
-
|
|
7555
|
-
// Prefer mutating the original Response headers. Rebuilding a Response from
|
|
7556
|
-
// response.headers can drop special headers such as Set-Cookie in Worker
|
|
7557
|
-
// runtimes, even when the header is not visible through Headers.has().
|
|
7558
|
-
try {
|
|
7559
|
-
for (const [key, value] of Object.entries(CORS_HEADERS)) {
|
|
7560
|
-
response.headers.set(key, value);
|
|
7561
|
-
}
|
|
7562
|
-
return response;
|
|
7563
|
-
} catch {
|
|
7564
|
-
// Some Responses, especially fetched upstream responses, have immutable
|
|
7565
|
-
// headers. Fall back to wrapping those responses.
|
|
7566
|
-
}
|
|
7567
|
-
|
|
7568
|
-
// Create new headers with CORS added
|
|
7569
|
-
const newHeaders = new Headers(response.headers);
|
|
7570
|
-
for (const [key, value] of Object.entries(CORS_HEADERS)) {
|
|
7571
|
-
newHeaders.set(key, value);
|
|
7572
|
-
}
|
|
7573
|
-
|
|
7574
|
-
// Return new Response with same body stream (not cloned, just transferred)
|
|
7575
|
-
return new Response(response.body, {
|
|
7576
|
-
status: response.status,
|
|
7577
|
-
statusText: response.statusText,
|
|
7578
|
-
headers: newHeaders,
|
|
7579
|
-
});
|
|
7580
|
-
}
|
|
7581
|
-
|
|
7582
7608
|
export async function router(request, env) {
|
|
7583
7609
|
const url = new URL(request.url);
|
|
7584
7610
|
const pathname = url.pathname;
|
|
7585
7611
|
|
|
7586
7612
|
// Handle CORS preflight requests
|
|
7587
7613
|
if (request.method === "OPTIONS") {
|
|
7588
|
-
return
|
|
7589
|
-
|
|
7590
|
-
|
|
7591
|
-
|
|
7614
|
+
return runtimePreflightResponse(request, env);
|
|
7615
|
+
}
|
|
7616
|
+
|
|
7617
|
+
// WebSockets do not use CORS. Reject foreign browser provenance before
|
|
7618
|
+
// route dispatch so a malicious page cannot open a local stream/bridge even
|
|
7619
|
+
// if a browser were to attach ambient cookies to the handshake.
|
|
7620
|
+
if (
|
|
7621
|
+
isTrustedLocalDevelopmentRequest(request, env) &&
|
|
7622
|
+
!isSameOriginBrowserRequest(request)
|
|
7623
|
+
) {
|
|
7624
|
+
return Response.json(
|
|
7625
|
+
{ error: "Cross-origin access is disabled for local development" },
|
|
7626
|
+
{ status: 403, headers: { "Cache-Control": "no-store" } }
|
|
7627
|
+
);
|
|
7592
7628
|
}
|
|
7593
7629
|
|
|
7594
7630
|
const routePath = pathname || "/";
|
|
@@ -7612,8 +7648,16 @@ ${packedThreadRouteCode}
|
|
|
7612
7648
|
);
|
|
7613
7649
|
|
|
7614
7650
|
if (routeMatch) {
|
|
7651
|
+
let controller = await routeMatch.data();
|
|
7652
|
+
|
|
7653
|
+
// Endpoint-declared access (spec: EndpointAccess). A 'public' declaration
|
|
7654
|
+
// opts that one endpoint out of the router's authentication gate; the
|
|
7655
|
+
// handler still receives the resolved caller identity when the request
|
|
7656
|
+
// presents verifiable credentials.
|
|
7657
|
+
const declaredPublic = getEndpointAccess(controller) === 'public';
|
|
7658
|
+
|
|
7615
7659
|
// Check if authentication is required for this route
|
|
7616
|
-
const publicRoute = isPublicApiRoute(routePath, request, env);
|
|
7660
|
+
const publicRoute = declaredPublic || isPublicApiRoute(routePath, request, env);
|
|
7617
7661
|
const isApiRoute = routePath.startsWith('/api/');
|
|
7618
7662
|
|
|
7619
7663
|
let authContext = null;
|
|
@@ -7628,13 +7672,13 @@ ${packedThreadRouteCode}
|
|
|
7628
7672
|
|
|
7629
7673
|
// If requireAuth returns a Response, it's an error (401)
|
|
7630
7674
|
if (authResult instanceof Response) {
|
|
7631
|
-
return
|
|
7675
|
+
return applyRuntimeCors(authResult, request, env);
|
|
7632
7676
|
}
|
|
7633
7677
|
|
|
7634
7678
|
authContext = authResult;
|
|
7635
7679
|
|
|
7636
7680
|
if (isAdminOnlyApiRoute(routePath, request.method) && authContext.user.role !== 'admin') {
|
|
7637
|
-
return
|
|
7681
|
+
return applyRuntimeCors(Response.json({ error: 'Forbidden: Admin access required' }, { status: 403 }), request, env);
|
|
7638
7682
|
}
|
|
7639
7683
|
|
|
7640
7684
|
if (routePath.startsWith('/api/threads/')) {
|
|
@@ -7648,18 +7692,32 @@ ${packedThreadRouteCode}
|
|
|
7648
7692
|
const agentBuilder = env.AGENT_BUILDER.get(agentBuilderId);
|
|
7649
7693
|
const thread = await agentBuilder.getThread(threadId);
|
|
7650
7694
|
if (!thread) {
|
|
7651
|
-
return
|
|
7695
|
+
return applyRuntimeCors(Response.json({ error: \`Thread not found: \${threadId}\` }, { status: 404 }), request, env);
|
|
7652
7696
|
}
|
|
7653
7697
|
if (!canAccessThread(authContext, thread)) {
|
|
7654
|
-
return
|
|
7698
|
+
return applyRuntimeCors(Response.json({ error: "Forbidden: You don't have access to this thread" }, { status: 403 }), request, env);
|
|
7655
7699
|
}
|
|
7656
7700
|
threadAccess = { threadId, thread };
|
|
7657
7701
|
}
|
|
7658
7702
|
}
|
|
7703
|
+
} else if (isApiRoute && declaredPublic) {
|
|
7704
|
+
// Optional caller resolution for endpoint-declared public routes:
|
|
7705
|
+
// verifiable credentials attribute the request, anything else stays
|
|
7706
|
+
// anonymous instead of being rejected (spec ThreadEndpointAuth).
|
|
7707
|
+
authContext = await authenticate(request, env);
|
|
7708
|
+
if (authContext && routePath.startsWith('/api/threads/')) {
|
|
7709
|
+
const threadId = routeMatch.params?.threadId || routeMatch.params?.id;
|
|
7710
|
+
if (threadId) {
|
|
7711
|
+
const agentBuilderId = env.AGENT_BUILDER.idFromName('singleton');
|
|
7712
|
+
const agentBuilder = env.AGENT_BUILDER.get(agentBuilderId);
|
|
7713
|
+
const thread = await agentBuilder.getThread(threadId);
|
|
7714
|
+
if (thread && canAccessThread(authContext, thread)) {
|
|
7715
|
+
threadAccess = { threadId, thread };
|
|
7716
|
+
}
|
|
7717
|
+
}
|
|
7718
|
+
}
|
|
7659
7719
|
}
|
|
7660
7720
|
|
|
7661
|
-
let controller = await routeMatch.data();
|
|
7662
|
-
|
|
7663
7721
|
// Check if this is a thread endpoint (marked by defineThreadEndpoint)
|
|
7664
7722
|
// If so, wrap it with createThreadEndpointHandler to provide ThreadState
|
|
7665
7723
|
if (isThreadEndpoint(controller)) {
|
|
@@ -7674,21 +7732,22 @@ ${packedThreadRouteCode}
|
|
|
7674
7732
|
config,
|
|
7675
7733
|
tools,
|
|
7676
7734
|
auth: authContext, // Add auth context to controller context
|
|
7735
|
+
caller: endpointCallerFromAuth(authContext), // Spec ControllerContext.caller
|
|
7677
7736
|
threadAccess, // Router's thread authorization, bound to the exact id
|
|
7678
7737
|
};
|
|
7679
7738
|
const result = await controller(context);
|
|
7680
7739
|
|
|
7681
7740
|
if (result instanceof Response) {
|
|
7682
|
-
return
|
|
7741
|
+
return applyRuntimeCors(result, request, env);
|
|
7683
7742
|
}
|
|
7684
7743
|
if (typeof result === "string") {
|
|
7685
7744
|
return new Response(result, {
|
|
7686
|
-
headers: corsHeaders("text/plain"),
|
|
7745
|
+
headers: corsHeaders("text/plain", request, env),
|
|
7687
7746
|
});
|
|
7688
7747
|
}
|
|
7689
7748
|
// JSON responses get CORS headers
|
|
7690
7749
|
return new Response(JSON.stringify(result), {
|
|
7691
|
-
headers: corsHeaders("application/json"),
|
|
7750
|
+
headers: corsHeaders("application/json", request, env),
|
|
7692
7751
|
});
|
|
7693
7752
|
}
|
|
7694
7753
|
|