millionsend 0.0.1 → 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.
Files changed (48) hide show
  1. package/README.md +153 -4
  2. package/dist/error.d.ts +24 -0
  3. package/dist/error.d.ts.map +1 -0
  4. package/dist/error.js +16 -0
  5. package/dist/error.js.map +1 -0
  6. package/dist/http.d.ts +34 -0
  7. package/dist/http.d.ts.map +1 -0
  8. package/dist/http.js +75 -0
  9. package/dist/http.js.map +1 -0
  10. package/dist/index.d.ts +40 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +50 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/query.d.ts +4 -0
  15. package/dist/query.d.ts.map +1 -0
  16. package/dist/query.js +7 -0
  17. package/dist/query.js.map +1 -0
  18. package/dist/resources/audiences.d.ts +17 -0
  19. package/dist/resources/audiences.d.ts.map +1 -0
  20. package/dist/resources/audiences.js +25 -0
  21. package/dist/resources/audiences.js.map +1 -0
  22. package/dist/resources/broadcasts.d.ts +16 -0
  23. package/dist/resources/broadcasts.d.ts.map +1 -0
  24. package/dist/resources/broadcasts.js +54 -0
  25. package/dist/resources/broadcasts.js.map +1 -0
  26. package/dist/resources/contacts.d.ts +22 -0
  27. package/dist/resources/contacts.d.ts.map +1 -0
  28. package/dist/resources/contacts.js +73 -0
  29. package/dist/resources/contacts.js.map +1 -0
  30. package/dist/resources/emails.d.ts +28 -0
  31. package/dist/resources/emails.d.ts.map +1 -0
  32. package/dist/resources/emails.js +64 -0
  33. package/dist/resources/emails.js.map +1 -0
  34. package/dist/resources/segments.d.ts +17 -0
  35. package/dist/resources/segments.d.ts.map +1 -0
  36. package/dist/resources/segments.js +35 -0
  37. package/dist/resources/segments.js.map +1 -0
  38. package/dist/resources/topics.d.ts +16 -0
  39. package/dist/resources/topics.d.ts.map +1 -0
  40. package/dist/resources/topics.js +29 -0
  41. package/dist/resources/topics.js.map +1 -0
  42. package/dist/types.d.ts +254 -0
  43. package/dist/types.d.ts.map +1 -0
  44. package/dist/types.js +7 -0
  45. package/dist/types.js.map +1 -0
  46. package/package.json +34 -9
  47. package/index.d.ts +0 -4
  48. package/index.js +0 -14
package/README.md CHANGED
@@ -1,7 +1,156 @@
1
1
  # millionsend
2
2
 
