@aranova/tracking-react 1.17.0 → 1.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/sales.mjs CHANGED
@@ -230,7 +230,6 @@ var jsonValueSchema = z.lazy(
230
230
  ])
231
231
  ).register(z.globalRegistry, { id: "JsonSerializableValue" });
232
232
  var contractNameSchema = z.string().check(z.regex(/^[a-z][a-z0-9_]{0,47}(:[a-z0-9_-]{1,48})?$/));
233
- var contractName = contractNameSchema;
234
233
  var violationRole = z.string().check(
235
234
  z.maxLength(200),
236
235
  z.regex(
@@ -242,38 +241,41 @@ var contractViolationSchema = z.strictObject({
242
241
  role: z.nullable(violationRole),
243
242
  rule: z.string().check(z.regex(/^[a-z][a-z_]{0,47}$/))
244
243
  });
244
+ var formFieldSchema = z.strictObject({
245
+ name: z.string(),
246
+ type: z.string(),
247
+ label: z.nullable(z.string()),
248
+ value: jsonValueSchema,
249
+ role: z.optional(z.nullable(contractNameSchema))
250
+ });
251
+ var formExtraSchema = z.optional(
252
+ z.nullable(
253
+ z.array(
254
+ z.strictObject({
255
+ key: z.string().check(z.maxLength(64)),
256
+ label: z.string().check(z.maxLength(200)),
257
+ value: jsonValueSchema
258
+ })
259
+ ).check(z.maxLength(20))
260
+ )
261
+ );
262
+ var contractVersionSchema = z.optional(z.nullable(z.int().check(z.gte(1))));
263
+ var contractHashSchema = z.optional(z.nullable(z.string().check(z.maxLength(64))));
264
+ var formContractViolationsSchema = z.optional(
265
+ z.nullable(z.array(contractViolationSchema).check(z.maxLength(MAX_CONTRACT_VIOLATIONS)))
266
+ );
245
267
  var formSubmitMetadataSchema = z.strictObject({
246
268
  form: z.strictObject({
247
269
  id: z.string(),
248
270
  action: z.nullable(z.string()),
249
- fields: z.optional(
250
- z.array(
251
- z.strictObject({
252
- name: z.string(),
253
- type: z.string(),
254
- label: z.nullable(z.string()),
255
- value: jsonValueSchema,
256
- role: z.optional(z.nullable(contractName))
257
- })
258
- )
259
- ),
260
- kind: z.optional(z.nullable(contractName)),
261
- contract_version: z.optional(z.nullable(z.int().check(z.gte(1)))),
262
- contract_hash: z.optional(z.nullable(z.string().check(z.maxLength(64)))),
263
- extra: z.optional(
264
- z.nullable(
265
- z.array(
266
- z.strictObject({
267
- key: z.string().check(z.maxLength(64)),
268
- label: z.string().check(z.maxLength(200)),
269
- value: jsonValueSchema
270
- })
271
- ).check(z.maxLength(20))
272
- )
273
- ),
274
- contract_violations: z.optional(
275
- z.nullable(z.array(contractViolationSchema).check(z.maxLength(MAX_CONTRACT_VIOLATIONS)))
276
- )
271
+ fields: z.optional(z.array(formFieldSchema)),
272
+ kind: z.optional(z.nullable(contractNameSchema)),
273
+ contract_version: contractVersionSchema,
274
+ contract_hash: contractHashSchema,
275
+ extra: formExtraSchema,
276
+ contract_violations: formContractViolationsSchema,
277
+ // Minted per submit; a later `form_details` names it to add answers to this lead.
278
+ submission_id: z.optional(z.nullable(z.uuidv4()))
277
279
  }),
278
280
  page: z.strictObject({
279
281
  path: z.string()
@@ -645,8 +647,48 @@ function parseTrigger(value) {
645
647
  if (typeof t.threshold_seconds === "number") spec.threshold_seconds = t.threshold_seconds;
646
648
  if (typeof t.page_threshold === "number") spec.page_threshold = t.page_threshold;
647
649
  if (typeof t.page_name === "string") spec.page_name = t.page_name;
650
+ if (t.metric === "percent" || t.metric === "seconds") spec.metric = t.metric;
651
+ if (typeof t.threshold === "number") spec.threshold = t.threshold;
652
+ if (typeof t.video_id === "string" || t.video_id === null) spec.video_id = t.video_id;
648
653
  return spec;
649
654
  }
655
+ function parseVideoEntry(fallbackKey, entry) {
656
+ const key = typeof entry.key === "string" && entry.key ? entry.key : fallbackKey;
657
+ if (!key) return null;
658
+ const host = typeof entry.host === "string" ? entry.host : "";
659
+ const title = typeof entry.title === "string" && entry.title ? entry.title : key;
660
+ const sourcesRaw = isRecord(entry.sources) ? entry.sources : null;
661
+ const desktop = sourcesRaw && typeof sourcesRaw.desktop === "string" ? sourcesRaw.desktop : typeof entry.desktop_uid === "string" ? entry.desktop_uid : "";
662
+ if (!host || !desktop) return null;
663
+ const mobile = sourcesRaw && typeof sourcesRaw.mobile === "string" ? sourcesRaw.mobile : typeof entry.mobile_uid === "string" ? entry.mobile_uid : null;
664
+ const posterTime = typeof entry.poster_time === "number" ? entry.poster_time : typeof entry.poster_time_s === "number" ? entry.poster_time_s : 4;
665
+ return {
666
+ key,
667
+ title,
668
+ host,
669
+ sources: { desktop, mobile },
670
+ poster_time: posterTime,
671
+ duration_s: typeof entry.duration_s === "number" ? entry.duration_s : null
672
+ };
673
+ }
674
+ function parseVideos(value) {
675
+ const out = {};
676
+ if (Array.isArray(value)) {
677
+ for (const item of value) {
678
+ if (!isRecord(item)) continue;
679
+ const parsed = parseVideoEntry("", item);
680
+ if (parsed) out[parsed.key] = parsed;
681
+ }
682
+ return out;
683
+ }
684
+ if (!isRecord(value)) return out;
685
+ for (const [key, entry] of Object.entries(value)) {
686
+ if (!isRecord(entry)) continue;
687
+ const parsed = parseVideoEntry(key, entry);
688
+ if (parsed) out[parsed.key] = parsed;
689
+ }
690
+ return out;
691
+ }
650
692
  function parseConversionConfig(raw) {
651
693
  if (!raw || typeof raw !== "object") return null;
652
694
  const obj = raw;
@@ -697,7 +739,8 @@ function parseConversionConfig(raw) {
697
739
  goals,
698
740
  linked_hostnames: Array.isArray(obj.linked_hostnames) ? obj.linked_hostnames.filter((h) => typeof h === "string" && h.length > 0) : [],
699
741
  integrations: parseIntegrations(obj.integrations),
700
- lead_forms: parseLeadForms(obj.lead_forms)
742
+ lead_forms: parseLeadForms(obj.lead_forms),
743
+ videos: parseVideos(obj.videos)
701
744
  };
702
745
  }
703
746
  function parseLeadForms(value) {
@@ -847,6 +890,21 @@ function automaticThresholdMet(goal, eventType, metadata) {
847
890
  case "form_start":
848
891
  case "phone_click":
849
892
  return true;
893
+ case "video_play":
894
+ return trigger.video_id == null || hasStringField(metadata, "video_id") && metadata.video_id === trigger.video_id;
895
+ case "video_progress": {
896
+ if (trigger.video_id != null && (!hasStringField(metadata, "video_id") || metadata.video_id !== trigger.video_id)) {
897
+ return false;
898
+ }
899
+ if (typeof trigger.threshold !== "number") return false;
900
+ if (trigger.metric === "seconds") {
901
+ return hasNumberField(metadata, "watched_s") && metadata.watched_s >= trigger.threshold;
902
+ }
903
+ if (trigger.metric === "percent") {
904
+ return hasNumberField(metadata, "max_percent") && metadata.max_percent >= trigger.threshold || hasNumberField(metadata, "watched_percent") && metadata.watched_percent >= trigger.threshold;
905
+ }
906
+ return false;
907
+ }
850
908
  default:
851
909
  return false;
852
910
  }
@@ -906,6 +964,9 @@ var RETRY_BASE_MS = 5e3;
906
964
  var RETRY_MAX_MS = 5 * 6e4;
907
965
  var runtimes = /* @__PURE__ */ new Map();
908
966
  var configuredIds = /* @__PURE__ */ new Set();
967
+ var EMPTY_GOALS = [];
968
+ var EMPTY_STRINGS = [];
969
+ var EMPTY_VIDEOS = {};
909
970
  var scriptLoad = null;
910
971
  var jsInitialized = false;
911
972
  function cacheKey(url) {
@@ -1096,11 +1157,11 @@ var TrackingConfigRuntime = class {
1096
1157
  void this.flush();
1097
1158
  }
1098
1159
  listGoals() {
1099
- return this.current?.goals ?? [];
1160
+ return this.current?.goals ?? EMPTY_GOALS;
1100
1161
  }
1101
1162
  /** Sibling hostnames for the linker — read from the cached object even while unconfirmed. */
1102
1163
  linkedHostnames() {
1103
- return this.current?.linked_hostnames ?? [];
1164
+ return this.current?.linked_hostnames ?? EMPTY_STRINGS;
1104
1165
  }
1105
1166
  /**
1106
1167
  * Integration blocks, from the cached object even while unconfirmed: the booking fallback
@@ -1113,6 +1174,14 @@ var TrackingConfigRuntime = class {
1113
1174
  leadForms() {
1114
1175
  return this.current?.lead_forms ?? null;
1115
1176
  }
1177
+ /** Configured Cloudflare Stream tracked videos for this site. */
1178
+ videos() {
1179
+ return this.current?.videos ?? EMPTY_VIDEOS;
1180
+ }
1181
+ /** Look up one configured Cloudflare Stream tracked video by key. */
1182
+ getVideo(key) {
1183
+ return this.current?.videos?.[key] ?? null;
1184
+ }
1116
1185
  async revalidateNow() {
1117
1186
  try {
1118
1187
  const headers = {};
@@ -1269,6 +1338,16 @@ var TrackingConfigRuntime = class {
1269
1338
  this.scheduleRetry();
1270
1339
  return;
1271
1340
  }
1341
+ if (outcome === "fired" && typeof window !== "undefined" && typeof window.fbq === "function") {
1342
+ try {
1343
+ window.fbq("trackCustom", item.key, {
1344
+ ...value != null ? { value } : {},
1345
+ ...currency ? { currency } : {},
1346
+ ...item.transactionId ? { transaction_id: item.transactionId } : {}
1347
+ });
1348
+ } catch {
1349
+ }
1350
+ }
1272
1351
  this.conversionQueue.shift();
1273
1352
  }
1274
1353
  }
@@ -1287,10 +1366,10 @@ var KNOWN_ROLES = new Set(LEAD_FORM_ROLES);
1287
1366
  var ROLE_ORDER = new Map(LEAD_FORM_ROLES.map((role, index) => [role, index]));
1288
1367
  var ADD_ON = /^add_on:[a-z0-9_-]{1,48}$/;
1289
1368
  var CONTRACT_NAME = /^[a-z][a-z0-9_]{0,47}(:[a-z0-9_-]{1,48})?$/;
1290
- function judgeLeadForm(kind, formId, fields, contracts, settings) {
1369
+ function judgeLeadForm(kind, formId, fields, contracts, settings, { partial = false } = {}) {
1291
1370
  const generated = contracts?.contracts[kind];
1292
1371
  const live = liveContract(settings.trackingConfig, kind);
1293
- const violations = check(live === void 0 ? generated : fromLive(live), fields);
1372
+ const violations = check(live === void 0 ? generated : fromLive(live), fields, partial);
1294
1373
  const liveHash = live === void 0 ? void 0 : live?.contract_hash ?? null;
1295
1374
  if (contracts && (liveHash !== void 0 && (generated?.hash ?? null) !== liveHash || contracts.registryVersion !== LEAD_FORM_REGISTRY_VERSION)) {
1296
1375
  violations.push({ role: null, rule: "contract_behind" });
@@ -1322,7 +1401,7 @@ function fromLive(live) {
1322
1401
  options: Object.fromEntries(live.options.map((o) => [o.role, o.options.map((x) => x.key)]))
1323
1402
  };
1324
1403
  }
1325
- function check(contract, fields) {
1404
+ function check(contract, fields, partial) {
1326
1405
  const answered = new Map(fields);
1327
1406
  const violations = [];
1328
1407
  for (const [role, value] of fields) {
@@ -1340,6 +1419,7 @@ function check(contract, fields) {
1340
1419
  violations.push({ role, rule: "unknown_option" });
1341
1420
  }
1342
1421
  }
1422
+ if (partial) return violations;
1343
1423
  for (const { role, requiredWhen } of contract?.requires ?? []) {
1344
1424
  const owing = requiredWhen === null || optionKeys(answered.get(requiredWhen.role)).some((key) => requiredWhen.anyOf.includes(key));
1345
1425
  if (owing && !answered.has(role)) violations.push({ role, rule: "missing_required" });
@@ -1939,7 +2019,7 @@ var zSaleItemEntitySchema = z4.object({
1939
2019
  external_item_id: z4.nullable(z4.string()),
1940
2020
  id: z4.uuid(),
1941
2021
  name: z4.nullable(z4.string()),
1942
- quantity: z4.string().check(z4.regex(/^(?!^[-+.]*$)[+-]?0*\d*\.?\d*$/)),
2022
+ quantity: z4.string(),
1943
2023
  unit_cost_cents: z4.nullable(z4.int()),
1944
2024
  unit_price_cents: z4.int()
1945
2025
  });
@@ -2003,12 +2083,15 @@ var zSmsWithheldReason = z4.enum([
2003
2083
  "test_or_bot_session",
2004
2084
  "invalid_phone",
2005
2085
  "recently_texted",
2086
+ "owner_not_alerted",
2087
+ "no_new_details",
2006
2088
  "do_not_contact",
2007
2089
  "do_not_text_tag",
2008
2090
  "missing_value",
2009
2091
  "us_texting_pending",
2010
2092
  "us_texting_rejected",
2011
- "texts_paused"
2093
+ "texts_paused",
2094
+ "outside_nanp"
2012
2095
  ]);
2013
2096
  var zSaleSmsStatusSchema = z4.object({
2014
2097
  can_send_now: z4._default(z4.boolean(), false),
@@ -2058,6 +2141,17 @@ var zApiErrorSchema = z4.object({
2058
2141
  errors: z4._default(z4.nullish(z4.array(zValidationErrorItem)), null),
2059
2142
  request_id: z4._default(z4.nullish(z4.string()), null)
2060
2143
  });
2144
+ var zWritebackCorrectionAction = z4.enum(["retry", "restate_now"]);
2145
+ var zWritebackCorrectionState = z4.enum([
2146
+ "queued",
2147
+ "sent",
2148
+ "restated",
2149
+ "failed",
2150
+ "limit_reached",
2151
+ "voided",
2152
+ "date_changed",
2153
+ "dry_run_ok"
2154
+ ]);
2061
2155
  var zWritebackEmailSource = z4.enum(["NONE", "SALE", "CUSTOMER", "HARVESTED"]);
2062
2156
  var zWritebackEnrichmentStatus = z4.enum(["NONE", "MATCHED", "AMBIGUOUS"]);
2063
2157
  var zWritebackSaleUploadCounts = z4.object({
@@ -2068,9 +2162,28 @@ var zWritebackSaleUploadCounts = z4.object({
2068
2162
  total: z4._default(z4.int(), 0),
2069
2163
  uploaded: z4._default(z4.int(), 0)
2070
2164
  });
2165
+ var zWritebackValueDrift = z4.enum(["none", "open", "failed"]);
2166
+ var zWritebackCorrectionSchema = z4.object({
2167
+ action: z4.nullable(zWritebackCorrectionAction),
2168
+ can_restate: z4._default(z4.boolean(), false),
2169
+ drift: zWritebackValueDrift,
2170
+ error_message: z4.nullable(z4.string()),
2171
+ google_currency: z4.string(),
2172
+ google_value_cents: z4.int(),
2173
+ restated_at: z4.nullable(z4.iso.datetime({ offset: true })),
2174
+ restated_from_cents: z4.nullable(z4.int()),
2175
+ restatement_limit: z4.int(),
2176
+ restatements_used: z4.int(),
2177
+ sale_currency: z4.string(),
2178
+ sale_value_cents: z4.int(),
2179
+ sends_at: z4.nullable(z4.iso.datetime({ offset: true })),
2180
+ state: zWritebackCorrectionState,
2181
+ upload_id: z4.uuid()
2182
+ });
2071
2183
  var zSaleWritebackStatusSchema = z4.object({
2072
2184
  blocked_reason: z4.nullable(z4.string()),
2073
2185
  can_dispatch: z4._default(z4.boolean(), false),
2186
+ correction: z4.nullable(zWritebackCorrectionSchema),
2074
2187
  email_source: z4.nullable(zWritebackEmailSource),
2075
2188
  enrichment_status: z4.nullable(zWritebackEnrichmentStatus),
2076
2189
  gclid_attached: z4._default(z4.boolean(), false),
@@ -2088,7 +2201,6 @@ var zSaleWritebackStatusSchema = z4.object({
2088
2201
  "out_of_window",
2089
2202
  "blocked"
2090
2203
  ]),
2091
- stale: z4._default(z4.boolean(), false),
2092
2204
  uncovered_service_ids: z4.array(z4.uuid()),
2093
2205
  uploads: zWritebackSaleUploadCounts
2094
2206
  });