@agent-native/core 0.7.1 → 0.7.4

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 (358) hide show
  1. package/dist/action.d.ts +8 -0
  2. package/dist/action.d.ts.map +1 -1
  3. package/dist/action.js +18 -0
  4. package/dist/action.js.map +1 -1
  5. package/dist/agent/production-agent.d.ts +9 -0
  6. package/dist/agent/production-agent.d.ts.map +1 -1
  7. package/dist/agent/production-agent.js +148 -36
  8. package/dist/agent/production-agent.js.map +1 -1
  9. package/dist/agent/run-manager.d.ts.map +1 -1
  10. package/dist/agent/run-manager.js +20 -1
  11. package/dist/agent/run-manager.js.map +1 -1
  12. package/dist/agent/run-store.d.ts +14 -0
  13. package/dist/agent/run-store.d.ts.map +1 -1
  14. package/dist/agent/run-store.js +63 -6
  15. package/dist/agent/run-store.js.map +1 -1
  16. package/dist/agent/types.d.ts +2 -0
  17. package/dist/agent/types.d.ts.map +1 -1
  18. package/dist/cli/create.js +1 -1
  19. package/dist/cli/create.js.map +1 -1
  20. package/dist/cli/setup-agents.d.ts.map +1 -1
  21. package/dist/cli/setup-agents.js +0 -2
  22. package/dist/cli/setup-agents.js.map +1 -1
  23. package/dist/cli/templates-meta.d.ts +52 -0
  24. package/dist/cli/templates-meta.d.ts.map +1 -0
  25. package/dist/cli/templates-meta.js +165 -0
  26. package/dist/cli/templates-meta.js.map +1 -0
  27. package/dist/client/AgentPanel.d.ts +5 -1
  28. package/dist/client/AgentPanel.d.ts.map +1 -1
  29. package/dist/client/AgentPanel.js +279 -30
  30. package/dist/client/AgentPanel.js.map +1 -1
  31. package/dist/client/AssistantChat.d.ts +2 -1
  32. package/dist/client/AssistantChat.d.ts.map +1 -1
  33. package/dist/client/AssistantChat.js +172 -40
  34. package/dist/client/AssistantChat.js.map +1 -1
  35. package/dist/client/ConnectBuilderCard.d.ts +21 -0
  36. package/dist/client/ConnectBuilderCard.d.ts.map +1 -0
  37. package/dist/client/ConnectBuilderCard.js +196 -0
  38. package/dist/client/ConnectBuilderCard.js.map +1 -0
  39. package/dist/client/FeedbackButton.d.ts +17 -0
  40. package/dist/client/FeedbackButton.d.ts.map +1 -0
  41. package/dist/client/FeedbackButton.js +147 -0
  42. package/dist/client/FeedbackButton.js.map +1 -0
  43. package/dist/client/IframeEmbed.d.ts +17 -0
  44. package/dist/client/IframeEmbed.d.ts.map +1 -0
  45. package/dist/client/IframeEmbed.js +108 -0
  46. package/dist/client/IframeEmbed.js.map +1 -0
  47. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  48. package/dist/client/MultiTabAssistantChat.js +34 -7
  49. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  50. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  51. package/dist/client/agent-chat-adapter.js +34 -15
  52. package/dist/client/agent-chat-adapter.js.map +1 -1
  53. package/dist/client/agent-chat.d.ts +6 -0
  54. package/dist/client/agent-chat.d.ts.map +1 -1
  55. package/dist/client/agent-chat.js +7 -0
  56. package/dist/client/agent-chat.js.map +1 -1
  57. package/dist/client/composer/MentionPopover.d.ts.map +1 -1
  58. package/dist/client/composer/MentionPopover.js +27 -24
  59. package/dist/client/composer/MentionPopover.js.map +1 -1
  60. package/dist/client/composer/TiptapComposer.d.ts +3 -1
  61. package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
  62. package/dist/client/composer/TiptapComposer.js +21 -4
  63. package/dist/client/composer/TiptapComposer.js.map +1 -1
  64. package/dist/client/embed.d.ts +28 -0
  65. package/dist/client/embed.d.ts.map +1 -0
  66. package/dist/client/embed.js +50 -0
  67. package/dist/client/embed.js.map +1 -0
  68. package/dist/client/index.d.ts +5 -1
  69. package/dist/client/index.d.ts.map +1 -1
  70. package/dist/client/index.js +5 -1
  71. package/dist/client/index.js.map +1 -1
  72. package/dist/client/integrations/IntegrationsPanel.js +2 -2
  73. package/dist/client/integrations/IntegrationsPanel.js.map +1 -1
  74. package/dist/client/onboarding/OnboardingBanner.js +2 -2
  75. package/dist/client/onboarding/OnboardingBanner.js.map +1 -1
  76. package/dist/client/onboarding/OnboardingPanel.d.ts.map +1 -1
  77. package/dist/client/onboarding/OnboardingPanel.js +139 -52
  78. package/dist/client/onboarding/OnboardingPanel.js.map +1 -1
  79. package/dist/client/onboarding/SetupButton.d.ts.map +1 -1
  80. package/dist/client/onboarding/SetupButton.js +13 -3
  81. package/dist/client/onboarding/SetupButton.js.map +1 -1
  82. package/dist/client/org/TeamPage.d.ts.map +1 -1
  83. package/dist/client/org/TeamPage.js +12 -7
  84. package/dist/client/org/TeamPage.js.map +1 -1
  85. package/dist/client/resources/ResourceEditor.d.ts.map +1 -1
  86. package/dist/client/resources/ResourceEditor.js +57 -2
  87. package/dist/client/resources/ResourceEditor.js.map +1 -1
  88. package/dist/client/resources/ResourceTree.d.ts +5 -1
  89. package/dist/client/resources/ResourceTree.d.ts.map +1 -1
  90. package/dist/client/resources/ResourceTree.js +17 -10
  91. package/dist/client/resources/ResourceTree.js.map +1 -1
  92. package/dist/client/resources/ResourcesPanel.d.ts.map +1 -1
  93. package/dist/client/resources/ResourcesPanel.js +12 -10
  94. package/dist/client/resources/ResourcesPanel.js.map +1 -1
  95. package/dist/client/settings/AgentsSection.d.ts.map +1 -1
  96. package/dist/client/settings/AgentsSection.js +6 -3
  97. package/dist/client/settings/AgentsSection.js.map +1 -1
  98. package/dist/client/settings/ComingSoonSection.js +1 -1
  99. package/dist/client/settings/ComingSoonSection.js.map +1 -1
  100. package/dist/client/settings/LLMSection.d.ts.map +1 -1
  101. package/dist/client/settings/LLMSection.js +1 -1
  102. package/dist/client/settings/LLMSection.js.map +1 -1
  103. package/dist/client/settings/SecretsSection.d.ts +12 -0
  104. package/dist/client/settings/SecretsSection.d.ts.map +1 -0
  105. package/dist/client/settings/SecretsSection.js +148 -0
  106. package/dist/client/settings/SecretsSection.js.map +1 -0
  107. package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
  108. package/dist/client/settings/SettingsPanel.js +114 -23
  109. package/dist/client/settings/SettingsPanel.js.map +1 -1
  110. package/dist/client/settings/SettingsSection.js +2 -2
  111. package/dist/client/settings/SettingsSection.js.map +1 -1
  112. package/dist/client/settings/UsageSection.d.ts +2 -0
  113. package/dist/client/settings/UsageSection.d.ts.map +1 -0
  114. package/dist/client/settings/UsageSection.js +70 -0
  115. package/dist/client/settings/UsageSection.js.map +1 -0
  116. package/dist/client/settings/index.d.ts +1 -0
  117. package/dist/client/settings/index.d.ts.map +1 -1
  118. package/dist/client/settings/index.js +1 -0
  119. package/dist/client/settings/index.js.map +1 -1
  120. package/dist/client/sharing/ShareButton.d.ts +14 -0
  121. package/dist/client/sharing/ShareButton.d.ts.map +1 -0
  122. package/dist/client/sharing/ShareButton.js +43 -0
  123. package/dist/client/sharing/ShareButton.js.map +1 -0
  124. package/dist/client/sharing/ShareDialog.d.ts +15 -0
  125. package/dist/client/sharing/ShareDialog.d.ts.map +1 -0
  126. package/dist/client/sharing/ShareDialog.js +209 -0
  127. package/dist/client/sharing/ShareDialog.js.map +1 -0
  128. package/dist/client/sharing/VisibilityBadge.d.ts +11 -0
  129. package/dist/client/sharing/VisibilityBadge.d.ts.map +1 -0
  130. package/dist/client/sharing/VisibilityBadge.js +20 -0
  131. package/dist/client/sharing/VisibilityBadge.js.map +1 -0
  132. package/dist/client/sharing/index.d.ts +4 -0
  133. package/dist/client/sharing/index.d.ts.map +1 -0
  134. package/dist/client/sharing/index.js +4 -0
  135. package/dist/client/sharing/index.js.map +1 -0
  136. package/dist/client/use-action.d.ts.map +1 -1
  137. package/dist/client/use-action.js +74 -6
  138. package/dist/client/use-action.js.map +1 -1
  139. package/dist/client/use-db-sync.d.ts +25 -2
  140. package/dist/client/use-db-sync.d.ts.map +1 -1
  141. package/dist/client/use-db-sync.js +62 -1
  142. package/dist/client/use-db-sync.js.map +1 -1
  143. package/dist/client/use-dev-mode.d.ts.map +1 -1
  144. package/dist/client/use-dev-mode.js +16 -1
  145. package/dist/client/use-dev-mode.js.map +1 -1
  146. package/dist/db/client.d.ts +12 -0
  147. package/dist/db/client.d.ts.map +1 -1
  148. package/dist/db/client.js +89 -2
  149. package/dist/db/client.js.map +1 -1
  150. package/dist/db/create-get-db.d.ts +11 -0
  151. package/dist/db/create-get-db.d.ts.map +1 -1
  152. package/dist/db/create-get-db.js +47 -3
  153. package/dist/db/create-get-db.js.map +1 -1
  154. package/dist/db/migrations.d.ts.map +1 -1
  155. package/dist/db/migrations.js +62 -5
  156. package/dist/db/migrations.js.map +1 -1
  157. package/dist/db/schema.d.ts +1 -0
  158. package/dist/db/schema.d.ts.map +1 -1
  159. package/dist/db/schema.js +4 -0
  160. package/dist/db/schema.js.map +1 -1
  161. package/dist/deploy/build.js +22 -3
  162. package/dist/deploy/build.js.map +1 -1
  163. package/dist/index.d.ts +2 -0
  164. package/dist/index.d.ts.map +1 -1
  165. package/dist/index.js +6 -0
  166. package/dist/index.js.map +1 -1
  167. package/dist/jobs/scheduler.d.ts.map +1 -1
  168. package/dist/jobs/scheduler.js +7 -2
  169. package/dist/jobs/scheduler.js.map +1 -1
  170. package/dist/oauth-tokens/google-refresh.d.ts +31 -0
  171. package/dist/oauth-tokens/google-refresh.d.ts.map +1 -0
  172. package/dist/oauth-tokens/google-refresh.js +115 -0
  173. package/dist/oauth-tokens/google-refresh.js.map +1 -0
  174. package/dist/oauth-tokens/index.d.ts +1 -0
  175. package/dist/oauth-tokens/index.d.ts.map +1 -1
  176. package/dist/oauth-tokens/index.js +1 -0
  177. package/dist/oauth-tokens/index.js.map +1 -1
  178. package/dist/onboarding/default-steps.d.ts.map +1 -1
  179. package/dist/onboarding/default-steps.js +62 -18
  180. package/dist/onboarding/default-steps.js.map +1 -1
  181. package/dist/org/accept-pending.d.ts +22 -0
  182. package/dist/org/accept-pending.d.ts.map +1 -0
  183. package/dist/org/accept-pending.js +75 -0
  184. package/dist/org/accept-pending.js.map +1 -0
  185. package/dist/org/context.js +1 -1
  186. package/dist/org/handlers.d.ts +2 -0
  187. package/dist/org/handlers.d.ts.map +1 -1
  188. package/dist/org/handlers.js +87 -11
  189. package/dist/org/handlers.js.map +1 -1
  190. package/dist/org/index.d.ts +2 -0
  191. package/dist/org/index.d.ts.map +1 -1
  192. package/dist/org/index.js +1 -0
  193. package/dist/org/index.js.map +1 -1
  194. package/dist/org/plugin.d.ts.map +1 -1
  195. package/dist/org/plugin.js +37 -22
  196. package/dist/org/plugin.js.map +1 -1
  197. package/dist/resources/handlers.js +1 -1
  198. package/dist/resources/handlers.js.map +1 -1
  199. package/dist/resources/metadata.d.ts.map +1 -1
  200. package/dist/resources/metadata.js +2 -2
  201. package/dist/resources/metadata.js.map +1 -1
  202. package/dist/resources/store.d.ts.map +1 -1
  203. package/dist/resources/store.js +27 -1
  204. package/dist/resources/store.js.map +1 -1
  205. package/dist/scripts/db/patch.d.ts.map +1 -1
  206. package/dist/scripts/db/patch.js +273 -11
  207. package/dist/scripts/db/patch.js.map +1 -1
  208. package/dist/secrets/index.d.ts +15 -0
  209. package/dist/secrets/index.d.ts.map +1 -0
  210. package/dist/secrets/index.js +15 -0
  211. package/dist/secrets/index.js.map +1 -0
  212. package/dist/secrets/onboarding.d.ts +18 -0
  213. package/dist/secrets/onboarding.d.ts.map +1 -0
  214. package/dist/secrets/onboarding.js +87 -0
  215. package/dist/secrets/onboarding.js.map +1 -0
  216. package/dist/secrets/register.d.ts +63 -0
  217. package/dist/secrets/register.d.ts.map +1 -0
  218. package/dist/secrets/register.js +55 -0
  219. package/dist/secrets/register.js.map +1 -0
  220. package/dist/secrets/routes.d.ts +67 -0
  221. package/dist/secrets/routes.d.ts.map +1 -0
  222. package/dist/secrets/routes.js +275 -0
  223. package/dist/secrets/routes.js.map +1 -0
  224. package/dist/secrets/schema.d.ts +154 -0
  225. package/dist/secrets/schema.d.ts.map +1 -0
  226. package/dist/secrets/schema.js +41 -0
  227. package/dist/secrets/schema.js.map +1 -0
  228. package/dist/secrets/storage.d.ts +54 -0
  229. package/dist/secrets/storage.d.ts.map +1 -0
  230. package/dist/secrets/storage.js +181 -0
  231. package/dist/secrets/storage.js.map +1 -0
  232. package/dist/server/action-discovery.d.ts +18 -0
  233. package/dist/server/action-discovery.d.ts.map +1 -1
  234. package/dist/server/action-discovery.js +97 -0
  235. package/dist/server/action-discovery.js.map +1 -1
  236. package/dist/server/action-routes.d.ts.map +1 -1
  237. package/dist/server/action-routes.js +26 -0
  238. package/dist/server/action-routes.js.map +1 -1
  239. package/dist/server/agent-chat-plugin.d.ts +12 -0
  240. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  241. package/dist/server/agent-chat-plugin.js +507 -48
  242. package/dist/server/agent-chat-plugin.js.map +1 -1
  243. package/dist/server/agent-discovery.js +2 -2
  244. package/dist/server/agent-discovery.js.map +1 -1
  245. package/dist/server/agent-teams.d.ts.map +1 -1
  246. package/dist/server/agent-teams.js +21 -58
  247. package/dist/server/agent-teams.js.map +1 -1
  248. package/dist/server/app-name.d.ts +13 -0
  249. package/dist/server/app-name.d.ts.map +1 -0
  250. package/dist/server/app-name.js +41 -0
  251. package/dist/server/app-name.js.map +1 -0
  252. package/dist/server/app-url.d.ts +24 -0
  253. package/dist/server/app-url.d.ts.map +1 -0
  254. package/dist/server/app-url.js +68 -0
  255. package/dist/server/app-url.js.map +1 -0
  256. package/dist/server/auth.d.ts +6 -0
  257. package/dist/server/auth.d.ts.map +1 -1
  258. package/dist/server/auth.js +284 -41
  259. package/dist/server/auth.js.map +1 -1
  260. package/dist/server/better-auth-instance.d.ts +1 -1
  261. package/dist/server/better-auth-instance.d.ts.map +1 -1
  262. package/dist/server/better-auth-instance.js +102 -7
  263. package/dist/server/better-auth-instance.js.map +1 -1
  264. package/dist/server/builder-browser.d.ts +21 -0
  265. package/dist/server/builder-browser.d.ts.map +1 -1
  266. package/dist/server/builder-browser.js +67 -4
  267. package/dist/server/builder-browser.js.map +1 -1
  268. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  269. package/dist/server/core-routes-plugin.js +151 -4
  270. package/dist/server/core-routes-plugin.js.map +1 -1
  271. package/dist/server/desktop-sso.d.ts +30 -0
  272. package/dist/server/desktop-sso.d.ts.map +1 -0
  273. package/dist/server/desktop-sso.js +74 -0
  274. package/dist/server/desktop-sso.js.map +1 -0
  275. package/dist/server/email-template.d.ts +51 -0
  276. package/dist/server/email-template.d.ts.map +1 -0
  277. package/dist/server/email-template.js +146 -0
  278. package/dist/server/email-template.js.map +1 -0
  279. package/dist/server/email.d.ts +23 -0
  280. package/dist/server/email.d.ts.map +1 -0
  281. package/dist/server/email.js +105 -0
  282. package/dist/server/email.js.map +1 -0
  283. package/dist/server/framework-request-handler.d.ts.map +1 -1
  284. package/dist/server/framework-request-handler.js +29 -0
  285. package/dist/server/framework-request-handler.js.map +1 -1
  286. package/dist/server/google-oauth.d.ts.map +1 -1
  287. package/dist/server/google-oauth.js +19 -3
  288. package/dist/server/google-oauth.js.map +1 -1
  289. package/dist/server/index.d.ts +5 -1
  290. package/dist/server/index.d.ts.map +1 -1
  291. package/dist/server/index.js +5 -1
  292. package/dist/server/index.js.map +1 -1
  293. package/dist/server/local-migration.d.ts +9 -0
  294. package/dist/server/local-migration.d.ts.map +1 -1
  295. package/dist/server/local-migration.js +44 -14
  296. package/dist/server/local-migration.js.map +1 -1
  297. package/dist/server/oauth-helpers.d.ts +2 -0
  298. package/dist/server/oauth-helpers.d.ts.map +1 -1
  299. package/dist/server/oauth-helpers.js +2 -0
  300. package/dist/server/oauth-helpers.js.map +1 -1
  301. package/dist/server/onboarding-html.d.ts +6 -0
  302. package/dist/server/onboarding-html.d.ts.map +1 -1
  303. package/dist/server/onboarding-html.js +229 -25
  304. package/dist/server/onboarding-html.js.map +1 -1
  305. package/dist/server/poll.d.ts.map +1 -1
  306. package/dist/server/poll.js +48 -0
  307. package/dist/server/poll.js.map +1 -1
  308. package/dist/sharing/access.d.ts +56 -0
  309. package/dist/sharing/access.d.ts.map +1 -0
  310. package/dist/sharing/access.js +149 -0
  311. package/dist/sharing/access.js.map +1 -0
  312. package/dist/sharing/actions/list-resource-shares.d.ts +3 -0
  313. package/dist/sharing/actions/list-resource-shares.d.ts.map +1 -0
  314. package/dist/sharing/actions/list-resource-shares.js +38 -0
  315. package/dist/sharing/actions/list-resource-shares.js.map +1 -0
  316. package/dist/sharing/actions/set-resource-visibility.d.ts +3 -0
  317. package/dist/sharing/actions/set-resource-visibility.d.ts.map +1 -0
  318. package/dist/sharing/actions/set-resource-visibility.js +24 -0
  319. package/dist/sharing/actions/set-resource-visibility.js.map +1 -0
  320. package/dist/sharing/actions/share-resource.d.ts +3 -0
  321. package/dist/sharing/actions/share-resource.d.ts.map +1 -0
  322. package/dist/sharing/actions/share-resource.js +64 -0
  323. package/dist/sharing/actions/share-resource.js.map +1 -0
  324. package/dist/sharing/actions/unshare-resource.d.ts +3 -0
  325. package/dist/sharing/actions/unshare-resource.d.ts.map +1 -0
  326. package/dist/sharing/actions/unshare-resource.js +24 -0
  327. package/dist/sharing/actions/unshare-resource.js.map +1 -0
  328. package/dist/sharing/index.d.ts +11 -0
  329. package/dist/sharing/index.d.ts.map +1 -0
  330. package/dist/sharing/index.js +11 -0
  331. package/dist/sharing/index.js.map +1 -0
  332. package/dist/sharing/registry.d.ts +44 -0
  333. package/dist/sharing/registry.d.ts.map +1 -0
  334. package/dist/sharing/registry.js +54 -0
  335. package/dist/sharing/registry.js.map +1 -0
  336. package/dist/sharing/schema.d.ts +202 -0
  337. package/dist/sharing/schema.d.ts.map +1 -0
  338. package/dist/sharing/schema.js +88 -0
  339. package/dist/sharing/schema.js.map +1 -0
  340. package/dist/templates/default/.agents/skills/inline-embeds/SKILL.md +88 -0
  341. package/dist/usage/store.d.ts +74 -12
  342. package/dist/usage/store.d.ts.map +1 -1
  343. package/dist/usage/store.js +210 -44
  344. package/dist/usage/store.js.map +1 -1
  345. package/dist/vite/action-types-plugin.d.ts +5 -0
  346. package/dist/vite/action-types-plugin.d.ts.map +1 -1
  347. package/dist/vite/action-types-plugin.js +129 -28
  348. package/dist/vite/action-types-plugin.js.map +1 -1
  349. package/dist/vite/client.d.ts.map +1 -1
  350. package/dist/vite/client.js +55 -0
  351. package/dist/vite/client.js.map +1 -1
  352. package/docs/content/deployment.md +59 -2
  353. package/docs/content/resources.md +9 -9
  354. package/docs/content/workspace-management.md +2 -2
  355. package/package.json +13 -5
  356. package/src/templates/default/.agents/skills/inline-embeds/SKILL.md +88 -0
  357. /package/dist/templates/workspace-core/{skills → .agents/skills}/company-policies/SKILL.md +0 -0
  358. /package/src/templates/workspace-core/{skills → .agents/skills}/company-policies/SKILL.md +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-url.d.ts","sourceRoot":"","sources":["../../src/server/app-url.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAiB,KAAK,OAAO,EAAE,MAAM,IAAI,CAAC;AAwBjD;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,GAAG,SAAS,CAKzD;AAED,wBAAgB,mBAAmB,CAAC,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAiB3D"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Resolve the canonical URL of this app — used in transactional emails,
