@easybits.cloud/mailmask 0.1.4 → 0.2.1

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 CHANGED
@@ -13,7 +13,7 @@ npm i @easybits.cloud/mailmask
13
13
  ```ts
14
14
  import { MailMask } from "@easybits.cloud/mailmask";
15
15
 
16
- const mm = new MailMask({ apiKey: "mm_live_..." });
16
+ const mm = new MailMask({ apiKey: "mk_..." });
17
17
 
18
18
  // Get your domains
19
19
  const domains = await mm.domains.list();
@@ -21,13 +21,14 @@ const domainId = domains[0].id;
21
21
 
22
22
  // Create an alias — emails to hello@yourdomain.com forward to your inbox
23
23
  const alias = await mm.aliases.create(domainId, {
24
- local: "hello",
24
+ alias: "hello",
25
25
  destinations: ["you@example.com"],
26
26
  });
27
27
 
28
28
  // Send an email (routed through MailMask for high deliverability)
29
29
  await mm.send.send(domainId, {
30
- from: "hello",
30
+ from: "hello", // must be an active alias; defaults to `noreply`
31
+ fromName: "Acme", // optional display name: Acme <hello@yourdomain.com>
31
32
  to: "client@example.com",
32
33
  subject: "Welcome!",
33
34
  html: "<p>Thanks for signing up.</p>",
package/dist/index.cjs CHANGED
@@ -33,8 +33,8 @@ var MailMaskError = class extends Error {
33
33
  this.name = "MailMaskError";
34
34
  }
35
35
  };
36
- async function request(baseUrl, apiKey, path, opts) {
37
- const res = await fetch(`${baseUrl}${path}`, {
36
+ async function request(baseUrl, apiKey, path, opts, doFetch = fetch) {
37
+ const res = await doFetch(`${baseUrl}${path}`, {
38
38
  ...opts,
39
39
  headers: {
40
40
  "Authorization": `Bearer ${apiKey}`,
@@ -52,7 +52,8 @@ var MailMask = class {
52
52
  constructor(config) {
53
53
  this.apiKey = config.apiKey;
54
54
  this.baseUrl = (config.baseUrl || "https://www.mailmask.studio").replace(/\/$/, "");
55
- const req = (path, opts) => request(this.baseUrl, this.apiKey, path, opts);
55
+ const doFetch = config.fetch ? config.fetch : fetch;
56
+ const req = (path, opts) => request(this.baseUrl, this.apiKey, path, opts, doFetch);
56
57
  this.domains = new DomainsResource(req);
57
58
  this.aliases = new AliasesResource(req);
58
59
  this.rules = new RulesResource(req);
@@ -90,16 +91,16 @@ var AliasesResource = class {
90
91
  this.req = req;
91
92
  }
92
93
  list(domainId) {
93
- return this.req(`/api/domains/${domainId}/aliases`);
94
+ return this.req(`/api/domains/${domainId}/alias`);
94
95
  }
95
96
  create(domainId, input) {
96
- return this.req(`/api/domains/${domainId}/aliases`, { method: "POST", body: JSON.stringify(input) });
97
+ return this.req(`/api/domains/${domainId}/alias`, { method: "POST", body: JSON.stringify(input) });
97
98
  }
98
99
  update(domainId, alias, input) {
99
- return this.req(`/api/domains/${domainId}/aliases/${alias}`, { method: "PUT", body: JSON.stringify(input) });
100
+ return this.req(`/api/domains/${domainId}/alias/${alias}`, { method: "PUT", body: JSON.stringify(input) });
100
101
  }
101
102
  delete(domainId, alias) {
102
- return this.req(`/api/domains/${domainId}/aliases/${alias}`, { method: "DELETE" });
103
+ return this.req(`/api/domains/${domainId}/alias/${alias}`, { method: "DELETE" });
103
104
  }
104
105
  };
105
106
  var RulesResource = class {
@@ -135,10 +136,10 @@ var SendResource = class {
135
136
  return this.req(`/api/domains/${domainId}/send`, { method: "POST", body: JSON.stringify(input) });
136
137
  }
137
138
  bulkSend(domainId, input) {
138
- return this.req(`/api/domains/${domainId}/bulk-send`, { method: "POST", body: JSON.stringify(input) });
139
+ return this.req(`/api/domains/${domainId}/send-bulk`, { method: "POST", body: JSON.stringify(input) });
139
140
  }
140
141
  bulkStatus(domainId, jobId) {
141
- return this.req(`/api/domains/${domainId}/bulk-send/${jobId}`);
142
+ return this.req(`/api/domains/${domainId}/bulk/${jobId}`);
142
143
  }
143
144
  };
144
145
  var SmtpResource = class {
package/dist/index.d.cts CHANGED
@@ -1,6 +1,12 @@
1
1
  interface MailMaskConfig {
2
2
  apiKey: string;
3
3
  baseUrl?: string;
4
+ /**
5
+ * `fetch` alterno. Sirve para poner un timeout por llamada
6
+ * (`AbortSignal.timeout`), reintentos o un proxy, y para probar el SDK
7
+ * contra el servidor en proceso sin levantar un puerto.
8
+ */
9
+ fetch?: typeof fetch;
4
10
  }
5
11
  interface Domain {
6
12
  id: string;
@@ -9,6 +15,15 @@ interface Domain {
9
15
  mxConfigured: boolean;
10
16
  createdAt: string;
11
17
  }
18
+ /** Respuesta de `domains.verify`. */
19
+ interface DomainVerification {
20
+ domain: string;
21
+ verified: boolean;
22
+ dkimVerified: boolean;
23
+ /** true cuando no se pudo consultar a SES: los campos son el último estado conocido. */
24
+ stale?: boolean;
25
+ error?: string;
26
+ }
12
27
  interface Alias {
13
28
  alias: string;
14
29
  domainId: string;
@@ -18,8 +33,9 @@ interface Alias {
18
33
  createdAt: string;
19
34
  }
20
35
  interface CreateAliasInput {
21
- local: string;
22
- forwardTo: string | string[];
36
+ /** Parte local, sin el dominio: "hola" para hola@tudominio.com. `*` para catch-all. */
37
+ alias: string;
38
+ destinations: string[];
23
39
  }
24
40
  interface UpdateAliasInput {
25
41
  enabled?: boolean;
@@ -66,23 +82,49 @@ interface EmailLog {
66
82
  error?: string;
67
83
  }
68
84
  interface SendEmailInput {
69
- fromLocal: string;
70
85
  to: string;
71
86
  subject: string;
72
- html: string;
87
+ /** Al menos uno de `html` o `body`. Con los dos se manda multipart. */
88
+ html?: string;
89
+ body?: string;
90
+ replyTo?: string;
91
+ /**
92
+ * Parte local de un alias **activo** del dominio. Sin esto el correo sale
93
+ * desde `noreply@tudominio.com`.
94
+ */
95
+ from?: string;
96
+ /** Nombre visible del remitente: `Libretas <hola@tudominio.com>`. */
97
+ fromName?: string;
73
98
  }
74
99
  interface BulkSendInput {
75
- from: string;
76
100
  recipients: string[];
77
101
  subject: string;
78
102
  html: string;
103
+ /** Alias activo del dominio; por omisión `noreply`. */
104
+ from?: string;
105
+ }
106
+ /** Lo que devuelve `bulkSend`: el job se encola, todavía no hay estado que leer. */
107
+ interface BulkJobCreated {
108
+ ok: boolean;
109
+ jobId: string;
79
110
  }
80
111
  interface BulkJob {
81
112
  id: string;
113
+ domainId: string;
114
+ recipients: string[];
115
+ subject: string;
116
+ html: string;
117
+ from: string;
82
118
  status: string;
83
119
  totalRecipients: number;
84
120
  sent: number;
85
121
  failed: number;
122
+ /** Destinatarios saltados por bounce o queja previa: total = sent + failed + skippedSuppressed. */
123
+ skippedSuppressed: number;
124
+ lastError?: string | null;
125
+ createdAt: string;
126
+ completedAt?: string | null;
127
+ expiresAt: string;
86
128
  }
87
129
  interface SmtpCredential {
88
130
  id: string;
@@ -91,6 +133,20 @@ interface SmtpCredential {
91
133
  iamUsername: string;
92
134
  createdAt: string;
93
135
  }
136
+ /**
137
+ * Lo que devuelve `smtp.create`. La contraseña se muestra **una sola vez**: no
138
+ * se puede volver a consultar, sólo revocar la credencial y crear otra.
139
+ */
140
+ interface SmtpCredentialCreated {
141
+ id: string;
142
+ label: string;
143
+ server: string;
144
+ port: number;
145
+ encryption: string;
146
+ username: string;
147
+ password: string;
148
+ createdAt: string;
149
+ }
94
150
  interface ApiKey {
95
151
  id: string;
96
152
  name: string;
@@ -127,7 +183,7 @@ declare class DomainsResource {
127
183
  ok: boolean;
128
184
  }>;
129
185
  health(id: string): Promise<Record<string, unknown>>;
130
- verify(id: string): Promise<Record<string, unknown>>;
186
+ verify(id: string): Promise<DomainVerification>;
131
187
  }
132
188
  declare class AliasesResource {
133
189
  private req;
@@ -160,16 +216,14 @@ declare class SendResource {
160
216
  send(domainId: string, input: SendEmailInput): Promise<{
161
217
  messageId: string;
162
218
  }>;
163
- bulkSend(domainId: string, input: BulkSendInput): Promise<BulkJob>;
219
+ bulkSend(domainId: string, input: BulkSendInput): Promise<BulkJobCreated>;
164
220
  bulkStatus(domainId: string, jobId: string): Promise<BulkJob>;
165
221
  }
166
222
  declare class SmtpResource {
167
223
  private req;
168
224
  constructor(req: Req);
169
225
  list(domainId: string): Promise<SmtpCredential[]>;
170
- create(domainId: string, label: string): Promise<SmtpCredential & {
171
- smtpPassword: string;
172
- }>;
226
+ create(domainId: string, label: string): Promise<SmtpCredentialCreated>;
173
227
  revoke(domainId: string, credId: string): Promise<{
174
228
  ok: boolean;
175
229
  }>;
@@ -186,4 +240,4 @@ declare class ApiKeysResource {
186
240
  }>;
187
241
  }
188
242
 
189
- export { type Alias, type ApiKey, type BulkJob, type BulkSendInput, type CreateAliasInput, type CreateRuleInput, type Domain, type EmailLog, MailMask, type MailMaskConfig, MailMaskError, type Rule, type SendEmailInput, type SmtpCredential, type UpdateAliasInput, type UpdateRuleInput };
243
+ export { type Alias, type ApiKey, type BulkJob, type BulkJobCreated, type BulkSendInput, type CreateAliasInput, type CreateRuleInput, type Domain, type DomainVerification, type EmailLog, MailMask, type MailMaskConfig, MailMaskError, type Rule, type SendEmailInput, type SmtpCredential, type SmtpCredentialCreated, type UpdateAliasInput, type UpdateRuleInput };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,12 @@
1
1
  interface MailMaskConfig {
2
2
  apiKey: string;
3
3
  baseUrl?: string;
4
+ /**
5
+ * `fetch` alterno. Sirve para poner un timeout por llamada
6
+ * (`AbortSignal.timeout`), reintentos o un proxy, y para probar el SDK
7
+ * contra el servidor en proceso sin levantar un puerto.
8
+ */
9
+ fetch?: typeof fetch;
4
10
  }
5
11
  interface Domain {
6
12
  id: string;
@@ -9,6 +15,15 @@ interface Domain {
9
15
  mxConfigured: boolean;
10
16
  createdAt: string;
11
17
  }
18
+ /** Respuesta de `domains.verify`. */
19
+ interface DomainVerification {
20
+ domain: string;
21
+ verified: boolean;
22
+ dkimVerified: boolean;
23
+ /** true cuando no se pudo consultar a SES: los campos son el último estado conocido. */
24
+ stale?: boolean;
25
+ error?: string;
26
+ }
12
27
  interface Alias {
13
28
  alias: string;
14
29
  domainId: string;
@@ -18,8 +33,9 @@ interface Alias {
18
33
  createdAt: string;
19
34
  }
20
35
  interface CreateAliasInput {
21
- local: string;
22
- forwardTo: string | string[];
36
+ /** Parte local, sin el dominio: "hola" para hola@tudominio.com. `*` para catch-all. */
37
+ alias: string;
38
+ destinations: string[];
23
39
  }
24
40
  interface UpdateAliasInput {
25
41
  enabled?: boolean;
@@ -66,23 +82,49 @@ interface EmailLog {
66
82
  error?: string;
67
83
  }
68
84
  interface SendEmailInput {
69
- fromLocal: string;
70
85
  to: string;
71
86
  subject: string;
72
- html: string;
87
+ /** Al menos uno de `html` o `body`. Con los dos se manda multipart. */
88
+ html?: string;
89
+ body?: string;
90
+ replyTo?: string;
91
+ /**
92
+ * Parte local de un alias **activo** del dominio. Sin esto el correo sale
93
+ * desde `noreply@tudominio.com`.
94
+ */
95
+ from?: string;
96
+ /** Nombre visible del remitente: `Libretas <hola@tudominio.com>`. */
97
+ fromName?: string;
73
98
  }
74
99
  interface BulkSendInput {
75
- from: string;
76
100
  recipients: string[];
77
101
  subject: string;
78
102
  html: string;
103
+ /** Alias activo del dominio; por omisión `noreply`. */
104
+ from?: string;
105
+ }
106
+ /** Lo que devuelve `bulkSend`: el job se encola, todavía no hay estado que leer. */
107
+ interface BulkJobCreated {
108
+ ok: boolean;
109
+ jobId: string;
79
110
  }
80
111
  interface BulkJob {
81
112
  id: string;
113
+ domainId: string;
114
+ recipients: string[];
115
+ subject: string;
116
+ html: string;
117
+ from: string;
82
118
  status: string;
83
119
  totalRecipients: number;
84
120
  sent: number;
85
121
  failed: number;
122
+ /** Destinatarios saltados por bounce o queja previa: total = sent + failed + skippedSuppressed. */
123
+ skippedSuppressed: number;
124
+ lastError?: string | null;
125
+ createdAt: string;
126
+ completedAt?: string | null;
127
+ expiresAt: string;
86
128
  }
87
129
  interface SmtpCredential {
88
130
  id: string;
@@ -91,6 +133,20 @@ interface SmtpCredential {
91
133
  iamUsername: string;
92
134
  createdAt: string;
93
135
  }
136
+ /**
137
+ * Lo que devuelve `smtp.create`. La contraseña se muestra **una sola vez**: no
138
+ * se puede volver a consultar, sólo revocar la credencial y crear otra.
139
+ */
140
+ interface SmtpCredentialCreated {
141
+ id: string;
142
+ label: string;
143
+ server: string;
144
+ port: number;
145
+ encryption: string;
146
+ username: string;
147
+ password: string;
148
+ createdAt: string;
149
+ }
94
150
  interface ApiKey {
95
151
  id: string;
96
152
  name: string;
@@ -127,7 +183,7 @@ declare class DomainsResource {
127
183
  ok: boolean;
128
184
  }>;
129
185
  health(id: string): Promise<Record<string, unknown>>;
130
- verify(id: string): Promise<Record<string, unknown>>;
186
+ verify(id: string): Promise<DomainVerification>;
131
187
  }
132
188
  declare class AliasesResource {
133
189
  private req;
@@ -160,16 +216,14 @@ declare class SendResource {
160
216
  send(domainId: string, input: SendEmailInput): Promise<{
161
217
  messageId: string;
162
218
  }>;
163
- bulkSend(domainId: string, input: BulkSendInput): Promise<BulkJob>;
219
+ bulkSend(domainId: string, input: BulkSendInput): Promise<BulkJobCreated>;
164
220
  bulkStatus(domainId: string, jobId: string): Promise<BulkJob>;
165
221
  }
166
222
  declare class SmtpResource {
167
223
  private req;
168
224
  constructor(req: Req);
169
225
  list(domainId: string): Promise<SmtpCredential[]>;
170
- create(domainId: string, label: string): Promise<SmtpCredential & {
171
- smtpPassword: string;
172
- }>;
226
+ create(domainId: string, label: string): Promise<SmtpCredentialCreated>;
173
227
  revoke(domainId: string, credId: string): Promise<{
174
228
  ok: boolean;
175
229
  }>;
@@ -186,4 +240,4 @@ declare class ApiKeysResource {
186
240
  }>;
187
241
  }
188
242
 
189
- export { type Alias, type ApiKey, type BulkJob, type BulkSendInput, type CreateAliasInput, type CreateRuleInput, type Domain, type EmailLog, MailMask, type MailMaskConfig, MailMaskError, type Rule, type SendEmailInput, type SmtpCredential, type UpdateAliasInput, type UpdateRuleInput };
243
+ export { type Alias, type ApiKey, type BulkJob, type BulkJobCreated, type BulkSendInput, type CreateAliasInput, type CreateRuleInput, type Domain, type DomainVerification, type EmailLog, MailMask, type MailMaskConfig, MailMaskError, type Rule, type SendEmailInput, type SmtpCredential, type SmtpCredentialCreated, type UpdateAliasInput, type UpdateRuleInput };
package/dist/index.js CHANGED
@@ -6,8 +6,8 @@ var MailMaskError = class extends Error {
6
6
  this.name = "MailMaskError";
7
7
  }
8
8
  };
9
- async function request(baseUrl, apiKey, path, opts) {
10
- const res = await fetch(`${baseUrl}${path}`, {
9
+ async function request(baseUrl, apiKey, path, opts, doFetch = fetch) {
10
+ const res = await doFetch(`${baseUrl}${path}`, {
11
11
  ...opts,
12
12
  headers: {
13
13
  "Authorization": `Bearer ${apiKey}`,
@@ -25,7 +25,8 @@ var MailMask = class {
25
25
  constructor(config) {
26
26
  this.apiKey = config.apiKey;
27
27
  this.baseUrl = (config.baseUrl || "https://www.mailmask.studio").replace(/\/$/, "");
28
- const req = (path, opts) => request(this.baseUrl, this.apiKey, path, opts);
28
+ const doFetch = config.fetch ? config.fetch : fetch;
29
+ const req = (path, opts) => request(this.baseUrl, this.apiKey, path, opts, doFetch);
29
30
  this.domains = new DomainsResource(req);
30
31
  this.aliases = new AliasesResource(req);
31
32
  this.rules = new RulesResource(req);
@@ -63,16 +64,16 @@ var AliasesResource = class {
63
64
  this.req = req;
64
65
  }
65
66
  list(domainId) {
66
- return this.req(`/api/domains/${domainId}/aliases`);
67
+ return this.req(`/api/domains/${domainId}/alias`);
67
68
  }
68
69
  create(domainId, input) {
69
- return this.req(`/api/domains/${domainId}/aliases`, { method: "POST", body: JSON.stringify(input) });
70
+ return this.req(`/api/domains/${domainId}/alias`, { method: "POST", body: JSON.stringify(input) });
70
71
  }
71
72
  update(domainId, alias, input) {
72
- return this.req(`/api/domains/${domainId}/aliases/${alias}`, { method: "PUT", body: JSON.stringify(input) });
73
+ return this.req(`/api/domains/${domainId}/alias/${alias}`, { method: "PUT", body: JSON.stringify(input) });
73
74
  }
74
75
  delete(domainId, alias) {
75
- return this.req(`/api/domains/${domainId}/aliases/${alias}`, { method: "DELETE" });
76
+ return this.req(`/api/domains/${domainId}/alias/${alias}`, { method: "DELETE" });
76
77
  }
77
78
  };
78
79
  var RulesResource = class {
@@ -108,10 +109,10 @@ var SendResource = class {
108
109
  return this.req(`/api/domains/${domainId}/send`, { method: "POST", body: JSON.stringify(input) });
109
110
  }
110
111
  bulkSend(domainId, input) {
111
- return this.req(`/api/domains/${domainId}/bulk-send`, { method: "POST", body: JSON.stringify(input) });
112
+ return this.req(`/api/domains/${domainId}/send-bulk`, { method: "POST", body: JSON.stringify(input) });
112
113
  }
113
114
  bulkStatus(domainId, jobId) {
114
- return this.req(`/api/domains/${domainId}/bulk-send/${jobId}`);
115
+ return this.req(`/api/domains/${domainId}/bulk/${jobId}`);
115
116
  }
116
117
  };
117
118
  var SmtpResource = class {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@easybits.cloud/mailmask",
3
- "version": "0.1.4",
3
+ "version": "0.2.1",
4
4
  "description": "Official SDK for the MailMask email alias/forwarding API",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",