@marlinjai/mail-contract 0.9.0 → 0.11.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 +2575 -981
- package/dist/index.d.ts +2575 -981
- package/dist/index.js +913 -641
- package/dist/index.mjs +891 -641
- 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,
|
|
@@ -435,10 +446,13 @@ __export(index_exports, {
|
|
|
435
446
|
USAGE_METRICS: () => USAGE_METRICS,
|
|
436
447
|
USAGE_WARNING_HEADER: () => USAGE_WARNING_HEADER,
|
|
437
448
|
USAGE_WARNING_RATIO: () => USAGE_WARNING_RATIO,
|
|
449
|
+
UnfilledLink: () => UnfilledLink,
|
|
438
450
|
Usage: () => Usage,
|
|
439
451
|
UsageMetric: () => UsageMetric,
|
|
440
452
|
UsageWarning: () => UsageWarning,
|
|
453
|
+
VALUE_LAYERS: () => VALUE_LAYERS,
|
|
441
454
|
ValidationIssue: () => ValidationIssue,
|
|
455
|
+
ValueLayer: () => ValueLayer,
|
|
442
456
|
VariantAnalytics: () => VariantAnalytics,
|
|
443
457
|
WEBHOOK_DELIVERY_STATUSES: () => WEBHOOK_DELIVERY_STATUSES,
|
|
444
458
|
WEBHOOK_EVENT_ID_HEADER: () => WEBHOOK_EVENT_ID_HEADER,
|
|
@@ -502,6 +516,7 @@ __export(index_exports, {
|
|
|
502
516
|
editMainInsertions: () => editMainInsertions,
|
|
503
517
|
effectivePreviewPicks: () => effectivePreviewPicks,
|
|
504
518
|
emptyFlow: () => emptyFlow,
|
|
519
|
+
emptyLinkValues: () => emptyLinkValues,
|
|
505
520
|
errorBody: () => errorBody,
|
|
506
521
|
escapeMergeHtml: () => escapeMergeHtml,
|
|
507
522
|
exportFilename: () => exportFilename,
|
|
@@ -532,6 +547,8 @@ __export(index_exports, {
|
|
|
532
547
|
languageInsertions: () => languageInsertions,
|
|
533
548
|
languageName: () => languageName,
|
|
534
549
|
languageTabs: () => languageTabs,
|
|
550
|
+
letterOnlyValues: () => letterOnlyValues,
|
|
551
|
+
linkTokens: () => linkTokens,
|
|
535
552
|
mainInsertionText: () => mainInsertionText,
|
|
536
553
|
matchLocale: () => matchLocale,
|
|
537
554
|
matchRoute: () => matchRoute,
|
|
@@ -552,6 +569,8 @@ __export(index_exports, {
|
|
|
552
569
|
previewInsertions: () => previewInsertions,
|
|
553
570
|
previewPersonalization: () => previewPersonalization,
|
|
554
571
|
primaryLanguage: () => primaryLanguage,
|
|
572
|
+
printedFields: () => printedFields,
|
|
573
|
+
rawMergeValue: () => rawMergeValue,
|
|
555
574
|
reachable: () => reachable,
|
|
556
575
|
readyWithoutInsertions: () => readyWithoutInsertions,
|
|
557
576
|
readyWithoutSubject: () => readyWithoutSubject,
|
|
@@ -568,6 +587,7 @@ __export(index_exports, {
|
|
|
568
587
|
renameTokenInDocument: () => renameTokenInDocument,
|
|
569
588
|
renameTokenInText: () => renameTokenInText,
|
|
570
589
|
resolveInsertions: () => resolveInsertions,
|
|
590
|
+
resolveValue: () => resolveValue,
|
|
571
591
|
restorePatch: () => restorePatch,
|
|
572
592
|
routes: () => routes,
|
|
573
593
|
sameJson: () => sameJson,
|
|
@@ -594,6 +614,8 @@ __export(index_exports, {
|
|
|
594
614
|
unknownRefusedInsertions: () => unknownRefusedInsertions,
|
|
595
615
|
unplacedInsertions: () => unplacedInsertions,
|
|
596
616
|
validateAutomation: () => validateAutomation,
|
|
617
|
+
valueNames: () => valueNames,
|
|
618
|
+
valuesRead: () => valuesRead,
|
|
597
619
|
verifyWebhook: () => verifyWebhook
|
|
598
620
|
});
|
|
599
621
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -677,6 +699,12 @@ var ERROR_STATUS = {
|
|
|
677
699
|
invalid_mjml: 422,
|
|
678
700
|
missing_unsubscribe_url: 422,
|
|
679
701
|
mailing_not_ready: 422,
|
|
702
|
+
/**
|
|
703
|
+
* A value placed inside a link's address comes out empty for at least one
|
|
704
|
+
* recipient, so the mailing does not start; `details.values` lists each such
|
|
705
|
+
* value with how many recipients it is empty for.
|
|
706
|
+
*/
|
|
707
|
+
unfilled_link: 422,
|
|
680
708
|
unknown_topic: 422,
|
|
681
709
|
unknown_provider: 422,
|
|
682
710
|
/**
|
|
@@ -745,10 +773,10 @@ var API_VERSION_PREFIX = "/v1";
|
|
|
745
773
|
var HEALTH_PATH = "/healthz";
|
|
746
774
|
|
|
747
775
|
// src/workspace.ts
|
|
748
|
-
var
|
|
776
|
+
var import_zod11 = require("zod");
|
|
749
777
|
|
|
750
778
|
// src/automations.ts
|
|
751
|
-
var
|
|
779
|
+
var import_zod10 = require("zod");
|
|
752
780
|
|
|
753
781
|
// src/templates.ts
|
|
754
782
|
var import_zod5 = require("zod");
|
|
@@ -769,11 +797,11 @@ var RESERVED_MERGE_FIELDS = {
|
|
|
769
797
|
};
|
|
770
798
|
var MERGE_FIELD_PATTERN = /\{\{\s*([a-z][a-z0-9_]*)\s*(?:\|([^}]*))?\}\}/g;
|
|
771
799
|
function findMergeFields(html) {
|
|
772
|
-
const
|
|
800
|
+
const uses2 = [];
|
|
773
801
|
for (const match of html.matchAll(MERGE_FIELD_PATTERN)) {
|
|
774
|
-
|
|
802
|
+
uses2.push({ name: match[1], fallback: match[2] === void 0 ? null : match[2].trim() });
|
|
775
803
|
}
|
|
776
|
-
return
|
|
804
|
+
return uses2;
|
|
777
805
|
}
|
|
778
806
|
function missingRequiredMergeFields(html) {
|
|
779
807
|
const used = new Set(findMergeFields(html).map((u) => u.name));
|
|
@@ -1456,10 +1484,10 @@ function exportFilename(name, format) {
|
|
|
1456
1484
|
}
|
|
1457
1485
|
|
|
1458
1486
|
// src/platform.ts
|
|
1459
|
-
var
|
|
1487
|
+
var import_zod9 = require("zod");
|
|
1460
1488
|
|
|
1461
1489
|
// src/mailings.ts
|
|
1462
|
-
var
|
|
1490
|
+
var import_zod8 = require("zod");
|
|
1463
1491
|
|
|
1464
1492
|
// src/ab-test.ts
|
|
1465
1493
|
var import_zod6 = require("zod");
|
|
@@ -1510,6 +1538,167 @@ function testGroupSize(total, fraction, variants) {
|
|
|
1510
1538
|
return Math.min(total, Math.max(variants, Math.ceil(total * fraction)));
|
|
1511
1539
|
}
|
|
1512
1540
|
|
|
1541
|
+
// src/values.ts
|
|
1542
|
+
var import_zod7 = require("zod");
|
|
1543
|
+
var MAX_MERGE_DEFAULTS = 50;
|
|
1544
|
+
var MAX_MERGE_DEFAULT_LENGTH = 2e3;
|
|
1545
|
+
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);
|
|
1546
|
+
var MergeDefaultValue = import_zod7.z.union([import_zod7.z.string().max(MAX_MERGE_DEFAULT_LENGTH), import_zod7.z.number().finite(), import_zod7.z.boolean()]);
|
|
1547
|
+
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)), {
|
|
1548
|
+
message: `the service fills ${SERVICE_FILLED_MERGE_FIELDS.join(" and ")}; a mailing cannot set them`
|
|
1549
|
+
});
|
|
1550
|
+
var LETTER_ONLY_MERGE_FIELDS = ["first_name", "last_name"];
|
|
1551
|
+
var NAME_ON_BROADCAST_REFUSAL = "name_on_broadcast";
|
|
1552
|
+
function letterOnlyValues(merge) {
|
|
1553
|
+
return LETTER_ONLY_MERGE_FIELDS.filter((name) => ownEntry(merge, name) !== void 0);
|
|
1554
|
+
}
|
|
1555
|
+
var VALUE_LAYERS = ["recipient", "mailing", "contact", "workspace", "fallback", "empty"];
|
|
1556
|
+
var ValueLayer = import_zod7.z.enum(VALUE_LAYERS);
|
|
1557
|
+
var ResolvedValue = import_zod7.z.object({ text: import_zod7.z.string(), layer: ValueLayer });
|
|
1558
|
+
var MessageValues = import_zod7.z.record(ResolvedValue);
|
|
1559
|
+
function scalarText(value) {
|
|
1560
|
+
if (typeof value === "string") return value;
|
|
1561
|
+
if (typeof value === "number" && Number.isFinite(value)) return String(value);
|
|
1562
|
+
if (typeof value === "boolean") return String(value);
|
|
1563
|
+
return null;
|
|
1564
|
+
}
|
|
1565
|
+
function isNameField(name) {
|
|
1566
|
+
return name === "first_name" || name === "last_name";
|
|
1567
|
+
}
|
|
1568
|
+
function rawMergeValue(name, sources) {
|
|
1569
|
+
const own = ownEntry(sources.recipient, name);
|
|
1570
|
+
if (scalarText(own) !== null) return { value: own, layer: "recipient" };
|
|
1571
|
+
const held = ownEntry(sources.mailing, name);
|
|
1572
|
+
if (scalarText(held) !== null) return { value: held, layer: "mailing" };
|
|
1573
|
+
if (isNameField(name)) {
|
|
1574
|
+
const stored = sources.contact?.[name];
|
|
1575
|
+
return typeof stored === "string" ? { value: stored, layer: "contact" } : null;
|
|
1576
|
+
}
|
|
1577
|
+
const property = ownEntry(sources.contact?.properties, name);
|
|
1578
|
+
if (scalarText(property) !== null) return { value: property, layer: "contact" };
|
|
1579
|
+
const byDefault = ownEntry(sources.workspace, name);
|
|
1580
|
+
return scalarText(byDefault) !== null ? { value: byDefault, layer: "workspace" } : null;
|
|
1581
|
+
}
|
|
1582
|
+
function resolveValue(name, fallback, sources) {
|
|
1583
|
+
const found = rawMergeValue(name, sources);
|
|
1584
|
+
const text = found === null ? null : scalarText(found.value);
|
|
1585
|
+
if (found !== null && text !== null && text.trim() !== "") return { text, layer: found.layer };
|
|
1586
|
+
const instead = fallback?.trim() ?? "";
|
|
1587
|
+
return instead === "" ? { text: "", layer: "empty" } : { text: instead, layer: "fallback" };
|
|
1588
|
+
}
|
|
1589
|
+
function pattern2() {
|
|
1590
|
+
return new RegExp(MERGE_FIELD_PATTERN.source, "g");
|
|
1591
|
+
}
|
|
1592
|
+
function isServiceFilled(name) {
|
|
1593
|
+
return SERVICE_FILLED_MERGE_FIELDS.includes(name);
|
|
1594
|
+
}
|
|
1595
|
+
function uses(text) {
|
|
1596
|
+
return [...text.matchAll(pattern2())].map((m) => ({ name: m[1], fallback: m[2] === void 0 ? null : m[2].trim() }));
|
|
1597
|
+
}
|
|
1598
|
+
function valueNames(texts, insertions) {
|
|
1599
|
+
const names = [];
|
|
1600
|
+
const add = (name) => {
|
|
1601
|
+
if (!isServiceFilled(name) && !names.includes(name)) names.push(name);
|
|
1602
|
+
};
|
|
1603
|
+
for (const text of texts) {
|
|
1604
|
+
for (const use of uses(text ?? "")) {
|
|
1605
|
+
const def = ownEntry(insertions, use.name);
|
|
1606
|
+
if (!def) {
|
|
1607
|
+
add(use.name);
|
|
1608
|
+
continue;
|
|
1609
|
+
}
|
|
1610
|
+
add(def.by);
|
|
1611
|
+
for (const inner of [...Object.values(def.choices), def.filled ?? "", def.otherwise]) for (const u of uses(inner)) add(u.name);
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
return names;
|
|
1615
|
+
}
|
|
1616
|
+
function printedFields(texts, insertions, chosen2) {
|
|
1617
|
+
const out = [];
|
|
1618
|
+
const add = (use) => {
|
|
1619
|
+
if (isServiceFilled(use.name)) return;
|
|
1620
|
+
if (!out.some((o) => o.name === use.name && o.fallback === use.fallback)) out.push(use);
|
|
1621
|
+
};
|
|
1622
|
+
for (const text of texts) {
|
|
1623
|
+
for (const use of uses(text ?? "")) {
|
|
1624
|
+
if (!ownEntry(insertions, use.name)) add(use);
|
|
1625
|
+
else for (const inner of uses(ownEntry(chosen2, use.name)?.text ?? "")) add(inner);
|
|
1626
|
+
}
|
|
1627
|
+
}
|
|
1628
|
+
return out;
|
|
1629
|
+
}
|
|
1630
|
+
function valuesRead(texts, insertions, chosen2, resolve) {
|
|
1631
|
+
const out = {};
|
|
1632
|
+
const read = (use) => {
|
|
1633
|
+
if (isServiceFilled(use.name)) return;
|
|
1634
|
+
const value = resolve(use.name, use.fallback);
|
|
1635
|
+
const seen = ownEntry(out, use.name);
|
|
1636
|
+
if (seen === void 0 || value.layer === "empty" && seen.layer !== "empty") out[use.name] = value;
|
|
1637
|
+
};
|
|
1638
|
+
for (const text of texts) {
|
|
1639
|
+
for (const use of uses(text ?? "")) {
|
|
1640
|
+
const def = ownEntry(insertions, use.name);
|
|
1641
|
+
if (!def) {
|
|
1642
|
+
read(use);
|
|
1643
|
+
continue;
|
|
1644
|
+
}
|
|
1645
|
+
read({ name: def.by, fallback: null });
|
|
1646
|
+
for (const inner of uses(ownEntry(chosen2, use.name)?.text ?? "")) read(inner);
|
|
1647
|
+
}
|
|
1648
|
+
}
|
|
1649
|
+
return out;
|
|
1650
|
+
}
|
|
1651
|
+
var HREF = /\bhref\s*=\s*(?:"([^"]*)"|'([^']*)')/gi;
|
|
1652
|
+
function linkTokens(html) {
|
|
1653
|
+
const out = [];
|
|
1654
|
+
for (const match of html.matchAll(HREF)) {
|
|
1655
|
+
for (const use of uses(match[1] ?? match[2] ?? "")) {
|
|
1656
|
+
if (isServiceFilled(use.name)) continue;
|
|
1657
|
+
if (!out.some((o) => o.name === use.name && o.fallback === use.fallback)) out.push(use);
|
|
1658
|
+
}
|
|
1659
|
+
}
|
|
1660
|
+
return out;
|
|
1661
|
+
}
|
|
1662
|
+
function emptyLinkValues(tokens, p) {
|
|
1663
|
+
const empty = [];
|
|
1664
|
+
for (const token of tokens) {
|
|
1665
|
+
const ins = ownEntry(p.insertions, token.name);
|
|
1666
|
+
const text = ins ? ins.text.replace(pattern2(), (_m, name, fallback) => p.value(name, fallback)) : p.value(token.name, token.fallback ?? void 0);
|
|
1667
|
+
if (text.trim() === "" && !empty.includes(token.name)) empty.push(token.name);
|
|
1668
|
+
}
|
|
1669
|
+
return empty;
|
|
1670
|
+
}
|
|
1671
|
+
var UnfilledLink = import_zod7.z.object({
|
|
1672
|
+
/** The value, or the insertion, that comes out empty. */
|
|
1673
|
+
value: import_zod7.z.string(),
|
|
1674
|
+
/** How many recipients it is empty for. */
|
|
1675
|
+
recipients: import_zod7.z.number().int().min(1)
|
|
1676
|
+
});
|
|
1677
|
+
var RESOLVE_PROBLEMS = ["unfilled_link", "empty_value", "insertion_miss"];
|
|
1678
|
+
var ResolveProblem = import_zod7.z.object({
|
|
1679
|
+
kind: import_zod7.z.enum(RESOLVE_PROBLEMS),
|
|
1680
|
+
severity: import_zod7.z.enum(["blocking", "note"]),
|
|
1681
|
+
value: import_zod7.z.string(),
|
|
1682
|
+
message: import_zod7.z.string()
|
|
1683
|
+
});
|
|
1684
|
+
var ResolvedRecipient = import_zod7.z.object({
|
|
1685
|
+
/** The recipient's index in the request; null for the reader with nothing of their own. */
|
|
1686
|
+
index: import_zod7.z.number().int().min(0).nullable(),
|
|
1687
|
+
/** The address the message would go to; null for the reader with nothing of their own. */
|
|
1688
|
+
email: Email.nullable(),
|
|
1689
|
+
/** The contact found for the recipient; null when the address has none yet (a send creates it, empty). */
|
|
1690
|
+
contact_id: Id.nullable(),
|
|
1691
|
+
/** The language version this recipient would get. */
|
|
1692
|
+
locale: LocaleTag,
|
|
1693
|
+
/** The subject line as they would read it. */
|
|
1694
|
+
subject: import_zod7.z.string(),
|
|
1695
|
+
values: MessageValues,
|
|
1696
|
+
/** The choice each insertion would make; null when the content has none. */
|
|
1697
|
+
insertions: InsertionChoices.nullable(),
|
|
1698
|
+
problems: import_zod7.z.array(ResolveProblem)
|
|
1699
|
+
});
|
|
1700
|
+
var RESOLVE_REJECTIONS = ["unknown_contact", "duplicate_in_batch"];
|
|
1701
|
+
|
|
1513
1702
|
// src/mailings.ts
|
|
1514
1703
|
var MAILING_STATUSES = [
|
|
1515
1704
|
"draft",
|
|
@@ -1520,9 +1709,9 @@ var MAILING_STATUSES = [
|
|
|
1520
1709
|
"partially_failed",
|
|
1521
1710
|
"cancelled"
|
|
1522
1711
|
];
|
|
1523
|
-
var MailingStatus =
|
|
1712
|
+
var MailingStatus = import_zod8.z.enum(MAILING_STATUSES);
|
|
1524
1713
|
var MAILING_ACTIONS = ["send", "schedule", "unschedule", "pause", "resume", "cancel", "retry-failed"];
|
|
1525
|
-
var MailingAction =
|
|
1714
|
+
var MailingAction = import_zod8.z.enum(MAILING_ACTIONS);
|
|
1526
1715
|
var MAILING_TRANSITIONS = {
|
|
1527
1716
|
draft: ["send", "schedule", "cancel"],
|
|
1528
1717
|
scheduled: ["send", "schedule", "unschedule", "cancel"],
|
|
@@ -1537,23 +1726,23 @@ function canTransition(status, action) {
|
|
|
1537
1726
|
}
|
|
1538
1727
|
var EDITABLE_MAILING_STATUSES = ["draft", "scheduled"];
|
|
1539
1728
|
var TERMINAL_MAILING_STATUSES = ["sent", "cancelled"];
|
|
1540
|
-
var MailingMetadata =
|
|
1541
|
-
var MailingCounts =
|
|
1542
|
-
total:
|
|
1543
|
-
queued:
|
|
1544
|
-
sending:
|
|
1545
|
-
sent:
|
|
1546
|
-
failed:
|
|
1547
|
-
skipped:
|
|
1729
|
+
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");
|
|
1730
|
+
var MailingCounts = import_zod8.z.object({
|
|
1731
|
+
total: import_zod8.z.number().int().min(0),
|
|
1732
|
+
queued: import_zod8.z.number().int().min(0),
|
|
1733
|
+
sending: import_zod8.z.number().int().min(0),
|
|
1734
|
+
sent: import_zod8.z.number().int().min(0),
|
|
1735
|
+
failed: import_zod8.z.number().int().min(0),
|
|
1736
|
+
skipped: import_zod8.z.number().int().min(0)
|
|
1548
1737
|
});
|
|
1549
1738
|
var MAILING_KINDS = ["broadcast", "automation", "notification"];
|
|
1550
|
-
var MailingKind =
|
|
1551
|
-
var Mailing =
|
|
1739
|
+
var MailingKind = import_zod8.z.enum(MAILING_KINDS);
|
|
1740
|
+
var Mailing = import_zod8.z.object({
|
|
1552
1741
|
id: Id,
|
|
1553
1742
|
kind: MailingKind,
|
|
1554
|
-
name:
|
|
1555
|
-
subject:
|
|
1556
|
-
preheader:
|
|
1743
|
+
name: import_zod8.z.string().max(200).nullable(),
|
|
1744
|
+
subject: import_zod8.z.string().min(1).max(998),
|
|
1745
|
+
preheader: import_zod8.z.string().max(500).nullable(),
|
|
1557
1746
|
/**
|
|
1558
1747
|
* The template the document was taken from, if any. The snapshot is what is
|
|
1559
1748
|
* sent in the main language; the template's other language versions are
|
|
@@ -1577,6 +1766,14 @@ var Mailing = import_zod7.z.object({
|
|
|
1577
1766
|
* language: without a ready version in it, the main language goes out.
|
|
1578
1767
|
*/
|
|
1579
1768
|
send_locale: LocaleTag.nullable(),
|
|
1769
|
+
/**
|
|
1770
|
+
* The template's language version the mailing was written from
|
|
1771
|
+
* (`MailingCreate.template_locale`), or null. When set, it equals `locale`
|
|
1772
|
+
* and `send_locale`: the mailing is one letter in that language, and the
|
|
1773
|
+
* template's other versions never go out with it (see "Writing from one
|
|
1774
|
+
* language version" in the contract's documentation).
|
|
1775
|
+
*/
|
|
1776
|
+
template_locale: LocaleTag.nullable().default(null),
|
|
1580
1777
|
/**
|
|
1581
1778
|
* The topic the mailing is sent under. Null for a letter (a one-to-one
|
|
1582
1779
|
* mailing with at most one recipient, which belongs to no topic and whose
|
|
@@ -1587,6 +1784,12 @@ var Mailing = import_zod7.z.object({
|
|
|
1587
1784
|
status: MailingStatus,
|
|
1588
1785
|
counts: MailingCounts,
|
|
1589
1786
|
metadata: MailingMetadata,
|
|
1787
|
+
/**
|
|
1788
|
+
* The values held on this mailing (see `MailingMerge`): the same for
|
|
1789
|
+
* everyone who gets it, above the contact's stored name and properties and
|
|
1790
|
+
* the workspace's defaults, below the recipient's own. Empty by default.
|
|
1791
|
+
*/
|
|
1792
|
+
merge: MailingMerge.default({}),
|
|
1590
1793
|
scheduled_at: Timestamp.nullable(),
|
|
1591
1794
|
/** The A/B test on subject or content (S4), null when there is none. */
|
|
1592
1795
|
ab_test: AbTestState.nullable(),
|
|
@@ -1598,15 +1801,15 @@ var Mailing = import_zod7.z.object({
|
|
|
1598
1801
|
* recipients refused as dead addresses in one run (see the provider's
|
|
1599
1802
|
* `rejections.anomaly`). Resuming clears it and starts a new run.
|
|
1600
1803
|
*/
|
|
1601
|
-
pause_reason:
|
|
1804
|
+
pause_reason: import_zod8.z.string().nullable().default(null),
|
|
1602
1805
|
created_at: Timestamp,
|
|
1603
1806
|
updated_at: Timestamp
|
|
1604
1807
|
});
|
|
1605
1808
|
var MailingSummary = Mailing.omit({ document: true });
|
|
1606
1809
|
var MailingContent = {
|
|
1607
|
-
name:
|
|
1608
|
-
subject:
|
|
1609
|
-
preheader:
|
|
1810
|
+
name: import_zod8.z.string().max(200).optional(),
|
|
1811
|
+
subject: import_zod8.z.string().min(1).max(998),
|
|
1812
|
+
preheader: import_zod8.z.string().max(500).optional(),
|
|
1610
1813
|
/** See `Mailing.send_locale`. */
|
|
1611
1814
|
send_locale: LocaleTag.nullable().optional(),
|
|
1612
1815
|
/**
|
|
@@ -1617,29 +1820,42 @@ var MailingContent = {
|
|
|
1617
1820
|
*/
|
|
1618
1821
|
topic: Slug.nullable().optional(),
|
|
1619
1822
|
provider_id: Id,
|
|
1620
|
-
metadata: MailingMetadata.optional()
|
|
1823
|
+
metadata: MailingMetadata.optional(),
|
|
1824
|
+
/** See `Mailing.merge`. `first_name` and `last_name` only on a letter (no topic). */
|
|
1825
|
+
merge: MailingMerge.optional()
|
|
1621
1826
|
};
|
|
1622
|
-
var MailingCreate =
|
|
1827
|
+
var MailingCreate = import_zod8.z.object({
|
|
1623
1828
|
...MailingContent,
|
|
1624
1829
|
subject: MailingContent.subject.optional(),
|
|
1625
1830
|
document: TemplateDocument.optional(),
|
|
1626
|
-
template_id: Id.optional()
|
|
1831
|
+
template_id: Id.optional(),
|
|
1832
|
+
template_locale: LocaleTag.optional()
|
|
1627
1833
|
}).refine((v) => v.document === void 0 !== (v.template_id === void 0), {
|
|
1628
1834
|
message: "exactly one of document or template_id",
|
|
1629
1835
|
path: ["document"]
|
|
1836
|
+
}).refine((v) => v.template_locale === void 0 || v.template_id !== void 0, {
|
|
1837
|
+
message: "template_locale names a version of template_id",
|
|
1838
|
+
path: ["template_locale"]
|
|
1630
1839
|
}).refine((v) => v.template_id !== void 0 || v.subject !== void 0, {
|
|
1631
1840
|
message: "a mailing made from a document needs a subject",
|
|
1632
1841
|
path: ["subject"]
|
|
1633
1842
|
});
|
|
1634
|
-
var MailingUpdate =
|
|
1635
|
-
name:
|
|
1843
|
+
var MailingUpdate = import_zod8.z.object({
|
|
1844
|
+
name: import_zod8.z.string().max(200).nullable().optional(),
|
|
1636
1845
|
subject: MailingContent.subject.optional(),
|
|
1637
|
-
preheader:
|
|
1846
|
+
preheader: import_zod8.z.string().max(500).nullable().optional(),
|
|
1638
1847
|
/** Null turns a draft into a letter, which it can only be with at most one recipient. */
|
|
1639
1848
|
topic: Slug.nullable().optional(),
|
|
1640
1849
|
send_locale: LocaleTag.nullable().optional(),
|
|
1641
1850
|
provider_id: Id.optional(),
|
|
1642
1851
|
metadata: MailingMetadata.optional(),
|
|
1852
|
+
/**
|
|
1853
|
+
* Replaces the mailing's values whole (see `Mailing.merge`). Giving a
|
|
1854
|
+
* mailing that holds `first_name` or `last_name` a topic is refused
|
|
1855
|
+
* (`name_on_broadcast`) unless the same call replaces its values without
|
|
1856
|
+
* them.
|
|
1857
|
+
*/
|
|
1858
|
+
merge: MailingMerge.optional(),
|
|
1643
1859
|
document: TemplateDocument.optional()
|
|
1644
1860
|
}).refine((v) => Object.keys(v).length > 0, "at least one field");
|
|
1645
1861
|
var MailingListQuery = PageQuery.extend({
|
|
@@ -1648,30 +1864,30 @@ var MailingListQuery = PageQuery.extend({
|
|
|
1648
1864
|
kind: MailingKind.optional(),
|
|
1649
1865
|
automation_id: Id.optional()
|
|
1650
1866
|
});
|
|
1651
|
-
var MailingSendRequest =
|
|
1652
|
-
var MailingRetryFailedRequest =
|
|
1867
|
+
var MailingSendRequest = import_zod8.z.object({}).strict();
|
|
1868
|
+
var MailingRetryFailedRequest = import_zod8.z.object({
|
|
1653
1869
|
/**
|
|
1654
1870
|
* Also requeue recipients whose outcome is unknown after a crash. They may
|
|
1655
1871
|
* already have received the message, so this is a human's decision, never a
|
|
1656
1872
|
* default.
|
|
1657
1873
|
*/
|
|
1658
|
-
include_outcome_unknown:
|
|
1874
|
+
include_outcome_unknown: import_zod8.z.boolean().optional()
|
|
1659
1875
|
}).strict();
|
|
1660
|
-
var MailingActionRequest =
|
|
1661
|
-
var MailingTestRequest =
|
|
1876
|
+
var MailingActionRequest = import_zod8.z.object({}).strict();
|
|
1877
|
+
var MailingTestRequest = import_zod8.z.object({
|
|
1662
1878
|
to: Email,
|
|
1663
1879
|
merge: Properties.optional(),
|
|
1664
1880
|
locale: LocaleTag.optional()
|
|
1665
1881
|
});
|
|
1666
|
-
var MailingTestResult =
|
|
1882
|
+
var MailingTestResult = import_zod8.z.object({
|
|
1667
1883
|
message_id: Id,
|
|
1668
|
-
provider_message_id:
|
|
1884
|
+
provider_message_id: import_zod8.z.string().nullable()
|
|
1669
1885
|
});
|
|
1670
1886
|
var RECIPIENT_STATUSES = ["queued", "sending", "sent", "failed", "skipped"];
|
|
1671
|
-
var RecipientStatus =
|
|
1887
|
+
var RecipientStatus = import_zod8.z.enum(RECIPIENT_STATUSES);
|
|
1672
1888
|
var SKIP_REASONS = ["suppressed", "not_subscribed", "contact_erased", "cancelled", "outcome_unknown"];
|
|
1673
|
-
var SkipReason =
|
|
1674
|
-
var Recipient =
|
|
1889
|
+
var SkipReason = import_zod8.z.enum(SKIP_REASONS);
|
|
1890
|
+
var Recipient = import_zod8.z.object({
|
|
1675
1891
|
id: Id,
|
|
1676
1892
|
mailing_id: Id,
|
|
1677
1893
|
contact_id: Id.nullable(),
|
|
@@ -1679,55 +1895,55 @@ var Recipient = import_zod7.z.object({
|
|
|
1679
1895
|
merge: Properties,
|
|
1680
1896
|
status: RecipientStatus,
|
|
1681
1897
|
skip_reason: SkipReason.nullable(),
|
|
1682
|
-
attempts:
|
|
1898
|
+
attempts: import_zod8.z.number().int().min(0),
|
|
1683
1899
|
message_id: Id.nullable(),
|
|
1684
|
-
last_error:
|
|
1900
|
+
last_error: import_zod8.z.string().nullable(),
|
|
1685
1901
|
created_at: Timestamp,
|
|
1686
1902
|
updated_at: Timestamp
|
|
1687
1903
|
});
|
|
1688
1904
|
var MAX_RECIPIENTS_PER_BATCH = 1e3;
|
|
1689
1905
|
var MAX_LETTER_RECIPIENTS = 1;
|
|
1690
1906
|
var LETTER_RECIPIENT_REFUSAL = "letter_has_one_recipient";
|
|
1691
|
-
var RecipientInput =
|
|
1907
|
+
var RecipientInput = import_zod8.z.object({
|
|
1692
1908
|
contact_id: Id.optional(),
|
|
1693
|
-
external_id:
|
|
1909
|
+
external_id: import_zod8.z.string().min(1).max(255).optional(),
|
|
1694
1910
|
email: Email.optional(),
|
|
1695
1911
|
merge: Properties.optional()
|
|
1696
1912
|
}).refine((v) => v.contact_id !== void 0 || v.external_id !== void 0 || v.email !== void 0, {
|
|
1697
1913
|
message: "contact_id, external_id or email is required",
|
|
1698
1914
|
path: ["email"]
|
|
1699
1915
|
});
|
|
1700
|
-
var RecipientBatch =
|
|
1701
|
-
recipients:
|
|
1916
|
+
var RecipientBatch = import_zod8.z.object({
|
|
1917
|
+
recipients: import_zod8.z.array(RecipientInput).min(1).max(MAX_RECIPIENTS_PER_BATCH)
|
|
1702
1918
|
});
|
|
1703
1919
|
var RECIPIENT_REJECTIONS = ["unknown_contact", "duplicate_in_batch"];
|
|
1704
|
-
var RecipientBatchResult =
|
|
1920
|
+
var RecipientBatchResult = import_zod8.z.object({
|
|
1705
1921
|
/** Newly queued. */
|
|
1706
|
-
added:
|
|
1922
|
+
added: import_zod8.z.number().int().min(0),
|
|
1707
1923
|
/** Already on the mailing from an earlier batch: left unchanged. */
|
|
1708
|
-
already_present:
|
|
1924
|
+
already_present: import_zod8.z.number().int().min(0),
|
|
1709
1925
|
/** Items not added, by their index in the request. */
|
|
1710
|
-
rejected:
|
|
1926
|
+
rejected: import_zod8.z.array(import_zod8.z.object({ index: import_zod8.z.number().int().min(0), reason: import_zod8.z.enum(RECIPIENT_REJECTIONS) }))
|
|
1711
1927
|
});
|
|
1712
1928
|
var RecipientListQuery = PageQuery.extend({
|
|
1713
1929
|
status: RecipientStatus.optional(),
|
|
1714
1930
|
skip_reason: SkipReason.optional()
|
|
1715
1931
|
});
|
|
1716
1932
|
var MESSAGE_OUTCOMES = ["sent", "failed"];
|
|
1717
|
-
var MessageOutcome =
|
|
1718
|
-
var MessageSummary =
|
|
1933
|
+
var MessageOutcome = import_zod8.z.enum(MESSAGE_OUTCOMES);
|
|
1934
|
+
var MessageSummary = import_zod8.z.object({
|
|
1719
1935
|
id: Id,
|
|
1720
1936
|
mailing_id: Id.nullable(),
|
|
1721
1937
|
recipient_id: Id.nullable(),
|
|
1722
1938
|
contact_id: Id.nullable(),
|
|
1723
1939
|
to: Email,
|
|
1724
|
-
subject:
|
|
1940
|
+
subject: import_zod8.z.string(),
|
|
1725
1941
|
provider_id: Id,
|
|
1726
|
-
provider_message_id:
|
|
1942
|
+
provider_message_id: import_zod8.z.string().nullable(),
|
|
1727
1943
|
outcome: MessageOutcome,
|
|
1728
|
-
error:
|
|
1729
|
-
is_test:
|
|
1730
|
-
recipient_count:
|
|
1944
|
+
error: import_zod8.z.string().nullable(),
|
|
1945
|
+
is_test: import_zod8.z.boolean(),
|
|
1946
|
+
recipient_count: import_zod8.z.number().int().min(1),
|
|
1731
1947
|
/** The language version the message was sent in; null for messages archived before languages existed. */
|
|
1732
1948
|
locale: LocaleTag.nullable(),
|
|
1733
1949
|
/**
|
|
@@ -1737,24 +1953,32 @@ var MessageSummary = import_zod7.z.object({
|
|
|
1737
1953
|
* "otherwise" text. Null when the message had no insertions.
|
|
1738
1954
|
*/
|
|
1739
1955
|
insertions: InsertionChoices.nullable(),
|
|
1956
|
+
/**
|
|
1957
|
+
* The values the message was written with, by name: the text each one
|
|
1958
|
+
* printed and the layer it came from (see `MessageValues`), recorded when it
|
|
1959
|
+
* was sent, so a later change to a default never rewrites what a reader got.
|
|
1960
|
+
* Null for a message archived before values were recorded, and for a signup
|
|
1961
|
+
* form's confirmation, which belongs to no mailing.
|
|
1962
|
+
*/
|
|
1963
|
+
values: MessageValues.nullable().default(null),
|
|
1740
1964
|
created_at: Timestamp
|
|
1741
1965
|
});
|
|
1742
|
-
var Message = MessageSummary.extend({ html:
|
|
1743
|
-
var MailingLanguageStatus =
|
|
1744
|
-
var MailingLanguage =
|
|
1966
|
+
var Message = MessageSummary.extend({ html: import_zod8.z.string() });
|
|
1967
|
+
var MailingLanguageStatus = import_zod8.z.enum(["main", "ready", "draft", "not_a_workspace_language"]);
|
|
1968
|
+
var MailingLanguage = import_zod8.z.object({
|
|
1745
1969
|
locale: LocaleTag,
|
|
1746
1970
|
status: MailingLanguageStatus,
|
|
1747
1971
|
/** Queued recipients who will get this version. */
|
|
1748
|
-
planned:
|
|
1972
|
+
planned: import_zod8.z.number().int().min(0),
|
|
1749
1973
|
/** Messages already sent in this language (tests excluded). */
|
|
1750
|
-
sent:
|
|
1974
|
+
sent: import_zod8.z.number().int().min(0)
|
|
1751
1975
|
});
|
|
1752
|
-
var MailingLanguageReport =
|
|
1976
|
+
var MailingLanguageReport = import_zod8.z.object({
|
|
1753
1977
|
main_locale: LocaleTag,
|
|
1754
1978
|
send_locale: LocaleTag.nullable(),
|
|
1755
|
-
languages:
|
|
1756
|
-
fallback:
|
|
1757
|
-
no_language:
|
|
1979
|
+
languages: import_zod8.z.array(MailingLanguage),
|
|
1980
|
+
fallback: import_zod8.z.array(import_zod8.z.object({ wanted: import_zod8.z.string(), planned: import_zod8.z.number().int().min(1) })),
|
|
1981
|
+
no_language: import_zod8.z.number().int().min(0),
|
|
1758
1982
|
/**
|
|
1759
1983
|
* Values that no choice of an insertion takes, so the "otherwise" text goes
|
|
1760
1984
|
* out (docs/plans/2026-09-25-translated-insertions.md, decision 3): per
|
|
@@ -1763,41 +1987,56 @@ var MailingLanguageReport = import_zod7.z.object({
|
|
|
1763
1987
|
* template's keys never produces one; a non-empty list means the client and
|
|
1764
1988
|
* the template have drifted apart.
|
|
1765
1989
|
*/
|
|
1766
|
-
insertion_misses:
|
|
1767
|
-
|
|
1768
|
-
insertion:
|
|
1769
|
-
value:
|
|
1770
|
-
planned:
|
|
1771
|
-
sent:
|
|
1990
|
+
insertion_misses: import_zod8.z.array(
|
|
1991
|
+
import_zod8.z.object({
|
|
1992
|
+
insertion: import_zod8.z.string(),
|
|
1993
|
+
value: import_zod8.z.string(),
|
|
1994
|
+
planned: import_zod8.z.number().int().min(0),
|
|
1995
|
+
sent: import_zod8.z.number().int().min(0)
|
|
1772
1996
|
})
|
|
1773
1997
|
)
|
|
1774
1998
|
});
|
|
1999
|
+
var MailingResolveRequest = import_zod8.z.object({
|
|
2000
|
+
recipients: import_zod8.z.array(RecipientInput).max(MAX_RECIPIENTS_PER_BATCH).optional()
|
|
2001
|
+
});
|
|
2002
|
+
var MailingResolveResult = import_zod8.z.object({
|
|
2003
|
+
/** Every value the mailing's content can read, in order of first appearance, without `email` and `unsubscribe_url`. */
|
|
2004
|
+
names: import_zod8.z.array(import_zod8.z.string()),
|
|
2005
|
+
/** The values and insertions placed inside a link's address: one of them empty for anybody refuses the send. */
|
|
2006
|
+
link_values: import_zod8.z.array(import_zod8.z.string()),
|
|
2007
|
+
/** One entry per resolved recipient, in the request's order; a single entry with `index: null` when none were given. */
|
|
2008
|
+
recipients: import_zod8.z.array(ResolvedRecipient),
|
|
2009
|
+
/** Items not resolved, by their index in the request, for the reasons `mailings.addRecipients` rejects one. */
|
|
2010
|
+
rejected: import_zod8.z.array(import_zod8.z.object({ index: import_zod8.z.number().int().min(0), reason: import_zod8.z.enum(RESOLVE_REJECTIONS) })),
|
|
2011
|
+
/** What would refuse `mailings.send` for these recipients, as its `unfilled_link` refusal lists it; empty means none. */
|
|
2012
|
+
blocking: import_zod8.z.array(UnfilledLink)
|
|
2013
|
+
});
|
|
1775
2014
|
var MessageListQuery = PageQuery.extend({
|
|
1776
2015
|
mailing_id: Id.optional(),
|
|
1777
2016
|
outcome: MessageOutcome.optional()
|
|
1778
2017
|
});
|
|
1779
2018
|
|
|
1780
2019
|
// src/platform.ts
|
|
1781
|
-
var Tag =
|
|
2020
|
+
var Tag = import_zod9.z.object({
|
|
1782
2021
|
id: Id,
|
|
1783
2022
|
slug: Slug,
|
|
1784
|
-
name:
|
|
1785
|
-
contact_count:
|
|
2023
|
+
name: import_zod9.z.string().min(1).max(120),
|
|
2024
|
+
contact_count: import_zod9.z.number().int().min(0),
|
|
1786
2025
|
created_at: Timestamp
|
|
1787
2026
|
});
|
|
1788
|
-
var TagCreate =
|
|
1789
|
-
var TagAssignment =
|
|
1790
|
-
contact_ids:
|
|
2027
|
+
var TagCreate = import_zod9.z.object({ slug: Slug, name: import_zod9.z.string().min(1).max(120) });
|
|
2028
|
+
var TagAssignment = import_zod9.z.object({
|
|
2029
|
+
contact_ids: import_zod9.z.array(Id).min(1).max(1e3)
|
|
1791
2030
|
});
|
|
1792
2031
|
var CONTACT_PROPERTY_TYPES = ["string", "number", "boolean", "date"];
|
|
1793
|
-
var ContactPropertyType =
|
|
1794
|
-
var ContactPropertyKey =
|
|
1795
|
-
var ContactPropertyDefinition =
|
|
2032
|
+
var ContactPropertyType = import_zod9.z.enum(CONTACT_PROPERTY_TYPES);
|
|
2033
|
+
var ContactPropertyKey = import_zod9.z.string().regex(/^[A-Za-z0-9_.-]{1,64}$/, "letters, digits, dot, underscore and hyphen, 1 to 64");
|
|
2034
|
+
var ContactPropertyDefinition = import_zod9.z.object({
|
|
1796
2035
|
key: ContactPropertyKey,
|
|
1797
|
-
label:
|
|
2036
|
+
label: import_zod9.z.string().min(1).max(120),
|
|
1798
2037
|
type: ContactPropertyType
|
|
1799
2038
|
});
|
|
1800
|
-
var ContactPropertyParams =
|
|
2039
|
+
var ContactPropertyParams = import_zod9.z.object({ key: ContactPropertyKey });
|
|
1801
2040
|
var FILTER_OPERATORS = [
|
|
1802
2041
|
"eq",
|
|
1803
2042
|
"neq",
|
|
@@ -1813,8 +2052,8 @@ var FILTER_OPERATORS = [
|
|
|
1813
2052
|
"in",
|
|
1814
2053
|
"not_in"
|
|
1815
2054
|
];
|
|
1816
|
-
var FilterOperator =
|
|
1817
|
-
var FilterField =
|
|
2055
|
+
var FilterOperator = import_zod9.z.enum(FILTER_OPERATORS);
|
|
2056
|
+
var FilterField = import_zod9.z.string().regex(
|
|
1818
2057
|
/^(email|first_name|last_name|locale|created_at|tag|topic|engagement:(opened|clicked)|property:[A-Za-z0-9_.-]{1,64})$/,
|
|
1819
2058
|
"unknown filter field"
|
|
1820
2059
|
);
|
|
@@ -1830,18 +2069,18 @@ var FILTER_FIELD_OPERATORS = {
|
|
|
1830
2069
|
property: FILTER_OPERATORS
|
|
1831
2070
|
};
|
|
1832
2071
|
var MAX_FILTER_DEPTH = 5;
|
|
1833
|
-
var FilterCondition =
|
|
2072
|
+
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), {
|
|
1834
2073
|
message: "exists and not_exists take no value; every other operator needs one",
|
|
1835
2074
|
path: ["value"]
|
|
1836
2075
|
}).refine((c) => c.op !== "in" && c.op !== "not_in" || Array.isArray(c.value), {
|
|
1837
2076
|
message: "in and not_in take an array",
|
|
1838
2077
|
path: ["value"]
|
|
1839
2078
|
});
|
|
1840
|
-
var SegmentFilter =
|
|
1841
|
-
() =>
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
2079
|
+
var SegmentFilter = import_zod9.z.lazy(
|
|
2080
|
+
() => import_zod9.z.union([
|
|
2081
|
+
import_zod9.z.object({ and: import_zod9.z.array(SegmentFilter).min(1).max(50) }).strict(),
|
|
2082
|
+
import_zod9.z.object({ or: import_zod9.z.array(SegmentFilter).min(1).max(50) }).strict(),
|
|
2083
|
+
import_zod9.z.object({ not: SegmentFilter }).strict(),
|
|
1845
2084
|
FilterCondition
|
|
1846
2085
|
])
|
|
1847
2086
|
);
|
|
@@ -1929,42 +2168,42 @@ function untypedValueProblem(c, every) {
|
|
|
1929
2168
|
if (orderOp) return every(isFilterNumber, "numbers (define the property to compare dates)");
|
|
1930
2169
|
return every((v) => isScalar(v) || v === null, "strings, numbers, booleans or null");
|
|
1931
2170
|
}
|
|
1932
|
-
var Segment =
|
|
2171
|
+
var Segment = import_zod9.z.object({
|
|
1933
2172
|
id: Id,
|
|
1934
|
-
name:
|
|
2173
|
+
name: import_zod9.z.string().min(1).max(120),
|
|
1935
2174
|
filter: SegmentFilter,
|
|
1936
2175
|
/** Computed on read. */
|
|
1937
|
-
contact_count:
|
|
2176
|
+
contact_count: import_zod9.z.number().int().min(0),
|
|
1938
2177
|
created_at: Timestamp,
|
|
1939
2178
|
updated_at: Timestamp
|
|
1940
2179
|
});
|
|
1941
|
-
var SegmentCreate =
|
|
1942
|
-
var SegmentPreviewRequest =
|
|
1943
|
-
var SegmentPreview =
|
|
1944
|
-
contact_count:
|
|
2180
|
+
var SegmentCreate = import_zod9.z.object({ name: import_zod9.z.string().min(1).max(120), filter: BoundedSegmentFilter });
|
|
2181
|
+
var SegmentPreviewRequest = import_zod9.z.object({ filter: BoundedSegmentFilter });
|
|
2182
|
+
var SegmentPreview = import_zod9.z.object({
|
|
2183
|
+
contact_count: import_zod9.z.number().int().min(0),
|
|
1945
2184
|
/** Up to five matching contacts, for a human to sanity-check the filter. */
|
|
1946
|
-
sample:
|
|
2185
|
+
sample: import_zod9.z.array(import_zod9.z.object({ id: Id, email: Email })).max(5)
|
|
1947
2186
|
});
|
|
1948
|
-
var MailingAudienceFromSegment =
|
|
2187
|
+
var MailingAudienceFromSegment = import_zod9.z.object({ segment_id: Id });
|
|
1949
2188
|
var SIGNUP_FORM_FIELDS = ["first_name", "last_name"];
|
|
1950
2189
|
var HOSTED_PAGE_LOCALES = ["en", "de", "it", "fr", "es"];
|
|
1951
|
-
var SignupFormTranslation =
|
|
1952
|
-
title:
|
|
1953
|
-
consent_text:
|
|
2190
|
+
var SignupFormTranslation = import_zod9.z.object({
|
|
2191
|
+
title: import_zod9.z.string().min(1).max(120),
|
|
2192
|
+
consent_text: import_zod9.z.string().min(1).max(2e3)
|
|
1954
2193
|
});
|
|
1955
|
-
var SignupForm =
|
|
2194
|
+
var SignupForm = import_zod9.z.object({
|
|
1956
2195
|
id: Id,
|
|
1957
|
-
name:
|
|
2196
|
+
name: import_zod9.z.string().min(1).max(120),
|
|
1958
2197
|
/** The heading of the hosted page. */
|
|
1959
|
-
title:
|
|
2198
|
+
title: import_zod9.z.string().min(1).max(120),
|
|
1960
2199
|
/** What the person agrees to, shown above the button and recorded with the confirmation. */
|
|
1961
|
-
consent_text:
|
|
1962
|
-
translations:
|
|
1963
|
-
topics:
|
|
1964
|
-
tags:
|
|
2200
|
+
consent_text: import_zod9.z.string().min(1).max(2e3),
|
|
2201
|
+
translations: import_zod9.z.record(SignupFormTranslation),
|
|
2202
|
+
topics: import_zod9.z.array(Slug).min(1),
|
|
2203
|
+
tags: import_zod9.z.array(Slug),
|
|
1965
2204
|
/** Fields shown besides email. */
|
|
1966
|
-
fields:
|
|
1967
|
-
double_opt_in:
|
|
2205
|
+
fields: import_zod9.z.array(import_zod9.z.enum(SIGNUP_FORM_FIELDS)),
|
|
2206
|
+
double_opt_in: import_zod9.z.literal(true),
|
|
1968
2207
|
/** The provider the confirmation mail is sent through. */
|
|
1969
2208
|
provider_id: Id,
|
|
1970
2209
|
/**
|
|
@@ -1973,11 +2212,11 @@ var SignupForm = import_zod8.z.object({
|
|
|
1973
2212
|
*/
|
|
1974
2213
|
confirmation_template_id: Id.nullable(),
|
|
1975
2214
|
/** Where the person lands after confirming. Null shows the hosted confirmation page. */
|
|
1976
|
-
redirect_url:
|
|
2215
|
+
redirect_url: import_zod9.z.string().url().nullable(),
|
|
1977
2216
|
/** Origins allowed to embed the form and call the submission route from a browser. */
|
|
1978
|
-
allowed_origins:
|
|
2217
|
+
allowed_origins: import_zod9.z.array(import_zod9.z.string().url()).max(20),
|
|
1979
2218
|
/** Bumped on every change; recorded with each confirmation. */
|
|
1980
|
-
version:
|
|
2219
|
+
version: import_zod9.z.number().int().min(1),
|
|
1981
2220
|
created_at: Timestamp,
|
|
1982
2221
|
updated_at: Timestamp
|
|
1983
2222
|
});
|
|
@@ -1992,56 +2231,56 @@ var SignupFormCreate = SignupForm.omit({
|
|
|
1992
2231
|
tags: SignupForm.shape.tags.optional(),
|
|
1993
2232
|
fields: SignupForm.shape.fields.optional(),
|
|
1994
2233
|
confirmation_template_id: Id.nullable().optional(),
|
|
1995
|
-
redirect_url:
|
|
2234
|
+
redirect_url: import_zod9.z.string().url().nullable().optional(),
|
|
1996
2235
|
allowed_origins: SignupForm.shape.allowed_origins.optional()
|
|
1997
2236
|
});
|
|
1998
|
-
var SignupFormEmbed =
|
|
1999
|
-
hosted_url:
|
|
2237
|
+
var SignupFormEmbed = import_zod9.z.object({
|
|
2238
|
+
hosted_url: import_zod9.z.string().url(),
|
|
2000
2239
|
/** A plain HTML form posting to the hosted page; works without JavaScript. */
|
|
2001
|
-
html:
|
|
2240
|
+
html: import_zod9.z.string(),
|
|
2002
2241
|
/** A small optional script that adds the time check and submits in place. */
|
|
2003
|
-
script_url:
|
|
2242
|
+
script_url: import_zod9.z.string().url(),
|
|
2004
2243
|
/** Where a browser fetches a fresh `form_token` from (GET, public, CORS for `allowed_origins`). */
|
|
2005
|
-
token_url:
|
|
2244
|
+
token_url: import_zod9.z.string().url()
|
|
2006
2245
|
});
|
|
2007
|
-
var SignupSubmission =
|
|
2246
|
+
var SignupSubmission = import_zod9.z.object({
|
|
2008
2247
|
email: Email,
|
|
2009
|
-
first_name:
|
|
2010
|
-
last_name:
|
|
2011
|
-
locale:
|
|
2248
|
+
first_name: import_zod9.z.string().max(200).optional(),
|
|
2249
|
+
last_name: import_zod9.z.string().max(200).optional(),
|
|
2250
|
+
locale: import_zod9.z.string().min(2).max(35).optional(),
|
|
2012
2251
|
/** Honeypot: must be empty. */
|
|
2013
|
-
website:
|
|
2252
|
+
website: import_zod9.z.string().max(0).optional(),
|
|
2014
2253
|
/**
|
|
2015
2254
|
* The signed render time from the form's token URL: a submission sooner than a
|
|
2016
2255
|
* human could fill the form, or long after, is refused.
|
|
2017
2256
|
*/
|
|
2018
|
-
form_token:
|
|
2257
|
+
form_token: import_zod9.z.string().min(1).max(512)
|
|
2019
2258
|
});
|
|
2020
2259
|
var IMPORT_STATUSES = ["uploaded", "validating", "validated", "committing", "completed", "failed", "cancelled"];
|
|
2021
|
-
var ImportStatus =
|
|
2260
|
+
var ImportStatus = import_zod9.z.enum(IMPORT_STATUSES);
|
|
2022
2261
|
var IMPORT_TERMINAL_STATUSES = ["completed", "failed", "cancelled"];
|
|
2023
|
-
var ImportColumnMapping =
|
|
2024
|
-
|
|
2262
|
+
var ImportColumnMapping = import_zod9.z.record(
|
|
2263
|
+
import_zod9.z.string().regex(/^(email|external_id|first_name|last_name|locale|property:[A-Za-z0-9_.-]{1,64}|ignore)$/)
|
|
2025
2264
|
);
|
|
2026
2265
|
var IMPORT_FILE_FIELD = "file";
|
|
2027
2266
|
var MAX_IMPORT_BYTES = 50 * 1024 * 1024;
|
|
2028
2267
|
var MAX_IMPORT_ROWS = 2e5;
|
|
2029
|
-
var ImportMappingRequest =
|
|
2268
|
+
var ImportMappingRequest = import_zod9.z.object({
|
|
2030
2269
|
/** CSV header -> contact field. Exactly one column maps to `email`. */
|
|
2031
2270
|
mapping: ImportColumnMapping.refine(
|
|
2032
2271
|
(m) => Object.values(m).filter((v) => v === "email").length === 1,
|
|
2033
2272
|
"exactly one column maps to email"
|
|
2034
2273
|
),
|
|
2035
|
-
topics:
|
|
2036
|
-
tags:
|
|
2274
|
+
topics: import_zod9.z.array(Slug).max(100),
|
|
2275
|
+
tags: import_zod9.z.array(Slug).max(100),
|
|
2037
2276
|
/** Existing contacts get the mapped fields overwritten; false only adds topics, tags and missing fields. */
|
|
2038
|
-
update_existing:
|
|
2277
|
+
update_existing: import_zod9.z.boolean().optional(),
|
|
2039
2278
|
/** The importer states the people consented; the service records who said so and when. */
|
|
2040
|
-
consent_confirmed:
|
|
2279
|
+
consent_confirmed: import_zod9.z.literal(true)
|
|
2041
2280
|
});
|
|
2042
|
-
var ImportCommitRequest =
|
|
2281
|
+
var ImportCommitRequest = import_zod9.z.object({ mapping_version: import_zod9.z.number().int().min(1) });
|
|
2043
2282
|
var IMPORT_ROW_OUTCOMES = ["created", "updated", "unchanged", "suppressed", "skipped"];
|
|
2044
|
-
var ImportRowOutcome =
|
|
2283
|
+
var ImportRowOutcome = import_zod9.z.enum(IMPORT_ROW_OUTCOMES);
|
|
2045
2284
|
var IMPORT_SKIP_REASONS = [
|
|
2046
2285
|
"missing_email",
|
|
2047
2286
|
"invalid_email",
|
|
@@ -2050,90 +2289,90 @@ var IMPORT_SKIP_REASONS = [
|
|
|
2050
2289
|
"external_id_conflict",
|
|
2051
2290
|
"wrong_column_count"
|
|
2052
2291
|
];
|
|
2053
|
-
var ImportSkipReason =
|
|
2054
|
-
var ImportReport =
|
|
2055
|
-
created:
|
|
2056
|
-
updated:
|
|
2057
|
-
unchanged:
|
|
2058
|
-
suppressed:
|
|
2059
|
-
skipped:
|
|
2060
|
-
skipped_by_reason:
|
|
2292
|
+
var ImportSkipReason = import_zod9.z.enum(IMPORT_SKIP_REASONS);
|
|
2293
|
+
var ImportReport = import_zod9.z.object({
|
|
2294
|
+
created: import_zod9.z.number().int().min(0),
|
|
2295
|
+
updated: import_zod9.z.number().int().min(0),
|
|
2296
|
+
unchanged: import_zod9.z.number().int().min(0),
|
|
2297
|
+
suppressed: import_zod9.z.number().int().min(0),
|
|
2298
|
+
skipped: import_zod9.z.number().int().min(0),
|
|
2299
|
+
skipped_by_reason: import_zod9.z.record(ImportSkipReason, import_zod9.z.number().int().min(0)),
|
|
2061
2300
|
/** Rows whose contact was subscribed without some topic, because the address is blocked for it. */
|
|
2062
|
-
topics_withheld:
|
|
2301
|
+
topics_withheld: import_zod9.z.number().int().min(0)
|
|
2063
2302
|
});
|
|
2064
|
-
var ImportJob =
|
|
2303
|
+
var ImportJob = import_zod9.z.object({
|
|
2065
2304
|
id: Id,
|
|
2066
2305
|
status: ImportStatus,
|
|
2067
|
-
file_name:
|
|
2068
|
-
file_bytes:
|
|
2069
|
-
total_rows:
|
|
2306
|
+
file_name: import_zod9.z.string().max(255).nullable(),
|
|
2307
|
+
file_bytes: import_zod9.z.number().int().min(0),
|
|
2308
|
+
total_rows: import_zod9.z.number().int().min(0),
|
|
2070
2309
|
/** The header row, as in the file. */
|
|
2071
|
-
columns:
|
|
2310
|
+
columns: import_zod9.z.array(import_zod9.z.string()),
|
|
2072
2311
|
/** The first rows, for the mapping screen. */
|
|
2073
|
-
sample:
|
|
2312
|
+
sample: import_zod9.z.array(import_zod9.z.array(import_zod9.z.string())).max(5),
|
|
2074
2313
|
/** A mapping guessed from the headers, for the mapping screen to start from. */
|
|
2075
2314
|
suggested_mapping: ImportColumnMapping,
|
|
2076
2315
|
mapping: ImportColumnMapping.nullable(),
|
|
2077
|
-
mapping_version:
|
|
2078
|
-
topics:
|
|
2079
|
-
tags:
|
|
2080
|
-
update_existing:
|
|
2316
|
+
mapping_version: import_zod9.z.number().int().min(0),
|
|
2317
|
+
topics: import_zod9.z.array(Slug),
|
|
2318
|
+
tags: import_zod9.z.array(Slug),
|
|
2319
|
+
update_existing: import_zod9.z.boolean(),
|
|
2081
2320
|
/** The dry run of the current mapping; null before one finished. */
|
|
2082
2321
|
dry_run: ImportReport.nullable(),
|
|
2083
2322
|
/** What the commit has written so far; null before it started. */
|
|
2084
2323
|
result: ImportReport.nullable(),
|
|
2085
2324
|
/** Rows the current phase (dry run or commit) has processed. */
|
|
2086
|
-
processed_rows:
|
|
2325
|
+
processed_rows: import_zod9.z.number().int().min(0),
|
|
2087
2326
|
/** Why a `failed` import failed. */
|
|
2088
|
-
error:
|
|
2327
|
+
error: import_zod9.z.string().nullable(),
|
|
2089
2328
|
created_at: Timestamp,
|
|
2090
2329
|
updated_at: Timestamp,
|
|
2091
2330
|
finished_at: Timestamp.nullable()
|
|
2092
2331
|
});
|
|
2093
|
-
var ImportRow =
|
|
2332
|
+
var ImportRow = import_zod9.z.object({
|
|
2094
2333
|
/** The line in the file, 1 being the first line after the header. */
|
|
2095
|
-
row:
|
|
2096
|
-
email:
|
|
2334
|
+
row: import_zod9.z.number().int().min(1),
|
|
2335
|
+
email: import_zod9.z.string().nullable(),
|
|
2097
2336
|
outcome: ImportRowOutcome,
|
|
2098
2337
|
reason: ImportSkipReason.nullable(),
|
|
2099
2338
|
/** A human explanation for a skipped row (which value, which column). */
|
|
2100
|
-
message:
|
|
2339
|
+
message: import_zod9.z.string().nullable(),
|
|
2101
2340
|
contact_id: Id.nullable()
|
|
2102
2341
|
});
|
|
2103
2342
|
var ImportRowListQuery = PageQuery.extend({ outcome: ImportRowOutcome.optional() });
|
|
2104
|
-
var MailingScheduleRequest =
|
|
2105
|
-
var TrackingSettings =
|
|
2106
|
-
var VariantAnalytics =
|
|
2107
|
-
key:
|
|
2108
|
-
sent:
|
|
2109
|
-
unique_opens:
|
|
2110
|
-
unique_clicks:
|
|
2111
|
-
});
|
|
2112
|
-
var MailingAnalytics =
|
|
2343
|
+
var MailingScheduleRequest = import_zod9.z.object({ send_at: Timestamp });
|
|
2344
|
+
var TrackingSettings = import_zod9.z.object({ opens: import_zod9.z.boolean(), clicks: import_zod9.z.boolean() });
|
|
2345
|
+
var VariantAnalytics = import_zod9.z.object({
|
|
2346
|
+
key: import_zod9.z.string(),
|
|
2347
|
+
sent: import_zod9.z.number().int().min(0),
|
|
2348
|
+
unique_opens: import_zod9.z.number().int().min(0).nullable(),
|
|
2349
|
+
unique_clicks: import_zod9.z.number().int().min(0).nullable()
|
|
2350
|
+
});
|
|
2351
|
+
var MailingAnalytics = import_zod9.z.object({
|
|
2113
2352
|
mailing_id: Id,
|
|
2114
2353
|
counts: MailingCounts,
|
|
2115
2354
|
/** What was tracked for this mailing, fixed when it started; null before it started. */
|
|
2116
2355
|
tracking: TrackingSettings.nullable(),
|
|
2117
2356
|
/** Unique recipients with a human open. Null when opens were not tracked. */
|
|
2118
|
-
unique_opens:
|
|
2357
|
+
unique_opens: import_zod9.z.number().int().min(0).nullable(),
|
|
2119
2358
|
/**
|
|
2120
2359
|
* Recipients whose only opens came from Apple Mail Privacy Protection, which
|
|
2121
2360
|
* loads every image on delivery: counted apart, never as human opens.
|
|
2122
2361
|
*/
|
|
2123
|
-
apple_mpp_opens:
|
|
2362
|
+
apple_mpp_opens: import_zod9.z.number().int().min(0).nullable(),
|
|
2124
2363
|
/** Opens and clicks from security scanners and prefetchers, filtered out of the unique counts. */
|
|
2125
|
-
machine_events:
|
|
2126
|
-
unique_clicks:
|
|
2127
|
-
unsubscribes:
|
|
2128
|
-
bounces:
|
|
2129
|
-
complaints:
|
|
2130
|
-
links:
|
|
2131
|
-
variants:
|
|
2364
|
+
machine_events: import_zod9.z.number().int().min(0).nullable(),
|
|
2365
|
+
unique_clicks: import_zod9.z.number().int().min(0).nullable(),
|
|
2366
|
+
unsubscribes: import_zod9.z.number().int().min(0),
|
|
2367
|
+
bounces: import_zod9.z.number().int().min(0),
|
|
2368
|
+
complaints: import_zod9.z.number().int().min(0),
|
|
2369
|
+
links: import_zod9.z.array(import_zod9.z.object({ url: import_zod9.z.string(), unique_clicks: import_zod9.z.number().int().min(0) })).nullable(),
|
|
2370
|
+
variants: import_zod9.z.array(VariantAnalytics).nullable()
|
|
2132
2371
|
});
|
|
2133
2372
|
|
|
2134
2373
|
// src/automations.ts
|
|
2135
2374
|
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})$/;
|
|
2136
|
-
var AutomationFilterField =
|
|
2375
|
+
var AutomationFilterField = import_zod10.z.string().regex(AUTOMATION_FILTER_FIELD_PATTERN, "unknown filter field");
|
|
2137
2376
|
var AUTOMATION_FILTER_FIELD_OPERATORS = {
|
|
2138
2377
|
...FILTER_FIELD_OPERATORS,
|
|
2139
2378
|
segment: ["eq", "neq", "in", "not_in"],
|
|
@@ -2143,18 +2382,18 @@ var AUTOMATION_FILTER_FIELD_OPERATORS = {
|
|
|
2143
2382
|
step: ["eq", "neq"]
|
|
2144
2383
|
};
|
|
2145
2384
|
var automationFilterFamily = filterFieldFamily;
|
|
2146
|
-
var AutomationFilterCondition =
|
|
2385
|
+
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), {
|
|
2147
2386
|
message: "exists and not_exists take no value; every other operator needs one",
|
|
2148
2387
|
path: ["value"]
|
|
2149
2388
|
}).refine((c) => c.op !== "in" && c.op !== "not_in" || Array.isArray(c.value), {
|
|
2150
2389
|
message: "in and not_in take an array",
|
|
2151
2390
|
path: ["value"]
|
|
2152
2391
|
});
|
|
2153
|
-
var AutomationFilter =
|
|
2154
|
-
() =>
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2392
|
+
var AutomationFilter = import_zod10.z.lazy(
|
|
2393
|
+
() => import_zod10.z.union([
|
|
2394
|
+
import_zod10.z.object({ and: import_zod10.z.array(AutomationFilter).min(1).max(50) }).strict(),
|
|
2395
|
+
import_zod10.z.object({ or: import_zod10.z.array(AutomationFilter).min(1).max(50) }).strict(),
|
|
2396
|
+
import_zod10.z.object({ not: AutomationFilter }).strict(),
|
|
2158
2397
|
AutomationFilterCondition
|
|
2159
2398
|
])
|
|
2160
2399
|
);
|
|
@@ -2167,20 +2406,20 @@ function filterConditions(filter) {
|
|
|
2167
2406
|
if ("not" in filter) return filterConditions(filter.not);
|
|
2168
2407
|
return [filter];
|
|
2169
2408
|
}
|
|
2170
|
-
var StepId =
|
|
2171
|
-
var TimeOfDay =
|
|
2172
|
-
var Weekday =
|
|
2173
|
-
var TimezoneName =
|
|
2409
|
+
var StepId = import_zod10.z.string().regex(/^[A-Za-z0-9_-]{1,64}$/, "letters, digits, underscore and hyphen, 1 to 64");
|
|
2410
|
+
var TimeOfDay = import_zod10.z.string().regex(/^([01]\d|2[0-3]):[0-5]\d$/, "HH:MM in 24 hours");
|
|
2411
|
+
var Weekday = import_zod10.z.number().int().min(0).max(6);
|
|
2412
|
+
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");
|
|
2174
2413
|
var MAX_DELAY_SECONDS = 365 * 24 * 60 * 60;
|
|
2175
|
-
var DateOnly =
|
|
2414
|
+
var DateOnly = import_zod10.z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "a calendar date such as 2026-09-20").refine((v) => {
|
|
2176
2415
|
const [y, m, d] = v.split("-").map(Number);
|
|
2177
2416
|
const t = new Date(Date.UTC(y, m - 1, d));
|
|
2178
2417
|
return t.getUTCFullYear() === y && t.getUTCMonth() + 1 === m && t.getUTCDate() === d;
|
|
2179
2418
|
}, "a real calendar date");
|
|
2180
|
-
var OffsetDays =
|
|
2419
|
+
var OffsetDays = import_zod10.z.number().int().min(-365).max(365);
|
|
2181
2420
|
var DATE_PASSED_ANSWERS = ["skip", "stop", "continue"];
|
|
2182
|
-
var DatePassedAnswer =
|
|
2183
|
-
var EventName =
|
|
2421
|
+
var DatePassedAnswer = import_zod10.z.enum(DATE_PASSED_ANSWERS);
|
|
2422
|
+
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");
|
|
2184
2423
|
var AUTOMATION_TRIGGER_KINDS = [
|
|
2185
2424
|
"topic_subscribed",
|
|
2186
2425
|
"form_confirmed",
|
|
@@ -2193,17 +2432,17 @@ var AUTOMATION_TRIGGER_KINDS = [
|
|
|
2193
2432
|
"segment_entered",
|
|
2194
2433
|
"link_clicked"
|
|
2195
2434
|
];
|
|
2196
|
-
var AutomationTriggerKind =
|
|
2435
|
+
var AutomationTriggerKind = import_zod10.z.enum(AUTOMATION_TRIGGER_KINDS);
|
|
2197
2436
|
var exclude = { exclude: BoundedAutomationFilter.nullish() };
|
|
2198
|
-
var AutomationTrigger =
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2437
|
+
var AutomationTrigger = import_zod10.z.discriminatedUnion("kind", [
|
|
2438
|
+
import_zod10.z.object({ kind: import_zod10.z.literal("topic_subscribed"), topic: Slug, ...exclude }).strict(),
|
|
2439
|
+
import_zod10.z.object({ kind: import_zod10.z.literal("form_confirmed"), form_id: Id, ...exclude }).strict(),
|
|
2440
|
+
import_zod10.z.object({ kind: import_zod10.z.literal("tag_added"), tag: Slug, ...exclude }).strict(),
|
|
2202
2441
|
/** `to` given: only a change that lands on this value fires. Absent: any change of the key. */
|
|
2203
|
-
|
|
2442
|
+
import_zod10.z.object({ kind: import_zod10.z.literal("property_changed"), key: ContactPropertyKey, to: JsonValue.optional(), ...exclude }).strict(),
|
|
2204
2443
|
/** `where` filters the event's own data, so only `event:<key>` leaves belong in it. */
|
|
2205
|
-
|
|
2206
|
-
|
|
2444
|
+
import_zod10.z.object({ kind: import_zod10.z.literal("event"), name: EventName, where: BoundedAutomationFilter.nullish(), ...exclude }).strict(),
|
|
2445
|
+
import_zod10.z.object({ kind: import_zod10.z.literal("manual"), ...exclude }).strict(),
|
|
2207
2446
|
/**
|
|
2208
2447
|
* Every year on a date the contact carries: a birthday, a joining date, a
|
|
2209
2448
|
* renewal. `offset_days` moves it ("three days before"), `at` is the wall
|
|
@@ -2213,8 +2452,8 @@ var AutomationTrigger = import_zod9.z.discriminatedUnion("kind", [
|
|
|
2213
2452
|
* A 29 February date fires on 1 March in a year that has no 29 February, so
|
|
2214
2453
|
* nobody is skipped every fourth year.
|
|
2215
2454
|
*/
|
|
2216
|
-
|
|
2217
|
-
kind:
|
|
2455
|
+
import_zod10.z.object({
|
|
2456
|
+
kind: import_zod10.z.literal("date_anniversary"),
|
|
2218
2457
|
key: ContactPropertyKey,
|
|
2219
2458
|
offset_days: OffsetDays,
|
|
2220
2459
|
at: TimeOfDay,
|
|
@@ -2226,8 +2465,8 @@ var AutomationTrigger = import_zod9.z.discriminatedUnion("kind", [
|
|
|
2226
2465
|
* not ask about a segment or about an event's data: there is no event, and a
|
|
2227
2466
|
* segment is its own trigger kind.
|
|
2228
2467
|
*/
|
|
2229
|
-
|
|
2230
|
-
kind:
|
|
2468
|
+
import_zod10.z.object({
|
|
2469
|
+
kind: import_zod10.z.literal("exact_date"),
|
|
2231
2470
|
on: DateOnly,
|
|
2232
2471
|
at: TimeOfDay,
|
|
2233
2472
|
where: BoundedAutomationFilter.nullish(),
|
|
@@ -2246,7 +2485,7 @@ var AutomationTrigger = import_zod9.z.discriminatedUnion("kind", [
|
|
|
2246
2485
|
* already exists. Entering those people as well is the publish dialog's
|
|
2247
2486
|
* backfill question, answered by a person rather than by the sweep.
|
|
2248
2487
|
*/
|
|
2249
|
-
|
|
2488
|
+
import_zod10.z.object({ kind: import_zod10.z.literal("segment_entered"), segment_id: Id, ...exclude }).strict(),
|
|
2250
2489
|
/**
|
|
2251
2490
|
* S4. When somebody clicks a link in a mailing that has already gone out.
|
|
2252
2491
|
*
|
|
@@ -2256,7 +2495,7 @@ var AutomationTrigger = import_zod9.z.discriminatedUnion("kind", [
|
|
|
2256
2495
|
* tracking off there is no click to hear about, so the validator refuses it
|
|
2257
2496
|
* rather than leaving an automation that can never fire.
|
|
2258
2497
|
*/
|
|
2259
|
-
|
|
2498
|
+
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()
|
|
2260
2499
|
]);
|
|
2261
2500
|
var AUTOMATION_DATE_TRIGGER_KINDS = ["date_anniversary", "exact_date"];
|
|
2262
2501
|
var MAX_TRIGGERS = 10;
|
|
@@ -2275,45 +2514,45 @@ var AUTOMATION_STEP_KINDS = [
|
|
|
2275
2514
|
"webhook",
|
|
2276
2515
|
"notify"
|
|
2277
2516
|
];
|
|
2278
|
-
var AutomationStepKind =
|
|
2517
|
+
var AutomationStepKind = import_zod10.z.enum(AUTOMATION_STEP_KINDS);
|
|
2279
2518
|
var next = { next: StepId.nullable() };
|
|
2280
|
-
var Unchosen =
|
|
2281
|
-
var DraftSlug =
|
|
2282
|
-
var DraftPropertyKey =
|
|
2283
|
-
var label2 = { label:
|
|
2284
|
-
var EmailStepLanguage =
|
|
2285
|
-
subject:
|
|
2286
|
-
preheader:
|
|
2519
|
+
var Unchosen = import_zod10.z.literal("");
|
|
2520
|
+
var DraftSlug = import_zod10.z.union([Slug, Unchosen]);
|
|
2521
|
+
var DraftPropertyKey = import_zod10.z.union([ContactPropertyKey, Unchosen]);
|
|
2522
|
+
var label2 = { label: import_zod10.z.string().max(120).nullish() };
|
|
2523
|
+
var EmailStepLanguage = import_zod10.z.object({
|
|
2524
|
+
subject: import_zod10.z.string().min(1).max(998),
|
|
2525
|
+
preheader: import_zod10.z.string().max(500).nullable(),
|
|
2287
2526
|
document: TemplateDocument,
|
|
2288
2527
|
/** This language's insertions, its texts over the template's structure (every text present). */
|
|
2289
2528
|
insertions: Insertions.nullish()
|
|
2290
2529
|
}).strict();
|
|
2291
|
-
var EmailStep =
|
|
2292
|
-
kind:
|
|
2530
|
+
var EmailStep = import_zod10.z.object({
|
|
2531
|
+
kind: import_zod10.z.literal("email"),
|
|
2293
2532
|
...label2,
|
|
2294
2533
|
...next,
|
|
2295
2534
|
template_id: Id.nullish(),
|
|
2296
2535
|
document: TemplateDocument.nullish(),
|
|
2297
2536
|
/** Empty while the step is being written, or when its template has a subject; else `not_chosen` refuses to publish it. */
|
|
2298
|
-
subject:
|
|
2299
|
-
preheader:
|
|
2537
|
+
subject: import_zod10.z.string().max(998),
|
|
2538
|
+
preheader: import_zod10.z.string().max(500).nullish(),
|
|
2300
2539
|
locale: LocaleTag.nullish(),
|
|
2301
|
-
languages:
|
|
2540
|
+
languages: import_zod10.z.record(LocaleTag, EmailStepLanguage).nullish(),
|
|
2302
2541
|
/** The main language's insertions, snapshot from the template when the automation is published. */
|
|
2303
2542
|
insertions: Insertions.nullish()
|
|
2304
2543
|
}).strict();
|
|
2305
|
-
var DelayStep =
|
|
2306
|
-
kind:
|
|
2544
|
+
var DelayStep = import_zod10.z.object({
|
|
2545
|
+
kind: import_zod10.z.literal("delay"),
|
|
2307
2546
|
...label2,
|
|
2308
2547
|
...next,
|
|
2309
|
-
wait:
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2548
|
+
wait: import_zod10.z.discriminatedUnion("mode", [
|
|
2549
|
+
import_zod10.z.object({ mode: import_zod10.z.literal("duration"), seconds: import_zod10.z.number().int().min(1).max(MAX_DELAY_SECONDS) }).strict(),
|
|
2550
|
+
import_zod10.z.object({ mode: import_zod10.z.literal("time_of_day"), at: TimeOfDay }).strict(),
|
|
2551
|
+
import_zod10.z.object({ mode: import_zod10.z.literal("weekday"), weekday: Weekday, at: TimeOfDay }).strict(),
|
|
2313
2552
|
/** A fixed day has no next occurrence, so `continue` is not one of its answers. */
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
mode:
|
|
2553
|
+
import_zod10.z.object({ mode: import_zod10.z.literal("date"), on: DateOnly, at: TimeOfDay, passed: import_zod10.z.enum(["skip", "stop"]) }).strict(),
|
|
2554
|
+
import_zod10.z.object({
|
|
2555
|
+
mode: import_zod10.z.literal("date_property"),
|
|
2317
2556
|
key: ContactPropertyKey,
|
|
2318
2557
|
offset_days: OffsetDays,
|
|
2319
2558
|
at: TimeOfDay,
|
|
@@ -2321,8 +2560,8 @@ var DelayStep = import_zod9.z.object({
|
|
|
2321
2560
|
}).strict()
|
|
2322
2561
|
])
|
|
2323
2562
|
}).strict();
|
|
2324
|
-
var ConditionStep =
|
|
2325
|
-
kind:
|
|
2563
|
+
var ConditionStep = import_zod10.z.object({
|
|
2564
|
+
kind: import_zod10.z.literal("condition"),
|
|
2326
2565
|
...label2,
|
|
2327
2566
|
filter: BoundedAutomationFilter,
|
|
2328
2567
|
yes: StepId.nullable(),
|
|
@@ -2333,49 +2572,49 @@ var ConditionStep = import_zod9.z.object({
|
|
|
2333
2572
|
* neither half means anything without the other: a window with no answer
|
|
2334
2573
|
* for the end of it would be a silent decision.
|
|
2335
2574
|
*/
|
|
2336
|
-
wait_for:
|
|
2575
|
+
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()
|
|
2337
2576
|
}).strict();
|
|
2338
|
-
var SplitBranchKey =
|
|
2577
|
+
var SplitBranchKey = import_zod10.z.string().regex(/^[A-Za-z0-9_-]{1,32}$/, "letters, digits, underscore and hyphen, 1 to 32");
|
|
2339
2578
|
var MIN_SPLIT_BRANCHES = 2;
|
|
2340
2579
|
var MAX_SPLIT_BRANCHES = 4;
|
|
2341
|
-
var SplitStep =
|
|
2342
|
-
kind:
|
|
2580
|
+
var SplitStep = import_zod10.z.object({
|
|
2581
|
+
kind: import_zod10.z.literal("split"),
|
|
2343
2582
|
...label2,
|
|
2344
|
-
branches:
|
|
2345
|
-
|
|
2583
|
+
branches: import_zod10.z.array(
|
|
2584
|
+
import_zod10.z.object({
|
|
2346
2585
|
key: SplitBranchKey,
|
|
2347
2586
|
/** A whole percentage. Zero is allowed: a branch kept in the flow but switched off. */
|
|
2348
|
-
weight:
|
|
2587
|
+
weight: import_zod10.z.number().int().min(0).max(100),
|
|
2349
2588
|
next: StepId.nullable()
|
|
2350
2589
|
}).strict()
|
|
2351
2590
|
).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")
|
|
2352
2591
|
}).strict();
|
|
2353
|
-
var GotoStep =
|
|
2592
|
+
var GotoStep = import_zod10.z.object({ kind: import_zod10.z.literal("goto"), ...label2, target: StepId.nullable() }).strict();
|
|
2354
2593
|
var MAX_STEP_VISITS = 20;
|
|
2355
|
-
var WebhookStep =
|
|
2356
|
-
var NotifyRecipients =
|
|
2357
|
-
var NotifyStep =
|
|
2358
|
-
kind:
|
|
2594
|
+
var WebhookStep = import_zod10.z.object({ kind: import_zod10.z.literal("webhook"), ...label2, ...next, endpoint_id: Id.nullable(), payload: JsonValue.nullish() }).strict();
|
|
2595
|
+
var NotifyRecipients = import_zod10.z.union([import_zod10.z.literal("owner"), import_zod10.z.literal("admins"), import_zod10.z.object({ member_id: Id }).strict()]);
|
|
2596
|
+
var NotifyStep = import_zod10.z.object({
|
|
2597
|
+
kind: import_zod10.z.literal("notify"),
|
|
2359
2598
|
...label2,
|
|
2360
2599
|
...next,
|
|
2361
2600
|
to: NotifyRecipients,
|
|
2362
2601
|
/** Empty while the step is being written; `not_chosen` refuses to publish it. */
|
|
2363
|
-
subject:
|
|
2364
|
-
body:
|
|
2602
|
+
subject: import_zod10.z.string().max(998),
|
|
2603
|
+
body: import_zod10.z.string().max(1e4)
|
|
2365
2604
|
}).strict();
|
|
2366
|
-
var AutomationStep =
|
|
2605
|
+
var AutomationStep = import_zod10.z.discriminatedUnion("kind", [
|
|
2367
2606
|
EmailStep,
|
|
2368
2607
|
DelayStep,
|
|
2369
2608
|
ConditionStep,
|
|
2370
|
-
|
|
2371
|
-
|
|
2609
|
+
import_zod10.z.object({ kind: import_zod10.z.literal("add_tag"), ...label2, ...next, tag: DraftSlug }).strict(),
|
|
2610
|
+
import_zod10.z.object({ kind: import_zod10.z.literal("remove_tag"), ...label2, ...next, tag: DraftSlug }).strict(),
|
|
2372
2611
|
/** `value` null clears the property, as a contact upsert does. */
|
|
2373
|
-
|
|
2612
|
+
import_zod10.z.object({ kind: import_zod10.z.literal("set_property"), ...label2, ...next, key: DraftPropertyKey, value: JsonValue }).strict(),
|
|
2374
2613
|
/** Subscribing never lifts a suppression: the service checks that, not the flow. */
|
|
2375
|
-
|
|
2614
|
+
import_zod10.z.object({ kind: import_zod10.z.literal("subscribe_topic"), ...label2, ...next, topic: DraftSlug }).strict(),
|
|
2376
2615
|
/** `topic` unsubscribes from the automation's own topic, `all` from every topic. */
|
|
2377
|
-
|
|
2378
|
-
|
|
2616
|
+
import_zod10.z.object({ kind: import_zod10.z.literal("unsubscribe"), ...label2, ...next, scope: import_zod10.z.enum(["topic", "all"]) }).strict(),
|
|
2617
|
+
import_zod10.z.object({ kind: import_zod10.z.literal("exit"), ...label2 }).strict(),
|
|
2379
2618
|
SplitStep,
|
|
2380
2619
|
GotoStep,
|
|
2381
2620
|
WebhookStep,
|
|
@@ -2399,25 +2638,25 @@ function stepTargets(step) {
|
|
|
2399
2638
|
}
|
|
2400
2639
|
}
|
|
2401
2640
|
var MAX_STEPS = 200;
|
|
2402
|
-
var AutomationFlow =
|
|
2403
|
-
triggers:
|
|
2641
|
+
var AutomationFlow = import_zod10.z.object({
|
|
2642
|
+
triggers: import_zod10.z.array(AutomationTrigger).max(MAX_TRIGGERS),
|
|
2404
2643
|
/** The first step. `null` is an empty flow. */
|
|
2405
2644
|
entry: StepId.nullable(),
|
|
2406
|
-
steps:
|
|
2645
|
+
steps: import_zod10.z.record(StepId, AutomationStep)
|
|
2407
2646
|
}).strict();
|
|
2408
2647
|
var emptyFlow = () => ({ triggers: [], entry: null, steps: {} });
|
|
2409
|
-
var QuietHours =
|
|
2648
|
+
var QuietHours = import_zod10.z.object({
|
|
2410
2649
|
start: TimeOfDay,
|
|
2411
2650
|
end: TimeOfDay,
|
|
2412
|
-
weekdays:
|
|
2651
|
+
weekdays: import_zod10.z.array(Weekday).min(1).max(7).nullish()
|
|
2413
2652
|
}).strict();
|
|
2414
2653
|
var RE_ENTRY_MODES = ["off", "after_exit"];
|
|
2415
|
-
var ReEntryMode =
|
|
2654
|
+
var ReEntryMode = import_zod10.z.enum(RE_ENTRY_MODES);
|
|
2416
2655
|
var MAX_RE_ENTRY_COOLDOWN_SECONDS = 365 * 24 * 60 * 60;
|
|
2417
|
-
var AutomationSettings =
|
|
2656
|
+
var AutomationSettings = import_zod10.z.object({
|
|
2418
2657
|
re_entry: ReEntryMode,
|
|
2419
2658
|
/** Seconds a person must wait after leaving before entering again. Only with `after_exit`. */
|
|
2420
|
-
re_entry_cooldown_s:
|
|
2659
|
+
re_entry_cooldown_s: import_zod10.z.number().int().min(0).max(MAX_RE_ENTRY_COOLDOWN_SECONDS).nullish(),
|
|
2421
2660
|
quiet_hours: QuietHours.nullish(),
|
|
2422
2661
|
/** Checked before every step; when it matches, the run ends. */
|
|
2423
2662
|
exit_filter: BoundedAutomationFilter.nullish()
|
|
@@ -2475,18 +2714,18 @@ var AUTOMATION_ISSUE_CODES = [
|
|
|
2475
2714
|
/** A one-off date that is already over everywhere on earth, so it would fire for nobody. */
|
|
2476
2715
|
"date_in_the_past"
|
|
2477
2716
|
];
|
|
2478
|
-
var AutomationIssueCode =
|
|
2479
|
-
var AutomationIssue =
|
|
2717
|
+
var AutomationIssueCode = import_zod10.z.enum(AUTOMATION_ISSUE_CODES);
|
|
2718
|
+
var AutomationIssue = import_zod10.z.object({
|
|
2480
2719
|
code: AutomationIssueCode,
|
|
2481
2720
|
/** The step the issue is about, when it is about one. */
|
|
2482
2721
|
step_id: StepId.nullable(),
|
|
2483
2722
|
/** Where inside the document, for the canvas to point at a field. */
|
|
2484
|
-
path:
|
|
2485
|
-
message:
|
|
2723
|
+
path: import_zod10.z.array(import_zod10.z.union([import_zod10.z.string(), import_zod10.z.number()])),
|
|
2724
|
+
message: import_zod10.z.string()
|
|
2486
2725
|
});
|
|
2487
|
-
var AutomationValidation =
|
|
2488
|
-
ok:
|
|
2489
|
-
issues:
|
|
2726
|
+
var AutomationValidation = import_zod10.z.object({
|
|
2727
|
+
ok: import_zod10.z.boolean(),
|
|
2728
|
+
issues: import_zod10.z.array(AutomationIssue)
|
|
2490
2729
|
});
|
|
2491
2730
|
function validateAutomation(flow, settings, ctx) {
|
|
2492
2731
|
const issues = [];
|
|
@@ -2877,7 +3116,7 @@ function cycles(flow) {
|
|
|
2877
3116
|
return out.sort();
|
|
2878
3117
|
}
|
|
2879
3118
|
var AUTOMATION_STATUSES = ["draft", "active", "paused", "archived"];
|
|
2880
|
-
var AutomationStatus =
|
|
3119
|
+
var AutomationStatus = import_zod10.z.enum(AUTOMATION_STATUSES);
|
|
2881
3120
|
var AUTOMATION_END_REASONS = [
|
|
2882
3121
|
"completed",
|
|
2883
3122
|
"exit_filter",
|
|
@@ -2896,9 +3135,9 @@ var AUTOMATION_END_REASONS = [
|
|
|
2896
3135
|
"ended_by_hand",
|
|
2897
3136
|
"failed"
|
|
2898
3137
|
];
|
|
2899
|
-
var AutomationEndReason =
|
|
3138
|
+
var AutomationEndReason = import_zod10.z.enum(AUTOMATION_END_REASONS);
|
|
2900
3139
|
var AUTOMATION_WAIT_REASONS = ["delay", "quiet_hours", "plan_limit", "sending", "condition"];
|
|
2901
|
-
var AutomationWaitReason =
|
|
3140
|
+
var AutomationWaitReason = import_zod10.z.enum(AUTOMATION_WAIT_REASONS);
|
|
2902
3141
|
var AUTOMATION_ENTRY_REFUSALS = [
|
|
2903
3142
|
"already_inside",
|
|
2904
3143
|
"re_entry_off",
|
|
@@ -2909,26 +3148,26 @@ var AUTOMATION_ENTRY_REFUSALS = [
|
|
|
2909
3148
|
"not_active",
|
|
2910
3149
|
"unknown_contact"
|
|
2911
3150
|
];
|
|
2912
|
-
var AutomationEntryRefusal =
|
|
2913
|
-
var AutomationCounts =
|
|
2914
|
-
started:
|
|
2915
|
-
in_progress:
|
|
2916
|
-
completed:
|
|
2917
|
-
exited:
|
|
2918
|
-
failed:
|
|
2919
|
-
});
|
|
2920
|
-
var Automation =
|
|
3151
|
+
var AutomationEntryRefusal = import_zod10.z.enum(AUTOMATION_ENTRY_REFUSALS);
|
|
3152
|
+
var AutomationCounts = import_zod10.z.object({
|
|
3153
|
+
started: import_zod10.z.number().int().min(0),
|
|
3154
|
+
in_progress: import_zod10.z.number().int().min(0),
|
|
3155
|
+
completed: import_zod10.z.number().int().min(0),
|
|
3156
|
+
exited: import_zod10.z.number().int().min(0),
|
|
3157
|
+
failed: import_zod10.z.number().int().min(0)
|
|
3158
|
+
});
|
|
3159
|
+
var Automation = import_zod10.z.object({
|
|
2921
3160
|
id: Id,
|
|
2922
|
-
name:
|
|
3161
|
+
name: import_zod10.z.string().min(1).max(200),
|
|
2923
3162
|
status: AutomationStatus,
|
|
2924
3163
|
/** Every automation sends under one topic; there are no transactional automations. */
|
|
2925
3164
|
topic: Slug,
|
|
2926
3165
|
provider_id: Id.nullable(),
|
|
2927
3166
|
settings: AutomationSettings,
|
|
2928
3167
|
/** The flow people are running through, null while the automation has never been published. */
|
|
2929
|
-
published_version:
|
|
3168
|
+
published_version: import_zod10.z.number().int().min(1).nullable(),
|
|
2930
3169
|
/** The flow being edited. Increments on every save, like a template's version. */
|
|
2931
|
-
draft_version:
|
|
3170
|
+
draft_version: import_zod10.z.number().int().min(1),
|
|
2932
3171
|
counts: AutomationCounts,
|
|
2933
3172
|
created_at: Timestamp,
|
|
2934
3173
|
updated_at: Timestamp,
|
|
@@ -2941,16 +3180,16 @@ var AutomationWithFlow = Automation.extend({
|
|
|
2941
3180
|
published_flow: AutomationFlow.nullable()
|
|
2942
3181
|
});
|
|
2943
3182
|
var AutomationSummary = Automation;
|
|
2944
|
-
var AutomationCreate =
|
|
2945
|
-
name:
|
|
3183
|
+
var AutomationCreate = import_zod10.z.object({
|
|
3184
|
+
name: import_zod10.z.string().min(1).max(200),
|
|
2946
3185
|
topic: Slug,
|
|
2947
3186
|
provider_id: Id.optional(),
|
|
2948
3187
|
flow: AutomationFlow.optional(),
|
|
2949
3188
|
settings: AutomationSettings.partial().optional()
|
|
2950
3189
|
});
|
|
2951
|
-
var AutomationUpdate =
|
|
2952
|
-
base_version:
|
|
2953
|
-
name:
|
|
3190
|
+
var AutomationUpdate = import_zod10.z.object({
|
|
3191
|
+
base_version: import_zod10.z.number().int().min(1),
|
|
3192
|
+
name: import_zod10.z.string().min(1).max(200).optional(),
|
|
2954
3193
|
topic: Slug.optional(),
|
|
2955
3194
|
provider_id: Id.optional(),
|
|
2956
3195
|
flow: AutomationFlow.optional(),
|
|
@@ -2963,42 +3202,42 @@ var AutomationListQuery = PageQuery.extend({
|
|
|
2963
3202
|
status: AutomationStatus.optional(),
|
|
2964
3203
|
topic: Slug.optional()
|
|
2965
3204
|
});
|
|
2966
|
-
var AutomationPublishRequest =
|
|
3205
|
+
var AutomationPublishRequest = import_zod10.z.object({
|
|
2967
3206
|
/**
|
|
2968
3207
|
* Answer what this publish would do and change nothing, whatever the flow
|
|
2969
3208
|
* looks like. Without it a publish that has no issues and moves nobody
|
|
2970
3209
|
* simply goes ahead, which is right for an API caller and wrong for a
|
|
2971
3210
|
* dialog that is only showing somebody what they are about to do.
|
|
2972
3211
|
*/
|
|
2973
|
-
dry_run:
|
|
2974
|
-
confirm:
|
|
3212
|
+
dry_run: import_zod10.z.boolean().optional(),
|
|
3213
|
+
confirm: import_zod10.z.boolean().optional(),
|
|
2975
3214
|
/** Per removed step: the step its waiting runs move to, or null to end them. */
|
|
2976
|
-
moves:
|
|
3215
|
+
moves: import_zod10.z.record(StepId, StepId.nullable()).optional(),
|
|
2977
3216
|
/** Also enter everyone who matches a trigger's condition right now. */
|
|
2978
|
-
backfill:
|
|
3217
|
+
backfill: import_zod10.z.boolean().optional()
|
|
2979
3218
|
}).strict();
|
|
2980
|
-
var AutomationPublishMove =
|
|
3219
|
+
var AutomationPublishMove = import_zod10.z.object({
|
|
2981
3220
|
step_id: StepId,
|
|
2982
3221
|
/** Why the step's people have to move: it is gone, or its delay changed. */
|
|
2983
|
-
change:
|
|
2984
|
-
waiting:
|
|
3222
|
+
change: import_zod10.z.enum(["removed", "delay_changed", "kind_changed"]),
|
|
3223
|
+
waiting: import_zod10.z.number().int().min(0),
|
|
2985
3224
|
/** Where they go: a step id, or null to end their runs with `step_removed`. */
|
|
2986
3225
|
destination: StepId.nullable()
|
|
2987
3226
|
});
|
|
2988
|
-
var AutomationPublishResult =
|
|
2989
|
-
published:
|
|
3227
|
+
var AutomationPublishResult = import_zod10.z.object({
|
|
3228
|
+
published: import_zod10.z.boolean(),
|
|
2990
3229
|
automation: Automation,
|
|
2991
3230
|
/** Empty when nothing has to move; non-empty and `published` false asks for a confirmation. */
|
|
2992
|
-
moves:
|
|
3231
|
+
moves: import_zod10.z.array(AutomationPublishMove),
|
|
2993
3232
|
/** How many people the backfill entered, or would enter when it is not confirmed. */
|
|
2994
|
-
backfill:
|
|
2995
|
-
issues:
|
|
2996
|
-
});
|
|
2997
|
-
var AutomationDuplicateRequest =
|
|
2998
|
-
var AutomationEnrollRequest =
|
|
2999
|
-
contact_ids:
|
|
3000
|
-
external_ids:
|
|
3001
|
-
emails:
|
|
3233
|
+
backfill: import_zod10.z.number().int().min(0),
|
|
3234
|
+
issues: import_zod10.z.array(AutomationIssue)
|
|
3235
|
+
});
|
|
3236
|
+
var AutomationDuplicateRequest = import_zod10.z.object({ name: import_zod10.z.string().min(1).max(200).optional() }).strict();
|
|
3237
|
+
var AutomationEnrollRequest = import_zod10.z.object({
|
|
3238
|
+
contact_ids: import_zod10.z.array(Id).min(1).max(1e3).optional(),
|
|
3239
|
+
external_ids: import_zod10.z.array(import_zod10.z.string().min(1).max(255)).min(1).max(1e3).optional(),
|
|
3240
|
+
emails: import_zod10.z.array(Email).min(1).max(1e3).optional(),
|
|
3002
3241
|
segment_id: Id.optional(),
|
|
3003
3242
|
/** Where to start them; the flow's entry step by default. */
|
|
3004
3243
|
step_id: StepId.optional()
|
|
@@ -3006,34 +3245,34 @@ var AutomationEnrollRequest = import_zod9.z.object({
|
|
|
3006
3245
|
(v) => [v.contact_ids, v.external_ids, v.emails, v.segment_id].filter((x) => x !== void 0).length === 1,
|
|
3007
3246
|
"name the people exactly one way: contact_ids, external_ids, emails or segment_id"
|
|
3008
3247
|
);
|
|
3009
|
-
var AutomationEnrollment =
|
|
3248
|
+
var AutomationEnrollment = import_zod10.z.object({
|
|
3010
3249
|
contact_id: Id.nullable(),
|
|
3011
3250
|
email: Email.nullable(),
|
|
3012
|
-
external_id:
|
|
3013
|
-
entered:
|
|
3251
|
+
external_id: import_zod10.z.string().nullable(),
|
|
3252
|
+
entered: import_zod10.z.boolean(),
|
|
3014
3253
|
run_id: Id.nullable(),
|
|
3015
3254
|
reason: AutomationEntryRefusal.nullable()
|
|
3016
3255
|
});
|
|
3017
|
-
var AutomationEnrollResult =
|
|
3018
|
-
entered:
|
|
3019
|
-
refused:
|
|
3020
|
-
results:
|
|
3256
|
+
var AutomationEnrollResult = import_zod10.z.object({
|
|
3257
|
+
entered: import_zod10.z.number().int().min(0),
|
|
3258
|
+
refused: import_zod10.z.number().int().min(0),
|
|
3259
|
+
results: import_zod10.z.array(AutomationEnrollment)
|
|
3021
3260
|
});
|
|
3022
|
-
var AutomationRunStatus =
|
|
3023
|
-
var AutomationRun =
|
|
3261
|
+
var AutomationRunStatus = import_zod10.z.enum(["active", "waiting", "completed", "exited", "failed"]);
|
|
3262
|
+
var AutomationRun = import_zod10.z.object({
|
|
3024
3263
|
id: Id,
|
|
3025
3264
|
automation_id: Id,
|
|
3026
3265
|
contact_id: Id,
|
|
3027
3266
|
email: Email,
|
|
3028
|
-
external_id:
|
|
3029
|
-
version:
|
|
3267
|
+
external_id: import_zod10.z.string().nullable(),
|
|
3268
|
+
version: import_zod10.z.number().int().min(1),
|
|
3030
3269
|
status: AutomationRunStatus,
|
|
3031
3270
|
current_step_id: StepId.nullable(),
|
|
3032
3271
|
next_action_at: Timestamp.nullable(),
|
|
3033
3272
|
wait_reason: AutomationWaitReason.nullable(),
|
|
3034
|
-
end_reason:
|
|
3273
|
+
end_reason: import_zod10.z.string().nullable(),
|
|
3035
3274
|
/** What went wrong the last time this run tried to take its step, null otherwise. */
|
|
3036
|
-
last_error:
|
|
3275
|
+
last_error: import_zod10.z.string().nullable(),
|
|
3037
3276
|
entered_at: Timestamp,
|
|
3038
3277
|
ended_at: Timestamp.nullable()
|
|
3039
3278
|
});
|
|
@@ -3043,13 +3282,13 @@ var AutomationRunListQuery = PageQuery.extend({
|
|
|
3043
3282
|
contact_id: Id.optional()
|
|
3044
3283
|
});
|
|
3045
3284
|
var ContactAutomationRun = AutomationRun.extend({
|
|
3046
|
-
automation:
|
|
3285
|
+
automation: import_zod10.z.object({ id: Id, name: import_zod10.z.string(), status: AutomationStatus })
|
|
3047
3286
|
});
|
|
3048
3287
|
var ContactAutomationListQuery = PageQuery.extend({ status: AutomationRunStatus.optional() });
|
|
3049
|
-
var AutomationStepExecution =
|
|
3288
|
+
var AutomationStepExecution = import_zod10.z.object({
|
|
3050
3289
|
step_id: StepId,
|
|
3051
3290
|
step_kind: AutomationStepKind,
|
|
3052
|
-
visit:
|
|
3291
|
+
visit: import_zod10.z.number().int().min(1),
|
|
3053
3292
|
started_at: Timestamp,
|
|
3054
3293
|
finished_at: Timestamp.nullable(),
|
|
3055
3294
|
/**
|
|
@@ -3061,48 +3300,48 @@ var AutomationStepExecution = import_zod9.z.object({
|
|
|
3061
3300
|
*/
|
|
3062
3301
|
outcome: Properties
|
|
3063
3302
|
});
|
|
3064
|
-
var AutomationJourney =
|
|
3303
|
+
var AutomationJourney = import_zod10.z.object({
|
|
3065
3304
|
run: AutomationRun,
|
|
3066
|
-
steps:
|
|
3305
|
+
steps: import_zod10.z.array(AutomationStepExecution)
|
|
3067
3306
|
});
|
|
3068
|
-
var AutomationStepReport =
|
|
3307
|
+
var AutomationStepReport = import_zod10.z.object({
|
|
3069
3308
|
step_id: StepId,
|
|
3070
3309
|
step_kind: AutomationStepKind,
|
|
3071
|
-
reached:
|
|
3072
|
-
waiting:
|
|
3073
|
-
passed:
|
|
3310
|
+
reached: import_zod10.z.number().int().min(0),
|
|
3311
|
+
waiting: import_zod10.z.number().int().min(0),
|
|
3312
|
+
passed: import_zod10.z.number().int().min(0),
|
|
3074
3313
|
/** Per branch, for a condition: how many took `yes` and how many `no`. */
|
|
3075
|
-
branches:
|
|
3314
|
+
branches: import_zod10.z.record(import_zod10.z.number().int().min(0)),
|
|
3076
3315
|
/** The step mailing's id, for an email step of the published version. */
|
|
3077
3316
|
mailing_id: Id.nullable()
|
|
3078
3317
|
});
|
|
3079
|
-
var AutomationReport =
|
|
3318
|
+
var AutomationReport = import_zod10.z.object({
|
|
3080
3319
|
counts: AutomationCounts,
|
|
3081
3320
|
/** Why the people who left did: `AutomationEndReason` to a count. */
|
|
3082
|
-
end_reasons:
|
|
3321
|
+
end_reasons: import_zod10.z.record(import_zod10.z.number().int().min(0)),
|
|
3083
3322
|
/**
|
|
3084
3323
|
* Why people a trigger named did not enter: `AutomationEntryRefusal` to a
|
|
3085
3324
|
* count. Without it a pause, an exclusion or a missing subscription would
|
|
3086
3325
|
* turn people away invisibly.
|
|
3087
3326
|
*/
|
|
3088
|
-
refusals:
|
|
3089
|
-
steps:
|
|
3090
|
-
});
|
|
3091
|
-
var AutomationExitRunRequest =
|
|
3092
|
-
var AutomationRunParams =
|
|
3093
|
-
var AutomationStepParams =
|
|
3094
|
-
var AutomationTestEmailRequest =
|
|
3095
|
-
var AutomationValidateRequest =
|
|
3096
|
-
var EventCreate =
|
|
3327
|
+
refusals: import_zod10.z.record(import_zod10.z.number().int().min(0)),
|
|
3328
|
+
steps: import_zod10.z.array(AutomationStepReport)
|
|
3329
|
+
});
|
|
3330
|
+
var AutomationExitRunRequest = import_zod10.z.object({ reason: import_zod10.z.string().max(200).optional() }).strict();
|
|
3331
|
+
var AutomationRunParams = import_zod10.z.object({ id: Id, run_id: Id });
|
|
3332
|
+
var AutomationStepParams = import_zod10.z.object({ id: Id, step_id: StepId });
|
|
3333
|
+
var AutomationTestEmailRequest = import_zod10.z.object({ to: Email, merge: Properties.optional(), locale: LocaleTag.optional() }).strict();
|
|
3334
|
+
var AutomationValidateRequest = import_zod10.z.object({ flow: AutomationFlow.optional(), settings: AutomationSettings.partial().optional() }).strict();
|
|
3335
|
+
var EventCreate = import_zod10.z.object({
|
|
3097
3336
|
name: EventName,
|
|
3098
|
-
contact:
|
|
3337
|
+
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"),
|
|
3099
3338
|
data: Properties.optional(),
|
|
3100
3339
|
occurred_at: Timestamp.optional(),
|
|
3101
|
-
id:
|
|
3340
|
+
id: import_zod10.z.string().min(1).max(128).optional()
|
|
3102
3341
|
}).strict();
|
|
3103
|
-
var Event =
|
|
3342
|
+
var Event = import_zod10.z.object({
|
|
3104
3343
|
id: Id,
|
|
3105
|
-
client_event_id:
|
|
3344
|
+
client_event_id: import_zod10.z.string().nullable(),
|
|
3106
3345
|
name: EventName,
|
|
3107
3346
|
contact_id: Id,
|
|
3108
3347
|
data: Properties,
|
|
@@ -3113,7 +3352,7 @@ var Event = import_zod9.z.object({
|
|
|
3113
3352
|
* hand. Each is then admitted or refused by the runtime on its own rules
|
|
3114
3353
|
* (consent, exclusions, re-entry), which `automations.report` counts.
|
|
3115
3354
|
*/
|
|
3116
|
-
entered:
|
|
3355
|
+
entered: import_zod10.z.number().int().min(0)
|
|
3117
3356
|
});
|
|
3118
3357
|
var EventListQuery = PageQuery.extend({
|
|
3119
3358
|
name: EventName.optional(),
|
|
@@ -3121,19 +3360,15 @@ var EventListQuery = PageQuery.extend({
|
|
|
3121
3360
|
});
|
|
3122
3361
|
|
|
3123
3362
|
// src/workspace.ts
|
|
3124
|
-
var CompanyId =
|
|
3363
|
+
var CompanyId = import_zod11.z.string().min(1).max(64);
|
|
3125
3364
|
var ASSET_POLICIES = ["any", "service_only"];
|
|
3126
|
-
var AssetPolicy =
|
|
3365
|
+
var AssetPolicy = import_zod11.z.enum(ASSET_POLICIES);
|
|
3127
3366
|
var MAX_ALLOWED_ASSET_HOSTS = 20;
|
|
3128
|
-
var AssetHost =
|
|
3129
|
-
var
|
|
3130
|
-
var MAX_MERGE_DEFAULT_LENGTH = 2e3;
|
|
3131
|
-
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);
|
|
3132
|
-
var MergeDefaultValue = import_zod10.z.union([import_zod10.z.string().max(MAX_MERGE_DEFAULT_LENGTH), import_zod10.z.number().finite(), import_zod10.z.boolean()]);
|
|
3133
|
-
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), {
|
|
3367
|
+
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");
|
|
3368
|
+
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), {
|
|
3134
3369
|
message: `a reserved merge field (${Object.keys(RESERVED_MERGE_FIELDS).join(", ")}) cannot have a workspace default`
|
|
3135
3370
|
});
|
|
3136
|
-
var WorkspaceSettings =
|
|
3371
|
+
var WorkspaceSettings = import_zod11.z.object({
|
|
3137
3372
|
/**
|
|
3138
3373
|
* The workspace's main language (a {@link LocaleTag}, e.g. "de"): the main
|
|
3139
3374
|
* language of a new template, and of the hosted pages when nothing else
|
|
@@ -3146,9 +3381,9 @@ var WorkspaceSettings = import_zod10.z.object({
|
|
|
3146
3381
|
* each; the hosted pages are offered in those of them they support (English,
|
|
3147
3382
|
* German, French, Italian, Spanish). The service stores canonical casing.
|
|
3148
3383
|
*/
|
|
3149
|
-
locales:
|
|
3384
|
+
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"),
|
|
3150
3385
|
/** Open and click tracking. Off by default, opt-in per workspace. */
|
|
3151
|
-
tracking_enabled:
|
|
3386
|
+
tracking_enabled: import_zod11.z.boolean(),
|
|
3152
3387
|
/** Where images, stylesheets and fonts in a mail may load from. `any` by default. */
|
|
3153
3388
|
asset_policy: AssetPolicy,
|
|
3154
3389
|
/**
|
|
@@ -3156,7 +3391,7 @@ var WorkspaceSettings = import_zod10.z.object({
|
|
|
3156
3391
|
* the workspace's website, typically. Empty by default. Ignored under `any`,
|
|
3157
3392
|
* which allows everything already.
|
|
3158
3393
|
*/
|
|
3159
|
-
allowed_asset_hosts:
|
|
3394
|
+
allowed_asset_hosts: import_zod11.z.array(AssetHost).max(MAX_ALLOWED_ASSET_HOSTS),
|
|
3160
3395
|
/** Merge values every mail of the workspace can use (see `MergeDefaults`). Empty by default. */
|
|
3161
3396
|
merge_defaults: MergeDefaults,
|
|
3162
3397
|
/**
|
|
@@ -3165,10 +3400,10 @@ var WorkspaceSettings = import_zod10.z.object({
|
|
|
3165
3400
|
*/
|
|
3166
3401
|
default_timezone: TimezoneName.nullable()
|
|
3167
3402
|
});
|
|
3168
|
-
var Workspace =
|
|
3403
|
+
var Workspace = import_zod11.z.object({
|
|
3169
3404
|
id: Id,
|
|
3170
3405
|
slug: Slug,
|
|
3171
|
-
name:
|
|
3406
|
+
name: import_zod11.z.string().min(1).max(120),
|
|
3172
3407
|
settings: WorkspaceSettings,
|
|
3173
3408
|
/**
|
|
3174
3409
|
* The auth-brain company (tenant) the workspace was created for, or null for
|
|
@@ -3179,13 +3414,13 @@ var Workspace = import_zod10.z.object({
|
|
|
3179
3414
|
created_at: Timestamp,
|
|
3180
3415
|
updated_at: Timestamp
|
|
3181
3416
|
});
|
|
3182
|
-
var WorkspaceCreate =
|
|
3417
|
+
var WorkspaceCreate = import_zod11.z.object({
|
|
3183
3418
|
slug: Slug,
|
|
3184
|
-
name:
|
|
3419
|
+
name: import_zod11.z.string().min(1).max(120),
|
|
3185
3420
|
settings: WorkspaceSettings.partial().optional(),
|
|
3186
|
-
owner:
|
|
3421
|
+
owner: import_zod11.z.object({
|
|
3187
3422
|
email: Email,
|
|
3188
|
-
name:
|
|
3423
|
+
name: import_zod11.z.string().max(200).nullable().optional()
|
|
3189
3424
|
}),
|
|
3190
3425
|
/**
|
|
3191
3426
|
* The signed-in person's active auth-brain company. The dashboard always
|
|
@@ -3195,49 +3430,49 @@ var WorkspaceCreate = import_zod10.z.object({
|
|
|
3195
3430
|
*/
|
|
3196
3431
|
company_id: CompanyId.optional()
|
|
3197
3432
|
});
|
|
3198
|
-
var WorkspaceUpdate =
|
|
3199
|
-
name:
|
|
3433
|
+
var WorkspaceUpdate = import_zod11.z.object({
|
|
3434
|
+
name: import_zod11.z.string().min(1).max(120),
|
|
3200
3435
|
settings: WorkspaceSettings.partial()
|
|
3201
3436
|
}).partial().refine((v) => Object.keys(v).length > 0, "at least one field");
|
|
3202
|
-
var WorkspaceMove =
|
|
3437
|
+
var WorkspaceMove = import_zod11.z.object({ company_id: CompanyId });
|
|
3203
3438
|
var MEMBER_ROLES = ["owner", "admin", "editor", "viewer"];
|
|
3204
|
-
var MemberRole =
|
|
3439
|
+
var MemberRole = import_zod11.z.enum(MEMBER_ROLES);
|
|
3205
3440
|
var WorkspaceMembership = Workspace.extend({ role: MemberRole });
|
|
3206
|
-
var Member =
|
|
3441
|
+
var Member = import_zod11.z.object({
|
|
3207
3442
|
id: Id,
|
|
3208
3443
|
/** The person's auth-brain subject. */
|
|
3209
|
-
subject:
|
|
3444
|
+
subject: import_zod11.z.string().min(1).max(255),
|
|
3210
3445
|
email: Email,
|
|
3211
|
-
name:
|
|
3446
|
+
name: import_zod11.z.string().max(200).nullable(),
|
|
3212
3447
|
role: MemberRole,
|
|
3213
3448
|
created_at: Timestamp
|
|
3214
3449
|
});
|
|
3215
|
-
var MemberCreate =
|
|
3216
|
-
subject:
|
|
3450
|
+
var MemberCreate = import_zod11.z.object({
|
|
3451
|
+
subject: import_zod11.z.string().min(1).max(255),
|
|
3217
3452
|
email: Email,
|
|
3218
|
-
name:
|
|
3453
|
+
name: import_zod11.z.string().max(200).nullable().optional(),
|
|
3219
3454
|
role: MemberRole
|
|
3220
3455
|
});
|
|
3221
|
-
var MemberUpdate =
|
|
3456
|
+
var MemberUpdate = import_zod11.z.object({ role: MemberRole });
|
|
3222
3457
|
var API_KEY_SCOPES = ["full", "read", "send"];
|
|
3223
|
-
var ApiKeyScope =
|
|
3224
|
-
var ApiKey =
|
|
3458
|
+
var ApiKeyScope = import_zod11.z.enum(API_KEY_SCOPES);
|
|
3459
|
+
var ApiKey = import_zod11.z.object({
|
|
3225
3460
|
id: Id,
|
|
3226
|
-
name:
|
|
3461
|
+
name: import_zod11.z.string().min(1).max(120),
|
|
3227
3462
|
/** The first characters of the key, for recognising it in a list. */
|
|
3228
|
-
prefix:
|
|
3463
|
+
prefix: import_zod11.z.string().min(4).max(32),
|
|
3229
3464
|
scope: ApiKeyScope,
|
|
3230
3465
|
last_used_at: Timestamp.nullable(),
|
|
3231
3466
|
revoked_at: Timestamp.nullable(),
|
|
3232
3467
|
created_at: Timestamp
|
|
3233
3468
|
});
|
|
3234
|
-
var ApiKeyCreate =
|
|
3235
|
-
name:
|
|
3469
|
+
var ApiKeyCreate = import_zod11.z.object({
|
|
3470
|
+
name: import_zod11.z.string().min(1).max(120),
|
|
3236
3471
|
/** Omitted means `full`. */
|
|
3237
3472
|
scope: ApiKeyScope.optional()
|
|
3238
3473
|
});
|
|
3239
|
-
var ApiKeyCreated =
|
|
3240
|
-
key:
|
|
3474
|
+
var ApiKeyCreated = import_zod11.z.object({
|
|
3475
|
+
key: import_zod11.z.string().min(20),
|
|
3241
3476
|
api_key: ApiKey
|
|
3242
3477
|
});
|
|
3243
3478
|
var AUDIT_ACTIONS = [
|
|
@@ -3326,29 +3561,29 @@ var AUDIT_ACTIONS = [
|
|
|
3326
3561
|
"automation.run_ended",
|
|
3327
3562
|
"event.recorded"
|
|
3328
3563
|
];
|
|
3329
|
-
var AuditAction =
|
|
3330
|
-
var AuditActor =
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
type:
|
|
3564
|
+
var AuditAction = import_zod11.z.enum(AUDIT_ACTIONS);
|
|
3565
|
+
var AuditActor = import_zod11.z.discriminatedUnion("type", [
|
|
3566
|
+
import_zod11.z.object({ type: import_zod11.z.literal("member"), member_id: Id, subject: import_zod11.z.string().min(1) }),
|
|
3567
|
+
import_zod11.z.object({
|
|
3568
|
+
type: import_zod11.z.literal("api_key"),
|
|
3334
3569
|
api_key_id: Id,
|
|
3335
3570
|
/**
|
|
3336
3571
|
* Who the client's application said it was acting for, from
|
|
3337
3572
|
* `ON_BEHALF_OF_HEADER`: reported by that application, never verified.
|
|
3338
3573
|
* Absent when the call carried no label.
|
|
3339
3574
|
*/
|
|
3340
|
-
on_behalf_of:
|
|
3575
|
+
on_behalf_of: import_zod11.z.string().min(1).max(ON_BEHALF_OF_MAX_LENGTH).optional()
|
|
3341
3576
|
}),
|
|
3342
3577
|
/** The service itself (the worker, a bounce, the hosted unsubscribe page). */
|
|
3343
|
-
|
|
3578
|
+
import_zod11.z.object({ type: import_zod11.z.literal("system"), reason: import_zod11.z.string().min(1).max(200) })
|
|
3344
3579
|
]);
|
|
3345
|
-
var AuditEntry =
|
|
3580
|
+
var AuditEntry = import_zod11.z.object({
|
|
3346
3581
|
id: Id,
|
|
3347
3582
|
action: AuditAction,
|
|
3348
3583
|
actor: AuditActor,
|
|
3349
|
-
target_type:
|
|
3584
|
+
target_type: import_zod11.z.string().min(1).max(64),
|
|
3350
3585
|
target_id: Id.nullable(),
|
|
3351
|
-
details:
|
|
3586
|
+
details: import_zod11.z.record(import_zod11.z.unknown()),
|
|
3352
3587
|
created_at: Timestamp
|
|
3353
3588
|
});
|
|
3354
3589
|
var AuditQuery = PageQuery.extend({
|
|
@@ -3357,12 +3592,12 @@ var AuditQuery = PageQuery.extend({
|
|
|
3357
3592
|
});
|
|
3358
3593
|
|
|
3359
3594
|
// src/invites.ts
|
|
3360
|
-
var
|
|
3595
|
+
var import_zod12 = require("zod");
|
|
3361
3596
|
var INVITE_STATUSES = ["pending", "accepted", "revoked", "expired"];
|
|
3362
|
-
var InviteStatus =
|
|
3597
|
+
var InviteStatus = import_zod12.z.enum(INVITE_STATUSES);
|
|
3363
3598
|
var DEFAULT_INVITE_TTL_DAYS = 7;
|
|
3364
3599
|
var MAX_INVITE_TTL_DAYS = 30;
|
|
3365
|
-
var Invite =
|
|
3600
|
+
var Invite = import_zod12.z.object({
|
|
3366
3601
|
id: Id,
|
|
3367
3602
|
/** Stored lowercased; only a person signed in with this address can accept. */
|
|
3368
3603
|
email: Email,
|
|
@@ -3370,32 +3605,32 @@ var Invite = import_zod11.z.object({
|
|
|
3370
3605
|
/** Derived from the timestamps below, never stored. */
|
|
3371
3606
|
status: InviteStatus,
|
|
3372
3607
|
/** The member who invited, while they are still one (null after they left). */
|
|
3373
|
-
invited_by:
|
|
3608
|
+
invited_by: import_zod12.z.object({ member_id: Id.nullable(), email: Email.nullable() }),
|
|
3374
3609
|
expires_at: Timestamp,
|
|
3375
3610
|
accepted_at: Timestamp.nullable(),
|
|
3376
3611
|
revoked_at: Timestamp.nullable(),
|
|
3377
3612
|
created_at: Timestamp
|
|
3378
3613
|
});
|
|
3379
|
-
var InviteCreate =
|
|
3614
|
+
var InviteCreate = import_zod12.z.object({
|
|
3380
3615
|
email: Email,
|
|
3381
3616
|
role: MemberRole,
|
|
3382
|
-
expires_in_days:
|
|
3617
|
+
expires_in_days: import_zod12.z.number().int().min(1).max(MAX_INVITE_TTL_DAYS).optional()
|
|
3383
3618
|
});
|
|
3384
|
-
var InviteCreated =
|
|
3619
|
+
var InviteCreated = import_zod12.z.object({
|
|
3385
3620
|
invite: Invite,
|
|
3386
|
-
token:
|
|
3621
|
+
token: import_zod12.z.string().min(32).max(128)
|
|
3387
3622
|
});
|
|
3388
3623
|
var InviteListQuery = PageQuery.extend({
|
|
3389
3624
|
status: InviteStatus.optional()
|
|
3390
3625
|
});
|
|
3391
|
-
var InviteAccept =
|
|
3392
|
-
token:
|
|
3626
|
+
var InviteAccept = import_zod12.z.object({
|
|
3627
|
+
token: import_zod12.z.string().min(32).max(128),
|
|
3393
3628
|
email: Email,
|
|
3394
|
-
name:
|
|
3629
|
+
name: import_zod12.z.string().max(200).nullable().optional()
|
|
3395
3630
|
});
|
|
3396
|
-
var InviteAccepted =
|
|
3631
|
+
var InviteAccepted = import_zod12.z.object({
|
|
3397
3632
|
workspace: WorkspaceMembership,
|
|
3398
|
-
already_member:
|
|
3633
|
+
already_member: import_zod12.z.boolean()
|
|
3399
3634
|
});
|
|
3400
3635
|
var INVITE_REFUSAL_REASONS = ["email_mismatch", "inviter_lacks_role", "expired", "revoked", "accepted"];
|
|
3401
3636
|
|
|
@@ -4025,13 +4260,13 @@ function renameInsertionEverywhere(drafts, from, rawTo) {
|
|
|
4025
4260
|
}
|
|
4026
4261
|
|
|
4027
4262
|
// src/providers.ts
|
|
4028
|
-
var
|
|
4263
|
+
var import_zod13 = require("zod");
|
|
4029
4264
|
var PROVIDER_KINDS = ["smtp", "resend"];
|
|
4030
|
-
var ProviderKind =
|
|
4031
|
-
var ProviderPolicy =
|
|
4032
|
-
daily_recipient_budget:
|
|
4033
|
-
min_interval_ms:
|
|
4034
|
-
max_recipients_per_message:
|
|
4265
|
+
var ProviderKind = import_zod13.z.enum(PROVIDER_KINDS);
|
|
4266
|
+
var ProviderPolicy = import_zod13.z.object({
|
|
4267
|
+
daily_recipient_budget: import_zod13.z.number().int().min(1).max(1e7),
|
|
4268
|
+
min_interval_ms: import_zod13.z.number().int().min(0).max(36e5),
|
|
4269
|
+
max_recipients_per_message: import_zod13.z.number().int().min(1).max(1e3)
|
|
4035
4270
|
});
|
|
4036
4271
|
var ICLOUD_SMTP_POLICY = {
|
|
4037
4272
|
daily_recipient_budget: 800,
|
|
@@ -4039,17 +4274,17 @@ var ICLOUD_SMTP_POLICY = {
|
|
|
4039
4274
|
max_recipients_per_message: 1
|
|
4040
4275
|
};
|
|
4041
4276
|
var SMTP_SECURITY = ["tls", "starttls"];
|
|
4042
|
-
var SmtpConfigBase =
|
|
4043
|
-
host:
|
|
4044
|
-
port:
|
|
4277
|
+
var SmtpConfigBase = import_zod13.z.object({
|
|
4278
|
+
host: import_zod13.z.string().min(1).max(255),
|
|
4279
|
+
port: import_zod13.z.number().int().min(1).max(65535),
|
|
4045
4280
|
/** `tls` connects encrypted (465), `starttls` upgrades (587). Never plaintext. */
|
|
4046
|
-
security:
|
|
4047
|
-
username:
|
|
4281
|
+
security: import_zod13.z.enum(SMTP_SECURITY),
|
|
4282
|
+
username: import_zod13.z.string().min(1).max(255)
|
|
4048
4283
|
});
|
|
4049
|
-
var ResendConfigBase =
|
|
4050
|
-
var ProviderRejections =
|
|
4051
|
-
count:
|
|
4052
|
-
last_error:
|
|
4284
|
+
var ResendConfigBase = import_zod13.z.object({});
|
|
4285
|
+
var ProviderRejections = import_zod13.z.object({
|
|
4286
|
+
count: import_zod13.z.number().int().min(0),
|
|
4287
|
+
last_error: import_zod13.z.string().nullable(),
|
|
4053
4288
|
last_at: Timestamp.nullable(),
|
|
4054
4289
|
/**
|
|
4055
4290
|
* The last time the bounce circuit breaker tripped on one of this provider's
|
|
@@ -4059,59 +4294,59 @@ var ProviderRejections = import_zod12.z.object({
|
|
|
4059
4294
|
* run's bounce blocks were undone and the mailing paused. `sample` is the
|
|
4060
4295
|
* reply that tripped it.
|
|
4061
4296
|
*/
|
|
4062
|
-
anomaly:
|
|
4297
|
+
anomaly: import_zod13.z.object({
|
|
4063
4298
|
at: Timestamp,
|
|
4064
4299
|
/** `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. */
|
|
4065
|
-
scope:
|
|
4300
|
+
scope: import_zod13.z.enum(["mailing", "provider"]),
|
|
4066
4301
|
/**
|
|
4067
4302
|
* True while the provider-wide breaker is open: no bounce blocks through
|
|
4068
4303
|
* this provider, test sends refused and mailings not started or resumed
|
|
4069
4304
|
* (`provider_anomaly`), until an admin clears it (`providers.clearAnomaly`).
|
|
4070
4305
|
*/
|
|
4071
|
-
blocking:
|
|
4306
|
+
blocking: import_zod13.z.boolean(),
|
|
4072
4307
|
mailing_id: Id.nullable(),
|
|
4073
|
-
reason:
|
|
4074
|
-
sample:
|
|
4308
|
+
reason: import_zod13.z.string(),
|
|
4309
|
+
sample: import_zod13.z.string()
|
|
4075
4310
|
}).nullable()
|
|
4076
4311
|
});
|
|
4077
|
-
var ProviderEvents =
|
|
4078
|
-
status:
|
|
4079
|
-
source:
|
|
4080
|
-
url:
|
|
4081
|
-
error:
|
|
4312
|
+
var ProviderEvents = import_zod13.z.object({
|
|
4313
|
+
status: import_zod13.z.enum(["active", "needs_secret"]),
|
|
4314
|
+
source: import_zod13.z.enum(["automatic", "manual"]).nullable(),
|
|
4315
|
+
url: import_zod13.z.string().url(),
|
|
4316
|
+
error: import_zod13.z.string().nullable(),
|
|
4082
4317
|
/**
|
|
4083
4318
|
* Events that named an email this provider never sent through the service
|
|
4084
4319
|
* (another workspace or system sharing the Resend account): counted, never
|
|
4085
4320
|
* acted on.
|
|
4086
4321
|
*/
|
|
4087
|
-
unmatched:
|
|
4322
|
+
unmatched: import_zod13.z.number().int().min(0)
|
|
4088
4323
|
});
|
|
4089
4324
|
var RESEND_EVENT_TYPES = ["email.bounced", "email.complained", "email.delivery_delayed"];
|
|
4090
|
-
var ResendSigningSecret =
|
|
4091
|
-
var ProviderEventsSecret =
|
|
4325
|
+
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_");
|
|
4326
|
+
var ProviderEventsSecret = import_zod13.z.object({ signing_secret: ResendSigningSecret });
|
|
4092
4327
|
var ProviderFields = {
|
|
4093
|
-
name:
|
|
4094
|
-
from_name:
|
|
4328
|
+
name: import_zod13.z.string().min(1).max(120),
|
|
4329
|
+
from_name: import_zod13.z.string().min(1).max(120),
|
|
4095
4330
|
from_email: Email,
|
|
4096
4331
|
reply_to: Email.nullable(),
|
|
4097
4332
|
policy: ProviderPolicy
|
|
4098
4333
|
};
|
|
4099
|
-
var Provider =
|
|
4100
|
-
|
|
4334
|
+
var Provider = import_zod13.z.discriminatedUnion("kind", [
|
|
4335
|
+
import_zod13.z.object({
|
|
4101
4336
|
id: Id,
|
|
4102
|
-
kind:
|
|
4337
|
+
kind: import_zod13.z.literal("smtp"),
|
|
4103
4338
|
config: SmtpConfigBase,
|
|
4104
|
-
has_secret:
|
|
4339
|
+
has_secret: import_zod13.z.boolean(),
|
|
4105
4340
|
...ProviderFields,
|
|
4106
4341
|
rejections: ProviderRejections,
|
|
4107
4342
|
created_at: Timestamp,
|
|
4108
4343
|
updated_at: Timestamp
|
|
4109
4344
|
}),
|
|
4110
|
-
|
|
4345
|
+
import_zod13.z.object({
|
|
4111
4346
|
id: Id,
|
|
4112
|
-
kind:
|
|
4347
|
+
kind: import_zod13.z.literal("resend"),
|
|
4113
4348
|
config: ResendConfigBase,
|
|
4114
|
-
has_secret:
|
|
4349
|
+
has_secret: import_zod13.z.boolean(),
|
|
4115
4350
|
...ProviderFields,
|
|
4116
4351
|
rejections: ProviderRejections,
|
|
4117
4352
|
events: ProviderEvents,
|
|
@@ -4119,31 +4354,31 @@ var Provider = import_zod12.z.discriminatedUnion("kind", [
|
|
|
4119
4354
|
updated_at: Timestamp
|
|
4120
4355
|
})
|
|
4121
4356
|
]);
|
|
4122
|
-
var ProviderCreate =
|
|
4123
|
-
|
|
4124
|
-
kind:
|
|
4125
|
-
config: SmtpConfigBase.extend({ password:
|
|
4357
|
+
var ProviderCreate = import_zod13.z.discriminatedUnion("kind", [
|
|
4358
|
+
import_zod13.z.object({
|
|
4359
|
+
kind: import_zod13.z.literal("smtp"),
|
|
4360
|
+
config: SmtpConfigBase.extend({ password: import_zod13.z.string().min(1).max(1024) }),
|
|
4126
4361
|
...ProviderFields
|
|
4127
4362
|
}),
|
|
4128
|
-
|
|
4129
|
-
kind:
|
|
4130
|
-
config: ResendConfigBase.extend({ api_key:
|
|
4363
|
+
import_zod13.z.object({
|
|
4364
|
+
kind: import_zod13.z.literal("resend"),
|
|
4365
|
+
config: ResendConfigBase.extend({ api_key: import_zod13.z.string().min(1).max(1024) }),
|
|
4131
4366
|
...ProviderFields
|
|
4132
4367
|
})
|
|
4133
4368
|
]);
|
|
4134
|
-
var ProviderUpdate =
|
|
4135
|
-
|
|
4136
|
-
kind:
|
|
4137
|
-
config: SmtpConfigBase.extend({ password:
|
|
4369
|
+
var ProviderUpdate = import_zod13.z.discriminatedUnion("kind", [
|
|
4370
|
+
import_zod13.z.object({
|
|
4371
|
+
kind: import_zod13.z.literal("smtp"),
|
|
4372
|
+
config: SmtpConfigBase.extend({ password: import_zod13.z.string().min(1).max(1024).optional() }).partial().optional(),
|
|
4138
4373
|
name: ProviderFields.name.optional(),
|
|
4139
4374
|
from_name: ProviderFields.from_name.optional(),
|
|
4140
4375
|
from_email: ProviderFields.from_email.optional(),
|
|
4141
4376
|
reply_to: ProviderFields.reply_to.optional(),
|
|
4142
4377
|
policy: ProviderPolicy.partial().optional()
|
|
4143
4378
|
}),
|
|
4144
|
-
|
|
4145
|
-
kind:
|
|
4146
|
-
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).optional() }).optional(),
|
|
4147
4382
|
name: ProviderFields.name.optional(),
|
|
4148
4383
|
from_name: ProviderFields.from_name.optional(),
|
|
4149
4384
|
from_email: ProviderFields.from_email.optional(),
|
|
@@ -4151,48 +4386,48 @@ var ProviderUpdate = import_zod12.z.discriminatedUnion("kind", [
|
|
|
4151
4386
|
policy: ProviderPolicy.partial().optional()
|
|
4152
4387
|
})
|
|
4153
4388
|
]);
|
|
4154
|
-
var ProviderUsage =
|
|
4389
|
+
var ProviderUsage = import_zod13.z.object({
|
|
4155
4390
|
provider_id: Id,
|
|
4156
|
-
recipients_last_24h:
|
|
4157
|
-
remaining_budget:
|
|
4391
|
+
recipients_last_24h: import_zod13.z.number().int().min(0),
|
|
4392
|
+
remaining_budget: import_zod13.z.number().int().min(0),
|
|
4158
4393
|
/** When enough of the rolling window frees up to send again, if exhausted. */
|
|
4159
4394
|
next_capacity_at: Timestamp.nullable()
|
|
4160
4395
|
});
|
|
4161
|
-
var ProviderVerifyResult =
|
|
4162
|
-
ok:
|
|
4163
|
-
error:
|
|
4396
|
+
var ProviderVerifyResult = import_zod13.z.object({
|
|
4397
|
+
ok: import_zod13.z.boolean(),
|
|
4398
|
+
error: import_zod13.z.string().nullable()
|
|
4164
4399
|
});
|
|
4165
4400
|
|
|
4166
4401
|
// src/contacts.ts
|
|
4167
|
-
var
|
|
4168
|
-
var Topic =
|
|
4402
|
+
var import_zod14 = require("zod");
|
|
4403
|
+
var Topic = import_zod14.z.object({
|
|
4169
4404
|
id: Id,
|
|
4170
4405
|
slug: Slug,
|
|
4171
|
-
name:
|
|
4406
|
+
name: import_zod14.z.string().min(1).max(120),
|
|
4172
4407
|
/** Shown on the hosted preference page. */
|
|
4173
|
-
description:
|
|
4408
|
+
description: import_zod14.z.string().max(1e3).nullable(),
|
|
4174
4409
|
/** Translations of `name` and `description` per locale, for the hosted page. */
|
|
4175
|
-
translations:
|
|
4176
|
-
|
|
4410
|
+
translations: import_zod14.z.record(
|
|
4411
|
+
import_zod14.z.object({ name: import_zod14.z.string().min(1).max(120), description: import_zod14.z.string().max(1e3).nullable() })
|
|
4177
4412
|
),
|
|
4178
4413
|
created_at: Timestamp,
|
|
4179
4414
|
updated_at: Timestamp
|
|
4180
4415
|
});
|
|
4181
|
-
var TopicCreate =
|
|
4416
|
+
var TopicCreate = import_zod14.z.object({
|
|
4182
4417
|
slug: Slug,
|
|
4183
|
-
name:
|
|
4184
|
-
description:
|
|
4418
|
+
name: import_zod14.z.string().min(1).max(120),
|
|
4419
|
+
description: import_zod14.z.string().max(1e3).optional(),
|
|
4185
4420
|
translations: Topic.shape.translations.optional()
|
|
4186
4421
|
});
|
|
4187
4422
|
var TopicUpdate = TopicCreate.omit({ slug: true }).partial().refine((v) => Object.keys(v).length > 0, "at least one field");
|
|
4188
|
-
var Contact =
|
|
4423
|
+
var Contact = import_zod14.z.object({
|
|
4189
4424
|
id: Id,
|
|
4190
|
-
external_id:
|
|
4425
|
+
external_id: import_zod14.z.string().min(1).max(255).nullable(),
|
|
4191
4426
|
/** Stored lowercased, unique per workspace. */
|
|
4192
4427
|
email: Email,
|
|
4193
|
-
first_name:
|
|
4194
|
-
last_name:
|
|
4195
|
-
locale:
|
|
4428
|
+
first_name: import_zod14.z.string().max(200).nullable(),
|
|
4429
|
+
last_name: import_zod14.z.string().max(200).nullable(),
|
|
4430
|
+
locale: import_zod14.z.string().min(2).max(35).nullable(),
|
|
4196
4431
|
/**
|
|
4197
4432
|
* The person's own time zone, an IANA name such as `Europe/Berlin` (A1).
|
|
4198
4433
|
* Every wall clock an automation waits for is read in it, falling back to the
|
|
@@ -4200,65 +4435,65 @@ var Contact = import_zod13.z.object({
|
|
|
4200
4435
|
*/
|
|
4201
4436
|
timezone: TimezoneName.nullable(),
|
|
4202
4437
|
properties: Properties,
|
|
4203
|
-
topics:
|
|
4438
|
+
topics: import_zod14.z.array(Slug),
|
|
4204
4439
|
/** The slugs of the contact's tags (S4). */
|
|
4205
|
-
tags:
|
|
4440
|
+
tags: import_zod14.z.array(Slug),
|
|
4206
4441
|
created_at: Timestamp,
|
|
4207
4442
|
updated_at: Timestamp
|
|
4208
4443
|
});
|
|
4209
|
-
var ContactUpsert =
|
|
4210
|
-
external_id:
|
|
4444
|
+
var ContactUpsert = import_zod14.z.object({
|
|
4445
|
+
external_id: import_zod14.z.string().min(1).max(255).optional(),
|
|
4211
4446
|
email: Email.optional(),
|
|
4212
|
-
first_name:
|
|
4213
|
-
last_name:
|
|
4214
|
-
locale:
|
|
4447
|
+
first_name: import_zod14.z.string().max(200).nullable().optional(),
|
|
4448
|
+
last_name: import_zod14.z.string().max(200).nullable().optional(),
|
|
4449
|
+
locale: import_zod14.z.string().min(2).max(35).nullable().optional(),
|
|
4215
4450
|
timezone: TimezoneName.nullable().optional(),
|
|
4216
4451
|
properties: Properties.optional(),
|
|
4217
|
-
topics:
|
|
4452
|
+
topics: import_zod14.z.array(Slug).max(100).optional()
|
|
4218
4453
|
}).refine((v) => v.external_id !== void 0 || v.email !== void 0, {
|
|
4219
4454
|
message: "external_id or email is required",
|
|
4220
4455
|
path: ["email"]
|
|
4221
4456
|
});
|
|
4222
|
-
var ContactUpsertResult =
|
|
4457
|
+
var ContactUpsertResult = import_zod14.z.object({
|
|
4223
4458
|
contact: Contact,
|
|
4224
|
-
created:
|
|
4459
|
+
created: import_zod14.z.boolean()
|
|
4225
4460
|
});
|
|
4226
4461
|
var ContactListQuery = PageQuery.extend({
|
|
4227
|
-
email:
|
|
4228
|
-
external_id:
|
|
4462
|
+
email: import_zod14.z.string().min(1).max(254).optional(),
|
|
4463
|
+
external_id: import_zod14.z.string().min(1).max(255).optional(),
|
|
4229
4464
|
topic: Slug.optional()
|
|
4230
4465
|
});
|
|
4231
|
-
var ContactErased =
|
|
4232
|
-
ok:
|
|
4233
|
-
erased_messages:
|
|
4234
|
-
erased_recipients:
|
|
4235
|
-
suppressions_kept:
|
|
4466
|
+
var ContactErased = import_zod14.z.object({
|
|
4467
|
+
ok: import_zod14.z.literal(true),
|
|
4468
|
+
erased_messages: import_zod14.z.number().int().min(0),
|
|
4469
|
+
erased_recipients: import_zod14.z.number().int().min(0),
|
|
4470
|
+
suppressions_kept: import_zod14.z.number().int().min(0)
|
|
4236
4471
|
});
|
|
4237
4472
|
var SUPPRESSION_REASONS = ["unsubscribed", "bounced", "complained", "manual"];
|
|
4238
|
-
var SuppressionReason =
|
|
4239
|
-
var Suppression =
|
|
4473
|
+
var SuppressionReason = import_zod14.z.enum(SUPPRESSION_REASONS);
|
|
4474
|
+
var Suppression = import_zod14.z.object({
|
|
4240
4475
|
id: Id,
|
|
4241
4476
|
email: Email,
|
|
4242
4477
|
reason: SuppressionReason,
|
|
4243
4478
|
topic: Slug.nullable(),
|
|
4244
4479
|
source_message_id: Id.nullable(),
|
|
4245
|
-
note:
|
|
4480
|
+
note: import_zod14.z.string().max(1e3).nullable(),
|
|
4246
4481
|
created_at: Timestamp
|
|
4247
4482
|
});
|
|
4248
|
-
var SuppressionCreate =
|
|
4483
|
+
var SuppressionCreate = import_zod14.z.object({
|
|
4249
4484
|
email: Email,
|
|
4250
|
-
reason:
|
|
4485
|
+
reason: import_zod14.z.enum(["manual", "unsubscribed"]),
|
|
4251
4486
|
topic: Slug.nullable().optional(),
|
|
4252
|
-
note:
|
|
4487
|
+
note: import_zod14.z.string().max(1e3).optional()
|
|
4253
4488
|
});
|
|
4254
4489
|
var SuppressionListQuery = PageQuery.extend({
|
|
4255
|
-
email:
|
|
4490
|
+
email: import_zod14.z.string().min(1).max(254).optional(),
|
|
4256
4491
|
reason: SuppressionReason.optional(),
|
|
4257
4492
|
topic: Slug.optional()
|
|
4258
4493
|
});
|
|
4259
4494
|
|
|
4260
4495
|
// src/webhooks.ts
|
|
4261
|
-
var
|
|
4496
|
+
var import_zod15 = require("zod");
|
|
4262
4497
|
var WEBHOOK_EVENT_TYPES = [
|
|
4263
4498
|
"message.sent",
|
|
4264
4499
|
"message.failed",
|
|
@@ -4302,23 +4537,23 @@ var WEBHOOK_EVENT_TYPES = [
|
|
|
4302
4537
|
"template.updated",
|
|
4303
4538
|
"template.deleted"
|
|
4304
4539
|
];
|
|
4305
|
-
var WebhookEventType =
|
|
4306
|
-
var MessageEventBase =
|
|
4540
|
+
var WebhookEventType = import_zod15.z.enum(WEBHOOK_EVENT_TYPES);
|
|
4541
|
+
var MessageEventBase = import_zod15.z.object({
|
|
4307
4542
|
message_id: Id,
|
|
4308
4543
|
mailing_id: Id.nullable(),
|
|
4309
4544
|
mailing_metadata: MailingMetadata.nullable(),
|
|
4310
4545
|
recipient_id: Id.nullable(),
|
|
4311
4546
|
contact_id: Id.nullable(),
|
|
4312
|
-
external_id:
|
|
4547
|
+
external_id: import_zod15.z.string().nullable(),
|
|
4313
4548
|
email: Email,
|
|
4314
|
-
subject:
|
|
4549
|
+
subject: import_zod15.z.string(),
|
|
4315
4550
|
topic: Slug.nullable(),
|
|
4316
|
-
provider_message_id:
|
|
4317
|
-
is_test:
|
|
4551
|
+
provider_message_id: import_zod15.z.string().nullable(),
|
|
4552
|
+
is_test: import_zod15.z.boolean()
|
|
4318
4553
|
});
|
|
4319
4554
|
var MessageSentData = MessageEventBase.extend({
|
|
4320
4555
|
/** The final HTML as sent, so the client can archive it beside its own records. */
|
|
4321
|
-
html:
|
|
4556
|
+
html: import_zod15.z.string(),
|
|
4322
4557
|
sent_at: Timestamp,
|
|
4323
4558
|
/**
|
|
4324
4559
|
* The choice each insertion made (see `Message.insertions`); absent or null
|
|
@@ -4329,20 +4564,20 @@ var MessageSentData = MessageEventBase.extend({
|
|
|
4329
4564
|
insertions: InsertionChoices.nullish()
|
|
4330
4565
|
});
|
|
4331
4566
|
var MessageFailedData = MessageEventBase.extend({
|
|
4332
|
-
error:
|
|
4567
|
+
error: import_zod15.z.string(),
|
|
4333
4568
|
/** False when the provider rejected permanently; the recipient will not be retried. */
|
|
4334
|
-
retryable:
|
|
4569
|
+
retryable: import_zod15.z.boolean(),
|
|
4335
4570
|
failed_at: Timestamp
|
|
4336
4571
|
});
|
|
4337
4572
|
var UNSUBSCRIBE_SOURCES = ["hosted_page", "one_click", "api", "dashboard", "signup_form"];
|
|
4338
|
-
var ContactUnsubscribedData =
|
|
4573
|
+
var ContactUnsubscribedData = import_zod15.z.object({
|
|
4339
4574
|
contact_id: Id.nullable(),
|
|
4340
|
-
external_id:
|
|
4575
|
+
external_id: import_zod15.z.string().nullable(),
|
|
4341
4576
|
email: Email,
|
|
4342
4577
|
/** The topic unsubscribed from; null means every topic. */
|
|
4343
4578
|
topic: Slug.nullable(),
|
|
4344
4579
|
mailing_id: Id.nullable(),
|
|
4345
|
-
source:
|
|
4580
|
+
source: import_zod15.z.enum(UNSUBSCRIBE_SOURCES),
|
|
4346
4581
|
unsubscribed_at: Timestamp
|
|
4347
4582
|
});
|
|
4348
4583
|
var ContactResubscribedData = ContactUnsubscribedData.omit({ unsubscribed_at: true }).extend({
|
|
@@ -4351,142 +4586,142 @@ var ContactResubscribedData = ContactUnsubscribedData.omit({ unsubscribed_at: tr
|
|
|
4351
4586
|
* breaker undid a `bounced` block it judged false (a `contact.bounced` for the
|
|
4352
4587
|
* same address and mailing went out before); `topic` is null.
|
|
4353
4588
|
*/
|
|
4354
|
-
source:
|
|
4589
|
+
source: import_zod15.z.enum([...UNSUBSCRIBE_SOURCES, "bounce_reverted"]),
|
|
4355
4590
|
resubscribed_at: Timestamp
|
|
4356
4591
|
});
|
|
4357
|
-
var ContactBouncedData =
|
|
4592
|
+
var ContactBouncedData = import_zod15.z.object({
|
|
4358
4593
|
contact_id: Id.nullable(),
|
|
4359
|
-
external_id:
|
|
4594
|
+
external_id: import_zod15.z.string().nullable(),
|
|
4360
4595
|
email: Email,
|
|
4361
4596
|
/** `bounced` for a hard bounce, `complained` for a spam complaint. */
|
|
4362
|
-
reason:
|
|
4597
|
+
reason: import_zod15.z.enum(["bounced", "complained"]),
|
|
4363
4598
|
message_id: Id.nullable(),
|
|
4364
|
-
diagnostic:
|
|
4599
|
+
diagnostic: import_zod15.z.string().nullable(),
|
|
4365
4600
|
bounced_at: Timestamp
|
|
4366
4601
|
});
|
|
4367
|
-
var MailingFinishedData =
|
|
4602
|
+
var MailingFinishedData = import_zod15.z.object({
|
|
4368
4603
|
mailing_id: Id,
|
|
4369
4604
|
mailing_metadata: MailingMetadata,
|
|
4370
|
-
status:
|
|
4605
|
+
status: import_zod15.z.enum(["sent", "partially_failed", "cancelled"]),
|
|
4371
4606
|
counts: MailingCounts,
|
|
4372
4607
|
finished_at: Timestamp
|
|
4373
4608
|
});
|
|
4374
|
-
var ContactSubscribedData =
|
|
4609
|
+
var ContactSubscribedData = import_zod15.z.object({
|
|
4375
4610
|
contact_id: Id,
|
|
4376
|
-
external_id:
|
|
4611
|
+
external_id: import_zod15.z.string().nullable(),
|
|
4377
4612
|
email: Email,
|
|
4378
|
-
topics:
|
|
4379
|
-
source:
|
|
4613
|
+
topics: import_zod15.z.array(Slug),
|
|
4614
|
+
source: import_zod15.z.enum(["signup_form", "api", "dashboard", "automation"]),
|
|
4380
4615
|
signup_form_id: Id.nullable(),
|
|
4381
|
-
signup_form_version:
|
|
4616
|
+
signup_form_version: import_zod15.z.number().int().min(1).nullable(),
|
|
4382
4617
|
subscribed_at: Timestamp
|
|
4383
4618
|
});
|
|
4384
|
-
var ImportFinishedData =
|
|
4619
|
+
var ImportFinishedData = import_zod15.z.object({
|
|
4385
4620
|
import_id: Id,
|
|
4386
|
-
status:
|
|
4621
|
+
status: import_zod15.z.enum(["completed", "cancelled", "failed"]),
|
|
4387
4622
|
result: ImportReport.nullable(),
|
|
4388
|
-
error:
|
|
4623
|
+
error: import_zod15.z.string().nullable(),
|
|
4389
4624
|
finished_at: Timestamp
|
|
4390
4625
|
});
|
|
4391
|
-
var MailingScheduledData =
|
|
4626
|
+
var MailingScheduledData = import_zod15.z.object({
|
|
4392
4627
|
mailing_id: Id,
|
|
4393
4628
|
mailing_metadata: MailingMetadata,
|
|
4394
4629
|
scheduled_at: Timestamp.nullable()
|
|
4395
4630
|
});
|
|
4396
|
-
var MailingStartedData =
|
|
4631
|
+
var MailingStartedData = import_zod15.z.object({
|
|
4397
4632
|
mailing_id: Id,
|
|
4398
4633
|
mailing_metadata: MailingMetadata,
|
|
4399
|
-
trigger:
|
|
4400
|
-
recipients:
|
|
4634
|
+
trigger: import_zod15.z.enum(["send", "schedule"]),
|
|
4635
|
+
recipients: import_zod15.z.number().int().min(0),
|
|
4401
4636
|
started_at: Timestamp
|
|
4402
4637
|
});
|
|
4403
|
-
var MailingScheduleFailedData =
|
|
4638
|
+
var MailingScheduleFailedData = import_zod15.z.object({
|
|
4404
4639
|
mailing_id: Id,
|
|
4405
4640
|
mailing_metadata: MailingMetadata,
|
|
4406
|
-
code:
|
|
4407
|
-
message:
|
|
4641
|
+
code: import_zod15.z.string(),
|
|
4642
|
+
message: import_zod15.z.string(),
|
|
4408
4643
|
failed_at: Timestamp
|
|
4409
4644
|
});
|
|
4410
|
-
var MailingAbWinnerSelectedData =
|
|
4645
|
+
var MailingAbWinnerSelectedData = import_zod15.z.object({
|
|
4411
4646
|
mailing_id: Id,
|
|
4412
4647
|
mailing_metadata: MailingMetadata,
|
|
4413
|
-
winner:
|
|
4414
|
-
decided_by:
|
|
4415
|
-
variants:
|
|
4648
|
+
winner: import_zod15.z.string(),
|
|
4649
|
+
decided_by: import_zod15.z.enum(["metric", "manual"]),
|
|
4650
|
+
variants: import_zod15.z.array(VariantAnalytics),
|
|
4416
4651
|
decided_at: Timestamp
|
|
4417
4652
|
});
|
|
4418
|
-
var ContactTaggedData =
|
|
4653
|
+
var ContactTaggedData = import_zod15.z.object({
|
|
4419
4654
|
contact_id: Id,
|
|
4420
|
-
external_id:
|
|
4655
|
+
external_id: import_zod15.z.string().nullable(),
|
|
4421
4656
|
email: Email,
|
|
4422
4657
|
/** Only the tags the contact did not already have. */
|
|
4423
|
-
tags:
|
|
4424
|
-
source:
|
|
4658
|
+
tags: import_zod15.z.array(Slug).min(1),
|
|
4659
|
+
source: import_zod15.z.enum(["api", "dashboard", "signup_form", "import", "automation"]),
|
|
4425
4660
|
tagged_at: Timestamp
|
|
4426
4661
|
});
|
|
4427
|
-
var ContactUpdatedData =
|
|
4662
|
+
var ContactUpdatedData = import_zod15.z.object({
|
|
4428
4663
|
contact_id: Id,
|
|
4429
|
-
external_id:
|
|
4664
|
+
external_id: import_zod15.z.string().nullable(),
|
|
4430
4665
|
email: Email,
|
|
4431
|
-
changed:
|
|
4666
|
+
changed: import_zod15.z.array(import_zod15.z.string()).min(1),
|
|
4432
4667
|
properties: Properties,
|
|
4433
|
-
source:
|
|
4668
|
+
source: import_zod15.z.enum(["api", "dashboard", "signup_form", "import", "automation"]),
|
|
4434
4669
|
updated_at: Timestamp
|
|
4435
4670
|
});
|
|
4436
|
-
var AutomationRunEventBase =
|
|
4671
|
+
var AutomationRunEventBase = import_zod15.z.object({
|
|
4437
4672
|
automation_id: Id,
|
|
4438
|
-
automation_name:
|
|
4673
|
+
automation_name: import_zod15.z.string(),
|
|
4439
4674
|
run_id: Id,
|
|
4440
|
-
version:
|
|
4675
|
+
version: import_zod15.z.number().int().min(1),
|
|
4441
4676
|
contact_id: Id,
|
|
4442
|
-
external_id:
|
|
4677
|
+
external_id: import_zod15.z.string().nullable(),
|
|
4443
4678
|
email: Email
|
|
4444
4679
|
});
|
|
4445
4680
|
var AutomationRunStartedData = AutomationRunEventBase.extend({
|
|
4446
4681
|
/** What let them in: a trigger kind, or `manual` for an explicit enrolment. */
|
|
4447
|
-
trigger_kind:
|
|
4682
|
+
trigger_kind: import_zod15.z.string(),
|
|
4448
4683
|
entered_at: Timestamp
|
|
4449
4684
|
});
|
|
4450
4685
|
var AutomationRunCompletedData = AutomationRunEventBase.extend({
|
|
4451
|
-
last_step_id:
|
|
4686
|
+
last_step_id: import_zod15.z.string().nullable(),
|
|
4452
4687
|
completed_at: Timestamp
|
|
4453
4688
|
});
|
|
4454
4689
|
var AutomationRunExitedData = AutomationRunEventBase.extend({
|
|
4455
4690
|
reason: AutomationEndReason,
|
|
4456
|
-
step_id:
|
|
4691
|
+
step_id: import_zod15.z.string().nullable(),
|
|
4457
4692
|
exited_at: Timestamp
|
|
4458
4693
|
});
|
|
4459
4694
|
var AutomationRunFailedData = AutomationRunEventBase.extend({
|
|
4460
|
-
reason:
|
|
4461
|
-
step_id:
|
|
4695
|
+
reason: import_zod15.z.string(),
|
|
4696
|
+
step_id: import_zod15.z.string().nullable(),
|
|
4462
4697
|
failed_at: Timestamp
|
|
4463
4698
|
});
|
|
4464
4699
|
var AutomationWebhookData = AutomationRunEventBase.extend({
|
|
4465
|
-
step_id:
|
|
4700
|
+
step_id: import_zod15.z.string(),
|
|
4466
4701
|
/** The step's own label, when it was given one, so a receiver can branch on a name. */
|
|
4467
|
-
step_label:
|
|
4702
|
+
step_label: import_zod15.z.string().nullable(),
|
|
4468
4703
|
/** Whatever the step carries, verbatim. Null when it carries nothing. */
|
|
4469
4704
|
payload: JsonValue.nullable(),
|
|
4470
4705
|
fired_at: Timestamp
|
|
4471
4706
|
});
|
|
4472
|
-
var TemplateEventBase =
|
|
4707
|
+
var TemplateEventBase = import_zod15.z.object({
|
|
4473
4708
|
template_id: Id,
|
|
4474
|
-
name:
|
|
4475
|
-
version:
|
|
4476
|
-
source:
|
|
4709
|
+
name: import_zod15.z.string().min(1).max(200),
|
|
4710
|
+
version: import_zod15.z.number().int().min(1),
|
|
4711
|
+
source: import_zod15.z.enum(["api", "dashboard", "mjml_import"])
|
|
4477
4712
|
});
|
|
4478
4713
|
var TemplateCreatedData = TemplateEventBase.extend({ created_at: Timestamp });
|
|
4479
|
-
var TemplateUpdatedData = TemplateEventBase.extend({ archived:
|
|
4714
|
+
var TemplateUpdatedData = TemplateEventBase.extend({ archived: import_zod15.z.boolean(), updated_at: Timestamp });
|
|
4480
4715
|
var TemplateDeletedData = TemplateEventBase.extend({ deleted_at: Timestamp });
|
|
4481
|
-
var envelope = (type, data) =>
|
|
4716
|
+
var envelope = (type, data) => import_zod15.z.object({
|
|
4482
4717
|
/** Unique per event: a receiver deduplicates on it (deliveries may repeat). */
|
|
4483
4718
|
id: Id,
|
|
4484
|
-
type:
|
|
4719
|
+
type: import_zod15.z.literal(type),
|
|
4485
4720
|
created_at: Timestamp,
|
|
4486
4721
|
workspace_id: Id,
|
|
4487
4722
|
data
|
|
4488
4723
|
});
|
|
4489
|
-
var WebhookEvent =
|
|
4724
|
+
var WebhookEvent = import_zod15.z.discriminatedUnion("type", [
|
|
4490
4725
|
envelope("message.sent", MessageSentData),
|
|
4491
4726
|
envelope("message.failed", MessageFailedData),
|
|
4492
4727
|
envelope("contact.unsubscribed", ContactUnsubscribedData),
|
|
@@ -4510,16 +4745,16 @@ var WebhookEvent = import_zod14.z.discriminatedUnion("type", [
|
|
|
4510
4745
|
envelope("template.updated", TemplateUpdatedData),
|
|
4511
4746
|
envelope("template.deleted", TemplateDeletedData)
|
|
4512
4747
|
]);
|
|
4513
|
-
var WebhookEndpoint =
|
|
4748
|
+
var WebhookEndpoint = import_zod15.z.object({
|
|
4514
4749
|
id: Id,
|
|
4515
|
-
url:
|
|
4516
|
-
description:
|
|
4517
|
-
events:
|
|
4518
|
-
enabled:
|
|
4750
|
+
url: import_zod15.z.string().url(),
|
|
4751
|
+
description: import_zod15.z.string().max(500).nullable(),
|
|
4752
|
+
events: import_zod15.z.array(WebhookEventType).min(1),
|
|
4753
|
+
enabled: import_zod15.z.boolean(),
|
|
4519
4754
|
created_at: Timestamp,
|
|
4520
4755
|
updated_at: Timestamp
|
|
4521
4756
|
});
|
|
4522
|
-
var WebhookUrl =
|
|
4757
|
+
var WebhookUrl = import_zod15.z.string().url().refine((u) => {
|
|
4523
4758
|
try {
|
|
4524
4759
|
const url = new URL(u);
|
|
4525
4760
|
if (url.protocol === "https:") return true;
|
|
@@ -4528,35 +4763,35 @@ var WebhookUrl = import_zod14.z.string().url().refine((u) => {
|
|
|
4528
4763
|
return false;
|
|
4529
4764
|
}
|
|
4530
4765
|
}, "must be https (http only for localhost)");
|
|
4531
|
-
var WebhookEndpointCreate =
|
|
4766
|
+
var WebhookEndpointCreate = import_zod15.z.object({
|
|
4532
4767
|
url: WebhookUrl,
|
|
4533
|
-
description:
|
|
4534
|
-
events:
|
|
4535
|
-
enabled:
|
|
4768
|
+
description: import_zod15.z.string().max(500).optional(),
|
|
4769
|
+
events: import_zod15.z.array(WebhookEventType).min(1),
|
|
4770
|
+
enabled: import_zod15.z.boolean().optional()
|
|
4536
4771
|
});
|
|
4537
|
-
var WebhookEndpointUpdate =
|
|
4772
|
+
var WebhookEndpointUpdate = import_zod15.z.object({
|
|
4538
4773
|
url: WebhookUrl,
|
|
4539
|
-
description:
|
|
4540
|
-
events:
|
|
4541
|
-
enabled:
|
|
4774
|
+
description: import_zod15.z.string().max(500).nullable(),
|
|
4775
|
+
events: import_zod15.z.array(WebhookEventType).min(1),
|
|
4776
|
+
enabled: import_zod15.z.boolean()
|
|
4542
4777
|
}).partial().refine((v) => Object.keys(v).length > 0, "at least one field");
|
|
4543
|
-
var WebhookEndpointWithSecret =
|
|
4778
|
+
var WebhookEndpointWithSecret = import_zod15.z.object({
|
|
4544
4779
|
endpoint: WebhookEndpoint,
|
|
4545
|
-
secret:
|
|
4780
|
+
secret: import_zod15.z.string().min(32)
|
|
4546
4781
|
});
|
|
4547
4782
|
var WEBHOOK_DELIVERY_STATUSES = ["pending", "succeeded", "failed"];
|
|
4548
|
-
var WebhookDeliveryStatus =
|
|
4783
|
+
var WebhookDeliveryStatus = import_zod15.z.enum(WEBHOOK_DELIVERY_STATUSES);
|
|
4549
4784
|
var WEBHOOK_MAX_ATTEMPTS = 8;
|
|
4550
4785
|
var WEBHOOK_RETRY_DELAYS_SECONDS = [30, 120, 600, 1800, 3600, 7200, 21600];
|
|
4551
|
-
var WebhookDelivery =
|
|
4786
|
+
var WebhookDelivery = import_zod15.z.object({
|
|
4552
4787
|
id: Id,
|
|
4553
4788
|
endpoint_id: Id,
|
|
4554
4789
|
event_id: Id,
|
|
4555
4790
|
event_type: WebhookEventType,
|
|
4556
4791
|
status: WebhookDeliveryStatus,
|
|
4557
|
-
attempts:
|
|
4558
|
-
last_status_code:
|
|
4559
|
-
last_error:
|
|
4792
|
+
attempts: import_zod15.z.number().int().min(0),
|
|
4793
|
+
last_status_code: import_zod15.z.number().int().min(100).max(599).nullable(),
|
|
4794
|
+
last_error: import_zod15.z.string().nullable(),
|
|
4560
4795
|
next_attempt_at: Timestamp.nullable(),
|
|
4561
4796
|
delivered_at: Timestamp.nullable(),
|
|
4562
4797
|
created_at: Timestamp
|
|
@@ -4565,7 +4800,7 @@ var WebhookDeliveryListQuery = PageQuery.extend({
|
|
|
4565
4800
|
status: WebhookDeliveryStatus.optional(),
|
|
4566
4801
|
event_type: WebhookEventType.optional()
|
|
4567
4802
|
});
|
|
4568
|
-
var WebhookDeliveryParams =
|
|
4803
|
+
var WebhookDeliveryParams = import_zod15.z.object({ id: Id, delivery_id: Id });
|
|
4569
4804
|
|
|
4570
4805
|
// src/webhook-signing.ts
|
|
4571
4806
|
var WEBHOOK_SIGNATURE_HEADER = "x-mail-signature";
|
|
@@ -4632,79 +4867,79 @@ async function verifyWebhook(input) {
|
|
|
4632
4867
|
}
|
|
4633
4868
|
|
|
4634
4869
|
// src/billing.ts
|
|
4635
|
-
var
|
|
4870
|
+
var import_zod16 = require("zod");
|
|
4636
4871
|
var PLAN_IDS = ["free", "starter", "growth", "design_partner"];
|
|
4637
|
-
var PlanId =
|
|
4638
|
-
var PlanLimits =
|
|
4639
|
-
monthly_messages:
|
|
4640
|
-
contacts:
|
|
4641
|
-
members:
|
|
4642
|
-
providers:
|
|
4643
|
-
webhook_endpoints:
|
|
4872
|
+
var PlanId = import_zod16.z.enum(PLAN_IDS);
|
|
4873
|
+
var PlanLimits = import_zod16.z.object({
|
|
4874
|
+
monthly_messages: import_zod16.z.number().int().min(0).nullable(),
|
|
4875
|
+
contacts: import_zod16.z.number().int().min(0).nullable(),
|
|
4876
|
+
members: import_zod16.z.number().int().min(1).nullable(),
|
|
4877
|
+
providers: import_zod16.z.number().int().min(1).nullable(),
|
|
4878
|
+
webhook_endpoints: import_zod16.z.number().int().min(0).nullable(),
|
|
4644
4879
|
/** Automations that may be live (active or paused) at once (A1). */
|
|
4645
|
-
active_automations:
|
|
4880
|
+
active_automations: import_zod16.z.number().int().min(0).nullable(),
|
|
4646
4881
|
/** Steps one automation may hold. Null is the flow's own cap, not unlimited. */
|
|
4647
|
-
automation_steps:
|
|
4882
|
+
automation_steps: import_zod16.z.number().int().min(1).nullable()
|
|
4648
4883
|
});
|
|
4649
|
-
var PlanFeatures =
|
|
4884
|
+
var PlanFeatures = import_zod16.z.object({
|
|
4650
4885
|
/** A/B tests of subject and content on a mailing (S4). */
|
|
4651
|
-
ab_testing:
|
|
4886
|
+
ab_testing: import_zod16.z.boolean(),
|
|
4652
4887
|
/** Open and click tracking, still off until a workspace turns it on (`settings.tracking_enabled`). */
|
|
4653
|
-
tracking:
|
|
4888
|
+
tracking: import_zod16.z.boolean(),
|
|
4654
4889
|
/** Sending and hosting pages on the workspace's own domain (a later phase). */
|
|
4655
|
-
custom_domains:
|
|
4890
|
+
custom_domains: import_zod16.z.boolean(),
|
|
4656
4891
|
/** Automations: flows a person walks through step by step (A1). */
|
|
4657
|
-
automations:
|
|
4892
|
+
automations: import_zod16.z.boolean()
|
|
4658
4893
|
});
|
|
4659
4894
|
var PLAN_FEATURES = ["ab_testing", "tracking", "custom_domains", "automations"];
|
|
4660
|
-
var Plan =
|
|
4895
|
+
var Plan = import_zod16.z.object({
|
|
4661
4896
|
id: PlanId,
|
|
4662
|
-
name:
|
|
4897
|
+
name: import_zod16.z.string().min(1),
|
|
4663
4898
|
/** Price in the smallest currency unit per month; null for plans not sold. */
|
|
4664
|
-
monthly_price_cents:
|
|
4665
|
-
currency:
|
|
4899
|
+
monthly_price_cents: import_zod16.z.number().int().min(0).nullable(),
|
|
4900
|
+
currency: import_zod16.z.string().length(3),
|
|
4666
4901
|
limits: PlanLimits,
|
|
4667
4902
|
features: PlanFeatures
|
|
4668
4903
|
});
|
|
4669
|
-
var CatalogPlan = Plan.extend({ sellable:
|
|
4670
|
-
var Subscription =
|
|
4904
|
+
var CatalogPlan = Plan.extend({ sellable: import_zod16.z.boolean() });
|
|
4905
|
+
var Subscription = import_zod16.z.object({
|
|
4671
4906
|
workspace_id: Id,
|
|
4672
4907
|
plan: PlanId,
|
|
4673
|
-
status:
|
|
4908
|
+
status: import_zod16.z.enum(["active", "trialing", "past_due", "cancelled"]),
|
|
4674
4909
|
current_period_start: Timestamp,
|
|
4675
4910
|
current_period_end: Timestamp,
|
|
4676
|
-
cancel_at_period_end:
|
|
4911
|
+
cancel_at_period_end: import_zod16.z.boolean(),
|
|
4677
4912
|
/**
|
|
4678
4913
|
* A design partner outside billing (plan `design_partner`, no limits, no
|
|
4679
4914
|
* checkout). Set only by an operator, never through the API.
|
|
4680
4915
|
*/
|
|
4681
|
-
billing_exempt:
|
|
4916
|
+
billing_exempt: import_zod16.z.boolean()
|
|
4682
4917
|
});
|
|
4683
4918
|
var USAGE_METRICS = ["messages", "contacts", "members", "providers", "webhook_endpoints", "active_automations"];
|
|
4684
|
-
var UsageMetric =
|
|
4919
|
+
var UsageMetric = import_zod16.z.enum(USAGE_METRICS);
|
|
4685
4920
|
var USAGE_WARNING_RATIO = 0.8;
|
|
4686
|
-
var UsageWarning =
|
|
4921
|
+
var UsageWarning = import_zod16.z.object({
|
|
4687
4922
|
metric: UsageMetric,
|
|
4688
|
-
used:
|
|
4689
|
-
limit:
|
|
4923
|
+
used: import_zod16.z.number().int().min(0),
|
|
4924
|
+
limit: import_zod16.z.number().int().min(0),
|
|
4690
4925
|
/** `approaching`: at or above USAGE_WARNING_RATIO of the limit; `reached`: at or above the limit. */
|
|
4691
|
-
level:
|
|
4926
|
+
level: import_zod16.z.enum(["approaching", "reached"])
|
|
4692
4927
|
});
|
|
4693
|
-
var Usage =
|
|
4928
|
+
var Usage = import_zod16.z.object({
|
|
4694
4929
|
plan: PlanId,
|
|
4695
4930
|
period_start: Timestamp,
|
|
4696
4931
|
period_end: Timestamp,
|
|
4697
|
-
metrics:
|
|
4698
|
-
warnings:
|
|
4932
|
+
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() })),
|
|
4933
|
+
warnings: import_zod16.z.array(UsageWarning)
|
|
4699
4934
|
});
|
|
4700
|
-
var CheckoutRequest =
|
|
4701
|
-
plan:
|
|
4702
|
-
success_url:
|
|
4703
|
-
cancel_url:
|
|
4935
|
+
var CheckoutRequest = import_zod16.z.object({
|
|
4936
|
+
plan: import_zod16.z.enum(["starter", "growth"]),
|
|
4937
|
+
success_url: import_zod16.z.string().url(),
|
|
4938
|
+
cancel_url: import_zod16.z.string().url()
|
|
4704
4939
|
});
|
|
4705
|
-
var CheckoutSession =
|
|
4706
|
-
var PortalRequest =
|
|
4707
|
-
var PortalSession =
|
|
4940
|
+
var CheckoutSession = import_zod16.z.object({ url: import_zod16.z.string().url() });
|
|
4941
|
+
var PortalRequest = import_zod16.z.object({ return_url: import_zod16.z.string().url() });
|
|
4942
|
+
var PortalSession = import_zod16.z.object({ url: import_zod16.z.string().url() });
|
|
4708
4943
|
var USAGE_WARNING_HEADER = "x-mail-usage-warning";
|
|
4709
4944
|
function formatUsageWarningHeader(warnings) {
|
|
4710
4945
|
if (warnings.length === 0) return null;
|
|
@@ -4724,7 +4959,7 @@ function parseUsageWarningHeader(value) {
|
|
|
4724
4959
|
}
|
|
4725
4960
|
|
|
4726
4961
|
// src/routes.ts
|
|
4727
|
-
var
|
|
4962
|
+
var import_zod17 = require("zod");
|
|
4728
4963
|
var list = (item) => page(item);
|
|
4729
4964
|
var foundationRoutes = {
|
|
4730
4965
|
"workspaces.create": {
|
|
@@ -4952,7 +5187,7 @@ var templateRoutes = {
|
|
|
4952
5187
|
path: "/v1/templates/:id/export",
|
|
4953
5188
|
params: IdParams,
|
|
4954
5189
|
query: TemplateExportQuery,
|
|
4955
|
-
response:
|
|
5190
|
+
response: import_zod17.z.string(),
|
|
4956
5191
|
responseType: "text",
|
|
4957
5192
|
status: 200,
|
|
4958
5193
|
access: "read",
|
|
@@ -5276,7 +5511,7 @@ var sendingRoutes = {
|
|
|
5276
5511
|
path: "/v1/mailings/:id/export",
|
|
5277
5512
|
params: IdParams,
|
|
5278
5513
|
query: MailingExportQuery,
|
|
5279
|
-
response:
|
|
5514
|
+
response: import_zod17.z.string(),
|
|
5280
5515
|
responseType: "text",
|
|
5281
5516
|
status: 200,
|
|
5282
5517
|
access: "read",
|
|
@@ -5322,6 +5557,21 @@ var sendingRoutes = {
|
|
|
5322
5557
|
access: "write",
|
|
5323
5558
|
phase: "S2"
|
|
5324
5559
|
},
|
|
5560
|
+
/**
|
|
5561
|
+
* A dry run: what each given recipient would be sent (every value's text and
|
|
5562
|
+
* the layer it comes from, each insertion's choice, the problems found),
|
|
5563
|
+
* without adding anybody. Reads only, in any state of the mailing.
|
|
5564
|
+
*/
|
|
5565
|
+
"mailings.resolve": {
|
|
5566
|
+
method: "POST",
|
|
5567
|
+
path: "/v1/mailings/:id/resolve",
|
|
5568
|
+
params: IdParams,
|
|
5569
|
+
body: MailingResolveRequest,
|
|
5570
|
+
response: MailingResolveResult,
|
|
5571
|
+
status: 200,
|
|
5572
|
+
access: "read",
|
|
5573
|
+
phase: "S2"
|
|
5574
|
+
},
|
|
5325
5575
|
"mailings.send": {
|
|
5326
5576
|
method: "POST",
|
|
5327
5577
|
path: "/v1/mailings/:id/send",
|
|
@@ -5509,7 +5759,7 @@ var platformRoutes = {
|
|
|
5509
5759
|
"contactProperties.list": {
|
|
5510
5760
|
method: "GET",
|
|
5511
5761
|
path: "/v1/contact-properties",
|
|
5512
|
-
response:
|
|
5762
|
+
response: import_zod17.z.object({ data: import_zod17.z.array(ContactPropertyDefinition) }),
|
|
5513
5763
|
status: 200,
|
|
5514
5764
|
access: "read",
|
|
5515
5765
|
phase: "S4"
|
|
@@ -5808,7 +6058,7 @@ var billingRoutes = {
|
|
|
5808
6058
|
"billing.plans": {
|
|
5809
6059
|
method: "GET",
|
|
5810
6060
|
path: "/v1/billing/plans",
|
|
5811
|
-
response:
|
|
6061
|
+
response: import_zod17.z.object({ data: import_zod17.z.array(CatalogPlan) }),
|
|
5812
6062
|
status: 200,
|
|
5813
6063
|
access: "read",
|
|
5814
6064
|
phase: "S5"
|
|
@@ -5950,7 +6200,7 @@ var automationRoutes = {
|
|
|
5950
6200
|
method: "POST",
|
|
5951
6201
|
path: "/v1/automations/:id/pause",
|
|
5952
6202
|
params: IdParams,
|
|
5953
|
-
body:
|
|
6203
|
+
body: import_zod17.z.object({}).strict(),
|
|
5954
6204
|
response: Automation,
|
|
5955
6205
|
status: 200,
|
|
5956
6206
|
access: "write",
|
|
@@ -5960,7 +6210,7 @@ var automationRoutes = {
|
|
|
5960
6210
|
method: "POST",
|
|
5961
6211
|
path: "/v1/automations/:id/resume",
|
|
5962
6212
|
params: IdParams,
|
|
5963
|
-
body:
|
|
6213
|
+
body: import_zod17.z.object({}).strict(),
|
|
5964
6214
|
response: Automation,
|
|
5965
6215
|
status: 200,
|
|
5966
6216
|
access: "write",
|
|
@@ -5970,7 +6220,7 @@ var automationRoutes = {
|
|
|
5970
6220
|
method: "POST",
|
|
5971
6221
|
path: "/v1/automations/:id/archive",
|
|
5972
6222
|
params: IdParams,
|
|
5973
|
-
body:
|
|
6223
|
+
body: import_zod17.z.object({}).strict(),
|
|
5974
6224
|
response: Automation,
|
|
5975
6225
|
status: 200,
|
|
5976
6226
|
access: "write",
|
|
@@ -6104,13 +6354,13 @@ function matchRoute(method, pathname) {
|
|
|
6104
6354
|
for (const [id, route] of Object.entries(routes)) {
|
|
6105
6355
|
if (route.method !== method) continue;
|
|
6106
6356
|
const names = [];
|
|
6107
|
-
const
|
|
6357
|
+
const pattern3 = new RegExp(
|
|
6108
6358
|
"^" + route.path.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace(/:([a-z_]+)/g, (_, name) => {
|
|
6109
6359
|
names.push(name);
|
|
6110
6360
|
return "([^/]+)";
|
|
6111
6361
|
}) + "$"
|
|
6112
6362
|
);
|
|
6113
|
-
const match =
|
|
6363
|
+
const match = pattern3.exec(pathname);
|
|
6114
6364
|
if (!match) continue;
|
|
6115
6365
|
const params = {};
|
|
6116
6366
|
names.forEach((name, i) => {
|
|
@@ -6311,6 +6561,7 @@ function matchRoute(method, pathname) {
|
|
|
6311
6561
|
InviteListQuery,
|
|
6312
6562
|
InviteStatus,
|
|
6313
6563
|
JsonValue,
|
|
6564
|
+
LETTER_ONLY_MERGE_FIELDS,
|
|
6314
6565
|
LETTER_RECIPIENT_REFUSAL,
|
|
6315
6566
|
LIST_UNSUBSCRIBE_POST_VALUE,
|
|
6316
6567
|
LOCALE_TAG_PATTERN,
|
|
@@ -6379,7 +6630,10 @@ function matchRoute(method, pathname) {
|
|
|
6379
6630
|
MailingLanguageReport,
|
|
6380
6631
|
MailingLanguageStatus,
|
|
6381
6632
|
MailingListQuery,
|
|
6633
|
+
MailingMerge,
|
|
6382
6634
|
MailingMetadata,
|
|
6635
|
+
MailingResolveRequest,
|
|
6636
|
+
MailingResolveResult,
|
|
6383
6637
|
MailingRetryFailedRequest,
|
|
6384
6638
|
MailingScheduleFailedData,
|
|
6385
6639
|
MailingScheduleRequest,
|
|
@@ -6404,6 +6658,8 @@ function matchRoute(method, pathname) {
|
|
|
6404
6658
|
MessageOutcome,
|
|
6405
6659
|
MessageSentData,
|
|
6406
6660
|
MessageSummary,
|
|
6661
|
+
MessageValues,
|
|
6662
|
+
NAME_ON_BROADCAST_REFUSAL,
|
|
6407
6663
|
NotifyRecipients,
|
|
6408
6664
|
NotifyStep,
|
|
6409
6665
|
ON_BEHALF_OF_HEADER,
|
|
@@ -6439,6 +6695,8 @@ function matchRoute(method, pathname) {
|
|
|
6439
6695
|
REQUEST_ID_HEADER,
|
|
6440
6696
|
RESEND_EVENT_TYPES,
|
|
6441
6697
|
RESERVED_MERGE_FIELDS,
|
|
6698
|
+
RESOLVE_PROBLEMS,
|
|
6699
|
+
RESOLVE_REJECTIONS,
|
|
6442
6700
|
RETRYABLE_ERRORS,
|
|
6443
6701
|
RETRY_AFTER_HEADER,
|
|
6444
6702
|
RE_ENTRY_MODES,
|
|
@@ -6451,6 +6709,9 @@ function matchRoute(method, pathname) {
|
|
|
6451
6709
|
RecipientStatus,
|
|
6452
6710
|
RemoteImage,
|
|
6453
6711
|
ResendSigningSecret,
|
|
6712
|
+
ResolveProblem,
|
|
6713
|
+
ResolvedRecipient,
|
|
6714
|
+
ResolvedValue,
|
|
6454
6715
|
SERVICE_FILLED_MERGE_FIELDS,
|
|
6455
6716
|
SIGNUP_FORM_FIELDS,
|
|
6456
6717
|
SKIP_REASONS,
|
|
@@ -6537,10 +6798,13 @@ function matchRoute(method, pathname) {
|
|
|
6537
6798
|
USAGE_METRICS,
|
|
6538
6799
|
USAGE_WARNING_HEADER,
|
|
6539
6800
|
USAGE_WARNING_RATIO,
|
|
6801
|
+
UnfilledLink,
|
|
6540
6802
|
Usage,
|
|
6541
6803
|
UsageMetric,
|
|
6542
6804
|
UsageWarning,
|
|
6805
|
+
VALUE_LAYERS,
|
|
6543
6806
|
ValidationIssue,
|
|
6807
|
+
ValueLayer,
|
|
6544
6808
|
VariantAnalytics,
|
|
6545
6809
|
WEBHOOK_DELIVERY_STATUSES,
|
|
6546
6810
|
WEBHOOK_EVENT_ID_HEADER,
|
|
@@ -6604,6 +6868,7 @@ function matchRoute(method, pathname) {
|
|
|
6604
6868
|
editMainInsertions,
|
|
6605
6869
|
effectivePreviewPicks,
|
|
6606
6870
|
emptyFlow,
|
|
6871
|
+
emptyLinkValues,
|
|
6607
6872
|
errorBody,
|
|
6608
6873
|
escapeMergeHtml,
|
|
6609
6874
|
exportFilename,
|
|
@@ -6634,6 +6899,8 @@ function matchRoute(method, pathname) {
|
|
|
6634
6899
|
languageInsertions,
|
|
6635
6900
|
languageName,
|
|
6636
6901
|
languageTabs,
|
|
6902
|
+
letterOnlyValues,
|
|
6903
|
+
linkTokens,
|
|
6637
6904
|
mainInsertionText,
|
|
6638
6905
|
matchLocale,
|
|
6639
6906
|
matchRoute,
|
|
@@ -6654,6 +6921,8 @@ function matchRoute(method, pathname) {
|
|
|
6654
6921
|
previewInsertions,
|
|
6655
6922
|
previewPersonalization,
|
|
6656
6923
|
primaryLanguage,
|
|
6924
|
+
printedFields,
|
|
6925
|
+
rawMergeValue,
|
|
6657
6926
|
reachable,
|
|
6658
6927
|
readyWithoutInsertions,
|
|
6659
6928
|
readyWithoutSubject,
|
|
@@ -6670,6 +6939,7 @@ function matchRoute(method, pathname) {
|
|
|
6670
6939
|
renameTokenInDocument,
|
|
6671
6940
|
renameTokenInText,
|
|
6672
6941
|
resolveInsertions,
|
|
6942
|
+
resolveValue,
|
|
6673
6943
|
restorePatch,
|
|
6674
6944
|
routes,
|
|
6675
6945
|
sameJson,
|
|
@@ -6696,5 +6966,7 @@ function matchRoute(method, pathname) {
|
|
|
6696
6966
|
unknownRefusedInsertions,
|
|
6697
6967
|
unplacedInsertions,
|
|
6698
6968
|
validateAutomation,
|
|
6969
|
+
valueNames,
|
|
6970
|
+
valuesRead,
|
|
6699
6971
|
verifyWebhook
|
|
6700
6972
|
});
|