3
+ * invite links, and anywhere we need an absolute URL that remains valid
4
+ * outside the current request context.
5
+ *
6
+ * Resolution order:
7
+ * 1. `APP_URL` env var — explicit override
8
+ * 2. `BETTER_AUTH_URL` env var — Better Auth's canonical URL
9
+ * 3. First-party template `prodUrl` from the registry (matched by
10
+ * package.json name) — lets deployed first-party apps (mail,
11
+ * calendar, analytics, …) use e.g. `analytics.agent-native.com`
12
+ * instead of their Netlify preview hostname.
13
+ * 4. Incoming request's origin (when an H3Event is available)
14
+ * 5. `http://localhost:3000`
15
+ */
16
+ import { getRequestURL } from "h3";
17
+ import path from "node:path";
18
+ import fs from "node:fs";
19
+ import { TEMPLATES } from "../cli/templates-meta.js";
20
+ let cachedPkgName = null;
21
+ function readPackageName() {
22
+ if (cachedPkgName !== null)
23
+ return cachedPkgName ?? undefined;
24
+ try {
25
+ const pkgPath = path.join(process.cwd(), "package.json");
26
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
27
+ cachedPkgName = typeof pkg?.name === "string" ? pkg.name : undefined;
28
+ }
29
+ catch {
30
+ cachedPkgName = undefined;
31
+ }
32
+ return cachedPkgName ?? undefined;
33
+ }
34
+ /** Strip trailing slashes for consistent URL concatenation. */
35
+ function stripTrailingSlash(u) {
36
+ return u.replace(/\/+$/, "");
37
+ }
38
+ /**
39
+ * Look up the first-party template `prodUrl` for the current app based on
40
+ * its `package.json` name. Returns undefined if the app isn't a known
41
+ * first-party template or the template has no `prodUrl`.
42
+ */
43
+ export function getFirstPartyProdUrl() {
44
+ const name = readPackageName();
45
+ if (!name)
46
+ return undefined;
47
+ const t = TEMPLATES.find((t) => t.name === name);
48
+ return t?.prodUrl;
49
+ }
50
+ export function getAppProductionUrl(event) {
51
+ const envUrl = process.env.APP_URL || process.env.BETTER_AUTH_URL;
52
+ if (envUrl)
53
+ return stripTrailingSlash(envUrl);
54
+ const firstParty = getFirstPartyProdUrl();
55
+ if (firstParty)
56
+ return stripTrailingSlash(firstParty);
57
+ if (event) {
58
+ try {
59
+ const url = getRequestURL(event);
60
+ return `${url.protocol}//${url.host}`;
61
+ }
62
+ catch {
63
+ // fall through
64
+ }
65
+ }
66
+ return "http://localhost:3000";
67
+ }
68
+ //# sourceMappingURL=app-url.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-url.js","sourceRoot":"","sources":["../../src/server/app-url.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,aAAa,EAAgB,MAAM,IAAI,CAAC;AACjD,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAErD,IAAI,aAAa,GAA8B,IAAI,CAAC;AAEpD,SAAS,eAAe;IACtB,IAAI,aAAa,KAAK,IAAI;QAAE,OAAO,aAAa,IAAI,SAAS,CAAC;IAC9D,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,cAAc,CAAC,CAAC;QACzD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;QACzD,aAAa,GAAG,OAAO,GAAG,EAAE,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;IACvE,CAAC;IAAC,MAAM,CAAC;QACP,aAAa,GAAG,SAAS,CAAC;IAC5B,CAAC;IACD,OAAO,aAAa,IAAI,SAAS,CAAC;AACpC,CAAC;AAED,+DAA+D;AAC/D,SAAS,kBAAkB,CAAC,CAAS;IACnC,OAAO,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAC/B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB;IAClC,MAAM,IAAI,GAAG,eAAe,EAAE,CAAC;IAC/B,IAAI,CAAC,IAAI;QAAE,OAAO,SAAS,CAAC;IAC5B,MAAM,CAAC,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IACjD,OAAO,CAAC,EAAE,OAAO,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,KAAe;IACjD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;IAClE,IAAI,MAAM;QAAE,OAAO,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAE9C,MAAM,UAAU,GAAG,oBAAoB,EAAE,CAAC;IAC1C,IAAI,UAAU;QAAE,OAAO,kBAAkB,CAAC,UAAU,CAAC,CAAC;IAEtD,IAAI,KAAK,EAAE,CAAC;QACV,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;YACjC,OAAO,GAAG,GAAG,CAAC,QAAQ,KAAK,GAAG,CAAC,IAAI,EAAE,CAAC;QACxC,CAAC;QAAC,MAAM,CAAC;YACP,eAAe;QACjB,CAAC;IACH,CAAC;IAED,OAAO,uBAAuB,CAAC;AACjC,CAAC"}
@@ -2,6 +2,11 @@ import type { H3Event } from "h3";
2
2
  import type { H3AppShim } from "./framework-request-handler.js";
