@agent-native/core 0.77.6 → 0.77.8

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 (177) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +29 -0
  3. package/corpus/core/package.json +3 -3
  4. package/corpus/core/src/agent/production-agent.ts +18 -0
  5. package/corpus/core/src/agent/thread-data-builder.ts +21 -2
  6. package/corpus/core/src/cli/create.ts +35 -1
  7. package/corpus/core/src/cli/skills.ts +8 -0
  8. package/corpus/core/src/client/AgentPanel.tsx +57 -25
  9. package/corpus/core/src/client/MultiTabAssistantChat.tsx +31 -1
  10. package/corpus/core/src/client/analytics.ts +24 -2
  11. package/corpus/core/src/client/use-agent-engine-configured.ts +29 -15
  12. package/corpus/core/src/client/use-chat-threads.ts +104 -55
  13. package/corpus/core/src/db/ddl-guard.ts +190 -0
  14. package/corpus/core/src/secrets/storage.ts +36 -2
  15. package/corpus/core/src/server/analytics.ts +27 -3
  16. package/corpus/core/src/settings/store.ts +40 -6
  17. package/corpus/core/src/sharing/access.ts +35 -13
  18. package/corpus/core/src/sharing/actions/share-resource.ts +32 -9
  19. package/corpus/core/src/sharing/actions/unshare-resource.ts +25 -2
  20. package/corpus/core/src/sharing/registry.ts +9 -0
  21. package/corpus/core/src/vite/client.ts +3 -0
  22. package/corpus/templates/analytics/actions/data-source-status.ts +25 -14
  23. package/corpus/templates/analytics/app/components/layout/NewAnalysisDialog.tsx +2 -2
  24. package/corpus/templates/analytics/app/lib/data-source-status.ts +47 -6
  25. package/corpus/templates/analytics/app/lib/data-sources.ts +14 -3
  26. package/corpus/templates/analytics/app/pages/DataSources.tsx +24 -5
  27. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +15 -43
  28. package/corpus/templates/analytics/changelog/2026-06-25-fixed-hubspot-data-source-status-so-private-app-tokens-legac.md +6 -0
  29. package/corpus/templates/analytics/netlify.toml +1 -0
  30. package/corpus/templates/analytics/server/lib/credential-keys.ts +3 -1
  31. package/corpus/templates/analytics/server/routes/api/test-connection.post.ts +12 -3
  32. package/corpus/templates/assets/app/components/layout/Sidebar.tsx +5 -2
  33. package/corpus/templates/assets/changelog/2026-06-25-create-now-returns-from-agent-settings-to-the-asset-chat-eve.md +6 -0
  34. package/corpus/templates/assets/netlify.toml +1 -0
  35. package/corpus/templates/brain/netlify.toml +1 -0
  36. package/corpus/templates/calendar/app/i18n-data.ts +12 -0
  37. package/corpus/templates/calendar/app/lib/clipboard.ts +58 -0
  38. package/corpus/templates/calendar/app/pages/AvailabilitySettings.tsx +15 -9
  39. package/corpus/templates/calendar/app/pages/BookingLinksPage.tsx +6 -2
  40. package/corpus/templates/calendar/changelog/2026-06-25-booking-link-copy-buttons-no-longer-fail-when-clipboard-perm.md +6 -0
  41. package/corpus/templates/calendar/netlify.toml +1 -0
  42. package/corpus/templates/chat/netlify.toml +1 -0
  43. package/corpus/templates/clips/AGENTS.md +9 -7
  44. package/corpus/templates/clips/actions/add-vocabulary-term.ts +2 -2
  45. package/corpus/templates/clips/actions/archive-recording.ts +5 -2
  46. package/corpus/templates/clips/actions/clear-edits.ts +5 -2
  47. package/corpus/templates/clips/actions/create-folder.ts +7 -2
  48. package/corpus/templates/clips/actions/delete-folder.ts +7 -4
  49. package/corpus/templates/clips/actions/delete-recording-permanent.ts +5 -2
  50. package/corpus/templates/clips/actions/finalize-recording.ts +5 -2
  51. package/corpus/templates/clips/actions/import-loom-recording.ts +2 -1
  52. package/corpus/templates/clips/actions/list-notifications.ts +9 -5
  53. package/corpus/templates/clips/actions/list-organization-state.ts +2 -1
  54. package/corpus/templates/clips/actions/list-recordings.ts +4 -1
  55. package/corpus/templates/clips/actions/move-recording.ts +5 -1
  56. package/corpus/templates/clips/actions/rename-folder.ts +6 -3
  57. package/corpus/templates/clips/actions/request-transcript.ts +5 -2
  58. package/corpus/templates/clips/actions/restore-recording.ts +5 -2
  59. package/corpus/templates/clips/actions/save-browser-diagnostics.ts +21 -8
  60. package/corpus/templates/clips/actions/set-chapters.ts +5 -2
  61. package/corpus/templates/clips/actions/set-thumbnail.ts +5 -2
  62. package/corpus/templates/clips/actions/split-recording.ts +5 -2
  63. package/corpus/templates/clips/actions/stitch-recordings.ts +6 -2
  64. package/corpus/templates/clips/actions/trash-recording.ts +5 -2
  65. package/corpus/templates/clips/actions/undo-edit.ts +5 -2
  66. package/corpus/templates/clips/actions/view-screen.ts +2 -1
  67. package/corpus/templates/clips/app/components/library/recording-card.tsx +24 -7
  68. package/corpus/templates/clips/app/lib/browser-diagnostics-capture.ts +5 -1
  69. package/corpus/templates/clips/changelog/2026-06-25-chrome-extension-recordings-now-upload-large-capture-bursts.md +6 -0
  70. package/corpus/templates/clips/changelog/2026-06-25-console-diagnostics-keep-more-useful-non-secret-details-when.md +6 -0
  71. package/corpus/templates/clips/changelog/2026-06-25-fixed-owner-recognition-so-clips-created-from-desktop-and-we.md +6 -0
  72. package/corpus/templates/clips/chrome-extension/package.json +3 -0
  73. package/corpus/templates/clips/chrome-extension/public/manifest.json +1 -1
  74. package/corpus/templates/clips/chrome-extension/src/background.ts +85 -9
  75. package/corpus/templates/clips/chrome-extension/src/content-script.ts +55 -0
  76. package/corpus/templates/clips/chrome-extension/src/offscreen.ts +79 -3
  77. package/corpus/templates/clips/chrome-extension/src/options.ts +10 -0
  78. package/corpus/templates/clips/chrome-extension/src/overlay.ts +6 -0
  79. package/corpus/templates/clips/chrome-extension/src/permission.ts +8 -1
  80. package/corpus/templates/clips/chrome-extension/src/popup.ts +65 -39
  81. package/corpus/templates/clips/chrome-extension/src/sentry.ts +206 -0
  82. package/corpus/templates/clips/chrome-extension/vite.config.ts +47 -0
  83. package/corpus/templates/clips/netlify.toml +1 -0
  84. package/corpus/templates/clips/server/db/index.ts +1 -0
  85. package/corpus/templates/clips/server/lib/google-calendar-oauth.ts +35 -23
  86. package/corpus/templates/clips/server/lib/public-agent-context.ts +8 -1
  87. package/corpus/templates/clips/server/lib/recordings.ts +18 -2
  88. package/corpus/templates/clips/server/lib/slack-oauth.ts +9 -6
  89. package/corpus/templates/clips/server/plugins/onboarding-calendar.ts +6 -2
  90. package/corpus/templates/clips/server/routes/api/public-recording.get.ts +2 -2
  91. package/corpus/templates/clips/server/routes/api/recordings/[recordingId]/thumbnail.post.ts +5 -2
  92. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/abort.post.ts +5 -2
  93. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +5 -2
  94. package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/reset-chunks.post.ts +5 -2
  95. package/corpus/templates/clips/shared/browser-diagnostics.ts +14 -4
  96. package/corpus/templates/content/netlify.toml +1 -0
  97. package/corpus/templates/design/netlify.toml +1 -0
  98. package/corpus/templates/dispatch/netlify.toml +1 -0
  99. package/corpus/templates/forms/netlify.toml +1 -0
  100. package/corpus/templates/macros/netlify.toml +1 -0
  101. package/corpus/templates/mail/app/components/email/EmailList.tsx +7 -3
  102. package/corpus/templates/mail/app/components/email/EmailThread.tsx +4 -1
  103. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +10 -2
  104. package/corpus/templates/mail/app/hooks/use-compose-state.ts +15 -5
  105. package/corpus/templates/mail/app/hooks/use-google-auth.ts +47 -9
  106. package/corpus/templates/mail/changelog/2026-06-25-account-avatars-stay-stable-while-mail-refreshes-google-acco.md +6 -0
  107. package/corpus/templates/mail/changelog/2026-06-25-mail-background-draft-saves-and-thread-prefetches-no-longer.md +6 -0
  108. package/corpus/templates/mail/netlify.toml +1 -0
  109. package/corpus/templates/plan/.agents/skills/visual-plan/references/canvas.md +8 -0
  110. package/corpus/templates/plan/netlify.toml +1 -0
  111. package/corpus/templates/slides/netlify.toml +1 -0
  112. package/corpus/templates/videos/netlify.toml +1 -0
  113. package/dist/agent/production-agent.d.ts.map +1 -1
  114. package/dist/agent/production-agent.js +18 -0
  115. package/dist/agent/production-agent.js.map +1 -1
  116. package/dist/agent/thread-data-builder.d.ts.map +1 -1
  117. package/dist/agent/thread-data-builder.js +23 -2
  118. package/dist/agent/thread-data-builder.js.map +1 -1
  119. package/dist/cli/create.d.ts.map +1 -1
  120. package/dist/cli/create.js +28 -1
  121. package/dist/cli/create.js.map +1 -1
  122. package/dist/cli/skills.d.ts +1 -1
  123. package/dist/cli/skills.d.ts.map +1 -1
  124. package/dist/cli/skills.js +8 -0
  125. package/dist/cli/skills.js.map +1 -1
  126. package/dist/client/AgentPanel.d.ts +8 -2
  127. package/dist/client/AgentPanel.d.ts.map +1 -1
  128. package/dist/client/AgentPanel.js +29 -15
  129. package/dist/client/AgentPanel.js.map +1 -1
  130. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  131. package/dist/client/MultiTabAssistantChat.js +4 -4
  132. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  133. package/dist/client/analytics.d.ts.map +1 -1
  134. package/dist/client/analytics.js +22 -2
  135. package/dist/client/analytics.js.map +1 -1
  136. package/dist/client/use-agent-engine-configured.d.ts.map +1 -1
  137. package/dist/client/use-agent-engine-configured.js +23 -13
  138. package/dist/client/use-agent-engine-configured.js.map +1 -1
  139. package/dist/client/use-chat-threads.d.ts +4 -0
  140. package/dist/client/use-chat-threads.d.ts.map +1 -1
  141. package/dist/client/use-chat-threads.js +49 -4
  142. package/dist/client/use-chat-threads.js.map +1 -1
  143. package/dist/collab/routes.d.ts +2 -2
  144. package/dist/db/ddl-guard.d.ts +88 -0
  145. package/dist/db/ddl-guard.d.ts.map +1 -0
  146. package/dist/db/ddl-guard.js +180 -0
  147. package/dist/db/ddl-guard.js.map +1 -0
  148. package/dist/notifications/routes.d.ts +1 -1
  149. package/dist/observability/routes.d.ts +5 -5
  150. package/dist/progress/routes.d.ts +1 -1
  151. package/dist/resources/handlers.d.ts +3 -3
  152. package/dist/secrets/storage.d.ts.map +1 -1
  153. package/dist/secrets/storage.js +26 -2
  154. package/dist/secrets/storage.js.map +1 -1
  155. package/dist/server/agent-engine-api-key-route.d.ts +2 -2
  156. package/dist/server/analytics.d.ts +4 -0
  157. package/dist/server/analytics.d.ts.map +1 -1
  158. package/dist/server/analytics.js +19 -3
  159. package/dist/server/analytics.js.map +1 -1
  160. package/dist/server/transcribe-voice.d.ts +1 -1
  161. package/dist/settings/store.d.ts.map +1 -1
  162. package/dist/settings/store.js +32 -6
  163. package/dist/settings/store.js.map +1 -1
  164. package/dist/sharing/access.d.ts.map +1 -1
  165. package/dist/sharing/access.js +26 -12
  166. package/dist/sharing/access.js.map +1 -1
  167. package/dist/sharing/actions/share-resource.js +20 -9
  168. package/dist/sharing/actions/share-resource.js.map +1 -1
  169. package/dist/sharing/actions/unshare-resource.js +13 -2
  170. package/dist/sharing/actions/unshare-resource.js.map +1 -1
  171. package/dist/sharing/registry.d.ts +9 -0
  172. package/dist/sharing/registry.d.ts.map +1 -1
  173. package/dist/sharing/registry.js.map +1 -1
  174. package/dist/vite/client.d.ts.map +1 -1
  175. package/dist/vite/client.js +1 -0
  176. package/dist/vite/client.js.map +1 -1
  177. package/package.json +3 -3
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-06-25
4
+ ---
5
+
6
+ Create no longer shows agent settings in the main asset chat area after reconnecting AI.
@@ -5,6 +5,7 @@ publish = "templates/assets/dist"
5
5
  functions = "templates/assets/.netlify/functions-internal"
