tempmail-sdk 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.md +162 -72
  2. package/demo/poll-emails.ts +25 -40
  3. package/dist/index.d.ts +96 -2
  4. package/dist/index.js +186 -21
  5. package/dist/logger.d.ts +73 -0
  6. package/dist/logger.js +100 -0
  7. package/dist/normalize.d.ts +12 -0
  8. package/dist/normalize.js +132 -0
  9. package/dist/providers/awamail.d.ts +15 -0
  10. package/dist/providers/awamail.js +91 -0
  11. package/dist/providers/chatgpt-org-uk.js +4 -2
  12. package/dist/providers/dropmail.d.ts +13 -0
  13. package/dist/providers/dropmail.js +86 -0
  14. package/dist/providers/linshi-email.js +4 -2
  15. package/dist/providers/mail-tm.d.ts +11 -0
  16. package/dist/providers/mail-tm.js +172 -0
  17. package/dist/providers/temp-mail-io.d.ts +13 -0
  18. package/dist/providers/temp-mail-io.js +99 -0
  19. package/dist/providers/tempmail-la.d.ts +15 -0
  20. package/dist/providers/tempmail-la.js +89 -0
  21. package/dist/providers/tempmail-lol.d.ts +1 -1
  22. package/dist/providers/tempmail-lol.js +5 -3
  23. package/dist/providers/tempmail.js +4 -2
  24. package/dist/retry.d.ts +38 -0
  25. package/dist/retry.js +121 -0
  26. package/dist/types.d.ts +118 -28
  27. package/dist/types.js +1 -1
  28. package/package.json +1 -1
  29. package/src/index.ts +182 -25
  30. package/src/logger.ts +106 -0
  31. package/src/normalize.ts +125 -0
  32. package/src/providers/awamail.ts +101 -0
  33. package/src/providers/chatgpt-org-uk.ts +3 -1
  34. package/src/providers/dropmail.ts +98 -0
  35. package/src/providers/linshi-email.ts +3 -1
  36. package/src/providers/mail-tm.ts +193 -0
  37. package/src/providers/temp-mail-io.ts +108 -0
  38. package/src/providers/tempmail-la.ts +99 -0
  39. package/src/providers/tempmail-lol.ts +4 -2
  40. package/src/providers/tempmail.ts +3 -1
  41. package/src/retry.ts +146 -0
  42. package/src/types.ts +120 -28
  43. package/test/example.ts +16 -1
