fix: TypeScript errors in IMAP, CalDAV, and calendar components
- Add @types/mailparser for proper type support - Fix ImapFlow type narrowing for fetchOne, search, mailbox - Add null checks for envelope in fetch loops - Fix ListResponse cast to use double-cast pattern - Fix CalendarView EventId type (string vs number) - Fix CalDAV displayName type handling Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
615a36eb20
commit
076d6bc4d4
25
package.json
25
package.json
|
|
@ -20,31 +20,32 @@
|
||||||
"@radix-ui/react-slot": "^1.1.1",
|
"@radix-ui/react-slot": "^1.1.1",
|
||||||
"@radix-ui/react-tabs": "^1.1.3",
|
"@radix-ui/react-tabs": "^1.1.3",
|
||||||
"@radix-ui/react-tooltip": "^1.1.6",
|
"@radix-ui/react-tooltip": "^1.1.6",
|
||||||
|
"@schedule-x/calendar": "^2.0.0",
|
||||||
|
"@schedule-x/drag-and-drop": "^2.0.0",
|
||||||
|
"@schedule-x/events-service": "^2.0.0",
|
||||||
|
"@schedule-x/react": "^2.0.0",
|
||||||
|
"@schedule-x/theme-default": "^2.0.0",
|
||||||
|
"@tiptap/react": "^2.0.0",
|
||||||
|
"@tiptap/starter-kit": "^2.0.0",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
|
"dompurify": "^3.2.0",
|
||||||
|
"imapflow": "^1.0.0",
|
||||||
"lucide-react": "^0.469.0",
|
"lucide-react": "^0.469.0",
|
||||||
|
"mailparser": "^3.7.0",
|
||||||
"next": "15.1.8",
|
"next": "15.1.8",
|
||||||
"next-auth": "5.0.0-beta.30",
|
"next-auth": "5.0.0-beta.30",
|
||||||
|
"nodemailer": "^7.0.0",
|
||||||
"react": "19.0.0",
|
"react": "19.0.0",
|
||||||
"react-dom": "19.0.0",
|
"react-dom": "19.0.0",
|
||||||
"tailwind-merge": "^2.6.0",
|
"tailwind-merge": "^2.6.0",
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
"zod": "^3.24.1",
|
|
||||||
"imapflow": "^1.0.0",
|
|
||||||
"nodemailer": "^7.0.0",
|
|
||||||
"mailparser": "^3.7.0",
|
|
||||||
"tsdav": "^2.0.0",
|
"tsdav": "^2.0.0",
|
||||||
"@schedule-x/react": "^2.0.0",
|
"zod": "^3.24.1"
|
||||||
"@schedule-x/calendar": "^2.0.0",
|
|
||||||
"@schedule-x/events-service": "^2.0.0",
|
|
||||||
"@schedule-x/drag-and-drop": "^2.0.0",
|
|
||||||
"@schedule-x/theme-default": "^2.0.0",
|
|
||||||
"@tiptap/react": "^2.0.0",
|
|
||||||
"@tiptap/starter-kit": "^2.0.0",
|
|
||||||
"dompurify": "^3.2.0"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/dompurify": "^3.2.0",
|
"@types/dompurify": "^3.2.0",
|
||||||
|
"@types/mailparser": "^3.4.6",
|
||||||
"@types/node": "^22.10.5",
|
"@types/node": "^22.10.5",
|
||||||
"@types/nodemailer": "^6.4.17",
|
"@types/nodemailer": "^6.4.17",
|
||||||
"@types/react": "^19.0.4",
|
"@types/react": "^19.0.4",
|
||||||
|
|
|
||||||
|
|
@ -134,13 +134,13 @@ export function CalendarView({
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const currentEvents = eventsPlugin.getAll()
|
const currentEvents = eventsPlugin.getAll()
|
||||||
const currentIds = new Set(currentEvents.map((e: { id: string }) => e.id))
|
const currentIds = new Set(currentEvents.map((e) => String(e.id)))
|
||||||
const newIds = new Set(scheduleEvents.map((e) => e.id))
|
const newIds = new Set(scheduleEvents.map((e) => String(e.id)))
|
||||||
|
|
||||||
// Remove events no longer present
|
// Remove events no longer present
|
||||||
currentEvents.forEach((e: { id: string }) => {
|
currentEvents.forEach((e) => {
|
||||||
if (!newIds.has(e.id)) {
|
if (!newIds.has(String(e.id))) {
|
||||||
eventsPlugin.remove(e.id)
|
eventsPlugin.remove(String(e.id))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -171,7 +171,7 @@ export async function getCalendars(
|
||||||
|
|
||||||
return calendars.map((cal: DAVCalendar) => ({
|
return calendars.map((cal: DAVCalendar) => ({
|
||||||
url: cal.url,
|
url: cal.url,
|
||||||
displayName: cal.displayName || 'Calendar',
|
displayName: (typeof cal.displayName === 'string' ? cal.displayName : null) || 'Calendar',
|
||||||
description: cal.description || undefined,
|
description: cal.description || undefined,
|
||||||
color:
|
color:
|
||||||
(cal as Record<string, unknown>).calendarColor as string | undefined,
|
(cal as Record<string, unknown>).calendarColor as string | undefined,
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ export async function listFolders(): Promise<MailFolder[]> {
|
||||||
path: mb.path,
|
path: mb.path,
|
||||||
name: parts[parts.length - 1] || mb.path,
|
name: parts[parts.length - 1] || mb.path,
|
||||||
delimiter: mb.delimiter || '/',
|
delimiter: mb.delimiter || '/',
|
||||||
specialUse: (mb as Record<string, unknown>).specialUse as string | null ?? null,
|
specialUse: (mb as unknown as Record<string, unknown>).specialUse as string | null ?? null,
|
||||||
subscribed: mb.subscribed ?? false,
|
subscribed: mb.subscribed ?? false,
|
||||||
messages,
|
messages,
|
||||||
unseen,
|
unseen,
|
||||||
|
|
@ -129,7 +129,8 @@ export async function listMessages(
|
||||||
return withClient(async (client) => {
|
return withClient(async (client) => {
|
||||||
const lock = await client.getMailboxLock(folder)
|
const lock = await client.getMailboxLock(folder)
|
||||||
try {
|
try {
|
||||||
const total = client.mailbox?.exists ?? 0
|
const mb = client.mailbox
|
||||||
|
const total = (mb && typeof mb === 'object' && 'exists' in mb) ? mb.exists ?? 0 : 0
|
||||||
if (total === 0) {
|
if (total === 0) {
|
||||||
return { messages: [], total: 0 }
|
return { messages: [], total: 0 }
|
||||||
}
|
}
|
||||||
|
|
@ -151,6 +152,7 @@ export async function listMessages(
|
||||||
headers: ['content-type'],
|
headers: ['content-type'],
|
||||||
})) {
|
})) {
|
||||||
const env = msg.envelope
|
const env = msg.envelope
|
||||||
|
if (!env) continue
|
||||||
messages.push({
|
messages.push({
|
||||||
uid: msg.uid,
|
uid: msg.uid,
|
||||||
from: env.from?.[0]
|
from: env.from?.[0]
|
||||||
|
|
@ -184,8 +186,10 @@ export async function getMessage(
|
||||||
return withClient(async (client) => {
|
return withClient(async (client) => {
|
||||||
const lock = await client.getMailboxLock(folder)
|
const lock = await client.getMailboxLock(folder)
|
||||||
try {
|
try {
|
||||||
const raw = await client.fetchOne(String(uid), { source: true, flags: true, uid: true }, { uid: true })
|
const rawResult = await client.fetchOne(String(uid), { source: true, flags: true, uid: true }, { uid: true })
|
||||||
if (!raw?.source) return null
|
if (!rawResult) return null
|
||||||
|
const raw = rawResult
|
||||||
|
if (!raw.source) return null
|
||||||
|
|
||||||
const parsed = await simpleParser(raw.source)
|
const parsed = await simpleParser(raw.source)
|
||||||
|
|
||||||
|
|
@ -203,7 +207,7 @@ export async function getMessage(
|
||||||
flags: Array.from(raw.flags || []),
|
flags: Array.from(raw.flags || []),
|
||||||
html: parsed.html || '',
|
html: parsed.html || '',
|
||||||
text: parsed.text || '',
|
text: parsed.text || '',
|
||||||
attachments: (parsed.attachments || []).map((att) => ({
|
attachments: (parsed.attachments || []).map((att: { filename?: string; contentType?: string; size?: number; contentId?: string; contentDisposition?: string }) => ({
|
||||||
filename: att.filename || 'attachment',
|
filename: att.filename || 'attachment',
|
||||||
contentType: att.contentType || 'application/octet-stream',
|
contentType: att.contentType || 'application/octet-stream',
|
||||||
size: att.size || 0,
|
size: att.size || 0,
|
||||||
|
|
@ -269,7 +273,7 @@ export async function deleteMessage(
|
||||||
// Try to move to Trash first
|
// Try to move to Trash first
|
||||||
const mailboxes = await client.list()
|
const mailboxes = await client.list()
|
||||||
const trash = mailboxes.find(
|
const trash = mailboxes.find(
|
||||||
(mb) => (mb as Record<string, unknown>).specialUse === '\\Trash'
|
(mb) => (mb as unknown as Record<string, unknown>).specialUse === '\\Trash'
|
||||||
)
|
)
|
||||||
|
|
||||||
if (trash && folder !== trash.path) {
|
if (trash && folder !== trash.path) {
|
||||||
|
|
@ -292,7 +296,7 @@ export async function searchMessages(
|
||||||
return withClient(async (client) => {
|
return withClient(async (client) => {
|
||||||
const lock = await client.getMailboxLock(folder)
|
const lock = await client.getMailboxLock(folder)
|
||||||
try {
|
try {
|
||||||
const uids = await client.search(
|
const searchResult = await client.search(
|
||||||
{
|
{
|
||||||
or: [
|
or: [
|
||||||
{ subject: query },
|
{ subject: query },
|
||||||
|
|
@ -304,6 +308,7 @@ export async function searchMessages(
|
||||||
{ uid: true }
|
{ uid: true }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const uids = Array.isArray(searchResult) ? searchResult : []
|
||||||
if (uids.length === 0) return []
|
if (uids.length === 0) return []
|
||||||
|
|
||||||
// Limit results
|
// Limit results
|
||||||
|
|
@ -317,6 +322,7 @@ export async function searchMessages(
|
||||||
flags: true,
|
flags: true,
|
||||||
}, { uid: true })) {
|
}, { uid: true })) {
|
||||||
const env = msg.envelope
|
const env = msg.envelope
|
||||||
|
if (!env) continue
|
||||||
messages.push({
|
messages.push({
|
||||||
uid: msg.uid,
|
uid: msg.uid,
|
||||||
from: env.from?.[0]
|
from: env.from?.[0]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue