@agent-native/core 0.163.3 → 0.164.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 (202) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/app/hooks/use-dashboard-chat-context.ts +29 -0
  3. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +1 -2
  4. package/corpus/templates/analytics/netlify.toml +2 -0
  5. package/corpus/templates/assets/netlify.toml +2 -0
  6. package/corpus/templates/brain/netlify.toml +2 -0
  7. package/corpus/templates/calendar/app/components/calendar/DayView.tsx +2 -1
  8. package/corpus/templates/calendar/changelog/2026-08-19-calendar-page-loads-stay-fast-after-idle-periods.md +6 -0
  9. package/corpus/templates/calendar/netlify.toml +2 -0
  10. package/corpus/templates/chat/netlify.toml +2 -0
  11. package/corpus/templates/clips/app/components/player/player-controls.tsx +3 -3
  12. package/corpus/templates/clips/app/components/player/reaction-emojis.ts +12 -0
  13. package/corpus/templates/clips/app/components/player/reactions-tray.tsx +90 -9
  14. package/corpus/templates/clips/app/components/player/scrubber.tsx +43 -10
  15. package/corpus/templates/clips/app/components/player/video-player.tsx +105 -15
  16. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +1 -2
  17. package/corpus/templates/clips/app/routes/_index.tsx +10 -2
  18. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +13 -8
  19. package/corpus/templates/clips/app/routes/share.$shareId.tsx +15 -8
  20. package/corpus/templates/clips/netlify.toml +2 -0
  21. package/corpus/templates/clips/server/routes/[...page].head.ts +5 -0
  22. package/corpus/templates/content/netlify.toml +2 -0
  23. package/corpus/templates/design/.agents/skills/design-editor-architecture/SKILL.md +103 -0
  24. package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +2 -1
  25. package/corpus/templates/design/AGENTS.md +3 -1
  26. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +3 -2
  27. package/corpus/templates/design/app/components/design/editor/AgentNativeMenuMark.tsx +25 -0
  28. package/corpus/templates/design/app/components/design/editor/DesignBottomToolbar.tsx +411 -0
  29. package/corpus/templates/design/app/components/design/editor/DesignCollaborators.tsx +153 -0
  30. package/corpus/templates/design/app/components/design/editor/DesignWorkspaceRail.tsx +231 -0
  31. package/corpus/templates/design/app/components/design/editor/MakeRealDialog.tsx +223 -0
  32. package/corpus/templates/design/app/components/design/editor/PendingScreenDeletionDialog.tsx +58 -0
  33. package/corpus/templates/design/app/components/design/editor/PendingVisualStyleWarningDialog.tsx +56 -0
  34. package/corpus/templates/design/app/components/design/editor/ReadOnlyEditorPanel.tsx +23 -0
  35. package/corpus/templates/design/app/components/design/editor/SaveTemplateDialog.tsx +161 -0
  36. package/corpus/templates/design/app/components/design/editor/toolbar-controls.tsx +185 -0
  37. package/corpus/templates/design/app/pages/DesignEditor.tsx +20913 -0
  38. package/corpus/templates/design/app/pages/design-editor/command-types.ts +120 -0
  39. package/corpus/templates/design/app/pages/design-editor/commands/README.md +193 -0
  40. package/corpus/templates/design/app/pages/design-editor/commands/add-auto-layout.ts +416 -0
  41. package/corpus/templates/design/app/pages/design-editor/commands/add-screen.ts +112 -0
  42. package/corpus/templates/design/app/pages/design-editor/commands/align-selection.ts +183 -0
  43. package/corpus/templates/design/app/pages/design-editor/commands/apply-design-editor-command.ts +243 -0
  44. package/corpus/templates/design/app/pages/design-editor/commands/apply-file-content-update.ts +236 -0
  45. package/corpus/templates/design/app/pages/design-editor/commands/apply-local-content-update.ts +304 -0
  46. package/corpus/templates/design/app/pages/design-editor/commands/apply-pending-visual-styles-with-agent.ts +376 -0
  47. package/corpus/templates/design/app/pages/design-editor/commands/apply-to-source.ts +132 -0
  48. package/corpus/templates/design/app/pages/design-editor/commands/can-move-layer.ts +117 -0
  49. package/corpus/templates/design/app/pages/design-editor/commands/change-selected-z-index.ts +212 -0
  50. package/corpus/templates/design/app/pages/design-editor/commands/commit-relative-style-delta-to-selected-layers.ts +176 -0
  51. package/corpus/templates/design/app/pages/design-editor/commands/commit-styles-to-selected-layers.ts +175 -0
  52. package/corpus/templates/design/app/pages/design-editor/commands/commit-visual-styles.ts +710 -0
  53. package/corpus/templates/design/app/pages/design-editor/commands/confirm-make-real.ts +99 -0
  54. package/corpus/templates/design/app/pages/design-editor/commands/copy-as-figma-svg.ts +95 -0
  55. package/corpus/templates/design/app/pages/design-editor/commands/copy-selection.ts +156 -0
  56. package/corpus/templates/design/app/pages/design-editor/commands/create-primitive.ts +291 -0
  57. package/corpus/templates/design/app/pages/design-editor/commands/create-screen-frame.ts +131 -0
  58. package/corpus/templates/design/app/pages/design-editor/commands/cross-screen-element-drop.ts +577 -0
  59. package/corpus/templates/design/app/pages/design-editor/commands/delete-files.ts +364 -0
  60. package/corpus/templates/design/app/pages/design-editor/commands/delete-selection.ts +521 -0
  61. package/corpus/templates/design/app/pages/design-editor/commands/detach-instance-menu-action.ts +88 -0
  62. package/corpus/templates/design/app/pages/design-editor/commands/distribute-selection.ts +114 -0
  63. package/corpus/templates/design/app/pages/design-editor/commands/download-all-screens-pdf.ts +116 -0
  64. package/corpus/templates/design/app/pages/design-editor/commands/download-pdf.ts +103 -0
  65. package/corpus/templates/design/app/pages/design-editor/commands/download-svg.ts +159 -0
  66. package/corpus/templates/design/app/pages/design-editor/commands/duplicate-screen.ts +201 -0
  67. package/corpus/templates/design/app/pages/design-editor/commands/duplicate-selection.ts +279 -0
  68. package/corpus/templates/design/app/pages/design-editor/commands/editor-paste.ts +81 -0
  69. package/corpus/templates/design/app/pages/design-editor/commands/enter-hotkey.ts +155 -0
  70. package/corpus/templates/design/app/pages/design-editor/commands/enter-single-screen.ts +168 -0
  71. package/corpus/templates/design/app/pages/design-editor/commands/escape-hotkey.ts +212 -0
  72. package/corpus/templates/design/app/pages/design-editor/commands/frame-selection.ts +119 -0
  73. package/corpus/templates/design/app/pages/design-editor/commands/geometry-commit.ts +169 -0
  74. package/corpus/templates/design/app/pages/design-editor/commands/get-selected-layer-snapshots.ts +177 -0
  75. package/corpus/templates/design/app/pages/design-editor/commands/group-selection.ts +127 -0
  76. package/corpus/templates/design/app/pages/design-editor/commands/iframe-context-menu.ts +121 -0
  77. package/corpus/templates/design/app/pages/design-editor/commands/import-figma-clipboard-into-design.ts +119 -0
  78. package/corpus/templates/design/app/pages/design-editor/commands/layer-marquee-selection-change.ts +163 -0
  79. package/corpus/templates/design/app/pages/design-editor/commands/layer-move-to-screen.ts +331 -0
  80. package/corpus/templates/design/app/pages/design-editor/commands/layer-move.ts +517 -0
  81. package/corpus/templates/design/app/pages/design-editor/commands/layer-rename.ts +247 -0
  82. package/corpus/templates/design/app/pages/design-editor/commands/layer-selection-change.ts +161 -0
  83. package/corpus/templates/design/app/pages/design-editor/commands/mode-change.ts +122 -0
  84. package/corpus/templates/design/app/pages/design-editor/commands/nudge-selection.ts +213 -0
  85. package/corpus/templates/design/app/pages/design-editor/commands/overview-primitive-reparent.ts +318 -0
  86. package/corpus/templates/design/app/pages/design-editor/commands/paste-copied-screens.ts +114 -0
  87. package/corpus/templates/design/app/pages/design-editor/commands/paste-over-selection.ts +70 -0
  88. package/corpus/templates/design/app/pages/design-editor/commands/paste-selection.ts +436 -0
  89. package/corpus/templates/design/app/pages/design-editor/commands/paste-to-replace.ts +135 -0
  90. package/corpus/templates/design/app/pages/design-editor/commands/pasted-image-files.ts +209 -0
  91. package/corpus/templates/design/app/pages/design-editor/commands/persist-frame-geometry-save.ts +113 -0
  92. package/corpus/templates/design/app/pages/design-editor/commands/persist-tweak-save.ts +160 -0
  93. package/corpus/templates/design/app/pages/design-editor/commands/primitive-created.ts +168 -0
  94. package/corpus/templates/design/app/pages/design-editor/commands/record-pending-live-layer-state-edit.ts +149 -0
  95. package/corpus/templates/design/app/pages/design-editor/commands/record-pending-live-structure-edit.ts +200 -0
  96. package/corpus/templates/design/app/pages/design-editor/commands/record-pending-live-text-edit.ts +152 -0
  97. package/corpus/templates/design/app/pages/design-editor/commands/record-pending-visual-style-edit.ts +247 -0
  98. package/corpus/templates/design/app/pages/design-editor/commands/redo.ts +1086 -0
  99. package/corpus/templates/design/app/pages/design-editor/commands/render-png-blob.ts +200 -0
  100. package/corpus/templates/design/app/pages/design-editor/commands/save-file-content.ts +207 -0
  101. package/corpus/templates/design/app/pages/design-editor/commands/screen-element-select.ts +262 -0
  102. package/corpus/templates/design/app/pages/design-editor/commands/screen-text-content-change.ts +216 -0
  103. package/corpus/templates/design/app/pages/design-editor/commands/screen-visual-duplicate-change.ts +108 -0
  104. package/corpus/templates/design/app/pages/design-editor/commands/screen-visual-structure-change.ts +280 -0
  105. package/corpus/templates/design/app/pages/design-editor/commands/screen-visual-style-change.ts +151 -0
  106. package/corpus/templates/design/app/pages/design-editor/commands/send-overview-annotations.ts +88 -0
  107. package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-move-semantic-handoff.ts +122 -0
  108. package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-semantic-handoff.ts +143 -0
  109. package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-state-semantic-handoff.ts +115 -0
  110. package/corpus/templates/design/app/pages/design-editor/commands/start-retry-generation.ts +152 -0
  111. package/corpus/templates/design/app/pages/design-editor/commands/start-sidebar-resize.ts +99 -0
  112. package/corpus/templates/design/app/pages/design-editor/commands/style-change.ts +152 -0
  113. package/corpus/templates/design/app/pages/design-editor/commands/styles-change.ts +155 -0
  114. package/corpus/templates/design/app/pages/design-editor/commands/suggest-auto-layout.ts +125 -0
  115. package/corpus/templates/design/app/pages/design-editor/commands/text-content-change.ts +201 -0
  116. package/corpus/templates/design/app/pages/design-editor/commands/tidy-up.ts +123 -0
  117. package/corpus/templates/design/app/pages/design-editor/commands/toggle-layer-hidden.ts +167 -0
  118. package/corpus/templates/design/app/pages/design-editor/commands/toggle-layer-locked.ts +175 -0
  119. package/corpus/templates/design/app/pages/design-editor/commands/toggle-motion-keyframe.ts +99 -0
  120. package/corpus/templates/design/app/pages/design-editor/commands/tweak-prompt-submit.ts +84 -0
  121. package/corpus/templates/design/app/pages/design-editor/commands/undo.ts +906 -0
  122. package/corpus/templates/design/app/pages/design-editor/commands/ungroup-selection.ts +170 -0
  123. package/corpus/templates/design/app/pages/design-editor/commands/visual-duplicate-change.ts +119 -0
  124. package/corpus/templates/design/app/pages/design-editor/commands/visual-structure-change.ts +274 -0
  125. package/corpus/templates/design/app/pages/design-editor/commands/write-frame-geometry-snapshot.ts +99 -0
  126. package/corpus/templates/design/app/pages/design-editor/derive/design-breakpoints.ts +56 -0
  127. package/corpus/templates/design/app/pages/design-editor/derive/overview-screens.ts +146 -0
  128. package/corpus/templates/design/app/pages/design-editor/domains/use-tweaks.ts +326 -0
  129. package/corpus/templates/design/app/pages/design-editor/editor-constants.ts +54 -0
  130. package/corpus/templates/design/app/pages/design-editor/editor-helpers.ts +183 -0
  131. package/corpus/templates/design/app/pages/design-editor/effects/adopt-db-file-content.ts +270 -0
  132. package/corpus/templates/design/app/pages/design-editor/effects/mirror-selection-to-agent-chat.ts +134 -0
  133. package/corpus/templates/design/app/pages/design-editor/effects/motion-autosave.ts +335 -0
  134. package/corpus/templates/design/app/pages/design-editor/effects/observe-collab-text.ts +183 -0
  135. package/corpus/templates/design/app/pages/design-editor/effects/publish-agent-selection-context.ts +252 -0
  136. package/corpus/templates/design/app/pages/design-editor/effects/resume-pending-generation.ts +178 -0
  137. package/corpus/templates/design/app/pages/design-editor/effects/seed-collab-content.ts +157 -0
  138. package/corpus/templates/design/app/pages/design-editor/preview-html.ts +19 -0
  139. package/corpus/templates/design/netlify.toml +2 -0
  140. package/corpus/templates/design/shared/board-file.ts +2 -1
  141. package/corpus/templates/dispatch/netlify.toml +2 -0
  142. package/corpus/templates/forms/netlify.toml +2 -0
  143. package/corpus/templates/mail/netlify.toml +2 -0
  144. package/corpus/templates/plan/netlify.toml +2 -0
  145. package/corpus/templates/slides/netlify.toml +2 -0
  146. package/dist/agent/engine/builder-engine.d.ts +6 -4
  147. package/dist/agent/engine/builder-engine.js +91 -26
  148. package/dist/agent/engine/registry.js +16 -0
  149. package/dist/cli/code-agent-agent-tools.d.ts +2 -0
  150. package/dist/cli/code-agent-agent-tools.js +188 -0
  151. package/dist/cli/code-agent-collaboration.d.ts +34 -0
  152. package/dist/cli/code-agent-collaboration.js +104 -0
  153. package/dist/cli/code-agent-executor.js +6 -0
  154. package/dist/cli/code-agent-schedules.d.ts +54 -0
  155. package/dist/cli/code-agent-schedules.js +198 -0
  156. package/dist/client/AgentPanel.js +1 -1
  157. package/dist/client/ConnectBuilderCard.js +5 -2
  158. package/dist/client/EnvironmentBadge.js +6 -5
  159. package/dist/client/chat/run-recovery.js +3 -2
  160. package/dist/client/chat/tool-call-display.js +2 -3
  161. package/dist/client/components/CodeRequiredDialog.js +4 -2
  162. package/dist/client/i18n.js +5 -4
  163. package/dist/client/settings/SettingsPanel.js +1 -1
  164. package/dist/client/settings/VoiceTranscriptionSection.js +1 -1
  165. package/dist/client/settings/useBuilderStatus.d.ts +6 -1
  166. package/dist/client/settings/useBuilderStatus.js +22 -33
  167. package/dist/client/transcription/BuilderTranscriptionCta.js +1 -1
  168. package/dist/code-agents/index.d.ts +2 -0
  169. package/dist/code-agents/index.js +2 -0
  170. package/dist/collab/routes.d.ts +1 -1
  171. package/dist/localization/shared.d.ts +2 -0
  172. package/dist/localization/shared.js +5 -0
  173. package/dist/mcp-client/oauth-client.d.ts +1 -0
  174. package/dist/mcp-client/oauth-client.js +50 -1
  175. package/dist/observability/routes.d.ts +1 -1
  176. package/dist/provider-api/actions/provider-api.d.ts +2 -2
  177. package/dist/resources/handlers.d.ts +1 -1
  178. package/dist/server/auth-marketing-locales.d.ts +7 -0
  179. package/dist/server/auth-marketing-locales.js +1322 -0
  180. package/dist/server/auth-marketing.d.ts +1 -0
  181. package/dist/server/auth-marketing.js +35 -6
  182. package/dist/server/auth.js +4 -17
  183. package/dist/server/builder-browser.d.ts +22 -0
  184. package/dist/server/builder-browser.js +77 -1
  185. package/dist/server/builder-oauth.d.ts +50 -0
  186. package/dist/server/builder-oauth.js +263 -0
  187. package/dist/server/core-routes-plugin.d.ts +11 -0
  188. package/dist/server/core-routes-plugin.js +291 -415
  189. package/dist/server/credential-provider.d.ts +1 -1
  190. package/dist/server/credential-provider.js +1 -1
  191. package/dist/server/csrf.js +2 -2
  192. package/dist/server/onboarding-html.js +52 -120
  193. package/dist/server/realtime-token.d.ts +1 -1
  194. package/dist/server/transcribe-voice.d.ts +1 -1
  195. package/dist/settings/store.d.ts +9 -0
  196. package/dist/settings/store.js +19 -0
  197. package/dist/templates/chat/netlify.toml +2 -0
  198. package/dist/vite/client.js +35 -37
  199. package/docs/content/deployment.mdx +2 -0
  200. package/docs/content/multi-app-workspace.mdx +1 -1
  201. package/package.json +2 -2
  202. package/src/templates/chat/netlify.toml +2 -0