3
- Official Node.js SDK for [MillionSend](https://github.com/MillionSend) — the open-source,
4
- self-hostable email platform (bring your own AWS SES, or use the hosted cloud).
3
+ Official Node.js / TypeScript SDK for [MillionSend](https://github.com/MillionSend/millionsend) — a self-hostable, Resend-compatible email API on AWS SES.
5
4
 
6
- **Status: under active development.** This release reserves the package name; the first working
7
- SDK will land here. Watch the [MillionSend GitHub org](https://github.com/MillionSend) for progress.
5
+ The API is wire-compatible with Resend, and this SDK deliberately mirrors the
6
+ shape of `resend`, so migrating is mostly a find-and-replace: swap the import,
7
+ the class name, and point `baseUrl` at your instance.
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ npm install millionsend
13
+ # or: pnpm add millionsend / yarn add millionsend / bun add millionsend
14
+ ```
15
+
16
+ Requires Node.js 18+ (uses the global `fetch`).
17
+
18
+ ## Quickstart
19
+
20
+ ```ts
21
+ import { MillionSend } from "millionsend";
22
+
23
+ const ms = new MillionSend("ms_123", { baseUrl: "https://mail.acme.dev" });
24
+
25
+ const { data, error } = await ms.emails.send({
26
+ from: "Acme <onboarding@acme.dev>",
27
+ to: "delivered@resend.dev",
28
+ subject: "Hello from MillionSend",
29
+ html: "<strong>It works!</strong>",
30
+ });
31
+
32
+ if (error) {
33
+ console.error(error.name, error.message);
34
+ } else {
35
+ console.log("sent", data.id);
36
+ }
37
+ ```
38
+
39
+ ## Configuration
40
+
41
+ ```ts
42
+ new MillionSend(apiKey?, {
43
+ baseUrl?, // your instance URL; defaults to MILLIONSEND_BASE_URL, then http://localhost:3001
44
+ fetch?, // custom fetch implementation (proxies, tests, custom agents)
45
+ userAgent?, // extra User-Agent suffix
46
+ });
47
+ ```
48
+
49
+ - `apiKey` falls back to `process.env.MILLIONSEND_API_KEY`. Missing key → throws at construction.
50
+ - `baseUrl` falls back to `process.env.MILLIONSEND_BASE_URL`. MillionSend is self-hosted, so **set this to your deployment in production.**
51
+
52
+ ## Errors
53
+
54
+ No method throws for an API error — every call resolves to `{ data, error }`.
55
+ `error` is `null` on success; otherwise `{ name, message, statusCode }` where
56
+ `name` is a stable snake_case code you can switch on (`validation_error`,
57
+ `not_found`, `restricted_api_key`, `sending_paused`, …). Client-side and
58
+ transport failures carry `statusCode: null`.
59
+
60
+ ```ts
61
+ const { data, error } = await ms.emails.get(id);
62
+ if (error?.name === "not_found") { /* … */ }
63
+ ```
64
+
65
+ ## Resources
66
+
67
+ ### Emails
68
+
69
+ ```ts
70
+ await ms.emails.send(payload, { idempotencyKey }); // POST /emails
71
+ await ms.emails.get(id); // GET /emails/:id
72
+ await ms.emails.cancel(id); // POST /emails/:id/cancel (scheduled only)
73
+ await ms.batch.send([payloadA, payloadB], { idempotencyKey }); // up to 100
74
+ ```
75
+
76
+ Send options are camelCase and mapped to the wire: `replyTo` → `reply_to`,
77
+ `scheduledAt` → `scheduled_at`. `to`/`cc`/`bcc`/`replyTo` accept a string or an array.
78
+
79
+ ### Audiences & contacts
80
+
81
+ ```ts
82
+ const { data: audience } = await ms.audiences.create({ name: "Registered users" });
83
+ await ms.audiences.list({ limit: 20, after });
84
+ await ms.audiences.get(id);
85
+ await ms.audiences.remove(id);
86
+
87
+ await ms.contacts.create({ audienceId, email: "ada@acme.dev", firstName: "Ada",
88
+ properties: { plan: "pro" } });
89
+ await ms.contacts.get({ audienceId, email }); // by id or email (email wins)
90
+ await ms.contacts.get(contactId); // bare string works too
91
+ await ms.contacts.update({ id, unsubscribed: true, firstName: null }); // null clears
92
+ await ms.contacts.remove({ email });
93
+ await ms.contacts.list({ audienceId, limit: 50 });
94
+
95
+ // Topic subscriptions (granular unsubscribe)
96
+ await ms.contacts.topics.update({ email, topics: [{ id: topicId, subscription: "opt_out" }] });
97
+ ```
98
+
99
+ ### Topics
100
+
101
+ ```ts
102
+ await ms.topics.create({ name: "Product updates", defaultSubscription: "opt_in" });
103
+ await ms.topics.get(id);
104
+ await ms.topics.list(); // bare { data } — topics are unpaginated
105
+ await ms.topics.remove(id);
106
+ ```
107
+
108
+ ### Broadcasts
109
+
110
+ ```ts
111
+ const { data } = await ms.broadcasts.create({
112
+ audienceId, from: "Acme <news@acme.dev>", subject: "Launch",
113
+ html: "<p>Hi {{{FIRST_NAME|there}}}</p>",
114
+ });
115
+ await ms.broadcasts.list();
116
+ await ms.broadcasts.get(id);
117
+ await ms.broadcasts.update(id, { subject: "Launch 🚀" }); // draft only
118
+ await ms.broadcasts.send(id, { scheduledAt: "2026-09-01T09:00:00Z" }); // omit to send now
119
+ await ms.broadcasts.cancel(id); // scheduled only
120
+ await ms.broadcasts.remove(id); // draft only
121
+ ```
122
+
123
+ ### Segments (MillionSend extension)
124
+
125
+ Dynamic segments are a saved filter over an audience's contacts — a MillionSend
126
+ superset with no Resend equivalent.
127
+
128
+ ```ts
129
+ await ms.segments.create({
130
+ name: "Pro plan",
131
+ audienceId,
132
+ filter: { match: "all", conditions: [{ field: "property:plan", op: "equals", value: "pro" }] },
133
+ });
134
+ await ms.segments.get(id); // includes a live contact_count
135
+ await ms.segments.list();
136
+ await ms.segments.update(id, { name: "Pro tier" });
137
+ await ms.segments.remove(id);
138
+ ```
139
+
140
+ ## Migrating from Resend
141
+
142
+ ```diff
143
+ - import { Resend } from "resend";
144
+ - const resend = new Resend("re_123");
145
+ + import { MillionSend } from "millionsend";
146
+ + const ms = new MillionSend("ms_123", { baseUrl: "https://mail.acme.dev" });
147
+ ```
148
+
149
+ Method names and payloads match. Notes:
150
+
151
+ - **Domains and API keys** are managed in the MillionSend dashboard, not via the API, so there are no `.domains`/`.apiKeys` resources here.
152
+ - Resend's `.segments` is an alias of audiences; MillionSend's `.segments` is the distinct dynamic-filter feature. Use `.audiences` for a straight port.
153
+
154
+ ## License
155
+
156
+ MIT
@@ -0,0 +1,24 @@
1
+ /**
2
+ * The error shape the MillionSend API returns on every non-2xx response, plus
3
+ * the two client-side conditions (a bad request never sent, a transport
4
+ * failure) which carry `statusCode: null`. Mirrors Resend's `ErrorResponse`, so
5
+ * code that switches on `error.name` ports across unchanged.
6
+ */
7
+ export interface ErrorResponse {
8
+ /** Stable snake_case code — the discriminant, e.g. "validation_error", "not_found". */
9
+ name: string;
10
+ message: string;
11
+ /** HTTP status; null when the request never reached the API. */
12
+ statusCode: number | null;
13
+ }
14
+ /** Every method resolves to this — it never throws for an API error. */
15
+ export type Result<T> = {
16
+ data: T;
17
+ error: null;
18
+ } | {
19
+ data: null;
20
+ error: ErrorResponse;
21
+ };
22
+ /** Coerce an arbitrary parsed error body into the canonical shape. */
23
+ export declare function toErrorResponse(body: unknown, status: number): ErrorResponse;
24
+ //# sourceMappingURL=error.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../src/error.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,uFAAuF;IACvF,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,gEAAgE;IAChE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,wEAAwE;AACxE,MAAM,MAAM,MAAM,CAAC,CAAC,IAAI;IAAE,IAAI,EAAE,CAAC,CAAC;IAAC,KAAK,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,aAAa,CAAA;CAAE,CAAC;AAExF,sEAAsE;AACtE,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,aAAa,CAa5E"}
package/dist/error.js ADDED
@@ -0,0 +1,16 @@
1
+ /** Coerce an arbitrary parsed error body into the canonical shape. */
2
+ export function toErrorResponse(body, status) {
3
+ if (body && typeof body === "object") {
4
+ const b = body;
5
+ const name = typeof b.name === "string" ? b.name : "application_error";
6
+ const message = typeof b.message === "string" ? b.message : `Request failed with status ${status}`;
7
+ const statusCode = typeof b.statusCode === "number" ? b.statusCode : status;
8
+ return { name, message, statusCode };
9
+ }
10
+ return {
11
+ name: "application_error",
12
+ message: `Request failed with status ${status}`,
13
+ statusCode: status,
14
+ };
15
+ }
16
+ //# sourceMappingURL=error.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error.js","sourceRoot":"","sources":["../src/error.ts"],"names":[],"mappings":"AAiBA,sEAAsE;AACtE,MAAM,UAAU,eAAe,CAAC,IAAa,EAAE,MAAc;IAC3D,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QACrC,MAAM,CAAC,GAAG,IAA+B,CAAC;QAC1C,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,mBAAmB,CAAC;QACvE,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,8BAA8B,MAAM,EAAE,CAAC;QACnG,MAAM,UAAU,GAAG,OAAO,CAAC,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC;QAC5E,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;IACvC,CAAC;IACD,OAAO;QACL,IAAI,EAAE,mBAAmB;QACzB,OAAO,EAAE,8BAA8B,MAAM,EAAE;QAC/C,UAAU,EAAE,MAAM;KACnB,CAAC;AACJ,CAAC"}
package/dist/http.d.ts ADDED
@@ -0,0 +1,34 @@
1
+ import { type Result } from "./error.js";
2
+ export interface MillionSendOptions {
3
+ /**
4
+ * Your MillionSend instance URL (no trailing slash needed). Falls back to
5
+ * `MILLIONSEND_BASE_URL`, then `http://localhost:3001`. Self-hosted, so there
6
+ * is no cloud default — set this to your deployment in production.
7
+ */
8
+ baseUrl?: string;
9
+ /** Inject a fetch implementation (tests, proxies, custom agents). */
10
+ fetch?: typeof fetch;
11
+ /** Extra User-Agent suffix appended after the SDK's own token. */
12
+ userAgent?: string;
13
+ }
14
+ export interface RequestOptions {
15
+ /** POST-only idempotency key (emails.send, batch.send). */
16
+ idempotencyKey?: string;
17
+ }
18
+ interface DoRequest {
19
+ method: "GET" | "POST" | "PATCH" | "DELETE";
20
+ path: string;
21
+ body?: unknown;
22
+ query?: Record<string, string | number | undefined> | undefined;
23
+ idempotencyKey?: string | undefined;
24
+ }
25
+ export declare class HttpClient {
26
+ private readonly apiKey;
27
+ private readonly baseUrl;
28
+ private readonly fetchImpl;
29
+ private readonly userAgent;
30
+ constructor(apiKey: string, options?: MillionSendOptions);
31
+ request<T>({ method, path, body, query, idempotencyKey }: DoRequest): Promise<Result<T>>;
32
+ }
33
+ export {};
34
+ //# sourceMappingURL=http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,MAAM,EAAmB,MAAM,YAAY,CAAC;AAK9E,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;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,2DAA2D;IAC3D,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;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;CACrC;AAYD,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;IACzC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAEvB,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,kBAAuB;IAkBtD,OAAO,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;CA0C/F"}
package/dist/http.js ADDED
@@ -0,0 +1,75 @@
1
+ import { toErrorResponse } from "./error.js";
2
+ const DEFAULT_BASE_URL = "http://localhost:3001";
3
+ const SDK_VERSION = "0.1.0";
4
+ function queryString(query) {
5
+ if (!query)
6
+ return "";
7
+ const params = new URLSearchParams();
8
+ for (const [key, value] of Object.entries(query)) {
9
+ if (value !== undefined)
10
+ params.set(key, String(value));
11
+ }
12
+ const s = params.toString();
13
+ return s ? `?${s}` : "";
14
+ }
15
+ export class HttpClient {
16
+ apiKey;
17
+ baseUrl;
18
+ fetchImpl;
19
+ userAgent;
20
+ constructor(apiKey, options = {}) {
21
+ this.apiKey = apiKey;
22
+ this.baseUrl = (options.baseUrl ?? process.env.MILLIONSEND_BASE_URL ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
23
+ // Bind so a passed-in fetch keeps its own `this`; default to the global.
24
+ const chosen = options.fetch ?? globalThis.fetch;
25
+ if (!chosen) {
26
+ throw new Error("No fetch implementation found. Use Node 18+ or pass `fetch` in the client options.");
27
+ }
28
+ this.fetchImpl = chosen;
29
+ const base = `millionsend-node/${SDK_VERSION}`;
30
+ this.userAgent = options.userAgent ? `${base} ${options.userAgent}` : base;
31
+ }
32
+ async request({ method, path, body, query, idempotencyKey }) {
33
+ const url = `${this.baseUrl}${path}${queryString(query)}`;
34
+ const headers = {
35
+ Authorization: `Bearer ${this.apiKey}`,
36
+ Accept: "application/json",
37
+ "User-Agent": this.userAgent,
38
+ };
39
+ const init = { method, headers };
40
+ if (body !== undefined && method !== "GET" && method !== "DELETE") {
41
+ headers["Content-Type"] = "application/json";
42
+ init.body = JSON.stringify(body);
43
+ }
44
+ // Idempotency is POST-only on the wire; sending it elsewhere is a no-op.
45
+ if (idempotencyKey && method === "POST")
46
+ headers["Idempotency-Key"] = idempotencyKey;
47
+ let response;
48
+ try {
49
+ response = await this.fetchImpl(url, init);
50
+ }
51
+ catch (cause) {
52
+ const error = {
53
+ name: "application_error",
54
+ message: cause instanceof Error ? cause.message : String(cause),
55
+ statusCode: null,
56
+ };
57
+ return { data: null, error };
58
+ }
59
+ const text = await response.text();
60
+ let parsed = null;
61
+ if (text) {
62
+ try {
63
+ parsed = JSON.parse(text);
64
+ }
65
+ catch {
66
+ parsed = text;
67
+ }
68
+ }
69
+ if (!response.ok) {
70
+ return { data: null, error: toErrorResponse(parsed, response.status) };
71
+ }
72
+ return { data: parsed, error: null };
73
+ }
74
+ }
75
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ import { type MillionSendOptions } from "./http.js";
2
+ import { Audiences } from "./resources/audiences.js";
3
+ import { Broadcasts } from "./resources/broadcasts.js";
4
+ import { Contacts } from "./resources/contacts.js";
5
+ import { Batch, Emails } from "./resources/emails.js";
6
+ import { Segments } from "./resources/segments.js";
7
+ import { Topics } from "./resources/topics.js";
8
+ /**
9
+ * The MillionSend client. Construct once and reuse.
10
+ *
11
+ * ```ts
12
+ * import { MillionSend } from "millionsend";
13
+ * const ms = new MillionSend("ms_...", { baseUrl: "https://mail.acme.dev" });
14
+ * const { data, error } = await ms.emails.send({
15
+ * from: "Acme <onboarding@acme.dev>",
16
+ * to: "delivered@resend.dev",
17
+ * subject: "Hello",
18
+ * html: "<strong>it works</strong>",
19
+ * });
20
+ * ```
21
+ *
22
+ * No method throws for an API error — each resolves to `{ data, error }`, with
23
+ * `error` being an {@link ErrorResponse} discriminated by `error.name`. The only
24
+ * throw is a missing API key at construction.
25
+ */
26
+ export declare class MillionSend {
27
+ readonly emails: Emails;
28
+ readonly batch: Batch;
29
+ readonly audiences: Audiences;
30
+ readonly contacts: Contacts;
31
+ readonly broadcasts: Broadcasts;
32
+ readonly topics: Topics;
33
+ readonly segments: Segments;
34
+ constructor(apiKey?: string, options?: MillionSendOptions);
35
+ }
36
+ export default MillionSend;
37
+ export type { ErrorResponse, Result } from "./error.js";
38
+ export type { MillionSendOptions, RequestOptions } from "./http.js";
39
+ export type * from "./types.js";
40
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +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,SAAS,EAAE,MAAM,0BAA0B,CAAC;AACrD,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;AAE/C;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,WAAW;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;gBAEhB,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB;CAgB1D;AAED,eAAe,WAAW,CAAC;AAE3B,YAAY,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACxD,YAAY,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACpE,mBAAmB,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,50 @@
1
+ import { HttpClient } from "./http.js";
2
+ import { Audiences } from "./resources/audiences.js";
3
+ import { Broadcasts } from "./resources/broadcasts.js";
4
+ import { Contacts } from "./resources/contacts.js";
5
+ import { Batch, Emails } from "./resources/emails.js";
6
+ import { Segments } from "./resources/segments.js";
7
+ import { Topics } from "./resources/topics.js";
8
+ /**
9
+ * The MillionSend client. Construct once and reuse.
10
+ *
11
+ * ```ts
12
+ * import { MillionSend } from "millionsend";
13
+ * const ms = new MillionSend("ms_...", { baseUrl: "https://mail.acme.dev" });
14
+ * const { data, error } = await ms.emails.send({
15
+ * from: "Acme <onboarding@acme.dev>",
16
+ * to: "delivered@resend.dev",
17
+ * subject: "Hello",
18
+ * html: "<strong>it works</strong>",
19
+ * });
20
+ * ```
21
+ *
22
+ * No method throws for an API error — each resolves to `{ data, error }`, with
23
+ * `error` being an {@link ErrorResponse} discriminated by `error.name`. The only
24
+ * throw is a missing API key at construction.
25
+ */
26
+ export class MillionSend {
27
+ emails;
28
+ batch;
29
+ audiences;
30
+ contacts;
31
+ broadcasts;
32
+ topics;
33
+ segments;
34
+ constructor(apiKey, options) {
35
+ const key = apiKey ?? process.env.MILLIONSEND_API_KEY;
36
+ if (!key) {
37
+ throw new Error("Missing API key. Pass it to new MillionSend(apiKey) or set MILLIONSEND_API_KEY.");
38
+ }
39
+ const http = new HttpClient(key, options);
40
+ this.emails = new Emails(http);
41
+ this.batch = new Batch(http);
42
+ this.audiences = new Audiences(http);
43
+ this.contacts = new Contacts(http);
44
+ this.broadcasts = new Broadcasts(http);
45
+ this.topics = new Topics(http);
46
+ this.segments = new Segments(http);
47
+ }
48
+ }
49
+ export default MillionSend;
50
+ //# sourceMappingURL=index.js.map
@@ -0,0 +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,SAAS,EAAE,MAAM,0BAA0B,CAAC;AACrD,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;AAE/C;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,OAAO,WAAW;IACb,MAAM,CAAS;IACf,KAAK,CAAQ;IACb,SAAS,CAAY;IACrB,QAAQ,CAAW;IACnB,UAAU,CAAa;IACvB,MAAM,CAAS;IACf,QAAQ,CAAW;IAE5B,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,SAAS,GAAG,IAAI,SAAS,CAAC,IAAI,CAAC,CAAC;QACrC,IAAI,CAAC,QAAQ,GAAG,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC;QACnC,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;IACrC,CAAC;CACF;AAED,eAAe,WAAW,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { ListOptions } from "./types.js";
2
+ /** Flatten keyset list options into the query map (undefined values are dropped). */
3
+ export declare function listQuery(options?: ListOptions): Record<string, string | number | undefined> | undefined;
4
+ //# sourceMappingURL=query.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,qFAAqF;AACrF,wBAAgB,SAAS,CACvB,OAAO,CAAC,EAAE,WAAW,GACpB,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC,GAAG,SAAS,CAGzD"}
package/dist/query.js ADDED
@@ -0,0 +1,7 @@
1
+ /** Flatten keyset list options into the query map (undefined values are dropped). */
2
+ export function listQuery(options) {
3
+ if (!options)
4
+ return undefined;
5
+ return { limit: options.limit, after: options.after, before: options.before };
6
+ }
7
+ //# sourceMappingURL=query.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.js","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"AAEA,qFAAqF;AACrF,MAAM,UAAU,SAAS,CACvB,OAAqB;IAErB,IAAI,CAAC,OAAO;QAAE,OAAO,SAAS,CAAC;IAC/B,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;AAChF,CAAC"}
@@ -0,0 +1,17 @@
1
+ import type { Result } from "../error.js";
2
+ import type { HttpClient } from "../http.js";
3
+ import type { Audience, AudienceListItem, CreateAudienceOptions, List, ListOptions, RemoveAudienceResponse } from "../types.js";
4
+ /**
5
+ * Audiences — named contact lists. Resend-compatible: a migrating app's
6
+ * `audiences.*` calls map straight over. (MillionSend's dynamic-filter
7
+ * `segments` are a separate, richer resource — see `client.segments`.)
8
+ */
9
+ export declare class Audiences {
10
+ private readonly http;
11
+ constructor(http: HttpClient);
12
+ create(payload: CreateAudienceOptions): Promise<Result<Audience>>;
13
+ get(id: string): Promise<Result<Audience>>;
14
+ list(options?: ListOptions): Promise<Result<List<AudienceListItem>>>;
15
+ remove(id: string): Promise<Result<RemoveAudienceResponse>>;
16
+ }
17
+ //# sourceMappingURL=audiences.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audiences.d.ts","sourceRoot":"","sources":["../../src/resources/audiences.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,QAAQ,EACR,gBAAgB,EAChB,qBAAqB,EACrB,IAAI,EACJ,WAAW,EACX,sBAAsB,EACvB,MAAM,aAAa,CAAC;AAErB;;;;GAIG;AACH,qBAAa,SAAS;IACR,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,UAAU;IAE7C,MAAM,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAIjE,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAI1C,IAAI,CAAC,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;IAIpE,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAC;CAG5D"}
@@ -0,0 +1,25 @@
1
+ import { listQuery } from "../query.js";
2
+ /**
3
+ * Audiences — named contact lists. Resend-compatible: a migrating app's
4
+ * `audiences.*` calls map straight over. (MillionSend's dynamic-filter
5
+ * `segments` are a separate, richer resource — see `client.segments`.)
6
+ */
7
+ export class Audiences {
8
+ http;
9
+ constructor(http) {
10
+ this.http = http;
11
+ }
12
+ create(payload) {
13
+ return this.http.request({ method: "POST", path: "/audiences", body: { name: payload.name } });
14
+ }
15
+ get(id) {
16
+ return this.http.request({ method: "GET", path: `/audiences/${encodeURIComponent(id)}` });
17
+ }
18
+ list(options) {
19
+ return this.http.request({ method: "GET", path: "/audiences", query: listQuery(options) });
20
+ }
21
+ remove(id) {
22
+ return this.http.request({ method: "DELETE", path: `/audiences/${encodeURIComponent(id)}` });
23
+ }
24
+ }
25
+ //# sourceMappingURL=audiences.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audiences.js","sourceRoot":"","sources":["../../src/resources/audiences.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAUxC;;;;GAIG;AACH,MAAM,OAAO,SAAS;IACS;IAA7B,YAA6B,IAAgB;QAAhB,SAAI,GAAJ,IAAI,CAAY;IAAG,CAAC;IAEjD,MAAM,CAAC,OAA8B;QACnC,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACjG,CAAC;IAED,GAAG,CAAC,EAAU;QACZ,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,cAAc,kBAAkB,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;IAC5F,CAAC;IAED,IAAI,CAAC,OAAqB;QACxB,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC7F,CAAC;IAED,MAAM,CAAC,EAAU;QACf,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,cAAc,kBAAkB,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;IAC/F,CAAC;CACF"}
@@ -0,0 +1,16 @@
1
+ import type { Result } from "../error.js";
2
+ import type { HttpClient } from "../http.js";
3
+ import type { Broadcast, BroadcastId, BroadcastListItem, CancelBroadcastResponse, CreateBroadcastOptions, List, ListOptions, RemoveBroadcastResponse, SendBroadcastOptions, UpdateBroadcastOptions } from "../types.js";
4
+ export declare class Broadcasts {
5
+ private readonly http;
6
+ constructor(http: HttpClient);
7
+ create(payload: CreateBroadcastOptions): Promise<Result<BroadcastId>>;
8
+ get(id: string): Promise<Result<Broadcast>>;
9
+ list(options?: ListOptions): Promise<Result<List<BroadcastListItem>>>;
10
+ update(id: string, payload: UpdateBroadcastOptions): Promise<Result<BroadcastId>>;
11
+ remove(id: string): Promise<Result<RemoveBroadcastResponse>>;
12
+ /** POST /broadcasts/:id/send — omit scheduledAt to send now. */
13
+ send(id: string, options?: SendBroadcastOptions): Promise<Result<BroadcastId>>;
14
+ cancel(id: string): Promise<Result<CancelBroadcastResponse>>;
15
+ }
16
+ //# sourceMappingURL=broadcasts.d.ts.map
@@ -0,0 +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;AAgBrB,qBAAa,UAAU;IACT,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,UAAU;IAE7C,MAAM,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IAIrE,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"}
@@ -0,0 +1,54 @@
1
+ import { listQuery } from "../query.js";
2
+ function toWire(o) {
3
+ return {
4
+ name: o.name,
5
+ audience_id: o.audienceId,
6
+ segment_id: o.segmentId,
7
+ from: o.from,
8
+ subject: o.subject,
9
+ html: o.html,
10
+ text: o.text,
11
+ reply_to: o.replyTo,
12
+ topic_id: o.topicId,
13
+ };
14
+ }
15
+ export class Broadcasts {
16
+ http;
17
+ constructor(http) {
18
+ this.http = http;
19
+ }
20
+ create(payload) {
21
+ return this.http.request({ method: "POST", path: "/broadcasts", body: toWire(payload) });
22
+ }
23
+ get(id) {
24
+ return this.http.request({ method: "GET", path: `/broadcasts/${encodeURIComponent(id)}` });
25
+ }
26
+ list(options) {
27
+ return this.http.request({ method: "GET", path: "/broadcasts", query: listQuery(options) });
28
+ }
29
+ update(id, payload) {
30
+ return this.http.request({
31
+ method: "PATCH",
32
+ path: `/broadcasts/${encodeURIComponent(id)}`,
33
+ body: toWire(payload),
34
+ });
35
+ }
36
+ remove(id) {
37
+ return this.http.request({ method: "DELETE", path: `/broadcasts/${encodeURIComponent(id)}` });
38
+ }
39
+ /** POST /broadcasts/:id/send — omit scheduledAt to send now. */
40
+ send(id, options = {}) {
41
+ return this.http.request({
42
+ method: "POST",
43
+ path: `/broadcasts/${encodeURIComponent(id)}/send`,
44
+ body: { scheduled_at: options.scheduledAt },
45
+ });
46
+ }
47
+ cancel(id) {
48
+ return this.http.request({
49
+ method: "POST",
50
+ path: `/broadcasts/${encodeURIComponent(id)}/cancel`,
51
+ });
52
+ }
53
+ }
54
+ //# sourceMappingURL=broadcasts.js.map
@@ -0,0 +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,CAAkD;IAChE,OAAO;QACL,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,WAAW,EAAE,CAAC,CAAC,UAAU;QACzB,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,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,MAAM,CAAC,OAA+B;QACpC,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC3F,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,22 @@
1
+ import type { Result } from "../error.js";
2
+ import type { HttpClient } from "../http.js";
3
+ import type { Contact, ContactAddress, ContactId, ContactListItem, CreateContactOptions, List, ListOptions, RemoveContactResponse, UpdateContactOptions, UpdateContactTopicsOptions, UpdateContactTopicsResponse } from "../types.js";
4
+ /** Per-contact topic subscriptions (opt in/out of a topic). */
5
+ export declare class ContactTopics {
6
+ private readonly http;
7
+ constructor(http: HttpClient);
8
+ update(options: UpdateContactTopicsOptions): Promise<Result<UpdateContactTopicsResponse>>;
9
+ }
10
+ export declare class Contacts {
11
+ private readonly http;
12
+ readonly topics: ContactTopics;
13
+ constructor(http: HttpClient);
14
+ create(payload: CreateContactOptions): Promise<Result<ContactId>>;
15
+ get(address: string | ContactAddress): Promise<Result<Contact>>;
16
+ update(options: UpdateContactOptions): Promise<Result<ContactId>>;
17
+ remove(address: string | ContactAddress): Promise<Result<RemoveContactResponse>>;
18
+ list(options?: ListOptions & {
19
+ audienceId?: string;
20
+ }): Promise<Result<List<ContactListItem>>>;
21
+ }
22
+ //# sourceMappingURL=contacts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contacts.d.ts","sourceRoot":"","sources":["../../src/resources/contacts.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,OAAO,EACP,cAAc,EACd,SAAS,EACT,eAAe,EACf,oBAAoB,EACpB,IAAI,EACJ,WAAW,EACX,qBAAqB,EACrB,oBAAoB,EACpB,0BAA0B,EAC1B,2BAA2B,EAC5B,MAAM,aAAa,CAAC;AAiCrB,+DAA+D;AAC/D,qBAAa,aAAa;IACZ,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,UAAU;IAE7C,MAAM,CAAC,OAAO,EAAE,0BAA0B,GAAG,OAAO,CAAC,MAAM,CAAC,2BAA2B,CAAC,CAAC;CAQ1F;AAED,qBAAa,QAAQ;IAGP,OAAO,CAAC,QAAQ,CAAC,IAAI;IAFjC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;gBAEF,IAAI,EAAE,UAAU;IAI7C,MAAM,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAOjE,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAI/D,MAAM,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAIjE,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC;IAIhF,IAAI,CAAC,OAAO,CAAC,EAAE,WAAW,GAAG;QAAE,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC;CAM9F"}