@marlinjai/mail-contract 0.10.0 → 0.12.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/dist/index.d.mts +2418 -988
- package/dist/index.d.ts +2418 -988
- package/dist/index.js +926 -640
- package/dist/index.mjs +900 -640
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -209,6 +209,7 @@ __export(index_exports, {
|
|
|
209
209
|
InviteListQuery: () => InviteListQuery,
|
|
210
210
|
InviteStatus: () => InviteStatus,
|
|
211
211
|
JsonValue: () => JsonValue,
|
|
212
|
+
LETTER_ONLY_MERGE_FIELDS: () => LETTER_ONLY_MERGE_FIELDS,
|
|
212
213
|
LETTER_RECIPIENT_REFUSAL: () => LETTER_RECIPIENT_REFUSAL,
|
|
213
214
|
LIST_UNSUBSCRIBE_POST_VALUE: () => LIST_UNSUBSCRIBE_POST_VALUE,
|
|
214
215
|
LOCALE_TAG_PATTERN: () => LOCALE_TAG_PATTERN,
|
|
@@ -277,7 +278,10 @@ __export(index_exports, {
|
|
|
277
278
|
MailingLanguageReport: () => MailingLanguageReport,
|
|
278
279
|
MailingLanguageStatus: () => MailingLanguageStatus,
|
|
279
280
|
MailingListQuery: () => MailingListQuery,
|
|
281
|
+
MailingMerge: () => MailingMerge,
|
|
280
282
|
MailingMetadata: () => MailingMetadata,
|
|
283
|
+
MailingResolveRequest: () => MailingResolveRequest,
|
|
284
|
+
MailingResolveResult: () => MailingResolveResult,
|
|
281
285
|
MailingRetryFailedRequest: () => MailingRetryFailedRequest,
|
|
282
286
|
MailingScheduleFailedData: () => MailingScheduleFailedData,
|
|
283
287
|
MailingScheduleRequest: () => MailingScheduleRequest,
|
|
@@ -302,6 +306,8 @@ __export(index_exports, {
|
|
|
302
306
|
MessageOutcome: () => MessageOutcome,
|
|
303
307
|
MessageSentData: () => MessageSentData,
|
|
304
308
|
MessageSummary: () => MessageSummary,
|
|
309
|
+
MessageValues: () => MessageValues,
|
|
310
|
+
NAME_ON_BROADCAST_REFUSAL: () => NAME_ON_BROADCAST_REFUSAL,
|
|
305
311
|
NotifyRecipients: () => NotifyRecipients,
|
|
306
312
|
NotifyStep: () => NotifyStep,
|
|
307
313
|
ON_BEHALF_OF_HEADER: () => ON_BEHALF_OF_HEADER,
|
|
@@ -337,6 +343,8 @@ __export(index_exports, {
|
|
|
337
343
|
REQUEST_ID_HEADER: () => REQUEST_ID_HEADER,
|
|
338
344
|
RESEND_EVENT_TYPES: () => RESEND_EVENT_TYPES,
|
|
339
345
|
RESERVED_MERGE_FIELDS: () => RESERVED_MERGE_FIELDS,
|
|
346
|
+
RESOLVE_PROBLEMS: () => RESOLVE_PROBLEMS,
|
|
347
|
+
RESOLVE_REJECTIONS: () => RESOLVE_REJECTIONS,
|
|
340
348
|
RETRYABLE_ERRORS: () => RETRYABLE_ERRORS,
|
|
341
349
|
RETRY_AFTER_HEADER: () => RETRY_AFTER_HEADER,
|
|
342
350
|
RE_ENTRY_MODES: () => RE_ENTRY_MODES,
|
|
@@ -349,6 +357,9 @@ __export(index_exports, {
|
|
|
349
357
|
RecipientStatus: () => RecipientStatus,
|
|
350
358
|
RemoteImage: () => RemoteImage,
|
|
351
359
|
ResendSigningSecret: () => ResendSigningSecret,
|
|
360
|
+
ResolveProblem: () => ResolveProblem,
|
|
361
|
+
ResolvedRecipient: () => ResolvedRecipient,
|
|
362
|
+
ResolvedValue: () => ResolvedValue,
|
|
352
363
|
SERVICE_FILLED_MERGE_FIELDS: () => SERVICE_FILLED_MERGE_FIELDS,
|
|
353
364
|
SIGNUP_FORM_FIELDS: () => SIGNUP_FORM_FIELDS,
|
|
354
365
|
SKIP_REASONS: () => SKIP_REASONS,
|
|
@@ -385,6 +396,8 @@ __export(index_exports, {
|
|
|
385
396
|
TEMPLATE_SORTS: () => TEMPLATE_SORTS,
|
|
386
397
|
TEMPLATE_SORT_DEFAULT_ORDER: () => TEMPLATE_SORT_DEFAULT_ORDER,
|
|
387
398
|
TERMINAL_MAILING_STATUSES: () => TERMINAL_MAILING_STATUSES,
|
|
399
|
+
TRUSTED_APPS: () => TRUSTED_APPS,
|
|
400
|
+
TRUSTED_APP_OPERATIONS: () => TRUSTED_APP_OPERATIONS,
|
|
388
401
|
Tag: () => Tag,
|
|
389
402
|
TagAssignment: () => TagAssignment,
|
|
390
403
|
TagCreate: () => TagCreate,
|
|
@@ -430,15 +443,19 @@ __export(index_exports, {
|
|
|
430
443
|
TrackingSettings: () => TrackingSettings,
|
|
431
444
|
TranslationInsertion: () => TranslationInsertion,
|
|
432
445
|
TranslationInsertions: () => TranslationInsertions,
|
|
446
|
+
TrustedApp: () => TrustedApp,
|
|
433
447
|
UNSUBSCRIBE_PATH_PREFIX: () => UNSUBSCRIBE_PATH_PREFIX,
|
|
434
448
|
UNSUBSCRIBE_SOURCES: () => UNSUBSCRIBE_SOURCES,
|
|
435
449
|
USAGE_METRICS: () => USAGE_METRICS,
|
|
436
450
|
USAGE_WARNING_HEADER: () => USAGE_WARNING_HEADER,
|
|
437
451
|
USAGE_WARNING_RATIO: () => USAGE_WARNING_RATIO,
|
|
452
|
+
UnfilledLink: () => UnfilledLink,
|
|
438
453
|
Usage: () => Usage,
|
|
439
454
|
UsageMetric: () => UsageMetric,
|
|
440
455
|
UsageWarning: () => UsageWarning,
|
|
456
|
+
VALUE_LAYERS: () => VALUE_LAYERS,
|
|
441
457
|
ValidationIssue: () => ValidationIssue,
|
|
458
|
+
ValueLayer: () => ValueLayer,
|
|
442
459
|
VariantAnalytics: () => VariantAnalytics,
|
|
443
460
|
WEBHOOK_DELIVERY_STATUSES: () => WEBHOOK_DELIVERY_STATUSES,
|
|
444
461
|
WEBHOOK_EVENT_ID_HEADER: () => WEBHOOK_EVENT_ID_HEADER,
|
|
@@ -502,6 +519,7 @@ __export(index_exports, {
|
|
|
502
519
|
editMainInsertions: () => editMainInsertions,
|
|
503
520
|
effectivePreviewPicks: () => effectivePreviewPicks,
|
|
504
521
|
emptyFlow: () => emptyFlow,
|
|
522
|
+
emptyLinkValues: () => emptyLinkValues,
|
|
505
523
|
errorBody: () => errorBody,
|
|
506
524
|
escapeMergeHtml: () => escapeMergeHtml,
|
|
507
525
|
exportFilename: () => exportFilename,
|
|
@@ -532,6 +550,8 @@ __export(index_exports, {
|
|
|
532
550
|
languageInsertions: () => languageInsertions,
|
|
533
551
|
languageName: () => languageName,
|
|
534
552
|
languageTabs: () => languageTabs,
|
|
553
|
+
letterOnlyValues: () => letterOnlyValues,
|
|
554
|
+
linkTokens: () => linkTokens,
|
|
535
555
|
mainInsertionText: () => mainInsertionText,
|
|
536
556
|
matchLocale: () => matchLocale,
|
|
537
557
|
matchRoute: () => matchRoute,
|
|
@@ -552,6 +572,8 @@ __export(index_exports, {
|
|
|
552
572
|
previewInsertions: () => previewInsertions,
|
|
553
573
|
previewPersonalization: () => previewPersonalization,
|
|
554
574
|
primaryLanguage: () => primaryLanguage,
|
|
575
|
+
printedFields: () => printedFields,
|
|
576
|
+
rawMergeValue: () => rawMergeValue,
|
|
555
577
|
reachable: () => reachable,
|
|
556
578
|
readyWithoutInsertions: () => readyWithoutInsertions,
|
|
557
579
|
readyWithoutSubject: () => readyWithoutSubject,
|
|
@@ -568,6 +590,7 @@ __export(index_exports, {
|
|
|
568
590
|
renameTokenInDocument: () => renameTokenInDocument,
|
|
569
591
|
renameTokenInText: () => renameTokenInText,
|
|
570
592
|
resolveInsertions: () => resolveInsertions,
|
|
593
|
+
resolveValue: () => resolveValue,
|
|
571
594
|
restorePatch: () => restorePatch,
|
|
572
595
|
routes: () => routes,
|
|
573
596
|
sameJson: () => sameJson,
|
|
@@ -591,9 +614,12 @@ __export(index_exports, {
|
|
|
591
614
|
translationInsertionProblems: () => translationInsertionProblems,
|
|
592
615
|
translationTextFromInput: () => translationTextFromInput,
|
|
593
616
|
triggerKey: () => triggerKey,
|
|
617
|
+
trustedAppMayCall: () => trustedAppMayCall,
|
|
594
618
|
unknownRefusedInsertions: () => unknownRefusedInsertions,
|
|
595
619
|
unplacedInsertions: () => unplacedInsertions,
|
|
596
620
|
validateAutomation: () => validateAutomation,
|
|
621
|
+
valueNames: () => valueNames,
|
|
622
|
+
valuesRead: () => valuesRead,
|
|
597
623
|
verifyWebhook: () => verifyWebhook
|
|
598
624
|
});
|
|
599
625
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -677,6 +703,12 @@ var ERROR_STATUS = {
|
|
|
677
703
|
invalid_mjml: 422,
|
|
678
704
|
missing_unsubscribe_url: 422,
|
|
679
705
|
mailing_not_ready: 422,
|
|
706
|
+
/**
|
|
707
|
+
* A value placed inside a link's address comes out empty for at least one
|
|
708
|
+
* recipient, so the mailing does not start; `details.values` lists each such
|
|
709
|
+
* value with how many recipients it is empty for.
|
|
710
|
+
*/
|
|
711
|
+
unfilled_link: 422,
|
|
680
712
|
unknown_topic: 422,
|
|
681
713
|
unknown_provider: 422,
|
|
682
714
|
/**
|
|
@@ -745,10 +777,10 @@ var API_VERSION_PREFIX = "/v1";
|
|
|
745
777
|
var HEALTH_PATH = "/healthz";
|
|
746
778
|
|
|
747
779
|
// src/workspace.ts
|
|
748
|
-
var
|
|
780
|
+
var import_zod11 = require("zod");
|
|
749
781
|
|
|
750
782
|
// src/automations.ts
|
|
751
|
-
var
|
|
783
|
+
var import_zod10 = require("zod");
|
|
752
784
|
|
|
753
785
|
// src/templates.ts
|
|
754
786
|
var import_zod5 = require("zod");
|
|
@@ -769,11 +801,11 @@ var RESERVED_MERGE_FIELDS = {
|
|
|
769
801
|
};
|
|
770
802
|
var MERGE_FIELD_PATTERN = /\{\{\s*([a-z][a-z0-9_]*)\s*(?:\|([^}]*))?\}\}/g;
|
|
771
803
|
function findMergeFields(html) {
|
|
772
|
-
const
|
|
804
|
+
const uses2 = [];
|
|
773
805
|
for (const match of html.matchAll(MERGE_FIELD_PATTERN)) {
|
|
774
|
-
|
|
806
|
+
uses2.push({ name: match[1], fallback: match[2] === void 0 ? null : match[2].trim() });
|
|
775
807
|
}
|
|
776
|
-
return
|
|
808
|
+
return uses2;
|
|
777
809
|
}
|
|
778
810
|
function missingRequiredMergeFields(html) {
|
|
779
811
|
const used = new Set(findMergeFields(html).map((u) => u.name));
|
|
@@ -1456,10 +1488,10 @@ function exportFilename(name, format) {
|
|
|
1456
1488
|
}
|
|
1457
1489
|
|
|
1458
1490
|
// src/platform.ts
|
|
1459
|
-
var
|
|
1491
|
+
var import_zod9 = require("zod");
|
|
1460
1492
|
|
|
1461
1493
|
// src/mailings.ts
|
|
1462
|
-
var
|
|
1494
|
+
var import_zod8 = require("zod");
|
|
1463
1495
|
|
|
1464
1496
|
// src/ab-test.ts
|
|
1465
1497
|
var import_zod6 = require("zod");
|
|
@@ -1510,6 +1542,167 @@ function testGroupSize(total, fraction, variants) {
|
|
|
1510
1542
|
return Math.min(total, Math.max(variants, Math.ceil(total * fraction)));
|
|
1511
1543
|
}
|
|
1512
1544
|
|
|
1545
|
+
// src/values.ts
|
|
1546
|
+
var import_zod7 = require("zod");
|
|
1547
|
+
var MAX_MERGE_DEFAULTS = 50;
|
|
1548
|
+
var MAX_MERGE_DEFAULT_LENGTH = 2e3;
|
|
1549
|
+
var MergeFieldName = import_zod7.z.string().regex(/^[a-z][a-z0-9_]*$/, "a merge-field name: lowercase letters, digits and underscores, starting with a letter").max(64);
|
|
1550
|
+
var MergeDefaultValue = import_zod7.z.union([import_zod7.z.string().max(MAX_MERGE_DEFAULT_LENGTH), import_zod7.z.number().finite(), import_zod7.z.boolean()]);
|
|
1551
|
+
var MailingMerge = import_zod7.z.record(MergeFieldName, MergeDefaultValue).refine((m) => Object.keys(m).length <= MAX_MERGE_DEFAULTS, `at most ${MAX_MERGE_DEFAULTS} values on a mailing`).refine((m) => !Object.keys(m).some((k) => SERVICE_FILLED_MERGE_FIELDS.includes(k)), {
|
|
1552
|
+
message: `the service fills ${SERVICE_FILLED_MERGE_FIELDS.join(" and ")}; a mailing cannot set them`
|
|
1553
|
+
});
|
|
1554
|
+
var LETTER_ONLY_MERGE_FIELDS = ["first_name", "last_name"];
|
|
1555
|
+
var NAME_ON_BROADCAST_REFUSAL = "name_on_broadcast";
|
|
1556
|
+
function letterOnlyValues(merge) {
|
|
1557
|
+
return LETTER_ONLY_MERGE_FIELDS.filter((name) => ownEntry(merge, name) !== void 0);
|
|
1558
|
+
}
|
|
1559
|
+
var VALUE_LAYERS = ["recipient", "mailing", "contact", "workspace", "fallback", "empty"];
|
|
1560
|
+
var ValueLayer = import_zod7.z.enum(VALUE_LAYERS);
|
|
1561
|
+
var ResolvedValue = import_zod7.z.object({ text: import_zod7.z.string(), layer: ValueLayer });
|
|
1562
|
+
var MessageValues = import_zod7.z.record(ResolvedValue);
|
|
1563
|
+
function scalarText(value) {
|
|
1564
|
+
if (typeof value === "string") return value;
|
|
1565
|
+
if (typeof value === "number" && Number.isFinite(value)) return String(value);
|
|
1566
|
+
if (typeof value === "boolean") return String(value);
|
|
1567
|
+
return null;
|
|
1568
|
+
}
|
|
1569
|
+
function isNameField(name) {
|
|
1570
|
+
return name === "first_name" || name === "last_name";
|
|
1571
|
+
}
|
|
1572
|
+
function rawMergeValue(name, sources) {
|
|
1573
|
+
const own = ownEntry(sources.recipient, name);
|
|
1574
|
+
if (scalarText(own) !== null) return { value: own, layer: "recipient" };
|
|
1575
|
+
const held = ownEntry(sources.mailing, name);
|
|
1576
|
+
if (scalarText(held) !== null) return { value: held, layer: "mailing" };
|
|
1577
|
+
if (isNameField(name)) {
|
|
1578
|
+
const stored = sources.contact?.[name];
|
|
1579
|
+
return typeof stored === "string" ? { value: stored, layer: "contact" } : null;
|
|
1580
|
+
}
|
|
1581
|
+
const property = ownEntry(sources.contact?.properties, name);
|
|
1582
|
+
if (scalarText(property) !== null) return { value: property, layer: "contact" };
|
|
1583
|
+
const byDefault = ownEntry(sources.workspace, name);
|
|
1584
|
+
return scalarText(byDefault) !== null ? { value: byDefault, layer: "workspace" } : null;
|
|
1585
|
+
}
|
|
1586
|
+
function resolveValue(name, fallback, sources) {
|
|
1587
|
+
const found = rawMergeValue(name, sources);
|
|
1588
|
+
const text = found === null ? null : scalarText(found.value);
|
|
1589
|
+
if (found !== null && text !== null && text.trim() !== "") return { text, layer: found.layer };
|
|
1590
|
+
const instead = fallback?.trim() ?? "";
|
|
1591
|
+
return instead === "" ? { text: "", layer: "empty" } : { text: instead, layer: "fallback" };
|
|
1592
|
+
}
|
|
1593
|
+
function pattern2() {
|
|
1594
|
+
return new RegExp(MERGE_FIELD_PATTERN.source, "g");
|
|
1595
|
+
}
|
|
1596
|
+
function isServiceFilled(name) {
|
|
1597
|
+
return SERVICE_FILLED_MERGE_FIELDS.includes(name);
|
|
1598
|
+
}
|
|
1599
|
+
function uses(text) {
|
|
1600
|
+
return [...text.matchAll(pattern2())].map((m) => ({ name: m[1], fallback: m[2] === void 0 ? null : m[2].trim() }));
|
|
1601
|
+
}
|
|
1602
|
+
function valueNames(texts, insertions) {
|
|
1603
|
+
const names = [];
|
|
1604
|
+
const add = (name) => {
|
|
1605
|
+
if (!isServiceFilled(name) && !names.includes(name)) names.push(name);
|
|
1606
|
+
};
|
|
1607
|
+
for (const text of texts) {
|
|
1608
|
+
for (const use of uses(text ?? "")) {
|
|
1609
|
+
const def = ownEntry(insertions, use.name);
|
|
1610
|
+
if (!def) {
|
|
1611
|
+
add(use.name);
|
|
1612
|
+
continue;
|
|
1613
|
+
}
|
|
1614
|
+
add(def.by);
|
|
1615
|
+
for (const inner of [...Object.values(def.choices), def.filled ?? "", def.otherwise]) for (const u of uses(inner)) add(u.name);
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
return names;
|
|
1619
|
+
}
|
|
1620
|
+
function printedFields(texts, insertions, chosen2) {
|
|
1621
|
+
const out = [];
|
|
1622
|
+
const add = (use) => {
|
|
1623
|
+
if (isServiceFilled(use.name)) return;
|
|
1624
|
+
if (!out.some((o) => o.name === use.name && o.fallback === use.fallback)) out.push(use);
|
|
1625
|
+
};
|
|
1626
|
+
for (const text of texts) {
|
|
1627
|
+
for (const use of uses(text ?? "")) {
|
|
1628
|
+
if (!ownEntry(insertions, use.name)) add(use);
|
|
1629
|
+
else for (const inner of uses(ownEntry(chosen2, use.name)?.text ?? "")) add(inner);
|
|
1630
|
+
}
|
|
1631
|
+
}
|
|
1632
|
+
return out;
|
|
1633
|
+
}
|
|
1634
|
+
function valuesRead(texts, insertions, chosen2, resolve) {
|
|
1635
|
+
const out = {};
|
|
1636
|
+
const read = (use) => {
|
|
1637
|
+
if (isServiceFilled(use.name)) return;
|
|
1638
|
+
const value = resolve(use.name, use.fallback);
|
|
1639
|
+
const seen = ownEntry(out, use.name);
|
|
1640
|
+
if (seen === void 0 || value.layer === "empty" && seen.layer !== "empty") out[use.name] = value;
|
|
1641
|
+
};
|
|
1642
|
+
for (const text of texts) {
|
|
1643
|
+
for (const use of uses(text ?? "")) {
|
|
1644
|
+
const def = ownEntry(insertions, use.name);
|
|
1645
|
+
if (!def) {
|
|
1646
|
+
read(use);
|
|
1647
|
+
continue;
|
|
1648
|
+
}
|
|
1649
|
+
read({ name: def.by, fallback: null });
|
|
1650
|
+
for (const inner of uses(ownEntry(chosen2, use.name)?.text ?? "")) read(inner);
|
|
1651
|
+
}
|
|
1652
|
+
}
|
|
1653
|
+
return out;
|
|
1654
|
+
}
|
|
1655
|
+
var HREF = /\bhref\s*=\s*(?:"([^"]*)"|'([^']*)')/gi;
|
|
1656
|
+
function linkTokens(html) {
|
|
1657
|
+
const out = [];
|
|
1658
|
+
for (const match of html.matchAll(HREF)) {
|
|
1659
|
+
for (const use of uses(match[1] ?? match[2] ?? "")) {
|
|
1660
|
+
if (isServiceFilled(use.name)) continue;
|
|
1661
|
+
if (!out.some((o) => o.name === use.name && o.fallback === use.fallback)) out.push(use);
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1664
|
+
return out;
|
|
1665
|
+
}
|
|
1666
|
+
function emptyLinkValues(tokens, p) {
|
|
1667
|
+
const empty = [];
|
|
1668
|
+
for (const token of tokens) {
|
|
1669
|
+
const ins = ownEntry(p.insertions, token.name);
|
|
1670
|
+
const text = ins ? ins.text.replace(pattern2(), (_m, name, fallback) => p.value(name, fallback)) : p.value(token.name, token.fallback ?? void 0);
|
|
1671
|
+
if (text.trim() === "" && !empty.includes(token.name)) empty.push(token.name);
|
|
1672
|
+
}
|
|
1673
|
+
return empty;
|
|
1674
|
+
}
|
|
1675
|
+
var UnfilledLink = import_zod7.z.object({
|
|
1676
|
+
/** The value, or the insertion, that comes out empty. */
|
|
1677
|
+
value: import_zod7.z.string(),
|
|
1678
|
+
/** How many recipients it is empty for. */
|
|
1679
|
+
recipients: import_zod7.z.number().int().min(1)
|
|
1680
|
+
});
|
|
1681
|
+
var RESOLVE_PROBLEMS = ["unfilled_link", "empty_value", "insertion_miss"];
|
|
1682
|
+
var ResolveProblem = import_zod7.z.object({
|
|
1683
|
+
kind: import_zod7.z.enum(RESOLVE_PROBLEMS),
|
|
1684
|
+
severity: import_zod7.z.enum(["blocking", "note"]),
|
|
1685
|
+
value: import_zod7.z.string(),
|
|
1686
|
+
message: import_zod7.z.string()
|
|
1687
|
+
});
|
|
1688
|
+
var ResolvedRecipient = import_zod7.z.object({
|
|
1689
|
+
/** The recipient's index in the request; null for the reader with nothing of their own. */
|
|
1690
|
+
index: import_zod7.z.number().int().min(0).nullable(),
|
|
1691
|
+
/** The address the message would go to; null for the reader with nothing of their own. */
|
|
1692
|
+
email: Email.nullable(),
|
|
1693
|
+
/** The contact found for the recipient; null when the address has none yet (a send creates it, empty). */
|
|
1694
|
+
contact_id: Id.nullable(),
|
|
1695
|
+
/** The language version this recipient would get. */
|
|
1696
|
+
locale: LocaleTag,
|
|
1697
|
+
/** The subject line as they would read it. */
|
|
1698
|
+
subject: import_zod7.z.string(),
|
|
1699
|
+
values: MessageValues,
|
|
1700
|
+
/** The choice each insertion would make; null when the content has none. */
|
|
1701
|
+
insertions: InsertionChoices.nullable(),
|
|
1702
|
+
problems: import_zod7.z.array(ResolveProblem)
|
|
1703
|
+
});
|
|
1704
|
+
var RESOLVE_REJECTIONS = ["unknown_contact", "duplicate_in_batch"];
|
|
1705
|
+
|
|
1513
1706
|
// src/mailings.ts
|
|
1514
1707
|
var MAILING_STATUSES = [
|
|
1515
1708
|
"draft",
|
|
@@ -1520,9 +1713,9 @@ var MAILING_STATUSES = [
|
|
|
1520
1713
|
"partially_failed",
|
|
1521
1714
|
"cancelled"
|
|
1522
1715
|
];
|
|
1523
|
-
var MailingStatus =
|
|
1716
|
+
var MailingStatus = import_zod8.z.enum(MAILING_STATUSES);
|
|
1524
1717
|
var MAILING_ACTIONS = ["send", "schedule", "unschedule", "pause", "resume", "cancel", "retry-failed"];
|
|
1525
|
-
var MailingAction =
|
|
1718
|
+
var MailingAction = import_zod8.z.enum(MAILING_ACTIONS);
|
|
1526
1719
|
var MAILING_TRANSITIONS = {
|
|
1527
1720
|
draft: ["send", "schedule", "cancel"],
|
|
1528
1721
|
scheduled: ["send", "schedule", "unschedule", "cancel"],
|
|
@@ -1537,23 +1730,23 @@ function canTransition(status, action) {
|
|
|
1537
1730
|
}
|
|
1538
1731
|
var EDITABLE_MAILING_STATUSES = ["draft", "scheduled"];
|
|
1539
1732
|
var TERMINAL_MAILING_STATUSES = ["sent", "cancelled"];
|
|
1540
|
-
var MailingMetadata =
|
|
1541
|
-
var MailingCounts =
|
|
1542
|
-
total:
|
|
1543
|
-
queued:
|
|
1544
|
-
sending:
|
|
1545
|
-
sent:
|
|
1546
|
-
failed:
|
|
1547
|
-
skipped:
|
|
1733
|
+
var MailingMetadata = import_zod8.z.record(import_zod8.z.string().max(500)).refine((v) => Object.keys(v).length <= 20, "at most 20 keys").refine((v) => Object.keys(v).every((k) => k.length >= 1 && k.length <= 64), "keys are 1 to 64 characters");
|
|
1734
|
+
var MailingCounts = import_zod8.z.object({
|
|
1735
|
+
total: import_zod8.z.number().int().min(0),
|
|
1736
|
+
queued: import_zod8.z.number().int().min(0),
|
|
1737
|
+
sending: import_zod8.z.number().int().min(0),
|
|
1738
|
+
sent: import_zod8.z.number().int().min(0),
|
|
1739
|
+
failed: import_zod8.z.number().int().min(0),
|
|
1740
|
+
skipped: import_zod8.z.number().int().min(0)
|
|
1548
1741
|
});
|
|
1549
1742
|
var MAILING_KINDS = ["broadcast", "automation", "notification"];
|
|
1550
|
-
var MailingKind =
|
|
1551
|
-
var Mailing =
|
|
1743
|
+
var MailingKind = import_zod8.z.enum(MAILING_KINDS);
|
|
1744
|
+
var Mailing = import_zod8.z.object({
|
|
1552
1745
|
id: Id,
|
|
1553
1746
|
kind: MailingKind,
|
|
1554
|
-
name:
|
|
1555
|
-
subject:
|
|
1556
|
-
preheader:
|
|
1747
|
+
name: import_zod8.z.string().max(200).nullable(),
|
|
1748
|
+
subject: import_zod8.z.string().min(1).max(998),
|
|
1749
|
+
preheader: import_zod8.z.string().max(500).nullable(),
|
|
1557
1750
|
/**
|
|
1558
1751
|
* The template the document was taken from, if any. The snapshot is what is
|
|
1559
1752
|
* sent in the main language; the template's other language versions are
|
|
@@ -1595,6 +1788,12 @@ var Mailing = import_zod7.z.object({
|
|
|
1595
1788
|
status: MailingStatus,
|
|
1596
1789
|
counts: MailingCounts,
|
|
1597
1790
|
metadata: MailingMetadata,
|
|
1791
|
+
/**
|
|
1792
|
+
* The values held on this mailing (see `MailingMerge`): the same for
|
|
1793
|
+
* everyone who gets it, above the contact's stored name and properties and
|
|
1794
|
+
* the workspace's defaults, below the recipient's own. Empty by default.
|
|
1795
|
+
*/
|
|
1796
|
+
merge: MailingMerge.default({}),
|
|
1598
1797
|
scheduled_at: Timestamp.nullable(),
|
|
1599
1798
|
/** The A/B test on subject or content (S4), null when there is none. */
|
|
1600
1799
|
ab_test: AbTestState.nullable(),
|
|
@@ -1606,15 +1805,15 @@ var Mailing = import_zod7.z.object({
|
|
|
1606
1805
|
* recipients refused as dead addresses in one run (see the provider's
|
|
1607
1806
|
* `rejections.anomaly`). Resuming clears it and starts a new run.
|
|
1608
1807
|
*/
|
|
1609
|
-
pause_reason:
|
|
1808
|
+
pause_reason: import_zod8.z.string().nullable().default(null),
|
|
1610
1809
|
created_at: Timestamp,
|
|
1611
1810
|
updated_at: Timestamp
|
|
1612
1811
|
});
|
|
1613
1812
|
var MailingSummary = Mailing.omit({ document: true });
|
|
1614
1813
|
var MailingContent = {
|
|
1615
|
-
name:
|
|
1616
|
-
subject:
|
|
1617
|
-
preheader:
|
|
1814
|
+
name: import_zod8.z.string().max(200).optional(),
|
|
1815
|
+
subject: import_zod8.z.string().min(1).max(998),
|
|
1816
|
+
preheader: import_zod8.z.string().max(500).optional(),
|
|
1618
1817
|
/** See `Mailing.send_locale`. */
|
|
1619
1818
|
send_locale: LocaleTag.nullable().optional(),
|
|
1620
1819
|
/**
|
|
@@ -1625,9 +1824,11 @@ var MailingContent = {
|
|
|
1625
1824
|
*/
|
|
1626
1825
|
topic: Slug.nullable().optional(),
|
|
1627
1826
|
provider_id: Id,
|
|
1628
|
-
metadata: MailingMetadata.optional()
|
|
1827
|
+
metadata: MailingMetadata.optional(),
|
|
1828
|
+
/** See `Mailing.merge`. `first_name` and `last_name` only on a letter (no topic). */
|
|
1829
|
+
merge: MailingMerge.optional()
|
|
1629
1830
|
};
|
|
1630
|
-
var MailingCreate =
|
|
1831
|
+
var MailingCreate = import_zod8.z.object({
|
|
1631
1832
|
...MailingContent,
|
|
1632
1833
|
subject: MailingContent.subject.optional(),
|
|
1633
1834
|
document: TemplateDocument.optional(),
|
|
@@ -1643,15 +1844,22 @@ var MailingCreate = import_zod7.z.object({
|
|
|
1643
1844
|
message: "a mailing made from a document needs a subject",
|
|
1644
1845
|
path: ["subject"]
|
|
1645
1846
|
});
|
|
1646
|
-
var MailingUpdate =
|
|
1647
|
-
name:
|
|
1847
|
+
var MailingUpdate = import_zod8.z.object({
|
|
1848
|
+
name: import_zod8.z.string().max(200).nullable().optional(),
|
|
1648
1849
|
subject: MailingContent.subject.optional(),
|
|
1649
|
-
preheader:
|
|
1850
|
+
preheader: import_zod8.z.string().max(500).nullable().optional(),
|
|
1650
1851
|
/** Null turns a draft into a letter, which it can only be with at most one recipient. */
|
|
1651
1852
|
topic: Slug.nullable().optional(),
|
|
1652
1853
|
send_locale: LocaleTag.nullable().optional(),
|
|
1653
1854
|
provider_id: Id.optional(),
|
|
1654
1855
|
metadata: MailingMetadata.optional(),
|
|
1856
|
+
/**
|
|
1857
|
+
* Replaces the mailing's values whole (see `Mailing.merge`). Giving a
|
|
1858
|
+
* mailing that holds `first_name` or `last_name` a topic is refused
|
|
1859
|
+
* (`name_on_broadcast`) unless the same call replaces its values without
|
|
1860
|
+
* them.
|
|
1861
|
+
*/
|
|
1862
|
+
merge: MailingMerge.optional(),
|
|
1655
1863
|
document: TemplateDocument.optional()
|
|
1656
1864
|
}).refine((v) => Object.keys(v).length > 0, "at least one field");
|
|
1657
1865
|
var MailingListQuery = PageQuery.extend({
|
|
@@ -1660,30 +1868,30 @@ var MailingListQuery = PageQuery.extend({
|
|
|
1660
1868
|
kind: MailingKind.optional(),
|
|
1661
1869
|
automation_id: Id.optional()
|
|
1662
1870
|
});
|
|
1663
|
-
var MailingSendRequest =
|
|
1664
|
-
var MailingRetryFailedRequest =
|
|
1871
|
+
var MailingSendRequest = import_zod8.z.object({}).strict();
|
|
1872
|
+
var MailingRetryFailedRequest = import_zod8.z.object({
|
|
1665
1873
|
/**
|
|
1666
1874
|
* Also requeue recipients whose outcome is unknown after a crash. They may
|
|
1667
1875
|
* already have received the message, so this is a human's decision, never a
|
|
1668
1876
|
* default.
|
|
1669
1877
|
*/
|
|
1670
|
-
include_outcome_unknown:
|
|
1878
|
+
include_outcome_unknown: import_zod8.z.boolean().optional()
|
|
1671
1879
|
}).strict();
|
|
1672
|
-
var MailingActionRequest =
|
|
1673
|
-
var MailingTestRequest =
|
|
1880
|
+
var MailingActionRequest = import_zod8.z.object({}).strict();
|
|
1881
|
+
var MailingTestRequest = import_zod8.z.object({
|
|
1674
1882
|
to: Email,
|
|
1675
1883
|
merge: Properties.optional(),
|
|
1676
1884
|
locale: LocaleTag.optional()
|
|
1677
1885
|
});
|
|
1678
|
-
var MailingTestResult =
|
|
1886
|
+
var MailingTestResult = import_zod8.z.object({
|
|
1679
1887
|
message_id: Id,
|
|
1680
|
-
provider_message_id:
|
|
1888
|
+
provider_message_id: import_zod8.z.string().nullable()
|
|
1681
1889
|
});
|
|
1682
1890
|
var RECIPIENT_STATUSES = ["queued", "sending", "sent", "failed", "skipped"];
|
|
1683
|
-
var RecipientStatus =
|
|
1891
|
+
var RecipientStatus = import_zod8.z.enum(RECIPIENT_STATUSES);
|
|
1684
1892
|
var SKIP_REASONS = ["suppressed", "not_subscribed", "contact_erased", "cancelled", "outcome_unknown"];
|
|
1685
|
-
var SkipReason =
|
|
1686
|
-
var Recipient =
|
|
1893
|
+
var SkipReason = import_zod8.z.enum(SKIP_REASONS);
|
|
1894
|
+
var Recipient = import_zod8.z.object({
|
|
1687
1895
|
id: Id,
|
|
1688
1896
|
mailing_id: Id,
|
|
1689
1897
|
contact_id: Id.nullable(),
|
|
@@ -1691,55 +1899,55 @@ var Recipient = import_zod7.z.object({
|
|
|
1691
1899
|
merge: Properties,
|
|
1692
1900
|
status: RecipientStatus,
|
|
1693
1901
|
skip_reason: SkipReason.nullable(),
|
|
1694
|
-
attempts:
|
|
1902
|
+
attempts: import_zod8.z.number().int().min(0),
|
|
1695
1903
|
message_id: Id.nullable(),
|
|
1696
|
-
last_error:
|
|
1904
|
+
last_error: import_zod8.z.string().nullable(),
|
|
1697
1905
|
created_at: Timestamp,
|
|
1698
1906
|
updated_at: Timestamp
|
|
1699
1907
|
});
|
|
1700
1908
|
var MAX_RECIPIENTS_PER_BATCH = 1e3;
|
|
1701
1909
|
var MAX_LETTER_RECIPIENTS = 1;
|
|
1702
1910
|
var LETTER_RECIPIENT_REFUSAL = "letter_has_one_recipient";
|
|
1703
|
-
var RecipientInput =
|
|
1911
|
+
var RecipientInput = import_zod8.z.object({
|
|
1704
1912
|
contact_id: Id.optional(),
|
|
1705
|
-
external_id:
|
|
1913
|
+
external_id: import_zod8.z.string().min(1).max(255).optional(),
|
|
1706
1914
|
email: Email.optional(),
|
|
1707
1915
|
merge: Properties.optional()
|
|
1708
1916
|
}).refine((v) => v.contact_id !== void 0 || v.external_id !== void 0 || v.email !== void 0, {
|
|
1709
1917
|
message: "contact_id, external_id or email is required",
|
|
1710
1918
|
path: ["email"]
|
|
1711
1919
|
});
|
|
1712
|
-
var RecipientBatch =
|
|
1713
|
-
recipients:
|
|
1920
|
+
var RecipientBatch = import_zod8.z.object({
|
|
1921
|
+
recipients: import_zod8.z.array(RecipientInput).min(1).max(MAX_RECIPIENTS_PER_BATCH)
|
|
1714
1922
|
});
|
|
1715
1923
|
var RECIPIENT_REJECTIONS = ["unknown_contact", "duplicate_in_batch"];
|
|
1716
|
-
var RecipientBatchResult =
|
|
1924
|
+
var RecipientBatchResult = import_zod8.z.object({
|
|
1717
1925
|
/** Newly queued. */
|
|
1718
|
-
added:
|
|
1926
|
+
added: import_zod8.z.number().int().min(0),
|
|
1719
1927
|
/** Already on the mailing from an earlier batch: left unchanged. */
|
|
1720
|
-
already_present:
|
|
1928
|
+
already_present: import_zod8.z.number().int().min(0),
|
|
1721
1929
|
/** Items not added, by their index in the request. */
|
|
1722
|
-
rejected:
|
|
1930
|
+
rejected: import_zod8.z.array(import_zod8.z.object({ index: import_zod8.z.number().int().min(0), reason: import_zod8.z.enum(RECIPIENT_REJECTIONS) }))
|
|
1723
1931
|
});
|
|
1724
1932
|
var RecipientListQuery = PageQuery.extend({
|
|
1725
1933
|
status: RecipientStatus.optional(),
|
|
1726
1934
|
skip_reason: SkipReason.optional()
|
|
1727
1935
|
});
|
|
1728
1936
|
var MESSAGE_OUTCOMES = ["sent", "failed"];
|
|
1729
|
-
var MessageOutcome =
|
|
1730
|
-
var MessageSummary =
|
|
1937
|
+
var MessageOutcome = import_zod8.z.enum(MESSAGE_OUTCOMES);
|
|
1938
|
+
var MessageSummary = import_zod8.z.object({
|
|
1731
1939
|
id: Id,
|
|
1732
1940
|
mailing_id: Id.nullable(),
|
|
1733
1941
|
recipient_id: Id.nullable(),
|
|
1734
1942
|
contact_id: Id.nullable(),
|
|
1735
1943
|
to: Email,
|
|
1736
|
-
subject:
|
|
1944
|
+
subject: import_zod8.z.string(),
|
|
1737
1945
|
provider_id: Id,
|
|
1738
|
-
provider_message_id:
|
|
1946
|
+
provider_message_id: import_zod8.z.string().nullable(),
|
|
1739
1947
|
outcome: MessageOutcome,
|
|
1740
|
-
error:
|
|
1741
|
-
is_test:
|
|
1742
|
-
recipient_count:
|
|
1948
|
+
error: import_zod8.z.string().nullable(),
|
|
1949
|
+
is_test: import_zod8.z.boolean(),
|
|
1950
|
+
recipient_count: import_zod8.z.number().int().min(1),
|
|
1743
1951
|
/** The language version the message was sent in; null for messages archived before languages existed. */
|
|
1744
1952
|
locale: LocaleTag.nullable(),
|
|
1745
1953
|
/**
|
|
@@ -1749,24 +1957,32 @@ var MessageSummary = import_zod7.z.object({
|
|
|
1749
1957
|
* "otherwise" text. Null when the message had no insertions.
|
|
1750
1958
|
*/
|
|
1751
1959
|
insertions: InsertionChoices.nullable(),
|
|
1960
|
+
/**
|
|
1961
|
+
* The values the message was written with, by name: the text each one
|
|
1962
|
+
* printed and the layer it came from (see `MessageValues`), recorded when it
|
|
1963
|
+
* was sent, so a later change to a default never rewrites what a reader got.
|
|
1964
|
+
* Null for a message archived before values were recorded, and for a signup
|
|
1965
|
+
* form's confirmation, which belongs to no mailing.
|
|
1966
|
+
*/
|
|
1967
|
+
values: MessageValues.nullable().default(null),
|
|
1752
1968
|
created_at: Timestamp
|
|
1753
1969
|
});
|
|
1754
|
-
var Message = MessageSummary.extend({ html:
|
|
1755
|
-
var MailingLanguageStatus =
|
|
1756
|
-
var MailingLanguage =
|
|
1970
|
+
var Message = MessageSummary.extend({ html: import_zod8.z.string() });
|
|
1971
|
+
var MailingLanguageStatus = import_zod8.z.enum(["main", "ready", "draft", "not_a_workspace_language"]);
|
|
1972
|
+
var MailingLanguage = import_zod8.z.object({
|
|
1757
1973
|
locale: LocaleTag,
|
|
1758
1974
|
status: MailingLanguageStatus,
|
|
1759
1975
|
/** Queued recipients who will get this version. */
|
|
1760
|
-
planned:
|
|
1976
|
+
planned: import_zod8.z.number().int().min(0),
|
|
1761
1977
|
/** Messages already sent in this language (tests excluded). */
|
|
1762
|
-
sent:
|
|
1978
|
+
sent: import_zod8.z.number().int().min(0)
|
|
1763
1979
|
});
|
|
1764
|
-
var MailingLanguageReport =
|
|
1980
|
+
var MailingLanguageReport = import_zod8.z.object({
|
|
1765
1981
|
main_locale: LocaleTag,
|
|
1766
1982
|
send_locale: LocaleTag.nullable(),
|
|
1767
|
-
languages:
|
|
1768
|
-
fallback:
|
|
1769
|
-
no_language:
|
|
1983
|
+
languages: import_zod8.z.array(MailingLanguage),
|
|
1984
|
+
fallback: import_zod8.z.array(import_zod8.z.object({ wanted: import_zod8.z.string(), planned: import_zod8.z.number().int().min(1) })),
|
|
1985
|
+
no_language: import_zod8.z.number().int().min(0),
|
|
1770
1986
|
/**
|
|
1771
1987
|
* Values that no choice of an insertion takes, so the "otherwise" text goes
|
|
1772
1988
|
* out (docs/plans/2026-09-25-translated-insertions.md, decision 3): per
|
|
@@ -1775,41 +1991,56 @@ var MailingLanguageReport = import_zod7.z.object({
|
|
|
1775
1991
|
* template's keys never produces one; a non-empty list means the client and
|
|
1776
1992
|
* the template have drifted apart.
|
|
1777
1993
|
*/
|
|
1778
|
-
insertion_misses:
|
|
1779
|
-
|
|
1780
|
-
insertion:
|
|
1781
|
-
value:
|
|
1782
|
-
planned:
|
|
1783
|
-
sent:
|
|
1994
|
+
insertion_misses: import_zod8.z.array(
|
|
1995
|
+
import_zod8.z.object({
|
|
1996
|
+
insertion: import_zod8.z.string(),
|
|
1997
|
+
value: import_zod8.z.string(),
|
|
1998
|
+
planned: import_zod8.z.number().int().min(0),
|
|
1999
|
+
sent: import_zod8.z.number().int().min(0)
|
|
1784
2000
|
})
|
|
1785
2001
|
)
|
|
1786
2002
|
});
|
|
2003
|
+
var MailingResolveRequest = import_zod8.z.object({
|
|
2004
|
+
recipients: import_zod8.z.array(RecipientInput).max(MAX_RECIPIENTS_PER_BATCH).optional()
|
|
2005
|
+
});
|
|
2006
|
+
var MailingResolveResult = import_zod8.z.object({
|
|
2007
|
+
/** Every value the mailing's content can read, in order of first appearance, without `email` and `unsubscribe_url`. */
|
|
2008
|
+
names: import_zod8.z.array(import_zod8.z.string()),
|
|
2009
|
+
/** The values and insertions placed inside a link's address: one of them empty for anybody refuses the send. */
|
|
2010
|
+
link_values: import_zod8.z.array(import_zod8.z.string()),
|
|
2011
|
+
/** One entry per resolved recipient, in the request's order; a single entry with `index: null` when none were given. */
|
|
2012
|
+
recipients: import_zod8.z.array(ResolvedRecipient),
|
|
2013
|
+
/** Items not resolved, by their index in the request, for the reasons `mailings.addRecipients` rejects one. */
|
|
2014
|
+
rejected: import_zod8.z.array(import_zod8.z.object({ index: import_zod8.z.number().int().min(0), reason: import_zod8.z.enum(RESOLVE_REJECTIONS) })),
|
|
2015
|
+
/** What would refuse `mailings.send` for these recipients, as its `unfilled_link` refusal lists it; empty means none. */
|
|
2016
|
+
blocking: import_zod8.z.array(UnfilledLink)
|
|
2017
|
+
});
|
|
1787
2018
|
var MessageListQuery = PageQuery.extend({
|
|
1788
2019
|
mailing_id: Id.optional(),
|
|
1789
2020
|
outcome: MessageOutcome.optional()
|
|
1790
2021
|
});
|
|
1791
2022
|
|
|
1792
2023
|
// src/platform.ts
|
|
1793
|
-
var Tag =
|
|
2024
|
+
var Tag = import_zod9.z.object({
|
|
1794
2025
|
id: Id,
|
|
1795
2026
|
slug: Slug,
|
|
1796
|
-
name:
|
|
1797
|
-
contact_count:
|
|
2027
|
+
name: import_zod9.z.string().min(1).max(120),
|
|
2028
|
+
contact_count: import_zod9.z.number().int().min(0),
|
|
1798
2029
|
created_at: Timestamp
|
|
1799
2030
|
});
|
|
1800
|
-
var TagCreate =
|
|
1801
|
-
var TagAssignment =
|
|
1802
|
-
contact_ids:
|
|
2031
|
+
var TagCreate = import_zod9.z.object({ slug: Slug, name: import_zod9.z.string().min(1).max(120) });
|
|
2032
|
+
var TagAssignment = import_zod9.z.object({
|
|
2033
|
+
contact_ids: import_zod9.z.array(Id).min(1).max(1e3)
|
|
1803
2034
|
});
|
|
1804
2035
|
var CONTACT_PROPERTY_TYPES = ["string", "number", "boolean", "date"];
|
|
1805
|
-
var ContactPropertyType =
|
|
1806
|
-
var ContactPropertyKey =
|
|
1807
|
-
var ContactPropertyDefinition =
|
|
2036
|
+
var ContactPropertyType = import_zod9.z.enum(CONTACT_PROPERTY_TYPES);
|
|
2037
|
+
var ContactPropertyKey = import_zod9.z.string().regex(/^[A-Za-z0-9_.-]{1,64}$/, "letters, digits, dot, underscore and hyphen, 1 to 64");
|
|
2038
|
+
var ContactPropertyDefinition = import_zod9.z.object({
|
|
1808
2039
|
key: ContactPropertyKey,
|
|
1809
|
-
label:
|
|
2040
|
+
label: import_zod9.z.string().min(1).max(120),
|
|
1810
2041
|
type: ContactPropertyType
|
|
1811
2042
|
});
|
|
1812
|
-
var ContactPropertyParams =
|
|
2043
|
+
var ContactPropertyParams = import_zod9.z.object({ key: ContactPropertyKey });
|
|
1813
2044
|
var FILTER_OPERATORS = [
|
|
1814
2045
|
"eq",
|
|
1815
2046
|
"neq",
|
|
@@ -1825,8 +2056,8 @@ var FILTER_OPERATORS = [
|
|
|
1825
2056
|
"in",
|
|
1826
2057
|
"not_in"
|
|
1827
2058
|
];
|
|
1828
|
-
var FilterOperator =
|
|
1829
|
-
var FilterField =
|
|
2059
|
+
var FilterOperator = import_zod9.z.enum(FILTER_OPERATORS);
|
|
2060
|
+
var FilterField = import_zod9.z.string().regex(
|
|
1830
2061
|
/^(email|first_name|last_name|locale|created_at|tag|topic|engagement:(opened|clicked)|property:[A-Za-z0-9_.-]{1,64})$/,
|
|
1831
2062
|
"unknown filter field"
|
|
1832
2063
|
);
|
|
@@ -1842,18 +2073,18 @@ var FILTER_FIELD_OPERATORS = {
|
|
|
1842
2073
|
property: FILTER_OPERATORS
|
|
1843
2074
|
};
|
|
1844
2075
|
var MAX_FILTER_DEPTH = 5;
|
|
1845
|
-
var FilterCondition =
|
|
2076
|
+
var FilterCondition = import_zod9.z.object({ field: FilterField, op: FilterOperator, value: JsonValue.optional() }).strict().refine((c) => (c.op === "exists" || c.op === "not_exists") === (c.value === void 0), {
|
|
1846
2077
|
message: "exists and not_exists take no value; every other operator needs one",
|
|
1847
2078
|
path: ["value"]
|
|
1848
2079
|
}).refine((c) => c.op !== "in" && c.op !== "not_in" || Array.isArray(c.value), {
|
|
1849
2080
|
message: "in and not_in take an array",
|
|
1850
2081
|
path: ["value"]
|
|
1851
2082
|
});
|
|
1852
|
-
var SegmentFilter =
|
|
1853
|
-
() =>
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
2083
|
+
var SegmentFilter = import_zod9.z.lazy(
|
|
2084
|
+
() => import_zod9.z.union([
|
|
2085
|
+
import_zod9.z.object({ and: import_zod9.z.array(SegmentFilter).min(1).max(50) }).strict(),
|
|
2086
|
+
import_zod9.z.object({ or: import_zod9.z.array(SegmentFilter).min(1).max(50) }).strict(),
|
|
2087
|
+
import_zod9.z.object({ not: SegmentFilter }).strict(),
|
|
1857
2088
|
FilterCondition
|
|
1858
2089
|
])
|
|
1859
2090
|
);
|
|
@@ -1941,42 +2172,42 @@ function untypedValueProblem(c, every) {
|
|
|
1941
2172
|
if (orderOp) return every(isFilterNumber, "numbers (define the property to compare dates)");
|
|
1942
2173
|
return every((v) => isScalar(v) || v === null, "strings, numbers, booleans or null");
|
|
1943
2174
|
}
|
|
1944
|
-
var Segment =
|
|
2175
|
+
var Segment = import_zod9.z.object({
|
|
1945
2176
|
id: Id,
|
|
1946
|
-
name:
|
|
2177
|
+
name: import_zod9.z.string().min(1).max(120),
|
|
1947
2178
|
filter: SegmentFilter,
|
|
1948
2179
|
/** Computed on read. */
|
|
1949
|
-
contact_count:
|
|
2180
|
+
contact_count: import_zod9.z.number().int().min(0),
|
|
1950
2181
|
created_at: Timestamp,
|
|
1951
2182
|
updated_at: Timestamp
|
|
1952
2183
|
});
|
|
1953
|
-
var SegmentCreate =
|
|
1954
|
-
var SegmentPreviewRequest =
|
|
1955
|
-
var SegmentPreview =
|
|
1956
|
-
contact_count:
|
|
2184
|
+
var SegmentCreate = import_zod9.z.object({ name: import_zod9.z.string().min(1).max(120), filter: BoundedSegmentFilter });
|
|
2185
|
+
var SegmentPreviewRequest = import_zod9.z.object({ filter: BoundedSegmentFilter });
|
|
2186
|
+
var SegmentPreview = import_zod9.z.object({
|
|
2187
|
+
contact_count: import_zod9.z.number().int().min(0),
|
|
1957
2188
|
/** Up to five matching contacts, for a human to sanity-check the filter. */
|
|
1958
|
-
sample:
|
|
2189
|
+
sample: import_zod9.z.array(import_zod9.z.object({ id: Id, email: Email })).max(5)
|
|
1959
2190
|
});
|
|
1960
|
-
var MailingAudienceFromSegment =
|
|
2191
|
+
var MailingAudienceFromSegment = import_zod9.z.object({ segment_id: Id });
|
|
1961
2192
|
var SIGNUP_FORM_FIELDS = ["first_name", "last_name"];
|
|
1962
2193
|
var HOSTED_PAGE_LOCALES = ["en", "de", "it", "fr", "es"];
|
|
1963
|
-
var SignupFormTranslation =
|
|
1964
|
-
title:
|
|
1965
|
-
consent_text:
|
|
2194
|
+
var SignupFormTranslation = import_zod9.z.object({
|
|
2195
|
+
title: import_zod9.z.string().min(1).max(120),
|
|
2196
|
+
consent_text: import_zod9.z.string().min(1).max(2e3)
|
|
1966
2197
|
});
|
|
1967
|
-
var SignupForm =
|
|
2198
|
+
var SignupForm = import_zod9.z.object({
|
|
1968
2199
|
id: Id,
|
|
1969
|
-
name:
|
|
2200
|
+
name: import_zod9.z.string().min(1).max(120),
|
|
1970
2201
|
/** The heading of the hosted page. */
|
|
1971
|
-
title:
|
|
2202
|
+
title: import_zod9.z.string().min(1).max(120),
|
|
1972
2203
|
/** What the person agrees to, shown above the button and recorded with the confirmation. */
|
|
1973
|
-
consent_text:
|
|
1974
|
-
translations:
|
|
1975
|
-
topics:
|
|
1976
|
-
tags:
|
|
2204
|
+
consent_text: import_zod9.z.string().min(1).max(2e3),
|
|
2205
|
+
translations: import_zod9.z.record(SignupFormTranslation),
|
|
2206
|
+
topics: import_zod9.z.array(Slug).min(1),
|
|
2207
|
+
tags: import_zod9.z.array(Slug),
|
|
1977
2208
|
/** Fields shown besides email. */
|
|
1978
|
-
fields:
|
|
1979
|
-
double_opt_in:
|
|
2209
|
+
fields: import_zod9.z.array(import_zod9.z.enum(SIGNUP_FORM_FIELDS)),
|
|
2210
|
+
double_opt_in: import_zod9.z.literal(true),
|
|
1980
2211
|
/** The provider the confirmation mail is sent through. */
|
|
1981
2212
|
provider_id: Id,
|
|
1982
2213
|
/**
|
|
@@ -1985,11 +2216,11 @@ var SignupForm = import_zod8.z.object({
|
|
|
1985
2216
|
*/
|
|
1986
2217
|
confirmation_template_id: Id.nullable(),
|
|
1987
2218
|
/** Where the person lands after confirming. Null shows the hosted confirmation page. */
|
|
1988
|
-
redirect_url:
|
|
2219
|
+
redirect_url: import_zod9.z.string().url().nullable(),
|
|
1989
2220
|
/** Origins allowed to embed the form and call the submission route from a browser. */
|
|
1990
|
-
allowed_origins:
|
|
2221
|
+
allowed_origins: import_zod9.z.array(import_zod9.z.string().url()).max(20),
|
|
1991
2222
|
/** Bumped on every change; recorded with each confirmation. */
|
|
1992
|
-
version:
|
|
2223
|
+
version: import_zod9.z.number().int().min(1),
|
|
1993
2224
|
created_at: Timestamp,
|
|
1994
2225
|
updated_at: Timestamp
|
|
1995
2226
|
});
|
|
@@ -2004,56 +2235,56 @@ var SignupFormCreate = SignupForm.omit({
|
|
|
2004
2235
|
tags: SignupForm.shape.tags.optional(),
|
|
2005
2236
|
fields: SignupForm.shape.fields.optional(),
|
|
2006
2237
|
confirmation_template_id: Id.nullable().optional(),
|
|
2007
|
-
redirect_url:
|
|
2238
|
+
redirect_url: import_zod9.z.string().url().nullable().optional(),
|
|
2008
2239
|
allowed_origins: SignupForm.shape.allowed_origins.optional()
|
|
2009
2240
|
});
|
|
2010
|
-
var SignupFormEmbed =
|
|
2011
|
-
hosted_url:
|
|
2241
|
+
var SignupFormEmbed = import_zod9.z.object({
|
|
2242
|
+
hosted_url: import_zod9.z.string().url(),
|
|
2012
2243
|
/** A plain HTML form posting to the hosted page; works without JavaScript. */
|
|
2013
|
-
html:
|
|
2244
|
+
html: import_zod9.z.string(),
|
|
2014
2245
|
/** A small optional script that adds the time check and submits in place. */
|
|
2015
|
-
script_url:
|
|
2246
|
+
script_url: import_zod9.z.string().url(),
|
|
2016
2247
|
/** Where a browser fetches a fresh `form_token` from (GET, public, CORS for `allowed_origins`). */
|
|
2017
|
-
token_url:
|
|
2248
|
+
token_url: import_zod9.z.string().url()
|
|
2018
2249
|
});
|
|
2019
|
-
var SignupSubmission =
|
|
2250
|
+
var SignupSubmission = import_zod9.z.object({
|
|
2020
2251
|
email: Email,
|
|
2021
|
-
first_name:
|
|
2022
|
-
last_name:
|
|
2023
|
-
locale:
|
|
2252
|
+
first_name: import_zod9.z.string().max(200).optional(),
|
|
2253
|
+
last_name: import_zod9.z.string().max(200).optional(),
|
|
2254
|
+
locale: import_zod9.z.string().min(2).max(35).optional(),
|
|
2024
2255
|
/** Honeypot: must be empty. */
|
|
2025
|
-
website:
|
|
2256
|
+
website: import_zod9.z.string().max(0).optional(),
|
|
2026
2257
|
/**
|
|
2027
2258
|
* The signed render time from the form's token URL: a submission sooner than a
|
|
2028
2259
|
* human could fill the form, or long after, is refused.
|
|
2029
2260
|
*/
|
|
2030
|
-
form_token:
|
|
2261
|
+
form_token: import_zod9.z.string().min(1).max(512)
|
|
2031
2262
|
});
|
|
2032
2263
|
var IMPORT_STATUSES = ["uploaded", "validating", "validated", "committing", "completed", "failed", "cancelled"];
|
|
2033
|
-
var ImportStatus =
|
|
2264
|
+
var ImportStatus = import_zod9.z.enum(IMPORT_STATUSES);
|
|
2034
2265
|
var IMPORT_TERMINAL_STATUSES = ["completed", "failed", "cancelled"];
|
|
2035
|
-
var ImportColumnMapping =
|
|
2036
|
-
|
|
2266
|
+
var ImportColumnMapping = import_zod9.z.record(
|
|
2267
|
+
import_zod9.z.string().regex(/^(email|external_id|first_name|last_name|locale|property:[A-Za-z0-9_.-]{1,64}|ignore)$/)
|
|
2037
2268
|
);
|
|
2038
2269
|
var IMPORT_FILE_FIELD = "file";
|
|
2039
2270
|
var MAX_IMPORT_BYTES = 50 * 1024 * 1024;
|
|
2040
2271
|
var MAX_IMPORT_ROWS = 2e5;
|
|
2041
|
-
var ImportMappingRequest =
|
|
2272
|
+
var ImportMappingRequest = import_zod9.z.object({
|
|
2042
2273
|
/** CSV header -> contact field. Exactly one column maps to `email`. */
|
|
2043
2274
|
mapping: ImportColumnMapping.refine(
|
|
2044
2275
|
(m) => Object.values(m).filter((v) => v === "email").length === 1,
|
|
2045
2276
|
"exactly one column maps to email"
|
|
2046
2277
|
),
|
|
2047
|
-
topics:
|
|
2048
|
-
tags:
|
|
2278
|
+
topics: import_zod9.z.array(Slug).max(100),
|
|
2279
|
+
tags: import_zod9.z.array(Slug).max(100),
|
|
2049
2280
|
/** Existing contacts get the mapped fields overwritten; false only adds topics, tags and missing fields. */
|
|
2050
|
-
update_existing:
|
|
2281
|
+
update_existing: import_zod9.z.boolean().optional(),
|
|
2051
2282
|
/** The importer states the people consented; the service records who said so and when. */
|
|
2052
|
-
consent_confirmed:
|
|
2283
|
+
consent_confirmed: import_zod9.z.literal(true)
|
|
2053
2284
|
});
|
|
2054
|
-
var ImportCommitRequest =
|
|
2285
|
+
var ImportCommitRequest = import_zod9.z.object({ mapping_version: import_zod9.z.number().int().min(1) });
|
|
2055
2286
|
var IMPORT_ROW_OUTCOMES = ["created", "updated", "unchanged", "suppressed", "skipped"];
|
|
2056
|
-
var ImportRowOutcome =
|
|
2287
|
+
var ImportRowOutcome = import_zod9.z.enum(IMPORT_ROW_OUTCOMES);
|
|
2057
2288
|
var IMPORT_SKIP_REASONS = [
|
|
2058
2289
|
"missing_email",
|
|
2059
2290
|
"invalid_email",
|
|
@@ -2062,90 +2293,90 @@ var IMPORT_SKIP_REASONS = [
|
|
|
2062
2293
|
"external_id_conflict",
|
|
2063
2294
|
"wrong_column_count"
|
|
2064
2295
|
];
|
|
2065
|
-
var ImportSkipReason =
|
|
2066
|
-
var ImportReport =
|
|
2067
|
-
created:
|
|
2068
|
-
updated:
|
|
2069
|
-
unchanged:
|
|
2070
|
-
suppressed:
|
|
2071
|
-
skipped:
|
|
2072
|
-
skipped_by_reason:
|
|
2296
|
+
var ImportSkipReason = import_zod9.z.enum(IMPORT_SKIP_REASONS);
|
|
2297
|
+
var ImportReport = import_zod9.z.object({
|
|
2298
|
+
created: import_zod9.z.number().int().min(0),
|
|
2299
|
+
updated: import_zod9.z.number().int().min(0),
|
|
2300
|
+
unchanged: import_zod9.z.number().int().min(0),
|
|
2301
|
+
suppressed: import_zod9.z.number().int().min(0),
|
|
2302
|
+
skipped: import_zod9.z.number().int().min(0),
|
|
2303
|
+
skipped_by_reason: import_zod9.z.record(ImportSkipReason, import_zod9.z.number().int().min(0)),
|
|
2073
2304
|
/** Rows whose contact was subscribed without some topic, because the address is blocked for it. */
|
|
2074
|
-
topics_withheld:
|
|
2305
|
+
topics_withheld: import_zod9.z.number().int().min(0)
|
|
2075
2306
|
});
|
|
2076
|
-
var ImportJob =
|
|
2307
|
+
var ImportJob = import_zod9.z.object({
|
|
2077
2308
|
id: Id,
|
|
2078
2309
|
status: ImportStatus,
|
|
2079
|
-
file_name:
|
|
2080
|
-
file_bytes:
|
|
2081
|
-
total_rows:
|
|
2310
|
+
file_name: import_zod9.z.string().max(255).nullable(),
|
|
2311
|
+
file_bytes: import_zod9.z.number().int().min(0),
|
|
2312
|
+
total_rows: import_zod9.z.number().int().min(0),
|
|
2082
2313
|
/** The header row, as in the file. */
|
|
2083
|
-
columns:
|
|
2314
|
+
columns: import_zod9.z.array(import_zod9.z.string()),
|
|
2084
2315
|
/** The first rows, for the mapping screen. */
|
|
2085
|
-
sample:
|
|
2316
|
+
sample: import_zod9.z.array(import_zod9.z.array(import_zod9.z.string())).max(5),
|
|
2086
2317
|
/** A mapping guessed from the headers, for the mapping screen to start from. */
|
|
2087
2318
|
suggested_mapping: ImportColumnMapping,
|
|
2088
2319
|
mapping: ImportColumnMapping.nullable(),
|
|
2089
|
-
mapping_version:
|
|
2090
|
-
topics:
|
|
2091
|
-
tags:
|
|
2092
|
-
update_existing:
|
|
2320
|
+
mapping_version: import_zod9.z.number().int().min(0),
|
|
2321
|
+
topics: import_zod9.z.array(Slug),
|
|
2322
|
+
tags: import_zod9.z.array(Slug),
|
|
2323
|
+
update_existing: import_zod9.z.boolean(),
|
|
2093
2324
|
/** The dry run of the current mapping; null before one finished. */
|
|
2094
2325
|
dry_run: ImportReport.nullable(),
|
|
2095
2326
|
/** What the commit has written so far; null before it started. */
|
|
2096
2327
|
result: ImportReport.nullable(),
|
|
2097
2328
|
/** Rows the current phase (dry run or commit) has processed. */
|
|
2098
|
-
processed_rows:
|
|
2329
|
+
processed_rows: import_zod9.z.number().int().min(0),
|
|
2099
2330
|
/** Why a `failed` import failed. */
|
|
2100
|
-
error:
|
|
2331
|
+
error: import_zod9.z.string().nullable(),
|
|
2101
2332
|
created_at: Timestamp,
|
|
2102
2333
|
updated_at: Timestamp,
|
|
2103
2334
|
finished_at: Timestamp.nullable()
|
|
2104
2335
|
});
|
|
2105
|
-
var ImportRow =
|
|
2336
|
+
var ImportRow = import_zod9.z.object({
|
|
2106
2337
|
/** The line in the file, 1 being the first line after the header. */
|
|
2107
|
-
row:
|
|
2108
|
-
email:
|
|
2338
|
+
row: import_zod9.z.number().int().min(1),
|
|
2339
|
+
email: import_zod9.z.string().nullable(),
|
|
2109
2340
|
outcome: ImportRowOutcome,
|
|
2110
2341
|
reason: ImportSkipReason.nullable(),
|
|
2111
2342
|
/** A human explanation for a skipped row (which value, which column). */
|
|
2112
|
-
message:
|
|
2343
|
+
message: import_zod9.z.string().nullable(),
|
|
2113
2344
|
contact_id: Id.nullable()
|
|
2114
2345
|
});
|
|
2115
2346
|
var ImportRowListQuery = PageQuery.extend({ outcome: ImportRowOutcome.optional() });
|
|
2116
|
-
var MailingScheduleRequest =
|
|
2117
|
-
var TrackingSettings =
|
|
2118
|
-
var VariantAnalytics =
|
|
2119
|
-
key:
|
|
2120
|
-
sent:
|
|
2121
|
-
unique_opens:
|
|
2122
|
-
unique_clicks:
|
|
2123
|
-
});
|
|
2124
|
-
var MailingAnalytics =
|
|
2347
|
+
var MailingScheduleRequest = import_zod9.z.object({ send_at: Timestamp });
|
|
2348
|
+
var TrackingSettings = import_zod9.z.object({ opens: import_zod9.z.boolean(), clicks: import_zod9.z.boolean() });
|
|
2349
|
+
var VariantAnalytics = import_zod9.z.object({
|
|
2350
|
+
key: import_zod9.z.string(),
|
|
2351
|
+
sent: import_zod9.z.number().int().min(0),
|
|
2352
|
+
unique_opens: import_zod9.z.number().int().min(0).nullable(),
|
|
2353
|
+
unique_clicks: import_zod9.z.number().int().min(0).nullable()
|
|
2354
|
+
});
|
|
2355
|
+
var MailingAnalytics = import_zod9.z.object({
|
|
2125
2356
|
mailing_id: Id,
|
|
2126
2357
|
counts: MailingCounts,
|
|
2127
2358
|
/** What was tracked for this mailing, fixed when it started; null before it started. */
|
|
2128
2359
|
tracking: TrackingSettings.nullable(),
|
|
2129
2360
|
/** Unique recipients with a human open. Null when opens were not tracked. */
|
|
2130
|
-
unique_opens:
|
|
2361
|
+
unique_opens: import_zod9.z.number().int().min(0).nullable(),
|
|
2131
2362
|
/**
|
|
2132
2363
|
* Recipients whose only opens came from Apple Mail Privacy Protection, which
|
|
2133
2364
|
* loads every image on delivery: counted apart, never as human opens.
|
|
2134
2365
|
*/
|
|
2135
|
-
apple_mpp_opens:
|
|
2366
|
+
apple_mpp_opens: import_zod9.z.number().int().min(0).nullable(),
|
|
2136
2367
|
/** Opens and clicks from security scanners and prefetchers, filtered out of the unique counts. */
|
|
2137
|
-
machine_events:
|
|
2138
|
-
unique_clicks:
|
|
2139
|
-
unsubscribes:
|
|
2140
|
-
bounces:
|
|
2141
|
-
complaints:
|
|
2142
|
-
links:
|
|
2143
|
-
variants:
|
|
2368
|
+
machine_events: import_zod9.z.number().int().min(0).nullable(),
|
|
2369
|
+
unique_clicks: import_zod9.z.number().int().min(0).nullable(),
|
|
2370
|
+
unsubscribes: import_zod9.z.number().int().min(0),
|
|
2371
|
+
bounces: import_zod9.z.number().int().min(0),
|
|
2372
|
+
complaints: import_zod9.z.number().int().min(0),
|
|
2373
|
+
links: import_zod9.z.array(import_zod9.z.object({ url: import_zod9.z.string(), unique_clicks: import_zod9.z.number().int().min(0) })).nullable(),
|
|
2374
|
+
variants: import_zod9.z.array(VariantAnalytics).nullable()
|
|
2144
2375
|
});
|
|
2145
2376
|
|
|
2146
2377
|
// src/automations.ts
|
|
2147
2378
|
var AUTOMATION_FILTER_FIELD_PATTERN = /^(email|first_name|last_name|locale|created_at|tag|topic|segment|engagement:(opened|clicked)|step:(opened|clicked)|property:[A-Za-z0-9_.-]{1,64}|event:[A-Za-z0-9_.-]{1,64})$/;
|
|
2148
|
-
var AutomationFilterField =
|
|
2379
|
+
var AutomationFilterField = import_zod10.z.string().regex(AUTOMATION_FILTER_FIELD_PATTERN, "unknown filter field");
|
|
2149
2380
|
var AUTOMATION_FILTER_FIELD_OPERATORS = {
|
|
2150
2381
|
...FILTER_FIELD_OPERATORS,
|
|
2151
2382
|
segment: ["eq", "neq", "in", "not_in"],
|
|
@@ -2155,18 +2386,18 @@ var AUTOMATION_FILTER_FIELD_OPERATORS = {
|
|
|
2155
2386
|
step: ["eq", "neq"]
|
|
2156
2387
|
};
|
|
2157
2388
|
var automationFilterFamily = filterFieldFamily;
|
|
2158
|
-
var AutomationFilterCondition =
|
|
2389
|
+
var AutomationFilterCondition = import_zod10.z.object({ field: AutomationFilterField, op: FilterOperator, value: JsonValue.optional() }).strict().refine((c) => (c.op === "exists" || c.op === "not_exists") === (c.value === void 0), {
|
|
2159
2390
|
message: "exists and not_exists take no value; every other operator needs one",
|
|
2160
2391
|
path: ["value"]
|
|
2161
2392
|
}).refine((c) => c.op !== "in" && c.op !== "not_in" || Array.isArray(c.value), {
|
|
2162
2393
|
message: "in and not_in take an array",
|
|
2163
2394
|
path: ["value"]
|
|
2164
2395
|
});
|
|
2165
|
-
var AutomationFilter =
|
|
2166
|
-
() =>
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2396
|
+
var AutomationFilter = import_zod10.z.lazy(
|
|
2397
|
+
() => import_zod10.z.union([
|
|
2398
|
+
import_zod10.z.object({ and: import_zod10.z.array(AutomationFilter).min(1).max(50) }).strict(),
|
|
2399
|
+
import_zod10.z.object({ or: import_zod10.z.array(AutomationFilter).min(1).max(50) }).strict(),
|
|
2400
|
+
import_zod10.z.object({ not: AutomationFilter }).strict(),
|
|
2170
2401
|
AutomationFilterCondition
|
|
2171
2402
|
])
|
|
2172
2403
|
);
|
|
@@ -2179,20 +2410,20 @@ function filterConditions(filter) {
|
|
|
2179
2410
|
if ("not" in filter) return filterConditions(filter.not);
|
|
2180
2411
|
return [filter];
|
|
2181
2412
|
}
|
|
2182
|
-
var StepId =
|
|
2183
|
-
var TimeOfDay =
|
|
2184
|
-
var Weekday =
|
|
2185
|
-
var TimezoneName =
|
|
2413
|
+
var StepId = import_zod10.z.string().regex(/^[A-Za-z0-9_-]{1,64}$/, "letters, digits, underscore and hyphen, 1 to 64");
|
|
2414
|
+
var TimeOfDay = import_zod10.z.string().regex(/^([01]\d|2[0-3]):[0-5]\d$/, "HH:MM in 24 hours");
|
|
2415
|
+
var Weekday = import_zod10.z.number().int().min(0).max(6);
|
|
2416
|
+
var TimezoneName = import_zod10.z.string().min(1).max(64).regex(/^(UTC|[A-Za-z][A-Za-z0-9_+-]*(?:\/[A-Za-z0-9_+-]+)+)$/, "an IANA time zone name such as Europe/Berlin");
|
|
2186
2417
|
var MAX_DELAY_SECONDS = 365 * 24 * 60 * 60;
|
|
2187
|
-
var DateOnly =
|
|
2418
|
+
var DateOnly = import_zod10.z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "a calendar date such as 2026-09-20").refine((v) => {
|
|
2188
2419
|
const [y, m, d] = v.split("-").map(Number);
|
|
2189
2420
|
const t = new Date(Date.UTC(y, m - 1, d));
|
|
2190
2421
|
return t.getUTCFullYear() === y && t.getUTCMonth() + 1 === m && t.getUTCDate() === d;
|
|
2191
2422
|
}, "a real calendar date");
|
|
2192
|
-
var OffsetDays =
|
|
2423
|
+
var OffsetDays = import_zod10.z.number().int().min(-365).max(365);
|
|
2193
2424
|
var DATE_PASSED_ANSWERS = ["skip", "stop", "continue"];
|
|
2194
|
-
var DatePassedAnswer =
|
|
2195
|
-
var EventName =
|
|
2425
|
+
var DatePassedAnswer = import_zod10.z.enum(DATE_PASSED_ANSWERS);
|
|
2426
|
+
var EventName = import_zod10.z.string().regex(/^[A-Za-z0-9][A-Za-z0-9_.:-]{0,79}$/, "letters, digits, dot, colon, underscore and hyphen, 1 to 80");
|
|
2196
2427
|
var AUTOMATION_TRIGGER_KINDS = [
|
|
2197
2428
|
"topic_subscribed",
|
|
2198
2429
|
"form_confirmed",
|
|
@@ -2205,17 +2436,17 @@ var AUTOMATION_TRIGGER_KINDS = [
|
|
|
2205
2436
|
"segment_entered",
|
|
2206
2437
|
"link_clicked"
|
|
2207
2438
|
];
|
|
2208
|
-
var AutomationTriggerKind =
|
|
2439
|
+
var AutomationTriggerKind = import_zod10.z.enum(AUTOMATION_TRIGGER_KINDS);
|
|
2209
2440
|
var exclude = { exclude: BoundedAutomationFilter.nullish() };
|
|
2210
|
-
var AutomationTrigger =
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2441
|
+
var AutomationTrigger = import_zod10.z.discriminatedUnion("kind", [
|
|
2442
|
+
import_zod10.z.object({ kind: import_zod10.z.literal("topic_subscribed"), topic: Slug, ...exclude }).strict(),
|
|
2443
|
+
import_zod10.z.object({ kind: import_zod10.z.literal("form_confirmed"), form_id: Id, ...exclude }).strict(),
|
|
2444
|
+
import_zod10.z.object({ kind: import_zod10.z.literal("tag_added"), tag: Slug, ...exclude }).strict(),
|
|
2214
2445
|
/** `to` given: only a change that lands on this value fires. Absent: any change of the key. */
|
|
2215
|
-
|
|
2446
|
+
import_zod10.z.object({ kind: import_zod10.z.literal("property_changed"), key: ContactPropertyKey, to: JsonValue.optional(), ...exclude }).strict(),
|
|
2216
2447
|
/** `where` filters the event's own data, so only `event:<key>` leaves belong in it. */
|
|
2217
|
-
|
|
2218
|
-
|
|
2448
|
+
import_zod10.z.object({ kind: import_zod10.z.literal("event"), name: EventName, where: BoundedAutomationFilter.nullish(), ...exclude }).strict(),
|
|
2449
|
+
import_zod10.z.object({ kind: import_zod10.z.literal("manual"), ...exclude }).strict(),
|
|
2219
2450
|
/**
|
|
2220
2451
|
* Every year on a date the contact carries: a birthday, a joining date, a
|
|
2221
2452
|
* renewal. `offset_days` moves it ("three days before"), `at` is the wall
|
|
@@ -2225,8 +2456,8 @@ var AutomationTrigger = import_zod9.z.discriminatedUnion("kind", [
|
|
|
2225
2456
|
* A 29 February date fires on 1 March in a year that has no 29 February, so
|
|
2226
2457
|
* nobody is skipped every fourth year.
|
|
2227
2458
|
*/
|
|
2228
|
-
|
|
2229
|
-
kind:
|
|
2459
|
+
import_zod10.z.object({
|
|
2460
|
+
kind: import_zod10.z.literal("date_anniversary"),
|
|
2230
2461
|
key: ContactPropertyKey,
|
|
2231
2462
|
offset_days: OffsetDays,
|
|
2232
2463
|
at: TimeOfDay,
|
|
@@ -2238,8 +2469,8 @@ var AutomationTrigger = import_zod9.z.discriminatedUnion("kind", [
|
|
|
2238
2469
|
* not ask about a segment or about an event's data: there is no event, and a
|
|
2239
2470
|
* segment is its own trigger kind.
|
|
2240
2471
|
*/
|
|
2241
|
-
|
|
2242
|
-
kind:
|
|
2472
|
+
import_zod10.z.object({
|
|
2473
|
+
kind: import_zod10.z.literal("exact_date"),
|
|
2243
2474
|
on: DateOnly,
|
|
2244
2475
|
at: TimeOfDay,
|
|
2245
2476
|
where: BoundedAutomationFilter.nullish(),
|
|
@@ -2258,7 +2489,7 @@ var AutomationTrigger = import_zod9.z.discriminatedUnion("kind", [
|
|
|
2258
2489
|
* already exists. Entering those people as well is the publish dialog's
|
|
2259
2490
|
* backfill question, answered by a person rather than by the sweep.
|
|
2260
2491
|
*/
|
|
2261
|
-
|
|
2492
|
+
import_zod10.z.object({ kind: import_zod10.z.literal("segment_entered"), segment_id: Id, ...exclude }).strict(),
|
|
2262
2493
|
/**
|
|
2263
2494
|
* S4. When somebody clicks a link in a mailing that has already gone out.
|
|
2264
2495
|
*
|
|
@@ -2268,7 +2499,7 @@ var AutomationTrigger = import_zod9.z.discriminatedUnion("kind", [
|
|
|
2268
2499
|
* tracking off there is no click to hear about, so the validator refuses it
|
|
2269
2500
|
* rather than leaving an automation that can never fire.
|
|
2270
2501
|
*/
|
|
2271
|
-
|
|
2502
|
+
import_zod10.z.object({ kind: import_zod10.z.literal("link_clicked"), mailing_id: Id, url: import_zod10.z.string().min(1).max(2048).optional(), ...exclude }).strict()
|
|
2272
2503
|
]);
|
|
2273
2504
|
var AUTOMATION_DATE_TRIGGER_KINDS = ["date_anniversary", "exact_date"];
|
|
2274
2505
|
var MAX_TRIGGERS = 10;
|
|
@@ -2287,45 +2518,45 @@ var AUTOMATION_STEP_KINDS = [
|
|
|
2287
2518
|
"webhook",
|
|
2288
2519
|
"notify"
|
|
2289
2520
|
];
|
|
2290
|
-
var AutomationStepKind =
|
|
2521
|
+
var AutomationStepKind = import_zod10.z.enum(AUTOMATION_STEP_KINDS);
|
|
2291
2522
|
var next = { next: StepId.nullable() };
|
|
2292
|
-
var Unchosen =
|
|
2293
|
-
var DraftSlug =
|
|
2294
|
-
var DraftPropertyKey =
|
|
2295
|
-
var label2 = { label:
|
|
2296
|
-
var EmailStepLanguage =
|
|
2297
|
-
subject:
|
|
2298
|
-
preheader:
|
|
2523
|
+
var Unchosen = import_zod10.z.literal("");
|
|
2524
|
+
var DraftSlug = import_zod10.z.union([Slug, Unchosen]);
|
|
2525
|
+
var DraftPropertyKey = import_zod10.z.union([ContactPropertyKey, Unchosen]);
|
|
2526
|
+
var label2 = { label: import_zod10.z.string().max(120).nullish() };
|
|
2527
|
+
var EmailStepLanguage = import_zod10.z.object({
|
|
2528
|
+
subject: import_zod10.z.string().min(1).max(998),
|
|
2529
|
+
preheader: import_zod10.z.string().max(500).nullable(),
|
|
2299
2530
|
document: TemplateDocument,
|
|
2300
2531
|
/** This language's insertions, its texts over the template's structure (every text present). */
|
|
2301
2532
|
insertions: Insertions.nullish()
|
|
2302
2533
|
}).strict();
|
|
2303
|
-
var EmailStep =
|
|
2304
|
-
kind:
|
|
2534
|
+
var EmailStep = import_zod10.z.object({
|
|
2535
|
+
kind: import_zod10.z.literal("email"),
|
|
2305
2536
|
...label2,
|
|
2306
2537
|
...next,
|
|
2307
2538
|
template_id: Id.nullish(),
|
|
2308
2539
|
document: TemplateDocument.nullish(),
|
|
2309
2540
|
/** Empty while the step is being written, or when its template has a subject; else `not_chosen` refuses to publish it. */
|
|
2310
|
-
subject:
|
|
2311
|
-
preheader:
|
|
2541
|
+
subject: import_zod10.z.string().max(998),
|
|
2542
|
+
preheader: import_zod10.z.string().max(500).nullish(),
|
|
2312
2543
|
locale: LocaleTag.nullish(),
|
|
2313
|
-
languages:
|
|
2544
|
+
languages: import_zod10.z.record(LocaleTag, EmailStepLanguage).nullish(),
|
|
2314
2545
|
/** The main language's insertions, snapshot from the template when the automation is published. */
|
|
2315
2546
|
insertions: Insertions.nullish()
|
|
2316
2547
|
}).strict();
|
|
2317
|
-
var DelayStep =
|
|
2318
|
-
kind:
|
|
2548
|
+
var DelayStep = import_zod10.z.object({
|
|
2549
|
+
kind: import_zod10.z.literal("delay"),
|
|
2319
2550
|
...label2,
|
|
2320
2551
|
...next,
|
|
2321
|
-
wait:
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2552
|
+
wait: import_zod10.z.discriminatedUnion("mode", [
|
|
2553
|
+
import_zod10.z.object({ mode: import_zod10.z.literal("duration"), seconds: import_zod10.z.number().int().min(1).max(MAX_DELAY_SECONDS) }).strict(),
|
|
2554
|
+
import_zod10.z.object({ mode: import_zod10.z.literal("time_of_day"), at: TimeOfDay }).strict(),
|
|
2555
|
+
import_zod10.z.object({ mode: import_zod10.z.literal("weekday"), weekday: Weekday, at: TimeOfDay }).strict(),
|
|
2325
2556
|
/** A fixed day has no next occurrence, so `continue` is not one of its answers. */
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
mode:
|
|
2557
|
+
import_zod10.z.object({ mode: import_zod10.z.literal("date"), on: DateOnly, at: TimeOfDay, passed: import_zod10.z.enum(["skip", "stop"]) }).strict(),
|
|
2558
|
+
import_zod10.z.object({
|
|
2559
|
+
mode: import_zod10.z.literal("date_property"),
|
|
2329
2560
|
key: ContactPropertyKey,
|
|
2330
2561
|
offset_days: OffsetDays,
|
|
2331
2562
|
at: TimeOfDay,
|
|
@@ -2333,8 +2564,8 @@ var DelayStep = import_zod9.z.object({
|
|
|
2333
2564
|
}).strict()
|
|
2334
2565
|
])
|
|
2335
2566
|
}).strict();
|
|
2336
|
-
var ConditionStep =
|
|
2337
|
-
kind:
|
|
2567
|
+
var ConditionStep = import_zod10.z.object({
|
|
2568
|
+
kind: import_zod10.z.literal("condition"),
|
|
2338
2569
|
...label2,
|
|
2339
2570
|
filter: BoundedAutomationFilter,
|
|
2340
2571
|
yes: StepId.nullable(),
|
|
@@ -2345,49 +2576,49 @@ var ConditionStep = import_zod9.z.object({
|
|
|
2345
2576
|
* neither half means anything without the other: a window with no answer
|
|
2346
2577
|
* for the end of it would be a silent decision.
|
|
2347
2578
|
*/
|
|
2348
|
-
wait_for:
|
|
2579
|
+
wait_for: import_zod10.z.object({ up_to_s: import_zod10.z.number().int().min(1).max(MAX_DELAY_SECONDS), on_timeout: import_zod10.z.enum(["yes", "no"]) }).strict().nullish()
|
|
2349
2580
|
}).strict();
|
|
2350
|
-
var SplitBranchKey =
|
|
2581
|
+
var SplitBranchKey = import_zod10.z.string().regex(/^[A-Za-z0-9_-]{1,32}$/, "letters, digits, underscore and hyphen, 1 to 32");
|
|
2351
2582
|
var MIN_SPLIT_BRANCHES = 2;
|
|
2352
2583
|
var MAX_SPLIT_BRANCHES = 4;
|
|
2353
|
-
var SplitStep =
|
|
2354
|
-
kind:
|
|
2584
|
+
var SplitStep = import_zod10.z.object({
|
|
2585
|
+
kind: import_zod10.z.literal("split"),
|
|
2355
2586
|
...label2,
|
|
2356
|
-
branches:
|
|
2357
|
-
|
|
2587
|
+
branches: import_zod10.z.array(
|
|
2588
|
+
import_zod10.z.object({
|
|
2358
2589
|
key: SplitBranchKey,
|
|
2359
2590
|
/** A whole percentage. Zero is allowed: a branch kept in the flow but switched off. */
|
|
2360
|
-
weight:
|
|
2591
|
+
weight: import_zod10.z.number().int().min(0).max(100),
|
|
2361
2592
|
next: StepId.nullable()
|
|
2362
2593
|
}).strict()
|
|
2363
2594
|
).min(MIN_SPLIT_BRANCHES).max(MAX_SPLIT_BRANCHES).refine((bs) => new Set(bs.map((b) => b.key)).size === bs.length, "each branch needs its own key").refine((bs) => bs.reduce((sum, b) => sum + b.weight, 0) === 100, "the weights have to come to 100")
|
|
2364
2595
|
}).strict();
|
|
2365
|
-
var GotoStep =
|
|
2596
|
+
var GotoStep = import_zod10.z.object({ kind: import_zod10.z.literal("goto"), ...label2, target: StepId.nullable() }).strict();
|
|
2366
2597
|
var MAX_STEP_VISITS = 20;
|
|
2367
|
-
var WebhookStep =
|
|
2368
|
-
var NotifyRecipients =
|
|
2369
|
-
var NotifyStep =
|
|
2370
|
-
kind:
|
|
2598
|
+
var WebhookStep = import_zod10.z.object({ kind: import_zod10.z.literal("webhook"), ...label2, ...next, endpoint_id: Id.nullable(), payload: JsonValue.nullish() }).strict();
|
|
2599
|
+
var NotifyRecipients = import_zod10.z.union([import_zod10.z.literal("owner"), import_zod10.z.literal("admins"), import_zod10.z.object({ member_id: Id }).strict()]);
|
|
2600
|
+
var NotifyStep = import_zod10.z.object({
|
|
2601
|
+
kind: import_zod10.z.literal("notify"),
|
|
2371
2602
|
...label2,
|
|
2372
2603
|
...next,
|
|
2373
2604
|
to: NotifyRecipients,
|
|
2374
2605
|
/** Empty while the step is being written; `not_chosen` refuses to publish it. */
|
|
2375
|
-
subject:
|
|
2376
|
-
body:
|
|
2606
|
+
subject: import_zod10.z.string().max(998),
|
|
2607
|
+
body: import_zod10.z.string().max(1e4)
|
|
2377
2608
|
}).strict();
|
|
2378
|
-
var AutomationStep =
|
|
2609
|
+
var AutomationStep = import_zod10.z.discriminatedUnion("kind", [
|
|
2379
2610
|
EmailStep,
|
|
2380
2611
|
DelayStep,
|
|
2381
2612
|
ConditionStep,
|
|
2382
|
-
|
|
2383
|
-
|
|
2613
|
+
import_zod10.z.object({ kind: import_zod10.z.literal("add_tag"), ...label2, ...next, tag: DraftSlug }).strict(),
|
|
2614
|
+
import_zod10.z.object({ kind: import_zod10.z.literal("remove_tag"), ...label2, ...next, tag: DraftSlug }).strict(),
|
|
2384
2615
|
/** `value` null clears the property, as a contact upsert does. */
|
|
2385
|
-
|
|
2616
|
+
import_zod10.z.object({ kind: import_zod10.z.literal("set_property"), ...label2, ...next, key: DraftPropertyKey, value: JsonValue }).strict(),
|
|
2386
2617
|
/** Subscribing never lifts a suppression: the service checks that, not the flow. */
|
|
2387
|
-
|
|
2618
|
+
import_zod10.z.object({ kind: import_zod10.z.literal("subscribe_topic"), ...label2, ...next, topic: DraftSlug }).strict(),
|
|
2388
2619
|
/** `topic` unsubscribes from the automation's own topic, `all` from every topic. */
|
|
2389
|
-
|
|
2390
|
-
|
|
2620
|
+
import_zod10.z.object({ kind: import_zod10.z.literal("unsubscribe"), ...label2, ...next, scope: import_zod10.z.enum(["topic", "all"]) }).strict(),
|
|
2621
|
+
import_zod10.z.object({ kind: import_zod10.z.literal("exit"), ...label2 }).strict(),
|
|
2391
2622
|
SplitStep,
|
|
2392
2623
|
GotoStep,
|
|
2393
2624
|
WebhookStep,
|
|
@@ -2411,25 +2642,25 @@ function stepTargets(step) {
|
|
|
2411
2642
|
}
|
|
2412
2643
|
}
|
|
2413
2644
|
var MAX_STEPS = 200;
|
|
2414
|
-
var AutomationFlow =
|
|
2415
|
-
triggers:
|
|
2645
|
+
var AutomationFlow = import_zod10.z.object({
|
|
2646
|
+
triggers: import_zod10.z.array(AutomationTrigger).max(MAX_TRIGGERS),
|
|
2416
2647
|
/** The first step. `null` is an empty flow. */
|
|
2417
2648
|
entry: StepId.nullable(),
|
|
2418
|
-
steps:
|
|
2649
|
+
steps: import_zod10.z.record(StepId, AutomationStep)
|
|
2419
2650
|
}).strict();
|
|
2420
2651
|
var emptyFlow = () => ({ triggers: [], entry: null, steps: {} });
|
|
2421
|
-
var QuietHours =
|
|
2652
|
+
var QuietHours = import_zod10.z.object({
|
|
2422
2653
|
start: TimeOfDay,
|
|
2423
2654
|
end: TimeOfDay,
|
|
2424
|
-
weekdays:
|
|
2655
|
+
weekdays: import_zod10.z.array(Weekday).min(1).max(7).nullish()
|
|
2425
2656
|
}).strict();
|
|
2426
2657
|
var RE_ENTRY_MODES = ["off", "after_exit"];
|
|
2427
|
-
var ReEntryMode =
|
|
2658
|
+
var ReEntryMode = import_zod10.z.enum(RE_ENTRY_MODES);
|
|
2428
2659
|
var MAX_RE_ENTRY_COOLDOWN_SECONDS = 365 * 24 * 60 * 60;
|
|
2429
|
-
var AutomationSettings =
|
|
2660
|
+
var AutomationSettings = import_zod10.z.object({
|
|
2430
2661
|
re_entry: ReEntryMode,
|
|
2431
2662
|
/** Seconds a person must wait after leaving before entering again. Only with `after_exit`. */
|
|
2432
|
-
re_entry_cooldown_s:
|
|
2663
|
+
re_entry_cooldown_s: import_zod10.z.number().int().min(0).max(MAX_RE_ENTRY_COOLDOWN_SECONDS).nullish(),
|
|
2433
2664
|
quiet_hours: QuietHours.nullish(),
|
|
2434
2665
|
/** Checked before every step; when it matches, the run ends. */
|
|
2435
2666
|
exit_filter: BoundedAutomationFilter.nullish()
|
|
@@ -2487,18 +2718,18 @@ var AUTOMATION_ISSUE_CODES = [
|
|
|
2487
2718
|
/** A one-off date that is already over everywhere on earth, so it would fire for nobody. */
|
|
2488
2719
|
"date_in_the_past"
|
|
2489
2720
|
];
|
|
2490
|
-
var AutomationIssueCode =
|
|
2491
|
-
var AutomationIssue =
|
|
2721
|
+
var AutomationIssueCode = import_zod10.z.enum(AUTOMATION_ISSUE_CODES);
|
|
2722
|
+
var AutomationIssue = import_zod10.z.object({
|
|
2492
2723
|
code: AutomationIssueCode,
|
|
2493
2724
|
/** The step the issue is about, when it is about one. */
|
|
2494
2725
|
step_id: StepId.nullable(),
|
|
2495
2726
|
/** Where inside the document, for the canvas to point at a field. */
|
|
2496
|
-
path:
|
|
2497
|
-
message:
|
|
2727
|
+
path: import_zod10.z.array(import_zod10.z.union([import_zod10.z.string(), import_zod10.z.number()])),
|
|
2728
|
+
message: import_zod10.z.string()
|
|
2498
2729
|
});
|
|
2499
|
-
var AutomationValidation =
|
|
2500
|
-
ok:
|
|
2501
|
-
issues:
|
|
2730
|
+
var AutomationValidation = import_zod10.z.object({
|
|
2731
|
+
ok: import_zod10.z.boolean(),
|
|
2732
|
+
issues: import_zod10.z.array(AutomationIssue)
|
|
2502
2733
|
});
|
|
2503
2734
|
function validateAutomation(flow, settings, ctx) {
|
|
2504
2735
|
const issues = [];
|
|
@@ -2889,7 +3120,7 @@ function cycles(flow) {
|
|
|
2889
3120
|
return out.sort();
|
|
2890
3121
|
}
|
|
2891
3122
|
var AUTOMATION_STATUSES = ["draft", "active", "paused", "archived"];
|
|
2892
|
-
var AutomationStatus =
|
|
3123
|
+
var AutomationStatus = import_zod10.z.enum(AUTOMATION_STATUSES);
|
|
2893
3124
|
var AUTOMATION_END_REASONS = [
|
|
2894
3125
|
"completed",
|
|
2895
3126
|
"exit_filter",
|
|
@@ -2908,9 +3139,9 @@ var AUTOMATION_END_REASONS = [
|
|
|
2908
3139
|
"ended_by_hand",
|
|
2909
3140
|
"failed"
|
|
2910
3141
|
];
|
|
2911
|
-
var AutomationEndReason =
|
|
3142
|
+
var AutomationEndReason = import_zod10.z.enum(AUTOMATION_END_REASONS);
|
|
2912
3143
|
var AUTOMATION_WAIT_REASONS = ["delay", "quiet_hours", "plan_limit", "sending", "condition"];
|
|
2913
|
-
var AutomationWaitReason =
|
|
3144
|
+
var AutomationWaitReason = import_zod10.z.enum(AUTOMATION_WAIT_REASONS);
|
|
2914
3145
|
var AUTOMATION_ENTRY_REFUSALS = [
|
|
2915
3146
|
"already_inside",
|
|
2916
3147
|
"re_entry_off",
|
|
@@ -2921,26 +3152,26 @@ var AUTOMATION_ENTRY_REFUSALS = [
|
|
|
2921
3152
|
"not_active",
|
|
2922
3153
|
"unknown_contact"
|
|
2923
3154
|
];
|
|
2924
|
-
var AutomationEntryRefusal =
|
|
2925
|
-
var AutomationCounts =
|
|
2926
|
-
started:
|
|
2927
|
-
in_progress:
|
|
2928
|
-
completed:
|
|
2929
|
-
exited:
|
|
2930
|
-
failed:
|
|
2931
|
-
});
|
|
2932
|
-
var Automation =
|
|
3155
|
+
var AutomationEntryRefusal = import_zod10.z.enum(AUTOMATION_ENTRY_REFUSALS);
|
|
3156
|
+
var AutomationCounts = import_zod10.z.object({
|
|
3157
|
+
started: import_zod10.z.number().int().min(0),
|
|
3158
|
+
in_progress: import_zod10.z.number().int().min(0),
|
|
3159
|
+
completed: import_zod10.z.number().int().min(0),
|
|
3160
|
+
exited: import_zod10.z.number().int().min(0),
|
|
3161
|
+
failed: import_zod10.z.number().int().min(0)
|
|
3162
|
+
});
|
|
3163
|
+
var Automation = import_zod10.z.object({
|
|
2933
3164
|
id: Id,
|
|
2934
|
-
name:
|
|
3165
|
+
name: import_zod10.z.string().min(1).max(200),
|
|
2935
3166
|
status: AutomationStatus,
|
|
2936
3167
|
/** Every automation sends under one topic; there are no transactional automations. */
|
|
2937
3168
|
topic: Slug,
|
|
2938
3169
|
provider_id: Id.nullable(),
|
|
2939
3170
|
settings: AutomationSettings,
|
|
2940
3171
|
/** The flow people are running through, null while the automation has never been published. */
|
|
2941
|
-
published_version:
|
|
3172
|
+
published_version: import_zod10.z.number().int().min(1).nullable(),
|
|
2942
3173
|
/** The flow being edited. Increments on every save, like a template's version. */
|
|
2943
|
-
draft_version:
|
|
3174
|
+
draft_version: import_zod10.z.number().int().min(1),
|
|
2944
3175
|
counts: AutomationCounts,
|
|
2945
3176
|
created_at: Timestamp,
|
|
2946
3177
|
updated_at: Timestamp,
|
|
@@ -2953,16 +3184,16 @@ var AutomationWithFlow = Automation.extend({
|
|
|
2953
3184
|
published_flow: AutomationFlow.nullable()
|
|
2954
3185
|
});
|
|
2955
3186
|
var AutomationSummary = Automation;
|
|
2956
|
-
var AutomationCreate =
|
|
2957
|
-
name:
|
|
3187
|
+
var AutomationCreate = import_zod10.z.object({
|
|
3188
|
+
name: import_zod10.z.string().min(1).max(200),
|
|
2958
3189
|
topic: Slug,
|
|
2959
3190
|
provider_id: Id.optional(),
|
|
2960
3191
|
flow: AutomationFlow.optional(),
|
|
2961
3192
|
settings: AutomationSettings.partial().optional()
|
|
2962
3193
|
});
|
|
2963
|
-
var AutomationUpdate =
|
|
2964
|
-
base_version:
|
|
2965
|
-
name:
|
|
3194
|
+
var AutomationUpdate = import_zod10.z.object({
|
|
3195
|
+
base_version: import_zod10.z.number().int().min(1),
|
|
3196
|
+
name: import_zod10.z.string().min(1).max(200).optional(),
|
|
2966
3197
|
topic: Slug.optional(),
|
|
2967
3198
|
provider_id: Id.optional(),
|
|
2968
3199
|
flow: AutomationFlow.optional(),
|
|
@@ -2975,42 +3206,42 @@ var AutomationListQuery = PageQuery.extend({
|
|
|
2975
3206
|
status: AutomationStatus.optional(),
|
|
2976
3207
|
topic: Slug.optional()
|
|
2977
3208
|
});
|
|
2978
|
-
var AutomationPublishRequest =
|
|
3209
|
+
var AutomationPublishRequest = import_zod10.z.object({
|
|
2979
3210
|
/**
|
|
2980
3211
|
* Answer what this publish would do and change nothing, whatever the flow
|
|
2981
3212
|
* looks like. Without it a publish that has no issues and moves nobody
|
|
2982
3213
|
* simply goes ahead, which is right for an API caller and wrong for a
|
|
2983
3214
|
* dialog that is only showing somebody what they are about to do.
|
|
2984
3215
|
*/
|
|
2985
|
-
dry_run:
|
|
2986
|
-
confirm:
|
|
3216
|
+
dry_run: import_zod10.z.boolean().optional(),
|
|
3217
|
+
confirm: import_zod10.z.boolean().optional(),
|
|
2987
3218
|
/** Per removed step: the step its waiting runs move to, or null to end them. */
|
|
2988
|
-
moves:
|
|
3219
|
+
moves: import_zod10.z.record(StepId, StepId.nullable()).optional(),
|
|
2989
3220
|
/** Also enter everyone who matches a trigger's condition right now. */
|
|
2990
|
-
backfill:
|
|
3221
|
+
backfill: import_zod10.z.boolean().optional()
|
|
2991
3222
|
}).strict();
|
|
2992
|
-
var AutomationPublishMove =
|
|
3223
|
+
var AutomationPublishMove = import_zod10.z.object({
|
|
2993
3224
|
step_id: StepId,
|
|
2994
3225
|
/** Why the step's people have to move: it is gone, or its delay changed. */
|
|
2995
|
-
change:
|
|
2996
|
-
waiting:
|
|
3226
|
+
change: import_zod10.z.enum(["removed", "delay_changed", "kind_changed"]),
|
|
3227
|
+
waiting: import_zod10.z.number().int().min(0),
|
|
2997
3228
|
/** Where they go: a step id, or null to end their runs with `step_removed`. */
|
|
2998
3229
|
destination: StepId.nullable()
|
|
2999
3230
|
});
|
|
3000
|
-
var AutomationPublishResult =
|
|
3001
|
-
published:
|
|
3231
|
+
var AutomationPublishResult = import_zod10.z.object({
|
|
3232
|
+
published: import_zod10.z.boolean(),
|
|
3002
3233
|
automation: Automation,
|
|
3003
3234
|
/** Empty when nothing has to move; non-empty and `published` false asks for a confirmation. */
|
|
3004
|
-
moves:
|
|
3235
|
+
moves: import_zod10.z.array(AutomationPublishMove),
|
|
3005
3236
|
/** How many people the backfill entered, or would enter when it is not confirmed. */
|
|
3006
|
-
backfill:
|
|
3007
|
-
issues:
|
|
3008
|
-
});
|
|
3009
|
-
var AutomationDuplicateRequest =
|
|
3010
|
-
var AutomationEnrollRequest =
|
|
3011
|
-
contact_ids:
|
|
3012
|
-
external_ids:
|
|
3013
|
-
emails:
|
|
3237
|
+
backfill: import_zod10.z.number().int().min(0),
|
|
3238
|
+
issues: import_zod10.z.array(AutomationIssue)
|
|
3239
|
+
});
|
|
3240
|
+
var AutomationDuplicateRequest = import_zod10.z.object({ name: import_zod10.z.string().min(1).max(200).optional() }).strict();
|
|
3241
|
+
var AutomationEnrollRequest = import_zod10.z.object({
|
|
3242
|
+
contact_ids: import_zod10.z.array(Id).min(1).max(1e3).optional(),
|
|
3243
|
+
external_ids: import_zod10.z.array(import_zod10.z.string().min(1).max(255)).min(1).max(1e3).optional(),
|
|
3244
|
+
emails: import_zod10.z.array(Email).min(1).max(1e3).optional(),
|
|
3014
3245
|
segment_id: Id.optional(),
|
|
3015
3246
|
/** Where to start them; the flow's entry step by default. */
|
|
3016
3247
|
step_id: StepId.optional()
|
|
@@ -3018,34 +3249,34 @@ var AutomationEnrollRequest = import_zod9.z.object({
|
|
|
3018
3249
|
(v) => [v.contact_ids, v.external_ids, v.emails, v.segment_id].filter((x) => x !== void 0).length === 1,
|
|
3019
3250
|
"name the people exactly one way: contact_ids, external_ids, emails or segment_id"
|
|
3020
3251
|
);
|
|
3021
|
-
var AutomationEnrollment =
|
|
3252
|
+
var AutomationEnrollment = import_zod10.z.object({
|
|
3022
3253
|
contact_id: Id.nullable(),
|
|
3023
3254
|
email: Email.nullable(),
|
|
3024
|
-
external_id:
|
|
3025
|
-
entered:
|
|
3255
|
+
external_id: import_zod10.z.string().nullable(),
|
|
3256
|
+
entered: import_zod10.z.boolean(),
|
|
3026
3257
|
run_id: Id.nullable(),
|
|
3027
3258
|
reason: AutomationEntryRefusal.nullable()
|
|
3028
3259
|
});
|
|
3029
|
-
var AutomationEnrollResult =
|
|
3030
|
-
entered:
|
|
3031
|
-
refused:
|
|
3032
|
-
results:
|
|
3260
|
+
var AutomationEnrollResult = import_zod10.z.object({
|
|
3261
|
+
entered: import_zod10.z.number().int().min(0),
|
|
3262
|
+
refused: import_zod10.z.number().int().min(0),
|
|
3263
|
+
results: import_zod10.z.array(AutomationEnrollment)
|
|
3033
3264
|
});
|
|
3034
|
-
var AutomationRunStatus =
|
|
3035
|
-
var AutomationRun =
|
|
3265
|
+
var AutomationRunStatus = import_zod10.z.enum(["active", "waiting", "completed", "exited", "failed"]);
|
|
3266
|
+
var AutomationRun = import_zod10.z.object({
|
|
3036
3267
|
id: Id,
|
|
3037
3268
|
automation_id: Id,
|
|
3038
3269
|
contact_id: Id,
|
|
3039
3270
|
email: Email,
|
|
3040
|
-
external_id:
|
|
3041
|
-
version:
|
|
3271
|
+
external_id: import_zod10.z.string().nullable(),
|
|
3272
|
+
version: import_zod10.z.number().int().min(1),
|
|
3042
3273
|
status: AutomationRunStatus,
|
|
3043
3274
|
current_step_id: StepId.nullable(),
|
|
3044
3275
|
next_action_at: Timestamp.nullable(),
|
|
3045
3276
|
wait_reason: AutomationWaitReason.nullable(),
|
|
3046
|
-
end_reason:
|
|
3277
|
+
end_reason: import_zod10.z.string().nullable(),
|
|
3047
3278
|
/** What went wrong the last time this run tried to take its step, null otherwise. */
|
|
3048
|
-
last_error:
|
|
3279
|
+
last_error: import_zod10.z.string().nullable(),
|
|
3049
3280
|
entered_at: Timestamp,
|
|
3050
3281
|
ended_at: Timestamp.nullable()
|
|
3051
3282
|
});
|
|
@@ -3055,13 +3286,13 @@ var AutomationRunListQuery = PageQuery.extend({
|
|
|
3055
3286
|
contact_id: Id.optional()
|
|
3056
3287
|
});
|
|
3057
3288
|
var ContactAutomationRun = AutomationRun.extend({
|
|
3058
|
-
automation:
|
|
3289
|
+
automation: import_zod10.z.object({ id: Id, name: import_zod10.z.string(), status: AutomationStatus })
|
|
3059
3290
|
});
|
|
3060
3291
|
var ContactAutomationListQuery = PageQuery.extend({ status: AutomationRunStatus.optional() });
|
|
3061
|
-
var AutomationStepExecution =
|
|
3292
|
+
var AutomationStepExecution = import_zod10.z.object({
|
|
3062
3293
|
step_id: StepId,
|
|
3063
3294
|
step_kind: AutomationStepKind,
|
|
3064
|
-
visit:
|
|
3295
|
+
visit: import_zod10.z.number().int().min(1),
|
|
3065
3296
|
started_at: Timestamp,
|
|
3066
3297
|
finished_at: Timestamp.nullable(),
|
|
3067
3298
|
/**
|
|
@@ -3073,48 +3304,48 @@ var AutomationStepExecution = import_zod9.z.object({
|
|
|
3073
3304
|
*/
|
|
3074
3305
|
outcome: Properties
|
|
3075
3306
|
});
|
|
3076
|
-
var AutomationJourney =
|
|
3307
|
+
var AutomationJourney = import_zod10.z.object({
|
|
3077
3308
|
run: AutomationRun,
|
|
3078
|
-
steps:
|
|
3309
|
+
steps: import_zod10.z.array(AutomationStepExecution)
|
|
3079
3310
|
});
|
|
3080
|
-
var AutomationStepReport =
|
|
3311
|
+
var AutomationStepReport = import_zod10.z.object({
|
|
3081
3312
|
step_id: StepId,
|
|
3082
3313
|
step_kind: AutomationStepKind,
|
|
3083
|
-
reached:
|
|
3084
|
-
waiting:
|
|
3085
|
-
passed:
|
|
3314
|
+
reached: import_zod10.z.number().int().min(0),
|
|
3315
|
+
waiting: import_zod10.z.number().int().min(0),
|
|
3316
|
+
passed: import_zod10.z.number().int().min(0),
|
|
3086
3317
|
/** Per branch, for a condition: how many took `yes` and how many `no`. */
|
|
3087
|
-
branches:
|
|
3318
|
+
branches: import_zod10.z.record(import_zod10.z.number().int().min(0)),
|
|
3088
3319
|
/** The step mailing's id, for an email step of the published version. */
|
|
3089
3320
|
mailing_id: Id.nullable()
|
|
3090
3321
|
});
|
|
3091
|
-
var AutomationReport =
|
|
3322
|
+
var AutomationReport = import_zod10.z.object({
|
|
3092
3323
|
counts: AutomationCounts,
|
|
3093
3324
|
/** Why the people who left did: `AutomationEndReason` to a count. */
|
|
3094
|
-
end_reasons:
|
|
3325
|
+
end_reasons: import_zod10.z.record(import_zod10.z.number().int().min(0)),
|
|
3095
3326
|
/**
|
|
3096
3327
|
* Why people a trigger named did not enter: `AutomationEntryRefusal` to a
|
|
3097
3328
|
* count. Without it a pause, an exclusion or a missing subscription would
|
|
3098
3329
|
* turn people away invisibly.
|
|
3099
3330
|
*/
|
|
3100
|
-
refusals:
|
|
3101
|
-
steps:
|
|
3102
|
-
});
|
|
3103
|
-
var AutomationExitRunRequest =
|
|
3104
|
-
var AutomationRunParams =
|
|
3105
|
-
var AutomationStepParams =
|
|
3106
|
-
var AutomationTestEmailRequest =
|
|
3107
|
-
var AutomationValidateRequest =
|
|
3108
|
-
var EventCreate =
|
|
3331
|
+
refusals: import_zod10.z.record(import_zod10.z.number().int().min(0)),
|
|
3332
|
+
steps: import_zod10.z.array(AutomationStepReport)
|
|
3333
|
+
});
|
|
3334
|
+
var AutomationExitRunRequest = import_zod10.z.object({ reason: import_zod10.z.string().max(200).optional() }).strict();
|
|
3335
|
+
var AutomationRunParams = import_zod10.z.object({ id: Id, run_id: Id });
|
|
3336
|
+
var AutomationStepParams = import_zod10.z.object({ id: Id, step_id: StepId });
|
|
3337
|
+
var AutomationTestEmailRequest = import_zod10.z.object({ to: Email, merge: Properties.optional(), locale: LocaleTag.optional() }).strict();
|
|
3338
|
+
var AutomationValidateRequest = import_zod10.z.object({ flow: AutomationFlow.optional(), settings: AutomationSettings.partial().optional() }).strict();
|
|
3339
|
+
var EventCreate = import_zod10.z.object({
|
|
3109
3340
|
name: EventName,
|
|
3110
|
-
contact:
|
|
3341
|
+
contact: import_zod10.z.object({ external_id: import_zod10.z.string().min(1).max(255).optional(), email: Email.optional(), id: Id.optional() }).refine((c) => [c.external_id, c.email, c.id].filter((x) => x !== void 0).length === 1, "name the contact exactly one way"),
|
|
3111
3342
|
data: Properties.optional(),
|
|
3112
3343
|
occurred_at: Timestamp.optional(),
|
|
3113
|
-
id:
|
|
3344
|
+
id: import_zod10.z.string().min(1).max(128).optional()
|
|
3114
3345
|
}).strict();
|
|
3115
|
-
var Event =
|
|
3346
|
+
var Event = import_zod10.z.object({
|
|
3116
3347
|
id: Id,
|
|
3117
|
-
client_event_id:
|
|
3348
|
+
client_event_id: import_zod10.z.string().nullable(),
|
|
3118
3349
|
name: EventName,
|
|
3119
3350
|
contact_id: Id,
|
|
3120
3351
|
data: Properties,
|
|
@@ -3125,7 +3356,7 @@ var Event = import_zod9.z.object({
|
|
|
3125
3356
|
* hand. Each is then admitted or refused by the runtime on its own rules
|
|
3126
3357
|
* (consent, exclusions, re-entry), which `automations.report` counts.
|
|
3127
3358
|
*/
|
|
3128
|
-
entered:
|
|
3359
|
+
entered: import_zod10.z.number().int().min(0)
|
|
3129
3360
|
});
|
|
3130
3361
|
var EventListQuery = PageQuery.extend({
|
|
3131
3362
|
name: EventName.optional(),
|
|
@@ -3133,19 +3364,15 @@ var EventListQuery = PageQuery.extend({
|
|
|
3133
3364
|
});
|
|
3134
3365
|
|
|
3135
3366
|
// src/workspace.ts
|
|
3136
|
-
var CompanyId =
|
|
3367
|
+
var CompanyId = import_zod11.z.string().min(1).max(64);
|
|
3137
3368
|
var ASSET_POLICIES = ["any", "service_only"];
|
|
3138
|
-
var AssetPolicy =
|
|
3369
|
+
var AssetPolicy = import_zod11.z.enum(ASSET_POLICIES);
|
|
3139
3370
|
var MAX_ALLOWED_ASSET_HOSTS = 20;
|
|
3140
|
-
var AssetHost =
|
|
3141
|
-
var
|
|
3142
|
-
var MAX_MERGE_DEFAULT_LENGTH = 2e3;
|
|
3143
|
-
var MergeFieldName = import_zod10.z.string().regex(/^[a-z][a-z0-9_]*$/, "a merge-field name: lowercase letters, digits and underscores, starting with a letter").max(64);
|
|
3144
|
-
var MergeDefaultValue = import_zod10.z.union([import_zod10.z.string().max(MAX_MERGE_DEFAULT_LENGTH), import_zod10.z.number().finite(), import_zod10.z.boolean()]);
|
|
3145
|
-
var MergeDefaults = import_zod10.z.record(MergeFieldName, MergeDefaultValue).refine((m) => Object.keys(m).length <= MAX_MERGE_DEFAULTS, `at most ${MAX_MERGE_DEFAULTS} merge defaults`).refine((m) => !Object.keys(m).some((k) => k in RESERVED_MERGE_FIELDS), {
|
|
3371
|
+
var AssetHost = import_zod11.z.string().trim().toLowerCase().min(1).max(253).regex(/^(?=.{1,253}(?::\d{1,5})?$)[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?(\.[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)+(:\d{1,5})?$/, "a host name such as example.com");
|
|
3372
|
+
var MergeDefaults = import_zod11.z.record(MergeFieldName, MergeDefaultValue).refine((m) => Object.keys(m).length <= MAX_MERGE_DEFAULTS, `at most ${MAX_MERGE_DEFAULTS} merge defaults`).refine((m) => !Object.keys(m).some((k) => k in RESERVED_MERGE_FIELDS), {
|
|
3146
3373
|
message: `a reserved merge field (${Object.keys(RESERVED_MERGE_FIELDS).join(", ")}) cannot have a workspace default`
|
|
3147
3374
|
});
|
|
3148
|
-
var WorkspaceSettings =
|
|
3375
|
+
var WorkspaceSettings = import_zod11.z.object({
|
|
3149
3376
|
/**
|
|
3150
3377
|
* The workspace's main language (a {@link LocaleTag}, e.g. "de"): the main
|
|
3151
3378
|
* language of a new template, and of the hosted pages when nothing else
|
|
@@ -3158,9 +3385,9 @@ var WorkspaceSettings = import_zod10.z.object({
|
|
|
3158
3385
|
* each; the hosted pages are offered in those of them they support (English,
|
|
3159
3386
|
* German, French, Italian, Spanish). The service stores canonical casing.
|
|
3160
3387
|
*/
|
|
3161
|
-
locales:
|
|
3388
|
+
locales: import_zod11.z.array(LocaleTag).min(1).max(20).refine((l) => new Set(l.map((t) => t.toLowerCase())).size === l.length, "a language appears twice"),
|
|
3162
3389
|
/** Open and click tracking. Off by default, opt-in per workspace. */
|
|
3163
|
-
tracking_enabled:
|
|
3390
|
+
tracking_enabled: import_zod11.z.boolean(),
|
|
3164
3391
|
/** Where images, stylesheets and fonts in a mail may load from. `any` by default. */
|
|
3165
3392
|
asset_policy: AssetPolicy,
|
|
3166
3393
|
/**
|
|
@@ -3168,7 +3395,7 @@ var WorkspaceSettings = import_zod10.z.object({
|
|
|
3168
3395
|
* the workspace's website, typically. Empty by default. Ignored under `any`,
|
|
3169
3396
|
* which allows everything already.
|
|
3170
3397
|
*/
|
|
3171
|
-
allowed_asset_hosts:
|
|
3398
|
+
allowed_asset_hosts: import_zod11.z.array(AssetHost).max(MAX_ALLOWED_ASSET_HOSTS),
|
|
3172
3399
|
/** Merge values every mail of the workspace can use (see `MergeDefaults`). Empty by default. */
|
|
3173
3400
|
merge_defaults: MergeDefaults,
|
|
3174
3401
|
/**
|
|
@@ -3177,10 +3404,10 @@ var WorkspaceSettings = import_zod10.z.object({
|
|
|
3177
3404
|
*/
|
|
3178
3405
|
default_timezone: TimezoneName.nullable()
|
|
3179
3406
|
});
|
|
3180
|
-
var Workspace =
|
|
3407
|
+
var Workspace = import_zod11.z.object({
|
|
3181
3408
|
id: Id,
|
|
3182
3409
|
slug: Slug,
|
|
3183
|
-
name:
|
|
3410
|
+
name: import_zod11.z.string().min(1).max(120),
|
|
3184
3411
|
settings: WorkspaceSettings,
|
|
3185
3412
|
/**
|
|
3186
3413
|
* The auth-brain company (tenant) the workspace was created for, or null for
|
|
@@ -3191,13 +3418,13 @@ var Workspace = import_zod10.z.object({
|
|
|
3191
3418
|
created_at: Timestamp,
|
|
3192
3419
|
updated_at: Timestamp
|
|
3193
3420
|
});
|
|
3194
|
-
var WorkspaceCreate =
|
|
3421
|
+
var WorkspaceCreate = import_zod11.z.object({
|
|
3195
3422
|
slug: Slug,
|
|
3196
|
-
name:
|
|
3423
|
+
name: import_zod11.z.string().min(1).max(120),
|
|
3197
3424
|
settings: WorkspaceSettings.partial().optional(),
|
|
3198
|
-
owner:
|
|
3425
|
+
owner: import_zod11.z.object({
|
|
3199
3426
|
email: Email,
|
|
3200
|
-
name:
|
|
3427
|
+
name: import_zod11.z.string().max(200).nullable().optional()
|
|
3201
3428
|
}),
|
|
3202
3429
|
/**
|
|
3203
3430
|
* The signed-in person's active auth-brain company. The dashboard always
|
|
@@ -3207,49 +3434,49 @@ var WorkspaceCreate = import_zod10.z.object({
|
|
|
3207
3434
|
*/
|
|
3208
3435
|
company_id: CompanyId.optional()
|
|
3209
3436
|
});
|
|
3210
|
-
var WorkspaceUpdate =
|
|
3211
|
-
name:
|
|
3437
|
+
var WorkspaceUpdate = import_zod11.z.object({
|
|
3438
|
+
name: import_zod11.z.string().min(1).max(120),
|
|
3212
3439
|
settings: WorkspaceSettings.partial()
|
|
3213
3440
|
}).partial().refine((v) => Object.keys(v).length > 0, "at least one field");
|
|
3214
|
-
var WorkspaceMove =
|
|
3441
|
+
var WorkspaceMove = import_zod11.z.object({ company_id: CompanyId });
|
|
3215
3442
|
var MEMBER_ROLES = ["owner", "admin", "editor", "viewer"];
|
|
3216
|
-
var MemberRole =
|
|
3443
|
+
var MemberRole = import_zod11.z.enum(MEMBER_ROLES);
|
|
3217
3444
|
var WorkspaceMembership = Workspace.extend({ role: MemberRole });
|
|
3218
|
-
var Member =
|
|
3445
|
+
var Member = import_zod11.z.object({
|
|
3219
3446
|
id: Id,
|
|
3220
3447
|
/** The person's auth-brain subject. */
|
|
3221
|
-
subject:
|
|
3448
|
+
subject: import_zod11.z.string().min(1).max(255),
|
|
3222
3449
|
email: Email,
|
|
3223
|
-
name:
|
|
3450
|
+
name: import_zod11.z.string().max(200).nullable(),
|
|
3224
3451
|
role: MemberRole,
|
|
3225
3452
|
created_at: Timestamp
|
|
3226
3453
|
});
|
|
3227
|
-
var MemberCreate =
|
|
3228
|
-
subject:
|
|
3454
|
+
var MemberCreate = import_zod11.z.object({
|
|
3455
|
+
subject: import_zod11.z.string().min(1).max(255),
|
|
3229
3456
|
email: Email,
|
|
3230
|
-
name:
|
|
3457
|
+
name: import_zod11.z.string().max(200).nullable().optional(),
|
|
3231
3458
|
role: MemberRole
|
|
3232
3459
|
});
|
|
3233
|
-
var MemberUpdate =
|
|
3460
|
+
var MemberUpdate = import_zod11.z.object({ role: MemberRole });
|
|
3234
3461
|
var API_KEY_SCOPES = ["full", "read", "send"];
|
|
3235
|
-
var ApiKeyScope =
|
|
3236
|
-
var ApiKey =
|
|
3462
|
+
var ApiKeyScope = import_zod11.z.enum(API_KEY_SCOPES);
|
|
3463
|
+
var ApiKey = import_zod11.z.object({
|
|
3237
3464
|
id: Id,
|
|
3238
|
-
name:
|
|
3465
|
+
name: import_zod11.z.string().min(1).max(120),
|
|
3239
3466
|
/** The first characters of the key, for recognising it in a list. */
|
|
3240
|
-
prefix:
|
|
3467
|
+
prefix: import_zod11.z.string().min(4).max(32),
|
|
3241
3468
|
scope: ApiKeyScope,
|
|
3242
3469
|
last_used_at: Timestamp.nullable(),
|
|
3243
3470
|
revoked_at: Timestamp.nullable(),
|
|
3244
3471
|
created_at: Timestamp
|
|
3245
3472
|
});
|
|
3246
|
-
var ApiKeyCreate =
|
|
3247
|
-
name:
|
|
3473
|
+
var ApiKeyCreate = import_zod11.z.object({
|
|
3474
|
+
name: import_zod11.z.string().min(1).max(120),
|
|
3248
3475
|
/** Omitted means `full`. */
|
|
3249
3476
|
scope: ApiKeyScope.optional()
|
|
3250
3477
|
});
|
|
3251
|
-
var ApiKeyCreated =
|
|
3252
|
-
key:
|
|
3478
|
+
var ApiKeyCreated = import_zod11.z.object({
|
|
3479
|
+
key: import_zod11.z.string().min(20),
|
|
3253
3480
|
api_key: ApiKey
|
|
3254
3481
|
});
|
|
3255
3482
|
var AUDIT_ACTIONS = [
|
|
@@ -3338,29 +3565,41 @@ var AUDIT_ACTIONS = [
|
|
|
3338
3565
|
"automation.run_ended",
|
|
3339
3566
|
"event.recorded"
|
|
3340
3567
|
];
|
|
3341
|
-
var AuditAction =
|
|
3342
|
-
var
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3568
|
+
var AuditAction = import_zod11.z.enum(AUDIT_ACTIONS);
|
|
3569
|
+
var TRUSTED_APPS = ["booking"];
|
|
3570
|
+
var TrustedApp = import_zod11.z.enum(TRUSTED_APPS);
|
|
3571
|
+
var AuditActor = import_zod11.z.discriminatedUnion("type", [
|
|
3572
|
+
import_zod11.z.object({
|
|
3573
|
+
type: import_zod11.z.literal("member"),
|
|
3574
|
+
member_id: Id,
|
|
3575
|
+
subject: import_zod11.z.string().min(1),
|
|
3576
|
+
/**
|
|
3577
|
+
* The application the person acted through, when it was not the dashboard:
|
|
3578
|
+
* the service set it from the service token the call carried, so it is
|
|
3579
|
+
* verified, unlike a key's `on_behalf_of`. Absent for the dashboard.
|
|
3580
|
+
*/
|
|
3581
|
+
app: TrustedApp.optional()
|
|
3582
|
+
}),
|
|
3583
|
+
import_zod11.z.object({
|
|
3584
|
+
type: import_zod11.z.literal("api_key"),
|
|
3346
3585
|
api_key_id: Id,
|
|
3347
3586
|
/**
|
|
3348
3587
|
* Who the client's application said it was acting for, from
|
|
3349
3588
|
* `ON_BEHALF_OF_HEADER`: reported by that application, never verified.
|
|
3350
3589
|
* Absent when the call carried no label.
|
|
3351
3590
|
*/
|
|
3352
|
-
on_behalf_of:
|
|
3591
|
+
on_behalf_of: import_zod11.z.string().min(1).max(ON_BEHALF_OF_MAX_LENGTH).optional()
|
|
3353
3592
|
}),
|
|
3354
3593
|
/** The service itself (the worker, a bounce, the hosted unsubscribe page). */
|
|
3355
|
-
|
|
3594
|
+
import_zod11.z.object({ type: import_zod11.z.literal("system"), reason: import_zod11.z.string().min(1).max(200) })
|
|
3356
3595
|
]);
|
|
3357
|
-
var AuditEntry =
|
|
3596
|
+
var AuditEntry = import_zod11.z.object({
|
|
3358
3597
|
id: Id,
|
|
3359
3598
|
action: AuditAction,
|
|
3360
3599
|
actor: AuditActor,
|
|
3361
|
-
target_type:
|
|
3600
|
+
target_type: import_zod11.z.string().min(1).max(64),
|
|
3362
3601
|
target_id: Id.nullable(),
|
|
3363
|
-
details:
|
|
3602
|
+
details: import_zod11.z.record(import_zod11.z.unknown()),
|
|
3364
3603
|
created_at: Timestamp
|
|
3365
3604
|
});
|
|
3366
3605
|
var AuditQuery = PageQuery.extend({
|
|
@@ -3369,12 +3608,12 @@ var AuditQuery = PageQuery.extend({
|
|
|
3369
3608
|
});
|
|
3370
3609
|
|
|
3371
3610
|
// src/invites.ts
|
|
3372
|
-
var
|
|
3611
|
+
var import_zod12 = require("zod");
|
|
3373
3612
|
var INVITE_STATUSES = ["pending", "accepted", "revoked", "expired"];
|
|
3374
|
-
var InviteStatus =
|
|
3613
|
+
var InviteStatus = import_zod12.z.enum(INVITE_STATUSES);
|
|
3375
3614
|
var DEFAULT_INVITE_TTL_DAYS = 7;
|
|
3376
3615
|
var MAX_INVITE_TTL_DAYS = 30;
|
|
3377
|
-
var Invite =
|
|
3616
|
+
var Invite = import_zod12.z.object({
|
|
3378
3617
|
id: Id,
|
|
3379
3618
|
/** Stored lowercased; only a person signed in with this address can accept. */
|
|
3380
3619
|
email: Email,
|
|
@@ -3382,32 +3621,32 @@ var Invite = import_zod11.z.object({
|
|
|
3382
3621
|
/** Derived from the timestamps below, never stored. */
|
|
3383
3622
|
status: InviteStatus,
|
|
3384
3623
|
/** The member who invited, while they are still one (null after they left). */
|
|
3385
|
-
invited_by:
|
|
3624
|
+
invited_by: import_zod12.z.object({ member_id: Id.nullable(), email: Email.nullable() }),
|
|
3386
3625
|
expires_at: Timestamp,
|
|
3387
3626
|
accepted_at: Timestamp.nullable(),
|
|
3388
3627
|
revoked_at: Timestamp.nullable(),
|
|
3389
3628
|
created_at: Timestamp
|
|
3390
3629
|
});
|
|
3391
|
-
var InviteCreate =
|
|
3630
|
+
var InviteCreate = import_zod12.z.object({
|
|
3392
3631
|
email: Email,
|
|
3393
3632
|
role: MemberRole,
|
|
3394
|
-
expires_in_days:
|
|
3633
|
+
expires_in_days: import_zod12.z.number().int().min(1).max(MAX_INVITE_TTL_DAYS).optional()
|
|
3395
3634
|
});
|
|
3396
|
-
var InviteCreated =
|
|
3635
|
+
var InviteCreated = import_zod12.z.object({
|
|
3397
3636
|
invite: Invite,
|
|
3398
|
-
token:
|
|
3637
|
+
token: import_zod12.z.string().min(32).max(128)
|
|
3399
3638
|
});
|
|
3400
3639
|
var InviteListQuery = PageQuery.extend({
|
|
3401
3640
|
status: InviteStatus.optional()
|
|
3402
3641
|
});
|
|
3403
|
-
var InviteAccept =
|
|
3404
|
-
token:
|
|
3642
|
+
var InviteAccept = import_zod12.z.object({
|
|
3643
|
+
token: import_zod12.z.string().min(32).max(128),
|
|
3405
3644
|
email: Email,
|
|
3406
|
-
name:
|
|
3645
|
+
name: import_zod12.z.string().max(200).nullable().optional()
|
|
3407
3646
|
});
|
|
3408
|
-
var InviteAccepted =
|
|
3647
|
+
var InviteAccepted = import_zod12.z.object({
|
|
3409
3648
|
workspace: WorkspaceMembership,
|
|
3410
|
-
already_member:
|
|
3649
|
+
already_member: import_zod12.z.boolean()
|
|
3411
3650
|
});
|
|
3412
3651
|
var INVITE_REFUSAL_REASONS = ["email_mismatch", "inviter_lacks_role", "expired", "revoked", "accepted"];
|
|
3413
3652
|
|
|
@@ -4037,13 +4276,13 @@ function renameInsertionEverywhere(drafts, from, rawTo) {
|
|
|
4037
4276
|
}
|
|
4038
4277
|
|
|
4039
4278
|
// src/providers.ts
|
|
4040
|
-
var
|
|
4279
|
+
var import_zod13 = require("zod");
|
|
4041
4280
|
var PROVIDER_KINDS = ["smtp", "resend"];
|
|
4042
|
-
var ProviderKind =
|
|
4043
|
-
var ProviderPolicy =
|
|
4044
|
-
daily_recipient_budget:
|
|
4045
|
-
min_interval_ms:
|
|
4046
|
-
max_recipients_per_message:
|
|
4281
|
+
var ProviderKind = import_zod13.z.enum(PROVIDER_KINDS);
|
|
4282
|
+
var ProviderPolicy = import_zod13.z.object({
|
|
4283
|
+
daily_recipient_budget: import_zod13.z.number().int().min(1).max(1e7),
|
|
4284
|
+
min_interval_ms: import_zod13.z.number().int().min(0).max(36e5),
|
|
4285
|
+
max_recipients_per_message: import_zod13.z.number().int().min(1).max(1e3)
|
|
4047
4286
|
});
|
|
4048
4287
|
var ICLOUD_SMTP_POLICY = {
|
|
4049
4288
|
daily_recipient_budget: 800,
|
|
@@ -4051,17 +4290,17 @@ var ICLOUD_SMTP_POLICY = {
|
|
|
4051
4290
|
max_recipients_per_message: 1
|
|
4052
4291
|
};
|
|
4053
4292
|
var SMTP_SECURITY = ["tls", "starttls"];
|
|
4054
|
-
var SmtpConfigBase =
|
|
4055
|
-
host:
|
|
4056
|
-
port:
|
|
4293
|
+
var SmtpConfigBase = import_zod13.z.object({
|
|
4294
|
+
host: import_zod13.z.string().min(1).max(255),
|
|
4295
|
+
port: import_zod13.z.number().int().min(1).max(65535),
|
|
4057
4296
|
/** `tls` connects encrypted (465), `starttls` upgrades (587). Never plaintext. */
|
|
4058
|
-
security:
|
|
4059
|
-
username:
|
|
4297
|
+
security: import_zod13.z.enum(SMTP_SECURITY),
|
|
4298
|
+
username: import_zod13.z.string().min(1).max(255)
|
|
4060
4299
|
});
|
|
4061
|
-
var ResendConfigBase =
|
|
4062
|
-
var ProviderRejections =
|
|
4063
|
-
count:
|
|
4064
|
-
last_error:
|
|
4300
|
+
var ResendConfigBase = import_zod13.z.object({});
|
|
4301
|
+
var ProviderRejections = import_zod13.z.object({
|
|
4302
|
+
count: import_zod13.z.number().int().min(0),
|
|
4303
|
+
last_error: import_zod13.z.string().nullable(),
|
|
4065
4304
|
last_at: Timestamp.nullable(),
|
|
4066
4305
|
/**
|
|
4067
4306
|
* The last time the bounce circuit breaker tripped on one of this provider's
|
|
@@ -4071,59 +4310,59 @@ var ProviderRejections = import_zod12.z.object({
|
|
|
4071
4310
|
* run's bounce blocks were undone and the mailing paused. `sample` is the
|
|
4072
4311
|
* reply that tripped it.
|
|
4073
4312
|
*/
|
|
4074
|
-
anomaly:
|
|
4313
|
+
anomaly: import_zod13.z.object({
|
|
4075
4314
|
at: Timestamp,
|
|
4076
4315
|
/** `mailing`: one mailing was paused. `provider`: 5 refusals in a row with the same reply across the provider's sends (test sends and one-recipient mailings included) within 24 hours. */
|
|
4077
|
-
scope:
|
|
4316
|
+
scope: import_zod13.z.enum(["mailing", "provider"]),
|
|
4078
4317
|
/**
|
|
4079
4318
|
* True while the provider-wide breaker is open: no bounce blocks through
|
|
4080
4319
|
* this provider, test sends refused and mailings not started or resumed
|
|
4081
4320
|
* (`provider_anomaly`), until an admin clears it (`providers.clearAnomaly`).
|
|
4082
4321
|
*/
|
|
4083
|
-
blocking:
|
|
4322
|
+
blocking: import_zod13.z.boolean(),
|
|
4084
4323
|
mailing_id: Id.nullable(),
|
|
4085
|
-
reason:
|
|
4086
|
-
sample:
|
|
4324
|
+
reason: import_zod13.z.string(),
|
|
4325
|
+
sample: import_zod13.z.string()
|
|
4087
4326
|
}).nullable()
|
|
4088
4327
|
});
|
|
4089
|
-
var ProviderEvents =
|
|
4090
|
-
status:
|
|
4091
|
-
source:
|
|
4092
|
-
url:
|
|
4093
|
-
error:
|
|
4328
|
+
var ProviderEvents = import_zod13.z.object({
|
|
4329
|
+
status: import_zod13.z.enum(["active", "needs_secret"]),
|
|
4330
|
+
source: import_zod13.z.enum(["automatic", "manual"]).nullable(),
|
|
4331
|
+
url: import_zod13.z.string().url(),
|
|
4332
|
+
error: import_zod13.z.string().nullable(),
|
|
4094
4333
|
/**
|
|
4095
4334
|
* Events that named an email this provider never sent through the service
|
|
4096
4335
|
* (another workspace or system sharing the Resend account): counted, never
|
|
4097
4336
|
* acted on.
|
|
4098
4337
|
*/
|
|
4099
|
-
unmatched:
|
|
4338
|
+
unmatched: import_zod13.z.number().int().min(0)
|
|
4100
4339
|
});
|
|
4101
4340
|
var RESEND_EVENT_TYPES = ["email.bounced", "email.complained", "email.delivery_delayed"];
|
|
4102
|
-
var ResendSigningSecret =
|
|
4103
|
-
var ProviderEventsSecret =
|
|
4341
|
+
var ResendSigningSecret = import_zod13.z.string().max(200).regex(/^whsec_[A-Za-z0-9+/]{16,}={0,2}$/, "must be the signing secret Resend shows, starting with whsec_");
|
|
4342
|
+
var ProviderEventsSecret = import_zod13.z.object({ signing_secret: ResendSigningSecret });
|
|
4104
4343
|
var ProviderFields = {
|
|
4105
|
-
name:
|
|
4106
|
-
from_name:
|
|
4344
|
+
name: import_zod13.z.string().min(1).max(120),
|
|
4345
|
+
from_name: import_zod13.z.string().min(1).max(120),
|
|
4107
4346
|
from_email: Email,
|
|
4108
4347
|
reply_to: Email.nullable(),
|
|
4109
4348
|
policy: ProviderPolicy
|
|
4110
4349
|
};
|
|
4111
|
-
var Provider =
|
|
4112
|
-
|
|
4350
|
+
var Provider = import_zod13.z.discriminatedUnion("kind", [
|
|
4351
|
+
import_zod13.z.object({
|
|
4113
4352
|
id: Id,
|
|
4114
|
-
kind:
|
|
4353
|
+
kind: import_zod13.z.literal("smtp"),
|
|
4115
4354
|
config: SmtpConfigBase,
|
|
4116
|
-
has_secret:
|
|
4355
|
+
has_secret: import_zod13.z.boolean(),
|
|
4117
4356
|
...ProviderFields,
|
|
4118
4357
|
rejections: ProviderRejections,
|
|
4119
4358
|
created_at: Timestamp,
|
|
4120
4359
|
updated_at: Timestamp
|
|
4121
4360
|
}),
|
|
4122
|
-
|
|
4361
|
+
import_zod13.z.object({
|
|
4123
4362
|
id: Id,
|
|
4124
|
-
kind:
|
|
4363
|
+
kind: import_zod13.z.literal("resend"),
|
|
4125
4364
|
config: ResendConfigBase,
|
|
4126
|
-
has_secret:
|
|
4365
|
+
has_secret: import_zod13.z.boolean(),
|
|
4127
4366
|
...ProviderFields,
|
|
4128
4367
|
rejections: ProviderRejections,
|
|
4129
4368
|
events: ProviderEvents,
|
|
@@ -4131,31 +4370,31 @@ var Provider = import_zod12.z.discriminatedUnion("kind", [
|
|
|
4131
4370
|
updated_at: Timestamp
|
|
4132
4371
|
})
|
|
4133
4372
|
]);
|
|
4134
|
-
var ProviderCreate =
|
|
4135
|
-
|
|
4136
|
-
kind:
|
|
4137
|
-
config: SmtpConfigBase.extend({ password:
|
|
4373
|
+
var ProviderCreate = import_zod13.z.discriminatedUnion("kind", [
|
|
4374
|
+
import_zod13.z.object({
|
|
4375
|
+
kind: import_zod13.z.literal("smtp"),
|
|
4376
|
+
config: SmtpConfigBase.extend({ password: import_zod13.z.string().min(1).max(1024) }),
|
|
4138
4377
|
...ProviderFields
|
|
4139
4378
|
}),
|
|
4140
|
-
|
|
4141
|
-
kind:
|
|
4142
|
-
config: ResendConfigBase.extend({ api_key:
|
|
4379
|
+
import_zod13.z.object({
|
|
4380
|
+
kind: import_zod13.z.literal("resend"),
|
|
4381
|
+
config: ResendConfigBase.extend({ api_key: import_zod13.z.string().min(1).max(1024) }),
|
|
4143
4382
|
...ProviderFields
|
|
4144
4383
|
})
|
|
4145
4384
|
]);
|
|
4146
|
-
var ProviderUpdate =
|
|
4147
|
-
|
|
4148
|
-
kind:
|
|
4149
|
-
config: SmtpConfigBase.extend({ password:
|
|
4385
|
+
var ProviderUpdate = import_zod13.z.discriminatedUnion("kind", [
|
|
4386
|
+
import_zod13.z.object({
|
|
4387
|
+
kind: import_zod13.z.literal("smtp"),
|
|
4388
|
+
config: SmtpConfigBase.extend({ password: import_zod13.z.string().min(1).max(1024).optional() }).partial().optional(),
|
|
4150
4389
|
name: ProviderFields.name.optional(),
|
|
4151
4390
|
from_name: ProviderFields.from_name.optional(),
|
|
4152
4391
|
from_email: ProviderFields.from_email.optional(),
|
|
4153
4392
|
reply_to: ProviderFields.reply_to.optional(),
|
|
4154
4393
|
policy: ProviderPolicy.partial().optional()
|
|
4155
4394
|
}),
|
|
4156
|
-
|
|
4157
|
-
kind:
|
|
4158
|
-
config: ResendConfigBase.extend({ api_key:
|
|
4395
|
+
import_zod13.z.object({
|
|
4396
|
+
kind: import_zod13.z.literal("resend"),
|
|
4397
|
+
config: ResendConfigBase.extend({ api_key: import_zod13.z.string().min(1).max(1024).optional() }).optional(),
|
|
4159
4398
|
name: ProviderFields.name.optional(),
|
|
4160
4399
|
from_name: ProviderFields.from_name.optional(),
|
|
4161
4400
|
from_email: ProviderFields.from_email.optional(),
|
|
@@ -4163,48 +4402,48 @@ var ProviderUpdate = import_zod12.z.discriminatedUnion("kind", [
|
|
|
4163
4402
|
policy: ProviderPolicy.partial().optional()
|
|
4164
4403
|
})
|
|
4165
4404
|
]);
|
|
4166
|
-
var ProviderUsage =
|
|
4405
|
+
var ProviderUsage = import_zod13.z.object({
|
|
4167
4406
|
provider_id: Id,
|
|
4168
|
-
recipients_last_24h:
|
|
4169
|
-
remaining_budget:
|
|
4407
|
+
recipients_last_24h: import_zod13.z.number().int().min(0),
|
|
4408
|
+
remaining_budget: import_zod13.z.number().int().min(0),
|
|
4170
4409
|
/** When enough of the rolling window frees up to send again, if exhausted. */
|
|
4171
4410
|
next_capacity_at: Timestamp.nullable()
|
|
4172
4411
|
});
|
|
4173
|
-
var ProviderVerifyResult =
|
|
4174
|
-
ok:
|
|
4175
|
-
error:
|
|
4412
|
+
var ProviderVerifyResult = import_zod13.z.object({
|
|
4413
|
+
ok: import_zod13.z.boolean(),
|
|
4414
|
+
error: import_zod13.z.string().nullable()
|
|
4176
4415
|
});
|
|
4177
4416
|
|
|
4178
4417
|
// src/contacts.ts
|
|
4179
|
-
var
|
|
4180
|
-
var Topic =
|
|
4418
|
+
var import_zod14 = require("zod");
|
|
4419
|
+
var Topic = import_zod14.z.object({
|
|
4181
4420
|
id: Id,
|
|
4182
4421
|
slug: Slug,
|
|
4183
|
-
name:
|
|
4422
|
+
name: import_zod14.z.string().min(1).max(120),
|
|
4184
4423
|
/** Shown on the hosted preference page. */
|
|
4185
|
-
description:
|
|
4424
|
+
description: import_zod14.z.string().max(1e3).nullable(),
|
|
4186
4425
|
/** Translations of `name` and `description` per locale, for the hosted page. */
|
|
4187
|
-
translations:
|
|
4188
|
-
|
|
4426
|
+
translations: import_zod14.z.record(
|
|
4427
|
+
import_zod14.z.object({ name: import_zod14.z.string().min(1).max(120), description: import_zod14.z.string().max(1e3).nullable() })
|
|
4189
4428
|
),
|
|
4190
4429
|
created_at: Timestamp,
|
|
4191
4430
|
updated_at: Timestamp
|
|
4192
4431
|
});
|
|
4193
|
-
var TopicCreate =
|
|
4432
|
+
var TopicCreate = import_zod14.z.object({
|
|
4194
4433
|
slug: Slug,
|
|
4195
|
-
name:
|
|
4196
|
-
description:
|
|
4434
|
+
name: import_zod14.z.string().min(1).max(120),
|
|
4435
|
+
description: import_zod14.z.string().max(1e3).optional(),
|
|
4197
4436
|
translations: Topic.shape.translations.optional()
|
|
4198
4437
|
});
|
|
4199
4438
|
var TopicUpdate = TopicCreate.omit({ slug: true }).partial().refine((v) => Object.keys(v).length > 0, "at least one field");
|
|
4200
|
-
var Contact =
|
|
4439
|
+
var Contact = import_zod14.z.object({
|
|
4201
4440
|
id: Id,
|
|
4202
|
-
external_id:
|
|
4441
|
+
external_id: import_zod14.z.string().min(1).max(255).nullable(),
|
|
4203
4442
|
/** Stored lowercased, unique per workspace. */
|
|
4204
4443
|
email: Email,
|
|
4205
|
-
first_name:
|
|
4206
|
-
last_name:
|
|
4207
|
-
locale:
|
|
4444
|
+
first_name: import_zod14.z.string().max(200).nullable(),
|
|
4445
|
+
last_name: import_zod14.z.string().max(200).nullable(),
|
|
4446
|
+
locale: import_zod14.z.string().min(2).max(35).nullable(),
|
|
4208
4447
|
/**
|
|
4209
4448
|
* The person's own time zone, an IANA name such as `Europe/Berlin` (A1).
|
|
4210
4449
|
* Every wall clock an automation waits for is read in it, falling back to the
|
|
@@ -4212,65 +4451,65 @@ var Contact = import_zod13.z.object({
|
|
|
4212
4451
|
*/
|
|
4213
4452
|
timezone: TimezoneName.nullable(),
|
|
4214
4453
|
properties: Properties,
|
|
4215
|
-
topics:
|
|
4454
|
+
topics: import_zod14.z.array(Slug),
|
|
4216
4455
|
/** The slugs of the contact's tags (S4). */
|
|
4217
|
-
tags:
|
|
4456
|
+
tags: import_zod14.z.array(Slug),
|
|
4218
4457
|
created_at: Timestamp,
|
|
4219
4458
|
updated_at: Timestamp
|
|
4220
4459
|
});
|
|
4221
|
-
var ContactUpsert =
|
|
4222
|
-
external_id:
|
|
4460
|
+
var ContactUpsert = import_zod14.z.object({
|
|
4461
|
+
external_id: import_zod14.z.string().min(1).max(255).optional(),
|
|
4223
4462
|
email: Email.optional(),
|
|
4224
|
-
first_name:
|
|
4225
|
-
last_name:
|
|
4226
|
-
locale:
|
|
4463
|
+
first_name: import_zod14.z.string().max(200).nullable().optional(),
|
|
4464
|
+
last_name: import_zod14.z.string().max(200).nullable().optional(),
|
|
4465
|
+
locale: import_zod14.z.string().min(2).max(35).nullable().optional(),
|
|
4227
4466
|
timezone: TimezoneName.nullable().optional(),
|
|
4228
4467
|
properties: Properties.optional(),
|
|
4229
|
-
topics:
|
|
4468
|
+
topics: import_zod14.z.array(Slug).max(100).optional()
|
|
4230
4469
|
}).refine((v) => v.external_id !== void 0 || v.email !== void 0, {
|
|
4231
4470
|
message: "external_id or email is required",
|
|
4232
4471
|
path: ["email"]
|
|
4233
4472
|
});
|
|
4234
|
-
var ContactUpsertResult =
|
|
4473
|
+
var ContactUpsertResult = import_zod14.z.object({
|
|
4235
4474
|
contact: Contact,
|
|
4236
|
-
created:
|
|
4475
|
+
created: import_zod14.z.boolean()
|
|
4237
4476
|
});
|
|
4238
4477
|
var ContactListQuery = PageQuery.extend({
|
|
4239
|
-
email:
|
|
4240
|
-
external_id:
|
|
4478
|
+
email: import_zod14.z.string().min(1).max(254).optional(),
|
|
4479
|
+
external_id: import_zod14.z.string().min(1).max(255).optional(),
|
|
4241
4480
|
topic: Slug.optional()
|
|
4242
4481
|
});
|
|
4243
|
-
var ContactErased =
|
|
4244
|
-
ok:
|
|
4245
|
-
erased_messages:
|
|
4246
|
-
erased_recipients:
|
|
4247
|
-
suppressions_kept:
|
|
4482
|
+
var ContactErased = import_zod14.z.object({
|
|
4483
|
+
ok: import_zod14.z.literal(true),
|
|
4484
|
+
erased_messages: import_zod14.z.number().int().min(0),
|
|
4485
|
+
erased_recipients: import_zod14.z.number().int().min(0),
|
|
4486
|
+
suppressions_kept: import_zod14.z.number().int().min(0)
|
|
4248
4487
|
});
|
|
4249
4488
|
var SUPPRESSION_REASONS = ["unsubscribed", "bounced", "complained", "manual"];
|
|
4250
|
-
var SuppressionReason =
|
|
4251
|
-
var Suppression =
|
|
4489
|
+
var SuppressionReason = import_zod14.z.enum(SUPPRESSION_REASONS);
|
|
4490
|
+
var Suppression = import_zod14.z.object({
|
|
4252
4491
|
id: Id,
|
|
4253
4492
|
email: Email,
|
|
4254
4493
|
reason: SuppressionReason,
|
|
4255
4494
|
topic: Slug.nullable(),
|
|
4256
4495
|
source_message_id: Id.nullable(),
|
|
4257
|
-
note:
|
|
4496
|
+
note: import_zod14.z.string().max(1e3).nullable(),
|
|
4258
4497
|
created_at: Timestamp
|
|
4259
4498
|
});
|
|
4260
|
-
var SuppressionCreate =
|
|
4499
|
+
var SuppressionCreate = import_zod14.z.object({
|
|
4261
4500
|
email: Email,
|
|
4262
|
-
reason:
|
|
4501
|
+
reason: import_zod14.z.enum(["manual", "unsubscribed"]),
|
|
4263
4502
|
topic: Slug.nullable().optional(),
|
|
4264
|
-
note:
|
|
4503
|
+
note: import_zod14.z.string().max(1e3).optional()
|
|
4265
4504
|
});
|
|
4266
4505
|
var SuppressionListQuery = PageQuery.extend({
|
|
4267
|
-
email:
|
|
4506
|
+
email: import_zod14.z.string().min(1).max(254).optional(),
|
|
4268
4507
|
reason: SuppressionReason.optional(),
|
|
4269
4508
|
topic: Slug.optional()
|
|
4270
4509
|
});
|
|
4271
4510
|
|
|
4272
4511
|
// src/webhooks.ts
|
|
4273
|
-
var
|
|
4512
|
+
var import_zod15 = require("zod");
|
|
4274
4513
|
var WEBHOOK_EVENT_TYPES = [
|
|
4275
4514
|
"message.sent",
|
|
4276
4515
|
"message.failed",
|
|
@@ -4314,23 +4553,23 @@ var WEBHOOK_EVENT_TYPES = [
|
|
|
4314
4553
|
"template.updated",
|
|
4315
4554
|
"template.deleted"
|
|
4316
4555
|
];
|
|
4317
|
-
var WebhookEventType =
|
|
4318
|
-
var MessageEventBase =
|
|
4556
|
+
var WebhookEventType = import_zod15.z.enum(WEBHOOK_EVENT_TYPES);
|
|
4557
|
+
var MessageEventBase = import_zod15.z.object({
|
|
4319
4558
|
message_id: Id,
|
|
4320
4559
|
mailing_id: Id.nullable(),
|
|
4321
4560
|
mailing_metadata: MailingMetadata.nullable(),
|
|
4322
4561
|
recipient_id: Id.nullable(),
|
|
4323
4562
|
contact_id: Id.nullable(),
|
|
4324
|
-
external_id:
|
|
4563
|
+
external_id: import_zod15.z.string().nullable(),
|
|
4325
4564
|
email: Email,
|
|
4326
|
-
subject:
|
|
4565
|
+
subject: import_zod15.z.string(),
|
|
4327
4566
|
topic: Slug.nullable(),
|
|
4328
|
-
provider_message_id:
|
|
4329
|
-
is_test:
|
|
4567
|
+
provider_message_id: import_zod15.z.string().nullable(),
|
|
4568
|
+
is_test: import_zod15.z.boolean()
|
|
4330
4569
|
});
|
|
4331
4570
|
var MessageSentData = MessageEventBase.extend({
|
|
4332
4571
|
/** The final HTML as sent, so the client can archive it beside its own records. */
|
|
4333
|
-
html:
|
|
4572
|
+
html: import_zod15.z.string(),
|
|
4334
4573
|
sent_at: Timestamp,
|
|
4335
4574
|
/**
|
|
4336
4575
|
* The choice each insertion made (see `Message.insertions`); absent or null
|
|
@@ -4341,20 +4580,20 @@ var MessageSentData = MessageEventBase.extend({
|
|
|
4341
4580
|
insertions: InsertionChoices.nullish()
|
|
4342
4581
|
});
|
|
4343
4582
|
var MessageFailedData = MessageEventBase.extend({
|
|
4344
|
-
error:
|
|
4583
|
+
error: import_zod15.z.string(),
|
|
4345
4584
|
/** False when the provider rejected permanently; the recipient will not be retried. */
|
|
4346
|
-
retryable:
|
|
4585
|
+
retryable: import_zod15.z.boolean(),
|
|
4347
4586
|
failed_at: Timestamp
|
|
4348
4587
|
});
|
|
4349
4588
|
var UNSUBSCRIBE_SOURCES = ["hosted_page", "one_click", "api", "dashboard", "signup_form"];
|
|
4350
|
-
var ContactUnsubscribedData =
|
|
4589
|
+
var ContactUnsubscribedData = import_zod15.z.object({
|
|
4351
4590
|
contact_id: Id.nullable(),
|
|
4352
|
-
external_id:
|
|
4591
|
+
external_id: import_zod15.z.string().nullable(),
|
|
4353
4592
|
email: Email,
|
|
4354
4593
|
/** The topic unsubscribed from; null means every topic. */
|
|
4355
4594
|
topic: Slug.nullable(),
|
|
4356
4595
|
mailing_id: Id.nullable(),
|
|
4357
|
-
source:
|
|
4596
|
+
source: import_zod15.z.enum(UNSUBSCRIBE_SOURCES),
|
|
4358
4597
|
unsubscribed_at: Timestamp
|
|
4359
4598
|
});
|
|
4360
4599
|
var ContactResubscribedData = ContactUnsubscribedData.omit({ unsubscribed_at: true }).extend({
|
|
@@ -4363,142 +4602,142 @@ var ContactResubscribedData = ContactUnsubscribedData.omit({ unsubscribed_at: tr
|
|
|
4363
4602
|
* breaker undid a `bounced` block it judged false (a `contact.bounced` for the
|
|
4364
4603
|
* same address and mailing went out before); `topic` is null.
|
|
4365
4604
|
*/
|
|
4366
|
-
source:
|
|
4605
|
+
source: import_zod15.z.enum([...UNSUBSCRIBE_SOURCES, "bounce_reverted"]),
|
|
4367
4606
|
resubscribed_at: Timestamp
|
|
4368
4607
|
});
|
|
4369
|
-
var ContactBouncedData =
|
|
4608
|
+
var ContactBouncedData = import_zod15.z.object({
|
|
4370
4609
|
contact_id: Id.nullable(),
|
|
4371
|
-
external_id:
|
|
4610
|
+
external_id: import_zod15.z.string().nullable(),
|
|
4372
4611
|
email: Email,
|
|
4373
4612
|
/** `bounced` for a hard bounce, `complained` for a spam complaint. */
|
|
4374
|
-
reason:
|
|
4613
|
+
reason: import_zod15.z.enum(["bounced", "complained"]),
|
|
4375
4614
|
message_id: Id.nullable(),
|
|
4376
|
-
diagnostic:
|
|
4615
|
+
diagnostic: import_zod15.z.string().nullable(),
|
|
4377
4616
|
bounced_at: Timestamp
|
|
4378
4617
|
});
|
|
4379
|
-
var MailingFinishedData =
|
|
4618
|
+
var MailingFinishedData = import_zod15.z.object({
|
|
4380
4619
|
mailing_id: Id,
|
|
4381
4620
|
mailing_metadata: MailingMetadata,
|
|
4382
|
-
status:
|
|
4621
|
+
status: import_zod15.z.enum(["sent", "partially_failed", "cancelled"]),
|
|
4383
4622
|
counts: MailingCounts,
|
|
4384
4623
|
finished_at: Timestamp
|
|
4385
4624
|
});
|
|
4386
|
-
var ContactSubscribedData =
|
|
4625
|
+
var ContactSubscribedData = import_zod15.z.object({
|
|
4387
4626
|
contact_id: Id,
|
|
4388
|
-
external_id:
|
|
4627
|
+
external_id: import_zod15.z.string().nullable(),
|
|
4389
4628
|
email: Email,
|
|
4390
|
-
topics:
|
|
4391
|
-
source:
|
|
4629
|
+
topics: import_zod15.z.array(Slug),
|
|
4630
|
+
source: import_zod15.z.enum(["signup_form", "api", "dashboard", "automation"]),
|
|
4392
4631
|
signup_form_id: Id.nullable(),
|
|
4393
|
-
signup_form_version:
|
|
4632
|
+
signup_form_version: import_zod15.z.number().int().min(1).nullable(),
|
|
4394
4633
|
subscribed_at: Timestamp
|
|
4395
4634
|
});
|
|
4396
|
-
var ImportFinishedData =
|
|
4635
|
+
var ImportFinishedData = import_zod15.z.object({
|
|
4397
4636
|
import_id: Id,
|
|
4398
|
-
status:
|
|
4637
|
+
status: import_zod15.z.enum(["completed", "cancelled", "failed"]),
|
|
4399
4638
|
result: ImportReport.nullable(),
|
|
4400
|
-
error:
|
|
4639
|
+
error: import_zod15.z.string().nullable(),
|
|
4401
4640
|
finished_at: Timestamp
|
|
4402
4641
|
});
|
|
4403
|
-
var MailingScheduledData =
|
|
4642
|
+
var MailingScheduledData = import_zod15.z.object({
|
|
4404
4643
|
mailing_id: Id,
|
|
4405
4644
|
mailing_metadata: MailingMetadata,
|
|
4406
4645
|
scheduled_at: Timestamp.nullable()
|
|
4407
4646
|
});
|
|
4408
|
-
var MailingStartedData =
|
|
4647
|
+
var MailingStartedData = import_zod15.z.object({
|
|
4409
4648
|
mailing_id: Id,
|
|
4410
4649
|
mailing_metadata: MailingMetadata,
|
|
4411
|
-
trigger:
|
|
4412
|
-
recipients:
|
|
4650
|
+
trigger: import_zod15.z.enum(["send", "schedule"]),
|
|
4651
|
+
recipients: import_zod15.z.number().int().min(0),
|
|
4413
4652
|
started_at: Timestamp
|
|
4414
4653
|
});
|
|
4415
|
-
var MailingScheduleFailedData =
|
|
4654
|
+
var MailingScheduleFailedData = import_zod15.z.object({
|
|
4416
4655
|
mailing_id: Id,
|
|
4417
4656
|
mailing_metadata: MailingMetadata,
|
|
4418
|
-
code:
|
|
4419
|
-
message:
|
|
4657
|
+
code: import_zod15.z.string(),
|
|
4658
|
+
message: import_zod15.z.string(),
|
|
4420
4659
|
failed_at: Timestamp
|
|
4421
4660
|
});
|
|
4422
|
-
var MailingAbWinnerSelectedData =
|
|
4661
|
+
var MailingAbWinnerSelectedData = import_zod15.z.object({
|
|
4423
4662
|
mailing_id: Id,
|
|
4424
4663
|
mailing_metadata: MailingMetadata,
|
|
4425
|
-
winner:
|
|
4426
|
-
decided_by:
|
|
4427
|
-
variants:
|
|
4664
|
+
winner: import_zod15.z.string(),
|
|
4665
|
+
decided_by: import_zod15.z.enum(["metric", "manual"]),
|
|
4666
|
+
variants: import_zod15.z.array(VariantAnalytics),
|
|
4428
4667
|
decided_at: Timestamp
|
|
4429
4668
|
});
|
|
4430
|
-
var ContactTaggedData =
|
|
4669
|
+
var ContactTaggedData = import_zod15.z.object({
|
|
4431
4670
|
contact_id: Id,
|
|
4432
|
-
external_id:
|
|
4671
|
+
external_id: import_zod15.z.string().nullable(),
|
|
4433
4672
|
email: Email,
|
|
4434
4673
|
/** Only the tags the contact did not already have. */
|
|
4435
|
-
tags:
|
|
4436
|
-
source:
|
|
4674
|
+
tags: import_zod15.z.array(Slug).min(1),
|
|
4675
|
+
source: import_zod15.z.enum(["api", "dashboard", "signup_form", "import", "automation"]),
|
|
4437
4676
|
tagged_at: Timestamp
|
|
4438
4677
|
});
|
|
4439
|
-
var ContactUpdatedData =
|
|
4678
|
+
var ContactUpdatedData = import_zod15.z.object({
|
|
4440
4679
|
contact_id: Id,
|
|
4441
|
-
external_id:
|
|
4680
|
+
external_id: import_zod15.z.string().nullable(),
|
|
4442
4681
|
email: Email,
|
|
4443
|
-
changed:
|
|
4682
|
+
changed: import_zod15.z.array(import_zod15.z.string()).min(1),
|
|
4444
4683
|
properties: Properties,
|
|
4445
|
-
source:
|
|
4684
|
+
source: import_zod15.z.enum(["api", "dashboard", "signup_form", "import", "automation"]),
|
|
4446
4685
|
updated_at: Timestamp
|
|
4447
4686
|
});
|
|
4448
|
-
var AutomationRunEventBase =
|
|
4687
|
+
var AutomationRunEventBase = import_zod15.z.object({
|
|
4449
4688
|
automation_id: Id,
|
|
4450
|
-
automation_name:
|
|
4689
|
+
automation_name: import_zod15.z.string(),
|
|
4451
4690
|
run_id: Id,
|
|
4452
|
-
version:
|
|
4691
|
+
version: import_zod15.z.number().int().min(1),
|
|
4453
4692
|
contact_id: Id,
|
|
4454
|
-
external_id:
|
|
4693
|
+
external_id: import_zod15.z.string().nullable(),
|
|
4455
4694
|
email: Email
|
|
4456
4695
|
});
|
|
4457
4696
|
var AutomationRunStartedData = AutomationRunEventBase.extend({
|
|
4458
4697
|
/** What let them in: a trigger kind, or `manual` for an explicit enrolment. */
|
|
4459
|
-
trigger_kind:
|
|
4698
|
+
trigger_kind: import_zod15.z.string(),
|
|
4460
4699
|
entered_at: Timestamp
|
|
4461
4700
|
});
|
|
4462
4701
|
var AutomationRunCompletedData = AutomationRunEventBase.extend({
|
|
4463
|
-
last_step_id:
|
|
4702
|
+
last_step_id: import_zod15.z.string().nullable(),
|
|
4464
4703
|
completed_at: Timestamp
|
|
4465
4704
|
});
|
|
4466
4705
|
var AutomationRunExitedData = AutomationRunEventBase.extend({
|
|
4467
4706
|
reason: AutomationEndReason,
|
|
4468
|
-
step_id:
|
|
4707
|
+
step_id: import_zod15.z.string().nullable(),
|
|
4469
4708
|
exited_at: Timestamp
|
|
4470
4709
|
});
|
|
4471
4710
|
var AutomationRunFailedData = AutomationRunEventBase.extend({
|
|
4472
|
-
reason:
|
|
4473
|
-
step_id:
|
|
4711
|
+
reason: import_zod15.z.string(),
|
|
4712
|
+
step_id: import_zod15.z.string().nullable(),
|
|
4474
4713
|
failed_at: Timestamp
|
|
4475
4714
|
});
|
|
4476
4715
|
var AutomationWebhookData = AutomationRunEventBase.extend({
|
|
4477
|
-
step_id:
|
|
4716
|
+
step_id: import_zod15.z.string(),
|
|
4478
4717
|
/** The step's own label, when it was given one, so a receiver can branch on a name. */
|
|
4479
|
-
step_label:
|
|
4718
|
+
step_label: import_zod15.z.string().nullable(),
|
|
4480
4719
|
/** Whatever the step carries, verbatim. Null when it carries nothing. */
|
|
4481
4720
|
payload: JsonValue.nullable(),
|
|
4482
4721
|
fired_at: Timestamp
|
|
4483
4722
|
});
|
|
4484
|
-
var TemplateEventBase =
|
|
4723
|
+
var TemplateEventBase = import_zod15.z.object({
|
|
4485
4724
|
template_id: Id,
|
|
4486
|
-
name:
|
|
4487
|
-
version:
|
|
4488
|
-
source:
|
|
4725
|
+
name: import_zod15.z.string().min(1).max(200),
|
|
4726
|
+
version: import_zod15.z.number().int().min(1),
|
|
4727
|
+
source: import_zod15.z.enum(["api", "dashboard", "mjml_import"])
|
|
4489
4728
|
});
|
|
4490
4729
|
var TemplateCreatedData = TemplateEventBase.extend({ created_at: Timestamp });
|
|
4491
|
-
var TemplateUpdatedData = TemplateEventBase.extend({ archived:
|
|
4730
|
+
var TemplateUpdatedData = TemplateEventBase.extend({ archived: import_zod15.z.boolean(), updated_at: Timestamp });
|
|
4492
4731
|
var TemplateDeletedData = TemplateEventBase.extend({ deleted_at: Timestamp });
|
|
4493
|
-
var envelope = (type, data) =>
|
|
4732
|
+
var envelope = (type, data) => import_zod15.z.object({
|
|
4494
4733
|
/** Unique per event: a receiver deduplicates on it (deliveries may repeat). */
|
|
4495
4734
|
id: Id,
|
|
4496
|
-
type:
|
|
4735
|
+
type: import_zod15.z.literal(type),
|
|
4497
4736
|
created_at: Timestamp,
|
|
4498
4737
|
workspace_id: Id,
|
|
4499
4738
|
data
|
|
4500
4739
|
});
|
|
4501
|
-
var WebhookEvent =
|
|
4740
|
+
var WebhookEvent = import_zod15.z.discriminatedUnion("type", [
|
|
4502
4741
|
envelope("message.sent", MessageSentData),
|
|
4503
4742
|
envelope("message.failed", MessageFailedData),
|
|
4504
4743
|
envelope("contact.unsubscribed", ContactUnsubscribedData),
|
|
@@ -4522,16 +4761,16 @@ var WebhookEvent = import_zod14.z.discriminatedUnion("type", [
|
|
|
4522
4761
|
envelope("template.updated", TemplateUpdatedData),
|
|
4523
4762
|
envelope("template.deleted", TemplateDeletedData)
|
|
4524
4763
|
]);
|
|
4525
|
-
var WebhookEndpoint =
|
|
4764
|
+
var WebhookEndpoint = import_zod15.z.object({
|
|
4526
4765
|
id: Id,
|
|
4527
|
-
url:
|
|
4528
|
-
description:
|
|
4529
|
-
events:
|
|
4530
|
-
enabled:
|
|
4766
|
+
url: import_zod15.z.string().url(),
|
|
4767
|
+
description: import_zod15.z.string().max(500).nullable(),
|
|
4768
|
+
events: import_zod15.z.array(WebhookEventType).min(1),
|
|
4769
|
+
enabled: import_zod15.z.boolean(),
|
|
4531
4770
|
created_at: Timestamp,
|
|
4532
4771
|
updated_at: Timestamp
|
|
4533
4772
|
});
|
|
4534
|
-
var WebhookUrl =
|
|
4773
|
+
var WebhookUrl = import_zod15.z.string().url().refine((u) => {
|
|
4535
4774
|
try {
|
|
4536
4775
|
const url = new URL(u);
|
|
4537
4776
|
if (url.protocol === "https:") return true;
|
|
@@ -4540,35 +4779,35 @@ var WebhookUrl = import_zod14.z.string().url().refine((u) => {
|
|
|
4540
4779
|
return false;
|
|
4541
4780
|
}
|
|
4542
4781
|
}, "must be https (http only for localhost)");
|
|
4543
|
-
var WebhookEndpointCreate =
|
|
4782
|
+
var WebhookEndpointCreate = import_zod15.z.object({
|
|
4544
4783
|
url: WebhookUrl,
|
|
4545
|
-
description:
|
|
4546
|
-
events:
|
|
4547
|
-
enabled:
|
|
4784
|
+
description: import_zod15.z.string().max(500).optional(),
|
|
4785
|
+
events: import_zod15.z.array(WebhookEventType).min(1),
|
|
4786
|
+
enabled: import_zod15.z.boolean().optional()
|
|
4548
4787
|
});
|
|
4549
|
-
var WebhookEndpointUpdate =
|
|
4788
|
+
var WebhookEndpointUpdate = import_zod15.z.object({
|
|
4550
4789
|
url: WebhookUrl,
|
|
4551
|
-
description:
|
|
4552
|
-
events:
|
|
4553
|
-
enabled:
|
|
4790
|
+
description: import_zod15.z.string().max(500).nullable(),
|
|
4791
|
+
events: import_zod15.z.array(WebhookEventType).min(1),
|
|
4792
|
+
enabled: import_zod15.z.boolean()
|
|
4554
4793
|
}).partial().refine((v) => Object.keys(v).length > 0, "at least one field");
|
|
4555
|
-
var WebhookEndpointWithSecret =
|
|
4794
|
+
var WebhookEndpointWithSecret = import_zod15.z.object({
|
|
4556
4795
|
endpoint: WebhookEndpoint,
|
|
4557
|
-
secret:
|
|
4796
|
+
secret: import_zod15.z.string().min(32)
|
|
4558
4797
|
});
|
|
4559
4798
|
var WEBHOOK_DELIVERY_STATUSES = ["pending", "succeeded", "failed"];
|
|
4560
|
-
var WebhookDeliveryStatus =
|
|
4799
|
+
var WebhookDeliveryStatus = import_zod15.z.enum(WEBHOOK_DELIVERY_STATUSES);
|
|
4561
4800
|
var WEBHOOK_MAX_ATTEMPTS = 8;
|
|
4562
4801
|
var WEBHOOK_RETRY_DELAYS_SECONDS = [30, 120, 600, 1800, 3600, 7200, 21600];
|
|
4563
|
-
var WebhookDelivery =
|
|
4802
|
+
var WebhookDelivery = import_zod15.z.object({
|
|
4564
4803
|
id: Id,
|
|
4565
4804
|
endpoint_id: Id,
|
|
4566
4805
|
event_id: Id,
|
|
4567
4806
|
event_type: WebhookEventType,
|
|
4568
4807
|
status: WebhookDeliveryStatus,
|
|
4569
|
-
attempts:
|
|
4570
|
-
last_status_code:
|
|
4571
|
-
last_error:
|
|
4808
|
+
attempts: import_zod15.z.number().int().min(0),
|
|
4809
|
+
last_status_code: import_zod15.z.number().int().min(100).max(599).nullable(),
|
|
4810
|
+
last_error: import_zod15.z.string().nullable(),
|
|
4572
4811
|
next_attempt_at: Timestamp.nullable(),
|
|
4573
4812
|
delivered_at: Timestamp.nullable(),
|
|
4574
4813
|
created_at: Timestamp
|
|
@@ -4577,7 +4816,7 @@ var WebhookDeliveryListQuery = PageQuery.extend({
|
|
|
4577
4816
|
status: WebhookDeliveryStatus.optional(),
|
|
4578
4817
|
event_type: WebhookEventType.optional()
|
|
4579
4818
|
});
|
|
4580
|
-
var WebhookDeliveryParams =
|
|
4819
|
+
var WebhookDeliveryParams = import_zod15.z.object({ id: Id, delivery_id: Id });
|
|
4581
4820
|
|
|
4582
4821
|
// src/webhook-signing.ts
|
|
4583
4822
|
var WEBHOOK_SIGNATURE_HEADER = "x-mail-signature";
|
|
@@ -4644,79 +4883,79 @@ async function verifyWebhook(input) {
|
|
|
4644
4883
|
}
|
|
4645
4884
|
|
|
4646
4885
|
// src/billing.ts
|
|
4647
|
-
var
|
|
4886
|
+
var import_zod16 = require("zod");
|
|
4648
4887
|
var PLAN_IDS = ["free", "starter", "growth", "design_partner"];
|
|
4649
|
-
var PlanId =
|
|
4650
|
-
var PlanLimits =
|
|
4651
|
-
monthly_messages:
|
|
4652
|
-
contacts:
|
|
4653
|
-
members:
|
|
4654
|
-
providers:
|
|
4655
|
-
webhook_endpoints:
|
|
4888
|
+
var PlanId = import_zod16.z.enum(PLAN_IDS);
|
|
4889
|
+
var PlanLimits = import_zod16.z.object({
|
|
4890
|
+
monthly_messages: import_zod16.z.number().int().min(0).nullable(),
|
|
4891
|
+
contacts: import_zod16.z.number().int().min(0).nullable(),
|
|
4892
|
+
members: import_zod16.z.number().int().min(1).nullable(),
|
|
4893
|
+
providers: import_zod16.z.number().int().min(1).nullable(),
|
|
4894
|
+
webhook_endpoints: import_zod16.z.number().int().min(0).nullable(),
|
|
4656
4895
|
/** Automations that may be live (active or paused) at once (A1). */
|
|
4657
|
-
active_automations:
|
|
4896
|
+
active_automations: import_zod16.z.number().int().min(0).nullable(),
|
|
4658
4897
|
/** Steps one automation may hold. Null is the flow's own cap, not unlimited. */
|
|
4659
|
-
automation_steps:
|
|
4898
|
+
automation_steps: import_zod16.z.number().int().min(1).nullable()
|
|
4660
4899
|
});
|
|
4661
|
-
var PlanFeatures =
|
|
4900
|
+
var PlanFeatures = import_zod16.z.object({
|
|
4662
4901
|
/** A/B tests of subject and content on a mailing (S4). */
|
|
4663
|
-
ab_testing:
|
|
4902
|
+
ab_testing: import_zod16.z.boolean(),
|
|
4664
4903
|
/** Open and click tracking, still off until a workspace turns it on (`settings.tracking_enabled`). */
|
|
4665
|
-
tracking:
|
|
4904
|
+
tracking: import_zod16.z.boolean(),
|
|
4666
4905
|
/** Sending and hosting pages on the workspace's own domain (a later phase). */
|
|
4667
|
-
custom_domains:
|
|
4906
|
+
custom_domains: import_zod16.z.boolean(),
|
|
4668
4907
|
/** Automations: flows a person walks through step by step (A1). */
|
|
4669
|
-
automations:
|
|
4908
|
+
automations: import_zod16.z.boolean()
|
|
4670
4909
|
});
|
|
4671
4910
|
var PLAN_FEATURES = ["ab_testing", "tracking", "custom_domains", "automations"];
|
|
4672
|
-
var Plan =
|
|
4911
|
+
var Plan = import_zod16.z.object({
|
|
4673
4912
|
id: PlanId,
|
|
4674
|
-
name:
|
|
4913
|
+
name: import_zod16.z.string().min(1),
|
|
4675
4914
|
/** Price in the smallest currency unit per month; null for plans not sold. */
|
|
4676
|
-
monthly_price_cents:
|
|
4677
|
-
currency:
|
|
4915
|
+
monthly_price_cents: import_zod16.z.number().int().min(0).nullable(),
|
|
4916
|
+
currency: import_zod16.z.string().length(3),
|
|
4678
4917
|
limits: PlanLimits,
|
|
4679
4918
|
features: PlanFeatures
|
|
4680
4919
|
});
|
|
4681
|
-
var CatalogPlan = Plan.extend({ sellable:
|
|
4682
|
-
var Subscription =
|
|
4920
|
+
var CatalogPlan = Plan.extend({ sellable: import_zod16.z.boolean() });
|
|
4921
|
+
var Subscription = import_zod16.z.object({
|
|
4683
4922
|
workspace_id: Id,
|
|
4684
4923
|
plan: PlanId,
|
|
4685
|
-
status:
|
|
4924
|
+
status: import_zod16.z.enum(["active", "trialing", "past_due", "cancelled"]),
|
|
4686
4925
|
current_period_start: Timestamp,
|
|
4687
4926
|
current_period_end: Timestamp,
|
|
4688
|
-
cancel_at_period_end:
|
|
4927
|
+
cancel_at_period_end: import_zod16.z.boolean(),
|
|
4689
4928
|
/**
|
|
4690
4929
|
* A design partner outside billing (plan `design_partner`, no limits, no
|
|
4691
4930
|
* checkout). Set only by an operator, never through the API.
|
|
4692
4931
|
*/
|
|
4693
|
-
billing_exempt:
|
|
4932
|
+
billing_exempt: import_zod16.z.boolean()
|
|
4694
4933
|
});
|
|
4695
4934
|
var USAGE_METRICS = ["messages", "contacts", "members", "providers", "webhook_endpoints", "active_automations"];
|
|
4696
|
-
var UsageMetric =
|
|
4935
|
+
var UsageMetric = import_zod16.z.enum(USAGE_METRICS);
|
|
4697
4936
|
var USAGE_WARNING_RATIO = 0.8;
|
|
4698
|
-
var UsageWarning =
|
|
4937
|
+
var UsageWarning = import_zod16.z.object({
|
|
4699
4938
|
metric: UsageMetric,
|
|
4700
|
-
used:
|
|
4701
|
-
limit:
|
|
4939
|
+
used: import_zod16.z.number().int().min(0),
|
|
4940
|
+
limit: import_zod16.z.number().int().min(0),
|
|
4702
4941
|
/** `approaching`: at or above USAGE_WARNING_RATIO of the limit; `reached`: at or above the limit. */
|
|
4703
|
-
level:
|
|
4942
|
+
level: import_zod16.z.enum(["approaching", "reached"])
|
|
4704
4943
|
});
|
|
4705
|
-
var Usage =
|
|
4944
|
+
var Usage = import_zod16.z.object({
|
|
4706
4945
|
plan: PlanId,
|
|
4707
4946
|
period_start: Timestamp,
|
|
4708
4947
|
period_end: Timestamp,
|
|
4709
|
-
metrics:
|
|
4710
|
-
warnings:
|
|
4948
|
+
metrics: import_zod16.z.record(UsageMetric, import_zod16.z.object({ used: import_zod16.z.number().int().min(0), limit: import_zod16.z.number().int().min(0).nullable() })),
|
|
4949
|
+
warnings: import_zod16.z.array(UsageWarning)
|
|
4711
4950
|
});
|
|
4712
|
-
var CheckoutRequest =
|
|
4713
|
-
plan:
|
|
4714
|
-
success_url:
|
|
4715
|
-
cancel_url:
|
|
4951
|
+
var CheckoutRequest = import_zod16.z.object({
|
|
4952
|
+
plan: import_zod16.z.enum(["starter", "growth"]),
|
|
4953
|
+
success_url: import_zod16.z.string().url(),
|
|
4954
|
+
cancel_url: import_zod16.z.string().url()
|
|
4716
4955
|
});
|
|
4717
|
-
var CheckoutSession =
|
|
4718
|
-
var PortalRequest =
|
|
4719
|
-
var PortalSession =
|
|
4956
|
+
var CheckoutSession = import_zod16.z.object({ url: import_zod16.z.string().url() });
|
|
4957
|
+
var PortalRequest = import_zod16.z.object({ return_url: import_zod16.z.string().url() });
|
|
4958
|
+
var PortalSession = import_zod16.z.object({ url: import_zod16.z.string().url() });
|
|
4720
4959
|
var USAGE_WARNING_HEADER = "x-mail-usage-warning";
|
|
4721
4960
|
function formatUsageWarningHeader(warnings) {
|
|
4722
4961
|
if (warnings.length === 0) return null;
|
|
@@ -4736,7 +4975,7 @@ function parseUsageWarningHeader(value) {
|
|
|
4736
4975
|
}
|
|
4737
4976
|
|
|
4738
4977
|
// src/routes.ts
|
|
4739
|
-
var
|
|
4978
|
+
var import_zod17 = require("zod");
|
|
4740
4979
|
var list = (item) => page(item);
|
|
4741
4980
|
var foundationRoutes = {
|
|
4742
4981
|
"workspaces.create": {
|
|
@@ -4964,7 +5203,7 @@ var templateRoutes = {
|
|
|
4964
5203
|
path: "/v1/templates/:id/export",
|
|
4965
5204
|
params: IdParams,
|
|
4966
5205
|
query: TemplateExportQuery,
|
|
4967
|
-
response:
|
|
5206
|
+
response: import_zod17.z.string(),
|
|
4968
5207
|
responseType: "text",
|
|
4969
5208
|
status: 200,
|
|
4970
5209
|
access: "read",
|
|
@@ -5288,7 +5527,7 @@ var sendingRoutes = {
|
|
|
5288
5527
|
path: "/v1/mailings/:id/export",
|
|
5289
5528
|
params: IdParams,
|
|
5290
5529
|
query: MailingExportQuery,
|
|
5291
|
-
response:
|
|
5530
|
+
response: import_zod17.z.string(),
|
|
5292
5531
|
responseType: "text",
|
|
5293
5532
|
status: 200,
|
|
5294
5533
|
access: "read",
|
|
@@ -5334,6 +5573,21 @@ var sendingRoutes = {
|
|
|
5334
5573
|
access: "write",
|
|
5335
5574
|
phase: "S2"
|
|
5336
5575
|
},
|
|
5576
|
+
/**
|
|
5577
|
+
* A dry run: what each given recipient would be sent (every value's text and
|
|
5578
|
+
* the layer it comes from, each insertion's choice, the problems found),
|
|
5579
|
+
* without adding anybody. Reads only, in any state of the mailing.
|
|
5580
|
+
*/
|
|
5581
|
+
"mailings.resolve": {
|
|
5582
|
+
method: "POST",
|
|
5583
|
+
path: "/v1/mailings/:id/resolve",
|
|
5584
|
+
params: IdParams,
|
|
5585
|
+
body: MailingResolveRequest,
|
|
5586
|
+
response: MailingResolveResult,
|
|
5587
|
+
status: 200,
|
|
5588
|
+
access: "read",
|
|
5589
|
+
phase: "S2"
|
|
5590
|
+
},
|
|
5337
5591
|
"mailings.send": {
|
|
5338
5592
|
method: "POST",
|
|
5339
5593
|
path: "/v1/mailings/:id/send",
|
|
@@ -5521,7 +5775,7 @@ var platformRoutes = {
|
|
|
5521
5775
|
"contactProperties.list": {
|
|
5522
5776
|
method: "GET",
|
|
5523
5777
|
path: "/v1/contact-properties",
|
|
5524
|
-
response:
|
|
5778
|
+
response: import_zod17.z.object({ data: import_zod17.z.array(ContactPropertyDefinition) }),
|
|
5525
5779
|
status: 200,
|
|
5526
5780
|
access: "read",
|
|
5527
5781
|
phase: "S4"
|
|
@@ -5820,7 +6074,7 @@ var billingRoutes = {
|
|
|
5820
6074
|
"billing.plans": {
|
|
5821
6075
|
method: "GET",
|
|
5822
6076
|
path: "/v1/billing/plans",
|
|
5823
|
-
response:
|
|
6077
|
+
response: import_zod17.z.object({ data: import_zod17.z.array(CatalogPlan) }),
|
|
5824
6078
|
status: 200,
|
|
5825
6079
|
access: "read",
|
|
5826
6080
|
phase: "S5"
|
|
@@ -5962,7 +6216,7 @@ var automationRoutes = {
|
|
|
5962
6216
|
method: "POST",
|
|
5963
6217
|
path: "/v1/automations/:id/pause",
|
|
5964
6218
|
params: IdParams,
|
|
5965
|
-
body:
|
|
6219
|
+
body: import_zod17.z.object({}).strict(),
|
|
5966
6220
|
response: Automation,
|
|
5967
6221
|
status: 200,
|
|
5968
6222
|
access: "write",
|
|
@@ -5972,7 +6226,7 @@ var automationRoutes = {
|
|
|
5972
6226
|
method: "POST",
|
|
5973
6227
|
path: "/v1/automations/:id/resume",
|
|
5974
6228
|
params: IdParams,
|
|
5975
|
-
body:
|
|
6229
|
+
body: import_zod17.z.object({}).strict(),
|
|
5976
6230
|
response: Automation,
|
|
5977
6231
|
status: 200,
|
|
5978
6232
|
access: "write",
|
|
@@ -5982,7 +6236,7 @@ var automationRoutes = {
|
|
|
5982
6236
|
method: "POST",
|
|
5983
6237
|
path: "/v1/automations/:id/archive",
|
|
5984
6238
|
params: IdParams,
|
|
5985
|
-
body:
|
|
6239
|
+
body: import_zod17.z.object({}).strict(),
|
|
5986
6240
|
response: Automation,
|
|
5987
6241
|
status: 200,
|
|
5988
6242
|
access: "write",
|
|
@@ -6099,6 +6353,12 @@ var routes = {
|
|
|
6099
6353
|
...billingRoutes,
|
|
6100
6354
|
...automationRoutes
|
|
6101
6355
|
};
|
|
6356
|
+
var TRUSTED_APP_OPERATIONS = {
|
|
6357
|
+
booking: ["workspaces.list", "workspace.update", "providers.list", "apiKeys.create", "apiKeys.revoke"]
|
|
6358
|
+
};
|
|
6359
|
+
function trustedAppMayCall(app, id) {
|
|
6360
|
+
return TRUSTED_APP_OPERATIONS[app].includes(id);
|
|
6361
|
+
}
|
|
6102
6362
|
function acceptsIdempotencyKey(route) {
|
|
6103
6363
|
return route.method !== "GET";
|
|
6104
6364
|
}
|
|
@@ -6116,13 +6376,13 @@ function matchRoute(method, pathname) {
|
|
|
6116
6376
|
for (const [id, route] of Object.entries(routes)) {
|
|
6117
6377
|
if (route.method !== method) continue;
|
|
6118
6378
|
const names = [];
|
|
6119
|
-
const
|
|
6379
|
+
const pattern3 = new RegExp(
|
|
6120
6380
|
"^" + route.path.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace(/:([a-z_]+)/g, (_, name) => {
|
|
6121
6381
|
names.push(name);
|
|
6122
6382
|
return "([^/]+)";
|
|
6123
6383
|
}) + "$"
|
|
6124
6384
|
);
|
|
6125
|
-
const match =
|
|
6385
|
+
const match = pattern3.exec(pathname);
|
|
6126
6386
|
if (!match) continue;
|
|
6127
6387
|
const params = {};
|
|
6128
6388
|
names.forEach((name, i) => {
|
|
@@ -6323,6 +6583,7 @@ function matchRoute(method, pathname) {
|
|
|
6323
6583
|
InviteListQuery,
|
|
6324
6584
|
InviteStatus,
|
|
6325
6585
|
JsonValue,
|
|
6586
|
+
LETTER_ONLY_MERGE_FIELDS,
|
|
6326
6587
|
LETTER_RECIPIENT_REFUSAL,
|
|
6327
6588
|
LIST_UNSUBSCRIBE_POST_VALUE,
|
|
6328
6589
|
LOCALE_TAG_PATTERN,
|
|
@@ -6391,7 +6652,10 @@ function matchRoute(method, pathname) {
|
|
|
6391
6652
|
MailingLanguageReport,
|
|
6392
6653
|
MailingLanguageStatus,
|
|
6393
6654
|
MailingListQuery,
|
|
6655
|
+
MailingMerge,
|
|
6394
6656
|
MailingMetadata,
|
|
6657
|
+
MailingResolveRequest,
|
|
6658
|
+
MailingResolveResult,
|
|
6395
6659
|
MailingRetryFailedRequest,
|
|
6396
6660
|
MailingScheduleFailedData,
|
|
6397
6661
|
MailingScheduleRequest,
|
|
@@ -6416,6 +6680,8 @@ function matchRoute(method, pathname) {
|
|
|
6416
6680
|
MessageOutcome,
|
|
6417
6681
|
MessageSentData,
|
|
6418
6682
|
MessageSummary,
|
|
6683
|
+
MessageValues,
|
|
6684
|
+
NAME_ON_BROADCAST_REFUSAL,
|
|
6419
6685
|
NotifyRecipients,
|
|
6420
6686
|
NotifyStep,
|
|
6421
6687
|
ON_BEHALF_OF_HEADER,
|
|
@@ -6451,6 +6717,8 @@ function matchRoute(method, pathname) {
|
|
|
6451
6717
|
REQUEST_ID_HEADER,
|
|
6452
6718
|
RESEND_EVENT_TYPES,
|
|
6453
6719
|
RESERVED_MERGE_FIELDS,
|
|
6720
|
+
RESOLVE_PROBLEMS,
|
|
6721
|
+
RESOLVE_REJECTIONS,
|
|
6454
6722
|
RETRYABLE_ERRORS,
|
|
6455
6723
|
RETRY_AFTER_HEADER,
|
|
6456
6724
|
RE_ENTRY_MODES,
|
|
@@ -6463,6 +6731,9 @@ function matchRoute(method, pathname) {
|
|
|
6463
6731
|
RecipientStatus,
|
|
6464
6732
|
RemoteImage,
|
|
6465
6733
|
ResendSigningSecret,
|
|
6734
|
+
ResolveProblem,
|
|
6735
|
+
ResolvedRecipient,
|
|
6736
|
+
ResolvedValue,
|
|
6466
6737
|
SERVICE_FILLED_MERGE_FIELDS,
|
|
6467
6738
|
SIGNUP_FORM_FIELDS,
|
|
6468
6739
|
SKIP_REASONS,
|
|
@@ -6499,6 +6770,8 @@ function matchRoute(method, pathname) {
|
|
|
6499
6770
|
TEMPLATE_SORTS,
|
|
6500
6771
|
TEMPLATE_SORT_DEFAULT_ORDER,
|
|
6501
6772
|
TERMINAL_MAILING_STATUSES,
|
|
6773
|
+
TRUSTED_APPS,
|
|
6774
|
+
TRUSTED_APP_OPERATIONS,
|
|
6502
6775
|
Tag,
|
|
6503
6776
|
TagAssignment,
|
|
6504
6777
|
TagCreate,
|
|
@@ -6544,15 +6817,19 @@ function matchRoute(method, pathname) {
|
|
|
6544
6817
|
TrackingSettings,
|
|
6545
6818
|
TranslationInsertion,
|
|
6546
6819
|
TranslationInsertions,
|
|
6820
|
+
TrustedApp,
|
|
6547
6821
|
UNSUBSCRIBE_PATH_PREFIX,
|
|
6548
6822
|
UNSUBSCRIBE_SOURCES,
|
|
6549
6823
|
USAGE_METRICS,
|
|
6550
6824
|
USAGE_WARNING_HEADER,
|
|
6551
6825
|
USAGE_WARNING_RATIO,
|
|
6826
|
+
UnfilledLink,
|
|
6552
6827
|
Usage,
|
|
6553
6828
|
UsageMetric,
|
|
6554
6829
|
UsageWarning,
|
|
6830
|
+
VALUE_LAYERS,
|
|
6555
6831
|
ValidationIssue,
|
|
6832
|
+
ValueLayer,
|
|
6556
6833
|
VariantAnalytics,
|
|
6557
6834
|
WEBHOOK_DELIVERY_STATUSES,
|
|
6558
6835
|
WEBHOOK_EVENT_ID_HEADER,
|
|
@@ -6616,6 +6893,7 @@ function matchRoute(method, pathname) {
|
|
|
6616
6893
|
editMainInsertions,
|
|
6617
6894
|
effectivePreviewPicks,
|
|
6618
6895
|
emptyFlow,
|
|
6896
|
+
emptyLinkValues,
|
|
6619
6897
|
errorBody,
|
|
6620
6898
|
escapeMergeHtml,
|
|
6621
6899
|
exportFilename,
|
|
@@ -6646,6 +6924,8 @@ function matchRoute(method, pathname) {
|
|
|
6646
6924
|
languageInsertions,
|
|
6647
6925
|
languageName,
|
|
6648
6926
|
languageTabs,
|
|
6927
|
+
letterOnlyValues,
|
|
6928
|
+
linkTokens,
|
|
6649
6929
|
mainInsertionText,
|
|
6650
6930
|
matchLocale,
|
|
6651
6931
|
matchRoute,
|
|
@@ -6666,6 +6946,8 @@ function matchRoute(method, pathname) {
|
|
|
6666
6946
|
previewInsertions,
|
|
6667
6947
|
previewPersonalization,
|
|
6668
6948
|
primaryLanguage,
|
|
6949
|
+
printedFields,
|
|
6950
|
+
rawMergeValue,
|
|
6669
6951
|
reachable,
|
|
6670
6952
|
readyWithoutInsertions,
|
|
6671
6953
|
readyWithoutSubject,
|
|
@@ -6682,6 +6964,7 @@ function matchRoute(method, pathname) {
|
|
|
6682
6964
|
renameTokenInDocument,
|
|
6683
6965
|
renameTokenInText,
|
|
6684
6966
|
resolveInsertions,
|
|
6967
|
+
resolveValue,
|
|
6685
6968
|
restorePatch,
|
|
6686
6969
|
routes,
|
|
6687
6970
|
sameJson,
|
|
@@ -6705,8 +6988,11 @@ function matchRoute(method, pathname) {
|
|
|
6705
6988
|
translationInsertionProblems,
|
|
6706
6989
|
translationTextFromInput,
|
|
6707
6990
|
triggerKey,
|
|
6991
|
+
trustedAppMayCall,
|
|
6708
6992
|
unknownRefusedInsertions,
|
|
6709
6993
|
unplacedInsertions,
|
|
6710
6994
|
validateAutomation,
|
|
6995
|
+
valueNames,
|
|
6996
|
+
valuesRead,
|
|
6711
6997
|
verifyWebhook
|
|
6712
6998
|
});
|