@@ -16,4 +16,5 @@ export interface ResolveBuiltInAuthMarketingOptions {
16
16
  }
17
17
  export declare const BUILT_IN_AUTH_MARKETING: Record<string, AuthMarketingContent>;
18
18
  export declare function resolveBuiltInAuthMarketing(opts?: ResolveBuiltInAuthMarketingOptions): AuthMarketingContent | undefined;
19
+ export declare function resolveBuiltInAuthMarketingSlug(opts?: ResolveBuiltInAuthMarketingOptions): string | undefined;
19
20
  export declare function resolveBuiltInAuthMarketingByName(value: string | undefined): AuthMarketingContent | undefined;
@@ -33,6 +33,7 @@ export const BUILT_IN_AUTH_MARKETING = {
33
33
  features: [
34
34
  "One-click screen recording with automatic titles, summaries, and chapters",
35
35
  "Calendar-synced meeting notes with live transcripts and action items",
36
+ "Push-to-talk voice dictation with clean text from anywhere",
36
37
  "One searchable library across recordings, meetings, and dictations",
37
38
  ],
38
39
  },
@@ -121,6 +122,34 @@ export const BUILT_IN_AUTH_MARKETING = {
121
122
  "Use the built-in app-agent loop or plug in your own agent backend",
122
123
  ],