package/dist/retry.js ADDED
@@ -0,0 +1,121 @@
1
+ "use strict";
2
+ /**
3
+ * 通用重试工具
4
+ * 提供请求重试、超时控制、指数退避等错误恢复机制
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.withRetry = withRetry;
8
+ exports.fetchWithTimeout = fetchWithTimeout;
9
+ const logger_1 = require("./logger");
10
+ const DEFAULT_RETRY_OPTIONS = {
11
+ maxRetries: 2,
12
+ initialDelay: 1000,
13
+ maxDelay: 5000,
14
+ timeout: 15000,
15
+ shouldRetry: defaultShouldRetry,
16
+ };
17
+ /**
18
+ * 默认重试判断
19
+ * 网络错误、超时、HTTP 4xx/5xx 错误均可重试
20
+ * 仅参数校验类错误(由 SDK 内部抛出)不重试
21
+ */
22
+ function defaultShouldRetry(error) {
23
+ if (!error)
24
+ return false;
25
+ const message = String(error.message || error || '').toLowerCase();
26
+ /* 网络级别错误 → 重试 */
27
+ if (message.includes('fetch failed') ||
28
+ message.includes('network') ||
29
+ message.includes('econnrefused') ||
30
+ message.includes('econnreset') ||
31
+ message.includes('etimedout') ||
32
+ message.includes('timeout') ||
33
+ message.includes('socket hang up') ||
34
+ message.includes('dns') ||
35
+ message.includes('abort')) {
36
+ return true;
37
+ }
38
+ /* HTTP 4xx/5xx 错误 → 重试 */
39
+ const statusMatch = message.match(/:\s*(\d{3})/);
40
+ if (statusMatch) {
41
+ const status = parseInt(statusMatch[1], 10);
42
+ return status >= 400;
43
+ }
44
+ return false;
45
+ }
46
+ /**
47
+ * 休眠指定毫秒
48
+ */
49
+ function sleep(ms) {
50
+ return new Promise(resolve => setTimeout(resolve, ms));
51
+ }
52
+ /**
53
+ * 带重试的异步操作执行器
54
+ * - 自动重试可恢复的错误(网络错误、超时、5xx)
55
+ * - 指数退避避免过度请求
56
+ * - 不可恢复的错误(4xx 参数错误等)直接抛出不重试
57
+ *
58
+ * @param fn 要执行的异步操作
59
+ * @param options 重试配置
60
+ */
61
+ async function withRetry(fn, options) {
62
+ const opts = { ...DEFAULT_RETRY_OPTIONS, ...options };
63
+ let lastError;
64
+ for (let attempt = 0; attempt <= opts.maxRetries; attempt++) {
65
+ try {
66
+ const result = await fn();
67
+ if (attempt > 0) {
68
+ logger_1.logger.info(`第 ${attempt + 1} 次尝试成功`);
69
+ }
70
+ return result;
71
+ }
72
+ catch (error) {
73
+ lastError = error;
74
+ const errorMsg = error.message || String(error);
75
+ /* 最后一次尝试失败或不可重试的错误 → 直接抛出 */
76
+ if (attempt >= opts.maxRetries || !opts.shouldRetry(error)) {
77
+ if (attempt >= opts.maxRetries && opts.maxRetries > 0) {
78
+ logger_1.logger.error(`重试 ${opts.maxRetries} 次后仍失败: ${errorMsg}`);
79
+ }
80
+ else if (!opts.shouldRetry(error)) {
81
+ logger_1.logger.debug(`不可重试的错误: ${errorMsg}`);
82
+ }
83
+ throw error;
84
+ }
85
+ /* 指数退避等待 */
86
+ const delay = Math.min(opts.initialDelay * Math.pow(2, attempt), opts.maxDelay);
87
+ logger_1.logger.warn(`请求失败 (${errorMsg}),${delay}ms 后第 ${attempt + 2} 次重试...`);
88
+ await sleep(delay);
89
+ }
90
+ }
91
+ throw lastError;
92
+ }
93
+ /**
94
+ * 带超时控制的 fetch 包装
95
+ * 在原生 fetch 基础上添加超时中断能力
96
+ *
97
+ * @param url 请求 URL
98
+ * @param init fetch 选项
99
+ * @param timeoutMs 超时时间(毫秒)
100
+ */
101
+ async function fetchWithTimeout(url, init, timeoutMs = DEFAULT_RETRY_OPTIONS.timeout) {
102
+ const controller = new AbortController();
103
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
104
+ try {
105
+ const response = await fetch(url, {
106
+ ...init,
107
+ signal: controller.signal,
108
+ });
109
+ return response;
110
+ }
111
+ catch (error) {
112
+ if (error.name === 'AbortError') {
113
+ throw new Error(`Request timeout after ${timeoutMs}ms: ${url}`);
114
+ }
115
+ throw error;
116
+ }
117
+ finally {
118
+ clearTimeout(timeoutId);
119
+ }
120
+ }
121
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmV0cnkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvcmV0cnkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7R0FHRzs7QUE2RUgsOEJBaUNDO0FBVUQsNENBc0JDO0FBNUlELHFDQUFrQztBQWtCbEMsTUFBTSxxQkFBcUIsR0FBMkI7SUFDcEQsVUFBVSxFQUFFLENBQUM7SUFDYixZQUFZLEVBQUUsSUFBSTtJQUNsQixRQUFRLEVBQUUsSUFBSTtJQUNkLE9BQU8sRUFBRSxLQUFLO0lBQ2QsV0FBVyxFQUFFLGtCQUFrQjtDQUNoQyxDQUFDO0FBRUY7Ozs7R0FJRztBQUNILFNBQVMsa0JBQWtCLENBQUMsS0FBVTtJQUNwQyxJQUFJLENBQUMsS0FBSztRQUFFLE9BQU8sS0FBSyxDQUFDO0lBRXpCLE1BQU0sT0FBTyxHQUFHLE1BQU0sQ0FBQyxLQUFLLENBQUMsT0FBTyxJQUFJLEtBQUssSUFBSSxFQUFFLENBQUMsQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUVuRSxpQkFBaUI7SUFDakIsSUFBSSxPQUFPLENBQUMsUUFBUSxDQUFDLGNBQWMsQ0FBQztRQUNoQyxPQUFPLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQztRQUMzQixPQUFPLENBQUMsUUFBUSxDQUFDLGNBQWMsQ0FBQztRQUNoQyxPQUFPLENBQUMsUUFBUSxDQUFDLFlBQVksQ0FBQztRQUM5QixPQUFPLENBQUMsUUFBUSxDQUFDLFdBQVcsQ0FBQztRQUM3QixPQUFPLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQztRQUMzQixPQUFPLENBQUMsUUFBUSxDQUFDLGdCQUFnQixDQUFDO1FBQ2xDLE9BQU8sQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDO1FBQ3ZCLE9BQU8sQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztRQUM5QixPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFRCwwQkFBMEI7SUFDMUIsTUFBTSxXQUFXLEdBQUcsT0FBTyxDQUFDLEtBQUssQ0FB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bEUsSUFBSSxDQUFDO1FBQ0gsTUFBTSxRQUFRLEdBQUcsTUFBTSxLQUFLLENBQUMsR0FBRyxFQUFFO1lBQ2hDLEdBQUcsSUFBSTtZQUNQLE1BQU0sRUFBRSxVQUFVLENBQUMsTUFBTTtTQUMxQixDQUFDLENBQUM7UUFDSCxPQUFPLFFBQVEsQ0FBQztJQUNsQixDQUFDO0lBQUMsT0FBTyxLQUFVLEVBQUUsQ0FBQztRQUNwQixJQUFJLEtBQUssQ0FBQyxJQUFJLEtBQUssWUFBWSxFQUFFLENBQUM7WUFDaEMsTUFBTSxJQUFJLEtBQUssQ0FBQyx5QkFBeUIsU0FBUyxPQUFPLEdBQUcsRUFBRSxDQUFDLENBQUM7UUFDbEUsQ0FBQztRQUNELE1BQU0sS0FBSyxDQUFDO0lBQ2QsQ0FBQztZQUFTLENBQUM7UUFDVCxZQUFZLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDMUIsQ0FBQztBQUNILENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIOmAmueUqOmHjeivleW3peWFt1xuICog5o+Q5L6b6K+35rGC6YeN6K+V44CB6LaF5pe25o6n5Yi244CB5oyH5pWw6YCA6YG/562J6ZSZ6K+v5oGi5aSN5py65Yi2XG4gKi9cblxuaW1wb3J0IHsgbG9nZ2VyIH0gZnJvbSAnLi9sb2dnZXInO1xuXG4vKipcbiAqIOmHjeivlemFjee9rumAiemhuVxuICovXG5leHBvcnQgaW50ZXJmYWNlIFJldHJ5T3B0aW9ucyB7XG4gIC8qKiDmnIDlpKfph43or5XmrKHmlbDvvIjkuI3lkKvpppbmrKHor7fmsYLvvInvvIzpu5jorqQgMiAqL1xuICBtYXhSZXRyaWVzPzogbnVtYmVyO1xuICAvKiog5Yid5aeL6YeN6K+V5bu26L+f77yI5q+r56eS77yJ77yM6buY6K6kIDEwMDAgKi9cbiAgaW5pdGlhbERlbGF5PzogbnVtYmVyO1xuICAvKiog5pyA5aSn6YeN6K+V5bu26L+f77yI5q+r56eS77yJ77yM6buY6K6kIDUwMDAgKi9cbiAgbWF4RGVsYXk/OiBudW1iZXI7XG4gIC8qKiDor7fmsYLotoXml7bml7bpl7TvvIjmr6vnp5LvvInvvIzpu5jorqQgMTUwMDAgKi9cbiAgdGltZW91dD86IG51bWJlcjtcbiAgLyoqIOaYr+WQpuWvueivpemUmeivr+i/m+ihjOmHjeivleeahOWIpOaWreWHveaVsCAqL1xuICBzaG91bGRSZXRyeT86IChlcnJvcjogYW55KSA9PiBib29sZWFuO1xufVxuXG5jb25zdCBERUZBVUxUX1JFVFJZX09QVElPTlM6IFJlcXVpcmVkPFJldHJ5T3B0aW9ucz4gPSB7XG4gIG1heFJldHJpZXM6IDIsXG4gIGluaXRpYWxEZWxheTogMTAwMCxcbiAgbWF4RGVsYXk6IDUwMDAsXG4gIHRpbWVvdXQ6IDE1MDAwLFxuICBzaG91bGRSZXRyeTogZGVmYXVsdFNob3VsZFJldHJ5LFxufTtcblxuLyoqXG4gKiDpu5jorqTph43or5XliKTmlq1cbiAqIOe9kee7nOmUmeivr+OAgei2heaXtuOAgUhUVFAgNHh4LzV4eCDplJnor6/lnYflj6/ph43or5VcbiAqIOS7heWPguaVsOagoemqjOexu+mUmeivr++8iOeUsSBTREsg5YaF6YOo5oqb5Ye677yJ5LiN6YeN6K+VXG4gKi9cbmZ1bmN0aW9uIGRlZmF1bHRTaG91bGRSZXRyeShlcnJvcjogYW55KTogYm9vbGVhbiB7XG4gIGlmICghZXJyb3IpIHJldHVybiBmYWxzZTtcblxuICBjb25zdCBtZXNzYWdlID0gU3RyaW5nKGVycm9yLm1lc3NhZ2UgfHwgZXJyb3IgfHwgJycpLnRvTG93ZXJDYXNlKCk7XG5cbiAgLyog572R57uc57qn5Yir6ZSZ6K+vIOKGkiDph43or5UgKi9cbiAgaWYgKG1lc3NhZ2UuaW5jbHVkZXMoJ2ZldGNoIGZhaWxlZCcpIHx8XG4gICAgICBtZXNzYWdlLmluY2x1ZGVzKCduZXR3b3JrJykgfHxcbiAgICAgIG1lc3NhZ2UuaW5jbHVkZXMoJ2Vjb25ucmVmdXNlZCcpIHx8XG4gICAgICBtZXNzYWdlLmluY2x1ZGVzKCdlY29ubnJlc2V0JykgfHxcbiAgICAgIG1lc3NhZ2UuaW5jbHVkZXMoJ2V0aW1lZG91dCcpIHx8XG4gICAgICBtZXNzYWdlLmluY2x1ZGVzKCd0aW1lb3V0JykgfHxcbiAgICAgIG1lc3NhZ2UuaW5jbHVkZXMoJ3NvY2tldCBoYW5nIHVwJykgfHxcbiAgICAgIG1lc3NhZ2UuaW5jbHVkZXMoJ2RucycpIHx8XG4gICAgICBtZXNzYWdlLmluY2x1ZGVzKCdhYm9ydCcpKSB7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICAvKiBIVFRQIDR4eC81eHgg6ZSZ6K+vIOKGkiDph43or5UgKi9cbiAgY29uc3Qgc3RhdHVzTWF0Y2ggPSBtZXNzYWdlLm1hdGNoKC86XFxzKihcXGR7M30pLyk7XG4gIGlmIChzdGF0dXNNYXRjaCkge1xuICAgIGNvbnN0IHN0YXR1cyA9IHBhcnNlSW50KHN0YXR1c01hdGNoWzFdLCAxMCk7XG4gICAgcmV0dXJuIHN0YXR1cyA+PSA0MDA7XG4gIH1cblxuICByZXR1cm4gZmFsc2U7XG59XG5cbi8qKlxuICog5LyR55yg5oyH5a6a5q+r56eSXG4gKi9cbmZ1bmN0aW9uIHNsZWVwKG1zOiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+IHtcbiAgcmV0dXJuIG5ldyBQcm9taXNlKHJlc29sdmUgPT4gc2V0VGltZW91dChyZXNvbHZlLCBtcykpO1xufVxuXG4vKipcbiAqIOW4pumHjeivleeahOW8guatpeaTjeS9nOaJp+ihjOWZqFxuICogLSDoh6rliqjph43or5Xlj6/mgaLlpI3nmoTplJnor6/vvIjnvZHnu5zplJnor6/jgIHotoXml7bjgIE1eHjvvIlcbiAqIC0g5oyH5pWw6YCA6YG/6YG/5YWN6L+H5bqm6K+35rGCXG4gKiAtIOS4jeWPr+aBouWkjeeahOmUmeivr++8iDR4eCDlj4LmlbDplJnor6/nrYnvvInnm7TmjqXmipvlh7rkuI3ph43or5VcbiAqXG4gKiBAcGFyYW0gZm4g6KaB5omn6KGM55qE5byC5q2l5pON5L2cXG4gKiBAcGFyYW0gb3B0aW9ucyDph43or5XphY3nva5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHdpdGhSZXRyeTxUPihmbjogKCkgPT4gUHJvbWlzZTxUPiwgb3B0aW9ucz86IFJldHJ5T3B0aW9ucyk6IFByb21pc2U8VD4ge1xuICBjb25zdCBvcHRzID0geyAuLi5ERUZBVUxUX1JFVFJZX09QVElPTlMsIC4uLm9wdGlvbnMgfTtcbiAgbGV0IGxhc3RFcnJvcjogYW55O1xuXG4gIGZvciAobGV0IGF0dGVtcHQgPSAwOyBhdHRlbXB0IDw9IG9wdHMubWF4UmV0cmllczsgYXR0ZW1wdCsrKSB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGZuKCk7XG4gICAgICBpZiAoYXR0ZW1wdCA+IDApIHtcbiAgICAgICAgbG9nZ2VyLmluZm8oYOesrCAke2F0dGVtcHQgKyAxfSDmrKHlsJ3or5XmiJDlip9gKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfSBjYXRjaCAoZXJyb3I6IGFueSkge1xuICAgICAgbGFzdEVycm9yID0gZXJyb3I7XG4gICAgICBjb25zdCBlcnJvck1zZyA9IGVycm9yLm1lc3NhZ2UgfHwgU3RyaW5nKGVycm9yKTtcblxuICAgICAgLyog5pyA5ZCO5LiA5qyh5bCd6K+V5aSx6LSl5oiW5LiN5Y+v6YeN6K+V55qE6ZSZ6K+vIOKGkiDnm7TmjqXmipvlh7ogKi9cbiAgICAgIGlmIChhdHRlbXB0ID49IG9wdHMubWF4UmV0cmllcyB8fCAhb3B0cy5zaG91bGRSZXRyeShlcnJvcikpIHtcbiAgICAgICAgaWYgKGF0dGVtcHQgPj0gb3B0cy5tYXhSZXRyaWVzICYmIG9wdHMubWF4UmV0cmllcyA+IDApIHtcbiAgICAgICAgICBsb2dnZXIuZXJyb3IoYOmHjeivlSAke29wdHMubWF4UmV0cmllc30g5qyh5ZCO5LuN5aSx6LSlOiAke2Vycm9yTXNnfWApO1xuICAgICAgICB9IGVsc2UgaWYgKCFvcHRzLnNob3VsZFJldHJ5KGVycm9yKSkge1xuICAgICAgICAgIGxvZ2dlci5kZWJ1Zyhg5LiN5Y+v6YeN6K+V55qE6ZSZ6K+vOiAke2Vycm9yTXNnfWApO1xuICAgICAgICB9XG4gICAgICAgIHRocm93IGVycm9yO1xuICAgICAgfVxuXG4gICAgICAvKiDmjIfmlbDpgIDpgb/nrYnlvoUgKi9cbiAgICAgIGNvbnN0IGRlbGF5ID0gTWF0aC5taW4ob3B0cy5pbml0aWFsRGVsYXkgKiBNYXRoLnBvdygyLCBhdHRlbXB0KSwgb3B0cy5tYXhEZWxheSk7XG4gICAgICBsb2dnZXIud2Fybihg6K+35rGC5aSx6LSlICgke2Vycm9yTXNnfSnvvIwke2RlbGF5fW1zIOWQjuesrCAke2F0dGVtcHQgKyAyfSDmrKHph43or5UuLi5gKTtcbiAgICAgIGF3YWl0IHNsZWVwKGRlbGF5KTtcbiAgICB9XG4gIH1cblxuICB0aHJvdyBsYXN0RXJyb3I7XG59XG5cbi8qKlxuICog5bim6LaF5pe25o6n5Yi255qEIGZldGNoIOWMheijhVxuICog5Zyo5Y6f55SfIGZldGNoIOWfuuehgOS4iua3u+WKoOi2heaXtuS4reaWreiDveWKm1xuICpcbiAqIEBwYXJhbSB1cmwg6K+35rGCIFVSTFxuICogQHBhcmFtIGluaXQgZmV0Y2gg6YCJ6aG5XG4gKiBAcGFyYW0gdGltZW91dE1zIOi2heaXtuaXtumXtO+8iOavq+enku+8iVxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZmV0Y2hXaXRoVGltZW91dChcbiAgdXJsOiBzdHJpbmcsXG4gIGluaXQ/OiBSZXF1ZXN0SW5pdCxcbiAgdGltZW91dE1zOiBudW1iZXIgPSBERUZBVUxUX1JFVFJZX09QVElPTlMudGltZW91dCxcbik6IFByb21pc2U8UmVzcG9uc2U+IHtcbiAgY29uc3QgY29udHJvbGxlciA9IG5ldyBBYm9ydENvbnRyb2xsZXIoKTtcbiAgY29uc3QgdGltZW91dElkID0gc2V0VGltZW91dCgoKSA9PiBjb250cm9sbGVyLmFib3J0KCksIHRpbWVvdXRNcyk7XG5cbiAgdHJ5IHtcbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKHVybCwge1xuICAgICAgLi4uaW5pdCxcbiAgICAgIHNpZ25hbDogY29udHJvbGxlci5zaWduYWwsXG4gICAgfSk7XG4gICAgcmV0dXJuIHJlc3BvbnNlO1xuICB9IGNhdGNoIChlcnJvcjogYW55KSB7XG4gICAgaWYgKGVycm9yLm5hbWUgPT09ICdBYm9ydEVycm9yJykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBSZXF1ZXN0IHRpbWVvdXQgYWZ0ZXIgJHt0aW1lb3V0TXN9bXM6ICR7dXJsfWApO1xuICAgIH1cbiAgICB0aHJvdyBlcnJvcjtcbiAgfSBmaW5hbGx5IHtcbiAgICBjbGVhclRpbWVvdXQodGltZW91dElkKTtcbiAgfVxufVxuIl19
package/dist/types.d.ts CHANGED
@@ -1,53 +1,143 @@
1
- export type Channel = 'tempmail' | 'linshi-email' | 'tempmail-lol' | 'chatgpt-org-uk';
1
+ /**
2
+ * 支持的临时邮箱渠道标识
3
+ * 每个渠道对应一个第三方临时邮箱服务商
4
+ */
5
+ export type Channel = 'tempmail' | 'linshi-email' | 'tempmail-lol' | 'chatgpt-org-uk' | 'tempmail-la' | 'temp-mail-io' | 'awamail' | 'mail-tm' | 'dropmail';
6
+ /**
7
+ * 创建临时邮箱后返回的邮箱信息
8
+ * 包含邮箱地址、认证令牌和生命周期信息
9
+ */
2
10
  export interface EmailInfo {
11
+ /** 创建该邮箱所使用的渠道 */
3
12
  channel: Channel;
13
+ /** 临时邮箱地址 */
4
14
  email: string;
15
+ /** 认证令牌,部分渠道在获取邮件时需要此令牌 */
5
16
  token?: string;
17
+ /** 邮箱过期时间(ISO 8601 字符串或 Unix 时间戳) */
6
18
  expiresAt?: string | number;
19
+ /** 邮箱创建时间(ISO 8601 字符串) */
7
20
  createdAt?: string;
8
21
  }
