shipmail 0.1.24 → 0.1.26
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 +69 -1
- package/dist/index.cjs +156 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +310 -2
- package/dist/index.d.ts +310 -2
- package/dist/index.js +156 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -21,6 +21,8 @@ Official TypeScript SDK for the [Shipmail](https://shipmail.to) API. Zero runtim
|
|
|
21
21
|
- [Threads](#threads)
|
|
22
22
|
- [Webhooks](#webhooks)
|
|
23
23
|
- [Suppressions](#suppressions)
|
|
24
|
+
- [Audiences](#audiences)
|
|
25
|
+
- [Newsletters](#newsletters)
|
|
24
26
|
- [Status](#status)
|
|
25
27
|
- [Pagination](#pagination)
|
|
26
28
|
- [Webhook verification](#webhook-verification)
|
|
@@ -232,6 +234,72 @@ for await (const item of shipmail.suppressions.listAutoPaginating({ limit: 100 }
|
|
|
232
234
|
}
|
|
233
235
|
```
|
|
234
236
|
|
|
237
|
+
## Audiences
|
|
238
|
+
|
|
239
|
+
```ts
|
|
240
|
+
const audience = await shipmail.audiences.create({
|
|
241
|
+
name: "Newsletter",
|
|
242
|
+
consent_source: "Website signup form",
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
await shipmail.audiences.subscribers.add(audience.id, {
|
|
246
|
+
email_address: "jane@example.com",
|
|
247
|
+
merge_fields: { plan: "pro" },
|
|
248
|
+
});
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
## Newsletters
|
|
252
|
+
|
|
253
|
+
```ts
|
|
254
|
+
import { readFile } from "node:fs/promises";
|
|
255
|
+
|
|
256
|
+
const newsletterDomains = await shipmail.newsletters.domains.list({ limit: 25 });
|
|
257
|
+
const hero = await shipmail.newsletters.assets.upload({
|
|
258
|
+
filename: "hero.png",
|
|
259
|
+
content_type: "image/png",
|
|
260
|
+
data: await readFile("hero.png"),
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
const newsletter = await shipmail.newsletters.create({
|
|
264
|
+
audience_id: "aud_...",
|
|
265
|
+
newsletter_domain_id: newsletterDomains.data[0].id,
|
|
266
|
+
name: "July changelog",
|
|
267
|
+
subject: "What shipped in July",
|
|
268
|
+
preview_text: "A quick product update",
|
|
269
|
+
blocks: [
|
|
270
|
+
{ type: "heading", level: 1, text: "July updates" },
|
|
271
|
+
{ type: "callout", variant: "info", title: "Quick note", body: "A short intro." },
|
|
272
|
+
{ type: "paragraph", body: "A quick product update." },
|
|
273
|
+
{ type: "image", url: hero.url, alt: "Product screenshot" },
|
|
274
|
+
{
|
|
275
|
+
type: "columns",
|
|
276
|
+
ratio: "50-50",
|
|
277
|
+
left: { title: "For teams", body: "Shared inbox improvements." },
|
|
278
|
+
right: { title: "For agents", body: "API and MCP improvements." },
|
|
279
|
+
},
|
|
280
|
+
],
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
await shipmail.newsletters.preview(newsletter.id);
|
|
284
|
+
|
|
285
|
+
await shipmail.newsletters.sendTest(newsletter.id, {
|
|
286
|
+
recipient_email: "owner@example.com",
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
await shipmail.newsletters.preflight(newsletter.id);
|
|
290
|
+
|
|
291
|
+
await shipmail.newsletters.schedule(newsletter.id, {
|
|
292
|
+
scheduled_at: "2026-08-01T09:00:00.000Z",
|
|
293
|
+
});
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
Newsletter test sends and schedules must pass preflight. Guardrail failures throw
|
|
297
|
+
`ValidationError` with the failed preflight items in `error.details`.
|
|
298
|
+
Preflight responses include `url_breakdown` so you can see which links, image
|
|
299
|
+
URLs, and video thumbnails count against the 20 unique URL limit.
|
|
300
|
+
Block prose fields are plain text in API requests. Use newlines for paragraph
|
|
301
|
+
breaks, and use `body_html` or `custom_html` only when you need raw HTML.
|
|
302
|
+
|
|
235
303
|
## Status
|
|
236
304
|
|
|
237
305
|
```ts
|
|
@@ -263,7 +331,7 @@ for await (const domain of shipmail.domains.listAutoPaginating({ limit: 25 })) {
|
|
|
263
331
|
}
|
|
264
332
|
```
|
|
265
333
|
|
|
266
|
-
`listAutoPaginating` is available on `domains`, `mailboxes`, `messages`, `threads`, `webhooks`, `webhooks.listDeliveriesAutoPaginating`, and `
|
|
334
|
+
`listAutoPaginating` is available on `domains`, `mailboxes`, `messages`, `threads`, `webhooks`, `webhooks.listDeliveriesAutoPaginating`, `suppressions`, `newsletters.domains`, and `newsletters.assets`.
|
|
267
335
|
|
|
268
336
|
## Webhook verification
|
|
269
337
|
|
package/dist/index.cjs
CHANGED
|
@@ -117,9 +117,9 @@ function mapErrorFromResponse(status, body, requestId) {
|
|
|
117
117
|
|
|
118
118
|
// src/pagination.ts
|
|
119
119
|
var Page = class {
|
|
120
|
-
constructor(client,
|
|
120
|
+
constructor(client, path2, query) {
|
|
121
121
|
this.client = client;
|
|
122
|
-
this.path =
|
|
122
|
+
this.path = path2;
|
|
123
123
|
this.query = query;
|
|
124
124
|
}
|
|
125
125
|
async *[Symbol.asyncIterator]() {
|
|
@@ -619,6 +619,149 @@ var Messages = class extends ApiResource {
|
|
|
619
619
|
}
|
|
620
620
|
};
|
|
621
621
|
|
|
622
|
+
// src/resources/newsletters.ts
|
|
623
|
+
function path(id) {
|
|
624
|
+
return `/newsletters/${encodeURIComponent(id)}`;
|
|
625
|
+
}
|
|
626
|
+
var NewsletterDomains = class extends ApiResource {
|
|
627
|
+
list(params, options) {
|
|
628
|
+
return this.client.request({
|
|
629
|
+
method: "GET",
|
|
630
|
+
path: "/newsletter-domains",
|
|
631
|
+
query: { cursor: params?.cursor, limit: params?.limit },
|
|
632
|
+
methodOptions: options
|
|
633
|
+
});
|
|
634
|
+
}
|
|
635
|
+
listAutoPaginating(params) {
|
|
636
|
+
return new Page(this.client, "/newsletter-domains", { limit: params?.limit });
|
|
637
|
+
}
|
|
638
|
+
};
|
|
639
|
+
var NewsletterAssets = class extends ApiResource {
|
|
640
|
+
list(params, options) {
|
|
641
|
+
return this.client.request({
|
|
642
|
+
method: "GET",
|
|
643
|
+
path: "/newsletter-assets",
|
|
644
|
+
query: {
|
|
645
|
+
cursor: params?.cursor,
|
|
646
|
+
limit: params?.limit,
|
|
647
|
+
kind: params?.kind,
|
|
648
|
+
q: params?.q
|
|
649
|
+
},
|
|
650
|
+
methodOptions: options
|
|
651
|
+
});
|
|
652
|
+
}
|
|
653
|
+
listAutoPaginating(params) {
|
|
654
|
+
return new Page(this.client, "/newsletter-assets", {
|
|
655
|
+
limit: params?.limit,
|
|
656
|
+
kind: params?.kind,
|
|
657
|
+
q: params?.q
|
|
658
|
+
});
|
|
659
|
+
}
|
|
660
|
+
upload(params, options) {
|
|
661
|
+
return this.client.request({
|
|
662
|
+
method: "POST",
|
|
663
|
+
path: "/newsletter-assets",
|
|
664
|
+
query: { filename: params.filename },
|
|
665
|
+
rawBody: params.data,
|
|
666
|
+
contentType: params.content_type,
|
|
667
|
+
methodOptions: options
|
|
668
|
+
});
|
|
669
|
+
}
|
|
670
|
+
};
|
|
671
|
+
var Newsletters = class extends ApiResource {
|
|
672
|
+
constructor(client) {
|
|
673
|
+
super(client);
|
|
674
|
+
this.domains = new NewsletterDomains(client);
|
|
675
|
+
this.assets = new NewsletterAssets(client);
|
|
676
|
+
}
|
|
677
|
+
create(params, options) {
|
|
678
|
+
return this.client.request({
|
|
679
|
+
method: "POST",
|
|
680
|
+
path: "/newsletters",
|
|
681
|
+
body: params,
|
|
682
|
+
methodOptions: options
|
|
683
|
+
});
|
|
684
|
+
}
|
|
685
|
+
createFromChangelog(params, options) {
|
|
686
|
+
return this.client.request({
|
|
687
|
+
method: "POST",
|
|
688
|
+
path: "/newsletters/from-changelog",
|
|
689
|
+
body: params,
|
|
690
|
+
methodOptions: options
|
|
691
|
+
});
|
|
692
|
+
}
|
|
693
|
+
list(params, options) {
|
|
694
|
+
return this.client.request({
|
|
695
|
+
method: "GET",
|
|
696
|
+
path: "/newsletters",
|
|
697
|
+
query: { cursor: params?.cursor, limit: params?.limit },
|
|
698
|
+
methodOptions: options
|
|
699
|
+
});
|
|
700
|
+
}
|
|
701
|
+
listAutoPaginating(params) {
|
|
702
|
+
return new Page(this.client, "/newsletters", { limit: params?.limit });
|
|
703
|
+
}
|
|
704
|
+
get(id, options) {
|
|
705
|
+
return this.client.request({
|
|
706
|
+
method: "GET",
|
|
707
|
+
path: path(id),
|
|
708
|
+
methodOptions: options
|
|
709
|
+
});
|
|
710
|
+
}
|
|
711
|
+
update(id, params, options) {
|
|
712
|
+
return this.client.request({
|
|
713
|
+
method: "PATCH",
|
|
714
|
+
path: path(id),
|
|
715
|
+
body: params,
|
|
716
|
+
methodOptions: options
|
|
717
|
+
});
|
|
718
|
+
}
|
|
719
|
+
preflight(id, options) {
|
|
720
|
+
return this.client.request({
|
|
721
|
+
method: "POST",
|
|
722
|
+
path: `${path(id)}/preflight`,
|
|
723
|
+
methodOptions: options
|
|
724
|
+
});
|
|
725
|
+
}
|
|
726
|
+
preview(id, options) {
|
|
727
|
+
return this.client.request({
|
|
728
|
+
method: "POST",
|
|
729
|
+
path: `${path(id)}/preview`,
|
|
730
|
+
methodOptions: options
|
|
731
|
+
});
|
|
732
|
+
}
|
|
733
|
+
sendTest(id, params, options) {
|
|
734
|
+
return this.client.request({
|
|
735
|
+
method: "POST",
|
|
736
|
+
path: `${path(id)}/test-send`,
|
|
737
|
+
body: params,
|
|
738
|
+
methodOptions: options
|
|
739
|
+
});
|
|
740
|
+
}
|
|
741
|
+
schedule(id, params, options) {
|
|
742
|
+
return this.client.request({
|
|
743
|
+
method: "POST",
|
|
744
|
+
path: `${path(id)}/schedule`,
|
|
745
|
+
body: params,
|
|
746
|
+
methodOptions: options
|
|
747
|
+
});
|
|
748
|
+
}
|
|
749
|
+
cancel(id, options) {
|
|
750
|
+
return this.client.request({
|
|
751
|
+
method: "POST",
|
|
752
|
+
path: `${path(id)}/cancel`,
|
|
753
|
+
methodOptions: options
|
|
754
|
+
});
|
|
755
|
+
}
|
|
756
|
+
resume(id, options) {
|
|
757
|
+
return this.client.request({
|
|
758
|
+
method: "POST",
|
|
759
|
+
path: `${path(id)}/resume`,
|
|
760
|
+
methodOptions: options
|
|
761
|
+
});
|
|
762
|
+
}
|
|
763
|
+
};
|
|
764
|
+
|
|
622
765
|
// src/resources/status.ts
|
|
623
766
|
var Status = class extends ApiResource {
|
|
624
767
|
get(options) {
|
|
@@ -787,7 +930,7 @@ var Webhooks = class extends ApiResource {
|
|
|
787
930
|
};
|
|
788
931
|
|
|
789
932
|
// src/version.ts
|
|
790
|
-
var VERSION = "0.1.
|
|
933
|
+
var VERSION = "0.1.26";
|
|
791
934
|
|
|
792
935
|
// src/client.ts
|
|
793
936
|
var DEFAULT_BASE_URL = "https://shipmail.to/api/v1";
|
|
@@ -811,6 +954,12 @@ function isApiErrorBody(value) {
|
|
|
811
954
|
const error = obj["error"];
|
|
812
955
|
return typeof error["type"] === "string" && typeof error["message"] === "string";
|
|
813
956
|
}
|
|
957
|
+
function rawBodyToBlobPart(rawBody) {
|
|
958
|
+
if (rawBody instanceof ArrayBuffer) return rawBody;
|
|
959
|
+
const buffer = new ArrayBuffer(rawBody.byteLength);
|
|
960
|
+
new Uint8Array(buffer).set(rawBody);
|
|
961
|
+
return buffer;
|
|
962
|
+
}
|
|
814
963
|
var ShipMailClient = class {
|
|
815
964
|
/**
|
|
816
965
|
* Create a new ShipMail client.
|
|
@@ -836,6 +985,7 @@ var ShipMailClient = class {
|
|
|
836
985
|
this.domains = new Domains(this);
|
|
837
986
|
this.mailboxes = new Mailboxes(this);
|
|
838
987
|
this.messages = new Messages(this);
|
|
988
|
+
this.newsletters = new Newsletters(this);
|
|
839
989
|
this.suppressions = new Suppressions(this);
|
|
840
990
|
this.threads = new Threads(this);
|
|
841
991
|
this.webhooks = new Webhooks(this);
|
|
@@ -879,7 +1029,7 @@ var ShipMailClient = class {
|
|
|
879
1029
|
let body = null;
|
|
880
1030
|
if (options.rawBody !== void 0) {
|
|
881
1031
|
headers["Content-Type"] = options.contentType ?? "application/octet-stream";
|
|
882
|
-
body = new Blob([options.rawBody]);
|
|
1032
|
+
body = new Blob([rawBodyToBlobPart(options.rawBody)]);
|
|
883
1033
|
} else if (options.body !== void 0) {
|
|
884
1034
|
headers["Content-Type"] = "application/json";
|
|
885
1035
|
body = JSON.stringify(options.body);
|
|
@@ -919,8 +1069,8 @@ var ShipMailClient = class {
|
|
|
919
1069
|
}
|
|
920
1070
|
throw lastError ?? new ShipMailError("Request failed after retries");
|
|
921
1071
|
}
|
|
922
|
-
buildUrl(
|
|
923
|
-
const url = new URL(`${this.baseUrl}${
|
|
1072
|
+
buildUrl(path2, query) {
|
|
1073
|
+
const url = new URL(`${this.baseUrl}${path2}`);
|
|
924
1074
|
if (query) {
|
|
925
1075
|
for (const [key, value] of Object.entries(query)) {
|
|
926
1076
|
if (value !== void 0) {
|