tempmail-sdk 1.1.2 → 1.1.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/src/retry.ts CHANGED
@@ -32,8 +32,13 @@ const DEFAULT_RETRY_OPTIONS: Required<RetryOptions> = {
32
32
 
33
33
  /**
34
34
  * 默认重试判断
35
- * 网络错误、超时、HTTP 4xx/5xx 错误均可重试
36
- * 仅参数校验类错误(由 SDK 内部抛出)不重试
35
+ * 以下错误类型会触发重试:
36
+ * - 网络连接错误(fetch failed, ECONNREFUSED, ECONNRESET 等)
37
+ * - 超时错误(timeout, abort)
38
+ * - DNS 解析失败
39
+ * - HTTP 429 限流
40
+ * - HTTP 4xx/5xx 服务端错误(含状态码的错误消息)
41
+ * 仅 SDK 内部的参数校验类错误不重试
37
42
  */
38
43
  function defaultShouldRetry(error: any): boolean {
39
44
  if (!error) return false;
@@ -58,7 +63,7 @@ function defaultShouldRetry(error: any): boolean {
58
63
  return true;
59
64
  }
60
65
 
61
- /* HTTP 4xx/5xx 错误 重试 */
66
+ /* HTTP 4xx/5xx 错误(含状态码的错误消息)→ 重试 */
62
67
  const statusMatch = message.match(/:\s*(\d{3})/);
63
68
  if (statusMatch) {
64
69
  const status = parseInt(statusMatch[1], 10);
@@ -77,9 +82,9 @@ function sleep(ms: number): Promise<void> {
77
82
 
78
83
  /**
79
84
  * 带重试的异步操作执行器
80
- * - 自动重试可恢复的错误(网络错误、超时、5xx)
85
+ * - 自动重试可恢复的错误(网络错误、超时、HTTP 4xx/5xx)
81
86
  * - 指数退避避免过度请求
82
- * - 不可恢复的错误(4xx 参数错误等)直接抛出不重试
87
+ * - 不可恢复的错误(SDK 内部参数校验错误等)直接抛出不重试
83
88
  *
84
89
  * @param fn 要执行的异步操作
85
90
  * @param options 重试配置
@@ -127,18 +132,46 @@ export async function withRetry<T>(fn: () => Promise<T>, options?: RetryOptions)
127
132
  * @param init fetch 选项
128
133
  * @param timeoutMs 超时时间(毫秒)
129
134
  */
135
+ /**
136
+ * 缓存的全局配置快照,避免每次请求都读取
137
+ * 仅在 setConfig 被调用时失效(通过 configVersion 比对)
138
+ */
139
+ let _cachedFetchConfig: { fetchFn: typeof fetch; timeout: number; version: number } | null = null;
140
+
141
+ /**
142
+ * 获取缓存的 fetch 配置
143
+ */
144
+ function getFetchConfig(): { fetchFn: typeof fetch; timeout: number } {
145
+ const config = getConfig();
146
+ /* 简单的引用比对即可,getConfig 在未变更时返回同一对象 */
147
+ if (!_cachedFetchConfig || _cachedFetchConfig.fetchFn !== (config.customFetch || fetch) || _cachedFetchConfig.timeout !== (config.timeout ?? DEFAULT_RETRY_OPTIONS.timeout)) {
148
+ _cachedFetchConfig = {
149
+ fetchFn: config.customFetch || fetch,
150
+ timeout: config.timeout ?? DEFAULT_RETRY_OPTIONS.timeout,
151
+ version: 0,
152
+ };
153
+ }
154
+ return _cachedFetchConfig;
155
+ }
156
+
130
157
  export async function fetchWithTimeout(
131
158
  url: string,
132
159
  init?: RequestInit,
133
160
  timeoutMs?: number,
134
161
  ): Promise<Response> {
135
- const config = getConfig();
136
- const effectiveTimeout = timeoutMs ?? config.timeout ?? DEFAULT_RETRY_OPTIONS.timeout;
162
+ const { fetchFn, timeout: defaultTimeout } = getFetchConfig();
163
+ const effectiveTimeout = timeoutMs ?? defaultTimeout;
137
164
  const controller = new AbortController();
138
165
  const timeoutId = setTimeout(() => controller.abort(), effectiveTimeout);
139
166
 
140
- /* 使用自定义 fetch 或原生 fetch */
141
- const fetchFn = config.customFetch || fetch;
167
+ /*
168
+ * 如果调用方已提供 signal,需要同时监听两个信号(调用方 + 超时)
169
+ * 任一触发则中断请求
170
+ */
171
+ const externalSignal = init?.signal;
172
+ if (externalSignal) {
173
+ externalSignal.addEventListener('abort', () => controller.abort(), { once: true });
174
+ }
142
175
 
143
176
  try {
144
177
  const response = await fetchFn(url, {
package/test/example.ts CHANGED
@@ -10,9 +10,13 @@ async function testGenerateEmail() {
10
10
  try {
11
11
  console.log(`Testing channel: ${channel}`);
12
12
  const emailInfo = await generateEmail({ channel });
13
+ if (!emailInfo) {
14
+ console.log(' Failed to generate email');
15
+ console.log();
16
+ continue;
17
+ }
13
18
  console.log(` Channel: ${emailInfo.channel}`);
14
19
  console.log(` Email: ${emailInfo.email}`);
15
- if (emailInfo.token) console.log(` Token: ${emailInfo.token}`);
16
20
  if (emailInfo.expiresAt) console.log(` Expires: ${emailInfo.expiresAt}`);
17
21
  if (emailInfo.createdAt) console.log(` Created: ${emailInfo.createdAt}`);
18
22
  console.log();
@@ -31,6 +35,10 @@ async function testGetEmails() {
31
35
 
32
36
  try {
33
37
  const emailInfo = await client.generate({ channel: 'tempmail' });
38
+ if (!emailInfo) {
39
+ console.log('Generated: null');
40
+ return;
41
+ }
34
42
  console.log(`Generated: ${emailInfo.channel} - ${emailInfo.email}`);
35
43
 
36
44
  const result = await client.getEmails();