22
+ /**
23
+ * 标准化邮件附件
24
+ * 不同渠道的附件字段名不同,SDK 统一归一化为此结构
25
+ */
26
+ export interface EmailAttachment {
27
+ /** 附件文件名 */
28
+ filename: string;
29
+ /** 附件大小(字节) */
30
+ size?: number;
31
+ /** MIME 类型,如 application/pdf */
32
+ contentType?: string;
33
+ /** 附件下载地址 */
34
+ url?: string;
35
+ }
36
+ /**
37
+ * 标准化邮件格式 - 所有提供商返回统一结构
38
+ */
9
39
  export interface Email {
10
- id?: string | number;
11
- eid?: string;
12
- _id?: string;
13
- from?: string;
14
- from_address?: string;
15
- from_name?: string;
16
- address_from?: string;
17
- name_from?: string;
18
- to?: string;
19
- name_to?: string;
20
- email_address?: string;
21
- subject?: string;
22
- e_subject?: string;
23
- body?: string;
24
- text?: string;
25
- content?: string;
26
- html?: string;
27
- html_content?: string;
28
- date?: string | number;
29
- e_date?: number;
30
- timestamp?: number;
31
- received_at?: string;
32
- created_at?: string;
33
- createdAt?: string;
34
- is_read?: number;
35
- has_html?: boolean;
36
- [key: string]: any;
40
+ /** 邮件唯一标识 */
41
+ id: string;
42
+ /** 发件人邮箱地址 */
43
+ from: string;
44
+ /** 收件人邮箱地址 */
45
+ to: string;
46
+ /** 邮件主题 */
47
+ subject: string;
48
+ /** 纯文本内容 */
49
+ text: string;
50
+ /** HTML 内容 */
51
+ html: string;
52
+ /** ISO 8601 格式的日期字符串 */
53
+ date: string;
54
+ /** 是否已读 */
55
+ isRead: boolean;
56
+ /** 附件列表 */
57
+ attachments: EmailAttachment[];
37
58
  }
