@marlinjai/mail-contract 0.6.1 → 0.8.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.
Files changed (5) hide show
  1. package/dist/index.d.mts +16533 -2594
  2. package/dist/index.d.ts +16533 -2594
  3. package/dist/index.js +1063 -763
  4. package/dist/index.mjs +1036 -763
  5. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -145,13 +145,13 @@ var API_VERSION_PREFIX = "/v1";
145
145
  var HEALTH_PATH = "/healthz";
146
146
 
147
147
  // src/workspace.ts
148
- import { z as z9 } from "zod";
148
+ import { z as z10 } from "zod";
149
149
 
150
150
  // src/automations.ts
151
- import { z as z8 } from "zod";
151
+ import { z as z9 } from "zod";
152
152
 
153
153
  // src/templates.ts
154
- import { z as z4 } from "zod";
154
+ import { z as z5 } from "zod";
155
155
 
156
156
  // src/insertions.ts
157
157
  import { z as z3 } from "zod";
@@ -442,22 +442,133 @@ function sampleMergeValue(values) {
442
442
  };
443
443
  }
444
444
 
445
+ // src/template-inputs.ts
446
+ import { z as z4 } from "zod";
447
+ var MAX_TEMPLATE_INPUTS = 50;
448
+ var MAX_TEMPLATE_INPUT_VALUES = 30;
449
+ var MAX_TEMPLATE_INPUT_LABEL_LENGTH = 80;
450
+ var MAX_TEMPLATE_INPUT_NOTE_LENGTH = 300;
451
+ var MAX_TEMPLATE_INPUT_EXAMPLE_LENGTH = 500;
452
+ var MAX_TEMPLATE_INPUTS_APP_LENGTH = 80;
453
+ var MAX_TEMPLATE_INPUTS_SEEN = 200;
454
+ var SERVICE_FILLED_MERGE_FIELDS = ["email", "unsubscribe_url"];
455
+ var line = (max) => z4.string().min(1).max(max).regex(/^[^\x00-\x1f\x7f]*$/, "one line, without control characters").refine((s) => s.trim() !== "", "not blank");
456
+ var label = line(MAX_TEMPLATE_INPUT_LABEL_LENGTH);
457
+ var note = line(MAX_TEMPLATE_INPUT_NOTE_LENGTH);
458
+ var TemplateInputName = InsertionName;
459
+ var TemplateInputSource = z4.discriminatedUnion("kind", [
460
+ z4.object({ kind: z4.literal("form_field"), form: label, field: label, note: note.optional() }),
461
+ z4.object({ kind: z4.literal("derived"), note })
462
+ ]);
463
+ var TemplateInputValue = z4.object({
464
+ /** The key the app sends, in an insertion choice's syntax, so a row "When it is venue" matches it exactly. */
465
+ value: InsertionChoiceKey,
466
+ label
467
+ });
468
+ var HttpUrl = z4.string().max(MAX_TEMPLATE_INPUT_EXAMPLE_LENGTH).url().refine((u) => {
469
+ try {
470
+ const { protocol } = new URL(u);
471
+ return protocol === "https:" || protocol === "http:";
472
+ } catch {
473
+ return false;
474
+ }
475
+ }, "an http or https address");
476
+ var common = {
477
+ /** What an author sees: "Contact reason", "First name". */
478
+ label,
479
+ source: TemplateInputSource,
480
+ /** The app may send it empty or not at all (a name nobody typed). Absent means it is always sent. */
481
+ optional: z4.boolean().optional()
482
+ };
483
+ var TemplateInput = z4.discriminatedUnion("kind", [
484
+ z4.object({ kind: z4.literal("text"), ...common, example: z4.string().max(MAX_TEMPLATE_INPUT_EXAMPLE_LENGTH).optional() }),
485
+ z4.object({ kind: z4.literal("url"), ...common, example: HttpUrl.optional() }),
486
+ z4.object({ kind: z4.literal("boolean"), ...common, example: z4.boolean().optional() }),
487
+ z4.object({
488
+ kind: z4.literal("one_of"),
489
+ ...common,
490
+ values: z4.array(TemplateInputValue).min(1).max(MAX_TEMPLATE_INPUT_VALUES),
491
+ example: InsertionChoiceKey.optional()
492
+ })
493
+ ]);
494
+ var TEMPLATE_INPUT_KINDS = ["text", "url", "boolean", "one_of"];
495
+ var TemplateInputMap = z4.record(TemplateInputName, TemplateInput).refine((m) => Object.keys(m).length <= MAX_TEMPLATE_INPUTS, `at most ${MAX_TEMPLATE_INPUTS} inputs`);
496
+ var TemplateInputsDeclaration = z4.object({
497
+ app: line(MAX_TEMPLATE_INPUTS_APP_LENGTH),
498
+ app_version: line(MAX_TEMPLATE_INPUTS_APP_LENGTH).optional(),
499
+ inputs: TemplateInputMap
500
+ });
501
+ var TemplateInputs = z4.object({
502
+ app: z4.string(),
503
+ app_version: z4.string().nullable(),
504
+ inputs: TemplateInputMap,
505
+ declared_by: z4.object({ api_key_id: Id, api_key_name: z4.string() }),
506
+ declared_at: Timestamp
507
+ });
508
+ var TemplateInputSeen = z4.object({
509
+ count: z4.number().int().min(1),
510
+ first_seen_at: Timestamp,
511
+ last_seen_at: Timestamp
512
+ });
513
+ var TemplateInputsSeen = z4.record(TemplateInputName, TemplateInputSeen);
514
+ var TemplateInputsDeclared = z4.object({
515
+ template_id: Id,
516
+ inputs: TemplateInputs,
517
+ /** False when the stored declaration already said exactly this (a redeploy of the same commit). */
518
+ changed: z4.boolean()
519
+ });
520
+ var TEMPLATE_INPUT_PROBLEM_REASONS = [
521
+ /** `email` or `unsubscribe_url`: the service fills it, a client's value is never read. */
522
+ "input_reserved",
523
+ /** A `one_of` input lists the same value twice. */
524
+ "input_values",
525
+ /** A `one_of` input's example is not one of its values. */
526
+ "input_example"
527
+ ];
528
+ function templateInputProblems(inputs) {
529
+ const problems = [];
530
+ for (const [name, input] of Object.entries(inputs)) {
531
+ if (SERVICE_FILLED_MERGE_FIELDS.includes(name)) {
532
+ problems.push({ reason: "input_reserved", path: name, message: `"${name}" is filled by the service, never by the app; leave it out of the declaration` });
533
+ }
534
+ if (input.kind !== "one_of") continue;
535
+ const seen = /* @__PURE__ */ new Set();
536
+ input.values.forEach((v, i) => {
537
+ if (seen.has(v.value)) {
538
+ problems.push({ reason: "input_values", path: `${name}.values.${i}`, message: `"${v.value}" is listed twice` });
539
+ }
540
+ seen.add(v.value);
541
+ });
542
+ if (input.example !== void 0 && !seen.has(input.example)) {
543
+ problems.push({ reason: "input_example", path: `${name}.example`, message: `the example "${input.example}" is not one of the values` });
544
+ }
545
+ }
546
+ return problems;
547
+ }
548
+ function templateInputDrift(inputs, seen) {
549
+ const declared = inputs ? Object.keys(inputs.inputs) : [];
550
+ return {
551
+ declared_not_seen: declared.filter((name) => ownEntry(seen, name) === void 0).sort(),
552
+ seen_not_declared: Object.keys(seen).filter((name) => ownEntry(inputs?.inputs, name) === void 0).sort()
553
+ };
554
+ }
555
+
445
556
  // src/templates.ts
446
557
  var DOCUMENT_SCHEMA_VERSIONS = ["1.0", "1.1"];
