@aranova/tracking-react 1.3.0 → 1.4.1

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.
@@ -1,4 +1,4 @@
1
- import { f as BookingDayWindows, h as ConversionIntegrations } from './bookings-CqdjLMkv.js';
1
+ import { j as BookingDayWindows, c as BookingMode, k as ConversionIntegrations } from './bookings-DIu1ho6v.js';
2
2
  import * as zod_v4_core from 'zod/v4/core';
3
3
  import * as z from 'zod/mini';
4
4
  import { J as JsonValue, F as FormSubmitConfig, a as FormSubmitMetadata } from './form-submit-BLb28aCk.js';
@@ -38,6 +38,11 @@ interface BookingIntegration {
38
38
  configVersion: number | null;
39
39
  rules: BookingRules | null;
40
40
  options: BookingOption[];
41
+ /**
42
+ * Where a booking from this page goes: `live` in production; on a development config `test`
43
+ * (the shop's test lead source) or `simulated` (never sent). Show a banner when not `live`.
44
+ */
45
+ mode: BookingMode;
41
46
  }
42
47
  /** What the visitor already typed, carried onto the shop's booking page. */
43
48
  interface BookingHandoffPrefill {
@@ -1,4 +1,4 @@
1
- import { f as BookingDayWindows, h as ConversionIntegrations } from './bookings-VsQdopTt.mjs';
1
+ import { j as BookingDayWindows, c as BookingMode, k as ConversionIntegrations } from './bookings-CqCuuyP6.mjs';
2
2
  import * as zod_v4_core from 'zod/v4/core';
3
3
  import * as z from 'zod/mini';
4
4
  import { J as JsonValue, F as FormSubmitConfig, a as FormSubmitMetadata } from './form-submit-BLb28aCk.mjs';
@@ -38,6 +38,11 @@ interface BookingIntegration {
38
38
  configVersion: number | null;
39
39
  rules: BookingRules | null;
40
40
  options: BookingOption[];
41
+ /**
42
+ * Where a booking from this page goes: `live` in production; on a development config `test`
43
+ * (the shop's test lead source) or `simulated` (never sent). Show a banner when not `live`.
44
+ */
45
+ mode: BookingMode;
41
46
  }
42
47
  /** What the visitor already typed, carried onto the shop's booking page. */
43
48
  interface BookingHandoffPrefill {
@@ -1,5 +1,5 @@
1
1
  import * as z from 'zod/mini';
2
- import { S as SalesBookingsClient, d as ConversionConfigStore, i as TrackingConfigRuntime } from './bookings-VsQdopTt.mjs';
2
+ import { S as SalesBookingsClient, g as ConversionConfigStore, l as TrackingConfigRuntime } from './bookings-CqCuuyP6.mjs';
3
3
  import { CountryCode } from 'libphonenumber-js';
4
4
 
5
5
  /** Raw identifiers a caller may hand us (normalized before use). */
@@ -1,5 +1,5 @@
1
1
  import * as z from 'zod/mini';
2
- import { S as SalesBookingsClient, d as ConversionConfigStore, i as TrackingConfigRuntime } from './bookings-CqdjLMkv.js';
2
+ import { S as SalesBookingsClient, g as ConversionConfigStore, l as TrackingConfigRuntime } from './bookings-DIu1ho6v.js';
3
3
  import { CountryCode } from 'libphonenumber-js';
4
4
 
5
5
  /** Raw identifiers a caller may hand us (normalized before use). */
package/dist/sales.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- export { A as AranovaApiError, B as BusinessConfig, a as BusinessConfigFeatures, b as BusinessConfigService, C as CompareTo, d as CurrencyRevenue, e as CustomerCurrencyDelta, f as CustomerCurrencyTotal, g as CustomerGetOptions, h as CustomerGetResult, i as CustomerKpis, j as CustomerKpisDeltas, k as CustomerKpisPrevious, l as CustomerListPage, m as CustomerListQuery, n as CustomerProfile, o as CustomerSegment, p as CustomerSegmentCount, q as CustomerSortField, r as CustomerSummary, s as CustomerSummaryQuery, D as DistinctCustomersByCurrency, E as EffectiveSaleProperty, G as Granularity, N as NAMED_RANGES, t as NamedRange, P as PublicServiceItem, S as SALE_SOURCES, u as SUPPORTED_CURRENCIES, v as Sale, w as SaleBuiltinRequirableField, x as SaleCursorPage, y as SaleFilters, z as SaleInput, F as SaleItem, H as SaleItemInput, I as SaleKeysetSortField, J as SaleListPage, K as SaleListQuery, L as SaleListQueryV2, M as SalePropertyOption, O as SalePropertyType, Q as SaleService, R as SaleServiceInput, T as SaleSortField, U as SaleSortOrder, V as SaleSource, W as SaleSourceFacts, X as SaleSummary, Y as SaleSummaryPrevious, Z as SaleSummaryQuery, _ as SaleSummaryQueryV2, $ as SaleSummaryV2, a0 as SaleUpdateInput, a1 as SalesBusinessClient, a2 as SalesCategoryBreakdown, a3 as SalesClient, a4 as SalesClientConfig, a5 as SalesCustomersClient, a6 as SalesServiceBreakdown, a7 as SalesTransportConfig, a8 as SalesTrendPoint, a9 as SummaryCurrencyDelta, aa as SummaryDeltas, ab as SummaryWindow, ac as SupportedCurrency, ad as TRACKING_RANGES, ae as TrackingOverviewRange, ag as createSalesClient, ah as currencySchema, ai as fetchServices, aj as formatDateInTz, ak as formatMoney, al as fromMinor, am as saleCreateSchema, an as saleItemSchema, ao as saleServiceSchema, ap as saleUpdateSchema, aq as salesRequest, as as toMinor } from './sales-DSL6vMuY.mjs';
2
- export { B as BookingDropOff, a as BookingFormSubmit, b as BookingInput, c as BookingOutcome, S as SalesBookingsClient, n as newBookingAttemptKey } from './bookings-VsQdopTt.mjs';
1
+ export { A as AranovaApiError, B as BusinessConfig, a as BusinessConfigFeatures, b as BusinessConfigService, C as CompareTo, d as CurrencyRevenue, e as CustomerCurrencyDelta, f as CustomerCurrencyTotal, g as CustomerGetOptions, h as CustomerGetResult, i as CustomerKpis, j as CustomerKpisDeltas, k as CustomerKpisPrevious, l as CustomerListPage, m as CustomerListQuery, n as CustomerProfile, o as CustomerSegment, p as CustomerSegmentCount, q as CustomerSortField, r as CustomerSummary, s as CustomerSummaryQuery, D as DistinctCustomersByCurrency, E as EffectiveSaleProperty, G as Granularity, N as NAMED_RANGES, t as NamedRange, P as PublicServiceItem, S as SALE_SOURCES, u as SUPPORTED_CURRENCIES, v as Sale, w as SaleBuiltinRequirableField, x as SaleCursorPage, y as SaleFilters, z as SaleInput, F as SaleItem, H as SaleItemInput, I as SaleKeysetSortField, J as SaleListPage, K as SaleListQuery, L as SaleListQueryV2, M as SalePropertyOption, O as SalePropertyType, Q as SaleService, R as SaleServiceInput, T as SaleSortField, U as SaleSortOrder, V as SaleSource, W as SaleSourceFacts, X as SaleSummary, Y as SaleSummaryPrevious, Z as SaleSummaryQuery, _ as SaleSummaryQueryV2, $ as SaleSummaryV2, a0 as SaleUpdateInput, a1 as SalesBusinessClient, a2 as SalesCategoryBreakdown, a3 as SalesClient, a4 as SalesClientConfig, a5 as SalesCustomersClient, a6 as SalesServiceBreakdown, a7 as SalesTransportConfig, a8 as SalesTrendPoint, a9 as SummaryCurrencyDelta, aa as SummaryDeltas, ab as SummaryWindow, ac as SupportedCurrency, ad as TRACKING_RANGES, ae as TrackingOverviewRange, ag as createSalesClient, ah as currencySchema, ai as fetchServices, aj as formatDateInTz, ak as formatMoney, al as fromMinor, am as saleCreateSchema, an as saleItemSchema, ao as saleServiceSchema, ap as saleUpdateSchema, aq as salesRequest, as as toMinor } from './sales-CxJVthx_.mjs';
2
+ export { B as BookingDropOff, a as BookingFormSubmit, b as BookingInput, c as BookingMode, d as BookingOutcome, e as BookingSimulation, f as BookingSubmitOptions, S as SalesBookingsClient, n as newBookingAttemptKey } from './bookings-CqCuuyP6.mjs';
3
3
  import 'zod/mini';
4
4
  import 'libphonenumber-js';
5
5
  import './form-submit-BLb28aCk.mjs';
package/dist/sales.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- export { A as AranovaApiError, B as BusinessConfig, a as BusinessConfigFeatures, b as BusinessConfigService, C as CompareTo, d as CurrencyRevenue, e as CustomerCurrencyDelta, f as CustomerCurrencyTotal, g as CustomerGetOptions, h as CustomerGetResult, i as CustomerKpis, j as CustomerKpisDeltas, k as CustomerKpisPrevious, l as CustomerListPage, m as CustomerListQuery, n as CustomerProfile, o as CustomerSegment, p as CustomerSegmentCount, q as CustomerSortField, r as CustomerSummary, s as CustomerSummaryQuery, D as DistinctCustomersByCurrency, E as EffectiveSaleProperty, G as Granularity, N as NAMED_RANGES, t as NamedRange, P as PublicServiceItem, S as SALE_SOURCES, u as SUPPORTED_CURRENCIES, v as Sale, w as SaleBuiltinRequirableField, x as SaleCursorPage, y as SaleFilters, z as SaleInput, F as SaleItem, H as SaleItemInput, I as SaleKeysetSortField, J as SaleListPage, K as SaleListQuery, L as SaleListQueryV2, M as SalePropertyOption, O as SalePropertyType, Q as SaleService, R as SaleServiceInput, T as SaleSortField, U as SaleSortOrder, V as SaleSource, W as SaleSourceFacts, X as SaleSummary, Y as SaleSummaryPrevious, Z as SaleSummaryQuery, _ as SaleSummaryQueryV2, $ as SaleSummaryV2, a0 as SaleUpdateInput, a1 as SalesBusinessClient, a2 as SalesCategoryBreakdown, a3 as SalesClient, a4 as SalesClientConfig, a5 as SalesCustomersClient, a6 as SalesServiceBreakdown, a7 as SalesTransportConfig, a8 as SalesTrendPoint, a9 as SummaryCurrencyDelta, aa as SummaryDeltas, ab as SummaryWindow, ac as SupportedCurrency, ad as TRACKING_RANGES, ae as TrackingOverviewRange, ag as createSalesClient, ah as currencySchema, ai as fetchServices, aj as formatDateInTz, ak as formatMoney, al as fromMinor, am as saleCreateSchema, an as saleItemSchema, ao as saleServiceSchema, ap as saleUpdateSchema, aq as salesRequest, as as toMinor } from './sales-_F3nnI2r.js';
2
- export { B as BookingDropOff, a as BookingFormSubmit, b as BookingInput, c as BookingOutcome, S as SalesBookingsClient, n as newBookingAttemptKey } from './bookings-CqdjLMkv.js';
1
+ export { A as AranovaApiError, B as BusinessConfig, a as BusinessConfigFeatures, b as BusinessConfigService, C as CompareTo, d as CurrencyRevenue, e as CustomerCurrencyDelta, f as CustomerCurrencyTotal, g as CustomerGetOptions, h as CustomerGetResult, i as CustomerKpis, j as CustomerKpisDeltas, k as CustomerKpisPrevious, l as CustomerListPage, m as CustomerListQuery, n as CustomerProfile, o as CustomerSegment, p as CustomerSegmentCount, q as CustomerSortField, r as CustomerSummary, s as CustomerSummaryQuery, D as DistinctCustomersByCurrency, E as EffectiveSaleProperty, G as Granularity, N as NAMED_RANGES, t as NamedRange, P as PublicServiceItem, S as SALE_SOURCES, u as SUPPORTED_CURRENCIES, v as Sale, w as SaleBuiltinRequirableField, x as SaleCursorPage, y as SaleFilters, z as SaleInput, F as SaleItem, H as SaleItemInput, I as SaleKeysetSortField, J as SaleListPage, K as SaleListQuery, L as SaleListQueryV2, M as SalePropertyOption, O as SalePropertyType, Q as SaleService, R as SaleServiceInput, T as SaleSortField, U as SaleSortOrder, V as SaleSource, W as SaleSourceFacts, X as SaleSummary, Y as SaleSummaryPrevious, Z as SaleSummaryQuery, _ as SaleSummaryQueryV2, $ as SaleSummaryV2, a0 as SaleUpdateInput, a1 as SalesBusinessClient, a2 as SalesCategoryBreakdown, a3 as SalesClient, a4 as SalesClientConfig, a5 as SalesCustomersClient, a6 as SalesServiceBreakdown, a7 as SalesTransportConfig, a8 as SalesTrendPoint, a9 as SummaryCurrencyDelta, aa as SummaryDeltas, ab as SummaryWindow, ac as SupportedCurrency, ad as TRACKING_RANGES, ae as TrackingOverviewRange, ag as createSalesClient, ah as currencySchema, ai as fetchServices, aj as formatDateInTz, ak as formatMoney, al as fromMinor, am as saleCreateSchema, an as saleItemSchema, ao as saleServiceSchema, ap as saleUpdateSchema, aq as salesRequest, as as toMinor } from './sales-hlcVTJSS.js';
2
+ export { B as BookingDropOff, a as BookingFormSubmit, b as BookingInput, c as BookingMode, d as BookingOutcome, e as BookingSimulation, f as BookingSubmitOptions, S as SalesBookingsClient, n as newBookingAttemptKey } from './bookings-DIu1ho6v.js';
3
3
  import 'zod/mini';
4
4
  import 'libphonenumber-js';
5
5
  import './form-submit-BLb28aCk.js';
package/dist/sales.js CHANGED
@@ -242,7 +242,8 @@ function getBookingIntegration(integrations) {
242
242
  timezone: booking.timezone,
243
243
  configVersion: booking.config_version,
244
244
  rules,
245
- options: booking.options.map((option) => ({ key: option.key, label: option.label }))
245
+ options: booking.options.map((option) => ({ key: option.key, label: option.label })),
246
+ mode: booking.mode ?? "live"
246
247
  };
247
248
  }
248
249
  function camelRules(rules) {
@@ -335,6 +336,55 @@ var AranovaApiError = class extends Error {
335
336
  }
336
337
  };
337
338
 
339
+ // ../tracking-core/src/resources/intl/date.ts
340
+ function formatDateInTz(iso3, timeZone, opts, locale) {
341
+ const date = new Date(iso3);
342
+ if (Number.isNaN(date.getTime())) return iso3;
343
+ return new Intl.DateTimeFormat(locale, {
344
+ year: "numeric",
345
+ month: "short",
346
+ day: "2-digit",
347
+ hour: "2-digit",
348
+ minute: "2-digit",
349
+ ...opts,
350
+ timeZone
351
+ }).format(date);
352
+ }
353
+
354
+ // ../tracking-core/src/resources/sales/money.ts
355
+ var MINOR_UNIT_EXPONENT = {
356
+ USD: 2,
357
+ CAD: 2
358
+ };
359
+ function exponentFor(currency) {
360
+ return MINOR_UNIT_EXPONENT[currency] ?? 2;
361
+ }
362
+ function toMinor(amount, currency) {
363
+ return Math.round(amount * 10 ** exponentFor(currency));
364
+ }
365
+ function fromMinor(cents, currency) {
366
+ return cents / 10 ** exponentFor(currency);
367
+ }
368
+ function formatMoney(cents, currency, locale) {
369
+ return new Intl.NumberFormat(locale, { style: "currency", currency }).format(
370
+ fromMinor(cents, currency)
371
+ );
372
+ }
373
+
374
+ // ../tracking-core/src/resources/tracking-config-runtime.ts
375
+ var DEFAULT_CDN_BASE_URL = "https://demos.aranova.io";
376
+ function trackingConfigKey(ref) {
377
+ if (ref.siteId) return `tracking-config/v1/sites/${ref.siteId}-${ref.environment}.json`;
378
+ return `tracking-config/v1/${ref.businessId}-${ref.environment}.json`;
379
+ }
380
+ function resolveTrackingConfigUrl(ref) {
381
+ if (ref.cdnUrl) return ref.cdnUrl;
382
+ const configured = ref.cdnBaseUrl?.trim();
383
+ const base = (configured || DEFAULT_CDN_BASE_URL).replace(/\/+$/, "");
384
+ return `${base}/${trackingConfigKey(ref)}`;
385
+ }
386
+ var RETRY_MAX_MS = 5 * 6e4;
387
+
338
388
  // ../tracking-core/src/ingest.ts
339
389
  var API_KEY_HEADER = "X-Aranova-Api-Key";
340
390
  var SDK_VERSION_HEADER = "X-Aranova-Sdk-Version";
@@ -393,6 +443,7 @@ async function apiRequest(config, method, path, body, extraHeaders) {
393
443
  var salesRequest = apiRequest;
394
444
 
395
445
  // ../tracking-core/src/resources/sales/bookings.ts
446
+ var BOOKING_SIMULATE_HEADER = "X-Aranova-Simulate";
396
447
  var BOOKING_ERROR_CODES = {
397
448
  unavailable: "booking_unavailable",
398
449
  stale: "booking_config_stale",
@@ -407,10 +458,11 @@ function sleep(ms) {
407
458
  });
408
459
  }
409
460
  function outcomeOf(body) {
461
+ const mode = body.mode ?? "live";
410
462
  if (body.status === "created")
411
- return { status: "created", id: body.id, requestCode: body.request_code };
412
- if (body.status === "pending") return { status: "pending", id: body.id };
413
- return { status: "failed", id: body.id, fallbackUrl: body.fallback_url };
463
+ return { status: "created", id: body.id, requestCode: body.request_code, mode };
464
+ if (body.status === "pending") return { status: "pending", id: body.id, mode };
465
+ return { status: "failed", id: body.id, fallbackUrl: body.fallback_url, mode };
414
466
  }
415
467
  function formSubmitPayload(input, formId, labels) {
416
468
  const vehicle = input.vehicle ? `${input.vehicle.year} ${input.vehicle.make} ${input.vehicle.model}` : "";
@@ -452,9 +504,29 @@ function formSubmitPayload(input, formId, labels) {
452
504
  function runtimeOf(firing) {
453
505
  return firing && "integrations" in firing ? firing : null;
454
506
  }
507
+ function isLocalUrl(url) {
508
+ try {
509
+ return ["localhost", "127.0.0.1", "[::1]"].includes(new URL(url).hostname);
510
+ } catch {
511
+ return false;
512
+ }
513
+ }
514
+ function bookingSetupMismatch(endpoint, runtime) {
515
+ if (!runtime || !isLocalUrl(endpoint)) return null;
516
+ const configUrl = resolveTrackingConfigUrl(runtime.ref);
517
+ if (isLocalUrl(configUrl)) return null;
518
+ return `[aranova] Bookings go to the local API (${endpoint}) but the runtime config comes from ${configUrl}. Set NEXT_PUBLIC_ARANOVA_CDN_BASE_URL to the local bucket (http://localhost:9100/aranova-demos) so both come from one backend.`;
519
+ }
455
520
  function createSalesBookingsClient(config, firing) {
456
521
  const submittedForms = /* @__PURE__ */ new Set();
457
522
  const staleAttempts = /* @__PURE__ */ new Set();
523
+ let isSetupChecked = false;
524
+ function warnOnSetupMismatch(runtime) {
525
+ if (isSetupChecked) return;
526
+ isSetupChecked = true;
527
+ const warning = bookingSetupMismatch(config.endpoint, runtime);
528
+ if (warning) console.warn(warning);
529
+ }
458
530
  function handoff(input) {
459
531
  const booking = getBookingIntegration(runtimeOf(firing)?.integrations());
460
532
  if (!booking) return null;
@@ -465,14 +537,18 @@ function createSalesBookingsClient(config, firing) {
465
537
  email: input.email
466
538
  });
467
539
  }
540
+ function failedBeforeSend(input) {
541
+ const mode = getBookingIntegration(runtimeOf(firing)?.integrations())?.mode ?? "live";
542
+ return { status: "failed", id: null, fallbackUrl: handoff(input), mode };
543
+ }
468
544
  function withHandoff(outcome, input) {
469
545
  if (outcome.status === "failed" && !outcome.fallbackUrl) {
470
546
  return { ...outcome, fallbackUrl: handoff(input) };
471
547
  }
472
548
  return outcome;
473
549
  }
474
- async function poll(id) {
475
- let outcome = { status: "pending", id };
550
+ async function poll(id, mode) {
551
+ let outcome = { status: "pending", id, mode };
476
552
  for (const delay of POLL_DELAYS_MS) {
477
553
  await sleep(delay);
478
554
  try {
@@ -487,12 +563,10 @@ function createSalesBookingsClient(config, firing) {
487
563
  }
488
564
  async function rejected(error, input, attemptKey, runtime) {
489
565
  if (!(error instanceof AranovaApiError)) {
490
- return { status: "failed", id: null, fallbackUrl: handoff(input) };
566
+ return failedBeforeSend(input);
491
567
  }
492
568
  if (error.code === BOOKING_ERROR_CODES.stale) {
493
- if (staleAttempts.has(attemptKey)) {
494
- return { status: "failed", id: null, fallbackUrl: handoff(input) };
495
- }
569
+ if (staleAttempts.has(attemptKey)) return failedBeforeSend(input);
496
570
  staleAttempts.add(attemptKey);
497
571
  await runtime?.revalidate();
498
572
  return { status: "stale", message: error.message };
@@ -508,15 +582,16 @@ function createSalesBookingsClient(config, firing) {
508
582
  if (error.code === "validation_error") {
509
583
  return { status: "invalid", message: INVALID_DETAILS, reasons: [] };
510
584
  }
511
- return { status: "failed", id: null, fallbackUrl: handoff(input) };
585
+ return failedBeforeSend(input);
512
586
  }
513
587
  return {
514
- async submit(input, { attemptKey, formSubmit }) {
588
+ async submit(input, { attemptKey, formSubmit, simulate }) {
515
589
  registerCapability("booking_integration");
516
590
  const runtime = runtimeOf(firing);
591
+ warnOnSetupMismatch(runtime);
517
592
  const booking = getBookingIntegration(runtime?.integrations());
518
593
  if (!booking?.acceptsBookings || booking.configVersion === null) {
519
- return { status: "failed", id: null, fallbackUrl: handoff(input) };
594
+ return failedBeforeSend(input);
520
595
  }
521
596
  if (formSubmit && !submittedForms.has(attemptKey)) {
522
597
  submittedForms.add(attemptKey);
@@ -546,12 +621,22 @@ function createSalesBookingsClient(config, firing) {
546
621
  };
547
622
  let response;
548
623
  try {
549
- response = await salesRequest(config, "POST", "/bookings", body);
624
+ const headers = simulate ? { [BOOKING_SIMULATE_HEADER]: simulate } : void 0;
625
+ response = await salesRequest(
626
+ config,
627
+ "POST",
628
+ "/bookings",
629
+ body,
630
+ headers
631
+ );
550
632
  } catch (error) {
551
633
  return rejected(error, input, attemptKey, runtime);
552
634
  }
553
635
  const outcome = outcomeOf(response);
554
- return withHandoff(outcome.status === "pending" ? await poll(outcome.id) : outcome, input);
636
+ return withHandoff(
637
+ outcome.status === "pending" ? await poll(outcome.id, outcome.mode) : outcome,
638
+ input
639
+ );
555
640
  },
556
641
  async status(id) {
557
642
  return outcomeOf(
@@ -565,41 +650,6 @@ function createSalesBookingsClient(config, firing) {
565
650
  };
566
651
  }
567
652
 
568
- // ../tracking-core/src/resources/intl/date.ts
569
- function formatDateInTz(iso3, timeZone, opts, locale) {
570
- const date = new Date(iso3);
571
- if (Number.isNaN(date.getTime())) return iso3;
572
- return new Intl.DateTimeFormat(locale, {
573
- year: "numeric",
574
- month: "short",
575
- day: "2-digit",
576
- hour: "2-digit",
577
- minute: "2-digit",
578
- ...opts,
579
- timeZone
580
- }).format(date);
581
- }
582
-
583
- // ../tracking-core/src/resources/sales/money.ts
584
- var MINOR_UNIT_EXPONENT = {
585
- USD: 2,
586
- CAD: 2
587
- };
588
- function exponentFor(currency) {
589
- return MINOR_UNIT_EXPONENT[currency] ?? 2;
590
- }
591
- function toMinor(amount, currency) {
592
- return Math.round(amount * 10 ** exponentFor(currency));
593
- }
594
- function fromMinor(cents, currency) {
595
- return cents / 10 ** exponentFor(currency);
596
- }
597
- function formatMoney(cents, currency, locale) {
598
- return new Intl.NumberFormat(locale, { style: "currency", currency }).format(
599
- fromMinor(cents, currency)
600
- );
601
- }
602
-
603
653
  // ../tracking-core/src/resources/sales/client.ts
604
654
  function fireRecordedConversions(firing, input, recorded, sale, currency) {
605
655
  if (!firing) return;
@@ -815,6 +865,7 @@ var zErrorCode = z.enum([
815
865
  "booking_not_found",
816
866
  "booking_not_cancellable",
817
867
  "booking_not_reschedulable",
868
+ "booking_not_synced",
818
869
  "manage_token_invalid",
819
870
  "google_error",
820
871
  "booking_unavailable",