@agent-native/core 0.176.1 → 0.176.2-nightly-20260831184159

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 (1037) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/.agents/skills/frontend-design/SKILL.md +4 -0
  3. package/corpus/templates/analytics/.agents/skills/secrets/SKILL.md +47 -0
  4. package/corpus/templates/analytics/AGENTS.md +13 -2
  5. package/corpus/templates/analytics/CHANGELOG.md +8 -0
  6. package/corpus/templates/analytics/actions/certify-dashboard.ts +39 -0
  7. package/corpus/templates/analytics/actions/get-sql-dashboard.ts +1 -1
  8. package/corpus/templates/analytics/actions/list-analysis-revisions.ts +4 -2
  9. package/corpus/templates/analytics/actions/list-dashboard-revisions.ts +4 -2
  10. package/corpus/templates/analytics/actions/search-analytics-query-catalog.ts +1 -0
  11. package/corpus/templates/analytics/actions/search-dashboard-references.ts +2 -1
  12. package/corpus/templates/analytics/actions/set-workspace-feature-flag.ts +2 -2
  13. package/corpus/templates/analytics/app/components/agents/FeatureFlagsFleetPanel.tsx +16 -1
  14. package/corpus/templates/analytics/app/components/layout/Layout.tsx +58 -0
  15. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +7 -19
  16. package/corpus/templates/analytics/app/global.css +0 -7
  17. package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +1 -1
  18. package/corpus/templates/analytics/app/i18n-data.ts +42 -0
  19. package/corpus/templates/analytics/app/lib/track-metric.ts +15 -0
  20. package/corpus/templates/analytics/app/pages/NotFound.tsx +1 -1
  21. package/corpus/templates/analytics/app/pages/Placeholder.tsx +1 -1
  22. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +115 -2
  23. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/types.ts +8 -0
  24. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +23 -25
  25. package/corpus/templates/analytics/app/root.tsx +5 -5
  26. package/corpus/templates/analytics/app/routes/_index.tsx +18 -20
  27. package/corpus/templates/analytics/app/routes/dashboard.tsx +1 -1
  28. package/corpus/templates/analytics/app/routes/home.tsx +39 -0
  29. package/corpus/templates/analytics/changelog/2026-08-27-show-analytics-s-own-registered-flags-in-fleet-feature-flag-.md +6 -0
  30. package/corpus/templates/analytics/changelog/2026-08-28-analytics-loading-placeholders-now-use-a-smooth-whole-surfac.md +6 -0
  31. package/corpus/templates/analytics/changelog/2026-08-28-analytics-loading-states-use-a-softer-whole-surfac.md +6 -0
  32. package/corpus/templates/analytics/changelog/2026-08-28-analytics-sidebar-horizontal-spacing-is-tighter.md +6 -0
  33. package/corpus/templates/analytics/changelog/2026-08-28-sidebar-branding-matches-the-app-text-color-with-a-tighter-m.md +6 -0
  34. package/corpus/templates/analytics/changelog/2026-08-28-sidebar-branding-uses-a-monochrome-agent-native-mark.md +6 -0
  35. package/corpus/templates/analytics/changelog/2026-08-29-analytics-loading-shine-is-more-subtle.md +6 -0
  36. package/corpus/templates/analytics/changelog/2026-08-29-chat-edits-can-be-reverted-to-saved-checkpoints.md +6 -0
  37. package/corpus/templates/analytics/changelog/2026-08-29-dashboard-certification-lives-in-the-overflow-menu.md +6 -0
  38. package/corpus/templates/analytics/changelog/2026-08-29-public-marketing-home.md +6 -0
  39. package/corpus/templates/analytics/package.json +2 -0
  40. package/corpus/templates/analytics/public/manifest.json +1 -1
  41. package/corpus/templates/analytics/server/db/schema.ts +4 -0
  42. package/corpus/templates/analytics/server/handlers/events.ts +10 -1
  43. package/corpus/templates/analytics/server/handlers/first-party-analytics.ts +9 -1
  44. package/corpus/templates/analytics/server/handlers/session-replay.ts +10 -1
  45. package/corpus/templates/analytics/server/lib/agent-readable-resource-context.ts +22 -2
  46. package/corpus/templates/analytics/server/lib/analytics-query-catalog.ts +82 -7
  47. package/corpus/templates/analytics/server/lib/dashboard-certification.ts +58 -0
  48. package/corpus/templates/analytics/server/lib/dashboard-report.ts +1 -0
  49. package/corpus/templates/analytics/server/lib/dashboards-store.ts +429 -46
  50. package/corpus/templates/analytics/server/lib/workspace-feature-flags.ts +204 -32
  51. package/corpus/templates/analytics/server/plugins/agent-chat.ts +139 -0
  52. package/corpus/templates/analytics/server/plugins/auth.ts +1 -0
  53. package/corpus/templates/analytics/server/plugins/core-routes.ts +3 -2
  54. package/corpus/templates/analytics/server/plugins/db.ts +11 -0
  55. package/corpus/templates/assets/.agents/skills/frontend-design/SKILL.md +4 -0
  56. package/corpus/templates/assets/.agents/skills/secrets/SKILL.md +47 -0
  57. package/corpus/templates/assets/app/components/layout/Header.tsx +2 -2
  58. package/corpus/templates/assets/app/components/layout/Layout.tsx +4 -3
  59. package/corpus/templates/assets/app/components/layout/Sidebar.tsx +14 -27
  60. package/corpus/templates/assets/app/hooks/use-navigation-state.ts +2 -2
  61. package/corpus/templates/assets/app/root.tsx +29 -9
  62. package/corpus/templates/assets/app/routes/_index.tsx +15 -116
  63. package/corpus/templates/assets/app/routes/chat.$threadId.tsx +1 -1
  64. package/corpus/templates/assets/app/routes/home.tsx +137 -0
  65. package/corpus/templates/assets/app/routes/library.tsx +5 -1
  66. package/corpus/templates/assets/app/routes/settings.tsx +28 -25
  67. package/corpus/templates/assets/changelog/2026-08-26-templates-across-brand-kits.md +1 -0
  68. package/corpus/templates/assets/public/manifest.json +1 -1
  69. package/corpus/templates/assets/server/plugins/auth.ts +1 -0
  70. package/corpus/templates/brain/.agents/skills/frontend-design/SKILL.md +4 -0
  71. package/corpus/templates/brain/.agents/skills/secrets/SKILL.md +47 -0
  72. package/corpus/templates/brain/app/components/layout/Layout.tsx +3 -3
  73. package/corpus/templates/brain/app/components/layout/Sidebar.tsx +10 -23
  74. package/corpus/templates/brain/app/lib/brain.ts +2 -2
  75. package/corpus/templates/brain/app/root.tsx +13 -3
  76. package/corpus/templates/brain/app/routes/_index.tsx +15 -55
  77. package/corpus/templates/brain/app/routes/home.tsx +76 -0
  78. package/corpus/templates/brain/app/routes.ts +1 -0
  79. package/corpus/templates/brain/public/manifest.json +1 -1
  80. package/corpus/templates/brain/server/lib/brain-health.ts +2 -2
  81. package/corpus/templates/brain/server/plugins/auth.ts +1 -1
  82. package/corpus/templates/brain/server/plugins/core-routes.ts +2 -1
  83. package/corpus/templates/calendar/.agents/skills/frontend-design/SKILL.md +4 -0
  84. package/corpus/templates/calendar/.agents/skills/secrets/SKILL.md +47 -0
  85. package/corpus/templates/calendar/CHANGELOG.md +12 -0
  86. package/corpus/templates/calendar/actions/event-action-helpers.ts +2 -1
  87. package/corpus/templates/calendar/actions/manage-event-draft.ts +1 -1
  88. package/corpus/templates/calendar/actions/update-event.ts +8 -1
  89. package/corpus/templates/calendar/amplify.yml +15 -0
  90. package/corpus/templates/calendar/app/components/calendar/ApolloPanel.tsx +2 -2
  91. package/corpus/templates/calendar/app/components/calendar/CreateEventDialog.tsx +102 -109
  92. package/corpus/templates/calendar/app/components/calendar/DayView.tsx +23 -10
  93. package/corpus/templates/calendar/app/components/calendar/DeleteEventDialog.tsx +2 -11
  94. package/corpus/templates/calendar/app/components/calendar/EventAttendeesSection.tsx +150 -141
  95. package/corpus/templates/calendar/app/components/calendar/EventCard.tsx +3 -1
  96. package/corpus/templates/calendar/app/components/calendar/EventDescription.tsx +2 -2
  97. package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +359 -222
  98. package/corpus/templates/calendar/app/components/calendar/InlineEventPickers.tsx +13 -5
  99. package/corpus/templates/calendar/app/components/calendar/WeekView.tsx +21 -9
  100. package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +21 -32
  101. package/corpus/templates/calendar/app/global.css +11 -0
  102. package/corpus/templates/calendar/app/hooks/use-meeting-start-notifications.ts +10 -0
  103. package/corpus/templates/calendar/app/hooks/use-navigation-state.ts +3 -3
  104. package/corpus/templates/calendar/app/i18n-data.ts +110 -0
  105. package/corpus/templates/calendar/app/lib/calendar-timezone.ts +12 -3
  106. package/corpus/templates/calendar/app/lib/event-popover-style.ts +43 -0
  107. package/corpus/templates/calendar/app/lib/mcp-embed.ts +8 -2
  108. package/corpus/templates/calendar/app/lib/utils.ts +3 -1
  109. package/corpus/templates/calendar/app/pages/BookingPage.tsx +2 -8
  110. package/corpus/templates/calendar/app/pages/CalendarView.tsx +9 -11
  111. package/corpus/templates/calendar/app/pages/ManageBookingPage.tsx +2 -6
  112. package/corpus/templates/calendar/app/pages/NotFound.tsx +1 -1
  113. package/corpus/templates/calendar/app/pages/Settings.tsx +54 -0
  114. package/corpus/templates/calendar/app/root.tsx +9 -1
  115. package/corpus/templates/calendar/app/routes/{_app._index.tsx → _app.home.tsx} +1 -1
  116. package/corpus/templates/calendar/app/routes/_index.tsx +34 -0
  117. package/corpus/templates/calendar/app/routes/event.tsx +2 -6
  118. package/corpus/templates/calendar/changelog/2026-08-28-all-day-events-stay-in-the-compact-top-bar-in-day-and-week-v.md +6 -0
  119. package/corpus/templates/calendar/changelog/2026-08-28-calendar-organizer-note-emails-now-link-back-to-agent-native.md +6 -0
  120. package/corpus/templates/calendar/changelog/2026-08-28-calendar-shows-google-profile-photos-in-the-desktop-app.md +6 -0
  121. package/corpus/templates/calendar/changelog/2026-08-28-event-creators-can-choose-whether-a-meeting-shows-as-free-or.md +6 -0
  122. package/corpus/templates/calendar/changelog/2026-08-28-event-popovers-match-notion-calendar-s-density-a-284px-blurr.md +6 -0
  123. package/corpus/templates/calendar/changelog/2026-08-28-fixed-calendar-navigation-scheduling-permissions-and-action-.md +6 -0
  124. package/corpus/templates/calendar/changelog/2026-08-28-google-calendar-connections-use-the-registered-callback-on-m.md +6 -0
  125. package/corpus/templates/calendar/changelog/2026-08-28-sidebar-branding-matches-the-app-text-color-with-a-tighter-m.md +6 -0
  126. package/corpus/templates/calendar/changelog/2026-08-28-sidebar-branding-uses-a-monochrome-agent-native-mark.md +6 -0
  127. package/corpus/templates/calendar/changelog/2026-08-28-the-calendar-sidebar-keeps-the-settings-link-compact.md +6 -0
  128. package/corpus/templates/calendar/changelog/2026-08-28-the-calendar-sidebar-keeps-the-workspace-picker-compact.md +6 -0
  129. package/corpus/templates/calendar/changelog/2026-08-29-public-marketing-home.md +6 -0
  130. package/corpus/templates/calendar/public/manifest.json +1 -1
  131. package/corpus/templates/calendar/server/handlers/google-auth.ts +10 -2
  132. package/corpus/templates/calendar/server/lib/emails.ts +2 -1
  133. package/corpus/templates/calendar/server/lib/event-guest-notifications.ts +31 -5
  134. package/corpus/templates/calendar/server/lib/google-calendar.ts +4 -2
  135. package/corpus/templates/calendar/server/plugins/auth.ts +1 -0
  136. package/corpus/templates/calendar/server/plugins/core-routes.ts +5 -3
  137. package/corpus/templates/calendar/shared/event-permissions.ts +12 -0
  138. package/corpus/templates/chat/.agents/skills/frontend-design/SKILL.md +4 -0
  139. package/corpus/templates/chat/.agents/skills/secrets/SKILL.md +47 -0
  140. package/corpus/templates/chat/AGENTS.md +5 -4
  141. package/corpus/templates/chat/app/components/layout/Header.tsx +1 -1
  142. package/corpus/templates/chat/app/components/layout/Layout.tsx +5 -4
  143. package/corpus/templates/chat/app/components/layout/Sidebar.tsx +16 -25
  144. package/corpus/templates/chat/app/hooks/use-navigation-state.ts +5 -5
  145. package/corpus/templates/chat/app/root.tsx +16 -3
  146. package/corpus/templates/chat/app/routes/_index.tsx +17 -74
  147. package/corpus/templates/chat/app/routes/chat.$threadId.tsx +1 -1
  148. package/corpus/templates/chat/app/routes/home.tsx +94 -0
  149. package/corpus/templates/chat/netlify.toml +2 -1
  150. package/corpus/templates/chat/public/manifest.json +1 -1
  151. package/corpus/templates/chat/server/plugins/auth.ts +1 -0
  152. package/corpus/templates/clips/.agents/skills/frontend-design/SKILL.md +4 -0
  153. package/corpus/templates/clips/.agents/skills/secrets/SKILL.md +47 -0
  154. package/corpus/templates/clips/actions/add-comment.ts +18 -1
  155. package/corpus/templates/clips/actions/get-recording-player-data.ts +2 -0
  156. package/corpus/templates/clips/actions/list-comments.ts +2 -0
  157. package/corpus/templates/clips/actions/list-notifications.ts +60 -28
  158. package/corpus/templates/clips/actions/list-recording-mention-members.ts +64 -0
  159. package/corpus/templates/clips/actions/list-recordings.ts +1 -1
  160. package/corpus/templates/clips/actions/reply-to-comment.ts +17 -1
  161. package/corpus/templates/clips/actions/update-comment.ts +36 -2
  162. package/corpus/templates/clips/app/components/library/empty-state.tsx +1 -3
  163. package/corpus/templates/clips/app/components/library/library-grid.tsx +18 -6
  164. package/corpus/templates/clips/app/components/library/library-layout.tsx +6 -58
  165. package/corpus/templates/clips/app/components/library/recording-card.tsx +101 -3
  166. package/corpus/templates/clips/app/components/library/sort-menu.tsx +2 -2
  167. package/corpus/templates/clips/app/components/player/comment-composer.tsx +284 -0
  168. package/corpus/templates/clips/app/components/player/comments-panel.tsx +162 -46
  169. package/corpus/templates/clips/app/components/player/transcript-panel.tsx +38 -133
  170. package/corpus/templates/clips/app/components/player/video-player.tsx +1 -1
  171. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +99 -20
  172. package/corpus/templates/clips/app/components/recorder/recording-toolbar.tsx +110 -116
  173. package/corpus/templates/clips/app/components/recorder/storage-setup-card.tsx +83 -60
  174. package/corpus/templates/clips/app/components/settings/ai-setup-section.tsx +17 -11
  175. package/corpus/templates/clips/app/components/settings/types.ts +5 -1
  176. package/corpus/templates/clips/app/components/settings/video-storage-section.tsx +21 -12
  177. package/corpus/templates/clips/app/global.css +0 -27
  178. package/corpus/templates/clips/app/hooks/use-desktop-promo.ts +3 -17
  179. package/corpus/templates/clips/app/hooks/use-mention-members.ts +24 -0
  180. package/corpus/templates/clips/app/hooks/use-navigation-state.ts +2 -2
  181. package/corpus/templates/clips/app/i18n/en-US.ts +15 -0
  182. package/corpus/templates/clips/app/lib/recording-backup.ts +245 -0
  183. package/corpus/templates/clips/app/lib/recording-retry.ts +189 -0
  184. package/corpus/templates/clips/app/lib/recording-status.ts +32 -0
  185. package/corpus/templates/clips/app/root.tsx +11 -2
  186. package/corpus/templates/clips/app/routes/_app.home.tsx +62 -0
  187. package/corpus/templates/clips/app/routes/_app.notifications.tsx +45 -12
  188. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +2 -0
  189. package/corpus/templates/clips/app/routes/_index.tsx +11 -40
  190. package/corpus/templates/clips/app/routes/download.tsx +148 -15
  191. package/corpus/templates/clips/app/routes/embed.$shareId.tsx +4 -3
  192. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +6 -11
  193. package/corpus/templates/clips/app/routes/record.tsx +72 -13
  194. package/corpus/templates/clips/app/routes/share.$shareId.tsx +40 -24
  195. package/corpus/templates/clips/app/routes/share.meeting.$meetingId.tsx +2 -7
  196. package/corpus/templates/clips/changelog/2026-08-28-chrome-extension-download-help.md +6 -0
  197. package/corpus/templates/clips/changelog/2026-08-28-clips-loading-skeletons-use-a-softer-whole-surface.md +6 -0
  198. package/corpus/templates/clips/changelog/2026-08-28-comment-composer-no-longer-has-an-outer-border.md +6 -0
  199. package/corpus/templates/clips/changelog/2026-08-29-clips-loading-shine-is-more-subtle.md +6 -0
  200. package/corpus/templates/clips/desktop/src/app.tsx +377 -476
  201. package/corpus/templates/clips/desktop/src/components/ui/skeleton.tsx +1 -1
  202. package/corpus/templates/clips/desktop/src/components/ui/spinner.tsx +1 -17
  203. package/corpus/templates/clips/desktop/src/lib/recorder.ts +4 -0
  204. package/corpus/templates/clips/desktop/src/overlays/countdown.tsx +0 -8
  205. package/corpus/templates/clips/desktop/src/overlays/record-pill.tsx +221 -460
  206. package/corpus/templates/clips/desktop/src/styles.css +0 -40
  207. package/corpus/templates/clips/desktop/src/tailwind.css +28 -14
  208. package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +15 -11
  209. package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +9 -0
  210. package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +192 -57
  211. package/corpus/templates/clips/desktop/src-tauri/src/recording_indicator.rs +9 -3
  212. package/corpus/templates/clips/desktop/src-tauri/src/tray.rs +12 -0
  213. package/corpus/templates/clips/desktop/src-tauri/src/util.rs +97 -3
  214. package/corpus/templates/clips/public/manifest.json +1 -1
  215. package/corpus/templates/clips/server/db/schema.ts +1 -0
  216. package/corpus/templates/clips/server/lib/activity-notifications.ts +30 -5
  217. package/corpus/templates/clips/server/lib/comment-mentions.ts +23 -0
  218. package/corpus/templates/clips/server/lib/emails.ts +2 -2
  219. package/corpus/templates/clips/server/lib/recording-page-access.ts +16 -0
  220. package/corpus/templates/clips/server/lib/transactional-email-templates.ts +14 -7
  221. package/corpus/templates/clips/server/plugins/auth.ts +1 -0
  222. package/corpus/templates/clips/server/plugins/core-routes.ts +5 -0
  223. package/corpus/templates/clips/server/plugins/db.ts +5 -0
  224. package/corpus/templates/clips/server/routes/api/auth/google-calendar.get.ts +4 -2
  225. package/corpus/templates/clips/server/routes/api/clips-latest.json.get.ts +77 -22
  226. package/corpus/templates/clips/server/routes/api/public-recording.get.ts +11 -0
  227. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/interrupt.post.ts +4 -4
  228. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/resume.get.ts +1 -1
  229. package/corpus/templates/clips/shared/comment-mentions.ts +71 -0
  230. package/corpus/templates/clips/shared/prerendered-public-paths.ts +1 -1
  231. package/corpus/templates/clips/shared/recording-core.ts +5 -0
  232. package/corpus/templates/clips/shared/recording-playhead.css +207 -0
  233. package/corpus/templates/clips/shared/recording-playhead.tsx +616 -0
  234. package/corpus/templates/content/.agents/skills/frontend-design/SKILL.md +4 -0
  235. package/corpus/templates/content/.agents/skills/secrets/SKILL.md +47 -0
  236. package/corpus/templates/content/CHANGELOG.md +6 -0
  237. package/corpus/templates/content/actions/_property-utils.ts +45 -9
  238. package/corpus/templates/content/actions/edit-document.ts +17 -0
  239. package/corpus/templates/content/actions/get-document.ts +31 -11
  240. package/corpus/templates/content/actions/list-document-properties.ts +30 -2
  241. package/corpus/templates/content/actions/list-document-versions.ts +49 -17
  242. package/corpus/templates/content/actions/list-documents.ts +13 -2
  243. package/corpus/templates/content/actions/restore-document-version.ts +8 -1
  244. package/corpus/templates/content/actions/update-document.ts +8 -0
  245. package/corpus/templates/content/app/components/QueryErrorState.tsx +1 -0
  246. package/corpus/templates/content/app/components/editor/DocumentBlockFields.tsx +28 -8
  247. package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +94 -61
  248. package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +24 -10
  249. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +16 -13
  250. package/corpus/templates/content/app/components/editor/database/settings.tsx +16 -13
  251. package/corpus/templates/content/app/components/layout/Layout.tsx +35 -1
  252. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +5 -18
  253. package/corpus/templates/content/app/hooks/use-document-properties.ts +5 -3
  254. package/corpus/templates/content/app/hooks/use-documents.ts +3 -1
  255. package/corpus/templates/content/app/hooks/use-navigation-state.ts +3 -3
  256. package/corpus/templates/content/app/root.tsx +9 -4
  257. package/corpus/templates/content/app/routes/{_app._index.tsx → _app.home.tsx} +12 -4
  258. package/corpus/templates/content/app/routes/_index.tsx +33 -0
  259. package/corpus/templates/content/changelog/2026-08-26-shared-page-load-failures-now-stay-visible-and-safe.md +6 -0
  260. package/corpus/templates/content/docs/product/capabilities/content.workspace.session-restore.md +2 -2
  261. package/corpus/templates/content/e2e/playwright.config.ts +1 -1
  262. package/corpus/templates/content/package.json +2 -0
  263. package/corpus/templates/content/parity/matrix.md +1 -1
  264. package/corpus/templates/content/parity/matrix.ts +1 -1
  265. package/corpus/templates/content/public/manifest.json +1 -1
  266. package/corpus/templates/content/server/db/schema.ts +1 -0
  267. package/corpus/templates/content/server/lib/document-version-context.ts +67 -0
  268. package/corpus/templates/content/server/plugins/agent-chat.ts +155 -0
  269. package/corpus/templates/content/server/plugins/auth.ts +1 -0
  270. package/corpus/templates/content/server/plugins/core-routes.ts +3 -2
  271. package/corpus/templates/content/server/plugins/db.ts +5 -0
  272. package/corpus/templates/content/shared/api.ts +6 -4
  273. package/corpus/templates/crm/.agents/skills/frontend-design/SKILL.md +4 -0
  274. package/corpus/templates/crm/.agents/skills/secrets/SKILL.md +47 -0
  275. package/corpus/templates/crm/actions/list-crm-dashboard-revisions.ts +1 -1
  276. package/corpus/templates/crm/agent-native.app-skill.json +1 -1
  277. package/corpus/templates/crm/app/components/layout/CrmCommandMenu.tsx +1 -1
  278. package/corpus/templates/crm/app/components/layout/CrmLayout.tsx +36 -1
  279. package/corpus/templates/crm/app/components/layout/CrmSidebar.tsx +3 -3
  280. package/corpus/templates/crm/app/root.tsx +28 -7
  281. package/corpus/templates/crm/app/routes/_index.tsx +28 -18
  282. package/corpus/templates/crm/app/routes/home.tsx +27 -0
  283. package/corpus/templates/crm/app/routes/setup.tsx +2 -2
  284. package/corpus/templates/crm/app/routes.ts +1 -0
  285. package/corpus/templates/crm/public/manifest.json +1 -1
  286. package/corpus/templates/crm/server/plugins/agent-chat.ts +81 -0
  287. package/corpus/templates/crm/server/plugins/auth.ts +1 -0
  288. package/corpus/templates/crm/server/plugins/core-routes.ts +2 -1
  289. package/corpus/templates/crm/server/plugins/db.ts +7 -1
  290. package/corpus/templates/crm/shared/crm-navigation.ts +3 -2
  291. package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +13 -0
  292. package/corpus/templates/design/.agents/skills/frontend-design/SKILL.md +4 -0
  293. package/corpus/templates/design/.agents/skills/secrets/SKILL.md +47 -0
  294. package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +22 -10
  295. package/corpus/templates/design/AGENTS.md +1 -1
  296. package/corpus/templates/design/actions/add-breakpoint.ts +3 -1
  297. package/corpus/templates/design/actions/add-fusion-screens.ts +2 -0
  298. package/corpus/templates/design/actions/add-localhost-screens.ts +16 -11
  299. package/corpus/templates/design/actions/apply-a11y-fix.ts +6 -8
  300. package/corpus/templates/design/actions/apply-component-prop-edit.ts +3 -1
  301. package/corpus/templates/design/actions/apply-design-token-edit.ts +3 -1
  302. package/corpus/templates/design/actions/apply-motion-edit.ts +18 -13
  303. package/corpus/templates/design/actions/apply-shader-fill.ts +3 -1
  304. package/corpus/templates/design/actions/apply-source-edit.ts +6 -1
  305. package/corpus/templates/design/actions/apply-tweaks.ts +3 -1
  306. package/corpus/templates/design/actions/apply-visual-edit.ts +14 -9
  307. package/corpus/templates/design/actions/clone-creative-context-design.ts +6 -1
  308. package/corpus/templates/design/actions/create-component.ts +3 -1
  309. package/corpus/templates/design/actions/create-file.ts +3 -1
  310. package/corpus/templates/design/actions/delete-file.ts +3 -1
  311. package/corpus/templates/design/actions/detach-component-instance.ts +3 -1
  312. package/corpus/templates/design/actions/edit-design.ts +16 -11
  313. package/corpus/templates/design/actions/generate-design.ts +19 -14
  314. package/corpus/templates/design/actions/get-design-branch-diff.ts +26 -31
  315. package/corpus/templates/design/actions/get-design-review.ts +25 -31
  316. package/corpus/templates/design/actions/get-design-system-index-status.ts +55 -0
  317. package/corpus/templates/design/actions/get-design-system.ts +1 -1
  318. package/corpus/templates/design/actions/hydrate-figma-paste-images.ts +3 -1
  319. package/corpus/templates/design/actions/import-design-source.ts +16 -9
  320. package/corpus/templates/design/actions/import-design-tokens.ts +3 -1
  321. package/corpus/templates/design/actions/import-figma-clipboard.ts +28 -16
  322. package/corpus/templates/design/actions/import-figma-frame.ts +3 -1
  323. package/corpus/templates/design/actions/insert-asset.ts +3 -1
  324. package/corpus/templates/design/actions/insert-design-native-asset.ts +3 -1
  325. package/corpus/templates/design/actions/insert-figma-library-asset.ts +3 -1
  326. package/corpus/templates/design/actions/list-design-versions.ts +23 -0
  327. package/corpus/templates/design/actions/migrate-board-objects-to-file.ts +3 -1
  328. package/corpus/templates/design/actions/open-visual-edit.ts +23 -20
  329. package/corpus/templates/design/actions/present-design-variants.ts +7 -2
  330. package/corpus/templates/design/actions/refresh-design-system-with-builder.ts +66 -10
  331. package/corpus/templates/design/actions/remove-breakpoint.ts +3 -1
  332. package/corpus/templates/design/actions/remove-motion-timeline.ts +3 -1
  333. package/corpus/templates/design/actions/restore-design-version.ts +16 -0
  334. package/corpus/templates/design/actions/set-layout-grid.ts +94 -0
  335. package/corpus/templates/design/actions/swap-component-instance.ts +6 -1
  336. package/corpus/templates/design/actions/update-design.ts +16 -11
  337. package/corpus/templates/design/actions/update-file.ts +2 -0
  338. package/corpus/templates/design/app/components/design/DesignCanvas.tsx +25 -0
  339. package/corpus/templates/design/app/components/design/EditPanel.tsx +36 -8
  340. package/corpus/templates/design/app/components/design/LayersPanel.tsx +6 -6
  341. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +185 -29
  342. package/corpus/templates/design/app/components/design/ReviewCommentsPanel.tsx +4 -4
  343. package/corpus/templates/design/app/components/design/ReviewPanel.tsx +1 -1
  344. package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +35 -10
  345. package/corpus/templates/design/app/components/design/canvas-primitive-style.ts +16 -9
  346. package/corpus/templates/design/app/components/design/edit-panel/component-section.tsx +51 -21
  347. package/corpus/templates/design/app/components/design/edit-panel/effects-properties.tsx +18 -17
  348. package/corpus/templates/design/app/components/design/edit-panel/field-primitives.tsx +6 -1
  349. package/corpus/templates/design/app/components/design/edit-panel/frame-presets-panel.tsx +3 -3
  350. package/corpus/templates/design/app/components/design/edit-panel/layout-grid-properties.tsx +88 -0
  351. package/corpus/templates/design/app/components/design/edit-panel/panel-primitives.tsx +5 -2
  352. package/corpus/templates/design/app/components/design/edit-panel/position-layout-properties.tsx +8 -4
  353. package/corpus/templates/design/app/components/design/edit-panel/typography-helpers.ts +8 -103
  354. package/corpus/templates/design/app/components/design/edit-panel/typography-properties.tsx +68 -83
  355. package/corpus/templates/design/app/components/design/editor/MakeRealDialog.tsx +35 -10
  356. package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +29 -24
  357. package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +6 -0
  358. package/corpus/templates/design/app/components/design/inspector/GlslShaderPanel.tsx +72 -71
  359. package/corpus/templates/design/app/components/design/inspector/InspectorControlPopover.tsx +1 -1
  360. package/corpus/templates/design/app/components/design/keyboard-shortcuts.ts +9 -0
  361. package/corpus/templates/design/app/components/design/multi-screen/types.ts +8 -0
  362. package/corpus/templates/design/app/components/layout/Layout.tsx +32 -0
  363. package/corpus/templates/design/app/components/layout/Sidebar.tsx +8 -21
  364. package/corpus/templates/design/app/global.css +72 -1
  365. package/corpus/templates/design/app/hooks/use-navigation-state.ts +1 -1
  366. package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +32 -1
  367. package/corpus/templates/design/app/i18n-data.ts +116 -12
  368. package/corpus/templates/design/app/i18n-keyboard-shortcuts.ts +3 -1
  369. package/corpus/templates/design/app/lib/design-system-data.ts +36 -0
  370. package/corpus/templates/design/app/pages/DesignEditor.tsx +170 -34
  371. package/corpus/templates/design/app/pages/DesignSystems.tsx +126 -11
  372. package/corpus/templates/design/app/pages/Index.tsx +15 -7
  373. package/corpus/templates/design/app/pages/NotFound.tsx +1 -1
  374. package/corpus/templates/design/app/pages/Templates.tsx +18 -3
  375. package/corpus/templates/design/app/pages/VisualEdit.tsx +1 -1
  376. package/corpus/templates/design/app/pages/design-editor/code-layer-state.ts +3 -3
  377. package/corpus/templates/design/app/pages/design-editor/commands/README.md +1 -0
  378. package/corpus/templates/design/app/pages/design-editor/commands/geometry-commit.ts +2 -1
  379. package/corpus/templates/design/app/pages/design-editor/commands/set-layout-grid.ts +66 -0
  380. package/corpus/templates/design/app/pages/design-editor/design-data-geometry-utils.ts +5 -0
  381. package/corpus/templates/design/app/pages/design-editor/effects/publish-agent-selection-context.ts +9 -1
  382. package/corpus/templates/design/app/pages/design-editor/effects/resume-pending-generation.ts +39 -9
  383. package/corpus/templates/design/app/pages/design-editor/generation-prompt-directives.ts +31 -2
  384. package/corpus/templates/design/app/pages/design-editor/geometry-persistence.ts +26 -0
  385. package/corpus/templates/design/app/pages/design-editor/intake-question-topics.ts +335 -0
  386. package/corpus/templates/design/app/pages/design-editor/nudge-intent.ts +8 -1
  387. package/corpus/templates/design/app/root.tsx +12 -2
  388. package/corpus/templates/design/app/routes/_index.tsx +14 -1
  389. package/corpus/templates/design/app/routes/home.tsx +21 -0
  390. package/corpus/templates/design/changelog/2026-08-21-builder-design-system-imports-reconcile-after-indexing.md +1 -1
  391. package/corpus/templates/design/changelog/2026-08-28-frames-can-carry-an-8px-layout-grid-that-positions-snap-to.md +6 -0
  392. package/corpus/templates/design/changelog/2026-08-28-x-and-y-are-always-whole-numbers.md +6 -0
  393. package/corpus/templates/design/public/manifest.json +1 -1
  394. package/corpus/templates/design/server/db/schema.ts +2 -0
  395. package/corpus/templates/design/server/handlers/design-system-builder-link.ts +84 -0
  396. package/corpus/templates/design/server/lib/builder-design-system-proxy.ts +9 -1
  397. package/corpus/templates/design/server/lib/design-versions.ts +1017 -0
  398. package/corpus/templates/design/server/plugins/agent-chat.ts +144 -0
  399. package/corpus/templates/design/server/plugins/auth.ts +1 -1
  400. package/corpus/templates/design/server/plugins/core-routes.ts +3 -2
  401. package/corpus/templates/design/server/plugins/db.ts +7 -0
  402. package/corpus/templates/design/server/routes/api/design-system-builder-link.get.ts +1 -0
  403. package/corpus/templates/design/shared/canvas-math.ts +106 -14
  404. package/corpus/templates/design/shared/layout-grid.ts +80 -0
  405. package/corpus/templates/dispatch/.agents/skills/frontend-design/SKILL.md +4 -0
  406. package/corpus/templates/dispatch/.agents/skills/secrets/SKILL.md +47 -0
  407. package/corpus/templates/dispatch/AGENTS.md +11 -13
  408. package/corpus/templates/dispatch/actions/list-workspace-connections.ts +10 -5
  409. package/corpus/templates/dispatch/app/i18n-data.ts +120 -0
  410. package/corpus/templates/dispatch/app/root.tsx +11 -1
  411. package/corpus/templates/dispatch/app/routes/_index.tsx +34 -7
  412. package/corpus/templates/dispatch/app/routes/home.tsx +7 -0
  413. package/corpus/templates/dispatch/package.json +1 -0
  414. package/corpus/templates/dispatch/public/manifest.json +1 -1
  415. package/corpus/templates/factory/.agents/skills/factory-graphs/SKILL.md +11 -2
  416. package/corpus/templates/factory/.agents/skills/frontend-design/SKILL.md +4 -0
  417. package/corpus/templates/factory/.agents/skills/secrets/SKILL.md +47 -0
  418. package/corpus/templates/factory/.env.example +2 -14
  419. package/corpus/templates/factory/AGENTS.md +12 -11
  420. package/corpus/templates/factory/README.md +15 -17
  421. package/corpus/templates/factory/actions/{babysit-agent-native-pull-request.ts → babysit-factory-pull-request.ts} +125 -88
  422. package/corpus/templates/factory/actions/create-factory-automation.ts +161 -0
  423. package/corpus/templates/factory/actions/create-factory.ts +4 -124
  424. package/corpus/templates/factory/actions/delete-factory.ts +11 -23
  425. package/corpus/templates/factory/actions/{start-builder-for-item.ts → dispatch-factory-item.ts} +169 -57
  426. package/corpus/templates/factory/actions/get-slack-feedback-context.ts +30 -10
  427. package/corpus/templates/factory/actions/get-triage-config.ts +22 -0
  428. package/corpus/templates/factory/actions/get-triage-item.ts +49 -2
  429. package/corpus/templates/factory/actions/{govern-agent-native-pull-request.ts → govern-factory-pull-request.ts} +95 -112
  430. package/corpus/templates/factory/actions/ingest-github-observation.ts +9 -2
  431. package/corpus/templates/factory/actions/list-factory-audit.ts +85 -12
  432. package/corpus/templates/factory/actions/list-factory-automation-templates.ts +56 -0
  433. package/corpus/templates/factory/actions/list-factory-automations.ts +36 -3
  434. package/corpus/templates/factory/actions/list-factory-graph-versions.ts +37 -10
  435. package/corpus/templates/factory/actions/list-triage-items.ts +120 -15
  436. package/corpus/templates/factory/actions/poll-github-sources.ts +102 -58
  437. package/corpus/templates/factory/actions/poll-sentry-errors.ts +73 -36
  438. package/corpus/templates/factory/actions/poll-slack-channel.ts +112 -28
  439. package/corpus/templates/factory/actions/{babysit-pull-request.ts → propose-pr-babysit-status.ts} +9 -47
  440. package/corpus/templates/factory/actions/reconcile-triage-run.ts +1 -1
  441. package/corpus/templates/factory/actions/save-factory-automation.ts +131 -33
  442. package/corpus/templates/factory/actions/save-factory-graph.ts +31 -8
  443. package/corpus/templates/factory/actions/save-triage-config.ts +7 -27
  444. package/corpus/templates/factory/actions/save-triage-rule.ts +1 -1
  445. package/corpus/templates/factory/app/components/factory/CreateFactoryAutomationView.tsx +258 -0
  446. package/corpus/templates/factory/app/components/factory/FactoryAuditView.tsx +349 -106
  447. package/corpus/templates/factory/app/components/factory/FactoryAutomationFields.tsx +614 -0
  448. package/corpus/templates/factory/app/components/factory/FactoryInboxView.tsx +1136 -0
  449. package/corpus/templates/factory/app/components/factory/FactoryInspector.tsx +7 -14
  450. package/corpus/templates/factory/app/components/factory/FactorySettingsView.tsx +4 -223
  451. package/corpus/templates/factory/app/components/factory/NewFactoryForm.tsx +10 -205
  452. package/corpus/templates/factory/app/components/factory/SlackMrkdwn.tsx +100 -0
  453. package/corpus/templates/factory/app/components/factory/audit-filters.ts +30 -0
  454. package/corpus/templates/factory/app/components/factory/factory-automation-form.ts +120 -0
  455. package/corpus/templates/factory/app/components/factory/inbox-filters.ts +84 -0
  456. package/corpus/templates/factory/app/components/factory/inbox-source-url.ts +23 -0
  457. package/corpus/templates/factory/app/components/factory/slack-emoji.ts +165 -0
  458. package/corpus/templates/factory/app/components/factory/slack-mrkdwn.ts +128 -0
  459. package/corpus/templates/factory/app/components/layout/Header.tsx +1 -1
  460. package/corpus/templates/factory/app/components/layout/Layout.tsx +63 -6
  461. package/corpus/templates/factory/app/components/layout/Sidebar.tsx +13 -26
  462. package/corpus/templates/factory/app/components/triage/triage-status-pill.tsx +63 -14
  463. package/corpus/templates/factory/app/global.css +106 -0
  464. package/corpus/templates/factory/app/hooks/use-navigation-state.ts +16 -10
  465. package/corpus/templates/factory/app/i18n/en-US.ts +154 -7
  466. package/corpus/templates/factory/app/lib/factory-tab-params.ts +59 -0
  467. package/corpus/templates/factory/app/lib/safe-http-url.ts +8 -0
  468. package/corpus/templates/factory/app/root.tsx +16 -3
  469. package/corpus/templates/factory/app/routes/_index.tsx +27 -5
  470. package/corpus/templates/factory/app/routes/factory.tsx +325 -733
  471. package/corpus/templates/factory/app/routes/home.tsx +13 -0
  472. package/corpus/templates/factory/app/routes/new-factory.tsx +3 -5
  473. package/corpus/templates/factory/changelog/2026-08-26-inbox-full-screen-thread.md +6 -0
  474. package/corpus/templates/factory/changelog/2026-08-26-inbox-thread-and-audit-labels.md +6 -0
  475. package/corpus/templates/factory/changelog/2026-08-27-audit-run-list-stacks.md +6 -0
  476. package/corpus/templates/factory/changelog/2026-08-27-audit-run-names-wrap.md +6 -0
  477. package/corpus/templates/factory/changelog/2026-08-27-factory-opens-on-inbox.md +6 -0
  478. package/corpus/templates/factory/changelog/2026-08-27-github-repository-url.md +6 -0
  479. package/corpus/templates/factory/changelog/2026-08-27-inbox-filters.md +6 -0
  480. package/corpus/templates/factory/changelog/2026-08-27-polling-does-not-enable-automations.md +6 -0
  481. package/corpus/templates/factory/changelog/2026-08-27-pr-babysit-can-poll-github.md +6 -0
  482. package/corpus/templates/factory/changelog/2026-08-28-factory-automations-use-workspace-connections.md +6 -0
  483. package/corpus/templates/factory/changelog/2026-08-28-inbox-approve-and-start-removed.md +6 -0
  484. package/corpus/templates/factory/changelog/2026-08-28-pr-babysit-audit-shows-decisions.md +6 -0
  485. package/corpus/templates/factory/changelog/2026-08-28-pr-babysit-reviews-next-github-prs.md +6 -0
  486. package/corpus/templates/factory/changelog/2026-08-28-pr-babysit-sticky-out-of-scope.md +6 -0
  487. package/corpus/templates/factory/changelog/2026-08-28-pr-babysit-uses-github-evidence.md +6 -0
  488. package/corpus/templates/factory/changelog/2026-08-29-audit-filters-pagination-scroll.md +6 -0
  489. package/corpus/templates/factory/changelog/2026-08-29-create-factory-automations.md +6 -0
  490. package/corpus/templates/factory/changelog/2026-08-29-dispatch-reaction-argument.md +6 -0
  491. package/corpus/templates/factory/changelog/2026-08-29-factory-action-names-match-behavior.md +6 -0
  492. package/corpus/templates/factory/public/manifest.json +1 -1
  493. package/corpus/templates/factory/server/connectors/slack.ts +8 -6
  494. package/corpus/templates/factory/server/db/schema.ts +23 -0
  495. package/corpus/templates/factory/server/lib/audit-cursor.ts +44 -0
  496. package/corpus/templates/factory/server/lib/factory-action-names.ts +15 -0
  497. package/corpus/templates/factory/server/lib/factory-audit-report.ts +29 -9
  498. package/corpus/templates/factory/server/lib/factory-automation-caller.ts +38 -0
  499. package/corpus/templates/factory/server/lib/factory-automation-config.ts +543 -0
  500. package/corpus/templates/factory/server/lib/factory-automation-plan.ts +0 -48
  501. package/corpus/templates/factory/server/lib/factory-automation-repair.ts +2 -18
  502. package/corpus/templates/factory/server/lib/factory-poll-cursors.ts +98 -0
  503. package/corpus/templates/factory/server/lib/factory-scope.ts +8 -0
  504. package/corpus/templates/factory/server/lib/github-repository.ts +104 -0
  505. package/corpus/templates/factory/server/lib/inbox-cursor.ts +34 -0
  506. package/corpus/templates/factory/server/lib/pr-babysit-prompt.ts +33 -0
  507. package/corpus/templates/factory/server/lib/require-factory-automation.ts +58 -17
  508. package/corpus/templates/factory/server/lib/safe-http-url.ts +8 -0
  509. package/corpus/templates/factory/server/lib/slack-feedback-prompt.ts +19 -10
  510. package/corpus/templates/factory/server/lib/source-reaction.ts +37 -0
  511. package/corpus/templates/factory/server/plugins/agent-chat.ts +18 -22
  512. package/corpus/templates/factory/server/plugins/auth.ts +1 -0
  513. package/corpus/templates/factory/server/plugins/factory-migrations.ts +26 -0
  514. package/corpus/templates/factory/server/plugins/factory-scheduler-job.ts +277 -164
  515. package/corpus/templates/factory/server/plugins/integrations.ts +5 -7
  516. package/corpus/templates/factory/server/triage/github-client.ts +274 -3
  517. package/corpus/templates/factory/server/triage/github-ingestion.ts +3 -1
  518. package/corpus/templates/factory/server/triage/metadata.ts +12 -0
  519. package/corpus/templates/factory/server/triage/pr-babysit.ts +22 -21
  520. package/corpus/templates/factory/server/triage/review-skill-alignment.ts +11 -11
  521. package/corpus/templates/factory/server/triage/review-state.ts +39 -0
  522. package/corpus/templates/factory/server/triage/slack-client.ts +14 -6
  523. package/corpus/templates/factory/server/triage/slack-poller.ts +34 -65
  524. package/corpus/templates/factory/server/triage/slack-user-labels.ts +126 -0
  525. package/corpus/templates/forms/.agents/skills/frontend-design/SKILL.md +4 -0
  526. package/corpus/templates/forms/.agents/skills/secrets/SKILL.md +47 -0
  527. package/corpus/templates/forms/AGENTS.md +4 -3
  528. package/corpus/templates/forms/actions/response-insights.ts +4 -4
  529. package/corpus/templates/forms/actions/retry-response-deliveries.ts +26 -0
  530. package/corpus/templates/forms/app/components/layout/Sidebar.tsx +8 -33
  531. package/corpus/templates/forms/app/hooks/use-navigation-state.ts +1 -1
  532. package/corpus/templates/forms/app/lib/route-prewarm.ts +1 -1
  533. package/corpus/templates/forms/app/root.tsx +3 -2
  534. package/corpus/templates/forms/app/routes/_app.home.tsx +47 -0
  535. package/corpus/templates/forms/app/routes/_app.tsx +2 -1
  536. package/corpus/templates/forms/app/routes/_index.tsx +10 -23
  537. package/corpus/templates/forms/public/manifest.json +1 -1
  538. package/corpus/templates/forms/server/db/schema.ts +64 -17
  539. package/corpus/templates/forms/server/handlers/submissions.ts +1022 -94
  540. package/corpus/templates/forms/server/lib/integrations.ts +100 -33
  541. package/corpus/templates/forms/server/middleware/00-public-cors.ts +1 -1
  542. package/corpus/templates/forms/server/plugins/auth.ts +1 -0
  543. package/corpus/templates/forms/server/plugins/core-routes.ts +1 -0
  544. package/corpus/templates/forms/server/plugins/db.ts +40 -0
  545. package/corpus/templates/macros/.agents/skills/frontend-design/SKILL.md +4 -0
  546. package/corpus/templates/macros/.agents/skills/secrets/SKILL.md +47 -0
  547. package/corpus/templates/macros/actions/view-screen.ts +1 -1
  548. package/corpus/templates/macros/app/components/layout/AppLayout.tsx +9 -21
  549. package/corpus/templates/macros/app/components/layout/Header.tsx +1 -1
  550. package/corpus/templates/macros/app/root.tsx +22 -8
  551. package/corpus/templates/macros/app/routes/_index.tsx +16 -291
  552. package/corpus/templates/macros/app/routes/home.tsx +312 -0
  553. package/corpus/templates/macros/server/plugins/auth.ts +9 -7
  554. package/corpus/templates/macros/server/plugins/core-routes.ts +1 -0
  555. package/corpus/templates/mail/.agents/skills/frontend-design/SKILL.md +4 -0
  556. package/corpus/templates/mail/.agents/skills/inbox-automations/SKILL.md +13 -2
  557. package/corpus/templates/mail/.agents/skills/inbox-reads-and-triage/SKILL.md +1 -1
  558. package/corpus/templates/mail/.agents/skills/secrets/SKILL.md +47 -0
  559. package/corpus/templates/mail/AGENTS.md +5 -2
  560. package/corpus/templates/mail/actions/apply-ai-filter.ts +294 -0
  561. package/corpus/templates/mail/actions/create-automation.ts +1 -0
  562. package/corpus/templates/mail/actions/get-ai-filter.ts +19 -0
  563. package/corpus/templates/mail/actions/manage-automations.ts +162 -157
  564. package/corpus/templates/mail/actions/manage-email-rules.ts +3 -0
  565. package/corpus/templates/mail/actions/navigate.ts +1 -1
  566. package/corpus/templates/mail/actions/update-automation.ts +1 -0
  567. package/corpus/templates/mail/actions/update-mail-preferences.ts +1 -0
  568. package/corpus/templates/mail/app/components/email/AiFilterDialog.tsx +127 -0
  569. package/corpus/templates/mail/app/components/email/EmailList.tsx +63 -0
  570. package/corpus/templates/mail/app/components/email/EmailThread.tsx +95 -0
  571. package/corpus/templates/mail/app/components/email/MobileActionBar.tsx +35 -3
  572. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +17 -22
  573. package/corpus/templates/mail/app/components/settings/AiFilterSection.tsx +401 -0
  574. package/corpus/templates/mail/app/hooks/use-ai-filter.ts +48 -0
  575. package/corpus/templates/mail/app/hooks/use-automations.ts +1 -0
  576. package/corpus/templates/mail/app/hooks/use-emails.ts +11 -3
  577. package/corpus/templates/mail/app/i18n/en-US.ts +55 -0
  578. package/corpus/templates/mail/app/lib/automation-visibility.ts +17 -0
  579. package/corpus/templates/mail/app/pages/InboxPage.tsx +5 -2
  580. package/corpus/templates/mail/app/pages/SettingsPage.tsx +16 -8
  581. package/corpus/templates/mail/app/pages/inbox-zero.ts +1 -2
  582. package/corpus/templates/mail/app/root.tsx +20 -8
  583. package/corpus/templates/mail/app/routes/_index.tsx +16 -55
  584. package/corpus/templates/mail/app/routes/home.tsx +71 -0
  585. package/corpus/templates/mail/changelog/2026-08-28-mail-settings-show-chat-created-automations.md +6 -0
  586. package/corpus/templates/mail/public/manifest.json +1 -1
  587. package/corpus/templates/mail/server/db/schema.ts +3 -0
  588. package/corpus/templates/mail/server/handlers/emails.ts +34 -11
  589. package/corpus/templates/mail/server/handlers/google-auth.ts +1 -1
  590. package/corpus/templates/mail/server/lib/ai-filter.ts +103 -0
  591. package/corpus/templates/mail/server/lib/automation-actions.ts +14 -9
  592. package/corpus/templates/mail/server/lib/automation-engine.ts +142 -18
  593. package/corpus/templates/mail/server/lib/automations.ts +9 -0
  594. package/corpus/templates/mail/server/lib/email-state.ts +7 -2
  595. package/corpus/templates/mail/server/lib/gmail-query.ts +10 -0
  596. package/corpus/templates/mail/server/lib/google-auth.ts +5 -8
  597. package/corpus/templates/mail/server/lib/jobs.ts +1 -5
  598. package/corpus/templates/mail/server/onboarding.ts +2 -2
  599. package/corpus/templates/mail/server/plugins/agent-chat.ts +5 -2
  600. package/corpus/templates/mail/server/plugins/auth.ts +1 -0
  601. package/corpus/templates/mail/server/plugins/core-routes.ts +4 -1
  602. package/corpus/templates/mail/server/plugins/db.ts +6 -0
  603. package/corpus/templates/mail/server/routes/api/attachments.get.ts +1 -5
  604. package/corpus/templates/mail/shared/ai-filter.ts +74 -0
  605. package/corpus/templates/mail/shared/types.ts +2 -0
  606. package/corpus/templates/plan/.agents/skills/frontend-design/SKILL.md +4 -0
  607. package/corpus/templates/plan/.agents/skills/secrets/SKILL.md +47 -0
  608. package/corpus/templates/plan/actions/list-plan-versions.ts +20 -5
  609. package/corpus/templates/plan/agent-native.json +1 -4
  610. package/corpus/templates/plan/app/components/editor/PlanDocumentEditor.tsx +5 -2
  611. package/corpus/templates/plan/app/components/layout/Layout.tsx +41 -1
  612. package/corpus/templates/plan/app/components/layout/Sidebar.tsx +4 -16
  613. package/corpus/templates/plan/app/components/plan/PlanMarkdownEditor.tsx +7 -4
  614. package/corpus/templates/plan/app/components/plan/wireframe/Wireframe.tsx +1 -1
  615. package/corpus/templates/plan/app/components/plan/wireframe/html-artboard.css +15 -0
  616. package/corpus/templates/plan/app/components/plan/wireframe/kit/plan-wireframe-tokens.css +0 -15
  617. package/corpus/templates/plan/app/components/plan/wireframe/kit/primitives.tsx +2 -2
  618. package/corpus/templates/plan/app/hooks/use-plan-presence.ts +20 -10
  619. package/corpus/templates/plan/app/pages/PlansPage.tsx +2 -2
  620. package/corpus/templates/plan/app/root.tsx +13 -7
  621. package/corpus/templates/plan/app/routes/_index.tsx +31 -6
  622. package/corpus/templates/plan/app/routes/chat.tsx +3 -6
  623. package/corpus/templates/plan/app/routes/home.tsx +11 -0
  624. package/corpus/templates/plan/app/routes/local-plans.$slug.tsx +2 -6
  625. package/corpus/templates/plan/app/routes/plans.$id.tsx +3 -6
  626. package/corpus/templates/plan/app/routes/plans.tsx +3 -6
  627. package/corpus/templates/plan/app/routes/recaps.$id.tsx +3 -6
  628. package/corpus/templates/plan/app/routes/recaps.tsx +3 -6
  629. package/corpus/templates/plan/changelog/2026-08-28-plan-loading-skeletons-use-a-softer-whole-surface.md +6 -0
  630. package/corpus/templates/plan/changelog/2026-08-29-plan-loading-shine-is-more-subtle.md +6 -0
  631. package/corpus/templates/plan/public/manifest.json +1 -1
  632. package/corpus/templates/plan/server/db/schema.ts +1 -0
  633. package/corpus/templates/plan/server/lib/plan-versions.ts +57 -0
  634. package/corpus/templates/plan/server/plugins/agent-chat.ts +83 -0
  635. package/corpus/templates/plan/server/plugins/core-routes.ts +1 -0
  636. package/corpus/templates/plan/server/plugins/db.ts +10 -0
  637. package/corpus/templates/slides/.agents/skills/frontend-design/SKILL.md +4 -0
  638. package/corpus/templates/slides/.agents/skills/secrets/SKILL.md +47 -0
  639. package/corpus/templates/slides/CHANGELOG.md +9 -0
  640. package/corpus/templates/slides/actions/_deck-write.ts +65 -0
  641. package/corpus/templates/slides/actions/add-slide.ts +44 -24
  642. package/corpus/templates/slides/actions/clone-context-slide.ts +22 -12
  643. package/corpus/templates/slides/actions/create-deck.ts +36 -21
  644. package/corpus/templates/slides/actions/delete-design-system.ts +10 -3
  645. package/corpus/templates/slides/actions/import-file.ts +9 -3
  646. package/corpus/templates/slides/actions/import-pptx.ts +11 -4
  647. package/corpus/templates/slides/actions/list-deck-versions.ts +20 -8
  648. package/corpus/templates/slides/actions/patch-deck.ts +29 -3
  649. package/corpus/templates/slides/actions/restore-deck-version.ts +37 -22
  650. package/corpus/templates/slides/actions/save-deck.ts +35 -22
  651. package/corpus/templates/slides/actions/update-deck-aspect-ratio.ts +31 -16
  652. package/corpus/templates/slides/actions/update-slide.ts +250 -37
  653. package/corpus/templates/slides/app/components/deck/SlideRenderer.tsx +10 -4
  654. package/corpus/templates/slides/app/components/editor/EditorActionCluster.tsx +2 -2
  655. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +7 -8
  656. package/corpus/templates/slides/app/components/editor/ImageOverlay.tsx +78 -12
  657. package/corpus/templates/slides/app/components/editor/SlideContextToolbar.tsx +42 -4
  658. package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +381 -53
  659. package/corpus/templates/slides/app/components/editor/SlidesLayersPanel.tsx +20 -34
  660. package/corpus/templates/slides/app/components/editor/slide-style.ts +5 -0
  661. package/corpus/templates/slides/app/components/editor/style-clipboard.ts +2 -0
  662. package/corpus/templates/slides/app/components/layout/AgentWorkIndicator.tsx +18 -2
  663. package/corpus/templates/slides/app/components/layout/Header.tsx +1 -1
  664. package/corpus/templates/slides/app/components/layout/Layout.tsx +39 -10
  665. package/corpus/templates/slides/app/components/layout/Sidebar.tsx +7 -20
  666. package/corpus/templates/slides/app/components/presentation/PresenterView.tsx +35 -15
  667. package/corpus/templates/slides/app/components/presentation/present-channel.ts +12 -0
  668. package/corpus/templates/slides/app/global.css +45 -13
  669. package/corpus/templates/slides/app/hooks/use-navigation-state.ts +1 -1
  670. package/corpus/templates/slides/app/i18n/en-US.ts +11 -0
  671. package/corpus/templates/slides/app/lib/sanitize-slide-html.ts +133 -5
  672. package/corpus/templates/slides/app/lib/slide-image-replacement.ts +741 -17
  673. package/corpus/templates/slides/app/lib/validate-native-slide-html.ts +1 -0
  674. package/corpus/templates/slides/app/pages/DeckEditor.tsx +288 -95
  675. package/corpus/templates/slides/app/pages/DesignSystems.tsx +5 -5
  676. package/corpus/templates/slides/app/pages/Index.tsx +7 -7
  677. package/corpus/templates/slides/app/pages/NotFound.tsx +1 -1
  678. package/corpus/templates/slides/app/pages/SharedPresentation.tsx +1 -1
  679. package/corpus/templates/slides/app/root.tsx +4 -23
  680. package/corpus/templates/slides/app/routes/_index.tsx +18 -7
  681. package/corpus/templates/slides/app/routes/home.tsx +26 -0
  682. package/corpus/templates/slides/changelog/2026-08-27-image-fit-controls-apply-cover-crops-and-position.md +6 -0
  683. package/corpus/templates/slides/changelog/2026-08-28-image-edits-persist-while-dropped-images-finish-uploading.md +6 -0
  684. package/corpus/templates/slides/changelog/2026-08-28-shared-slides-with-a-style-block-render-again.md +6 -0
  685. package/corpus/templates/slides/changelog/2026-08-28-slides-loading-skeletons-use-a-softer-whole-surface.md +6 -0
  686. package/corpus/templates/slides/changelog/2026-08-28-standard-empty-home-layout.md +6 -0
  687. package/corpus/templates/slides/changelog/2026-08-29-chat-imports-attached-decks-on-request.md +6 -0
  688. package/corpus/templates/slides/changelog/2026-08-29-slides-loading-shine-is-more-subtle.md +6 -0
  689. package/corpus/templates/slides/package.json +3 -0
  690. package/corpus/templates/slides/public/manifest.json +1 -1
  691. package/corpus/templates/slides/server/db/schema.ts +1 -0
  692. package/corpus/templates/slides/server/handlers/google-docs-auth.ts +1 -1
  693. package/corpus/templates/slides/server/lib/chat-attachments.ts +102 -7
  694. package/corpus/templates/slides/server/lib/deck-versions.ts +77 -2
  695. package/corpus/templates/slides/server/plugins/agent-chat.ts +95 -1
  696. package/corpus/templates/slides/server/plugins/auth.ts +1 -0
  697. package/corpus/templates/slides/server/plugins/core-routes.ts +8 -1
  698. package/corpus/templates/slides/server/plugins/db.ts +5 -0
  699. package/corpus/templates/tasks/.agents/skills/frontend-design/SKILL.md +4 -0
  700. package/corpus/templates/tasks/.agents/skills/secrets/SKILL.md +47 -0
  701. package/corpus/templates/tasks/AGENTS.md +2 -1
  702. package/corpus/templates/tasks/README.md +3 -1
  703. package/corpus/templates/tasks/app/components/layout/Sidebar.tsx +5 -18
  704. package/corpus/templates/tasks/app/root.tsx +19 -3
  705. package/corpus/templates/tasks/app/routes/_index.tsx +28 -14
  706. package/corpus/templates/tasks/app/routes/home.tsx +24 -0
  707. package/corpus/templates/tasks/public/manifest.json +1 -1
  708. package/corpus/templates/tasks/server/plugins/auth.ts +1 -0
  709. package/dist/a2a/client.d.ts +4 -0
  710. package/dist/a2a/client.js +15 -2
  711. package/dist/action.d.ts +3 -1
  712. package/dist/agent/engine/ai-sdk-engine.js +13 -9
  713. package/dist/agent/engine/anthropic-engine.js +2 -1
  714. package/dist/agent/engine/builder-engine.js +23 -5
  715. package/dist/agent/engine/limit-provider-tools.d.ts +3 -0
  716. package/dist/agent/engine/limit-provider-tools.js +23 -0
  717. package/dist/agent/engine/openai-compatible-endpoint.d.ts +2 -0
  718. package/dist/agent/engine/openai-compatible-endpoint.js +4 -0
  719. package/dist/agent/engine/output-tokens.d.ts +12 -6
  720. package/dist/agent/engine/output-tokens.js +42 -16
  721. package/dist/agent/engine/registry.d.ts +1 -1
  722. package/dist/agent/engine/registry.js +69 -16
  723. package/dist/agent/production-agent.js +107 -13
  724. package/dist/agent/run-manager.d.ts +9 -0
  725. package/dist/agent/run-manager.js +35 -6
  726. package/dist/agent/thread-data-builder.d.ts +6 -1
  727. package/dist/agent/thread-data-builder.js +20 -5
  728. package/dist/agent/types.d.ts +2 -0
  729. package/dist/app-config/agent.d.ts +4 -0
  730. package/dist/app-config/agent.js +44 -0
  731. package/dist/app-config/integrations.d.ts +1 -0
  732. package/dist/app-config/integrations.js +8 -0
  733. package/dist/app-config/migration.d.ts +1 -0
  734. package/dist/app-config/migration.js +4 -0
  735. package/dist/app-config/observability.d.ts +4 -1
  736. package/dist/app-config/observability.js +25 -1
  737. package/dist/app-config/schema.d.ts +9 -0
  738. package/dist/app-config/store.js +1 -0
  739. package/dist/client/AgentAskPopover.d.ts +2 -1
  740. package/dist/client/AgentAskPopover.js +2 -2
  741. package/dist/client/AgentPanel.d.ts +35 -10
  742. package/dist/client/AgentPanel.js +136 -119
  743. package/dist/client/AssistantChat.d.ts +9 -2
  744. package/dist/client/AssistantChat.js +161 -36
  745. package/dist/client/ConnectBuilderCard.js +3 -1
  746. package/dist/client/DefaultSpinner.d.ts +13 -1
  747. package/dist/client/DefaultSpinner.js +52 -46
  748. package/dist/client/FeedbackButton.d.ts +12 -0
  749. package/dist/client/FeedbackButton.js +62 -28
  750. package/dist/client/MultiTabAssistantChat.js +30 -11
  751. package/dist/client/NewWorkspaceAppFlow.js +5 -3
  752. package/dist/client/agent-chat/index.d.ts +1 -0
  753. package/dist/client/agent-chat/index.js +1 -0
  754. package/dist/client/agent-chat-adapter.js +16 -1
  755. package/dist/client/agent-chat.d.ts +9 -0
  756. package/dist/client/agent-chat.js +6 -3
  757. package/dist/client/agent-page/AgentJobsTab.d.ts +2 -1
  758. package/dist/client/agent-page/AgentJobsTab.js +8 -5
  759. package/dist/client/agent-page/AgentTabsPage.js +2 -2
  760. package/dist/client/analytics.d.ts +2 -0
  761. package/dist/client/analytics.js +86 -15
  762. package/dist/client/app-providers.js +13 -1
  763. package/dist/client/auth/AuthPage.d.ts +87 -0
  764. package/dist/client/auth/AuthPage.js +1847 -0
  765. package/dist/client/auth/ResetPasswordPage.d.ts +9 -0
  766. package/dist/client/auth/ResetPasswordPage.js +119 -0
  767. package/dist/client/auth/entry.d.ts +1 -0
  768. package/dist/client/auth/entry.js +15 -0
  769. package/dist/client/chat/message-components.d.ts +53 -0
  770. package/dist/client/chat/message-components.js +181 -11
  771. package/dist/client/chat/run-recovery.d.ts +4 -1
  772. package/dist/client/chat/run-recovery.js +30 -12
  773. package/dist/client/chat/tool-call-display.d.ts +4 -2
  774. package/dist/client/chat/tool-call-display.js +16 -11
  775. package/dist/client/chat-first.js +8 -2
  776. package/dist/client/chat-model-groups.js +11 -1
  777. package/dist/client/collab/index.d.ts +1 -1
  778. package/dist/client/components/CodeRequiredDialog.js +22 -35
  779. package/dist/client/components/icons/AgentNativeIcon.d.ts +3 -3
  780. package/dist/client/components/icons/AgentNativeIcon.js +4 -4
  781. package/dist/client/components/ui/message-scroller.js +1 -1
  782. package/dist/client/composer/runtime-adapters.js +2 -0
  783. package/dist/client/feedback-context.d.ts +1 -0
  784. package/dist/client/feedback-context.js +3 -2
  785. package/dist/client/host-bridge.d.ts +1 -0
  786. package/dist/client/index.d.ts +2 -2
  787. package/dist/client/index.js +1 -1
  788. package/dist/client/integrations/IntegrationsPanel.d.ts +2 -1
  789. package/dist/client/integrations/IntegrationsPanel.js +3 -3
  790. package/dist/client/observability/ThumbsFeedback.js +73 -10
  791. package/dist/client/onboarding/FirstRunOnboarding.js +24 -15
  792. package/dist/client/onboarding/OnboardingPanel.js +5 -3
  793. package/dist/client/onboarding/first-run-startup-gate.js +7 -1
  794. package/dist/client/resources/McpIntegrationDialog.d.ts +2 -1
  795. package/dist/client/resources/McpIntegrationDialog.js +10 -2
  796. package/dist/client/session-replay.js +10 -0
  797. package/dist/client/settings/BuilderConnectPopover.d.ts +25 -0
  798. package/dist/client/settings/BuilderConnectPopover.js +55 -0
  799. package/dist/client/settings/SettingsPanel.js +21 -7
  800. package/dist/client/settings/SettingsTabsPage.d.ts +1 -1
  801. package/dist/client/settings/SettingsTabsPage.js +42 -25
  802. package/dist/client/settings/VoiceTranscriptionSection.js +16 -22
  803. package/dist/client/settings/index.d.ts +1 -0
  804. package/dist/client/settings/index.js +1 -0
  805. package/dist/client/settings/useBuilderStatus.d.ts +7 -0
  806. package/dist/client/settings/useBuilderStatus.js +77 -21
  807. package/dist/client/setup-connections/BuilderConnectCard.js +2 -1
  808. package/dist/client/setup-connections/useBuilderConnectCardController.d.ts +3 -1
  809. package/dist/client/setup-connections/useBuilderConnectCardController.js +4 -2
  810. package/dist/client/sse-event-processor.js +8 -0
  811. package/dist/client/terminal/AgentTerminal.js +6 -7
  812. package/dist/client/transcription/BuilderTranscriptionCta.js +17 -69
  813. package/dist/client/ui/index.d.ts +1 -0
  814. package/dist/client/ui/index.js +1 -0
  815. package/dist/client/use-chat-models.js +5 -4
  816. package/dist/client/webmcp.d.ts +4 -0
  817. package/dist/client/webmcp.js +51 -4
  818. package/dist/collab/client.d.ts +13 -0
  819. package/dist/collab/client.js +96 -21
  820. package/dist/dashboard-storage/index.d.ts +1 -1
  821. package/dist/dashboard-storage/schema.d.ts +19 -0
  822. package/dist/dashboard-storage/schema.js +1 -0
  823. package/dist/dashboard-storage/store.d.ts +9 -0
  824. package/dist/dashboard-storage/store.js +93 -3
  825. package/dist/deploy/build.d.ts +19 -3
  826. package/dist/deploy/build.js +262 -10
  827. package/dist/index.browser.d.ts +1 -1
  828. package/dist/index.browser.js +1 -1
  829. package/dist/index.d.ts +1 -1
  830. package/dist/index.js +1 -1
  831. package/dist/ingestion/media.js +7 -2
  832. package/dist/integrations/config-store.js +2 -4
  833. package/dist/integrations/google-docs-poller.d.ts +1 -1
  834. package/dist/integrations/google-docs-poller.js +100 -24
  835. package/dist/integrations/plugin.js +45 -15
  836. package/dist/integrations/webhook-handler.js +2 -1
  837. package/dist/jobs/background-automation-runner.js +17 -1
  838. package/dist/localization/core-messages/ar-SA.js +19 -0
  839. package/dist/localization/core-messages/de-DE.js +19 -0
  840. package/dist/localization/core-messages/en-US.d.ts +19 -0
  841. package/dist/localization/core-messages/en-US.js +19 -0
  842. package/dist/localization/core-messages/es-ES.js +19 -0
  843. package/dist/localization/core-messages/fr-FR.js +19 -0
  844. package/dist/localization/core-messages/hi-IN.js +19 -0
  845. package/dist/localization/core-messages/ja-JP.js +19 -0
  846. package/dist/localization/core-messages/ko-KR.js +19 -0
  847. package/dist/localization/core-messages/pt-BR.js +19 -0
  848. package/dist/localization/core-messages/zh-CN.js +19 -0
  849. package/dist/localization/core-messages/zh-TW.js +19 -0
  850. package/dist/localization/core-messages.d.ts +19 -0
  851. package/dist/localization/default-messages.d.ts +11 -0
  852. package/dist/localization/default-messages.js +11 -0
  853. package/dist/mcp/analytics.d.ts +103 -0
  854. package/dist/mcp/analytics.js +204 -0
  855. package/dist/mcp/build-server.d.ts +7 -0
  856. package/dist/mcp/build-server.js +132 -35
  857. package/dist/mcp/screen-memory-stdio.d.ts +7 -7
  858. package/dist/mcp/server.js +37 -8
  859. package/dist/mcp/stdio.js +1 -0
  860. package/dist/mcp-client/errors.js +30 -10
  861. package/dist/mcp-client/oauth-routes.d.ts +7 -2
  862. package/dist/mcp-client/oauth-routes.js +12 -3
  863. package/dist/mcp-client/routes.js +2 -1
  864. package/dist/oauth-tokens/store.js +6 -3
  865. package/dist/observability/routes.d.ts +5 -5
  866. package/dist/observability/routes.js +8 -2
  867. package/dist/observability/store.d.ts +1 -1
  868. package/dist/observability/store.js +18 -3
  869. package/dist/observability/types.d.ts +1 -0
  870. package/dist/onboarding/plugin.js +16 -4
  871. package/dist/progress/routes.d.ts +1 -1
  872. package/dist/provider-api/actions/custom-provider-registration.d.ts +16 -16
  873. package/dist/provider-api/actions/provider-api.d.ts +12 -12
  874. package/dist/resources/handlers.d.ts +2 -2
  875. package/dist/secrets/routes.d.ts +9 -9
  876. package/dist/server/action-routes.d.ts +1 -6
  877. package/dist/server/action-routes.js +61 -18
  878. package/dist/server/agent-chat/plugin-options.d.ts +8 -1
  879. package/dist/server/agent-chat-plugin.d.ts +3 -0
  880. package/dist/server/agent-chat-plugin.js +49 -4
  881. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  882. package/dist/server/agent-run-context.d.ts +1 -0
  883. package/dist/server/agent-run-context.js +6 -0
  884. package/dist/server/analytics.d.ts +3 -2
  885. package/dist/server/analytics.js +18 -7
  886. package/dist/server/app-url.d.ts +5 -2
  887. package/dist/server/app-url.js +4 -3
  888. package/dist/server/auth.d.ts +25 -0
  889. package/dist/server/auth.js +168 -21
  890. package/dist/server/better-auth-instance.js +18 -4
  891. package/dist/server/better-auth-migrations.d.ts +14 -0
  892. package/dist/server/better-auth-migrations.js +5 -1
  893. package/dist/server/builder-api-auth.js +30 -6
  894. package/dist/server/builder-browser.d.ts +10 -0
  895. package/dist/server/builder-browser.js +22 -5
  896. package/dist/server/builder-design-systems.d.ts +11 -0
  897. package/dist/server/builder-design-systems.js +52 -3
  898. package/dist/server/builder-oauth.d.ts +13 -6
  899. package/dist/server/builder-oauth.js +121 -63
  900. package/dist/server/capture-error.js +3 -0
  901. package/dist/server/cookie-namespace.d.ts +1 -0
  902. package/dist/server/cookie-namespace.js +3 -0
  903. package/dist/server/core-routes-plugin.d.ts +25 -9
  904. package/dist/server/core-routes-plugin.js +180 -76
  905. package/dist/server/credential-provider.js +22 -12
  906. package/dist/server/email.d.ts +4 -0
  907. package/dist/server/email.js +13 -5
  908. package/dist/server/framework-request-handler.js +6 -3
  909. package/dist/server/google-credential-check.d.ts +7 -3
  910. package/dist/server/google-credential-check.js +71 -0
  911. package/dist/server/google-oauth-credentials.d.ts +4 -3
  912. package/dist/server/google-oauth-credentials.js +7 -8
  913. package/dist/server/google-oauth.d.ts +9 -4
  914. package/dist/server/google-oauth.js +14 -93
  915. package/dist/server/index.d.ts +1 -1
  916. package/dist/server/index.js +1 -1
  917. package/dist/server/jwks-secret-rotation.d.ts +29 -0
  918. package/dist/server/jwks-secret-rotation.js +150 -0
  919. package/dist/server/onboarding-html.d.ts +2 -14
  920. package/dist/server/onboarding-html.js +254 -2519
  921. package/dist/server/origin-allowlist.d.ts +15 -0
  922. package/dist/server/origin-allowlist.js +93 -0
  923. package/dist/server/release-migrations.js +48 -0
  924. package/dist/server/request-context.d.ts +2 -0
  925. package/dist/server/request-context.js +7 -2
  926. package/dist/server/self-dispatch.js +5 -0
  927. package/dist/server/sentry.js +5 -0
  928. package/dist/server/ssr-handler.js +5 -0
  929. package/dist/server/transcribe-voice.d.ts +1 -1
  930. package/dist/server/workspace-provider-oauth.d.ts +9 -0
  931. package/dist/server/workspace-provider-oauth.js +96 -31
  932. package/dist/shared/index.d.ts +2 -0
  933. package/dist/shared/index.js +2 -0
  934. package/dist/shared/loading-labels.d.ts +1 -0
  935. package/dist/shared/loading-labels.js +55 -0
  936. package/dist/shared/qa-test-email.d.ts +1 -0
  937. package/dist/shared/qa-test-email.js +42 -0
  938. package/dist/shared/route-warmup-config.js +2 -2
  939. package/dist/shared/sign-in-journey.js +1 -1
  940. package/dist/shared/ssr-auth-redirect.d.ts +8 -0
  941. package/dist/shared/ssr-auth-redirect.js +56 -0
  942. package/dist/shared/test-traffic.d.ts +8 -0
  943. package/dist/shared/test-traffic.js +11 -0
  944. package/dist/styles/agent-native.css +50 -14
  945. package/dist/styles/blocks.css +0 -6
  946. package/dist/templates/chat/.agents/skills/frontend-design/SKILL.md +4 -0
  947. package/dist/templates/chat/.agents/skills/secrets/SKILL.md +47 -0
  948. package/dist/templates/chat/AGENTS.md +5 -4
  949. package/dist/templates/chat/app/components/layout/Header.tsx +1 -1
  950. package/dist/templates/chat/app/components/layout/Layout.tsx +5 -4
  951. package/dist/templates/chat/app/components/layout/Sidebar.tsx +16 -25
  952. package/dist/templates/chat/app/hooks/use-navigation-state.ts +5 -5
  953. package/dist/templates/chat/app/root.tsx +16 -3
  954. package/dist/templates/chat/app/routes/_index.tsx +17 -74
  955. package/dist/templates/chat/app/routes/chat.$threadId.tsx +1 -1
  956. package/dist/templates/chat/app/routes/home.tsx +94 -0
  957. package/dist/templates/chat/netlify.toml +2 -1
  958. package/dist/templates/chat/public/manifest.json +1 -1
  959. package/dist/templates/chat/server/plugins/auth.ts +1 -0
  960. package/dist/templates/default/.agents/skills/frontend-design/SKILL.md +4 -0
  961. package/dist/templates/default/.agents/skills/secrets/SKILL.md +47 -0
  962. package/dist/templates/default/AGENTS.md +10 -6
  963. package/dist/templates/default/DEVELOPING.md +8 -1
  964. package/dist/templates/default/app/hooks/use-navigation-state.ts +1 -1
  965. package/dist/templates/default/app/root.tsx +10 -3
  966. package/dist/templates/default/app/routes/_index.tsx +10 -86
  967. package/dist/templates/default/app/routes/home.tsx +94 -0
  968. package/dist/templates/default/app/routes/settings.tsx +1 -1
  969. package/dist/templates/default/public/manifest.json +1 -1
  970. package/dist/templates/default/server/plugins/auth.ts +5 -0
  971. package/dist/templates/headless/.agents/skills/secrets/SKILL.md +47 -0
  972. package/dist/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +4 -0
  973. package/dist/templates/workspace-core/.agents/skills/secrets/SKILL.md +47 -0
  974. package/dist/templates/workspace-root/.env.example +3 -2
  975. package/dist/terminal/pty-server.d.ts +2 -0
  976. package/dist/terminal/pty-server.js +22 -5
  977. package/dist/tracking/registry.d.ts +1 -0
  978. package/dist/tracking/registry.js +12 -0
  979. package/dist/usage/store.d.ts +1 -0
  980. package/dist/usage/store.js +16 -7
  981. package/dist/vite/client.d.ts +1 -1
  982. package/dist/vite/client.js +59 -0
  983. package/dist/workspace-connections/index.d.ts +1 -1
  984. package/dist/workspace-connections/index.js +1 -1
  985. package/dist/workspace-connections/store.d.ts +1 -0
  986. package/dist/workspace-connections/store.js +4 -0
  987. package/docs/content/aws-amplify.mdx +179 -0
  988. package/docs/content/client-agent-chat.mdx +1 -1
  989. package/docs/content/deploy-an-app.mdx +2 -1
  990. package/docs/content/deployment.mdx +14 -3
  991. package/docs/content/environment-variables.mdx +1 -0
  992. package/docs/content/template-forms-agent.mdx +65 -0
  993. package/docs/content/template-forms-developers.mdx +220 -65
  994. package/docs/content/template-forms-features.mdx +154 -0
  995. package/docs/content/template-forms-integrations.mdx +40 -0
  996. package/docs/content/template-forms.mdx +49 -36
  997. package/docs/content/template-mail-developers.mdx +3 -3
  998. package/docs/content/toolkit-settings.mdx +3 -3
  999. package/docs/content/webmcp.mdx +31 -12
  1000. package/package.json +3 -3
  1001. package/src/templates/chat/.agents/skills/frontend-design/SKILL.md +4 -0
  1002. package/src/templates/chat/.agents/skills/secrets/SKILL.md +47 -0
  1003. package/src/templates/chat/AGENTS.md +5 -4
  1004. package/src/templates/chat/app/components/layout/Header.tsx +1 -1
  1005. package/src/templates/chat/app/components/layout/Layout.tsx +5 -4
  1006. package/src/templates/chat/app/components/layout/Sidebar.tsx +16 -25
  1007. package/src/templates/chat/app/hooks/use-navigation-state.ts +5 -5
  1008. package/src/templates/chat/app/root.tsx +16 -3
  1009. package/src/templates/chat/app/routes/_index.tsx +17 -74
  1010. package/src/templates/chat/app/routes/chat.$threadId.tsx +1 -1
  1011. package/src/templates/chat/app/routes/home.tsx +94 -0
  1012. package/src/templates/chat/netlify.toml +2 -1
  1013. package/src/templates/chat/public/manifest.json +1 -1
  1014. package/src/templates/chat/server/plugins/auth.ts +1 -0
  1015. package/src/templates/default/.agents/skills/frontend-design/SKILL.md +4 -0
  1016. package/src/templates/default/.agents/skills/secrets/SKILL.md +47 -0
  1017. package/src/templates/default/AGENTS.md +10 -6
  1018. package/src/templates/default/DEVELOPING.md +8 -1
  1019. package/src/templates/default/app/hooks/use-navigation-state.ts +1 -1
  1020. package/src/templates/default/app/root.tsx +10 -3
  1021. package/src/templates/default/app/routes/_index.tsx +10 -86
  1022. package/src/templates/default/app/routes/home.tsx +94 -0
  1023. package/src/templates/default/app/routes/settings.tsx +1 -1
  1024. package/src/templates/default/public/manifest.json +1 -1
  1025. package/src/templates/default/server/plugins/auth.ts +5 -0
  1026. package/src/templates/headless/.agents/skills/secrets/SKILL.md +47 -0
  1027. package/src/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +4 -0
  1028. package/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +47 -0
  1029. package/src/templates/workspace-root/.env.example +3 -2
  1030. package/corpus/templates/factory/actions/approve-factory-item.ts +0 -244
  1031. package/corpus/templates/factory/app/components/factory/FactorySourceSettingsGroup.tsx +0 -33
  1032. package/corpus/templates/factory/server/routes/_agent-native/factory/builder-callback.post.ts +0 -116
  1033. package/corpus/templates/factory/server/triage/ai-services-git.ts +0 -205
  1034. package/corpus/templates/factory/server/triage/builder-executor.ts +0 -123
  1035. package/docs/content/template-forms-building-publishing.mdx +0 -135
  1036. package/docs/content/template-forms-responses.mdx +0 -120
  1037. /package/corpus/templates/clips/{server/lib → shared}/upload-interruption.ts +0 -0