59
+ /**
60
+ * 获取邮件列表的返回结果
61
+ * success 为 false 时表示请求失败(重试耗尽),emails 为空数组
62
+ */
38
63
  export interface GetEmailsResult {
64
+ /** 所使用的渠道 */
39
65
  channel: Channel;
66
+ /** 查询的邮箱地址 */
40
67
  email: string;
68
+ /** 邮件列表,失败时为空数组 */
41
69
  emails: Email[];
70
+ /** 请求是否成功,false 表示重试耗尽后仍失败 */
42
71
  success: boolean;
43
72
  }
73
+ /**
74
+ * 重试配置
75
+ * SDK 内部对网络错误、超时、5xx 服务端错误自动重试
76
+ * 4xx 客户端错误(如参数错误)不会重试
77
+ *
78
+ * @example
79
+ * ```ts
80
+ * // 自定义重试策略:最多重试 3 次,首次延迟 2 秒
81
+ * const email = await generateEmail({
82
+ * channel: 'mail-tm',
83
+ * retry: { maxRetries: 3, initialDelay: 2000 },
84
+ * });
85
+ * ```
86
+ */
87
+ export interface RetryConfig {
88
+ /** 最大重试次数(不含首次请求),默认 2 */
89
+ maxRetries?: number;
90
+ /** 初始重试延迟(毫秒),采用指数退避策略,默认 1000 */
91
+ initialDelay?: number;
92
+ /** 最大重试延迟上限(毫秒),默认 5000 */
93
+ maxDelay?: number;
94
+ /** 单次请求超时时间(毫秒),默认 15000 */
95
+ timeout?: number;
96
+ }
97
+ /**
98
+ * 创建临时邮箱的选项
99
+ *
100
+ * @example
101
+ * ```ts
102
+ * // 使用指定渠道创建邮箱
103
+ * const email = await generateEmail({ channel: 'mail-tm' });
104
+ *
105
+ * // 随机选择渠道
106
+ * const email = await generateEmail();
107
+ * ```
108
+ */
44
109
  export interface GenerateEmailOptions {
110
+ /** 指定渠道,不传则随机选择 */
45
111
  channel?: Channel;
112
+ /** 邮箱有效时长 */
46
113
  duration?: number;
114
+ /** 指定邮箱域名 */
47
115
  domain?: string | null;
116
+ /** 重试配置,不传则使用默认值(最多重试 2 次) */
117
+ retry?: RetryConfig;
48
118
  }
119
+ /**
120
+ * 获取邮件列表的选项
121
+ *
122
+ * @example
123
+ * ```ts
124
+ * const result = await getEmails({
125
+ * channel: emailInfo.channel,
126
+ * email: emailInfo.email,
127
+ * token: emailInfo.token,
128
+ * });
129
+ * if (result.success && result.emails.length > 0) {
130
+ * console.log('收到邮件:', result.emails);
131
+ * }
132
+ * ```
133
+ */
49
134
  export interface GetEmailsOptions {
135
+ /** 渠道标识,必填 */
50
136
  channel: Channel;
137
+ /** 邮箱地址,必填 */
51
138
  email: string;
139
+ /** 认证令牌 */
52
140
  token?: string;
141
+ /** 重试配置,不传则使用默认值(最多重试 2 次) */
142
+ retry?: RetryConfig;
53
143
  }
