zupost 0.2.0 → 0.5.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/dist/index.d.mts +456 -2
- package/dist/index.d.ts +456 -2
- package/dist/index.js +280 -4
- package/dist/index.mjs +278 -3
- package/package.json +60 -61
package/dist/index.js
CHANGED
|
@@ -73,12 +73,13 @@ var __async = (__this, __arguments, generator) => {
|
|
|
73
73
|
var index_exports = {};
|
|
74
74
|
__export(index_exports, {
|
|
75
75
|
Zupost: () => Zupost,
|
|
76
|
-
ZupostError: () => ZupostError
|
|
76
|
+
ZupostError: () => ZupostError,
|
|
77
|
+
defineSequence: () => defineSequence
|
|
77
78
|
});
|
|
78
79
|
module.exports = __toCommonJS(index_exports);
|
|
79
80
|
|
|
80
81
|
// package.json
|
|
81
|
-
var version = "0.
|
|
82
|
+
var version = "0.5.1";
|
|
82
83
|
|
|
83
84
|
// src/errors.ts
|
|
84
85
|
var ZupostError = class _ZupostError extends Error {
|
|
@@ -139,7 +140,7 @@ var HttpClient = class {
|
|
|
139
140
|
__privateAdd(this, _baseUrl);
|
|
140
141
|
__privateSet(this, _baseUrl, baseUrl.replace(/\/$/, ""));
|
|
141
142
|
__privateSet(this, _defaultHeaders, {
|
|
142
|
-
Authorization: `Bearer ${apiKey}`,
|
|
143
|
+
"Authorization": `Bearer ${apiKey}`,
|
|
143
144
|
"Content-Type": "application/json",
|
|
144
145
|
"User-Agent": userAgent
|
|
145
146
|
});
|
|
@@ -187,6 +188,16 @@ var HttpClient = class {
|
|
|
187
188
|
return this.request(path, "POST", body);
|
|
188
189
|
});
|
|
189
190
|
}
|
|
191
|
+
patch(path, body) {
|
|
192
|
+
return __async(this, null, function* () {
|
|
193
|
+
return this.request(path, "PATCH", body);
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
delete(path, body) {
|
|
197
|
+
return __async(this, null, function* () {
|
|
198
|
+
return this.request(path, "DELETE", body);
|
|
199
|
+
});
|
|
200
|
+
}
|
|
190
201
|
};
|
|
191
202
|
_defaultHeaders = new WeakMap();
|
|
192
203
|
_baseUrl = new WeakMap();
|
|
@@ -302,6 +313,229 @@ var Campaigns = class {
|
|
|
302
313
|
}
|
|
303
314
|
};
|
|
304
315
|
|
|
316
|
+
// src/contact/contacts.ts
|
|
317
|
+
function buildQuery(params) {
|
|
318
|
+
const search = new URLSearchParams();
|
|
319
|
+
for (const [key, value] of Object.entries(params)) {
|
|
320
|
+
if (value === void 0) continue;
|
|
321
|
+
if (Array.isArray(value)) {
|
|
322
|
+
for (const v of value) search.append(key, String(v));
|
|
323
|
+
} else {
|
|
324
|
+
search.set(key, String(value));
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
const query = search.toString();
|
|
328
|
+
return query ? `?${query}` : "";
|
|
329
|
+
}
|
|
330
|
+
var Contacts = class {
|
|
331
|
+
constructor(http) {
|
|
332
|
+
this.http = http;
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Create or upsert a contact by email. Idempotent on (project, email).
|
|
336
|
+
*
|
|
337
|
+
* @example
|
|
338
|
+
* ```typescript
|
|
339
|
+
* const contact = await zupost.contacts.create({
|
|
340
|
+
* email: 'user@example.com',
|
|
341
|
+
* name: 'Jane Doe',
|
|
342
|
+
* marketingConsent: true,
|
|
343
|
+
* marketingConsentSource: 'signup-form',
|
|
344
|
+
* tags: ['vip', 'beta'],
|
|
345
|
+
* });
|
|
346
|
+
* ```
|
|
347
|
+
*/
|
|
348
|
+
create(options) {
|
|
349
|
+
return __async(this, null, function* () {
|
|
350
|
+
return this.http.post("/contact", options);
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Get a contact by ID.
|
|
355
|
+
*/
|
|
356
|
+
get(id) {
|
|
357
|
+
return __async(this, null, function* () {
|
|
358
|
+
return this.http.get(`/contact/${encodeURIComponent(id)}`);
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* List contacts with optional search, consent and tag filters.
|
|
363
|
+
*/
|
|
364
|
+
list() {
|
|
365
|
+
return __async(this, arguments, function* (options = {}) {
|
|
366
|
+
const query = buildQuery({
|
|
367
|
+
skip: options.skip,
|
|
368
|
+
take: options.take,
|
|
369
|
+
search: options.search,
|
|
370
|
+
marketingConsent: options.marketingConsent === void 0 ? void 0 : String(options.marketingConsent),
|
|
371
|
+
tag: options.tag
|
|
372
|
+
});
|
|
373
|
+
return this.http.get(`/contact${query}`);
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Update a contact. Pass only the fields that should change.
|
|
378
|
+
*
|
|
379
|
+
* Toggling `marketingConsent` or `trackingConsent` automatically records
|
|
380
|
+
* a corresponding ContactEvent for the audit trail.
|
|
381
|
+
*/
|
|
382
|
+
update(id, patch) {
|
|
383
|
+
return __async(this, null, function* () {
|
|
384
|
+
return this.http.patch(`/contact/${encodeURIComponent(id)}`, patch);
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* GDPR right-to-be-forgotten. Anonymises the contact, sets `forgottenAt`
|
|
389
|
+
* and disables consent. Existing email events are anonymised in a
|
|
390
|
+
* follow-up cascade.
|
|
391
|
+
*/
|
|
392
|
+
forget(id) {
|
|
393
|
+
return __async(this, null, function* () {
|
|
394
|
+
return this.http.delete(`/contact/${encodeURIComponent(id)}`);
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Get the chronological event timeline for a contact.
|
|
399
|
+
*/
|
|
400
|
+
events(_0) {
|
|
401
|
+
return __async(this, arguments, function* (id, options = {}) {
|
|
402
|
+
const query = buildQuery({
|
|
403
|
+
skip: options.skip,
|
|
404
|
+
take: options.take,
|
|
405
|
+
type: options.type
|
|
406
|
+
});
|
|
407
|
+
return this.http.get(`/contact/${encodeURIComponent(id)}/events${query}`);
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* GDPR data access export. Returns the complete record for a contact
|
|
412
|
+
* including all emails, events, subscriptions and tags.
|
|
413
|
+
*/
|
|
414
|
+
export(id) {
|
|
415
|
+
return __async(this, null, function* () {
|
|
416
|
+
return this.http.get(`/contact/${encodeURIComponent(id)}/export`);
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Add a tag to a contact (idempotent).
|
|
421
|
+
*/
|
|
422
|
+
addTag(id, name) {
|
|
423
|
+
return __async(this, null, function* () {
|
|
424
|
+
return this.http.post(`/contact/${encodeURIComponent(id)}/tags`, { name });
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Remove a tag from a contact.
|
|
429
|
+
*/
|
|
430
|
+
removeTag(id, name) {
|
|
431
|
+
return __async(this, null, function* () {
|
|
432
|
+
return this.http.delete(
|
|
433
|
+
`/contact/${encodeURIComponent(id)}/tags/${encodeURIComponent(name)}`
|
|
434
|
+
);
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
};
|
|
438
|
+
|
|
439
|
+
// src/sequence/sequences.ts
|
|
440
|
+
function buildQuery2(params) {
|
|
441
|
+
const search = new URLSearchParams();
|
|
442
|
+
for (const [key, value] of Object.entries(params)) {
|
|
443
|
+
if (value === void 0) continue;
|
|
444
|
+
search.set(key, String(value));
|
|
445
|
+
}
|
|
446
|
+
const q = search.toString();
|
|
447
|
+
return q ? `?${q}` : "";
|
|
448
|
+
}
|
|
449
|
+
var Sequences = class {
|
|
450
|
+
constructor(http) {
|
|
451
|
+
this.http = http;
|
|
452
|
+
this.runs = {
|
|
453
|
+
list: (_0, ..._1) => __async(this, [_0, ..._1], function* (sequenceId, options = {}) {
|
|
454
|
+
const query = buildQuery2({
|
|
455
|
+
skip: options.skip,
|
|
456
|
+
take: options.take,
|
|
457
|
+
status: options.status,
|
|
458
|
+
contactId: options.contactId
|
|
459
|
+
});
|
|
460
|
+
return this.http.get(
|
|
461
|
+
`/sequence/${encodeURIComponent(sequenceId)}/runs${query}`
|
|
462
|
+
);
|
|
463
|
+
})
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Create a new sequence (always starts in DRAFT). Pass `definition` to
|
|
468
|
+
* seed the first version, or omit it to create an empty placeholder you
|
|
469
|
+
* can later push versions into.
|
|
470
|
+
*/
|
|
471
|
+
create(options) {
|
|
472
|
+
return __async(this, null, function* () {
|
|
473
|
+
return this.http.post("/sequence", options);
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* Get a sequence by ID.
|
|
478
|
+
*/
|
|
479
|
+
get(id) {
|
|
480
|
+
return __async(this, null, function* () {
|
|
481
|
+
return this.http.get(`/sequence/${encodeURIComponent(id)}`);
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
/**
|
|
485
|
+
* List sequences with filters.
|
|
486
|
+
*/
|
|
487
|
+
list() {
|
|
488
|
+
return __async(this, arguments, function* (options = {}) {
|
|
489
|
+
const query = buildQuery2({
|
|
490
|
+
skip: options.skip,
|
|
491
|
+
take: options.take,
|
|
492
|
+
type: options.type,
|
|
493
|
+
status: options.status,
|
|
494
|
+
search: options.search
|
|
495
|
+
});
|
|
496
|
+
return this.http.get(`/sequence${query}`);
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
500
|
+
* Delete a sequence and all its versions and runs.
|
|
501
|
+
*/
|
|
502
|
+
delete(id) {
|
|
503
|
+
return __async(this, null, function* () {
|
|
504
|
+
return this.http.delete(`/sequence/${encodeURIComponent(id)}`);
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* Change the lifecycle status: DRAFT, ACTIVE, PAUSED, ARCHIVED.
|
|
509
|
+
*/
|
|
510
|
+
setStatus(id, status) {
|
|
511
|
+
return __async(this, null, function* () {
|
|
512
|
+
return this.http.post(`/sequence/${encodeURIComponent(id)}/status`, { status });
|
|
513
|
+
});
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* Save a new immutable version of the sequence definition. If `activate`
|
|
517
|
+
* is true (default), the new version becomes the active one for future
|
|
518
|
+
* triggered runs. Existing in-flight runs keep their pinned version.
|
|
519
|
+
*/
|
|
520
|
+
saveVersion(id, options) {
|
|
521
|
+
return __async(this, null, function* () {
|
|
522
|
+
return this.http.post(`/sequence/${encodeURIComponent(id)}/versions`, options);
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* Trigger a sequence run for a contact or ad-hoc email. The sequence
|
|
527
|
+
* must be ACTIVE.
|
|
528
|
+
*/
|
|
529
|
+
trigger(id, options) {
|
|
530
|
+
return __async(this, null, function* () {
|
|
531
|
+
if (!options.contactId && !options.email) {
|
|
532
|
+
throw new Error("trigger requires contactId or email");
|
|
533
|
+
}
|
|
534
|
+
return this.http.post(`/sequence/${encodeURIComponent(id)}/runs`, options);
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
};
|
|
538
|
+
|
|
305
539
|
// src/zupost.ts
|
|
306
540
|
var _client;
|
|
307
541
|
var Zupost = class {
|
|
@@ -315,11 +549,53 @@ var Zupost = class {
|
|
|
315
549
|
__privateSet(this, _client, new HttpClient(apiKey, baseUrl, `node-sdk@${version}`));
|
|
316
550
|
this.emails = new Emails(__privateGet(this, _client));
|
|
317
551
|
this.campaigns = new Campaigns(__privateGet(this, _client));
|
|
552
|
+
this.contacts = new Contacts(__privateGet(this, _client));
|
|
553
|
+
this.sequences = new Sequences(__privateGet(this, _client));
|
|
318
554
|
}
|
|
319
555
|
};
|
|
320
556
|
_client = new WeakMap();
|
|
557
|
+
|
|
558
|
+
// src/sequence/define.ts
|
|
559
|
+
function defineSequence(definition) {
|
|
560
|
+
const issues = [];
|
|
561
|
+
const stepKeys = Object.keys(definition.steps);
|
|
562
|
+
if (!definition.steps[definition.entry]) {
|
|
563
|
+
issues.push(`entry "${String(definition.entry)}" is not a defined step`);
|
|
564
|
+
}
|
|
565
|
+
if (stepKeys.length === 0) issues.push("steps must contain at least one step");
|
|
566
|
+
for (const key of stepKeys) {
|
|
567
|
+
const step = definition.steps[key];
|
|
568
|
+
if (step.key !== key) issues.push(`step.key "${step.key}" does not match object key "${key}"`);
|
|
569
|
+
const checkRef = (ref, where) => {
|
|
570
|
+
if (ref && !definition.steps[ref]) {
|
|
571
|
+
issues.push(`step "${key}" ${where} points at unknown step "${ref}"`);
|
|
572
|
+
}
|
|
573
|
+
};
|
|
574
|
+
switch (step.type) {
|
|
575
|
+
case "send_email":
|
|
576
|
+
case "wait":
|
|
577
|
+
case "tag_add":
|
|
578
|
+
case "tag_remove":
|
|
579
|
+
case "update_contact":
|
|
580
|
+
case "webhook":
|
|
581
|
+
checkRef(step.next, "next");
|
|
582
|
+
break;
|
|
583
|
+
case "branch":
|
|
584
|
+
checkRef(step.thenNext, "thenNext");
|
|
585
|
+
checkRef(step.elseNext, "elseNext");
|
|
586
|
+
break;
|
|
587
|
+
case "end":
|
|
588
|
+
break;
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
if (issues.length > 0) {
|
|
592
|
+
throw new Error(`Invalid sequence definition: ${issues.join("; ")}`);
|
|
593
|
+
}
|
|
594
|
+
return definition;
|
|
595
|
+
}
|
|
321
596
|
// Annotate the CommonJS export names for ESM import in node:
|
|
322
597
|
0 && (module.exports = {
|
|
323
598
|
Zupost,
|
|
324
|
-
ZupostError
|
|
599
|
+
ZupostError,
|
|
600
|
+
defineSequence
|
|
325
601
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -44,7 +44,7 @@ var __async = (__this, __arguments, generator) => {
|
|
|
44
44
|
};
|
|
45
45
|
|
|
46
46
|
// package.json
|
|
47
|
-
var version = "0.
|
|
47
|
+
var version = "0.5.1";
|
|
48
48
|
|
|
49
49
|
// src/errors.ts
|
|
50
50
|
var ZupostError = class _ZupostError extends Error {
|
|
@@ -105,7 +105,7 @@ var HttpClient = class {
|
|
|
105
105
|
__privateAdd(this, _baseUrl);
|
|
106
106
|
__privateSet(this, _baseUrl, baseUrl.replace(/\/$/, ""));
|
|
107
107
|
__privateSet(this, _defaultHeaders, {
|
|
108
|
-
Authorization: `Bearer ${apiKey}`,
|
|
108
|
+
"Authorization": `Bearer ${apiKey}`,
|
|
109
109
|
"Content-Type": "application/json",
|
|
110
110
|
"User-Agent": userAgent
|
|
111
111
|
});
|
|
@@ -153,6 +153,16 @@ var HttpClient = class {
|
|
|
153
153
|
return this.request(path, "POST", body);
|
|
154
154
|
});
|
|
155
155
|
}
|
|
156
|
+
patch(path, body) {
|
|
157
|
+
return __async(this, null, function* () {
|
|
158
|
+
return this.request(path, "PATCH", body);
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
delete(path, body) {
|
|
162
|
+
return __async(this, null, function* () {
|
|
163
|
+
return this.request(path, "DELETE", body);
|
|
164
|
+
});
|
|
165
|
+
}
|
|
156
166
|
};
|
|
157
167
|
_defaultHeaders = new WeakMap();
|
|
158
168
|
_baseUrl = new WeakMap();
|
|
@@ -268,6 +278,229 @@ var Campaigns = class {
|
|
|
268
278
|
}
|
|
269
279
|
};
|
|
270
280
|
|
|
281
|
+
// src/contact/contacts.ts
|
|
282
|
+
function buildQuery(params) {
|
|
283
|
+
const search = new URLSearchParams();
|
|
284
|
+
for (const [key, value] of Object.entries(params)) {
|
|
285
|
+
if (value === void 0) continue;
|
|
286
|
+
if (Array.isArray(value)) {
|
|
287
|
+
for (const v of value) search.append(key, String(v));
|
|
288
|
+
} else {
|
|
289
|
+
search.set(key, String(value));
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
const query = search.toString();
|
|
293
|
+
return query ? `?${query}` : "";
|
|
294
|
+
}
|
|
295
|
+
var Contacts = class {
|
|
296
|
+
constructor(http) {
|
|
297
|
+
this.http = http;
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Create or upsert a contact by email. Idempotent on (project, email).
|
|
301
|
+
*
|
|
302
|
+
* @example
|
|
303
|
+
* ```typescript
|
|
304
|
+
* const contact = await zupost.contacts.create({
|
|
305
|
+
* email: 'user@example.com',
|
|
306
|
+
* name: 'Jane Doe',
|
|
307
|
+
* marketingConsent: true,
|
|
308
|
+
* marketingConsentSource: 'signup-form',
|
|
309
|
+
* tags: ['vip', 'beta'],
|
|
310
|
+
* });
|
|
311
|
+
* ```
|
|
312
|
+
*/
|
|
313
|
+
create(options) {
|
|
314
|
+
return __async(this, null, function* () {
|
|
315
|
+
return this.http.post("/contact", options);
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Get a contact by ID.
|
|
320
|
+
*/
|
|
321
|
+
get(id) {
|
|
322
|
+
return __async(this, null, function* () {
|
|
323
|
+
return this.http.get(`/contact/${encodeURIComponent(id)}`);
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* List contacts with optional search, consent and tag filters.
|
|
328
|
+
*/
|
|
329
|
+
list() {
|
|
330
|
+
return __async(this, arguments, function* (options = {}) {
|
|
331
|
+
const query = buildQuery({
|
|
332
|
+
skip: options.skip,
|
|
333
|
+
take: options.take,
|
|
334
|
+
search: options.search,
|
|
335
|
+
marketingConsent: options.marketingConsent === void 0 ? void 0 : String(options.marketingConsent),
|
|
336
|
+
tag: options.tag
|
|
337
|
+
});
|
|
338
|
+
return this.http.get(`/contact${query}`);
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Update a contact. Pass only the fields that should change.
|
|
343
|
+
*
|
|
344
|
+
* Toggling `marketingConsent` or `trackingConsent` automatically records
|
|
345
|
+
* a corresponding ContactEvent for the audit trail.
|
|
346
|
+
*/
|
|
347
|
+
update(id, patch) {
|
|
348
|
+
return __async(this, null, function* () {
|
|
349
|
+
return this.http.patch(`/contact/${encodeURIComponent(id)}`, patch);
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* GDPR right-to-be-forgotten. Anonymises the contact, sets `forgottenAt`
|
|
354
|
+
* and disables consent. Existing email events are anonymised in a
|
|
355
|
+
* follow-up cascade.
|
|
356
|
+
*/
|
|
357
|
+
forget(id) {
|
|
358
|
+
return __async(this, null, function* () {
|
|
359
|
+
return this.http.delete(`/contact/${encodeURIComponent(id)}`);
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Get the chronological event timeline for a contact.
|
|
364
|
+
*/
|
|
365
|
+
events(_0) {
|
|
366
|
+
return __async(this, arguments, function* (id, options = {}) {
|
|
367
|
+
const query = buildQuery({
|
|
368
|
+
skip: options.skip,
|
|
369
|
+
take: options.take,
|
|
370
|
+
type: options.type
|
|
371
|
+
});
|
|
372
|
+
return this.http.get(`/contact/${encodeURIComponent(id)}/events${query}`);
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* GDPR data access export. Returns the complete record for a contact
|
|
377
|
+
* including all emails, events, subscriptions and tags.
|
|
378
|
+
*/
|
|
379
|
+
export(id) {
|
|
380
|
+
return __async(this, null, function* () {
|
|
381
|
+
return this.http.get(`/contact/${encodeURIComponent(id)}/export`);
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Add a tag to a contact (idempotent).
|
|
386
|
+
*/
|
|
387
|
+
addTag(id, name) {
|
|
388
|
+
return __async(this, null, function* () {
|
|
389
|
+
return this.http.post(`/contact/${encodeURIComponent(id)}/tags`, { name });
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Remove a tag from a contact.
|
|
394
|
+
*/
|
|
395
|
+
removeTag(id, name) {
|
|
396
|
+
return __async(this, null, function* () {
|
|
397
|
+
return this.http.delete(
|
|
398
|
+
`/contact/${encodeURIComponent(id)}/tags/${encodeURIComponent(name)}`
|
|
399
|
+
);
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
// src/sequence/sequences.ts
|
|
405
|
+
function buildQuery2(params) {
|
|
406
|
+
const search = new URLSearchParams();
|
|
407
|
+
for (const [key, value] of Object.entries(params)) {
|
|
408
|
+
if (value === void 0) continue;
|
|
409
|
+
search.set(key, String(value));
|
|
410
|
+
}
|
|
411
|
+
const q = search.toString();
|
|
412
|
+
return q ? `?${q}` : "";
|
|
413
|
+
}
|
|
414
|
+
var Sequences = class {
|
|
415
|
+
constructor(http) {
|
|
416
|
+
this.http = http;
|
|
417
|
+
this.runs = {
|
|
418
|
+
list: (_0, ..._1) => __async(this, [_0, ..._1], function* (sequenceId, options = {}) {
|
|
419
|
+
const query = buildQuery2({
|
|
420
|
+
skip: options.skip,
|
|
421
|
+
take: options.take,
|
|
422
|
+
status: options.status,
|
|
423
|
+
contactId: options.contactId
|
|
424
|
+
});
|
|
425
|
+
return this.http.get(
|
|
426
|
+
`/sequence/${encodeURIComponent(sequenceId)}/runs${query}`
|
|
427
|
+
);
|
|
428
|
+
})
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Create a new sequence (always starts in DRAFT). Pass `definition` to
|
|
433
|
+
* seed the first version, or omit it to create an empty placeholder you
|
|
434
|
+
* can later push versions into.
|
|
435
|
+
*/
|
|
436
|
+
create(options) {
|
|
437
|
+
return __async(this, null, function* () {
|
|
438
|
+
return this.http.post("/sequence", options);
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* Get a sequence by ID.
|
|
443
|
+
*/
|
|
444
|
+
get(id) {
|
|
445
|
+
return __async(this, null, function* () {
|
|
446
|
+
return this.http.get(`/sequence/${encodeURIComponent(id)}`);
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
/**
|
|
450
|
+
* List sequences with filters.
|
|
451
|
+
*/
|
|
452
|
+
list() {
|
|
453
|
+
return __async(this, arguments, function* (options = {}) {
|
|
454
|
+
const query = buildQuery2({
|
|
455
|
+
skip: options.skip,
|
|
456
|
+
take: options.take,
|
|
457
|
+
type: options.type,
|
|
458
|
+
status: options.status,
|
|
459
|
+
search: options.search
|
|
460
|
+
});
|
|
461
|
+
return this.http.get(`/sequence${query}`);
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* Delete a sequence and all its versions and runs.
|
|
466
|
+
*/
|
|
467
|
+
delete(id) {
|
|
468
|
+
return __async(this, null, function* () {
|
|
469
|
+
return this.http.delete(`/sequence/${encodeURIComponent(id)}`);
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* Change the lifecycle status: DRAFT, ACTIVE, PAUSED, ARCHIVED.
|
|
474
|
+
*/
|
|
475
|
+
setStatus(id, status) {
|
|
476
|
+
return __async(this, null, function* () {
|
|
477
|
+
return this.http.post(`/sequence/${encodeURIComponent(id)}/status`, { status });
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* Save a new immutable version of the sequence definition. If `activate`
|
|
482
|
+
* is true (default), the new version becomes the active one for future
|
|
483
|
+
* triggered runs. Existing in-flight runs keep their pinned version.
|
|
484
|
+
*/
|
|
485
|
+
saveVersion(id, options) {
|
|
486
|
+
return __async(this, null, function* () {
|
|
487
|
+
return this.http.post(`/sequence/${encodeURIComponent(id)}/versions`, options);
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* Trigger a sequence run for a contact or ad-hoc email. The sequence
|
|
492
|
+
* must be ACTIVE.
|
|
493
|
+
*/
|
|
494
|
+
trigger(id, options) {
|
|
495
|
+
return __async(this, null, function* () {
|
|
496
|
+
if (!options.contactId && !options.email) {
|
|
497
|
+
throw new Error("trigger requires contactId or email");
|
|
498
|
+
}
|
|
499
|
+
return this.http.post(`/sequence/${encodeURIComponent(id)}/runs`, options);
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
};
|
|
503
|
+
|
|
271
504
|
// src/zupost.ts
|
|
272
505
|
var _client;
|
|
273
506
|
var Zupost = class {
|
|
@@ -281,10 +514,52 @@ var Zupost = class {
|
|
|
281
514
|
__privateSet(this, _client, new HttpClient(apiKey, baseUrl, `node-sdk@${version}`));
|
|
282
515
|
this.emails = new Emails(__privateGet(this, _client));
|
|
283
516
|
this.campaigns = new Campaigns(__privateGet(this, _client));
|
|
517
|
+
this.contacts = new Contacts(__privateGet(this, _client));
|
|
518
|
+
this.sequences = new Sequences(__privateGet(this, _client));
|
|
284
519
|
}
|
|
285
520
|
};
|
|
286
521
|
_client = new WeakMap();
|
|
522
|
+
|
|
523
|
+
// src/sequence/define.ts
|
|
524
|
+
function defineSequence(definition) {
|
|
525
|
+
const issues = [];
|
|
526
|
+
const stepKeys = Object.keys(definition.steps);
|
|
527
|
+
if (!definition.steps[definition.entry]) {
|
|
528
|
+
issues.push(`entry "${String(definition.entry)}" is not a defined step`);
|
|
529
|
+
}
|
|
530
|
+
if (stepKeys.length === 0) issues.push("steps must contain at least one step");
|
|
531
|
+
for (const key of stepKeys) {
|
|
532
|
+
const step = definition.steps[key];
|
|
533
|
+
if (step.key !== key) issues.push(`step.key "${step.key}" does not match object key "${key}"`);
|
|
534
|
+
const checkRef = (ref, where) => {
|
|
535
|
+
if (ref && !definition.steps[ref]) {
|
|
536
|
+
issues.push(`step "${key}" ${where} points at unknown step "${ref}"`);
|
|
537
|
+
}
|
|
538
|
+
};
|
|
539
|
+
switch (step.type) {
|
|
540
|
+
case "send_email":
|
|
541
|
+
case "wait":
|
|
542
|
+
case "tag_add":
|
|
543
|
+
case "tag_remove":
|
|
544
|
+
case "update_contact":
|
|
545
|
+
case "webhook":
|
|
546
|
+
checkRef(step.next, "next");
|
|
547
|
+
break;
|
|
548
|
+
case "branch":
|
|
549
|
+
checkRef(step.thenNext, "thenNext");
|
|
550
|
+
checkRef(step.elseNext, "elseNext");
|
|
551
|
+
break;
|
|
552
|
+
case "end":
|
|
553
|
+
break;
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
if (issues.length > 0) {
|
|
557
|
+
throw new Error(`Invalid sequence definition: ${issues.join("; ")}`);
|
|
558
|
+
}
|
|
559
|
+
return definition;
|
|
560
|
+
}
|
|
287
561
|
export {
|
|
288
562
|
Zupost,
|
|
289
|
-
ZupostError
|
|
563
|
+
ZupostError,
|
|
564
|
+
defineSequence
|
|
290
565
|
};
|