@agent-native/core 0.15.6 → 0.15.9

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 (31) hide show
  1. package/dist/agent/engine/builder-engine.d.ts.map +1 -1
  2. package/dist/agent/engine/builder-engine.js +19 -1
  3. package/dist/agent/engine/builder-engine.js.map +1 -1
  4. package/dist/client/AssistantChat.d.ts.map +1 -1
  5. package/dist/client/AssistantChat.js +9 -1
  6. package/dist/client/AssistantChat.js.map +1 -1
  7. package/dist/client/settings/SettingsPanel.js.map +1 -1
  8. package/dist/client/settings/useBuilderStatus.d.ts +1 -1
  9. package/dist/client/settings/useBuilderStatus.d.ts.map +1 -1
  10. package/dist/client/settings/useBuilderStatus.js +82 -11
  11. package/dist/client/settings/useBuilderStatus.js.map +1 -1
  12. package/dist/client/settings/useBuilderStatus.spec.js +43 -1
  13. package/dist/client/settings/useBuilderStatus.spec.js.map +1 -1
  14. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  15. package/dist/server/agent-chat-plugin.js +5 -2
  16. package/dist/server/agent-chat-plugin.js.map +1 -1
  17. package/dist/server/builder-browser.d.ts +39 -11
  18. package/dist/server/builder-browser.d.ts.map +1 -1
  19. package/dist/server/builder-browser.js +182 -17
  20. package/dist/server/builder-browser.js.map +1 -1
  21. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  22. package/dist/server/core-routes-plugin.js +72 -13
  23. package/dist/server/core-routes-plugin.js.map +1 -1
  24. package/dist/server/credential-provider.d.ts +25 -4
  25. package/dist/server/credential-provider.d.ts.map +1 -1
  26. package/dist/server/credential-provider.js +81 -5
  27. package/dist/server/credential-provider.js.map +1 -1
  28. package/dist/server/google-realtime-session.d.ts.map +1 -1
  29. package/dist/server/google-realtime-session.js +1 -1
  30. package/dist/server/google-realtime-session.js.map +1 -1
  31. package/package.json +1 -1
