@tratto/email 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -252,9 +252,24 @@ await tratto.campaigns.send(id, { scheduledAt: new Date('2025-07-01T09:00:00Z')
252
252
  const stats = await tratto.campaigns.getStats(id);
253
253
  console.log(stats.rates.openRate);
254
254
 
255
+ // Cancel a scheduled send: back to draft, scheduledAt cleared
256
+ await tratto.campaigns.unschedule(id);
257
+
258
+ // 409 if it cannot: the send already started, the campaign is in another
259
+ // status, or it already sent a test wave to part of the list and is waiting
260
+ // for the bounce rate. Those emails cannot be recalled, so pause it instead.
261
+
255
262
  // Pause
256
263
  await tratto.campaigns.pause(id);
257
264
 
265
+ // Why a campaign is paused: 'quota_exceeded', 'schedule_missed',
266
+ // 'bounce_rate' (it stopped itself on too many permanent bounces),
267
+ // or null when it was paused by hand.
268
+ const campaign = await tratto.campaigns.get(id);
269
+ if (campaign.pausedReason === 'bounce_rate') {
270
+ console.log('Stopped: too many bounces. Clean the list before resuming.');
271
+ }
272
+
258
273
  // Test send
259
274
  const { emailId } = await tratto.campaigns.testSend(id, 'me@example.com');
260
275
  ```
@@ -281,6 +296,16 @@ await tratto.templates.testSend(tpl.id, 'me@example.com', { name: 'Alice' });
281
296
  await tratto.templates.delete(tpl.id);
282
297
  ```
283
298
 
299
+ Templates created from `markdown` come back with `format: 'emailmd'`, the
300
+ markdown in `source`, the rendered HTML in `html`, and — when part of the
301
+ markdown could not be rendered — a `renderWarnings: string[]` array on the
302
+ template object. The field is absent when there is nothing to report:
303
+
304
+ ```ts
305
+ const tpl = await tratto.templates.create({ name: 'Welcome', markdown: '# Hi {{name}}' });
306
+ if (tpl.renderWarnings?.length) console.warn(tpl.renderWarnings);
307
+ ```
308
+
284
309
  ---
285
310
 
286
311
  ### Webhooks
@@ -342,7 +367,9 @@ console.log('Open rate:', summary.openRate);
342
367
  const points = await tratto.analytics.getTimeseries('7d');
343
368
  ```
344
369
 
345
- Supported periods: `'7d'` | `'30d'` | `'90d'`. Results are cached server-side for 1 hour.
370
+ Supported periods: `'7d'` | `'30d'` | `'90d'` | `'180d'` | `'1y'` (default `'30d'`).
371
+ `'180d'` and `'1y'` read the long-term aggregate, which holds live data only:
372
+ they are rejected for test-mode keys. Results are cached server-side for 1 hour.
346
373
 
347
374
  ---
348
375
 
@@ -430,12 +457,11 @@ import type {
430
457
  Contact,
431
458
  Audience,
432
459
  Campaign,
460
+ CampaignPausedReason,
433
461
  CampaignStatsDetail,
434
462
  Template,
435
463
  Webhook,
436
464
  Domain,
437
- ApiKey,
438
- ApiKeyCreated,
439
465
  AnalyticsSummary,
440
466
  TimeseriesPoint,
441
467
  Flow,
@@ -452,14 +478,23 @@ See the [`examples/`](examples/) folder:
452
478
 
453
479
  | File | Description |
454
480
  |---|---|
455
- | [`send-email.ts`](examples/send-email.ts) | Send transactional emails (HTML, template, with idempotency) |
481
+ | [`send-email.ts`](examples/send-email.ts) | Send transactional emails (HTML, template, with idempotency), read the timeline |
456
482
  | [`contacts.ts`](examples/contacts.ts) | Contact management and CSV bulk import |
457
- | [`campaign.ts`](examples/campaign.ts) | Create, configure, and send a marketing campaign |
483
+ | [`audiences.ts`](examples/audiences.ts) | Rule-based audiences, adding contacts to one |
484
+ | [`campaign.ts`](examples/campaign.ts) | Create, configure, send, unschedule and pause a marketing campaign |
485
+ | [`templates.ts`](examples/templates.ts) | Template life cycle: create, edit, versions, test send, delete |
458
486
  | [`analytics.ts`](examples/analytics.ts) | Fetch delivery metrics and daily timeseries |
459
487
  | [`webhook.ts`](examples/webhook.ts) | Register a webhook and inspect delivery history |
488
+ | [`domains.ts`](examples/domains.ts) | Add a sending domain, print its DNS records, verify it |
489
+ | [`flows.ts`](examples/flows.ts) | Automation flows (needs an API key with the `*` permission) |
490
+ | [`workspace.ts`](examples/workspace.ts) | Workspace settings, per-send-type senders, members |
460
491
  | [`nextjs.ts`](examples/nextjs.ts) | Next.js App Router route handler sending a welcome email |
461
492
  | [`express.ts`](examples/express.ts) | Express route sending a password-reset email |
462
493
  | [`fastify.ts`](examples/fastify.ts) | Fastify route sending an order-confirmation email via template |
494
+ | [`smoke.ts`](examples/smoke.ts) | Runnable round-trip against a real API in test mode ([how to run](CONTRIBUTING.md#manual-smoke-test)) |
495
+
496
+ Every example is type-checked and linted with the rest of the repo, so a
497
+ renamed method breaks the build instead of a user's integration.
463
498
 
464
499
  Run any example with [tsx](https://github.com/privatenumber/tsx):
465
500
 
@@ -467,6 +502,9 @@ Run any example with [tsx](https://github.com/privatenumber/tsx):
467
502
  TRATTO_API_KEY=tratto_live_... npx tsx examples/send-email.ts
468
503
  ```
469
504
 
505
+ The examples are written the way you would use the SDK, against real
506
+ resources: read them before you run them.
507
+
470
508
  ---
471
509
 
472
510
  ## Contributing
package/dist/index.d.mts CHANGED
@@ -154,6 +154,15 @@ interface AddContactsToAudienceResult {
154
154
  notFound: number;
155
155
  }
156
156
  type CampaignStatus = 'draft' | 'sending' | 'scheduled' | 'paused' | 'completed';
157
+ /**
158
+ * Why a paused campaign is paused. `null` for a manual pause, or for a
159
+ * campaign that was never paused.
160
+ *
161
+ * - `quota_exceeded` — the dispatcher hit the monthly plan cap mid-send.
162
+ * - `schedule_missed` — the scheduled send window passed without dispatch.
163
+ * - `bounce_rate` — too many permanent bounces, the campaign stopped itself.
164
+ */
165
+ type CampaignPausedReason = 'quota_exceeded' | 'schedule_missed' | 'bounce_rate';
157
166
  interface CampaignStats {
158
167
  total: number;
159
168
  sent: number;
@@ -166,6 +175,8 @@ interface Campaign {
166
175
  id: string;
167
176
  name: string;
168
177
  status: CampaignStatus;
178
+ /** Set whenever `status` is `paused`, `null` otherwise. */
179
+ pausedReason: CampaignPausedReason | null;
169
180
  templateId: string;
170
181
  audienceId: string;
171
182
  fromName: string;
@@ -176,6 +187,14 @@ interface Campaign {
176
187
  sentAt: string | null;
177
188
  stats: CampaignStats;
178
189
  createdAt: string;
190
+ /**
191
+ * The editable markdown of an emailmd campaign (its own copy — editing it
192
+ * never touches the template). Returned by `get()` only: `list()` omits
193
+ * `source` and `renderWarnings` to keep the payload small.
194
+ */
195
+ source?: string;
196
+ /** Markdown that could not be rendered. Returned by `get()` only, absent when empty. */
197
+ renderWarnings?: string[];
179
198
  }
180
199
  interface CampaignStatsDetail {
181
200
  campaignId: string;
@@ -306,7 +325,8 @@ interface ListDomainsParams {
306
325
  after?: string;
307
326
  limit?: number;
308
327
  }
309
- type AnalyticsPeriod = '7d' | '30d' | '90d';
328
+ /** `'180d'` and `'1y'` read the long-term aggregate (live data only) and are rejected for test-mode keys. */
329
+ type AnalyticsPeriod = '7d' | '30d' | '90d' | '180d' | '1y';
310
330
  interface AnalyticsSummary {
311
331
  period: AnalyticsPeriod;
312
332
  totalSent: number;
@@ -364,6 +384,29 @@ interface ListFlowsParams {
364
384
  type WorkspacePlan = 'free' | 'starter' | 'growth';
365
385
  type WorkspaceMemberRole = 'owner' | 'admin' | 'member';
366
386
  type WorkspaceLocale = 'it' | 'en';
387
+ type SendType = 'marketing' | 'automation' | 'transactional';
388
+ /**
389
+ * Sender for one send type. `fromEmail` must be on a domain already verified
390
+ * for the workspace; `replyTo` is a response header, not the envelope sender,
391
+ * so it needs no verified domain.
392
+ */
393
+ interface Sender {
394
+ fromEmail: string;
395
+ fromName: string;
396
+ replyTo?: string | null;
397
+ }
398
+ /**
399
+ * Default sender per send type (API >= 0.5.7).
400
+ *
401
+ * `null` on a type means it is not configured and **inherits** the
402
+ * workspace-wide `defaultFromEmail`/`defaultFromName` — it is never a reason
403
+ * for a send to be refused.
404
+ *
405
+ * Which type applies where: `marketing` for campaigns and template test sends,
406
+ * `automation` for the emails a flow sends (resolved when the flow is
407
+ * activated), `transactional` for API sends that carry no `from` of their own.
408
+ */
409
+ type Senders = Record<SendType, Sender | null>;
367
410
  interface Workspace {
368
411
  id: string;
369
412
  name: string;
@@ -374,6 +417,11 @@ interface Workspace {
374
417
  /** Workspace default sender, used when a send does not specify one. */
375
418
  defaultFromName: string | null;
376
419
  defaultFromEmail: string | null;
420
+ /**
421
+ * Per-send-type senders. Optional: an API older than 0.5.7 does not send
422
+ * the field at all, so read it defensively rather than assuming three keys.
423
+ */
424
+ senders?: Partial<Senders>;
377
425
  /**
378
426
  * Tenant-hosted unsubscribe/preference page. When set, {{unsubscribe_url}}
379
427
  * resolves here instead of the Tratto-hosted page.
@@ -409,6 +457,13 @@ interface UpdateWorkspaceParams {
409
457
  locale?: WorkspaceLocale;
410
458
  defaultFromName?: string;
411
459
  defaultFromEmail?: string;
460
+ /**
461
+ * Partial write: sending only `marketing` leaves the other two untouched,
462
+ * and `{ marketing: null }` puts that type back to inheriting the
463
+ * workspace-wide default. Both halves of a sender travel together — a
464
+ * `fromEmail` without a `fromName` is refused.
465
+ */
466
+ senders?: Partial<Record<SendType, Sender | null>>;
412
467
  /** Set to null to clear and fall back to the Tratto-hosted page. */
413
468
  customUnsubscribeUrl?: string | null;
414
469
  /**
@@ -477,6 +532,21 @@ declare class CampaignsResource extends BaseResource {
477
532
  send(id: string, params?: SendCampaignParams): Promise<{
478
533
  status: string;
479
534
  }>;
535
+ /**
536
+ * Cancel a scheduled send: the campaign goes back to `draft` and its
537
+ * `scheduledAt` is cleared.
538
+ *
539
+ * Only a campaign still waiting for its date can be unscheduled. Anything
540
+ * else answers 409: a send already running, a campaign in any other status,
541
+ * or one that has already sent a test wave to part of its list and is
542
+ * waiting for the bounce rate before sending the rest. In those cases the
543
+ * emails already out cannot be recalled, so `pause()` is the way to stop it.
544
+ */
545
+ unschedule(id: string): Promise<{
546
+ id: string;
547
+ status: 'draft';
548
+ scheduledAt: null;
549
+ }>;
480
550
  pause(id: string): Promise<{
481
551
  status: string;
482
552
  }>;
@@ -571,4 +641,4 @@ declare class Tratto {
571
641
  constructor(apiKey: string, options?: TrattoOptions);
572
642
  }
573
643
 
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 };
644
+ export { type AddContactsToAudienceResult, type AnalyticsPeriod, type AnalyticsSummary, type Audience, type AudienceRule, type AudienceRuleOperator, type Campaign, type CampaignPausedReason, 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 SendType, type Sender, type Senders, 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
@@ -154,6 +154,15 @@ interface AddContactsToAudienceResult {
154
154
  notFound: number;
155
155
  }
156
156
  type CampaignStatus = 'draft' | 'sending' | 'scheduled' | 'paused' | 'completed';
157
+ /**
158
+ * Why a paused campaign is paused. `null` for a manual pause, or for a
159
+ * campaign that was never paused.
160
+ *
161
+ * - `quota_exceeded` — the dispatcher hit the monthly plan cap mid-send.
162
+ * - `schedule_missed` — the scheduled send window passed without dispatch.
163
+ * - `bounce_rate` — too many permanent bounces, the campaign stopped itself.
164
+ */
165
+ type CampaignPausedReason = 'quota_exceeded' | 'schedule_missed' | 'bounce_rate';
157
166
  interface CampaignStats {
158
167
  total: number;
159
168
  sent: number;
@@ -166,6 +175,8 @@ interface Campaign {
166
175
  id: string;
167
176
  name: string;
168
177
  status: CampaignStatus;
178
+ /** Set whenever `status` is `paused`, `null` otherwise. */
179
+ pausedReason: CampaignPausedReason | null;
169
180
  templateId: string;
170
181
  audienceId: string;
171
182
  fromName: string;
@@ -176,6 +187,14 @@ interface Campaign {
176
187
  sentAt: string | null;
177
188
  stats: CampaignStats;
178
189
  createdAt: string;
190
+ /**
191
+ * The editable markdown of an emailmd campaign (its own copy — editing it
192
+ * never touches the template). Returned by `get()` only: `list()` omits
193
+ * `source` and `renderWarnings` to keep the payload small.
194
+ */
195
+ source?: string;
196
+ /** Markdown that could not be rendered. Returned by `get()` only, absent when empty. */
197
+ renderWarnings?: string[];
179
198
  }
180
199
  interface CampaignStatsDetail {
181
200
  campaignId: string;
@@ -306,7 +325,8 @@ interface ListDomainsParams {
306
325
  after?: string;
307
326
  limit?: number;
308
327
  }
309
- type AnalyticsPeriod = '7d' | '30d' | '90d';
328
+ /** `'180d'` and `'1y'` read the long-term aggregate (live data only) and are rejected for test-mode keys. */
329
+ type AnalyticsPeriod = '7d' | '30d' | '90d' | '180d' | '1y';
310
330
  interface AnalyticsSummary {
311
331
  period: AnalyticsPeriod;
312
332
  totalSent: number;
@@ -364,6 +384,29 @@ interface ListFlowsParams {
364
384
  type WorkspacePlan = 'free' | 'starter' | 'growth';
365
385
  type WorkspaceMemberRole = 'owner' | 'admin' | 'member';
366
386
  type WorkspaceLocale = 'it' | 'en';
387
+ type SendType = 'marketing' | 'automation' | 'transactional';
388
+ /**
389
+ * Sender for one send type. `fromEmail` must be on a domain already verified
390
+ * for the workspace; `replyTo` is a response header, not the envelope sender,
391
+ * so it needs no verified domain.
392
+ */
393
+ interface Sender {
394
+ fromEmail: string;
395
+ fromName: string;
396
+ replyTo?: string | null;
397
+ }
398
+ /**
399
+ * Default sender per send type (API >= 0.5.7).
400
+ *
401
+ * `null` on a type means it is not configured and **inherits** the
402
+ * workspace-wide `defaultFromEmail`/`defaultFromName` — it is never a reason
403
+ * for a send to be refused.
404
+ *
405
+ * Which type applies where: `marketing` for campaigns and template test sends,
406
+ * `automation` for the emails a flow sends (resolved when the flow is
407
+ * activated), `transactional` for API sends that carry no `from` of their own.
408
+ */
409
+ type Senders = Record<SendType, Sender | null>;
367
410
  interface Workspace {
368
411
  id: string;
369
412
  name: string;
@@ -374,6 +417,11 @@ interface Workspace {
374
417
  /** Workspace default sender, used when a send does not specify one. */
375
418
  defaultFromName: string | null;
376
419
  defaultFromEmail: string | null;
420
+ /**
421
+ * Per-send-type senders. Optional: an API older than 0.5.7 does not send
422
+ * the field at all, so read it defensively rather than assuming three keys.
423
+ */
424
+ senders?: Partial<Senders>;
377
425
  /**
378
426
  * Tenant-hosted unsubscribe/preference page. When set, {{unsubscribe_url}}
379
427
  * resolves here instead of the Tratto-hosted page.
@@ -409,6 +457,13 @@ interface UpdateWorkspaceParams {
409
457
  locale?: WorkspaceLocale;
410
458
  defaultFromName?: string;
411
459
  defaultFromEmail?: string;
460
+ /**
461
+ * Partial write: sending only `marketing` leaves the other two untouched,
462
+ * and `{ marketing: null }` puts that type back to inheriting the
463
+ * workspace-wide default. Both halves of a sender travel together — a
464
+ * `fromEmail` without a `fromName` is refused.
465
+ */
466
+ senders?: Partial<Record<SendType, Sender | null>>;
412
467
  /** Set to null to clear and fall back to the Tratto-hosted page. */
413
468
  customUnsubscribeUrl?: string | null;
414
469
  /**
@@ -477,6 +532,21 @@ declare class CampaignsResource extends BaseResource {
477
532
  send(id: string, params?: SendCampaignParams): Promise<{
478
533
  status: string;
479
534
  }>;
535
+ /**
536
+ * Cancel a scheduled send: the campaign goes back to `draft` and its
537
+ * `scheduledAt` is cleared.
538
+ *
539
+ * Only a campaign still waiting for its date can be unscheduled. Anything
540
+ * else answers 409: a send already running, a campaign in any other status,
541
+ * or one that has already sent a test wave to part of its list and is
542
+ * waiting for the bounce rate before sending the rest. In those cases the
543
+ * emails already out cannot be recalled, so `pause()` is the way to stop it.
544
+ */
545
+ unschedule(id: string): Promise<{
546
+ id: string;
547
+ status: 'draft';
548
+ scheduledAt: null;
549
+ }>;
480
550
  pause(id: string): Promise<{
481
551
  status: string;
482
552
  }>;
@@ -571,4 +641,4 @@ declare class Tratto {
571
641
  constructor(apiKey: string, options?: TrattoOptions);
572
642
  }
573
643
 
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 };
644
+ export { type AddContactsToAudienceResult, type AnalyticsPeriod, type AnalyticsSummary, type Audience, type AudienceRule, type AudienceRuleOperator, type Campaign, type CampaignPausedReason, 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 SendType, type Sender, type Senders, 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
@@ -36,6 +36,9 @@ var TrattoError = class extends Error {
36
36
  }
37
37
  };
38
38
 
39
+ // package.json
40
+ var version = "1.2.0";
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
  };
@@ -189,6 +192,23 @@ var CampaignsResource = class extends BaseResource {
189
192
  }
190
193
  return this.fetchData("POST", `/v1/campaigns/${id}/send`, { body });
191
194
  }
195
+ /**
196
+ * Cancel a scheduled send: the campaign goes back to `draft` and its
197
+ * `scheduledAt` is cleared.
198
+ *
199
+ * Only a campaign still waiting for its date can be unscheduled. Anything
200
+ * else answers 409: a send already running, a campaign in any other status,
201
+ * or one that has already sent a test wave to part of its list and is
202
+ * waiting for the bounce rate before sending the rest. In those cases the
203
+ * emails already out cannot be recalled, so `pause()` is the way to stop it.
204
+ */
205
+ unschedule(id) {
206
+ return this.fetchData(
207
+ "POST",
208
+ `/v1/campaigns/${id}/unschedule`,
209
+ { body: {} }
210
+ );
211
+ }
192
212
  pause(id) {
193
213
  return this.fetchData("POST", `/v1/campaigns/${id}/pause`, { body: {} });
194
214
  }
@@ -227,8 +247,8 @@ var TemplatesResource = class extends BaseResource {
227
247
  listVersions(id) {
228
248
  return this.fetchData("GET", `/v1/templates/${id}/versions`);
229
249
  }
230
- getVersion(id, version) {
231
- return this.fetchData("GET", `/v1/templates/${id}/versions/${version}`);
250
+ getVersion(id, version2) {
251
+ return this.fetchData("GET", `/v1/templates/${id}/versions/${version2}`);
232
252
  }
233
253
  testSend(id, to, variables = {}) {
234
254
  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.2.0";
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
  };
@@ -162,6 +165,23 @@ var CampaignsResource = class extends BaseResource {
162
165
  }
163
166
  return this.fetchData("POST", `/v1/campaigns/${id}/send`, { body });
164
167
  }
168
+ /**
169
+ * Cancel a scheduled send: the campaign goes back to `draft` and its
170
+ * `scheduledAt` is cleared.
171
+ *
172
+ * Only a campaign still waiting for its date can be unscheduled. Anything
173
+ * else answers 409: a send already running, a campaign in any other status,
174
+ * or one that has already sent a test wave to part of its list and is
175
+ * waiting for the bounce rate before sending the rest. In those cases the
176
+ * emails already out cannot be recalled, so `pause()` is the way to stop it.
177
+ */
178
+ unschedule(id) {
179
+ return this.fetchData(
180
+ "POST",
181
+ `/v1/campaigns/${id}/unschedule`,
182
+ { body: {} }
183
+ );
184
+ }
165
185
  pause(id) {
166
186
  return this.fetchData("POST", `/v1/campaigns/${id}/pause`, { body: {} });
167
187
  }
@@ -200,8 +220,8 @@ var TemplatesResource = class extends BaseResource {
200
220
  listVersions(id) {
201
221
  return this.fetchData("GET", `/v1/templates/${id}/versions`);
202
222
  }
203
- getVersion(id, version) {
204
- return this.fetchData("GET", `/v1/templates/${id}/versions/${version}`);
223
+ getVersion(id, version2) {
224
+ return this.fetchData("GET", `/v1/templates/${id}/versions/${version2}`);
205
225
  }
206
226
  testSend(id, to, variables = {}) {
207
227
  return this.fetchData(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tratto/email",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Tratto Node.js SDK \u2014 send transactional and marketing email",
5
5
  "author": "Tratto <hello@tratto.email>",
6
6
  "license": "MIT",
@@ -29,7 +29,7 @@
29
29
  "scripts": {
30
30
  "build": "tsup src/index.ts --format cjs,esm --dts --clean",
31
31
  "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
32
- "lint": "eslint src --ext .ts",
32
+ "lint": "eslint src examples --ext .ts",
33
33
  "typecheck": "tsc --noEmit",
34
34
  "test": "vitest run",
35
35
  "test:watch": "vitest",
@@ -49,5 +49,8 @@
49
49
  },
50
50
  "engines": {
51
51
  "node": ">=18"
52
+ },
53
+ "volta": {
54
+ "node": "24.21.0"
52
55
  }
53
56
  }