123
124
  },
125
+ crm: {
126
+ appName: "Agent-Native CRM",
127
+ tagline: "A complete Native SQL CRM or a connected companion grounded in its source system.",
128
+ features: [
129
+ "Run accounts, people, opportunities, tasks, and cadence on Native SQL",
130
+ "Connect scoped HubSpot or Salesforce records without copying credentials",
131
+ "Work with the same safe actions from the UI or your CRM agent",
132
+ ],
133
+ },
134
+ factory: {
135
+ appName: "Agent-Native Factory",
136
+ tagline: "Build agent factories: work in one end, shipped changes out the other, with gates you control.",
137
+ features: [
138
+ "Inspect Slack and pull-request signals in one queue",
139
+ "Tune rules with prompts and reviewable feedback",
140
+ "Approve bounded agent work with a durable audit trail",
141
+ ],
142
+ },
143
+ tasks: {
144
+ appName: "Agent-Native Tasks",
145
+ tagline: "Manage your personal tasks: triage in the inbox, finish from the list. Use an agent that can do all of that for you.",
146
+ features: [
147
+ "Inbox triage — capture ideas and drafts as they come, then promote them to tasks when they are ready",
148
+ "Task management — create, reorder, and complete tasks in a list that stays in the order you put it in",
149
+ "Track what you care about with custom fields — text, numbers, currency, dates, and color-coded selects",
150
+ "Anything you can do here, the agent can do too — and it sees what is on your screen, so “finish these” means the rows you actually selected",
151
+ ],
152
+ },
124
153
  };