@@ -22,7 +22,11 @@ export interface BuilderBrowserStatus {
22
22
  * account, which takes precedence for their request.
23
23
  */
24
24
  envManaged: boolean;
25
- credentialSource?: "user" | "org" | "env";
25
+ credentialSource?: "user" | "org" | "workspace" | "env";
26
+ connectError?: {
27
+ message: string;
28
+ at: number;
29
+ };
26
30
  appHost: string;
27
31
  apiHost: string;
28
32
  /**
@@ -75,6 +79,18 @@ export declare function getBuilderBranchProjectId(): string;
75
79
  export declare function isBuilderBranchingEnabled(): boolean;
76
80
  export declare function resolveBuilderBranchProjectId(): Promise<string>;
77
81
  export declare function resolveIsBuilderBranchingEnabled(): Promise<boolean>;
82
+ /**
83
+ * Query param on the callback URL that carries the original preview opener
84
+ * origin when cli-auth's allow-list forces `preview_url` to the gateway.
85
+ * Read on the callback to derive the correct postMessage targetOrigin.
86
+ *
87
+ * Not signed: the receive-side trust check in `useBuilderStatus` still
88
+ * gates messages by allow-listed origin. The worst an attacker could do by
89
+ * crafting a different `_an_opener` value is target a postMessage to an
90
+ * origin that doesn't match the actual opener — postMessage drops the
91
+ * message in that case, identical to the legacy wildcard-fallback path.
92
+ */
93
+ export declare const BUILDER_OPENER_PARAM = "_an_opener";
78
94
  /**
79
95
  * Build the Builder cli-auth URL for the connect popup. When a signed
80
96
  * `state` token is supplied it is embedded inside the `redirect_url`
@@ -83,12 +99,13 @@ export declare function resolveIsBuilderBranchingEnabled(): Promise<boolean>;
83
99
  * api-key / etc., so we don't depend on Builder echoing a top-level
84
100
  * `state` parameter (it doesn't).
85
101
  *
86
- * The user-facing connect entry point is `/_agent-native/builder/connect`
87
- * (a server-side 302). Status / chat-card responses surface that path
88
- * rather than the cli-auth URL directly, so the 302 handler can mint a
89
- * fresh state bound to the current session on every click.
102
+ * Status responses can surface this URL directly; the legacy
103
+ * `/_agent-native/builder/connect` trampoline still calls this helper for
104
+ * clients that only know the app-local connect URL.
90
105
  */
91
- export declare function buildBuilderCliAuthUrl(origin: string, state?: string | null): string;
106
+ export declare function buildBuilderCliAuthUrl(callbackOrigin: string, state?: string | null, options?: {
107
+ previewOrigin?: string;
108
+ }): string;
92
109
  /**
93
110
  * The bare URL surfaced to clients as `connectUrl`. The status route appends
94
111
  * a short-lived signed connect token when it knows the current owner; this
@@ -97,12 +114,20 @@ export declare function buildBuilderCliAuthUrl(origin: string, state?: string |
97
114
  */
98
115
  export declare function getBuilderBrowserConnectUrl(origin: string): string;
99
116
  /**
100
- * Builder CLI-auth does not need the workspace OAuth relay that Google uses.
101
- * In Builder/Fusion previews, keep connect + callback URLs on the actual app
102
- * preview origin so the signed connect token and pending row are verified by
103
- * the same deployment that minted them.
117
+ * User-visible Builder connect origin. In Builder/Fusion previews, keep the
118
+ * connect URL on the actual app preview origin so clicking Connect happens in
119
+ * the same deployment that minted the signed connect token.
104
120
  */
105
121
  export declare function getBuilderBrowserOriginForEvent(event: H3Event): string;
122
+ /**
123
+ * Builder's /cli-auth page currently only accepts localhost, *.builder.io,
124
+ * *.agent-native.com, or builder: redirect_url destinations. Preview hosts
125
+ * such as *.builderio.xyz and *.builder.codes are valid app origins for us,
126
+ * but Builder rejects them and falls back to http://localhost:10110/auth.
127
+ * Use a configured public gateway for the callback in those cases while
128
+ * leaving the surfaced connect URL on the user's active preview.
129
+ */
130
+ export declare function getBuilderCliAuthCallbackOriginForEvent(event: H3Event): string;
106
131
  export declare function getBuilderBrowserStatus(origin: string): BuilderBrowserStatus;
107
132
  export declare function getBuilderBrowserStatusForEvent(event: H3Event): BuilderBrowserStatus;
108
133
  /**
@@ -125,7 +150,9 @@ export declare function getBuilderCallbackEnvVars(params: {
125
150
  value: string;
126
151
  }[];
127
152
  export declare function resolveSafePreviewUrl(previewUrl: string | null | undefined, event: H3Event): string;
128
- export declare function createBuilderBrowserCallbackPage(previewUrl: string): string;
153
+ export declare function createBuilderBrowserCallbackPage(previewUrl: string, opts?: {
154
+ parentOrigin?: string;
155
+ }): string;
129
156
  /**
130
157
  * HTML page rendered inside the OAuth popup when the callback handler caught
131
158
  * an error persisting the per-user Builder credentials. Without this, the
@@ -144,6 +171,7 @@ export declare function createBuilderBrowserCallbackErrorPage(message: string, o
144
171
  title?: string;
145
172
  body?: string;
146
173
  closeHint?: string;
174
+ parentOrigin?: string;
147
175
  }): string;
148
176
  export interface RunBuilderAgentArgs {
149
177
  prompt: string;
@@ -1 +1 @@
1
- {"version":3,"file":"builder-browser.d.ts","sourceRoot":"","sources":["../../src/server/builder-browser.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"builder-browser.d.ts","sourceRoot":"","sources":["../../src/server/builder-browser.ts"],"names":[],"mappings":"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"}
@@ -165,7 +165,16 @@ function isAllowedBrowserReturnUrl(urlString) {
165
165
  const isLocalhost = hostname === "localhost" ||
166
166
  hostname === "127.0.0.1" ||
167
167
  hostname === "[::1]";
168
- const isBuilderDomain = hostname === "builder.io" || hostname.endsWith(".builder.io");
168
+ const isBuilderDomain = hostname === "builder.io" ||
169
+ hostname.endsWith(".builder.io") ||
170
+ hostname === "builder.my" ||
171
+ hostname.endsWith(".builder.my") ||
172
+ hostname === "builderio.xyz" ||
173
+ hostname.endsWith(".builderio.xyz") ||
174
+ hostname === "builderio.dev" ||
175
+ hostname.endsWith(".builderio.dev") ||
176
+ hostname === "builder.codes" ||
177
+ hostname.endsWith(".builder.codes");
169
178
  const isAgentNativeDomain = hostname === "agent-native.com" || hostname.endsWith(".agent-native.com");
170
179
  return (isAllowedProtocol &&
171
180
  (isLocalhost || isBuilderDomain || isAgentNativeDomain));
@@ -224,6 +233,72 @@ export async function resolveBuilderBranchProjectId() {
224
233
  export async function resolveIsBuilderBranchingEnabled() {
225
234
  return !!(await resolveBuilderBranchProjectId());
226
235
  }
236
+ function isBuilderCliAuthAllowedOrigin(origin) {
237
+ if (!origin)
238
+ return false;
239
+ try {
240
+ const parsed = new URL(origin);
241
+ const hostname = parsed.hostname.toLowerCase();
242
+ const isAllowedProtocol = parsed.protocol === "http:" || parsed.protocol === "https:";
243
+ const isLocalhost = hostname === "localhost" ||
244
+ hostname === "127.0.0.1" ||
245
+ hostname === "::1" ||
246
+ hostname === "[::1]";
247
+ const isBuilderDomain = hostname === "builder.io" || hostname.endsWith(".builder.io");
248
+ const isAgentNativeDomain = hostname === "agent-native.com" || hostname.endsWith(".agent-native.com");
249
+ return (isAllowedProtocol &&
250
+ (isLocalhost || isBuilderDomain || isAgentNativeDomain));
251
+ }
252
+ catch {
253
+ return false;
254
+ }
255
+ }
256
+ function firstBuilderCliAuthCallbackOriginFromEnv() {
257
+ for (const key of [
258
+ "APP_URL",
259
+ "VITE_APP_URL",
260
+ "BETTER_AUTH_URL",
261
+ "VITE_BETTER_AUTH_URL",
262
+ "WORKSPACE_GATEWAY_URL",
263
+ "VITE_WORKSPACE_GATEWAY_URL",
264
+ ]) {
265
+ const raw = process.env[key];
266
+ if (!raw)
267
+ continue;
268
+ try {
269
+ const origin = new URL(raw).origin;
270
+ if (isBuilderCliAuthAllowedOrigin(origin))
271
+ return origin;
272
+ }
273
+ catch {
274
+ // Ignore malformed environment values.
275
+ }
276
+ }
277
+ return null;
278
+ }
279
+ /**
280
+ * Query param on the callback URL that carries the original preview opener
281
+ * origin when cli-auth's allow-list forces `preview_url` to the gateway.
282
+ * Read on the callback to derive the correct postMessage targetOrigin.
283
+ *
284
+ * Not signed: the receive-side trust check in `useBuilderStatus` still
285
+ * gates messages by allow-listed origin. The worst an attacker could do by
286
+ * crafting a different `_an_opener` value is target a postMessage to an
287
+ * origin that doesn't match the actual opener — postMessage drops the
288
+ * message in that case, identical to the legacy wildcard-fallback path.
289
+ */
290
+ export const BUILDER_OPENER_PARAM = "_an_opener";
291
+ function isBuilderOpenerOriginSafe(value) {
292
+ if (!value)
293
+ return false;
294
+ try {
295
+ const parsed = new URL(value);
296
+ return parsed.protocol === "http:" || parsed.protocol === "https:";
297
+ }
298
+ catch {
299
+ return false;
300
+ }
301
+ }
227
302
  /**
228
303
  * Build the Builder cli-auth URL for the connect popup. When a signed
229
304
  * `state` token is supplied it is embedded inside the `redirect_url`
@@ -232,24 +307,38 @@ export async function resolveIsBuilderBranchingEnabled() {
232
307
  * api-key / etc., so we don't depend on Builder echoing a top-level
233
308
  * `state` parameter (it doesn't).
234
309
  *
235
- * The user-facing connect entry point is `/_agent-native/builder/connect`
236
- * (a server-side 302). Status / chat-card responses surface that path
237
- * rather than the cli-auth URL directly, so the 302 handler can mint a
238
- * fresh state bound to the current session on every click.
310
+ * Status responses can surface this URL directly; the legacy
311
+ * `/_agent-native/builder/connect` trampoline still calls this helper for
312
+ * clients that only know the app-local connect URL.
239
313
  */
240
- export function buildBuilderCliAuthUrl(origin, state = null) {
241
- const normalizedOrigin = normalizeOrigin(origin);
314
+ export function buildBuilderCliAuthUrl(callbackOrigin, state = null, options = {}) {
315
+ const normalizedCallbackOrigin = normalizeOrigin(callbackOrigin);
316
+ const requestedPreviewOrigin = normalizeOrigin(options.previewOrigin || callbackOrigin);
317
+ const normalizedPreviewOrigin = isBuilderCliAuthAllowedOrigin(requestedPreviewOrigin)
318
+ ? requestedPreviewOrigin
319
+ : normalizedCallbackOrigin;
242
320
  const appBasePath = getAppBasePath();
243
- const callbackUrl = new URL(`${appBasePath}${BUILDER_CALLBACK_PATH}`, normalizedOrigin);
321
+ const callbackUrl = new URL(`${appBasePath}${BUILDER_CALLBACK_PATH}`, normalizedCallbackOrigin);
244
322
  if (state) {
245
323
  callbackUrl.searchParams.set(BUILDER_STATE_PARAM, state);
246
324
  }
325
+ // When the cli-auth allow-list forces preview_url onto the gateway origin,
326
+ // the callback would otherwise lose the real opener origin and post its
327
+ // success message to the gateway instead of the preview tab. Embed the
328
+ // original preview origin in the callback's own query string so the
329
+ // callback handler can recover it for parentOrigin / postMessage. Builder
330
+ // preserves the redirect_url's query verbatim, so this round-trips.
331
+ if (requestedPreviewOrigin &&
332
+ requestedPreviewOrigin !== normalizedPreviewOrigin &&
333
+ isBuilderOpenerOriginSafe(requestedPreviewOrigin)) {
334
+ callbackUrl.searchParams.set(BUILDER_OPENER_PARAM, requestedPreviewOrigin);
335
+ }
247
336
  const url = new URL("/cli-auth", getBuilderAppHost());
248
337
  url.searchParams.set("response_type", "code");
249
338
  url.searchParams.set("host", BUILDER_BROWSER_HOST);
250
339
  url.searchParams.set("client_id", BUILDER_BROWSER_CLIENT_ID);
251
340
  url.searchParams.set("redirect_url", callbackUrl.toString());
252
- url.searchParams.set("preview_url", `${normalizedOrigin}${appBasePath}`);
341
+ url.searchParams.set("preview_url", `${normalizedPreviewOrigin}${appBasePath}`);
253
342
  url.searchParams.set("framework", "agent-native");
254
343
  return url.toString();
255
344
  }
@@ -301,17 +390,61 @@ function isTrustedBuilderRequestHost(host) {
301
390
  return false;
302
391
  }
303
392
  }
393
+ function isLoopbackBuilderRequestHost(host) {
394
+ if (!host)
395
+ return false;
396
+ try {
397
+ const hostname = new URL(`http://${host}`).hostname.toLowerCase();
398
+ return (hostname === "localhost" ||
399
+ hostname === "127.0.0.1" ||
400
+ hostname === "::1" ||
401
+ hostname === "[::1]");
402
+ }
403
+ catch {
404
+ return false;
405
+ }
406
+ }
407
+ function firstPublicBuilderPreviewOriginFromEnv() {
408
+ for (const key of [
409
+ "FUSION_ENV_ORIGIN",
410
+ "VITE_FUSION_ENV_ORIGIN",
411
+ "BUILDER_PREVIEW_URL",
412
+ "VITE_BUILDER_PREVIEW_URL",
413
+ ]) {
414
+ const raw = process.env[key];
415
+ if (!raw)
416
+ continue;
417
+ try {
418
+ const url = new URL(raw);
419
+ if (url.protocol !== "http:" && url.protocol !== "https:")
420
+ continue;
421
+ if (isLoopbackBuilderRequestHost(url.host))
422
+ continue;
423
+ if (!isTrustedBuilderRequestHost(url.host))
424
+ continue;
425
+ return url.origin;
426
+ }
427
+ catch {
428
+ // Ignore malformed environment values.
429
+ }
430
+ }
431
+ return null;
432
+ }
304
433
  /**
305
- * Builder CLI-auth does not need the workspace OAuth relay that Google uses.
306
- * In Builder/Fusion previews, keep connect + callback URLs on the actual app
307
- * preview origin so the signed connect token and pending row are verified by
308
- * the same deployment that minted them.
434
+ * User-visible Builder connect origin. In Builder/Fusion previews, keep the
435
+ * connect URL on the actual app preview origin so clicking Connect happens in
436
+ * the same deployment that minted the signed connect token.
309
437
  */
310
438
  export function getBuilderBrowserOriginForEvent(event) {
311
439
  const headerHost = firstHeaderValue(readEventHeader(event, "x-forwarded-host") ||
312
440
  readEventHeader(event, "host"));
313
441
  if (!isTrustedBuilderRequestHost(headerHost))
314
442
  return getOrigin(event);
443
+ if (isLoopbackBuilderRequestHost(headerHost)) {
444
+ const publicPreviewOrigin = firstPublicBuilderPreviewOriginFromEnv();
445
+ if (publicPreviewOrigin)
446
+ return publicPreviewOrigin;
447
+ }
315
448
  const rawProto = firstHeaderValue(readEventHeader(event, "x-forwarded-proto"));
316
449
  const proto = rawProto === "http" || rawProto === "https"
317
450
  ? rawProto
@@ -320,6 +453,20 @@ export function getBuilderBrowserOriginForEvent(event) {
320
453
  : "http";
321
454
  return `${proto}://${headerHost}`;
322
455
  }
456
+ /**
457
+ * Builder's /cli-auth page currently only accepts localhost, *.builder.io,
458
+ * *.agent-native.com, or builder: redirect_url destinations. Preview hosts
459
+ * such as *.builderio.xyz and *.builder.codes are valid app origins for us,
460
+ * but Builder rejects them and falls back to http://localhost:10110/auth.
461
+ * Use a configured public gateway for the callback in those cases while
462
+ * leaving the surfaced connect URL on the user's active preview.
463
+ */
464
+ export function getBuilderCliAuthCallbackOriginForEvent(event) {
465
+ const previewOrigin = getBuilderBrowserOriginForEvent(event);
466
+ if (isBuilderCliAuthAllowedOrigin(previewOrigin))
467
+ return previewOrigin;
468
+ return firstBuilderCliAuthCallbackOriginFromEnv() ?? previewOrigin;
469
+ }
323
470
  export function getBuilderBrowserStatus(origin) {
324
471
  const branchProjectId = getConfiguredBuilderBranchProjectId();
325
472
  const envManaged = !!process.env.BUILDER_PRIVATE_KEY;
@@ -371,7 +518,7 @@ export function resolveSafePreviewUrl(previewUrl, event) {
371
518
  if (previewUrl && isAllowedBrowserReturnUrl(previewUrl)) {
372
519
  return previewUrl;
373
520
  }
374
- return getOrigin(event);
521
+ return getBuilderBrowserOriginForEvent(event);
375
522
  }
376
523
  /**
377
524
  * Inline theme-detection script that runs before the body paints. Reads the
@@ -517,8 +664,24 @@ const BUILDER_CALLBACK_BASE_CSS = `
517
664
  word-break: break-word;
518
665
  }
519
666
  `;
520
- export function createBuilderBrowserCallbackPage(previewUrl) {
667
+ function safeOriginFromUrl(value) {
668
+ if (!value)
669
+ return null;
670
+ try {
671
+ return new URL(value).origin;
672
+ }
673
+ catch {
674
+ return null;
675
+ }
676
+ }
677
+ export function createBuilderBrowserCallbackPage(previewUrl, opts = {}) {
521
678
  const escapedUrl = JSON.stringify(previewUrl);
679
+ const parentOrigin = safeOriginFromUrl(opts.parentOrigin) ?? safeOriginFromUrl(previewUrl);
680
+ // postMessage requires a specific target origin for cross-origin opener
681
+ // delivery; only fall back to "*" when we have no usable origin (the
682
+ // BroadcastChannel path on the success page still works for same-origin
683
+ // openers in that case).
684
+ const escapedTargetOrigin = JSON.stringify(parentOrigin ?? "*");
522
685
  return `<!doctype html>
523
686
  <html lang="en">
524
687
  <head>
@@ -561,7 +724,7 @@ export function createBuilderBrowserCallbackPage(previewUrl) {
561
724
  if (window.opener && !window.opener.closed) {
562
725
  window.opener.postMessage(
563
726
  { type: "builder-connect-success" },
564
- window.location.origin,
727
+ ${escapedTargetOrigin},
565
728
  );
566
729
  }
567
730
  } catch (e) {}
@@ -597,6 +760,8 @@ export function createBuilderBrowserCallbackPage(previewUrl) {
597
760
  */
598
761
  export function createBuilderBrowserCallbackErrorPage(message, opts = {}) {
599
762
  const escapedMessage = JSON.stringify(message);
763
+ const parentOrigin = safeOriginFromUrl(opts.parentOrigin);
764
+ const escapedTargetOrigin = JSON.stringify(parentOrigin ?? "*");
600
765
  const title = opts.title ?? "Couldn't save Builder connection";
601
766
  const body = opts.body ??
602
767
  "Builder authorized your account but the server couldn't persist the credentials.";
@@ -645,7 +810,7 @@ export function createBuilderBrowserCallbackErrorPage(message, opts = {}) {
645
810
  try {
646
811
  window.opener.postMessage(
647
812
  { type: "builder-connect-error", message: msg },
648
- window.location.origin,
813
+ ${escapedTargetOrigin},
649
814
  );
650
815
  } catch (e) {}
651
816
  }