package/dist/types.js CHANGED
@@ -1,3 +1,3 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvdHlwZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiIsInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCB0eXBlIENoYW5uZWwgPSAndGVtcG1haWwnIHwgJ2xpbnNoaS1lbWFpbCcgfCAndGVtcG1haWwtbG9sJyB8ICdjaGF0Z3B0LW9yZy11ayc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgRW1haWxJbmZvIHtcbiAgY2hhbm5lbDogQ2hhbm5lbDtcbiAgZW1haWw6IHN0cmluZztcbiAgdG9rZW4/OiBzdHJpbmc7XG4gIGV4cGlyZXNBdD86IHN0cmluZyB8IG51bWJlcjtcbiAgY3JlYXRlZEF0Pzogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEVtYWlsIHtcbiAgaWQ/OiBzdHJpbmcgfCBudW1iZXI7XG4gIGVpZD86IHN0cmluZztcbiAgX2lkPzogc3RyaW5nO1xuICBmcm9tPzogc3RyaW5nO1xuICBmcm9tX2FkZHJlc3M/OiBzdHJpbmc7XG4gIGZyb21fbmFtZT86IHN0cmluZztcbiAgYWRkcmVzc19mcm9tPzogc3RyaW5nO1xuICBuYW1lX2Zyb20/OiBzdHJpbmc7XG4gIHRvPzogc3RyaW5nO1xuICBuYW1lX3RvPzogc3RyaW5nO1xuICBlbWFpbF9hZGRyZXNzPzogc3RyaW5nO1xuICBzdWJqZWN0Pzogc3RyaW5nO1xuICBlX3N1YmplY3Q/OiBzdHJpbmc7XG4gIGJvZHk/OiBzdHJpbmc7XG4gIHRleHQ/OiBzdHJpbmc7XG4gIGNvbnRlbnQ/OiBzdHJpbmc7XG4gIGh0bWw/OiBzdHJpbmc7XG4gIGh0bWxfY29udGVudD86IHN0cmluZztcbiAgZGF0ZT86IHN0cmluZyB8IG51bWJlcjtcbiAgZV9kYXRlPzogbnVtYmVyO1xuICB0aW1lc3RhbXA/OiBudW1iZXI7XG4gIHJlY2VpdmVkX2F0Pzogc3RyaW5nO1xuICBjcmVhdGVkX2F0Pzogc3RyaW5nO1xuICBjcmVhdGVkQXQ/OiBzdHJpbmc7XG4gIGlzX3JlYWQ/OiBudW1iZXI7XG4gIGhhc19odG1sPzogYm9vbGVhbjtcbiAgW2tleTogc3RyaW5nXTogYW55O1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEdldEVtYWlsc1Jlc3VsdCB7XG4gIGNoYW5uZWw6IENoYW5uZWw7XG4gIGVtYWlsOiBzdHJpbmc7XG4gIGVtYWlsczogRW1haWxbXTtcbiAgc3VjY2VzczogYm9vbGVhbjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBHZW5lcmF0ZUVtYWlsT3B0aW9ucyB7XG4gIGNoYW5uZWw/OiBDaGFubmVsO1xuICBkdXJhdGlvbj86IG51bWJlcjtcbiAgZG9tYWluPzogc3RyaW5nIHwgbnVsbDtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBHZXRFbWFpbHNPcHRpb25zIHtcbiAgY2hhbm5lbDogQ2hhbm5lbDtcbiAgZW1haWw6IHN0cmluZztcbiAgdG9rZW4/OiBzdHJpbmc7XG59XG4iXX0=
3
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvdHlwZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICog5pSv5oyB55qE5Li05pe26YKu566x5rig6YGT5qCH6K+GXG4gKiDmr4/kuKrmuKDpgZPlr7nlupTkuIDkuKrnrKzkuInmlrnkuLTml7bpgq7nrrHmnI3liqHllYZcbiAqL1xuZXhwb3J0IHR5cGUgQ2hhbm5lbCA9ICd0ZW1wbWFpbCcgfCAnbGluc2hpLWVtYWlsJyB8ICd0ZW1wbWFpbC1sb2wnIHwgJ2NoYXRncHQtb3JnLXVrJyB8ICd0ZW1wbWFpbC1sYScgfCAndGVtcC1tYWlsLWlvJyB8ICdhd2FtYWlsJyB8ICdtYWlsLXRtJyB8ICdkcm9wbWFpbCc7XG5cbi8qKlxuICog5Yib5bu65Li05pe26YKu566x5ZCO6L+U5Zue55qE6YKu566x5L+h5oGvXG4gKiDljIXlkKvpgq7nrrHlnLDlnYDjgIHorqTor4Hku6TniYzlkoznlJ/lkb3lkajmnJ/kv6Hmga9cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBFbWFpbEluZm8ge1xuICAvKiog5Yib5bu66K+l6YKu566x5omA5L2/55So55qE5rig6YGTICovXG4gIGNoYW5uZWw6IENoYW5uZWw7XG4gIC8qKiDkuLTml7bpgq7nrrHlnLDlnYAgKi9cbiAgZW1haWw6IHN0cmluZztcbiAgLyoqIOiupOivgeS7pOeJjO+8jOmDqOWIhua4oOmBk+WcqOiOt+WPlumCruS7tuaXtumcgOimgeatpOS7pOeJjCAqL1xuICB0b2tlbj86IHN0cmluZztcbiAgLyoqIOmCrueusei/h+acn+aXtumXtO+8iElTTyA4NjAxIOWtl+espuS4suaIliBVbml4IOaXtumXtOaIs++8iSAqL1xuICBleHBpcmVzQXQ/OiBzdHJpbmcgfCBudW1iZXI7XG4gIC8qKiDpgq7nrrHliJvlu7rml7bpl7TvvIhJU08gODYwMSDlrZfnrKbkuLLvvIkgKi9cbiAgY3JlYXRlZEF0Pzogc3RyaW5nO1xufVxuXG4vKipcbiAqIOagh+WHhuWMlumCruS7tumZhOS7tlxuICog5LiN5ZCM5rig6YGT55qE6ZmE5Lu25a2X5q615ZCN5LiN5ZCM77yMU0RLIOe7n+S4gOW9kuS4gOWMluS4uuatpOe7k+aehFxuICovXG5leHBvcnQgaW50ZXJmYWNlIEVtYWlsQXR0YWNobWVudCB7XG4gIC8qKiDpmYTku7bmlofku7blkI0gKi9cbiAgZmlsZW5hbWU6IHN0cmluZztcbiAgLyoqIOmZhOS7tuWkp+Wwj++8iOWtl+iKgu+8iSAqL1xuICBzaXplPzogbnVtYmVyO1xuICAvKiogTUlNRSDnsbvlnovvvIzlpoIgYXBwbGljYXRpb24vcGRmICovXG4gIGNvbnRlbnRUeXBlPzogc3RyaW5nO1xuICAvKiog6ZmE5Lu25LiL6L295Zyw5Z2AICovXG4gIHVybD86IHN0cmluZztcbn1cblxuLyoqXG4gKiDmoIflh4bljJbpgq7ku7bmoLzlvI8gLSDmiYDmnInmj5DkvpvllYbov5Tlm57nu5/kuIDnu5PmnoRcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBFbWFpbCB7XG4gIC8qKiDpgq7ku7bllK/kuIDmoIfor4YgKi9cbiAgaWQ6IHN0cmluZztcbiAgLyoqIOWPkeS7tuS6uumCrueuseWcsOWdgCAqL1xuICBmcm9tOiBzdHJpbmc7XG4gIC8qKiDmlLbku7bkurrpgq7nrrHlnLDlnYAgKi9cbiAgdG86IHN0cmluZztcbiAgLyoqIOmCruS7tuS4u+mimCAqL1xuICBzdWJqZWN0OiBzdHJpbmc7XG4gIC8qKiDnuq/mlofmnKzlhoXlrrkgKi9cbiAgdGV4dDogc3RyaW5nO1xuICAvKiogSFRNTCDlhoXlrrkgKi9cbiAgaHRtbDogc3RyaW5nO1xuICAvKiogSVNPIDg2MDEg5qC85byP55qE5pel5pyf5a2X56ym5LiyICovXG4gIGRhdGU6IHN0cmluZztcbiAgLyoqIOaYr+WQpuW3suivuyAqL1xuICBpc1JlYWQ6IGJvb2xlYW47XG4gIC8qKiDpmYTku7bliJfooaggKi9cbiAgYXR0YWNobWVudHM6IEVtYWlsQXR0YWNobWVudFtdO1xufVxuXG4vKipcbiAqIOiOt+WPlumCruS7tuWIl+ihqOeahOi/lOWbnue7k+aenFxuICogc3VjY2VzcyDkuLogZmFsc2Ug5pe26KGo56S66K+35rGC5aSx6LSl77yI6YeN6K+V6ICX5bC977yJ77yMZW1haWxzIOS4uuepuuaVsOe7hFxuICovXG5leHBvcnQgaW50ZXJmYWNlIEdldEVtYWlsc1Jlc3VsdCB7XG4gIC8qKiDmiYDkvb/nlKjnmoTmuKDpgZMgKi9cbiAgY2hhbm5lbDogQ2hhbm5lbDtcbiAgLyoqIOafpeivoueahOmCrueuseWcsOWdgCAqL1xuICBlbWFpbDogc3RyaW5nO1xuICAvKiog6YKu5Lu25YiX6KGo77yM5aSx6LSl5pe25Li656m65pWw57uEICovXG4gIGVtYWlsczogRW1haWxbXTtcbiAgLyoqIOivt+axguaYr+WQpuaIkOWKn++8jGZhbHNlIOihqOekuumHjeivleiAl+WwveWQjuS7jeWksei0pSAqL1xuICBzdWNjZXNzOiBib29sZWFuO1xufVxuXG4vKipcbiAqIOmHjeivlemFjee9rlxuICogU0RLIOWGhemDqOWvuee9kee7nOmUmeivr+OAgei2heaXtuOAgTV4eCDmnI3liqHnq6/plJnor6/oh6rliqjph43or5VcbiAqIDR4eCDlrqLmiLfnq6/plJnor6/vvIjlpoLlj4LmlbDplJnor6/vvInkuI3kvJrph43or5VcbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHNcbiAqIC8vIOiHquWumuS5iemHjeivleetlueVpe+8muacgOWkmumHjeivlSAzIOasoe+8jOmmluasoeW7tui/nyAyIOenklxuICogY29uc3QgZW1haWwgPSBhd2FpdCBnZW5lcmF0ZUVtYWlsKHtcbiAqICAgY2hhbm5lbDogJ21haWwtdG0nLFxuICogICByZXRyeTogeyBtYXhSZXRyaWVzOiAzLCBpbml0aWFsRGVsYXk6IDIwMDAgfSxcbiAqIH0pO1xuICogYGBgXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUmV0cnlDb25maWcge1xuICAvKiog5pyA5aSn6YeN6K+V5qyh5pWw77yI5LiN5ZCr6aaW5qyh6K+35rGC77yJ77yM6buY6K6kIDIgKi9cbiAgbWF4UmV0cmllcz86IG51bWJlcjtcbiAgLyoqIOWIneWni+mHjeivleW7tui/n++8iOavq+enku+8ie+8jOmHh+eUqOaMh+aVsOmAgOmBv+etlueVpe+8jOm7mOiupCAxMDAwICovXG4gIGluaXRpYWxEZWxheT86IG51bWJlcjtcbiAgLyoqIOacgOWkp+mHjeivleW7tui/n+S4iumZkO+8iOavq+enku+8ie+8jOm7mOiupCA1MDAwICovXG4gIG1heERlbGF5PzogbnVtYmVyO1xuICAvKiog5Y2V5qyh6K+35rGC6LaF5pe25pe26Ze077yI5q+r56eS77yJ77yM6buY6K6kIDE1MDAwICovXG4gIHRpbWVvdXQ/OiBudW1iZXI7XG59XG5cbi8qKlxuICog5Yib5bu65Li05pe26YKu566x55qE6YCJ6aG5XG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHRzXG4gKiAvLyDkvb/nlKjmjIflrprmuKDpgZPliJvlu7rpgq7nrrFcbiAqIGNvbnN0IGVtYWlsID0gYXdhaXQgZ2VuZXJhdGVFbWFpbCh7IGNoYW5uZWw6ICdtYWlsLXRtJyB9KTtcbiAqXG4gKiAvLyDpmo/mnLrpgInmi6nmuKDpgZNcbiAqIGNvbnN0IGVtYWlsID0gYXdhaXQgZ2VuZXJhdGVFbWFpbCgpO1xuICogYGBgXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgR2VuZXJhdGVFbWFpbE9wdGlvbnMge1xuICAvKiog5oyH5a6a5rig6YGT77yM5LiN5Lyg5YiZ6ZqP5py66YCJ5oupICovXG4gIGNoYW5uZWw/OiBDaGFubmVsO1xuICAvKiog6YKu566x5pyJ5pWI5pe26ZW/ICovXG4gIGR1cmF0aW9uPzogbnVtYmVyO1xuICAvKiog5oyH5a6a6YKu566x5Z+f5ZCNICovXG4gIGRvbWFpbj86IHN0cmluZyB8IG51bGw7XG4gIC8qKiDph43or5XphY3nva7vvIzkuI3kvKDliJnkvb/nlKjpu5jorqTlgLzvvIjmnIDlpJrph43or5UgMiDmrKHvvIkgKi9cbiAgcmV0cnk/OiBSZXRyeUNvbmZpZztcbn1cblxuLyoqXG4gKiDojrflj5bpgq7ku7bliJfooajnmoTpgInpoblcbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHNcbiAqIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGdldEVtYWlscyh7XG4gKiAgIGNoYW5uZWw6IGVtYWlsSW5mby5jaGFubmVsLFxuICogICBlbWFpbDogZW1haWxJbmZvLmVtYWlsLFxuICogICB0b2tlbjogZW1haWxJbmZvLnRva2VuLFxuICogfSk7XG4gKiBpZiAocmVzdWx0LnN1Y2Nlc3MgJiYgcmVzdWx0LmVtYWlscy5sZW5ndGggPiAwKSB7XG4gKiAgIGNvbnNvbGUubG9nKCfmlLbliLDpgq7ku7Y6JywgcmVzdWx0LmVtYWlscyk7XG4gKiB9XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBHZXRFbWFpbHNPcHRpb25zIHtcbiAgLyoqIOa4oOmBk+agh+ivhu+8jOW/heWhqyAqL1xuICBjaGFubmVsOiBDaGFubmVsO1xuICAvKiog6YKu566x5Zyw5Z2A77yM5b+F5aGrICovXG4gIGVtYWlsOiBzdHJpbmc7XG4gIC8qKiDorqTor4Hku6TniYwgKi9cbiAgdG9rZW4/OiBzdHJpbmc7XG4gIC8qKiDph43or5XphY3nva7vvIzkuI3kvKDliJnkvb/nlKjpu5jorqTlgLzvvIjmnIDlpJrph43or5UgMiDmrKHvvIkgKi9cbiAgcmV0cnk/OiBSZXRyeUNvbmZpZztcbn1cbiJdfQ==
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tempmail-sdk",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "临时邮箱 SDK - 支持多个临时邮箱服务商",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/src/index.ts CHANGED
@@ -2,49 +2,117 @@ import * as tempmail from './providers/tempmail';
2
2
  import * as linshiEmail from './providers/linshi-email';
