types.ts 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774
  1. export type ViewKey =
  2. | 'dashboard'
  3. | 'domains'
  4. | 'dns-api'
  5. | 'smtp'
  6. | 'inbox'
  7. | 'tokens'
  8. | 'logs'
  9. | 'webhooks'
  10. | 'admin'
  11. | 'settings';
  12. export type DomainMode = 'list' | 'detail';
  13. export type UserStatus = 'pending_email' | 'pending_review' | 'active' | 'disabled';
  14. export type UserRole = 'admin' | 'user';
  15. export interface MailboxPermissions {
  16. view: boolean;
  17. receive: boolean;
  18. send: boolean;
  19. }
  20. export type MailboxAccessType = 'owner' | 'assigned' | 'admin';
  21. export interface MailboxAccess {
  22. type: MailboxAccessType;
  23. permissions: MailboxPermissions;
  24. }
  25. export interface UserResourceCounts {
  26. domains: number;
  27. dnsCredentials: number;
  28. apiTokens: number;
  29. inboundMailboxes: number;
  30. inboundMessages: number;
  31. sendEvents: number;
  32. smtpCredential: number;
  33. }
  34. export interface User {
  35. id: number;
  36. username: string;
  37. email: string;
  38. role: UserRole;
  39. status: UserStatus;
  40. createdAt?: string;
  41. updatedAt?: string;
  42. resourceCounts?: UserResourceCounts;
  43. }
  44. export interface AdminUser extends User {
  45. resourceCounts: UserResourceCounts;
  46. }
  47. export interface RuntimeConfig {
  48. appBaseUrl: string;
  49. mailHostname: string;
  50. sendingIp: string;
  51. defaultSpfMechanisms: string;
  52. dmarcPolicy: string;
  53. dmarcRua: string;
  54. registrationRequiresApproval: boolean;
  55. sendRequiresVerified: boolean;
  56. engagementTrackingEnabled: boolean;
  57. listUnsubscribeMailto: string;
  58. listUnsubscribeUrl: string;
  59. listUnsubscribePostEnabled: boolean;
  60. feedbackIdEnabled: boolean;
  61. reportAbuseTo: string;
  62. csaComplaintsTo: string;
  63. bounceAddress: string;
  64. bounceEnvelopeEnabled: boolean;
  65. systemChecks?: SystemChecks;
  66. submission?: {
  67. enabled: boolean;
  68. host: string;
  69. ports: Array<{ port: number; protocol: string }>;
  70. username: string;
  71. passwordSet: boolean;
  72. inboundEnabled: boolean;
  73. tls: boolean;
  74. requireTlsForAuth: boolean;
  75. };
  76. mailAccess?: {
  77. host: string;
  78. tls: boolean;
  79. requireTlsForAuth: boolean;
  80. imap: {
  81. enabled: boolean;
  82. ports: Array<{ port: number; protocol: string }>;
  83. };
  84. pop3: {
  85. enabled: boolean;
  86. ports: Array<{ port: number; protocol: string }>;
  87. };
  88. };
  89. apiTokenSet?: boolean;
  90. usingDefaultAdminPassword?: boolean;
  91. }
  92. export interface SystemChecks {
  93. checkedAt: string;
  94. ptr: DnsRecord;
  95. }
  96. export interface DnsRecord {
  97. key: string;
  98. label: string;
  99. host: string;
  100. type: string;
  101. value?: string;
  102. status?: string;
  103. current?: string | string[];
  104. warnings?: string[];
  105. managed?: boolean;
  106. }
  107. export interface DomainStatus {
  108. checkedAt?: string;
  109. verified?: boolean;
  110. records?: DnsRecord[];
  111. optionalRecords?: DnsRecord[];
  112. warnings?: string[];
  113. live?: Record<string, string[]>;
  114. apply?: {
  115. ok: boolean;
  116. results?: Array<{
  117. key: string;
  118. type: string;
  119. host: string;
  120. ok: boolean;
  121. skipped?: boolean;
  122. detail?: string;
  123. error?: string;
  124. }>;
  125. };
  126. }
  127. export interface Domain {
  128. id: number;
  129. userId: number;
  130. dnsCredentialId: number | null;
  131. smtpRelayId: number | null;
  132. domain: string;
  133. selector: string;
  134. verificationToken: string;
  135. dkimPublic: string;
  136. senderHost: string;
  137. sendingIp: string;
  138. spfExtra: string;
  139. dmarcPolicy: string;
  140. dmarcRua: string;
  141. catchAllAddress: string;
  142. mailboxSignupEnabled: boolean;
  143. status: DomainStatus;
  144. createdAt: string;
  145. updatedAt: string;
  146. }
  147. export interface InboundMailboxDomain {
  148. id: number;
  149. userId: number;
  150. domain: string;
  151. mailboxSignupEnabled: boolean;
  152. }
  153. export interface DnsCredential {
  154. id: number;
  155. userId?: number;
  156. name: string;
  157. provider: 'cloudflare' | 'aliyun' | 'dnspod' | string;
  158. zoneName: string;
  159. defaultTtl: number;
  160. credentialSet?: boolean;
  161. createdAt: string;
  162. updatedAt: string;
  163. }
  164. export interface SmtpCredentialSummary {
  165. id?: number;
  166. userId?: number;
  167. username: string;
  168. passwordSet?: boolean;
  169. createdAt?: string;
  170. updatedAt?: string;
  171. }
  172. export interface SmtpCredentialInput {
  173. username: string;
  174. /** Write-only. The API never returns this value. */
  175. password?: string;
  176. }
  177. /** Backward-compatible name for existing page and admin model imports. */
  178. export type SmtpCredential = SmtpCredentialSummary;
  179. export interface SmtpRelaySummary {
  180. id: number;
  181. userId?: number;
  182. name: string;
  183. host: string;
  184. port: number;
  185. secure: boolean;
  186. username: string;
  187. passwordSet: boolean;
  188. helo: string;
  189. isDefault: boolean;
  190. createdAt?: string;
  191. updatedAt?: string;
  192. }
  193. export interface SmtpRelayInput {
  194. name: string;
  195. host: string;
  196. port: number | string;
  197. secure?: boolean;
  198. username?: string;
  199. password?: string;
  200. helo?: string;
  201. isDefault?: boolean;
  202. }
  203. /** Backward-compatible names for existing imports. */
  204. export type SmtpRelay = SmtpRelaySummary;
  205. export type SmtpRelayPayload = SmtpRelayInput;
  206. export interface SystemEmailSettings {
  207. host: string;
  208. port: number;
  209. secure: boolean;
  210. username: string;
  211. password?: string;
  212. passwordSet: boolean;
  213. helo: string;
  214. fromEmail: string;
  215. fromName: string;
  216. testRecipient: string;
  217. }
  218. export interface AdminResourceInventory {
  219. users: AdminUserResourceGroup[];
  220. warnings: Array<{
  221. type: 'domain_dns_credential_owner_mismatch' | string;
  222. domainId: number;
  223. domain: string;
  224. domainUserId: number;
  225. dnsCredentialId: number;
  226. dnsCredentialUserId: number;
  227. }>;
  228. }
  229. export interface AdminUserResourceGroup {
  230. user: AdminUser;
  231. domains: Domain[];
  232. dnsCredentials: DnsCredential[];
  233. smtpCredential: SmtpCredential | null;
  234. apiTokens: ApiToken[];
  235. inboundMailboxes: InboundMailbox[];
  236. inboundMessageCount: number;
  237. sendEventCount: number;
  238. }
  239. export interface UserMergeOptions {
  240. transferDomains: boolean;
  241. transferDnsCredentials: boolean;
  242. transferApiTokens: boolean;
  243. transferSendEvents: boolean;
  244. transferSmtpCredential: boolean;
  245. disableSource: boolean;
  246. }
  247. export interface UserMergePreview {
  248. sourceUser: User;
  249. targetUser: User;
  250. confirmationText: string;
  251. counts: UserResourceCounts;
  252. selectedCounts: UserResourceCounts;
  253. defaultOptions: UserMergeOptions;
  254. resources: {
  255. source: Omit<AdminUserResourceGroup, 'user'>;
  256. target: Omit<AdminUserResourceGroup, 'user'>;
  257. };
  258. smtp: {
  259. sourceCredential: SmtpCredential | null;
  260. targetCredential: SmtpCredential | null;
  261. conflict: boolean;
  262. };
  263. warnings: Array<{ type: string; message?: string }>;
  264. }
  265. export interface UserMergeResult {
  266. sourceUser: User;
  267. targetUser: User;
  268. counts: UserResourceCounts;
  269. warnings: UserMergePreview['warnings'];
  270. }
  271. export interface AuditLogEntry {
  272. id: number;
  273. actorUserId: number | null;
  274. action: string;
  275. targetType: string;
  276. targetId: string;
  277. targetUserId: number | null;
  278. summary: Record<string, unknown>;
  279. createdAt: string;
  280. }
  281. export type ApiTokenScope = 'send' | 'mailboxes:read' | 'mailboxes:write' | 'messages:read' | string;
  282. export type ApiTokenMailboxAccess = 'owner' | 'selected' | 'all';
  283. export interface ApiTokenInput {
  284. name?: string;
  285. scopes?: ApiTokenScope[];
  286. expiresAt?: string | null;
  287. mailboxAccess?: ApiTokenMailboxAccess;
  288. mailboxIds?: number[];
  289. }
  290. export interface ApiToken {
  291. id: number;
  292. userId?: number;
  293. name: string;
  294. tokenPrefix: string;
  295. token?: string;
  296. tokenRecoverable: boolean;
  297. scopes: ApiTokenScope[];
  298. mailboxAccess: ApiTokenMailboxAccess;
  299. mailboxIds: number[];
  300. expiresAt?: string | null;
  301. revokedAt?: string | null;
  302. revokedReason?: string;
  303. status?: 'active' | 'expired' | 'revoked' | string;
  304. lastUsedAt?: string;
  305. createdAt: string;
  306. }
  307. export interface InboundMailbox {
  308. id: number;
  309. userId: number;
  310. ownerUserId?: number;
  311. domainId: number;
  312. domain: string;
  313. address: string;
  314. localPart: string;
  315. displayName: string;
  316. aliases: string[];
  317. forwardTo: string[];
  318. keepForwarded: boolean;
  319. quotaMb: number | null;
  320. passwordSet: boolean;
  321. passwordRecoverable: boolean;
  322. status: string;
  323. expiresAt?: string | null;
  324. temporary?: boolean;
  325. messageCount: number | null;
  326. unreadCount: number | null;
  327. lastMessageAt?: string | null;
  328. access?: MailboxAccess;
  329. createdAt: string;
  330. updatedAt: string;
  331. }
  332. export interface AdminMailboxAccessGrant {
  333. user: User;
  334. permissions: MailboxPermissions;
  335. createdAt: string;
  336. updatedAt: string;
  337. }
  338. export interface AdminMailboxAccessEntry {
  339. mailbox: InboundMailbox;
  340. owner: User;
  341. grants: AdminMailboxAccessGrant[];
  342. }
  343. export interface MailboxClientConfig {
  344. username: string;
  345. password?: string;
  346. incoming: {
  347. protocol: string;
  348. host: string;
  349. port: number;
  350. security: string;
  351. authMethod: string;
  352. username: string;
  353. password?: string;
  354. };
  355. pop3?: {
  356. protocol: string;
  357. host: string;
  358. port: number;
  359. security: string;
  360. authMethod: string;
  361. username: string;
  362. password?: string;
  363. };
  364. outgoing: {
  365. protocol: string;
  366. host: string;
  367. port: number;
  368. security: string;
  369. authMethod: string;
  370. username: string;
  371. password?: string;
  372. };
  373. }
  374. export interface InboundMessage {
  375. id: number;
  376. mailboxId: number;
  377. userId: number;
  378. domainId: number;
  379. domain: string;
  380. mailboxAddress: string;
  381. folder: string;
  382. sender: string;
  383. recipients: string[];
  384. subject: string;
  385. messageId: string;
  386. preview: string;
  387. read: boolean;
  388. receivedAt: string;
  389. createdAt: string;
  390. updatedAt: string;
  391. rawMessage?: string;
  392. textBody?: string;
  393. htmlBody?: string;
  394. }
  395. export interface InboundFolder {
  396. name: string;
  397. specialUse: string | null;
  398. messageCount: number;
  399. unreadCount: number;
  400. }
  401. export interface PaginationQuery {
  402. page?: number;
  403. pageSize?: number;
  404. }
  405. export interface SendEventFilters extends PaginationQuery {
  406. status?: string;
  407. domainId?: number;
  408. from?: string;
  409. to?: string;
  410. recipient?: string;
  411. q?: string;
  412. }
  413. export interface InboundMessageFilters extends PaginationQuery {
  414. mailboxId?: number;
  415. folder?: string;
  416. read?: boolean;
  417. q?: string;
  418. }
  419. export interface PaginatedResult<T> {
  420. total: number;
  421. page: number;
  422. pageSize: number;
  423. items: T[];
  424. }
  425. export interface DeliveryLogEntry {
  426. at: string;
  427. phase: 'connect' | 'smtp' | 'auth' | 'envelope' | 'data' | 'queue' | 'quit' | 'error' | string;
  428. direction?: 'client' | 'server' | 'system' | string;
  429. command?: string;
  430. response?: string;
  431. message?: string;
  432. code?: number;
  433. ok?: boolean;
  434. messageBytes?: number;
  435. }
  436. export interface DeliveryAttempt {
  437. at: string;
  438. source?: string;
  439. queueId: string;
  440. recipient?: string;
  441. relay?: string;
  442. dsn?: string;
  443. status: string;
  444. response?: string;
  445. raw?: string;
  446. }
  447. export interface SendEventTimelineEntry {
  448. stage: string;
  449. at: string;
  450. tone: 'success' | 'warning' | 'error' | 'info' | 'neutral';
  451. status?: string;
  452. queueId?: string;
  453. recipient?: string;
  454. relay?: string;
  455. response?: string;
  456. webhookId?: number;
  457. responseStatus?: number | null;
  458. source?: string;
  459. targetOrigin?: string;
  460. trackingLinkId?: number | null;
  461. }
  462. export interface TrackingEvent {
  463. id: number;
  464. sendEventId: number;
  465. trackingLinkId?: number | null;
  466. eventType: 'open' | 'click';
  467. source: 'direct' | 'proxy' | 'scanner';
  468. occurredAt: string;
  469. userAgent?: string;
  470. targetOrigin?: string;
  471. }
  472. export interface TrackingLink {
  473. id: number;
  474. target: string;
  475. targetOrigin: string;
  476. clicks: number;
  477. firstClickedAt?: string | null;
  478. lastClickedAt?: string | null;
  479. }
  480. export interface TrackingSummary {
  481. totalOpens: number;
  482. totalClicks: number;
  483. uniqueOpen: boolean;
  484. uniqueClick: boolean;
  485. proxyOpens: number;
  486. scannerEvents: number;
  487. firstOpenedAt?: string | null;
  488. lastOpenedAt?: string | null;
  489. firstClickedAt?: string | null;
  490. lastClickedAt?: string | null;
  491. }
  492. export interface SendTracking {
  493. enabled: boolean;
  494. opens: boolean;
  495. clicks: boolean;
  496. messageLevel: boolean;
  497. summary?: TrackingSummary;
  498. events?: TrackingEvent[];
  499. eventCount?: number;
  500. eventsTruncated?: boolean;
  501. links?: TrackingLink[];
  502. linkCount?: number;
  503. linksTruncated?: boolean;
  504. }
  505. export interface SendEvent {
  506. id: number;
  507. userId: number;
  508. domainId: number | null;
  509. smtpRelayId: number | null;
  510. domain?: string;
  511. sender: string;
  512. recipients: string[];
  513. subject: string;
  514. status: string;
  515. detail: string;
  516. queueId?: string;
  517. messageId?: string;
  518. deliveryLog?: DeliveryLogEntry[];
  519. deliveryAttempts?: DeliveryAttempt[];
  520. webhookDeliveries?: WebhookDelivery[];
  521. tracking?: SendTracking;
  522. deliveredAt?: string;
  523. createdAt: string;
  524. }
  525. export interface Analytics {
  526. windowDays: number;
  527. summary: {
  528. total: number;
  529. submitted: number;
  530. queued: number;
  531. failed: number;
  532. accepted: number;
  533. delivered: number;
  534. pending: number;
  535. deferred: number;
  536. bounced: number;
  537. terminalFailed: number;
  538. recipients: number;
  539. today: number;
  540. last7Days: number;
  541. successRate: number;
  542. acceptanceRate: number;
  543. deliveryRate: number;
  544. failureRate: number;
  545. domains: number;
  546. verifiedDomains: number;
  547. };
  548. deliveryFunnel: Array<{
  549. stage: string;
  550. total: number;
  551. rate: number;
  552. }>;
  553. engagement: {
  554. trackedDelivered: number;
  555. totalOpens: number;
  556. uniqueOpens: number;
  557. proxyOpens: number;
  558. totalClicks: number;
  559. uniqueClicks: number;
  560. scannerEvents: number;
  561. openRate: number;
  562. clickRate: number;
  563. clickToOpenRate: number;
  564. };
  565. engagementByDay: Array<{
  566. day: string;
  567. opens: number;
  568. uniqueOpens: number;
  569. clicks: number;
  570. uniqueClicks: number;
  571. scannerEvents: number;
  572. }>;
  573. topLinks: Array<{
  574. fingerprint: string;
  575. target: string;
  576. targetOrigin: string;
  577. clicks: number;
  578. uniqueClicks: number;
  579. lastClickedAt: string;
  580. }>;
  581. byDay: Array<{
  582. day: string;
  583. date?: string;
  584. total: number;
  585. queued: number;
  586. failed: number;
  587. accepted?: number;
  588. delivered?: number;
  589. pending?: number;
  590. terminalFailed?: number;
  591. recipients: number;
  592. }>;
  593. byDomain: Array<{
  594. domain: string;
  595. total: number;
  596. queued: number;
  597. failed: number;
  598. accepted?: number;
  599. delivered?: number;
  600. pending?: number;
  601. terminalFailed?: number;
  602. recipients: number;
  603. }>;
  604. byStatus: Array<{ status: string; total: number }>;
  605. hourly: Array<{
  606. hour: number;
  607. total: number;
  608. queued: number;
  609. failed: number;
  610. accepted?: number;
  611. delivered?: number;
  612. pending?: number;
  613. terminalFailed?: number;
  614. }>;
  615. failureReasons: Array<{
  616. reason: string;
  617. total: number;
  618. statuses: Record<string, number>;
  619. lastSeenAt: string;
  620. }>;
  621. recentFailures: SendEvent[];
  622. }
  623. export interface AppData {
  624. me: User | null;
  625. config: RuntimeConfig | null;
  626. domains: Domain[];
  627. events: SendEvent[];
  628. analytics: Analytics | null;
  629. smtpCredential: SmtpCredential | null;
  630. smtpCredentials: SmtpCredential[];
  631. smtpRelays: SmtpRelay[];
  632. inboundMailboxes: InboundMailbox[];
  633. inboundMessages: InboundMessage[];
  634. dnsCredentials: DnsCredential[];
  635. apiTokens: ApiToken[];
  636. settings: RuntimeConfig | null;
  637. users: User[];
  638. }
  639. export interface AddDomainPayload {
  640. domain: string;
  641. senderHost?: string;
  642. sendingIp?: string;
  643. dnsCredentialId?: number | string;
  644. smtpRelayId?: number | string | null;
  645. selector?: string;
  646. dmarcPolicy?: string;
  647. spfExtra?: string;
  648. immediateCheck?: boolean;
  649. }
  650. export interface DomainPatchPayload {
  651. selector?: string;
  652. dnsCredentialId?: number | string | null;
  653. smtpRelayId?: number | string | null;
  654. senderHost?: string;
  655. sendingIp?: string;
  656. spfExtra?: string;
  657. dmarcPolicy?: string;
  658. dmarcRua?: string;
  659. catchAllAddress?: string;
  660. mailboxSignupEnabled?: boolean;
  661. }
  662. export type WebhookEvent = 'sent' | 'bounced' | 'failed' | 'opened' | 'clicked' | 'received';
  663. export type WebhookDeliveryStatus = 'pending' | 'processing' | 'success' | 'dead';
  664. export interface Webhook {
  665. id: number;
  666. userId: number;
  667. domainId: number | null;
  668. mailboxId: number | null;
  669. name: string;
  670. url: string;
  671. secretPrefix: string;
  672. events: WebhookEvent[];
  673. enabled: boolean;
  674. createdAt: string;
  675. updatedAt: string;
  676. /** Present only on create / rotate-secret responses. */
  677. secret?: string;
  678. }
  679. export interface WebhookPayload {
  680. name: string;
  681. url: string;
  682. events: WebhookEvent[];
  683. domainId?: number | string | null;
  684. mailboxId?: number | string | null;
  685. enabled?: boolean;
  686. }
  687. export interface WebhookPatchPayload {
  688. name?: string;
  689. url?: string;
  690. events?: WebhookEvent[];
  691. domainId?: number | string | null;
  692. mailboxId?: number | string | null;
  693. enabled?: boolean;
  694. }
  695. export interface WebhookDelivery {
  696. id: number;
  697. webhookId: number;
  698. userId: number;
  699. sendEventId: number;
  700. inboundMessageId?: number | null;
  701. eventType: WebhookEvent | string;
  702. payloadJson?: string;
  703. status: WebhookDeliveryStatus | string;
  704. attemptCount: number;
  705. nextAttemptAt?: string | null;
  706. lastAttemptAt?: string | null;
  707. responseStatus?: number | null;
  708. responseBodyPreview?: string;
  709. error?: string;
  710. createdAt: string;
  711. }
  712. export interface WebhookDeliveryFilters {
  713. status?: WebhookDeliveryStatus | string;
  714. webhookId?: number;
  715. eventType?: WebhookEvent | string;
  716. limit?: number;
  717. }