It's empty here
diff --git a/apps/mail/components/ui/ai-sidebar.tsx b/apps/mail/components/ui/ai-sidebar.tsx
index 2fce4311f3..b14b3c3628 100644
--- a/apps/mail/components/ui/ai-sidebar.tsx
+++ b/apps/mail/components/ui/ai-sidebar.tsx
@@ -348,11 +348,10 @@ function AISidebar({ className }: AISidebarProps) {
const { isPro, track, refetch: refetchBilling } = useBilling();
const queryClient = useQueryClient();
const trpc = useTRPC();
- const [threadId, setThreadId] = useQueryState('threadId');
+ const [threadId] = useQueryState('threadId');
const { folder } = useParams<{ folder: string }>();
const { refetch: refetchLabels } = useLabels();
const [searchValue] = useSearchValue();
- const { data: session } = useSession();
const { data: activeConnection } = useActiveConnection();
const agent = useAgent({
@@ -363,7 +362,6 @@ function AISidebar({ className }: AISidebarProps) {
const chatState = useAgentChat({
agent,
- initialMessages: [],
maxSteps: 5,
body: {
threadId: threadId ?? undefined,
diff --git a/apps/mail/components/ui/app-sidebar.tsx b/apps/mail/components/ui/app-sidebar.tsx
index a598f375c8..11548f688d 100644
--- a/apps/mail/components/ui/app-sidebar.tsx
+++ b/apps/mail/components/ui/app-sidebar.tsx
@@ -157,7 +157,7 @@ export function AppSidebar({ ...props }: React.ComponentProps) {
className="mt-3 inline-flex h-7 w-full items-center justify-center gap-0.5 overflow-hidden rounded-lg bg-[#8B5CF6] px-2"
>
-
diff --git a/apps/mail/components/ui/nav-user.tsx b/apps/mail/components/ui/nav-user.tsx
index 9f558cd7ea..4b35d91960 100644
--- a/apps/mail/components/ui/nav-user.tsx
+++ b/apps/mail/components/ui/nav-user.tsx
@@ -152,7 +152,7 @@ export function NavUser() {
success: () => 'Signed out successfully!',
error: 'Error signing out',
async finally() {
- await handleClearCache();
+ // await handleClearCache();
window.location.href = '/login';
},
});
diff --git a/apps/mail/hooks/use-compose-editor.ts b/apps/mail/hooks/use-compose-editor.ts
index 71d0c3b79a..7852d75e4a 100644
--- a/apps/mail/hooks/use-compose-editor.ts
+++ b/apps/mail/hooks/use-compose-editor.ts
@@ -1,6 +1,7 @@
import { useEditor, type KeyboardShortcutCommand, Extension, generateJSON } from '@tiptap/react';
import { AutoComplete } from '@/components/create/editor-autocomplete';
import { defaultExtensions } from '@/components/create/extensions';
+import Emoji, { gitHubEmojis } from '@tiptap/extension-emoji';
import { FileHandler } from '@tiptap/extension-file-handler';
import Placeholder from '@tiptap/extension-placeholder';
import { Plugin, PluginKey } from '@tiptap/pm/state';
@@ -258,6 +259,11 @@ const useComposeEditor = ({
Placeholder.configure({
placeholder,
}),
+ Emoji.configure({
+ emojis: gitHubEmojis,
+ enableEmoticons: true,
+ // suggestion,
+ }),
// breaks the image upload
// ...(onAttachmentsChange
// ? [
diff --git a/apps/mail/hooks/use-connections.ts b/apps/mail/hooks/use-connections.ts
index 2242e0e386..999f4f0323 100644
--- a/apps/mail/hooks/use-connections.ts
+++ b/apps/mail/hooks/use-connections.ts
@@ -9,6 +9,14 @@ export const useConnections = () => {
export const useActiveConnection = () => {
const trpc = useTRPC();
- const connectionsQuery = useQuery(trpc.connections.getDefault.queryOptions());
+ const connectionsQuery = useQuery(
+ trpc.connections.getDefault.queryOptions(void 0, {
+ staleTime: 1000 * 60 * 60, // 1 hour,
+ gcTime: 1000 * 60 * 60 * 24, // 24 hours
+ refetchOnWindowFocus: false,
+ refetchOnMount: false,
+ refetchOnReconnect: false,
+ }),
+ );
return connectionsQuery;
};
diff --git a/apps/mail/hooks/use-threads.ts b/apps/mail/hooks/use-threads.ts
index f524701597..a9877373da 100644
--- a/apps/mail/hooks/use-threads.ts
+++ b/apps/mail/hooks/use-threads.ts
@@ -69,8 +69,8 @@ export const useThread = (threadId: string | null, historyId?: string | null) =>
const [_threadId] = useQueryState('threadId');
const id = threadId ? threadId : _threadId;
const trpc = useTRPC();
- const { data } = useSettings();
- const { resolvedTheme } = useTheme();
+ // const { data } = useSettings();
+ // const { resolvedTheme } = useTheme();
const previousHistoryId = usePrevious(historyId ?? null);
const queryClient = useQueryClient();
@@ -92,44 +92,44 @@ export const useThread = (threadId: string | null, historyId?: string | null) =>
),
);
- const isTrustedSender = useMemo(
- () =>
- !!data?.settings?.externalImages ||
- !!data?.settings?.trustedSenders?.includes(threadQuery.data?.latest?.sender.email ?? ''),
- [data?.settings, threadQuery.data?.latest?.sender.email],
- );
+ // const isTrustedSender = useMemo(
+ // () =>
+ // !!data?.settings?.externalImages ||
+ // !!data?.settings?.trustedSenders?.includes(threadQuery.data?.latest?.sender.email ?? ''),
+ // [data?.settings, threadQuery.data?.latest?.sender.email],
+ // );
const latestDraft = useMemo(() => {
if (!threadQuery.data?.latest?.id) return undefined;
return threadQuery.data.messages.findLast((e) => e.isDraft);
}, [threadQuery]);
- const { mutateAsync: processEmailContent } = useMutation(
- trpc.mail.processEmailContent.mutationOptions(),
- );
-
- const prefetchEmailContent = async (message: ParsedMessage) => {
- return queryClient.prefetchQuery({
- queryKey: ['email-content', message.id, isTrustedSender, resolvedTheme],
- queryFn: async () => {
- const result = await processEmailContent({
- html: message.decodedBody ?? '',
- shouldLoadImages: isTrustedSender,
- theme: (resolvedTheme as 'light' | 'dark') || 'light',
- });
-
- return {
- html: result.processedHtml,
- hasBlockedImages: result.hasBlockedImages,
- };
- },
- });
- };
-
- useEffect(() => {
- if (!threadQuery.data?.latest?.id) return;
- prefetchEmailContent(threadQuery.data.latest);
- }, [threadQuery.data?.latest]);
+ // const { mutateAsync: processEmailContent } = useMutation(
+ // trpc.mail.processEmailContent.mutationOptions(),
+ // );
+
+ // const prefetchEmailContent = async (message: ParsedMessage) => {
+ // return queryClient.prefetchQuery({
+ // queryKey: ['email-content', message.id, isTrustedSender, resolvedTheme],
+ // queryFn: async () => {
+ // const result = await processEmailContent({
+ // html: message.decodedBody ?? '',
+ // shouldLoadImages: isTrustedSender,
+ // theme: (resolvedTheme as 'light' | 'dark') || 'light',
+ // });
+
+ // return {
+ // html: result.processedHtml,
+ // hasBlockedImages: result.hasBlockedImages,
+ // };
+ // },
+ // });
+ // };
+
+ // useEffect(() => {
+ // if (!threadQuery.data?.latest?.id) return;
+ // prefetchEmailContent(threadQuery.data.latest);
+ // }, [threadQuery.data?.latest]);
const isGroupThread = useMemo(() => {
if (!threadQuery.data?.latest?.id) return false;
diff --git a/apps/mail/lib/email-utils.ts b/apps/mail/lib/email-utils.ts
index af84480ded..5ef6683b55 100644
--- a/apps/mail/lib/email-utils.ts
+++ b/apps/mail/lib/email-utils.ts
@@ -1,5 +1,6 @@
import * as emailAddresses from 'email-addresses';
import type { Sender } from '@/types';
+import DOMPurify from 'dompurify';
import Color from 'color';
export const fixNonReadableColors = (
@@ -207,3 +208,15 @@ export const wasSentWithTLS = (receivedHeaders: string[]) => {
return false;
};
+
+// cleans up html string for xss attacks and returns html
+export const cleanHtml = (html: string) => {
+ if (!html) return '
No email content available
';
+
+ try {
+ return DOMPurify.sanitize(html);
+ } catch (error) {
+ console.warn('DOMPurify Failed or not Available, falling back to Default HTML ', error);
+ return '
No email content available
';
+ }
+};
diff --git a/apps/mail/lib/trpc.server.ts b/apps/mail/lib/trpc.server.ts
index 6210a468ac..78a5b127a7 100644
--- a/apps/mail/lib/trpc.server.ts
+++ b/apps/mail/lib/trpc.server.ts
@@ -8,7 +8,7 @@ export const getServerTrpc = (req: Request) =>
createTRPCClient
({
links: [
httpBatchLink({
- maxItems: 8,
+ maxItems: 1,
url: getUrl(),
transformer: superjson,
headers: req.headers,
diff --git a/apps/mail/locales.ts b/apps/mail/locales.ts
new file mode 100644
index 0000000000..98c280f558
--- /dev/null
+++ b/apps/mail/locales.ts
@@ -0,0 +1,177 @@
+export const locales = {
+ en: 'English',
+ ar: 'Arabic',
+ ca: 'Catalan',
+ cs: 'Czech',
+ de: 'German',
+ es: 'Spanish',
+ fr: 'French',
+ hi: 'Hindi',
+ nl: 'Dutch',
+ ja: 'Japanese',
+ ko: 'Korean',
+ lv: 'Latvian',
+ pl: 'Polish',
+ pt: 'Portuguese',
+ ru: 'Russian',
+ tr: 'Turkish',
+ hu: 'Hungarian',
+ fa: 'Persian',
+ vi: 'Vietnamese',
+ 'zh-CN': 'Chinese (Simplified)',
+ 'zh-TW': 'Chinese (Traditional)',
+ af: 'Afrikaans',
+ sq: 'Albanian',
+ am: 'Amharic',
+ hy: 'Armenian',
+ az: 'Azerbaijani',
+ eu: 'Basque',
+ be: 'Belarusian',
+ bn: 'Bengali',
+ bs: 'Bosnian',
+ bg: 'Bulgarian',
+ hr: 'Croatian',
+ da: 'Danish',
+ fi: 'Finnish',
+ gl: 'Galician',
+ ka: 'Georgian',
+ el: 'Greek',
+ gu: 'Gujarati',
+ ht: 'Haitian Creole',
+ ha: 'Hausa',
+ he: 'Hebrew',
+ is: 'Icelandic',
+ ig: 'Igbo',
+ id: 'Indonesian',
+ ga: 'Irish',
+ it: 'Italian',
+ jv: 'Javanese',
+ kn: 'Kannada',
+ kk: 'Kazakh',
+ km: 'Khmer',
+ rw: 'Kinyarwanda',
+ ku: 'Kurdish',
+ ky: 'Kyrgyz',
+ la: 'Latin',
+ lt: 'Lithuanian',
+ lb: 'Luxembourgish',
+ mk: 'Macedonian',
+ mg: 'Malagasy',
+ ms: 'Malay',
+ ml: 'Malayalam',
+ mt: 'Maltese',
+ mi: 'Maori',
+ mr: 'Marathi',
+ mn: 'Mongolian',
+ ne: 'Nepali',
+ nb: 'Norwegian Bokmål',
+ nn: 'Norwegian Nynorsk',
+ or: 'Odia',
+ ps: 'Pashto',
+ pa: 'Punjabi',
+ ro: 'Romanian',
+ sm: 'Samoan',
+ gd: 'Scottish Gaelic',
+ sr: 'Serbian',
+ st: 'Sesotho',
+ sn: 'Shona',
+ sd: 'Sindhi',
+ si: 'Sinhala',
+ sk: 'Slovak',
+ sl: 'Slovenian',
+ so: 'Somali',
+ su: 'Sundanese',
+ sw: 'Swahili',
+ sv: 'Swedish',
+ tl: 'Tagalog',
+ tg: 'Tajik',
+ ta: 'Tamil',
+ tt: 'Tatar',
+ te: 'Telugu',
+ th: 'Thai',
+ ti: 'Tigrinya',
+ to: 'Tongan',
+ tk: 'Turkmen',
+ uk: 'Ukrainian',
+ ur: 'Urdu',
+ ug: 'Uyghur',
+ uz: 'Uzbek',
+ cy: 'Welsh',
+ fy: 'Western Frisian',
+ xh: 'Xhosa',
+ yi: 'Yiddish',
+ yo: 'Yoruba',
+ zu: 'Zulu',
+ fil: 'Filipino',
+ dv: 'Divehi',
+ eo: 'Esperanto',
+ et: 'Estonian',
+ fo: 'Faroese',
+ fj: 'Fijian',
+ gsw: 'Swiss German',
+ haw: 'Hawaiian',
+ kl: 'Greenlandic',
+ ln: 'Lingala',
+ mh: 'Marshallese',
+ nv: 'Navajo',
+ ny: 'Chichewa',
+ qu: 'Quechua',
+ rap: 'Rapa Nui',
+ tvl: 'Tuvaluan',
+ war: 'Waray',
+ wo: 'Wolof',
+ ts: 'Tsonga',
+ tn: 'Tswana',
+ ve: 'Venda',
+ vo: 'Volapük',
+ wa: 'Walloon',
+ chr: 'Cherokee',
+ iu: 'Inuktitut',
+ oj: 'Ojibwe',
+ cr: 'Cree',
+ lo: 'Lao',
+ my: 'Burmese',
+ dz: 'Dzongkha',
+ bm: 'Bambara',
+ ee: 'Ewe',
+ ff: 'Fulah',
+ ki: 'Kikuyu',
+ lg: 'Ganda',
+ nd: 'North Ndebele',
+ nr: 'South Ndebele',
+ nso: 'Northern Sotho',
+ om: 'Oromo',
+ rn: 'Rundi',
+ sg: 'Sango',
+ ss: 'Swati',
+ ak: 'Akan',
+ tw: 'Twi',
+ bh: 'Bihari',
+ gn: 'Guarani',
+ ay: 'Aymara',
+ co: 'Corsican',
+ io: 'Ido',
+ ii: 'Sichuan Yi',
+ kw: 'Cornish',
+ li: 'Limburgish',
+ oc: 'Occitan',
+ os: 'Ossetic',
+ se: 'Northern Sami',
+ sc: 'Sardinian',
+ za: 'Zhuang',
+ kab: 'Kabyle',
+ ber: 'Berber',
+ an: 'Aragonese',
+ ast: 'Asturian',
+ br: 'Breton',
+ ckb: 'Central Kurdish',
+ cv: 'Chuvash',
+ mzn: 'Mazanderani',
+ pms: 'Piedmontese',
+ sah: 'Sakha',
+ szl: 'Silesian',
+ tcy: 'Tulu',
+ vec: 'Venetian',
+ wuu: 'Wu Chinese',
+ yue: 'Cantonese',
+};
diff --git a/apps/mail/messages/ar.json b/apps/mail/messages/ar.json
index f84e448423..03a72e62f3 100644
--- a/apps/mail/messages/ar.json
+++ b/apps/mail/messages/ar.json
@@ -401,6 +401,7 @@
"spam": "البريد المزعج",
"archive": "الأرشيف",
"bin": "سلة المحذوفات",
+ "livesupport": "الدعم المباشر",
"feedback": "الملاحظات",
"settings": "الإعدادات",
"voice": "المساعد الصوتي"
diff --git a/apps/mail/messages/ca.json b/apps/mail/messages/ca.json
index 9dc677cd6b..5be164ca3f 100644
--- a/apps/mail/messages/ca.json
+++ b/apps/mail/messages/ca.json
@@ -401,6 +401,7 @@
"spam": "Contingut no desitjat",
"archive": "Arxivats",
"bin": "Paperera",
+ "livesupport": "Suport en directe",
"feedback": "Feedback",
"settings": "Configuració",
"voice": "Assistent de veu"
diff --git a/apps/mail/messages/cs.json b/apps/mail/messages/cs.json
index 939f3fefe0..a3514b9255 100644
--- a/apps/mail/messages/cs.json
+++ b/apps/mail/messages/cs.json
@@ -401,6 +401,7 @@
"spam": "Nevyžádaná pošta",
"archive": "Archiv",
"bin": "Odstraněná pošta",
+ "livesupport": "Živá podpora",
"feedback": "Zpětná vazba",
"settings": "Nastavení",
"voice": "Hlasový asistent"
diff --git a/apps/mail/messages/de.json b/apps/mail/messages/de.json
index 42793938a0..c52575fb44 100644
--- a/apps/mail/messages/de.json
+++ b/apps/mail/messages/de.json
@@ -401,6 +401,7 @@
"spam": "Spam",
"archive": "Archiv",
"bin": "Papierkorb",
+ "livesupport": "Live-Support",
"feedback": "Rückmeldung",
"settings": "Einstellungen",
"voice": "Sprachassistent"
diff --git a/apps/mail/messages/en.json b/apps/mail/messages/en.json
index 6aaacb8baa..98c8a2fb9e 100644
--- a/apps/mail/messages/en.json
+++ b/apps/mail/messages/en.json
@@ -401,6 +401,7 @@
"spam": "Spam",
"archive": "Archive",
"bin": "Bin",
+ "livesupport": "Live Support",
"feedback": "Feedback",
"settings": "Settings",
"voice": "Voice Assistant"
diff --git a/apps/mail/messages/es.json b/apps/mail/messages/es.json
index 7f7b466df3..4d28272c47 100644
--- a/apps/mail/messages/es.json
+++ b/apps/mail/messages/es.json
@@ -401,6 +401,7 @@
"spam": "Spam",
"archive": "Archivados",
"bin": "Papelera de reciclaje",
+ "livesupport": "Soporte en vivo",
"feedback": "Sugerencias",
"settings": "Configuración",
"voice": "Asistente de voz"
diff --git a/apps/mail/messages/fa.json b/apps/mail/messages/fa.json
index 6a9ce00e78..e806099f06 100644
--- a/apps/mail/messages/fa.json
+++ b/apps/mail/messages/fa.json
@@ -401,6 +401,7 @@
"spam": "هرزنامه",
"archive": "آرشیو",
"bin": "سطل زباله",
+ "livesupport": "پشتیبانی زنده",
"feedback": "بازخورد",
"settings": "تنظیمات",
"voice": "دستیار صوتی"
diff --git a/apps/mail/messages/fr.json b/apps/mail/messages/fr.json
index 123cc97f34..488c979680 100644
--- a/apps/mail/messages/fr.json
+++ b/apps/mail/messages/fr.json
@@ -401,6 +401,7 @@
"spam": "Pourriels",
"archive": "Archives",
"bin": "Corbeille",
+ "livesupport": "Support en direct",
"feedback": "Vos commentaires",
"settings": "Paramètres",
"voice": "Assistant vocal"
diff --git a/apps/mail/messages/hi.json b/apps/mail/messages/hi.json
index a0bb813c6e..5eac04d0e7 100644
--- a/apps/mail/messages/hi.json
+++ b/apps/mail/messages/hi.json
@@ -401,7 +401,8 @@
"spam": "स्पैम",
"archive": "आर्काइव",
"bin": "बिन",
- "feedback": "Feedback",
+ "livesupport": "लाइव सपोर्ट",
+ "feedback": "प्रतिक्रिया",
"settings": "सेटिंग्स",
"voice": "वॉइस असिस्टेंट"
},
diff --git a/apps/mail/messages/hu.json b/apps/mail/messages/hu.json
index e2af343132..4b3c028aba 100644
--- a/apps/mail/messages/hu.json
+++ b/apps/mail/messages/hu.json
@@ -401,6 +401,7 @@
"spam": "Spam",
"archive": "Archívum",
"bin": "Lomtár",
+ "livesupport": "Élő támogatás",
"feedback": "Visszajelzés",
"settings": "Beállítások",
"voice": "Hangasszisztens"
diff --git a/apps/mail/messages/ja.json b/apps/mail/messages/ja.json
index a14e6e4b03..41d3d32a1e 100644
--- a/apps/mail/messages/ja.json
+++ b/apps/mail/messages/ja.json
@@ -401,6 +401,7 @@
"spam": "迷惑メール",
"archive": "アーカイブ",
"bin": "ごみ箱",
+ "livesupport": "ライブサポート",
"feedback": "フィードバック",
"settings": "設定",
"voice": "音声アシスタント"
diff --git a/apps/mail/messages/ko.json b/apps/mail/messages/ko.json
index c2550440b6..e4fa26eef8 100644
--- a/apps/mail/messages/ko.json
+++ b/apps/mail/messages/ko.json
@@ -401,6 +401,7 @@
"spam": "스팸",
"archive": "보관함",
"bin": "휴지통",
+ "livesupport": "실시간 지원",
"feedback": "피드백",
"settings": "설정",
"voice": "음성 비서"
diff --git a/apps/mail/messages/lv.json b/apps/mail/messages/lv.json
index 340796a12f..6e6f622af7 100644
--- a/apps/mail/messages/lv.json
+++ b/apps/mail/messages/lv.json
@@ -401,6 +401,7 @@
"spam": "Mēstules",
"archive": "Arhīvs",
"bin": "Miskaste",
+ "livesupport": "Tiešsaistes atbalsts",
"feedback": "Atsauksmes",
"settings": "Iestatījumi",
"voice": "Balss asistents"
diff --git a/apps/mail/messages/nl.json b/apps/mail/messages/nl.json
index 836138b47f..9c099e23c5 100644
--- a/apps/mail/messages/nl.json
+++ b/apps/mail/messages/nl.json
@@ -401,6 +401,7 @@
"spam": "Spam",
"archive": "Archief",
"bin": "Prullenbak",
+ "livesupport": "Live ondersteuning",
"feedback": "Feedback",
"settings": "Instellingen",
"voice": "Spraakassistent"
diff --git a/apps/mail/messages/pl.json b/apps/mail/messages/pl.json
index 8682ba4f14..7f509df2e0 100644
--- a/apps/mail/messages/pl.json
+++ b/apps/mail/messages/pl.json
@@ -401,6 +401,7 @@
"spam": "Spam",
"archive": "Archiwum",
"bin": "Kosz",
+ "livesupport": "Wsparcie na żywo",
"feedback": "Opinie",
"settings": "Ustawienia",
"voice": "Asystent głosowy"
diff --git a/apps/mail/messages/pt.json b/apps/mail/messages/pt.json
index 61ea4190ff..fcf438dcbe 100644
--- a/apps/mail/messages/pt.json
+++ b/apps/mail/messages/pt.json
@@ -401,6 +401,7 @@
"spam": "Spam",
"archive": "Arquivados",
"bin": "Lixeira",
+ "livesupport": "Suporte ao vivo",
"feedback": "Feedback",
"settings": "Configurações",
"voice": "Assistente de voz"
diff --git a/apps/mail/messages/ru.json b/apps/mail/messages/ru.json
index 5f391841e1..e2c5bb0e81 100644
--- a/apps/mail/messages/ru.json
+++ b/apps/mail/messages/ru.json
@@ -401,6 +401,7 @@
"spam": "Спам",
"archive": "Архив",
"bin": "Корзина",
+ "livesupport": "Поддержка в реальном времени",
"feedback": "Отзывы",
"settings": "Настройки",
"voice": "Голосовой помощник"
diff --git a/apps/mail/messages/tr.json b/apps/mail/messages/tr.json
index 33c2e87491..238b3039ae 100644
--- a/apps/mail/messages/tr.json
+++ b/apps/mail/messages/tr.json
@@ -401,6 +401,7 @@
"spam": "İstenmeyen E-posta",
"archive": "Arşiv",
"bin": "Çöp",
+ "livesupport": "Canlı Destek",
"feedback": "Geribildirim",
"settings": "Ayarlar",
"voice": "Sesli Asistan"
diff --git a/apps/mail/messages/vi.json b/apps/mail/messages/vi.json
index 00b4007ed1..d95ebba7b4 100644
--- a/apps/mail/messages/vi.json
+++ b/apps/mail/messages/vi.json
@@ -401,6 +401,7 @@
"spam": "Thư rác",
"archive": "Lưu trữ",
"bin": "Thùng rác",
+ "livesupport": "Hỗ trợ trực tuyến",
"feedback": "Phản hồi",
"settings": "Cài đặt",
"voice": "Trợ lý giọng nói"
diff --git a/apps/mail/messages/zh_CN.json b/apps/mail/messages/zh_CN.json
index b96166f41b..af8d4353a1 100644
--- a/apps/mail/messages/zh_CN.json
+++ b/apps/mail/messages/zh_CN.json
@@ -401,6 +401,7 @@
"spam": "垃圾邮件",
"archive": "存档",
"bin": "回收站",
+ "livesupport": "在线支持",
"feedback": "反馈",
"settings": "设置",
"voice": "语音助手"
diff --git a/apps/mail/messages/zh_TW.json b/apps/mail/messages/zh_TW.json
index 44b61ebf7a..f412931ac7 100644
--- a/apps/mail/messages/zh_TW.json
+++ b/apps/mail/messages/zh_TW.json
@@ -401,6 +401,7 @@
"spam": "垃圾郵件",
"archive": "封存",
"bin": "垃圾桶",
+ "livesupport": "即時支援",
"feedback": "意見反饋",
"settings": "設定",
"voice": "語音助理"
diff --git a/apps/mail/package.json b/apps/mail/package.json
index d433fa75be..bd8ddb349d 100644
--- a/apps/mail/package.json
+++ b/apps/mail/package.json
@@ -35,6 +35,7 @@
"@tiptap/core": "2.23.0",
"@tiptap/extension-bold": "2.23.0",
"@tiptap/extension-document": "2.23.0",
+ "@tiptap/extension-emoji": "2.23.1",
"@tiptap/extension-file-handler": "2.23.0",
"@tiptap/extension-image": "2.23.0",
"@tiptap/extension-link": "2.23.0",
diff --git a/apps/mail/providers/query-provider.tsx b/apps/mail/providers/query-provider.tsx
index 0e498c1789..2c0f429955 100644
--- a/apps/mail/providers/query-provider.tsx
+++ b/apps/mail/providers/query-provider.tsx
@@ -90,7 +90,7 @@ export const trpcClient = createTRPCClient({
transformer: superjson,
url: getUrl(),
methodOverride: 'POST',
- maxItems: 8,
+ maxItems: 1,
fetch: (url, options) =>
fetch(url, { ...options, credentials: 'include' }).then((res) => {
const currentPath = new URL(window.location.href).pathname;
diff --git a/apps/server/package.json b/apps/server/package.json
index 4bf3f70f06..ee6834eda4 100644
--- a/apps/server/package.json
+++ b/apps/server/package.json
@@ -24,6 +24,7 @@
"@ai-sdk/openai": "^1.3.21",
"@ai-sdk/perplexity": "1.1.9",
"@ai-sdk/ui-utils": "1.2.11",
+ "@arcadeai/arcadejs": "1.8.1",
"@coinbase/cookie-manager": "1.1.8",
"@googleapis/gmail": "12.0.0",
"@googleapis/people": "3.0.9",
@@ -56,6 +57,7 @@
"hono-party": "^0.0.12",
"jose": "6.0.11",
"jsonrepair": "^3.12.0",
+ "mime-types": "3.0.1",
"mimetext": "^3.0.27",
"p-retry": "6.2.1",
"partyserver": "^0.0.71",
@@ -67,10 +69,9 @@
"string-strip-html": "^13.4.12",
"superjson": "catalog:",
"twilio": "5.7.0",
- "wrangler": "catalog:",
- "zod": "catalog:",
"uuid": "11.1.0",
- "mime-types": "3.0.1"
+ "wrangler": "catalog:",
+ "zod": "catalog:"
},
"devDependencies": {
"@types/he": "1.2.3",
diff --git a/apps/server/src/db/migrations/0035_uneven_shiva.sql b/apps/server/src/db/migrations/0035_uneven_shiva.sql
new file mode 100644
index 0000000000..86335fc541
--- /dev/null
+++ b/apps/server/src/db/migrations/0035_uneven_shiva.sql
@@ -0,0 +1,46 @@
+ALTER TABLE "mail0_account" DROP CONSTRAINT "mail0_account_user_id_mail0_user_id_fk";
+--> statement-breakpoint
+ALTER TABLE "mail0_connection" DROP CONSTRAINT "mail0_connection_user_id_mail0_user_id_fk";
+--> statement-breakpoint
+ALTER TABLE "mail0_session" DROP CONSTRAINT "mail0_session_user_id_mail0_user_id_fk";
+--> statement-breakpoint
+ALTER TABLE "mail0_user_hotkeys" DROP CONSTRAINT "mail0_user_hotkeys_user_id_mail0_user_id_fk";
+--> statement-breakpoint
+ALTER TABLE "mail0_user_settings" DROP CONSTRAINT "mail0_user_settings_user_id_mail0_user_id_fk";
+--> statement-breakpoint
+ALTER TABLE "mail0_account" ADD CONSTRAINT "mail0_account_user_id_mail0_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."mail0_user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
+ALTER TABLE "mail0_connection" ADD CONSTRAINT "mail0_connection_user_id_mail0_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."mail0_user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
+ALTER TABLE "mail0_session" ADD CONSTRAINT "mail0_session_user_id_mail0_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."mail0_user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
+ALTER TABLE "mail0_summary" ADD CONSTRAINT "mail0_summary_connection_id_mail0_connection_id_fk" FOREIGN KEY ("connection_id") REFERENCES "public"."mail0_connection"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
+ALTER TABLE "mail0_user_hotkeys" ADD CONSTRAINT "mail0_user_hotkeys_user_id_mail0_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."mail0_user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
+ALTER TABLE "mail0_user_settings" ADD CONSTRAINT "mail0_user_settings_user_id_mail0_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."mail0_user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
+CREATE INDEX "account_user_id_idx" ON "mail0_account" USING btree ("user_id");--> statement-breakpoint
+CREATE INDEX "account_provider_user_id_idx" ON "mail0_account" USING btree ("provider_id","user_id");--> statement-breakpoint
+CREATE INDEX "account_expires_at_idx" ON "mail0_account" USING btree ("access_token_expires_at");--> statement-breakpoint
+CREATE INDEX "connection_user_id_idx" ON "mail0_connection" USING btree ("user_id");--> statement-breakpoint
+CREATE INDEX "connection_expires_at_idx" ON "mail0_connection" USING btree ("expires_at");--> statement-breakpoint
+CREATE INDEX "connection_provider_id_idx" ON "mail0_connection" USING btree ("provider_id");--> statement-breakpoint
+CREATE INDEX "early_access_is_early_access_idx" ON "mail0_early_access" USING btree ("is_early_access");--> statement-breakpoint
+CREATE INDEX "jwks_created_at_idx" ON "mail0_jwks" USING btree ("created_at");--> statement-breakpoint
+CREATE INDEX "note_user_id_idx" ON "mail0_note" USING btree ("user_id");--> statement-breakpoint
+CREATE INDEX "note_thread_id_idx" ON "mail0_note" USING btree ("thread_id");--> statement-breakpoint
+CREATE INDEX "note_user_thread_idx" ON "mail0_note" USING btree ("user_id","thread_id");--> statement-breakpoint
+CREATE INDEX "note_is_pinned_idx" ON "mail0_note" USING btree ("is_pinned");--> statement-breakpoint
+CREATE INDEX "oauth_access_token_user_id_idx" ON "mail0_oauth_access_token" USING btree ("user_id");--> statement-breakpoint
+CREATE INDEX "oauth_access_token_client_id_idx" ON "mail0_oauth_access_token" USING btree ("client_id");--> statement-breakpoint
+CREATE INDEX "oauth_access_token_expires_at_idx" ON "mail0_oauth_access_token" USING btree ("access_token_expires_at");--> statement-breakpoint
+CREATE INDEX "oauth_application_user_id_idx" ON "mail0_oauth_application" USING btree ("user_id");--> statement-breakpoint
+CREATE INDEX "oauth_application_disabled_idx" ON "mail0_oauth_application" USING btree ("disabled");--> statement-breakpoint
+CREATE INDEX "oauth_consent_user_id_idx" ON "mail0_oauth_consent" USING btree ("user_id");--> statement-breakpoint
+CREATE INDEX "oauth_consent_client_id_idx" ON "mail0_oauth_consent" USING btree ("client_id");--> statement-breakpoint
+CREATE INDEX "oauth_consent_given_idx" ON "mail0_oauth_consent" USING btree ("consent_given");--> statement-breakpoint
+CREATE INDEX "session_user_id_idx" ON "mail0_session" USING btree ("user_id");--> statement-breakpoint
+CREATE INDEX "session_expires_at_idx" ON "mail0_session" USING btree ("expires_at");--> statement-breakpoint
+CREATE INDEX "summary_connection_id_idx" ON "mail0_summary" USING btree ("connection_id");--> statement-breakpoint
+CREATE INDEX "summary_connection_id_saved_idx" ON "mail0_summary" USING btree ("connection_id","saved");--> statement-breakpoint
+CREATE INDEX "summary_saved_idx" ON "mail0_summary" USING btree ("saved");--> statement-breakpoint
+CREATE INDEX "user_hotkeys_shortcuts_idx" ON "mail0_user_hotkeys" USING btree ("shortcuts");--> statement-breakpoint
+CREATE INDEX "user_settings_settings_idx" ON "mail0_user_settings" USING btree ("settings");--> statement-breakpoint
+CREATE INDEX "verification_identifier_idx" ON "mail0_verification" USING btree ("identifier");--> statement-breakpoint
+CREATE INDEX "verification_expires_at_idx" ON "mail0_verification" USING btree ("expires_at");--> statement-breakpoint
+CREATE INDEX "writing_style_matrix_style_idx" ON "mail0_writing_style_matrix" USING btree ("style");
\ No newline at end of file
diff --git a/apps/server/src/db/migrations/meta/0035_snapshot.json b/apps/server/src/db/migrations/meta/0035_snapshot.json
new file mode 100644
index 0000000000..211511a509
--- /dev/null
+++ b/apps/server/src/db/migrations/meta/0035_snapshot.json
@@ -0,0 +1,1610 @@
+{
+ "id": "0b7459fd-f13f-4111-b30a-f0bd16a5b406",
+ "prevId": "185ab778-1f86-44d6-ac1a-90e9399b1342",
+ "version": "7",
+ "dialect": "postgresql",
+ "tables": {
+ "public.mail0_account": {
+ "name": "mail0_account",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "account_id": {
+ "name": "account_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "provider_id": {
+ "name": "provider_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "access_token": {
+ "name": "access_token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "refresh_token": {
+ "name": "refresh_token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "id_token": {
+ "name": "id_token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "access_token_expires_at": {
+ "name": "access_token_expires_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "refresh_token_expires_at": {
+ "name": "refresh_token_expires_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "scope": {
+ "name": "scope",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "password": {
+ "name": "password",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "account_user_id_idx": {
+ "name": "account_user_id_idx",
+ "columns": [
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "account_provider_user_id_idx": {
+ "name": "account_provider_user_id_idx",
+ "columns": [
+ {
+ "expression": "provider_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "account_expires_at_idx": {
+ "name": "account_expires_at_idx",
+ "columns": [
+ {
+ "expression": "access_token_expires_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "mail0_account_user_id_mail0_user_id_fk": {
+ "name": "mail0_account_user_id_mail0_user_id_fk",
+ "tableFrom": "mail0_account",
+ "tableTo": "mail0_user",
+ "columnsFrom": [
+ "user_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.mail0_connection": {
+ "name": "mail0_connection",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "email": {
+ "name": "email",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "picture": {
+ "name": "picture",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "access_token": {
+ "name": "access_token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "refresh_token": {
+ "name": "refresh_token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "scope": {
+ "name": "scope",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "provider_id": {
+ "name": "provider_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "connection_user_id_idx": {
+ "name": "connection_user_id_idx",
+ "columns": [
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "connection_expires_at_idx": {
+ "name": "connection_expires_at_idx",
+ "columns": [
+ {
+ "expression": "expires_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "connection_provider_id_idx": {
+ "name": "connection_provider_id_idx",
+ "columns": [
+ {
+ "expression": "provider_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "mail0_connection_user_id_mail0_user_id_fk": {
+ "name": "mail0_connection_user_id_mail0_user_id_fk",
+ "tableFrom": "mail0_connection",
+ "tableTo": "mail0_user",
+ "columnsFrom": [
+ "user_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {
+ "mail0_connection_user_id_email_unique": {
+ "name": "mail0_connection_user_id_email_unique",
+ "nullsNotDistinct": false,
+ "columns": [
+ "user_id",
+ "email"
+ ]
+ }
+ },
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.mail0_early_access": {
+ "name": "mail0_early_access",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "email": {
+ "name": "email",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "is_early_access": {
+ "name": "is_early_access",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "has_used_ticket": {
+ "name": "has_used_ticket",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false,
+ "default": "''"
+ }
+ },
+ "indexes": {
+ "early_access_is_early_access_idx": {
+ "name": "early_access_is_early_access_idx",
+ "columns": [
+ {
+ "expression": "is_early_access",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {
+ "mail0_early_access_email_unique": {
+ "name": "mail0_early_access_email_unique",
+ "nullsNotDistinct": false,
+ "columns": [
+ "email"
+ ]
+ }
+ },
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.mail0_jwks": {
+ "name": "mail0_jwks",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "public_key": {
+ "name": "public_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "private_key": {
+ "name": "private_key",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "jwks_created_at_idx": {
+ "name": "jwks_created_at_idx",
+ "columns": [
+ {
+ "expression": "created_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.mail0_note": {
+ "name": "mail0_note",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "thread_id": {
+ "name": "thread_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "content": {
+ "name": "content",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "color": {
+ "name": "color",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'default'"
+ },
+ "is_pinned": {
+ "name": "is_pinned",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false,
+ "default": false
+ },
+ "order": {
+ "name": "order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true,
+ "default": 0
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "note_user_id_idx": {
+ "name": "note_user_id_idx",
+ "columns": [
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "note_thread_id_idx": {
+ "name": "note_thread_id_idx",
+ "columns": [
+ {
+ "expression": "thread_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "note_user_thread_idx": {
+ "name": "note_user_thread_idx",
+ "columns": [
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "thread_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "note_is_pinned_idx": {
+ "name": "note_is_pinned_idx",
+ "columns": [
+ {
+ "expression": "is_pinned",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "mail0_note_user_id_mail0_user_id_fk": {
+ "name": "mail0_note_user_id_mail0_user_id_fk",
+ "tableFrom": "mail0_note",
+ "tableTo": "mail0_user",
+ "columnsFrom": [
+ "user_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.mail0_oauth_access_token": {
+ "name": "mail0_oauth_access_token",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "access_token": {
+ "name": "access_token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "refresh_token": {
+ "name": "refresh_token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "access_token_expires_at": {
+ "name": "access_token_expires_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "refresh_token_expires_at": {
+ "name": "refresh_token_expires_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "client_id": {
+ "name": "client_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "scopes": {
+ "name": "scopes",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "oauth_access_token_user_id_idx": {
+ "name": "oauth_access_token_user_id_idx",
+ "columns": [
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "oauth_access_token_client_id_idx": {
+ "name": "oauth_access_token_client_id_idx",
+ "columns": [
+ {
+ "expression": "client_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "oauth_access_token_expires_at_idx": {
+ "name": "oauth_access_token_expires_at_idx",
+ "columns": [
+ {
+ "expression": "access_token_expires_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {
+ "mail0_oauth_access_token_access_token_unique": {
+ "name": "mail0_oauth_access_token_access_token_unique",
+ "nullsNotDistinct": false,
+ "columns": [
+ "access_token"
+ ]
+ },
+ "mail0_oauth_access_token_refresh_token_unique": {
+ "name": "mail0_oauth_access_token_refresh_token_unique",
+ "nullsNotDistinct": false,
+ "columns": [
+ "refresh_token"
+ ]
+ }
+ },
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.mail0_oauth_application": {
+ "name": "mail0_oauth_application",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "icon": {
+ "name": "icon",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "metadata": {
+ "name": "metadata",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "client_id": {
+ "name": "client_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "client_secret": {
+ "name": "client_secret",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "redirect_u_r_ls": {
+ "name": "redirect_u_r_ls",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "type": {
+ "name": "type",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "disabled": {
+ "name": "disabled",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "oauth_application_user_id_idx": {
+ "name": "oauth_application_user_id_idx",
+ "columns": [
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "oauth_application_disabled_idx": {
+ "name": "oauth_application_disabled_idx",
+ "columns": [
+ {
+ "expression": "disabled",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {
+ "mail0_oauth_application_client_id_unique": {
+ "name": "mail0_oauth_application_client_id_unique",
+ "nullsNotDistinct": false,
+ "columns": [
+ "client_id"
+ ]
+ }
+ },
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.mail0_oauth_consent": {
+ "name": "mail0_oauth_consent",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "client_id": {
+ "name": "client_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "scopes": {
+ "name": "scopes",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "consent_given": {
+ "name": "consent_given",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "oauth_consent_user_id_idx": {
+ "name": "oauth_consent_user_id_idx",
+ "columns": [
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "oauth_consent_client_id_idx": {
+ "name": "oauth_consent_client_id_idx",
+ "columns": [
+ {
+ "expression": "client_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "oauth_consent_given_idx": {
+ "name": "oauth_consent_given_idx",
+ "columns": [
+ {
+ "expression": "consent_given",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.mail0_session": {
+ "name": "mail0_session",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "token": {
+ "name": "token",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "ip_address": {
+ "name": "ip_address",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "user_agent": {
+ "name": "user_agent",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "session_user_id_idx": {
+ "name": "session_user_id_idx",
+ "columns": [
+ {
+ "expression": "user_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "session_expires_at_idx": {
+ "name": "session_expires_at_idx",
+ "columns": [
+ {
+ "expression": "expires_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "mail0_session_user_id_mail0_user_id_fk": {
+ "name": "mail0_session_user_id_mail0_user_id_fk",
+ "tableFrom": "mail0_session",
+ "tableTo": "mail0_user",
+ "columnsFrom": [
+ "user_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {
+ "mail0_session_token_unique": {
+ "name": "mail0_session_token_unique",
+ "nullsNotDistinct": false,
+ "columns": [
+ "token"
+ ]
+ }
+ },
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.mail0_summary": {
+ "name": "mail0_summary",
+ "schema": "",
+ "columns": {
+ "message_id": {
+ "name": "message_id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "content": {
+ "name": "content",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "connection_id": {
+ "name": "connection_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "saved": {
+ "name": "saved",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true,
+ "default": false
+ },
+ "tags": {
+ "name": "tags",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "suggested_reply": {
+ "name": "suggested_reply",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "summary_connection_id_idx": {
+ "name": "summary_connection_id_idx",
+ "columns": [
+ {
+ "expression": "connection_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "summary_connection_id_saved_idx": {
+ "name": "summary_connection_id_saved_idx",
+ "columns": [
+ {
+ "expression": "connection_id",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ },
+ {
+ "expression": "saved",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "summary_saved_idx": {
+ "name": "summary_saved_idx",
+ "columns": [
+ {
+ "expression": "saved",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "mail0_summary_connection_id_mail0_connection_id_fk": {
+ "name": "mail0_summary_connection_id_mail0_connection_id_fk",
+ "tableFrom": "mail0_summary",
+ "tableTo": "mail0_connection",
+ "columnsFrom": [
+ "connection_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.mail0_user": {
+ "name": "mail0_user",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "email": {
+ "name": "email",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "email_verified": {
+ "name": "email_verified",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "image": {
+ "name": "image",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "default_connection_id": {
+ "name": "default_connection_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "custom_prompt": {
+ "name": "custom_prompt",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "phone_number": {
+ "name": "phone_number",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "phone_number_verified": {
+ "name": "phone_number_verified",
+ "type": "boolean",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {},
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {
+ "mail0_user_email_unique": {
+ "name": "mail0_user_email_unique",
+ "nullsNotDistinct": false,
+ "columns": [
+ "email"
+ ]
+ },
+ "mail0_user_phone_number_unique": {
+ "name": "mail0_user_phone_number_unique",
+ "nullsNotDistinct": false,
+ "columns": [
+ "phone_number"
+ ]
+ }
+ },
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.mail0_user_hotkeys": {
+ "name": "mail0_user_hotkeys",
+ "schema": "",
+ "columns": {
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "shortcuts": {
+ "name": "shortcuts",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "user_hotkeys_shortcuts_idx": {
+ "name": "user_hotkeys_shortcuts_idx",
+ "columns": [
+ {
+ "expression": "shortcuts",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "mail0_user_hotkeys_user_id_mail0_user_id_fk": {
+ "name": "mail0_user_hotkeys_user_id_mail0_user_id_fk",
+ "tableFrom": "mail0_user_hotkeys",
+ "tableTo": "mail0_user",
+ "columnsFrom": [
+ "user_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.mail0_user_settings": {
+ "name": "mail0_user_settings",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "user_id": {
+ "name": "user_id",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "settings": {
+ "name": "settings",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "'{\"language\":\"en\",\"timezone\":\"UTC\",\"dynamicContent\":false,\"externalImages\":true,\"customPrompt\":\"\",\"trustedSenders\":[],\"isOnboarded\":false,\"colorTheme\":\"system\",\"zeroSignature\":true,\"autoRead\":true,\"defaultEmailAlias\":\"\",\"categories\":[{\"id\":\"Important\",\"name\":\"Important\",\"searchValue\":\"is:important NOT is:sent NOT is:draft\",\"order\":0,\"icon\":\"Lightning\",\"isDefault\":false},{\"id\":\"All Mail\",\"name\":\"All Mail\",\"searchValue\":\"NOT is:draft (is:inbox OR (is:sent AND to:me))\",\"order\":1,\"icon\":\"Mail\",\"isDefault\":true},{\"id\":\"Personal\",\"name\":\"Personal\",\"searchValue\":\"is:personal NOT is:sent NOT is:draft\",\"order\":2,\"icon\":\"User\",\"isDefault\":false},{\"id\":\"Promotions\",\"name\":\"Promotions\",\"searchValue\":\"is:promotions NOT is:sent NOT is:draft\",\"order\":3,\"icon\":\"Tag\",\"isDefault\":false},{\"id\":\"Updates\",\"name\":\"Updates\",\"searchValue\":\"is:updates NOT is:sent NOT is:draft\",\"order\":4,\"icon\":\"Bell\",\"isDefault\":false},{\"id\":\"Unread\",\"name\":\"Unread\",\"searchValue\":\"is:unread NOT is:sent NOT is:draft\",\"order\":5,\"icon\":\"ScanEye\",\"isDefault\":false}],\"imageCompression\":\"medium\"}'::jsonb"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ }
+ },
+ "indexes": {
+ "user_settings_settings_idx": {
+ "name": "user_settings_settings_idx",
+ "columns": [
+ {
+ "expression": "settings",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "mail0_user_settings_user_id_mail0_user_id_fk": {
+ "name": "mail0_user_settings_user_id_mail0_user_id_fk",
+ "tableFrom": "mail0_user_settings",
+ "tableTo": "mail0_user",
+ "columnsFrom": [
+ "user_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {
+ "mail0_user_settings_user_id_unique": {
+ "name": "mail0_user_settings_user_id_unique",
+ "nullsNotDistinct": false,
+ "columns": [
+ "user_id"
+ ]
+ }
+ },
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.mail0_verification": {
+ "name": "mail0_verification",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "text",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "identifier": {
+ "name": "identifier",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "value": {
+ "name": "value",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "expires_at": {
+ "name": "expires_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "verification_identifier_idx": {
+ "name": "verification_identifier_idx",
+ "columns": [
+ {
+ "expression": "identifier",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ },
+ "verification_expires_at_idx": {
+ "name": "verification_expires_at_idx",
+ "columns": [
+ {
+ "expression": "expires_at",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ },
+ "public.mail0_writing_style_matrix": {
+ "name": "mail0_writing_style_matrix",
+ "schema": "",
+ "columns": {
+ "connectionId": {
+ "name": "connectionId",
+ "type": "text",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "numMessages": {
+ "name": "numMessages",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "style": {
+ "name": "style",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "updatedAt": {
+ "name": "updatedAt",
+ "type": "timestamp",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "writing_style_matrix_style_idx": {
+ "name": "writing_style_matrix_style_idx",
+ "columns": [
+ {
+ "expression": "style",
+ "isExpression": false,
+ "asc": true,
+ "nulls": "last"
+ }
+ ],
+ "isUnique": false,
+ "concurrently": false,
+ "method": "btree",
+ "with": {}
+ }
+ },
+ "foreignKeys": {
+ "mail0_writing_style_matrix_connectionId_mail0_connection_id_fk": {
+ "name": "mail0_writing_style_matrix_connectionId_mail0_connection_id_fk",
+ "tableFrom": "mail0_writing_style_matrix",
+ "tableTo": "mail0_connection",
+ "columnsFrom": [
+ "connectionId"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {
+ "mail0_writing_style_matrix_connectionId_pk": {
+ "name": "mail0_writing_style_matrix_connectionId_pk",
+ "columns": [
+ "connectionId"
+ ]
+ }
+ },
+ "uniqueConstraints": {},
+ "policies": {},
+ "checkConstraints": {},
+ "isRLSEnabled": false
+ }
+ },
+ "enums": {},
+ "schemas": {},
+ "sequences": {},
+ "roles": {},
+ "policies": {},
+ "views": {},
+ "_meta": {
+ "columns": {},
+ "schemas": {},
+ "tables": {}
+ }
+}
\ No newline at end of file
diff --git a/apps/server/src/db/migrations/meta/_journal.json b/apps/server/src/db/migrations/meta/_journal.json
index e1106690ec..530acb75a0 100644
--- a/apps/server/src/db/migrations/meta/_journal.json
+++ b/apps/server/src/db/migrations/meta/_journal.json
@@ -253,6 +253,13 @@
"when": 1751008013033,
"tag": "0034_mushy_runaways",
"breakpoints": true
+ },
+ {
+ "idx": 35,
+ "version": "7",
+ "when": 1751568728663,
+ "tag": "0035_uneven_shiva",
+ "breakpoints": true
}
]
}
\ No newline at end of file
diff --git a/apps/server/src/db/schema.ts b/apps/server/src/db/schema.ts
index ffdd57a967..bbe8016dee 100644
--- a/apps/server/src/db/schema.ts
+++ b/apps/server/src/db/schema.ts
@@ -7,6 +7,7 @@ import {
jsonb,
primaryKey,
unique,
+ index,
} from 'drizzle-orm/pg-core';
import { defaultUserSettings } from '../lib/schemas';
@@ -26,63 +27,93 @@ export const user = createTable('user', {
phoneNumberVerified: boolean('phone_number_verified'),
});
-export const session = createTable('session', {
- id: text('id').primaryKey(),
- expiresAt: timestamp('expires_at').notNull(),
- token: text('token').notNull().unique(),
- createdAt: timestamp('created_at').notNull(),
- updatedAt: timestamp('updated_at').notNull(),
- ipAddress: text('ip_address'),
- userAgent: text('user_agent'),
- userId: text('user_id')
- .notNull()
- .references(() => user.id),
-});
+export const session = createTable(
+ 'session',
+ {
+ id: text('id').primaryKey(),
+ expiresAt: timestamp('expires_at').notNull(),
+ token: text('token').notNull().unique(),
+ createdAt: timestamp('created_at').notNull(),
+ updatedAt: timestamp('updated_at').notNull(),
+ ipAddress: text('ip_address'),
+ userAgent: text('user_agent'),
+ userId: text('user_id')
+ .notNull()
+ .references(() => user.id, { onDelete: 'cascade' }),
+ },
+ (t) => [
+ index('session_user_id_idx').on(t.userId),
+ index('session_expires_at_idx').on(t.expiresAt),
+ ],
+);
-export const account = createTable('account', {
- id: text('id').primaryKey(),
- accountId: text('account_id').notNull(),
- providerId: text('provider_id').notNull(),
- userId: text('user_id')
- .notNull()
- .references(() => user.id),
- accessToken: text('access_token'),
- refreshToken: text('refresh_token'),
- idToken: text('id_token'),
- accessTokenExpiresAt: timestamp('access_token_expires_at'),
- refreshTokenExpiresAt: timestamp('refresh_token_expires_at'),
- scope: text('scope'),
- password: text('password'),
- createdAt: timestamp('created_at').notNull(),
- updatedAt: timestamp('updated_at').notNull(),
-});
+export const account = createTable(
+ 'account',
+ {
+ id: text('id').primaryKey(),
+ accountId: text('account_id').notNull(),
+ providerId: text('provider_id').notNull(),
+ userId: text('user_id')
+ .notNull()
+ .references(() => user.id, { onDelete: 'cascade' }),
+ accessToken: text('access_token'),
+ refreshToken: text('refresh_token'),
+ idToken: text('id_token'),
+ accessTokenExpiresAt: timestamp('access_token_expires_at'),
+ refreshTokenExpiresAt: timestamp('refresh_token_expires_at'),
+ scope: text('scope'),
+ password: text('password'),
+ createdAt: timestamp('created_at').notNull(),
+ updatedAt: timestamp('updated_at').notNull(),
+ },
+ (t) => [
+ index('account_user_id_idx').on(t.userId),
+ index('account_provider_user_id_idx').on(t.providerId, t.userId),
+ index('account_expires_at_idx').on(t.accessTokenExpiresAt),
+ ],
+);
-export const userHotkeys = createTable('user_hotkeys', {
- userId: text('user_id')
- .primaryKey()
- .references(() => user.id),
- shortcuts: jsonb('shortcuts').notNull(),
- createdAt: timestamp('created_at').notNull(),
- updatedAt: timestamp('updated_at').notNull(),
-});
+export const userHotkeys = createTable(
+ 'user_hotkeys',
+ {
+ userId: text('user_id')
+ .primaryKey()
+ .references(() => user.id, { onDelete: 'cascade' }),
+ shortcuts: jsonb('shortcuts').notNull(),
+ createdAt: timestamp('created_at').notNull(),
+ updatedAt: timestamp('updated_at').notNull(),
+ },
+ (t) => [index('user_hotkeys_shortcuts_idx').on(t.shortcuts)],
+);
-export const verification = createTable('verification', {
- id: text('id').primaryKey(),
- identifier: text('identifier').notNull(),
- value: text('value').notNull(),
- expiresAt: timestamp('expires_at').notNull(),
- createdAt: timestamp('created_at'),
- updatedAt: timestamp('updated_at'),
-});
+export const verification = createTable(
+ 'verification',
+ {
+ id: text('id').primaryKey(),
+ identifier: text('identifier').notNull(),
+ value: text('value').notNull(),
+ expiresAt: timestamp('expires_at').notNull(),
+ createdAt: timestamp('created_at'),
+ updatedAt: timestamp('updated_at'),
+ },
+ (t) => [
+ index('verification_identifier_idx').on(t.identifier),
+ index('verification_expires_at_idx').on(t.expiresAt),
+ ],
+);
-export const earlyAccess = createTable('early_access', {
- id: text('id').primaryKey(),
- email: text('email').notNull().unique(),
- createdAt: timestamp('created_at').notNull(),
- updatedAt: timestamp('updated_at').notNull(),
- isEarlyAccess: boolean('is_early_access').notNull().default(false),
- hasUsedTicket: text('has_used_ticket').default(''),
-});
+export const earlyAccess = createTable(
+ 'early_access',
+ {
+ id: text('id').primaryKey(),
+ email: text('email').notNull().unique(),
+ createdAt: timestamp('created_at').notNull(),
+ updatedAt: timestamp('updated_at').notNull(),
+ isEarlyAccess: boolean('is_early_access').notNull().default(false),
+ hasUsedTicket: text('has_used_ticket').default(''),
+ },
+ (t) => [index('early_access_is_early_access_idx').on(t.isEarlyAccess)],
+);
export const connection = createTable(
'connection',
@@ -90,7 +121,7 @@ export const connection = createTable(
id: text('id').primaryKey(),
userId: text('user_id')
.notNull()
- .references(() => user.id),
+ .references(() => user.id, { onDelete: 'cascade' }),
email: text('email').notNull(),
name: text('name'),
picture: text('picture'),
@@ -102,45 +133,73 @@ export const connection = createTable(
createdAt: timestamp('created_at').notNull(),
updatedAt: timestamp('updated_at').notNull(),
},
- (t) => [unique().on(t.userId, t.email)],
+ (t) => [
+ unique().on(t.userId, t.email),
+ index('connection_user_id_idx').on(t.userId),
+ index('connection_expires_at_idx').on(t.expiresAt),
+ index('connection_provider_id_idx').on(t.providerId),
+ ],
);
-export const summary = createTable('summary', {
- messageId: text('message_id').primaryKey(),
- content: text('content').notNull(),
- createdAt: timestamp('created_at').notNull(),
- updatedAt: timestamp('updated_at').notNull(),
- connectionId: text('connection_id').notNull(),
- saved: boolean('saved').notNull().default(false),
- tags: text('tags'),
- suggestedReply: text('suggested_reply'),
-});
+export const summary = createTable(
+ 'summary',
+ {
+ messageId: text('message_id').primaryKey(),
+ content: text('content').notNull(),
+ createdAt: timestamp('created_at').notNull(),
+ updatedAt: timestamp('updated_at').notNull(),
+ connectionId: text('connection_id')
+ .notNull()
+ .references(() => connection.id, { onDelete: 'cascade' }),
+ saved: boolean('saved').notNull().default(false),
+ tags: text('tags'),
+ suggestedReply: text('suggested_reply'),
+ },
+ (t) => [
+ index('summary_connection_id_idx').on(t.connectionId),
+ index('summary_connection_id_saved_idx').on(t.connectionId, t.saved),
+ index('summary_saved_idx').on(t.saved),
+ ],
+);
// Testing
-export const note = createTable('note', {
- id: text('id').primaryKey(),
- userId: text('user_id')
- .notNull()
- .references(() => user.id, { onDelete: 'cascade' }),
- threadId: text('thread_id').notNull(),
- content: text('content').notNull(),
- color: text('color').notNull().default('default'),
- isPinned: boolean('is_pinned').default(false),
- order: integer('order').notNull().default(0),
- createdAt: timestamp('created_at').notNull().defaultNow(),
- updatedAt: timestamp('updated_at').notNull().defaultNow(),
-});
+export const note = createTable(
+ 'note',
+ {
+ id: text('id').primaryKey(),
+ userId: text('user_id')
+ .notNull()
+ .references(() => user.id, { onDelete: 'cascade' }),
+ threadId: text('thread_id').notNull(),
+ content: text('content').notNull(),
+ color: text('color').notNull().default('default'),
+ isPinned: boolean('is_pinned').default(false),
+ order: integer('order').notNull().default(0),
+ createdAt: timestamp('created_at').notNull().defaultNow(),
+ updatedAt: timestamp('updated_at').notNull().defaultNow(),
+ },
+ (t) => [
+ index('note_user_id_idx').on(t.userId),
+ index('note_thread_id_idx').on(t.threadId),
+ index('note_user_thread_idx').on(t.userId, t.threadId),
+ index('note_is_pinned_idx').on(t.isPinned),
+ ],
+);
-export const userSettings = createTable('user_settings', {
- id: text('id').primaryKey(),
- userId: text('user_id')
- .notNull()
- .references(() => user.id)
- .unique(),
- settings: jsonb('settings').notNull().default(defaultUserSettings),
- createdAt: timestamp('created_at').notNull(),
- updatedAt: timestamp('updated_at').notNull(),
-});
+export const userSettings = createTable(
+ 'user_settings',
+ {
+ id: text('id').primaryKey(),
+ userId: text('user_id')
+ .notNull()
+ .references(() => user.id, { onDelete: 'cascade' })
+ .unique(),
+ settings: jsonb('settings').notNull().default(defaultUserSettings),
+ createdAt: timestamp('created_at').notNull(),
+ updatedAt: timestamp('updated_at').notNull(),
+ },
+ (t) => [index('user_settings_settings_idx').on(t.settings)],
+);
export const writingStyleMatrix = createTable(
'writing_style_matrix',
@@ -162,51 +221,79 @@ export const writingStyleMatrix = createTable(
primaryKey({
columns: [table.connectionId],
}),
+ index('writing_style_matrix_style_idx').on(table.style),
];
},
);
-export const jwks = createTable('jwks', {
- id: text('id').primaryKey(),
- publicKey: text('public_key').notNull(),
- privateKey: text('private_key').notNull(),
- createdAt: timestamp('created_at').notNull(),
-});
+export const jwks = createTable(
+ 'jwks',
+ {
+ id: text('id').primaryKey(),
+ publicKey: text('public_key').notNull(),
+ privateKey: text('private_key').notNull(),
+ createdAt: timestamp('created_at').notNull(),
+ },
+ (t) => [index('jwks_created_at_idx').on(t.createdAt)],
+);
-export const oauthApplication = createTable('oauth_application', {
- id: text('id').primaryKey(),
- name: text('name'),
- icon: text('icon'),
- metadata: text('metadata'),
- clientId: text('client_id').unique(),
- clientSecret: text('client_secret'),
- redirectURLs: text('redirect_u_r_ls'),
- type: text('type'),
- disabled: boolean('disabled'),
- userId: text('user_id'),
- createdAt: timestamp('created_at'),
- updatedAt: timestamp('updated_at'),
-});
+export const oauthApplication = createTable(
+ 'oauth_application',
+ {
+ id: text('id').primaryKey(),
+ name: text('name'),
+ icon: text('icon'),
+ metadata: text('metadata'),
+ clientId: text('client_id').unique(),
+ clientSecret: text('client_secret'),
+ redirectURLs: text('redirect_u_r_ls'),
+ type: text('type'),
+ disabled: boolean('disabled'),
+ userId: text('user_id'),
+ createdAt: timestamp('created_at'),
+ updatedAt: timestamp('updated_at'),
+ },
+ (t) => [
+ index('oauth_application_user_id_idx').on(t.userId),
+ index('oauth_application_disabled_idx').on(t.disabled),
+ ],
+);
-export const oauthAccessToken = createTable('oauth_access_token', {
- id: text('id').primaryKey(),
- accessToken: text('access_token').unique(),
- refreshToken: text('refresh_token').unique(),
- accessTokenExpiresAt: timestamp('access_token_expires_at'),
- refreshTokenExpiresAt: timestamp('refresh_token_expires_at'),
- clientId: text('client_id'),
- userId: text('user_id'),
- scopes: text('scopes'),
- createdAt: timestamp('created_at'),
- updatedAt: timestamp('updated_at'),
-});
+export const oauthAccessToken = createTable(
+ 'oauth_access_token',
+ {
+ id: text('id').primaryKey(),
+ accessToken: text('access_token').unique(),
+ refreshToken: text('refresh_token').unique(),
+ accessTokenExpiresAt: timestamp('access_token_expires_at'),
+ refreshTokenExpiresAt: timestamp('refresh_token_expires_at'),
+ clientId: text('client_id'),
+ userId: text('user_id'),
+ scopes: text('scopes'),
+ createdAt: timestamp('created_at'),
+ updatedAt: timestamp('updated_at'),
+ },
+ (t) => [
+ index('oauth_access_token_user_id_idx').on(t.userId),
+ index('oauth_access_token_client_id_idx').on(t.clientId),
+ index('oauth_access_token_expires_at_idx').on(t.accessTokenExpiresAt),
+ ],
+);
-export const oauthConsent = createTable('oauth_consent', {
- id: text('id').primaryKey(),
- clientId: text('client_id'),
- userId: text('user_id'),
- scopes: text('scopes'),
- createdAt: timestamp('created_at'),
- updatedAt: timestamp('updated_at'),
- consentGiven: boolean('consent_given'),
-});
+export const oauthConsent = createTable(
+ 'oauth_consent',
+ {
+ id: text('id').primaryKey(),
+ clientId: text('client_id'),
+ userId: text('user_id'),
+ scopes: text('scopes'),
+ createdAt: timestamp('created_at'),
+ updatedAt: timestamp('updated_at'),
+ consentGiven: boolean('consent_given'),
+ },
+ (t) => [
+ index('oauth_consent_user_id_idx').on(t.userId),
+ index('oauth_consent_client_id_idx').on(t.clientId),
+ index('oauth_consent_given_idx').on(t.consentGiven),
+ ],
+);
diff --git a/apps/server/src/lib/driver/google.ts b/apps/server/src/lib/driver/google.ts
index 8fcc4d5406..b42c5d10ee 100644
--- a/apps/server/src/lib/driver/google.ts
+++ b/apps/server/src/lib/driver/google.ts
@@ -484,7 +484,7 @@ export class GoogleMailManager implements MailManager {
throw new Error('Draft not found');
}
- const parsedDraft = this.parseDraft(res.data);
+ const parsedDraft = await this.parseDraft(res.data);
if (!parsedDraft) {
throw new Error('Failed to parse draft');
}
@@ -1111,7 +1111,8 @@ export class GoogleMailManager implements MailManager {
raw: encodedMessage,
};
}
- private parseDraft(draft: gmail_v1.Schema$Draft) {
+
+ private async parseDraft(draft: gmail_v1.Schema$Draft) {
if (!draft.message) return null;
const headers = draft.message.payload?.headers || [];
@@ -1121,26 +1122,61 @@ export class GoogleMailManager implements MailManager {
?.value?.split(',')
.map((e) => e.trim())
.filter(Boolean) || [];
- const subject = headers.find((h) => h.name === 'Subject')?.value;
-
- let content = '';
- const payload = draft.message.payload;
-
- if (payload) {
- if (payload.parts) {
- const textPart = payload.parts.find((part) => part.mimeType === 'text/html');
- if (textPart?.body?.data) {
- content = fromBinary(textPart.body.data);
- }
- } else if (payload.body?.data) {
- content = fromBinary(payload.body.data);
- }
- }
+ const subject = headers.find((h) => h.name === 'Subject')?.value;
+
const cc =
draft.message.payload?.headers?.find((h) => h.name === 'Cc')?.value?.split(',') || [];
const bcc =
draft.message.payload?.headers?.find((h) => h.name === 'Bcc')?.value?.split(',') || [];
+
+ const payload = draft.message.payload;
+ let content = '';
+ let attachments: {
+ filename: string;
+ mimeType: string;
+ size: number;
+ attachmentId: string;
+ headers: { name: string; value: string }[];
+ body: string;
+ }[] = [];
+
+ if (payload?.parts) {
+ // Get body
+ const htmlPart = payload.parts.find((part) => part.mimeType === 'text/html');
+ if (htmlPart?.body?.data) {
+ content = fromBinary(htmlPart.body.data);
+ }
+
+ // Get attachments
+ const attachmentParts = payload.parts.filter(
+ (part) => !!part.filename && !!part.body?.attachmentId
+ );
+
+ attachments = await Promise.all(
+ attachmentParts.map(async (part) => {
+ try {
+ const attachmentData = await this.getAttachment(draft.message!.id!, part.body!.attachmentId!);
+ return {
+ filename: part.filename || '',
+ mimeType: part.mimeType || '',
+ size: Number(part.body?.size || 0),
+ attachmentId: part.body!.attachmentId!,
+ headers:
+ part.headers?.map((h) => ({
+ name: h.name ?? '',
+ value: h.value ?? '',
+ })) ?? [],
+ body: attachmentData ?? '',
+ };
+ } catch (e) {
+ return null;
+ }
+ })
+ ).then((a) => a.filter((a): a is NonNullable => a !== null));
+ } else if (payload?.body?.data) {
+ content = fromBinary(payload.body.data);
+ }
return {
id: draft.id || '',
@@ -1150,8 +1186,10 @@ export class GoogleMailManager implements MailManager {
rawMessage: draft.message,
cc,
bcc,
+ attachments,
};
}
+
private async withErrorHandler(
operation: string,
fn: () => Promise | T,
diff --git a/apps/server/src/lib/driver/types.ts b/apps/server/src/lib/driver/types.ts
index 0e442833bf..28d9b784e8 100644
--- a/apps/server/src/lib/driver/types.ts
+++ b/apps/server/src/lib/driver/types.ts
@@ -24,7 +24,9 @@ export interface ParsedDraft {
to?: string[];
subject?: string;
content?: string;
- rawMessage?: T;
+ rawMessage?: {
+ internalDate?: string;
+ };
cc?: string[];
bcc?: string[];
}
diff --git a/apps/server/src/routes/agent/orchestrator.ts b/apps/server/src/routes/agent/orchestrator.ts
new file mode 100644
index 0000000000..5e4129da83
--- /dev/null
+++ b/apps/server/src/routes/agent/orchestrator.ts
@@ -0,0 +1,84 @@
+import { streamText, tool, type DataStreamWriter, type ToolSet } from 'ai';
+import { perplexity } from '@ai-sdk/perplexity';
+import { env } from 'cloudflare:workers';
+import { Tools } from '../../types';
+import { z } from 'zod';
+
+/**
+ * Orchestrator that handles the distinction between tools and agents.
+ * Tools execute and return results, while agents stream responses directly.
+ */
+export class ToolOrchestrator {
+ private dataStream: DataStreamWriter;
+ private streamingTools: Set = new Set([Tools.WebSearch]);
+
+ constructor(dataStream: DataStreamWriter) {
+ this.dataStream = dataStream;
+ }
+
+ /**
+ * Determines if a tool should be treated as an agent that streams
+ */
+ isStreamingTool(toolName: string): boolean {
+ return this.streamingTools.has(toolName);
+ }
+
+ /**
+ * Creates a streaming agent wrapper for tools that should stream responses directly
+ */
+ createStreamingAgent(toolName: string, originalTool: any) {
+ if (!this.isStreamingTool(toolName)) {
+ return originalTool;
+ }
+
+ // For webSearch, we want to stream the response directly without wrapping it as a tool result
+ if (toolName === Tools.WebSearch) {
+ return tool({
+ description: 'Search the web for information using Perplexity AI',
+ parameters: z.object({
+ query: z.string().describe('The query to search the web for'),
+ }),
+ execute: async ({ query }) => {
+ try {
+ const response = streamText({
+ model: perplexity('sonar'),
+ messages: [
+ { role: 'system', content: 'Be precise and concise.' },
+ { role: 'system', content: 'Do not include sources in your response.' },
+ { role: 'system', content: 'Do not use markdown formatting in your response.' },
+ { role: 'user', content: query },
+ ],
+ maxTokens: 1024,
+ });
+
+ // Stream the response directly to the data stream
+ response.mergeIntoDataStream(this.dataStream);
+
+ // Return a placeholder result since the actual streaming happens above
+ return { type: 'streaming_response', toolName };
+ } catch (error) {
+ console.error('Error searching the web:', error);
+ throw new Error('Failed to search the web');
+ }
+ },
+ });
+ }
+
+ return originalTool;
+ }
+
+ /**
+ * Processes all tools and returns modified versions for streaming tools
+ */
+ processTools(tools: T): T {
+ const processedTools = { ...tools };
+
+ for (const [toolName, toolInstance] of Object.entries(tools)) {
+ if (this.isStreamingTool(toolName)) {
+ processedTools[toolName as keyof T] = this.createStreamingAgent(toolName, toolInstance);
+ }
+ }
+
+ return processedTools;
+ }
+}
diff --git a/apps/server/src/routes/agent/tools.ts b/apps/server/src/routes/agent/tools.ts
index fd07d48d71..1147e3e268 100644
--- a/apps/server/src/routes/agent/tools.ts
+++ b/apps/server/src/routes/agent/tools.ts
@@ -1,9 +1,11 @@
+import { toZodToolSet, executeOrAuthorizeZodTool } from '@arcadeai/arcadejs/lib';
+import { generateText, streamText, tool, type DataStreamWriter } from 'ai';
import { composeEmail } from '../../trpc/routes/ai/compose';
import type { MailManager } from '../../lib/driver/types';
import { perplexity } from '@ai-sdk/perplexity';
+import { Arcade } from '@arcadeai/arcadejs';
import { colors } from '../../lib/prompts';
import { env } from 'cloudflare:workers';
-import { generateText, tool } from 'ai';
import { Tools } from '../../types';
import { z } from 'zod';
@@ -328,33 +330,52 @@ const deleteLabel = (driver: MailManager) =>
},
});
-export const webSearch = tool({
- description: 'Search the web for information using Perplexity AI',
- parameters: z.object({
- query: z.string().describe('The query to search the web for'),
- }),
- execute: async ({ query }) => {
- try {
- const { text } = await generateText({
- model: perplexity('sonar'),
- messages: [
- { role: 'system', content: 'Be precise and concise.' },
- { role: 'system', content: 'Do not include sources in your response.' },
- { role: 'system', content: 'Do not use markdown formatting in your response.' },
- { role: 'user', content: query },
- ],
- maxTokens: 1024,
- });
+const getGoogleTools = async (connectionId: string) => {
+ const arcade = new Arcade();
+ const googleToolkit = await arcade.tools.list({ toolkit: 'google', limit: 30 });
+ const googleTools = toZodToolSet({
+ tools: googleToolkit.items,
+ client: arcade,
+ userId: connectionId, // Your app's internal ID for the user (an email, UUID, etc). It's used internally to identify your user in Arcade
+ executeFactory: executeOrAuthorizeZodTool, // Checks if tool is authorized and executes it, or returns authorization URL if needed
+ });
+ return googleTools;
+};
+
+export const webSearch = (dataStream: DataStreamWriter) =>
+ tool({
+ description: 'Search the web for information using Perplexity AI',
+ parameters: z.object({
+ query: z.string().describe('The query to search the web for'),
+ }),
+ execute: async ({ query }) => {
+ try {
+ const response = streamText({
+ model: perplexity('sonar'),
+ messages: [
+ { role: 'system', content: 'Be precise and concise.' },
+ { role: 'system', content: 'Do not include sources in your response.' },
+ { role: 'system', content: 'Do not use markdown formatting in your response.' },
+ { role: 'user', content: query },
+ ],
+ maxTokens: 1024,
+ });
- return text;
- } catch (error) {
- console.error('Error searching the web:', error);
- throw new Error('Failed to search the web');
- }
- },
-});
+ response.mergeIntoDataStream(dataStream);
-export const tools = (driver: MailManager, connectionId: string) => {
+ return { type: 'streaming_response', query };
+ } catch (error) {
+ console.error('Error searching the web:', error);
+ throw new Error('Failed to search the web');
+ }
+ },
+ });
+
+export const tools = async (
+ driver: MailManager,
+ connectionId: string,
+ dataStream: DataStreamWriter,
+) => {
return {
[Tools.GetThread]: getEmail(driver),
[Tools.ComposeEmail]: composeEmailTool(connectionId),
@@ -368,8 +389,9 @@ export const tools = (driver: MailManager, connectionId: string) => {
[Tools.BulkDelete]: bulkDelete(driver),
[Tools.BulkArchive]: bulkArchive(driver),
[Tools.DeleteLabel]: deleteLabel(driver),
- [Tools.AskZeroMailbox]: askZeroMailbox(connectionId),
- [Tools.AskZeroThread]: askZeroThread(connectionId),
- [Tools.WebSearch]: webSearch,
+ // [Tools.AskZeroMailbox]: askZeroMailbox(connectionId),
+ // [Tools.AskZeroThread]: askZeroThread(connectionId),
+ [Tools.WebSearch]: webSearch(dataStream),
+ // ...(await getGoogleTools(connectionId)),
};
};
diff --git a/apps/server/src/routes/ai.ts b/apps/server/src/routes/ai.ts
index 7234dd2a45..a1d3c21eeb 100644
--- a/apps/server/src/routes/ai.ts
+++ b/apps/server/src/routes/ai.ts
@@ -145,7 +145,7 @@ aiRouter.post('/call', async (c) => {
const driver = connectionToDriver(connection);
const { text } = await generateText({
- model: openai('gpt-4o'),
+ model: openai(env.OPENAI_MODEL || 'gpt-4o'),
system: systemPrompt,
prompt: data.query,
tools: {
@@ -158,7 +158,7 @@ aiRouter.post('/call', async (c) => {
console.log('[DEBUG] buildGmailSearchQuery', params);
const result = await generateText({
- model: openai('gpt-4o'),
+ model: openai(env.OPENAI_MODEL || 'gpt-4o'),
system: GmailSearchAssistantSystemPrompt(),
prompt: params.query,
});
diff --git a/apps/server/src/routes/chat.ts b/apps/server/src/routes/chat.ts
index 6df33dc171..0722432247 100644
--- a/apps/server/src/routes/chat.ts
+++ b/apps/server/src/routes/chat.ts
@@ -18,6 +18,7 @@ import type { IGetThreadResponse, MailManager } from '../lib/driver/types';
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { createSimpleAuth, type SimpleAuth } from '../lib/auth';
import { connectionToDriver } from '../lib/server-utils';
+import { ToolOrchestrator } from './agent/orchestrator';
import type { CreateDraftData } from '../lib/schemas';
import { FOLDERS, parseHeaders } from '../lib/utils';
import { env, RpcTarget } from 'cloudflare:workers';
@@ -352,7 +353,12 @@ export class ZeroAgent extends AIChatAgent {
throw new Error('Unauthorized no driver or connectionId [2]');
}
}
- const tools = { ...authTools(this.driver, connectionId), buildGmailSearchQuery };
+ const orchestrator = new ToolOrchestrator(dataStream);
+ const rawTools = {
+ ...(await authTools(this.driver, connectionId, dataStream)),
+ buildGmailSearchQuery,
+ };
+ const tools = orchestrator.processTools(rawTools);
const processedMessages = await processToolCalls(
{
messages: this.messages,
@@ -363,7 +369,7 @@ export class ZeroAgent extends AIChatAgent {
);
const result = streamText({
- model: openai('gpt-4o'),
+ model: openai(env.OPENAI_MODEL || 'gpt-4o'),
messages: processedMessages,
tools,
onFinish,
@@ -689,7 +695,7 @@ export class ZeroAgent extends AIChatAgent {
async buildGmailSearchQuery(query: string) {
const result = await generateText({
- model: openai('gpt-4o'),
+ model: openai(env.OPENAI_MODEL || 'gpt-4o'),
system: GmailSearchAssistantSystemPrompt(),
prompt: query,
});
@@ -1242,7 +1248,7 @@ export class ZeroMCP extends McpAgent {
},
async (s) => {
const result = await generateText({
- model: openai('gpt-4o'),
+ model: openai(env.OPENAI_MODEL || 'gpt-4o'),
system: GmailSearchAssistantSystemPrompt(),
prompt: s.query,
});
@@ -1587,7 +1593,7 @@ const buildGmailSearchQuery = tool({
}),
execute: async ({ query }) => {
const result = await generateObject({
- model: openai('gpt-4o'),
+ model: openai(env.OPENAI_MODEL || 'gpt-4o'),
system: GmailSearchAssistantSystemPrompt(),
prompt: query,
schema: z.object({
diff --git a/apps/server/src/services/mcp-service/mcp.ts b/apps/server/src/services/mcp-service/mcp.ts
index 71bb913509..822d29dc32 100644
--- a/apps/server/src/services/mcp-service/mcp.ts
+++ b/apps/server/src/services/mcp-service/mcp.ts
@@ -55,7 +55,7 @@ export class ZeroMCP extends McpAgent
},
async (s) => {
const result = await generateText({
- model: openai('gpt-4o'),
+ model: openai(env.OPENAI_MODEL || 'gpt-4o'),
system: GmailSearchAssistantSystemPrompt(),
prompt: s.query,
});
diff --git a/apps/server/src/trpc/routes/ai/compose.ts b/apps/server/src/trpc/routes/ai/compose.ts
index 9ab24a7cc3..f0fbc5b890 100644
--- a/apps/server/src/trpc/routes/ai/compose.ts
+++ b/apps/server/src/trpc/routes/ai/compose.ts
@@ -11,6 +11,7 @@ import { stripHtml } from 'string-strip-html';
import { openai } from '@ai-sdk/openai';
import { generateText } from 'ai';
import { z } from 'zod';
+import { env } from 'cloudflare:workers';
type ComposeEmailInput = {
prompt: string;
@@ -84,7 +85,7 @@ export async function composeEmail(input: ComposeEmailInput) {
];
const { text } = await generateText({
- model: openai('gpt-4o-mini'),
+ model: openai(env.OPENAI_MINI_MODEL || 'gpt-4o-mini'),
messages: [
{
role: 'system',
@@ -273,7 +274,7 @@ const generateSubject = async (message: string, styleProfile?: WritingStyleMatri
);
const { text } = await generateText({
- model: openai('gpt-4o'),
+ model: openai(env.OPENAI_MODEL || 'gpt-4o'),
messages: [
{
role: 'system',
diff --git a/apps/server/src/trpc/routes/ai/search.ts b/apps/server/src/trpc/routes/ai/search.ts
index 51f26aba1f..88c0c4c24d 100644
--- a/apps/server/src/trpc/routes/ai/search.ts
+++ b/apps/server/src/trpc/routes/ai/search.ts
@@ -5,6 +5,7 @@ import {
import { activeDriverProcedure } from '../../trpc';
import { openai } from '@ai-sdk/openai';
import { generateObject } from 'ai';
+import { env } from 'cloudflare:workers';
import { z } from 'zod';
export const generateSearchQuery = activeDriverProcedure
@@ -21,7 +22,7 @@ export const generateSearchQuery = activeDriverProcedure
: '';
const result = await generateObject({
- model: openai('gpt-4o'),
+ model: openai(env.OPENAI_MODEL || 'gpt-4o'),
system: systemPrompt,
prompt: input.query,
schema: z.object({
diff --git a/docker-compose.prod.yaml b/docker-compose.prod.yaml
index 9df2dee965..780b4b313f 100644
--- a/docker-compose.prod.yaml
+++ b/docker-compose.prod.yaml
@@ -12,6 +12,10 @@ services:
RESEND_API_KEY: ${RESEND_API_KEY}
AI_SYSTEM_PROMPT: ${AI_SYSTEM_PROMPT}
GROQ_API_KEY: ${GROQ_API_KEY}
+ PERPLEXITY_API_KEY: ${PERPLEXITY_API_KEY}
+ OPENAI_API_KEY: ${OPENAI_API_KEY}
+ OPENAI_MODEL: ${OPENAI_MODEL}
+ OPENAI_MINI_MODEL: ${OPENAI_MINI_MODEL}
NEXT_PUBLIC_ELEVENLABS_AGENT_ID: ${NEXT_PUBLIC_ELEVENLABS_AGENT_ID}
NEXT_PUBLIC_IMAGE_PROXY: ${NEXT_PUBLIC_IMAGE_PROXY}
NEXT_PUBLIC_POSTHOG_KEY: ${NEXT_PUBLIC_POSTHOG_KEY}
diff --git a/i18n.lock b/i18n.lock
index 33136c09e7..c6d90c6fe4 100644
--- a/i18n.lock
+++ b/i18n.lock
@@ -852,6 +852,7 @@ checksums:
navigation/sidebar/spam: 904064026d3ce87cd872e0b819a15310
navigation/sidebar/archive: fa813ab3074103e5daad07462af25789
navigation/sidebar/bin: e95691895f3a89d896838716e48290bd
+ navigation/sidebar/livesupport: 087e6998c099b3c08c5ade57c5f68752
navigation/sidebar/feedback: 6fac88806e0c269a30777b283988c61c
navigation/sidebar/settings: 8df6777277469c1fd88cc18dde2f1cc3
navigation/sidebar/voice: 81a94ad8770dca9c3cbb5a88329b6a6f
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 5a300f3660..1a1df2feab 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -154,6 +154,9 @@ importers:
'@tiptap/extension-document':
specifier: 2.23.0
version: 2.23.0(@tiptap/core@2.23.0(@tiptap/pm@2.23.0))
+ '@tiptap/extension-emoji':
+ specifier: 2.23.1
+ version: 2.23.1(@tiptap/core@2.23.0(@tiptap/pm@2.23.0))(@tiptap/pm@2.23.0)(@tiptap/suggestion@2.23.0(@tiptap/core@2.23.0(@tiptap/pm@2.23.0))(@tiptap/pm@2.23.0))(emojibase@16.0.0)
'@tiptap/extension-file-handler':
specifier: 2.23.0
version: 2.23.0(@tiptap/core@2.23.0(@tiptap/pm@2.23.0))(@tiptap/extension-text-style@2.23.0(@tiptap/core@2.23.0(@tiptap/pm@2.23.0)))
@@ -482,6 +485,9 @@ importers:
'@ai-sdk/ui-utils':
specifier: 1.2.11
version: 1.2.11(zod@3.25.67)
+ '@arcadeai/arcadejs':
+ specifier: 1.8.1
+ version: 1.8.1
'@coinbase/cookie-manager':
specifier: 1.1.8
version: 1.1.8
@@ -759,6 +765,9 @@ packages:
resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
engines: {node: '>=6.0.0'}
+ '@arcadeai/arcadejs@1.8.1':
+ resolution: {integrity: sha512-ZTj2UvdfFmFn1as4gdDiZD8nbnEFZcZUzH9XtTmjRbgf/1V8s1wEtlzlI3vct+dA+KZ+NhS79AEw5lx/Ki0xSw==}
+
'@babel/code-frame@7.27.1':
resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==}
engines: {node: '>=6.9.0'}
@@ -3435,6 +3444,13 @@ packages:
'@tiptap/core': ^2.7.0
'@tiptap/pm': ^2.7.0
+ '@tiptap/extension-emoji@2.23.1':
+ resolution: {integrity: sha512-bqTn+hbq0bDIcrPIIjVq3GndJ/PYQfReMDlyTv0mUCtRbP7zReJ1oFx02d25RmwgS6XL3U8WW4kEFomhliwWSQ==}
+ peerDependencies:
+ '@tiptap/core': ^2.7.0
+ '@tiptap/pm': ^2.7.0
+ '@tiptap/suggestion': ^2.7.0
+
'@tiptap/extension-file-handler@2.23.0':
resolution: {integrity: sha512-rTimkgFtMIbYYydf2suvIpF+GnFRU80BppnrOUNfW+HzaI0i1p0gKzEDKJuPBMAEFfG/Q7Yxetk6rO6Y5Sq6Mw==}
peerDependencies:
@@ -3693,6 +3709,12 @@ packages:
'@types/ms@2.1.0':
resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==}
+ '@types/node-fetch@2.6.12':
+ resolution: {integrity: sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==}
+
+ '@types/node@18.19.115':
+ resolution: {integrity: sha512-kNrFiTgG4a9JAn1LMQeLOv3MvXIPokzXziohMrMsvpYgLpdEt/mMiVYc4sGKtDfyxM5gIDF4VgrPRyCw4fHOYg==}
+
'@types/node@22.13.8':
resolution: {integrity: sha512-G3EfaZS+iOGYWLLRCEAXdWK9my08oHNZ+FHluRiggIYJPOXzhOiDgpVCUHaUvyIC5/fj7C/p637jdzC666AOKQ==}
@@ -3841,6 +3863,10 @@ packages:
resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==}
engines: {node: '>= 14'}
+ agentkeepalive@4.6.0:
+ resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==}
+ engines: {node: '>= 8.0.0'}
+
agents@0.0.93:
resolution: {integrity: sha512-W25kx492Txn5XYY9gx2YBhGmfC8C/N3JQzfjbmq9GjhYtAFCsJdIw6C5xbLt/ev2x3Uor/8XMHXYiw/2YbTSkQ==}
peerDependencies:
@@ -4628,6 +4654,15 @@ packages:
emoji-regex@9.2.2:
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
+ emojibase-data@15.3.2:
+ resolution: {integrity: sha512-TpDyTDDTdqWIJixV5sTA6OQ0P0JfIIeK2tFRR3q56G9LK65ylAZ7z3KyBXokpvTTJ+mLUXQXbLNyVkjvnTLE+A==}
+ peerDependencies:
+ emojibase: '*'
+
+ emojibase@16.0.0:
+ resolution: {integrity: sha512-Nw2m7JLIO4Ou2X/yZPRNscHQXVbbr6SErjkJ7EooG7MbR3yDZszCv9KTizsXFc7yZl0n3WF+qUKIC/Lw6H9xaQ==}
+ engines: {node: '>=18.12.0'}
+
encodeurl@2.0.0:
resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==}
engines: {node: '>= 0.8'}
@@ -4956,6 +4991,9 @@ packages:
resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==}
engines: {node: '>=14'}
+ form-data-encoder@1.7.2:
+ resolution: {integrity: sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==}
+
form-data-encoder@4.1.0:
resolution: {integrity: sha512-G6NsmEW15s0Uw9XnCg+33H3ViYRyiM0hMrMhhqQOR8NFc5GhYrI+6I3u7OTw7b91J2g8rtvMBZJDbcGb2YUniw==}
engines: {node: '>= 18'}
@@ -4964,6 +5002,10 @@ packages:
resolution: {integrity: sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA==}
engines: {node: '>= 6'}
+ formdata-node@4.4.1:
+ resolution: {integrity: sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==}
+ engines: {node: '>= 12.20'}
+
formdata-node@6.0.3:
resolution: {integrity: sha512-8e1++BCiTzUno9v5IZ2J6bv4RU+3UKDmqWUQD0MIMVCd9AdhWkO1gw57oo1mNEX1dMq2EGI+FbWz4B92pscSQg==}
engines: {node: '>= 18'}
@@ -5224,6 +5266,9 @@ packages:
resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
engines: {node: '>=10.17.0'}
+ humanize-ms@1.2.1:
+ resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==}
+
husky@9.1.7:
resolution: {integrity: sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==}
engines: {node: '>=18'}
@@ -5339,6 +5384,9 @@ packages:
is-decimal@2.0.1:
resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==}
+ is-emoji-supported@0.0.5:
+ resolution: {integrity: sha512-WOlXUhDDHxYqcSmFZis+xWhhqXiK2SU0iYiqmth5Ip0FHLZQAt9rKL5ahnilE8/86WH8tZ3bmNNNC+bTzamqlw==}
+
is-extglob@2.1.1:
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
engines: {node: '>=0.10.0'}
@@ -5942,6 +5990,11 @@ packages:
react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc
react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc
+ node-domexception@1.0.0:
+ resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
+ engines: {node: '>=10.5.0'}
+ deprecated: Use your platform's native DOMException instead
+
node-fetch@2.7.0:
resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==}
engines: {node: 4.x || >=6.0.0}
@@ -7309,6 +7362,9 @@ packages:
uncrypto@0.1.3:
resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==}
+ undici-types@5.26.5:
+ resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
+
undici-types@6.20.0:
resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==}
@@ -7529,6 +7585,10 @@ packages:
w3c-keyname@2.2.8:
resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==}
+ web-streams-polyfill@4.0.0-beta.3:
+ resolution: {integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==}
+ engines: {node: '>= 14'}
+
web-vitals@4.2.4:
resolution: {integrity: sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==}
@@ -7742,6 +7802,19 @@ snapshots:
'@jridgewell/gen-mapping': 0.3.8
'@jridgewell/trace-mapping': 0.3.25
+ '@arcadeai/arcadejs@1.8.1':
+ dependencies:
+ '@types/node': 18.19.115
+ '@types/node-fetch': 2.6.12
+ abort-controller: 3.0.0
+ agentkeepalive: 4.6.0
+ form-data-encoder: 1.7.2
+ formdata-node: 4.4.1
+ node-fetch: 2.7.0
+ zod: 3.25.67
+ transitivePeerDependencies:
+ - encoding
+
'@babel/code-frame@7.27.1':
dependencies:
'@babel/helper-validator-identifier': 7.27.1
@@ -10372,6 +10445,17 @@ snapshots:
'@tiptap/core': 2.23.0(@tiptap/pm@2.23.0)
'@tiptap/pm': 2.23.0
+ '@tiptap/extension-emoji@2.23.1(@tiptap/core@2.23.0(@tiptap/pm@2.23.0))(@tiptap/pm@2.23.0)(@tiptap/suggestion@2.23.0(@tiptap/core@2.23.0(@tiptap/pm@2.23.0))(@tiptap/pm@2.23.0))(emojibase@16.0.0)':
+ dependencies:
+ '@tiptap/core': 2.23.0(@tiptap/pm@2.23.0)
+ '@tiptap/pm': 2.23.0
+ '@tiptap/suggestion': 2.23.0(@tiptap/core@2.23.0(@tiptap/pm@2.23.0))(@tiptap/pm@2.23.0)
+ emoji-regex: 10.4.0
+ emojibase-data: 15.3.2(emojibase@16.0.0)
+ is-emoji-supported: 0.0.5
+ transitivePeerDependencies:
+ - emojibase
+
'@tiptap/extension-file-handler@2.23.0(@tiptap/core@2.23.0(@tiptap/pm@2.23.0))(@tiptap/extension-text-style@2.23.0(@tiptap/core@2.23.0(@tiptap/pm@2.23.0)))':
dependencies:
'@tiptap/core': 2.23.0(@tiptap/pm@2.23.0)
@@ -10640,6 +10724,15 @@ snapshots:
'@types/ms@2.1.0': {}
+ '@types/node-fetch@2.6.12':
+ dependencies:
+ '@types/node': 22.15.29
+ form-data: 4.0.3
+
+ '@types/node@18.19.115':
+ dependencies:
+ undici-types: 5.26.5
+
'@types/node@22.13.8':
dependencies:
undici-types: 6.20.0
@@ -10804,6 +10897,10 @@ snapshots:
agent-base@7.1.3: {}
+ agentkeepalive@4.6.0:
+ dependencies:
+ humanize-ms: 1.2.1
+
agents@0.0.93(@cloudflare/workers-types@4.20250628.0)(react@19.1.0):
dependencies:
'@modelcontextprotocol/sdk': 1.12.0
@@ -11581,6 +11678,12 @@ snapshots:
emoji-regex@9.2.2: {}
+ emojibase-data@15.3.2(emojibase@16.0.0):
+ dependencies:
+ emojibase: 16.0.0
+
+ emojibase@16.0.0: {}
+
encodeurl@2.0.0: {}
encoding-sniffer@0.2.1:
@@ -12101,6 +12204,8 @@ snapshots:
cross-spawn: 7.0.6
signal-exit: 4.1.0
+ form-data-encoder@1.7.2: {}
+
form-data-encoder@4.1.0: {}
form-data@4.0.3:
@@ -12111,6 +12216,11 @@ snapshots:
hasown: 2.0.2
mime-types: 2.1.35
+ formdata-node@4.4.1:
+ dependencies:
+ node-domexception: 1.0.0
+ web-streams-polyfill: 4.0.0-beta.3
+
formdata-node@6.0.3: {}
forwarded@0.2.0: {}
@@ -12413,6 +12523,10 @@ snapshots:
human-signals@2.1.0: {}
+ humanize-ms@1.2.1:
+ dependencies:
+ ms: 2.1.3
+
husky@9.1.7: {}
hyphenate-style-name@1.1.0: {}
@@ -12518,6 +12632,8 @@ snapshots:
is-decimal@2.0.1: {}
+ is-emoji-supported@0.0.5: {}
+
is-extglob@2.1.1: {}
is-finalizationregistry@1.1.1:
@@ -13213,6 +13329,8 @@ snapshots:
react: 19.1.0
react-dom: 19.1.0(react@19.1.0)
+ node-domexception@1.0.0: {}
+
node-fetch@2.7.0:
dependencies:
whatwg-url: 5.0.0
@@ -14860,6 +14978,8 @@ snapshots:
uncrypto@0.1.3: {}
+ undici-types@5.26.5: {}
+
undici-types@6.20.0: {}
undici-types@6.21.0: {}
@@ -15075,6 +15195,8 @@ snapshots:
w3c-keyname@2.2.8: {}
+ web-streams-polyfill@4.0.0-beta.3: {}
+
web-vitals@4.2.4: {}
webidl-conversions@3.0.1: {}