@tratto/email 0.1.0 → 1.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Tratto
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
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
@@ -51,6 +67,45 @@ const tratto = new Tratto(apiKey, options?);
51
67
 
52
68
  ---
53
69
 
70
+ ## Test mode
71
+
72
+ Every workspace can create **test API keys** (`tratto_test_…`) alongside live ones. A test key runs the exact same pipeline — statuses, email timeline, webhooks — but **nothing is actually delivered**: no domain verification needed, no monthly quota consumed (test sends have their own daily cap).
73
+
74
+ ```ts
75
+ const tratto = new Tratto('tratto_test_...');
76
+
77
+ // Works immediately, even with an unverified sender domain
78
+ const { id, livemode } = await tratto.emails.send({
79
+ from: 'Acme <hello@any-domain.dev>',
80
+ to: 'delivered@simulator.tratto.email',
81
+ subject: 'Hello from test mode',
82
+ html: '<p>It works!</p>',
83
+ });
84
+ // livemode === false
85
+ ```
86
+
87
+ ### Simulator addresses
88
+
89
+ The recipient address picks the outcome (any other address simulates a normal delivery):
90
+
91
+ | Recipient | Outcome |
92
+ |---|---|
93
+ | `delivered@simulator.tratto.email` | `delivered` event |
94
+ | `bounced@simulator.tratto.email` | permanent bounce → email ends `failed` |
95
+ | `soft-bounced@simulator.tratto.email` | transient bounce |
96
+ | `complained@simulator.tratto.email` | spam complaint event |
97
+
98
+ ### What to expect
99
+
100
+ - Responses and webhook payloads carry `livemode: false` so your integration can tell test traffic apart.
101
+ - A test key only ever sees test data: listing or fetching emails created with a live key returns 404/empty, and vice versa.
102
+ - Test emails are retained for 7 days.
103
+ - Endpoints that reach real recipients (campaign send, template test-send, flow activation) reject test keys with `403 TEST_MODE_NOT_SUPPORTED`.
104
+
105
+ Switching to production is a one-line change: swap the key for a `tratto_live_…` one (verified sender domain required).
106
+
107
+ ---
108
+
54
109
  ## API Reference
55
110
 
56
111
  All methods return `Promise<T>`. Use `async/await` or `.then()`.
@@ -276,26 +331,6 @@ const { deletedAt } = await tratto.domains.delete(domain.id);
276
331
 
277
332
  ---
278
333
 
279
- ### API Keys
280
-
281
- ```ts
282
- // Create — raw key is shown only once
283
- const key = await tratto.apiKeys.create({
284
- name: 'CI deployment key',
285
- env: 'live',
286
- permissions: ['emails:send'],
287
- });
288
- console.log('Raw key (save this!):', key.key);
289
-
290
- // List (prefix only, never raw token)
291
- const { data } = await tratto.apiKeys.list();
292
-
293
- // Revoke
294
- const { revokedAt } = await tratto.apiKeys.revoke(key.id);
295
- ```
296
-
297
- ---
298
-
299
334
  ### Analytics
300
335
 
