@standardagents/builder 0.38.0 → 0.38.2

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 +1243 -418
  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-BBu-Osn5.d.ts → index-CF-lgN47.d.ts} +74 -11
  41. package/dist/index.d.ts +2 -2
  42. package/dist/index.js +1064 -304
  43. package/dist/index.js.map +1 -1
  44. package/dist/plugin.js +106 -69
  45. package/dist/plugin.js.map +1 -1
  46. package/dist/runtime.d.ts +68 -11
  47. package/dist/runtime.js +950 -225
  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,
@@ -7468,8 +7534,13 @@ import {
7468
7534
  canAccessThread,
7469
7535
  endpointCallerFromAuth,
7470
7536
  isHostedInstance,
7537
+ isTrustedLocalDevelopmentRequest,
7538
+ isSameOriginBrowserRequest,
7471
7539
  isPublicApiRoute,
7472
7540
  isAdminOnlyApiRoute,
7541
+ applyRuntimeCors,
7542
+ runtimeCorsHeaders,
7543
+ runtimePreflightResponse,
7473
7544
  } from "@standardagents/builder/runtime";
7474
7545
  import { isThreadEndpoint, getEndpointAccess } from "@standardagents/spec";
7475
7546
 
@@ -7526,71 +7597,34 @@ function isHtmlNavigationRequest(request) {
7526
7597
  return (accept === '' || accept === '*/*') && isUiNavigationPath(pathname);
7527
7598
  }
7528
7599
 
7529
- // CORS headers for API responses
7530
- const CORS_HEADERS = {
7531
- "Access-Control-Allow-Origin": "*",
7532
- "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
7533
- "Access-Control-Allow-Headers": "Content-Type, Authorization, X-Requested-With",
7534
- "Access-Control-Max-Age": "86400",
7535
- };
7536
-
7537
7600
  // Helper to create headers with CORS
7538
- function corsHeaders(contentType) {
7601
+ function corsHeaders(contentType, request, env) {
7539
7602
  return {
7540
7603
  "Content-Type": contentType,
7541
- ...CORS_HEADERS,
7604
+ ...runtimeCorsHeaders(request, env),
7542
7605
  };
7543
7606
  }
7544
7607
 
7545
- // Helper to add CORS headers to any Response without touching the body
7546
- function addCorsHeaders(response) {
7547
- // Skip WebSocket upgrade responses - they can't be wrapped
7548
- if (response.status === 101) {
7549
- return response;
7550
- }
7551
-
7552
- // Skip if already has CORS headers
7553
- if (response.headers.has("Access-Control-Allow-Origin")) {
7554
- return response;
7555
- }
7556
-
7557
- // Prefer mutating the original Response headers. Rebuilding a Response from
7558
- // response.headers can drop special headers such as Set-Cookie in Worker
7559
- // runtimes, even when the header is not visible through Headers.has().
7560
- try {
7561
- for (const [key, value] of Object.entries(CORS_HEADERS)) {
7562
- response.headers.set(key, value);
7563
- }
7564
- return response;
7565
- } catch {
7566
- // Some Responses, especially fetched upstream responses, have immutable
7567
- // headers. Fall back to wrapping those responses.
7568
- }
7569
-
7570
- // Create new headers with CORS added
7571
- const newHeaders = new Headers(response.headers);
7572
- for (const [key, value] of Object.entries(CORS_HEADERS)) {
7573
- newHeaders.set(key, value);
7574
- }
7575
-
7576
- // Return new Response with same body stream (not cloned, just transferred)
7577
- return new Response(response.body, {
7578
- status: response.status,
7579
- statusText: response.statusText,
7580
- headers: newHeaders,
7581
- });
7582
- }
7583
-
7584
7608
  export async function router(request, env) {
7585
7609
  const url = new URL(request.url);
7586
7610
  const pathname = url.pathname;
7587
7611
 
7588
7612
  // Handle CORS preflight requests
7589
7613
  if (request.method === "OPTIONS") {
7590
- return new Response(null, {
7591
- status: 204,
7592
- headers: CORS_HEADERS,
7593
- });
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
+ );
7594
7628
  }
7595
7629
 
7596
7630
  const routePath = pathname || "/";
@@ -7632,19 +7666,22 @@ ${packedThreadRouteCode}
7632
7666
  // across requests.
7633
7667
  let threadAccess = null;
7634
7668
 
7635
- // Require authentication for all API routes except public ones
7669
+ // Require authentication for all API routes except public ones.
7670
+ // WebSocket tickets are single-use and are consumed here. Controllers
7671
+ // must reuse context.auth (resolveRequestAuth) rather than calling
7672
+ // requireAuth again, or a ticket-only upgrade will 401.
7636
7673
  if (isApiRoute && !publicRoute) {
7637
7674
  const authResult = await requireAuth(request, env);
7638
7675
 
7639
7676
  // If requireAuth returns a Response, it's an error (401)
7640
7677
  if (authResult instanceof Response) {
7641
- return addCorsHeaders(authResult);
7678
+ return applyRuntimeCors(authResult, request, env);
7642
7679
  }
7643
7680
 
7644
7681
  authContext = authResult;
7645
7682
 
7646
7683
  if (isAdminOnlyApiRoute(routePath, request.method) && authContext.user.role !== 'admin') {
7647
- return addCorsHeaders(Response.json({ error: 'Forbidden: Admin access required' }, { status: 403 }));
7684
+ return applyRuntimeCors(Response.json({ error: 'Forbidden: Admin access required' }, { status: 403 }), request, env);
7648
7685
  }
7649
7686
 
7650
7687
  if (routePath.startsWith('/api/threads/')) {
@@ -7658,10 +7695,10 @@ ${packedThreadRouteCode}
7658
7695
  const agentBuilder = env.AGENT_BUILDER.get(agentBuilderId);
7659
7696
  const thread = await agentBuilder.getThread(threadId);
7660
7697
  if (!thread) {
7661
- return addCorsHeaders(Response.json({ error: \`Thread not found: \${threadId}\` }, { status: 404 }));
7698
+ return applyRuntimeCors(Response.json({ error: \`Thread not found: \${threadId}\` }, { status: 404 }), request, env);
7662
7699
  }
7663
7700
  if (!canAccessThread(authContext, thread)) {
7664
- return addCorsHeaders(Response.json({ error: "Forbidden: You don't have access to this thread" }, { status: 403 }));
7701
+ return applyRuntimeCors(Response.json({ error: "Forbidden: You don't have access to this thread" }, { status: 403 }), request, env);
7665
7702
  }
7666
7703
  threadAccess = { threadId, thread };
7667
7704
  }
@@ -7704,16 +7741,16 @@ ${packedThreadRouteCode}
7704
7741
  const result = await controller(context);
7705
7742
 
7706
7743
  if (result instanceof Response) {
7707
- return addCorsHeaders(result);
7744
+ return applyRuntimeCors(result, request, env);
7708
7745
  }
7709
7746
  if (typeof result === "string") {
7710
7747
  return new Response(result, {
7711
- headers: corsHeaders("text/plain"),
7748
+ headers: corsHeaders("text/plain", request, env),
7712
7749
  });
7713
7750
  }
7714
7751
  // JSON responses get CORS headers
7715
7752
  return new Response(JSON.stringify(result), {
7716
- headers: corsHeaders("application/json"),
7753
+ headers: corsHeaders("application/json", request, env),
7717
7754
  });
7718
7755
  }
7719
7756