mailtruss 0.0.0-stage → 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/LICENSE ADDED
@@ -0,0 +1,9 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mailtruss
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,26 @@
1
- # Temporary Holding Version
1
+ # mailtruss
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Official TypeScript and JavaScript client for the [Mailtruss](https://mailtruss.com) email API. No dependencies. Node 18+, Bun, Deno and edge runtimes (it uses `fetch`).
4
+
5
+ ```bash
6
+ npm install mailtruss
7
+ ```
8
+
9
+ ```ts
10
+ import { MailClient } from "mailtruss";
11
+
12
+ const mail = new MailClient({ apiKey: process.env.MAILTRUSS_API_KEY! });
13
+
14
+ const { id } = await mail.emails.send(
15
+ { from: "Ada <ada@yourdomain.com>", to: "you@example.com", subject: "Hello", html: "<p>It works.</p>" },
16
+ { idempotencyKey: "order-42" }, // makes retries safe
17
+ );
18
+ ```
19
+
20
+ Covers every resource of the API: `emails`, `domains`, `apiKeys`, `contacts`, `segments`, `topics`, `templates`, `broadcasts`, `suppressions`, `webhooks`, `logs`. The machine-readable description is at `https://mailtruss.com/api/v1/openapi.json`.
21
+
22
+ - Errors are `MailError` with `statusCode`, `name_` and `requestId` (search it in the dashboard's API logs).
23
+ - A send is retried only when you pass an `idempotencyKey`; reads and deletes retry on 429 and 5xx.
24
+ - Base address: `baseUrl` option, then `MAILTRUSS_API_URL`, then `https://mailtruss.com`.
25
+
26
+ MIT licensed. Documentation: https://mailtruss.com/docs
@@ -0,0 +1,427 @@
1
+ export type EmailAddress = string;
2
+ export type Tag = {
3
+ name: string;
4
+ value: string;
5
+ };
6
+ export type Attachment = {
7
+ filename: string;
8
+ content?: string;
9
+ path?: string;
10
+ content_type?: string;
11
+ content_id?: string;
12
+ };
13
+ export type SendEmailParams = {
14
+ from: string;
15
+ to: string | string[];
16
+ subject?: string;
17
+ html?: string;
18
+ text?: string;
19
+ cc?: string | string[];
20
+ bcc?: string | string[];
21
+ reply_to?: string | string[];
22
+ headers?: Record<string, string>;
23
+ attachments?: Attachment[];
24
+ tags?: Tag[];
25
+ /** ISO 8601, up to 30 days ahead. */
26
+ scheduled_at?: string;
27
+ template?: {
28
+ id: string;
29
+ variables?: Record<string, unknown>;
30
+ };
31
+ };
32
+ export type Email = {
33
+ object: "email";
34
+ id: string;
35
+ to: string[];
36
+ from: string;
37
+ created_at: string;
38
+ subject: string;
39
+ html: string | null;
40
+ text: string | null;
41
+ bcc: string[];
42
+ cc: string[];
43
+ reply_to: string[];
44
+ last_event: string;
45
+ scheduled_at: string | null;
46
+ tags: Tag[];
47
+ };
48
+ export type Contact = {
49
+ object: "contact";
50
+ id: string;
51
+ email: string;
52
+ first_name: string | null;
53
+ last_name: string | null;
54
+ tags: string[];
55
+ unsubscribed: boolean;
56
+ created_at: string;
57
+ };
58
+ export type PagedList<T> = {
59
+ object: "list";
60
+ page: number;
61
+ total: number;
62
+ has_more: boolean;
63
+ data: T[];
64
+ };
65
+ export type List<T> = {
66
+ object: "list";
67
+ has_more: boolean;
68
+ data: T[];
69
+ };
70
+ export type ClientOptions = {
71
+ apiKey: string;
72
+ /** Defaults to the MAILTRUSS_API_URL environment variable, then https://mailtruss.com. */
73
+ baseUrl?: string;
74
+ /** Per-request timeout in ms (default 30000). */
75
+ timeoutMs?: number;
76
+ /** Retries are only attempted for 429/5xx when an idempotency key makes the request safe to repeat. */
77
+ maxRetries?: number;
78
+ fetch?: typeof fetch;
79
+ };
80
+ export type RequestOptions = {
81
+ idempotencyKey?: string;
82
+ signal?: AbortSignal;
83
+ };
84
+ /** Thrown for every non-2xx response. `requestId` can be searched in the dashboard's API logs. */
85
+ export declare class MailError extends Error {
86
+ readonly statusCode: number;
87
+ readonly name_: string;
88
+ readonly requestId: string | null;
89
+ readonly retryAfterSeconds?: number | undefined;
90
+ constructor(statusCode: number, name_: string, message: string, requestId: string | null, retryAfterSeconds?: number | undefined);
91
+ get code(): string;
92
+ }
93
+ export declare class MailTimeoutError extends Error {
94
+ constructor(ms: number);
95
+ }
96
+ export declare class MailClient {
97
+ private readonly o;
98
+ constructor(options: ClientOptions);
99
+ private request;
100
+ readonly emails: {
101
+ send: (p: SendEmailParams, o?: RequestOptions) => Promise<{
102
+ id: string;
103
+ }>;
104
+ batch: (p: SendEmailParams[], o?: RequestOptions) => Promise<{
105
+ data: {
106
+ id: string;
107
+ }[];
108
+ }>;
109
+ get: (id: string, o?: RequestOptions) => Promise<Email>;
110
+ list: (q?: {
111
+ limit?: number;
112
+ after?: string;
113
+ }, o?: RequestOptions) => Promise<List<Email>>;
114
+ reschedule: (id: string, scheduled_at: string, o?: RequestOptions) => Promise<{
115
+ id: string;
116
+ }>;
117
+ cancel: (id: string, o?: RequestOptions) => Promise<{
118
+ id: string;
119
+ }>;
120
+ };
121
+ readonly domains: {
122
+ create: (p: {
123
+ name: string;
124
+ region?: string;
125
+ mail_from_subdomain?: string;
126
+ }, o?: RequestOptions) => Promise<{
127
+ id: string;
128
+ name: string;
129
+ status: string;
130
+ records: {
131
+ record: string;
132
+ name: string;
133
+ type: string;
134
+ value: string;
135
+ status: string;
136
+ }[];
137
+ }>;
138
+ list: (o?: RequestOptions) => Promise<List<{
139
+ id: string;
140
+ name: string;
141
+ status: string;
142
+ }>>;
143
+ verify: (id: string, o?: RequestOptions) => Promise<{
144
+ id: string;
145
+ status: string;
146
+ }>;
147
+ get: (id: string, o?: RequestOptions) => Promise<{
148
+ id: string;
149
+ name: string;
150
+ status: string;
151
+ records: {
152
+ record: string;
153
+ name: string;
154
+ type: string;
155
+ value: string;
156
+ status: string;
157
+ }[];
158
+ }>;
159
+ /** Click and open tracking are off by default. Tell your recipients before turning them on. */
160
+ setTracking: (id: string, p: {
161
+ click_tracking?: boolean;
162
+ open_tracking?: boolean;
163
+ }, o?: RequestOptions) => Promise<{
164
+ id: string;
165
+ click_tracking: boolean;
166
+ open_tracking: boolean;
167
+ }>;
168
+ remove: (id: string, o?: RequestOptions) => Promise<{
169
+ id: string;
170
+ deleted: true;
171
+ }>;
172
+ };
173
+ readonly apiKeys: {
174
+ create: (p: {
175
+ name: string;
176
+ permission?: "full_access" | "sending_access";
177
+ domain_id?: string;
178
+ }, o?: RequestOptions) => Promise<{
179
+ id: string;
180
+ token: string;
181
+ }>;
182
+ list: (o?: RequestOptions) => Promise<List<{
183
+ id: string;
184
+ name: string;
185
+ prefix: string;
186
+ }>>;
187
+ remove: (id: string, o?: RequestOptions) => Promise<Record<string, never>>;
188
+ };
189
+ private q;
190
+ private id;
191
+ readonly contacts: {
192
+ create: (p: {
193
+ email: string;
194
+ first_name?: string | null;
195
+ last_name?: string | null;
196
+ tags?: string[];
197
+ properties?: Record<string, string | number | boolean | null>;
198
+ }, o?: RequestOptions) => Promise<{
199
+ id: string;
200
+ created: boolean;
201
+ }>;
202
+ /** `idOrEmail` is the contact id or the email address. */
203
+ get: (idOrEmail: string, o?: RequestOptions) => Promise<Contact & {
204
+ properties: Record<string, unknown>;
205
+ }>;
206
+ list: (q?: {
207
+ q?: string;
208
+ tag?: string;
209
+ status?: "subscribed" | "unsubscribed";
210
+ page?: number;
211
+ limit?: number;
212
+ }, o?: RequestOptions) => Promise<PagedList<Contact>>;
213
+ update: (idOrEmail: string, p: {
214
+ first_name?: string | null;
215
+ last_name?: string | null;
216
+ tags?: string[];
217
+ }, o?: RequestOptions) => Promise<{
218
+ id: string;
219
+ }>;
220
+ remove: (idOrEmail: string, o?: RequestOptions) => Promise<{
221
+ id: string;
222
+ deleted: true;
223
+ }>;
224
+ };
225
+ readonly segments: {
226
+ create: (p: {
227
+ name: string;
228
+ rules: {
229
+ match: "all" | "any";
230
+ conditions: {
231
+ field: string;
232
+ op: string;
233
+ value?: unknown;
234
+ }[];
235
+ };
236
+ }, o?: RequestOptions) => Promise<{
237
+ id: string;
238
+ name: string;
239
+ }>;
240
+ list: (o?: RequestOptions) => Promise<List<{
241
+ id: string;
242
+ name: string;
243
+ size: number | null;
244
+ }>>;
245
+ get: (id: string, o?: RequestOptions) => Promise<{
246
+ id: string;
247
+ name: string;
248
+ size: number | null;
249
+ }>;
250
+ remove: (id: string, o?: RequestOptions) => Promise<{
251
+ id: string;
252
+ deleted: true;
253
+ }>;
254
+ };
255
+ readonly topics: {
256
+ create: (p: {
257
+ name: string;
258
+ description?: string;
259
+ default_subscribed?: boolean;
260
+ }, o?: RequestOptions) => Promise<{
261
+ id: string;
262
+ name: string;
263
+ }>;
264
+ list: (o?: RequestOptions) => Promise<List<{
265
+ id: string;
266
+ name: string;
267
+ }>>;
268
+ };
269
+ readonly suppressions: {
270
+ add: (email: string, o?: RequestOptions) => Promise<{
271
+ email: string;
272
+ created: boolean;
273
+ }>;
274
+ list: (q?: {
275
+ q?: string;
276
+ reason?: "hard_bounce" | "complaint" | "unsubscribe" | "manual";
277
+ page?: number;
278
+ limit?: number;
279
+ }, o?: RequestOptions) => Promise<PagedList<{
280
+ id: string;
281
+ email: string;
282
+ reason: string;
283
+ }>>;
284
+ /** Complaints and unsubscribes cannot be removed (403). `idOrEmail` is the suppression id or the address. */
285
+ remove: (idOrEmail: string, o?: RequestOptions) => Promise<{
286
+ id: string;
287
+ deleted: true;
288
+ }>;
289
+ };
290
+ readonly webhooks: {
291
+ /** The signing secret is returned once, here and from `rotateSecret`. */
292
+ create: (p: {
293
+ url: string;
294
+ events: string[];
295
+ }, o?: RequestOptions) => Promise<{
296
+ id: string;
297
+ signing_secret: string;
298
+ }>;
299
+ list: (o?: RequestOptions) => Promise<List<{
300
+ id: string;
301
+ url: string;
302
+ events: string[];
303
+ enabled: boolean;
304
+ }>>;
305
+ get: (id: string, o?: RequestOptions) => Promise<{
306
+ id: string;
307
+ url: string;
308
+ events: string[];
309
+ enabled: boolean;
310
+ }>;
311
+ update: (id: string, p: {
312
+ url?: string;
313
+ events?: string[];
314
+ enabled?: boolean;
315
+ }, o?: RequestOptions) => Promise<{
316
+ id: string;
317
+ enabled: boolean;
318
+ }>;
319
+ rotateSecret: (id: string, o?: RequestOptions) => Promise<{
320
+ id: string;
321
+ signing_secret: string;
322
+ }>;
323
+ remove: (id: string, o?: RequestOptions) => Promise<{
324
+ id: string;
325
+ deleted: true;
326
+ }>;
327
+ };
328
+ readonly templates: {
329
+ create: (p: {
330
+ name: string;
331
+ subject: string;
332
+ html: string;
333
+ text?: string | null;
334
+ alias?: string;
335
+ publish?: boolean;
336
+ }, o?: RequestOptions) => Promise<{
337
+ id: string;
338
+ version: number;
339
+ published_version: number | null;
340
+ }>;
341
+ list: (o?: RequestOptions) => Promise<List<{
342
+ id: string;
343
+ name: string;
344
+ alias: string | null;
345
+ published_version: number | null;
346
+ }>>;
347
+ get: (id: string, o?: RequestOptions) => Promise<{
348
+ id: string;
349
+ name: string;
350
+ subject: string;
351
+ html: string;
352
+ text: string | null;
353
+ variables: unknown[];
354
+ }>;
355
+ /** Saves a new, unpublished version. */
356
+ update: (id: string, p: {
357
+ name?: string;
358
+ alias?: string | null;
359
+ subject?: string;
360
+ html?: string;
361
+ text?: string | null;
362
+ }, o?: RequestOptions) => Promise<{
363
+ id: string;
364
+ version: number;
365
+ }>;
366
+ publish: (id: string, p?: {
367
+ version?: number;
368
+ }, o?: RequestOptions) => Promise<{
369
+ id: string;
370
+ published_version: number;
371
+ }>;
372
+ remove: (id: string, o?: RequestOptions) => Promise<{
373
+ id: string;
374
+ deleted: true;
375
+ }>;
376
+ };
377
+ readonly broadcasts: {
378
+ /** Creates a draft; nothing is sent until `send`. */
379
+ create: (p: {
380
+ name: string;
381
+ from: string;
382
+ subject: string;
383
+ html: string;
384
+ text?: string | null;
385
+ reply_to?: string | null;
386
+ segment_id?: string | null;
387
+ topic_id?: string | null;
388
+ }, o?: RequestOptions) => Promise<{
389
+ id: string;
390
+ status: string;
391
+ }>;
392
+ list: (o?: RequestOptions) => Promise<List<{
393
+ id: string;
394
+ name: string;
395
+ status: string;
396
+ }>>;
397
+ get: (id: string, o?: RequestOptions) => Promise<{
398
+ id: string;
399
+ status: string;
400
+ stats: unknown;
401
+ }>;
402
+ send: (id: string, p?: {
403
+ scheduled_at?: string | null;
404
+ }, o?: RequestOptions) => Promise<{
405
+ id: string;
406
+ }>;
407
+ cancel: (id: string, o?: RequestOptions) => Promise<{
408
+ id: string;
409
+ }>;
410
+ remove: (id: string, o?: RequestOptions) => Promise<{
411
+ id: string;
412
+ deleted: true;
413
+ }>;
414
+ };
415
+ readonly logs: {
416
+ list: (q?: {
417
+ limit?: number;
418
+ after?: string;
419
+ }, o?: RequestOptions) => Promise<List<{
420
+ id: string;
421
+ request_id: string;
422
+ method: string;
423
+ path: string;
424
+ status_code: number;
425
+ }>>;
426
+ };
427
+ }
package/dist/index.js ADDED
@@ -0,0 +1,151 @@
1
+ /** Thrown for every non-2xx response. `requestId` can be searched in the dashboard's API logs. */
2
+ export class MailError extends Error {
3
+ statusCode;
4
+ name_;
5
+ requestId;
6
+ retryAfterSeconds;
7
+ constructor(statusCode, name_, message, requestId, retryAfterSeconds) {
8
+ super(message);
9
+ this.statusCode = statusCode;
10
+ this.name_ = name_;
11
+ this.requestId = requestId;
12
+ this.retryAfterSeconds = retryAfterSeconds;
13
+ this.name = "MailError";
14
+ }
15
+ get code() { return this.name_; }
16
+ }
17
+ export class MailTimeoutError extends Error {
18
+ constructor(ms) { super(`Request timed out after ${ms}ms. The email may or may not have been accepted; use an idempotency key and retry safely.`); this.name = "MailTimeoutError"; }
19
+ }
20
+ export class MailClient {
21
+ o;
22
+ constructor(options) {
23
+ if (!options.apiKey)
24
+ throw new Error("MailClient: `apiKey` is required");
25
+ this.o = { timeoutMs: 30_000, maxRetries: 2, ...options };
26
+ }
27
+ async request(method, path, body, opts = {}) {
28
+ const base = (this.o.baseUrl ?? (typeof process !== "undefined" ? process.env.MAILTRUSS_API_URL ?? process.env.MAIL_API_URL : undefined) ?? "https://mailtruss.com").replace(/\/$/, "");
29
+ const f = this.o.fetch ?? fetch;
30
+ const retryable = !!opts.idempotencyKey || method === "GET" || method === "DELETE";
31
+ for (let attempt = 0;; attempt++) {
32
+ const ctl = new AbortController();
33
+ const timer = setTimeout(() => ctl.abort(new MailTimeoutError(this.o.timeoutMs)), this.o.timeoutMs);
34
+ opts.signal?.addEventListener("abort", () => ctl.abort(opts.signal.reason), { once: true });
35
+ try {
36
+ const res = await f(`${base}${path}`, {
37
+ method, signal: ctl.signal,
38
+ headers: { Authorization: `Bearer ${this.o.apiKey}`, "Content-Type": "application/json", "User-Agent": "mailtruss-node/0.1.0", ...(opts.idempotencyKey ? { "Idempotency-Key": opts.idempotencyKey } : {}) },
39
+ body: body === undefined ? undefined : JSON.stringify(body),
40
+ });
41
+ const json = (await res.json().catch(() => null));
42
+ if (res.ok)
43
+ return json;
44
+ const retryAfter = Number(res.headers.get("retry-after")) || undefined;
45
+ if (retryable && attempt < this.o.maxRetries && (res.status === 429 || res.status >= 500)) {
46
+ await new Promise((r) => setTimeout(r, (retryAfter ?? 2 ** attempt) * 1000));
47
+ continue;
48
+ }
49
+ throw new MailError(res.status, json?.name ?? "application_error", json?.message ?? res.statusText, res.headers.get("x-request-id"), retryAfter);
50
+ }
51
+ catch (e) {
52
+ if (e instanceof MailError)
53
+ throw e;
54
+ const reason = ctl.signal.reason;
55
+ if (reason instanceof MailTimeoutError)
56
+ throw reason;
57
+ if (opts.signal?.aborted)
58
+ throw e;
59
+ if (retryable && attempt < this.o.maxRetries) {
60
+ await new Promise((r) => setTimeout(r, 2 ** attempt * 500));
61
+ continue;
62
+ }
63
+ throw e;
64
+ }
65
+ finally {
66
+ clearTimeout(timer);
67
+ }
68
+ }
69
+ }
70
+ emails = {
71
+ send: (p, o) => this.request("POST", "/api/v1/emails", p, o),
72
+ batch: (p, o) => this.request("POST", "/api/v1/emails/batch", p, o),
73
+ get: (id, o) => this.request("GET", `/api/v1/emails/${encodeURIComponent(id)}`, undefined, o),
74
+ list: (q = {}, o) => this.request("GET", `/api/v1/emails${this.q(q)}`, undefined, o),
75
+ reschedule: (id, scheduled_at, o) => this.request("PATCH", `/api/v1/emails/${encodeURIComponent(id)}`, { scheduled_at }, o),
76
+ cancel: (id, o) => this.request("POST", `/api/v1/emails/${encodeURIComponent(id)}/cancel`, undefined, o),
77
+ };
78
+ domains = {
79
+ create: (p, o) => this.request("POST", "/api/v1/domains", p, o),
80
+ list: (o) => this.request("GET", "/api/v1/domains", undefined, o),
81
+ verify: (id, o) => this.request("POST", `/api/v1/domains/${encodeURIComponent(id)}/verify`, undefined, o),
82
+ get: (id, o) => this.request("GET", `/api/v1/domains/${encodeURIComponent(id)}`, undefined, o),
83
+ /** Click and open tracking are off by default. Tell your recipients before turning them on. */
84
+ setTracking: (id, p, o) => this.request("PATCH", `/api/v1/domains/${encodeURIComponent(id)}`, p, o),
85
+ remove: (id, o) => this.request("DELETE", `/api/v1/domains/${encodeURIComponent(id)}`, undefined, o),
86
+ };
87
+ apiKeys = {
88
+ create: (p, o) => this.request("POST", "/api/v1/api-keys", p, o),
89
+ list: (o) => this.request("GET", "/api/v1/api-keys", undefined, o),
90
+ remove: (id, o) => this.request("DELETE", `/api/v1/api-keys/${encodeURIComponent(id)}`, undefined, o),
91
+ };
92
+ q(params) {
93
+ const e = Object.entries(params).filter(([, v]) => v != null && v !== "").map(([k, v]) => [k, String(v)]);
94
+ return e.length ? `?${new URLSearchParams(e)}` : "";
95
+ }
96
+ id(v) { return encodeURIComponent(v); }
97
+ contacts = {
98
+ create: (p, o) => this.request("POST", "/api/v1/contacts", p, o),
99
+ /** `idOrEmail` is the contact id or the email address. */
100
+ get: (idOrEmail, o) => this.request("GET", `/api/v1/contacts/${this.id(idOrEmail)}`, undefined, o),
101
+ list: (q = {}, o) => this.request("GET", `/api/v1/contacts${this.q(q)}`, undefined, o),
102
+ update: (idOrEmail, p, o) => this.request("PATCH", `/api/v1/contacts/${this.id(idOrEmail)}`, p, o),
103
+ remove: (idOrEmail, o) => this.request("DELETE", `/api/v1/contacts/${this.id(idOrEmail)}`, undefined, o),
104
+ };
105
+ segments = {
106
+ create: (p, o) => this.request("POST", "/api/v1/segments", p, o),
107
+ list: (o) => this.request("GET", "/api/v1/segments", undefined, o),
108
+ get: (id, o) => this.request("GET", `/api/v1/segments/${this.id(id)}`, undefined, o),
109
+ remove: (id, o) => this.request("DELETE", `/api/v1/segments/${this.id(id)}`, undefined, o),
110
+ };
111
+ topics = {
112
+ create: (p, o) => this.request("POST", "/api/v1/topics", p, o),
113
+ list: (o) => this.request("GET", "/api/v1/topics", undefined, o),
114
+ };
115
+ suppressions = {
116
+ add: (email, o) => this.request("POST", "/api/v1/suppressions", { email }, o),
117
+ list: (q = {}, o) => this.request("GET", `/api/v1/suppressions${this.q(q)}`, undefined, o),
118
+ /** Complaints and unsubscribes cannot be removed (403). `idOrEmail` is the suppression id or the address. */
119
+ remove: (idOrEmail, o) => this.request("DELETE", `/api/v1/suppressions/${this.id(idOrEmail)}`, undefined, o),
120
+ };
121
+ webhooks = {
122
+ /** The signing secret is returned once, here and from `rotateSecret`. */
123
+ create: (p, o) => this.request("POST", "/api/v1/webhooks", p, o),
124
+ list: (o) => this.request("GET", "/api/v1/webhooks", undefined, o),
125
+ get: (id, o) => this.request("GET", `/api/v1/webhooks/${this.id(id)}`, undefined, o),
126
+ update: (id, p, o) => this.request("PATCH", `/api/v1/webhooks/${this.id(id)}`, p, o),
127
+ rotateSecret: (id, o) => this.request("POST", `/api/v1/webhooks/${this.id(id)}/rotate-secret`, undefined, o),
128
+ remove: (id, o) => this.request("DELETE", `/api/v1/webhooks/${this.id(id)}`, undefined, o),
129
+ };
130
+ templates = {
131
+ create: (p, o) => this.request("POST", "/api/v1/templates", p, o),
132
+ list: (o) => this.request("GET", "/api/v1/templates", undefined, o),
133
+ get: (id, o) => this.request("GET", `/api/v1/templates/${this.id(id)}`, undefined, o),
134
+ /** Saves a new, unpublished version. */
135
+ update: (id, p, o) => this.request("PATCH", `/api/v1/templates/${this.id(id)}`, p, o),
136
+ publish: (id, p = {}, o) => this.request("POST", `/api/v1/templates/${this.id(id)}/publish`, p, o),
137
+ remove: (id, o) => this.request("DELETE", `/api/v1/templates/${this.id(id)}`, undefined, o),
138
+ };
139
+ broadcasts = {
140
+ /** Creates a draft; nothing is sent until `send`. */
141
+ create: (p, o) => this.request("POST", "/api/v1/broadcasts", p, o),
142
+ list: (o) => this.request("GET", "/api/v1/broadcasts", undefined, o),
143
+ get: (id, o) => this.request("GET", `/api/v1/broadcasts/${this.id(id)}`, undefined, o),
144
+ send: (id, p = {}, o) => this.request("POST", `/api/v1/broadcasts/${this.id(id)}/send`, p, o),
145
+ cancel: (id, o) => this.request("POST", `/api/v1/broadcasts/${this.id(id)}/cancel`, undefined, o),
146
+ remove: (id, o) => this.request("DELETE", `/api/v1/broadcasts/${this.id(id)}`, undefined, o),
147
+ };
148
+ logs = {
149
+ list: (q = {}, o) => this.request("GET", `/api/v1/logs${this.q(q)}`, undefined, o),
150
+ };
151
+ }
package/package.json CHANGED
@@ -1,6 +1,48 @@
1
1
  {
2
2
  "name": "mailtruss",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.1.0",
4
+ "description": "Official TypeScript and JavaScript client for the Mailtruss email API",
5
+ "license": "MIT",
6
+ "author": "Mailtruss <hello@mailtruss.com>",
7
+ "homepage": "https://mailtruss.com/docs",
8
+ "type": "module",
9
+ "keywords": [
10
+ "email",
11
+ "transactional-email",
12
+ "email-api",
13
+ "mailtruss",
14
+ "smtp-alternative"
15
+ ],
16
+ "main": "./dist/index.js",
17
+ "types": "./dist/index.d.ts",
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/index.d.ts",
21
+ "import": "./dist/index.js",
22
+ "default": "./dist/index.js"
23
+ },
24
+ "./package.json": "./package.json"
25
+ },
26
+ "files": [
27
+ "dist",
28
+ "README.md",
29
+ "LICENSE"
30
+ ],
31
+ "engines": {
32
+ "node": ">=18"
33
+ },
34
+ "sideEffects": false,
35
+ "devDependencies": {
36
+ "typescript": "^5.9.0",
37
+ "vitest": "^3.2.0",
38
+ "@types/node": "^22.0.0"
39
+ },
40
+ "publishConfig": {
41
+ "access": "public"
42
+ },
43
+ "scripts": {
44
+ "build": "tsc -p tsconfig.build.json",
45
+ "typecheck": "tsc --noEmit",
46
+ "test": "vitest run"
47
+ }
6
48
  }