mail page imap connection
This commit is contained in:
parent
ba0a5873b2
commit
4836353591
141
app/api/mail/route.ts
Normal file
141
app/api/mail/route.ts
Normal file
@ -0,0 +1,141 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import Imap from 'imap';
|
||||
import { simpleParser } from 'mailparser';
|
||||
|
||||
// IMAP configuration
|
||||
const imapConfig = {
|
||||
user: 'contact@governance-labs.org',
|
||||
password: 'K!376c$6H#kMknM',
|
||||
host: 'mail.governance-labs.org',
|
||||
port: 993,
|
||||
tls: true,
|
||||
tlsOptions: { rejectUnauthorized: false }
|
||||
};
|
||||
|
||||
// Helper function to create a promise-based IMAP connection
|
||||
function createImapConnection() {
|
||||
return new Promise((resolve, reject) => {
|
||||
const imap = new Imap(imapConfig);
|
||||
|
||||
imap.once('ready', () => resolve(imap));
|
||||
imap.once('error', (err: Error) => reject(err));
|
||||
imap.connect();
|
||||
});
|
||||
}
|
||||
|
||||
// Helper function to promisify the message fetching
|
||||
function fetchMessages(imap: Imap, box: string) {
|
||||
return new Promise((resolve, reject) => {
|
||||
imap.openBox(box, false, (err, mailbox) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// Search for all messages
|
||||
imap.search(['ALL'], (err, results) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// No messages found
|
||||
if (!results || !results.length) {
|
||||
resolve([]);
|
||||
return;
|
||||
}
|
||||
|
||||
const fetch = imap.fetch(results, {
|
||||
bodies: ['HEADER.FIELDS (FROM TO SUBJECT DATE)', 'TEXT'],
|
||||
struct: true
|
||||
});
|
||||
|
||||
const messages: any[] = [];
|
||||
|
||||
fetch.on('message', (msg) => {
|
||||
const message: any = {};
|
||||
|
||||
msg.on('body', (stream, info) => {
|
||||
let buffer = '';
|
||||
stream.on('data', (chunk) => {
|
||||
buffer += chunk.toString('utf8');
|
||||
});
|
||||
stream.once('end', () => {
|
||||
if (info.which === 'TEXT') {
|
||||
message.body = buffer;
|
||||
} else {
|
||||
message.header = Imap.parseHeader(buffer);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
msg.once('attributes', (attrs) => {
|
||||
message.attributes = attrs;
|
||||
});
|
||||
|
||||
msg.once('end', () => {
|
||||
messages.push(message);
|
||||
});
|
||||
});
|
||||
|
||||
fetch.once('error', (err) => {
|
||||
reject(err);
|
||||
});
|
||||
|
||||
fetch.once('end', () => {
|
||||
resolve(messages);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export async function GET(request: Request) {
|
||||
try {
|
||||
const imap = await createImapConnection() as Imap;
|
||||
const messages = await fetchMessages(imap, 'INBOX');
|
||||
|
||||
// Process messages into the format expected by the frontend
|
||||
const processedMessages = messages.map((msg: any, index: number) => ({
|
||||
id: index + 1,
|
||||
accountId: 1,
|
||||
from: msg.header.from[0],
|
||||
fromName: msg.header.from[0].split('<')[0].trim(),
|
||||
to: msg.header.to[0],
|
||||
subject: msg.header.subject[0],
|
||||
body: msg.body,
|
||||
date: msg.header.date[0],
|
||||
read: !(msg.attributes.flags.indexOf('\\Seen') < 0),
|
||||
starred: !(msg.attributes.flags.indexOf('\\Flagged') < 0),
|
||||
category: 'inbox'
|
||||
}));
|
||||
|
||||
imap.end();
|
||||
return NextResponse.json({ messages: processedMessages });
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error fetching emails:', error);
|
||||
return NextResponse.json({ error: 'Failed to fetch emails' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
// Add endpoint to get mailboxes
|
||||
export async function POST(request: Request) {
|
||||
try {
|
||||
const imap = await createImapConnection() as Imap;
|
||||
|
||||
const mailboxes = await new Promise((resolve, reject) => {
|
||||
imap.getBoxes((err, boxes) => {
|
||||
if (err) reject(err);
|
||||
resolve(boxes);
|
||||
});
|
||||
});
|
||||
|
||||
imap.end();
|
||||
return NextResponse.json({ mailboxes });
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error fetching mailboxes:', error);
|
||||
return NextResponse.json({ error: 'Failed to fetch mailboxes' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
@ -1,856 +1,134 @@
|
||||
'use client';
|
||||
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogAction,
|
||||
AlertDialogCancel,
|
||||
AlertDialogContent,
|
||||
AlertDialogDescription,
|
||||
AlertDialogFooter,
|
||||
AlertDialogHeader,
|
||||
AlertDialogTitle,
|
||||
} from "@/components/ui/alert-dialog";
|
||||
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
|
||||
import { MoreVertical, Settings, Plus as PlusIcon, Trash2, Edit, Mail, Inbox, Send, Star, Trash, Plus, ChevronLeft, ChevronRight, Search, ChevronDown, Folder, ChevronUp, Reply, Forward, ReplyAll, MoreHorizontal, FolderOpen, X } from 'lucide-react';
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Paperclip, Copy, EyeOff } from 'lucide-react';
|
||||
|
||||
interface Account {
|
||||
id: number;
|
||||
name: string;
|
||||
email: string;
|
||||
color: string;
|
||||
}
|
||||
import { Card } from "@/components/ui/card"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Input } from "@/components/ui/input"
|
||||
import { Mail, Search, Star, Inbox, Send, Archive, Trash } from "lucide-react"
|
||||
import { useState, useEffect } from "react"
|
||||
|
||||
interface Email {
|
||||
id: number;
|
||||
accountId: number;
|
||||
from: string;
|
||||
fromName: string;
|
||||
to: string;
|
||||
subject: string;
|
||||
body: string;
|
||||
date: string;
|
||||
read: boolean;
|
||||
starred: boolean;
|
||||
category: string;
|
||||
id: number
|
||||
accountId: number
|
||||
from: string
|
||||
fromName: string
|
||||
to: string
|
||||
subject: string
|
||||
body: string
|
||||
date: string
|
||||
read: boolean
|
||||
starred: boolean
|
||||
category: string
|
||||
}
|
||||
|
||||
export default function MailPage() {
|
||||
// Mock data for email accounts
|
||||
const [accounts, setAccounts] = useState<Account[]>([
|
||||
{ id: 1, name: 'Work', email: 'john.doe@company.com', color: 'bg-blue-500' },
|
||||
{ id: 2, name: 'Personal', email: 'johndoe@gmail.com', color: 'bg-green-500' },
|
||||
{ id: 3, name: 'Side Project', email: 'john@sideproject.io', color: 'bg-purple-500' }
|
||||
]);
|
||||
const [emails, setEmails] = useState<Email[]>([])
|
||||
const [loading, setLoading] = useState(true)
|
||||
|
||||
// Mock data for emails
|
||||
const [emails, setEmails] = useState<Email[]>([
|
||||
{
|
||||
id: 1,
|
||||
accountId: 1,
|
||||
from: 'sarah@company.com',
|
||||
fromName: 'Sarah Johnson',
|
||||
to: 'john.doe@company.com',
|
||||
subject: 'Project Status Update',
|
||||
body: 'Hi John, here is the latest update on the project. We have completed the first phase and are moving to the second phase.',
|
||||
date: '2025-04-15T10:30:00',
|
||||
read: false,
|
||||
starred: true,
|
||||
category: 'inbox'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
accountId: 1,
|
||||
from: 'mike@company.com',
|
||||
fromName: 'Mike Chen',
|
||||
to: 'john.doe@company.com',
|
||||
subject: 'Meeting Tomorrow',
|
||||
body: 'Don\'t forget we have a team meeting tomorrow at 10am in Conference Room A.',
|
||||
date: '2025-04-14T16:45:00',
|
||||
read: true,
|
||||
starred: false,
|
||||
category: 'inbox'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
accountId: 2,
|
||||
from: 'lisa@gmail.com',
|
||||
fromName: 'Lisa Smith',
|
||||
to: 'johndoe@gmail.com',
|
||||
subject: 'Weekend Plans',
|
||||
body: 'Hey, are you free this weekend? I was thinking we could go hiking at the national park.',
|
||||
date: '2025-04-13T09:15:00',
|
||||
read: false,
|
||||
starred: false,
|
||||
category: 'inbox'
|
||||
useEffect(() => {
|
||||
async function fetchEmails() {
|
||||
try {
|
||||
const res = await fetch('/api/mail')
|
||||
if (!res.ok) throw new Error('Failed to fetch emails')
|
||||
const data = await res.json()
|
||||
setEmails(data.messages)
|
||||
} catch (error) {
|
||||
console.error('Error fetching emails:', error)
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
const [selectedAccount, setSelectedAccount] = useState(1);
|
||||
const [currentView, setCurrentView] = useState('inbox');
|
||||
const [selectedEmail, setSelectedEmail] = useState<number | null>(null);
|
||||
const [sidebarOpen, setSidebarOpen] = useState(true);
|
||||
const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false);
|
||||
const [composeOpen, setComposeOpen] = useState(false);
|
||||
const [accountsDropdownOpen, setAccountsDropdownOpen] = useState(false);
|
||||
const [foldersDropdownOpen, setFoldersDropdownOpen] = useState(false);
|
||||
const [showAccountActions, setShowAccountActions] = useState<number | null>(null);
|
||||
const [showEmailActions, setShowEmailActions] = useState(false);
|
||||
const [selectedEmails, setSelectedEmails] = useState<number[]>([]);
|
||||
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
|
||||
const [deleteType, setDeleteType] = useState<'email' | 'emails' | 'account'>('email');
|
||||
const [itemToDelete, setItemToDelete] = useState<number | null>(null);
|
||||
const [showBulkActions, setShowBulkActions] = useState(false);
|
||||
const [showCc, setShowCc] = useState(false);
|
||||
const [showBcc, setShowBcc] = useState(false);
|
||||
|
||||
// Mock folders data
|
||||
const folders = [
|
||||
{ id: 1, name: 'Important' },
|
||||
{ id: 2, name: 'Work' },
|
||||
{ id: 3, name: 'Personal' },
|
||||
{ id: 4, name: 'Archive' }
|
||||
];
|
||||
|
||||
// Modified accounts array with "All" option
|
||||
const allAccounts = [
|
||||
{ id: 0, name: 'All', email: '', color: 'bg-gray-500' },
|
||||
...accounts
|
||||
];
|
||||
|
||||
// Filter emails based on selected account and view
|
||||
const filteredEmails = emails.filter(email =>
|
||||
(selectedAccount === 0 || email.accountId === selectedAccount) &&
|
||||
(currentView === 'starred' ? email.starred : email.category === currentView)
|
||||
);
|
||||
|
||||
// Handle email selection
|
||||
const handleEmailClick = (emailId: number) => {
|
||||
const updatedEmails = emails.map(email =>
|
||||
email.id === emailId ? { ...email, read: true } : email
|
||||
);
|
||||
setEmails(updatedEmails);
|
||||
setSelectedEmail(emailId);
|
||||
};
|
||||
|
||||
// Toggle starred status
|
||||
const toggleStarred = (emailId: number, e: React.MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
const updatedEmails = emails.map(email =>
|
||||
email.id === emailId ? { ...email, starred: !email.starred } : email
|
||||
);
|
||||
setEmails(updatedEmails);
|
||||
};
|
||||
|
||||
// Format date for display
|
||||
const formatDate = (dateString: string) => {
|
||||
const date = new Date(dateString);
|
||||
const now = new Date();
|
||||
|
||||
if (date.toDateString() === now.toDateString()) {
|
||||
return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
||||
} else {
|
||||
return date.toLocaleDateString([], { month: 'short', day: 'numeric' });
|
||||
}
|
||||
};
|
||||
|
||||
// Get selected email
|
||||
const getSelectedEmail = () => {
|
||||
return emails.find(email => email.id === selectedEmail);
|
||||
};
|
||||
|
||||
// Get account color
|
||||
const getAccountColor = (accountId: number) => {
|
||||
const account = accounts.find(acc => acc.id === accountId);
|
||||
return account ? account.color : 'bg-gray-500';
|
||||
};
|
||||
|
||||
// Handle bulk selection
|
||||
const toggleEmailSelection = (emailId: number, e: React.MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
setSelectedEmails(prev =>
|
||||
prev.includes(emailId)
|
||||
? prev.filter(id => id !== emailId)
|
||||
: [...prev, emailId]
|
||||
);
|
||||
setShowBulkActions(true);
|
||||
};
|
||||
|
||||
// Handle select all
|
||||
const toggleSelectAll = () => {
|
||||
if (selectedEmails.length === filteredEmails.length) {
|
||||
setSelectedEmails([]);
|
||||
setShowBulkActions(false);
|
||||
} else {
|
||||
setSelectedEmails(filteredEmails.map(email => email.id));
|
||||
setShowBulkActions(true);
|
||||
}
|
||||
};
|
||||
|
||||
// Handle bulk delete
|
||||
const handleBulkDelete = () => {
|
||||
setDeleteType('emails');
|
||||
setShowDeleteConfirm(true);
|
||||
};
|
||||
|
||||
// Handle delete confirmation
|
||||
const handleDeleteConfirm = () => {
|
||||
if (deleteType === 'email' && itemToDelete) {
|
||||
setEmails(emails.filter(email => email.id !== itemToDelete));
|
||||
setSelectedEmail(null);
|
||||
} else if (deleteType === 'emails') {
|
||||
setEmails(emails.filter(email => !selectedEmails.includes(email.id)));
|
||||
setSelectedEmails([]);
|
||||
setShowBulkActions(false);
|
||||
} else if (deleteType === 'account' && itemToDelete) {
|
||||
handleAccountAction(itemToDelete, 'delete');
|
||||
}
|
||||
setShowDeleteConfirm(false);
|
||||
};
|
||||
|
||||
// Modified account action handler
|
||||
const handleAccountAction = (accountId: number, action: 'edit' | 'delete') => {
|
||||
setShowAccountActions(null);
|
||||
if (action === 'delete') {
|
||||
setDeleteType('account');
|
||||
setItemToDelete(accountId);
|
||||
setShowDeleteConfirm(true);
|
||||
}
|
||||
// Handle edit in a real application
|
||||
};
|
||||
fetchEmails()
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className="flex h-[calc(100vh-theme(spacing.12))] bg-gray-50 text-gray-900 overflow-hidden mt-12">
|
||||
<div className="flex h-screen bg-gray-100">
|
||||
{/* Sidebar */}
|
||||
<div className={`${sidebarOpen ? 'w-72' : 'w-20'} bg-white/95 backdrop-blur-sm border-0 shadow-lg flex flex-col transition-all duration-300 ease-in-out
|
||||
${mobileSidebarOpen ? 'fixed inset-y-0 left-0 z-40' : 'hidden'} md:block`}>
|
||||
{/* Logo and toggle */}
|
||||
<div className="p-3 flex items-center justify-between border-b border-gray-100">
|
||||
{sidebarOpen && <h1 className="text-lg font-semibold text-gray-800">Mail</h1>}
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="hidden md:flex text-gray-600"
|
||||
onClick={() => setSidebarOpen(!sidebarOpen)}
|
||||
>
|
||||
{sidebarOpen ? <ChevronLeft className="h-4 w-4" /> : <ChevronRight className="h-4 w-4" />}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Account Selection */}
|
||||
<div className="relative">
|
||||
<div className="p-3 border-b border-gray-100">
|
||||
{sidebarOpen ? (
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="w-full justify-between text-gray-600 hover:text-gray-900"
|
||||
onClick={() => setAccountsDropdownOpen(!accountsDropdownOpen)}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className={`w-2.5 h-2.5 rounded-full ${getAccountColor(selectedAccount)}`}></div>
|
||||
<span>{accounts.find(acc => acc.id === selectedAccount)?.name || 'All accounts'}</span>
|
||||
</div>
|
||||
{accountsDropdownOpen ? <ChevronUp className="h-4 w-4" /> : <ChevronDown className="h-4 w-4" />}
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="w-full aspect-square"
|
||||
onClick={() => setAccountsDropdownOpen(!accountsDropdownOpen)}
|
||||
>
|
||||
<div className={`w-2.5 h-2.5 rounded-full ${getAccountColor(selectedAccount)}`}></div>
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Accounts Dropdown */}
|
||||
{accountsDropdownOpen && sidebarOpen && (
|
||||
<div className="absolute top-full left-0 w-full bg-white border border-gray-100 shadow-lg rounded-b-lg z-50">
|
||||
{allAccounts.map(account => (
|
||||
<div key={account.id} className="relative group">
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="w-full justify-start px-4 py-2 text-sm"
|
||||
onClick={() => {
|
||||
setSelectedAccount(account.id);
|
||||
setAccountsDropdownOpen(false);
|
||||
}}
|
||||
>
|
||||
<div className="flex items-center gap-2 w-full">
|
||||
<div className={`w-2.5 h-2.5 rounded-full ${account.color}`}></div>
|
||||
<div className="flex flex-col items-start flex-1">
|
||||
<span className="font-medium">{account.name}</span>
|
||||
{account.email && <span className="text-xs text-gray-500">{account.email}</span>}
|
||||
</div>
|
||||
{account.id !== 0 && (
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="opacity-0 group-hover:opacity-100"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setShowAccountActions(account.id);
|
||||
}}
|
||||
>
|
||||
<MoreVertical className="h-4 w-4 text-gray-500" />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</Button>
|
||||
|
||||
{/* Account Actions Dropdown */}
|
||||
{showAccountActions === account.id && account.id !== 0 && (
|
||||
<div className="absolute right-0 mt-1 w-48 bg-white border border-gray-100 shadow-lg rounded-lg z-50">
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="w-full justify-start px-4 py-2 text-sm text-gray-600 hover:text-gray-900"
|
||||
onClick={() => handleAccountAction(account.id, 'edit')}
|
||||
>
|
||||
<Edit className="h-4 w-4 mr-2" />
|
||||
Edit account
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="w-full justify-start px-4 py-2 text-sm text-red-600 hover:text-red-700"
|
||||
onClick={() => handleAccountAction(account.id, 'delete')}
|
||||
>
|
||||
<Trash2 className="h-4 w-4 mr-2" />
|
||||
Remove account
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
|
||||
{/* Add Account Button */}
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="w-full justify-start px-4 py-2 text-sm text-blue-600 hover:text-blue-700 border-t border-gray-100"
|
||||
onClick={() => {
|
||||
setAccountsDropdownOpen(false);
|
||||
// Handle add account in a real application
|
||||
}}
|
||||
>
|
||||
<PlusIcon className="h-4 w-4 mr-2" />
|
||||
Add account
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Compose button */}
|
||||
<Button
|
||||
className={`mx-3 mt-3 mb-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 flex items-center justify-center transition-all ${sidebarOpen ? 'py-2 px-4' : 'p-2'}`}
|
||||
onClick={() => setComposeOpen(true)}
|
||||
>
|
||||
{sidebarOpen ? (
|
||||
<div className="flex items-center">
|
||||
<PlusIcon className="h-4 w-4" />
|
||||
<span className="ml-2">Compose</span>
|
||||
</div>
|
||||
) : (
|
||||
<PlusIcon className="h-4 w-4" />
|
||||
)}
|
||||
<div className="w-64 bg-white shadow-sm border-r border-gray-200 p-4">
|
||||
<Button className="w-full mb-4 gap-2">
|
||||
<Mail className="h-4 w-4" />
|
||||
Compose
|
||||
</Button>
|
||||
|
||||
{/* Navigation */}
|
||||
<nav className="flex-1 overflow-y-auto py-2">
|
||||
<ul className="space-y-0.5 px-2">
|
||||
<li>
|
||||
<Button
|
||||
variant={currentView === 'inbox' ? 'secondary' : 'ghost'}
|
||||
className={`w-full justify-start py-2 ${currentView === 'inbox' ? 'bg-gray-100 text-gray-900' : 'text-gray-600 hover:text-gray-900'}`}
|
||||
onClick={() => {setCurrentView('inbox'); setSelectedEmail(null);}}
|
||||
>
|
||||
<Inbox className="h-4 w-4 mr-2" />
|
||||
{sidebarOpen && <span>Inbox</span>}
|
||||
</Button>
|
||||
</li>
|
||||
<li>
|
||||
<Button
|
||||
variant={currentView === 'starred' ? 'secondary' : 'ghost'}
|
||||
className={`w-full justify-start py-2 ${currentView === 'starred' ? 'bg-gray-100 text-gray-900' : 'text-gray-600 hover:text-gray-900'}`}
|
||||
onClick={() => {setCurrentView('starred'); setSelectedEmail(null);}}
|
||||
>
|
||||
<Star className="h-4 w-4 mr-2" />
|
||||
{sidebarOpen && <span>Starred</span>}
|
||||
</Button>
|
||||
</li>
|
||||
<li>
|
||||
<Button
|
||||
variant={currentView === 'sent' ? 'secondary' : 'ghost'}
|
||||
className={`w-full justify-start py-2 ${currentView === 'sent' ? 'bg-gray-100 text-gray-900' : 'text-gray-600 hover:text-gray-900'}`}
|
||||
onClick={() => {setCurrentView('sent'); setSelectedEmail(null);}}
|
||||
>
|
||||
<Send className="h-4 w-4 mr-2" />
|
||||
{sidebarOpen && <span>Sent</span>}
|
||||
</Button>
|
||||
</li>
|
||||
<li>
|
||||
<Button
|
||||
variant={currentView === 'trash' ? 'secondary' : 'ghost'}
|
||||
className={`w-full justify-start py-2 ${currentView === 'trash' ? 'bg-gray-100 text-gray-900' : 'text-gray-600 hover:text-gray-900'}`}
|
||||
onClick={() => {setCurrentView('trash'); setSelectedEmail(null);}}
|
||||
>
|
||||
<Trash className="h-4 w-4 mr-2" />
|
||||
{sidebarOpen && <span>Trash</span>}
|
||||
</Button>
|
||||
</li>
|
||||
|
||||
{/* Folders Section */}
|
||||
<li className="mt-4">
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="w-full justify-between py-2 text-gray-600 hover:text-gray-900"
|
||||
onClick={() => setFoldersDropdownOpen(!foldersDropdownOpen)}
|
||||
>
|
||||
<div className="flex items-center">
|
||||
<Folder className="h-4 w-4 mr-2" />
|
||||
{sidebarOpen && <span>Folders</span>}
|
||||
</div>
|
||||
{sidebarOpen && (foldersDropdownOpen ? <ChevronUp className="h-4 w-4" /> : <ChevronDown className="h-4 w-4" />)}
|
||||
</Button>
|
||||
|
||||
{/* Folders Dropdown */}
|
||||
{foldersDropdownOpen && sidebarOpen && (
|
||||
<ul className="mt-1 space-y-1">
|
||||
{folders.map(folder => (
|
||||
<li key={folder.id}>
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="w-full justify-start py-1.5 pl-8 text-sm text-gray-600 hover:text-gray-900"
|
||||
onClick={() => {
|
||||
setCurrentView(folder.name.toLowerCase());
|
||||
setSelectedEmail(null);
|
||||
}}
|
||||
>
|
||||
{folder.name}
|
||||
</Button>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<nav className="space-y-1">
|
||||
<Button variant="ghost" className="w-full justify-start gap-2">
|
||||
<Inbox className="h-4 w-4" />
|
||||
Inbox
|
||||
</Button>
|
||||
<Button variant="ghost" className="w-full justify-start gap-2">
|
||||
<Star className="h-4 w-4" />
|
||||
Starred
|
||||
</Button>
|
||||
<Button variant="ghost" className="w-full justify-start gap-2">
|
||||
<Send className="h-4 w-4" />
|
||||
Sent
|
||||
</Button>
|
||||
<Button variant="ghost" className="w-full justify-start gap-2">
|
||||
<Archive className="h-4 w-4" />
|
||||
Archive
|
||||
</Button>
|
||||
<Button variant="ghost" className="w-full justify-start gap-2">
|
||||
<Trash className="h-4 w-4" />
|
||||
Trash
|
||||
</Button>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
{/* Main content */}
|
||||
<div className="flex-1 flex overflow-hidden">
|
||||
{/* Email list */}
|
||||
<div className="w-[380px] bg-white/95 backdrop-blur-sm border-r border-gray-100 overflow-y-auto">
|
||||
<div className="p-4 border-b border-gray-100 flex justify-between items-center">
|
||||
<div className="flex items-center gap-4">
|
||||
{filteredEmails.length > 0 && (
|
||||
<Checkbox
|
||||
checked={selectedEmails.length === filteredEmails.length}
|
||||
onCheckedChange={toggleSelectAll}
|
||||
{/* Main Content */}
|
||||
<div className="flex-1 flex flex-col">
|
||||
<header className="bg-white shadow-sm border-b border-gray-200 p-4">
|
||||
<div className="flex items-center">
|
||||
<div className="flex-1">
|
||||
<div className="relative">
|
||||
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 h-4 w-4" />
|
||||
<Input
|
||||
type="search"
|
||||
placeholder="Search mail..."
|
||||
className="w-full pl-10"
|
||||
/>
|
||||
)}
|
||||
<h2 className="text-lg font-semibold text-gray-800 capitalize">
|
||||
{currentView === 'starred' ? 'Starred' : currentView}
|
||||
</h2>
|
||||
</div>
|
||||
<div className="text-sm text-gray-500">
|
||||
{filteredEmails.length} emails
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{/* Bulk Actions Bar */}
|
||||
{showBulkActions && selectedEmails.length > 0 && (
|
||||
<div className="p-2 bg-gray-50 border-b border-gray-100 flex items-center justify-between">
|
||||
<span className="text-sm text-gray-600">{selectedEmails.length} selected</span>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="text-gray-600 hover:text-gray-900"
|
||||
onClick={() => {
|
||||
// Handle move to folder
|
||||
}}
|
||||
>
|
||||
<FolderOpen className="h-4 w-4 mr-2" />
|
||||
Move to
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="text-red-600 hover:text-red-700"
|
||||
onClick={handleBulkDelete}
|
||||
>
|
||||
<Trash2 className="h-4 w-4 mr-2" />
|
||||
Delete
|
||||
</Button>
|
||||
</div>
|
||||
<main className="flex-1 overflow-auto p-4">
|
||||
{loading ? (
|
||||
<div className="flex items-center justify-center h-full">
|
||||
<p className="text-gray-500">Loading emails...</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{filteredEmails.length > 0 ? (
|
||||
<ul>
|
||||
{filteredEmails.map(email => (
|
||||
<li
|
||||
key={email.id}
|
||||
className={`border-b border-gray-100 cursor-pointer ${email.read ? 'bg-white/95' : 'bg-blue-50/95'} hover:bg-gray-50/95`}
|
||||
onClick={() => handleEmailClick(email.id)}
|
||||
>
|
||||
<div className="p-4">
|
||||
<div className="flex justify-between items-start mb-1">
|
||||
<div className="flex items-center gap-3">
|
||||
<Checkbox
|
||||
checked={selectedEmails.includes(email.id)}
|
||||
onClick={(e) => toggleEmailSelection(email.id, e)}
|
||||
/>
|
||||
<div className="flex items-center">
|
||||
<div className={`w-2 h-2 rounded-full ${!email.read ? 'bg-blue-600' : 'bg-transparent'} mr-2`}></div>
|
||||
<span className={`font-medium ${!email.read ? 'font-semibold' : ''} text-gray-900`}>{email.fromName}</span>
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-2">
|
||||
{emails.map((email) => (
|
||||
<Card key={email.id} className={`p-4 hover:bg-gray-50 cursor-pointer ${!email.read ? 'bg-blue-50' : ''}`}>
|
||||
<div className="flex items-center gap-4">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-4 w-4 p-0"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
// TODO: Implement star functionality
|
||||
}}
|
||||
>
|
||||
<Star className={`h-4 w-4 ${email.starred ? 'fill-yellow-400 text-yellow-400' : 'text-gray-400'}`} />
|
||||
</Button>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="flex items-center gap-2">
|
||||
<p className="font-medium truncate">{email.fromName}</p>
|
||||
<span className="text-sm text-gray-500">
|
||||
{new Date(email.date).toLocaleDateString()}
|
||||
</span>
|
||||
</div>
|
||||
<div className="text-xs text-gray-500">{formatDate(email.date)}</div>
|
||||
<p className="text-sm font-medium truncate">{email.subject}</p>
|
||||
<p className="text-sm text-gray-500 truncate">{email.body}</p>
|
||||
</div>
|
||||
<div className="flex justify-between items-center mb-1">
|
||||
<h3 className={`${!email.read ? 'font-semibold' : ''} text-gray-800`}>{email.subject}</h3>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="text-gray-400 hover:text-yellow-500"
|
||||
onClick={(e) => toggleStarred(email.id, e)}
|
||||
>
|
||||
<Star className="h-4 w-4" fill={email.starred ? 'currentColor' : 'none'} color={email.starred ? '#F59E0B' : 'currentColor'} />
|
||||
</Button>
|
||||
</div>
|
||||
<p className="text-sm text-gray-600 truncate">
|
||||
{email.body}
|
||||
</p>
|
||||
</div>
|
||||
</li>
|
||||
</Card>
|
||||
))}
|
||||
</ul>
|
||||
) : (
|
||||
<div className="flex flex-col items-center justify-center h-64 text-gray-500">
|
||||
<Mail className="h-12 w-12 mb-4 opacity-30" />
|
||||
<p>No emails in this folder</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Email detail view - Always visible */}
|
||||
<div className="flex-1 overflow-y-auto bg-white">
|
||||
{selectedEmail ? (
|
||||
<div className="h-full flex flex-col">
|
||||
{/* Email actions header */}
|
||||
<div className="p-4 border-b border-gray-100 flex items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="text-gray-700 hover:bg-gray-100 hover:text-gray-900"
|
||||
>
|
||||
<Reply className="h-4 w-4 mr-2" />
|
||||
Reply
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="text-gray-700 hover:bg-gray-100 hover:text-gray-900"
|
||||
>
|
||||
<ReplyAll className="h-4 w-4 mr-2" />
|
||||
Reply all
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="text-gray-700 hover:bg-gray-100 hover:text-gray-900"
|
||||
>
|
||||
<Forward className="h-4 w-4 mr-2" />
|
||||
Forward
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="text-gray-500 hover:text-gray-700"
|
||||
onClick={() => setShowEmailActions(!showEmailActions)}
|
||||
>
|
||||
<MoreHorizontal className="h-4 w-4" />
|
||||
</Button>
|
||||
{showEmailActions && (
|
||||
<div className="absolute right-4 mt-32 w-48 bg-white border border-gray-100 shadow-lg rounded-lg z-50">
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="w-full justify-start px-4 py-2 text-sm text-gray-600 hover:text-gray-900"
|
||||
onClick={() => {
|
||||
// Handle move to folder
|
||||
setShowEmailActions(false);
|
||||
}}
|
||||
>
|
||||
<FolderOpen className="h-4 w-4 mr-2" />
|
||||
Move to folder
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="w-full justify-start px-4 py-2 text-sm text-red-600 hover:text-red-700"
|
||||
onClick={() => {
|
||||
// Handle delete email
|
||||
setShowEmailActions(false);
|
||||
}}
|
||||
>
|
||||
<Trash2 className="h-4 w-4 mr-2" />
|
||||
Delete
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Email content */}
|
||||
<div className="flex-1 p-6">
|
||||
<div className="max-w-3xl mx-auto">
|
||||
{getSelectedEmail() && (
|
||||
<>
|
||||
<div className="mb-6">
|
||||
<div className="flex justify-between items-center mb-4">
|
||||
<h1 className="text-xl font-bold">{getSelectedEmail()?.subject}</h1>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="text-gray-400 hover:text-yellow-400"
|
||||
onClick={(e) => getSelectedEmail() && toggleStarred(getSelectedEmail()!.id, e)}
|
||||
>
|
||||
<Star className="h-5 w-5" fill={getSelectedEmail()?.starred ? 'currentColor' : 'none'} />
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center">
|
||||
<Avatar>
|
||||
<AvatarFallback className={`${getAccountColor(getSelectedEmail()!.accountId)}`}>
|
||||
{getSelectedEmail()?.fromName.charAt(0)}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
<div className="ml-3">
|
||||
<div className="font-medium">{getSelectedEmail()?.fromName}</div>
|
||||
<div className="text-sm text-gray-500 flex items-center">
|
||||
<span>{getSelectedEmail()?.from}</span>
|
||||
<span className="mx-2">•</span>
|
||||
<span>{new Date(getSelectedEmail()!.date).toLocaleString([], { dateStyle: 'medium', timeStyle: 'short' })}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="border-t border-gray-200 pt-6 prose max-w-none">
|
||||
<p>{getSelectedEmail()?.body}</p>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="h-full flex items-center justify-center">
|
||||
<div className="text-center">
|
||||
<Mail className="h-16 w-16 mx-auto mb-4 text-gray-300" />
|
||||
<p className="text-gray-500">No email selected</p>
|
||||
<p className="text-sm text-gray-400">Choose an email from the list to read its contents</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
{/* Compose email modal */}
|
||||
{composeOpen && (
|
||||
<div className="fixed inset-0 bg-black/25 backdrop-blur-sm flex items-center justify-center p-4 z-50">
|
||||
<Card className="w-full max-w-2xl bg-white max-h-[90vh] flex flex-col">
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2 border-b">
|
||||
<CardTitle className="text-xl">New Message</CardTitle>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="text-gray-500 hover:text-gray-700"
|
||||
onClick={() => setComposeOpen(false)}
|
||||
>
|
||||
<X className="h-4 w-4" />
|
||||
</Button>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-3 overflow-y-auto flex-1 pt-2">
|
||||
<div className="space-y-2 border-b border-gray-100 pb-3">
|
||||
<div>
|
||||
<Label className="text-sm text-gray-700 mb-0.5">From</Label>
|
||||
<select className="w-full bg-white border border-gray-200 rounded-lg px-3 py-1.5 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent">
|
||||
{accounts.map(account => (
|
||||
<option key={account.id} value={account.id}>
|
||||
{account.name} ({account.email})
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<div className="flex items-center justify-between mb-0.5">
|
||||
<Label className="text-sm text-gray-700">To</Label>
|
||||
<div className="flex items-center gap-2">
|
||||
{!showCc && (
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="h-6 text-xs text-gray-500 hover:text-gray-700"
|
||||
onClick={() => setShowCc(true)}
|
||||
>
|
||||
Add Cc
|
||||
</Button>
|
||||
)}
|
||||
{!showBcc && (
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="h-6 text-xs text-gray-500 hover:text-gray-700"
|
||||
onClick={() => setShowBcc(true)}
|
||||
>
|
||||
Add Bcc
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<Input
|
||||
type="email"
|
||||
placeholder="email@example.com"
|
||||
className="bg-white border-gray-200 py-1.5"
|
||||
/>
|
||||
</div>
|
||||
{showCc && (
|
||||
<div>
|
||||
<div className="flex items-center justify-between mb-0.5">
|
||||
<Label className="text-sm text-gray-700">Cc</Label>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="h-6 text-xs text-gray-500 hover:text-gray-700"
|
||||
onClick={() => setShowCc(false)}
|
||||
>
|
||||
Remove
|
||||
</Button>
|
||||
</div>
|
||||
<Input
|
||||
type="email"
|
||||
placeholder="cc@example.com"
|
||||
className="bg-white border-gray-200 py-1.5"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{showBcc && (
|
||||
<div>
|
||||
<div className="flex items-center justify-between mb-0.5">
|
||||
<Label className="text-sm text-gray-700">Bcc</Label>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="h-6 text-xs text-gray-500 hover:text-gray-700"
|
||||
onClick={() => setShowBcc(false)}
|
||||
>
|
||||
Remove
|
||||
</Button>
|
||||
</div>
|
||||
<Input
|
||||
type="email"
|
||||
placeholder="bcc@example.com"
|
||||
className="bg-white border-gray-200 py-1.5"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<Label className="text-sm text-gray-700 mb-0.5">Subject</Label>
|
||||
<Input
|
||||
type="text"
|
||||
placeholder="Subject"
|
||||
className="bg-white border-gray-200 py-1.5"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex-1">
|
||||
<Label className="text-sm text-gray-700 mb-0.5">Message</Label>
|
||||
<Textarea
|
||||
className="mt-0.5 h-[calc(100%-1.5rem)] min-h-[200px] bg-white border-gray-200 resize-none"
|
||||
placeholder="Write your message here..."
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* File Attachment Section */}
|
||||
<div className="border-t border-gray-100 pt-3">
|
||||
<div className="flex items-center gap-4">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="border border-gray-200 text-blue-600 hover:bg-blue-50 hover:text-blue-700"
|
||||
onClick={() => document.getElementById('file-upload')?.click()}
|
||||
>
|
||||
<Paperclip className="h-4 w-4 mr-2" />
|
||||
Attach files
|
||||
</Button>
|
||||
<span className="text-xs text-gray-500">Maximum file size: 25 MB</span>
|
||||
</div>
|
||||
<input
|
||||
type="file"
|
||||
id="file-upload"
|
||||
multiple
|
||||
className="hidden"
|
||||
onChange={(e) => {
|
||||
// Handle file upload
|
||||
console.log(e.target.files);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end gap-3 pt-3 border-t border-gray-100">
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="border border-gray-200 text-blue-600 hover:bg-blue-50 hover:text-blue-700"
|
||||
onClick={() => setComposeOpen(false)}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
className="bg-blue-600 text-white hover:bg-blue-700"
|
||||
onClick={() => setComposeOpen(false)}
|
||||
>
|
||||
Send
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Delete Confirmation Dialog */}
|
||||
<AlertDialog open={showDeleteConfirm} onOpenChange={setShowDeleteConfirm}>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>Are you sure?</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
{deleteType === 'email' && "This email will be moved to trash."}
|
||||
{deleteType === 'emails' && `${selectedEmails.length} emails will be moved to trash.`}
|
||||
{deleteType === 'account' && "This account will be permanently removed. This action cannot be undone."}
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel onClick={() => setShowDeleteConfirm(false)}>Cancel</AlertDialogCancel>
|
||||
<AlertDialogAction
|
||||
className={deleteType === 'account' ? 'bg-red-600 hover:bg-red-700' : ''}
|
||||
onClick={handleDeleteConfirm}
|
||||
>
|
||||
{deleteType === 'account' ? 'Delete Account' : 'Move to Trash'}
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
</div>
|
||||
);
|
||||
)
|
||||
}
|
||||
406
package-lock.json
generated
406
package-lock.json
generated
@ -38,6 +38,9 @@
|
||||
"@radix-ui/react-toggle": "^1.1.1",
|
||||
"@radix-ui/react-toggle-group": "^1.1.1",
|
||||
"@radix-ui/react-tooltip": "^1.1.6",
|
||||
"@types/imap": "^0.8.42",
|
||||
"@types/mailparser": "^3.4.5",
|
||||
"@types/nodemailer": "^6.4.17",
|
||||
"@types/pg": "^8.11.12",
|
||||
"@types/react-datepicker": "^6.2.0",
|
||||
"autoprefixer": "^10.4.20",
|
||||
@ -47,11 +50,14 @@
|
||||
"date-fns": "^3.6.0",
|
||||
"embla-carousel-react": "8.5.1",
|
||||
"fullcalendar": "^6.1.15",
|
||||
"imap": "^0.8.19",
|
||||
"input-otp": "1.4.1",
|
||||
"lucide-react": "^0.454.0",
|
||||
"mailparser": "^3.7.2",
|
||||
"next": "14.2.24",
|
||||
"next-auth": "^4.24.11",
|
||||
"next-themes": "^0.4.4",
|
||||
"nodemailer": "^6.10.1",
|
||||
"pg": "^8.14.1",
|
||||
"react": "^18",
|
||||
"react-datepicker": "^8.3.0",
|
||||
@ -2722,6 +2728,19 @@
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.0.tgz",
|
||||
"integrity": "sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg=="
|
||||
},
|
||||
"node_modules/@selderee/plugin-htmlparser2": {
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.11.0.tgz",
|
||||
"integrity": "sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"domhandler": "^5.0.3",
|
||||
"selderee": "^0.11.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://ko-fi.com/killymxi"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/counter": {
|
||||
"version": "0.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz",
|
||||
@ -2790,6 +2809,25 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz",
|
||||
"integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw=="
|
||||
},
|
||||
"node_modules/@types/imap": {
|
||||
"version": "0.8.42",
|
||||
"resolved": "https://registry.npmjs.org/@types/imap/-/imap-0.8.42.tgz",
|
||||
"integrity": "sha512-FusePG9Cp2GYN6OLow9xBCkjznFkAR7WCz0Fm+j1p/ER6C8V8P71DtjpSmwrZsS7zekCeqdTPHEk9N5OgPwcsg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/mailparser": {
|
||||
"version": "3.4.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/mailparser/-/mailparser-3.4.5.tgz",
|
||||
"integrity": "sha512-EPERBp7fLeFZh7tS2X36MF7jawUx3Y6/0rXciZah3CTYgwLi3e0kpGUJ6FOmUabgzis/U1g+3/JzrVWbWIOGjg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*",
|
||||
"iconv-lite": "^0.6.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.10.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.5.tgz",
|
||||
@ -2798,6 +2836,15 @@
|
||||
"undici-types": "~6.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/nodemailer": {
|
||||
"version": "6.4.17",
|
||||
"resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.17.tgz",
|
||||
"integrity": "sha512-I9CCaIp6DTldEg7vyUTZi8+9Vo0hi1/T8gv3C89yk1rSAAzoKQ8H8ki/jBYJSFoH/BisgLP8tkZMlQ91CIquww==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/pg": {
|
||||
"version": "8.11.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.11.12.tgz",
|
||||
@ -3144,6 +3191,12 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/core-util-is": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
|
||||
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||
@ -3316,6 +3369,15 @@
|
||||
"resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz",
|
||||
"integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg=="
|
||||
},
|
||||
"node_modules/deepmerge": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
|
||||
"integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/detect-node-es": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
|
||||
@ -3340,6 +3402,61 @@
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/dom-serializer": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
|
||||
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.3.0",
|
||||
"domhandler": "^5.0.2",
|
||||
"entities": "^4.2.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/domelementtype": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
|
||||
"integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/fb55"
|
||||
}
|
||||
],
|
||||
"license": "BSD-2-Clause"
|
||||
},
|
||||
"node_modules/domhandler": {
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
|
||||
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/domhandler?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/domutils": {
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
|
||||
"integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==",
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"dom-serializer": "^2.0.0",
|
||||
"domelementtype": "^2.3.0",
|
||||
"domhandler": "^5.0.3"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/domutils?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/eastasianwidth": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
|
||||
@ -3380,6 +3497,27 @@
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
|
||||
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="
|
||||
},
|
||||
"node_modules/encoding-japanese": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/encoding-japanese/-/encoding-japanese-2.2.0.tgz",
|
||||
"integrity": "sha512-EuJWwlHPZ1LbADuKTClvHtwbaFn4rOD+dRAbWysqEOXRc2Uui0hJInNJrsdH0c+OhJA4nrCBdSkW4DD5YxAo6A==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/entities": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
|
||||
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=0.12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.0.tgz",
|
||||
@ -3616,6 +3754,80 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/he": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
|
||||
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"he": "bin/he"
|
||||
}
|
||||
},
|
||||
"node_modules/html-to-text": {
|
||||
"version": "9.0.5",
|
||||
"resolved": "https://registry.npmjs.org/html-to-text/-/html-to-text-9.0.5.tgz",
|
||||
"integrity": "sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@selderee/plugin-htmlparser2": "^0.11.0",
|
||||
"deepmerge": "^4.3.1",
|
||||
"dom-serializer": "^2.0.0",
|
||||
"htmlparser2": "^8.0.2",
|
||||
"selderee": "^0.11.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/htmlparser2": {
|
||||
"version": "8.0.2",
|
||||
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz",
|
||||
"integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==",
|
||||
"funding": [
|
||||
"https://github.com/fb55/htmlparser2?sponsor=1",
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/fb55"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.3.0",
|
||||
"domhandler": "^5.0.3",
|
||||
"domutils": "^3.0.1",
|
||||
"entities": "^4.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/iconv-lite": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
||||
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/imap": {
|
||||
"version": "0.8.19",
|
||||
"resolved": "https://registry.npmjs.org/imap/-/imap-0.8.19.tgz",
|
||||
"integrity": "sha512-z5DxEA1uRnZG73UcPA4ES5NSCGnPuuouUx43OPX7KZx1yzq3N8/vx2mtXEShT5inxB3pRgnfG1hijfu7XN2YMw==",
|
||||
"dependencies": {
|
||||
"readable-stream": "1.1.x",
|
||||
"utf7": ">=1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/input-otp": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/input-otp/-/input-otp-1.4.1.tgz",
|
||||
@ -3693,6 +3905,12 @@
|
||||
"node": ">=0.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/isarray": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
|
||||
"integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/isexe": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||
@ -3734,6 +3952,39 @@
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
|
||||
},
|
||||
"node_modules/leac": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/leac/-/leac-0.6.0.tgz",
|
||||
"integrity": "sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://ko-fi.com/killymxi"
|
||||
}
|
||||
},
|
||||
"node_modules/libbase64": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/libbase64/-/libbase64-1.3.0.tgz",
|
||||
"integrity": "sha512-GgOXd0Eo6phYgh0DJtjQ2tO8dc0IVINtZJeARPeiIJqge+HdsWSuaDTe8ztQ7j/cONByDZ3zeB325AHiv5O0dg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/libmime": {
|
||||
"version": "5.3.6",
|
||||
"resolved": "https://registry.npmjs.org/libmime/-/libmime-5.3.6.tgz",
|
||||
"integrity": "sha512-j9mBC7eiqi6fgBPAGvKCXJKJSIASanYF4EeA4iBzSG0HxQxmXnR3KbyWqTn4CwsKSebqCv2f5XZfAO6sKzgvwA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"encoding-japanese": "2.2.0",
|
||||
"iconv-lite": "0.6.3",
|
||||
"libbase64": "1.3.0",
|
||||
"libqp": "2.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/libqp": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/libqp/-/libqp-2.1.1.tgz",
|
||||
"integrity": "sha512-0Wd+GPz1O134cP62YU2GTOPNA7Qgl09XwCqM5zpBv87ERCXdfDtyKXvV7c9U22yWJh44QZqBocFnXN11K96qow==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lilconfig": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",
|
||||
@ -3750,6 +4001,15 @@
|
||||
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
|
||||
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
|
||||
},
|
||||
"node_modules/linkify-it": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz",
|
||||
"integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"uc.micro": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
@ -3779,6 +4039,44 @@
|
||||
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc"
|
||||
}
|
||||
},
|
||||
"node_modules/mailparser": {
|
||||
"version": "3.7.2",
|
||||
"resolved": "https://registry.npmjs.org/mailparser/-/mailparser-3.7.2.tgz",
|
||||
"integrity": "sha512-iI0p2TCcIodR1qGiRoDBBwboSSff50vQAWytM5JRggLfABa4hHYCf3YVujtuzV454xrOP352VsAPIzviqMTo4Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"encoding-japanese": "2.2.0",
|
||||
"he": "1.2.0",
|
||||
"html-to-text": "9.0.5",
|
||||
"iconv-lite": "0.6.3",
|
||||
"libmime": "5.3.6",
|
||||
"linkify-it": "5.0.0",
|
||||
"mailsplit": "5.4.2",
|
||||
"nodemailer": "6.9.16",
|
||||
"punycode.js": "2.3.1",
|
||||
"tlds": "1.255.0"
|
||||
}
|
||||
},
|
||||
"node_modules/mailparser/node_modules/nodemailer": {
|
||||
"version": "6.9.16",
|
||||
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.16.tgz",
|
||||
"integrity": "sha512-psAuZdTIRN08HKVd/E8ObdV6NO7NTBY3KsC30F7M4H1OnmLCUNaS56FpYxyb26zWLSyYF9Ozch9KYHhHegsiOQ==",
|
||||
"license": "MIT-0",
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/mailsplit": {
|
||||
"version": "5.4.2",
|
||||
"resolved": "https://registry.npmjs.org/mailsplit/-/mailsplit-5.4.2.tgz",
|
||||
"integrity": "sha512-4cczG/3Iu3pyl8JgQ76dKkisurZTmxMrA4dj/e8d2jKYcFTZ7MxOzg1gTioTDMPuFXwTrVuN/gxhkrO7wLg7qA==",
|
||||
"license": "(MIT OR EUPL-1.1+)",
|
||||
"dependencies": {
|
||||
"libbase64": "1.3.0",
|
||||
"libmime": "5.3.6",
|
||||
"libqp": "2.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/merge2": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
|
||||
@ -3978,6 +4276,15 @@
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
|
||||
"integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw=="
|
||||
},
|
||||
"node_modules/nodemailer": {
|
||||
"version": "6.10.1",
|
||||
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.10.1.tgz",
|
||||
"integrity": "sha512-Z+iLaBGVaSjbIzQ4pX6XV41HrooLsQ10ZWPUehGmuantvzWoDVBnmsdUcOIDM1t+yPor5pDhVlDESgOMEGxhHA==",
|
||||
"license": "MIT-0",
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/normalize-path": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||
@ -4072,6 +4379,19 @@
|
||||
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
|
||||
"integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="
|
||||
},
|
||||
"node_modules/parseley": {
|
||||
"version": "0.12.1",
|
||||
"resolved": "https://registry.npmjs.org/parseley/-/parseley-0.12.1.tgz",
|
||||
"integrity": "sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"leac": "^0.6.0",
|
||||
"peberminta": "^0.9.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://ko-fi.com/killymxi"
|
||||
}
|
||||
},
|
||||
"node_modules/path-key": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
||||
@ -4100,6 +4420,15 @@
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/peberminta": {
|
||||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/peberminta/-/peberminta-0.9.0.tgz",
|
||||
"integrity": "sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://ko-fi.com/killymxi"
|
||||
}
|
||||
},
|
||||
"node_modules/pg": {
|
||||
"version": "8.14.1",
|
||||
"resolved": "https://registry.npmjs.org/pg/-/pg-8.14.1.tgz",
|
||||
@ -4541,6 +4870,15 @@
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||
},
|
||||
"node_modules/punycode.js": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz",
|
||||
"integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/queue-microtask": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||
@ -4776,6 +5114,18 @@
|
||||
"pify": "^2.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/readable-stream": {
|
||||
"version": "1.1.14",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
|
||||
"integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"core-util-is": "~1.0.0",
|
||||
"inherits": "~2.0.1",
|
||||
"isarray": "0.0.1",
|
||||
"string_decoder": "~0.10.x"
|
||||
}
|
||||
},
|
||||
"node_modules/readdirp": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||
@ -4872,6 +5222,12 @@
|
||||
"queue-microtask": "^1.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/scheduler": {
|
||||
"version": "0.23.2",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
|
||||
@ -4880,6 +5236,27 @@
|
||||
"loose-envify": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/selderee": {
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/selderee/-/selderee-0.11.0.tgz",
|
||||
"integrity": "sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"parseley": "^0.12.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://ko-fi.com/killymxi"
|
||||
}
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
|
||||
"integrity": "sha512-mfmm3/H9+67MCVix1h+IXTpDwL6710LyHuk7+cWC9T1mE0qz4iHhh6r4hU2wrIT9iTsAAC2XQRvfblL028cpLw==",
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"semver": "bin/semver"
|
||||
}
|
||||
},
|
||||
"node_modules/shebang-command": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||
@ -4944,6 +5321,12 @@
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/string_decoder": {
|
||||
"version": "0.10.31",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
|
||||
"integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/string-width": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
|
||||
@ -5169,6 +5552,15 @@
|
||||
"resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz",
|
||||
"integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg=="
|
||||
},
|
||||
"node_modules/tlds": {
|
||||
"version": "1.255.0",
|
||||
"resolved": "https://registry.npmjs.org/tlds/-/tlds-1.255.0.tgz",
|
||||
"integrity": "sha512-tcwMRIioTcF/FcxLev8MJWxCp+GUALRhFEqbDoZrnowmKSGqPrl5pqS+Sut2m8BgJ6S4FExCSSpGffZ0Tks6Aw==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"tlds": "bin.js"
|
||||
}
|
||||
},
|
||||
"node_modules/to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
@ -5203,6 +5595,12 @@
|
||||
"node": ">=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/uc.micro": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz",
|
||||
"integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "6.20.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz",
|
||||
@ -5286,6 +5684,14 @@
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/utf7": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/utf7/-/utf7-1.0.2.tgz",
|
||||
"integrity": "sha512-qQrPtYLLLl12NF4DrM9CvfkxkYI97xOb5dsnGZHE3teFr0tWiEZ9UdgMPczv24vl708cYMpe6mGXGHrotIp3Bw==",
|
||||
"dependencies": {
|
||||
"semver": "~5.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
|
||||
@ -39,6 +39,9 @@
|
||||
"@radix-ui/react-toggle": "^1.1.1",
|
||||
"@radix-ui/react-toggle-group": "^1.1.1",
|
||||
"@radix-ui/react-tooltip": "^1.1.6",
|
||||
"@types/imap": "^0.8.42",
|
||||
"@types/mailparser": "^3.4.5",
|
||||
"@types/nodemailer": "^6.4.17",
|
||||
"@types/pg": "^8.11.12",
|
||||
"@types/react-datepicker": "^6.2.0",
|
||||
"autoprefixer": "^10.4.20",
|
||||
@ -48,11 +51,14 @@
|
||||
"date-fns": "^3.6.0",
|
||||
"embla-carousel-react": "8.5.1",
|
||||
"fullcalendar": "^6.1.15",
|
||||
"imap": "^0.8.19",
|
||||
"input-otp": "1.4.1",
|
||||
"lucide-react": "^0.454.0",
|
||||
"mailparser": "^3.7.2",
|
||||
"next": "14.2.24",
|
||||
"next-auth": "^4.24.11",
|
||||
"next-themes": "^0.4.4",
|
||||
"nodemailer": "^6.10.1",
|
||||
"pg": "^8.14.1",
|
||||
"react": "^18",
|
||||
"react-datepicker": "^8.3.0",
|
||||
|
||||
280
yarn.lock
280
yarn.lock
@ -19,11 +19,6 @@
|
||||
resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.0.tgz"
|
||||
integrity sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==
|
||||
|
||||
"@esbuild/linux-arm64@0.25.0":
|
||||
version "0.25.0"
|
||||
resolved "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.0.tgz"
|
||||
integrity sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==
|
||||
|
||||
"@floating-ui/core@^1.6.0":
|
||||
version "1.6.9"
|
||||
resolved "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.9.tgz"
|
||||
@ -169,16 +164,6 @@
|
||||
resolved "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.24.tgz"
|
||||
integrity sha512-7Tdi13aojnAZGpapVU6meVSpNzgrFwZ8joDcNS8cJVNuP3zqqrLqeory9Xec5TJZR/stsGJdfwo8KeyloT3+rQ==
|
||||
|
||||
"@next/swc-linux-arm64-gnu@14.2.24":
|
||||
version "14.2.24"
|
||||
resolved "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.24.tgz"
|
||||
integrity sha512-nxvJgWOpSNmzidYvvGDfXwxkijb6hL9+cjZx1PVG6urr2h2jUqBALkKjT7kpfurRWicK6hFOvarmaWsINT1hnA==
|
||||
|
||||
"@next/swc-linux-arm64-musl@14.2.24":
|
||||
version "14.2.24"
|
||||
resolved "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.24.tgz"
|
||||
integrity sha512-PaBgOPhqa4Abxa3y/P92F3kklNPsiFjcjldQGT7kFmiY5nuFn8ClBEoX8GIpqU1ODP2y8P6hio6vTomx2Vy0UQ==
|
||||
|
||||
"@nodelib/fs.scandir@2.1.5":
|
||||
version "2.1.5"
|
||||
resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz"
|
||||
@ -950,6 +935,14 @@
|
||||
resolved "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.0.tgz"
|
||||
integrity sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==
|
||||
|
||||
"@selderee/plugin-htmlparser2@^0.11.0":
|
||||
version "0.11.0"
|
||||
resolved "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.11.0.tgz"
|
||||
integrity sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==
|
||||
dependencies:
|
||||
domhandler "^5.0.3"
|
||||
selderee "^0.11.0"
|
||||
|
||||
"@swc/counter@^0.1.3":
|
||||
version "0.1.3"
|
||||
resolved "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz"
|
||||
@ -1014,6 +1007,21 @@
|
||||
resolved "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz"
|
||||
integrity sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==
|
||||
|
||||
"@types/imap@^0.8.42":
|
||||
version "0.8.42"
|
||||
resolved "https://registry.npmjs.org/@types/imap/-/imap-0.8.42.tgz"
|
||||
integrity sha512-FusePG9Cp2GYN6OLow9xBCkjznFkAR7WCz0Fm+j1p/ER6C8V8P71DtjpSmwrZsS7zekCeqdTPHEk9N5OgPwcsg==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/mailparser@^3.4.5":
|
||||
version "3.4.5"
|
||||
resolved "https://registry.npmjs.org/@types/mailparser/-/mailparser-3.4.5.tgz"
|
||||
integrity sha512-EPERBp7fLeFZh7tS2X36MF7jawUx3Y6/0rXciZah3CTYgwLi3e0kpGUJ6FOmUabgzis/U1g+3/JzrVWbWIOGjg==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
iconv-lite "^0.6.3"
|
||||
|
||||
"@types/node@*", "@types/node@^22":
|
||||
version "22.10.5"
|
||||
resolved "https://registry.npmjs.org/@types/node/-/node-22.10.5.tgz"
|
||||
@ -1021,6 +1029,13 @@
|
||||
dependencies:
|
||||
undici-types "~6.20.0"
|
||||
|
||||
"@types/nodemailer@^6.4.17":
|
||||
version "6.4.17"
|
||||
resolved "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.17.tgz"
|
||||
integrity sha512-I9CCaIp6DTldEg7vyUTZi8+9Vo0hi1/T8gv3C89yk1rSAAzoKQ8H8ki/jBYJSFoH/BisgLP8tkZMlQ91CIquww==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/pg@^8.11.12":
|
||||
version "8.11.12"
|
||||
resolved "https://registry.npmjs.org/@types/pg/-/pg-8.11.12.tgz"
|
||||
@ -1231,6 +1246,11 @@ cookie@^0.7.0:
|
||||
resolved "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz"
|
||||
integrity sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==
|
||||
|
||||
core-util-is@~1.0.0:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz"
|
||||
integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==
|
||||
|
||||
cross-spawn@^7.0.0:
|
||||
version "7.0.6"
|
||||
resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz"
|
||||
@ -1343,6 +1363,11 @@ decimal.js-light@^2.4.1:
|
||||
resolved "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz"
|
||||
integrity sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==
|
||||
|
||||
deepmerge@^4.3.1:
|
||||
version "4.3.1"
|
||||
resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz"
|
||||
integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==
|
||||
|
||||
detect-node-es@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz"
|
||||
@ -1366,6 +1391,36 @@ dom-helpers@^5.0.1:
|
||||
"@babel/runtime" "^7.8.7"
|
||||
csstype "^3.0.2"
|
||||
|
||||
dom-serializer@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz"
|
||||
integrity sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==
|
||||
dependencies:
|
||||
domelementtype "^2.3.0"
|
||||
domhandler "^5.0.2"
|
||||
entities "^4.2.0"
|
||||
|
||||
domelementtype@^2.3.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz"
|
||||
integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==
|
||||
|
||||
domhandler@^5.0.2, domhandler@^5.0.3:
|
||||
version "5.0.3"
|
||||
resolved "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz"
|
||||
integrity sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==
|
||||
dependencies:
|
||||
domelementtype "^2.3.0"
|
||||
|
||||
domutils@^3.0.1:
|
||||
version "3.2.2"
|
||||
resolved "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz"
|
||||
integrity sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==
|
||||
dependencies:
|
||||
dom-serializer "^2.0.0"
|
||||
domelementtype "^2.3.0"
|
||||
domhandler "^5.0.3"
|
||||
|
||||
eastasianwidth@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz"
|
||||
@ -1404,6 +1459,16 @@ emoji-regex@^9.2.2:
|
||||
resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz"
|
||||
integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==
|
||||
|
||||
encoding-japanese@2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.npmjs.org/encoding-japanese/-/encoding-japanese-2.2.0.tgz"
|
||||
integrity sha512-EuJWwlHPZ1LbADuKTClvHtwbaFn4rOD+dRAbWysqEOXRc2Uui0hJInNJrsdH0c+OhJA4nrCBdSkW4DD5YxAo6A==
|
||||
|
||||
entities@^4.2.0, entities@^4.4.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz"
|
||||
integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==
|
||||
|
||||
esbuild-register@3.6.0:
|
||||
version "3.6.0"
|
||||
resolved "https://registry.npmjs.org/esbuild-register/-/esbuild-register-3.6.0.tgz"
|
||||
@ -1567,6 +1632,52 @@ hasown@^2.0.2:
|
||||
dependencies:
|
||||
function-bind "^1.1.2"
|
||||
|
||||
he@1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.npmjs.org/he/-/he-1.2.0.tgz"
|
||||
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
|
||||
|
||||
html-to-text@9.0.5:
|
||||
version "9.0.5"
|
||||
resolved "https://registry.npmjs.org/html-to-text/-/html-to-text-9.0.5.tgz"
|
||||
integrity sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==
|
||||
dependencies:
|
||||
"@selderee/plugin-htmlparser2" "^0.11.0"
|
||||
deepmerge "^4.3.1"
|
||||
dom-serializer "^2.0.0"
|
||||
htmlparser2 "^8.0.2"
|
||||
selderee "^0.11.0"
|
||||
|
||||
htmlparser2@^8.0.2:
|
||||
version "8.0.2"
|
||||
resolved "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz"
|
||||
integrity sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==
|
||||
dependencies:
|
||||
domelementtype "^2.3.0"
|
||||
domhandler "^5.0.3"
|
||||
domutils "^3.0.1"
|
||||
entities "^4.4.0"
|
||||
|
||||
iconv-lite@^0.6.3, iconv-lite@0.6.3:
|
||||
version "0.6.3"
|
||||
resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz"
|
||||
integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==
|
||||
dependencies:
|
||||
safer-buffer ">= 2.1.2 < 3.0.0"
|
||||
|
||||
imap@^0.8.19:
|
||||
version "0.8.19"
|
||||
resolved "https://registry.npmjs.org/imap/-/imap-0.8.19.tgz"
|
||||
integrity sha512-z5DxEA1uRnZG73UcPA4ES5NSCGnPuuouUx43OPX7KZx1yzq3N8/vx2mtXEShT5inxB3pRgnfG1hijfu7XN2YMw==
|
||||
dependencies:
|
||||
readable-stream "1.1.x"
|
||||
utf7 ">=1.0.2"
|
||||
|
||||
inherits@~2.0.1:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz"
|
||||
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
||||
|
||||
input-otp@1.4.1:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.npmjs.org/input-otp/-/input-otp-1.4.1.tgz"
|
||||
@ -1613,6 +1724,11 @@ is-number@^7.0.0:
|
||||
resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz"
|
||||
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
|
||||
|
||||
isarray@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
|
||||
integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==
|
||||
|
||||
isexe@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz"
|
||||
@ -1642,6 +1758,31 @@ jose@^4.15.5, jose@^4.15.9:
|
||||
resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz"
|
||||
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
|
||||
|
||||
leac@^0.6.0:
|
||||
version "0.6.0"
|
||||
resolved "https://registry.npmjs.org/leac/-/leac-0.6.0.tgz"
|
||||
integrity sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==
|
||||
|
||||
libbase64@1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.npmjs.org/libbase64/-/libbase64-1.3.0.tgz"
|
||||
integrity sha512-GgOXd0Eo6phYgh0DJtjQ2tO8dc0IVINtZJeARPeiIJqge+HdsWSuaDTe8ztQ7j/cONByDZ3zeB325AHiv5O0dg==
|
||||
|
||||
libmime@5.3.6:
|
||||
version "5.3.6"
|
||||
resolved "https://registry.npmjs.org/libmime/-/libmime-5.3.6.tgz"
|
||||
integrity sha512-j9mBC7eiqi6fgBPAGvKCXJKJSIASanYF4EeA4iBzSG0HxQxmXnR3KbyWqTn4CwsKSebqCv2f5XZfAO6sKzgvwA==
|
||||
dependencies:
|
||||
encoding-japanese "2.2.0"
|
||||
iconv-lite "0.6.3"
|
||||
libbase64 "1.3.0"
|
||||
libqp "2.1.1"
|
||||
|
||||
libqp@2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.npmjs.org/libqp/-/libqp-2.1.1.tgz"
|
||||
integrity sha512-0Wd+GPz1O134cP62YU2GTOPNA7Qgl09XwCqM5zpBv87ERCXdfDtyKXvV7c9U22yWJh44QZqBocFnXN11K96qow==
|
||||
|
||||
lilconfig@^3.0.0, lilconfig@^3.1.3:
|
||||
version "3.1.3"
|
||||
resolved "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz"
|
||||
@ -1652,6 +1793,13 @@ lines-and-columns@^1.1.6:
|
||||
resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz"
|
||||
integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
|
||||
|
||||
linkify-it@5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz"
|
||||
integrity sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==
|
||||
dependencies:
|
||||
uc.micro "^2.0.0"
|
||||
|
||||
lodash@^4.17.21:
|
||||
version "4.17.21"
|
||||
resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz"
|
||||
@ -1681,6 +1829,31 @@ lucide-react@^0.454.0:
|
||||
resolved "https://registry.npmjs.org/lucide-react/-/lucide-react-0.454.0.tgz"
|
||||
integrity sha512-hw7zMDwykCLnEzgncEEjHeA6+45aeEzRYuKHuyRSOPkhko+J3ySGjGIzu+mmMfDFG1vazHepMaYFYHbTFAZAAQ==
|
||||
|
||||
mailparser@^3.7.2:
|
||||
version "3.7.2"
|
||||
resolved "https://registry.npmjs.org/mailparser/-/mailparser-3.7.2.tgz"
|
||||
integrity sha512-iI0p2TCcIodR1qGiRoDBBwboSSff50vQAWytM5JRggLfABa4hHYCf3YVujtuzV454xrOP352VsAPIzviqMTo4Q==
|
||||
dependencies:
|
||||
encoding-japanese "2.2.0"
|
||||
he "1.2.0"
|
||||
html-to-text "9.0.5"
|
||||
iconv-lite "0.6.3"
|
||||
libmime "5.3.6"
|
||||
linkify-it "5.0.0"
|
||||
mailsplit "5.4.2"
|
||||
nodemailer "6.9.16"
|
||||
punycode.js "2.3.1"
|
||||
tlds "1.255.0"
|
||||
|
||||
mailsplit@5.4.2:
|
||||
version "5.4.2"
|
||||
resolved "https://registry.npmjs.org/mailsplit/-/mailsplit-5.4.2.tgz"
|
||||
integrity sha512-4cczG/3Iu3pyl8JgQ76dKkisurZTmxMrA4dj/e8d2jKYcFTZ7MxOzg1gTioTDMPuFXwTrVuN/gxhkrO7wLg7qA==
|
||||
dependencies:
|
||||
libbase64 "1.3.0"
|
||||
libmime "5.3.6"
|
||||
libqp "2.1.1"
|
||||
|
||||
merge2@^1.3.0:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz"
|
||||
@ -1773,6 +1946,16 @@ node-releases@^2.0.19:
|
||||
resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz"
|
||||
integrity sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==
|
||||
|
||||
nodemailer@^6.10.1, nodemailer@^6.6.5:
|
||||
version "6.10.1"
|
||||
resolved "https://registry.npmjs.org/nodemailer/-/nodemailer-6.10.1.tgz"
|
||||
integrity sha512-Z+iLaBGVaSjbIzQ4pX6XV41HrooLsQ10ZWPUehGmuantvzWoDVBnmsdUcOIDM1t+yPor5pDhVlDESgOMEGxhHA==
|
||||
|
||||
nodemailer@6.9.16:
|
||||
version "6.9.16"
|
||||
resolved "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.16.tgz"
|
||||
integrity sha512-psAuZdTIRN08HKVd/E8ObdV6NO7NTBY3KsC30F7M4H1OnmLCUNaS56FpYxyb26zWLSyYF9Ozch9KYHhHegsiOQ==
|
||||
|
||||
normalize-path@^3.0.0, normalize-path@~3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz"
|
||||
@ -1828,6 +2011,14 @@ package-json-from-dist@^1.0.0:
|
||||
resolved "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz"
|
||||
integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==
|
||||
|
||||
parseley@^0.12.0:
|
||||
version "0.12.1"
|
||||
resolved "https://registry.npmjs.org/parseley/-/parseley-0.12.1.tgz"
|
||||
integrity sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw==
|
||||
dependencies:
|
||||
leac "^0.6.0"
|
||||
peberminta "^0.9.0"
|
||||
|
||||
path-key@^3.1.0:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz"
|
||||
@ -1846,6 +2037,11 @@ path-scurry@^1.11.1:
|
||||
lru-cache "^10.2.0"
|
||||
minipass "^5.0.0 || ^6.0.2 || ^7.0.0"
|
||||
|
||||
peberminta@^0.9.0:
|
||||
version "0.9.0"
|
||||
resolved "https://registry.npmjs.org/peberminta/-/peberminta-0.9.0.tgz"
|
||||
integrity sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==
|
||||
|
||||
pg-cloudflare@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz"
|
||||
@ -2093,6 +2289,11 @@ prop-types@^15.6.2, prop-types@^15.8.1:
|
||||
object-assign "^4.1.1"
|
||||
react-is "^16.13.1"
|
||||
|
||||
punycode.js@2.3.1:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz"
|
||||
integrity sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==
|
||||
|
||||
queue-microtask@^1.2.2:
|
||||
version "1.2.3"
|
||||
resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz"
|
||||
@ -2205,6 +2406,16 @@ read-cache@^1.0.0:
|
||||
dependencies:
|
||||
pify "^2.3.0"
|
||||
|
||||
readable-stream@1.1.x:
|
||||
version "1.1.14"
|
||||
resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz"
|
||||
integrity sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==
|
||||
dependencies:
|
||||
core-util-is "~1.0.0"
|
||||
inherits "~2.0.1"
|
||||
isarray "0.0.1"
|
||||
string_decoder "~0.10.x"
|
||||
|
||||
readdirp@~3.6.0:
|
||||
version "3.6.0"
|
||||
resolved "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz"
|
||||
@ -2259,6 +2470,11 @@ run-parallel@^1.1.9:
|
||||
dependencies:
|
||||
queue-microtask "^1.2.2"
|
||||
|
||||
"safer-buffer@>= 2.1.2 < 3.0.0":
|
||||
version "2.1.2"
|
||||
resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz"
|
||||
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
|
||||
|
||||
scheduler@^0.23.2:
|
||||
version "0.23.2"
|
||||
resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz"
|
||||
@ -2266,6 +2482,18 @@ scheduler@^0.23.2:
|
||||
dependencies:
|
||||
loose-envify "^1.1.0"
|
||||
|
||||
selderee@^0.11.0:
|
||||
version "0.11.0"
|
||||
resolved "https://registry.npmjs.org/selderee/-/selderee-0.11.0.tgz"
|
||||
integrity sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==
|
||||
dependencies:
|
||||
parseley "^0.12.0"
|
||||
|
||||
semver@~5.3.0:
|
||||
version "5.3.0"
|
||||
resolved "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz"
|
||||
integrity sha512-mfmm3/H9+67MCVix1h+IXTpDwL6710LyHuk7+cWC9T1mE0qz4iHhh6r4hU2wrIT9iTsAAC2XQRvfblL028cpLw==
|
||||
|
||||
shebang-command@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz"
|
||||
@ -2303,6 +2531,11 @@ streamsearch@^1.1.0:
|
||||
resolved "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz"
|
||||
integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==
|
||||
|
||||
string_decoder@~0.10.x:
|
||||
version "0.10.31"
|
||||
resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
|
||||
integrity sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==
|
||||
|
||||
"string-width-cjs@npm:string-width@^4.2.0":
|
||||
version "4.2.3"
|
||||
resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz"
|
||||
@ -2438,6 +2671,11 @@ tiny-invariant@^1.3.1:
|
||||
resolved "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz"
|
||||
integrity sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==
|
||||
|
||||
tlds@1.255.0:
|
||||
version "1.255.0"
|
||||
resolved "https://registry.npmjs.org/tlds/-/tlds-1.255.0.tgz"
|
||||
integrity sha512-tcwMRIioTcF/FcxLev8MJWxCp+GUALRhFEqbDoZrnowmKSGqPrl5pqS+Sut2m8BgJ6S4FExCSSpGffZ0Tks6Aw==
|
||||
|
||||
to-regex-range@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz"
|
||||
@ -2460,6 +2698,11 @@ typescript@^5, typescript@>=5.1.0:
|
||||
resolved "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz"
|
||||
integrity sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==
|
||||
|
||||
uc.micro@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz"
|
||||
integrity sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==
|
||||
|
||||
undici-types@~6.20.0:
|
||||
version "6.20.0"
|
||||
resolved "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz"
|
||||
@ -2493,6 +2736,13 @@ use-sync-external-store@^1.2.2:
|
||||
resolved "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.4.0.tgz"
|
||||
integrity sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==
|
||||
|
||||
utf7@>=1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmjs.org/utf7/-/utf7-1.0.2.tgz"
|
||||
integrity sha512-qQrPtYLLLl12NF4DrM9CvfkxkYI97xOb5dsnGZHE3teFr0tWiEZ9UdgMPczv24vl708cYMpe6mGXGHrotIp3Bw==
|
||||
dependencies:
|
||||
semver "~5.3.0"
|
||||
|
||||
util-deprecate@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user