@@ -6,16 +6,19 @@
6
6
  *
7
7
  * After first account exists, this page acts as a normal login page.
8
8
  */
9
+ import { createElement } from "react";
10
+ import { renderToString } from "react-dom/server";
9
11
  import { getAppConfig } from "../app-config/index.js";
12
+ import { AuthPage, } from "../client/auth/AuthPage.js";
13
+ import { ResetPasswordPage } from "../client/auth/ResetPasswordPage.js";
10
14
  import { getLocaleInitScript } from "../localization/server.js";
11
15
  import { DEFAULT_LOCALE, LOCALE_METADATA, LOCALE_STORAGE_KEY, SUPPORTED_LOCALES, localeDisplayName, } from "../localization/shared.js";
12
16
  import { NATIVE_AUTH_COPY } from "../shared/auth-copy.js";
13
17
  import { docsUrl } from "../shared/docs-url.js";
14
18
  import { BETA_FORCE_QUERY_PARAM, BETA_FORCE_SESSION_STORAGE_KEY, BETA_OPT_OUT_DURATION_MS, BETA_OPT_OUT_QUERY_PARAM, BETA_OPT_OUT_STORAGE_KEY, ENVIRONMENT_BETA_HOSTS, } from "../shared/environment-lanes.js";
15
19
  import { PASSWORD_MAX_LENGTH, PASSWORD_MIN_LENGTH, } from "../shared/password-policy.js";
