@z_06/relay-temp-mail 1.0.0
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 +226 -0
- package/README.zh-CN.md +195 -0
- package/dist/index.cjs +613 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +317 -0
- package/dist/index.d.ts +317 -0
- package/dist/index.js +580 -0
- package/dist/index.js.map +1 -0
- package/package.json +38 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,613 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
AuthError: () => AuthError,
|
|
24
|
+
NetworkError: () => NetworkError,
|
|
25
|
+
NotFoundError: () => NotFoundError,
|
|
26
|
+
ParseError: () => ParseError,
|
|
27
|
+
RateLimitError: () => RateLimitError,
|
|
28
|
+
RelayClient: () => RelayClient,
|
|
29
|
+
RelayTempMailError: () => RelayTempMailError
|
|
30
|
+
});
|
|
31
|
+
module.exports = __toCommonJS(index_exports);
|
|
32
|
+
|
|
33
|
+
// src/errors.ts
|
|
34
|
+
var RelayTempMailError = class extends Error {
|
|
35
|
+
/**
|
|
36
|
+
* Creates a new RelayTempMailError instance.
|
|
37
|
+
*
|
|
38
|
+
* @param message - Human-readable error message describing the error.
|
|
39
|
+
* @param code - Machine-readable error code (e.g., 'UNKNOWN_ERROR').
|
|
40
|
+
* @param statusCode - Optional HTTP status code associated with the error.
|
|
41
|
+
* @param response - Optional raw response data from the API.
|
|
42
|
+
*/
|
|
43
|
+
constructor(message, code, statusCode, response) {
|
|
44
|
+
super(message);
|
|
45
|
+
this.name = this.constructor.name;
|
|
46
|
+
this.code = code;
|
|
47
|
+
this.statusCode = statusCode;
|
|
48
|
+
this.response = response;
|
|
49
|
+
if (Error.captureStackTrace) {
|
|
50
|
+
Error.captureStackTrace(this, this.constructor);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
var NetworkError = class extends RelayTempMailError {
|
|
55
|
+
constructor(message, response) {
|
|
56
|
+
super(message, "NETWORK_ERROR", void 0, response);
|
|
57
|
+
this.code = "NETWORK_ERROR";
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
var AuthError = class extends RelayTempMailError {
|
|
61
|
+
constructor(message, statusCode, response) {
|
|
62
|
+
super(message, "AUTH_ERROR", statusCode, response);
|
|
63
|
+
this.code = "AUTH_ERROR";
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
var NotFoundError = class extends RelayTempMailError {
|
|
67
|
+
constructor(message, response) {
|
|
68
|
+
super(message, "NOT_FOUND", 404, response);
|
|
69
|
+
this.code = "NOT_FOUND";
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
var ParseError = class extends RelayTempMailError {
|
|
73
|
+
constructor(message, response) {
|
|
74
|
+
super(message, "PARSE_ERROR", void 0, response);
|
|
75
|
+
this.code = "PARSE_ERROR";
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
var RateLimitError = class extends RelayTempMailError {
|
|
79
|
+
constructor(message, response) {
|
|
80
|
+
super(message, "RATE_LIMIT_ERROR", 429, response);
|
|
81
|
+
this.code = "RATE_LIMIT_ERROR";
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
// src/cf-api.ts
|
|
86
|
+
var DefaultHttpClient = class {
|
|
87
|
+
async get(url, options) {
|
|
88
|
+
const response = await fetch(url, {
|
|
89
|
+
method: "GET",
|
|
90
|
+
headers: options?.headers
|
|
91
|
+
});
|
|
92
|
+
if (!response.ok) {
|
|
93
|
+
const errorBody = await response.text();
|
|
94
|
+
throw new RelayTempMailError(
|
|
95
|
+
`HTTP ${response.status}: ${errorBody}`,
|
|
96
|
+
"HTTP_ERROR",
|
|
97
|
+
response.status,
|
|
98
|
+
errorBody
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
return response.json();
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
var CFEmailClient = class {
|
|
105
|
+
/**
|
|
106
|
+
* Creates a new CFEmailClient instance.
|
|
107
|
+
*
|
|
108
|
+
* @param apiUrl - Base URL for the CF temp email API
|
|
109
|
+
* @param token - Bearer token for authentication
|
|
110
|
+
* @param httpClient - Optional HTTP client (defaults to fetch-based implementation)
|
|
111
|
+
*/
|
|
112
|
+
constructor(apiUrl, token, httpClient) {
|
|
113
|
+
this.apiUrl = apiUrl;
|
|
114
|
+
this.token = token;
|
|
115
|
+
this.httpClient = httpClient ?? new DefaultHttpClient();
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Retrieves emails from the CF temp email API.
|
|
119
|
+
*
|
|
120
|
+
* @param limit - Maximum number of emails to return (default: 20)
|
|
121
|
+
* @param offset - Pagination offset (default: 0)
|
|
122
|
+
* @returns Promise resolving to an array of Email objects
|
|
123
|
+
* @throws AuthError if authentication fails
|
|
124
|
+
* @throws NetworkError if there's a network problem
|
|
125
|
+
* @throws NotFoundError if the endpoint doesn't exist
|
|
126
|
+
* @throws RateLimitError if rate limited
|
|
127
|
+
*/
|
|
128
|
+
async getMails(limit = 20, offset = 0) {
|
|
129
|
+
const url = new URL(`${this.apiUrl}/api/mails`);
|
|
130
|
+
url.searchParams.set("limit", String(limit));
|
|
131
|
+
url.searchParams.set("offset", String(offset));
|
|
132
|
+
const headers = {
|
|
133
|
+
"Authorization": `Bearer ${this.token}`
|
|
134
|
+
};
|
|
135
|
+
try {
|
|
136
|
+
const response = await this.httpClient.get(url.toString(), { headers });
|
|
137
|
+
return this.mapCFResponse(response);
|
|
138
|
+
} catch (error) {
|
|
139
|
+
throw this.handleError(error);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Maps the raw CF API response to the Email interface.
|
|
144
|
+
*
|
|
145
|
+
* Converts snake_case property names to camelCase.
|
|
146
|
+
*
|
|
147
|
+
* @param response - Raw response from CF API
|
|
148
|
+
* @returns Array of Email objects
|
|
149
|
+
*/
|
|
150
|
+
mapCFResponse(response) {
|
|
151
|
+
return response.results.map((item) => ({
|
|
152
|
+
id: item.id,
|
|
153
|
+
messageId: item.message_id,
|
|
154
|
+
source: item.source,
|
|
155
|
+
address: item.address,
|
|
156
|
+
raw: item.raw,
|
|
157
|
+
metadata: item.metadata,
|
|
158
|
+
createdAt: item.created_at
|
|
159
|
+
}));
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Handles errors from HTTP requests.
|
|
163
|
+
*
|
|
164
|
+
* Maps HTTP errors to appropriate error classes.
|
|
165
|
+
*
|
|
166
|
+
* @param error - The caught error
|
|
167
|
+
* @returns Appropriate RelayTempMailError subclass
|
|
168
|
+
*/
|
|
169
|
+
handleError(error) {
|
|
170
|
+
if (error instanceof RelayTempMailError) {
|
|
171
|
+
const statusCode = error.statusCode;
|
|
172
|
+
if (statusCode === 401 || statusCode === 403) {
|
|
173
|
+
return new AuthError(error.message, statusCode, error.response);
|
|
174
|
+
}
|
|
175
|
+
if (statusCode === 404) {
|
|
176
|
+
return new NotFoundError(error.message, error.response);
|
|
177
|
+
}
|
|
178
|
+
if (statusCode === 429) {
|
|
179
|
+
return new RateLimitError(error.message, error.response);
|
|
180
|
+
}
|
|
181
|
+
return error;
|
|
182
|
+
}
|
|
183
|
+
if (error instanceof TypeError && error.message.includes("fetch")) {
|
|
184
|
+
return new NetworkError(error.message);
|
|
185
|
+
}
|
|
186
|
+
if (error instanceof Error) {
|
|
187
|
+
return new NetworkError(error.message);
|
|
188
|
+
}
|
|
189
|
+
return new RelayTempMailError(
|
|
190
|
+
"Unknown error occurred",
|
|
191
|
+
"UNKNOWN_ERROR",
|
|
192
|
+
void 0,
|
|
193
|
+
error
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
// src/http.ts
|
|
199
|
+
var HttpClient = class {
|
|
200
|
+
/**
|
|
201
|
+
* Creates a new HttpClient instance.
|
|
202
|
+
*
|
|
203
|
+
* @param baseUrl - Base URL for all requests (e.g., 'https://api.example.com')
|
|
204
|
+
* @param defaultTimeout - Default timeout in milliseconds (default: 30000)
|
|
205
|
+
* @param defaultRetries - Default number of retries on failure (default: 0)
|
|
206
|
+
*/
|
|
207
|
+
constructor(baseUrl, defaultTimeout = 3e4, defaultRetries = 0) {
|
|
208
|
+
this.baseUrl = baseUrl.replace(/\/$/, "");
|
|
209
|
+
this.defaultTimeout = defaultTimeout;
|
|
210
|
+
this.defaultRetries = defaultRetries;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Makes an HTTP request to the specified path.
|
|
214
|
+
*
|
|
215
|
+
* @param method - HTTP method (GET, POST, PUT, DELETE, etc.)
|
|
216
|
+
* @param path - API path (will be appended to baseUrl)
|
|
217
|
+
* @param options - Optional request configuration
|
|
218
|
+
* @returns Promise resolving to the parsed JSON response
|
|
219
|
+
*/
|
|
220
|
+
async request(method, path, options = {}) {
|
|
221
|
+
const timeout = options.timeout ?? this.defaultTimeout;
|
|
222
|
+
const retries = options.retries ?? this.defaultRetries;
|
|
223
|
+
let lastError;
|
|
224
|
+
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
225
|
+
try {
|
|
226
|
+
const response = await this.executeRequest(method, path, options, timeout);
|
|
227
|
+
return await this.handleResponse(response);
|
|
228
|
+
} catch (error) {
|
|
229
|
+
lastError = error;
|
|
230
|
+
if (attempt < retries && this.shouldRetry(error)) {
|
|
231
|
+
const delay = 1e3 * Math.pow(2, attempt);
|
|
232
|
+
await this.sleep(delay);
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
if (error instanceof RelayTempMailError) {
|
|
236
|
+
throw error;
|
|
237
|
+
}
|
|
238
|
+
throw this.classifyError(error);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
throw lastError || new NetworkError("Request failed");
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Executes the actual HTTP request with timeout support.
|
|
245
|
+
*/
|
|
246
|
+
async executeRequest(method, path, options, timeout) {
|
|
247
|
+
const url = `${this.baseUrl}${path}`;
|
|
248
|
+
const controller = new AbortController();
|
|
249
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
250
|
+
try {
|
|
251
|
+
const fetchOptions = {
|
|
252
|
+
method,
|
|
253
|
+
headers: {
|
|
254
|
+
"Content-Type": "application/json",
|
|
255
|
+
...options.headers
|
|
256
|
+
},
|
|
257
|
+
signal: controller.signal
|
|
258
|
+
};
|
|
259
|
+
if (options.body !== void 0) {
|
|
260
|
+
fetchOptions.body = JSON.stringify(options.body);
|
|
261
|
+
}
|
|
262
|
+
const response = await fetch(url, fetchOptions);
|
|
263
|
+
return response;
|
|
264
|
+
} finally {
|
|
265
|
+
clearTimeout(timeoutId);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Handles the HTTP response, parsing JSON and checking for errors.
|
|
270
|
+
*/
|
|
271
|
+
async handleResponse(response) {
|
|
272
|
+
if (!response.ok) {
|
|
273
|
+
throw this.classifyError(new Error(`HTTP ${response.status}`), response);
|
|
274
|
+
}
|
|
275
|
+
const text = await response.text();
|
|
276
|
+
if (!text) {
|
|
277
|
+
return {};
|
|
278
|
+
}
|
|
279
|
+
return JSON.parse(text);
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Classifies an error based on the error type and HTTP response.
|
|
283
|
+
*/
|
|
284
|
+
classifyError(error, response) {
|
|
285
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
286
|
+
return new NetworkError("Request timed out");
|
|
287
|
+
}
|
|
288
|
+
if (error instanceof TypeError && error.message.includes("fetch")) {
|
|
289
|
+
return new NetworkError("Network request failed");
|
|
290
|
+
}
|
|
291
|
+
if (error instanceof Error && error.message.includes("Failed to fetch")) {
|
|
292
|
+
return new NetworkError("Network request failed");
|
|
293
|
+
}
|
|
294
|
+
if (response) {
|
|
295
|
+
const status = response.status;
|
|
296
|
+
if (status === 401 || status === 403) {
|
|
297
|
+
return new AuthError(
|
|
298
|
+
`Authentication failed: ${response.statusText}`,
|
|
299
|
+
status
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
if (status === 404) {
|
|
303
|
+
return new NotFoundError(`Resource not found: ${response.statusText}`);
|
|
304
|
+
}
|
|
305
|
+
if (status === 429) {
|
|
306
|
+
return new RateLimitError(
|
|
307
|
+
`Rate limit exceeded: ${response.statusText}`
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
if (status >= 500) {
|
|
311
|
+
return new NetworkError(
|
|
312
|
+
`Server error: ${response.statusText}`,
|
|
313
|
+
status
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
if (error instanceof Error) {
|
|
318
|
+
return new RelayTempMailError(
|
|
319
|
+
error.message,
|
|
320
|
+
"REQUEST_ERROR",
|
|
321
|
+
response?.status
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
return new RelayTempMailError("Unknown error occurred", "UNKNOWN_ERROR");
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Determines if a request should be retried based on the error.
|
|
328
|
+
*/
|
|
329
|
+
shouldRetry(error) {
|
|
330
|
+
if (error instanceof NetworkError) {
|
|
331
|
+
return true;
|
|
332
|
+
}
|
|
333
|
+
if (error instanceof RelayTempMailError && error.statusCode) {
|
|
334
|
+
return error.statusCode >= 500;
|
|
335
|
+
}
|
|
336
|
+
if (error instanceof Error) {
|
|
337
|
+
if (error.name === "AbortError") {
|
|
338
|
+
return true;
|
|
339
|
+
}
|
|
340
|
+
if (error instanceof TypeError && error.message.includes("fetch")) {
|
|
341
|
+
return true;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
return false;
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Sleep for a specified duration.
|
|
348
|
+
*/
|
|
349
|
+
sleep(ms) {
|
|
350
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
351
|
+
}
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
// src/parser.ts
|
|
355
|
+
var MOZMAIL_PATTERN = /[a-zA-Z0-9]+@mozmail\.com/g;
|
|
356
|
+
var ENCODED_WORD_PATTERN = /=\?([^?]+)\?([BbQq])\?([^?]*)\?=/g;
|
|
357
|
+
var EmailParser = class {
|
|
358
|
+
parseEmail(raw) {
|
|
359
|
+
const headers = this.parseHeaders(raw);
|
|
360
|
+
const toHeader = headers.get("to") || "";
|
|
361
|
+
const fromHeader = headers.get("from") || "";
|
|
362
|
+
const messageIdHeader = headers.get("message-id") || "";
|
|
363
|
+
const relayAlias = this.extractRelayAlias(raw);
|
|
364
|
+
return {
|
|
365
|
+
id: 0,
|
|
366
|
+
messageId: this.extractMessageId(messageIdHeader),
|
|
367
|
+
source: this.extractEmailAddress(fromHeader),
|
|
368
|
+
address: this.extractEmailAddress(toHeader),
|
|
369
|
+
raw,
|
|
370
|
+
metadata: null,
|
|
371
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
372
|
+
relayAlias: relayAlias || void 0
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
extractRelayAlias(raw) {
|
|
376
|
+
try {
|
|
377
|
+
const headers = this.parseHeaders(raw);
|
|
378
|
+
const toHeader = headers.get("to");
|
|
379
|
+
if (!toHeader) return null;
|
|
380
|
+
const decodedTo = this.decodeHeader(toHeader);
|
|
381
|
+
const matches = decodedTo.match(MOZMAIL_PATTERN);
|
|
382
|
+
return matches && matches.length > 0 ? matches[0].toLowerCase() : null;
|
|
383
|
+
} catch {
|
|
384
|
+
return null;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
parseHeaders(raw) {
|
|
388
|
+
const headers = /* @__PURE__ */ new Map();
|
|
389
|
+
const headerEnd = raw.indexOf("\r\n\r\n");
|
|
390
|
+
const headerSection = headerEnd === -1 ? raw : raw.substring(0, headerEnd);
|
|
391
|
+
const lines = headerSection.split(/\r?\n/);
|
|
392
|
+
let currentHeader = null;
|
|
393
|
+
let currentValue = "";
|
|
394
|
+
for (const line of lines) {
|
|
395
|
+
if (/^\s/.test(line)) {
|
|
396
|
+
if (currentHeader) currentValue += " " + line.trim();
|
|
397
|
+
} else {
|
|
398
|
+
if (currentHeader) headers.set(currentHeader, currentValue);
|
|
399
|
+
const colonIndex = line.indexOf(":");
|
|
400
|
+
if (colonIndex > 0) {
|
|
401
|
+
currentHeader = line.substring(0, colonIndex).toLowerCase().trim();
|
|
402
|
+
currentValue = line.substring(colonIndex + 1).trim();
|
|
403
|
+
} else {
|
|
404
|
+
currentHeader = null;
|
|
405
|
+
currentValue = "";
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
if (currentHeader) headers.set(currentHeader, currentValue);
|
|
410
|
+
return headers;
|
|
411
|
+
}
|
|
412
|
+
decodeHeader(value) {
|
|
413
|
+
return value.replace(ENCODED_WORD_PATTERN, (_, charset, encoding, encoded) => {
|
|
414
|
+
try {
|
|
415
|
+
if (encoding.toUpperCase() === "Q") {
|
|
416
|
+
return this.decodeQuotedPrintable(encoded);
|
|
417
|
+
} else if (encoding.toUpperCase() === "B") {
|
|
418
|
+
return this.decodeBase64(encoded);
|
|
419
|
+
}
|
|
420
|
+
return encoded;
|
|
421
|
+
} catch {
|
|
422
|
+
return encoded;
|
|
423
|
+
}
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
decodeQuotedPrintable(encoded) {
|
|
427
|
+
let decoded = encoded.replace(/_/g, " ");
|
|
428
|
+
decoded = decoded.replace(
|
|
429
|
+
/=([0-9A-Fa-f]{2})/g,
|
|
430
|
+
(_, hex) => String.fromCharCode(parseInt(hex, 16))
|
|
431
|
+
);
|
|
432
|
+
return decoded;
|
|
433
|
+
}
|
|
434
|
+
decodeBase64(encoded) {
|
|
435
|
+
return Buffer.from(encoded, "base64").toString("utf-8");
|
|
436
|
+
}
|
|
437
|
+
extractEmailAddress(headerValue) {
|
|
438
|
+
if (!headerValue) return "";
|
|
439
|
+
const decoded = this.decodeHeader(headerValue);
|
|
440
|
+
const bracketMatch = decoded.match(/<([^>]+)>/);
|
|
441
|
+
if (bracketMatch) return bracketMatch[1].trim().toLowerCase();
|
|
442
|
+
const emailMatch = decoded.match(/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/);
|
|
443
|
+
return emailMatch ? emailMatch[0].toLowerCase() : decoded.trim().toLowerCase();
|
|
444
|
+
}
|
|
445
|
+
extractMessageId(headerValue) {
|
|
446
|
+
if (!headerValue) return `<generated-${Date.now()}@relay-temp-mail>`;
|
|
447
|
+
const cleaned = headerValue.replace(/[<>]/g, "").trim();
|
|
448
|
+
return `<${cleaned}>`;
|
|
449
|
+
}
|
|
450
|
+
};
|
|
451
|
+
|
|
452
|
+
// src/relay-api.ts
|
|
453
|
+
var RelayAPIClient = class {
|
|
454
|
+
constructor(csrfToken, sessionId, httpClient) {
|
|
455
|
+
this.csrfToken = csrfToken;
|
|
456
|
+
this.sessionId = sessionId;
|
|
457
|
+
this.httpClient = httpClient ?? new HttpClient("https://relay.firefox.com");
|
|
458
|
+
}
|
|
459
|
+
getAuthHeaders() {
|
|
460
|
+
return {
|
|
461
|
+
"Origin": "https://relay.firefox.com",
|
|
462
|
+
"Referer": "https://relay.firefox.com/accounts/profile/?",
|
|
463
|
+
"Accept": "application/json",
|
|
464
|
+
"X-CSRFToken": this.csrfToken,
|
|
465
|
+
"Cookie": `sessionid=${this.sessionId}; csrftoken=${this.csrfToken}`
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
async getAliases() {
|
|
469
|
+
const response = await this.httpClient.request(
|
|
470
|
+
"GET",
|
|
471
|
+
"/api/v1/relayaddresses/",
|
|
472
|
+
{ headers: this.getAuthHeaders() }
|
|
473
|
+
);
|
|
474
|
+
return response.map((item) => this.mapAliasResponse(item));
|
|
475
|
+
}
|
|
476
|
+
async createAlias() {
|
|
477
|
+
const response = await this.httpClient.request(
|
|
478
|
+
"POST",
|
|
479
|
+
"/api/v1/relayaddresses/",
|
|
480
|
+
{
|
|
481
|
+
headers: this.getAuthHeaders(),
|
|
482
|
+
body: { enabled: true }
|
|
483
|
+
}
|
|
484
|
+
);
|
|
485
|
+
return this.mapAliasResponse(response);
|
|
486
|
+
}
|
|
487
|
+
async deleteAlias(id) {
|
|
488
|
+
await this.httpClient.request(
|
|
489
|
+
"DELETE",
|
|
490
|
+
`/api/v1/relayaddresses/${id}/`,
|
|
491
|
+
{ headers: this.getAuthHeaders() }
|
|
492
|
+
);
|
|
493
|
+
}
|
|
494
|
+
mapAliasResponse(data) {
|
|
495
|
+
return {
|
|
496
|
+
id: data.id,
|
|
497
|
+
address: data.address,
|
|
498
|
+
fullAddress: data.full_address,
|
|
499
|
+
enabled: data.enabled,
|
|
500
|
+
createdAt: data.created_at,
|
|
501
|
+
domain: data.domain,
|
|
502
|
+
maskType: data.mask_type,
|
|
503
|
+
description: data.description,
|
|
504
|
+
numForwarded: data.num_forwarded,
|
|
505
|
+
numBlocked: data.num_blocked,
|
|
506
|
+
lastModifiedAt: data.last_modified_at,
|
|
507
|
+
lastUsedAt: data.last_used_at,
|
|
508
|
+
numLevelOneTrackersBlocked: data.num_level_one_trackers_blocked,
|
|
509
|
+
numReplied: data.num_replied,
|
|
510
|
+
numSpam: data.num_spam,
|
|
511
|
+
blockListEmails: data.block_list_emails,
|
|
512
|
+
generatedFor: data.generated_for,
|
|
513
|
+
usedOn: data.used_on
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
};
|
|
517
|
+
|
|
518
|
+
// src/client.ts
|
|
519
|
+
var RelayClient = class {
|
|
520
|
+
/**
|
|
521
|
+
* Creates a new RelayClient instance.
|
|
522
|
+
*
|
|
523
|
+
* @param config - Configuration object containing authentication tokens and API URLs
|
|
524
|
+
*/
|
|
525
|
+
constructor(config) {
|
|
526
|
+
const timeout = config.timeout ?? 3e4;
|
|
527
|
+
const relayHttpClient = new HttpClient("https://relay.firefox.com", timeout);
|
|
528
|
+
this.relayApi = new RelayAPIClient(
|
|
529
|
+
config.csrfToken,
|
|
530
|
+
config.sessionId,
|
|
531
|
+
relayHttpClient
|
|
532
|
+
);
|
|
533
|
+
this.cfApi = new CFEmailClient(config.cfApiUrl, config.cfToken);
|
|
534
|
+
this.parser = new EmailParser();
|
|
535
|
+
}
|
|
536
|
+
/**
|
|
537
|
+
* Lists all Firefox Relay email aliases.
|
|
538
|
+
*
|
|
539
|
+
* @returns Promise resolving to an array of RelayAlias objects
|
|
540
|
+
* @throws AuthError if authentication fails
|
|
541
|
+
* @throws NetworkError if there's a network problem
|
|
542
|
+
*/
|
|
543
|
+
async listAliases() {
|
|
544
|
+
return this.relayApi.getAliases();
|
|
545
|
+
}
|
|
546
|
+
/**
|
|
547
|
+
* Creates a new Firefox Relay email alias.
|
|
548
|
+
*
|
|
549
|
+
* @returns Promise resolving to the newly created RelayAlias
|
|
550
|
+
* @throws AuthError if authentication fails
|
|
551
|
+
* @throws NetworkError if there's a network problem
|
|
552
|
+
*/
|
|
553
|
+
async createAlias() {
|
|
554
|
+
return this.relayApi.createAlias();
|
|
555
|
+
}
|
|
556
|
+
/**
|
|
557
|
+
* Deletes a Firefox Relay email alias.
|
|
558
|
+
*
|
|
559
|
+
* @param id - The ID of the alias to delete
|
|
560
|
+
* @throws AuthError if authentication fails
|
|
561
|
+
* @throws NotFoundError if the alias doesn't exist
|
|
562
|
+
* @throws NetworkError if there's a network problem
|
|
563
|
+
*/
|
|
564
|
+
async deleteAlias(id) {
|
|
565
|
+
return this.relayApi.deleteAlias(id);
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* Retrieves and parses emails from the CloudFlare temp email API.
|
|
569
|
+
*
|
|
570
|
+
* If aliasAddress is provided, only emails sent to that address are returned.
|
|
571
|
+
*
|
|
572
|
+
* @param aliasAddress - Optional email address to filter by
|
|
573
|
+
* @param options - Query options for pagination
|
|
574
|
+
* @returns Promise resolving to an array of ParsedEmail objects
|
|
575
|
+
* @throws AuthError if authentication fails
|
|
576
|
+
* @throws NetworkError if there's a network problem
|
|
577
|
+
*/
|
|
578
|
+
async getEmails(aliasAddress, options) {
|
|
579
|
+
const limit = options?.limit ?? 20;
|
|
580
|
+
const offset = options?.offset ?? 0;
|
|
581
|
+
const emails = await this.cfApi.getMails(limit, offset);
|
|
582
|
+
const parsedEmails = emails.map((email) => {
|
|
583
|
+
const parsed = this.parser.parseEmail(email.raw);
|
|
584
|
+
return {
|
|
585
|
+
...parsed,
|
|
586
|
+
id: email.id,
|
|
587
|
+
messageId: email.messageId,
|
|
588
|
+
source: email.source,
|
|
589
|
+
address: email.address,
|
|
590
|
+
createdAt: email.createdAt,
|
|
591
|
+
metadata: email.metadata
|
|
592
|
+
};
|
|
593
|
+
});
|
|
594
|
+
if (aliasAddress) {
|
|
595
|
+
const normalizedAlias = aliasAddress.toLowerCase();
|
|
596
|
+
return parsedEmails.filter(
|
|
597
|
+
(email) => email.relayAlias?.toLowerCase() === normalizedAlias
|
|
598
|
+
);
|
|
599
|
+
}
|
|
600
|
+
return parsedEmails;
|
|
601
|
+
}
|
|
602
|
+
};
|
|
603
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
604
|
+
0 && (module.exports = {
|
|
605
|
+
AuthError,
|
|
606
|
+
NetworkError,
|
|
607
|
+
NotFoundError,
|
|
608
|
+
ParseError,
|
|
609
|
+
RateLimitError,
|
|
610
|
+
RelayClient,
|
|
611
|
+
RelayTempMailError
|
|
612
|
+
});
|
|
613
|
+
//# sourceMappingURL=index.cjs.map
|