@tratto/angular 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.
- package/README.md +502 -0
- package/fesm2022/tratto-angular.mjs +932 -0
- package/fesm2022/tratto-angular.mjs.map +1 -0
- package/package.json +35 -0
- package/types/tratto-angular.d.ts +1028 -0
package/README.md
ADDED
|
@@ -0,0 +1,502 @@
|
|
|
1
|
+
# @tratto/angular
|
|
2
|
+
|
|
3
|
+
Official Angular SDK for the [Tratto](https://tratto.email) email platform.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@tratto/angular)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install @tratto/angular
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
`@tratto/angular` requires Angular 22+ and `@angular/common/http`. No other peer dependencies.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Setup
|
|
19
|
+
|
|
20
|
+
### Standalone applications (Angular 14+)
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
// app.config.ts
|
|
24
|
+
import { ApplicationConfig } from '@angular/core';
|
|
25
|
+
import { provideHttpClient } from '@angular/common/http';
|
|
26
|
+
import { provideTratt } from '@tratto/angular';
|
|
27
|
+
|
|
28
|
+
export const appConfig: ApplicationConfig = {
|
|
29
|
+
providers: [
|
|
30
|
+
provideHttpClient(),
|
|
31
|
+
provideTratt({ apiKey: 'tratto_live_...' }),
|
|
32
|
+
],
|
|
33
|
+
};
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### NgModule applications
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
// app.module.ts
|
|
40
|
+
import { NgModule } from '@angular/core';
|
|
41
|
+
import { HttpClientModule } from '@angular/common/http';
|
|
42
|
+
import { TrattoModule } from '@tratto/angular';
|
|
43
|
+
|
|
44
|
+
@NgModule({
|
|
45
|
+
imports: [
|
|
46
|
+
HttpClientModule,
|
|
47
|
+
TrattoModule.forRoot({ apiKey: 'tratto_live_...' }),
|
|
48
|
+
],
|
|
49
|
+
})
|
|
50
|
+
export class AppModule {}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Custom base URL
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
provideTratt({
|
|
57
|
+
apiKey: 'tratto_live_...',
|
|
58
|
+
baseUrl: 'https://api.tratto.email', // optional — this is the default
|
|
59
|
+
})
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Usage
|
|
65
|
+
|
|
66
|
+
Inject `TrattoService` (facade) or any individual resource service.
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
import { Component, inject } from '@angular/core';
|
|
70
|
+
import { TrattoService } from '@tratto/angular';
|
|
71
|
+
|
|
72
|
+
@Component({ ... })
|
|
73
|
+
export class MyComponent {
|
|
74
|
+
private tratto = inject(TrattoService);
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
You can also inject resource services directly:
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
import { EmailsService } from '@tratto/angular';
|
|
82
|
+
|
|
83
|
+
@Component({ ... })
|
|
84
|
+
export class MyComponent {
|
|
85
|
+
private emails = inject(EmailsService);
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
All methods return `Observable<T>`. Subscribe or use the `async` pipe as you would with any Angular HTTP call.
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## API Reference
|
|
94
|
+
|
|
95
|
+
### Emails
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
const { emails } = inject(TrattoService);
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
#### `emails.send(params, idempotencyKey?)`
|
|
102
|
+
|
|
103
|
+
Send a transactional email. At least one of `html`, `text`, or `templateId` is required.
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
emails.send({
|
|
107
|
+
from: 'Tratto <hello@mail.acme.com>',
|
|
108
|
+
to: 'user@example.com',
|
|
109
|
+
subject: 'Welcome!',
|
|
110
|
+
html: '<p>Hello world</p>',
|
|
111
|
+
}).subscribe(({ id }) => console.log('Email sent:', id));
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
With a template and idempotency key:
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
emails.send(
|
|
118
|
+
{
|
|
119
|
+
from: 'hello@mail.acme.com',
|
|
120
|
+
to: ['alice@example.com', 'bob@example.com'],
|
|
121
|
+
subject: 'Reset your password',
|
|
122
|
+
templateId: 'tpl_abc123',
|
|
123
|
+
variables: { name: 'Alice', link: 'https://...' },
|
|
124
|
+
},
|
|
125
|
+
'unique-idempotency-key',
|
|
126
|
+
).subscribe(({ id }) => console.log(id));
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
#### `emails.list(params?)`
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
emails.list({ limit: 20, status: 'delivered' })
|
|
133
|
+
.subscribe(({ data, pagination }) => console.log(data));
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
#### `emails.get(id)`
|
|
137
|
+
|
|
138
|
+
```ts
|
|
139
|
+
emails.get('em_abc123').subscribe(email => console.log(email));
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
#### `emails.listEvents(id)`
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
emails.listEvents('em_abc123').subscribe(events => console.log(events));
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
### Contacts
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
const { contacts } = inject(TrattoService);
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
#### `contacts.create(params)`
|
|
157
|
+
|
|
158
|
+
```ts
|
|
159
|
+
contacts.create({
|
|
160
|
+
email: 'alice@example.com',
|
|
161
|
+
firstName: 'Alice',
|
|
162
|
+
tags: ['vip'],
|
|
163
|
+
}).subscribe(({ id }) => console.log(id));
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
#### `contacts.list(params?)`
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
contacts.list({ status: 'subscribed', limit: 50 })
|
|
170
|
+
.subscribe(({ data }) => console.log(data));
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
#### `contacts.update(id, params)`
|
|
174
|
+
|
|
175
|
+
```ts
|
|
176
|
+
contacts.update('con_abc123', { status: 'unsubscribed' })
|
|
177
|
+
.subscribe(({ id }) => console.log(id));
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
#### `contacts.importCsv(csvText)`
|
|
181
|
+
|
|
182
|
+
Bulk-import contacts from a CSV string (async job). Poll `getImportJob` to track progress.
|
|
183
|
+
|
|
184
|
+
```ts
|
|
185
|
+
const csv = `email,first_name,last_name
|
|
186
|
+
alice@example.com,Alice,Smith
|
|
187
|
+
bob@example.com,Bob,Jones`;
|
|
188
|
+
|
|
189
|
+
contacts.importCsv(csv).subscribe(({ jobId }) => {
|
|
190
|
+
contacts.getImportJob(jobId).subscribe(status => console.log(status));
|
|
191
|
+
});
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
### Audiences
|
|
197
|
+
|
|
198
|
+
```ts
|
|
199
|
+
const { audiences } = inject(TrattoService);
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
```ts
|
|
203
|
+
// Create a dynamic segment
|
|
204
|
+
audiences.create({
|
|
205
|
+
name: 'Power users',
|
|
206
|
+
rules: [{ field: 'tags', operator: 'array_contains', value: 'vip' }],
|
|
207
|
+
}).subscribe(({ id }) => console.log(id));
|
|
208
|
+
|
|
209
|
+
// List
|
|
210
|
+
audiences.list().subscribe(({ data }) => console.log(data));
|
|
211
|
+
|
|
212
|
+
// Add contacts (up to 500 IDs per call)
|
|
213
|
+
audiences.addContacts('aud_abc123', ['con_1', 'con_2'])
|
|
214
|
+
.subscribe(result => console.log(result.added));
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
### Campaigns
|
|
220
|
+
|
|
221
|
+
```ts
|
|
222
|
+
const { campaigns } = inject(TrattoService);
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
```ts
|
|
226
|
+
// Create a draft campaign
|
|
227
|
+
campaigns.create({
|
|
228
|
+
name: 'June Newsletter',
|
|
229
|
+
templateId: 'tpl_abc123',
|
|
230
|
+
audienceId: 'aud_abc123',
|
|
231
|
+
fromName: 'Acme',
|
|
232
|
+
fromEmail: 'news@mail.acme.com',
|
|
233
|
+
subjectA: 'Our June update',
|
|
234
|
+
}).subscribe(({ id }) => console.log(id));
|
|
235
|
+
|
|
236
|
+
// Send immediately
|
|
237
|
+
campaigns.send('cmp_abc123').subscribe(({ status }) => console.log(status));
|
|
238
|
+
|
|
239
|
+
// Schedule for a future date
|
|
240
|
+
campaigns.send('cmp_abc123', { scheduledAt: new Date('2025-07-01T09:00:00Z') })
|
|
241
|
+
.subscribe(({ status }) => console.log(status));
|
|
242
|
+
|
|
243
|
+
// Delivery stats
|
|
244
|
+
campaigns.getStats('cmp_abc123').subscribe(stats => console.log(stats.rates));
|
|
245
|
+
|
|
246
|
+
// Pause
|
|
247
|
+
campaigns.pause('cmp_abc123').subscribe();
|
|
248
|
+
|
|
249
|
+
// Test send
|
|
250
|
+
campaigns.testSend('cmp_abc123', 'me@example.com')
|
|
251
|
+
.subscribe(({ emailId }) => console.log(emailId));
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
### Templates
|
|
257
|
+
|
|
258
|
+
```ts
|
|
259
|
+
const { templates } = inject(TrattoService);
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
```ts
|
|
263
|
+
// Create
|
|
264
|
+
templates.create({ name: 'Welcome email', html: '<h1>Hi {{name}}!</h1>' })
|
|
265
|
+
.subscribe(tpl => console.log(tpl.id));
|
|
266
|
+
|
|
267
|
+
// Update (auto-creates a new version)
|
|
268
|
+
templates.update('tpl_abc123', { html: '<h1>Hello {{name}}!</h1>' })
|
|
269
|
+
.subscribe(tpl => console.log(tpl.version));
|
|
270
|
+
|
|
271
|
+
// Version history
|
|
272
|
+
templates.listVersions('tpl_abc123').subscribe(versions => console.log(versions));
|
|
273
|
+
templates.getVersion('tpl_abc123', 2).subscribe(v => console.log(v.html));
|
|
274
|
+
|
|
275
|
+
// Test send
|
|
276
|
+
templates.testSend('tpl_abc123', 'me@example.com', { name: 'Alice' }).subscribe();
|
|
277
|
+
|
|
278
|
+
// Delete
|
|
279
|
+
templates.delete('tpl_abc123').subscribe();
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
### Webhooks
|
|
285
|
+
|
|
286
|
+
```ts
|
|
287
|
+
const { webhooks } = inject(TrattoService);
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
```ts
|
|
291
|
+
// Register — save the secret, it is shown only once
|
|
292
|
+
webhooks.create({
|
|
293
|
+
url: 'https://my-app.com/webhooks/tratto',
|
|
294
|
+
events: ['delivered', 'bounced', 'complained'],
|
|
295
|
+
}).subscribe(({ id, secret }) => {
|
|
296
|
+
console.log('Webhook ID:', id);
|
|
297
|
+
console.log('Signing secret (save this!):', secret);
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
// List
|
|
301
|
+
webhooks.list().subscribe(hooks => console.log(hooks));
|
|
302
|
+
|
|
303
|
+
// Delivery history
|
|
304
|
+
webhooks.listDeliveries('wh_abc123', { limit: 20 })
|
|
305
|
+
.subscribe(({ data }) => console.log(data));
|
|
306
|
+
|
|
307
|
+
// Test connectivity
|
|
308
|
+
webhooks.test('wh_abc123').subscribe(({ queued }) => console.log(queued));
|
|
309
|
+
|
|
310
|
+
// Rotate signing secret
|
|
311
|
+
webhooks.rotateSecret('wh_abc123').subscribe(({ secret }) => console.log(secret));
|
|
312
|
+
|
|
313
|
+
// Delete
|
|
314
|
+
webhooks.delete('wh_abc123').subscribe();
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
---
|
|
318
|
+
|
|
319
|
+
### Domains
|
|
320
|
+
|
|
321
|
+
```ts
|
|
322
|
+
const { domains } = inject(TrattoService);
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
```ts
|
|
326
|
+
// Add domain — response contains the DNS records to publish
|
|
327
|
+
domains.add('mail.acme.com').subscribe(domain => {
|
|
328
|
+
console.log('Publish these DNS records:', domain.records);
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
// Trigger SPF/DKIM/DMARC verification
|
|
332
|
+
domains.verify('dom_abc123').subscribe(domain => console.log(domain.status));
|
|
333
|
+
|
|
334
|
+
// List / get
|
|
335
|
+
domains.list().subscribe(({ data }) => console.log(data));
|
|
336
|
+
domains.get('dom_abc123').subscribe(domain => console.log(domain));
|
|
337
|
+
|
|
338
|
+
// Delete
|
|
339
|
+
domains.delete('dom_abc123').subscribe(({ deletedAt }) => console.log(deletedAt));
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
---
|
|
343
|
+
|
|
344
|
+
### API Keys
|
|
345
|
+
|
|
346
|
+
```ts
|
|
347
|
+
const { apiKeys } = inject(TrattoService);
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
```ts
|
|
351
|
+
// Create — raw key is shown only once
|
|
352
|
+
apiKeys.create({
|
|
353
|
+
name: 'CI deployment key',
|
|
354
|
+
env: 'live',
|
|
355
|
+
permissions: ['emails:send'],
|
|
356
|
+
}).subscribe(key => {
|
|
357
|
+
console.log('Raw key (save this!):', key.key);
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
// List (prefix only, never raw token)
|
|
361
|
+
apiKeys.list().subscribe(({ data }) => console.log(data));
|
|
362
|
+
|
|
363
|
+
// Revoke
|
|
364
|
+
apiKeys.revoke('key_abc123').subscribe(({ revokedAt }) => console.log(revokedAt));
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
---
|
|
368
|
+
|
|
369
|
+
### Analytics
|
|
370
|
+
|
|
371
|
+
```ts
|
|
372
|
+
const { analytics } = inject(TrattoService);
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
```ts
|
|
376
|
+
// Aggregated summary
|
|
377
|
+
analytics.getSummary('30d').subscribe(summary => {
|
|
378
|
+
console.log('Open rate:', summary.openRate);
|
|
379
|
+
console.log('Bounce rate:', summary.bounceRate);
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
// Daily timeseries
|
|
383
|
+
analytics.getTimeseries('7d').subscribe(points => console.log(points));
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
Supported periods: `'7d'` | `'30d'` | `'90d'`. Results are cached server-side for 1 hour.
|
|
387
|
+
|
|
388
|
+
---
|
|
389
|
+
|
|
390
|
+
### Flows
|
|
391
|
+
|
|
392
|
+
```ts
|
|
393
|
+
const { flows } = inject(TrattoService);
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
```ts
|
|
397
|
+
// Create a draft flow
|
|
398
|
+
flows.create({ name: 'Welcome series' }).subscribe(({ id }) => console.log(id));
|
|
399
|
+
|
|
400
|
+
// Configure trigger and steps
|
|
401
|
+
flows.update('flw_abc123', {
|
|
402
|
+
trigger: { type: 'contact_joins_audience', config: { audienceId: 'aud_abc123' } },
|
|
403
|
+
steps: [
|
|
404
|
+
{ id: 'step_1', type: 'send_email', config: { templateId: 'tpl_abc123' } },
|
|
405
|
+
{ id: 'step_2', type: 'wait', config: { delay: '3d' } },
|
|
406
|
+
{ id: 'step_3', type: 'send_email', config: { templateId: 'tpl_def456' } },
|
|
407
|
+
],
|
|
408
|
+
}).subscribe();
|
|
409
|
+
|
|
410
|
+
// Activate / deactivate
|
|
411
|
+
flows.activate('flw_abc123').subscribe(flow => console.log(flow.status));
|
|
412
|
+
flows.deactivate('flw_abc123').subscribe();
|
|
413
|
+
|
|
414
|
+
// Delete (draft or inactive only)
|
|
415
|
+
flows.delete('flw_abc123').subscribe();
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
---
|
|
419
|
+
|
|
420
|
+
### Workspace
|
|
421
|
+
|
|
422
|
+
```ts
|
|
423
|
+
const { workspace } = inject(TrattoService);
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
```ts
|
|
427
|
+
// Get current workspace
|
|
428
|
+
workspace.get().subscribe(ws => console.log(ws.name, ws.plan));
|
|
429
|
+
|
|
430
|
+
// Update settings
|
|
431
|
+
workspace.update({ name: 'Acme Corp', timezone: 'Europe/Rome' }).subscribe();
|
|
432
|
+
|
|
433
|
+
// Preferences
|
|
434
|
+
workspace.updatePreferences({
|
|
435
|
+
locale: 'en',
|
|
436
|
+
emailNotifications: { weeklyReport: true },
|
|
437
|
+
}).subscribe();
|
|
438
|
+
|
|
439
|
+
// Team management
|
|
440
|
+
workspace.inviteMember({ email: 'dev@acme.com', role: 'admin' }).subscribe();
|
|
441
|
+
workspace.updateMember('usr_abc123', { role: 'member' }).subscribe();
|
|
442
|
+
workspace.removeMember('usr_abc123').subscribe();
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
---
|
|
446
|
+
|
|
447
|
+
## Error handling
|
|
448
|
+
|
|
449
|
+
HTTP errors surface as Angular `HttpErrorResponse`. Use `catchError` from RxJS:
|
|
450
|
+
|
|
451
|
+
```ts
|
|
452
|
+
import { catchError, EMPTY } from 'rxjs';
|
|
453
|
+
|
|
454
|
+
emails.send({ from: '...', to: '...', subject: '...', html: '...' }).pipe(
|
|
455
|
+
catchError(err => {
|
|
456
|
+
console.error(err.status, err.error?.message);
|
|
457
|
+
return EMPTY;
|
|
458
|
+
}),
|
|
459
|
+
).subscribe(({ id }) => console.log(id));
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
---
|
|
463
|
+
|
|
464
|
+
## TypeScript
|
|
465
|
+
|
|
466
|
+
The SDK ships full type declarations. All request params and response shapes are exported:
|
|
467
|
+
|
|
468
|
+
```ts
|
|
469
|
+
import type {
|
|
470
|
+
SendEmailParams,
|
|
471
|
+
EmailDetail,
|
|
472
|
+
EmailEvent,
|
|
473
|
+
PaginatedResponse,
|
|
474
|
+
Contact,
|
|
475
|
+
Audience,
|
|
476
|
+
Campaign,
|
|
477
|
+
CampaignStatsDetail,
|
|
478
|
+
Template,
|
|
479
|
+
Webhook,
|
|
480
|
+
Domain,
|
|
481
|
+
ApiKey,
|
|
482
|
+
ApiKeyCreated,
|
|
483
|
+
AnalyticsSummary,
|
|
484
|
+
TimeseriesPoint,
|
|
485
|
+
Flow,
|
|
486
|
+
Workspace,
|
|
487
|
+
WorkspaceMember,
|
|
488
|
+
} from '@tratto/angular';
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
---
|
|
492
|
+
|
|
493
|
+
## Example app
|
|
494
|
+
|
|
495
|
+
See [`examples/angular-app`](examples/angular-app) for a runnable Angular 22 standalone app
|
|
496
|
+
that demonstrates SDK setup, email sending, contact listing, and analytics.
|
|
497
|
+
|
|
498
|
+
---
|
|
499
|
+
|
|
500
|
+
## License
|
|
501
|
+
|
|
502
|
+
MIT
|