3
3
  type H3App = H3AppShim;
4
4
  import type { BetterAuthConfig } from "./better-auth-instance.js";
5
+ /**
6
+ * Get the configured session max age. Desktop SSO broker writes from
7
+ * OAuth flows read this so expiration stays consistent with the cookie.
8
+ */
9
+ export declare function getSessionMaxAge(): number;
5
10
  export interface AuthSession {
6
11
  email: string;
7
12
  userId?: string;
@@ -43,6 +48,7 @@ export interface AuthOptions {
43
48
  */
44
49
  betterAuth?: BetterAuthConfig;
45
50
  }
51
+ export declare const COOKIE_NAME: string;
46
52
  /**
47
53
  * Create a new session in the legacy sessions table.
48
54
  * Used by google-oauth.ts for mobile deep linking.
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/server/auth.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAOhE,KAAK,KAAK,GAAG,SAAS,CAAC;AAGvB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AASlE,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oEAAoE;IACpE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kEAAkE;IAClE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,mDAAmD;IACnD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC7D;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;OAEG;IACH,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC/B;AAgHD;;;GAGG;AACH,wBAAsB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAS7E;AAED,uDAAuD;AACvD,wBAAsB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAOhE;AAED;;;GAGG;AACH,wBAAsB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiB3E;AAgCD;;;;;;GAMG;AACH,wBAAsB,YAAY,CAChC,KAAK,EAAE,OAAO,GACb,OAAO,CAAC,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC,CAG5C;AAqFD;;;;;;;;;;;;GAYG;AACH,wBAAsB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAiG5E;AA6nBD;;;;;;;;;;;;GAYG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,KAAK,EACV,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,OAAO,CAAC,CAiJlB;AAMD;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAEzE"}
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/server/auth.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAOhE,KAAK,KAAK,GAAG,SAAS,CAAC;AAQvB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAWlE;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAMD,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oEAAoE;IACpE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kEAAkE;IAClE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,mDAAmD;IACnD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC7D;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;OAEG;IACH,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC/B;AAqBD,eAAO,MAAM,WAAW,QAER,CAAC;AA2HjB;;;GAGG;AACH,wBAAsB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAS7E;AAED,uDAAuD;AACvD,wBAAsB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAOhE;AAED;;;GAGG;AACH,wBAAsB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiB3E;AA0CD;;;;;;GAMG;AACH,wBAAsB,YAAY,CAChC,KAAK,EAAE,OAAO,GACb,OAAO,CAAC,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC,CAG5C;AAqFD;;;;;;;;;;;;GAYG;AACH,wBAAsB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CA0I5E;AAmxBD;;;;;;;;;;;;GAYG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,KAAK,EACV,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,OAAO,CAAC,CA6JlB;AAMD;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAEzE"}
@@ -14,20 +14,47 @@ import { defineEventHandler, getMethod, getQuery, setResponseHeader, setResponse
14
14
  function toWebRequest(event) {
15
15
  return event.req;
16
16
  }
17
- import { getDbExec, isPostgres, intType } from "../db/client.js";
17
+ import { getDbExec, isPostgres, intType, isLocalDatabase, } from "../db/client.js";
18
18
  import { getBetterAuth, getBetterAuthSync } from "./better-auth-instance.js";
19
- import { getOnboardingHtml } from "./onboarding-html.js";
19
+ import { getOnboardingHtml, getResetPasswordHtml } from "./onboarding-html.js";
20
20
  import { migrateLocalUserData } from "./local-migration.js";
21
21
  import { readBody } from "../server/h3-helpers.js";
22
+ import { readDesktopSso, writeDesktopSso, clearDesktopSso, } from "./desktop-sso.js";
23
+ import { isElectron as isElectronRequest } from "./google-oauth.js";
24
+ /**
25
+ * Get the configured session max age. Desktop SSO broker writes from
26
+ * OAuth flows read this so expiration stays consistent with the cookie.
27
+ */
28
+ export function getSessionMaxAge() {
29
+ return sessionMaxAge;
30
+ }
22
31
  // ---------------------------------------------------------------------------
23
32
  // Constants
24
33
  // ---------------------------------------------------------------------------
25
- const COOKIE_NAME = "an_session";
34
+ /**
35
+ * Cookie name for the framework's session cookie.
36
+ *
37
+ * Browsers scope cookies by host (NOT host+port — RFC 6265), so two apps
38
+ * running on different localhost ports share one cookie jar. When multiple
39
+ * templates run side-by-side (`dev:all`, the desktop app, multi-template
40
+ * deploys on a shared domain), they would otherwise stomp on each other's
41
+ * `an_session` cookie and ping-pong each other into a logged-out state.
42
+ *
43
+ * When `APP_NAME` is set, suffix the cookie so each app gets its own slot.
44
+ */
45
+ const APP_NAME_SLUG = (process.env.APP_NAME || "")
46
+ .toLowerCase()
47
+ .replace(/[^a-z0-9]+/g, "_")
48
+ .replace(/^_+|_+$/g, "");
49
+ export const COOKIE_NAME = APP_NAME_SLUG
50
+ ? `an_session_${APP_NAME_SLUG}`
51
+ : "an_session";
26
52
  const DEFAULT_MAX_AGE = 60 * 60 * 24 * 30; // 30 days
27
53
  const LOCAL_MODE_MARKER_PATH = path.resolve(process.cwd(), ".agent-native", "auth-mode");
28
54
  // ---------------------------------------------------------------------------
29
55
  // AUTH_MODE detection
30
56
  // ---------------------------------------------------------------------------
57
+ let _warnedRemoteLocalMode = false;
31
58
  /**
32
59
  * Check if the app is in local-only mode (no auth).
33
60
  *
@@ -39,8 +66,20 @@ const LOCAL_MODE_MARKER_PATH = path.resolve(process.cwd(), ".agent-native", "aut
39
66
  * no auth is used. In development, getSession() also falls back to
40
67
  * local@localhost automatically if no other auth method succeeds, so
41
68
  * apps are always usable without configuration in dev.
69
+ *
70
+ * Refuses to enable on any non-local database (Postgres, Turso, D1): local
71
+ * mode uses a single shared virtual user with no per-machine scoping, so on
72
+ * a shared DB every developer would land on the same account and collide.
42
73
  */
43
74
  async function isLocalModeEnabled() {
75
+ if (!isLocalDatabase()) {
76
+ if (process.env.AUTH_MODE === "local" && !_warnedRemoteLocalMode) {
77
+ _warnedRemoteLocalMode = true;
78
+ console.warn("[agent-native] AUTH_MODE=local ignored: database is not local SQLite. " +
79
+ "local@localhost has no per-user scoping and would collide across developers on a shared DB.");
80
+ }
81
+ return false;
82
+ }
44
83
  if (process.env.AUTH_MODE === "local")
45
84
  return true;
46
85
  try {
@@ -174,6 +213,15 @@ let _authGuardConfig = null;
174
213
  * /_agent-native/* routes).
175
214
  */
176
215
  let _authGuardFn = null;
216
+ /**
217
+ * The H3 app the auth routes + guard were last mounted on. Module-level
218
+ * state survives Vite HMR restarts, but each HMR cycle creates a fresh
219
+ * nitroApp/H3 instance whose middleware array is empty again. Tracking the
220
+ * app here lets autoMountAuth detect "same module state, new app" and
221
+ * re-mount routes instead of silently skipping them because `_authGuardFn`
222
+ * looks populated from a previous cycle.
223
+ */
224
+ let _mountedApp = null;
177
225
  /**
178
226
  * Run the auth guard on an event. Returns a Response/object to block the
179
227
  * request (login page or 401), or undefined to allow it through.
@@ -314,6 +362,14 @@ export async function getSession(event) {
314
362
  const session = await customGetSession(event);
315
363
  if (session)
316
364
  return session;
365
+ // Desktop SSO broker: even with BYOA auth, fall back to the broker
366
+ // for Electron requests so cross-template SSO works for custom-auth
367
+ // templates too.
368
+ if (isElectronRequest(event)) {
369
+ const sso = await readDesktopSso();
370
+ if (sso?.email)
371
+ return { email: sso.email, token: sso.token };
372
+ }
317
373
  // Fall through to mobile _session check
318
374
  }
319
375
  else {
@@ -325,6 +381,9 @@ export async function getSession(event) {
325
381
  headers: event.headers,
326
382
  });
327
383
  if (baSession?.user?.email) {
384
+ // Successful real sign-in — clear the upgrade-pending marker so
385
+ // the dev fallback becomes reachable again for future local work.
386
+ clearUpgradePendingCookie(event);
328
387
  return mapBetterAuthSession(baSession);
329
388
  }
330
389
  }
@@ -336,8 +395,24 @@ export async function getSession(event) {
336
395
  const cookie = getCookie(event, COOKIE_NAME);
337
396
  if (cookie) {
338
397
  const email = await getSessionEmail(cookie);
339
- if (email)
398
+ if (email) {
399
+ clearUpgradePendingCookie(event);
340
400
  return { email, token: cookie };
401
+ }
402
+ }
403
+ // 5b. Desktop SSO broker fallback.
404
+ // Each template in the Electron desktop app has its own database, so
405
+ // a session token created by one template doesn't resolve in another.
406
+ // When an Electron request has no resolvable session, trust the
407
+ // home-dir SSO record written by whichever template the user signed
408
+ // into. Gated on Electron user-agent so no non-desktop code path
409
+ // consults the file.
410
+ if (isElectronRequest(event)) {
411
+ const sso = await readDesktopSso();
412
+ if (sso?.email) {
413
+ clearUpgradePendingCookie(event);
414
+ return { email: sso.email, token: sso.token };
415
+ }
341
416
  }
342
417
  }
343
418
  // 6. Mobile WebView bridge — _session query param
@@ -347,8 +422,7 @@ export async function getSession(event) {
347
422
  if (email) {
348
423
  setCookie(event, COOKIE_NAME, qToken, {
349
424
  httpOnly: true,
350
- secure: !isDevEnvironment(),
351
- sameSite: "lax",
425
+ ...crossSiteCookieAttrs(event),
352
426
  path: "/",
353
427
  maxAge: sessionMaxAge,
354
428
  });
@@ -356,15 +430,113 @@ export async function getSession(event) {
356
430
  return { email, token: qToken };
357
431
  }
358
432
  }
359
- // 7. Dev-mode safety net — in development, always fall back to local@localhost
360
- // so the app is usable without any auth configuration. This prevents 401
361
- // errors when Better Auth isn't configured, the marker file is missing, or
362
- // the user simply wants to play around locally.
363
- if (isDevEnvironment()) {
433
+ // 7. Dev-mode safety net — in development on a local SQLite database, fall
434
+ // back to local@localhost so the app is usable without any auth configuration.
435
+ // This prevents 401 errors when Better Auth isn't configured, the marker file
436
+ // is missing, or the user simply wants to play around locally.
437
+ //
438
+ // Gated on isLocalDatabase() because local@localhost has no per-user scoping:
439
+ // on a shared DB (Postgres, Turso, D1) this fallback would land every
440
+ // developer on the same account and expose each other's data.
441
+ //
442
+ // EXCEPTION: if the user has explicitly exited local mode (clicked "Upgrade
443
+ // to real account"), they've signaled they want real auth. The upgrade
444
+ // cookie suppresses this fallback so the onboarding/sign-in page is served
445
+ // instead of silently re-authenticating them as local@localhost.
446
+ if (isDevEnvironment() &&
447
+ isLocalDatabase() &&
448
+ !isUpgradePending(event) &&
449
+ !hasSignInFlag(event)) {
364
450
  return LOCAL_SESSION;
365
451
  }
366
452
  return null;
367
453
  }
454
+ /**
455
+ * Cookie set by POST /_agent-native/auth/exit-local-mode so we know the user
456
+ * is in the middle of upgrading from local@localhost to a real account.
457
+ * While this cookie is present we skip the dev-mode "auto local session"
458
+ * fallback so the onboarding/sign-in page can actually render.
459
+ * Cleared on successful sign-in/sign-up.
460
+ */
461
+ const UPGRADE_COOKIE = "an_upgrade_pending";
462
+ function isUpgradePending(event) {
463
+ try {
464
+ return getCookie(event, UPGRADE_COOKIE) === "1";
465
+ }
466
+ catch {
467
+ return false;
468
+ }
469
+ }
470
+ function setUpgradePendingCookie(event) {
471
+ setCookie(event, UPGRADE_COOKIE, "1", {
472
+ httpOnly: true,
473
+ ...crossSiteCookieAttrs(event),
474
+ path: "/",
475
+ maxAge: 60 * 60, // 1 hour — enough to complete sign-in
476
+ });
477
+ }
478
+ /**
479
+ * URL-flag fallback for third-party iframe contexts (e.g. the Builder.io
480
+ * editor) where SameSite=Lax cookies from an exit-local-mode POST are not
481
+ * delivered on the subsequent reload. TeamPage reloads with ?signin=1 so
482
+ * we can reliably suppress the dev-mode local fallback without a cookie.
483
+ */
484
+ function hasSignInFlag(event) {
485
+ try {
486
+ return getQuery(event)?.signin === "1";
487
+ }
488
+ catch {
489
+ return false;
490
+ }
491
+ }
492
+ /**
493
+ * Cookie attributes that work in both same-site and third-party iframe
494
+ * contexts. Over HTTPS we emit `SameSite=None; Secure` (required by browsers
495
+ * to ship the cookie back inside a cross-origin iframe); for plain HTTP dev
496
+ * we keep `SameSite=Lax` since `None` requires Secure.
497
+ */
498
+ function crossSiteCookieAttrs(event) {
499
+ return isHttpsRequest(event)
500
+ ? { sameSite: "none", secure: true }
501
+ : { sameSite: "lax", secure: false };
502
+ }
503
+ function isHttpsRequest(event) {
504
+ try {
505
+ const req = event.req ?? event.node?.req;
506
+ const headers = req?.headers;
507
+ const get = (k) => {
508
+ if (!headers)
509
+ return undefined;
510
+ if (typeof headers.get === "function") {
511
+ return headers.get(k) ?? undefined;
512
+ }
513
+ const v = headers[k];
514
+ return Array.isArray(v) ? v[0] : v;
515
+ };
516
+ const xfProto = get("x-forwarded-proto");
517
+ if (xfProto && String(xfProto).split(",")[0].trim() === "https") {
518
+ return true;
519
+ }
520
+ const url = req?.url;
521
+ if (typeof url === "string" && url.startsWith("https://"))
522
+ return true;
523
+ const appUrl = process.env.APP_URL || process.env.BETTER_AUTH_URL || "";
524
+ if (appUrl.startsWith("https://"))
525
+ return true;
526
+ }
527
+ catch {
528
+ // ignore
529
+ }
530
+ return false;
531
+ }
532
+ function clearUpgradePendingCookie(event) {
533
+ try {
534
+ deleteCookie(event, UPGRADE_COOKIE, { path: "/" });
535
+ }
536
+ catch {
537
+ // ignore
538
+ }
539
+ }
368
540
  // ---------------------------------------------------------------------------
369
541
  // Public path matching
370
542
  // ---------------------------------------------------------------------------
@@ -489,6 +661,38 @@ async function removeAuthModeLocal() {
489
661
  return false;
490
662
  }
491
663
  }
664
+ /**
665
+ * POST /_agent-native/auth/migrate-local-data handler. Exposed here (not
666
+ * inlined in a single mount function) because it must be registered from
667
+ * every auth-mount path — including local-mode and fallback — so the
668
+ * upgrade-from-local flow never 500s when BetterAuth init is skipped or
669
+ * failed. Previously this was only mounted inside mountBetterAuthRoutes()
670
+ * which meant that in local mode (or when BetterAuth failed to init) the
671
+ * request fell through to the Nitro SSR renderer and produced a 500.
672
+ */
673
+ const migrateLocalDataHandler = defineEventHandler(async (event) => {
674
+ if (getMethod(event) !== "POST") {
675
+ setResponseStatus(event, 405);
676
+ return { error: "Method not allowed" };
677
+ }
678
+ const session = await getSession(event);
679
+ if (!session?.email || session.email === "local@localhost") {
680
+ setResponseStatus(event, 401);
681
+ return { error: "Not authenticated as a real account" };
682
+ }
683
+ try {
684
+ const result = await migrateLocalUserData(session.email);
685
+ return { ok: true, ...result };
686
+ }
687
+ catch (e) {
688
+ console.error("[migrate-local-data] Migration threw for", session.email, e);
689
+ setResponseStatus(event, 500);
690
+ return {
691
+ error: e?.message || "Migration failed",
692
+ stack: isDevEnvironment() ? e?.stack : undefined,
693
+ };
694
+ }
695
+ });
492
696
  // ---------------------------------------------------------------------------
493
697
  // mountBetterAuthRoutes — Better Auth powered auth with backward-compat routes
494
698
  // ---------------------------------------------------------------------------
@@ -549,6 +753,9 @@ async function mountBetterAuthRoutes(app, options) {
549
753
  setResponseStatus(event, 500);
550
754
  return { error: "Failed to disable local mode" };
551
755
  }
756
+ // Mark the browser so getSession's dev-mode fallback won't silently
757
+ // re-authenticate the user as local@localhost on the next request.
758
+ setUpgradePendingCookie(event);
552
759
  return { ok: true };
553
760
  }));