301
336
  ```ts
@@ -422,6 +457,9 @@ See the [`examples/`](examples/) folder:
422
457
  | [`campaign.ts`](examples/campaign.ts) | Create, configure, and send a marketing campaign |
423
458
  | [`analytics.ts`](examples/analytics.ts) | Fetch delivery metrics and daily timeseries |
424
459
  | [`webhook.ts`](examples/webhook.ts) | Register a webhook and inspect delivery history |
460
+ | [`nextjs.ts`](examples/nextjs.ts) | Next.js App Router route handler sending a welcome email |
461
+ | [`express.ts`](examples/express.ts) | Express route sending a password-reset email |
462
+ | [`fastify.ts`](examples/fastify.ts) | Fastify route sending an order-confirmation email via template |
425
463
 
426
464
  Run any example with [tsx](https://github.com/privatenumber/tsx):
427
465
 
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[];
@@ -199,6 +205,7 @@ interface ListCampaignsParams {
199
205
  interface SendCampaignParams {
200
206
  scheduledAt?: Date | string;
201
207
  }
208
+ type TemplateFormat = 'html' | 'emailmd';
202
209
  type TemplateStatus = 'draft' | 'published';
203
210
  interface TemplateSummary {
204
211
  id: string;
@@ -209,15 +216,29 @@ interface TemplateSummary {
209
216
  updatedAt: string;
210
217
  }
211
218
  interface Template extends TemplateSummary {
219
+ /** Always the pinned, ready-to-send HTML — for emailmd templates it is derived from `source`. */
212
220
  html: string;
221
+ /** 'html' for templates created before formats existed. Immutable after creation. */
222
+ format: TemplateFormat;
223
+ /** The markdown source of truth for emailmd templates. */
224
+ source?: string;
225
+ renderWarnings?: string[];
213
226
  }
214
227
  interface CreateTemplateParams {
215
228
  name: string;
216
229
  html?: string;
230
+ /**
231
+ * emailmd markdown source. Creates a `format: 'emailmd'` template whose
232
+ * HTML is rendered server-side at save time. Mutually exclusive with
233
+ * `html` — sending both (or `html` on an emailmd template) is rejected.
234
+ */
235
+ markdown?: string;
217
236
  }
218
237
  interface UpdateTemplateParams {
219
238
  name?: string;
220
239
  html?: string;
240
+ /** New markdown source for an emailmd template (re-rendered at save). */
241
+ markdown?: string;
221
242
  status?: TemplateStatus;
222
243
  }
223
244
  interface ListTemplatesParams {
@@ -285,29 +306,6 @@ interface ListDomainsParams {
285
306
  after?: string;
286
307
  limit?: number;
287
308
  }
288
- type ApiKeyEnv = 'live' | 'test';
289
- interface ApiKey {
290
- id: string;
291
- name: string;
292
- prefix: string;
293
- env: ApiKeyEnv;
294
- permissions: string[];
295
- createdAt: string;
296
- lastUsedAt: string | null;
297
- revokedAt: string | null;
298
- }
299
- interface ApiKeyCreated extends ApiKey {
300
- key: string;
301
- }
302
- interface CreateApiKeyParams {
303
- name: string;
304
- env: ApiKeyEnv;
305
- permissions: string[];
306
- }
307
- interface ListApiKeysParams {
308
- after?: string;
309
- limit?: number;
310
- }
311
309
  type AnalyticsPeriod = '7d' | '30d' | '90d';
312
310
  interface AnalyticsSummary {
313
311
  period: AnalyticsPeriod;
@@ -373,6 +371,20 @@ interface Workspace {
373
371
  timezone: string;
374
372
  locale: WorkspaceLocale;
375
373
  plan: WorkspacePlan;
374
+ /** Workspace default sender, used when a send does not specify one. */
375
+ defaultFromName: string | null;
376
+ defaultFromEmail: string | null;
377
+ /**
378
+ * Tenant-hosted unsubscribe/preference page. When set, {{unsubscribe_url}}
379
+ * resolves here instead of the Tratto-hosted page.
380
+ */
381
+ customUnsubscribeUrl: string | null;
382
+ /**
383
+ * Keep the "Sent using Tratto" branded footer on every HTML send even on a
384
+ * paid plan. On the free plan the branded footer is always applied
385
+ * regardless of this flag.
386
+ */
387
+ keepTrattoBranding: boolean;
376
388
  createdAt: string;
377
389
  }
378
390
  interface WorkspaceMember {
@@ -395,6 +407,16 @@ interface UpdateWorkspaceParams {
395
407
  slug?: string;
396
408
  timezone?: string;
397
409
  locale?: WorkspaceLocale;
410
+ defaultFromName?: string;
411
+ defaultFromEmail?: string;
412
+ /** Set to null to clear and fall back to the Tratto-hosted page. */
413
+ customUnsubscribeUrl?: string | null;
414
+ /**
415
+ * Opt in to keep the branded footer on paid plans. Accepted on any plan
416
+ * (no effect on free, where branding is mandatory) and never auto-reset
417
+ * by plan changes.
418
+ */
419
+ keepTrattoBranding?: boolean;
398
420
  }
399
421
  interface UpdateWorkspacePreferencesParams {
400
422
  locale?: WorkspaceLocale;
@@ -503,15 +525,6 @@ declare class DomainsResource extends BaseResource {
503
525
  }>;
504
526
  }
505
527
 
506
- declare class ApiKeysResource extends BaseResource {
507
- create(params: CreateApiKeyParams, idempotencyKey?: string): Promise<ApiKeyCreated>;
508
- list(params?: ListApiKeysParams): Promise<PaginatedResponse<ApiKey>>;
509
- revoke(id: string): Promise<{
510
- id: string;
511
- revokedAt: string;
512
- }>;
513
- }
514
-
515
528
  declare class AnalyticsResource extends BaseResource {
516
529
  getSummary(period?: AnalyticsPeriod): Promise<AnalyticsSummary>;
517
530
  getTimeseries(period?: AnalyticsPeriod): Promise<TimeseriesPoint[]>;
@@ -552,11 +565,10 @@ declare class Tratto {
552
565
  readonly templates: TemplatesResource;
553
566
  readonly webhooks: WebhooksResource;
554
567
  readonly domains: DomainsResource;
555
- readonly apiKeys: ApiKeysResource;
556
568
  readonly analytics: AnalyticsResource;
557
569
  readonly flows: FlowsResource;
558
570
  readonly workspace: WorkspaceResource;
559
571
  constructor(apiKey: string, options?: TrattoOptions);
560
572
  }
561
573
 
562
- export { type AddContactsToAudienceResult, type AnalyticsPeriod, type AnalyticsSummary, type ApiKey, type ApiKeyCreated, type ApiKeyEnv, type Audience, type AudienceRule, type AudienceRuleOperator, type Campaign, type CampaignStats, type CampaignStatsDetail, type CampaignStatus, type Contact, type ContactStatus, type CreateApiKeyParams, type CreateAudienceParams, type CreateCampaignParams, type CreateContactParams, type CreateFlowParams, type CreateTemplateParams, type CreateWebhookParams, type Domain, type DomainRecord, type DomainStatus, type DomainSummary, type EmailDetail, type EmailEvent, type EmailSummary, type Flow, type FlowStatus, type FlowStep, type FlowStepType, type FlowTrigger, type FlowTriggerType, type ImportJobStatus, type InviteMemberParams, type ListApiKeysParams, type ListAudiencesParams, type ListCampaignsParams, type ListContactsParams, type ListDomainsParams, type ListEmailsParams, type ListFlowsParams, type ListTemplatesParams, type ListWebhookDeliveriesParams, type PaginatedResponse, type Pagination, type SendCampaignParams, type SendEmailParams, type Template, type TemplateStatus, type TemplateSummary, type TemplateVersion, type TemplateVersionSummary, type TimeseriesPoint, Tratto, TrattoError, type TrattoOptions, type UpdateContactParams, type UpdateFlowParams, type UpdateMemberParams, type UpdateTemplateParams, type UpdateWorkspaceParams, type UpdateWorkspacePreferencesParams, type Webhook, type WebhookDelivery, type WebhookDeliveryStatus, type WebhookEventType, type WebhookStatus, type Workspace, type WorkspaceLocale, type WorkspaceMember, type WorkspaceMemberRole, type WorkspacePlan, type WorkspacePreferences };
574
+ export { type AddContactsToAudienceResult, type AnalyticsPeriod, type AnalyticsSummary, type Audience, type AudienceRule, type AudienceRuleOperator, type Campaign, type CampaignStats, type CampaignStatsDetail, type CampaignStatus, type Contact, type ContactStatus, type CreateAudienceParams, type CreateCampaignParams, type CreateContactParams, type CreateFlowParams, type CreateTemplateParams, type CreateWebhookParams, type Domain, type DomainRecord, type DomainStatus, type DomainSummary, type EmailDetail, type EmailEvent, type EmailSummary, type Flow, type FlowStatus, type FlowStep, type FlowStepType, type FlowTrigger, type FlowTriggerType, type ImportJobStatus, type InviteMemberParams, type ListAudiencesParams, type ListCampaignsParams, type ListContactsParams, type ListDomainsParams, type ListEmailsParams, type ListFlowsParams, type ListTemplatesParams, type ListWebhookDeliveriesParams, type PaginatedResponse, type Pagination, type SendCampaignParams, type SendEmailParams, type Template, type TemplateStatus, type TemplateSummary, type TemplateVersion, type TemplateVersionSummary, type TimeseriesPoint, Tratto, TrattoError, type TrattoOptions, type UpdateContactParams, type UpdateFlowParams, type UpdateMemberParams, type UpdateTemplateParams, type UpdateWorkspaceParams, type UpdateWorkspacePreferencesParams, type Webhook, type WebhookDelivery, type WebhookDeliveryStatus, type WebhookEventType, type WebhookStatus, type Workspace, type WorkspaceLocale, type WorkspaceMember, type WorkspaceMemberRole, type WorkspacePlan, type WorkspacePreferences };
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[];
@@ -199,6 +205,7 @@ interface ListCampaignsParams {
199
205
  interface SendCampaignParams {
200
206
  scheduledAt?: Date | string;
201
207
  }
208
+ type TemplateFormat = 'html' | 'emailmd';
202
209
  type TemplateStatus = 'draft' | 'published';
203
210
  interface TemplateSummary {
204
211
  id: string;
@@ -209,15 +216,29 @@ interface TemplateSummary {
209
216
  updatedAt: string;
210
217
  }
211
218
  interface Template extends TemplateSummary {
219
+ /** Always the pinned, ready-to-send HTML — for emailmd templates it is derived from `source`. */
212
220
  html: string;
221
+ /** 'html' for templates created before formats existed. Immutable after creation. */
222
+ format: TemplateFormat;
223
+ /** The markdown source of truth for emailmd templates. */
224
+ source?: string;
225
+ renderWarnings?: string[];
213
226
  }
214
227
  interface CreateTemplateParams {
215
228
  name: string;
216
229
  html?: string;
230
+ /**
231
+ * emailmd markdown source. Creates a `format: 'emailmd'` template whose
232
+ * HTML is rendered server-side at save time. Mutually exclusive with
233
+ * `html` — sending both (or `html` on an emailmd template) is rejected.
234
+ */
235
+ markdown?: string;
217
236
  }
218
237
  interface UpdateTemplateParams {
219
238
  name?: string;
220
239
  html?: string;
240
+ /** New markdown source for an emailmd template (re-rendered at save). */
241
+ markdown?: string;
221
242
  status?: TemplateStatus;
222
243
  }
223
244
  interface ListTemplatesParams {
@@ -285,29 +306,6 @@ interface ListDomainsParams {
285
306
  after?: string;
286
307
  limit?: number;
287
308
  }
288
- type ApiKeyEnv = 'live' | 'test';
289
- interface ApiKey {
290
- id: string;
291
- name: string;
292
- prefix: string;
293
- env: ApiKeyEnv;
294
- permissions: string[];
295
- createdAt: string;
296
- lastUsedAt: string | null;
297
- revokedAt: string | null;
298
- }
299
- interface ApiKeyCreated extends ApiKey {
300
- key: string;
301
- }
302
- interface CreateApiKeyParams {
303
- name: string;
304
- env: ApiKeyEnv;
305
- permissions: string[];
306
- }
307
- interface ListApiKeysParams {
308
- after?: string;
309
- limit?: number;
310
- }
311
309
  type AnalyticsPeriod = '7d' | '30d' | '90d';
312
310
  interface AnalyticsSummary {
313
311
  period: AnalyticsPeriod;
@@ -373,6 +371,20 @@ interface Workspace {
373
371
  timezone: string;
374
372
  locale: WorkspaceLocale;
375
373
  plan: WorkspacePlan;
374
+ /** Workspace default sender, used when a send does not specify one. */
375
+ defaultFromName: string | null;
376
+ defaultFromEmail: string | null;
377
+ /**
378
+ * Tenant-hosted unsubscribe/preference page. When set, {{unsubscribe_url}}
379
+ * resolves here instead of the Tratto-hosted page.
380
+ */
381
+ customUnsubscribeUrl: string | null;
382
+ /**
383
+ * Keep the "Sent using Tratto" branded footer on every HTML send even on a
384
+ * paid plan. On the free plan the branded footer is always applied
385
+ * regardless of this flag.
386
+ */
387
+ keepTrattoBranding: boolean;
376
388
  createdAt: string;
377
389
  }
378
390
  interface WorkspaceMember {
@@ -395,6 +407,16 @@ interface UpdateWorkspaceParams {
395
407
  slug?: string;
396
408
  timezone?: string;
397
409
  locale?: WorkspaceLocale;
410
+ defaultFromName?: string;
411
+ defaultFromEmail?: string;
412
+ /** Set to null to clear and fall back to the Tratto-hosted page. */
413
+ customUnsubscribeUrl?: string | null;
414
+ /**
415
+ * Opt in to keep the branded footer on paid plans. Accepted on any plan
416
+ * (no effect on free, where branding is mandatory) and never auto-reset
417
+ * by plan changes.
418
+ */
419
+ keepTrattoBranding?: boolean;
398
420
  }
399
421
  interface UpdateWorkspacePreferencesParams {
400
422
  locale?: WorkspaceLocale;
@@ -503,15 +525,6 @@ declare class DomainsResource extends BaseResource {
503
525
  }>;
504
526
  }
505
527
 
506
- declare class ApiKeysResource extends BaseResource {
507
- create(params: CreateApiKeyParams, idempotencyKey?: string): Promise<ApiKeyCreated>;
508
- list(params?: ListApiKeysParams): Promise<PaginatedResponse<ApiKey>>;
509
- revoke(id: string): Promise<{
510
- id: string;
511
- revokedAt: string;
512
- }>;
513
- }
514
-
515
528
  declare class AnalyticsResource extends BaseResource {
516
529
  getSummary(period?: AnalyticsPeriod): Promise<AnalyticsSummary>;
517
530
  getTimeseries(period?: AnalyticsPeriod): Promise<TimeseriesPoint[]>;
@@ -552,11 +565,10 @@ declare class Tratto {
552
565
  readonly templates: TemplatesResource;
553
566
  readonly webhooks: WebhooksResource;
554
567
  readonly domains: DomainsResource;
555
- readonly apiKeys: ApiKeysResource;
556
568
  readonly analytics: AnalyticsResource;
557
569
  readonly flows: FlowsResource;
558
570
  readonly workspace: WorkspaceResource;
559
571
  constructor(apiKey: string, options?: TrattoOptions);
560
572
  }
561
573
 
562
- export { type AddContactsToAudienceResult, type AnalyticsPeriod, type AnalyticsSummary, type ApiKey, type ApiKeyCreated, type ApiKeyEnv, type Audience, type AudienceRule, type AudienceRuleOperator, type Campaign, type CampaignStats, type CampaignStatsDetail, type CampaignStatus, type Contact, type ContactStatus, type CreateApiKeyParams, type CreateAudienceParams, type CreateCampaignParams, type CreateContactParams, type CreateFlowParams, type CreateTemplateParams, type CreateWebhookParams, type Domain, type DomainRecord, type DomainStatus, type DomainSummary, type EmailDetail, type EmailEvent, type EmailSummary, type Flow, type FlowStatus, type FlowStep, type FlowStepType, type FlowTrigger, type FlowTriggerType, type ImportJobStatus, type InviteMemberParams, type ListApiKeysParams, type ListAudiencesParams, type ListCampaignsParams, type ListContactsParams, type ListDomainsParams, type ListEmailsParams, type ListFlowsParams, type ListTemplatesParams, type ListWebhookDeliveriesParams, type PaginatedResponse, type Pagination, type SendCampaignParams, type SendEmailParams, type Template, type TemplateStatus, type TemplateSummary, type TemplateVersion, type TemplateVersionSummary, type TimeseriesPoint, Tratto, TrattoError, type TrattoOptions, type UpdateContactParams, type UpdateFlowParams, type UpdateMemberParams, type UpdateTemplateParams, type UpdateWorkspaceParams, type UpdateWorkspacePreferencesParams, type Webhook, type WebhookDelivery, type WebhookDeliveryStatus, type WebhookEventType, type WebhookStatus, type Workspace, type WorkspaceLocale, type WorkspaceMember, type WorkspaceMemberRole, type WorkspacePlan, type WorkspacePreferences };
574
+ export { type AddContactsToAudienceResult, type AnalyticsPeriod, type AnalyticsSummary, type Audience, type AudienceRule, type AudienceRuleOperator, type Campaign, type CampaignStats, type CampaignStatsDetail, type CampaignStatus, type Contact, type ContactStatus, type CreateAudienceParams, type CreateCampaignParams, type CreateContactParams, type CreateFlowParams, type CreateTemplateParams, type CreateWebhookParams, type Domain, type DomainRecord, type DomainStatus, type DomainSummary, type EmailDetail, type EmailEvent, type EmailSummary, type Flow, type FlowStatus, type FlowStep, type FlowStepType, type FlowTrigger, type FlowTriggerType, type ImportJobStatus, type InviteMemberParams, type ListAudiencesParams, type ListCampaignsParams, type ListContactsParams, type ListDomainsParams, type ListEmailsParams, type ListFlowsParams, type ListTemplatesParams, type ListWebhookDeliveriesParams, type PaginatedResponse, type Pagination, type SendCampaignParams, type SendEmailParams, type Template, type TemplateStatus, type TemplateSummary, type TemplateVersion, type TemplateVersionSummary, type TimeseriesPoint, Tratto, TrattoError, type TrattoOptions, type UpdateContactParams, type UpdateFlowParams, type UpdateMemberParams, type UpdateTemplateParams, type UpdateWorkspaceParams, type UpdateWorkspacePreferencesParams, type Webhook, type WebhookDelivery, type WebhookDeliveryStatus, type WebhookEventType, type WebhookStatus, type Workspace, type WorkspaceLocale, type WorkspaceMember, type WorkspaceMemberRole, type WorkspacePlan, type WorkspacePreferences };
package/dist/index.js CHANGED
@@ -212,7 +212,8 @@ var TemplatesResource = class extends BaseResource {
212
212
  return this.fetch("GET", `/v1/templates${qs}`);
213
213
  }
214
214
  create(params) {
215
- return this.fetchData("POST", "/v1/templates", { body: params });
215
+ const body = params.markdown !== void 0 ? { ...params, format: "emailmd" } : params;
216
+ return this.fetchData("POST", "/v1/templates", { body });
216
217
  }
217
218
  get(id) {
218
219
  return this.fetchData("GET", `/v1/templates/${id}`);
@@ -288,23 +289,6 @@ var DomainsResource = class extends BaseResource {
288
289
  }
289
290
  };
290
291
 
291
- // src/resources/api-keys.ts
292
- var ApiKeysResource = class extends BaseResource {
293
- create(params, idempotencyKey) {
294
- return this.fetchData("POST", "/v1/api-keys", {
295
- body: params,
296
- headers: idempotencyKey ? { "Idempotency-Key": idempotencyKey } : void 0
297
- });
298
- }
299
- list(params) {
300
- const qs = this.buildQuery({ after: params?.after, limit: params?.limit });
301
- return this.fetch("GET", `/v1/api-keys${qs}`);
302
- }
303
- revoke(id) {
304
- return this.fetchData("DELETE", `/v1/api-keys/${id}`);
305
- }
306
- };
307
-
308
292
  // src/resources/analytics.ts
309
293
  var AnalyticsResource = class extends BaseResource {
310
294
  getSummary(period = "30d") {
@@ -390,7 +374,6 @@ var Tratto = class {
390
374
  this.templates = new TemplatesResource(apiKey, baseUrl);
391
375
  this.webhooks = new WebhooksResource(apiKey, baseUrl);
392
376
  this.domains = new DomainsResource(apiKey, baseUrl);
393
- this.apiKeys = new ApiKeysResource(apiKey, baseUrl);
394
377
  this.analytics = new AnalyticsResource(apiKey, baseUrl);
395
378
  this.flows = new FlowsResource(apiKey, baseUrl);
396
379
  this.workspace = new WorkspaceResource(apiKey, baseUrl);
package/dist/index.mjs CHANGED
@@ -185,7 +185,8 @@ var TemplatesResource = class extends BaseResource {
185
185
  return this.fetch("GET", `/v1/templates${qs}`);
186
186
  }
187
187
  create(params) {
188
- return this.fetchData("POST", "/v1/templates", { body: params });
188
+ const body = params.markdown !== void 0 ? { ...params, format: "emailmd" } : params;
189
+ return this.fetchData("POST", "/v1/templates", { body });
189
190
  }
190
191
  get(id) {
191
192
  return this.fetchData("GET", `/v1/templates/${id}`);
@@ -261,23 +262,6 @@ var DomainsResource = class extends BaseResource {
261
262
  }
262
263
  };
263
264
 
264
- // src/resources/api-keys.ts
265
- var ApiKeysResource = class extends BaseResource {
266
- create(params, idempotencyKey) {
267
- return this.fetchData("POST", "/v1/api-keys", {
268
- body: params,
269
- headers: idempotencyKey ? { "Idempotency-Key": idempotencyKey } : void 0
270
- });
271
- }
272
- list(params) {
273
- const qs = this.buildQuery({ after: params?.after, limit: params?.limit });
274
- return this.fetch("GET", `/v1/api-keys${qs}`);
275
- }
276
- revoke(id) {
277
- return this.fetchData("DELETE", `/v1/api-keys/${id}`);
278
- }
279
- };
280
-
281
265
  // src/resources/analytics.ts
282
266
  var AnalyticsResource = class extends BaseResource {
283
267
  getSummary(period = "30d") {
@@ -363,7 +347,6 @@ var Tratto = class {
363
347
  this.templates = new TemplatesResource(apiKey, baseUrl);
364
348
  this.webhooks = new WebhooksResource(apiKey, baseUrl);
365
349
  this.domains = new DomainsResource(apiKey, baseUrl);
366
- this.apiKeys = new ApiKeysResource(apiKey, baseUrl);
367
350
  this.analytics = new AnalyticsResource(apiKey, baseUrl);
368
351
  this.flows = new FlowsResource(apiKey, baseUrl);
369
352
  this.workspace = new WorkspaceResource(apiKey, baseUrl);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tratto/email",
3
- "version": "0.1.0",
4
- "description": "Tratto Node.js SDK — send transactional and marketing email",
3
+ "version": "1.1.0",
4
+ "description": "Tratto Node.js SDK \u2014 send transactional and marketing email",
5
5
  "author": "Tratto <hello@tratto.email>",
6
6
  "license": "MIT",
7
7
  "homepage": "https://tratto.email",
@@ -22,7 +22,9 @@
22
22
  "require": "./dist/index.js"
23
23
  }
24
24
  },
25
- "files": ["dist"],
25
+ "files": [
26
+ "dist"
27
+ ],
26
28
  "sideEffects": false,
27
29
  "scripts": {
28
30
  "build": "tsup src/index.ts --format cjs,esm --dts --clean",
@@ -30,12 +32,17 @@
30
32
  "lint": "eslint src --ext .ts",
31
33
  "typecheck": "tsc --noEmit",
32
34
  "test": "vitest run",
33
- "test:watch": "vitest"
35
+ "test:watch": "vitest",
36
+ "test:coverage": "vitest run --coverage"
34
37
  },
35
38
  "devDependencies": {
39
+ "@types/express": "^5.0.0",
36
40
  "@typescript-eslint/eslint-plugin": "^8.0.0",
37
41
  "@typescript-eslint/parser": "^8.0.0",
42
+ "@vitest/coverage-v8": "^2.0.0",
38
43
  "eslint": "^9.0.0",
44
+ "express": "^5.0.0",
45
+ "fastify": "^5.0.0",
39
46
  "tsup": "^8.0.0",
40
47
  "typescript": "^5.5.0",
41
48
  "vitest": "^2.0.0"