@agent-native/core 0.9.1 → 0.11.0

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 (288) hide show
  1. package/README.md +4 -4
  2. package/dist/a2a/caller-auth.d.ts +12 -0
  3. package/dist/a2a/caller-auth.d.ts.map +1 -0
  4. package/dist/a2a/caller-auth.js +54 -0
  5. package/dist/a2a/caller-auth.js.map +1 -0
  6. package/dist/action.d.ts +17 -0
  7. package/dist/action.d.ts.map +1 -1
  8. package/dist/action.js +22 -0
  9. package/dist/action.js.map +1 -1
  10. package/dist/agent/engine/builder-engine.d.ts.map +1 -1
  11. package/dist/agent/engine/builder-engine.js +5 -4
  12. package/dist/agent/engine/builder-engine.js.map +1 -1
  13. package/dist/agent/engine/registry.d.ts +6 -3
  14. package/dist/agent/engine/registry.d.ts.map +1 -1
  15. package/dist/agent/engine/registry.js +8 -17
  16. package/dist/agent/engine/registry.js.map +1 -1
  17. package/dist/agent/production-agent.d.ts +1 -1
  18. package/dist/agent/production-agent.d.ts.map +1 -1
  19. package/dist/agent/production-agent.js +60 -30
  20. package/dist/agent/production-agent.js.map +1 -1
  21. package/dist/agent/run-manager.d.ts.map +1 -1
  22. package/dist/agent/run-manager.js +12 -3
  23. package/dist/agent/run-manager.js.map +1 -1
  24. package/dist/agent/thread-data-builder.d.ts +12 -0
  25. package/dist/agent/thread-data-builder.d.ts.map +1 -1
  26. package/dist/agent/thread-data-builder.js +96 -0
  27. package/dist/agent/thread-data-builder.js.map +1 -1
  28. package/dist/cli/create.d.ts.map +1 -1
  29. package/dist/cli/create.js +16 -10
  30. package/dist/cli/create.js.map +1 -1
  31. package/dist/client/AgentPanel.d.ts.map +1 -1
  32. package/dist/client/AgentPanel.js +8 -22
  33. package/dist/client/AgentPanel.js.map +1 -1
  34. package/dist/client/AssistantChat.d.ts.map +1 -1
  35. package/dist/client/AssistantChat.js +130 -34
  36. package/dist/client/AssistantChat.js.map +1 -1
  37. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  38. package/dist/client/agent-chat-adapter.js +21 -7
  39. package/dist/client/agent-chat-adapter.js.map +1 -1
  40. package/dist/client/agent-sidebar-state.d.ts +3 -0
  41. package/dist/client/agent-sidebar-state.d.ts.map +1 -0
  42. package/dist/client/agent-sidebar-state.js +24 -0
  43. package/dist/client/agent-sidebar-state.js.map +1 -0
  44. package/dist/client/analytics.d.ts +25 -0
  45. package/dist/client/analytics.d.ts.map +1 -1
  46. package/dist/client/analytics.js +40 -0
  47. package/dist/client/analytics.js.map +1 -1
  48. package/dist/client/components/ui/dropdown-menu.d.ts +28 -0
  49. package/dist/client/components/ui/dropdown-menu.d.ts.map +1 -0
  50. package/dist/client/components/ui/dropdown-menu.js +34 -0
  51. package/dist/client/components/ui/dropdown-menu.js.map +1 -0
  52. package/dist/client/components/ui/tooltip.d.ts +2 -1
  53. package/dist/client/components/ui/tooltip.d.ts.map +1 -1
  54. package/dist/client/components/ui/tooltip.js +9 -2
  55. package/dist/client/components/ui/tooltip.js.map +1 -1
  56. package/dist/client/composer/ComposerPlusMenu.d.ts.map +1 -1
  57. package/dist/client/composer/ComposerPlusMenu.js +41 -8
  58. package/dist/client/composer/ComposerPlusMenu.js.map +1 -1
  59. package/dist/client/composer/PromptComposer.d.ts.map +1 -1
  60. package/dist/client/composer/PromptComposer.js +30 -0
  61. package/dist/client/composer/PromptComposer.js.map +1 -1
  62. package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
  63. package/dist/client/composer/TiptapComposer.js +27 -2
  64. package/dist/client/composer/TiptapComposer.js.map +1 -1
  65. package/dist/client/dev-overlay/DevOverlay.d.ts.map +1 -1
  66. package/dist/client/dev-overlay/DevOverlay.js +4 -4
  67. package/dist/client/dev-overlay/DevOverlay.js.map +1 -1
  68. package/dist/client/error-format.d.ts.map +1 -1
  69. package/dist/client/error-format.js +6 -0
  70. package/dist/client/error-format.js.map +1 -1
  71. package/dist/client/extensions/EmbeddedExtension.d.ts.map +1 -1
  72. package/dist/client/extensions/EmbeddedExtension.js +16 -4
  73. package/dist/client/extensions/EmbeddedExtension.js.map +1 -1
  74. package/dist/client/extensions/ExtensionEditor.d.ts.map +1 -1
  75. package/dist/client/extensions/ExtensionEditor.js +6 -6
  76. package/dist/client/extensions/ExtensionEditor.js.map +1 -1
  77. package/dist/client/extensions/ExtensionSlot.d.ts.map +1 -1
  78. package/dist/client/extensions/ExtensionSlot.js +15 -2
  79. package/dist/client/extensions/ExtensionSlot.js.map +1 -1
  80. package/dist/client/extensions/ExtensionViewer.d.ts.map +1 -1
  81. package/dist/client/extensions/ExtensionViewer.js +41 -19
  82. package/dist/client/extensions/ExtensionViewer.js.map +1 -1
  83. package/dist/client/extensions/ExtensionsListPage.d.ts.map +1 -1
  84. package/dist/client/extensions/ExtensionsListPage.js +2 -2
  85. package/dist/client/extensions/ExtensionsListPage.js.map +1 -1
  86. package/dist/client/extensions/ExtensionsSidebarSection.d.ts.map +1 -1
  87. package/dist/client/extensions/ExtensionsSidebarSection.js +52 -63
  88. package/dist/client/extensions/ExtensionsSidebarSection.js.map +1 -1
  89. package/dist/client/extensions/iframe-bridge.d.ts.map +1 -1
  90. package/dist/client/extensions/iframe-bridge.js +5 -8
  91. package/dist/client/extensions/iframe-bridge.js.map +1 -1
  92. package/dist/client/index.d.ts +1 -1
  93. package/dist/client/index.d.ts.map +1 -1
  94. package/dist/client/index.js +1 -1
  95. package/dist/client/index.js.map +1 -1
  96. package/dist/client/notifications/NotificationsBell.d.ts.map +1 -1
  97. package/dist/client/notifications/NotificationsBell.js +42 -6
  98. package/dist/client/notifications/NotificationsBell.js.map +1 -1
  99. package/dist/client/org/InvitationBanner.d.ts.map +1 -1
  100. package/dist/client/org/InvitationBanner.js +5 -5
  101. package/dist/client/org/InvitationBanner.js.map +1 -1
  102. package/dist/client/org/OrgSwitcher.d.ts +7 -1
  103. package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
  104. package/dist/client/org/OrgSwitcher.js +8 -3
  105. package/dist/client/org/OrgSwitcher.js.map +1 -1
  106. package/dist/client/org/TeamPage.d.ts.map +1 -1
  107. package/dist/client/org/TeamPage.js +156 -22
  108. package/dist/client/org/TeamPage.js.map +1 -1
  109. package/dist/client/org/hooks.d.ts +29 -1
  110. package/dist/client/org/hooks.d.ts.map +1 -1
  111. package/dist/client/org/hooks.js +39 -2
  112. package/dist/client/org/hooks.js.map +1 -1
  113. package/dist/client/org/index.d.ts +2 -1
  114. package/dist/client/org/index.d.ts.map +1 -1
  115. package/dist/client/org/index.js +1 -1
  116. package/dist/client/org/index.js.map +1 -1
  117. package/dist/client/resources/ResourceTree.d.ts.map +1 -1
  118. package/dist/client/resources/ResourceTree.js +11 -3
  119. package/dist/client/resources/ResourceTree.js.map +1 -1
  120. package/dist/client/resources/ResourcesPanel.d.ts.map +1 -1
  121. package/dist/client/resources/ResourcesPanel.js +62 -12
  122. package/dist/client/resources/ResourcesPanel.js.map +1 -1
  123. package/dist/client/resources/use-mcp-servers.d.ts +2 -0
  124. package/dist/client/resources/use-mcp-servers.d.ts.map +1 -1
  125. package/dist/client/resources/use-mcp-servers.js +59 -3
  126. package/dist/client/resources/use-mcp-servers.js.map +1 -1
  127. package/dist/client/settings/SecretsSection.d.ts.map +1 -1
  128. package/dist/client/settings/SecretsSection.js +9 -0
  129. package/dist/client/settings/SecretsSection.js.map +1 -1
  130. package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
  131. package/dist/client/settings/SettingsPanel.js +50 -12
  132. package/dist/client/settings/SettingsPanel.js.map +1 -1
  133. package/dist/client/settings/VoiceTranscriptionSection.d.ts.map +1 -1
  134. package/dist/client/settings/VoiceTranscriptionSection.js +13 -30
  135. package/dist/client/settings/VoiceTranscriptionSection.js.map +1 -1
  136. package/dist/client/settings/useBuilderStatus.d.ts.map +1 -1
  137. package/dist/client/settings/useBuilderStatus.js +27 -1
  138. package/dist/client/settings/useBuilderStatus.js.map +1 -1
  139. package/dist/client/sharing/ShareButton.d.ts +4 -0
  140. package/dist/client/sharing/ShareButton.d.ts.map +1 -1
  141. package/dist/client/sharing/ShareButton.js +5 -1
  142. package/dist/client/sharing/ShareButton.js.map +1 -1
  143. package/dist/client/sse-event-processor.d.ts +1 -1
  144. package/dist/client/sse-event-processor.d.ts.map +1 -1
  145. package/dist/client/sse-event-processor.js +14 -7
  146. package/dist/client/sse-event-processor.js.map +1 -1
  147. package/dist/client/use-db-sync.d.ts.map +1 -1
  148. package/dist/client/use-db-sync.js +100 -19
  149. package/dist/client/use-db-sync.js.map +1 -1
  150. package/dist/deploy/build.d.ts.map +1 -1
  151. package/dist/deploy/build.js +25 -49
  152. package/dist/deploy/build.js.map +1 -1
  153. package/dist/deploy/route-discovery.d.ts.map +1 -1
  154. package/dist/deploy/route-discovery.js +1 -0
  155. package/dist/deploy/route-discovery.js.map +1 -1
  156. package/dist/deploy/workspace-core.d.ts +1 -1
  157. package/dist/deploy/workspace-core.d.ts.map +1 -1
  158. package/dist/deploy/workspace-core.js +1 -0
  159. package/dist/deploy/workspace-core.js.map +1 -1
  160. package/dist/extensions/actions.d.ts.map +1 -1
  161. package/dist/extensions/actions.js +17 -3
  162. package/dist/extensions/actions.js.map +1 -1
  163. package/dist/extensions/routes.js +1 -1
  164. package/dist/extensions/routes.js.map +1 -1
  165. package/dist/extensions/schema.d.ts +14 -14
  166. package/dist/extensions/schema.d.ts.map +1 -1
  167. package/dist/extensions/schema.js +4 -4
  168. package/dist/extensions/schema.js.map +1 -1
  169. package/dist/extensions/store.d.ts.map +1 -1
  170. package/dist/extensions/store.js +23 -0
  171. package/dist/extensions/store.js.map +1 -1
  172. package/dist/extensions/theme.d.ts +8 -1
  173. package/dist/extensions/theme.d.ts.map +1 -1
  174. package/dist/extensions/theme.js +43 -34
  175. package/dist/extensions/theme.js.map +1 -1
  176. package/dist/index.browser.d.ts +1 -1
  177. package/dist/index.browser.d.ts.map +1 -1
  178. package/dist/index.browser.js +1 -1
  179. package/dist/index.browser.js.map +1 -1
  180. package/dist/index.d.ts +1 -1
  181. package/dist/index.d.ts.map +1 -1
  182. package/dist/index.js +1 -1
  183. package/dist/index.js.map +1 -1
  184. package/dist/mcp-client/routes.d.ts +1 -0
  185. package/dist/mcp-client/routes.d.ts.map +1 -1
  186. package/dist/mcp-client/routes.js +28 -1
  187. package/dist/mcp-client/routes.js.map +1 -1
  188. package/dist/org/accept-pending.d.ts.map +1 -1
  189. package/dist/org/accept-pending.js +5 -3
  190. package/dist/org/accept-pending.js.map +1 -1
  191. package/dist/org/free-email-providers.d.ts +18 -0
  192. package/dist/org/free-email-providers.d.ts.map +1 -0
  193. package/dist/org/free-email-providers.js +124 -0
  194. package/dist/org/free-email-providers.js.map +1 -0
  195. package/dist/org/handlers.d.ts +29 -5
  196. package/dist/org/handlers.d.ts.map +1 -1
  197. package/dist/org/handlers.js +178 -37
  198. package/dist/org/handlers.js.map +1 -1
  199. package/dist/org/index.d.ts +2 -1
  200. package/dist/org/index.d.ts.map +1 -1
  201. package/dist/org/index.js +2 -1
  202. package/dist/org/index.js.map +1 -1
  203. package/dist/org/migrations.d.ts.map +1 -1
  204. package/dist/org/migrations.js +4 -0
  205. package/dist/org/migrations.js.map +1 -1
  206. package/dist/org/plugin.d.ts.map +1 -1
  207. package/dist/org/plugin.js +13 -4
  208. package/dist/org/plugin.js.map +1 -1
  209. package/dist/org/schema.d.ts +19 -0
  210. package/dist/org/schema.d.ts.map +1 -1
  211. package/dist/org/schema.js +1 -0
  212. package/dist/org/schema.js.map +1 -1
  213. package/dist/org/types.d.ts +1 -0
  214. package/dist/org/types.d.ts.map +1 -1
  215. package/dist/org/types.js.map +1 -1
  216. package/dist/resources/metadata.d.ts +1 -0
  217. package/dist/resources/metadata.d.ts.map +1 -1
  218. package/dist/resources/metadata.js +13 -3
  219. package/dist/resources/metadata.js.map +1 -1
  220. package/dist/resources/store.d.ts.map +1 -1
  221. package/dist/resources/store.js +44 -6
  222. package/dist/resources/store.js.map +1 -1
  223. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  224. package/dist/server/agent-chat-plugin.js +115 -113
  225. package/dist/server/agent-chat-plugin.js.map +1 -1
  226. package/dist/server/auth.d.ts.map +1 -1
  227. package/dist/server/auth.js +33 -0
  228. package/dist/server/auth.js.map +1 -1
  229. package/dist/server/builder-browser.d.ts.map +1 -1
  230. package/dist/server/builder-browser.js +169 -68
  231. package/dist/server/builder-browser.js.map +1 -1
  232. package/dist/server/credential-provider.d.ts +2 -2
  233. package/dist/server/credential-provider.d.ts.map +1 -1
  234. package/dist/server/credential-provider.js +31 -12
  235. package/dist/server/credential-provider.js.map +1 -1
  236. package/dist/server/framework-request-handler.d.ts.map +1 -1
  237. package/dist/server/framework-request-handler.js +31 -0
  238. package/dist/server/framework-request-handler.js.map +1 -1
  239. package/dist/server/google-oauth.d.ts.map +1 -1
  240. package/dist/server/google-oauth.js +10 -3
  241. package/dist/server/google-oauth.js.map +1 -1
  242. package/dist/server/google-realtime-session.d.ts.map +1 -1
  243. package/dist/server/google-realtime-session.js +19 -6
  244. package/dist/server/google-realtime-session.js.map +1 -1
  245. package/dist/server/index.d.ts +2 -0
  246. package/dist/server/index.d.ts.map +1 -1
  247. package/dist/server/index.js +2 -0
  248. package/dist/server/index.js.map +1 -1
  249. package/dist/server/onboarding-html.d.ts.map +1 -1
  250. package/dist/server/onboarding-html.js +45 -6
  251. package/dist/server/onboarding-html.js.map +1 -1
  252. package/dist/server/request-context.d.ts +17 -0
  253. package/dist/server/request-context.d.ts.map +1 -1
  254. package/dist/server/request-context.js +40 -1
  255. package/dist/server/request-context.js.map +1 -1
  256. package/dist/server/sentry-plugin.d.ts +11 -0
  257. package/dist/server/sentry-plugin.d.ts.map +1 -0
  258. package/dist/server/sentry-plugin.js +116 -0
  259. package/dist/server/sentry-plugin.js.map +1 -0
  260. package/dist/server/sentry.d.ts +92 -0
  261. package/dist/server/sentry.d.ts.map +1 -0
  262. package/dist/server/sentry.js +287 -0
  263. package/dist/server/sentry.js.map +1 -0
  264. package/dist/server/transcribe-voice.d.ts +2 -4
  265. package/dist/server/transcribe-voice.d.ts.map +1 -1
  266. package/dist/server/transcribe-voice.js +4 -16
  267. package/dist/server/transcribe-voice.js.map +1 -1
  268. package/dist/server/voice-providers-status.d.ts.map +1 -1
  269. package/dist/server/voice-providers-status.js +19 -35
  270. package/dist/server/voice-providers-status.js.map +1 -1
  271. package/dist/styles/agent-native.css +15 -0
  272. package/docs/content/cloneable-saas.md +7 -9
  273. package/docs/content/deployment.md +6 -2
  274. package/docs/content/dispatch.md +1 -1
  275. package/docs/content/extensions.md +177 -142
  276. package/docs/content/faq.md +2 -2
  277. package/docs/content/getting-started.md +13 -11
  278. package/docs/content/multi-app-workspace.md +2 -2
  279. package/docs/content/observability.md +47 -0
  280. package/docs/content/pure-agent-apps.md +1 -1
  281. package/docs/content/template-clips.md +3 -3
  282. package/docs/content/template-design.md +3 -3
  283. package/docs/content/template-dispatch.md +1 -1
  284. package/docs/content/template-forms.md +1 -1
  285. package/docs/content/template-mail.md +1 -1
  286. package/docs/content/what-is-agent-native.md +4 -4
  287. package/docs/content/workspace.md +1 -1
  288. package/package.json +2 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sentry-plugin.js","sourceRoot":"","sources":["../../src/server/sentry-plugin.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Nitro plugin that initializes server-side Sentry and attaches per-request\n * user context.\n *\n * Wires three pieces:\n * 1. On startup, `initServerSentry()` reads `SENTRY_SERVER_DSN` and arms\n * the SDK (no-op when the env var is unset).\n * 2. On every request, hook into Nitro's `request` event: resolve the\n * session via `getSession(event)` and tag the per-request isolation\n * scope with the user's id/email/orgId. Wrapped in try/catch so a\n * session-resolution failure can never 500 the request.\n * 3. On every Nitro `error` event, capture the exception with the route,\n * method, and user-agent attached as searchable tags.\n *\n * Mounted as a default plugin from `framework-request-handler.ts` —\n * templates that don't define `server/plugins/sentry.ts` get this for\n * free. Templates that need to customize (e.g. add custom tags / skip\n * Sentry) can override by exporting their own `sentry.ts` plugin.\n */\nimport {\n awaitBootstrap,\n markDefaultPluginProvided,\n} from \"./framework-request-handler.js\";\nimport { getSession } from \"./auth.js\";\nimport {\n captureRouteError,\n initServerSentry,\n isServerSentryEnabled,\n setSentryRequestContext,\n setSentryUserForRequest,\n} from \"./sentry.js\";\nimport { addRequestContextObserver } from \"./request-context.js\";\nimport { getHeader, getMethod, type H3Event } from \"h3\";\n\ntype NitroPluginDef = (nitroApp: any) => void | Promise<void>;\n\nfunction readRoute(event: H3Event): string | undefined {\n try {\n return event.url?.pathname;\n } catch {\n return undefined;\n }\n}\n\nfunction readUserAgent(event: H3Event): string | undefined {\n try {\n return getHeader(event, \"user-agent\");\n } catch {\n return undefined;\n }\n}\n\n/**\n * Skip session resolution for paths that obviously don't need one. Avoids\n * a DB round-trip on every static-asset / favicon / public-share request\n * while keeping API + framework routes covered.\n */\nfunction shouldResolveSession(path: string | undefined): boolean {\n if (!path) return false;\n // Vite / React Router static assets and similar.\n if (\n path.startsWith(\"/assets/\") ||\n path.startsWith(\"/_build/\") ||\n path === \"/favicon.ico\" ||\n path.startsWith(\"/static/\")\n ) {\n return false;\n }\n return true;\n}\n\nexport function createSentryPlugin(): NitroPluginDef {\n return async (nitroApp: any) => {\n markDefaultPluginProvided(nitroApp, \"sentry\");\n await awaitBootstrap(nitroApp);\n\n initServerSentry();\n if (!isServerSentryEnabled()) {\n // No DSN — skip wiring per-request hooks. We'd just be paying the\n // call-site overhead for every request to no effect.\n return;\n }\n\n // Per-request: resolve session and attach to Sentry isolation scope so\n // any exception captured later in the request carries the user. Wrapped\n // in try/catch so a session-DB hiccup or auth-broken state never turns\n // into a 500 — the worst case is we lose user context on the event.\n nitroApp.hooks?.hook?.(\"request\", async (event: H3Event) => {\n if (!shouldResolveSession(readRoute(event))) return;\n try {\n const session = await getSession(event);\n setSentryUserForRequest(session);\n } catch {\n // best-effort — don't break the request\n }\n });\n\n // Wrap-time: every `runWithRequestContext({ userEmail, orgId, ... })`\n // call also pins user/org onto Sentry's per-async-context isolation\n // scope. Covers paths the cookie-based `request` hook can't see —\n // integration webhook processors, A2A calls, agent-chat tool\n // re-entries, and any internal call chain that opens a request scope\n // without an HTTP cookie.\n addRequestContextObserver((ctx) => {\n setSentryRequestContext({ userEmail: ctx.userEmail, orgId: ctx.orgId });\n });\n\n // Per-error: capture with route/method/UA tags. Nitro's `error` hook\n // signature is (error, { event, tags }) — we forward what we can.\n nitroApp.hooks?.hook?.(\n \"error\",\n (error: unknown, ctx?: { event?: H3Event }) => {\n try {\n const event = ctx?.event;\n captureRouteError(error, {\n route: event ? readRoute(event) : undefined,\n method: event ? getMethod(event) : undefined,\n userAgent: event ? readUserAgent(event) : undefined,\n });\n } catch {\n // Sentry capture must never escape into Nitro's error path.\n }\n },\n );\n };\n}\n\n/**\n * Default Sentry plugin — auto-mounts when a template doesn't define its\n * own `server/plugins/sentry.ts`. Reads `SENTRY_SERVER_DSN` from env and\n * silently no-ops when it's unset, so this is safe to default-mount in\n * every template (including local dev with no DSN configured).\n */\nexport const defaultSentryPlugin: NitroPluginDef = createSentryPlugin();\n"]}
@@ -0,0 +1,92 @@
1
+ import type { AuthSession } from "./auth.js";
2
+ /**
3
+ * Initialize server-side Sentry. Idempotent — safe to call from multiple
4
+ * plugin entrypoints. Returns `true` if initialization actually happened
5
+ * (DSN was set), `false` if Sentry is disabled (no DSN).
6
+ *
7
+ * No DSN is hardcoded: unlike the CLI (a published binary that always
8
+ * wants to phone home crashes), the server runs in customer environments.
9
+ * Operators set `SENTRY_SERVER_DSN` when they want their own Sentry
10
+ * project to receive these events; without it the module no-ops.
11
+ */
12
+ export declare function initServerSentry(): boolean;
13
+ /**
14
+ * `true` once `initServerSentry()` has succeeded with a DSN. Plugins that
15
+ * want to skip work when Sentry is disabled can check this before calling
16
+ * the helpers below.
17
+ */
18
+ export declare function isServerSentryEnabled(): boolean;
19
+ /**
20
+ * Attach the current request's user to Sentry's isolation scope so any
21
+ * `captureException` triggered later in the request carries the right
22
+ * `user.id` / `user.email` / `user.username` and `orgId` tag.
23
+ *
24
+ * Sentry node 10 uses Node's AsyncLocalStorage to give each async context
25
+ * its own isolation scope, so setting on `getIsolationScope()` here only
26
+ * affects events emitted while this request's async context is active.
27
+ *
28
+ * No-ops gracefully when Sentry isn't initialized or no session exists —
29
+ * never throws into the request path.
30
+ */
31
+ export declare function setSentryUserForRequest(session: AuthSession | null): void;
32
+ /**
33
+ * Pin a user/org onto the current isolation scope from a lighter
34
+ * `RequestContext`-shaped payload. Used by the request-context observer so
35
+ * action handlers, agent-chat runs, and integration webhook processors —
36
+ * all of which already wrap their work in `runWithRequestContext({ userEmail,
37
+ * orgId, ... })` — automatically tag Sentry events with the right user even
38
+ * when the Nitro `request` hook didn't see a cookie (e.g. webhook delivery,
39
+ * A2A calls, internal background runs).
40
+ *
41
+ * Skips overwriting a richer user identity already set by
42
+ * `setSentryUserForRequest` — the cookie-resolved session has
43
+ * userId/username on top of email, which we shouldn't clobber.
44
+ */
45
+ export declare function setSentryRequestContext(ctx: {
46
+ userEmail?: string;
47
+ orgId?: string;
48
+ }): void;
49
+ /**
50
+ * Capture an error from one of the auth attempt routes (login / signup)
51
+ * with the email pinned to the event so support can filter by user. Sets
52
+ * Sentry level to `warning` (not `error`) — bad-password attempts aren't
53
+ * actionable, but a sustained spike of warnings on a route IS the signal
54
+ * we care about.
55
+ *
56
+ * Caller should still return their normal HTTP response (401/409/etc.);
57
+ * this just records the error for observability.
58
+ */
59
+ export declare function captureAuthError(error: unknown, context: {
60
+ route: "login" | "signup" | "logout";
61
+ email?: string;
62
+ }): string | undefined;
63
+ export interface RouteErrorContext {
64
+ /** The full request path (e.g. `/_agent-native/agent-chat`). */
65
+ route?: string;
66
+ /** HTTP method (e.g. `GET`, `POST`). */
67
+ method?: string;
68
+ /** Caller's `User-Agent` header. */
69
+ userAgent?: string;
70
+ /** Free-form extra tags to add to the event (low-cardinality). */
71
+ tags?: Record<string, string | undefined>;
72
+ /**
73
+ * High-cardinality / structured payload — not searchable but visible in
74
+ * the Sentry event detail (recording IDs, byte counts, compression
75
+ * metadata, response body tails, etc.).
76
+ */
77
+ extra?: Record<string, unknown>;
78
+ /**
79
+ * Grouped contexts shown as separate cards in the Sentry event UI.
80
+ */
81
+ contexts?: Record<string, Record<string, unknown>>;
82
+ }
83
+ /**
84
+ * Capture an exception that surfaced in a Nitro route handler with the
85
+ * request's route/method/userAgent attached as searchable Sentry tags.
86
+ *
87
+ * Non-throwing: if Sentry isn't initialized or the underlying capture
88
+ * fails, this is a no-op. Returns the Sentry event ID when capture
89
+ * succeeded, otherwise `undefined`.
90
+ */
91
+ export declare function captureRouteError(error: unknown, context?: RouteErrorContext): string | undefined;
92
+ //# sourceMappingURL=sentry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sentry.d.ts","sourceRoot":"","sources":["../../src/server/sentry.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAoC7C;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAoF1C;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,IAAI,OAAO,CAE/C;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,GAAG,IAAI,CAsBzE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,IAAI,CAgBP;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,OAAO,EACd,OAAO,EAAE;IAAE,KAAK,EAAE,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAChE,MAAM,GAAG,SAAS,CAcpB;AAED,MAAM,WAAW,iBAAiB;IAChC,gEAAgE;IAChE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wCAAwC;IACxC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oCAAoC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kEAAkE;IAClE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IAC1C;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACpD;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,OAAO,EACd,OAAO,GAAE,iBAAsB,GAC9B,MAAM,GAAG,SAAS,CA2BpB"}
@@ -0,0 +1,287 @@
1
+ /**
2
+ * Server-side Sentry initialization for Nitro.
3
+ *
4
+ * Errors thrown inside Nitro routes (the framework's own /_agent-native/*
5
+ * handlers, the template's API routes, action handlers, agent-chat streams)
6
+ * never reach the CLI's Sentry init — that only covers the developer's
7
+ * machine. Without server-side Sentry the only signal a 500 ever produces
8
+ * is a server-side console.error that lives and dies with the request.
9
+ *
10
+ * This module is the third Sentry init point in the framework:
11
+ * - cli/index.ts → @sentry/node, hardcoded DSN, "agent-native-cli"
12
+ * - client/analytics.ts → @sentry/browser, VITE_SENTRY_CLIENT_DSN
13
+ * - server/sentry.ts → @sentry/node, SENTRY_SERVER_DSN
14
+ *
15
+ * Each maps to a different Sentry project so we can route errors to the
16
+ * right team without one project drowning out the others. Don't wire the
17
+ * three together — they share the SDK package but live in different
18
+ * processes / runtimes / call sites.
19
+ */
20
+ import * as Sentry from "@sentry/node";
21
+ import path from "node:path";
22
+ import fs from "node:fs";
23
+ import { fileURLToPath } from "node:url";
24
+ let _initStarted = false;
25
+ let _initSucceeded = false;
26
+ /**
27
+ * Resolve the agent-native version baked into core's package.json so Sentry
28
+ * "release" reflects the running framework version. Mirrors how the CLI
29
+ * computes `_version` — same dist layout, same fallback string. Guarded so
30
+ * a missing/unreadable package.json never crashes server boot.
31
+ */
32
+ function resolveServerRelease() {
33
+ const explicit = process.env.AGENT_NATIVE_RELEASE;
34
+ if (explicit)
35
+ return explicit;
36
+ try {
37
+ const here = path.dirname(fileURLToPath(import.meta.url));
38
+ // dist/server/sentry.js → ../../package.json
39
+ const pkgPath = path.resolve(here, "../../package.json");
40
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
41
+ if (pkg?.version)
42
+ return `agent-native-server@${pkg.version}`;
43
+ }
44
+ catch {
45
+ // ignore — fall through to "unknown"
46
+ }
47
+ return "agent-native-server@unknown";
48
+ }
49
+ function parseTracesSampleRate() {
50
+ const raw = process.env.SENTRY_SERVER_TRACES_SAMPLE_RATE;
51
+ if (!raw)
52
+ return 0;
53
+ const n = Number(raw);
54
+ if (!Number.isFinite(n) || n < 0 || n > 1)
55
+ return 0;
56
+ return n;
57
+ }
58
+ /**
59
+ * Initialize server-side Sentry. Idempotent — safe to call from multiple
60
+ * plugin entrypoints. Returns `true` if initialization actually happened
61
+ * (DSN was set), `false` if Sentry is disabled (no DSN).
62
+ *
63
+ * No DSN is hardcoded: unlike the CLI (a published binary that always
64
+ * wants to phone home crashes), the server runs in customer environments.
65
+ * Operators set `SENTRY_SERVER_DSN` when they want their own Sentry
66
+ * project to receive these events; without it the module no-ops.
67
+ */
68
+ export function initServerSentry() {
69
+ if (_initStarted)
70
+ return _initSucceeded;
71
+ _initStarted = true;
72
+ const dsn = process.env.SENTRY_SERVER_DSN;
73
+ if (!dsn) {
74
+ if (process.env.DEBUG) {
75
+ console.log("[agent-native] SENTRY_SERVER_DSN not set — server Sentry disabled.");
76
+ }
77
+ return false;
78
+ }
79
+ Sentry.init({
80
+ dsn,
81
+ environment: process.env.NODE_ENV || "production",
82
+ release: resolveServerRelease(),
83
+ tracesSampleRate: parseTracesSampleRate(),
84
+ // sendDefaultPii MUST stay false — the framework runs inside customer
85
+ // environments and we never want to silently ship request headers,
86
+ // cookies, or process.env contents to Sentry without explicit consent.
87
+ sendDefaultPii: false,
88
+ beforeSend(event) {
89
+ // Drop expected user-input rejections so they don't pollute Sentry
90
+ // with non-bug noise. Mirrors the CLI's drop list — the framework
91
+ // and CLI both throw `ValidationError` for the same class of input
92
+ // failures, and exception type comes through as the class name.
93
+ const exceptionType = event.exception?.values?.[0]?.type;
94
+ if (exceptionType === "ValidationError" ||
95
+ event.tags?.handled === "validation") {
96
+ return null;
97
+ }
98
+ // Defense in depth: scrub PII even if some integration auto-attached
99
+ // request metadata despite sendDefaultPii: false.
100
+ if (event.request) {
101
+ if (event.request.headers) {
102
+ const headers = event.request.headers;
103
+ for (const k of Object.keys(headers)) {
104
+ const lk = k.toLowerCase();
105
+ if (lk === "cookie" ||
106
+ lk === "authorization" ||
107
+ lk === "set-cookie" ||
108
+ lk === "proxy-authorization") {
109
+ delete headers[k];
110
+ }
111
+ }
112
+ }
113
+ // Cookies live in their own field too.
114
+ delete event.request.cookies;
115
+ }
116
+ // Keep user info that was explicitly set via Sentry.setUser
117
+ // (id/email/username) so we can attribute crashes back to a real
118
+ // operator. Always strip ip_address — auto-collected, no consent.
119
+ if (event.user) {
120
+ const user = event.user;
121
+ delete user.ip_address;
122
+ const hasIdentity = typeof user.id === "string" ||
123
+ typeof user.email === "string" ||
124
+ typeof user.username === "string";
125
+ if (!hasIdentity) {
126
+ delete event.user;
127
+ }
128
+ }
129
+ // Sentry's contexts can carry process.env snapshots — strip env-shaped
130
+ // contexts so we don't leak deployment secrets.
131
+ if (event.contexts && typeof event.contexts === "object") {
132
+ delete event.contexts.runtime_env;
133
+ }
134
+ return event;
135
+ },
136
+ });
137
+ _initSucceeded = true;
138
+ return true;
139
+ }
140
+ /**
141
+ * `true` once `initServerSentry()` has succeeded with a DSN. Plugins that
142
+ * want to skip work when Sentry is disabled can check this before calling
143
+ * the helpers below.
144
+ */
145
+ export function isServerSentryEnabled() {
146
+ return _initSucceeded;
147
+ }
148
+ /**
149
+ * Attach the current request's user to Sentry's isolation scope so any
150
+ * `captureException` triggered later in the request carries the right
151
+ * `user.id` / `user.email` / `user.username` and `orgId` tag.
152
+ *
153
+ * Sentry node 10 uses Node's AsyncLocalStorage to give each async context
154
+ * its own isolation scope, so setting on `getIsolationScope()` here only
155
+ * affects events emitted while this request's async context is active.
156
+ *
157
+ * No-ops gracefully when Sentry isn't initialized or no session exists —
158
+ * never throws into the request path.
159
+ */
160
+ export function setSentryUserForRequest(session) {
161
+ if (!_initSucceeded)
162
+ return;
163
+ try {
164
+ const scope = Sentry.getIsolationScope();
165
+ if (!session) {
166
+ scope.setUser(null);
167
+ scope.setTag("orgId", null);
168
+ return;
169
+ }
170
+ scope.setUser({
171
+ id: session.userId ?? session.email,
172
+ email: session.email,
173
+ username: session.name,
174
+ });
175
+ scope.setTag("orgId", session.orgId ?? null);
176
+ if (session.orgRole) {
177
+ scope.setTag("orgRole", session.orgRole);
178
+ }
179
+ }
180
+ catch {
181
+ // Sentry scope APIs should never throw, but if they do we'd rather
182
+ // continue serving the request than crash on observability.
183
+ }
184
+ }
185
+ /**
186
+ * Pin a user/org onto the current isolation scope from a lighter
187
+ * `RequestContext`-shaped payload. Used by the request-context observer so
188
+ * action handlers, agent-chat runs, and integration webhook processors —
189
+ * all of which already wrap their work in `runWithRequestContext({ userEmail,
190
+ * orgId, ... })` — automatically tag Sentry events with the right user even
191
+ * when the Nitro `request` hook didn't see a cookie (e.g. webhook delivery,
192
+ * A2A calls, internal background runs).
193
+ *
194
+ * Skips overwriting a richer user identity already set by
195
+ * `setSentryUserForRequest` — the cookie-resolved session has
196
+ * userId/username on top of email, which we shouldn't clobber.
197
+ */
198
+ export function setSentryRequestContext(ctx) {
199
+ if (!_initSucceeded)
200
+ return;
201
+ try {
202
+ const scope = Sentry.getIsolationScope();
203
+ if (ctx.userEmail) {
204
+ const existing = scope.getScopeData().user;
205
+ if (!existing?.id && !existing?.email) {
206
+ scope.setUser({ id: ctx.userEmail, email: ctx.userEmail });
207
+ }
208
+ }
209
+ if (ctx.orgId) {
210
+ scope.setTag("orgId", ctx.orgId);
211
+ }
212
+ }
213
+ catch {
214
+ // never throw
215
+ }
216
+ }
217
+ /**
218
+ * Capture an error from one of the auth attempt routes (login / signup)
219
+ * with the email pinned to the event so support can filter by user. Sets
220
+ * Sentry level to `warning` (not `error`) — bad-password attempts aren't
221
+ * actionable, but a sustained spike of warnings on a route IS the signal
222
+ * we care about.
223
+ *
224
+ * Caller should still return their normal HTTP response (401/409/etc.);
225
+ * this just records the error for observability.
226
+ */
227
+ export function captureAuthError(error, context) {
228
+ if (!_initSucceeded)
229
+ return undefined;
230
+ try {
231
+ return Sentry.withScope((scope) => {
232
+ scope.setLevel("warning");
233
+ scope.setTag("auth", context.route);
234
+ if (context.email) {
235
+ scope.setUser({ id: context.email, email: context.email });
236
+ }
237
+ return Sentry.captureException(error);
238
+ });
239
+ }
240
+ catch {
241
+ return undefined;
242
+ }
243
+ }
244
+ /**
245
+ * Capture an exception that surfaced in a Nitro route handler with the
246
+ * request's route/method/userAgent attached as searchable Sentry tags.
247
+ *
248
+ * Non-throwing: if Sentry isn't initialized or the underlying capture
249
+ * fails, this is a no-op. Returns the Sentry event ID when capture
250
+ * succeeded, otherwise `undefined`.
251
+ */
252
+ export function captureRouteError(error, context = {}) {
253
+ if (!_initSucceeded)
254
+ return undefined;
255
+ try {
256
+ return Sentry.withScope((scope) => {
257
+ if (context.route)
258
+ scope.setTag("route", context.route);
259
+ if (context.method)
260
+ scope.setTag("method", context.method);
261
+ if (context.userAgent)
262
+ scope.setTag("userAgent", context.userAgent);
263
+ if (context.tags) {
264
+ for (const [k, v] of Object.entries(context.tags)) {
265
+ if (typeof v === "string")
266
+ scope.setTag(k, v);
267
+ }
268
+ }
269
+ if (context.extra) {
270
+ for (const [k, v] of Object.entries(context.extra)) {
271
+ if (v !== undefined)
272
+ scope.setExtra(k, v);
273
+ }
274
+ }
275
+ if (context.contexts) {
276
+ for (const [k, v] of Object.entries(context.contexts)) {
277
+ scope.setContext(k, v);
278
+ }
279
+ }
280
+ return Sentry.captureException(error);
281
+ });
282
+ }
283
+ catch {
284
+ return undefined;
285
+ }
286
+ }
287
+ //# sourceMappingURL=sentry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sentry.js","sourceRoot":"","sources":["../../src/server/sentry.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Server-side Sentry initialization for Nitro.\n *\n * Errors thrown inside Nitro routes (the framework's own /_agent-native/*\n * handlers, the template's API routes, action handlers, agent-chat streams)\n * never reach the CLI's Sentry init — that only covers the developer's\n * machine. Without server-side Sentry the only signal a 500 ever produces\n * is a server-side console.error that lives and dies with the request.\n *\n * This module is the third Sentry init point in the framework:\n * - cli/index.ts → @sentry/node, hardcoded DSN, \"agent-native-cli\"\n * - client/analytics.ts → @sentry/browser, VITE_SENTRY_CLIENT_DSN\n * - server/sentry.ts → @sentry/node, SENTRY_SERVER_DSN\n *\n * Each maps to a different Sentry project so we can route errors to the\n * right team without one project drowning out the others. Don't wire the\n * three together — they share the SDK package but live in different\n * processes / runtimes / call sites.\n */\nimport * as Sentry from \"@sentry/node\";\nimport path from \"node:path\";\nimport fs from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport type { AuthSession } from \"./auth.js\";\n\nlet _initStarted = false;\nlet _initSucceeded = false;\n\n/**\n * Resolve the agent-native version baked into core's package.json so Sentry\n * \"release\" reflects the running framework version. Mirrors how the CLI\n * computes `_version` — same dist layout, same fallback string. Guarded so\n * a missing/unreadable package.json never crashes server boot.\n */\nfunction resolveServerRelease(): string {\n const explicit = process.env.AGENT_NATIVE_RELEASE;\n if (explicit) return explicit;\n try {\n const here = path.dirname(fileURLToPath(import.meta.url));\n // dist/server/sentry.js → ../../package.json\n const pkgPath = path.resolve(here, \"../../package.json\");\n const pkg = JSON.parse(fs.readFileSync(pkgPath, \"utf-8\")) as {\n version?: string;\n };\n if (pkg?.version) return `agent-native-server@${pkg.version}`;\n } catch {\n // ignore — fall through to \"unknown\"\n }\n return \"agent-native-server@unknown\";\n}\n\nfunction parseTracesSampleRate(): number {\n const raw = process.env.SENTRY_SERVER_TRACES_SAMPLE_RATE;\n if (!raw) return 0;\n const n = Number(raw);\n if (!Number.isFinite(n) || n < 0 || n > 1) return 0;\n return n;\n}\n\n/**\n * Initialize server-side Sentry. Idempotent — safe to call from multiple\n * plugin entrypoints. Returns `true` if initialization actually happened\n * (DSN was set), `false` if Sentry is disabled (no DSN).\n *\n * No DSN is hardcoded: unlike the CLI (a published binary that always\n * wants to phone home crashes), the server runs in customer environments.\n * Operators set `SENTRY_SERVER_DSN` when they want their own Sentry\n * project to receive these events; without it the module no-ops.\n */\nexport function initServerSentry(): boolean {\n if (_initStarted) return _initSucceeded;\n _initStarted = true;\n\n const dsn = process.env.SENTRY_SERVER_DSN;\n if (!dsn) {\n if (process.env.DEBUG) {\n console.log(\n \"[agent-native] SENTRY_SERVER_DSN not set — server Sentry disabled.\",\n );\n }\n return false;\n }\n\n Sentry.init({\n dsn,\n environment: process.env.NODE_ENV || \"production\",\n release: resolveServerRelease(),\n tracesSampleRate: parseTracesSampleRate(),\n // sendDefaultPii MUST stay false — the framework runs inside customer\n // environments and we never want to silently ship request headers,\n // cookies, or process.env contents to Sentry without explicit consent.\n sendDefaultPii: false,\n beforeSend(event) {\n // Drop expected user-input rejections so they don't pollute Sentry\n // with non-bug noise. Mirrors the CLI's drop list — the framework\n // and CLI both throw `ValidationError` for the same class of input\n // failures, and exception type comes through as the class name.\n const exceptionType = event.exception?.values?.[0]?.type;\n if (\n exceptionType === \"ValidationError\" ||\n event.tags?.handled === \"validation\"\n ) {\n return null;\n }\n\n // Defense in depth: scrub PII even if some integration auto-attached\n // request metadata despite sendDefaultPii: false.\n if (event.request) {\n if (event.request.headers) {\n const headers = event.request.headers as Record<string, string>;\n for (const k of Object.keys(headers)) {\n const lk = k.toLowerCase();\n if (\n lk === \"cookie\" ||\n lk === \"authorization\" ||\n lk === \"set-cookie\" ||\n lk === \"proxy-authorization\"\n ) {\n delete headers[k];\n }\n }\n }\n // Cookies live in their own field too.\n delete (event.request as Record<string, unknown>).cookies;\n }\n\n // Keep user info that was explicitly set via Sentry.setUser\n // (id/email/username) so we can attribute crashes back to a real\n // operator. Always strip ip_address — auto-collected, no consent.\n if (event.user) {\n const user = event.user as Record<string, unknown>;\n delete user.ip_address;\n const hasIdentity =\n typeof user.id === \"string\" ||\n typeof user.email === \"string\" ||\n typeof user.username === \"string\";\n if (!hasIdentity) {\n delete event.user;\n }\n }\n\n // Sentry's contexts can carry process.env snapshots — strip env-shaped\n // contexts so we don't leak deployment secrets.\n if (event.contexts && typeof event.contexts === \"object\") {\n delete (event.contexts as Record<string, unknown>).runtime_env;\n }\n\n return event;\n },\n });\n\n _initSucceeded = true;\n return true;\n}\n\n/**\n * `true` once `initServerSentry()` has succeeded with a DSN. Plugins that\n * want to skip work when Sentry is disabled can check this before calling\n * the helpers below.\n */\nexport function isServerSentryEnabled(): boolean {\n return _initSucceeded;\n}\n\n/**\n * Attach the current request's user to Sentry's isolation scope so any\n * `captureException` triggered later in the request carries the right\n * `user.id` / `user.email` / `user.username` and `orgId` tag.\n *\n * Sentry node 10 uses Node's AsyncLocalStorage to give each async context\n * its own isolation scope, so setting on `getIsolationScope()` here only\n * affects events emitted while this request's async context is active.\n *\n * No-ops gracefully when Sentry isn't initialized or no session exists —\n * never throws into the request path.\n */\nexport function setSentryUserForRequest(session: AuthSession | null): void {\n if (!_initSucceeded) return;\n try {\n const scope = Sentry.getIsolationScope();\n if (!session) {\n scope.setUser(null);\n scope.setTag(\"orgId\", null);\n return;\n }\n scope.setUser({\n id: session.userId ?? session.email,\n email: session.email,\n username: session.name,\n });\n scope.setTag(\"orgId\", session.orgId ?? null);\n if (session.orgRole) {\n scope.setTag(\"orgRole\", session.orgRole);\n }\n } catch {\n // Sentry scope APIs should never throw, but if they do we'd rather\n // continue serving the request than crash on observability.\n }\n}\n\n/**\n * Pin a user/org onto the current isolation scope from a lighter\n * `RequestContext`-shaped payload. Used by the request-context observer so\n * action handlers, agent-chat runs, and integration webhook processors —\n * all of which already wrap their work in `runWithRequestContext({ userEmail,\n * orgId, ... })` — automatically tag Sentry events with the right user even\n * when the Nitro `request` hook didn't see a cookie (e.g. webhook delivery,\n * A2A calls, internal background runs).\n *\n * Skips overwriting a richer user identity already set by\n * `setSentryUserForRequest` — the cookie-resolved session has\n * userId/username on top of email, which we shouldn't clobber.\n */\nexport function setSentryRequestContext(ctx: {\n userEmail?: string;\n orgId?: string;\n}): void {\n if (!_initSucceeded) return;\n try {\n const scope = Sentry.getIsolationScope();\n if (ctx.userEmail) {\n const existing = scope.getScopeData().user;\n if (!existing?.id && !existing?.email) {\n scope.setUser({ id: ctx.userEmail, email: ctx.userEmail });\n }\n }\n if (ctx.orgId) {\n scope.setTag(\"orgId\", ctx.orgId);\n }\n } catch {\n // never throw\n }\n}\n\n/**\n * Capture an error from one of the auth attempt routes (login / signup)\n * with the email pinned to the event so support can filter by user. Sets\n * Sentry level to `warning` (not `error`) — bad-password attempts aren't\n * actionable, but a sustained spike of warnings on a route IS the signal\n * we care about.\n *\n * Caller should still return their normal HTTP response (401/409/etc.);\n * this just records the error for observability.\n */\nexport function captureAuthError(\n error: unknown,\n context: { route: \"login\" | \"signup\" | \"logout\"; email?: string },\n): string | undefined {\n if (!_initSucceeded) return undefined;\n try {\n return Sentry.withScope((scope) => {\n scope.setLevel(\"warning\");\n scope.setTag(\"auth\", context.route);\n if (context.email) {\n scope.setUser({ id: context.email, email: context.email });\n }\n return Sentry.captureException(error);\n });\n } catch {\n return undefined;\n }\n}\n\nexport interface RouteErrorContext {\n /** The full request path (e.g. `/_agent-native/agent-chat`). */\n route?: string;\n /** HTTP method (e.g. `GET`, `POST`). */\n method?: string;\n /** Caller's `User-Agent` header. */\n userAgent?: string;\n /** Free-form extra tags to add to the event (low-cardinality). */\n tags?: Record<string, string | undefined>;\n /**\n * High-cardinality / structured payload — not searchable but visible in\n * the Sentry event detail (recording IDs, byte counts, compression\n * metadata, response body tails, etc.).\n */\n extra?: Record<string, unknown>;\n /**\n * Grouped contexts shown as separate cards in the Sentry event UI.\n */\n contexts?: Record<string, Record<string, unknown>>;\n}\n\n/**\n * Capture an exception that surfaced in a Nitro route handler with the\n * request's route/method/userAgent attached as searchable Sentry tags.\n *\n * Non-throwing: if Sentry isn't initialized or the underlying capture\n * fails, this is a no-op. Returns the Sentry event ID when capture\n * succeeded, otherwise `undefined`.\n */\nexport function captureRouteError(\n error: unknown,\n context: RouteErrorContext = {},\n): string | undefined {\n if (!_initSucceeded) return undefined;\n try {\n return Sentry.withScope((scope) => {\n if (context.route) scope.setTag(\"route\", context.route);\n if (context.method) scope.setTag(\"method\", context.method);\n if (context.userAgent) scope.setTag(\"userAgent\", context.userAgent);\n if (context.tags) {\n for (const [k, v] of Object.entries(context.tags)) {\n if (typeof v === \"string\") scope.setTag(k, v);\n }\n }\n if (context.extra) {\n for (const [k, v] of Object.entries(context.extra)) {\n if (v !== undefined) scope.setExtra(k, v);\n }\n }\n if (context.contexts) {\n for (const [k, v] of Object.entries(context.contexts)) {\n scope.setContext(k, v);\n }\n }\n return Sentry.captureException(error);\n });\n } catch {\n return undefined;\n }\n}\n"]}
@@ -6,10 +6,8 @@
6
6
  * `{ error }` on failure.
7
7
  *
8
8
  * Key resolution order for BYOK providers:
9
- * 1. User-scoped encrypted secret (`readAppSecret` set via the sidebar
10
- * settings UI).
11
- * 2. `resolveCredential("<PROVIDER>_API_KEY")` — env var + SQL settings
12
- * store.
9
+ * 1. Request-scoped encrypted secret (`app_secrets`: user, org, workspace).
10
+ * 2. Env var fallback only outside authenticated request contexts.
13
11
  *
14
12
  * If no server provider is configured, returns 400 with an error the
15
13
  * composer UI can surface (the client falls back to Web Speech when possible).
@@ -1 +1 @@
1
- {"version":3,"file":"transcribe-voice.d.ts","sourceRoot":"","sources":["../../src/server/transcribe-voice.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AA6FH,wBAAgB,4BAA4B;UAwcxB,MAAM;;;IA7FzB"}
1
+ {"version":3,"file":"transcribe-voice.d.ts","sourceRoot":"","sources":["../../src/server/transcribe-voice.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AA8FH,wBAAgB,4BAA4B;UA8bxB,MAAM;;;IA7FzB"}
@@ -6,10 +6,8 @@
6
6
  * `{ error }` on failure.
7
7
  *
8
8
  * Key resolution order for BYOK providers:
9
- * 1. User-scoped encrypted secret (`readAppSecret` set via the sidebar
10
- * settings UI).
11
- * 2. `resolveCredential("<PROVIDER>_API_KEY")` — env var + SQL settings
12
- * store.
9
+ * 1. Request-scoped encrypted secret (`app_secrets`: user, org, workspace).
10
+ * 2. Env var fallback only outside authenticated request contexts.
13
11
  *
14
12
  * If no server provider is configured, returns 400 with an error the
15
13
  * composer UI can surface (the client falls back to Web Speech when possible).
@@ -19,11 +17,9 @@
19
17
  * typed JSON-in / JSON-out).
20
18
  */
21
19
  import { defineEventHandler, getMethod, getRequestHeader, readMultipartFormData, setResponseStatus, } from "h3";
22
- import { readAppSecret } from "../secrets/storage.js";
23
- import { resolveCredential } from "../credentials/index.js";
24
20
  import { getSession } from "./auth.js";
25
21
  import { appStateGet } from "../application-state/store.js";
26
- import { resolveHasBuilderPrivateKey } from "./credential-provider.js";
22
+ import { resolveHasBuilderPrivateKey, resolveSecret, } from "./credential-provider.js";
27
23
  import { transcribeWithBuilder } from "../transcription/builder-transcription.js";
28
24
  import { runWithRequestContext } from "./request-context.js";
29
25
  import { getOrgContext } from "../org/context.js";
@@ -200,15 +196,7 @@ export function createTranscribeVoiceHandler() {
200
196
  // Per-user-or-fallback API key resolution. Hoisted up so the Gemini
201
197
  // path below can use it without duplicating logic.
202
198
  async function resolveApiKey(key) {
203
- const ctx = { userEmail: session?.email };
204
- if (!session?.email)
205
- return (await resolveCredential(key, ctx)) ?? undefined;
206
- const userSecret = await readAppSecret({
207
- key,
208
- scope: "user",
209
- scopeId: session.email,
210
- }).catch(() => null);
211
- return (userSecret?.value || (await resolveCredential(key, ctx)) || undefined);
199
+ return (await withRequestContext(() => resolveSecret(key))) ?? undefined;
212
200
  }
213
201
  if (transcriptText) {
214
202
  return await cleanupTranscriptText({