@agent-native/core 0.200.0 → 0.200.1-nightly-20261002213029

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 (107) hide show
  1. package/dist/agent/actions/manage-builder-connection.js +1 -1
  2. package/dist/agent/engine/ai-sdk-engine.js +8 -1
  3. package/dist/agent/engine/builder-engine.js +1 -1
  4. package/dist/agent/engine/credential-errors.d.ts +1 -1
  5. package/dist/agent/engine/credential-errors.js +2 -2
  6. package/dist/agent/engine/translate-ai-sdk.d.ts +1 -1
  7. package/dist/agent/engine/translate-ai-sdk.js +2 -1
  8. package/dist/agent/production-agent.js +1 -1
  9. package/dist/agent/run-manager.d.ts +7 -0
  10. package/dist/agent/run-manager.js +4 -0
  11. package/dist/agent/thread-data-builder.js +63 -14
  12. package/dist/brand-kit/fig/index.js +1 -1
  13. package/dist/cli/skills-content/turn-into-app-skill.d.ts +1 -1
  14. package/dist/cli/skills-content/turn-into-app-skill.js +2 -2
  15. package/dist/client/agent-engine-key.js +1 -1
  16. package/dist/client/chat/agentkit-agent-native.js +26 -14
  17. package/dist/client/error-format.js +5 -5
  18. package/dist/client/uploads/upload-editor-image.js +1 -1
  19. package/dist/client/use-chat-threads.js +48 -1
  20. package/dist/collab/awareness.d.ts +2 -2
  21. package/dist/deploy/build.js +7 -1
  22. package/dist/extensions/web-search-tool.js +2 -2
  23. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  24. package/dist/file-upload/actions/upload-image.js +1 -1
  25. package/dist/file-upload/builder.js +2 -2
  26. package/dist/file-upload/registry.js +1 -1
  27. package/dist/ingestion/pptx.d.ts +3 -1
  28. package/dist/ingestion/pptx.js +3 -2
  29. package/dist/jobs/actions/manage-recurring-job.d.ts +1 -1
  30. package/dist/localization/default-messages.js +11 -11
  31. package/dist/mcp/build-server.js +11 -5
  32. package/dist/mcp-client/manager.js +14 -2
  33. package/dist/notifications/routes.d.ts +3 -3
  34. package/dist/observability/metrics.js +10 -1
  35. package/dist/onboarding/app-profile.js +1 -1
  36. package/dist/onboarding/default-steps.js +4 -4
  37. package/dist/private-blob/attachment-errors.js +1 -1
  38. package/dist/progress/routes.d.ts +1 -1
  39. package/dist/resources/handlers.js +1 -1
  40. package/dist/secrets/routes.d.ts +6 -6
  41. package/dist/server/action-routes.js +14 -3
  42. package/dist/server/agent-chat/browser-team-tools.js +4 -4
  43. package/dist/server/agent-chat/context-tools.js +2 -2
  44. package/dist/server/agent-chat-ai-setup.js +1 -1
  45. package/dist/server/agent-chat-plugin.d.ts +2 -2
  46. package/dist/server/agent-chat-plugin.js +9 -5
  47. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  48. package/dist/server/agent-engine-default-model-route.d.ts +1 -1
  49. package/dist/server/builder-api-auth.js +5 -5
  50. package/dist/server/builder-browser.js +1 -1
  51. package/dist/server/builder-design-systems.js +1 -1
  52. package/dist/server/core-routes-plugin.d.ts +5 -11
  53. package/dist/server/core-routes-plugin.js +36 -68
  54. package/dist/server/credential-provider.js +3 -3
  55. package/dist/server/deep-link.d.ts +2 -0
  56. package/dist/server/deep-link.js +30 -3
  57. package/dist/server/fusion-app.js +1 -1
  58. package/dist/server/prompts/framework-core.js +1 -1
  59. package/dist/server/realtime-voice.js +1 -1
  60. package/dist/server/transcribe-voice.js +3 -3
  61. package/dist/shared/connect-required.js +1 -1
  62. package/dist/templates/chat/.agents/skills/turn-into-app/SKILL.md +2 -2
  63. package/dist/templates/default/.agents/skills/turn-into-app/SKILL.md +2 -2
  64. package/dist/templates/default/app/i18n/ar-SA.ts +3 -3
  65. package/dist/templates/default/app/i18n/de-DE.ts +3 -3
  66. package/dist/templates/default/app/i18n/en-US.ts +3 -3
  67. package/dist/templates/default/app/i18n/es-ES.ts +3 -3
  68. package/dist/templates/default/app/i18n/fr-FR.ts +3 -3
  69. package/dist/templates/default/app/i18n/hi-IN.ts +3 -3
  70. package/dist/templates/default/app/i18n/ja-JP.ts +3 -3
  71. package/dist/templates/default/app/i18n/ko-KR.ts +3 -3
  72. package/dist/templates/default/app/i18n/pt-BR.ts +3 -3
  73. package/dist/templates/default/app/i18n/zh-CN.ts +3 -3
  74. package/dist/templates/default/app/i18n/zh-TW.ts +3 -3
  75. package/dist/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +2 -2
  76. package/dist/templates/workspace-root/.env.example +1 -1
  77. package/dist/transcription/builder-transcription.js +1 -1
  78. package/dist/triggers/actions/manage-automation.d.ts +2 -2
  79. package/docs/content/getting-started.mdx +1 -1
  80. package/docs/content/multi-app-workspace.mdx +1 -1
  81. package/docs/content/onboarding.mdx +7 -8
  82. package/docs/content/real-time-collaboration.mdx +1 -1
  83. package/docs/content/template-chat-developers.mdx +1 -1
  84. package/docs/content/template-clips-developers.mdx +1 -1
  85. package/docs/content/template-content-developers.mdx +1 -1
  86. package/docs/content/template-slides-features.mdx +2 -2
  87. package/docs/content/toolkit-settings.mdx +10 -10
  88. package/docs/content/toolkit-setup-connections.mdx +1 -1
  89. package/docs/content/tracking.mdx +1 -1
  90. package/docs/content/updating-ui-in-production.mdx +3 -3
  91. package/docs/content/voice-input.mdx +1 -1
  92. package/package.json +4 -4
  93. package/src/templates/chat/.agents/skills/turn-into-app/SKILL.md +2 -2
  94. package/src/templates/default/.agents/skills/turn-into-app/SKILL.md +2 -2
  95. package/src/templates/default/app/i18n/ar-SA.ts +3 -3
  96. package/src/templates/default/app/i18n/de-DE.ts +3 -3
  97. package/src/templates/default/app/i18n/en-US.ts +3 -3
  98. package/src/templates/default/app/i18n/es-ES.ts +3 -3
  99. package/src/templates/default/app/i18n/fr-FR.ts +3 -3
  100. package/src/templates/default/app/i18n/hi-IN.ts +3 -3
  101. package/src/templates/default/app/i18n/ja-JP.ts +3 -3
  102. package/src/templates/default/app/i18n/ko-KR.ts +3 -3
  103. package/src/templates/default/app/i18n/pt-BR.ts +3 -3
  104. package/src/templates/default/app/i18n/zh-CN.ts +3 -3
  105. package/src/templates/default/app/i18n/zh-TW.ts +3 -3
  106. package/src/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +2 -2
  107. package/src/templates/workspace-root/.env.example +1 -1