125
154
  const SLUG_ALIASES = {
126
155
  "agent-native": "",
@@ -204,12 +233,12 @@ function candidateSlugs(opts = {}) {
204
233
  return candidates.filter((slug) => !!slug);
205
234
  }
206
235
  export function resolveBuiltInAuthMarketing(opts = {}) {
207
- for (const slug of candidateSlugs(opts)) {
208
- const marketing = BUILT_IN_AUTH_MARKETING[slug];
209
- if (marketing)
210
- return cloneMarketing(marketing);
211
- }
212
- return undefined;
236
+ const slug = resolveBuiltInAuthMarketingSlug(opts);
237
+ const marketing = slug ? BUILT_IN_AUTH_MARKETING[slug] : undefined;
238
+ return marketing ? cloneMarketing(marketing) : undefined;
239
+ }
240
+ export function resolveBuiltInAuthMarketingSlug(opts = {}) {
241
+ return candidateSlugs(opts).find((slug) => !!BUILT_IN_AUTH_MARKETING[slug]);
213
242
  }
214
243
  export function resolveBuiltInAuthMarketingByName(value) {
215
244
  const slug = normalizeSlug(value);
@@ -61,7 +61,7 @@ import { getAppProductionUrl } from "./app-url.js";
61
61
  import { readAnalyticsAnonymousId, readFirstTouchAttribution, signupAttributionFromCookieHeader, } from "./attribution.js";
62
62
  import { getAuthLoginMode } from "./auth-login-mode.js";
63
63
  import { createBetterAuthSessionForEmail, ensureGoogleAuthIdentity, getAuthSecret, getBetterAuth, getBetterAuthSync, isDeployPreview, } from "./better-auth-instance.js";
64
- import { BUILDER_CONNECT_OWNER_COOKIE, BUILDER_CONNECT_PARAM, BUILDER_RELAY_PATH, BUILDER_RELAY_STATE_PARAM, BUILDER_STATE_PARAM, verifyBuilderCallbackStateAndGetOwner, verifyBuilderConnectTokenAndGetOwner, verifyBuilderPreviewRelayStateForCallback, } from "./builder-browser.js";
64
+ import { BUILDER_CONNECT_PARAM, BUILDER_RELAY_PATH, BUILDER_RELAY_STATE_PARAM, verifyBuilderConnectTokenAndGetOwner, verifyBuilderPreviewRelayStateForCallback, } from "./builder-browser.js";
65
65
  import { resolveAuthCookieNamespace } from "./cookie-namespace.js";
66
66
  import { getAllowedCorsOrigin, readCorsAllowedOrigins, } from "./cors-origins.js";
67
67
  import { readDesktopSso, writeDesktopSso, clearDesktopSso, } from "./desktop-sso.js";
@@ -1521,9 +1521,6 @@ export function shouldBypassAuthForBuilderConnect(event, p) {
1521
1521
  if (p === "/_agent-native/builder/callback") {
1522
1522
  const url = event.node?.req?.url ?? event.path ?? "/";
1523
1523
  const queryStart = url.indexOf("?");
1524
- const state = queryStart >= 0
1525
- ? new URLSearchParams(url.slice(queryStart + 1)).get(BUILDER_STATE_PARAM)
1526
- : null;
1527
1524
  const relayState = queryStart >= 0
1528
1525
  ? new URLSearchParams(url.slice(queryStart + 1)).get(BUILDER_RELAY_STATE_PARAM)
1529
1526
  : null;
@@ -1536,19 +1533,9 @@ export function shouldBypassAuthForBuilderConnect(event, p) {
1536
1533
  // Dedicated relay secret missing: let the auth guard fail closed.
1537
1534
  }
1538
1535
  }
1539
- // The signed `_an_state` authenticates this specific Builder callback
1540
- // flow back to our app. A stale localhost session cookie can otherwise
1541
- // make the global guard reject the callback before the handler gets to
1542
- // validate the state and owner. This only bypasses to the callback route;
1543
- // the callback handler still verifies the signed owner / pending flow.
1544
- if (verifyBuilderCallbackStateAndGetOwner(state))
1545
- return true;
1546
- // The legacy owner cookie is broader and can be stale across shared
1547
- // browser sessions, so keep it limited to the session-lost popup case.
1548
- const hasSession = getFrameworkSessionCookieValues(event).length > 0;
1549
- if (hasSession)
1550
- return false;
1551
- return Boolean(verifyBuilderConnectTokenAndGetOwner(getCookie(event, BUILDER_CONNECT_OWNER_COOKIE)));
1536
+ // Builder OAuth callback requires the signed-in session that started the
1537
+ // flow; the handler verifies state + pending row + session owner. Do not
1538
+ // bypass on legacy CLI `_an_state` or owner cookies.
1552
1539
  }
1553
1540
  return false;
1554
1541
  }
@@ -35,6 +35,28 @@ export interface BuilderRelayRequestBody {
35
35
  relayState: string;
36
36
  credentials: BuilderRelayCredentials;
37
37
  }
38
+ /**
39
+ * Opaque OAuth `state` for Builder connect. Bound to the app auth secret so a
40
+ * pending row cannot be forged from another deployment that shares a database.
41
+ */
42
+ export declare function createBuilderConnectState(): string;
43
+ export declare function isSignedBuilderConnectState(value: string | null | undefined): boolean;
44
+ /**
45
+ * Railway-safe Builder OAuth callback URL check: same origin as this request
46
+ * (via `isAllowedOAuthRedirectUri`), under `/_agent-native/`, HTTPS in
47
+ * production, and loopback HTTP only outside production. No fixed domain
48
+ * allowlist — any deploy origin (including `*.up.railway.app`) works when the
49
+ * redirect URI is this app's own callback.
50
+ */
51
+ export declare function isBuilderConnectCallbackUrlAllowed(candidate: string, event: H3Event): boolean;
52
+ /**
53
+ * Build this request's Builder OAuth callback URL from the current origin +
54
+ * `getAppBasePath()` + `BUILDER_CALLBACK_PATH`. Intentionally ignores any
55
+ * `?redirect_uri=` query override — connect always returns to this app's own
56
+ * callback. Validated with `isBuilderConnectCallbackUrlAllowed` (Railway-safe,
57
+ * no fixed domain allowlist).
58
+ */
59
+ export declare function resolveBuilderConnectCallbackUrl(event: H3Event): string | null;
38
60
  export declare function isSafeBuilderRelayTargetOrigin(value: string): boolean;
39
61
  export declare function isTrustedBuilderRelayTargetOrigin(value: string): boolean;
40
62
  /**
@@ -3,7 +3,7 @@ import { getHeader } from "h3";
3
3
  import { getSetting } from "../settings/store.js";
4
4
  import { applyBuilderUtmTrackingParams } from "../shared/builder-link-tracking.js";
5
5
  import { getAuthSecret, resolveSignupTrackingIdentity, } from "./better-auth-instance.js";
6
- import { getAppBasePath, getOrigin } from "./google-oauth.js";
6
+ import { getAppBasePath, getOrigin, isAllowedOAuthRedirectUri, } from "./google-oauth.js";
7
7
  import { getRequestOrgId, getRequestUserEmail } from "./request-context.js";
8
8
  const DEFAULT_BUILDER_APP_HOST = "https://builder.io";
9
9
  const DEFAULT_BUILDER_API_HOST = "https://api.builder.io";
@@ -47,6 +47,82 @@ function safeEqualText(expected, actual) {
47
47
  return (expectedBuffer.length === actualBuffer.length &&
48
48
  timingSafeEqual(expectedBuffer, actualBuffer));
49
49
  }
50
+ /**
51
+ * Opaque OAuth `state` for Builder connect. Bound to the app auth secret so a
52
+ * pending row cannot be forged from another deployment that shares a database.
53
+ */
54
+ export function createBuilderConnectState() {
55
+ const stateNonce = randomBytes(32).toString("base64url");
56
+ const signature = createHmac("sha256", `builder-connect-state:${getAuthSecret()}`)
57
+ .update(stateNonce)
58
+ .digest("base64url");
59
+ return `${stateNonce}.${signature}`;
60
+ }
61
+ export function isSignedBuilderConnectState(value) {
62
+ if (!value)
63
+ return false;
64
+ const [nonce, signature, ...rest] = value.split(".");
65
+ if (!nonce ||
66
+ !signature ||
67
+ rest.length ||
68
+ !/^[A-Za-z0-9_-]{43}$/.test(nonce) ||
69
+ !/^[A-Za-z0-9_-]{43}$/.test(signature)) {
70
+ return false;
71
+ }
72
+ const expected = createHmac("sha256", `builder-connect-state:${getAuthSecret()}`)
73
+ .update(nonce)
74
+ .digest("base64url");
75
+ return safeEqualText(expected, signature);
76
+ }
77
+ /**
78
+ * Railway-safe Builder OAuth callback URL check: same origin as this request
79
+ * (via `isAllowedOAuthRedirectUri`), under `/_agent-native/`, HTTPS in
80
+ * production, and loopback HTTP only outside production. No fixed domain
81
+ * allowlist — any deploy origin (including `*.up.railway.app`) works when the
82
+ * redirect URI is this app's own callback.
83
+ */
84
+ export function isBuilderConnectCallbackUrlAllowed(candidate, event) {
85
+ if (!isAllowedOAuthRedirectUri(candidate, event))
86
+ return false;
87
+ let url;
88
+ try {
89
+ url = new URL(candidate);
90
+ }
91
+ catch {
92
+ // coercion-ok: malformed callback strings are not allowed redirects.
93
+ return false;
94
+ }
95
+ if (url.username || url.password)
96
+ return false;
97
+ const hostname = url.hostname.toLowerCase();
98
+ const loopback = hostname === "localhost" ||
99
+ hostname === "127.0.0.1" ||
100
+ hostname === "::1" ||
101
+ hostname === "[::1]";
102
+ if (loopback) {
103
+ return url.protocol === "http:" && process.env.NODE_ENV !== "production";
104
+ }
105
+ return url.protocol === "https:";
106
+ }
107
+ /**
108
+ * Build this request's Builder OAuth callback URL from the current origin +
109
+ * `getAppBasePath()` + `BUILDER_CALLBACK_PATH`. Intentionally ignores any
110
+ * `?redirect_uri=` query override — connect always returns to this app's own
111
+ * callback. Validated with `isBuilderConnectCallbackUrlAllowed` (Railway-safe,
112
+ * no fixed domain allowlist).
113
+ */
114
+ export function resolveBuilderConnectCallbackUrl(event) {
115
+ const withBase = `${getOrigin(event)}${getAppBasePath()}${BUILDER_CALLBACK_PATH}`;
116
+ if (isBuilderConnectCallbackUrlAllowed(withBase, event))
117
+ return withBase;
118
+ // Match google-oauth default-redirect behavior when the request is not under
119
+ // APP_BASE_PATH: fall back to the root `/_agent-native/...` callback.
120
+ const root = `${getOrigin(event)}${BUILDER_CALLBACK_PATH}`;
121
+ if (root !== withBase && isBuilderConnectCallbackUrlAllowed(root, event)) {
122
+ return root;
123
+ }
124
+ return null;
125
+ }
50
126
  function normalizeBuilderRelayBasePath(value) {
51
127
  if (!value)
52
128
  return "";
@@ -0,0 +1,50 @@
1
+ export declare const BUILDER_OAUTH_ISSUER = "https://mcp.builder.io";
2
+ export declare const BUILDER_OAUTH_RESOURCE = "https://api.builder.io";
3
+ export declare const BUILDER_OAUTH_PROTECTED_RESOURCE_METADATA = "https://mcp.builder.io/.well-known/oauth-protected-resource/api";
4
+ export declare const BUILDER_OAUTH_AUTHORIZATION_METADATA = "https://mcp.builder.io/.well-known/oauth-authorization-server";
5
+ export declare const BUILDER_OAUTH_AUTHORIZATION_ENDPOINT = "https://mcp.builder.io/oauth/authorize";
6
+ export declare const BUILDER_OAUTH_TOKEN_ENDPOINT = "https://mcp.builder.io/oauth/token";
7
+ export declare const BUILDER_OAUTH_REGISTRATION_ENDPOINT = "https://mcp.builder.io/oauth/register";
8
+ export declare const BUILDER_OAUTH_REVOCATION_ENDPOINT = "https://mcp.builder.io/oauth/revoke";
9
+ export declare const BUILDER_OAUTH_SCOPE = "builder:ai:invoke";
10
+ export declare const BUILDER_OAUTH_SCOPES: readonly ["builder:ai:invoke"];
11
+ export type BuilderOAuthPendingFlow = {
12
+ codeVerifier: string;
13
+ clientInformation: unknown;
14
+ discoveryState?: unknown;
15
+ redirectUri: string;
16
+ };
17
+ export type BuilderOAuthSession = {
18
+ accessToken: string;
19
+ expiresAt?: number;
20
+ scopes: string[];
21
+ };
22
+ export type BuilderOAuthRequestAccess = BuilderOAuthSession & {
23
+ ownerEmail: string;
24
+ };
25
+ export declare function startBuilderOAuthAuthorization(input: {
26
+ ownerEmail: string;
27
+ redirectUri: string;
28
+ state: string;
29
+ }): Promise<{
30
+ authorizationUrl: string;
31
+ pending: BuilderOAuthPendingFlow;
32
+ }>;
33
+ export declare function finishBuilderOAuthAuthorization(input: {
34
+ ownerEmail: string;
35
+ code: string;
36
+ iss?: string;
37
+ pending: BuilderOAuthPendingFlow;
38
+ }): Promise<void>;
39
+ export declare function markBuilderOAuthReconnectRequired(ownerEmail: string): Promise<void>;
40
+ export declare function builderOAuthReconnectRequired(ownerEmail: string): Promise<boolean>;
41
+ export declare function getBuilderOAuthSession(ownerEmail: string): Promise<BuilderOAuthSession | null>;
42
+ export declare function hasBuilderOAuthSession(ownerEmail: string): Promise<boolean>;
43
+ export declare function resolveBuilderOAuthRequestAccess(input: {
44
+ ownerEmail: string;
45
+ requiredScope: string;
46
+ }): Promise<BuilderOAuthRequestAccess | null>;
47
+ export declare function deleteBuilderOAuthSession(ownerEmail: string): Promise<{
48
+ localDeleted: boolean;
49
+ remoteRevoked: boolean;
50
+ }>;
@@ -0,0 +1,263 @@
1
+ import { finishMcpOAuthAuthorization, getMcpOAuthAccessToken, readMcpOAuthCredentials, revokeMcpOAuthCredentials, saveMcpOAuthCredentials, startMcpOAuthAuthorization, validateMcpOAuthCallbackIssuer, } from "../mcp-client/oauth-client.js";
2
+ import { getOAuthTokens } from "../oauth-tokens/store.js";
3
+ import { getSetting, mutateSetting, putSetting } from "../settings/store.js";
4
+ export const BUILDER_OAUTH_ISSUER = "https://mcp.builder.io";
5
+ export const BUILDER_OAUTH_RESOURCE = "https://api.builder.io";
6
+ export const BUILDER_OAUTH_PROTECTED_RESOURCE_METADATA = "https://mcp.builder.io/.well-known/oauth-protected-resource/api";
7
+ export const BUILDER_OAUTH_AUTHORIZATION_METADATA = "https://mcp.builder.io/.well-known/oauth-authorization-server";
8
+ export const BUILDER_OAUTH_AUTHORIZATION_ENDPOINT = "https://mcp.builder.io/oauth/authorize";
9
+ export const BUILDER_OAUTH_TOKEN_ENDPOINT = "https://mcp.builder.io/oauth/token";
10
+ export const BUILDER_OAUTH_REGISTRATION_ENDPOINT = "https://mcp.builder.io/oauth/register";
11
+ export const BUILDER_OAUTH_REVOCATION_ENDPOINT = "https://mcp.builder.io/oauth/revoke";
12
+ export const BUILDER_OAUTH_SCOPE = "builder:ai:invoke";
13
+ export const BUILDER_OAUTH_SCOPES = [BUILDER_OAUTH_SCOPE];
14
+ const BUILDER_OAUTH_KEY = "builder-general-resource-v1";
15
+ const REFRESH_SKEW_MS = 60_000;
16
+ const REFRESH_LEASE_MS = 15_000;
17
+ const REFRESH_WAIT_MS = 50;
18
+ function ownerOptions(ownerEmail) {
19
+ const scopeId = ownerEmail.trim().toLowerCase();
20
+ if (!scopeId)
21
+ throw new Error("Builder OAuth owner email is required");
22
+ return {
23
+ key: BUILDER_OAUTH_KEY,
24
+ scope: "user",
25
+ scopeId,
26
+ serverUrl: BUILDER_OAUTH_RESOURCE,
27
+ };
28
+ }
29
+ function refreshLeaseKey(ownerEmail) {
30
+ return `builder-oauth-refresh:user:${ownerOptions(ownerEmail).scopeId}`;
31
+ }
32
+ function reconnectKey(ownerEmail) {
33
+ return `builder-oauth-reconnect:user:${ownerOptions(ownerEmail).scopeId}`;
34
+ }
35
+ function discoveryState() {
36
+ return {
37
+ authorizationServerUrl: BUILDER_OAUTH_ISSUER,
38
+ authorizationServerMetadata: {
39
+ issuer: BUILDER_OAUTH_ISSUER,
40
+ authorization_endpoint: BUILDER_OAUTH_AUTHORIZATION_ENDPOINT,
41
+ token_endpoint: BUILDER_OAUTH_TOKEN_ENDPOINT,
42
+ registration_endpoint: BUILDER_OAUTH_REGISTRATION_ENDPOINT,
43
+ revocation_endpoint: BUILDER_OAUTH_REVOCATION_ENDPOINT,
44
+ // MCP SDK auth() reads these from the provided discovery blob and throws
45
+ // if they are missing — do not omit them when skipping live metadata fetch.
46
+ response_types_supported: ["code"],
47
+ grant_types_supported: ["authorization_code", "refresh_token"],
48
+ code_challenge_methods_supported: ["S256"],
49
+ },
50
+ resourceMetadataUrl: BUILDER_OAUTH_PROTECTED_RESOURCE_METADATA,
51
+ resourceMetadata: {
52
+ resource: BUILDER_OAUTH_RESOURCE,
53
+ authorization_servers: [BUILDER_OAUTH_ISSUER],
54
+ },
55
+ };
56
+ }
57
+ function scopesFrom(credentials) {
58
+ const declared = credentials.tokens.scope;
59
+ if (typeof declared !== "string")
60
+ return [...BUILDER_OAUTH_SCOPES];
61
+ return declared.split(/\s+/).filter(Boolean);
62
+ }
63
+ function resourceUrlsMatch(left, right) {
64
+ try {
65
+ return new URL(left).href === new URL(right).href;
66
+ }
67
+ catch {
68
+ return left === right;
69
+ }
70
+ }
71
+ function isBuilderDiscoveryState(value) {
72
+ if (!value || typeof value !== "object")
73
+ return false;
74
+ const discovery = value;
75
+ const authorizationServers = discovery.resourceMetadata?.authorization_servers;
76
+ const responseTypes = discovery.authorizationServerMetadata?.response_types_supported;
77
+ const grantTypes = discovery.authorizationServerMetadata?.grant_types_supported;
78
+ const challengeMethods = discovery.authorizationServerMetadata?.code_challenge_methods_supported;
79
+ const resource = typeof discovery.resourceMetadata?.resource === "string"
80
+ ? discovery.resourceMetadata.resource
81
+ : null;
82
+ return (discovery?.authorizationServerUrl === BUILDER_OAUTH_ISSUER &&
83
+ discovery.authorizationServerMetadata?.issuer === BUILDER_OAUTH_ISSUER &&
84
+ discovery.authorizationServerMetadata?.authorization_endpoint ===
85
+ BUILDER_OAUTH_AUTHORIZATION_ENDPOINT &&
86
+ discovery.authorizationServerMetadata?.token_endpoint ===
87
+ BUILDER_OAUTH_TOKEN_ENDPOINT &&
88
+ discovery.authorizationServerMetadata?.registration_endpoint ===
89
+ BUILDER_OAUTH_REGISTRATION_ENDPOINT &&
90
+ discovery.authorizationServerMetadata?.revocation_endpoint ===
91
+ BUILDER_OAUTH_REVOCATION_ENDPOINT &&
92
+ Array.isArray(responseTypes) &&
93
+ responseTypes.includes("code") &&
94
+ Array.isArray(grantTypes) &&
95
+ grantTypes.includes("authorization_code") &&
96
+ Array.isArray(challengeMethods) &&
97
+ challengeMethods.includes("S256") &&
98
+ discovery.resourceMetadataUrl ===
99
+ BUILDER_OAUTH_PROTECTED_RESOURCE_METADATA &&
100
+ !!resource &&
101
+ resourceUrlsMatch(resource, BUILDER_OAUTH_RESOURCE) &&
102
+ Array.isArray(authorizationServers) &&
103
+ authorizationServers.includes(BUILDER_OAUTH_ISSUER));
104
+ }
105
+ function isBuilderCredential(credentials) {
106
+ return (resourceUrlsMatch(credentials.serverUrl, BUILDER_OAUTH_RESOURCE) &&
107
+ credentials.clientInformation.issuer === BUILDER_OAUTH_ISSUER &&
108
+ credentials.tokens.issuer === BUILDER_OAUTH_ISSUER &&
109
+ isBuilderDiscoveryState(credentials.discoveryState));
110
+ }
111
+ function sessionFrom(credentials) {
112
+ if (!isBuilderCredential(credentials))
113
+ return null;
114
+ const accessToken = credentials.tokens.access_token;
115
+ if (typeof accessToken !== "string" || !accessToken)
116
+ return null;
117
+ return {
118
+ accessToken,
119
+ expiresAt: credentials.tokenExpiresAt,
120
+ scopes: scopesFrom(credentials),
121
+ };
122
+ }
123
+ export async function startBuilderOAuthAuthorization(input) {
124
+ ownerOptions(input.ownerEmail);
125
+ const started = await startMcpOAuthAuthorization({
126
+ serverUrl: BUILDER_OAUTH_RESOURCE,
127
+ redirectUrl: input.redirectUri,
128
+ state: input.state,
129
+ scope: BUILDER_OAUTH_SCOPE,
130
+ discoveryState: discoveryState(),
131
+ });
132
+ return {
133
+ authorizationUrl: started.authorizationUrl.toString(),
134
+ pending: {
135
+ codeVerifier: started.codeVerifier,
136
+ clientInformation: started.clientInformation,
137
+ discoveryState: started.discoveryState,
138
+ redirectUri: input.redirectUri,
139
+ },
140
+ };
141
+ }
142
+ export async function finishBuilderOAuthAuthorization(input) {
143
+ if (!isBuilderDiscoveryState(input.pending.discoveryState)) {
144
+ throw new Error("Builder OAuth pending flow has an invalid discovery binding");
145
+ }
146
+ validateMcpOAuthCallbackIssuer(input.pending.discoveryState, input.iss);
147
+ const result = await finishMcpOAuthAuthorization({
148
+ serverUrl: BUILDER_OAUTH_RESOURCE,
149
+ redirectUrl: input.pending.redirectUri,
150
+ state: "callback-state-validated-by-route",
151
+ codeVerifier: input.pending.codeVerifier,
152
+ clientInformation: input.pending.clientInformation,
153
+ discoveryState: input.pending.discoveryState,
154
+ authorizationCode: input.code,
155
+ iss: input.iss,
156
+ });
157
+ if (!isBuilderCredential(result.credentials)) {
158
+ throw new Error("Builder OAuth exchange returned credentials for another resource");
159
+ }
160
+ await saveMcpOAuthCredentials({
161
+ ...ownerOptions(input.ownerEmail),
162
+ credentials: result.credentials,
163
+ });
164
+ await putSetting(reconnectKey(input.ownerEmail), {
165
+ required: false,
166
+ at: Date.now(),
167
+ }).catch(() => {
168
+ // coercion-ok: reconnect flag clear is best-effort after a successful grant.
169
+ });
170
+ }
171
+ export async function markBuilderOAuthReconnectRequired(ownerEmail) {
172
+ await putSetting(reconnectKey(ownerEmail), {
173
+ required: true,
174
+ at: Date.now(),
175
+ });
176
+ }
177
+ export async function builderOAuthReconnectRequired(ownerEmail) {
178
+ const row = await getSetting(reconnectKey(ownerEmail));
179
+ return row?.required === true;
180
+ }
181
+ export async function getBuilderOAuthSession(ownerEmail) {
182
+ if (await builderOAuthReconnectRequired(ownerEmail))
183
+ return null;
184
+ const credentials = await readMcpOAuthCredentials(ownerOptions(ownerEmail));
185
+ if (!credentials || !isBuilderCredential(credentials))
186
+ return null;
187
+ if (typeof credentials.tokenExpiresAt === "number" &&
188
+ credentials.tokenExpiresAt - Date.now() <= REFRESH_SKEW_MS) {
189
+ return refreshBuilderOAuthSession(ownerEmail);
190
+ }
191
+ return sessionFrom(credentials);
192
+ }
193
+ export async function hasBuilderOAuthSession(ownerEmail) {
194
+ const options = ownerOptions(ownerEmail);
195
+ const stored = await getOAuthTokens("mcp", options.key, `${options.scope}:${options.scopeId}`);
196
+ return stored !== null;
197
+ }
198
+ export async function resolveBuilderOAuthRequestAccess(input) {
199
+ const session = await getBuilderOAuthSession(input.ownerEmail);
200
+ if (!session)
201
+ return null;
202
+ if (!session.scopes.includes(input.requiredScope)) {
203
+ throw new Error(`Builder OAuth connection does not grant ${input.requiredScope}`);
204
+ }
205
+ return { ...session, ownerEmail: ownerOptions(input.ownerEmail).scopeId };
206
+ }
207
+ async function refreshBuilderOAuthSession(ownerEmail) {
208
+ const owner = crypto.randomUUID();
209
+ const leaseKey = refreshLeaseKey(ownerEmail);
210
+ const lease = await mutateSetting(leaseKey, (current) => {
211
+ if (typeof current?.expiresAt !== "number" ||
212
+ current.expiresAt <= Date.now()) {
213
+ return { owner, expiresAt: Date.now() + REFRESH_LEASE_MS };
214
+ }
215
+ return current;
216
+ });
217
+ if (lease.owner !== owner)
218
+ return waitForRefreshedSession(ownerEmail);
219
+ try {
220
+ const options = ownerOptions(ownerEmail);
221
+ const accessToken = await getMcpOAuthAccessToken(options);
222
+ const next = await readMcpOAuthCredentials(options);
223
+ if (!accessToken || !next || !isBuilderCredential(next)) {
224
+ throw new Error("Builder OAuth refresh failed");
225
+ }
226
+ return sessionFrom(next);
227
+ }
228
+ catch {
229
+ await markBuilderOAuthReconnectRequired(ownerEmail);
230
+ return null;
231
+ }
232
+ finally {
233
+ await mutateSetting(leaseKey, (current) => current?.owner === owner ? { owner: "", expiresAt: 0 } : (current ?? {}));
234
+ }
235
+ }
236
+ async function waitForRefreshedSession(ownerEmail) {
237
+ for (let waited = 0; waited < REFRESH_LEASE_MS; waited += REFRESH_WAIT_MS) {
238
+ await new Promise((resolve) => setTimeout(resolve, REFRESH_WAIT_MS));
239
+ const credentials = await readMcpOAuthCredentials(ownerOptions(ownerEmail));
240
+ if (!credentials || !isBuilderCredential(credentials))
241
+ return null;
242
+ if (typeof credentials.tokenExpiresAt !== "number" ||
243
+ credentials.tokenExpiresAt - Date.now() <= REFRESH_SKEW_MS) {
244
+ continue;
245
+ }
246
+ return sessionFrom(credentials);
247
+ }
248
+ return null;
249
+ }
250
+ export async function deleteBuilderOAuthSession(ownerEmail) {
251
+ const options = ownerOptions(ownerEmail);
252
+ const result = await revokeMcpOAuthCredentials(options);
253
+ await putSetting(reconnectKey(ownerEmail), {
254
+ required: false,
255
+ at: Date.now(),
256
+ }).catch(() => {
257
+ // coercion-ok: reconnect flag clear is best-effort after local revoke.
258
+ });
259
+ return {
260
+ localDeleted: result.local === "deleted",
261
+ remoteRevoked: result.remote === "succeeded",
262
+ };
263
+ }
@@ -1,5 +1,6 @@
1
1
  import type { H3Event } from "h3";
2
2
  import { type DatabaseSchemaHealthResult } from "../db/runtime-diagnostics.js";
3
+ import { getSetting, deleteSetting, mutateSetting, listSettingsByPrefix } from "../settings/store.js";
3
4
  import { type AuthSession } from "./auth.js";
4
5
  import { type BuilderConnectTrackingParams, type BuilderRelayCredentials } from "./builder-browser.js";
5
6
  import type { EnvKeyConfig } from "./create-server.js";
@@ -162,6 +163,16 @@ export declare function buildBuilderWaitlistFormPayload(event: H3Event, sessionE
162
163
  };
163
164
  export declare const AVATAR_RASTER_MIME: RegExp;
164
165
  export declare function resolveAvatarEmailParam(pathname: string, appBasePath?: string): string;
166
+ export declare function isBuilderConnectCallbackOwner(pendingOwner: string, sessionOwner: string | undefined): boolean;
167
+ export declare function consumeBuilderConnectPendingState(state: string, dependencies?: {
168
+ mutate: typeof mutateSetting;
169
+ remove: typeof deleteSetting;
170
+ }): Promise<Record<string, unknown> | null>;
171
+ export declare function readBuilderConnectPendingState(state: string, read?: typeof getSetting): Promise<Record<string, unknown> | null>;
172
+ export declare function purgeExpiredBuilderConnectPendingStates(now?: number, dependencies?: {
173
+ list: typeof listSettingsByPrefix;
174
+ remove: typeof deleteSetting;
175
+ }): Promise<number>;
165
176
  type BuilderAnonymousOwnerResolver = (event: H3Event) => string | null | Promise<string | null>;
166
177
  export type BuilderOwnerContext = {
167
178
  email: string | undefined;