evo360-types 1.3.472 → 1.3.476

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.
@@ -28,11 +28,16 @@ exports.zCampaignTypeSchema = zod_1.z.enum([
28
28
  "promotional",
29
29
  ]);
30
30
  exports.zCampaignChannelSchema = zod_1.z.enum(["whatsapp", "email"]);
31
+ /** ADDITIVE ONLY — mirrors CampaignVariableSource in types/evo-campaigns/index.ts.
32
+ * This list is SEPARATE from the TS union; dropping a value here rejects channel
33
+ * configs already persisted in Firestore. */
31
34
  exports.zCampaignVariableSourceSchema = zod_1.z.enum([
32
35
  "placeholder",
33
36
  "fixed",
34
37
  "csv_column",
35
38
  "qr_link",
39
+ // E-MAIL ONLY (F3.2): resolves to channels.email.media.url.
40
+ "campaign_media",
36
41
  ]);
37
42
  /** ADDITIVE ONLY. The FE parses every recipient through this enum; a value written
38
43
  * to Firestore but missing here makes it drop the WHOLE recipient document. */
@@ -31,11 +31,16 @@ export const zCampaignTypeSchema = z.enum([
31
31
 
32
32
  export const zCampaignChannelSchema = z.enum(["whatsapp", "email"]);
33
33
 
34
+ /** ADDITIVE ONLY — mirrors CampaignVariableSource in types/evo-campaigns/index.ts.
35
+ * This list is SEPARATE from the TS union; dropping a value here rejects channel
36
+ * configs already persisted in Firestore. */
34
37
  export const zCampaignVariableSourceSchema = z.enum([
35
38
  "placeholder",
36
39
  "fixed",
37
40
  "csv_column",
38
41
  "qr_link",
42
+ // E-MAIL ONLY (F3.2): resolves to channels.email.media.url.
43
+ "campaign_media",
39
44
  ]);
40
45
 
41
46
  /** ADDITIVE ONLY. The FE parses every recipient through this enum; a value written
@@ -26,7 +26,7 @@ export type CampaignType = "conversion" | "informative" | "relationship" | "oper
26
26
  /** Delivery channel of a campaign. */
27
27
  export type CampaignChannel = "whatsapp" | "email";
28
28
  /** Where a template variable gets its value from at send time. */
29
- export type CampaignVariableSource = "placeholder" | "fixed" | "csv_column" | "qr_link";
29
+ export type CampaignVariableSource = "placeholder" | "fixed" | "csv_column" | "qr_link" | "campaign_media";
30
30
  export interface ICampaignVariableMapping {
31
31
  /** Template variable name/index this mapping fills. */
32
32
  variable: string;
@@ -76,10 +76,19 @@ export interface ICampaignTicketPolicy {
76
76
  note?: string;
77
77
  }
78
78
  export interface ICampaignMedia {
79
- /** 'image' | 'video' | 'document' — WhatsApp header media type. */
79
+ /** 'image' | 'video' | 'document' — WhatsApp header media type; always 'image' on e-mail. */
80
80
  type: string;
81
- /** Full gs:// URI in WABA_MEDIA_BUCKET under tenants/<tenant>/ (feat-082/084 flow). */
81
+ /**
82
+ * Full gs:// URI of the stored object.
83
+ * WhatsApp: WABA_MEDIA_BUCKET (private) under tenants/<tenant>/ (feat-082/084 flow).
84
+ * E-mail: the PUBLIC bucket (F3.2) — an e-mail client fetches the image
85
+ * unauthenticated, so a private object or a signed URL cannot work.
86
+ */
82
87
  gcs_path?: string;
88
+ /**
89
+ * Public https URL of the object. E-mail REQUIRES it (it is what goes in the
90
+ * <img src>); on WhatsApp it is optional (`gcs_path` wins at send time).
91
+ */
83
92
  url?: string;
84
93
  /** Mime type of the uploaded media (drives the header component). */
85
94
  mime_type?: string | null;
@@ -96,7 +105,11 @@ export interface ICampaignChannelConfig {
96
105
  /** WhatsApp: template category from introspection (MARKETING/UTILITY/AUTHENTICATION). */
97
106
  template_category?: string;
98
107
  variable_mappings: ICampaignVariableMapping[];
99
- /** WhatsApp header media (when the template requires it). */
108
+ /**
109
+ * WhatsApp: the template's header media (when the template requires it).
110
+ * E-mail: the campaign's image, reachable from the HTML through a
111
+ * `campaign_media` variable mapping (F3.2). PUBLICLY READABLE — never a patient asset.
112
+ */
100
113
  media?: ICampaignMedia;
101
114
  ctas: ICampaignCta[];
102
115
  /** Outbound department for the resulting ticket. */
@@ -350,6 +363,14 @@ export interface ICampaignRecipientChannelState {
350
363
  delivered_at?: Date | null;
351
364
  read_at?: Date | null;
352
365
  clicked_at?: Date | null;
366
+ /**
367
+ * CTA that produced `clicked_at` (F3.2). The click consumer already carried the
368
+ * `cta_id` to BigQuery but dropped it from the doc, so a conversion could only be
369
+ * written with `cta_id: null` and no report could answer WHICH call to action
370
+ * converted. Stamped in the same transaction as `clicked_at`, sharing that
371
+ * milestone's idempotency: the FIRST click wins, later ones never overwrite it.
372
+ */
373
+ clicked_cta_id?: string | null;
353
374
  replied_at?: Date | null;
354
375
  /** Milestone stamp of a provider failure. Completes the six — `failed` was the one
355
376
  * milestone without a timestamp, so its consumer had to key idempotency off
@@ -375,6 +396,15 @@ export type CampaignExclusionReason =
375
396
  | "frequency_check_unavailable"
376
397
  /** No identifier for this channel (no mobile / no e-mail). */
377
398
  | "no_channel"
399
+ /**
400
+ * There IS an identifier for this channel, but it cannot be delivered to — a phone
401
+ * that is not a valid E.164 number, an address that is not an e-mail (F3.2). Before
402
+ * this existed, eligibility was decided by `!!mobile` / `!!email`, so a malformed
403
+ * value counted as ELIGIBLE, burned a send and failed at the provider. Distinct from
404
+ * `no_channel` on purpose: "fix this contact's data" and "this contact has no such
405
+ * channel" are different instructions for whoever reads the audience.
406
+ */
407
+ | "invalid"
378
408
  /** Removed by hand from the audience — always the value under the `manual` key. */
379
409
  | "manual_removed";
380
410
  export interface ICampaignRecipientEligibility {
@@ -74,7 +74,8 @@ export type CampaignVariableSource =
74
74
  | "placeholder" // resolved by the placeholder engine (feat-055) via `token`
75
75
  | "fixed" // literal `value`
76
76
  | "csv_column" // pulled from the recipient's csv_variables by `column`
77
- | "qr_link"; // a quick-reply /qr link for `cta_id`
77
+ | "qr_link" // a quick-reply /qr link for `cta_id`
78
+ | "campaign_media"; // E-MAIL ONLY: the public URL of `channels.email.media` (F3.2)
78
79
 
79
80
  export interface ICampaignVariableMapping {
80
81
  /** Template variable name/index this mapping fills. */
@@ -88,6 +89,8 @@ export interface ICampaignVariableMapping {
88
89
  column?: string;
89
90
  /** source='qr_link': the CTA whose /qr link is injected. */
90
91
  cta_id?: string;
92
+ // source='campaign_media' carries no extra field: it resolves to
93
+ // `channels.email.media.url` of the campaign it belongs to.
91
94
  }
92
95
 
93
96
  export interface ICampaignCta {
@@ -132,10 +135,19 @@ export interface ICampaignTicketPolicy {
132
135
  }
133
136
 
134
137
  export interface ICampaignMedia {
135
- /** 'image' | 'video' | 'document' — WhatsApp header media type. */
138
+ /** 'image' | 'video' | 'document' — WhatsApp header media type; always 'image' on e-mail. */
136
139
  type: string;
137
- /** Full gs:// URI in WABA_MEDIA_BUCKET under tenants/<tenant>/ (feat-082/084 flow). */
140
+ /**
141
+ * Full gs:// URI of the stored object.
142
+ * WhatsApp: WABA_MEDIA_BUCKET (private) under tenants/<tenant>/ (feat-082/084 flow).
143
+ * E-mail: the PUBLIC bucket (F3.2) — an e-mail client fetches the image
144
+ * unauthenticated, so a private object or a signed URL cannot work.
145
+ */
138
146
  gcs_path?: string;
147
+ /**
148
+ * Public https URL of the object. E-mail REQUIRES it (it is what goes in the
149
+ * <img src>); on WhatsApp it is optional (`gcs_path` wins at send time).
150
+ */
139
151
  url?: string;
140
152
  /** Mime type of the uploaded media (drives the header component). */
141
153
  mime_type?: string | null;
@@ -155,7 +167,11 @@ export interface ICampaignChannelConfig {
155
167
  /** WhatsApp: template category from introspection (MARKETING/UTILITY/AUTHENTICATION). */
156
168
  template_category?: string;
157
169
  variable_mappings: ICampaignVariableMapping[];
158
- /** WhatsApp header media (when the template requires it). */
170
+ /**
171
+ * WhatsApp: the template's header media (when the template requires it).
172
+ * E-mail: the campaign's image, reachable from the HTML through a
173
+ * `campaign_media` variable mapping (F3.2). PUBLICLY READABLE — never a patient asset.
174
+ */
159
175
  media?: ICampaignMedia;
160
176
  ctas: ICampaignCta[];
161
177
  /** Outbound department for the resulting ticket. */
@@ -479,6 +495,14 @@ export interface ICampaignRecipientChannelState {
479
495
  delivered_at?: Date | null;
480
496
  read_at?: Date | null;
481
497
  clicked_at?: Date | null;
498
+ /**
499
+ * CTA that produced `clicked_at` (F3.2). The click consumer already carried the
500
+ * `cta_id` to BigQuery but dropped it from the doc, so a conversion could only be
501
+ * written with `cta_id: null` and no report could answer WHICH call to action
502
+ * converted. Stamped in the same transaction as `clicked_at`, sharing that
503
+ * milestone's idempotency: the FIRST click wins, later ones never overwrite it.
504
+ */
505
+ clicked_cta_id?: string | null;
482
506
  replied_at?: Date | null;
483
507
  /** Milestone stamp of a provider failure. Completes the six — `failed` was the one
484
508
  * milestone without a timestamp, so its consumer had to key idempotency off
@@ -505,6 +529,15 @@ export type CampaignExclusionReason =
505
529
  | "frequency_check_unavailable"
506
530
  /** No identifier for this channel (no mobile / no e-mail). */
507
531
  | "no_channel"
532
+ /**
533
+ * There IS an identifier for this channel, but it cannot be delivered to — a phone
534
+ * that is not a valid E.164 number, an address that is not an e-mail (F3.2). Before
535
+ * this existed, eligibility was decided by `!!mobile` / `!!email`, so a malformed
536
+ * value counted as ELIGIBLE, burned a send and failed at the provider. Distinct from
537
+ * `no_channel` on purpose: "fix this contact's data" and "this contact has no such
538
+ * channel" are different instructions for whoever reads the audience.
539
+ */
540
+ | "invalid"
508
541
  /** Removed by hand from the audience — always the value under the `manual` key. */
509
542
  | "manual_removed";
510
543
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "evo360-types",
3
- "version": "1.3.472",
3
+ "version": "1.3.476",
4
4
  "description": "HREVO360 Shared Types",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",