database wf 9

This commit is contained in:
alma 2025-04-17 13:26:35 +02:00
parent 58f0b37476
commit ed6a33b8d7
13 changed files with 626 additions and 380 deletions

View File

@ -58,6 +58,35 @@ export const authOptions: NextAuthOptions = {
strategy: "jwt",
maxAge: 30 * 24 * 60 * 60, // 30 days
},
cookies: {
sessionToken: {
name: `__Secure-next-auth.session-token`,
options: {
httpOnly: true,
sameSite: 'lax',
path: '/',
secure: true
}
},
callbackUrl: {
name: `__Secure-next-auth.callback-url`,
options: {
httpOnly: true,
sameSite: 'lax',
path: '/',
secure: true
}
},
csrfToken: {
name: `__Host-next-auth.csrf-token`,
options: {
httpOnly: true,
sameSite: 'lax',
path: '/',
secure: true
}
}
},
callbacks: {
async jwt({ token, account, profile }) {
if (account && profile) {
@ -121,11 +150,13 @@ export const authOptions: NextAuthOptions = {
session.accessToken = token.accessToken;
session.user = {
...session.user,
id: token.sub as string,
name: token.name,
email: token.email,
image: null,
username: token.username ?? '',
first_name: token.first_name ?? '',
last_name: token.last_name ?? '',
username: token.username ?? '',
role: token.role ?? [],
};

View File

@ -1,15 +1,14 @@
import { NextResponse } from 'next/server';
import Imap from 'imap';
import { cookies } from 'next/headers';
interface StoredCredentials {
user: string;
email: string;
password: string;
host: string;
port: string;
port: number;
}
export let storedCredentials: StoredCredentials | null = null;
export async function POST(request: Request) {
try {
const { email, password, host, port } = await request.json();
@ -40,8 +39,25 @@ export async function POST(request: Request) {
return new Promise((resolve, reject) => {
imap.once('ready', () => {
imap.end();
// Store credentials
storedCredentials = { user: email, password, host, port };
// Store credentials in cookie
const cookieStore = cookies();
const credentials: StoredCredentials = {
email,
password,
host,
port: parseInt(port)
};
// Set the cookie with proper security options
cookieStore.set('imap_credentials', JSON.stringify(credentials), {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'lax',
path: '/',
maxAge: 30 * 24 * 60 * 60 // 30 days
});
resolve(NextResponse.json({ success: true }));
});
@ -78,14 +94,25 @@ export async function POST(request: Request) {
}
export async function GET() {
if (!storedCredentials) {
const cookieStore = cookies();
const credentialsCookie = cookieStore.get('imap_credentials');
if (!credentialsCookie?.value) {
return NextResponse.json(
{ error: 'No stored credentials found' },
{ status: 404 }
);
}
// Return credentials without password
const { password, ...safeCredentials } = storedCredentials;
return NextResponse.json(safeCredentials);
try {
const credentials = JSON.parse(credentialsCookie.value);
// Return credentials without password for security
const { password, ...safeCredentials } = credentials;
return NextResponse.json(safeCredentials);
} catch (error) {
return NextResponse.json(
{ error: 'Invalid credentials format' },
{ status: 400 }
);
}
}

View File

@ -1,362 +1,52 @@
import { NextResponse } from 'next/server';
import Imap from 'imap';
import nodemailer from 'nodemailer';
import { parseEmailHeaders, decodeEmailBody } from '@/lib/email-parser';
import { cookies } from 'next/headers';
import { ImapFlow } from 'imapflow';
interface StoredCredentials {
email: string;
password: string;
host: string;
port: number;
}
interface Email {
id: string;
from: string;
subject: string;
date: Date;
read: boolean;
starred: boolean;
body: string;
to?: string;
folder: string;
}
interface ImapBox {
messages: {
total: number;
};
}
interface ImapMessage {
on: (event: string, callback: (data: any) => void) => void;
once: (event: string, callback: (data: any) => void) => void;
attributes: {
uid: number;
flags: string[];
size: number;
};
body: {
[key: string]: {
on: (event: string, callback: (data: any) => void) => void;
};
};
}
interface ImapConfig {
user: string;
password: string;
host: string;
port: number;
tls: boolean;
authTimeout: number;
connTimeout: number;
debug?: (info: string) => void;
}
function getStoredCredentials(): StoredCredentials | null {
const cookieStore = cookies();
const credentialsCookie = cookieStore.get('imap_credentials');
console.log('Retrieved credentials cookie:', credentialsCookie ? 'Found' : 'Not found');
if (!credentialsCookie?.value) {
console.log('No credentials cookie found');
return null;
}
export async function GET() {
try {
const credentials = JSON.parse(credentialsCookie.value);
console.log('Parsed credentials:', {
...credentials,
password: '***'
});
const cookieStore = cookies();
const credentials = cookieStore.get('imap_credentials');
// Validate required fields
if (!credentials.email || !credentials.password || !credentials.host || !credentials.port) {
console.error('Missing required credentials fields');
return null;
}
return {
email: credentials.email,
password: credentials.password,
host: credentials.host,
port: credentials.port
};
} catch (error) {
console.error('Error parsing credentials cookie:', error);
return null;
}
}
export async function GET(request: Request) {
try {
const credentials = getStoredCredentials();
if (!credentials) {
return NextResponse.json(
{ error: 'No stored credentials found' },
{ error: 'No credentials found' },
{ status: 401 }
);
}
// Get pagination parameters from URL
const url = new URL(request.url);
const folder = url.searchParams.get('folder') || 'INBOX';
const page = parseInt(url.searchParams.get('page') || '1');
const limit = parseInt(url.searchParams.get('limit') || '24');
const offset = (page - 1) * limit;
const { email, password, host, port } = JSON.parse(credentials.value);
return new Promise((resolve) => {
const imap = new Imap({
user: credentials.email,
password: credentials.password,
host: credentials.host,
port: credentials.port,
tls: true,
tlsOptions: { rejectUnauthorized: false },
authTimeout: 30000,
connTimeout: 30000
});
const timeout = setTimeout(() => {
console.error('IMAP connection timeout');
imap.end();
resolve(NextResponse.json({
emails: [],
error: 'Connection timeout'
}));
}, 30000);
imap.once('error', (err: Error) => {
console.error('IMAP error:', err);
clearTimeout(timeout);
resolve(NextResponse.json({
emails: [],
error: 'IMAP connection error'
}));
});
imap.once('ready', () => {
imap.getBoxes((err, boxes) => {
if (err) {
console.error('Error getting mailboxes:', err);
clearTimeout(timeout);
imap.end();
resolve(NextResponse.json({ emails: [], error: 'Failed to get mailboxes' }));
return;
}
const availableMailboxes = Object.keys(boxes).filter(
box => !['Starred', 'Archives'].includes(box)
);
console.log('Available mailboxes:', availableMailboxes);
// Only process the requested folder
imap.openBox(folder, false, (err, box) => {
if (err) {
console.error(`Error opening box ${folder}:`, err);
clearTimeout(timeout);
imap.end();
resolve(NextResponse.json({ emails: [], error: `Failed to open folder ${folder}` }));
return;
}
// Get the specified folder
const totalMessages = box.messages.total;
// Calculate the range of messages to fetch
const start = Math.max(1, totalMessages - offset - limit + 1);
const end = totalMessages - offset;
if (start > end) {
clearTimeout(timeout);
imap.end();
resolve(NextResponse.json({
emails: [],
folders: availableMailboxes,
mailUrl: process.env.NEXT_PUBLIC_IFRAME_MAIL_URL
}));
return;
}
// Fetch messages in the calculated range
imap.search(['ALL'], (err, results) => {
if (err) {
console.error(`Error searching in ${folder}:`, err);
clearTimeout(timeout);
imap.end();
resolve(NextResponse.json({ emails: [], error: `Failed to search in ${folder}` }));
return;
}
if (!results || results.length === 0) {
clearTimeout(timeout);
imap.end();
resolve(NextResponse.json({
emails: [],
folders: availableMailboxes,
mailUrl: process.env.NEXT_PUBLIC_IFRAME_MAIL_URL
}));
return;
}
// Take only the most recent emails up to the limit
const recentResults = results.slice(-limit);
const emails: any[] = [];
const fetch = imap.fetch(recentResults, {
bodies: ['HEADER', 'TEXT'],
struct: true
});
fetch.on('message', (msg) => {
let header = '';
let text = '';
let messageId: number | null = null;
let messageFlags: string[] = [];
msg.once('attributes', (attrs) => {
messageId = attrs.uid;
messageFlags = attrs.flags || [];
});
msg.on('body', (stream, info) => {
let buffer = '';
stream.on('data', (chunk) => {
buffer += chunk.toString('utf8');
});
stream.on('end', () => {
if (info.which === 'HEADER') {
header = buffer;
} else if (info.which === 'TEXT') {
text = buffer;
}
});
});
msg.on('end', () => {
if (!messageId) {
console.error('No message ID found for email');
return;
}
const parsedHeader = Imap.parseHeader(header);
const email = {
id: messageId,
from: parsedHeader.from?.[0] || '',
to: parsedHeader.to?.[0] || '',
subject: parsedHeader.subject?.[0] || '(No subject)',
date: parsedHeader.date?.[0] || new Date().toISOString(),
body: text,
folder: folder,
flags: messageFlags,
read: messageFlags.includes('\\Seen'),
starred: messageFlags.includes('\\Flagged')
};
emails.push(email);
});
});
fetch.on('error', (err) => {
console.error(`Error fetching emails from ${folder}:`, err);
clearTimeout(timeout);
imap.end();
resolve(NextResponse.json({ emails: [], error: `Failed to fetch emails from ${folder}` }));
});
fetch.on('end', () => {
// Sort emails by date (most recent first)
emails.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
clearTimeout(timeout);
imap.end();
resolve(NextResponse.json({
emails,
folders: availableMailboxes,
mailUrl: process.env.NEXT_PUBLIC_IFRAME_MAIL_URL
}));
});
});
});
});
});
imap.connect();
const client = new ImapFlow({
host,
port: parseInt(port),
secure: true,
auth: {
user: email,
pass: password,
},
});
await client.connect();
const mailbox = await client.mailboxOpen('INBOX');
const messages = await client.fetch('1:10', { envelope: true });
const result = [];
for await (const message of messages) {
result.push({
id: message.uid,
subject: message.envelope.subject,
from: message.envelope.from[0].address,
date: message.envelope.date,
});
}
await client.logout();
return NextResponse.json(result);
} catch (error) {
console.error('Error in GET /api/mail:', error);
console.error('Mail API error:', error);
return NextResponse.json(
{ error: 'Failed to fetch emails' },
{ status: 500 }
);
}
}
export async function POST(request: Request) {
try {
const credentials = getStoredCredentials();
if (!credentials) {
return NextResponse.json(
{ error: 'No stored credentials found' },
{ status: 401 }
);
}
let body;
try {
body = await request.json();
} catch (error) {
return NextResponse.json(
{ error: 'Invalid JSON in request body' },
{ status: 400 }
);
}
const { to, subject, body: emailBody, attachments } = body;
if (!to || !subject || !emailBody) {
return NextResponse.json(
{ error: 'Missing required fields: to, subject, or body' },
{ status: 400 }
);
}
const transporter = nodemailer.createTransport({
host: credentials.host,
port: credentials.port,
secure: true,
auth: {
user: credentials.email,
pass: credentials.password,
},
});
const mailOptions = {
from: credentials.email,
to,
subject,
text: emailBody,
attachments: attachments || [],
};
const info = await transporter.sendMail(mailOptions);
console.log('Email sent:', info.messageId);
return NextResponse.json({
success: true,
messageId: info.messageId,
message: 'Email sent successfully'
});
} catch (error) {
console.error('Error sending email:', error);
return NextResponse.json(
{
error: error instanceof Error ? error.message : 'Failed to send email',
details: error instanceof Error ? error.stack : undefined
},
{ status: 500 }
);
}
}

View File

@ -6,7 +6,6 @@ import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { setCookie } from 'cookies-next';
export default function LoginPage() {
const router = useRouter();
@ -43,34 +42,24 @@ export default function LoginPage() {
throw new Error(testData.error || 'Failed to connect to email server');
}
// Store all credentials in a single cookie
const credentials = {
email,
password,
host,
port: parseInt(port),
};
console.log('Storing credentials in cookie:', {
...credentials,
password: '***'
// Store credentials using the API endpoint
const loginResponse = await fetch('/api/mail/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email,
password,
host,
port,
}),
});
// Store as a single cookie with proper options
setCookie('imap_credentials', JSON.stringify(credentials), {
maxAge: 60 * 60 * 24, // 1 day
path: '/',
sameSite: 'lax',
secure: process.env.NODE_ENV === 'production',
httpOnly: false // Allow access from JavaScript
});
const loginData = await loginResponse.json();
// Verify cookie was set
const stored = document.cookie.split(';').find(c => c.trim().startsWith('imap_credentials='));
console.log('Cookie verification:', stored ? 'Cookie found' : 'Cookie not found');
if (!stored) {
throw new Error('Failed to store credentials');
if (!loginResponse.ok) {
throw new Error(loginData.error || 'Failed to store credentials');
}
// Redirect to mail page

View File

@ -18,6 +18,14 @@ export default withAuth(
if (req.nextUrl.pathname === "/" || req.nextUrl.pathname === "/signin") {
return true;
}
// Check if the request is for an API route
if (req.nextUrl.pathname.startsWith('/api/')) {
// For API routes, require a valid token
return !!token;
}
// For all other routes, require a valid token
return !!token;
},
},

10
node_modules/.package-lock.json generated vendored
View File

@ -2214,6 +2214,16 @@
"@types/node": "*"
}
},
"node_modules/@types/imapflow": {
"version": "1.0.20",
"resolved": "https://registry.npmjs.org/@types/imapflow/-/imapflow-1.0.20.tgz",
"integrity": "sha512-kmBeiV815byuxYlu2lomAx3VY3SsyOYg4rDsK5vT6CGZ6Sow2AUEZwieql8uAizO6+p4sQchw/g3vQX76XBIpA==",
"dev": true,
"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",

21
node_modules/@types/imapflow/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) Microsoft Corporation.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE

15
node_modules/@types/imapflow/README.md generated vendored Normal file
View File

@ -0,0 +1,15 @@
# Installation
> `npm install --save @types/imapflow`
# Summary
This package contains type definitions for imapflow (https://imapflow.com/).
# Details
Files were exported from https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/imapflow.
### Additional Details
* Last updated: Mon, 03 Mar 2025 07:02:16 GMT
* Dependencies: [@types/node](https://npmjs.com/package/@types/node)
# Credits
These definitions were written by [Jeffrey Ratton](https://github.com/jeffreyratton98), [Martin Badin](https://github.com/martin-badin), [Northern Star](https://github.com/grayson-code), and [Zachary Nawar](https://github.com/remscar).

393
node_modules/@types/imapflow/index.d.ts generated vendored Normal file
View File

@ -0,0 +1,393 @@
/// <reference types="node" />
import { EventEmitter } from "stream";
export type Readable = import("stream").Readable;
export class ImapFlow extends EventEmitter {
constructor(options: ImapFlowOptions);
authenticated: string | boolean;
capabilities: Map<string, (boolean | number)>;
emitLogs: boolean;
enabled: Set<string>;
id: string;
idling: boolean;
mailbox: MailboxObject | boolean;
secureConnection: boolean;
serverInfo: IdInfoObject;
usable: boolean;
append(
path: string,
content: string | Buffer,
flags?: string[],
idate?: Date | string,
): Promise<AppendResonseObject>;
connect(): Promise<void>;
logout(): Promise<void>;
close(): void;
download(
range: SequenceString,
part?: string,
options?: { uid?: boolean; maxBytes?: number; chunkSize?: number },
): Promise<DownloadObject>;
getMailboxLock(path: string, options?: null | { readonly?: boolean }): Promise<MailboxLockObject>;
getQuota(path: string): Promise<QuotaResponse | boolean>;
idle(): Promise<boolean>;
/**
* @see {@link https://imapflow.com/module-imapflow-ImapFlow.html#list}
*/
list(options?: {
statusQuery?: StatusQuery;
specialUseHints?: SpecialUseHints;
}): Promise<ListResponse[]>;
listTree(): Promise<ListTreeResponse>;
mailboxClose(): Promise<boolean>;
mailboxCreate(path: string | any[]): Promise<MailboxCreateResponse>;
mailboxDelete(path: string | any[]): Promise<MailboxDeleteResponse>;
mailboxOpen(path: string | any[], options?: { readOnly?: boolean }): Promise<MailboxObject>;
mailboxRename(path: string | any[], newPath: string | any[]): Promise<MailboxRenameResponse>;
mailboxSubscribe(path: string | any[]): Promise<boolean>;
mailboxUnsubscribe(path: string | any[]): Promise<boolean>;
messageCopy(
range: SequenceString | number[] | SearchObject,
destination: string,
options?: { uid?: boolean },
): Promise<CopyResponseObject>;
messageDelete(range: SequenceString | number[] | SearchObject, options?: { uid?: boolean }): Promise<boolean>;
messageFlagsAdd(
range: SequenceString | number[] | SearchObject,
Array: string[],
options?: { uid?: boolean; unchangedSince?: bigint; useLabels?: boolean },
): Promise<boolean>;
messageFlagsRemove(
range: SequenceString | number[] | SearchObject,
Array: string[],
options?: { uid?: boolean; unchangedSince?: bigint; useLabels?: boolean },
): Promise<boolean>;
messageFlagsSet(
range: SequenceString | number[] | SearchObject,
Array: string[],
options?: { uid?: boolean; unchangedSince?: bigint; useLabels?: boolean },
): Promise<boolean>;
messageMove(
range: SequenceString | number[] | SearchObject,
destination: string,
options?: { uid?: boolean },
): Promise<CopyResponseObject>;
fetchOne(
seq: SequenceString,
query: FetchQueryObject,
options?: {
uid?: boolean;
},
): Promise<FetchMessageObject>;
noop(): Promise<void>;
search(query: SearchObject, options?: { uid?: boolean }): Promise<number[]>;
status(
path: string,
query: {
messages?: boolean;
recent?: boolean;
uidNext?: boolean;
uidValidity?: boolean;
unseen?: boolean;
highestModseq?: boolean;
},
): Promise<StatusObject>;
fetch(
range: SequenceString | number[] | SearchObject,
query: FetchQueryObject,
options?: { uid?: boolean; changedSince?: bigint; binary?: boolean },
): AsyncGenerator<FetchMessageObject, never, void>;
fetchAll(
range: SequenceString | number[] | SearchObject,
query: FetchQueryObject,
options?: { uid?: boolean; changedSince?: bigint; binary?: boolean },
): Promise<FetchMessageObject[]>;
}
export interface ImapFlowOptions {
host: string;
port: number;
auth: {
user: string;
pass?: string;
accessToken?: string;
};
secure?: boolean;
servername?: string;
disableCompression?: boolean;
clientInfo?: IdInfoObject;
disableAutoIdle?: boolean;
tls?: object;
logger?: Logger | false;
emitLogs?: boolean;
verifyOnly?: boolean;
logRaw?: boolean;
proxy?: string;
qresync?: boolean;
maxIdleTime?: number;
missingIdleCommand?: string;
disableBinary?: boolean;
disableAutoEnable?: boolean;
connectionTimeout?: number;
greetingTimeout?: number;
socketTimeout?: number;
}
export interface AppendResonseObject {
path: string;
uidValidity?: bigint;
uid?: number;
seq?: number;
}
export interface CopyResponseObject {
path: string;
destination: string;
uidValidity?: bigint;
uidMap?: Map<number, number>;
}
export interface DownloadObject {
content: Readable;
meta: {
expectedSize: number;
contentType: string;
charset?: string;
disposition?: string;
filename?: string;
};
}
export interface MailboxObject {
path: string;
delimeter: string;
flags: Set<string>;
specialUse: string;
listed: boolean;
subscribed: boolean;
permanentFlags: Set<string>;
mailboxId: string;
highestModseq: BigInt;
uidValidity: BigInt;
uidNext: number;
exists: number;
}
export interface MailboxLockObject {
path: string;
release: () => void;
}
export interface FetchMessageObject {
seq: number;
uid: number;
source: Buffer;
modseq: BigInt;
emailId: string;
threadId?: string;
labels: Set<string>;
size: number;
flags: Set<string>;
envelope: MessageEnvelopeObject;
bodyStructure: MessageStructureObject;
internalDate: Date;
bodyParts: Map<string, Buffer>;
headers: Buffer;
}
export interface FetchQueryObject {
uid?: boolean;
flags?: boolean;
bodyStructure?: boolean;
envelope?: boolean;
internalDate?: boolean;
size?: boolean;
source?: boolean | object;
threadId?: boolean;
labels?: boolean;
headers?: boolean | string[];
bodyParts?: string[];
}
export interface MailboxRenameResponse {
path: string;
newPath: string;
}
export interface MessageAddressObject {
name?: string;
address?: string;
}
export interface MessageEnvelopeObject {
date: Date;
subject: string;
messageId: string;
inReplyTo: string;
from: MessageAddressObject[];
sender: MessageAddressObject[];
replyTo: MessageAddressObject[];
to: MessageAddressObject[];
cc: MessageAddressObject[];
bcc: MessageAddressObject[];
}
export interface QuotaResponse {
path: string;
storage?: object;
messages?: object;
}
export type SequenceString = string;
export interface SearchObject {
seq?: SequenceString;
answered?: boolean;
deleted?: boolean;
draft?: boolean;
flagged?: boolean;
seen?: boolean;
all?: boolean;
new?: boolean;
old?: boolean;
recent?: boolean;
from?: string;
to?: string;
cc?: string;
bcc?: string;
body?: string;
subject?: string;
larger?: number;
smaller?: number;
uid?: SequenceString;
modseq?: bigint;
emailId?: string;
threadId?: string;
before?: Date | string;
on?: Date | string;
since?: Date | string;
sentBefore?: Date | string;
sentOn?: Date | string;
sentSince?: Date | string;
keyword?: string;
unKeyword?: string;
header?: { [key: string]: boolean | string };
or?: SearchObject[];
}
export interface StatusObject {
path: string;
messages?: number;
recent?: number;
uidNext?: number;
uidValidity?: bigint;
unseen?: number;
highestModseq?: bigint;
}
export interface IdInfoObject {
name?: string;
version?: string;
os?: string;
vendor?: string;
"support-url"?: string;
date?: Date;
}
export interface ListResponse {
path: string;
name: string;
delimiter: string;
flags: Set<string>;
specialUse: string;
listed: boolean;
subscribed: boolean;
status?: StatusObject;
}
export interface ListTreeResponse {
root: boolean;
path: string;
name: string;
delimiter: string;
flags: [];
specialUse: string;
listed: boolean;
subscribed: boolean;
disabled: boolean;
folders: ListTreeResponse[];
}
export interface MailboxCreateResponse {
path: string;
mailboxId?: string;
created: boolean;
}
export interface MailboxDeleteResponse {
path: string;
}
export interface MessageStructureObject {
part: string;
type: string;
parameters: string;
id: string;
encoding: string;
size: number;
envelope: MessageEnvelopeObject;
disposition: string;
dispositionParameters: string;
childNodes: MessageStructureObject[];
}
export interface Logger {
debug: (obj: object) => void;
info: (obj: object) => void;
warn: (obj: object) => void;
error: (obj: object) => void;
}
export interface StatusQuery {
messages?: boolean;
recent?: boolean;
uidNext?: boolean;
uidValidity?: boolean;
unseen?: boolean;
highestModseq?: boolean;
}
export interface SpecialUseHints {
sent: string;
trash: string;
junk: string;
drafts: string;
}

43
node_modules/@types/imapflow/package.json generated vendored Normal file
View File

@ -0,0 +1,43 @@
{
"name": "@types/imapflow",
"version": "1.0.20",
"description": "TypeScript definitions for imapflow",
"homepage": "https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/imapflow",
"license": "MIT",
"contributors": [
{
"name": "Jeffrey Ratton",
"githubUsername": "jeffreyratton98",
"url": "https://github.com/jeffreyratton98"
},
{
"name": "Martin Badin",
"githubUsername": "martin-badin",
"url": "https://github.com/martin-badin"
},
{
"name": "Northern Star",
"githubUsername": "grayson-code",
"url": "https://github.com/grayson-code"
},
{
"name": "Zachary Nawar",
"githubUsername": "remscar",
"url": "https://github.com/remscar"
}
],
"main": "",
"types": "index.d.ts",
"repository": {
"type": "git",
"url": "https://github.com/DefinitelyTyped/DefinitelyTyped.git",
"directory": "types/imapflow"
},
"scripts": {},
"dependencies": {
"@types/node": "*"
},
"peerDependencies": {},
"typesPublisherContentHash": "5a7661a9dee2cf2fab17d371ef006249b141fe3d09adc38c21661ce457b282ac",
"typeScriptVersion": "5.0"
}

11
package-lock.json generated
View File

@ -75,6 +75,7 @@
"vaul": "^0.9.6"
},
"devDependencies": {
"@types/imapflow": "^1.0.20",
"@types/node": "^22.14.1",
"@types/react": "^18",
"@types/react-dom": "^18",
@ -2831,6 +2832,16 @@
"@types/node": "*"
}
},
"node_modules/@types/imapflow": {
"version": "1.0.20",
"resolved": "https://registry.npmjs.org/@types/imapflow/-/imapflow-1.0.20.tgz",
"integrity": "sha512-kmBeiV815byuxYlu2lomAx3VY3SsyOYg4rDsK5vT6CGZ6Sow2AUEZwieql8uAizO6+p4sQchw/g3vQX76XBIpA==",
"dev": true,
"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",

View File

@ -76,6 +76,7 @@
"vaul": "^0.9.6"
},
"devDependencies": {
"@types/imapflow": "^1.0.20",
"@types/node": "^22.14.1",
"@types/react": "^18",
"@types/react-dom": "^18",

View File

@ -1014,6 +1014,13 @@
dependencies:
"@types/node" "*"
"@types/imapflow@^1.0.20":
version "1.0.20"
resolved "https://registry.npmjs.org/@types/imapflow/-/imapflow-1.0.20.tgz"
integrity sha512-kmBeiV815byuxYlu2lomAx3VY3SsyOYg4rDsK5vT6CGZ6Sow2AUEZwieql8uAizO6+p4sQchw/g3vQX76XBIpA==
dependencies:
"@types/node" "*"
"@types/mailparser@^3.4.5":
version "3.4.5"
resolved "https://registry.npmjs.org/@types/mailparser/-/mailparser-3.4.5.tgz"