554
761
  // Backward-compat: POST /_agent-native/auth/login
@@ -570,8 +777,7 @@ async function mountBetterAuthRoutes(app, options) {
570
777
  await addSession(sessionToken, "user");
571
778
  setCookie(event, COOKIE_NAME, sessionToken, {
572
779
  httpOnly: true,
573
- secure: !isDevEnvironment(),
574
- sameSite: "lax",
780
+ ...crossSiteCookieAttrs(event),
575
781
  path: "/",
576
782
  maxAge: sessionMaxAge,
577
783
  });
@@ -591,12 +797,18 @@ async function mountBetterAuthRoutes(app, options) {
591
797
  if (result?.token) {
592
798
  setCookie(event, COOKIE_NAME, result.token, {
593
799
  httpOnly: true,
594
- secure: !isDevEnvironment(),
595
- sameSite: "lax",
800
+ ...crossSiteCookieAttrs(event),
596
801
  path: "/",
597
802
  maxAge: sessionMaxAge,
598
803
  });
599
804
  await addSession(result.token, email);
805
+ if (isElectronRequest(event)) {
806
+ await writeDesktopSso({
807
+ email,
808
+ token: result.token,
809
+ expiresAt: Date.now() + sessionMaxAge * 1000,
810
+ });
811
+ }
600
812
  }
601
813
  return { ok: true };
602
814
  }
@@ -645,6 +857,8 @@ async function mountBetterAuthRoutes(app, options) {
645
857
  catch {
646
858
  // Ignore if no Better Auth session
647
859
  }
860
+ if (isElectronRequest(event))
861
+ await clearDesktopSso();
648
862
  return { ok: true };
649
863
  }));