16
- import { signInJourneyInlineScript } from "../shared/sign-in-journey.js";
17
20
  import { AGENT_NATIVE_SOCIAL_IMAGE_ALT, AGENT_NATIVE_SOCIAL_IMAGE_HEIGHT, AGENT_NATIVE_SOCIAL_IMAGE_PATH, AGENT_NATIVE_SOCIAL_IMAGE_TYPE, AGENT_NATIVE_SOCIAL_IMAGE_WIDTH, withAgentNativeSocialImageCacheBuster, } from "../shared/social-meta.js";
18
- import { normalizeAppBasePath } from "./app-base-path.js";
21
+ import { getAppBasePathFromViteEnv, normalizeAppBasePath, } from "./app-base-path.js";
19
22
  import { AUTH_MARKETING_LOCALE_COPY, } from "./auth-marketing-locales.js";
20
23
  import { BUILT_IN_AUTH_MARKETING, resolveBuiltInAuthMarketing, resolveBuiltInAuthMarketingSlug, } from "./auth-marketing.js";
21
24
  import { resolveGoogleAuthMode, } from "./google-auth-mode.js";
@@ -64,9 +67,9 @@ function workspaceBasePathFromRequest(requestPath) {
64
67
  }
65
68
  return normalizeAppBasePath(`/${firstSegment}`);
66
69
  }
67
- function withAppBasePath(path) {
70
+ function withAppBasePath(path, explicitBasePath) {
68
71
  const cleanPath = path.startsWith("/") ? path : `/${path}`;
69
- const basePath = normalizeAppBasePath(process.env.VITE_APP_BASE_PATH || process.env.APP_BASE_PATH);
72
+ const basePath = explicitBasePath ?? getAppBasePathFromViteEnv();
70
73
  return `${basePath}${cleanPath}`;
71
74
  }
72
75
  const AGENT_NATIVE_TERMS_URL = "https://www.agent-native.com/terms";
@@ -877,7 +880,6 @@ const AUTH_LOCALE_COPY = {
877
880
  googlePopupHelp: "اسمح بالنوافذ المنبثقة لهذا الموقع ثم حاول مرة أخرى",
878
881
  },
879
882
  };
