tempmail-sdk 1.1.0 → 1.1.2

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 (50) hide show
  1. package/README.md +44 -0
  2. package/bun.lock +60 -0
  3. package/demo/poll-emails.ts +7 -8
  4. package/dist/config.d.ts +47 -0
  5. package/dist/config.js +68 -0
  6. package/dist/index.d.ts +21 -20
  7. package/dist/index.js +84 -38
  8. package/dist/normalize.js +28 -3
  9. package/dist/providers/awamail.d.ts +2 -2
  10. package/dist/providers/awamail.js +1 -1
  11. package/dist/providers/chatgpt-org-uk.d.ts +2 -2
  12. package/dist/providers/chatgpt-org-uk.js +1 -1
  13. package/dist/providers/dropmail.d.ts +2 -2
  14. package/dist/providers/dropmail.js +1 -1
  15. package/dist/providers/guerrillamail.d.ts +2 -2
  16. package/dist/providers/guerrillamail.js +1 -1
  17. package/dist/providers/linshi-email.d.ts +2 -2
  18. package/dist/providers/linshi-email.js +1 -1
  19. package/dist/providers/mail-tm.d.ts +2 -2
  20. package/dist/providers/mail-tm.js +1 -1
  21. package/dist/providers/maildrop.d.ts +2 -2
  22. package/dist/providers/maildrop.js +1 -1
  23. package/dist/providers/temp-mail-io.d.ts +2 -2
  24. package/dist/providers/temp-mail-io.js +1 -1
  25. package/dist/providers/tempmail-la.d.ts +2 -2
  26. package/dist/providers/tempmail-la.js +1 -1
  27. package/dist/providers/tempmail-lol.d.ts +2 -2
  28. package/dist/providers/tempmail-lol.js +1 -1
  29. package/dist/providers/tempmail.d.ts +2 -2
  30. package/dist/providers/tempmail.js +25 -2
  31. package/dist/retry.js +14 -5
  32. package/dist/types.d.ts +13 -14
  33. package/dist/types.js +1 -1
  34. package/package.json +1 -1
  35. package/src/config.ts +82 -0
  36. package/src/index.ts +87 -40
  37. package/src/normalize.ts +30 -2
  38. package/src/providers/awamail.ts +2 -2
  39. package/src/providers/chatgpt-org-uk.ts +2 -2
  40. package/src/providers/dropmail.ts +2 -2
  41. package/src/providers/guerrillamail.ts +2 -2
  42. package/src/providers/linshi-email.ts +2 -2
  43. package/src/providers/mail-tm.ts +2 -2
  44. package/src/providers/maildrop.ts +2 -2
  45. package/src/providers/temp-mail-io.ts +2 -2
  46. package/src/providers/tempmail-la.ts +2 -2
  47. package/src/providers/tempmail-lol.ts +2 -2
  48. package/src/providers/tempmail.ts +27 -3
  49. package/src/retry.ts +15 -4
  50. package/src/types.ts +14 -14
@@ -1,4 +1,4 @@
1
- import { EmailInfo, Email, Channel } from '../types';
1
+ import { InternalEmailInfo, Email, Channel } from '../types';
2
2
  import { normalizeEmail } from '../normalize';
3
3
 
4
4
  const CHANNEL: Channel = 'tempmail';
@@ -14,7 +14,7 @@ const DEFAULT_HEADERS = {
14
14
  'DNT': '1',
15
15
  };
16
16
 
