@aranova/tracking-react 0.7.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.
package/dist/index.d.ts CHANGED
@@ -1398,6 +1398,307 @@ interface TypedTrackingClient<TRegistry extends TriggerRegistryConfig> {
1398
1398
  getVisitorId(): string;
1399
1399
  }
1400
1400
 
1401
+ /**
1402
+ * Sales / Conversions wire schemas — the client-side source of truth.
1403
+ *
1404
+ * `saleCreateSchema` is mirrored by `SaleCreateSchema` in
1405
+ * `apps/api/src/schemas/tracking_sales.py` and enforced by the backend drift
1406
+ * test (the `resources` section of `events.schema.json`). Keep them in lockstep.
1407
+ *
1408
+ * Money is **integer minor units (cents)**; `quantity` is a decimal string;
1409
+ * `currency` is the required `SupportedCurrency` enum.
1410
+ */
1411
+ declare const SUPPORTED_CURRENCIES: readonly ["USD", "CAD"];
1412
+ type SupportedCurrency = (typeof SUPPORTED_CURRENCIES)[number];
1413
+ declare const TRACKING_ENVIRONMENTS: readonly ["production", "development"];
1414
+ declare const saleItemSchema: z.ZodObject<{
1415
+ external_item_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
1416
+ name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
1417
+ category: z.ZodOptional<z.ZodNullable<z.ZodString>>;
1418
+ quantity: z.ZodString;
1419
+ unit_price_cents: z.ZodNumber;
1420
+ unit_cost_cents: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
1421
+ }, "strict", z.ZodTypeAny, {
1422
+ quantity: string;
1423
+ unit_price_cents: number;
1424
+ name?: string | null | undefined;
1425
+ external_item_id?: string | null | undefined;
1426
+ category?: string | null | undefined;
1427
+ unit_cost_cents?: number | null | undefined;
1428
+ }, {
1429
+ quantity: string;
1430
+ unit_price_cents: number;
1431
+ name?: string | null | undefined;
1432
+ external_item_id?: string | null | undefined;
1433
+ category?: string | null | undefined;
1434
+ unit_cost_cents?: number | null | undefined;
1435
+ }>;
1436
+ declare const saleCreateSchema: z.ZodObject<{
1437
+ external_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
1438
+ description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
1439
+ service: z.ZodOptional<z.ZodNullable<z.ZodString>>;
1440
+ currency: z.ZodEnum<["USD", "CAD"]>;
1441
+ amount_total_cents: z.ZodNumber;
1442
+ occurred_at: z.ZodString;
1443
+ environment: z.ZodDefault<z.ZodEnum<["production", "development"]>>;
1444
+ items: z.ZodDefault<z.ZodArray<z.ZodObject<{
1445
+ external_item_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
1446
+ name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
1447
+ category: z.ZodOptional<z.ZodNullable<z.ZodString>>;
1448
+ quantity: z.ZodString;
1449
+ unit_price_cents: z.ZodNumber;
1450
+ unit_cost_cents: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
1451
+ }, "strict", z.ZodTypeAny, {
1452
+ quantity: string;
1453
+ unit_price_cents: number;
1454
+ name?: string | null | undefined;
1455
+ external_item_id?: string | null | undefined;
1456
+ category?: string | null | undefined;
1457
+ unit_cost_cents?: number | null | undefined;
1458
+ }, {
1459
+ quantity: string;
1460
+ unit_price_cents: number;
1461
+ name?: string | null | undefined;
1462
+ external_item_id?: string | null | undefined;
1463
+ category?: string | null | undefined;
1464
+ unit_cost_cents?: number | null | undefined;
1465
+ }>, "many">>;
1466
+ metadata: z.ZodOptional<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
1467
+ }, "strict", z.ZodTypeAny, {
1468
+ currency: "USD" | "CAD";
1469
+ amount_total_cents: number;
1470
+ occurred_at: string;
1471
+ environment: "production" | "development";
1472
+ items: {
1473
+ quantity: string;
1474
+ unit_price_cents: number;
1475
+ name?: string | null | undefined;
1476
+ external_item_id?: string | null | undefined;
1477
+ category?: string | null | undefined;
1478
+ unit_cost_cents?: number | null | undefined;
1479
+ }[];
1480
+ metadata?: Record<string, unknown> | null | undefined;
1481
+ external_id?: string | null | undefined;
1482
+ description?: string | null | undefined;
1483
+ service?: string | null | undefined;
1484
+ }, {
1485
+ currency: "USD" | "CAD";
1486
+ amount_total_cents: number;
1487
+ occurred_at: string;
1488
+ metadata?: Record<string, unknown> | null | undefined;
1489
+ external_id?: string | null | undefined;
1490
+ description?: string | null | undefined;
1491
+ service?: string | null | undefined;
1492
+ environment?: "production" | "development" | undefined;
1493
+ items?: {
1494
+ quantity: string;
1495
+ unit_price_cents: number;
1496
+ name?: string | null | undefined;
1497
+ external_item_id?: string | null | undefined;
1498
+ category?: string | null | undefined;
1499
+ unit_cost_cents?: number | null | undefined;
1500
+ }[] | undefined;
1501
+ }>;
1502
+ declare const saleUpdateSchema: z.ZodObject<{
1503
+ description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
1504
+ service: z.ZodOptional<z.ZodNullable<z.ZodString>>;
1505
+ currency: z.ZodOptional<z.ZodEnum<["USD", "CAD"]>>;
1506
+ amount_total_cents: z.ZodOptional<z.ZodNumber>;
1507
+ occurred_at: z.ZodOptional<z.ZodString>;
1508
+ items: z.ZodOptional<z.ZodArray<z.ZodObject<{
1509
+ external_item_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
1510
+ name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
1511
+ category: z.ZodOptional<z.ZodNullable<z.ZodString>>;
1512
+ quantity: z.ZodString;
1513
+ unit_price_cents: z.ZodNumber;
1514
+ unit_cost_cents: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
1515
+ }, "strict", z.ZodTypeAny, {
1516
+ quantity: string;
1517
+ unit_price_cents: number;
1518
+ name?: string | null | undefined;
1519
+ external_item_id?: string | null | undefined;
1520
+ category?: string | null | undefined;
1521
+ unit_cost_cents?: number | null | undefined;
1522
+ }, {
1523
+ quantity: string;
1524
+ unit_price_cents: number;
1525
+ name?: string | null | undefined;
1526
+ external_item_id?: string | null | undefined;
1527
+ category?: string | null | undefined;
1528
+ unit_cost_cents?: number | null | undefined;
1529
+ }>, "many">>;
1530
+ metadata: z.ZodOptional<z.ZodNullable<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
1531
+ }, "strict", z.ZodTypeAny, {
1532
+ metadata?: Record<string, unknown> | null | undefined;
1533
+ description?: string | null | undefined;
1534
+ service?: string | null | undefined;
1535
+ currency?: "USD" | "CAD" | undefined;
1536
+ amount_total_cents?: number | undefined;
1537
+ occurred_at?: string | undefined;
1538
+ items?: {
1539
+ quantity: string;
1540
+ unit_price_cents: number;
1541
+ name?: string | null | undefined;
1542
+ external_item_id?: string | null | undefined;
1543
+ category?: string | null | undefined;
1544
+ unit_cost_cents?: number | null | undefined;
1545
+ }[] | undefined;
1546
+ }, {
1547
+ metadata?: Record<string, unknown> | null | undefined;
1548
+ description?: string | null | undefined;
1549
+ service?: string | null | undefined;
1550
+ currency?: "USD" | "CAD" | undefined;
1551
+ amount_total_cents?: number | undefined;
1552
+ occurred_at?: string | undefined;
1553
+ items?: {
1554
+ quantity: string;
1555
+ unit_price_cents: number;
1556
+ name?: string | null | undefined;
1557
+ external_item_id?: string | null | undefined;
1558
+ category?: string | null | undefined;
1559
+ unit_cost_cents?: number | null | undefined;
1560
+ }[] | undefined;
1561
+ }>;
1562
+ type SaleItemInput = z.input<typeof saleItemSchema>;
1563
+ type SaleInput = z.input<typeof saleCreateSchema>;
1564
+ type SaleUpdateInput = z.input<typeof saleUpdateSchema>;
1565
+ interface SaleItem {
1566
+ id: string;
1567
+ external_item_id: string | null;
1568
+ name: string | null;
1569
+ category: string | null;
1570
+ quantity: string;
1571
+ unit_price_cents: number;
1572
+ unit_cost_cents: number | null;
1573
+ }
1574
+ interface Sale {
1575
+ id: string;
1576
+ business_id: string;
1577
+ business_name?: string | null;
1578
+ external_id: string | null;
1579
+ currency: SupportedCurrency;
1580
+ amount_total_cents: number;
1581
+ description: string | null;
1582
+ service_id: string | null;
1583
+ service_key?: string | null;
1584
+ service_label?: string | null;
1585
+ occurred_at: string;
1586
+ environment: (typeof TRACKING_ENVIRONMENTS)[number];
1587
+ metadata: Record<string, unknown> | null;
1588
+ created_at: string;
1589
+ updated_at: string;
1590
+ items: SaleItem[];
1591
+ }
1592
+ interface SaleListPage {
1593
+ items: Sale[];
1594
+ total: number;
1595
+ }
1596
+ interface SaleCursorPage {
1597
+ items: Sale[];
1598
+ next_cursor: string | null;
1599
+ }
1600
+ interface SaleListQuery {
1601
+ business_id?: string;
1602
+ external_id?: string;
1603
+ currency?: SupportedCurrency;
1604
+ environment?: (typeof TRACKING_ENVIRONMENTS)[number];
1605
+ since?: string;
1606
+ until?: string;
1607
+ limit?: number;
1608
+ cursor?: string | null;
1609
+ }
1610
+
1611
+ /** Shared config for every sales HTTP helper. */
1612
+ interface SalesTransportConfig {
1613
+ /** Public (`aranv_pk_…`) or secret (`aranv_sk_…`) API key. */
1614
+ apiKey: string;
1615
+ /**
1616
+ * Base tracking endpoint, e.g. `https://aranovainternal-production.up.railway.app/tracking`.
1617
+ * The `/sales` path is appended by the helpers.
1618
+ */
1619
+ endpoint: string;
1620
+ /** Optional SDK identity headers (mirrors the event ingest client). */
1621
+ sdkVersion?: string;
1622
+ packageName?: string;
1623
+ surface?: string;
1624
+ environment?: string;
1625
+ }
1626
+
1627
+ /** Config for {@link createSalesClient}. */
1628
+ interface SalesClientConfig extends SalesTransportConfig {
1629
+ /** Applied when an individual `record()` call omits `currency`. */
1630
+ defaultCurrency?: SupportedCurrency;
1631
+ }
1632
+ /**
1633
+ * One isomorphic sales client — what a key may *do* is enforced by the backend,
1634
+ * not by hiding methods. A **public** key (`aranv_pk_…`) may `record` (the
1635
+ * backend rejects reads/CRUD from it with a `403`); a **secret** key
1636
+ * (`aranv_sk_…`), used **server-side only**, gets full read/list/update/delete.
1637
+ * Never ship a secret key in a browser bundle.
1638
+ *
1639
+ * Generic over the service-key union `TService`: bind the type emitted by
1640
+ * `@aranova/tracking-cli gen` for compile-time-checked `service` values.
1641
+ */
1642
+ interface SalesClient<TService extends string = string> {
1643
+ record(input: Omit<SaleInput, 'currency' | 'occurred_at' | 'service'> & {
1644
+ service?: TService | null;
1645
+ currency?: SupportedCurrency;
1646
+ occurred_at?: string;
1647
+ }): Promise<Sale>;
1648
+ list(query?: SaleListQuery): Promise<SaleCursorPage>;
1649
+ get(id: string): Promise<Sale>;
1650
+ update(id: string, patch: Omit<SaleUpdateInput, 'service'> & {
1651
+ service?: TService | null;
1652
+ }): Promise<Sale>;
1653
+ delete(id: string): Promise<void>;
1654
+ }
1655
+ declare function createSalesClient<TService extends string = string>(config: SalesClientConfig): SalesClient<TService>;
1656
+
1657
+ /** A business's active service, as returned by `GET /tracking/services`. */
1658
+ interface PublicServiceItem {
1659
+ key: string;
1660
+ label: string;
1661
+ }
1662
+ /**
1663
+ * Fetch the caller's business's active service taxonomy. Accepts a public or
1664
+ * secret key (the taxonomy is low-sensitivity category names). Powers the
1665
+ * `@aranova/tracking-cli gen` codegen.
1666
+ */
1667
+ declare function fetchServices(config: SalesTransportConfig): Promise<PublicServiceItem[]>;
1668
+
1669
+ /**
1670
+ * Convert a major amount (dollars `250.5`) to integer minor units (`25050`).
1671
+ *
1672
+ * Convenience only — the wire is always integer cents. Uses float multiply +
1673
+ * `Math.round`, so values that aren't exactly representable in binary float
1674
+ * (e.g. `1.005`) can round to the neighbouring cent. If you already hold an
1675
+ * exact cents integer, pass it straight through and skip this helper.
1676
+ */
1677
+ declare function toMinor(amount: number, currency: SupportedCurrency): number;
1678
+ /** Convert integer minor units (`25050`) to a major amount (`250.5`). */
1679
+ declare function fromMinor(cents: number, currency: SupportedCurrency): number;
1680
+ /**
1681
+ * Format integer minor units as a localized currency string (e.g. `"$250.50"`).
1682
+ * Uses the built-in `Intl.NumberFormat` — no extra dependency.
1683
+ */
1684
+ declare function formatMoney(cents: number, currency: SupportedCurrency, locale?: string): string;
1685
+
1686
+ /**
1687
+ * Error thrown by the sales client (`createSalesClient`) on a
1688
+ * non-2xx response. Unlike the fire-and-forget event queue (which swallows
1689
+ * failures), a sale is a transaction the caller must be able to react to.
1690
+ */
1691
+ declare class AranovaApiError extends Error {
1692
+ readonly status: number;
1693
+ readonly code: string | undefined;
1694
+ readonly requestId: string | undefined;
1695
+ constructor(message: string, options: {
1696
+ status: number;
1697
+ code?: string;
1698
+ requestId?: string;
1699
+ });
1700
+ }
1701
+
1401
1702
  /**
1402
1703
  * Props for the Google Ads tracking component.
1403
1704
  *
@@ -1506,4 +1807,4 @@ interface CreateTrackingResult<TRegistry extends TriggerRegistryConfig> {
1506
1807
  }
1507
1808
  declare function createTracking<TRegistry extends TriggerRegistryConfig>(options: CreateTrackingOptions<TRegistry>): CreateTrackingResult<TRegistry>;
1508
1809
 
1509
- export { type AutomaticEventName, ConsentBanner, type ConsentState, type CreateTrackingOptions, type CreateTrackingResult, type CtaClickConfig, type CtaClickMetadata, type EventConfig, type EventMetadata, type EventName, type FormStartConfig, type FormStartMetadata, type FormSubmitConfig, type FormSubmitMetadata, GoogleAdsTracking, type GoogleAdsTrackingProps, type JsonValue, type ManualEventName, type MultiPageSessionConfig, type MultiPageSessionMetadata, type PageViewConfig, type PageViewMetadata, type PhoneClickConfig, type PhoneClickMetadata, type RegisteredAutomaticEvents, type RegisteredManualEvents, type ScrollDepthConfig, type ScrollDepthMetadata, type SpecificPageName, type SpecificPageVisitConfig, type SpecificPageVisitMetadata, TRACKING_PARAM_KEYS, type TimeOnSiteConfig, type TimeOnSiteMetadata, type TrackingClient, type TrackingClientContext, type TrackingEventCreatePayload, type TrackingInitConfig, type TrackingInstallSurface, type TrackingParams, type TrackingProviderProps, type TrackingSessionUpsertPayload, type TriggerRegistryConfig, type TypedTrackEventOptions, type TypedTrackingClient, captureTrackingParamsFromLocation, createTracking, createTrackingClientContext, createTrackingEventCreatePayload, createTrackingSessionUpsertPayload, getConsentState, setConsentState, useConsentState, useGclid, useTrackingParams };
1810
+ export { AranovaApiError, type AutomaticEventName, ConsentBanner, type ConsentState, type CreateTrackingOptions, type CreateTrackingResult, type CtaClickConfig, type CtaClickMetadata, type EventConfig, type EventMetadata, type EventName, type FormStartConfig, type FormStartMetadata, type FormSubmitConfig, type FormSubmitMetadata, GoogleAdsTracking, type GoogleAdsTrackingProps, type JsonValue, type ManualEventName, type MultiPageSessionConfig, type MultiPageSessionMetadata, type PageViewConfig, type PageViewMetadata, type PhoneClickConfig, type PhoneClickMetadata, type PublicServiceItem, type RegisteredAutomaticEvents, type RegisteredManualEvents, type Sale, type SaleCursorPage, type SaleInput, type SaleItem, type SaleItemInput, type SaleListPage, type SaleListQuery, type SaleUpdateInput, type SalesClient, type SalesClientConfig, type SalesTransportConfig, type ScrollDepthConfig, type ScrollDepthMetadata, type SpecificPageName, type SpecificPageVisitConfig, type SpecificPageVisitMetadata, type SupportedCurrency, TRACKING_PARAM_KEYS, type TimeOnSiteConfig, type TimeOnSiteMetadata, type TrackingClient, type TrackingClientContext, type TrackingEventCreatePayload, type TrackingInitConfig, type TrackingInstallSurface, type TrackingParams, type TrackingProviderProps, type TrackingSessionUpsertPayload, type TriggerRegistryConfig, type TypedTrackEventOptions, type TypedTrackingClient, captureTrackingParamsFromLocation, createSalesClient, createTracking, createTrackingClientContext, createTrackingEventCreatePayload, createTrackingSessionUpsertPayload, fetchServices, formatMoney, fromMinor, getConsentState, setConsentState, toMinor, useConsentState, useGclid, useTrackingParams };
package/dist/index.js CHANGED
@@ -20,16 +20,22 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var src_exports = {};
22
22
  __export(src_exports, {
23
+ AranovaApiError: () => AranovaApiError,
23
24
  ConsentBanner: () => ConsentBanner,
24
25
  GoogleAdsTracking: () => GoogleAdsTracking,
25
26
  TRACKING_PARAM_KEYS: () => TRACKING_PARAM_KEYS,
26
27
  captureTrackingParamsFromLocation: () => captureTrackingParamsFromLocation,
28
+ createSalesClient: () => createSalesClient,
27
29
  createTracking: () => createTracking,
28
30
  createTrackingClientContext: () => createTrackingClientContext,
29
31
  createTrackingEventCreatePayload: () => createTrackingEventCreatePayload,
30
32
  createTrackingSessionUpsertPayload: () => createTrackingSessionUpsertPayload,
33
+ fetchServices: () => fetchServices,
34
+ formatMoney: () => formatMoney,
35
+ fromMinor: () => fromMinor,
31
36
  getConsentState: () => getConsentState,
32
37
  setConsentState: () => setConsentState,
38
+ toMinor: () => toMinor,
33
39
  useConsentState: () => useConsentState,
34
40
  useGclid: () => useGclid,
35
41
  useTrackingParams: () => useTrackingParams
@@ -503,6 +509,10 @@ var DEFAULT_FLUSH_INTERVAL_MS = 2e3;
503
509
  var DEFAULT_MAX_QUEUE_SIZE = 10;
504
510
  var HARD_MAX_BATCH = 50;
505
511
  var API_KEY_HEADER = "X-Aranova-Api-Key";
512
+ var SDK_VERSION_HEADER = "X-Aranova-Sdk-Version";
513
+ var SDK_PACKAGE_HEADER = "X-Aranova-Sdk-Package";
514
+ var SDK_SURFACE_HEADER = "X-Aranova-Sdk-Surface";
515
+ var SDK_ENVIRONMENT_HEADER = "X-Aranova-Sdk-Environment";
506
516
  function buildContext(surface, sdkVersion, packageName, environment, activeGtagIds) {
507
517
  return {
508
518
  surface,
@@ -531,7 +541,7 @@ function consentSnapshot() {
531
541
  return null;
532
542
  }
533
543
  }
534
- async function postWithFetch(url, body, apiKey, keepalive) {
544
+ async function postWithFetch(url, body, apiKey, identity, keepalive) {
535
545
  if (typeof fetch !== "function")
536
546
  return;
537
547
  try {
@@ -539,7 +549,11 @@ async function postWithFetch(url, body, apiKey, keepalive) {
539
549
  method: "POST",
540
550
  headers: {
541
551
  "Content-Type": "application/json",
542
- [API_KEY_HEADER]: apiKey
552
+ [API_KEY_HEADER]: apiKey,
553
+ [SDK_VERSION_HEADER]: identity.sdkVersion,
554
+ [SDK_PACKAGE_HEADER]: identity.packageName,
555
+ [SDK_SURFACE_HEADER]: identity.surface,
556
+ [SDK_ENVIRONMENT_HEADER]: identity.environment
543
557
  },
544
558
  body,
545
559
  keepalive,
@@ -576,6 +590,12 @@ function createTrackingClient(config) {
576
590
  const activeGtagIds = config.activeGtagIds ?? null;
577
591
  const endpointBase = config.endpoint.replace(/\/$/, "");
578
592
  const eventsUrl = `${endpointBase}/events`;
593
+ const identityHeaders2 = {
594
+ sdkVersion: sdkVersion ?? "",
595
+ packageName: packageName ?? "",
596
+ surface: config.surface,
597
+ environment
598
+ };
579
599
  let queue = [];
580
600
  let flushTimer = null;
581
601
  let firstPage = null;
@@ -651,7 +671,7 @@ function createTrackingClient(config) {
651
671
  events
652
672
  };
653
673
  const serialized = JSON.stringify(body);
654
- await postWithFetch(eventsUrl, serialized, config.apiKey, false);
674
+ await postWithFetch(eventsUrl, serialized, config.apiKey, identityHeaders2, false);
655
675
  }
656
676
  function trackEvent(input) {
657
677
  if (destroyed)
@@ -682,7 +702,7 @@ function createTrackingClient(config) {
682
702
  events
683
703
  };
684
704
  const serialized = JSON.stringify(body);
685
- void postWithFetch(eventsUrl, serialized, config.apiKey, true);
705
+ void postWithFetch(eventsUrl, serialized, config.apiKey, identityHeaders2, true);
686
706
  }
687
707
  if (typeof window !== "undefined") {
688
708
  window.addEventListener("pagehide", flushOnUnload);
@@ -1277,6 +1297,121 @@ function attachFormStart(client, config) {
1277
1297
  };
1278
1298
  }
1279
1299
 
1300
+ // ../tracking-core/src/resources/sales/errors.ts
1301
+ var AranovaApiError = class extends Error {
1302
+ constructor(message, options) {
1303
+ super(message);
1304
+ this.name = "AranovaApiError";
1305
+ this.status = options.status;
1306
+ this.code = options.code;
1307
+ this.requestId = options.requestId;
1308
+ }
1309
+ };
1310
+
1311
+ // ../tracking-core/src/resources/sales/transport.ts
1312
+ function identityHeaders(config) {
1313
+ const headers = { [API_KEY_HEADER]: config.apiKey };
1314
+ if (config.sdkVersion) headers[SDK_VERSION_HEADER] = config.sdkVersion;
1315
+ if (config.packageName) headers[SDK_PACKAGE_HEADER] = config.packageName;
1316
+ if (config.surface) headers[SDK_SURFACE_HEADER] = config.surface;
1317
+ if (config.environment) headers[SDK_ENVIRONMENT_HEADER] = config.environment;
1318
+ return headers;
1319
+ }
1320
+ function joinUrl(endpoint, path) {
1321
+ return `${endpoint.replace(/\/$/, "")}${path}`;
1322
+ }
1323
+ async function salesRequest(config, method, path, body) {
1324
+ const headers = identityHeaders(config);
1325
+ if (body !== void 0) headers["Content-Type"] = "application/json";
1326
+ const response = await fetch(joinUrl(config.endpoint, path), {
1327
+ method,
1328
+ headers,
1329
+ body: body === void 0 ? void 0 : JSON.stringify(body)
1330
+ });
1331
+ if (!response.ok) {
1332
+ let detail;
1333
+ let code;
1334
+ try {
1335
+ const parsed = await response.json();
1336
+ if (parsed && typeof parsed === "object") {
1337
+ const record = parsed;
1338
+ if (typeof record.detail === "string") detail = record.detail;
1339
+ if (typeof record.code === "string") code = record.code;
1340
+ }
1341
+ } catch {
1342
+ }
1343
+ throw new AranovaApiError(detail ?? response.statusText ?? "Request failed", {
1344
+ status: response.status,
1345
+ code,
1346
+ requestId: response.headers.get("x-request-id") ?? void 0
1347
+ });
1348
+ }
1349
+ if (response.status === 204) return void 0;
1350
+ return await response.json();
1351
+ }
1352
+
1353
+ // ../tracking-core/src/resources/sales/client.ts
1354
+ function createSalesClient(config) {
1355
+ return {
1356
+ async record(input) {
1357
+ const currency = input.currency ?? config.defaultCurrency;
1358
+ if (!currency) {
1359
+ throw new Error(
1360
+ "record: `currency` is required (pass it on the sale or set config.defaultCurrency)"
1361
+ );
1362
+ }
1363
+ const body = {
1364
+ ...input,
1365
+ currency,
1366
+ occurred_at: input.occurred_at ?? (/* @__PURE__ */ new Date()).toISOString()
1367
+ };
1368
+ return salesRequest(config, "POST", "/sales", body);
1369
+ },
1370
+ async list(query) {
1371
+ const { cursor, limit, ...filters } = query ?? {};
1372
+ return salesRequest(config, "POST", "/sales/query", {
1373
+ filters,
1374
+ ...limit !== void 0 ? { limit } : {},
1375
+ ...cursor !== void 0 ? { cursor } : {}
1376
+ });
1377
+ },
1378
+ async get(id) {
1379
+ return salesRequest(config, "GET", `/sales/${id}`);
1380
+ },
1381
+ async update(id, patch) {
1382
+ return salesRequest(config, "PATCH", `/sales/${id}`, patch);
1383
+ },
1384
+ async delete(id) {
1385
+ await salesRequest(config, "DELETE", `/sales/${id}`);
1386
+ }
1387
+ };
1388
+ }
1389
+
1390
+ // ../tracking-core/src/resources/services.ts
1391
+ async function fetchServices(config) {
1392
+ return salesRequest(config, "GET", "/services");
1393
+ }
1394
+
1395
+ // ../tracking-core/src/resources/sales/money.ts
1396
+ var MINOR_UNIT_EXPONENT = {
1397
+ USD: 2,
1398
+ CAD: 2
1399
+ };
1400
+ function exponentFor(currency) {
1401
+ return MINOR_UNIT_EXPONENT[currency] ?? 2;
1402
+ }
1403
+ function toMinor(amount, currency) {
1404
+ return Math.round(amount * 10 ** exponentFor(currency));
1405
+ }
1406
+ function fromMinor(cents, currency) {
1407
+ return cents / 10 ** exponentFor(currency);
1408
+ }
1409
+ function formatMoney(cents, currency, locale) {
1410
+ return new Intl.NumberFormat(locale, { style: "currency", currency }).format(
1411
+ fromMinor(cents, currency)
1412
+ );
1413
+ }
1414
+
1280
1415
  // src/ConsentBanner.tsx