880
- const defaultAuthCopy = AUTH_LOCALE_COPY[DEFAULT_LOCALE];
881
883
  function resolveBuiltInMarketingSlug(marketing, opts = {}) {
882
884
  if (!marketing)
883
885
  return undefined;
@@ -918,14 +920,47 @@ function isAgentNativeHostedHost(host) {
918
920
  const hostname = normalizeRequestHostname(host);
919
921
  return (hostname === "agent-native.com" || hostname.endsWith(".agent-native.com"));
920
922
  }
923
+ function initialAuthView(opts, authMode, googleOnly) {
924
+ if (googleOnly)
925
+ return "googleOnly";
926
+ if (authMode === "magic-link")
927
+ return "magicLink";
928
+ try {
929
+ const url = new URL(opts.requestPath ?? "/", "https://agent-native.local");
930
+ if (url.searchParams.has("verified") ||
931
+ url.searchParams.get("error") === "verification_link_invalid") {
932
+ return "login";
933
+ }
934
+ const requestedView = url.searchParams.get("tab");
935
+ if (requestedView === "login" || requestedView === "signup") {
936
+ return requestedView;
937
+ }
938
+ const pathname = url.pathname.replace(/\/+$/, "") || "/";
939
+ if (pathname.endsWith("/login"))
940
+ return "login";
941
+ if (pathname.endsWith("/signup"))
942
+ return "signup";
943
+ }
944
+ catch (error) {
945
+ // coercion-ok: malformed paths use the public signup state; no session data is inferred.
946
+ void error;
947
+ }
948
+ return "signup";
949
+ }
950
+ function serializeAuthPageData(value) {
951
+ return JSON.stringify(value)
952
+ .replaceAll("&", "\\u0026")
953
+ .replaceAll("<", "\\u003c")
954
+ .replaceAll(">", "\\u003e")
955
+ .replaceAll("\u2028", "\\u2028")
956
+ .replaceAll("\u2029", "\\u2029");
957
+ }
921
958
  export function getOnboardingHtml(opts = {}) {
922
959
  const showGoogle = hasGoogleOAuth();
923
960
  const googleOnly = !!opts.googleOnly;
924
961
  const authMode = opts.authMode ?? "password";
925
- const magicLinkMode = authMode === "magic-link";
926
962
  const simplifiedAuth = opts.initialPrompt === true;
927
- const renderGoogleButton = showGoogle;
928
- const configuredAppBasePath = normalizeAppBasePath(process.env.VITE_APP_BASE_PATH || process.env.APP_BASE_PATH);
963
+ const configuredAppBasePath = getAppBasePathFromViteEnv();
929
964
  const appBasePath = configuredAppBasePath || workspaceBasePathFromRequest(opts.requestPath);
930
965
  const workspaceRuntime = isWorkspaceRuntime();
931
966
  const trackingApp = getAppConfig().app.slug ??
@@ -957,13 +992,6 @@ export function getOnboardingHtml(opts = {}) {
957
992
  requestHost: opts.requestHost,
958
993
  requestPath: opts.requestPath,
959
994
  });
960
- const defaultMarketingCopy = marketing
961
- ? {
962
- tagline: marketing.tagline,
963
- description: marketing.description,
964
- features: marketing.features,
965
- }
966
- : undefined;
967
995
  const localizedMarketingCopy = {};
968
996
  if (marketingSlug) {
969
997
  for (const [locale, copyBySlug] of Object.entries(AUTH_MARKETING_LOCALE_COPY)) {
@@ -979,65 +1007,11 @@ export function getOnboardingHtml(opts = {}) {
979
1007
  command: marketing.signupLocalModeNote.command.trim(),
980
1008
  }
981
1009
  : undefined;
982
- const brandMarkSrc = withAppBasePath("/agent-native-icon-dark.svg");
1010
+ const brandMarkSrc = withAppBasePath("/agent-native-icon-dark.svg", appBasePath);
983
1011
  const socialImageUrl = withAgentNativeSocialImageCacheBuster(opts.requestOrigin
984
- ? `${opts.requestOrigin}${withAppBasePath(AGENT_NATIVE_SOCIAL_IMAGE_PATH)}`
985
- : withAppBasePath(AGENT_NATIVE_SOCIAL_IMAGE_PATH));
986
- const esc = (s) => s
987
- .replace(/&/g, "&amp;")
988
- .replace(/</g, "&lt;")
989
- .replace(/>/g, "&gt;")
990
- .replace(/"/g, "&quot;");
991
- const t = (key) => defaultAuthCopy[key];
992
- const i18nAttr = (key) => key ? ` data-i18n="${key}"` : "";
993
- const googleUnavailableHtml = googleOnly && !showGoogle
994
- ? `<p class="google-error show" id="google-err" role="status"${i18nAttr("googleNotConfigured")}>${esc(t("googleNotConfigured"))}</p>`
995
- : "";
996
- const i18nAriaAttr = (key) => key ? ` data-i18n-aria-label="${key}"` : "";
997
- const i18nPlaceholderAttr = (key) => key ? ` data-i18n-placeholder="${key}"` : "";
998
- const i18nDataAttr = (attr, key) => (key ? ` data-i18n-${attr}="${key}"` : "");
999
- const i18nText = (key) => `<span${i18nAttr(key)}>${esc(t(key))}</span>`;
1000
- const localizedValue = (value, key) => (value === undefined ? i18nText(key) : esc(value));
1001
- const localizedAnchorLabel = (value, key) => value === undefined ? `${i18nAttr(key)}>${esc(t(key))}` : `>${esc(value)}`;
1002
- const localeMenuItemsHtml = [
1003
- ` <button type="button" class="locale-menu-item" role="menuitemradio" aria-checked="false" data-locale-value="system">
1004
- <span class="locale-menu-check" aria-hidden="true">✓</span>
1005
- <span data-system-language>${esc(t("systemLanguage"))}</span>
1006
- </button>`,
1007
- ...SUPPORTED_LOCALES.map((locale) => {
1008
- const label = localeDisplayName(locale);
1009
- return ` <button type="button" class="locale-menu-item" role="menuitemradio" aria-checked="false" data-locale-value="${esc(locale)}">
1010
- <span class="locale-menu-check" aria-hidden="true">✓</span>
1011
- <span>${esc(label)}</span>
1012
- </button>`;
1013
- }),
1014
- ].join("\n");
1015
- const localePickerHtml = `
1016
- <div class="locale-picker">
1017
- <button type="button" class="locale-trigger" id="auth-locale-trigger" aria-haspopup="menu" aria-expanded="false" aria-controls="auth-locale-menu" aria-label="${esc(t("languageLabel"))}" title="${esc(t("languageLabel"))}"${i18nAriaAttr("languageLabel")} data-i18n-title="languageLabel">
1018
- <svg viewBox="0 0 24 24" aria-hidden="true">
1019
- <path d="M4 5h7" />
1020
- <path d="M7.5 4v1" />
1021
- <path d="M9.5 5c-.8 4.4-2.6 7.2-5.5 9" />
1022
- <path d="M5 9c1.2 2.1 3.2 3.8 6 5" />
1023
- <path d="M13 20l4-9 4 9" />
1024
- <path d="M14.5 17h5" />
1025
- </svg>
1026
- </button>
1027
- <div class="locale-menu" id="auth-locale-menu" role="menu" aria-labelledby="auth-locale-trigger" hidden>
1028
- ${localeMenuItemsHtml}
1029
- </div>
1030
- </div>`;
1031
- const environmentBadgeHtml = `
1032
- <div class="environment-switcher" id="environment-switcher" hidden>
1033
- <button type="button" class="environment-badge" id="environment-badge" aria-expanded="false" aria-controls="environment-popover">beta</button>
1034
- <div class="environment-popover" id="environment-popover" role="dialog" aria-labelledby="environment-popover-title" hidden>
1035
- <div class="environment-popover-title" id="environment-popover-title">You're on Agent-Native Beta</div>
1036
- <div class="environment-popover-copy">Choose where you want to continue.</div>
1037
- <a class="environment-production-link" id="environment-production-link" href="">Switch to production</a>
1038
- <button type="button" class="environment-hide-badge" id="environment-hide-badge">Hide badge</button>
1039
- </div>
1040
- </div>`;
1012
+ ? `${opts.requestOrigin}${withAppBasePath(AGENT_NATIVE_SOCIAL_IMAGE_PATH, appBasePath)}`
1013
+ : withAppBasePath(AGENT_NATIVE_SOCIAL_IMAGE_PATH, appBasePath));
1014
+ const t = (key) => EN_AUTH_COPY[key];
1041
1015
  const hostedSignupLegalNotice = opts.signupLegalNotice === undefined &&
1042
1016
  isAgentNativeHostedHost(opts.requestHost)
1043
1017
  ? {
@@ -1048,59 +1022,13 @@ ${localeMenuItemsHtml}
1048
1022
  const signupLegalNotice = opts.signupLegalNotice === false
1049
1023
  ? undefined
1050
1024
  : (opts.signupLegalNotice ?? hostedSignupLegalNotice);
1051
- const signupLegalNoteHtml = signupLegalNotice
1052
- ? ` <p class="legal-note">${localizedValue(signupLegalNotice.prefix, "legalPrefix")} <a href="${esc(signupLegalNotice.termsUrl)}" target="_blank" rel="noreferrer"${localizedAnchorLabel(signupLegalNotice.termsLabel, "legalTerms")}</a> ${localizedValue(signupLegalNotice.connector, "legalConnector")} <a href="${esc(signupLegalNotice.privacyUrl)}" target="_blank" rel="noreferrer"${localizedAnchorLabel(signupLegalNotice.privacyLabel, "legalPrivacy")}</a>${localizedValue(signupLegalNotice.suffix, "legalSuffix")}</p>`
1053
- : "";
1054
- const magicLinkSuccessHtml = magicLinkMode
1055
- ? ` <div class="magic-link-success" id="magic-link-success" aria-live="polite" hidden>
1056
- <p class="magic-link-success-copy"><span${i18nAttr("magicLinkSentCopy")}>${esc(t("magicLinkSentCopy"))}</span> <strong id="magic-link-success-email"></strong>.</p>
1057
- <button type="button" class="link-button magic-link-back" id="magic-link-back"${i18nAttr("back")}>${esc(t("back"))}</button>
1058
- </div>
1059
- `
1060
- : "";
1061
- const signupLocalModeNoteHtml = signupLocalModeNote
1062
- ? ` <div class="signup-local-mode-note" id="signup-local-mode-note" data-command="${esc(signupLocalModeNote.command)}">
1063
- <p>${esc(signupLocalModeNote.text)}</p>
1064
- <code>${esc(signupLocalModeNote.command)}</code>
1065
- <button type="button" class="copy-run-local" id="copy-signup-local-mode" onclick="__anCopySignupLocalModeCommand()"${i18nAttr("copyCommand")}>${esc(t("copyCommand"))}</button>
1066
- </div>`
1067
- : "";
1068
- const identitySsoHtml = identitySsoLoginButtonHtml();
1069
- const embeddedAuthCss = identitySsoHtml
1025
+ const identitySsoEnabled = Boolean(identitySsoLoginButtonHtml());
1026
+ const embeddedAuthCss = identitySsoEnabled
1070
1027
  ? ' html[data-agent-native-embedded="1"] #identity-sso-btn { display: none !important; }\n'
1071
1028
  : "";
1072
- const localDevHtml = `
1073
- <div class="local-dev-signin" id="local-dev-signin" hidden>
1074
- <button type="button" class="btn-local-dev btn-primary" id="local-dev-btn" title="${esc(t("localDevDescription"))}"${i18nAttr("localDevButton")} data-i18n-title="localDevDescription" aria-describedby="local-dev-description">${esc(t("localDevButton"))}</button>
1075
- <p class="local-dev-description" id="local-dev-description">
1076
- <span${i18nAttr("localDevDescription")}>${esc(t("localDevDescription"))}</span>
1077
- <a class="local-dev-help" id="local-dev-help" href="${docsUrl("authentication", { hash: "local-development-sign-in" })}" target="_blank" rel="noreferrer" aria-label="${esc(t("localDevHelp"))}" title="${esc(t("localDevHelp"))}" data-i18n-title="localDevHelp"${i18nAriaAttr("localDevHelp")}><span class="local-dev-help-glyph" aria-hidden="true">?</span></a>
1078
- </p>
1079
- <button type="button" class="local-dev-full-options" id="local-dev-full-options" hidden${i18nAttr("localDevFullOptions")}>${esc(t("localDevFullOptions"))}</button>
1080
- <p class="msg error" id="local-dev-msg" role="status" aria-live="polite"></p>
1081
- </div>`;
1082
- const identitySsoMagicLinkSelector = identitySsoHtml
1029
+ const identitySsoMagicLinkSelector = identitySsoEnabled
1083
1030
  ? " .card.magic-link-complete #identity-sso-btn,\n"
1084
1031
  : "";
1085
- const identitySsoScript = identitySsoHtml
1086
- ? `
1087
- function __anIdentitySsoUrl() {
1088
- var params = new URLSearchParams();
1089
- params.set('return', __anResumeHref());
1090
- return __anPath('/_agent-native/identity/login') + '?' + params.toString();
1091
- }
1092
- function __anStartIdentitySso(event) {
1093
- if (event && event.preventDefault) event.preventDefault();
1094
- window.location.href = __anIdentitySsoUrl();
1095
- return false;
1096
- }
1097
- (function __anPrepareIdentitySsoButton() {
1098
- var identity = document.getElementById('identity-sso-btn');
1099
- if (!identity) return;
1100
- identity.setAttribute('href', __anIdentitySsoUrl());
1101
- identity.addEventListener('click', __anStartIdentitySso);
1102
- })();`
1103
- : "";
1104
1032
  const marketingStyles = hasMarketing
1105
1033
  ? `
1106
1034
  body.has-marketing { padding: 0; position: relative; overflow-x: hidden; }
@@ -1237,306 +1165,59 @@ ${localeMenuItemsHtml}
1237
1165
  }
1238
1166
  `
1239
1167
  : "";
1240
- const marketingPanelHtml = hasMarketing
1241
- ? `<canvas id="starfield"></canvas>
1242
- <div class="split">
1243
- <div class="marketing-panel">
1244
- <div class="marketing-content">
1245
- <h2 class="app-name">
1246
- <img class="brand-mark" src="${esc(brandMarkSrc)}" alt="" aria-hidden="true" />
1247
- <span>${esc(marketing.appName)}</span>
1248
- </h2>
1249
- <p class="app-tagline" data-marketing-field="tagline">${esc(marketing.tagline)}</p>
1250
- ${marketing.description ? ` <p class="app-desc" data-marketing-field="description">${esc(marketing.description)}</p>\n` : ""}${marketing.features?.length
1251
- ? ` <ul class="feature-list">\n${marketing.features.map((f, index) => ` <li data-marketing-feature-index="${index}">${esc(f)}</li>`).join("\n")}\n </ul>\n`
1252
- : ""} <div class="marketing-actions">
1253
- <a class="oss-link" href="https://github.com/BuilderIO/agent-native" target="_blank" rel="noreferrer">
1254
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-4.3 1.4-4.3-2.5-6-3m12 5v-3.5c0-1 .1-1.4-.5-2 2.8-.3 5.5-1.4 5.5-6a4.6 4.6 0 00-1.3-3.2 4.2 4.2 0 00-.1-3.2s-1.1-.3-3.5 1.3a12.3 12.3 0 00-6.2 0C6.5 2.8 5.4 3.1 5.4 3.1a4.2 4.2 0 00-.1 3.2A4.6 4.6 0 004 9.5c0 4.6 2.7 5.7 5.5 6-.6.6-.6 1.2-.5 2V21"/></svg>
1255
- <span${i18nAttr("openSource")}>${esc(t("openSource"))}</span>
1256
- </a>
1257
- </div>
1258
- </div>
1259
- </div>
1260
- <div class="form-panel">`
1261
- : "";
1262
- const marketingCloseHtml = hasMarketing ? `\n </div>\n</div>` : "";
1263
- const starfieldScript = hasMarketing
1264
- ? `
1265
- (function initStarfield() {
1266
- var canvas = document.getElementById('starfield');
1267
- if (!canvas) return;
1268
- var gl = canvas.getContext('webgl', { alpha: false, antialias: false });
1269
- if (!gl) return;
1270
-
1271
- var vs = gl.createShader(gl.VERTEX_SHADER);
1272
- gl.shaderSource(vs, 'attribute vec2 position;void main(){gl_Position=vec4(position,0.0,1.0);}');
1273
- gl.compileShader(vs);
1274
-
1275
- var fs = gl.createShader(gl.FRAGMENT_SHADER);
1276
- gl.shaderSource(fs, [
1277
- 'precision highp float;',
1278
- 'uniform float iTime;uniform vec2 iResolution;uniform vec3 uPointer;',
1279
- '#define S(a,b,t) smoothstep(a,b,t)',
1280
- '#define NUM_LAYERS 4.',
1281
- 'float N21(vec2 p){vec3 a=fract(vec3(p.xyx)*vec3(213.897,653.453,253.098));a+=dot(a,a.yzx+79.76);return fract((a.x+a.y)*a.z);}',
1282
- 'vec2 GetPos(vec2 id,vec2 offs,float t){float n=N21(id+offs);float n1=fract(n*10.);float n2=fract(n*100.);float a=t+n;return offs+vec2(sin(a*n1),cos(a*n2))*.4;}',
1283
- 'vec2 Attract(vec2 p,vec2 cursor,float strength){vec2 delta=cursor-p;float d=length(delta);float pull=1.-smoothstep(.08,1.9,d);pull=pull*pull*(3.-2.*pull);return p+delta*pull*.095*strength;}',
1284
- 'float df_line(vec2 a,vec2 b,vec2 p){vec2 pa=p-a,ba=b-a;float h=clamp(dot(pa,ba)/dot(ba,ba),0.,1.);return length(pa-ba*h);}',
1285
- 'float line(vec2 a,vec2 b,vec2 uv){float r1=.025;float r2=.006;float d=df_line(a,b,uv);float d2=length(a-b);float fade=S(1.5,.5,d2);fade+=S(.05,.02,abs(d2-.75));return S(r1,r2,d)*fade;}',
1286
- 'float NetLayer(vec2 st,float n,float t,vec2 pointer,float pointerStrength){',
1287
- ' vec2 cell=floor(st);vec2 id=cell+n;vec2 cursor=pointer-cell;st=fract(st)-.5;',
1288
- ' vec2 p0=Attract(GetPos(id,vec2(-1,-1),t),cursor,pointerStrength);vec2 p1=Attract(GetPos(id,vec2(0,-1),t),cursor,pointerStrength);vec2 p2=Attract(GetPos(id,vec2(1,-1),t),cursor,pointerStrength);',
1289
- ' vec2 p3=Attract(GetPos(id,vec2(-1,0),t),cursor,pointerStrength);vec2 p4=Attract(GetPos(id,vec2(0,0),t),cursor,pointerStrength);vec2 p5=Attract(GetPos(id,vec2(1,0),t),cursor,pointerStrength);',
1290
- ' vec2 p6=Attract(GetPos(id,vec2(-1,1),t),cursor,pointerStrength);vec2 p7=Attract(GetPos(id,vec2(0,1),t),cursor,pointerStrength);vec2 p8=Attract(GetPos(id,vec2(1,1),t),cursor,pointerStrength);',
1291
- ' float m=0.;float sparkle=0.;float d;float s;float pulse;',
1292
- ' m+=line(p4,p0,st);d=length(st-p0);s=(.005/(d*d));s*=S(1.,.7,d);pulse=sin((fract(p0.x)+fract(p0.y)+t)*5.)*.4+.6;pulse=pow(pulse,20.);sparkle+=s*pulse;',
1293
- ' m+=line(p4,p1,st);d=length(st-p1);s=(.005/(d*d));s*=S(1.,.7,d);pulse=sin((fract(p1.x)+fract(p1.y)+t)*5.)*.4+.6;pulse=pow(pulse,20.);sparkle+=s*pulse;',
1294
- ' m+=line(p4,p2,st);d=length(st-p2);s=(.005/(d*d));s*=S(1.,.7,d);pulse=sin((fract(p2.x)+fract(p2.y)+t)*5.)*.4+.6;pulse=pow(pulse,20.);sparkle+=s*pulse;',
1295
- ' m+=line(p4,p3,st);d=length(st-p3);s=(.005/(d*d));s*=S(1.,.7,d);pulse=sin((fract(p3.x)+fract(p3.y)+t)*5.)*.4+.6;pulse=pow(pulse,20.);sparkle+=s*pulse;',
1296
- ' m+=line(p4,p4,st);d=length(st-p4);s=(.005/(d*d));s*=S(1.,.7,d);pulse=sin((fract(p4.x)+fract(p4.y)+t)*5.)*.4+.6;pulse=pow(pulse,20.);sparkle+=s*pulse;',
1297
- ' m+=line(p4,p5,st);d=length(st-p5);s=(.005/(d*d));s*=S(1.,.7,d);pulse=sin((fract(p5.x)+fract(p5.y)+t)*5.)*.4+.6;pulse=pow(pulse,20.);sparkle+=s*pulse;',
1298
- ' m+=line(p4,p6,st);d=length(st-p6);s=(.005/(d*d));s*=S(1.,.7,d);pulse=sin((fract(p6.x)+fract(p6.y)+t)*5.)*.4+.6;pulse=pow(pulse,20.);sparkle+=s*pulse;',
1299
- ' m+=line(p4,p7,st);d=length(st-p7);s=(.005/(d*d));s*=S(1.,.7,d);pulse=sin((fract(p7.x)+fract(p7.y)+t)*5.)*.4+.6;pulse=pow(pulse,20.);sparkle+=s*pulse;',
1300
- ' m+=line(p4,p8,st);d=length(st-p8);s=(.005/(d*d));s*=S(1.,.7,d);pulse=sin((fract(p8.x)+fract(p8.y)+t)*5.)*.4+.6;pulse=pow(pulse,20.);sparkle+=s*pulse;',
1301
- ' m+=line(p1,p3,st);m+=line(p1,p5,st);m+=line(p7,p5,st);m+=line(p7,p3,st);',
1302
- ' float sPhase=(sin(t+n)+sin(t*.1))*.25+.5;sPhase+=pow(sin(t*.1)*.5+.5,50.)*5.;m+=sparkle*sPhase;',
1303
- ' return m;',
1304
- '}',
1305
- 'void mainImage(out vec4 fragColor,in vec2 fragCoord){',
1306
- ' vec2 uv=(fragCoord-iResolution.xy*.5)/iResolution.y;',
1307
- ' float t=iTime*.03;float s=sin(t);float c=cos(t);mat2 rot=mat2(c,-s,s,c);vec2 st=uv*rot;vec2 pointerUv=(uPointer.xy-iResolution.xy*.5)/iResolution.y;',
1308
- ' float m=0.;',
1309
- ' for(float i=0.;i<1.;i+=1./NUM_LAYERS){float z=fract(t+i);float size=mix(15.,1.,z);float fade=S(0.,.6,z)*S(1.,.8,z);vec2 pointerSt=pointerUv*rot*size;vec2 layerSt=st*size;float warp=1.-smoothstep(.15,2.7,length(layerSt-pointerSt));warp=warp*warp*(3.-2.*warp)*uPointer.z;layerSt-=(pointerSt-layerSt)*warp*.035;m+=fade*NetLayer(layerSt,i,iTime*0.3,pointerSt,uPointer.z);}',
1310
- ' float cursorLift=1.-smoothstep(.04,.48,length(uv-pointerUv));cursorLift=cursorLift*cursorLift*(3.-2.*cursorLift)*uPointer.z;m*=1.+cursorLift*1.6;',
1311
- ' vec3 col=vec3(0.35)*m;col*=1.-dot(uv,uv);',
1312
- ' float tt=min(iTime,5.0);col*=S(0.,20.,tt);',
1313
- ' col=clamp(col,0.,1.);fragColor=vec4(col,1.);',
1314
- '}',
1315
- 'void main(){mainImage(gl_FragColor,gl_FragCoord.xy);}'
1316
- ].join('\\n'));
1317
- gl.compileShader(fs);
1318
-
1319
- var prog = gl.createProgram();
1320
- gl.attachShader(prog, vs);
1321
- gl.attachShader(prog, fs);
1322
- gl.linkProgram(prog);
1323
- gl.useProgram(prog);
1324
-
1325
- var buf = gl.createBuffer();
1326
- gl.bindBuffer(gl.ARRAY_BUFFER, buf);
1327
- gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1,1,-1,-1,1,-1,1,1,-1,1,1]), gl.STATIC_DRAW);
1328
- var pos = gl.getAttribLocation(prog, 'position');
1329
- gl.enableVertexAttribArray(pos);
1330
- gl.vertexAttribPointer(pos, 2, gl.FLOAT, false, 0, 0);
1331
-
1332
- var uTime = gl.getUniformLocation(prog, 'iTime');
1333
- var uRes = gl.getUniformLocation(prog, 'iResolution');
1334
- var uPointer = gl.getUniformLocation(prog, 'uPointer');
1335
- var reducedMotionQuery = window.matchMedia ? window.matchMedia('(prefers-reduced-motion: reduce)') : null;
1336
- var reducedMotion = reducedMotionQuery ? reducedMotionQuery.matches : false;
1337
- var pointerDpr = 1, hasPointer = false;
1338
- var pointerX = 0, pointerY = 0, pointerStrength = 0;
1339
- var targetX = 0, targetY = 0, targetStrength = 0;
1340
-
1341
- function resize() {
1342
- var w = window.innerWidth, h = window.innerHeight;
1343
- pointerDpr = Math.min(window.devicePixelRatio, 1.5);
1344
- canvas.width = w * pointerDpr; canvas.height = h * pointerDpr;
1345
- gl.viewport(0, 0, canvas.width, canvas.height);
1346
- if (!hasPointer) {
1347
- pointerX = targetX = canvas.width * 0.5;
1348
- pointerY = targetY = canvas.height * 0.5;
1349
- }
1350
- }
1351
- function onPointerMove(event) {
1352
- var rect = canvas.getBoundingClientRect();
1353
- var x = event.clientX - rect.left;
1354
- var y = event.clientY - rect.top;
1355
- hasPointer = true;
1356
- targetX = x * pointerDpr;
1357
- targetY = (rect.height - y) * pointerDpr;
1358
- targetStrength = x >= 0 && x <= rect.width && y >= 0 && y <= rect.height ? 1 : 0;
1359
- }
1360
- function fadePointer() {
1361
- targetStrength = 0;
1362
- }
1363
- function easePointer(allowPointer) {
1364
- if (!allowPointer) {
1365
- pointerStrength = 0;
1366
- return;
1367
- }
1368
- pointerX += (targetX - pointerX) * 0.22;
1369
- pointerY += (targetY - pointerY) * 0.22;
1370
- pointerStrength += (targetStrength - pointerStrength) * 0.14;
1371
- if (pointerStrength < 0.001 && targetStrength === 0) pointerStrength = 0;
1372
- }
1373
- resize();
1374
- window.addEventListener('resize', resize);
1375
- window.addEventListener('pointermove', onPointerMove, { passive: true });
1376
- window.addEventListener('mousemove', onPointerMove, { passive: true });
1377
- document.addEventListener('pointerleave', fadePointer, { passive: true });
1378
- window.addEventListener('blur', fadePointer);
1379
-
1380
- var start = performance.now(), last = 0, raf = 0, reducedMotionStaticTime = 20;
1381
- function draw(timeSeconds, allowPointer) {
1382
- easePointer(allowPointer !== false && !reducedMotion);
1383
- gl.uniform1f(uTime, timeSeconds);
1384
- gl.uniform2f(uRes, canvas.width, canvas.height);
1385
- gl.uniform3f(uPointer, pointerX, pointerY, pointerStrength);
1386
- gl.drawArrays(gl.TRIANGLES, 0, 6);
1387
- }
1388
- function render(now) {
1389
- if (reducedMotion) {
1390
- raf = 0;
1391
- return;
1392
- }
1393
- raf = requestAnimationFrame(render);
1394
- if (now - last < 33) return;
1395
- last = now;
1396
- draw((now - start) * 0.001);
1397
- }
1398
- function startAnimation() {
1399
- if (!raf) raf = requestAnimationFrame(render);
1400
- }
1401
- function stopAnimation() {
1402
- if (raf) {
1403
- cancelAnimationFrame(raf);
1404
- raf = 0;
1405
- }
1406
- }
1407
- function onReducedMotionChange() {
1408
- reducedMotion = reducedMotionQuery ? reducedMotionQuery.matches : false;
1409
- if (reducedMotion) {
1410
- stopAnimation();
1411
- last = 0;
1412
- draw(reducedMotionStaticTime, false);
1413
- } else {
1414
- startAnimation();
1415
- }
1416
- }
1417
- draw(reducedMotion ? reducedMotionStaticTime : 0, !reducedMotion);
1418
- if (reducedMotionQuery) {
1419
- if (reducedMotionQuery.addEventListener) {
1420
- reducedMotionQuery.addEventListener('change', onReducedMotionChange);
1421
- } else {
1422
- reducedMotionQuery.addListener(onReducedMotionChange);
1423
- }
1424
- }
1425
- if (!reducedMotion) startAnimation();
1426
- })();`
1427
- : "";
1428
- const environmentBadgeScript = `
1429
- (function __anInitEnvironmentBadge() {
1430
- var switcher = document.getElementById('environment-switcher');
1431
- var button = document.getElementById('environment-badge');
1432
- var popover = document.getElementById('environment-popover');
1433
- var productionLink = document.getElementById('environment-production-link');
1434
- var hideButton = document.getElementById('environment-hide-badge');
1435
- if (!switcher || !button || !popover || !productionLink || !hideButton) return;
1436
- if (window.parent !== window) return;
1437
-
1438
- try {
1439
- var forceUrl = new URL(window.location.href);
1440
- if (forceUrl.searchParams.get(${JSON.stringify(BETA_FORCE_QUERY_PARAM)}) === 'true') {
1441
- window.sessionStorage.setItem(${JSON.stringify(BETA_FORCE_SESSION_STORAGE_KEY)}, '1');
1442
- }
1443
- } catch (error) {
1444
- void error;
1445
- }
1446
-
1447
- // Persist the beta opt-out before authentication replaces this cached shell.
1448
- try {
1449
- var optOutUrl = new URL(window.location.href);
1450
- var optOutValue = optOutUrl.searchParams.get(${JSON.stringify(BETA_OPT_OUT_QUERY_PARAM)});
1451
- if (optOutValue !== null) {
1452
- var optOutExpiry = Number(optOutValue);
1453
- var optOutIsActive = Number.isFinite(optOutExpiry) && optOutExpiry > Date.now();
1454
- var optOutStorageReady = false;
1455
- try {
1456
- if (optOutIsActive) {
1457
- window.localStorage.setItem(
1458
- ${JSON.stringify(BETA_OPT_OUT_STORAGE_KEY)},
1459
- String(optOutExpiry),
1460
- );
1461
- }
1462
- optOutStorageReady = true;
1463
- } catch (error) {
1464
- void error;
1465
- }
1466
- if (optOutStorageReady) {
1467
- optOutUrl.searchParams.delete(${JSON.stringify(BETA_OPT_OUT_QUERY_PARAM)});
1468
- window.history.replaceState(null, '', optOutUrl.toString());
1469
- }
1470
- }
1471
- } catch (error) {
1472
- void error;
1473
- }
1474
-
1475
- var betaHosts = ${JSON.stringify(ENVIRONMENT_BETA_HOSTS)};
1476
- var hostname = (window.location.hostname || '').toLowerCase().replace(/\\.$/, '');
1477
- var productionHost = hostname.indexOf('beta.') === 0 ? hostname.slice(5) : '';
1478
- if (!productionHost || betaHosts[productionHost] !== hostname) return;
1479
-
1480
- try {
1481
- var productionUrl = new URL(window.location.href);
1482
- productionUrl.protocol = 'https:';
1483
- productionUrl.hostname = productionHost;
1484
- productionUrl.port = '';
1485
- productionUrl.searchParams.set(
1486
- ${JSON.stringify(BETA_OPT_OUT_QUERY_PARAM)},
1487
- String(Date.now() + ${BETA_OPT_OUT_DURATION_MS}),
1488
- );
1489
- productionLink.href = productionUrl.toString();
1490
- } catch (error) {
1491
- void error;
1492
- return;
1493
- }
1494
-
1495
- function setOpen(open) {
1496
- popover.hidden = !open;
1497
- button.setAttribute('aria-expanded', String(open));
1498
- }
1499
-
1500
- switcher.hidden = false;
1501
- button.addEventListener('click', function() {
1502
- setOpen(popover.hidden);
1503
- });
1504
- document.addEventListener('click', function(event) {
1505
- if (!switcher.contains(event.target)) setOpen(false);
1506
- });
1507
- document.addEventListener('keydown', function(event) {
1508
- if (event.key === 'Escape') setOpen(false);
1509
- });
1510
- hideButton.addEventListener('click', function() {
1511
- setOpen(false);
1512
- switcher.hidden = true;
1513
- });
1514
- })();`;
1515
- return `<!DOCTYPE html>
1516
- <html lang="${DEFAULT_LOCALE}" dir="ltr">
1517
- <head>
1518
- <meta charset="UTF-8">
1519
- <script data-agent-native-locale-init>${localeInitScript}</script>
1520
- <script data-agent-native-embedded-init>${embeddedAuthInitScript}</script>
1521
- <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
1522
- <title>${hasMarketing ? esc(marketing.appName) + " — " + esc(t("pageTitleSignIn")) : esc(t("pageTitleWelcome"))}</title>
1523
- <link rel="icon" type="image/svg+xml" href="${withAppBasePath("/favicon.svg")}">
1524
- <link rel="apple-touch-icon" href="${withAppBasePath("/icon-180.svg")}">
1525
- ${hasMarketing
1526
- ? `<meta name="description" content="${esc(marketing.tagline)}">
1527
- <meta property="og:title" content="${esc(marketing.appName)}">
1528
- <meta property="og:description" content="${esc(marketing.tagline)}">
1529
- <meta property="og:image" content="${esc(socialImageUrl)}">
1530
- <meta property="og:image:secure_url" content="${esc(socialImageUrl)}">
1531
- <meta property="og:image:type" content="${AGENT_NATIVE_SOCIAL_IMAGE_TYPE}">
1532
- <meta property="og:image:width" content="${AGENT_NATIVE_SOCIAL_IMAGE_WIDTH}">
1533
- <meta property="og:image:height" content="${AGENT_NATIVE_SOCIAL_IMAGE_HEIGHT}">
1534
- <meta property="og:image:alt" content="${AGENT_NATIVE_SOCIAL_IMAGE_ALT}">
1535
- <meta name="twitter:card" content="summary_large_image">
1536
- <meta name="twitter:image" content="${esc(socialImageUrl)}">
1537
- <meta name="twitter:image:alt" content="${AGENT_NATIVE_SOCIAL_IMAGE_ALT}">`
1538
- : ""}
1539
- <style>
1168
+ const authMarketingLocales = Object.fromEntries(Object.entries(localizedMarketingCopy).map(([locale, copy]) => [
1169
+ locale,
1170
+ {
1171
+ appName: marketing?.appName ?? "",
1172
+ tagline: copy.tagline ?? marketing?.tagline ?? "",
1173
+ description: copy.description ?? marketing?.description,
1174
+ features: copy.features ?? marketing?.features,
1175
+ },
1176
+ ]));
1177
+ const authPageProps = {
1178
+ authMode,
1179
+ googleOnly,
1180
+ initialPrompt: simplifiedAuth,
1181
+ initialView: initialAuthView(opts, authMode, googleOnly),
1182
+ appBasePath,
1183
+ workspaceRuntime,
1184
+ trackingApp,
1185
+ defaultLocale: DEFAULT_LOCALE,
1186
+ localeStorageKey: LOCALE_STORAGE_KEY,
1187
+ locales: AUTH_LOCALE_COPY,
1188
+ localeMetadata: LOCALE_METADATA,
1189
+ localeOptions: SUPPORTED_LOCALES.map((locale) => ({
1190
+ value: locale,
1191
+ label: localeDisplayName(locale),
1192
+ })),
1193
+ marketing: hasMarketing && marketing ? marketing : undefined,
1194
+ marketingLocales: authMarketingLocales,
1195
+ brandMarkSrc,
1196
+ githubUrl: "https://github.com/BuilderIO/agent-native",
1197
+ showGoogle,
1198
+ signupLegalNotice,
1199
+ signupLocalModeNote,
1200
+ connectionLabel: getConnectionLabel(),
1201
+ docsAuthUrl: docsUrl("authentication", {
1202
+ hash: "local-development-sign-in",
1203
+ }),
1204
+ identitySsoEnabled,
1205
+ publicOAuthOrigin,
1206
+ workspaceGatewayReturnOrigin,
1207
+ googleAuthMode,
1208
+ builderPreviewLocalDevEnabled,
1209
+ environmentBetaHosts: ENVIRONMENT_BETA_HOSTS,
1210
+ betaForceQueryParam: BETA_FORCE_QUERY_PARAM,
1211
+ betaForceSessionStorageKey: BETA_FORCE_SESSION_STORAGE_KEY,
1212
+ betaOptOutQueryParam: BETA_OPT_OUT_QUERY_PARAM,
1213
+ betaOptOutStorageKey: BETA_OPT_OUT_STORAGE_KEY,
1214
+ betaOptOutDurationMs: BETA_OPT_OUT_DURATION_MS,
1215
+ passwordMinLength: PASSWORD_MIN_LENGTH,
1216
+ passwordMaxLength: PASSWORD_MAX_LENGTH,
1217
+ passwordMaxCopy: `Choose a password with no more than ${PASSWORD_MAX_LENGTH} characters.`,
1218
+ };
1219
+ const authPageData = serializeAuthPageData(authPageProps);
1220
+ const authDocumentStyles = `\n
1540
1221
  *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
1541
1222
  .sr-only {
1542
1223
  position: absolute;
@@ -2148,1997 +1829,126 @@ ${marketingStyles}
2148
1829
  body.simplified-auth .card { border-color: transparent; box-shadow: none; }
2149
1830
  body.simplified-auth .local-note { display: none !important; }
2150
1831
  ${embeddedAuthCss}
2151
- </style>
2152
- </head>
2153
- <body${simplifiedAuth ? ' class="simplified-auth"' : hasMarketing ? ' class="has-marketing"' : ""}>
2154
- ${localePickerHtml}
2155
- ${environmentBadgeHtml}
2156
- ${marketingPanelHtml}
2157
- <div class="card">
2158
- <h1 id="heading"${i18nAttr(googleOnly ? "signInTitle" : "welcomeTitle")}>${esc(t(googleOnly ? "signInTitle" : "welcomeTitle"))}</h1>
2159
- <p class="subtitle" id="subtitle"${i18nAttr(googleOnly ? "googleOnlySubtitle" : "createAccountSubtitle")}>${esc(t(googleOnly ? "googleOnlySubtitle" : "createAccountSubtitle"))}</p>
2160
- <p
2161
- class="upgrade-note"
2162
- id="upgrade-note"
2163
- data-upgrade-copy="${esc(t("upgradeCopy"))}"
2164
- ${i18nDataAttr("data-upgrade-copy", "upgradeCopy").trim()}
2165
- ></p>
2166
- ${identitySsoHtml}
2167
- ${localDevHtml}
2168
- <div id="full-auth-options" class="full-auth-options">
2169
- ${googleUnavailableHtml}
2170
- ${renderGoogleButton
2171
- ? `
2172
- <div class="google-signin" id="google-signin">
2173
- <button class="btn-google" id="google-btn" onclick="signInWithGoogle()">
2174
- <svg viewBox="0 0 24 24"><path fill="#4285F4" d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 0 1-2.2 3.32v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.1z"/><path fill="#34A853" d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"/><path fill="#FBBC05" d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"/><path fill="#EA4335" d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"/></svg>
2175
- <span${i18nAttr("googleButton")}>${esc(t("googleButton"))}</span>
2176
- </button>
2177
- <p class="google-error" id="google-err"></p>
2178
- <p class="google-debug" id="google-debug"></p>
2179
- </div>
2180
- ${googleOnly ? "" : `\n <div class="divider" id="auth-divider"${i18nAttr("dividerOr")}>${esc(t("dividerOr"))}</div>\n`}
2181
- `
2182
- : ""}
2183
- ${googleOnly
2184
- ? ""
2185
- : `${magicLinkMode ? '\n <form id="magic-link-form" class="form">\n <label for="m-email"' + i18nAttr("email") + ">" + esc(t("email")) + '</label>\n <input id="m-email" type="email" autocomplete="email" placeholder="' + esc(t("emailPlaceholder")) + '" required />\n <button type="submit" id="magic-link-submit" class="magic-link-submit"' + i18nAttr("sendMagicLink") + ">" + esc(t("sendMagicLink")) + '</button>\n <p class="msg" id="m-msg"></p>\n' + signupLegalNoteHtml + '\n <p style="margin-top:0.75rem;font-size:0.75rem;text-align:start">\n <a href="#" id="use-password-link" class="link-button auth-mode-link"' + i18nAttr("usePasswordInstead") + ">" + esc(t("usePasswordInstead")) + "</a>\n </p>\n </form>\n" : ""}${magicLinkSuccessHtml} <div class="tabs" id="auth-tabs">
2186
- <button class="tab" data-tab="signup"${i18nAttr("createAccount")}>${esc(t("createAccount"))}</button>
2187
- <button class="tab" data-tab="login"${i18nAttr("signIn")}>${esc(t("signIn"))}</button>
2188
- </div>
2189
-
2190
- <form id="signup-form" class="form">
2191
- <label for="s-email"${i18nAttr("email")}>${esc(t("email"))}</label>
2192
- <input id="s-email" type="email" autocomplete="email" placeholder="${esc(t("emailPlaceholder"))}" required />
2193
- <label for="s-pass"${i18nAttr("password")}>${esc(t("password"))}</label>
2194
- <input id="s-pass" type="password" autocomplete="new-password" placeholder="${esc(t("passwordMinPlaceholder"))}"${i18nPlaceholderAttr("passwordMinPlaceholder")} required minlength="${PASSWORD_MIN_LENGTH}" maxlength="${PASSWORD_MAX_LENGTH}" />
2195
- <label for="s-pass2"${i18nAttr("confirmPassword")}>${esc(t("confirmPassword"))}</label>
2196
- <input id="s-pass2" type="password" autocomplete="new-password" placeholder="${esc(t("confirmPasswordPlaceholder"))}"${i18nPlaceholderAttr("confirmPasswordPlaceholder")} required minlength="${PASSWORD_MIN_LENGTH}" maxlength="${PASSWORD_MAX_LENGTH}" />
2197
- <button type="submit"${i18nAttr("createAccount")}>${esc(t("createAccount"))}</button>
2198
- ${signupLegalNoteHtml}
2199
- ${signupLocalModeNoteHtml}
2200
- <p class="msg" id="s-msg"></p>
2201
- </form>
2202
-
2203
- <div id="verification-step" class="form verification-step" aria-live="polite">
2204
- <div class="step-progress" aria-label="${esc(t("signupProgress"))}"${i18nAriaAttr("signupProgress")}>
2205
- <div class="progress-step complete"><span>1</span><strong${i18nAttr("progressAccount")}>${esc(t("progressAccount"))}</strong></div>
2206
- <div class="progress-step current"><span>2</span><strong${i18nAttr("progressVerify")}>${esc(t("progressVerify"))}</strong></div>
2207
- <div class="progress-step"><span>3</span><strong${i18nAttr("progressStart")}>${esc(t("progressStart"))}</strong></div>
2208
- </div>
2209
- <div class="verification-panel">
2210
- <p class="verification-kicker"${i18nAttr("verificationSent")}>${esc(t("verificationSent"))}</p>
2211
- <p class="verification-copy"><span${i18nAttr("verifyCopyPrefix")}>${esc(t("verifyCopyPrefix"))}</span> <strong id="verify-email"></strong><span${i18nAttr("verifyCopySuffix")}>${esc(t("verifyCopySuffix"))}</span></p>
2212
- <p class="verification-note"${i18nAttr("verificationNote")}>${esc(t("verificationNote"))}</p>
2213
- </div>
2214
- <button type="button" class="btn-primary" id="verify-continue"${i18nAttr("continue")}>${esc(t("continue"))}</button>
2215
- <div class="inline-actions">
2216
- <button type="button" class="link-button" id="resend-verification"${i18nAttr("resendEmail")}>${esc(t("resendEmail"))}</button>
2217
- <button type="button" class="link-button" id="back-to-signup"${i18nAttr("back")}>${esc(t("back"))}</button>
2218
- </div>
2219
- <p class="msg" id="verify-msg"></p>
2220
- </div>
2221
-
2222
- <form id="login-form" class="form">
2223
- <label for="l-email"${i18nAttr("email")}>${esc(t("email"))}</label>
2224
- <input id="l-email" type="email" autocomplete="email" placeholder="${esc(t("emailPlaceholder"))}" required />
2225
- <label for="l-pass"${i18nAttr("password")}>${esc(t("password"))}</label>
2226
- <input id="l-pass" type="password" autocomplete="current-password" placeholder="${esc(t("enterPasswordPlaceholder"))}"${i18nPlaceholderAttr("enterPasswordPlaceholder")} required />
2227
- <button type="submit"${i18nAttr("signIn")}>${esc(t("signIn"))}</button>
2228
- <p class="msg error" id="l-msg"></p>
2229
- <p style="margin-top:0.75rem;font-size:0.75rem;text-align:right">
2230
- <a href="#" id="forgot-link" style="color:#888;text-decoration:underline;text-underline-offset:2px"${i18nAttr("forgotPassword")}>${esc(t("forgotPassword"))}</a>
2231
- </p>
2232
- ${magicLinkMode ? `<p style="margin-top:0.5rem;font-size:0.75rem;text-align:center"><a href="#" id="back-to-magic-link" class="link-button"${i18nAttr("backToMagicLink")}>${esc(t("backToMagicLink"))}</a></p>` : ""}
2233
- </form>
2234
-
2235
- <form id="forgot-form" class="form">
2236
- <label for="f-email"${i18nAttr("email")}>${esc(t("email"))}</label>
2237
- <input id="f-email" type="email" autocomplete="email" placeholder="${esc(t("emailPlaceholder"))}" required />
2238
- <button type="submit"${i18nAttr("sendResetLink")}>${esc(t("sendResetLink"))}</button>
2239
- <p class="msg" id="f-msg"></p>
2240
- <p style="margin-top:0.75rem;font-size:0.75rem;text-align:center">
2241
- <a href="#" id="back-to-login" style="color:#888;text-decoration:underline;text-underline-offset:2px"${i18nAttr("backToSignIn")}>${esc(t("backToSignIn"))}</a>
2242
- </p>
2243
- </form>`}
2244
- </div>
2245
- </div>
2246
- <p class="local-note" id="local-note">
2247
- <span${i18nAttr("localNotePrefix")}>${esc(t("localNotePrefix"))}</span> (<strong>${getConnectionLabel()}</strong>)<span${i18nAttr("localNoteSuffix")}>${esc(t("localNoteSuffix"))}</span>
2248
- </p>${marketingCloseHtml}
2249
- <script>
2250
- ${environmentBadgeScript}
2251
- function __anBasePath() {
2252
- var configured = ${JSON.stringify(appBasePath)};
2253
- if (configured) return configured;
2254
- var marker = '/_agent-native';
2255
- var idx = window.location.pathname.indexOf(marker);
2256
- if (idx > 0) return window.location.pathname.slice(0, idx);
2257
- if (${JSON.stringify(workspaceRuntime)}) {
2258
- var segments = window.location.pathname.split('/');
2259
- for (var i = 0; i < segments.length; i++) {
2260
- var segment = segments[i];
2261
- if (segment && segment !== '_agent-native' && segment !== 'api' && segment !== 'sign-in' && segment !== 'login' && segment !== 'signup') {
2262
- return '/' + segment;
2263
- }
2264
- }
2265
- }
2266
- return '';
2267
- }
2268
- function __anPath(path) {
2269
- return __anBasePath() + path;
2270
- }
2271
- ${signInJourneyInlineScript()}
2272
- var __anJourney = __anCreateSignInJourney(__anBasePath());
2273
- /**
2274
- * Where this document sends the visitor once a session exists. One
2275
- * function, one answer — the page used to have two ("__anGetReturnPath"
2276
- * and "__anGetSignedInReturnPath") that disagreed about whether the
2277
- * sign-in page itself was an acceptable destination, which is how
2278
- * verification emails ended up linking back to a login form.
2279
- */
2280
- function __anResumeHref() {
2281
- return __anJourney.journeyForLocation(window.location).resumeHref;
2282
- }
2283
- var __AN_AUTH_DEFAULT_LOCALE = ${JSON.stringify(DEFAULT_LOCALE)};
2284
- var __AN_AUTH_SUPPORTED_LOCALES = ${JSON.stringify(SUPPORTED_LOCALES)};
2285
- var __AN_AUTH_LOCALE_STORAGE_KEY = ${JSON.stringify(LOCALE_STORAGE_KEY)};
2286
- var __AN_AUTH_LOCALE_METADATA = ${JSON.stringify(LOCALE_METADATA)};
2287
- var __AN_AUTH_LOCALES = ${JSON.stringify(AUTH_LOCALE_COPY)};
2288
- var __AN_AUTH_MARKETING_APP_NAME = ${JSON.stringify(marketing?.appName ?? "")};
2289
- var __AN_AUTH_HAS_MARKETING = ${JSON.stringify(hasMarketing)};
2290
- var __AN_AUTH_MARKETING_SLUG = ${JSON.stringify(marketingSlug ?? "")};
2291
- var __AN_AUTH_MARKETING_DEFAULT = ${JSON.stringify(defaultMarketingCopy ?? {})};
2292
- var __AN_AUTH_MARKETING_LOCALES = ${JSON.stringify(localizedMarketingCopy)};
2293
- var __anAuthLocale = __AN_AUTH_DEFAULT_LOCALE;
2294
- var __anAuthLocalePreference = 'system';
2295
- var __AN_AUTH_MODE = ${JSON.stringify(authMode)};
2296
- var __anAuthView = ${JSON.stringify(googleOnly ? "googleOnly" : "signup")};
2297
- var __AN_AUTH_APP = ${JSON.stringify(trackingApp)};
2298
- function __anTrackAuth(name, properties) {
2299
- try {
2300
- var config = window.__AGENT_NATIVE_CONFIG__ || {};
2301
- if (!config.agentNativeAnalyticsPublicKey) return;
2302
- var anonymousId = '';
2303
- // coercion-ok: privacy-restricted storage means this public event cannot be attributed
2304
- try { anonymousId = localStorage.getItem('agent-native.anonymous_id') || ''; } catch (e) {}
2305
- if (!anonymousId) return;
2306
- var sessionId = '';
2307
- // coercion-ok: privacy-restricted storage means this public event has no session id
2308
- try { sessionId = sessionStorage.getItem('agent-native.session_id') || ''; } catch (e) {}
2309
- var body = JSON.stringify({
2310
- publicKey: config.agentNativeAnalyticsPublicKey,
2311
- event: name,
2312
- properties: Object.assign({ app: __AN_AUTH_APP }, properties || {}),
2313
- anonymousId: anonymousId,
2314
- sessionId: sessionId || undefined,
2315
- timestamp: new Date().toISOString()
2316
- });
2317
- var endpoint = config.agentNativeAnalyticsEndpoint || 'https://analytics.agent-native.com/track';
2318
- if (navigator.sendBeacon && navigator.sendBeacon(endpoint, body)) return;
2319
- fetch(endpoint, {
2320
- method: 'POST',
2321
- body: body,
2322
- keepalive: true,
2323
- headers: { 'Content-Type': 'text/plain;charset=UTF-8' }
2324
- // coercion-ok: analytics delivery is best effort and cannot block auth
2325
- }).catch(function() {});
2326
- // coercion-ok: analytics delivery is best effort and cannot block auth
2327
- } catch (e) {}
2328
- }
2329
- function __anAuthLocaleIsSupported(value) {
2330
- return __AN_AUTH_SUPPORTED_LOCALES.indexOf(value) !== -1;
2331
- }
2332
- function __anNormalizeAuthLocale(value) {
2333
- if (typeof value !== 'string' || !value) return null;
2334
- if (__anAuthLocaleIsSupported(value)) return value;
2335
- try {
2336
- var canonical = Intl.getCanonicalLocales(value)[0];
2337
- if (__anAuthLocaleIsSupported(canonical)) return canonical;
2338
- var language = canonical && canonical.split('-')[0].toLowerCase();
2339
- for (var i = 0; i < __AN_AUTH_SUPPORTED_LOCALES.length; i++) {
2340
- var locale = __AN_AUTH_SUPPORTED_LOCALES[i];
2341
- if (locale.split('-')[0].toLowerCase() === language) return locale;
2342
- }
2343
- } catch(e) {}
2344
- return null;
2345
- }
2346
- function __anNormalizeAuthLocalePreference(value) {
2347
- if (value === 'system') return 'system';
2348
- return __anNormalizeAuthLocale(value);
2349
- }
2350
- function __anReadAuthLocalePreference() {
2351
- try {
2352
- return __anNormalizeAuthLocalePreference(localStorage.getItem(__AN_AUTH_LOCALE_STORAGE_KEY)) || 'system';
2353
- } catch(e) {
2354
- return 'system';
2355
- }
2356
- }
2357
- function __anWriteAuthLocalePreference(preference) {
2358
- try {
2359
- localStorage.setItem(__AN_AUTH_LOCALE_STORAGE_KEY, preference);
2360
- } catch(e) {}
2361
- }
2362
- function __anBrowserAuthLocales() {
2363
- try {
2364
- if (navigator.languages && navigator.languages.length) return navigator.languages;
2365
- if (navigator.language) return [navigator.language];
2366
- } catch(e) {}
2367
- return [];
2368
- }
2369
- function __anResolveAuthSystemLocale() {
2370
- var locales = __anBrowserAuthLocales();
2371
- for (var i = 0; i < locales.length; i++) {
2372
- var match = __anNormalizeAuthLocale(locales[i]);
2373
- if (match) return match;
2374
- }
2375
- return __AN_AUTH_DEFAULT_LOCALE;
2376
- }
2377
- function __anResolveAuthLocale(preference) {
2378
- var normalizedPreference = __anNormalizeAuthLocalePreference(preference) || 'system';
2379
- return normalizedPreference === 'system'
2380
- ? __anResolveAuthSystemLocale()
2381
- : normalizedPreference;
2382
- }
2383
- function __anApplyAuthSystemLanguage() {
2384
- var systemLanguage = document.querySelector('[data-system-language]');
2385
- if (!systemLanguage) return;
2386
- var systemLocale = __anResolveAuthSystemLocale();
2387
- var localized = __AN_AUTH_LOCALES[systemLocale] || __AN_AUTH_LOCALES[__AN_AUTH_DEFAULT_LOCALE] || {};
2388
- systemLanguage.textContent = localized.systemLanguage || 'System';
2389
- }
2390
- function __anT(key) {
2391
- var localized = __AN_AUTH_LOCALES[__anAuthLocale] || __AN_AUTH_LOCALES[__AN_AUTH_DEFAULT_LOCALE] || {};
2392
- var fallback = __AN_AUTH_LOCALES[__AN_AUTH_DEFAULT_LOCALE] || {};
2393
- return localized[key] || fallback[key] || key;
2394
- }
2395
- function __anAuthErrorText(data, fallback) {
2396
- var candidate = data && (data.error || data.message);
2397
- if (typeof candidate !== 'string' || !candidate.trim()) return fallback;
2398
- var message = candidate.trim();
2399
- if (/failed query|\bselect\b.*\bfrom\b|\binsert\b.*\binto\b|\bupdate\b.*\bset\b|\bdelete\b.*\bfrom\b|\bsql\b|database|relation .* does not exist|column .* does not exist|syntax error|constraint|connection refused|econn|timeout/i.test(message)) {
2400
- return fallback;
2401
- }
2402
- return message;
2403
- }
2404
- function __anBindPasswordValidation(input) {
2405
- if (!input) return;
2406
- input.addEventListener('invalid', function() {
2407
- if (input.validity && input.validity.tooShort) {
2408
- input.setCustomValidity(__anT('passwordMinPlaceholder'));
2409
- } else if (input.validity && input.validity.tooLong) {
2410
- input.setCustomValidity('Choose a password with no more than ${PASSWORD_MAX_LENGTH} characters.');
2411
- }
2412
- });
2413
- input.addEventListener('input', function() {
2414
- input.setCustomValidity('');
2415
- });
2416
- }
2417
- function __anSetAuthI18nKey(node, key) {
2418
- if (!node || !key) return;
2419
- node.setAttribute('data-i18n', key);
2420
- node.textContent = __anT(key);
2421
- }
2422
- function __anAuthHeadingKeys(view) {
2423
- if (view === 'login') return { heading: 'welcomeBackTitle', subtitle: 'signInSubtitle' };
2424
- if (view === 'forgot') return { heading: 'resetPasswordTitle', subtitle: 'resetPasswordSubtitle' };
2425
- if (view === 'verification') return { heading: 'checkEmailTitle', subtitle: 'finishAccountSubtitle' };
2426
- if (view === 'googleOnly') return { heading: 'signInTitle', subtitle: 'googleOnlySubtitle' };
2427
- if (view === 'magicLinkSent') return { heading: 'magicLinkSent', subtitle: 'magicLinkSentCopy' };
2428
- if (view === 'magicLink') return { heading: 'magicLinkTitle', subtitle: 'magicLinkSubtitle' };
2429
- return { heading: 'welcomeTitle', subtitle: 'createAccountSubtitle' };
2430
- }
2431
- function __anRefreshAuthViewCopy() {
2432
- var keys = __anAuthHeadingKeys(__anAuthView);
2433
- __anSetAuthI18nKey(document.getElementById('heading'), keys.heading);
2434
- __anSetAuthI18nKey(document.getElementById('subtitle'), keys.subtitle);
2435
- }
2436
- function __anSetAuthView(view) {
2437
- __anAuthView = view || 'signup';
2438
- __anRefreshAuthViewCopy();
2439
- }
2440
- function __anMarketingCopy() {
2441
- if (!__AN_AUTH_MARKETING_SLUG) return __AN_AUTH_MARKETING_DEFAULT || {};
2442
- var localeMarketing = __AN_AUTH_MARKETING_LOCALES[__anAuthLocale] || {};
2443
- return {
2444
- tagline: localeMarketing.tagline || __AN_AUTH_MARKETING_DEFAULT.tagline,
2445
- description: localeMarketing.description || __AN_AUTH_MARKETING_DEFAULT.description,
2446
- features: localeMarketing.features || __AN_AUTH_MARKETING_DEFAULT.features || []
2447
- };
2448
- }
2449
- function __anApplyAuthMarketingCopy() {
2450
- var copy = __anMarketingCopy();
2451
- var tagline = document.querySelector('[data-marketing-field="tagline"]');
2452
- if (tagline && copy.tagline) tagline.textContent = copy.tagline;
2453
- var description = document.querySelector('[data-marketing-field="description"]');
2454
- if (description && copy.description) description.textContent = copy.description;
2455
- document.querySelectorAll('[data-marketing-feature-index]').forEach(function(node) {
2456
- var index = Number(node.getAttribute('data-marketing-feature-index'));
2457
- var feature = copy.features && copy.features[index];
2458
- if (feature) node.textContent = feature;
2459
- });
2460
- }
2461
- function __anApplyAuthLocale(preference) {
2462
- __anAuthLocalePreference = __anNormalizeAuthLocalePreference(preference) || __anReadAuthLocalePreference();
2463
- __anAuthLocale = __anResolveAuthLocale(__anAuthLocalePreference);
2464
- var root = document.documentElement;
2465
- var meta = __AN_AUTH_LOCALE_METADATA[__anAuthLocale] || {};
2466
- root.setAttribute('lang', __anAuthLocale);
2467
- root.setAttribute('dir', meta.dir || 'ltr');
2468
- root.setAttribute('data-locale', __anAuthLocale);
2469
- document.querySelectorAll('[data-i18n]').forEach(function(node) {
2470
- node.textContent = __anT(node.getAttribute('data-i18n'));
2471
- });
2472
- document.querySelectorAll('[data-i18n-placeholder]').forEach(function(node) {
2473
- node.setAttribute('placeholder', __anT(node.getAttribute('data-i18n-placeholder')));
2474
- });
2475
- document.querySelectorAll('[data-i18n-aria-label]').forEach(function(node) {
2476
- node.setAttribute('aria-label', __anT(node.getAttribute('data-i18n-aria-label')));
2477
- });
2478
- document.querySelectorAll('[data-i18n-title]').forEach(function(node) {
2479
- node.setAttribute('title', __anT(node.getAttribute('data-i18n-title')));
2480
- });
2481
- document.querySelectorAll('[data-i18n-data-upgrade-copy]').forEach(function(node) {
2482
- node.setAttribute('data-upgrade-copy', __anT(node.getAttribute('data-i18n-data-upgrade-copy')));
2483
- });
2484
- document.querySelectorAll('[data-locale-value]').forEach(function(node) {
2485
- var checked = node.getAttribute('data-locale-value') === __anAuthLocalePreference;
2486
- node.setAttribute('aria-checked', checked ? 'true' : 'false');
2487
- });
2488
- document.title = __AN_AUTH_HAS_MARKETING && __AN_AUTH_MARKETING_APP_NAME
2489
- ? __AN_AUTH_MARKETING_APP_NAME + ' — ' + __anT('pageTitleSignIn')
2490
- : __anT('pageTitleWelcome');
2491
- __anApplyAuthSystemLanguage();
2492
- __anApplyAuthMarketingCopy();
2493
- __anRefreshAuthViewCopy();
2494
- }
2495
- function __anSetAuthLocaleMenuOpen(open) {
2496
- var trigger = document.getElementById('auth-locale-trigger');
2497
- var menu = document.getElementById('auth-locale-menu');
2498
- if (!trigger || !menu) return;
2499
- if (open) {
2500
- menu.removeAttribute('hidden');
2501
- } else {
2502
- menu.setAttribute('hidden', '');
2503
- }
2504
- trigger.setAttribute('aria-expanded', open ? 'true' : 'false');
2505
- }
2506
- (function __anInitAuthLocalePicker() {
2507
- var trigger = document.getElementById('auth-locale-trigger');
2508
- var menu = document.getElementById('auth-locale-menu');
2509
- var preference = __anReadAuthLocalePreference();
2510
- __anApplyAuthLocale(preference);
2511
- if (!trigger || !menu) return;
2512
- trigger.addEventListener('click', function(event) {
2513
- event.preventDefault();
2514
- __anSetAuthLocaleMenuOpen(menu.hasAttribute('hidden'));
2515
- });
2516
- menu.querySelectorAll('[data-locale-value]').forEach(function(item) {
2517
- item.addEventListener('click', function() {
2518
- var next = __anNormalizeAuthLocalePreference(item.getAttribute('data-locale-value')) || 'system';
2519
- __anWriteAuthLocalePreference(next);
2520
- __anApplyAuthLocale(next);
2521
- __anSetAuthLocaleMenuOpen(false);
2522
- trigger.focus();
2523
- });
2524
- });
2525
- document.addEventListener('click', function(event) {
2526
- var picker = document.querySelector('.locale-picker');
2527
- if (picker && picker.contains(event.target)) return;
2528
- __anSetAuthLocaleMenuOpen(false);
2529
- });
2530
- document.addEventListener('keydown', function(event) {
2531
- if (event.key === 'Escape') __anSetAuthLocaleMenuOpen(false);
2532
- });
2533
- })();
2534
- var __AN_PUBLIC_OAUTH_ORIGIN = ${JSON.stringify(publicOAuthOrigin)};
2535
- var __AN_WORKSPACE_GATEWAY_RETURN_ORIGIN = ${JSON.stringify(workspaceGatewayReturnOrigin)};
2536
- var __AN_GOOGLE_AUTH_MODE = ${JSON.stringify(googleAuthMode)};
2537
- var __AN_BUILDER_PREVIEW_LOCAL_DEV_ENABLED = ${JSON.stringify(builderPreviewLocalDevEnabled)};
2538
- function __anConfiguredOAuthOrigin() {
2539
- if (!__AN_PUBLIC_OAUTH_ORIGIN) return '';
2540
- try {
2541
- var origin = new URL(__AN_PUBLIC_OAUTH_ORIGIN).origin;
2542
- return origin && origin !== window.location.origin ? origin : '';
2543
- } catch(e) {
2544
- return '';
2545
- }
2546
- }
2547
- function __anAuthPath(path) {
2548
- var origin = __anIsBuilderPreview() ? __anConfiguredOAuthOrigin() : '';
2549
- return origin ? origin + path : __anPath(path);
2550
- }
2551
- function __anGoogleAuthUrlPath() {
2552
- return __anIsBuilderPreview()
2553
- ? __anAuthPath('/_agent-native/google/auth-url')
2554
- : __anPath('/_agent-native/google/auth-url');
2555
- }
2556
- function __anBuilderPreviewReturnOrigin() {
2557
- var candidates = [window.location.href, document.referrer || ''];
2558
- try {
2559
- if (window.location.ancestorOrigins) {
2560
- for (var j = 0; j < window.location.ancestorOrigins.length; j++) {
2561
- candidates.push(window.location.ancestorOrigins[j]);
2562
- }
2563
- }
2564
- } catch(e) {}
2565
- for (var i = 0; i < candidates.length; i++) {
2566
- try {
2567
- var url = new URL(candidates[i]);
2568
- var host = url.hostname.toLowerCase();
2569
- var isPreviewHost =
2570
- host === 'builderio.xyz' || host.slice(-14) === '.builderio.xyz' ||
2571
- host === 'builderio.dev' || host.slice(-14) === '.builderio.dev' ||
2572
- host === 'builder.codes' || host.slice(-14) === '.builder.codes' ||
2573
- host === 'builder.my' || host.slice(-11) === '.builder.my';
2574
- if (url.protocol === 'https:' && isPreviewHost) return url.origin;
2575
- } catch(e) {}
2576
- }
2577
- return '';
2578
- }
2579
- function __anWorkspaceGatewayReturnOrigin() {
2580
- var previewOrigin = __anBuilderPreviewReturnOrigin();
2581
- if (previewOrigin) return previewOrigin;
2582
- if (__AN_WORKSPACE_GATEWAY_RETURN_ORIGIN) return __AN_WORKSPACE_GATEWAY_RETURN_ORIGIN;
2583
- return __anIsBuilderDesktop() ? 'http://127.0.0.1:8080' : '';
2584
- }
2585
- function __anNormalizeWorkspaceReturnPath(ret) {
2586
- try {
2587
- var url = new URL(ret || '/', window.location.origin);
2588
- var path = url.pathname || '/';
2589
- if (path === '/dispatch/dispatch') {
2590
- path = '/dispatch';
2591
- } else if (path.indexOf('/dispatch/') === 0) {
2592
- var rest = path.slice('/dispatch/'.length);
2593
- var first = rest.split('/')[0];
2594
- var dispatchRoutes = {
2595
- overview: true, apps: true, metrics: true, vault: true,
2596
- integrations: true, messaging: true, workspace: true,
2597
- agents: true, destinations: true, identities: true,
2598
- approvals: true, audit: true, team: true, 'thread-debug': true,
2599
- 'new-app': true
2600
- };
2601
- if (first === 'dispatch') {
2602
- path = '/dispatch' + rest.slice(first.length);
2603
- } else if (first && !dispatchRoutes[first]) {
2604
- path = '/' + rest;
2605
- }
2606
- }
2607
- return path + url.search + url.hash;
2608
- } catch(e) {
2609
- return ret || '/';
2610
- }
2611
- }
2612
- function __anOAuthReturnTarget(ret) {
2613
- var path = __anNormalizeWorkspaceReturnPath(ret);
2614
- var origin = __anWorkspaceGatewayReturnOrigin();
2615
- return origin ? origin + path : path;
2616
- }
2617
- function __anSessionBridgeUrl(ret, sessionToken) {
2618
- try {
2619
- var url = new URL(ret || window.location.pathname + window.location.search, window.location.origin);
2620
- url.searchParams.set('_session', sessionToken);
2621
- return url.pathname + url.search + url.hash;
2622
- } catch(e) {
2623
- var sep = (ret || '/').indexOf('?') === -1 ? '?' : '&';
2624
- return (ret || '/') + sep + '_session=' + encodeURIComponent(sessionToken);
2625
- }
2626
- }
2627
- function __anFinishOAuthExchange(ret, flowId, sessionToken) {
2628
- __anStopOAuthPopupWatch();
2629
- __anStopNativeOAuthAbandonment();
2630
- __anGoogleSignInInFlight = false;
2631
- __anClearGoogleSignInFlow();
2632
- __anMagicLinkInFlight = false;
2633
- if (__anIsBuilderPreview()) {
2634
- if (sessionToken) {
2635
- __anSetOAuthDebug('OAuth exchange redeemed; applying session bridge to embedded app', flowId);
2636
- window.location.replace(__anSessionBridgeUrl(ret, sessionToken));
2637
- return;
2638
- }
2639
- __anSetOAuthDebug('OAuth exchange redeemed; reloading the embedded app', flowId);
2640
- window.location.reload();
2641
- return;
2642
- }
2643
- __anSetOAuthDebug('OAuth exchange redeemed; returning to the app', flowId);
2644
- __anRedirectToSignedInApp(ret);
2645
- }
2646
- function __anRedirectToSignedInApp(ret) {
2647
- window.location.replace(ret || __anResumeHref());
2648
- }
2649
- function __anMaybeRedirectSignedIn(ret) {
2650
- return fetch(__anPath('/_agent-native/auth/session'), {
2651
- headers: { 'Accept': 'application/json' },
2652
- credentials: 'include',
2653
- cache: 'no-store',
2654
- }).then(function(res) {
2655
- if (!res.ok) return null;
2656
- return res.json().catch(function() { return null; });
2657
- }).then(function(data) {
2658
- if (data && data.email && !data.error) {
2659
- __anRedirectToSignedInApp(ret);
2660
- return true;
2661
- }
2662
- return false;
2663
- }).catch(function() {
2664
- return false;
2665
- });
2666
- }
2667
- function __anIsLoopbackHostname() {
2668
- var hostname = (window.location.hostname || '').toLowerCase();
2669
- return hostname === 'localhost' || hostname === '::1' || hostname === '127.0.0.1' || hostname.indexOf('127.') === 0;
2670
- }
2671
- function __anIsBuilderPreviewHost() {
2672
- var hostname = (window.location.hostname || '').toLowerCase();
2673
- return hostname.endsWith('.builderio.xyz') || hostname.endsWith('.builderio.dev') || hostname.endsWith('.builder.codes') || hostname.endsWith('.builder.my');
2674
- }
2675
- function __anCanUseLocalDevSignin() {
2676
- return __anIsLoopbackHostname() || (__AN_BUILDER_PREVIEW_LOCAL_DEV_ENABLED && __anIsBuilderPreviewHost());
2677
- }
2678
- function __anShouldStartWithLocalDev() {
2679
- if (!__anCanUseLocalDevSignin()) return false;
2680
- var params = new URLSearchParams(window.location.search);
2681
- var explicitTab = params.get('tab');
2682
- var verifiedRedirect = typeof __anIsVerifiedRedirectSuccess === 'function' && __anIsVerifiedRedirectSuccess();
2683
- return explicitTab !== 'login' && explicitTab !== 'signup' && !verifiedRedirect;
2684
- }
2685
- function __anSetFullAuthOptionsVisible(visible) {
2686
- var options = document.getElementById('full-auth-options');
2687
- var toggle = document.getElementById('local-dev-full-options');
2688
- if (!options) return;
2689
- if (visible) {
2690
- options.removeAttribute('hidden');
2691
- if (toggle) toggle.setAttribute('hidden', '');
2692
- } else {
2693
- options.setAttribute('hidden', '');
2694
- if (toggle) toggle.removeAttribute('hidden');
2695
- }
2696
- }
2697
- (function __anPrepareLocalDevButton() {
2698
- var container = document.getElementById('local-dev-signin');
2699
- var button = document.getElementById('local-dev-btn');
2700
- var fullOptionsButton = document.getElementById('local-dev-full-options');
2701
- if (!container || !button || !__anCanUseLocalDevSignin()) return;
2702
- function __anShowLocalDevSignin() {
2703
- container.hidden = false;
2704
- var startWithLocalDev = __anShouldStartWithLocalDev();
2705
- __anSetFullAuthOptionsVisible(!startWithLocalDev);
2706
- if (startWithLocalDev) button.focus();
2707
- if (fullOptionsButton) fullOptionsButton.addEventListener('click', function() {
2708
- __anSetFullAuthOptionsVisible(true);
2709
- var firstInput = document.querySelector('#full-auth-options input, #full-auth-options button, #full-auth-options a');
2710
- if (firstInput) firstInput.focus();
2711
- });
2712
- button.addEventListener('click', function() {
2713
- button.disabled = true;
2714
- button.textContent = __anT('localDevSigningIn');
2715
- fetch(__anPath('/_agent-native/auth/local-dev'), {
2716
- method: 'POST',
2717
- credentials: 'include',
2718
- headers: { 'Accept': 'application/json' },
2719
- }).then(function(response) {
2720
- if (!response.ok) throw new Error('local-dev-auth-failed');
2721
- }).then(function() {
2722
- __anRedirectToSignedInApp(__anResumeHref());
2723
- }).catch(function() {
2724
- container.hidden = true;
2725
- __anSetFullAuthOptionsVisible(true);
2726
- });
2727
- });
2728
- }
2729
- fetch(__anPath('/_agent-native/auth/local-dev'), {
2730
- method: 'GET',
2731
- credentials: 'include',
2732
- cache: 'no-store',
2733
- headers: { 'Accept': 'application/json' },
2734
- }).then(function(response) {
2735
- if (!response.ok) return null;
2736
- return response.json().then(function(data) {
2737
- return data;
2738
- }, function() {
2739
- return null;
2740
- });
2741
- }, function() {
2742
- return null;
2743
- }).then(function(data) {
2744
- if (data && data.available === true) {
2745
- __anShowLocalDevSignin();
2746
- } else {
2747
- __anSetFullAuthOptionsVisible(true);
2748
- }
2749
- });
2750
- })();
2751
- ${identitySsoScript}
2752
- (function __anRedirectIfAlreadySignedIn() {
2753
- __anMaybeRedirectSignedIn();
2754
- })();
2755
- function __anSafeAttributionValue(value) {
2756
- return typeof value === 'string' ? value.trim().slice(0, 120) : '';
2757
- }
2758
- function __anGenerateAnalyticsAnonymousId() {
2759
- try {
2760
- if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') return crypto.randomUUID();
2761
- } catch(e) {}
2762
- return Date.now().toString(36) + Math.random().toString(36).slice(2) + Math.random().toString(36).slice(2);
2763
- }
2764
- function __anSyncAnalyticsAnonymousId() {
2765
- try {
2766
- var anonymousId = '';
2767
- try { anonymousId = localStorage.getItem('agent-native.anonymous_id') || ''; } catch(e) {}
2768
- if (!/^[A-Za-z0-9_-]{1,128}$/.test(anonymousId)) {
2769
- anonymousId = __anGenerateAnalyticsAnonymousId();
2770
- try { localStorage.setItem('agent-native.anonymous_id', anonymousId); } catch(e) {}
2771
- }
2772
- document.cookie = 'an_aid=' + encodeURIComponent(anonymousId) + '; path=/; max-age=2592000; SameSite=Lax';
2773
- } catch(e) {}
2774
- }
2775
- function __anFirstTouchCookiePresent() {
2776
- try {
2777
- return document.cookie.split(';').some(function(part) {
2778
- return part.trim().indexOf('an_ft=') === 0;
2779
- });
2780
- } catch(e) {
2781
- return false;
2782
- }
2783
- }
2784
- function __anWriteFirstTouchCookie(json) {
2785
- try {
2786
- document.cookie = 'an_ft=' + encodeURIComponent(json) + '; path=/; max-age=2592000; SameSite=Lax';
2787
- } catch(e) {}
2788
- }
2789
- function __anExternalReferrerHost(referrer) {
2790
- try {
2791
- var url = new URL(referrer);
2792
- if (url.host.toLowerCase() === window.location.host.toLowerCase()) return '';
2793
- return __anSafeAttributionValue(url.host);
2794
- } catch(e) {
2795
- return '';
2796
- }
2797
- }
2798
- function __anCaptureSignupAttribution() {
2799
- try {
2800
- var stored = '';
2801
- try { stored = localStorage.getItem('an_attribution') || ''; } catch(e) {}
2802
- if (stored) {
2803
- if (!__anFirstTouchCookiePresent()) __anWriteFirstTouchCookie(stored);
2804
- return;
2805
- }
2806
- if (__anFirstTouchCookiePresent()) return;
2807
- var params = new URLSearchParams(window.location.search || '');
2808
- var ft = {};
2809
- ['ref', 'via', 'utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term'].forEach(function(key) {
2810
- var value = __anSafeAttributionValue(params.get(key));
2811
- if (value) ft[key] = value;
2812
- });
2813
- var returnPath = __anJourney.normalizeAppPath(params.get('return'));
2814
- var landingPath = __anSafeAttributionValue(returnPath || window.location.pathname || '');
2815
- if (landingPath) ft.landing_path = landingPath;
2816
- var referrer = __anExternalReferrerHost(document.referrer || '');
2817
- if (referrer) ft.landing_referrer = referrer;
2818
- ft.landed_at = new Date().toISOString();
2819
- var json = JSON.stringify(ft);
2820
- try { localStorage.setItem('an_attribution', json); } catch(e) {}
2821
- __anWriteFirstTouchCookie(json);
2822
- } catch(e) {}
2823
- }
2824
- __anSyncAnalyticsAnonymousId();
2825
- __anCaptureSignupAttribution();
2826
- var __anBuilderPreviewSeen = false;
2827
- function __anRememberBuilderPreview() {
2828
- __anBuilderPreviewSeen = true;
2829
- try { sessionStorage.setItem('__an_builder_preview_seen', '1'); } catch(e) {}
2830
- }
2831
- function __anHasBuilderPreviewSignal() {
2832
- try {
2833
- var params = new URLSearchParams(window.location.search);
2834
- if (params.has('builder.preview') || params.has('builder.frameEditing') || params.has('__builder_editing__')) return true;
2835
- } catch(e) {}
2836
- return false;
2837
- }
2838
- function __anIsBuilderPreview() {
2839
- if (__anBuilderPreviewSeen) return true;
2840
- if (__anHasBuilderPreviewSignal()) {
2841
- __anRememberBuilderPreview();
2842
- return true;
2843
- }
2844
- try {
2845
- if (sessionStorage.getItem('__an_builder_preview_seen') === '1') {
2846
- __anBuilderPreviewSeen = true;
2847
- return true;
2848
- }
2849
- } catch(e) {}
2850
- try {
2851
- var ref = document.referrer || '';
2852
- var fromBuilder = ref.indexOf('builder.io') !== -1 || ref.indexOf('builder.my') !== -1 || ref.indexOf('builderio.xyz') !== -1 || ref.indexOf('builderio.dev') !== -1 || ref.indexOf('builder.codes') !== -1;
2853
- if (fromBuilder) __anRememberBuilderPreview();
2854
- return fromBuilder;
2855
- } catch(e) {
2856
- return false;
2857
- }
2858
- }
2859
- __anIsBuilderPreview();
2860
- function __anIsBuilderDesktop() {
2861
- try {
2862
- var ua = navigator.userAgent || '';
2863
- return ua.indexOf('Electron') !== -1 && ua.indexOf('AgentNativeDesktop') === -1;
2864
- } catch(e) {
2865
- return false;
2866
- }
2867
- }
2868
- function __anIsAgentNativeDesktop() {
2869
- try {
2870
- return (navigator.userAgent || '').indexOf('AgentNativeDesktop') !== -1;
2871
- } catch(e) {
2872
- return false;
2873
- }
2874
- }
2875
- function __anIsInFrame() {
2876
- try {
2877
- return window.self !== window.top;
2878
- } catch(e) {
2879
- return true;
2880
- }
2881
- }
2882
- function __anIsElectron() {
2883
- try {
2884
- return (navigator.userAgent || '').indexOf('Electron') !== -1;
2885
- } catch(e) {
2886
- return false;
2887
- }
2888
- }
2889
- function __anResolveAuthFlow() {
2890
- if (__anIsBuilderPreview()) return __anIsInFrame() ? 'popup' : 'redirect';
2891
- // Per-session override for ad-hoc testing outside Builder: append
2892
- // ?authMode=popup or ?authMode=redirect to the sign-in URL.
2893
- var qp = new URLSearchParams(window.location.search).get('authMode');
2894
- if (qp === 'popup' || qp === 'redirect') return qp;
2895
- var mode = __AN_GOOGLE_AUTH_MODE || 'auto';
2896
- if (mode === 'popup') return 'popup';
2897
- if (mode === 'redirect') return 'redirect';
2898
- return __anIsAgentNativeDesktop() ? 'redirect' : 'popup';
2899
- }
2900
- var __anOAuthPollTimer = null;
2901
- var __anOAuthPopupWatchTimer = null;
2902
- var __anOAuthPopupCloseGraceTimer = null;
2903
- var __anOAuthPopupCloseGraceMs = 5000;
2904
- var __anNativeOAuthFlowId = null;
2905
- var __anNativeOAuthRequestPending = false;
2906
- var __anNativeOAuthReturnObserved = false;
2907
- var __anNativeOAuthAbandonGraceTimer = null;
2908
- var __anNativeOAuthAbandonGraceMs = 5000;
2909
- var __anOAuthPollCount = 0;
2910
- var __anGoogleSignInInFlight = false;
2911
- var __anGoogleSignInFlowId = null;
2912
- var __anGoogleSignInRecoveryFlowId = null;
2913
- var __anMagicLinkInFlight = false;
2914
- var __anGoogleRecoverBound = false;
2915
- function __anNewOAuthFlowId() {
2916
- try {
2917
- if (window.crypto && typeof window.crypto.randomUUID === 'function') {
2918
- return window.crypto.randomUUID();
2919
- }
2920
- } catch(e) {}
2921
- return 'builder-' + Date.now().toString(36) + '-' + Math.random().toString(36).slice(2);
2922
- }
2923
- function __anNewOAuthVerifier() {
2924
- try {
2925
- if (window.crypto && typeof window.crypto.randomUUID === 'function') {
2926
- return window.crypto.randomUUID() + window.crypto.randomUUID();
2927
- }
2928
- if (window.crypto && typeof window.crypto.getRandomValues === 'function') {
2929
- var bytes = new Uint8Array(32);
2930
- window.crypto.getRandomValues(bytes);
2931
- var binary = '';
2932
- for (var i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);
2933
- return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');
2934
- }
2935
- } catch(e) { // coercion-ok: callers reject the empty verifier fallback.
2936
- }
2937
- return '';
2938
- }
2939
- function __anFlowDebugId(flowId) {
2940
- return flowId ? String(flowId).slice(-10) : '';
2941
- }
2942
- function __anSetOAuthDebug(message, flowId) {
2943
- var text = message + (flowId ? ' (flow ' + __anFlowDebugId(flowId) + ')' : '');
2944
- try {
2945
- console.info('[agent-native][google-oauth] ' + text);
2946
- } catch(e) {}
2947
- // Only surface the debug overlay when explicitly opted in via #oauth-debug
2948
- // hash or ?oauth_debug=1 query — otherwise it leaks raw flow IDs and
2949
- // diagnostic strings into the user-facing sign-in screen.
2950
- var showDebugOverlay = false;
2951
- try {
2952
- var loc = window.location || {};
2953
- showDebugOverlay =
2954
- (typeof loc.hash === 'string' && loc.hash.indexOf('oauth-debug') !== -1) ||
2955
- (typeof loc.search === 'string' && loc.search.indexOf('oauth_debug=1') !== -1);
2956
- } catch(e) {}
2957
- var debug = document.getElementById('google-debug');
2958
- if (debug) {
2959
- debug.textContent = text;
2960
- if (showDebugOverlay) debug.classList.add('show');
2961
- }
2962
- }
2963
- function __anStopOAuthExchangePolling() {
2964
- if (__anOAuthPollTimer) {
2965
- clearInterval(__anOAuthPollTimer);
2966
- __anOAuthPollTimer = null;
2967
- }
2968
- }
2969
- function __anStopOAuthPopupWatch() {
2970
- if (__anOAuthPopupWatchTimer) {
2971
- clearInterval(__anOAuthPopupWatchTimer);
2972
- __anOAuthPopupWatchTimer = null;
2973
- }
2974
- if (__anOAuthPopupCloseGraceTimer) {
2975
- clearTimeout(__anOAuthPopupCloseGraceTimer);
2976
- __anOAuthPopupCloseGraceTimer = null;
2977
- }
2978
- }
2979
- function __anStopNativeOAuthAbandonment() {
2980
- __anCancelNativeOAuthAbandonment();
2981
- __anNativeOAuthFlowId = null;
2982
- __anNativeOAuthRequestPending = false;
2983
- }
2984
- function __anCancelNativeOAuthAbandonment() {
2985
- if (__anNativeOAuthAbandonGraceTimer) {
2986
- clearTimeout(__anNativeOAuthAbandonGraceTimer);
2987
- __anNativeOAuthAbandonGraceTimer = null;
2988
- }
2989
- __anNativeOAuthReturnObserved = false;
2990
- }
2991
- function __anBeginNativeOAuth(flowId) {
2992
- __anStopNativeOAuthAbandonment();
2993
- __anNativeOAuthFlowId = flowId;
2994
- __anNativeOAuthRequestPending = true;
2995
- __anNativeOAuthReturnObserved = false;
2996
- }
2997
- function __anMarkNativeOAuthPolling(flowId) {
2998
- if (__anNativeOAuthFlowId !== flowId) return;
2999
- __anNativeOAuthRequestPending = false;
3000
- }
3001
- function __anIsCurrentNativeOAuth(flowId) {
3002
- return __anNativeOAuthFlowId === flowId && __anIsCurrentGoogleSignInFlow(flowId);
3003
- }
3004
- function __anFinalizeNativeOAuthAbandonment(flowId) {
3005
- if (!__anIsCurrentNativeOAuth(flowId) || !__anOAuthPollTimer) return;
3006
- if (document.visibilityState === 'hidden') {
3007
- __anCancelNativeOAuthAbandonment();
3008
- return;
3009
- }
3010
- __anStopNativeOAuthAbandonment();
3011
- if (__anInvalidateGoogleSignInFlow(flowId)) {
3012
- __anStopOAuthExchangePolling();
3013
- __anRecoverGoogleSignInAfterReturn(flowId);
3014
- }
3015
- }
3016
- function __anScheduleNativeOAuthAbandonment(flowId) {
3017
- // Returning focus is the only signal that the system-browser ceremony was
3018
- // abandoned. Preserve the exchange poll briefly for a late deep-link.
3019
- if (
3020
- !__anIsCurrentNativeOAuth(flowId) ||
3021
- __anNativeOAuthRequestPending ||
3022
- !__anNativeOAuthReturnObserved ||
3023
- !__anOAuthPollTimer ||
3024
- __anNativeOAuthAbandonGraceTimer
3025
- ) return;
3026
- __anNativeOAuthAbandonGraceTimer = setTimeout(function() {
3027
- __anNativeOAuthAbandonGraceTimer = null;
3028
- __anFinalizeNativeOAuthAbandonment(flowId);
3029
- }, __anNativeOAuthAbandonGraceMs);
3030
- }
3031
- function __anBeginGoogleSignInFlow(flowId) {
3032
- __anGoogleSignInFlowId = flowId;
3033
- __anGoogleSignInRecoveryFlowId = null;
3034
- __anGoogleSignInInFlight = true;
3035
- }
3036
- function __anIsCurrentGoogleSignInFlow(flowId) {
3037
- return __anGoogleSignInInFlight && __anGoogleSignInFlowId === flowId;
3038
- }
3039
- function __anClearGoogleSignInFlow() {
3040
- __anGoogleSignInFlowId = null;
3041
- __anGoogleSignInRecoveryFlowId = null;
3042
- }
3043
- function __anInvalidateGoogleSignInFlow(flowId) {
3044
- if (!__anIsCurrentGoogleSignInFlow(flowId)) return false;
3045
- __anGoogleSignInFlowId = null;
3046
- __anGoogleSignInRecoveryFlowId = flowId;
3047
- return true;
3048
- }
3049
- function __anCanRecoverGoogleSignInFlow(flowId, expectedFlowId) {
3050
- // Focus can return while either the system-browser exchange or the popup
3051
- // exchange is still active. Let that exchange finish before recovering.
3052
- if (!flowId && (__anNativeOAuthFlowId || __anOAuthPollTimer || __anOAuthPopupWatchTimer)) return false;
3053
- if (flowId) {
3054
- return __anGoogleSignInInFlight &&
3055
- !__anGoogleSignInFlowId &&
3056
- __anGoogleSignInRecoveryFlowId === flowId;
3057
- }
3058
- return __anGoogleSignInInFlight && __anGoogleSignInFlowId === expectedFlowId;
3059
- }
3060
- function __anFinalizeOAuthPopupClose(flowId) {
3061
- if (!__anIsCurrentGoogleSignInFlow(flowId)) return;
3062
- __anOAuthPopupCloseGraceTimer = null;
3063
- if (__anInvalidateGoogleSignInFlow(flowId)) {
3064
- __anStopOAuthExchangePolling();
3065
- __anRecoverGoogleSignInAfterReturn(flowId);
3066
- }
3067
- }
3068
- function __anHandleOAuthPopupClosed(flowId) {
3069
- __anStopOAuthPopupWatch();
3070
- // The success callback closes its tab 250ms after staging the token, but
3071
- // the opener polls once per second. Let an active exchange win that race.
3072
- if (__anOAuthPollTimer) {
3073
- __anOAuthPopupCloseGraceTimer = setTimeout(function() {
3074
- __anFinalizeOAuthPopupClose(flowId);
3075
- }, __anOAuthPopupCloseGraceMs);
3076
- return;
3077
- }
3078
- __anFinalizeOAuthPopupClose(flowId);
3079
- }
3080
- function __anWatchOAuthPopupClose(popup, flowId) {
3081
- __anStopOAuthPopupWatch();
3082
- __anOAuthPopupWatchTimer = setInterval(function() {
3083
- if (!__anIsCurrentGoogleSignInFlow(flowId)) {
3084
- __anStopOAuthPopupWatch();
3085
- return;
3086
- }
3087
- var closed = false;
3088
- try {
3089
- closed = popup.closed === true;
3090
- } catch(e) {
3091
- __anHandleOAuthPopupClosed(flowId);
3092
- return;
3093
- }
3094
- if (!closed) return;
3095
- __anHandleOAuthPopupClosed(flowId);
3096
- }, 500);
3097
- }
3098
- function __anShowAuthExchangeError(err, btn, message, kind) {
3099
- __anStopOAuthExchangePolling();
3100
- __anStopOAuthPopupWatch();
3101
- __anStopNativeOAuthAbandonment();
3102
- err.textContent = message;
3103
- err.classList.add('show', 'error');
3104
- btn.disabled = false;
3105
- if (kind === 'magic-link') {
3106
- __anMagicLinkInFlight = false;
3107
- showMagicLinkForm();
3108
- } else {
3109
- __anGoogleSignInInFlight = false;
3110
- __anClearGoogleSignInFlow();
3111
- }
3112
- }
3113
- function __anShowOAuthError(err, btn, message) {
3114
- __anShowAuthExchangeError(err, btn, message, 'google');
3115
- }
3116
- function __anRecoverGoogleSignInAfterReturn(flowId) {
3117
- // The user left for the Google sign-in window and came back. If the flow
3118
- // never completed (e.g. they closed the window to switch profiles), the
3119
- // button is stuck disabled with no error path firing for up to 5 minutes.
3120
- // Re-enable it so they can retry. Wait briefly first so a genuinely
3121
- // in-flight exchange can still finish and navigate without a flicker.
3122
- if (!flowId && __anNativeOAuthFlowId) {
3123
- __anNativeOAuthReturnObserved = true;
3124
- __anScheduleNativeOAuthAbandonment(__anNativeOAuthFlowId);
3125
- return;
3126
- }
3127
- var expectedFlowId = flowId || __anGoogleSignInFlowId;
3128
- if (!__anCanRecoverGoogleSignInFlow(flowId, expectedFlowId)) return;
3129
- setTimeout(function() {
3130
- if (!__anCanRecoverGoogleSignInFlow(flowId, expectedFlowId)) return;
3131
- __anMaybeRedirectSignedIn(__anResumeHref()).then(function(redirected) {
3132
- if (!__anCanRecoverGoogleSignInFlow(flowId, expectedFlowId)) return;
3133
- if (redirected) return;
3134
- var btn = document.getElementById('google-btn');
3135
- if (!btn || !btn.disabled) return;
3136
- // Keep the desktop-exchange poll alive. Agent-Native Desktop opens
3137
- // Google in the system browser, so focus can return before the
3138
- // callback has stored the session token.
3139
- btn.disabled = false;
3140
- __anGoogleSignInInFlight = false;
3141
- __anClearGoogleSignInFlow();
3142
- });
3143
- }, 1200);
3144
- }
3145
- function __anBindGoogleRecover() {
3146
- if (__anGoogleRecoverBound) return;
3147
- __anGoogleRecoverBound = true;
3148
- window.addEventListener('focus', function() {
3149
- __anRecoverGoogleSignInAfterReturn();
3150
- });
3151
- window.addEventListener('blur', function() {
3152
- __anCancelNativeOAuthAbandonment();
3153
- });
3154
- document.addEventListener('visibilitychange', function() {
3155
- if (document.visibilityState === 'visible') {
3156
- __anRecoverGoogleSignInAfterReturn();
3157
- } else {
3158
- __anCancelNativeOAuthAbandonment();
3159
- }
3160
- });
3161
- }
3162
- function __anHandlePopupOAuthFailure(ret, btn, err, flowId, redirectReason, builderFrameMessage) {
3163
- if (__anIsBuilderPreview() && __anIsInFrame()) {
3164
- __anShowOAuthError(err, btn, builderFrameMessage + ' ' + __anT('googlePopupHelp') + ' (flow ' + __anFlowDebugId(flowId) + ').');
3165
- return;
3166
- }
3167
- __anStartRedirectOAuth(ret, btn, err, flowId, redirectReason);
3168
- }
3169
- function __anStartRedirectOAuth(ret, btn, err, flowId, reason) {
3170
- var params = new URLSearchParams();
3171
- var oauthReturn = __anIsBuilderPreview() ? __anOAuthReturnTarget(ret) : ret;
3172
- if (oauthReturn) params.set('return', oauthReturn);
3173
- params.set('redirect', '1');
3174
- __anSetOAuthDebug(reason || 'Opening Google sign-in redirect', flowId);
3175
- try {
3176
- __anOpenOAuthUrl(__anGoogleAuthUrlPath() + '?' + params.toString());
3177
- } catch(e) {
3178
- __anShowOAuthError(err, btn, __anT('failedToConnect'));
3179
- }
3180
- }
3181
- function __anWaitForOAuthExchange(flowId, ret, btn, err, kind, verifier) {
3182
- var started = Date.now();
3183
- var timeoutMs = 5 * 60 * 1000;
3184
- var isMagicLink = kind === 'magic-link';
3185
- __anOAuthPollCount = 0;
3186
- async function check() {
3187
- if (!isMagicLink && !__anIsCurrentGoogleSignInFlow(flowId)) return;
3188
- __anOAuthPollCount++;
3189
- try {
3190
- var exchangeParams = '?flow_id=' + encodeURIComponent(flowId);
3191
- var exchangeOptions = { credentials: 'include' };
3192
- if (verifier) {
3193
- exchangeOptions.headers = { 'X-Agent-Native-Desktop-Verifier': verifier };
3194
- }
3195
- var res = await fetch(__anPath('/_agent-native/auth/desktop-exchange') + exchangeParams, exchangeOptions);
3196
- var data = await res.json().catch(function() { return {}; });
3197
- if (!isMagicLink && !__anIsCurrentGoogleSignInFlow(flowId)) return;
3198
- if (data && (data.email || data.token)) {
3199
- if (__anOAuthPollTimer) clearInterval(__anOAuthPollTimer);
3200
- __anOAuthPollTimer = null;
3201
- __anFinishOAuthExchange(ret, flowId, data.token);
3202
- return;
3203
- }
3204
- if (data && data.error) {
3205
- __anSetOAuthDebug('OAuth exchange returned an error: ' + (data.message || data.error), flowId);
3206
- __anShowAuthExchangeError(
3207
- err,
3208
- btn,
3209
- __anAuthErrorText(data, isMagicLink ? __anT('magicLinkFailed') : __anT('googleNotConfigured')),
3210
- isMagicLink ? 'magic-link' : 'google',
3211
- );
3212
- return;
3213
- }
3214
- if (data && data.pending && (__anOAuthPollCount === 1 || __anOAuthPollCount % 5 === 0)) {
3215
- __anSetOAuthDebug('Waiting for the Google callback; polling attempt ' + __anOAuthPollCount, flowId);
3216
- }
3217
- } catch(e) {
3218
- if (__anOAuthPollCount === 1 || __anOAuthPollCount % 5 === 0) {
3219
- __anSetOAuthDebug('Could not reach the OAuth exchange endpoint: ' + (e && e.message ? e.message : 'network error'), flowId);
3220
- }
3221
- }
3222
- if (Date.now() - started > timeoutMs) {
3223
- __anShowAuthExchangeError(
3224
- err,
3225
- btn,
3226
- isMagicLink
3227
- ? __anT('magicLinkFailed')
3228
- : __anT('googleNeverFinished') + ' Flow ' + __anFlowDebugId(flowId) + '.',
3229
- isMagicLink ? 'magic-link' : 'google',
3230
- );
3231
- }
3232
- }
3233
- __anStopOAuthExchangePolling();
3234
- __anOAuthPollTimer = setInterval(check, 1000);
3235
- setTimeout(check, 500);
3236
- }
3237
- async function __anRequestDesktopOAuthUrl(flowId, verifier, oauthReturn) {
3238
- var params = new URLSearchParams();
3239
- if (oauthReturn) params.set('return', oauthReturn);
3240
- params.set('desktop', '1');
3241
- params.set('flow_id', flowId);
3242
- var res = await fetch(__anGoogleAuthUrlPath() + '?' + params.toString(), {
3243
- method: 'POST',
3244
- credentials: 'include',
3245
- headers: {
3246
- 'Accept': 'application/json',
3247
- 'X-Agent-Native-Desktop-Verifier': verifier
3248
- }
3249
- });
3250
- var data;
3251
- try {
3252
- data = await res.json();
3253
- } catch(e) {
3254
- throw new Error(__anT('failedToConnect'));
3255
- }
3256
- if (!res.ok || !data || typeof data.url !== 'string' || !data.url) {
3257
- throw new Error(__anAuthErrorText(data, __anT('failedToConnect')));
3258
- }
3259
- return data.url;
3260
- }
3261
- function __anStartPopupOAuth(ret, btn, err, flowId) {
3262
- var verifier = __anNewOAuthVerifier();
3263
- if (!verifier) {
3264
- __anShowOAuthError(err, btn, __anT('failedToConnect'));
3265
- return;
3266
- }
3267
- var oauthReturn = __anIsBuilderPreview() ? __anOAuthReturnTarget(ret) : ret;
3268
- try { sessionStorage.setItem('__an_signin', '1'); } catch(e) {}
3269
- __anSetOAuthDebug('Opening Google sign-in popup', flowId);
3270
- var popup;
3271
- try {
3272
- popup = window.open('', '_blank', 'width=640,height=760');
3273
- if (!popup) {
3274
- __anHandlePopupOAuthFailure(ret, btn, err, flowId, 'Google popup was blocked; falling back to redirect', 'Google popup was blocked.');
3275
- return;
3276
- }
3277
- try { popup.opener = null; } catch(e) {}
3278
- __anWatchOAuthPopupClose(popup, flowId);
3279
- } catch(e) {
3280
- __anHandlePopupOAuthFailure(ret, btn, err, flowId, 'Could not open Google popup; falling back to redirect', 'Could not open Google popup.');
3281
- return;
3282
- }
3283
- __anRequestDesktopOAuthUrl(flowId, verifier, oauthReturn).then(function(url) {
3284
- if (!__anIsCurrentGoogleSignInFlow(flowId)) return;
3285
- try {
3286
- popup.location.href = url;
3287
- __anSetOAuthDebug('Google popup opened; waiting for callback', flowId);
3288
- __anWaitForOAuthExchange(flowId, ret, btn, err, 'google', verifier);
3289
- } catch(e) {
3290
- throw e;
3291
- }
3292
- }).catch(function(e) {
3293
- if (!__anIsCurrentGoogleSignInFlow(flowId)) return;
3294
- try { popup.close(); } catch(closeErr) {}
3295
- __anShowOAuthError(err, btn, e && e.message ? e.message : __anT('failedToConnect'));
3296
- });
3297
- }
3298
- function __anStartNativeDesktopOAuth(ret, btn, err, flowId) {
3299
- var verifier = __anNewOAuthVerifier();
3300
- if (!verifier) {
3301
- __anShowOAuthError(err, btn, __anT('failedToConnect'));
3302
- return;
3303
- }
3304
- var oauthReturn = ret;
3305
- __anBeginNativeOAuth(flowId);
3306
- __anSetOAuthDebug('Preparing Google sign-in in system browser', flowId);
3307
- __anRequestDesktopOAuthUrl(flowId, verifier, oauthReturn).then(function(url) {
3308
- if (!__anIsCurrentGoogleSignInFlow(flowId)) return;
3309
- __anMarkNativeOAuthPolling(flowId);
3310
- __anSetOAuthDebug('Opening Google sign-in in system browser', flowId);
3311
- __anOpenOAuthUrl(url);
3312
- __anWaitForOAuthExchange(flowId, ret, btn, err, 'google', verifier);
3313
- __anScheduleNativeOAuthAbandonment(flowId);
3314
- }).catch(function(e) {
3315
- if (!__anIsCurrentGoogleSignInFlow(flowId)) return;
3316
- __anShowOAuthError(err, btn, e && e.message ? e.message : __anT('failedToConnect'));
3317
- });
3318
- }
3319
- function __anOpenOAuthUrl(url) {
3320
- try { sessionStorage.setItem('__an_signin', '1'); } catch(e) {}
3321
- window.location.href = url;
3322
- }
3323
- (function revealLocalNote() {
3324
- var h = location.hostname;
3325
- if (h === 'localhost' || h === '127.0.0.1' || h === '::1' || h.endsWith('.local')) {
3326
- var n = document.getElementById('local-note');
3327
- if (n) n.classList.add('show');
3328
- }
3329
- })();
3330
- (function revealUpgradeNote() {
3331
- var shouldShow = false;
3332
- try {
3333
- var params = new URLSearchParams(location.search);
3334
- shouldShow = params.get('signin') === '1' || params.get('upgrade-from-local') === '1';
3335
- } catch(e) {}
3336
- if (!shouldShow) {
3337
- try { shouldShow = localStorage.getItem('an_migrate_from_local') === '1'; } catch(e) {}
3338
- }
3339
- if (!shouldShow) return;
3340
- var n = document.getElementById('upgrade-note');
3341
- if (!n) return;
3342
- n.textContent = n.getAttribute('data-upgrade-copy') || __anT('migrateLocalFallback');
3343
- n.classList.add('show');
3344
- })();
3345
- ${googleOnly
3346
- ? ""
3347
- : ` var TAB_STORAGE_KEY = 'an.onboarding.tab';
3348
- var tabs = document.querySelectorAll('.tab');
3349
- var forms = document.querySelectorAll('.form');
3350
- var pendingSignupEmail = '';
3351
- var pendingSignupPassword = '';
3352
- var verificationCheckInFlight = false;
3353
- var RESEND_VERIFICATION_COOLDOWN_SECONDS = 60;
3354
- var resendVerificationCooldownUntil = 0;
3355
- var resendVerificationCooldownTimer = null;
3356
- var PENDING_SIGNUP_EMAIL_STORAGE_KEY = 'an.onboarding.pendingSignupEmail';
3357
- // The verification link can open in a new tab, so in-memory pending state
3358
- // cannot be the only source of the account email. Keep only the address,
3359
- // never the password, for the manual-login fallback.
3360
- function pendingSignupEmailStorageKey() {
3361
- return PENDING_SIGNUP_EMAIL_STORAGE_KEY + ':' + (__anBasePath() || '/');
3362
- }
3363
- function rememberPendingSignupEmail(email) {
3364
- try {
3365
- if (email) localStorage.setItem(pendingSignupEmailStorageKey(), email);
3366
- else localStorage.removeItem(pendingSignupEmailStorageKey());
3367
- // coercion-ok: localStorage is optional; the in-memory and form fallbacks remain available.
3368
- } catch (e) {}
3369
- }
3370
- function readRememberedPendingSignupEmail() {
3371
- try {
3372
- var email = localStorage.getItem(pendingSignupEmailStorageKey()) || '';
3373
- return __anIsValidAuthEmail(email) ? __anNormalizeAuthEmail(email) : '';
3374
- // coercion-ok: localStorage is optional; callers fall back to the in-memory or form value.
3375
- } catch (e) {
3376
- return '';
3377
- }
3378
- }
3379
- function clearRememberedPendingSignupEmail() {
3380
- rememberPendingSignupEmail('');
3381
- }
3382
- function hideMagicLinkSuccess() {
3383
- var card = document.querySelector('.card');
3384
- if (card) card.classList.remove('magic-link-complete');
3385
- var success = document.getElementById('magic-link-success');
3386
- if (success) {
3387
- success.classList.remove('is-visible');
3388
- success.setAttribute('hidden', '');
3389
- }
3390
- }
3391
- function showMagicLinkSuccess(email) {
3392
- var card = document.querySelector('.card');
3393
- if (card) card.classList.add('magic-link-complete');
3394
- var success = document.getElementById('magic-link-success');
3395
- var successEmail = document.getElementById('magic-link-success-email');
3396
- if (successEmail && typeof email === 'string') successEmail.textContent = email;
3397
- if (success) {
3398
- success.removeAttribute('hidden');
3399
- success.classList.add('is-visible');
3400
- }
3401
- forms.forEach(function(x) { x.classList.remove('active'); });
3402
- var authTabs = document.getElementById('auth-tabs');
3403
- if (authTabs) authTabs.hidden = true;
3404
- __anSetAuthView('magicLinkSent');
3405
- }
3406
- function showMagicLinkForm() {
3407
- __anStopOAuthExchangePolling();
3408
- __anMagicLinkInFlight = false;
3409
- var form = document.getElementById('magic-link-form');
3410
- if (!form) return;
3411
- hideMagicLinkSuccess();
3412
- forms.forEach(function(x) { x.classList.remove('active'); });
3413
- form.classList.add('active');
3414
- var authTabs = document.getElementById('auth-tabs');
3415
- if (authTabs) authTabs.hidden = true;
3416
- updateMagicLinkSubmitState();
3417
- __anSetAuthView('magicLink');
3418
- }
3419
- function updateMagicLinkSubmitState() {
3420
- var emailInput = document.getElementById('m-email');
3421
- var button = document.getElementById('magic-link-submit');
3422
- if (!emailInput || !button) return;
3423
- var isValid = __anIsValidAuthEmail(emailInput.value);
3424
- button.disabled = !isValid;
3425
- var googleButton = document.getElementById('google-btn');
3426
- if (googleButton) googleButton.classList.toggle('magic-link-secondary', isValid);
3427
- }
3428
- function setActiveTab(name, opts) {
3429
- if (name !== 'signup' && name !== 'login') return;
3430
- var form = document.getElementById(name + '-form');
3431
- if (!form) return;
3432
- var card = document.querySelector('.card');
3433
- if (card) card.classList.remove('verifying');
3434
- var authTabs = document.getElementById('auth-tabs');
3435
- if (authTabs) authTabs.hidden = false;
3436
- tabs.forEach(function(x) { x.classList.remove('active'); });
3437
- forms.forEach(function(x) { x.classList.remove('active'); });
3438
- var btn = document.querySelector('.tab[data-tab="' + name + '"]');
3439
- if (btn) btn.classList.add('active');
3440
- form.classList.add('active');
3441
- __anSetAuthView(name);
3442
- if (opts && opts.persist) {
3443
- try { localStorage.setItem(TAB_STORAGE_KEY, name); } catch (e) {}
3444
- }
3445
- }
3446
- function showVerificationStep(email, password) {
3447
- pendingSignupEmail = email || '';
3448
- pendingSignupPassword = password || '';
3449
- rememberPendingSignupEmail(pendingSignupEmail);
3450
- tabs.forEach(function(x) { x.classList.remove('active'); });
3451
- forms.forEach(function(x) { x.classList.remove('active'); });
3452
- var card = document.querySelector('.card');
3453
- if (card) card.classList.add('verifying');
3454
- var step = document.getElementById('verification-step');
3455
- if (step) step.classList.add('active');
3456
- var emailNode = document.getElementById('verify-email');
3457
- if (emailNode) emailNode.textContent = pendingSignupEmail;
3458
- __anSetAuthView('verification');
3459
- var msg = document.getElementById('verify-msg');
3460
- if (msg) {
3461
- msg.classList.remove('show', 'error', 'success');
3462
- msg.textContent = '';
3463
- }
3464
- try { localStorage.setItem(TAB_STORAGE_KEY, 'signup'); } catch (e) {}
3465
- }
3466
- function getVerificationMessageNode() {
3467
- var verifyStep = document.getElementById('verification-step');
3468
- if (verifyStep && verifyStep.classList.contains('active')) {
3469
- return document.getElementById('verify-msg');
3470
- }
3471
- return document.getElementById('l-msg') || document.getElementById('verify-msg');
3472
- }
3473
- function isVerificationStepActive() {
3474
- var verifyStep = document.getElementById('verification-step');
3475
- return !!(verifyStep && verifyStep.classList.contains('active'));
3476
- }
3477
- function getPendingSignupEmail() {
3478
- var signupEmail = document.getElementById('s-email');
3479
- var loginEmail = document.getElementById('l-email');
3480
- return (pendingSignupEmail || readRememberedPendingSignupEmail() || (signupEmail && signupEmail.value) || (loginEmail && loginEmail.value) || '').trim();
3481
- }
3482
- function getPendingSignupPassword() {
3483
- var signupPassword = document.getElementById('s-pass');
3484
- return pendingSignupPassword || (signupPassword && signupPassword.value) || '';
3485
- }
3486
- function __anNormalizeAuthEmail(value) {
3487
- return String(value || '').trim().toLowerCase();
3488
- }
3489
- function __anIsValidAuthEmail(value) {
3490
- return /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(__anNormalizeAuthEmail(value));
3491
- }
3492
- function __anIsVerifiedRedirectSuccess() {
3493
- try {
3494
- var params = new URLSearchParams(location.search);
3495
- return params.has('verified') && !params.has('error');
3496
- } catch (e) {
3497
- return false;
3498
- }
3499
- }
3500
- function __anVerificationRedirectError() {
3501
- try {
3502
- var params = new URLSearchParams(location.search);
3503
- return params.get('error') === 'verification_link_invalid'
3504
- ? __anT('verificationLinkInvalid')
3505
- : '';
3506
- } catch (e) { // coercion-ok: malformed query has no verification error to render
3507
- return '';
3508
- }
3509
- }
3510
- function __anShowEmailValidationError(input, msg) {
3511
- if (msg) {
3512
- msg.textContent = __anT('invalidEmail');
3513
- msg.classList.add('show', 'error');
3514
- }
3515
- if (input && typeof input.focus === 'function') input.focus();
3516
- }
3517
- function movePendingSignupToLogin(message) {
3518
- var email = getPendingSignupEmail();
3519
- setActiveTab('login', { persist: true });
3520
- var loginEmail = document.getElementById('l-email');
3521
- var loginPassword = document.getElementById('l-pass');
3522
- var msg = document.getElementById('l-msg');
3523
- if (loginEmail && email) loginEmail.value = email;
3524
- if (msg) {
3525
- msg.textContent = message || __anT('signInToContinue');
3526
- msg.classList.remove('error');
3527
- msg.classList.add('show', 'success');
3528
- }
3529
- setTimeout(function() { if (loginPassword) loginPassword.focus(); }, 0);
3530
- }
3531
- async function signInWithPendingSignup() {
3532
- var email = getPendingSignupEmail();
3533
- var password = getPendingSignupPassword();
3534
- if (!email || !password) {
3535
- return { ok: false, needsManualSignIn: true };
3536
- }
3537
- var res = await fetch(__anPath('/_agent-native/auth/login'), {
3538
- method: 'POST',
3539
- headers: { 'Content-Type': 'application/json' },
3540
- body: JSON.stringify({ email: email, password: password }),
3541
- });
3542
- if (res.ok) {
3543
- clearRememberedPendingSignupEmail();
3544
- __anRedirectToSignedInApp();
3545
- return { ok: true };
3546
- }
3547
- var data = await res.json().catch(function(error) {
3548
- console.warn('[auth] Could not parse sign-in response', error);
3549
- return null;
3550
- });
3551
- var error = __anAuthErrorText(data, __anT('finishSignInFailed'));
3552
- return {
3553
- ok: false,
3554
- error: error,
3555
- isWaitingForVerification: /not verified|verification/i.test(error),
3556
- };
3557
- }
3558
- async function checkVerificationSession(fallbackText, opts) {
3559
- opts = opts || {};
3560
- if (verificationCheckInFlight) return;
3561
- verificationCheckInFlight = true;
3562
- var msg = getVerificationMessageNode();
3563
- var continueBtn = document.getElementById('verify-continue');
3564
- if (continueBtn && !opts.silent) {
3565
- continueBtn.disabled = true;
3566
- continueBtn.textContent = __anT('checking');
3567
- }
3568
- if (msg && !opts.silent) {
3569
- msg.textContent = __anT('checkingVerification');
3570
- msg.classList.remove('error');
3571
- msg.classList.add('show', 'success');
3572
- }
3573
- try {
3574
- var res = await fetch(__anPath('/_agent-native/auth/session'), {
3575
- headers: { 'Accept': 'application/json' },
3576
- });
3577
- var data = await res.json().catch(function() { return {}; });
3578
- if (res.ok && data && data.email && !data.error) {
3579
- clearRememberedPendingSignupEmail();
3580
- __anRedirectToSignedInApp();
3581
- return;
3582
- }
3583
- var loginResult = await signInWithPendingSignup();
3584
- if (loginResult.ok) return;
3585
- if (loginResult.needsManualSignIn) {
3586
- if (!opts.silent) {
3587
- movePendingSignupToLogin(fallbackText || __anT('enterPasswordAfterVerification'));
3588
- }
3589
- return;
3590
- }
3591
- if (loginResult.error && !loginResult.isWaitingForVerification) {
3592
- if (!opts.silent) {
3593
- movePendingSignupToLogin(__anT('finishSignInManually'));
3594
- }
3595
- return;
3596
- }
3597
- if (msg && !opts.silent) {
3598
- msg.textContent = fallbackText || __anT('stillWaitingVerification');
3599
- msg.classList.remove('success');
3600
- msg.classList.add('show', 'error');
3601
- }
3602
- } catch (err) {
3603
- if (msg && !opts.silent) {
3604
- msg.textContent = __anT('checkVerificationFailed');
3605
- msg.classList.remove('success');
3606
- msg.classList.add('show', 'error');
3607
- }
3608
- } finally {
3609
- verificationCheckInFlight = false;
3610
- if (continueBtn && !opts.silent) {
3611
- continueBtn.disabled = false;
3612
- continueBtn.textContent = __anT('continue');
3613
- }
3614
- }
3615
- }
3616
- function maybeCompleteVerificationAfterReturn() {
3617
- if (!isVerificationStepActive()) return;
3618
- checkVerificationSession(null, { silent: true });
3619
- }
3620
- function updateResendVerificationCooldown() {
3621
- var btn = document.getElementById('resend-verification');
3622
- if (!btn) return;
3623
- var remaining = Math.ceil((resendVerificationCooldownUntil - Date.now()) / 1000);
3624
- if (remaining > 0) {
3625
- btn.disabled = true;
3626
- btn.textContent = __anT('resendEmail') + ' (' + remaining + 's)';
3627
- return;
3628
- }
3629
- if (resendVerificationCooldownTimer) {
3630
- clearInterval(resendVerificationCooldownTimer);
3631
- resendVerificationCooldownTimer = null;
3632
- }
3633
- resendVerificationCooldownUntil = 0;
3634
- btn.disabled = false;
3635
- btn.textContent = __anT('resendEmail');
3636
- }
3637
- function startResendVerificationCooldown(seconds) {
3638
- resendVerificationCooldownUntil = Date.now() + seconds * 1000;
3639
- updateResendVerificationCooldown();
3640
- if (resendVerificationCooldownTimer) clearInterval(resendVerificationCooldownTimer);
3641
- resendVerificationCooldownTimer = setInterval(updateResendVerificationCooldown, 1000);
3642
- }
3643
- async function resendVerificationEmail() {
3644
- var btn = document.getElementById('resend-verification');
3645
- var msg = document.getElementById('verify-msg');
3646
- var email = getPendingSignupEmail();
3647
- if (!email) return;
3648
- if (resendVerificationCooldownUntil > Date.now()) {
3649
- updateResendVerificationCooldown();
3650
- return;
3651
- }
3652
- var original = btn ? btn.textContent : '';
3653
- if (btn) {
3654
- btn.disabled = true;
3655
- btn.textContent = __anT('sending');
3656
- }
3657
- if (msg) msg.classList.remove('show', 'error', 'success');
3658
- try {
3659
- var res = await fetch(__anPath('/_agent-native/auth/ba/send-verification-email'), {
3660
- method: 'POST',
3661
- headers: { 'Content-Type': 'application/json' },
3662
- body: JSON.stringify({ email: email, callbackURL: __anResumeHref() }),
3663
- });
3664
- if (res.ok) {
3665
- if (msg) {
3666
- msg.textContent = __anT('sentVerification');
3667
- msg.classList.add('show', 'success');
3668
- }
3669
- startResendVerificationCooldown(RESEND_VERIFICATION_COOLDOWN_SECONDS);
3670
- return;
3671
- }
3672
- var data = await res.json().catch(function() { return {}; });
3673
- if (msg) {
3674
- msg.textContent = __anAuthErrorText(data, __anT('resendVerificationFailed'));
3675
- msg.classList.add('show', 'error');
3676
- }
3677
- if (btn) {
3678
- btn.disabled = false;
3679
- btn.textContent = original;
3680
- }
3681
- } catch (err) {
3682
- if (msg) {
3683
- msg.textContent = __anT('networkErrorRetry');
3684
- msg.classList.add('show', 'error');
3685
- }
3686
- if (btn) {
3687
- btn.disabled = false;
3688
- btn.textContent = original;
3689
- }
3690
- }
3691
- }
3692
- (function initActiveTab() {
3693
- var initial = __AN_AUTH_MODE === 'magic-link' ? 'magicLink' : 'signup';
3694
- var verificationError = __anVerificationRedirectError();
3695
- try {
3696
- var params = new URLSearchParams(location.search);
3697
- var qp = params.get('tab');
3698
- var path = location.pathname;
3699
- while (path.length > 1 && path.charAt(path.length - 1) === '/') path = path.slice(0, -1);
3700
- if (qp === 'login' || qp === 'signup') {
3701
- initial = qp;
3702
- } else if (__anIsVerifiedRedirectSuccess()) {
3703
- initial = 'login';
3704
- } else if (verificationError) {
3705
- initial = 'login';
3706
- } else if (path === '/login' || path.endsWith('/login')) {
3707
- initial = 'login';
3708
- } else if (path === '/signup' || path.endsWith('/signup')) {
3709
- initial = 'signup';
3710
- } else if (__AN_AUTH_MODE !== 'magic-link') {
3711
- var stored = localStorage.getItem(TAB_STORAGE_KEY);
3712
- if (stored === 'login' || stored === 'signup') initial = stored;
3713
- }
3714
- } catch (e) {}
3715
- if (initial === 'magicLink') showMagicLinkForm();
3716
- else setActiveTab(initial, { persist: false });
3717
- if (verificationError) {
3718
- var verificationMsg = document.getElementById('l-msg');
3719
- if (verificationMsg) {
3720
- verificationMsg.textContent = verificationError;
3721
- verificationMsg.classList.add('show', 'error');
3722
- }
3723
- }
3724
- try {
3725
- if (__anIsVerifiedRedirectSuccess()) {
3726
- var rememberedEmail = readRememberedPendingSignupEmail();
3727
- var loginEmail = document.getElementById('l-email');
3728
- if (loginEmail && rememberedEmail) loginEmail.value = rememberedEmail;
3729
- var msg = document.getElementById('l-msg');
3730
- if (msg) {
3731
- msg.textContent = __anT('emailVerifiedFinishing');
3732
- msg.classList.remove('error');
3733
- msg.classList.add('show', 'success');
3734
- }
3735
- checkVerificationSession(__anT('emailVerifiedSignIn'));
3736
- }
3737
- } catch (e) {}
3738
- })();
3739
- tabs.forEach(function(t) { t.addEventListener('click', function() {
3740
- setActiveTab(t.dataset.tab, { persist: true });
3741
- }); });
3742
-
3743
- var usePasswordLink = document.getElementById('use-password-link');
3744
- if (usePasswordLink) usePasswordLink.addEventListener('click', function(e) {
3745
- e.preventDefault();
3746
- setActiveTab('login', { persist: false });
3747
- var magicEmail = document.getElementById('m-email');
3748
- var loginEmail = document.getElementById('l-email');
3749
- if (magicEmail && loginEmail && magicEmail.value) loginEmail.value = magicEmail.value;
3750
- });
3751
- var backToMagicLink = document.getElementById('back-to-magic-link');
3752
- if (backToMagicLink) backToMagicLink.addEventListener('click', function(e) {
3753
- e.preventDefault();
3754
- showMagicLinkForm();
3755
- });
3756
- var magicLinkBack = document.getElementById('magic-link-back');
3757
- if (magicLinkBack) magicLinkBack.addEventListener('click', function(e) {
3758
- e.preventDefault();
3759
- var magicLinkEmailInput = document.getElementById('m-email');
3760
- if (magicLinkEmailInput) magicLinkEmailInput.value = '';
3761
- showMagicLinkForm();
3762
- if (magicLinkEmailInput) magicLinkEmailInput.focus();
3763
- });
3764
-
3765
- var magicLinkForm = document.getElementById('magic-link-form');
3766
- __anBindPasswordValidation(document.getElementById('s-pass'));
3767
- __anBindPasswordValidation(document.getElementById('s-pass2'));
3768
- var magicLinkEmail = document.getElementById('m-email');
3769
- if (magicLinkEmail) {
3770
- magicLinkEmail.addEventListener('input', updateMagicLinkSubmitState);
3771
- magicLinkEmail.addEventListener('change', updateMagicLinkSubmitState);
3772
- updateMagicLinkSubmitState();
3773
- }
3774
- if (magicLinkForm) magicLinkForm.addEventListener('submit', async function(e) {
3775
- e.preventDefault();
3776
- var btn = magicLinkForm.querySelector('button[type="submit"]');
3777
- var msg = document.getElementById('m-msg');
3778
- var emailInput = document.getElementById('m-email');
3779
- var email = __anNormalizeAuthEmail(emailInput && emailInput.value);
3780
- var isDesktopMagicLink = __anIsAgentNativeDesktop();
3781
- msg.classList.remove('show', 'error', 'success');
3782
- if (!__anIsValidAuthEmail(email)) {
3783
- __anShowEmailValidationError(emailInput, msg);
3784
- return;
3785
- }
3786
- __anTrackAuth('auth.signup_clicked', { surface: 'signup', method: 'magic_link', auth_view: __anAuthView });
3787
- var originalLabel = btn.textContent;
3788
- btn.disabled = true;
3789
- __anMagicLinkInFlight = isDesktopMagicLink;
3790
- btn.textContent = __anT('sending');
3791
- try {
3792
- var res = await fetch(__anPath('/_agent-native/auth/magic-link'), {
3793
- method: 'POST',
3794
- headers: { 'Content-Type': 'application/json' },
3795
- body: JSON.stringify({
3796
- email: email,
3797
- callbackURL: isDesktopMagicLink
3798
- ? __anPath('/_agent-native/auth/magic-link/desktop-callback')
3799
- : __anResumeHref(),
3800
- }),
3801
- });
3802
- var data = await res.json().catch(function(error) {
3803
- console.warn('[auth] Could not parse magic-link response', error);
3804
- return null;
3805
- });
3806
- if (res.ok) {
3807
- btn.disabled = false;
3808
- btn.textContent = originalLabel;
3809
- showMagicLinkSuccess(email);
3810
- if (isDesktopMagicLink) {
3811
- var magicFlowId = data && typeof data.flowId === 'string' ? data.flowId : '';
3812
- var magicVerifier = data && typeof data.verifier === 'string' ? data.verifier : '';
3813
- if (!magicFlowId || !magicVerifier) {
3814
- throw new Error('The sign-in flow was not initialized.');
3815
- }
3816
- __anWaitForOAuthExchange(magicFlowId, __anResumeHref(), btn, msg, 'magic-link', magicVerifier);
3817
- }
3818
- return;
3819
- }
3820
- __anMagicLinkInFlight = false;
3821
- msg.textContent = __anAuthErrorText(data, __anT('magicLinkFailed'));
3822
- msg.classList.add('show', 'error');
3823
- btn.disabled = false;
3824
- btn.textContent = originalLabel;
3825
- } catch (err) {
3826
- __anMagicLinkInFlight = false;
3827
- msg.textContent = __anT('networkErrorDashRetry');
3828
- msg.classList.add('show', 'error');
3829
- btn.disabled = false;
3830
- btn.textContent = originalLabel;
3831
- }
3832
- });
3833
-
3834
- document.getElementById('signup-form').addEventListener('submit', async function(e) {
3835
- e.preventDefault();
3836
- var form = e.currentTarget;
3837
- var btn = form.querySelector('button[type="submit"]');
3838
- var msg = document.getElementById('s-msg');
3839
- msg.classList.remove('show', 'error', 'success');
3840
- var pass = document.getElementById('s-pass').value;
3841
- var pass2 = document.getElementById('s-pass2').value;
3842
- if (pass !== pass2) {
3843
- msg.textContent = __anT('passwordsMismatch');
3844
- msg.classList.add('show', 'error');
3845
- return;
3846
- }
3847
- var originalLabel = btn.textContent;
3848
- btn.disabled = true;
3849
- btn.textContent = __anT('creatingAccount');
3850
- try {
3851
- var emailInput = document.getElementById('s-email');
3852
- var email = __anNormalizeAuthEmail(emailInput && emailInput.value);
3853
- if (!__anIsValidAuthEmail(email)) {
3854
- btn.disabled = false;
3855
- btn.textContent = originalLabel;
3856
- __anShowEmailValidationError(emailInput, msg);
3857
- return;
3858
- }
3859
- __anTrackAuth('auth.signup_clicked', { surface: 'signup', method: 'password', auth_view: __anAuthView });
3860
- var res = await fetch(__anPath('/_agent-native/auth/register'), {
3861
- method: 'POST',
3862
- headers: { 'Content-Type': 'application/json' },
3863
- body: JSON.stringify({
3864
- email: email,
3865
- password: pass,
3866
- callbackURL: __anResumeHref(),
3867
- }),
3868
- });
3869
- var data = await res.json().catch(function() { return {}; });
3870
- if (res.ok) {
3871
- // If email verification is required, the server won't return a session.
3872
- // Try logging in — if it fails (unverified), show a "check your email" message.
3873
- var loginRes = await fetch(__anPath('/_agent-native/auth/login'), {
3874
- method: 'POST',
3875
- headers: { 'Content-Type': 'application/json' },
3876
- body: JSON.stringify({ email: email, password: pass }),
3877
- });
3878
- if (loginRes.ok) {
3879
- clearRememberedPendingSignupEmail();
3880
- msg.textContent = __anT('accountCreatedSigningIn');
3881
- msg.classList.add('show', 'success');
3882
- __anRedirectToSignedInApp();
3883
- return;
3884
- }
3885
- var loginData;
3886
- try {
3887
- loginData = await loginRes.json();
3888
- } catch (error) {
3889
- console.warn('[auth] Could not parse sign-in response', error);
3890
- }
3891
- var loginError = __anAuthErrorText(loginData, __anT('registrationFailed'));
3892
- if (loginRes.status === 403 && /not verified|verification/i.test(loginError)) {
3893
- btn.disabled = false;
3894
- btn.textContent = originalLabel;
3895
- showVerificationStep(email, pass);
3896
- return;
3897
- }
3898
- msg.textContent = loginError;
3899
- msg.classList.add('show', 'error');
3900
- btn.disabled = false;
3901
- btn.textContent = originalLabel;
3902
- return;
3903
- }
3904
- msg.textContent = __anAuthErrorText(data, __anT('registrationFailed'));
3905
- msg.classList.add('show', 'error');
3906
- btn.disabled = false;
3907
- btn.textContent = originalLabel;
3908
- } catch (err) {
3909
- msg.textContent = __anT('networkErrorDashRetry');
3910
- msg.classList.add('show', 'error');
3911
- btn.disabled = false;
3912
- btn.textContent = originalLabel;
3913
- }
3914
- });
3915
-
3916
- var verifyContinue = document.getElementById('verify-continue');
3917
- if (verifyContinue) verifyContinue.addEventListener('click', function(e) {
3918
- e.preventDefault();
3919
- checkVerificationSession();
3920
- });
3921
- window.addEventListener('focus', maybeCompleteVerificationAfterReturn);
3922
- document.addEventListener('visibilitychange', function() {
3923
- if (document.visibilityState === 'visible') maybeCompleteVerificationAfterReturn();
3924
- });
3925
- var resendBtn = document.getElementById('resend-verification');
3926
- if (resendBtn) resendBtn.addEventListener('click', function(e) {
3927
- e.preventDefault();
3928
- resendVerificationEmail();
3929
- });
3930
- var backToSignup = document.getElementById('back-to-signup');
3931
- if (backToSignup) backToSignup.addEventListener('click', function(e) {
3932
- e.preventDefault();
3933
- clearRememberedPendingSignupEmail();
3934
- setActiveTab('signup', { persist: true });
3935
- var email = document.getElementById('s-email');
3936
- setTimeout(function() { if (email) email.focus(); }, 0);
3937
- });
3938
-
3939
- var forgotLink = document.getElementById('forgot-link');
3940
- var backToLogin = document.getElementById('back-to-login');
3941
- if (forgotLink) forgotLink.addEventListener('click', function(e) {
3942
- e.preventDefault();
3943
- document.getElementById('login-form').classList.remove('active');
3944
- document.getElementById('forgot-form').classList.add('active');
3945
- __anSetAuthView('forgot');
3946
- var fEmail = document.getElementById('f-email');
3947
- var lEmail = document.getElementById('l-email');
3948
- if (lEmail && lEmail.value) fEmail.value = lEmail.value;
3949
- setTimeout(function() { fEmail.focus(); }, 0);
3950
- });
3951
- if (backToLogin) backToLogin.addEventListener('click', function(e) {
3952
- e.preventDefault();
3953
- document.getElementById('forgot-form').classList.remove('active');
3954
- document.getElementById('login-form').classList.add('active');
3955
- __anSetAuthView('login');
3956
- });
3957
-
3958
- var forgotForm = document.getElementById('forgot-form');
3959
- if (forgotForm) forgotForm.addEventListener('submit', async function(e) {
3960
- e.preventDefault();
3961
- var btn = e.currentTarget.querySelector('button[type="submit"]');
3962
- var msg = document.getElementById('f-msg');
3963
- msg.classList.remove('show', 'error', 'success');
3964
- var original = btn.textContent;
3965
- btn.disabled = true;
3966
- btn.textContent = __anT('sending');
3967
- try {
3968
- var emailInput = document.getElementById('f-email');
3969
- var email = __anNormalizeAuthEmail(emailInput && emailInput.value);
3970
- if (!__anIsValidAuthEmail(email)) {
3971
- btn.disabled = false;
3972
- btn.textContent = original;
3973
- __anShowEmailValidationError(emailInput, msg);
3974
- return;
3975
- }
3976
- var res = await fetch(__anPath('/_agent-native/auth/ba/request-password-reset'), {
3977
- method: 'POST',
3978
- headers: { 'Content-Type': 'application/json' },
3979
- body: JSON.stringify({ email: email }),
3980
- });
3981
- if (res.ok) {
3982
- msg.textContent = __anT('resetEmailSent');
3983
- msg.classList.add('show', 'success');
3984
- btn.textContent = __anT('sent');
3985
- return;
3986
- }
3987
- var data = await res.json().catch(function() { return {}; });
3988
- msg.textContent = __anAuthErrorText(data, __anT('resetEmailFailed'));
3989
- msg.classList.add('show', 'error');
3990
- btn.disabled = false;
3991
- btn.textContent = original;
3992
- } catch (err) {
3993
- msg.textContent = __anT('networkErrorDashRetry');
3994
- msg.classList.add('show', 'error');
3995
- btn.disabled = false;
3996
- btn.textContent = original;
3997
- }
3998
- });
3999
-
4000
- document.getElementById('login-form').addEventListener('submit', async function(e) {
4001
- e.preventDefault();
4002
- var form = e.currentTarget;
4003
- var btn = form.querySelector('button[type="submit"]');
4004
- var msg = document.getElementById('l-msg');
4005
- msg.classList.remove('show', 'success');
4006
- msg.classList.add('error');
4007
- var originalLabel = btn.textContent;
4008
- btn.disabled = true;
4009
- btn.textContent = __anT('signingIn');
4010
- try {
4011
- var emailInput = document.getElementById('l-email');
4012
- var email = __anNormalizeAuthEmail(emailInput && emailInput.value);
4013
- if (!__anIsValidAuthEmail(email)) {
4014
- btn.disabled = false;
4015
- btn.textContent = originalLabel;
4016
- __anShowEmailValidationError(emailInput, msg);
4017
- return;
4018
- }
4019
- var res = await fetch(__anPath('/_agent-native/auth/login'), {
4020
- method: 'POST',
4021
- headers: { 'Content-Type': 'application/json' },
4022
- body: JSON.stringify({
4023
- email: email,
4024
- password: document.getElementById('l-pass').value,
4025
- }),
4026
- });
4027
- if (res.ok) {
4028
- clearRememberedPendingSignupEmail();
4029
- __anRedirectToSignedInApp();
4030
- return;
4031
- }
4032
- var data = await res.json().catch(function() { return {}; });
4033
- msg.textContent = __anAuthErrorText(data, __anT('invalidLogin'));
4034
- msg.classList.add('show');
4035
- btn.disabled = false;
4036
- btn.textContent = originalLabel;
4037
- } catch (err) {
4038
- msg.textContent = __anT('networkErrorDashRetry');
4039
- msg.classList.add('show');
4040
- btn.disabled = false;
4041
- btn.textContent = originalLabel;
4042
- }
4043
- });
4044
- `}
4045
- ${renderGoogleButton
4046
- ? `
4047
- async function signInWithGoogle() {
4048
- __anTrackAuth(__anAuthView === 'login' ? 'auth.login_clicked' : 'auth.signup_clicked', { surface: __anAuthView === 'login' ? 'login' : 'signup', method: 'google', auth_view: __anAuthView });
4049
- var btn = document.getElementById('google-btn');
4050
- var err = document.getElementById('google-err');
4051
- var ret = __anResumeHref();
4052
- var flowId = __anNewOAuthFlowId();
4053
- btn.disabled = true;
4054
- __anBeginGoogleSignInFlow(flowId);
4055
- __anBindGoogleRecover();
4056
- err.classList.remove('show');
4057
- if (__anResolveAuthFlow() === 'popup') {
4058
- __anStartPopupOAuth(ret, btn, err, flowId);
4059
- return;
4060
- }
4061
- if (__anIsAgentNativeDesktop()) {
4062
- __anStartNativeDesktopOAuth(ret, btn, err, flowId);
4063
- return;
4064
- }
4065
- if (__anIsBuilderPreview()) {
4066
- __anStartRedirectOAuth(ret, btn, err, flowId, 'Opening Google sign-in redirect from Builder preview');
4067
- return;
4068
- }
4069
- try {
4070
- var authUrl = __anGoogleAuthUrlPath() + '?return=' + encodeURIComponent(ret);
4071
- var res = await fetch(authUrl);
4072
- var data = await res.json();
4073
- if (!__anIsCurrentGoogleSignInFlow(flowId)) return;
4074
- if (data.url) {
4075
- __anOpenOAuthUrl(data.url);
4076
- } else {
4077
- err.textContent = __anAuthErrorText(data, __anT('googleNotConfigured'));
4078
- err.classList.add('show');
4079
- btn.disabled = false;
4080
- __anGoogleSignInInFlight = false;
4081
- __anClearGoogleSignInFlow();
4082
- }
4083
- } catch (e) {
4084
- err.textContent = __anT('failedToConnect');
4085
- err.classList.add('show');
4086
- btn.disabled = false;
4087
- __anGoogleSignInInFlight = false;
4088
- __anClearGoogleSignInFlow();
4089
- }
4090
- }`
4091
- : ""}
4092
- ${starfieldScript}
4093
- ${signupLocalModeNote
4094
- ? `
4095
- function __anCopyCommandFromPanel(panelId, buttonId) {
4096
- var panel = document.getElementById(panelId);
4097
- var button = document.getElementById(buttonId);
4098
- if (!panel || !button) return;
4099
- var command = panel.getAttribute('data-command') || '';
4100
- var original = button.textContent || __anT('copyCommand');
4101
- function markCopied() {
4102
- button.textContent = __anT('copied');
4103
- setTimeout(function() { button.textContent = original; }, 1600);
4104
- }
4105
- if (navigator.clipboard && navigator.clipboard.writeText) {
4106
- navigator.clipboard.writeText(command).then(markCopied).catch(function() {});
4107
- }
4108
- }
4109
- function __anCopySignupLocalModeCommand() {
4110
- __anCopyCommandFromPanel('signup-local-mode-note', 'copy-signup-local-mode');
4111
- }
4112
- `
4113
- : ""}
4114
- if (__anAuthView === 'signup' || __anAuthView === 'magicLink' || __anAuthView === 'googleOnly') {
4115
- __anTrackAuth('auth.signup_viewed', {
4116
- surface: 'signup',
4117
- auth_mode: __AN_AUTH_MODE,
4118
- auth_view: __anAuthView
4119
- });
4120
- }
4121
- </script>
4122
- </body>
4123
- </html>`;
1832
+ `;
1833
+ const authPageLayoutStyles = `
1834
+ .auth-root { width: 100%; }
1835
+ .auth-marketing-home { width: 100%; padding: 0; position: relative; overflow-x: hidden; }
1836
+ .auth-marketing-shell { padding: 0; }
1837
+ .auth-marketing-home .split { width: 100%; }
1838
+ .auth-marketing-home .marketing-panel { min-width: 0; }
1839
+ .auth-marketing-home .form-panel { min-width: 0; }
1840
+ .auth-marketing-home [data-agent-native-starfield] { position: fixed; inset: 0; width: 100%; height: 100%; }
1841
+ @media (max-width: 900px) {
1842
+ .auth-marketing-home .auth-marketing-shell { display: block; }
1843
+ }
1844
+ `;
1845
+ const authClientScriptPath = `${appBasePath}/assets/auth-client.js`;
1846
+ const title = hasMarketing
1847
+ ? `${marketing.appName} — ${t("pageTitleSignIn")}`
1848
+ : t("pageTitleWelcome");
1849
+ const authDocumentMarkup = renderToString(createElement("html", { lang: DEFAULT_LOCALE, dir: "ltr" }, createElement("head", null, createElement("meta", { charSet: "UTF-8" }), createElement("script", {
1850
+ "data-agent-native-locale-init": "",
1851
+ dangerouslySetInnerHTML: { __html: localeInitScript },
1852
+ }), createElement("script", {
1853
+ "data-agent-native-embedded-init": "",
1854
+ dangerouslySetInnerHTML: { __html: embeddedAuthInitScript },
1855
+ }), createElement("meta", {
1856
+ name: "viewport",
1857
+ content: "width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no",
1858
+ }), createElement("title", null, title), createElement("link", {
1859
+ rel: "icon",
1860
+ type: "image/svg+xml",
1861
+ href: withAppBasePath("/favicon.svg", appBasePath),
1862
+ }), createElement("link", {
1863
+ rel: "apple-touch-icon",
1864
+ href: withAppBasePath("/icon-180.svg", appBasePath),
1865
+ }), hasMarketing
1866
+ ? [
1867
+ createElement("meta", {
1868
+ key: "description",
1869
+ name: "description",
1870
+ content: marketing.tagline,
1871
+ }),
1872
+ createElement("meta", {
1873
+ key: "og-title",
1874
+ property: "og:title",
1875
+ content: marketing.appName,
1876
+ }),
1877
+ createElement("meta", {
1878
+ key: "og-description",
1879
+ property: "og:description",
1880
+ content: marketing.tagline,
1881
+ }),
1882
+ createElement("meta", {
1883
+ key: "og-image",
1884
+ property: "og:image",
1885
+ content: socialImageUrl,
1886
+ }),
1887
+ createElement("meta", {
1888
+ key: "og-image-secure",
1889
+ property: "og:image:secure_url",
1890
+ content: socialImageUrl,
1891
+ }),
1892
+ createElement("meta", {
1893
+ key: "og-image-type",
1894
+ property: "og:image:type",
1895
+ content: AGENT_NATIVE_SOCIAL_IMAGE_TYPE,
1896
+ }),
1897
+ createElement("meta", {
1898
+ key: "og-image-width",
1899
+ property: "og:image:width",
1900
+ content: AGENT_NATIVE_SOCIAL_IMAGE_WIDTH,
1901
+ }),
1902
+ createElement("meta", {
1903
+ key: "og-image-height",
1904
+ property: "og:image:height",
1905
+ content: AGENT_NATIVE_SOCIAL_IMAGE_HEIGHT,
1906
+ }),
1907
+ createElement("meta", {
1908
+ key: "og-image-alt",
1909
+ property: "og:image:alt",
1910
+ content: AGENT_NATIVE_SOCIAL_IMAGE_ALT,
1911
+ }),
1912
+ createElement("meta", {
1913
+ key: "twitter-card",
1914
+ name: "twitter:card",
1915
+ content: "summary_large_image",
1916
+ }),
1917
+ createElement("meta", {
1918
+ key: "twitter-image",
1919
+ name: "twitter:image",
1920
+ content: socialImageUrl,
1921
+ }),
1922
+ createElement("meta", {
1923
+ key: "twitter-image-alt",
1924
+ name: "twitter:image:alt",
1925
+ content: AGENT_NATIVE_SOCIAL_IMAGE_ALT,
1926
+ }),
1927
+ ]
1928
+ : null, createElement("style", {
1929
+ dangerouslySetInnerHTML: {
1930
+ __html: authDocumentStyles + authPageLayoutStyles,
1931
+ },
1932
+ }), createElement("script", {
1933
+ type: "module",
1934
+ src: authClientScriptPath,
1935
+ })), createElement("body", {
1936
+ className: simplifiedAuth
1937
+ ? "simplified-auth"
1938
+ : hasMarketing
1939
+ ? "has-marketing"
1940
+ : undefined,
1941
+ }, createElement("div", { id: "agent-native-auth-root", className: "auth-root" }, createElement(AuthPage, authPageProps)), createElement("script", {
1942
+ type: "application/json",
1943
+ id: "agent-native-auth-data",
1944
+ dangerouslySetInnerHTML: { __html: authPageData },
1945
+ }))));
1946
+ return `<!DOCTYPE html>${authDocumentMarkup}`;
4124
1947
  }
4125
1948
  /** @deprecated Use getOnboardingHtml() instead */
4126
1949
  export const ONBOARDING_HTML = getOnboardingHtml();
4127
- /**
4128
- * HTML for the password reset page — shown when the user clicks the link in
4129
- * their reset email. Posts `{ newPassword, token }` to Better Auth's
4130
- * `/reset-password` endpoint, then redirects to the login page.
4131
- */
4132
- export function getResetPasswordHtml() {
4133
- return `<!DOCTYPE html>
4134
- <html lang="en">
4135
- <head>
4136
- <meta charset="UTF-8">
4137
- <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
4138
- <title>Reset password</title>
4139
- <link rel="icon" type="image/svg+xml" href="${withAppBasePath("/favicon.svg")}">
4140
- <link rel="apple-touch-icon" href="${withAppBasePath("/icon-180.svg")}">
4141
- <style>
1950
+ const RESET_PASSWORD_STYLES = `
1951
+ /* guard:allow-raw-color - standalone reset page has no app theme token layer */
4142
1952
  *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
4143
1953
  body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; background: #0a0a0a; color: #e5e5e5; display: flex; align-items: center; justify-content: center; min-height: 100vh; padding: 1rem; }
4144
1954
  .card { width: 100%; max-width: 400px; padding: 2rem; background: #141414; border: 1px solid rgba(255,255,255,0.08); border-radius: 12px; }
@@ -4157,113 +1967,38 @@ export function getResetPasswordHtml() {
4157
1967
  .msg.show { display: block; }
4158
1968
  .back { display: inline-block; margin-top: 1rem; font-size: 0.75rem; color: #888; text-decoration: none; }
4159
1969
  .back:hover { color: #bbb; }
4160
- </style>
4161
- </head>
4162
- <body>
4163
- <div class="card">
4164
- <h1>Choose a new password</h1>
4165
- <p class="subtitle">Set a new password for your account.</p>
4166
- <form id="reset-form">
4167
- <label for="p1">New password</label>
4168
- <input id="p1" type="password" autocomplete="new-password" placeholder="At least ${PASSWORD_MIN_LENGTH} characters" required minlength="${PASSWORD_MIN_LENGTH}" maxlength="${PASSWORD_MAX_LENGTH}" />
4169
- <label for="p2">Confirm password</label>
4170
- <input id="p2" type="password" autocomplete="new-password" placeholder="Confirm password" required minlength="${PASSWORD_MIN_LENGTH}" maxlength="${PASSWORD_MAX_LENGTH}" />
4171
- <button type="submit">Save new password</button>
4172
- <p class="msg" id="msg"></p>
4173
- </form>
4174
- <a class="back" id="back-link" href="/">Back to sign in</a>
4175
- </div>
4176
- <script>
4177
- (function() {
4178
- // Derive the app's base path so apps mounted under a prefix
4179
- // (e.g. /mail, /calendar) get sent home instead of to the root domain.
4180
- var RESET_PATH = '/_agent-native/auth/reset';
4181
- var pathname = window.location.pathname;
4182
- var idx = pathname.indexOf(RESET_PATH);
4183
- var basePath = (idx >= 0 ? pathname.slice(0, idx) : '') || '';
4184
- var homeHref = basePath + '/';
4185
- var backLink = document.getElementById('back-link');
4186
- if (backLink) backLink.setAttribute('href', homeHref);
4187
- var params = new URLSearchParams(location.search);
4188
- var token = params.get('token') || '';
4189
- var msg = document.getElementById('msg');
4190
- var resetForm = document.getElementById('reset-form');
4191
- function resetErrorText(data, fallback) {
4192
- var candidate = data && (data.error || data.message);
4193
- if (typeof candidate !== 'string' || !candidate.trim()) return fallback;
4194
- var message = candidate.trim();
4195
- if (/failed query|\bselect\b.*\bfrom\b|\binsert\b.*\binto\b|\bupdate\b.*\bset\b|\bdelete\b.*\bfrom\b|\bsql\b|database|relation .* does not exist|column .* does not exist|syntax error|constraint|connection refused|econn|timeout/i.test(message)) {
4196
- return fallback;
4197
- }
4198
- if (/password.*(?:at least|minimum|min(?:imum)?|too short)/i.test(message)) {
4199
- return 'Choose a password with at least ${PASSWORD_MIN_LENGTH} characters.';
4200
- }
4201
- if (/password.*(?:at most|maximum|max(?:imum)?|too long)/i.test(message)) {
4202
- return 'Choose a password with no more than ${PASSWORD_MAX_LENGTH} characters.';
4203
- }
4204
- return message;
4205
- }
4206
- function bindPasswordValidation(input) {
4207
- if (!input) return;
4208
- input.addEventListener('invalid', function() {
4209
- if (input.validity && input.validity.tooShort) {
4210
- input.setCustomValidity('Choose a password with at least ${PASSWORD_MIN_LENGTH} characters.');
4211
- } else if (input.validity && input.validity.tooLong) {
4212
- input.setCustomValidity('Choose a password with no more than ${PASSWORD_MAX_LENGTH} characters.');
4213
- }
4214
- });
4215
- input.addEventListener('input', function() {
4216
- input.setCustomValidity('');
4217
- });
4218
- }
4219
- bindPasswordValidation(document.getElementById('p1'));
4220
- bindPasswordValidation(document.getElementById('p2'));
4221
- if (!token) {
4222
- msg.textContent = 'This password reset link is missing or invalid. Request a new one.';
4223
- msg.classList.add('show', 'error');
4224
- resetForm.style.display = 'none';
4225
- return;
4226
- }
4227
- resetForm.addEventListener('submit', async function(e) {
4228
- e.preventDefault();
4229
- var btn = e.currentTarget.querySelector('button[type="submit"]');
4230
- var p1 = document.getElementById('p1').value;
4231
- var p2 = document.getElementById('p2').value;
4232
- msg.classList.remove('show', 'error', 'success');
4233
- if (p1 !== p2) {
4234
- msg.textContent = 'Passwords do not match.';
4235
- msg.classList.add('show', 'error');
4236
- return;
4237
- }
4238
- var original = btn.textContent;
4239
- btn.disabled = true;
4240
- btn.textContent = 'Saving…';
4241
- try {
4242
- var res = await fetch(basePath + '/_agent-native/auth/ba/reset-password', {
4243
- method: 'POST',
4244
- headers: { 'Content-Type': 'application/json' },
4245
- body: JSON.stringify({ newPassword: p1, token: token }),
4246
- });
4247
- if (res.ok) {
4248
- msg.textContent = 'Password updated — redirecting to sign in…';
4249
- msg.classList.add('show', 'success');
4250
- setTimeout(function() { window.location.href = homeHref; }, 1200);
4251
- return;
4252
- }
4253
- var data = await res.json().catch(function() { return {}; });
4254
- msg.textContent = resetErrorText(data, "We couldn't update your password. The link may have expired; request a new one.");
4255
- msg.classList.add('show', 'error');
4256
- btn.disabled = false;
4257
- btn.textContent = original;
4258
- } catch (err) {
4259
- msg.textContent = "We couldn't reach the server. Check your connection and try again.";
4260
- msg.classList.add('show', 'error');
4261
- btn.disabled = false;
4262
- btn.textContent = original;
4263
- }
4264
- });
4265
- })();
4266
- </script>
4267
- </body>
4268
- </html>`;
1970
+ `;
1971
+ /** React document for the password reset page linked from auth email. */
1972
+ export function getResetPasswordHtml(requestPath) {
1973
+ const configuredAppBasePath = getAppBasePathFromViteEnv();
1974
+ const appBasePath = configuredAppBasePath || workspaceBasePathFromRequest(requestPath);
1975
+ const resetPageProps = {
1976
+ pageType: "reset-password",
1977
+ appBasePath,
1978
+ passwordMinLength: PASSWORD_MIN_LENGTH,
1979
+ passwordMaxLength: PASSWORD_MAX_LENGTH,
1980
+ };
1981
+ const resetDocumentMarkup = renderToString(createElement("html", { lang: "en", dir: "ltr" }, createElement("head", null, createElement("meta", { charSet: "UTF-8" }), createElement("meta", {
1982
+ name: "viewport",
1983
+ content: "width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no",
1984
+ }), createElement("title", null, "Reset password"), createElement("link", {
1985
+ rel: "icon",
1986
+ type: "image/svg+xml",
1987
+ href: withAppBasePath("/favicon.svg", appBasePath),
1988
+ }), createElement("link", {
1989
+ rel: "apple-touch-icon",
1990
+ href: withAppBasePath("/icon-180.svg", appBasePath),
1991
+ }), createElement("style", {
1992
+ dangerouslySetInnerHTML: { __html: RESET_PASSWORD_STYLES },
1993
+ }), createElement("script", {
1994
+ type: "module",
1995
+ src: `${appBasePath}/assets/auth-client.js`,
1996
+ })), createElement("body", null, createElement("div", { id: "agent-native-auth-root" }, createElement(ResetPasswordPage, resetPageProps)), createElement("script", {
1997
+ type: "application/json",
1998
+ id: "agent-native-auth-data",
1999
+ dangerouslySetInnerHTML: {
2000
+ __html: serializeAuthPageData(resetPageProps),
2001
+ },
2002
+ }))));
2003
+ return `<!DOCTYPE html>${resetDocumentMarkup}`;
4269
2004
  }