millionsend 0.2.0 → 0.4.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 +172 -17
- package/dist/http.d.ts +22 -2
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +33 -6
- package/dist/http.js.map +1 -1
- package/dist/index.d.ts +17 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -1
- package/dist/resources/api-keys.d.ts +12 -0
- package/dist/resources/api-keys.d.ts.map +1 -0
- package/dist/resources/api-keys.js +26 -0
- package/dist/resources/api-keys.js.map +1 -0
- package/dist/resources/broadcasts.d.ts +1 -0
- package/dist/resources/broadcasts.d.ts.map +1 -1
- package/dist/resources/broadcasts.js +7 -1
- package/dist/resources/broadcasts.js.map +1 -1
- package/dist/resources/contact-properties.d.ts +15 -0
- package/dist/resources/contact-properties.d.ts.map +1 -0
- package/dist/resources/contact-properties.js +43 -0
- package/dist/resources/contact-properties.js.map +1 -0
- package/dist/resources/contacts.d.ts +22 -2
- package/dist/resources/contacts.d.ts.map +1 -1
- package/dist/resources/contacts.js +47 -1
- package/dist/resources/contacts.js.map +1 -1
- package/dist/resources/deliverability.d.ts +14 -0
- package/dist/resources/deliverability.d.ts.map +1 -0
- package/dist/resources/deliverability.js +15 -0
- package/dist/resources/deliverability.js.map +1 -0
- package/dist/resources/domains.d.ts +18 -0
- package/dist/resources/domains.d.ts.map +1 -0
- package/dist/resources/domains.js +54 -0
- package/dist/resources/domains.js.map +1 -0
- package/dist/resources/emails.d.ts +13 -9
- package/dist/resources/emails.d.ts.map +1 -1
- package/dist/resources/emails.js +36 -1
- package/dist/resources/emails.js.map +1 -1
- package/dist/resources/suppressions.d.ts +33 -0
- package/dist/resources/suppressions.d.ts.map +1 -0
- package/dist/resources/suppressions.js +68 -0
- package/dist/resources/suppressions.js.map +1 -0
- package/dist/resources/templates.d.ts +22 -0
- package/dist/resources/templates.d.ts.map +1 -0
- package/dist/resources/templates.js +61 -0
- package/dist/resources/templates.js.map +1 -0
- package/dist/resources/topics.d.ts +4 -5
- package/dist/resources/topics.d.ts.map +1 -1
- package/dist/resources/topics.js +9 -1
- package/dist/resources/topics.js.map +1 -1
- package/dist/resources/usage.d.ts +11 -0
- package/dist/resources/usage.d.ts.map +1 -0
- package/dist/resources/usage.js +12 -0
- package/dist/resources/usage.js.map +1 -0
- package/dist/resources/webhooks.d.ts +14 -0
- package/dist/resources/webhooks.d.ts.map +1 -0
- package/dist/resources/webhooks.js +36 -0
- package/dist/resources/webhooks.js.map +1 -0
- package/dist/types.d.ts +443 -12
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -43,11 +43,14 @@ new MillionSend(apiKey?, {
|
|
|
43
43
|
baseUrl?, // your instance URL; defaults to MILLIONSEND_BASE_URL, then http://localhost:3001
|
|
44
44
|
fetch?, // custom fetch implementation (proxies, tests, custom agents)
|
|
45
45
|
userAgent?, // extra User-Agent suffix
|
|
46
|
+
timeoutMs?, // request deadline; defaults to 30,000 ms
|
|
47
|
+
allowInsecureHttp?, // accept a non-loopback http:// baseUrl (default: refused)
|
|
46
48
|
});
|
|
47
49
|
```
|
|
48
50
|
|
|
49
51
|
- `apiKey` falls back to `process.env.MILLIONSEND_API_KEY`. Missing key → throws at construction.
|
|
50
52
|
- `baseUrl` falls back to `process.env.MILLIONSEND_BASE_URL`. MillionSend is self-hosted, so **set this to your deployment in production.**
|
|
53
|
+
- Plain `http://` is only accepted for loopback hosts (`localhost`, `127.0.0.1`, `::1`); any other `http://` URL throws at construction, since the API key is sent as a bearer header. Pass `allowInsecureHttp: true` to talk to a non-TLS instance elsewhere (e.g. inside a private network).
|
|
51
54
|
|
|
52
55
|
## Errors
|
|
53
56
|
|
|
@@ -64,41 +67,102 @@ if (error?.name === "not_found") { /* … */ }
|
|
|
64
67
|
|
|
65
68
|
## Resources
|
|
66
69
|
|
|
70
|
+
Inputs are camelCase and mapped to the wire's snake_case (`replyTo` → `reply_to`,
|
|
71
|
+
`scheduledAt` → `scheduled_at`, `topicId` → `topic_id`, …). Every field you pass
|
|
72
|
+
is sent; nothing is dropped client-side. Responses are the wire shape verbatim.
|
|
73
|
+
List endpoints take `{ limit, after, before }` (keyset cursors) and return
|
|
74
|
+
`{ object: "list", data, has_more }`.
|
|
75
|
+
|
|
67
76
|
### Emails
|
|
68
77
|
|
|
69
78
|
```ts
|
|
70
|
-
await ms.emails.send(
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
79
|
+
await ms.emails.send({
|
|
80
|
+
from: "Acme <onboarding@acme.dev>",
|
|
81
|
+
to: ["ada@acme.dev"], cc, bcc, replyTo,
|
|
82
|
+
subject: "Hello",
|
|
83
|
+
html: "<p>Hi</p>", text: "Hi",
|
|
84
|
+
scheduledAt: "2026-09-01T09:00:00Z", // or "in 2 hours"
|
|
85
|
+
tags: [{ name: "campaign", value: "launch" }],
|
|
86
|
+
topicId, // skip opted-out recipients, add unsubscribe link
|
|
87
|
+
attachments: [{ filename: "hi.txt", content: Buffer.from("hi"), contentType: "text/plain" }],
|
|
88
|
+
headers: { "X-Entity-Ref-ID": "123" },
|
|
89
|
+
}, { idempotencyKey }); // POST /emails
|
|
90
|
+
await ms.emails.get(id); // GET /emails/:id (includes a nullable `score`)
|
|
91
|
+
await ms.emails.list({ limit: 50 }); // GET /emails
|
|
92
|
+
await ms.emails.update({ id, scheduledAt }); // PATCH /emails/:id (reschedule)
|
|
93
|
+
await ms.emails.cancel(id); // POST /emails/:id/cancel (scheduled only)
|
|
94
|
+
await ms.emails.remove(id); // DELETE /emails/:id
|
|
95
|
+
await ms.emails.getInsights(id); // GET /emails/:id/insights (best-practice report)
|
|
74
96
|
```
|
|
75
97
|
|
|
76
|
-
|
|
77
|
-
`
|
|
98
|
+
`attachments[].content` is a base64 string or a `Buffer` (encoded for you).
|
|
99
|
+
`template` is sent through as-is; MillionSend answers `422` until templates can be sent.
|
|
100
|
+
|
|
101
|
+
### Batch
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
const { data } = await ms.batch.send([payloadA, payloadB], {
|
|
105
|
+
idempotencyKey,
|
|
106
|
+
batchValidation: "permissive", // x-batch-validation; default "strict" rejects the whole batch
|
|
107
|
+
});
|
|
108
|
+
data.data; // [{ id }] for the accepted emails
|
|
109
|
+
data.errors; // permissive only: [{ index, message }] for the rejected ones
|
|
110
|
+
```
|
|
78
111
|
|
|
79
112
|
### Contacts
|
|
80
113
|
|
|
81
114
|
Contacts are team-global — one list per team, no audiences.
|
|
82
115
|
|
|
83
116
|
```ts
|
|
84
|
-
await ms.contacts.create({
|
|
85
|
-
|
|
117
|
+
await ms.contacts.create({
|
|
118
|
+
email: "ada@acme.dev", firstName: "Ada", lastName: "Lovelace",
|
|
119
|
+
unsubscribed: false, properties: { plan: "pro" },
|
|
120
|
+
segments: [{ id: segmentId }],
|
|
121
|
+
topics: [{ id: topicId, subscription: "opt_in" }],
|
|
122
|
+
});
|
|
86
123
|
await ms.contacts.get({ email }); // by id or email (email wins)
|
|
87
124
|
await ms.contacts.get(contactId); // bare string works too
|
|
88
125
|
await ms.contacts.update({ id, unsubscribed: true, firstName: null }); // null clears
|
|
89
126
|
await ms.contacts.remove({ email });
|
|
90
127
|
await ms.contacts.list({ limit: 50 });
|
|
128
|
+
await ms.contacts.list({ segmentId }); // GET /segments/:id/contacts
|
|
129
|
+
|
|
130
|
+
// Bulk create (MillionSend extension): up to 1000 per call
|
|
131
|
+
const { data } = await ms.contacts.batch.create(items, {
|
|
132
|
+
onConflict: "upsert", // ?on_conflict=error|skip|upsert
|
|
133
|
+
batchValidation: "permissive", // x-batch-validation
|
|
134
|
+
});
|
|
135
|
+
data.data; // [{ index, id, status: "created" | "updated" | "skipped" }]
|
|
136
|
+
data.counts; // { created, updated, skipped, failed }
|
|
137
|
+
data.errors; // permissive only
|
|
138
|
+
|
|
139
|
+
// Segment membership
|
|
140
|
+
await ms.contacts.segments.add({ email, segmentId });
|
|
141
|
+
await ms.contacts.segments.remove({ id: contactId, segmentId });
|
|
91
142
|
|
|
92
143
|
// Topic subscriptions (granular unsubscribe)
|
|
93
144
|
await ms.contacts.topics.update({ email, topics: [{ id: topicId, subscription: "opt_out" }] });
|
|
94
145
|
```
|
|
95
146
|
|
|
147
|
+
`contact.properties` on `get` is typed per property: `{ plan: { type: "string", value: "pro" } }`.
|
|
148
|
+
|
|
149
|
+
### Contact properties
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
await ms.contactProperties.create({ key: "plan", type: "string", fallbackValue: "free" });
|
|
153
|
+
await ms.contactProperties.list();
|
|
154
|
+
await ms.contactProperties.get(id);
|
|
155
|
+
await ms.contactProperties.update({ id, fallbackValue: null }); // null clears
|
|
156
|
+
await ms.contactProperties.remove(id);
|
|
157
|
+
```
|
|
158
|
+
|
|
96
159
|
### Topics
|
|
97
160
|
|
|
98
161
|
```ts
|
|
99
|
-
await ms.topics.create({ name: "Product updates", defaultSubscription: "opt_in" });
|
|
162
|
+
await ms.topics.create({ name: "Product updates", defaultSubscription: "opt_in", visibility: "public" });
|
|
100
163
|
await ms.topics.get(id);
|
|
101
|
-
await ms.topics.list(); //
|
|
164
|
+
await ms.topics.list(); // { object: "list", data, has_more: false } — topics are unpaginated
|
|
165
|
+
await ms.topics.update(id, { name: "Product news" });
|
|
102
166
|
await ms.topics.remove(id);
|
|
103
167
|
```
|
|
104
168
|
|
|
@@ -108,17 +172,82 @@ Target a `segmentId` and/or `topicId`; omit both to send to all contacts.
|
|
|
108
172
|
|
|
109
173
|
```ts
|
|
110
174
|
const { data } = await ms.broadcasts.create({
|
|
111
|
-
segmentId, from: "Acme <news@acme.dev>", subject: "Launch",
|
|
112
|
-
html: "<p>Hi {{{FIRST_NAME|there}}}</p>",
|
|
175
|
+
name: "Launch", segmentId, from: "Acme <news@acme.dev>", subject: "Launch",
|
|
176
|
+
html: "<p>Hi {{{FIRST_NAME|there}}}</p>", previewText: "It's here",
|
|
177
|
+
send: true, scheduledAt: "in 1 hour", // omit `send` to save a draft
|
|
113
178
|
});
|
|
114
179
|
await ms.broadcasts.list();
|
|
115
180
|
await ms.broadcasts.get(id);
|
|
116
|
-
await ms.broadcasts.update(id, { subject: "Launch 🚀" }); // draft only
|
|
181
|
+
await ms.broadcasts.update(id, { subject: "Launch 🚀", topicId: null }); // draft only; null clears
|
|
117
182
|
await ms.broadcasts.send(id, { scheduledAt: "2026-09-01T09:00:00Z" }); // omit to send now
|
|
118
183
|
await ms.broadcasts.cancel(id); // scheduled only
|
|
119
184
|
await ms.broadcasts.remove(id); // draft only
|
|
120
185
|
```
|
|
121
186
|
|
|
187
|
+
### Suppressions
|
|
188
|
+
|
|
189
|
+
```ts
|
|
190
|
+
await ms.suppressions.add({ email: "bounced@acme.dev", origin: "manual" }); // `create` is an alias
|
|
191
|
+
await ms.suppressions.list({ origin: "bounce", limit: 100 });
|
|
192
|
+
await ms.suppressions.get(idOrEmail);
|
|
193
|
+
await ms.suppressions.remove(idOrEmail);
|
|
194
|
+
await ms.suppressions.batch.add({ emails, origin: "unsubscribe" }); // up to 1000
|
|
195
|
+
await ms.suppressions.batch.remove({ emails }); // or { ids }
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Domains
|
|
199
|
+
|
|
200
|
+
```ts
|
|
201
|
+
const { data } = await ms.domains.create({
|
|
202
|
+
name: "acme.dev", region: "us-east-1", customReturnPath: "send",
|
|
203
|
+
openTracking: true, clickTracking: true, trackingSubdomain: "links",
|
|
204
|
+
});
|
|
205
|
+
data.records; // DNS records to publish
|
|
206
|
+
await ms.domains.list();
|
|
207
|
+
await ms.domains.get(id);
|
|
208
|
+
await ms.domains.verify(id);
|
|
209
|
+
await ms.domains.update({ id, clickTracking: false, trackingSubdomain: null }); // null clears
|
|
210
|
+
await ms.domains.remove(id);
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Webhooks
|
|
214
|
+
|
|
215
|
+
```ts
|
|
216
|
+
const { data } = await ms.webhooks.create({
|
|
217
|
+
endpoint: "https://acme.dev/hooks/millionsend",
|
|
218
|
+
events: ["email.delivered", "email.bounced"],
|
|
219
|
+
signingSecret: "whsec_…", // optional: keep an existing secret
|
|
220
|
+
});
|
|
221
|
+
data.signing_secret;
|
|
222
|
+
await ms.webhooks.list();
|
|
223
|
+
await ms.webhooks.get(id); // includes signing_secret
|
|
224
|
+
await ms.webhooks.update(id, { status: "disabled" });
|
|
225
|
+
await ms.webhooks.remove(id);
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### API keys
|
|
229
|
+
|
|
230
|
+
```ts
|
|
231
|
+
const { data } = await ms.apiKeys.create({ name: "ci", permission: "sending_access", domainId });
|
|
232
|
+
data.token; // shown once
|
|
233
|
+
await ms.apiKeys.list();
|
|
234
|
+
await ms.apiKeys.remove(id);
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Templates
|
|
238
|
+
|
|
239
|
+
`id` arguments accept the template id or its alias.
|
|
240
|
+
|
|
241
|
+
```ts
|
|
242
|
+
await ms.templates.create({ name: "Welcome", html: "<p>Hi</p>", subject: "Welcome!", alias: "welcome" });
|
|
243
|
+
await ms.templates.list();
|
|
244
|
+
await ms.templates.get("welcome");
|
|
245
|
+
await ms.templates.update("welcome", { subject: null, alias: null }); // null clears
|
|
246
|
+
await ms.templates.duplicate(id);
|
|
247
|
+
await ms.templates.publish(id); // no-op: every save is live (kept for Resend compatibility)
|
|
248
|
+
await ms.templates.remove(id);
|
|
249
|
+
```
|
|
250
|
+
|
|
122
251
|
### Segments (MillionSend extension)
|
|
123
252
|
|
|
124
253
|
Dynamic segments are a saved filter over the team's contacts — a MillionSend
|
|
@@ -135,6 +264,24 @@ await ms.segments.update(id, { name: "Pro tier" });
|
|
|
135
264
|
await ms.segments.remove(id);
|
|
136
265
|
```
|
|
137
266
|
|
|
267
|
+
### Deliverability (MillionSend extension)
|
|
268
|
+
|
|
269
|
+
The account-level deliverability score over the trailing 30 days. Scores are
|
|
270
|
+
0–10 (`null` until there is enough data); per-email reports live on
|
|
271
|
+
`ms.emails.getInsights(id)`.
|
|
272
|
+
|
|
273
|
+
```ts
|
|
274
|
+
const { data } = await ms.deliverability.get();
|
|
275
|
+
// data.score, data.band, data.complaint_rate, data.guardrail_status, …
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### Usage (MillionSend extension)
|
|
279
|
+
|
|
280
|
+
```ts
|
|
281
|
+
const { data } = await ms.usage.get();
|
|
282
|
+
// data.plan, data.limits.emails_per_day, data.today.emails_sent, data.today.resets_at
|
|
283
|
+
```
|
|
284
|
+
|
|
138
285
|
## Migrating from Resend
|
|
139
286
|
|
|
140
287
|
```diff
|
|
@@ -144,10 +291,18 @@ await ms.segments.remove(id);
|
|
|
144
291
|
+ const ms = new MillionSend("ms_123", { baseUrl: "https://mail.acme.dev" });
|
|
145
292
|
```
|
|
146
293
|
|
|
147
|
-
Method names and
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
- **No audiences.** Contacts are team-global, so `.audiences` calls have no
|
|
294
|
+
Method names, payloads and request options (`idempotencyKey`, `batchValidation`)
|
|
295
|
+
match `resend`. Notes:
|
|
296
|
+
|
|
297
|
+
- **No audiences.** Contacts are team-global, so `.audiences` calls have no
|
|
298
|
+
equivalent — drop them and call `.contacts` directly. The API keeps
|
|
299
|
+
`/audiences/*` routes as a compatibility shim, but the SDK does not expose them.
|
|
300
|
+
For subsets of contacts, use `.segments` (dynamic filters) or topics.
|
|
301
|
+
- **Templates** cannot be sent yet: `emails.send({ template })` is forwarded and
|
|
302
|
+
answered with `422`. `templates.publish` is a no-op (every save is live).
|
|
303
|
+
- **MillionSend extensions** (no Resend counterpart): `segments`,
|
|
304
|
+
`deliverability`, `usage`, `emails.getInsights`, `contacts.batch`, and the
|
|
305
|
+
`origin` field on suppressions.
|
|
151
306
|
|
|
152
307
|
## License
|
|
153
308
|
|
package/dist/http.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type Result } from "./error.js";
|
|
2
|
+
import type { BatchValidation } from "./types.js";
|
|
2
3
|
export interface MillionSendOptions {
|
|
3
4
|
/**
|
|
4
5
|
* Your MillionSend instance URL (no trailing slash needed). Falls back to
|
|
@@ -10,25 +11,44 @@ export interface MillionSendOptions {
|
|
|
10
11
|
fetch?: typeof fetch;
|
|
11
12
|
/** Extra User-Agent suffix appended after the SDK's own token. */
|
|
12
13
|
userAgent?: string;
|
|
14
|
+
/** Request deadline in milliseconds. Defaults to 30 seconds. */
|
|
15
|
+
timeoutMs?: number;
|
|
16
|
+
/**
|
|
17
|
+
* Plain `http://` is only accepted for loopback hosts, since the API key
|
|
18
|
+
* travels as a bearer header. Set to `true` to talk to a non-TLS instance
|
|
19
|
+
* elsewhere (e.g. inside a private network).
|
|
20
|
+
*/
|
|
21
|
+
allowInsecureHttp?: boolean;
|
|
13
22
|
}
|
|
14
23
|
export interface RequestOptions {
|
|
15
24
|
/** POST-only idempotency key (emails.send, batch.send). */
|
|
16
25
|
idempotencyKey?: string;
|
|
17
26
|
}
|
|
27
|
+
export interface BatchRequestOptions extends RequestOptions {
|
|
28
|
+
/**
|
|
29
|
+
* `x-batch-validation`: `strict` (the API default) rejects the whole batch
|
|
30
|
+
* when one item is invalid; `permissive` writes the valid subset and lists
|
|
31
|
+
* the failed items in the response's `errors`.
|
|
32
|
+
*/
|
|
33
|
+
batchValidation?: BatchValidation;
|
|
34
|
+
}
|
|
18
35
|
interface DoRequest {
|
|
19
36
|
method: "GET" | "POST" | "PATCH" | "DELETE";
|
|
20
37
|
path: string;
|
|
21
38
|
body?: unknown;
|
|
22
39
|
query?: Record<string, string | number | undefined> | undefined;
|
|
23
40
|
idempotencyKey?: string | undefined;
|
|
41
|
+
/** Extra request headers; undefined values are skipped. */
|
|
42
|
+
headers?: Record<string, string | undefined> | undefined;
|
|
24
43
|
}
|
|
25
44
|
export declare class HttpClient {
|
|
26
|
-
private
|
|
45
|
+
#private;
|
|
27
46
|
private readonly baseUrl;
|
|
28
47
|
private readonly fetchImpl;
|
|
48
|
+
private readonly timeoutMs;
|
|
29
49
|
private readonly userAgent;
|
|
30
50
|
constructor(apiKey: string, options?: MillionSendOptions);
|
|
31
|
-
request<T>({ method, path, body, query, idempotencyKey }: DoRequest): Promise<Result<T>>;
|
|
51
|
+
request<T>({ method, path, body, query, idempotencyKey, headers: extraHeaders, }: DoRequest): Promise<Result<T>>;
|
|
32
52
|
}
|
|
33
53
|
export {};
|
|
34
54
|
//# sourceMappingURL=http.d.ts.map
|
package/dist/http.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,MAAM,EAAmB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,MAAM,EAAmB,MAAM,YAAY,CAAC;AAC9E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAMlD,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,kEAAkE;IAClE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gEAAgE;IAChE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,cAAc;IAC7B,2DAA2D;IAC3D,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,mBAAoB,SAAQ,cAAc;IACzD;;;;OAIG;IACH,eAAe,CAAC,EAAE,eAAe,CAAC;CACnC;AAED,UAAU,SAAS;IACjB,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC;IAChE,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,2DAA2D;IAC3D,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC;CAC1D;AA0BD,qBAAa,UAAU;;IAErB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;IACzC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAEvB,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,kBAAuB;IA2BtD,OAAO,CAAC,CAAC,EAAE,EACf,MAAM,EACN,IAAI,EACJ,IAAI,EACJ,KAAK,EACL,cAAc,EACd,OAAO,EAAE,YAAY,GACtB,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;CA6ClC"}
|
package/dist/http.js
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
import { toErrorResponse } from "./error.js";
|
|
2
2
|
const DEFAULT_BASE_URL = "http://localhost:3001";
|
|
3
|
-
const
|
|
3
|
+
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
4
|
+
const SDK_VERSION = "0.4.0";
|
|
5
|
+
const LOOPBACK_HOSTS = new Set(["localhost", "127.0.0.1", "[::1]"]);
|
|
6
|
+
/** True for an `http://` URL whose host is not loopback. Unparseable URLs are left to fetch. */
|
|
7
|
+
function isInsecureHttpUrl(url) {
|
|
8
|
+
let parsed;
|
|
9
|
+
try {
|
|
10
|
+
parsed = new URL(url);
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
if (parsed.protocol !== "http:")
|
|
16
|
+
return false;
|
|
17
|
+
return !LOOPBACK_HOSTS.has(parsed.hostname) && !parsed.hostname.startsWith("127.");
|
|
18
|
+
}
|
|
4
19
|
function queryString(query) {
|
|
5
20
|
if (!query)
|
|
6
21
|
return "";
|
|
@@ -13,30 +28,42 @@ function queryString(query) {
|
|
|
13
28
|
return s ? `?${s}` : "";
|
|
14
29
|
}
|
|
15
30
|
export class HttpClient {
|
|
16
|
-
apiKey;
|
|
31
|
+
#apiKey;
|
|
17
32
|
baseUrl;
|
|
18
33
|
fetchImpl;
|
|
34
|
+
timeoutMs;
|
|
19
35
|
userAgent;
|
|
20
36
|
constructor(apiKey, options = {}) {
|
|
21
|
-
this
|
|
37
|
+
this.#apiKey = apiKey;
|
|
22
38
|
this.baseUrl = (options.baseUrl ?? process.env.MILLIONSEND_BASE_URL ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
39
|
+
if (!options.allowInsecureHttp && isInsecureHttpUrl(this.baseUrl)) {
|
|
40
|
+
throw new Error(`Refusing to send the API key over plain http to ${this.baseUrl}. Use https, or set allowInsecureHttp: true.`);
|
|
41
|
+
}
|
|
23
42
|
// Bind so a passed-in fetch keeps its own `this`; default to the global.
|
|
24
43
|
const chosen = options.fetch ?? globalThis.fetch;
|
|
25
44
|
if (!chosen) {
|
|
26
45
|
throw new Error("No fetch implementation found. Use Node 18+ or pass `fetch` in the client options.");
|
|
27
46
|
}
|
|
28
47
|
this.fetchImpl = chosen;
|
|
48
|
+
this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
49
|
+
if (!Number.isFinite(this.timeoutMs) || this.timeoutMs <= 0) {
|
|
50
|
+
throw new Error("timeoutMs must be a positive finite number.");
|
|
51
|
+
}
|
|
29
52
|
const base = `millionsend-node/${SDK_VERSION}`;
|
|
30
53
|
this.userAgent = options.userAgent ? `${base} ${options.userAgent}` : base;
|
|
31
54
|
}
|
|
32
|
-
async request({ method, path, body, query, idempotencyKey }) {
|
|
55
|
+
async request({ method, path, body, query, idempotencyKey, headers: extraHeaders, }) {
|
|
33
56
|
const url = `${this.baseUrl}${path}${queryString(query)}`;
|
|
34
57
|
const headers = {
|
|
35
|
-
Authorization: `Bearer ${this
|
|
58
|
+
Authorization: `Bearer ${this.#apiKey}`,
|
|
36
59
|
Accept: "application/json",
|
|
37
60
|
"User-Agent": this.userAgent,
|
|
38
61
|
};
|
|
39
|
-
const
|
|
62
|
+
for (const [key, value] of Object.entries(extraHeaders ?? {})) {
|
|
63
|
+
if (value !== undefined)
|
|
64
|
+
headers[key] = value;
|
|
65
|
+
}
|
|
66
|
+
const init = { method, headers, signal: AbortSignal.timeout(this.timeoutMs) };
|
|
40
67
|
if (body !== undefined && method !== "GET" && method !== "DELETE") {
|
|
41
68
|
headers["Content-Type"] = "application/json";
|
|
42
69
|
init.body = JSON.stringify(body);
|
package/dist/http.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmC,eAAe,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
import { type MillionSendOptions } from "./http.js";
|
|
2
|
+
import { ApiKeys } from "./resources/api-keys.js";
|
|
2
3
|
import { Broadcasts } from "./resources/broadcasts.js";
|
|
4
|
+
import { ContactProperties } from "./resources/contact-properties.js";
|
|
3
5
|
import { Contacts } from "./resources/contacts.js";
|
|
6
|
+
import { Deliverability } from "./resources/deliverability.js";
|
|
7
|
+
import { Domains } from "./resources/domains.js";
|
|
4
8
|
import { Batch, Emails } from "./resources/emails.js";
|
|
5
9
|
import { Segments } from "./resources/segments.js";
|
|
10
|
+
import { Suppressions } from "./resources/suppressions.js";
|
|
11
|
+
import { Templates } from "./resources/templates.js";
|
|
6
12
|
import { Topics } from "./resources/topics.js";
|
|
13
|
+
import { Usage } from "./resources/usage.js";
|
|
14
|
+
import { Webhooks } from "./resources/webhooks.js";
|
|
7
15
|
/**
|
|
8
16
|
* The MillionSend client. Construct once and reuse.
|
|
9
17
|
*
|
|
@@ -26,13 +34,21 @@ export declare class MillionSend {
|
|
|
26
34
|
readonly emails: Emails;
|
|
27
35
|
readonly batch: Batch;
|
|
28
36
|
readonly contacts: Contacts;
|
|
37
|
+
readonly contactProperties: ContactProperties;
|
|
29
38
|
readonly broadcasts: Broadcasts;
|
|
30
39
|
readonly topics: Topics;
|
|
31
40
|
readonly segments: Segments;
|
|
41
|
+
readonly suppressions: Suppressions;
|
|
42
|
+
readonly domains: Domains;
|
|
43
|
+
readonly webhooks: Webhooks;
|
|
44
|
+
readonly apiKeys: ApiKeys;
|
|
45
|
+
readonly templates: Templates;
|
|
46
|
+
readonly deliverability: Deliverability;
|
|
47
|
+
readonly usage: Usage;
|
|
32
48
|
constructor(apiKey?: string, options?: MillionSendOptions);
|
|
33
49
|
}
|
|
34
50
|
export default MillionSend;
|
|
35
51
|
export type { ErrorResponse, Result } from "./error.js";
|
|
36
|
-
export type { MillionSendOptions, RequestOptions } from "./http.js";
|
|
52
|
+
export type { BatchRequestOptions, MillionSendOptions, RequestOptions } from "./http.js";
|
|
37
53
|
export type * from "./types.js";
|
|
38
54
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnD,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAChE,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC/C,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAEnD;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,WAAW;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,iBAAiB,EAAE,iBAAiB,CAAC;IAC9C,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;IACxC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;gBAEV,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB;CAuB1D;AAED,eAAe,WAAW,CAAC;AAE3B,YAAY,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACxD,YAAY,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACzF,mBAAmB,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
import { HttpClient } from "./http.js";
|
|
2
|
+
import { ApiKeys } from "./resources/api-keys.js";
|
|
2
3
|
import { Broadcasts } from "./resources/broadcasts.js";
|
|
4
|
+
import { ContactProperties } from "./resources/contact-properties.js";
|
|
3
5
|
import { Contacts } from "./resources/contacts.js";
|
|
6
|
+
import { Deliverability } from "./resources/deliverability.js";
|
|
7
|
+
import { Domains } from "./resources/domains.js";
|
|
4
8
|
import { Batch, Emails } from "./resources/emails.js";
|
|
5
9
|
import { Segments } from "./resources/segments.js";
|
|
10
|
+
import { Suppressions } from "./resources/suppressions.js";
|
|
11
|
+
import { Templates } from "./resources/templates.js";
|
|
6
12
|
import { Topics } from "./resources/topics.js";
|
|
13
|
+
import { Usage } from "./resources/usage.js";
|
|
14
|
+
import { Webhooks } from "./resources/webhooks.js";
|
|
7
15
|
/**
|
|
8
16
|
* The MillionSend client. Construct once and reuse.
|
|
9
17
|
*
|
|
@@ -26,9 +34,17 @@ export class MillionSend {
|
|
|
26
34
|
emails;
|
|
27
35
|
batch;
|
|
28
36
|
contacts;
|
|
37
|
+
contactProperties;
|
|
29
38
|
broadcasts;
|
|
30
39
|
topics;
|
|
31
40
|
segments;
|
|
41
|
+
suppressions;
|
|
42
|
+
domains;
|
|
43
|
+
webhooks;
|
|
44
|
+
apiKeys;
|
|
45
|
+
templates;
|
|
46
|
+
deliverability;
|
|
47
|
+
usage;
|
|
32
48
|
constructor(apiKey, options) {
|
|
33
49
|
const key = apiKey ?? process.env.MILLIONSEND_API_KEY;
|
|
34
50
|
if (!key) {
|
|
@@ -38,9 +54,17 @@ export class MillionSend {
|
|
|
38
54
|
this.emails = new Emails(http);
|
|
39
55
|
this.batch = new Batch(http);
|
|
40
56
|
this.contacts = new Contacts(http);
|
|
57
|
+
this.contactProperties = new ContactProperties(http);
|
|
41
58
|
this.broadcasts = new Broadcasts(http);
|
|
42
59
|
this.topics = new Topics(http);
|
|
43
60
|
this.segments = new Segments(http);
|
|
61
|
+
this.suppressions = new Suppressions(http);
|
|
62
|
+
this.domains = new Domains(http);
|
|
63
|
+
this.webhooks = new Webhooks(http);
|
|
64
|
+
this.apiKeys = new ApiKeys(http);
|
|
65
|
+
this.templates = new Templates(http);
|
|
66
|
+
this.deliverability = new Deliverability(http);
|
|
67
|
+
this.usage = new Usage(http);
|
|
44
68
|
}
|
|
45
69
|
}
|
|
46
70
|
export default MillionSend;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAA2B,MAAM,WAAW,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnD,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAA2B,MAAM,WAAW,CAAC;AAChE,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC/C,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAEnD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,OAAO,WAAW;IACb,MAAM,CAAS;IACf,KAAK,CAAQ;IACb,QAAQ,CAAW;IACnB,iBAAiB,CAAoB;IACrC,UAAU,CAAa;IACvB,MAAM,CAAS;IACf,QAAQ,CAAW;IACnB,YAAY,CAAe;IAC3B,OAAO,CAAU;IACjB,QAAQ,CAAW;IACnB,OAAO,CAAU;IACjB,SAAS,CAAY;IACrB,cAAc,CAAiB;IAC/B,KAAK,CAAQ;IAEtB,YAAY,MAAe,EAAE,OAA4B;QACvD,MAAM,GAAG,GAAG,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;QACtD,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CACb,iFAAiF,CAClF,CAAC;QACJ,CAAC;QACD,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAC1C,IAAI,CAAC,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,CAAC,KAAK,GAAG,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC;QAC7B,IAAI,CAAC,QAAQ,GAAG,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,CAAC,iBAAiB,GAAG,IAAI,iBAAiB,CAAC,IAAI,CAAC,CAAC;QACrD,IAAI,CAAC,UAAU,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC;QACvC,IAAI,CAAC,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,CAAC,QAAQ,GAAG,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,CAAC,YAAY,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC;QAC3C,IAAI,CAAC,OAAO,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;QACjC,IAAI,CAAC,QAAQ,GAAG,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,CAAC,OAAO,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;QACjC,IAAI,CAAC,SAAS,GAAG,IAAI,SAAS,CAAC,IAAI,CAAC,CAAC;QACrC,IAAI,CAAC,cAAc,GAAG,IAAI,cAAc,CAAC,IAAI,CAAC,CAAC;QAC/C,IAAI,CAAC,KAAK,GAAG,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC;CACF;AAED,eAAe,WAAW,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Result } from "../error.js";
|
|
2
|
+
import type { HttpClient } from "../http.js";
|
|
3
|
+
import type { ApiKeyListItem, CreateApiKeyOptions, CreateApiKeyResponse, List, ListOptions, RemoveApiKeyResponse } from "../types.js";
|
|
4
|
+
/** API keys. The token is returned once, on `create`. */
|
|
5
|
+
export declare class ApiKeys {
|
|
6
|
+
private readonly http;
|
|
7
|
+
constructor(http: HttpClient);
|
|
8
|
+
create(payload: CreateApiKeyOptions): Promise<Result<CreateApiKeyResponse>>;
|
|
9
|
+
list(options?: ListOptions): Promise<Result<List<ApiKeyListItem>>>;
|
|
10
|
+
remove(id: string): Promise<Result<RemoveApiKeyResponse>>;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=api-keys.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-keys.d.ts","sourceRoot":"","sources":["../../src/resources/api-keys.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,OAAO,KAAK,EACV,cAAc,EACd,mBAAmB,EACnB,oBAAoB,EACpB,IAAI,EACJ,WAAW,EACX,oBAAoB,EACrB,MAAM,aAAa,CAAC;AAErB,yDAAyD;AACzD,qBAAa,OAAO;IACN,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,UAAU;IAE7C,MAAM,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAY3E,IAAI,CAAC,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;IAIlE,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;CAG1D"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { listQuery } from "../query.js";
|
|
2
|
+
/** API keys. The token is returned once, on `create`. */
|
|
3
|
+
export class ApiKeys {
|
|
4
|
+
http;
|
|
5
|
+
constructor(http) {
|
|
6
|
+
this.http = http;
|
|
7
|
+
}
|
|
8
|
+
create(payload) {
|
|
9
|
+
return this.http.request({
|
|
10
|
+
method: "POST",
|
|
11
|
+
path: "/api-keys",
|
|
12
|
+
body: {
|
|
13
|
+
name: payload.name,
|
|
14
|
+
permission: payload.permission,
|
|
15
|
+
domain_id: payload.domainId ?? payload.domain_id,
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
list(options) {
|
|
20
|
+
return this.http.request({ method: "GET", path: "/api-keys", query: listQuery(options) });
|
|
21
|
+
}
|
|
22
|
+
remove(id) {
|
|
23
|
+
return this.http.request({ method: "DELETE", path: `/api-keys/${encodeURIComponent(id)}` });
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=api-keys.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-keys.js","sourceRoot":"","sources":["../../src/resources/api-keys.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAUxC,yDAAyD;AACzD,MAAM,OAAO,OAAO;IACW;IAA7B,YAA6B,IAAgB;QAAhB,SAAI,GAAJ,IAAI,CAAY;IAAG,CAAC;IAEjD,MAAM,CAAC,OAA4B;QACjC,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC;YACvB,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,WAAW;YACjB,IAAI,EAAE;gBACJ,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,UAAU,EAAE,OAAO,CAAC,UAAU;gBAC9B,SAAS,EAAE,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,SAAS;aACjD;SACF,CAAC,CAAC;IACL,CAAC;IAED,IAAI,CAAC,OAAqB;QACxB,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC5F,CAAC;IAED,MAAM,CAAC,EAAU;QACf,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,aAAa,kBAAkB,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;IAC9F,CAAC;CACF"}
|
|
@@ -4,6 +4,7 @@ import type { Broadcast, BroadcastId, BroadcastListItem, CancelBroadcastResponse
|
|
|
4
4
|
export declare class Broadcasts {
|
|
5
5
|
private readonly http;
|
|
6
6
|
constructor(http: HttpClient);
|
|
7
|
+
/** POST /broadcasts — a draft unless `send: true` (optionally with `scheduledAt`). */
|
|
7
8
|
create(payload: CreateBroadcastOptions): Promise<Result<BroadcastId>>;
|
|
8
9
|
get(id: string): Promise<Result<Broadcast>>;
|
|
9
10
|
list(options?: ListOptions): Promise<Result<List<BroadcastListItem>>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"broadcasts.d.ts","sourceRoot":"","sources":["../../src/resources/broadcasts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,OAAO,KAAK,EACV,SAAS,EACT,WAAW,EACX,iBAAiB,EACjB,uBAAuB,EACvB,sBAAsB,EACtB,IAAI,EACJ,WAAW,EACX,uBAAuB,EACvB,oBAAoB,EACpB,sBAAsB,EACvB,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"broadcasts.d.ts","sourceRoot":"","sources":["../../src/resources/broadcasts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,OAAO,KAAK,EACV,SAAS,EACT,WAAW,EACX,iBAAiB,EACjB,uBAAuB,EACvB,sBAAsB,EACtB,IAAI,EACJ,WAAW,EACX,uBAAuB,EACvB,oBAAoB,EACpB,sBAAsB,EACvB,MAAM,aAAa,CAAC;AAgBrB,qBAAa,UAAU;IACT,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,UAAU;IAE7C,sFAAsF;IACtF,MAAM,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IAQrE,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAI3C,IAAI,CAAC,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC;IAIrE,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IAQjF,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,uBAAuB,CAAC,CAAC;IAI5D,gEAAgE;IAChE,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,oBAAyB,GAAG,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IAQlF,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,uBAAuB,CAAC,CAAC;CAM7D"}
|
|
@@ -8,6 +8,7 @@ function toWire(o) {
|
|
|
8
8
|
html: o.html,
|
|
9
9
|
text: o.text,
|
|
10
10
|
reply_to: o.replyTo,
|
|
11
|
+
preview_text: o.previewText,
|
|
11
12
|
topic_id: o.topicId,
|
|
12
13
|
};
|
|
13
14
|
}
|
|
@@ -16,8 +17,13 @@ export class Broadcasts {
|
|
|
16
17
|
constructor(http) {
|
|
17
18
|
this.http = http;
|
|
18
19
|
}
|
|
20
|
+
/** POST /broadcasts — a draft unless `send: true` (optionally with `scheduledAt`). */
|
|
19
21
|
create(payload) {
|
|
20
|
-
return this.http.request({
|
|
22
|
+
return this.http.request({
|
|
23
|
+
method: "POST",
|
|
24
|
+
path: "/broadcasts",
|
|
25
|
+
body: { ...toWire(payload), send: payload.send, scheduled_at: payload.scheduledAt },
|
|
26
|
+
});
|
|
21
27
|
}
|
|
22
28
|
get(id) {
|
|
23
29
|
return this.http.request({ method: "GET", path: `/broadcasts/${encodeURIComponent(id)}` });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"broadcasts.js","sourceRoot":"","sources":["../../src/resources/broadcasts.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAcxC,SAAS,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"broadcasts.js","sourceRoot":"","sources":["../../src/resources/broadcasts.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAcxC,SAAS,MAAM,CAAC,CAAyB;IACvC,OAAO;QACL,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,UAAU,EAAE,CAAC,CAAC,SAAS;QACvB,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,QAAQ,EAAE,CAAC,CAAC,OAAO;QACnB,YAAY,EAAE,CAAC,CAAC,WAAW;QAC3B,QAAQ,EAAE,CAAC,CAAC,OAAO;KACpB,CAAC;AACJ,CAAC;AAED,MAAM,OAAO,UAAU;IACQ;IAA7B,YAA6B,IAAgB;QAAhB,SAAI,GAAJ,IAAI,CAAY;IAAG,CAAC;IAEjD,sFAAsF;IACtF,MAAM,CAAC,OAA+B;QACpC,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC;YACvB,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,aAAa;YACnB,IAAI,EAAE,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,YAAY,EAAE,OAAO,CAAC,WAAW,EAAE;SACpF,CAAC,CAAC;IACL,CAAC;IAED,GAAG,CAAC,EAAU;QACZ,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,eAAe,kBAAkB,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;IAC7F,CAAC;IAED,IAAI,CAAC,OAAqB;QACxB,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC9F,CAAC;IAED,MAAM,CAAC,EAAU,EAAE,OAA+B;QAChD,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC;YACvB,MAAM,EAAE,OAAO;YACf,IAAI,EAAE,eAAe,kBAAkB,CAAC,EAAE,CAAC,EAAE;YAC7C,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC;SACtB,CAAC,CAAC;IACL,CAAC;IAED,MAAM,CAAC,EAAU;QACf,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,eAAe,kBAAkB,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;IAChG,CAAC;IAED,gEAAgE;IAChE,IAAI,CAAC,EAAU,EAAE,UAAgC,EAAE;QACjD,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC;YACvB,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,eAAe,kBAAkB,CAAC,EAAE,CAAC,OAAO;YAClD,IAAI,EAAE,EAAE,YAAY,EAAE,OAAO,CAAC,WAAW,EAAE;SAC5C,CAAC,CAAC;IACL,CAAC;IAED,MAAM,CAAC,EAAU;QACf,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC;YACvB,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,eAAe,kBAAkB,CAAC,EAAE,CAAC,SAAS;SACrD,CAAC,CAAC;IACL,CAAC;CACF"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Result } from "../error.js";
|
|
2
|
+
import type { HttpClient } from "../http.js";
|
|
3
|
+
import type { ContactProperty, ContactPropertyId, ContactPropertyListItem, CreateContactPropertyOptions, List, ListOptions, RemoveContactPropertyResponse, UpdateContactPropertyOptions } from "../types.js";
|
|
4
|
+
/** Custom contact property definitions (key, type, fallback). */
|
|
5
|
+
export declare class ContactProperties {
|
|
6
|
+
private readonly http;
|
|
7
|
+
constructor(http: HttpClient);
|
|
8
|
+
create(payload: CreateContactPropertyOptions): Promise<Result<ContactProperty>>;
|
|
9
|
+
list(options?: ListOptions): Promise<Result<List<ContactPropertyListItem>>>;
|
|
10
|
+
get(id: string): Promise<Result<ContactProperty>>;
|
|
11
|
+
/** PATCH /contact-properties/:id — `fallbackValue: null` clears it. */
|
|
12
|
+
update(payload: UpdateContactPropertyOptions): Promise<Result<ContactPropertyId>>;
|
|
13
|
+
remove(id: string): Promise<Result<RemoveContactPropertyResponse>>;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=contact-properties.d.ts.map
|