@@ -123,7 +123,7 @@ export function createBuilderBrowserTool(deps) {
123
123
  const entries = {
124
124
  "connect-file-storage": {
125
125
  tool: {
126
- description: "Render the inline file-storage setup card when an image or file attachment could not be durably uploaded. The card lets the user connect Builder for managed object storage or open the same custom-key setup used by onboarding. Call it immediately when the attachment context says storage is missing; do not ask the user to upload the file again.",
126
+ description: "Render the inline file-storage setup card when an image or file attachment could not be durably uploaded. The card lets the user use Builder.io for managed object storage or open the same custom-key setup used by onboarding. Call it immediately when the attachment context says storage is missing; do not ask the user to upload the file again.",
127
127
  parameters: {
128
128
  type: "object",
129
129
  properties: {},
@@ -148,7 +148,7 @@ export function createBuilderBrowserTool(deps) {
148
148
  properties: {
149
149
  prompt: {
150
150
  type: "string",
151
- description: "The user's feature / change request, verbatim. Forwarded to Builder's cloud agent when the user clicks Send. Omit only for generic 'connect Builder' requests that aren't tied to a specific code change.",
151
+ description: "The user's feature / change request, verbatim. Forwarded to Builder's cloud agent when the user clicks Send. Omit only for generic 'use Builder.io' requests that aren't tied to a specific code change.",
152
152
  },
153
153
  extensionId: {
154
154
  type: "string",
@@ -293,7 +293,7 @@ export function createBuilderBrowserTool(deps) {
293
293
  },
294
294
  "activate-browser": {
295
295
  tool: {
296
- description: "Activate browser automation tools. Call this when you need to interact with a real browser — e.g. to extract design tokens from a rendered page, take screenshots, read computed styles from JS-heavy sites, or test a live URL. After activation, chrome-devtools MCP tools (navigate, click, evaluate_script, take_screenshot, etc.) become available on your next action. Requires a Builder.io connection (free tier available).",
296
+ description: "Activate browser automation tools. Call this when you need to interact with a real browser — e.g. to extract design tokens from a rendered page, take screenshots, read computed styles from JS-heavy sites, or test a live URL. After activation, chrome-devtools MCP tools (navigate, click, evaluate_script, take_screenshot, etc.) become available on your next action. Requires Builder.io to be set up (free tier available).",
297
297
  parameters: {
298
298
  type: "object",
299
299
  properties: {
@@ -310,7 +310,7 @@ export function createBuilderBrowserTool(deps) {
310
310
  if (!creds.privateKey || !creds.publicKey) {
311
311
  return JSON.stringify({
312
312
  error: "builder-not-connected",
313
- message: "Builder.io is not connected. Call `connect-builder` first to enable browser automation.",
313
+ message: "Builder.io is not connected. Call `connect-builder` first so the user can use browser automation.",
314
314
  });
315
315
  }
316
316
  const { requestBuilderBrowserConnection } = await import("../builder-browser.js");
@@ -101,9 +101,9 @@ When you finish a task that has obvious recurring value — daily inbox triage,
101
101
  If the user says yes, call \`manage-jobs\` (action: "create") with the original prompt as the job's instructions and the cadence they confirmed.
102
102
 
103
103
  Do NOT add this offer for one-shot work: lookups (find Alice, what's the schema, who reported X), single drafts/replies, navigation requests, or any task whose value is in the moment. Skip it when the prompt is already explicitly recurring (the user said "every morning…" — you'd be asking what they already told you). One short sentence at most; do not turn it into a list of cadence options.`,
104
- builder: `### Connecting Builder.io
104
+ builder: `### Using Builder.io
105
105
 
106
- When the user asks to connect Builder.io or you hit a "Builder not configured" error, call the \`connect-builder\` tool. It renders a Connect/code-change card inline — do NOT write out multi-step setup instructions yourself. Inspect the returned \`builderEnabled\` flag: \`true\` means Builder Cloud Agents can take the code-change handoff, while \`false\` means this requires a code change and the user should edit locally or use Builder.io to edit this code in the cloud and continue customizing the app any way they like. If Builder Cloud Agents are not available for this workspace, never send the user to Builder org settings or beta settings.`,
106
+ When the user asks to use Builder.io or you hit a "Builder not configured" error, call the \`connect-builder\` tool. It renders a Builder.io setup/code-change card inline — do NOT write out multi-step setup instructions yourself. Inspect the returned \`builderEnabled\` flag: \`true\` means Builder Cloud Agents can take the code-change handoff, while \`false\` means this requires a code change and the user should edit locally or use Builder.io to edit this code in the cloud and continue customizing the app any way they like. If Builder Cloud Agents are not available for this workspace, never send the user to Builder org settings or beta settings.`,
107
107
  browser: `### Browser Automation
108
108
 
109
109
  You can activate a real Chrome browser via Builder.io for tasks that need full page rendering:
@@ -76,7 +76,7 @@ export async function requireAgentChatAiSetup() {
76
76
  return;
77
77
  throw createError({
78
78
  statusCode: 403,
79
- statusMessage: "Connect Builder AI or a provider API key before chatting.",
79
+ statusMessage: "Use Builder.io or a provider API key before chatting.",
80
80
  data: { code: AGENT_CHAT_AI_SETUP_REQUIRED_CODE },
81
81
  });
82
82
  }
@@ -115,11 +115,11 @@ export declare function resolveFetchToolKeyAllowlist(keyName: string, resolvedKe
115
115
  export declare function resolveHostedBuilderHandoff(browserTools: Record<string, ActionEntry>, canToggle: boolean): Record<string, ActionEntry>;
116
116
  /** Setup CTAs that must be callable on the very first request.
117
117
  *
118
- * Both are recovery actions: the agent should answer "connect Builder for me"
118
+ * Both are recovery actions: the agent should answer "use Builder.io for me"
119
119
  * or a failed upload by rendering the inline card, not by spending a turn in
120
120
  * `tool-search` first. `connect-builder` is registered in every registry that
121
121
  * receives `browserTools`, local dev included, so naming it only through the
122
- * hosted-only handoff left local dev advertising "Connect Builder.io" in the
122
+ * hosted-only handoff left local dev advertising "Use Builder.io" in the
123
123
  * UI while the agent was never told the tool existed. Names the registry does
124
124
  * not have are dropped by `filterInitialEngineTools`, so listing both here is
125
125
  * safe for lean registries. */
@@ -578,11 +578,11 @@ export function resolveHostedBuilderHandoff(browserTools, canToggle) {
578
578
  }
579
579
  /** Setup CTAs that must be callable on the very first request.
580
580
  *
581
- * Both are recovery actions: the agent should answer "connect Builder for me"
581
+ * Both are recovery actions: the agent should answer "use Builder.io for me"
582
582
  * or a failed upload by rendering the inline card, not by spending a turn in
583
583
  * `tool-search` first. `connect-builder` is registered in every registry that
584
584
  * receives `browserTools`, local dev included, so naming it only through the
585
- * hosted-only handoff left local dev advertising "Connect Builder.io" in the
585
+ * hosted-only handoff left local dev advertising "Use Builder.io" in the
586
586
  * UI while the agent was never told the tool existed. Names the registry does
587
587
  * not have are dropped by `filterInitialEngineTools`, so listing both here is
588
588
  * safe for lean registries. */
@@ -5040,7 +5040,7 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
5040
5040
  : null;
5041
5041
  const { isBuilderGatewayDeployConfigured } = await import("./credential-provider.js");
5042
5042
  return {
5043
- active: true,
5043
+ active: run.inFlight,
5044
5044
  runId: run.runId,
5045
5045
  threadId: run.threadId,
5046
5046
  turnId: run.turnId,
@@ -5383,7 +5383,11 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
5383
5383
  const incomingScope = parseScopeFromBody(body.scope);
5384
5384
  await setThreadScope(threadId, owner, incomingScope);
5385
5385
  }
5386
- return { ok: true };
5386
+ // The scope the thread really has now (a detach can land
5387
+ // between the read above and this save), so the client records
5388
+ // what the server holds instead of guessing from the page.
5389
+ const saved = await resolveThreadAccess(owner, threadId, "editor", { orgId });
5390
+ return { ok: true, scope: saved?.scope ?? null };
5387
5391
  });
5388
5392
  }
5389
5393
  // POST /threads/:id/queued — apply a single queue mutation against
@@ -5765,7 +5769,7 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
5765
5769
  code: AGENT_CHAT_AI_SETUP_REQUIRED_CODE,
5766
5770
  message: error.statusMessage ??
5767
5771
  error.message ??
5768
- "Connect Builder AI or a provider API key before chatting.",
5772
+ "Use Builder.io or a provider API key before chatting.",
5769
5773
  },
5770
5774
  });
5771
5775
  };
@@ -65,6 +65,7 @@ export declare function createAgentEngineApiKeyHandler(): import("h3").EventHand
65
65
  error: any;
66
66
  code: any;
67
67
  } | {
68
+ error?: undefined;
68
69
  errorCode?: undefined;
69
70
  code?: undefined;
70
71
  ok: boolean;
@@ -72,6 +73,5 @@ export declare function createAgentEngineApiKeyHandler(): import("h3").EventHand
72
73
  baseUrlKey?: string;
73
74
  scope: AgentEngineApiKeyScope;
74
75
  defaultModel?: import("./agent-engine-default-model-route.js").SavedKeyDefaultModelOutcome;
75
- error?: undefined;
76
76
  }>>;
77
77
  export {};
@@ -8,8 +8,8 @@ export declare const AGENT_ENGINE_API_KEY_ACTION_NAME = "agent-engine-api-key";
8
8
  * resolveEngine's credential detection.
9
9
  */
10
10
  export declare function createAgentEngineDisconnectHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
11
- ok?: undefined;
12
11
  error: string;
12
+ ok?: undefined;
13
13
  scope?: undefined;
14
14
  } | {
15
15
  ok: boolean;
@@ -50,7 +50,7 @@ async function resolveBuilderPublishAuthorization(ownerEmail, orgId) {
50
50
  if (!server)
51
51
  continue;
52
52
  if (!server.oauthSecretKey) {
53
- throw new ActionContractError("Builder Publish is configured without OAuth custody. Reconnect Builder.io Publish in Settings to continue.", {
53
+ throw new ActionContractError("Builder.io Publish is configured without OAuth custody. Sign in to Builder.io Publish again in Settings to continue.", {
54
54
  errorCode: "builder_oauth_reauthorization_required",
55
55
  statusCode: 400,
56
56
  });
@@ -77,7 +77,7 @@ async function resolveBuilderPublishAuthorization(ownerEmail, orgId) {
77
77
  !resourceBound ||
78
78
  !scopes.has("mcp:publish:read") ||
79
79
  [...scopes].some((scope) => scope !== "mcp:publish:read" && scope !== "offline_access")) {
80
- throw new ActionContractError("Builder Publish access needs re-authorizing to grant mcp:publish:read. Open Settings and reconnect Builder.io Publish.", {
80
+ throw new ActionContractError("Builder.io Publish access needs re-authorizing to grant mcp:publish:read. Open Settings and authorize Builder.io Publish again.", {
81
81
  errorCode: "builder_oauth_reauthorization_required",
82
82
  statusCode: 400,
83
83
  });
@@ -86,7 +86,7 @@ async function resolveBuilderPublishAuthorization(ownerEmail, orgId) {
86
86
  const authorization = config.headers?.Authorization;
87
87
  const match = authorization?.match(/^Bearer\s+(.+)$/i);
88
88
  if (!match?.[1]) {
89
- throw new ActionContractError("Builder Publish access expired. Reconnect Builder.io Publish in Settings to continue.", {
89
+ throw new ActionContractError("Builder.io Publish access expired. Sign in to Builder.io Publish again in Settings to continue.", {
90
90
  errorCode: "builder_oauth_reauthorization_required",
91
91
  statusCode: 400,
92
92
  });
@@ -101,7 +101,7 @@ async function resolveBuilderPublishAuthorization(ownerEmail, orgId) {
101
101
  if (ownerEmail) {
102
102
  const personalServer = (await listRemoteServers("user", ownerEmail)).find((entry) => isBuilderPublishResource(entry.url));
103
103
  if (personalServer) {
104
- throw new ActionContractError("Builder Publish is connected only for this user. Remove it and reconnect Builder.io Publish for the workspace.", {
104
+ throw new ActionContractError("Builder.io Publish is connected only for this user. Remove it and sign in to Builder.io Publish for the workspace.", {
105
105
  errorCode: "builder_oauth_reauthorization_required",
106
106
  statusCode: 400,
107
107
  });
@@ -117,7 +117,7 @@ export async function resolveBuilderRequestAuthorization(input = {}) {
117
117
  if (publishAuthorization)
118
118
  return publishAuthorization;
119
119
  if (ownerEmail && (await readOAuthCustody(ownerEmail, orgId))) {
120
- throw new ActionContractError("Builder Publish access is not connected for this workspace. Connect Builder.io Publish in Settings to grant mcp:publish:read.", {
120
+ throw new ActionContractError("Builder.io Publish access is not connected for this workspace. Sign in to Builder.io Publish in Settings to grant mcp:publish:read.", {
121
121
  errorCode: "builder_oauth_reauthorization_required",
122
122
  statusCode: 400,
123
123
  });
@@ -1561,7 +1561,7 @@ async function resolveBuilderApiAuthorization(requiredScope) {
1561
1561
  requiredScope,
1562
1562
  });
1563
1563
  if (!authorization) {
1564
- throw new ActionContractError("Builder.io is not connected. Connect Builder.io in Settings.", { errorCode: "builder_not_connected", statusCode: 400 });
1564
+ throw new ActionContractError("Builder.io is not connected. Sign in to Builder.io in Settings to continue.", { errorCode: "builder_not_connected", statusCode: 400 });
1565
1565
  }
1566
1566
  if (authorization.source === "legacy" && !authorization.legacyPublicKey) {
1567
1567
  throw new ActionContractError("Builder legacy credentials require BUILDER_PUBLIC_KEY for this request.", { errorCode: "builder_legacy_public_key_required", statusCode: 400 });
@@ -404,7 +404,7 @@ async function resolveBuilderDesignSystemAuthorization(requiredScope) {
404
404
  (authorization.source === "legacy" && !authorization.legacyPublicKey)) {
405
405
  throw new FeatureNotConfiguredError({
406
406
  requiredCredential: "BUILDER_PRIVATE_KEY",
407
- message: "Connect Builder.io (free tier available) before indexing a design system from Figma or code.",
407
+ message: "Use Builder.io (free tier available) to index a design system from Figma or code.",
408
408
  builderConnectUrl: "/_agent-native/builder/connect",
409
409
  });
410
410
  }
@@ -88,11 +88,11 @@ export declare function resolveBuilderOrgMutation(event: H3Event, options?: {
88
88
  deny: string | null;
89
89
  whoCanFix?: CredentialFixer;
90
90
  }>;
91
- export declare const BUILDER_CONNECT_NEEDS_ORGANIZATION = "Builder.io connects through an organization. Switch to one you belong to, or ask an organization owner or admin to invite you, then connect Builder again.";
92
- export declare const BUILDER_CONNECT_SESSION_NOT_SHARED = "This window can't see your sign-in, which happens in previews and embedded browsers. Open the app in its own browser tab, sign in, then connect Builder there.";
93
- export declare const BUILDER_ORG_MEMBERSHIP_UNREADABLE = "Couldn't check your organization membership. Try connecting Builder again in a moment.";
94
- export declare const BUILDER_ORG_ALREADY_CONNECTED = "Your organization already has a Builder.io connection, and a new account would take its place. An organization owner or admin can reconnect it in Settings.";
95
- export declare const BUILDER_ORG_RECONNECT_BY_LOGIN = "Your organization already has a Builder.io account. Log in to Builder to reconnect it.";
91
+ export declare const BUILDER_CONNECT_NEEDS_ORGANIZATION = "Builder.io access is managed through an organization. Switch to one you belong to, or ask an organization owner or admin to invite you, then set up Builder.io again.";
92
+ export declare const BUILDER_CONNECT_SESSION_NOT_SHARED = "This window can't see your sign-in, which happens in previews and embedded browsers. Open the app in its own browser tab, sign in, then set up Builder.io there.";
93
+ export declare const BUILDER_ORG_MEMBERSHIP_UNREADABLE = "Couldn't check your organization membership. Try starting Builder.io setup again in a moment.";
94
+ export declare const BUILDER_ORG_ALREADY_CONNECTED = "Your organization already has a Builder.io connection, and a new account would take its place. An organization owner or admin can sign in to Builder.io again in Settings.";
95
+ export declare const BUILDER_ORG_RECONNECT_BY_LOGIN = "Your organization already has a Builder.io account. Sign in to Builder.io to use it.";
96
96
  /** Query/body field naming which Builder.io connection a request targets. */
97
97
  export declare const BUILDER_CONNECTION_SCOPE_PARAM = "scope";
98
98
  /**
@@ -665,12 +665,6 @@ interface BuilderAccountActivationInput {
665
665
  * mode both run exactly this, after `authorizeBuilderConnectScope`.
666
666
  */
667
667
  export declare function activateBuilderAccount(event: H3Event, input: BuilderAccountActivationInput): Promise<BuilderAccountActivationResult>;
668
- /**
669
- * The popup-era account activation: answers with a page that hands the result
670
- * to its opener and closes. The error row is the opener's fallback channel,
671
- * read by its status poll when the page's message never arrives.
672
- */
673
- export declare function sendBuilderActivationPopup(event: H3Event, input: BuilderAccountActivationInput): Promise<string>;
674
668
  /**
675
669
  * `POST /_agent-native/builder/provision` — one-click Builder.io account
676
670
  * activation as a single JSON request, no popup. Session cookies are
@@ -59,7 +59,7 @@ import { getSession } from "./auth.js";
59
59
  import { createAutomationFailureUnsubscribeHandler } from "./automation-failure-notifications.js";
60
60
  import { getBetterAuthInternalAdapter, getBetterAuthSync, } from "./better-auth-instance.js";
61
61
  import { resolveBuilderRequestAuthorization } from "./builder-api-auth.js";
62
- import { BUILDER_CONNECT_PARAM, BUILDER_CONNECT_MODE_PARAM, BUILDER_AGENT_NATIVE_PROVISION_MODE, BUILDER_PROVISIONING_TOKEN_PARAM, BUILDER_CONNECT_ATTEMPT_PARAM, BUILDER_CONNECT_STATE_COOKIE, BUILDER_ENV_KEYS, BUILDER_OPENER_PARAM, BUILDER_RELAY_FLOW_HEADER, BUILDER_RELAY_SIGNATURE_HEADER, BUILDER_RELAY_STATE_PARAM, BUILDER_RELAY_TIMESTAMP_HEADER, appendBuilderConnectToken, appendBuilderConnectStateCookie, builderConnectTrackingProperties, BUILDER_UPSTREAM_FAILURE_STATUS, createBuilderConnectState, createBuilderBrowserCallbackErrorPage, createBuilderBrowserCallbackPage, createBuilderRelayRequest, getBuilderConnectTrackingParams, getBuilderBrowserOriginForEvent, getBuilderBrowserStatusForEvent, isBuilderAccountAlreadyExistsError, isBuilderAccountProvisioningEnabled, isBuilderConnectCallbackUrlAllowed, isSignedBuilderConnectState, normalizeBuilderAgentContext, parseBuilderConnectStateCookie, provisionBuilderAccount, resolveBuilderBranchProjectId, resolveBuilderConnectCallbackUrl, resolveBuilderConnectCallbackState, resolveBuilderPreviewRelayParentOrigin, removeBuilderConnectStateCookie, runBuilderAgent, sendBuilderPopupErrorPage, verifyBuilderRelayRequest, verifyBuilderPreviewRelayStateForCallback, verifyBuilderConnectTokenAndGetOwner, signBuilderProvisioningToken, verifyBuilderProvisioningToken, withBuilderConnectTrackingParams, } from "./builder-browser.js";
62
+ import { BUILDER_CONNECT_PARAM, BUILDER_CONNECT_MODE_PARAM, BUILDER_AGENT_NATIVE_PROVISION_MODE, BUILDER_CONNECT_ATTEMPT_PARAM, BUILDER_CONNECT_STATE_COOKIE, BUILDER_ENV_KEYS, BUILDER_OPENER_PARAM, BUILDER_RELAY_FLOW_HEADER, BUILDER_RELAY_SIGNATURE_HEADER, BUILDER_RELAY_STATE_PARAM, BUILDER_RELAY_TIMESTAMP_HEADER, appendBuilderConnectToken, appendBuilderConnectStateCookie, builderConnectTrackingProperties, BUILDER_UPSTREAM_FAILURE_STATUS, createBuilderConnectState, createBuilderBrowserCallbackErrorPage, createBuilderBrowserCallbackPage, createBuilderRelayRequest, getBuilderConnectTrackingParams, getBuilderBrowserOriginForEvent, getBuilderBrowserStatusForEvent, isBuilderAccountAlreadyExistsError, isBuilderAccountProvisioningEnabled, isBuilderConnectCallbackUrlAllowed, isSignedBuilderConnectState, normalizeBuilderAgentContext, parseBuilderConnectStateCookie, provisionBuilderAccount, resolveBuilderBranchProjectId, resolveBuilderConnectCallbackUrl, resolveBuilderConnectCallbackState, resolveBuilderPreviewRelayParentOrigin, removeBuilderConnectStateCookie, runBuilderAgent, sendBuilderPopupErrorPage, verifyBuilderRelayRequest, verifyBuilderPreviewRelayStateForCallback, verifyBuilderConnectTokenAndGetOwner, signBuilderProvisioningToken, verifyBuilderProvisioningToken, withBuilderConnectTrackingParams, } from "./builder-browser.js";
63
63
  import { BUILDER_ASSETS_WRITE_SCOPE, BUILDER_OAUTH_SCOPE, builderOAuthScopeFor, canRoleConnectPersonalBuilder, deleteBuilderOAuthSession, exchangeBuilderOAuthAuthorization, getBuilderOAuthGrants, getBuilderOAuthStoredScope, hasStoredBuilderOAuthGrant, isBuilderOrgManagerRole, isPersonalBuilderGrantAllowed, saveBuilderOAuthCredentials, startBuilderOAuthAuthorization, } from "./builder-oauth.js";
64
64
  import { captureError, registerErrorCaptureProvider } from "./capture-error.js";
65
65
  import { createChatGPTSubscriptionOAuthCallbackHandler, createChatGPTSubscriptionOAuthStartHandler, } from "./chatgpt-subscription-oauth.js";
@@ -274,11 +274,11 @@ export async function resolveBuilderOrgMutation(event, options = {}) {
274
274
  return { orgId, role, deny: null };
275
275
  }
276
276
  const BUILDER_ORG_CONNECTION_DENIED = "Only an organization owner or admin can change the shared Builder connection.";
277
- export const BUILDER_CONNECT_NEEDS_ORGANIZATION = "Builder.io connects through an organization. Switch to one you belong to, or ask an organization owner or admin to invite you, then connect Builder again.";
278
- export const BUILDER_CONNECT_SESSION_NOT_SHARED = "This window can't see your sign-in, which happens in previews and embedded browsers. Open the app in its own browser tab, sign in, then connect Builder there.";
279
- export const BUILDER_ORG_MEMBERSHIP_UNREADABLE = "Couldn't check your organization membership. Try connecting Builder again in a moment.";
280
- export const BUILDER_ORG_ALREADY_CONNECTED = "Your organization already has a Builder.io connection, and a new account would take its place. An organization owner or admin can reconnect it in Settings.";
281
- export const BUILDER_ORG_RECONNECT_BY_LOGIN = "Your organization already has a Builder.io account. Log in to Builder to reconnect it.";
277
+ export const BUILDER_CONNECT_NEEDS_ORGANIZATION = "Builder.io access is managed through an organization. Switch to one you belong to, or ask an organization owner or admin to invite you, then set up Builder.io again.";
278
+ export const BUILDER_CONNECT_SESSION_NOT_SHARED = "This window can't see your sign-in, which happens in previews and embedded browsers. Open the app in its own browser tab, sign in, then set up Builder.io there.";
279
+ export const BUILDER_ORG_MEMBERSHIP_UNREADABLE = "Couldn't check your organization membership. Try starting Builder.io setup again in a moment.";
280
+ export const BUILDER_ORG_ALREADY_CONNECTED = "Your organization already has a Builder.io connection, and a new account would take its place. An organization owner or admin can sign in to Builder.io again in Settings.";
281
+ export const BUILDER_ORG_RECONNECT_BY_LOGIN = "Your organization already has a Builder.io account. Sign in to Builder.io to use it.";
282
282
  /** Query/body field naming which Builder.io connection a request targets. */
283
283
  export const BUILDER_CONNECTION_SCOPE_PARAM = "scope";
284
284
  /**
@@ -291,8 +291,8 @@ export function parseBuilderConnectionScope(value) {
291
291
  return null;
292
292
  return value === "org" || value === "personal" ? value : "invalid";
293
293
  }
294
- const BUILDER_PERSONAL_CONNECTION_DENIED = "Owners and admins connect Builder.io for the organization.";
295
- const BUILDER_CONNECTION_MEMBERSHIP_ENDED = "You're no longer a member of the organization this Builder.io connection started in. Restart it from Settings.";
294
+ const BUILDER_PERSONAL_CONNECTION_DENIED = "Owners and admins set up Builder.io for the organization.";
295
+ const BUILDER_CONNECTION_MEMBERSHIP_ENDED = "You're no longer a member of the organization this Builder.io setup started in. Start it again from Settings.";
296
296
  /**
297
297
  * Who may start a connect for the named Builder.io connection. The org
298
298
  * connection needs owner/admin; a personal one is for members only, and only
@@ -1527,10 +1527,10 @@ export async function activateBuilderAccount(event, input) {
1527
1527
  }
1528
1528
  if (!session?.token ||
1529
1529
  !verifyBuilderProvisioningToken(input.provisioningToken, ownerEmail, session.token)) {
1530
- return fail(403, "This activation link is expired. Close this popup and click Activate again.", "provision_token_invalid");
1530
+ return fail(403, "This activation link is expired. Refresh Builder.io setup and try again.", "provision_token_invalid");
1531
1531
  }
1532
1532
  if (session.emailVerified !== true) {
1533
- return fail(403, "Verify your email before connecting Builder.", "email_not_verified");
1533
+ return fail(403, "Verify your email before using Builder.io.", "email_not_verified");
1534
1534
  }
1535
1535
  try {
1536
1536
  const activation = await decideBuilderActivation(event, {
@@ -1570,35 +1570,11 @@ export async function activateBuilderAccount(event, input) {
1570
1570
  catch (error) {
1571
1571
  console.error("[builder] Agent-Native account provisioning failed:", error instanceof Error ? error.message : error);
1572
1572
  if (isBuilderAccountAlreadyExistsError(error)) {
1573
- return fail(409, "A Builder account already exists for this email. Log in to connect it.", "account_exists", "account_exists");
1573
+ return fail(409, "A Builder.io account already exists for this email. Sign in to Builder.io to use it.", "account_exists", "account_exists");
1574
1574
  }
1575
- return fail(BUILDER_UPSTREAM_FAILURE_STATUS, "Couldn't create your Builder account. Try again or connect an existing account.", "provision_failed");
1575
+ return fail(BUILDER_UPSTREAM_FAILURE_STATUS, "Couldn't create your Builder.io account. Try again or sign in with an existing account.", "provision_failed");
1576
1576
  }
1577
1577
  }
1578
- /**
1579
- * The popup-era account activation: answers with a page that hands the result
1580
- * to its opener and closes. The error row is the opener's fallback channel,
1581
- * read by its status poll when the page's message never arrives.
1582
- */
1583
- export async function sendBuilderActivationPopup(event, input) {
1584
- const result = await activateBuilderAccount(event, input);
1585
- const parentOrigin = getBuilderBrowserOriginForEvent(event);
1586
- const attempt = input.connectAttemptId
1587
- ? { attemptId: input.connectAttemptId }
1588
- : {};
1589
- if (!result.ok) {
1590
- const code = result.code ? { code: result.code } : {};
1591
- await putSetting(getBuilderConnectErrorKey(input.ownerEmail, input.connectAttemptId), { message: result.message, at: Date.now(), ...code, ...attempt }).catch(() => { });
1592
- return sendBuilderPopupErrorPage(event, result.status, result.message, {
1593
- parentOrigin,
1594
- ...attempt,
1595
- ...code,
1596
- });
1597
- }
1598
- setResponseHeader(event, "Cache-Control", "no-store");
1599
- setResponseHeader(event, "Content-Type", "text/html; charset=utf-8");
1600
- return createBuilderBrowserCallbackPage(`${parentOrigin}${getAppBasePath() || "/"}`, { parentOrigin, ...attempt });
1601
- }
1602
1578
  const builderProvisionBodySchema = z.object({
1603
1579
  // Checked by activateBuilderAccount, so a missing token is refused like an
1604
1580
  // expired one and the client's refresh-and-retry covers both.
@@ -2850,7 +2826,7 @@ export function createCoreRoutesPlugin(options = {}) {
2850
2826
  ? "Builder connection status could not be read. Retry in a moment."
2851
2827
  : error instanceof Error
2852
2828
  ? error.message
2853
- : "Builder access expired. Reconnect Builder.io.",
2829
+ : "Builder access expired. Sign in to Builder.io again.",
2854
2830
  at: Date.now(),
2855
2831
  },
2856
2832
  });
@@ -3026,9 +3002,9 @@ export function createCoreRoutesPlugin(options = {}) {
3026
3002
  isAnonymousWaitlistSessionEmail(ownerEmail)) {
3027
3003
  setResponseStatus(event, 401);
3028
3004
  setResponseHeader(event, "Content-Type", "text/html; charset=utf-8");
3029
- return createBuilderBrowserCallbackErrorPage("Sign in to connect Builder.", {
3005
+ return createBuilderBrowserCallbackErrorPage("Sign in to use Builder.io.", {
3030
3006
  title: "Sign in required",
3031
- body: "Builder OAuth is tied to a signed-in account. Sign in, then try Connect Builder again.",
3007
+ body: "Builder OAuth is tied to a signed-in account. Sign in, then start Builder.io setup again.",
3032
3008
  parentOrigin: getBuilderBrowserOriginForEvent(event),
3033
3009
  ...(connectAttemptId ? { attemptId: connectAttemptId } : {}),
3034
3010
  });
@@ -3046,8 +3022,8 @@ export function createCoreRoutesPlugin(options = {}) {
3046
3022
  // local desktop popups stamped as same-site/cross-site by the browser.
3047
3023
  if (!isSameOriginConnect(event) && !hasValidConnectToken) {
3048
3024
  const crossOriginMessage = connectToken
3049
- ? "This Builder connect link is expired or belongs to a different deployment. Close this popup and click Connect account again."
3050
- : "Builder connect opened without a fresh signed link. Close this popup and click Connect account again.";
3025
+ ? "This Builder.io setup link is expired or belongs to a different deployment. Close this popup and start Builder.io setup again from the app."
3026
+ : "Builder.io setup opened without a fresh signed link. Close this popup and start setup again from the app.";
3051
3027
  await trackBuilderLifecycle(event, "builder connect failed", ownerEmail, {
3052
3028
  ...builderConnectTrackingProperties(connectTracking),
3053
3029
  reason: "cross_origin",
@@ -3071,14 +3047,14 @@ export function createCoreRoutesPlugin(options = {}) {
3071
3047
  setResponseStatus(event, 403);
3072
3048
  setResponseHeader(event, "Content-Type", "text/html; charset=utf-8");
3073
3049
  return createBuilderBrowserCallbackErrorPage(crossOriginMessage, {
3074
- title: "Couldn't start Builder connection",
3075
- body: "The connect popup did not include a valid signed link for this app.",
3076
- closeHint: "Close this popup, refresh the app, and try Connect account again.",
3050
+ title: "Couldn't start Builder.io setup",
3051
+ body: "The Builder.io setup popup did not include a valid signed link for this app.",
3052
+ closeHint: "Close this popup, refresh the app, and start Builder.io setup again.",
3077
3053
  parentOrigin: getBuilderBrowserOriginForEvent(event),
3078
3054
  ...(connectAttemptId ? { attemptId: connectAttemptId } : {}),
3079
3055
  });
3080
3056
  }
3081
- const denyConnect = async (status, message, reason) => {
3057
+ const denyConnect = async (status, message, reason, title = "Not allowed to use Builder.io for this organization") => {
3082
3058
  await putSetting(getBuilderConnectErrorKey(ownerEmail, connectAttemptId), {
3083
3059
  message,
3084
3060
  at: Date.now(),
@@ -3092,7 +3068,7 @@ export function createCoreRoutesPlugin(options = {}) {
3092
3068
  setResponseStatus(event, status);
3093
3069
  setResponseHeader(event, "Content-Type", "text/html; charset=utf-8");
3094
3070
  return createBuilderBrowserCallbackErrorPage(message, {
3095
- title: "Not allowed to connect Builder for this organization",
3071
+ title,
3096
3072
  body: message,
3097
3073
  parentOrigin: getBuilderBrowserOriginForEvent(event),
3098
3074
  ...(connectAttemptId ? { attemptId: connectAttemptId } : {}),
@@ -3111,18 +3087,10 @@ export function createCoreRoutesPlugin(options = {}) {
3111
3087
  return denyConnect(403, scopeAuthorization.deny.message, scopeAuthorization.deny.reason);
3112
3088
  }
3113
3089
  const scopedConnectAuthorization = scopeAuthorization.member;
3114
- // Clients that still open a popup to create an account land here;
3115
- // current clients call POST /builder/provision instead.
3090
+ // Account creation always uses POST /builder/provision so it never
3091
+ // depends on a popup or a browser's popup policy.
3116
3092
  if (shouldProvisionAgentNativeAccount) {
3117
- return sendBuilderActivationPopup(event, {
3118
- ownerEmail,
3119
- session: ownerContext.session,
3120
- provisioningToken: requestUrl.searchParams.get(BUILDER_PROVISIONING_TOKEN_PARAM),
3121
- requestedScope: requestedConnectionScope,
3122
- member: scopedConnectAuthorization,
3123
- connectAttemptId,
3124
- tracking: connectTracking,
3125
- });
3093
+ return denyConnect(400, "Use Builder.io setup in the app to create or activate an account.", "popup_provision_not_supported", "Use Builder.io setup in the app");
3126
3094
  }
3127
3095
  // Clear any prior failure row from a previous attempt — otherwise
3128
3096
  // useBuilderStatus polling sees the stale error and aborts the
@@ -3195,7 +3163,7 @@ export function createCoreRoutesPlugin(options = {}) {
3195
3163
  reason: "pending_storage_unavailable",
3196
3164
  stage: "connect",
3197
3165
  });
3198
- const msg = "Could not initiate Builder connect — storage unavailable. Try again.";
3166
+ const msg = "Could not start Builder.io setup — storage unavailable. Try again.";
3199
3167
  console.error("[builder] Could not store pending-connect state:", err?.message ?? err);
3200
3168
  // Best-effort: also write the error row so the parent's
3201
3169
  // /builder/status poll picks it up if BroadcastChannel doesn't.
@@ -3439,7 +3407,7 @@ export function createCoreRoutesPlugin(options = {}) {
3439
3407
  if (!privateKey || !publicKey) {
3440
3408
  setResponseStatus(event, 400);
3441
3409
  setResponseHeader(event, "Content-Type", "text/html; charset=utf-8");
3442
- return createBuilderBrowserCallbackErrorPage("Builder didn't return credentials. Restart the connect flow from settings.", {
3410
+ return createBuilderBrowserCallbackErrorPage("Builder didn't return credentials. Start Builder.io setup again from Settings.", {
3443
3411
  parentOrigin: relayParentOrigin,
3444
3412
  ...(requestConnectAttemptId
3445
3413
  ? { attemptId: requestConnectAttemptId }
@@ -3563,11 +3531,11 @@ export function createCoreRoutesPlugin(options = {}) {
3563
3531
  if (resetStateCookie && carriesOAuthResult) {
3564
3532
  deleteCookie(event, BUILDER_CONNECT_STATE_COOKIE, { path: "/" });
3565
3533
  }
3566
- return fail(403, "No active Builder connect flow found. Restart the connection from Settings.");
3534
+ return fail(403, "No active Builder.io setup was found. Start it again from Settings.");
3567
3535
  }
3568
3536
  const pending = await readBuilderConnectPendingState(state);
3569
3537
  if (!pending) {
3570
- return fail(403, "No active Builder connect flow found. Restart the connection from Settings.");
3538
+ return fail(403, "No active Builder.io setup was found. Start it again from Settings.");
3571
3539
  }
3572
3540
  callbackAttemptId =
3573
3541
  typeof pending.attemptId === "string"
@@ -3597,7 +3565,7 @@ export function createCoreRoutesPlugin(options = {}) {
3597
3565
  if (Date.now() >= expiresAt) {
3598
3566
  await deleteSetting(`builder-connect-pending:${state}`).catch(() => false); // coercion-ok: expired pending cleanup is best-effort; callback already failed verification
3599
3567
  }
3600
- return fail(403, "Builder connect callback could not be verified. Restart the connection.", ownerEmail ?? undefined, "callback_verification_failed", tracking);
3568
+ return fail(403, "Builder.io setup could not be verified. Start the setup again.", ownerEmail ?? undefined, "callback_verification_failed", tracking);
3601
3569
  }
3602
3570
  const denied = requestUrl.searchParams.get("error");
3603
3571
  const code = requestUrl.searchParams.get("code");
@@ -3618,11 +3586,11 @@ export function createCoreRoutesPlugin(options = {}) {
3618
3586
  });
3619
3587
  }
3620
3588
  catch {
3621
- return fail(BUILDER_UPSTREAM_FAILURE_STATUS, "Builder could not exchange the authorization code. Restart the connection.", ownerEmail, "code_exchange_failed", tracking);
3589
+ return fail(BUILDER_UPSTREAM_FAILURE_STATUS, "Builder could not exchange the authorization code. Start Builder.io setup again.", ownerEmail, "code_exchange_failed", tracking);
3622
3590
  }
3623
3591
  const requestedConnectionScope = parseBuilderConnectionScope(pending.connectionScope);
3624
3592
  if (requestedConnectionScope === "invalid") {
3625
- return fail(403, "Builder connect callback could not be verified. Restart the connection.", ownerEmail, "callback_verification_failed", tracking);
3593
+ return fail(403, "Builder.io setup could not be verified. Start the setup again.", ownerEmail, "callback_verification_failed", tracking);
3626
3594
  }
3627
3595
  const pendingOrgId = typeof pending.orgId === "string" ? pending.orgId : null;
3628
3596
  // Authority is read again after the external OAuth round trip, in
@@ -3660,11 +3628,11 @@ export function createCoreRoutesPlugin(options = {}) {
3660
3628
  });
3661
3629
  }
3662
3630
  catch {
3663
- return fail(500, "Builder credentials could not be saved. Restart the connection.", ownerEmail, "credential_write_failed", tracking);
3631
+ return fail(500, "Builder credentials could not be saved. Start Builder.io setup again.", ownerEmail, "credential_write_failed", tracking);
3664
3632
  }
3665
3633
  const consumed = await consumeBuilderConnectPendingState(state);
3666
3634
  if (!consumed) {
3667
- return fail(403, "No active Builder connect flow found. Restart the connection from Settings.", ownerEmail, "callback_verification_failed", tracking);
3635
+ return fail(403, "No active Builder.io setup was found. Start it again from Settings.", ownerEmail, "callback_verification_failed", tracking);
3668
3636
  }
3669
3637
  dropConnectStateCookie(state);
3670
3638
  try {
@@ -3674,7 +3642,7 @@ export function createCoreRoutesPlugin(options = {}) {
3674
3642
  ]);
3675
3643
  }
3676
3644
  catch {
3677
- return fail(500, "Builder credentials could not be saved. Restart the connection.", ownerEmail, "credential_write_failed", tracking);
3645
+ return fail(500, "Builder credentials could not be saved. Start Builder.io setup again.", ownerEmail, "credential_write_failed", tracking);
3678
3646
  }
3679
3647
  await trackBuilderLifecycle(event, "builder connect succeeded", ownerEmail, {
3680
3648
  ...builderConnectTrackingProperties(tracking),
@@ -4251,7 +4219,7 @@ export function createCoreRoutesPlugin(options = {}) {
4251
4219
  }
4252
4220
  setResponseStatus(event, 503);
4253
4221
  return {
4254
- error: "No object storage is connected. Connect Builder.io (free) or add your own S3-compatible storage keys in Settings → File uploads.",
4222
+ error: "No object storage is connected. Use Builder.io's managed storage (free) or add your own S3-compatible storage keys in Settings → File uploads.",
4255
4223
  };
4256
4224
  }));
4257
4225
  // ─── Voice transcription (Whisper) ───────────────────────────────
@@ -69,7 +69,7 @@ export class FeatureNotConfiguredError extends Error {
69
69
  byokDocsUrl;
70
70
  constructor(opts) {
71
71
  super(opts.message ??
72
- `Feature requires credential "${opts.requiredCredential}". Connect Builder (free tier available) or set your own key.`);
72
+ `Feature requires credential "${opts.requiredCredential}". Use Builder.io (free tier available) or set your own key.`);
73
73
  this.name = "FeatureNotConfiguredError";
74
74
  this.requiredCredential = opts.requiredCredential;
75
75
  this.builderConnectUrl = opts.builderConnectUrl;
@@ -864,7 +864,7 @@ export async function getBuilderCredentialAuthFailure(creds = {}) {
864
864
  fingerprint,
865
865
  message: typeof row.message === "string" && row.message
866
866
  ? row.message
867
- : "Builder rejected the connected credentials. Reconnect Builder.io (free tier available).",
867
+ : "Builder rejected the connected credentials. Sign in to Builder.io again (free tier available).",
868
868
  status: typeof row.status === "number" ? row.status : undefined,
869
869
  code: typeof row.code === "string" ? row.code : undefined,
870
870
  at,
@@ -888,7 +888,7 @@ export async function recordBuilderCredentialAuthFailure(details) {
888
888
  await putSetting(settingKey, {
889
889
  fingerprint,
890
890
  message: details?.message ||
891
- "Builder rejected the connected credentials. Reconnect Builder.io (free tier available).",
891
+ "Builder rejected the connected credentials. Sign in to Builder.io again (free tier available).",
892
892
  ...(typeof details?.status === "number" && { status: details.status }),
893
893
  ...(details?.code && { code: details.code }),
894
894
  strikes,
@@ -1,6 +1,8 @@
1
1
  export declare const OPEN_ROUTE_SUBPATH = "/open";
2
2
  export declare const DESKTOP_OPEN_URL = "agentnative://open";
3
3
  export declare const VSCODE_OPEN_URL = "vscode://builder.agent-native/open";
4
+ export declare function isSameOriginUrl(urlOrPath: string, origin?: string): boolean;
5
+ export declare function isAgentNativeOpenUrl(urlOrPath: string, origin?: string, basePath?: string): boolean;
4
6
  export interface DeepLinkInput {
5
7
  app?: string;
6
8
  view: string;
@@ -1,9 +1,31 @@
1
- import { withCollapsedAgentSidebarParam } from "../shared/agent-sidebar-url.js";
2
- import { getConfiguredAppBasePath, normalizeAppBasePath, } from "./app-base-path.js";
3
- import { publicFrameworkPath } from "./framework-route-prefix.js";
1
+ import { AGENT_NATIVE_OPEN_PATH, withCollapsedAgentSidebarParam, } from "../shared/agent-sidebar-url.js";
2
+ import { getConfiguredAppBasePath, normalizeAppBasePath, stripAppBasePath, } from "./app-base-path.js";
3
+ import { canonicalFrameworkPathname, publicFrameworkPath, } from "./framework-route-prefix.js";
4
4
  export const OPEN_ROUTE_SUBPATH = "/open";
5
5
  export const DESKTOP_OPEN_URL = "agentnative://open";
6
6
  export const VSCODE_OPEN_URL = "vscode://builder.agent-native/open";
7
+ export function isSameOriginUrl(urlOrPath, origin) {
8
+ const hasAuthority = /^[a-z][a-z0-9+.-]*:/i.test(urlOrPath) || urlOrPath.startsWith("//");
9
+ if (!hasAuthority)
10
+ return true;
11
+ if (!origin)
12
+ return false;
13
+ if (!URL.canParse(origin) || !URL.canParse(urlOrPath, origin))
14
+ return false;
15
+ return new URL(urlOrPath, origin).origin === new URL(origin).origin;
16
+ }
17
+ export function isAgentNativeOpenUrl(urlOrPath, origin, basePath = getConfiguredAppBasePath()) {
18
+ const base = origin ?? "http://agent-native.invalid";
19
+ if (!URL.canParse(urlOrPath, base))
20
+ return false;
21
+ const url = new URL(urlOrPath, base);
22
+ if (url.protocol === "agentnative:" && url.host === "open")
23
+ return true;
24
+ if (!isSameOriginUrl(urlOrPath, origin))
25
+ return false;
26
+ return (canonicalFrameworkPathname(stripAppBasePath(url.pathname, basePath)) ===
27
+ AGENT_NATIVE_OPEN_PATH);
28
+ }
7
29
  function buildQuery(input) {
8
30
  const sp = new URLSearchParams();
9
31
  if (input.app)
@@ -24,6 +46,11 @@ export function buildDeepLink(input) {
24
46
  export function toAbsoluteOpenUrl(urlOrPath, origin) {
25
47
  if (/^[a-z][a-z0-9+.-]*:\/\//i.test(urlOrPath))
26
48
  return urlOrPath;
49
+ if (urlOrPath.startsWith("//")) {
50
+ return origin && URL.canParse(urlOrPath, origin)
51
+ ? new URL(urlOrPath, origin).toString()
52
+ : urlOrPath;
53
+ }
27
54
  const basePath = getConfiguredAppBasePath();
28
55
  const path = withBasePath(urlOrPath, basePath);
29
56
  if (!origin)
@@ -34,7 +34,7 @@ async function resolveFusionAuth(requiredScope) {
34
34
  requiredScope,
35
35
  });
36
36
  if (!authorization) {
37
- throw new Error("Builder.io is not connected. Connect Builder.io in Settings.");
37
+ throw new Error("Builder.io is not connected. Sign in to Builder.io in Settings to continue.");
38
38
  }
39
39
  if (authorization.source === "legacy" && !authorization.legacyPublicKey) {
40
40
  throw new Error("Builder legacy credentials require BUILDER_PUBLIC_KEY for this request.");