retransmit.dev 0.1.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 +80 -0
- package/dist/index.cjs +163 -0
- package/dist/index.d.cts +105 -0
- package/dist/index.d.ts +105 -0
- package/dist/index.js +133 -0
- package/package.json +54 -0
package/README.md
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# retransmit.dev
|
|
2
|
+
|
|
3
|
+
Node.js SDK for the [Retransmit](https://retransmit.dev) email API. Zero dependencies, works on Node 18+ and edge runtimes with `fetch`.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install retransmit.dev
|
|
9
|
+
# or
|
|
10
|
+
pnpm add retransmit.dev
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
Grab an API key from your Retransmit dashboard, then:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { Retransmit } from "retransmit.dev";
|
|
19
|
+
|
|
20
|
+
const retransmit = new Retransmit("rt_xxxxxxxxxxxx");
|
|
21
|
+
// or set RETRANSMIT_API_KEY and call `new Retransmit()`
|
|
22
|
+
|
|
23
|
+
const { data, error } = await retransmit.emails.send({
|
|
24
|
+
from: "Acme <hello@yourdomain.com>",
|
|
25
|
+
to: "user@example.com",
|
|
26
|
+
subject: "Hello from Retransmit",
|
|
27
|
+
html: "<p>It works!</p>",
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
if (error) {
|
|
31
|
+
console.error(error.code, error.message);
|
|
32
|
+
} else {
|
|
33
|
+
console.log(data.id); // em_xxxxxxxxxxxx
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Emails are queued and sent asynchronously. Check the outcome later:
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
const { data } = await retransmit.emails.get("em_xxxxxxxxxxxx");
|
|
41
|
+
console.log(data?.status); // "delivered"
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Batches
|
|
45
|
+
|
|
46
|
+
Send up to 10,000 emails in one request:
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
const { data: batch } = await retransmit.batch.send([
|
|
50
|
+
{ from: "Acme <hello@yourdomain.com>", to: "a@example.com", subject: "Hi", text: "Hello A" },
|
|
51
|
+
{ from: "Acme <hello@yourdomain.com>", to: "b@example.com", subject: "Hi", text: "Hello B" },
|
|
52
|
+
]);
|
|
53
|
+
|
|
54
|
+
const { data: progress } = await retransmit.batch.get(batch!.id);
|
|
55
|
+
console.log(progress?.processed, "/", progress?.total, progress?.counts);
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Error handling
|
|
59
|
+
|
|
60
|
+
Methods never throw on API errors — they return `{ data, error }`:
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
const { data, error } = await retransmit.emails.send(/* ... */);
|
|
64
|
+
if (error) {
|
|
65
|
+
// error.code: "validation_error" | "domain_not_verified" | "unauthorized" | ...
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Only constructing the client without an API key throws.
|
|
70
|
+
|
|
71
|
+
## Configuration
|
|
72
|
+
|
|
73
|
+
| Option | Env var | Default |
|
|
74
|
+
| --- | --- | --- |
|
|
75
|
+
| `apiKey` (first argument) | `RETRANSMIT_API_KEY` | — (required) |
|
|
76
|
+
| `baseUrl` | `RETRANSMIT_BASE_URL` | `https://api.retransmit.dev` |
|
|
77
|
+
|
|
78
|
+
## License
|
|
79
|
+
|
|
80
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
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
|
+
Batch: () => Batch,
|
|
24
|
+
EMAIL_STATUSES: () => EMAIL_STATUSES,
|
|
25
|
+
Emails: () => Emails,
|
|
26
|
+
Retransmit: () => Retransmit
|
|
27
|
+
});
|
|
28
|
+
module.exports = __toCommonJS(index_exports);
|
|
29
|
+
|
|
30
|
+
// src/emails.ts
|
|
31
|
+
function toWirePayload(options) {
|
|
32
|
+
return {
|
|
33
|
+
from: options.from,
|
|
34
|
+
to: options.to,
|
|
35
|
+
cc: options.cc,
|
|
36
|
+
bcc: options.bcc,
|
|
37
|
+
reply_to: options.replyTo,
|
|
38
|
+
subject: options.subject,
|
|
39
|
+
html: options.html,
|
|
40
|
+
text: options.text
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
var Emails = class {
|
|
44
|
+
constructor(client) {
|
|
45
|
+
this.client = client;
|
|
46
|
+
}
|
|
47
|
+
client;
|
|
48
|
+
/** Queues a single email. Poll `get(id)` or subscribe to webhooks for the outcome. */
|
|
49
|
+
send(options) {
|
|
50
|
+
return this.client.request("POST", "/v1/emails", toWirePayload(options));
|
|
51
|
+
}
|
|
52
|
+
/** Retrieves an email with its current status and event history. */
|
|
53
|
+
get(id) {
|
|
54
|
+
return this.client.request("GET", `/v1/emails/${encodeURIComponent(id)}`);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// src/batch.ts
|
|
59
|
+
var Batch = class {
|
|
60
|
+
constructor(client) {
|
|
61
|
+
this.client = client;
|
|
62
|
+
}
|
|
63
|
+
client;
|
|
64
|
+
/** Queues up to 10,000 emails in one request. Track progress with `get(id)`. */
|
|
65
|
+
send(emails) {
|
|
66
|
+
return this.client.request("POST", "/v1/emails/batch", {
|
|
67
|
+
emails: emails.map(toWirePayload)
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
/** Batch progress: how many emails are in each status so far. */
|
|
71
|
+
get(id) {
|
|
72
|
+
return this.client.request("GET", `/v1/emails/batch/${encodeURIComponent(id)}`);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// src/retransmit.ts
|
|
77
|
+
var DEFAULT_BASE_URL = "https://api.retransmit.dev";
|
|
78
|
+
var USER_AGENT = "retransmit.dev-node/0.1.0";
|
|
79
|
+
function readEnv(name) {
|
|
80
|
+
return typeof process !== "undefined" ? process.env?.[name] : void 0;
|
|
81
|
+
}
|
|
82
|
+
var Retransmit = class {
|
|
83
|
+
emails = new Emails(this);
|
|
84
|
+
batch = new Batch(this);
|
|
85
|
+
apiKey;
|
|
86
|
+
baseUrl;
|
|
87
|
+
constructor(apiKey, options = {}) {
|
|
88
|
+
const key = apiKey ?? readEnv("RETRANSMIT_API_KEY");
|
|
89
|
+
if (!key) {
|
|
90
|
+
throw new Error(
|
|
91
|
+
'Missing API key. Pass it to `new Retransmit("rt_...")` or set the RETRANSMIT_API_KEY environment variable.'
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
this.apiKey = key;
|
|
95
|
+
this.baseUrl = (options.baseUrl ?? readEnv("RETRANSMIT_BASE_URL") ?? DEFAULT_BASE_URL).replace(
|
|
96
|
+
/\/+$/,
|
|
97
|
+
""
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
/** Internal transport shared by the resource classes. API failures are returned, never thrown. */
|
|
101
|
+
async request(method, path, body) {
|
|
102
|
+
let response;
|
|
103
|
+
try {
|
|
104
|
+
response = await fetch(`${this.baseUrl}${path}`, {
|
|
105
|
+
method,
|
|
106
|
+
headers: {
|
|
107
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
108
|
+
"Content-Type": "application/json",
|
|
109
|
+
"User-Agent": USER_AGENT
|
|
110
|
+
},
|
|
111
|
+
body: body === void 0 ? void 0 : JSON.stringify(body)
|
|
112
|
+
});
|
|
113
|
+
} catch (cause) {
|
|
114
|
+
return {
|
|
115
|
+
data: null,
|
|
116
|
+
error: {
|
|
117
|
+
code: "network_error",
|
|
118
|
+
message: cause instanceof Error ? cause.message : "Unable to reach the Retransmit API"
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
let json = null;
|
|
123
|
+
try {
|
|
124
|
+
json = await response.json();
|
|
125
|
+
} catch {
|
|
126
|
+
}
|
|
127
|
+
if (!response.ok) {
|
|
128
|
+
const error = json?.error;
|
|
129
|
+
return {
|
|
130
|
+
data: null,
|
|
131
|
+
error: error ?? {
|
|
132
|
+
code: "internal_error",
|
|
133
|
+
message: `Request failed with status ${response.status}`
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
return { data: json, error: null };
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
// src/types.ts
|
|
142
|
+
var EMAIL_STATUSES = [
|
|
143
|
+
"queued",
|
|
144
|
+
"scheduled",
|
|
145
|
+
"sent",
|
|
146
|
+
"delivery_delayed",
|
|
147
|
+
"delivered",
|
|
148
|
+
"opened",
|
|
149
|
+
"clicked",
|
|
150
|
+
"bounced",
|
|
151
|
+
"complained",
|
|
152
|
+
"suppressed",
|
|
153
|
+
"canceled",
|
|
154
|
+
"rejected",
|
|
155
|
+
"failed"
|
|
156
|
+
];
|
|
157
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
158
|
+
0 && (module.exports = {
|
|
159
|
+
Batch,
|
|
160
|
+
EMAIL_STATUSES,
|
|
161
|
+
Emails,
|
|
162
|
+
Retransmit
|
|
163
|
+
});
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Response and payload types mirror the public API wire format
|
|
3
|
+
* (snake_case fields, ISO 8601 timestamps). Kept standalone on purpose:
|
|
4
|
+
* this package is published to npm and cannot import workspace packages.
|
|
5
|
+
*/
|
|
6
|
+
declare const EMAIL_STATUSES: readonly ["queued", "scheduled", "sent", "delivery_delayed", "delivered", "opened", "clicked", "bounced", "complained", "suppressed", "canceled", "rejected", "failed"];
|
|
7
|
+
type EmailStatus = (typeof EMAIL_STATUSES)[number];
|
|
8
|
+
interface RetransmitError {
|
|
9
|
+
code: string;
|
|
10
|
+
message: string;
|
|
11
|
+
}
|
|
12
|
+
type Result<T> = {
|
|
13
|
+
data: T;
|
|
14
|
+
error: null;
|
|
15
|
+
} | {
|
|
16
|
+
data: null;
|
|
17
|
+
error: RetransmitError;
|
|
18
|
+
};
|
|
19
|
+
interface RetransmitOptions {
|
|
20
|
+
/** Override the API origin. Defaults to `https://api.retransmit.dev` (or `RETRANSMIT_BASE_URL`). */
|
|
21
|
+
baseUrl?: string;
|
|
22
|
+
}
|
|
23
|
+
interface SendEmailOptions {
|
|
24
|
+
/** Sender, as `address@domain.com` or `Name <address@domain.com>`. The domain must be verified on your account. */
|
|
25
|
+
from: string;
|
|
26
|
+
/** One recipient or up to 50. */
|
|
27
|
+
to: string | string[];
|
|
28
|
+
cc?: string | string[];
|
|
29
|
+
bcc?: string | string[];
|
|
30
|
+
replyTo?: string | string[];
|
|
31
|
+
subject: string;
|
|
32
|
+
/** HTML body. At least one of `html` or `text` is required. */
|
|
33
|
+
html?: string;
|
|
34
|
+
/** Plain-text body. At least one of `html` or `text` is required. */
|
|
35
|
+
text?: string;
|
|
36
|
+
}
|
|
37
|
+
interface SendEmailResponse {
|
|
38
|
+
id: string;
|
|
39
|
+
status: "queued";
|
|
40
|
+
created_at: string;
|
|
41
|
+
}
|
|
42
|
+
interface EmailEvent {
|
|
43
|
+
type: string;
|
|
44
|
+
created_at: string;
|
|
45
|
+
}
|
|
46
|
+
interface GetEmailResponse {
|
|
47
|
+
id: string;
|
|
48
|
+
batch_id: string | null;
|
|
49
|
+
from: string;
|
|
50
|
+
to: string[];
|
|
51
|
+
cc: string[] | null;
|
|
52
|
+
bcc: string[] | null;
|
|
53
|
+
reply_to: string[] | null;
|
|
54
|
+
subject: string;
|
|
55
|
+
status: EmailStatus;
|
|
56
|
+
error: string | null;
|
|
57
|
+
created_at: string;
|
|
58
|
+
last_event_at: string | null;
|
|
59
|
+
events: EmailEvent[];
|
|
60
|
+
}
|
|
61
|
+
interface SendBatchResponse {
|
|
62
|
+
id: string;
|
|
63
|
+
total: number;
|
|
64
|
+
status: "queued";
|
|
65
|
+
created_at: string;
|
|
66
|
+
}
|
|
67
|
+
interface GetBatchResponse {
|
|
68
|
+
id: string;
|
|
69
|
+
total: number;
|
|
70
|
+
/** Emails that have left the queue (any status other than `queued`/`scheduled`). */
|
|
71
|
+
processed: number;
|
|
72
|
+
/** Email count per status, e.g. `{ queued: 4, delivered: 96 }`. */
|
|
73
|
+
counts: Partial<Record<EmailStatus, number>>;
|
|
74
|
+
created_at: string;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
declare class Batch {
|
|
78
|
+
private readonly client;
|
|
79
|
+
constructor(client: Retransmit);
|
|
80
|
+
/** Queues up to 10,000 emails in one request. Track progress with `get(id)`. */
|
|
81
|
+
send(emails: SendEmailOptions[]): Promise<Result<SendBatchResponse>>;
|
|
82
|
+
/** Batch progress: how many emails are in each status so far. */
|
|
83
|
+
get(id: string): Promise<Result<GetBatchResponse>>;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
declare class Emails {
|
|
87
|
+
private readonly client;
|
|
88
|
+
constructor(client: Retransmit);
|
|
89
|
+
/** Queues a single email. Poll `get(id)` or subscribe to webhooks for the outcome. */
|
|
90
|
+
send(options: SendEmailOptions): Promise<Result<SendEmailResponse>>;
|
|
91
|
+
/** Retrieves an email with its current status and event history. */
|
|
92
|
+
get(id: string): Promise<Result<GetEmailResponse>>;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
declare class Retransmit {
|
|
96
|
+
readonly emails: Emails;
|
|
97
|
+
readonly batch: Batch;
|
|
98
|
+
private readonly apiKey;
|
|
99
|
+
private readonly baseUrl;
|
|
100
|
+
constructor(apiKey?: string, options?: RetransmitOptions);
|
|
101
|
+
/** Internal transport shared by the resource classes. API failures are returned, never thrown. */
|
|
102
|
+
request<T>(method: "GET" | "POST", path: string, body?: unknown): Promise<Result<T>>;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export { Batch, EMAIL_STATUSES, type EmailEvent, type EmailStatus, Emails, type GetBatchResponse, type GetEmailResponse, type Result, Retransmit, type RetransmitError, type RetransmitOptions, type SendBatchResponse, type SendEmailOptions, type SendEmailResponse };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Response and payload types mirror the public API wire format
|
|
3
|
+
* (snake_case fields, ISO 8601 timestamps). Kept standalone on purpose:
|
|
4
|
+
* this package is published to npm and cannot import workspace packages.
|
|
5
|
+
*/
|
|
6
|
+
declare const EMAIL_STATUSES: readonly ["queued", "scheduled", "sent", "delivery_delayed", "delivered", "opened", "clicked", "bounced", "complained", "suppressed", "canceled", "rejected", "failed"];
|
|
7
|
+
type EmailStatus = (typeof EMAIL_STATUSES)[number];
|
|
8
|
+
interface RetransmitError {
|
|
9
|
+
code: string;
|
|
10
|
+
message: string;
|
|
11
|
+
}
|
|
12
|
+
type Result<T> = {
|
|
13
|
+
data: T;
|
|
14
|
+
error: null;
|
|
15
|
+
} | {
|
|
16
|
+
data: null;
|
|
17
|
+
error: RetransmitError;
|
|
18
|
+
};
|
|
19
|
+
interface RetransmitOptions {
|
|
20
|
+
/** Override the API origin. Defaults to `https://api.retransmit.dev` (or `RETRANSMIT_BASE_URL`). */
|
|
21
|
+
baseUrl?: string;
|
|
22
|
+
}
|
|
23
|
+
interface SendEmailOptions {
|
|
24
|
+
/** Sender, as `address@domain.com` or `Name <address@domain.com>`. The domain must be verified on your account. */
|
|
25
|
+
from: string;
|
|
26
|
+
/** One recipient or up to 50. */
|
|
27
|
+
to: string | string[];
|
|
28
|
+
cc?: string | string[];
|
|
29
|
+
bcc?: string | string[];
|
|
30
|
+
replyTo?: string | string[];
|
|
31
|
+
subject: string;
|
|
32
|
+
/** HTML body. At least one of `html` or `text` is required. */
|
|
33
|
+
html?: string;
|
|
34
|
+
/** Plain-text body. At least one of `html` or `text` is required. */
|
|
35
|
+
text?: string;
|
|
36
|
+
}
|
|
37
|
+
interface SendEmailResponse {
|
|
38
|
+
id: string;
|
|
39
|
+
status: "queued";
|
|
40
|
+
created_at: string;
|
|
41
|
+
}
|
|
42
|
+
interface EmailEvent {
|
|
43
|
+
type: string;
|
|
44
|
+
created_at: string;
|
|
45
|
+
}
|
|
46
|
+
interface GetEmailResponse {
|
|
47
|
+
id: string;
|
|
48
|
+
batch_id: string | null;
|
|
49
|
+
from: string;
|
|
50
|
+
to: string[];
|
|
51
|
+
cc: string[] | null;
|
|
52
|
+
bcc: string[] | null;
|
|
53
|
+
reply_to: string[] | null;
|
|
54
|
+
subject: string;
|
|
55
|
+
status: EmailStatus;
|
|
56
|
+
error: string | null;
|
|
57
|
+
created_at: string;
|
|
58
|
+
last_event_at: string | null;
|
|
59
|
+
events: EmailEvent[];
|
|
60
|
+
}
|
|
61
|
+
interface SendBatchResponse {
|
|
62
|
+
id: string;
|
|
63
|
+
total: number;
|
|
64
|
+
status: "queued";
|
|
65
|
+
created_at: string;
|
|
66
|
+
}
|
|
67
|
+
interface GetBatchResponse {
|
|
68
|
+
id: string;
|
|
69
|
+
total: number;
|
|
70
|
+
/** Emails that have left the queue (any status other than `queued`/`scheduled`). */
|
|
71
|
+
processed: number;
|
|
72
|
+
/** Email count per status, e.g. `{ queued: 4, delivered: 96 }`. */
|
|
73
|
+
counts: Partial<Record<EmailStatus, number>>;
|
|
74
|
+
created_at: string;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
declare class Batch {
|
|
78
|
+
private readonly client;
|
|
79
|
+
constructor(client: Retransmit);
|
|
80
|
+
/** Queues up to 10,000 emails in one request. Track progress with `get(id)`. */
|
|
81
|
+
send(emails: SendEmailOptions[]): Promise<Result<SendBatchResponse>>;
|
|
82
|
+
/** Batch progress: how many emails are in each status so far. */
|
|
83
|
+
get(id: string): Promise<Result<GetBatchResponse>>;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
declare class Emails {
|
|
87
|
+
private readonly client;
|
|
88
|
+
constructor(client: Retransmit);
|
|
89
|
+
/** Queues a single email. Poll `get(id)` or subscribe to webhooks for the outcome. */
|
|
90
|
+
send(options: SendEmailOptions): Promise<Result<SendEmailResponse>>;
|
|
91
|
+
/** Retrieves an email with its current status and event history. */
|
|
92
|
+
get(id: string): Promise<Result<GetEmailResponse>>;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
declare class Retransmit {
|
|
96
|
+
readonly emails: Emails;
|
|
97
|
+
readonly batch: Batch;
|
|
98
|
+
private readonly apiKey;
|
|
99
|
+
private readonly baseUrl;
|
|
100
|
+
constructor(apiKey?: string, options?: RetransmitOptions);
|
|
101
|
+
/** Internal transport shared by the resource classes. API failures are returned, never thrown. */
|
|
102
|
+
request<T>(method: "GET" | "POST", path: string, body?: unknown): Promise<Result<T>>;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export { Batch, EMAIL_STATUSES, type EmailEvent, type EmailStatus, Emails, type GetBatchResponse, type GetEmailResponse, type Result, Retransmit, type RetransmitError, type RetransmitOptions, type SendBatchResponse, type SendEmailOptions, type SendEmailResponse };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
// src/emails.ts
|
|
2
|
+
function toWirePayload(options) {
|
|
3
|
+
return {
|
|
4
|
+
from: options.from,
|
|
5
|
+
to: options.to,
|
|
6
|
+
cc: options.cc,
|
|
7
|
+
bcc: options.bcc,
|
|
8
|
+
reply_to: options.replyTo,
|
|
9
|
+
subject: options.subject,
|
|
10
|
+
html: options.html,
|
|
11
|
+
text: options.text
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
var Emails = class {
|
|
15
|
+
constructor(client) {
|
|
16
|
+
this.client = client;
|
|
17
|
+
}
|
|
18
|
+
client;
|
|
19
|
+
/** Queues a single email. Poll `get(id)` or subscribe to webhooks for the outcome. */
|
|
20
|
+
send(options) {
|
|
21
|
+
return this.client.request("POST", "/v1/emails", toWirePayload(options));
|
|
22
|
+
}
|
|
23
|
+
/** Retrieves an email with its current status and event history. */
|
|
24
|
+
get(id) {
|
|
25
|
+
return this.client.request("GET", `/v1/emails/${encodeURIComponent(id)}`);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// src/batch.ts
|
|
30
|
+
var Batch = class {
|
|
31
|
+
constructor(client) {
|
|
32
|
+
this.client = client;
|
|
33
|
+
}
|
|
34
|
+
client;
|
|
35
|
+
/** Queues up to 10,000 emails in one request. Track progress with `get(id)`. */
|
|
36
|
+
send(emails) {
|
|
37
|
+
return this.client.request("POST", "/v1/emails/batch", {
|
|
38
|
+
emails: emails.map(toWirePayload)
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
/** Batch progress: how many emails are in each status so far. */
|
|
42
|
+
get(id) {
|
|
43
|
+
return this.client.request("GET", `/v1/emails/batch/${encodeURIComponent(id)}`);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// src/retransmit.ts
|
|
48
|
+
var DEFAULT_BASE_URL = "https://api.retransmit.dev";
|
|
49
|
+
var USER_AGENT = "retransmit.dev-node/0.1.0";
|
|
50
|
+
function readEnv(name) {
|
|
51
|
+
return typeof process !== "undefined" ? process.env?.[name] : void 0;
|
|
52
|
+
}
|
|
53
|
+
var Retransmit = class {
|
|
54
|
+
emails = new Emails(this);
|
|
55
|
+
batch = new Batch(this);
|
|
56
|
+
apiKey;
|
|
57
|
+
baseUrl;
|
|
58
|
+
constructor(apiKey, options = {}) {
|
|
59
|
+
const key = apiKey ?? readEnv("RETRANSMIT_API_KEY");
|
|
60
|
+
if (!key) {
|
|
61
|
+
throw new Error(
|
|
62
|
+
'Missing API key. Pass it to `new Retransmit("rt_...")` or set the RETRANSMIT_API_KEY environment variable.'
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
this.apiKey = key;
|
|
66
|
+
this.baseUrl = (options.baseUrl ?? readEnv("RETRANSMIT_BASE_URL") ?? DEFAULT_BASE_URL).replace(
|
|
67
|
+
/\/+$/,
|
|
68
|
+
""
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
/** Internal transport shared by the resource classes. API failures are returned, never thrown. */
|
|
72
|
+
async request(method, path, body) {
|
|
73
|
+
let response;
|
|
74
|
+
try {
|
|
75
|
+
response = await fetch(`${this.baseUrl}${path}`, {
|
|
76
|
+
method,
|
|
77
|
+
headers: {
|
|
78
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
79
|
+
"Content-Type": "application/json",
|
|
80
|
+
"User-Agent": USER_AGENT
|
|
81
|
+
},
|
|
82
|
+
body: body === void 0 ? void 0 : JSON.stringify(body)
|
|
83
|
+
});
|
|
84
|
+
} catch (cause) {
|
|
85
|
+
return {
|
|
86
|
+
data: null,
|
|
87
|
+
error: {
|
|
88
|
+
code: "network_error",
|
|
89
|
+
message: cause instanceof Error ? cause.message : "Unable to reach the Retransmit API"
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
let json = null;
|
|
94
|
+
try {
|
|
95
|
+
json = await response.json();
|
|
96
|
+
} catch {
|
|
97
|
+
}
|
|
98
|
+
if (!response.ok) {
|
|
99
|
+
const error = json?.error;
|
|
100
|
+
return {
|
|
101
|
+
data: null,
|
|
102
|
+
error: error ?? {
|
|
103
|
+
code: "internal_error",
|
|
104
|
+
message: `Request failed with status ${response.status}`
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
return { data: json, error: null };
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
// src/types.ts
|
|
113
|
+
var EMAIL_STATUSES = [
|
|
114
|
+
"queued",
|
|
115
|
+
"scheduled",
|
|
116
|
+
"sent",
|
|
117
|
+
"delivery_delayed",
|
|
118
|
+
"delivered",
|
|
119
|
+
"opened",
|
|
120
|
+
"clicked",
|
|
121
|
+
"bounced",
|
|
122
|
+
"complained",
|
|
123
|
+
"suppressed",
|
|
124
|
+
"canceled",
|
|
125
|
+
"rejected",
|
|
126
|
+
"failed"
|
|
127
|
+
];
|
|
128
|
+
export {
|
|
129
|
+
Batch,
|
|
130
|
+
EMAIL_STATUSES,
|
|
131
|
+
Emails,
|
|
132
|
+
Retransmit
|
|
133
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "retransmit.dev",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Node.js SDK for the Retransmit email API",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"email",
|
|
7
|
+
"retransmit",
|
|
8
|
+
"ses",
|
|
9
|
+
"transactional-email"
|
|
10
|
+
],
|
|
11
|
+
"homepage": "https://retransmit.dev/docs",
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://github.com/jpainam/retransmit.git",
|
|
15
|
+
"directory": "packages/sdk"
|
|
16
|
+
},
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"type": "module",
|
|
19
|
+
"sideEffects": false,
|
|
20
|
+
"main": "./dist/index.cjs",
|
|
21
|
+
"module": "./dist/index.js",
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"exports": {
|
|
24
|
+
".": {
|
|
25
|
+
"import": {
|
|
26
|
+
"types": "./dist/index.d.ts",
|
|
27
|
+
"default": "./dist/index.js"
|
|
28
|
+
},
|
|
29
|
+
"require": {
|
|
30
|
+
"types": "./dist/index.d.cts",
|
|
31
|
+
"default": "./dist/index.cjs"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"files": [
|
|
36
|
+
"dist"
|
|
37
|
+
],
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/node": "^26.2.0",
|
|
40
|
+
"tsup": "^8.5.0",
|
|
41
|
+
"typescript": "^6.0.3",
|
|
42
|
+
"@retransmit/config": "0.0.0"
|
|
43
|
+
},
|
|
44
|
+
"publishConfig": {
|
|
45
|
+
"access": "public"
|
|
46
|
+
},
|
|
47
|
+
"engines": {
|
|
48
|
+
"node": ">=18"
|
|
49
|
+
},
|
|
50
|
+
"scripts": {
|
|
51
|
+
"build": "tsup src/index.ts --format esm,cjs --dts --clean",
|
|
52
|
+
"check-types": "tsc --noEmit"
|
|
53
|
+
}
|
|
54
|
+
}
|