@agent-native/core 0.92.0 → 0.92.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (363) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +14 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/application-state/store.ts +12 -1
  5. package/corpus/core/src/client/AssistantChat.tsx +27 -14
  6. package/corpus/core/src/client/PoweredByBadge.tsx +1 -8
  7. package/corpus/core/src/client/agent-chat-adapter.ts +37 -10
  8. package/corpus/core/src/client/chat/widgets/DataTableWidget.tsx +52 -1
  9. package/corpus/core/src/client/db-admin/TableEditor.tsx +49 -0
  10. package/corpus/core/src/client/db-admin/export-utils.ts +13 -4
  11. package/corpus/core/src/client/db-admin/useAgentSync.ts +72 -0
  12. package/corpus/core/src/client/error-capture.ts +69 -7
  13. package/corpus/core/src/client/extensions/EmbeddedExtension.tsx +5 -1
  14. package/corpus/core/src/client/extensions/ExtensionViewer.tsx +53 -8
  15. package/corpus/core/src/client/extensions/InlineExtensionFrame.tsx +5 -1
  16. package/corpus/core/src/client/extensions/portable-extension.ts +1 -0
  17. package/corpus/core/src/client/org/OrgSwitcher.tsx +12 -9
  18. package/corpus/core/src/client/org/TeamPage.tsx +77 -71
  19. package/corpus/core/src/client/settings/SettingsPanel.tsx +205 -52
  20. package/corpus/core/src/client/settings/SettingsSection.tsx +8 -1
  21. package/corpus/core/src/client/settings/SettingsTabsPage.tsx +25 -9
  22. package/corpus/core/src/db-admin/agent-tools.ts +8 -2
  23. package/corpus/core/src/db-admin/operations.ts +116 -4
  24. package/corpus/core/src/db-admin/routes.ts +1 -0
  25. package/corpus/core/src/db-admin/types.ts +4 -0
  26. package/corpus/core/src/extensions/html-shell.ts +5 -4
  27. package/corpus/core/src/extensions/routes.ts +10 -0
  28. package/corpus/core/src/navigation/index.ts +1 -1
  29. package/corpus/core/src/resources/handlers.ts +10 -8
  30. package/corpus/core/src/server/poll.ts +293 -8
  31. package/corpus/core/src/styles/agent-native.css +27 -0
  32. package/corpus/core/src/templates/default/.agents/skills/actions/SKILL.md +5 -0
  33. package/corpus/core/src/templates/default/.agents/skills/adding-a-feature/SKILL.md +5 -0
  34. package/corpus/core/src/templates/default/.agents/skills/real-time-sync/SKILL.md +1 -1
  35. package/corpus/core/src/templates/default/.agents/skills/security/SKILL.md +7 -0
  36. package/corpus/core/src/templates/default/.agents/skills/storing-data/SKILL.md +5 -1
  37. package/corpus/core/src/templates/default/AGENTS.md +4 -2
  38. package/corpus/core/src/templates/headless/AGENTS.md +4 -0
  39. package/corpus/core/src/templates/workspace-core/.agents/skills/actions/SKILL.md +5 -0
  40. package/corpus/core/src/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +5 -0
  41. package/corpus/core/src/templates/workspace-core/.agents/skills/context-awareness/SKILL.md +4 -0
  42. package/corpus/core/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +6 -0
  43. package/corpus/core/src/templates/workspace-core/.agents/skills/performance/SKILL.md +4 -0
  44. package/corpus/core/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +1 -1
  45. package/corpus/core/src/templates/workspace-core/.agents/skills/security/SKILL.md +7 -0
  46. package/corpus/core/src/templates/workspace-core/.agents/skills/storing-data/SKILL.md +5 -1
  47. package/corpus/core/src/templates/workspace-core/AGENTS.md +7 -1
  48. package/corpus/core/src/templates/workspace-root/AGENTS.md +7 -1
  49. package/corpus/templates/analytics/.agents/skills/actions/SKILL.md +5 -0
  50. package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +10 -0
  51. package/corpus/templates/analytics/.agents/skills/real-time-sync/SKILL.md +1 -1
  52. package/corpus/templates/analytics/.agents/skills/security/SKILL.md +7 -0
  53. package/corpus/templates/analytics/.agents/skills/storing-data/SKILL.md +5 -1
  54. package/corpus/templates/analytics/AGENTS.md +33 -14
  55. package/corpus/templates/analytics/actions/capture-test-error.ts +4 -0
  56. package/corpus/templates/analytics/actions/get-analytics-alert-rule-defaults.ts +23 -0
  57. package/corpus/templates/analytics/actions/get-error-issue.ts +1 -1
  58. package/corpus/templates/analytics/actions/list-analysis-revisions.ts +40 -0
  59. package/corpus/templates/analytics/actions/list-dashboard-revisions.ts +40 -0
  60. package/corpus/templates/analytics/actions/list-dashboard-usage-stats.ts +299 -0
  61. package/corpus/templates/analytics/actions/navigate.ts +4 -2
  62. package/corpus/templates/analytics/actions/restore-analysis-revision.ts +43 -0
  63. package/corpus/templates/analytics/actions/restore-dashboard-revision.ts +68 -0
  64. package/corpus/templates/analytics/actions/save-analytics-alert-rule.ts +14 -0
  65. package/corpus/templates/analytics/actions/save-monitor.ts +1 -1
  66. package/corpus/templates/analytics/actions/view-screen.ts +24 -0
  67. package/corpus/templates/analytics/app/components/analysis/AnalysisHistoryPanel.tsx +181 -0
  68. package/corpus/templates/analytics/app/components/dashboard/DashboardHistoryPanel.tsx +184 -0
  69. package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +22 -16
  70. package/corpus/templates/analytics/app/components/layout/Header.tsx +1 -1
  71. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +27 -21
  72. package/corpus/templates/analytics/app/hooks/use-analysis-revisions.ts +43 -0
  73. package/corpus/templates/analytics/app/hooks/use-dashboard-chat-context.ts +110 -0
  74. package/corpus/templates/analytics/app/hooks/use-dashboard-revisions.ts +43 -0
  75. package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +8 -3
  76. package/corpus/templates/analytics/app/i18n/zh-TW.ts +64 -2
  77. package/corpus/templates/analytics/app/i18n-data.ts +783 -3
  78. package/corpus/templates/analytics/app/pages/Agents.tsx +359 -19
  79. package/corpus/templates/analytics/app/pages/Settings.tsx +3 -2
  80. package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/index.tsx +34 -1
  81. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +28 -0
  82. package/corpus/templates/analytics/app/pages/analyses/AnalysisDetail.tsx +18 -1
  83. package/corpus/templates/analytics/app/pages/monitoring/ErrorsPanel.tsx +7 -10
  84. package/corpus/templates/analytics/app/pages/monitoring/errors/IssueDetail.tsx +479 -23
  85. package/corpus/templates/analytics/app/pages/monitoring/errors/IssueList.tsx +0 -9
  86. package/corpus/templates/analytics/app/pages/monitoring/errors/i18n.ts +11 -0
  87. package/corpus/templates/analytics/app/pages/monitoring/errors/types.ts +9 -1
  88. package/corpus/templates/analytics/app/pages/monitoring/uptime/MonitorFormPage.tsx +6 -3
  89. package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +26 -30
  90. package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +9 -99
  91. package/corpus/templates/analytics/app/pages/settings/AlertRulesSettingsCard.tsx +262 -104
  92. package/corpus/templates/analytics/app/routes/team.tsx +1 -1
  93. package/corpus/templates/analytics/changelog/2026-07-08-admins-can-audit-dashboard-usage-ownership-and-cleanup-signa.md +6 -0
  94. package/corpus/templates/analytics/changelog/2026-07-08-agent-monitoring-stays-available-to-non-admins.md +6 -0
  95. package/corpus/templates/analytics/changelog/2026-07-08-alert-rules-are-easier-to-scan-expand-and-edit-from-settings.md +6 -0
  96. package/corpus/templates/analytics/changelog/2026-07-08-analytics-alert-forms-remember-last-email-recipients.md +6 -0
  97. package/corpus/templates/analytics/changelog/2026-07-08-analytics-alert-rules-can-now-use-per-rule-slack-and-webhook.md +6 -0
  98. package/corpus/templates/analytics/changelog/2026-07-08-dashboard-history-and-chat-context.md +5 -0
  99. package/corpus/templates/analytics/changelog/2026-07-08-dashboard-usage-now-counts-explorer-dashboard-traffic.md +6 -0
  100. package/corpus/templates/analytics/changelog/2026-07-08-demo-mode-session-emails-are-filtered-and-anonymized.md +6 -0
  101. package/corpus/templates/analytics/changelog/2026-07-08-error-issue-detail-adds-stack-traces-and-frequency-bars.md +6 -0
  102. package/corpus/templates/analytics/changelog/2026-07-08-error-issue-detail-now-shows-the-latest-occurrence-message-a.md +6 -0
  103. package/corpus/templates/analytics/changelog/2026-07-08-monitoring-errors-only-show-test-action-when-empty.md +6 -0
  104. package/corpus/templates/analytics/changelog/2026-07-08-production-session-replay-now-requires-private-blob-storage-.md +6 -0
  105. package/corpus/templates/analytics/changelog/2026-07-08-shared-extension-links-now-show-a-clear-message-when-you-do-.md +6 -0
  106. package/corpus/templates/analytics/changelog/2026-07-08-team-settings-show-access-controls-next-to-member-lists.md +6 -0
  107. package/corpus/templates/analytics/changelog/2026-07-08-uptime-monitors-now-use-a-10-second-request-timeout-by-defau.md +6 -0
  108. package/corpus/templates/analytics/server/db/schema-monitoring.ts +1 -1
  109. package/corpus/templates/analytics/server/db/schema.ts +56 -0
  110. package/corpus/templates/analytics/server/lib/analytics-alerts.ts +92 -0
  111. package/corpus/templates/analytics/server/lib/dashboards-store.ts +334 -5
  112. package/corpus/templates/analytics/server/lib/error-capture.ts +231 -36
  113. package/corpus/templates/analytics/server/lib/session-replay.ts +114 -8
  114. package/corpus/templates/analytics/server/lib/uptime-monitors.ts +5 -4
  115. package/corpus/templates/analytics/server/plugins/db.ts +112 -2
  116. package/corpus/templates/analytics/server/routes/api/dashboard-agent-context.json.get.ts +1 -0
  117. package/corpus/templates/assets/.agents/skills/actions/SKILL.md +5 -0
  118. package/corpus/templates/assets/.agents/skills/real-time-sync/SKILL.md +1 -1
  119. package/corpus/templates/assets/.agents/skills/security/SKILL.md +7 -0
  120. package/corpus/templates/assets/.agents/skills/storing-data/SKILL.md +5 -1
  121. package/corpus/templates/assets/AGENTS.md +4 -0
  122. package/corpus/templates/assets/app/routes/settings.tsx +1 -1
  123. package/corpus/templates/assets/app/routes/team.tsx +1 -1
  124. package/corpus/templates/brain/.agents/skills/actions/SKILL.md +5 -0
  125. package/corpus/templates/brain/.agents/skills/adding-a-feature/SKILL.md +5 -0
  126. package/corpus/templates/brain/.agents/skills/real-time-sync/SKILL.md +1 -1
  127. package/corpus/templates/brain/.agents/skills/security/SKILL.md +7 -0
  128. package/corpus/templates/brain/AGENTS.md +4 -0
  129. package/corpus/templates/brain/app/routes/team.tsx +1 -1
  130. package/corpus/templates/calendar/.agents/skills/actions/SKILL.md +5 -0
  131. package/corpus/templates/calendar/.agents/skills/real-time-sync/SKILL.md +1 -1
  132. package/corpus/templates/calendar/.agents/skills/security/SKILL.md +7 -0
  133. package/corpus/templates/calendar/.agents/skills/storing-data/SKILL.md +5 -1
  134. package/corpus/templates/calendar/AGENTS.md +4 -0
  135. package/corpus/templates/calendar/app/components/calendar/DayView.tsx +11 -2
  136. package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +21 -8
  137. package/corpus/templates/calendar/app/components/calendar/MonthView.tsx +7 -1
  138. package/corpus/templates/calendar/app/components/calendar/WeekView.tsx +11 -2
  139. package/corpus/templates/calendar/app/lib/popover-click-guard.ts +48 -4
  140. package/corpus/templates/calendar/app/pages/Settings.tsx +1 -1
  141. package/corpus/templates/calendar/app/routes/_app.team.tsx +1 -1
  142. package/corpus/templates/calendar/changelog/2026-07-08-clicking-empty-calendar-space-closes-an-open-event-popover-b.md +6 -0
  143. package/corpus/templates/chat/.agents/skills/actions/SKILL.md +5 -0
  144. package/corpus/templates/chat/.agents/skills/adding-a-feature/SKILL.md +5 -0
  145. package/corpus/templates/chat/.agents/skills/real-time-sync/SKILL.md +1 -1
  146. package/corpus/templates/chat/.agents/skills/security/SKILL.md +7 -0
  147. package/corpus/templates/chat/AGENTS.md +4 -0
  148. package/corpus/templates/chat/app/hooks/use-navigation-state.ts +1 -1
  149. package/corpus/templates/chat/app/routes/settings.tsx +2 -2
  150. package/corpus/templates/chat/app/routes/team.tsx +1 -1
  151. package/corpus/templates/clips/.agents/skills/actions/SKILL.md +5 -0
  152. package/corpus/templates/clips/.agents/skills/security/SKILL.md +7 -0
  153. package/corpus/templates/clips/AGENTS.md +4 -0
  154. package/corpus/templates/clips/actions/finalize-recording.ts +9 -3
  155. package/corpus/templates/clips/actions/set-thumbnail.ts +11 -2
  156. package/corpus/templates/clips/app/components/meetings/canvas-editor.tsx +1 -7
  157. package/corpus/templates/clips/app/components/player/player-controls.tsx +21 -13
  158. package/corpus/templates/clips/app/components/player/video-player.tsx +30 -75
  159. package/corpus/templates/clips/app/i18n/ar-SA.ts +6 -5
  160. package/corpus/templates/clips/app/i18n/de-DE.ts +6 -6
  161. package/corpus/templates/clips/app/i18n/en-US.ts +6 -5
  162. package/corpus/templates/clips/app/i18n/es-ES.ts +6 -5
  163. package/corpus/templates/clips/app/i18n/fr-FR.ts +6 -6
  164. package/corpus/templates/clips/app/i18n/hi-IN.ts +6 -5
  165. package/corpus/templates/clips/app/i18n/ja-JP.ts +6 -5
  166. package/corpus/templates/clips/app/i18n/ko-KR.ts +6 -5
  167. package/corpus/templates/clips/app/i18n/pt-BR.ts +6 -5
  168. package/corpus/templates/clips/app/i18n/zh-CN.ts +6 -5
  169. package/corpus/templates/clips/app/i18n/zh-TW.ts +6 -5
  170. package/corpus/templates/clips/app/routes/_app.meetings.$meetingId.tsx +51 -118
  171. package/corpus/templates/clips/changelog/2026-07-08-hosted-clip-uploads-now-clear-failed-buffered-chunks.md +6 -0
  172. package/corpus/templates/clips/changelog/2026-07-08-hosted-recording-uploads-now-avoid-sql-chunk-storage.md +6 -0
  173. package/corpus/templates/clips/changelog/2026-07-08-meeting-recaps-now-keep-summaries-action-items-and-transcrip.md +6 -0
  174. package/corpus/templates/clips/changelog/2026-07-08-video-playback-controls-now-match-loom-style-5-second-skips-.md +6 -0
  175. package/corpus/templates/clips/server/lib/recording-upload-state.ts +63 -0
  176. package/corpus/templates/clips/server/lib/video-storage.ts +4 -0
  177. package/corpus/templates/clips/server/routes/api/recordings/[recordingId]/thumbnail.post.ts +19 -13
  178. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +40 -1
  179. package/corpus/templates/content/.agents/skills/actions/SKILL.md +5 -0
  180. package/corpus/templates/content/.agents/skills/real-time-sync/SKILL.md +1 -1
  181. package/corpus/templates/content/.agents/skills/security/SKILL.md +7 -0
  182. package/corpus/templates/content/.agents/skills/storing-data/SKILL.md +5 -1
  183. package/corpus/templates/content/AGENTS.md +4 -0
  184. package/corpus/templates/content/app/routes/_app.settings.tsx +2 -2
  185. package/corpus/templates/content/app/routes/_app.team.tsx +1 -1
  186. package/corpus/templates/design/.agents/skills/actions/SKILL.md +5 -0
  187. package/corpus/templates/design/.agents/skills/security/SKILL.md +7 -0
  188. package/corpus/templates/design/AGENTS.md +4 -0
  189. package/corpus/templates/design/actions/take-design-screenshot.ts +12 -9
  190. package/corpus/templates/design/app/components/design/inspector/ImageFillControls.tsx +57 -13
  191. package/corpus/templates/design/app/routes/team.tsx +1 -1
  192. package/corpus/templates/design/changelog/2026-07-08-local-images-added-to-designs-now-upload-to-file-storage-ins.md +6 -0
  193. package/corpus/templates/dispatch/.agents/skills/actions/SKILL.md +5 -0
  194. package/corpus/templates/dispatch/.agents/skills/security/SKILL.md +7 -0
  195. package/corpus/templates/dispatch/AGENTS.md +4 -0
  196. package/corpus/templates/dispatch/app/hooks/use-navigation-state.ts +1 -1
  197. package/corpus/templates/dispatch/app/routes/settings.tsx +2 -2
  198. package/corpus/templates/dispatch/app/routes/team.tsx +1 -1
  199. package/corpus/templates/forms/.agents/skills/actions/SKILL.md +5 -0
  200. package/corpus/templates/forms/.agents/skills/real-time-sync/SKILL.md +1 -1
  201. package/corpus/templates/forms/.agents/skills/security/SKILL.md +7 -0
  202. package/corpus/templates/forms/.agents/skills/storing-data/SKILL.md +5 -1
  203. package/corpus/templates/forms/AGENTS.md +4 -0
  204. package/corpus/templates/forms/app/routes/_app.settings.tsx +2 -2
  205. package/corpus/templates/forms/app/routes/_app.team.tsx +1 -1
  206. package/corpus/templates/forms/shared/navigation.ts +1 -1
  207. package/corpus/templates/macros/.agents/skills/security/SKILL.md +7 -0
  208. package/corpus/templates/macros/AGENTS.md +4 -0
  209. package/corpus/templates/macros/app/routes/settings.tsx +2 -2
  210. package/corpus/templates/macros/app/routes/team.tsx +1 -1
  211. package/corpus/templates/mail/.agents/skills/actions/SKILL.md +5 -0
  212. package/corpus/templates/mail/.agents/skills/email-drafts/SKILL.md +1 -1
  213. package/corpus/templates/mail/.agents/skills/real-time-sync/SKILL.md +1 -1
  214. package/corpus/templates/mail/.agents/skills/security/SKILL.md +7 -0
  215. package/corpus/templates/mail/.agents/skills/storing-data/SKILL.md +5 -1
  216. package/corpus/templates/mail/AGENTS.md +4 -0
  217. package/corpus/templates/mail/changelog/2026-07-08-mail-attachments-in-hosted-environments-now-require-file-sto.md +6 -0
  218. package/corpus/templates/mail/server/handlers/media.ts +26 -1
  219. package/corpus/templates/mail/server/lib/outgoing-email.ts +24 -1
  220. package/corpus/templates/mail/server/lib/upload-store.ts +2 -1
  221. package/corpus/templates/plan/.agents/skills/actions/SKILL.md +5 -0
  222. package/corpus/templates/plan/.agents/skills/adding-a-feature/SKILL.md +5 -0
  223. package/corpus/templates/plan/.agents/skills/real-time-sync/SKILL.md +1 -1
  224. package/corpus/templates/plan/.agents/skills/security/SKILL.md +7 -0
  225. package/corpus/templates/plan/AGENTS.md +4 -0
  226. package/corpus/templates/plan/app/hooks/use-navigation-state.ts +1 -1
  227. package/corpus/templates/plan/app/routes/settings.tsx +2 -2
  228. package/corpus/templates/plan/app/routes/team.tsx +1 -1
  229. package/corpus/templates/plan/changelog/2026-07-08-hosted-plan-images-now-require-connected-storage.md +6 -0
  230. package/corpus/templates/plan/server/lib/plan-assets.ts +33 -4
  231. package/corpus/templates/slides/.agents/skills/actions/SKILL.md +5 -0
  232. package/corpus/templates/slides/.agents/skills/security/SKILL.md +7 -0
  233. package/corpus/templates/slides/AGENTS.md +4 -0
  234. package/corpus/templates/slides/actions/generate-image-api.ts +15 -3
  235. package/corpus/templates/slides/app/routes/settings.tsx +2 -2
  236. package/corpus/templates/slides/app/routes/team.tsx +1 -1
  237. package/corpus/templates/slides/changelog/2026-07-08-generated-slide-images-now-return-hosted-file-storage-urls-i.md +6 -0
  238. package/corpus/templates/slides/shared/api.ts +1 -1
  239. package/dist/application-state/store.d.ts.map +1 -1
  240. package/dist/application-state/store.js +8 -2
  241. package/dist/application-state/store.js.map +1 -1
  242. package/dist/client/AssistantChat.d.ts.map +1 -1
  243. package/dist/client/AssistantChat.js +24 -13
  244. package/dist/client/AssistantChat.js.map +1 -1
  245. package/dist/client/PoweredByBadge.d.ts +1 -1
  246. package/dist/client/PoweredByBadge.d.ts.map +1 -1
  247. package/dist/client/PoweredByBadge.js +3 -9
  248. package/dist/client/PoweredByBadge.js.map +1 -1
  249. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  250. package/dist/client/agent-chat-adapter.js +28 -9
  251. package/dist/client/agent-chat-adapter.js.map +1 -1
  252. package/dist/client/chat/widgets/DataTableWidget.d.ts.map +1 -1
  253. package/dist/client/chat/widgets/DataTableWidget.js +19 -2
  254. package/dist/client/chat/widgets/DataTableWidget.js.map +1 -1
  255. package/dist/client/db-admin/TableEditor.d.ts.map +1 -1
  256. package/dist/client/db-admin/TableEditor.js +19 -2
  257. package/dist/client/db-admin/TableEditor.js.map +1 -1
  258. package/dist/client/db-admin/export-utils.d.ts +2 -0
  259. package/dist/client/db-admin/export-utils.d.ts.map +1 -1
  260. package/dist/client/db-admin/export-utils.js +11 -3
  261. package/dist/client/db-admin/export-utils.js.map +1 -1
  262. package/dist/client/db-admin/useAgentSync.d.ts.map +1 -1
  263. package/dist/client/db-admin/useAgentSync.js +63 -0
  264. package/dist/client/db-admin/useAgentSync.js.map +1 -1
  265. package/dist/client/error-capture.d.ts.map +1 -1
  266. package/dist/client/error-capture.js +41 -7
  267. package/dist/client/error-capture.js.map +1 -1
  268. package/dist/client/extensions/EmbeddedExtension.d.ts.map +1 -1
  269. package/dist/client/extensions/EmbeddedExtension.js +3 -1
  270. package/dist/client/extensions/EmbeddedExtension.js.map +1 -1
  271. package/dist/client/extensions/ExtensionViewer.d.ts.map +1 -1
  272. package/dist/client/extensions/ExtensionViewer.js +32 -5
  273. package/dist/client/extensions/ExtensionViewer.js.map +1 -1
  274. package/dist/client/extensions/InlineExtensionFrame.d.ts.map +1 -1
  275. package/dist/client/extensions/InlineExtensionFrame.js +3 -1
  276. package/dist/client/extensions/InlineExtensionFrame.js.map +1 -1
  277. package/dist/client/extensions/portable-extension.d.ts.map +1 -1
  278. package/dist/client/extensions/portable-extension.js +1 -0
  279. package/dist/client/extensions/portable-extension.js.map +1 -1
  280. package/dist/client/org/OrgSwitcher.d.ts +1 -1
  281. package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
  282. package/dist/client/org/OrgSwitcher.js +11 -6
  283. package/dist/client/org/OrgSwitcher.js.map +1 -1
  284. package/dist/client/org/TeamPage.d.ts.map +1 -1
  285. package/dist/client/org/TeamPage.js +5 -5
  286. package/dist/client/org/TeamPage.js.map +1 -1
  287. package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
  288. package/dist/client/settings/SettingsPanel.js +37 -14
  289. package/dist/client/settings/SettingsPanel.js.map +1 -1
  290. package/dist/client/settings/SettingsSection.js +1 -1
  291. package/dist/client/settings/SettingsSection.js.map +1 -1
  292. package/dist/client/settings/SettingsTabsPage.d.ts.map +1 -1
  293. package/dist/client/settings/SettingsTabsPage.js +21 -10
  294. package/dist/client/settings/SettingsTabsPage.js.map +1 -1
  295. package/dist/collab/routes.d.ts +1 -1
  296. package/dist/db-admin/agent-tools.d.ts.map +1 -1
  297. package/dist/db-admin/agent-tools.js +7 -2
  298. package/dist/db-admin/agent-tools.js.map +1 -1
  299. package/dist/db-admin/operations.d.ts.map +1 -1
  300. package/dist/db-admin/operations.js +90 -4
  301. package/dist/db-admin/operations.js.map +1 -1
  302. package/dist/db-admin/routes.d.ts.map +1 -1
  303. package/dist/db-admin/routes.js +1 -0
  304. package/dist/db-admin/routes.js.map +1 -1
  305. package/dist/db-admin/types.d.ts +4 -0
  306. package/dist/db-admin/types.d.ts.map +1 -1
  307. package/dist/db-admin/types.js.map +1 -1
  308. package/dist/extensions/html-shell.d.ts +5 -4
  309. package/dist/extensions/html-shell.d.ts.map +1 -1
  310. package/dist/extensions/html-shell.js.map +1 -1
  311. package/dist/extensions/routes.d.ts.map +1 -1
  312. package/dist/extensions/routes.js +8 -0
  313. package/dist/extensions/routes.js.map +1 -1
  314. package/dist/navigation/index.d.ts +1 -1
  315. package/dist/navigation/index.d.ts.map +1 -1
  316. package/dist/navigation/index.js +1 -1
  317. package/dist/navigation/index.js.map +1 -1
  318. package/dist/notifications/routes.d.ts +1 -1
  319. package/dist/observability/routes.d.ts +1 -1
  320. package/dist/resources/handlers.d.ts +6 -1
  321. package/dist/resources/handlers.d.ts.map +1 -1
  322. package/dist/resources/handlers.js +9 -8
  323. package/dist/resources/handlers.js.map +1 -1
  324. package/dist/server/poll.d.ts +12 -4
  325. package/dist/server/poll.d.ts.map +1 -1
  326. package/dist/server/poll.js +236 -9
  327. package/dist/server/poll.js.map +1 -1
  328. package/dist/styles/agent-native.css +27 -0
  329. package/dist/templates/default/.agents/skills/actions/SKILL.md +5 -0
  330. package/dist/templates/default/.agents/skills/adding-a-feature/SKILL.md +5 -0
  331. package/dist/templates/default/.agents/skills/real-time-sync/SKILL.md +1 -1
  332. package/dist/templates/default/.agents/skills/security/SKILL.md +7 -0
  333. package/dist/templates/default/.agents/skills/storing-data/SKILL.md +5 -1
  334. package/dist/templates/default/AGENTS.md +4 -2
  335. package/dist/templates/headless/AGENTS.md +4 -0
  336. package/dist/templates/workspace-core/.agents/skills/actions/SKILL.md +5 -0
  337. package/dist/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +5 -0
  338. package/dist/templates/workspace-core/.agents/skills/context-awareness/SKILL.md +4 -0
  339. package/dist/templates/workspace-core/.agents/skills/extensions/SKILL.md +6 -0
  340. package/dist/templates/workspace-core/.agents/skills/performance/SKILL.md +4 -0
  341. package/dist/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +1 -1
  342. package/dist/templates/workspace-core/.agents/skills/security/SKILL.md +7 -0
  343. package/dist/templates/workspace-core/.agents/skills/storing-data/SKILL.md +5 -1
  344. package/dist/templates/workspace-core/AGENTS.md +7 -1
  345. package/dist/templates/workspace-root/AGENTS.md +7 -1
  346. package/package.json +1 -1
  347. package/src/templates/default/.agents/skills/actions/SKILL.md +5 -0
  348. package/src/templates/default/.agents/skills/adding-a-feature/SKILL.md +5 -0
  349. package/src/templates/default/.agents/skills/real-time-sync/SKILL.md +1 -1
  350. package/src/templates/default/.agents/skills/security/SKILL.md +7 -0
  351. package/src/templates/default/.agents/skills/storing-data/SKILL.md +5 -1
  352. package/src/templates/default/AGENTS.md +4 -2
  353. package/src/templates/headless/AGENTS.md +4 -0
  354. package/src/templates/workspace-core/.agents/skills/actions/SKILL.md +5 -0
  355. package/src/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +5 -0
  356. package/src/templates/workspace-core/.agents/skills/context-awareness/SKILL.md +4 -0
  357. package/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +6 -0
  358. package/src/templates/workspace-core/.agents/skills/performance/SKILL.md +4 -0
  359. package/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +1 -1
  360. package/src/templates/workspace-core/.agents/skills/security/SKILL.md +7 -0
  361. package/src/templates/workspace-core/.agents/skills/storing-data/SKILL.md +5 -1
  362. package/src/templates/workspace-core/AGENTS.md +7 -1
  363. package/src/templates/workspace-root/AGENTS.md +7 -1