650
864
  // GET /_agent-native/auth/session
@@ -659,24 +873,18 @@ async function mountBetterAuthRoutes(app, options) {
659
873
  // POST /_agent-native/auth/migrate-local-data — move local-mode data to
660
874
  // the currently signed-in account. Called by the UI after a user upgrades
661
875
  // from local mode to a real account so they don't lose their data.
662
- app.use("/_agent-native/auth/migrate-local-data", defineEventHandler(async (event) => {
663
- if (getMethod(event) !== "POST") {
876
+ app.use("/_agent-native/auth/migrate-local-data", migrateLocalDataHandler);
877
+ // GET /_agent-native/auth/reset HTML page shown when a user clicks the
878
+ // reset link in their email. Reads ?token=... and POSTs to Better Auth's
879
+ // /reset-password endpoint on submit.
880
+ app.use("/_agent-native/auth/reset", defineEventHandler((event) => {
881
+ if (getMethod(event) !== "GET") {
664
882
  setResponseStatus(event, 405);
665
883
  return { error: "Method not allowed" };
666
884
  }
667
- const session = await getSession(event);
668
- if (!session?.email || session.email === "local@localhost") {
669
- setResponseStatus(event, 401);
670
- return { error: "Not authenticated as a real account" };
671
- }
672
- try {
673
- const result = await migrateLocalUserData(session.email);
674
- return { ok: true, ...result };
675
- }
676
- catch (e) {
677
- setResponseStatus(event, 500);
678
- return { error: e?.message || "Migration failed" };
679
- }
885
+ return new Response(getResetPasswordHtml(), {
886
+ headers: { "Content-Type": "text/html; charset=utf-8" },
887
+ });
680
888
  }));
681
889
  // Auth guard — stored both in framework middleware registry AND in
682
890
  // _authGuardFn so the server middleware can enforce it on ALL routes.
@@ -706,8 +914,7 @@ function mountTokenOnlyRoutes(app, accessTokens, publicPaths = []) {
706
914
  await addSession(sessionToken, "user");
707
915
  setCookie(event, COOKIE_NAME, sessionToken, {
708
916
  httpOnly: true,
709
- secure: !isDevEnvironment(),
710
- sameSite: "lax",
917
+ ...crossSiteCookieAttrs(event),
711
918
  path: "/",
712
919
  maxAge: sessionMaxAge,
713
920
  });
@@ -718,6 +925,8 @@ function mountTokenOnlyRoutes(app, accessTokens, publicPaths = []) {
718
925
  if (cookie)
719
926
  await removeSession(cookie);
720
927
  deleteCookie(event, COOKIE_NAME, { path: "/" });
928
+ if (isElectronRequest(event))
929
+ await clearDesktopSso();
721
930
  return { ok: true };
722
931
  }));
723
932
  app.use("/_agent-native/auth/session", defineEventHandler(async (event) => {
@@ -728,6 +937,7 @@ function mountTokenOnlyRoutes(app, accessTokens, publicPaths = []) {
728
937
  const session = await getSession(event);
729
938
  return session ?? { error: "Not authenticated" };
730
939
  }));
940
+ app.use("/_agent-native/auth/migrate-local-data", migrateLocalDataHandler);
731
941
  _authGuardConfig = { loginHtml: TOKEN_LOGIN_HTML, publicPaths };
732
942
  const guardFn = createAuthGuardFn();
733
943
  _authGuardFn = guardFn;
@@ -757,8 +967,14 @@ function mountLocalModeRoutes(app) {
757
967
  setResponseStatus(event, 500);
758
968
  return { error: "Failed to disable local mode" };
759
969
  }
970
+ // Mark the browser so getSession's dev-mode fallback won't silently
971
+ // re-authenticate the user as local@localhost on the next request.
972
+ setUpgradePendingCookie(event);
760
973
  return { ok: true };
761
974
  }));
975
+ // Upgrade path: migrate-local-data must be reachable from local mode
976
+ // because the user is still in local mode when they trigger the upgrade.
977
+ app.use("/_agent-native/auth/migrate-local-data", migrateLocalDataHandler);
762
978
  }
763
979
  // ---------------------------------------------------------------------------
764
980
  // mountAuthFallbackRoutes — minimal auth endpoints when Better Auth init fails
@@ -784,12 +1000,18 @@ function mountAuthFallbackRoutes(app) {
784
1000
  if (result?.token) {
785
1001
  setCookie(event, COOKIE_NAME, result.token, {
786
1002
  httpOnly: true,
787
- secure: !isDevEnvironment(),
788
- sameSite: "lax",
1003
+ ...crossSiteCookieAttrs(event),
789
1004
  path: "/",
790
1005
  maxAge: sessionMaxAge,
791
1006
  });
792
1007
  await addSession(result.token, email);
1008
+ if (isElectronRequest(event)) {
1009
+ await writeDesktopSso({
1010
+ email,
1011
+ token: result.token,
1012
+ expiresAt: Date.now() + sessionMaxAge * 1000,
1013
+ });
1014
+ }
793
1015
  }
794
1016
  return { ok: true };
795
1017
  }
@@ -838,6 +1060,8 @@ function mountAuthFallbackRoutes(app) {
838
1060
  catch {
839
1061
  // Ignore if Better Auth is still unavailable
840
1062
  }
1063
+ if (isElectronRequest(event))
1064
+ await clearDesktopSso();
841
1065
  return { ok: true };
842
1066
  }));