447
- var DocumentSchemaVersion = z4.enum(DOCUMENT_SCHEMA_VERSIONS);
448
- var TemplateDocument = z4.object({
558
+ var DocumentSchemaVersion = z5.enum(DOCUMENT_SCHEMA_VERSIONS);
559
+ var TemplateDocument = z5.object({
449
560
  version: DocumentSchemaVersion,
450
- metadata: z4.record(z4.unknown()),
451
- sections: z4.array(z4.record(z4.unknown()))
561
+ metadata: z5.record(z5.unknown()),
562
+ sections: z5.array(z5.record(z5.unknown()))
452
563
  }).passthrough();
453
564
  var MAX_DOCUMENT_BYTES = 1e6;
454
565
  var MAX_SUBJECT_LENGTH = 998;
455
566
  var MAX_PREHEADER_LENGTH = 500;
456
- var TemplateSubject = z4.string().max(MAX_SUBJECT_LENGTH).regex(/^[^\x00-\x1f\x7f]*$/, "one line, without control characters");
457
- var TemplatePreheader = z4.string().max(MAX_PREHEADER_LENGTH).regex(/^[^\x00-\x1f\x7f]*$/, "one line, without control characters");
567
+ var TemplateSubject = z5.string().max(MAX_SUBJECT_LENGTH).regex(/^[^\x00-\x1f\x7f]*$/, "one line, without control characters");
568
+ var TemplatePreheader = z5.string().max(MAX_PREHEADER_LENGTH).regex(/^[^\x00-\x1f\x7f]*$/, "one line, without control characters");
458
569
  var TEMPLATE_LANGUAGE_STATUSES = ["draft", "ready"];
459
- var TemplateLanguageStatus = z4.enum(TEMPLATE_LANGUAGE_STATUSES);
460
- var TemplateTranslation = z4.object({
570
+ var TemplateLanguageStatus = z5.enum(TEMPLATE_LANGUAGE_STATUSES);
571
+ var TemplateTranslation = z5.object({
461
572
  subject: TemplateSubject.nullable(),
462
573
  preheader: TemplatePreheader.nullable(),
463
574
  document: TemplateDocument,
@@ -475,11 +586,11 @@ var TemplateTranslation = z4.object({
475
586
  insertions: TranslationInsertions.optional()
476
587
  });
477
588
  var MAX_TEMPLATE_TRANSLATIONS = 19;
478
- var TemplateTranslations = z4.record(LocaleTag, TemplateTranslation).refine((t) => Object.keys(t).length <= MAX_TEMPLATE_TRANSLATIONS, `at most ${MAX_TEMPLATE_TRANSLATIONS} language versions`);
479
- var Template = z4.object({
589
+ var TemplateTranslations = z5.record(LocaleTag, TemplateTranslation).refine((t) => Object.keys(t).length <= MAX_TEMPLATE_TRANSLATIONS, `at most ${MAX_TEMPLATE_TRANSLATIONS} language versions`);
590
+ var Template = z5.object({
480
591
  id: Id,
481
- name: z4.string().min(1).max(200),
482
- description: z4.string().max(2e3).nullable(),
592
+ name: z5.string().min(1).max(200),
593
+ description: z5.string().max(2e3).nullable(),
483
594
  /**
484
595
  * The main language: what `subject`, `preheader` and `document` are written
485
596
  * in, and what every recipient without a ready version of their own gets.
@@ -503,21 +614,33 @@ var Template = z4.object({
503
614
  * texts in `translations[tag].insertions`.
504
615
  */
505
616
  insertions: Insertions,
617
+ /**
618
+ * What the sending app declared this template receives
619
+ * (`templates.declareInputs`); null until an app declares. Not part of a
620
+ * version: declaring never changes `version` or `updated_at`.
621
+ */
622
+ inputs: TemplateInputs.nullable(),
623
+ /**
624
+ * The merge names real sends of this template carried, with a count and
625
+ * when first and last seen. Names only, never values. `{}` before the
626
+ * first send.
627
+ */
628
+ inputs_seen: TemplateInputsSeen,
506
629
  /** Increments on every saved change, of any language. */
507
- version: z4.number().int().min(1),
508
- thumbnail_url: z4.string().url().nullable(),
630
+ version: z5.number().int().min(1),
631
+ thumbnail_url: z5.string().url().nullable(),
509
632
  archived_at: Timestamp.nullable(),
510
633
  created_at: Timestamp,
511
634
  updated_at: Timestamp
512
635
  });
513
- var TemplateSummary = Template.omit({ document: true, translations: true, insertions: true }).extend({
514
- languages: z4.record(LocaleTag, TemplateLanguageStatus),
636
+ var TemplateSummary = Template.omit({ document: true, translations: true, insertions: true, inputs: true, inputs_seen: true }).extend({
637
+ languages: z5.record(LocaleTag, TemplateLanguageStatus),
515
638
  /** The names of the template's insertions, sorted alphabetically. */
516
- insertion_names: z4.array(z4.string())
639
+ insertion_names: z5.array(z5.string())
517
640
  });
518
- var TemplateCreate = z4.object({
519
- name: z4.string().min(1).max(200),
520
- description: z4.string().max(2e3).optional(),
641
+ var TemplateCreate = z5.object({
642
+ name: z5.string().min(1).max(200),
643
+ description: z5.string().max(2e3).optional(),
521
644
  locale: LocaleTag.optional(),
522
645
  subject: TemplateSubject.nullable().optional(),
523
646
  preheader: TemplatePreheader.nullable().optional(),
@@ -525,15 +648,15 @@ var TemplateCreate = z4.object({
525
648
  translations: TemplateTranslations.optional(),
526
649
  insertions: Insertions.optional()
527
650
  });
528
- var TemplateUpdate = z4.object({
529
- base_version: z4.number().int().min(1),
530
- name: z4.string().min(1).max(200).optional(),
531
- description: z4.string().max(2e3).nullable().optional(),
651
+ var TemplateUpdate = z5.object({
652
+ base_version: z5.number().int().min(1),
653
+ name: z5.string().min(1).max(200).optional(),
654
+ description: z5.string().max(2e3).nullable().optional(),
532
655
  locale: LocaleTag.optional(),
533
656
  subject: TemplateSubject.nullable().optional(),
534
657
  preheader: TemplatePreheader.nullable().optional(),
535
658
  document: TemplateDocument.optional(),
536
- translations: z4.record(LocaleTag, TemplateTranslation.nullable()).optional(),
659
+ translations: z5.record(LocaleTag, TemplateTranslation.nullable()).optional(),
537
660
  /**
538
661
  * The main language's insertions, whole: what is left out is removed, from
539
662
  * every language in the same save. A rename is a removal and an addition,
@@ -541,87 +664,87 @@ var TemplateUpdate = z4.object({
541
664
  * save (it sends those languages in `translations`).
542
665
  */
543
666
  insertions: Insertions.optional(),
544
- archived: z4.boolean().optional()
667
+ archived: z5.boolean().optional()
545
668
  }).refine(
546
669
  (v) => v.name !== void 0 || v.description !== void 0 || v.locale !== void 0 || v.subject !== void 0 || v.preheader !== void 0 || v.document !== void 0 || v.translations !== void 0 || v.insertions !== void 0 || v.archived !== void 0,
547
670
  "at least one field besides base_version"
548
671
  );
549
- var SavedSectionBody = z4.record(z4.unknown());
672
+ var SavedSectionBody = z5.record(z5.unknown());
550
673
  var MAX_SAVED_SECTIONS = 50;
551
- var SavedSection = z4.object({
674
+ var SavedSection = z5.object({
552
675
  id: Id,
553
- name: z4.string().min(1).max(200),
554
- description: z4.string().max(2e3).nullable(),
676
+ name: z5.string().min(1).max(200),
677
+ description: z5.string().max(2e3).nullable(),
555
678
  section: SavedSectionBody,
556
- created_by: z4.string().nullable(),
679
+ created_by: z5.string().nullable(),
557
680
  created_at: Timestamp,
558
681
  updated_at: Timestamp
559
682
  });
560
- var SavedSectionCreate = z4.object({
561
- name: z4.string().min(1).max(200),
562
- description: z4.string().max(2e3).optional(),
683
+ var SavedSectionCreate = z5.object({
684
+ name: z5.string().min(1).max(200),
685
+ description: z5.string().max(2e3).optional(),
563
686
  section: SavedSectionBody
564
687
  });
565
- var SavedSectionUpdate = z4.object({
566
- name: z4.string().min(1).max(200).optional(),
567
- description: z4.string().max(2e3).nullable().optional(),
688
+ var SavedSectionUpdate = z5.object({
689
+ name: z5.string().min(1).max(200).optional(),
690
+ description: z5.string().max(2e3).nullable().optional(),
568
691
  section: SavedSectionBody.optional()
569
692
  }).refine((v) => v.name !== void 0 || v.description !== void 0 || v.section !== void 0, "at least one field");
570
693
  var TemplateListQuery = PageQuery.extend({
571
- archived: z4.enum(["true", "false"]).optional()
694
+ archived: z5.enum(["true", "false"]).optional()
572
695
  });
573
- var TemplateVersion = z4.object({
696
+ var TemplateVersion = z5.object({
574
697
  template_id: Id,
575
- version: z4.number().int().min(1),
698
+ version: z5.number().int().min(1),
576
699
  locale: LocaleTag,
577
700
  subject: TemplateSubject.nullable(),
578
701
  preheader: TemplatePreheader.nullable(),
579
702
  document: TemplateDocument,
580
703
  translations: TemplateTranslations,
581
704
  insertions: Insertions,
582
- created_by: z4.string().nullable(),
705
+ created_by: z5.string().nullable(),
583
706
  created_at: Timestamp
584
707
  });
585
- var TemplateVersionParams = z4.object({
708
+ var TemplateVersionParams = z5.object({
586
709
  id: Id,
587
- version: z4.coerce.number().int().min(1)
710
+ version: z5.coerce.number().int().min(1)
588
711
  });
589
- var CompileMessage = z4.object({
590
- message: z4.string().min(1),
712
+ var CompileMessage = z5.object({
713
+ message: z5.string().min(1),
591
714
  /** Where in the document or the MJML the message points, when known. */
592
- path: z4.string().optional(),
593
- line: z4.number().int().min(1).optional()
715
+ path: z5.string().optional(),
716
+ line: z5.number().int().min(1).optional()
594
717
  });
595
- var CompileResult = z4.object({
596
- mjml: z4.string(),
597
- html: z4.string(),
598
- warnings: z4.array(CompileMessage),
599
- errors: z4.array(CompileMessage)
718
+ var CompileResult = z5.object({
719
+ mjml: z5.string(),
720
+ html: z5.string(),
721
+ warnings: z5.array(CompileMessage),
722
+ errors: z5.array(CompileMessage)
600
723
  });
601
- var TemplateCompileRequest = z4.object({
602
- version: z4.number().int().min(1).optional(),
724
+ var TemplateCompileRequest = z5.object({
725
+ version: z5.number().int().min(1).optional(),
603
726
  locale: LocaleTag.optional()
604
727
  });
605
- var CompileRequest = z4.object({
728
+ var CompileRequest = z5.object({
606
729
  document: TemplateDocument
607
730
  });
608
731
  var ASSET_CONTENT_TYPES = ["image/png", "image/jpeg", "image/gif", "image/webp"];
609
- var AssetContentType = z4.enum(ASSET_CONTENT_TYPES);
732
+ var AssetContentType = z5.enum(ASSET_CONTENT_TYPES);
610
733
  var MAX_ASSET_BYTES = 10 * 1024 * 1024;
611
- var Asset = z4.object({
734
+ var Asset = z5.object({
612
735
  id: Id,
613
- url: z4.string().url(),
736
+ url: z5.string().url(),
614
737
  content_type: AssetContentType,
615
- size_bytes: z4.number().int().min(1).max(MAX_ASSET_BYTES),
616
- width: z4.number().int().min(1).nullable(),
617
- height: z4.number().int().min(1).nullable(),
618
- filename: z4.string().min(1).max(255),
738
+ size_bytes: z5.number().int().min(1).max(MAX_ASSET_BYTES),
739
+ width: z5.number().int().min(1).nullable(),
740
+ height: z5.number().int().min(1).nullable(),
741
+ filename: z5.string().min(1).max(255),
619
742
  created_at: Timestamp
620
743
  });
621
744
  var ASSET_UPLOAD_FIELD = "file";
622
745
  var MAX_IMPORT_URL_LENGTH = 2048;
623
- var AssetImport = z4.object({
624
- url: z4.string().max(MAX_IMPORT_URL_LENGTH).url().refine((u) => {
746
+ var AssetImport = z5.object({
747
+ url: z5.string().max(MAX_IMPORT_URL_LENGTH).url().refine((u) => {
625
748
  try {
626
749
  const url = new URL(u);
627
750
  if (url.protocol === "https:") return true;
@@ -631,7 +754,7 @@ var AssetImport = z4.object({
631
754
  }
632
755
  }, "must be https (http only for localhost)"),
633
756
  /** The stored file name; derived from the address when omitted. */
634
- filename: z4.string().min(1).max(255).optional()
757
+ filename: z5.string().min(1).max(255).optional()
635
758
  });
636
759
  var MAX_MJML_IMPORT_BYTES = 512 * 1024;
637
760
  var MAX_MJML_DEPTH = 32;
@@ -646,56 +769,56 @@ var MJML_IMPORT_REFUSALS = [
646
769
  "too_complex",
647
770
  "invalid_document"
648
771
  ];
649
- var ImportWarning = z4.object({
650
- severity: z4.enum(["info", "warning"]),
772
+ var ImportWarning = z5.object({
773
+ severity: z5.enum(["info", "warning"]),
651
774
  /** Stable kind, e.g. `kept_as_html`, `unknown_component`, `remote_image_not_imported`. */
652
- code: z4.string().min(1).max(64),
775
+ code: z5.string().min(1).max(64),
653
776
  /** Where in the source, e.g. `mj-body > mj-section[2] > mj-column[1] > mj-social[1]`. */
654
- path: z4.string(),
655
- line: z4.number().int().min(1).optional(),
656
- message: z4.string().min(1),
657
- fragment: z4.string().optional()
777
+ path: z5.string(),
778
+ line: z5.number().int().min(1).optional(),
779
+ message: z5.string().min(1),
780
+ fragment: z5.string().optional()
658
781
  });
659
- var RemoteImage = z4.object({
660
- url: z4.string().min(1),
782
+ var RemoteImage = z5.object({
783
+ url: z5.string().min(1),
661
784
  /** The element and attribute it is loaded from, e.g. `<img src>`. */
662
- where: z4.string()
785
+ where: z5.string()
663
786
  });
664
- var ImportedAsset = z4.object({
665
- source_url: z4.string().min(1),
787
+ var ImportedAsset = z5.object({
788
+ source_url: z5.string().min(1),
666
789
  asset_id: Id,
667
- url: z4.string().url()
790
+ url: z5.string().url()
668
791
  });
669
- var mjmlSource = z4.string().min(1, "paste or upload the MJML");
670
- var TemplateImportPreviewRequest = z4.object({ mjml: mjmlSource });
671
- var TemplateImportPreview = z4.object({
792
+ var mjmlSource = z5.string().min(1, "paste or upload the MJML");
793
+ var TemplateImportPreviewRequest = z5.object({ mjml: mjmlSource });
794
+ var TemplateImportPreview = z5.object({
672
795
  document: TemplateDocument,
673
- warnings: z4.array(ImportWarning),
796
+ warnings: z5.array(ImportWarning),
674
797
  /** The document compiled under the workspace's asset policy, exactly as a send would. */
675
798
  compiled: CompileResult,
676
799
  /** Images loaded from outside the service; under `service_only` each is also a compile error. */
677
- remote_images: z4.array(RemoteImage),
678
- asset_policy: z4.enum(["any", "service_only"])
800
+ remote_images: z5.array(RemoteImage),
801
+ asset_policy: z5.enum(["any", "service_only"])
679
802
  });
680
- var TemplateImport = z4.object({
681
- name: z4.string().min(1).max(200),
682
- description: z4.string().max(2e3).optional(),
803
+ var TemplateImport = z5.object({
804
+ name: z5.string().min(1).max(200),
805
+ description: z5.string().max(2e3).optional(),
683
806
  mjml: mjmlSource,
684
- import_remote_assets: z4.boolean().optional()
807
+ import_remote_assets: z5.boolean().optional()
685
808
  });
686
- var TemplateImportResult = z4.object({
809
+ var TemplateImportResult = z5.object({
687
810
  template: Template,
688
- warnings: z4.array(ImportWarning),
689
- imported_assets: z4.array(ImportedAsset)
811
+ warnings: z5.array(ImportWarning),
812
+ imported_assets: z5.array(ImportedAsset)
690
813
  });
691
814
  var EXPORT_FORMATS = ["mjml", "html"];
692
- var ExportFormat = z4.enum(EXPORT_FORMATS);
693
- var TemplateExportQuery = z4.object({
815
+ var ExportFormat = z5.enum(EXPORT_FORMATS);
816
+ var TemplateExportQuery = z5.object({
694
817
  format: ExportFormat,
695
- version: z4.coerce.number().int().min(1).optional(),
818
+ version: z5.coerce.number().int().min(1).optional(),
696
819
  locale: LocaleTag.optional()
697
820
  });
698
- var MailingExportQuery = z4.object({ format: ExportFormat });
821
+ var MailingExportQuery = z5.object({ format: ExportFormat });
699
822
  var EXPORT_CONTENT_TYPES = {
700
823
  mjml: "text/plain; charset=utf-8",
701
824
  html: "text/html; charset=utf-8"
@@ -714,7 +837,7 @@ function formatExportWarningsHeader(messages) {
714
837
  function parseExportWarningsHeader(value) {
715
838
  if (!value) return [];
716
839
  try {
717
- const parsed = z4.array(CompileMessage).safeParse(JSON.parse(decodeURIComponent(value)));
840
+ const parsed = z5.array(CompileMessage).safeParse(JSON.parse(decodeURIComponent(value)));
718
841
  return parsed.success ? parsed.data : [];
719
842
  } catch {
720
843
  return [];
@@ -726,32 +849,32 @@ function exportFilename(name, format) {
726
849
  }
727
850
 
728
851
  // src/platform.ts
729
- import { z as z7 } from "zod";
852
+ import { z as z8 } from "zod";
730
853
 
731
854
  // src/mailings.ts
732
- import { z as z6 } from "zod";
855
+ import { z as z7 } from "zod";
733
856
 
734
857
  // src/ab-test.ts
735
- import { z as z5 } from "zod";
736
- var AbVariant = z5.object({
737
- key: z5.string().regex(/^[a-z]$/, "a single lowercase letter"),
738
- subject: z5.string().min(1).max(998).optional(),
858
+ import { z as z6 } from "zod";
859
+ var AbVariant = z6.object({
860
+ key: z6.string().regex(/^[a-z]$/, "a single lowercase letter"),
861
+ subject: z6.string().min(1).max(998).optional(),
739
862
  /** Replaces the mailing's document for this variant. */
740
- document: z5.record(z5.unknown()).optional(),
863
+ document: z6.record(z6.unknown()).optional(),
741
864
  /**
742
865
  * Keeps the document this variant key already has in the mailing's current
743
866
  * test, so a test can be changed without sending every document again. The
744
867
  * service refuses it (`validation_failed`) when that variant has none.
745
868
  */
746
- keep_document: z5.literal(true).optional()
869
+ keep_document: z6.literal(true).optional()
747
870
  });
748
871
  var AB_WINNER_METRICS = ["opens", "clicks", "manual"];
749
- var AbTestConfig = z5.object({
750
- variants: z5.array(AbVariant).min(2).max(5),
872
+ var AbTestConfig = z6.object({
873
+ variants: z6.array(AbVariant).min(2).max(5),
751
874
  /** Share of recipients in the test group, split evenly across variants; the rest get the winner. */
752
- test_fraction: z5.number().gt(0).lte(1),
753
- winner_metric: z5.enum(AB_WINNER_METRICS),
754
- decide_after_minutes: z5.number().int().min(15).max(10080).optional()
875
+ test_fraction: z6.number().gt(0).lte(1),
876
+ winner_metric: z6.enum(AB_WINNER_METRICS),
877
+ decide_after_minutes: z6.number().int().min(15).max(10080).optional()
755
878
  }).refine((c) => new Set(c.variants.map((v) => v.key)).size === c.variants.length, "variant keys must be unique").refine((c) => c.variants.every((v) => v.subject !== void 0 || v.document !== void 0 || v.keep_document === true), {
756
879
  message: "every variant changes the subject, the document or both",
757
880
  path: ["variants"]
@@ -763,19 +886,19 @@ var AbTestConfig = z5.object({
763
886
  path: ["decide_after_minutes"]
764
887
  });
765
888
  var AB_TEST_STATUSES = ["pending", "testing", "awaiting_pick", "decided"];
766
- var AbTestState = z5.object({
767
- variants: z5.array(z5.object({ key: z5.string(), subject: z5.string().nullable(), has_document: z5.boolean() })),
768
- test_fraction: z5.number(),
769
- winner_metric: z5.enum(AB_WINNER_METRICS),
770
- decide_after_minutes: z5.number().int().nullable(),
771
- status: z5.enum(AB_TEST_STATUSES),
889
+ var AbTestState = z6.object({
890
+ variants: z6.array(z6.object({ key: z6.string(), subject: z6.string().nullable(), has_document: z6.boolean() })),
891
+ test_fraction: z6.number(),
892
+ winner_metric: z6.enum(AB_WINNER_METRICS),
893
+ decide_after_minutes: z6.number().int().nullable(),
894
+ status: z6.enum(AB_TEST_STATUSES),
772
895
  /** When the metric decides; null for manual or before the start. */
773
896
  decide_at: Timestamp.nullable(),
774
- winner: z5.string().nullable(),
775
- decided_by: z5.enum(["metric", "manual"]).nullable(),
897
+ winner: z6.string().nullable(),
898
+ decided_by: z6.enum(["metric", "manual"]).nullable(),
776
899
  decided_at: Timestamp.nullable()
777
900
  });
778
- var AbWinnerRequest = z5.object({ variant: z5.string().regex(/^[a-z]$/) });
901
+ var AbWinnerRequest = z6.object({ variant: z6.string().regex(/^[a-z]$/) });
779
902
  function testGroupSize(total, fraction, variants) {
780
903
  return Math.min(total, Math.max(variants, Math.ceil(total * fraction)));
781
904
  }
@@ -790,9 +913,9 @@ var MAILING_STATUSES = [
790
913
  "partially_failed",
791
914
  "cancelled"
792
915
  ];
793
- var MailingStatus = z6.enum(MAILING_STATUSES);
916
+ var MailingStatus = z7.enum(MAILING_STATUSES);
794
917
  var MAILING_ACTIONS = ["send", "schedule", "unschedule", "pause", "resume", "cancel", "retry-failed"];
795
- var MailingAction = z6.enum(MAILING_ACTIONS);
918
+ var MailingAction = z7.enum(MAILING_ACTIONS);
796
919
  var MAILING_TRANSITIONS = {
797
920
  draft: ["send", "schedule", "cancel"],
798
921
  scheduled: ["send", "schedule", "unschedule", "cancel"],
@@ -807,23 +930,23 @@ function canTransition(status, action) {
807
930
  }
808
931
  var EDITABLE_MAILING_STATUSES = ["draft", "scheduled"];
809
932
  var TERMINAL_MAILING_STATUSES = ["sent", "cancelled"];
810
- var MailingMetadata = z6.record(z6.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");
811
- var MailingCounts = z6.object({
812
- total: z6.number().int().min(0),
813
- queued: z6.number().int().min(0),
814
- sending: z6.number().int().min(0),
815
- sent: z6.number().int().min(0),
816
- failed: z6.number().int().min(0),
817
- skipped: z6.number().int().min(0)
933
+ var MailingMetadata = z7.record(z7.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");
934
+ var MailingCounts = z7.object({
935
+ total: z7.number().int().min(0),
936
+ queued: z7.number().int().min(0),
937
+ sending: z7.number().int().min(0),
938
+ sent: z7.number().int().min(0),
939
+ failed: z7.number().int().min(0),
940
+ skipped: z7.number().int().min(0)
818
941
  });
819
942
  var MAILING_KINDS = ["broadcast", "automation", "notification"];
820
- var MailingKind = z6.enum(MAILING_KINDS);
821
- var Mailing = z6.object({
943
+ var MailingKind = z7.enum(MAILING_KINDS);
944
+ var Mailing = z7.object({
822
945
  id: Id,
823
946
  kind: MailingKind,
824
- name: z6.string().max(200).nullable(),
825
- subject: z6.string().min(1).max(998),
826
- preheader: z6.string().max(500).nullable(),
947
+ name: z7.string().max(200).nullable(),
948
+ subject: z7.string().min(1).max(998),
949
+ preheader: z7.string().max(500).nullable(),
827
950
  /**
828
951
  * The template the document was taken from, if any. The snapshot is what is
829
952
  * sent in the main language; the template's other language versions are
@@ -868,15 +991,15 @@ var Mailing = z6.object({
868
991
  * recipients refused as dead addresses in one run (see the provider's
869
992
  * `rejections.anomaly`). Resuming clears it and starts a new run.
870
993
  */
871
- pause_reason: z6.string().nullable().default(null),
994
+ pause_reason: z7.string().nullable().default(null),
872
995
  created_at: Timestamp,
873
996
  updated_at: Timestamp
874
997
  });
875
998
  var MailingSummary = Mailing.omit({ document: true });
876
999
  var MailingContent = {
877
- name: z6.string().max(200).optional(),
878
- subject: z6.string().min(1).max(998),
879
- preheader: z6.string().max(500).optional(),
1000
+ name: z7.string().max(200).optional(),
1001
+ subject: z7.string().min(1).max(998),
1002
+ preheader: z7.string().max(500).optional(),
880
1003
  /** See `Mailing.send_locale`. */
881
1004
  send_locale: LocaleTag.nullable().optional(),
882
1005
  /**
@@ -889,7 +1012,7 @@ var MailingContent = {
889
1012
  provider_id: Id,
890
1013
  metadata: MailingMetadata.optional()
891
1014
  };
892
- var MailingCreate = z6.object({
1015
+ var MailingCreate = z7.object({
893
1016
  ...MailingContent,
894
1017
  subject: MailingContent.subject.optional(),
895
1018
  document: TemplateDocument.optional(),
@@ -901,10 +1024,10 @@ var MailingCreate = z6.object({
901
1024
  message: "a mailing made from a document needs a subject",
902
1025
  path: ["subject"]
903
1026
  });
904
- var MailingUpdate = z6.object({
905
- name: z6.string().max(200).nullable().optional(),
1027
+ var MailingUpdate = z7.object({
1028
+ name: z7.string().max(200).nullable().optional(),
906
1029
  subject: MailingContent.subject.optional(),
907
- preheader: z6.string().max(500).nullable().optional(),
1030
+ preheader: z7.string().max(500).nullable().optional(),
908
1031
  /** Null turns a draft into a letter, which it can only be with at most one recipient. */
909
1032
  topic: Slug.nullable().optional(),
910
1033
  send_locale: LocaleTag.nullable().optional(),
@@ -918,30 +1041,30 @@ var MailingListQuery = PageQuery.extend({
918
1041
  kind: MailingKind.optional(),
919
1042
  automation_id: Id.optional()
920
1043
  });
921
- var MailingSendRequest = z6.object({}).strict();
922
- var MailingRetryFailedRequest = z6.object({
1044
+ var MailingSendRequest = z7.object({}).strict();
1045
+ var MailingRetryFailedRequest = z7.object({
923
1046
  /**
924
1047
  * Also requeue recipients whose outcome is unknown after a crash. They may
925
1048
  * already have received the message, so this is a human's decision, never a
926
1049
  * default.
927
1050
  */
928
- include_outcome_unknown: z6.boolean().optional()
1051
+ include_outcome_unknown: z7.boolean().optional()
929
1052
  }).strict();
930
- var MailingActionRequest = z6.object({}).strict();
931
- var MailingTestRequest = z6.object({
1053
+ var MailingActionRequest = z7.object({}).strict();
1054
+ var MailingTestRequest = z7.object({
932
1055
  to: Email,
933
1056
  merge: Properties.optional(),
934
1057
  locale: LocaleTag.optional()
935
1058
  });
936
- var MailingTestResult = z6.object({
1059
+ var MailingTestResult = z7.object({
937
1060
  message_id: Id,
938
- provider_message_id: z6.string().nullable()
1061
+ provider_message_id: z7.string().nullable()
939
1062
  });
940
1063
  var RECIPIENT_STATUSES = ["queued", "sending", "sent", "failed", "skipped"];
941
- var RecipientStatus = z6.enum(RECIPIENT_STATUSES);
1064
+ var RecipientStatus = z7.enum(RECIPIENT_STATUSES);
942
1065
  var SKIP_REASONS = ["suppressed", "not_subscribed", "contact_erased", "cancelled", "outcome_unknown"];
943
- var SkipReason = z6.enum(SKIP_REASONS);
944
- var Recipient = z6.object({
1066
+ var SkipReason = z7.enum(SKIP_REASONS);
1067
+ var Recipient = z7.object({
945
1068
  id: Id,
946
1069
  mailing_id: Id,
947
1070
  contact_id: Id.nullable(),
@@ -949,55 +1072,55 @@ var Recipient = z6.object({
949
1072
  merge: Properties,
950
1073
  status: RecipientStatus,
951
1074
  skip_reason: SkipReason.nullable(),
952
- attempts: z6.number().int().min(0),
1075
+ attempts: z7.number().int().min(0),
953
1076
  message_id: Id.nullable(),
954
- last_error: z6.string().nullable(),
1077
+ last_error: z7.string().nullable(),
955
1078
  created_at: Timestamp,
956
1079
  updated_at: Timestamp
957
1080
  });
958
1081
  var MAX_RECIPIENTS_PER_BATCH = 1e3;
959
1082
  var MAX_LETTER_RECIPIENTS = 1;
960
1083
  var LETTER_RECIPIENT_REFUSAL = "letter_has_one_recipient";
961
- var RecipientInput = z6.object({
1084
+ var RecipientInput = z7.object({
962
1085
  contact_id: Id.optional(),
963
- external_id: z6.string().min(1).max(255).optional(),
1086
+ external_id: z7.string().min(1).max(255).optional(),
964
1087
  email: Email.optional(),
965
1088
  merge: Properties.optional()
966
1089
  }).refine((v) => v.contact_id !== void 0 || v.external_id !== void 0 || v.email !== void 0, {
967
1090
  message: "contact_id, external_id or email is required",
968
1091
  path: ["email"]
969
1092
  });
970
- var RecipientBatch = z6.object({
971
- recipients: z6.array(RecipientInput).min(1).max(MAX_RECIPIENTS_PER_BATCH)
1093
+ var RecipientBatch = z7.object({
1094
+ recipients: z7.array(RecipientInput).min(1).max(MAX_RECIPIENTS_PER_BATCH)
972
1095
  });
973
1096
  var RECIPIENT_REJECTIONS = ["unknown_contact", "duplicate_in_batch"];
974
- var RecipientBatchResult = z6.object({
1097
+ var RecipientBatchResult = z7.object({
975
1098
  /** Newly queued. */
976
- added: z6.number().int().min(0),
1099
+ added: z7.number().int().min(0),
977
1100
  /** Already on the mailing from an earlier batch: left unchanged. */
978
- already_present: z6.number().int().min(0),
1101
+ already_present: z7.number().int().min(0),
979
1102
  /** Items not added, by their index in the request. */
980
- rejected: z6.array(z6.object({ index: z6.number().int().min(0), reason: z6.enum(RECIPIENT_REJECTIONS) }))
1103
+ rejected: z7.array(z7.object({ index: z7.number().int().min(0), reason: z7.enum(RECIPIENT_REJECTIONS) }))
981
1104
  });
982
1105
  var RecipientListQuery = PageQuery.extend({
983
1106
  status: RecipientStatus.optional(),
984
1107
  skip_reason: SkipReason.optional()
985
1108
  });
986
1109
  var MESSAGE_OUTCOMES = ["sent", "failed"];
987
- var MessageOutcome = z6.enum(MESSAGE_OUTCOMES);
988
- var MessageSummary = z6.object({
1110
+ var MessageOutcome = z7.enum(MESSAGE_OUTCOMES);
1111
+ var MessageSummary = z7.object({
989
1112
  id: Id,
990
1113
  mailing_id: Id.nullable(),
991
1114
  recipient_id: Id.nullable(),
992
1115
  contact_id: Id.nullable(),
993
1116
  to: Email,
994
- subject: z6.string(),
1117
+ subject: z7.string(),
995
1118
  provider_id: Id,
996
- provider_message_id: z6.string().nullable(),
1119
+ provider_message_id: z7.string().nullable(),
997
1120
  outcome: MessageOutcome,
998
- error: z6.string().nullable(),
999
- is_test: z6.boolean(),
1000
- recipient_count: z6.number().int().min(1),
1121
+ error: z7.string().nullable(),
1122
+ is_test: z7.boolean(),
1123
+ recipient_count: z7.number().int().min(1),
1001
1124
  /** The language version the message was sent in; null for messages archived before languages existed. */
1002
1125
  locale: LocaleTag.nullable(),
1003
1126
  /**
@@ -1009,22 +1132,22 @@ var MessageSummary = z6.object({
1009
1132
  insertions: InsertionChoices.nullable(),
1010
1133
  created_at: Timestamp
1011
1134
  });
1012
- var Message = MessageSummary.extend({ html: z6.string() });
1013
- var MailingLanguageStatus = z6.enum(["main", "ready", "draft", "not_a_workspace_language"]);
1014
- var MailingLanguage = z6.object({
1135
+ var Message = MessageSummary.extend({ html: z7.string() });
1136
+ var MailingLanguageStatus = z7.enum(["main", "ready", "draft", "not_a_workspace_language"]);
1137
+ var MailingLanguage = z7.object({
1015
1138
  locale: LocaleTag,
1016
1139
  status: MailingLanguageStatus,
1017
1140
  /** Queued recipients who will get this version. */
1018
- planned: z6.number().int().min(0),
1141
+ planned: z7.number().int().min(0),
1019
1142
  /** Messages already sent in this language (tests excluded). */
1020
- sent: z6.number().int().min(0)
1143
+ sent: z7.number().int().min(0)
1021
1144
  });
1022
- var MailingLanguageReport = z6.object({
1145
+ var MailingLanguageReport = z7.object({
1023
1146
  main_locale: LocaleTag,
1024
1147
  send_locale: LocaleTag.nullable(),
1025
- languages: z6.array(MailingLanguage),
1026
- fallback: z6.array(z6.object({ wanted: z6.string(), planned: z6.number().int().min(1) })),
1027
- no_language: z6.number().int().min(0),
1148
+ languages: z7.array(MailingLanguage),
1149
+ fallback: z7.array(z7.object({ wanted: z7.string(), planned: z7.number().int().min(1) })),
1150
+ no_language: z7.number().int().min(0),
1028
1151
  /**
1029
1152
  * Values that no choice of an insertion takes, so the "otherwise" text goes
1030
1153
  * out (docs/plans/2026-09-25-translated-insertions.md, decision 3): per
@@ -1033,12 +1156,12 @@ var MailingLanguageReport = z6.object({
1033
1156
  * template's keys never produces one; a non-empty list means the client and
1034
1157
  * the template have drifted apart.
1035
1158
  */
1036
- insertion_misses: z6.array(
1037
- z6.object({
1038
- insertion: z6.string(),
1039
- value: z6.string(),
1040
- planned: z6.number().int().min(0),
1041
- sent: z6.number().int().min(0)
1159
+ insertion_misses: z7.array(
1160
+ z7.object({
1161
+ insertion: z7.string(),
1162
+ value: z7.string(),
1163
+ planned: z7.number().int().min(0),
1164
+ sent: z7.number().int().min(0)
1042
1165
  })
1043
1166
  )
1044
1167
  });
@@ -1048,26 +1171,26 @@ var MessageListQuery = PageQuery.extend({
1048
1171
  });
1049
1172
 
1050
1173
  // src/platform.ts
1051
- var Tag = z7.object({
1174
+ var Tag = z8.object({
1052
1175
  id: Id,
1053
1176
  slug: Slug,
1054
- name: z7.string().min(1).max(120),
1055
- contact_count: z7.number().int().min(0),
1177
+ name: z8.string().min(1).max(120),
1178
+ contact_count: z8.number().int().min(0),
1056
1179
  created_at: Timestamp
1057
1180
  });
1058
- var TagCreate = z7.object({ slug: Slug, name: z7.string().min(1).max(120) });
1059
- var TagAssignment = z7.object({
1060
- contact_ids: z7.array(Id).min(1).max(1e3)
1181
+ var TagCreate = z8.object({ slug: Slug, name: z8.string().min(1).max(120) });
1182
+ var TagAssignment = z8.object({
1183
+ contact_ids: z8.array(Id).min(1).max(1e3)
1061
1184
  });
1062
1185
  var CONTACT_PROPERTY_TYPES = ["string", "number", "boolean", "date"];
1063
- var ContactPropertyType = z7.enum(CONTACT_PROPERTY_TYPES);
1064
- var ContactPropertyKey = z7.string().regex(/^[A-Za-z0-9_.-]{1,64}$/, "letters, digits, dot, underscore and hyphen, 1 to 64");
1065
- var ContactPropertyDefinition = z7.object({
1186
+ var ContactPropertyType = z8.enum(CONTACT_PROPERTY_TYPES);
1187
+ var ContactPropertyKey = z8.string().regex(/^[A-Za-z0-9_.-]{1,64}$/, "letters, digits, dot, underscore and hyphen, 1 to 64");
1188
+ var ContactPropertyDefinition = z8.object({
1066
1189
  key: ContactPropertyKey,
1067
- label: z7.string().min(1).max(120),
1190
+ label: z8.string().min(1).max(120),
1068
1191
  type: ContactPropertyType
1069
1192
  });
1070
- var ContactPropertyParams = z7.object({ key: ContactPropertyKey });
1193
+ var ContactPropertyParams = z8.object({ key: ContactPropertyKey });
1071
1194
  var FILTER_OPERATORS = [
1072
1195
  "eq",
1073
1196
  "neq",
@@ -1083,8 +1206,8 @@ var FILTER_OPERATORS = [
1083
1206
  "in",
1084
1207
  "not_in"
1085
1208
  ];
1086
- var FilterOperator = z7.enum(FILTER_OPERATORS);
1087
- var FilterField = z7.string().regex(
1209
+ var FilterOperator = z8.enum(FILTER_OPERATORS);
1210
+ var FilterField = z8.string().regex(
1088
1211
  /^(email|first_name|last_name|locale|created_at|tag|topic|engagement:(opened|clicked)|property:[A-Za-z0-9_.-]{1,64})$/,
1089
1212
  "unknown filter field"
1090
1213
  );
@@ -1100,18 +1223,18 @@ var FILTER_FIELD_OPERATORS = {
1100
1223
  property: FILTER_OPERATORS
1101
1224
  };
1102
1225
  var MAX_FILTER_DEPTH = 5;
1103
- var FilterCondition = z7.object({ field: FilterField, op: FilterOperator, value: JsonValue.optional() }).strict().refine((c) => (c.op === "exists" || c.op === "not_exists") === (c.value === void 0), {
1226
+ var FilterCondition = z8.object({ field: FilterField, op: FilterOperator, value: JsonValue.optional() }).strict().refine((c) => (c.op === "exists" || c.op === "not_exists") === (c.value === void 0), {
1104
1227
  message: "exists and not_exists take no value; every other operator needs one",
1105
1228
  path: ["value"]
1106
1229
  }).refine((c) => c.op !== "in" && c.op !== "not_in" || Array.isArray(c.value), {
1107
1230
  message: "in and not_in take an array",
1108
1231
  path: ["value"]
1109
1232
  });
1110
- var SegmentFilter = z7.lazy(
1111
- () => z7.union([
1112
- z7.object({ and: z7.array(SegmentFilter).min(1).max(50) }).strict(),
1113
- z7.object({ or: z7.array(SegmentFilter).min(1).max(50) }).strict(),
1114
- z7.object({ not: SegmentFilter }).strict(),
1233
+ var SegmentFilter = z8.lazy(
1234
+ () => z8.union([
1235
+ z8.object({ and: z8.array(SegmentFilter).min(1).max(50) }).strict(),
1236
+ z8.object({ or: z8.array(SegmentFilter).min(1).max(50) }).strict(),
1237
+ z8.object({ not: SegmentFilter }).strict(),
1115
1238
  FilterCondition
1116
1239
  ])
1117
1240
  );
@@ -1199,42 +1322,42 @@ function untypedValueProblem(c, every) {
1199
1322
  if (orderOp) return every(isFilterNumber, "numbers (define the property to compare dates)");
1200
1323
  return every((v) => isScalar(v) || v === null, "strings, numbers, booleans or null");
1201
1324
  }
1202
- var Segment = z7.object({
1325
+ var Segment = z8.object({
1203
1326
  id: Id,
1204
- name: z7.string().min(1).max(120),
1327
+ name: z8.string().min(1).max(120),
1205
1328
  filter: SegmentFilter,
1206
1329
  /** Computed on read. */
1207
- contact_count: z7.number().int().min(0),
1330
+ contact_count: z8.number().int().min(0),
1208
1331
  created_at: Timestamp,
1209
1332
  updated_at: Timestamp
1210
1333
  });
1211
- var SegmentCreate = z7.object({ name: z7.string().min(1).max(120), filter: BoundedSegmentFilter });
1212
- var SegmentPreviewRequest = z7.object({ filter: BoundedSegmentFilter });
1213
- var SegmentPreview = z7.object({
1214
- contact_count: z7.number().int().min(0),
1334
+ var SegmentCreate = z8.object({ name: z8.string().min(1).max(120), filter: BoundedSegmentFilter });
1335
+ var SegmentPreviewRequest = z8.object({ filter: BoundedSegmentFilter });
1336
+ var SegmentPreview = z8.object({
1337
+ contact_count: z8.number().int().min(0),
1215
1338
  /** Up to five matching contacts, for a human to sanity-check the filter. */
1216
- sample: z7.array(z7.object({ id: Id, email: Email })).max(5)
1339
+ sample: z8.array(z8.object({ id: Id, email: Email })).max(5)
1217
1340
  });
1218
- var MailingAudienceFromSegment = z7.object({ segment_id: Id });
1341
+ var MailingAudienceFromSegment = z8.object({ segment_id: Id });
1219
1342
  var SIGNUP_FORM_FIELDS = ["first_name", "last_name"];
1220
1343
  var HOSTED_PAGE_LOCALES = ["en", "de", "it", "fr", "es"];
1221
- var SignupFormTranslation = z7.object({
1222
- title: z7.string().min(1).max(120),
1223
- consent_text: z7.string().min(1).max(2e3)
1344
+ var SignupFormTranslation = z8.object({
1345
+ title: z8.string().min(1).max(120),
1346
+ consent_text: z8.string().min(1).max(2e3)
1224
1347
  });
1225
- var SignupForm = z7.object({
1348
+ var SignupForm = z8.object({
1226
1349
  id: Id,
1227
- name: z7.string().min(1).max(120),
1350
+ name: z8.string().min(1).max(120),
1228
1351
  /** The heading of the hosted page. */
1229
- title: z7.string().min(1).max(120),
1352
+ title: z8.string().min(1).max(120),
1230
1353
  /** What the person agrees to, shown above the button and recorded with the confirmation. */
1231
- consent_text: z7.string().min(1).max(2e3),
1232
- translations: z7.record(SignupFormTranslation),
1233
- topics: z7.array(Slug).min(1),
1234
- tags: z7.array(Slug),
1354
+ consent_text: z8.string().min(1).max(2e3),
1355
+ translations: z8.record(SignupFormTranslation),
1356
+ topics: z8.array(Slug).min(1),
1357
+ tags: z8.array(Slug),
1235
1358
  /** Fields shown besides email. */
1236
- fields: z7.array(z7.enum(SIGNUP_FORM_FIELDS)),
1237
- double_opt_in: z7.literal(true),
1359
+ fields: z8.array(z8.enum(SIGNUP_FORM_FIELDS)),
1360
+ double_opt_in: z8.literal(true),
1238
1361
  /** The provider the confirmation mail is sent through. */
1239
1362
  provider_id: Id,
1240
1363
  /**
@@ -1243,11 +1366,11 @@ var SignupForm = z7.object({
1243
1366
  */
1244
1367
  confirmation_template_id: Id.nullable(),
1245
1368
  /** Where the person lands after confirming. Null shows the hosted confirmation page. */
1246
- redirect_url: z7.string().url().nullable(),
1369
+ redirect_url: z8.string().url().nullable(),
1247
1370
  /** Origins allowed to embed the form and call the submission route from a browser. */
1248
- allowed_origins: z7.array(z7.string().url()).max(20),
1371
+ allowed_origins: z8.array(z8.string().url()).max(20),
1249
1372
  /** Bumped on every change; recorded with each confirmation. */
1250
- version: z7.number().int().min(1),
1373
+ version: z8.number().int().min(1),
1251
1374
  created_at: Timestamp,
1252
1375
  updated_at: Timestamp
1253
1376
  });
@@ -1262,56 +1385,56 @@ var SignupFormCreate = SignupForm.omit({
1262
1385
  tags: SignupForm.shape.tags.optional(),
1263
1386
  fields: SignupForm.shape.fields.optional(),
1264
1387
  confirmation_template_id: Id.nullable().optional(),
1265
- redirect_url: z7.string().url().nullable().optional(),
1388
+ redirect_url: z8.string().url().nullable().optional(),
1266
1389
  allowed_origins: SignupForm.shape.allowed_origins.optional()
1267
1390
  });
1268
- var SignupFormEmbed = z7.object({
1269
- hosted_url: z7.string().url(),
1391
+ var SignupFormEmbed = z8.object({
1392
+ hosted_url: z8.string().url(),
1270
1393
  /** A plain HTML form posting to the hosted page; works without JavaScript. */
1271
- html: z7.string(),
1394
+ html: z8.string(),
1272
1395
  /** A small optional script that adds the time check and submits in place. */
1273
- script_url: z7.string().url(),
1396
+ script_url: z8.string().url(),
1274
1397
  /** Where a browser fetches a fresh `form_token` from (GET, public, CORS for `allowed_origins`). */
1275
- token_url: z7.string().url()
1398
+ token_url: z8.string().url()
1276
1399
  });
1277
- var SignupSubmission = z7.object({
1400
+ var SignupSubmission = z8.object({
1278
1401
  email: Email,
1279
- first_name: z7.string().max(200).optional(),
1280
- last_name: z7.string().max(200).optional(),
1281
- locale: z7.string().min(2).max(35).optional(),
1402
+ first_name: z8.string().max(200).optional(),
1403
+ last_name: z8.string().max(200).optional(),
1404
+ locale: z8.string().min(2).max(35).optional(),
1282
1405
  /** Honeypot: must be empty. */
1283
- website: z7.string().max(0).optional(),
1406
+ website: z8.string().max(0).optional(),
1284
1407
  /**
1285
1408
  * The signed render time from the form's token URL: a submission sooner than a
1286
1409
  * human could fill the form, or long after, is refused.
1287
1410
  */
1288
- form_token: z7.string().min(1).max(512)
1411
+ form_token: z8.string().min(1).max(512)
1289
1412
  });
1290
1413
  var IMPORT_STATUSES = ["uploaded", "validating", "validated", "committing", "completed", "failed", "cancelled"];
1291
- var ImportStatus = z7.enum(IMPORT_STATUSES);
1414
+ var ImportStatus = z8.enum(IMPORT_STATUSES);
1292
1415
  var IMPORT_TERMINAL_STATUSES = ["completed", "failed", "cancelled"];
1293
- var ImportColumnMapping = z7.record(
1294
- z7.string().regex(/^(email|external_id|first_name|last_name|locale|property:[A-Za-z0-9_.-]{1,64}|ignore)$/)
1416
+ var ImportColumnMapping = z8.record(
1417
+ z8.string().regex(/^(email|external_id|first_name|last_name|locale|property:[A-Za-z0-9_.-]{1,64}|ignore)$/)
1295
1418
  );
1296
1419
  var IMPORT_FILE_FIELD = "file";
1297
1420
  var MAX_IMPORT_BYTES = 50 * 1024 * 1024;
1298
1421
  var MAX_IMPORT_ROWS = 2e5;
1299
- var ImportMappingRequest = z7.object({
1422
+ var ImportMappingRequest = z8.object({
1300
1423
  /** CSV header -> contact field. Exactly one column maps to `email`. */
1301
1424
  mapping: ImportColumnMapping.refine(
1302
1425
  (m) => Object.values(m).filter((v) => v === "email").length === 1,
1303
1426
  "exactly one column maps to email"
1304
1427
  ),
1305
- topics: z7.array(Slug).max(100),
1306
- tags: z7.array(Slug).max(100),
1428
+ topics: z8.array(Slug).max(100),
1429
+ tags: z8.array(Slug).max(100),
1307
1430
  /** Existing contacts get the mapped fields overwritten; false only adds topics, tags and missing fields. */
1308
- update_existing: z7.boolean().optional(),
1431
+ update_existing: z8.boolean().optional(),
1309
1432
  /** The importer states the people consented; the service records who said so and when. */
1310
- consent_confirmed: z7.literal(true)
1433
+ consent_confirmed: z8.literal(true)
1311
1434
  });
1312
- var ImportCommitRequest = z7.object({ mapping_version: z7.number().int().min(1) });
1435
+ var ImportCommitRequest = z8.object({ mapping_version: z8.number().int().min(1) });
1313
1436
  var IMPORT_ROW_OUTCOMES = ["created", "updated", "unchanged", "suppressed", "skipped"];
1314
- var ImportRowOutcome = z7.enum(IMPORT_ROW_OUTCOMES);
1437
+ var ImportRowOutcome = z8.enum(IMPORT_ROW_OUTCOMES);
1315
1438
  var IMPORT_SKIP_REASONS = [
1316
1439
  "missing_email",
1317
1440
  "invalid_email",
@@ -1320,90 +1443,90 @@ var IMPORT_SKIP_REASONS = [
1320
1443
  "external_id_conflict",
1321
1444
  "wrong_column_count"
1322
1445
  ];
1323
- var ImportSkipReason = z7.enum(IMPORT_SKIP_REASONS);
1324
- var ImportReport = z7.object({
1325
- created: z7.number().int().min(0),
1326
- updated: z7.number().int().min(0),
1327
- unchanged: z7.number().int().min(0),
1328
- suppressed: z7.number().int().min(0),
1329
- skipped: z7.number().int().min(0),
1330
- skipped_by_reason: z7.record(ImportSkipReason, z7.number().int().min(0)),
1446
+ var ImportSkipReason = z8.enum(IMPORT_SKIP_REASONS);
1447
+ var ImportReport = z8.object({
1448
+ created: z8.number().int().min(0),
1449
+ updated: z8.number().int().min(0),
1450
+ unchanged: z8.number().int().min(0),
1451
+ suppressed: z8.number().int().min(0),
1452
+ skipped: z8.number().int().min(0),
1453
+ skipped_by_reason: z8.record(ImportSkipReason, z8.number().int().min(0)),
1331
1454
  /** Rows whose contact was subscribed without some topic, because the address is blocked for it. */
1332
- topics_withheld: z7.number().int().min(0)
1455
+ topics_withheld: z8.number().int().min(0)
1333
1456
  });
1334
- var ImportJob = z7.object({
1457
+ var ImportJob = z8.object({
1335
1458
  id: Id,
1336
1459
  status: ImportStatus,
1337
- file_name: z7.string().max(255).nullable(),
1338
- file_bytes: z7.number().int().min(0),
1339
- total_rows: z7.number().int().min(0),
1460
+ file_name: z8.string().max(255).nullable(),
1461
+ file_bytes: z8.number().int().min(0),
1462
+ total_rows: z8.number().int().min(0),
1340
1463
  /** The header row, as in the file. */
1341
- columns: z7.array(z7.string()),
1464
+ columns: z8.array(z8.string()),
1342
1465
  /** The first rows, for the mapping screen. */
1343
- sample: z7.array(z7.array(z7.string())).max(5),
1466
+ sample: z8.array(z8.array(z8.string())).max(5),
1344
1467
  /** A mapping guessed from the headers, for the mapping screen to start from. */
1345
1468
  suggested_mapping: ImportColumnMapping,
1346
1469
  mapping: ImportColumnMapping.nullable(),
1347
- mapping_version: z7.number().int().min(0),
1348
- topics: z7.array(Slug),
1349
- tags: z7.array(Slug),
1350
- update_existing: z7.boolean(),
1470
+ mapping_version: z8.number().int().min(0),
1471
+ topics: z8.array(Slug),
1472
+ tags: z8.array(Slug),
1473
+ update_existing: z8.boolean(),
1351
1474
  /** The dry run of the current mapping; null before one finished. */
1352
1475
  dry_run: ImportReport.nullable(),
1353
1476
  /** What the commit has written so far; null before it started. */
1354
1477
  result: ImportReport.nullable(),
1355
1478
  /** Rows the current phase (dry run or commit) has processed. */
1356
- processed_rows: z7.number().int().min(0),
1479
+ processed_rows: z8.number().int().min(0),
1357
1480
  /** Why a `failed` import failed. */
1358
- error: z7.string().nullable(),
1481
+ error: z8.string().nullable(),
1359
1482
  created_at: Timestamp,
1360
1483
  updated_at: Timestamp,
1361
1484
  finished_at: Timestamp.nullable()
1362
1485
  });
1363
- var ImportRow = z7.object({
1486
+ var ImportRow = z8.object({
1364
1487
  /** The line in the file, 1 being the first line after the header. */
1365
- row: z7.number().int().min(1),
1366
- email: z7.string().nullable(),
1488
+ row: z8.number().int().min(1),
1489
+ email: z8.string().nullable(),
1367
1490
  outcome: ImportRowOutcome,
1368
1491
  reason: ImportSkipReason.nullable(),
1369
1492
  /** A human explanation for a skipped row (which value, which column). */
1370
- message: z7.string().nullable(),
1493
+ message: z8.string().nullable(),
1371
1494
  contact_id: Id.nullable()
1372
1495
  });
1373
1496
  var ImportRowListQuery = PageQuery.extend({ outcome: ImportRowOutcome.optional() });
1374
- var MailingScheduleRequest = z7.object({ send_at: Timestamp });
1375
- var TrackingSettings = z7.object({ opens: z7.boolean(), clicks: z7.boolean() });
1376
- var VariantAnalytics = z7.object({
1377
- key: z7.string(),
1378
- sent: z7.number().int().min(0),
1379
- unique_opens: z7.number().int().min(0).nullable(),
1380
- unique_clicks: z7.number().int().min(0).nullable()
1381
- });
1382
- var MailingAnalytics = z7.object({
1497
+ var MailingScheduleRequest = z8.object({ send_at: Timestamp });
1498
+ var TrackingSettings = z8.object({ opens: z8.boolean(), clicks: z8.boolean() });
1499
+ var VariantAnalytics = z8.object({
1500
+ key: z8.string(),
1501
+ sent: z8.number().int().min(0),
1502
+ unique_opens: z8.number().int().min(0).nullable(),
1503
+ unique_clicks: z8.number().int().min(0).nullable()
1504
+ });
1505
+ var MailingAnalytics = z8.object({
1383
1506
  mailing_id: Id,
1384
1507
  counts: MailingCounts,
1385
1508
  /** What was tracked for this mailing, fixed when it started; null before it started. */
1386
1509
  tracking: TrackingSettings.nullable(),
1387
1510
  /** Unique recipients with a human open. Null when opens were not tracked. */
1388
- unique_opens: z7.number().int().min(0).nullable(),
1511
+ unique_opens: z8.number().int().min(0).nullable(),
1389
1512
  /**
1390
1513
  * Recipients whose only opens came from Apple Mail Privacy Protection, which
1391
1514
  * loads every image on delivery: counted apart, never as human opens.
1392
1515
  */
1393
- apple_mpp_opens: z7.number().int().min(0).nullable(),
1516
+ apple_mpp_opens: z8.number().int().min(0).nullable(),
1394
1517
  /** Opens and clicks from security scanners and prefetchers, filtered out of the unique counts. */
1395
- machine_events: z7.number().int().min(0).nullable(),
1396
- unique_clicks: z7.number().int().min(0).nullable(),
1397
- unsubscribes: z7.number().int().min(0),
1398
- bounces: z7.number().int().min(0),
1399
- complaints: z7.number().int().min(0),
1400
- links: z7.array(z7.object({ url: z7.string(), unique_clicks: z7.number().int().min(0) })).nullable(),
1401
- variants: z7.array(VariantAnalytics).nullable()
1518
+ machine_events: z8.number().int().min(0).nullable(),
1519
+ unique_clicks: z8.number().int().min(0).nullable(),
1520
+ unsubscribes: z8.number().int().min(0),
1521
+ bounces: z8.number().int().min(0),
1522
+ complaints: z8.number().int().min(0),
1523
+ links: z8.array(z8.object({ url: z8.string(), unique_clicks: z8.number().int().min(0) })).nullable(),
1524
+ variants: z8.array(VariantAnalytics).nullable()
1402
1525
  });
1403
1526
 
1404
1527
  // src/automations.ts
1405
1528
  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})$/;
1406
- var AutomationFilterField = z8.string().regex(AUTOMATION_FILTER_FIELD_PATTERN, "unknown filter field");
1529
+ var AutomationFilterField = z9.string().regex(AUTOMATION_FILTER_FIELD_PATTERN, "unknown filter field");
1407
1530
  var AUTOMATION_FILTER_FIELD_OPERATORS = {
1408
1531
  ...FILTER_FIELD_OPERATORS,
1409
1532
  segment: ["eq", "neq", "in", "not_in"],
@@ -1413,18 +1536,18 @@ var AUTOMATION_FILTER_FIELD_OPERATORS = {
1413
1536
  step: ["eq", "neq"]
1414
1537
  };
1415
1538
  var automationFilterFamily = filterFieldFamily;
1416
- var AutomationFilterCondition = z8.object({ field: AutomationFilterField, op: FilterOperator, value: JsonValue.optional() }).strict().refine((c) => (c.op === "exists" || c.op === "not_exists") === (c.value === void 0), {
1539
+ var AutomationFilterCondition = z9.object({ field: AutomationFilterField, op: FilterOperator, value: JsonValue.optional() }).strict().refine((c) => (c.op === "exists" || c.op === "not_exists") === (c.value === void 0), {
1417
1540
  message: "exists and not_exists take no value; every other operator needs one",
1418
1541
  path: ["value"]
1419
1542
  }).refine((c) => c.op !== "in" && c.op !== "not_in" || Array.isArray(c.value), {
1420
1543
  message: "in and not_in take an array",
1421
1544
  path: ["value"]
1422
1545
  });
1423
- var AutomationFilter = z8.lazy(
1424
- () => z8.union([
1425
- z8.object({ and: z8.array(AutomationFilter).min(1).max(50) }).strict(),
1426
- z8.object({ or: z8.array(AutomationFilter).min(1).max(50) }).strict(),
1427
- z8.object({ not: AutomationFilter }).strict(),
1546
+ var AutomationFilter = z9.lazy(
1547
+ () => z9.union([
1548
+ z9.object({ and: z9.array(AutomationFilter).min(1).max(50) }).strict(),
1549
+ z9.object({ or: z9.array(AutomationFilter).min(1).max(50) }).strict(),
1550
+ z9.object({ not: AutomationFilter }).strict(),
1428
1551
  AutomationFilterCondition
1429
1552
  ])
1430
1553
  );
@@ -1437,20 +1560,20 @@ function filterConditions(filter) {
1437
1560
  if ("not" in filter) return filterConditions(filter.not);
1438
1561
  return [filter];
1439
1562
  }
1440
- var StepId = z8.string().regex(/^[A-Za-z0-9_-]{1,64}$/, "letters, digits, underscore and hyphen, 1 to 64");
1441
- var TimeOfDay = z8.string().regex(/^([01]\d|2[0-3]):[0-5]\d$/, "HH:MM in 24 hours");
1442
- var Weekday = z8.number().int().min(0).max(6);
1443
- var TimezoneName = z8.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");
1563
+ var StepId = z9.string().regex(/^[A-Za-z0-9_-]{1,64}$/, "letters, digits, underscore and hyphen, 1 to 64");
1564
+ var TimeOfDay = z9.string().regex(/^([01]\d|2[0-3]):[0-5]\d$/, "HH:MM in 24 hours");
1565
+ var Weekday = z9.number().int().min(0).max(6);
1566
+ var TimezoneName = z9.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");
1444
1567
  var MAX_DELAY_SECONDS = 365 * 24 * 60 * 60;
1445
- var DateOnly = z8.string().regex(/^\d{4}-\d{2}-\d{2}$/, "a calendar date such as 2026-09-20").refine((v) => {
1568
+ var DateOnly = z9.string().regex(/^\d{4}-\d{2}-\d{2}$/, "a calendar date such as 2026-09-20").refine((v) => {
1446
1569
  const [y, m, d] = v.split("-").map(Number);
1447
1570
  const t = new Date(Date.UTC(y, m - 1, d));
1448
1571
  return t.getUTCFullYear() === y && t.getUTCMonth() + 1 === m && t.getUTCDate() === d;
1449
1572
  }, "a real calendar date");
1450
- var OffsetDays = z8.number().int().min(-365).max(365);
1573
+ var OffsetDays = z9.number().int().min(-365).max(365);
1451
1574
  var DATE_PASSED_ANSWERS = ["skip", "stop", "continue"];
1452
- var DatePassedAnswer = z8.enum(DATE_PASSED_ANSWERS);
1453
- var EventName = z8.string().regex(/^[A-Za-z0-9][A-Za-z0-9_.:-]{0,79}$/, "letters, digits, dot, colon, underscore and hyphen, 1 to 80");
1575
+ var DatePassedAnswer = z9.enum(DATE_PASSED_ANSWERS);
1576
+ var EventName = z9.string().regex(/^[A-Za-z0-9][A-Za-z0-9_.:-]{0,79}$/, "letters, digits, dot, colon, underscore and hyphen, 1 to 80");
1454
1577
  var AUTOMATION_TRIGGER_KINDS = [
1455
1578
  "topic_subscribed",
1456
1579
  "form_confirmed",
@@ -1463,17 +1586,17 @@ var AUTOMATION_TRIGGER_KINDS = [
1463
1586
  "segment_entered",
1464
1587
  "link_clicked"
1465
1588
  ];
1466
- var AutomationTriggerKind = z8.enum(AUTOMATION_TRIGGER_KINDS);
1589
+ var AutomationTriggerKind = z9.enum(AUTOMATION_TRIGGER_KINDS);
1467
1590
  var exclude = { exclude: BoundedAutomationFilter.nullish() };
1468
- var AutomationTrigger = z8.discriminatedUnion("kind", [
1469
- z8.object({ kind: z8.literal("topic_subscribed"), topic: Slug, ...exclude }).strict(),
1470
- z8.object({ kind: z8.literal("form_confirmed"), form_id: Id, ...exclude }).strict(),
1471
- z8.object({ kind: z8.literal("tag_added"), tag: Slug, ...exclude }).strict(),
1591
+ var AutomationTrigger = z9.discriminatedUnion("kind", [
1592
+ z9.object({ kind: z9.literal("topic_subscribed"), topic: Slug, ...exclude }).strict(),
1593
+ z9.object({ kind: z9.literal("form_confirmed"), form_id: Id, ...exclude }).strict(),
1594
+ z9.object({ kind: z9.literal("tag_added"), tag: Slug, ...exclude }).strict(),
1472
1595
  /** `to` given: only a change that lands on this value fires. Absent: any change of the key. */
1473
- z8.object({ kind: z8.literal("property_changed"), key: ContactPropertyKey, to: JsonValue.optional(), ...exclude }).strict(),
1596
+ z9.object({ kind: z9.literal("property_changed"), key: ContactPropertyKey, to: JsonValue.optional(), ...exclude }).strict(),
1474
1597
  /** `where` filters the event's own data, so only `event:<key>` leaves belong in it. */
1475
- z8.object({ kind: z8.literal("event"), name: EventName, where: BoundedAutomationFilter.nullish(), ...exclude }).strict(),
1476
- z8.object({ kind: z8.literal("manual"), ...exclude }).strict(),
1598
+ z9.object({ kind: z9.literal("event"), name: EventName, where: BoundedAutomationFilter.nullish(), ...exclude }).strict(),
1599
+ z9.object({ kind: z9.literal("manual"), ...exclude }).strict(),
1477
1600
  /**
1478
1601
  * Every year on a date the contact carries: a birthday, a joining date, a
1479
1602
  * renewal. `offset_days` moves it ("three days before"), `at` is the wall
@@ -1483,8 +1606,8 @@ var AutomationTrigger = z8.discriminatedUnion("kind", [
1483
1606
  * A 29 February date fires on 1 March in a year that has no 29 February, so
1484
1607
  * nobody is skipped every fourth year.
1485
1608
  */
1486
- z8.object({
1487
- kind: z8.literal("date_anniversary"),
1609
+ z9.object({
1610
+ kind: z9.literal("date_anniversary"),
1488
1611
  key: ContactPropertyKey,
1489
1612
  offset_days: OffsetDays,
1490
1613
  at: TimeOfDay,
@@ -1496,8 +1619,8 @@ var AutomationTrigger = z8.discriminatedUnion("kind", [
1496
1619
  * not ask about a segment or about an event's data: there is no event, and a
1497
1620
  * segment is its own trigger kind.
1498
1621
  */
1499
- z8.object({
1500
- kind: z8.literal("exact_date"),
1622
+ z9.object({
1623
+ kind: z9.literal("exact_date"),
1501
1624
  on: DateOnly,
1502
1625
  at: TimeOfDay,
1503
1626
  where: BoundedAutomationFilter.nullish(),
@@ -1516,7 +1639,7 @@ var AutomationTrigger = z8.discriminatedUnion("kind", [
1516
1639
  * already exists. Entering those people as well is the publish dialog's
1517
1640
  * backfill question, answered by a person rather than by the sweep.
1518
1641
  */
1519
- z8.object({ kind: z8.literal("segment_entered"), segment_id: Id, ...exclude }).strict(),
1642
+ z9.object({ kind: z9.literal("segment_entered"), segment_id: Id, ...exclude }).strict(),
1520
1643
  /**
1521
1644
  * S4. When somebody clicks a link in a mailing that has already gone out.
1522
1645
  *
@@ -1526,7 +1649,7 @@ var AutomationTrigger = z8.discriminatedUnion("kind", [
1526
1649
  * tracking off there is no click to hear about, so the validator refuses it
1527
1650
  * rather than leaving an automation that can never fire.
1528
1651
  */
1529
- z8.object({ kind: z8.literal("link_clicked"), mailing_id: Id, url: z8.string().min(1).max(2048).optional(), ...exclude }).strict()
1652
+ z9.object({ kind: z9.literal("link_clicked"), mailing_id: Id, url: z9.string().min(1).max(2048).optional(), ...exclude }).strict()
1530
1653
  ]);
1531
1654
  var AUTOMATION_DATE_TRIGGER_KINDS = ["date_anniversary", "exact_date"];
1532
1655
  var MAX_TRIGGERS = 10;
@@ -1545,45 +1668,45 @@ var AUTOMATION_STEP_KINDS = [
1545
1668
  "webhook",
1546
1669
  "notify"
1547
1670
  ];
1548
- var AutomationStepKind = z8.enum(AUTOMATION_STEP_KINDS);
1671
+ var AutomationStepKind = z9.enum(AUTOMATION_STEP_KINDS);
1549
1672
  var next = { next: StepId.nullable() };
1550
- var Unchosen = z8.literal("");
1551
- var DraftSlug = z8.union([Slug, Unchosen]);
1552
- var DraftPropertyKey = z8.union([ContactPropertyKey, Unchosen]);
1553
- var label = { label: z8.string().max(120).nullish() };
1554
- var EmailStepLanguage = z8.object({
1555
- subject: z8.string().min(1).max(998),
1556
- preheader: z8.string().max(500).nullable(),
1673
+ var Unchosen = z9.literal("");
1674
+ var DraftSlug = z9.union([Slug, Unchosen]);
1675
+ var DraftPropertyKey = z9.union([ContactPropertyKey, Unchosen]);
1676
+ var label2 = { label: z9.string().max(120).nullish() };
1677
+ var EmailStepLanguage = z9.object({
1678
+ subject: z9.string().min(1).max(998),
1679
+ preheader: z9.string().max(500).nullable(),
1557
1680
  document: TemplateDocument,
1558
1681
  /** This language's insertions, its texts over the template's structure (every text present). */
1559
1682
  insertions: Insertions.nullish()
1560
1683
  }).strict();
1561
- var EmailStep = z8.object({
1562
- kind: z8.literal("email"),
1563
- ...label,
1684
+ var EmailStep = z9.object({
1685
+ kind: z9.literal("email"),
1686
+ ...label2,
1564
1687
  ...next,
1565
1688
  template_id: Id.nullish(),
1566
1689
  document: TemplateDocument.nullish(),
1567
1690
  /** Empty while the step is being written, or when its template has a subject; else `not_chosen` refuses to publish it. */
1568
- subject: z8.string().max(998),
1569
- preheader: z8.string().max(500).nullish(),
1691
+ subject: z9.string().max(998),
1692
+ preheader: z9.string().max(500).nullish(),
1570
1693
  locale: LocaleTag.nullish(),
1571
- languages: z8.record(LocaleTag, EmailStepLanguage).nullish(),
1694
+ languages: z9.record(LocaleTag, EmailStepLanguage).nullish(),
1572
1695
  /** The main language's insertions, snapshot from the template when the automation is published. */
1573
1696
  insertions: Insertions.nullish()
1574
1697
  }).strict();
1575
- var DelayStep = z8.object({
1576
- kind: z8.literal("delay"),
1577
- ...label,
1698
+ var DelayStep = z9.object({
1699
+ kind: z9.literal("delay"),
1700
+ ...label2,
1578
1701
  ...next,
1579
- wait: z8.discriminatedUnion("mode", [
1580
- z8.object({ mode: z8.literal("duration"), seconds: z8.number().int().min(1).max(MAX_DELAY_SECONDS) }).strict(),
1581
- z8.object({ mode: z8.literal("time_of_day"), at: TimeOfDay }).strict(),
1582
- z8.object({ mode: z8.literal("weekday"), weekday: Weekday, at: TimeOfDay }).strict(),
1702
+ wait: z9.discriminatedUnion("mode", [
1703
+ z9.object({ mode: z9.literal("duration"), seconds: z9.number().int().min(1).max(MAX_DELAY_SECONDS) }).strict(),
1704
+ z9.object({ mode: z9.literal("time_of_day"), at: TimeOfDay }).strict(),
1705
+ z9.object({ mode: z9.literal("weekday"), weekday: Weekday, at: TimeOfDay }).strict(),
1583
1706
  /** A fixed day has no next occurrence, so `continue` is not one of its answers. */
1584
- z8.object({ mode: z8.literal("date"), on: DateOnly, at: TimeOfDay, passed: z8.enum(["skip", "stop"]) }).strict(),
1585
- z8.object({
1586
- mode: z8.literal("date_property"),
1707
+ z9.object({ mode: z9.literal("date"), on: DateOnly, at: TimeOfDay, passed: z9.enum(["skip", "stop"]) }).strict(),
1708
+ z9.object({
1709
+ mode: z9.literal("date_property"),
1587
1710
  key: ContactPropertyKey,
1588
1711
  offset_days: OffsetDays,
1589
1712
  at: TimeOfDay,
@@ -1591,9 +1714,9 @@ var DelayStep = z8.object({
1591
1714
  }).strict()
1592
1715
  ])
1593
1716
  }).strict();
1594
- var ConditionStep = z8.object({
1595
- kind: z8.literal("condition"),
1596
- ...label,
1717
+ var ConditionStep = z9.object({
1718
+ kind: z9.literal("condition"),
1719
+ ...label2,
1597
1720
  filter: BoundedAutomationFilter,
1598
1721
  yes: StepId.nullable(),
1599
1722
  no: StepId.nullable(),
@@ -1603,49 +1726,49 @@ var ConditionStep = z8.object({
1603
1726
  * neither half means anything without the other: a window with no answer
1604
1727
  * for the end of it would be a silent decision.
1605
1728
  */
1606
- wait_for: z8.object({ up_to_s: z8.number().int().min(1).max(MAX_DELAY_SECONDS), on_timeout: z8.enum(["yes", "no"]) }).strict().nullish()
1729
+ wait_for: z9.object({ up_to_s: z9.number().int().min(1).max(MAX_DELAY_SECONDS), on_timeout: z9.enum(["yes", "no"]) }).strict().nullish()
1607
1730
  }).strict();
1608
- var SplitBranchKey = z8.string().regex(/^[A-Za-z0-9_-]{1,32}$/, "letters, digits, underscore and hyphen, 1 to 32");
1731
+ var SplitBranchKey = z9.string().regex(/^[A-Za-z0-9_-]{1,32}$/, "letters, digits, underscore and hyphen, 1 to 32");
1609
1732
  var MIN_SPLIT_BRANCHES = 2;
1610
1733
  var MAX_SPLIT_BRANCHES = 4;
1611
- var SplitStep = z8.object({
1612
- kind: z8.literal("split"),
1613
- ...label,
1614
- branches: z8.array(
1615
- z8.object({
1734
+ var SplitStep = z9.object({
1735
+ kind: z9.literal("split"),
1736
+ ...label2,
1737
+ branches: z9.array(
1738
+ z9.object({
1616
1739
  key: SplitBranchKey,
1617
1740
  /** A whole percentage. Zero is allowed: a branch kept in the flow but switched off. */
1618
- weight: z8.number().int().min(0).max(100),
1741
+ weight: z9.number().int().min(0).max(100),
1619
1742
  next: StepId.nullable()
1620
1743
  }).strict()
1621
1744
  ).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")
1622
1745
  }).strict();
1623
- var GotoStep = z8.object({ kind: z8.literal("goto"), ...label, target: StepId.nullable() }).strict();
1746
+ var GotoStep = z9.object({ kind: z9.literal("goto"), ...label2, target: StepId.nullable() }).strict();
1624
1747
  var MAX_STEP_VISITS = 20;
1625
- var WebhookStep = z8.object({ kind: z8.literal("webhook"), ...label, ...next, endpoint_id: Id.nullable(), payload: JsonValue.nullish() }).strict();
1626
- var NotifyRecipients = z8.union([z8.literal("owner"), z8.literal("admins"), z8.object({ member_id: Id }).strict()]);
1627
- var NotifyStep = z8.object({
1628
- kind: z8.literal("notify"),
1629
- ...label,
1748
+ var WebhookStep = z9.object({ kind: z9.literal("webhook"), ...label2, ...next, endpoint_id: Id.nullable(), payload: JsonValue.nullish() }).strict();
1749
+ var NotifyRecipients = z9.union([z9.literal("owner"), z9.literal("admins"), z9.object({ member_id: Id }).strict()]);
1750
+ var NotifyStep = z9.object({
1751
+ kind: z9.literal("notify"),
1752
+ ...label2,
1630
1753
  ...next,
1631
1754
  to: NotifyRecipients,
1632
1755
  /** Empty while the step is being written; `not_chosen` refuses to publish it. */
1633
- subject: z8.string().max(998),
1634
- body: z8.string().max(1e4)
1756
+ subject: z9.string().max(998),
1757
+ body: z9.string().max(1e4)
1635
1758
  }).strict();
1636
- var AutomationStep = z8.discriminatedUnion("kind", [
1759
+ var AutomationStep = z9.discriminatedUnion("kind", [
1637
1760
  EmailStep,
1638
1761
  DelayStep,
1639
1762
  ConditionStep,
1640
- z8.object({ kind: z8.literal("add_tag"), ...label, ...next, tag: DraftSlug }).strict(),
1641
- z8.object({ kind: z8.literal("remove_tag"), ...label, ...next, tag: DraftSlug }).strict(),
1763
+ z9.object({ kind: z9.literal("add_tag"), ...label2, ...next, tag: DraftSlug }).strict(),
1764
+ z9.object({ kind: z9.literal("remove_tag"), ...label2, ...next, tag: DraftSlug }).strict(),
1642
1765
  /** `value` null clears the property, as a contact upsert does. */
1643
- z8.object({ kind: z8.literal("set_property"), ...label, ...next, key: DraftPropertyKey, value: JsonValue }).strict(),
1766
+ z9.object({ kind: z9.literal("set_property"), ...label2, ...next, key: DraftPropertyKey, value: JsonValue }).strict(),
1644
1767
  /** Subscribing never lifts a suppression: the service checks that, not the flow. */
1645
- z8.object({ kind: z8.literal("subscribe_topic"), ...label, ...next, topic: DraftSlug }).strict(),
1768
+ z9.object({ kind: z9.literal("subscribe_topic"), ...label2, ...next, topic: DraftSlug }).strict(),
1646
1769
  /** `topic` unsubscribes from the automation's own topic, `all` from every topic. */
1647
- z8.object({ kind: z8.literal("unsubscribe"), ...label, ...next, scope: z8.enum(["topic", "all"]) }).strict(),
1648
- z8.object({ kind: z8.literal("exit"), ...label }).strict(),
1770
+ z9.object({ kind: z9.literal("unsubscribe"), ...label2, ...next, scope: z9.enum(["topic", "all"]) }).strict(),
1771
+ z9.object({ kind: z9.literal("exit"), ...label2 }).strict(),
1649
1772
  SplitStep,
1650
1773
  GotoStep,
1651
1774
  WebhookStep,
@@ -1669,25 +1792,25 @@ function stepTargets(step) {
1669
1792
  }
1670
1793
  }
1671
1794
  var MAX_STEPS = 200;
1672
- var AutomationFlow = z8.object({
1673
- triggers: z8.array(AutomationTrigger).max(MAX_TRIGGERS),
1795
+ var AutomationFlow = z9.object({
1796
+ triggers: z9.array(AutomationTrigger).max(MAX_TRIGGERS),
1674
1797
  /** The first step. `null` is an empty flow. */
1675
1798
  entry: StepId.nullable(),
1676
- steps: z8.record(StepId, AutomationStep)
1799
+ steps: z9.record(StepId, AutomationStep)
1677
1800
  }).strict();
1678
1801
  var emptyFlow = () => ({ triggers: [], entry: null, steps: {} });
1679
- var QuietHours = z8.object({
1802
+ var QuietHours = z9.object({
1680
1803
  start: TimeOfDay,
1681
1804
  end: TimeOfDay,
1682
- weekdays: z8.array(Weekday).min(1).max(7).nullish()
1805
+ weekdays: z9.array(Weekday).min(1).max(7).nullish()
1683
1806
  }).strict();
1684
1807
  var RE_ENTRY_MODES = ["off", "after_exit"];
1685
- var ReEntryMode = z8.enum(RE_ENTRY_MODES);
1808
+ var ReEntryMode = z9.enum(RE_ENTRY_MODES);
1686
1809
  var MAX_RE_ENTRY_COOLDOWN_SECONDS = 365 * 24 * 60 * 60;
1687
- var AutomationSettings = z8.object({
1810
+ var AutomationSettings = z9.object({
1688
1811
  re_entry: ReEntryMode,
1689
1812
  /** Seconds a person must wait after leaving before entering again. Only with `after_exit`. */
1690
- re_entry_cooldown_s: z8.number().int().min(0).max(MAX_RE_ENTRY_COOLDOWN_SECONDS).nullish(),
1813
+ re_entry_cooldown_s: z9.number().int().min(0).max(MAX_RE_ENTRY_COOLDOWN_SECONDS).nullish(),
1691
1814
  quiet_hours: QuietHours.nullish(),
1692
1815
  /** Checked before every step; when it matches, the run ends. */
1693
1816
  exit_filter: BoundedAutomationFilter.nullish()
@@ -1745,18 +1868,18 @@ var AUTOMATION_ISSUE_CODES = [
1745
1868
  /** A one-off date that is already over everywhere on earth, so it would fire for nobody. */
1746
1869
  "date_in_the_past"
1747
1870
  ];
1748
- var AutomationIssueCode = z8.enum(AUTOMATION_ISSUE_CODES);
1749
- var AutomationIssue = z8.object({
1871
+ var AutomationIssueCode = z9.enum(AUTOMATION_ISSUE_CODES);
1872
+ var AutomationIssue = z9.object({
1750
1873
  code: AutomationIssueCode,
1751
1874
  /** The step the issue is about, when it is about one. */
1752
1875
  step_id: StepId.nullable(),
1753
1876
  /** Where inside the document, for the canvas to point at a field. */
1754
- path: z8.array(z8.union([z8.string(), z8.number()])),
1755
- message: z8.string()
1877
+ path: z9.array(z9.union([z9.string(), z9.number()])),
1878
+ message: z9.string()
1756
1879
  });
1757
- var AutomationValidation = z8.object({
1758
- ok: z8.boolean(),
1759
- issues: z8.array(AutomationIssue)
1880
+ var AutomationValidation = z9.object({
1881
+ ok: z9.boolean(),
1882
+ issues: z9.array(AutomationIssue)
1760
1883
  });
1761
1884
  function validateAutomation(flow, settings, ctx) {
1762
1885
  const issues = [];
@@ -2147,7 +2270,7 @@ function cycles(flow) {
2147
2270
  return out.sort();
2148
2271
  }
2149
2272
  var AUTOMATION_STATUSES = ["draft", "active", "paused", "archived"];
2150
- var AutomationStatus = z8.enum(AUTOMATION_STATUSES);
2273
+ var AutomationStatus = z9.enum(AUTOMATION_STATUSES);
2151
2274
  var AUTOMATION_END_REASONS = [
2152
2275
  "completed",
2153
2276
  "exit_filter",
@@ -2166,9 +2289,9 @@ var AUTOMATION_END_REASONS = [
2166
2289
  "ended_by_hand",
2167
2290
  "failed"
2168
2291
  ];
2169
- var AutomationEndReason = z8.enum(AUTOMATION_END_REASONS);
2292
+ var AutomationEndReason = z9.enum(AUTOMATION_END_REASONS);
2170
2293
  var AUTOMATION_WAIT_REASONS = ["delay", "quiet_hours", "plan_limit", "sending", "condition"];
2171
- var AutomationWaitReason = z8.enum(AUTOMATION_WAIT_REASONS);
2294
+ var AutomationWaitReason = z9.enum(AUTOMATION_WAIT_REASONS);
2172
2295
  var AUTOMATION_ENTRY_REFUSALS = [
2173
2296
  "already_inside",
2174
2297
  "re_entry_off",
@@ -2179,26 +2302,26 @@ var AUTOMATION_ENTRY_REFUSALS = [
2179
2302
  "not_active",
2180
2303
  "unknown_contact"
2181
2304
  ];
2182
- var AutomationEntryRefusal = z8.enum(AUTOMATION_ENTRY_REFUSALS);
2183
- var AutomationCounts = z8.object({
2184
- started: z8.number().int().min(0),
2185
- in_progress: z8.number().int().min(0),
2186
- completed: z8.number().int().min(0),
2187
- exited: z8.number().int().min(0),
2188
- failed: z8.number().int().min(0)
2189
- });
2190
- var Automation = z8.object({
2305
+ var AutomationEntryRefusal = z9.enum(AUTOMATION_ENTRY_REFUSALS);
2306
+ var AutomationCounts = z9.object({
2307
+ started: z9.number().int().min(0),
2308
+ in_progress: z9.number().int().min(0),
2309
+ completed: z9.number().int().min(0),
2310
+ exited: z9.number().int().min(0),
2311
+ failed: z9.number().int().min(0)
2312
+ });
2313
+ var Automation = z9.object({
2191
2314
  id: Id,
2192
- name: z8.string().min(1).max(200),
2315
+ name: z9.string().min(1).max(200),
2193
2316
  status: AutomationStatus,
2194
2317
  /** Every automation sends under one topic; there are no transactional automations. */
2195
2318
  topic: Slug,
2196
2319
  provider_id: Id.nullable(),
2197
2320
  settings: AutomationSettings,
2198
2321
  /** The flow people are running through, null while the automation has never been published. */
2199
- published_version: z8.number().int().min(1).nullable(),
2322
+ published_version: z9.number().int().min(1).nullable(),
2200
2323
  /** The flow being edited. Increments on every save, like a template's version. */
2201
- draft_version: z8.number().int().min(1),
2324
+ draft_version: z9.number().int().min(1),
2202
2325
  counts: AutomationCounts,
2203
2326
  created_at: Timestamp,
2204
2327
  updated_at: Timestamp,
@@ -2211,16 +2334,16 @@ var AutomationWithFlow = Automation.extend({
2211
2334
  published_flow: AutomationFlow.nullable()
2212
2335
  });
2213
2336
  var AutomationSummary = Automation;
2214
- var AutomationCreate = z8.object({
2215
- name: z8.string().min(1).max(200),
2337
+ var AutomationCreate = z9.object({
2338
+ name: z9.string().min(1).max(200),
2216
2339
  topic: Slug,
2217
2340
  provider_id: Id.optional(),
2218
2341
  flow: AutomationFlow.optional(),
2219
2342
  settings: AutomationSettings.partial().optional()
2220
2343
  });
2221
- var AutomationUpdate = z8.object({
2222
- base_version: z8.number().int().min(1),
2223
- name: z8.string().min(1).max(200).optional(),
2344
+ var AutomationUpdate = z9.object({
2345
+ base_version: z9.number().int().min(1),
2346
+ name: z9.string().min(1).max(200).optional(),
2224
2347
  topic: Slug.optional(),
2225
2348
  provider_id: Id.optional(),
2226
2349
  flow: AutomationFlow.optional(),
@@ -2233,42 +2356,42 @@ var AutomationListQuery = PageQuery.extend({
2233
2356
  status: AutomationStatus.optional(),
2234
2357
  topic: Slug.optional()
2235
2358
  });
2236
- var AutomationPublishRequest = z8.object({
2359
+ var AutomationPublishRequest = z9.object({
2237
2360
  /**
2238
2361
  * Answer what this publish would do and change nothing, whatever the flow
2239
2362
  * looks like. Without it a publish that has no issues and moves nobody
2240
2363
  * simply goes ahead, which is right for an API caller and wrong for a
2241
2364
  * dialog that is only showing somebody what they are about to do.
2242
2365
  */
2243
- dry_run: z8.boolean().optional(),
2244
- confirm: z8.boolean().optional(),
2366
+ dry_run: z9.boolean().optional(),
2367
+ confirm: z9.boolean().optional(),
2245
2368
  /** Per removed step: the step its waiting runs move to, or null to end them. */
2246
- moves: z8.record(StepId, StepId.nullable()).optional(),
2369
+ moves: z9.record(StepId, StepId.nullable()).optional(),
2247
2370
  /** Also enter everyone who matches a trigger's condition right now. */
2248
- backfill: z8.boolean().optional()
2371
+ backfill: z9.boolean().optional()
2249
2372
  }).strict();
2250
- var AutomationPublishMove = z8.object({
2373
+ var AutomationPublishMove = z9.object({
2251
2374
  step_id: StepId,
2252
2375
  /** Why the step's people have to move: it is gone, or its delay changed. */
2253
- change: z8.enum(["removed", "delay_changed", "kind_changed"]),
2254
- waiting: z8.number().int().min(0),
2376
+ change: z9.enum(["removed", "delay_changed", "kind_changed"]),
2377
+ waiting: z9.number().int().min(0),
2255
2378
  /** Where they go: a step id, or null to end their runs with `step_removed`. */
2256
2379
  destination: StepId.nullable()
2257
2380
  });
2258
- var AutomationPublishResult = z8.object({
2259
- published: z8.boolean(),
2381
+ var AutomationPublishResult = z9.object({
2382
+ published: z9.boolean(),
2260
2383
  automation: Automation,
2261
2384
  /** Empty when nothing has to move; non-empty and `published` false asks for a confirmation. */
2262
- moves: z8.array(AutomationPublishMove),
2385
+ moves: z9.array(AutomationPublishMove),
2263
2386
  /** How many people the backfill entered, or would enter when it is not confirmed. */
2264
- backfill: z8.number().int().min(0),
2265
- issues: z8.array(AutomationIssue)
2266
- });
2267
- var AutomationDuplicateRequest = z8.object({ name: z8.string().min(1).max(200).optional() }).strict();
2268
- var AutomationEnrollRequest = z8.object({
2269
- contact_ids: z8.array(Id).min(1).max(1e3).optional(),
2270
- external_ids: z8.array(z8.string().min(1).max(255)).min(1).max(1e3).optional(),
2271
- emails: z8.array(Email).min(1).max(1e3).optional(),
2387
+ backfill: z9.number().int().min(0),
2388
+ issues: z9.array(AutomationIssue)
2389
+ });
2390
+ var AutomationDuplicateRequest = z9.object({ name: z9.string().min(1).max(200).optional() }).strict();
2391
+ var AutomationEnrollRequest = z9.object({
2392
+ contact_ids: z9.array(Id).min(1).max(1e3).optional(),
2393
+ external_ids: z9.array(z9.string().min(1).max(255)).min(1).max(1e3).optional(),
2394
+ emails: z9.array(Email).min(1).max(1e3).optional(),
2272
2395
  segment_id: Id.optional(),
2273
2396
  /** Where to start them; the flow's entry step by default. */
2274
2397
  step_id: StepId.optional()
@@ -2276,34 +2399,34 @@ var AutomationEnrollRequest = z8.object({
2276
2399
  (v) => [v.contact_ids, v.external_ids, v.emails, v.segment_id].filter((x) => x !== void 0).length === 1,
2277
2400
  "name the people exactly one way: contact_ids, external_ids, emails or segment_id"
2278
2401
  );
2279
- var AutomationEnrollment = z8.object({
2402
+ var AutomationEnrollment = z9.object({
2280
2403
  contact_id: Id.nullable(),
2281
2404
  email: Email.nullable(),
2282
- external_id: z8.string().nullable(),
2283
- entered: z8.boolean(),
2405
+ external_id: z9.string().nullable(),
2406
+ entered: z9.boolean(),
2284
2407
  run_id: Id.nullable(),
2285
2408
  reason: AutomationEntryRefusal.nullable()
2286
2409
  });
2287
- var AutomationEnrollResult = z8.object({
2288
- entered: z8.number().int().min(0),
2289
- refused: z8.number().int().min(0),
2290
- results: z8.array(AutomationEnrollment)
2410
+ var AutomationEnrollResult = z9.object({
2411
+ entered: z9.number().int().min(0),
2412
+ refused: z9.number().int().min(0),
2413
+ results: z9.array(AutomationEnrollment)
2291
2414
  });
2292
- var AutomationRunStatus = z8.enum(["active", "waiting", "completed", "exited", "failed"]);
2293
- var AutomationRun = z8.object({
2415
+ var AutomationRunStatus = z9.enum(["active", "waiting", "completed", "exited", "failed"]);
2416
+ var AutomationRun = z9.object({
2294
2417
  id: Id,
2295
2418
  automation_id: Id,
2296
2419
  contact_id: Id,
2297
2420
  email: Email,
2298
- external_id: z8.string().nullable(),
2299
- version: z8.number().int().min(1),
2421
+ external_id: z9.string().nullable(),
2422
+ version: z9.number().int().min(1),
2300
2423
  status: AutomationRunStatus,
2301
2424
  current_step_id: StepId.nullable(),
2302
2425
  next_action_at: Timestamp.nullable(),
2303
2426
  wait_reason: AutomationWaitReason.nullable(),
2304
- end_reason: z8.string().nullable(),
2427
+ end_reason: z9.string().nullable(),
2305
2428
  /** What went wrong the last time this run tried to take its step, null otherwise. */
2306
- last_error: z8.string().nullable(),
2429
+ last_error: z9.string().nullable(),
2307
2430
  entered_at: Timestamp,
2308
2431
  ended_at: Timestamp.nullable()
2309
2432
  });
@@ -2313,13 +2436,13 @@ var AutomationRunListQuery = PageQuery.extend({
2313
2436
  contact_id: Id.optional()
2314
2437
  });
2315
2438
  var ContactAutomationRun = AutomationRun.extend({
2316
- automation: z8.object({ id: Id, name: z8.string(), status: AutomationStatus })
2439
+ automation: z9.object({ id: Id, name: z9.string(), status: AutomationStatus })
2317
2440
  });
2318
2441
  var ContactAutomationListQuery = PageQuery.extend({ status: AutomationRunStatus.optional() });
2319
- var AutomationStepExecution = z8.object({
2442
+ var AutomationStepExecution = z9.object({
2320
2443
  step_id: StepId,
2321
2444
  step_kind: AutomationStepKind,
2322
- visit: z8.number().int().min(1),
2445
+ visit: z9.number().int().min(1),
2323
2446
  started_at: Timestamp,
2324
2447
  finished_at: Timestamp.nullable(),
2325
2448
  /**
@@ -2331,48 +2454,48 @@ var AutomationStepExecution = z8.object({
2331
2454
  */
2332
2455
  outcome: Properties
2333
2456
  });
2334
- var AutomationJourney = z8.object({
2457
+ var AutomationJourney = z9.object({
2335
2458
  run: AutomationRun,
2336
- steps: z8.array(AutomationStepExecution)
2459
+ steps: z9.array(AutomationStepExecution)
2337
2460
  });
2338
- var AutomationStepReport = z8.object({
2461
+ var AutomationStepReport = z9.object({
2339
2462
  step_id: StepId,
2340
2463
  step_kind: AutomationStepKind,
2341
- reached: z8.number().int().min(0),
2342
- waiting: z8.number().int().min(0),
2343
- passed: z8.number().int().min(0),
2464
+ reached: z9.number().int().min(0),
2465
+ waiting: z9.number().int().min(0),
2466
+ passed: z9.number().int().min(0),
2344
2467
  /** Per branch, for a condition: how many took `yes` and how many `no`. */
2345
- branches: z8.record(z8.number().int().min(0)),
2468
+ branches: z9.record(z9.number().int().min(0)),
2346
2469
  /** The step mailing's id, for an email step of the published version. */
2347
2470
  mailing_id: Id.nullable()
2348
2471
  });
2349
- var AutomationReport = z8.object({
2472
+ var AutomationReport = z9.object({
2350
2473
  counts: AutomationCounts,
2351
2474
  /** Why the people who left did: `AutomationEndReason` to a count. */
2352
- end_reasons: z8.record(z8.number().int().min(0)),
2475
+ end_reasons: z9.record(z9.number().int().min(0)),
2353
2476
  /**
2354
2477
  * Why people a trigger named did not enter: `AutomationEntryRefusal` to a
2355
2478
  * count. Without it a pause, an exclusion or a missing subscription would
2356
2479
  * turn people away invisibly.
2357
2480
  */
2358
- refusals: z8.record(z8.number().int().min(0)),
2359
- steps: z8.array(AutomationStepReport)
2360
- });
2361
- var AutomationExitRunRequest = z8.object({ reason: z8.string().max(200).optional() }).strict();
2362
- var AutomationRunParams = z8.object({ id: Id, run_id: Id });
2363
- var AutomationStepParams = z8.object({ id: Id, step_id: StepId });
2364
- var AutomationTestEmailRequest = z8.object({ to: Email, merge: Properties.optional(), locale: LocaleTag.optional() }).strict();
2365
- var AutomationValidateRequest = z8.object({ flow: AutomationFlow.optional(), settings: AutomationSettings.partial().optional() }).strict();
2366
- var EventCreate = z8.object({
2481
+ refusals: z9.record(z9.number().int().min(0)),
2482
+ steps: z9.array(AutomationStepReport)
2483
+ });
2484
+ var AutomationExitRunRequest = z9.object({ reason: z9.string().max(200).optional() }).strict();
2485
+ var AutomationRunParams = z9.object({ id: Id, run_id: Id });
2486
+ var AutomationStepParams = z9.object({ id: Id, step_id: StepId });
2487
+ var AutomationTestEmailRequest = z9.object({ to: Email, merge: Properties.optional(), locale: LocaleTag.optional() }).strict();
2488
+ var AutomationValidateRequest = z9.object({ flow: AutomationFlow.optional(), settings: AutomationSettings.partial().optional() }).strict();
2489
+ var EventCreate = z9.object({
2367
2490
  name: EventName,
2368
- contact: z8.object({ external_id: z8.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"),
2491
+ contact: z9.object({ external_id: z9.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"),
2369
2492
  data: Properties.optional(),
2370
2493
  occurred_at: Timestamp.optional(),
2371
- id: z8.string().min(1).max(128).optional()
2494
+ id: z9.string().min(1).max(128).optional()
2372
2495
  }).strict();
2373
- var Event = z8.object({
2496
+ var Event = z9.object({
2374
2497
  id: Id,
2375
- client_event_id: z8.string().nullable(),
2498
+ client_event_id: z9.string().nullable(),
2376
2499
  name: EventName,
2377
2500
  contact_id: Id,
2378
2501
  data: Properties,
@@ -2383,7 +2506,7 @@ var Event = z8.object({
2383
2506
  * hand. Each is then admitted or refused by the runtime on its own rules
2384
2507
  * (consent, exclusions, re-entry), which `automations.report` counts.
2385
2508
  */
2386
- entered: z8.number().int().min(0)
2509
+ entered: z9.number().int().min(0)
2387
2510
  });
2388
2511
  var EventListQuery = PageQuery.extend({
2389
2512
  name: EventName.optional(),
@@ -2391,19 +2514,19 @@ var EventListQuery = PageQuery.extend({
2391
2514
  });
2392
2515
 
2393
2516
  // src/workspace.ts
2394
- var CompanyId = z9.string().min(1).max(64);
2517
+ var CompanyId = z10.string().min(1).max(64);
2395
2518
  var ASSET_POLICIES = ["any", "service_only"];
2396
- var AssetPolicy = z9.enum(ASSET_POLICIES);
2519
+ var AssetPolicy = z10.enum(ASSET_POLICIES);
2397
2520
  var MAX_ALLOWED_ASSET_HOSTS = 20;
2398
- var AssetHost = z9.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");
2521
+ var AssetHost = z10.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");
2399
2522
  var MAX_MERGE_DEFAULTS = 50;
2400
2523
  var MAX_MERGE_DEFAULT_LENGTH = 2e3;
2401
- var MergeFieldName = z9.string().regex(/^[a-z][a-z0-9_]*$/, "a merge-field name: lowercase letters, digits and underscores, starting with a letter").max(64);
2402
- var MergeDefaultValue = z9.union([z9.string().max(MAX_MERGE_DEFAULT_LENGTH), z9.number().finite(), z9.boolean()]);
2403
- var MergeDefaults = z9.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), {
2524
+ var MergeFieldName = z10.string().regex(/^[a-z][a-z0-9_]*$/, "a merge-field name: lowercase letters, digits and underscores, starting with a letter").max(64);
2525
+ var MergeDefaultValue = z10.union([z10.string().max(MAX_MERGE_DEFAULT_LENGTH), z10.number().finite(), z10.boolean()]);
2526
+ var MergeDefaults = z10.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), {
2404
2527
  message: `a reserved merge field (${Object.keys(RESERVED_MERGE_FIELDS).join(", ")}) cannot have a workspace default`
2405
2528
  });
2406
- var WorkspaceSettings = z9.object({
2529
+ var WorkspaceSettings = z10.object({
2407
2530
  /**
2408
2531
  * The workspace's main language (a {@link LocaleTag}, e.g. "de"): the main
2409
2532
  * language of a new template, and of the hosted pages when nothing else
@@ -2416,9 +2539,9 @@ var WorkspaceSettings = z9.object({
2416
2539
  * each; the hosted pages are offered in those of them they support (English,
2417
2540
  * German, French, Italian, Spanish). The service stores canonical casing.
2418
2541
  */
2419
- locales: z9.array(LocaleTag).min(1).max(20).refine((l) => new Set(l.map((t) => t.toLowerCase())).size === l.length, "a language appears twice"),
2542
+ locales: z10.array(LocaleTag).min(1).max(20).refine((l) => new Set(l.map((t) => t.toLowerCase())).size === l.length, "a language appears twice"),
2420
2543
  /** Open and click tracking. Off by default, opt-in per workspace. */
2421
- tracking_enabled: z9.boolean(),
2544
+ tracking_enabled: z10.boolean(),
2422
2545
  /** Where images, stylesheets and fonts in a mail may load from. `any` by default. */
2423
2546
  asset_policy: AssetPolicy,
2424
2547
  /**
@@ -2426,7 +2549,7 @@ var WorkspaceSettings = z9.object({
2426
2549
  * the workspace's website, typically. Empty by default. Ignored under `any`,
2427
2550
  * which allows everything already.
2428
2551
  */
2429
- allowed_asset_hosts: z9.array(AssetHost).max(MAX_ALLOWED_ASSET_HOSTS),
2552
+ allowed_asset_hosts: z10.array(AssetHost).max(MAX_ALLOWED_ASSET_HOSTS),
2430
2553
  /** Merge values every mail of the workspace can use (see `MergeDefaults`). Empty by default. */
2431
2554
  merge_defaults: MergeDefaults,
2432
2555
  /**
@@ -2435,10 +2558,10 @@ var WorkspaceSettings = z9.object({
2435
2558
  */
2436
2559
  default_timezone: TimezoneName.nullable()
2437
2560
  });
2438
- var Workspace = z9.object({
2561
+ var Workspace = z10.object({
2439
2562
  id: Id,
2440
2563
  slug: Slug,
2441
- name: z9.string().min(1).max(120),
2564
+ name: z10.string().min(1).max(120),
2442
2565
  settings: WorkspaceSettings,
2443
2566
  /**
2444
2567
  * The auth-brain company (tenant) the workspace was created for, or null for
@@ -2449,13 +2572,13 @@ var Workspace = z9.object({
2449
2572
  created_at: Timestamp,
2450
2573
  updated_at: Timestamp
2451
2574
  });
2452
- var WorkspaceCreate = z9.object({
2575
+ var WorkspaceCreate = z10.object({
2453
2576
  slug: Slug,
2454
- name: z9.string().min(1).max(120),
2577
+ name: z10.string().min(1).max(120),
2455
2578
  settings: WorkspaceSettings.partial().optional(),
2456
- owner: z9.object({
2579
+ owner: z10.object({
2457
2580
  email: Email,
2458
- name: z9.string().max(200).nullable().optional()
2581
+ name: z10.string().max(200).nullable().optional()
2459
2582
  }),
2460
2583
  /**
2461
2584
  * The signed-in person's active auth-brain company. The dashboard always
@@ -2465,49 +2588,49 @@ var WorkspaceCreate = z9.object({
2465
2588
  */
2466
2589
  company_id: CompanyId.optional()
2467
2590
  });
2468
- var WorkspaceUpdate = z9.object({
2469
- name: z9.string().min(1).max(120),
2591
+ var WorkspaceUpdate = z10.object({
2592
+ name: z10.string().min(1).max(120),
2470
2593
  settings: WorkspaceSettings.partial()
2471
2594
  }).partial().refine((v) => Object.keys(v).length > 0, "at least one field");
2472
- var WorkspaceMove = z9.object({ company_id: CompanyId });
2595
+ var WorkspaceMove = z10.object({ company_id: CompanyId });
2473
2596
  var MEMBER_ROLES = ["owner", "admin", "editor", "viewer"];
2474
- var MemberRole = z9.enum(MEMBER_ROLES);
2597
+ var MemberRole = z10.enum(MEMBER_ROLES);
2475
2598
  var WorkspaceMembership = Workspace.extend({ role: MemberRole });
2476
- var Member = z9.object({
2599
+ var Member = z10.object({
2477
2600
  id: Id,
2478
2601
  /** The person's auth-brain subject. */
2479
- subject: z9.string().min(1).max(255),
2602
+ subject: z10.string().min(1).max(255),
2480
2603
  email: Email,
2481
- name: z9.string().max(200).nullable(),
2604
+ name: z10.string().max(200).nullable(),
2482
2605
  role: MemberRole,
2483
2606
  created_at: Timestamp
2484
2607
  });
2485
- var MemberCreate = z9.object({
2486
- subject: z9.string().min(1).max(255),
2608
+ var MemberCreate = z10.object({
2609
+ subject: z10.string().min(1).max(255),
2487
2610
  email: Email,
2488
- name: z9.string().max(200).nullable().optional(),
2611
+ name: z10.string().max(200).nullable().optional(),
2489
2612
  role: MemberRole
2490
2613
  });
2491
- var MemberUpdate = z9.object({ role: MemberRole });
2614
+ var MemberUpdate = z10.object({ role: MemberRole });
2492
2615
  var API_KEY_SCOPES = ["full", "read", "send"];
2493
- var ApiKeyScope = z9.enum(API_KEY_SCOPES);
2494
- var ApiKey = z9.object({
2616
+ var ApiKeyScope = z10.enum(API_KEY_SCOPES);
2617
+ var ApiKey = z10.object({
2495
2618
  id: Id,
2496
- name: z9.string().min(1).max(120),
2619
+ name: z10.string().min(1).max(120),
2497
2620
  /** The first characters of the key, for recognising it in a list. */
2498
- prefix: z9.string().min(4).max(32),
2621
+ prefix: z10.string().min(4).max(32),
2499
2622
  scope: ApiKeyScope,
2500
2623
  last_used_at: Timestamp.nullable(),
2501
2624
  revoked_at: Timestamp.nullable(),
2502
2625
  created_at: Timestamp
2503
2626
  });
2504
- var ApiKeyCreate = z9.object({
2505
- name: z9.string().min(1).max(120),
2627
+ var ApiKeyCreate = z10.object({
2628
+ name: z10.string().min(1).max(120),
2506
2629
  /** Omitted means `full`. */
2507
2630
  scope: ApiKeyScope.optional()
2508
2631
  });
2509
- var ApiKeyCreated = z9.object({
2510
- key: z9.string().min(20),
2632
+ var ApiKeyCreated = z10.object({
2633
+ key: z10.string().min(20),
2511
2634
  api_key: ApiKey
2512
2635
  });
2513
2636
  var AUDIT_ACTIONS = [
@@ -2534,6 +2657,7 @@ var AUDIT_ACTIONS = [
2534
2657
  "template.created",
2535
2658
  "template.updated",
2536
2659
  "template.deleted",
2660
+ "template.inputs_declared",
2537
2661
  "saved_section.created",
2538
2662
  "saved_section.updated",
2539
2663
  "saved_section.deleted",
@@ -2595,29 +2719,29 @@ var AUDIT_ACTIONS = [
2595
2719
  "automation.run_ended",
2596
2720
  "event.recorded"
2597
2721
  ];
2598
- var AuditAction = z9.enum(AUDIT_ACTIONS);
2599
- var AuditActor = z9.discriminatedUnion("type", [
2600
- z9.object({ type: z9.literal("member"), member_id: Id, subject: z9.string().min(1) }),
2601
- z9.object({
2602
- type: z9.literal("api_key"),
2722
+ var AuditAction = z10.enum(AUDIT_ACTIONS);
2723
+ var AuditActor = z10.discriminatedUnion("type", [
2724
+ z10.object({ type: z10.literal("member"), member_id: Id, subject: z10.string().min(1) }),
2725
+ z10.object({
2726
+ type: z10.literal("api_key"),
2603
2727
  api_key_id: Id,
2604
2728
  /**
2605
2729
  * Who the client's application said it was acting for, from
2606
2730
  * `ON_BEHALF_OF_HEADER`: reported by that application, never verified.
2607
2731
  * Absent when the call carried no label.
2608
2732
  */
2609
- on_behalf_of: z9.string().min(1).max(ON_BEHALF_OF_MAX_LENGTH).optional()
2733
+ on_behalf_of: z10.string().min(1).max(ON_BEHALF_OF_MAX_LENGTH).optional()
2610
2734
  }),
2611
2735
  /** The service itself (the worker, a bounce, the hosted unsubscribe page). */
2612
- z9.object({ type: z9.literal("system"), reason: z9.string().min(1).max(200) })
2736
+ z10.object({ type: z10.literal("system"), reason: z10.string().min(1).max(200) })
2613
2737
  ]);
2614
- var AuditEntry = z9.object({
2738
+ var AuditEntry = z10.object({
2615
2739
  id: Id,
2616
2740
  action: AuditAction,
2617
2741
  actor: AuditActor,
2618
- target_type: z9.string().min(1).max(64),
2742
+ target_type: z10.string().min(1).max(64),
2619
2743
  target_id: Id.nullable(),
2620
- details: z9.record(z9.unknown()),
2744
+ details: z10.record(z10.unknown()),
2621
2745
  created_at: Timestamp
2622
2746
  });
2623
2747
  var AuditQuery = PageQuery.extend({
@@ -2626,12 +2750,12 @@ var AuditQuery = PageQuery.extend({
2626
2750
  });
2627
2751
 
2628
2752
  // src/invites.ts
2629
- import { z as z10 } from "zod";
2753
+ import { z as z11 } from "zod";
2630
2754
  var INVITE_STATUSES = ["pending", "accepted", "revoked", "expired"];
2631
- var InviteStatus = z10.enum(INVITE_STATUSES);
2755
+ var InviteStatus = z11.enum(INVITE_STATUSES);
2632
2756
  var DEFAULT_INVITE_TTL_DAYS = 7;
2633
2757
  var MAX_INVITE_TTL_DAYS = 30;
2634
- var Invite = z10.object({
2758
+ var Invite = z11.object({
2635
2759
  id: Id,
2636
2760
  /** Stored lowercased; only a person signed in with this address can accept. */
2637
2761
  email: Email,
@@ -2639,32 +2763,32 @@ var Invite = z10.object({
2639
2763
  /** Derived from the timestamps below, never stored. */
2640
2764
  status: InviteStatus,
2641
2765
  /** The member who invited, while they are still one (null after they left). */
2642
- invited_by: z10.object({ member_id: Id.nullable(), email: Email.nullable() }),
2766
+ invited_by: z11.object({ member_id: Id.nullable(), email: Email.nullable() }),
2643
2767
  expires_at: Timestamp,
2644
2768
  accepted_at: Timestamp.nullable(),
2645
2769
  revoked_at: Timestamp.nullable(),
2646
2770
  created_at: Timestamp
2647
2771
  });
2648
- var InviteCreate = z10.object({
2772
+ var InviteCreate = z11.object({
2649
2773
  email: Email,
2650
2774
  role: MemberRole,
2651
- expires_in_days: z10.number().int().min(1).max(MAX_INVITE_TTL_DAYS).optional()
2775
+ expires_in_days: z11.number().int().min(1).max(MAX_INVITE_TTL_DAYS).optional()
2652
2776
  });
2653
- var InviteCreated = z10.object({
2777
+ var InviteCreated = z11.object({
2654
2778
  invite: Invite,
2655
- token: z10.string().min(32).max(128)
2779
+ token: z11.string().min(32).max(128)
2656
2780
  });
2657
2781
  var InviteListQuery = PageQuery.extend({
2658
2782
  status: InviteStatus.optional()
2659
2783
  });
2660
- var InviteAccept = z10.object({
2661
- token: z10.string().min(32).max(128),
2784
+ var InviteAccept = z11.object({
2785
+ token: z11.string().min(32).max(128),
2662
2786
  email: Email,
2663
- name: z10.string().max(200).nullable().optional()
2787
+ name: z11.string().max(200).nullable().optional()
2664
2788
  });
2665
- var InviteAccepted = z10.object({
2789
+ var InviteAccepted = z11.object({
2666
2790
  workspace: WorkspaceMembership,
2667
- already_member: z10.boolean()
2791
+ already_member: z11.boolean()
2668
2792
  });
2669
2793
  var INVITE_REFUSAL_REASONS = ["email_mismatch", "inviter_lacks_role", "expired", "revoked", "accepted"];
2670
2794
 
@@ -2971,14 +3095,14 @@ function insertionNameProblem(insertions, name, current) {
2971
3095
  if (has(RESERVED_MERGE_FIELDS, name)) return `"${name}" is a merge field the service fills itself. Choose another name.`;
2972
3096
  if (name !== current && has(insertions, name)) return `There is already an insertion called "${name}".`;
2973
3097
  const chooser = Object.entries(insertions).find(([other, def]) => def.by === name && other !== current);
2974
- if (chooser) return `"${name}" is the value that chooses "${chooser[0]}". Choose another name.`;
2975
- if (current !== void 0 && ownEntry(insertions, current)?.by === name) return `"${name}" is the value that chooses this insertion. Choose another name.`;
3098
+ if (chooser) return `"${name}" is the value "${chooser[0]}" depends on. Choose another name.`;
3099
+ if (current !== void 0 && ownEntry(insertions, current)?.by === name) return `"${name}" is the value this insertion depends on. Choose another name.`;
2976
3100
  return null;
2977
3101
  }
2978
3102
  function insertionByProblem(insertions, by, self) {
2979
- if (!InsertionName.safeParse(by).success) return "The value that chooses is a merge-field name: lowercase letters, digits and underscores (like reason).";
2980
- if (by === "unsubscribe_url") return "The unsubscribe link cannot choose a text. Use a value the client or the contact provides.";
2981
- if (by === self || has(insertions, by)) return `"${by}" is an insertion, not a value. Use a value the client or the contact provides.`;
3103
+ if (!InsertionName.safeParse(by).success) return "The value it depends on is a merge-field name: lowercase letters, digits and underscores (like reason).";
3104
+ if (by === "unsubscribe_url") return "An insertion cannot depend on the unsubscribe link. Use a value the app or the contact provides.";
3105
+ if (by === self || has(insertions, by)) return `"${by}" is an insertion, not a value. Use a value the app or the contact provides.`;
2982
3106
  return null;
2983
3107
  }
2984
3108
  function normalizeChoiceKey(raw) {
@@ -2986,10 +3110,10 @@ function normalizeChoiceKey(raw) {
2986
3110
  }
2987
3111
  function choiceKeyProblem(insertion, key, current) {
2988
3112
  if (INSERTION_TEXT_SLOTS.includes(key)) {
2989
- return `"${key}" names the insertion's ${key === "filled" ? '"any other filled value"' : '"otherwise"'} text, so it cannot be a choice. Choose another value.`;
3113
+ return `"${key}" is kept for the insertion's ${key === "filled" ? '"any other value"' : '"empty"'} sentence, so it cannot be a value. Choose another value.`;
2990
3114
  }
2991
- if (!InsertionChoiceKey.safeParse(key).success) return "A choice is the value a client sends: lowercase letters, digits, hyphens and underscores (like venue).";
2992
- if (key !== current && has(insertion.choices, key)) return `There is already a choice "${key}".`;
3115
+ if (!InsertionChoiceKey.safeParse(key).success) return "A value is written exactly as the app sends it: lowercase letters, digits, hyphens and underscores (like venue).";
3116
+ if (key !== current && has(insertion.choices, key)) return `"${key}" already has its own sentence.`;
2993
3117
  return null;
2994
3118
  }
2995
3119
  function addInsertion(drafts, rawName, rawBy) {
@@ -2998,7 +3122,7 @@ function addInsertion(drafts, rawName, rawBy) {
2998
3122
  if (Object.keys(drafts.insertions).length >= MAX_INSERTIONS) return { ok: false, message: `A template holds at most ${MAX_INSERTIONS} insertions.` };
2999
3123
  const nameProblem = insertionNameProblem(drafts.insertions, name);
3000
3124
  if (nameProblem) return { ok: false, message: nameProblem };
3001
- if (name === by) return { ok: false, message: "An insertion cannot be chosen by its own name. Use the value the client sends (like reason)." };
3125
+ if (name === by) return { ok: false, message: "An insertion cannot depend on its own name. Use the value the app sends (like reason)." };
3002
3126
  const byProblem = insertionByProblem(drafts.insertions, by);
3003
3127
  if (byProblem) return { ok: false, message: byProblem };
3004
3128
  return { ok: true, drafts: editMainInsertions(drafts, { ...drafts.insertions, [name]: { by, choices: {}, filled: null, otherwise: "" } }) };
@@ -3181,6 +3305,25 @@ var REFUSAL_HINTS = {
3181
3305
  insertion_with_fallback: 'Remove the |fallback from the insertion in the subject, preheader or body: its "otherwise" text is the fallback.',
3182
3306
  unknown_translation_insertion: "A language names an insertion or a choice the main language no longer has. Reload the template and try again."
3183
3307
  };
3308
+ function unknownRefusedInsertions(details, drafts) {
3309
+ const reason = details?.reason;
3310
+ if (typeof reason !== "string" || !has(REFUSAL_HINTS, reason)) return [];
3311
+ const names = [];
3312
+ const add = (name) => {
3313
+ if (typeof name === "string" && name !== "" && ownEntry(drafts.insertions, name) === void 0 && !names.includes(name)) names.push(name);
3314
+ };
3315
+ if (Array.isArray(details?.missing)) {
3316
+ for (const m of details.missing) if (typeof m === "object" && m !== null) add(m.insertion);
3317
+ }
3318
+ if (Array.isArray(details?.issues)) {
3319
+ for (const issue of details.issues) {
3320
+ const path = typeof issue === "object" && issue !== null && Array.isArray(issue.path) ? issue.path.map(String) : [];
3321
+ const at = path.indexOf("insertions");
3322
+ if (at >= 0) add(path[at + 1]);
3323
+ }
3324
+ }
3325
+ return names;
3326
+ }
3184
3327
  function insertionRefusalHint(details) {
3185
3328
  const reason = details?.reason;
3186
3329
  if (typeof reason !== "string" || !has(REFUSAL_HINTS, reason)) return null;
@@ -3189,15 +3332,99 @@ function insertionRefusalHint(details) {
3189
3332
  const missing = Array.isArray(details?.missing) ? details.missing.filter((m) => typeof m === "object" && m !== null && typeof m.insertion === "string" && typeof m.choice === "string") : [];
3190
3333
  return missing.length > 0 ? `The language has ${describeMissingTexts(missing)}. ${hint}` : hint;
3191
3334
  }
3335
+ function tokenOf(name) {
3336
+ return new RegExp(String.raw`\{\{(\s*)${name}(\s*)(\|[^}]*)?\}\}`, "g");
3337
+ }
3338
+ function renameTokenInText(text, from, to) {
3339
+ let count = 0;
3340
+ const out = text.replace(tokenOf(from), (_m, before, after, fallback) => {
3341
+ count++;
3342
+ return `{{${before}${to}${after}${fallback ?? ""}}}`;
3343
+ });
3344
+ return { text: count > 0 ? out : text, count };
3345
+ }
3346
+ function renameTokenInDocument(document, from, to) {
3347
+ let count = 0;
3348
+ const walk = (value) => {
3349
+ if (typeof value === "string") {
3350
+ const r = renameTokenInText(value, from, to);
3351
+ count += r.count;
3352
+ return r.text;
3353
+ }
3354
+ if (Array.isArray(value)) {
3355
+ let changed = false;
3356
+ const next2 = value.map((v) => {
3357
+ const w = walk(v);
3358
+ if (w !== v) changed = true;
3359
+ return w;
3360
+ });
3361
+ return changed ? next2 : value;
3362
+ }
3363
+ if (value && typeof value === "object") {
3364
+ let changed = false;
3365
+ const next2 = {};
3366
+ for (const [k, v] of Object.entries(value)) {
3367
+ const w = walk(v);
3368
+ if (w !== v) changed = true;
3369
+ next2[k] = w;
3370
+ }
3371
+ return changed ? next2 : value;
3372
+ }
3373
+ return value;
3374
+ };
3375
+ const renamed = walk(document);
3376
+ return { document: renamed, count };
3377
+ }
3378
+ function renameInsertionPlacements(drafts, from, to) {
3379
+ if (from === to) return { drafts, places: [] };
3380
+ const places = [];
3381
+ const note2 = (locale, where, count) => {
3382
+ if (count > 0) places.push({ locale, where, count });
3383
+ };
3384
+ const body = renameTokenInDocument(drafts.main.document, from, to);
3385
+ const subject = renameTokenInText(drafts.main.subject, from, to);
3386
+ const preheader = renameTokenInText(drafts.main.preheader, from, to);
3387
+ note2(null, "body", body.count);
3388
+ note2(null, "subject", subject.count);
3389
+ note2(null, "preheader", preheader.count);
3390
+ let out = {
3391
+ ...drafts,
3392
+ main: { subject: subject.text, preheader: preheader.text, document: body.document },
3393
+ mainDocumentChanged: drafts.mainDocumentChanged || body.count > 0
3394
+ };
3395
+ for (const [tag, version] of Object.entries(drafts.translations)) {
3396
+ const b = renameTokenInDocument(version.document, from, to);
3397
+ const s = version.subject === null ? { text: null, count: 0 } : renameTokenInText(version.subject, from, to);
3398
+ const p = version.preheader === null ? { text: null, count: 0 } : renameTokenInText(version.preheader, from, to);
3399
+ note2(tag, "body", b.count);
3400
+ note2(tag, "subject", s.count);
3401
+ note2(tag, "preheader", p.count);
3402
+ if (b.count + s.count + p.count === 0) continue;
3403
+ out = {
3404
+ ...out,
3405
+ translations: { ...out.translations, [tag]: { ...version, document: b.document, subject: s.text, preheader: p.text } },
3406
+ changed: out.changed.includes(tag) ? out.changed : [...out.changed, tag]
3407
+ };
3408
+ }
3409
+ return { drafts: out, places };
3410
+ }
3411
+ function renameInsertionEverywhere(drafts, from, rawTo) {
3412
+ const renamed = renameInsertionChecked(drafts, from, rawTo);
3413
+ if (!renamed.ok) return renamed;
3414
+ const to = rawTo.trim();
3415
+ if (to === from) return { ok: true, drafts, places: [] };
3416
+ const placed = renameInsertionPlacements(renamed.drafts, from, to);
3417
+ return { ok: true, drafts: placed.drafts, places: placed.places };
3418
+ }
3192
3419
 
3193
3420
  // src/providers.ts
3194
- import { z as z11 } from "zod";
3421
+ import { z as z12 } from "zod";
3195
3422
  var PROVIDER_KINDS = ["smtp", "resend"];
3196
- var ProviderKind = z11.enum(PROVIDER_KINDS);
3197
- var ProviderPolicy = z11.object({
3198
- daily_recipient_budget: z11.number().int().min(1).max(1e7),
3199
- min_interval_ms: z11.number().int().min(0).max(36e5),
3200
- max_recipients_per_message: z11.number().int().min(1).max(1e3)
3423
+ var ProviderKind = z12.enum(PROVIDER_KINDS);
3424
+ var ProviderPolicy = z12.object({
3425
+ daily_recipient_budget: z12.number().int().min(1).max(1e7),
3426
+ min_interval_ms: z12.number().int().min(0).max(36e5),
3427
+ max_recipients_per_message: z12.number().int().min(1).max(1e3)
3201
3428
  });
3202
3429
  var ICLOUD_SMTP_POLICY = {
3203
3430
  daily_recipient_budget: 800,
@@ -3205,17 +3432,17 @@ var ICLOUD_SMTP_POLICY = {
3205
3432
  max_recipients_per_message: 1
3206
3433
  };
3207
3434
  var SMTP_SECURITY = ["tls", "starttls"];
3208
- var SmtpConfigBase = z11.object({
3209
- host: z11.string().min(1).max(255),
3210
- port: z11.number().int().min(1).max(65535),
3435
+ var SmtpConfigBase = z12.object({
3436
+ host: z12.string().min(1).max(255),
3437
+ port: z12.number().int().min(1).max(65535),
3211
3438
  /** `tls` connects encrypted (465), `starttls` upgrades (587). Never plaintext. */
3212
- security: z11.enum(SMTP_SECURITY),
3213
- username: z11.string().min(1).max(255)
3439
+ security: z12.enum(SMTP_SECURITY),
3440
+ username: z12.string().min(1).max(255)
3214
3441
  });
3215
- var ResendConfigBase = z11.object({});
3216
- var ProviderRejections = z11.object({
3217
- count: z11.number().int().min(0),
3218
- last_error: z11.string().nullable(),
3442
+ var ResendConfigBase = z12.object({});
3443
+ var ProviderRejections = z12.object({
3444
+ count: z12.number().int().min(0),
3445
+ last_error: z12.string().nullable(),
3219
3446
  last_at: Timestamp.nullable(),
3220
3447
  /**
3221
3448
  * The last time the bounce circuit breaker tripped on one of this provider's
@@ -3225,59 +3452,59 @@ var ProviderRejections = z11.object({
3225
3452
  * run's bounce blocks were undone and the mailing paused. `sample` is the
3226
3453
  * reply that tripped it.
3227
3454
  */
3228
- anomaly: z11.object({
3455
+ anomaly: z12.object({
3229
3456
  at: Timestamp,
3230
3457
  /** `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. */
3231
- scope: z11.enum(["mailing", "provider"]),
3458
+ scope: z12.enum(["mailing", "provider"]),
3232
3459
  /**
3233
3460
  * True while the provider-wide breaker is open: no bounce blocks through
3234
3461
  * this provider, test sends refused and mailings not started or resumed
3235
3462
  * (`provider_anomaly`), until an admin clears it (`providers.clearAnomaly`).
3236
3463
  */
3237
- blocking: z11.boolean(),
3464
+ blocking: z12.boolean(),
3238
3465
  mailing_id: Id.nullable(),
3239
- reason: z11.string(),
3240
- sample: z11.string()
3466
+ reason: z12.string(),
3467
+ sample: z12.string()
3241
3468
  }).nullable()
3242
3469
  });
3243
- var ProviderEvents = z11.object({
3244
- status: z11.enum(["active", "needs_secret"]),
3245
- source: z11.enum(["automatic", "manual"]).nullable(),
3246
- url: z11.string().url(),
3247
- error: z11.string().nullable(),
3470
+ var ProviderEvents = z12.object({
3471
+ status: z12.enum(["active", "needs_secret"]),
3472
+ source: z12.enum(["automatic", "manual"]).nullable(),
3473
+ url: z12.string().url(),
3474
+ error: z12.string().nullable(),
3248
3475
  /**
3249
3476
  * Events that named an email this provider never sent through the service
3250
3477
  * (another workspace or system sharing the Resend account): counted, never
3251
3478
  * acted on.
3252
3479
  */
3253
- unmatched: z11.number().int().min(0)
3480
+ unmatched: z12.number().int().min(0)
3254
3481
  });
3255
3482
  var RESEND_EVENT_TYPES = ["email.bounced", "email.complained", "email.delivery_delayed"];
3256
- var ResendSigningSecret = z11.string().max(200).regex(/^whsec_[A-Za-z0-9+/]{16,}={0,2}$/, "must be the signing secret Resend shows, starting with whsec_");
3257
- var ProviderEventsSecret = z11.object({ signing_secret: ResendSigningSecret });
3483
+ var ResendSigningSecret = z12.string().max(200).regex(/^whsec_[A-Za-z0-9+/]{16,}={0,2}$/, "must be the signing secret Resend shows, starting with whsec_");
3484
+ var ProviderEventsSecret = z12.object({ signing_secret: ResendSigningSecret });
3258
3485
  var ProviderFields = {
3259
- name: z11.string().min(1).max(120),
3260
- from_name: z11.string().min(1).max(120),
3486
+ name: z12.string().min(1).max(120),
3487
+ from_name: z12.string().min(1).max(120),
3261
3488
  from_email: Email,
3262
3489
  reply_to: Email.nullable(),
3263
3490
  policy: ProviderPolicy
3264
3491
  };
3265
- var Provider = z11.discriminatedUnion("kind", [
3266
- z11.object({
3492
+ var Provider = z12.discriminatedUnion("kind", [
3493
+ z12.object({
3267
3494
  id: Id,
3268
- kind: z11.literal("smtp"),
3495
+ kind: z12.literal("smtp"),
3269
3496
  config: SmtpConfigBase,
3270
- has_secret: z11.boolean(),
3497
+ has_secret: z12.boolean(),
3271
3498
  ...ProviderFields,
3272
3499
  rejections: ProviderRejections,
3273
3500
  created_at: Timestamp,
3274
3501
  updated_at: Timestamp
3275
3502
  }),
3276
- z11.object({
3503
+ z12.object({
3277
3504
  id: Id,
3278
- kind: z11.literal("resend"),
3505
+ kind: z12.literal("resend"),
3279
3506
  config: ResendConfigBase,
3280
- has_secret: z11.boolean(),
3507
+ has_secret: z12.boolean(),
3281
3508
  ...ProviderFields,
3282
3509
  rejections: ProviderRejections,
3283
3510
  events: ProviderEvents,
@@ -3285,31 +3512,31 @@ var Provider = z11.discriminatedUnion("kind", [
3285
3512
  updated_at: Timestamp
3286
3513
  })
3287
3514
  ]);
3288
- var ProviderCreate = z11.discriminatedUnion("kind", [
3289
- z11.object({
3290
- kind: z11.literal("smtp"),
3291
- config: SmtpConfigBase.extend({ password: z11.string().min(1).max(1024) }),
3515
+ var ProviderCreate = z12.discriminatedUnion("kind", [
3516
+ z12.object({
3517
+ kind: z12.literal("smtp"),
3518
+ config: SmtpConfigBase.extend({ password: z12.string().min(1).max(1024) }),
3292
3519
  ...ProviderFields
3293
3520
  }),
3294
- z11.object({
3295
- kind: z11.literal("resend"),
3296
- config: ResendConfigBase.extend({ api_key: z11.string().min(1).max(1024) }),
3521
+ z12.object({
3522
+ kind: z12.literal("resend"),
3523
+ config: ResendConfigBase.extend({ api_key: z12.string().min(1).max(1024) }),
3297
3524
  ...ProviderFields
3298
3525
  })
3299
3526
  ]);
3300
- var ProviderUpdate = z11.discriminatedUnion("kind", [
3301
- z11.object({
3302
- kind: z11.literal("smtp"),
3303
- config: SmtpConfigBase.extend({ password: z11.string().min(1).max(1024).optional() }).partial().optional(),
3527
+ var ProviderUpdate = z12.discriminatedUnion("kind", [
3528
+ z12.object({
3529
+ kind: z12.literal("smtp"),
3530
+ config: SmtpConfigBase.extend({ password: z12.string().min(1).max(1024).optional() }).partial().optional(),
3304
3531
  name: ProviderFields.name.optional(),
3305
3532
  from_name: ProviderFields.from_name.optional(),
3306
3533
  from_email: ProviderFields.from_email.optional(),
3307
3534
  reply_to: ProviderFields.reply_to.optional(),
3308
3535
  policy: ProviderPolicy.partial().optional()
3309
3536
  }),
3310
- z11.object({
3311
- kind: z11.literal("resend"),
3312
- config: ResendConfigBase.extend({ api_key: z11.string().min(1).max(1024).optional() }).optional(),
3537
+ z12.object({
3538
+ kind: z12.literal("resend"),
3539
+ config: ResendConfigBase.extend({ api_key: z12.string().min(1).max(1024).optional() }).optional(),
3313
3540
  name: ProviderFields.name.optional(),
3314
3541
  from_name: ProviderFields.from_name.optional(),
3315
3542
  from_email: ProviderFields.from_email.optional(),
@@ -3317,48 +3544,48 @@ var ProviderUpdate = z11.discriminatedUnion("kind", [
3317
3544
  policy: ProviderPolicy.partial().optional()
3318
3545
  })
3319
3546
  ]);
3320
- var ProviderUsage = z11.object({
3547
+ var ProviderUsage = z12.object({
3321
3548
  provider_id: Id,
3322
- recipients_last_24h: z11.number().int().min(0),
3323
- remaining_budget: z11.number().int().min(0),
3549
+ recipients_last_24h: z12.number().int().min(0),
3550
+ remaining_budget: z12.number().int().min(0),
3324
3551
  /** When enough of the rolling window frees up to send again, if exhausted. */
3325
3552
  next_capacity_at: Timestamp.nullable()
3326
3553
  });
3327
- var ProviderVerifyResult = z11.object({
3328
- ok: z11.boolean(),
3329
- error: z11.string().nullable()
3554
+ var ProviderVerifyResult = z12.object({
3555
+ ok: z12.boolean(),
3556
+ error: z12.string().nullable()
3330
3557
  });
3331
3558
 
3332
3559
  // src/contacts.ts
3333
- import { z as z12 } from "zod";
3334
- var Topic = z12.object({
3560
+ import { z as z13 } from "zod";
3561
+ var Topic = z13.object({
3335
3562
  id: Id,
3336
3563
  slug: Slug,
3337
- name: z12.string().min(1).max(120),
3564
+ name: z13.string().min(1).max(120),
3338
3565
  /** Shown on the hosted preference page. */
3339
- description: z12.string().max(1e3).nullable(),
3566
+ description: z13.string().max(1e3).nullable(),
3340
3567
  /** Translations of `name` and `description` per locale, for the hosted page. */
3341
- translations: z12.record(
3342
- z12.object({ name: z12.string().min(1).max(120), description: z12.string().max(1e3).nullable() })
3568
+ translations: z13.record(
3569
+ z13.object({ name: z13.string().min(1).max(120), description: z13.string().max(1e3).nullable() })
3343
3570
  ),
3344
3571
  created_at: Timestamp,
3345
3572
  updated_at: Timestamp
3346
3573
  });
3347
- var TopicCreate = z12.object({
3574
+ var TopicCreate = z13.object({
3348
3575
  slug: Slug,
3349
- name: z12.string().min(1).max(120),
3350
- description: z12.string().max(1e3).optional(),
3576
+ name: z13.string().min(1).max(120),
3577
+ description: z13.string().max(1e3).optional(),
3351
3578
  translations: Topic.shape.translations.optional()
3352
3579
  });
3353
3580
  var TopicUpdate = TopicCreate.omit({ slug: true }).partial().refine((v) => Object.keys(v).length > 0, "at least one field");
3354
- var Contact = z12.object({
3581
+ var Contact = z13.object({
3355
3582
  id: Id,
3356
- external_id: z12.string().min(1).max(255).nullable(),
3583
+ external_id: z13.string().min(1).max(255).nullable(),
3357
3584
  /** Stored lowercased, unique per workspace. */
3358
3585
  email: Email,
3359
- first_name: z12.string().max(200).nullable(),
3360
- last_name: z12.string().max(200).nullable(),
3361
- locale: z12.string().min(2).max(35).nullable(),
3586
+ first_name: z13.string().max(200).nullable(),
3587
+ last_name: z13.string().max(200).nullable(),
3588
+ locale: z13.string().min(2).max(35).nullable(),
3362
3589
  /**
3363
3590
  * The person's own time zone, an IANA name such as `Europe/Berlin` (A1).
3364
3591
  * Every wall clock an automation waits for is read in it, falling back to the
@@ -3366,65 +3593,65 @@ var Contact = z12.object({
3366
3593
  */
3367
3594
  timezone: TimezoneName.nullable(),
3368
3595
  properties: Properties,
3369
- topics: z12.array(Slug),
3596
+ topics: z13.array(Slug),
3370
3597
  /** The slugs of the contact's tags (S4). */
3371
- tags: z12.array(Slug),
3598
+ tags: z13.array(Slug),
3372
3599
  created_at: Timestamp,
3373
3600
  updated_at: Timestamp
3374
3601
  });
3375
- var ContactUpsert = z12.object({
3376
- external_id: z12.string().min(1).max(255).optional(),
3602
+ var ContactUpsert = z13.object({
3603
+ external_id: z13.string().min(1).max(255).optional(),
3377
3604
  email: Email.optional(),
3378
- first_name: z12.string().max(200).nullable().optional(),
3379
- last_name: z12.string().max(200).nullable().optional(),
3380
- locale: z12.string().min(2).max(35).nullable().optional(),
3605
+ first_name: z13.string().max(200).nullable().optional(),
3606
+ last_name: z13.string().max(200).nullable().optional(),
3607
+ locale: z13.string().min(2).max(35).nullable().optional(),
3381
3608
  timezone: TimezoneName.nullable().optional(),
3382
3609
  properties: Properties.optional(),
3383
- topics: z12.array(Slug).max(100).optional()
3610
+ topics: z13.array(Slug).max(100).optional()
3384
3611
  }).refine((v) => v.external_id !== void 0 || v.email !== void 0, {
3385
3612
  message: "external_id or email is required",
3386
3613
  path: ["email"]
3387
3614
  });
3388
- var ContactUpsertResult = z12.object({
3615
+ var ContactUpsertResult = z13.object({
3389
3616
  contact: Contact,
3390
- created: z12.boolean()
3617
+ created: z13.boolean()
3391
3618
  });
3392
3619
  var ContactListQuery = PageQuery.extend({
3393
- email: z12.string().min(1).max(254).optional(),
3394
- external_id: z12.string().min(1).max(255).optional(),
3620
+ email: z13.string().min(1).max(254).optional(),
3621
+ external_id: z13.string().min(1).max(255).optional(),
3395
3622
  topic: Slug.optional()
3396
3623
  });
3397
- var ContactErased = z12.object({
3398
- ok: z12.literal(true),
3399
- erased_messages: z12.number().int().min(0),
3400
- erased_recipients: z12.number().int().min(0),
3401
- suppressions_kept: z12.number().int().min(0)
3624
+ var ContactErased = z13.object({
3625
+ ok: z13.literal(true),
3626
+ erased_messages: z13.number().int().min(0),
3627
+ erased_recipients: z13.number().int().min(0),
3628
+ suppressions_kept: z13.number().int().min(0)
3402
3629
  });
3403
3630
  var SUPPRESSION_REASONS = ["unsubscribed", "bounced", "complained", "manual"];
3404
- var SuppressionReason = z12.enum(SUPPRESSION_REASONS);
3405
- var Suppression = z12.object({
3631
+ var SuppressionReason = z13.enum(SUPPRESSION_REASONS);
3632
+ var Suppression = z13.object({
3406
3633
  id: Id,
3407
3634
  email: Email,
3408
3635
  reason: SuppressionReason,
3409
3636
  topic: Slug.nullable(),
3410
3637
  source_message_id: Id.nullable(),
3411
- note: z12.string().max(1e3).nullable(),
3638
+ note: z13.string().max(1e3).nullable(),
3412
3639
  created_at: Timestamp
3413
3640
  });
3414
- var SuppressionCreate = z12.object({
3641
+ var SuppressionCreate = z13.object({
3415
3642
  email: Email,
3416
- reason: z12.enum(["manual", "unsubscribed"]),
3643
+ reason: z13.enum(["manual", "unsubscribed"]),
3417
3644
  topic: Slug.nullable().optional(),
3418
- note: z12.string().max(1e3).optional()
3645
+ note: z13.string().max(1e3).optional()
3419
3646
  });
3420
3647
  var SuppressionListQuery = PageQuery.extend({
3421
- email: z12.string().min(1).max(254).optional(),
3648
+ email: z13.string().min(1).max(254).optional(),
3422
3649
  reason: SuppressionReason.optional(),
3423
3650
  topic: Slug.optional()
3424
3651
  });
3425
3652
 
3426
3653
  // src/webhooks.ts
3427
- import { z as z13 } from "zod";
3654
+ import { z as z14 } from "zod";
3428
3655
  var WEBHOOK_EVENT_TYPES = [
3429
3656
  "message.sent",
3430
3657
  "message.failed",
@@ -3468,23 +3695,23 @@ var WEBHOOK_EVENT_TYPES = [
3468
3695
  "template.updated",
3469
3696
  "template.deleted"
3470
3697
  ];
3471
- var WebhookEventType = z13.enum(WEBHOOK_EVENT_TYPES);
3472
- var MessageEventBase = z13.object({
3698
+ var WebhookEventType = z14.enum(WEBHOOK_EVENT_TYPES);
3699
+ var MessageEventBase = z14.object({
3473
3700
  message_id: Id,
3474
3701
  mailing_id: Id.nullable(),
3475
3702
  mailing_metadata: MailingMetadata.nullable(),
3476
3703
  recipient_id: Id.nullable(),
3477
3704
  contact_id: Id.nullable(),
3478
- external_id: z13.string().nullable(),
3705
+ external_id: z14.string().nullable(),
3479
3706
  email: Email,
3480
- subject: z13.string(),
3707
+ subject: z14.string(),
3481
3708
  topic: Slug.nullable(),
3482
- provider_message_id: z13.string().nullable(),
3483
- is_test: z13.boolean()
3709
+ provider_message_id: z14.string().nullable(),
3710
+ is_test: z14.boolean()
3484
3711
  });
3485
3712
  var MessageSentData = MessageEventBase.extend({
3486
3713
  /** The final HTML as sent, so the client can archive it beside its own records. */
3487
- html: z13.string(),
3714
+ html: z14.string(),
3488
3715
  sent_at: Timestamp,
3489
3716
  /**
3490
3717
  * The choice each insertion made (see `Message.insertions`); absent or null
@@ -3495,20 +3722,20 @@ var MessageSentData = MessageEventBase.extend({
3495
3722
  insertions: InsertionChoices.nullish()
3496
3723
  });
3497
3724
  var MessageFailedData = MessageEventBase.extend({
3498
- error: z13.string(),
3725
+ error: z14.string(),
3499
3726
  /** False when the provider rejected permanently; the recipient will not be retried. */
3500
- retryable: z13.boolean(),
3727
+ retryable: z14.boolean(),
3501
3728
  failed_at: Timestamp
3502
3729
  });
3503
3730
  var UNSUBSCRIBE_SOURCES = ["hosted_page", "one_click", "api", "dashboard", "signup_form"];
3504
- var ContactUnsubscribedData = z13.object({
3731
+ var ContactUnsubscribedData = z14.object({
3505
3732
  contact_id: Id.nullable(),
3506
- external_id: z13.string().nullable(),
3733
+ external_id: z14.string().nullable(),
3507
3734
  email: Email,
3508
3735
  /** The topic unsubscribed from; null means every topic. */
3509
3736
  topic: Slug.nullable(),
3510
3737
  mailing_id: Id.nullable(),
3511
- source: z13.enum(UNSUBSCRIBE_SOURCES),
3738
+ source: z14.enum(UNSUBSCRIBE_SOURCES),
3512
3739
  unsubscribed_at: Timestamp
3513
3740
  });
3514
3741
  var ContactResubscribedData = ContactUnsubscribedData.omit({ unsubscribed_at: true }).extend({
@@ -3517,142 +3744,142 @@ var ContactResubscribedData = ContactUnsubscribedData.omit({ unsubscribed_at: tr
3517
3744
  * breaker undid a `bounced` block it judged false (a `contact.bounced` for the
3518
3745
  * same address and mailing went out before); `topic` is null.
3519
3746
  */
3520
- source: z13.enum([...UNSUBSCRIBE_SOURCES, "bounce_reverted"]),
3747
+ source: z14.enum([...UNSUBSCRIBE_SOURCES, "bounce_reverted"]),
3521
3748
  resubscribed_at: Timestamp
3522
3749
  });
3523
- var ContactBouncedData = z13.object({
3750
+ var ContactBouncedData = z14.object({
3524
3751
  contact_id: Id.nullable(),
3525
- external_id: z13.string().nullable(),
3752
+ external_id: z14.string().nullable(),
3526
3753
  email: Email,
3527
3754
  /** `bounced` for a hard bounce, `complained` for a spam complaint. */
3528
- reason: z13.enum(["bounced", "complained"]),
3755
+ reason: z14.enum(["bounced", "complained"]),
3529
3756
  message_id: Id.nullable(),
3530
- diagnostic: z13.string().nullable(),
3757
+ diagnostic: z14.string().nullable(),
3531
3758
  bounced_at: Timestamp
3532
3759
  });
3533
- var MailingFinishedData = z13.object({
3760
+ var MailingFinishedData = z14.object({
3534
3761
  mailing_id: Id,
3535
3762
  mailing_metadata: MailingMetadata,
3536
- status: z13.enum(["sent", "partially_failed", "cancelled"]),
3763
+ status: z14.enum(["sent", "partially_failed", "cancelled"]),
3537
3764
  counts: MailingCounts,
3538
3765
  finished_at: Timestamp
3539
3766
  });
3540
- var ContactSubscribedData = z13.object({
3767
+ var ContactSubscribedData = z14.object({
3541
3768
  contact_id: Id,
3542
- external_id: z13.string().nullable(),
3769
+ external_id: z14.string().nullable(),
3543
3770
  email: Email,
3544
- topics: z13.array(Slug),
3545
- source: z13.enum(["signup_form", "api", "dashboard", "automation"]),
3771
+ topics: z14.array(Slug),
3772
+ source: z14.enum(["signup_form", "api", "dashboard", "automation"]),
3546
3773
  signup_form_id: Id.nullable(),
3547
- signup_form_version: z13.number().int().min(1).nullable(),
3774
+ signup_form_version: z14.number().int().min(1).nullable(),
3548
3775
  subscribed_at: Timestamp
3549
3776
  });
3550
- var ImportFinishedData = z13.object({
3777
+ var ImportFinishedData = z14.object({
3551
3778
  import_id: Id,
3552
- status: z13.enum(["completed", "cancelled", "failed"]),
3779
+ status: z14.enum(["completed", "cancelled", "failed"]),
3553
3780
  result: ImportReport.nullable(),
3554
- error: z13.string().nullable(),
3781
+ error: z14.string().nullable(),
3555
3782
  finished_at: Timestamp
3556
3783
  });
3557
- var MailingScheduledData = z13.object({
3784
+ var MailingScheduledData = z14.object({
3558
3785
  mailing_id: Id,
3559
3786
  mailing_metadata: MailingMetadata,
3560
3787
  scheduled_at: Timestamp.nullable()
3561
3788
  });
3562
- var MailingStartedData = z13.object({
3789
+ var MailingStartedData = z14.object({
3563
3790
  mailing_id: Id,
3564
3791
  mailing_metadata: MailingMetadata,
3565
- trigger: z13.enum(["send", "schedule"]),
3566
- recipients: z13.number().int().min(0),
3792
+ trigger: z14.enum(["send", "schedule"]),
3793
+ recipients: z14.number().int().min(0),
3567
3794
  started_at: Timestamp
3568
3795
  });
3569
- var MailingScheduleFailedData = z13.object({
3796
+ var MailingScheduleFailedData = z14.object({
3570
3797
  mailing_id: Id,
3571
3798
  mailing_metadata: MailingMetadata,
3572
- code: z13.string(),
3573
- message: z13.string(),
3799
+ code: z14.string(),
3800
+ message: z14.string(),
3574
3801
  failed_at: Timestamp
3575
3802
  });
3576
- var MailingAbWinnerSelectedData = z13.object({
3803
+ var MailingAbWinnerSelectedData = z14.object({
3577
3804
  mailing_id: Id,
3578
3805
  mailing_metadata: MailingMetadata,
3579
- winner: z13.string(),
3580
- decided_by: z13.enum(["metric", "manual"]),
3581
- variants: z13.array(VariantAnalytics),
3806
+ winner: z14.string(),
3807
+ decided_by: z14.enum(["metric", "manual"]),
3808
+ variants: z14.array(VariantAnalytics),
3582
3809
  decided_at: Timestamp
3583
3810
  });
3584
- var ContactTaggedData = z13.object({
3811
+ var ContactTaggedData = z14.object({
3585
3812
  contact_id: Id,
3586
- external_id: z13.string().nullable(),
3813
+ external_id: z14.string().nullable(),
3587
3814
  email: Email,
3588
3815
  /** Only the tags the contact did not already have. */
3589
- tags: z13.array(Slug).min(1),
3590
- source: z13.enum(["api", "dashboard", "signup_form", "import", "automation"]),
3816
+ tags: z14.array(Slug).min(1),
3817
+ source: z14.enum(["api", "dashboard", "signup_form", "import", "automation"]),
3591
3818
  tagged_at: Timestamp
3592
3819
  });
3593
- var ContactUpdatedData = z13.object({
3820
+ var ContactUpdatedData = z14.object({
3594
3821
  contact_id: Id,
3595
- external_id: z13.string().nullable(),
3822
+ external_id: z14.string().nullable(),
3596
3823
  email: Email,
3597
- changed: z13.array(z13.string()).min(1),
3824
+ changed: z14.array(z14.string()).min(1),
3598
3825
  properties: Properties,
3599
- source: z13.enum(["api", "dashboard", "signup_form", "import", "automation"]),
3826
+ source: z14.enum(["api", "dashboard", "signup_form", "import", "automation"]),
3600
3827
  updated_at: Timestamp
3601
3828
  });
3602
- var AutomationRunEventBase = z13.object({
3829
+ var AutomationRunEventBase = z14.object({
3603
3830
  automation_id: Id,
3604
- automation_name: z13.string(),
3831
+ automation_name: z14.string(),
3605
3832
  run_id: Id,
3606
- version: z13.number().int().min(1),
3833
+ version: z14.number().int().min(1),
3607
3834
  contact_id: Id,
3608
- external_id: z13.string().nullable(),
3835
+ external_id: z14.string().nullable(),
3609
3836
  email: Email
3610
3837
  });
3611
3838
  var AutomationRunStartedData = AutomationRunEventBase.extend({
3612
3839
  /** What let them in: a trigger kind, or `manual` for an explicit enrolment. */
3613
- trigger_kind: z13.string(),
3840
+ trigger_kind: z14.string(),
3614
3841
  entered_at: Timestamp
3615
3842
  });
3616
3843
  var AutomationRunCompletedData = AutomationRunEventBase.extend({
3617
- last_step_id: z13.string().nullable(),
3844
+ last_step_id: z14.string().nullable(),
3618
3845
  completed_at: Timestamp
3619
3846
  });
3620
3847
  var AutomationRunExitedData = AutomationRunEventBase.extend({
3621
3848
  reason: AutomationEndReason,
3622
- step_id: z13.string().nullable(),
3849
+ step_id: z14.string().nullable(),
3623
3850
  exited_at: Timestamp
3624
3851
  });
3625
3852
  var AutomationRunFailedData = AutomationRunEventBase.extend({
3626
- reason: z13.string(),
3627
- step_id: z13.string().nullable(),
3853
+ reason: z14.string(),
3854
+ step_id: z14.string().nullable(),
3628
3855
  failed_at: Timestamp
3629
3856
  });
3630
3857
  var AutomationWebhookData = AutomationRunEventBase.extend({
3631
- step_id: z13.string(),
3858
+ step_id: z14.string(),
3632
3859
  /** The step's own label, when it was given one, so a receiver can branch on a name. */
3633
- step_label: z13.string().nullable(),
3860
+ step_label: z14.string().nullable(),
3634
3861
  /** Whatever the step carries, verbatim. Null when it carries nothing. */
3635
3862
  payload: JsonValue.nullable(),
3636
3863
  fired_at: Timestamp
3637
3864
  });
3638
- var TemplateEventBase = z13.object({
3865
+ var TemplateEventBase = z14.object({
3639
3866
  template_id: Id,
3640
- name: z13.string().min(1).max(200),
3641
- version: z13.number().int().min(1),
3642
- source: z13.enum(["api", "dashboard", "mjml_import"])
3867
+ name: z14.string().min(1).max(200),
3868
+ version: z14.number().int().min(1),
3869
+ source: z14.enum(["api", "dashboard", "mjml_import"])
3643
3870
  });
3644
3871
  var TemplateCreatedData = TemplateEventBase.extend({ created_at: Timestamp });
3645
- var TemplateUpdatedData = TemplateEventBase.extend({ archived: z13.boolean(), updated_at: Timestamp });
3872
+ var TemplateUpdatedData = TemplateEventBase.extend({ archived: z14.boolean(), updated_at: Timestamp });
3646
3873
  var TemplateDeletedData = TemplateEventBase.extend({ deleted_at: Timestamp });
3647
- var envelope = (type, data) => z13.object({
3874
+ var envelope = (type, data) => z14.object({
3648
3875
  /** Unique per event: a receiver deduplicates on it (deliveries may repeat). */
3649
3876
  id: Id,
3650
- type: z13.literal(type),
3877
+ type: z14.literal(type),
3651
3878
  created_at: Timestamp,
3652
3879
  workspace_id: Id,
3653
3880
  data
3654
3881
  });
3655
- var WebhookEvent = z13.discriminatedUnion("type", [
3882
+ var WebhookEvent = z14.discriminatedUnion("type", [
3656
3883
  envelope("message.sent", MessageSentData),
3657
3884
  envelope("message.failed", MessageFailedData),
3658
3885
  envelope("contact.unsubscribed", ContactUnsubscribedData),
@@ -3676,16 +3903,16 @@ var WebhookEvent = z13.discriminatedUnion("type", [
3676
3903
  envelope("template.updated", TemplateUpdatedData),
3677
3904
  envelope("template.deleted", TemplateDeletedData)
3678
3905
  ]);
3679
- var WebhookEndpoint = z13.object({
3906
+ var WebhookEndpoint = z14.object({
3680
3907
  id: Id,
3681
- url: z13.string().url(),
3682
- description: z13.string().max(500).nullable(),
3683
- events: z13.array(WebhookEventType).min(1),
3684
- enabled: z13.boolean(),
3908
+ url: z14.string().url(),
3909
+ description: z14.string().max(500).nullable(),
3910
+ events: z14.array(WebhookEventType).min(1),
3911
+ enabled: z14.boolean(),
3685
3912
  created_at: Timestamp,
3686
3913
  updated_at: Timestamp
3687
3914
  });
3688
- var WebhookUrl = z13.string().url().refine((u) => {
3915
+ var WebhookUrl = z14.string().url().refine((u) => {
3689
3916
  try {
3690
3917
  const url = new URL(u);
3691
3918
  if (url.protocol === "https:") return true;
@@ -3694,35 +3921,35 @@ var WebhookUrl = z13.string().url().refine((u) => {
3694
3921
  return false;
3695
3922
  }
3696
3923
  }, "must be https (http only for localhost)");
3697
- var WebhookEndpointCreate = z13.object({
3924
+ var WebhookEndpointCreate = z14.object({
3698
3925
  url: WebhookUrl,
3699
- description: z13.string().max(500).optional(),
3700
- events: z13.array(WebhookEventType).min(1),
3701
- enabled: z13.boolean().optional()
3926
+ description: z14.string().max(500).optional(),
3927
+ events: z14.array(WebhookEventType).min(1),
3928
+ enabled: z14.boolean().optional()
3702
3929
  });
3703
- var WebhookEndpointUpdate = z13.object({
3930
+ var WebhookEndpointUpdate = z14.object({
3704
3931
  url: WebhookUrl,
3705
- description: z13.string().max(500).nullable(),
3706
- events: z13.array(WebhookEventType).min(1),
3707
- enabled: z13.boolean()
3932
+ description: z14.string().max(500).nullable(),
3933
+ events: z14.array(WebhookEventType).min(1),
3934
+ enabled: z14.boolean()
3708
3935
  }).partial().refine((v) => Object.keys(v).length > 0, "at least one field");
3709
- var WebhookEndpointWithSecret = z13.object({
3936
+ var WebhookEndpointWithSecret = z14.object({
3710
3937
  endpoint: WebhookEndpoint,
3711
- secret: z13.string().min(32)
3938
+ secret: z14.string().min(32)
3712
3939
  });
3713
3940
  var WEBHOOK_DELIVERY_STATUSES = ["pending", "succeeded", "failed"];
3714
- var WebhookDeliveryStatus = z13.enum(WEBHOOK_DELIVERY_STATUSES);
3941
+ var WebhookDeliveryStatus = z14.enum(WEBHOOK_DELIVERY_STATUSES);
3715
3942
  var WEBHOOK_MAX_ATTEMPTS = 8;
3716
3943
  var WEBHOOK_RETRY_DELAYS_SECONDS = [30, 120, 600, 1800, 3600, 7200, 21600];
3717
- var WebhookDelivery = z13.object({
3944
+ var WebhookDelivery = z14.object({
3718
3945
  id: Id,
3719
3946
  endpoint_id: Id,
3720
3947
  event_id: Id,
3721
3948
  event_type: WebhookEventType,
3722
3949
  status: WebhookDeliveryStatus,
3723
- attempts: z13.number().int().min(0),
3724
- last_status_code: z13.number().int().min(100).max(599).nullable(),
3725
- last_error: z13.string().nullable(),
3950
+ attempts: z14.number().int().min(0),
3951
+ last_status_code: z14.number().int().min(100).max(599).nullable(),
3952
+ last_error: z14.string().nullable(),
3726
3953
  next_attempt_at: Timestamp.nullable(),
3727
3954
  delivered_at: Timestamp.nullable(),
3728
3955
  created_at: Timestamp
@@ -3731,7 +3958,7 @@ var WebhookDeliveryListQuery = PageQuery.extend({
3731
3958
  status: WebhookDeliveryStatus.optional(),
3732
3959
  event_type: WebhookEventType.optional()
3733
3960
  });
3734
- var WebhookDeliveryParams = z13.object({ id: Id, delivery_id: Id });
3961
+ var WebhookDeliveryParams = z14.object({ id: Id, delivery_id: Id });
3735
3962
 
3736
3963
  // src/webhook-signing.ts
3737
3964
  var WEBHOOK_SIGNATURE_HEADER = "x-mail-signature";
@@ -3798,79 +4025,79 @@ async function verifyWebhook(input) {
3798
4025
  }
3799
4026
 
3800
4027
  // src/billing.ts
3801
- import { z as z14 } from "zod";
4028
+ import { z as z15 } from "zod";
3802
4029
  var PLAN_IDS = ["free", "starter", "growth", "design_partner"];
3803
- var PlanId = z14.enum(PLAN_IDS);
3804
- var PlanLimits = z14.object({
3805
- monthly_messages: z14.number().int().min(0).nullable(),
3806
- contacts: z14.number().int().min(0).nullable(),
3807
- members: z14.number().int().min(1).nullable(),
3808
- providers: z14.number().int().min(1).nullable(),
3809
- webhook_endpoints: z14.number().int().min(0).nullable(),
4030
+ var PlanId = z15.enum(PLAN_IDS);
4031
+ var PlanLimits = z15.object({
4032
+ monthly_messages: z15.number().int().min(0).nullable(),
4033
+ contacts: z15.number().int().min(0).nullable(),
4034
+ members: z15.number().int().min(1).nullable(),
4035
+ providers: z15.number().int().min(1).nullable(),
4036
+ webhook_endpoints: z15.number().int().min(0).nullable(),
3810
4037
  /** Automations that may be live (active or paused) at once (A1). */
3811
- active_automations: z14.number().int().min(0).nullable(),
4038
+ active_automations: z15.number().int().min(0).nullable(),
3812
4039
  /** Steps one automation may hold. Null is the flow's own cap, not unlimited. */
3813
- automation_steps: z14.number().int().min(1).nullable()
4040
+ automation_steps: z15.number().int().min(1).nullable()
3814
4041
  });
3815
- var PlanFeatures = z14.object({
4042
+ var PlanFeatures = z15.object({
3816
4043
  /** A/B tests of subject and content on a mailing (S4). */
3817
- ab_testing: z14.boolean(),
4044
+ ab_testing: z15.boolean(),
3818
4045
  /** Open and click tracking, still off until a workspace turns it on (`settings.tracking_enabled`). */
3819
- tracking: z14.boolean(),
4046
+ tracking: z15.boolean(),
3820
4047
  /** Sending and hosting pages on the workspace's own domain (a later phase). */
3821
- custom_domains: z14.boolean(),
4048
+ custom_domains: z15.boolean(),
3822
4049
  /** Automations: flows a person walks through step by step (A1). */
3823
- automations: z14.boolean()
4050
+ automations: z15.boolean()
3824
4051
  });
3825
4052
  var PLAN_FEATURES = ["ab_testing", "tracking", "custom_domains", "automations"];
3826
- var Plan = z14.object({
4053
+ var Plan = z15.object({
3827
4054
  id: PlanId,
3828
- name: z14.string().min(1),
4055
+ name: z15.string().min(1),
3829
4056
  /** Price in the smallest currency unit per month; null for plans not sold. */
3830
- monthly_price_cents: z14.number().int().min(0).nullable(),
3831
- currency: z14.string().length(3),
4057
+ monthly_price_cents: z15.number().int().min(0).nullable(),
4058
+ currency: z15.string().length(3),
3832
4059
  limits: PlanLimits,
3833
4060
  features: PlanFeatures
3834
4061
  });
3835
- var CatalogPlan = Plan.extend({ sellable: z14.boolean() });
3836
- var Subscription = z14.object({
4062
+ var CatalogPlan = Plan.extend({ sellable: z15.boolean() });
4063
+ var Subscription = z15.object({
3837
4064
  workspace_id: Id,
3838
4065
  plan: PlanId,
3839
- status: z14.enum(["active", "trialing", "past_due", "cancelled"]),
4066
+ status: z15.enum(["active", "trialing", "past_due", "cancelled"]),
3840
4067
  current_period_start: Timestamp,
3841
4068
  current_period_end: Timestamp,
3842
- cancel_at_period_end: z14.boolean(),
4069
+ cancel_at_period_end: z15.boolean(),
3843
4070
  /**
3844
4071
  * A design partner outside billing (plan `design_partner`, no limits, no
3845
4072
  * checkout). Set only by an operator, never through the API.
3846
4073
  */
3847
- billing_exempt: z14.boolean()
4074
+ billing_exempt: z15.boolean()
3848
4075
  });
3849
4076
  var USAGE_METRICS = ["messages", "contacts", "members", "providers", "webhook_endpoints", "active_automations"];
3850
- var UsageMetric = z14.enum(USAGE_METRICS);
4077
+ var UsageMetric = z15.enum(USAGE_METRICS);
3851
4078
  var USAGE_WARNING_RATIO = 0.8;
3852
- var UsageWarning = z14.object({
4079
+ var UsageWarning = z15.object({
3853
4080
  metric: UsageMetric,
3854
- used: z14.number().int().min(0),
3855
- limit: z14.number().int().min(0),
4081
+ used: z15.number().int().min(0),
4082
+ limit: z15.number().int().min(0),
3856
4083
  /** `approaching`: at or above USAGE_WARNING_RATIO of the limit; `reached`: at or above the limit. */
3857
- level: z14.enum(["approaching", "reached"])
4084
+ level: z15.enum(["approaching", "reached"])
3858
4085
  });
3859
- var Usage = z14.object({
4086
+ var Usage = z15.object({
3860
4087
  plan: PlanId,
3861
4088
  period_start: Timestamp,
3862
4089
  period_end: Timestamp,
3863
- metrics: z14.record(UsageMetric, z14.object({ used: z14.number().int().min(0), limit: z14.number().int().min(0).nullable() })),
3864
- warnings: z14.array(UsageWarning)
4090
+ metrics: z15.record(UsageMetric, z15.object({ used: z15.number().int().min(0), limit: z15.number().int().min(0).nullable() })),
4091
+ warnings: z15.array(UsageWarning)
3865
4092
  });
3866
- var CheckoutRequest = z14.object({
3867
- plan: z14.enum(["starter", "growth"]),
3868
- success_url: z14.string().url(),
3869
- cancel_url: z14.string().url()
4093
+ var CheckoutRequest = z15.object({
4094
+ plan: z15.enum(["starter", "growth"]),
4095
+ success_url: z15.string().url(),
4096
+ cancel_url: z15.string().url()
3870
4097
  });
3871
- var CheckoutSession = z14.object({ url: z14.string().url() });
3872
- var PortalRequest = z14.object({ return_url: z14.string().url() });
3873
- var PortalSession = z14.object({ url: z14.string().url() });
4098
+ var CheckoutSession = z15.object({ url: z15.string().url() });
4099
+ var PortalRequest = z15.object({ return_url: z15.string().url() });
4100
+ var PortalSession = z15.object({ url: z15.string().url() });
3874
4101
  var USAGE_WARNING_HEADER = "x-mail-usage-warning";
3875
4102
  function formatUsageWarningHeader(warnings) {
3876
4103
  if (warnings.length === 0) return null;
@@ -3890,7 +4117,7 @@ function parseUsageWarningHeader(value) {
3890
4117
  }
3891
4118
 
3892
4119
  // src/routes.ts
3893
- import { z as z15 } from "zod";
4120
+ import { z as z16 } from "zod";
3894
4121
  var list = (item) => page(item);
3895
4122
  var foundationRoutes = {
3896
4123
  "workspaces.create": {
@@ -4047,6 +4274,25 @@ var templateRoutes = {
4047
4274
  access: "write",
4048
4275
  phase: "S1"
4049
4276
  },
4277
+ /**
4278
+ * The sending app declares what the template receives (see
4279
+ * `template-inputs.ts`). Replaces the stored declaration whole; the same
4280
+ * declaration again is a no-op (`changed: false`). Creates no template
4281
+ * version and takes no `base_version`, so it never conflicts with an edit.
4282
+ * An API key only (`send` or `full`): the declaration is the app's statement
4283
+ * about its own code, so a dashboard member is refused with `forbidden`, a
4284
+ * rule the access levels cannot express and the service enforces itself.
4285
+ */
4286
+ "templates.declareInputs": {
4287
+ method: "PUT",
4288
+ path: "/v1/templates/:id/inputs",
4289
+ params: IdParams,
4290
+ body: TemplateInputsDeclaration,
4291
+ response: TemplateInputsDeclared,
4292
+ status: 200,
4293
+ access: "write",
4294
+ phase: "S1"
4295
+ },
4050
4296
  "templates.delete": {
4051
4297
  method: "DELETE",
4052
4298
  path: "/v1/templates/:id",
@@ -4098,7 +4344,7 @@ var templateRoutes = {
4098
4344
  path: "/v1/templates/:id/export",
4099
4345
  params: IdParams,
4100
4346
  query: TemplateExportQuery,
4101
- response: z15.string(),
4347
+ response: z16.string(),
4102
4348
  responseType: "text",
4103
4349
  status: 200,
4104
4350
  access: "read",
@@ -4422,7 +4668,7 @@ var sendingRoutes = {
4422
4668
  path: "/v1/mailings/:id/export",
4423
4669
  params: IdParams,
4424
4670
  query: MailingExportQuery,
4425
- response: z15.string(),
4671
+ response: z16.string(),
4426
4672
  responseType: "text",
4427
4673
  status: 200,
4428
4674
  access: "read",
@@ -4655,7 +4901,7 @@ var platformRoutes = {
4655
4901
  "contactProperties.list": {
4656
4902
  method: "GET",
4657
4903
  path: "/v1/contact-properties",
4658
- response: z15.object({ data: z15.array(ContactPropertyDefinition) }),
4904
+ response: z16.object({ data: z16.array(ContactPropertyDefinition) }),
4659
4905
  status: 200,
4660
4906
  access: "read",
4661
4907
  phase: "S4"
@@ -4954,7 +5200,7 @@ var billingRoutes = {
4954
5200
  "billing.plans": {
4955
5201
  method: "GET",
4956
5202
  path: "/v1/billing/plans",
4957
- response: z15.object({ data: z15.array(CatalogPlan) }),
5203
+ response: z16.object({ data: z16.array(CatalogPlan) }),
4958
5204
  status: 200,
4959
5205
  access: "read",
4960
5206
  phase: "S5"
@@ -5096,7 +5342,7 @@ var automationRoutes = {
5096
5342
  method: "POST",
5097
5343
  path: "/v1/automations/:id/pause",
5098
5344
  params: IdParams,
5099
- body: z15.object({}).strict(),
5345
+ body: z16.object({}).strict(),
5100
5346
  response: Automation,
5101
5347
  status: 200,
5102
5348
  access: "write",
@@ -5106,7 +5352,7 @@ var automationRoutes = {
5106
5352
  method: "POST",
5107
5353
  path: "/v1/automations/:id/resume",
5108
5354
  params: IdParams,
5109
- body: z15.object({}).strict(),
5355
+ body: z16.object({}).strict(),
5110
5356
  response: Automation,
5111
5357
  status: 200,
5112
5358
  access: "write",
@@ -5116,7 +5362,7 @@ var automationRoutes = {
5116
5362
  method: "POST",
5117
5363
  path: "/v1/automations/:id/archive",
5118
5364
  params: IdParams,
5119
- body: z15.object({}).strict(),
5365
+ body: z16.object({}).strict(),
5120
5366
  response: Automation,
5121
5367
  status: 200,
5122
5368
  access: "write",
@@ -5495,6 +5741,13 @@ export {
5495
5741
  MAX_STEPS,
5496
5742
  MAX_STEP_VISITS,
5497
5743
  MAX_SUBJECT_LENGTH,
5744
+ MAX_TEMPLATE_INPUTS,
5745
+ MAX_TEMPLATE_INPUTS_APP_LENGTH,
5746
+ MAX_TEMPLATE_INPUTS_SEEN,
5747
+ MAX_TEMPLATE_INPUT_EXAMPLE_LENGTH,
5748
+ MAX_TEMPLATE_INPUT_LABEL_LENGTH,
5749
+ MAX_TEMPLATE_INPUT_NOTE_LENGTH,
5750
+ MAX_TEMPLATE_INPUT_VALUES,
5498
5751
  MAX_TEMPLATE_TRANSLATIONS,
5499
5752
  MAX_TRIGGERS,
5500
5753
  MEMBER_ROLES,
@@ -5589,6 +5842,7 @@ export {
5589
5842
  RecipientStatus,
5590
5843
  RemoteImage,
5591
5844
  ResendSigningSecret,
5845
+ SERVICE_FILLED_MERGE_FIELDS,
5592
5846
  SIGNUP_FORM_FIELDS,
5593
5847
  SKIP_REASONS,
5594
5848
  SMTP_SECURITY,
@@ -5618,6 +5872,8 @@ export {
5618
5872
  SuppressionCreate,
5619
5873
  SuppressionListQuery,
5620
5874
  SuppressionReason,
5875
+ TEMPLATE_INPUT_KINDS,
5876
+ TEMPLATE_INPUT_PROBLEM_REASONS,
5621
5877
  TEMPLATE_LANGUAGE_STATUSES,
5622
5878
  TERMINAL_MAILING_STATUSES,
5623
5879
  Tag,
@@ -5634,6 +5890,16 @@ export {
5634
5890
  TemplateImportPreview,
5635
5891
  TemplateImportPreviewRequest,
5636
5892
  TemplateImportResult,
5893
+ TemplateInput,
5894
+ TemplateInputMap,
5895
+ TemplateInputName,
5896
+ TemplateInputSeen,
5897
+ TemplateInputSource,
5898
+ TemplateInputValue,
5899
+ TemplateInputs,
5900
+ TemplateInputsDeclaration,
5901
+ TemplateInputsDeclared,
5902
+ TemplateInputsSeen,
5637
5903
  TemplateLanguageStatus,
5638
5904
  TemplateListQuery,
5639
5905
  TemplatePreheader,
@@ -5787,6 +6053,10 @@ export {
5787
6053
  renameInsertionChecked,
5788
6054
  renameInsertionChoice,
5789
6055
  renameInsertionChoiceChecked,
6056
+ renameInsertionEverywhere,
6057
+ renameInsertionPlacements,
6058
+ renameTokenInDocument,
6059
+ renameTokenInText,
5790
6060
  resolveInsertions,
5791
6061
  restorePatch,
5792
6062
  routes,
@@ -5802,6 +6072,8 @@ export {
5802
6072
  stepTargets,
5803
6073
  storedTemplateLine,
5804
6074
  stronglyConnected,
6075
+ templateInputDrift,
6076
+ templateInputProblems,
5805
6077
  templateRoutes,
5806
6078
  testGroupSize,
5807
6079
  tightLoops,
@@ -5809,6 +6081,7 @@ export {
5809
6081
  translationInsertionProblems,
5810
6082
  translationTextFromInput,
5811
6083
  triggerKey,
6084
+ unknownRefusedInsertions,
5812
6085
  unplacedInsertions,
5813
6086
  validateAutomation,
5814
6087
  verifyWebhook