@@ -1,3 +1,7 @@
1
+ import { stat, readFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+
1
5
  /**
2
6
  * Server-side error capture — OWNED BY THE ERROR CAPTURE FEATURE.
3
7
  *
@@ -58,6 +62,10 @@ const DEFAULT_ISSUE_LIMIT = 50;
58
62
  const MAX_ISSUE_LIMIT = 100;
59
63
  const DEFAULT_EVENTS_PER_ISSUE_READ = 50;
60
64
  const SPARKLINE_DAYS = 14;
65
+ const SOURCE_CONTEXT_BEFORE = 4;
66
+ const SOURCE_CONTEXT_AFTER = 4;
67
+ const MAX_SOURCE_CONTEXT_FILE_BYTES = 2_000_000;
68
+ const MAX_SOURCE_CONTEXT_LINE_CHARS = 500;
61
69
 
62
70
  // ---------------------------------------------------------------------------
63
71
  // Pure helpers (unit tested)
@@ -70,6 +78,13 @@ export interface ParsedStackFrame {
70
78
  colno: number | null;
71
79
  inApp: boolean;
72
80
  raw: string;
81
+ sourceContext?: SourceContextLine[];
82
+ }
83
+
84
+ export interface SourceContextLine {
85
+ line: number;
86
+ text: string;
87
+ highlight: boolean;
73
88
  }
74
89
 
75
90
  const VENDOR_FILE_RE =
@@ -179,6 +194,172 @@ export function parseStack(
179
194
  return frames;
180
195
  }
181
196
 
197
+ export function sourceContextFromText(
198
+ source: string,
199
+ lineNumber: number | null | undefined,
200
+ options: { before?: number; after?: number } = {},
201
+ ): SourceContextLine[] | null {
202
+ if (!lineNumber || lineNumber < 1) return null;
203
+ const lines = source.split(/\r?\n/);
204
+ if (lineNumber > lines.length) return null;
205
+ const before = options.before ?? SOURCE_CONTEXT_BEFORE;
206
+ const after = options.after ?? SOURCE_CONTEXT_AFTER;
207
+ const start = Math.max(1, lineNumber - before);
208
+ const end = Math.min(lines.length, lineNumber + after);
209
+ const context: SourceContextLine[] = [];
210
+ for (let line = start; line <= end; line += 1) {
211
+ const text = lines[line - 1] ?? "";
212
+ context.push({
213
+ line,
214
+ text:
215
+ text.length > MAX_SOURCE_CONTEXT_LINE_CHARS
216
+ ? `${text.slice(0, MAX_SOURCE_CONTEXT_LINE_CHARS)}…`
217
+ : text,
218
+ highlight: line === lineNumber,
219
+ });
220
+ }
221
+ return context;
222
+ }
223
+
224
+ const SOURCE_EXT_RE = /\.(?:[cm]?[jt]sx?|vue|svelte|css|scss|json)$/i;
225
+ const SOURCE_CONTEXT_ALLOWED_PREFIXES = ["app/"] as const;
226
+
227
+ function templateRootFrom(value: string): string | null {
228
+ const marker = `${path.sep}templates${path.sep}analytics`;
229
+ const index = value.indexOf(marker);
230
+ if (index < 0) return null;
231
+ return value.slice(0, index + marker.length);
232
+ }
233
+
234
+ function sourceRoots(): string[] {
235
+ const roots = new Set<string>();
236
+ const cwdTemplateRoot = templateRootFrom(process.cwd());
237
+ roots.add(cwdTemplateRoot ?? process.cwd());
238
+ try {
239
+ const modulePath = fileURLToPath(import.meta.url);
240
+ const moduleTemplateRoot = templateRootFrom(modulePath);
241
+ if (moduleTemplateRoot) roots.add(moduleTemplateRoot);
242
+ } catch {
243
+ // import.meta.url is always file: in Node, but source context is best-effort.
244
+ }
245
+ return Array.from(roots).map((root) => path.resolve(root));
246
+ }
247
+
248
+ function isWithinRoot(candidate: string, root: string): boolean {
249
+ const relative = path.relative(root, candidate);
250
+ return (
251
+ relative === "" ||
252
+ (!relative.startsWith("..") && !path.isAbsolute(relative))
253
+ );
254
+ }
255
+
256
+ function cleanFrameFile(file: string | null): string | null {
257
+ if (!file) return null;
258
+ let cleaned = file.trim();
259
+ if (!cleaned || cleaned === "<anonymous>" || cleaned === "[native code]") {
260
+ return null;
261
+ }
262
+ if (/^https?:\/\//i.test(cleaned)) {
263
+ try {
264
+ cleaned = new URL(cleaned).pathname;
265
+ } catch {
266
+ return null;
267
+ }
268
+ } else if (cleaned.startsWith("file://")) {
269
+ try {
270
+ cleaned = fileURLToPath(cleaned);
271
+ } catch {
272
+ return null;
273
+ }
274
+ }
275
+ cleaned = cleaned.replace(/[?#].*$/, "");
276
+ try {
277
+ cleaned = decodeURIComponent(cleaned);
278
+ } catch {
279
+ // Keep the original path when a browser stack includes malformed escapes.
280
+ }
281
+ return cleaned;
282
+ }
283
+
284
+ export function trustedSourceRelativePath(cleaned: string): string | null {
285
+ const normalized = cleaned.replace(/\\/g, "/").replace(/^\/+/, "");
286
+ if (
287
+ !normalized ||
288
+ normalized.startsWith("../") ||
289
+ normalized.includes("/../")
290
+ ) {
291
+ return null;
292
+ }
293
+ if (
294
+ !SOURCE_CONTEXT_ALLOWED_PREFIXES.some((prefix) =>
295
+ normalized.startsWith(prefix),
296
+ )
297
+ ) {
298
+ return null;
299
+ }
300
+ return normalized;
301
+ }
302
+
303
+ async function resolveSourcePath(
304
+ frame: ParsedStackFrame,
305
+ ): Promise<string | null> {
306
+ if (!frame.inApp) return null;
307
+ const cleaned = cleanFrameFile(frame.file);
308
+ if (!cleaned || !SOURCE_EXT_RE.test(cleaned)) return null;
309
+ const relativePath = trustedSourceRelativePath(cleaned);
310
+ if (!relativePath) return null;
311
+ const roots = sourceRoots();
312
+ const candidates = new Set<string>();
313
+ for (const root of roots) candidates.add(path.resolve(root, relativePath));
314
+
315
+ for (const candidate of candidates) {
316
+ if (!roots.some((root) => isWithinRoot(candidate, root))) continue;
317
+ try {
318
+ const fileStat = await stat(candidate);
319
+ if (
320
+ fileStat.isFile() &&
321
+ fileStat.size > 0 &&
322
+ fileStat.size <= MAX_SOURCE_CONTEXT_FILE_BYTES
323
+ ) {
324
+ return candidate;
325
+ }
326
+ } catch {
327
+ // Try the next candidate.
328
+ }
329
+ }
330
+ return null;
331
+ }
332
+
333
+ async function sourceContextForFrame(
334
+ frame: ParsedStackFrame,
335
+ ): Promise<SourceContextLine[] | undefined> {
336
+ if (!frame.lineno) return undefined;
337
+ const sourcePath = await resolveSourcePath(frame);
338
+ if (!sourcePath) return undefined;
339
+ try {
340
+ const source = await readFile(sourcePath, "utf8");
341
+ return (
342
+ sourceContextFromText(source, frame.lineno, {
343
+ before: SOURCE_CONTEXT_BEFORE,
344
+ after: SOURCE_CONTEXT_AFTER,
345
+ }) ?? undefined
346
+ );
347
+ } catch {
348
+ return undefined;
349
+ }
350
+ }
351
+
352
+ async function addSourceContexts(
353
+ frames: ParsedStackFrame[],
354
+ ): Promise<ParsedStackFrame[]> {
355
+ return Promise.all(
356
+ frames.map(async (frame) => {
357
+ const sourceContext = await sourceContextForFrame(frame);
358
+ return sourceContext?.length ? { ...frame, sourceContext } : frame;
359
+ }),
360
+ );
361
+ }
362
+
182
363
  /** Strip content hashes + query/hash from a filename for stable grouping. */
183
364
  export function normalizeFrameFile(file: string | null): string {
184
365
  if (!file) return "";
@@ -1031,6 +1212,7 @@ export interface ErrorEventDetail {
1031
1212
  culprit: string | null;
1032
1213
  level: ExceptionLevel;
1033
1214
  stack: ParsedStackFrame[];
1215
+ rawStack: string | null;
1034
1216
  handled: boolean;
1035
1217
  url: string | null;
1036
1218
  userId: string | null;
@@ -1164,42 +1346,55 @@ export async function getErrorIssue(
1164
1346
  );
1165
1347
 
1166
1348
  const sessions = new Map<string, { recordingId: string; path: string }>();
1167
- const events: ErrorEventDetail[] = eventRows.map((row: any) => {
1168
- let recordingId: string | null = null;
1169
- if (row.sessionRecordingId && byId.has(row.sessionRecordingId)) {
1170
- recordingId = row.sessionRecordingId;
1171
- } else if (row.clientRecordingId && byClientId.has(row.clientRecordingId)) {
1172
- recordingId = byClientId.get(row.clientRecordingId) ?? null;
1173
- }
1174
- if (recordingId && !sessions.has(recordingId)) {
1175
- sessions.set(recordingId, {
1176
- recordingId,
1177
- path: `/sessions/${recordingId}`,
1178
- });
1179
- }
1180
- return {
1181
- id: row.id,
1182
- type: row.type,
1183
- message: row.message ?? "",
1184
- culprit: row.culprit ?? null,
1185
- level: coerceLevel(row.level),
1186
- stack: parseJson<ParsedStackFrame[]>(row.stack, []),
1187
- handled: Boolean(row.handled),
1188
- url: row.url ?? null,
1189
- userId: row.userId ?? null,
1190
- anonymousId: row.anonymousId ?? null,
1191
- userKey: row.userKey ?? null,
1192
- sessionId: row.sessionId ?? null,
1193
- sessionRecordingId: recordingId,
1194
- sessionRecordingPath: recordingPath(recordingId),
1195
- release: row.release ?? null,
1196
- environment: row.environment ?? null,
1197
- tags: parseJson<Record<string, unknown>>(row.tags, {}),
1198
- extra: parseJson<Record<string, unknown>>(row.extra, {}),
1199
- breadcrumbs: parseJson<unknown[]>(row.breadcrumbs, []),
1200
- occurredAt: row.occurredAt,
1201
- };
1202
- });
1349
+ const events = await Promise.all(
1350
+ eventRows.map(
1351
+ async (row: any, index: number): Promise<ErrorEventDetail> => {
1352
+ let recordingId: string | null = null;
1353
+ if (row.sessionRecordingId && byId.has(row.sessionRecordingId)) {
1354
+ recordingId = row.sessionRecordingId;
1355
+ } else if (
1356
+ row.clientRecordingId &&
1357
+ byClientId.has(row.clientRecordingId)
1358
+ ) {
1359
+ recordingId = byClientId.get(row.clientRecordingId) ?? null;
1360
+ }
1361
+ if (recordingId && !sessions.has(recordingId)) {
1362
+ sessions.set(recordingId, {
1363
+ recordingId,
1364
+ path: `/sessions/${recordingId}`,
1365
+ });
1366
+ }
1367
+ return {
1368
+ id: row.id,
1369
+ type: row.type,
1370
+ message: row.message ?? "",
1371
+ culprit: row.culprit ?? null,
1372
+ level: coerceLevel(row.level),
1373
+ stack:
1374
+ index === 0
1375
+ ? await addSourceContexts(
1376
+ parseJson<ParsedStackFrame[]>(row.stack, []),
1377
+ )
1378
+ : parseJson<ParsedStackFrame[]>(row.stack, []),
1379
+ rawStack: row.rawStack ?? null,
1380
+ handled: Boolean(row.handled),
1381
+ url: row.url ?? null,
1382
+ userId: row.userId ?? null,
1383
+ anonymousId: row.anonymousId ?? null,
1384
+ userKey: row.userKey ?? null,
1385
+ sessionId: row.sessionId ?? null,
1386
+ sessionRecordingId: recordingId,
1387
+ sessionRecordingPath: recordingPath(recordingId),
1388
+ release: row.release ?? null,
1389
+ environment: row.environment ?? null,
1390
+ tags: parseJson<Record<string, unknown>>(row.tags, {}),
1391
+ extra: parseJson<Record<string, unknown>>(row.extra, {}),
1392
+ breadcrumbs: parseJson<unknown[]>(row.breadcrumbs, []),
1393
+ occurredAt: row.occurredAt,
1394
+ };
1395
+ },
1396
+ ),
1397
+ );
1203
1398
 
1204
1399
  const sparklines = await sparklinesForIssues([issueId]);
1205
1400
  const issue: ErrorIssueSummary = {
@@ -2,6 +2,7 @@ import { Buffer } from "node:buffer";
2
2
  import { createHash, randomUUID } from "node:crypto";
3
3
  import { gzipSync, gunzipSync } from "node:zlib";
4
4
 
5
+ import { readAppState } from "@agent-native/core/application-state";
5
6
  import {
6
7
  deletePrivateBlob,
7
8
  putPrivateBlob,
@@ -237,6 +238,7 @@ const DEFAULT_REPLAY_MAX_REQUESTS_PER_MINUTE = 120;
237
238
  const RETENTION_DELETE_BATCH_SIZE = 500;
238
239
  const REPLAY_PRIVATE_BLOB_REF_KIND = "agent-native.session-replay.private-blob";
239
240
  const REPLAY_PRIVATE_BLOB_REF_VERSION = 1;
241
+ const SESSION_DEMO_EMAIL_PATTERN = /[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/gi;
240
242
  let inlineReplayFallbackWarned = false;
241
243
 
242
244
  function replayError(message: string, statusCode: number): Error {
@@ -274,6 +276,92 @@ function replayEmail(value: unknown): string | null {
274
276
  return raw && raw.includes("@") ? raw : null;
275
277
  }
276
278
 
279
+ function normalizedEmail(value: unknown): string | null {
280
+ return replayEmail(value)?.toLowerCase() ?? null;
281
+ }
282
+
283
+ function isBuilderEmail(value: unknown): boolean {
284
+ return normalizedEmail(value)?.endsWith("@builder.io") === true;
285
+ }
286
+
287
+ async function isSessionDemoModeEnabled(): Promise<boolean> {
288
+ if (process.env.DEMO_MODE === "true") return true;
289
+ try {
290
+ const state = await readAppState("demo-mode");
291
+ return state?.enabled === true;
292
+ } catch {
293
+ return false;
294
+ }
295
+ }
296
+
297
+ function demoBuilderSessionCondition() {
298
+ return or(
299
+ sql`lower(${schema.sessionRecordings.userId}) like ${"%@builder.io"}`,
300
+ sql`lower(${schema.sessionRecordings.userKey}) like ${"%@builder.io"}`,
301
+ );
302
+ }
303
+
304
+ class SessionDemoAnonymizer {
305
+ private readonly aliases = new Map<string, string>();
306
+
307
+ aliasFor(value: unknown): string | null {
308
+ const raw = replayString(value);
309
+ if (!raw || raw.match(SESSION_DEMO_EMAIL_PATTERN)?.[0] !== raw) {
310
+ return null;
311
+ }
312
+ const email = raw.toLowerCase();
313
+ let alias = this.aliases.get(email);
314
+ if (!alias) {
315
+ alias = `anonymized-${this.aliases.size + 1}@builder.io`;
316
+ this.aliases.set(email, alias);
317
+ }
318
+ return alias;
319
+ }
320
+
321
+ summarize(row: any, role?: SessionReplayAccessRole): SessionRecordingSummary {
322
+ const summary = rowToSessionRecordingSummary(row, role);
323
+ return {
324
+ ...summary,
325
+ userId: this.aliasFor(row.userId) ?? summary.userId,
326
+ userKey: this.aliasFor(row.userKey) ?? summary.userKey,
327
+ ownerEmail: this.aliasFor(summary.ownerEmail) ?? summary.ownerEmail,
328
+ metadata: anonymizeEmailValue(summary.metadata, this) as Record<
329
+ string,
330
+ unknown
331
+ >,
332
+ };
333
+ }
334
+ }
335
+
336
+ function anonymizeEmailValue(
337
+ value: unknown,
338
+ anonymizer: SessionDemoAnonymizer,
339
+ ): unknown {
340
+ const alias = anonymizer.aliasFor(value);
341
+ if (alias) return alias;
342
+ if (Array.isArray(value)) {
343
+ return value.map((item) => anonymizeEmailValue(item, anonymizer));
344
+ }
345
+ if (typeof value === "string") {
346
+ return value.replace(SESSION_DEMO_EMAIL_PATTERN, (email) => {
347
+ return anonymizer.aliasFor(email) ?? email;
348
+ });
349
+ }
350
+ if (value && typeof value === "object") {
351
+ const out: Record<string, unknown> = {};
352
+ for (const [key, item] of Object.entries(value)) {
353
+ out[key] = anonymizeEmailValue(item, anonymizer);
354
+ }
355
+ return out;
356
+ }
357
+ return value;
358
+ }
359
+
360
+ function assertDemoVisibleSession(row: any): void {
361
+ if (isBuilderEmail(row.userId) || isBuilderEmail(row.userKey)) return;
362
+ throw replayError("Session recording not found", 404);
363
+ }
364
+
277
365
  function replayInteger(value: unknown): number | null {
278
366
  if (typeof value === "number" && Number.isInteger(value)) return value;
279
367
  if (typeof value === "string" && /^-?\d+$/.test(value.trim())) {
@@ -580,16 +668,16 @@ function abandonedReplayMinutes(): number {
580
668
  );
581
669
  }
582
670
 
583
- function productionInlineFallbackAllowed(): boolean {
671
+ function inlineReplayFallbackAllowed(): boolean {
584
672
  if (process.env.NODE_ENV !== "production") return true;
585
- return process.env.ANALYTICS_SESSION_REPLAY_SQL_FALLBACK === "1";
673
+ return false;
586
674
  }
587
675
 
588
676
  function warnInlineReplayFallback(): void {
589
677
  if (inlineReplayFallbackWarned) return;
590
678
  inlineReplayFallbackWarned = true;
591
679
  console.warn(
592
- "[session-replay] Private blob storage is not configured; storing capped replay chunks inline in SQL. This is intended only for local/dev use.",
680
+ "[session-replay] Private blob storage is not configured; storing capped replay chunks inline in SQL. This is for local/dev use only.",
593
681
  );
594
682
  }
595
683
 
@@ -619,9 +707,9 @@ async function storeReplayChunkBlob(
619
707
  },
620
708
  });
621
709
  if (!handle) {
622
- if (!productionInlineFallbackAllowed()) {
710
+ if (!inlineReplayFallbackAllowed()) {
623
711
  throw replayError(
624
- "Session replay blob storage is required in production. Configure a private blob provider or set ANALYTICS_SESSION_REPLAY_SQL_FALLBACK=1 for a capped temporary fallback.",
712
+ "Session replay blob storage is required in production. Configure a private blob provider before enabling full snapshot playback.",
625
713
  503,
626
714
  );
627
715
  }
@@ -1580,6 +1668,7 @@ export async function listSessionRecordings(
1580
1668
  filters: SessionReplayListFilters = {},
1581
1669
  ): Promise<SessionRecordingSummary[]> {
1582
1670
  const db = getDb() as any;
1671
+ const demoMode = await isSessionDemoModeEnabled();
1583
1672
  const limit = Math.min(
1584
1673
  MAX_SESSION_RECORDINGS_LIMIT,
1585
1674
  Math.max(1, filters.limit ?? DEFAULT_SESSION_RECORDINGS_LIMIT),
@@ -1592,6 +1681,7 @@ export async function listSessionRecordings(
1592
1681
  replayVisibleIdentityCondition(),
1593
1682
  replayPlayableEventsCondition(),
1594
1683
  ];
1684
+ if (demoMode) conditions.push(demoBuilderSessionCondition());
1595
1685
  if (filters.app)
1596
1686
  conditions.push(eq(schema.sessionRecordings.app, filters.app));
1597
1687
  if (filters.template) {
@@ -1645,13 +1735,22 @@ export async function listSessionRecordings(
1645
1735
  .where(and(...conditions))
1646
1736
  .orderBy(desc(schema.sessionRecordings.startedAt))
1647
1737
  .limit(limit);
1648
- return rows.map((row: any) => rowToSessionRecordingSummary(row));
1738
+ if (!demoMode) {
1739
+ return rows.map((row: any) => rowToSessionRecordingSummary(row));
1740
+ }
1741
+ const anonymizer = new SessionDemoAnonymizer();
1742
+ return rows
1743
+ .filter(
1744
+ (row: any) => isBuilderEmail(row.userId) || isBuilderEmail(row.userKey),
1745
+ )
1746
+ .map((row: any) => anonymizer.summarize(row));
1649
1747
  }
1650
1748
 
1651
1749
  export async function getSessionReplaySummary(
1652
1750
  recordingId: string,
1653
1751
  scope: SessionReplayScope,
1654
1752
  ): Promise<SessionRecordingSummary> {
1753
+ const demoMode = await isSessionDemoModeEnabled();
1655
1754
  const access = await resolveAccess("session-recording", recordingId, {
1656
1755
  userEmail: scope.userEmail,
1657
1756
  orgId: scope.orgId ?? undefined,
@@ -1660,12 +1759,17 @@ export async function getSessionReplaySummary(
1660
1759
  if (!isVisibleSessionRecording(access.resource)) {
1661
1760
  throw replayError("Session recording not found", 404);
1662
1761
  }
1663
- return rowToSessionRecordingSummary(access.resource, access.role);
1762
+ if (!demoMode) {
1763
+ return rowToSessionRecordingSummary(access.resource, access.role);
1764
+ }
1765
+ assertDemoVisibleSession(access.resource);
1766
+ return new SessionDemoAnonymizer().summarize(access.resource, access.role);
1664
1767
  }
1665
1768
 
1666
1769
  export async function getSessionReplayTokenizedSummary(
1667
1770
  recordingId: string,
1668
1771
  ): Promise<SessionRecordingSummary> {
1772
+ const demoMode = await isSessionDemoModeEnabled();
1669
1773
  const db = getDb() as any;
1670
1774
  // guard:allow-unscoped -- called only after verifySessionReplayAgentAccess(recordingId, token) verifies a signed, recording-scoped agent_access token.
1671
1775
  const [row] = await db
@@ -1676,7 +1780,9 @@ export async function getSessionReplayTokenizedSummary(
1676
1780
  if (!row || !isVisibleSessionRecording(row)) {
1677
1781
  throw replayError("Session recording not found", 404);
1678
1782
  }
1679
- return rowToSessionRecordingSummary(row, "viewer");
1783
+ if (!demoMode) return rowToSessionRecordingSummary(row, "viewer");
1784
+ assertDemoVisibleSession(row);
1785
+ return new SessionDemoAnonymizer().summarize(row, "viewer");
1680
1786
  }
1681
1787
 
1682
1788
  function parseInlineReplayEvents(inlineData: string): unknown[] {
@@ -203,6 +203,7 @@ const MAX_REDIRECT_HOPS = 5;
203
203
  const MONITOR_RUNNING_STALE_MS = 5 * 60 * 1000;
204
204
  const DEFAULT_RESULT_RETENTION_DAYS = 30;
205
205
  const DEFAULT_MONITOR_LIMIT_PER_OWNER = 100;
206
+ export const DEFAULT_MONITOR_TIMEOUT_MS = 10_000;
206
207
  const MAX_REQUEST_HEADER_COUNT = 20;
207
208
  const MAX_REQUEST_HEADER_NAME_LENGTH = 128;
208
209
  const MAX_REQUEST_HEADER_VALUE_BYTES = 2048;
@@ -822,7 +823,7 @@ export async function runMonitorCheck(
822
823
  monitor.timeoutMs,
823
824
  MIN_TIMEOUT_MS,
824
825
  MAX_TIMEOUT_MS,
825
- 15000,
826
+ DEFAULT_MONITOR_TIMEOUT_MS,
826
827
  );
827
828
  const timer = setTimeout(() => controller.abort(), timeoutMs);
828
829
  const start = Date.now();
@@ -925,7 +926,7 @@ function rowToMonitor(row: any): Monitor {
925
926
  ),
926
927
  requestBody: row.requestBody ?? null,
927
928
  intervalSeconds: Number(row.intervalSeconds ?? 300),
928
- timeoutMs: Number(row.timeoutMs ?? 15000),
929
+ timeoutMs: Number(row.timeoutMs ?? DEFAULT_MONITOR_TIMEOUT_MS),
929
930
  expectedStatus: normalizeStatusMatcher(
930
931
  safeJsonParse<unknown>(row.expectedStatus, null),
931
932
  ),
@@ -1155,10 +1156,10 @@ export async function saveMonitor(
1155
1156
  300,
1156
1157
  );
1157
1158
  const timeoutMs = clampInt(
1158
- input.timeoutMs ?? 15000,
1159
+ input.timeoutMs ?? DEFAULT_MONITOR_TIMEOUT_MS,
1159
1160
  MIN_TIMEOUT_MS,
1160
1161
  MAX_TIMEOUT_MS,
1161
- 15000,
1162
+ DEFAULT_MONITOR_TIMEOUT_MS,
1162
1163
  );
1163
1164
  const expectedStatus = normalizeStatusMatcher(input.expectedStatus);
1164
1165
  const assertions = normalizeAssertions(input.assertions);