1281
1416
  var import_jsx_runtime = require("react/jsx-runtime");
1282
1417
  function ConsentBanner() {
@@ -1375,7 +1510,7 @@ function useConsentState() {
1375
1510
  var import_react4 = require("react");
1376
1511
 
1377
1512
  // package.json
1378
- var version = "0.7.1";
1513
+ var version = "0.8.0";
1379
1514
 
1380
1515
  // src/factory.tsx
1381
1516
  var import_jsx_runtime2 = require("react/jsx-runtime");
@@ -1485,16 +1620,22 @@ function createTracking(options) {
1485
1620
  }
1486
1621
  // Annotate the CommonJS export names for ESM import in node:
1487
1622
  0 && (module.exports = {
1623
+ AranovaApiError,
1488
1624
  ConsentBanner,
1489
1625
  GoogleAdsTracking,
1490
1626
  TRACKING_PARAM_KEYS,
1491
1627
  captureTrackingParamsFromLocation,
1628
+ createSalesClient,
1492
1629
  createTracking,
1493
1630
  createTrackingClientContext,
1494
1631
  createTrackingEventCreatePayload,
1495
1632
  createTrackingSessionUpsertPayload,
1633
+ fetchServices,
1634
+ formatMoney,
1635
+ fromMinor,
1496
1636
  getConsentState,
1497
1637
  setConsentState,
1638
+ toMinor,
1498
1639
  useConsentState,
1499
1640
  useGclid,
1500
1641
  useTrackingParams