@tratto/email 1.0.0 → 1.1.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
@@ -34,6 +34,22 @@ const { id } = await tratto.emails.send({
34
34
  console.log('Sent email:', id);
35
35
  ```
36
36
 
37
+ Or write the email in [emailmd](https://www.emailmd.dev/) markdown — the API
38
+ renders it into responsive, email-safe HTML (plus a text part) server-side:
39
+
40
+ ```ts
41
+ await tratto.emails.send({
42
+ from: 'Acme <hello@mail.acme.com>',
43
+ to: 'user@example.com',
44
+ subject: 'Welcome!',
45
+ markdown: '# Welcome, {{firstName}}\n\nGlad to have you on board.',
46
+ });
47
+ ```
48
+
49
+ `markdown` is mutually exclusive with `html`. Templates accept it too:
50
+ `templates.create({ name, markdown })` creates a `format: 'emailmd'` template
51
+ whose HTML is rendered and pinned at save time.
52
+
37
53
  ---
38
54
 
39
55
  ## Setup
@@ -265,6 +281,16 @@ await tratto.templates.testSend(tpl.id, 'me@example.com', { name: 'Alice' });
265
281
  await tratto.templates.delete(tpl.id);
266
282
  ```
267
283
 
284
+ Templates created from `markdown` come back with `format: 'emailmd'`, the
285
+ markdown in `source`, the rendered HTML in `html`, and — when part of the
286
+ markdown could not be rendered — a `renderWarnings: string[]` array on the
287
+ template object. The field is absent when there is nothing to report:
288
+
289
+ ```ts
290
+ const tpl = await tratto.templates.create({ name: 'Welcome', markdown: '# Hi {{name}}' });
291
+ if (tpl.renderWarnings?.length) console.warn(tpl.renderWarnings);
292
+ ```
293
+
268
294
  ---
269
295
 
270
296
  ### Webhooks
@@ -326,7 +352,9 @@ console.log('Open rate:', summary.openRate);
326
352
  const points = await tratto.analytics.getTimeseries('7d');
327
353
  ```
328
354
 
329
- Supported periods: `'7d'` | `'30d'` | `'90d'`. Results are cached server-side for 1 hour.
355
+ Supported periods: `'7d'` | `'30d'` | `'90d'` | `'180d'` | `'1y'` (default `'30d'`).
356
+ `'180d'` and `'1y'` read the long-term aggregate, which holds live data only:
357
+ they are rejected for test-mode keys. Results are cached server-side for 1 hour.
330
358
 
331
359
  ---
332
360
 
@@ -418,8 +446,6 @@ import type {
418
446
  Template,
419
447
  Webhook,
420
448
  Domain,
421
- ApiKey,
422
- ApiKeyCreated,
423
449
  AnalyticsSummary,
424
450
  TimeseriesPoint,
425
451
  Flow,
package/dist/index.d.mts CHANGED
@@ -32,6 +32,12 @@ interface SendEmailParams {
32
32
  to: string | string[];
33
33
  subject: string;
34
34
  html?: string;
35
+ /**
36
+ * emailmd markdown, rendered server-side into responsive email HTML
37
+ * (plus a text part). Mutually exclusive with `html` — the API rejects
38
+ * requests carrying both.
39
+ */
40
+ markdown?: string;
35
41
  text?: string;
36
42
  cc?: string[];
37
43
  bcc?: string[];
@@ -170,6 +176,14 @@ interface Campaign {
170
176
  sentAt: string | null;
171
177
  stats: CampaignStats;
172
178
  createdAt: string;
179
+ /**
180
+ * The editable markdown of an emailmd campaign (its own copy — editing it
181
+ * never touches the template). Returned by `get()` only: `list()` omits
182
+ * `source` and `renderWarnings` to keep the payload small.
183
+ */
184
+ source?: string;
185
+ /** Markdown that could not be rendered. Returned by `get()` only, absent when empty. */
186
+ renderWarnings?: string[];
173
187
  }
174
188
  interface CampaignStatsDetail {
175
189
  campaignId: string;
@@ -199,6 +213,7 @@ interface ListCampaignsParams {
199
213
  interface SendCampaignParams {
200
214
  scheduledAt?: Date | string;
201
215
  }
216
+ type TemplateFormat = 'html' | 'emailmd';
202
217
  type TemplateStatus = 'draft' | 'published';
203
218
  interface TemplateSummary {
204
219
  id: string;
@@ -209,15 +224,29 @@ interface TemplateSummary {
209
224
  updatedAt: string;
210
225
  }
211
226
  interface Template extends TemplateSummary {
227
+ /** Always the pinned, ready-to-send HTML — for emailmd templates it is derived from `source`. */
212
228
  html: string;
229
+ /** 'html' for templates created before formats existed. Immutable after creation. */
230
+ format: TemplateFormat;
231
+ /** The markdown source of truth for emailmd templates. */
232
+ source?: string;
233
+ renderWarnings?: string[];
213
234
  }
214
235
  interface CreateTemplateParams {
215
236
  name: string;
216
237
  html?: string;
238
+ /**
239
+ * emailmd markdown source. Creates a `format: 'emailmd'` template whose
240
+ * HTML is rendered server-side at save time. Mutually exclusive with
241
+ * `html` — sending both (or `html` on an emailmd template) is rejected.
242
+ */
243
+ markdown?: string;
217
244
  }
218
245
  interface UpdateTemplateParams {
219
246
  name?: string;
220
247
  html?: string;
248
+ /** New markdown source for an emailmd template (re-rendered at save). */
249
+ markdown?: string;
221
250
  status?: TemplateStatus;
222
251
  }
223
252
  interface ListTemplatesParams {
@@ -285,7 +314,8 @@ interface ListDomainsParams {
285
314
  after?: string;
286
315
  limit?: number;
287
316
  }
288
- type AnalyticsPeriod = '7d' | '30d' | '90d';
317
+ /** `'180d'` and `'1y'` read the long-term aggregate (live data only) and are rejected for test-mode keys. */
318
+ type AnalyticsPeriod = '7d' | '30d' | '90d' | '180d' | '1y';
289
319
  interface AnalyticsSummary {
290
320
  period: AnalyticsPeriod;
291
321
  totalSent: number;
@@ -350,6 +380,20 @@ interface Workspace {
350
380
  timezone: string;
351
381
  locale: WorkspaceLocale;
352
382
  plan: WorkspacePlan;
383
+ /** Workspace default sender, used when a send does not specify one. */
384
+ defaultFromName: string | null;
385
+ defaultFromEmail: string | null;
386
+ /**
387
+ * Tenant-hosted unsubscribe/preference page. When set, {{unsubscribe_url}}
388
+ * resolves here instead of the Tratto-hosted page.
389
+ */
390
+ customUnsubscribeUrl: string | null;
391
+ /**
392
+ * Keep the "Sent using Tratto" branded footer on every HTML send even on a
393
+ * paid plan. On the free plan the branded footer is always applied
394
+ * regardless of this flag.
395
+ */
396
+ keepTrattoBranding: boolean;
353
397
  createdAt: string;
354
398
  }
355
399
  interface WorkspaceMember {
@@ -372,6 +416,16 @@ interface UpdateWorkspaceParams {
372
416
  slug?: string;
373
417
  timezone?: string;
374
418
  locale?: WorkspaceLocale;
419
+ defaultFromName?: string;
420
+ defaultFromEmail?: string;
421
+ /** Set to null to clear and fall back to the Tratto-hosted page. */
422
+ customUnsubscribeUrl?: string | null;
423
+ /**
424
+ * Opt in to keep the branded footer on paid plans. Accepted on any plan
425
+ * (no effect on free, where branding is mandatory) and never auto-reset
426
+ * by plan changes.
427
+ */
428
+ keepTrattoBranding?: boolean;
375
429
  }
376
430
  interface UpdateWorkspacePreferencesParams {
377
431
  locale?: WorkspaceLocale;
package/dist/index.d.ts CHANGED
@@ -32,6 +32,12 @@ interface SendEmailParams {
32
32
  to: string | string[];
33
33
  subject: string;
34
34
  html?: string;
35
+ /**
36
+ * emailmd markdown, rendered server-side into responsive email HTML
37
+ * (plus a text part). Mutually exclusive with `html` — the API rejects
38
+ * requests carrying both.
39
+ */
40
+ markdown?: string;
35
41
  text?: string;
36
42
  cc?: string[];
37
43
  bcc?: string[];
@@ -170,6 +176,14 @@ interface Campaign {
170
176
  sentAt: string | null;
171
177
  stats: CampaignStats;
172
178
  createdAt: string;
179
+ /**
180
+ * The editable markdown of an emailmd campaign (its own copy — editing it
181
+ * never touches the template). Returned by `get()` only: `list()` omits
182
+ * `source` and `renderWarnings` to keep the payload small.
183
+ */
184
+ source?: string;
185
+ /** Markdown that could not be rendered. Returned by `get()` only, absent when empty. */
186
+ renderWarnings?: string[];
173
187
  }
174
188
  interface CampaignStatsDetail {
175
189
  campaignId: string;
@@ -199,6 +213,7 @@ interface ListCampaignsParams {
199
213
  interface SendCampaignParams {
200
214
  scheduledAt?: Date | string;
201
215
  }
216
+ type TemplateFormat = 'html' | 'emailmd';
202
217
  type TemplateStatus = 'draft' | 'published';
203
218
  interface TemplateSummary {
204
219
  id: string;
@@ -209,15 +224,29 @@ interface TemplateSummary {
209
224
  updatedAt: string;
210
225
  }
211
226
  interface Template extends TemplateSummary {
227
+ /** Always the pinned, ready-to-send HTML — for emailmd templates it is derived from `source`. */
212
228
  html: string;
229
+ /** 'html' for templates created before formats existed. Immutable after creation. */
230
+ format: TemplateFormat;
231
+ /** The markdown source of truth for emailmd templates. */
232
+ source?: string;
233
+ renderWarnings?: string[];
213
234
  }
214
235
  interface CreateTemplateParams {
215
236
  name: string;
216
237
  html?: string;
238
+ /**
239
+ * emailmd markdown source. Creates a `format: 'emailmd'` template whose
240
+ * HTML is rendered server-side at save time. Mutually exclusive with
241
+ * `html` — sending both (or `html` on an emailmd template) is rejected.
242
+ */
243
+ markdown?: string;
217
244
  }
218
245
  interface UpdateTemplateParams {
219
246
  name?: string;
220
247
  html?: string;
248
+ /** New markdown source for an emailmd template (re-rendered at save). */
249
+ markdown?: string;
221
250
  status?: TemplateStatus;
222
251
  }
223
252
  interface ListTemplatesParams {
@@ -285,7 +314,8 @@ interface ListDomainsParams {
285
314
  after?: string;
286
315
  limit?: number;
287
316
  }
288
- type AnalyticsPeriod = '7d' | '30d' | '90d';
317
+ /** `'180d'` and `'1y'` read the long-term aggregate (live data only) and are rejected for test-mode keys. */
318
+ type AnalyticsPeriod = '7d' | '30d' | '90d' | '180d' | '1y';
289
319
  interface AnalyticsSummary {
290
320
  period: AnalyticsPeriod;
291
321
  totalSent: number;
@@ -350,6 +380,20 @@ interface Workspace {
350
380
  timezone: string;
351
381
  locale: WorkspaceLocale;
352
382
  plan: WorkspacePlan;
383
+ /** Workspace default sender, used when a send does not specify one. */
384
+ defaultFromName: string | null;
385
+ defaultFromEmail: string | null;
386
+ /**
387
+ * Tenant-hosted unsubscribe/preference page. When set, {{unsubscribe_url}}
388
+ * resolves here instead of the Tratto-hosted page.
389
+ */
390
+ customUnsubscribeUrl: string | null;
391
+ /**
392
+ * Keep the "Sent using Tratto" branded footer on every HTML send even on a
393
+ * paid plan. On the free plan the branded footer is always applied
394
+ * regardless of this flag.
395
+ */
396
+ keepTrattoBranding: boolean;
353
397
  createdAt: string;
354
398
  }
355
399
  interface WorkspaceMember {
@@ -372,6 +416,16 @@ interface UpdateWorkspaceParams {
372
416
  slug?: string;
373
417
  timezone?: string;
374
418
  locale?: WorkspaceLocale;
419
+ defaultFromName?: string;
420
+ defaultFromEmail?: string;
421
+ /** Set to null to clear and fall back to the Tratto-hosted page. */
422
+ customUnsubscribeUrl?: string | null;
423
+ /**
424
+ * Opt in to keep the branded footer on paid plans. Accepted on any plan
425
+ * (no effect on free, where branding is mandatory) and never auto-reset
426
+ * by plan changes.
427
+ */
428
+ keepTrattoBranding?: boolean;
375
429
  }
376
430
  interface UpdateWorkspacePreferencesParams {
377
431
  locale?: WorkspaceLocale;
package/dist/index.js CHANGED
@@ -36,6 +36,9 @@ var TrattoError = class extends Error {
36
36
  }
37
37
  };
38
38
 
39
+ // package.json
40
+ var version = "1.1.1";
41
+
39
42
  // src/resources/base.ts
40
43
  var BaseResource = class {
41
44
  constructor(apiKey, baseUrl) {
@@ -47,7 +50,7 @@ var BaseResource = class {
47
50
  const contentType = options?.contentType ?? (hasBody ? "application/json" : void 0);
48
51
  const headers = {
49
52
  Authorization: `Bearer ${this.apiKey}`,
50
- "User-Agent": "@tratto/email/0.1.0",
53
+ "User-Agent": `@tratto/email/${version}`,
51
54
  ...contentType ? { "Content-Type": contentType } : {},
52
55
  ...options?.headers
53
56
  };
@@ -212,7 +215,8 @@ var TemplatesResource = class extends BaseResource {
212
215
  return this.fetch("GET", `/v1/templates${qs}`);
213
216
  }
214
217
  create(params) {
215
- return this.fetchData("POST", "/v1/templates", { body: params });
218
+ const body = params.markdown !== void 0 ? { ...params, format: "emailmd" } : params;
219
+ return this.fetchData("POST", "/v1/templates", { body });
216
220
  }
217
221
  get(id) {
218
222
  return this.fetchData("GET", `/v1/templates/${id}`);
@@ -226,8 +230,8 @@ var TemplatesResource = class extends BaseResource {
226
230
  listVersions(id) {
227
231
  return this.fetchData("GET", `/v1/templates/${id}/versions`);
228
232
  }
229
- getVersion(id, version) {
230
- return this.fetchData("GET", `/v1/templates/${id}/versions/${version}`);
233
+ getVersion(id, version2) {
234
+ return this.fetchData("GET", `/v1/templates/${id}/versions/${version2}`);
231
235
  }
232
236
  testSend(id, to, variables = {}) {
233
237
  return this.fetchData(
package/dist/index.mjs CHANGED
@@ -9,6 +9,9 @@ var TrattoError = class extends Error {
9
9
  }
10
10
  };
11
11
 
12
+ // package.json
13
+ var version = "1.1.1";
14
+
12
15
  // src/resources/base.ts
13
16
  var BaseResource = class {
14
17
  constructor(apiKey, baseUrl) {
@@ -20,7 +23,7 @@ var BaseResource = class {
20
23
  const contentType = options?.contentType ?? (hasBody ? "application/json" : void 0);
21
24
  const headers = {
22
25
  Authorization: `Bearer ${this.apiKey}`,
23
- "User-Agent": "@tratto/email/0.1.0",
26
+ "User-Agent": `@tratto/email/${version}`,
24
27
  ...contentType ? { "Content-Type": contentType } : {},
25
28
  ...options?.headers
26
29
  };
@@ -185,7 +188,8 @@ var TemplatesResource = class extends BaseResource {
185
188
  return this.fetch("GET", `/v1/templates${qs}`);
186
189
  }
187
190
  create(params) {
188
- return this.fetchData("POST", "/v1/templates", { body: params });
191
+ const body = params.markdown !== void 0 ? { ...params, format: "emailmd" } : params;
192
+ return this.fetchData("POST", "/v1/templates", { body });
189
193
  }
190
194
  get(id) {
191
195
  return this.fetchData("GET", `/v1/templates/${id}`);
@@ -199,8 +203,8 @@ var TemplatesResource = class extends BaseResource {
199
203
  listVersions(id) {
200
204
  return this.fetchData("GET", `/v1/templates/${id}/versions`);
201
205
  }
202
- getVersion(id, version) {
203
- return this.fetchData("GET", `/v1/templates/${id}/versions/${version}`);
206
+ getVersion(id, version2) {
207
+ return this.fetchData("GET", `/v1/templates/${id}/versions/${version2}`);
204
208
  }
205
209
  testSend(id, to, variables = {}) {
206
210
  return this.fetchData(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tratto/email",
3
- "version": "1.0.0",
3
+ "version": "1.1.1",
4
4
  "description": "Tratto Node.js SDK \u2014 send transactional and marketing email",
5
5
  "author": "Tratto <hello@tratto.email>",
6
6
  "license": "MIT",