tempmail-sdk 1.1.3 → 1.1.4
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 +43 -38
- package/demo/poll-emails.ts +290 -28
- package/dist/config.d.ts +16 -0
- package/dist/config.js +4 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +30 -15
- package/dist/providers/chatgpt-org-uk.js +120 -54
- package/dist/providers/dropmail.js +134 -3
- package/dist/providers/linshi-email.d.ts +1 -1
- package/dist/providers/linshi-email.js +18 -7
- package/dist/providers/linshi-token.d.ts +25 -0
- package/dist/providers/linshi-token.js +69 -0
- package/dist/providers/mail-tm.js +39 -22
- package/dist/providers/smail-pw.d.ts +9 -0
- package/dist/providers/smail-pw.js +356 -0
- package/dist/types.d.ts +6 -1
- package/dist/types.js +1 -1
- package/package.json +1 -1
- package/src/config.ts +16 -0
- package/src/index.ts +29 -13
- package/src/providers/chatgpt-org-uk.ts +131 -53
- package/src/providers/dropmail.ts +161 -2
- package/src/providers/linshi-email.ts +23 -7
- package/src/providers/linshi-token.ts +86 -0
- package/src/providers/mail-tm.ts +39 -21
- package/src/providers/smail-pw.ts +382 -0
- package/src/types.ts +6 -1
- package/test/example.ts +174 -3
- package/dist/providers/tempmail-la.d.ts +0 -15
- package/dist/providers/tempmail-la.js +0 -90
- package/src/providers/tempmail-la.ts +0 -100
package/README.md
CHANGED
|
@@ -22,11 +22,11 @@ npm install @XxxXTeam/tempmail-sdk --registry=https://npm.pkg.github.com
|
|
|
22
22
|
| `tempmail` | tempmail.ing | - | 支持自定义有效期 |
|
|
23
23
|
| `linshi-email` | linshi-email.com | - | |
|
|
24
24
|
| `tempmail-lol` | tempmail.lol | ✅ | 支持指定域名 |
|
|
25
|
-
| `chatgpt-org-uk` | mail.chatgpt.org.uk |
|
|
26
|
-
| `tempmail-la` | tempmail.la | - | 支持分页 |
|
|
25
|
+
| `chatgpt-org-uk` | mail.chatgpt.org.uk | ✅ | 首页注入 `__BROWSER_AUTH`,创建邮箱时须带 `X-Inbox-Token` + `gm_sid`(已自动处理) |
|
|
27
26
|
| `temp-mail-io` | temp-mail.io | - | |
|
|
28
27
|
| `awamail` | awamail.com | ✅ | Session Cookie 自动管理 |
|
|
29
|
-
| `mail-tm` | mail.tm | ✅ |
|
|
28
|
+
| `mail-tm` | mail.tm / api.mail.tm | ✅ | 自动注册账号;请求与 **Internxt** 等站点前端一致(`GET /domains?page=1`、`GET /messages?page=1` 及常见浏览器头) |
|
|
29
|
+
| `smail-pw` | smail.pw | ✅ | `POST/GET https://smail.pw/_root.data`,`__session` Cookie;解析 RSC/Flight 中的 **D1 邮件行对象**(`subject`/`time` 等) |
|
|
30
30
|
| `dropmail` | dropmail.me | ✅ | GraphQL API |
|
|
31
31
|
| `guerrillamail` | guerrillamail.com | ✅ | 公开 JSON API |
|
|
32
32
|
| `maildrop` | maildrop.cc | ✅ | GraphQL API,自带反垃圾 |
|
|
@@ -76,13 +76,13 @@ console.log(channels);
|
|
|
76
76
|
// { channel: 'linshi-email', name: '临时邮箱', website: 'linshi-email.com' },
|
|
77
77
|
// { channel: 'tempmail-lol', name: 'TempMail LOL', website: 'tempmail.lol' },
|
|
78
78
|
// { channel: 'chatgpt-org-uk', name: 'ChatGPT Mail', website: 'mail.chatgpt.org.uk' },
|
|
79
|
-
// { channel: 'tempmail-la', name: 'TempMail LA', website: 'tempmail.la' },
|
|
80
79
|
// { channel: 'temp-mail-io', name: 'Temp Mail IO', website: 'temp-mail.io' },
|
|
81
80
|
// { channel: 'awamail', name: 'AwaMail', website: 'awamail.com' },
|
|
82
81
|
// { channel: 'mail-tm', name: 'Mail.tm', website: 'mail.tm' },
|
|
83
82
|
// { channel: 'dropmail', name: 'DropMail', website: 'dropmail.me' },
|
|
84
83
|
// { channel: 'guerrillamail', name: 'Guerrilla Mail', website: 'guerrillamail.com' },
|
|
85
|
-
// { channel: 'maildrop', name: 'Maildrop', website: 'maildrop.cc' }
|
|
84
|
+
// { channel: 'maildrop', name: 'Maildrop', website: 'maildrop.cc' },
|
|
85
|
+
// { channel: 'smail-pw', name: 'Smail.pw', website: 'smail.pw' }
|
|
86
86
|
// ]
|
|
87
87
|
|
|
88
88
|
const info = getChannelInfo('tempmail');
|
|
@@ -107,38 +107,29 @@ const emailInfo3 = await generateEmail({ channel: 'tempmail', duration: 60 });
|
|
|
107
107
|
|
|
108
108
|
// tempmail-lol 渠道支持指定域名
|
|
109
109
|
const emailInfo4 = await generateEmail({ channel: 'tempmail-lol', domain: 'example.com' });
|
|
110
|
+
|
|
111
|
+
// 只尝试指定渠道(探测可用性、写自动化时用)
|
|
112
|
+
const probe = await generateEmail({ channel: 'smail-pw', channelFallback: false });
|
|
110
113
|
```
|
|
111
114
|
|
|
112
115
|
#### 获取邮件
|
|
113
116
|
|
|
114
|
-
|
|
115
|
-
import { getEmails } from 'tempmail-sdk';
|
|
116
|
-
|
|
117
|
-
// 不需要 Token 的渠道
|
|
118
|
-
const result = await getEmails({
|
|
119
|
-
channel: 'tempmail',
|
|
120
|
-
email: 'xxx@ibymail.com',
|
|
121
|
-
});
|
|
122
|
-
console.log(result.emails); // 标准化邮件数组
|
|
117
|
+
`getEmails` 的第一个参数必须是 **`generateEmail` 返回的 `EmailInfo`**(或与 `TempEmailClient` 缓存的相同结构)。Token / Session 由 SDK 内部绑定到该对象,**不要**再手动传入 `token` 字段。
|
|
123
118
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
console.log(email.html); // HTML
|
|
139
|
-
console.log(email.date); // ISO 日期
|
|
140
|
-
console.log(email.isRead); // 是否已读
|
|
141
|
-
console.log(email.attachments); // 附件列表
|
|
119
|
+
```typescript
|
|
120
|
+
import { generateEmail, getEmails } from 'tempmail-sdk';
|
|
121
|
+
|
|
122
|
+
const emailInfo = await generateEmail({ channel: 'tempmail' });
|
|
123
|
+
if (!emailInfo) throw new Error('创建失败');
|
|
124
|
+
const result = await getEmails(emailInfo);
|
|
125
|
+
console.log(result.success, result.emails.length);
|
|
126
|
+
|
|
127
|
+
const mailTm = await generateEmail({ channel: 'mail-tm' });
|
|
128
|
+
if (mailTm) {
|
|
129
|
+
const r2 = await getEmails(mailTm, { retry: { maxRetries: 3, timeout: 20000 } });
|
|
130
|
+
for (const email of r2.emails) {
|
|
131
|
+
console.log(email.id, email.from, email.subject, email.date);
|
|
132
|
+
}
|
|
142
133
|
}
|
|
143
134
|
```
|
|
144
135
|
|
|
@@ -171,8 +162,10 @@ for (const email of result2.emails) {
|
|
|
171
162
|
| 字段 | 类型 | 说明 |
|
|
172
163
|
|------|------|------|
|
|
173
164
|
| `channel` | `Channel` | 指定渠道(可选,不指定则随机) |
|
|
165
|
+
| `channelFallback` | `boolean` | 默认 `true`:指定渠道失败会继续尝试其他渠道;设为 `false` 时仅尝试 `channel` |
|
|
174
166
|
| `duration` | `number` | 有效期分钟数(仅 `tempmail` 渠道) |
|
|
175
167
|
| `domain` | `string` | 指定域名(仅 `tempmail-lol` 渠道) |
|
|
168
|
+
| `retry` | `RetryConfig` | 创建邮箱时的重试(超时、5xx、网络错误等) |
|
|
176
169
|
|
|
177
170
|
**返回值:** `EmailInfo`
|
|
178
171
|
|
|
@@ -184,17 +177,16 @@ for (const email of result2.emails) {
|
|
|
184
177
|
| `expiresAt` | `string \| number?` | 过期时间 |
|
|
185
178
|
| `createdAt` | `string?` | 创建时间 |
|
|
186
179
|
|
|
187
|
-
### getEmails(options)
|
|
180
|
+
### getEmails(info, options?)
|
|
188
181
|
|
|
189
182
|
获取邮件列表。
|
|
190
183
|
|
|
191
184
|
**参数:**
|
|
192
185
|
|
|
193
|
-
|
|
|
194
|
-
|
|
195
|
-
| `
|
|
196
|
-
| `
|
|
197
|
-
| `token` | `string` | 部分 | 访问令牌(`tempmail-lol`、`awamail`、`mail-tm`、`dropmail`、`guerrillamail`、`maildrop` 必填) |
|
|
186
|
+
| 参数 | 类型 | 说明 |
|
|
187
|
+
|------|------|------|
|
|
188
|
+
| `info` | `EmailInfo` | 由 `generateEmail()` 或 `TempEmailClient.generate()` 返回;SDK 从中读取 `channel`、`email` 及内部 Token |
|
|
189
|
+
| `options?.retry` | `RetryConfig` | 拉取邮件时的重试配置(可选) |
|
|
198
190
|
|
|
199
191
|
**返回值:** `GetEmailsResult`
|
|
200
192
|
|
|
@@ -281,6 +273,19 @@ export TEMPMAIL_TIMEOUT=30000
|
|
|
281
273
|
|
|
282
274
|
> **提示:** Node.js 原生 fetch 不支持代理,推荐通过 `customFetch` + `undici` 的 `ProxyAgent` 实现代理支持。
|
|
283
275
|
|
|
276
|
+
DropMail 自动令牌等更多配置见源码 `src/config.ts` 注释(`DROPMAIL_*` 环境变量)。
|
|
277
|
+
|
|
278
|
+
## 示例脚本(本仓库)
|
|
279
|
+
|
|
280
|
+
在 `sdk/npm` 目录执行:
|
|
281
|
+
|
|
282
|
+
| 命令 / 文件 | 说明 |
|
|
283
|
+
|-------------|------|
|
|
284
|
+
| `npx ts-node demo/poll-emails.ts` | 未配置 SMTP 时为交互式选渠道并轮询;配置 `SMTP_HOST` 等后可自动向各渠道发探针并轮询(`POLL_CHANNELS`、`POLL_INTERVAL_MS`、`POLL_MAX_ROUNDS`) |
|
|
285
|
+
| `npm run demo:internxt` | `demo/internxt-tempmail-probe.ts`:检查 Internxt 页面与 **Mail.tm(SDK `mail-tm`)** 全流程 |
|
|
286
|
+
|
|
287
|
+
`poll-emails` 使用 SMTP 时需安装:`npm install nodemailer @types/nodemailer`(若尚未加入 devDependencies)。
|
|
288
|
+
|
|
284
289
|
## 环境要求
|
|
285
290
|
|
|
286
291
|
- Node.js 18+(需要原生 `fetch` 支持)
|
package/demo/poll-emails.ts
CHANGED
|
@@ -1,18 +1,66 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Demo: 获取指定渠道邮箱,轮询获取邮件
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
4
|
* 使用方法:
|
|
5
|
-
*
|
|
5
|
+
* npx ts-node demo/poll-emails.ts
|
|
6
|
+
*
|
|
7
|
+
* 行为:
|
|
8
|
+
* - 已设置 SMTP_HOST:自动对全部渠道(可用 POLL_CHANNELS 限定)创建临时邮箱、经 SMTP 发送探针邮件并轮询是否收到,用于验收渠道是否可用。
|
|
9
|
+
* - 未设置 SMTP_HOST:交互式选择单个渠道并轮询(原行为)。
|
|
10
|
+
* - 已设置 SMTP 时仍想交互:加参数 --interactive 或 -i
|
|
11
|
+
*
|
|
12
|
+
* SMTP 环境变量(自动模式必填 SMTP_HOST):
|
|
13
|
+
* SMTP_HOST 服务器地址
|
|
14
|
+
* SMTP_PORT 端口,默认 587
|
|
15
|
+
* SMTP_SECURE 含义随端口变化:
|
|
16
|
+
* - 465 / smtps / implicit:隐式 TLS(整条连接即 SSL,对应 nodemailer secure:true)
|
|
17
|
+
* - 587、2525、25:不使用 secure:true;1/true 表示「强制 STARTTLS」(requireTLS)
|
|
18
|
+
* - 其它端口:1/true 视为隐式 TLS(secure:true)
|
|
19
|
+
* SMTP_REQUIRE_TLS 是否强制 STARTTLS(仅非隐式 TLS 时有效)。未设时 587/2525 默认强制,25 默认不强制
|
|
20
|
+
* SMTP_IGNORE_TLS 1/true 则禁用 STARTTLS(明文,仅调试)
|
|
21
|
+
* SMTP_TLS_REJECT_UNAUTHORIZED 默认校验证书;0/false 允许自签名(仅调试)
|
|
22
|
+
* SMTP_USER 用户名(可选,无认证可留空)
|
|
23
|
+
* SMTP_PASS 密码(可选)
|
|
24
|
+
* SMTP_FROM 发件人地址,默认 SMTP_USER,再否则 noreply@localhost
|
|
25
|
+
*
|
|
26
|
+
* 可选:
|
|
27
|
+
* POLL_CHANNELS 逗号分隔的渠道 id,仅测这些;未设则测全部
|
|
28
|
+
* POLL_INTERVAL_MS 轮询间隔毫秒,默认 5000
|
|
29
|
+
* POLL_MAX_ROUNDS 每渠道最大轮询次数,默认 60
|
|
6
30
|
*/
|
|
7
31
|
|
|
32
|
+
import { randomBytes } from 'crypto';
|
|
8
33
|
import * as readline from 'readline';
|
|
9
|
-
import
|
|
34
|
+
import nodemailer from 'nodemailer';
|
|
35
|
+
import {
|
|
36
|
+
generateEmail,
|
|
37
|
+
getEmails,
|
|
38
|
+
listChannels,
|
|
39
|
+
getChannelInfo,
|
|
40
|
+
Channel,
|
|
41
|
+
EmailInfo,
|
|
42
|
+
ChannelInfo,
|
|
43
|
+
Email,
|
|
44
|
+
} from '../src';
|
|
10
45
|
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
const MAX_POLL_COUNT = 60; // 最大轮询次数
|
|
46
|
+
const POLL_INTERVAL = parseInt(process.env.POLL_INTERVAL_MS || '5000', 10);
|
|
47
|
+
const MAX_POLL_COUNT = parseInt(process.env.POLL_MAX_ROUNDS || '60', 10);
|
|
14
48
|
|
|
15
|
-
|
|
49
|
+
interface SmtpConfig {
|
|
50
|
+
host: string;
|
|
51
|
+
port: number;
|
|
52
|
+
/** true = 隐式 TLS(SMTPS,典型端口 465) */
|
|
53
|
+
secure: boolean;
|
|
54
|
+
/** 明文连接后强制升级到 TLS(587 提交端口) */
|
|
55
|
+
requireTLS: boolean;
|
|
56
|
+
ignoreTLS: boolean;
|
|
57
|
+
tls?: { rejectUnauthorized?: boolean };
|
|
58
|
+
user?: string;
|
|
59
|
+
pass?: string;
|
|
60
|
+
from: string;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function printJson(label: string, data: unknown): void {
|
|
16
64
|
console.log(`\n${label}:`);
|
|
17
65
|
console.log(JSON.stringify(data, null, 2));
|
|
18
66
|
}
|
|
@@ -34,16 +82,124 @@ function question(prompt: string): Promise<string> {
|
|
|
34
82
|
});
|
|
35
83
|
}
|
|
36
84
|
|
|
85
|
+
function envBool(v: string | undefined, defaultVal: boolean): boolean {
|
|
86
|
+
if (v === undefined || v.trim() === '') {
|
|
87
|
+
return defaultVal;
|
|
88
|
+
}
|
|
89
|
+
const s = v.trim().toLowerCase();
|
|
90
|
+
if (['1', 'true', 'yes'].includes(s)) {
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
if (['0', 'false', 'no'].includes(s)) {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
return defaultVal;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function loadSmtpConfig(): SmtpConfig | null {
|
|
100
|
+
const host = process.env.SMTP_HOST?.trim();
|
|
101
|
+
if (!host) {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
const port = parseInt(process.env.SMTP_PORT || '587', 10);
|
|
105
|
+
const sec = process.env.SMTP_SECURE?.trim().toLowerCase();
|
|
106
|
+
|
|
107
|
+
const submissionPorts = new Set([25, 587, 2525]);
|
|
108
|
+
const userWantsEncryption =
|
|
109
|
+
sec === '1' || sec === 'true' || sec === 'yes' || sec === 'implicit' || sec === 'smtps';
|
|
110
|
+
|
|
111
|
+
/** 465 或显式 smtps / implicit → 连接即 TLS */
|
|
112
|
+
const implicitTls =
|
|
113
|
+
port === 465 || sec === 'implicit' || sec === 'smtps';
|
|
114
|
+
|
|
115
|
+
let secure = false;
|
|
116
|
+
if (implicitTls) {
|
|
117
|
+
secure = true;
|
|
118
|
+
} else if (!submissionPorts.has(port) && userWantsEncryption) {
|
|
119
|
+
secure = true;
|
|
120
|
+
}
|
|
121
|
+
/*
|
|
122
|
+
* 587/2525/25 必须用 secure:false,由 STARTTLS 升级;此前把 SMTP_SECURE=1 当成 secure:true
|
|
123
|
+
* 会导致与提交端口不兼容(对方期待明文握手再 STARTTLS)。
|
|
124
|
+
*/
|
|
125
|
+
const ignoreTLS = envBool(process.env.SMTP_IGNORE_TLS, false);
|
|
126
|
+
|
|
127
|
+
const defaultRequireStartTls =
|
|
128
|
+
!secure &&
|
|
129
|
+
!ignoreTLS &&
|
|
130
|
+
(port === 587 || port === 2525 || (port === 25 && userWantsEncryption));
|
|
131
|
+
const requireTLS = envBool(process.env.SMTP_REQUIRE_TLS, defaultRequireStartTls);
|
|
132
|
+
|
|
133
|
+
const rejectUnauthorized = envBool(process.env.SMTP_TLS_REJECT_UNAUTHORIZED, true);
|
|
134
|
+
|
|
135
|
+
const user = process.env.SMTP_USER?.trim() || undefined;
|
|
136
|
+
const pass = process.env.SMTP_PASS?.trim() || undefined;
|
|
137
|
+
const from =
|
|
138
|
+
process.env.SMTP_FROM?.trim() ||
|
|
139
|
+
user ||
|
|
140
|
+
'noreply@localhost';
|
|
141
|
+
return {
|
|
142
|
+
host,
|
|
143
|
+
port,
|
|
144
|
+
secure,
|
|
145
|
+
requireTLS,
|
|
146
|
+
ignoreTLS,
|
|
147
|
+
tls: { rejectUnauthorized },
|
|
148
|
+
user,
|
|
149
|
+
pass,
|
|
150
|
+
from,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function channelsToTest(all: ChannelInfo[]): Channel[] {
|
|
155
|
+
const raw = process.env.POLL_CHANNELS?.trim();
|
|
156
|
+
if (!raw) {
|
|
157
|
+
return all.map((c) => c.channel);
|
|
158
|
+
}
|
|
159
|
+
const wanted = raw.split(',').map((s) => s.trim()).filter(Boolean);
|
|
160
|
+
const valid = new Set<Channel>(all.map((c) => c.channel));
|
|
161
|
+
const picked: Channel[] = [];
|
|
162
|
+
for (const id of wanted) {
|
|
163
|
+
if (valid.has(id as Channel)) {
|
|
164
|
+
picked.push(id as Channel);
|
|
165
|
+
} else {
|
|
166
|
+
console.warn(`未知渠道,已跳过: ${id}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return picked.length > 0 ? picked : all.map((c) => c.channel);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
async function sendProbeMail(config: SmtpConfig, to: string, subject: string, text: string): Promise<void> {
|
|
173
|
+
const transporter = nodemailer.createTransport({
|
|
174
|
+
host: config.host,
|
|
175
|
+
port: config.port,
|
|
176
|
+
secure: config.secure,
|
|
177
|
+
requireTLS: config.requireTLS,
|
|
178
|
+
ignoreTLS: config.ignoreTLS,
|
|
179
|
+
tls: config.tls,
|
|
180
|
+
auth:
|
|
181
|
+
config.user !== undefined && config.pass !== undefined
|
|
182
|
+
? { user: config.user, pass: config.pass }
|
|
183
|
+
: undefined,
|
|
184
|
+
});
|
|
185
|
+
await transporter.sendMail({
|
|
186
|
+
from: config.from,
|
|
187
|
+
to,
|
|
188
|
+
subject,
|
|
189
|
+
text,
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
|
|
37
193
|
async function selectChannel(channels: ChannelInfo[]): Promise<Channel> {
|
|
38
194
|
console.log('\n请选择渠道:');
|
|
39
195
|
channels.forEach((ch, index) => {
|
|
40
196
|
console.log(` [${index + 1}] ${ch.channel} - ${ch.name} (${ch.website})`);
|
|
41
197
|
});
|
|
42
|
-
|
|
198
|
+
|
|
43
199
|
while (true) {
|
|
44
200
|
const input = await question('\n请输入渠道编号 (1-' + channels.length + '): ');
|
|
45
201
|
const num = parseInt(input, 10);
|
|
46
|
-
|
|
202
|
+
|
|
47
203
|
if (num >= 1 && num <= channels.length) {
|
|
48
204
|
return channels[num - 1].channel;
|
|
49
205
|
}
|
|
@@ -82,24 +238,20 @@ async function pollEmails(emailInfo: EmailInfo): Promise<void> {
|
|
|
82
238
|
|
|
83
239
|
while (pollCount < MAX_POLL_COUNT) {
|
|
84
240
|
pollCount++;
|
|
85
|
-
|
|
241
|
+
|
|
86
242
|
try {
|
|
87
243
|
const result = await getEmails(emailInfo);
|
|
88
244
|
|
|
89
245
|
const timestamp = new Date().toLocaleTimeString();
|
|
90
|
-
|
|
246
|
+
|
|
91
247
|
if (result.emails.length > 0) {
|
|
92
248
|
console.log(`\n[${timestamp}] 🎉 收到 ${result.emails.length} 封邮件!\n`);
|
|
93
|
-
|
|
94
|
-
// 打印原始返回数据
|
|
249
|
+
|
|
95
250
|
printJson('返回数据 (GetEmailsResult)', result);
|
|
96
251
|
|
|
97
252
|
for (let i = 0; i < result.emails.length; i++) {
|
|
98
253
|
printEmail(result.emails[i], i);
|
|
99
254
|
}
|
|
100
|
-
|
|
101
|
-
// 收到邮件后可以选择继续轮询或退出
|
|
102
|
-
// break;
|
|
103
255
|
} else {
|
|
104
256
|
process.stdout.write(`\r[${timestamp}] 第 ${pollCount}/${MAX_POLL_COUNT} 次检查,暂无新邮件...`);
|
|
105
257
|
}
|
|
@@ -113,31 +265,130 @@ async function pollEmails(emailInfo: EmailInfo): Promise<void> {
|
|
|
113
265
|
console.log('\n\n已达到最大轮询次数,停止轮询');
|
|
114
266
|
}
|
|
115
267
|
|
|
116
|
-
|
|
268
|
+
type ProbeResult = 'ok' | 'fail_create' | 'fail_smtp' | 'fail_timeout';
|
|
269
|
+
|
|
270
|
+
async function probeChannel(channel: Channel, smtp: SmtpConfig): Promise<ProbeResult> {
|
|
271
|
+
const emailInfo = await generateEmail({ channel, channelFallback: false });
|
|
272
|
+
if (!emailInfo) {
|
|
273
|
+
console.log(' ❌ 创建临时邮箱失败');
|
|
274
|
+
return 'fail_create';
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const to = String(emailInfo.email ?? '').trim();
|
|
278
|
+
if (!to || !to.includes('@')) {
|
|
279
|
+
console.log(' ❌ 无效收件地址(渠道未返回邮箱,例如 linshi-email 触发频率限制时 API 会返回空 data)');
|
|
280
|
+
return 'fail_create';
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const marker = `tm-sdk-${Date.now()}-${randomBytes(4).toString('hex')}`;
|
|
284
|
+
const subject = `[tempmail-sdk] ${marker}`;
|
|
285
|
+
const text = `自动化探针邮件\nmarker: ${marker}\nchannel: ${channel}\n`;
|
|
286
|
+
|
|
287
|
+
try {
|
|
288
|
+
await sendProbeMail(smtp, to, subject, text);
|
|
289
|
+
} catch (err) {
|
|
290
|
+
console.log(` ❌ SMTP 发送失败: ${err}`);
|
|
291
|
+
return 'fail_smtp';
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
console.log(` 📤 已发送测试邮件 → ${to}`);
|
|
295
|
+
|
|
296
|
+
let probeMismatchLogged = false;
|
|
297
|
+
for (let i = 0; i < MAX_POLL_COUNT; i++) {
|
|
298
|
+
const result = await getEmails(emailInfo);
|
|
299
|
+
if (result.success && result.emails.length > 0) {
|
|
300
|
+
const hit = result.emails.some(
|
|
301
|
+
(e) =>
|
|
302
|
+
(e.subject && e.subject.includes(marker)) ||
|
|
303
|
+
(e.text && e.text.includes(marker)) ||
|
|
304
|
+
(e.html && e.html.includes(marker)),
|
|
305
|
+
);
|
|
306
|
+
if (hit) {
|
|
307
|
+
console.log(` ✅ 已收到匹配邮件(第 ${i + 1} 次轮询)`);
|
|
308
|
+
return 'ok';
|
|
309
|
+
}
|
|
310
|
+
const hintChannel = channel === 'smail-pw' || channel === 'chatgpt-org-uk';
|
|
311
|
+
if (hintChannel && !probeMismatchLogged) {
|
|
312
|
+
probeMismatchLogged = true;
|
|
313
|
+
const subs = result.emails.map((e) => e.subject || '(无主题)').join('; ');
|
|
314
|
+
console.log(`\n 提示: 已解析到 ${result.emails.length} 封邮件,但主题/正文/HTML 未含探针标记。主题摘要: ${subs.slice(0, 200)}`);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
process.stdout.write(`\r 轮询 ${i + 1}/${MAX_POLL_COUNT}...`);
|
|
318
|
+
await sleep(POLL_INTERVAL);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
console.log('\n ❌ 超时未收到带标记的邮件');
|
|
322
|
+
if (channel === 'smail-pw') {
|
|
323
|
+
console.log(
|
|
324
|
+
' 提示: smail.pw 依赖 RSC 响应解析;若已修复解析仍超时,可能是外发 SMTP 被拒/延迟,可加大 POLL_MAX_ROUNDS、POLL_INTERVAL_MS 后重试。',
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
return 'fail_timeout';
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
async function runSmtpAutoSuite(smtp: SmtpConfig): Promise<void> {
|
|
331
|
+
console.log('═'.repeat(50));
|
|
332
|
+
console.log(' 临时邮箱 Demo — SMTP 自动探针(默认测全部渠道)');
|
|
333
|
+
console.log('═'.repeat(50));
|
|
334
|
+
console.log(
|
|
335
|
+
`\nSMTP: ${smtp.host}:${smtp.port} implicitTLS=${smtp.secure} requireTLS=${smtp.requireTLS} ignoreTLS=${smtp.ignoreTLS} tls.rejectUnauthorized=${smtp.tls?.rejectUnauthorized ?? true} from=${smtp.from}`,
|
|
336
|
+
);
|
|
337
|
+
|
|
338
|
+
const all = listChannels();
|
|
339
|
+
const targets = channelsToTest(all);
|
|
340
|
+
console.log(`\n待测渠道 (${targets.length}): ${targets.join(', ')}\n`);
|
|
341
|
+
|
|
342
|
+
const stats: Record<ProbeResult, number> = {
|
|
343
|
+
ok: 0,
|
|
344
|
+
fail_create: 0,
|
|
345
|
+
fail_smtp: 0,
|
|
346
|
+
fail_timeout: 0,
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
for (const channel of targets) {
|
|
350
|
+
const info = getChannelInfo(channel);
|
|
351
|
+
const label = info ? `${info.name} (${channel})` : channel;
|
|
352
|
+
console.log(`\n── ${label} ──`);
|
|
353
|
+
const r = await probeChannel(channel, smtp);
|
|
354
|
+
stats[r]++;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
console.log('\n' + '═'.repeat(50));
|
|
358
|
+
console.log(' 汇总');
|
|
359
|
+
console.log('═'.repeat(50));
|
|
360
|
+
console.log(` 成功收到: ${stats.ok}`);
|
|
361
|
+
console.log(` 创建失败: ${stats.fail_create}`);
|
|
362
|
+
console.log(` SMTP 失败: ${stats.fail_smtp}`);
|
|
363
|
+
console.log(` 超时未收到: ${stats.fail_timeout}`);
|
|
364
|
+
|
|
365
|
+
const bad = stats.fail_create + stats.fail_smtp + stats.fail_timeout;
|
|
366
|
+
if (bad > 0) {
|
|
367
|
+
process.exitCode = 1;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
async function runInteractive(): Promise<void> {
|
|
117
372
|
console.log('═'.repeat(50));
|
|
118
373
|
console.log(' 临时邮箱 Demo - 获取邮箱并轮询邮件');
|
|
119
374
|
console.log('═'.repeat(50));
|
|
120
375
|
|
|
121
|
-
// 1. 列出所有支持的渠道
|
|
122
376
|
console.log('\n[1] 列出所有支持的渠道...');
|
|
123
377
|
const channels = listChannels();
|
|
124
378
|
printJson('支持的渠道列表', channels);
|
|
125
379
|
|
|
126
|
-
// 2. 让用户选择渠道
|
|
127
380
|
console.log('\n[2] 选择渠道...');
|
|
128
381
|
const selectedChannel = await selectChannel(channels);
|
|
129
|
-
|
|
130
|
-
// 3. 获取指定渠道信息
|
|
382
|
+
|
|
131
383
|
console.log(`\n[3] 获取渠道 "${selectedChannel}" 信息...`);
|
|
132
384
|
const channelInfo = getChannelInfo(selectedChannel);
|
|
133
385
|
printJson('渠道信息', channelInfo);
|
|
134
386
|
|
|
135
|
-
// 4. 从指定渠道获取邮箱
|
|
136
387
|
console.log(`\n[4] 从 ${selectedChannel} 渠道获取临时邮箱...`);
|
|
137
|
-
|
|
388
|
+
|
|
138
389
|
try {
|
|
139
390
|
const emailInfo = await generateEmail({ channel: selectedChannel });
|
|
140
|
-
|
|
391
|
+
|
|
141
392
|
if (!emailInfo) {
|
|
142
393
|
console.error('\n❌ 所有渠道均不可用');
|
|
143
394
|
process.exit(1);
|
|
@@ -146,7 +397,7 @@ async function main(): Promise<void> {
|
|
|
146
397
|
|
|
147
398
|
console.log('\n✅ 获取邮箱成功!');
|
|
148
399
|
printJson('返回数据 (EmailInfo)', emailInfo);
|
|
149
|
-
|
|
400
|
+
|
|
150
401
|
console.log('\n📋 邮箱信息:');
|
|
151
402
|
console.log(` 渠道: ${emailInfo.channel}`);
|
|
152
403
|
console.log(` 邮箱: ${emailInfo.email}`);
|
|
@@ -158,14 +409,25 @@ async function main(): Promise<void> {
|
|
|
158
409
|
}
|
|
159
410
|
|
|
160
411
|
console.log('\n📧 请发送邮件到以上邮箱地址进行测试');
|
|
161
|
-
|
|
162
|
-
// 5. 轮询获取邮件
|
|
163
|
-
await pollEmails(emailInfo);
|
|
164
412
|
|
|
413
|
+
await pollEmails(emailInfo);
|
|
165
414
|
} catch (error) {
|
|
166
415
|
console.error(`\n❌ 获取邮箱失败: ${error}`);
|
|
167
416
|
process.exit(1);
|
|
168
417
|
}
|
|
169
418
|
}
|
|
170
419
|
|
|
420
|
+
async function main(): Promise<void> {
|
|
421
|
+
const argv = new Set(process.argv.slice(2));
|
|
422
|
+
const forceInteractive = argv.has('--interactive') || argv.has('-i');
|
|
423
|
+
const smtp = loadSmtpConfig();
|
|
424
|
+
|
|
425
|
+
if (smtp && !forceInteractive) {
|
|
426
|
+
await runSmtpAutoSuite(smtp);
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
await runInteractive();
|
|
431
|
+
}
|
|
432
|
+
|
|
171
433
|
main().catch(console.error);
|
package/dist/config.d.ts
CHANGED
|
@@ -6,6 +6,9 @@
|
|
|
6
6
|
* TEMPMAIL_PROXY - 代理 URL
|
|
7
7
|
* TEMPMAIL_TIMEOUT - 超时毫秒数
|
|
8
8
|
* TEMPMAIL_INSECURE - 设为 "1" 或 "true" 跳过 SSL 验证
|
|
9
|
+
* DROPMAIL_AUTH_TOKEN / DROPMAIL_API_TOKEN - DropMail GraphQL 的 af_ 令牌(可选;未设置时 SDK 会 /api/token/generate 获取并在将过期时用 /api/token/renew 续期)
|
|
10
|
+
* DROPMAIL_NO_AUTO_TOKEN - 设为 "1" 或 "true" 则禁止自动拉取/续期令牌
|
|
11
|
+
* DROPMAIL_RENEW_LIFETIME - 自动续期请求的 lifetime,默认 1d(与官网 renew 接口一致)
|
|
9
12
|
*
|
|
10
13
|
* Node.js 环境下设置 insecure 会自动设置 NODE_TLS_REJECT_UNAUTHORIZED=0
|
|
11
14
|
*/
|
|
@@ -19,6 +22,19 @@ export interface SDKConfig {
|
|
|
19
22
|
timeout?: number;
|
|
20
23
|
/** 跳过 SSL 证书验证(调试用) */
|
|
21
24
|
insecure?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* DropMail 渠道专用:GraphQL 端点 `https://dropmail.me/api/graphql/${token}` 中的 token(须为官网生成的 `af_` 前缀令牌)。
|
|
27
|
+
* 也可通过环境变量 DROPMAIL_AUTH_TOKEN 或 DROPMAIL_API_TOKEN 提供。
|
|
28
|
+
* 未配置且未设置 DROPMAIL_NO_AUTO_TOKEN 时,会向 https://dropmail.me/api/token/generate 申请 1h 令牌并内存缓存。
|
|
29
|
+
*/
|
|
30
|
+
dropmailAuthToken?: string;
|
|
31
|
+
/** 为 true 时不自动请求 token(须配置 dropmailAuthToken 或环境变量) */
|
|
32
|
+
dropmailDisableAutoToken?: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* 自动管理令牌即将过期时,调用 /api/token/renew 使用的 lifetime(如 1h、1d)。
|
|
35
|
+
* 也可通过环境变量 DROPMAIL_RENEW_LIFETIME 设置。
|
|
36
|
+
*/
|
|
37
|
+
dropmailRenewLifetime?: string;
|
|
22
38
|
/**
|
|
23
39
|
* 自定义 fetch 函数,用于完全控制 HTTP 请求行为
|
|
24
40
|
* 当设置了 proxy 但环境不支持 undici 时,可通过此选项传入支持代理的 fetch 实现
|
package/dist/config.js
CHANGED
|
@@ -7,6 +7,9 @@
|
|
|
7
7
|
* TEMPMAIL_PROXY - 代理 URL
|
|
8
8
|
* TEMPMAIL_TIMEOUT - 超时毫秒数
|
|
9
9
|
* TEMPMAIL_INSECURE - 设为 "1" 或 "true" 跳过 SSL 验证
|
|
10
|
+
* DROPMAIL_AUTH_TOKEN / DROPMAIL_API_TOKEN - DropMail GraphQL 的 af_ 令牌(可选;未设置时 SDK 会 /api/token/generate 获取并在将过期时用 /api/token/renew 续期)
|
|
11
|
+
* DROPMAIL_NO_AUTO_TOKEN - 设为 "1" 或 "true" 则禁止自动拉取/续期令牌
|
|
12
|
+
* DROPMAIL_RENEW_LIFETIME - 自动续期请求的 lifetime,默认 1d(与官网 renew 接口一致)
|
|
10
13
|
*
|
|
11
14
|
* Node.js 环境下设置 insecure 会自动设置 NODE_TLS_REJECT_UNAUTHORIZED=0
|
|
12
15
|
*/
|
|
@@ -65,4 +68,4 @@ function setConfig(config) {
|
|
|
65
68
|
function getConfig() {
|
|
66
69
|
return globalConfig;
|
|
67
70
|
}
|
|
68
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
71
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlnLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2NvbmZpZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7Ozs7Ozs7Ozs7R0FhRzs7QUFxRUgsOEJBVUM7QUFHRCw4QkFFQztBQXBERCxrQkFBa0I7QUFDbEIsU0FBUyxhQUFhO0lBQ3BCLE1BQU0sTUFBTSxHQUFjLEVBQUUsQ0FBQztJQUM3QixJQUFJLE9BQU8sT0FBTyxLQUFLLFdBQVcsSUFBSSxPQUFPLENBQUMsR0FBRyxFQUFFLENBQUM7UUFDbEQsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLGNBQWMsRUFBRSxDQUFDO1lBQy9CLE1BQU0sQ0FBQyxLQUFLLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxjQUFjLENBQUM7UUFDNUMsQ0FBQztRQUNELElBQUksT0FBTyxDQUFDLEdBQUcsQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1lBQ2pDLE1BQU0sQ0FBQyxHQUFHLFFBQVEsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLGdCQUFnQixFQUFFLEVBQUUsQ0FBQyxDQUFDO1lBQ3JELElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUM7Z0JBQUUsTUFBTSxDQUFDLE9BQU8sR0FBRyxDQUFDLENBQUM7UUFDN0MsQ0FBQztRQUNELElBQUksT0FBTyxDQUFDLEdBQUcsQ0FBQyxpQkFBaUIsS0FBSyxHQUFHLElBQUksT0FBTyxDQUFDLEdBQUcsQ0FBQyxpQkFBaUIsRUFBRSxXQUFXLEVBQUUsS0FBSyxNQUFNLEVBQUUsQ0FBQztZQUNyRyxNQUFNLENBQUMsUUFBUSxHQUFHLElBQUksQ0FBQztRQUN6QixDQUFDO0lBQ0gsQ0FBQztJQUNELE9BQU8sTUFBTSxDQUFDO0FBQ2hCLENBQUM7QUFFRCxJQUFJLFlBQVksR0FBYyxhQUFhLEVBQUUsQ0FBQztBQUU5Qzs7Ozs7Ozs7Ozs7Ozs7OztHQWdCRztBQUNILFNBQWdCLFNBQVMsQ0FBQyxNQUFpQjtJQUN6QyxZQUFZLEdBQUcsRUFBRSxHQUFHLE1BQU0sRUFBRSxDQUFDO0lBQzdCLG1DQUFtQztJQUNuQyxJQUFJLE9BQU8sT0FBTyxLQUFLLFdBQVcsSUFBSSxPQUFPLENBQUMsR0FBRyxFQUFFLENBQUM7UUFDbEQsSUFBSSxNQUFNLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDcEIsT0FBTyxDQUFDLEdBQUcsQ0FBQyw0QkFBNEIsR0FBRyxHQUFHLENBQUM7UUFDakQsQ0FBQzthQUFNLENBQUM7WUFDTixPQUFPLE9BQU8sQ0FBQyxHQUFHLENBQUMsNEJBQTRCLENBQUM7UUFDbEQsQ0FBQztJQUNILENBQUM7QUFDSCxDQUFDO0FBRUQsb0JBQW9CO0FBQ3BCLFNBQWdCLFNBQVM7SUFDdkIsT0FBTyxZQUFZLENBQUM7QUFDdEIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogU0RLIOWFqOWxgOmFjee9rlxuICog5YyF5ZCr5Luj55CG44CB6LaF5pe244CBU1NMIOetieiuvue9ru+8jOS9nOeUqOS6juaJgOaciSBIVFRQIOivt+axglxuICpcbiAqIOaUr+aMgeeOr+Wig+WPmOmHj+iHquWKqOivu+WPlu+8iOS8mOWFiOe6p+S9juS6juS7o+eggeiuvue9ru+8ie+8mlxuICogICBURU1QTUFJTF9QUk9YWSAgICAtIOS7o+eQhiBVUkxcbiAqICAgVEVNUE1BSUxfVElNRU9VVCAgLSDotoXml7bmr6vnp5LmlbBcbiAqICAgVEVNUE1BSUxfSU5TRUNVUkUgLSDorr7kuLogXCIxXCIg5oiWIFwidHJ1ZVwiIOi3s+i/hyBTU0wg6aqM6K+BXG4gKiAgIERST1BNQUlMX0FVVEhfVE9LRU4gLyBEUk9QTUFJTF9BUElfVE9LRU4gLSBEcm9wTWFpbCBHcmFwaFFMIOeahCBhZl8g5Luk54mM77yI5Y+v6YCJ77yb5pyq6K6+572u5pe2IFNESyDkvJogL2FwaS90b2tlbi9nZW5lcmF0ZSDojrflj5blubblnKjlsIbov4fmnJ/ml7bnlKggL2FwaS90b2tlbi9yZW5ldyDnu63mnJ/vvIlcbiAqICAgRFJPUE1BSUxfTk9fQVVUT19UT0tFTiAtIOiuvuS4uiBcIjFcIiDmiJYgXCJ0cnVlXCIg5YiZ56aB5q2i6Ieq5Yqo5ouJ5Y+WL+e7reacn+S7pOeJjFxuICogICBEUk9QTUFJTF9SRU5FV19MSUZFVElNRSAtIOiHquWKqOe7reacn+ivt+axgueahCBsaWZldGltZe+8jOm7mOiupCAxZO+8iOS4juWumOe9kSByZW5ldyDmjqXlj6PkuIDoh7TvvIlcbiAqXG4gKiBOb2RlLmpzIOeOr+Wig+S4i+iuvue9riBpbnNlY3VyZSDkvJroh6rliqjorr7nva4gTk9ERV9UTFNfUkVKRUNUX1VOQVVUSE9SSVpFRD0wXG4gKi9cblxuLyoqXG4gKiBTREsg5YWo5bGA6YWN572u5o6l5Y+jXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU0RLQ29uZmlnIHtcbiAgLyoqIOS7o+eQhiBVUkzvvIzmlK/mjIEgaHR0cC9odHRwcy9zb2NrczXvvIzlpoIgXCJodHRwOi8vMTI3LjAuMC4xOjc4OTBcIiAqL1xuICBwcm94eT86IHN0cmluZztcbiAgLyoqIOWFqOWxgOm7mOiupOi2heaXtu+8iOavq+enku+8ie+8jOm7mOiupCAxNTAwMCAqL1xuICB0aW1lb3V0PzogbnVtYmVyO1xuICAvKiog6Lez6L+HIFNTTCDor4Hkuabpqozor4HvvIjosIPor5XnlKjvvIkgKi9cbiAgaW5zZWN1cmU/OiBib29sZWFuO1xuICAvKipcbiAgICogRHJvcE1haWwg5rig6YGT5LiT55So77yaR3JhcGhRTCDnq6/ngrkgYGh0dHBzOi8vZHJvcG1haWwubWUvYXBpL2dyYXBocWwvJHt0b2tlbn1gIOS4reeahCB0b2tlbu+8iOmhu+S4uuWumOe9keeUn+aIkOeahCBgYWZfYCDliY3nvIDku6TniYzvvInjgIJcbiAgICog5Lmf5Y+v6YCa6L+H546v5aKD5Y+Y6YePIERST1BNQUlMX0FVVEhfVE9LRU4g5oiWIERST1BNQUlMX0FQSV9UT0tFTiDmj5DkvpvjgIJcbiAgICog5pyq6YWN572u5LiU5pyq6K6+572uIERST1BNQUlMX05PX0FVVE9fVE9LRU4g5pe277yM5Lya5ZCRIGh0dHBzOi8vZHJvcG1haWwubWUvYXBpL3Rva2VuL2dlbmVyYXRlIOeUs+ivtyAxaCDku6TniYzlubblhoXlrZjnvJPlrZjjgIJcbiAgICovXG4gIGRyb3BtYWlsQXV0aFRva2VuPzogc3RyaW5nO1xuICAvKiog5Li6IHRydWUg5pe25LiN6Ieq5Yqo6K+35rGCIHRva2Vu77yI6aG76YWN572uIGRyb3BtYWlsQXV0aFRva2VuIOaIlueOr+Wig+WPmOmHj++8iSAqL1xuICBkcm9wbWFpbERpc2FibGVBdXRvVG9rZW4/OiBib29sZWFuO1xuICAvKipcbiAgICog6Ieq5Yqo566h55CG5Luk54mM5Y2z5bCG6L+H5pyf5pe277yM6LCD55SoIC9hcGkvdG9rZW4vcmVuZXcg5L2/55So55qEIGxpZmV0aW1l77yI5aaCIDFo44CBMWTvvInjgIJcbiAgICog5Lmf5Y+v6YCa6L+H546v5aKD5Y+Y6YePIERST1BNQUlMX1JFTkVXX0xJRkVUSU1FIOiuvue9ruOAglxuICAgKi9cbiAgZHJvcG1haWxSZW5ld0xpZmV0aW1lPzogc3RyaW5nO1xuICAvKipcbiAgICog6Ieq5a6a5LmJIGZldGNoIOWHveaVsO+8jOeUqOS6juWujOWFqOaOp+WItiBIVFRQIOivt+axguihjOS4ulxuICAgKiDlvZPorr7nva7kuoYgcHJveHkg5L2G546v5aKD5LiN5pSv5oyBIHVuZGljaSDml7bvvIzlj6/pgJrov4fmraTpgInpobnkvKDlhaXmlK/mjIHku6PnkIbnmoQgZmV0Y2gg5a6e546wXG4gICAqL1xuICBjdXN0b21GZXRjaD86IHR5cGVvZiBmZXRjaDtcbn1cblxuLyoqIOS7jueOr+Wig+WPmOmHj+ivu+WPlum7mOiupOmFjee9riAqL1xuZnVuY3Rpb24gbG9hZEVudkNvbmZpZygpOiBTREtDb25maWcge1xuICBjb25zdCBjb25maWc6IFNES0NvbmZpZyA9IHt9O1xuICBpZiAodHlwZW9mIHByb2Nlc3MgIT09ICd1bmRlZmluZWQnICYmIHByb2Nlc3MuZW52KSB7XG4gICAgaWYgKHByb2Nlc3MuZW52LlRFTVBNQUlMX1BST1hZKSB7XG4gICAgICBjb25maWcucHJveHkgPSBwcm9jZXNzLmVudi5URU1QTUFJTF9QUk9YWTtcbiAgICB9XG4gICAgaWYgKHByb2Nlc3MuZW52LlRFTVBNQUlMX1RJTUVPVVQpIHtcbiAgICAgIGNvbnN0IHQgPSBwYXJzZUludChwcm9jZXNzLmVudi5URU1QTUFJTF9USU1FT1VULCAxMCk7XG4gICAgICBpZiAoIWlzTmFOKHQpICYmIHQgPiAwKSBjb25maWcudGltZW91dCA9IHQ7XG4gICAgfVxuICAgIGlmIChwcm9jZXNzLmVudi5URU1QTUFJTF9JTlNFQ1VSRSA9PT0gJzEnIHx8IHByb2Nlc3MuZW52LlRFTVBNQUlMX0lOU0VDVVJFPy50b0xvd2VyQ2FzZSgpID09PSAndHJ1ZScpIHtcbiAgICAgIGNvbmZpZy5pbnNlY3VyZSA9IHRydWU7XG4gICAgfVxuICB9XG4gIHJldHVybiBjb25maWc7XG59XG5cbmxldCBnbG9iYWxDb25maWc6IFNES0NvbmZpZyA9IGxvYWRFbnZDb25maWcoKTtcblxuLyoqXG4gKiDorr7nva4gU0RLIOWFqOWxgOmFjee9rlxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0c1xuICogLy8g5LiA6KGM6Lez6L+HIFNTTCDpqozor4FcbiAqIHNldENvbmZpZyh7IGluc2VjdXJlOiB0cnVlIH0pO1xuICpcbiAqIC8vIOiuvue9ruS7o+eQhuWSjOi2heaXtlxuICogc2V0Q29uZmlnKHsgcHJveHk6ICdodHRwOi8vMTI3LjAuMC4xOjc4OTAnLCB0aW1lb3V0OiAzMDAwMCB9KTtcbiAqXG4gKiAvLyDkvb/nlKjoh6rlrprkuYkgZmV0Y2jvvIjlpoLmlK/mjIHku6PnkIbnmoQgdW5kaWNp77yJXG4gKiBpbXBvcnQgeyBQcm94eUFnZW50LCBmZXRjaCBhcyB1bmRpY2lGZXRjaCB9IGZyb20gJ3VuZGljaSc7XG4gKiBjb25zdCBhZ2VudCA9IG5ldyBQcm94eUFnZW50KCdodHRwOi8vMTI3LjAuMC4xOjc4OTAnKTtcbiAqIHNldENvbmZpZyh7IGN1c3RvbUZldGNoOiAodXJsLCBpbml0KSA9PiB1bmRpY2lGZXRjaCh1cmwsIHsgLi4uaW5pdCwgZGlzcGF0Y2hlcjogYWdlbnQgfSkgfSk7XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNldENvbmZpZyhjb25maWc6IFNES0NvbmZpZyk6IHZvaWQge1xuICBnbG9iYWxDb25maWcgPSB7IC4uLmNvbmZpZyB9O1xuICAvKiBOb2RlLmpzIOeOr+Wig+S4iyBpbnNlY3VyZSDoh6rliqjorr7nva7njq/looPlj5jph48gKi9cbiAgaWYgKHR5cGVvZiBwcm9jZXNzICE9PSAndW5kZWZpbmVkJyAmJiBwcm9jZXNzLmVudikge1xuICAgIGlmIChjb25maWcuaW5zZWN1cmUpIHtcbiAgICAgIHByb2Nlc3MuZW52Lk5PREVfVExTX1JFSkVDVF9VTkFVVEhPUklaRUQgPSAnMCc7XG4gICAgfSBlbHNlIHtcbiAgICAgIGRlbGV0ZSBwcm9jZXNzLmVudi5OT0RFX1RMU19SRUpFQ1RfVU5BVVRIT1JJWkVEO1xuICAgIH1cbiAgfVxufVxuXG4vKiog6I635Y+W5b2T5YmNIFNESyDlhajlsYDphY3nva4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRDb25maWcoKTogU0RLQ29uZmlnIHtcbiAgcmV0dXJuIGdsb2JhbENvbmZpZztcbn1cbiJdfQ==
|
package/dist/index.d.ts
CHANGED
|
@@ -5,6 +5,8 @@ export { normalizeEmail } from './normalize';
|
|
|
5
5
|
export { withRetry, fetchWithTimeout, RetryOptions } from './retry';
|
|
6
6
|
export { LogLevel, LogHandler, setLogLevel, getLogLevel, setLogger, logger } from './logger';
|
|
7
7
|
export { SDKConfig, setConfig, getConfig } from './config';
|
|
8
|
+
export type { SyntheticBrowserProfile } from './providers/linshi-token';
|
|
9
|
+
export { deriveLinshiApiPathKey, randomSyntheticLinshiKey, randomBrowserLikeProfile, syntheticVisitorIdFromProfile, } from './providers/linshi-token';
|
|
8
10
|
/**
|
|
9
11
|
* 渠道信息,包含渠道标识、显示名称和对应网站
|
|
10
12
|
*/
|
|
@@ -39,7 +41,8 @@ export declare function getChannelInfo(channel: Channel): ChannelInfo | undefine
|
|
|
39
41
|
* 创建临时邮箱
|
|
40
42
|
*
|
|
41
43
|
* 错误处理策略:
|
|
42
|
-
* -
|
|
44
|
+
* - 指定渠道失败时,默认自动尝试其他可用渠道(打乱顺序逐个尝试)
|
|
45
|
+
* - `channelFallback: false` 且指定了 `channel` 时,仅尝试该渠道,失败即返回 null
|
|
43
46
|
* - 未指定渠道时,打乱全部渠道逐个尝试,直到成功
|
|
44
47
|
* - 所有渠道均不可用时返回 null(不抛出异常)
|
|
45
48
|
*
|