@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.
Files changed (54) hide show
  1. package/dist/built-in-routes.js +1246 -518
  2. package/dist/built-in-routes.js.map +1 -1
  3. package/dist/client/{ApiKeysView-L85eJb6G.js → ApiKeysView-AH5i-H6j.js} +1 -1
  4. package/dist/client/CenteredContentView-DaBp0K-A.js +1 -0
  5. package/dist/client/{CompositionView-BGp0EJCk.js → CompositionView-yY1Q4M23.js} +1 -1
  6. 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
  7. 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
  8. 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
  9. package/dist/client/{JsonViewer-DkHnIfq3.js → JsonViewer-Bi8Zdmir.js} +1 -1
  10. package/dist/client/LoginView-BIKahEU6.js +1 -0
  11. package/dist/client/{MarketplaceView-DEnujUBs.js → MarketplaceView-DPDPVH68.js} +1 -1
  12. 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
  13. 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
  14. package/dist/client/{ModelsView-BkCLr8sp.js → ModelsView-Q2WXu1Gw.js} +1 -1
  15. package/dist/client/{PromptEditView-BjCfsJQE.js → PromptEditView-BzA-3n1w.js} +1 -1
  16. package/dist/client/{PromptModal-nxu_LIv6.js → PromptModal-CJWh_cru.js} +1 -1
  17. package/dist/client/{PromptsView-1yXGCmEZ.js → PromptsView-BezNl-Et.js} +1 -1
  18. package/dist/client/{ProvidersView-DxF6gafk.js → ProvidersView-BuzSKxuT.js} +1 -1
  19. package/dist/client/ThreadInspectorPane.vue_vue_type_script_setup_true_lang-DOxNp_3C.js +22 -0
  20. package/dist/client/{ThreadsView-CBup_w8u.js → ThreadsView-DPCpZA4J.js} +1 -1
  21. package/dist/client/{ToolsView-B30TfXU9.js → ToolsView-DMjFMAhH.js} +1 -1
  22. 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
  23. package/dist/client/{UsersView-kE7Xr4f3.js → UsersView-B7jXLNQs.js} +1 -1
  24. package/dist/client/{VariablesView-yYuynG0M.js → VariablesView-CF7x0G8g.js} +1 -1
  25. package/dist/client/assets/{ThreadInspectorPane-BRGO_P0_.css → ThreadInspectorPane-CZMdV0Tb.css} +1 -1
  26. package/dist/client/assets/{index-B-69GGhJ.css → index-DAABRRAA.css} +1 -1
  27. package/dist/client/{check-YKi1o6p6.js → check-CD2lvcVi.js} +1 -1
  28. package/dist/client/{chevron-right-T0zzq_GX.js → chevron-right-bWZrmJ5a.js} +1 -1
  29. package/dist/client/{copy-C_gUGAj1.js → copy-B7nifl6a.js} +1 -1
  30. package/dist/client/{formkit-CE26dtFp.js → formkit-DJxUzqRQ.js} +1 -1
  31. package/dist/client/index-eGECJFYe.js +6 -0
  32. package/dist/client/index.html +6 -6
  33. package/dist/client/{package-B70IFSDB.js → package-Dyv7fTIQ.js} +1 -1
  34. package/dist/client/{plus-BN9IHYdt.js → plus-XkSslfF4.js} +1 -1
  35. package/dist/client/{syntax-D-ZcovVx.js → syntax-D68HCEYm.js} +1 -1
  36. package/dist/client/{timeAgo-G1ovbWPH.js → timeAgo-DRBdu9ed.js} +1 -1
  37. package/dist/client/{useActionFeedback-7pfPjKMi.js → useActionFeedback-FN4t6ezB.js} +1 -1
  38. package/dist/client/{vendor-TPZjEwCU.js → vendor-c_uwtQ-S.js} +13 -13
  39. package/dist/client/{vue-CZ-ORfS3.js → vue-BuvSxRmI.js} +1 -1
  40. package/dist/{index-Lfan8QMN.d.ts → index-CF-lgN47.d.ts} +83 -12
  41. package/dist/index.d.ts +2 -2
  42. package/dist/index.js +1155 -360
  43. package/dist/index.js.map +1 -1
  44. package/dist/plugin.js +131 -72
  45. package/dist/plugin.js.map +1 -1
  46. package/dist/runtime.d.ts +69 -11
  47. package/dist/runtime.js +1018 -280
  48. package/dist/runtime.js.map +1 -1
  49. package/dist/test.d.ts +1 -1
  50. package/package.json +7 -6
  51. package/dist/client/CenteredContentView-D9jkWoLc.js +0 -1
  52. package/dist/client/LoginView-BXD9Odc-.js +0 -1
  53. package/dist/client/ThreadInspectorPane.vue_vue_type_script_setup_true_lang-CjwWJ3uw.js +0 -22
  54. 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(/'/g, "\\'").replace(/\\/g, "\\\\");
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(/'/g, "\\'").replace(/\\/g, "\\\\");
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?.STANDARD_AGENTS_HOSTED;
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) && !trustedLocalHost) {
6813
- res.statusCode = 403;
6814
- res.setHeader("Content-Type", "application/json");
6815
- res.end(JSON.stringify({ error: "Authoring APIs are available only from local development hosts" }));
6816
- return;
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
- ...CORS_HEADERS,
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 new Response(null, {
7589
- status: 204,
7590
- headers: CORS_HEADERS,
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 addCorsHeaders(authResult);
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 addCorsHeaders(Response.json({ error: 'Forbidden: Admin access required' }, { status: 403 }));
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 addCorsHeaders(Response.json({ error: \`Thread not found: \${threadId}\` }, { status: 404 }));
7695
+ return applyRuntimeCors(Response.json({ error: \`Thread not found: \${threadId}\` }, { status: 404 }), request, env);
7652
7696
  }
7653
7697
  if (!canAccessThread(authContext, thread)) {
7654
- return addCorsHeaders(Response.json({ error: "Forbidden: You don't have access to this thread" }, { status: 403 }));
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 addCorsHeaders(result);
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