17
- export async function generateEmail(duration: number = 30): Promise<EmailInfo> {
17
+ export async function generateEmail(duration: number = 30): Promise<InternalEmailInfo> {
18
18
  const response = await fetch(`${BASE_URL}/generate`, {
19
19
  method: 'POST',
20
20
  headers: DEFAULT_HEADERS,
@@ -57,5 +57,29 @@ export async function getEmails(email: string): Promise<Email[]> {
57
57
  }
58
58
 
59
59
  const rawEmails = data.emails || [];
60
- return rawEmails.map((raw: any) => normalizeEmail(raw, email));
60
+ return rawEmails.map((raw: any) => normalizeEmail(flattenMessage(raw, email), email));
61
+ }
62
+
63
+ /**
64
+ * 将 tempmail.ing 的原始邮件格式扁平化
65
+ *
66
+ * API 返回格式:
67
+ * from_address: 发件人邮箱
68
+ * content: HTML 内容(非纯文本)
69
+ * text: 纯文本(通常为空)
70
+ * received_at: 接收时间
71
+ * is_read: 0/1
72
+ */
73
+ function flattenMessage(raw: any, recipientEmail: string): any {
74
+ return {
75
+ id: raw.id ?? '',
76
+ from: raw.from_address || raw.from || '',
77
+ to: recipientEmail,
78
+ subject: raw.subject || '',
79
+ text: raw.text || '',
80
+ html: raw.content || raw.html || '',
81
+ date: raw.received_at || raw.date || '',
82
+ isRead: raw.is_read === 1 || raw.is_read === true,
83
+ attachments: raw.attachments || [],
84
+ };
61
85
  }
package/src/retry.ts CHANGED
@@ -4,6 +4,7 @@
4
4
  */
5
5
 
6
6
  import { logger } from './logger';
7
+ import { getConfig } from './config';
7
8
 
8
9
  /**
9
10
  * 重试配置选项
@@ -52,6 +53,11 @@ function defaultShouldRetry(error: any): boolean {
52
53
  return true;
53
54
  }
54
55
 
56
+ /* HTTP 429 限流 → 重试 */
57
+ if (message.includes('429') || message.includes('too many requests') || message.includes('rate limit')) {
58
+ return true;
59
+ }
60
+
55
61
  /* HTTP 4xx/5xx 错误 → 重试 */
56
62
  const statusMatch = message.match(/:\s*(\d{3})/);
57
63
  if (statusMatch) {
@@ -124,20 +130,25 @@ export async function withRetry<T>(fn: () => Promise<T>, options?: RetryOptions)
124
130
  export async function fetchWithTimeout(
125
131
  url: string,
126
132
  init?: RequestInit,
127
- timeoutMs: number = DEFAULT_RETRY_OPTIONS.timeout,
133
+ timeoutMs?: number,
128
134
  ): Promise<Response> {
135
+ const config = getConfig();
136
+ const effectiveTimeout = timeoutMs ?? config.timeout ?? DEFAULT_RETRY_OPTIONS.timeout;
129
137
  const controller = new AbortController();
130
- const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
138
+ const timeoutId = setTimeout(() => controller.abort(), effectiveTimeout);
139
+
140
+ /* 使用自定义 fetch 或原生 fetch */
141
+ const fetchFn = config.customFetch || fetch;
131
142
 
132
143
  try {
133
- const response = await fetch(url, {
144
+ const response = await fetchFn(url, {
134
145
  ...init,
135
146
  signal: controller.signal,
136
147
  });
137
148
  return response;
138
149
  } catch (error: any) {
139
150
  if (error.name === 'AbortError') {
140
- throw new Error(`Request timeout after ${timeoutMs}ms: ${url}`);
151
+ throw new Error(`Request timeout after ${effectiveTimeout}ms: ${url}`);
141
152
  }
142
153
  throw error;
143
154
  } finally {
package/src/types.ts CHANGED
@@ -6,21 +6,29 @@ export type Channel = 'tempmail' | 'linshi-email' | 'tempmail-lol' | 'chatgpt-or
6
6
 
7
7
  /**
8
8
  * 创建临时邮箱后返回的邮箱信息
9
- * 包含邮箱地址、认证令牌和生命周期信息
9
+ * Token 等认证信息由 SDK 内部维护,不对外暴露
10
10
  */
11
11
  export interface EmailInfo {
12
12
  /** 创建该邮箱所使用的渠道 */
13
13
  channel: Channel;
14
14
  /** 临时邮箱地址 */
15
15
  email: string;
16
- /** 认证令牌,部分渠道在获取邮件时需要此令牌 */
17
- token?: string;
18
16
  /** 邮箱过期时间(ISO 8601 字符串或 Unix 时间戳) */
19
17
  expiresAt?: string | number;
20
18
  /** 邮箱创建时间(ISO 8601 字符串) */
21
19
  createdAt?: string;
22
20
  }
23
21
 
22
+ /**
23
+ * SDK 内部使用的邮箱信息,包含 token 等认证数据
24
+ * 不对外导出,用户无法访问
25
+ * @internal
26
+ */
27
+ export interface InternalEmailInfo extends EmailInfo {
28
+ /** 认证令牌,由 SDK 内部维护 */
29
+ token?: string;
30
+ }
31
+
24
32
  /**
25
33
  * 标准化邮件附件
26
34
  * 不同渠道的附件字段名不同,SDK 统一归一化为此结构
@@ -125,26 +133,18 @@ export interface GenerateEmailOptions {
125
133
 
126
134
  /**
127
135
  * 获取邮件列表的选项
136
+ * Channel/Email/Token 等由 SDK 从 EmailInfo 中自动获取,用户无需手动传递
128
137
  *
129
138
  * @example
130
139
  * ```ts
131
- * const result = await getEmails({
132
- * channel: emailInfo.channel,
133
- * email: emailInfo.email,
134
- * token: emailInfo.token,
135
- * });
140
+ * const info = await generateEmail({ channel: 'mail-tm' });
141
+ * const result = await getEmails(info);
136
142
  * if (result.success && result.emails.length > 0) {
137
143
  * console.log('收到邮件:', result.emails);
138
144
  * }
139
145
  * ```
140
146
  */
141
147
  export interface GetEmailsOptions {
142
- /** 渠道标识,必填 */
143
- channel: Channel;
144
- /** 邮箱地址,必填 */
145
- email: string;
146
- /** 认证令牌 */
147
- token?: string;
148
148
  /** 重试配置,不传则使用默认值(最多重试 2 次) */
149
149
  retry?: RetryConfig;
150
150
  }