Files
cloudflare_temp_email/worker/src/models/index.ts
Dream Hunter e772db8c3e feat: add SEND_MAIL delivery and quota controls (#986)
* feat: add SEND_MAIL delivery and quota controls

* test: cover -1 unlimited runtime for send mail quota

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix: split send limit validation and save

* refactor: move send limit counters to settings

* fix: polish send mail limit review follow-ups

* docs: note SEND_MAIL breaking change

* test: align send mail limit e2e with new messages

* fix: address review follow-ups

* fix: harden admin send mail handlers

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-17 11:37:14 +08:00

211 lines
5.9 KiB
TypeScript

import type {
AuthenticatorTransportFuture,
CredentialDeviceType,
Base64URLString,
} from '@simplewebauthn/server';
export type Passkey = {
id: Base64URLString;
publicKey: string;
counter: number;
deviceType: CredentialDeviceType;
backedUp: boolean;
transports?: AuthenticatorTransportFuture[];
};
export class AdminWebhookSettings {
enableAllowList: boolean;
allowList: string[];
constructor(enableAllowList: boolean, allowList: string[]) {
this.enableAllowList = enableAllowList;
this.allowList = allowList;
}
}
export type WebhookMail = {
id: string;
url?: string;
from: string;
to: string;
subject: string;
raw: string;
parsedText: string;
parsedHtml: string;
}
export type CustomSqlCleanup = {
id: string; // Unique identifier
name: string; // Cleanup task name
sql: string; // Custom SQL statement (DELETE only)
enabled: boolean; // Whether to enable auto cleanup
}
export type CleanupSettings = {
enableMailsAutoCleanup: boolean | undefined;
cleanMailsDays: number;
enableUnknowMailsAutoCleanup: boolean | undefined;
cleanUnknowMailsDays: number;
enableSendBoxAutoCleanup: boolean | undefined;
cleanSendBoxDays: number;
enableAddressAutoCleanup: boolean | undefined;
cleanAddressDays: number;
enableInactiveAddressAutoCleanup: boolean | undefined;
cleanInactiveAddressDays: number;
enableUnboundAddressAutoCleanup: boolean | undefined;
cleanUnboundAddressDays: number;
enableEmptyAddressAutoCleanup: boolean | undefined;
cleanEmptyAddressDays: number;
customSqlCleanupList: CustomSqlCleanup[] | undefined;
}
export class GeoData {
ip: string;
country: string | undefined;
city: string | undefined;
timezone: string | undefined;
postalCode: string | undefined;
region: string | undefined;
latitude: number | undefined;
longitude: number | undefined;
regionCode: string | undefined;
asOrganization: string | undefined;
constructor(ip: string | null, data: GeoData | undefined | null) {
const {
country, city, timezone, postalCode, region,
latitude, longitude, regionCode, asOrganization
} = data || {};
this.ip = ip || "unknown";
this.country = country;
this.city = city;
this.timezone = timezone;
this.postalCode = postalCode;
this.region = region;
this.latitude = latitude;
this.longitude = longitude;
this.regionCode = regionCode;
this.asOrganization = asOrganization;
}
}
export class UserSettings {
enable: boolean | undefined;
enableMailVerify: boolean | undefined;
verifyMailSender: string | undefined;
enableMailAllowList: boolean | undefined;
mailAllowList: string[] | undefined;
maxAddressCount: number;
enableEmailCheckRegex: boolean | undefined;
emailCheckRegex: string | undefined;
constructor(data: UserSettings | undefined | null) {
const {
enable, enableMailVerify, verifyMailSender,
enableMailAllowList, mailAllowList, maxAddressCount,
enableEmailCheckRegex, emailCheckRegex
} = data || {};
this.enable = enable;
this.enableMailVerify = enableMailVerify;
this.verifyMailSender = verifyMailSender;
this.enableMailAllowList = enableMailAllowList;
this.mailAllowList = mailAllowList;
this.maxAddressCount = (typeof maxAddressCount === "number" && maxAddressCount >= 0) ? maxAddressCount : 5;
this.enableEmailCheckRegex = enableEmailCheckRegex;
this.emailCheckRegex = emailCheckRegex;
}
}
export class AddressCreationSettings {
enableSubdomainMatch: boolean | undefined;
constructor(data: AddressCreationSettings | undefined | null) {
const { enableSubdomainMatch } = data || {};
this.enableSubdomainMatch = enableSubdomainMatch;
}
}
export class UserInfo {
geoData: GeoData;
userEmail: string;
constructor(geoData: GeoData, userEmail: string) {
this.geoData = geoData;
this.userEmail = userEmail;
}
}
export class WebhookSettings {
enabled: boolean = false
url: string = ''
method: string = 'POST'
headers: string = JSON.stringify({
"Content-Type": "application/json"
}, null, 2)
body: string = JSON.stringify({
"id": "${id}",
"url": "${url}",
"from": "${from}",
"to": "${to}",
"subject": "${subject}",
"raw": "${raw}",
"parsedText": "${parsedText}",
"parsedHtml": "${parsedHtml}",
}, null, 2)
}
export type UserOauth2Settings = {
name: string;
icon?: string; // SVG icon string for the provider
clientID: string;
clientSecret: string;
authorizationURL: string;
accessTokenURL: string;
accessTokenFormat: string;
userInfoURL: string;
redirectURL: string;
logoutURL?: string;
userEmailKey: string;
enableEmailFormat?: boolean; // Enable email format transformation
userEmailFormat?: string; // Regex pattern to match email
userEmailReplace?: string; // Replacement template using $1, $2, etc.
scope: string;
enableMailAllowList?: boolean | undefined;
mailAllowList?: string[] | undefined;
}
export type EmailRuleSettings = {
blockReceiveUnknowAddressEmail: boolean;
emailForwardingList: SubdomainForwardAddressList[]
}
export type SendMailLimitConfig = {
dailyEnabled: boolean;
monthlyEnabled: boolean;
dailyLimit: number | null;
monthlyLimit: number | null;
}
export type RoleConfig = {
maxAddressCount?: number;
// future configs can be added here
}
export type RoleAddressConfig = Record<string, RoleConfig>;
export type RawMailRow = {
id: number;
message_id?: string;
source?: string;
address?: string;
raw?: string;
raw_blob?: unknown;
metadata?: string;
created_at?: string;
}