@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.js CHANGED
@@ -283,7 +283,6 @@ var jsonValueSchema = z.lazy(
283
283
  ])
284
284
  ).register(z.globalRegistry, { id: "JsonSerializableValue" });
285
285
  var contractNameSchema = z.string().check(z.regex(/^[a-z][a-z0-9_]{0,47}(:[a-z0-9_-]{1,48})?$/));
286
- var contractName = contractNameSchema;
287
286
  var violationRole = z.string().check(
288
287
  z.maxLength(200),
289
288
  z.regex(
@@ -295,38 +294,41 @@ var contractViolationSchema = z.strictObject({
295
294
  role: z.nullable(violationRole),
296
295
  rule: z.string().check(z.regex(/^[a-z][a-z_]{0,47}$/))
297
296
  });
297
+ var formFieldSchema = z.strictObject({
298
+ name: z.string(),
299
+ type: z.string(),
300
+ label: z.nullable(z.string()),
301
+ value: jsonValueSchema,
302
+ role: z.optional(z.nullable(contractNameSchema))
303
+ });
304
+ var formExtraSchema = z.optional(
305
+ z.nullable(
306
+ z.array(
307
+ z.strictObject({
308
+ key: z.string().check(z.maxLength(64)),
309
+ label: z.string().check(z.maxLength(200)),
310
+ value: jsonValueSchema
311
+ })
312
+ ).check(z.maxLength(20))
313
+ )
314
+ );
315
+ var contractVersionSchema = z.optional(z.nullable(z.int().check(z.gte(1))));
316
+ var contractHashSchema = z.optional(z.nullable(z.string().check(z.maxLength(64))));
317
+ var formContractViolationsSchema = z.optional(
318
+ z.nullable(z.array(contractViolationSchema).check(z.maxLength(MAX_CONTRACT_VIOLATIONS)))
319
+ );
298
320
  var formSubmitMetadataSchema = z.strictObject({
299
321
  form: z.strictObject({
300
322
  id: z.string(),
301
323
  action: z.nullable(z.string()),
302
- fields: z.optional(
303
- z.array(
304
- z.strictObject({
305
- name: z.string(),
306
- type: z.string(),
307
- label: z.nullable(z.string()),
308
- value: jsonValueSchema,
309
- role: z.optional(z.nullable(contractName))
310
- })
311
- )
312
- ),
313
- kind: z.optional(z.nullable(contractName)),
314
- contract_version: z.optional(z.nullable(z.int().check(z.gte(1)))),
315
- contract_hash: z.optional(z.nullable(z.string().check(z.maxLength(64)))),
316
- extra: z.optional(
317
- z.nullable(
318
- z.array(
319
- z.strictObject({
320
- key: z.string().check(z.maxLength(64)),
321
- label: z.string().check(z.maxLength(200)),
322
- value: jsonValueSchema
323
- })
324
- ).check(z.maxLength(20))
325
- )
326
- ),
327
- contract_violations: z.optional(
328
- z.nullable(z.array(contractViolationSchema).check(z.maxLength(MAX_CONTRACT_VIOLATIONS)))
329
- )
324
+ fields: z.optional(z.array(formFieldSchema)),
325
+ kind: z.optional(z.nullable(contractNameSchema)),
326
+ contract_version: contractVersionSchema,
327
+ contract_hash: contractHashSchema,
328
+ extra: formExtraSchema,
329
+ contract_violations: formContractViolationsSchema,
330
+ // Minted per submit; a later `form_details` names it to add answers to this lead.
331
+ submission_id: z.optional(z.nullable(z.uuidv4()))
330
332
  }),
331
333
  page: z.strictObject({
332
334
  path: z.string()
@@ -698,8 +700,48 @@ function parseTrigger(value) {
698
700
  if (typeof t.threshold_seconds === "number") spec.threshold_seconds = t.threshold_seconds;
699
701
  if (typeof t.page_threshold === "number") spec.page_threshold = t.page_threshold;
700
702
  if (typeof t.page_name === "string") spec.page_name = t.page_name;
703
+ if (t.metric === "percent" || t.metric === "seconds") spec.metric = t.metric;
704
+ if (typeof t.threshold === "number") spec.threshold = t.threshold;
705
+ if (typeof t.video_id === "string" || t.video_id === null) spec.video_id = t.video_id;
701
706
  return spec;
702
707
  }
708
+ function parseVideoEntry(fallbackKey, entry) {
709
+ const key = typeof entry.key === "string" && entry.key ? entry.key : fallbackKey;
710
+ if (!key) return null;
711
+ const host = typeof entry.host === "string" ? entry.host : "";
712
+ const title = typeof entry.title === "string" && entry.title ? entry.title : key;
713
+ const sourcesRaw = isRecord(entry.sources) ? entry.sources : null;
714
+ const desktop = sourcesRaw && typeof sourcesRaw.desktop === "string" ? sourcesRaw.desktop : typeof entry.desktop_uid === "string" ? entry.desktop_uid : "";
715
+ if (!host || !desktop) return null;
716
+ const mobile = sourcesRaw && typeof sourcesRaw.mobile === "string" ? sourcesRaw.mobile : typeof entry.mobile_uid === "string" ? entry.mobile_uid : null;
717
+ const posterTime = typeof entry.poster_time === "number" ? entry.poster_time : typeof entry.poster_time_s === "number" ? entry.poster_time_s : 4;
718
+ return {
719
+ key,
720
+ title,
721
+ host,
722
+ sources: { desktop, mobile },
723
+ poster_time: posterTime,
724
+ duration_s: typeof entry.duration_s === "number" ? entry.duration_s : null
725
+ };
726
+ }
727
+ function parseVideos(value) {
728
+ const out = {};
729
+ if (Array.isArray(value)) {
730
+ for (const item of value) {
731
+ if (!isRecord(item)) continue;
732
+ const parsed = parseVideoEntry("", item);
733
+ if (parsed) out[parsed.key] = parsed;
734
+ }
735
+ return out;
736
+ }
737
+ if (!isRecord(value)) return out;
738
+ for (const [key, entry] of Object.entries(value)) {
739
+ if (!isRecord(entry)) continue;
740
+ const parsed = parseVideoEntry(key, entry);
741
+ if (parsed) out[parsed.key] = parsed;
742
+ }
743
+ return out;
744
+ }
703
745
  function parseConversionConfig(raw) {
704
746
  if (!raw || typeof raw !== "object") return null;
705
747
  const obj = raw;
@@ -750,7 +792,8 @@ function parseConversionConfig(raw) {
750
792
  goals,
751
793
  linked_hostnames: Array.isArray(obj.linked_hostnames) ? obj.linked_hostnames.filter((h) => typeof h === "string" && h.length > 0) : [],
752
794
  integrations: parseIntegrations(obj.integrations),
753
- lead_forms: parseLeadForms(obj.lead_forms)
795
+ lead_forms: parseLeadForms(obj.lead_forms),
796
+ videos: parseVideos(obj.videos)
754
797
  };
755
798
  }
756
799
  function parseLeadForms(value) {
@@ -900,6 +943,21 @@ function automaticThresholdMet(goal, eventType, metadata) {
900
943
  case "form_start":
901
944
  case "phone_click":
902
945
  return true;
946
+ case "video_play":
947
+ return trigger.video_id == null || hasStringField(metadata, "video_id") && metadata.video_id === trigger.video_id;
948
+ case "video_progress": {
949
+ if (trigger.video_id != null && (!hasStringField(metadata, "video_id") || metadata.video_id !== trigger.video_id)) {
950
+ return false;
951
+ }
952
+ if (typeof trigger.threshold !== "number") return false;
953
+ if (trigger.metric === "seconds") {
954
+ return hasNumberField(metadata, "watched_s") && metadata.watched_s >= trigger.threshold;
955
+ }
956
+ if (trigger.metric === "percent") {
957
+ return hasNumberField(metadata, "max_percent") && metadata.max_percent >= trigger.threshold || hasNumberField(metadata, "watched_percent") && metadata.watched_percent >= trigger.threshold;
958
+ }
959
+ return false;
960
+ }
903
961
  default:
904
962
  return false;
905
963
  }
@@ -959,6 +1017,9 @@ var RETRY_BASE_MS = 5e3;
959
1017
  var RETRY_MAX_MS = 5 * 6e4;
960
1018
  var runtimes = /* @__PURE__ */ new Map();
961
1019
  var configuredIds = /* @__PURE__ */ new Set();
1020
+ var EMPTY_GOALS = [];
1021
+ var EMPTY_STRINGS = [];
1022
+ var EMPTY_VIDEOS = {};
962
1023
  var scriptLoad = null;
963
1024
  var jsInitialized = false;
964
1025
  function cacheKey(url) {
@@ -1149,11 +1210,11 @@ var TrackingConfigRuntime = class {
1149
1210
  void this.flush();
1150
1211
  }
1151
1212
  listGoals() {
1152
- return this.current?.goals ?? [];
1213
+ return this.current?.goals ?? EMPTY_GOALS;
1153
1214
  }
1154
1215
  /** Sibling hostnames for the linker — read from the cached object even while unconfirmed. */
1155
1216
  linkedHostnames() {
1156
- return this.current?.linked_hostnames ?? [];
1217
+ return this.current?.linked_hostnames ?? EMPTY_STRINGS;
1157
1218
  }
1158
1219
  /**
1159
1220
  * Integration blocks, from the cached object even while unconfirmed: the booking fallback
@@ -1166,6 +1227,14 @@ var TrackingConfigRuntime = class {
1166
1227
  leadForms() {
1167
1228
  return this.current?.lead_forms ?? null;
1168
1229
  }
1230
+ /** Configured Cloudflare Stream tracked videos for this site. */
1231
+ videos() {
1232
+ return this.current?.videos ?? EMPTY_VIDEOS;
1233
+ }
1234
+ /** Look up one configured Cloudflare Stream tracked video by key. */
1235
+ getVideo(key) {
1236
+ return this.current?.videos?.[key] ?? null;
1237
+ }
1169
1238
  async revalidateNow() {
1170
1239
  try {
1171
1240
  const headers = {};
@@ -1322,6 +1391,16 @@ var TrackingConfigRuntime = class {
1322
1391
  this.scheduleRetry();
1323
1392
  return;
1324
1393
  }
1394
+ if (outcome === "fired" && typeof window !== "undefined" && typeof window.fbq === "function") {
1395
+ try {
1396
+ window.fbq("trackCustom", item.key, {
1397
+ ...value != null ? { value } : {},
1398
+ ...currency ? { currency } : {},
1399
+ ...item.transactionId ? { transaction_id: item.transactionId } : {}
1400
+ });
1401
+ } catch {
1402
+ }
1403
+ }
1325
1404
  this.conversionQueue.shift();
1326
1405
  }
1327
1406
  }
@@ -1340,10 +1419,10 @@ var KNOWN_ROLES = new Set(LEAD_FORM_ROLES);
1340
1419
  var ROLE_ORDER = new Map(LEAD_FORM_ROLES.map((role, index) => [role, index]));
1341
1420
  var ADD_ON = /^add_on:[a-z0-9_-]{1,48}$/;
1342
1421
  var CONTRACT_NAME = /^[a-z][a-z0-9_]{0,47}(:[a-z0-9_-]{1,48})?$/;
1343
- function judgeLeadForm(kind, formId, fields, contracts, settings) {
1422
+ function judgeLeadForm(kind, formId, fields, contracts, settings, { partial = false } = {}) {
1344
1423
  const generated = contracts?.contracts[kind];
1345
1424
  const live = liveContract(settings.trackingConfig, kind);
1346
- const violations = check(live === void 0 ? generated : fromLive(live), fields);
1425
+ const violations = check(live === void 0 ? generated : fromLive(live), fields, partial);
1347
1426
  const liveHash = live === void 0 ? void 0 : live?.contract_hash ?? null;
1348
1427
  if (contracts && (liveHash !== void 0 && (generated?.hash ?? null) !== liveHash || contracts.registryVersion !== LEAD_FORM_REGISTRY_VERSION)) {
1349
1428
  violations.push({ role: null, rule: "contract_behind" });
@@ -1375,7 +1454,7 @@ function fromLive(live) {
1375
1454
  options: Object.fromEntries(live.options.map((o) => [o.role, o.options.map((x) => x.key)]))
1376
1455
  };
1377
1456
  }
1378
- function check(contract, fields) {
1457
+ function check(contract, fields, partial) {
1379
1458
  const answered = new Map(fields);
1380
1459
  const violations = [];
1381
1460
  for (const [role, value] of fields) {
@@ -1393,6 +1472,7 @@ function check(contract, fields) {
1393
1472
  violations.push({ role, rule: "unknown_option" });
1394
1473
  }
1395
1474
  }
1475
+ if (partial) return violations;
1396
1476
  for (const { role, requiredWhen } of contract?.requires ?? []) {
1397
1477
  const owing = requiredWhen === null || optionKeys(answered.get(requiredWhen.role)).some((key) => requiredWhen.anyOf.includes(key));
1398
1478
  if (owing && !answered.has(role)) violations.push({ role, rule: "missing_required" });
@@ -1992,7 +2072,7 @@ var zSaleItemEntitySchema = z4.object({
1992
2072
  external_item_id: z4.nullable(z4.string()),
1993
2073
  id: z4.uuid(),
1994
2074
  name: z4.nullable(z4.string()),
1995
- quantity: z4.string().check(z4.regex(/^(?!^[-+.]*$)[+-]?0*\d*\.?\d*$/)),
2075
+ quantity: z4.string(),
1996
2076
  unit_cost_cents: z4.nullable(z4.int()),
1997
2077
  unit_price_cents: z4.int()
1998
2078
  });
@@ -2056,12 +2136,15 @@ var zSmsWithheldReason = z4.enum([
2056
2136
  "test_or_bot_session",
2057
2137
  "invalid_phone",
2058
2138
  "recently_texted",
2139
+ "owner_not_alerted",
2140
+ "no_new_details",
2059
2141
  "do_not_contact",
2060
2142
  "do_not_text_tag",
2061
2143
  "missing_value",
2062
2144
  "us_texting_pending",
2063
2145
  "us_texting_rejected",
2064
- "texts_paused"
2146
+ "texts_paused",
2147
+ "outside_nanp"
2065
2148
  ]);
2066
2149
  var zSaleSmsStatusSchema = z4.object({
2067
2150
  can_send_now: z4._default(z4.boolean(), false),
@@ -2111,6 +2194,17 @@ var zApiErrorSchema = z4.object({
2111
2194
  errors: z4._default(z4.nullish(z4.array(zValidationErrorItem)), null),
2112
2195
  request_id: z4._default(z4.nullish(z4.string()), null)
2113
2196
  });
2197
+ var zWritebackCorrectionAction = z4.enum(["retry", "restate_now"]);
2198
+ var zWritebackCorrectionState = z4.enum([
2199
+ "queued",
2200
+ "sent",
2201
+ "restated",
2202
+ "failed",
2203
+ "limit_reached",
2204
+ "voided",
2205
+ "date_changed",
2206
+ "dry_run_ok"
2207
+ ]);
2114
2208
  var zWritebackEmailSource = z4.enum(["NONE", "SALE", "CUSTOMER", "HARVESTED"]);
2115
2209
  var zWritebackEnrichmentStatus = z4.enum(["NONE", "MATCHED", "AMBIGUOUS"]);
2116
2210
  var zWritebackSaleUploadCounts = z4.object({
@@ -2121,9 +2215,28 @@ var zWritebackSaleUploadCounts = z4.object({
2121
2215
  total: z4._default(z4.int(), 0),
2122
2216
  uploaded: z4._default(z4.int(), 0)
2123
2217
  });
2218
+ var zWritebackValueDrift = z4.enum(["none", "open", "failed"]);
2219
+ var zWritebackCorrectionSchema = z4.object({
2220
+ action: z4.nullable(zWritebackCorrectionAction),
2221
+ can_restate: z4._default(z4.boolean(), false),
2222
+ drift: zWritebackValueDrift,
2223
+ error_message: z4.nullable(z4.string()),
2224
+ google_currency: z4.string(),
2225
+ google_value_cents: z4.int(),
2226
+ restated_at: z4.nullable(z4.iso.datetime({ offset: true })),
2227
+ restated_from_cents: z4.nullable(z4.int()),
2228
+ restatement_limit: z4.int(),
2229
+ restatements_used: z4.int(),
2230
+ sale_currency: z4.string(),
2231
+ sale_value_cents: z4.int(),
2232
+ sends_at: z4.nullable(z4.iso.datetime({ offset: true })),
2233
+ state: zWritebackCorrectionState,
2234
+ upload_id: z4.uuid()
2235
+ });
2124
2236
  var zSaleWritebackStatusSchema = z4.object({
2125
2237
  blocked_reason: z4.nullable(z4.string()),
2126
2238
  can_dispatch: z4._default(z4.boolean(), false),
2239
+ correction: z4.nullable(zWritebackCorrectionSchema),
2127
2240
  email_source: z4.nullable(zWritebackEmailSource),
2128
2241
  enrichment_status: z4.nullable(zWritebackEnrichmentStatus),
2129
2242
  gclid_attached: z4._default(z4.boolean(), false),
@@ -2141,7 +2254,6 @@ var zSaleWritebackStatusSchema = z4.object({
2141
2254
  "out_of_window",
2142
2255
  "blocked"
2143
2256
  ]),
2144
- stale: z4._default(z4.boolean(), false),
2145
2257
  uncovered_service_ids: z4.array(z4.uuid()),
2146
2258
  uploads: zWritebackSaleUploadCounts
2147
2259
  });