3
3
  import * as tempmailLol from './providers/tempmail-lol';
4
4
  import * as chatgptOrgUk from './providers/chatgpt-org-uk';
5
- import { Channel, EmailInfo, Email, GetEmailsResult, GenerateEmailOptions, GetEmailsOptions } from './types';
5
+ import * as tempmailLa from './providers/tempmail-la';
6
+ import * as tempMailIO from './providers/temp-mail-io';
7
+ import * as awamail from './providers/awamail';
8
+ import * as mailTm from './providers/mail-tm';
9
+ import * as dropmail from './providers/dropmail';
10
+ import { Channel, EmailInfo, Email, EmailAttachment, GetEmailsResult, GenerateEmailOptions, GetEmailsOptions } from './types';
11
+ import { withRetry, RetryOptions } from './retry';
12
+ import { logger } from './logger';
6
13
 
7
- export { Channel, EmailInfo, Email, GetEmailsResult, GenerateEmailOptions, GetEmailsOptions } from './types';
14
+ export { Channel, EmailInfo, Email, EmailAttachment, GetEmailsResult, GenerateEmailOptions, GetEmailsOptions } from './types';
15
+ export { normalizeEmail } from './normalize';
16
+ export { withRetry, fetchWithTimeout, RetryOptions } from './retry';
17
+ export { LogLevel, LogHandler, setLogLevel, getLogLevel, setLogger, logger } from './logger';
8
18
 