843
1067
  app.use("/_agent-native/auth/local-mode", defineEventHandler(async (event) => {
@@ -868,6 +1092,9 @@ function mountAuthFallbackRoutes(app) {
868
1092
  setResponseStatus(event, 500);
869
1093
  return { error: "Failed to disable local mode" };
870
1094
  }
1095
+ // Mark the browser so getSession's dev-mode fallback won't silently
1096
+ // re-authenticate the user as local@localhost on the next request.
1097
+ setUpgradePendingCookie(event);
871
1098
  return { ok: true };
872
1099
  }));
873
1100
  app.use("/_agent-native/auth/session", defineEventHandler(async (event) => {
@@ -878,6 +1105,10 @@ function mountAuthFallbackRoutes(app) {
878
1105
  const session = await getSession(event);
879
1106
  return session ?? { error: "Not authenticated" };
880
1107
  }));
1108
+ // Must be reachable from fallback mode too — otherwise a user who
1109
+ // upgrades-from-local on a server that couldn't init Better Auth gets a
1110
+ // 500 instead of a clear 401.
1111
+ app.use("/_agent-native/auth/migrate-local-data", migrateLocalDataHandler);
881
1112
  }
882
1113
  // ---------------------------------------------------------------------------
883
1114
  // autoMountAuth — the recommended entry point
