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.
- package/README.md +162 -72
- package/demo/poll-emails.ts +25 -40
- package/dist/index.d.ts +96 -2
- package/dist/index.js +186 -21
- package/dist/logger.d.ts +73 -0
- package/dist/logger.js +100 -0
- package/dist/normalize.d.ts +12 -0
- package/dist/normalize.js +132 -0
- package/dist/providers/awamail.d.ts +15 -0
- package/dist/providers/awamail.js +91 -0
- package/dist/providers/chatgpt-org-uk.js +4 -2
- package/dist/providers/dropmail.d.ts +13 -0
- package/dist/providers/dropmail.js +86 -0
- package/dist/providers/linshi-email.js +4 -2
- package/dist/providers/mail-tm.d.ts +11 -0
- package/dist/providers/mail-tm.js +172 -0
- package/dist/providers/temp-mail-io.d.ts +13 -0
- package/dist/providers/temp-mail-io.js +99 -0
- package/dist/providers/tempmail-la.d.ts +15 -0
- package/dist/providers/tempmail-la.js +89 -0
- package/dist/providers/tempmail-lol.d.ts +1 -1
- package/dist/providers/tempmail-lol.js +5 -3
- package/dist/providers/tempmail.js +4 -2
- package/dist/retry.d.ts +38 -0
- package/dist/retry.js +121 -0
- package/dist/types.d.ts +118 -28
- package/dist/types.js +1 -1
- package/package.json +1 -1
- package/src/index.ts +182 -25
- package/src/logger.ts +106 -0
- package/src/normalize.ts +125 -0
- package/src/providers/awamail.ts +101 -0
- package/src/providers/chatgpt-org-uk.ts +3 -1
- package/src/providers/dropmail.ts +98 -0
- package/src/providers/linshi-email.ts +3 -1
- package/src/providers/mail-tm.ts +193 -0
- package/src/providers/temp-mail-io.ts +108 -0
- package/src/providers/tempmail-la.ts +99 -0
- package/src/providers/tempmail-lol.ts +4 -2
- package/src/providers/tempmail.ts +3 -1
- package/src/retry.ts +146 -0
- package/src/types.ts +120 -28
- 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
|
-
|
|
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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
from
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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,
|
|
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
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
77
|
-
break;
|
|
202
|
+
return tempmail.getEmails(email);
|
|
78
203
|
case 'linshi-email':
|
|
79
|
-
|
|
80
|
-
break;
|
|
204
|
+
return linshiEmail.getEmails(email);
|
|
81
205
|
case 'tempmail-lol':
|
|
82
|
-
if (!token)
|
|
83
|
-
|
|
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
|
-
|
|
89
|
-
|
|
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
|
}
|