19
+ /** 渠道名称到 provider 实现的映射表 */
9
20
  const providers = {
10
21
  'tempmail': tempmail,
11
22
  'linshi-email': linshiEmail,
12
23
  'tempmail-lol': tempmailLol,
13
24
  'chatgpt-org-uk': chatgptOrgUk,
25
+ 'tempmail-la': tempmailLa,
26
+ 'temp-mail-io': tempMailIO,
27
+ 'awamail': awamail,
28
+ 'mail-tm': mailTm,
29
+ 'dropmail': dropmail,
14
30
  };
15
31
 
16
- const allChannels: Channel[] = ['tempmail', 'linshi-email', 'tempmail-lol', 'chatgpt-org-uk'];
32
+ /** 所有支持的渠道列表,用于随机选择和遍历 */
33
+ const allChannels: Channel[] = ['tempmail', 'linshi-email', 'tempmail-lol', 'chatgpt-org-uk', 'tempmail-la', 'temp-mail-io', 'awamail', 'mail-tm', 'dropmail'];
17
34
 
35
+ /**
36
+ * 渠道信息,包含渠道标识、显示名称和对应网站
37
+ */
18
38
  export interface ChannelInfo {
39
+ /** 渠道标识 */
19
40
  channel: Channel;
41
+ /** 渠道显示名称 */
20
42
  name: string;
43
+ /** 对应的临时邮箱服务网站 */
21
44
  website: string;
22
45
  }
23
46
 
47
+ /** 渠道信息映射表 */
24
48
  const channelInfoMap: Record<Channel, ChannelInfo> = {
25
49
  'tempmail': { channel: 'tempmail', name: 'TempMail', website: 'tempmail.ing' },
26
50
  'linshi-email': { channel: 'linshi-email', name: '临时邮箱', website: 'linshi-email.com' },
27
51
  'tempmail-lol': { channel: 'tempmail-lol', name: 'TempMail LOL', website: 'tempmail.lol' },
28
52
  'chatgpt-org-uk': { channel: 'chatgpt-org-uk', name: 'ChatGPT Mail', website: 'mail.chatgpt.org.uk' },
53
+ 'tempmail-la': { channel: 'tempmail-la', name: 'TempMail LA', website: 'tempmail.la' },
54
+ 'temp-mail-io': { channel: 'temp-mail-io', name: 'Temp Mail IO', website: 'temp-mail.io' },
55
+ 'awamail': { channel: 'awamail', name: 'AwaMail', website: 'awamail.com' },
56
+ 'mail-tm': { channel: 'mail-tm', name: 'Mail.tm', website: 'mail.tm' },
57
+ 'dropmail': { channel: 'dropmail', name: 'DropMail', website: 'dropmail.me' },
29
58
  };
30
59
 
31
60
  /**
32
61
  * 获取所有支持的渠道列表
62
+ *
63
+ * @returns 所有渠道的信息数组
64
+ *
65
+ * @example
66
+ * ```ts
67
+ * const channels = listChannels();
68
+ * channels.forEach(ch => console.log(`${ch.name} (${ch.website})`));
69
+ * ```
33
70
  */
34
71
  export function listChannels(): ChannelInfo[] {
35
72
  return allChannels.map(ch => channelInfoMap[ch]);
36
73
  }
37
74
 
38
75
  /**
39
- * 获取指定渠道信息
76
+ * 获取指定渠道的详细信息
77
+ *
78
+ * @param channel - 渠道标识
79
+ * @returns 渠道信息,不存在时返回 undefined
40
80
  */
41
81
  export function getChannelInfo(channel: Channel): ChannelInfo | undefined {
42
82
  return channelInfoMap[channel];
43
83
  }
44
84
 
85
+ /**
86
+ * 创建临时邮箱
87
+ *
88
+ * 错误处理策略:
89
+ * - 网络错误、超时、服务端 5xx 错误 → 自动重试(默认 2 次,指数退避)
90
+ * - 4xx 客户端错误、参数错误 → 直接抛出异常
91
+ *
92
+ * @param options - 创建选项,可指定渠道、有效时长、域名等
93
+ * @returns 邮箱信息,包含地址、令牌等
94
+ * @throws 重试耗尽后仍失败时抛出异常
95
+ *
96
+ * @example
97
+ * ```ts
98
+ * const emailInfo = await generateEmail({ channel: 'temp-mail-io' });
99
+ * console.log(emailInfo.email); // 临时邮箱地址
100
+ * ```
101
+ */
45
102
  export async function generateEmail(options: GenerateEmailOptions = {}): Promise<EmailInfo> {
46
103
  const channel = options.channel || allChannels[Math.floor(Math.random() * allChannels.length)];
47
-
104
+
105
+ logger.info(`创建临时邮箱, 渠道: ${channel}`);
106
+ const result = await withRetry(() => generateEmailOnce(channel, options), options.retry);
107
+ logger.info(`邮箱创建成功: ${result.email}`);
108
+ return result;
109
+ }
110
+
111
+ /**
112
+ * 单次创建邮箱(不含重试逻辑)
113
+ * 根据渠道类型分发到对应的 provider 实现
114
+ */
115
+ async function generateEmailOnce(channel: Channel, options: GenerateEmailOptions): Promise<EmailInfo> {
48
116
  switch (channel) {
49
117
  case 'tempmail':
50
118
  return tempmail.generateEmail(options.duration || 30);
@@ -54,14 +122,50 @@ export async function generateEmail(options: GenerateEmailOptions = {}): Promise
54
122
  return tempmailLol.generateEmail(options.domain || null);
55
123
  case 'chatgpt-org-uk':
56
124
  return chatgptOrgUk.generateEmail();
125
+ case 'tempmail-la':
126
+ return tempmailLa.generateEmail();
127
+ case 'temp-mail-io':
128
+ return tempMailIO.generateEmail();
129
+ case 'awamail':
130
+ return awamail.generateEmail();
131
+ case 'mail-tm':
132
+ return mailTm.generateEmail();
133
+ case 'dropmail':
134
+ return dropmail.generateEmail();
57
135
  default:
58
136
  throw new Error(`Unknown channel: ${channel}`);
59
137
  }
60
138
  }