6
6
 
7
7
  [build.environment]
8
+ GA_MEASUREMENT_ID = "G-ESF7FYXGN9"
8
9
  NITRO_PRESET = "netlify"
9
10
  NPM_CONFIG_PRODUCTION = "false"
10
11
 
@@ -5,6 +5,7 @@ publish = "templates/brain/dist"
5
5
  functions = "templates/brain/.netlify/functions-internal"
6
6
 
7
7
  [build.environment]
8
+ GA_MEASUREMENT_ID = "G-ESF7FYXGN9"
8
9
  NITRO_PRESET = "netlify"
9
10
  NPM_CONFIG_PRODUCTION = "false"
10
11
 
@@ -5,6 +5,7 @@ const enUS = {
5
5
  connect: "Connect",
6
6
  connected: "Connected",
7
7
  connecting: "Connecting...",
8
+ clipboardUnavailable: "Clipboard access is unavailable",
8
9
  disconnect: "Disconnect",
9
10
  notConnected: "Not connected",
10
11
  saving: "Saving...",
@@ -3626,6 +3627,7 @@ export const messagesByLocale = {
3626
3627
  connect: "连接",
3627
3628
  connected: "已连接",
3628
3629
  connecting: "正在连接...",
3630
+ clipboardUnavailable: "无法访问剪贴板",
3629
3631
  disconnect: "断开连接",
3630
3632
  notConnected: "未连接",
3631
3633
  saving: "正在保存...",
@@ -3681,6 +3683,7 @@ export const messagesByLocale = {
3681
3683
  connect: "Conectar",
3682
3684
  connected: "Conectado",
3683
3685
  connecting: "Conectando...",
3686
+ clipboardUnavailable: "El acceso al portapapeles no está disponible",
3684
3687
  disconnect: "Desconectar",
3685
3688
  notConnected: "No conectado",
3686
3689
  saving: "Guardando...",
@@ -3737,6 +3740,7 @@ export const messagesByLocale = {
3737
3740
  connect: "Connecter",
3738
3741
  connected: "Connecté",
3739
3742
  connecting: "Connexion...",
3743
+ clipboardUnavailable: "L’accès au presse-papiers n’est pas disponible",
3740
3744
  disconnect: "Déconnecter",
3741
3745
  notConnected: "Non connecté",
3742
3746
  saving: "Enregistrement...",
@@ -3794,6 +3798,8 @@ export const messagesByLocale = {
3794
3798
  connect: "Verbinden",
3795
3799
  connected: "Verbunden",
3796
3800
  connecting: "Verbinden...",
3801
+ clipboardUnavailable:
3802
+ "Zugriff auf die Zwischenablage ist nicht verfügbar",
3797
3803
  disconnect: "Trennen",
3798
3804
  notConnected: "Nicht verbunden",
3799
3805
  saving: "Speichern...",
@@ -3851,6 +3857,7 @@ export const messagesByLocale = {
3851
3857
  connect: "接続",
3852
3858
  connected: "接続済み",
3853
3859
  connecting: "接続中...",
3860
+ clipboardUnavailable: "クリップボードへのアクセスは利用できません",
3854
3861
  disconnect: "切断",
3855
3862
  notConnected: "未接続",
3856
3863
  saving: "保存中...",
@@ -3906,6 +3913,7 @@ export const messagesByLocale = {
3906
3913
  connect: "연결",
3907
3914
  connected: "연결됨",
3908
3915
  connecting: "연결 중...",
3916
+ clipboardUnavailable: "클립보드 접근을 사용할 수 없습니다",
3909
3917
  disconnect: "연결 해제",
3910
3918
  notConnected: "연결되지 않음",
3911
3919
  saving: "저장 중...",
@@ -3961,6 +3969,8 @@ export const messagesByLocale = {
3961
3969
  connect: "Conectar",
3962
3970
  connected: "Conectado",
3963
3971
  connecting: "Conectando...",
3972
+ clipboardUnavailable:
3973
+ "O acesso à área de transferência não está disponível",
3964
3974
  disconnect: "Desconectar",
3965
3975
  notConnected: "Não conectado",
3966
3976
  saving: "Salvando...",
@@ -4017,6 +4027,7 @@ export const messagesByLocale = {
4017
4027
  connect: "कनेक्ट करें",
4018
4028
  connected: "कनेक्टेड",
4019
4029
  connecting: "कनेक्ट कर रहे हैं...",
4030
+ clipboardUnavailable: "क्लिपबोर्ड एक्सेस उपलब्ध नहीं है",
4020
4031
  disconnect: "डिस्कनेक्ट करें",
4021
4032
  notConnected: "कनेक्टेड नहीं",
4022
4033
  saving: "सहेज रहे हैं...",
@@ -4071,6 +4082,7 @@ export const messagesByLocale = {
4071
4082
  connect: "اتصال",
4072
4083
  connected: "متصل",
4073
4084
  connecting: "جارٍ الاتصال...",
4085
+ clipboardUnavailable: "الوصول إلى الحافظة غير متاح",
4074
4086
  disconnect: "قطع الاتصال",
4075
4087
  notConnected: "غير متصل",
4076
4088
  saving: "جارٍ الحفظ...",
@@ -0,0 +1,58 @@
1
+ type ElectronClipboardApi = {
2
+ clipboard?: {
3
+ writeText?: (text: string) => boolean | Promise<boolean>;
4
+ };
5
+ };
6
+
7
+ function getElectronClipboard(): ElectronClipboardApi["clipboard"] | null {
8
+ const api = (
9
+ globalThis as typeof globalThis & {
10
+ electronAPI?: ElectronClipboardApi;
11
+ }
12
+ ).electronAPI;
13
+ return api?.clipboard ?? null;
14
+ }
15
+
16
+ function copyWithExecCommand(text: string): boolean {
17
+ if (typeof document === "undefined" || !document.body) return false;
18
+ const textarea = document.createElement("textarea");
19
+ textarea.value = text;
20
+ textarea.setAttribute("readonly", "");
21
+ textarea.style.position = "fixed";
22
+ textarea.style.left = "-9999px";
23
+ textarea.style.top = "0";
24
+ textarea.style.opacity = "0";
25
+ document.body.appendChild(textarea);
26
+ textarea.select();
27
+ textarea.setSelectionRange(0, text.length);
28
+ try {
29
+ return document.execCommand("copy");
30
+ } catch {
31
+ return false;
32
+ } finally {
33
+ document.body.removeChild(textarea);
34
+ }
35
+ }
36
+
37
+ export async function copyTextToClipboard(text: string): Promise<boolean> {
38
+ const electronClipboard = getElectronClipboard();
39
+ if (electronClipboard?.writeText) {
40
+ try {
41
+ const copied = await electronClipboard.writeText(text);
42
+ if (copied !== false) return true;
43
+ } catch {
44
+ // Fall through to browser clipboard options.
45
+ }
46
+ }
47
+
48
+ if (typeof navigator !== "undefined" && navigator.clipboard?.writeText) {
49
+ try {
50
+ await navigator.clipboard.writeText(text);
51
+ return true;
52
+ } catch {
53
+ // Electron/web embeds can deny clipboard-write even after a click.
54
+ }
55
+ }
56
+
57
+ return copyWithExecCommand(text);
58
+ }
@@ -21,6 +21,7 @@ import {
21
21
  useUpdateAvailability,
22
22
  } from "@/hooks/use-availability";
23
23
  import { useDbStatus } from "@/hooks/use-db-status";
24
+ import { copyTextToClipboard } from "@/lib/clipboard";
24
25
 
25
26
  type DayName = keyof AvailabilityConfig["weeklySchedule"];
26
27
 
@@ -64,6 +65,19 @@ export default function AvailabilitySettings() {
64
65
  const { isLocal } = useDbStatus();
65
66
  const [showCloudUpgrade, setShowCloudUpgrade] = useState(false);
66
67
 
68
+ async function handleCopyBookingLink() {
69
+ if (isLocal) {
70
+ setShowCloudUpgrade(true);
71
+ return;
72
+ }
73
+ const url = `${window.location.origin}/book/${bookingSlug}`;
74
+ if (await copyTextToClipboard(url)) {
75
+ toast.success(t("bookingLinks.bookingLinkCopied"));
76
+ return;
77
+ }
78
+ toast.error(t("common.clipboardUnavailable"));
79
+ }
80
+
67
81
  useEffect(() => {
68
82
  if (availability) {
69
83
  setSchedule(availability.weeklySchedule);
@@ -283,15 +297,7 @@ export default function AvailabilitySettings() {
283
297
  <Button
284
298
  variant="outline"
285
299
  size="sm"
286
- onClick={() => {
287
- if (isLocal) {
288
- setShowCloudUpgrade(true);
289
- return;
290
- }
291
- const url = `${window.location.origin}/book/${bookingSlug}`;
292
- navigator.clipboard.writeText(url);
293
- toast.success(t("bookingLinks.bookingLinkCopied"));
294
- }}
300
+ onClick={() => void handleCopyBookingLink()}
295
301
  >
296
302
  {t("bookingLinks.copyBookingLink")}
297
303
  </Button>
@@ -112,6 +112,7 @@ import {
112
112
  } from "@/hooks/use-booking-links";
113
113
  import { useGoogleAuthStatus } from "@/hooks/use-google-auth";
114
114
  import { useZoomStatus, useConnectZoom } from "@/hooks/use-zoom-auth";
115
+ import { copyTextToClipboard } from "@/lib/clipboard";
115
116
  import { cn } from "@/lib/utils";
116
117
 
117
118
  import BookingsList from "./BookingsList";
@@ -899,8 +900,11 @@ export default function BookingLinksPage({
899
900
  }
900
901
 
901
902
  async function copyPreviewUrl(slug: string) {
902
- await navigator.clipboard.writeText(getBookingUrl(slug));
903
- toast.success(t("bookingLinks.bookingLinkCopied"));
903
+ if (await copyTextToClipboard(getBookingUrl(slug))) {
904
+ toast.success(t("bookingLinks.bookingLinkCopied"));
905
+ return;
906
+ }
907
+ toast.error(t("common.clipboardUnavailable"));
904
908
  }
905
909
 
906
910
  function openPreview(slug: string) {
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-06-25
4
+ ---
5
+
6
+ Booking link copy buttons no longer fail when clipboard permissions are blocked.
@@ -5,6 +5,7 @@ publish = "templates/calendar/dist"
5
5
  functions = "templates/calendar/.netlify/functions-internal"
6
6
 
7
7
  [build.environment]
8
+ GA_MEASUREMENT_ID = "G-ESF7FYXGN9"
8
9
  NITRO_PRESET = "netlify"
9
10
  NPM_CONFIG_PRODUCTION = "false"
10
11
 
@@ -5,5 +5,6 @@ publish = "templates/chat/dist"
5
5
  functions = "templates/chat/.netlify/functions-internal"
6
6
 
7
7
  [build.environment]
8
+ GA_MEASUREMENT_ID = "G-ESF7FYXGN9"
8
9
  NITRO_PRESET = "netlify"
9
10
  NPM_CONFIG_PRODUCTION = "false"
@@ -64,13 +64,15 @@ Detailed media, meeting, dictation, editing, and sharing rules live in
64
64
  - Browser recordings can include redacted browser diagnostics captured during
65
65
  the recording session. `save-browser-diagnostics` is UI/internal and stores
66
66
  bounded console logs plus fetch/XHR method, URL path/query keys, status, and
67
- duration; it never captures headers, bodies, cookies, or query values. Use
68
- `get-recording-player-data` for full diagnostics when you have editor access.
69
- Public agent context exposes the redacted console stream (all levels) as
70
- `browserDiagnostics.consoleLogs` and the fetch/XHR stream as
71
- `browserDiagnostics.networkRequests` (method, sanitized URL with query values
72
- redacted, status, duration), plus `consoleIssues` and `failedNetworkRequests`
73
- highlights. All bounded; page URL, headers, bodies, and cookies stay omitted.
67
+ duration; it never captures headers, bodies, cookies, or network URL query
68
+ values. Console text keeps useful non-secret values while redacting
69
+ credential-looking keys/headers. Use `get-recording-player-data` for full
70
+ diagnostics when you have editor access. Public agent context exposes the
71
+ redacted console stream (all levels) as `browserDiagnostics.consoleLogs` and
72
+ the fetch/XHR stream as `browserDiagnostics.networkRequests` (method,
73
+ sanitized URL with query values redacted, status, duration), plus
74
+ `consoleIssues` and `failedNetworkRequests` highlights. All bounded; page
75
+ URL, headers, bodies, and cookies stay omitted.
74
76
  - The Chrome extension lives in `chrome-extension/`. It launches `/record` with
75
77
  `clipsExtensionId` and `clipsCaptureSessionId`, then the recorder sends
76
78
  `CLIPS_CAPTURE_START/STOP/CANCEL` back to the extension. The extension uses
@@ -21,7 +21,7 @@ import { createError } from "h3";
21
21
  import { z } from "zod";
22
22
 
23
23
  import { getDb, schema } from "../server/db/index.js";
24
- import { nanoid } from "../server/lib/recordings.js";
24
+ import { nanoid, ownerEmailMatches } from "../server/lib/recordings.js";
25
25
 
26
26
  export default defineAction({
27
27
  description:
@@ -66,7 +66,7 @@ export default defineAction({
66
66
  .from(schema.vocabulary)
67
67
  .where(
68
68
  and(
69
- eq(schema.vocabulary.ownerEmail, ownerEmail),
69
+ ownerEmailMatches(schema.vocabulary.ownerEmail, ownerEmail),
70
70
  eq(schema.vocabulary.term, term),
71
71
  ),
72
72
  )
@@ -11,7 +11,10 @@ import { and, eq } from "drizzle-orm";
11
11
  import { z } from "zod";
12
12
 
13
13
  import { getDb, schema } from "../server/db/index.js";
14
- import { getCurrentOwnerEmail } from "../server/lib/recordings.js";
14
+ import {
15
+ getCurrentOwnerEmail,
16
+ ownerEmailMatches,
17
+ } from "../server/lib/recordings.js";
15
18
 
16
19
  export default defineAction({
17
20
  description:
@@ -29,7 +32,7 @@ export default defineAction({
29
32
  .where(
30
33
  and(
31
34
  eq(schema.recordings.id, args.id),
32
- eq(schema.recordings.ownerEmail, ownerEmail),
35
+ ownerEmailMatches(schema.recordings.ownerEmail, ownerEmail),
33
36
  ),
34
37
  );
35
38
  if (!existing) throw new Error(`Recording not found: ${args.id}`);
@@ -17,7 +17,10 @@ import { z } from "zod";
17
17
 
18
18
  import { DEFAULT_EDITS, serializeEdits } from "../app/lib/timestamp-mapping.js";
19
19
  import { getDb, schema } from "../server/db/index.js";
20
- import { getCurrentOwnerEmail } from "../server/lib/recordings.js";
20
+ import {
21
+ getCurrentOwnerEmail,
22
+ ownerEmailMatches,
23
+ } from "../server/lib/recordings.js";
21
24
  import { assertNativeRecordingMedia } from "./lib/native-media.js";
22
25
 
23
26
  export default defineAction({
@@ -36,7 +39,7 @@ export default defineAction({
36
39
  .where(
37
40
  and(
38
41
  eq(schema.recordings.id, args.recordingId),
39
- eq(schema.recordings.ownerEmail, ownerEmail),
42
+ ownerEmailMatches(schema.recordings.ownerEmail, ownerEmail),
40
43
  ),
41
44
  );
42
45
  if (!existing) {
@@ -7,6 +7,7 @@ import { getDb, schema } from "../server/db/index.js";
7
7
  import {
8
8
  getCurrentOwnerEmail,
9
9
  nanoid,
10
+ ownerEmailMatches,
10
11
  requireOrganizationAccess,
11
12
  } from "../server/lib/recordings.js";
12
13
 
@@ -64,7 +65,9 @@ export default defineAction({
64
65
  : isNull(schema.folders.spaceId),
65
66
  ];
66
67
  if (!args.spaceId) {
67
- parentWhereClauses.push(eq(schema.folders.ownerEmail, ownerEmail));
68
+ parentWhereClauses.push(
69
+ ownerEmailMatches(schema.folders.ownerEmail, ownerEmail),
70
+ );
68
71
  }
69
72
  const [parent] = await db
70
73
  .select({ id: schema.folders.id, spaceId: schema.folders.spaceId })
@@ -77,7 +80,9 @@ export default defineAction({
77
80
  // Next position within siblings
78
81
  const whereClauses = [eq(schema.folders.organizationId, organizationId)];
79
82
  if (!args.spaceId) {
80
- whereClauses.push(eq(schema.folders.ownerEmail, ownerEmail));
83
+ whereClauses.push(
84
+ ownerEmailMatches(schema.folders.ownerEmail, ownerEmail),
85
+ );
81
86
  }
82
87
  whereClauses.push(
83
88
  args.spaceId
@@ -4,7 +4,10 @@ import { and, eq, inArray } from "drizzle-orm";
4
4
  import { z } from "zod";
5
5
 
6
6
  import { getDb, schema } from "../server/db/index.js";
7
- import { getCurrentOwnerEmail } from "../server/lib/recordings.js";
7
+ import {
8
+ getCurrentOwnerEmail,
9
+ ownerEmailMatches,
10
+ } from "../server/lib/recordings.js";
8
11
 
9
12
  export default defineAction({
10
13
  description:
@@ -23,7 +26,7 @@ export default defineAction({
23
26
  .where(
24
27
  and(
25
28
  eq(schema.folders.id, args.id),
26
- eq(schema.folders.ownerEmail, ownerEmail),
29
+ ownerEmailMatches(schema.folders.ownerEmail, ownerEmail),
27
30
  ),
28
31
  );
29
32
 
@@ -41,7 +44,7 @@ export default defineAction({
41
44
  .where(
42
45
  and(
43
46
  inArray(schema.folders.parentId, frontier),
44
- eq(schema.folders.ownerEmail, ownerEmail),
47
+ ownerEmailMatches(schema.folders.ownerEmail, ownerEmail),
45
48
  ),
46
49
  );
47
50
  const nextIds = children.map((c) => c.id);
@@ -63,7 +66,7 @@ export default defineAction({
63
66
  .where(
64
67
  and(
65
68
  inArray(schema.folders.id, descendants),
66
- eq(schema.folders.ownerEmail, ownerEmail),
69
+ ownerEmailMatches(schema.folders.ownerEmail, ownerEmail),
67
70
  ),
68
71
  );
69
72
 
@@ -15,7 +15,10 @@ import { and, eq } from "drizzle-orm";
15
15
  import { z } from "zod";
16
16
 
17
17
  import { getDb, schema } from "../server/db/index.js";
18
- import { getCurrentOwnerEmail } from "../server/lib/recordings.js";
18
+ import {
19
+ getCurrentOwnerEmail,
20
+ ownerEmailMatches,
21
+ } from "../server/lib/recordings.js";
19
22
 
20
23
  export default defineAction({
21
24
  description:
@@ -33,7 +36,7 @@ export default defineAction({
33
36
  .where(
34
37
  and(
35
38
  eq(schema.recordings.id, args.id),
36
- eq(schema.recordings.ownerEmail, ownerEmail),
39
+ ownerEmailMatches(schema.recordings.ownerEmail, ownerEmail),
37
40
  ),
38
41
  );
39
42
  if (!existing) throw new Error(`Recording not found: ${args.id}`);
@@ -28,7 +28,10 @@ import {
28
28
  applyFaststart,
29
29
  hasPlayableMp4Metadata,
30
30
  } from "../server/lib/faststart.js";
31
- import { getCurrentOwnerEmail } from "../server/lib/recordings.js";
31
+ import {
32
+ getCurrentOwnerEmail,
33
+ ownerEmailMatches,
34
+ } from "../server/lib/recordings.js";
32
35
  import {
33
36
  requiresConfiguredVideoStorage,
34
37
  STORAGE_SETUP_REQUIRED_REASON,
@@ -151,7 +154,7 @@ export default defineAction({
151
154
  .where(
152
155
  and(
153
156
  eq(schema.recordings.id, id),
154
- eq(schema.recordings.ownerEmail, ownerEmail),
157
+ ownerEmailMatches(schema.recordings.ownerEmail, ownerEmail),
155
158
  ),
156
159
  );
157
160
 
@@ -11,6 +11,7 @@ import { getDb, schema } from "../server/db/index.js";
11
11
  import {
12
12
  getCurrentOwnerEmail,
13
13
  nanoid,
14
+ ownerEmailMatches,
14
15
  parseSpaceIds,
15
16
  requireOrganizationAccess,
16
17
  stringifySpaceIds,
@@ -148,7 +149,7 @@ export default defineAction({
148
149
  .where(
149
150
  and(
150
151
  eq(schema.recordings.id, args.recordingId),
151
- eq(schema.recordings.ownerEmail, ownerEmail),
152
+ ownerEmailMatches(schema.recordings.ownerEmail, ownerEmail),
152
153
  ),
153
154
  );
154
155
  if (!existingRecording) {
@@ -11,11 +11,15 @@
11
11
  */
12
12
 
13
13
  import { defineAction } from "@agent-native/core";
14
- import { and, desc, eq, gte, inArray } from "drizzle-orm";
14
+ import { and, desc, gte, inArray } from "drizzle-orm";
15
15
  import { z } from "zod";
16
16
 
17
17
  import { getDb, schema } from "../server/db/index.js";
18
- import { getCurrentOwnerEmail } from "../server/lib/recordings.js";
18
+ import {
19
+ getCurrentOwnerEmail,
20
+ ownerEmailMatches,
21
+ sameOwnerEmail,
22
+ } from "../server/lib/recordings.js";
19
23
 
20
24
  export default defineAction({
21
25
  description:
@@ -36,7 +40,7 @@ export default defineAction({
36
40
  title: schema.recordings.title,
37
41
  })
38
42
  .from(schema.recordings)
39
- .where(eq(schema.recordings.ownerEmail, me));
43
+ .where(ownerEmailMatches(schema.recordings.ownerEmail, me));
40
44
  if (myRecordings.length === 0) {
41
45
  return { items: [], count: 0 };
42
46
  }
@@ -82,7 +86,7 @@ export default defineAction({
82
86
 
83
87
  const items = [
84
88
  ...comments
85
- .filter((c) => c.authorEmail !== me)
89
+ .filter((c) => !sameOwnerEmail(c.authorEmail, me))
86
90
  .map((c) => ({
87
91
  id: `c:${c.id}`,
88
92
  kind: (mentionRegex.test(c.content) ? "mention" : "comment") as
@@ -95,7 +99,7 @@ export default defineAction({
95
99
  createdAt: c.createdAt,
96
100
  })),
97
101
  ...reactions
98
- .filter((r) => r.viewerEmail !== me)
102
+ .filter((r) => !sameOwnerEmail(r.viewerEmail, me))
99
103
  .map((r) => ({
100
104
  id: `r:${r.id}`,
101
105
  kind: "reaction" as const,
@@ -20,6 +20,7 @@ import { z } from "zod";
20
20
  import { getDb, schema } from "../server/db/index.js";
21
21
  import {
22
22
  getCurrentOwnerEmail,
23
+ ownerEmailMatches,
23
24
  requireOrganizationAccess,
24
25
  } from "../server/lib/recordings.js";
25
26
 
@@ -128,7 +129,7 @@ export default defineAction({
128
129
  eq(schema.folders.organizationId, organizationId),
129
130
  or(
130
131
  isNotNull(schema.folders.spaceId),
131
- eq(schema.folders.ownerEmail, ownerEmail),
132
+ ownerEmailMatches(schema.folders.ownerEmail, ownerEmail),
132
133
  ),
133
134
  ),
134
135
  )
@@ -17,6 +17,7 @@ import { z } from "zod";
17
17
  import { getDb, schema } from "../server/db/index.js";
18
18
  import {
19
19
  getActiveOrganizationId,
20
+ ownerEmailMatches,
20
21
  parseSpaceIds,
21
22
  } from "../server/lib/recordings.js";
22
23
 
@@ -82,7 +83,9 @@ export default defineAction({
82
83
  if (args.view === "library") {
83
84
  const email = getRequestUserEmail();
84
85
  if (email) {
85
- whereClauses.push(eq(schema.recordings.ownerEmail, email));
86
+ whereClauses.push(
87
+ ownerEmailMatches(schema.recordings.ownerEmail, email),
88
+ );
86
89
  }
87
90
  if (orgId) {
88
91
  whereClauses.push(eq(schema.recordings.organizationId, orgId));
@@ -9,6 +9,7 @@ import {
9
9
  getCurrentOwnerEmail,
10
10
  parseSpaceIds,
11
11
  requireActiveOrganizationId,
12
+ sameOwnerEmail,
12
13
  } from "../server/lib/recordings.js";
13
14
 
14
15
  const moveRecordingSchema = z
@@ -69,7 +70,10 @@ export default defineAction({
69
70
  )
70
71
  .limit(1);
71
72
 
72
- if (!folder || (!folder.spaceId && folder.ownerEmail !== ownerEmail)) {
73
+ if (
74
+ !folder ||
75
+ (!folder.spaceId && !sameOwnerEmail(folder.ownerEmail, ownerEmail))
76
+ ) {
73
77
  throw new Error(`Folder not found: ${folderId}`);
74
78
  }
75
79
 
@@ -4,7 +4,10 @@ import { and, eq } from "drizzle-orm";
4
4
  import { z } from "zod";
5
5
 
6
6
  import { getDb, schema } from "../server/db/index.js";
7
- import { getCurrentOwnerEmail } from "../server/lib/recordings.js";
7
+ import {
8
+ getCurrentOwnerEmail,
9
+ ownerEmailMatches,
10
+ } from "../server/lib/recordings.js";
8
11
 
9
12
  export default defineAction({
10
13
  description: "Rename a folder.",
@@ -22,7 +25,7 @@ export default defineAction({
22
25
  .where(
23
26
  and(
24
27
  eq(schema.folders.id, args.id),
25
- eq(schema.folders.ownerEmail, ownerEmail),
28
+ ownerEmailMatches(schema.folders.ownerEmail, ownerEmail),
26
29
  ),
27
30
  );
28
31
 
@@ -36,7 +39,7 @@ export default defineAction({
36
39
  .where(
37
40
  and(
38
41
  eq(schema.folders.id, args.id),
39
- eq(schema.folders.ownerEmail, ownerEmail),
42
+ ownerEmailMatches(schema.folders.ownerEmail, ownerEmail),
40
43
  ),
41
44
  );
42
45
 
@@ -50,7 +50,10 @@ import { and, eq } from "drizzle-orm";
50
50
  import { z } from "zod";
51
51
 
52
52
  import { getDb, schema } from "../server/db/index.js";
53
- import { getCurrentOwnerEmail } from "../server/lib/recordings.js";
53
+ import {
54
+ getCurrentOwnerEmail,
55
+ ownerEmailMatches,
56
+ } from "../server/lib/recordings.js";
54
57
  import { normalizeLoomShareUrl } from "../shared/loom.js";
55
58
  import {
56
59
  buildCaptionSegmentsFromText,
@@ -574,7 +577,7 @@ async function completeReadyTranscript({
574
577
  .where(
575
578
  and(
576
579
  eq(schema.recordings.id, recordingId),
577
- eq(schema.recordings.ownerEmail, ownerEmail),
580
+ ownerEmailMatches(schema.recordings.ownerEmail, ownerEmail),
578
581
  ),
579
582
  )
580
583
  .limit(1);
@@ -11,7 +11,10 @@ import { and, eq } from "drizzle-orm";
11
11
  import { z } from "zod";
12
12
 
13
13
  import { getDb, schema } from "../server/db/index.js";
14
- import { getCurrentOwnerEmail } from "../server/lib/recordings.js";
14
+ import {
15
+ getCurrentOwnerEmail,
16
+ ownerEmailMatches,
17
+ } from "../server/lib/recordings.js";
15
18
 
16
19
  export default defineAction({
17
20
  description: "Restore a recording from archive or trash back to the library.",
@@ -28,7 +31,7 @@ export default defineAction({
28
31
  .where(
29
32
  and(
30
33
  eq(schema.recordings.id, args.id),
31
- eq(schema.recordings.ownerEmail, ownerEmail),
34
+ ownerEmailMatches(schema.recordings.ownerEmail, ownerEmail),
32
35
  ),
33
36
  );
34
37
  if (!existing) throw new Error(`Recording not found: ${args.id}`);