@@ -896,13 +1127,17 @@ function mountAuthFallbackRoutes(app) {
896
1127
  * Returns true if auth was mounted, false if skipped.
897
1128
  */
898
1129
  export async function autoMountAuth(app, options = {}) {
899
- // If auth is already mounted (e.g., default plugin ran before custom plugin),
900
- // don't re-mount routes — but DO update the live config if custom options
901
- // like googleOnly or loginHtml were provided. This fixes the production race
902
- // where the default plugin (no googleOnly) mounts first, and the template's
903
- // custom auth plugin runs later. Because createAuthGuardFn() reads from
904
- // _authGuardConfig on every request, updating it here takes effect immediately.
905
- if (_authGuardFn) {
1130
+ // If auth is already mounted on THIS app (e.g., default plugin ran before
1131
+ // custom plugin in the same server boot), don't re-mount routes — but DO
1132
+ // update the live config if custom options like googleOnly or loginHtml
1133
+ // were provided. createAuthGuardFn() reads from _authGuardConfig on every
1134
+ // request, so updating it here takes effect immediately.
1135
+ //
1136
+ // We gate on `_mountedApp === app` because module-level state survives
1137
+ // Vite HMR — without this check, an HMR-restarted Nitro instance (fresh
1138
+ // H3 app, empty middleware) would short-circuit here and end up with no
1139
+ // auth routes mounted at all.
1140
+ if (_authGuardFn && _mountedApp === app) {
906
1141
  if (_authGuardConfig) {
907
1142
  if (options.googleOnly || options.loginHtml) {
908
1143
  _authGuardConfig.loginHtml =
@@ -918,6 +1153,11 @@ export async function autoMountAuth(app, options = {}) {
918
1153
  }
919
1154
  return true;
920
1155
  }
1156
+ // Fresh app (first boot, or HMR created a new Nitro instance) — reset
1157
+ // the guard so the mount path below installs it on the new app.
1158
+ _authGuardFn = null;
1159
+ _authGuardConfig = null;
1160
+ _mountedApp = app;
921
1161
  if (!app) {
922
1162
  if ((await isLocalModeEnabled()) || isDevEnvironment()) {
923
1163
  authDisabledMode = false;
@@ -965,8 +1205,11 @@ export async function autoMountAuth(app, options = {}) {
965
1205
  if (cookie)
966
1206
  await removeSession(cookie);
967
1207
  deleteCookie(event, COOKIE_NAME, { path: "/" });
1208
+ if (isElectronRequest(event))
1209
+ await clearDesktopSso();
968
1210
  return { ok: true };
969
1211
  }));
1212
+ app.use("/_agent-native/auth/migrate-local-data", migrateLocalDataHandler);
970
1213
  const byoaLoginHtml = options.loginHtml ?? TOKEN_LOGIN_HTML;
971
1214
  _authGuardConfig = { loginHtml: byoaLoginHtml, publicPaths };
972
1215
  const guardFn = createAuthGuardFn();