61
139
 
140
+ /**
141
+ * 获取邮件列表
142
+ *
143
+ * 错误处理策略:
144
+ * - 网络错误、超时、服务端 5xx 错误 → 自动重试(默认 2 次)
145
+ * - 重试耗尽后返回 { success: false, emails: [] },不抛异常
146
+ * - 参数校验错误(缺少 channel / token)直接抛出
147
+ *
148
+ * 这种设计让调用方在轮询场景下不会因网络波动而中断整个流程,
149
+ * 只需检查 success 字段即可判断本次请求是否成功。
150
+ *
151
+ * @param options - 获取选项,包含渠道、邮箱地址、令牌
152
+ * @returns 邮件结果,包含 success 标记和邮件列表
153
+ *
154
+ * @example
155
+ * ```ts
156
+ * const result = await getEmails({
157
+ * channel: emailInfo.channel,
158
+ * email: emailInfo.email,
159
+ * token: emailInfo.token,
160
+ * });
161
+ * if (result.success && result.emails.length > 0) {
162
+ * console.log('收到邮件:', result.emails[0].subject);
163
+ * }
164
+ * ```
165
+ */
62
166
  export async function getEmails(options: GetEmailsOptions): Promise<GetEmailsResult> {
63
167
  const { channel, email, token } = options;
64
-
168
+
65
169
  if (!channel) {
66
170
  throw new Error('Channel is required');
67
171
  }
@@ -69,44 +173,93 @@ export async function getEmails(options: GetEmailsOptions): Promise<GetEmailsRes
69
173
  throw new Error('Email is required');
70
174
  }
71
175
 
72
- let emails: Email[] = [];
176
+ logger.debug(`获取邮件, 渠道: ${channel}, 邮箱: ${email}`);
177
+ try {
178
+ const emails = await withRetry(() => getEmailsOnce(channel, email, token), options.retry);
179
+ if (emails.length > 0) {
180
+ logger.info(`获取到 ${emails.length} 封邮件, 渠道: ${channel}`);
181
+ } else {
182
+ logger.debug(`暂无邮件, 渠道: ${channel}`);
183
+ }
184
+ return { channel, email, emails, success: true };
185
+ } catch (err: any) {
186
+ /*
187
+ * 重试耗尽后仍然失败 → 返回空结果而非抛异常
188
+ * 这样调用方在轮询场景下不会因为一次网络波动而中断整个流程
189
+ */
190
+ logger.error(`获取邮件失败, 渠道: ${channel}, 错误: ${err.message || err}`);
191
+ return { channel, email, emails: [], success: false };
192
+ }
193
+ }
73
194
 
195
+ /**
196
+ * 单次获取邮件(不含重试逻辑)
197
+ * 根据渠道类型分发到对应的 provider 实现,并校验必需的 token 参数
198
+ */
199
+ async function getEmailsOnce(channel: Channel, email: string, token?: string): Promise<Email[]> {
74
200
  switch (channel) {
75
201
  case 'tempmail':
76
- emails = await tempmail.getEmails(email);
77
- break;
202
+ return tempmail.getEmails(email);
78
203
  case 'linshi-email':
79
- emails = await linshiEmail.getEmails(email);
80
- break;
204
+ return linshiEmail.getEmails(email);
81
205
  case 'tempmail-lol':
82
- if (!token) {
83
- throw new Error('Token is required for tempmail-lol channel');
84
- }
85
- emails = await tempmailLol.getEmails(token);
86
- break;
206
+ if (!token) throw new Error('Token is required for tempmail-lol channel');
207
+ return tempmailLol.getEmails(token, email);
87
208
  case 'chatgpt-org-uk':
88
- emails = await chatgptOrgUk.getEmails(email);
89
- break;
209
+ return chatgptOrgUk.getEmails(email);
210
+ case 'tempmail-la':
211
+ return tempmailLa.getEmails(email);
212
+ case 'temp-mail-io':
213
+ return tempMailIO.getEmails(email);
214
+ case 'awamail':
215
+ if (!token) throw new Error('Token is required for awamail channel');
216
+ return awamail.getEmails(token, email);
217
+ case 'mail-tm':
218
+ if (!token) throw new Error('Token is required for mail-tm channel');
219
+ return mailTm.getEmails(token, email);
220
+ case 'dropmail':
221
+ if (!token) throw new Error('Token is required for dropmail channel');
222
+ return dropmail.getEmails(token, email);
90
223
  default:
91
224
  throw new Error(`Unknown channel: ${channel}`);
92
225
  }
93
-
94
- return {
95
- channel,
96
- email,
97
- emails,
98
- success: true,
99
- };
100
226
  }
101
227
 
228
+ /**
229
+ * 临时邮箱客户端
230
+ * 封装了邮箱创建和邮件获取的完整流程,自动管理邮箱信息和认证令牌
231
+ *
232
+ * @example
233
+ * ```ts
234
+ * const client = new TempEmailClient();
235
+ * const emailInfo = await client.generate({ channel: 'mail-tm' });
236
+ * console.log('邮箱:', emailInfo.email);
237
+ *
238
+ * // 轮询获取邮件
239
+ * const result = await client.getEmails();
240
+ * if (result.success) {
241
+ * console.log('邮件数:', result.emails.length);
242
+ * }
243
+ * ```
244
+ */
102
245
  export class TempEmailClient {
103
246
  private emailInfo: EmailInfo | null = null;
104
247
 
248
+ /**
249
+ * 创建临时邮箱并缓存邮箱信息
250
+ * 后续调用 getEmails() 时自动使用此邮箱的渠道、地址和令牌
251
+ */
105
252
  async generate(options: GenerateEmailOptions = {}): Promise<EmailInfo> {
106
253
  this.emailInfo = await generateEmail(options);
107
254
  return this.emailInfo;
108
255
  }
109
256
 
257
+ /**
258
+ * 获取当前邮箱的邮件列表
259
+ * 必须先调用 generate() 创建邮箱
260
+ *
261
+ * @throws 未调用 generate() 时抛出异常
262
+ */
110
263
  async getEmails(): Promise<GetEmailsResult> {
111
264
  if (!this.emailInfo) {
112
265
  throw new Error('No email generated. Call generate() first.');
@@ -119,6 +272,10 @@ export class TempEmailClient {
119
272
  });
120
273
  }
121
274
 
275
+ /**
276
+ * 获取当前缓存的邮箱信息
277
+ * 未调用 generate() 时返回 null
278
+ */
122
279
  getEmailInfo(): EmailInfo | null {
123
280
  return this.emailInfo;
124
281
  }